Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index a1a6432..2214f12 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -104,6 +104,8 @@
 	- info on CPU_IDLE, CPU idle state management subsystem.
 cputopology.txt
 	- documentation on how CPU topology info is exported via sysfs.
+crc32.txt
+	- brief tutorial on CRC computation
 cris/
 	- directory with info about Linux on CRIS architecture.
 crypto/
diff --git a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
index 23a43b8..2a7f9a0 100644
--- a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
+++ b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc
@@ -55,7 +55,7 @@
 Date:		August 2008
 Contact:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 Description:
-		This file determines if the the transaction of the USB TMC
+		This file determines if the transaction of the USB TMC
 		device is to be automatically aborted if there is any error.
 		For more details about this, please see the document,
 		"Universal Serial Bus Test and Measurement Class Specification
diff --git a/Documentation/ABI/testing/debugfs-olpc b/Documentation/ABI/testing/debugfs-olpc
new file mode 100644
index 0000000..bd76cc6
--- /dev/null
+++ b/Documentation/ABI/testing/debugfs-olpc
@@ -0,0 +1,16 @@
+What:		/sys/kernel/debug/olpc-ec/cmd
+Date:		Dec 2011
+KernelVersion:	3.4
+Contact:	devel@lists.laptop.org
+Description:
+
+A generic interface for executing OLPC Embedded Controller commands and
+reading their responses.
+
+To execute a command, write data with the format: CC:N A A A A
+CC is the (hex) command, N is the count of expected reply bytes, and A A A A
+are optional (hex) arguments.
+
+To read the response (if any), read from the generic node after executing
+a command. Hex reply bytes will be returned, *whether or not* they came from
+the immediately previous command.
diff --git a/Documentation/ABI/testing/sysfs-block-dm b/Documentation/ABI/testing/sysfs-block-dm
new file mode 100644
index 0000000..87ca569
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-block-dm
@@ -0,0 +1,25 @@
+What:		/sys/block/dm-<num>/dm/name
+Date:		January 2009
+KernelVersion:	2.6.29
+Contact:	dm-devel@redhat.com
+Description:	Device-mapper device name.
+		Read-only string containing mapped device name.
+Users:		util-linux, device-mapper udev rules
+
+What:		/sys/block/dm-<num>/dm/uuid
+Date:		January 2009
+KernelVersion:	2.6.29
+Contact:	dm-devel@redhat.com
+Description:	Device-mapper device UUID.
+		Read-only string containing DM-UUID or empty string
+		if DM-UUID is not set.
+Users:		util-linux, device-mapper udev rules
+
+What:		/sys/block/dm-<num>/dm/suspended
+Date:		June 2009
+KernelVersion:	2.6.31
+Contact:	dm-devel@redhat.com
+Description:	Device-mapper device suspend state.
+		Contains the value 1 while the device is suspended.
+		Otherwise it contains 0. Read-only attribute.
+Users:		util-linux, device-mapper udev rules
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-format b/Documentation/ABI/testing/sysfs-bus-event_source-devices-format
new file mode 100644
index 0000000..079afc7
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-format
@@ -0,0 +1,14 @@
+Where:		/sys/bus/event_source/devices/<dev>/format
+Date:		January 2012
+Kernel Version: 3.3
+Contact:	Jiri Olsa <jolsa@redhat.com>
+Description:
+		Attribute group to describe the magic bits that go into
+		perf_event_attr::config[012] for a particular pmu.
+		Each attribute of this group defines the 'hardware' bitmask
+		we want to export, so that userspace can deal with sane
+		name/value pairs.
+
+		Example: 'config1:1,6-10,44'
+		Defines contents of attribute that occupies bits 1,6-10,44 of
+		perf_event_attr::config1.
diff --git a/Documentation/ABI/testing/sysfs-bus-rpmsg b/Documentation/ABI/testing/sysfs-bus-rpmsg
new file mode 100644
index 0000000..189e419
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-rpmsg
@@ -0,0 +1,75 @@
+What:		/sys/bus/rpmsg/devices/.../name
+Date:		June 2011
+KernelVersion:	3.3
+Contact:	Ohad Ben-Cohen <ohad@wizery.com>
+Description:
+		Every rpmsg device is a communication channel with a remote
+		processor. Channels are identified with a (textual) name,
+		which is maximum 32 bytes long (defined as RPMSG_NAME_SIZE in
+		rpmsg.h).
+
+		This sysfs entry contains the name of this channel.
+
+What:		/sys/bus/rpmsg/devices/.../src
+Date:		June 2011
+KernelVersion:	3.3
+Contact:	Ohad Ben-Cohen <ohad@wizery.com>
+Description:
+		Every rpmsg device is a communication channel with a remote
+		processor. Channels have a local ("source") rpmsg address,
+		and remote ("destination") rpmsg address. When an entity
+		starts listening on one end of a channel, it assigns it with
+		a unique rpmsg address (a 32 bits integer). This way when
+		inbound messages arrive to this address, the rpmsg core
+		dispatches them to the listening entity (a kernel driver).
+
+		This sysfs entry contains the src (local) rpmsg address
+		of this channel. If it contains 0xffffffff, then an address
+		wasn't assigned (can happen if no driver exists for this
+		channel).
+
+What:		/sys/bus/rpmsg/devices/.../dst
+Date:		June 2011
+KernelVersion:	3.3
+Contact:	Ohad Ben-Cohen <ohad@wizery.com>
+Description:
+		Every rpmsg device is a communication channel with a remote
+		processor. Channels have a local ("source") rpmsg address,
+		and remote ("destination") rpmsg address. When an entity
+		starts listening on one end of a channel, it assigns it with
+		a unique rpmsg address (a 32 bits integer). This way when
+		inbound messages arrive to this address, the rpmsg core
+		dispatches them to the listening entity.
+
+		This sysfs entry contains the dst (remote) rpmsg address
+		of this channel. If it contains 0xffffffff, then an address
+		wasn't assigned (can happen if the kernel driver that
+		is attached to this channel is exposing a service to the
+		remote processor. This make it a local rpmsg server,
+		and it is listening for inbound messages that may be sent
+		from any remote rpmsg client; it is not bound to a single
+		remote entity).
+
+What:		/sys/bus/rpmsg/devices/.../announce
+Date:		June 2011
+KernelVersion:	3.3
+Contact:	Ohad Ben-Cohen <ohad@wizery.com>
+Description:
+		Every rpmsg device is a communication channel with a remote
+		processor. Channels are identified by a textual name (see
+		/sys/bus/rpmsg/devices/.../name above) and have a local
+		("source") rpmsg address, and remote ("destination") rpmsg
+		address.
+
+		A channel is first created when an entity, whether local
+		or remote, starts listening on it for messages (and is thus
+		called an rpmsg server).
+
+		When that happens, a "name service" announcement is sent
+		to the other processor, in order to let it know about the
+		creation of the channel (this way remote clients know they
+		can start sending messages).
+
+		This sysfs entry tells us whether the channel is a local
+		server channel that is announced (values are either
+		true or false).
diff --git a/Documentation/ABI/testing/sysfs-driver-samsung-laptop b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
index e82e7c2..678819a 100644
--- a/Documentation/ABI/testing/sysfs-driver-samsung-laptop
+++ b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
@@ -17,3 +17,21 @@
 		Specifically, not all support the "overclock" option,
 		and it's still unknown if this value even changes
 		anything, other than making the user feel a bit better.
+
+What:		/sys/devices/platform/samsung/battery_life_extender
+Date:		December 1, 2011
+KernelVersion:	3.3
+Contact:	Corentin Chary <corentin.chary@gmail.com>
+Description:	Max battery charge level can be modified, battery cycle
+		life can be extended by reducing the max battery charge
+		level.
+		0 means normal battery mode (100% charge)
+		1 means battery life extender mode (80% charge)
+
+What:		/sys/devices/platform/samsung/usb_charge
+Date:		December 1, 2011
+KernelVersion:	3.3
+Contact:	Corentin Chary <corentin.chary@gmail.com>
+Description:	Use your USB ports to charge devices, even
+		when your laptop is powered off.
+		1 means enabled, 0 means disabled.
diff --git a/Documentation/ABI/testing/sysfs-firmware-acpi b/Documentation/ABI/testing/sysfs-firmware-acpi
index 4f9ba3c..dd930c8 100644
--- a/Documentation/ABI/testing/sysfs-firmware-acpi
+++ b/Documentation/ABI/testing/sysfs-firmware-acpi
@@ -1,3 +1,23 @@
+What:		/sys/firmware/acpi/bgrt/
+Date:		January 2012
+Contact:	Matthew Garrett <mjg@redhat.com>
+Description:
+		The BGRT is an ACPI 5.0 feature that allows the OS
+		to obtain a copy of the firmware boot splash and
+		some associated metadata. This is intended to be used
+		by boot splash applications in order to interact with
+		the firmware boot splash in order to avoid jarring
+		transitions.
+
+		image: The image bitmap. Currently a 32-bit BMP.
+		status: 1 if the image is valid, 0 if firmware invalidated it.
+		type: 0 indicates image is in BMP format.
+		version: The version of the BGRT. Currently 1.
+		xoffset: The number of pixels between the left of the screen
+			 and the left edge of the image.
+		yoffset: The number of pixels between the top of the screen
+			 and the top edge of the image.
+
 What:		/sys/firmware/acpi/interrupts/
 Date:		February 2008
 Contact:	Len Brown <lenb@kernel.org>
diff --git a/Documentation/ABI/testing/sysfs-kernel-mm-cleancache b/Documentation/ABI/testing/sysfs-kernel-mm-cleancache
deleted file mode 100644
index 662ae64..0000000
--- a/Documentation/ABI/testing/sysfs-kernel-mm-cleancache
+++ /dev/null
@@ -1,11 +0,0 @@
-What:		/sys/kernel/mm/cleancache/
-Date:		April 2011
-Contact:	Dan Magenheimer <dan.magenheimer@oracle.com>
-Description:
-		/sys/kernel/mm/cleancache/ contains a number of files which
-		record a count of various cleancache operations
-		(sum across all filesystems):
-			succ_gets
-			failed_gets
-			puts
-			flushes
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
index 2b90d32..c58b236 100644
--- a/Documentation/CodingStyle
+++ b/Documentation/CodingStyle
@@ -793,6 +793,35 @@
 work correctly.
 
 
+		Chapter 19:  Inline assembly
+
+In architecture-specific code, you may need to use inline assembly to interface
+with CPU or platform functionality.  Don't hesitate to do so when necessary.
+However, don't use inline assembly gratuitously when C can do the job.  You can
+and should poke hardware from C when possible.
+
+Consider writing simple helper functions that wrap common bits of inline
+assembly, rather than repeatedly writing them with slight variations.  Remember
+that inline assembly can use C parameters.
+
+Large, non-trivial assembly functions should go in .S files, with corresponding
+C prototypes defined in C header files.  The C prototypes for assembly
+functions should use "asmlinkage".
+
+You may need to mark your asm statement as volatile, to prevent GCC from
+removing it if GCC doesn't notice any side effects.  You don't always need to
+do so, though, and doing so unnecessarily can limit optimization.
+
+When writing a single inline assembly statement containing multiple
+instructions, put each instruction on a separate line in a separate quoted
+string, and end each string except the last with \n\t to properly indent the
+next instruction in the assembly output:
+
+	asm ("magic %reg1, #42\n\t"
+	     "more_magic %reg2, %reg3"
+	     : /* outputs */ : /* inputs */ : /* clobbers */);
+
+
 
 		Appendix I: References
 
diff --git a/Documentation/DMA-attributes.txt b/Documentation/DMA-attributes.txt
index b768cc0..5c72eed 100644
--- a/Documentation/DMA-attributes.txt
+++ b/Documentation/DMA-attributes.txt
@@ -31,3 +31,21 @@
 Since it is optional for platforms to implement DMA_ATTR_WEAK_ORDERING,
 those that do not will simply ignore the attribute and exhibit default
 behavior.
+
+DMA_ATTR_WRITE_COMBINE
+----------------------
+
+DMA_ATTR_WRITE_COMBINE specifies that writes to the mapping may be
+buffered to improve performance.
+
+Since it is optional for platforms to implement DMA_ATTR_WRITE_COMBINE,
+those that do not will simply ignore the attribute and exhibit default
+behavior.
+
+DMA_ATTR_NON_CONSISTENT
+-----------------------
+
+DMA_ATTR_NON_CONSISTENT lets the platform to choose to return either
+consistent or non-consistent memory as it sees fit.  By using this API,
+you are guaranteeing to the platform that you have all the correct and
+necessary sync points for this memory in the driver.
diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl
index 9c27e51..7514dbf 100644
--- a/Documentation/DocBook/device-drivers.tmpl
+++ b/Documentation/DocBook/device-drivers.tmpl
@@ -446,4 +446,21 @@
 !Edrivers/i2c/i2c-core.c
   </chapter>
 
+  <chapter id="hsi">
+     <title>High Speed Synchronous Serial Interface (HSI)</title>
+
+     <para>
+	High Speed Synchronous Serial Interface (HSI) is a
+	serial interface mainly used for connecting application
+	engines (APE) with cellular modem engines (CMT) in cellular
+	handsets.
+
+	HSI provides multiplexing for up to 16 logical channels,
+	low-latency and full duplex communication.
+     </para>
+
+!Iinclude/linux/hsi/hsi.h
+!Edrivers/hsi/hsi.c
+  </chapter>
+
 </book>
diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl
index d71b57f..4ee4ba3 100644
--- a/Documentation/DocBook/kgdb.tmpl
+++ b/Documentation/DocBook/kgdb.tmpl
@@ -362,6 +362,23 @@
    </para>
   </para>
   </sect1>
+   <sect1 id="kgdbreboot">
+   <title>Run time parameter: kgdbreboot</title>
+   <para> The kgdbreboot feature allows you to change how the debugger
+   deals with the reboot notification.  You have 3 choices for the
+   behavior.  The default behavior is always set to 0.</para>
+   <orderedlist>
+   <listitem><para>echo -1 > /sys/module/debug_core/parameters/kgdbreboot</para>
+   <para>Ignore the reboot notification entirely.</para>
+   </listitem>
+   <listitem><para>echo 0 > /sys/module/debug_core/parameters/kgdbreboot</para>
+   <para>Send the detach message to any attached debugger client.</para>
+   </listitem>
+   <listitem><para>echo 1 > /sys/module/debug_core/parameters/kgdbreboot</para>
+   <para>Enter the debugger on reboot notify.</para>
+   </listitem>
+   </orderedlist>
+  </sect1>
   </chapter>
   <chapter id="usingKDB">
   <title>Using kdb</title>
diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml
index cea6fd3..7dc65c5 100644
--- a/Documentation/DocBook/media/v4l/biblio.xml
+++ b/Documentation/DocBook/media/v4l/biblio.xml
@@ -128,6 +128,26 @@
       <subtitle>Version 1.02</subtitle>
     </biblioentry>
 
+    <biblioentry id="itu-t81">
+      <abbrev>ITU-T.81</abbrev>
+      <authorgroup>
+	<corpauthor>International Telecommunication Union
+(<ulink url="http://www.itu.int">http://www.itu.int</ulink>)</corpauthor>
+      </authorgroup>
+      <title>ITU-T Recommendation T.81
+"Information Technology &mdash; Digital Compression and Coding of Continous-Tone
+Still Images &mdash; Requirements and Guidelines"</title>
+    </biblioentry>
+
+    <biblioentry id="w3c-jpeg-jfif">
+      <abbrev>W3C JPEG JFIF</abbrev>
+      <authorgroup>
+	<corpauthor>The World Wide Web Consortium (<ulink
+url="http://www.w3.org/Graphics/JPEG">http://www.w3.org</ulink>)</corpauthor>
+      </authorgroup>
+      <title>JPEG JFIF</title>
+    </biblioentry>
+
     <biblioentry id="smpte12m">
       <abbrev>SMPTE&nbsp;12M</abbrev>
       <authorgroup>
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
index a2485b3..bce97c5 100644
--- a/Documentation/DocBook/media/v4l/compat.xml
+++ b/Documentation/DocBook/media/v4l/compat.xml
@@ -2393,6 +2393,20 @@
 	    to the <link linkend="control">User controls class</link>.
 	  </para>
         </listitem>
+        <listitem>
+	  <para>Added the device_caps field to struct v4l2_capabilities and added the new
+	  V4L2_CAP_DEVICE_CAPS capability.</para>
+        </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 3.4</title>
+      <orderedlist>
+        <listitem>
+	  <para>Added <link linkend="jpeg-controls">JPEG compression control
+	  class</link>.</para>
+        </listitem>
       </orderedlist>
     </section>
 
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index a1be378..b84f25e 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -1286,6 +1286,49 @@
 and reproducible audio bitstream. 0 = unmuted, 1 = muted.</entry>
 	      </row>
 	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-audio-dec-playback">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_audio_dec_playback</entry>
+	      </row><row><entry spanname="descr">Determines how monolingual audio should be played back.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO</constant>&nbsp;</entry>
+		      <entry>Automatically determines the best playback mode.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO</constant>&nbsp;</entry>
+		      <entry>Stereo playback.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT</constant>&nbsp;</entry>
+		      <entry>Left channel playback.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_RIGHT</constant>&nbsp;</entry>
+		      <entry>Right channel playback.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_MONO</constant>&nbsp;</entry>
+		      <entry>Mono playback.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO</constant>&nbsp;</entry>
+		      <entry>Stereo playback with swapped left and right channels.</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-audio-dec-multilingual-playback">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_audio_dec_playback</entry>
+	      </row><row><entry spanname="descr">Determines how multilingual audio should be played back.</entry>
+	      </row>
+	      <row><entry></entry></row>
 	      <row id="v4l2-mpeg-video-encoding">
 		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_ENCODING</constant>&nbsp;</entry>
 		<entry>enum&nbsp;v4l2_mpeg_video_encoding</entry>
@@ -1447,6 +1490,22 @@
 		  </tbody>
 		</entrytbl>
 	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-video-dec-pts">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DEC_PTS</constant>&nbsp;</entry>
+		<entry>integer64</entry>
+	      </row><row><entry spanname="descr">This read-only control returns the
+33-bit video Presentation Time Stamp as defined in ITU T-REC-H.222.0 and ISO/IEC 13818-1 of
+the currently displayed frame. This is the same PTS as is used in &VIDIOC-DECODER-CMD;.</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-video-dec-frame">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DEC_FRAME</constant>&nbsp;</entry>
+		<entry>integer64</entry>
+	      </row><row><entry spanname="descr">This read-only control returns the
+frame counter of the frame that is currently displayed (decoded). This value is reset to 0 whenever
+the decoder is started.</entry>
+	      </row>
 
 
 	      <row><entry></entry></row>
@@ -3377,6 +3436,167 @@
 	</tbody>
       </tgroup>
       </table>
+    </section>
 
+    <section id="jpeg-controls">
+      <title>JPEG Control Reference</title>
+      <para>The JPEG class includes controls for common features of JPEG
+      encoders and decoders. Currently it includes features for codecs
+      implementing progressive baseline DCT compression process with
+      Huffman entrophy coding.</para>
+      <table pgwide="1" frame="none" id="jpeg-control-id">
+      <title>JPEG Control IDs</title>
+
+      <tgroup cols="4">
+	<colspec colname="c1" colwidth="1*" />
+	<colspec colname="c2" colwidth="6*" />
+	<colspec colname="c3" colwidth="2*" />
+	<colspec colname="c4" colwidth="6*" />
+	<spanspec namest="c1" nameend="c2" spanname="id" />
+	<spanspec namest="c2" nameend="c4" spanname="descr" />
+	<thead>
+	  <row>
+	    <entry spanname="id" align="left">ID</entry>
+	    <entry align="left">Type</entry>
+	  </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+	  </row>
+	</thead>
+	<tbody valign="top">
+	  <row><entry></entry></row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_JPEG_CLASS</constant>&nbsp;</entry>
+	    <entry>class</entry>
+	  </row><row><entry spanname="descr">The JPEG class descriptor. Calling
+	  &VIDIOC-QUERYCTRL; for this control will return a description of this
+	  control class.
+
+	</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_JPEG_CHROMA_SUBSAMPLING</constant></entry>
+	    <entry>menu</entry>
+	  </row>
+	  <row id="jpeg-chroma-subsampling-control">
+	    <entry spanname="descr">The chroma subsampling factors describe how
+	    each component of an input image is sampled, in respect to maximum
+	    sample rate in each spatial dimension. See <xref linkend="itu-t81"/>,
+	    clause A.1.1. for more details. The <constant>
+	    V4L2_CID_JPEG_CHROMA_SUBSAMPLING</constant> control determines how
+	    Cb and Cr components are downsampled after coverting an input image
+	    from RGB to Y'CbCr color space.
+	    </entry>
+	  </row>
+	  <row>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_444</constant>
+		  </entry><entry>No chroma subsampling, each pixel has
+		  Y, Cr and Cb values.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_422</constant>
+		  </entry><entry>Horizontally subsample Cr, Cb components
+		  by a factor of 2.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_420</constant>
+		  </entry><entry>Subsample Cr, Cb components horizontally
+		  and vertically by 2.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_411</constant>
+		  </entry><entry>Horizontally subsample Cr, Cb components
+		  by a factor of 4.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_410</constant>
+		  </entry><entry>Subsample Cr, Cb components horizontally
+		  by 4 and vertically by 2.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY</constant>
+		  </entry><entry>Use only luminance component.</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_JPEG_RESTART_INTERVAL</constant>
+	    </entry><entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">
+	      The restart interval determines an interval of inserting RSTm
+	      markers (m = 0..7). The purpose of these markers is to additionally
+	      reinitialize the encoder process, in order to process blocks of
+	      an image independently.
+	      For the lossy compression processes the restart interval unit is
+	      MCU (Minimum Coded Unit) and its value is contained in DRI
+	      (Define Restart Interval) marker. If <constant>
+	      V4L2_CID_JPEG_RESTART_INTERVAL</constant> control is set to 0,
+	      DRI and RSTm markers will not be inserted.
+	    </entry>
+	  </row>
+	  <row id="jpeg-quality-control">
+	    <entry spanname="id"><constant>V4L2_CID_JPEG_COMPRESION_QUALITY</constant></entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">
+	      <constant>V4L2_CID_JPEG_COMPRESION_QUALITY</constant> control
+	      determines trade-off between image quality and size.
+	      It provides simpler method for applications to control image quality,
+	      without a need for direct reconfiguration of luminance and chrominance
+	      quantization tables.
+
+	      In cases where a driver uses quantization tables configured directly
+	      by an application, using interfaces defined elsewhere, <constant>
+	      V4L2_CID_JPEG_COMPRESION_QUALITY</constant> control should be set
+	      by driver to 0.
+
+	      <para>The value range of this control is driver-specific. Only
+	      positive, non-zero values are meaningful. The recommended range
+	      is 1 - 100, where larger values correspond to better image quality.
+	      </para>
+	    </entry>
+	    </row>
+	  <row id="jpeg-active-marker-control">
+	    <entry spanname="id"><constant>V4L2_CID_JPEG_ACTIVE_MARKER</constant></entry>
+	    <entry>bitmask</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Specify which JPEG markers are included
+	    in compressed stream. This control is valid only for encoders.
+	    </entry>
+	  </row>
+	  <row>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_JPEG_ACTIVE_MARKER_APP0</constant></entry>
+		  <entry>Application data segment APP<subscript>0</subscript>.</entry>
+		</row><row>
+		  <entry><constant>V4L2_JPEG_ACTIVE_MARKER_APP1</constant></entry>
+		  <entry>Application data segment APP<subscript>1</subscript>.</entry>
+		</row><row>
+		  <entry><constant>V4L2_JPEG_ACTIVE_MARKER_COM</constant></entry>
+		  <entry>Comment segment.</entry>
+		</row><row>
+		  <entry><constant>V4L2_JPEG_ACTIVE_MARKER_DQT</constant></entry>
+		  <entry>Quantization tables segment.</entry>
+		</row><row>
+		  <entry><constant>V4L2_JPEG_ACTIVE_MARKER_DHT</constant></entry>
+		  <entry>Huffman tables segment.</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+	  <row><entry></entry></row>
+	</tbody>
+      </tgroup>
+      </table>
+      <para>For more details about JPEG specification, refer
+      to <xref linkend="itu-t81"/>, <xref linkend="jfif"/>,
+      <xref linkend="w3c-jpeg-jfif"/>.</para>
     </section>
 </section>
diff --git a/Documentation/DocBook/media/v4l/selection-api.xml b/Documentation/DocBook/media/v4l/selection-api.xml
index 2f0bdb4..b299e47 100644
--- a/Documentation/DocBook/media/v4l/selection-api.xml
+++ b/Documentation/DocBook/media/v4l/selection-api.xml
@@ -52,6 +52,10 @@
 	  </textobject>
 	</mediaobject>
       </figure>
+
+For complete list of the available selection targets see table <xref
+linkend="v4l2-sel-target"/>
+
     </section>
 
   <section>
@@ -186,7 +190,7 @@
 
    <section>
 
-     <title>Scaling control.</title>
+     <title>Scaling control</title>
 
 <para>An application can detect if scaling is performed by comparing the width
 and the height of rectangles obtained using <constant> V4L2_SEL_TGT_CROP_ACTIVE
@@ -200,7 +204,7 @@
 
   <section>
 
-    <title>Comparison with old cropping API.</title>
+    <title>Comparison with old cropping API</title>
 
 <para>The selection API was introduced to cope with deficiencies of previous
 <link linkend="crop"> API </link>, that was designed to control simple capture
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index e97c512..8ae3887 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -128,6 +128,22 @@
 applications. -->
 
       <revision>
+	<revnumber>3.4</revnumber>
+	<date>2012-01-25</date>
+	<authorinitials>sn</authorinitials>
+	<revremark>Added <link linkend="jpeg-controls">JPEG compression
+	    control class.</link>
+	</revremark>
+      </revision>
+
+      <revision>
+	<revnumber>3.3</revnumber>
+	<date>2012-01-11</date>
+	<authorinitials>hv</authorinitials>
+	<revremark>Added device_caps field to struct v4l2_capabilities.</revremark>
+      </revision>
+
+      <revision>
 	<revnumber>3.2</revnumber>
 	<date>2011-08-26</date>
 	<authorinitials>hv</authorinitials>
@@ -417,7 +433,7 @@
 </partinfo>
 
 <title>Video for Linux Two API Specification</title>
- <subtitle>Revision 3.2</subtitle>
+ <subtitle>Revision 3.3</subtitle>
 
   <chapter id="common">
     &sub-common;
@@ -473,6 +489,7 @@
     &sub-cropcap;
     &sub-dbg-g-chip-ident;
     &sub-dbg-g-register;
+    &sub-decoder-cmd;
     &sub-dqevent;
     &sub-encoder-cmd;
     &sub-enumaudio;
diff --git a/Documentation/DocBook/media/v4l/vidioc-decoder-cmd.xml b/Documentation/DocBook/media/v4l/vidioc-decoder-cmd.xml
new file mode 100644
index 0000000..74b87f6
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/vidioc-decoder-cmd.xml
@@ -0,0 +1,256 @@
+<refentry id="vidioc-decoder-cmd">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_DECODER_CMD, VIDIOC_TRY_DECODER_CMD</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_DECODER_CMD</refname>
+    <refname>VIDIOC_TRY_DECODER_CMD</refname>
+    <refpurpose>Execute an decoder command</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>struct v4l2_decoder_cmd *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>&fd;</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>VIDIOC_DECODER_CMD, VIDIOC_TRY_DECODER_CMD</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+
+      <para>This is an <link linkend="experimental">experimental</link>
+interface and may change in the future.</para>
+    </note>
+
+    <para>These ioctls control an audio/video (usually MPEG-) decoder.
+<constant>VIDIOC_DECODER_CMD</constant> sends a command to the
+decoder, <constant>VIDIOC_TRY_DECODER_CMD</constant> can be used to
+try a command without actually executing it. To send a command applications
+must initialize all fields of a &v4l2-decoder-cmd; and call
+<constant>VIDIOC_DECODER_CMD</constant> or <constant>VIDIOC_TRY_DECODER_CMD</constant>
+with a pointer to this structure.</para>
+
+    <para>The <structfield>cmd</structfield> field must contain the
+command code. Some commands use the <structfield>flags</structfield> field for
+additional information.
+</para>
+
+    <para>A <function>write</function>() or &VIDIOC-STREAMON; call sends an implicit
+START command to the decoder if it has not been started yet.
+</para>
+
+    <para>A <function>close</function>() or &VIDIOC-STREAMOFF; call of a streaming
+file descriptor sends an implicit immediate STOP command to the decoder, and all
+buffered data is discarded.</para>
+
+    <para>These ioctls are optional, not all drivers may support
+them. They were introduced in Linux 3.3.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-decoder-cmd">
+      <title>struct <structname>v4l2_decoder_cmd</structname></title>
+      <tgroup cols="5">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>cmd</structfield></entry>
+            <entry></entry>
+            <entry></entry>
+	    <entry>The decoder command, see <xref linkend="decoder-cmds" />.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>flags</structfield></entry>
+            <entry></entry>
+            <entry></entry>
+	    <entry>Flags to go with the command. If no flags are defined for
+this command, drivers and applications must set this field to zero.</entry>
+	  </row>
+	  <row>
+	    <entry>union</entry>
+	    <entry>(anonymous)</entry>
+            <entry></entry>
+	    <entry></entry>
+            <entry></entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>struct</entry>
+            <entry><structfield>start</structfield></entry>
+            <entry></entry>
+            <entry>Structure containing additional data for the
+<constant>V4L2_DEC_CMD_START</constant> command.</entry>
+	  </row>
+	  <row>
+            <entry></entry>
+            <entry></entry>
+	    <entry>__s32</entry>
+	    <entry><structfield>speed</structfield></entry>
+            <entry>Playback speed and direction. The playback speed is defined as
+<structfield>speed</structfield>/1000 of the normal speed. So 1000 is normal playback.
+Negative numbers denote reverse playback, so -1000 does reverse playback at normal
+speed. Speeds -1, 0 and 1 have special meanings: speed 0 is shorthand for 1000
+(normal playback). A speed of 1 steps just one frame forward, a speed of -1 steps
+just one frame back.
+	    </entry>
+	  </row>
+	  <row>
+            <entry></entry>
+            <entry></entry>
+	    <entry>__u32</entry>
+	    <entry><structfield>format</structfield></entry>
+            <entry>Format restrictions. This field is set by the driver, not the
+application. Possible values are <constant>V4L2_DEC_START_FMT_NONE</constant> if
+there are no format restrictions or <constant>V4L2_DEC_START_FMT_GOP</constant>
+if the decoder operates on full GOPs (<wordasword>Group Of Pictures</wordasword>).
+This is usually the case for reverse playback: the decoder needs full GOPs, which
+it can then play in reverse order. So to implement reverse playback the application
+must feed the decoder the last GOP in the video file, then the GOP before that, etc. etc.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>struct</entry>
+            <entry><structfield>stop</structfield></entry>
+            <entry></entry>
+            <entry>Structure containing additional data for the
+<constant>V4L2_DEC_CMD_STOP</constant> command.</entry>
+	  </row>
+	  <row>
+            <entry></entry>
+            <entry></entry>
+	    <entry>__u64</entry>
+	    <entry><structfield>pts</structfield></entry>
+            <entry>Stop playback at this <structfield>pts</structfield> or immediately
+if the playback is already past that timestamp. Leave to 0 if you want to stop after the
+last frame was decoded.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>struct</entry>
+            <entry><structfield>raw</structfield></entry>
+            <entry></entry>
+            <entry></entry>
+	  </row>
+	  <row>
+            <entry></entry>
+            <entry></entry>
+	    <entry>__u32</entry>
+	    <entry><structfield>data</structfield>[16]</entry>
+	    <entry>Reserved for future extensions. Drivers and
+applications must set the array to zero.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="decoder-cmds">
+      <title>Decoder Commands</title>
+      <tgroup cols="3">
+	&cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>V4L2_DEC_CMD_START</constant></entry>
+	    <entry>0</entry>
+	    <entry>Start the decoder. When the decoder is already
+running or paused, this command will just change the playback speed.
+That means that calling <constant>V4L2_DEC_CMD_START</constant> when
+the decoder was paused will <emphasis>not</emphasis> resume the decoder.
+You have to explicitly call <constant>V4L2_DEC_CMD_RESUME</constant> for that.
+This command has one flag:
+<constant>V4L2_DEC_CMD_START_MUTE_AUDIO</constant>. If set, then audio will
+be muted when playing back at a non-standard speed.
+            </entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_DEC_CMD_STOP</constant></entry>
+	    <entry>1</entry>
+	    <entry>Stop the decoder. When the decoder is already stopped,
+this command does nothing. This command has two flags:
+if <constant>V4L2_DEC_CMD_STOP_TO_BLACK</constant> is set, then the decoder will
+set the picture to black after it stopped decoding. Otherwise the last image will
+repeat. If <constant>V4L2_DEC_CMD_STOP_IMMEDIATELY</constant> is set, then the decoder
+stops immediately (ignoring the <structfield>pts</structfield> value), otherwise it
+will keep decoding until timestamp >= pts or until the last of the pending data from
+its internal buffers was decoded.
+</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_DEC_CMD_PAUSE</constant></entry>
+	    <entry>2</entry>
+	    <entry>Pause the decoder. When the decoder has not been
+started yet, the driver will return an &EPERM;. When the decoder is
+already paused, this command does nothing. This command has one flag:
+if <constant>V4L2_DEC_CMD_PAUSE_TO_BLACK</constant> is set, then set the
+decoder output to black when paused.
+</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_DEC_CMD_RESUME</constant></entry>
+	    <entry>3</entry>
+	    <entry>Resume decoding after a PAUSE command. When the
+decoder has not been started yet, the driver will return an &EPERM;.
+When the decoder is already running, this command does nothing. No
+flags are defined for this command.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+	<term><errorcode>EINVAL</errorcode></term>
+	<listitem>
+	  <para>The <structfield>cmd</structfield> field is invalid.</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><errorcode>EPERM</errorcode></term>
+	<listitem>
+	  <para>The application sent a PAUSE or RESUME command when
+the decoder was not running.</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml b/Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml
index af7f3f2..f431b3b 100644
--- a/Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml
@@ -74,15 +74,16 @@
 encoding will continue until the end of the current <wordasword>Group
 Of Pictures</wordasword>, otherwise it will stop immediately.</para>
 
-    <para>A <function>read</function>() call sends a START command to
-the encoder if it has not been started yet. After a STOP command,
+    <para>A <function>read</function>() or &VIDIOC-STREAMON; call sends an implicit
+START command to the encoder if it has not been started yet. After a STOP command,
 <function>read</function>() calls will read the remaining data
 buffered by the driver. When the buffer is empty,
 <function>read</function>() will return zero and the next
 <function>read</function>() call will restart the encoder.</para>
 
-    <para>A <function>close</function>() call sends an immediate STOP
-to the encoder, and all buffered data is discarded.</para>
+    <para>A <function>close</function>() or &VIDIOC-STREAMOFF; call of a streaming
+file descriptor sends an implicit immediate STOP to the encoder, and all buffered
+data is discarded.</para>
 
     <para>These ioctls are optional, not all drivers may support
 them. They were introduced in Linux 2.6.21.</para>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml b/Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml
index 01ea24b..4874849 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml
@@ -57,6 +57,11 @@
   <refsect1>
     <title>Description</title>
 
+    <para>These ioctls are <emphasis role="bold">deprecated</emphasis>.
+    New drivers and applications should use <link linkend="jpeg-controls">
+    JPEG class controls</link> for image quality and JPEG markers control.
+    </para>
+
     <para>[to do]</para>
 
     <para>Ronald Bultje elaborates:</para>
@@ -86,7 +91,10 @@
 	  <row>
 	    <entry>int</entry>
 	    <entry><structfield>quality</structfield></entry>
-	    <entry></entry>
+	    <entry>Deprecated. If <link linkend="jpeg-quality-control"><constant>
+	    V4L2_CID_JPEG_IMAGE_QUALITY</constant></link> control is exposed by
+	    a driver applications should use it instead and ignore this field.
+	    </entry>
 	  </row>
 	  <row>
 	    <entry>int</entry>
@@ -116,7 +124,11 @@
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>jpeg_markers</structfield></entry>
-	    <entry>See <xref linkend="jpeg-markers" />.</entry>
+	    <entry>See <xref linkend="jpeg-markers"/>. Deprecated.
+	    If <link linkend="jpeg-active-marker-control"><constant>
+	    V4L2_CID_JPEG_ACTIVE_MARKER</constant></link> control
+	    is exposed by a driver applications should use it instead
+	    and ignore this field.</entry>
 	  </row>
 	</tbody>
       </tgroup>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
index a9d36e0..bb04eff 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
@@ -58,43 +58,43 @@
 
     <para>The ioctls are used to query and configure selection rectangles.</para>
 
-<para> To query the cropping (composing) rectangle set <structfield>
-&v4l2-selection;::type </structfield> to the respective buffer type.  Do not
-use multiplanar buffers.  Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE
+<para> To query the cropping (composing) rectangle set &v4l2-selection;
+<structfield> type </structfield> field to the respective buffer type.
+Do not use multiplanar buffers.  Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE
 </constant> instead of <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
 </constant>.  Use <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> instead of
 <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE </constant>.  The next step is
-setting <structfield> &v4l2-selection;::target </structfield> to value
-<constant> V4L2_SEL_TGT_CROP_ACTIVE </constant> (<constant>
+setting the value of &v4l2-selection; <structfield>target</structfield> field
+to <constant> V4L2_SEL_TGT_CROP_ACTIVE </constant> (<constant>
 V4L2_SEL_TGT_COMPOSE_ACTIVE </constant>).  Please refer to table <xref
 linkend="v4l2-sel-target" /> or <xref linkend="selection-api" /> for additional
-targets.  Fields <structfield> &v4l2-selection;::flags </structfield> and
-<structfield> &v4l2-selection;::reserved </structfield> are ignored and they
-must be filled with zeros.  The driver fills the rest of the structure or
+targets.  The <structfield>flags</structfield> and <structfield>reserved
+</structfield> fields of &v4l2-selection; are ignored and they must be filled
+with zeros.  The driver fills the rest of the structure or
 returns &EINVAL; if incorrect buffer type or target was used. If cropping
 (composing) is not supported then the active rectangle is not mutable and it is
-always equal to the bounds rectangle.  Finally, structure <structfield>
-&v4l2-selection;::r </structfield> is filled with the current cropping
+always equal to the bounds rectangle.  Finally, the &v4l2-rect;
+<structfield>r</structfield> rectangle is filled with the current cropping
 (composing) coordinates. The coordinates are expressed in driver-dependent
 units. The only exception are rectangles for images in raw formats, whose
 coordinates are always expressed in pixels.  </para>
 
-<para> To change the cropping (composing) rectangle set <structfield>
-&v4l2-selection;::type </structfield> to the respective buffer type.  Do not
+<para> To change the cropping (composing) rectangle set the &v4l2-selection;
+<structfield>type</structfield> field to the respective buffer type.  Do not
 use multiplanar buffers.  Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE
 </constant> instead of <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
 </constant>.  Use <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> instead of
 <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE </constant>.  The next step is
-setting <structfield> &v4l2-selection;::target </structfield> to value
-<constant> V4L2_SEL_TGT_CROP_ACTIVE </constant> (<constant>
+setting the value of &v4l2-selection; <structfield>target</structfield> to
+<constant>V4L2_SEL_TGT_CROP_ACTIVE</constant> (<constant>
 V4L2_SEL_TGT_COMPOSE_ACTIVE </constant>). Please refer to table <xref
 linkend="v4l2-sel-target" /> or <xref linkend="selection-api" /> for additional
-targets.  Set desired active area into the field <structfield>
-&v4l2-selection;::r </structfield>.  Field <structfield>
-&v4l2-selection;::reserved </structfield> is ignored and must be filled with
-zeros.  The driver may adjust the rectangle coordinates. An application may
-introduce constraints to control rounding behaviour. Set the field
-<structfield> &v4l2-selection;::flags </structfield> to one of values:
+targets.  The &v4l2-rect; <structfield>r</structfield> rectangle need to be
+set to the desired active area. Field &v4l2-selection; <structfield> reserved
+</structfield> is ignored and must be filled with zeros.  The driver may adjust
+coordinates of the requested rectangle. An application may
+introduce constraints to control rounding behaviour. The &v4l2-selection;
+<structfield>flags</structfield> field must be set to one of the following:
 
 <itemizedlist>
   <listitem>
@@ -129,7 +129,7 @@
 
 <orderedlist>
   <listitem>
-    <para>Satisfy constraints from <structfield>&v4l2-selection;::flags</structfield>.</para>
+    <para>Satisfy constraints from &v4l2-selection; <structfield>flags</structfield>.</para>
   </listitem>
   <listitem>
     <para>Adjust width, height, left, and top to hardware limits and alignments.</para>
@@ -145,7 +145,7 @@
   </listitem>
 </orderedlist>
 
-On success the field <structfield> &v4l2-selection;::r </structfield> contains
+On success the &v4l2-rect; <structfield>r</structfield> field contains
 the adjusted rectangle. When the parameters are unsuitable the application may
 modify the cropping (composing) or image parameters and repeat the cycle until
 satisfactory parameters have been negotiated. If constraints flags have to be
@@ -162,38 +162,38 @@
 	<tbody valign="top">
 	  <row>
             <entry><constant>V4L2_SEL_TGT_CROP_ACTIVE</constant></entry>
-            <entry>0</entry>
-            <entry>area that is currently cropped by hardware</entry>
+            <entry>0x0000</entry>
+            <entry>The area that is currently cropped by hardware.</entry>
 	  </row>
 	  <row>
             <entry><constant>V4L2_SEL_TGT_CROP_DEFAULT</constant></entry>
-            <entry>1</entry>
-            <entry>suggested cropping rectangle that covers the "whole picture"</entry>
+            <entry>0x0001</entry>
+            <entry>Suggested cropping rectangle that covers the "whole picture".</entry>
 	  </row>
 	  <row>
             <entry><constant>V4L2_SEL_TGT_CROP_BOUNDS</constant></entry>
-            <entry>2</entry>
-            <entry>limits for the cropping rectangle</entry>
+            <entry>0x0002</entry>
+            <entry>Limits for the cropping rectangle.</entry>
 	  </row>
 	  <row>
             <entry><constant>V4L2_SEL_TGT_COMPOSE_ACTIVE</constant></entry>
-            <entry>256</entry>
-            <entry>area to which data are composed by hardware</entry>
+            <entry>0x0100</entry>
+            <entry>The area to which data is composed by hardware.</entry>
 	  </row>
 	  <row>
             <entry><constant>V4L2_SEL_TGT_COMPOSE_DEFAULT</constant></entry>
-            <entry>257</entry>
-            <entry>suggested composing rectangle that covers the "whole picture"</entry>
+            <entry>0x0101</entry>
+            <entry>Suggested composing rectangle that covers the "whole picture".</entry>
 	  </row>
 	  <row>
             <entry><constant>V4L2_SEL_TGT_COMPOSE_BOUNDS</constant></entry>
-            <entry>258</entry>
-            <entry>limits for the composing rectangle</entry>
+            <entry>0x0102</entry>
+            <entry>Limits for the composing rectangle.</entry>
 	  </row>
 	  <row>
             <entry><constant>V4L2_SEL_TGT_COMPOSE_PADDED</constant></entry>
-            <entry>259</entry>
-            <entry>the active area and all padding pixels that are inserted or modified by the hardware</entry>
+            <entry>0x0103</entry>
+            <entry>The active area and all padding pixels that are inserted or modified by hardware.</entry>
 	  </row>
 	</tbody>
       </tgroup>
@@ -209,12 +209,14 @@
 	  <row>
             <entry><constant>V4L2_SEL_FLAG_GE</constant></entry>
             <entry>0x00000001</entry>
-            <entry>indicate that adjusted rectangle must contain a rectangle from <structfield>&v4l2-selection;::r</structfield></entry>
+            <entry>Indicates that the adjusted rectangle must contain the original
+	    &v4l2-selection; <structfield>r</structfield> rectangle.</entry>
 	  </row>
 	  <row>
             <entry><constant>V4L2_SEL_FLAG_LE</constant></entry>
             <entry>0x00000002</entry>
-            <entry>indicate that adjusted rectangle must be inside a rectangle from <structfield>&v4l2-selection;::r</structfield></entry>
+            <entry>Indicates that the adjusted rectangle must be inside the original
+	    &v4l2-rect; <structfield>r</structfield> rectangle.</entry>
 	  </row>
 	</tbody>
       </tgroup>
@@ -245,27 +247,29 @@
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>type</structfield></entry>
-	    <entry>Type of the buffer (from &v4l2-buf-type;)</entry>
+	    <entry>Type of the buffer (from &v4l2-buf-type;).</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>target</structfield></entry>
-            <entry>used to select between <link linkend="v4l2-sel-target"> cropping and composing rectangles </link></entry>
+            <entry>Used to select between <link linkend="v4l2-sel-target"> cropping
+	    and composing rectangles</link>.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>flags</structfield></entry>
-            <entry>control over coordinates adjustments, refer to <link linkend="v4l2-sel-flags">selection flags</link></entry>
+            <entry>Flags controlling the selection rectangle adjustments, refer to
+	    <link linkend="v4l2-sel-flags">selection flags</link>.</entry>
 	  </row>
 	  <row>
 	    <entry>&v4l2-rect;</entry>
 	    <entry><structfield>r</structfield></entry>
-	    <entry>selection rectangle</entry>
+	    <entry>The selection rectangle.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>reserved[9]</structfield></entry>
-	    <entry>Reserved fields for future use</entry>
+	    <entry>Reserved fields for future use.</entry>
 	  </row>
 	</tbody>
       </tgroup>
@@ -278,24 +282,24 @@
       <varlistentry>
 	<term><errorcode>EINVAL</errorcode></term>
 	<listitem>
-	  <para>The buffer <structfield> &v4l2-selection;::type </structfield>
-or <structfield> &v4l2-selection;::target </structfield> is not supported, or
-the <structfield> &v4l2-selection;::flags </structfield> are invalid.</para>
+	  <para>Given buffer type <structfield>type</structfield> or
+the selection target <structfield>target</structfield> is not supported,
+or the <structfield>flags</structfield> argument is not valid.</para>
 	</listitem>
       </varlistentry>
       <varlistentry>
 	<term><errorcode>ERANGE</errorcode></term>
 	<listitem>
-	  <para>it is not possible to adjust a rectangle <structfield>
-&v4l2-selection;::r </structfield> that satisfies all contraints from
-<structfield> &v4l2-selection;::flags </structfield>.</para>
+	  <para>It is not possible to adjust &v4l2-rect; <structfield>
+r</structfield> rectangle to satisfy all contraints given in the
+<structfield>flags</structfield> argument.</para>
 	</listitem>
       </varlistentry>
       <varlistentry>
 	<term><errorcode>EBUSY</errorcode></term>
 	<listitem>
-	  <para>it is not possible to apply change of selection rectangle at the moment.
-Usually because streaming is in progress.</para>
+	  <para>It is not possible to apply change of the selection rectangle
+at the moment. Usually because streaming is in progress.</para>
 	</listitem>
       </varlistentry>
     </variablelist>
diff --git a/Documentation/DocBook/media/v4l/vidioc-querycap.xml b/Documentation/DocBook/media/v4l/vidioc-querycap.xml
index e3664d6..4643505 100644
--- a/Documentation/DocBook/media/v4l/vidioc-querycap.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-querycap.xml
@@ -124,12 +124,35 @@
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>capabilities</structfield></entry>
-	    <entry>Device capabilities, see <xref
-		linkend="device-capabilities" />.</entry>
+	    <entry>Available capabilities of the physical device as a whole, see <xref
+		linkend="device-capabilities" />. The same physical device can export
+		multiple devices in /dev (e.g. /dev/videoX, /dev/vbiY and /dev/radioZ).
+		The <structfield>capabilities</structfield> field should contain a union
+		of all capabilities available around the several V4L2 devices exported
+		to userspace.
+		For all those devices the <structfield>capabilities</structfield> field
+		returns the same set of	capabilities. This allows applications to open
+		just one of the devices (typically the video device) and discover whether
+		video, vbi and/or radio are also supported.
+	    </entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
-	    <entry><structfield>reserved</structfield>[4]</entry>
+	    <entry><structfield>device_caps</structfield></entry>
+	    <entry>Device capabilities of the opened device, see <xref
+		linkend="device-capabilities" />. Should contain the available capabilities
+		of that specific device node. So, for example, <structfield>device_caps</structfield>
+		of a radio device will only contain radio related capabilities and
+		no video or vbi capabilities. This field is only set if the <structfield>capabilities</structfield>
+		field contains the <constant>V4L2_CAP_DEVICE_CAPS</constant> capability.
+		Only the <structfield>capabilities</structfield> field can have the
+		<constant>V4L2_CAP_DEVICE_CAPS</constant> capability, <structfield>device_caps</structfield>
+		will never set <constant>V4L2_CAP_DEVICE_CAPS</constant>.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[3]</entry>
 	    <entry>Reserved for future extensions. Drivers must set
 this array to zero.</entry>
 	  </row>
@@ -276,6 +299,13 @@
 	    <entry>The device supports the <link
 linkend="mmap">streaming</link> I/O method.</entry>
 	  </row>
+	  <row>
+	    <entry><constant>V4L2_CAP_DEVICE_CAPS</constant></entry>
+	    <entry>0x80000000</entry>
+	    <entry>The driver fills the <structfield>device_caps</structfield>
+	    field. This capability can only appear in the <structfield>capabilities</structfield>
+	    field and never in the <structfield>device_caps</structfield> field.</entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>
diff --git a/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml b/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
index e013da8..18b1a82 100644
--- a/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
@@ -96,8 +96,8 @@
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>reserved</structfield>[7]</entry>
-	    <entry>Reserved for future extensions. Drivers and
-	    applications must set the array to zero.</entry>
+	    <entry>Reserved for future extensions. Applications
+	    must set the array to zero.</entry>
 	  </row>
 	</tbody>
       </tgroup>
@@ -112,7 +112,7 @@
 	<term><errorcode>EINVAL</errorcode></term>
 	<listitem>
 	  <para>The <structfield>tuner</structfield> index is out of
-bounds or the value in the <structfield>type</structfield> field is
+bounds, the wrap_around value is not supported or the value in the <structfield>type</structfield> field is
 wrong.</para>
 	</listitem>
       </varlistentry>
diff --git a/Documentation/EDID/1024x768.S b/Documentation/EDID/1024x768.S
new file mode 100644
index 0000000..4b486fe
--- /dev/null
+++ b/Documentation/EDID/1024x768.S
@@ -0,0 +1,44 @@
+/*
+   1024x768.S: EDID data set for standard 1024x768 60 Hz monitor
+
+   Copyright (C) 2011 Carsten Emde <C.Emde@osadl.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.
+
+   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.
+*/
+
+/* EDID */
+#define VERSION 1
+#define REVISION 3
+
+/* Display */
+#define CLOCK 65000 /* kHz */
+#define XPIX 1024
+#define YPIX 768
+#define XY_RATIO XY_RATIO_4_3
+#define XBLANK 320
+#define YBLANK 38
+#define XOFFSET 8
+#define XPULSE 144
+#define YOFFSET (63+3)
+#define YPULSE (63+6)
+#define DPI 72
+#define VFREQ 60 /* Hz */
+#define TIMING_NAME "Linux XGA"
+#define ESTABLISHED_TIMINGS_BITS 0x08 /* Bit 3 -> 1024x768 @60 Hz */
+#define HSYNC_POL 0
+#define VSYNC_POL 0
+#define CRC 0x55
+
+#include "edid.S"
diff --git a/Documentation/EDID/1280x1024.S b/Documentation/EDID/1280x1024.S
new file mode 100644
index 0000000..a2799fe
--- /dev/null
+++ b/Documentation/EDID/1280x1024.S
@@ -0,0 +1,44 @@
+/*
+   1280x1024.S: EDID data set for standard 1280x1024 60 Hz monitor
+
+   Copyright (C) 2011 Carsten Emde <C.Emde@osadl.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.
+
+   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.
+*/
+
+/* EDID */
+#define VERSION 1
+#define REVISION 3
+
+/* Display */
+#define CLOCK 108000 /* kHz */
+#define XPIX 1280
+#define YPIX 1024
+#define XY_RATIO XY_RATIO_5_4
+#define XBLANK 408
+#define YBLANK 42
+#define XOFFSET 48
+#define XPULSE 112
+#define YOFFSET (63+1)
+#define YPULSE (63+3)
+#define DPI 72
+#define VFREQ 60 /* Hz */
+#define TIMING_NAME "Linux SXGA"
+#define ESTABLISHED_TIMINGS_BITS 0x00 /* none */
+#define HSYNC_POL 1
+#define VSYNC_POL 1
+#define CRC 0xa0
+
+#include "edid.S"
diff --git a/Documentation/EDID/1680x1050.S b/Documentation/EDID/1680x1050.S
new file mode 100644
index 0000000..96f67ca
--- /dev/null
+++ b/Documentation/EDID/1680x1050.S
@@ -0,0 +1,44 @@
+/*
+   1680x1050.S: EDID data set for standard 1680x1050 60 Hz monitor
+
+   Copyright (C) 2012 Carsten Emde <C.Emde@osadl.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.
+
+   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.
+*/
+
+/* EDID */
+#define VERSION 1
+#define REVISION 3
+
+/* Display */
+#define CLOCK 146250 /* kHz */
+#define XPIX 1680
+#define YPIX 1050
+#define XY_RATIO XY_RATIO_16_10
+#define XBLANK 560
+#define YBLANK 39
+#define XOFFSET 104
+#define XPULSE 176
+#define YOFFSET (63+3)
+#define YPULSE (63+6)
+#define DPI 96
+#define VFREQ 60 /* Hz */
+#define TIMING_NAME "Linux WSXGA"
+#define ESTABLISHED_TIMINGS_BITS 0x00 /* none */
+#define HSYNC_POL 1
+#define VSYNC_POL 1
+#define CRC 0x26
+
+#include "edid.S"
diff --git a/Documentation/EDID/1920x1080.S b/Documentation/EDID/1920x1080.S
new file mode 100644
index 0000000..36ed5d5
--- /dev/null
+++ b/Documentation/EDID/1920x1080.S
@@ -0,0 +1,44 @@
+/*
+   1920x1080.S: EDID data set for standard 1920x1080 60 Hz monitor
+
+   Copyright (C) 2012 Carsten Emde <C.Emde@osadl.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.
+
+   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.
+*/
+
+/* EDID */
+#define VERSION 1
+#define REVISION 3
+
+/* Display */
+#define CLOCK 148500 /* kHz */
+#define XPIX 1920
+#define YPIX 1080
+#define XY_RATIO XY_RATIO_16_9
+#define XBLANK 280
+#define YBLANK 45
+#define XOFFSET 88
+#define XPULSE 44
+#define YOFFSET (63+4)
+#define YPULSE (63+5)
+#define DPI 96
+#define VFREQ 60 /* Hz */
+#define TIMING_NAME "Linux FHD"
+#define ESTABLISHED_TIMINGS_BITS 0x00 /* none */
+#define HSYNC_POL 1
+#define VSYNC_POL 1
+#define CRC 0x05
+
+#include "edid.S"
diff --git a/Documentation/EDID/HOWTO.txt b/Documentation/EDID/HOWTO.txt
new file mode 100644
index 0000000..75a9f2a
--- /dev/null
+++ b/Documentation/EDID/HOWTO.txt
@@ -0,0 +1,39 @@
+In the good old days when graphics parameters were configured explicitly
+in a file called xorg.conf, even broken hardware could be managed.
+
+Today, with the advent of Kernel Mode Setting, a graphics board is
+either correctly working because all components follow the standards -
+or the computer is unusable, because the screen remains dark after
+booting or it displays the wrong area. Cases when this happens are:
+- The graphics board does not recognize the monitor.
+- The graphics board is unable to detect any EDID data.
+- The graphics board incorrectly forwards EDID data to the driver.
+- The monitor sends no or bogus EDID data.
+- A KVM sends its own EDID data instead of querying the connected monitor.
+Adding the kernel parameter "nomodeset" helps in most cases, but causes
+restrictions later on.
+
+As a remedy for such situations, the kernel configuration item
+CONFIG_DRM_LOAD_EDID_FIRMWARE was introduced. It allows to provide an
+individually prepared or corrected EDID data set in the /lib/firmware
+directory from where it is loaded via the firmware interface. The code
+(see drivers/gpu/drm/drm_edid_load.c) contains built-in data sets for
+commonly used screen resolutions (1024x768, 1280x1024, 1680x1050,
+1920x1080) as binary blobs, but the kernel source tree does not contain
+code to create these data. In order to elucidate the origin of the
+built-in binary EDID blobs and to facilitate the creation of individual
+data for a specific misbehaving monitor, commented sources and a
+Makefile environment are given here.
+
+To create binary EDID and C source code files from the existing data
+material, simply type "make".
+
+If you want to create your own EDID file, copy the file 1024x768.S and
+replace the settings with your own data. The CRC value in the last line
+  #define CRC 0x55
+is a bit tricky. After a first version of the binary data set is
+created, it must be be checked with the "edid-decode" utility which will
+most probably complain about a wrong CRC. Fortunately, the utility also
+displays the correct CRC which must then be inserted into the source
+file. After the make procedure is repeated, the EDID data set is ready
+to be used.
diff --git a/Documentation/EDID/Makefile b/Documentation/EDID/Makefile
new file mode 100644
index 0000000..17763ca
--- /dev/null
+++ b/Documentation/EDID/Makefile
@@ -0,0 +1,26 @@
+
+SOURCES	:= $(wildcard [0-9]*x[0-9]*.S)
+
+BIN	:= $(patsubst %.S, %.bin, $(SOURCES))
+
+IHEX	:= $(patsubst %.S, %.bin.ihex, $(SOURCES))
+
+CODE	:= $(patsubst %.S, %.c, $(SOURCES))
+
+all:	$(BIN) $(IHEX) $(CODE)
+
+clean:
+	@rm -f *.o *.bin.ihex *.bin *.c
+
+%.o:	%.S
+	@cc -c $^
+
+%.bin:	%.o
+	@objcopy -Obinary $^ $@
+
+%.bin.ihex:	%.o
+	@objcopy -Oihex $^ $@
+	@dos2unix $@ 2>/dev/null
+
+%.c:	%.bin
+	@echo "{" >$@; hexdump -f hex $^ >>$@; echo "};" >>$@
diff --git a/Documentation/EDID/edid.S b/Documentation/EDID/edid.S
new file mode 100644
index 0000000..ea97ae2
--- /dev/null
+++ b/Documentation/EDID/edid.S
@@ -0,0 +1,261 @@
+/*
+   edid.S: EDID data template
+
+   Copyright (C) 2012 Carsten Emde <C.Emde@osadl.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.
+
+   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.
+*/
+
+
+/* Manufacturer */
+#define MFG_LNX1 'L'
+#define MFG_LNX2 'N'
+#define MFG_LNX3 'X'
+#define SERIAL 0
+#define YEAR 2012
+#define WEEK 5
+
+/* EDID 1.3 standard definitions */
+#define XY_RATIO_16_10	0b00
+#define XY_RATIO_4_3	0b01
+#define XY_RATIO_5_4	0b10
+#define XY_RATIO_16_9	0b11
+
+#define mfgname2id(v1,v2,v3) \
+	((((v1-'@')&0x1f)<<10)+(((v2-'@')&0x1f)<<5)+((v3-'@')&0x1f))
+#define swap16(v1) ((v1>>8)+((v1&0xff)<<8))
+#define msbs2(v1,v2) ((((v1>>8)&0x0f)<<4)+((v2>>8)&0x0f))
+#define msbs4(v1,v2,v3,v4) \
+	(((v1&0x03)>>2)+((v2&0x03)>>4)+((v3&0x03)>>6)+((v4&0x03)>>8))
+#define pixdpi2mm(pix,dpi) ((pix*25)/dpi)
+#define xsize pixdpi2mm(XPIX,DPI)
+#define ysize pixdpi2mm(YPIX,DPI)
+
+		.data
+
+/* Fixed header pattern */
+header:		.byte	0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x00
+
+mfg_id:		.word	swap16(mfgname2id(MFG_LNX1, MFG_LNX2, MFG_LNX3))
+
+prod_code:	.word	0
+
+/* Serial number. 32 bits, little endian. */
+serial_number:	.long	SERIAL
+
+/* Week of manufacture */
+week:		.byte	WEEK
+
+/* Year of manufacture, less 1990. (1990-2245)
+   If week=255, it is the model year instead */
+year:		.byte	YEAR-1990
+
+version:	.byte	VERSION 	/* EDID version, usually 1 (for 1.3) */
+revision:	.byte	REVISION	/* EDID revision, usually 3 (for 1.3) */
+
+/* If Bit 7=1	Digital input. If set, the following bit definitions apply:
+     Bits 6-1	Reserved, must be 0
+     Bit 0	Signal is compatible with VESA DFP 1.x TMDS CRGB,
+		  1 pixel per clock, up to 8 bits per color, MSB aligned,
+   If Bit 7=0	Analog input. If clear, the following bit definitions apply:
+     Bits 6-5	Video white and sync levels, relative to blank
+		  00=+0.7/-0.3 V; 01=+0.714/-0.286 V;
+		  10=+1.0/-0.4 V; 11=+0.7/0 V
+   Bit 4	Blank-to-black setup (pedestal) expected
+   Bit 3	Separate sync supported
+   Bit 2	Composite sync (on HSync) supported
+   Bit 1	Sync on green supported
+   Bit 0	VSync pulse must be serrated when somposite or
+		  sync-on-green is used. */
+video_parms:	.byte	0x6d
+
+/* Maximum horizontal image size, in centimetres
+   (max 292 cm/115 in at 16:9 aspect ratio) */
+max_hor_size:	.byte	xsize/10
+
+/* Maximum vertical image size, in centimetres.
+   If either byte is 0, undefined (e.g. projector) */
+max_vert_size:	.byte	ysize/10
+
+/* Display gamma, minus 1, times 100 (range 1.00-3.5 */
+gamma:		.byte	120
+
+/* Bit 7	DPMS standby supported
+   Bit 6	DPMS suspend supported
+   Bit 5	DPMS active-off supported
+   Bits 4-3	Display type: 00=monochrome; 01=RGB colour;
+		  10=non-RGB multicolour; 11=undefined
+   Bit 2	Standard sRGB colour space. Bytes 25-34 must contain
+		  sRGB standard values.
+   Bit 1	Preferred timing mode specified in descriptor block 1.
+   Bit 0	GTF supported with default parameter values. */
+dsp_features:	.byte	0xea
+
+/* Chromaticity coordinates. */
+/* Red and green least-significant bits
+   Bits 7-6	Red x value least-significant 2 bits
+   Bits 5-4	Red y value least-significant 2 bits
+   Bits 3-2	Green x value lst-significant 2 bits
+   Bits 1-0	Green y value least-significant 2 bits */
+red_green_lsb:	.byte	0x5e
+
+/* Blue and white least-significant 2 bits */
+blue_white_lsb:	.byte	0xc0
+
+/* Red x value most significant 8 bits.
+   0-255 encodes 0-0.996 (255/256); 0-0.999 (1023/1024) with lsbits */
+red_x_msb:	.byte	0xa4
+
+/* Red y value most significant 8 bits */
+red_y_msb:	.byte	0x59
+
+/* Green x and y value most significant 8 bits */
+green_x_y_msb:	.byte	0x4a,0x98
+
+/* Blue x and y value most significant 8 bits */
+blue_x_y_msb:	.byte	0x25,0x20
+
+/* Default white point x and y value most significant 8 bits */
+white_x_y_msb:	.byte	0x50,0x54
+
+/* Established timings */
+/* Bit 7	720x400 @ 70 Hz
+   Bit 6	720x400 @ 88 Hz
+   Bit 5	640x480 @ 60 Hz
+   Bit 4	640x480 @ 67 Hz
+   Bit 3	640x480 @ 72 Hz
+   Bit 2	640x480 @ 75 Hz
+   Bit 1	800x600 @ 56 Hz
+   Bit 0	800x600 @ 60 Hz */
+estbl_timing1:	.byte	0x00
+
+/* Bit 7	800x600 @ 72 Hz
+   Bit 6	800x600 @ 75 Hz
+   Bit 5	832x624 @ 75 Hz
+   Bit 4	1024x768 @ 87 Hz, interlaced (1024x768)
+   Bit 3	1024x768 @ 60 Hz
+   Bit 2	1024x768 @ 72 Hz
+   Bit 1	1024x768 @ 75 Hz
+   Bit 0	1280x1024 @ 75 Hz */
+estbl_timing2:	.byte	ESTABLISHED_TIMINGS_BITS
+
+/* Bit 7	1152x870 @ 75 Hz (Apple Macintosh II)
+   Bits 6-0 	Other manufacturer-specific display mod */
+estbl_timing3:	.byte	0x00
+
+/* Standard timing */
+/* X resolution, less 31, divided by 8 (256-2288 pixels) */
+std_xres:	.byte	(XPIX/8)-31
+/* Y resolution, X:Y pixel ratio
+   Bits 7-6	X:Y pixel ratio: 00=16:10; 01=4:3; 10=5:4; 11=16:9.
+   Bits 5-0	Vertical frequency, less 60 (60-123 Hz) */
+std_vres:	.byte	(XY_RATIO<<6)+VFREQ-60
+		.fill	7,2,0x0101	/* Unused */
+
+descriptor1:
+/* Pixel clock in 10 kHz units. (0.-655.35 MHz, little-endian) */
+clock:		.word	CLOCK/10
+
+/* Horizontal active pixels 8 lsbits (0-4095) */
+x_act_lsb:	.byte	XPIX&0xff
+/* Horizontal blanking pixels 8 lsbits (0-4095)
+   End of active to start of next active. */
+x_blk_lsb:	.byte	XBLANK&0xff
+/* Bits 7-4 	Horizontal active pixels 4 msbits
+   Bits 3-0	Horizontal blanking pixels 4 msbits */
+x_msbs:		.byte	msbs2(XPIX,XBLANK)
+
+/* Vertical active lines 8 lsbits (0-4095) */
+y_act_lsb:	.byte	YPIX&0xff
+/* Vertical blanking lines 8 lsbits (0-4095) */
+y_blk_lsb:	.byte	YBLANK&0xff
+/* Bits 7-4 	Vertical active lines 4 msbits
+   Bits 3-0 	Vertical blanking lines 4 msbits */
+y_msbs:		.byte	msbs2(YPIX,YBLANK)
+
+/* Horizontal sync offset pixels 8 lsbits (0-1023) From blanking start */
+x_snc_off_lsb:	.byte	XOFFSET&0xff
+/* Horizontal sync pulse width pixels 8 lsbits (0-1023) */
+x_snc_pls_lsb:	.byte	XPULSE&0xff
+/* Bits 7-4 	Vertical sync offset lines 4 lsbits -63)
+   Bits 3-0 	Vertical sync pulse width lines 4 lsbits -63) */
+y_snc_lsb:	.byte	((YOFFSET-63)<<4)+(YPULSE-63)
+/* Bits 7-6 	Horizontal sync offset pixels 2 msbits
+   Bits 5-4 	Horizontal sync pulse width pixels 2 msbits
+   Bits 3-2 	Vertical sync offset lines 2 msbits
+   Bits 1-0 	Vertical sync pulse width lines 2 msbits */
+xy_snc_msbs:	.byte	msbs4(XOFFSET,XPULSE,YOFFSET,YPULSE)
+
+/* Horizontal display size, mm, 8 lsbits (0-4095 mm, 161 in) */
+x_dsp_size:	.byte	xsize&0xff
+
+/* Vertical display size, mm, 8 lsbits (0-4095 mm, 161 in) */
+y_dsp_size:	.byte	ysize&0xff
+
+/* Bits 7-4 	Horizontal display size, mm, 4 msbits
+   Bits 3-0 	Vertical display size, mm, 4 msbits */
+dsp_size_mbsb:	.byte	msbs2(xsize,ysize)
+
+/* Horizontal border pixels (each side; total is twice this) */
+x_border:	.byte	0
+/* Vertical border lines (each side; total is twice this) */
+y_border:	.byte	0
+
+/* Bit 7 	Interlaced
+   Bits 6-5 	Stereo mode: 00=No stereo; other values depend on bit 0:
+   Bit 0=0: 01=Field sequential, sync=1 during right; 10=similar,
+     sync=1 during left; 11=4-way interleaved stereo
+   Bit 0=1 2-way interleaved stereo: 01=Right image on even lines;
+     10=Left image on even lines; 11=side-by-side
+   Bits 4-3 	Sync type: 00=Analog composite; 01=Bipolar analog composite;
+     10=Digital composite (on HSync); 11=Digital separate
+   Bit 2 	If digital separate: Vertical sync polarity (1=positive)
+   Other types: VSync serrated (HSync during VSync)
+   Bit 1 	If analog sync: Sync on all 3 RGB lines (else green only)
+   Digital: HSync polarity (1=positive)
+   Bit 0 	2-way line-interleaved stereo, if bits 4-3 are not 00. */
+features:	.byte	0x18+(VSYNC_POL<<2)+(HSYNC_POL<<1)
+
+descriptor2:	.byte	0,0	/* Not a detailed timing descriptor */
+		.byte	0	/* Must be zero */
+		.byte	0xff	/* Descriptor is monitor serial number (text) */
+		.byte	0	/* Must be zero */
+start1:		.ascii	"Linux #0"
+end1:		.byte	0x0a	/* End marker */
+		.fill	12-(end1-start1), 1, 0x20 /* Padded spaces */
+descriptor3:	.byte	0,0	/* Not a detailed timing descriptor */
+		.byte	0	/* Must be zero */
+		.byte	0xfd	/* Descriptor is monitor range limits */
+		.byte	0	/* Must be zero */
+start2:		.byte	VFREQ-1	/* Minimum vertical field rate (1-255 Hz) */
+		.byte	VFREQ+1	/* Maximum vertical field rate (1-255 Hz) */
+		.byte	(CLOCK/(XPIX+XBLANK))-1 /* Minimum horizontal line rate
+						    (1-255 kHz) */
+		.byte	(CLOCK/(XPIX+XBLANK))+1 /* Maximum horizontal line rate
+						    (1-255 kHz) */
+		.byte	(CLOCK/10000)+1	/* Maximum pixel clock rate, rounded up
+					   to 10 MHz multiple (10-2550 MHz) */
+		.byte	0	/* No extended timing information type */
+end2:		.byte	0x0a	/* End marker */
+		.fill	12-(end2-start2), 1, 0x20 /* Padded spaces */
+descriptor4:	.byte	0,0	/* Not a detailed timing descriptor */
+		.byte	0	/* Must be zero */
+		.byte	0xfc	/* Descriptor is text */
+		.byte	0	/* Must be zero */
+start3:		.ascii	TIMING_NAME
+end3:		.byte	0x0a	/* End marker */
+		.fill	12-(end3-start3), 1, 0x20 /* Padded spaces */
+extensions:	.byte	0	/* Number of extensions to follow */
+checksum:	.byte	CRC	/* Sum of all bytes must be 0 */
diff --git a/Documentation/EDID/hex b/Documentation/EDID/hex
new file mode 100644
index 0000000..8873ebb
--- /dev/null
+++ b/Documentation/EDID/hex
@@ -0,0 +1 @@
+"\t" 8/1 "0x%02x, " "\n"
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 9b4bc5c..30b656e 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -1,3 +1,3 @@
 obj-m := DocBook/ accounting/ auxdisplay/ connector/ \
 	filesystems/ filesystems/configfs/ ia64/ laptops/ networking/ \
-	pcmcia/ spi/ timers/ vm/ watchdog/src/
+	pcmcia/ spi/ timers/ watchdog/src/
diff --git a/Documentation/acpi/apei/einj.txt b/Documentation/acpi/apei/einj.txt
index e7cc363..e20b6da 100644
--- a/Documentation/acpi/apei/einj.txt
+++ b/Documentation/acpi/apei/einj.txt
@@ -53,6 +53,14 @@
   This file is used to set the second error parameter value. Effect of
   parameter depends on error_type specified.
 
+- notrigger
+  The EINJ mechanism is a two step process. First inject the error, then
+  perform some actions to trigger it. Setting "notrigger" to 1 skips the
+  trigger phase, which *may* allow the user to cause the error in some other
+  context by a simple access to the cpu, memory location, or device that is
+  the target of the error injection. Whether this actually works depends
+  on what operations the BIOS actually includes in the trigger phase.
+
 BIOS versions based in the ACPI 4.0 specification have limited options
 to control where the errors are injected.  Your BIOS may support an
 extension (enabled with the param_extension=1 module parameter, or
diff --git a/Documentation/aoe/aoe.txt b/Documentation/aoe/aoe.txt
index b5aada9..5f5aa16 100644
--- a/Documentation/aoe/aoe.txt
+++ b/Documentation/aoe/aoe.txt
@@ -35,7 +35,7 @@
     sh Documentation/aoe/mkshelf.sh /dev/etherd 0
 
   There is also an autoload script that shows how to edit
-  /etc/modprobe.conf to ensure that the aoe module is loaded when
+  /etc/modprobe.d/aoe.conf to ensure that the aoe module is loaded when
   necessary.
 
 USING DEVICE NODES
diff --git a/Documentation/aoe/autoload.sh b/Documentation/aoe/autoload.sh
index 78dad13..815dff4 100644
--- a/Documentation/aoe/autoload.sh
+++ b/Documentation/aoe/autoload.sh
@@ -1,8 +1,8 @@
 #!/bin/sh
 # set aoe to autoload by installing the
-# aliases in /etc/modprobe.conf
+# aliases in /etc/modprobe.d/
 
-f=/etc/modprobe.conf
+f=/etc/modprobe.d/aoe.conf
 
 if test ! -r $f || test ! -w $f; then
 	echo "cannot configure $f for module autoloading" 1>&2
diff --git a/Documentation/backlight/lp855x-driver.txt b/Documentation/backlight/lp855x-driver.txt
new file mode 100644
index 0000000..f5e4caa
--- /dev/null
+++ b/Documentation/backlight/lp855x-driver.txt
@@ -0,0 +1,78 @@
+Kernel driver lp855x
+====================
+
+Backlight driver for LP855x ICs
+
+Supported chips:
+	Texas Instruments LP8550, LP8551, LP8552, LP8553 and LP8556
+
+Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+
+Description
+-----------
+
+* Brightness control
+
+Brightness can be controlled by the pwm input or the i2c command.
+The lp855x driver supports both cases.
+
+* Device attributes
+
+1) bl_ctl_mode
+Backlight control mode.
+Value : pwm based or register based
+
+2) chip_id
+The lp855x chip id.
+Value : lp8550/lp8551/lp8552/lp8553/lp8556
+
+Platform data for lp855x
+------------------------
+
+For supporting platform specific data, the lp855x platform data can be used.
+
+* name : Backlight driver name. If it is not defined, default name is set.
+* mode : Brightness control mode. PWM or register based.
+* device_control : Value of DEVICE CONTROL register.
+* initial_brightness : Initial value of backlight brightness.
+* pwm_data : Platform specific pwm generation functions.
+	     Only valid when brightness is pwm input mode.
+	     Functions should be implemented by PWM driver.
+	     - pwm_set_intensity() : set duty of PWM
+	     - pwm_get_intensity() : get current duty of PWM
+* load_new_rom_data :
+	0 : use default configuration data
+	1 : update values of eeprom or eprom registers on loading driver
+* size_program : Total size of lp855x_rom_data.
+* rom_data : List of new eeprom/eprom registers.
+
+example 1) lp8552 platform data : i2c register mode with new eeprom data
+
+#define EEPROM_A5_ADDR	0xA5
+#define EEPROM_A5_VAL	0x4f	/* EN_VSYNC=0 */
+
+static struct lp855x_rom_data lp8552_eeprom_arr[] = {
+	{EEPROM_A5_ADDR, EEPROM_A5_VAL},
+};
+
+static struct lp855x_platform_data lp8552_pdata = {
+	.name = "lcd-bl",
+	.mode = REGISTER_BASED,
+	.device_control = I2C_CONFIG(LP8552),
+	.initial_brightness = INITIAL_BRT,
+	.load_new_rom_data = 1,
+	.size_program = ARRAY_SIZE(lp8552_eeprom_arr),
+	.rom_data = lp8552_eeprom_arr,
+};
+
+example 2) lp8556 platform data : pwm input mode with default rom data
+
+static struct lp855x_platform_data lp8556_pdata = {
+	.mode = PWM_BASED,
+	.device_control = PWM_CONFIG(LP8556),
+	.initial_brightness = INITIAL_BRT,
+	.pwm_data = {
+		     .pwm_set_intensity = platform_pwm_set_intensity,
+		     .pwm_get_intensity = platform_pwm_get_intensity,
+		     },
+};
diff --git a/Documentation/blockdev/floppy.txt b/Documentation/blockdev/floppy.txt
index 6ccab88..470fe4b 100644
--- a/Documentation/blockdev/floppy.txt
+++ b/Documentation/blockdev/floppy.txt
@@ -49,7 +49,7 @@
 
  options floppy omnibook messages
 
-in /etc/modprobe.conf.
+in a configuration file in /etc/modprobe.d/.
 
 
  The floppy driver related options are:
diff --git a/Documentation/cgroups/cpusets.txt b/Documentation/cgroups/cpusets.txt
index 5c51ed4..cefd3d8 100644
--- a/Documentation/cgroups/cpusets.txt
+++ b/Documentation/cgroups/cpusets.txt
@@ -217,7 +217,7 @@
 
 The cpus and mems files in the root (top_cpuset) cpuset are
 read-only.  The cpus file automatically tracks the value of
-cpu_online_map using a CPU hotplug notifier, and the mems file
+cpu_online_mask using a CPU hotplug notifier, and the mems file
 automatically tracks the value of node_states[N_HIGH_MEMORY]--i.e.,
 nodes with memory--using the cpuset_track_online_nodes() hook.
 
diff --git a/Documentation/clk.txt b/Documentation/clk.txt
new file mode 100644
index 0000000..1943fae
--- /dev/null
+++ b/Documentation/clk.txt
@@ -0,0 +1,233 @@
+		The Common Clk Framework
+		Mike Turquette <mturquette@ti.com>
+
+This document endeavours to explain the common clk framework details,
+and how to port a platform over to this framework.  It is not yet a
+detailed explanation of the clock api in include/linux/clk.h, but
+perhaps someday it will include that information.
+
+	Part 1 - introduction and interface split
+
+The common clk framework is an interface to control the clock nodes
+available on various devices today.  This may come in the form of clock
+gating, rate adjustment, muxing or other operations.  This framework is
+enabled with the CONFIG_COMMON_CLK option.
+
+The interface itself is divided into two halves, each shielded from the
+details of its counterpart.  First is the common definition of struct
+clk which unifies the framework-level accounting and infrastructure that
+has traditionally been duplicated across a variety of platforms.  Second
+is a common implementation of the clk.h api, defined in
+drivers/clk/clk.c.  Finally there is struct clk_ops, whose operations
+are invoked by the clk api implementation.
+
+The second half of the interface is comprised of the hardware-specific
+callbacks registered with struct clk_ops and the corresponding
+hardware-specific structures needed to model a particular clock.  For
+the remainder of this document any reference to a callback in struct
+clk_ops, such as .enable or .set_rate, implies the hardware-specific
+implementation of that code.  Likewise, references to struct clk_foo
+serve as a convenient shorthand for the implementation of the
+hardware-specific bits for the hypothetical "foo" hardware.
+
+Tying the two halves of this interface together is struct clk_hw, which
+is defined in struct clk_foo and pointed to within struct clk.  This
+allows easy for navigation between the two discrete halves of the common
+clock interface.
+
+	Part 2 - common data structures and api
+
+Below is the common struct clk definition from
+include/linux/clk-private.h, modified for brevity:
+
+	struct clk {
+		const char		*name;
+		const struct clk_ops	*ops;
+		struct clk_hw		*hw;
+		char			**parent_names;
+		struct clk		**parents;
+		struct clk		*parent;
+		struct hlist_head	children;
+		struct hlist_node	child_node;
+		...
+	};
+
+The members above make up the core of the clk tree topology.  The clk
+api itself defines several driver-facing functions which operate on
+struct clk.  That api is documented in include/linux/clk.h.
+
+Platforms and devices utilizing the common struct clk use the struct
+clk_ops pointer in struct clk to perform the hardware-specific parts of
+the operations defined in clk.h:
+
+	struct clk_ops {
+		int		(*prepare)(struct clk_hw *hw);
+		void		(*unprepare)(struct clk_hw *hw);
+		int		(*enable)(struct clk_hw *hw);
+		void		(*disable)(struct clk_hw *hw);
+		int		(*is_enabled)(struct clk_hw *hw);
+		unsigned long	(*recalc_rate)(struct clk_hw *hw,
+						unsigned long parent_rate);
+		long		(*round_rate)(struct clk_hw *hw, unsigned long,
+						unsigned long *);
+		int		(*set_parent)(struct clk_hw *hw, u8 index);
+		u8		(*get_parent)(struct clk_hw *hw);
+		int		(*set_rate)(struct clk_hw *hw, unsigned long);
+		void		(*init)(struct clk_hw *hw);
+	};
+
+	Part 3 - hardware clk implementations
+
+The strength of the common struct clk comes from its .ops and .hw pointers
+which abstract the details of struct clk from the hardware-specific bits, and
+vice versa.  To illustrate consider the simple gateable clk implementation in
+drivers/clk/clk-gate.c:
+
+struct clk_gate {
+	struct clk_hw	hw;
+	void __iomem    *reg;
+	u8              bit_idx;
+	...
+};
+
+struct clk_gate contains struct clk_hw hw as well as hardware-specific
+knowledge about which register and bit controls this clk's gating.
+Nothing about clock topology or accounting, such as enable_count or
+notifier_count, is needed here.  That is all handled by the common
+framework code and struct clk.
+
+Let's walk through enabling this clk from driver code:
+
+	struct clk *clk;
+	clk = clk_get(NULL, "my_gateable_clk");
+
+	clk_prepare(clk);
+	clk_enable(clk);
+
+The call graph for clk_enable is very simple:
+
+clk_enable(clk);
+	clk->ops->enable(clk->hw);
+	[resolves to...]
+		clk_gate_enable(hw);
+		[resolves struct clk gate with to_clk_gate(hw)]
+			clk_gate_set_bit(gate);
+
+And the definition of clk_gate_set_bit:
+
+static void clk_gate_set_bit(struct clk_gate *gate)
+{
+	u32 reg;
+
+	reg = __raw_readl(gate->reg);
+	reg |= BIT(gate->bit_idx);
+	writel(reg, gate->reg);
+}
+
+Note that to_clk_gate is defined as:
+
+#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, clk)
+
+This pattern of abstraction is used for every clock hardware
+representation.
+
+	Part 4 - supporting your own clk hardware
+
+When implementing support for a new type of clock it only necessary to
+include the following header:
+
+#include <linux/clk-provider.h>
+
+include/linux/clk.h is included within that header and clk-private.h
+must never be included from the code which implements the operations for
+a clock.  More on that below in Part 5.
+
+To construct a clk hardware structure for your platform you must define
+the following:
+
+struct clk_foo {
+	struct clk_hw hw;
+	... hardware specific data goes here ...
+};
+
+To take advantage of your data you'll need to support valid operations
+for your clk:
+
+struct clk_ops clk_foo_ops {
+	.enable		= &clk_foo_enable;
+	.disable	= &clk_foo_disable;
+};
+
+Implement the above functions using container_of:
+
+#define to_clk_foo(_hw) container_of(_hw, struct clk_foo, hw)
+
+int clk_foo_enable(struct clk_hw *hw)
+{
+	struct clk_foo *foo;
+
+	foo = to_clk_foo(hw);
+
+	... perform magic on foo ...
+
+	return 0;
+};
+
+Below is a matrix detailing which clk_ops are mandatory based upon the
+hardware capbilities of that clock.  A cell marked as "y" means
+mandatory, a cell marked as "n" implies that either including that
+callback is invalid or otherwise uneccesary.  Empty cells are either
+optional or must be evaluated on a case-by-case basis.
+
+                           clock hardware characteristics
+	     -----------------------------------------------------------
+             | gate | change rate | single parent | multiplexer | root |
+             |------|-------------|---------------|-------------|------|
+.prepare     |      |             |               |             |      |
+.unprepare   |      |             |               |             |      |
+             |      |             |               |             |      |
+.enable      | y    |             |               |             |      |
+.disable     | y    |             |               |             |      |
+.is_enabled  | y    |             |               |             |      |
+             |      |             |               |             |      |
+.recalc_rate |      | y           |               |             |      |
+.round_rate  |      | y           |               |             |      |
+.set_rate    |      | y           |               |             |      |
+             |      |             |               |             |      |
+.set_parent  |      |             | n             | y           | n    |
+.get_parent  |      |             | n             | y           | n    |
+             |      |             |               |             |      |
+.init        |      |             |               |             |      |
+	     -----------------------------------------------------------
+
+Finally, register your clock at run-time with a hardware-specific
+registration function.  This function simply populates struct clk_foo's
+data and then passes the common struct clk parameters to the framework
+with a call to:
+
+clk_register(...)
+
+See the basic clock types in drivers/clk/clk-*.c for examples.
+
+	Part 5 - static initialization of clock data
+
+For platforms with many clocks (often numbering into the hundreds) it
+may be desirable to statically initialize some clock data.  This
+presents a problem since the definition of struct clk should be hidden
+from everyone except for the clock core in drivers/clk/clk.c.
+
+To get around this problem struct clk's definition is exposed in
+include/linux/clk-private.h along with some macros for more easily
+initializing instances of the basic clock types.  These clocks must
+still be initialized with the common clock framework via a call to
+__clk_init.
+
+clk-private.h must NEVER be included by code which implements struct
+clk_ops callbacks, nor must it be included by any logic which pokes
+around inside of struct clk at run-time.  To do so is a layering
+violation.
+
+To better enforce this policy, always follow this simple rule: any
+statically initialized clock data MUST be defined in a separate file
+from the logic that implements its ops.  Basically separate the logic
+from the data and all is well.
diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
index a20bfd4..66ef8f3 100644
--- a/Documentation/cpu-hotplug.txt
+++ b/Documentation/cpu-hotplug.txt
@@ -47,7 +47,7 @@
              other cpus later online, read FAQ's for more info.
 
 additional_cpus=n (*)	Use this to limit hotpluggable cpus. This option sets
-  			cpu_possible_map = cpu_present_map + additional_cpus
+  			cpu_possible_mask = cpu_present_mask + additional_cpus
 
 cede_offline={"off","on"}  Use this option to disable/enable putting offlined
 		            processors to an extended H_CEDE state on
@@ -64,11 +64,11 @@
 on the apicid values in those tables for disabled apics. In the event
 BIOS doesn't mark such hot-pluggable cpus as disabled entries, one could
 use this parameter "additional_cpus=x" to represent those cpus in the
-cpu_possible_map.
+cpu_possible_mask.
 
 possible_cpus=n		[s390,x86_64] use this to set hotpluggable cpus.
 			This option sets possible_cpus bits in
-			cpu_possible_map. Thus keeping the numbers of bits set
+			cpu_possible_mask. Thus keeping the numbers of bits set
 			constant even if the machine gets rebooted.
 
 CPU maps and such
@@ -76,7 +76,7 @@
 [More on cpumaps and primitive to manipulate, please check
 include/linux/cpumask.h that has more descriptive text.]
 
-cpu_possible_map: Bitmap of possible CPUs that can ever be available in the
+cpu_possible_mask: Bitmap of possible CPUs that can ever be available in the
 system. This is used to allocate some boot time memory for per_cpu variables
 that aren't designed to grow/shrink as CPUs are made available or removed.
 Once set during boot time discovery phase, the map is static, i.e no bits
@@ -84,13 +84,13 @@
 upfront can save some boot time memory. See below for how we use heuristics
 in x86_64 case to keep this under check.
 
-cpu_online_map: Bitmap of all CPUs currently online. Its set in __cpu_up()
+cpu_online_mask: Bitmap of all CPUs currently online. Its set in __cpu_up()
 after a cpu is available for kernel scheduling and ready to receive
 interrupts from devices. Its cleared when a cpu is brought down using
 __cpu_disable(), before which all OS services including interrupts are
 migrated to another target CPU.
 
-cpu_present_map: Bitmap of CPUs currently present in the system. Not all
+cpu_present_mask: Bitmap of CPUs currently present in the system. Not all
 of them may be online. When physical hotplug is processed by the relevant
 subsystem (e.g ACPI) can change and new bit either be added or removed
 from the map depending on the event is hot-add/hot-remove. There are currently
@@ -99,22 +99,22 @@
 
 You really dont need to manipulate any of the system cpu maps. They should
 be read-only for most use. When setting up per-cpu resources almost always use
-cpu_possible_map/for_each_possible_cpu() to iterate.
+cpu_possible_mask/for_each_possible_cpu() to iterate.
 
 Never use anything other than cpumask_t to represent bitmap of CPUs.
 
 	#include <linux/cpumask.h>
 
-	for_each_possible_cpu     - Iterate over cpu_possible_map
-	for_each_online_cpu       - Iterate over cpu_online_map
-	for_each_present_cpu      - Iterate over cpu_present_map
+	for_each_possible_cpu     - Iterate over cpu_possible_mask
+	for_each_online_cpu       - Iterate over cpu_online_mask
+	for_each_present_cpu      - Iterate over cpu_present_mask
 	for_each_cpu_mask(x,mask) - Iterate over some random collection of cpu mask.
 
 	#include <linux/cpu.h>
 	get_online_cpus() and put_online_cpus():
 
 The above calls are used to inhibit cpu hotplug operations. While the
-cpu_hotplug.refcount is non zero, the cpu_online_map will not change.
+cpu_hotplug.refcount is non zero, the cpu_online_mask will not change.
 If you merely need to avoid cpus going away, you could also use
 preempt_disable() and preempt_enable() for those sections.
 Just remember the critical section cannot call any
diff --git a/Documentation/cpuidle/sysfs.txt b/Documentation/cpuidle/sysfs.txt
index 50d7b16..9d28a34 100644
--- a/Documentation/cpuidle/sysfs.txt
+++ b/Documentation/cpuidle/sysfs.txt
@@ -36,6 +36,7 @@
 /sys/devices/system/cpu/cpu0/cpuidle/state0:
 total 0
 -r--r--r-- 1 root root 4096 Feb  8 10:42 desc
+-rw-r--r-- 1 root root 4096 Feb  8 10:42 disable
 -r--r--r-- 1 root root 4096 Feb  8 10:42 latency
 -r--r--r-- 1 root root 4096 Feb  8 10:42 name
 -r--r--r-- 1 root root 4096 Feb  8 10:42 power
@@ -45,6 +46,7 @@
 /sys/devices/system/cpu/cpu0/cpuidle/state1:
 total 0
 -r--r--r-- 1 root root 4096 Feb  8 10:42 desc
+-rw-r--r-- 1 root root 4096 Feb  8 10:42 disable
 -r--r--r-- 1 root root 4096 Feb  8 10:42 latency
 -r--r--r-- 1 root root 4096 Feb  8 10:42 name
 -r--r--r-- 1 root root 4096 Feb  8 10:42 power
@@ -54,6 +56,7 @@
 /sys/devices/system/cpu/cpu0/cpuidle/state2:
 total 0
 -r--r--r-- 1 root root 4096 Feb  8 10:42 desc
+-rw-r--r-- 1 root root 4096 Feb  8 10:42 disable
 -r--r--r-- 1 root root 4096 Feb  8 10:42 latency
 -r--r--r-- 1 root root 4096 Feb  8 10:42 name
 -r--r--r-- 1 root root 4096 Feb  8 10:42 power
@@ -63,6 +66,7 @@
 /sys/devices/system/cpu/cpu0/cpuidle/state3:
 total 0
 -r--r--r-- 1 root root 4096 Feb  8 10:42 desc
+-rw-r--r-- 1 root root 4096 Feb  8 10:42 disable
 -r--r--r-- 1 root root 4096 Feb  8 10:42 latency
 -r--r--r-- 1 root root 4096 Feb  8 10:42 name
 -r--r--r-- 1 root root 4096 Feb  8 10:42 power
@@ -72,6 +76,7 @@
 
 
 * desc : Small description about the idle state (string)
+* disable : Option to disable this idle state (bool)
 * latency : Latency to exit out of this idle state (in microseconds)
 * name : Name of the idle state (string)
 * power : Power consumed while in this idle state (in milliwatts)
diff --git a/Documentation/crc32.txt b/Documentation/crc32.txt
new file mode 100644
index 0000000..a08a7dd
--- /dev/null
+++ b/Documentation/crc32.txt
@@ -0,0 +1,182 @@
+A brief CRC tutorial.
+
+A CRC is a long-division remainder.  You add the CRC to the message,
+and the whole thing (message+CRC) is a multiple of the given
+CRC polynomial.  To check the CRC, you can either check that the
+CRC matches the recomputed value, *or* you can check that the
+remainder computed on the message+CRC is 0.  This latter approach
+is used by a lot of hardware implementations, and is why so many
+protocols put the end-of-frame flag after the CRC.
+
+It's actually the same long division you learned in school, except that
+- We're working in binary, so the digits are only 0 and 1, and
+- When dividing polynomials, there are no carries.  Rather than add and
+  subtract, we just xor.  Thus, we tend to get a bit sloppy about
+  the difference between adding and subtracting.
+
+Like all division, the remainder is always smaller than the divisor.
+To produce a 32-bit CRC, the divisor is actually a 33-bit CRC polynomial.
+Since it's 33 bits long, bit 32 is always going to be set, so usually the
+CRC is written in hex with the most significant bit omitted.  (If you're
+familiar with the IEEE 754 floating-point format, it's the same idea.)
+
+Note that a CRC is computed over a string of *bits*, so you have
+to decide on the endianness of the bits within each byte.  To get
+the best error-detecting properties, this should correspond to the
+order they're actually sent.  For example, standard RS-232 serial is
+little-endian; the most significant bit (sometimes used for parity)
+is sent last.  And when appending a CRC word to a message, you should
+do it in the right order, matching the endianness.
+
+Just like with ordinary division, you proceed one digit (bit) at a time.
+Each step of the division you take one more digit (bit) of the dividend
+and append it to the current remainder.  Then you figure out the
+appropriate multiple of the divisor to subtract to being the remainder
+back into range.  In binary, this is easy - it has to be either 0 or 1,
+and to make the XOR cancel, it's just a copy of bit 32 of the remainder.
+
+When computing a CRC, we don't care about the quotient, so we can
+throw the quotient bit away, but subtract the appropriate multiple of
+the polynomial from the remainder and we're back to where we started,
+ready to process the next bit.
+
+A big-endian CRC written this way would be coded like:
+for (i = 0; i < input_bits; i++) {
+	multiple = remainder & 0x80000000 ? CRCPOLY : 0;
+	remainder = (remainder << 1 | next_input_bit()) ^ multiple;
+}
+
+Notice how, to get at bit 32 of the shifted remainder, we look
+at bit 31 of the remainder *before* shifting it.
+
+But also notice how the next_input_bit() bits we're shifting into
+the remainder don't actually affect any decision-making until
+32 bits later.  Thus, the first 32 cycles of this are pretty boring.
+Also, to add the CRC to a message, we need a 32-bit-long hole for it at
+the end, so we have to add 32 extra cycles shifting in zeros at the
+end of every message,
+
+These details lead to a standard trick: rearrange merging in the
+next_input_bit() until the moment it's needed.  Then the first 32 cycles
+can be precomputed, and merging in the final 32 zero bits to make room
+for the CRC can be skipped entirely.  This changes the code to:
+
+for (i = 0; i < input_bits; i++) {
+	remainder ^= next_input_bit() << 31;
+	multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+	remainder = (remainder << 1) ^ multiple;
+}
+
+With this optimization, the little-endian code is particularly simple:
+for (i = 0; i < input_bits; i++) {
+	remainder ^= next_input_bit();
+	multiple = (remainder & 1) ? CRCPOLY : 0;
+	remainder = (remainder >> 1) ^ multiple;
+}
+
+The most significant coefficient of the remainder polynomial is stored
+in the least significant bit of the binary "remainder" variable.
+The other details of endianness have been hidden in CRCPOLY (which must
+be bit-reversed) and next_input_bit().
+
+As long as next_input_bit is returning the bits in a sensible order, we don't
+*have* to wait until the last possible moment to merge in additional bits.
+We can do it 8 bits at a time rather than 1 bit at a time:
+for (i = 0; i < input_bytes; i++) {
+	remainder ^= next_input_byte() << 24;
+	for (j = 0; j < 8; j++) {
+		multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+		remainder = (remainder << 1) ^ multiple;
+	}
+}
+
+Or in little-endian:
+for (i = 0; i < input_bytes; i++) {
+	remainder ^= next_input_byte();
+	for (j = 0; j < 8; j++) {
+		multiple = (remainder & 1) ? CRCPOLY : 0;
+		remainder = (remainder >> 1) ^ multiple;
+	}
+}
+
+If the input is a multiple of 32 bits, you can even XOR in a 32-bit
+word at a time and increase the inner loop count to 32.
+
+You can also mix and match the two loop styles, for example doing the
+bulk of a message byte-at-a-time and adding bit-at-a-time processing
+for any fractional bytes at the end.
+
+To reduce the number of conditional branches, software commonly uses
+the byte-at-a-time table method, popularized by Dilip V. Sarwate,
+"Computation of Cyclic Redundancy Checks via Table Look-Up", Comm. ACM
+v.31 no.8 (August 1998) p. 1008-1013.
+
+Here, rather than just shifting one bit of the remainder to decide
+in the correct multiple to subtract, we can shift a byte at a time.
+This produces a 40-bit (rather than a 33-bit) intermediate remainder,
+and the correct multiple of the polynomial to subtract is found using
+a 256-entry lookup table indexed by the high 8 bits.
+
+(The table entries are simply the CRC-32 of the given one-byte messages.)
+
+When space is more constrained, smaller tables can be used, e.g. two
+4-bit shifts followed by a lookup in a 16-entry table.
+
+It is not practical to process much more than 8 bits at a time using this
+technique, because tables larger than 256 entries use too much memory and,
+more importantly, too much of the L1 cache.
+
+To get higher software performance, a "slicing" technique can be used.
+See "High Octane CRC Generation with the Intel Slicing-by-8 Algorithm",
+ftp://download.intel.com/technology/comms/perfnet/download/slicing-by-8.pdf
+
+This does not change the number of table lookups, but does increase
+the parallelism.  With the classic Sarwate algorithm, each table lookup
+must be completed before the index of the next can be computed.
+
+A "slicing by 2" technique would shift the remainder 16 bits at a time,
+producing a 48-bit intermediate remainder.  Rather than doing a single
+lookup in a 65536-entry table, the two high bytes are looked up in
+two different 256-entry tables.  Each contains the remainder required
+to cancel out the corresponding byte.  The tables are different because the
+polynomials to cancel are different.  One has non-zero coefficients from
+x^32 to x^39, while the other goes from x^40 to x^47.
+
+Since modern processors can handle many parallel memory operations, this
+takes barely longer than a single table look-up and thus performs almost
+twice as fast as the basic Sarwate algorithm.
+
+This can be extended to "slicing by 4" using 4 256-entry tables.
+Each step, 32 bits of data is fetched, XORed with the CRC, and the result
+broken into bytes and looked up in the tables.  Because the 32-bit shift
+leaves the low-order bits of the intermediate remainder zero, the
+final CRC is simply the XOR of the 4 table look-ups.
+
+But this still enforces sequential execution: a second group of table
+look-ups cannot begin until the previous groups 4 table look-ups have all
+been completed.  Thus, the processor's load/store unit is sometimes idle.
+
+To make maximum use of the processor, "slicing by 8" performs 8 look-ups
+in parallel.  Each step, the 32-bit CRC is shifted 64 bits and XORed
+with 64 bits of input data.  What is important to note is that 4 of
+those 8 bytes are simply copies of the input data; they do not depend
+on the previous CRC at all.  Thus, those 4 table look-ups may commence
+immediately, without waiting for the previous loop iteration.
+
+By always having 4 loads in flight, a modern superscalar processor can
+be kept busy and make full use of its L1 cache.
+
+Two more details about CRC implementation in the real world:
+
+Normally, appending zero bits to a message which is already a multiple
+of a polynomial produces a larger multiple of that polynomial.  Thus,
+a basic CRC will not detect appended zero bits (or bytes).  To enable
+a CRC to detect this condition, it's common to invert the CRC before
+appending it.  This makes the remainder of the message+crc come out not
+as zero, but some fixed non-zero value.  (The CRC of the inversion
+pattern, 0xffffffff.)
+
+The same problem applies to zero bits prepended to the message, and a
+similar solution is used.  Instead of starting the CRC computation with
+a remainder of 0, an initial remainder of all ones is used.  As long as
+you start the same way on decoding, it doesn't make a difference.
diff --git a/Documentation/device-mapper/thin-provisioning.txt b/Documentation/device-mapper/thin-provisioning.txt
index 1ff044d..3370bc4 100644
--- a/Documentation/device-mapper/thin-provisioning.txt
+++ b/Documentation/device-mapper/thin-provisioning.txt
@@ -75,10 +75,12 @@
 
 As a guide, we suggest you calculate the number of bytes to use in the
 metadata device as 48 * $data_dev_size / $data_block_size but round it up
-to 2MB if the answer is smaller.  The largest size supported is 16GB.
+to 2MB if the answer is smaller.  If you're creating large numbers of
+snapshots which are recording large amounts of change, you may find you
+need to increase this.
 
-If you're creating large numbers of snapshots which are recording large
-amounts of change, you may need find you need to increase this.
+The largest size supported is 16GB: If the device is larger,
+a warning will be issued and the excess space will not be used.
 
 Reloading a pool table
 ----------------------
@@ -167,6 +169,38 @@
 
     dmsetup create snap --table "0 2097152 thin /dev/mapper/pool 1"
 
+External snapshots
+------------------
+
+You can use an external _read only_ device as an origin for a
+thinly-provisioned volume.  Any read to an unprovisioned area of the
+thin device will be passed through to the origin.  Writes trigger
+the allocation of new blocks as usual.
+
+One use case for this is VM hosts that want to run guests on
+thinly-provisioned volumes but have the base image on another device
+(possibly shared between many VMs).
+
+You must not write to the origin device if you use this technique!
+Of course, you may write to the thin device and take internal snapshots
+of the thin volume.
+
+i) Creating a snapshot of an external device
+
+  This is the same as creating a thin device.
+  You don't mention the origin at this stage.
+
+    dmsetup message /dev/mapper/pool 0 "create_thin 0"
+
+ii) Using a snapshot of an external device.
+
+  Append an extra parameter to the thin target specifying the origin:
+
+    dmsetup create snap --table "0 2097152 thin /dev/mapper/pool 0 /dev/image"
+
+  N.B. All descendants (internal snapshots) of this snapshot require the
+  same extra origin parameter.
+
 Deactivation
 ------------
 
@@ -189,7 +223,13 @@
 	      <low water mark (blocks)> [<number of feature args> [<arg>]*]
 
     Optional feature arguments:
-    - 'skip_block_zeroing': skips the zeroing of newly-provisioned blocks.
+
+      skip_block_zeroing: Skip the zeroing of newly-provisioned blocks.
+
+      ignore_discard: Disable discard support.
+
+      no_discard_passdown: Don't pass discards down to the underlying
+			   data device, but just remove the mapping.
 
     Data block size must be between 64KB (128 sectors) and 1GB
     (2097152 sectors) inclusive.
@@ -237,16 +277,6 @@
 
 	Deletes a thin device.  Irreversible.
 
-    trim <dev id> <new size in sectors>
-
-	Delete mappings from the end of a thin device.  Irreversible.
-	You might want to use this if you're reducing the size of
-	your thinly-provisioned device.  In many cases, due to the
-	sharing of blocks between devices, it is not possible to
-	determine in advance how much space 'trim' will release.  (In
-	future a userspace tool might be able to perform this
-	calculation.)
-
     set_transaction_id <current id> <new id>
 
 	Userland volume managers, such as LVM, need a way to
@@ -262,7 +292,7 @@
 
 i) Constructor
 
-    thin <pool dev> <dev id>
+    thin <pool dev> <dev id> [<external origin dev>]
 
     pool dev:
 	the thin-pool device, e.g. /dev/mapper/my_pool or 253:0
@@ -271,6 +301,11 @@
 	the internal device identifier of the device to be
 	activated.
 
+    external origin dev:
+	an optional block device outside the pool to be treated as a
+	read-only snapshot origin: reads to unprovisioned areas of the
+	thin target will be mapped to this device.
+
 The pool doesn't store any size against the thin devices.  If you
 load a thin target that is smaller than you've been using previously,
 then you'll have no access to blocks mapped beyond the end.  If you
diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt
new file mode 100644
index 0000000..32e4879
--- /dev/null
+++ b/Documentation/device-mapper/verity.txt
@@ -0,0 +1,194 @@
+dm-verity
+==========
+
+Device-Mapper's "verity" target provides transparent integrity checking of
+block devices using a cryptographic digest provided by the kernel crypto API.
+This target is read-only.
+
+Construction Parameters
+=======================
+    <version> <dev> <hash_dev> <hash_start>
+    <data_block_size> <hash_block_size>
+    <num_data_blocks> <hash_start_block>
+    <algorithm> <digest> <salt>
+
+<version>
+    This is the version number of the on-disk format.
+
+    0 is the original format used in the Chromium OS.
+	The salt is appended when hashing, digests are stored continuously and
+	the rest of the block is padded with zeros.
+
+    1 is the current format that should be used for new devices.
+	The salt is prepended when hashing and each digest is
+	padded with zeros to the power of two.
+
+<dev>
+    This is the device containing the data the integrity of which needs to be
+    checked.  It may be specified as a path, like /dev/sdaX, or a device number,
+    <major>:<minor>.
+
+<hash_dev>
+    This is the device that that supplies the hash tree data.  It may be
+    specified similarly to the device path and may be the same device.  If the
+    same device is used, the hash_start should be outside of the dm-verity
+    configured device size.
+
+<data_block_size>
+    The block size on a data device.  Each block corresponds to one digest on
+    the hash device.
+
+<hash_block_size>
+    The size of a hash block.
+
+<num_data_blocks>
+    The number of data blocks on the data device.  Additional blocks are
+    inaccessible.  You can place hashes to the same partition as data, in this
+    case hashes are placed after <num_data_blocks>.
+
+<hash_start_block>
+    This is the offset, in <hash_block_size>-blocks, from the start of hash_dev
+    to the root block of the hash tree.
+
+<algorithm>
+    The cryptographic hash algorithm used for this device.  This should
+    be the name of the algorithm, like "sha1".
+
+<digest>
+    The hexadecimal encoding of the cryptographic hash of the root hash block
+    and the salt.  This hash should be trusted as there is no other authenticity
+    beyond this point.
+
+<salt>
+    The hexadecimal encoding of the salt value.
+
+Theory of operation
+===================
+
+dm-verity is meant to be setup as part of a verified boot path.  This
+may be anything ranging from a boot using tboot or trustedgrub to just
+booting from a known-good device (like a USB drive or CD).
+
+When a dm-verity device is configured, it is expected that the caller
+has been authenticated in some way (cryptographic signatures, etc).
+After instantiation, all hashes will be verified on-demand during
+disk access.  If they cannot be verified up to the root node of the
+tree, the root hash, then the I/O will fail.  This should identify
+tampering with any data on the device and the hash data.
+
+Cryptographic hashes are used to assert the integrity of the device on a
+per-block basis.  This allows for a lightweight hash computation on first read
+into the page cache.  Block hashes are stored linearly-aligned to the nearest
+block the size of a page.
+
+Hash Tree
+---------
+
+Each node in the tree is a cryptographic hash.  If it is a leaf node, the hash
+is of some block data on disk.  If it is an intermediary node, then the hash is
+of a number of child nodes.
+
+Each entry in the tree is a collection of neighboring nodes that fit in one
+block.  The number is determined based on block_size and the size of the
+selected cryptographic digest algorithm.  The hashes are linearly-ordered in
+this entry and any unaligned trailing space is ignored but included when
+calculating the parent node.
+
+The tree looks something like:
+
+alg = sha256, num_blocks = 32768, block_size = 4096
+
+                                 [   root    ]
+                                /    . . .    \
+                     [entry_0]                 [entry_1]
+                    /  . . .  \                 . . .   \
+         [entry_0_0]   . . .  [entry_0_127]    . . . .  [entry_1_127]
+           / ... \             /   . . .  \             /           \
+     blk_0 ... blk_127  blk_16256   blk_16383      blk_32640 . . . blk_32767
+
+
+On-disk format
+==============
+
+Below is the recommended on-disk format. The verity kernel code does not
+read the on-disk header. It only reads the hash blocks which directly
+follow the header. It is expected that a user-space tool will verify the
+integrity of the verity_header and then call dmsetup with the correct
+parameters. Alternatively, the header can be omitted and the dmsetup
+parameters can be passed via the kernel command-line in a rooted chain
+of trust where the command-line is verified.
+
+The on-disk format is especially useful in cases where the hash blocks
+are on a separate partition. The magic number allows easy identification
+of the partition contents. Alternatively, the hash blocks can be stored
+in the same partition as the data to be verified. In such a configuration
+the filesystem on the partition would be sized a little smaller than
+the full-partition, leaving room for the hash blocks.
+
+struct superblock {
+	uint8_t signature[8]
+		"verity\0\0";
+
+	uint8_t version;
+		1 - current format
+
+	uint8_t data_block_bits;
+		log2(data block size)
+
+	uint8_t hash_block_bits;
+		log2(hash block size)
+
+	uint8_t pad1[1];
+		zero padding
+
+	uint16_t salt_size;
+		big-endian salt size
+
+	uint8_t pad2[2];
+		zero padding
+
+	uint32_t data_blocks_hi;
+		big-endian high 32 bits of the 64-bit number of data blocks
+
+	uint32_t data_blocks_lo;
+		big-endian low 32 bits of the 64-bit number of data blocks
+
+	uint8_t algorithm[16];
+		cryptographic algorithm
+
+	uint8_t salt[384];
+		salt (the salt size is specified above)
+
+	uint8_t pad3[88];
+		zero padding to 512-byte boundary
+}
+
+Directly following the header (and with sector number padded to the next hash
+block boundary) are the hash blocks which are stored a depth at a time
+(starting from the root), sorted in order of increasing index.
+
+Status
+======
+V (for Valid) is returned if every check performed so far was valid.
+If any check failed, C (for Corruption) is returned.
+
+Example
+=======
+
+Setup a device:
+  dmsetup create vroot --table \
+    "0 2097152 "\
+    "verity 1 /dev/sda1 /dev/sda2 4096 4096 2097152 1 "\
+    "4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076 "\
+    "1234000000000000000000000000000000000000000000000000000000000000"
+
+A command line tool veritysetup is available to compute or verify
+the hash tree or activate the kernel driver.  This is available from
+the LVM2 upstream repository and may be supplied as a package called
+device-mapper-verity-tools:
+    git://sources.redhat.com/git/lvm2
+    http://sourceware.org/git/?p=lvm2.git
+    http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/verity?cvsroot=lvm2
+
+veritysetup -a vroot /dev/sda1 /dev/sda2 \
+	4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076
diff --git a/Documentation/devicetree/bindings/arm/atmel-aic.txt b/Documentation/devicetree/bindings/arm/atmel-aic.txt
new file mode 100644
index 0000000..aabca4f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/atmel-aic.txt
@@ -0,0 +1,38 @@
+* Advanced Interrupt Controller (AIC)
+
+Required properties:
+- compatible: Should be "atmel,<chip>-aic"
+- interrupt-controller: Identifies the node as an interrupt controller.
+- interrupt-parent: For single AIC system, it is an empty property.
+- #interrupt-cells: The number of cells to define the interrupts. It sould be 2.
+  The first cell is the IRQ number (aka "Peripheral IDentifier" on datasheet).
+  The second cell is used to specify flags:
+    bits[3:0] trigger type and level flags:
+      1 = low-to-high edge triggered.
+      2 = high-to-low edge triggered.
+      4 = active high level-sensitive.
+      8 = active low level-sensitive.
+      Valid combinations are 1, 2, 3, 4, 8.
+      Default flag for internal sources should be set to 4 (active high).
+- reg: Should contain AIC registers location and length
+
+Examples:
+	/*
+	 * AIC
+	 */
+	aic: interrupt-controller@fffff000 {
+		compatible = "atmel,at91rm9200-aic";
+		interrupt-controller;
+		interrupt-parent;
+		#interrupt-cells = <2>;
+		reg = <0xfffff000 0x200>;
+	};
+
+	/*
+	 * An interrupt generating device that is wired to an AIC.
+	 */
+	dma: dma-controller@ffffec00 {
+		compatible = "atmel,at91sam9g45-dma";
+		reg = <0xffffec00 0x200>;
+		interrupts = <21 4>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt
new file mode 100644
index 0000000..ecc81e3
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt
@@ -0,0 +1,92 @@
+Atmel AT91 device tree bindings.
+================================
+
+PIT Timer required properties:
+- compatible: Should be "atmel,at91sam9260-pit"
+- reg: Should contain registers location and length
+- interrupts: Should contain interrupt for the PIT which is the IRQ line
+  shared across all System Controller members.
+
+TC/TCLIB Timer required properties:
+- compatible: Should be "atmel,<chip>-pit".
+  <chip> can be "at91rm9200" or "at91sam9x5"
+- reg: Should contain registers location and length
+- interrupts: Should contain all interrupts for the TC block
+  Note that you can specify several interrupt cells if the TC
+  block has one interrupt per channel.
+
+Examples:
+
+One interrupt per TC block:
+	tcb0: timer@fff7c000 {
+		compatible = "atmel,at91rm9200-tcb";
+		reg = <0xfff7c000 0x100>;
+		interrupts = <18 4>;
+	};
+
+One interrupt per TC channel in a TC block:
+	tcb1: timer@fffdc000 {
+		compatible = "atmel,at91rm9200-tcb";
+		reg = <0xfffdc000 0x100>;
+		interrupts = <26 4 27 4 28 4>;
+	};
+
+RSTC Reset Controller required properties:
+- compatible: Should be "atmel,<chip>-rstc".
+  <chip> can be "at91sam9260" or "at91sam9g45"
+- reg: Should contain registers location and length
+
+Example:
+
+	rstc@fffffd00 {
+		compatible = "atmel,at91sam9260-rstc";
+		reg = <0xfffffd00 0x10>;
+	};
+
+RAMC SDRAM/DDR Controller required properties:
+- compatible: Should be "atmel,at91sam9260-sdramc",
+			"atmel,at91sam9g45-ddramc",
+- reg: Should contain registers location and length
+  For at91sam9263 and at91sam9g45 you must specify 2 entries.
+
+Examples:
+
+	ramc0: ramc@ffffe800 {
+		compatible = "atmel,at91sam9g45-ddramc";
+		reg = <0xffffe800 0x200>;
+	};
+
+	ramc0: ramc@ffffe400 {
+		compatible = "atmel,at91sam9g45-ddramc";
+		reg = <0xffffe400 0x200
+		       0xffffe600 0x200>;
+	};
+
+SHDWC Shutdown Controller
+
+required properties:
+- compatible: Should be "atmel,<chip>-shdwc".
+  <chip> can be "at91sam9260", "at91sam9rl" or "at91sam9x5".
+- reg: Should contain registers location and length
+
+optional properties:
+- atmel,wakeup-mode: String, operation mode of the wakeup mode.
+  Supported values are: "none", "high", "low", "any".
+- atmel,wakeup-counter: Counter on Wake-up 0 (between 0x0 and 0xf).
+
+optional at91sam9260 properties:
+- atmel,wakeup-rtt-timer: boolean to enable Real-time Timer Wake-up.
+
+optional at91sam9rl properties:
+- atmel,wakeup-rtc-timer: boolean to enable Real-time Clock Wake-up.
+- atmel,wakeup-rtt-timer: boolean to enable Real-time Timer Wake-up.
+
+optional at91sam9x5 properties:
+- atmel,wakeup-rtc-timer: boolean to enable Real-time Clock Wake-up.
+
+Example:
+
+	rstc@fffffd00 {
+		compatible = "atmel,at91sam9260-rstc";
+		reg = <0xfffffd00 0x10>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/atmel-pmc.txt b/Documentation/devicetree/bindings/arm/atmel-pmc.txt
new file mode 100644
index 0000000..389bed5
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/atmel-pmc.txt
@@ -0,0 +1,11 @@
+* Power Management Controller (PMC)
+
+Required properties:
+- compatible: Should be "atmel,at91rm9200-pmc"
+- reg: Should contain PMC registers location and length
+
+Examples:
+	pmc: pmc@fffffc00 {
+		compatible = "atmel,at91rm9200-pmc";
+		reg = <0xfffffc00 0x100>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt
index 54bddda..bfbc771 100644
--- a/Documentation/devicetree/bindings/arm/fsl.txt
+++ b/Documentation/devicetree/bindings/arm/fsl.txt
@@ -28,3 +28,25 @@
 i.MX6 Quad SABRE Lite Board
 Required root node properties:
     - compatible = "fsl,imx6q-sabrelite", "fsl,imx6q";
+
+Generic i.MX boards
+-------------------
+
+No iomux setup is done for these boards, so this must have been configured
+by the bootloader for boards to work with the generic bindings.
+
+i.MX27 generic board
+Required root node properties:
+    - compatible = "fsl,imx27";
+
+i.MX51 generic board
+Required root node properties:
+    - compatible = "fsl,imx51";
+
+i.MX53 generic board
+Required root node properties:
+    - compatible = "fsl,imx53";
+
+i.MX6q generic board
+Required root node properties:
+    - compatible = "fsl,imx6q";
diff --git a/Documentation/devicetree/bindings/arm/mrvl.txt b/Documentation/devicetree/bindings/arm/mrvl.txt
new file mode 100644
index 0000000..d8de933
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mrvl.txt
@@ -0,0 +1,6 @@
+Marvell Platforms Device Tree Bindings
+----------------------------------------------------
+
+PXA168 Aspenite Board
+Required root node properties:
+	- compatible = "mrvl,pxa168-aspenite", "mrvl,pxa168";
diff --git a/Documentation/devicetree/bindings/arm/omap/intc.txt b/Documentation/devicetree/bindings/arm/omap/intc.txt
new file mode 100644
index 0000000..f2583e6
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/omap/intc.txt
@@ -0,0 +1,27 @@
+* OMAP Interrupt Controller
+
+OMAP2/3 are using a TI interrupt controller that can support several
+configurable number of interrupts.
+
+Main node required properties:
+
+- compatible : should be:
+	"ti,omap2-intc"
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The type shall be a <u32> and the value shall be 1.
+
+  The cell contains the interrupt number in the range [0-128].
+- ti,intc-size: Number of interrupts handled by the interrupt controller.
+- reg: physical base address and size of the intc registers map.
+
+Example:
+
+	intc: interrupt-controller@1 {
+		compatible = "ti,omap2-intc";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		ti,intc-size = <96>;
+		reg = <0x48200000 0x1000>;
+	};
+
diff --git a/Documentation/devicetree/bindings/arm/spear.txt b/Documentation/devicetree/bindings/arm/spear.txt
new file mode 100644
index 0000000..f8e54f0
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/spear.txt
@@ -0,0 +1,8 @@
+ST SPEAr Platforms Device Tree Bindings
+---------------------------------------
+
+Boards with the ST SPEAr600 SoC shall have the following properties:
+
+Required root node property:
+
+compatible = "st,spear600";
diff --git a/Documentation/devicetree/bindings/arm/tegra/emc.txt b/Documentation/devicetree/bindings/arm/tegra/emc.txt
new file mode 100644
index 0000000..09335f8
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/tegra/emc.txt
@@ -0,0 +1,100 @@
+Embedded Memory Controller
+
+Properties:
+- name : Should be emc
+- #address-cells : Should be 1
+- #size-cells : Should be 0
+- compatible : Should contain "nvidia,tegra20-emc".
+- reg : Offset and length of the register set for the device
+- nvidia,use-ram-code : If present, the sub-nodes will be addressed
+  and chosen using the ramcode board selector. If omitted, only one
+  set of tables can be present and said tables will be used
+  irrespective of ram-code configuration.
+
+Child device nodes describe the memory settings for different configurations and clock rates.
+
+Example:
+
+	emc@7000f400 {
+		#address-cells = < 1 >;
+		#size-cells = < 0 >;
+		compatible = "nvidia,tegra20-emc";
+		reg = <0x7000f4000 0x200>;
+	}
+
+
+Embedded Memory Controller ram-code table
+
+If the emc node has the nvidia,use-ram-code property present, then the
+next level of nodes below the emc table are used to specify which settings
+apply for which ram-code settings.
+
+If the emc node lacks the nvidia,use-ram-code property, this level is omitted
+and the tables are stored directly under the emc node (see below).
+
+Properties:
+
+- name : Should be emc-tables
+- nvidia,ram-code : the binary representation of the ram-code board strappings
+  for which this node (and children) are valid.
+
+
+
+Embedded Memory Controller configuration table
+
+This is a table containing the EMC register settings for the various
+operating speeds of the memory controller. They are always located as
+subnodes of the emc controller node.
+
+There are two ways of specifying which tables to use:
+
+* The simplest is if there is just one set of tables in the device tree,
+  and they will always be used (based on which frequency is used).
+  This is the preferred method, especially when firmware can fill in
+  this information based on the specific system information and just
+  pass it on to the kernel.
+
+* The slightly more complex one is when more than one memory configuration
+  might exist on the system.  The Tegra20 platform handles this during
+  early boot by selecting one out of possible 4 memory settings based
+  on a 2-pin "ram code" bootstrap setting on the board. The values of
+  these strappings can be read through a register in the SoC, and thus
+  used to select which tables to use.
+
+Properties:
+- name : Should be emc-table
+- compatible : Should contain "nvidia,tegra20-emc-table".
+- reg : either an opaque enumerator to tell different tables apart, or
+  the valid frequency for which the table should be used (in kHz).
+- clock-frequency : the clock frequency for the EMC at which this
+  table should be used (in kHz).
+- nvidia,emc-registers : a 46 word array of EMC registers to be programmed
+  for operation at the 'clock-frequency' setting.
+  The order and contents of the registers are:
+    RC, RFC, RAS, RP, R2W, W2R, R2P, W2P, RD_RCD, WR_RCD, RRD, REXT,
+    WDV, QUSE, QRST, QSAFE, RDV, REFRESH, BURST_REFRESH_NUM, PDEX2WR,
+    PDEX2RD, PCHG2PDEN, ACT2PDEN, AR2PDEN, RW2PDEN, TXSR, TCKE, TFAW,
+    TRPAB, TCLKSTABLE, TCLKSTOP, TREFBW, QUSE_EXTRA, FBIO_CFG6, ODT_WRITE,
+    ODT_READ, FBIO_CFG5, CFG_DIG_DLL, DLL_XFORM_DQS, DLL_XFORM_QUSE,
+    ZCAL_REF_CNT, ZCAL_WAIT_CNT, AUTO_CAL_INTERVAL, CFG_CLKTRIM_0,
+    CFG_CLKTRIM_1, CFG_CLKTRIM_2
+
+		emc-table@166000 {
+			reg = <166000>;
+			compatible = "nvidia,tegra20-emc-table";
+			clock-frequency = < 166000 >;
+			nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+						 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+						 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+						 0 0 0 0 >;
+		};
+
+		emc-table@333000 {
+			reg = <333000>;
+			compatible = "nvidia,tegra20-emc-table";
+			clock-frequency = < 333000 >;
+			nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+						 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+						 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+						 0 0 0 0 >;
+		};
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
new file mode 100644
index 0000000..b5846e2
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
@@ -0,0 +1,19 @@
+NVIDIA Tegra Power Management Controller (PMC)
+
+Properties:
+- name : Should be pmc
+- compatible : Should contain "nvidia,tegra<chip>-pmc".
+- reg : Offset and length of the register set for the device
+- nvidia,invert-interrupt : If present, inverts the PMU interrupt signal.
+  The PMU is an external Power Management Unit, whose interrupt output
+  signal is fed into the PMC. This signal is optionally inverted, and then
+  fed into the ARM GIC. The PMC is not involved in the detection or
+  handling of this interrupt signal, merely its inversion.
+
+Example:
+
+pmc@7000f400 {
+	compatible = "nvidia,tegra20-pmc";
+	reg = <0x7000e400 0x400>;
+	nvidia,invert-interrupt;
+};
diff --git a/Documentation/devicetree/bindings/arm/twd.txt b/Documentation/devicetree/bindings/arm/twd.txt
new file mode 100644
index 0000000..75b8610
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/twd.txt
@@ -0,0 +1,48 @@
+* ARM Timer Watchdog
+
+ARM 11MP, Cortex-A5 and Cortex-A9 are often associated with a per-core
+Timer-Watchdog (aka TWD), which provides both a per-cpu local timer
+and watchdog.
+
+The TWD is usually attached to a GIC to deliver its two per-processor
+interrupts.
+
+** Timer node required properties:
+
+- compatible : Should be one of:
+	"arm,cortex-a9-twd-timer"
+	"arm,cortex-a5-twd-timer"
+	"arm,arm11mp-twd-timer"
+
+- interrupts : One interrupt to each core
+
+- reg : Specify the base address and the size of the TWD timer
+	register window.
+
+Example:
+
+	twd-timer@2c000600 {
+		compatible = "arm,arm11mp-twd-timer"";
+		reg = <0x2c000600 0x20>;
+		interrupts = <1 13 0xf01>;
+	};
+
+** Watchdog node properties:
+
+- compatible : Should be one of:
+	"arm,cortex-a9-twd-wdt"
+	"arm,cortex-a5-twd-wdt"
+	"arm,arm11mp-twd-wdt"
+
+- interrupts : One interrupt to each core
+
+- reg : Specify the base address and the size of the TWD watchdog
+	register window.
+
+Example:
+
+	twd-watchdog@2c000620 {
+		compatible = "arm,arm11mp-twd-wdt";
+		reg = <0x2c000620 0x20>;
+		interrupts = <1 14 0xf01>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/vexpress.txt b/Documentation/devicetree/bindings/arm/vexpress.txt
new file mode 100644
index 0000000..ec8b50c
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/vexpress.txt
@@ -0,0 +1,146 @@
+ARM Versatile Express boards family
+-----------------------------------
+
+ARM's Versatile Express platform consists of a motherboard and one
+or more daughterboards (tiles). The motherboard provides a set of
+peripherals. Processor and RAM "live" on the tiles.
+
+The motherboard and each core tile should be described by a separate
+Device Tree source file, with the tile's description including
+the motherboard file using a /include/ directive. As the motherboard
+can be initialized in one of two different configurations ("memory
+maps"), care must be taken to include the correct one.
+
+Required properties in the root node:
+- compatible value:
+	compatible = "arm,vexpress,<model>", "arm,vexpress";
+  where <model> is the full tile model name (as used in the tile's
+    Technical Reference Manual), eg.:
+    - for Coretile Express A5x2 (V2P-CA5s):
+	compatible = "arm,vexpress,v2p-ca5s", "arm,vexpress";
+    - for Coretile Express A9x4 (V2P-CA9):
+	compatible = "arm,vexpress,v2p-ca9", "arm,vexpress";
+  If a tile comes in several variants or can be used in more then one
+  configuration, the compatible value should be:
+	compatible = "arm,vexpress,<model>,<variant>", \
+				"arm,vexpress,<model>", "arm,vexpress";
+  eg:
+    - Coretile Express A15x2 (V2P-CA15) with Tech Chip 1:
+	compatible = "arm,vexpress,v2p-ca15,tc1", \
+				"arm,vexpress,v2p-ca15", "arm,vexpress";
+    - LogicTile Express 13MG (V2F-2XV6) running Cortex-A7 (3 cores) SMM:
+	compatible = "arm,vexpress,v2f-2xv6,ca7x3", \
+				"arm,vexpress,v2f-2xv6", "arm,vexpress";
+
+Optional properties in the root node:
+- tile model name (use name from the tile's Technical Reference
+  Manual, eg. "V2P-CA5s")
+	model = "<model>";
+- tile's HBI number (unique ARM's board model ID, visible on the
+  PCB's silkscreen) in hexadecimal transcription:
+	arm,hbi = <0xhbi>
+  eg:
+  - for Coretile Express A5x2 (V2P-CA5s) HBI-0191:
+	arm,hbi = <0x191>;
+  - Coretile Express A9x4 (V2P-CA9) HBI-0225:
+	arm,hbi = <0x225>;
+
+Top-level standard "cpus" node is required. It must contain a node
+with device_type = "cpu" property for every available core, eg.:
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a5";
+			reg = <0>;
+		};
+	};
+
+The motherboard description file provides a single "motherboard" node
+using 2 address cells corresponding to the Static Memory Bus used
+between the motherboard and the tile. The first cell defines the Chip
+Select (CS) line number, the second cell address offset within the CS.
+All interrupt lines between the motherboard and the tile are active
+high and are described using single cell.
+
+Optional properties of the "motherboard" node:
+- motherboard's memory map variant:
+	arm,v2m-memory-map = "<name>";
+  where name is one of:
+  - "rs1" - for RS1 map (i.a. peripherals on CS3); this map is also
+            referred to as "ARM Cortex-A Series memory map":
+	arm,v2m-memory-map = "rs1";
+  When this property is missing, the motherboard is using the original
+  memory map (also known as the "Legacy memory map", primarily used
+  with the original CoreTile Express A9x4) with peripherals on CS7.
+
+Motherboard .dtsi files provide a set of labelled peripherals that
+can be used to obtain required phandle in the tile's "aliases" node:
+- UARTs, note that the numbers correspond to the physical connectors
+  on the motherboard's back panel:
+	v2m_serial0, v2m_serial1, v2m_serial2 and v2m_serial3
+- I2C controllers:
+	v2m_i2c_dvi and v2m_i2c_pcie
+- SP804 timers:
+	v2m_timer01 and v2m_timer23
+
+Current Linux implementation requires a "arm,v2m_timer" alias
+pointing at one of the motherboard's SP804 timers, if it is to be
+used as the system timer. This alias should be defined in the
+motherboard files.
+
+The tile description must define "ranges", "interrupt-map-mask" and
+"interrupt-map" properties to translate the motherboard's address
+and interrupt space into one used by the tile's processor.
+
+Abbreviated example:
+
+/dts-v1/;
+
+/ {
+	model = "V2P-CA5s";
+	arm,hbi = <0x225>;
+	compatible = "arm,vexpress-v2p-ca5s", "arm,vexpress";
+	interrupt-parent = <&gic>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	chosen { };
+
+	aliases {
+		serial0 = &v2m_serial0;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a5";
+			reg = <0>;
+		};
+	};
+
+	gic: interrupt-controller@2c001000 {
+		compatible = "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0x2c001000 0x1000>,
+		      <0x2c000100 0x100>;
+	};
+
+	motherboard {
+		/* CS0 is visible at 0x08000000 */
+		ranges = <0 0 0x08000000 0x04000000>;
+		interrupt-map-mask = <0 0 63>;
+		/* Active high IRQ 0 is connected to GIC's SPI0 */
+		interrupt-map = <0 0 0 &gic 0 0 4>;
+	};
+};
+
+/include/ "vexpress-v2m-rs1.dtsi"
diff --git a/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt
new file mode 100644
index 0000000..90fa7da
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt
@@ -0,0 +1,30 @@
+* NVIDIA Tegra APB DMA controller
+
+Required properties:
+- compatible: Should be "nvidia,<chip>-apbdma"
+- reg: Should contain DMA registers location and length. This shuld include
+  all of the per-channel registers.
+- interrupts: Should contain all of the per-channel DMA interrupts.
+
+Examples:
+
+apbdma: dma@6000a000 {
+	compatible = "nvidia,tegra20-apbdma";
+	reg = <0x6000a000 0x1200>;
+	interrupts = < 0 136 0x04
+		       0 137 0x04
+		       0 138 0x04
+		       0 139 0x04
+		       0 140 0x04
+		       0 141 0x04
+		       0 142 0x04
+		       0 143 0x04
+		       0 144 0x04
+		       0 145 0x04
+		       0 146 0x04
+		       0 147 0x04
+		       0 148 0x04
+		       0 149 0x04
+		       0 150 0x04
+		       0 151 0x04 >;
+};
diff --git a/Documentation/devicetree/bindings/gpio/gpio-omap.txt b/Documentation/devicetree/bindings/gpio/gpio-omap.txt
new file mode 100644
index 0000000..bff51a2
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-omap.txt
@@ -0,0 +1,36 @@
+OMAP GPIO controller bindings
+
+Required properties:
+- compatible:
+  - "ti,omap2-gpio" for OMAP2 controllers
+  - "ti,omap3-gpio" for OMAP3 controllers
+  - "ti,omap4-gpio" for OMAP4 controllers
+- #gpio-cells : Should be two.
+  - first cell is the pin number
+  - second cell is used to specify optional parameters (unused)
+- gpio-controller : Marks the device node as a GPIO controller.
+- #interrupt-cells : Should be 2.
+- interrupt-controller: Mark the device node as an interrupt controller
+  The first cell is the GPIO number.
+  The second cell is used to specify flags:
+    bits[3:0] trigger type and level flags:
+      1 = low-to-high edge triggered.
+      2 = high-to-low edge triggered.
+      4 = active high level-sensitive.
+      8 = active low level-sensitive.
+
+OMAP specific properties:
+- ti,hwmods: Name of the hwmod associated to the GPIO:
+  "gpio<X>", <X> being the 1-based instance number from the HW spec
+
+
+Example:
+
+gpio4: gpio4 {
+    compatible = "ti,omap4-gpio";
+    ti,hwmods = "gpio4";
+    #gpio-cells = <2>;
+    gpio-controller;
+    #interrupt-cells = <2>;
+    interrupt-controller;
+};
diff --git a/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt b/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt
new file mode 100644
index 0000000..16695d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt
@@ -0,0 +1,23 @@
+twl4030 GPIO controller bindings
+
+Required properties:
+- compatible:
+  - "ti,twl4030-gpio" for twl4030 GPIO controller
+- #gpio-cells : Should be two.
+  - first cell is the pin number
+  - second cell is used to specify optional parameters (unused)
+- gpio-controller : Marks the device node as a GPIO controller.
+- #interrupt-cells : Should be 2.
+- interrupt-controller: Mark the device node as an interrupt controller
+  The first cell is the GPIO number.
+  The second cell is not used.
+
+Example:
+
+twl_gpio: gpio {
+    compatible = "ti,twl4030-gpio";
+    #gpio-cells = <2>;
+    gpio-controller;
+    #interrupt-cells = <2>;
+    interrupt-controller;
+};
diff --git a/Documentation/devicetree/bindings/gpio/gpio_atmel.txt b/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
new file mode 100644
index 0000000..66efc80
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
@@ -0,0 +1,20 @@
+* Atmel GPIO controller (PIO)
+
+Required properties:
+- compatible: "atmel,<chip>-gpio", where <chip> is at91rm9200 or at91sam9x5.
+- reg: Should contain GPIO controller registers location and length
+- interrupts: Should be the port interrupt shared by all the pins.
+- #gpio-cells: Should be two.  The first cell is the pin number and
+  the second cell is used to specify optional parameters (currently
+  unused).
+- gpio-controller: Marks the device node as a GPIO controller.
+
+Example:
+	pioA: gpio@fffff200 {
+		compatible = "atmel,at91rm9200-gpio";
+		reg = <0xfffff200 0x100>;
+		interrupts = <2 4>;
+		#gpio-cells = <2>;
+		gpio-controller;
+	};
+
diff --git a/Documentation/devicetree/bindings/gpio/gpio_i2c.txt b/Documentation/devicetree/bindings/gpio/gpio_i2c.txt
new file mode 100644
index 0000000..4f8ec94
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio_i2c.txt
@@ -0,0 +1,32 @@
+Device-Tree bindings for i2c gpio driver
+
+Required properties:
+	- compatible = "i2c-gpio";
+	- gpios: sda and scl gpio
+
+
+Optional properties:
+	- i2c-gpio,sda-open-drain: sda as open drain
+	- i2c-gpio,scl-open-drain: scl as open drain
+	- i2c-gpio,scl-output-only: scl as output only
+	- i2c-gpio,delay-us: delay between GPIO operations (may depend on each platform)
+	- i2c-gpio,timeout-ms: timeout to get data
+
+Example nodes:
+
+i2c@0 {
+	compatible = "i2c-gpio";
+	gpios = <&pioA 23 0 /* sda */
+		 &pioA 24 0 /* scl */
+		>;
+	i2c-gpio,sda-open-drain;
+	i2c-gpio,scl-open-drain;
+	i2c-gpio,delay-us = <2>;	/* ~100 kHz */
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	rv3029c2@56 {
+		compatible = "rv3029c2";
+		reg = <0x56>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt
index eb4b530..023c952 100644
--- a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt
@@ -1,8 +1,40 @@
-NVIDIA Tegra 2 GPIO controller
+NVIDIA Tegra GPIO controller
 
 Required properties:
-- compatible : "nvidia,tegra20-gpio"
+- compatible : "nvidia,tegra<chip>-gpio"
+- reg : Physical base address and length of the controller's registers.
+- interrupts : The interrupt outputs from the controller. For Tegra20,
+  there should be 7 interrupts specified, and for Tegra30, there should
+  be 8 interrupts specified.
 - #gpio-cells : Should be two. The first cell is the pin number and the
   second cell is used to specify optional parameters:
   - bit 0 specifies polarity (0 for normal, 1 for inverted)
 - gpio-controller : Marks the device node as a GPIO controller.
+- #interrupt-cells : Should be 2.
+  The first cell is the GPIO number.
+  The second cell is used to specify flags:
+    bits[3:0] trigger type and level flags:
+      1 = low-to-high edge triggered.
+      2 = high-to-low edge triggered.
+      4 = active high level-sensitive.
+      8 = active low level-sensitive.
+      Valid combinations are 1, 2, 3, 4, 8.
+- interrupt-controller : Marks the device node as an interrupt controller.
+
+Example:
+
+gpio: gpio@6000d000 {
+	compatible = "nvidia,tegra20-gpio";
+	reg = < 0x6000d000 0x1000 >;
+	interrupts = < 0 32 0x04
+		       0 33 0x04
+		       0 34 0x04
+		       0 35 0x04
+		       0 55 0x04
+		       0 87 0x04
+		       0 89 0x04 >;
+	#gpio-cells = <2>;
+	gpio-controller;
+	#interrupt-cells = <2>;
+	interrupt-controller;
+};
diff --git a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
new file mode 100644
index 0000000..1e34cfe
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
@@ -0,0 +1,23 @@
+* Marvell PXA GPIO controller
+
+Required properties:
+- compatible : Should be "mrvl,pxa-gpio" or "mrvl,mmp-gpio"
+- reg : Address and length of the register set for the device
+- interrupts : Should be the port interrupt shared by all gpio pins, if
+- interrupt-name : Should be the name of irq resource.
+  one number.
+- gpio-controller : Marks the device node as a gpio controller.
+- #gpio-cells : Should be one.  It is the pin number.
+
+Example:
+
+	gpio: gpio@d4019000 {
+		compatible = "mrvl,mmp-gpio", "mrvl,pxa-gpio";
+		reg = <0xd4019000 0x1000>;
+		interrupts = <49>, <17>, <18>;
+		interrupt-name = "gpio_mux", "gpio0", "gpio1";
+		gpio-controller;
+		#gpio-cells = <1>;
+		interrupt-controller;
+		#interrupt-cells = <1>;
+      };
diff --git a/Documentation/devicetree/bindings/gpio/sodaville.txt b/Documentation/devicetree/bindings/gpio/sodaville.txt
new file mode 100644
index 0000000..563eff22
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/sodaville.txt
@@ -0,0 +1,48 @@
+GPIO controller on CE4100 / Sodaville SoCs
+==========================================
+
+The bindings for CE4100's GPIO controller match the generic description
+which is covered by the gpio.txt file in this folder.
+
+The only additional property is the intel,muxctl property which holds the
+value which is written into the MUXCNTL register.
+
+There is no compatible property for now because the driver is probed via
+PCI id (vendor 0x8086 device 0x2e67).
+
+The interrupt specifier consists of two cells encoded as follows:
+ - <1st cell>: The interrupt-number that identifies the interrupt source.
+ - <2nd cell>: The level-sense information, encoded as follows:
+		4 - active high level-sensitive
+		8 - active low level-sensitive
+
+Example of the GPIO device and one user:
+
+	pcigpio: gpio@b,1 {
+			/* two cells for GPIO and interrupt */
+			#gpio-cells = <2>;
+			#interrupt-cells = <2>;
+			compatible = "pci8086,2e67.2",
+					   "pci8086,2e67",
+					   "pciclassff0000",
+					   "pciclassff00";
+
+			reg = <0x15900 0x0 0x0 0x0 0x0>;
+			/* Interrupt line of the gpio device */
+			interrupts = <15 1>;
+			/* It is an interrupt and GPIO controller itself */
+			interrupt-controller;
+			gpio-controller;
+			intel,muxctl = <0>;
+	};
+
+	testuser@20 {
+			compatible = "example,testuser";
+			/* User the 11th GPIO line as an active high triggered
+			 * level interrupt
+			 */
+			interrupts = <11 8>;
+			interrupt-parent = <&pcigpio>;
+			/* Use this GPIO also with the gpio functions */
+			gpios = <&pcigpio 11 0>;
+	};
diff --git a/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt b/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt
new file mode 100644
index 0000000..071eb3c
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt
@@ -0,0 +1,37 @@
+* I2C
+
+Required properties :
+
+ - reg : Offset and length of the register set for the device
+ - compatible : should be "mrvl,mmp-twsi" where CHIP is the name of a
+   compatible processor, e.g. pxa168, pxa910, mmp2, mmp3.
+   For the pxa2xx/pxa3xx, an additional node "mrvl,pxa-i2c" is required
+   as shown in the example below.
+
+Recommended properties :
+
+ - interrupts : <a b> where a is the interrupt number and b is a
+   field that represents an encoding of the sense and level
+   information for the interrupt.  This should be encoded based on
+   the information in section 2) depending on the type of interrupt
+   controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+ - mrvl,i2c-polling : Disable interrupt of i2c controller. Polling
+   status register of i2c controller instead.
+ - mrvl,i2c-fast-mode : Enable fast mode of i2c controller.
+
+Examples:
+	twsi1: i2c@d4011000 {
+		compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+		reg = <0xd4011000 0x1000>;
+		interrupts = <7>;
+		mrvl,i2c-fast-mode;
+	};
+	
+	twsi2: i2c@d4025000 {
+		compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+		reg = <0xd4025000 0x1000>;
+		interrupts = <58>;
+	};
+
diff --git a/Documentation/devicetree/bindings/i2c/sirf-i2c.txt b/Documentation/devicetree/bindings/i2c/sirf-i2c.txt
new file mode 100644
index 0000000..7baf9e1
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/sirf-i2c.txt
@@ -0,0 +1,19 @@
+I2C for SiRFprimaII platforms
+
+Required properties :
+- compatible : Must be "sirf,prima2-i2c"
+- reg: physical base address of the controller and length of memory mapped
+     region.
+- interrupts: interrupt number to the cpu.
+
+Optional properties:
+- clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz.
+  The absence of the propoerty indicates the default frequency 100 kHz.
+
+Examples :
+
+i2c0: i2c@b00e0000 {
+    compatible = "sirf,prima2-i2c";
+    reg = <0xb00e0000 0x10000>;
+    interrupts = <24>;
+};
diff --git a/Documentation/devicetree/bindings/input/matrix-keymap.txt b/Documentation/devicetree/bindings/input/matrix-keymap.txt
new file mode 100644
index 0000000..3cd8b98
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/matrix-keymap.txt
@@ -0,0 +1,19 @@
+A simple common binding for matrix-connected key boards. Currently targeted at
+defining the keys in the scope of linux key codes since that is a stable and
+standardized interface at this time.
+
+Required properties:
+- linux,keymap: an array of packed 1-cell entries containing the equivalent
+  of row, column and linux key-code. The 32-bit big endian cell is packed
+  as:
+	row << 24 | column << 16 | key-code
+
+Optional properties:
+Some users of this binding might choose to specify secondary keymaps for
+cases where there is a modifier key such as a Fn key. Proposed names
+for said properties are "linux,fn-keymap" or with another descriptive
+word for the modifier other from "Fn".
+
+Example:
+	linux,keymap = < 0x00030012
+			 0x0102003a >;
diff --git a/Documentation/devicetree/bindings/input/tegra-kbc.txt b/Documentation/devicetree/bindings/input/tegra-kbc.txt
index 5ecfa99..72683be 100644
--- a/Documentation/devicetree/bindings/input/tegra-kbc.txt
+++ b/Documentation/devicetree/bindings/input/tegra-kbc.txt
@@ -3,16 +3,21 @@
 Required properties:
 - compatible: "nvidia,tegra20-kbc"
 
-Optional properties:
-- debounce-delay: delay in milliseconds per row scan for debouncing
-- repeat-delay: delay in milliseconds before repeat starts
-- ghost-filter: enable ghost filtering for this device
-- wakeup-source: configure keyboard as a wakeup source for suspend/resume
+Optional properties, in addition to those specified by the shared
+matrix-keyboard bindings:
+
+- linux,fn-keymap: a second keymap, same specification as the
+  matrix-keyboard-controller spec but to be used when the KEY_FN modifier
+  key is pressed.
+- nvidia,debounce-delay-ms: delay in milliseconds per row scan for debouncing
+- nvidia,repeat-delay-ms: delay in milliseconds before repeat starts
+- nvidia,ghost-filter: enable ghost filtering for this device
+- nvidia,wakeup-source: configure keyboard as a wakeup source for suspend/resume
 
 Example:
 
 keyboard: keyboard {
 	compatible = "nvidia,tegra20-kbc";
 	reg = <0x7000e200 0x100>;
-	ghost-filter;
+	nvidia,ghost-filter;
 };
diff --git a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
new file mode 100644
index 0000000..dbd4368
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
@@ -0,0 +1,33 @@
+* TI Highspeed MMC host controller for OMAP
+
+The Highspeed MMC Host Controller on TI OMAP family
+provides an interface for MMC, SD, and SDIO types of memory cards.
+
+Required properties:
+- compatible:
+ Should be "ti,omap2-hsmmc", for OMAP2 controllers
+ Should be "ti,omap3-hsmmc", for OMAP3 controllers
+ Should be "ti,omap4-hsmmc", for OMAP4 controllers
+- ti,hwmods: Must be "mmc<n>", n is controller instance starting 1
+- reg : should contain hsmmc registers location and length
+
+Optional properties:
+ti,dual-volt: boolean, supports dual voltage cards
+<supply-name>-supply: phandle to the regulator device tree node
+"supply-name" examples are "vmmc", "vmmc_aux" etc
+ti,bus-width: Number of data lines, default assumed is 1 if the property is missing.
+cd-gpios: GPIOs for card detection
+wp-gpios: GPIOs for write protection
+ti,non-removable: non-removable slot (like eMMC)
+ti,needs-special-reset: Requires a special softreset sequence
+
+Example:
+	mmc1: mmc@0x4809c000 {
+		compatible = "ti,omap4-hsmmc";
+		reg = <0x4809c000 0x400>;
+		ti,hwmods = "mmc1";
+		ti,dual-volt;
+		ti,bus-width = <4>;
+		vmmc-supply = <&vmmc>; /* phandle to regulator node */
+		ti,non-removable;
+	};
diff --git a/Documentation/devicetree/bindings/mtd/arm-versatile.txt b/Documentation/devicetree/bindings/mtd/arm-versatile.txt
index 476845d..beace4b 100644
--- a/Documentation/devicetree/bindings/mtd/arm-versatile.txt
+++ b/Documentation/devicetree/bindings/mtd/arm-versatile.txt
@@ -4,5 +4,5 @@
 - compatible : must be "arm,versatile-flash";
 - bank-width : width in bytes of flash interface.
 
-Optional properties:
-- Subnode partition map from mtd flash binding
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
diff --git a/Documentation/devicetree/bindings/mtd/atmel-dataflash.txt b/Documentation/devicetree/bindings/mtd/atmel-dataflash.txt
index ef66ddd..1889a4d 100644
--- a/Documentation/devicetree/bindings/mtd/atmel-dataflash.txt
+++ b/Documentation/devicetree/bindings/mtd/atmel-dataflash.txt
@@ -3,6 +3,9 @@
 Required properties:
 - compatible : "atmel,<model>", "atmel,<series>", "atmel,dataflash".
 
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
+
 Example:
 
 flash@1 {
diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
new file mode 100644
index 0000000..a200695
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
@@ -0,0 +1,41 @@
+Atmel NAND flash
+
+Required properties:
+- compatible : "atmel,at91rm9200-nand".
+- reg : should specify localbus address and size used for the chip,
+	and if availlable the ECC.
+- atmel,nand-addr-offset : offset for the address latch.
+- atmel,nand-cmd-offset : offset for the command latch.
+- #address-cells, #size-cells : Must be present if the device has sub-nodes
+  representing partitions.
+
+- gpios : specifies the gpio pins to control the NAND device. detect is an
+  optional gpio and may be set to 0 if not present.
+
+Optional properties:
+- nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
+  Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
+  "soft_bch".
+- nand-bus-width : 8 or 16 bus width if not present 8
+- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
+
+Examples:
+nand0: nand@40000000,0 {
+	compatible = "atmel,at91rm9200-nand";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	reg = <0x40000000 0x10000000
+	       0xffffe800 0x200
+	      >;
+	atmel,nand-addr-offset = <21>;	/* ale */
+	atmel,nand-cmd-offset = <22>;	/* cle */
+	nand-on-flash-bbt;
+	nand-ecc-mode = "soft";
+	gpios = <&pioC 13 0	/* rdy */
+		 &pioC 14 0 	/* nce */
+		 0		/* cd */
+		>;
+	partition@0 {
+		...
+	};
+};
diff --git a/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt b/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt
index 00f1f54..fce4894 100644
--- a/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt
@@ -19,6 +19,10 @@
 	read registers (tR). Required if property "gpios" is not used
 	(R/B# pins not connected).
 
+Each flash chip described may optionally contain additional sub-nodes
+describing partitions of the address space. See partition.txt for more
+detail.
+
 Examples:
 
 upm@1,0 {
diff --git a/Documentation/devicetree/bindings/mtd/fsmc-nand.txt b/Documentation/devicetree/bindings/mtd/fsmc-nand.txt
new file mode 100644
index 0000000..e2c663b
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/fsmc-nand.txt
@@ -0,0 +1,33 @@
+* FSMC NAND
+
+Required properties:
+- compatible : "st,spear600-fsmc-nand"
+- reg : Address range of the mtd chip
+- reg-names: Should contain the reg names "fsmc_regs" and "nand_data"
+- st,ale-off : Chip specific offset to ALE
+- st,cle-off : Chip specific offset to CLE
+
+Optional properties:
+- bank-width : Width (in bytes) of the device.  If not present, the width
+  defaults to 1 byte
+- nand-skip-bbtscan: Indicates the the BBT scanning should be skipped
+
+Example:
+
+	fsmc: flash@d1800000 {
+		compatible = "st,spear600-fsmc-nand";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xd1800000 0x1000	/* FSMC Register */
+		       0xd2000000 0x4000>;	/* NAND Base */
+		reg-names = "fsmc_regs", "nand_data";
+		st,ale-off = <0x20000>;
+		st,cle-off = <0x10000>;
+
+		bank-width = <1>;
+		nand-skip-bbtscan;
+
+		partition@0 {
+			...
+		};
+	};
diff --git a/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt b/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt
index 719f4dc..36ef07d 100644
--- a/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt
@@ -25,6 +25,9 @@
   GPIO state and before and after command byte writes, this register will be
   read to ensure that the GPIO accesses have completed.
 
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
+
 Examples:
 
 gpio-nand@1,0 {
diff --git a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt
index 80152cb..a63c2bd7 100644
--- a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt
+++ b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt
@@ -23,27 +23,8 @@
  - vendor-id : Contains the flash chip's vendor id (1 byte).
  - device-id : Contains the flash chip's device id (1 byte).
 
-In addition to the information on the mtd bank itself, the
-device tree may optionally contain additional information
-describing partitions of the address space.  This can be
-used on platforms which have strong conventions about which
-portions of a flash are used for what purposes, but which don't
-use an on-flash partition table such as RedBoot.
-
-Each partition is represented as a sub-node of the mtd device.
-Each node's name represents the name of the corresponding
-partition of the mtd device.
-
-Flash partitions
- - reg : The partition's offset and size within the mtd bank.
- - label : (optional) The label / name for this partition.
-   If omitted, the label is taken from the node name (excluding
-   the unit address).
- - read-only : (optional) This parameter, if present, is a hint to
-   Linux that this partition should only be mounted
-   read-only.  This is usually used for flash partitions
-   containing early-boot firmware images or data which should not
-   be clobbered.
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/mtd/nand.txt b/Documentation/devicetree/bindings/mtd/nand.txt
new file mode 100644
index 0000000..03855c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/nand.txt
@@ -0,0 +1,7 @@
+* MTD generic binding
+
+- nand-ecc-mode : String, operation mode of the NAND ecc mode.
+  Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
+  "soft_bch".
+- nand-bus-width : 8 or 16 bus width if not present 8
+- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt
new file mode 100644
index 0000000..f114ce1
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/partition.txt
@@ -0,0 +1,38 @@
+Representing flash partitions in devicetree
+
+Partitions can be represented by sub-nodes of an mtd device. This can be used
+on platforms which have strong conventions about which portions of a flash are
+used for what purposes, but which don't use an on-flash partition table such
+as RedBoot.
+
+#address-cells & #size-cells must both be present in the mtd device and be
+equal to 1.
+
+Required properties:
+- reg : The partition's offset and size within the mtd bank.
+
+Optional properties:
+- label : The label / name for this partition.  If omitted, the label is taken
+  from the node name (excluding the unit address).
+- read-only : This parameter, if present, is a hint to Linux that this
+  partition should only be mounted read-only. This is usually used for flash
+  partitions containing early-boot firmware images or data which should not be
+  clobbered.
+
+Examples:
+
+
+flash@0 {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	partition@0 {
+		label = "u-boot";
+		reg = <0x0000000 0x100000>;
+		read-only;
+	};
+
+	uimage@100000 {
+		reg = <0x0100000 0x200000>;
+	};
+];
diff --git a/Documentation/devicetree/bindings/mtd/spear_smi.txt b/Documentation/devicetree/bindings/mtd/spear_smi.txt
new file mode 100644
index 0000000..7248aad
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/spear_smi.txt
@@ -0,0 +1,31 @@
+* SPEAr SMI
+
+Required properties:
+- compatible : "st,spear600-smi"
+- reg : Address range of the mtd chip
+- #address-cells, #size-cells : Must be present if the device has sub-nodes
+  representing partitions.
+- interrupt-parent: Should be the phandle for the interrupt controller
+  that services interrupts for this device
+- interrupts: Should contain the STMMAC interrupts
+- clock-rate : Functional clock rate of SMI in Hz
+
+Optional properties:
+- st,smi-fast-mode : Flash supports read in fast mode
+
+Example:
+
+	smi: flash@fc000000 {
+		compatible = "st,spear600-smi";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xfc000000 0x1000>;
+		interrupt-parent = <&vic1>;
+		interrupts = <12>;
+		clock-rate = <50000000>;	/* 50MHz */
+
+		flash@f8000000 {
+			st,smi-fast-mode;
+			...
+		};
+	};
diff --git a/Documentation/devicetree/bindings/power_supply/max17042_battery.txt b/Documentation/devicetree/bindings/power_supply/max17042_battery.txt
new file mode 100644
index 0000000..5bc9b68
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_supply/max17042_battery.txt
@@ -0,0 +1,18 @@
+max17042_battery
+~~~~~~~~~~~~~~~~
+
+Required properties :
+ - compatible : "maxim,max17042"
+
+Optional properties :
+ - maxim,rsns-microohm : Resistance of rsns resistor in micro Ohms
+                         (datasheet-recommended value is 10000).
+   Defining this property enables current-sense functionality.
+
+Example:
+
+	battery-charger@36 {
+		compatible = "maxim,max17042";
+		reg = <0x36>;
+		maxim,rsns-microohm = <10000>;
+	};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic-msgr.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic-msgr.txt
new file mode 100644
index 0000000..bc8ded6
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/fsl/mpic-msgr.txt
@@ -0,0 +1,63 @@
+* FSL MPIC Message Registers
+
+This binding specifies what properties must be available in the device tree
+representation of the message register blocks found in some FSL MPIC
+implementations.
+
+Required properties:
+
+    - compatible: Specifies the compatibility list for the message register
+      block.  The type shall be <string-list> and the value shall be of the form
+      "fsl,mpic-v<version>-msgr", where <version> is the version number of
+      the MPIC containing the message registers.
+
+    - reg: Specifies the base physical address(s) and size(s) of the
+      message register block's addressable register space.  The type shall be
+      <prop-encoded-array>.
+
+    - interrupts: Specifies a list of interrupt-specifiers which are available
+      for receiving interrupts. Interrupt-specifier consists of two cells: first
+      cell is interrupt-number and second cell is level-sense. The type shall be
+      <prop-encoded-array>.
+
+Optional properties:
+
+    - mpic-msgr-receive-mask: Specifies what registers in the containing block
+      are allowed to receive interrupts. The value is a bit mask where a set
+      bit at bit 'n' indicates that message register 'n' can receive interrupts.
+      Note that "bit 'n'" is numbered from LSB for PPC hardware. The type shall
+      be <u32>. If not present, then all of the message registers in the block
+      are available.
+
+Aliases:
+
+    An alias should be created for every message register block.  They are not
+    required, though.  However, a particular implementation of this binding
+    may require aliases to be present.  Aliases are of the form
+    'mpic-msgr-block<n>', where <n> is an integer specifying the block's number.
+    Numbers shall start at 0.
+
+Example:
+
+	aliases {
+		mpic-msgr-block0 = &mpic_msgr_block0;
+		mpic-msgr-block1 = &mpic_msgr_block1;
+	};
+
+	mpic_msgr_block0: mpic-msgr-block@41400 {
+		compatible = "fsl,mpic-v3.1-msgr";
+		reg = <0x41400 0x200>;
+		// Message registers 0 and 2 in this block can receive interrupts on
+		// sources 0xb0 and 0xb2, respectively.
+		interrupts = <0xb0 2 0xb2 2>;
+		mpic-msgr-receive-mask = <0x5>;
+	};
+
+	mpic_msgr_block1: mpic-msgr-block@42400 {
+		compatible = "fsl,mpic-v3.1-msgr";
+		reg = <0x42400 0x200>;
+		// Message registers 0 and 2 in this block can receive interrupts on
+		// sources 0xb4 and 0xb6, respectively.
+		interrupts = <0xb4 2 0xb6 2>;
+		mpic-msgr-receive-mask = <0x5>;
+	};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
index 2cf38bd..dc57446 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
+++ b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
@@ -56,7 +56,27 @@
           to the client.  The presence of this property also mandates
           that any initialization related to interrupt sources shall
           be limited to sources explicitly referenced in the device tree.
-       
+
+  - big-endian
+      Usage: optional
+      Value type: <empty>
+          If present the MPIC will be assumed to be big-endian.  Some
+          device-trees omit this property on MPIC nodes even when the MPIC is
+          in fact big-endian, so certain boards override this property.
+
+  - single-cpu-affinity
+      Usage: optional
+      Value type: <empty>
+          If present the MPIC will be assumed to only be able to route
+          non-IPI interrupts to a single CPU at a time (EG: Freescale MPIC).
+
+  - last-interrupt-source
+      Usage: optional
+      Value type: <u32>
+          Some MPICs do not correctly report the number of hardware sources
+          in the global feature registers.  If specified, this field will
+          override the value read from MPIC_GREG_FEATURE_LAST_SRC.
+
 INTERRUPT SPECIFIER DEFINITION
 
   Interrupt specifiers consists of 4 cells encoded as
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt b/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt
index 5d586e1..5693877 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt
+++ b/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt
@@ -6,8 +6,10 @@
   etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" depending on
   the parent type.
 
-- reg : should contain the address and the length of the shared message
-  interrupt register set.
+- reg : It may contain one or two regions. The first region should contain
+  the address and the length of the shared message interrupt register set.
+  The second region should contain the address of aliased MSIIR register for
+  platforms that have such an alias.
 
 - msi-available-ranges: use <start count> style section to define which
   msi interrupt can be used in the 256 msi interrupts. This property is
diff --git a/Documentation/devicetree/bindings/regulator/anatop-regulator.txt b/Documentation/devicetree/bindings/regulator/anatop-regulator.txt
new file mode 100644
index 0000000..357758c
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/anatop-regulator.txt
@@ -0,0 +1,29 @@
+Anatop Voltage regulators
+
+Required properties:
+- compatible: Must be "fsl,anatop-regulator"
+- anatop-reg-offset: Anatop MFD register offset
+- anatop-vol-bit-shift: Bit shift for the register
+- anatop-vol-bit-width: Number of bits used in the register
+- anatop-min-bit-val: Minimum value of this register
+- anatop-min-voltage: Minimum voltage of this regulator
+- anatop-max-voltage: Maximum voltage of this regulator
+
+Any property defined as part of the core regulator
+binding, defined in regulator.txt, can also be used.
+
+Example:
+
+	regulator-vddpu {
+		compatible = "fsl,anatop-regulator";
+		regulator-name = "vddpu";
+		regulator-min-microvolt = <725000>;
+		regulator-max-microvolt = <1300000>;
+		regulator-always-on;
+		anatop-reg-offset = <0x140>;
+		anatop-vol-bit-shift = <9>;
+		anatop-vol-bit-width = <5>;
+		anatop-min-bit-val = <1>;
+		anatop-min-voltage = <725000>;
+		anatop-max-voltage = <1300000>;
+	};
diff --git a/Documentation/devicetree/bindings/rtc/sa1100-rtc.txt b/Documentation/devicetree/bindings/rtc/sa1100-rtc.txt
new file mode 100644
index 0000000..0cda19a
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/sa1100-rtc.txt
@@ -0,0 +1,17 @@
+* Marvell Real Time Clock controller
+
+Required properties:
+- compatible: should be "mrvl,sa1100-rtc"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- interrupts: Should be two. The first interrupt number is the rtc alarm
+  interrupt and the second interrupt number is the rtc hz interrupt.
+- interrupt-names: Assign name of irq resource.
+
+Example:
+	rtc: rtc@d4010000 {
+		compatible = "mrvl,mmp-rtc";
+		reg = <0xd4010000 0x1000>;
+		interrupts = <5>, <6>;
+		interrupt-name = "rtc 1Hz", "rtc alarm";
+	};
diff --git a/Documentation/devicetree/bindings/serial/mrvl-serial.txt b/Documentation/devicetree/bindings/serial/mrvl-serial.txt
new file mode 100644
index 0000000..d744340
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/mrvl-serial.txt
@@ -0,0 +1,4 @@
+PXA UART controller
+
+Required properties:
+- compatible : should be "mrvl,mmp-uart" or "mrvl,pxa-uart".
diff --git a/Documentation/devicetree/bindings/sound/alc5632.txt b/Documentation/devicetree/bindings/sound/alc5632.txt
new file mode 100644
index 0000000..8608f74
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/alc5632.txt
@@ -0,0 +1,24 @@
+ALC5632 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+  - compatible : "realtek,alc5632"
+
+  - reg : the I2C address of the device.
+
+  - gpio-controller : Indicates this device is a GPIO controller.
+
+  - #gpio-cells : Should be two. The first cell is the pin number and the
+    second cell is used to specify optional parameters (currently unused).
+
+Example:
+
+alc5632: alc5632@1e {
+	compatible = "realtek,alc5632";
+	reg = <0x1a>;
+
+	gpio-controller;
+	#gpio-cells = <2>;
+};
diff --git a/Documentation/devicetree/bindings/sound/imx-audmux.txt b/Documentation/devicetree/bindings/sound/imx-audmux.txt
new file mode 100644
index 0000000..215aa98
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/imx-audmux.txt
@@ -0,0 +1,13 @@
+Freescale Digital Audio Mux (AUDMUX) device
+
+Required properties:
+- compatible : "fsl,imx21-audmux" for AUDMUX version firstly used on i.MX21,
+  or "fsl,imx31-audmux" for the version firstly used on i.MX31.
+- reg : Should contain AUDMUX registers location and length
+
+Example:
+
+audmux@021d8000 {
+	compatible = "fsl,imx6q-audmux", "fsl,imx31-audmux";
+	reg = <0x021d8000 0x4000>;
+};
diff --git a/Documentation/devicetree/bindings/sound/soc/codecs/fsl-sgtl5000.txt b/Documentation/devicetree/bindings/sound/sgtl5000.txt
similarity index 100%
rename from Documentation/devicetree/bindings/sound/soc/codecs/fsl-sgtl5000.txt
rename to Documentation/devicetree/bindings/sound/sgtl5000.txt
diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-alc5632.txt b/Documentation/devicetree/bindings/sound/tegra-audio-alc5632.txt
new file mode 100644
index 0000000..b77a97c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tegra-audio-alc5632.txt
@@ -0,0 +1,59 @@
+NVIDIA Tegra audio complex
+
+Required properties:
+- compatible : "nvidia,tegra-audio-alc5632"
+- nvidia,model : The user-visible name of this sound complex.
+- 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:
+
+  * Headset Stereophone
+  * Int Spk
+  * Headset Mic
+  * Digital Mic
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S controller
+- nvidia,audio-codec : The phandle of the ALC5632 audio codec
+
+Example:
+
+sound {
+	compatible = "nvidia,tegra-audio-alc5632-paz00",
+				 "nvidia,tegra-audio-alc5632";
+
+	nvidia,model = "Compal PAZ00";
+
+	nvidia,audio-routing =
+				"Int Spk", "SPK_OUTP",
+				"Int Spk", "SPK_OUTN",
+				"Headset Mic","MICBIAS1",
+				"MIC1_N", "Headset Mic",
+				"MIC1_P", "Headset Mic",
+				"Headset Stereophone", "HP_OUT_R",
+				"Headset Stereophone", "HP_OUT_L";
+
+	nvidia,i2s-controller = <&tegra_i2s1>;
+	nvidia,audio-codec = <&alc5632>;
+};
diff --git a/Documentation/devicetree/bindings/usb/atmel-usb.txt b/Documentation/devicetree/bindings/usb/atmel-usb.txt
new file mode 100644
index 0000000..60bd215
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/atmel-usb.txt
@@ -0,0 +1,49 @@
+Atmel SOC USB controllers
+
+OHCI
+
+Required properties:
+ - compatible: Should be "atmel,at91rm9200-ohci" for USB controllers
+   used in host mode.
+ - num-ports: Number of ports.
+ - atmel,vbus-gpio: If present, specifies a gpio that needs to be
+   activated for the bus to be powered.
+ - atmel,oc-gpio: If present, specifies a gpio that needs to be
+   activated for the overcurrent detection.
+
+usb0: ohci@00500000 {
+	compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+	reg = <0x00500000 0x100000>;
+	interrupts = <20 4>;
+	num-ports = <2>;
+};
+
+EHCI
+
+Required properties:
+ - compatible: Should be "atmel,at91sam9g45-ehci" for USB controllers
+   used in host mode.
+
+usb1: ehci@00800000 {
+	compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
+	reg = <0x00800000 0x100000>;
+	interrupts = <22 4>;
+};
+
+AT91 USB device controller
+
+Required properties:
+ - compatible: Should be "atmel,at91rm9200-udc"
+ - reg: Address and length of the register set for the device
+ - interrupts: Should contain macb interrupt
+
+Optional properties:
+ - atmel,vbus-gpio: If present, specifies a gpio that needs to be
+   activated for the bus to be powered.
+
+usb1: gadget@fffa4000 {
+	compatible = "atmel,at91rm9200-udc";
+	reg = <0xfffa4000 0x4000>;
+	interrupts = <10 4>;
+	atmel,vbus-gpio = <&pioC 5 0>;
+};
diff --git a/Documentation/devicetree/bindings/usb/tegra-usb.txt b/Documentation/devicetree/bindings/usb/tegra-usb.txt
index 035d63d..007005d 100644
--- a/Documentation/devicetree/bindings/usb/tegra-usb.txt
+++ b/Documentation/devicetree/bindings/usb/tegra-usb.txt
@@ -11,3 +11,16 @@
  - phy_type : Should be one of "ulpi" or "utmi".
  - nvidia,vbus-gpio : If present, specifies a gpio that needs to be
    activated for the bus to be powered.
+
+Optional properties:
+  - dr_mode : dual role mode. Indicates the working mode for
+   nvidia,tegra20-ehci compatible controllers.  Can be "host", "peripheral",
+   or "otg".  Default to "host" if not defined for backward compatibility.
+      host means this is a host controller
+      peripheral means it is device controller
+      otg means it can operate as either ("on the go")
+  - nvidia,has-legacy-mode : boolean indicates whether this controller can
+    operate in legacy mode (as APX 2500 / 2600). In legacy mode some
+    registers are accessed through the APB_MISC base address instead of
+    the USB controller. Since this is a legacy issue it probably does not
+    warrant a compatible string of its own.
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index a20008a..82ac057 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -34,6 +34,7 @@
 powervr	Imagination Technologies
 qcom	Qualcomm, Inc.
 ramtron	Ramtron International
+realtek Realtek Semiconductor Corp.
 samsung	Samsung Semiconductor
 sbs	Smart Battery System
 schindler	Schindler
diff --git a/Documentation/devicetree/usage-model.txt b/Documentation/devicetree/usage-model.txt
new file mode 100644
index 0000000..c5a8009
--- /dev/null
+++ b/Documentation/devicetree/usage-model.txt
@@ -0,0 +1,412 @@
+Linux and the Device Tree
+-------------------------
+The Linux usage model for device tree data
+
+Author: Grant Likely <grant.likely@secretlab.ca>
+
+This article describes how Linux uses the device tree.  An overview of
+the device tree data format can be found on the device tree usage page
+at devicetree.org[1].
+
+[1] http://devicetree.org/Device_Tree_Usage
+
+The "Open Firmware Device Tree", or simply Device Tree (DT), is a data
+structure and language for describing hardware.  More specifically, it
+is a description of hardware that is readable by an operating system
+so that the operating system doesn't need to hard code details of the
+machine.
+
+Structurally, the DT is a tree, or acyclic graph with named nodes, and
+nodes may have an arbitrary number of named properties encapsulating
+arbitrary data.  A mechanism also exists to create arbitrary
+links from one node to another outside of the natural tree structure.
+
+Conceptually, a common set of usage conventions, called 'bindings',
+is defined for how data should appear in the tree to describe typical
+hardware characteristics including data busses, interrupt lines, GPIO
+connections, and peripheral devices.
+
+As much as possible, hardware is described using existing bindings to
+maximize use of existing support code, but since property and node
+names are simply text strings, it is easy to extend existing bindings
+or create new ones by defining new nodes and properties.  Be wary,
+however, of creating a new binding without first doing some homework
+about what already exists.  There are currently two different,
+incompatible, bindings for i2c busses that came about because the new
+binding was created without first investigating how i2c devices were
+already being enumerated in existing systems.
+
+1. History
+----------
+The DT was originally created by Open Firmware as part of the
+communication method for passing data from Open Firmware to a client
+program (like to an operating system).  An operating system used the
+Device Tree to discover the topology of the hardware at runtime, and
+thereby support a majority of available hardware without hard coded
+information (assuming drivers were available for all devices).
+
+Since Open Firmware is commonly used on PowerPC and SPARC platforms,
+the Linux support for those architectures has for a long time used the
+Device Tree.
+
+In 2005, when PowerPC Linux began a major cleanup and to merge 32-bit
+and 64-bit support, the decision was made to require DT support on all
+powerpc platforms, regardless of whether or not they used Open
+Firmware.  To do this, a DT representation called the Flattened Device
+Tree (FDT) was created which could be passed to the kernel as a binary
+blob without requiring a real Open Firmware implementation.  U-Boot,
+kexec, and other bootloaders were modified to support both passing a
+Device Tree Binary (dtb) and to modify a dtb at boot time.  DT was
+also added to the PowerPC boot wrapper (arch/powerpc/boot/*) so that
+a dtb could be wrapped up with the kernel image to support booting
+existing non-DT aware firmware.
+
+Some time later, FDT infrastructure was generalized to be usable by
+all architectures.  At the time of this writing, 6 mainlined
+architectures (arm, microblaze, mips, powerpc, sparc, and x86) and 1
+out of mainline (nios) have some level of DT support.
+
+2. Data Model
+-------------
+If you haven't already read the Device Tree Usage[1] page,
+then go read it now.  It's okay, I'll wait....
+
+2.1 High Level View
+-------------------
+The most important thing to understand is that the DT is simply a data
+structure that describes the hardware.  There is nothing magical about
+it, and it doesn't magically make all hardware configuration problems
+go away.  What it does do is provide a language for decoupling the
+hardware configuration from the board and device driver support in the
+Linux kernel (or any other operating system for that matter).  Using
+it allows board and device support to become data driven; to make
+setup decisions based on data passed into the kernel instead of on
+per-machine hard coded selections.
+
+Ideally, data driven platform setup should result in less code
+duplication and make it easier to support a wide range of hardware
+with a single kernel image.
+
+Linux uses DT data for three major purposes:
+1) platform identification,
+2) runtime configuration, and
+3) device population.
+
+2.2 Platform Identification
+---------------------------
+First and foremost, the kernel will use data in the DT to identify the
+specific machine.  In a perfect world, the specific platform shouldn't
+matter to the kernel because all platform details would be described
+perfectly by the device tree in a consistent and reliable manner.
+Hardware is not perfect though, and so the kernel must identify the
+machine during early boot so that it has the opportunity to run
+machine-specific fixups.
+
+In the majority of cases, the machine identity is irrelevant, and the
+kernel will instead select setup code based on the machine's core
+CPU or SoC.  On ARM for example, setup_arch() in
+arch/arm/kernel/setup.c will call setup_machine_fdt() in
+arch/arm/kernel/devicetree.c which searches through the machine_desc
+table and selects the machine_desc which best matches the device tree
+data.  It determines the best match by looking at the 'compatible'
+property in the root device tree node, and comparing it with the
+dt_compat list in struct machine_desc.
+
+The 'compatible' property contains a sorted list of strings starting
+with the exact name of the machine, followed by an optional list of
+boards it is compatible with sorted from most compatible to least.  For
+example, the root compatible properties for the TI BeagleBoard and its
+successor, the BeagleBoard xM board might look like:
+
+	compatible = "ti,omap3-beagleboard", "ti,omap3450", "ti,omap3";
+	compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3";
+
+Where "ti,omap3-beagleboard-xm" specifies the exact model, it also
+claims that it compatible with the OMAP 3450 SoC, and the omap3 family
+of SoCs in general.  You'll notice that the list is sorted from most
+specific (exact board) to least specific (SoC family).
+
+Astute readers might point out that the Beagle xM could also claim
+compatibility with the original Beagle board.  However, one should be
+cautioned about doing so at the board level since there is typically a
+high level of change from one board to another, even within the same
+product line, and it is hard to nail down exactly what is meant when one
+board claims to be compatible with another.  For the top level, it is
+better to err on the side of caution and not claim one board is
+compatible with another.  The notable exception would be when one
+board is a carrier for another, such as a CPU module attached to a
+carrier board.
+
+One more note on compatible values.  Any string used in a compatible
+property must be documented as to what it indicates.  Add
+documentation for compatible strings in Documentation/devicetree/bindings.
+
+Again on ARM, for each machine_desc, the kernel looks to see if
+any of the dt_compat list entries appear in the compatible property.
+If one does, then that machine_desc is a candidate for driving the
+machine.  After searching the entire table of machine_descs,
+setup_machine_fdt() returns the 'most compatible' machine_desc based
+on which entry in the compatible property each machine_desc matches
+against.  If no matching machine_desc is found, then it returns NULL.
+
+The reasoning behind this scheme is the observation that in the majority
+of cases, a single machine_desc can support a large number of boards
+if they all use the same SoC, or same family of SoCs.  However,
+invariably there will be some exceptions where a specific board will
+require special setup code that is not useful in the generic case.
+Special cases could be handled by explicitly checking for the
+troublesome board(s) in generic setup code, but doing so very quickly
+becomes ugly and/or unmaintainable if it is more than just a couple of
+cases.
+
+Instead, the compatible list allows a generic machine_desc to provide
+support for a wide common set of boards by specifying "less
+compatible" value in the dt_compat list.  In the example above,
+generic board support can claim compatibility with "ti,omap3" or
+"ti,omap3450".  If a bug was discovered on the original beagleboard
+that required special workaround code during early boot, then a new
+machine_desc could be added which implements the workarounds and only
+matches on "ti,omap3-beagleboard".
+
+PowerPC uses a slightly different scheme where it calls the .probe()
+hook from each machine_desc, and the first one returning TRUE is used.
+However, this approach does not take into account the priority of the
+compatible list, and probably should be avoided for new architecture
+support.
+
+2.3 Runtime configuration
+-------------------------
+In most cases, a DT will be the sole method of communicating data from
+firmware to the kernel, so also gets used to pass in runtime and
+configuration data like the kernel parameters string and the location
+of an initrd image.
+
+Most of this data is contained in the /chosen node, and when booting
+Linux it will look something like this:
+
+	chosen {
+		bootargs = "console=ttyS0,115200 loglevel=8";
+		initrd-start = <0xc8000000>;
+		initrd-end = <0xc8200000>;
+	};
+
+The bootargs property contains the kernel arguments, and the initrd-*
+properties define the address and size of an initrd blob.  The
+chosen node may also optionally contain an arbitrary number of
+additional properties for platform-specific configuration data.
+
+During early boot, the architecture setup code calls of_scan_flat_dt()
+several times with different helper callbacks to parse device tree
+data before paging is setup.  The of_scan_flat_dt() code scans through
+the device tree and uses the helpers to extract information required
+during early boot.  Typically the early_init_dt_scan_chosen() helper
+is used to parse the chosen node including kernel parameters,
+early_init_dt_scan_root() to initialize the DT address space model,
+and early_init_dt_scan_memory() to determine the size and
+location of usable RAM.
+
+On ARM, the function setup_machine_fdt() is responsible for early
+scanning of the device tree after selecting the correct machine_desc
+that supports the board.
+
+2.4 Device population
+---------------------
+After the board has been identified, and after the early configuration data
+has been parsed, then kernel initialization can proceed in the normal
+way.  At some point in this process, unflatten_device_tree() is called
+to convert the data into a more efficient runtime representation.
+This is also when machine-specific setup hooks will get called, like
+the machine_desc .init_early(), .init_irq() and .init_machine() hooks
+on ARM.  The remainder of this section uses examples from the ARM
+implementation, but all architectures will do pretty much the same
+thing when using a DT.
+
+As can be guessed by the names, .init_early() is used for any machine-
+specific setup that needs to be executed early in the boot process,
+and .init_irq() is used to set up interrupt handling.  Using a DT
+doesn't materially change the behaviour of either of these functions.
+If a DT is provided, then both .init_early() and .init_irq() are able
+to call any of the DT query functions (of_* in include/linux/of*.h) to
+get additional data about the platform.
+
+The most interesting hook in the DT context is .init_machine() which
+is primarily responsible for populating the Linux device model with
+data about the platform.  Historically this has been implemented on
+embedded platforms by defining a set of static clock structures,
+platform_devices, and other data in the board support .c file, and
+registering it en-masse in .init_machine().  When DT is used, then
+instead of hard coding static devices for each platform, the list of
+devices can be obtained by parsing the DT, and allocating device
+structures dynamically.
+
+The simplest case is when .init_machine() is only responsible for
+registering a block of platform_devices.  A platform_device is a concept
+used by Linux for memory or I/O mapped devices which cannot be detected
+by hardware, and for 'composite' or 'virtual' devices (more on those
+later).  While there is no 'platform device' terminology for the DT,
+platform devices roughly correspond to device nodes at the root of the
+tree and children of simple memory mapped bus nodes.
+
+About now is a good time to lay out an example.  Here is part of the
+device tree for the NVIDIA Tegra board.
+
+/{
+	compatible = "nvidia,harmony", "nvidia,tegra20";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	interrupt-parent = <&intc>;
+
+	chosen { };
+	aliases { };
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x40000000>;
+	};
+
+	soc {
+		compatible = "nvidia,tegra20-soc", "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		intc: interrupt-controller@50041000 {
+			compatible = "nvidia,tegra20-gic";
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			reg = <0x50041000 0x1000>, < 0x50040100 0x0100 >;
+		};
+
+		serial@70006300 {
+			compatible = "nvidia,tegra20-uart";
+			reg = <0x70006300 0x100>;
+			interrupts = <122>;
+		};
+
+		i2s1: i2s@70002800 {
+			compatible = "nvidia,tegra20-i2s";
+			reg = <0x70002800 0x100>;
+			interrupts = <77>;
+			codec = <&wm8903>;
+		};
+
+		i2c@7000c000 {
+			compatible = "nvidia,tegra20-i2c";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x7000c000 0x100>;
+			interrupts = <70>;
+
+			wm8903: codec@1a {
+				compatible = "wlf,wm8903";
+				reg = <0x1a>;
+				interrupts = <347>;
+			};
+		};
+	};
+
+	sound {
+		compatible = "nvidia,harmony-sound";
+		i2s-controller = <&i2s1>;
+		i2s-codec = <&wm8903>;
+	};
+};
+
+At .machine_init() time, Tegra board support code will need to look at
+this DT and decide which nodes to create platform_devices for.
+However, looking at the tree, it is not immediately obvious what kind
+of device each node represents, or even if a node represents a device
+at all.  The /chosen, /aliases, and /memory nodes are informational
+nodes that don't describe devices (although arguably memory could be
+considered a device).  The children of the /soc node are memory mapped
+devices, but the codec@1a is an i2c device, and the sound node
+represents not a device, but rather how other devices are connected
+together to create the audio subsystem.  I know what each device is
+because I'm familiar with the board design, but how does the kernel
+know what to do with each node?
+
+The trick is that the kernel starts at the root of the tree and looks
+for nodes that have a 'compatible' property.  First, it is generally
+assumed that any node with a 'compatible' property represents a device
+of some kind, and second, it can be assumed that any node at the root
+of the tree is either directly attached to the processor bus, or is a
+miscellaneous system device that cannot be described any other way.
+For each of these nodes, Linux allocates and registers a
+platform_device, which in turn may get bound to a platform_driver.
+
+Why is using a platform_device for these nodes a safe assumption?
+Well, for the way that Linux models devices, just about all bus_types
+assume that its devices are children of a bus controller.  For
+example, each i2c_client is a child of an i2c_master.  Each spi_device
+is a child of an SPI bus.  Similarly for USB, PCI, MDIO, etc.  The
+same hierarchy is also found in the DT, where I2C device nodes only
+ever appear as children of an I2C bus node.  Ditto for SPI, MDIO, USB,
+etc.  The only devices which do not require a specific type of parent
+device are platform_devices (and amba_devices, but more on that
+later), which will happily live at the base of the Linux /sys/devices
+tree.  Therefore, if a DT node is at the root of the tree, then it
+really probably is best registered as a platform_device.
+
+Linux board support code calls of_platform_populate(NULL, NULL, NULL)
+to kick off discovery of devices at the root of the tree.  The
+parameters are all NULL because when starting from the root of the
+tree, there is no need to provide a starting node (the first NULL), a
+parent struct device (the last NULL), and we're not using a match
+table (yet).  For a board that only needs to register devices,
+.init_machine() can be completely empty except for the
+of_platform_populate() call.
+
+In the Tegra example, this accounts for the /soc and /sound nodes, but
+what about the children of the SoC node?  Shouldn't they be registered
+as platform devices too?  For Linux DT support, the generic behaviour
+is for child devices to be registered by the parent's device driver at
+driver .probe() time.  So, an i2c bus device driver will register a
+i2c_client for each child node, an SPI bus driver will register
+its spi_device children, and similarly for other bus_types.
+According to that model, a driver could be written that binds to the
+SoC node and simply registers platform_devices for each of its
+children.  The board support code would allocate and register an SoC
+device, a (theoretical) SoC device driver could bind to the SoC device,
+and register platform_devices for /soc/interrupt-controller, /soc/serial,
+/soc/i2s, and /soc/i2c in its .probe() hook.  Easy, right?
+
+Actually, it turns out that registering children of some
+platform_devices as more platform_devices is a common pattern, and the
+device tree support code reflects that and makes the above example
+simpler.  The second argument to of_platform_populate() is an
+of_device_id table, and any node that matches an entry in that table
+will also get its child nodes registered.  In the tegra case, the code
+can look something like this:
+
+static void __init harmony_init_machine(void)
+{
+	/* ... */
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+"simple-bus" is defined in the ePAPR 1.0 specification as a property
+meaning a simple memory mapped bus, so the of_platform_populate() code
+could be written to just assume simple-bus compatible nodes will
+always be traversed.  However, we pass it in as an argument so that
+board support code can always override the default behaviour.
+
+[Need to add discussion of adding i2c/spi/etc child devices]
+
+Appendix A: AMBA devices
+------------------------
+
+ARM Primecells are a certain kind of device attached to the ARM AMBA
+bus which include some support for hardware detection and power
+management.  In Linux, struct amba_device and the amba_bus_type is
+used to represent Primecell devices.  However, the fiddly bit is that
+not all devices on an AMBA bus are Primecells, and for Linux it is
+typical for both amba_device and platform_device instances to be
+siblings of the same bus segment.
+
+When using the DT, this creates problems for of_platform_populate()
+because it must decide whether to register each node as either a
+platform_device or an amba_device.  This unfortunately complicates the
+device creation model a little bit, but the solution turns out not to
+be too invasive.  If a node is compatible with "arm,amba-primecell", then
+of_platform_populate() will register it as an amba_device instead of a
+platform_device.
diff --git a/Documentation/dma-buf-sharing.txt b/Documentation/dma-buf-sharing.txt
index 225f96d..3bbd5c5 100644
--- a/Documentation/dma-buf-sharing.txt
+++ b/Documentation/dma-buf-sharing.txt
@@ -32,8 +32,12 @@
 *IMPORTANT*: [see https://lkml.org/lkml/2011/12/20/211 for more details]
 For this first version, A buffer shared using the dma_buf sharing API:
 - *may* be exported to user space using "mmap" *ONLY* by exporter, outside of
-   this framework.
-- may be used *ONLY* by importers that do not need CPU access to the buffer.
+  this framework.
+- with this new iteration of the dma-buf api cpu access from the kernel has been
+  enable, see below for the details.
+
+dma-buf operations for device dma only
+--------------------------------------
 
 The dma_buf buffer sharing API usage contains the following steps:
 
@@ -219,10 +223,120 @@
    If the exporter chooses not to allow an attach() operation once a
    map_dma_buf() API has been called, it simply returns an error.
 
-Miscellaneous notes:
+Kernel cpu access to a dma-buf buffer object
+--------------------------------------------
+
+The motivation to allow cpu access from the kernel to a dma-buf object from the
+importers side are:
+- fallback operations, e.g. if the devices is connected to a usb bus and the
+  kernel needs to shuffle the data around first before sending it away.
+- full transparency for existing users on the importer side, i.e. userspace
+  should not notice the difference between a normal object from that subsystem
+  and an imported one backed by a dma-buf. This is really important for drm
+  opengl drivers that expect to still use all the existing upload/download
+  paths.
+
+Access to a dma_buf from the kernel context involves three steps:
+
+1. Prepare access, which invalidate any necessary caches and make the object
+   available for cpu access.
+2. Access the object page-by-page with the dma_buf map apis
+3. Finish access, which will flush any necessary cpu caches and free reserved
+   resources.
+
+1. Prepare access
+
+   Before an importer can access a dma_buf object with the cpu from the kernel
+   context, it needs to notify the exporter of the access that is about to
+   happen.
+
+   Interface:
+      int dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
+				   size_t start, size_t len,
+				   enum dma_data_direction direction)
+
+   This allows the exporter to ensure that the memory is actually available for
+   cpu access - the exporter might need to allocate or swap-in and pin the
+   backing storage. The exporter also needs to ensure that cpu access is
+   coherent for the given range and access direction. The range and access
+   direction can be used by the exporter to optimize the cache flushing, i.e.
+   access outside of the range or with a different direction (read instead of
+   write) might return stale or even bogus data (e.g. when the exporter needs to
+   copy the data to temporary storage).
+
+   This step might fail, e.g. in oom conditions.
+
+2. Accessing the buffer
+
+   To support dma_buf objects residing in highmem cpu access is page-based using
+   an api similar to kmap. Accessing a dma_buf is done in aligned chunks of
+   PAGE_SIZE size. Before accessing a chunk it needs to be mapped, which returns
+   a pointer in kernel virtual address space. Afterwards the chunk needs to be
+   unmapped again. There is no limit on how often a given chunk can be mapped
+   and unmapped, i.e. the importer does not need to call begin_cpu_access again
+   before mapping the same chunk again.
+
+   Interfaces:
+      void *dma_buf_kmap(struct dma_buf *, unsigned long);
+      void dma_buf_kunmap(struct dma_buf *, unsigned long, void *);
+
+   There are also atomic variants of these interfaces. Like for kmap they
+   facilitate non-blocking fast-paths. Neither the importer nor the exporter (in
+   the callback) is allowed to block when using these.
+
+   Interfaces:
+      void *dma_buf_kmap_atomic(struct dma_buf *, unsigned long);
+      void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long, void *);
+
+   For importers all the restrictions of using kmap apply, like the limited
+   supply of kmap_atomic slots. Hence an importer shall only hold onto at most 2
+   atomic dma_buf kmaps at the same time (in any given process context).
+
+   dma_buf kmap calls outside of the range specified in begin_cpu_access are
+   undefined. If the range is not PAGE_SIZE aligned, kmap needs to succeed on
+   the partial chunks at the beginning and end but may return stale or bogus
+   data outside of the range (in these partial chunks).
+
+   Note that these calls need to always succeed. The exporter needs to complete
+   any preparations that might fail in begin_cpu_access.
+
+3. Finish access
+
+   When the importer is done accessing the range specified in begin_cpu_access,
+   it needs to announce this to the exporter (to facilitate cache flushing and
+   unpinning of any pinned resources). The result of of any dma_buf kmap calls
+   after end_cpu_access is undefined.
+
+   Interface:
+      void dma_buf_end_cpu_access(struct dma_buf *dma_buf,
+				  size_t start, size_t len,
+				  enum dma_data_direction dir);
+
+
+Miscellaneous notes
+-------------------
+
 - Any exporters or users of the dma-buf buffer sharing framework must have
   a 'select DMA_SHARED_BUFFER' in their respective Kconfigs.
 
+- In order to avoid fd leaks on exec, the FD_CLOEXEC flag must be set
+  on the file descriptor.  This is not just a resource leak, but a
+  potential security hole.  It could give the newly exec'd application
+  access to buffers, via the leaked fd, to which it should otherwise
+  not be permitted access.
+
+  The problem with doing this via a separate fcntl() call, versus doing it
+  atomically when the fd is created, is that this is inherently racy in a
+  multi-threaded app[3].  The issue is made worse when it is library code
+  opening/creating the file descriptor, as the application may not even be
+  aware of the fd's.
+
+  To avoid this problem, userspace must have a way to request O_CLOEXEC
+  flag be set when the dma-buf fd is created.  So any API provided by
+  the exporting driver to create a dmabuf fd must provide a way to let
+  userspace control setting of O_CLOEXEC flag passed in to dma_buf_fd().
+
 References:
 [1] struct dma_buf_ops in include/linux/dma-buf.h
 [2] All interfaces mentioned above defined in include/linux/dma-buf.h
+[3] https://lwn.net/Articles/236486/
diff --git a/Documentation/dontdiff b/Documentation/dontdiff
index 0c083c5..b4a898f 100644
--- a/Documentation/dontdiff
+++ b/Documentation/dontdiff
@@ -158,7 +158,6 @@
 logo_*_clut224.c
 logo_*_mono.c
 lxdialog
-mach
 mach-types
 mach-types.h
 machtypes.h
diff --git a/Documentation/dvb/cards.txt b/Documentation/dvb/cards.txt
index cc09187..97709e9 100644
--- a/Documentation/dvb/cards.txt
+++ b/Documentation/dvb/cards.txt
@@ -119,4 +119,5 @@
   - Compro Videomate DVB-T300
   - Compro Videomate DVB-T200
   - AVerMedia AVerTVHD MCE A180
+  - KWorld PC150-U ATSC Hybrid
 
diff --git a/Documentation/dvb/lmedm04.txt b/Documentation/dvb/lmedm04.txt
index 10b5f04..f4b720a 100644
--- a/Documentation/dvb/lmedm04.txt
+++ b/Documentation/dvb/lmedm04.txt
@@ -66,5 +66,16 @@
 For LME2510C
 dd if=US290D.sys ibs=1 skip=33152 count=3697 of=dvb-usb-lme2510c-s0194.fw
 
+---------------------------------------------------------------------
+
+The m88rs2000 tuner driver can be found in windows/system32/drivers
+
+US2B0D.sys (dated 29 Jun 2010)
+
+dd if=US2B0D.sys ibs=1 skip=34432 count=3871 of=dvb-usb-lme2510c-rs2000.fw
+
+We need to modify id of rs2000 firmware or it will warm boot id 3344:1120.
+
+echo -ne \\xF0\\x22 | dd conv=notrunc bs=1 count=2 seek=266 of=dvb-usb-lme2510c-rs2000.fw
 
 Copy the firmware file(s) to /lib/firmware
diff --git a/Documentation/edac.txt b/Documentation/edac.txt
index 249822c..fdcc49f 100644
--- a/Documentation/edac.txt
+++ b/Documentation/edac.txt
@@ -334,8 +334,8 @@
 
 	Reading the file will return the actual scrubbing rate employed.
 
-	If configuration fails or memory scrubbing is not implemented, the value
-	of the attribute file will be -1.
+	If configuration fails or memory scrubbing is not implemented, accessing
+	that attribute will fail.
 
 
 
diff --git a/Documentation/fb/intel810.txt b/Documentation/fb/intel810.txt
index be3e783..a8e9f5b 100644
--- a/Documentation/fb/intel810.txt
+++ b/Documentation/fb/intel810.txt
@@ -211,7 +211,7 @@
 	modprobe i810fb vram=2 xres=1024 bpp=8 hsync1=30 hsync2=55 vsync1=50 \
 	         vsync2=85 accel=1 mtrr=1
 
-Or just add the following to /etc/modprobe.conf
+Or just add the following to a configuration file in /etc/modprobe.d/
 
 	options i810fb vram=2 xres=1024 bpp=16 hsync1=30 hsync2=55 vsync1=50 \
 	vsync2=85 accel=1 mtrr=1
diff --git a/Documentation/fb/intelfb.txt b/Documentation/fb/intelfb.txt
index dd9e944..feac4e4 100644
--- a/Documentation/fb/intelfb.txt
+++ b/Documentation/fb/intelfb.txt
@@ -120,7 +120,7 @@
 
 	modprobe intelfb mode=800x600-32@75 vram=8 accel=1 hwcursor=1
 
-Or just add the following to /etc/modprobe.conf
+Or just add the following to a configuration file in /etc/modprobe.d/
 
 	options intelfb mode=800x600-32@75 vram=8 accel=1 hwcursor=1
 
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 4bfd982..709e08e 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -6,14 +6,6 @@
 
 ---------------------------
 
-What:	x86 floppy disable_hlt
-When:	2012
-Why:	ancient workaround of dubious utility clutters the
-	code used by everybody else.
-Who:	Len Brown <len.brown@intel.com>
-
----------------------------
-
 What:	CONFIG_APM_CPU_IDLE, and its ability to call APM BIOS in idle
 When:	2012
 Why:	This optional sub-feature of APM is of dubious reliability,
@@ -513,20 +505,6 @@
 
 ----------------------------
 
-What:	The CAP9 SoC family will be removed
-When:	3.4
-Files:	arch/arm/mach-at91/at91cap9.c
-	arch/arm/mach-at91/at91cap9_devices.c
-	arch/arm/mach-at91/include/mach/at91cap9.h
-	arch/arm/mach-at91/include/mach/at91cap9_matrix.h
-	arch/arm/mach-at91/include/mach/at91cap9_ddrsdr.h
-	arch/arm/mach-at91/board-cap9adk.c
-Why:	The code is not actively maintained and platforms are now hard to find.
-Who:	Nicolas Ferre <nicolas.ferre@atmel.com>
-	Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-
-----------------------------
-
 What:	Low Performance USB Block driver ("CONFIG_BLK_DEV_UB")
 When:	3.6
 Why:	This driver provides support for USB storage devices like "USB
@@ -543,3 +521,13 @@
 Why:	The old kmap_atomic() with two arguments is deprecated, we only
 	keep it for backward compatibility for few cycles and then drop it.
 Who:	Cong Wang <amwang@redhat.com>
+
+----------------------------
+
+What:	get_robust_list syscall
+When:	2013
+Why:	There appear to be no production users of the get_robust_list syscall,
+	and it runs the risk of leaking address locations, allowing the bypass
+	of ASLR. It was only ever intended for debugging, so it should be
+	removed.
+Who:	Kees Cook <keescook@chromium.org>
diff --git a/Documentation/filesystems/debugfs.txt b/Documentation/filesystems/debugfs.txt
index 4e25758..7a34f82 100644
--- a/Documentation/filesystems/debugfs.txt
+++ b/Documentation/filesystems/debugfs.txt
@@ -136,7 +136,7 @@
 	void __iomem *base;
     };
 
-    struct dentry *debugfs_create_regset32(const char *name, mode_t mode,
+    struct dentry *debugfs_create_regset32(const char *name, umode_t mode,
 				     struct dentry *parent,
 				     struct debugfs_regset32 *regset);
 
diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt
index 8c10bf3..1b7f9ac 100644
--- a/Documentation/filesystems/ext4.txt
+++ b/Documentation/filesystems/ext4.txt
@@ -144,9 +144,6 @@
 			mount the device. This will enable 'journal_checksum'
 			internally.
 
-journal=update		Update the ext4 file system's journal to the current
-			format.
-
 journal_dev=devnum	When the external journal device's major/minor numbers
 			have changed, this option allows the user to specify
 			the new journal location.  The journal device is
@@ -356,11 +353,6 @@
 			interoperability  with  older kernels which only
 			store and expect 16-bit values.
 
-resize			Allows to resize filesystem to the end of the last
-			existing block group, further resize has to be done
-			with resize2fs either online, or offline. It can be
-			used only with conjunction with remount.
-
 block_validity		This options allows to enables/disables the in-kernel
 noblock_validity	facility for tracking filesystem metadata blocks
 			within internal data structures. This allows multi-
diff --git a/Documentation/filesystems/files.txt b/Documentation/filesystems/files.txt
index ac2facc..46dfc6b 100644
--- a/Documentation/filesystems/files.txt
+++ b/Documentation/filesystems/files.txt
@@ -113,8 +113,8 @@
 	if (fd >= 0) {
 		/* locate_fd() may have expanded fdtable, load the ptr */
 		fdt = files_fdtable(files);
-		FD_SET(fd, fdt->open_fds);
-		FD_CLR(fd, fdt->close_on_exec);
+		__set_open_fd(fd, fdt);
+		__clear_close_on_exec(fd, fdt);
 		spin_unlock(&files->file_lock);
 	.....
 
diff --git a/Documentation/filesystems/nfs/idmapper.txt b/Documentation/filesystems/nfs/idmapper.txt
index 120fd3c..fe03d10 100644
--- a/Documentation/filesystems/nfs/idmapper.txt
+++ b/Documentation/filesystems/nfs/idmapper.txt
@@ -4,13 +4,21 @@
 =========
 Id mapper is used by NFS to translate user and group ids into names, and to
 translate user and group names into ids.  Part of this translation involves
-performing an upcall to userspace to request the information.  Id mapper will
-user request-key to perform this upcall and cache the result.  The program
-/usr/sbin/nfs.idmap should be called by request-key, and will perform the
-translation and initialize a key with the resulting information.
+performing an upcall to userspace to request the information.  There are two
+ways NFS could obtain this information: placing a call to /sbin/request-key
+or by placing a call to the rpc.idmap daemon.
 
- NFS_USE_NEW_IDMAPPER must be selected when configuring the kernel to use this
- feature.
+NFS will attempt to call /sbin/request-key first.  If this succeeds, the
+result will be cached using the generic request-key cache.  This call should
+only fail if /etc/request-key.conf is not configured for the id_resolver key
+type, see the "Configuring" section below if you wish to use the request-key
+method.
+
+If the call to /sbin/request-key fails (if /etc/request-key.conf is not
+configured with the id_resolver key type), then the idmapper will ask the
+legacy rpc.idmap daemon for the id mapping.  This result will be stored
+in a custom NFS idmap cache.
+
 
 ===========
 Configuring
diff --git a/Documentation/filesystems/nfs/pnfs.txt b/Documentation/filesystems/nfs/pnfs.txt
index 983e14a..c7919c6 100644
--- a/Documentation/filesystems/nfs/pnfs.txt
+++ b/Documentation/filesystems/nfs/pnfs.txt
@@ -53,3 +53,57 @@
 bit which holds it in the pnfs_layout_hdr's list.  When the final lseg
 is removed from the pnfs_layout_hdr's list, the NFS_LAYOUT_DESTROYED
 bit is set, preventing any new lsegs from being added.
+
+layout drivers
+--------------
+
+PNFS utilizes what is called layout drivers. The STD defines 3 basic
+layout types: "files" "objects" and "blocks". For each of these types
+there is a layout-driver with a common function-vectors table which
+are called by the nfs-client pnfs-core to implement the different layout
+types.
+
+Files-layout-driver code is in: fs/nfs/nfs4filelayout.c && nfs4filelayoutdev.c
+Objects-layout-deriver code is in: fs/nfs/objlayout/.. directory
+Blocks-layout-deriver code is in: fs/nfs/blocklayout/.. directory
+
+objects-layout setup
+--------------------
+
+As part of the full STD implementation the objlayoutdriver.ko needs, at times,
+to automatically login to yet undiscovered iscsi/osd devices. For this the
+driver makes up-calles to a user-mode script called *osd_login*
+
+The path_name of the script to use is by default:
+	/sbin/osd_login.
+This name can be overridden by the Kernel module parameter:
+	objlayoutdriver.osd_login_prog
+
+If Kernel does not find the osd_login_prog path it will zero it out
+and will not attempt farther logins. An admin can then write new value
+to the objlayoutdriver.osd_login_prog Kernel parameter to re-enable it.
+
+The /sbin/osd_login is part of the nfs-utils package, and should usually
+be installed on distributions that support this Kernel version.
+
+The API to the login script is as follows:
+	Usage: $0 -u <URI> -o <OSDNAME> -s <SYSTEMID>
+	Options:
+		-u		target uri e.g. iscsi://<ip>:<port>
+				(allways exists)
+				(More protocols can be defined in the future.
+				 The client does not interpret this string it is
+				 passed unchanged as recieved from the Server)
+		-o		osdname of the requested target OSD
+				(Might be empty)
+				(A string which denotes the OSD name, there is a
+				 limit of 64 chars on this string)
+		-s 		systemid of the requested target OSD
+				(Might be empty)
+				(This string, if not empty is always an hex
+				 representation of the 20 bytes osd_system_id)
+
+blocks-layout setup
+-------------------
+
+TODO: Document the setup needs of the blocks layout driver
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index b4a3d76..74acd96 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -429,3 +429,9 @@
 You must also keep in mind that ->fsync() is not called with i_mutex held
 anymore, so if you require i_mutex locking you must make sure to take it and
 release it yourself.
+
+--
+[mandatory]
+	d_alloc_root() is gone, along with a lot of bugs caused by code
+misusing it.  Replacement: d_make_root(inode).  The difference is,
+d_make_root() drops the reference to inode if dentry allocation fails.  
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index a76a26a..b7413cb 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -290,7 +290,7 @@
   rsslim        current limit in bytes on the rss
   start_code    address above which program text can run
   end_code      address below which program text can run
-  start_stack   address of the start of the stack
+  start_stack   address of the start of the main process stack
   esp           current value of ESP
   eip           current value of EIP
   pending       bitmap of pending signals
@@ -325,7 +325,7 @@
 a7cb1000-a7cb2000 ---p 00000000 00:00 0
 a7cb2000-a7eb2000 rw-p 00000000 00:00 0
 a7eb2000-a7eb3000 ---p 00000000 00:00 0
-a7eb3000-a7ed5000 rw-p 00000000 00:00 0
+a7eb3000-a7ed5000 rw-p 00000000 00:00 0          [stack:1001]
 a7ed5000-a8008000 r-xp 00000000 03:00 4222       /lib/libc.so.6
 a8008000-a800a000 r--p 00133000 03:00 4222       /lib/libc.so.6
 a800a000-a800b000 rw-p 00135000 03:00 4222       /lib/libc.so.6
@@ -357,11 +357,39 @@
 
  [heap]                   = the heap of the program
  [stack]                  = the stack of the main process
+ [stack:1001]             = the stack of the thread with tid 1001
  [vdso]                   = the "virtual dynamic shared object",
                             the kernel system call handler
 
  or if empty, the mapping is anonymous.
 
+The /proc/PID/task/TID/maps is a view of the virtual memory from the viewpoint
+of the individual tasks of a process. In this file you will see a mapping marked
+as [stack] if that task sees it as a stack. This is a key difference from the
+content of /proc/PID/maps, where you will see all mappings that are being used
+as stack by all of those tasks. Hence, for the example above, the task-level
+map, i.e. /proc/PID/task/TID/maps for thread 1001 will look like this:
+
+08048000-08049000 r-xp 00000000 03:00 8312       /opt/test
+08049000-0804a000 rw-p 00001000 03:00 8312       /opt/test
+0804a000-0806b000 rw-p 00000000 00:00 0          [heap]
+a7cb1000-a7cb2000 ---p 00000000 00:00 0
+a7cb2000-a7eb2000 rw-p 00000000 00:00 0
+a7eb2000-a7eb3000 ---p 00000000 00:00 0
+a7eb3000-a7ed5000 rw-p 00000000 00:00 0          [stack]
+a7ed5000-a8008000 r-xp 00000000 03:00 4222       /lib/libc.so.6
+a8008000-a800a000 r--p 00133000 03:00 4222       /lib/libc.so.6
+a800a000-a800b000 rw-p 00135000 03:00 4222       /lib/libc.so.6
+a800b000-a800e000 rw-p 00000000 00:00 0
+a800e000-a8022000 r-xp 00000000 03:00 14462      /lib/libpthread.so.0
+a8022000-a8023000 r--p 00013000 03:00 14462      /lib/libpthread.so.0
+a8023000-a8024000 rw-p 00014000 03:00 14462      /lib/libpthread.so.0
+a8024000-a8027000 rw-p 00000000 00:00 0
+a8027000-a8043000 r-xp 00000000 03:00 8317       /lib/ld-linux.so.2
+a8043000-a8044000 r--p 0001b000 03:00 8317       /lib/ld-linux.so.2
+a8044000-a8045000 rw-p 0001c000 03:00 8317       /lib/ld-linux.so.2
+aff35000-aff4a000 rw-p 00000000 00:00 0
+ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]
 
 The /proc/PID/smaps is an extension based on maps, showing the memory
 consumption for each of the process's mappings. For each of mappings there
diff --git a/Documentation/filesystems/qnx6.txt b/Documentation/filesystems/qnx6.txt
new file mode 100644
index 0000000..050223e
--- /dev/null
+++ b/Documentation/filesystems/qnx6.txt
@@ -0,0 +1,174 @@
+The QNX6 Filesystem
+===================
+
+The qnx6fs is used by newer QNX operating system versions. (e.g. Neutrino)
+It got introduced in QNX 6.4.0 and is used default since 6.4.1.
+
+Option
+======
+
+mmi_fs		Mount filesystem as used for example by Audi MMI 3G system
+
+Specification
+=============
+
+qnx6fs shares many properties with traditional Unix filesystems. It has the
+concepts of blocks, inodes and directories.
+On QNX it is possible to create little endian and big endian qnx6 filesystems.
+This feature makes it possible to create and use a different endianness fs
+for the target (QNX is used on quite a range of embedded systems) plattform
+running on a different endianess.
+The Linux driver handles endianness transparently. (LE and BE)
+
+Blocks
+------
+
+The space in the device or file is split up into blocks. These are a fixed
+size of 512, 1024, 2048 or 4096, which is decided when the filesystem is
+created.
+Blockpointers are 32bit, so the maximum space that can be adressed is
+2^32 * 4096 bytes or 16TB
+
+The superblocks
+---------------
+
+The superblock contains all global information about the filesystem.
+Each qnx6fs got two superblocks, each one having a 64bit serial number.
+That serial number is used to identify the "active" superblock.
+In write mode with reach new snapshot (after each synchronous write), the
+serial of the new master superblock is increased (old superblock serial + 1)
+
+So basically the snapshot functionality is realized by an atomic final
+update of the serial number. Before updating that serial, all modifications
+are done by copying all modified blocks during that specific write request
+(or period) and building up a new (stable) filesystem structure under the
+inactive superblock.
+
+Each superblock holds a set of root inodes for the different filesystem
+parts. (Inode, Bitmap and Longfilenames)
+Each of these root nodes holds information like total size of the stored
+data and the adressing levels in that specific tree.
+If the level value is 0, up to 16 direct blocks can be adressed by each
+node.
+Level 1 adds an additional indirect adressing level where each indirect
+adressing block holds up to blocksize / 4 bytes pointers to data blocks.
+Level 2 adds an additional indirect adressig block level (so, already up
+to 16 * 256 * 256 = 1048576 blocks that can be adressed by such a tree)a
+
+Unused block pointers are always set to ~0 - regardless of root node,
+indirect adressing blocks or inodes.
+Data leaves are always on the lowest level. So no data is stored on upper
+tree levels.
+
+The first Superblock is located at 0x2000. (0x2000 is the bootblock size)
+The Audi MMI 3G first superblock directly starts at byte 0.
+Second superblock position can either be calculated from the superblock
+information (total number of filesystem blocks) or by taking the highest
+device address, zeroing the last 3 bytes and then substracting 0x1000 from
+that address.
+
+0x1000 is the size reserved for each superblock - regardless of the
+blocksize of the filesystem.
+
+Inodes
+------
+
+Each object in the filesystem is represented by an inode. (index node)
+The inode structure contains pointers to the filesystem blocks which contain
+the data held in the object and all of the metadata about an object except
+its longname. (filenames longer than 27 characters)
+The metadata about an object includes the permissions, owner, group, flags,
+size, number of blocks used, access time, change time and modification time.
+
+Object mode field is POSIX format. (which makes things easier)
+
+There are also pointers to the first 16 blocks, if the object data can be
+adressed with 16 direct blocks.
+For more than 16 blocks an indirect adressing in form of another tree is
+used. (scheme is the same as the one used for the superblock root nodes)
+
+The filesize is stored 64bit. Inode counting starts with 1. (whilst long
+filename inodes start with 0)
+
+Directories
+-----------
+
+A directory is a filesystem object and has an inode just like a file.
+It is a specially formatted file containing records which associate each
+name with an inode number.
+'.' inode number points to the directory inode
+'..' inode number points to the parent directory inode
+Eeach filename record additionally got a filename length field.
+
+One special case are long filenames or subdirectory names.
+These got set a filename length field of 0xff in the corresponding directory
+record plus the longfile inode number also stored in that record.
+With that longfilename inode number, the longfilename tree can be walked
+starting with the superblock longfilename root node pointers.
+
+Special files
+-------------
+
+Symbolic links are also filesystem objects with inodes. They got a specific
+bit in the inode mode field identifying them as symbolic link.
+The directory entry file inode pointer points to the target file inode.
+
+Hard links got an inode, a directory entry, but a specific mode bit set,
+no block pointers and the directory file record pointing to the target file
+inode.
+
+Character and block special devices do not exist in QNX as those files
+are handled by the QNX kernel/drivers and created in /dev independant of the
+underlaying filesystem.
+
+Long filenames
+--------------
+
+Long filenames are stored in a seperate adressing tree. The staring point
+is the longfilename root node in the active superblock.
+Each data block (tree leaves) holds one long filename. That filename is
+limited to 510 bytes. The first two starting bytes are used as length field
+for the actual filename.
+If that structure shall fit for all allowed blocksizes, it is clear why there
+is a limit of 510 bytes for the actual filename stored.
+
+Bitmap
+------
+
+The qnx6fs filesystem allocation bitmap is stored in a tree under bitmap
+root node in the superblock and each bit in the bitmap represents one
+filesystem block.
+The first block is block 0, which starts 0x1000 after superblock start.
+So for a normal qnx6fs 0x3000 (bootblock + superblock) is the physical
+address at which block 0 is located.
+
+Bits at the end of the last bitmap block are set to 1, if the device is
+smaller than addressing space in the bitmap.
+
+Bitmap system area
+------------------
+
+The bitmap itself is devided into three parts.
+First the system area, that is split into two halfs.
+Then userspace.
+
+The requirement for a static, fixed preallocated system area comes from how
+qnx6fs deals with writes.
+Each superblock got it's own half of the system area. So superblock #1
+always uses blocks from the lower half whilst superblock #2 just writes to
+blocks represented by the upper half bitmap system area bits.
+
+Bitmap blocks, Inode blocks and indirect addressing blocks for those two
+tree structures are treated as system blocks.
+
+The rational behind that is that a write request can work on a new snapshot
+(system area of the inactive - resp. lower serial numbered superblock) while
+at the same time there is still a complete stable filesystem structer in the
+other half of the system area.
+
+When finished with writing (a sync write is completed, the maximum sync leap
+time or a filesystem sync is requested), serial of the previously inactive
+superblock atomically is increased and the fs switches over to that - then
+stable declared - superblock.
+
+For all data outside the system area, blocks are just copied while writing.
diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt
index 792faa3..620a078 100644
--- a/Documentation/gpio.txt
+++ b/Documentation/gpio.txt
@@ -271,9 +271,26 @@
 power management, such as by powering down unused chip sectors and, more
 easily, gating off unused clocks.
 
-Note that requesting a GPIO does NOT cause it to be configured in any
-way; it just marks that GPIO as in use.  Separate code must handle any
-pin setup (e.g. controlling which pin the GPIO uses, pullup/pulldown).
+For GPIOs that use pins known to the pinctrl subsystem, that subsystem should
+be informed of their use; a gpiolib driver's .request() operation may call
+pinctrl_request_gpio(), and a gpiolib driver's .free() operation may call
+pinctrl_free_gpio(). The pinctrl subsystem allows a pinctrl_request_gpio()
+to succeed concurrently with a pin or pingroup being "owned" by a device for
+pin multiplexing.
+
+Any programming of pin multiplexing hardware that is needed to route the
+GPIO signal to the appropriate pin should occur within a GPIO driver's
+.direction_input() or .direction_output() operations, and occur after any
+setup of an output GPIO's value. This allows a glitch-free migration from a
+pin's special function to GPIO. This is sometimes required when using a GPIO
+to implement a workaround on signals typically driven by a non-GPIO HW block.
+
+Some platforms allow some or all GPIO signals to be routed to different pins.
+Similarly, other aspects of the GPIO or pin may need to be configured, such as
+pullup/pulldown. Platform software should arrange that any such details are
+configured prior to gpio_request() being called for those GPIOs, e.g. using
+the pinctrl subsystem's mapping table, so that GPIO users need not be aware
+of these details.
 
 Also note that it's your responsibility to have stopped using a GPIO
 before you free it.
@@ -302,6 +319,8 @@
 
 	* GPIOF_INIT_LOW	- as output, set initial level to LOW
 	* GPIOF_INIT_HIGH	- as output, set initial level to HIGH
+	* GPIOF_OPEN_DRAIN	- gpio pin is open drain type.
+	* GPIOF_OPEN_SOURCE	- gpio pin is open source type.
 
 since GPIOF_INIT_* are only valid when configured as output, so group valid
 combinations as:
@@ -310,8 +329,19 @@
 	* GPIOF_OUT_INIT_LOW	- configured as output, initial level LOW
 	* GPIOF_OUT_INIT_HIGH	- configured as output, initial level HIGH
 
-In the future, these flags can be extended to support more properties such
-as open-drain status.
+When setting the flag as GPIOF_OPEN_DRAIN then it will assume that pins is
+open drain type. Such pins will not be driven to 1 in output mode. It is
+require to connect pull-up on such pins. By enabling this flag, gpio lib will
+make the direction to input when it is asked to set value of 1 in output mode
+to make the pin HIGH. The pin is make to LOW by driving value 0 in output mode.
+
+When setting the flag as GPIOF_OPEN_SOURCE then it will assume that pins is
+open source type. Such pins will not be driven to 0 in output mode. It is
+require to connect pull-down on such pin. By enabling this flag, gpio lib will
+make the direction to input when it is asked to set value of 0 in output mode
+to make the pin LOW. The pin is make to HIGH by driving value 1 in output mode.
+
+In the future, these flags can be extended to support more properties.
 
 Further more, to ease the claim/release of multiple GPIOs, 'struct gpio' is
 introduced to encapsulate all three fields as:
diff --git a/Documentation/hwmon/k10temp b/Documentation/hwmon/k10temp
index a10f736..90956b6 100644
--- a/Documentation/hwmon/k10temp
+++ b/Documentation/hwmon/k10temp
@@ -11,7 +11,7 @@
   Socket S1G2: Athlon (X2), Sempron (X2), Turion X2 (Ultra)
 * 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"
+* AMD Family 15h processors: "Bulldozer" (FX-Series), "Trinity"
 
   Prefix: 'k10temp'
   Addresses scanned: PCI space
diff --git a/Documentation/hwmon/lm90 b/Documentation/hwmon/lm90
index 9cd14cfe..b466974 100644
--- a/Documentation/hwmon/lm90
+++ b/Documentation/hwmon/lm90
@@ -118,6 +118,10 @@
     Addresses scanned: I2C 0x48 through 0x4F
     Datasheet: Publicly available at NXP website
                http://ics.nxp.com/products/interface/datasheet/sa56004x.pdf
+  * GMT G781
+    Prefix: 'g781'
+    Addresses scanned: I2C 0x4c, 0x4d
+    Datasheet: Not publicly available from GMT
 
 Author: Jean Delvare <khali@linux-fr.org>
 
diff --git a/Documentation/hwmon/mc13783-adc b/Documentation/hwmon/mc13783-adc
index 044531a..d0e7b3f 100644
--- a/Documentation/hwmon/mc13783-adc
+++ b/Documentation/hwmon/mc13783-adc
@@ -3,8 +3,11 @@
 
 Supported chips:
   * Freescale Atlas MC13783
-    Prefix: 'mc13783_adc'
+    Prefix: 'mc13783'
     Datasheet: http://www.freescale.com/files/rf_if/doc/data_sheet/MC13783.pdf?fsrch=1
+  * Freescale Atlas MC13892
+    Prefix: 'mc13892'
+    Datasheet: http://cache.freescale.com/files/analog/doc/data_sheet/MC13892.pdf?fsrch=1&sr=1
 
 Authors:
     Sascha Hauer <s.hauer@pengutronix.de>
@@ -13,20 +16,21 @@
 Description
 -----------
 
-The Freescale MC13783 is a Power Management and Audio Circuit. Among
-other things it contains a 10-bit A/D converter. The converter has 16
-channels which can be used in different modes.
-The A/D converter has a resolution of 2.25mV. Channels 0-4 have
-a dedicated meaning with chip internal scaling applied. Channels 5-7
-can be used as general purpose inputs or alternatively in a dedicated
-mode. Channels 12-15 are occupied by the touchscreen if it's active.
+The Freescale MC13783 and MC13892 are Power Management and Audio Circuits.
+Among other things they contain a 10-bit A/D converter. The converter has 16
+(MC13783) resp. 12 (MC13892) channels which can be used in different modes. The
+A/D converter has a resolution of 2.25mV.
 
-Currently the driver only supports channels 2 and 5-15 with no alternative
-modes for channels 5-7.
+Some channels can be used as General Purpose inputs or in a dedicated mode with
+a chip internal scaling applied .
 
-See this table for the meaning of the different channels and their chip
-internal scaling:
+Currently the driver only supports the Application Supply channel (BP / BPSNS),
+the General Purpose inputs and touchscreen.
 
+See the following tables for the meaning of the different channels and their
+chip internal scaling:
+
+MC13783:
 Channel	Signal						Input Range	Scaling
 -------------------------------------------------------------------------------
 0	Battery Voltage (BATT)				2.50 - 4.65V	-2.40V
@@ -34,7 +38,7 @@
 2	Application Supply (BP)				2.50 - 4.65V	-2.40V
 3	Charger Voltage (CHRGRAW)			0 - 10V /	/5
 							0 - 20V		/10
-4	Charger Current (CHRGISNSP-CHRGISNSN)		-0.25V - 0.25V	x4
+4	Charger Current (CHRGISNSP-CHRGISNSN)		-0.25 - 0.25V	x4
 5	General Purpose ADIN5 / Battery Pack Thermistor	0 - 2.30V	No
 6	General Purpose ADIN6 / Backup Voltage (LICELL)	0 - 2.30V /	No /
 							1.50 - 3.50V	-1.20V
@@ -48,3 +52,23 @@
 13	General Purpose TSX2 / Touchscreen X-plate 2	0 - 2.30V	No
 14	General Purpose TSY1 / Touchscreen Y-plate 1	0 - 2.30V	No
 15	General Purpose TSY2 / Touchscreen Y-plate 2	0 - 2.30V	No
+
+MC13892:
+Channel	Signal						Input Range	Scaling
+-------------------------------------------------------------------------------
+0	Battery Voltage (BATT)				0 - 4.8V	/2
+1	Battery Current (BATT - BATTISNSCC)		-60 - 60 mV	x20
+2	Application Supply (BPSNS)			0 - 4.8V	/2
+3	Charger Voltage (CHRGRAW)			0 - 12V /	/5
+							0 - 20V		/10
+4	Charger Current (CHRGISNS-BPSNS) /		-0.3 - 0.3V /	x4 /
+	Touchscreen X-plate 1				0 - 2.4V	No
+5	General Purpose ADIN5 /	Battery Pack Thermistor	0 - 2.4V	No
+6	General Purpose ADIN6 / Backup Voltage (LICELL)	0 - 2.4V /	No
+	Backup Voltage (LICELL)                        	0 - 3.6V	x2/3
+7	General Purpose ADIN7 / UID / Die Temperature	0 - 2.4V /	No /
+							0 - 4.8V	/2
+12	General Purpose TSX1 / Touchscreen X-plate 1	0 - 2.4V	No
+13	General Purpose TSX2 / Touchscreen X-plate 2	0 - 2.4V	No
+14	General Purpose TSY1 / Touchscreen Y-plate 1	0 - 2.4V	No
+15	General Purpose TSY2 / Touchscreen Y-plate 2	0 - 2.4V	No
diff --git a/Documentation/hwmon/mcp3021 b/Documentation/hwmon/mcp3021
new file mode 100644
index 0000000..325fd87
--- /dev/null
+++ b/Documentation/hwmon/mcp3021
@@ -0,0 +1,22 @@
+Kernel driver MCP3021
+======================
+
+Supported chips:
+  * Microchip Technology MCP3021
+    Prefix: 'mcp3021'
+    Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21805a.pdf
+
+Author: Mingkai Hu
+
+Description
+-----------
+
+This driver implements support for the Microchip Technology MCP3021 chip.
+
+The Microchip Technology Inc. MCP3021 is a successive approximation A/D
+converter (ADC) with 10-bit resolution.
+This device provides one single-ended input with very low power consumption.
+Communication to the MCP3021 is performed using a 2-wire I2C compatible
+interface. Standard (100 kHz) and Fast (400 kHz) I2C modes are available.
+The default I2C device address is 0x4d (contact the Microchip factory for
+additional address options).
diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801
index 2871fd5..71f55bb 100644
--- a/Documentation/i2c/busses/i2c-i801
+++ b/Documentation/i2c/busses/i2c-i801
@@ -20,6 +20,7 @@
   * Intel Patsburg (PCH)
   * Intel DH89xxCC (PCH)
   * Intel Panther Point (PCH)
+  * Intel Lynx Point (PCH)
    Datasheets: Publicly available at the Intel website
 
 On Intel Patsburg and later chipsets, both the normal host SMBus controller
diff --git a/Documentation/i2c/busses/scx200_acb b/Documentation/i2c/busses/scx200_acb
index 7c07883d..ce83c87 100644
--- a/Documentation/i2c/busses/scx200_acb
+++ b/Documentation/i2c/busses/scx200_acb
@@ -28,5 +28,5 @@
 parameter to your boot command line:
   scx200_acb.base=0x810,0x820
 If the scx200_acb driver is built as a module, add the following line to
-the file /etc/modprobe.conf instead:
+a configuration file in /etc/modprobe.d/ instead:
   options scx200_acb base=0x810,0x820
diff --git a/Documentation/ide/ide.txt b/Documentation/ide/ide.txt
index e77bebf..7aca987 100644
--- a/Documentation/ide/ide.txt
+++ b/Documentation/ide/ide.txt
@@ -169,7 +169,7 @@
 
 	alias block-major-3 ide-probe
 
-to /etc/modprobe.conf.
+to a configuration file in /etc/modprobe.d/.
 
 When ide.c is used as a module, you can pass command line parameters to the
 driver using the "options=" keyword to insmod, while replacing any ',' with
diff --git a/Documentation/input/input.txt b/Documentation/input/input.txt
index b3d6787..666c06c 100644
--- a/Documentation/input/input.txt
+++ b/Documentation/input/input.txt
@@ -250,8 +250,8 @@
 a USB keyboard works and is correctly connected to the kernel keyboard
 driver. 
 
-  Doing a cat /dev/input/mouse0 (c, 13, 32) will verify that a mouse
-is also emulated, characters should appear if you move it.
+  Doing a "cat /dev/input/mouse0" (c, 13, 32) will verify that a mouse
+is also emulated; characters should appear if you move it.
 
   You can test the joystick emulation with the 'jstest' utility,
 available in the joystick package (see Documentation/input/joystick.txt).
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 68fbfb6..e34b531d 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -218,12 +218,14 @@
 'h'	00-7F				conflict! Charon filesystem
 					<mailto:zapman@interlan.net>
 'h'	00-1F	linux/hpet.h		conflict!
+'h'	80-8F	fs/hfsplus/ioctl.c
 'i'	00-3F	linux/i2o-dev.h		conflict!
 'i'	0B-1F	linux/ipmi.h		conflict!
 'i'	80-8F	linux/i8k.h
 'j'	00-3F	linux/joystick.h
 'k'	00-0F	linux/spi/spidev.h	conflict!
 'k'	00-05	video/kyro.h		conflict!
+'k'	10-17	linux/hsi/hsi_char.h	HSI character device
 'l'	00-3F	linux/tcfs_fs.h		transparent cryptographic file system
 					<http://web.archive.org/web/*/http://mikonos.dia.unisa.it/tcfs>
 'l'	40-7F	linux/udf_fs_i.h	in development:
diff --git a/Documentation/isdn/README.gigaset b/Documentation/isdn/README.gigaset
index ef3343e..7534c60 100644
--- a/Documentation/isdn/README.gigaset
+++ b/Documentation/isdn/README.gigaset
@@ -97,8 +97,7 @@
 				   2.5.): 1=on (default), 0=off
 
      Depending on your distribution you may want to create a separate module
-     configuration file /etc/modprobe.d/gigaset for these, or add them to a
-     custom file like /etc/modprobe.conf.local.
+     configuration file like /etc/modprobe.d/gigaset.conf for these.
 
 2.2. Device nodes for user space programs
      ------------------------------------
@@ -212,8 +211,8 @@
 
         options ppp_async flag_time=0
 
-     to an appropriate module configuration file, like /etc/modprobe.d/gigaset
-     or /etc/modprobe.conf.local.
+     to an appropriate module configuration file, like
+     /etc/modprobe.d/gigaset.conf.
 
      Unimodem mode is needed for making some devices [e.g. SX100] work which
      do not support the regular Gigaset command set. If debug output (see
@@ -237,8 +236,8 @@
 	modprobe usb_gigaset startmode=0
      or by adding a line like
 	options usb_gigaset startmode=0
-     to an appropriate module configuration file, like /etc/modprobe.d/gigaset
-     or /etc/modprobe.conf.local.
+     to an appropriate module configuration file, like
+     /etc/modprobe.d/gigaset.conf
 
 2.6. Call-ID (CID) mode
      ------------------
@@ -310,7 +309,7 @@
 
            options isdn dialtimeout=15
 
-        to /etc/modprobe.d/gigaset, /etc/modprobe.conf.local or a similar file.
+        to /etc/modprobe.d/gigaset.conf or a similar file.
 
      Problem:
         The isdnlog program emits error messages or just doesn't work.
@@ -350,8 +349,7 @@
      The initial value can be set using the debug parameter when loading the
      module "gigaset", e.g. by adding a line
         options gigaset debug=0
-     to your module configuration file, eg. /etc/modprobe.d/gigaset or
-     /etc/modprobe.conf.local.
+     to your module configuration file, eg. /etc/modprobe.d/gigaset.conf
 
      Generated debugging information can be found
      - as output of the command
diff --git a/Documentation/kbuild/kconfig.txt b/Documentation/kbuild/kconfig.txt
index c313d71..9d5f2a9 100644
--- a/Documentation/kbuild/kconfig.txt
+++ b/Documentation/kbuild/kconfig.txt
@@ -28,12 +28,10 @@
 
 	grep "(NEW)" conf.new
 
-to see the new config symbols or you can 'diff' the previous and
-new .config files to see the differences:
+to see the new config symbols or you can use diffconfig to see the
+differences between the previous and new .config files:
 
-	diff .config.old .config | less
-
-(Yes, we need something better here.)
+	scripts/diffconfig .config.old .config | less
 
 ______________________________________________________________________
 Environment variables for '*config'
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 8cadb75..c1601e5 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -713,6 +713,21 @@
 			The filter can be disabled or changed to another
 			driver later using sysfs.
 
+	drm_kms_helper.edid_firmware=[<connector>:]<file>
+			Broken monitors, graphic adapters and KVMs may
+			send no or incorrect EDID data sets. This parameter
+			allows to specify an EDID data set in the
+			/lib/firmware directory that is used instead.
+			Generic built-in EDID data sets are used, if one of
+			edid/1024x768.bin, edid/1280x1024.bin,
+			edid/1680x1050.bin, or edid/1920x1080.bin is given
+			and no file with the same name exists. Details and
+			instructions how to build your own EDID data are
+			available in Documentation/EDID/HOWTO.txt. An EDID
+			data set will only be used for a particular connector,
+			if its name and a colon are prepended to the EDID
+			name.
+
 	dscc4.setup=	[NET]
 
 	earlycon=	[KNL] Output early console device and options.
@@ -1071,8 +1086,6 @@
 			no_x2apic_optout
 				BIOS x2APIC opt-out request will be ignored
 
-	inttest=	[IA-64]
-
 	iomem=		Disable strict checking of access to MMIO memory
 		strict	regions from userspace.
 		relaxed
@@ -1657,6 +1670,14 @@
 			of returning the full 64-bit number.
 			The default is to return 64-bit inode numbers.
 
+	nfs.max_session_slots=
+			[NFSv4.1] Sets the maximum number of session slots
+			the client will attempt to negotiate with the server.
+			This limits the number of simultaneous RPC requests
+			that the client can send to the NFSv4.1 server.
+			Note that there is little point in setting this
+			value higher than the max_tcp_slot_table_limit.
+
 	nfs.nfs4_disable_idmapping=
 			[NFSv4] When set to the default of '1', this option
 			ensures that both the RPC level authentication
@@ -1670,6 +1691,27 @@
 			back to using the idmapper.
 			To turn off this behaviour, set the value to '0'.
 
+	nfs.send_implementation_id =
+			[NFSv4.1] Send client implementation identification
+			information in exchange_id requests.
+			If zero, no implementation identification information
+			will be sent.
+			The default is to send the implementation identification
+			information.
+
+	nfsd.nfs4_disable_idmapping=
+			[NFSv4] When set to the default of '1', the NFSv4
+			server will return only numeric uids and gids to
+			clients using auth_sys, and will accept numeric uids
+			and gids from such clients.  This is intended to ease
+			migration from NFSv2/v3.
+
+	objlayoutdriver.osd_login_prog=
+			[NFS] [OBJLAYOUT] sets the pathname to the program which
+			is used to automatically discover and login into new
+			osd-targets. Please see:
+			Documentation/filesystems/pnfs.txt for more explanations
+
 	nmi_debug=	[KNL,AVR32,SH] Specify one or more actions to take
 			when a NMI is triggered.
 			Format: [state][,regs][,debounce][,die]
@@ -1833,6 +1875,8 @@
 			shutdown the other cpus.  Instead use the REBOOT_VECTOR
 			irq.
 
+	nomodule	Disable module load
+
 	nopat		[X86] Disable PAT (page attribute table extension of
 			pagetables) support.
 
@@ -2109,8 +2153,14 @@
 				the default.
 				off: Turn ECRC off
 				on: Turn ECRC on.
-		realloc		reallocate PCI resources if allocations done by BIOS
-				are erroneous.
+		realloc=	Enable/disable reallocating PCI bridge resources
+				if allocations done by BIOS are too small to
+				accommodate resources required by all child
+				devices.
+				off: Turn realloc off
+				on: Turn realloc on
+		realloc		same as realloc=on
+		noari		do not use PCIe ARI.
 
 	pcie_aspm=	[PCIE] Forcibly enable or disable PCIe Active State Power
 			Management.
@@ -2118,6 +2168,10 @@
 		force	Enable ASPM even on devices that claim not to support it.
 			WARNING: Forcing ASPM on may cause system lockups.
 
+	pcie_hp=	[PCIE] PCI Express Hotplug driver options:
+		nomsi	Do not use MSI for PCI Express Native Hotplug (this
+			makes all PCIe ports use INTx for hotplug services).
+
 	pcie_ports=	[PCIE] PCIe ports handling:
 		auto	Ask the BIOS whether or not to use native PCIe services
 			associated with PCIe ports (PME, hot-plug, AER).  Use
@@ -2635,6 +2689,13 @@
 			to facilitate early boot debugging.
 			See also Documentation/trace/events.txt
 
+	transparent_hugepage=
+			[KNL]
+			Format: [always|madvise|never]
+			Can be used to control the default behavior of the system
+			with respect to transparent hugepages.
+			See Documentation/vm/transhuge.txt for more details.
+
 	tsc=		Disable clocksource stability checks for TSC.
 			Format: <string>
 			[x86] reliable: mark tsc clocksource as reliable, this
diff --git a/Documentation/laptops/asus-laptop.txt b/Documentation/laptops/asus-laptop.txt
index 803e51f..a1e04d6 100644
--- a/Documentation/laptops/asus-laptop.txt
+++ b/Documentation/laptops/asus-laptop.txt
@@ -45,7 +45,7 @@
 Usage
 -----
 
-  Try "modprobe asus_acpi". Check your dmesg (simply type dmesg). You should
+  Try "modprobe asus-laptop". Check your dmesg (simply type dmesg). You should
   see some lines like this :
 
       Asus Laptop Extras version 0.42
diff --git a/Documentation/laptops/sony-laptop.txt b/Documentation/laptops/sony-laptop.txt
index 2bd4e82..0d5ac7f 100644
--- a/Documentation/laptops/sony-laptop.txt
+++ b/Documentation/laptops/sony-laptop.txt
@@ -17,6 +17,11 @@
 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
+module.  For example the "FN/E" key combination (EJECTCD on some models)
+generates the scancode 20 (0x14).
+
 Backlight control:
 ------------------
 If your laptop model supports it, you will find sysfs files in the
diff --git a/Documentation/laptops/sonypi.txt b/Documentation/laptops/sonypi.txt
index 4857acf..606bdb9 100644
--- a/Documentation/laptops/sonypi.txt
+++ b/Documentation/laptops/sonypi.txt
@@ -110,7 +110,7 @@
 -----------
 
 In order to automatically load the sonypi module on use, you can put those
-lines in your /etc/modprobe.conf file:
+lines a configuration file in /etc/modprobe.d/:
 
 	alias char-major-10-250 sonypi
 	options sonypi minor=250
diff --git a/Documentation/leds/leds-lp5521.txt b/Documentation/leds/leds-lp5521.txt
index c4d8d15..0e542ab 100644
--- a/Documentation/leds/leds-lp5521.txt
+++ b/Documentation/leds/leds-lp5521.txt
@@ -43,17 +43,23 @@
 example platform data:
 
 Note: chan_nr can have values between 0 and 2.
+The name of each channel can be configurable.
+If the name field is not defined, the default name will be set to 'xxxx:channelN'
+(XXXX : pdata->label or i2c client name, N : channel number)
 
 static struct lp5521_led_config lp5521_led_config[] = {
         {
+		.name = "red",
                 .chan_nr        = 0,
                 .led_current    = 50,
 		.max_current    = 130,
         }, {
+		.name = "green",
                 .chan_nr        = 1,
                 .led_current    = 0,
 		.max_current    = 130,
         }, {
+		.name = "blue",
                 .chan_nr        = 2,
                 .led_current    = 0,
 		.max_current    = 130,
@@ -86,3 +92,60 @@
 
 If the current is set to 0 in the platform data, that channel is
 disabled and it is not visible in the sysfs.
+
+The 'update_config' : CONFIG register (ADDR 08h)
+This value is platform-specific data.
+If update_config is not defined, the CONFIG register is set with
+'LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT'.
+(Enable auto-powersave, set charge pump to auto, red to battery)
+
+example of update_config :
+
+#define LP5521_CONFIGS	(LP5521_PWM_HF | LP5521_PWRSAVE_EN | \
+			LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT | \
+			LP5521_CLK_INT)
+
+static struct lp5521_platform_data lp5521_pdata = {
+	.led_config = lp5521_led_config,
+	.num_channels = ARRAY_SIZE(lp5521_led_config),
+	.clock_mode = LP5521_CLOCK_INT,
+	.update_config = LP5521_CONFIGS,
+};
+
+LED patterns : LP5521 has autonomous operation without external control.
+Pattern data can be defined in the platform data.
+
+example of led pattern data :
+
+/* RGB(50,5,0) 500ms on, 500ms off, infinite loop */
+static u8 pattern_red[] = {
+		0x40, 0x32, 0x60, 0x00,	0x40, 0x00, 0x60, 0x00,
+		};
+
+static u8 pattern_green[] = {
+		0x40, 0x05, 0x60, 0x00, 0x40, 0x00, 0x60, 0x00,
+		};
+
+static struct lp5521_led_pattern board_led_patterns[] = {
+	{
+		.r = pattern_red,
+		.g = pattern_green,
+		.size_r = ARRAY_SIZE(pattern_red),
+		.size_g = ARRAY_SIZE(pattern_green),
+	},
+};
+
+static struct lp5521_platform_data lp5521_platform_data = {
+        .led_config     = lp5521_led_config,
+        .num_channels   = ARRAY_SIZE(lp5521_led_config),
+        .clock_mode     = LP5521_CLOCK_EXT,
+	.patterns = board_led_patterns,
+	.num_patterns = ARRAY_SIZE(board_led_patterns),
+};
+
+Then predefined led pattern(s) can be executed via the sysfs.
+To start the pattern #1,
+# echo 1 > /sys/bus/i2c/devices/xxxx/led_pattern
+(xxxx : i2c bus & slave address)
+To end the pattern,
+# echo 0 > /sys/bus/i2c/devices/xxxx/led_pattern
diff --git a/Documentation/mono.txt b/Documentation/mono.txt
index e8e1758..d01ac60 100644
--- a/Documentation/mono.txt
+++ b/Documentation/mono.txt
@@ -38,11 +38,11 @@
         /sbin/modprobe binfmt_misc
 	# Some distributions, like Fedora Core, perform
 	# the following command automatically when the
-	# binfmt_misc module is loaded into the kernel.
+	# binfmt_misc module is loaded into the kernel
+	# or during normal boot up (systemd-based systems).
 	# Thus, it is possible that the following line
-	# is not needed at all. Look at /etc/modprobe.conf
-	# to check whether this is applicable or not.
-        mount -t binfmt_misc none /proc/sys/fs/binfmt_misc
+	# is not needed at all.
+	mount -t binfmt_misc none /proc/sys/fs/binfmt_misc
 fi
 
 # Register support for .NET CLR binaries
diff --git a/Documentation/networking/baycom.txt b/Documentation/networking/baycom.txt
index 4e68849..688f18f 100644
--- a/Documentation/networking/baycom.txt
+++ b/Documentation/networking/baycom.txt
@@ -93,7 +93,7 @@
 modems it should access at which ports. This can be done with the setbaycom
 utility. If you are only using one modem, you can also configure the
 driver from the insmod command line (or by means of an option line in
-/etc/modprobe.conf).
+/etc/modprobe.d/*.conf).
 
 Examples:
   modprobe baycom_ser_fdx mode="ser12*" iobase=0x3f8 irq=4
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index 080ad26..bfea8a3 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -173,9 +173,8 @@
 
 	Module options may be given as command line arguments to the
 insmod or modprobe command, but are usually specified in either the
-/etc/modules.conf or /etc/modprobe.conf configuration file, or in a
-distro-specific configuration file (some of which are detailed in the next
-section).
+/etc/modrobe.d/*.conf configuration files, or in a distro-specific
+configuration file (some of which are detailed in the next section).
 
 	Details on bonding support for sysfs is provided in the
 "Configuring Bonding Manually via Sysfs" section, below.
@@ -1021,7 +1020,7 @@
 
 	Because the sysconfig scripts supply the bonding module
 options in the ifcfg-bondX file, it is not necessary to add them to
-the system /etc/modules.conf or /etc/modprobe.conf configuration file.
+the system /etc/modules.d/*.conf configuration files.
 
 3.2 Configuration with Initscripts Support
 ------------------------------------------
@@ -1098,15 +1097,13 @@
 	arp_ip_target=+192.168.1.1 arp_ip_target=+192.168.1.2
 
 	is the proper syntax to specify multiple targets.  When specifying
-options via BONDING_OPTS, it is not necessary to edit /etc/modules.conf or
-/etc/modprobe.conf.
+options via BONDING_OPTS, it is not necessary to edit /etc/modprobe.d/*.conf.
 
 	For even older versions of initscripts that do not support
-BONDING_OPTS, it is necessary to edit /etc/modules.conf (or
-/etc/modprobe.conf, depending upon your distro) to load the bonding module
-with your desired options when the bond0 interface is brought up.  The
-following lines in /etc/modules.conf (or modprobe.conf) will load the
-bonding module, and select its options:
+BONDING_OPTS, it is necessary to edit /etc/modprobe.d/*.conf, depending upon
+your distro) to load the bonding module with your desired options when the
+bond0 interface is brought up.  The following lines in /etc/modprobe.d/*.conf
+will load the bonding module, and select its options:
 
 alias bond0 bonding
 options bond0 mode=balance-alb miimon=100
@@ -1152,7 +1149,7 @@
 version 8.
 
 	The general method for these systems is to place the bonding
-module parameters into /etc/modules.conf or /etc/modprobe.conf (as
+module parameters into a config file in /etc/modprobe.d/ (as
 appropriate for the installed distro), then add modprobe and/or
 ifenslave commands to the system's global init script.  The name of
 the global init script differs; for sysconfig, it is
@@ -1228,7 +1225,7 @@
 specify a different name for each instance (the module loading system
 requires that every loaded module, even multiple instances of the same
 module, have a unique name).  This is accomplished by supplying multiple
-sets of bonding options in /etc/modprobe.conf, for example:
+sets of bonding options in /etc/modprobe.d/*.conf, for example:
 
 alias bond0 bonding
 options bond0 -o bond0 mode=balance-rr miimon=100
@@ -1793,8 +1790,8 @@
 	On systems with network configuration scripts that do not
 associate physical devices directly with network interface names (so
 that the same physical device always has the same "ethX" name), it may
-be necessary to add some special logic to either /etc/modules.conf or
-/etc/modprobe.conf (depending upon which is installed on the system).
+be necessary to add some special logic to config files in
+/etc/modprobe.d/.
 
 	For example, given a modules.conf containing the following:
 
@@ -1821,20 +1818,15 @@
 bonding is loaded.  This command is fully documented in the
 modules.conf manual page.
 
-	On systems utilizing modprobe.conf (or modprobe.conf.local),
-an equivalent problem can occur.  In this case, the following can be
-added to modprobe.conf (or modprobe.conf.local, as appropriate), as
-follows (all on one line; it has been split here for clarity):
+	On systems utilizing modprobe an equivalent problem can occur.
+In this case, the following can be added to config files in
+/etc/modprobe.d/ as:
 
-install bonding /sbin/modprobe tg3; /sbin/modprobe e1000;
-	/sbin/modprobe --ignore-install bonding
+softdep bonding pre: tg3 e1000
 
-	This will, when loading the bonding module, rather than
-performing the normal action, instead execute the provided command.
-This command loads the device drivers in the order needed, then calls
-modprobe with --ignore-install to cause the normal action to then take
-place.  Full documentation on this can be found in the modprobe.conf
-and modprobe manual pages.
+	This will load tg3 and e1000 modules before loading the bonding one.
+Full documentation on this can be found in the modprobe.d and modprobe
+manual pages.
 
 8.3. Painfully Slow Or No Failed Link Detection By Miimon
 ---------------------------------------------------------
diff --git a/Documentation/networking/dl2k.txt b/Documentation/networking/dl2k.txt
index 10e8490..cba74f7 100644
--- a/Documentation/networking/dl2k.txt
+++ b/Documentation/networking/dl2k.txt
@@ -45,12 +45,13 @@
 "ifconfig". If tested ok, continue the next step.
 
 4. cp dl2k.ko /lib/modules/`uname -r`/kernel/drivers/net
-5. Add the following line to /etc/modprobe.conf:
+5. Add the following line to /etc/modprobe.d/dl2k.conf:
 	alias eth0 dl2k
-6. Run "netconfig" or "netconf" to create configuration script ifcfg-eth0
+6. Run depmod to updated module indexes.
+7. Run "netconfig" or "netconf" to create configuration script ifcfg-eth0
    located at /etc/sysconfig/network-scripts or create it manually.
    [see - Configuration Script Sample]
-7. Driver will automatically load and configure at next boot time.
+8. Driver will automatically load and configure at next boot time.
 
 Compiling the Driver
 ====================
@@ -154,8 +155,8 @@
   -----------------
   1. Copy dl2k.o to the network modules directory, typically
      /lib/modules/2.x.x-xx/net or /lib/modules/2.x.x/kernel/drivers/net.
-  2. Locate the boot module configuration file, most commonly modprobe.conf
-     or modules.conf (for 2.4) in the /etc directory. Add the following lines:
+  2. Locate the boot module configuration file, most commonly in the
+     /etc/modprobe.d/ directory. Add the following lines:
 
      alias ethx dl2k
      options dl2k <optional parameters>
diff --git a/Documentation/networking/driver.txt b/Documentation/networking/driver.txt
index 03283da..da59e28 100644
--- a/Documentation/networking/driver.txt
+++ b/Documentation/networking/driver.txt
@@ -2,16 +2,16 @@
 
 Transmit path guidelines:
 
-1) The hard_start_xmit method must never return '1' under any
-   normal circumstances.  It is considered a hard error unless
+1) The ndo_start_xmit method must not return NETDEV_TX_BUSY under
+   any normal circumstances.  It is considered a hard error unless
    there is no way your device can tell ahead of time when it's
    transmit function will become busy.
 
    Instead it must maintain the queue properly.  For example,
    for a driver implementing scatter-gather this means:
 
-	static int drv_hard_start_xmit(struct sk_buff *skb,
-		   		       struct net_device *dev)
+	static netdev_tx_t drv_hard_start_xmit(struct sk_buff *skb,
+					       struct net_device *dev)
 	{
 		struct drv *dp = netdev_priv(dev);
 
@@ -23,7 +23,7 @@
 			unlock_tx(dp);
 			printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
 			       dev->name);
-			return 1;
+			return NETDEV_TX_BUSY;
 		}
 
 		... queue packet to card ...
@@ -35,6 +35,7 @@
 		...
 		unlock_tx(dp);
 		...
+		return NETDEV_TX_OK;
 	}
 
    And then at the end of your TX reclamation event handling:
@@ -58,15 +59,12 @@
             TX_BUFFS_AVAIL(dp) > 0)
 		netif_wake_queue(dp->dev);
 
-2) Do not forget to update netdev->trans_start to jiffies after
-   each new tx packet is given to the hardware.
-
-3) A hard_start_xmit method must not modify the shared parts of a
+2) An ndo_start_xmit method must not modify the shared parts of a
    cloned SKB.
 
-4) Do not forget that once you return 0 from your hard_start_xmit
-   method, it is your driver's responsibility to free up the SKB
-   and in some finite amount of time.
+3) Do not forget that once you return NETDEV_TX_OK from your
+   ndo_start_xmit method, it is your driver's responsibility to free
+   up the SKB and in some finite amount of time.
 
    For example, this means that it is not allowed for your TX
    mitigation scheme to let TX packets "hang out" in the TX
@@ -74,8 +72,9 @@
    This error can deadlock sockets waiting for send buffer room
    to be freed up.
 
-   If you return 1 from the hard_start_xmit method, you must not keep
-   any reference to that SKB and you must not attempt to free it up.
+   If you return NETDEV_TX_BUSY from the ndo_start_xmit method, you
+   must not keep any reference to that SKB and you must not attempt
+   to free it up.
 
 Probing guidelines:
 
@@ -85,10 +84,10 @@
 
 Close/stop guidelines:
 
-1) After the dev->stop routine has been called, the hardware must
+1) After the ndo_stop routine has been called, the hardware must
    not receive or transmit any data.  All in flight packets must
    be aborted. If necessary, poll or wait for completion of 
    any reset commands.
 
-2) The dev->stop routine will be called by unregister_netdevice
+2) The ndo_stop routine will be called by unregister_netdevice
    if device is still UP.
diff --git a/Documentation/networking/e100.txt b/Documentation/networking/e100.txt
index 162f323..fcb6c71c 100644
--- a/Documentation/networking/e100.txt
+++ b/Documentation/networking/e100.txt
@@ -94,8 +94,8 @@
 
   Configuring a network driver to load properly when the system is started is
   distribution dependent. Typically, the configuration process involves adding
-  an alias line to /etc/modules.conf or /etc/modprobe.conf as well as editing
-  other system startup scripts and/or configuration files.  Many popular Linux
+  an alias line to /etc/modprobe.d/*.conf as well as editing other system
+  startup scripts and/or configuration files.  Many popular Linux
   distributions ship with tools to make these changes for you. To learn the
   proper way to configure a network device for your system, refer to your
   distribution documentation.  If during this process you are asked for the
@@ -103,7 +103,7 @@
   PRO/100 Family of Adapters is e100.
 
   As an example, if you install the e100 driver for two PRO/100 adapters
-  (eth0 and eth1), add the following to modules.conf or modprobe.conf:
+  (eth0 and eth1), add the following to a configuraton file in /etc/modprobe.d/
 
        alias eth0 e100
        alias eth1 e100
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index ad3e80e..bd80ba5 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -604,15 +604,8 @@
 ip_local_port_range - 2 INTEGERS
 	Defines the local port range that is used by TCP and UDP to
 	choose the local port. The first number is the first, the
-	second the last local port number. Default value depends on
-	amount of memory available on the system:
-	> 128Mb 32768-61000
-	< 128Mb 1024-4999 or even less.
-	This number defines number of active connections, which this
-	system can issue simultaneously to systems not supporting
-	TCP extensions (timestamps). With tcp_tw_recycle enabled
-	(i.e. by default) range 1024-4999 is enough to issue up to
-	2000 connections per second to systems supporting timestamps.
+	second the last local port number. The default values are
+	32768 and 61000 respectively.
 
 ip_local_reserved_ports - list of comma separated ranges
 	Specify the ports which are reserved for known third-party
diff --git a/Documentation/networking/ipv6.txt b/Documentation/networking/ipv6.txt
index 9fd7e21..6cd74fa 100644
--- a/Documentation/networking/ipv6.txt
+++ b/Documentation/networking/ipv6.txt
@@ -2,9 +2,9 @@
 Options for the ipv6 module are supplied as parameters at load time.
 
 Module options may be given as command line arguments to the insmod
-or modprobe command, but are usually specified in either the
-/etc/modules.conf or /etc/modprobe.conf configuration file, or in a
-distro-specific configuration file.
+or modprobe command, but are usually specified in either
+/etc/modules.d/*.conf configuration files, or in a distro-specific
+configuration file.
 
 The available ipv6 module parameters are listed below.  If a parameter
 is not specified the default value is used.
diff --git a/Documentation/networking/ixgb.txt b/Documentation/networking/ixgb.txt
index e196f16..d75a1f9 100644
--- a/Documentation/networking/ixgb.txt
+++ b/Documentation/networking/ixgb.txt
@@ -274,9 +274,9 @@
   -------------------------------------------------
   Configuring a network driver to load properly when the system is started is
   distribution dependent. Typically, the configuration process involves adding
-  an alias line to /etc/modprobe.conf as well as editing other system startup
-  scripts and/or configuration files.  Many popular Linux distributions ship
-  with tools to make these changes for you.  To learn the proper way to
+  an alias line to files in /etc/modprobe.d/ as well as editing other system
+  startup scripts and/or configuration files.  Many popular Linux distributions
+  ship with tools to make these changes for you.  To learn the proper way to
   configure a network device for your system, refer to your distribution
   documentation.  If during this process you are asked for the driver or module
   name, the name for the Linux Base Driver for the Intel 10GbE Family of
diff --git a/Documentation/networking/ltpc.txt b/Documentation/networking/ltpc.txt
index fe2a912..0bf3220c 100644
--- a/Documentation/networking/ltpc.txt
+++ b/Documentation/networking/ltpc.txt
@@ -25,7 +25,7 @@
 
 If you load the driver as a module, you can pass the parameters "io=",
 "irq=", and "dma=" on the command line with insmod or modprobe, or add
-them as options in /etc/modprobe.conf:
+them as options in a configuration file in /etc/modprobe.d/ directory:
 
  alias lt0 ltpc # autoload the module when the interface is configured
  options ltpc io=0x240 irq=9 dma=1
diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt
index 8935834..c7ecc70 100644
--- a/Documentation/networking/netdevices.txt
+++ b/Documentation/networking/netdevices.txt
@@ -47,26 +47,25 @@
 
 struct net_device synchronization rules
 =======================================
-dev->open:
+ndo_open:
 	Synchronization: rtnl_lock() semaphore.
 	Context: process
 
-dev->stop:
+ndo_stop:
 	Synchronization: rtnl_lock() semaphore.
 	Context: process
-	Note1: netif_running() is guaranteed false
-	Note2: dev->poll() is guaranteed to be stopped
+	Note: netif_running() is guaranteed false
 
-dev->do_ioctl:
+ndo_do_ioctl:
 	Synchronization: rtnl_lock() semaphore.
 	Context: process
 
-dev->get_stats:
+ndo_get_stats:
 	Synchronization: dev_base_lock rwlock.
 	Context: nominally process, but don't sleep inside an rwlock
 
-dev->hard_start_xmit:
-	Synchronization: netif_tx_lock spinlock.
+ndo_start_xmit:
+	Synchronization: __netif_tx_lock spinlock.
 
 	When the driver sets NETIF_F_LLTX in dev->features this will be
 	called without holding netif_tx_lock. In this case the driver
@@ -87,20 +86,20 @@
 	o NETDEV_TX_LOCKED Locking failed, please retry quickly.
 	  Only valid when NETIF_F_LLTX is set.
 
-dev->tx_timeout:
-	Synchronization: netif_tx_lock spinlock.
+ndo_tx_timeout:
+	Synchronization: netif_tx_lock spinlock; all TX queues frozen.
 	Context: BHs disabled
 	Notes: netif_queue_stopped() is guaranteed true
 
-dev->set_rx_mode:
-	Synchronization: netif_tx_lock spinlock.
+ndo_set_rx_mode:
+	Synchronization: netif_addr_lock spinlock.
 	Context: BHs disabled
 
 struct napi_struct synchronization rules
 ========================================
 napi->poll:
 	Synchronization: NAPI_STATE_SCHED bit in napi->state.  Device
-		driver's dev->close method will invoke napi_disable() on
+		driver's ndo_stop method will invoke napi_disable() on
 		all NAPI instances which will do a sleeping poll on the
 		NAPI_STATE_SCHED napi->state bit, waiting for all pending
 		NAPI activity to cease.
diff --git a/Documentation/networking/vortex.txt b/Documentation/networking/vortex.txt
index bd70976..b4038ff 100644
--- a/Documentation/networking/vortex.txt
+++ b/Documentation/networking/vortex.txt
@@ -67,8 +67,8 @@
 =================
 
 There are several parameters which may be provided to the driver when
-its module is loaded.  These are usually placed in /etc/modprobe.conf
-(/etc/modules.conf in 2.4).  Example:
+its module is loaded.  These are usually placed in /etc/modprobe.d/*.conf
+configuretion files.  Example:
 
 options 3c59x debug=3 rx_copybreak=300
 
@@ -425,7 +425,7 @@
       1) Increase the debug level.  Usually this is done via:
 
          a) modprobe driver debug=7
-         b) In /etc/modprobe.conf (or /etc/modules.conf for 2.4):
+         b) In /etc/modprobe.d/driver.conf:
             options driver debug=7
 
       2) Recreate the problem with the higher debug level,
diff --git a/Documentation/parport.txt b/Documentation/parport.txt
index 93a7cee..c208e43 100644
--- a/Documentation/parport.txt
+++ b/Documentation/parport.txt
@@ -36,18 +36,17 @@
 are automatically detected.
 
 
-KMod
-----
+modprobe
+--------
 
-If you use kmod, you will find it useful to edit /etc/modprobe.conf.
-Here is an example of the lines that need to be added:
+If you use modprobe , you will find it useful to add lines as below to a
+configuration file in /etc/modprobe.d/ directory:.
 
 	alias parport_lowlevel parport_pc
 	options parport_pc io=0x378,0x278 irq=7,auto
 
-KMod will then automatically load parport_pc (with the options
-"io=0x378,0x278 irq=7,auto") whenever a parallel port device driver
-(such as lp) is loaded.
+modprobe will load parport_pc (with the options "io=0x378,0x278 irq=7,auto")
+whenever a parallel port device driver (such as lp) is loaded.
 
 Note that these are example lines only!  You shouldn't in general need
 to specify any options to parport_pc in order to be able to use a
diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
index 150fd38..d97bccf 100644
--- a/Documentation/pinctrl.txt
+++ b/Documentation/pinctrl.txt
@@ -206,12 +206,21 @@
 stable value when nothing is driving the rail it is connected to, or when it's
 unconnected.
 
-For example, a platform may do this:
+Pin configuration can be programmed either using the explicit APIs described
+immediately below, or by adding configuration entries into the mapping table;
+see section "Board/machine configuration" below.
+
+For example, a platform may do the following to pull up a pin to VDD:
+
+#include <linux/pinctrl/consumer.h>
 
 ret = pin_config_set("foo-dev", "FOO_GPIO_PIN", PLATFORM_X_PULL_UP);
 
-To pull up a pin to VDD. The pin configuration driver implements callbacks for
-changing pin configuration in the pin controller ops like this:
+The format and meaning of the configuration parameter, PLATFORM_X_PULL_UP
+above, is entirely defined by the pin controller driver.
+
+The pin configuration driver implements callbacks for changing pin
+configuration in the pin controller ops like this:
 
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinconf.h>
@@ -492,14 +501,10 @@
     {"map-i2c0", i2c0, pinctrl0, fi2c0, gi2c0}
   }
 
-  Every map must be assigned a symbolic name, pin controller and function.
-  The group is not compulsory - if it is omitted the first group presented by
-  the driver as applicable for the function will be selected, which is
-  useful for simple cases.
-
-  The device name is present in map entries tied to specific devices. Maps
-  without device names are referred to as SYSTEM pinmuxes, such as can be taken
-  by the machine implementation on boot and not tied to any specific device.
+  Every map must be assigned a state name, pin controller, device and
+  function. The group is not compulsory - if it is omitted the first group
+  presented by the driver as applicable for the function will be selected,
+  which is useful for simple cases.
 
   It is possible to map several groups to the same combination of device,
   pin controller and function. This is for cases where a certain function on
@@ -726,19 +731,19 @@
 All the above functions are mandatory to implement for a pinmux driver.
 
 
-Pinmux interaction with the GPIO subsystem
-==========================================
+Pin control interaction with the GPIO subsystem
+===============================================
 
-The public pinmux API contains two functions named pinmux_request_gpio()
-and pinmux_free_gpio(). These two functions shall *ONLY* be called from
+The public pinmux API contains two functions named pinctrl_request_gpio()
+and pinctrl_free_gpio(). These two functions shall *ONLY* be called from
 gpiolib-based drivers as part of their gpio_request() and
-gpio_free() semantics. Likewise the pinmux_gpio_direction_[input|output]
+gpio_free() semantics. Likewise the pinctrl_gpio_direction_[input|output]
 shall only be called from within respective gpio_direction_[input|output]
 gpiolib implementation.
 
 NOTE that platforms and individual drivers shall *NOT* request GPIO pins to be
-muxed in. Instead, implement a proper gpiolib driver and have that driver
-request proper muxing for its pins.
+controlled e.g. muxed in. Instead, implement a proper gpiolib driver and have
+that driver request proper muxing and other control for its pins.
 
 The function list could become long, especially if you can convert every
 individual pin into a GPIO pin independent of any other pins, and then try
@@ -747,7 +752,7 @@
 In this case, the function array would become 64 entries for each GPIO
 setting and then the device functions.
 
-For this reason there are two functions a pinmux driver can implement
+For this reason there are two functions a pin control driver can implement
 to enable only GPIO on an individual pin: .gpio_request_enable() and
 .gpio_disable_free().
 
@@ -762,12 +767,12 @@
 will be passed along to this function.
 
 Alternatively to using these special functions, it is fully allowed to use
-named functions for each GPIO pin, the pinmux_request_gpio() will attempt to
+named functions for each GPIO pin, the pinctrl_request_gpio() will attempt to
 obtain the function "gpioN" where "N" is the global GPIO pin number if no
 special GPIO-handler is registered.
 
 
-Pinmux board/machine configuration
+Board/machine configuration
 ==================================
 
 Boards and machines define how a certain complete running system is put
@@ -775,27 +780,33 @@
 constrained and how the clock tree looks. Of course pinmux settings are also
 part of this.
 
-A pinmux config for a machine looks pretty much like a simple regulator
-configuration, so for the example array above we want to enable i2c and
-spi on the second function mapping:
+A pin controller configuration for a machine looks pretty much like a simple
+regulator configuration, so for the example array above we want to enable i2c
+and spi on the second function mapping:
 
 #include <linux/pinctrl/machine.h>
 
-static const struct pinmux_map __initdata pmx_mapping[] = {
+static const struct pinctrl_map __initdata mapping[] = {
 	{
-		.ctrl_dev_name = "pinctrl-foo",
-		.function = "spi0",
 		.dev_name = "foo-spi.0",
+		.name = PINCTRL_STATE_DEFAULT,
+		.type = PIN_MAP_TYPE_MUX_GROUP,
+		.ctrl_dev_name = "pinctrl-foo",
+		.data.mux.function = "spi0",
 	},
 	{
-		.ctrl_dev_name = "pinctrl-foo",
-		.function = "i2c0",
 		.dev_name = "foo-i2c.0",
+		.name = PINCTRL_STATE_DEFAULT,
+		.type = PIN_MAP_TYPE_MUX_GROUP,
+		.ctrl_dev_name = "pinctrl-foo",
+		.data.mux.function = "i2c0",
 	},
 	{
-		.ctrl_dev_name = "pinctrl-foo",
-		.function = "mmc0",
 		.dev_name = "foo-mmc.0",
+		.name = PINCTRL_STATE_DEFAULT,
+		.type = PIN_MAP_TYPE_MUX_GROUP,
+		.ctrl_dev_name = "pinctrl-foo",
+		.data.mux.function = "mmc0",
 	},
 };
 
@@ -805,21 +816,51 @@
 
 As you can see we may have several pin controllers on the system and thus
 we need to specify which one of them that contain the functions we wish
-to map. The map can also use struct device * directly, so there is no
-inherent need to use strings to specify .dev_name or .ctrl_dev_name, these
-are for the situation where you do not have a handle to the struct device *,
-for example if they are not yet instantiated or cumbersome to obtain.
+to map.
 
 You register this pinmux mapping to the pinmux subsystem by simply:
 
-       ret = pinmux_register_mappings(pmx_mapping, ARRAY_SIZE(pmx_mapping));
+       ret = pinctrl_register_mappings(mapping, ARRAY_SIZE(mapping));
 
 Since the above construct is pretty common there is a helper macro to make
 it even more compact which assumes you want to use pinctrl-foo and position
 0 for mapping, for example:
 
-static struct pinmux_map __initdata pmx_mapping[] = {
-       PINMUX_MAP("I2CMAP", "pinctrl-foo", "i2c0", "foo-i2c.0"),
+static struct pinctrl_map __initdata mapping[] = {
+	PIN_MAP_MUX_GROUP("foo-i2c.o", PINCTRL_STATE_DEFAULT, "pinctrl-foo", NULL, "i2c0"),
+};
+
+The mapping table may also contain pin configuration entries. It's common for
+each pin/group to have a number of configuration entries that affect it, so
+the table entries for configuration reference an array of config parameters
+and values. An example using the convenience macros is shown below:
+
+static unsigned long i2c_grp_configs[] = {
+	FOO_PIN_DRIVEN,
+	FOO_PIN_PULLUP,
+};
+
+static unsigned long i2c_pin_configs[] = {
+	FOO_OPEN_COLLECTOR,
+	FOO_SLEW_RATE_SLOW,
+};
+
+static struct pinctrl_map __initdata mapping[] = {
+	PIN_MAP_MUX_GROUP("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", "i2c0"),
+	PIN_MAP_MUX_CONFIGS_GROUP("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", i2c_grp_configs),
+	PIN_MAP_MUX_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0scl", i2c_pin_configs),
+	PIN_MAP_MUX_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0sda", i2c_pin_configs),
+};
+
+Finally, some devices expect the mapping table to contain certain specific
+named states. When running on hardware that doesn't need any pin controller
+configuration, the mapping table must still contain those named states, in
+order to explicitly indicate that the states were provided and intended to
+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[] = {
+	PIN_MAP_DUMMY_STATE("foo-i2c.0", PINCTRL_STATE_DEFAULT),
 };
 
 
@@ -831,81 +872,96 @@
 
 ...
 {
+	.dev_name = "foo-spi.0",
 	.name = "spi0-pos-A",
+	.type = PIN_MAP_TYPE_MUX_GROUP,
 	.ctrl_dev_name = "pinctrl-foo",
 	.function = "spi0",
 	.group = "spi0_0_grp",
-	.dev_name = "foo-spi.0",
 },
 {
+	.dev_name = "foo-spi.0",
 	.name = "spi0-pos-B",
+	.type = PIN_MAP_TYPE_MUX_GROUP,
 	.ctrl_dev_name = "pinctrl-foo",
 	.function = "spi0",
 	.group = "spi0_1_grp",
-	.dev_name = "foo-spi.0",
 },
 ...
 
 This example mapping is used to switch between two positions for spi0 at
 runtime, as described further below under the heading "Runtime pinmuxing".
 
-Further it is possible to match several groups of pins to the same function
-for a single device, say for example in the mmc0 example above, where you can
+Further it is possible for one named state to affect the muxing of several
+groups of pins, say for example in the mmc0 example above, where you can
 additively expand the mmc0 bus from 2 to 4 to 8 pins. If we want to use all
 three groups for a total of 2+2+4 = 8 pins (for an 8-bit MMC bus as is the
 case), we define a mapping like this:
 
 ...
 {
+	.dev_name = "foo-mmc.0",
 	.name = "2bit"
+	.type = PIN_MAP_TYPE_MUX_GROUP,
 	.ctrl_dev_name = "pinctrl-foo",
 	.function = "mmc0",
 	.group = "mmc0_1_grp",
-	.dev_name = "foo-mmc.0",
 },
 {
+	.dev_name = "foo-mmc.0",
 	.name = "4bit"
+	.type = PIN_MAP_TYPE_MUX_GROUP,
 	.ctrl_dev_name = "pinctrl-foo",
 	.function = "mmc0",
 	.group = "mmc0_1_grp",
-	.dev_name = "foo-mmc.0",
 },
 {
+	.dev_name = "foo-mmc.0",
 	.name = "4bit"
+	.type = PIN_MAP_TYPE_MUX_GROUP,
 	.ctrl_dev_name = "pinctrl-foo",
 	.function = "mmc0",
 	.group = "mmc0_2_grp",
-	.dev_name = "foo-mmc.0",
 },
 {
+	.dev_name = "foo-mmc.0",
 	.name = "8bit"
+	.type = PIN_MAP_TYPE_MUX_GROUP,
 	.ctrl_dev_name = "pinctrl-foo",
+	.function = "mmc0",
 	.group = "mmc0_1_grp",
-	.dev_name = "foo-mmc.0",
 },
 {
+	.dev_name = "foo-mmc.0",
 	.name = "8bit"
+	.type = PIN_MAP_TYPE_MUX_GROUP,
 	.ctrl_dev_name = "pinctrl-foo",
 	.function = "mmc0",
 	.group = "mmc0_2_grp",
-	.dev_name = "foo-mmc.0",
 },
 {
+	.dev_name = "foo-mmc.0",
 	.name = "8bit"
+	.type = PIN_MAP_TYPE_MUX_GROUP,
 	.ctrl_dev_name = "pinctrl-foo",
 	.function = "mmc0",
 	.group = "mmc0_3_grp",
-	.dev_name = "foo-mmc.0",
 },
 ...
 
 The result of grabbing this mapping from the device with something like
 this (see next paragraph):
 
-	pmx = pinmux_get(&device, "8bit");
+	p = pinctrl_get(dev);
+	s = pinctrl_lookup_state(p, "8bit");
+	ret = pinctrl_select_state(p, s);
+
+or more simply:
+
+	p = pinctrl_get_select(dev, "8bit");
 
 Will be that you activate all the three bottom records in the mapping at
-once. Since they share the same name, pin controller device, funcion and
+once. Since they share the same name, pin controller device, function and
 device, and since we allow multiple groups to match to a single device, they
 all get selected, and they all get enabled and disable simultaneously by the
 pinmux core.
@@ -914,97 +970,111 @@
 Pinmux requests from drivers
 ============================
 
-Generally it is discouraged to let individual drivers get and enable pinmuxes.
-So if possible, handle the pinmuxes in platform code or some other place where
-you have access to all the affected struct device * pointers. In some cases
-where a driver needs to switch between different mux mappings at runtime
-this is not possible.
+Generally it is discouraged to let individual drivers get and enable pin
+control. So if possible, handle the pin control in platform code or some other
+place where you have access to all the affected struct device * pointers. In
+some cases where a driver needs to e.g. switch between different mux mappings
+at runtime this is not possible.
 
-A driver may request a certain mux to be activated, usually just the default
-mux like this:
+A driver may request a certain control state to be activated, usually just the
+default state like this:
 
-#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/consumer.h>
 
 struct foo_state {
-       struct pinmux *pmx;
+       struct pinctrl *p;
+       struct pinctrl_state *s;
        ...
 };
 
 foo_probe()
 {
-	/* Allocate a state holder named "state" etc */
-	struct pinmux pmx;
+	/* Allocate a state holder named "foo" etc */
+	struct foo_state *foo = ...;
 
-	pmx = pinmux_get(&device, NULL);
-	if IS_ERR(pmx)
-		return PTR_ERR(pmx);
-	pinmux_enable(pmx);
+	foo->p = pinctrl_get(&device);
+	if (IS_ERR(foo->p)) {
+		/* FIXME: clean up "foo" here */
+		return PTR_ERR(foo->p);
+	}
 
-	state->pmx = pmx;
+	foo->s = pinctrl_lookup_state(foo->p, PINCTRL_STATE_DEFAULT);
+	if (IS_ERR(foo->s)) {
+		pinctrl_put(foo->p);
+		/* FIXME: clean up "foo" here */
+		return PTR_ERR(s);
+	}
+
+	ret = pinctrl_select_state(foo->s);
+	if (ret < 0) {
+		pinctrl_put(foo->p);
+		/* FIXME: clean up "foo" here */
+		return ret;
+	}
 }
 
 foo_remove()
 {
-	pinmux_disable(state->pmx);
-	pinmux_put(state->pmx);
+	pinctrl_put(state->p);
 }
 
-If you want to grab a specific mux mapping and not just the first one found for
-this device you can specify a specific mapping name, for example in the above
-example the second i2c0 setting: pinmux_get(&device, "spi0-pos-B");
-
-This get/enable/disable/put sequence can just as well be handled by bus drivers
+This get/lookup/select/put sequence can just as well be handled by bus drivers
 if you don't want each and every driver to handle it and you know the
 arrangement on your bus.
 
-The semantics of the get/enable respective disable/put is as follows:
+The semantics of the pinctrl APIs are:
 
-- pinmux_get() is called in process context to reserve the pins affected with
-  a certain mapping and set up the pinmux core and the driver. It will allocate
-  a struct from the kernel memory to hold the pinmux state.
+- pinctrl_get() is called in process context to obtain a handle to all pinctrl
+  information for a given client device. It will allocate a struct from the
+  kernel memory to hold the pinmux state. All mapping table parsing or similar
+  slow operations take place within this API.
 
-- pinmux_enable()/pinmux_disable() is quick and can be called from fastpath
-  (irq context) when you quickly want to set up/tear down the hardware muxing
-  when running a device driver. Usually it will just poke some values into a
-  register.
+- pinctrl_lookup_state() is called in process context to obtain a handle to a
+  specific state for a the client device. This operation may be slow too.
 
-- pinmux_disable() is called in process context to tear down the pin requests
-  and release the state holder struct for the mux setting.
+- pinctrl_select_state() programs pin controller hardware according to the
+  definition of the state as given by the mapping table. In theory this is a
+  fast-path operation, since it only involved blasting some register settings
+  into hardware. However, note that some pin controllers may have their
+  registers on a slow/IRQ-based bus, so client devices should not assume they
+  can call pinctrl_select_state() from non-blocking contexts.
 
-Usually the pinmux core handled the get/put pair and call out to the device
-drivers bookkeeping operations, like checking available functions and the
-associated pins, whereas the enable/disable pass on to the pin controller
+- pinctrl_put() frees all information associated with a pinctrl handle.
+
+Usually the pin control core handled the get/put pair and call out to the
+device drivers bookkeeping operations, like checking available functions and
+the associated pins, whereas the enable/disable pass on to the pin controller
 driver which takes care of activating and/or deactivating the mux setting by
 quickly poking some registers.
 
-The pins are allocated for your device when you issue the pinmux_get() call,
+The pins are allocated for your device when you issue the pinctrl_get() call,
 after this you should be able to see this in the debugfs listing of all pins.
 
 
-System pinmux hogging
-=====================
+System pin control hogging
+==========================
 
-A system pinmux map entry, i.e. a pinmux setting that does not have a device
-associated with it, can be hogged by the core when the pin controller is
-registered. This means that the core will attempt to call pinmux_get() and
-pinmux_enable() on it immediately after the pin control device has been
-registered.
+Pin control map entries can be hogged by the core when the pin controller
+is registered. This means that the core will attempt to call pinctrl_get(),
+lookup_state() and select_state() on it immediately after the pin control
+device has been registered.
 
-This is enabled by simply setting the .hog_on_boot field in the map to true,
-like this:
+This occurs for mapping table entries where the client device name is equal
+to the pin controller device name, and the state name is PINCTRL_STATE_DEFAULT.
 
 {
-	.name = "POWERMAP"
+	.dev_name = "pinctrl-foo",
+	.name = PINCTRL_STATE_DEFAULT,
+	.type = PIN_MAP_TYPE_MUX_GROUP,
 	.ctrl_dev_name = "pinctrl-foo",
 	.function = "power_func",
-	.hog_on_boot = true,
 },
 
 Since it may be common to request the core to hog a few always-applicable
 mux settings on the primary pin controller, there is a convenience macro for
 this:
 
-PINMUX_MAP_PRIMARY_SYS_HOG("POWERMAP", "power_func")
+PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-foo", NULL /* group */, "power_func")
 
 This gives the exact same result as the above construction.
 
@@ -1016,32 +1086,47 @@
 an SPI port from one set of pins to another set of pins. Say for example for
 spi0 in the example above, we expose two different groups of pins for the same
 function, but with different named in the mapping as described under
-"Advanced mapping" above. So we have two mappings named "spi0-pos-A" and
-"spi0-pos-B".
+"Advanced mapping" above. So that for an SPI device, we have two states named
+"pos-A" and "pos-B".
 
 This snippet first muxes the function in the pins defined by group A, enables
 it, disables and releases it, and muxes it in on the pins defined by group B:
 
+#include <linux/pinctrl/consumer.h>
+
 foo_switch()
 {
-	struct pinmux *pmx;
+	struct pinctrl *p;
+	struct pinctrl_state *s1, *s2;
+
+	/* Setup */
+	p = pinctrl_get(&device);
+	if (IS_ERR(p))
+		...
+
+	s1 = pinctrl_lookup_state(foo->p, "pos-A");
+	if (IS_ERR(s1))
+		...
+
+	s2 = pinctrl_lookup_state(foo->p, "pos-B");
+	if (IS_ERR(s2))
+		...
 
 	/* Enable on position A */
-	pmx = pinmux_get(&device, "spi0-pos-A");
-	if IS_ERR(pmx)
-		return PTR_ERR(pmx);
-	pinmux_enable(pmx);
+	ret = pinctrl_select_state(s1);
+	if (ret < 0)
+	    ...
 
-	/* This releases the pins again */
-	pinmux_disable(pmx);
-	pinmux_put(pmx);
+	...
 
 	/* Enable on position B */
-	pmx = pinmux_get(&device, "spi0-pos-B");
-	if IS_ERR(pmx)
-		return PTR_ERR(pmx);
-	pinmux_enable(pmx);
+	ret = pinctrl_select_state(s2);
+	if (ret < 0)
+	    ...
+
 	...
+
+	pinctrl_put(p);
 }
 
 The above has to be done from process context.
diff --git a/Documentation/powerpc/firmware-assisted-dump.txt b/Documentation/powerpc/firmware-assisted-dump.txt
new file mode 100644
index 0000000..3007bc9
--- /dev/null
+++ b/Documentation/powerpc/firmware-assisted-dump.txt
@@ -0,0 +1,270 @@
+
+                   Firmware-Assisted Dump
+                   ------------------------
+                       July 2011
+
+The goal of firmware-assisted dump is to enable the dump of
+a crashed system, and to do so from a fully-reset system, and
+to minimize the total elapsed time until the system is back
+in production use.
+
+- Firmware assisted dump (fadump) infrastructure is intended to replace
+  the existing phyp assisted dump.
+- Fadump uses the same firmware interfaces and memory reservation model
+  as phyp assisted dump.
+- Unlike phyp dump, fadump exports the memory dump through /proc/vmcore
+  in the ELF format in the same way as kdump. This helps us reuse the
+  kdump infrastructure for dump capture and filtering.
+- Unlike phyp dump, userspace tool does not need to refer any sysfs
+  interface while reading /proc/vmcore.
+- Unlike phyp dump, fadump allows user to release all the memory reserved
+  for dump, with a single operation of echo 1 > /sys/kernel/fadump_release_mem.
+- Once enabled through kernel boot parameter, fadump can be
+  started/stopped through /sys/kernel/fadump_registered interface (see
+  sysfs files section below) and can be easily integrated with kdump
+  service start/stop init scripts.
+
+Comparing with kdump or other strategies, firmware-assisted
+dump offers several strong, practical advantages:
+
+-- Unlike kdump, the system has been reset, and loaded
+   with a fresh copy of the kernel.  In particular,
+   PCI and I/O devices have been reinitialized and are
+   in a clean, consistent state.
+-- Once the dump is copied out, the memory that held the dump
+   is immediately available to the running kernel. And therefore,
+   unlike kdump, fadump doesn't need a 2nd reboot to get back
+   the system to the production configuration.
+
+The above can only be accomplished by coordination with,
+and assistance from the Power firmware. The procedure is
+as follows:
+
+-- The first kernel registers the sections of memory with the
+   Power firmware for dump preservation during OS initialization.
+   These registered sections of memory are reserved by the first
+   kernel during early boot.
+
+-- When a system crashes, the Power firmware will save
+   the low memory (boot memory of size larger of 5% of system RAM
+   or 256MB) of RAM to the previous registered region. It will
+   also save system registers, and hardware PTE's.
+
+   NOTE: The term 'boot memory' means size of the low memory chunk
+         that is required for a kernel to boot successfully when
+         booted with restricted memory. By default, the boot memory
+         size will be the larger of 5% of system RAM or 256MB.
+         Alternatively, user can also specify boot memory size
+         through boot parameter 'fadump_reserve_mem=' which will
+         override the default calculated size. Use this option
+         if default boot memory size is not sufficient for second
+         kernel to boot successfully.
+
+-- After the low memory (boot memory) area has been saved, the
+   firmware will reset PCI and other hardware state.  It will
+   *not* clear the RAM. It will then launch the bootloader, as
+   normal.
+
+-- The freshly booted kernel will notice that there is a new
+   node (ibm,dump-kernel) in the device tree, indicating that
+   there is crash data available from a previous boot. During
+   the early boot OS will reserve rest of the memory above
+   boot memory size effectively booting with restricted memory
+   size. This will make sure that the second kernel will not
+   touch any of the dump memory area.
+
+-- User-space tools will read /proc/vmcore to obtain the contents
+   of memory, which holds the previous crashed kernel dump in ELF
+   format. The userspace tools may copy this info to disk, or
+   network, nas, san, iscsi, etc. as desired.
+
+-- Once the userspace tool is done saving dump, it will echo
+   '1' to /sys/kernel/fadump_release_mem to release the reserved
+   memory back to general use, except the memory required for
+   next firmware-assisted dump registration.
+
+   e.g.
+     # echo 1 > /sys/kernel/fadump_release_mem
+
+Please note that the firmware-assisted dump feature
+is only available on Power6 and above systems with recent
+firmware versions.
+
+Implementation details:
+----------------------
+
+During boot, a check is made to see if firmware supports
+this feature on that particular machine. If it does, then
+we check to see if an active dump is waiting for us. If yes
+then everything but boot memory size of RAM is reserved during
+early boot (See Fig. 2). This area is released once we finish
+collecting the dump from user land scripts (e.g. kdump scripts)
+that are run. If there is dump data, then the
+/sys/kernel/fadump_release_mem file is created, and the reserved
+memory is held.
+
+If there is no waiting dump data, then only the memory required
+to hold CPU state, HPTE region, boot memory dump and elfcore
+header, is reserved at the top of memory (see Fig. 1). This area
+is *not* released: this region will be kept permanently reserved,
+so that it can act as a receptacle for a copy of the boot memory
+content in addition to CPU state and HPTE region, in the case a
+crash does occur.
+
+  o Memory Reservation during first kernel
+
+  Low memory                                        Top of memory
+  0      boot memory size                                       |
+  |           |                       |<--Reserved dump area -->|
+  V           V                       |   Permanent Reservation V
+  +-----------+----------/ /----------+---+----+-----------+----+
+  |           |                       |CPU|HPTE|  DUMP     |ELF |
+  +-----------+----------/ /----------+---+----+-----------+----+
+        |                                           ^
+        |                                           |
+        \                                           /
+         -------------------------------------------
+          Boot memory content gets transferred to
+          reserved area by firmware at the time of
+          crash
+                   Fig. 1
+
+  o Memory Reservation during second kernel after crash
+
+  Low memory                                        Top of memory
+  0      boot memory size                                       |
+  |           |<------------- Reserved dump area ----------- -->|
+  V           V                                                 V
+  +-----------+----------/ /----------+---+----+-----------+----+
+  |           |                       |CPU|HPTE|  DUMP     |ELF |
+  +-----------+----------/ /----------+---+----+-----------+----+
+        |                                                    |
+        V                                                    V
+   Used by second                                    /proc/vmcore
+   kernel to boot
+                   Fig. 2
+
+Currently the dump will be copied from /proc/vmcore to a
+a new file upon user intervention. The dump data available through
+/proc/vmcore will be in ELF format. Hence the existing kdump
+infrastructure (kdump scripts) to save the dump works fine with
+minor modifications.
+
+The tools to examine the dump will be same as the ones
+used for kdump.
+
+How to enable firmware-assisted dump (fadump):
+-------------------------------------
+
+1. Set config option CONFIG_FA_DUMP=y and build kernel.
+2. Boot into linux kernel with 'fadump=on' kernel cmdline option.
+3. Optionally, user can also set 'fadump_reserve_mem=' kernel cmdline
+   to specify size of the memory to reserve for boot memory dump
+   preservation.
+
+NOTE: If firmware-assisted dump fails to reserve memory then it will
+   fallback to existing kdump mechanism if 'crashkernel=' option
+   is set at kernel cmdline.
+
+Sysfs/debugfs files:
+------------
+
+Firmware-assisted dump feature uses sysfs file system to hold
+the control files and debugfs file to display memory reserved region.
+
+Here is the list of files under kernel sysfs:
+
+ /sys/kernel/fadump_enabled
+
+    This is used to display the fadump status.
+    0 = fadump is disabled
+    1 = fadump is enabled
+
+    This interface can be used by kdump init scripts to identify if
+    fadump is enabled in the kernel and act accordingly.
+
+ /sys/kernel/fadump_registered
+
+    This is used to display the fadump registration status as well
+    as to control (start/stop) the fadump registration.
+    0 = fadump is not registered.
+    1 = fadump is registered and ready to handle system crash.
+
+    To register fadump echo 1 > /sys/kernel/fadump_registered and
+    echo 0 > /sys/kernel/fadump_registered for un-register and stop the
+    fadump. Once the fadump is un-registered, the system crash will not
+    be handled and vmcore will not be captured. This interface can be
+    easily integrated with kdump service start/stop.
+
+ /sys/kernel/fadump_release_mem
+
+    This file is available only when fadump is active during
+    second kernel. This is used to release the reserved memory
+    region that are held for saving crash dump. To release the
+    reserved memory echo 1 to it:
+
+    echo 1  > /sys/kernel/fadump_release_mem
+
+    After echo 1, the content of the /sys/kernel/debug/powerpc/fadump_region
+    file will change to reflect the new memory reservations.
+
+    The existing userspace tools (kdump infrastructure) can be easily
+    enhanced to use this interface to release the memory reserved for
+    dump and continue without 2nd reboot.
+
+Here is the list of files under powerpc debugfs:
+(Assuming debugfs is mounted on /sys/kernel/debug directory.)
+
+ /sys/kernel/debug/powerpc/fadump_region
+
+    This file shows the reserved memory regions if fadump is
+    enabled otherwise this file is empty. The output format
+    is:
+    <region>: [<start>-<end>] <reserved-size> bytes, Dumped: <dump-size>
+
+    e.g.
+    Contents when fadump is registered during first kernel
+
+    # cat /sys/kernel/debug/powerpc/fadump_region
+    CPU : [0x0000006ffb0000-0x0000006fff001f] 0x40020 bytes, Dumped: 0x0
+    HPTE: [0x0000006fff0020-0x0000006fff101f] 0x1000 bytes, Dumped: 0x0
+    DUMP: [0x0000006fff1020-0x0000007fff101f] 0x10000000 bytes, Dumped: 0x0
+
+    Contents when fadump is active during second kernel
+
+    # cat /sys/kernel/debug/powerpc/fadump_region
+    CPU : [0x0000006ffb0000-0x0000006fff001f] 0x40020 bytes, Dumped: 0x40020
+    HPTE: [0x0000006fff0020-0x0000006fff101f] 0x1000 bytes, Dumped: 0x1000
+    DUMP: [0x0000006fff1020-0x0000007fff101f] 0x10000000 bytes, Dumped: 0x10000000
+        : [0x00000010000000-0x0000006ffaffff] 0x5ffb0000 bytes, Dumped: 0x5ffb0000
+
+NOTE: Please refer to Documentation/filesystems/debugfs.txt on
+      how to mount the debugfs filesystem.
+
+
+TODO:
+-----
+ o Need to come up with the better approach to find out more
+   accurate boot memory size that is required for a kernel to
+   boot successfully when booted with restricted memory.
+ o The fadump implementation introduces a fadump crash info structure
+   in the scratch area before the ELF core header. The idea of introducing
+   this structure is to pass some important crash info data to the second
+   kernel which will help second kernel to populate ELF core header with
+   correct data before it gets exported through /proc/vmcore. The current
+   design implementation does not address a possibility of introducing
+   additional fields (in future) to this structure without affecting
+   compatibility. Need to come up with the better approach to address this.
+   The possible approaches are:
+	1. Introduce version field for version tracking, bump up the version
+	whenever a new field is added to the structure in future. The version
+	field can be used to find out what fields are valid for the current
+	version of the structure.
+	2. Reserve the area of predefined size (say PAGE_SIZE) for this
+	structure and have unused area as reserved (initialized to zero)
+	for future field additions.
+   The advantage of approach 1 over 2 is we don't need to reserve extra space.
+---
+Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+This document is based on the original documentation written for phyp
+assisted dump by Linas Vepstas and Manish Ahuja.
diff --git a/Documentation/powerpc/mpc52xx.txt b/Documentation/powerpc/mpc52xx.txt
index 10dd4ab..0d540a3 100644
--- a/Documentation/powerpc/mpc52xx.txt
+++ b/Documentation/powerpc/mpc52xx.txt
@@ -2,7 +2,7 @@
 -----------------------------
 
 For the latest info, go to http://www.246tNt.com/mpc52xx/
- 
+
 To compile/use :
 
   - U-Boot:
@@ -10,23 +10,23 @@
         if you wish to ).
      # make lite5200_defconfig
      # make uImage
-    
+
      then, on U-boot:
      => tftpboot 200000 uImage
      => tftpboot 400000 pRamdisk
      => bootm 200000 400000
-    
+
   - DBug:
      # <edit Makefile to set ARCH=ppc & CROSS_COMPILE=... ( also EXTRAVERSION
         if you wish to ).
      # make lite5200_defconfig
      # cp your_initrd.gz arch/ppc/boot/images/ramdisk.image.gz
-     # make zImage.initrd 
-     # make 
+     # make zImage.initrd
+     # make
 
      then in DBug:
      DBug> dn -i zImage.initrd.lite5200
-     
+
 
 Some remarks :
  - The port is named mpc52xxx, and config options are PPC_MPC52xx. The MGT5100
diff --git a/Documentation/powerpc/phyp-assisted-dump.txt b/Documentation/powerpc/phyp-assisted-dump.txt
deleted file mode 100644
index ad34020..0000000
--- a/Documentation/powerpc/phyp-assisted-dump.txt
+++ /dev/null
@@ -1,127 +0,0 @@
-
-                   Hypervisor-Assisted Dump
-                   ------------------------
-                       November 2007
-
-The goal of hypervisor-assisted dump is to enable the dump of
-a crashed system, and to do so from a fully-reset system, and
-to minimize the total elapsed time until the system is back
-in production use.
-
-As compared to kdump or other strategies, hypervisor-assisted
-dump offers several strong, practical advantages:
-
--- Unlike kdump, the system has been reset, and loaded
-   with a fresh copy of the kernel.  In particular,
-   PCI and I/O devices have been reinitialized and are
-   in a clean, consistent state.
--- As the dump is performed, the dumped memory becomes
-   immediately available to the system for normal use.
--- After the dump is completed, no further reboots are
-   required; the system will be fully usable, and running
-   in its normal, production mode on its normal kernel.
-
-The above can only be accomplished by coordination with,
-and assistance from the hypervisor. The procedure is
-as follows:
-
--- When a system crashes, the hypervisor will save
-   the low 256MB of RAM to a previously registered
-   save region. It will also save system state, system
-   registers, and hardware PTE's.
-
--- After the low 256MB area has been saved, the
-   hypervisor will reset PCI and other hardware state.
-   It will *not* clear RAM. It will then launch the
-   bootloader, as normal.
-
--- The freshly booted kernel will notice that there
-   is a new node (ibm,dump-kernel) in the device tree,
-   indicating that there is crash data available from
-   a previous boot. It will boot into only 256MB of RAM,
-   reserving the rest of system memory.
-
--- Userspace tools will parse /sys/kernel/release_region
-   and read /proc/vmcore to obtain the contents of memory,
-   which holds the previous crashed kernel. The userspace
-   tools may copy this info to disk, or network, nas, san,
-   iscsi, etc. as desired.
-
-   For Example: the values in /sys/kernel/release-region
-   would look something like this (address-range pairs).
-   CPU:0x177fee000-0x10000: HPTE:0x177ffe020-0x1000: /
-   DUMP:0x177fff020-0x10000000, 0x10000000-0x16F1D370A
-
--- As the userspace tools complete saving a portion of
-   dump, they echo an offset and size to
-   /sys/kernel/release_region to release the reserved
-   memory back to general use.
-
-   An example of this is:
-     "echo 0x40000000 0x10000000 > /sys/kernel/release_region"
-   which will release 256MB at the 1GB boundary.
-
-Please note that the hypervisor-assisted dump feature
-is only available on Power6-based systems with recent
-firmware versions.
-
-Implementation details:
-----------------------
-
-During boot, a check is made to see if firmware supports
-this feature on this particular machine. If it does, then
-we check to see if a active dump is waiting for us. If yes
-then everything but 256 MB of RAM is reserved during early
-boot. This area is released once we collect a dump from user
-land scripts that are run. If there is dump data, then
-the /sys/kernel/release_region file is created, and
-the reserved memory is held.
-
-If there is no waiting dump data, then only the highest
-256MB of the ram is reserved as a scratch area. This area
-is *not* released: this region will be kept permanently
-reserved, so that it can act as a receptacle for a copy
-of the low 256MB in the case a crash does occur. See,
-however, "open issues" below, as to whether
-such a reserved region is really needed.
-
-Currently the dump will be copied from /proc/vmcore to a
-a new file upon user intervention. The starting address
-to be read and the range for each data point in provided
-in /sys/kernel/release_region.
-
-The tools to examine the dump will be same as the ones
-used for kdump.
-
-General notes:
---------------
-Security: please note that there are potential security issues
-with any sort of dump mechanism. In particular, plaintext
-(unencrypted) data, and possibly passwords, may be present in
-the dump data. Userspace tools must take adequate precautions to
-preserve security.
-
-Open issues/ToDo:
-------------
- o The various code paths that tell the hypervisor that a crash
-   occurred, vs. it simply being a normal reboot, should be
-   reviewed, and possibly clarified/fixed.
-
- o Instead of using /sys/kernel, should there be a /sys/dump
-   instead? There is a dump_subsys being created by the s390 code,
-   perhaps the pseries code should use a similar layout as well.
-
- o Is reserving a 256MB region really required? The goal of
-   reserving a 256MB scratch area is to make sure that no
-   important crash data is clobbered when the hypervisor
-   save low mem to the scratch area. But, if one could assure
-   that nothing important is located in some 256MB area, then
-   it would not need to be reserved. Something that can be
-   improved in subsequent versions.
-
- o Still working the kdump team to integrate this with kdump,
-   some work remains but this would not affect the current
-   patches.
-
- o Still need to write a shell script, to copy the dump away.
-   Currently I am parsing it manually.
diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
new file mode 100644
index 0000000..70a048c
--- /dev/null
+++ b/Documentation/remoteproc.txt
@@ -0,0 +1,322 @@
+Remote Processor Framework
+
+1. Introduction
+
+Modern SoCs typically have heterogeneous remote processor devices in asymmetric
+multiprocessing (AMP) configurations, which may be running different instances
+of operating system, whether it's Linux or any other flavor of real-time OS.
+
+OMAP4, for example, has dual Cortex-A9, dual Cortex-M3 and a C64x+ DSP.
+In a typical configuration, the dual cortex-A9 is running Linux in a SMP
+configuration, and each of the other three cores (two M3 cores and a DSP)
+is running its own instance of RTOS in an AMP configuration.
+
+The remoteproc framework allows different platforms/architectures to
+control (power on, load firmware, power off) those remote processors while
+abstracting the hardware differences, so the entire driver doesn't need to be
+duplicated. In addition, this framework also adds rpmsg virtio devices
+for remote processors that supports this kind of communication. This way,
+platform-specific remoteproc drivers only need to provide a few low-level
+handlers, and then all rpmsg drivers will then just work
+(for more information about the virtio-based rpmsg bus and its drivers,
+please read Documentation/rpmsg.txt).
+Registration of other types of virtio devices is now also possible. Firmwares
+just need to publish what kind of virtio devices do they support, and then
+remoteproc will add those devices. This makes it possible to reuse the
+existing virtio drivers with remote processor backends at a minimal development
+cost.
+
+2. User API
+
+  int rproc_boot(struct rproc *rproc)
+    - Boot a remote processor (i.e. load its firmware, power it on, ...).
+      If the remote processor is already powered on, this function immediately
+      returns (successfully).
+      Returns 0 on success, and an appropriate error value otherwise.
+      Note: to use this function you should already have a valid rproc
+      handle. There are several ways to achieve that cleanly (devres, pdata,
+      the way remoteproc_rpmsg.c does this, or, if this becomes prevalent, we
+      might also consider using dev_archdata for this). See also
+      rproc_get_by_name() below.
+
+  void rproc_shutdown(struct rproc *rproc)
+    - Power off a remote processor (previously booted with rproc_boot()).
+      In case @rproc is still being used by an additional user(s), then
+      this function will just decrement the power refcount and exit,
+      without really powering off the device.
+      Every call to rproc_boot() must (eventually) be accompanied by a call
+      to rproc_shutdown(). Calling rproc_shutdown() redundantly is a bug.
+      Notes:
+      - we're not decrementing the rproc's refcount, only the power refcount.
+        which means that the @rproc handle stays valid even after
+        rproc_shutdown() returns, and users can still use it with a subsequent
+        rproc_boot(), if needed.
+      - don't call rproc_shutdown() to unroll rproc_get_by_name(), exactly
+        because rproc_shutdown() _does not_ decrement the refcount of @rproc.
+        To decrement the refcount of @rproc, use rproc_put() (but _only_ if
+        you acquired @rproc using rproc_get_by_name()).
+
+  struct rproc *rproc_get_by_name(const char *name)
+    - Find an rproc handle using the remote processor's name, and then
+      boot it. If it's already powered on, then just immediately return
+      (successfully). Returns the rproc handle on success, and NULL on failure.
+      This function increments the remote processor's refcount, so always
+      use rproc_put() to decrement it back once rproc isn't needed anymore.
+      Note: currently rproc_get_by_name() and rproc_put() are not used anymore
+      by the rpmsg bus and its drivers. We need to scrutinize the use cases
+      that still need them, and see if we can migrate them to use the non
+      name-based boot/shutdown interface.
+
+  void rproc_put(struct rproc *rproc)
+    - Decrement @rproc's power refcount and shut it down if it reaches zero
+      (essentially by just calling rproc_shutdown), and then decrement @rproc's
+      validity refcount too.
+      After this function returns, @rproc may _not_ be used anymore, and its
+      handle should be considered invalid.
+      This function should be called _iff_ the @rproc handle was grabbed by
+      calling rproc_get_by_name().
+
+3. Typical usage
+
+#include <linux/remoteproc.h>
+
+/* in case we were given a valid 'rproc' handle */
+int dummy_rproc_example(struct rproc *my_rproc)
+{
+	int ret;
+
+	/* let's power on and boot our remote processor */
+	ret = rproc_boot(my_rproc);
+	if (ret) {
+		/*
+		 * something went wrong. handle it and leave.
+		 */
+	}
+
+	/*
+	 * our remote processor is now powered on... give it some work
+	 */
+
+	/* let's shut it down now */
+	rproc_shutdown(my_rproc);
+}
+
+4. API for implementors
+
+  struct rproc *rproc_alloc(struct device *dev, const char *name,
+				const struct rproc_ops *ops,
+				const char *firmware, int len)
+    - Allocate a new remote processor handle, but don't register
+      it yet. Required parameters are the underlying device, the
+      name of this remote processor, platform-specific ops handlers,
+      the name of the firmware to boot this rproc with, and the
+      length of private data needed by the allocating rproc driver (in bytes).
+
+      This function should be used by rproc implementations during
+      initialization of the remote processor.
+      After creating an rproc handle using this function, and when ready,
+      implementations should then call rproc_register() to complete
+      the registration of the remote processor.
+      On success, the new rproc is returned, and on failure, NULL.
+
+      Note: _never_ directly deallocate @rproc, even if it was not registered
+      yet. Instead, if you just need to unroll rproc_alloc(), use rproc_free().
+
+  void rproc_free(struct rproc *rproc)
+    - Free an rproc handle that was allocated by rproc_alloc.
+      This function should _only_ be used if @rproc was only allocated,
+      but not registered yet.
+      If @rproc was already successfully registered (by calling
+      rproc_register()), then use rproc_unregister() instead.
+
+  int rproc_register(struct rproc *rproc)
+    - Register @rproc with the remoteproc framework, after it has been
+      allocated with rproc_alloc().
+      This is called by the platform-specific rproc implementation, whenever
+      a new remote processor device is probed.
+      Returns 0 on success and an appropriate error code otherwise.
+      Note: this function initiates an asynchronous firmware loading
+      context, which will look for virtio devices supported by the rproc's
+      firmware.
+      If found, those virtio devices will be created and added, so as a result
+      of registering this remote processor, additional virtio drivers might get
+      probed.
+
+  int rproc_unregister(struct rproc *rproc)
+    - Unregister a remote processor, and decrement its refcount.
+      If its refcount drops to zero, then @rproc will be freed. If not,
+      it will be freed later once the last reference is dropped.
+
+      This function should be called when the platform specific rproc
+      implementation decides to remove the rproc device. it should
+      _only_ be called if a previous invocation of rproc_register()
+      has completed successfully.
+
+      After rproc_unregister() returns, @rproc is _not_ valid anymore and
+      it shouldn't be used. More specifically, don't call rproc_free()
+      or try to directly free @rproc after rproc_unregister() returns;
+      none of these are needed, and calling them is a bug.
+
+      Returns 0 on success and -EINVAL if @rproc isn't valid.
+
+5. Implementation callbacks
+
+These callbacks should be provided by platform-specific remoteproc
+drivers:
+
+/**
+ * struct rproc_ops - platform-specific device handlers
+ * @start:	power on the device and boot it
+ * @stop:	power off the device
+ * @kick:	kick a virtqueue (virtqueue id given as a parameter)
+ */
+struct rproc_ops {
+	int (*start)(struct rproc *rproc);
+	int (*stop)(struct rproc *rproc);
+	void (*kick)(struct rproc *rproc, int vqid);
+};
+
+Every remoteproc implementation should at least provide the ->start and ->stop
+handlers. If rpmsg/virtio functionality is also desired, then the ->kick handler
+should be provided as well.
+
+The ->start() handler takes an rproc handle and should then power on the
+device and boot it (use rproc->priv to access platform-specific private data).
+The boot address, in case needed, can be found in rproc->bootaddr (remoteproc
+core puts there the ELF entry point).
+On success, 0 should be returned, and on failure, an appropriate error code.
+
+The ->stop() handler takes an rproc handle and powers the device down.
+On success, 0 is returned, and on failure, an appropriate error code.
+
+The ->kick() handler takes an rproc handle, and an index of a virtqueue
+where new message was placed in. Implementations should interrupt the remote
+processor and let it know it has pending messages. Notifying remote processors
+the exact virtqueue index to look in is optional: it is easy (and not
+too expensive) to go through the existing virtqueues and look for new buffers
+in the used rings.
+
+6. Binary Firmware Structure
+
+At this point remoteproc only supports ELF32 firmware binaries. However,
+it is quite expected that other platforms/devices which we'd want to
+support with this framework will be based on different binary formats.
+
+When those use cases show up, we will have to decouple the binary format
+from the framework core, so we can support several binary formats without
+duplicating common code.
+
+When the firmware is parsed, its various segments are loaded to memory
+according to the specified device address (might be a physical address
+if the remote processor is accessing memory directly).
+
+In addition to the standard ELF segments, most remote processors would
+also include a special section which we call "the resource table".
+
+The resource table contains system resources that the remote processor
+requires before it should be powered on, such as allocation of physically
+contiguous memory, or iommu mapping of certain on-chip peripherals.
+Remotecore will only power up the device after all the resource table's
+requirement are met.
+
+In addition to system resources, the resource table may also contain
+resource entries that publish the existence of supported features
+or configurations by the remote processor, such as trace buffers and
+supported virtio devices (and their configurations).
+
+The resource table begins with this header:
+
+/**
+ * struct resource_table - firmware resource table header
+ * @ver: version number
+ * @num: number of resource entries
+ * @reserved: reserved (must be zero)
+ * @offset: array of offsets pointing at the various resource entries
+ *
+ * The header of the resource table, as expressed by this structure,
+ * contains a version number (should we need to change this format in the
+ * future), the number of available resource entries, and their offsets
+ * in the table.
+ */
+struct resource_table {
+	u32 ver;
+	u32 num;
+	u32 reserved[2];
+	u32 offset[0];
+} __packed;
+
+Immediately following this header are the resource entries themselves,
+each of which begins with the following resource entry header:
+
+/**
+ * struct fw_rsc_hdr - firmware resource entry header
+ * @type: resource type
+ * @data: resource data
+ *
+ * Every resource entry begins with a 'struct fw_rsc_hdr' header providing
+ * its @type. The content of the entry itself will immediately follow
+ * this header, and it should be parsed according to the resource type.
+ */
+struct fw_rsc_hdr {
+	u32 type;
+	u8 data[0];
+} __packed;
+
+Some resources entries are mere announcements, where the host is informed
+of specific remoteproc configuration. Other entries require the host to
+do something (e.g. allocate a system resource). Sometimes a negotiation
+is expected, where the firmware requests a resource, and once allocated,
+the host should provide back its details (e.g. address of an allocated
+memory region).
+
+Here are the various resource types that are currently supported:
+
+/**
+ * enum fw_resource_type - types of resource entries
+ *
+ * @RSC_CARVEOUT:   request for allocation of a physically contiguous
+ *		    memory region.
+ * @RSC_DEVMEM:     request to iommu_map a memory-based peripheral.
+ * @RSC_TRACE:	    announces the availability of a trace buffer into which
+ *		    the remote processor will be writing logs.
+ * @RSC_VDEV:       declare support for a virtio device, and serve as its
+ *		    virtio header.
+ * @RSC_LAST:       just keep this one at the end
+ *
+ * Please note that these values are used as indices to the rproc_handle_rsc
+ * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to
+ * check the validity of an index before the lookup table is accessed, so
+ * please update it as needed.
+ */
+enum fw_resource_type {
+	RSC_CARVEOUT	= 0,
+	RSC_DEVMEM	= 1,
+	RSC_TRACE	= 2,
+	RSC_VDEV	= 3,
+	RSC_LAST	= 4,
+};
+
+For more details regarding a specific resource type, please see its
+dedicated structure in include/linux/remoteproc.h.
+
+We also expect that platform-specific resource entries will show up
+at some point. When that happens, we could easily add a new RSC_PLATFORM
+type, and hand those resources to the platform-specific rproc driver to handle.
+
+7. Virtio and remoteproc
+
+The firmware should provide remoteproc information about virtio devices
+that it supports, and their configurations: a RSC_VDEV resource entry
+should specify the virtio device id (as in virtio_ids.h), virtio features,
+virtio config space, vrings information, etc.
+
+When a new remote processor is registered, the remoteproc framework
+will look for its resource table and will register the virtio devices
+it supports. A firmware may support any number of virtio devices, and
+of any type (a single remote processor can also easily support several
+rpmsg virtio devices this way, if desired).
+
+Of course, RSC_VDEV resource entries are only good enough for static
+allocation of virtio devices. Dynamic allocations will also be made possible
+using the rpmsg bus (similar to how we already do dynamic allocations of
+rpmsg channels; read more about it in rpmsg.txt).
diff --git a/Documentation/rpmsg.txt b/Documentation/rpmsg.txt
new file mode 100644
index 0000000..409d9f9
--- /dev/null
+++ b/Documentation/rpmsg.txt
@@ -0,0 +1,293 @@
+Remote Processor Messaging (rpmsg) Framework
+
+Note: this document describes the rpmsg bus and how to write rpmsg drivers.
+To learn how to add rpmsg support for new platforms, check out remoteproc.txt
+(also a resident of Documentation/).
+
+1. Introduction
+
+Modern SoCs typically employ heterogeneous remote processor devices in
+asymmetric multiprocessing (AMP) configurations, which may be running
+different instances of operating system, whether it's Linux or any other
+flavor of real-time OS.
+
+OMAP4, for example, has dual Cortex-A9, dual Cortex-M3 and a C64x+ DSP.
+Typically, the dual cortex-A9 is running Linux in a SMP configuration,
+and each of the other three cores (two M3 cores and a DSP) is running
+its own instance of RTOS in an AMP configuration.
+
+Typically AMP remote processors employ dedicated DSP codecs and multimedia
+hardware accelerators, and therefore are often used to offload CPU-intensive
+multimedia tasks from the main application processor.
+
+These remote processors could also be used to control latency-sensitive
+sensors, drive random hardware blocks, or just perform background tasks
+while the main CPU is idling.
+
+Users of those remote processors can either be userland apps (e.g. multimedia
+frameworks talking with remote OMX components) or kernel drivers (controlling
+hardware accessible only by the remote processor, reserving kernel-controlled
+resources on behalf of the remote processor, etc..).
+
+Rpmsg is a virtio-based messaging bus that allows kernel drivers to communicate
+with remote processors available on the system. In turn, drivers could then
+expose appropriate user space interfaces, if needed.
+
+When writing a driver that exposes rpmsg communication to userland, please
+keep in mind that remote processors might have direct access to the
+system's physical memory and other sensitive hardware resources (e.g. on
+OMAP4, remote cores and hardware accelerators may have direct access to the
+physical memory, gpio banks, dma controllers, i2c bus, gptimers, mailbox
+devices, hwspinlocks, etc..). Moreover, those remote processors might be
+running RTOS where every task can access the entire memory/devices exposed
+to the processor. To minimize the risks of rogue (or buggy) userland code
+exploiting remote bugs, and by that taking over the system, it is often
+desired to limit userland to specific rpmsg channels (see definition below)
+it can send messages on, and if possible, minimize how much control
+it has over the content of the messages.
+
+Every rpmsg device is a communication channel with a remote processor (thus
+rpmsg devices are called channels). Channels are identified by a textual name
+and have a local ("source") rpmsg address, and remote ("destination") rpmsg
+address.
+
+When a driver starts listening on a channel, its rx callback is bound with
+a unique rpmsg local address (a 32-bit integer). This way when inbound messages
+arrive, the rpmsg core dispatches them to the appropriate driver according
+to their destination address (this is done by invoking the driver's rx handler
+with the payload of the inbound message).
+
+
+2. User API
+
+  int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int len);
+   - sends a message across to the remote processor on a given channel.
+     The caller should specify the channel, the data it wants to send,
+     and its length (in bytes). The message will be sent on the specified
+     channel, i.e. its source and destination address fields will be
+     set to the channel's src and dst addresses.
+
+     In case there are no TX buffers available, the function will block until
+     one becomes available (i.e. until the remote processor consumes
+     a tx buffer and puts it back on virtio's used descriptor ring),
+     or a timeout of 15 seconds elapses. When the latter happens,
+     -ERESTARTSYS is returned.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst);
+   - sends a message across to the remote processor on a given channel,
+     to a destination address provided by the caller.
+     The caller should specify the channel, the data it wants to send,
+     its length (in bytes), and an explicit destination address.
+     The message will then be sent to the remote processor to which the
+     channel belongs, using the channel's src address, and the user-provided
+     dst address (thus the channel's dst address will be ignored).
+
+     In case there are no TX buffers available, the function will block until
+     one becomes available (i.e. until the remote processor consumes
+     a tx buffer and puts it back on virtio's used descriptor ring),
+     or a timeout of 15 seconds elapses. When the latter happens,
+     -ERESTARTSYS is returned.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+							void *data, int len);
+   - sends a message across to the remote processor, using the src and dst
+     addresses provided by the user.
+     The caller should specify the channel, the data it wants to send,
+     its length (in bytes), and explicit source and destination addresses.
+     The message will then be sent to the remote processor to which the
+     channel belongs, but the channel's src and dst addresses will be
+     ignored (and the user-provided addresses will be used instead).
+
+     In case there are no TX buffers available, the function will block until
+     one becomes available (i.e. until the remote processor consumes
+     a tx buffer and puts it back on virtio's used descriptor ring),
+     or a timeout of 15 seconds elapses. When the latter happens,
+     -ERESTARTSYS is returned.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len);
+   - sends a message across to the remote processor on a given channel.
+     The caller should specify the channel, the data it wants to send,
+     and its length (in bytes). The message will be sent on the specified
+     channel, i.e. its source and destination address fields will be
+     set to the channel's src and dst addresses.
+
+     In case there are no TX buffers available, the function will immediately
+     return -ENOMEM without waiting until one becomes available.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
+   - sends a message across to the remote processor on a given channel,
+     to a destination address provided by the user.
+     The user should specify the channel, the data it wants to send,
+     its length (in bytes), and an explicit destination address.
+     The message will then be sent to the remote processor to which the
+     channel belongs, using the channel's src address, and the user-provided
+     dst address (thus the channel's dst address will be ignored).
+
+     In case there are no TX buffers available, the function will immediately
+     return -ENOMEM without waiting until one becomes available.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+							void *data, int len);
+   - sends a message across to the remote processor, using source and
+     destination addresses provided by the user.
+     The user should specify the channel, the data it wants to send,
+     its length (in bytes), and explicit source and destination addresses.
+     The message will then be sent to the remote processor to which the
+     channel belongs, but the channel's src and dst addresses will be
+     ignored (and the user-provided addresses will be used instead).
+
+     In case there are no TX buffers available, the function will immediately
+     return -ENOMEM without waiting until one becomes available.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rpdev,
+		void (*cb)(struct rpmsg_channel *, void *, int, void *, u32),
+		void *priv, u32 addr);
+   - every rpmsg address in the system is bound to an rx callback (so when
+     inbound messages arrive, they are dispatched by the rpmsg bus using the
+     appropriate callback handler) by means of an rpmsg_endpoint struct.
+
+     This function allows drivers to create such an endpoint, and by that,
+     bind a callback, and possibly some private data too, to an rpmsg address
+     (either one that is known in advance, or one that will be dynamically
+     assigned for them).
+
+     Simple rpmsg drivers need not call rpmsg_create_ept, because an endpoint
+     is already created for them when they are probed by the rpmsg bus
+     (using the rx callback they provide when they registered to the rpmsg bus).
+
+     So things should just work for simple drivers: they already have an
+     endpoint, their rx callback is bound to their rpmsg address, and when
+     relevant inbound messages arrive (i.e. messages which their dst address
+     equals to the src address of their rpmsg channel), the driver's handler
+     is invoked to process it.
+
+     That said, more complicated drivers might do need to allocate
+     additional rpmsg addresses, and bind them to different rx callbacks.
+     To accomplish that, those drivers need to call this function.
+     Drivers should provide their channel (so the new endpoint would bind
+     to the same remote processor their channel belongs to), an rx callback
+     function, an optional private data (which is provided back when the
+     rx callback is invoked), and an address they want to bind with the
+     callback. If addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will
+     dynamically assign them an available rpmsg address (drivers should have
+     a very good reason why not to always use RPMSG_ADDR_ANY here).
+
+     Returns a pointer to the endpoint on success, or NULL on error.
+
+  void rpmsg_destroy_ept(struct rpmsg_endpoint *ept);
+   - destroys an existing rpmsg endpoint. user should provide a pointer
+     to an rpmsg endpoint that was previously created with rpmsg_create_ept().
+
+  int register_rpmsg_driver(struct rpmsg_driver *rpdrv);
+   - registers an rpmsg driver with the rpmsg bus. user should provide
+     a pointer to an rpmsg_driver struct, which contains the driver's
+     ->probe() and ->remove() functions, an rx callback, and an id_table
+     specifying the names of the channels this driver is interested to
+     be probed with.
+
+  void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv);
+   - unregisters an rpmsg driver from the rpmsg bus. user should provide
+     a pointer to a previously-registered rpmsg_driver struct.
+     Returns 0 on success, and an appropriate error value on failure.
+
+
+3. Typical usage
+
+The following is a simple rpmsg driver, that sends an "hello!" message
+on probe(), and whenever it receives an incoming message, it dumps its
+content to the console.
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rpmsg.h>
+
+static void rpmsg_sample_cb(struct rpmsg_channel *rpdev, void *data, int len,
+						void *priv, u32 src)
+{
+	print_hex_dump(KERN_INFO, "incoming message:", DUMP_PREFIX_NONE,
+						16, 1, data, len, true);
+}
+
+static int rpmsg_sample_probe(struct rpmsg_channel *rpdev)
+{
+	int err;
+
+	dev_info(&rpdev->dev, "chnl: 0x%x -> 0x%x\n", rpdev->src, rpdev->dst);
+
+	/* send a message on our channel */
+	err = rpmsg_send(rpdev, "hello!", 6);
+	if (err) {
+		pr_err("rpmsg_send failed: %d\n", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static void __devexit rpmsg_sample_remove(struct rpmsg_channel *rpdev)
+{
+	dev_info(&rpdev->dev, "rpmsg sample client driver is removed\n");
+}
+
+static struct rpmsg_device_id rpmsg_driver_sample_id_table[] = {
+	{ .name	= "rpmsg-client-sample" },
+	{ },
+};
+MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_sample_id_table);
+
+static struct rpmsg_driver rpmsg_sample_client = {
+	.drv.name	= KBUILD_MODNAME,
+	.drv.owner	= THIS_MODULE,
+	.id_table	= rpmsg_driver_sample_id_table,
+	.probe		= rpmsg_sample_probe,
+	.callback	= rpmsg_sample_cb,
+	.remove		= __devexit_p(rpmsg_sample_remove),
+};
+
+static int __init init(void)
+{
+	return register_rpmsg_driver(&rpmsg_sample_client);
+}
+module_init(init);
+
+static void __exit fini(void)
+{
+	unregister_rpmsg_driver(&rpmsg_sample_client);
+}
+module_exit(fini);
+
+Note: a similar sample which can be built and loaded can be found
+in samples/rpmsg/.
+
+4. Allocations of rpmsg channels:
+
+At this point we only support dynamic allocations of rpmsg channels.
+
+This is possible only with remote processors that have the VIRTIO_RPMSG_F_NS
+virtio device feature set. This feature bit means that the remote
+processor supports dynamic name service announcement messages.
+
+When this feature is enabled, creation of rpmsg devices (i.e. channels)
+is completely dynamic: the remote processor announces the existence of a
+remote rpmsg service by sending a name service message (which contains
+the name and rpmsg addr of the remote service, see struct rpmsg_ns_msg).
+
+This message is then handled by the rpmsg bus, which in turn dynamically
+creates and registers an rpmsg channel (which represents the remote service).
+If/when a relevant rpmsg driver is registered, it will be immediately probed
+by the bus, and can then start sending messages to the remote service.
+
+The plan is also to add static creation of rpmsg channels via the virtio
+config space, but it's not implemented yet.
diff --git a/Documentation/s390/3270.txt b/Documentation/s390/3270.txt
index 7a5c73a..7c715de 100644
--- a/Documentation/s390/3270.txt
+++ b/Documentation/s390/3270.txt
@@ -47,9 +47,9 @@
 one another.  ReIPL as soon as possible after running the configuration
 script and the resulting /tmp/mkdev3270.
 
-If you have chosen to make tub3270 a module, you add a line to
-/etc/modprobe.conf.  If you are working on a VM virtual machine, you
-can use DEF GRAF to define virtual 3270 devices.
+If you have chosen to make tub3270 a module, you add a line to a
+configuration file under /etc/modprobe.d/.  If you are working on a VM
+virtual machine, you can use DEF GRAF to define virtual 3270 devices.
 
 You may generate both 3270 and 3215 console support, or one or the
 other, or neither.  If you generate both, the console type under VM is
@@ -60,7 +60,7 @@
 
 In brief, these are the steps:
 	1. Install the tub3270 patch
-	2. (If a module) add a line to /etc/modprobe.conf
+	2. (If a module) add a line to a file in /etc/modprobe.d/*.conf
 	3. (If VM) define devices with DEF GRAF
 	4. Reboot
 	5. Configure
@@ -84,13 +84,12 @@
 		make modules_install
 
 	2. (Perform this step only if you have configured tub3270 as a
-	module.)  Add a line to /etc/modprobe.conf to automatically
-	load the driver when it's needed.  With this line added,
-	you will see login prompts appear on your 3270s as soon as
-	boot is complete (or with emulated 3270s, as soon as you dial
-	into your vm guest using the command "DIAL <vmguestname>").
-	Since the line-mode major number is 227, the line to add to
-	/etc/modprobe.conf should be:
+	module.)  Add a line to a file /etc/modprobe.d/*.conf to automatically
+	load the driver when it's needed.  With this line added, you will see
+	login prompts appear on your 3270s as soon as boot is complete (or
+	with emulated 3270s, as soon as you dial into your vm guest using the
+	command "DIAL <vmguestname>").  Since the line-mode major number is
+	227, the line to add should be:
 		alias char-major-227 tub3270
 
 	3. Define graphic devices to your vm guest machine, if you
diff --git a/Documentation/scsi/00-INDEX b/Documentation/scsi/00-INDEX
index b48ded5..b7dd650 100644
--- a/Documentation/scsi/00-INDEX
+++ b/Documentation/scsi/00-INDEX
@@ -94,3 +94,5 @@
 	- info on second generation driver for sym53c8xx based adapters
 tmscsim.txt
 	- info on driver for AM53c974 based adapters
+ufs.txt
+	- info on Universal Flash Storage(UFS) and UFS host controller driver.
diff --git a/Documentation/scsi/LICENSE.qla2xxx b/Documentation/scsi/LICENSE.qla2xxx
index 19e7cd4..ce0fdf3 100644
--- a/Documentation/scsi/LICENSE.qla2xxx
+++ b/Documentation/scsi/LICENSE.qla2xxx
@@ -1,48 +1,11 @@
 Copyright (c) 2003-2011 QLogic Corporation
-QLogic Linux/ESX Fibre Channel HBA Driver
+QLogic Linux FC-FCoE Driver
 
-This program includes a device driver for Linux 2.6/ESX that may be
-distributed with QLogic hardware specific firmware binary file.
+This program includes a device driver for Linux 3.x.
 You may modify and redistribute the device driver code under the
 GNU General Public License (a copy of which is attached hereto as
 Exhibit A) published by the Free Software Foundation (version 2).
 
-You may redistribute the hardware specific firmware binary file
-under the following terms:
-
-	1. Redistribution of source code (only if applicable),
-	   must retain the above copyright notice, this list of
-	   conditions and the following disclaimer.
-
-	2. Redistribution 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 name of QLogic Corporation may not be used to
-	   endorse or promote products derived from this software
-	   without specific prior written permission
-
-REGARDLESS OF WHAT LICENSING MECHANISM IS USED OR APPLICABLE,
-THIS PROGRAM IS PROVIDED BY QLOGIC CORPORATION "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 AUTHOR
-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.
-
-USER ACKNOWLEDGES AND AGREES THAT USE OF THIS PROGRAM WILL NOT
-CREATE OR GIVE GROUNDS FOR A LICENSE BY IMPLICATION, ESTOPPEL, OR
-OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS (PATENT, COPYRIGHT,
-TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT) EMBODIED IN
-ANY OTHER QLOGIC HARDWARE OR SOFTWARE EITHER SOLELY OR IN
-COMBINATION WITH THIS PROGRAM.
 
 
 EXHIBIT A
diff --git a/Documentation/scsi/aic79xx.txt b/Documentation/scsi/aic79xx.txt
index 64ac709..e2d3273 100644
--- a/Documentation/scsi/aic79xx.txt
+++ b/Documentation/scsi/aic79xx.txt
@@ -215,7 +215,7 @@
                  INCORRECTLY CAN RENDER YOUR SYSTEM INOPERABLE.
                  USE THEM WITH CAUTION. 
 
-   Edit the file "modprobe.conf" in the directory /etc and add/edit a
+   Put a .conf file in the /etc/modprobe.d/ directory and add/edit a
    line containing 'options aic79xx aic79xx=[command[,command...]]' where
    'command' is one or more of the following:
    -----------------------------------------------------------------
diff --git a/Documentation/scsi/aic7xxx.txt b/Documentation/scsi/aic7xxx.txt
index 18f8d19..7c5d022 100644
--- a/Documentation/scsi/aic7xxx.txt
+++ b/Documentation/scsi/aic7xxx.txt
@@ -190,7 +190,7 @@
                  INCORRECTLY CAN RENDER YOUR SYSTEM INOPERABLE.
                  USE THEM WITH CAUTION. 
 
-   Edit the file "modprobe.conf" in the directory /etc and add/edit a
+   Put a .conf file in the /etc/modprobe.d directory and add/edit a
    line containing 'options aic7xxx aic7xxx=[command[,command...]]' where
    'command' is one or more of the following:
    -----------------------------------------------------------------
diff --git a/Documentation/scsi/bfa.txt b/Documentation/scsi/bfa.txt
new file mode 100644
index 0000000..f2d6e9d
--- /dev/null
+++ b/Documentation/scsi/bfa.txt
@@ -0,0 +1,82 @@
+Linux driver for Brocade FC/FCOE adapters
+
+
+Supported Hardware
+------------------
+
+bfa 3.0.2.2 driver supports all Brocade FC/FCOE adapters. Below is a list of
+adapter models with corresponding PCIIDs.
+
+	PCIID		  	Model
+
+	1657:0013:1657:0014	425 4Gbps dual port FC HBA
+	1657:0013:1657:0014	825 8Gbps PCIe dual port FC HBA
+	1657:0013:103c:1742	HP 82B 8Gbps PCIedual port FC HBA
+	1657:0013:103c:1744	HP 42B 4Gbps dual port FC HBA
+	1657:0017:1657:0014	415 4Gbps single port FC HBA
+	1657:0017:1657:0014	815 8Gbps single port FC HBA
+	1657:0017:103c:1741	HP 41B 4Gbps single port FC HBA
+	1657:0017:103c 1743	HP 81B 8Gbps single port FC HBA
+	1657:0021:103c:1779	804 8Gbps FC HBA for HP Bladesystem c-class
+
+	1657:0014:1657:0014	1010 10Gbps single port CNA - FCOE
+	1657:0014:1657:0014	1020 10Gbps dual port CNA - FCOE
+	1657:0014:1657:0014	1007 10Gbps dual port CNA - FCOE
+	1657:0014:1657:0014	1741 10Gbps dual port CNA - FCOE
+
+	1657:0022:1657:0024	1860 16Gbps FC HBA
+	1657:0022:1657:0022	1860 10Gbps CNA - FCOE
+
+
+Firmware download
+-----------------
+
+The latest Firmware package for 3.0.2.2 bfa driver can be found at:
+
+http://www.brocade.com/services-support/drivers-downloads/adapters/Linux.page
+
+and then click following respective util package link:
+
+	Version			Link
+
+	v3.0.0.0	Linux Adapter Firmware package for RHEL 6.2, SLES 11SP2
+
+
+Configuration & Management utility download
+-------------------------------------------
+
+The latest driver configuration & management utility for 3.0.2.2 bfa driver can
+be found at:
+
+http://www.brocade.com/services-support/drivers-downloads/adapters/Linux.page
+
+and then click following respective util pacakge link
+
+	Version			Link
+
+	v3.0.2.0	Linux Adapter Firmware package for RHEL 6.2, SLES 11SP2
+
+
+Documentation
+-------------
+
+The latest Administration's Guide, Installation and Reference Manual,
+Troubleshooting Guide, and Release Notes for the corresponding out-of-box
+driver can be found at:
+
+http://www.brocade.com/services-support/drivers-downloads/adapters/Linux.page
+
+and use the following inbox and out-of-box driver version mapping to find
+the corresponding documentation:
+
+	Inbox Version		Out-of-box Version
+
+	v3.0.2.2		v3.0.0.0
+
+
+Support
+-------
+
+For general product and support info, go to the Brocade website at:
+
+http://www.brocade.com/services-support/index.page
diff --git a/Documentation/scsi/libsas.txt b/Documentation/scsi/libsas.txt
index aa54f54..3cc9c78 100644
--- a/Documentation/scsi/libsas.txt
+++ b/Documentation/scsi/libsas.txt
@@ -398,21 +398,6 @@
 	task_done -- callback when the task has finished execution
 };
 
-When an external entity, entity other than the LLDD or the
-SAS Layer, wants to work with a struct domain_device, it
-_must_ call kobject_get() when getting a handle on the
-device and kobject_put() when it is done with the device.
-
-This does two things:
-     A) implements proper kfree() for the device;
-     B) increments/decrements the kref for all players:
-     domain_device
-	all domain_device's ... (if past an expander)
-	    port
-		host adapter
-		     pci device
-			 and up the ladder, etc.
-
 DISCOVERY
 ---------
 
diff --git a/Documentation/scsi/osst.txt b/Documentation/scsi/osst.txt
index ad86c6d..00c8ebb2 100644
--- a/Documentation/scsi/osst.txt
+++ b/Documentation/scsi/osst.txt
@@ -66,7 +66,7 @@
 If you want to have the module autoloaded on access to /dev/osst, you may
 add something like
 alias char-major-206 osst
-to your /etc/modprobe.conf (before 2.6: modules.conf).
+to a file under /etc/modprobe.d/ directory.
 
 You may find it convenient to create a symbolic link 
 ln -s nosst0 /dev/tape
diff --git a/Documentation/scsi/st.txt b/Documentation/scsi/st.txt
index 691ca29..685bf35 100644
--- a/Documentation/scsi/st.txt
+++ b/Documentation/scsi/st.txt
@@ -390,6 +390,10 @@
 	     MT_ST_SYSV sets the SYSV semantics (mode)
 	     MT_ST_NOWAIT enables immediate mode (i.e., don't wait for
 	        the command to finish) for some commands (e.g., rewind)
+	     MT_ST_NOWAIT_EOF enables immediate filemark mode (i.e. when
+	        writing a filemark, don't wait for it to complete). Please
+		see the BASICS note about MTWEOFI with respect to the
+		possible dangers of writing immediate filemarks.
 	     MT_ST_SILI enables setting the SILI bit in SCSI commands when
 		reading in variable block mode to enhance performance when
 		reading blocks shorter than the byte count; set this only
diff --git a/Documentation/scsi/ufs.txt b/Documentation/scsi/ufs.txt
new file mode 100644
index 0000000..41a6164
--- /dev/null
+++ b/Documentation/scsi/ufs.txt
@@ -0,0 +1,133 @@
+                       Universal Flash Storage
+                       =======================
+
+
+Contents
+--------
+
+1. Overview
+2. UFS Architecture Overview
+  2.1 Application Layer
+  2.2 UFS Transport Protocol(UTP) layer
+  2.3 UFS Interconnect(UIC) Layer
+3. UFSHCD Overview
+  3.1 UFS controller initialization
+  3.2 UTP Transfer requests
+  3.3 UFS error handling
+  3.4 SCSI Error handling
+
+
+1. Overview
+-----------
+
+Universal Flash Storage(UFS) is a storage specification for flash devices.
+It is aimed to provide a universal storage interface for both
+embedded and removable flash memory based storage in mobile
+devices such as smart phones and tablet computers. The specification
+is defined by JEDEC Solid State Technology Association. UFS is based
+on MIPI M-PHY physical layer standard. UFS uses MIPI M-PHY as the
+physical layer and MIPI Unipro as the link layer.
+
+The main goals of UFS is to provide,
+ * Optimized performance:
+   For UFS version 1.0 and 1.1 the target performance is as follows,
+   Support for Gear1 is mandatory (rate A: 1248Mbps, rate B: 1457.6Mbps)
+   Support for Gear2 is optional (rate A: 2496Mbps, rate B: 2915.2Mbps)
+   Future version of the standard,
+   Gear3 (rate A: 4992Mbps, rate B: 5830.4Mbps)
+ * Low power consumption
+ * High random IOPs and low latency
+
+
+2. UFS Architecture Overview
+----------------------------
+
+UFS has a layered communication architecture which is based on SCSI
+SAM-5 architectural model.
+
+UFS communication architecture consists of following layers,
+
+2.1 Application Layer
+
+  The Application layer is composed of UFS command set layer(UCS),
+  Task Manager and Device manager. The UFS interface is designed to be
+  protocol agnostic, however SCSI has been selected as a baseline
+  protocol for versions 1.0 and 1.1 of UFS protocol  layer.
+  UFS supports subset of SCSI commands defined by SPC-4 and SBC-3.
+  * UCS: It handles SCSI commands supported by UFS specification.
+  * Task manager: It handles task management functions defined by the
+     UFS which are meant for command queue control.
+  * Device manager: It handles device level operations and device
+     configuration operations. Device level operations mainly involve
+     device power management operations and commands to Interconnect
+     layers. Device level configurations involve handling of query
+     requests which are used to modify and retrieve configuration
+     information of the device.
+
+2.2 UFS Transport Protocol(UTP) layer
+
+  UTP layer provides services for
+  the higher layers through Service Access Points. UTP defines 3
+  service access points for higher layers.
+  * UDM_SAP: Device manager service access point is exposed to device
+    manager for device level operations. These device level operations
+    are done through query requests.
+  * UTP_CMD_SAP: Command service access point is exposed to UFS command
+    set layer(UCS) to transport commands.
+  * UTP_TM_SAP: Task management service access point is exposed to task
+    manager to transport task management functions.
+  UTP transports messages through UFS protocol information unit(UPIU).
+
+2.3 UFS Interconnect(UIC) Layer
+
+  UIC is the lowest layer of UFS layered architecture. It handles
+  connection between UFS host and UFS device. UIC consists of
+  MIPI UniPro and MIPI M-PHY. UIC provides 2 service access points
+  to upper layer,
+  * UIC_SAP: To transport UPIU between UFS host and UFS device.
+  * UIO_SAP: To issue commands to Unipro layers.
+
+
+3. UFSHCD Overview
+------------------
+
+The UFS host controller driver is based on Linux SCSI Framework.
+UFSHCD is a low level device driver which acts as an interface between
+SCSI Midlayer and PCIe based UFS host controllers.
+
+The current UFSHCD implementation supports following functionality,
+
+3.1 UFS controller initialization
+
+  The initialization module brings UFS host controller to active state
+  and prepares the controller to transfer commands/response between
+  UFSHCD and UFS device.
+
+3.2 UTP Transfer requests
+
+  Transfer request handling module of UFSHCD receives SCSI commands
+  from SCSI Midlayer, forms UPIUs and issues the UPIUs to UFS Host
+  controller. Also, the module decodes, responses received from UFS
+  host controller in the form of UPIUs and intimates the SCSI Midlayer
+  of the status of the command.
+
+3.3 UFS error handling
+
+  Error handling module handles Host controller fatal errors,
+  Device fatal errors and UIC interconnect layer related errors.
+
+3.4 SCSI Error handling
+
+  This is done through UFSHCD SCSI error handling routines registered
+  with SCSI Midlayer. Examples of some of the error handling commands
+  issues by SCSI Midlayer are Abort task, Lun reset and host reset.
+  UFSHCD Routines to perform these tasks are registered with
+  SCSI Midlayer through .eh_abort_handler, .eh_device_reset_handler and
+  .eh_host_reset_handler.
+
+In this version of UFSHCD Query requests and power management
+functionality are not implemented.
+
+UFS Specifications can be found at,
+UFS - http://www.jedec.org/sites/default/files/docs/JESD220.pdf
+UFSHCI - http://www.jedec.org/sites/default/files/docs/JESD223.pdf
diff --git a/Documentation/serial/computone.txt b/Documentation/serial/computone.txt
index 39ddcdb..a6a1158 100644
--- a/Documentation/serial/computone.txt
+++ b/Documentation/serial/computone.txt
@@ -49,7 +49,7 @@
 
 	Note the hardware address from the Computone ISA cards installed into
 		the system.  These are required for editing ip2.c or editing
-		/etc/modprobe.conf, or for specification on the modprobe
+		/etc/modprobe.d/*.conf, or for specification on the modprobe
 		command line.
 
 	Note that the /etc/modules.conf should be used for older (pre-2.6)
@@ -66,7 +66,7 @@
 c) Set address on ISA cards then:
    edit /usr/src/linux/drivers/char/ip2.c if needed 
 	or
-   edit /etc/modprobe.conf if needed (module).
+   edit config file in  /etc/modprobe.d/ if needed (module).
 	or both to match this setting.
 d) Run "make modules"
 e) Run "make modules_install"
@@ -153,11 +153,11 @@
 selects polled mode). If no base addresses are specified the defaults in 
 ip2.c are used. If you are autoloading the driver module with kerneld or
 kmod the base addresses and interrupt number must also be set in ip2.c
-and recompile or just insert and options line in /etc/modprobe.conf or both.
+and recompile or just insert and options line in /etc/modprobe.d/*.conf or both.
 The options line is equivalent to the command line and takes precedence over
 what is in ip2.c. 
 
-/etc/modprobe.conf sample:
+config sample to put /etc/modprobe.d/*.conf:
 	options ip2 io=1,0x328 irq=1,10
 	alias char-major-71 ip2
 	alias char-major-72 ip2
diff --git a/Documentation/serial/rocket.txt b/Documentation/serial/rocket.txt
index 1d85829..60b0398 100644
--- a/Documentation/serial/rocket.txt
+++ b/Documentation/serial/rocket.txt
@@ -62,7 +62,7 @@
 
 If installed as a module, the module must be loaded.  This can be done
 manually by entering "modprobe rocket".  To have the module loaded automatically
-upon system boot, edit the /etc/modprobe.conf file and add the line
+upon system boot, edit a /etc/modprobe.d/*.conf file and add the line
 "alias char-major-46 rocket".
 
 In order to use the ports, their device names (nodes) must be created with mknod.
diff --git a/Documentation/serial/stallion.txt b/Documentation/serial/stallion.txt
index 5c4902d..5509091 100644
--- a/Documentation/serial/stallion.txt
+++ b/Documentation/serial/stallion.txt
@@ -139,8 +139,8 @@
 
 You will probably want to enter this module load and configuration information
 into your system startup scripts so that the drivers are loaded and configured
-on each system boot. Typically the start up script would be something like
-/etc/modprobe.conf.
+on each system boot. Typically configuration files are put in the
+/etc/modprobe.d/ directory.
 
 
 2.2 STATIC DRIVER CONFIGURATION:
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 12e3a0f..8c16d50 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -860,7 +860,8 @@
 
     [Multiple options for each card instance]
     model	- force the model name
-    position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF)
+    position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF,
+    		   3 = VIACOMBO, 4 = COMBO)
     probe_mask  - Bitmask to probe codecs (default = -1, meaning all slots)
     		  When the bit 8 (0x100) is set, the lower 8 bits are used
 		  as the "fixed" codec slots; i.e. the driver probes the
@@ -925,6 +926,11 @@
 	    (Usually SD_LPIB register is more accurate than the
 	    position buffer.)
 
+	    position_fix=3 is specific to VIA devices.  The position
+	    of the capture stream is checked from both LPIB and POSBUF
+	    values.  position_fix=4 is a combination mode, using LPIB
+	    for playback and POSBUF for capture.
+
     NB: If you get many "azx_get_response timeout" messages at
     loading, it's likely a problem of interrupts (e.g. ACPI irq
     routing).  Try to boot with options like "pci=noacpi".  Also, you
@@ -2038,7 +2044,7 @@
     Install the necessary firmware files in alsa-firmware package.
     When no hotplug fw loader is available, you need to load the
     firmware via vxloader utility in alsa-tools package.  To invoke
-    vxloader automatically, add the following to /etc/modprobe.conf
+    vxloader automatically, add the following to /etc/modprobe.d/alsa.conf
 
 	install snd-vx222 /sbin/modprobe --first-time -i snd-vx222 && /usr/bin/vxloader
 
@@ -2162,10 +2168,10 @@
 as the same card module.
 
 An example configuration for a single emu10k1 card is like below:
------ /etc/modprobe.conf
+----- /etc/modprobe.d/alsa.conf
 alias snd-card-0 snd-emu10k1
 alias sound-slot-0 snd-emu10k1
------ /etc/modprobe.conf
+----- /etc/modprobe.d/alsa.conf
 
 The available number of auto-loaded sound cards depends on the module
 option "cards_limit" of snd module.  As default it's set to 1.
@@ -2178,7 +2184,7 @@
 
 An example configuration for two sound cards is like below:
 
------ /etc/modprobe.conf
+----- /etc/modprobe.d/alsa.conf
 # ALSA portion
 options snd cards_limit=2
 alias snd-card-0 snd-interwave
@@ -2188,7 +2194,7 @@
 # OSS/Free portion
 alias sound-slot-0 snd-interwave
 alias sound-slot-1 snd-ens1371
------ /etc/modprobe.conf
+----- /etc/modprobe.d/alsa.conf
 
 In this example, the interwave card is always loaded as the first card
 (index 0) and ens1371 as the second (index 1).
diff --git a/Documentation/sound/alsa/Audiophile-Usb.txt b/Documentation/sound/alsa/Audiophile-Usb.txt
index a4c53d8..654dd3b 100644
--- a/Documentation/sound/alsa/Audiophile-Usb.txt
+++ b/Documentation/sound/alsa/Audiophile-Usb.txt
@@ -232,7 +232,7 @@
    # modprobe snd-usb-audio index=1 device_setup=0x09
 
  * Or while configuring the modules options in your modules configuration file
-   - For Fedora distributions, edit the /etc/modprobe.conf file:
+   (tipically a .conf file in /etc/modprobe.d/ directory:
        alias snd-card-1 snd-usb-audio
        options snd-usb-audio index=1 device_setup=0x09
 
@@ -253,7 +253,7 @@
    - first turn off the device
    - de-register the snd-usb-audio module (modprobe -r)
    - change the device_setup parameter by changing the device_setup
-     option in /etc/modprobe.conf 
+     option in /etc/modprobe.d/*.conf
    - turn on the device
  * A workaround for this last issue has been applied to kernel 2.6.23, but it may not
    be enough to ensure the 'stability' of the device initialization.
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index c8c5454..d97d992 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -8,37 +8,10 @@
   5stack-digout	5-jack in back, 2-jack in front, a SPDIF out
   6stack	6-jack in back, 2-jack in front
   6stack-digout	6-jack with a SPDIF out
-  w810		3-jack
-  z71v		3-jack (HP shared SPDIF)
-  asus		3-jack (ASUS Mobo)
-  asus-w1v	ASUS W1V
-  asus-dig	ASUS with SPDIF out
-  asus-dig2	ASUS with SPDIF out (using GPIO2)
-  uniwill	3-jack
-  fujitsu	Fujitsu Laptops (Pi1536)
-  F1734		2-jack
-  lg		LG laptop (m1 express dual)
-  lg-lw		LG LW20/LW25 laptop
-  tcl		TCL S700
-  clevo		Clevo laptops (m520G, m665n)
-  medion	Medion Rim 2150
-  test		for testing/debugging purpose, almost all controls can be
-		adjusted.  Appearing only when compiled with
-		$CONFIG_SND_DEBUG=y
-  auto		auto-config reading BIOS (default)
 
 ALC260
 ======
-  fujitsu	Fujitsu S7020
-  acer		Acer TravelMate
-  will		Will laptops (PB V7900)
-  replacer	Replacer 672V
-  favorit100	Maxdata Favorit 100XS
-  basic		fixed pin assignment (old default model)
-  test		for testing/debugging purpose, almost all controls can
-		adjusted.  Appearing only when compiled with
-		$CONFIG_SND_DEBUG=y
-  auto		auto-config reading BIOS (default)
+  N/A
 
 ALC262
 ======
@@ -70,55 +43,7 @@
 
 ALC882/883/885/888/889
 ======================
-  3stack-dig	3-jack with SPDIF I/O
-  6stack-dig	6-jack digital with SPDIF I/O
-  arima		Arima W820Di1
-  targa		Targa T8, MSI-1049 T8
-  asus-a7j	ASUS A7J
-  asus-a7m	ASUS A7M
-  macpro	MacPro support
-  mb5		Macbook 5,1
-  macmini3	Macmini 3,1
-  mba21		Macbook Air 2,1
-  mbp3		Macbook Pro rev3
-  imac24	iMac 24'' with jack detection
-  imac91	iMac 9,1
-  w2jc		ASUS W2JC
-  3stack-2ch-dig	3-jack with SPDIF I/O (ALC883)
-  alc883-6stack-dig	6-jack digital with SPDIF I/O (ALC883)
-  3stack-6ch    3-jack 6-channel
-  3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
-  6stack-dig-demo  6-jack digital for Intel demo board
-  acer		Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
-  acer-aspire	Acer Aspire 9810
-  acer-aspire-4930g Acer Aspire 4930G
-  acer-aspire-6530g Acer Aspire 6530G
-  acer-aspire-7730g Acer Aspire 7730G
-  acer-aspire-8930g Acer Aspire 8930G
-  medion	Medion Laptops
-  targa-dig	Targa/MSI
-  targa-2ch-dig	Targa/MSI with 2-channel
-  targa-8ch-dig Targa/MSI with 8-channel (MSI GX620)
-  laptop-eapd   3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
-  lenovo-101e	Lenovo 101E
-  lenovo-nb0763	Lenovo NB0763
-  lenovo-ms7195-dig Lenovo MS7195
-  lenovo-sky	Lenovo Sky
-  haier-w66	Haier W66
-  3stack-hp	HP machines with 3stack (Lucknow, Samba boards)
-  6stack-dell	Dell machines with 6stack (Inspiron 530)
-  mitac		Mitac 8252D
-  clevo-m540r	Clevo M540R (6ch + digital)
-  clevo-m720	Clevo M720 laptop series
-  fujitsu-pi2515 Fujitsu AMILO Pi2515
-  fujitsu-xa3530 Fujitsu AMILO XA3530
-  3stack-6ch-intel Intel DG33* boards
-  intel-alc889a	Intel IbexPeak with ALC889A
-  intel-x58	Intel DX58 with ALC889
-  asus-p5q	ASUS P5Q-EM boards
-  mb31		MacBook 3,1
-  sony-vaio-tt  Sony VAIO TT
-  auto		auto-config reading BIOS (default)
+  N/A
 
 ALC861/660
 ==========
diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt
index 91fee3b..7813c06 100644
--- a/Documentation/sound/alsa/HD-Audio.txt
+++ b/Documentation/sound/alsa/HD-Audio.txt
@@ -59,7 +59,12 @@
 `position_fix=1` means to use LPIB method explicitly.
 `position_fix=2` means to use the position-buffer.
 `position_fix=3` means to use a combination of both methods, needed
-for some VIA and ATI controllers.  0 is the default value for all other
+for some VIA controllers.  The capture stream position is corrected
+by comparing both LPIB and position-buffer values.
+`position_fix=4` is another combination available for all controllers,
+and uses LPIB for the playback and the position-buffer for the capture
+streams.
+0 is the default value for all other
 controllers, the automatic check and fallback to LPIB as described in
 the above.  If you get a problem of repeated sounds, this option might
 help.
diff --git a/Documentation/sound/alsa/MIXART.txt b/Documentation/sound/alsa/MIXART.txt
index ef42c44..4ee35b4 100644
--- a/Documentation/sound/alsa/MIXART.txt
+++ b/Documentation/sound/alsa/MIXART.txt
@@ -76,9 +76,9 @@
  when CONFIG_FW_LOADER is set.  The mixartloader is necessary only
  for older versions or when you build the driver into kernel.]
  
-For loading the firmware automatically after the module is loaded, use
-the post-install command.  For example, add the following entry to
-/etc/modprobe.conf for miXart driver:
+For loading the firmware automatically after the module is loaded, use a
+install command.  For example, add the following entry to
+/etc/modprobe.d/mixart.conf for miXart driver:
 
 	install snd-mixart /sbin/modprobe --first-time -i snd-mixart && \
 			   /usr/bin/mixartloader
diff --git a/Documentation/sound/alsa/OSS-Emulation.txt b/Documentation/sound/alsa/OSS-Emulation.txt
index 022aaeb..152ca2a 100644
--- a/Documentation/sound/alsa/OSS-Emulation.txt
+++ b/Documentation/sound/alsa/OSS-Emulation.txt
@@ -19,7 +19,7 @@
 define these aliases by yourself.
 
 Only necessary step for auto-loading of OSS modules is to define the
-card alias in /etc/modprobe.conf, such as
+card alias in /etc/modprobe.d/alsa.conf, such as
 
 	alias sound-slot-0 snd-emu10k1
 
diff --git a/Documentation/sound/oss/AudioExcelDSP16 b/Documentation/sound/oss/AudioExcelDSP16
index e0dc064..ea8549f 100644
--- a/Documentation/sound/oss/AudioExcelDSP16
+++ b/Documentation/sound/oss/AudioExcelDSP16
@@ -41,7 +41,7 @@
 		(0x300, 0x310, 0x320 or 0x330)
 mpu_irq		MPU-401 irq line (5, 7, 9, 10 or 0)
 
-The /etc/modprobe.conf will have lines like this:
+A configuration file in /etc/modprobe.d/ directory will have lines like this:
 
 options opl3 io=0x388
 options ad1848 io=0x530 irq=11 dma=3
@@ -51,11 +51,11 @@
 ad1848 are the corresponding options for the MSS and OPL3 modules.
 
 Loading MSS and OPL3 needs to pre load the aedsp16 module to set up correctly
-the sound card. Installation dependencies must be written in the modprobe.conf
-file:
+the sound card. Installation dependencies must be written in configuration
+files under /etc/modprobe.d/ directory:
 
-install ad1848 /sbin/modprobe aedsp16 && /sbin/modprobe -i ad1848
-install opl3 /sbin/modprobe aedsp16 && /sbin/modprobe -i opl3
+softdep ad1848 pre: aedsp16
+softdep opl3 pre: aedsp16
 
 Then you must load the sound modules stack in this order:
 sound -> aedsp16 -> [ ad1848, opl3 ]
diff --git a/Documentation/sound/oss/CMI8330 b/Documentation/sound/oss/CMI8330
index 9c439f1..8a5fd16 100644
--- a/Documentation/sound/oss/CMI8330
+++ b/Documentation/sound/oss/CMI8330
@@ -143,11 +143,10 @@
 
 
 
-Alma Chao <elysian@ethereal.torsion.org> suggests the following /etc/modprobe.conf:
+Alma Chao <elysian@ethereal.torsion.org> suggests the following in
+a /etc/modprobe.d/*conf file:
 
 alias sound ad1848
 alias synth0 opl3
 options ad1848 io=0x530 irq=7 dma=0 soundpro=1
 options opl3 io=0x388
-
-	
diff --git a/Documentation/sound/oss/Introduction b/Documentation/sound/oss/Introduction
index 75d967f..42da2d8 100644
--- a/Documentation/sound/oss/Introduction
+++ b/Documentation/sound/oss/Introduction
@@ -167,8 +167,8 @@
 MODPROBE:
 =========
 
-If loading via modprobe, these common files are automatically loaded 
-when requested by modprobe.  For example, my /etc/modprobe.conf contains:
+If loading via modprobe, these common files are automatically loaded when
+requested by modprobe.  For example, my /etc/modprobe.d/oss.conf contains:
 
 alias sound sb 
 options sb io=0x240 irq=9 dma=3 dma16=5 mpu_io=0x300
@@ -228,7 +228,7 @@
 driver, you should do the following:
 
 1.  remove sound modules (detailed above)
-2.  remove the sound modules from /etc/modprobe.conf
+2.  remove the sound modules from /etc/modprobe.d/*.conf
 3.  move the sound modules from /lib/modules/<kernel>/misc
     (for example, I make a /lib/modules/<kernel>/misc/tmp
     directory and copy the sound module files to that 
@@ -265,7 +265,7 @@
     sb.o could be copied (or symlinked) to sb1.o for the
     second SoundBlaster.
 
-2.  Make a second entry in /etc/modprobe.conf, for example,
+2.  Make a second entry in /etc/modprobe.d/*conf, for example,
     sound1 or sb1.  This second entry should refer to the
     new module names for example sb1, and should include
     the I/O, etc. for the second sound card.
@@ -369,7 +369,7 @@
 2)  On the command line when using insmod or in a bash script
     using command line calls to load sound.
 
-3)  In /etc/modprobe.conf when using modprobe.
+3)  In /etc/modprobe.d/*conf when using modprobe.
 
 4)  Via Red Hat's GPL'd /usr/sbin/sndconfig program (text based).
 
diff --git a/Documentation/sound/oss/Opti b/Documentation/sound/oss/Opti
index c15af3c..4cd5d9a 100644
--- a/Documentation/sound/oss/Opti
+++ b/Documentation/sound/oss/Opti
@@ -18,7 +18,7 @@
 If you have another OS installed on your computer it is recommended
 that Linux and the other OS use the same resources.
 
-Also, it is recommended that resources specified in /etc/modprobe.conf
+Also, it is recommended that resources specified in /etc/modprobe.d/*.conf
 and resources specified in /etc/isapnp.conf agree.
 
 Compiling the sound driver
@@ -67,11 +67,7 @@
 
 Using kmod and autoloading the sound driver
 -------------------------------------------
-Comment: as of linux-2.1.90 kmod is replacing kerneld.
-The config file '/etc/modprobe.conf' is used as before.
-
-This is the sound part of my /etc/modprobe.conf file.
-Following that I will explain each line.
+Config files in '/etc/modprobe.d/' are used as below:
 
 alias mixer0 mad16
 alias audio0 mad16
diff --git a/Documentation/sound/oss/PAS16 b/Documentation/sound/oss/PAS16
index 3dca4b7..5c27229ee 100644
--- a/Documentation/sound/oss/PAS16
+++ b/Documentation/sound/oss/PAS16
@@ -128,7 +128,7 @@
   You can then get OPL3 functionality by issuing the command:
   insmod opl3
   In addition, you must either add the following line to 
-  /etc/modprobe.conf:
+  /etc/modprobe.d/*.conf:
   options opl3 io=0x388
   or else add the following line to /etc/lilo.conf:
   opl3=0x388
@@ -158,5 +158,5 @@
 append="pas2=0x388,10,3,-1,0,-1,-1,-1 opl3=0x388"
 
 If sound is built totally modular, the above options may be 
-specified in /etc/modprobe.conf for pas2, sb and opl3
+specified in /etc/modprobe.d/*.conf for pas2, sb and opl3
 respectively. 
diff --git a/Documentation/sound/oss/README.modules b/Documentation/sound/oss/README.modules
index e691d74..cdc0394 100644
--- a/Documentation/sound/oss/README.modules
+++ b/Documentation/sound/oss/README.modules
@@ -26,7 +26,7 @@
 drivers/sound dir. Now one simply configures and makes one's kernel and
 modules in the usual way.
 
- Then, add to your /etc/modprobe.conf something like:
+ Then, add to your /etc/modprobe.d/oss.conf something like:
 
 alias char-major-14-* sb
 install sb /sbin/modprobe -i sb && /sbin/modprobe adlib_card
@@ -36,7 +36,7 @@
  Alternatively, if you have compiled in kernel level ISAPnP support:
 
 alias char-major-14 sb
-post-install sb /sbin/modprobe "-k" "adlib_card"
+softdep sb post: adlib_card
 options adlib_card io=0x388
 
   The effect of this is that the sound driver and all necessary bits and
@@ -66,12 +66,12 @@
  Note that at present there is no way to configure the io, irq and other
 parameters for the modular drivers as one does for the wired drivers.. One
 needs to pass the modules the necessary parameters as arguments, either
-with /etc/modprobe.conf or with command-line args to modprobe, e.g.
+with /etc/modprobe.d/*.conf or with command-line args to modprobe, e.g.
 
 modprobe sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330
 modprobe adlib_card io=0x388
 
- recommend using /etc/modprobe.conf.
+ recommend using /etc/modprobe.d/*.conf.
 
 Persistent DMA Buffers:
 
@@ -89,7 +89,7 @@
 
 To make the sound driver use persistent DMA buffers we need to pass the
 sound.o module a "dmabuf=1" command-line argument. This is normally done
-in /etc/modprobe.conf like so:
+in /etc/modprobe.d/*.conf files like so:
 
 options sound		dmabuf=1
 
diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt
index 312e375..642f844 100644
--- a/Documentation/sysrq.txt
+++ b/Documentation/sysrq.txt
@@ -241,9 +241,8 @@
 
 *  I have more questions, who can I ask?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-And I'll answer any questions about the registration system you got, also
-responding as soon as possible.
- -Crutcher
+Just ask them on the linux-kernel mailing list:
+	linux-kernel@vger.kernel.org
 
 *  Credits
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt
index 817df29..4204eb0 100644
--- a/Documentation/usb/power-management.txt
+++ b/Documentation/usb/power-management.txt
@@ -179,7 +179,8 @@
 
 	modprobe usbcore autosuspend=5
 
-Equivalently, you could add to /etc/modprobe.conf a line saying:
+Equivalently, you could add to a configuration file in /etc/modprobe.d
+a line saying:
 
 	options usbcore autosuspend=5
 
diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885
index 23584d0..f316d18 100644
--- a/Documentation/video4linux/CARDLIST.cx23885
+++ b/Documentation/video4linux/CARDLIST.cx23885
@@ -32,3 +32,4 @@
  31 -> Leadtek Winfast PxDVR3200 H XC4000                  [107d:6f39]
  32 -> MPX-885
  33 -> Mygica X8507                                        [14f1:8502]
+ 34 -> TerraTec Cinergy T PCIe Dual                        [153b:117e]
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index eee18e6..fa4b3f9 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -59,7 +59,7 @@
  58 -> Pinnacle PCTV HD 800i                               [11bd:0051]
  59 -> DViCO FusionHDTV 5 PCI nano                         [18ac:d530]
  60 -> Pinnacle Hybrid PCTV                                [12ab:1788]
- 61 -> Leadtek TV2000 XP Global                            [107d:6f18,107d:6618]
+ 61 -> Leadtek TV2000 XP Global                            [107d:6f18,107d:6618,107d:6619]
  62 -> PowerColor RA330                                    [14f1:ea3d]
  63 -> Geniatech X8000-MT DVBT                             [14f1:8852]
  64 -> DViCO FusionHDTV DVB-T PRO                          [18ac:db30]
@@ -87,3 +87,5 @@
  86 -> TeVii S464 DVB-S/S2                                 [d464:9022]
  87 -> Leadtek WinFast DTV2000 H PLUS                      [107d:6f42]
  88 -> Leadtek WinFast DTV1800 H (XC4000)                  [107d:6f38]
+ 89 -> Leadtek TV2000 XP Global (SC4100)                   [107d:6f36]
+ 90 -> Leadtek TV2000 XP Global (XC4100)                   [107d:6f43]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index e7be3ac..d99262d 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -7,7 +7,7 @@
   6 -> Terratec Cinergy 200 USB                 (em2800)
   7 -> Leadtek Winfast USB II                   (em2800)        [0413:6023]
   8 -> Kworld USB2800                           (em2800)
-  9 -> Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker  (em2820/em2840) [1b80:e302,1b80:e304,2304:0207,2304:021a]
+  9 -> Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker  (em2820/em2840) [1b80:e302,1b80:e304,2304:0207,2304:021a,093b:a003]
  10 -> Hauppauge WinTV HVR 900                  (em2880)        [2040:6500]
  11 -> Terratec Hybrid XS                       (em2880)
  12 -> Kworld PVR TV 2800 RF                    (em2820/em2840)
@@ -61,7 +61,7 @@
  61 -> Pixelview PlayTV Box 4 USB 2.0           (em2820/em2840)
  62 -> Gadmei TVR200                            (em2820/em2840)
  63 -> Kaiomy TVnPC U2                          (em2860)        [eb1a:e303]
- 64 -> Easy Cap Capture DC-60                   (em2860)
+ 64 -> Easy Cap Capture DC-60                   (em2860)        [1b80:e309]
  65 -> IO-DATA GV-MVP/SZ                        (em2820/em2840) [04bb:0515]
  66 -> Empire dual TV                           (em2880)
  67 -> Terratec Grabby                          (em2860)        [0ccd:0096,0ccd:10AF]
@@ -76,7 +76,11 @@
  76 -> KWorld PlusTV 340U or UB435-Q (ATSC)     (em2870)        [1b80:a340]
  77 -> EM2874 Leadership ISDBT                  (em2874)
  78 -> PCTV nanoStick T2 290e                   (em28174)
- 79 -> Terratec Cinergy H5                      (em2884)        [0ccd:10a2,0ccd:10ad]
+ 79 -> Terratec Cinergy H5                      (em2884)        [0ccd:008e,0ccd:00ac,0ccd:10a2,0ccd:10ad]
  80 -> PCTV DVB-S2 Stick (460e)                 (em28174)
  81 -> Hauppauge WinTV HVR 930C                 (em2884)        [2040:1605]
  82 -> Terratec Cinergy HTC Stick               (em2884)        [0ccd:00b2]
+ 83 -> Honestech Vidbox NW03                    (em2860)        [eb1a:5006]
+ 84 -> MaxMedia UB425-TC                        (em2874)        [1b80:e425]
+ 85 -> PCTV QuatroStick (510e)                  (em2884)        [2304:0242]
+ 86 -> PCTV QuatroStick nano (520e)             (em2884)        [2013:0251]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index e7ef38a..34f3b33 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -187,3 +187,4 @@
 186 -> Beholder BeholdTV 501                    [5ace:5010]
 187 -> Beholder BeholdTV 503 FM                 [5ace:5030]
 188 -> Sensoray 811/911                         [6000:0811,6000:0911]
+189 -> Kworld PC150-U                           [17de:a134]
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner
index 6323b7a..c83f6e4 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -78,10 +78,11 @@
 tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
 tuner=79 - Philips PAL/SECAM multi (FM1216 MK5)
 tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough
-tuner=81 - Xceive 4000 tuner
 tuner=81 - Partsnic (Daewoo) PTI-5NF05
 tuner=82 - Philips CU1216L
 tuner=83 - NXP TDA18271
 tuner=84 - Sony BTF-Pxn01Z
 tuner=85 - Philips FQ1236 MK5
 tuner=86 - Tena TNF5337 MFD
+tuner=87 - Xceive 4000 tuner
+tuner=88 - Xceive 5000C tuner
diff --git a/Documentation/video4linux/CQcam.txt b/Documentation/video4linux/CQcam.txt
index 8977e7c..6e680fe 100644
--- a/Documentation/video4linux/CQcam.txt
+++ b/Documentation/video4linux/CQcam.txt
@@ -61,29 +61,19 @@
 2.2 Configuration
 
   The configuration requires module configuration and device
-configuration.  I like kmod or kerneld process with the
-/etc/modprobe.conf file so the modules can automatically load/unload as
-they are used.  The video devices could already exist, be generated
-using MAKEDEV, or need to be created.  The following sections detail
-these procedures.
+configuration.  The following sections detail these procedures.
 
 
 2.1 Module Configuration
 
   Using modules requires a bit of work to install and pass the
-parameters.  Understand that entries in /etc/modprobe.conf of:
+parameters.  Understand that entries in /etc/modprobe.d/*.conf of:
 
    alias parport_lowlevel parport_pc
    options parport_pc io=0x378 irq=none
    alias char-major-81 videodev
    alias char-major-81-0 c-qcam
 
-will cause the kmod/modprobe to do certain things.  If you are
-using kmod, then a request for a 'char-major-81-0' will cause
-the 'c-qcam' module to load.  If you have other video sources with
-modules, you might want to assign the different minor numbers to
-different modules.
-
 2.2 Device Configuration
 
   At this point, we need to ensure that the device files exist.
diff --git a/Documentation/video4linux/Zoran b/Documentation/video4linux/Zoran
index 9ed629d..b5a911f 100644
--- a/Documentation/video4linux/Zoran
+++ b/Documentation/video4linux/Zoran
@@ -255,7 +255,7 @@
 option with X being the card number as given in the previous section.
 To have more than one card, use card=X1[,X2[,X3,[X4[..]]]]
 
-To automate this, add the following to your /etc/modprobe.conf:
+To automate this, add the following to your /etc/modprobe.d/zoran.conf:
 
 options zr36067 card=X1[,X2[,X3[,X4[..]]]]
 alias char-major-81-0 zr36067
diff --git a/Documentation/video4linux/bttv/Modules.conf b/Documentation/video4linux/bttv/Modules.conf
index 753f159..8f258fa 100644
--- a/Documentation/video4linux/bttv/Modules.conf
+++ b/Documentation/video4linux/bttv/Modules.conf
@@ -1,4 +1,4 @@
-# For modern kernels (2.6 or above), this belongs in /etc/modprobe.conf
+# For modern kernels (2.6 or above), this belongs in /etc/modprobe.d/*.conf
 # For for 2.4 kernels or earlier, this belongs in /etc/modules.conf.
 
 # i2c
diff --git a/Documentation/video4linux/fimc.txt b/Documentation/video4linux/fimc.txt
new file mode 100644
index 0000000..eb04970
--- /dev/null
+++ b/Documentation/video4linux/fimc.txt
@@ -0,0 +1,178 @@
+Samsung S5P/EXYNOS4 FIMC driver
+
+Copyright (C) 2012 Samsung Electronics Co., Ltd.
+---------------------------------------------------------------------------
+
+The FIMC (Fully Interactive Mobile Camera) device available in Samsung
+SoC Application Processors is an integrated camera host interface, color
+space converter, image resizer and rotator.  It's also capable of capturing
+data from LCD controller (FIMD) through the SoC internal writeback data
+path.  There are multiple FIMC instances in the SoCs (up to 4), having
+slightly different capabilities, like pixel alignment constraints, rotator
+availability, LCD writeback support, etc. The driver is located at
+drivers/media/video/s5p-fimc directory.
+
+1. Supported SoCs
+=================
+
+S5PC100 (mem-to-mem only), S5PV210, EXYNOS4210
+
+2. Supported features
+=====================
+
+ - camera parallel interface capture (ITU-R.BT601/565);
+ - camera serial interface capture (MIPI-CSI2);
+ - memory-to-memory processing (color space conversion, scaling, mirror
+   and rotation);
+ - dynamic pipeline re-configuration at runtime (re-attachment of any FIMC
+   instance to any parallel video input or any MIPI-CSI front-end);
+ - runtime PM and system wide suspend/resume
+
+Not currently supported:
+ - LCD writeback input
+ - per frame clock gating (mem-to-mem)
+
+3. Files partitioning
+=====================
+
+- media device driver
+  drivers/media/video/s5p-fimc/fimc-mdevice.[ch]
+
+ - camera capture video device driver
+  drivers/media/video/s5p-fimc/fimc-capture.c
+
+ - MIPI-CSI2 receiver subdev
+  drivers/media/video/s5p-fimc/mipi-csis.[ch]
+
+ - video post-processor (mem-to-mem)
+  drivers/media/video/s5p-fimc/fimc-core.c
+
+ - common files
+  drivers/media/video/s5p-fimc/fimc-core.h
+  drivers/media/video/s5p-fimc/fimc-reg.h
+  drivers/media/video/s5p-fimc/regs-fimc.h
+
+4. User space interfaces
+========================
+
+4.1. Media device interface
+
+The driver supports Media Controller API as defined at
+http://http://linuxtv.org/downloads/v4l-dvb-apis/media_common.html
+The media device driver name is "SAMSUNG S5P FIMC".
+
+The purpose of this interface is to allow changing assignment of FIMC instances
+to the SoC peripheral camera input at runtime and optionally to control internal
+connections of the MIPI-CSIS device(s) to the FIMC entities.
+
+The media device interface allows to configure the SoC for capturing image
+data from the sensor through more than one FIMC instance (e.g. for simultaneous
+viewfinder and still capture setup).
+Reconfiguration is done by enabling/disabling media links created by the driver
+during initialization. The internal device topology can be easily discovered
+through media entity and links enumeration.
+
+4.2. Memory-to-memory video node
+
+V4L2 memory-to-memory interface at /dev/video? device node.  This is standalone
+video device, it has no media pads. However please note the mem-to-mem and
+capture video node operation on same FIMC instance is not allowed.  The driver
+detects such cases but the applications should prevent them to avoid an
+undefined behaviour.
+
+4.3. Capture video node
+
+The driver supports V4L2 Video Capture Interface as defined at:
+http://linuxtv.org/downloads/v4l-dvb-apis/devices.html
+
+At the capture and mem-to-mem video nodes only the multi-planar API is
+supported. For more details see:
+http://linuxtv.org/downloads/v4l-dvb-apis/planar-apis.html
+
+4.4. Camera capture subdevs
+
+Each FIMC instance exports a sub-device node (/dev/v4l-subdev?), a sub-device
+node is also created per each available and enabled at the platform level
+MIPI-CSI receiver device (currently up to two).
+
+4.5. sysfs
+
+In order to enable more precise camera pipeline control through the sub-device
+API the driver creates a sysfs entry associated with "s5p-fimc-md" platform
+device. The entry path is: /sys/platform/devices/s5p-fimc-md/subdev_conf_mode.
+
+In typical use case there could be a following capture pipeline configuration:
+sensor subdev -> mipi-csi subdev -> fimc subdev -> video node
+
+When we configure these devices through sub-device API at user space, the
+configuration flow must be from left to right, and the video node is
+configured as last one.
+When we don't use sub-device user space API the whole configuration of all
+devices belonging to the pipeline is done at the video node driver.
+The sysfs entry allows to instruct the capture node driver not to configure
+the sub-devices (format, crop), to avoid resetting the subdevs' configuration
+when the last configuration steps at the video node is performed.
+
+For full sub-device control support (subdevs configured at user space before
+starting streaming):
+# echo "sub-dev" > /sys/platform/devices/s5p-fimc-md/subdev_conf_mode
+
+For V4L2 video node control only (subdevs configured internally by the host
+driver):
+# echo "vid-dev" > /sys/platform/devices/s5p-fimc-md/subdev_conf_mode
+This is a default option.
+
+5. Device mapping to video and subdev device nodes
+==================================================
+
+There are associated two video device nodes with each device instance in
+hardware - video capture and mem-to-mem and additionally a subdev node for
+more precise FIMC capture subsystem control. In addition a separate v4l2
+sub-device node is created per each MIPI-CSIS device.
+
+How to find out which /dev/video? or /dev/v4l-subdev? is assigned to which
+device?
+
+You can either grep through the kernel log to find relevant information, i.e.
+# dmesg | grep -i fimc
+(note that udev, if present, might still have rearranged the video nodes),
+
+or retrieve the information from /dev/media? with help of the media-ctl tool:
+# media-ctl -p
+
+6. Platform support
+===================
+
+The machine code (plat-s5p and arch/arm/mach-*) must select following options
+
+CONFIG_S5P_DEV_FIMC0       mandatory
+CONFIG_S5P_DEV_FIMC1  \
+CONFIG_S5P_DEV_FIMC2  |    optional
+CONFIG_S5P_DEV_FIMC3  |
+CONFIG_S5P_SETUP_FIMC /
+CONFIG_S5P_SETUP_MIPIPHY \
+CONFIG_S5P_DEV_CSIS0     | optional for MIPI-CSI interface
+CONFIG_S5P_DEV_CSIS1     /
+
+Except that, relevant s5p_device_fimc? should be registered in the machine code
+in addition to a "s5p-fimc-md" platform device to which the media device driver
+is bound.  The "s5p-fimc-md" device instance is required even if only mem-to-mem
+operation is used.
+
+The description of sensor(s) attached to FIMC/MIPI-CSIS camera inputs should be
+passed as the "s5p-fimc-md" device platform_data.  The platform data structure
+is defined in file include/media/s5p_fimc.h.
+
+7. Build
+========
+
+This driver depends on following config options:
+PLAT_S5P,
+PM_RUNTIME,
+I2C,
+REGULATOR,
+VIDEO_V4L2_SUBDEV_API,
+
+If the driver is built as a loadable kernel module (CONFIG_VIDEO_SAMSUNG_S5P_FIMC=m)
+two modules are created (in addition to the core v4l2 modules): s5p-fimc.ko and
+optional s5p-csis.ko (MIPI-CSI receiver subdev).
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index f2060f0d..e6c2842 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -217,6 +217,7 @@
 sonixj		06f8:3004	Hercules Classic Silver
 sonixj		06f8:3008	Hercules Deluxe Optical Glass
 pac7302		06f8:3009	Hercules Classic Link
+pac7302		06f8:301b	Hercules Link
 nw80x		0728:d001	AVerMedia Camguard
 spca508		0733:0110	ViewQuest VQ110
 spca501		0733:0401	Intel Create and Share
diff --git a/Documentation/video4linux/meye.txt b/Documentation/video4linux/meye.txt
index 34e2842..a051152 100644
--- a/Documentation/video4linux/meye.txt
+++ b/Documentation/video4linux/meye.txt
@@ -55,7 +55,7 @@
 -----------
 
 In order to automatically load the meye module on use, you can put those lines
-in your /etc/modprobe.conf file:
+in your /etc/modprobe.d/meye.conf file:
 
 	alias char-major-81 videodev
 	alias char-major-81-0 meye
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index e1d94bf..6386f8c 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -95,7 +95,7 @@
 Capability: basic
 Architectures: all
 Type: system ioctl
-Parameters: none
+Parameters: machine type identifier (KVM_VM_*)
 Returns: a VM fd that can be used to control the new virtual machine.
 
 The new VM has no virtual cpus and no memory.  An mmap() of a VM fd
@@ -103,6 +103,11 @@
 corresponds to guest physical address zero.  Use of mmap() on a VM fd
 is discouraged if userspace memory allocation (KVM_CAP_USER_MEMORY) is
 available.
+You most certainly want to use 0 as machine type.
+
+In order to create user controlled virtual machines on S390, check
+KVM_CAP_S390_UCONTROL and use the flag KVM_VM_S390_UCONTROL as
+privileged user (CAP_SYS_ADMIN).
 
 4.3 KVM_GET_MSR_INDEX_LIST
 
@@ -213,6 +218,11 @@
 single-threaded guest vcpus, it should make all vcpu ids be a multiple
 of the number of vcpus per vcore.
 
+For virtual cpus that have been created with S390 user controlled virtual
+machines, the resulting vcpu fd can be memory mapped at page offset
+KVM_S390_SIE_PAGE_OFFSET in order to obtain a memory map of the virtual
+cpu's hardware control block.
+
 4.8 KVM_GET_DIRTY_LOG (vm ioctl)
 
 Capability: basic
@@ -1159,6 +1169,14 @@
 
 /* Depends on KVM_CAP_IOMMU */
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
+/* The following two depend on KVM_CAP_PCI_2_3 */
+#define KVM_DEV_ASSIGN_PCI_2_3		(1 << 1)
+#define KVM_DEV_ASSIGN_MASK_INTX	(1 << 2)
+
+If KVM_DEV_ASSIGN_PCI_2_3 is set, the kernel will manage legacy INTx interrupts
+via the PCI-2.3-compliant device-level mask, thus enable IRQ sharing with other
+assigned devices or host devices. KVM_DEV_ASSIGN_MASK_INTX specifies the
+guest's view on the INTx mask, see KVM_ASSIGN_SET_INTX_MASK for details.
 
 The KVM_DEV_ASSIGN_ENABLE_IOMMU flag is a mandatory option to ensure
 isolation of the device.  Usages not specifying this flag are deprecated.
@@ -1399,6 +1417,71 @@
 If datamatch flag is set, the event will be signaled only if the written value
 to the registered address is equal to datamatch in struct kvm_ioeventfd.
 
+4.59 KVM_DIRTY_TLB
+
+Capability: KVM_CAP_SW_TLB
+Architectures: ppc
+Type: vcpu ioctl
+Parameters: struct kvm_dirty_tlb (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_dirty_tlb {
+	__u64 bitmap;
+	__u32 num_dirty;
+};
+
+This must be called whenever userspace has changed an entry in the shared
+TLB, prior to calling KVM_RUN on the associated vcpu.
+
+The "bitmap" field is the userspace address of an array.  This array
+consists of a number of bits, equal to the total number of TLB entries as
+determined by the last successful call to KVM_CONFIG_TLB, rounded up to the
+nearest multiple of 64.
+
+Each bit corresponds to one TLB entry, ordered the same as in the shared TLB
+array.
+
+The array is little-endian: the bit 0 is the least significant bit of the
+first byte, bit 8 is the least significant bit of the second byte, etc.
+This avoids any complications with differing word sizes.
+
+The "num_dirty" field is a performance hint for KVM to determine whether it
+should skip processing the bitmap and just invalidate everything.  It must
+be set to the number of set bits in the bitmap.
+
+4.60 KVM_ASSIGN_SET_INTX_MASK
+
+Capability: KVM_CAP_PCI_2_3
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_assigned_pci_dev (in)
+Returns: 0 on success, -1 on error
+
+Allows userspace to mask PCI INTx interrupts from the assigned device.  The
+kernel will not deliver INTx interrupts to the guest between setting and
+clearing of KVM_ASSIGN_SET_INTX_MASK via this interface.  This enables use of
+and emulation of PCI 2.3 INTx disable command register behavior.
+
+This may be used for both PCI 2.3 devices supporting INTx disable natively and
+older devices lacking this support. Userspace is responsible for emulating the
+read value of the INTx disable bit in the guest visible PCI command register.
+When modifying the INTx disable state, userspace should precede updating the
+physical device command register by calling this ioctl to inform the kernel of
+the new intended INTx mask state.
+
+Note that the kernel uses the device INTx disable bit to internally manage the
+device interrupt state for PCI 2.3 devices.  Reads of this register may
+therefore not match the expected value.  Writes should always use the guest
+intended INTx disable value rather than attempting to read-copy-update the
+current physical device state.  Races between user and kernel updates to the
+INTx disable bit are handled lazily in the kernel.  It's possible the device
+may generate unintended interrupts, but they will not be injected into the
+guest.
+
+See KVM_ASSIGN_DEV_IRQ for the data structure.  The target device is specified
+by assigned_dev_id.  In the flags field, only KVM_DEV_ASSIGN_MASK_INTX is
+evaluated.
+
 4.62 KVM_CREATE_SPAPR_TCE
 
 Capability: KVM_CAP_SPAPR_TCE
@@ -1491,6 +1574,101 @@
 Some guests configure the LINT1 NMI input to cause a panic, aiding in
 debugging.
 
+4.65 KVM_S390_UCAS_MAP
+
+Capability: KVM_CAP_S390_UCONTROL
+Architectures: s390
+Type: vcpu ioctl
+Parameters: struct kvm_s390_ucas_mapping (in)
+Returns: 0 in case of success
+
+The parameter is defined like this:
+	struct kvm_s390_ucas_mapping {
+		__u64 user_addr;
+		__u64 vcpu_addr;
+		__u64 length;
+	};
+
+This ioctl maps the memory at "user_addr" with the length "length" to
+the vcpu's address space starting at "vcpu_addr". All parameters need to
+be alligned by 1 megabyte.
+
+4.66 KVM_S390_UCAS_UNMAP
+
+Capability: KVM_CAP_S390_UCONTROL
+Architectures: s390
+Type: vcpu ioctl
+Parameters: struct kvm_s390_ucas_mapping (in)
+Returns: 0 in case of success
+
+The parameter is defined like this:
+	struct kvm_s390_ucas_mapping {
+		__u64 user_addr;
+		__u64 vcpu_addr;
+		__u64 length;
+	};
+
+This ioctl unmaps the memory in the vcpu's address space starting at
+"vcpu_addr" with the length "length". The field "user_addr" is ignored.
+All parameters need to be alligned by 1 megabyte.
+
+4.67 KVM_S390_VCPU_FAULT
+
+Capability: KVM_CAP_S390_UCONTROL
+Architectures: s390
+Type: vcpu ioctl
+Parameters: vcpu absolute address (in)
+Returns: 0 in case of success
+
+This call creates a page table entry on the virtual cpu's address space
+(for user controlled virtual machines) or the virtual machine's address
+space (for regular virtual machines). This only works for minor faults,
+thus it's recommended to access subject memory page via the user page
+table upfront. This is useful to handle validity intercepts for user
+controlled virtual machines to fault in the virtual cpu's lowcore pages
+prior to calling the KVM_RUN ioctl.
+
+4.68 KVM_SET_ONE_REG
+
+Capability: KVM_CAP_ONE_REG
+Architectures: all
+Type: vcpu ioctl
+Parameters: struct kvm_one_reg (in)
+Returns: 0 on success, negative value on failure
+
+struct kvm_one_reg {
+       __u64 id;
+       __u64 addr;
+};
+
+Using this ioctl, a single vcpu register can be set to a specific value
+defined by user space with the passed in struct kvm_one_reg, where id
+refers to the register identifier as described below and addr is a pointer
+to a variable with the respective size. There can be architecture agnostic
+and architecture specific registers. Each have their own range of operation
+and their own constants and width. To keep track of the implemented
+registers, find a list below:
+
+  Arch  |       Register        | Width (bits)
+        |                       |
+  PPC   | KVM_REG_PPC_HIOR      | 64
+
+4.69 KVM_GET_ONE_REG
+
+Capability: KVM_CAP_ONE_REG
+Architectures: all
+Type: vcpu ioctl
+Parameters: struct kvm_one_reg (in and out)
+Returns: 0 on success, negative value on failure
+
+This ioctl allows to receive the value of a single register implemented
+in a vcpu. The register to read is indicated by the "id" field of the
+kvm_one_reg struct passed in. On success, the register value can be found
+at the memory location pointed to by "addr".
+
+The list of registers accessible using this interface is identical to the
+list in 4.64.
+
 5. The kvm_run structure
 
 Application code obtains a pointer to the kvm_run structure by
@@ -1651,6 +1829,20 @@
 
 s390 specific.
 
+		/* KVM_EXIT_S390_UCONTROL */
+		struct {
+			__u64 trans_exc_code;
+			__u32 pgm_code;
+		} s390_ucontrol;
+
+s390 specific. A page fault has occurred for a user controlled virtual
+machine (KVM_VM_S390_UNCONTROL) on it's host page table that cannot be
+resolved by the kernel.
+The program code and the translation exception code that were placed
+in the cpu's lowcore are presented here as defined by the z Architecture
+Principles of Operation Book in the Chapter for Dynamic Address Translation
+(DAT)
+
 		/* KVM_EXIT_DCR */
 		struct {
 			__u32 dcrn;
@@ -1693,6 +1885,29 @@
 		/* Fix the size of the union. */
 		char padding[256];
 	};
+
+	/*
+	 * shared registers between kvm and userspace.
+	 * kvm_valid_regs specifies the register classes set by the host
+	 * kvm_dirty_regs specified the register classes dirtied by userspace
+	 * struct kvm_sync_regs is architecture specific, as well as the
+	 * bits for kvm_valid_regs and kvm_dirty_regs
+	 */
+	__u64 kvm_valid_regs;
+	__u64 kvm_dirty_regs;
+	union {
+		struct kvm_sync_regs regs;
+		char padding[1024];
+	} s;
+
+If KVM_CAP_SYNC_REGS is defined, these fields allow userspace to access
+certain guest registers without having to call SET/GET_*REGS. Thus we can
+avoid some system call overhead if userspace has to handle the exit.
+Userspace can query the validity of the structure by checking
+kvm_valid_regs for specific bits. These bits are architecture specific
+and usually define the validity of a groups of registers. (e.g. one bit
+ for general purpose registers)
+
 };
 
 6. Capabilities that can be enabled
@@ -1741,3 +1956,45 @@
 HTAB invisible to the guest.
 
 When this capability is enabled, KVM_EXIT_PAPR_HCALL can occur.
+
+6.3 KVM_CAP_SW_TLB
+
+Architectures: ppc
+Parameters: args[0] is the address of a struct kvm_config_tlb
+Returns: 0 on success; -1 on error
+
+struct kvm_config_tlb {
+	__u64 params;
+	__u64 array;
+	__u32 mmu_type;
+	__u32 array_len;
+};
+
+Configures the virtual CPU's TLB array, establishing a shared memory area
+between userspace and KVM.  The "params" and "array" fields are userspace
+addresses of mmu-type-specific data structures.  The "array_len" field is an
+safety mechanism, and should be set to the size in bytes of the memory that
+userspace has reserved for the array.  It must be at least the size dictated
+by "mmu_type" and "params".
+
+While KVM_RUN is active, the shared region is under control of KVM.  Its
+contents are undefined, and any modification by userspace results in
+boundedly undefined behavior.
+
+On return from KVM_RUN, the shared region will reflect the current state of
+the guest's TLB.  If userspace makes any changes, it must call KVM_DIRTY_TLB
+to tell KVM which entries have been changed, prior to calling KVM_RUN again
+on this vcpu.
+
+For mmu types KVM_MMU_FSL_BOOKE_NOHV and KVM_MMU_FSL_BOOKE_HV:
+ - The "params" field is of type "struct kvm_book3e_206_tlb_params".
+ - The "array" field points to an array of type "struct
+   kvm_book3e_206_tlb_entry".
+ - The array consists of all entries in the first TLB, followed by all
+   entries in the second TLB.
+ - Within a TLB, entries are ordered first by increasing set number.  Within a
+   set, entries are ordered by way (increasing ESEL).
+ - The hash for determining set number in TLB0 is: (MAS2 >> 12) & (num_sets - 1)
+   where "num_sets" is the tlb_sizes[] value divided by the tlb_ways[] value.
+ - The tsize field of mas1 shall be set to 4K on TLB0, even though the
+   hardware ignores this value for TLB0.
diff --git a/Documentation/virtual/kvm/ppc-pv.txt b/Documentation/virtual/kvm/ppc-pv.txt
index 2b7ce19..6e7c370 100644
--- a/Documentation/virtual/kvm/ppc-pv.txt
+++ b/Documentation/virtual/kvm/ppc-pv.txt
@@ -81,28 +81,8 @@
 also define a new hypercall feature to indicate that the host can give you more
 registers. Only if the host supports the additional features, make use of them.
 
-The magic page has the following layout as described in
-arch/powerpc/include/asm/kvm_para.h:
-
-struct kvm_vcpu_arch_shared {
-	__u64 scratch1;
-	__u64 scratch2;
-	__u64 scratch3;
-	__u64 critical;		/* Guest may not get interrupts if == r1 */
-	__u64 sprg0;
-	__u64 sprg1;
-	__u64 sprg2;
-	__u64 sprg3;
-	__u64 srr0;
-	__u64 srr1;
-	__u64 dar;
-	__u64 msr;
-	__u32 dsisr;
-	__u32 int_pending;	/* Tells the guest if we have an interrupt */
-};
-
-Additions to the page must only occur at the end. Struct fields are always 32
-or 64 bit aligned, depending on them being 32 or 64 bit wide respectively.
+The magic page layout is described by struct kvm_vcpu_arch_shared
+in arch/powerpc/include/asm/kvm_para.h.
 
 Magic page features
 ===================
diff --git a/Documentation/vm/Makefile b/Documentation/vm/Makefile
deleted file mode 100644
index 3fa4d06..0000000
--- a/Documentation/vm/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# kbuild trick to avoid linker error. Can be omitted if a module is built.
-obj- := dummy.o
-
-# List of programs to build
-hostprogs-y := page-types hugepage-mmap hugepage-shm map_hugetlb
-
-# Tell kbuild to always build the programs
-always := $(hostprogs-y)
diff --git a/Documentation/vm/cleancache.txt b/Documentation/vm/cleancache.txt
index d5c615a..142fbb0 100644
--- a/Documentation/vm/cleancache.txt
+++ b/Documentation/vm/cleancache.txt
@@ -46,10 +46,11 @@
 the pool id, a file key, and a page index into the file.  (The combination
 of a pool id, a file key, and an index is sometimes called a "handle".)
 A "get_page" will copy the page, if found, from cleancache into kernel memory.
-A "flush_page" will ensure the page no longer is present in cleancache;
-a "flush_inode" will flush all pages associated with the specified file;
-and, when a filesystem is unmounted, a "flush_fs" will flush all pages in
-all files specified by the given pool id and also surrender the pool id.
+An "invalidate_page" will ensure the page no longer is present in cleancache;
+an "invalidate_inode" will invalidate all pages associated with the specified
+file; and, when a filesystem is unmounted, an "invalidate_fs" will invalidate
+all pages in all files specified by the given pool id and also surrender
+the pool id.
 
 An "init_shared_fs", like init_fs, obtains a pool id but tells cleancache
 to treat the pool as shared using a 128-bit UUID as a key.  On systems
@@ -62,12 +63,12 @@
 cleancache implementation can simply disable shared_init by always
 returning a negative value.
 
-If a get_page is successful on a non-shared pool, the page is flushed (thus
-making cleancache an "exclusive" cache).  On a shared pool, the page
-is NOT flushed on a successful get_page so that it remains accessible to
+If a get_page is successful on a non-shared pool, the page is invalidated
+(thus making cleancache an "exclusive" cache).  On a shared pool, the page
+is NOT invalidated on a successful get_page so that it remains accessible to
 other sharers.  The kernel is responsible for ensuring coherency between
 cleancache (shared or not), the page cache, and the filesystem, using
-cleancache flush operations as required.
+cleancache invalidate operations as required.
 
 Note that cleancache must enforce put-put-get coherency and get-get
 coherency.  For the former, if two puts are made to the same handle but
@@ -77,20 +78,20 @@
 never succeed unless preceded by a successful put with that handle.
 
 Last, cleancache provides no SMP serialization guarantees; if two
-different Linux threads are simultaneously putting and flushing a page
+different Linux threads are simultaneously putting and invalidating a page
 with the same handle, the results are indeterminate.  Callers must
 lock the page to ensure serial behavior.
 
 CLEANCACHE PERFORMANCE METRICS
 
-Cleancache monitoring is done by sysfs files in the
-/sys/kernel/mm/cleancache directory.  The effectiveness of cleancache
+If properly configured, monitoring of cleancache is done via debugfs in
+the /sys/kernel/debug/mm/cleancache directory.  The effectiveness of cleancache
 can be measured (across all filesystems) with:
 
 succ_gets	- number of gets that were successful
 failed_gets	- number of gets that failed
 puts		- number of puts attempted (all "succeed")
-flushes		- number of flushes attempted
+invalidates	- number of invalidates attempted
 
 A backend implementation may provide additional metrics.
 
@@ -143,7 +144,7 @@
 
 The core hooks for cleancache in VFS are in most cases a single line
 and the minimum set are placed precisely where needed to maintain
-coherency (via cleancache_flush operations) between cleancache,
+coherency (via cleancache_invalidate operations) between cleancache,
 the page cache, and disk.  All hooks compile into nothingness if
 cleancache is config'ed off and turn into a function-pointer-
 compare-to-NULL if config'ed on but no backend claims the ops
@@ -184,15 +185,15 @@
 transcendent memory.
 
 4) Why is non-shared cleancache "exclusive"?  And where is the
-   page "flushed" after a "get"? (Minchan Kim)
+   page "invalidated" after a "get"? (Minchan Kim)
 
 The main reason is to free up space in transcendent memory and
-to avoid unnecessary cleancache_flush calls.  If you want inclusive,
+to avoid unnecessary cleancache_invalidate calls.  If you want inclusive,
 the page can be "put" immediately following the "get".  If
 put-after-get for inclusive becomes common, the interface could
-be easily extended to add a "get_no_flush" call.
+be easily extended to add a "get_no_invalidate" call.
 
-The flush is done by the cleancache backend implementation.
+The invalidate is done by the cleancache backend implementation.
 
 5) What's the performance impact?
 
@@ -222,7 +223,7 @@
   as tmpfs should not enable cleancache)
 - To ensure coherency/correctness, the FS must ensure that all
   file removal or truncation operations either go through VFS or
-  add hooks to do the equivalent cleancache "flush" operations
+  add hooks to do the equivalent cleancache "invalidate" operations
 - To ensure coherency/correctness, either inode numbers must
   be unique across the lifetime of the on-disk file OR the
   FS must provide an "encode_fh" function.
@@ -243,11 +244,11 @@
 inode/filehandle, the pool id could be eliminated.  But, this
 won't work because cleancache retains pagecache data pages
 persistently even when the inode has been pruned from the
-inode unused list, and only flushes the data page if the file
+inode unused list, and only invalidates the data page if the file
 gets removed/truncated.  So if cleancache used the inode kva,
 there would be potential coherency issues if/when the inode
 kva is reused for a different file.  Alternately, if cleancache
-flushed the pages when the inode kva was freed, much of the value
+invalidated the pages when the inode kva was freed, much of the value
 of cleancache would be lost because the cache of pages in cleanache
 is potentially much larger than the kernel pagecache and is most
 useful if the pages survive inode cache removal.
diff --git a/Documentation/vm/hugepage-mmap.c b/Documentation/vm/hugepage-mmap.c
deleted file mode 100644
index db0dd9a..0000000
--- a/Documentation/vm/hugepage-mmap.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * hugepage-mmap:
- *
- * Example of using huge page memory in a user application using the mmap
- * system call.  Before running this application, make sure that the
- * administrator has mounted the hugetlbfs filesystem (on some directory
- * like /mnt) using the command mount -t hugetlbfs nodev /mnt. In this
- * example, the app is requesting memory of size 256MB that is backed by
- * huge pages.
- *
- * For the ia64 architecture, the Linux kernel reserves Region number 4 for
- * huge pages.  That means that if one requires a fixed address, a huge page
- * aligned address starting with 0x800000... will be required.  If a fixed
- * address is not required, the kernel will select an address in the proper
- * range.
- * Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-
-#define FILE_NAME "/mnt/hugepagefile"
-#define LENGTH (256UL*1024*1024)
-#define PROTECTION (PROT_READ | PROT_WRITE)
-
-/* Only ia64 requires this */
-#ifdef __ia64__
-#define ADDR (void *)(0x8000000000000000UL)
-#define FLAGS (MAP_SHARED | MAP_FIXED)
-#else
-#define ADDR (void *)(0x0UL)
-#define FLAGS (MAP_SHARED)
-#endif
-
-static void check_bytes(char *addr)
-{
-	printf("First hex is %x\n", *((unsigned int *)addr));
-}
-
-static void write_bytes(char *addr)
-{
-	unsigned long i;
-
-	for (i = 0; i < LENGTH; i++)
-		*(addr + i) = (char)i;
-}
-
-static void read_bytes(char *addr)
-{
-	unsigned long i;
-
-	check_bytes(addr);
-	for (i = 0; i < LENGTH; i++)
-		if (*(addr + i) != (char)i) {
-			printf("Mismatch at %lu\n", i);
-			break;
-		}
-}
-
-int main(void)
-{
-	void *addr;
-	int fd;
-
-	fd = open(FILE_NAME, O_CREAT | O_RDWR, 0755);
-	if (fd < 0) {
-		perror("Open failed");
-		exit(1);
-	}
-
-	addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, fd, 0);
-	if (addr == MAP_FAILED) {
-		perror("mmap");
-		unlink(FILE_NAME);
-		exit(1);
-	}
-
-	printf("Returned address is %p\n", addr);
-	check_bytes(addr);
-	write_bytes(addr);
-	read_bytes(addr);
-
-	munmap(addr, LENGTH);
-	close(fd);
-	unlink(FILE_NAME);
-
-	return 0;
-}
diff --git a/Documentation/vm/hugepage-shm.c b/Documentation/vm/hugepage-shm.c
deleted file mode 100644
index 07956d8..0000000
--- a/Documentation/vm/hugepage-shm.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * hugepage-shm:
- *
- * Example of using huge page memory in a user application using Sys V shared
- * memory system calls.  In this example the app is requesting 256MB of
- * memory that is backed by huge pages.  The application uses the flag
- * SHM_HUGETLB in the shmget system call to inform the kernel that it is
- * requesting huge pages.
- *
- * For the ia64 architecture, the Linux kernel reserves Region number 4 for
- * huge pages.  That means that if one requires a fixed address, a huge page
- * aligned address starting with 0x800000... will be required.  If a fixed
- * address is not required, the kernel will select an address in the proper
- * range.
- * Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
- *
- * Note: The default shared memory limit is quite low on many kernels,
- * you may need to increase it via:
- *
- * echo 268435456 > /proc/sys/kernel/shmmax
- *
- * This will increase the maximum size per shared memory segment to 256MB.
- * The other limit that you will hit eventually is shmall which is the
- * total amount of shared memory in pages. To set it to 16GB on a system
- * with a 4kB pagesize do:
- *
- * echo 4194304 > /proc/sys/kernel/shmall
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <sys/mman.h>
-
-#ifndef SHM_HUGETLB
-#define SHM_HUGETLB 04000
-#endif
-
-#define LENGTH (256UL*1024*1024)
-
-#define dprintf(x)  printf(x)
-
-/* Only ia64 requires this */
-#ifdef __ia64__
-#define ADDR (void *)(0x8000000000000000UL)
-#define SHMAT_FLAGS (SHM_RND)
-#else
-#define ADDR (void *)(0x0UL)
-#define SHMAT_FLAGS (0)
-#endif
-
-int main(void)
-{
-	int shmid;
-	unsigned long i;
-	char *shmaddr;
-
-	if ((shmid = shmget(2, LENGTH,
-			    SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W)) < 0) {
-		perror("shmget");
-		exit(1);
-	}
-	printf("shmid: 0x%x\n", shmid);
-
-	shmaddr = shmat(shmid, ADDR, SHMAT_FLAGS);
-	if (shmaddr == (char *)-1) {
-		perror("Shared memory attach failure");
-		shmctl(shmid, IPC_RMID, NULL);
-		exit(2);
-	}
-	printf("shmaddr: %p\n", shmaddr);
-
-	dprintf("Starting the writes:\n");
-	for (i = 0; i < LENGTH; i++) {
-		shmaddr[i] = (char)(i);
-		if (!(i % (1024 * 1024)))
-			dprintf(".");
-	}
-	dprintf("\n");
-
-	dprintf("Starting the Check...");
-	for (i = 0; i < LENGTH; i++)
-		if (shmaddr[i] != (char)i)
-			printf("\nIndex %lu mismatched\n", i);
-	dprintf("Done.\n");
-
-	if (shmdt((const void *)shmaddr) != 0) {
-		perror("Detach failure");
-		shmctl(shmid, IPC_RMID, NULL);
-		exit(3);
-	}
-
-	shmctl(shmid, IPC_RMID, NULL);
-
-	return 0;
-}
diff --git a/Documentation/vm/map_hugetlb.c b/Documentation/vm/map_hugetlb.c
deleted file mode 100644
index eda1a6d..0000000
--- a/Documentation/vm/map_hugetlb.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Example of using hugepage memory in a user application using the mmap
- * system call with MAP_HUGETLB flag.  Before running this program make
- * sure the administrator has allocated enough default sized huge pages
- * to cover the 256 MB allocation.
- *
- * For ia64 architecture, Linux kernel reserves Region number 4 for hugepages.
- * That means the addresses starting with 0x800000... will need to be
- * specified.  Specifying a fixed address is not required on ppc64, i386
- * or x86_64.
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-
-#define LENGTH (256UL*1024*1024)
-#define PROTECTION (PROT_READ | PROT_WRITE)
-
-#ifndef MAP_HUGETLB
-#define MAP_HUGETLB 0x40000 /* arch specific */
-#endif
-
-/* Only ia64 requires this */
-#ifdef __ia64__
-#define ADDR (void *)(0x8000000000000000UL)
-#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_FIXED)
-#else
-#define ADDR (void *)(0x0UL)
-#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
-#endif
-
-static void check_bytes(char *addr)
-{
-	printf("First hex is %x\n", *((unsigned int *)addr));
-}
-
-static void write_bytes(char *addr)
-{
-	unsigned long i;
-
-	for (i = 0; i < LENGTH; i++)
-		*(addr + i) = (char)i;
-}
-
-static void read_bytes(char *addr)
-{
-	unsigned long i;
-
-	check_bytes(addr);
-	for (i = 0; i < LENGTH; i++)
-		if (*(addr + i) != (char)i) {
-			printf("Mismatch at %lu\n", i);
-			break;
-		}
-}
-
-int main(void)
-{
-	void *addr;
-
-	addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, 0, 0);
-	if (addr == MAP_FAILED) {
-		perror("mmap");
-		exit(1);
-	}
-
-	printf("Returned address is %p\n", addr);
-	check_bytes(addr);
-	write_bytes(addr);
-	read_bytes(addr);
-
-	munmap(addr, LENGTH);
-
-	return 0;
-}
diff --git a/Documentation/vm/page-types.c b/Documentation/vm/page-types.c
deleted file mode 100644
index 7445caa..0000000
--- a/Documentation/vm/page-types.c
+++ /dev/null
@@ -1,1100 +0,0 @@
-/*
- * page-types: Tool for querying page flags
- *
- * 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 in the hope that it will be useful, but WITHOUT
- * 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 find a copy of v2 of the GNU General Public License somewhere on
- * your Linux system; if not, write to the Free Software Foundation, Inc., 59
- * Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * Copyright (C) 2009 Intel corporation
- *
- * Authors: Wu Fengguang <fengguang.wu@intel.com>
- */
-
-#define _LARGEFILE64_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <stdarg.h>
-#include <string.h>
-#include <getopt.h>
-#include <limits.h>
-#include <assert.h>
-#include <sys/types.h>
-#include <sys/errno.h>
-#include <sys/fcntl.h>
-#include <sys/mount.h>
-#include <sys/statfs.h>
-#include "../../include/linux/magic.h"
-
-
-#ifndef MAX_PATH
-# define MAX_PATH 256
-#endif
-
-#ifndef STR
-# define _STR(x) #x
-# define STR(x) _STR(x)
-#endif
-
-/*
- * pagemap kernel ABI bits
- */
-
-#define PM_ENTRY_BYTES      sizeof(uint64_t)
-#define PM_STATUS_BITS      3
-#define PM_STATUS_OFFSET    (64 - PM_STATUS_BITS)
-#define PM_STATUS_MASK      (((1LL << PM_STATUS_BITS) - 1) << PM_STATUS_OFFSET)
-#define PM_STATUS(nr)       (((nr) << PM_STATUS_OFFSET) & PM_STATUS_MASK)
-#define PM_PSHIFT_BITS      6
-#define PM_PSHIFT_OFFSET    (PM_STATUS_OFFSET - PM_PSHIFT_BITS)
-#define PM_PSHIFT_MASK      (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET)
-#define PM_PSHIFT(x)        (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK)
-#define PM_PFRAME_MASK      ((1LL << PM_PSHIFT_OFFSET) - 1)
-#define PM_PFRAME(x)        ((x) & PM_PFRAME_MASK)
-
-#define PM_PRESENT          PM_STATUS(4LL)
-#define PM_SWAP             PM_STATUS(2LL)
-
-
-/*
- * kernel page flags
- */
-
-#define KPF_BYTES		8
-#define PROC_KPAGEFLAGS		"/proc/kpageflags"
-
-/* copied from kpageflags_read() */
-#define KPF_LOCKED		0
-#define KPF_ERROR		1
-#define KPF_REFERENCED		2
-#define KPF_UPTODATE		3
-#define KPF_DIRTY		4
-#define KPF_LRU			5
-#define KPF_ACTIVE		6
-#define KPF_SLAB		7
-#define KPF_WRITEBACK		8
-#define KPF_RECLAIM		9
-#define KPF_BUDDY		10
-
-/* [11-20] new additions in 2.6.31 */
-#define KPF_MMAP		11
-#define KPF_ANON		12
-#define KPF_SWAPCACHE		13
-#define KPF_SWAPBACKED		14
-#define KPF_COMPOUND_HEAD	15
-#define KPF_COMPOUND_TAIL	16
-#define KPF_HUGE		17
-#define KPF_UNEVICTABLE		18
-#define KPF_HWPOISON		19
-#define KPF_NOPAGE		20
-#define KPF_KSM			21
-
-/* [32-] kernel hacking assistances */
-#define KPF_RESERVED		32
-#define KPF_MLOCKED		33
-#define KPF_MAPPEDTODISK	34
-#define KPF_PRIVATE		35
-#define KPF_PRIVATE_2		36
-#define KPF_OWNER_PRIVATE	37
-#define KPF_ARCH		38
-#define KPF_UNCACHED		39
-
-/* [48-] take some arbitrary free slots for expanding overloaded flags
- * not part of kernel API
- */
-#define KPF_READAHEAD		48
-#define KPF_SLOB_FREE		49
-#define KPF_SLUB_FROZEN		50
-#define KPF_SLUB_DEBUG		51
-
-#define KPF_ALL_BITS		((uint64_t)~0ULL)
-#define KPF_HACKERS_BITS	(0xffffULL << 32)
-#define KPF_OVERLOADED_BITS	(0xffffULL << 48)
-#define BIT(name)		(1ULL << KPF_##name)
-#define BITS_COMPOUND		(BIT(COMPOUND_HEAD) | BIT(COMPOUND_TAIL))
-
-static const char *page_flag_names[] = {
-	[KPF_LOCKED]		= "L:locked",
-	[KPF_ERROR]		= "E:error",
-	[KPF_REFERENCED]	= "R:referenced",
-	[KPF_UPTODATE]		= "U:uptodate",
-	[KPF_DIRTY]		= "D:dirty",
-	[KPF_LRU]		= "l:lru",
-	[KPF_ACTIVE]		= "A:active",
-	[KPF_SLAB]		= "S:slab",
-	[KPF_WRITEBACK]		= "W:writeback",
-	[KPF_RECLAIM]		= "I:reclaim",
-	[KPF_BUDDY]		= "B:buddy",
-
-	[KPF_MMAP]		= "M:mmap",
-	[KPF_ANON]		= "a:anonymous",
-	[KPF_SWAPCACHE]		= "s:swapcache",
-	[KPF_SWAPBACKED]	= "b:swapbacked",
-	[KPF_COMPOUND_HEAD]	= "H:compound_head",
-	[KPF_COMPOUND_TAIL]	= "T:compound_tail",
-	[KPF_HUGE]		= "G:huge",
-	[KPF_UNEVICTABLE]	= "u:unevictable",
-	[KPF_HWPOISON]		= "X:hwpoison",
-	[KPF_NOPAGE]		= "n:nopage",
-	[KPF_KSM]		= "x:ksm",
-
-	[KPF_RESERVED]		= "r:reserved",
-	[KPF_MLOCKED]		= "m:mlocked",
-	[KPF_MAPPEDTODISK]	= "d:mappedtodisk",
-	[KPF_PRIVATE]		= "P:private",
-	[KPF_PRIVATE_2]		= "p:private_2",
-	[KPF_OWNER_PRIVATE]	= "O:owner_private",
-	[KPF_ARCH]		= "h:arch",
-	[KPF_UNCACHED]		= "c:uncached",
-
-	[KPF_READAHEAD]		= "I:readahead",
-	[KPF_SLOB_FREE]		= "P:slob_free",
-	[KPF_SLUB_FROZEN]	= "A:slub_frozen",
-	[KPF_SLUB_DEBUG]	= "E:slub_debug",
-};
-
-
-static const char *debugfs_known_mountpoints[] = {
-	"/sys/kernel/debug",
-	"/debug",
-	0,
-};
-
-/*
- * data structures
- */
-
-static int		opt_raw;	/* for kernel developers */
-static int		opt_list;	/* list pages (in ranges) */
-static int		opt_no_summary;	/* don't show summary */
-static pid_t		opt_pid;	/* process to walk */
-
-#define MAX_ADDR_RANGES	1024
-static int		nr_addr_ranges;
-static unsigned long	opt_offset[MAX_ADDR_RANGES];
-static unsigned long	opt_size[MAX_ADDR_RANGES];
-
-#define MAX_VMAS	10240
-static int		nr_vmas;
-static unsigned long	pg_start[MAX_VMAS];
-static unsigned long	pg_end[MAX_VMAS];
-
-#define MAX_BIT_FILTERS	64
-static int		nr_bit_filters;
-static uint64_t		opt_mask[MAX_BIT_FILTERS];
-static uint64_t		opt_bits[MAX_BIT_FILTERS];
-
-static int		page_size;
-
-static int		pagemap_fd;
-static int		kpageflags_fd;
-
-static int		opt_hwpoison;
-static int		opt_unpoison;
-
-static char		hwpoison_debug_fs[MAX_PATH+1];
-static int		hwpoison_inject_fd;
-static int		hwpoison_forget_fd;
-
-#define HASH_SHIFT	13
-#define HASH_SIZE	(1 << HASH_SHIFT)
-#define HASH_MASK	(HASH_SIZE - 1)
-#define HASH_KEY(flags)	(flags & HASH_MASK)
-
-static unsigned long	total_pages;
-static unsigned long	nr_pages[HASH_SIZE];
-static uint64_t 	page_flags[HASH_SIZE];
-
-
-/*
- * helper functions
- */
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
-#define min_t(type, x, y) ({			\
-	type __min1 = (x);			\
-	type __min2 = (y);			\
-	__min1 < __min2 ? __min1 : __min2; })
-
-#define max_t(type, x, y) ({			\
-	type __max1 = (x);			\
-	type __max2 = (y);			\
-	__max1 > __max2 ? __max1 : __max2; })
-
-static unsigned long pages2mb(unsigned long pages)
-{
-	return (pages * page_size) >> 20;
-}
-
-static void fatal(const char *x, ...)
-{
-	va_list ap;
-
-	va_start(ap, x);
-	vfprintf(stderr, x, ap);
-	va_end(ap);
-	exit(EXIT_FAILURE);
-}
-
-static int checked_open(const char *pathname, int flags)
-{
-	int fd = open(pathname, flags);
-
-	if (fd < 0) {
-		perror(pathname);
-		exit(EXIT_FAILURE);
-	}
-
-	return fd;
-}
-
-/*
- * pagemap/kpageflags routines
- */
-
-static unsigned long do_u64_read(int fd, char *name,
-				 uint64_t *buf,
-				 unsigned long index,
-				 unsigned long count)
-{
-	long bytes;
-
-	if (index > ULONG_MAX / 8)
-		fatal("index overflow: %lu\n", index);
-
-	if (lseek(fd, index * 8, SEEK_SET) < 0) {
-		perror(name);
-		exit(EXIT_FAILURE);
-	}
-
-	bytes = read(fd, buf, count * 8);
-	if (bytes < 0) {
-		perror(name);
-		exit(EXIT_FAILURE);
-	}
-	if (bytes % 8)
-		fatal("partial read: %lu bytes\n", bytes);
-
-	return bytes / 8;
-}
-
-static unsigned long kpageflags_read(uint64_t *buf,
-				     unsigned long index,
-				     unsigned long pages)
-{
-	return do_u64_read(kpageflags_fd, PROC_KPAGEFLAGS, buf, index, pages);
-}
-
-static unsigned long pagemap_read(uint64_t *buf,
-				  unsigned long index,
-				  unsigned long pages)
-{
-	return do_u64_read(pagemap_fd, "/proc/pid/pagemap", buf, index, pages);
-}
-
-static unsigned long pagemap_pfn(uint64_t val)
-{
-	unsigned long pfn;
-
-	if (val & PM_PRESENT)
-		pfn = PM_PFRAME(val);
-	else
-		pfn = 0;
-
-	return pfn;
-}
-
-
-/*
- * page flag names
- */
-
-static char *page_flag_name(uint64_t flags)
-{
-	static char buf[65];
-	int present;
-	int i, j;
-
-	for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
-		present = (flags >> i) & 1;
-		if (!page_flag_names[i]) {
-			if (present)
-				fatal("unknown flag bit %d\n", i);
-			continue;
-		}
-		buf[j++] = present ? page_flag_names[i][0] : '_';
-	}
-
-	return buf;
-}
-
-static char *page_flag_longname(uint64_t flags)
-{
-	static char buf[1024];
-	int i, n;
-
-	for (i = 0, n = 0; i < ARRAY_SIZE(page_flag_names); i++) {
-		if (!page_flag_names[i])
-			continue;
-		if ((flags >> i) & 1)
-			n += snprintf(buf + n, sizeof(buf) - n, "%s,",
-					page_flag_names[i] + 2);
-	}
-	if (n)
-		n--;
-	buf[n] = '\0';
-
-	return buf;
-}
-
-
-/*
- * page list and summary
- */
-
-static void show_page_range(unsigned long voffset,
-			    unsigned long offset, uint64_t flags)
-{
-	static uint64_t      flags0;
-	static unsigned long voff;
-	static unsigned long index;
-	static unsigned long count;
-
-	if (flags == flags0 && offset == index + count &&
-	    (!opt_pid || voffset == voff + count)) {
-		count++;
-		return;
-	}
-
-	if (count) {
-		if (opt_pid)
-			printf("%lx\t", voff);
-		printf("%lx\t%lx\t%s\n",
-				index, count, page_flag_name(flags0));
-	}
-
-	flags0 = flags;
-	index  = offset;
-	voff   = voffset;
-	count  = 1;
-}
-
-static void show_page(unsigned long voffset,
-		      unsigned long offset, uint64_t flags)
-{
-	if (opt_pid)
-		printf("%lx\t", voffset);
-	printf("%lx\t%s\n", offset, page_flag_name(flags));
-}
-
-static void show_summary(void)
-{
-	int i;
-
-	printf("             flags\tpage-count       MB"
-		"  symbolic-flags\t\t\tlong-symbolic-flags\n");
-
-	for (i = 0; i < ARRAY_SIZE(nr_pages); i++) {
-		if (nr_pages[i])
-			printf("0x%016llx\t%10lu %8lu  %s\t%s\n",
-				(unsigned long long)page_flags[i],
-				nr_pages[i],
-				pages2mb(nr_pages[i]),
-				page_flag_name(page_flags[i]),
-				page_flag_longname(page_flags[i]));
-	}
-
-	printf("             total\t%10lu %8lu\n",
-			total_pages, pages2mb(total_pages));
-}
-
-
-/*
- * page flag filters
- */
-
-static int bit_mask_ok(uint64_t flags)
-{
-	int i;
-
-	for (i = 0; i < nr_bit_filters; i++) {
-		if (opt_bits[i] == KPF_ALL_BITS) {
-			if ((flags & opt_mask[i]) == 0)
-				return 0;
-		} else {
-			if ((flags & opt_mask[i]) != opt_bits[i])
-				return 0;
-		}
-	}
-
-	return 1;
-}
-
-static uint64_t expand_overloaded_flags(uint64_t flags)
-{
-	/* SLOB/SLUB overload several page flags */
-	if (flags & BIT(SLAB)) {
-		if (flags & BIT(PRIVATE))
-			flags ^= BIT(PRIVATE) | BIT(SLOB_FREE);
-		if (flags & BIT(ACTIVE))
-			flags ^= BIT(ACTIVE) | BIT(SLUB_FROZEN);
-		if (flags & BIT(ERROR))
-			flags ^= BIT(ERROR) | BIT(SLUB_DEBUG);
-	}
-
-	/* PG_reclaim is overloaded as PG_readahead in the read path */
-	if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM))
-		flags ^= BIT(RECLAIM) | BIT(READAHEAD);
-
-	return flags;
-}
-
-static uint64_t well_known_flags(uint64_t flags)
-{
-	/* hide flags intended only for kernel hacker */
-	flags &= ~KPF_HACKERS_BITS;
-
-	/* hide non-hugeTLB compound pages */
-	if ((flags & BITS_COMPOUND) && !(flags & BIT(HUGE)))
-		flags &= ~BITS_COMPOUND;
-
-	return flags;
-}
-
-static uint64_t kpageflags_flags(uint64_t flags)
-{
-	flags = expand_overloaded_flags(flags);
-
-	if (!opt_raw)
-		flags = well_known_flags(flags);
-
-	return flags;
-}
-
-/* verify that a mountpoint is actually a debugfs instance */
-static int debugfs_valid_mountpoint(const char *debugfs)
-{
-	struct statfs st_fs;
-
-	if (statfs(debugfs, &st_fs) < 0)
-		return -ENOENT;
-	else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
-		return -ENOENT;
-
-	return 0;
-}
-
-/* find the path to the mounted debugfs */
-static const char *debugfs_find_mountpoint(void)
-{
-	const char **ptr;
-	char type[100];
-	FILE *fp;
-
-	ptr = debugfs_known_mountpoints;
-	while (*ptr) {
-		if (debugfs_valid_mountpoint(*ptr) == 0) {
-			strcpy(hwpoison_debug_fs, *ptr);
-			return hwpoison_debug_fs;
-		}
-		ptr++;
-	}
-
-	/* give up and parse /proc/mounts */
-	fp = fopen("/proc/mounts", "r");
-	if (fp == NULL)
-		perror("Can't open /proc/mounts for read");
-
-	while (fscanf(fp, "%*s %"
-		      STR(MAX_PATH)
-		      "s %99s %*s %*d %*d\n",
-		      hwpoison_debug_fs, type) == 2) {
-		if (strcmp(type, "debugfs") == 0)
-			break;
-	}
-	fclose(fp);
-
-	if (strcmp(type, "debugfs") != 0)
-		return NULL;
-
-	return hwpoison_debug_fs;
-}
-
-/* mount the debugfs somewhere if it's not mounted */
-
-static void debugfs_mount(void)
-{
-	const char **ptr;
-
-	/* see if it's already mounted */
-	if (debugfs_find_mountpoint())
-		return;
-
-	ptr = debugfs_known_mountpoints;
-	while (*ptr) {
-		if (mount(NULL, *ptr, "debugfs", 0, NULL) == 0) {
-			/* save the mountpoint */
-			strcpy(hwpoison_debug_fs, *ptr);
-			break;
-		}
-		ptr++;
-	}
-
-	if (*ptr == NULL) {
-		perror("mount debugfs");
-		exit(EXIT_FAILURE);
-	}
-}
-
-/*
- * page actions
- */
-
-static void prepare_hwpoison_fd(void)
-{
-	char buf[MAX_PATH + 1];
-
-	debugfs_mount();
-
-	if (opt_hwpoison && !hwpoison_inject_fd) {
-		snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn",
-			hwpoison_debug_fs);
-		hwpoison_inject_fd = checked_open(buf, O_WRONLY);
-	}
-
-	if (opt_unpoison && !hwpoison_forget_fd) {
-		snprintf(buf, MAX_PATH, "%s/hwpoison/unpoison-pfn",
-			hwpoison_debug_fs);
-		hwpoison_forget_fd = checked_open(buf, O_WRONLY);
-	}
-}
-
-static int hwpoison_page(unsigned long offset)
-{
-	char buf[100];
-	int len;
-
-	len = sprintf(buf, "0x%lx\n", offset);
-	len = write(hwpoison_inject_fd, buf, len);
-	if (len < 0) {
-		perror("hwpoison inject");
-		return len;
-	}
-	return 0;
-}
-
-static int unpoison_page(unsigned long offset)
-{
-	char buf[100];
-	int len;
-
-	len = sprintf(buf, "0x%lx\n", offset);
-	len = write(hwpoison_forget_fd, buf, len);
-	if (len < 0) {
-		perror("hwpoison forget");
-		return len;
-	}
-	return 0;
-}
-
-/*
- * page frame walker
- */
-
-static int hash_slot(uint64_t flags)
-{
-	int k = HASH_KEY(flags);
-	int i;
-
-	/* Explicitly reserve slot 0 for flags 0: the following logic
-	 * cannot distinguish an unoccupied slot from slot (flags==0).
-	 */
-	if (flags == 0)
-		return 0;
-
-	/* search through the remaining (HASH_SIZE-1) slots */
-	for (i = 1; i < ARRAY_SIZE(page_flags); i++, k++) {
-		if (!k || k >= ARRAY_SIZE(page_flags))
-			k = 1;
-		if (page_flags[k] == 0) {
-			page_flags[k] = flags;
-			return k;
-		}
-		if (page_flags[k] == flags)
-			return k;
-	}
-
-	fatal("hash table full: bump up HASH_SHIFT?\n");
-	exit(EXIT_FAILURE);
-}
-
-static void add_page(unsigned long voffset,
-		     unsigned long offset, uint64_t flags)
-{
-	flags = kpageflags_flags(flags);
-
-	if (!bit_mask_ok(flags))
-		return;
-
-	if (opt_hwpoison)
-		hwpoison_page(offset);
-	if (opt_unpoison)
-		unpoison_page(offset);
-
-	if (opt_list == 1)
-		show_page_range(voffset, offset, flags);
-	else if (opt_list == 2)
-		show_page(voffset, offset, flags);
-
-	nr_pages[hash_slot(flags)]++;
-	total_pages++;
-}
-
-#define KPAGEFLAGS_BATCH	(64 << 10)	/* 64k pages */
-static void walk_pfn(unsigned long voffset,
-		     unsigned long index,
-		     unsigned long count)
-{
-	uint64_t buf[KPAGEFLAGS_BATCH];
-	unsigned long batch;
-	long pages;
-	unsigned long i;
-
-	while (count) {
-		batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH);
-		pages = kpageflags_read(buf, index, batch);
-		if (pages == 0)
-			break;
-
-		for (i = 0; i < pages; i++)
-			add_page(voffset + i, index + i, buf[i]);
-
-		index += pages;
-		count -= pages;
-	}
-}
-
-#define PAGEMAP_BATCH	(64 << 10)
-static void walk_vma(unsigned long index, unsigned long count)
-{
-	uint64_t buf[PAGEMAP_BATCH];
-	unsigned long batch;
-	unsigned long pages;
-	unsigned long pfn;
-	unsigned long i;
-
-	while (count) {
-		batch = min_t(unsigned long, count, PAGEMAP_BATCH);
-		pages = pagemap_read(buf, index, batch);
-		if (pages == 0)
-			break;
-
-		for (i = 0; i < pages; i++) {
-			pfn = pagemap_pfn(buf[i]);
-			if (pfn)
-				walk_pfn(index + i, pfn, 1);
-		}
-
-		index += pages;
-		count -= pages;
-	}
-}
-
-static void walk_task(unsigned long index, unsigned long count)
-{
-	const unsigned long end = index + count;
-	unsigned long start;
-	int i = 0;
-
-	while (index < end) {
-
-		while (pg_end[i] <= index)
-			if (++i >= nr_vmas)
-				return;
-		if (pg_start[i] >= end)
-			return;
-
-		start = max_t(unsigned long, pg_start[i], index);
-		index = min_t(unsigned long, pg_end[i], end);
-
-		assert(start < index);
-		walk_vma(start, index - start);
-	}
-}
-
-static void add_addr_range(unsigned long offset, unsigned long size)
-{
-	if (nr_addr_ranges >= MAX_ADDR_RANGES)
-		fatal("too many addr ranges\n");
-
-	opt_offset[nr_addr_ranges] = offset;
-	opt_size[nr_addr_ranges] = min_t(unsigned long, size, ULONG_MAX-offset);
-	nr_addr_ranges++;
-}
-
-static void walk_addr_ranges(void)
-{
-	int i;
-
-	kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY);
-
-	if (!nr_addr_ranges)
-		add_addr_range(0, ULONG_MAX);
-
-	for (i = 0; i < nr_addr_ranges; i++)
-		if (!opt_pid)
-			walk_pfn(0, opt_offset[i], opt_size[i]);
-		else
-			walk_task(opt_offset[i], opt_size[i]);
-
-	close(kpageflags_fd);
-}
-
-
-/*
- * user interface
- */
-
-static const char *page_flag_type(uint64_t flag)
-{
-	if (flag & KPF_HACKERS_BITS)
-		return "(r)";
-	if (flag & KPF_OVERLOADED_BITS)
-		return "(o)";
-	return "   ";
-}
-
-static void usage(void)
-{
-	int i, j;
-
-	printf(
-"page-types [options]\n"
-"            -r|--raw                   Raw mode, for kernel developers\n"
-"            -d|--describe flags        Describe flags\n"
-"            -a|--addr    addr-spec     Walk a range of pages\n"
-"            -b|--bits    bits-spec     Walk pages with specified bits\n"
-"            -p|--pid     pid           Walk process address space\n"
-#if 0 /* planned features */
-"            -f|--file    filename      Walk file address space\n"
-#endif
-"            -l|--list                  Show page details in ranges\n"
-"            -L|--list-each             Show page details one by one\n"
-"            -N|--no-summary            Don't show summary info\n"
-"            -X|--hwpoison              hwpoison pages\n"
-"            -x|--unpoison              unpoison pages\n"
-"            -h|--help                  Show this usage message\n"
-"flags:\n"
-"            0x10                       bitfield format, e.g.\n"
-"            anon                       bit-name, e.g.\n"
-"            0x10,anon                  comma-separated list, e.g.\n"
-"addr-spec:\n"
-"            N                          one page at offset N (unit: pages)\n"
-"            N+M                        pages range from N to N+M-1\n"
-"            N,M                        pages range from N to M-1\n"
-"            N,                         pages range from N to end\n"
-"            ,M                         pages range from 0 to M-1\n"
-"bits-spec:\n"
-"            bit1,bit2                  (flags & (bit1|bit2)) != 0\n"
-"            bit1,bit2=bit1             (flags & (bit1|bit2)) == bit1\n"
-"            bit1,~bit2                 (flags & (bit1|bit2)) == bit1\n"
-"            =bit1,bit2                 flags == (bit1|bit2)\n"
-"bit-names:\n"
-	);
-
-	for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
-		if (!page_flag_names[i])
-			continue;
-		printf("%16s%s", page_flag_names[i] + 2,
-				 page_flag_type(1ULL << i));
-		if (++j > 3) {
-			j = 0;
-			putchar('\n');
-		}
-	}
-	printf("\n                                   "
-		"(r) raw mode bits  (o) overloaded bits\n");
-}
-
-static unsigned long long parse_number(const char *str)
-{
-	unsigned long long n;
-
-	n = strtoll(str, NULL, 0);
-
-	if (n == 0 && str[0] != '0')
-		fatal("invalid name or number: %s\n", str);
-
-	return n;
-}
-
-static void parse_pid(const char *str)
-{
-	FILE *file;
-	char buf[5000];
-
-	opt_pid = parse_number(str);
-
-	sprintf(buf, "/proc/%d/pagemap", opt_pid);
-	pagemap_fd = checked_open(buf, O_RDONLY);
-
-	sprintf(buf, "/proc/%d/maps", opt_pid);
-	file = fopen(buf, "r");
-	if (!file) {
-		perror(buf);
-		exit(EXIT_FAILURE);
-	}
-
-	while (fgets(buf, sizeof(buf), file) != NULL) {
-		unsigned long vm_start;
-		unsigned long vm_end;
-		unsigned long long pgoff;
-		int major, minor;
-		char r, w, x, s;
-		unsigned long ino;
-		int n;
-
-		n = sscanf(buf, "%lx-%lx %c%c%c%c %llx %x:%x %lu",
-			   &vm_start,
-			   &vm_end,
-			   &r, &w, &x, &s,
-			   &pgoff,
-			   &major, &minor,
-			   &ino);
-		if (n < 10) {
-			fprintf(stderr, "unexpected line: %s\n", buf);
-			continue;
-		}
-		pg_start[nr_vmas] = vm_start / page_size;
-		pg_end[nr_vmas] = vm_end / page_size;
-		if (++nr_vmas >= MAX_VMAS) {
-			fprintf(stderr, "too many VMAs\n");
-			break;
-		}
-	}
-	fclose(file);
-}
-
-static void parse_file(const char *name)
-{
-}
-
-static void parse_addr_range(const char *optarg)
-{
-	unsigned long offset;
-	unsigned long size;
-	char *p;
-
-	p = strchr(optarg, ',');
-	if (!p)
-		p = strchr(optarg, '+');
-
-	if (p == optarg) {
-		offset = 0;
-		size   = parse_number(p + 1);
-	} else if (p) {
-		offset = parse_number(optarg);
-		if (p[1] == '\0')
-			size = ULONG_MAX;
-		else {
-			size = parse_number(p + 1);
-			if (*p == ',') {
-				if (size < offset)
-					fatal("invalid range: %lu,%lu\n",
-							offset, size);
-				size -= offset;
-			}
-		}
-	} else {
-		offset = parse_number(optarg);
-		size   = 1;
-	}
-
-	add_addr_range(offset, size);
-}
-
-static void add_bits_filter(uint64_t mask, uint64_t bits)
-{
-	if (nr_bit_filters >= MAX_BIT_FILTERS)
-		fatal("too much bit filters\n");
-
-	opt_mask[nr_bit_filters] = mask;
-	opt_bits[nr_bit_filters] = bits;
-	nr_bit_filters++;
-}
-
-static uint64_t parse_flag_name(const char *str, int len)
-{
-	int i;
-
-	if (!*str || !len)
-		return 0;
-
-	if (len <= 8 && !strncmp(str, "compound", len))
-		return BITS_COMPOUND;
-
-	for (i = 0; i < ARRAY_SIZE(page_flag_names); i++) {
-		if (!page_flag_names[i])
-			continue;
-		if (!strncmp(str, page_flag_names[i] + 2, len))
-			return 1ULL << i;
-	}
-
-	return parse_number(str);
-}
-
-static uint64_t parse_flag_names(const char *str, int all)
-{
-	const char *p    = str;
-	uint64_t   flags = 0;
-
-	while (1) {
-		if (*p == ',' || *p == '=' || *p == '\0') {
-			if ((*str != '~') || (*str == '~' && all && *++str))
-				flags |= parse_flag_name(str, p - str);
-			if (*p != ',')
-				break;
-			str = p + 1;
-		}
-		p++;
-	}
-
-	return flags;
-}
-
-static void parse_bits_mask(const char *optarg)
-{
-	uint64_t mask;
-	uint64_t bits;
-	const char *p;
-
-	p = strchr(optarg, '=');
-	if (p == optarg) {
-		mask = KPF_ALL_BITS;
-		bits = parse_flag_names(p + 1, 0);
-	} else if (p) {
-		mask = parse_flag_names(optarg, 0);
-		bits = parse_flag_names(p + 1, 0);
-	} else if (strchr(optarg, '~')) {
-		mask = parse_flag_names(optarg, 1);
-		bits = parse_flag_names(optarg, 0);
-	} else {
-		mask = parse_flag_names(optarg, 0);
-		bits = KPF_ALL_BITS;
-	}
-
-	add_bits_filter(mask, bits);
-}
-
-static void describe_flags(const char *optarg)
-{
-	uint64_t flags = parse_flag_names(optarg, 0);
-
-	printf("0x%016llx\t%s\t%s\n",
-		(unsigned long long)flags,
-		page_flag_name(flags),
-		page_flag_longname(flags));
-}
-
-static const struct option opts[] = {
-	{ "raw"       , 0, NULL, 'r' },
-	{ "pid"       , 1, NULL, 'p' },
-	{ "file"      , 1, NULL, 'f' },
-	{ "addr"      , 1, NULL, 'a' },
-	{ "bits"      , 1, NULL, 'b' },
-	{ "describe"  , 1, NULL, 'd' },
-	{ "list"      , 0, NULL, 'l' },
-	{ "list-each" , 0, NULL, 'L' },
-	{ "no-summary", 0, NULL, 'N' },
-	{ "hwpoison"  , 0, NULL, 'X' },
-	{ "unpoison"  , 0, NULL, 'x' },
-	{ "help"      , 0, NULL, 'h' },
-	{ NULL        , 0, NULL, 0 }
-};
-
-int main(int argc, char *argv[])
-{
-	int c;
-
-	page_size = getpagesize();
-
-	while ((c = getopt_long(argc, argv,
-				"rp:f:a:b:d:lLNXxh", opts, NULL)) != -1) {
-		switch (c) {
-		case 'r':
-			opt_raw = 1;
-			break;
-		case 'p':
-			parse_pid(optarg);
-			break;
-		case 'f':
-			parse_file(optarg);
-			break;
-		case 'a':
-			parse_addr_range(optarg);
-			break;
-		case 'b':
-			parse_bits_mask(optarg);
-			break;
-		case 'd':
-			describe_flags(optarg);
-			exit(0);
-		case 'l':
-			opt_list = 1;
-			break;
-		case 'L':
-			opt_list = 2;
-			break;
-		case 'N':
-			opt_no_summary = 1;
-			break;
-		case 'X':
-			opt_hwpoison = 1;
-			prepare_hwpoison_fd();
-			break;
-		case 'x':
-			opt_unpoison = 1;
-			prepare_hwpoison_fd();
-			break;
-		case 'h':
-			usage();
-			exit(0);
-		default:
-			usage();
-			exit(1);
-		}
-	}
-
-	if (opt_list && opt_pid)
-		printf("voffset\t");
-	if (opt_list == 1)
-		printf("offset\tlen\tflags\n");
-	if (opt_list == 2)
-		printf("offset\tflags\n");
-
-	walk_addr_ranges();
-
-	if (opt_list == 1)
-		show_page_range(0, 0, 0);  /* drain the buffer */
-
-	if (opt_no_summary)
-		return 0;
-
-	if (opt_list)
-		printf("\n\n");
-
-	show_summary();
-
-	return 0;
-}
diff --git a/Documentation/vm/pagemap.txt b/Documentation/vm/pagemap.txt
index df09b96..4600cbe 100644
--- a/Documentation/vm/pagemap.txt
+++ b/Documentation/vm/pagemap.txt
@@ -60,6 +60,7 @@
     19. HWPOISON
     20. NOPAGE
     21. KSM
+    22. THP
 
 Short descriptions to the page flags:
 
@@ -97,6 +98,9 @@
 21. KSM
     identical memory pages dynamically shared between one or more processes
 
+22. THP
+    contiguous pages which construct transparent hugepages
+
     [IO related page flags]
  1. ERROR     IO error occurred
  3. UPTODATE  page has up-to-date data
diff --git a/Documentation/watchdog/00-INDEX b/Documentation/watchdog/00-INDEX
deleted file mode 100644
index fc9082a..0000000
--- a/Documentation/watchdog/00-INDEX
+++ /dev/null
@@ -1,19 +0,0 @@
-00-INDEX
-	- this file.
-convert_drivers_to_kernel_api.txt
-	- how-to for converting old watchdog drivers to the new kernel API.
-hpwdt.txt
-	- information on the HP iLO2 NMI watchdog
-pcwd-watchdog.txt
-	- documentation for Berkshire Products PC Watchdog ISA cards.
-src/
-	- directory holding watchdog related example programs.
-watchdog-api.txt
-	- description of the Linux Watchdog driver API.
-watchdog-kernel-api.txt
-	- description of the Linux WatchDog Timer Driver Core kernel API.
-watchdog-parameters.txt
-	- information on driver parameters (for drivers other than
-	  the ones that have driver-specific files here)
-wdt.txt
-	- description of the Watchdog Timer Interfaces for Linux.
diff --git a/Documentation/watchdog/convert_drivers_to_kernel_api.txt b/Documentation/watchdog/convert_drivers_to_kernel_api.txt
index be8119b..271b885 100644
--- a/Documentation/watchdog/convert_drivers_to_kernel_api.txt
+++ b/Documentation/watchdog/convert_drivers_to_kernel_api.txt
@@ -59,6 +59,10 @@
 	WDIOC_GETTIMEOUT:
 		No preparations needed
 
+	WDIOC_GETTIMELEFT:
+		It needs get_timeleft() callback to be defined. Otherwise it
+		will return EOPNOTSUPP
+
   Other IOCTLs can be served using the ioctl-callback. Note that this is mainly
   intended for porting old drivers; new drivers should not invent private IOCTLs.
   Private IOCTLs are processed first. When the callback returns with
diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt
index 9e16246..227f6cd 100644
--- a/Documentation/watchdog/watchdog-kernel-api.txt
+++ b/Documentation/watchdog/watchdog-kernel-api.txt
@@ -1,6 +1,6 @@
 The Linux WatchDog Timer Driver Core kernel API.
 ===============================================
-Last reviewed: 29-Nov-2011
+Last reviewed: 16-Mar-2012
 
 Wim Van Sebroeck <wim@iguana.be>
 
@@ -77,6 +77,7 @@
 	int (*ping)(struct watchdog_device *);
 	unsigned int (*status)(struct watchdog_device *);
 	int (*set_timeout)(struct watchdog_device *, unsigned int);
+	unsigned int (*get_timeleft)(struct watchdog_device *);
 	long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
 };
 
@@ -117,11 +118,13 @@
   status of the device is reported with watchdog WDIOF_* status flags/bits.
 * set_timeout: this routine checks and changes the timeout of the watchdog
   timer device. It returns 0 on success, -EINVAL for "parameter out of range"
-  and -EIO for "could not write value to the watchdog". On success the timeout
-  value of the watchdog_device will be changed to the value that was just used
-  to re-program the watchdog timer device.
+  and -EIO for "could not write value to the watchdog". On success this
+  routine should set the timeout value of the watchdog_device to the
+  achieved timeout value (which may be different from the requested one
+  because the watchdog does not necessarily has a 1 second resolution).
   (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the
   watchdog's info structure).
+* get_timeleft: this routines returns the time that's left before a reset.
 * ioctl: if this routine is present then it will be called first before we do
   our own internal ioctl call handling. This routine should return -ENOIOCTLCMD
   if a command is not supported. The parameters that are passed to the ioctl
diff --git a/MAINTAINERS b/MAINTAINERS
index 6555183..6010b9d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -163,7 +163,7 @@
 L:	linux-serial@vger.kernel.org
 W:	http://serial.sourceforge.net
 S:	Maintained
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
 F:	drivers/tty/serial/8250*
 F:	include/linux/serial_8250.h
 
@@ -464,6 +464,7 @@
 M:	Richard Henderson <rth@twiddle.net>
 M:	Ivan Kokshaysky <ink@jurassic.park.msu.ru>
 M:	Matt Turner <mattst88@gmail.com>
+S:	Odd Fixes
 L:	linux-alpha@vger.kernel.org
 F:	arch/alpha/
 
@@ -503,7 +504,7 @@
 AMD IOMMU (AMD-VI)
 M:	Joerg Roedel <joerg.roedel@amd.com>
 L:	iommu@lists.linux-foundation.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/joro/linux-2.6-iommu.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
 S:	Supported
 F:	drivers/iommu/amd_iommu*.[ch]
 F:	include/linux/amd-iommu.h
@@ -715,6 +716,7 @@
 ARM/CLKDEV SUPPORT
 M:	Russell King <linux@arm.linux.org.uk>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
 F:	arch/arm/include/asm/clkdev.h
 F:	drivers/clk/clkdev.c
 
@@ -784,7 +786,6 @@
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 T:	git git://git.pengutronix.de/git/imx/linux-2.6.git
-F:	arch/arm/mach-mx*/
 F:	arch/arm/mach-imx/
 F:	arch/arm/plat-mxc/
 
@@ -814,9 +815,12 @@
 
 ARM/H4700 (HP IPAQ HX4700) MACHINE SUPPORT
 M:	Philipp Zabel <philipp.zabel@gmail.com>
+M:	Paul Parsons <lost.distance@yahoo.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 F:	arch/arm/mach-pxa/hx4700.c
 F:	arch/arm/mach-pxa/include/mach/hx4700.h
+F:	sound/soc/pxa/hx4700.c
 
 ARM/HP JORNADA 7XX MACHINE SUPPORT
 M:	Kristoffer Ericson <kristoffer.ericson@gmail.com>
@@ -1501,7 +1505,7 @@
 
 BLOCK LAYER
 M:	Jens Axboe <axboe@kernel.dk>
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 S:	Maintained
 F:	block/
 
@@ -1639,7 +1643,7 @@
 M:	Mauro Carvalho Chehab <mchehab@infradead.org>
 L:	linux-media@vger.kernel.org
 W:	http://linuxtv.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
 F:	Documentation/video4linux/bttv/
 F:	drivers/media/video/bt8xx/bttv*
@@ -1669,7 +1673,7 @@
 CAFE CMOS INTEGRATED CAMERA CONTROLLER DRIVER
 M:	Jonathan Corbet <corbet@lwn.net>
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
 F:	Documentation/video4linux/cafe_ccic
 F:	drivers/media/video/marvell-ccic/
@@ -1831,8 +1835,16 @@
 S:	Supported
 F:	sound/soc/codecs/cs4270*
 
+CLEANCACHE API
+M:	Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+F:	mm/cleancache.c
+F:	include/linux/cleancache.h
+
 CLK API
 M:	Russell King <linux@arm.linux.org.uk>
+S:	Maintained
 F:	include/linux/clk.h
 
 CISCO FCOE HBA DRIVER
@@ -1927,7 +1939,7 @@
 
 CONTROL GROUPS (CGROUPS)
 M:	Tejun Heo <tj@kernel.org>
-M:	Li Zefan <lizf@cn.fujitsu.com>
+M:	Li Zefan <lizefan@huawei.com>
 L:	containers@lists.linux-foundation.org
 L:	cgroups@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
@@ -2028,7 +2040,7 @@
 M:	Andy Walls <awalls@md.metrocast.net>
 L:	ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:	http://linuxtv.org
 W:	http://www.ivtvdriver.org/index.php/Cx18
 S:	Maintained
@@ -2101,6 +2113,13 @@
 S:	Orphan
 F:	drivers/net/wan/pc300*
 
+CYTTSP TOUCHSCREEN DRIVER
+M:      Javier Martinez Canillas <javier@dowhile0.org>
+L:      linux-input@vger.kernel.org
+S:      Maintained
+F:      drivers/input/touchscreen/cyttsp*
+F:      include/linux/input/cyttsp.h
+
 DAMA SLAVE for AX.25
 M:	Joerg Reuter <jreuter@yaina.de>
 W:	http://yaina.de/jreuter/
@@ -2205,13 +2224,16 @@
 S:	Maintained
 
 DEVICE-MAPPER  (LVM)
-P:	Alasdair Kergon
+M:	Alasdair Kergon <agk@redhat.com>
+M:	dm-devel@redhat.com
 L:	dm-devel@redhat.com
 W:	http://sources.redhat.com/dm
 Q:	http://patchwork.kernel.org/project/dm-devel/list/
+T:	quilt http://people.redhat.com/agk/patches/linux/editing/
 S:	Maintained
 F:	Documentation/device-mapper/
 F:	drivers/md/dm*
+F:	drivers/md/persistent-data/
 F:	include/linux/device-mapper.h
 F:	include/linux/dm-*.h
 
@@ -2242,6 +2264,15 @@
 F:	fs/quota/
 F:	include/linux/quota*.h
 
+DISPLAYLINK USB 2.0 FRAMEBUFFER DRIVER (UDLFB)
+M:	Bernie Thompson <bernie@plugable.com>
+L:	linux-fbdev@vger.kernel.org
+S:	Maintained
+W:	http://plugable.com/category/projects/udlfb/
+F:	drivers/video/udlfb.c
+F:	include/video/udlfb.h
+F:	Documentation/fb/udlfb.txt
+
 DISTRIBUTED LOCK MANAGER (DLM)
 M:	Christine Caulfield <ccaulfie@redhat.com>
 M:	David Teigland <teigland@redhat.com>
@@ -2326,7 +2357,7 @@
 
 DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS
 M:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
 S:	Supported
 F:	Documentation/kobject.txt
 F:	drivers/base/
@@ -2348,7 +2379,7 @@
 M:	Keith Packard <keithp@keithp.com>
 L:	intel-gfx@lists.freedesktop.org (subscribers-only)
 L:	dri-devel@lists.freedesktop.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/keithp/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/keithp/linux.git
 S:	Supported
 F:	drivers/gpu/drm/i915
 F:	include/drm/i915*
@@ -2363,15 +2394,6 @@
 F:	drivers/gpu/drm/exynos
 F:	include/drm/exynos*
 
-EXYNOS MIPI DISPLAY DRIVERS
-M:	Inki Dae <inki.dae@samsung.com>
-M:	Donghwa Lee <dh09.lee@samsung.com>
-M:	Kyungmin Park <kyungmin.park@samsung.com>
-L:	linux-fbdev@vger.kernel.org
-S:	Maintained
-F:	drivers/video/exynos/exynos_mipi*
-F:	include/video/exynos_mipi*
-
 DSCC4 DRIVER
 M:	Francois Romieu <romieu@fr.zoreil.com>
 L:	netdev@vger.kernel.org
@@ -2652,6 +2674,21 @@
 S:	Supported
 F:	security/integrity/evm/
 
+EXYNOS DP DRIVER
+M:	Jingoo Han <jg1.han@samsung.com>
+L:	linux-fbdev@vger.kernel.org
+S:	Maintained
+F:	drivers/video/exynos/exynos_dp*
+
+EXYNOS MIPI DISPLAY DRIVERS
+M:	Inki Dae <inki.dae@samsung.com>
+M:	Donghwa Lee <dh09.lee@samsung.com>
+M:	Kyungmin Park <kyungmin.park@samsung.com>
+L:	linux-fbdev@vger.kernel.org
+S:	Maintained
+F:	drivers/video/exynos/exynos_mipi*
+F:	include/video/exynos_mipi*
+
 F71805F HARDWARE MONITORING DRIVER
 M:	Jean Delvare <khali@linux-fr.org>
 L:	lm-sensors@lm-sensors.org
@@ -2936,8 +2973,8 @@
 M:	Steven Whitehouse <swhiteho@redhat.com>
 L:	cluster-devel@redhat.com
 W:	http://sources.redhat.com/cluster/
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes.git
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-fixes.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw.git
 S:	Supported
 F:	Documentation/filesystems/gfs2*.txt
 F:	fs/gfs2/
@@ -2978,42 +3015,42 @@
 GSPCA FINEPIX SUBDRIVER
 M:	Frank Zago <frank@zago.net>
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
 F:	drivers/media/video/gspca/finepix.c
 
 GSPCA GL860 SUBDRIVER
 M:	Olivier Lorin <o.lorin@laposte.net>
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
 F:	drivers/media/video/gspca/gl860/
 
 GSPCA M5602 SUBDRIVER
 M:	Erik Andren <erik.andren@gmail.com>
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
 F:	drivers/media/video/gspca/m5602/
 
 GSPCA PAC207 SONIXB SUBDRIVER
 M:	Hans de Goede <hdegoede@redhat.com>
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
 F:	drivers/media/video/gspca/pac207.c
 
 GSPCA SN9C20X SUBDRIVER
 M:	Brian Johnson <brijohn@gmail.com>
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
 F:	drivers/media/video/gspca/sn9c20x.c
 
 GSPCA T613 SUBDRIVER
 M:	Leandro Costantino <lcostantino@gmail.com>
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
 F:	drivers/media/video/gspca/t613.c
 
@@ -3021,7 +3058,7 @@
 M:	Jean-Francois Moine <moinejf@free.fr>
 W:	http://moinejf.free.fr
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
 F:	drivers/media/video/gspca/
 
@@ -3307,7 +3344,7 @@
 M:	"David S. Miller" <davem@davemloft.net>
 L:	linux-ide@vger.kernel.org
 Q:	http://patchwork.ozlabs.org/project/linux-ide/list/
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide.git
 S:	Maintained
 F:	Documentation/ide/
 F:	drivers/ide/
@@ -3419,7 +3456,7 @@
 INTEL IDLE DRIVER
 M:	Len Brown <lenb@kernel.org>
 L:	linux-pm@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-idle-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git
 S:	Supported
 F:	drivers/idle/intel_idle.c
 
@@ -3519,17 +3556,13 @@
 S:	Supported
 F:	arch/x86/platform/mrst/pmu.*
 
-INTEL PRO/WIRELESS 2100 NETWORK CONNECTION SUPPORT
+INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT
+M:	Stanislav Yakovlev <stas.yakovlev@gmail.com>
 L:	linux-wireless@vger.kernel.org
-S:	Orphan
+S:	Maintained
 F:	Documentation/networking/README.ipw2100
-F:	drivers/net/wireless/ipw2x00/ipw2100.*
-
-INTEL PRO/WIRELESS 2915ABG NETWORK CONNECTION SUPPORT
-L:	linux-wireless@vger.kernel.org
-S:	Orphan
 F:	Documentation/networking/README.ipw2200
-F:	drivers/net/wireless/ipw2x00/ipw2200.*
+F:	drivers/net/wireless/ipw2x00/
 
 INTEL(R) TRUSTED EXECUTION TECHNOLOGY (TXT)
 M:	Joseph Cihula <joseph.cihula@intel.com>
@@ -3726,7 +3759,7 @@
 M:	Andy Walls <awalls@md.metrocast.net>
 L:	ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:	http://www.ivtvdriver.org
 S:	Maintained
 F:	Documentation/video4linux/*.ivtv
@@ -3822,8 +3855,8 @@
 
 KERNEL BUILD + files below scripts/ (unless maintained elsewhere)
 M:	Michal Marek <mmarek@suse.cz>
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6.git for-next
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6.git rc-fixes
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git for-next
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git rc-fixes
 L:	linux-kbuild@vger.kernel.org
 S:	Maintained
 F:	Documentation/kbuild/
@@ -4070,7 +4103,7 @@
 M:	Matt Porter <mporter@kernel.crashing.org>
 W:	http://www.penguinppc.org/
 L:	linuxppc-dev@lists.ozlabs.org
-T:	git git://git.infradead.org/users/jwboyer/powerpc-4xx.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git
 S:	Maintained
 F:	arch/powerpc/platforms/40x/
 F:	arch/powerpc/platforms/44x/
@@ -4203,12 +4236,14 @@
 F:	drivers/hwmon/ltc4261.c
 
 LTP (Linux Test Project)
-M:	Rishikesh K Rajak <risrajak@linux.vnet.ibm.com>
-M:	Garrett Cooper <yanegomi@gmail.com>
+M:	Shubham Goyal <shubham@linux.vnet.ibm.com>
 M:	Mike Frysinger <vapier@gentoo.org>
-M:	Subrata Modak <subrata@linux.vnet.ibm.com>
+M:	Cyril Hrubis <chrubis@suse.cz>
+M:	Caspar Zhang <caspar@casparzhang.com>
+M:	Wanlong Gao <gaowanlong@cn.fujitsu.com>
 L:	ltp-list@lists.sourceforge.net (subscribers-only)
 W:	http://ltp.sourceforge.net/
+T:	git git://github.com/linux-test-project/ltp.git
 T:	git git://ltp.git.sourceforge.net/gitroot/ltp/ltp-dev
 S:	Maintained
 
@@ -4246,7 +4281,7 @@
 M:	Johannes Berg <johannes@sipsolutions.net>
 L:	linux-wireless@vger.kernel.org
 W:	http://linuxwireless.org/
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git
 S:	Maintained
 F:	Documentation/networking/mac80211-injection.txt
 F:	include/net/mac80211.h
@@ -4257,7 +4292,7 @@
 M:	Mattias Nissler <mattias.nissler@gmx.de>
 L:	linux-wireless@vger.kernel.org
 W:	http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/PID
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git
 S:	Maintained
 F:	net/mac80211/rc80211_pid*
 
@@ -4274,6 +4309,13 @@
 L:	linux-man@vger.kernel.org
 S:	Maintained
 
+MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
+M:	Mirko Lindner <mlindner@marvell.com>
+M:	Stephen Hemminger <shemminger@vyatta.com>
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	drivers/net/ethernet/marvell/sk*
+
 MARVELL LIBERTAS WIRELESS DRIVER
 M:	Dan Williams <dcbw@redhat.com>
 L:	libertas-dev@lists.infradead.org
@@ -4304,12 +4346,6 @@
 S:	Odd Fixes
 F:	drivers/mmc/host/mvsdio.*
 
-MARVELL YUKON / SYSKONNECT DRIVER
-M:	Mirko Lindner <mlindner@syskonnect.de>
-M:	Ralph Roesler <rroesler@syskonnect.de>
-W:	http://www.syskonnect.com
-S:	Supported
-
 MATROX FRAMEBUFFER DRIVER
 L:	linux-fbdev@vger.kernel.org
 S:	Orphan
@@ -4329,7 +4365,7 @@
 L:	linux-media@vger.kernel.org
 W:	http://linuxtv.org
 Q:	http://patchwork.kernel.org/project/linux-media/list/
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
 F:	Documentation/dvb/
 F:	Documentation/video4linux/
@@ -4386,6 +4422,13 @@
 S:	Supported
 F:	arch/microblaze/
 
+MICROCHANNEL ARCHITECTURE (MCA)
+M:	James Bottomley <James.Bottomley@HansenPartnership.com>
+S:	Maintained
+F:	Documentation/mca.txt
+F:	drivers/mca/
+F:	include/linux/mca*
+
 MICROTEK X6 SCANNER
 M:	Oliver Neukum <oliver@neukum.name>
 S:	Maintained
@@ -4401,14 +4444,6 @@
 F:	Documentation/mips/
 F:	arch/mips/
 
-MISCELLANEOUS MCA-SUPPORT
-M:	James Bottomley <James.Bottomley@HansenPartnership.com>
-S:	Maintained
-F:	Documentation/ia64/mca.txt
-F:	Documentation/mca.txt
-F:	drivers/mca/
-F:	include/linux/mca*
-
 MODULE SUPPORT
 M:	Rusty Russell <rusty@rustcorp.com.au>
 S:	Maintained
@@ -4616,7 +4651,7 @@
 M:	Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
 M:	Patrick McHardy <kaber@trash.net>
 L:	netdev@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
 S:	Maintained
 F:	net/ipv4/
 F:	net/ipv6/
@@ -4632,7 +4667,7 @@
 M:	"John W. Linville" <linville@tuxdriver.com>
 L:	linux-wireless@vger.kernel.org
 Q:	http://patchwork.kernel.org/project/linux-wireless/list/
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git
 S:	Maintained
 F:	net/mac80211/
 F:	net/rfkill/
@@ -4645,8 +4680,8 @@
 NETWORKING DRIVERS
 L:	netdev@vger.kernel.org
 W:	http://www.linuxfoundation.org/en/Net
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.git
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git
 S:	Odd Fixes
 F:	drivers/net/
 F:	include/linux/if_*
@@ -4862,7 +4897,7 @@
 OMNIVISION OV7670 SENSOR DRIVER
 M:	Jonathan Corbet <corbet@lwn.net>
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
 F:	drivers/media/video/ov7670.c
 
@@ -5037,7 +5072,7 @@
 L:	linux-parisc@vger.kernel.org
 W:	http://www.parisc-linux.org/
 Q:	http://patchwork.kernel.org/project/linux-parisc/list/
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/kyle/parisc-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/parisc-2.6.git
 S:	Maintained
 F:	arch/parisc/
 F:	drivers/parisc/
@@ -5090,17 +5125,17 @@
 F:	Documentation/powerpc/eeh-pci-error-recovery.txt
 
 PCI SUBSYSTEM
-M:	Jesse Barnes <jbarnes@virtuousgeek.org>
+M:	Bjorn Helgaas <bhelgaas@google.com>
 L:	linux-pci@vger.kernel.org
 Q:	http://patchwork.kernel.org/project/linux-pci/list/
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci.git
 S:	Supported
 F:	Documentation/PCI/
 F:	drivers/pci/
 F:	include/linux/pci*
 
 PCI HOTPLUG
-M:	Jesse Barnes <jbarnes@virtuousgeek.org>
+M:	Bjorn Helgaas <bhelgaas@google.com>
 L:	linux-pci@vger.kernel.org
 S:	Supported
 F:	drivers/pci/hotplug
@@ -5146,7 +5181,7 @@
 PERFORMANCE EVENTS SUBSYSTEM
 M:	Peter Zijlstra <a.p.zijlstra@chello.nl>
 M:	Paul Mackerras <paulus@samba.org>
-M:	Ingo Molnar <mingo@elte.hu>
+M:	Ingo Molnar <mingo@redhat.com>
 M:	Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core
 S:	Supported
@@ -5378,7 +5413,7 @@
 L:	pvrusb2@isely.net	(subscribers-only)
 L:	linux-media@vger.kernel.org
 W:	http://www.isely.net/pvrusb2/
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
 F:	Documentation/video4linux/README.pvrusb2
 F:	drivers/media/video/pvrusb2/
@@ -5386,7 +5421,7 @@
 PXA2xx/PXA3xx SUPPORT
 M:	Eric Miao <eric.y.miao@gmail.com>
 M:	Russell King <linux@arm.linux.org.uk>
-M:	Haojian Zhuang <haojian.zhuang@marvell.com>
+M:	Haojian Zhuang <haojian.zhuang@gmail.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:	git git://github.com/hzhuang1/linux.git
 T:	git git://git.linaro.org/people/ycmiao/pxa-linux.git
@@ -5401,7 +5436,7 @@
 
 MMP SUPPORT
 M:	Eric Miao <eric.y.miao@gmail.com>
-M:	Haojian Zhuang <haojian.zhuang@marvell.com>
+M:	Haojian Zhuang <haojian.zhuang@gmail.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:	git git://github.com/hzhuang1/linux.git
 T:	git git://git.linaro.org/people/ycmiao/pxa-linux.git
@@ -5544,7 +5579,7 @@
 M:	Josh Triplett <josh@freedesktop.org>
 M:	"Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
 S:	Supported
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git
 F:	Documentation/RCU/torture.txt
 F:	kernel/rcutorture.c
 
@@ -5569,7 +5604,7 @@
 M:	"Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
 W:	http://www.rdrop.com/users/paulmck/rclock/
 S:	Supported
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git
 F:	Documentation/RCU/
 F:	include/linux/rcu*
 F:	include/linux/srcu*
@@ -5598,6 +5633,13 @@
 F:	drivers/base/regmap/
 F:	include/linux/regmap.h
 
+REMOTE PROCESSOR (REMOTEPROC) SUBSYSTEM
+M:	Ohad Ben-Cohen <ohad@wizery.com>
+S:	Maintained
+F:	drivers/remoteproc/
+F:	Documentation/remoteproc.txt
+F:	include/linux/remoteproc.h
+
 RFKILL
 M:	Johannes Berg <johannes@sipsolutions.net>
 L:	linux-wireless@vger.kernel.org
@@ -5723,13 +5765,19 @@
 SAA7146 VIDEO4LINUX-2 DRIVER
 M:	Michael Hunold <michael@mihu.de>
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:	http://www.mihu.de/linux/saa7146
 S:	Maintained
 F:	drivers/media/common/saa7146*
 F:	drivers/media/video/*7146*
 F:	include/media/*7146*
 
+SAMSUNG LAPTOP DRIVER
+M:	Corentin Chary <corentincj@iksaif.net>
+L:	platform-driver-x86@vger.kernel.org
+S:	Maintained
+F:	drivers/platform/x86/samsung-laptop.c
+
 SAMSUNG AUDIO (ASoC) DRIVERS
 M:	Sangbeom Kim <sbkim73@samsung.com>
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -5781,7 +5829,7 @@
 F:	drivers/watchdog/sc1200wdt.c
 
 SCHEDULER
-M:	Ingo Molnar <mingo@elte.hu>
+M:	Ingo Molnar <mingo@redhat.com>
 M:	Peter Zijlstra <peterz@infradead.org>
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git sched/core
 S:	Maintained
@@ -6028,7 +6076,8 @@
 TI DAVINCI MACHINE SUPPORT
 M:	Sekhar Nori <nsekhar@ti.com>
 M:	Kevin Hilman <khilman@ti.com>
-L:	davinci-linux-open-source@linux.davincidsp.com (subscribers-only)
+L:	davinci-linux-open-source@linux.davincidsp.com (moderated for non-subscribers)
+T:	git git://gitorious.org/linux-davinci/linux-davinci.git
 Q:	http://patchwork.kernel.org/project/linux-davinci/list/
 S:	Supported
 F:	arch/arm/mach-davinci
@@ -6068,12 +6117,6 @@
 S:	Maintained
 F:	drivers/usb/misc/sisusbvga/
 
-SKGE, SKY2 10/100/1000 GIGABIT ETHERNET DRIVERS
-M:	Stephen Hemminger <shemminger@vyatta.com>
-L:	netdev@vger.kernel.org
-S:	Maintained
-F:	drivers/net/ethernet/marvell/sk*
-
 SLAB ALLOCATOR
 M:	Christoph Lameter <cl@linux-foundation.org>
 M:	Pekka Enberg <penberg@kernel.org>
@@ -6146,7 +6189,7 @@
 SOC-CAMERA V4L2 SUBSYSTEM
 M:	Guennadi Liakhovetski <g.liakhovetski@gmx.de>
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:	Maintained
 F:	include/media/v4l2*
 F:	drivers/media/video/v4l2*
@@ -6218,8 +6261,8 @@
 M:	"David S. Miller" <davem@davemloft.net>
 L:	sparclinux@vger.kernel.org
 Q:	http://patchwork.ozlabs.org/project/sparclinux/list/
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next.git
 S:	Maintained
 F:	arch/sparc/
 F:	drivers/sbus/
@@ -6227,8 +6270,8 @@
 SPARC SERIAL DRIVERS
 M:	"David S. Miller" <davem@davemloft.net>
 L:	sparclinux@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next.git
 S:	Maintained
 F:	include/linux/sunserialcore.h
 F:	drivers/tty/serial/suncore.c
@@ -6239,6 +6282,15 @@
 F:	drivers/tty/serial/sunzilog.c
 F:	drivers/tty/serial/sunzilog.h
 
+SPARSE CHECKER
+M:	"Christopher Li" <sparse@chrisli.org>
+L:	linux-sparse@vger.kernel.org
+W:	https://sparse.wiki.kernel.org/
+T:	git git://git.kernel.org/pub/scm/devel/sparse/sparse.git
+T:	git git://git.kernel.org/pub/scm/devel/sparse/chrisl/sparse.git
+S:	Maintained
+F:	include/linux/compiler.h
+
 SPEAR PLATFORM SUPPORT
 M:	Viresh Kumar <viresh.kumar@st.com>
 L:	spear-devel@list.st.com
@@ -6533,7 +6585,7 @@
 L:	target-devel@vger.kernel.org
 L:	http://groups.google.com/group/linux-iscsi-target-dev
 W:	http://www.linux-iscsi.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core.git master
 S:	Supported
 F:	drivers/target/
 F:	include/target/
@@ -6571,9 +6623,10 @@
 TEGRA SUPPORT
 M:	Colin Cross <ccross@android.com>
 M:	Olof Johansson <olof@lixom.net>
-M:	Stephen Warren <swarren@nvidia.com>
+M:	Stephen Warren <swarren@wwwdotorg.org>
 L:	linux-tegra@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/olof/tegra.git
+Q:	http://patchwork.ozlabs.org/project/linux-tegra/list/
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra.git
 S:	Supported
 F:	arch/arm/mach-tegra
 
@@ -6724,7 +6777,7 @@
 TTY LAYER
 M:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 S:	Supported
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
 F:	drivers/tty/
 F:	drivers/tty/serial/serial_core.c
 F:	include/linux/serial_core.h
@@ -6892,7 +6945,7 @@
 M:	Luca Risolia <luca.risolia@studio.unibo.it>
 L:	linux-usb@vger.kernel.org
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:	http://www.linux-projects.org
 S:	Maintained
 F:	drivers/media/video/et61x251/
@@ -7048,7 +7101,7 @@
 M:	Luca Risolia <luca.risolia@studio.unibo.it>
 L:	linux-usb@vger.kernel.org
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:	http://www.linux-projects.org
 S:	Maintained
 F:	Documentation/video4linux/sn9c102.txt
@@ -7058,7 +7111,7 @@
 M:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 L:	linux-usb@vger.kernel.org
 W:	http://www.linux-usb.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
 S:	Supported
 F:	Documentation/usb/
 F:	drivers/net/usb/
@@ -7084,7 +7137,7 @@
 M:	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:	linux-uvc-devel@lists.berlios.de (subscribers-only)
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:	http://www.ideasonboard.org/uvc/
 S:	Maintained
 F:	drivers/media/video/uvc/
@@ -7093,7 +7146,7 @@
 M:	Luca Risolia <luca.risolia@studio.unibo.it>
 L:	linux-usb@vger.kernel.org
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:	http://www.linux-projects.org
 S:	Maintained
 F:	Documentation/video4linux/w9968cf.txt
@@ -7122,7 +7175,7 @@
 M:	Antoine Jacquet <royale@zerezo.com>
 L:	linux-usb@vger.kernel.org
 L:	linux-media@vger.kernel.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:	http://royale.zerezo.com/zr364xx/
 S:	Maintained
 F:	Documentation/video4linux/zr364xx.txt
@@ -7272,7 +7325,7 @@
 M:	Mark Brown <broonie@opensource.wolfsonmicro.com>
 W:	http://opensource.wolfsonmicro.com/node/15
 W:	http://www.slimlogic.co.uk/?p=48
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6.git
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/lrg/regulator.git
 S:	Supported
 F:	drivers/regulator/
 F:	include/linux/regulator/
diff --git a/Makefile b/Makefile
index 1932984..5e637c2 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
-PATCHLEVEL = 3
+PATCHLEVEL = 4
 SUBLEVEL = 0
-EXTRAVERSION =
+EXTRAVERSION = -rc1
 NAME = Saber-toothed Squirrel
 
 # *DOCUMENTATION*
@@ -1170,7 +1170,7 @@
 #
 clean: rm-dirs  := $(CLEAN_DIRS)
 clean: rm-files := $(CLEAN_FILES)
-clean-dirs      := $(addprefix _clean_, . $(vmlinux-alldirs) Documentation)
+clean-dirs      := $(addprefix _clean_, . $(vmlinux-alldirs) Documentation samples)
 
 PHONY += $(clean-dirs) clean archclean
 $(clean-dirs):
diff --git a/arch/Kconfig b/arch/Kconfig
index 5b448a7..684eb5a 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -120,6 +120,9 @@
 
 config HAVE_OPTPROBES
 	bool
+
+config HAVE_NMI_WATCHDOG
+	bool
 #
 # An arch should select this if it provides all these things:
 #
@@ -210,4 +213,7 @@
 config HAVE_CMPXCHG_DOUBLE
 	bool
 
+config ARCH_WANT_OLD_COMPAT_IPC
+	bool
+
 source "kernel/gcov/Kconfig"
diff --git a/arch/alpha/boot/bootp.c b/arch/alpha/boot/bootp.c
index be61670..2a542a5 100644
--- a/arch/alpha/boot/bootp.c
+++ b/arch/alpha/boot/bootp.c
@@ -13,7 +13,6 @@
 #include <generated/utsrelease.h>
 #include <linux/mm.h>
 
-#include <asm/system.h>
 #include <asm/console.h>
 #include <asm/hwrpb.h>
 #include <asm/pgtable.h>
diff --git a/arch/alpha/boot/bootpz.c b/arch/alpha/boot/bootpz.c
index c98865f..d6ad191 100644
--- a/arch/alpha/boot/bootpz.c
+++ b/arch/alpha/boot/bootpz.c
@@ -15,7 +15,6 @@
 #include <generated/utsrelease.h>
 #include <linux/mm.h>
 
-#include <asm/system.h>
 #include <asm/console.h>
 #include <asm/hwrpb.h>
 #include <asm/pgtable.h>
diff --git a/arch/alpha/boot/head.S b/arch/alpha/boot/head.S
index f3d9808..b06812b 100644
--- a/arch/alpha/boot/head.S
+++ b/arch/alpha/boot/head.S
@@ -4,7 +4,6 @@
  * initial bootloader stuff..
  */
 
-#include <asm/system.h>
 
 	.set noreorder
 	.globl	__start
diff --git a/arch/alpha/boot/main.c b/arch/alpha/boot/main.c
index ded57d9..3baf2d1 100644
--- a/arch/alpha/boot/main.c
+++ b/arch/alpha/boot/main.c
@@ -11,7 +11,6 @@
 #include <generated/utsrelease.h>
 #include <linux/mm.h>
 
-#include <asm/system.h>
 #include <asm/console.h>
 #include <asm/hwrpb.h>
 #include <asm/pgtable.h>
diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h
index 640f909..f62251e 100644
--- a/arch/alpha/include/asm/atomic.h
+++ b/arch/alpha/include/asm/atomic.h
@@ -3,7 +3,6 @@
 
 #include <linux/types.h>
 #include <asm/barrier.h>
-#include <asm/system.h>
 
 /*
  * Atomic operations that C can't guarantee us.  Useful for
@@ -169,6 +168,73 @@
 	return result;
 }
 
+/*
+ * Atomic exchange routines.
+ */
+
+#define __ASM__MB
+#define ____xchg(type, args...)		__xchg ## type ## _local(args)
+#define ____cmpxchg(type, args...)	__cmpxchg ## type ## _local(args)
+#include <asm/xchg.h>
+
+#define xchg_local(ptr,x)						\
+  ({									\
+     __typeof__(*(ptr)) _x_ = (x);					\
+     (__typeof__(*(ptr))) __xchg_local((ptr), (unsigned long)_x_,	\
+				       sizeof(*(ptr)));			\
+  })
+
+#define cmpxchg_local(ptr, o, n)					\
+  ({									\
+     __typeof__(*(ptr)) _o_ = (o);					\
+     __typeof__(*(ptr)) _n_ = (n);					\
+     (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,	\
+					  (unsigned long)_n_,		\
+					  sizeof(*(ptr)));		\
+  })
+
+#define cmpxchg64_local(ptr, o, n)					\
+  ({									\
+	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
+	cmpxchg_local((ptr), (o), (n));					\
+  })
+
+#ifdef CONFIG_SMP
+#undef __ASM__MB
+#define __ASM__MB	"\tmb\n"
+#endif
+#undef ____xchg
+#undef ____cmpxchg
+#define ____xchg(type, args...)		__xchg ##type(args)
+#define ____cmpxchg(type, args...)	__cmpxchg ##type(args)
+#include <asm/xchg.h>
+
+#define xchg(ptr,x)							\
+  ({									\
+     __typeof__(*(ptr)) _x_ = (x);					\
+     (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_,		\
+				 sizeof(*(ptr)));			\
+  })
+
+#define cmpxchg(ptr, o, n)						\
+  ({									\
+     __typeof__(*(ptr)) _o_ = (o);					\
+     __typeof__(*(ptr)) _n_ = (n);					\
+     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		\
+				    (unsigned long)_n_,	sizeof(*(ptr)));\
+  })
+
+#define cmpxchg64(ptr, o, n)						\
+  ({									\
+	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
+	cmpxchg((ptr), (o), (n));					\
+  })
+
+#undef __ASM__MB
+#undef ____cmpxchg
+
+#define __HAVE_ARCH_CMPXCHG 1
+
 #define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
 #define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
 
diff --git a/arch/alpha/include/asm/auxvec.h b/arch/alpha/include/asm/auxvec.h
index e96fe88..a3a579d 100644
--- a/arch/alpha/include/asm/auxvec.h
+++ b/arch/alpha/include/asm/auxvec.h
@@ -21,4 +21,6 @@
 #define AT_L2_CACHESHAPE	36
 #define AT_L3_CACHESHAPE	37
 
+#define AT_VECTOR_SIZE_ARCH 4 /* entries in ARCH_DLINFO */
+
 #endif /* __ASM_ALPHA_AUXVEC_H */
diff --git a/arch/alpha/include/asm/core_lca.h b/arch/alpha/include/asm/core_lca.h
index f7cb4b4..8ee6c51 100644
--- a/arch/alpha/include/asm/core_lca.h
+++ b/arch/alpha/include/asm/core_lca.h
@@ -1,8 +1,8 @@
 #ifndef __ALPHA_LCA__H__
 #define __ALPHA_LCA__H__
 
-#include <asm/system.h>
 #include <asm/compiler.h>
+#include <asm/mce.h>
 
 /*
  * Low Cost Alpha (LCA) definitions (these apply to 21066 and 21068,
diff --git a/arch/alpha/include/asm/core_mcpcia.h b/arch/alpha/include/asm/core_mcpcia.h
index 9f67a05..ad44bef 100644
--- a/arch/alpha/include/asm/core_mcpcia.h
+++ b/arch/alpha/include/asm/core_mcpcia.h
@@ -7,6 +7,7 @@
 
 #include <linux/types.h>
 #include <asm/compiler.h>
+#include <asm/mce.h>
 
 /*
  * MCPCIA is the internal name for a core logic chipset which provides
diff --git a/arch/alpha/include/asm/core_t2.h b/arch/alpha/include/asm/core_t2.h
index 91b4680..ade9d92 100644
--- a/arch/alpha/include/asm/core_t2.h
+++ b/arch/alpha/include/asm/core_t2.h
@@ -7,7 +7,6 @@
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <asm/compiler.h>
-#include <asm/system.h>
 
 /*
  * T2 is the internal name for the core logic chipset which provides
diff --git a/arch/alpha/include/asm/dma-mapping.h b/arch/alpha/include/asm/dma-mapping.h
index 4567aca..dfa32f0 100644
--- a/arch/alpha/include/asm/dma-mapping.h
+++ b/arch/alpha/include/asm/dma-mapping.h
@@ -12,16 +12,22 @@
 
 #include <asm-generic/dma-mapping-common.h>
 
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-				       dma_addr_t *dma_handle, gfp_t gfp)
+#define dma_alloc_coherent(d,s,h,f)	dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+				    dma_addr_t *dma_handle, gfp_t gfp,
+				    struct dma_attrs *attrs)
 {
-	return get_dma_ops(dev)->alloc_coherent(dev, size, dma_handle, gfp);
+	return get_dma_ops(dev)->alloc(dev, size, dma_handle, gfp, attrs);
 }
 
-static inline void dma_free_coherent(struct device *dev, size_t size,
-				     void *vaddr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+				  void *vaddr, dma_addr_t dma_handle,
+				  struct dma_attrs *attrs)
 {
-	get_dma_ops(dev)->free_coherent(dev, size, vaddr, dma_handle);
+	get_dma_ops(dev)->free(dev, size, vaddr, dma_handle, attrs);
 }
 
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
diff --git a/arch/alpha/include/asm/elf.h b/arch/alpha/include/asm/elf.h
index da5449e..968d999 100644
--- a/arch/alpha/include/asm/elf.h
+++ b/arch/alpha/include/asm/elf.h
@@ -2,6 +2,7 @@
 #define __ASM_ALPHA_ELF_H
 
 #include <asm/auxvec.h>
+#include <asm/special_insns.h>
 
 /* Special values for the st_other field in the symbol table.  */
 
diff --git a/arch/alpha/include/asm/exec.h b/arch/alpha/include/asm/exec.h
new file mode 100644
index 0000000..4a5a41f
--- /dev/null
+++ b/arch/alpha/include/asm/exec.h
@@ -0,0 +1,6 @@
+#ifndef __ALPHA_EXEC_H
+#define __ALPHA_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* __ALPHA_EXEC_H */
diff --git a/arch/alpha/include/asm/fpu.h b/arch/alpha/include/asm/fpu.h
index ecb17a7..db00f78 100644
--- a/arch/alpha/include/asm/fpu.h
+++ b/arch/alpha/include/asm/fpu.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_ALPHA_FPU_H
 #define __ASM_ALPHA_FPU_H
 
+#include <asm/special_insns.h>
+
 /*
  * Alpha floating-point control register defines:
  */
diff --git a/arch/alpha/include/asm/io.h b/arch/alpha/include/asm/io.h
index 56ff965..7a3d38d 100644
--- a/arch/alpha/include/asm/io.h
+++ b/arch/alpha/include/asm/io.h
@@ -6,7 +6,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <asm/compiler.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/machvec.h>
 #include <asm/hwrpb.h>
diff --git a/arch/alpha/include/asm/irqflags.h b/arch/alpha/include/asm/irqflags.h
index 299bbc7..ffb1726 100644
--- a/arch/alpha/include/asm/irqflags.h
+++ b/arch/alpha/include/asm/irqflags.h
@@ -1,7 +1,7 @@
 #ifndef __ALPHA_IRQFLAGS_H
 #define __ALPHA_IRQFLAGS_H
 
-#include <asm/system.h>
+#include <asm/pal.h>
 
 #define IPL_MIN		0
 #define IPL_SW0		1
diff --git a/arch/alpha/include/asm/mce.h b/arch/alpha/include/asm/mce.h
new file mode 100644
index 0000000..660285b
--- /dev/null
+++ b/arch/alpha/include/asm/mce.h
@@ -0,0 +1,83 @@
+#ifndef __ALPHA_MCE_H
+#define __ALPHA_MCE_H
+
+/*
+ * This is the logout header that should be common to all platforms
+ * (assuming they are running OSF/1 PALcode, I guess).
+ */
+struct el_common {
+	unsigned int	size;		/* size in bytes of logout area */
+	unsigned int	sbz1	: 30;	/* should be zero */
+	unsigned int	err2	:  1;	/* second error */
+	unsigned int	retry	:  1;	/* retry flag */
+	unsigned int	proc_offset;	/* processor-specific offset */
+	unsigned int	sys_offset;	/* system-specific offset */
+	unsigned int	code;		/* machine check code */
+	unsigned int	frame_rev;	/* frame revision */
+};
+
+/* Machine Check Frame for uncorrectable errors (Large format)
+ *      --- This is used to log uncorrectable errors such as
+ *          double bit ECC errors.
+ *      --- These errors are detected by both processor and systems.
+ */
+struct el_common_EV5_uncorrectable_mcheck {
+        unsigned long   shadow[8];        /* Shadow reg. 8-14, 25           */
+        unsigned long   paltemp[24];      /* PAL TEMP REGS.                 */
+        unsigned long   exc_addr;         /* Address of excepting instruction*/
+        unsigned long   exc_sum;          /* Summary of arithmetic traps.   */
+        unsigned long   exc_mask;         /* Exception mask (from exc_sum). */
+        unsigned long   pal_base;         /* Base address for PALcode.      */
+        unsigned long   isr;              /* Interrupt Status Reg.          */
+        unsigned long   icsr;             /* CURRENT SETUP OF EV5 IBOX      */
+        unsigned long   ic_perr_stat;     /* I-CACHE Reg. <11> set Data parity
+                                                         <12> set TAG parity*/
+        unsigned long   dc_perr_stat;     /* D-CACHE error Reg. Bits set to 1:
+                                                     <2> Data error in bank 0
+                                                     <3> Data error in bank 1
+                                                     <4> Tag error in bank 0
+                                                     <5> Tag error in bank 1 */
+        unsigned long   va;               /* Effective VA of fault or miss. */
+        unsigned long   mm_stat;          /* Holds the reason for D-stream 
+                                             fault or D-cache parity errors */
+        unsigned long   sc_addr;          /* Address that was being accessed
+                                             when EV5 detected Secondary cache
+                                             failure.                 */
+        unsigned long   sc_stat;          /* Helps determine if the error was
+                                             TAG/Data parity(Secondary Cache)*/
+        unsigned long   bc_tag_addr;      /* Contents of EV5 BC_TAG_ADDR    */
+        unsigned long   ei_addr;          /* Physical address of any transfer
+                                             that is logged in EV5 EI_STAT */
+        unsigned long   fill_syndrome;    /* For correcting ECC errors.     */
+        unsigned long   ei_stat;          /* Helps identify reason of any 
+                                             processor uncorrectable error
+                                             at its external interface.     */
+        unsigned long   ld_lock;          /* Contents of EV5 LD_LOCK register*/
+};
+
+struct el_common_EV6_mcheck {
+	unsigned int FrameSize;		/* Bytes, including this field */
+	unsigned int FrameFlags;	/* <31> = Retry, <30> = Second Error */
+	unsigned int CpuOffset;		/* Offset to CPU-specific info */
+	unsigned int SystemOffset;	/* Offset to system-specific info */
+	unsigned int MCHK_Code;
+	unsigned int MCHK_Frame_Rev;
+	unsigned long I_STAT;		/* EV6 Internal Processor Registers */
+	unsigned long DC_STAT;		/* (See the 21264 Spec) */
+	unsigned long C_ADDR;
+	unsigned long DC1_SYNDROME;
+	unsigned long DC0_SYNDROME;
+	unsigned long C_STAT;
+	unsigned long C_STS;
+	unsigned long MM_STAT;
+	unsigned long EXC_ADDR;
+	unsigned long IER_CM;
+	unsigned long ISUM;
+	unsigned long RESERVED0;
+	unsigned long PAL_BASE;
+	unsigned long I_CTL;
+	unsigned long PCTX;
+};
+
+
+#endif /* __ALPHA_MCE_H */
diff --git a/arch/alpha/include/asm/mman.h b/arch/alpha/include/asm/mman.h
index 72db984..cbeb361 100644
--- a/arch/alpha/include/asm/mman.h
+++ b/arch/alpha/include/asm/mman.h
@@ -56,6 +56,10 @@
 #define MADV_HUGEPAGE	14		/* Worth backing with hugepages */
 #define MADV_NOHUGEPAGE	15		/* Not worth backing with hugepages */
 
+#define MADV_DONTDUMP   16		/* Explicity exclude from the core dump,
+					   overrides the coredump filter bits */
+#define MADV_DODUMP	17		/* Clear the MADV_NODUMP flag */
+
 /* compatibility flags */
 #define MAP_FILE	0
 
diff --git a/arch/alpha/include/asm/mmu_context.h b/arch/alpha/include/asm/mmu_context.h
index 86c08a0..4c51c05 100644
--- a/arch/alpha/include/asm/mmu_context.h
+++ b/arch/alpha/include/asm/mmu_context.h
@@ -7,7 +7,6 @@
  * Copyright (C) 1996, Linus Torvalds
  */
 
-#include <asm/system.h>
 #include <asm/machvec.h>
 #include <asm/compiler.h>
 #include <asm-generic/mm_hooks.h>
diff --git a/arch/alpha/include/asm/pal.h b/arch/alpha/include/asm/pal.h
index 9b4ba0d..6699ee5 100644
--- a/arch/alpha/include/asm/pal.h
+++ b/arch/alpha/include/asm/pal.h
@@ -48,4 +48,116 @@
 #define PAL_retsys	61
 #define PAL_rti		63
 
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+extern void halt(void) __attribute__((noreturn));
+#define __halt() __asm__ __volatile__ ("call_pal %0 #halt" : : "i" (PAL_halt))
+
+#define imb() \
+__asm__ __volatile__ ("call_pal %0 #imb" : : "i" (PAL_imb) : "memory")
+
+#define draina() \
+__asm__ __volatile__ ("call_pal %0 #draina" : : "i" (PAL_draina) : "memory")
+
+#define __CALL_PAL_R0(NAME, TYPE)				\
+extern inline TYPE NAME(void)					\
+{								\
+	register TYPE __r0 __asm__("$0");			\
+	__asm__ __volatile__(					\
+		"call_pal %1 # " #NAME				\
+		:"=r" (__r0)					\
+		:"i" (PAL_ ## NAME)				\
+		:"$1", "$16", "$22", "$23", "$24", "$25");	\
+	return __r0;						\
+}
+
+#define __CALL_PAL_W1(NAME, TYPE0)				\
+extern inline void NAME(TYPE0 arg0)				\
+{								\
+	register TYPE0 __r16 __asm__("$16") = arg0;		\
+	__asm__ __volatile__(					\
+		"call_pal %1 # "#NAME				\
+		: "=r"(__r16)					\
+		: "i"(PAL_ ## NAME), "0"(__r16)			\
+		: "$1", "$22", "$23", "$24", "$25");		\
+}
+
+#define __CALL_PAL_W2(NAME, TYPE0, TYPE1)			\
+extern inline void NAME(TYPE0 arg0, TYPE1 arg1)			\
+{								\
+	register TYPE0 __r16 __asm__("$16") = arg0;		\
+	register TYPE1 __r17 __asm__("$17") = arg1;		\
+	__asm__ __volatile__(					\
+		"call_pal %2 # "#NAME				\
+		: "=r"(__r16), "=r"(__r17)			\
+		: "i"(PAL_ ## NAME), "0"(__r16), "1"(__r17)	\
+		: "$1", "$22", "$23", "$24", "$25");		\
+}
+
+#define __CALL_PAL_RW1(NAME, RTYPE, TYPE0)			\
+extern inline RTYPE NAME(TYPE0 arg0)				\
+{								\
+	register RTYPE __r0 __asm__("$0");			\
+	register TYPE0 __r16 __asm__("$16") = arg0;		\
+	__asm__ __volatile__(					\
+		"call_pal %2 # "#NAME				\
+		: "=r"(__r16), "=r"(__r0)			\
+		: "i"(PAL_ ## NAME), "0"(__r16)			\
+		: "$1", "$22", "$23", "$24", "$25");		\
+	return __r0;						\
+}
+
+#define __CALL_PAL_RW2(NAME, RTYPE, TYPE0, TYPE1)		\
+extern inline RTYPE NAME(TYPE0 arg0, TYPE1 arg1)		\
+{								\
+	register RTYPE __r0 __asm__("$0");			\
+	register TYPE0 __r16 __asm__("$16") = arg0;		\
+	register TYPE1 __r17 __asm__("$17") = arg1;		\
+	__asm__ __volatile__(					\
+		"call_pal %3 # "#NAME				\
+		: "=r"(__r16), "=r"(__r17), "=r"(__r0)		\
+		: "i"(PAL_ ## NAME), "0"(__r16), "1"(__r17)	\
+		: "$1", "$22", "$23", "$24", "$25");		\
+	return __r0;						\
+}
+
+__CALL_PAL_W1(cflush, unsigned long);
+__CALL_PAL_R0(rdmces, unsigned long);
+__CALL_PAL_R0(rdps, unsigned long);
+__CALL_PAL_R0(rdusp, unsigned long);
+__CALL_PAL_RW1(swpipl, unsigned long, unsigned long);
+__CALL_PAL_R0(whami, unsigned long);
+__CALL_PAL_W2(wrent, void*, unsigned long);
+__CALL_PAL_W1(wripir, unsigned long);
+__CALL_PAL_W1(wrkgp, unsigned long);
+__CALL_PAL_W1(wrmces, unsigned long);
+__CALL_PAL_RW2(wrperfmon, unsigned long, unsigned long, unsigned long);
+__CALL_PAL_W1(wrusp, unsigned long);
+__CALL_PAL_W1(wrvptptr, unsigned long);
+
+/*
+ * TB routines..
+ */
+#define __tbi(nr,arg,arg1...)					\
+({								\
+	register unsigned long __r16 __asm__("$16") = (nr);	\
+	register unsigned long __r17 __asm__("$17"); arg;	\
+	__asm__ __volatile__(					\
+		"call_pal %3 #__tbi"				\
+		:"=r" (__r16),"=r" (__r17)			\
+		:"0" (__r16),"i" (PAL_tbi) ,##arg1		\
+		:"$0", "$1", "$22", "$23", "$24", "$25");	\
+})
+
+#define tbi(x,y)	__tbi(x,__r17=(y),"1" (__r17))
+#define tbisi(x)	__tbi(1,__r17=(x),"1" (__r17))
+#define tbisd(x)	__tbi(2,__r17=(x),"1" (__r17))
+#define tbis(x)		__tbi(3,__r17=(x),"1" (__r17))
+#define tbiap()		__tbi(-1, /* no second argument */)
+#define tbia()		__tbi(-2, /* no second argument */)
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __KERNEL__ */
+
 #endif /* __ALPHA_PAL_H */
diff --git a/arch/alpha/include/asm/pci.h b/arch/alpha/include/asm/pci.h
index 28d0497..d01afb7 100644
--- a/arch/alpha/include/asm/pci.h
+++ b/arch/alpha/include/asm/pci.h
@@ -7,6 +7,7 @@
 #include <linux/dma-mapping.h>
 #include <asm/scatterlist.h>
 #include <asm/machvec.h>
+#include <asm-generic/pci-bridge.h>
 
 /*
  * The following structure is used to manage multiple PCI busses.
@@ -99,12 +100,6 @@
 	return channel ? 15 : 14;
 }
 
-extern void pcibios_resource_to_bus(struct pci_dev *, struct pci_bus_region *,
-				    struct resource *);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-				    struct pci_bus_region *region);
-
 #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
 
 static inline int pci_proc_domain(struct pci_bus *bus)
diff --git a/arch/alpha/include/asm/pgtable.h b/arch/alpha/include/asm/pgtable.h
index de98a73..81a4342 100644
--- a/arch/alpha/include/asm/pgtable.h
+++ b/arch/alpha/include/asm/pgtable.h
@@ -15,6 +15,7 @@
 #include <asm/page.h>
 #include <asm/processor.h>	/* For TASK_SIZE */
 #include <asm/machvec.h>
+#include <asm/setup.h>
 
 struct mm_struct;
 struct vm_area_struct;
diff --git a/arch/alpha/include/asm/posix_types.h b/arch/alpha/include/asm/posix_types.h
index db16741..24779fc 100644
--- a/arch/alpha/include/asm/posix_types.h
+++ b/arch/alpha/include/asm/posix_types.h
@@ -8,116 +8,13 @@
  */
 
 typedef unsigned int	__kernel_ino_t;
-typedef unsigned int	__kernel_mode_t;
+#define __kernel_ino_t __kernel_ino_t
+
 typedef unsigned int	__kernel_nlink_t;
-typedef long		__kernel_off_t;
-typedef long long	__kernel_loff_t;
-typedef int		__kernel_pid_t;
-typedef int		__kernel_ipc_pid_t;
-typedef unsigned int	__kernel_uid_t;
-typedef unsigned int	__kernel_gid_t;
-typedef unsigned long	__kernel_size_t;
-typedef long		__kernel_ssize_t;
-typedef long		__kernel_ptrdiff_t;
-typedef long		__kernel_time_t;
-typedef long		__kernel_suseconds_t;
-typedef long		__kernel_clock_t;
-typedef int		__kernel_daddr_t;
-typedef char *		__kernel_caddr_t;
+#define __kernel_nlink_t __kernel_nlink_t
+
 typedef unsigned long	__kernel_sigset_t;	/* at least 32 bits */
-typedef unsigned short	__kernel_uid16_t;
-typedef unsigned short	__kernel_gid16_t;
-typedef int		__kernel_clockid_t;
-typedef int		__kernel_timer_t;
 
-typedef struct {
-	int	val[2];
-} __kernel_fsid_t;
-
-typedef __kernel_uid_t __kernel_old_uid_t;
-typedef __kernel_gid_t __kernel_old_gid_t;
-typedef __kernel_uid_t __kernel_uid32_t;
-typedef __kernel_gid_t __kernel_gid32_t;
-
-typedef unsigned int	__kernel_old_dev_t;
-
-#ifdef __KERNEL__
-
-#ifndef __GNUC__
-
-#define	__FD_SET(d, set)	((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
-#define	__FD_CLR(d, set)	((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
-#define	__FD_ISSET(d, set)	(((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) != 0)
-#define	__FD_ZERO(set)	\
-  ((void) memset ((void *) (set), 0, sizeof (__kernel_fd_set)))
-
-#else /* __GNUC__ */
-
-/* With GNU C, use inline functions instead so args are evaluated only once: */
-
-#undef __FD_SET
-static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	fdsetp->fds_bits[_tmp] |= (1UL<<_rem);
-}
-
-#undef __FD_CLR
-static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem);
-}
-
-#undef __FD_ISSET
-static __inline__ int __FD_ISSET(unsigned long fd, const __kernel_fd_set *p)
-{ 
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0;
-}
-
-/*
- * This will unroll the loop for the normal constant case (8 ints,
- * for a 256-bit fd_set)
- */
-#undef __FD_ZERO
-static __inline__ void __FD_ZERO(__kernel_fd_set *p)
-{
-	unsigned long *tmp = p->fds_bits;
-	int i;
-
-	if (__builtin_constant_p(__FDSET_LONGS)) {
-		switch (__FDSET_LONGS) {
-		      case 16:
-			tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
-			tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
-			tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
-			tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
-			return;
-
-		      case 8:
-			tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
-			tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
-			return;
-
-		      case 4:
-			tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
-			return;
-		}
-	}
-	i = __FDSET_LONGS;
-	while (i) {
-		i--;
-		*tmp = 0;
-		tmp++;
-	}
-}
-
-#endif /* __GNUC__ */
-
-#endif /* __KERNEL__ */
+#include <asm-generic/posix_types.h>
 
 #endif /* _ALPHA_POSIX_TYPES_H */
diff --git a/arch/alpha/include/asm/setup.h b/arch/alpha/include/asm/setup.h
index 2e023a4..b50014b 100644
--- a/arch/alpha/include/asm/setup.h
+++ b/arch/alpha/include/asm/setup.h
@@ -3,4 +3,40 @@
 
 #define COMMAND_LINE_SIZE	256
 
+/*
+ * We leave one page for the initial stack page, and one page for
+ * the initial process structure. Also, the console eats 3 MB for
+ * the initial bootloader (one of which we can reclaim later).
+ */
+#define BOOT_PCB	0x20000000
+#define BOOT_ADDR	0x20000000
+/* Remove when official MILO sources have ELF support: */
+#define BOOT_SIZE	(16*1024)
+
+#ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS
+#define KERNEL_START_PHYS	0x300000 /* Old bootloaders hardcoded this.  */
+#else
+#define KERNEL_START_PHYS	0x1000000 /* required: Wildfire/Titan/Marvel */
+#endif
+
+#define KERNEL_START	(PAGE_OFFSET+KERNEL_START_PHYS)
+#define SWAPPER_PGD	KERNEL_START
+#define INIT_STACK	(PAGE_OFFSET+KERNEL_START_PHYS+0x02000)
+#define EMPTY_PGT	(PAGE_OFFSET+KERNEL_START_PHYS+0x04000)
+#define EMPTY_PGE	(PAGE_OFFSET+KERNEL_START_PHYS+0x08000)
+#define ZERO_PGE	(PAGE_OFFSET+KERNEL_START_PHYS+0x0A000)
+
+#define START_ADDR	(PAGE_OFFSET+KERNEL_START_PHYS+0x10000)
+
+/*
+ * This is setup by the secondary bootstrap loader.  Because
+ * the zero page is zeroed out as soon as the vm system is
+ * initialized, we need to copy things out into a more permanent
+ * place.
+ */
+#define PARAM			ZERO_PGE
+#define COMMAND_LINE		((char*)(PARAM + 0x0000))
+#define INITRD_START		(*(unsigned long *) (PARAM+0x100))
+#define INITRD_SIZE		(*(unsigned long *) (PARAM+0x108))
+
 #endif
diff --git a/arch/alpha/include/asm/special_insns.h b/arch/alpha/include/asm/special_insns.h
new file mode 100644
index 0000000..88d3452
--- /dev/null
+++ b/arch/alpha/include/asm/special_insns.h
@@ -0,0 +1,41 @@
+#ifndef __ALPHA_SPECIAL_INSNS_H
+#define __ALPHA_SPECIAL_INSNS_H
+
+enum implver_enum {
+	IMPLVER_EV4,
+	IMPLVER_EV5,
+	IMPLVER_EV6
+};
+
+#ifdef CONFIG_ALPHA_GENERIC
+#define implver()				\
+({ unsigned long __implver;			\
+   __asm__ ("implver %0" : "=r"(__implver));	\
+   (enum implver_enum) __implver; })
+#else
+/* Try to eliminate some dead code.  */
+#ifdef CONFIG_ALPHA_EV4
+#define implver() IMPLVER_EV4
+#endif
+#ifdef CONFIG_ALPHA_EV5
+#define implver() IMPLVER_EV5
+#endif
+#if defined(CONFIG_ALPHA_EV6)
+#define implver() IMPLVER_EV6
+#endif
+#endif
+
+enum amask_enum {
+	AMASK_BWX = (1UL << 0),
+	AMASK_FIX = (1UL << 1),
+	AMASK_CIX = (1UL << 2),
+	AMASK_MAX = (1UL << 8),
+	AMASK_PRECISE_TRAP = (1UL << 9),
+};
+
+#define amask(mask)						\
+({ unsigned long __amask, __input = (mask);			\
+   __asm__ ("amask %1,%0" : "=r"(__amask) : "rI"(__input));	\
+   __amask; })
+
+#endif /* __ALPHA_SPECIAL_INSNS_H */
diff --git a/arch/alpha/include/asm/spinlock.h b/arch/alpha/include/asm/spinlock.h
index d0faca1..3bba21e 100644
--- a/arch/alpha/include/asm/spinlock.h
+++ b/arch/alpha/include/asm/spinlock.h
@@ -1,7 +1,6 @@
 #ifndef _ALPHA_SPINLOCK_H
 #define _ALPHA_SPINLOCK_H
 
-#include <asm/system.h>
 #include <linux/kernel.h>
 #include <asm/current.h>
 
diff --git a/arch/alpha/include/asm/switch_to.h b/arch/alpha/include/asm/switch_to.h
new file mode 100644
index 0000000..44c0d4f
--- /dev/null
+++ b/arch/alpha/include/asm/switch_to.h
@@ -0,0 +1,14 @@
+#ifndef __ALPHA_SWITCH_TO_H
+#define __ALPHA_SWITCH_TO_H
+
+
+struct task_struct;
+extern struct task_struct *alpha_switch_to(unsigned long, struct task_struct *);
+
+#define switch_to(P,N,L)						 \
+  do {									 \
+    (L) = alpha_switch_to(virt_to_phys(&task_thread_info(N)->pcb), (P)); \
+    check_mmu_context();						 \
+  } while (0)
+
+#endif /* __ALPHA_SWITCH_TO_H */
diff --git a/arch/alpha/include/asm/system.h b/arch/alpha/include/asm/system.h
deleted file mode 100644
index 9f78e69..0000000
--- a/arch/alpha/include/asm/system.h
+++ /dev/null
@@ -1,354 +0,0 @@
-#ifndef __ALPHA_SYSTEM_H
-#define __ALPHA_SYSTEM_H
-
-#include <asm/pal.h>
-#include <asm/page.h>
-#include <asm/barrier.h>
-
-/*
- * System defines.. Note that this is included both from .c and .S
- * files, so it does only defines, not any C code.
- */
-
-/*
- * We leave one page for the initial stack page, and one page for
- * the initial process structure. Also, the console eats 3 MB for
- * the initial bootloader (one of which we can reclaim later).
- */
-#define BOOT_PCB	0x20000000
-#define BOOT_ADDR	0x20000000
-/* Remove when official MILO sources have ELF support: */
-#define BOOT_SIZE	(16*1024)
-
-#ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS
-#define KERNEL_START_PHYS	0x300000 /* Old bootloaders hardcoded this.  */
-#else
-#define KERNEL_START_PHYS	0x1000000 /* required: Wildfire/Titan/Marvel */
-#endif
-
-#define KERNEL_START	(PAGE_OFFSET+KERNEL_START_PHYS)
-#define SWAPPER_PGD	KERNEL_START
-#define INIT_STACK	(PAGE_OFFSET+KERNEL_START_PHYS+0x02000)
-#define EMPTY_PGT	(PAGE_OFFSET+KERNEL_START_PHYS+0x04000)
-#define EMPTY_PGE	(PAGE_OFFSET+KERNEL_START_PHYS+0x08000)
-#define ZERO_PGE	(PAGE_OFFSET+KERNEL_START_PHYS+0x0A000)
-
-#define START_ADDR	(PAGE_OFFSET+KERNEL_START_PHYS+0x10000)
-
-/*
- * This is setup by the secondary bootstrap loader.  Because
- * the zero page is zeroed out as soon as the vm system is
- * initialized, we need to copy things out into a more permanent
- * place.
- */
-#define PARAM			ZERO_PGE
-#define COMMAND_LINE		((char*)(PARAM + 0x0000))
-#define INITRD_START		(*(unsigned long *) (PARAM+0x100))
-#define INITRD_SIZE		(*(unsigned long *) (PARAM+0x108))
-
-#ifndef __ASSEMBLY__
-#include <linux/kernel.h>
-#define AT_VECTOR_SIZE_ARCH 4 /* entries in ARCH_DLINFO */
-
-/*
- * This is the logout header that should be common to all platforms
- * (assuming they are running OSF/1 PALcode, I guess).
- */
-struct el_common {
-	unsigned int	size;		/* size in bytes of logout area */
-	unsigned int	sbz1	: 30;	/* should be zero */
-	unsigned int	err2	:  1;	/* second error */
-	unsigned int	retry	:  1;	/* retry flag */
-	unsigned int	proc_offset;	/* processor-specific offset */
-	unsigned int	sys_offset;	/* system-specific offset */
-	unsigned int	code;		/* machine check code */
-	unsigned int	frame_rev;	/* frame revision */
-};
-
-/* Machine Check Frame for uncorrectable errors (Large format)
- *      --- This is used to log uncorrectable errors such as
- *          double bit ECC errors.
- *      --- These errors are detected by both processor and systems.
- */
-struct el_common_EV5_uncorrectable_mcheck {
-        unsigned long   shadow[8];        /* Shadow reg. 8-14, 25           */
-        unsigned long   paltemp[24];      /* PAL TEMP REGS.                 */
-        unsigned long   exc_addr;         /* Address of excepting instruction*/
-        unsigned long   exc_sum;          /* Summary of arithmetic traps.   */
-        unsigned long   exc_mask;         /* Exception mask (from exc_sum). */
-        unsigned long   pal_base;         /* Base address for PALcode.      */
-        unsigned long   isr;              /* Interrupt Status Reg.          */
-        unsigned long   icsr;             /* CURRENT SETUP OF EV5 IBOX      */
-        unsigned long   ic_perr_stat;     /* I-CACHE Reg. <11> set Data parity
-                                                         <12> set TAG parity*/
-        unsigned long   dc_perr_stat;     /* D-CACHE error Reg. Bits set to 1:
-                                                     <2> Data error in bank 0
-                                                     <3> Data error in bank 1
-                                                     <4> Tag error in bank 0
-                                                     <5> Tag error in bank 1 */
-        unsigned long   va;               /* Effective VA of fault or miss. */
-        unsigned long   mm_stat;          /* Holds the reason for D-stream 
-                                             fault or D-cache parity errors */
-        unsigned long   sc_addr;          /* Address that was being accessed
-                                             when EV5 detected Secondary cache
-                                             failure.                 */
-        unsigned long   sc_stat;          /* Helps determine if the error was
-                                             TAG/Data parity(Secondary Cache)*/
-        unsigned long   bc_tag_addr;      /* Contents of EV5 BC_TAG_ADDR    */
-        unsigned long   ei_addr;          /* Physical address of any transfer
-                                             that is logged in EV5 EI_STAT */
-        unsigned long   fill_syndrome;    /* For correcting ECC errors.     */
-        unsigned long   ei_stat;          /* Helps identify reason of any 
-                                             processor uncorrectable error
-                                             at its external interface.     */
-        unsigned long   ld_lock;          /* Contents of EV5 LD_LOCK register*/
-};
-
-struct el_common_EV6_mcheck {
-	unsigned int FrameSize;		/* Bytes, including this field */
-	unsigned int FrameFlags;	/* <31> = Retry, <30> = Second Error */
-	unsigned int CpuOffset;		/* Offset to CPU-specific info */
-	unsigned int SystemOffset;	/* Offset to system-specific info */
-	unsigned int MCHK_Code;
-	unsigned int MCHK_Frame_Rev;
-	unsigned long I_STAT;		/* EV6 Internal Processor Registers */
-	unsigned long DC_STAT;		/* (See the 21264 Spec) */
-	unsigned long C_ADDR;
-	unsigned long DC1_SYNDROME;
-	unsigned long DC0_SYNDROME;
-	unsigned long C_STAT;
-	unsigned long C_STS;
-	unsigned long MM_STAT;
-	unsigned long EXC_ADDR;
-	unsigned long IER_CM;
-	unsigned long ISUM;
-	unsigned long RESERVED0;
-	unsigned long PAL_BASE;
-	unsigned long I_CTL;
-	unsigned long PCTX;
-};
-
-extern void halt(void) __attribute__((noreturn));
-#define __halt() __asm__ __volatile__ ("call_pal %0 #halt" : : "i" (PAL_halt))
-
-#define switch_to(P,N,L)						 \
-  do {									 \
-    (L) = alpha_switch_to(virt_to_phys(&task_thread_info(N)->pcb), (P)); \
-    check_mmu_context();						 \
-  } while (0)
-
-struct task_struct;
-extern struct task_struct *alpha_switch_to(unsigned long, struct task_struct*);
-
-#define imb() \
-__asm__ __volatile__ ("call_pal %0 #imb" : : "i" (PAL_imb) : "memory")
-
-#define draina() \
-__asm__ __volatile__ ("call_pal %0 #draina" : : "i" (PAL_draina) : "memory")
-
-enum implver_enum {
-	IMPLVER_EV4,
-	IMPLVER_EV5,
-	IMPLVER_EV6
-};
-
-#ifdef CONFIG_ALPHA_GENERIC
-#define implver()				\
-({ unsigned long __implver;			\
-   __asm__ ("implver %0" : "=r"(__implver));	\
-   (enum implver_enum) __implver; })
-#else
-/* Try to eliminate some dead code.  */
-#ifdef CONFIG_ALPHA_EV4
-#define implver() IMPLVER_EV4
-#endif
-#ifdef CONFIG_ALPHA_EV5
-#define implver() IMPLVER_EV5
-#endif
-#if defined(CONFIG_ALPHA_EV6)
-#define implver() IMPLVER_EV6
-#endif
-#endif
-
-enum amask_enum {
-	AMASK_BWX = (1UL << 0),
-	AMASK_FIX = (1UL << 1),
-	AMASK_CIX = (1UL << 2),
-	AMASK_MAX = (1UL << 8),
-	AMASK_PRECISE_TRAP = (1UL << 9),
-};
-
-#define amask(mask)						\
-({ unsigned long __amask, __input = (mask);			\
-   __asm__ ("amask %1,%0" : "=r"(__amask) : "rI"(__input));	\
-   __amask; })
-
-#define __CALL_PAL_R0(NAME, TYPE)				\
-extern inline TYPE NAME(void)					\
-{								\
-	register TYPE __r0 __asm__("$0");			\
-	__asm__ __volatile__(					\
-		"call_pal %1 # " #NAME				\
-		:"=r" (__r0)					\
-		:"i" (PAL_ ## NAME)				\
-		:"$1", "$16", "$22", "$23", "$24", "$25");	\
-	return __r0;						\
-}
-
-#define __CALL_PAL_W1(NAME, TYPE0)				\
-extern inline void NAME(TYPE0 arg0)				\
-{								\
-	register TYPE0 __r16 __asm__("$16") = arg0;		\
-	__asm__ __volatile__(					\
-		"call_pal %1 # "#NAME				\
-		: "=r"(__r16)					\
-		: "i"(PAL_ ## NAME), "0"(__r16)			\
-		: "$1", "$22", "$23", "$24", "$25");		\
-}
-
-#define __CALL_PAL_W2(NAME, TYPE0, TYPE1)			\
-extern inline void NAME(TYPE0 arg0, TYPE1 arg1)			\
-{								\
-	register TYPE0 __r16 __asm__("$16") = arg0;		\
-	register TYPE1 __r17 __asm__("$17") = arg1;		\
-	__asm__ __volatile__(					\
-		"call_pal %2 # "#NAME				\
-		: "=r"(__r16), "=r"(__r17)			\
-		: "i"(PAL_ ## NAME), "0"(__r16), "1"(__r17)	\
-		: "$1", "$22", "$23", "$24", "$25");		\
-}
-
-#define __CALL_PAL_RW1(NAME, RTYPE, TYPE0)			\
-extern inline RTYPE NAME(TYPE0 arg0)				\
-{								\
-	register RTYPE __r0 __asm__("$0");			\
-	register TYPE0 __r16 __asm__("$16") = arg0;		\
-	__asm__ __volatile__(					\
-		"call_pal %2 # "#NAME				\
-		: "=r"(__r16), "=r"(__r0)			\
-		: "i"(PAL_ ## NAME), "0"(__r16)			\
-		: "$1", "$22", "$23", "$24", "$25");		\
-	return __r0;						\
-}
-
-#define __CALL_PAL_RW2(NAME, RTYPE, TYPE0, TYPE1)		\
-extern inline RTYPE NAME(TYPE0 arg0, TYPE1 arg1)		\
-{								\
-	register RTYPE __r0 __asm__("$0");			\
-	register TYPE0 __r16 __asm__("$16") = arg0;		\
-	register TYPE1 __r17 __asm__("$17") = arg1;		\
-	__asm__ __volatile__(					\
-		"call_pal %3 # "#NAME				\
-		: "=r"(__r16), "=r"(__r17), "=r"(__r0)		\
-		: "i"(PAL_ ## NAME), "0"(__r16), "1"(__r17)	\
-		: "$1", "$22", "$23", "$24", "$25");		\
-	return __r0;						\
-}
-
-__CALL_PAL_W1(cflush, unsigned long);
-__CALL_PAL_R0(rdmces, unsigned long);
-__CALL_PAL_R0(rdps, unsigned long);
-__CALL_PAL_R0(rdusp, unsigned long);
-__CALL_PAL_RW1(swpipl, unsigned long, unsigned long);
-__CALL_PAL_R0(whami, unsigned long);
-__CALL_PAL_W2(wrent, void*, unsigned long);
-__CALL_PAL_W1(wripir, unsigned long);
-__CALL_PAL_W1(wrkgp, unsigned long);
-__CALL_PAL_W1(wrmces, unsigned long);
-__CALL_PAL_RW2(wrperfmon, unsigned long, unsigned long, unsigned long);
-__CALL_PAL_W1(wrusp, unsigned long);
-__CALL_PAL_W1(wrvptptr, unsigned long);
-
-/*
- * TB routines..
- */
-#define __tbi(nr,arg,arg1...)					\
-({								\
-	register unsigned long __r16 __asm__("$16") = (nr);	\
-	register unsigned long __r17 __asm__("$17"); arg;	\
-	__asm__ __volatile__(					\
-		"call_pal %3 #__tbi"				\
-		:"=r" (__r16),"=r" (__r17)			\
-		:"0" (__r16),"i" (PAL_tbi) ,##arg1		\
-		:"$0", "$1", "$22", "$23", "$24", "$25");	\
-})
-
-#define tbi(x,y)	__tbi(x,__r17=(y),"1" (__r17))
-#define tbisi(x)	__tbi(1,__r17=(x),"1" (__r17))
-#define tbisd(x)	__tbi(2,__r17=(x),"1" (__r17))
-#define tbis(x)		__tbi(3,__r17=(x),"1" (__r17))
-#define tbiap()		__tbi(-1, /* no second argument */)
-#define tbia()		__tbi(-2, /* no second argument */)
-
-/*
- * Atomic exchange routines.
- */
-
-#define __ASM__MB
-#define ____xchg(type, args...)		__xchg ## type ## _local(args)
-#define ____cmpxchg(type, args...)	__cmpxchg ## type ## _local(args)
-#include <asm/xchg.h>
-
-#define xchg_local(ptr,x)						\
-  ({									\
-     __typeof__(*(ptr)) _x_ = (x);					\
-     (__typeof__(*(ptr))) __xchg_local((ptr), (unsigned long)_x_,	\
-				       sizeof(*(ptr)));			\
-  })
-
-#define cmpxchg_local(ptr, o, n)					\
-  ({									\
-     __typeof__(*(ptr)) _o_ = (o);					\
-     __typeof__(*(ptr)) _n_ = (n);					\
-     (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,	\
-					  (unsigned long)_n_,		\
-					  sizeof(*(ptr)));		\
-  })
-
-#define cmpxchg64_local(ptr, o, n)					\
-  ({									\
-	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
-	cmpxchg_local((ptr), (o), (n));					\
-  })
-
-#ifdef CONFIG_SMP
-#undef __ASM__MB
-#define __ASM__MB	"\tmb\n"
-#endif
-#undef ____xchg
-#undef ____cmpxchg
-#define ____xchg(type, args...)		__xchg ##type(args)
-#define ____cmpxchg(type, args...)	__cmpxchg ##type(args)
-#include <asm/xchg.h>
-
-#define xchg(ptr,x)							\
-  ({									\
-     __typeof__(*(ptr)) _x_ = (x);					\
-     (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_,		\
-				 sizeof(*(ptr)));			\
-  })
-
-#define cmpxchg(ptr, o, n)						\
-  ({									\
-     __typeof__(*(ptr)) _o_ = (o);					\
-     __typeof__(*(ptr)) _n_ = (n);					\
-     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		\
-				    (unsigned long)_n_,	sizeof(*(ptr)));\
-  })
-
-#define cmpxchg64(ptr, o, n)						\
-  ({									\
-	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
-	cmpxchg((ptr), (o), (n));					\
-  })
-
-#undef __ASM__MB
-#undef ____cmpxchg
-
-#define __HAVE_ARCH_CMPXCHG 1
-
-#endif /* __ASSEMBLY__ */
-
-#define arch_align_stack(x) (x)
-
-#endif
diff --git a/arch/alpha/include/asm/xchg.h b/arch/alpha/include/asm/xchg.h
index beba1b8..1d1b436 100644
--- a/arch/alpha/include/asm/xchg.h
+++ b/arch/alpha/include/asm/xchg.h
@@ -1,4 +1,4 @@
-#ifndef __ALPHA_SYSTEM_H
+#ifndef _ALPHA_ATOMIC_H
 #error Do not include xchg.h directly!
 #else
 /*
diff --git a/arch/alpha/kernel/binfmt_loader.c b/arch/alpha/kernel/binfmt_loader.c
index 3fcfad4..d1f474d 100644
--- a/arch/alpha/kernel/binfmt_loader.c
+++ b/arch/alpha/kernel/binfmt_loader.c
@@ -46,6 +46,7 @@
 
 static int __init init_loader_binfmt(void)
 {
-	return insert_binfmt(&loader_format);
+	insert_binfmt(&loader_format);
+	return 0;
 }
 arch_initcall(init_loader_binfmt);
diff --git a/arch/alpha/kernel/core_apecs.c b/arch/alpha/kernel/core_apecs.c
index ca46b2c..708c831 100644
--- a/arch/alpha/kernel/core_apecs.c
+++ b/arch/alpha/kernel/core_apecs.c
@@ -21,6 +21,7 @@
 
 #include <asm/ptrace.h>
 #include <asm/smp.h>
+#include <asm/mce.h>
 
 #include "proto.h"
 #include "pci_impl.h"
diff --git a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c
index 1d6ee6c..c44339e 100644
--- a/arch/alpha/kernel/core_cia.c
+++ b/arch/alpha/kernel/core_cia.c
@@ -23,6 +23,7 @@
 #include <linux/bootmem.h>
 
 #include <asm/ptrace.h>
+#include <asm/mce.h>
 
 #include "proto.h"
 #include "pci_impl.h"
diff --git a/arch/alpha/kernel/core_t2.c b/arch/alpha/kernel/core_t2.c
index 2f770e9..3ada4f7 100644
--- a/arch/alpha/kernel/core_t2.c
+++ b/arch/alpha/kernel/core_t2.c
@@ -21,6 +21,7 @@
 
 #include <asm/ptrace.h>
 #include <asm/delay.h>
+#include <asm/mce.h>
 
 #include "proto.h"
 #include "pci_impl.h"
diff --git a/arch/alpha/kernel/err_impl.h b/arch/alpha/kernel/err_impl.h
index 0c010ca..ae529c4 100644
--- a/arch/alpha/kernel/err_impl.h
+++ b/arch/alpha/kernel/err_impl.h
@@ -7,6 +7,8 @@
  * 	implementations.
  */
 
+#include <asm/mce.h>
+
 union el_timestamp;
 struct el_subpacket;
 struct ev7_lf_subpackets;
diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S
index 4bdd1d2..c352499 100644
--- a/arch/alpha/kernel/head.S
+++ b/arch/alpha/kernel/head.S
@@ -8,14 +8,12 @@
  */
 
 #include <linux/init.h>
-#include <asm/system.h>
 #include <asm/asm-offsets.h>
+#include <asm/pal.h>
+#include <asm/setup.h>
 
 __HEAD
-.globl swapper_pg_dir
 .globl _stext
-swapper_pg_dir=SWAPPER_PGD
-
 	.set noreorder
 	.globl	__start
 	.ent	__start
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
index 381431a..2872acc 100644
--- a/arch/alpha/kernel/irq.c
+++ b/arch/alpha/kernel/irq.c
@@ -26,7 +26,6 @@
 #include <linux/profile.h>
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c
index 51b7fbd..772ddfdb 100644
--- a/arch/alpha/kernel/irq_alpha.c
+++ b/arch/alpha/kernel/irq_alpha.c
@@ -11,6 +11,7 @@
 #include <asm/machvec.h>
 #include <asm/dma.h>
 #include <asm/perf_event.h>
+#include <asm/mce.h>
 
 #include "proto.h"
 #include "irq_impl.h"
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 01e8715..49ee319 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -40,7 +40,6 @@
 #include <asm/fpu.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/sysinfo.h>
 #include <asm/thread_info.h>
 #include <asm/hwrpb.h>
diff --git a/arch/alpha/kernel/pci-noop.c b/arch/alpha/kernel/pci-noop.c
index 04eea48..df24b76 100644
--- a/arch/alpha/kernel/pci-noop.c
+++ b/arch/alpha/kernel/pci-noop.c
@@ -108,7 +108,8 @@
 }
 
 static void *alpha_noop_alloc_coherent(struct device *dev, size_t size,
-				       dma_addr_t *dma_handle, gfp_t gfp)
+				       dma_addr_t *dma_handle, gfp_t gfp,
+				       struct dma_attrs *attrs)
 {
 	void *ret;
 
@@ -123,7 +124,8 @@
 }
 
 static void alpha_noop_free_coherent(struct device *dev, size_t size,
-				     void *cpu_addr, dma_addr_t dma_addr)
+				     void *cpu_addr, dma_addr_t dma_addr,
+				     struct dma_attrs *attrs)
 {
 	free_pages((unsigned long)cpu_addr, get_order(size));
 }
@@ -174,8 +176,8 @@
 }
 
 struct dma_map_ops alpha_noop_ops = {
-	.alloc_coherent		= alpha_noop_alloc_coherent,
-	.free_coherent		= alpha_noop_free_coherent,
+	.alloc			= alpha_noop_alloc_coherent,
+	.free			= alpha_noop_free_coherent,
 	.map_page		= alpha_noop_map_page,
 	.map_sg			= alpha_noop_map_sg,
 	.mapping_error		= alpha_noop_mapping_error,
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 8c723c1..1a62963 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -43,12 +43,10 @@
 
 const char pci_hae0_name[] = "HAE0";
 
-/* Indicate whether we respect the PCI setup left by console. */
 /*
- * Make this long-lived  so that we know when shutting down
- * whether we probed only or not.
+ * If PCI_PROBE_ONLY in pci_flags is set, we don't change any PCI resource
+ * assignments.
  */
-int pci_probe_only;
 
 /*
  * The PCI controller list.
@@ -215,7 +213,7 @@
 	struct pdev_srm_saved_conf *tmp;
 	static int printed = 0;
 
-	if (!alpha_using_srm || pci_probe_only)
+	if (!alpha_using_srm || pci_has_flag(PCI_PROBE_ONLY))
 		return;
 
 	if (!printed) {
@@ -242,7 +240,7 @@
 	struct pdev_srm_saved_conf *tmp;
 
 	/* No need to restore if probed only. */
-	if (pci_probe_only)
+	if (pci_has_flag(PCI_PROBE_ONLY))
 		return;
 
 	/* Restore SRM config. */
@@ -253,46 +251,17 @@
 #endif
 
 void __devinit
-pcibios_fixup_resource(struct resource *res, struct resource *root)
-{
-	res->start += root->start;
-	res->end += root->start;
-}
-
-void __devinit
-pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
-{
-	/* Update device resources.  */
-	struct pci_controller *hose = (struct pci_controller *)bus->sysdata;
-	int i;
-
-	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-		if (!dev->resource[i].start)
-			continue;
-		if (dev->resource[i].flags & IORESOURCE_IO)
-			pcibios_fixup_resource(&dev->resource[i],
-					       hose->io_space);
-		else if (dev->resource[i].flags & IORESOURCE_MEM)
-			pcibios_fixup_resource(&dev->resource[i],
-					       hose->mem_space);
-	}
-}
-
-void __devinit
 pcibios_fixup_bus(struct pci_bus *bus)
 {
 	struct pci_dev *dev = bus->self;
 
-	if (pci_probe_only && dev &&
+	if (pci_has_flag(PCI_PROBE_ONLY) && dev &&
  		   (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
  		pci_read_bridge_bases(bus);
- 		pcibios_fixup_device_resources(dev, bus);
 	} 
 
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 		pdev_save_srm_config(dev);
-		if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
-			pcibios_fixup_device_resources(dev, bus);
 	}
 }
 
@@ -302,42 +271,6 @@
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
 
-void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-			 struct resource *res)
-{
-	struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
-	unsigned long offset = 0;
-
-	if (res->flags & IORESOURCE_IO)
-		offset = hose->io_space->start;
-	else if (res->flags & IORESOURCE_MEM)
-		offset = hose->mem_space->start;
-
-	region->start = res->start - offset;
-	region->end = res->end - offset;
-}
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-			     struct pci_bus_region *region)
-{
-	struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
-	unsigned long offset = 0;
-
-	if (res->flags & IORESOURCE_IO)
-		offset = hose->io_space->start;
-	else if (res->flags & IORESOURCE_MEM)
-		offset = hose->mem_space->start;
-
-	res->start = region->start + offset;
-	res->end = region->end + offset;
-}
-
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-#endif
-
 int
 pcibios_enable_device(struct pci_dev *dev, int mask)
 {
@@ -374,7 +307,8 @@
 
 			if (r->parent || !r->start || !r->flags)
 				continue;
-			if (pci_probe_only || (r->flags & IORESOURCE_PCI_FIXED))
+			if (pci_has_flag(PCI_PROBE_ONLY) ||
+			    (r->flags & IORESOURCE_PCI_FIXED))
 				pci_claim_resource(dev, i);
 		}
 	}
@@ -416,8 +350,10 @@
 			hose->mem_space->end = end;
 
 		INIT_LIST_HEAD(&resources);
-		pci_add_resource(&resources, hose->io_space);
-		pci_add_resource(&resources, hose->mem_space);
+		pci_add_resource_offset(&resources, hose->io_space,
+					hose->io_space->start);
+		pci_add_resource_offset(&resources, hose->mem_space,
+					hose->mem_space->start);
 
 		bus = pci_scan_root_bus(NULL, next_busno, alpha_mv.pci_ops,
 					hose, &resources);
diff --git a/arch/alpha/kernel/pci_impl.h b/arch/alpha/kernel/pci_impl.h
index 85457b2..2b0ac42 100644
--- a/arch/alpha/kernel/pci_impl.h
+++ b/arch/alpha/kernel/pci_impl.h
@@ -173,9 +173,6 @@
 extern struct pci_controller *hose_head, **hose_tail;
 extern struct pci_controller *pci_isa_hose;
 
-/* Indicate that we trust the console to configure things properly.  */
-extern int pci_probe_only;
-
 extern unsigned long alpha_agpgart_size;
 
 extern void common_init_pci(void);
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
index 4361080..cd63479 100644
--- a/arch/alpha/kernel/pci_iommu.c
+++ b/arch/alpha/kernel/pci_iommu.c
@@ -434,7 +434,8 @@
    else DMA_ADDRP is undefined.  */
 
 static void *alpha_pci_alloc_coherent(struct device *dev, size_t size,
-				      dma_addr_t *dma_addrp, gfp_t gfp)
+				      dma_addr_t *dma_addrp, gfp_t gfp,
+				      struct dma_attrs *attrs)
 {
 	struct pci_dev *pdev = alpha_gendev_to_pci(dev);
 	void *cpu_addr;
@@ -478,7 +479,8 @@
    DMA_ADDR past this call are illegal.  */
 
 static void alpha_pci_free_coherent(struct device *dev, size_t size,
-				    void *cpu_addr, dma_addr_t dma_addr)
+				    void *cpu_addr, dma_addr_t dma_addr,
+				    struct dma_attrs *attrs)
 {
 	struct pci_dev *pdev = alpha_gendev_to_pci(dev);
 	pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL);
@@ -952,8 +954,8 @@
 }
 
 struct dma_map_ops alpha_pci_ops = {
-	.alloc_coherent		= alpha_pci_alloc_coherent,
-	.free_coherent		= alpha_pci_free_coherent,
+	.alloc			= alpha_pci_alloc_coherent,
+	.free			= alpha_pci_free_coherent,
 	.map_page		= alpha_pci_map_page,
 	.unmap_page		= alpha_pci_unmap_page,
 	.map_sg			= alpha_pci_map_sg,
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 89bbe5b..153d3fc 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -31,7 +31,6 @@
 
 #include <asm/reg.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/hwrpb.h>
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index e2af5eb..54616f4 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -16,7 +16,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/fpu.h>
 
 #include "proto.h"
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index 32de560..9e3107cc5 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -55,7 +55,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/hwrpb.h>
 #include <asm/dma.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 6f7feb5..35f2ef4 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -120,12 +120,13 @@
  */
 SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask)
 {
-	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sighand->siglock);
+	sigset_t blocked;
+
 	current->saved_sigmask = current->blocked;
-	siginitset(&current->blocked, mask);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+
+	mask &= _BLOCKABLE;
+	siginitset(&blocked, mask);
+	set_current_blocked(&blocked);
 
 	current->state = TASK_INTERRUPTIBLE;
 	schedule();
@@ -238,10 +239,7 @@
 		goto give_sigsegv;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(sc, regs, sw))
 		goto give_sigsegv;
@@ -276,10 +274,7 @@
 		goto give_sigsegv;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(&frame->uc.uc_mcontext, regs, sw))
 		goto give_sigsegv;
@@ -501,14 +496,8 @@
 	else
 		ret = setup_frame(sig, ka, oldset, regs, sw);
 
-	if (ret == 0) {
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-		if (!(ka->sa.sa_flags & SA_NODEFER)) 
-			sigaddset(&current->blocked,sig);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
-	}
+	if (ret == 0)
+		block_sigmask(ka, sig);
 
 	return ret;
 }
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 4087a56..50d438d 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -450,7 +450,7 @@
 		smp_num_probed = 1;
 	}
 
-	printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_map = %lx\n",
+	printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n",
 	       smp_num_probed, cpumask_bits(cpu_present_mask)[0]);
 }
 
diff --git a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c
index 8606d77..118dc6a 100644
--- a/arch/alpha/kernel/sys_alcor.c
+++ b/arch/alpha/kernel/sys_alcor.c
@@ -18,7 +18,6 @@
 #include <linux/bitops.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c
index 1029619..4c50f8f4 100644
--- a/arch/alpha/kernel/sys_cabriolet.c
+++ b/arch/alpha/kernel/sys_cabriolet.c
@@ -18,7 +18,6 @@
 #include <linux/bitops.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c
index 13f0717..5bf401f 100644
--- a/arch/alpha/kernel/sys_dp264.c
+++ b/arch/alpha/kernel/sys_dp264.c
@@ -21,7 +21,6 @@
 #include <linux/bitops.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/sys_eb64p.c b/arch/alpha/kernel/sys_eb64p.c
index 3c6c13c..ad40a42 100644
--- a/arch/alpha/kernel/sys_eb64p.c
+++ b/arch/alpha/kernel/sys_eb64p.c
@@ -17,7 +17,6 @@
 #include <linux/bitops.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/sys_eiger.c b/arch/alpha/kernel/sys_eiger.c
index 35f480d..79d69d7 100644
--- a/arch/alpha/kernel/sys_eiger.c
+++ b/arch/alpha/kernel/sys_eiger.c
@@ -18,7 +18,6 @@
 #include <linux/bitops.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c
index 7f1a87f1..5a0af11 100644
--- a/arch/alpha/kernel/sys_jensen.c
+++ b/arch/alpha/kernel/sys_jensen.c
@@ -15,7 +15,6 @@
 #include <linux/init.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 
 #define __EXTERN_INLINE inline
 #include <asm/io.h>
diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c
index 95cfc83..14a4b6a 100644
--- a/arch/alpha/kernel/sys_marvel.c
+++ b/arch/alpha/kernel/sys_marvel.c
@@ -13,7 +13,6 @@
 #include <linux/bitops.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
@@ -384,7 +383,8 @@
 
 	marvel_register_error_handlers();
 
-	pci_probe_only = 1;
+	/* Indicate that we trust the console to configure things properly */
+	pci_set_flags(PCI_PROBE_ONLY);
 	common_init_pci();
 	locate_and_init_vga(NULL);
 
diff --git a/arch/alpha/kernel/sys_miata.c b/arch/alpha/kernel/sys_miata.c
index 258da68..d5b9776 100644
--- a/arch/alpha/kernel/sys_miata.c
+++ b/arch/alpha/kernel/sys_miata.c
@@ -17,7 +17,6 @@
 #include <linux/reboot.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c
index c0fd728..5e82dc1 100644
--- a/arch/alpha/kernel/sys_mikasa.c
+++ b/arch/alpha/kernel/sys_mikasa.c
@@ -17,7 +17,7 @@
 #include <linux/bitops.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
+#include <asm/mce.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
index 4112200..4d4c046 100644
--- a/arch/alpha/kernel/sys_nautilus.c
+++ b/arch/alpha/kernel/sys_nautilus.c
@@ -35,7 +35,6 @@
 #include <linux/bitops.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c
index 2172528..063e594 100644
--- a/arch/alpha/kernel/sys_noritake.c
+++ b/arch/alpha/kernel/sys_noritake.c
@@ -18,7 +18,7 @@
 #include <linux/bitops.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
+#include <asm/mce.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c
index a125d6b..dfd510a 100644
--- a/arch/alpha/kernel/sys_rawhide.c
+++ b/arch/alpha/kernel/sys_rawhide.c
@@ -16,7 +16,6 @@
 #include <linux/init.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/sys_ruffian.c b/arch/alpha/kernel/sys_ruffian.c
index 2581cbe..a3f4852 100644
--- a/arch/alpha/kernel/sys_ruffian.c
+++ b/arch/alpha/kernel/sys_ruffian.c
@@ -18,7 +18,6 @@
 #include <linux/init.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/sys_rx164.c b/arch/alpha/kernel/sys_rx164.c
index b172b27..08ee737 100644
--- a/arch/alpha/kernel/sys_rx164.c
+++ b/arch/alpha/kernel/sys_rx164.c
@@ -17,7 +17,6 @@
 #include <linux/bitops.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c
index 98d1dbf..8a0aa6d 100644
--- a/arch/alpha/kernel/sys_sable.c
+++ b/arch/alpha/kernel/sys_sable.c
@@ -16,7 +16,6 @@
 #include <linux/init.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c
index 47bec1e..febd24e 100644
--- a/arch/alpha/kernel/sys_sio.c
+++ b/arch/alpha/kernel/sys_sio.c
@@ -20,7 +20,6 @@
 
 #include <asm/compiler.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/sys_sx164.c b/arch/alpha/kernel/sys_sx164.c
index 73e1c31..d063b36 100644
--- a/arch/alpha/kernel/sys_sx164.c
+++ b/arch/alpha/kernel/sys_sx164.c
@@ -17,7 +17,6 @@
 #include <linux/bitops.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
@@ -26,6 +25,7 @@
 #include <asm/core_cia.h>
 #include <asm/hwrpb.h>
 #include <asm/tlbflush.h>
+#include <asm/special_insns.h>
 
 #include "proto.h"
 #include "irq_impl.h"
diff --git a/arch/alpha/kernel/sys_takara.c b/arch/alpha/kernel/sys_takara.c
index 2ae99ad..dd0f1ea 100644
--- a/arch/alpha/kernel/sys_takara.c
+++ b/arch/alpha/kernel/sys_takara.c
@@ -16,7 +16,6 @@
 #include <linux/init.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c
index f47b30a..2533db2 100644
--- a/arch/alpha/kernel/sys_titan.c
+++ b/arch/alpha/kernel/sys_titan.c
@@ -21,7 +21,6 @@
 #include <linux/bitops.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
@@ -331,7 +330,8 @@
  	 */
  	titan_late_init();
  
-	pci_probe_only = 1;
+	/* Indicate that we trust the console to configure things properly */
+	pci_set_flags(PCI_PROBE_ONLY);
 	common_init_pci();
 	SMC669_Init(0);
 	locate_and_init_vga(NULL);
diff --git a/arch/alpha/kernel/sys_wildfire.c b/arch/alpha/kernel/sys_wildfire.c
index 17c85a6..ee18748 100644
--- a/arch/alpha/kernel/sys_wildfire.c
+++ b/arch/alpha/kernel/sys_wildfire.c
@@ -15,7 +15,6 @@
 #include <linux/bitops.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index 0414e02..80d987c 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -24,6 +24,7 @@
 #include <asm/sysinfo.h>
 #include <asm/hwrpb.h>
 #include <asm/mmu_context.h>
+#include <asm/special_insns.h>
 
 #include "proto.h"
 
diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S
index f937ad1..647b84c 100644
--- a/arch/alpha/kernel/vmlinux.lds.S
+++ b/arch/alpha/kernel/vmlinux.lds.S
@@ -2,6 +2,7 @@
 #include <asm/thread_info.h>
 #include <asm/cache.h>
 #include <asm/page.h>
+#include <asm/setup.h>
 
 OUTPUT_FORMAT("elf64-alpha")
 OUTPUT_ARCH(alpha)
@@ -25,6 +26,7 @@
 		*(.fixup)
 		*(.gnu.warning)
 	} :kernel
+	swapper_pg_dir = SWAPPER_PGD;
 	_etext = .;	/* End of text section */
 
 	NOTES :kernel :note
diff --git a/arch/alpha/lib/stacktrace.c b/arch/alpha/lib/stacktrace.c
index 6d432e4..5e83216 100644
--- a/arch/alpha/lib/stacktrace.c
+++ b/arch/alpha/lib/stacktrace.c
@@ -1,5 +1,4 @@
 #include <linux/kernel.h>
-#include <asm/system.h>
 
 typedef unsigned int instr;
 
diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c
index fadd5f8..5eecab1 100644
--- a/arch/alpha/mm/fault.c
+++ b/arch/alpha/mm/fault.c
@@ -24,7 +24,6 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 extern void die_if_kernel(char *,struct pt_regs *,long, unsigned long *);
diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c
index 69d0c57..1ad6ca7 100644
--- a/arch/alpha/mm/init.c
+++ b/arch/alpha/mm/init.c
@@ -22,7 +22,6 @@
 #include <linux/vmalloc.h>
 #include <linux/gfp.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -31,6 +30,7 @@
 #include <asm/mmu_context.h>
 #include <asm/console.h>
 #include <asm/tlb.h>
+#include <asm/setup.h>
 
 extern void die_if_kernel(char *,struct pt_regs *,long);
 
diff --git a/arch/alpha/oprofile/common.c b/arch/alpha/oprofile/common.c
index bd8ac53..a0a5d27 100644
--- a/arch/alpha/oprofile/common.c
+++ b/arch/alpha/oprofile/common.c
@@ -12,7 +12,6 @@
 #include <linux/smp.h>
 #include <linux/errno.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 
 #include "op_impl.h"
 
diff --git a/arch/alpha/oprofile/op_model_ev4.c b/arch/alpha/oprofile/op_model_ev4.c
index 80d764d..18aa9b4 100644
--- a/arch/alpha/oprofile/op_model_ev4.c
+++ b/arch/alpha/oprofile/op_model_ev4.c
@@ -11,7 +11,6 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 
 #include "op_impl.h"
 
diff --git a/arch/alpha/oprofile/op_model_ev5.c b/arch/alpha/oprofile/op_model_ev5.c
index ceea6e1..c32f8a0 100644
--- a/arch/alpha/oprofile/op_model_ev5.c
+++ b/arch/alpha/oprofile/op_model_ev5.c
@@ -11,7 +11,6 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 
 #include "op_impl.h"
 
diff --git a/arch/alpha/oprofile/op_model_ev6.c b/arch/alpha/oprofile/op_model_ev6.c
index 0869f85..1c84cc2 100644
--- a/arch/alpha/oprofile/op_model_ev6.c
+++ b/arch/alpha/oprofile/op_model_ev6.c
@@ -11,7 +11,6 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 
 #include "op_impl.h"
 
diff --git a/arch/alpha/oprofile/op_model_ev67.c b/arch/alpha/oprofile/op_model_ev67.c
index 5b9d178..34a57a1 100644
--- a/arch/alpha/oprofile/op_model_ev67.c
+++ b/arch/alpha/oprofile/op_model_ev67.c
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 
 #include "op_impl.h"
 
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index dfb0312..cf006d4 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -9,6 +9,7 @@
 	select SYS_SUPPORTS_APM_EMULATION
 	select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI)
 	select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
+	select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
 	select HAVE_ARCH_KGDB
 	select HAVE_KPROBES if !XIP_KERNEL
 	select HAVE_KRETPROBES if (HAVE_KPROBES)
@@ -21,6 +22,7 @@
 	select HAVE_KERNEL_GZIP
 	select HAVE_KERNEL_LZO
 	select HAVE_KERNEL_LZMA
+	select HAVE_KERNEL_XZ
 	select HAVE_IRQ_WORK
 	select HAVE_PERF_EVENTS
 	select PERF_USE_VMALLOC
@@ -28,10 +30,10 @@
 	select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
 	select HAVE_C_RECORDMCOUNT
 	select HAVE_GENERIC_HARDIRQS
-	select HAVE_SPARSE_IRQ
 	select GENERIC_IRQ_SHOW
 	select CPU_PM if (SUSPEND || CPU_IDLE)
 	select GENERIC_PCI_IOMAP
+	select HAVE_BPF_JIT if NET
 	help
 	  The ARM series is a line of low-power-consumption RISC chip designs
 	  licensed by ARM Ltd and targeted at embedded applications and
@@ -52,9 +54,6 @@
 config SYS_SUPPORTS_APM_EMULATION
 	bool
 
-config HAVE_SCHED_CLOCK
-	bool
-
 config GENERIC_GPIO
 	bool
 
@@ -180,12 +179,18 @@
 config NEED_DMA_MAP_STATE
        def_bool y
 
+config ARCH_HAS_DMA_SET_COHERENT_MASK
+	bool
+
 config GENERIC_ISA_DMA
 	bool
 
 config FIQ
 	bool
 
+config NEED_RET_TO_USER
+	bool
+
 config ARCH_MTD_XIP
 	bool
 
@@ -214,6 +219,13 @@
 	  this feature (eg, building a kernel for a single machine) and
 	  you need to shrink the kernel to the minimal size.
 
+config NEED_MACH_IO_H
+	bool
+	help
+	  Select this when mach/io.h is required to provide special
+	  definitions for this platform.  The need for mach/io.h should
+	  be avoided when possible.
+
 config NEED_MACH_MEMORY_H
 	bool
 	help
@@ -265,7 +277,9 @@
 	select GENERIC_CLOCKEVENTS
 	select PLAT_VERSATILE
 	select PLAT_VERSATILE_FPGA_IRQ
+	select NEED_MACH_IO_H
 	select NEED_MACH_MEMORY_H
+	select SPARSE_IRQ
 	help
 	  Support for ARM's Integrator platform.
 
@@ -312,6 +326,7 @@
 	select HAVE_CLK
 	select HAVE_PATA_PLATFORM
 	select ICST
+	select NO_IOPORT
 	select PLAT_VERSATILE
 	select PLAT_VERSATILE_CLCD
 	help
@@ -322,9 +337,11 @@
 	select ARCH_REQUIRE_GPIOLIB
 	select HAVE_CLK
 	select CLKDEV_LOOKUP
+	select IRQ_DOMAIN
+	select NEED_MACH_IO_H if PCCARD
 	help
 	  This enables support for systems based on the Atmel AT91RM9200,
-	  AT91SAM9 and AT91CAP9 processors.
+	  AT91SAM9 processors.
 
 config ARCH_BCMRING
 	bool "Broadcom BCMRING"
@@ -350,6 +367,7 @@
 	select GENERIC_CLOCKEVENTS
 	select HAVE_ARM_SCU
 	select HAVE_SMP
+	select SPARSE_IRQ
 	select USE_OF
 	help
 	  Support for the Calxeda Highbank SoC based boards.
@@ -400,6 +418,7 @@
 	select ISA
 	select NO_IOPORT
 	select ARCH_USES_GETTIMEOFFSET
+	select NEED_MACH_IO_H
 	select NEED_MACH_MEMORY_H
 	help
 	  This is an evaluation board for the StrongARM processor available
@@ -426,6 +445,7 @@
 	select FOOTBRIDGE
 	select GENERIC_CLOCKEVENTS
 	select HAVE_IDE
+	select NEED_MACH_IO_H
 	select NEED_MACH_MEMORY_H
 	help
 	  Support for systems based on the DC21285 companion chip
@@ -438,7 +458,6 @@
 	select CLKDEV_LOOKUP
 	select CLKSRC_MMIO
 	select GENERIC_IRQ_CHIP
-	select HAVE_SCHED_CLOCK
 	select MULTI_IRQ_HANDLER
 	help
 	  Support for Freescale MXC/iMX-based family of processors
@@ -478,7 +497,9 @@
 	select PCI
 	select ARCH_SUPPORTS_MSI
 	select VMSPLIT_1G
+	select NEED_MACH_IO_H
 	select NEED_MACH_MEMORY_H
+	select NEED_RET_TO_USER
 	help
 	  Support for Intel's IOP13XX (XScale) family of processors.
 
@@ -486,6 +507,8 @@
 	bool "IOP32x-based"
 	depends on MMU
 	select CPU_XSCALE
+	select NEED_MACH_IO_H
+	select NEED_RET_TO_USER
 	select PLAT_IOP
 	select PCI
 	select ARCH_REQUIRE_GPIOLIB
@@ -497,6 +520,8 @@
 	bool "IOP33x-based"
 	depends on MMU
 	select CPU_XSCALE
+	select NEED_MACH_IO_H
+	select NEED_RET_TO_USER
 	select PLAT_IOP
 	select PCI
 	select ARCH_REQUIRE_GPIOLIB
@@ -509,6 +534,7 @@
 	select CPU_XSC3
  	select PCI
 	select ARCH_USES_GETTIMEOFFSET
+	select NEED_MACH_IO_H
 	select NEED_MACH_MEMORY_H
 	help
 	  Support for Intel's IXP23xx (XScale) family of processors.
@@ -519,6 +545,7 @@
 	select CPU_XSCALE
 	select PCI
 	select ARCH_USES_GETTIMEOFFSET
+	select NEED_MACH_IO_H
 	select NEED_MACH_MEMORY_H
 	help
 	  Support for Intel's IXP2400/2800 (XScale) family of processors.
@@ -526,12 +553,13 @@
 config ARCH_IXP4XX
 	bool "IXP4xx-based"
 	depends on MMU
+	select ARCH_HAS_DMA_SET_COHERENT_MASK
 	select CLKSRC_MMIO
 	select CPU_XSCALE
 	select GENERIC_GPIO
 	select GENERIC_CLOCKEVENTS
-	select HAVE_SCHED_CLOCK
 	select MIGHT_HAVE_PCI
+	select NEED_MACH_IO_H
 	select DMABOUNCE if PCI
 	help
 	  Support for Intel's IXP4XX (XScale) family of processors.
@@ -542,6 +570,7 @@
 	select PCI
 	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_CLOCKEVENTS
+	select NEED_MACH_IO_H
 	select PLAT_ORION
 	help
 	  Support for the Marvell Dove SoC 88AP510
@@ -552,6 +581,7 @@
 	select PCI
 	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_CLOCKEVENTS
+	select NEED_MACH_IO_H
 	select PLAT_ORION
 	help
 	  Support for the following Marvell Kirkwood series SoCs:
@@ -576,6 +606,7 @@
 	select PCI
 	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_CLOCKEVENTS
+	select NEED_MACH_IO_H
 	select PLAT_ORION
 	help
 	  Support for the following Marvell MV78xx0 series SoCs:
@@ -601,7 +632,6 @@
 	select CLKDEV_LOOKUP
 	select GENERIC_CLOCKEVENTS
 	select GPIO_PXA
-	select HAVE_SCHED_CLOCK
 	select TICK_ONESHOT
 	select PLAT_PXA
 	select SPARSE_IRQ
@@ -642,9 +672,9 @@
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_GPIO
 	select HAVE_CLK
-	select HAVE_SCHED_CLOCK
 	select HAVE_SMP
 	select MIGHT_HAVE_CACHE_L2X0
+	select NEED_MACH_IO_H if PCI
 	select ARCH_HAS_CPUFREQ
 	help
 	  This enables support for NVIDIA Tegra based systems (Tegra APX,
@@ -659,7 +689,6 @@
 	select DW_APB_TIMER
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_GPIO
-	select HAVE_SCHED_CLOCK
 	select HAVE_TCM
 	select NO_IOPORT
 	select SPARSE_IRQ
@@ -687,7 +716,6 @@
 	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_CLOCKEVENTS
 	select GPIO_PXA
-	select HAVE_SCHED_CLOCK
 	select TICK_ONESHOT
 	select PLAT_PXA
 	select SPARSE_IRQ
@@ -731,7 +759,6 @@
 	bool "RiscPC"
 	select ARCH_ACORN
 	select FIQ
-	select TIMER_ACORN
 	select ARCH_MAY_HAVE_PC_FDC
 	select HAVE_PATA_PLATFORM
 	select ISA_DMA_API
@@ -739,6 +766,7 @@
 	select ARCH_SPARSEMEM_ENABLE
 	select ARCH_USES_GETTIMEOFFSET
 	select HAVE_IDE
+	select NEED_MACH_IO_H
 	select NEED_MACH_MEMORY_H
 	help
 	  On the Acorn Risc-PC, Linux can support the internal IDE disk and
@@ -754,31 +782,31 @@
 	select ARCH_HAS_CPUFREQ
 	select CPU_FREQ
 	select GENERIC_CLOCKEVENTS
-	select HAVE_CLK
-	select HAVE_SCHED_CLOCK
+	select CLKDEV_LOOKUP
 	select TICK_ONESHOT
 	select ARCH_REQUIRE_GPIOLIB
 	select HAVE_IDE
 	select NEED_MACH_MEMORY_H
+	select SPARSE_IRQ
 	help
 	  Support for StrongARM 11x0 based boards.
 
-config ARCH_S3C2410
-	bool "Samsung S3C2410, S3C2412, S3C2413, S3C2416, S3C2440, S3C2442, S3C2443, S3C2450"
+config ARCH_S3C24XX
+	bool "Samsung S3C24XX SoCs"
 	select GENERIC_GPIO
 	select ARCH_HAS_CPUFREQ
 	select HAVE_CLK
 	select CLKDEV_LOOKUP
 	select ARCH_USES_GETTIMEOFFSET
 	select HAVE_S3C2410_I2C if I2C
+	select HAVE_S3C_RTC if RTC_CLASS
+	select HAVE_S3C2410_WATCHDOG if WATCHDOG
+	select NEED_MACH_IO_H
 	help
-	  Samsung S3C2410X CPU based systems, such as the Simtec Electronics
-	  BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or
-	  the Samsung SMDK2410 development board (and derivatives).
-
-	  Note, the S3C2416 and the S3C2450 are so close that they even share
-	  the same SoC ID code. This means that there is no separate machine
-	  directory (no arch/arm/mach-s3c2450) as the S3C2416 was first.
+	  Samsung S3C2410, S3C2412, S3C2413, S3C2416, S3C2440, S3C2442, S3C2443
+	  and S3C2450 SoCs based systems, such as the Simtec Electronics BAST
+	  (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or the
+	  Samsung SMDK2410 development board (and derivatives).
 
 config ARCH_S3C64XX
 	bool "Samsung S3C64XX"
@@ -812,7 +840,6 @@
 	select CLKSRC_MMIO
 	select HAVE_S3C2410_WATCHDOG if WATCHDOG
 	select GENERIC_CLOCKEVENTS
-	select HAVE_SCHED_CLOCK
 	select HAVE_S3C2410_I2C if I2C
 	select HAVE_S3C_RTC if RTC_CLASS
 	help
@@ -843,7 +870,6 @@
 	select CLKSRC_MMIO
 	select ARCH_HAS_CPUFREQ
 	select GENERIC_CLOCKEVENTS
-	select HAVE_SCHED_CLOCK
 	select HAVE_S3C2410_I2C if I2C
 	select HAVE_S3C_RTC if RTC_CLASS
 	select HAVE_S3C2410_WATCHDOG if WATCHDOG
@@ -877,6 +903,7 @@
 	select PCI
 	select ARCH_USES_GETTIMEOFFSET
 	select NEED_MACH_MEMORY_H
+	select NEED_MACH_IO_H
 	help
 	  Support for the StrongARM based Digital DNARD machine, also known
 	  as "Shark" (<http://www.shark-linux.de/shark.html>).
@@ -886,7 +913,6 @@
 	depends on MMU
 	select CLKSRC_MMIO
 	select CPU_ARM926T
-	select HAVE_SCHED_CLOCK
 	select HAVE_TCM
 	select ARM_AMBA
 	select ARM_PATCH_PHYS_VIRT
@@ -901,6 +927,7 @@
 
 config ARCH_U8500
 	bool "ST-Ericsson U8500 Series"
+	depends on MMU
 	select CPU_V7
 	select ARM_AMBA
 	select GENERIC_CLOCKEVENTS
@@ -944,7 +971,6 @@
 	select ARCH_HAS_CPUFREQ
 	select CLKSRC_MMIO
 	select GENERIC_CLOCKEVENTS
-	select HAVE_SCHED_CLOCK
 	select ARCH_HAS_HOLES_MEMORYMODEL
 	help
 	  Support for TI's OMAP platform (OMAP1/2/3/4).
@@ -1066,12 +1092,10 @@
 
 source "arch/arm/plat-spear/Kconfig"
 
-if ARCH_S3C2410
-source "arch/arm/mach-s3c2410/Kconfig"
+source "arch/arm/mach-s3c24xx/Kconfig"
+if ARCH_S3C24XX
 source "arch/arm/mach-s3c2412/Kconfig"
-source "arch/arm/mach-s3c2416/Kconfig"
 source "arch/arm/mach-s3c2440/Kconfig"
-source "arch/arm/mach-s3c2443/Kconfig"
 endif
 
 if ARCH_S3C64XX
@@ -1110,13 +1134,11 @@
 config PLAT_IOP
 	bool
 	select GENERIC_CLOCKEVENTS
-	select HAVE_SCHED_CLOCK
 
 config PLAT_ORION
 	bool
 	select CLKSRC_MMIO
 	select GENERIC_IRQ_CHIP
-	select HAVE_SCHED_CLOCK
 
 config PLAT_PXA
 	bool
@@ -1127,6 +1149,7 @@
 config ARM_TIMER_SP804
 	bool
 	select CLKSRC_MMIO
+	select HAVE_SCHED_CLOCK
 
 source arch/arm/mm/Kconfig
 
@@ -1577,7 +1600,8 @@
 config ARCH_NR_GPIO
 	int
 	default 1024 if ARCH_SHMOBILE || ARCH_TEGRA
-	default 350 if ARCH_U8500
+	default 355 if ARCH_U8500
+	default 264 if MACH_H4700
 	default 0
 	help
 	  Maximum number of GPIOs in the system.
@@ -1588,7 +1612,7 @@
 
 config HZ
 	int
-	default 200 if ARCH_EBSA110 || ARCH_S3C2410 || ARCH_S5P64X0 || \
+	default 200 if ARCH_EBSA110 || ARCH_S3C24XX || ARCH_S5P64X0 || \
 		ARCH_S5PV210 || ARCH_EXYNOS4
 	default OMAP_32K_TIMER_HZ if ARCH_OMAP && OMAP_32K_TIMER
 	default AT91_TIMER_HZ if ARCH_AT91
@@ -2114,7 +2138,7 @@
 
 config CPU_FREQ_S3C24XX
 	bool "CPUfreq driver for Samsung S3C24XX series CPUs (EXPERIMENTAL)"
-	depends on ARCH_S3C2410 && CPU_FREQ && EXPERIMENTAL
+	depends on ARCH_S3C24XX && CPU_FREQ && EXPERIMENTAL
 	select CPU_FREQ_S3C
 	help
 	  This enables the CPUfreq driver for the Samsung S3C24XX family
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index e0d236d..85348a0 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -81,47 +81,14 @@
 	prompt "Kernel low-level debugging port"
 	depends on DEBUG_LL
 
-	config DEBUG_LL_UART_NONE
-		bool "No low-level debugging UART"
-		help
-		  Say Y here if your platform doesn't provide a UART option
-		  below. This relies on your platform choosing the right UART
-		  definition internally in order for low-level debugging to
-		  work.
-
-	config DEBUG_ICEDCC
-		bool "Kernel low-level debugging via EmbeddedICE DCC channel"
-		help
-		  Say Y here if you want the debug print routines to direct
-		  their output to the EmbeddedICE macrocell's DCC channel using
-		  co-processor 14. This is known to work on the ARM9 style ICE
-		  channel and on the XScale with the PEEDI.
-
-		  Note that the system will appear to hang during boot if there
-		  is nothing connected to read from the DCC.
-
 	config AT91_DEBUG_LL_DBGU0
 		bool "Kernel low-level debugging on rm9200, 9260/9g20, 9261/9g10 and 9rl"
 		depends on HAVE_AT91_DBGU0
 
 	config AT91_DEBUG_LL_DBGU1
-		bool "Kernel low-level debugging on 9263, 9g45 and cap9"
+		bool "Kernel low-level debugging on 9263 and 9g45"
 		depends on HAVE_AT91_DBGU1
 
-	config DEBUG_FOOTBRIDGE_COM1
-		bool "Kernel low-level debugging messages via footbridge 8250 at PCI COM1"
-		depends on FOOTBRIDGE
-		help
-		  Say Y here if you want the debug print routines to direct
-		  their output to the 8250 at PCI COM1.
-
-	config DEBUG_DC21285_PORT
-		bool "Kernel low-level debugging messages via footbridge serial port"
-		depends on FOOTBRIDGE
-		help
-		  Say Y here if you want the debug print routines to direct
-		  their output to the serial port in the DC21285 (Footbridge).
-
 	config DEBUG_CLPS711X_UART1
 		bool "Kernel low-level debugging messages via UART1"
 		depends on ARCH_CLPS711X
@@ -136,6 +103,20 @@
 		  Say Y here if you want the debug print routines to direct
 		  their output to the second serial port on these devices.
 
+	config DEBUG_DC21285_PORT
+		bool "Kernel low-level debugging messages via footbridge serial port"
+		depends on FOOTBRIDGE
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the serial port in the DC21285 (Footbridge).
+
+	config DEBUG_FOOTBRIDGE_COM1
+		bool "Kernel low-level debugging messages via footbridge 8250 at PCI COM1"
+		depends on FOOTBRIDGE
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the 8250 at PCI COM1.
+
 	config DEBUG_HIGHBANK_UART
 		bool "Kernel low-level debugging messages via Highbank UART"
 		depends on ARCH_HIGHBANK
@@ -199,61 +180,12 @@
 		  Say Y here if you want kernel low-level debugging support
 		  on i.MX50 or i.MX53.
 
-	config DEBUG_IMX6Q_UART
-		bool "i.MX6Q Debug UART"
+	config DEBUG_IMX6Q_UART4
+		bool "i.MX6Q Debug UART4"
 		depends on SOC_IMX6Q
 		help
 		  Say Y here if you want kernel low-level debugging support
-		  on i.MX6Q.
-
-	config DEBUG_S3C_UART0
-		depends on PLAT_SAMSUNG
-		bool "Use S3C UART 0 for low-level debug"
-		help
-		  Say Y here if you want the debug print routines to direct
-		  their output to UART 0. The port must have been initialised
-		  by the boot-loader before use.
-
-		  The uncompressor code port configuration is now handled
-		  by CONFIG_S3C_LOWLEVEL_UART_PORT.
-
-	config DEBUG_S3C_UART1
-		depends on PLAT_SAMSUNG
-		bool "Use S3C UART 1 for low-level debug"
-		help
-		  Say Y here if you want the debug print routines to direct
-		  their output to UART 1. The port must have been initialised
-		  by the boot-loader before use.
-
-		  The uncompressor code port configuration is now handled
-		  by CONFIG_S3C_LOWLEVEL_UART_PORT.
-
-	config DEBUG_S3C_UART2
-		depends on PLAT_SAMSUNG
-		bool "Use S3C UART 2 for low-level debug"
-		help
-		  Say Y here if you want the debug print routines to direct
-		  their output to UART 2. The port must have been initialised
-		  by the boot-loader before use.
-
-		  The uncompressor code port configuration is now handled
-		  by CONFIG_S3C_LOWLEVEL_UART_PORT.
-
-	config DEBUG_REALVIEW_STD_PORT
-		bool "RealView Default UART"
-		depends on ARCH_REALVIEW
-		help
-		  Say Y here if you want the debug print routines to direct
-		  their output to the serial port on RealView EB, PB11MP, PBA8
-		  and PBX platforms.
-
-	config DEBUG_REALVIEW_PB1176_PORT
-		bool "RealView PB1176 UART"
-		depends on MACH_REALVIEW_PB1176
-		help
-		  Say Y here if you want the debug print routines to direct
-		  their output to the standard serial port on the RealView
-		  PB1176 platform.
+		  on i.MX6Q UART4.
 
 	config DEBUG_MSM_UART1
 		bool "Kernel low-level debugging messages via MSM UART1"
@@ -292,6 +224,90 @@
 		  Say Y here if you want the debug print routines to direct
 		  their output to the serial port on MSM 8960 devices.
 
+	config DEBUG_REALVIEW_STD_PORT
+		bool "RealView Default UART"
+		depends on ARCH_REALVIEW
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the serial port on RealView EB, PB11MP, PBA8
+		  and PBX platforms.
+
+	config DEBUG_REALVIEW_PB1176_PORT
+		bool "RealView PB1176 UART"
+		depends on MACH_REALVIEW_PB1176
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the standard serial port on the RealView
+		  PB1176 platform.
+
+	config DEBUG_S3C_UART0
+		depends on PLAT_SAMSUNG
+		bool "Use S3C UART 0 for low-level debug"
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to UART 0. The port must have been initialised
+		  by the boot-loader before use.
+
+		  The uncompressor code port configuration is now handled
+		  by CONFIG_S3C_LOWLEVEL_UART_PORT.
+
+	config DEBUG_S3C_UART1
+		depends on PLAT_SAMSUNG
+		bool "Use S3C UART 1 for low-level debug"
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to UART 1. The port must have been initialised
+		  by the boot-loader before use.
+
+		  The uncompressor code port configuration is now handled
+		  by CONFIG_S3C_LOWLEVEL_UART_PORT.
+
+	config DEBUG_S3C_UART2
+		depends on PLAT_SAMSUNG
+		bool "Use S3C UART 2 for low-level debug"
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to UART 2. The port must have been initialised
+		  by the boot-loader before use.
+
+		  The uncompressor code port configuration is now handled
+		  by CONFIG_S3C_LOWLEVEL_UART_PORT.
+
+	config DEBUG_LL_UART_NONE
+		bool "No low-level debugging UART"
+		help
+		  Say Y here if your platform doesn't provide a UART option
+		  below. This relies on your platform choosing the right UART
+		  definition internally in order for low-level debugging to
+		  work.
+
+	config DEBUG_ICEDCC
+		bool "Kernel low-level debugging via EmbeddedICE DCC channel"
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the EmbeddedICE macrocell's DCC channel using
+		  co-processor 14. This is known to work on the ARM9 style ICE
+		  channel and on the XScale with the PEEDI.
+
+		  Note that the system will appear to hang during boot if there
+		  is nothing connected to read from the DCC.
+
+	config DEBUG_SEMIHOSTING
+		bool "Kernel low-level debug output via semihosting I"
+		help
+		  Semihosting enables code running on an ARM target to use
+		  the I/O facilities on a host debugger/emulator through a
+		  simple SVC calls. The host debugger or emulator must have
+		  semihosting enabled for the special svc call to be trapped
+		  otherwise the kernel will crash.
+
+		  This is known to work with OpenOCD, as wellas
+		  ARM's Fast Models, or any other controlling environment
+		  that implements semihosting.
+
+		  For more details about semihosting, please see
+		  chapter 8 of DUI0203I_rvct_developer_guide.pdf from ARM Ltd.
+
 endchoice
 
 config EARLY_PRINTK
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 1683bfb..047a207 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -174,12 +174,13 @@
 machine-$(CONFIG_ARCH_PXA)		:= pxa
 machine-$(CONFIG_ARCH_REALVIEW)		:= realview
 machine-$(CONFIG_ARCH_RPC)		:= rpc
-machine-$(CONFIG_ARCH_S3C2410)		:= s3c2410 s3c2412 s3c2416 s3c2440 s3c2443
+machine-$(CONFIG_ARCH_S3C24XX)		:= s3c24xx s3c2412 s3c2440
 machine-$(CONFIG_ARCH_S3C64XX)		:= s3c64xx
 machine-$(CONFIG_ARCH_S5P64X0)		:= s5p64x0
 machine-$(CONFIG_ARCH_S5PC100)		:= s5pc100
 machine-$(CONFIG_ARCH_S5PV210)		:= s5pv210
 machine-$(CONFIG_ARCH_EXYNOS4)		:= exynos
+machine-$(CONFIG_ARCH_EXYNOS5)		:= exynos
 machine-$(CONFIG_ARCH_SA1100)		:= sa1100
 machine-$(CONFIG_ARCH_SHARK)		:= shark
 machine-$(CONFIG_ARCH_SHMOBILE) 	:= shmobile
@@ -252,6 +253,7 @@
 
 # If we have a machine-specific directory, then include it in the build.
 core-y				+= arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
+core-y				+= arch/arm/net/
 core-y				+= $(machdirs) $(platdirs)
 
 drivers-$(CONFIG_OPROFILE)      += arch/arm/oprofile/
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index fc871e7..c877087 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -11,8 +11,6 @@
 # Copyright (C) 1995-2002 Russell King
 #
 
-MKIMAGE         := $(srctree)/scripts/mkuboot.sh
-
 ifneq ($(MACHINE),)
 include $(srctree)/$(MACHINE)/Makefile.boot
 endif
@@ -69,22 +67,19 @@
 
 clean-files := *.dtb
 
-quiet_cmd_uimage = UIMAGE  $@
-      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel \
-		   -C none -a $(LOADADDR) -e $(STARTADDR) \
-		   -n 'Linux-$(KERNELRELEASE)' -d $< $@
-
-ifeq ($(CONFIG_ZBOOT_ROM),y)
-$(obj)/uImage: LOADADDR=$(CONFIG_ZBOOT_ROM_TEXT)
+ifneq ($(LOADADDR),)
+  UIMAGE_LOADADDR=$(LOADADDR)
 else
-$(obj)/uImage: LOADADDR=$(ZRELADDR)
+  ifeq ($(CONFIG_ZBOOT_ROM),y)
+    UIMAGE_LOADADDR=$(CONFIG_ZBOOT_ROM_TEXT)
+  else
+    UIMAGE_LOADADDR=$(ZRELADDR)
+  endif
 endif
 
-$(obj)/uImage: STARTADDR=$(LOADADDR)
-
 check_for_multiple_loadaddr = \
-if [ $(words $(LOADADDR)) -gt 1 ]; then \
-	echo 'multiple load addresses: $(LOADADDR)'; \
+if [ $(words $(UIMAGE_LOADADDR)) -gt 1 ]; then \
+	echo 'multiple load addresses: $(UIMAGE_LOADADDR)'; \
 	echo 'This is incompatible with uImages'; \
 	echo 'Specify LOADADDR on the commandline to build an uImage'; \
 	false; \
diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore
index e0936a1..d0d441c 100644
--- a/arch/arm/boot/compressed/.gitignore
+++ b/arch/arm/boot/compressed/.gitignore
@@ -1,8 +1,10 @@
+ashldi3.S
 font.c
 lib1funcs.S
 piggy.gzip
 piggy.lzo
 piggy.lzma
+piggy.xzkern
 vmlinux
 vmlinux.lds
 
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index cf0a64c..bb26756 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -92,6 +92,7 @@
 suffix_$(CONFIG_KERNEL_GZIP) = gzip
 suffix_$(CONFIG_KERNEL_LZO)  = lzo
 suffix_$(CONFIG_KERNEL_LZMA) = lzma
+suffix_$(CONFIG_KERNEL_XZ)   = xzkern
 
 # Borrowed libfdt files for the ATAG compatibility mode
 
@@ -112,10 +113,12 @@
 
 targets       := vmlinux vmlinux.lds \
 		 piggy.$(suffix_y) piggy.$(suffix_y).o \
-		 lib1funcs.o lib1funcs.S font.o font.c head.o misc.o $(OBJS)
+		 lib1funcs.o lib1funcs.S ashldi3.o ashldi3.S \
+		 font.o font.c head.o misc.o $(OBJS)
 
 # Make sure files are removed during clean
-extra-y       += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S $(libfdt) $(libfdt_hdrs)
+extra-y       += piggy.gzip piggy.lzo piggy.lzma piggy.xzkern \
+		 lib1funcs.S ashldi3.S $(libfdt) $(libfdt_hdrs)
 
 ifeq ($(CONFIG_FUNCTION_TRACER),y)
 ORIG_CFLAGS := $(KBUILD_CFLAGS)
@@ -151,6 +154,12 @@
 $(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S
 	$(call cmd,shipped)
 
+# For __aeabi_llsl
+ashldi3 = $(obj)/ashldi3.o
+
+$(obj)/ashldi3.S: $(srctree)/arch/$(SRCARCH)/lib/ashldi3.S
+	$(call cmd,shipped)
+
 # We need to prevent any GOTOFF relocs being used with references
 # to symbols in the .bss section since we cannot relocate them
 # independently from the rest at run time.  This can be achieved by
@@ -172,7 +181,7 @@
 fi
 
 $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
-	 	$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE
+		$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) FORCE
 	@$(check_for_multiple_zreladdr)
 	$(call if_changed,ld)
 	@$(check_for_bad_syms)
diff --git a/arch/arm/boot/compressed/decompress.c b/arch/arm/boot/compressed/decompress.c
index 07be5a2..f41b38c 100644
--- a/arch/arm/boot/compressed/decompress.c
+++ b/arch/arm/boot/compressed/decompress.c
@@ -44,6 +44,12 @@
 #include "../../../../lib/decompress_unlzma.c"
 #endif
 
+#ifdef CONFIG_KERNEL_XZ
+#define memmove memmove
+#define memcpy memcpy
+#include "../../../../lib/decompress_unxz.c"
+#endif
+
 int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x))
 {
 	return decompress(input, len, NULL, NULL, output, NULL, error);
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index c5d6025..5f6045f 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -58,7 +58,7 @@
 		add	\rb, \rb, #0x00010000	@ Ser1
 #endif
 		.endm
-#elif defined(CONFIG_ARCH_S3C2410)
+#elif defined(CONFIG_ARCH_S3C24XX)
 		.macro loadsp, rb, tmp
 		mov	\rb, #0x50000000
 		add	\rb, \rb, #0x4000 * CONFIG_S3C_LOWLEVEL_UART_PORT
diff --git a/arch/arm/boot/compressed/piggy.xzkern.S b/arch/arm/boot/compressed/piggy.xzkern.S
new file mode 100644
index 0000000..5703f30
--- /dev/null
+++ b/arch/arm/boot/compressed/piggy.xzkern.S
@@ -0,0 +1,6 @@
+	.section .piggydata,#alloc
+	.globl	input_data
+input_data:
+	.incbin	"arch/arm/boot/compressed/piggy.xzkern"
+	.globl	input_data_end
+input_data_end:
diff --git a/arch/arm/boot/dts/am3517_mt_ventoux.dts b/arch/arm/boot/dts/am3517_mt_ventoux.dts
new file mode 100644
index 0000000..5eb26d7
--- /dev/null
+++ b/arch/arm/boot/dts/am3517_mt_ventoux.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011 Ilya Yanok, EmCraft Systems
+ *
+ * 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.
+ */
+/dts-v1/;
+
+/include/ "omap3.dtsi"
+
+/ {
+	model = "TeeJet Mt.Ventoux";
+	compatible = "teejet,mt_ventoux", "ti,omap3";
+
+	memory {
+		device_type = "memory";
+		reg = <0x80000000 0x10000000>; /* 256 MB */
+	};
+
+	/* AM35xx doesn't have IVA */
+	soc {
+		iva {
+			status = "disabled";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi
index 07603b8..799ad18 100644
--- a/arch/arm/boot/dts/at91sam9g20.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20.dtsi
@@ -23,6 +23,11 @@
 		serial4 = &usart3;
 		serial5 = &usart4;
 		serial6 = &usart5;
+		gpio0 = &pioA;
+		gpio1 = &pioB;
+		gpio2 = &pioC;
+		tcb0 = &tcb0;
+		tcb1 = &tcb1;
 	};
 	cpus {
 		cpu@0 {
@@ -30,7 +35,7 @@
 		};
 	};
 
-	memory@20000000 {
+	memory {
 		reg = <0x20000000 0x08000000>;
 	};
 
@@ -47,24 +52,89 @@
 			ranges;
 
 			aic: interrupt-controller@fffff000 {
-				#interrupt-cells = <1>;
+				#interrupt-cells = <2>;
 				compatible = "atmel,at91rm9200-aic";
 				interrupt-controller;
 				interrupt-parent;
 				reg = <0xfffff000 0x200>;
 			};
 
+			ramc0: ramc@ffffea00 {
+				compatible = "atmel,at91sam9260-sdramc";
+				reg = <0xffffea00 0x200>;
+			};
+
+			pmc: pmc@fffffc00 {
+				compatible = "atmel,at91rm9200-pmc";
+				reg = <0xfffffc00 0x100>;
+			};
+
+			rstc@fffffd00 {
+				compatible = "atmel,at91sam9260-rstc";
+				reg = <0xfffffd00 0x10>;
+			};
+
+			shdwc@fffffd10 {
+				compatible = "atmel,at91sam9260-shdwc";
+				reg = <0xfffffd10 0x10>;
+			};
+
+			pit: timer@fffffd30 {
+				compatible = "atmel,at91sam9260-pit";
+				reg = <0xfffffd30 0xf>;
+				interrupts = <1 4>;
+			};
+
+			tcb0: timer@fffa0000 {
+				compatible = "atmel,at91rm9200-tcb";
+				reg = <0xfffa0000 0x100>;
+				interrupts = <17 4 18 4 19 4>;
+			};
+
+			tcb1: timer@fffdc000 {
+				compatible = "atmel,at91rm9200-tcb";
+				reg = <0xfffdc000 0x100>;
+				interrupts = <26 4 27 4 28 4>;
+			};
+
+			pioA: gpio@fffff400 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffff400 0x100>;
+				interrupts = <2 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioB: gpio@fffff600 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffff600 0x100>;
+				interrupts = <3 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioC: gpio@fffff800 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffff800 0x100>;
+				interrupts = <4 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
 			dbgu: serial@fffff200 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfffff200 0x200>;
-				interrupts = <1>;
+				interrupts = <1 4>;
 				status = "disabled";
 			};
 
 			usart0: serial@fffb0000 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfffb0000 0x200>;
-				interrupts = <6>;
+				interrupts = <6 4>;
 				atmel,use-dma-rx;
 				atmel,use-dma-tx;
 				status = "disabled";
@@ -73,7 +143,7 @@
 			usart1: serial@fffb4000 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfffb4000 0x200>;
-				interrupts = <7>;
+				interrupts = <7 4>;
 				atmel,use-dma-rx;
 				atmel,use-dma-tx;
 				status = "disabled";
@@ -82,7 +152,7 @@
 			usart2: serial@fffb8000 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfffb8000 0x200>;
-				interrupts = <8>;
+				interrupts = <8 4>;
 				atmel,use-dma-rx;
 				atmel,use-dma-tx;
 				status = "disabled";
@@ -91,7 +161,7 @@
 			usart3: serial@fffd0000 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfffd0000 0x200>;
-				interrupts = <23>;
+				interrupts = <23 4>;
 				atmel,use-dma-rx;
 				atmel,use-dma-tx;
 				status = "disabled";
@@ -100,7 +170,7 @@
 			usart4: serial@fffd4000 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfffd4000 0x200>;
-				interrupts = <24>;
+				interrupts = <24 4>;
 				atmel,use-dma-rx;
 				atmel,use-dma-tx;
 				status = "disabled";
@@ -109,7 +179,7 @@
 			usart5: serial@fffd8000 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfffd8000 0x200>;
-				interrupts = <25>;
+				interrupts = <25 4>;
 				atmel,use-dma-rx;
 				atmel,use-dma-tx;
 				status = "disabled";
@@ -118,9 +188,52 @@
 			macb0: ethernet@fffc4000 {
 				compatible = "cdns,at32ap7000-macb", "cdns,macb";
 				reg = <0xfffc4000 0x100>;
-				interrupts = <21>;
+				interrupts = <21 4>;
+				status = "disabled";
+			};
+
+			usb1: gadget@fffa4000 {
+				compatible = "atmel,at91rm9200-udc";
+				reg = <0xfffa4000 0x4000>;
+				interrupts = <10 4>;
 				status = "disabled";
 			};
 		};
+
+		nand0: nand@40000000 {
+			compatible = "atmel,at91rm9200-nand";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x40000000 0x10000000
+			       0xffffe800 0x200
+			      >;
+			atmel,nand-addr-offset = <21>;
+			atmel,nand-cmd-offset = <22>;
+			gpios = <&pioC 13 0
+				 &pioC 14 0
+				 0
+				>;
+			status = "disabled";
+		};
+
+		usb0: ohci@00500000 {
+			compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+			reg = <0x00500000 0x100000>;
+			interrupts = <20 4>;
+			status = "disabled";
+		};
+	};
+
+	i2c@0 {
+		compatible = "i2c-gpio";
+		gpios = <&pioA 23 0 /* sda */
+			 &pioA 24 0 /* scl */
+			>;
+		i2c-gpio,sda-open-drain;
+		i2c-gpio,scl-open-drain;
+		i2c-gpio,delay-us = <2>;	/* ~100 kHz */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
 	};
 };
diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
new file mode 100644
index 0000000..7829a4d
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9g25ek.dts
@@ -0,0 +1,49 @@
+/*
+ * at91sam9g25ek.dts - Device Tree file for AT91SAM9G25-EK board
+ *
+ *  Copyright (C) 2012 Atmel,
+ *                2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+/include/ "at91sam9x5.dtsi"
+/include/ "at91sam9x5cm.dtsi"
+
+/ {
+	model = "Atmel AT91SAM9G25-EK";
+	compatible = "atmel,at91sam9g25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+
+	chosen {
+		bootargs = "128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
+	};
+
+	ahb {
+		apb {
+			dbgu: serial@fffff200 {
+				status = "okay";
+			};
+
+			usart0: serial@f801c000 {
+				status = "okay";
+			};
+
+			macb0: ethernet@f802c000 {
+				phy-mode = "rmii";
+				status = "okay";
+			};
+		};
+
+		usb0: ohci@00600000 {
+			status = "okay";
+			num-ports = <2>;
+			atmel,vbus-gpio = <&pioD 19 1
+					   &pioD 20 1
+					  >;
+		};
+
+		usb1: ehci@00700000 {
+			status = "okay";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index fffa005..9e6eb6e 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -22,6 +22,13 @@
 		serial2 = &usart1;
 		serial3 = &usart2;
 		serial4 = &usart3;
+		gpio0 = &pioA;
+		gpio1 = &pioB;
+		gpio2 = &pioC;
+		gpio3 = &pioD;
+		gpio4 = &pioE;
+		tcb0 = &tcb0;
+		tcb1 = &tcb1;
 	};
 	cpus {
 		cpu@0 {
@@ -29,7 +36,7 @@
 		};
 	};
 
-	memory@70000000 {
+	memory {
 		reg = <0x70000000 0x10000000>;
 	};
 
@@ -46,30 +53,115 @@
 			ranges;
 
 			aic: interrupt-controller@fffff000 {
-				#interrupt-cells = <1>;
+				#interrupt-cells = <2>;
 				compatible = "atmel,at91rm9200-aic";
 				interrupt-controller;
 				interrupt-parent;
 				reg = <0xfffff000 0x200>;
 			};
 
+			ramc0: ramc@ffffe400 {
+				compatible = "atmel,at91sam9g45-ddramc";
+				reg = <0xffffe400 0x200
+				       0xffffe600 0x200>;
+			};
+
+			pmc: pmc@fffffc00 {
+				compatible = "atmel,at91rm9200-pmc";
+				reg = <0xfffffc00 0x100>;
+			};
+
+			rstc@fffffd00 {
+				compatible = "atmel,at91sam9g45-rstc";
+				reg = <0xfffffd00 0x10>;
+			};
+
+			pit: timer@fffffd30 {
+				compatible = "atmel,at91sam9260-pit";
+				reg = <0xfffffd30 0xf>;
+				interrupts = <1 4>;
+			};
+
+
+			shdwc@fffffd10 {
+				compatible = "atmel,at91sam9rl-shdwc";
+				reg = <0xfffffd10 0x10>;
+			};
+
+			tcb0: timer@fff7c000 {
+				compatible = "atmel,at91rm9200-tcb";
+				reg = <0xfff7c000 0x100>;
+				interrupts = <18 4>;
+			};
+
+			tcb1: timer@fffd4000 {
+				compatible = "atmel,at91rm9200-tcb";
+				reg = <0xfffd4000 0x100>;
+				interrupts = <18 4>;
+			};
+
 			dma: dma-controller@ffffec00 {
 				compatible = "atmel,at91sam9g45-dma";
 				reg = <0xffffec00 0x200>;
-				interrupts = <21>;
+				interrupts = <21 4>;
+			};
+
+			pioA: gpio@fffff200 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffff200 0x100>;
+				interrupts = <2 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioB: gpio@fffff400 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffff400 0x100>;
+				interrupts = <3 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioC: gpio@fffff600 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffff600 0x100>;
+				interrupts = <4 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioD: gpio@fffff800 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffff800 0x100>;
+				interrupts = <5 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioE: gpio@fffffa00 {
+				compatible = "atmel,at91rm9200-gpio";
+				reg = <0xfffffa00 0x100>;
+				interrupts = <5 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
 			};
 
 			dbgu: serial@ffffee00 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xffffee00 0x200>;
-				interrupts = <1>;
+				interrupts = <1 4>;
 				status = "disabled";
 			};
 
 			usart0: serial@fff8c000 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfff8c000 0x200>;
-				interrupts = <7>;
+				interrupts = <7 4>;
 				atmel,use-dma-rx;
 				atmel,use-dma-tx;
 				status = "disabled";
@@ -78,7 +170,7 @@
 			usart1: serial@fff90000 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfff90000 0x200>;
-				interrupts = <8>;
+				interrupts = <8 4>;
 				atmel,use-dma-rx;
 				atmel,use-dma-tx;
 				status = "disabled";
@@ -87,7 +179,7 @@
 			usart2: serial@fff94000 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfff94000 0x200>;
-				interrupts = <9>;
+				interrupts = <9 4>;
 				atmel,use-dma-rx;
 				atmel,use-dma-tx;
 				status = "disabled";
@@ -96,7 +188,7 @@
 			usart3: serial@fff98000 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfff98000 0x200>;
-				interrupts = <10>;
+				interrupts = <10 4>;
 				atmel,use-dma-rx;
 				atmel,use-dma-tx;
 				status = "disabled";
@@ -105,9 +197,52 @@
 			macb0: ethernet@fffbc000 {
 				compatible = "cdns,at32ap7000-macb", "cdns,macb";
 				reg = <0xfffbc000 0x100>;
-				interrupts = <25>;
+				interrupts = <25 4>;
 				status = "disabled";
 			};
 		};
+
+		nand0: nand@40000000 {
+			compatible = "atmel,at91rm9200-nand";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x40000000 0x10000000
+			       0xffffe200 0x200
+			      >;
+			atmel,nand-addr-offset = <21>;
+			atmel,nand-cmd-offset = <22>;
+			gpios = <&pioC 8 0
+				 &pioC 14 0
+				 0
+				>;
+			status = "disabled";
+		};
+
+		usb0: ohci@00700000 {
+			compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+			reg = <0x00700000 0x100000>;
+			interrupts = <22 4>;
+			status = "disabled";
+		};
+
+		usb1: ehci@00800000 {
+			compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
+			reg = <0x00800000 0x100000>;
+			interrupts = <22 4>;
+			status = "disabled";
+		};
+	};
+
+	i2c@0 {
+		compatible = "i2c-gpio";
+		gpios = <&pioA 20 0 /* sda */
+			 &pioA 21 0 /* scl */
+			>;
+		i2c-gpio,sda-open-drain;
+		i2c-gpio,scl-open-drain;
+		i2c-gpio,delay-us = <5>;	/* ~100 kHz */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
 	};
 };
diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
index a387e77..a3633bd 100644
--- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
+++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
@@ -14,13 +14,24 @@
 	compatible = "atmel,at91sam9m10g45ek", "atmel,at91sam9g45", "atmel,at91sam9";
 
 	chosen {
-		bootargs = "mem=64M console=ttyS0,115200 mtdparts=atmel_nand:4M(bootstrap/uboot/kernel)ro,60M(rootfs),-(data) root=/dev/mtdblock1 rw rootfstype=jffs2";
+		bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2";
 	};
 
-	memory@70000000 {
+	memory {
 		reg = <0x70000000 0x4000000>;
 	};
 
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		main_clock: clock@0 {
+			compatible = "atmel,osc", "fixed-clock";
+			clock-frequency = <12000000>;
+		};
+	};
+
 	ahb {
 		apb {
 			dbgu: serial@ffffee00 {
@@ -36,5 +47,110 @@
 				status = "okay";
 			};
 		};
+
+		nand0: nand@40000000 {
+			nand-bus-width = <8>;
+			nand-ecc-mode = "soft";
+			nand-on-flash-bbt;
+			status = "okay";
+
+			boot@0 {
+				label = "bootstrap/uboot/kernel";
+				reg = <0x0 0x400000>;
+			};
+
+			rootfs@400000 {
+				label = "rootfs";
+				reg = <0x400000 0x3C00000>;
+			};
+
+			data@4000000 {
+				label = "data";
+				reg = <0x4000000 0xC000000>;
+			};
+		};
+
+		usb0: ohci@00700000 {
+			status = "okay";
+			num-ports = <2>;
+			atmel,vbus-gpio = <&pioD 1 1
+					   &pioD 3 1>;
+		};
+
+		usb1: ehci@00800000 {
+			status = "okay";
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		d8 {
+			label = "d8";
+			gpios = <&pioD 30 0>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		d6 {
+			label = "d6";
+			gpios = <&pioD 0 1>;
+			linux,default-trigger = "nand-disk";
+		};
+
+		d7 {
+			label = "d7";
+			gpios = <&pioD 31 1>;
+			linux,default-trigger = "mmc0";
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		left_click {
+			label = "left_click";
+			gpios = <&pioB 6 1>;
+			linux,code = <272>;
+			gpio-key,wakeup;
+		};
+
+		right_click {
+			label = "right_click";
+			gpios = <&pioB 7 1>;
+			linux,code = <273>;
+			gpio-key,wakeup;
+		};
+
+		left {
+			label = "Joystick Left";
+			gpios = <&pioB 14 1>;
+			linux,code = <105>;
+		};
+
+		right {
+			label = "Joystick Right";
+			gpios = <&pioB 15 1>;
+			linux,code = <106>;
+		};
+
+		up {
+			label = "Joystick Up";
+			gpios = <&pioB 16 1>;
+			linux,code = <103>;
+		};
+
+		down {
+			label = "Joystick Down";
+			gpios = <&pioB 17 1>;
+			linux,code = <108>;
+		};
+
+		enter {
+			label = "Joystick Press";
+			gpios = <&pioB 18 1>;
+			linux,code = <28>;
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
new file mode 100644
index 0000000..70ab3a4
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -0,0 +1,264 @@
+/*
+ * at91sam9x5.dtsi - Device Tree Include file for AT91SAM9x5 family SoC
+ *                   applies to AT91SAM9G15, AT91SAM9G25, AT91SAM9G35,
+ *                   AT91SAM9X25, AT91SAM9X35 SoC
+ *
+ *  Copyright (C) 2012 Atmel,
+ *                2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "Atmel AT91SAM9x5 family SoC";
+	compatible = "atmel,at91sam9x5";
+	interrupt-parent = <&aic>;
+
+	aliases {
+		serial0 = &dbgu;
+		serial1 = &usart0;
+		serial2 = &usart1;
+		serial3 = &usart2;
+		gpio0 = &pioA;
+		gpio1 = &pioB;
+		gpio2 = &pioC;
+		gpio3 = &pioD;
+		tcb0 = &tcb0;
+		tcb1 = &tcb1;
+	};
+	cpus {
+		cpu@0 {
+			compatible = "arm,arm926ejs";
+		};
+	};
+
+	memory {
+		reg = <0x20000000 0x10000000>;
+	};
+
+	ahb {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		apb {
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			aic: interrupt-controller@fffff000 {
+				#interrupt-cells = <2>;
+				compatible = "atmel,at91rm9200-aic";
+				interrupt-controller;
+				interrupt-parent;
+				reg = <0xfffff000 0x200>;
+			};
+
+			ramc0: ramc@ffffe800 {
+				compatible = "atmel,at91sam9g45-ddramc";
+				reg = <0xffffe800 0x200>;
+			};
+
+			pmc: pmc@fffffc00 {
+				compatible = "atmel,at91rm9200-pmc";
+				reg = <0xfffffc00 0x100>;
+			};
+
+			rstc@fffffe00 {
+				compatible = "atmel,at91sam9g45-rstc";
+				reg = <0xfffffe00 0x10>;
+			};
+
+			shdwc@fffffe10 {
+				compatible = "atmel,at91sam9x5-shdwc";
+				reg = <0xfffffe10 0x10>;
+			};
+
+			pit: timer@fffffe30 {
+				compatible = "atmel,at91sam9260-pit";
+				reg = <0xfffffe30 0xf>;
+				interrupts = <1 4>;
+			};
+
+			tcb0: timer@f8008000 {
+				compatible = "atmel,at91sam9x5-tcb";
+				reg = <0xf8008000 0x100>;
+				interrupts = <17 4>;
+			};
+
+			tcb1: timer@f800c000 {
+				compatible = "atmel,at91sam9x5-tcb";
+				reg = <0xf800c000 0x100>;
+				interrupts = <17 4>;
+			};
+
+			dma0: dma-controller@ffffec00 {
+				compatible = "atmel,at91sam9g45-dma";
+				reg = <0xffffec00 0x200>;
+				interrupts = <20 4>;
+			};
+
+			dma1: dma-controller@ffffee00 {
+				compatible = "atmel,at91sam9g45-dma";
+				reg = <0xffffee00 0x200>;
+				interrupts = <21 4>;
+			};
+
+			pioA: gpio@fffff400 {
+				compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+				reg = <0xfffff400 0x100>;
+				interrupts = <2 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioB: gpio@fffff600 {
+				compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+				reg = <0xfffff600 0x100>;
+				interrupts = <2 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioC: gpio@fffff800 {
+				compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+				reg = <0xfffff800 0x100>;
+				interrupts = <3 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			pioD: gpio@fffffa00 {
+				compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+				reg = <0xfffffa00 0x100>;
+				interrupts = <3 4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			dbgu: serial@fffff200 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xfffff200 0x200>;
+				interrupts = <1 4>;
+				status = "disabled";
+			};
+
+			usart0: serial@f801c000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xf801c000 0x200>;
+				interrupts = <5 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+
+			usart1: serial@f8020000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xf8020000 0x200>;
+				interrupts = <6 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+
+			usart2: serial@f8024000 {
+				compatible = "atmel,at91sam9260-usart";
+				reg = <0xf8024000 0x200>;
+				interrupts = <7 4>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "disabled";
+			};
+
+			macb0: ethernet@f802c000 {
+				compatible = "cdns,at32ap7000-macb", "cdns,macb";
+				reg = <0xf802c000 0x100>;
+				interrupts = <24 4>;
+				status = "disabled";
+			};
+
+			macb1: ethernet@f8030000 {
+				compatible = "cdns,at32ap7000-macb", "cdns,macb";
+				reg = <0xf8030000 0x100>;
+				interrupts = <27 4>;
+				status = "disabled";
+			};
+		};
+
+		nand0: nand@40000000 {
+			compatible = "atmel,at91rm9200-nand";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x40000000 0x10000000
+			      >;
+			atmel,nand-addr-offset = <21>;
+			atmel,nand-cmd-offset = <22>;
+			gpios = <&pioD 5 0
+				 &pioD 4 0
+				 0
+				>;
+			status = "disabled";
+		};
+
+		usb0: ohci@00600000 {
+			compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+			reg = <0x00600000 0x100000>;
+			interrupts = <22 4>;
+			status = "disabled";
+		};
+
+		usb1: ehci@00700000 {
+			compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
+			reg = <0x00700000 0x100000>;
+			interrupts = <22 4>;
+			status = "disabled";
+		};
+	};
+
+	i2c@0 {
+		compatible = "i2c-gpio";
+		gpios = <&pioA 30 0 /* sda */
+			 &pioA 31 0 /* scl */
+			>;
+		i2c-gpio,sda-open-drain;
+		i2c-gpio,scl-open-drain;
+		i2c-gpio,delay-us = <2>;	/* ~100 kHz */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	i2c@1 {
+		compatible = "i2c-gpio";
+		gpios = <&pioC 0 0 /* sda */
+			 &pioC 1 0 /* scl */
+			>;
+		i2c-gpio,sda-open-drain;
+		i2c-gpio,scl-open-drain;
+		i2c-gpio,delay-us = <2>;	/* ~100 kHz */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	i2c@2 {
+		compatible = "i2c-gpio";
+		gpios = <&pioB 4 0 /* sda */
+			 &pioB 5 0 /* scl */
+			>;
+		i2c-gpio,sda-open-drain;
+		i2c-gpio,scl-open-drain;
+		i2c-gpio,delay-us = <2>;	/* ~100 kHz */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+};
diff --git a/arch/arm/boot/dts/at91sam9x5cm.dtsi b/arch/arm/boot/dts/at91sam9x5cm.dtsi
new file mode 100644
index 0000000..31e7be2
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9x5cm.dtsi
@@ -0,0 +1,74 @@
+/*
+ * at91sam9x5cm.dtsi - Device Tree Include file for AT91SAM9x5 CPU Module
+ *
+ *  Copyright (C) 2012 Atmel,
+ *                2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/ {
+	memory {
+		reg = <0x20000000 0x8000000>;
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		main_clock: clock@0 {
+			compatible = "atmel,osc", "fixed-clock";
+			clock-frequency = <12000000>;
+		};
+	};
+
+	ahb {
+		nand0: nand@40000000 {
+			nand-bus-width = <8>;
+			nand-ecc-mode = "soft";
+			nand-on-flash-bbt;
+			status = "okay";
+
+			at91bootstrap@0 {
+				label = "at91bootstrap";
+				reg = <0x0 0x40000>;
+			};
+
+			uboot@40000 {
+				label = "u-boot";
+				reg = <0x40000 0x80000>;
+			};
+
+			ubootenv@c0000 {
+				label = "U-Boot Env";
+				reg = <0xc0000 0x140000>;
+			};
+
+			kernel@200000 {
+				label = "kernel";
+				reg = <0x200000 0x600000>;
+			};
+
+			rootfs@800000 {
+				label = "rootfs";
+				reg = <0x800000 0x1f800000>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		pb18 {
+			label = "pb18";
+			gpios = <&pioB 18 1>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		pd21 {
+			label = "pd21";
+			gpios = <&pioD 21 0>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/db8500.dtsi b/arch/arm/boot/dts/db8500.dtsi
new file mode 100644
index 0000000..d73dce6
--- /dev/null
+++ b/arch/arm/boot/dts/db8500.dtsi
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2012 Linaro Ltd
+ *
+ * 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/ "skeleton.dtsi"
+
+/ {
+	soc-u9500 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "stericsson,db8500";
+		interrupt-parent = <&intc>;
+		ranges;
+
+		intc: interrupt-controller@a0411000 {
+			compatible = "arm,cortex-a9-gic";
+			#interrupt-cells = <3>;
+			#address-cells = <1>;
+			interrupt-controller;
+			interrupt-parent;
+			reg = <0xa0411000 0x1000>,
+			      <0xa0410100 0x100>;
+		};
+
+		L2: l2-cache {
+			compatible = "arm,pl310-cache";
+			reg = <0xa0412000 0x1000>;
+			interrupts = <0 13 4>;
+			cache-unified;
+			cache-level = <2>;
+		};
+
+		pmu {
+			compatible = "arm,cortex-a9-pmu";
+			interrupts = <0 7 0x4>;
+		};
+
+		timer@a0410600 {
+			compatible = "arm,cortex-a9-twd-timer";
+			reg = <0xa0410600 0x20>;
+			interrupts = <1 13 0x304>;
+		};
+
+		rtc@80154000 {
+			compatible = "stericsson,db8500-rtc";
+			reg = <0x80154000 0x1000>;
+			interrupts = <0 18 0x4>;
+		};
+
+		gpio0: gpio@8012e000 {
+			compatible = "stericsson,db8500-gpio",
+				"stmicroelectronics,nomadik-gpio";
+			reg =  <0x8012e000 0x80>;
+			interrupts = <0 119 0x4>;
+			supports-sleepmode;
+			gpio-controller;
+		};
+
+		gpio1: gpio@8012e080 {
+			compatible = "stericsson,db8500-gpio",
+				"stmicroelectronics,nomadik-gpio";
+			reg =  <0x8012e080 0x80>;
+			interrupts = <0 120 0x4>;
+			supports-sleepmode;
+			gpio-controller;
+		};
+
+		gpio2: gpio@8000e000 {
+			compatible = "stericsson,db8500-gpio",
+				"stmicroelectronics,nomadik-gpio";
+			reg =  <0x8000e000 0x80>;
+			interrupts = <0 121 0x4>;
+			supports-sleepmode;
+			gpio-controller;
+		};
+
+		gpio3: gpio@8000e080 {
+			compatible = "stericsson,db8500-gpio",
+				"stmicroelectronics,nomadik-gpio";
+			reg =  <0x8000e080 0x80>;
+			interrupts = <0 122 0x4>;
+			supports-sleepmode;
+			gpio-controller;
+		};
+
+		gpio4: gpio@8000e100 {
+			compatible = "stericsson,db8500-gpio",
+				"stmicroelectronics,nomadik-gpio";
+			reg =  <0x8000e100 0x80>;
+			interrupts = <0 123 0x4>;
+			supports-sleepmode;
+			gpio-controller;
+		};
+
+		gpio5: gpio@8000e180 {
+			compatible = "stericsson,db8500-gpio",
+				"stmicroelectronics,nomadik-gpio";
+			reg =  <0x8000e180 0x80>;
+			interrupts = <0 124 0x4>;
+			supports-sleepmode;
+			gpio-controller;
+		};
+
+		gpio6: gpio@8011e000 {
+			compatible = "stericsson,db8500-gpio",
+				"stmicroelectronics,nomadik-gpio";
+			reg =  <0x8011e000 0x80>;
+			interrupts = <0 125 0x4>;
+			supports-sleepmode;
+			gpio-controller;
+		};
+
+		gpio7: gpio@8011e080 {
+			compatible = "stericsson,db8500-gpio",
+				"stmicroelectronics,nomadik-gpio";
+			reg =  <0x8011e080 0x80>;
+			interrupts = <0 126 0x4>;
+			supports-sleepmode;
+			gpio-controller;
+		};
+
+		gpio8: gpio@a03fe000 {
+			compatible = "stericsson,db8500-gpio",
+				"stmicroelectronics,nomadik-gpio";
+			reg =  <0xa03fe000 0x80>;
+			interrupts = <0 127 0x4>;
+			supports-sleepmode;
+			gpio-controller;
+		};
+
+		usb@a03e0000 {
+			compatible = "stericsson,db8500-musb",
+				"mentor,musb";
+			reg = <0xa03e0000 0x10000>;
+			interrupts = <0 23 0x4>;
+		};
+
+		dma-controller@801C0000 {
+			compatible = "stericsson,db8500-dma40",
+					"stericsson,dma40";
+			reg = <0x801C0000 0x1000 0x40010000 0x800>;
+			interrupts = <0 25 0x4>;
+		};
+
+		prcmu@80157000 {
+			compatible = "stericsson,db8500-prcmu";
+			reg = <0x80157000 0x1000>;
+			interrupts = <46 47>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ab8500@5 {
+				compatible = "stericsson,ab8500";
+				reg = <5>; /* mailbox 5 is i2c */
+				interrupts = <0 40 0x4>;
+			};
+		};
+
+		i2c@80004000 {
+			compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+			reg = <0x80004000 0x1000>;
+			interrupts = <0 21 0x4>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c@80122000 {
+			compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+			reg = <0x80122000 0x1000>;
+			interrupts = <0 22 0x4>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c@80128000 {
+			compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+			reg = <0x80128000 0x1000>;
+			interrupts = <0 55 0x4>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c@80110000 {
+			compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+			reg = <0x80110000 0x1000>;
+			interrupts = <0 12 0x4>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c@8012a000 {
+			compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+			reg = <0x8012a000 0x1000>;
+			interrupts = <0 51 0x4>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		ssp@80002000 {
+			compatible = "arm,pl022", "arm,primecell";
+			reg = <80002000 0x1000>;
+			interrupts = <0 14 0x4>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+
+			// Add one of these for each child device
+			cs-gpios = <&gpio0 31 &gpio4 14 &gpio4 16 &gpio6 22 &gpio7 0>;
+
+		};
+
+		uart@80120000 {
+			compatible = "arm,pl011", "arm,primecell";
+			reg = <0x80120000 0x1000>;
+			interrupts = <0 11 0x4>;
+			status = "disabled";
+		};
+		uart@80121000 {
+			compatible = "arm,pl011", "arm,primecell";
+			reg = <0x80121000 0x1000>;
+			interrupts = <0 19 0x4>;
+			status = "disabled";
+		};
+		uart@80007000 {
+			compatible = "arm,pl011", "arm,primecell";
+			reg = <0x80007000 0x1000>;
+			interrupts = <0 26 0x4>;
+			status = "disabled";
+		};
+
+		sdi@80126000 {
+			compatible = "arm,pl18x", "arm,primecell";
+			reg = <0x80126000 0x1000>;
+			interrupts = <0 60 0x4>;
+			status = "disabled";
+		};
+		sdi@80118000 {
+			compatible = "arm,pl18x", "arm,primecell";
+			reg = <0x80118000 0x1000>;
+			interrupts = <0 50 0x4>;
+			status = "disabled";
+		};
+		sdi@80005000 {
+			compatible = "arm,pl18x", "arm,primecell";
+			reg = <0x80005000 0x1000>;
+			interrupts = <0 41 0x4>;
+			status = "disabled";
+		};
+		sdi@80119000 {
+			compatible = "arm,pl18x", "arm,primecell";
+			reg = <0x80119000 0x1000>;
+			interrupts = <0 59 0x4>;
+			status = "disabled";
+		};
+		sdi@80114000 {
+			compatible = "arm,pl18x", "arm,primecell";
+			reg = <0x80114000 0x1000>;
+			interrupts = <0 99 0x4>;
+			status = "disabled";
+		};
+		sdi@80008000 {
+			compatible = "arm,pl18x", "arm,primecell";
+			reg = <0x80114000 0x1000>;
+			interrupts = <0 100 0x4>;
+			status = "disabled";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts
new file mode 100644
index 0000000..399d17b
--- /dev/null
+++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
@@ -0,0 +1,26 @@
+/*
+ * SAMSUNG SMDK5250 board device tree source
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *		http://www.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.
+*/
+
+/dts-v1/;
+/include/ "exynos5250.dtsi"
+
+/ {
+	model = "SAMSUNG SMDK5250 board based on EXYNOS5250";
+	compatible = "samsung,smdk5250", "samsung,exynos5250";
+
+	memory {
+		reg = <0x40000000 0x80000000>;
+	};
+
+	chosen {
+		bootargs = "root=/dev/ram0 rw ramdisk=8192 console=ttySAC1,115200";
+	};
+};
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
new file mode 100644
index 0000000..dfc4335
--- /dev/null
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -0,0 +1,413 @@
+/*
+ * SAMSUNG EXYNOS5250 SoC device tree source
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * SAMSUNG EXYNOS5250 SoC device nodes are listed in this file.
+ * EXYNOS5250 based board files can include this file and provide
+ * values for board specfic bindings.
+ *
+ * Note: This file does not include device nodes for all the controllers in
+ * EXYNOS5250 SoC. As device tree coverage for EXYNOS5250 increases,
+ * additional nodes can be added to this file.
+ *
+ * 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/ "skeleton.dtsi"
+
+/ {
+	compatible = "samsung,exynos5250";
+	interrupt-parent = <&gic>;
+
+	gic:interrupt-controller@10490000 {
+		compatible = "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		interrupt-controller;
+		reg = <0x10490000 0x1000>, <0x10480000 0x100>;
+	};
+
+	watchdog {
+		compatible = "samsung,s3c2410-wdt";
+		reg = <0x101D0000 0x100>;
+		interrupts = <0 42 0>;
+	};
+
+	rtc {
+		compatible = "samsung,s3c6410-rtc";
+		reg = <0x101E0000 0x100>;
+		interrupts = <0 43 0>, <0 44 0>;
+	};
+
+	sdhci@12200000 {
+		compatible = "samsung,exynos4210-sdhci";
+		reg = <0x12200000 0x100>;
+		interrupts = <0 75 0>;
+	};
+
+	sdhci@12210000 {
+		compatible = "samsung,exynos4210-sdhci";
+		reg = <0x12210000 0x100>;
+		interrupts = <0 76 0>;
+	};
+
+	sdhci@12220000 {
+		compatible = "samsung,exynos4210-sdhci";
+		reg = <0x12220000 0x100>;
+		interrupts = <0 77 0>;
+	};
+
+	sdhci@12230000 {
+		compatible = "samsung,exynos4210-sdhci";
+		reg = <0x12230000 0x100>;
+		interrupts = <0 78 0>;
+	};
+
+	serial@12C00000 {
+		compatible = "samsung,exynos4210-uart";
+		reg = <0x12C00000 0x100>;
+		interrupts = <0 51 0>;
+	};
+
+	serial@12C10000 {
+		compatible = "samsung,exynos4210-uart";
+		reg = <0x12C10000 0x100>;
+		interrupts = <0 52 0>;
+	};
+
+	serial@12C20000 {
+		compatible = "samsung,exynos4210-uart";
+		reg = <0x12C20000 0x100>;
+		interrupts = <0 53 0>;
+	};
+
+	serial@12C30000 {
+		compatible = "samsung,exynos4210-uart";
+		reg = <0x12C30000 0x100>;
+		interrupts = <0 54 0>;
+	};
+
+	i2c@12C60000 {
+		compatible = "samsung,s3c2440-i2c";
+		reg = <0x12C60000 0x100>;
+		interrupts = <0 56 0>;
+	};
+
+	i2c@12C70000 {
+		compatible = "samsung,s3c2440-i2c";
+		reg = <0x12C70000 0x100>;
+		interrupts = <0 57 0>;
+	};
+
+	i2c@12C80000 {
+		compatible = "samsung,s3c2440-i2c";
+		reg = <0x12C80000 0x100>;
+		interrupts = <0 58 0>;
+	};
+
+	i2c@12C90000 {
+		compatible = "samsung,s3c2440-i2c";
+		reg = <0x12C90000 0x100>;
+		interrupts = <0 59 0>;
+	};
+
+	i2c@12CA0000 {
+		compatible = "samsung,s3c2440-i2c";
+		reg = <0x12CA0000 0x100>;
+		interrupts = <0 60 0>;
+	};
+
+	i2c@12CB0000 {
+		compatible = "samsung,s3c2440-i2c";
+		reg = <0x12CB0000 0x100>;
+		interrupts = <0 61 0>;
+	};
+
+	i2c@12CC0000 {
+		compatible = "samsung,s3c2440-i2c";
+		reg = <0x12CC0000 0x100>;
+		interrupts = <0 62 0>;
+	};
+
+	i2c@12CD0000 {
+		compatible = "samsung,s3c2440-i2c";
+		reg = <0x12CD0000 0x100>;
+		interrupts = <0 63 0>;
+	};
+
+	amba {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "arm,amba-bus";
+		interrupt-parent = <&gic>;
+		ranges;
+
+		pdma0: pdma@121A0000 {
+			compatible = "arm,pl330", "arm,primecell";
+			reg = <0x121A0000 0x1000>;
+			interrupts = <0 34 0>;
+		};
+
+		pdma1: pdma@121B0000 {
+			compatible = "arm,pl330", "arm,primecell";
+			reg = <0x121B0000 0x1000>;
+			interrupts = <0 35 0>;
+		};
+
+		mdma0: pdma@10800000 {
+			compatible = "arm,pl330", "arm,primecell";
+			reg = <0x10800000 0x1000>;
+			interrupts = <0 33 0>;
+		};
+
+		mdma1: pdma@11C10000 {
+			compatible = "arm,pl330", "arm,primecell";
+			reg = <0x11C10000 0x1000>;
+			interrupts = <0 124 0>;
+		};
+	};
+
+	gpio-controllers {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		gpio-controller;
+		ranges;
+
+		gpa0: gpio-controller@11400000 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400000 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpa1: gpio-controller@11400020 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400020 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpa2: gpio-controller@11400040 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400040 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpb0: gpio-controller@11400060 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400060 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpb1: gpio-controller@11400080 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400080 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpb2: gpio-controller@114000A0 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x114000A0 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpb3: gpio-controller@114000C0 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x114000C0 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpc0: gpio-controller@114000E0 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x114000E0 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpc1: gpio-controller@11400100 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400100 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpc2: gpio-controller@11400120 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400120 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpc3: gpio-controller@11400140 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400140 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpd0: gpio-controller@11400160 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400160 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpd1: gpio-controller@11400180 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400180 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpy0: gpio-controller@114001A0 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x114001A0 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpy1: gpio-controller@114001C0 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x114001C0 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpy2: gpio-controller@114001E0 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x114001E0 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpy3: gpio-controller@11400200 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400200 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpy4: gpio-controller@11400220 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400220 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpy5: gpio-controller@11400240 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400240 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpy6: gpio-controller@11400260 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400260 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpx0: gpio-controller@11400C00 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400C00 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpx1: gpio-controller@11400C20 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400C20 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpx2: gpio-controller@11400C40 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400C40 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpx3: gpio-controller@11400C60 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x11400C60 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpe0: gpio-controller@13400000 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x13400000 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpe1: gpio-controller@13400020 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x13400020 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpf0: gpio-controller@13400040 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x13400040 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpf1: gpio-controller@13400060 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x13400060 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpg0: gpio-controller@13400080 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x13400080 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpg1: gpio-controller@134000A0 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x134000A0 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpg2: gpio-controller@134000C0 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x134000C0 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gph0: gpio-controller@134000E0 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x134000E0 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gph1: gpio-controller@13400100 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x13400100 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpv0: gpio-controller@10D10000 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x10D10000 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpv1: gpio-controller@10D10020 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x10D10020 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpv2: gpio-controller@10D10040 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x10D10040 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpv3: gpio-controller@10D10060 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x10D10060 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpv4: gpio-controller@10D10080 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x10D10080 0x20>;
+			#gpio-cells = <4>;
+		};
+
+		gpz: gpio-controller@03860000 {
+			compatible = "samsung,exynos4-gpio";
+			reg = <0x03860000 0x20>;
+			#gpio-cells = <4>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
index 305635b..37c0ff9c 100644
--- a/arch/arm/boot/dts/highbank.dts
+++ b/arch/arm/boot/dts/highbank.dts
@@ -72,15 +72,15 @@
 		ranges;
 
 		timer@fff10600 {
-			compatible = "arm,smp-twd";
+			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0xfff10600 0x20>;
-			interrupts = <1 13 0xf04>;
+			interrupts = <1 13 0xf01>;
 		};
 
 		watchdog@fff10620 {
-			compatible = "arm,cortex-a9-wdt";
+			compatible = "arm,cortex-a9-twd-wdt";
 			reg = <0xfff10620 0x20>;
-			interrupts = <1 14 0xf04>;
+			interrupts = <1 14 0xf01>;
 		};
 
 		intc: interrupt-controller@fff11000 {
diff --git a/arch/arm/boot/dts/imx27-phytec-phycore.dts b/arch/arm/boot/dts/imx27-phytec-phycore.dts
new file mode 100644
index 0000000..a51a08f
--- /dev/null
+++ b/arch/arm/boot/dts/imx27-phytec-phycore.dts
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012 Sascha Hauer, Pengutronix
+ *
+ * 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
+ */
+
+/dts-v1/;
+/include/ "imx27.dtsi"
+
+/ {
+	model = "Phytec pcm038";
+	compatible = "phytec,imx27-pcm038", "fsl,imx27";
+
+	memory {
+		reg = <0x0 0x0>;
+	};
+
+	soc {
+		aipi@10000000 { /* aipi */
+
+			wdog@10002000 {
+				status = "okay";
+			};
+
+			uart@1000a000 {
+				fsl,uart-has-rtscts;
+				status = "okay";
+			};
+
+			uart@1000b000 {
+				fsl,uart-has-rtscts;
+				status = "okay";
+			};
+
+			uart@1000c000 {
+				fsl,uart-has-rtscts;
+				status = "okay";
+			};
+
+			fec@1002b000 {
+				status = "okay";
+			};
+
+			i2c@1001d000 {
+				clock-frequency = <400000>;
+				status = "okay";
+				at24@4c {
+					compatible = "at,24c32";
+					pagesize = <32>;
+					reg = <0x52>;
+				};
+				pcf8563@51 {
+					compatible = "nxp,pcf8563";
+					reg = <0x51>;
+				};
+				lm75@4a {
+					compatible = "national,lm75";
+					reg = <0x4a>;
+				};
+			};
+		};
+	};
+
+	nor_flash@c0000000 {
+		compatible = "cfi-flash";
+		bank-width = <2>;
+		reg = <0xc0000000 0x02000000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+};
diff --git a/arch/arm/boot/dts/imx27.dtsi b/arch/arm/boot/dts/imx27.dtsi
new file mode 100644
index 0000000..bc5e7d5
--- /dev/null
+++ b/arch/arm/boot/dts/imx27.dtsi
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2012 Sascha Hauer, Pengutronix
+ *
+ * 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/ "skeleton.dtsi"
+
+/ {
+	aliases {
+		serial0 = &uart1;
+		serial1 = &uart2;
+		serial2 = &uart3;
+		serial3 = &uart4;
+		serial4 = &uart5;
+		serial5 = &uart6;
+	};
+
+	avic: avic-interrupt-controller@e0000000 {
+		compatible = "fsl,imx27-avic", "fsl,avic";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		reg = <0x10040000 0x1000>;
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		osc26m {
+			compatible = "fsl,imx-osc26m", "fixed-clock";
+			clock-frequency = <26000000>;
+		};
+	};
+
+	soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		interrupt-parent = <&avic>;
+		ranges;
+
+		aipi@10000000 { /* AIPI1 */
+			compatible = "fsl,aipi-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x10000000 0x10000000>;
+			ranges;
+
+			wdog@10002000 {
+				compatible = "fsl,imx27-wdt", "fsl,imx21-wdt";
+				reg = <0x10002000 0x4000>;
+				interrupts = <27>;
+				status = "disabled";
+			};
+
+			uart1: uart@1000a000 {
+				compatible = "fsl,imx27-uart", "fsl,imx21-uart";
+				reg = <0x1000a000 0x1000>;
+				interrupts = <20>;
+				status = "disabled";
+			};
+
+			uart2: uart@1000b000 {
+				compatible = "fsl,imx27-uart", "fsl,imx21-uart";
+				reg = <0x1000b000 0x1000>;
+				interrupts = <19>;
+				status = "disabled";
+			};
+
+			uart3: uart@1000c000 {
+				compatible = "fsl,imx27-uart", "fsl,imx21-uart";
+				reg = <0x1000c000 0x1000>;
+				interrupts = <18>;
+				status = "disabled";
+			};
+
+			uart4: uart@1000d000 {
+				compatible = "fsl,imx27-uart", "fsl,imx21-uart";
+				reg = <0x1000d000 0x1000>;
+				interrupts = <17>;
+				status = "disabled";
+			};
+
+			cspi1: cspi@1000e000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,imx27-cspi";
+				reg = <0x1000e000 0x1000>;
+				interrupts = <16>;
+				status = "disabled";
+			};
+
+			cspi2: cspi@1000f000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,imx27-cspi";
+				reg = <0x1000f000 0x1000>;
+				interrupts = <15>;
+				status = "disabled";
+			};
+
+			i2c1: i2c@10012000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,imx27-i2c", "fsl,imx1-i2c";
+				reg = <0x10012000 0x1000>;
+				interrupts = <12>;
+				status = "disabled";
+			};
+
+			gpio1: gpio@10015000 {
+				compatible = "fsl,imx27-gpio", "fsl,imx21-gpio";
+				reg = <0x10015000 0x100>;
+				interrupts = <8>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+			};
+
+			gpio2: gpio@10015100 {
+				compatible = "fsl,imx27-gpio", "fsl,imx21-gpio";
+				reg = <0x10015100 0x100>;
+				interrupts = <8>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+			};
+
+			gpio3: gpio@10015200 {
+				compatible = "fsl,imx27-gpio", "fsl,imx21-gpio";
+				reg = <0x10015200 0x100>;
+				interrupts = <8>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+			};
+
+			gpio4: gpio@10015300 {
+				compatible = "fsl,imx27-gpio", "fsl,imx21-gpio";
+				reg = <0x10015300 0x100>;
+				interrupts = <8>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+			};
+
+			gpio5: gpio@10015400 {
+				compatible = "fsl,imx27-gpio", "fsl,imx21-gpio";
+				reg = <0x10015400 0x100>;
+				interrupts = <8>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+			};
+
+			gpio6: gpio@10015500 {
+				compatible = "fsl,imx27-gpio", "fsl,imx21-gpio";
+				reg = <0x10015500 0x100>;
+				interrupts = <8>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+			};
+
+			cspi3: cspi@10017000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,imx27-cspi";
+				reg = <0x10017000 0x1000>;
+				interrupts = <6>;
+				status = "disabled";
+			};
+
+			uart5: uart@1001b000 {
+				compatible = "fsl,imx27-uart", "fsl,imx21-uart";
+				reg = <0x1001b000 0x1000>;
+				interrupts = <49>;
+				status = "disabled";
+			};
+
+			uart6: uart@1001c000 {
+				compatible = "fsl,imx27-uart", "fsl,imx21-uart";
+				reg = <0x1001c000 0x1000>;
+				interrupts = <48>;
+				status = "disabled";
+			};
+
+			i2c2: i2c@1001d000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,imx27-i2c", "fsl,imx1-i2c";
+				reg = <0x1001d000 0x1000>;
+				interrupts = <1>;
+				status = "disabled";
+			};
+
+			fec: fec@1002b000 {
+				compatible = "fsl,imx27-fec";
+				reg = <0x1002b000 0x4000>;
+				interrupts = <50>;
+				status = "disabled";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts
index 564cb8c..9949e60 100644
--- a/arch/arm/boot/dts/imx51-babbage.dts
+++ b/arch/arm/boot/dts/imx51-babbage.dts
@@ -56,8 +56,95 @@
 						compatible = "fsl,mc13892";
 						spi-max-frequency = <6000000>;
 						reg = <0>;
-						mc13xxx-irq-gpios = <&gpio1 8 0>;
-						fsl,mc13xxx-uses-regulator;
+						interrupt-parent = <&gpio1>;
+						interrupts = <8>;
+
+						regulators {
+							sw1_reg: sw1 {
+								regulator-min-microvolt = <600000>;
+								regulator-max-microvolt = <1375000>;
+								regulator-boot-on;
+								regulator-always-on;
+							};
+
+							sw2_reg: sw2 {
+								regulator-min-microvolt = <900000>;
+								regulator-max-microvolt = <1850000>;
+								regulator-boot-on;
+								regulator-always-on;
+							};
+
+							sw3_reg: sw3 {
+								regulator-min-microvolt = <1100000>;
+								regulator-max-microvolt = <1850000>;
+								regulator-boot-on;
+								regulator-always-on;
+							};
+
+							sw4_reg: sw4 {
+								regulator-min-microvolt = <1100000>;
+								regulator-max-microvolt = <1850000>;
+								regulator-boot-on;
+								regulator-always-on;
+							};
+
+							vpll_reg: vpll {
+								regulator-min-microvolt = <1050000>;
+								regulator-max-microvolt = <1800000>;
+								regulator-boot-on;
+								regulator-always-on;
+							};
+
+							vdig_reg: vdig {
+								regulator-min-microvolt = <1650000>;
+								regulator-max-microvolt = <1650000>;
+								regulator-boot-on;
+							};
+
+							vsd_reg: vsd {
+								regulator-min-microvolt = <1800000>;
+								regulator-max-microvolt = <3150000>;
+							};
+
+							vusb2_reg: vusb2 {
+								regulator-min-microvolt = <2400000>;
+								regulator-max-microvolt = <2775000>;
+								regulator-boot-on;
+								regulator-always-on;
+							};
+
+							vvideo_reg: vvideo {
+								regulator-min-microvolt = <2775000>;
+								regulator-max-microvolt = <2775000>;
+							};
+
+							vaudio_reg: vaudio {
+								regulator-min-microvolt = <2300000>;
+								regulator-max-microvolt = <3000000>;
+							};
+
+							vcam_reg: vcam {
+								regulator-min-microvolt = <2500000>;
+								regulator-max-microvolt = <3000000>;
+							};
+
+							vgen1_reg: vgen1 {
+								regulator-min-microvolt = <1200000>;
+								regulator-max-microvolt = <1200000>;
+							};
+
+							vgen2_reg: vgen2 {
+								regulator-min-microvolt = <1200000>;
+								regulator-max-microvolt = <3150000>;
+								regulator-always-on;
+							};
+
+							vgen3_reg: vgen3 {
+								regulator-min-microvolt = <1800000>;
+								regulator-max-microvolt = <2900000>;
+								regulator-always-on;
+							};
+						};
 					};
 
 					flash: at45db321d@1 {
diff --git a/arch/arm/boot/dts/imx6q-arm2.dts b/arch/arm/boot/dts/imx6q-arm2.dts
index c3977e0..ce1c823 100644
--- a/arch/arm/boot/dts/imx6q-arm2.dts
+++ b/arch/arm/boot/dts/imx6q-arm2.dts
@@ -36,11 +36,13 @@
 			usdhc@02198000 { /* uSDHC3 */
 				cd-gpios = <&gpio6 11 0>;
 				wp-gpios = <&gpio6 14 0>;
+				vmmc-supply = <&reg_3p3v>;
 				status = "okay";
 			};
 
 			usdhc@0219c000 { /* uSDHC4 */
 				fsl,card-wired;
+				vmmc-supply = <&reg_3p3v>;
 				status = "okay";
 			};
 
@@ -50,6 +52,18 @@
 		};
 	};
 
+	regulators {
+		compatible = "simple-bus";
+
+		reg_3p3v: 3p3v {
+			compatible = "regulator-fixed";
+			regulator-name = "3P3V";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
+		};
+	};
+
 	leds {
 		compatible = "gpio-leds";
 
diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts
index 08d920d..4663a4e 100644
--- a/arch/arm/boot/dts/imx6q-sabrelite.dts
+++ b/arch/arm/boot/dts/imx6q-sabrelite.dts
@@ -32,18 +32,52 @@
 			usdhc@02198000 { /* uSDHC3 */
 				cd-gpios = <&gpio7 0 0>;
 				wp-gpios = <&gpio7 1 0>;
+				vmmc-supply = <&reg_3p3v>;
 				status = "okay";
 			};
 
 			usdhc@0219c000 { /* uSDHC4 */
 				cd-gpios = <&gpio2 6 0>;
 				wp-gpios = <&gpio2 7 0>;
+				vmmc-supply = <&reg_3p3v>;
 				status = "okay";
 			};
 
 			uart2: uart@021e8000 {
 				status = "okay";
 			};
+
+			i2c@021a0000 { /* I2C1 */
+				status = "okay";
+				clock-frequency = <100000>;
+
+				codec: sgtl5000@0a {
+					compatible = "fsl,sgtl5000";
+					reg = <0x0a>;
+					VDDA-supply = <&reg_2p5v>;
+					VDDIO-supply = <&reg_3p3v>;
+				};
+			};
+		};
+	};
+
+	regulators {
+		compatible = "simple-bus";
+
+		reg_2p5v: 2p5v {
+			compatible = "regulator-fixed";
+			regulator-name = "2P5V";
+			regulator-min-microvolt = <2500000>;
+			regulator-max-microvolt = <2500000>;
+			regulator-always-on;
+		};
+
+		reg_3p3v: 3p3v {
+			compatible = "regulator-fixed";
+			regulator-name = "3P3V";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index 263e8f3..4905f51 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -88,9 +88,9 @@
 		ranges;
 
 		timer@00a00600 {
-			compatible = "arm,smp-twd";
-			reg = <0x00a00600 0x100>;
-			interrupts = <1 13 0xf4>;
+			compatible = "arm,cortex-a9-twd-timer";
+			reg = <0x00a00600 0x20>;
+			interrupts = <1 13 0xf01>;
 		};
 
 		L2: l2-cache@00a02000 {
diff --git a/arch/arm/boot/dts/kirkwood-dreamplug.dts b/arch/arm/boot/dts/kirkwood-dreamplug.dts
new file mode 100644
index 0000000..a5376b8
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-dreamplug.dts
@@ -0,0 +1,24 @@
+/dts-v1/;
+
+/include/ "kirkwood.dtsi"
+
+/ {
+	model = "Globalscale Technologies Dreamplug";
+	compatible = "globalscale,dreamplug-003-ds2001", "globalscale,dreamplug", "mrvl,kirkwood-88f6281", "mrvl,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x20000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8 earlyprintk";
+	};
+
+	ocp@f1000000 {
+		serial@12000 {
+			clock-frequency = <200000000>;
+			status = "ok";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/kirkwood.dtsi b/arch/arm/boot/dts/kirkwood.dtsi
new file mode 100644
index 0000000..3474ef8
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood.dtsi
@@ -0,0 +1,36 @@
+/include/ "skeleton.dtsi"
+
+/ {
+	compatible = "mrvl,kirkwood";
+
+	ocp@f1000000 {
+		compatible = "simple-bus";
+		ranges = <0 0xf1000000 0x1000000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		serial@12000 {
+			compatible = "ns16550a";
+			reg = <0x12000 0x100>;
+			reg-shift = <2>;
+			interrupts = <33>;
+			/* set clock-frequency in board dts */
+			status = "disabled";
+		};
+
+		serial@12100 {
+			compatible = "ns16550a";
+			reg = <0x12100 0x100>;
+			reg-shift = <2>;
+			interrupts = <34>;
+			/* set clock-frequency in board dts */
+			status = "disabled";
+		};
+
+		rtc@10300 {
+			compatible = "mrvl,kirkwood-rtc", "mrvl,orion-rtc";
+			reg = <0x10300 0x20>;
+			interrupts = <53>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts
index 9486be6..9f72cd4 100644
--- a/arch/arm/boot/dts/omap3-beagle.dts
+++ b/arch/arm/boot/dts/omap3-beagle.dts
@@ -13,15 +13,6 @@
 	model = "TI OMAP3 BeagleBoard";
 	compatible = "ti,omap3-beagle", "ti,omap3";
 
-	/*
-	 * Since the initial device tree board file does not create any
-	 * devices (MMC, network...), the only way to boot is to provide a
-	 * ramdisk.
-	 */
-	chosen {
-		bootargs = "root=/dev/ram0 rw console=ttyO2,115200n8 initrd=0x81600000,20M ramdisk_size=20480 no_console_suspend debug earlyprintk";
-	};
-
 	memory {
 		device_type = "memory";
 		reg = <0x80000000 0x20000000>; /* 512 MB */
diff --git a/arch/arm/boot/dts/omap3-evm.dts b/arch/arm/boot/dts/omap3-evm.dts
new file mode 100644
index 0000000..2eee16e
--- /dev/null
+++ b/arch/arm/boot/dts/omap3-evm.dts
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.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.
+ */
+/dts-v1/;
+
+/include/ "omap3.dtsi"
+
+/ {
+	model = "TI OMAP3 EVM (OMAP3530, AM/DM37x)";
+	compatible = "ti,omap3-evm", "ti,omap3";
+
+	memory {
+		device_type = "memory";
+		reg = <0x80000000 0x10000000>; /* 256 MB */
+	};
+};
diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi
index 216c331..c612135 100644
--- a/arch/arm/boot/dts/omap3.dtsi
+++ b/arch/arm/boot/dts/omap3.dtsi
@@ -61,34 +61,57 @@
 		ranges;
 		ti,hwmods = "l3_main";
 
-		intc: interrupt-controller@1 {
-			compatible = "ti,omap3-intc";
+		intc: interrupt-controller@48200000 {
+			compatible = "ti,omap2-intc";
 			interrupt-controller;
 			#interrupt-cells = <1>;
+			ti,intc-size = <96>;
+			reg = <0x48200000 0x1000>;
 		};
 
-		uart1: serial@0x4806a000 {
+		uart1: serial@4806a000 {
 			compatible = "ti,omap3-uart";
 			ti,hwmods = "uart1";
 			clock-frequency = <48000000>;
 		};
 
-		uart2: serial@0x4806c000 {
+		uart2: serial@4806c000 {
 			compatible = "ti,omap3-uart";
 			ti,hwmods = "uart2";
 			clock-frequency = <48000000>;
 		};
 
-		uart3: serial@0x49020000 {
+		uart3: serial@49020000 {
 			compatible = "ti,omap3-uart";
 			ti,hwmods = "uart3";
 			clock-frequency = <48000000>;
 		};
 
-		uart4: serial@0x49042000 {
+		uart4: serial@49042000 {
 			compatible = "ti,omap3-uart";
 			ti,hwmods = "uart4";
 			clock-frequency = <48000000>;
 		};
+
+		i2c1: i2c@48070000 {
+			compatible = "ti,omap3-i2c";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ti,hwmods = "i2c1";
+		};
+
+		i2c2: i2c@48072000 {
+			compatible = "ti,omap3-i2c";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ti,hwmods = "i2c2";
+		};
+
+		i2c3: i2c@48060000 {
+			compatible = "ti,omap3-i2c";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ti,hwmods = "i2c3";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/omap4-panda.dts b/arch/arm/boot/dts/omap4-panda.dts
index c702657..9755ad5 100644
--- a/arch/arm/boot/dts/omap4-panda.dts
+++ b/arch/arm/boot/dts/omap4-panda.dts
@@ -13,15 +13,6 @@
 	model = "TI OMAP4 PandaBoard";
 	compatible = "ti,omap4-panda", "ti,omap4430", "ti,omap4";
 
-	/*
-	 * Since the initial device tree board file does not create any
-	 * devices (MMC, network...), the only way to boot is to provide a
-	 * ramdisk.
-	 */
-	chosen {
-		bootargs = "root=/dev/ram0 rw console=ttyO2,115200n8 initrd=0x81600000,20M ramdisk_size=20480 no_console_suspend debug";
-	};
-
 	memory {
 		device_type = "memory";
 		reg = <0x80000000 0x40000000>; /* 1 GB */
diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts
index 066e28c..63c6b2b 100644
--- a/arch/arm/boot/dts/omap4-sdp.dts
+++ b/arch/arm/boot/dts/omap4-sdp.dts
@@ -13,15 +13,6 @@
 	model = "TI OMAP4 SDP board";
 	compatible = "ti,omap4-sdp", "ti,omap4430", "ti,omap4";
 
-	/*
-	 * Since the initial device tree board file does not create any
-	 * devices (MMC, network...), the only way to boot is to provide a
-	 * ramdisk.
-	 */
-	chosen {
-		bootargs = "root=/dev/ram0 rw console=ttyO2,115200n8 initrd=0x81600000,20M ramdisk_size=20480 no_console_suspend debug";
-	};
-
 	memory {
 		device_type = "memory";
 		reg = <0x80000000 0x40000000>; /* 1 GB */
diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index e8fe75f..3d35559 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -99,33 +99,61 @@
 		gic: interrupt-controller@48241000 {
 			compatible = "arm,cortex-a9-gic";
 			interrupt-controller;
-			#interrupt-cells = <1>;
+			#interrupt-cells = <3>;
 			reg = <0x48241000 0x1000>,
 			      <0x48240100 0x0100>;
 		};
 
-		uart1: serial@0x4806a000 {
+		uart1: serial@4806a000 {
 			compatible = "ti,omap4-uart";
 			ti,hwmods = "uart1";
 			clock-frequency = <48000000>;
 		};
 
-		uart2: serial@0x4806c000 {
+		uart2: serial@4806c000 {
 			compatible = "ti,omap4-uart";
 			ti,hwmods = "uart2";
 			clock-frequency = <48000000>;
 		};
 
-		uart3: serial@0x48020000 {
+		uart3: serial@48020000 {
 			compatible = "ti,omap4-uart";
 			ti,hwmods = "uart3";
 			clock-frequency = <48000000>;
 		};
 
-		uart4: serial@0x4806e000 {
+		uart4: serial@4806e000 {
 			compatible = "ti,omap4-uart";
 			ti,hwmods = "uart4";
 			clock-frequency = <48000000>;
 		};
+
+		i2c1: i2c@48070000 {
+			compatible = "ti,omap4-i2c";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ti,hwmods = "i2c1";
+		};
+
+		i2c2: i2c@48072000 {
+			compatible = "ti,omap4-i2c";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ti,hwmods = "i2c2";
+		};
+
+		i2c3: i2c@48060000 {
+			compatible = "ti,omap4-i2c";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ti,hwmods = "i2c3";
+		};
+
+		i2c4: i2c@48350000 {
+			compatible = "ti,omap4-i2c";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			ti,hwmods = "i2c4";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/pxa168-aspenite.dts b/arch/arm/boot/dts/pxa168-aspenite.dts
new file mode 100644
index 0000000..e762fac
--- /dev/null
+++ b/arch/arm/boot/dts/pxa168-aspenite.dts
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (C) 2012 Marvell Technology Group Ltd.
+ *  Author: Haojian Zhuang <haojian.zhuang@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
+ *  publishhed by the Free Software Foundation.
+ */
+
+/dts-v1/;
+/include/ "pxa168.dtsi"
+
+/ {
+	model = "Marvell PXA168 Aspenite Development Board";
+	compatible = "mrvl,pxa168-aspenite", "mrvl,pxa168";
+
+	chosen {
+		bootargs = "console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.100:/nfsroot/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on";
+	};
+
+	memory {
+		reg = <0x00000000 0x04000000>;
+	};
+
+	soc {
+		apb@d4000000 {
+			uart1: uart@d4017000 {
+				status = "okay";
+			};
+			twsi1: i2c@d4011000 {
+				status = "okay";
+			};
+			rtc: rtc@d4010000 {
+				status = "okay";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/pxa168.dtsi b/arch/arm/boot/dts/pxa168.dtsi
new file mode 100644
index 0000000..d32d512
--- /dev/null
+++ b/arch/arm/boot/dts/pxa168.dtsi
@@ -0,0 +1,98 @@
+/*
+ *  Copyright (C) 2012 Marvell Technology Group Ltd.
+ *  Author: Haojian Zhuang <haojian.zhuang@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
+ *  publishhed by the Free Software Foundation.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	aliases {
+		serial0 = &uart1;
+		serial1 = &uart2;
+		serial2 = &uart3;
+		i2c0 = &twsi1;
+		i2c1 = &twsi2;
+	};
+
+	intc: intc-interrupt-controller@d4282000 {
+		compatible = "mrvl,mmp-intc", "mrvl,intc";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		reg = <0xd4282000 0x1000>;
+	};
+
+	soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		interrupt-parent = <&intc>;
+		ranges;
+
+		apb@d4000000 {	/* APB */
+			compatible = "mrvl,apb-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xd4000000 0x00200000>;
+			ranges;
+
+			uart1: uart@d4017000 {
+				compatible = "mrvl,mmp-uart", "mrvl,pxa-uart";
+				reg = <0xd4017000 0x1000>;
+				interrupts = <27>;
+				status = "disabled";
+			};
+
+			uart2: uart@d4018000 {
+				compatible = "mrvl,mmp-uart", "mrvl,pxa-uart";
+				reg = <0xd4018000 0x1000>;
+				interrupts = <28>;
+				status = "disabled";
+			};
+
+			uart3: uart@d4026000 {
+				compatible = "mrvl,mmp-uart", "mrvl,pxa-uart";
+				reg = <0xd4026000 0x1000>;
+				interrupts = <29>;
+				status = "disabled";
+			};
+
+			gpio: gpio@d4019000 {
+				compatible = "mrvl,mmp-gpio", "mrvl,pxa-gpio";
+				reg = <0xd4019000 0x1000>;
+				interrupts = <49>;
+				interrupt-names = "gpio_mux";
+				gpio-controller;
+				#gpio-cells = <1>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+			};
+
+			twsi1: i2c@d4011000 {
+				compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+				reg = <0xd4011000 0x1000>;
+				interrupts = <7>;
+				mrvl,i2c-fast-mode;
+				status = "disabled";
+			};
+
+			twsi2: i2c@d4025000 {
+				compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+				reg = <0xd4025000 0x1000>;
+				interrupts = <58>;
+				status = "disabled";
+			};
+
+			rtc: rtc@d4010000 {
+				compatible = "mrvl,mmp-rtc";
+				reg = <0xd4010000 0x1000>;
+				interrupts = <5 6>;
+				interrupt-names = "rtc 1Hz", "rtc alarm";
+				status = "disabled";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/snowball.dts b/arch/arm/boot/dts/snowball.dts
new file mode 100644
index 0000000..359c6d6
--- /dev/null
+++ b/arch/arm/boot/dts/snowball.dts
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2011 ST-Ericsson AB
+ *
+ * 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
+ */
+
+/dts-v1/;
+/include/ "db8500.dtsi"
+
+/ {
+	model = "Calao Systems Snowball platform with device tree";
+	compatible = "calaosystems,snowball-a9500";
+
+	memory {
+		reg = <0x00000000 0x20000000>;
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		button@1 {
+			debounce_interval = <50>;
+			wakeup = <1>;
+			linux,code = <2>;
+			label = "userpb";
+			gpios = <&gpio1 0>;
+		};
+		button@2 {
+			debounce_interval = <50>;
+			wakeup = <1>;
+			linux,code = <3>;
+			label = "userpb";
+			gpios = <&gpio4 23>;
+		};
+		button@3 {
+			debounce_interval = <50>;
+			wakeup = <1>;
+			linux,code = <4>;
+			label = "userpb";
+			gpios = <&gpio4 23>;
+		};
+		button@4 {
+			debounce_interval = <50>;
+			wakeup = <1>;
+			linux,code = <5>;
+			label = "userpb";
+			gpios = <&gpio5 1>;
+		};
+		button@5 {
+			debounce_interval = <50>;
+			wakeup = <1>;
+			linux,code = <6>;
+			label = "userpb";
+			gpios = <&gpio5 2>;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		used-led {
+			label = "user_led";
+			gpios = <&gpio4 14>;
+		};
+	};
+
+	soc-u9500 {
+
+		external-bus@50000000 {
+			compatible = "simple-bus";
+			reg = <0x50000000 0x10000000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			ethernet@50000000 {
+				compatible = "smsc,9111";
+				reg = <0x50000000 0x10000>;
+				interrupts = <12>;
+				interrupt-parent = <&gpio4>;
+			};
+		};
+
+		sdi@80126000 {
+			status = "enabled";
+			cd-gpios = <&gpio6 26>;
+		};
+
+		sdi@80114000 {
+			status = "enabled";
+		};
+
+		uart@80120000 {
+			status = "okay";
+		};
+
+		uart@80121000 {
+			status = "okay";
+		};
+
+		uart@80007000 {
+			status = "okay";
+		};
+
+		i2c@80004000 {
+			tc3589x@42 {
+				//compatible = "tc3589x";
+				reg = <0x42>;
+				interrupts = <25>;
+				interrupt-parent = <&gpio6>;
+			};
+			tps61052@33 {
+				//compatible = "tps61052";
+				reg = <0x33>;
+			};
+		};
+
+		i2c@80128000 {
+			lp5521@0x33 {
+				// compatible = "lp5521";
+				reg = <0x33>;
+			};
+			lp5521@0x34 {
+				// compatible = "lp5521";
+				reg = <0x34>;
+			};
+			bh1780@0x29 {
+				// compatible = "rohm,bh1780gli";
+				reg = <0x33>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/spear600-evb.dts b/arch/arm/boot/dts/spear600-evb.dts
new file mode 100644
index 0000000..636292e
--- /dev/null
+++ b/arch/arm/boot/dts/spear600-evb.dts
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012 Stefan Roese <sr@denx.de>
+ *
+ * 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
+ */
+
+/dts-v1/;
+/include/ "spear600.dtsi"
+
+/ {
+	model = "ST SPEAr600 Evaluation Board";
+	compatible = "st,spear600-evb", "st,spear600";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	memory {
+		device_type = "memory";
+		reg = <0 0x10000000>;
+	};
+
+	ahb {
+		gmac: ethernet@e0800000 {
+			phy-mode = "gmii";
+			status = "okay";
+		};
+
+		apb {
+			serial@d0000000 {
+				status = "okay";
+			};
+
+			serial@d0080000 {
+				status = "okay";
+			};
+
+			i2c@d0200000 {
+				clock-frequency = <400000>;
+				status = "okay";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/spear600.dtsi b/arch/arm/boot/dts/spear600.dtsi
new file mode 100644
index 0000000..ebe0885
--- /dev/null
+++ b/arch/arm/boot/dts/spear600.dtsi
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2012 Stefan Roese <sr@denx.de>
+ *
+ * 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/ "skeleton.dtsi"
+
+/ {
+	compatible = "st,spear600";
+
+	cpus {
+		cpu@0 {
+			compatible = "arm,arm926ejs";
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0 0x40000000>;
+	};
+
+	ahb {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		ranges = <0xd0000000 0xd0000000 0x30000000>;
+
+		vic0: interrupt-controller@f1100000 {
+			compatible = "arm,pl190-vic";
+			interrupt-controller;
+			reg = <0xf1100000 0x1000>;
+			#interrupt-cells = <1>;
+		};
+
+		vic1: interrupt-controller@f1000000 {
+			compatible = "arm,pl190-vic";
+			interrupt-controller;
+			reg = <0xf1000000 0x1000>;
+			#interrupt-cells = <1>;
+		};
+
+		gmac: ethernet@e0800000 {
+			compatible = "st,spear600-gmac";
+			reg = <0xe0800000 0x8000>;
+			interrupt-parent = <&vic1>;
+			interrupts = <24 23>;
+			interrupt-names = "macirq", "eth_wake_irq";
+			status = "disabled";
+		};
+
+		fsmc: flash@d1800000 {
+			compatible = "st,spear600-fsmc-nand";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xd1800000 0x1000	/* FSMC Register */
+			       0xd2000000 0x4000>;	/* NAND Base */
+			reg-names = "fsmc_regs", "nand_data";
+			st,ale-off = <0x20000>;
+			st,cle-off = <0x10000>;
+			status = "disabled";
+		};
+
+		smi: flash@fc000000 {
+			compatible = "st,spear600-smi";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xfc000000 0x1000>;
+			interrupt-parent = <&vic1>;
+			interrupts = <12>;
+			status = "disabled";
+		};
+
+		ehci@e1800000 {
+			compatible = "st,spear600-ehci", "usb-ehci";
+			reg = <0xe1800000 0x1000>;
+			interrupt-parent = <&vic1>;
+			interrupts = <27>;
+			status = "disabled";
+		};
+
+		ehci@e2000000 {
+			compatible = "st,spear600-ehci", "usb-ehci";
+			reg = <0xe2000000 0x1000>;
+			interrupt-parent = <&vic1>;
+			interrupts = <29>;
+			status = "disabled";
+		};
+
+		ohci@e1900000 {
+			compatible = "st,spear600-ohci", "usb-ohci";
+			reg = <0xe1900000 0x1000>;
+			interrupt-parent = <&vic1>;
+			interrupts = <26>;
+			status = "disabled";
+		};
+
+		ohci@e2100000 {
+			compatible = "st,spear600-ohci", "usb-ohci";
+			reg = <0xe2100000 0x1000>;
+			interrupt-parent = <&vic1>;
+			interrupts = <28>;
+			status = "disabled";
+		};
+
+		apb {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "simple-bus";
+			ranges = <0xd0000000 0xd0000000 0x30000000>;
+
+			serial@d0000000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0xd0000000 0x1000>;
+				interrupt-parent = <&vic0>;
+				interrupts = <24>;
+				status = "disabled";
+			};
+
+			serial@d0080000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0xd0080000 0x1000>;
+				interrupt-parent = <&vic0>;
+				interrupts = <25>;
+				status = "disabled";
+			};
+
+			/* local/cpu GPIO */
+			gpio0: gpio@f0100000 {
+				#gpio-cells = <2>;
+				compatible = "arm,pl061", "arm,primecell";
+				gpio-controller;
+				reg = <0xf0100000 0x1000>;
+				interrupt-parent = <&vic0>;
+				interrupts = <18>;
+			};
+
+			/* basic GPIO */
+			gpio1: gpio@fc980000 {
+				#gpio-cells = <2>;
+				compatible = "arm,pl061", "arm,primecell";
+				gpio-controller;
+				reg = <0xfc980000 0x1000>;
+				interrupt-parent = <&vic1>;
+				interrupts = <19>;
+			};
+
+			/* appl GPIO */
+			gpio2: gpio@d8100000 {
+				#gpio-cells = <2>;
+				compatible = "arm,pl061", "arm,primecell";
+				gpio-controller;
+				reg = <0xd8100000 0x1000>;
+				interrupt-parent = <&vic1>;
+				interrupts = <4>;
+			};
+
+			i2c@d0200000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "snps,designware-i2c";
+				reg = <0xd0200000 0x1000>;
+				interrupt-parent = <&vic0>;
+				interrupts = <28>;
+				status = "disabled";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/tegra-cardhu.dts b/arch/arm/boot/dts/tegra-cardhu.dts
index 70c41fc..ac3fb75 100644
--- a/arch/arm/boot/dts/tegra-cardhu.dts
+++ b/arch/arm/boot/dts/tegra-cardhu.dts
@@ -14,6 +14,22 @@
 		clock-frequency = < 408000000 >;
 	};
 
+	serial@70006040 {
+		status = "disable";
+	};
+
+	serial@70006200 {
+		status = "disable";
+	};
+
+	serial@70006300 {
+		status = "disable";
+	};
+
+	serial@70006400 {
+		status = "disable";
+	};
+
 	i2c@7000c000 {
 		clock-frequency = <100000>;
 	};
@@ -33,4 +49,22 @@
 	i2c@7000d000 {
 		clock-frequency = <100000>;
 	};
+
+	sdhci@78000000 {
+		cd-gpios = <&gpio 69 0>; /* gpio PI5 */
+		wp-gpios = <&gpio 155 0>; /* gpio PT3 */
+		power-gpios = <&gpio 31 0>; /* gpio PD7 */
+	};
+
+	sdhci@78000200 {
+		status = "disable";
+	};
+
+	sdhci@78000400 {
+		status = "disable";
+	};
+
+	sdhci@78000400 {
+		support-8bit;
+	};
 };
diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts
index 80afa1b..6e8447d 100644
--- a/arch/arm/boot/dts/tegra-harmony.dts
+++ b/arch/arm/boot/dts/tegra-harmony.dts
@@ -10,19 +10,25 @@
 		reg = < 0x00000000 0x40000000 >;
 	};
 
+	pmc@7000f400 {
+		nvidia,invert-interrupt;
+	};
+
 	i2c@7000c000 {
 		clock-frequency = <400000>;
 
-		codec: wm8903@1a {
+		wm8903: wm8903@1a {
 			compatible = "wlf,wm8903";
 			reg = <0x1a>;
-			interrupts = < 347 >;
+			interrupt-parent = <&gpio>;
+			interrupts = < 187 0x04 >;
 
 			gpio-controller;
 			#gpio-cells = <2>;
 
-			/* 0x8000 = Not configured */
-			gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >;
+			micdet-cfg = <0>;
+			micdet-delay = <100>;
+			gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >;
 		};
 	};
 
@@ -38,13 +44,32 @@
 		clock-frequency = <400000>;
 	};
 
-	sound {
-		compatible = "nvidia,harmony-sound", "nvidia,tegra-wm8903";
+	i2s@70002a00 {
+		status = "disable";
+	};
 
-		spkr-en-gpios = <&codec 2 0>;
-		hp-det-gpios = <&gpio 178 0>;
-		int-mic-en-gpios = <&gpio 184 0>;
-		ext-mic-en-gpios = <&gpio 185 0>;
+	sound {
+		compatible = "nvidia,tegra-audio-wm8903-harmony",
+			     "nvidia,tegra-audio-wm8903";
+		nvidia,model = "NVIDIA Tegra Harmony";
+
+		nvidia,audio-routing =
+			"Headphone Jack", "HPOUTR",
+			"Headphone Jack", "HPOUTL",
+			"Int Spk", "ROP",
+			"Int Spk", "RON",
+			"Int Spk", "LOP",
+			"Int Spk", "LON",
+			"Mic Jack", "MICBIAS",
+			"IN1L", "Mic Jack";
+
+		nvidia,i2s-controller = <&tegra_i2s1>;
+		nvidia,audio-codec = <&wm8903>;
+
+		nvidia,spkr-en-gpios = <&wm8903 2 0>;
+		nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
+		nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */
+		nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
 	};
 
 	serial@70006000 {
diff --git a/arch/arm/boot/dts/tegra-paz00.dts b/arch/arm/boot/dts/tegra-paz00.dts
index 825d295..6c02abb 100644
--- a/arch/arm/boot/dts/tegra-paz00.dts
+++ b/arch/arm/boot/dts/tegra-paz00.dts
@@ -12,6 +12,13 @@
 
 	i2c@7000c000 {
 		clock-frequency = <400000>;
+
+		alc5632: alc5632@1e {
+			compatible = "realtek,alc5632";
+			reg = <0x1e>;
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
 	};
 
 	i2c@7000c400 {
@@ -35,6 +42,35 @@
 
 	i2c@7000d000 {
 		clock-frequency = <400000>;
+
+		adt7461@4c {
+			compatible = "adi,adt7461";
+			reg = <0x4c>;
+		};
+	};
+
+	i2s@70002a00 {
+		status = "disable";
+	};
+
+	sound {
+		compatible = "nvidia,tegra-audio-alc5632-paz00",
+			"nvidia,tegra-audio-alc5632";
+
+		nvidia,model = "Compal PAZ00";
+
+		nvidia,audio-routing =
+			"Int Spk", "SPKOUT",
+			"Int Spk", "SPKOUTN",
+			"Headset Mic", "MICBIAS1",
+			"MIC1", "Headset Mic",
+			"Headset Stereophone", "HPR",
+			"Headset Stereophone", "HPL",
+			"DMICDAT", "Digital Mic";
+
+		nvidia,audio-codec = <&alc5632>;
+		nvidia,i2s-controller = <&tegra_i2s1>;
+		nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
 	};
 
 	serial@70006000 {
@@ -74,4 +110,25 @@
 	sdhci@c8000600 {
 		support-8bit;
 	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		power {
+			label = "Power";
+			gpios = <&gpio 79 1>; /* gpio PJ7, active low */
+			linux,code = <116>; /* KEY_POWER */
+			gpio-key,wakeup;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		wifi {
+			label = "wifi-led";
+			gpios = <&gpio 24 0>;
+			linux,default-trigger = "rfkill0";
+		};
+	};
 };
diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts
index b55a02e..dbf1c5a 100644
--- a/arch/arm/boot/dts/tegra-seaboard.dts
+++ b/arch/arm/boot/dts/tegra-seaboard.dts
@@ -13,6 +13,20 @@
 
 	i2c@7000c000 {
 		clock-frequency = <400000>;
+
+		wm8903: wm8903@1a {
+			compatible = "wlf,wm8903";
+			reg = <0x1a>;
+			interrupt-parent = <&gpio>;
+			interrupts = < 187 0x04 >;
+
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			micdet-cfg = <0>;
+			micdet-delay = <100>;
+			gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >;
+		};
 	};
 
 	i2c@7000c400 {
@@ -32,6 +46,32 @@
 		};
 	};
 
+	i2s@70002a00 {
+		status = "disable";
+	};
+
+	sound {
+		compatible = "nvidia,tegra-audio-wm8903-seaboard",
+			     "nvidia,tegra-audio-wm8903";
+		nvidia,model = "NVIDIA Tegra Seaboard";
+
+		nvidia,audio-routing =
+			"Headphone Jack", "HPOUTR",
+			"Headphone Jack", "HPOUTL",
+			"Int Spk", "ROP",
+			"Int Spk", "RON",
+			"Int Spk", "LOP",
+			"Int Spk", "LON",
+			"Mic Jack", "MICBIAS",
+			"IN1R", "Mic Jack";
+
+		nvidia,i2s-controller = <&tegra_i2s1>;
+		nvidia,audio-codec = <&wm8903>;
+
+		nvidia,spkr-en-gpios = <&wm8903 2 0>;
+		nvidia,hp-det-gpios = <&gpio 185 0>; /* gpio PX1 */
+	};
+
 	serial@70006000 {
 		status = "disable";
 	};
@@ -72,6 +112,7 @@
 
 	usb@c5000000 {
 		nvidia,vbus-gpio = <&gpio 24 0>; /* PD0 */
+		dr_mode = "otg";
 	};
 
 	gpio-keys {
@@ -93,4 +134,42 @@
 			gpio-key,wakeup;
 		};
 	};
+
+	emc@7000f400 {
+		emc-table@190000 {
+			reg = < 190000 >;
+			compatible = "nvidia,tegra20-emc-table";
+			clock-frequency = < 190000 >;
+			nvidia,emc-registers = < 0x0000000c 0x00000026
+				0x00000009 0x00000003 0x00000004 0x00000004
+				0x00000002 0x0000000c 0x00000003 0x00000003
+				0x00000002 0x00000001 0x00000004 0x00000005
+				0x00000004 0x00000009 0x0000000d 0x0000059f
+				0x00000000 0x00000003 0x00000003 0x00000003
+				0x00000003 0x00000001 0x0000000b 0x000000c8
+				0x00000003 0x00000007 0x00000004 0x0000000f
+				0x00000002 0x00000000 0x00000000 0x00000002
+				0x00000000 0x00000000 0x00000083 0xa06204ae
+				0x007dc010 0x00000000 0x00000000 0x00000000
+				0x00000000 0x00000000 0x00000000 0x00000000 >;
+		};
+
+		emc-table@380000 {
+			reg = < 380000 >;
+			compatible = "nvidia,tegra20-emc-table";
+			clock-frequency = < 380000 >;
+			nvidia,emc-registers = < 0x00000017 0x0000004b
+				0x00000012 0x00000006 0x00000004 0x00000005
+				0x00000003 0x0000000c 0x00000006 0x00000006
+				0x00000003 0x00000001 0x00000004 0x00000005
+				0x00000004 0x00000009 0x0000000d 0x00000b5f
+				0x00000000 0x00000003 0x00000003 0x00000006
+				0x00000006 0x00000001 0x00000011 0x000000c8
+				0x00000003 0x0000000e 0x00000007 0x0000000f
+				0x00000002 0x00000000 0x00000000 0x00000002
+				0x00000000 0x00000000 0x00000083 0xe044048b
+				0x007d8010 0x00000000 0x00000000 0x00000000
+				0x00000000 0x00000000 0x00000000 0x00000000 >;
+		};
+	};
 };
diff --git a/arch/arm/boot/dts/tegra-trimslice.dts b/arch/arm/boot/dts/tegra-trimslice.dts
index 3b3ee7d..2524768 100644
--- a/arch/arm/boot/dts/tegra-trimslice.dts
+++ b/arch/arm/boot/dts/tegra-trimslice.dts
@@ -26,6 +26,18 @@
 		status = "disable";
 	};
 
+	i2s@70002800 {
+		status = "disable";
+	};
+
+	i2s@70002a00 {
+		status = "disable";
+	};
+
+	das@70000c00 {
+		status = "disable";
+	};
+
 	serial@70006000 {
 		clock-frequency = < 216000000 >;
 	};
diff --git a/arch/arm/boot/dts/tegra-ventana.dts b/arch/arm/boot/dts/tegra-ventana.dts
index c7d3b87..2dcff87 100644
--- a/arch/arm/boot/dts/tegra-ventana.dts
+++ b/arch/arm/boot/dts/tegra-ventana.dts
@@ -12,6 +12,20 @@
 
 	i2c@7000c000 {
 		clock-frequency = <400000>;
+
+		wm8903: wm8903@1a {
+			compatible = "wlf,wm8903";
+			reg = <0x1a>;
+			interrupt-parent = <&gpio>;
+			interrupts = < 187 0x04 >;
+
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			micdet-cfg = <0>;
+			micdet-delay = <100>;
+			gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >;
+		};
 	};
 
 	i2c@7000c400 {
@@ -26,6 +40,34 @@
 		clock-frequency = <400000>;
 	};
 
+	i2s@70002a00 {
+		status = "disable";
+	};
+
+	sound {
+		compatible = "nvidia,tegra-audio-wm8903-ventana",
+			     "nvidia,tegra-audio-wm8903";
+		nvidia,model = "NVIDIA Tegra Ventana";
+
+		nvidia,audio-routing =
+			"Headphone Jack", "HPOUTR",
+			"Headphone Jack", "HPOUTL",
+			"Int Spk", "ROP",
+			"Int Spk", "RON",
+			"Int Spk", "LOP",
+			"Int Spk", "LON",
+			"Mic Jack", "MICBIAS",
+			"IN1L", "Mic Jack";
+
+		nvidia,i2s-controller = <&tegra_i2s1>;
+		nvidia,audio-codec = <&wm8903>;
+
+		nvidia,spkr-en-gpios = <&wm8903 2 0>;
+		nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
+		nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */
+		nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
+	};
+
 	serial@70006000 {
 		status = "disable";
 	};
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 3da7afd..108e894 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -4,6 +4,11 @@
 	compatible = "nvidia,tegra20";
 	interrupt-parent = <&intc>;
 
+	pmc@7000f400 {
+		compatible = "nvidia,tegra20-pmc";
+		reg = <0x7000e400 0x400>;
+	};
+
 	intc: interrupt-controller@50041000 {
 		compatible = "arm,cortex-a9-gic";
 		interrupt-controller;
@@ -12,6 +17,33 @@
 		      < 0x50040100 0x0100 >;
 	};
 
+	pmu {
+		compatible = "arm,cortex-a9-pmu";
+		interrupts = <0 56 0x04
+			      0 57 0x04>;
+	};
+
+	apbdma: dma@6000a000 {
+		compatible = "nvidia,tegra20-apbdma";
+		reg = <0x6000a000 0x1200>;
+		interrupts = < 0 104 0x04
+			       0 105 0x04
+			       0 106 0x04
+			       0 107 0x04
+			       0 108 0x04
+			       0 109 0x04
+			       0 110 0x04
+			       0 111 0x04
+			       0 112 0x04
+			       0 113 0x04
+			       0 114 0x04
+			       0 115 0x04
+			       0 116 0x04
+			       0 117 0x04
+			       0 118 0x04
+			       0 119 0x04 >;
+	};
+
 	i2c@7000c000 {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -44,18 +76,18 @@
 		interrupts = < 0 53 0x04 >;
 	};
 
-	i2s@70002800 {
+	tegra_i2s1: i2s@70002800 {
 		compatible = "nvidia,tegra20-i2s";
 		reg = <0x70002800 0x200>;
 		interrupts = < 0 13 0x04 >;
-		dma-channel = < 2 >;
+		nvidia,dma-request-selector = < &apbdma 2 >;
 	};
 
-	i2s@70002a00 {
+	tegra_i2s2: i2s@70002a00 {
 		compatible = "nvidia,tegra20-i2s";
 		reg = <0x70002a00 0x200>;
 		interrupts = < 0 3 0x04 >;
-		dma-channel = < 1 >;
+		nvidia,dma-request-selector = < &apbdma 1 >;
 	};
 
 	das@70000c00 {
@@ -75,6 +107,8 @@
 			       0 89 0x04 >;
 		#gpio-cells = <2>;
 		gpio-controller;
+		#interrupt-cells = <2>;
+		interrupt-controller;
 	};
 
 	pinmux: pinmux@70000000 {
@@ -120,6 +154,13 @@
 		interrupts = < 0 91 0x04 >;
 	};
 
+	emc@7000f400 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "nvidia,tegra20-emc";
+		reg = <0x7000f400 0x200>;
+	};
+
 	sdhci@c8000000 {
 		compatible = "nvidia,tegra20-sdhci";
 		reg = <0xc8000000 0x200>;
@@ -149,6 +190,7 @@
 		reg = <0xc5000000 0x4000>;
 		interrupts = < 0 20 0x04 >;
 		phy_type = "utmi";
+		nvidia,has-legacy-mode;
 	};
 
 	usb@c5004000 {
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index ee7db98..62a7b39 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -4,6 +4,11 @@
 	compatible = "nvidia,tegra30";
 	interrupt-parent = <&intc>;
 
+	pmc@7000f400 {
+		compatible = "nvidia,tegra20-pmc", "nvidia,tegra30-pmc";
+		reg = <0x7000e400 0x400>;
+	};
+
 	intc: interrupt-controller@50041000 {
 		compatible = "arm,cortex-a9-gic";
 		interrupt-controller;
@@ -12,6 +17,51 @@
 		      < 0x50040100 0x0100 >;
 	};
 
+	pmu {
+		compatible = "arm,cortex-a9-pmu";
+		interrupts = <0 144 0x04
+			      0 145 0x04
+			      0 146 0x04
+			      0 147 0x04>;
+	};
+
+	apbdma: dma@6000a000 {
+		compatible = "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma";
+		reg = <0x6000a000 0x1400>;
+		interrupts = < 0 104 0x04
+			       0 105 0x04
+			       0 106 0x04
+			       0 107 0x04
+			       0 108 0x04
+			       0 109 0x04
+			       0 110 0x04
+			       0 111 0x04
+			       0 112 0x04
+			       0 113 0x04
+			       0 114 0x04
+			       0 115 0x04
+			       0 116 0x04
+			       0 117 0x04
+			       0 118 0x04
+			       0 119 0x04
+			       0 128 0x04
+			       0 129 0x04
+			       0 130 0x04
+			       0 131 0x04
+			       0 132 0x04
+			       0 133 0x04
+			       0 134 0x04
+			       0 135 0x04
+			       0 136 0x04
+			       0 137 0x04
+			       0 138 0x04
+			       0 139 0x04
+			       0 140 0x04
+			       0 141 0x04
+			       0 142 0x04
+			       0 143 0x04 >;
+	};
+
 	i2c@7000c000 {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -55,9 +105,18 @@
 	gpio: gpio@6000d000 {
 		compatible = "nvidia,tegra30-gpio", "nvidia,tegra20-gpio";
 		reg = < 0x6000d000 0x1000 >;
-		interrupts = < 0 32 0x04 0 33 0x04 0 34 0x04 0 35 0x04 0 55 0x04 0 87 0x04 0 89 0x04 >;
+		interrupts = < 0 32 0x04
+			       0 33 0x04
+			       0 34 0x04
+			       0 35 0x04
+			       0 55 0x04
+			       0 87 0x04
+			       0 89 0x04
+			       0 125 0x04 >;
 		#gpio-cells = <2>;
 		gpio-controller;
+		#interrupt-cells = <2>;
+		interrupt-controller;
 	};
 
 	serial@70006000 {
diff --git a/arch/arm/boot/dts/usb_a9g20-dab-mmx.dtsi b/arch/arm/boot/dts/usb_a9g20-dab-mmx.dtsi
new file mode 100644
index 0000000..ad3eca1
--- /dev/null
+++ b/arch/arm/boot/dts/usb_a9g20-dab-mmx.dtsi
@@ -0,0 +1,96 @@
+/*
+ * calao-dab-mmx.dtsi - Device Tree Include file for Calao DAB-MMX Daughter Board
+ *
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+/ {
+	ahb {
+		apb {
+			usart1: serial@fffb4000 {
+				status = "okay";
+			};
+
+			usart3: serial@fffd0000 {
+				status = "okay";
+			};
+		};
+	};
+
+	i2c-gpio@0 {
+		status = "okay";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		user_led1 {
+			label = "user_led1";
+			gpios = <&pioB 20 1>;
+		};
+
+/*
+* led already used by mother board but active as high
+*		user_led2 {
+*			label = "user_led2";
+*			gpios = <&pioB 21 1>;
+*		};
+*/
+		user_led3 {
+			label = "user_led3";
+			gpios = <&pioB 22 1>;
+		};
+
+		user_led4 {
+			label = "user_led4";
+			gpios = <&pioB 23 1>;
+		};
+
+		red {
+			label = "red";
+			gpios = <&pioB 24 1>;
+		};
+
+		orange {
+			label = "orange";
+			gpios = <&pioB 30 1>;
+		};
+
+		green {
+			label = "green";
+			gpios = <&pioB 31 1>;
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		user_pb1 {
+			label = "user_pb1";
+			gpios = <&pioB 25 1>;
+			linux,code = <0x100>;
+		};
+
+		user_pb2 {
+			label = "user_pb2";
+			gpios = <&pioB 13 1>;
+			linux,code = <0x101>;
+		};
+
+		user_pb3 {
+			label = "user_pb3";
+			gpios = <&pioA 26 1>;
+			linux,code = <0x102>;
+		};
+
+		user_pb4 {
+			label = "user_pb4";
+			gpios = <&pioC 9 1>;
+			linux,code = <0x103>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/usb_a9g20.dts b/arch/arm/boot/dts/usb_a9g20.dts
index f04b535..7c2399c 100644
--- a/arch/arm/boot/dts/usb_a9g20.dts
+++ b/arch/arm/boot/dts/usb_a9g20.dts
@@ -13,13 +13,24 @@
 	compatible = "calao,usb-a9g20", "atmel,at91sam9g20", "atmel,at91sam9";
 
 	chosen {
-		bootargs = "mem=64M console=ttyS0,115200 mtdparts=atmel_nand:128k(at91bootstrap),256k(barebox)ro,128k(bareboxenv),128k(bareboxenv2),4M(kernel),120M(rootfs),-(data) root=/dev/mtdblock5 rw rootfstype=ubifs";
+		bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
 	};
 
-	memory@20000000 {
+	memory {
 		reg = <0x20000000 0x4000000>;
 	};
 
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		main_clock: clock@0 {
+			compatible = "atmel,osc", "fixed-clock";
+			clock-frequency = <12000000>;
+		};
+	};
+
 	ahb {
 		apb {
 			dbgu: serial@fffff200 {
@@ -30,6 +41,90 @@
 				phy-mode = "rmii";
 				status = "okay";
 			};
+
+			usb1: gadget@fffa4000 {
+				atmel,vbus-gpio = <&pioC 5 0>;
+				status = "okay";
+			};
+		};
+
+		nand0: nand@40000000 {
+			nand-bus-width = <8>;
+			nand-ecc-mode = "soft";
+			nand-on-flash-bbt;
+			status = "okay";
+
+			at91bootstrap@0 {
+				label = "at91bootstrap";
+				reg = <0x0 0x20000>;
+			};
+
+			barebox@20000 {
+				label = "barebox";
+				reg = <0x20000 0x40000>;
+			};
+
+			bareboxenv@60000 {
+				label = "bareboxenv";
+				reg = <0x60000 0x20000>;
+			};
+
+			bareboxenv2@80000 {
+				label = "bareboxenv2";
+				reg = <0x80000 0x20000>;
+			};
+
+			kernel@a0000 {
+				label = "kernel";
+				reg = <0xa0000 0x400000>;
+			};
+
+			rootfs@4a0000 {
+				label = "rootfs";
+				reg = <0x4a0000 0x7800000>;
+			};
+
+			data@7ca0000 {
+				label = "data";
+				reg = <0x7ca0000 0x8360000>;
+			};
+		};
+
+		usb0: ohci@00500000 {
+			num-ports = <2>;
+			status = "okay";
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		user_led {
+			label = "user_led";
+			gpios = <&pioB 21 1>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		user_pb {
+			label = "user_pb";
+			gpios = <&pioB 10 1>;
+			linux,code = <28>;
+			gpio-key,wakeup;
+		};
+	};
+
+	i2c@0 {
+		status = "okay";
+
+		rv3029c2@56 {
+			compatible = "rv3029c2";
+			reg = <0x56>;
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
new file mode 100644
index 0000000..16076e2
--- /dev/null
+++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -0,0 +1,201 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * Motherboard Express uATX
+ * V2M-P1
+ *
+ * HBI-0190D
+ *
+ * RS1 memory map ("ARM Cortex-A Series memory map" in the board's
+ * Technical Reference Manual)
+ *
+ * WARNING! The hardware described in this file is independent from the
+ * original variant (vexpress-v2m.dtsi), but there is a strong
+ * correspondence between the two configurations.
+ *
+ * TAKE CARE WHEN MAINTAINING THIS FILE TO PROPAGATE ANY RELEVANT
+ * CHANGES TO vexpress-v2m.dtsi!
+ */
+
+/ {
+	aliases {
+		arm,v2m_timer = &v2m_timer01;
+	};
+
+	motherboard {
+		compatible = "simple-bus";
+		arm,v2m-memory-map = "rs1";
+		#address-cells = <2>; /* SMB chipselect number and offset */
+		#size-cells = <1>;
+		#interrupt-cells = <1>;
+
+		flash@0,00000000 {
+			compatible = "arm,vexpress-flash", "cfi-flash";
+			reg = <0 0x00000000 0x04000000>,
+			      <4 0x00000000 0x04000000>;
+			bank-width = <4>;
+		};
+
+		psram@1,00000000 {
+			compatible = "arm,vexpress-psram", "mtd-ram";
+			reg = <1 0x00000000 0x02000000>;
+			bank-width = <4>;
+		};
+
+		vram@2,00000000 {
+			compatible = "arm,vexpress-vram";
+			reg = <2 0x00000000 0x00800000>;
+		};
+
+		ethernet@2,02000000 {
+			compatible = "smsc,lan9118", "smsc,lan9115";
+			reg = <2 0x02000000 0x10000>;
+			interrupts = <15>;
+			phy-mode = "mii";
+			reg-io-width = <4>;
+			smsc,irq-active-high;
+			smsc,irq-push-pull;
+		};
+
+		usb@2,03000000 {
+			compatible = "nxp,usb-isp1761";
+			reg = <2 0x03000000 0x20000>;
+			interrupts = <16>;
+			port1-otg;
+		};
+
+		iofpga@3,00000000 {
+			compatible = "arm,amba-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 3 0 0x200000>;
+
+			sysreg@010000 {
+				compatible = "arm,vexpress-sysreg";
+				reg = <0x010000 0x1000>;
+			};
+
+			sysctl@020000 {
+				compatible = "arm,sp810", "arm,primecell";
+				reg = <0x020000 0x1000>;
+			};
+
+			/* PCI-E I2C bus */
+			v2m_i2c_pcie: i2c@030000 {
+				compatible = "arm,versatile-i2c";
+				reg = <0x030000 0x1000>;
+
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				pcie-switch@60 {
+					compatible = "idt,89hpes32h8";
+					reg = <0x60>;
+				};
+			};
+
+			aaci@040000 {
+				compatible = "arm,pl041", "arm,primecell";
+				reg = <0x040000 0x1000>;
+				interrupts = <11>;
+			};
+
+			mmci@050000 {
+				compatible = "arm,pl180", "arm,primecell";
+				reg = <0x050000 0x1000>;
+				interrupts = <9 10>;
+			};
+
+			kmi@060000 {
+				compatible = "arm,pl050", "arm,primecell";
+				reg = <0x060000 0x1000>;
+				interrupts = <12>;
+			};
+
+			kmi@070000 {
+				compatible = "arm,pl050", "arm,primecell";
+				reg = <0x070000 0x1000>;
+				interrupts = <13>;
+			};
+
+			v2m_serial0: uart@090000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x090000 0x1000>;
+				interrupts = <5>;
+			};
+
+			v2m_serial1: uart@0a0000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x0a0000 0x1000>;
+				interrupts = <6>;
+			};
+
+			v2m_serial2: uart@0b0000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x0b0000 0x1000>;
+				interrupts = <7>;
+			};
+
+			v2m_serial3: uart@0c0000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x0c0000 0x1000>;
+				interrupts = <8>;
+			};
+
+			wdt@0f0000 {
+				compatible = "arm,sp805", "arm,primecell";
+				reg = <0x0f0000 0x1000>;
+				interrupts = <0>;
+			};
+
+			v2m_timer01: timer@110000 {
+				compatible = "arm,sp804", "arm,primecell";
+				reg = <0x110000 0x1000>;
+				interrupts = <2>;
+			};
+
+			v2m_timer23: timer@120000 {
+				compatible = "arm,sp804", "arm,primecell";
+				reg = <0x120000 0x1000>;
+			};
+
+			/* DVI I2C bus */
+			v2m_i2c_dvi: i2c@160000 {
+				compatible = "arm,versatile-i2c";
+				reg = <0x160000 0x1000>;
+
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				dvi-transmitter@39 {
+					compatible = "sil,sii9022-tpi", "sil,sii9022";
+					reg = <0x39>;
+				};
+
+				dvi-transmitter@60 {
+					compatible = "sil,sii9022-cpi", "sil,sii9022";
+					reg = <0x60>;
+				};
+			};
+
+			rtc@170000 {
+				compatible = "arm,pl031", "arm,primecell";
+				reg = <0x170000 0x1000>;
+				interrupts = <4>;
+			};
+
+			compact-flash@1a0000 {
+				compatible = "arm,vexpress-cf", "ata-generic";
+				reg = <0x1a0000 0x100
+				       0x1a0100 0xf00>;
+				reg-shift = <2>;
+			};
+
+			clcd@1f0000 {
+				compatible = "arm,pl111", "arm,primecell";
+				reg = <0x1f0000 0x1000>;
+				interrupts = <14>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi
new file mode 100644
index 0000000..a6c9c7c
--- /dev/null
+++ b/arch/arm/boot/dts/vexpress-v2m.dtsi
@@ -0,0 +1,200 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * Motherboard Express uATX
+ * V2M-P1
+ *
+ * HBI-0190D
+ *
+ * Original memory map ("Legacy memory map" in the board's
+ * Technical Reference Manual)
+ *
+ * WARNING! The hardware described in this file is independent from the
+ * RS1 variant (vexpress-v2m-rs1.dtsi), but there is a strong
+ * correspondence between the two configurations.
+ *
+ * TAKE CARE WHEN MAINTAINING THIS FILE TO PROPAGATE ANY RELEVANT
+ * CHANGES TO vexpress-v2m-rs1.dtsi!
+ */
+
+/ {
+	aliases {
+		arm,v2m_timer = &v2m_timer01;
+	};
+
+	motherboard {
+		compatible = "simple-bus";
+		#address-cells = <2>; /* SMB chipselect number and offset */
+		#size-cells = <1>;
+		#interrupt-cells = <1>;
+
+		flash@0,00000000 {
+			compatible = "arm,vexpress-flash", "cfi-flash";
+			reg = <0 0x00000000 0x04000000>,
+			      <1 0x00000000 0x04000000>;
+			bank-width = <4>;
+		};
+
+		psram@2,00000000 {
+			compatible = "arm,vexpress-psram", "mtd-ram";
+			reg = <2 0x00000000 0x02000000>;
+			bank-width = <4>;
+		};
+
+		vram@3,00000000 {
+			compatible = "arm,vexpress-vram";
+			reg = <3 0x00000000 0x00800000>;
+		};
+
+		ethernet@3,02000000 {
+			compatible = "smsc,lan9118", "smsc,lan9115";
+			reg = <3 0x02000000 0x10000>;
+			interrupts = <15>;
+			phy-mode = "mii";
+			reg-io-width = <4>;
+			smsc,irq-active-high;
+			smsc,irq-push-pull;
+		};
+
+		usb@3,03000000 {
+			compatible = "nxp,usb-isp1761";
+			reg = <3 0x03000000 0x20000>;
+			interrupts = <16>;
+			port1-otg;
+		};
+
+		iofpga@7,00000000 {
+			compatible = "arm,amba-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 7 0 0x20000>;
+
+			sysreg@00000 {
+				compatible = "arm,vexpress-sysreg";
+				reg = <0x00000 0x1000>;
+			};
+
+			sysctl@01000 {
+				compatible = "arm,sp810", "arm,primecell";
+				reg = <0x01000 0x1000>;
+			};
+
+			/* PCI-E I2C bus */
+			v2m_i2c_pcie: i2c@02000 {
+				compatible = "arm,versatile-i2c";
+				reg = <0x02000 0x1000>;
+
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				pcie-switch@60 {
+					compatible = "idt,89hpes32h8";
+					reg = <0x60>;
+				};
+			};
+
+			aaci@04000 {
+				compatible = "arm,pl041", "arm,primecell";
+				reg = <0x04000 0x1000>;
+				interrupts = <11>;
+			};
+
+			mmci@05000 {
+				compatible = "arm,pl180", "arm,primecell";
+				reg = <0x05000 0x1000>;
+				interrupts = <9 10>;
+			};
+
+			kmi@06000 {
+				compatible = "arm,pl050", "arm,primecell";
+				reg = <0x06000 0x1000>;
+				interrupts = <12>;
+			};
+
+			kmi@07000 {
+				compatible = "arm,pl050", "arm,primecell";
+				reg = <0x07000 0x1000>;
+				interrupts = <13>;
+			};
+
+			v2m_serial0: uart@09000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x09000 0x1000>;
+				interrupts = <5>;
+			};
+
+			v2m_serial1: uart@0a000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x0a000 0x1000>;
+				interrupts = <6>;
+			};
+
+			v2m_serial2: uart@0b000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x0b000 0x1000>;
+				interrupts = <7>;
+			};
+
+			v2m_serial3: uart@0c000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x0c000 0x1000>;
+				interrupts = <8>;
+			};
+
+			wdt@0f000 {
+				compatible = "arm,sp805", "arm,primecell";
+				reg = <0x0f000 0x1000>;
+				interrupts = <0>;
+			};
+
+			v2m_timer01: timer@11000 {
+				compatible = "arm,sp804", "arm,primecell";
+				reg = <0x11000 0x1000>;
+				interrupts = <2>;
+			};
+
+			v2m_timer23: timer@12000 {
+				compatible = "arm,sp804", "arm,primecell";
+				reg = <0x12000 0x1000>;
+			};
+
+			/* DVI I2C bus */
+			v2m_i2c_dvi: i2c@16000 {
+				compatible = "arm,versatile-i2c";
+				reg = <0x16000 0x1000>;
+
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				dvi-transmitter@39 {
+					compatible = "sil,sii9022-tpi", "sil,sii9022";
+					reg = <0x39>;
+				};
+
+				dvi-transmitter@60 {
+					compatible = "sil,sii9022-cpi", "sil,sii9022";
+					reg = <0x60>;
+				};
+			};
+
+			rtc@17000 {
+				compatible = "arm,pl031", "arm,primecell";
+				reg = <0x17000 0x1000>;
+				interrupts = <4>;
+			};
+
+			compact-flash@1a000 {
+				compatible = "arm,vexpress-cf", "ata-generic";
+				reg = <0x1a000 0x100
+				       0x1a100 0xf00>;
+				reg-shift = <2>;
+			};
+
+			clcd@1f000 {
+				compatible = "arm,pl111", "arm,primecell";
+				reg = <0x1f000 0x1000>;
+				interrupts = <14>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
new file mode 100644
index 0000000..941b161
--- /dev/null
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
@@ -0,0 +1,157 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * CoreTile Express A15x2 (version with Test Chip 1)
+ * Cortex-A15 MPCore (V2P-CA15)
+ *
+ * HBI-0237A
+ */
+
+/dts-v1/;
+
+/ {
+	model = "V2P-CA15";
+	arm,hbi = <0x237>;
+	compatible = "arm,vexpress,v2p-ca15,tc1", "arm,vexpress,v2p-ca15", "arm,vexpress";
+	interrupt-parent = <&gic>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	chosen { };
+
+	aliases {
+		serial0 = &v2m_serial0;
+		serial1 = &v2m_serial1;
+		serial2 = &v2m_serial2;
+		serial3 = &v2m_serial3;
+		i2c0 = &v2m_i2c_dvi;
+		i2c1 = &v2m_i2c_pcie;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <0>;
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <1>;
+		};
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x80000000 0x40000000>;
+	};
+
+	hdlcd@2b000000 {
+		compatible = "arm,hdlcd";
+		reg = <0x2b000000 0x1000>;
+		interrupts = <0 85 4>;
+	};
+
+	memory-controller@2b0a0000 {
+		compatible = "arm,pl341", "arm,primecell";
+		reg = <0x2b0a0000 0x1000>;
+	};
+
+	wdt@2b060000 {
+		compatible = "arm,sp805", "arm,primecell";
+		reg = <0x2b060000 0x1000>;
+		interrupts = <98>;
+	};
+
+	gic: interrupt-controller@2c001000 {
+		compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0x2c001000 0x1000>,
+		      <0x2c002000 0x100>;
+	};
+
+	memory-controller@7ffd0000 {
+		compatible = "arm,pl354", "arm,primecell";
+		reg = <0x7ffd0000 0x1000>;
+		interrupts = <0 86 4>,
+			     <0 87 4>;
+	};
+
+	dma@7ffb0000 {
+		compatible = "arm,pl330", "arm,primecell";
+		reg = <0x7ffb0000 0x1000>;
+		interrupts = <0 92 4>,
+			     <0 88 4>,
+			     <0 89 4>,
+			     <0 90 4>,
+			     <0 91 4>;
+	};
+
+	pmu {
+		compatible = "arm,cortex-a15-pmu", "arm,cortex-a9-pmu";
+		interrupts = <0 68 4>,
+			     <0 69 4>;
+	};
+
+	motherboard {
+		ranges = <0 0 0x08000000 0x04000000>,
+			 <1 0 0x14000000 0x04000000>,
+			 <2 0 0x18000000 0x04000000>,
+			 <3 0 0x1c000000 0x04000000>,
+			 <4 0 0x0c000000 0x04000000>,
+			 <5 0 0x10000000 0x04000000>;
+
+		interrupt-map-mask = <0 0 63>;
+		interrupt-map = <0 0  0 &gic 0  0 4>,
+				<0 0  1 &gic 0  1 4>,
+				<0 0  2 &gic 0  2 4>,
+				<0 0  3 &gic 0  3 4>,
+				<0 0  4 &gic 0  4 4>,
+				<0 0  5 &gic 0  5 4>,
+				<0 0  6 &gic 0  6 4>,
+				<0 0  7 &gic 0  7 4>,
+				<0 0  8 &gic 0  8 4>,
+				<0 0  9 &gic 0  9 4>,
+				<0 0 10 &gic 0 10 4>,
+				<0 0 11 &gic 0 11 4>,
+				<0 0 12 &gic 0 12 4>,
+				<0 0 13 &gic 0 13 4>,
+				<0 0 14 &gic 0 14 4>,
+				<0 0 15 &gic 0 15 4>,
+				<0 0 16 &gic 0 16 4>,
+				<0 0 17 &gic 0 17 4>,
+				<0 0 18 &gic 0 18 4>,
+				<0 0 19 &gic 0 19 4>,
+				<0 0 20 &gic 0 20 4>,
+				<0 0 21 &gic 0 21 4>,
+				<0 0 22 &gic 0 22 4>,
+				<0 0 23 &gic 0 23 4>,
+				<0 0 24 &gic 0 24 4>,
+				<0 0 25 &gic 0 25 4>,
+				<0 0 26 &gic 0 26 4>,
+				<0 0 27 &gic 0 27 4>,
+				<0 0 28 &gic 0 28 4>,
+				<0 0 29 &gic 0 29 4>,
+				<0 0 30 &gic 0 30 4>,
+				<0 0 31 &gic 0 31 4>,
+				<0 0 32 &gic 0 32 4>,
+				<0 0 33 &gic 0 33 4>,
+				<0 0 34 &gic 0 34 4>,
+				<0 0 35 &gic 0 35 4>,
+				<0 0 36 &gic 0 36 4>,
+				<0 0 37 &gic 0 37 4>,
+				<0 0 38 &gic 0 38 4>,
+				<0 0 39 &gic 0 39 4>,
+				<0 0 40 &gic 0 40 4>,
+				<0 0 41 &gic 0 41 4>,
+				<0 0 42 &gic 0 42 4>;
+	};
+};
+
+/include/ "vexpress-v2m-rs1.dtsi"
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
new file mode 100644
index 0000000..6905e66d
--- /dev/null
+++ b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
@@ -0,0 +1,162 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * CoreTile Express A5x2
+ * Cortex-A5 MPCore (V2P-CA5s)
+ *
+ * HBI-0225B
+ */
+
+/dts-v1/;
+
+/ {
+	model = "V2P-CA5s";
+	arm,hbi = <0x225>;
+	compatible = "arm,vexpress,v2p-ca5s", "arm,vexpress";
+	interrupt-parent = <&gic>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	chosen { };
+
+	aliases {
+		serial0 = &v2m_serial0;
+		serial1 = &v2m_serial1;
+		serial2 = &v2m_serial2;
+		serial3 = &v2m_serial3;
+		i2c0 = &v2m_i2c_dvi;
+		i2c1 = &v2m_i2c_pcie;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a5";
+			reg = <0>;
+			next-level-cache = <&L2>;
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a5";
+			reg = <1>;
+			next-level-cache = <&L2>;
+		};
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x80000000 0x40000000>;
+	};
+
+	hdlcd@2a110000 {
+		compatible = "arm,hdlcd";
+		reg = <0x2a110000 0x1000>;
+		interrupts = <0 85 4>;
+	};
+
+	memory-controller@2a150000 {
+		compatible = "arm,pl341", "arm,primecell";
+		reg = <0x2a150000 0x1000>;
+	};
+
+	memory-controller@2a190000 {
+		compatible = "arm,pl354", "arm,primecell";
+		reg = <0x2a190000 0x1000>;
+		interrupts = <0 86 4>,
+			     <0 87 4>;
+	};
+
+	scu@2c000000 {
+		compatible = "arm,cortex-a5-scu";
+		reg = <0x2c000000 0x58>;
+	};
+
+	timer@2c000600 {
+		compatible = "arm,cortex-a5-twd-timer";
+		reg = <0x2c000600 0x38>;
+		interrupts = <1 2 0x304>,
+			     <1 3 0x304>;
+	};
+
+	gic: interrupt-controller@2c001000 {
+		compatible = "arm,corex-a5-gic", "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0x2c001000 0x1000>,
+		      <0x2c000100 0x100>;
+	};
+
+	L2: cache-controller@2c0f0000 {
+		compatible = "arm,pl310-cache";
+		reg = <0x2c0f0000 0x1000>;
+		interrupts = <0 84 4>;
+		cache-level = <2>;
+	};
+
+	pmu {
+		compatible = "arm,cortex-a5-pmu", "arm,cortex-a9-pmu";
+		interrupts = <0 68 4>,
+			     <0 69 4>;
+	};
+
+	motherboard {
+		ranges = <0 0 0x08000000 0x04000000>,
+			 <1 0 0x14000000 0x04000000>,
+			 <2 0 0x18000000 0x04000000>,
+			 <3 0 0x1c000000 0x04000000>,
+			 <4 0 0x0c000000 0x04000000>,
+			 <5 0 0x10000000 0x04000000>;
+
+		interrupt-map-mask = <0 0 63>;
+		interrupt-map = <0 0  0 &gic 0  0 4>,
+				<0 0  1 &gic 0  1 4>,
+				<0 0  2 &gic 0  2 4>,
+				<0 0  3 &gic 0  3 4>,
+				<0 0  4 &gic 0  4 4>,
+				<0 0  5 &gic 0  5 4>,
+				<0 0  6 &gic 0  6 4>,
+				<0 0  7 &gic 0  7 4>,
+				<0 0  8 &gic 0  8 4>,
+				<0 0  9 &gic 0  9 4>,
+				<0 0 10 &gic 0 10 4>,
+				<0 0 11 &gic 0 11 4>,
+				<0 0 12 &gic 0 12 4>,
+				<0 0 13 &gic 0 13 4>,
+				<0 0 14 &gic 0 14 4>,
+				<0 0 15 &gic 0 15 4>,
+				<0 0 16 &gic 0 16 4>,
+				<0 0 17 &gic 0 17 4>,
+				<0 0 18 &gic 0 18 4>,
+				<0 0 19 &gic 0 19 4>,
+				<0 0 20 &gic 0 20 4>,
+				<0 0 21 &gic 0 21 4>,
+				<0 0 22 &gic 0 22 4>,
+				<0 0 23 &gic 0 23 4>,
+				<0 0 24 &gic 0 24 4>,
+				<0 0 25 &gic 0 25 4>,
+				<0 0 26 &gic 0 26 4>,
+				<0 0 27 &gic 0 27 4>,
+				<0 0 28 &gic 0 28 4>,
+				<0 0 29 &gic 0 29 4>,
+				<0 0 30 &gic 0 30 4>,
+				<0 0 31 &gic 0 31 4>,
+				<0 0 32 &gic 0 32 4>,
+				<0 0 33 &gic 0 33 4>,
+				<0 0 34 &gic 0 34 4>,
+				<0 0 35 &gic 0 35 4>,
+				<0 0 36 &gic 0 36 4>,
+				<0 0 37 &gic 0 37 4>,
+				<0 0 38 &gic 0 38 4>,
+				<0 0 39 &gic 0 39 4>,
+				<0 0 40 &gic 0 40 4>,
+				<0 0 41 &gic 0 41 4>,
+				<0 0 42 &gic 0 42 4>;
+	};
+};
+
+/include/ "vexpress-v2m-rs1.dtsi"
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
new file mode 100644
index 0000000..da77869
--- /dev/null
+++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
@@ -0,0 +1,192 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * CoreTile Express A9x4
+ * Cortex-A9 MPCore (V2P-CA9)
+ *
+ * HBI-0191B
+ */
+
+/dts-v1/;
+
+/ {
+	model = "V2P-CA9";
+	arm,hbi = <0x191>;
+	compatible = "arm,vexpress,v2p-ca9", "arm,vexpress";
+	interrupt-parent = <&gic>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	chosen { };
+
+	aliases {
+		serial0 = &v2m_serial0;
+		serial1 = &v2m_serial1;
+		serial2 = &v2m_serial2;
+		serial3 = &v2m_serial3;
+		i2c0 = &v2m_i2c_dvi;
+		i2c1 = &v2m_i2c_pcie;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <0>;
+			next-level-cache = <&L2>;
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <1>;
+			next-level-cache = <&L2>;
+		};
+
+		cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <2>;
+			next-level-cache = <&L2>;
+		};
+
+		cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <3>;
+			next-level-cache = <&L2>;
+		};
+	};
+
+	memory@60000000 {
+		device_type = "memory";
+		reg = <0x60000000 0x40000000>;
+	};
+
+	clcd@10020000 {
+		compatible = "arm,pl111", "arm,primecell";
+		reg = <0x10020000 0x1000>;
+		interrupts = <0 44 4>;
+	};
+
+	memory-controller@100e0000 {
+		compatible = "arm,pl341", "arm,primecell";
+		reg = <0x100e0000 0x1000>;
+	};
+
+	memory-controller@100e1000 {
+		compatible = "arm,pl354", "arm,primecell";
+		reg = <0x100e1000 0x1000>;
+		interrupts = <0 45 4>,
+			     <0 46 4>;
+	};
+
+	timer@100e4000 {
+		compatible = "arm,sp804", "arm,primecell";
+		reg = <0x100e4000 0x1000>;
+		interrupts = <0 48 4>,
+			     <0 49 4>;
+	};
+
+	watchdog@100e5000 {
+		compatible = "arm,sp805", "arm,primecell";
+		reg = <0x100e5000 0x1000>;
+		interrupts = <0 51 4>;
+	};
+
+	scu@1e000000 {
+		compatible = "arm,cortex-a9-scu";
+		reg = <0x1e000000 0x58>;
+	};
+
+	timer@1e000600 {
+		compatible = "arm,cortex-a9-twd-timer";
+		reg = <0x1e000600 0x20>;
+		interrupts = <1 2 0xf04>,
+			     <1 3 0xf04>;
+	};
+
+	gic: interrupt-controller@1e001000 {
+		compatible = "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0x1e001000 0x1000>,
+		      <0x1e000100 0x100>;
+	};
+
+	L2: cache-controller@1e00a000 {
+		compatible = "arm,pl310-cache";
+		reg = <0x1e00a000 0x1000>;
+		interrupts = <0 43 4>;
+		cache-level = <2>;
+		arm,data-latency = <1 1 1>;
+		arm,tag-latency = <1 1 1>;
+	};
+
+	pmu {
+		compatible = "arm,cortex-a9-pmu";
+		interrupts = <0 60 4>,
+			     <0 61 4>,
+			     <0 62 4>,
+			     <0 63 4>;
+	};
+
+	motherboard {
+		ranges = <0 0 0x40000000 0x04000000>,
+			 <1 0 0x44000000 0x04000000>,
+			 <2 0 0x48000000 0x04000000>,
+			 <3 0 0x4c000000 0x04000000>,
+			 <7 0 0x10000000 0x00020000>;
+
+		interrupt-map-mask = <0 0 63>;
+		interrupt-map = <0 0  0 &gic 0  0 4>,
+				<0 0  1 &gic 0  1 4>,
+				<0 0  2 &gic 0  2 4>,
+				<0 0  3 &gic 0  3 4>,
+				<0 0  4 &gic 0  4 4>,
+				<0 0  5 &gic 0  5 4>,
+				<0 0  6 &gic 0  6 4>,
+				<0 0  7 &gic 0  7 4>,
+				<0 0  8 &gic 0  8 4>,
+				<0 0  9 &gic 0  9 4>,
+				<0 0 10 &gic 0 10 4>,
+				<0 0 11 &gic 0 11 4>,
+				<0 0 12 &gic 0 12 4>,
+				<0 0 13 &gic 0 13 4>,
+				<0 0 14 &gic 0 14 4>,
+				<0 0 15 &gic 0 15 4>,
+				<0 0 16 &gic 0 16 4>,
+				<0 0 17 &gic 0 17 4>,
+				<0 0 18 &gic 0 18 4>,
+				<0 0 19 &gic 0 19 4>,
+				<0 0 20 &gic 0 20 4>,
+				<0 0 21 &gic 0 21 4>,
+				<0 0 22 &gic 0 22 4>,
+				<0 0 23 &gic 0 23 4>,
+				<0 0 24 &gic 0 24 4>,
+				<0 0 25 &gic 0 25 4>,
+				<0 0 26 &gic 0 26 4>,
+				<0 0 27 &gic 0 27 4>,
+				<0 0 28 &gic 0 28 4>,
+				<0 0 29 &gic 0 29 4>,
+				<0 0 30 &gic 0 30 4>,
+				<0 0 31 &gic 0 31 4>,
+				<0 0 32 &gic 0 32 4>,
+				<0 0 33 &gic 0 33 4>,
+				<0 0 34 &gic 0 34 4>,
+				<0 0 35 &gic 0 35 4>,
+				<0 0 36 &gic 0 36 4>,
+				<0 0 37 &gic 0 37 4>,
+				<0 0 38 &gic 0 38 4>,
+				<0 0 39 &gic 0 39 4>,
+				<0 0 40 &gic 0 40 4>,
+				<0 0 41 &gic 0 41 4>,
+				<0 0 42 &gic 0 42 4>;
+	};
+};
+
+/include/ "vexpress-v2m.dtsi"
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index 81a933e..283fa1d 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -24,9 +24,6 @@
 config ICST
 	bool
 
-config PL330
-	bool
-
 config SA1111
 	bool
 	select DMABOUNCE if !ARCH_PXA
@@ -35,9 +32,6 @@
 	bool
 	select ZONE_DMA
 
-config TIMER_ACORN
-	bool
-
 config SHARP_LOCOMO
 	bool
 
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index 6ea9b6f..215816f 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -5,11 +5,9 @@
 obj-$(CONFIG_ARM_GIC)		+= gic.o
 obj-$(CONFIG_ARM_VIC)		+= vic.o
 obj-$(CONFIG_ICST)		+= icst.o
-obj-$(CONFIG_PL330)		+= pl330.o
 obj-$(CONFIG_SA1111)		+= sa1111.o
 obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o
 obj-$(CONFIG_DMABOUNCE)		+= dmabounce.o
-obj-$(CONFIG_TIMER_ACORN)	+= time-acorn.o
 obj-$(CONFIG_SHARP_LOCOMO)	+= locomo.o
 obj-$(CONFIG_SHARP_PARAM)	+= sharpsl_param.o
 obj-$(CONFIG_SHARP_SCOOP)	+= scoop.o
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index f0783be..aa52699 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -686,13 +686,12 @@
 	 * For primary GICs, skip over SGIs.
 	 * For secondary GICs, skip over PPIs, too.
 	 */
-	hwirq_base = 32;
-	if (gic_nr == 0) {
-		if ((irq_start & 31) > 0) {
-			hwirq_base = 16;
-			if (irq_start != -1)
-				irq_start = (irq_start & ~31) + 16;
-		}
+	if (gic_nr == 0 && (irq_start & 31) > 0) {
+		hwirq_base = 16;
+		if (irq_start != -1)
+			irq_start = (irq_start & ~31) + 16;
+	} else {
+		hwirq_base = 32;
 	}
 
 	/*
diff --git a/arch/arm/common/it8152.c b/arch/arm/common/it8152.c
index fb1f1cf..dcb1349 100644
--- a/arch/arm/common/it8152.c
+++ b/arch/arm/common/it8152.c
@@ -299,8 +299,8 @@
 		goto err1;
 	}
 
-	pci_add_resource(&sys->resources, &it8152_io);
-	pci_add_resource(&sys->resources, &it8152_mem);
+	pci_add_resource_offset(&sys->resources, &it8152_io, sys->io_offset);
+	pci_add_resource_offset(&sys->resources, &it8152_mem, sys->mem_offset);
 
 	if (platform_notify || platform_notify_remove) {
 		printk(KERN_ERR "PCI: Can't use platform_notify\n");
diff --git a/arch/arm/common/pl330.c b/arch/arm/common/pl330.c
deleted file mode 100644
index ff3ad22..0000000
--- a/arch/arm/common/pl330.c
+++ /dev/null
@@ -1,1960 +0,0 @@
-/* linux/arch/arm/common/pl330.c
- *
- * Copyright (C) 2010 Samsung Electronics Co Ltd.
- *	Jaswinder Singh <jassi.brar@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 distributed in the hope that it will be useful,
- * but WITHOUT 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/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/hardware/pl330.h>
-
-/* Register and Bit field Definitions */
-#define DS		0x0
-#define DS_ST_STOP	0x0
-#define DS_ST_EXEC	0x1
-#define DS_ST_CMISS	0x2
-#define DS_ST_UPDTPC	0x3
-#define DS_ST_WFE	0x4
-#define DS_ST_ATBRR	0x5
-#define DS_ST_QBUSY	0x6
-#define DS_ST_WFP	0x7
-#define DS_ST_KILL	0x8
-#define DS_ST_CMPLT	0x9
-#define DS_ST_FLTCMP	0xe
-#define DS_ST_FAULT	0xf
-
-#define DPC		0x4
-#define INTEN		0x20
-#define ES		0x24
-#define INTSTATUS	0x28
-#define INTCLR		0x2c
-#define FSM		0x30
-#define FSC		0x34
-#define FTM		0x38
-
-#define _FTC		0x40
-#define FTC(n)		(_FTC + (n)*0x4)
-
-#define _CS		0x100
-#define CS(n)		(_CS + (n)*0x8)
-#define CS_CNS		(1 << 21)
-
-#define _CPC		0x104
-#define CPC(n)		(_CPC + (n)*0x8)
-
-#define _SA		0x400
-#define SA(n)		(_SA + (n)*0x20)
-
-#define _DA		0x404
-#define DA(n)		(_DA + (n)*0x20)
-
-#define _CC		0x408
-#define CC(n)		(_CC + (n)*0x20)
-
-#define CC_SRCINC	(1 << 0)
-#define CC_DSTINC	(1 << 14)
-#define CC_SRCPRI	(1 << 8)
-#define CC_DSTPRI	(1 << 22)
-#define CC_SRCNS	(1 << 9)
-#define CC_DSTNS	(1 << 23)
-#define CC_SRCIA	(1 << 10)
-#define CC_DSTIA	(1 << 24)
-#define CC_SRCBRSTLEN_SHFT	4
-#define CC_DSTBRSTLEN_SHFT	18
-#define CC_SRCBRSTSIZE_SHFT	1
-#define CC_DSTBRSTSIZE_SHFT	15
-#define CC_SRCCCTRL_SHFT	11
-#define CC_SRCCCTRL_MASK	0x7
-#define CC_DSTCCTRL_SHFT	25
-#define CC_DRCCCTRL_MASK	0x7
-#define CC_SWAP_SHFT	28
-
-#define _LC0		0x40c
-#define LC0(n)		(_LC0 + (n)*0x20)
-
-#define _LC1		0x410
-#define LC1(n)		(_LC1 + (n)*0x20)
-
-#define DBGSTATUS	0xd00
-#define DBG_BUSY	(1 << 0)
-
-#define DBGCMD		0xd04
-#define DBGINST0	0xd08
-#define DBGINST1	0xd0c
-
-#define CR0		0xe00
-#define CR1		0xe04
-#define CR2		0xe08
-#define CR3		0xe0c
-#define CR4		0xe10
-#define CRD		0xe14
-
-#define PERIPH_ID	0xfe0
-#define PCELL_ID	0xff0
-
-#define CR0_PERIPH_REQ_SET	(1 << 0)
-#define CR0_BOOT_EN_SET		(1 << 1)
-#define CR0_BOOT_MAN_NS		(1 << 2)
-#define CR0_NUM_CHANS_SHIFT	4
-#define CR0_NUM_CHANS_MASK	0x7
-#define CR0_NUM_PERIPH_SHIFT	12
-#define CR0_NUM_PERIPH_MASK	0x1f
-#define CR0_NUM_EVENTS_SHIFT	17
-#define CR0_NUM_EVENTS_MASK	0x1f
-
-#define CR1_ICACHE_LEN_SHIFT	0
-#define CR1_ICACHE_LEN_MASK	0x7
-#define CR1_NUM_ICACHELINES_SHIFT	4
-#define CR1_NUM_ICACHELINES_MASK	0xf
-
-#define CRD_DATA_WIDTH_SHIFT	0
-#define CRD_DATA_WIDTH_MASK	0x7
-#define CRD_WR_CAP_SHIFT	4
-#define CRD_WR_CAP_MASK		0x7
-#define CRD_WR_Q_DEP_SHIFT	8
-#define CRD_WR_Q_DEP_MASK	0xf
-#define CRD_RD_CAP_SHIFT	12
-#define CRD_RD_CAP_MASK		0x7
-#define CRD_RD_Q_DEP_SHIFT	16
-#define CRD_RD_Q_DEP_MASK	0xf
-#define CRD_DATA_BUFF_SHIFT	20
-#define CRD_DATA_BUFF_MASK	0x3ff
-
-#define	PART		0x330
-#define DESIGNER	0x41
-#define REVISION	0x0
-#define INTEG_CFG	0x0
-#define PERIPH_ID_VAL	((PART << 0) | (DESIGNER << 12))
-
-#define PCELL_ID_VAL	0xb105f00d
-
-#define PL330_STATE_STOPPED		(1 << 0)
-#define PL330_STATE_EXECUTING		(1 << 1)
-#define PL330_STATE_WFE			(1 << 2)
-#define PL330_STATE_FAULTING		(1 << 3)
-#define PL330_STATE_COMPLETING		(1 << 4)
-#define PL330_STATE_WFP			(1 << 5)
-#define PL330_STATE_KILLING		(1 << 6)
-#define PL330_STATE_FAULT_COMPLETING	(1 << 7)
-#define PL330_STATE_CACHEMISS		(1 << 8)
-#define PL330_STATE_UPDTPC		(1 << 9)
-#define PL330_STATE_ATBARRIER		(1 << 10)
-#define PL330_STATE_QUEUEBUSY		(1 << 11)
-#define PL330_STATE_INVALID		(1 << 15)
-
-#define PL330_STABLE_STATES (PL330_STATE_STOPPED | PL330_STATE_EXECUTING \
-				| PL330_STATE_WFE | PL330_STATE_FAULTING)
-
-#define CMD_DMAADDH	0x54
-#define CMD_DMAEND	0x00
-#define CMD_DMAFLUSHP	0x35
-#define CMD_DMAGO	0xa0
-#define CMD_DMALD	0x04
-#define CMD_DMALDP	0x25
-#define CMD_DMALP	0x20
-#define CMD_DMALPEND	0x28
-#define CMD_DMAKILL	0x01
-#define CMD_DMAMOV	0xbc
-#define CMD_DMANOP	0x18
-#define CMD_DMARMB	0x12
-#define CMD_DMASEV	0x34
-#define CMD_DMAST	0x08
-#define CMD_DMASTP	0x29
-#define CMD_DMASTZ	0x0c
-#define CMD_DMAWFE	0x36
-#define CMD_DMAWFP	0x30
-#define CMD_DMAWMB	0x13
-
-#define SZ_DMAADDH	3
-#define SZ_DMAEND	1
-#define SZ_DMAFLUSHP	2
-#define SZ_DMALD	1
-#define SZ_DMALDP	2
-#define SZ_DMALP	2
-#define SZ_DMALPEND	2
-#define SZ_DMAKILL	1
-#define SZ_DMAMOV	6
-#define SZ_DMANOP	1
-#define SZ_DMARMB	1
-#define SZ_DMASEV	2
-#define SZ_DMAST	1
-#define SZ_DMASTP	2
-#define SZ_DMASTZ	1
-#define SZ_DMAWFE	2
-#define SZ_DMAWFP	2
-#define SZ_DMAWMB	1
-#define SZ_DMAGO	6
-
-#define BRST_LEN(ccr)	((((ccr) >> CC_SRCBRSTLEN_SHFT) & 0xf) + 1)
-#define BRST_SIZE(ccr)	(1 << (((ccr) >> CC_SRCBRSTSIZE_SHFT) & 0x7))
-
-#define BYTE_TO_BURST(b, ccr)  ((b) / BRST_SIZE(ccr) / BRST_LEN(ccr))
-#define BURST_TO_BYTE(c, ccr)  ((c) * BRST_SIZE(ccr) * BRST_LEN(ccr))
-
-/*
- * With 256 bytes, we can do more than 2.5MB and 5MB xfers per req
- * at 1byte/burst for P<->M and M<->M respectively.
- * For typical scenario, at 1word/burst, 10MB and 20MB xfers per req
- * should be enough for P<->M and M<->M respectively.
- */
-#define MCODE_BUFF_PER_REQ	256
-
-/* If the _pl330_req is available to the client */
-#define IS_FREE(req)	(*((u8 *)((req)->mc_cpu)) == CMD_DMAEND)
-
-/* Use this _only_ to wait on transient states */
-#define UNTIL(t, s)	while (!(_state(t) & (s))) cpu_relax();
-
-#ifdef PL330_DEBUG_MCGEN
-static unsigned cmd_line;
-#define PL330_DBGCMD_DUMP(off, x...)	do { \
-						printk("%x:", cmd_line); \
-						printk(x); \
-						cmd_line += off; \
-					} while (0)
-#define PL330_DBGMC_START(addr)		(cmd_line = addr)
-#else
-#define PL330_DBGCMD_DUMP(off, x...)	do {} while (0)
-#define PL330_DBGMC_START(addr)		do {} while (0)
-#endif
-
-struct _xfer_spec {
-	u32 ccr;
-	struct pl330_req *r;
-	struct pl330_xfer *x;
-};
-
-enum dmamov_dst {
-	SAR = 0,
-	CCR,
-	DAR,
-};
-
-enum pl330_dst {
-	SRC = 0,
-	DST,
-};
-
-enum pl330_cond {
-	SINGLE,
-	BURST,
-	ALWAYS,
-};
-
-struct _pl330_req {
-	u32 mc_bus;
-	void *mc_cpu;
-	/* Number of bytes taken to setup MC for the req */
-	u32 mc_len;
-	struct pl330_req *r;
-	/* Hook to attach to DMAC's list of reqs with due callback */
-	struct list_head rqd;
-};
-
-/* ToBeDone for tasklet */
-struct _pl330_tbd {
-	bool reset_dmac;
-	bool reset_mngr;
-	u8 reset_chan;
-};
-
-/* A DMAC Thread */
-struct pl330_thread {
-	u8 id;
-	int ev;
-	/* If the channel is not yet acquired by any client */
-	bool free;
-	/* Parent DMAC */
-	struct pl330_dmac *dmac;
-	/* Only two at a time */
-	struct _pl330_req req[2];
-	/* Index of the last enqueued request */
-	unsigned lstenq;
-	/* Index of the last submitted request or -1 if the DMA is stopped */
-	int req_running;
-};
-
-enum pl330_dmac_state {
-	UNINIT,
-	INIT,
-	DYING,
-};
-
-/* A DMAC */
-struct pl330_dmac {
-	spinlock_t		lock;
-	/* Holds list of reqs with due callbacks */
-	struct list_head	req_done;
-	/* Pointer to platform specific stuff */
-	struct pl330_info	*pinfo;
-	/* Maximum possible events/irqs */
-	int			events[32];
-	/* BUS address of MicroCode buffer */
-	u32			mcode_bus;
-	/* CPU address of MicroCode buffer */
-	void			*mcode_cpu;
-	/* List of all Channel threads */
-	struct pl330_thread	*channels;
-	/* Pointer to the MANAGER thread */
-	struct pl330_thread	*manager;
-	/* To handle bad news in interrupt */
-	struct tasklet_struct	tasks;
-	struct _pl330_tbd	dmac_tbd;
-	/* State of DMAC operation */
-	enum pl330_dmac_state	state;
-};
-
-static inline void _callback(struct pl330_req *r, enum pl330_op_err err)
-{
-	if (r && r->xfer_cb)
-		r->xfer_cb(r->token, err);
-}
-
-static inline bool _queue_empty(struct pl330_thread *thrd)
-{
-	return (IS_FREE(&thrd->req[0]) && IS_FREE(&thrd->req[1]))
-		? true : false;
-}
-
-static inline bool _queue_full(struct pl330_thread *thrd)
-{
-	return (IS_FREE(&thrd->req[0]) || IS_FREE(&thrd->req[1]))
-		? false : true;
-}
-
-static inline bool is_manager(struct pl330_thread *thrd)
-{
-	struct pl330_dmac *pl330 = thrd->dmac;
-
-	/* MANAGER is indexed at the end */
-	if (thrd->id == pl330->pinfo->pcfg.num_chan)
-		return true;
-	else
-		return false;
-}
-
-/* If manager of the thread is in Non-Secure mode */
-static inline bool _manager_ns(struct pl330_thread *thrd)
-{
-	struct pl330_dmac *pl330 = thrd->dmac;
-
-	return (pl330->pinfo->pcfg.mode & DMAC_MODE_NS) ? true : false;
-}
-
-static inline u32 get_id(struct pl330_info *pi, u32 off)
-{
-	void __iomem *regs = pi->base;
-	u32 id = 0;
-
-	id |= (readb(regs + off + 0x0) << 0);
-	id |= (readb(regs + off + 0x4) << 8);
-	id |= (readb(regs + off + 0x8) << 16);
-	id |= (readb(regs + off + 0xc) << 24);
-
-	return id;
-}
-
-static inline u32 _emit_ADDH(unsigned dry_run, u8 buf[],
-		enum pl330_dst da, u16 val)
-{
-	if (dry_run)
-		return SZ_DMAADDH;
-
-	buf[0] = CMD_DMAADDH;
-	buf[0] |= (da << 1);
-	*((u16 *)&buf[1]) = val;
-
-	PL330_DBGCMD_DUMP(SZ_DMAADDH, "\tDMAADDH %s %u\n",
-		da == 1 ? "DA" : "SA", val);
-
-	return SZ_DMAADDH;
-}
-
-static inline u32 _emit_END(unsigned dry_run, u8 buf[])
-{
-	if (dry_run)
-		return SZ_DMAEND;
-
-	buf[0] = CMD_DMAEND;
-
-	PL330_DBGCMD_DUMP(SZ_DMAEND, "\tDMAEND\n");
-
-	return SZ_DMAEND;
-}
-
-static inline u32 _emit_FLUSHP(unsigned dry_run, u8 buf[], u8 peri)
-{
-	if (dry_run)
-		return SZ_DMAFLUSHP;
-
-	buf[0] = CMD_DMAFLUSHP;
-
-	peri &= 0x1f;
-	peri <<= 3;
-	buf[1] = peri;
-
-	PL330_DBGCMD_DUMP(SZ_DMAFLUSHP, "\tDMAFLUSHP %u\n", peri >> 3);
-
-	return SZ_DMAFLUSHP;
-}
-
-static inline u32 _emit_LD(unsigned dry_run, u8 buf[],	enum pl330_cond cond)
-{
-	if (dry_run)
-		return SZ_DMALD;
-
-	buf[0] = CMD_DMALD;
-
-	if (cond == SINGLE)
-		buf[0] |= (0 << 1) | (1 << 0);
-	else if (cond == BURST)
-		buf[0] |= (1 << 1) | (1 << 0);
-
-	PL330_DBGCMD_DUMP(SZ_DMALD, "\tDMALD%c\n",
-		cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'));
-
-	return SZ_DMALD;
-}
-
-static inline u32 _emit_LDP(unsigned dry_run, u8 buf[],
-		enum pl330_cond cond, u8 peri)
-{
-	if (dry_run)
-		return SZ_DMALDP;
-
-	buf[0] = CMD_DMALDP;
-
-	if (cond == BURST)
-		buf[0] |= (1 << 1);
-
-	peri &= 0x1f;
-	peri <<= 3;
-	buf[1] = peri;
-
-	PL330_DBGCMD_DUMP(SZ_DMALDP, "\tDMALDP%c %u\n",
-		cond == SINGLE ? 'S' : 'B', peri >> 3);
-
-	return SZ_DMALDP;
-}
-
-static inline u32 _emit_LP(unsigned dry_run, u8 buf[],
-		unsigned loop, u8 cnt)
-{
-	if (dry_run)
-		return SZ_DMALP;
-
-	buf[0] = CMD_DMALP;
-
-	if (loop)
-		buf[0] |= (1 << 1);
-
-	cnt--; /* DMAC increments by 1 internally */
-	buf[1] = cnt;
-
-	PL330_DBGCMD_DUMP(SZ_DMALP, "\tDMALP_%c %u\n", loop ? '1' : '0', cnt);
-
-	return SZ_DMALP;
-}
-
-struct _arg_LPEND {
-	enum pl330_cond cond;
-	bool forever;
-	unsigned loop;
-	u8 bjump;
-};
-
-static inline u32 _emit_LPEND(unsigned dry_run, u8 buf[],
-		const struct _arg_LPEND *arg)
-{
-	enum pl330_cond cond = arg->cond;
-	bool forever = arg->forever;
-	unsigned loop = arg->loop;
-	u8 bjump = arg->bjump;
-
-	if (dry_run)
-		return SZ_DMALPEND;
-
-	buf[0] = CMD_DMALPEND;
-
-	if (loop)
-		buf[0] |= (1 << 2);
-
-	if (!forever)
-		buf[0] |= (1 << 4);
-
-	if (cond == SINGLE)
-		buf[0] |= (0 << 1) | (1 << 0);
-	else if (cond == BURST)
-		buf[0] |= (1 << 1) | (1 << 0);
-
-	buf[1] = bjump;
-
-	PL330_DBGCMD_DUMP(SZ_DMALPEND, "\tDMALP%s%c_%c bjmpto_%x\n",
-			forever ? "FE" : "END",
-			cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'),
-			loop ? '1' : '0',
-			bjump);
-
-	return SZ_DMALPEND;
-}
-
-static inline u32 _emit_KILL(unsigned dry_run, u8 buf[])
-{
-	if (dry_run)
-		return SZ_DMAKILL;
-
-	buf[0] = CMD_DMAKILL;
-
-	return SZ_DMAKILL;
-}
-
-static inline u32 _emit_MOV(unsigned dry_run, u8 buf[],
-		enum dmamov_dst dst, u32 val)
-{
-	if (dry_run)
-		return SZ_DMAMOV;
-
-	buf[0] = CMD_DMAMOV;
-	buf[1] = dst;
-	*((u32 *)&buf[2]) = val;
-
-	PL330_DBGCMD_DUMP(SZ_DMAMOV, "\tDMAMOV %s 0x%x\n",
-		dst == SAR ? "SAR" : (dst == DAR ? "DAR" : "CCR"), val);
-
-	return SZ_DMAMOV;
-}
-
-static inline u32 _emit_NOP(unsigned dry_run, u8 buf[])
-{
-	if (dry_run)
-		return SZ_DMANOP;
-
-	buf[0] = CMD_DMANOP;
-
-	PL330_DBGCMD_DUMP(SZ_DMANOP, "\tDMANOP\n");
-
-	return SZ_DMANOP;
-}
-
-static inline u32 _emit_RMB(unsigned dry_run, u8 buf[])
-{
-	if (dry_run)
-		return SZ_DMARMB;
-
-	buf[0] = CMD_DMARMB;
-
-	PL330_DBGCMD_DUMP(SZ_DMARMB, "\tDMARMB\n");
-
-	return SZ_DMARMB;
-}
-
-static inline u32 _emit_SEV(unsigned dry_run, u8 buf[], u8 ev)
-{
-	if (dry_run)
-		return SZ_DMASEV;
-
-	buf[0] = CMD_DMASEV;
-
-	ev &= 0x1f;
-	ev <<= 3;
-	buf[1] = ev;
-
-	PL330_DBGCMD_DUMP(SZ_DMASEV, "\tDMASEV %u\n", ev >> 3);
-
-	return SZ_DMASEV;
-}
-
-static inline u32 _emit_ST(unsigned dry_run, u8 buf[], enum pl330_cond cond)
-{
-	if (dry_run)
-		return SZ_DMAST;
-
-	buf[0] = CMD_DMAST;
-
-	if (cond == SINGLE)
-		buf[0] |= (0 << 1) | (1 << 0);
-	else if (cond == BURST)
-		buf[0] |= (1 << 1) | (1 << 0);
-
-	PL330_DBGCMD_DUMP(SZ_DMAST, "\tDMAST%c\n",
-		cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'));
-
-	return SZ_DMAST;
-}
-
-static inline u32 _emit_STP(unsigned dry_run, u8 buf[],
-		enum pl330_cond cond, u8 peri)
-{
-	if (dry_run)
-		return SZ_DMASTP;
-
-	buf[0] = CMD_DMASTP;
-
-	if (cond == BURST)
-		buf[0] |= (1 << 1);
-
-	peri &= 0x1f;
-	peri <<= 3;
-	buf[1] = peri;
-
-	PL330_DBGCMD_DUMP(SZ_DMASTP, "\tDMASTP%c %u\n",
-		cond == SINGLE ? 'S' : 'B', peri >> 3);
-
-	return SZ_DMASTP;
-}
-
-static inline u32 _emit_STZ(unsigned dry_run, u8 buf[])
-{
-	if (dry_run)
-		return SZ_DMASTZ;
-
-	buf[0] = CMD_DMASTZ;
-
-	PL330_DBGCMD_DUMP(SZ_DMASTZ, "\tDMASTZ\n");
-
-	return SZ_DMASTZ;
-}
-
-static inline u32 _emit_WFE(unsigned dry_run, u8 buf[], u8 ev,
-		unsigned invalidate)
-{
-	if (dry_run)
-		return SZ_DMAWFE;
-
-	buf[0] = CMD_DMAWFE;
-
-	ev &= 0x1f;
-	ev <<= 3;
-	buf[1] = ev;
-
-	if (invalidate)
-		buf[1] |= (1 << 1);
-
-	PL330_DBGCMD_DUMP(SZ_DMAWFE, "\tDMAWFE %u%s\n",
-		ev >> 3, invalidate ? ", I" : "");
-
-	return SZ_DMAWFE;
-}
-
-static inline u32 _emit_WFP(unsigned dry_run, u8 buf[],
-		enum pl330_cond cond, u8 peri)
-{
-	if (dry_run)
-		return SZ_DMAWFP;
-
-	buf[0] = CMD_DMAWFP;
-
-	if (cond == SINGLE)
-		buf[0] |= (0 << 1) | (0 << 0);
-	else if (cond == BURST)
-		buf[0] |= (1 << 1) | (0 << 0);
-	else
-		buf[0] |= (0 << 1) | (1 << 0);
-
-	peri &= 0x1f;
-	peri <<= 3;
-	buf[1] = peri;
-
-	PL330_DBGCMD_DUMP(SZ_DMAWFP, "\tDMAWFP%c %u\n",
-		cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'P'), peri >> 3);
-
-	return SZ_DMAWFP;
-}
-
-static inline u32 _emit_WMB(unsigned dry_run, u8 buf[])
-{
-	if (dry_run)
-		return SZ_DMAWMB;
-
-	buf[0] = CMD_DMAWMB;
-
-	PL330_DBGCMD_DUMP(SZ_DMAWMB, "\tDMAWMB\n");
-
-	return SZ_DMAWMB;
-}
-
-struct _arg_GO {
-	u8 chan;
-	u32 addr;
-	unsigned ns;
-};
-
-static inline u32 _emit_GO(unsigned dry_run, u8 buf[],
-		const struct _arg_GO *arg)
-{
-	u8 chan = arg->chan;
-	u32 addr = arg->addr;
-	unsigned ns = arg->ns;
-
-	if (dry_run)
-		return SZ_DMAGO;
-
-	buf[0] = CMD_DMAGO;
-	buf[0] |= (ns << 1);
-
-	buf[1] = chan & 0x7;
-
-	*((u32 *)&buf[2]) = addr;
-
-	return SZ_DMAGO;
-}
-
-#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
-
-/* Returns Time-Out */
-static bool _until_dmac_idle(struct pl330_thread *thrd)
-{
-	void __iomem *regs = thrd->dmac->pinfo->base;
-	unsigned long loops = msecs_to_loops(5);
-
-	do {
-		/* Until Manager is Idle */
-		if (!(readl(regs + DBGSTATUS) & DBG_BUSY))
-			break;
-
-		cpu_relax();
-	} while (--loops);
-
-	if (!loops)
-		return true;
-
-	return false;
-}
-
-static inline void _execute_DBGINSN(struct pl330_thread *thrd,
-		u8 insn[], bool as_manager)
-{
-	void __iomem *regs = thrd->dmac->pinfo->base;
-	u32 val;
-
-	val = (insn[0] << 16) | (insn[1] << 24);
-	if (!as_manager) {
-		val |= (1 << 0);
-		val |= (thrd->id << 8); /* Channel Number */
-	}
-	writel(val, regs + DBGINST0);
-
-	val = *((u32 *)&insn[2]);
-	writel(val, regs + DBGINST1);
-
-	/* If timed out due to halted state-machine */
-	if (_until_dmac_idle(thrd)) {
-		dev_err(thrd->dmac->pinfo->dev, "DMAC halted!\n");
-		return;
-	}
-
-	/* Get going */
-	writel(0, regs + DBGCMD);
-}
-
-/*
- * Mark a _pl330_req as free.
- * We do it by writing DMAEND as the first instruction
- * because no valid request is going to have DMAEND as
- * its first instruction to execute.
- */
-static void mark_free(struct pl330_thread *thrd, int idx)
-{
-	struct _pl330_req *req = &thrd->req[idx];
-
-	_emit_END(0, req->mc_cpu);
-	req->mc_len = 0;
-
-	thrd->req_running = -1;
-}
-
-static inline u32 _state(struct pl330_thread *thrd)
-{
-	void __iomem *regs = thrd->dmac->pinfo->base;
-	u32 val;
-
-	if (is_manager(thrd))
-		val = readl(regs + DS) & 0xf;
-	else
-		val = readl(regs + CS(thrd->id)) & 0xf;
-
-	switch (val) {
-	case DS_ST_STOP:
-		return PL330_STATE_STOPPED;
-	case DS_ST_EXEC:
-		return PL330_STATE_EXECUTING;
-	case DS_ST_CMISS:
-		return PL330_STATE_CACHEMISS;
-	case DS_ST_UPDTPC:
-		return PL330_STATE_UPDTPC;
-	case DS_ST_WFE:
-		return PL330_STATE_WFE;
-	case DS_ST_FAULT:
-		return PL330_STATE_FAULTING;
-	case DS_ST_ATBRR:
-		if (is_manager(thrd))
-			return PL330_STATE_INVALID;
-		else
-			return PL330_STATE_ATBARRIER;
-	case DS_ST_QBUSY:
-		if (is_manager(thrd))
-			return PL330_STATE_INVALID;
-		else
-			return PL330_STATE_QUEUEBUSY;
-	case DS_ST_WFP:
-		if (is_manager(thrd))
-			return PL330_STATE_INVALID;
-		else
-			return PL330_STATE_WFP;
-	case DS_ST_KILL:
-		if (is_manager(thrd))
-			return PL330_STATE_INVALID;
-		else
-			return PL330_STATE_KILLING;
-	case DS_ST_CMPLT:
-		if (is_manager(thrd))
-			return PL330_STATE_INVALID;
-		else
-			return PL330_STATE_COMPLETING;
-	case DS_ST_FLTCMP:
-		if (is_manager(thrd))
-			return PL330_STATE_INVALID;
-		else
-			return PL330_STATE_FAULT_COMPLETING;
-	default:
-		return PL330_STATE_INVALID;
-	}
-}
-
-static void _stop(struct pl330_thread *thrd)
-{
-	void __iomem *regs = thrd->dmac->pinfo->base;
-	u8 insn[6] = {0, 0, 0, 0, 0, 0};
-
-	if (_state(thrd) == PL330_STATE_FAULT_COMPLETING)
-		UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING);
-
-	/* Return if nothing needs to be done */
-	if (_state(thrd) == PL330_STATE_COMPLETING
-		  || _state(thrd) == PL330_STATE_KILLING
-		  || _state(thrd) == PL330_STATE_STOPPED)
-		return;
-
-	_emit_KILL(0, insn);
-
-	/* Stop generating interrupts for SEV */
-	writel(readl(regs + INTEN) & ~(1 << thrd->ev), regs + INTEN);
-
-	_execute_DBGINSN(thrd, insn, is_manager(thrd));
-}
-
-/* Start doing req 'idx' of thread 'thrd' */
-static bool _trigger(struct pl330_thread *thrd)
-{
-	void __iomem *regs = thrd->dmac->pinfo->base;
-	struct _pl330_req *req;
-	struct pl330_req *r;
-	struct _arg_GO go;
-	unsigned ns;
-	u8 insn[6] = {0, 0, 0, 0, 0, 0};
-	int idx;
-
-	/* Return if already ACTIVE */
-	if (_state(thrd) != PL330_STATE_STOPPED)
-		return true;
-
-	idx = 1 - thrd->lstenq;
-	if (!IS_FREE(&thrd->req[idx]))
-		req = &thrd->req[idx];
-	else {
-		idx = thrd->lstenq;
-		if (!IS_FREE(&thrd->req[idx]))
-			req = &thrd->req[idx];
-		else
-			req = NULL;
-	}
-
-	/* Return if no request */
-	if (!req || !req->r)
-		return true;
-
-	r = req->r;
-
-	if (r->cfg)
-		ns = r->cfg->nonsecure ? 1 : 0;
-	else if (readl(regs + CS(thrd->id)) & CS_CNS)
-		ns = 1;
-	else
-		ns = 0;
-
-	/* See 'Abort Sources' point-4 at Page 2-25 */
-	if (_manager_ns(thrd) && !ns)
-		dev_info(thrd->dmac->pinfo->dev, "%s:%d Recipe for ABORT!\n",
-			__func__, __LINE__);
-
-	go.chan = thrd->id;
-	go.addr = req->mc_bus;
-	go.ns = ns;
-	_emit_GO(0, insn, &go);
-
-	/* Set to generate interrupts for SEV */
-	writel(readl(regs + INTEN) | (1 << thrd->ev), regs + INTEN);
-
-	/* Only manager can execute GO */
-	_execute_DBGINSN(thrd, insn, true);
-
-	thrd->req_running = idx;
-
-	return true;
-}
-
-static bool _start(struct pl330_thread *thrd)
-{
-	switch (_state(thrd)) {
-	case PL330_STATE_FAULT_COMPLETING:
-		UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING);
-
-		if (_state(thrd) == PL330_STATE_KILLING)
-			UNTIL(thrd, PL330_STATE_STOPPED)
-
-	case PL330_STATE_FAULTING:
-		_stop(thrd);
-
-	case PL330_STATE_KILLING:
-	case PL330_STATE_COMPLETING:
-		UNTIL(thrd, PL330_STATE_STOPPED)
-
-	case PL330_STATE_STOPPED:
-		return _trigger(thrd);
-
-	case PL330_STATE_WFP:
-	case PL330_STATE_QUEUEBUSY:
-	case PL330_STATE_ATBARRIER:
-	case PL330_STATE_UPDTPC:
-	case PL330_STATE_CACHEMISS:
-	case PL330_STATE_EXECUTING:
-		return true;
-
-	case PL330_STATE_WFE: /* For RESUME, nothing yet */
-	default:
-		return false;
-	}
-}
-
-static inline int _ldst_memtomem(unsigned dry_run, u8 buf[],
-		const struct _xfer_spec *pxs, int cyc)
-{
-	int off = 0;
-
-	while (cyc--) {
-		off += _emit_LD(dry_run, &buf[off], ALWAYS);
-		off += _emit_RMB(dry_run, &buf[off]);
-		off += _emit_ST(dry_run, &buf[off], ALWAYS);
-		off += _emit_WMB(dry_run, &buf[off]);
-	}
-
-	return off;
-}
-
-static inline int _ldst_devtomem(unsigned dry_run, u8 buf[],
-		const struct _xfer_spec *pxs, int cyc)
-{
-	int off = 0;
-
-	while (cyc--) {
-		off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->r->peri);
-		off += _emit_LDP(dry_run, &buf[off], SINGLE, pxs->r->peri);
-		off += _emit_ST(dry_run, &buf[off], ALWAYS);
-		off += _emit_FLUSHP(dry_run, &buf[off], pxs->r->peri);
-	}
-
-	return off;
-}
-
-static inline int _ldst_memtodev(unsigned dry_run, u8 buf[],
-		const struct _xfer_spec *pxs, int cyc)
-{
-	int off = 0;
-
-	while (cyc--) {
-		off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->r->peri);
-		off += _emit_LD(dry_run, &buf[off], ALWAYS);
-		off += _emit_STP(dry_run, &buf[off], SINGLE, pxs->r->peri);
-		off += _emit_FLUSHP(dry_run, &buf[off], pxs->r->peri);
-	}
-
-	return off;
-}
-
-static int _bursts(unsigned dry_run, u8 buf[],
-		const struct _xfer_spec *pxs, int cyc)
-{
-	int off = 0;
-
-	switch (pxs->r->rqtype) {
-	case MEMTODEV:
-		off += _ldst_memtodev(dry_run, &buf[off], pxs, cyc);
-		break;
-	case DEVTOMEM:
-		off += _ldst_devtomem(dry_run, &buf[off], pxs, cyc);
-		break;
-	case MEMTOMEM:
-		off += _ldst_memtomem(dry_run, &buf[off], pxs, cyc);
-		break;
-	default:
-		off += 0x40000000; /* Scare off the Client */
-		break;
-	}
-
-	return off;
-}
-
-/* Returns bytes consumed and updates bursts */
-static inline int _loop(unsigned dry_run, u8 buf[],
-		unsigned long *bursts, const struct _xfer_spec *pxs)
-{
-	int cyc, cycmax, szlp, szlpend, szbrst, off;
-	unsigned lcnt0, lcnt1, ljmp0, ljmp1;
-	struct _arg_LPEND lpend;
-
-	/* Max iterations possible in DMALP is 256 */
-	if (*bursts >= 256*256) {
-		lcnt1 = 256;
-		lcnt0 = 256;
-		cyc = *bursts / lcnt1 / lcnt0;
-	} else if (*bursts > 256) {
-		lcnt1 = 256;
-		lcnt0 = *bursts / lcnt1;
-		cyc = 1;
-	} else {
-		lcnt1 = *bursts;
-		lcnt0 = 0;
-		cyc = 1;
-	}
-
-	szlp = _emit_LP(1, buf, 0, 0);
-	szbrst = _bursts(1, buf, pxs, 1);
-
-	lpend.cond = ALWAYS;
-	lpend.forever = false;
-	lpend.loop = 0;
-	lpend.bjump = 0;
-	szlpend = _emit_LPEND(1, buf, &lpend);
-
-	if (lcnt0) {
-		szlp *= 2;
-		szlpend *= 2;
-	}
-
-	/*
-	 * Max bursts that we can unroll due to limit on the
-	 * size of backward jump that can be encoded in DMALPEND
-	 * which is 8-bits and hence 255
-	 */
-	cycmax = (255 - (szlp + szlpend)) / szbrst;
-
-	cyc = (cycmax < cyc) ? cycmax : cyc;
-
-	off = 0;
-
-	if (lcnt0) {
-		off += _emit_LP(dry_run, &buf[off], 0, lcnt0);
-		ljmp0 = off;
-	}
-
-	off += _emit_LP(dry_run, &buf[off], 1, lcnt1);
-	ljmp1 = off;
-
-	off += _bursts(dry_run, &buf[off], pxs, cyc);
-
-	lpend.cond = ALWAYS;
-	lpend.forever = false;
-	lpend.loop = 1;
-	lpend.bjump = off - ljmp1;
-	off += _emit_LPEND(dry_run, &buf[off], &lpend);
-
-	if (lcnt0) {
-		lpend.cond = ALWAYS;
-		lpend.forever = false;
-		lpend.loop = 0;
-		lpend.bjump = off - ljmp0;
-		off += _emit_LPEND(dry_run, &buf[off], &lpend);
-	}
-
-	*bursts = lcnt1 * cyc;
-	if (lcnt0)
-		*bursts *= lcnt0;
-
-	return off;
-}
-
-static inline int _setup_loops(unsigned dry_run, u8 buf[],
-		const struct _xfer_spec *pxs)
-{
-	struct pl330_xfer *x = pxs->x;
-	u32 ccr = pxs->ccr;
-	unsigned long c, bursts = BYTE_TO_BURST(x->bytes, ccr);
-	int off = 0;
-
-	while (bursts) {
-		c = bursts;
-		off += _loop(dry_run, &buf[off], &c, pxs);
-		bursts -= c;
-	}
-
-	return off;
-}
-
-static inline int _setup_xfer(unsigned dry_run, u8 buf[],
-		const struct _xfer_spec *pxs)
-{
-	struct pl330_xfer *x = pxs->x;
-	int off = 0;
-
-	/* DMAMOV SAR, x->src_addr */
-	off += _emit_MOV(dry_run, &buf[off], SAR, x->src_addr);
-	/* DMAMOV DAR, x->dst_addr */
-	off += _emit_MOV(dry_run, &buf[off], DAR, x->dst_addr);
-
-	/* Setup Loop(s) */
-	off += _setup_loops(dry_run, &buf[off], pxs);
-
-	return off;
-}
-
-/*
- * A req is a sequence of one or more xfer units.
- * Returns the number of bytes taken to setup the MC for the req.
- */
-static int _setup_req(unsigned dry_run, struct pl330_thread *thrd,
-		unsigned index, struct _xfer_spec *pxs)
-{
-	struct _pl330_req *req = &thrd->req[index];
-	struct pl330_xfer *x;
-	u8 *buf = req->mc_cpu;
-	int off = 0;
-
-	PL330_DBGMC_START(req->mc_bus);
-
-	/* DMAMOV CCR, ccr */
-	off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr);
-
-	x = pxs->r->x;
-	do {
-		/* Error if xfer length is not aligned at burst size */
-		if (x->bytes % (BRST_SIZE(pxs->ccr) * BRST_LEN(pxs->ccr)))
-			return -EINVAL;
-
-		pxs->x = x;
-		off += _setup_xfer(dry_run, &buf[off], pxs);
-
-		x = x->next;
-	} while (x);
-
-	/* DMASEV peripheral/event */
-	off += _emit_SEV(dry_run, &buf[off], thrd->ev);
-	/* DMAEND */
-	off += _emit_END(dry_run, &buf[off]);
-
-	return off;
-}
-
-static inline u32 _prepare_ccr(const struct pl330_reqcfg *rqc)
-{
-	u32 ccr = 0;
-
-	if (rqc->src_inc)
-		ccr |= CC_SRCINC;
-
-	if (rqc->dst_inc)
-		ccr |= CC_DSTINC;
-
-	/* We set same protection levels for Src and DST for now */
-	if (rqc->privileged)
-		ccr |= CC_SRCPRI | CC_DSTPRI;
-	if (rqc->nonsecure)
-		ccr |= CC_SRCNS | CC_DSTNS;
-	if (rqc->insnaccess)
-		ccr |= CC_SRCIA | CC_DSTIA;
-
-	ccr |= (((rqc->brst_len - 1) & 0xf) << CC_SRCBRSTLEN_SHFT);
-	ccr |= (((rqc->brst_len - 1) & 0xf) << CC_DSTBRSTLEN_SHFT);
-
-	ccr |= (rqc->brst_size << CC_SRCBRSTSIZE_SHFT);
-	ccr |= (rqc->brst_size << CC_DSTBRSTSIZE_SHFT);
-
-	ccr |= (rqc->scctl << CC_SRCCCTRL_SHFT);
-	ccr |= (rqc->dcctl << CC_DSTCCTRL_SHFT);
-
-	ccr |= (rqc->swap << CC_SWAP_SHFT);
-
-	return ccr;
-}
-
-static inline bool _is_valid(u32 ccr)
-{
-	enum pl330_dstcachectrl dcctl;
-	enum pl330_srccachectrl scctl;
-
-	dcctl = (ccr >> CC_DSTCCTRL_SHFT) & CC_DRCCCTRL_MASK;
-	scctl = (ccr >> CC_SRCCCTRL_SHFT) & CC_SRCCCTRL_MASK;
-
-	if (dcctl == DINVALID1 || dcctl == DINVALID2
-			|| scctl == SINVALID1 || scctl == SINVALID2)
-		return false;
-	else
-		return true;
-}
-
-/*
- * Submit a list of xfers after which the client wants notification.
- * Client is not notified after each xfer unit, just once after all
- * xfer units are done or some error occurs.
- */
-int pl330_submit_req(void *ch_id, struct pl330_req *r)
-{
-	struct pl330_thread *thrd = ch_id;
-	struct pl330_dmac *pl330;
-	struct pl330_info *pi;
-	struct _xfer_spec xs;
-	unsigned long flags;
-	void __iomem *regs;
-	unsigned idx;
-	u32 ccr;
-	int ret = 0;
-
-	/* No Req or Unacquired Channel or DMAC */
-	if (!r || !thrd || thrd->free)
-		return -EINVAL;
-
-	pl330 = thrd->dmac;
-	pi = pl330->pinfo;
-	regs = pi->base;
-
-	if (pl330->state == DYING
-		|| pl330->dmac_tbd.reset_chan & (1 << thrd->id)) {
-		dev_info(thrd->dmac->pinfo->dev, "%s:%d\n",
-			__func__, __LINE__);
-		return -EAGAIN;
-	}
-
-	/* If request for non-existing peripheral */
-	if (r->rqtype != MEMTOMEM && r->peri >= pi->pcfg.num_peri) {
-		dev_info(thrd->dmac->pinfo->dev,
-				"%s:%d Invalid peripheral(%u)!\n",
-				__func__, __LINE__, r->peri);
-		return -EINVAL;
-	}
-
-	spin_lock_irqsave(&pl330->lock, flags);
-
-	if (_queue_full(thrd)) {
-		ret = -EAGAIN;
-		goto xfer_exit;
-	}
-
-	/* Prefer Secure Channel */
-	if (!_manager_ns(thrd))
-		r->cfg->nonsecure = 0;
-	else
-		r->cfg->nonsecure = 1;
-
-	/* Use last settings, if not provided */
-	if (r->cfg)
-		ccr = _prepare_ccr(r->cfg);
-	else
-		ccr = readl(regs + CC(thrd->id));
-
-	/* If this req doesn't have valid xfer settings */
-	if (!_is_valid(ccr)) {
-		ret = -EINVAL;
-		dev_info(thrd->dmac->pinfo->dev, "%s:%d Invalid CCR(%x)!\n",
-			__func__, __LINE__, ccr);
-		goto xfer_exit;
-	}
-
-	idx = IS_FREE(&thrd->req[0]) ? 0 : 1;
-
-	xs.ccr = ccr;
-	xs.r = r;
-
-	/* First dry run to check if req is acceptable */
-	ret = _setup_req(1, thrd, idx, &xs);
-	if (ret < 0)
-		goto xfer_exit;
-
-	if (ret > pi->mcbufsz / 2) {
-		dev_info(thrd->dmac->pinfo->dev,
-			"%s:%d Trying increasing mcbufsz\n",
-				__func__, __LINE__);
-		ret = -ENOMEM;
-		goto xfer_exit;
-	}
-
-	/* Hook the request */
-	thrd->lstenq = idx;
-	thrd->req[idx].mc_len = _setup_req(0, thrd, idx, &xs);
-	thrd->req[idx].r = r;
-
-	ret = 0;
-
-xfer_exit:
-	spin_unlock_irqrestore(&pl330->lock, flags);
-
-	return ret;
-}
-EXPORT_SYMBOL(pl330_submit_req);
-
-static void pl330_dotask(unsigned long data)
-{
-	struct pl330_dmac *pl330 = (struct pl330_dmac *) data;
-	struct pl330_info *pi = pl330->pinfo;
-	unsigned long flags;
-	int i;
-
-	spin_lock_irqsave(&pl330->lock, flags);
-
-	/* The DMAC itself gone nuts */
-	if (pl330->dmac_tbd.reset_dmac) {
-		pl330->state = DYING;
-		/* Reset the manager too */
-		pl330->dmac_tbd.reset_mngr = true;
-		/* Clear the reset flag */
-		pl330->dmac_tbd.reset_dmac = false;
-	}
-
-	if (pl330->dmac_tbd.reset_mngr) {
-		_stop(pl330->manager);
-		/* Reset all channels */
-		pl330->dmac_tbd.reset_chan = (1 << pi->pcfg.num_chan) - 1;
-		/* Clear the reset flag */
-		pl330->dmac_tbd.reset_mngr = false;
-	}
-
-	for (i = 0; i < pi->pcfg.num_chan; i++) {
-
-		if (pl330->dmac_tbd.reset_chan & (1 << i)) {
-			struct pl330_thread *thrd = &pl330->channels[i];
-			void __iomem *regs = pi->base;
-			enum pl330_op_err err;
-
-			_stop(thrd);
-
-			if (readl(regs + FSC) & (1 << thrd->id))
-				err = PL330_ERR_FAIL;
-			else
-				err = PL330_ERR_ABORT;
-
-			spin_unlock_irqrestore(&pl330->lock, flags);
-
-			_callback(thrd->req[1 - thrd->lstenq].r, err);
-			_callback(thrd->req[thrd->lstenq].r, err);
-
-			spin_lock_irqsave(&pl330->lock, flags);
-
-			thrd->req[0].r = NULL;
-			thrd->req[1].r = NULL;
-			mark_free(thrd, 0);
-			mark_free(thrd, 1);
-
-			/* Clear the reset flag */
-			pl330->dmac_tbd.reset_chan &= ~(1 << i);
-		}
-	}
-
-	spin_unlock_irqrestore(&pl330->lock, flags);
-
-	return;
-}
-
-/* Returns 1 if state was updated, 0 otherwise */
-int pl330_update(const struct pl330_info *pi)
-{
-	struct _pl330_req *rqdone;
-	struct pl330_dmac *pl330;
-	unsigned long flags;
-	void __iomem *regs;
-	u32 val;
-	int id, ev, ret = 0;
-
-	if (!pi || !pi->pl330_data)
-		return 0;
-
-	regs = pi->base;
-	pl330 = pi->pl330_data;
-
-	spin_lock_irqsave(&pl330->lock, flags);
-
-	val = readl(regs + FSM) & 0x1;
-	if (val)
-		pl330->dmac_tbd.reset_mngr = true;
-	else
-		pl330->dmac_tbd.reset_mngr = false;
-
-	val = readl(regs + FSC) & ((1 << pi->pcfg.num_chan) - 1);
-	pl330->dmac_tbd.reset_chan |= val;
-	if (val) {
-		int i = 0;
-		while (i < pi->pcfg.num_chan) {
-			if (val & (1 << i)) {
-				dev_info(pi->dev,
-					"Reset Channel-%d\t CS-%x FTC-%x\n",
-						i, readl(regs + CS(i)),
-						readl(regs + FTC(i)));
-				_stop(&pl330->channels[i]);
-			}
-			i++;
-		}
-	}
-
-	/* Check which event happened i.e, thread notified */
-	val = readl(regs + ES);
-	if (pi->pcfg.num_events < 32
-			&& val & ~((1 << pi->pcfg.num_events) - 1)) {
-		pl330->dmac_tbd.reset_dmac = true;
-		dev_err(pi->dev, "%s:%d Unexpected!\n", __func__, __LINE__);
-		ret = 1;
-		goto updt_exit;
-	}
-
-	for (ev = 0; ev < pi->pcfg.num_events; ev++) {
-		if (val & (1 << ev)) { /* Event occurred */
-			struct pl330_thread *thrd;
-			u32 inten = readl(regs + INTEN);
-			int active;
-
-			/* Clear the event */
-			if (inten & (1 << ev))
-				writel(1 << ev, regs + INTCLR);
-
-			ret = 1;
-
-			id = pl330->events[ev];
-
-			thrd = &pl330->channels[id];
-
-			active = thrd->req_running;
-			if (active == -1) /* Aborted */
-				continue;
-
-			rqdone = &thrd->req[active];
-			mark_free(thrd, active);
-
-			/* Get going again ASAP */
-			_start(thrd);
-
-			/* For now, just make a list of callbacks to be done */
-			list_add_tail(&rqdone->rqd, &pl330->req_done);
-		}
-	}
-
-	/* Now that we are in no hurry, do the callbacks */
-	while (!list_empty(&pl330->req_done)) {
-		struct pl330_req *r;
-
-		rqdone = container_of(pl330->req_done.next,
-					struct _pl330_req, rqd);
-
-		list_del_init(&rqdone->rqd);
-
-		/* Detach the req */
-		r = rqdone->r;
-		rqdone->r = NULL;
-
-		spin_unlock_irqrestore(&pl330->lock, flags);
-		_callback(r, PL330_ERR_NONE);
-		spin_lock_irqsave(&pl330->lock, flags);
-	}
-
-updt_exit:
-	spin_unlock_irqrestore(&pl330->lock, flags);
-
-	if (pl330->dmac_tbd.reset_dmac
-			|| pl330->dmac_tbd.reset_mngr
-			|| pl330->dmac_tbd.reset_chan) {
-		ret = 1;
-		tasklet_schedule(&pl330->tasks);
-	}
-
-	return ret;
-}
-EXPORT_SYMBOL(pl330_update);
-
-int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op)
-{
-	struct pl330_thread *thrd = ch_id;
-	struct pl330_dmac *pl330;
-	unsigned long flags;
-	int ret = 0, active;
-
-	if (!thrd || thrd->free || thrd->dmac->state == DYING)
-		return -EINVAL;
-
-	pl330 = thrd->dmac;
-	active = thrd->req_running;
-
-	spin_lock_irqsave(&pl330->lock, flags);
-
-	switch (op) {
-	case PL330_OP_FLUSH:
-		/* Make sure the channel is stopped */
-		_stop(thrd);
-
-		thrd->req[0].r = NULL;
-		thrd->req[1].r = NULL;
-		mark_free(thrd, 0);
-		mark_free(thrd, 1);
-		break;
-
-	case PL330_OP_ABORT:
-		/* Make sure the channel is stopped */
-		_stop(thrd);
-
-		/* ABORT is only for the active req */
-		if (active == -1)
-			break;
-
-		thrd->req[active].r = NULL;
-		mark_free(thrd, active);
-
-		/* Start the next */
-	case PL330_OP_START:
-		if ((active == -1) && !_start(thrd))
-			ret = -EIO;
-		break;
-
-	default:
-		ret = -EINVAL;
-	}
-
-	spin_unlock_irqrestore(&pl330->lock, flags);
-	return ret;
-}
-EXPORT_SYMBOL(pl330_chan_ctrl);
-
-int pl330_chan_status(void *ch_id, struct pl330_chanstatus *pstatus)
-{
-	struct pl330_thread *thrd = ch_id;
-	struct pl330_dmac *pl330;
-	struct pl330_info *pi;
-	void __iomem *regs;
-	int active;
-	u32 val;
-
-	if (!pstatus || !thrd || thrd->free)
-		return -EINVAL;
-
-	pl330 = thrd->dmac;
-	pi = pl330->pinfo;
-	regs = pi->base;
-
-	/* The client should remove the DMAC and add again */
-	if (pl330->state == DYING)
-		pstatus->dmac_halted = true;
-	else
-		pstatus->dmac_halted = false;
-
-	val = readl(regs + FSC);
-	if (val & (1 << thrd->id))
-		pstatus->faulting = true;
-	else
-		pstatus->faulting = false;
-
-	active = thrd->req_running;
-
-	if (active == -1) {
-		/* Indicate that the thread is not running */
-		pstatus->top_req = NULL;
-		pstatus->wait_req = NULL;
-	} else {
-		pstatus->top_req = thrd->req[active].r;
-		pstatus->wait_req = !IS_FREE(&thrd->req[1 - active])
-					? thrd->req[1 - active].r : NULL;
-	}
-
-	pstatus->src_addr = readl(regs + SA(thrd->id));
-	pstatus->dst_addr = readl(regs + DA(thrd->id));
-
-	return 0;
-}
-EXPORT_SYMBOL(pl330_chan_status);
-
-/* Reserve an event */
-static inline int _alloc_event(struct pl330_thread *thrd)
-{
-	struct pl330_dmac *pl330 = thrd->dmac;
-	struct pl330_info *pi = pl330->pinfo;
-	int ev;
-
-	for (ev = 0; ev < pi->pcfg.num_events; ev++)
-		if (pl330->events[ev] == -1) {
-			pl330->events[ev] = thrd->id;
-			return ev;
-		}
-
-	return -1;
-}
-
-static bool _chan_ns(const struct pl330_info *pi, int i)
-{
-	return pi->pcfg.irq_ns & (1 << i);
-}
-
-/* Upon success, returns IdentityToken for the
- * allocated channel, NULL otherwise.
- */
-void *pl330_request_channel(const struct pl330_info *pi)
-{
-	struct pl330_thread *thrd = NULL;
-	struct pl330_dmac *pl330;
-	unsigned long flags;
-	int chans, i;
-
-	if (!pi || !pi->pl330_data)
-		return NULL;
-
-	pl330 = pi->pl330_data;
-
-	if (pl330->state == DYING)
-		return NULL;
-
-	chans = pi->pcfg.num_chan;
-
-	spin_lock_irqsave(&pl330->lock, flags);
-
-	for (i = 0; i < chans; i++) {
-		thrd = &pl330->channels[i];
-		if ((thrd->free) && (!_manager_ns(thrd) ||
-					_chan_ns(pi, i))) {
-			thrd->ev = _alloc_event(thrd);
-			if (thrd->ev >= 0) {
-				thrd->free = false;
-				thrd->lstenq = 1;
-				thrd->req[0].r = NULL;
-				mark_free(thrd, 0);
-				thrd->req[1].r = NULL;
-				mark_free(thrd, 1);
-				break;
-			}
-		}
-		thrd = NULL;
-	}
-
-	spin_unlock_irqrestore(&pl330->lock, flags);
-
-	return thrd;
-}
-EXPORT_SYMBOL(pl330_request_channel);
-
-/* Release an event */
-static inline void _free_event(struct pl330_thread *thrd, int ev)
-{
-	struct pl330_dmac *pl330 = thrd->dmac;
-	struct pl330_info *pi = pl330->pinfo;
-
-	/* If the event is valid and was held by the thread */
-	if (ev >= 0 && ev < pi->pcfg.num_events
-			&& pl330->events[ev] == thrd->id)
-		pl330->events[ev] = -1;
-}
-
-void pl330_release_channel(void *ch_id)
-{
-	struct pl330_thread *thrd = ch_id;
-	struct pl330_dmac *pl330;
-	unsigned long flags;
-
-	if (!thrd || thrd->free)
-		return;
-
-	_stop(thrd);
-
-	_callback(thrd->req[1 - thrd->lstenq].r, PL330_ERR_ABORT);
-	_callback(thrd->req[thrd->lstenq].r, PL330_ERR_ABORT);
-
-	pl330 = thrd->dmac;
-
-	spin_lock_irqsave(&pl330->lock, flags);
-	_free_event(thrd, thrd->ev);
-	thrd->free = true;
-	spin_unlock_irqrestore(&pl330->lock, flags);
-}
-EXPORT_SYMBOL(pl330_release_channel);
-
-/* Initialize the structure for PL330 configuration, that can be used
- * by the client driver the make best use of the DMAC
- */
-static void read_dmac_config(struct pl330_info *pi)
-{
-	void __iomem *regs = pi->base;
-	u32 val;
-
-	val = readl(regs + CRD) >> CRD_DATA_WIDTH_SHIFT;
-	val &= CRD_DATA_WIDTH_MASK;
-	pi->pcfg.data_bus_width = 8 * (1 << val);
-
-	val = readl(regs + CRD) >> CRD_DATA_BUFF_SHIFT;
-	val &= CRD_DATA_BUFF_MASK;
-	pi->pcfg.data_buf_dep = val + 1;
-
-	val = readl(regs + CR0) >> CR0_NUM_CHANS_SHIFT;
-	val &= CR0_NUM_CHANS_MASK;
-	val += 1;
-	pi->pcfg.num_chan = val;
-
-	val = readl(regs + CR0);
-	if (val & CR0_PERIPH_REQ_SET) {
-		val = (val >> CR0_NUM_PERIPH_SHIFT) & CR0_NUM_PERIPH_MASK;
-		val += 1;
-		pi->pcfg.num_peri = val;
-		pi->pcfg.peri_ns = readl(regs + CR4);
-	} else {
-		pi->pcfg.num_peri = 0;
-	}
-
-	val = readl(regs + CR0);
-	if (val & CR0_BOOT_MAN_NS)
-		pi->pcfg.mode |= DMAC_MODE_NS;
-	else
-		pi->pcfg.mode &= ~DMAC_MODE_NS;
-
-	val = readl(regs + CR0) >> CR0_NUM_EVENTS_SHIFT;
-	val &= CR0_NUM_EVENTS_MASK;
-	val += 1;
-	pi->pcfg.num_events = val;
-
-	pi->pcfg.irq_ns = readl(regs + CR3);
-
-	pi->pcfg.periph_id = get_id(pi, PERIPH_ID);
-	pi->pcfg.pcell_id = get_id(pi, PCELL_ID);
-}
-
-static inline void _reset_thread(struct pl330_thread *thrd)
-{
-	struct pl330_dmac *pl330 = thrd->dmac;
-	struct pl330_info *pi = pl330->pinfo;
-
-	thrd->req[0].mc_cpu = pl330->mcode_cpu
-				+ (thrd->id * pi->mcbufsz);
-	thrd->req[0].mc_bus = pl330->mcode_bus
-				+ (thrd->id * pi->mcbufsz);
-	thrd->req[0].r = NULL;
-	mark_free(thrd, 0);
-
-	thrd->req[1].mc_cpu = thrd->req[0].mc_cpu
-				+ pi->mcbufsz / 2;
-	thrd->req[1].mc_bus = thrd->req[0].mc_bus
-				+ pi->mcbufsz / 2;
-	thrd->req[1].r = NULL;
-	mark_free(thrd, 1);
-}
-
-static int dmac_alloc_threads(struct pl330_dmac *pl330)
-{
-	struct pl330_info *pi = pl330->pinfo;
-	int chans = pi->pcfg.num_chan;
-	struct pl330_thread *thrd;
-	int i;
-
-	/* Allocate 1 Manager and 'chans' Channel threads */
-	pl330->channels = kzalloc((1 + chans) * sizeof(*thrd),
-					GFP_KERNEL);
-	if (!pl330->channels)
-		return -ENOMEM;
-
-	/* Init Channel threads */
-	for (i = 0; i < chans; i++) {
-		thrd = &pl330->channels[i];
-		thrd->id = i;
-		thrd->dmac = pl330;
-		_reset_thread(thrd);
-		thrd->free = true;
-	}
-
-	/* MANAGER is indexed at the end */
-	thrd = &pl330->channels[chans];
-	thrd->id = chans;
-	thrd->dmac = pl330;
-	thrd->free = false;
-	pl330->manager = thrd;
-
-	return 0;
-}
-
-static int dmac_alloc_resources(struct pl330_dmac *pl330)
-{
-	struct pl330_info *pi = pl330->pinfo;
-	int chans = pi->pcfg.num_chan;
-	int ret;
-
-	/*
-	 * Alloc MicroCode buffer for 'chans' Channel threads.
-	 * A channel's buffer offset is (Channel_Id * MCODE_BUFF_PERCHAN)
-	 */
-	pl330->mcode_cpu = dma_alloc_coherent(pi->dev,
-				chans * pi->mcbufsz,
-				&pl330->mcode_bus, GFP_KERNEL);
-	if (!pl330->mcode_cpu) {
-		dev_err(pi->dev, "%s:%d Can't allocate memory!\n",
-			__func__, __LINE__);
-		return -ENOMEM;
-	}
-
-	ret = dmac_alloc_threads(pl330);
-	if (ret) {
-		dev_err(pi->dev, "%s:%d Can't to create channels for DMAC!\n",
-			__func__, __LINE__);
-		dma_free_coherent(pi->dev,
-				chans * pi->mcbufsz,
-				pl330->mcode_cpu, pl330->mcode_bus);
-		return ret;
-	}
-
-	return 0;
-}
-
-int pl330_add(struct pl330_info *pi)
-{
-	struct pl330_dmac *pl330;
-	void __iomem *regs;
-	int i, ret;
-
-	if (!pi || !pi->dev)
-		return -EINVAL;
-
-	/* If already added */
-	if (pi->pl330_data)
-		return -EINVAL;
-
-	/*
-	 * If the SoC can perform reset on the DMAC, then do it
-	 * before reading its configuration.
-	 */
-	if (pi->dmac_reset)
-		pi->dmac_reset(pi);
-
-	regs = pi->base;
-
-	/* Check if we can handle this DMAC */
-	if ((get_id(pi, PERIPH_ID) & 0xfffff) != PERIPH_ID_VAL
-	   || get_id(pi, PCELL_ID) != PCELL_ID_VAL) {
-		dev_err(pi->dev, "PERIPH_ID 0x%x, PCELL_ID 0x%x !\n",
-			get_id(pi, PERIPH_ID), get_id(pi, PCELL_ID));
-		return -EINVAL;
-	}
-
-	/* Read the configuration of the DMAC */
-	read_dmac_config(pi);
-
-	if (pi->pcfg.num_events == 0) {
-		dev_err(pi->dev, "%s:%d Can't work without events!\n",
-			__func__, __LINE__);
-		return -EINVAL;
-	}
-
-	pl330 = kzalloc(sizeof(*pl330), GFP_KERNEL);
-	if (!pl330) {
-		dev_err(pi->dev, "%s:%d Can't allocate memory!\n",
-			__func__, __LINE__);
-		return -ENOMEM;
-	}
-
-	/* Assign the info structure and private data */
-	pl330->pinfo = pi;
-	pi->pl330_data = pl330;
-
-	spin_lock_init(&pl330->lock);
-
-	INIT_LIST_HEAD(&pl330->req_done);
-
-	/* Use default MC buffer size if not provided */
-	if (!pi->mcbufsz)
-		pi->mcbufsz = MCODE_BUFF_PER_REQ * 2;
-
-	/* Mark all events as free */
-	for (i = 0; i < pi->pcfg.num_events; i++)
-		pl330->events[i] = -1;
-
-	/* Allocate resources needed by the DMAC */
-	ret = dmac_alloc_resources(pl330);
-	if (ret) {
-		dev_err(pi->dev, "Unable to create channels for DMAC\n");
-		kfree(pl330);
-		return ret;
-	}
-
-	tasklet_init(&pl330->tasks, pl330_dotask, (unsigned long) pl330);
-
-	pl330->state = INIT;
-
-	return 0;
-}
-EXPORT_SYMBOL(pl330_add);
-
-static int dmac_free_threads(struct pl330_dmac *pl330)
-{
-	struct pl330_info *pi = pl330->pinfo;
-	int chans = pi->pcfg.num_chan;
-	struct pl330_thread *thrd;
-	int i;
-
-	/* Release Channel threads */
-	for (i = 0; i < chans; i++) {
-		thrd = &pl330->channels[i];
-		pl330_release_channel((void *)thrd);
-	}
-
-	/* Free memory */
-	kfree(pl330->channels);
-
-	return 0;
-}
-
-static void dmac_free_resources(struct pl330_dmac *pl330)
-{
-	struct pl330_info *pi = pl330->pinfo;
-	int chans = pi->pcfg.num_chan;
-
-	dmac_free_threads(pl330);
-
-	dma_free_coherent(pi->dev, chans * pi->mcbufsz,
-				pl330->mcode_cpu, pl330->mcode_bus);
-}
-
-void pl330_del(struct pl330_info *pi)
-{
-	struct pl330_dmac *pl330;
-
-	if (!pi || !pi->pl330_data)
-		return;
-
-	pl330 = pi->pl330_data;
-
-	pl330->state = UNINIT;
-
-	tasklet_kill(&pl330->tasks);
-
-	/* Free DMAC resources */
-	dmac_free_resources(pl330);
-
-	kfree(pl330);
-	pi->pl330_data = NULL;
-}
-EXPORT_SYMBOL(pl330_del);
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 61691cd..9173d11 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -16,6 +16,7 @@
  */
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -28,9 +29,8 @@
 #include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
 #include <asm/mach/irq.h>
+#include <asm/mach-types.h>
 #include <asm/sizes.h>
 
 #include <asm/hardware/sa1111.h>
@@ -86,8 +86,10 @@
 #define IRQ_S1_CD_VALID		(52)
 #define IRQ_S0_BVD1_STSCHG	(53)
 #define IRQ_S1_BVD1_STSCHG	(54)
+#define SA1111_IRQ_NR		(55)
 
-extern void __init sa1110_mb_enable(void);
+extern void sa1110_mb_enable(void);
+extern void sa1110_mb_disable(void);
 
 /*
  * We keep the following data for the overall SA1111.  Note that the
@@ -104,6 +106,7 @@
 	int		irq_base;	/* base for cascaded on-chip IRQs */
 	spinlock_t	lock;
 	void __iomem	*base;
+	struct sa1111_platform_data *pdata;
 #ifdef CONFIG_PM
 	void		*saved_state;
 #endif
@@ -118,6 +121,7 @@
 struct sa1111_dev_info {
 	unsigned long	offset;
 	unsigned long	skpcr_mask;
+	bool		dma;
 	unsigned int	devid;
 	unsigned int	irq[6];
 };
@@ -126,6 +130,7 @@
 	{
 		.offset		= SA1111_USB,
 		.skpcr_mask	= SKPCR_UCLKEN,
+		.dma		= true,
 		.devid		= SA1111_DEVID_USB,
 		.irq = {
 			IRQ_USBPWR,
@@ -139,6 +144,7 @@
 	{
 		.offset		= 0x0600,
 		.skpcr_mask	= SKPCR_I2SCLKEN | SKPCR_L3CLKEN,
+		.dma		= true,
 		.devid		= SA1111_DEVID_SAC,
 		.irq = {
 			AUDXMTDMADONEA,
@@ -155,7 +161,7 @@
 	{
 		.offset		= SA1111_KBD,
 		.skpcr_mask	= SKPCR_PTCLKEN,
-		.devid		= SA1111_DEVID_PS2,
+		.devid		= SA1111_DEVID_PS2_KBD,
 		.irq = {
 			IRQ_TPRXINT,
 			IRQ_TPTXINT
@@ -164,7 +170,7 @@
 	{
 		.offset		= SA1111_MSE,
 		.skpcr_mask	= SKPCR_PMCLKEN,
-		.devid		= SA1111_DEVID_PS2,
+		.devid		= SA1111_DEVID_PS2_MSE,
 		.irq = {
 			IRQ_MSRXINT,
 			IRQ_MSTXINT
@@ -434,16 +440,28 @@
 	.irq_set_wake	= sa1111_wake_highirq,
 };
 
-static void sa1111_setup_irq(struct sa1111 *sachip)
+static int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base)
 {
 	void __iomem *irqbase = sachip->base + SA1111_INTC;
-	unsigned int irq;
+	unsigned i, irq;
+	int ret;
 
 	/*
 	 * We're guaranteed that this region hasn't been taken.
 	 */
 	request_mem_region(sachip->phys + SA1111_INTC, 512, "irq");
 
+	ret = irq_alloc_descs(-1, irq_base, SA1111_IRQ_NR, -1);
+	if (ret <= 0) {
+		dev_err(sachip->dev, "unable to allocate %u irqs: %d\n",
+			SA1111_IRQ_NR, ret);
+		if (ret == 0)
+			ret = -EINVAL;
+		return ret;
+	}
+
+	sachip->irq_base = ret;
+
 	/* disable all IRQs */
 	sa1111_writel(0, irqbase + SA1111_INTEN0);
 	sa1111_writel(0, irqbase + SA1111_INTEN1);
@@ -463,14 +481,16 @@
 	sa1111_writel(~0, irqbase + SA1111_INTSTATCLR0);
 	sa1111_writel(~0, irqbase + SA1111_INTSTATCLR1);
 
-	for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) {
+	for (i = IRQ_GPAIN0; i <= SSPROR; i++) {
+		irq = sachip->irq_base + i;
 		irq_set_chip_and_handler(irq, &sa1111_low_chip,
 					 handle_edge_irq);
 		irq_set_chip_data(irq, sachip);
 		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
 
-	for (irq = AUDXMTDMADONEA; irq <= IRQ_S1_BVD1_STSCHG; irq++) {
+	for (i = AUDXMTDMADONEA; i <= IRQ_S1_BVD1_STSCHG; i++) {
+		irq = sachip->irq_base + i;
 		irq_set_chip_and_handler(irq, &sa1111_high_chip,
 					 handle_edge_irq);
 		irq_set_chip_data(irq, sachip);
@@ -483,6 +503,11 @@
 	irq_set_irq_type(sachip->irq, IRQ_TYPE_EDGE_RISING);
 	irq_set_handler_data(sachip->irq, sachip);
 	irq_set_chained_handler(sachip->irq, sa1111_irq_handler);
+
+	dev_info(sachip->dev, "Providing IRQ%u-%u\n",
+		sachip->irq_base, sachip->irq_base + SA1111_IRQ_NR - 1);
+
+	return 0;
 }
 
 /*
@@ -581,41 +606,10 @@
 }
 #endif
 
-#ifdef CONFIG_DMABOUNCE
-/*
- * According to the "Intel StrongARM SA-1111 Microprocessor Companion
- * Chip Specification Update" (June 2000), erratum #7, there is a
- * significant bug in the SA1111 SDRAM shared memory controller.  If
- * an access to a region of memory above 1MB relative to the bank base,
- * it is important that address bit 10 _NOT_ be asserted. Depending
- * on the configuration of the RAM, bit 10 may correspond to one
- * of several different (processor-relative) address bits.
- *
- * This routine only identifies whether or not a given DMA address
- * is susceptible to the bug.
- *
- * This should only get called for sa1111_device types due to the
- * way we configure our device dma_masks.
- */
-static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
-{
-	/*
-	 * Section 4.6 of the "Intel StrongARM SA-1111 Development Module
-	 * User's Guide" mentions that jumpers R51 and R52 control the
-	 * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
-	 * SDRAM bank 1 on Neponset). The default configuration selects
-	 * Assabet, so any address in bank 1 is necessarily invalid.
-	 */
-	return (machine_is_assabet() || machine_is_pfs168()) &&
-		(addr >= 0xc8000000 || (addr + size) >= 0xc8000000);
-}
-#endif
-
 static void sa1111_dev_release(struct device *_dev)
 {
 	struct sa1111_dev *dev = SA1111_DEV(_dev);
 
-	release_resource(&dev->res);
 	kfree(dev);
 }
 
@@ -624,67 +618,58 @@
 		      struct sa1111_dev_info *info)
 {
 	struct sa1111_dev *dev;
+	unsigned i;
 	int ret;
 
 	dev = kzalloc(sizeof(struct sa1111_dev), GFP_KERNEL);
 	if (!dev) {
 		ret = -ENOMEM;
-		goto out;
+		goto err_alloc;
 	}
 
+	device_initialize(&dev->dev);
 	dev_set_name(&dev->dev, "%4.4lx", info->offset);
 	dev->devid	 = info->devid;
 	dev->dev.parent  = sachip->dev;
 	dev->dev.bus     = &sa1111_bus_type;
 	dev->dev.release = sa1111_dev_release;
-	dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask;
 	dev->res.start   = sachip->phys + info->offset;
 	dev->res.end     = dev->res.start + 511;
 	dev->res.name    = dev_name(&dev->dev);
 	dev->res.flags   = IORESOURCE_MEM;
 	dev->mapbase     = sachip->base + info->offset;
 	dev->skpcr_mask  = info->skpcr_mask;
-	memmove(dev->irq, info->irq, sizeof(dev->irq));
+
+	for (i = 0; i < ARRAY_SIZE(info->irq); i++)
+		dev->irq[i] = sachip->irq_base + info->irq[i];
+
+	/*
+	 * If the parent device has a DMA mask associated with it, and
+	 * this child supports DMA, propagate it down to the children.
+	 */
+	if (info->dma && sachip->dev->dma_mask) {
+		dev->dma_mask = *sachip->dev->dma_mask;
+		dev->dev.dma_mask = &dev->dma_mask;
+		dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask;
+	}
 
 	ret = request_resource(parent, &dev->res);
 	if (ret) {
-		printk("SA1111: failed to allocate resource for %s\n",
+		dev_err(sachip->dev, "failed to allocate resource for %s\n",
 			dev->res.name);
-		dev_set_name(&dev->dev, NULL);
-		kfree(dev);
-		goto out;
+		goto err_resource;
 	}
 
+	ret = device_add(&dev->dev);
+	if (ret)
+		goto err_add;
+	return 0;
 
-	ret = device_register(&dev->dev);
-	if (ret) {
-		release_resource(&dev->res);
-		kfree(dev);
-		goto out;
-	}
-
-#ifdef CONFIG_DMABOUNCE
-	/*
-	 * If the parent device has a DMA mask associated with it,
-	 * propagate it down to the children.
-	 */
-	if (sachip->dev->dma_mask) {
-		dev->dma_mask = *sachip->dev->dma_mask;
-		dev->dev.dma_mask = &dev->dma_mask;
-
-		if (dev->dma_mask != 0xffffffffUL) {
-			ret = dmabounce_register_dev(&dev->dev, 1024, 4096,
-					sa1111_needs_bounce);
-			if (ret) {
-				dev_err(&dev->dev, "SA1111: Failed to register"
-					" with dmabounce\n");
-				device_unregister(&dev->dev);
-			}
-		}
-	}
-#endif
-
-out:
+ err_add:
+	release_resource(&dev->res);
+ err_resource:
+	put_device(&dev->dev);
+ err_alloc:
 	return ret;
 }
 
@@ -698,16 +683,21 @@
  *	Returns:
  *	%-ENODEV	device not found.
  *	%-EBUSY		physical address already marked in-use.
+ *	%-EINVAL	no platform data passed
  *	%0		successful.
  */
 static int __devinit
 __sa1111_probe(struct device *me, struct resource *mem, int irq)
 {
+	struct sa1111_platform_data *pd = me->platform_data;
 	struct sa1111 *sachip;
 	unsigned long id;
 	unsigned int has_devs;
 	int i, ret = -ENODEV;
 
+	if (!pd)
+		return -EINVAL;
+
 	sachip = kzalloc(sizeof(struct sa1111), GFP_KERNEL);
 	if (!sachip)
 		return -ENOMEM;
@@ -727,6 +717,7 @@
 	sachip->dev = me;
 	dev_set_drvdata(sachip->dev, sachip);
 
+	sachip->pdata = pd;
 	sachip->phys = mem->start;
 	sachip->irq = irq;
 
@@ -759,6 +750,16 @@
 	 */
 	sa1111_wake(sachip);
 
+	/*
+	 * The interrupt controller must be initialised before any
+	 * other device to ensure that the interrupts are available.
+	 */
+	if (sachip->irq != NO_IRQ) {
+		ret = sa1111_setup_irq(sachip, pd->irq_base);
+		if (ret)
+			goto err_unmap;
+	}
+
 #ifdef CONFIG_ARCH_SA1100
 	{
 	unsigned int val;
@@ -789,24 +790,14 @@
 	}
 #endif
 
-	/*
-	 * The interrupt controller must be initialised before any
-	 * other device to ensure that the interrupts are available.
-	 */
-	if (sachip->irq != NO_IRQ)
-		sa1111_setup_irq(sachip);
-
 	g_sa1111 = sachip;
 
 	has_devs = ~0;
-	if (machine_is_assabet() || machine_is_jornada720() ||
-	    machine_is_badge4())
-		has_devs &= ~(1 << 4);
-	else
-		has_devs &= ~(1 << 1);
+	if (pd)
+		has_devs &= ~pd->disable_devs;
 
 	for (i = 0; i < ARRAY_SIZE(sa1111_devices); i++)
-		if (has_devs & (1 << i))
+		if (sa1111_devices[i].devid & has_devs)
 			sa1111_init_one_child(sachip, mem, &sa1111_devices[i]);
 
 	return 0;
@@ -824,7 +815,10 @@
 
 static int sa1111_remove_one(struct device *dev, void *data)
 {
-	device_unregister(dev);
+	struct sa1111_dev *sadev = SA1111_DEV(dev);
+	device_del(&sadev->dev);
+	release_resource(&sadev->res);
+	put_device(&sadev->dev);
 	return 0;
 }
 
@@ -846,6 +840,7 @@
 	if (sachip->irq != NO_IRQ) {
 		irq_set_chained_handler(sachip->irq, NULL);
 		irq_set_handler_data(sachip->irq, NULL);
+		irq_free_descs(sachip->irq_base, SA1111_IRQ_NR);
 
 		release_mem_region(sachip->phys + SA1111_INTC, 512);
 	}
@@ -904,6 +899,9 @@
 	save->skpwm0   = sa1111_readl(base + SA1111_SKPWM0);
 	save->skpwm1   = sa1111_readl(base + SA1111_SKPWM1);
 
+	sa1111_writel(0, sachip->base + SA1111_SKPWM0);
+	sa1111_writel(0, sachip->base + SA1111_SKPWM1);
+
 	base = sachip->base + SA1111_INTC;
 	save->intpol0  = sa1111_readl(base + SA1111_INTPOL0);
 	save->intpol1  = sa1111_readl(base + SA1111_INTPOL1);
@@ -919,13 +917,15 @@
 	 */
 	val = sa1111_readl(sachip->base + SA1111_SKCR);
 	sa1111_writel(val | SKCR_SLEEP, sachip->base + SA1111_SKCR);
-	sa1111_writel(0, sachip->base + SA1111_SKPWM0);
-	sa1111_writel(0, sachip->base + SA1111_SKPWM1);
 
 	clk_disable(sachip->clk);
 
 	spin_unlock_irqrestore(&sachip->lock, flags);
 
+#ifdef CONFIG_ARCH_SA1100
+	sa1110_mb_disable();
+#endif
+
 	return 0;
 }
 
@@ -966,6 +966,11 @@
 	 */
 	sa1111_wake(sachip);
 
+#ifdef CONFIG_ARCH_SA1100
+	/* Enable the memory bus request/grant signals */
+	sa1110_mb_enable();
+#endif
+
 	/*
 	 * Only lock for write ops. Also, sa1111_wake must be called with
 	 * released spinlock!
@@ -1053,6 +1058,7 @@
 	.resume		= sa1111_resume,
 	.driver		= {
 		.name	= "sa1111",
+		.owner	= THIS_MODULE,
 	},
 };
 
@@ -1238,16 +1244,23 @@
  *	sa1111_enable_device - enable an on-chip SA1111 function block
  *	@sadev: SA1111 function block device to enable
  */
-void sa1111_enable_device(struct sa1111_dev *sadev)
+int sa1111_enable_device(struct sa1111_dev *sadev)
 {
 	struct sa1111 *sachip = sa1111_chip_driver(sadev);
 	unsigned long flags;
 	unsigned int val;
+	int ret = 0;
 
-	spin_lock_irqsave(&sachip->lock, flags);
-	val = sa1111_readl(sachip->base + SA1111_SKPCR);
-	sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
-	spin_unlock_irqrestore(&sachip->lock, flags);
+	if (sachip->pdata && sachip->pdata->enable)
+		ret = sachip->pdata->enable(sachip->pdata->data, sadev->devid);
+
+	if (ret == 0) {
+		spin_lock_irqsave(&sachip->lock, flags);
+		val = sa1111_readl(sachip->base + SA1111_SKPCR);
+		sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
+		spin_unlock_irqrestore(&sachip->lock, flags);
+	}
+	return ret;
 }
 EXPORT_SYMBOL(sa1111_enable_device);
 
@@ -1265,6 +1278,9 @@
 	val = sa1111_readl(sachip->base + SA1111_SKPCR);
 	sa1111_writel(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
 	spin_unlock_irqrestore(&sachip->lock, flags);
+
+	if (sachip->pdata && sachip->pdata->disable)
+		sachip->pdata->disable(sachip->pdata->data, sadev->devid);
 }
 EXPORT_SYMBOL(sa1111_disable_device);
 
@@ -1279,7 +1295,7 @@
 	struct sa1111_dev *dev = SA1111_DEV(_dev);
 	struct sa1111_driver *drv = SA1111_DRV(_drv);
 
-	return dev->devid == drv->devid;
+	return dev->devid & drv->devid;
 }
 
 static int sa1111_bus_suspend(struct device *dev, pm_message_t state)
@@ -1304,6 +1320,14 @@
 	return ret;
 }
 
+static void sa1111_bus_shutdown(struct device *dev)
+{
+	struct sa1111_driver *drv = SA1111_DRV(dev->driver);
+
+	if (drv && drv->shutdown)
+		drv->shutdown(SA1111_DEV(dev));
+}
+
 static int sa1111_bus_probe(struct device *dev)
 {
 	struct sa1111_dev *sadev = SA1111_DEV(dev);
@@ -1333,6 +1357,7 @@
 	.remove		= sa1111_bus_remove,
 	.suspend	= sa1111_bus_suspend,
 	.resume		= sa1111_bus_resume,
+	.shutdown	= sa1111_bus_shutdown,
 };
 EXPORT_SYMBOL(sa1111_bus_type);
 
@@ -1349,9 +1374,70 @@
 }
 EXPORT_SYMBOL(sa1111_driver_unregister);
 
+#ifdef CONFIG_DMABOUNCE
+/*
+ * According to the "Intel StrongARM SA-1111 Microprocessor Companion
+ * Chip Specification Update" (June 2000), erratum #7, there is a
+ * significant bug in the SA1111 SDRAM shared memory controller.  If
+ * an access to a region of memory above 1MB relative to the bank base,
+ * it is important that address bit 10 _NOT_ be asserted. Depending
+ * on the configuration of the RAM, bit 10 may correspond to one
+ * of several different (processor-relative) address bits.
+ *
+ * This routine only identifies whether or not a given DMA address
+ * is susceptible to the bug.
+ *
+ * This should only get called for sa1111_device types due to the
+ * way we configure our device dma_masks.
+ */
+static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
+{
+	/*
+	 * Section 4.6 of the "Intel StrongARM SA-1111 Development Module
+	 * User's Guide" mentions that jumpers R51 and R52 control the
+	 * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
+	 * SDRAM bank 1 on Neponset). The default configuration selects
+	 * Assabet, so any address in bank 1 is necessarily invalid.
+	 */
+	return (machine_is_assabet() || machine_is_pfs168()) &&
+		(addr >= 0xc8000000 || (addr + size) >= 0xc8000000);
+}
+
+static int sa1111_notifier_call(struct notifier_block *n, unsigned long action,
+	void *data)
+{
+	struct sa1111_dev *dev = SA1111_DEV(data);
+
+	switch (action) {
+	case BUS_NOTIFY_ADD_DEVICE:
+		if (dev->dev.dma_mask && dev->dma_mask < 0xffffffffUL) {
+			int ret = dmabounce_register_dev(&dev->dev, 1024, 4096,
+					sa1111_needs_bounce);
+			if (ret)
+				dev_err(&dev->dev, "failed to register with dmabounce: %d\n", ret);
+		}
+		break;
+
+	case BUS_NOTIFY_DEL_DEVICE:
+		if (dev->dev.dma_mask && dev->dma_mask < 0xffffffffUL)
+			dmabounce_unregister_dev(&dev->dev);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block sa1111_bus_notifier = {
+	.notifier_call = sa1111_notifier_call,
+};
+#endif
+
 static int __init sa1111_init(void)
 {
 	int ret = bus_register(&sa1111_bus_type);
+#ifdef CONFIG_DMABOUNCE
+	if (ret == 0)
+		bus_register_notifier(&sa1111_bus_type, &sa1111_bus_notifier);
+#endif
 	if (ret == 0)
 		platform_driver_register(&sa1111_device_driver);
 	return ret;
@@ -1360,6 +1446,9 @@
 static void __exit sa1111_exit(void)
 {
 	platform_driver_unregister(&sa1111_device_driver);
+#ifdef CONFIG_DMABOUNCE
+	bus_unregister_notifier(&sa1111_bus_type, &sa1111_bus_notifier);
+#endif
 	bus_unregister(&sa1111_bus_type);
 }
 
diff --git a/arch/arm/common/time-acorn.c b/arch/arm/common/time-acorn.c
deleted file mode 100644
index deeed56..0000000
--- a/arch/arm/common/time-acorn.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *  linux/arch/arm/common/time-acorn.c
- *
- *  Copyright (c) 1996-2000 Russell King.
- *
- * 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.
- *
- *  Changelog:
- *   24-Sep-1996	RMK	Created
- *   10-Oct-1996	RMK	Brought up to date with arch-sa110eval
- *   04-Dec-1997	RMK	Updated for new arch/arm/time.c
- *   13=Jun-2004	DS	Moved to arch/arm/common b/c shared w/CLPS7500
- */
-#include <linux/timex.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/hardware/ioc.h>
-
-#include <asm/mach/time.h>
-
-unsigned long ioc_timer_gettimeoffset(void)
-{
-	unsigned int count1, count2, status;
-	long offset;
-
-	ioc_writeb (0, IOC_T0LATCH);
-	barrier ();
-	count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
-	barrier ();
-	status = ioc_readb(IOC_IRQREQA);
-	barrier ();
-	ioc_writeb (0, IOC_T0LATCH);
-	barrier ();
-	count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
-
-	offset = count2;
-	if (count2 < count1) {
-		/*
-		 * We have not had an interrupt between reading count1
-		 * and count2.
-		 */
-		if (status & (1 << 5))
-			offset -= LATCH;
-	} else if (count2 > count1) {
-		/*
-		 * We have just had another interrupt between reading
-		 * count1 and count2.
-		 */
-		offset -= LATCH;
-	}
-
-	offset = (LATCH - offset) * (tick_nsec / 1000);
-	return (offset + LATCH/2) / LATCH;
-}
-
-void __init ioctime_init(void)
-{
-	ioc_writeb(LATCH & 255, IOC_T0LTCHL);
-	ioc_writeb(LATCH >> 8, IOC_T0LTCHH);
-	ioc_writeb(0, IOC_T0GO);
-}
-
-static irqreturn_t
-ioc_timer_interrupt(int irq, void *dev_id)
-{
-	timer_tick();
-	return IRQ_HANDLED;
-}
-
-static struct irqaction ioc_timer_irq = {
-	.name		= "timer",
-	.flags		= IRQF_DISABLED,
-	.handler	= ioc_timer_interrupt
-};
-
-/*
- * Set up timer interrupt.
- */
-static void __init ioc_timer_init(void)
-{
-	ioctime_init();
-	setup_irq(IRQ_TIMER, &ioc_timer_irq);
-}
-
-struct sys_timer ioc_timer = {
-	.init		= ioc_timer_init,
-	.offset		= ioc_timer_gettimeoffset,
-};
-
diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c
index 8794a34..df13a3f 100644
--- a/arch/arm/common/timer-sp.c
+++ b/arch/arm/common/timer-sp.c
@@ -26,6 +26,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 
+#include <asm/sched_clock.h>
 #include <asm/hardware/arm_timer.h>
 
 static long __init sp804_get_clock_rate(const char *name)
@@ -67,7 +68,16 @@
 	return rate;
 }
 
-void __init sp804_clocksource_init(void __iomem *base, const char *name)
+static void __iomem *sched_clock_base;
+
+static u32 sp804_read(void)
+{
+	return ~readl_relaxed(sched_clock_base + TIMER_VALUE);
+}
+
+void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base,
+						     const char *name,
+						     int use_sched_clock)
 {
 	long rate = sp804_get_clock_rate(name);
 
@@ -83,6 +93,11 @@
 
 	clocksource_mmio_init(base + TIMER_VALUE, name,
 		rate, 200, 32, clocksource_mmio_readl_down);
+
+	if (use_sched_clock) {
+		sched_clock_base = base;
+		setup_sched_clock(sp804_read, 32, rate);
+	}
 }
 
 
diff --git a/arch/arm/common/via82c505.c b/arch/arm/common/via82c505.c
index 67dd2af..1171a50 100644
--- a/arch/arm/common/via82c505.c
+++ b/arch/arm/common/via82c505.c
@@ -6,7 +6,6 @@
 #include <linux/ioport.h>
 #include <linux/io.h>
 
-#include <asm/system.h>
 
 #include <asm/mach/pci.h>
 
diff --git a/arch/arm/configs/at91cap9_defconfig b/arch/arm/configs/at91cap9_defconfig
deleted file mode 100644
index 8826eb2..0000000
--- a/arch/arm/configs/at91cap9_defconfig
+++ /dev/null
@@ -1,108 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT91CAP9=y
-CONFIG_MACH_AT91CAP9ADK=y
-CONFIG_MTD_AT91_DATAFLASH_CARD=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_AEABI=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_JEDECPROBE=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_DATAFLASH=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_NETDEVICES=y
-CONFIG_MII=y
-CONFIG_MACB=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_ADS7846=y
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_SPI=y
-CONFIG_SPI_ATMEL=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_FB=y
-CONFIG_FB_ATMEL=y
-CONFIG_LOGO=y
-# CONFIG_LOGO_LINUX_MONO is not set
-# CONFIG_LOGO_LINUX_CLUT224 is not set
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_ETH=m
-CONFIG_USB_FILE_STORAGE=m
-CONFIG_MMC=y
-CONFIG_MMC_AT91=m
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AT91SAM9=y
-CONFIG_EXT2_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_USER=y
diff --git a/arch/arm/configs/at91sam9g20_defconfig b/arch/arm/configs/at91sam9g20_defconfig
index 9123568..994d331 100644
--- a/arch/arm/configs/at91sam9g20_defconfig
+++ b/arch/arm/configs/at91sam9g20_defconfig
@@ -74,6 +74,8 @@
 CONFIG_SERIAL_ATMEL=y
 CONFIG_SERIAL_ATMEL_CONSOLE=y
 CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_GPIO=y
 CONFIG_SPI=y
 CONFIG_SPI_ATMEL=y
 CONFIG_SPI_SPIDEV=y
@@ -105,6 +107,7 @@
 CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_RV3029C2=y
 CONFIG_RTC_DRV_AT91SAM9=y
 CONFIG_EXT2_FS=y
 CONFIG_MSDOS_FS=y
diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig
index a22e930..b5ac644 100644
--- a/arch/arm/configs/imx_v4_v5_defconfig
+++ b/arch/arm/configs/imx_v4_v5_defconfig
@@ -45,6 +45,7 @@
 CONFIG_FPE_NWFPE_XP=y
 CONFIG_PM_DEBUG=y
 CONFIG_NET=y
+CONFIG_SMSC911X=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
@@ -68,6 +69,7 @@
 CONFIG_MTD_CFI_ADV_OPTIONS=y
 CONFIG_MTD_CFI_GEOMETRY=y
 # CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
 # CONFIG_MTD_CFI_I2 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_PHYSMAP=y
@@ -78,6 +80,8 @@
 CONFIG_EEPROM_AT24=y
 CONFIG_EEPROM_AT25=y
 CONFIG_NETDEVICES=y
+CONFIG_CS89x0=y
+CONFIG_CS89x0_PLATFORM=y
 CONFIG_DM9000=y
 CONFIG_SMC91X=y
 CONFIG_SMC911X=y
@@ -115,6 +119,21 @@
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_LCD_L4F00242T03=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_MEDIA=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF_DMA_CONTIG=y
+CONFIG_VIDEOBUF2_CORE=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=y
+CONFIG_SOC_CAMERA_OV2640=y
+CONFIG_VIDEO_MX2_HOSTSUPPORT=y
+CONFIG_VIDEO_MX2=y
 CONFIG_BACKLIGHT_PWM=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FONTS=y
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 3a4fb2e..dc6f641 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -5,6 +5,7 @@
 CONFIG_LOG_BUF_SHIFT=18
 CONFIG_CGROUPS=y
 CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
@@ -12,7 +13,6 @@
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_ARCH_MXC=y
 CONFIG_MACH_MX31LILLY=y
@@ -26,7 +26,6 @@
 CONFIG_MACH_KZM_ARM11_01=y
 CONFIG_MACH_PCM043=y
 CONFIG_MACH_MX35_3DS=y
-CONFIG_MACH_EUKREA_CPUIMX35=y
 CONFIG_MACH_VPR200=y
 CONFIG_MACH_IMX51_DT=y
 CONFIG_MACH_MX51_3DS=y
@@ -82,8 +81,9 @@
 CONFIG_NETDEVICES=y
 # CONFIG_NET_VENDOR_BROADCOM is not set
 # CONFIG_NET_VENDOR_CHELSIO is not set
+CONFIG_CS89x0=y
+CONFIG_CS89x0_PLATFORM=y
 # CONFIG_NET_VENDOR_FARADAY is not set
-CONFIG_FEC=y
 # CONFIG_NET_VENDOR_INTEL is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
@@ -126,7 +126,40 @@
 CONFIG_IMX2_WDT=y
 CONFIG_MFD_MC13XXX=y
 CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_MC13783=y
 CONFIG_REGULATOR_MC13892=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF2_CORE=y
+CONFIG_VIDEOBUF2_MEMOPS=y
+CONFIG_VIDEOBUF2_DMA_CONTIG=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=y
+CONFIG_SOC_CAMERA_OV2640=y
+CONFIG_MX3_VIDEO=y
+CONFIG_VIDEO_MX3=y
+CONFIG_FB=y
+CONFIG_FB_MX3=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_L4F00242T03=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_MXC=y
diff --git a/arch/arm/configs/integrator_defconfig b/arch/arm/configs/integrator_defconfig
index 1103f62..a8314c3 100644
--- a/arch/arm/configs/integrator_defconfig
+++ b/arch/arm/configs/integrator_defconfig
@@ -57,18 +57,24 @@
 CONFIG_NET_ETHERNET=y
 CONFIG_NET_PCI=y
 CONFIG_E100=y
+CONFIG_SMC91X=y
 # CONFIG_KEYBOARD_ATKBD is not set
 # CONFIG_SERIO_SERPORT is not set
 CONFIG_SERIAL_AMBA_PL010=y
 CONFIG_SERIAL_AMBA_PL010_CONSOLE=y
 CONFIG_FB=y
 CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_ARMCLCD=y
 CONFIG_FB_MATROX=y
 CONFIG_FB_MATROX_MILLENIUM=y
 CONFIG_FB_MATROX_MYSTIQUE=y
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_MMC=y
+CONFIG_MMC_ARMMMCI=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_PL030=y
 CONFIG_EXT2_FS=y
+CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_CRAMFS=y
@@ -78,5 +84,7 @@
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
 CONFIG_PARTITION_ADVANCED=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig
new file mode 100644
index 0000000..fb20881
--- /dev/null
+++ b/arch/arm/configs/lpc32xx_defconfig
@@ -0,0 +1,145 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_LPC32XX=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,115200n81 root=/dev/ram0"
+CONFIG_CPU_IDLE=y
+CONFIG_FPE_NWFPE=y
+CONFIG_VFP=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_AOUT=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_MUSEUM_IDS=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=1
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_MISC_DEVICES=y
+CONFIG_EEPROM_AT25=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_MII=y
+CONFIG_PHYLIB=y
+CONFIG_SMSC_PHY=y
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=240
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_LPC32XX=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_PNX=y
+CONFIG_SPI=y
+CONFIG_SPI_PL022=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_PNX4008_WATCHDOG=y
+CONFIG_FB=y
+CONFIG_FB_ARMCLCD=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SEQUENCER=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_DYNAMIC_MINORS=y
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_SPI is not set
+CONFIG_SND_SOC=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_MMC=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_ARMMMCI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+CONFIG_RTC_DRV_LPC32XX=y
+CONFIG_EXT2_FS=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_WBUF_VERIFY=y
+CONFIG_CRAMFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_FTRACE is not set
+# CONFIG_ARM_UNWIND is not set
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/magician_defconfig b/arch/arm/configs/magician_defconfig
index 443675d..a691ef4 100644
--- a/arch/arm/configs/magician_defconfig
+++ b/arch/arm/configs/magician_defconfig
@@ -101,7 +101,7 @@
 CONFIG_HTC_EGPIO=y
 CONFIG_HTC_PASIC3=y
 CONFIG_REGULATOR=y
-CONFIG_REGULATOR_BQ24022=y
+CONFIG_REGULATOR_GPIO=y
 CONFIG_FB=y
 CONFIG_FB_PXA=y
 CONFIG_FB_PXA_OVERLAY=y
diff --git a/arch/arm/configs/mini2440_defconfig b/arch/arm/configs/mini2440_defconfig
index 2472a95..42da918 100644
--- a/arch/arm/configs/mini2440_defconfig
+++ b/arch/arm/configs/mini2440_defconfig
@@ -13,7 +13,7 @@
 CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_BLK_DEV_INTEGRITY=y
-CONFIG_ARCH_S3C2410=y
+CONFIG_ARCH_S3C24XX=y
 CONFIG_S3C_ADC=y
 CONFIG_S3C24XX_PWM=y
 CONFIG_MACH_MINI2440=y
diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig
index 6ee781b..1ebbf45 100644
--- a/arch/arm/configs/mxs_defconfig
+++ b/arch/arm/configs/mxs_defconfig
@@ -77,10 +77,10 @@
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
-CONFIG_I2C=m
+CONFIG_I2C=y
 # CONFIG_I2C_COMPAT is not set
-CONFIG_I2C_CHARDEV=m
-CONFIG_I2C_MXS=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MXS=y
 CONFIG_SPI=y
 CONFIG_SPI_GPIO=m
 CONFIG_DEBUG_GPIO=y
@@ -90,6 +90,20 @@
 CONFIG_DISPLAY_SUPPORT=m
 # CONFIG_HID_SUPPORT is not set
 # CONFIG_USB_SUPPORT is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+CONFIG_SND_DRIVERS=y
+CONFIG_SND_ARM=y
+CONFIG_SND_SOC=y
+CONFIG_SND_MXS_SOC=y
+CONFIG_SND_SOC_MXS_SGTL5000=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+CONFIG_SND_SOC_SGTL5000=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_MMC=y
 CONFIG_MMC_MXS=y
 CONFIG_RTC_CLASS=y
diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig
index f9096c1..193448f 100644
--- a/arch/arm/configs/s3c2410_defconfig
+++ b/arch/arm/configs/s3c2410_defconfig
@@ -3,40 +3,47 @@
 CONFIG_IKCONFIG=m
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_S3C2410=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_ARCH_S3C24XX=y
 CONFIG_S3C_BOOT_ERROR_RESET=y
 CONFIG_S3C_ADC=y
 CONFIG_S3C24XX_PWM=y
-CONFIG_ARCH_SMDK2410=y
+CONFIG_CPU_S3C2412=y
+CONFIG_CPU_S3C2416=y
+CONFIG_CPU_S3C2440=y
+CONFIG_CPU_S3C2442=y
+CONFIG_CPU_S3C2443=y
+CONFIG_MACH_AML_M5900=y
+CONFIG_ARCH_BAST=y
 CONFIG_ARCH_H1940=y
 CONFIG_MACH_N30=y
-CONFIG_ARCH_BAST=y
 CONFIG_MACH_OTOM=y
-CONFIG_MACH_AML_M5900=y
+CONFIG_MACH_QT2410=y
+CONFIG_ARCH_SMDK2410=y
 CONFIG_MACH_TCT_HAMMER=y
 CONFIG_MACH_VR1000=y
-CONFIG_MACH_QT2410=y
 CONFIG_MACH_JIVE=y
 CONFIG_MACH_SMDK2412=y
 CONFIG_MACH_VSTMS=y
 CONFIG_MACH_SMDK2416=y
 CONFIG_MACH_ANUBIS=y
-CONFIG_MACH_NEO1973_GTA02=y
+CONFIG_MACH_AT2440EVB=y
+CONFIG_MACH_MINI2440=y
+CONFIG_MACH_NEXCODER_2440=y
 CONFIG_MACH_OSIRIS=y
 CONFIG_MACH_OSIRIS_DVS=m
 CONFIG_MACH_RX3715=y
 CONFIG_ARCH_S3C2440=y
-CONFIG_MACH_NEXCODER_2440=y
-CONFIG_SMDK2440_CPU2442=y
-CONFIG_MACH_AT2440EVB=y
-CONFIG_MACH_MINI2440=y
+CONFIG_MACH_NEO1973_GTA02=y
 CONFIG_MACH_RX1950=y
+CONFIG_SMDK2440_CPU2442=y
 CONFIG_MACH_SMDK2443=y
 # CONFIG_ARM_THUMB is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
@@ -45,7 +52,6 @@
 CONFIG_FPE_NWFPE=y
 CONFIG_FPE_NWFPE_XP=y
 CONFIG_BINFMT_AOUT=y
-CONFIG_PM=y
 CONFIG_APM_EMULATION=m
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -58,7 +64,6 @@
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 CONFIG_NET_IPIP=m
-CONFIG_NET_IPGRE=m
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
@@ -80,7 +85,6 @@
 CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
 CONFIG_IPV6_TUNNEL=m
 CONFIG_NETFILTER=y
-CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CT_PROTO_DCCP=m
@@ -138,7 +142,6 @@
 CONFIG_NF_CONNTRACK_IPV4=m
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_TTL=m
@@ -150,7 +153,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_NETMAP=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_TARGET_ECN=m
@@ -177,8 +179,6 @@
 CONFIG_IP6_NF_MANGLE=m
 CONFIG_IP6_NF_RAW=m
 CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
 CONFIG_BT_BNEP=m
@@ -199,7 +199,6 @@
 CONFIG_MAC80211_LEDS=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -221,9 +220,6 @@
 CONFIG_BLK_DEV_UB=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_ATA_OVER_ETH=m
-CONFIG_EEPROM_AT25=m
-CONFIG_EEPROM_LEGACY=m
-CONFIG_EEPROM_93CX6=m
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_IDETAPE=m
@@ -240,7 +236,6 @@
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
 CONFIG_DM9000=y
 CONFIG_INPUT_EVDEV=y
 CONFIG_MOUSE_APPLETOUCH=m
@@ -274,7 +269,6 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
 CONFIG_INPUT_MISC=y
-CONFIG_INPUT_ATI_REMOTE=m
 CONFIG_INPUT_ATI_REMOTE2=m
 CONFIG_INPUT_KEYSPAN_REMOTE=m
 CONFIG_INPUT_POWERMATE=m
@@ -300,7 +294,6 @@
 CONFIG_SPI=y
 CONFIG_SPI_GPIO=m
 CONFIG_SPI_S3C24XX=m
-CONFIG_SPI_S3C24XX_GPIO=m
 CONFIG_SPI_SPIDEV=m
 CONFIG_SPI_TLE62X0=m
 CONFIG_SENSORS_LM75=m
@@ -315,7 +308,6 @@
 CONFIG_FB_S3C2410=y
 CONFIG_FB_SM501=y
 CONFIG_BACKLIGHT_PWM=m
-# CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_SOUND=y
 CONFIG_SND=y
@@ -330,10 +322,6 @@
 CONFIG_SND_USB_AUDIO=m
 CONFIG_SND_USB_CAIAQ=m
 CONFIG_SND_SOC=y
-CONFIG_SND_S3C24XX_SOC=y
-CONFIG_SND_S3C24XX_SOC_JIVE_WM8750=m
-CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710=m
-CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650=m
 # CONFIG_USB_HID is not set
 CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
@@ -387,9 +375,7 @@
 CONFIG_MMC_SDHCI=m
 CONFIG_MMC_SPI=m
 CONFIG_MMC_S3C=y
-CONFIG_LEDS_CLASS=m
 CONFIG_LEDS_S3C24XX=m
-CONFIG_LEDS_H1940=m
 CONFIG_LEDS_PCA9532=m
 CONFIG_LEDS_GPIO=m
 CONFIG_LEDS_PCA955X=m
@@ -410,8 +396,6 @@
 CONFIG_EXT3_FS_POSIX_ACL=y
 CONFIG_EXT4_FS=m
 CONFIG_EXT4_FS_POSIX_ACL=y
-CONFIG_INOTIFY=y
-CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 CONFIG_FUSE_FS=m
 CONFIG_ISO9660_FS=y
@@ -436,9 +420,6 @@
 CONFIG_NFSD_V3_ACL=y
 CONFIG_NFSD_V4=y
 CONFIG_CIFS=m
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_BSD_DISKLABEL=y
-CONFIG_SOLARIS_X86_PARTITION=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_737=m
 CONFIG_NLS_CODEPAGE_775=m
@@ -481,9 +462,7 @@
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_MUTEXES=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_LL=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/arm/configs/tct_hammer_defconfig b/arch/arm/configs/tct_hammer_defconfig
index 95c0f0d..1d24f84 100644
--- a/arch/arm/configs/tct_hammer_defconfig
+++ b/arch/arm/configs/tct_hammer_defconfig
@@ -14,7 +14,7 @@
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_S3C2410=y
+CONFIG_ARCH_S3C24XX=y
 CONFIG_MACH_TCT_HAMMER=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index fd5d304..351d670 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -11,11 +11,14 @@
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_ELF_CORE is not set
 CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
 # CONFIG_IOSCHED_DEADLINE is not set
 # CONFIG_IOSCHED_CFQ is not set
 CONFIG_ARCH_TEGRA=y
@@ -27,18 +30,20 @@
 CONFIG_MACH_TRIMSLICE=y
 CONFIG_MACH_WARIO=y
 CONFIG_MACH_VENTANA=y
-CONFIG_TEGRA_DEBUG_UARTD=y
-CONFIG_ARM_ERRATA_742230=y
+CONFIG_TEGRA_EMC_SCALING_ENABLE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
-CONFIG_NR_CPUS=2
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 # CONFIG_OABI_COMPAT is not set
 CONFIG_HIGHMEM=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_AUTO_ZRELADDR=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_CPU_IDLE=y
 CONFIG_VFP=y
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -68,7 +73,6 @@
 # CONFIG_FIRMWARE_IN_KERNEL is not set
 CONFIG_PROC_DEVICETREE=y
 CONFIG_BLK_DEV_LOOP=y
-CONFIG_MISC_DEVICES=y
 CONFIG_AD525X_DPOT=y
 CONFIG_AD525X_DPOT_I2C=y
 CONFIG_ICS932S401=y
@@ -76,6 +80,7 @@
 CONFIG_ISL29003=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
@@ -85,8 +90,7 @@
 CONFIG_USB_NET_SMSC75XX=y
 CONFIG_USB_NET_SMSC95XX=y
 # CONFIG_WLAN is not set
-# CONFIG_INPUT is not set
-# CONFIG_SERIO is not set
+CONFIG_INPUT_EVDEV=y
 # CONFIG_VT is not set
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_DEVKMEM is not set
@@ -96,13 +100,15 @@
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 # CONFIG_I2C_COMPAT is not set
-# CONFIG_I2C_HELPER_AUTO is not set
 CONFIG_I2C_TEGRA=y
 CONFIG_SPI=y
 CONFIG_SPI_TEGRA=y
 CONFIG_SENSORS_LM90=y
 CONFIG_MFD_TPS6586X=y
 CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_GPIO=y
 CONFIG_REGULATOR_TPS6586X=y
 CONFIG_SOUND=y
 CONFIG_SND=y
@@ -116,11 +122,13 @@
 CONFIG_SND_SOC_TEGRA=y
 CONFIG_SND_SOC_TEGRA_WM8903=y
 CONFIG_SND_SOC_TEGRA_TRIMSLICE=y
+CONFIG_SND_SOC_TEGRA_ALC5632=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_TEGRA=y
 CONFIG_USB_STORAGE=y
 CONFIG_MMC=y
+CONFIG_MMC_BLOCK_MINORS=16
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_TEGRA=y
@@ -130,6 +138,11 @@
 CONFIG_IIO=y
 CONFIG_SENSORS_ISL29018=y
 CONFIG_SENSORS_AK8975=y
+CONFIG_MFD_NVEC=y
+CONFIG_KEYBOARD_NVEC=y
+CONFIG_SERIO_NVEC_PS2=y
+CONFIG_TEGRA_IOMMU_GART=y
+CONFIG_TEGRA_IOMMU_SMMU=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
@@ -138,13 +151,12 @@
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_POSIX_ACL=y
 CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
 # CONFIG_DNOTIFY is not set
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_EFI_PARTITION=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
@@ -162,9 +174,8 @@
 CONFIG_DEBUG_LL=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CRYPTO_ECB=y
-CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_ARC4=y
 CONFIG_CRYPTO_TWOFISH=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_TEGRA_AES=y
 CONFIG_CRC_CCITT=y
-CONFIG_CRC16=y
diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig
index 2d7b6e7..889d73a 100644
--- a/arch/arm/configs/u8500_defconfig
+++ b/arch/arm/configs/u8500_defconfig
@@ -13,6 +13,7 @@
 CONFIG_MACH_HREFV60=y
 CONFIG_MACH_SNOWBALL=y
 CONFIG_MACH_U5500=y
+CONFIG_MACH_UX500_DT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index 23371b1..03fb936 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -23,6 +23,8 @@
 #include <asm/ptrace.h>
 #include <asm/domain.h>
 
+#define IOMEM(x)	(x)
+
 /*
  * Endian independent macros for shifting bytes within registers.
  */
diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h
index 86976d0..68374ba 100644
--- a/arch/arm/include/asm/atomic.h
+++ b/arch/arm/include/asm/atomic.h
@@ -13,7 +13,9 @@
 
 #include <linux/compiler.h>
 #include <linux/types.h>
-#include <asm/system.h>
+#include <linux/irqflags.h>
+#include <asm/barrier.h>
+#include <asm/cmpxchg.h>
 
 #define ATOMIC_INIT(i)	{ (i) }
 
diff --git a/arch/arm/include/asm/barrier.h b/arch/arm/include/asm/barrier.h
new file mode 100644
index 0000000..0511238
--- /dev/null
+++ b/arch/arm/include/asm/barrier.h
@@ -0,0 +1,69 @@
+#ifndef __ASM_BARRIER_H
+#define __ASM_BARRIER_H
+
+#ifndef __ASSEMBLY__
+#include <asm/outercache.h>
+
+#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
+
+#if __LINUX_ARM_ARCH__ >= 7 ||		\
+	(__LINUX_ARM_ARCH__ == 6 && defined(CONFIG_CPU_32v6K))
+#define sev()	__asm__ __volatile__ ("sev" : : : "memory")
+#define wfe()	__asm__ __volatile__ ("wfe" : : : "memory")
+#define wfi()	__asm__ __volatile__ ("wfi" : : : "memory")
+#endif
+
+#if __LINUX_ARM_ARCH__ >= 7
+#define isb() __asm__ __volatile__ ("isb" : : : "memory")
+#define dsb() __asm__ __volatile__ ("dsb" : : : "memory")
+#define dmb() __asm__ __volatile__ ("dmb" : : : "memory")
+#elif defined(CONFIG_CPU_XSC3) || __LINUX_ARM_ARCH__ == 6
+#define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
+				    : : "r" (0) : "memory")
+#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
+				    : : "r" (0) : "memory")
+#define dmb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
+				    : : "r" (0) : "memory")
+#elif defined(CONFIG_CPU_FA526)
+#define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
+				    : : "r" (0) : "memory")
+#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
+				    : : "r" (0) : "memory")
+#define dmb() __asm__ __volatile__ ("" : : : "memory")
+#else
+#define isb() __asm__ __volatile__ ("" : : : "memory")
+#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
+				    : : "r" (0) : "memory")
+#define dmb() __asm__ __volatile__ ("" : : : "memory")
+#endif
+
+#ifdef CONFIG_ARCH_HAS_BARRIERS
+#include <mach/barriers.h>
+#elif defined(CONFIG_ARM_DMA_MEM_BUFFERABLE) || defined(CONFIG_SMP)
+#define mb()		do { dsb(); outer_sync(); } while (0)
+#define rmb()		dsb()
+#define wmb()		mb()
+#else
+#include <asm/memory.h>
+#define mb()	do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
+#define rmb()	do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
+#define wmb()	do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
+#endif
+
+#ifndef CONFIG_SMP
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+#else
+#define smp_mb()	dmb()
+#define smp_rmb()	dmb()
+#define smp_wmb()	dmb()
+#endif
+
+#define read_barrier_depends()		do { } while(0)
+#define smp_read_barrier_depends()	do { } while(0)
+
+#define set_mb(var, value)	do { var = value; smp_mb(); } while (0)
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_BARRIER_H */
diff --git a/arch/arm/include/asm/bitops.h b/arch/arm/include/asm/bitops.h
index f7419ef..e691ec9 100644
--- a/arch/arm/include/asm/bitops.h
+++ b/arch/arm/include/asm/bitops.h
@@ -24,7 +24,7 @@
 #endif
 
 #include <linux/compiler.h>
-#include <asm/system.h>
+#include <linux/irqflags.h>
 
 #define smp_mb__before_clear_bit()	smp_mb()
 #define smp_mb__after_clear_bit()	smp_mb()
diff --git a/arch/arm/include/asm/bug.h b/arch/arm/include/asm/bug.h
index fac79dc..7af5c6c 100644
--- a/arch/arm/include/asm/bug.h
+++ b/arch/arm/include/asm/bug.h
@@ -1,6 +1,7 @@
 #ifndef _ASMARM_BUG_H
 #define _ASMARM_BUG_H
 
+#include <linux/linkage.h>
 
 #ifdef CONFIG_BUG
 
@@ -57,4 +58,33 @@
 
 #include <asm-generic/bug.h>
 
+struct pt_regs;
+void die(const char *msg, struct pt_regs *regs, int err);
+
+struct siginfo;
+void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
+		unsigned long err, unsigned long trap);
+
+#ifdef CONFIG_ARM_LPAE
+#define FAULT_CODE_ALIGNMENT	33
+#define FAULT_CODE_DEBUG	34
+#else
+#define FAULT_CODE_ALIGNMENT	1
+#define FAULT_CODE_DEBUG	2
+#endif
+
+void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
+				       struct pt_regs *),
+		     int sig, int code, const char *name);
+
+void hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int,
+				       struct pt_regs *),
+		     int sig, int code, const char *name);
+
+extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
+
+struct mm_struct;
+extern void show_pte(struct mm_struct *mm, unsigned long addr);
+extern void __show_regs(struct pt_regs *);
+
 #endif
diff --git a/arch/arm/include/asm/cmpxchg.h b/arch/arm/include/asm/cmpxchg.h
new file mode 100644
index 0000000..d41d7cb
--- /dev/null
+++ b/arch/arm/include/asm/cmpxchg.h
@@ -0,0 +1,295 @@
+#ifndef __ASM_ARM_CMPXCHG_H
+#define __ASM_ARM_CMPXCHG_H
+
+#include <linux/irqflags.h>
+#include <asm/barrier.h>
+
+#if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110)
+/*
+ * On the StrongARM, "swp" is terminally broken since it bypasses the
+ * cache totally.  This means that the cache becomes inconsistent, and,
+ * since we use normal loads/stores as well, this is really bad.
+ * Typically, this causes oopsen in filp_close, but could have other,
+ * more disastrous effects.  There are two work-arounds:
+ *  1. Disable interrupts and emulate the atomic swap
+ *  2. Clean the cache, perform atomic swap, flush the cache
+ *
+ * We choose (1) since its the "easiest" to achieve here and is not
+ * dependent on the processor type.
+ *
+ * NOTE that this solution won't work on an SMP system, so explcitly
+ * forbid it here.
+ */
+#define swp_is_buggy
+#endif
+
+static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
+{
+	extern void __bad_xchg(volatile void *, int);
+	unsigned long ret;
+#ifdef swp_is_buggy
+	unsigned long flags;
+#endif
+#if __LINUX_ARM_ARCH__ >= 6
+	unsigned int tmp;
+#endif
+
+	smp_mb();
+
+	switch (size) {
+#if __LINUX_ARM_ARCH__ >= 6
+	case 1:
+		asm volatile("@	__xchg1\n"
+		"1:	ldrexb	%0, [%3]\n"
+		"	strexb	%1, %2, [%3]\n"
+		"	teq	%1, #0\n"
+		"	bne	1b"
+			: "=&r" (ret), "=&r" (tmp)
+			: "r" (x), "r" (ptr)
+			: "memory", "cc");
+		break;
+	case 4:
+		asm volatile("@	__xchg4\n"
+		"1:	ldrex	%0, [%3]\n"
+		"	strex	%1, %2, [%3]\n"
+		"	teq	%1, #0\n"
+		"	bne	1b"
+			: "=&r" (ret), "=&r" (tmp)
+			: "r" (x), "r" (ptr)
+			: "memory", "cc");
+		break;
+#elif defined(swp_is_buggy)
+#ifdef CONFIG_SMP
+#error SMP is not supported on this platform
+#endif
+	case 1:
+		raw_local_irq_save(flags);
+		ret = *(volatile unsigned char *)ptr;
+		*(volatile unsigned char *)ptr = x;
+		raw_local_irq_restore(flags);
+		break;
+
+	case 4:
+		raw_local_irq_save(flags);
+		ret = *(volatile unsigned long *)ptr;
+		*(volatile unsigned long *)ptr = x;
+		raw_local_irq_restore(flags);
+		break;
+#else
+	case 1:
+		asm volatile("@	__xchg1\n"
+		"	swpb	%0, %1, [%2]"
+			: "=&r" (ret)
+			: "r" (x), "r" (ptr)
+			: "memory", "cc");
+		break;
+	case 4:
+		asm volatile("@	__xchg4\n"
+		"	swp	%0, %1, [%2]"
+			: "=&r" (ret)
+			: "r" (x), "r" (ptr)
+			: "memory", "cc");
+		break;
+#endif
+	default:
+		__bad_xchg(ptr, size), ret = 0;
+		break;
+	}
+	smp_mb();
+
+	return ret;
+}
+
+#define xchg(ptr,x) \
+	((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+#include <asm-generic/cmpxchg-local.h>
+
+#if __LINUX_ARM_ARCH__ < 6
+/* min ARCH < ARMv6 */
+
+#ifdef CONFIG_SMP
+#error "SMP is not supported on this platform"
+#endif
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)				  	       \
+	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+			(unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#ifndef CONFIG_SMP
+#include <asm-generic/cmpxchg.h>
+#endif
+
+#else	/* min ARCH >= ARMv6 */
+
+extern void __bad_cmpxchg(volatile void *ptr, int size);
+
+/*
+ * cmpxchg only support 32-bits operands on ARMv6.
+ */
+
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+				      unsigned long new, int size)
+{
+	unsigned long oldval, res;
+
+	switch (size) {
+#ifndef CONFIG_CPU_V6	/* min ARCH >= ARMv6K */
+	case 1:
+		do {
+			asm volatile("@ __cmpxchg1\n"
+			"	ldrexb	%1, [%2]\n"
+			"	mov	%0, #0\n"
+			"	teq	%1, %3\n"
+			"	strexbeq %0, %4, [%2]\n"
+				: "=&r" (res), "=&r" (oldval)
+				: "r" (ptr), "Ir" (old), "r" (new)
+				: "memory", "cc");
+		} while (res);
+		break;
+	case 2:
+		do {
+			asm volatile("@ __cmpxchg1\n"
+			"	ldrexh	%1, [%2]\n"
+			"	mov	%0, #0\n"
+			"	teq	%1, %3\n"
+			"	strexheq %0, %4, [%2]\n"
+				: "=&r" (res), "=&r" (oldval)
+				: "r" (ptr), "Ir" (old), "r" (new)
+				: "memory", "cc");
+		} while (res);
+		break;
+#endif
+	case 4:
+		do {
+			asm volatile("@ __cmpxchg4\n"
+			"	ldrex	%1, [%2]\n"
+			"	mov	%0, #0\n"
+			"	teq	%1, %3\n"
+			"	strexeq %0, %4, [%2]\n"
+				: "=&r" (res), "=&r" (oldval)
+				: "r" (ptr), "Ir" (old), "r" (new)
+				: "memory", "cc");
+		} while (res);
+		break;
+	default:
+		__bad_cmpxchg(ptr, size);
+		oldval = 0;
+	}
+
+	return oldval;
+}
+
+static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
+					 unsigned long new, int size)
+{
+	unsigned long ret;
+
+	smp_mb();
+	ret = __cmpxchg(ptr, old, new, size);
+	smp_mb();
+
+	return ret;
+}
+
+#define cmpxchg(ptr,o,n)						\
+	((__typeof__(*(ptr)))__cmpxchg_mb((ptr),			\
+					  (unsigned long)(o),		\
+					  (unsigned long)(n),		\
+					  sizeof(*(ptr))))
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+					    unsigned long old,
+					    unsigned long new, int size)
+{
+	unsigned long ret;
+
+	switch (size) {
+#ifdef CONFIG_CPU_V6	/* min ARCH == ARMv6 */
+	case 1:
+	case 2:
+		ret = __cmpxchg_local_generic(ptr, old, new, size);
+		break;
+#endif
+	default:
+		ret = __cmpxchg(ptr, old, new, size);
+	}
+
+	return ret;
+}
+
+#define cmpxchg_local(ptr,o,n)						\
+	((__typeof__(*(ptr)))__cmpxchg_local((ptr),			\
+				       (unsigned long)(o),		\
+				       (unsigned long)(n),		\
+				       sizeof(*(ptr))))
+
+#ifndef CONFIG_CPU_V6	/* min ARCH >= ARMv6K */
+
+/*
+ * Note : ARMv7-M (currently unsupported by Linux) does not support
+ * ldrexd/strexd. If ARMv7-M is ever supported by the Linux kernel, it should
+ * not be allowed to use __cmpxchg64.
+ */
+static inline unsigned long long __cmpxchg64(volatile void *ptr,
+					     unsigned long long old,
+					     unsigned long long new)
+{
+	register unsigned long long oldval asm("r0");
+	register unsigned long long __old asm("r2") = old;
+	register unsigned long long __new asm("r4") = new;
+	unsigned long res;
+
+	do {
+		asm volatile(
+		"	@ __cmpxchg8\n"
+		"	ldrexd	%1, %H1, [%2]\n"
+		"	mov	%0, #0\n"
+		"	teq	%1, %3\n"
+		"	teqeq	%H1, %H3\n"
+		"	strexdeq %0, %4, %H4, [%2]\n"
+			: "=&r" (res), "=&r" (oldval)
+			: "r" (ptr), "Ir" (__old), "r" (__new)
+			: "memory", "cc");
+	} while (res);
+
+	return oldval;
+}
+
+static inline unsigned long long __cmpxchg64_mb(volatile void *ptr,
+						unsigned long long old,
+						unsigned long long new)
+{
+	unsigned long long ret;
+
+	smp_mb();
+	ret = __cmpxchg64(ptr, old, new);
+	smp_mb();
+
+	return ret;
+}
+
+#define cmpxchg64(ptr,o,n)						\
+	((__typeof__(*(ptr)))__cmpxchg64_mb((ptr),			\
+					    (unsigned long long)(o),	\
+					    (unsigned long long)(n)))
+
+#define cmpxchg64_local(ptr,o,n)					\
+	((__typeof__(*(ptr)))__cmpxchg64((ptr),				\
+					 (unsigned long long)(o),	\
+					 (unsigned long long)(n)))
+
+#else /* min ARCH = ARMv6 */
+
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#endif
+
+#endif	/* __LINUX_ARM_ARCH__ >= 6 */
+
+#endif /* __ASM_ARM_CMPXCHG_H */
diff --git a/arch/arm/include/asm/compiler.h b/arch/arm/include/asm/compiler.h
new file mode 100644
index 0000000..8155db2
--- /dev/null
+++ b/arch/arm/include/asm/compiler.h
@@ -0,0 +1,15 @@
+#ifndef __ASM_ARM_COMPILER_H
+#define __ASM_ARM_COMPILER_H
+
+/*
+ * This is used to ensure the compiler did actually allocate the register we
+ * asked it for some inline assembly sequences.  Apparently we can't trust
+ * the compiler from one version to another so a bit of paranoia won't hurt.
+ * This string is meant to be concatenated with the inline asm string and
+ * will cause compilation to stop on mismatch.
+ * (for details, see gcc PR 15089)
+ */
+#define __asmeq(x, y)  ".ifnc " x "," y " ; .err ; .endif\n\t"
+
+
+#endif /* __ASM_ARM_COMPILER_H */
diff --git a/arch/arm/include/asm/cp15.h b/arch/arm/include/asm/cp15.h
new file mode 100644
index 0000000..5ef4d80
--- /dev/null
+++ b/arch/arm/include/asm/cp15.h
@@ -0,0 +1,87 @@
+#ifndef __ASM_ARM_CP15_H
+#define __ASM_ARM_CP15_H
+
+#include <asm/barrier.h>
+
+/*
+ * CR1 bits (CP#15 CR1)
+ */
+#define CR_M	(1 << 0)	/* MMU enable				*/
+#define CR_A	(1 << 1)	/* Alignment abort enable		*/
+#define CR_C	(1 << 2)	/* Dcache enable			*/
+#define CR_W	(1 << 3)	/* Write buffer enable			*/
+#define CR_P	(1 << 4)	/* 32-bit exception handler		*/
+#define CR_D	(1 << 5)	/* 32-bit data address range		*/
+#define CR_L	(1 << 6)	/* Implementation defined		*/
+#define CR_B	(1 << 7)	/* Big endian				*/
+#define CR_S	(1 << 8)	/* System MMU protection		*/
+#define CR_R	(1 << 9)	/* ROM MMU protection			*/
+#define CR_F	(1 << 10)	/* Implementation defined		*/
+#define CR_Z	(1 << 11)	/* Implementation defined		*/
+#define CR_I	(1 << 12)	/* Icache enable			*/
+#define CR_V	(1 << 13)	/* Vectors relocated to 0xffff0000	*/
+#define CR_RR	(1 << 14)	/* Round Robin cache replacement	*/
+#define CR_L4	(1 << 15)	/* LDR pc can set T bit			*/
+#define CR_DT	(1 << 16)
+#define CR_IT	(1 << 18)
+#define CR_ST	(1 << 19)
+#define CR_FI	(1 << 21)	/* Fast interrupt (lower latency mode)	*/
+#define CR_U	(1 << 22)	/* Unaligned access operation		*/
+#define CR_XP	(1 << 23)	/* Extended page tables			*/
+#define CR_VE	(1 << 24)	/* Vectored interrupts			*/
+#define CR_EE	(1 << 25)	/* Exception (Big) Endian		*/
+#define CR_TRE	(1 << 28)	/* TEX remap enable			*/
+#define CR_AFE	(1 << 29)	/* Access flag enable			*/
+#define CR_TE	(1 << 30)	/* Thumb exception enable		*/
+
+#ifndef __ASSEMBLY__
+
+#if __LINUX_ARM_ARCH__ >= 4
+#define vectors_high()	(cr_alignment & CR_V)
+#else
+#define vectors_high()	(0)
+#endif
+
+extern unsigned long cr_no_alignment;	/* defined in entry-armv.S */
+extern unsigned long cr_alignment;	/* defined in entry-armv.S */
+
+static inline unsigned int get_cr(void)
+{
+	unsigned int val;
+	asm("mrc p15, 0, %0, c1, c0, 0	@ get CR" : "=r" (val) : : "cc");
+	return val;
+}
+
+static inline void set_cr(unsigned int val)
+{
+	asm volatile("mcr p15, 0, %0, c1, c0, 0	@ set CR"
+	  : : "r" (val) : "cc");
+	isb();
+}
+
+#ifndef CONFIG_SMP
+extern void adjust_cr(unsigned long mask, unsigned long set);
+#endif
+
+#define CPACC_FULL(n)		(3 << (n * 2))
+#define CPACC_SVC(n)		(1 << (n * 2))
+#define CPACC_DISABLE(n)	(0 << (n * 2))
+
+static inline unsigned int get_copro_access(void)
+{
+	unsigned int val;
+	asm("mrc p15, 0, %0, c1, c0, 2 @ get copro access"
+	  : "=r" (val) : : "cc");
+	return val;
+}
+
+static inline void set_copro_access(unsigned int val)
+{
+	asm volatile("mcr p15, 0, %0, c1, c0, 2 @ set copro access"
+	  : : "r" (val) : "cc");
+	isb();
+}
+
+#endif
+
+#endif
diff --git a/arch/arm/include/asm/cpuidle.h b/arch/arm/include/asm/cpuidle.h
new file mode 100644
index 0000000..2fca60a
--- /dev/null
+++ b/arch/arm/include/asm/cpuidle.h
@@ -0,0 +1,29 @@
+#ifndef __ASM_ARM_CPUIDLE_H
+#define __ASM_ARM_CPUIDLE_H
+
+#ifdef CONFIG_CPU_IDLE
+extern int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int index);
+#else
+static inline int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int index) { return -ENODEV; }
+#endif
+
+/* Common ARM WFI state */
+#define ARM_CPUIDLE_WFI_STATE_PWR(p) {\
+	.enter                  = arm_cpuidle_simple_enter,\
+	.exit_latency           = 1,\
+	.target_residency       = 1,\
+	.power_usage		= p,\
+	.flags                  = CPUIDLE_FLAG_TIME_VALID,\
+	.name                   = "WFI",\
+	.desc                   = "ARM WFI",\
+}
+
+/*
+ * in case power_specified == 1, give a default WFI power value needed
+ * by some governors
+ */
+#define ARM_CPUIDLE_WFI_STATE ARM_CPUIDLE_WFI_STATE_PWR(UINT_MAX)
+
+#endif
diff --git a/arch/arm/include/asm/div64.h b/arch/arm/include/asm/div64.h
index d3f0a9e..fe92ccf 100644
--- a/arch/arm/include/asm/div64.h
+++ b/arch/arm/include/asm/div64.h
@@ -1,8 +1,8 @@
 #ifndef __ASM_ARM_DIV64
 #define __ASM_ARM_DIV64
 
-#include <asm/system.h>
 #include <linux/types.h>
+#include <asm/compiler.h>
 
 /*
  * The semantics of do_div() are:
diff --git a/arch/arm/include/asm/dma.h b/arch/arm/include/asm/dma.h
index 69a5b0b..5694a0d 100644
--- a/arch/arm/include/asm/dma.h
+++ b/arch/arm/include/asm/dma.h
@@ -19,7 +19,6 @@
  * It should not be re-used except for that purpose.
  */
 #include <linux/spinlock.h>
-#include <asm/system.h>
 #include <asm/scatterlist.h>
 
 #include <mach/isa-dma.h>
diff --git a/arch/arm/include/asm/domain.h b/arch/arm/include/asm/domain.h
index b5dc173..3d22204 100644
--- a/arch/arm/include/asm/domain.h
+++ b/arch/arm/include/asm/domain.h
@@ -10,6 +10,10 @@
 #ifndef __ASM_PROC_DOMAIN_H
 #define __ASM_PROC_DOMAIN_H
 
+#ifndef __ASSEMBLY__
+#include <asm/barrier.h>
+#endif
+
 /*
  * Domain numbers
  *
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index 0e9ce8d..38050b1 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -130,8 +130,4 @@
 extern unsigned long arch_randomize_brk(struct mm_struct *mm);
 #define arch_randomize_brk arch_randomize_brk
 
-extern int vectors_user_mapping(void);
-#define arch_setup_additional_pages(bprm, uses_interp) vectors_user_mapping()
-#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
-
 #endif
diff --git a/arch/arm/include/asm/exec.h b/arch/arm/include/asm/exec.h
new file mode 100644
index 0000000..7c4fbef
--- /dev/null
+++ b/arch/arm/include/asm/exec.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_ARM_EXEC_H
+#define __ASM_ARM_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* __ASM_ARM_EXEC_H */
diff --git a/arch/arm/include/asm/hardware/arm_timer.h b/arch/arm/include/asm/hardware/arm_timer.h
index c0f4e7b..d6030ff 100644
--- a/arch/arm/include/asm/hardware/arm_timer.h
+++ b/arch/arm/include/asm/hardware/arm_timer.h
@@ -9,7 +9,12 @@
  *
  * Integrator AP has 16-bit timers, Integrator CP, Versatile and Realview
  * can have 16-bit or 32-bit selectable via a bit in the control register.
+ *
+ * Every SP804 contains two identical timers.
  */
+#define TIMER_1_BASE	0x00
+#define TIMER_2_BASE	0x20
+
 #define TIMER_LOAD	0x00			/* ACVR rw */
 #define TIMER_VALUE	0x04			/* ACVR ro */
 #define TIMER_CTRL	0x08			/* ACVR rw */
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index 7df239b..c4c87bc 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -103,11 +103,11 @@
 #define L2X0_ADDR_FILTER_EN		1
 
 #ifndef __ASSEMBLY__
-extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);
+extern void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask);
 #if defined(CONFIG_CACHE_L2X0) && defined(CONFIG_OF)
-extern int l2x0_of_init(__u32 aux_val, __u32 aux_mask);
+extern int l2x0_of_init(u32 aux_val, u32 aux_mask);
 #else
-static inline int l2x0_of_init(__u32 aux_val, __u32 aux_mask)
+static inline int l2x0_of_init(u32 aux_val, u32 aux_mask)
 {
 	return -ENODEV;
 }
diff --git a/arch/arm/include/asm/hardware/entry-macro-iomd.S b/arch/arm/include/asm/hardware/entry-macro-iomd.S
index e0af498..8c215ac 100644
--- a/arch/arm/include/asm/hardware/entry-macro-iomd.S
+++ b/arch/arm/include/asm/hardware/entry-macro-iomd.S
@@ -11,14 +11,6 @@
 /* IOC / IOMD based hardware */
 #include <asm/hardware/iomd.h>
 
-		.macro	disable_fiq
-		mov	r12, #ioc_base_high
-		.if	ioc_base_low
-		orr	r12, r12, #ioc_base_low
-		.endif
-		strb	r12, [r12, #0x38]	@ Disable FIQ register
-		.endm
-
 		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 		ldrb	\irqstat, [\base, #IOMD_IRQREQB]	@ get high priority first
 		ldr	\tmp, =irq_prio_h
diff --git a/arch/arm/include/asm/hardware/iop3xx.h b/arch/arm/include/asm/hardware/iop3xx.h
index 077c323..2ff2c75 100644
--- a/arch/arm/include/asm/hardware/iop3xx.h
+++ b/arch/arm/include/asm/hardware/iop3xx.h
@@ -231,6 +231,9 @@
 
 
 #ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
 void iop3xx_map_io(void);
 void iop_init_cp6_handler(void);
 void iop_init_time(unsigned long tickrate);
diff --git a/arch/arm/include/asm/hardware/iop_adma.h b/arch/arm/include/asm/hardware/iop_adma.h
index 59b8c38..122f86d 100644
--- a/arch/arm/include/asm/hardware/iop_adma.h
+++ b/arch/arm/include/asm/hardware/iop_adma.h
@@ -49,7 +49,6 @@
 /**
  * struct iop_adma_chan - internal representation of an ADMA device
  * @pending: allows batching of hardware operations
- * @completed_cookie: identifier for the most recently completed operation
  * @lock: serializes enqueue/dequeue operations to the slot pool
  * @mmr_base: memory mapped register base
  * @chain: device chain view of the descriptors
@@ -62,7 +61,6 @@
  */
 struct iop_adma_chan {
 	int pending;
-	dma_cookie_t completed_cookie;
 	spinlock_t lock; /* protects the descriptor slot pool */
 	void __iomem *mmr_base;
 	struct list_head chain;
diff --git a/arch/arm/include/asm/hardware/it8152.h b/arch/arm/include/asm/hardware/it8152.h
index 43cab49..73f84fa 100644
--- a/arch/arm/include/asm/hardware/it8152.h
+++ b/arch/arm/include/asm/hardware/it8152.h
@@ -9,6 +9,9 @@
 
 #ifndef __ASM_HARDWARE_IT8152_H
 #define __ASM_HARDWARE_IT8152_H
+
+#include <mach/irqs.h>
+
 extern void __iomem *it8152_base_address;
 
 #define IT8152_IO_BASE			(it8152_base_address + 0x03e00000)
diff --git a/arch/arm/include/asm/hardware/pl330.h b/arch/arm/include/asm/hardware/pl330.h
deleted file mode 100644
index c182138..0000000
--- a/arch/arm/include/asm/hardware/pl330.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/* linux/include/asm/hardware/pl330.h
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@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 distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __PL330_CORE_H
-#define __PL330_CORE_H
-
-#define PL330_MAX_CHAN		8
-#define PL330_MAX_IRQS		32
-#define PL330_MAX_PERI		32
-
-enum pl330_srccachectrl {
-	SCCTRL0 = 0, /* Noncacheable and nonbufferable */
-	SCCTRL1, /* Bufferable only */
-	SCCTRL2, /* Cacheable, but do not allocate */
-	SCCTRL3, /* Cacheable and bufferable, but do not allocate */
-	SINVALID1,
-	SINVALID2,
-	SCCTRL6, /* Cacheable write-through, allocate on reads only */
-	SCCTRL7, /* Cacheable write-back, allocate on reads only */
-};
-
-enum pl330_dstcachectrl {
-	DCCTRL0 = 0, /* Noncacheable and nonbufferable */
-	DCCTRL1, /* Bufferable only */
-	DCCTRL2, /* Cacheable, but do not allocate */
-	DCCTRL3, /* Cacheable and bufferable, but do not allocate */
-	DINVALID1,              /* AWCACHE = 0x1000 */
-	DINVALID2,
-	DCCTRL6, /* Cacheable write-through, allocate on writes only */
-	DCCTRL7, /* Cacheable write-back, allocate on writes only */
-};
-
-/* Populated by the PL330 core driver for DMA API driver's info */
-struct pl330_config {
-	u32	periph_id;
-	u32	pcell_id;
-#define DMAC_MODE_NS	(1 << 0)
-	unsigned int	mode;
-	unsigned int	data_bus_width:10; /* In number of bits */
-	unsigned int	data_buf_dep:10;
-	unsigned int	num_chan:4;
-	unsigned int	num_peri:6;
-	u32		peri_ns;
-	unsigned int	num_events:6;
-	u32		irq_ns;
-};
-
-/* Handle to the DMAC provided to the PL330 core */
-struct pl330_info {
-	/* Owning device */
-	struct device *dev;
-	/* Size of MicroCode buffers for each channel. */
-	unsigned mcbufsz;
-	/* ioremap'ed address of PL330 registers. */
-	void __iomem	*base;
-	/* Client can freely use it. */
-	void	*client_data;
-	/* PL330 core data, Client must not touch it. */
-	void	*pl330_data;
-	/* Populated by the PL330 core driver during pl330_add */
-	struct pl330_config	pcfg;
-	/*
-	 * If the DMAC has some reset mechanism, then the
-	 * client may want to provide pointer to the method.
-	 */
-	void (*dmac_reset)(struct pl330_info *pi);
-};
-
-enum pl330_byteswap {
-	SWAP_NO = 0,
-	SWAP_2,
-	SWAP_4,
-	SWAP_8,
-	SWAP_16,
-};
-
-/**
- * Request Configuration.
- * The PL330 core does not modify this and uses the last
- * working configuration if the request doesn't provide any.
- *
- * The Client may want to provide this info only for the
- * first request and a request with new settings.
- */
-struct pl330_reqcfg {
-	/* Address Incrementing */
-	unsigned dst_inc:1;
-	unsigned src_inc:1;
-
-	/*
-	 * For now, the SRC & DST protection levels
-	 * and burst size/length are assumed same.
-	 */
-	bool nonsecure;
-	bool privileged;
-	bool insnaccess;
-	unsigned brst_len:5;
-	unsigned brst_size:3; /* in power of 2 */
-
-	enum pl330_dstcachectrl dcctl;
-	enum pl330_srccachectrl scctl;
-	enum pl330_byteswap swap;
-};
-
-/*
- * One cycle of DMAC operation.
- * There may be more than one xfer in a request.
- */
-struct pl330_xfer {
-	u32 src_addr;
-	u32 dst_addr;
-	/* Size to xfer */
-	u32 bytes;
-	/*
-	 * Pointer to next xfer in the list.
-	 * The last xfer in the req must point to NULL.
-	 */
-	struct pl330_xfer *next;
-};
-
-/* The xfer callbacks are made with one of these arguments. */
-enum pl330_op_err {
-	/* The all xfers in the request were success. */
-	PL330_ERR_NONE,
-	/* If req aborted due to global error. */
-	PL330_ERR_ABORT,
-	/* If req failed due to problem with Channel. */
-	PL330_ERR_FAIL,
-};
-
-enum pl330_reqtype {
-	MEMTOMEM,
-	MEMTODEV,
-	DEVTOMEM,
-	DEVTODEV,
-};
-
-/* A request defining Scatter-Gather List ending with NULL xfer. */
-struct pl330_req {
-	enum pl330_reqtype rqtype;
-	/* Index of peripheral for the xfer. */
-	unsigned peri:5;
-	/* Unique token for this xfer, set by the client. */
-	void *token;
-	/* Callback to be called after xfer. */
-	void (*xfer_cb)(void *token, enum pl330_op_err err);
-	/* If NULL, req will be done at last set parameters. */
-	struct pl330_reqcfg *cfg;
-	/* Pointer to first xfer in the request. */
-	struct pl330_xfer *x;
-};
-
-/*
- * To know the status of the channel and DMAC, the client
- * provides a pointer to this structure. The PL330 core
- * fills it with current information.
- */
-struct pl330_chanstatus {
-	/*
-	 * If the DMAC engine halted due to some error,
-	 * the client should remove-add DMAC.
-	 */
-	bool dmac_halted;
-	/*
-	 * If channel is halted due to some error,
-	 * the client should ABORT/FLUSH and START the channel.
-	 */
-	bool faulting;
-	/* Location of last load */
-	u32 src_addr;
-	/* Location of last store */
-	u32 dst_addr;
-	/*
-	 * Pointer to the currently active req, NULL if channel is
-	 * inactive, even though the requests may be present.
-	 */
-	struct pl330_req *top_req;
-	/* Pointer to req waiting second in the queue if any. */
-	struct pl330_req *wait_req;
-};
-
-enum pl330_chan_op {
-	/* Start the channel */
-	PL330_OP_START,
-	/* Abort the active xfer */
-	PL330_OP_ABORT,
-	/* Stop xfer and flush queue */
-	PL330_OP_FLUSH,
-};
-
-extern int pl330_add(struct pl330_info *);
-extern void pl330_del(struct pl330_info *pi);
-extern int pl330_update(const struct pl330_info *pi);
-extern void pl330_release_channel(void *ch_id);
-extern void *pl330_request_channel(const struct pl330_info *pi);
-extern int pl330_chan_status(void *ch_id, struct pl330_chanstatus *pstatus);
-extern int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op);
-extern int pl330_submit_req(void *ch_id, struct pl330_req *r);
-
-#endif	/* __PL330_CORE_H */
diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h
index 92ed254..7c2bbc7 100644
--- a/arch/arm/include/asm/hardware/sa1111.h
+++ b/arch/arm/include/asm/hardware/sa1111.h
@@ -132,34 +132,10 @@
 #define SKPCR_DCLKEN	(1<<7)
 #define SKPCR_PWMCLKEN	(1<<8)
 
-/*
- * USB Host controller
- */
+/* USB Host controller */
 #define SA1111_USB		0x0400
 
 /*
- * Offsets from SA1111_USB_BASE
- */
-#define SA1111_USB_STATUS	0x0118
-#define SA1111_USB_RESET	0x011c
-#define SA1111_USB_IRQTEST	0x0120
-
-#define USB_RESET_FORCEIFRESET	(1 << 0)
-#define USB_RESET_FORCEHCRESET	(1 << 1)
-#define USB_RESET_CLKGENRESET	(1 << 2)
-#define USB_RESET_SIMSCALEDOWN	(1 << 3)
-#define USB_RESET_USBINTTEST	(1 << 4)
-#define USB_RESET_SLEEPSTBYEN	(1 << 5)
-#define USB_RESET_PWRSENSELOW	(1 << 6)
-#define USB_RESET_PWRCTRLLOW	(1 << 7)
-
-#define USB_STATUS_IRQHCIRMTWKUP  (1 <<  7)
-#define USB_STATUS_IRQHCIBUFFACC  (1 <<  8)
-#define USB_STATUS_NIRQHCIM       (1 <<  9)
-#define USB_STATUS_NHCIMFCLR      (1 << 10)
-#define USB_STATUS_USBPWRSENSE    (1 << 11)
-
-/*
  * Serial Audio Controller
  *
  * Registers
@@ -327,22 +303,6 @@
  *    PC_SSR		GPIO Block C Sleep State
  */
 
-#define _PA_DDR		_SA1111( 0x1000 )
-#define _PA_DRR		_SA1111( 0x1004 )
-#define _PA_DWR		_SA1111( 0x1004 )
-#define _PA_SDR		_SA1111( 0x1008 )
-#define _PA_SSR		_SA1111( 0x100c )
-#define _PB_DDR		_SA1111( 0x1010 )
-#define _PB_DRR		_SA1111( 0x1014 )
-#define _PB_DWR		_SA1111( 0x1014 )
-#define _PB_SDR		_SA1111( 0x1018 )
-#define _PB_SSR		_SA1111( 0x101c )
-#define _PC_DDR		_SA1111( 0x1020 )
-#define _PC_DRR		_SA1111( 0x1024 )
-#define _PC_DWR		_SA1111( 0x1024 )
-#define _PC_SDR		_SA1111( 0x1028 )
-#define _PC_SSR		_SA1111( 0x102c )
-
 #define SA1111_GPIO	0x1000
 
 #define SA1111_GPIO_PADDR	(0x000)
@@ -425,106 +385,30 @@
 #define SA1111_WAKEPOL0		0x0034
 #define SA1111_WAKEPOL1		0x0038
 
-/*
- * PS/2 Trackpad and Mouse Interfaces
- *
- * Registers
- *    PS2CR		Control Register
- *    PS2STAT		Status Register
- *    PS2DATA		Transmit/Receive Data register
- *    PS2CLKDIV		Clock Division Register
- *    PS2PRECNT		Clock Precount Register
- *    PS2TEST1		Test register 1
- *    PS2TEST2		Test register 2
- *    PS2TEST3		Test register 3
- *    PS2TEST4		Test register 4
- */
-
+/* PS/2 Trackpad and Mouse Interfaces */
 #define SA1111_KBD		0x0a00
 #define SA1111_MSE		0x0c00
 
-/*
- * These are offsets from the above bases.
- */
-#define SA1111_PS2CR		0x0000
-#define SA1111_PS2STAT		0x0004
-#define SA1111_PS2DATA		0x0008
-#define SA1111_PS2CLKDIV	0x000c
-#define SA1111_PS2PRECNT	0x0010
+/* PCMCIA Interface */
+#define SA1111_PCMCIA		0x1600
 
-#define PS2CR_ENA		0x08
-#define PS2CR_FKD		0x02
-#define PS2CR_FKC		0x01
-
-#define PS2STAT_STP		0x0100
-#define PS2STAT_TXE		0x0080
-#define PS2STAT_TXB		0x0040
-#define PS2STAT_RXF		0x0020
-#define PS2STAT_RXB		0x0010
-#define PS2STAT_ENA		0x0008
-#define PS2STAT_RXP		0x0004
-#define PS2STAT_KBD		0x0002
-#define PS2STAT_KBC		0x0001
-
-/*
- * PCMCIA Interface
- *
- * Registers
- *    PCSR	Status Register
- *    PCCR	Control Register
- *    PCSSR	Sleep State Register
- */
-
-#define SA1111_PCMCIA	0x1600
-
-/*
- * These are offsets from the above base.
- */
-#define SA1111_PCCR	0x0000
-#define SA1111_PCSSR	0x0004
-#define SA1111_PCSR	0x0008
-
-#define PCSR_S0_READY	(1<<0)
-#define PCSR_S1_READY	(1<<1)
-#define PCSR_S0_DETECT	(1<<2)
-#define PCSR_S1_DETECT	(1<<3)
-#define PCSR_S0_VS1	(1<<4)
-#define PCSR_S0_VS2	(1<<5)
-#define PCSR_S1_VS1	(1<<6)
-#define PCSR_S1_VS2	(1<<7)
-#define PCSR_S0_WP	(1<<8)
-#define PCSR_S1_WP	(1<<9)
-#define PCSR_S0_BVD1	(1<<10)
-#define PCSR_S0_BVD2	(1<<11)
-#define PCSR_S1_BVD1	(1<<12)
-#define PCSR_S1_BVD2	(1<<13)
-
-#define PCCR_S0_RST	(1<<0)
-#define PCCR_S1_RST	(1<<1)
-#define PCCR_S0_FLT	(1<<2)
-#define PCCR_S1_FLT	(1<<3)
-#define PCCR_S0_PWAITEN	(1<<4)
-#define PCCR_S1_PWAITEN	(1<<5)
-#define PCCR_S0_PSE	(1<<6)
-#define PCCR_S1_PSE	(1<<7)
-
-#define PCSSR_S0_SLEEP	(1<<0)
-#define PCSSR_S1_SLEEP	(1<<1)
 
 
 
 
 extern struct bus_type sa1111_bus_type;
 
-#define SA1111_DEVID_SBI	0
-#define SA1111_DEVID_SK		1
-#define SA1111_DEVID_USB	2
-#define SA1111_DEVID_SAC	3
-#define SA1111_DEVID_SSP	4
-#define SA1111_DEVID_PS2	5
-#define SA1111_DEVID_GPIO	6
-#define SA1111_DEVID_INT	7
-#define SA1111_DEVID_PCMCIA	8
+#define SA1111_DEVID_SBI	(1 << 0)
+#define SA1111_DEVID_SK		(1 << 1)
+#define SA1111_DEVID_USB	(1 << 2)
+#define SA1111_DEVID_SAC	(1 << 3)
+#define SA1111_DEVID_SSP	(1 << 4)
+#define SA1111_DEVID_PS2	(3 << 5)
+#define SA1111_DEVID_PS2_KBD	(1 << 5)
+#define SA1111_DEVID_PS2_MSE	(1 << 6)
+#define SA1111_DEVID_GPIO	(1 << 7)
+#define SA1111_DEVID_INT	(1 << 8)
+#define SA1111_DEVID_PCMCIA	(1 << 9)
 
 struct sa1111_dev {
 	struct device	dev;
@@ -548,6 +432,7 @@
 	int (*remove)(struct sa1111_dev *);
 	int (*suspend)(struct sa1111_dev *, pm_message_t);
 	int (*resume)(struct sa1111_dev *);
+	void (*shutdown)(struct sa1111_dev *);
 };
 
 #define SA1111_DRV(_d)	container_of((_d), struct sa1111_driver, drv)
@@ -555,9 +440,10 @@
 #define SA1111_DRIVER_NAME(_sadev) ((_sadev)->dev.driver->name)
 
 /*
- * These frob the SKPCR register.
+ * These frob the SKPCR register, and call platform specific
+ * enable/disable functions.
  */
-void sa1111_enable_device(struct sa1111_dev *);
+int sa1111_enable_device(struct sa1111_dev *);
 void sa1111_disable_device(struct sa1111_dev *);
 
 unsigned int sa1111_pll_clock(struct sa1111_dev *);
@@ -580,6 +466,10 @@
 
 struct sa1111_platform_data {
 	int	irq_base;	/* base for cascaded on-chip IRQs */
+	unsigned disable_devs;
+	void	*data;
+	int	(*enable)(void *, unsigned);
+	void	(*disable)(void *, unsigned);
 };
 
 #endif  /* _ASM_ARCH_SA1111 */
diff --git a/arch/arm/include/asm/hardware/timer-sp.h b/arch/arm/include/asm/hardware/timer-sp.h
index 4384d81..2dd9d3f 100644
--- a/arch/arm/include/asm/hardware/timer-sp.h
+++ b/arch/arm/include/asm/hardware/timer-sp.h
@@ -1,2 +1,15 @@
-void sp804_clocksource_init(void __iomem *, const char *);
+void __sp804_clocksource_and_sched_clock_init(void __iomem *,
+					      const char *, int);
+
+static inline void sp804_clocksource_init(void __iomem *base, const char *name)
+{
+	__sp804_clocksource_and_sched_clock_init(base, name, 0);
+}
+
+static inline void sp804_clocksource_and_sched_clock_init(void __iomem *base,
+							  const char *name)
+{
+	__sp804_clocksource_and_sched_clock_init(base, name, 1);
+}
+
 void sp804_clockevents_init(void __iomem *, unsigned int, const char *);
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 9275828..9af5563 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -26,7 +26,6 @@
 #include <linux/types.h>
 #include <asm/byteorder.h>
 #include <asm/memory.h>
-#include <asm/system.h>
 #include <asm-generic/pci_iomap.h>
 
 /*
@@ -83,6 +82,11 @@
 extern void __iomem *__arm_ioremap(unsigned long, size_t, unsigned int);
 extern void __iomem *__arm_ioremap_exec(unsigned long, size_t, bool cached);
 extern void __iounmap(volatile void __iomem *addr);
+extern void __arm_iounmap(volatile void __iomem *addr);
+
+extern void __iomem * (*arch_ioremap_caller)(unsigned long, size_t,
+	unsigned int, void *);
+extern void (*arch_iounmap)(volatile void __iomem *);
 
 /*
  * Bad read/write accesses...
@@ -97,8 +101,11 @@
 	return (void __iomem *)addr;
 }
 
+#define IOMEM(x)	((void __force __iomem *)(x))
+
 /* IO barriers */
 #ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
+#include <asm/barrier.h>
 #define __iormb()		rmb()
 #define __iowmb()		wmb()
 #else
@@ -109,7 +116,11 @@
 /*
  * Now, pick up the machine-defined IO definitions
  */
+#ifdef CONFIG_NEED_MACH_IO_H
 #include <mach/io.h>
+#else
+#define __io(a)		__typesafe_io((a) & IO_SPACE_LIMIT)
+#endif
 
 /*
  * This is the limit of PC card/PCI/ISA IO space, which is by default
@@ -211,18 +222,18 @@
  * Again, this are defined to perform little endian accesses.  See the
  * IO port primitives for more information.
  */
-#ifdef __mem_pci
-#define readb_relaxed(c) ({ u8  __r = __raw_readb(__mem_pci(c)); __r; })
+#ifndef readl
+#define readb_relaxed(c) ({ u8  __r = __raw_readb(c); __r; })
 #define readw_relaxed(c) ({ u16 __r = le16_to_cpu((__force __le16) \
-					__raw_readw(__mem_pci(c))); __r; })
+					__raw_readw(c)); __r; })
 #define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
-					__raw_readl(__mem_pci(c))); __r; })
+					__raw_readl(c)); __r; })
 
-#define writeb_relaxed(v,c)	((void)__raw_writeb(v,__mem_pci(c)))
+#define writeb_relaxed(v,c)	((void)__raw_writeb(v,c))
 #define writew_relaxed(v,c)	((void)__raw_writew((__force u16) \
-					cpu_to_le16(v),__mem_pci(c)))
+					cpu_to_le16(v),c))
 #define writel_relaxed(v,c)	((void)__raw_writel((__force u32) \
-					cpu_to_le32(v),__mem_pci(c)))
+					cpu_to_le32(v),c))
 
 #define readb(c)		({ u8  __v = readb_relaxed(c); __iormb(); __v; })
 #define readw(c)		({ u16 __v = readw_relaxed(c); __iormb(); __v; })
@@ -232,30 +243,19 @@
 #define writew(v,c)		({ __iowmb(); writew_relaxed(v,c); })
 #define writel(v,c)		({ __iowmb(); writel_relaxed(v,c); })
 
-#define readsb(p,d,l)		__raw_readsb(__mem_pci(p),d,l)
-#define readsw(p,d,l)		__raw_readsw(__mem_pci(p),d,l)
-#define readsl(p,d,l)		__raw_readsl(__mem_pci(p),d,l)
+#define readsb(p,d,l)		__raw_readsb(p,d,l)
+#define readsw(p,d,l)		__raw_readsw(p,d,l)
+#define readsl(p,d,l)		__raw_readsl(p,d,l)
 
-#define writesb(p,d,l)		__raw_writesb(__mem_pci(p),d,l)
-#define writesw(p,d,l)		__raw_writesw(__mem_pci(p),d,l)
-#define writesl(p,d,l)		__raw_writesl(__mem_pci(p),d,l)
+#define writesb(p,d,l)		__raw_writesb(p,d,l)
+#define writesw(p,d,l)		__raw_writesw(p,d,l)
+#define writesl(p,d,l)		__raw_writesl(p,d,l)
 
-#define memset_io(c,v,l)	_memset_io(__mem_pci(c),(v),(l))
-#define memcpy_fromio(a,c,l)	_memcpy_fromio((a),__mem_pci(c),(l))
-#define memcpy_toio(c,a,l)	_memcpy_toio(__mem_pci(c),(a),(l))
+#define memset_io(c,v,l)	_memset_io(c,(v),(l))
+#define memcpy_fromio(a,c,l)	_memcpy_fromio((a),c,(l))
+#define memcpy_toio(c,a,l)	_memcpy_toio(c,(a),(l))
 
-#elif !defined(readb)
-
-#define readb(c)			(__readwrite_bug("readb"),0)
-#define readw(c)			(__readwrite_bug("readw"),0)
-#define readl(c)			(__readwrite_bug("readl"),0)
-#define writeb(v,c)			__readwrite_bug("writeb")
-#define writew(v,c)			__readwrite_bug("writew")
-#define writel(v,c)			__readwrite_bug("writel")
-
-#define check_signature(io,sig,len)	(0)
-
-#endif	/* __mem_pci */
+#endif	/* readl */
 
 /*
  * ioremap and friends.
@@ -264,16 +264,11 @@
  * Documentation/io-mapping.txt.
  *
  */
-#ifndef __arch_ioremap
-#define __arch_ioremap			__arm_ioremap
-#define __arch_iounmap			__iounmap
-#endif
-
-#define ioremap(cookie,size)		__arch_ioremap((cookie), (size), MT_DEVICE)
-#define ioremap_nocache(cookie,size)	__arch_ioremap((cookie), (size), MT_DEVICE)
-#define ioremap_cached(cookie,size)	__arch_ioremap((cookie), (size), MT_DEVICE_CACHED)
-#define ioremap_wc(cookie,size)		__arch_ioremap((cookie), (size), MT_DEVICE_WC)
-#define iounmap				__arch_iounmap
+#define ioremap(cookie,size)		__arm_ioremap((cookie), (size), MT_DEVICE)
+#define ioremap_nocache(cookie,size)	__arm_ioremap((cookie), (size), MT_DEVICE)
+#define ioremap_cached(cookie,size)	__arm_ioremap((cookie), (size), MT_DEVICE_CACHED)
+#define ioremap_wc(cookie,size)		__arm_ioremap((cookie), (size), MT_DEVICE_WC)
+#define iounmap				__arm_iounmap
 
 /*
  * io{read,write}{8,16,32} macros
diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index 5a526af..35c21c3 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -1,14 +1,18 @@
 #ifndef __ASM_ARM_IRQ_H
 #define __ASM_ARM_IRQ_H
 
+#define NR_IRQS_LEGACY	16
+
+#ifndef CONFIG_SPARSE_IRQ
 #include <mach/irqs.h>
+#else
+#define NR_IRQS NR_IRQS_LEGACY
+#endif
 
 #ifndef irq_canonicalize
 #define irq_canonicalize(i)	(i)
 #endif
 
-#define NR_IRQS_LEGACY	16
-
 /*
  * Use this value to indicate lack of interrupt
  * capability
diff --git a/arch/arm/include/asm/jump_label.h b/arch/arm/include/asm/jump_label.h
new file mode 100644
index 0000000..5c5ca2e
--- /dev/null
+++ b/arch/arm/include/asm/jump_label.h
@@ -0,0 +1,41 @@
+#ifndef _ASM_ARM_JUMP_LABEL_H
+#define _ASM_ARM_JUMP_LABEL_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <asm/system.h>
+
+#define JUMP_LABEL_NOP_SIZE 4
+
+#ifdef CONFIG_THUMB2_KERNEL
+#define JUMP_LABEL_NOP	"nop.w"
+#else
+#define JUMP_LABEL_NOP	"nop"
+#endif
+
+static __always_inline bool arch_static_branch(struct jump_label_key *key)
+{
+	asm goto("1:\n\t"
+		 JUMP_LABEL_NOP "\n\t"
+		 ".pushsection __jump_table,  \"aw\"\n\t"
+		 ".word 1b, %l[l_yes], %c0\n\t"
+		 ".popsection\n\t"
+		 : :  "i" (key) :  : l_yes);
+
+	return false;
+l_yes:
+	return true;
+}
+
+#endif /* __KERNEL__ */
+
+typedef u32 jump_label_t;
+
+struct jump_entry {
+	jump_label_t code;
+	jump_label_t target;
+	jump_label_t key;
+};
+
+#endif
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
index c6a1842..f77ffc1 100644
--- a/arch/arm/include/asm/localtimer.h
+++ b/arch/arm/include/asm/localtimer.h
@@ -11,47 +11,24 @@
 #define __ASM_ARM_LOCALTIMER_H
 
 #include <linux/errno.h>
-#include <linux/interrupt.h>
 
 struct clock_event_device;
 
-/*
- * Setup a per-cpu timer, whether it be a local timer or dummy broadcast
- */
-void percpu_timer_setup(void);
+struct local_timer_ops {
+	int  (*setup)(struct clock_event_device *);
+	void (*stop)(struct clock_event_device *);
+};
 
 #ifdef CONFIG_LOCAL_TIMERS
-
-#ifdef CONFIG_HAVE_ARM_TWD
-
-#include "smp_twd.h"
-
-#define local_timer_stop(c)	twd_timer_stop((c))
-
-#else
-
 /*
- * Stop the local timer
+ * Register a local timer driver
  */
-void local_timer_stop(struct clock_event_device *);
-
-#endif
-
-/*
- * Setup a local timer interrupt for a CPU.
- */
-int local_timer_setup(struct clock_event_device *);
-
+int local_timer_register(struct local_timer_ops *);
 #else
-
-static inline int local_timer_setup(struct clock_event_device *evt)
+static inline int local_timer_register(struct local_timer_ops *ops)
 {
 	return -ENXIO;
 }
-
-static inline void local_timer_stop(struct clock_event_device *evt)
-{
-}
 #endif
 
 #endif
diff --git a/arch/arm/include/asm/mc146818rtc.h b/arch/arm/include/asm/mc146818rtc.h
index 6b884d2..e8567bb 100644
--- a/arch/arm/include/asm/mc146818rtc.h
+++ b/arch/arm/include/asm/mc146818rtc.h
@@ -5,7 +5,9 @@
 #define _ASM_MC146818RTC_H
 
 #include <linux/io.h>
-#include <mach/irqs.h>
+#include <linux/kernel.h>
+
+#define RTC_IRQ BUILD_BUG_ON(1)
 
 #ifndef RTC_PORT
 #define RTC_PORT(x)	(0x70 + (x))
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index a8997d7..fcb5757 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -116,6 +116,8 @@
 #define MODULES_END		(END_MEM)
 #define MODULES_VADDR		(PHYS_OFFSET)
 
+#define XIP_VIRT_ADDR(physaddr)  (physaddr)
+
 #endif /* !CONFIG_MMU */
 
 /*
diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
index 1496565..b8e580a 100644
--- a/arch/arm/include/asm/mmu.h
+++ b/arch/arm/include/asm/mmu.h
@@ -34,4 +34,11 @@
 
 #endif
 
+/*
+ * switch_mm() may do a full cache flush over the context switch,
+ * so enable interrupts over the context switch to avoid high
+ * latency.
+ */
+#define __ARCH_WANT_INTERRUPTS_ON_CTXSW
+
 #endif
diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h
index 71605d9..a0b3cac 100644
--- a/arch/arm/include/asm/mmu_context.h
+++ b/arch/arm/include/asm/mmu_context.h
@@ -18,6 +18,7 @@
 #include <asm/cacheflush.h>
 #include <asm/cachetype.h>
 #include <asm/proc-fns.h>
+#include <asm-generic/mm_hooks.h>
 
 void __check_kvm_seq(struct mm_struct *mm);
 
@@ -133,32 +134,4 @@
 #define deactivate_mm(tsk,mm)	do { } while (0)
 #define activate_mm(prev,next)	switch_mm(prev, next, NULL)
 
-/*
- * We are inserting a "fake" vma for the user-accessible vector page so
- * gdb and friends can get to it through ptrace and /proc/<pid>/mem.
- * But we also want to remove it before the generic code gets to see it
- * during process exit or the unmapping of it would  cause total havoc.
- * (the macro is used as remove_vma() is static to mm/mmap.c)
- */
-#define arch_exit_mmap(mm) \
-do { \
-	struct vm_area_struct *high_vma = find_vma(mm, 0xffff0000); \
-	if (high_vma) { \
-		BUG_ON(high_vma->vm_next);  /* it should be last */ \
-		if (high_vma->vm_prev) \
-			high_vma->vm_prev->vm_next = NULL; \
-		else \
-			mm->mmap = NULL; \
-		rb_erase(&high_vma->vm_rb, &mm->mm_rb); \
-		mm->mmap_cache = NULL; \
-		mm->map_count--; \
-		remove_vma(high_vma); \
-	} \
-} while (0)
-
-static inline void arch_dup_mmap(struct mm_struct *oldmm,
-				 struct mm_struct *mm)
-{
-}
-
 #endif
diff --git a/arch/arm/include/asm/opcodes.h b/arch/arm/include/asm/opcodes.h
index c0efdd6..19c48de 100644
--- a/arch/arm/include/asm/opcodes.h
+++ b/arch/arm/include/asm/opcodes.h
@@ -17,4 +17,63 @@
 #define ARM_OPCODE_CONDTEST_PASS   1
 #define ARM_OPCODE_CONDTEST_UNCOND 2
 
+
+/*
+ * Opcode byteswap helpers
+ *
+ * These macros help with converting instructions between a canonical integer
+ * format and in-memory representation, in an endianness-agnostic manner.
+ *
+ * __mem_to_opcode_*() convert from in-memory representation to canonical form.
+ * __opcode_to_mem_*() convert from canonical form to in-memory representation.
+ *
+ *
+ * Canonical instruction representation:
+ *
+ *	ARM:		0xKKLLMMNN
+ *	Thumb 16-bit:	0x0000KKLL, where KK < 0xE8
+ *	Thumb 32-bit:	0xKKLLMMNN, where KK >= 0xE8
+ *
+ * There is no way to distinguish an ARM instruction in canonical representation
+ * from a Thumb instruction (just as these cannot be distinguished in memory).
+ * Where this distinction is important, it needs to be tracked separately.
+ *
+ * Note that values in the range 0x0000E800..0xE7FFFFFF intentionally do not
+ * represent any valid Thumb-2 instruction.  For this range,
+ * __opcode_is_thumb32() and __opcode_is_thumb16() will both be false.
+ */
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+#include <linux/swab.h>
+
+#ifdef CONFIG_CPU_ENDIAN_BE8
+#define __opcode_to_mem_arm(x) swab32(x)
+#define __opcode_to_mem_thumb16(x) swab16(x)
+#define __opcode_to_mem_thumb32(x) swahb32(x)
+#else
+#define __opcode_to_mem_arm(x) ((u32)(x))
+#define __opcode_to_mem_thumb16(x) ((u16)(x))
+#define __opcode_to_mem_thumb32(x) swahw32(x)
+#endif
+
+#define __mem_to_opcode_arm(x) __opcode_to_mem_arm(x)
+#define __mem_to_opcode_thumb16(x) __opcode_to_mem_thumb16(x)
+#define __mem_to_opcode_thumb32(x) __opcode_to_mem_thumb32(x)
+
+/* Operations specific to Thumb opcodes */
+
+/* Instruction size checks: */
+#define __opcode_is_thumb32(x) ((u32)(x) >= 0xE8000000UL)
+#define __opcode_is_thumb16(x) ((u32)(x) < 0xE800UL)
+
+/* Operations to construct or split 32-bit Thumb instructions: */
+#define __opcode_thumb32_first(x) ((u16)((x) >> 16))
+#define __opcode_thumb32_second(x) ((u16)(x))
+#define __opcode_thumb32_compose(first, second) \
+	(((u32)(u16)(first) << 16) | (u32)(u16)(second))
+
+#endif /* __ASSEMBLY__ */
+
 #endif /* __ASM_ARM_OPCODES_H */
diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
index 97b440c..5838361 100644
--- a/arch/arm/include/asm/page.h
+++ b/arch/arm/include/asm/page.h
@@ -151,6 +151,8 @@
 #define clear_page(page)	memset((void *)(page), 0, PAGE_SIZE)
 extern void copy_page(void *to, const void *from);
 
+#define __HAVE_ARCH_GATE_AREA 1
+
 #ifdef CONFIG_ARM_LPAE
 #include <asm/pgtable-3level-types.h>
 #else
diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h
index da337ba..a98a2e1 100644
--- a/arch/arm/include/asm/pci.h
+++ b/arch/arm/include/asm/pci.h
@@ -57,14 +57,6 @@
 extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                                enum pci_mmap_state mmap_state, int write_combine);
 
-extern void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-			 struct resource *res);
-
-extern void
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-			struct pci_bus_region *region);
-
 /*
  * Dummy implementation; always return 0.
  */
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
index 7523340..00cbe10 100644
--- a/arch/arm/include/asm/perf_event.h
+++ b/arch/arm/include/asm/perf_event.h
@@ -22,6 +22,7 @@
 	ARM_PERF_PMU_ID_CA9,
 	ARM_PERF_PMU_ID_CA5,
 	ARM_PERF_PMU_ID_CA15,
+	ARM_PERF_PMU_ID_CA7,
 	ARM_NUM_PMU_IDS,
 };
 
diff --git a/arch/arm/include/asm/pgtable-nommu.h b/arch/arm/include/asm/pgtable-nommu.h
index ffc0e857..7ec60d60 100644
--- a/arch/arm/include/asm/pgtable-nommu.h
+++ b/arch/arm/include/asm/pgtable-nommu.h
@@ -79,7 +79,6 @@
  * No page table caches to initialise.
  */
 #define pgtable_cache_init()	do { } while (0)
-#define io_remap_page_range	remap_page_range
 #define io_remap_pfn_range	remap_pfn_range
 
 
diff --git a/arch/arm/include/asm/posix_types.h b/arch/arm/include/asm/posix_types.h
index 2446d23..efdf990 100644
--- a/arch/arm/include/asm/posix_types.h
+++ b/arch/arm/include/asm/posix_types.h
@@ -19,59 +19,22 @@
  * assume GCC is being used.
  */
 
-typedef unsigned long		__kernel_ino_t;
 typedef unsigned short		__kernel_mode_t;
+#define __kernel_mode_t __kernel_mode_t
+
 typedef unsigned short		__kernel_nlink_t;
-typedef long			__kernel_off_t;
-typedef int			__kernel_pid_t;
+#define __kernel_nlink_t __kernel_nlink_t
+
 typedef unsigned short		__kernel_ipc_pid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
+
 typedef unsigned short		__kernel_uid_t;
 typedef unsigned short		__kernel_gid_t;
-typedef unsigned int		__kernel_size_t;
-typedef int			__kernel_ssize_t;
-typedef int			__kernel_ptrdiff_t;
-typedef long			__kernel_time_t;
-typedef long			__kernel_suseconds_t;
-typedef long			__kernel_clock_t;
-typedef int			__kernel_timer_t;
-typedef int			__kernel_clockid_t;
-typedef int			__kernel_daddr_t;
-typedef char *			__kernel_caddr_t;
-typedef unsigned short		__kernel_uid16_t;
-typedef unsigned short		__kernel_gid16_t;
-typedef unsigned int		__kernel_uid32_t;
-typedef unsigned int		__kernel_gid32_t;
+#define __kernel_uid_t __kernel_uid_t
 
-typedef unsigned short		__kernel_old_uid_t;
-typedef unsigned short		__kernel_old_gid_t;
 typedef unsigned short		__kernel_old_dev_t;
+#define __kernel_old_dev_t __kernel_old_dev_t
 
-#ifdef __GNUC__
-typedef long long		__kernel_loff_t;
-#endif
-
-typedef struct {
-	int	val[2];
-} __kernel_fsid_t;
-
-#if defined(__KERNEL__)
-
-#undef	__FD_SET
-#define __FD_SET(fd, fdsetp) \
-		(((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] |= (1<<((fd) & 31)))
-
-#undef	__FD_CLR
-#define __FD_CLR(fd, fdsetp) \
-		(((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] &= ~(1<<((fd) & 31)))
-
-#undef	__FD_ISSET
-#define __FD_ISSET(fd, fdsetp) \
-		((((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] & (1<<((fd) & 31))) != 0)
-
-#undef	__FD_ZERO
-#define __FD_ZERO(fdsetp) \
-		(memset (fdsetp, 0, sizeof (*(fd_set *)(fdsetp))))
-
-#endif
+#include <asm-generic/posix_types.h>
 
 #endif
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index cb8d638..5ac8d3d 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -22,7 +22,6 @@
 #include <asm/hw_breakpoint.h>
 #include <asm/ptrace.h>
 #include <asm/types.h>
-#include <asm/system.h>
 
 #ifdef __KERNEL__
 #define STACK_TOP	((current->personality & ADDR_LIMIT_32BIT) ? \
@@ -56,7 +55,6 @@
 #define start_thread(regs,pc,sp)					\
 ({									\
 	unsigned long *stack = (unsigned long *)sp;			\
-	set_fs(USER_DS);						\
 	memset(regs->uregs, 0, sizeof(regs->uregs));			\
 	if (current->personality & ADDR_LIMIT_32BIT)			\
 		regs->ARM_cpsr = USR_MODE;				\
@@ -90,6 +88,8 @@
 #define cpu_relax()			barrier()
 #endif
 
+void cpu_idle_wait(void);
+
 /*
  * Create a new kernel thread
  */
diff --git a/arch/arm/include/asm/prom.h b/arch/arm/include/asm/prom.h
index ee03633..aeae9c6 100644
--- a/arch/arm/include/asm/prom.h
+++ b/arch/arm/include/asm/prom.h
@@ -13,8 +13,6 @@
 
 #ifdef CONFIG_OF
 
-#include <asm/irq.h>
-
 extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys);
 extern void arm_dt_memblock_reserve(void);
 
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
index ef9ffba9..0f01f46 100644
--- a/arch/arm/include/asm/smp_twd.h
+++ b/arch/arm/include/asm/smp_twd.h
@@ -18,11 +18,28 @@
 #define TWD_TIMER_CONTROL_PERIODIC	(1 << 1)
 #define TWD_TIMER_CONTROL_IT_ENABLE	(1 << 2)
 
-struct clock_event_device;
+#include <linux/ioport.h>
 
-extern void __iomem *twd_base;
+struct twd_local_timer {
+	struct resource	res[2];
+};
 
-void twd_timer_setup(struct clock_event_device *);
-void twd_timer_stop(struct clock_event_device *);
+#define DEFINE_TWD_LOCAL_TIMER(name,base,irq)	\
+struct twd_local_timer name __initdata = {	\
+	.res	= {				\
+		DEFINE_RES_MEM(base, 0x10),	\
+		DEFINE_RES_IRQ(irq),		\
+	},					\
+};
+
+int twd_local_timer_register(struct twd_local_timer *);
+
+#ifdef CONFIG_HAVE_ARM_TWD
+void twd_local_timer_of_register(void);
+#else
+static inline void twd_local_timer_of_register(void)
+{
+}
+#endif
 
 #endif
diff --git a/arch/arm/include/asm/switch_to.h b/arch/arm/include/asm/switch_to.h
new file mode 100644
index 0000000..fa09e6b
--- /dev/null
+++ b/arch/arm/include/asm/switch_to.h
@@ -0,0 +1,18 @@
+#ifndef __ASM_ARM_SWITCH_TO_H
+#define __ASM_ARM_SWITCH_TO_H
+
+#include <linux/thread_info.h>
+
+/*
+ * switch_to(prev, next) should switch from task `prev' to `next'
+ * `prev' will never be the same as `next'.  schedule() itself
+ * contains the memory barrier to tell GCC not to cache `current'.
+ */
+extern struct task_struct *__switch_to(struct task_struct *, struct thread_info *, struct thread_info *);
+
+#define switch_to(prev,next,last)					\
+do {									\
+	last = __switch_to(prev,task_thread_info(prev), task_thread_info(next));	\
+} while (0)
+
+#endif /* __ASM_ARM_SWITCH_TO_H */
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index e4c96cc..74542c5 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -1,543 +1,8 @@
-#ifndef __ASM_ARM_SYSTEM_H
-#define __ASM_ARM_SYSTEM_H
-
-#ifdef __KERNEL__
-
-#define CPU_ARCH_UNKNOWN	0
-#define CPU_ARCH_ARMv3		1
-#define CPU_ARCH_ARMv4		2
-#define CPU_ARCH_ARMv4T		3
-#define CPU_ARCH_ARMv5		4
-#define CPU_ARCH_ARMv5T		5
-#define CPU_ARCH_ARMv5TE	6
-#define CPU_ARCH_ARMv5TEJ	7
-#define CPU_ARCH_ARMv6		8
-#define CPU_ARCH_ARMv7		9
-
-/*
- * CR1 bits (CP#15 CR1)
- */
-#define CR_M	(1 << 0)	/* MMU enable				*/
-#define CR_A	(1 << 1)	/* Alignment abort enable		*/
-#define CR_C	(1 << 2)	/* Dcache enable			*/
-#define CR_W	(1 << 3)	/* Write buffer enable			*/
-#define CR_P	(1 << 4)	/* 32-bit exception handler		*/
-#define CR_D	(1 << 5)	/* 32-bit data address range		*/
-#define CR_L	(1 << 6)	/* Implementation defined		*/
-#define CR_B	(1 << 7)	/* Big endian				*/
-#define CR_S	(1 << 8)	/* System MMU protection		*/
-#define CR_R	(1 << 9)	/* ROM MMU protection			*/
-#define CR_F	(1 << 10)	/* Implementation defined		*/
-#define CR_Z	(1 << 11)	/* Implementation defined		*/
-#define CR_I	(1 << 12)	/* Icache enable			*/
-#define CR_V	(1 << 13)	/* Vectors relocated to 0xffff0000	*/
-#define CR_RR	(1 << 14)	/* Round Robin cache replacement	*/
-#define CR_L4	(1 << 15)	/* LDR pc can set T bit			*/
-#define CR_DT	(1 << 16)
-#define CR_IT	(1 << 18)
-#define CR_ST	(1 << 19)
-#define CR_FI	(1 << 21)	/* Fast interrupt (lower latency mode)	*/
-#define CR_U	(1 << 22)	/* Unaligned access operation		*/
-#define CR_XP	(1 << 23)	/* Extended page tables			*/
-#define CR_VE	(1 << 24)	/* Vectored interrupts			*/
-#define CR_EE	(1 << 25)	/* Exception (Big) Endian		*/
-#define CR_TRE	(1 << 28)	/* TEX remap enable			*/
-#define CR_AFE	(1 << 29)	/* Access flag enable			*/
-#define CR_TE	(1 << 30)	/* Thumb exception enable		*/
-
-/*
- * This is used to ensure the compiler did actually allocate the register we
- * asked it for some inline assembly sequences.  Apparently we can't trust
- * the compiler from one version to another so a bit of paranoia won't hurt.
- * This string is meant to be concatenated with the inline asm string and
- * will cause compilation to stop on mismatch.
- * (for details, see gcc PR 15089)
- */
-#define __asmeq(x, y)  ".ifnc " x "," y " ; .err ; .endif\n\t"
-
-#ifndef __ASSEMBLY__
-
-#include <linux/compiler.h>
-#include <linux/linkage.h>
-#include <linux/irqflags.h>
-
-#include <asm/outercache.h>
-
-struct thread_info;
-struct task_struct;
-
-/* information about the system we're running on */
-extern unsigned int system_rev;
-extern unsigned int system_serial_low;
-extern unsigned int system_serial_high;
-extern unsigned int mem_fclk_21285;
-
-struct pt_regs;
-
-void die(const char *msg, struct pt_regs *regs, int err);
-
-struct siginfo;
-void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
-		unsigned long err, unsigned long trap);
-
-#ifdef CONFIG_ARM_LPAE
-#define FAULT_CODE_ALIGNMENT	33
-#define FAULT_CODE_DEBUG	34
-#else
-#define FAULT_CODE_ALIGNMENT	1
-#define FAULT_CODE_DEBUG	2
-#endif
-
-void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
-				       struct pt_regs *),
-		     int sig, int code, const char *name);
-
-void hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int,
-				       struct pt_regs *),
-		     int sig, int code, const char *name);
-
-#define xchg(ptr,x) \
-	((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-
-extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
-
-struct mm_struct;
-extern void show_pte(struct mm_struct *mm, unsigned long addr);
-extern void __show_regs(struct pt_regs *);
-
-extern int __pure cpu_architecture(void);
-extern void cpu_init(void);
-
-void soft_restart(unsigned long);
-extern void (*arm_pm_restart)(char str, const char *cmd);
-
-#define UDBG_UNDEFINED	(1 << 0)
-#define UDBG_SYSCALL	(1 << 1)
-#define UDBG_BADABORT	(1 << 2)
-#define UDBG_SEGV	(1 << 3)
-#define UDBG_BUS	(1 << 4)
-
-extern unsigned int user_debug;
-
-#if __LINUX_ARM_ARCH__ >= 4
-#define vectors_high()	(cr_alignment & CR_V)
-#else
-#define vectors_high()	(0)
-#endif
-
-#if __LINUX_ARM_ARCH__ >= 7 ||		\
-	(__LINUX_ARM_ARCH__ == 6 && defined(CONFIG_CPU_32v6K))
-#define sev()	__asm__ __volatile__ ("sev" : : : "memory")
-#define wfe()	__asm__ __volatile__ ("wfe" : : : "memory")
-#define wfi()	__asm__ __volatile__ ("wfi" : : : "memory")
-#endif
-
-#if __LINUX_ARM_ARCH__ >= 7
-#define isb() __asm__ __volatile__ ("isb" : : : "memory")
-#define dsb() __asm__ __volatile__ ("dsb" : : : "memory")
-#define dmb() __asm__ __volatile__ ("dmb" : : : "memory")
-#elif defined(CONFIG_CPU_XSC3) || __LINUX_ARM_ARCH__ == 6
-#define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
-				    : : "r" (0) : "memory")
-#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
-				    : : "r" (0) : "memory")
-#define dmb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
-				    : : "r" (0) : "memory")
-#elif defined(CONFIG_CPU_FA526)
-#define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
-				    : : "r" (0) : "memory")
-#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
-				    : : "r" (0) : "memory")
-#define dmb() __asm__ __volatile__ ("" : : : "memory")
-#else
-#define isb() __asm__ __volatile__ ("" : : : "memory")
-#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
-				    : : "r" (0) : "memory")
-#define dmb() __asm__ __volatile__ ("" : : : "memory")
-#endif
-
-#ifdef CONFIG_ARCH_HAS_BARRIERS
-#include <mach/barriers.h>
-#elif defined(CONFIG_ARM_DMA_MEM_BUFFERABLE) || defined(CONFIG_SMP)
-#define mb()		do { dsb(); outer_sync(); } while (0)
-#define rmb()		dsb()
-#define wmb()		mb()
-#else
-#include <asm/memory.h>
-#define mb()	do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
-#define rmb()	do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
-#define wmb()	do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
-#endif
-
-#ifndef CONFIG_SMP
-#define smp_mb()	barrier()
-#define smp_rmb()	barrier()
-#define smp_wmb()	barrier()
-#else
-#define smp_mb()	dmb()
-#define smp_rmb()	dmb()
-#define smp_wmb()	dmb()
-#endif
-
-#define read_barrier_depends()		do { } while(0)
-#define smp_read_barrier_depends()	do { } while(0)
-
-#define set_mb(var, value)	do { var = value; smp_mb(); } while (0)
-#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
-
-extern unsigned long cr_no_alignment;	/* defined in entry-armv.S */
-extern unsigned long cr_alignment;	/* defined in entry-armv.S */
-
-static inline unsigned int get_cr(void)
-{
-	unsigned int val;
-	asm("mrc p15, 0, %0, c1, c0, 0	@ get CR" : "=r" (val) : : "cc");
-	return val;
-}
-
-static inline void set_cr(unsigned int val)
-{
-	asm volatile("mcr p15, 0, %0, c1, c0, 0	@ set CR"
-	  : : "r" (val) : "cc");
-	isb();
-}
-
-#ifndef CONFIG_SMP
-extern void adjust_cr(unsigned long mask, unsigned long set);
-#endif
-
-#define CPACC_FULL(n)		(3 << (n * 2))
-#define CPACC_SVC(n)		(1 << (n * 2))
-#define CPACC_DISABLE(n)	(0 << (n * 2))
-
-static inline unsigned int get_copro_access(void)
-{
-	unsigned int val;
-	asm("mrc p15, 0, %0, c1, c0, 2 @ get copro access"
-	  : "=r" (val) : : "cc");
-	return val;
-}
-
-static inline void set_copro_access(unsigned int val)
-{
-	asm volatile("mcr p15, 0, %0, c1, c0, 2 @ set copro access"
-	  : : "r" (val) : "cc");
-	isb();
-}
-
-/*
- * switch_mm() may do a full cache flush over the context switch,
- * so enable interrupts over the context switch to avoid high
- * latency.
- */
-#define __ARCH_WANT_INTERRUPTS_ON_CTXSW
-
-/*
- * switch_to(prev, next) should switch from task `prev' to `next'
- * `prev' will never be the same as `next'.  schedule() itself
- * contains the memory barrier to tell GCC not to cache `current'.
- */
-extern struct task_struct *__switch_to(struct task_struct *, struct thread_info *, struct thread_info *);
-
-#define switch_to(prev,next,last)					\
-do {									\
-	last = __switch_to(prev,task_thread_info(prev), task_thread_info(next));	\
-} while (0)
-
-#if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110)
-/*
- * On the StrongARM, "swp" is terminally broken since it bypasses the
- * cache totally.  This means that the cache becomes inconsistent, and,
- * since we use normal loads/stores as well, this is really bad.
- * Typically, this causes oopsen in filp_close, but could have other,
- * more disastrous effects.  There are two work-arounds:
- *  1. Disable interrupts and emulate the atomic swap
- *  2. Clean the cache, perform atomic swap, flush the cache
- *
- * We choose (1) since its the "easiest" to achieve here and is not
- * dependent on the processor type.
- *
- * NOTE that this solution won't work on an SMP system, so explcitly
- * forbid it here.
- */
-#define swp_is_buggy
-#endif
-
-static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
-{
-	extern void __bad_xchg(volatile void *, int);
-	unsigned long ret;
-#ifdef swp_is_buggy
-	unsigned long flags;
-#endif
-#if __LINUX_ARM_ARCH__ >= 6
-	unsigned int tmp;
-#endif
-
-	smp_mb();
-
-	switch (size) {
-#if __LINUX_ARM_ARCH__ >= 6
-	case 1:
-		asm volatile("@	__xchg1\n"
-		"1:	ldrexb	%0, [%3]\n"
-		"	strexb	%1, %2, [%3]\n"
-		"	teq	%1, #0\n"
-		"	bne	1b"
-			: "=&r" (ret), "=&r" (tmp)
-			: "r" (x), "r" (ptr)
-			: "memory", "cc");
-		break;
-	case 4:
-		asm volatile("@	__xchg4\n"
-		"1:	ldrex	%0, [%3]\n"
-		"	strex	%1, %2, [%3]\n"
-		"	teq	%1, #0\n"
-		"	bne	1b"
-			: "=&r" (ret), "=&r" (tmp)
-			: "r" (x), "r" (ptr)
-			: "memory", "cc");
-		break;
-#elif defined(swp_is_buggy)
-#ifdef CONFIG_SMP
-#error SMP is not supported on this platform
-#endif
-	case 1:
-		raw_local_irq_save(flags);
-		ret = *(volatile unsigned char *)ptr;
-		*(volatile unsigned char *)ptr = x;
-		raw_local_irq_restore(flags);
-		break;
-
-	case 4:
-		raw_local_irq_save(flags);
-		ret = *(volatile unsigned long *)ptr;
-		*(volatile unsigned long *)ptr = x;
-		raw_local_irq_restore(flags);
-		break;
-#else
-	case 1:
-		asm volatile("@	__xchg1\n"
-		"	swpb	%0, %1, [%2]"
-			: "=&r" (ret)
-			: "r" (x), "r" (ptr)
-			: "memory", "cc");
-		break;
-	case 4:
-		asm volatile("@	__xchg4\n"
-		"	swp	%0, %1, [%2]"
-			: "=&r" (ret)
-			: "r" (x), "r" (ptr)
-			: "memory", "cc");
-		break;
-#endif
-	default:
-		__bad_xchg(ptr, size), ret = 0;
-		break;
-	}
-	smp_mb();
-
-	return ret;
-}
-
-extern void disable_hlt(void);
-extern void enable_hlt(void);
-
-void cpu_idle_wait(void);
-
-#include <asm-generic/cmpxchg-local.h>
-
-#if __LINUX_ARM_ARCH__ < 6
-/* min ARCH < ARMv6 */
-
-#ifdef CONFIG_SMP
-#error "SMP is not supported on this platform"
-#endif
-
-/*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
- */
-#define cmpxchg_local(ptr, o, n)				  	       \
-	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
-			(unsigned long)(n), sizeof(*(ptr))))
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-
-#ifndef CONFIG_SMP
-#include <asm-generic/cmpxchg.h>
-#endif
-
-#else	/* min ARCH >= ARMv6 */
-
-extern void __bad_cmpxchg(volatile void *ptr, int size);
-
-/*
- * cmpxchg only support 32-bits operands on ARMv6.
- */
-
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-				      unsigned long new, int size)
-{
-	unsigned long oldval, res;
-
-	switch (size) {
-#ifndef CONFIG_CPU_V6	/* min ARCH >= ARMv6K */
-	case 1:
-		do {
-			asm volatile("@ __cmpxchg1\n"
-			"	ldrexb	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexbeq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
-	case 2:
-		do {
-			asm volatile("@ __cmpxchg1\n"
-			"	ldrexh	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexheq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
-#endif
-	case 4:
-		do {
-			asm volatile("@ __cmpxchg4\n"
-			"	ldrex	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexeq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
-	default:
-		__bad_cmpxchg(ptr, size);
-		oldval = 0;
-	}
-
-	return oldval;
-}
-
-static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
-					 unsigned long new, int size)
-{
-	unsigned long ret;
-
-	smp_mb();
-	ret = __cmpxchg(ptr, old, new, size);
-	smp_mb();
-
-	return ret;
-}
-
-#define cmpxchg(ptr,o,n)						\
-	((__typeof__(*(ptr)))__cmpxchg_mb((ptr),			\
-					  (unsigned long)(o),		\
-					  (unsigned long)(n),		\
-					  sizeof(*(ptr))))
-
-static inline unsigned long __cmpxchg_local(volatile void *ptr,
-					    unsigned long old,
-					    unsigned long new, int size)
-{
-	unsigned long ret;
-
-	switch (size) {
-#ifdef CONFIG_CPU_V6	/* min ARCH == ARMv6 */
-	case 1:
-	case 2:
-		ret = __cmpxchg_local_generic(ptr, old, new, size);
-		break;
-#endif
-	default:
-		ret = __cmpxchg(ptr, old, new, size);
-	}
-
-	return ret;
-}
-
-#define cmpxchg_local(ptr,o,n)						\
-	((__typeof__(*(ptr)))__cmpxchg_local((ptr),			\
-				       (unsigned long)(o),		\
-				       (unsigned long)(n),		\
-				       sizeof(*(ptr))))
-
-#ifndef CONFIG_CPU_V6	/* min ARCH >= ARMv6K */
-
-/*
- * Note : ARMv7-M (currently unsupported by Linux) does not support
- * ldrexd/strexd. If ARMv7-M is ever supported by the Linux kernel, it should
- * not be allowed to use __cmpxchg64.
- */
-static inline unsigned long long __cmpxchg64(volatile void *ptr,
-					     unsigned long long old,
-					     unsigned long long new)
-{
-	register unsigned long long oldval asm("r0");
-	register unsigned long long __old asm("r2") = old;
-	register unsigned long long __new asm("r4") = new;
-	unsigned long res;
-
-	do {
-		asm volatile(
-		"	@ __cmpxchg8\n"
-		"	ldrexd	%1, %H1, [%2]\n"
-		"	mov	%0, #0\n"
-		"	teq	%1, %3\n"
-		"	teqeq	%H1, %H3\n"
-		"	strexdeq %0, %4, %H4, [%2]\n"
-			: "=&r" (res), "=&r" (oldval)
-			: "r" (ptr), "Ir" (__old), "r" (__new)
-			: "memory", "cc");
-	} while (res);
-
-	return oldval;
-}
-
-static inline unsigned long long __cmpxchg64_mb(volatile void *ptr,
-						unsigned long long old,
-						unsigned long long new)
-{
-	unsigned long long ret;
-
-	smp_mb();
-	ret = __cmpxchg64(ptr, old, new);
-	smp_mb();
-
-	return ret;
-}
-
-#define cmpxchg64(ptr,o,n)						\
-	((__typeof__(*(ptr)))__cmpxchg64_mb((ptr),			\
-					    (unsigned long long)(o),	\
-					    (unsigned long long)(n)))
-
-#define cmpxchg64_local(ptr,o,n)					\
-	((__typeof__(*(ptr)))__cmpxchg64((ptr),				\
-					 (unsigned long long)(o),	\
-					 (unsigned long long)(n)))
-
-#else /* min ARCH = ARMv6 */
-
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-
-#endif
-
-#endif	/* __LINUX_ARM_ARCH__ >= 6 */
-
-#endif /* __ASSEMBLY__ */
-
-#define arch_align_stack(x) (x)
-
-#endif /* __KERNEL__ */
-
-#endif
+/* FILE TO BE DELETED. DO NOT ADD STUFF HERE! */
+#include <asm/barrier.h>
+#include <asm/compiler.h>
+#include <asm/cmpxchg.h>
+#include <asm/exec.h>
+#include <asm/switch_to.h>
+#include <asm/system_info.h>
+#include <asm/system_misc.h>
diff --git a/arch/arm/include/asm/system_info.h b/arch/arm/include/asm/system_info.h
new file mode 100644
index 0000000..dfd386d
--- /dev/null
+++ b/arch/arm/include/asm/system_info.h
@@ -0,0 +1,27 @@
+#ifndef __ASM_ARM_SYSTEM_INFO_H
+#define __ASM_ARM_SYSTEM_INFO_H
+
+#define CPU_ARCH_UNKNOWN	0
+#define CPU_ARCH_ARMv3		1
+#define CPU_ARCH_ARMv4		2
+#define CPU_ARCH_ARMv4T		3
+#define CPU_ARCH_ARMv5		4
+#define CPU_ARCH_ARMv5T		5
+#define CPU_ARCH_ARMv5TE	6
+#define CPU_ARCH_ARMv5TEJ	7
+#define CPU_ARCH_ARMv6		8
+#define CPU_ARCH_ARMv7		9
+
+#ifndef __ASSEMBLY__
+
+/* information about the system we're running on */
+extern unsigned int system_rev;
+extern unsigned int system_serial_low;
+extern unsigned int system_serial_high;
+extern unsigned int mem_fclk_21285;
+
+extern int __pure cpu_architecture(void);
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __ASM_ARM_SYSTEM_INFO_H */
diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h
new file mode 100644
index 0000000..5a85f14
--- /dev/null
+++ b/arch/arm/include/asm/system_misc.h
@@ -0,0 +1,29 @@
+#ifndef __ASM_ARM_SYSTEM_MISC_H
+#define __ASM_ARM_SYSTEM_MISC_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/compiler.h>
+#include <linux/linkage.h>
+#include <linux/irqflags.h>
+
+extern void cpu_init(void);
+
+void soft_restart(unsigned long);
+extern void (*arm_pm_restart)(char str, const char *cmd);
+extern void (*arm_pm_idle)(void);
+
+#define UDBG_UNDEFINED	(1 << 0)
+#define UDBG_SYSCALL	(1 << 1)
+#define UDBG_BADABORT	(1 << 2)
+#define UDBG_SEGV	(1 << 3)
+#define UDBG_BUS	(1 << 4)
+
+extern unsigned int user_debug;
+
+extern void disable_hlt(void);
+extern void enable_hlt(void);
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __ASM_ARM_SYSTEM_MISC_H */
diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h
index 02b2f82..85fe61e 100644
--- a/arch/arm/include/asm/tlbflush.h
+++ b/arch/arm/include/asm/tlbflush.h
@@ -318,6 +318,21 @@
 
 #define tlb_flag(f)	((always_tlb_flags & (f)) || (__tlb_flag & possible_tlb_flags & (f)))
 
+#define __tlb_op(f, insnarg, arg)					\
+	do {								\
+		if (always_tlb_flags & (f))				\
+			asm("mcr " insnarg				\
+			    : : "r" (arg) : "cc");			\
+		else if (possible_tlb_flags & (f))			\
+			asm("tst %1, %2\n\t"				\
+			    "mcrne " insnarg				\
+			    : : "r" (arg), "r" (__tlb_flag), "Ir" (f)	\
+			    : "cc");					\
+	} while (0)
+
+#define tlb_op(f, regs, arg)	__tlb_op(f, "p15, 0, %0, " regs, arg)
+#define tlb_l2_op(f, regs, arg)	__tlb_op(f, "p15, 1, %0, " regs, arg)
+
 static inline void local_flush_tlb_all(void)
 {
 	const int zero = 0;
@@ -326,16 +341,11 @@
 	if (tlb_flag(TLB_WB))
 		dsb();
 
-	if (tlb_flag(TLB_V3_FULL))
-		asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc");
-	if (tlb_flag(TLB_V4_U_FULL | TLB_V6_U_FULL))
-		asm("mcr p15, 0, %0, c8, c7, 0" : : "r" (zero) : "cc");
-	if (tlb_flag(TLB_V4_D_FULL | TLB_V6_D_FULL))
-		asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc");
-	if (tlb_flag(TLB_V4_I_FULL | TLB_V6_I_FULL))
-		asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
-	if (tlb_flag(TLB_V7_UIS_FULL))
-		asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc");
+	tlb_op(TLB_V3_FULL, "c6, c0, 0", zero);
+	tlb_op(TLB_V4_U_FULL | TLB_V6_U_FULL, "c8, c7, 0", zero);
+	tlb_op(TLB_V4_D_FULL | TLB_V6_D_FULL, "c8, c6, 0", zero);
+	tlb_op(TLB_V4_I_FULL | TLB_V6_I_FULL, "c8, c5, 0", zero);
+	tlb_op(TLB_V7_UIS_FULL, "c8, c3, 0", zero);
 
 	if (tlb_flag(TLB_BARRIER)) {
 		dsb();
@@ -352,29 +362,23 @@
 	if (tlb_flag(TLB_WB))
 		dsb();
 
-	if (cpumask_test_cpu(get_cpu(), mm_cpumask(mm))) {
-		if (tlb_flag(TLB_V3_FULL))
-			asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc");
-		if (tlb_flag(TLB_V4_U_FULL))
-			asm("mcr p15, 0, %0, c8, c7, 0" : : "r" (zero) : "cc");
-		if (tlb_flag(TLB_V4_D_FULL))
-			asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc");
-		if (tlb_flag(TLB_V4_I_FULL))
-			asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
+	if (possible_tlb_flags & (TLB_V3_FULL|TLB_V4_U_FULL|TLB_V4_D_FULL|TLB_V4_I_FULL)) {
+		if (cpumask_test_cpu(get_cpu(), mm_cpumask(mm))) {
+			tlb_op(TLB_V3_FULL, "c6, c0, 0", zero);
+			tlb_op(TLB_V4_U_FULL, "c8, c7, 0", zero);
+			tlb_op(TLB_V4_D_FULL, "c8, c6, 0", zero);
+			tlb_op(TLB_V4_I_FULL, "c8, c5, 0", zero);
+		}
+		put_cpu();
 	}
-	put_cpu();
 
-	if (tlb_flag(TLB_V6_U_ASID))
-		asm("mcr p15, 0, %0, c8, c7, 2" : : "r" (asid) : "cc");
-	if (tlb_flag(TLB_V6_D_ASID))
-		asm("mcr p15, 0, %0, c8, c6, 2" : : "r" (asid) : "cc");
-	if (tlb_flag(TLB_V6_I_ASID))
-		asm("mcr p15, 0, %0, c8, c5, 2" : : "r" (asid) : "cc");
-	if (tlb_flag(TLB_V7_UIS_ASID))
+	tlb_op(TLB_V6_U_ASID, "c8, c7, 2", asid);
+	tlb_op(TLB_V6_D_ASID, "c8, c6, 2", asid);
+	tlb_op(TLB_V6_I_ASID, "c8, c5, 2", asid);
 #ifdef CONFIG_ARM_ERRATA_720789
-		asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc");
+	tlb_op(TLB_V7_UIS_ASID, "c8, c3, 0", zero);
 #else
-		asm("mcr p15, 0, %0, c8, c3, 2" : : "r" (asid) : "cc");
+	tlb_op(TLB_V7_UIS_ASID, "c8, c3, 2", asid);
 #endif
 
 	if (tlb_flag(TLB_BARRIER))
@@ -392,30 +396,23 @@
 	if (tlb_flag(TLB_WB))
 		dsb();
 
-	if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
-		if (tlb_flag(TLB_V3_PAGE))
-			asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (uaddr) : "cc");
-		if (tlb_flag(TLB_V4_U_PAGE))
-			asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (uaddr) : "cc");
-		if (tlb_flag(TLB_V4_D_PAGE))
-			asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc");
-		if (tlb_flag(TLB_V4_I_PAGE))
-			asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
+	if (possible_tlb_flags & (TLB_V3_PAGE|TLB_V4_U_PAGE|TLB_V4_D_PAGE|TLB_V4_I_PAGE|TLB_V4_I_FULL) &&
+	    cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
+		tlb_op(TLB_V3_PAGE, "c6, c0, 0", uaddr);
+		tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", uaddr);
+		tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", uaddr);
+		tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", uaddr);
 		if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
 			asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
 	}
 
-	if (tlb_flag(TLB_V6_U_PAGE))
-		asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (uaddr) : "cc");
-	if (tlb_flag(TLB_V6_D_PAGE))
-		asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc");
-	if (tlb_flag(TLB_V6_I_PAGE))
-		asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
-	if (tlb_flag(TLB_V7_UIS_PAGE))
+	tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", uaddr);
+	tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", uaddr);
+	tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", uaddr);
 #ifdef CONFIG_ARM_ERRATA_720789
-		asm("mcr p15, 0, %0, c8, c3, 3" : : "r" (uaddr & PAGE_MASK) : "cc");
+	tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 3", uaddr & PAGE_MASK);
 #else
-		asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (uaddr) : "cc");
+	tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", uaddr);
 #endif
 
 	if (tlb_flag(TLB_BARRIER))
@@ -432,25 +429,17 @@
 	if (tlb_flag(TLB_WB))
 		dsb();
 
-	if (tlb_flag(TLB_V3_PAGE))
-		asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (kaddr) : "cc");
-	if (tlb_flag(TLB_V4_U_PAGE))
-		asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (kaddr) : "cc");
-	if (tlb_flag(TLB_V4_D_PAGE))
-		asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc");
-	if (tlb_flag(TLB_V4_I_PAGE))
-		asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
+	tlb_op(TLB_V3_PAGE, "c6, c0, 0", kaddr);
+	tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", kaddr);
+	tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", kaddr);
+	tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", kaddr);
 	if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
 		asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
 
-	if (tlb_flag(TLB_V6_U_PAGE))
-		asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (kaddr) : "cc");
-	if (tlb_flag(TLB_V6_D_PAGE))
-		asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc");
-	if (tlb_flag(TLB_V6_I_PAGE))
-		asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
-	if (tlb_flag(TLB_V7_UIS_PAGE))
-		asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (kaddr) : "cc");
+	tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", kaddr);
+	tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", kaddr);
+	tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", kaddr);
+	tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", kaddr);
 
 	if (tlb_flag(TLB_BARRIER)) {
 		dsb();
@@ -475,13 +464,8 @@
 {
 	const unsigned int __tlb_flag = __cpu_tlb_flags;
 
-	if (tlb_flag(TLB_DCLEAN))
-		asm("mcr	p15, 0, %0, c7, c10, 1	@ flush_pmd"
-			: : "r" (pmd) : "cc");
-
-	if (tlb_flag(TLB_L2CLEAN_FR))
-		asm("mcr	p15, 1, %0, c15, c9, 1  @ L2 flush_pmd"
-			: : "r" (pmd) : "cc");
+	tlb_op(TLB_DCLEAN, "c7, c10, 1	@ flush_pmd", pmd);
+	tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1  @ L2 flush_pmd", pmd);
 
 	if (tlb_flag(TLB_WB))
 		dsb();
@@ -491,15 +475,11 @@
 {
 	const unsigned int __tlb_flag = __cpu_tlb_flags;
 
-	if (tlb_flag(TLB_DCLEAN))
-		asm("mcr	p15, 0, %0, c7, c10, 1	@ flush_pmd"
-			: : "r" (pmd) : "cc");
-
-	if (tlb_flag(TLB_L2CLEAN_FR))
-		asm("mcr	p15, 1, %0, c15, c9, 1  @ L2 flush_pmd"
-			: : "r" (pmd) : "cc");
+	tlb_op(TLB_DCLEAN, "c7, c10, 1	@ flush_pmd", pmd);
+	tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1  @ L2 flush_pmd", pmd);
 }
 
+#undef tlb_op
 #undef tlb_flag
 #undef always_tlb_flags
 #undef possible_tlb_flags
diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h
index 5b29a66..f555bb3 100644
--- a/arch/arm/include/asm/traps.h
+++ b/arch/arm/include/asm/traps.h
@@ -46,7 +46,7 @@
 	return in ? : __in_irqentry_text(ptr);
 }
 
-extern void __init early_trap_init(void);
+extern void __init early_trap_init(void *);
 extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
 extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
 
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 2958976..71f6536 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -16,8 +16,8 @@
 #include <asm/errno.h>
 #include <asm/memory.h>
 #include <asm/domain.h>
-#include <asm/system.h>
 #include <asm/unified.h>
+#include <asm/compiler.h>
 
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 43b740d..7b787d6 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -7,6 +7,8 @@
 
 ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_ftrace.o = -pg
+CFLAGS_REMOVE_insn.o = -pg
+CFLAGS_REMOVE_patch.o = -pg
 endif
 
 CFLAGS_REMOVE_return_address.o = -pg
@@ -14,30 +16,29 @@
 # Object file lists.
 
 obj-y		:= elf.o entry-armv.o entry-common.o irq.o opcodes.o \
-		   process.o ptrace.o return_address.o setup.o signal.o \
-		   sys_arm.o stacktrace.o time.o traps.o
+		   process.o ptrace.o return_address.o sched_clock.o \
+		   setup.o signal.o stacktrace.o sys_arm.o time.o traps.o
 
 obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o
 
 obj-$(CONFIG_LEDS)		+= leds.o
 obj-$(CONFIG_OC_ETM)		+= etm.o
-
+obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 obj-$(CONFIG_ISA_DMA_API)	+= dma.o
-obj-$(CONFIG_ARCH_ACORN)	+= ecard.o 
 obj-$(CONFIG_FIQ)		+= fiq.o fiqasm.o
 obj-$(CONFIG_MODULES)		+= armksyms.o module.o
 obj-$(CONFIG_ARTHUR)		+= arthur.o
 obj-$(CONFIG_ISA_DMA)		+= dma-isa.o
 obj-$(CONFIG_PCI)		+= bios32.o isa.o
 obj-$(CONFIG_ARM_CPU_SUSPEND)	+= sleep.o suspend.o
-obj-$(CONFIG_HAVE_SCHED_CLOCK)	+= sched_clock.o
 obj-$(CONFIG_SMP)		+= smp.o smp_tlb.o
 obj-$(CONFIG_HAVE_ARM_SCU)	+= smp_scu.o
 obj-$(CONFIG_HAVE_ARM_TWD)	+= smp_twd.o
-obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o
-obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o
+obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o insn.o
+obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o insn.o
+obj-$(CONFIG_JUMP_LABEL)	+= jump_label.o insn.o patch.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
-obj-$(CONFIG_KPROBES)		+= kprobes.o kprobes-common.o
+obj-$(CONFIG_KPROBES)		+= kprobes.o kprobes-common.o patch.o
 ifdef CONFIG_THUMB2_KERNEL
 obj-$(CONFIG_KPROBES)		+= kprobes-thumb.o
 else
@@ -62,9 +63,6 @@
 CFLAGS_swp_emulate.o		:= -Wa,-march=armv7-a
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
 
-obj-$(CONFIG_CRUNCH)		+= crunch.o crunch-bits.o
-AFLAGS_crunch-bits.o		:= -Wa,-mcpu=ep9312
-
 obj-$(CONFIG_CPU_XSCALE)	+= xscale-cp0.o
 obj-$(CONFIG_CPU_XSC3)		+= xscale-cp0.o
 obj-$(CONFIG_CPU_MOHAWK)	+= xscale-cp0.o
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index 5b0bce6..b57c75e 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -18,7 +18,6 @@
 #include <linux/io.h>
 
 #include <asm/checksum.h>
-#include <asm/system.h>
 #include <asm/ftrace.h>
 
 /*
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index f58ba35..ede5f77 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -16,7 +16,6 @@
 #include <asm/mach/pci.h>
 
 static int debug_pci;
-static int use_firmware;
 
 /*
  * We can't use pci_find_device() here since we are
@@ -295,34 +294,11 @@
 }
 
 /*
- * Adjust the device resources from bus-centric to Linux-centric.
- */
-static void __devinit
-pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev)
-{
-	resource_size_t offset;
-	int i;
-
-	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-		if (dev->resource[i].start == 0)
-			continue;
-		if (dev->resource[i].flags & IORESOURCE_MEM)
-			offset = root->mem_offset;
-		else
-			offset = root->io_offset;
-
-		dev->resource[i].start += offset;
-		dev->resource[i].end   += offset;
-	}
-}
-
-/*
  * pcibios_fixup_bus - Called after each bus is probed,
  * but before its children are examined.
  */
 void pcibios_fixup_bus(struct pci_bus *bus)
 {
-	struct pci_sys_data *root = bus->sysdata;
 	struct pci_dev *dev;
 	u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_FAST_BACK;
 
@@ -333,8 +309,6 @@
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 		u16 status;
 
-		pdev_fixup_device_resources(root, dev);
-
 		pci_read_config_word(dev, PCI_STATUS, &status);
 
 		/*
@@ -400,43 +374,6 @@
 #endif
 
 /*
- * Convert from Linux-centric to bus-centric addresses for bridge devices.
- */
-void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-			 struct resource *res)
-{
-	struct pci_sys_data *root = dev->sysdata;
-	unsigned long offset = 0;
-
-	if (res->flags & IORESOURCE_IO)
-		offset = root->io_offset;
-	if (res->flags & IORESOURCE_MEM)
-		offset = root->mem_offset;
-
-	region->start = res->start - offset;
-	region->end   = res->end - offset;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void __devinit
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-			struct pci_bus_region *region)
-{
-	struct pci_sys_data *root = dev->sysdata;
-	unsigned long offset = 0;
-
-	if (res->flags & IORESOURCE_IO)
-		offset = root->io_offset;
-	if (res->flags & IORESOURCE_MEM)
-		offset = root->mem_offset;
-
-	res->start = region->start + offset;
-	res->end   = region->end + offset;
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
-/*
  * Swizzle the device pin each time we cross a bridge.
  * This might update pin and returns the slot number.
  */
@@ -497,10 +434,10 @@
 
 		if (ret > 0) {
 			if (list_empty(&sys->resources)) {
-				pci_add_resource(&sys->resources,
-						 &ioport_resource);
-				pci_add_resource(&sys->resources,
-						 &iomem_resource);
+				pci_add_resource_offset(&sys->resources,
+					 &ioport_resource, sys->io_offset);
+				pci_add_resource_offset(&sys->resources,
+					 &iomem_resource, sys->mem_offset);
 			}
 
 			sys->bus = hw->scan(nr, sys);
@@ -525,6 +462,7 @@
 
 	INIT_LIST_HEAD(&hw->buses);
 
+	pci_add_flags(PCI_REASSIGN_ALL_RSRC);
 	if (hw->preinit)
 		hw->preinit();
 	pcibios_init_hw(hw);
@@ -536,7 +474,7 @@
 	list_for_each_entry(sys, &hw->buses, node) {
 		struct pci_bus *bus = sys->bus;
 
-		if (!use_firmware) {
+		if (!pci_has_flag(PCI_PROBE_ONLY)) {
 			/*
 			 * Size the bridge windows.
 			 */
@@ -573,7 +511,7 @@
 		debug_pci = 1;
 		return NULL;
 	} else if (!strcmp(str, "firmware")) {
-		use_firmware = 1;
+		pci_add_flags(PCI_PROBE_ONLY);
 		return NULL;
 	}
 	return str;
diff --git a/arch/arm/kernel/cpuidle.c b/arch/arm/kernel/cpuidle.c
new file mode 100644
index 0000000..89545f6
--- /dev/null
+++ b/arch/arm/kernel/cpuidle.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2012 Linaro Ltd.
+ *
+ * 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/cpuidle.h>
+#include <asm/proc-fns.h>
+
+int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int index)
+{
+	cpu_do_idle();
+
+	return index;
+}
diff --git a/arch/arm/kernel/crunch.c b/arch/arm/kernel/crunch.c
deleted file mode 100644
index 25ef223..0000000
--- a/arch/arm/kernel/crunch.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * arch/arm/kernel/crunch.c
- * Cirrus MaverickCrunch context switching and handling
- *
- * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
- *
- * 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/types.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <mach/ep93xx-regs.h>
-#include <asm/thread_notify.h>
-
-struct crunch_state *crunch_owner;
-
-void crunch_task_release(struct thread_info *thread)
-{
-	local_irq_disable();
-	if (crunch_owner == &thread->crunchstate)
-		crunch_owner = NULL;
-	local_irq_enable();
-}
-
-static int crunch_enabled(u32 devcfg)
-{
-	return !!(devcfg & EP93XX_SYSCON_DEVCFG_CPENA);
-}
-
-static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t)
-{
-	struct thread_info *thread = (struct thread_info *)t;
-	struct crunch_state *crunch_state;
-	u32 devcfg;
-
-	crunch_state = &thread->crunchstate;
-
-	switch (cmd) {
-	case THREAD_NOTIFY_FLUSH:
-		memset(crunch_state, 0, sizeof(*crunch_state));
-
-		/*
-		 * FALLTHROUGH: Ensure we don't try to overwrite our newly
-		 * initialised state information on the first fault.
-		 */
-
-	case THREAD_NOTIFY_EXIT:
-		crunch_task_release(thread);
-		break;
-
-	case THREAD_NOTIFY_SWITCH:
-		devcfg = __raw_readl(EP93XX_SYSCON_DEVCFG);
-		if (crunch_enabled(devcfg) || crunch_owner == crunch_state) {
-			/*
-			 * We don't use ep93xx_syscon_swlocked_write() here
-			 * because we are on the context switch path and
-			 * preemption is already disabled.
-			 */
-			devcfg ^= EP93XX_SYSCON_DEVCFG_CPENA;
-			__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
-			__raw_writel(devcfg, EP93XX_SYSCON_DEVCFG);
-		}
-		break;
-	}
-
-	return NOTIFY_DONE;
-}
-
-static struct notifier_block crunch_notifier_block = {
-	.notifier_call	= crunch_do,
-};
-
-static int __init crunch_init(void)
-{
-	thread_register_notifier(&crunch_notifier_block);
-	elf_hwcap |= HWCAP_CRUNCH;
-
-	return 0;
-}
-
-late_initcall(crunch_init);
diff --git a/arch/arm/kernel/debug.S b/arch/arm/kernel/debug.S
index 204e216..c45522c 100644
--- a/arch/arm/kernel/debug.S
+++ b/arch/arm/kernel/debug.S
@@ -10,6 +10,7 @@
  *  32-bit debugging code
  */
 #include <linux/linkage.h>
+#include <asm/assembler.h>
 
 		.text
 
@@ -100,7 +101,7 @@
 
 #endif	/* CONFIG_CPU_V6 */
 
-#else
+#elif !defined(CONFIG_DEBUG_SEMIHOSTING)
 #include <mach/debug-macro.S>
 #endif	/* CONFIG_DEBUG_ICEDCC */
 
@@ -155,6 +156,8 @@
 
 		.ltorg
 
+#ifndef CONFIG_DEBUG_SEMIHOSTING
+
 ENTRY(printascii)
 		addruart_current r3, r1, r2
 		b	2f
@@ -177,3 +180,24 @@
 		mov	r0, #0
 		b	1b
 ENDPROC(printch)
+
+#else
+
+ENTRY(printascii)
+		mov	r1, r0
+		mov	r0, #0x04		@ SYS_WRITE0
+	ARM(	svc	#0x123456	)
+	THUMB(	svc	#0xab		)
+		mov	pc, lr
+ENDPROC(printascii)
+
+ENTRY(printch)
+		adr	r1, hexbuf
+		strb	r0, [r1]
+		mov	r0, #0x03		@ SYS_WRITEC
+	ARM(	svc	#0x123456	)
+	THUMB(	svc	#0xab		)
+		mov	pc, lr
+ENDPROC(printch)
+
+#endif
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
deleted file mode 100644
index 1651d49..0000000
--- a/arch/arm/kernel/ecard.c
+++ /dev/null
@@ -1,1232 +0,0 @@
-/*
- *  linux/arch/arm/kernel/ecard.c
- *
- *  Copyright 1995-2001 Russell King
- *
- * 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.
- *
- *  Find all installed expansion cards, and handle interrupts from them.
- *
- *  Created from information from Acorns RiscOS3 PRMs
- *
- *  08-Dec-1996	RMK	Added code for the 9'th expansion card - the ether
- *			podule slot.
- *  06-May-1997	RMK	Added blacklist for cards whose loader doesn't work.
- *  12-Sep-1997	RMK	Created new handling of interrupt enables/disables
- *			- cards can now register their own routine to control
- *			interrupts (recommended).
- *  29-Sep-1997	RMK	Expansion card interrupt hardware not being re-enabled
- *			on reset from Linux. (Caused cards not to respond
- *			under RiscOS without hard reset).
- *  15-Feb-1998	RMK	Added DMA support
- *  12-Sep-1998	RMK	Added EASI support
- *  10-Jan-1999	RMK	Run loaders in a simulated RISC OS environment.
- *  17-Apr-1999	RMK	Support for EASI Type C cycles.
- */
-#define ECARD_C
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/completion.h>
-#include <linux/reboot.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/kthread.h>
-#include <linux/io.h>
-
-#include <asm/dma.h>
-#include <asm/ecard.h>
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mmu_context.h>
-#include <asm/mach/irq.h>
-#include <asm/tlbflush.h>
-
-#include "ecard.h"
-
-#ifndef CONFIG_ARCH_RPC
-#define HAVE_EXPMASK
-#endif
-
-struct ecard_request {
-	void		(*fn)(struct ecard_request *);
-	ecard_t		*ec;
-	unsigned int	address;
-	unsigned int	length;
-	unsigned int	use_loader;
-	void		*buffer;
-	struct completion *complete;
-};
-
-struct expcard_blacklist {
-	unsigned short	 manufacturer;
-	unsigned short	 product;
-	const char	*type;
-};
-
-static ecard_t *cards;
-static ecard_t *slot_to_expcard[MAX_ECARDS];
-static unsigned int ectcr;
-#ifdef HAS_EXPMASK
-static unsigned int have_expmask;
-#endif
-
-/* List of descriptions of cards which don't have an extended
- * identification, or chunk directories containing a description.
- */
-static struct expcard_blacklist __initdata blacklist[] = {
-	{ MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" }
-};
-
-asmlinkage extern int
-ecard_loader_reset(unsigned long base, loader_t loader);
-asmlinkage extern int
-ecard_loader_read(int off, unsigned long base, loader_t loader);
-
-static inline unsigned short ecard_getu16(unsigned char *v)
-{
-	return v[0] | v[1] << 8;
-}
-
-static inline signed long ecard_gets24(unsigned char *v)
-{
-	return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
-}
-
-static inline ecard_t *slot_to_ecard(unsigned int slot)
-{
-	return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL;
-}
-
-/* ===================== Expansion card daemon ======================== */
-/*
- * Since the loader programs on the expansion cards need to be run
- * in a specific environment, create a separate task with this
- * environment up, and pass requests to this task as and when we
- * need to.
- *
- * This should allow 99% of loaders to be called from Linux.
- *
- * From a security standpoint, we trust the card vendors.  This
- * may be a misplaced trust.
- */
-static void ecard_task_reset(struct ecard_request *req)
-{
-	struct expansion_card *ec = req->ec;
-	struct resource *res;
-
-	res = ec->slot_no == 8
-		? &ec->resource[ECARD_RES_MEMC]
-		: ec->easi
-		  ? &ec->resource[ECARD_RES_EASI]
-		  : &ec->resource[ECARD_RES_IOCSYNC];
-
-	ecard_loader_reset(res->start, ec->loader);
-}
-
-static void ecard_task_readbytes(struct ecard_request *req)
-{
-	struct expansion_card *ec = req->ec;
-	unsigned char *buf = req->buffer;
-	unsigned int len = req->length;
-	unsigned int off = req->address;
-
-	if (ec->slot_no == 8) {
-		void __iomem *base = (void __iomem *)
-				ec->resource[ECARD_RES_MEMC].start;
-
-		/*
-		 * The card maintains an index which increments the address
-		 * into a 4096-byte page on each access.  We need to keep
-		 * track of the counter.
-		 */
-		static unsigned int index;
-		unsigned int page;
-
-		page = (off >> 12) * 4;
-		if (page > 256 * 4)
-			return;
-
-		off &= 4095;
-
-		/*
-		 * If we are reading offset 0, or our current index is
-		 * greater than the offset, reset the hardware index counter.
-		 */
-		if (off == 0 || index > off) {
-			writeb(0, base);
-			index = 0;
-		}
-
-		/*
-		 * Increment the hardware index counter until we get to the
-		 * required offset.  The read bytes are discarded.
-		 */
-		while (index < off) {
-			readb(base + page);
-			index += 1;
-		}
-
-		while (len--) {
-			*buf++ = readb(base + page);
-			index += 1;
-		}
-	} else {
-		unsigned long base = (ec->easi
-			 ? &ec->resource[ECARD_RES_EASI]
-			 : &ec->resource[ECARD_RES_IOCSYNC])->start;
-		void __iomem *pbase = (void __iomem *)base;
-
-		if (!req->use_loader || !ec->loader) {
-			off *= 4;
-			while (len--) {
-				*buf++ = readb(pbase + off);
-				off += 4;
-			}
-		} else {
-			while(len--) {
-				/*
-				 * The following is required by some
-				 * expansion card loader programs.
-				 */
-				*(unsigned long *)0x108 = 0;
-				*buf++ = ecard_loader_read(off++, base,
-							   ec->loader);
-			}
-		}
-	}
-
-}
-
-static DECLARE_WAIT_QUEUE_HEAD(ecard_wait);
-static struct ecard_request *ecard_req;
-static DEFINE_MUTEX(ecard_mutex);
-
-/*
- * Set up the expansion card daemon's page tables.
- */
-static void ecard_init_pgtables(struct mm_struct *mm)
-{
-	struct vm_area_struct vma;
-
-	/* We want to set up the page tables for the following mapping:
-	 *  Virtual	Physical
-	 *  0x03000000	0x03000000
-	 *  0x03010000	unmapped
-	 *  0x03210000	0x03210000
-	 *  0x03400000	unmapped
-	 *  0x08000000	0x08000000
-	 *  0x10000000	unmapped
-	 *
-	 * FIXME: we don't follow this 100% yet.
-	 */
-	pgd_t *src_pgd, *dst_pgd;
-
-	src_pgd = pgd_offset(mm, (unsigned long)IO_BASE);
-	dst_pgd = pgd_offset(mm, IO_START);
-
-	memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE));
-
-	src_pgd = pgd_offset(mm, (unsigned long)EASI_BASE);
-	dst_pgd = pgd_offset(mm, EASI_START);
-
-	memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (EASI_SIZE / PGDIR_SIZE));
-
-	vma.vm_flags = VM_EXEC;
-	vma.vm_mm = mm;
-
-	flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE);
-	flush_tlb_range(&vma, EASI_START, EASI_START + EASI_SIZE);
-}
-
-static int ecard_init_mm(void)
-{
-	struct mm_struct * mm = mm_alloc();
-	struct mm_struct *active_mm = current->active_mm;
-
-	if (!mm)
-		return -ENOMEM;
-
-	current->mm = mm;
-	current->active_mm = mm;
-	activate_mm(active_mm, mm);
-	mmdrop(active_mm);
-	ecard_init_pgtables(mm);
-	return 0;
-}
-
-static int
-ecard_task(void * unused)
-{
-	/*
-	 * Allocate a mm.  We're not a lazy-TLB kernel task since we need
-	 * to set page table entries where the user space would be.  Note
-	 * that this also creates the page tables.  Failure is not an
-	 * option here.
-	 */
-	if (ecard_init_mm())
-		panic("kecardd: unable to alloc mm\n");
-
-	while (1) {
-		struct ecard_request *req;
-
-		wait_event_interruptible(ecard_wait, ecard_req != NULL);
-
-		req = xchg(&ecard_req, NULL);
-		if (req != NULL) {
-			req->fn(req);
-			complete(req->complete);
-		}
-	}
-}
-
-/*
- * Wake the expansion card daemon to action our request.
- *
- * FIXME: The test here is not sufficient to detect if the
- * kcardd is running.
- */
-static void ecard_call(struct ecard_request *req)
-{
-	DECLARE_COMPLETION_ONSTACK(completion);
-
-	req->complete = &completion;
-
-	mutex_lock(&ecard_mutex);
-	ecard_req = req;
-	wake_up(&ecard_wait);
-
-	/*
-	 * Now wait for kecardd to run.
-	 */
-	wait_for_completion(&completion);
-	mutex_unlock(&ecard_mutex);
-}
-
-/* ======================= Mid-level card control ===================== */
-
-static void
-ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
-{
-	struct ecard_request req;
-
-	req.fn		= ecard_task_readbytes;
-	req.ec		= ec;
-	req.address	= off;
-	req.length	= len;
-	req.use_loader	= useld;
-	req.buffer	= addr;
-
-	ecard_call(&req);
-}
-
-int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
-{
-	struct ex_chunk_dir excd;
-	int index = 16;
-	int useld = 0;
-
-	if (!ec->cid.cd)
-		return 0;
-
-	while(1) {
-		ecard_readbytes(&excd, ec, index, 8, useld);
-		index += 8;
-		if (c_id(&excd) == 0) {
-			if (!useld && ec->loader) {
-				useld = 1;
-				index = 0;
-				continue;
-			}
-			return 0;
-		}
-		if (c_id(&excd) == 0xf0) { /* link */
-			index = c_start(&excd);
-			continue;
-		}
-		if (c_id(&excd) == 0x80) { /* loader */
-			if (!ec->loader) {
-				ec->loader = kmalloc(c_len(&excd),
-							       GFP_KERNEL);
-				if (ec->loader)
-					ecard_readbytes(ec->loader, ec,
-							(int)c_start(&excd),
-							c_len(&excd), useld);
-				else
-					return 0;
-			}
-			continue;
-		}
-		if (c_id(&excd) == id && num-- == 0)
-			break;
-	}
-
-	if (c_id(&excd) & 0x80) {
-		switch (c_id(&excd) & 0x70) {
-		case 0x70:
-			ecard_readbytes((unsigned char *)excd.d.string, ec,
-					(int)c_start(&excd), c_len(&excd),
-					useld);
-			break;
-		case 0x00:
-			break;
-		}
-	}
-	cd->start_offset = c_start(&excd);
-	memcpy(cd->d.string, excd.d.string, 256);
-	return 1;
-}
-
-/* ======================= Interrupt control ============================ */
-
-static void ecard_def_irq_enable(ecard_t *ec, int irqnr)
-{
-#ifdef HAS_EXPMASK
-	if (irqnr < 4 && have_expmask) {
-		have_expmask |= 1 << irqnr;
-		__raw_writeb(have_expmask, EXPMASK_ENABLE);
-	}
-#endif
-}
-
-static void ecard_def_irq_disable(ecard_t *ec, int irqnr)
-{
-#ifdef HAS_EXPMASK
-	if (irqnr < 4 && have_expmask) {
-		have_expmask &= ~(1 << irqnr);
-		__raw_writeb(have_expmask, EXPMASK_ENABLE);
-	}
-#endif
-}
-
-static int ecard_def_irq_pending(ecard_t *ec)
-{
-	return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask;
-}
-
-static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr)
-{
-	panic("ecard_def_fiq_enable called - impossible");
-}
-
-static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr)
-{
-	panic("ecard_def_fiq_disable called - impossible");
-}
-
-static int ecard_def_fiq_pending(ecard_t *ec)
-{
-	return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask;
-}
-
-static expansioncard_ops_t ecard_default_ops = {
-	ecard_def_irq_enable,
-	ecard_def_irq_disable,
-	ecard_def_irq_pending,
-	ecard_def_fiq_enable,
-	ecard_def_fiq_disable,
-	ecard_def_fiq_pending
-};
-
-/*
- * Enable and disable interrupts from expansion cards.
- * (interrupts are disabled for these functions).
- *
- * They are not meant to be called directly, but via enable/disable_irq.
- */
-static void ecard_irq_unmask(struct irq_data *d)
-{
-	ecard_t *ec = slot_to_ecard(d->irq - 32);
-
-	if (ec) {
-		if (!ec->ops)
-			ec->ops = &ecard_default_ops;
-
-		if (ec->claimed && ec->ops->irqenable)
-			ec->ops->irqenable(ec, d->irq);
-		else
-			printk(KERN_ERR "ecard: rejecting request to "
-				"enable IRQs for %d\n", d->irq);
-	}
-}
-
-static void ecard_irq_mask(struct irq_data *d)
-{
-	ecard_t *ec = slot_to_ecard(d->irq - 32);
-
-	if (ec) {
-		if (!ec->ops)
-			ec->ops = &ecard_default_ops;
-
-		if (ec->ops && ec->ops->irqdisable)
-			ec->ops->irqdisable(ec, d->irq);
-	}
-}
-
-static struct irq_chip ecard_chip = {
-	.name		= "ECARD",
-	.irq_ack	= ecard_irq_mask,
-	.irq_mask	= ecard_irq_mask,
-	.irq_unmask	= ecard_irq_unmask,
-};
-
-void ecard_enablefiq(unsigned int fiqnr)
-{
-	ecard_t *ec = slot_to_ecard(fiqnr);
-
-	if (ec) {
-		if (!ec->ops)
-			ec->ops = &ecard_default_ops;
-
-		if (ec->claimed && ec->ops->fiqenable)
-			ec->ops->fiqenable(ec, fiqnr);
-		else
-			printk(KERN_ERR "ecard: rejecting request to "
-				"enable FIQs for %d\n", fiqnr);
-	}
-}
-
-void ecard_disablefiq(unsigned int fiqnr)
-{
-	ecard_t *ec = slot_to_ecard(fiqnr);
-
-	if (ec) {
-		if (!ec->ops)
-			ec->ops = &ecard_default_ops;
-
-		if (ec->ops->fiqdisable)
-			ec->ops->fiqdisable(ec, fiqnr);
-	}
-}
-
-static void ecard_dump_irq_state(void)
-{
-	ecard_t *ec;
-
-	printk("Expansion card IRQ state:\n");
-
-	for (ec = cards; ec; ec = ec->next) {
-		if (ec->slot_no == 8)
-			continue;
-
-		printk("  %d: %sclaimed, ",
-		       ec->slot_no, ec->claimed ? "" : "not ");
-
-		if (ec->ops && ec->ops->irqpending &&
-		    ec->ops != &ecard_default_ops)
-			printk("irq %spending\n",
-			       ec->ops->irqpending(ec) ? "" : "not ");
-		else
-			printk("irqaddr %p, mask = %02X, status = %02X\n",
-			       ec->irqaddr, ec->irqmask, readb(ec->irqaddr));
-	}
-}
-
-static void ecard_check_lockup(struct irq_desc *desc)
-{
-	static unsigned long last;
-	static int lockup;
-
-	/*
-	 * If the timer interrupt has not run since the last million
-	 * unrecognised expansion card interrupts, then there is
-	 * something seriously wrong.  Disable the expansion card
-	 * interrupts so at least we can continue.
-	 *
-	 * Maybe we ought to start a timer to re-enable them some time
-	 * later?
-	 */
-	if (last == jiffies) {
-		lockup += 1;
-		if (lockup > 1000000) {
-			printk(KERN_ERR "\nInterrupt lockup detected - "
-			       "disabling all expansion card interrupts\n");
-
-			desc->irq_data.chip->irq_mask(&desc->irq_data);
-			ecard_dump_irq_state();
-		}
-	} else
-		lockup = 0;
-
-	/*
-	 * If we did not recognise the source of this interrupt,
-	 * warn the user, but don't flood the user with these messages.
-	 */
-	if (!last || time_after(jiffies, last + 5*HZ)) {
-		last = jiffies;
-		printk(KERN_WARNING "Unrecognised interrupt from backplane\n");
-		ecard_dump_irq_state();
-	}
-}
-
-static void
-ecard_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-	ecard_t *ec;
-	int called = 0;
-
-	desc->irq_data.chip->irq_mask(&desc->irq_data);
-	for (ec = cards; ec; ec = ec->next) {
-		int pending;
-
-		if (!ec->claimed || ec->irq == NO_IRQ || ec->slot_no == 8)
-			continue;
-
-		if (ec->ops && ec->ops->irqpending)
-			pending = ec->ops->irqpending(ec);
-		else
-			pending = ecard_default_ops.irqpending(ec);
-
-		if (pending) {
-			generic_handle_irq(ec->irq);
-			called ++;
-		}
-	}
-	desc->irq_data.chip->irq_unmask(&desc->irq_data);
-
-	if (called == 0)
-		ecard_check_lockup(desc);
-}
-
-#ifdef HAS_EXPMASK
-static unsigned char priority_masks[] =
-{
-	0xf0, 0xf1, 0xf3, 0xf7, 0xff, 0xff, 0xff, 0xff
-};
-
-static unsigned char first_set[] =
-{
-	0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
-	0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00
-};
-
-static void
-ecard_irqexp_handler(unsigned int irq, struct irq_desc *desc)
-{
-	const unsigned int statusmask = 15;
-	unsigned int status;
-
-	status = __raw_readb(EXPMASK_STATUS) & statusmask;
-	if (status) {
-		unsigned int slot = first_set[status];
-		ecard_t *ec = slot_to_ecard(slot);
-
-		if (ec->claimed) {
-			/*
-			 * this ugly code is so that we can operate a
-			 * prioritorising system:
-			 *
-			 * Card 0 	highest priority
-			 * Card 1
-			 * Card 2
-			 * Card 3	lowest priority
-			 *
-			 * Serial cards should go in 0/1, ethernet/scsi in 2/3
-			 * otherwise you will lose serial data at high speeds!
-			 */
-			generic_handle_irq(ec->irq);
-		} else {
-			printk(KERN_WARNING "card%d: interrupt from unclaimed "
-			       "card???\n", slot);
-			have_expmask &= ~(1 << slot);
-			__raw_writeb(have_expmask, EXPMASK_ENABLE);
-		}
-	} else
-		printk(KERN_WARNING "Wild interrupt from backplane (masks)\n");
-}
-
-static int __init ecard_probeirqhw(void)
-{
-	ecard_t *ec;
-	int found;
-
-	__raw_writeb(0x00, EXPMASK_ENABLE);
-	__raw_writeb(0xff, EXPMASK_STATUS);
-	found = (__raw_readb(EXPMASK_STATUS) & 15) == 0;
-	__raw_writeb(0xff, EXPMASK_ENABLE);
-
-	if (found) {
-		printk(KERN_DEBUG "Expansion card interrupt "
-		       "management hardware found\n");
-
-		/* for each card present, set a bit to '1' */
-		have_expmask = 0x80000000;
-
-		for (ec = cards; ec; ec = ec->next)
-			have_expmask |= 1 << ec->slot_no;
-
-		__raw_writeb(have_expmask, EXPMASK_ENABLE);
-	}
-
-	return found;
-}
-#else
-#define ecard_irqexp_handler NULL
-#define ecard_probeirqhw() (0)
-#endif
-
-static void __iomem *__ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
-{
-	void __iomem *address = NULL;
-	int slot = ec->slot_no;
-
-	if (ec->slot_no == 8)
-		return ECARD_MEMC8_BASE;
-
-	ectcr &= ~(1 << slot);
-
-	switch (type) {
-	case ECARD_MEMC:
-		if (slot < 4)
-			address = ECARD_MEMC_BASE + (slot << 14);
-		break;
-
-	case ECARD_IOC:
-		if (slot < 4)
-			address = ECARD_IOC_BASE + (slot << 14);
-		else
-			address = ECARD_IOC4_BASE + ((slot - 4) << 14);
-		if (address)
-			address += speed << 19;
-		break;
-
-	case ECARD_EASI:
-		address = ECARD_EASI_BASE + (slot << 24);
-		if (speed == ECARD_FAST)
-			ectcr |= 1 << slot;
-		break;
-
-	default:
-		break;
-	}
-
-#ifdef IOMD_ECTCR
-	iomd_writeb(ectcr, IOMD_ECTCR);
-#endif
-	return address;
-}
-
-static int ecard_prints(struct seq_file *m, ecard_t *ec)
-{
-	seq_printf(m, "  %d: %s ", ec->slot_no, ec->easi ? "EASI" : "    ");
-
-	if (ec->cid.id == 0) {
-		struct in_chunk_dir incd;
-
-		seq_printf(m, "[%04X:%04X] ",
-			ec->cid.manufacturer, ec->cid.product);
-
-		if (!ec->card_desc && ec->cid.cd &&
-		    ecard_readchunk(&incd, ec, 0xf5, 0)) {
-			ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL);
-
-			if (ec->card_desc)
-				strcpy((char *)ec->card_desc, incd.d.string);
-		}
-
-		seq_printf(m, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*");
-	} else
-		seq_printf(m, "Simple card %d\n", ec->cid.id);
-
-	return 0;
-}
-
-static int ecard_devices_proc_show(struct seq_file *m, void *v)
-{
-	ecard_t *ec = cards;
-
-	while (ec) {
-		ecard_prints(m, ec);
-		ec = ec->next;
-	}
-	return 0;
-}
-
-static int ecard_devices_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, ecard_devices_proc_show, NULL);
-}
-
-static const struct file_operations bus_ecard_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= ecard_devices_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static struct proc_dir_entry *proc_bus_ecard_dir = NULL;
-
-static void ecard_proc_init(void)
-{
-	proc_bus_ecard_dir = proc_mkdir("bus/ecard", NULL);
-	proc_create("devices", 0, proc_bus_ecard_dir, &bus_ecard_proc_fops);
-}
-
-#define ec_set_resource(ec,nr,st,sz)				\
-	do {							\
-		(ec)->resource[nr].name = dev_name(&ec->dev);	\
-		(ec)->resource[nr].start = st;			\
-		(ec)->resource[nr].end = (st) + (sz) - 1;	\
-		(ec)->resource[nr].flags = IORESOURCE_MEM;	\
-	} while (0)
-
-static void __init ecard_free_card(struct expansion_card *ec)
-{
-	int i;
-
-	for (i = 0; i < ECARD_NUM_RESOURCES; i++)
-		if (ec->resource[i].flags)
-			release_resource(&ec->resource[i]);
-
-	kfree(ec);
-}
-
-static struct expansion_card *__init ecard_alloc_card(int type, int slot)
-{
-	struct expansion_card *ec;
-	unsigned long base;
-	int i;
-
-	ec = kzalloc(sizeof(ecard_t), GFP_KERNEL);
-	if (!ec) {
-		ec = ERR_PTR(-ENOMEM);
-		goto nomem;
-	}
-
-	ec->slot_no = slot;
-	ec->easi = type == ECARD_EASI;
-	ec->irq = NO_IRQ;
-	ec->fiq = NO_IRQ;
-	ec->dma = NO_DMA;
-	ec->ops = &ecard_default_ops;
-
-	dev_set_name(&ec->dev, "ecard%d", slot);
-	ec->dev.parent = NULL;
-	ec->dev.bus = &ecard_bus_type;
-	ec->dev.dma_mask = &ec->dma_mask;
-	ec->dma_mask = (u64)0xffffffff;
-	ec->dev.coherent_dma_mask = ec->dma_mask;
-
-	if (slot < 4) {
-		ec_set_resource(ec, ECARD_RES_MEMC,
-				PODSLOT_MEMC_BASE + (slot << 14),
-				PODSLOT_MEMC_SIZE);
-		base = PODSLOT_IOC0_BASE + (slot << 14);
-	} else
-		base = PODSLOT_IOC4_BASE + ((slot - 4) << 14);
-
-#ifdef CONFIG_ARCH_RPC
-	if (slot < 8) {
-		ec_set_resource(ec, ECARD_RES_EASI,
-				PODSLOT_EASI_BASE + (slot << 24),
-				PODSLOT_EASI_SIZE);
-	}
-
-	if (slot == 8) {
-		ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE);
-	} else
-#endif
-
-	for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++)
-		ec_set_resource(ec, i + ECARD_RES_IOCSLOW,
-				base + (i << 19), PODSLOT_IOC_SIZE);
-
-	for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
-		if (ec->resource[i].flags &&
-		    request_resource(&iomem_resource, &ec->resource[i])) {
-			dev_err(&ec->dev, "resource(s) not available\n");
-			ec->resource[i].end -= ec->resource[i].start;
-			ec->resource[i].start = 0;
-			ec->resource[i].flags = 0;
-		}
-	}
-
- nomem:
-	return ec;
-}
-
-static ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct expansion_card *ec = ECARD_DEV(dev);
-	return sprintf(buf, "%u\n", ec->irq);
-}
-
-static ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct expansion_card *ec = ECARD_DEV(dev);
-	return sprintf(buf, "%u\n", ec->dma);
-}
-
-static ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct expansion_card *ec = ECARD_DEV(dev);
-	char *str = buf;
-	int i;
-
-	for (i = 0; i < ECARD_NUM_RESOURCES; i++)
-		str += sprintf(str, "%08x %08x %08lx\n",
-				ec->resource[i].start,
-				ec->resource[i].end,
-				ec->resource[i].flags);
-
-	return str - buf;
-}
-
-static ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct expansion_card *ec = ECARD_DEV(dev);
-	return sprintf(buf, "%u\n", ec->cid.manufacturer);
-}
-
-static ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct expansion_card *ec = ECARD_DEV(dev);
-	return sprintf(buf, "%u\n", ec->cid.product);
-}
-
-static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct expansion_card *ec = ECARD_DEV(dev);
-	return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC");
-}
-
-static struct device_attribute ecard_dev_attrs[] = {
-	__ATTR(device,   S_IRUGO, ecard_show_device,    NULL),
-	__ATTR(dma,      S_IRUGO, ecard_show_dma,       NULL),
-	__ATTR(irq,      S_IRUGO, ecard_show_irq,       NULL),
-	__ATTR(resource, S_IRUGO, ecard_show_resources, NULL),
-	__ATTR(type,     S_IRUGO, ecard_show_type,      NULL),
-	__ATTR(vendor,   S_IRUGO, ecard_show_vendor,    NULL),
-	__ATTR_NULL,
-};
-
-
-int ecard_request_resources(struct expansion_card *ec)
-{
-	int i, err = 0;
-
-	for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
-		if (ecard_resource_end(ec, i) &&
-		    !request_mem_region(ecard_resource_start(ec, i),
-					ecard_resource_len(ec, i),
-					ec->dev.driver->name)) {
-			err = -EBUSY;
-			break;
-		}
-	}
-
-	if (err) {
-		while (i--)
-			if (ecard_resource_end(ec, i))
-				release_mem_region(ecard_resource_start(ec, i),
-						   ecard_resource_len(ec, i));
-	}
-	return err;
-}
-EXPORT_SYMBOL(ecard_request_resources);
-
-void ecard_release_resources(struct expansion_card *ec)
-{
-	int i;
-
-	for (i = 0; i < ECARD_NUM_RESOURCES; i++)
-		if (ecard_resource_end(ec, i))
-			release_mem_region(ecard_resource_start(ec, i),
-					   ecard_resource_len(ec, i));
-}
-EXPORT_SYMBOL(ecard_release_resources);
-
-void ecard_setirq(struct expansion_card *ec, const struct expansion_card_ops *ops, void *irq_data)
-{
-	ec->irq_data = irq_data;
-	barrier();
-	ec->ops = ops;
-}
-EXPORT_SYMBOL(ecard_setirq);
-
-void __iomem *ecardm_iomap(struct expansion_card *ec, unsigned int res,
-			   unsigned long offset, unsigned long maxsize)
-{
-	unsigned long start = ecard_resource_start(ec, res);
-	unsigned long end = ecard_resource_end(ec, res);
-
-	if (offset > (end - start))
-		return NULL;
-
-	start += offset;
-	if (maxsize && end - start > maxsize)
-		end = start + maxsize;
-	
-	return devm_ioremap(&ec->dev, start, end - start);
-}
-EXPORT_SYMBOL(ecardm_iomap);
-
-/*
- * Probe for an expansion card.
- *
- * If bit 1 of the first byte of the card is set, then the
- * card does not exist.
- */
-static int __init
-ecard_probe(int slot, card_type_t type)
-{
-	ecard_t **ecp;
-	ecard_t *ec;
-	struct ex_ecid cid;
-	void __iomem *addr;
-	int i, rc;
-
-	ec = ecard_alloc_card(type, slot);
-	if (IS_ERR(ec)) {
-		rc = PTR_ERR(ec);
-		goto nomem;
-	}
-
-	rc = -ENODEV;
-	if ((addr = __ecard_address(ec, type, ECARD_SYNC)) == NULL)
-		goto nodev;
-
-	cid.r_zero = 1;
-	ecard_readbytes(&cid, ec, 0, 16, 0);
-	if (cid.r_zero)
-		goto nodev;
-
-	ec->cid.id	= cid.r_id;
-	ec->cid.cd	= cid.r_cd;
-	ec->cid.is	= cid.r_is;
-	ec->cid.w	= cid.r_w;
-	ec->cid.manufacturer = ecard_getu16(cid.r_manu);
-	ec->cid.product = ecard_getu16(cid.r_prod);
-	ec->cid.country = cid.r_country;
-	ec->cid.irqmask = cid.r_irqmask;
-	ec->cid.irqoff  = ecard_gets24(cid.r_irqoff);
-	ec->cid.fiqmask = cid.r_fiqmask;
-	ec->cid.fiqoff  = ecard_gets24(cid.r_fiqoff);
-	ec->fiqaddr	=
-	ec->irqaddr	= addr;
-
-	if (ec->cid.is) {
-		ec->irqmask = ec->cid.irqmask;
-		ec->irqaddr += ec->cid.irqoff;
-		ec->fiqmask = ec->cid.fiqmask;
-		ec->fiqaddr += ec->cid.fiqoff;
-	} else {
-		ec->irqmask = 1;
-		ec->fiqmask = 4;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(blacklist); i++)
-		if (blacklist[i].manufacturer == ec->cid.manufacturer &&
-		    blacklist[i].product == ec->cid.product) {
-			ec->card_desc = blacklist[i].type;
-			break;
-		}
-
-	/*
-	 * hook the interrupt handlers
-	 */
-	if (slot < 8) {
-		ec->irq = 32 + slot;
-		irq_set_chip_and_handler(ec->irq, &ecard_chip,
-					 handle_level_irq);
-		set_irq_flags(ec->irq, IRQF_VALID);
-	}
-
-	if (slot == 8)
-		ec->irq = 11;
-#ifdef CONFIG_ARCH_RPC
-	/* On RiscPC, only first two slots have DMA capability */
-	if (slot < 2)
-		ec->dma = 2 + slot;
-#endif
-
-	for (ecp = &cards; *ecp; ecp = &(*ecp)->next);
-
-	*ecp = ec;
-	slot_to_expcard[slot] = ec;
-
-	device_register(&ec->dev);
-
-	return 0;
-
- nodev:
-	ecard_free_card(ec);
- nomem:
-	return rc;
-}
-
-/*
- * Initialise the expansion card system.
- * Locate all hardware - interrupt management and
- * actual cards.
- */
-static int __init ecard_init(void)
-{
-	struct task_struct *task;
-	int slot, irqhw;
-
-	task = kthread_run(ecard_task, NULL, "kecardd");
-	if (IS_ERR(task)) {
-		printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n",
-		       PTR_ERR(task));
-		return PTR_ERR(task);
-	}
-
-	printk("Probing expansion cards\n");
-
-	for (slot = 0; slot < 8; slot ++) {
-		if (ecard_probe(slot, ECARD_EASI) == -ENODEV)
-			ecard_probe(slot, ECARD_IOC);
-	}
-
-	ecard_probe(8, ECARD_IOC);
-
-	irqhw = ecard_probeirqhw();
-
-	irq_set_chained_handler(IRQ_EXPANSIONCARD,
-				irqhw ? ecard_irqexp_handler : ecard_irq_handler);
-
-	ecard_proc_init();
-
-	return 0;
-}
-
-subsys_initcall(ecard_init);
-
-/*
- *	ECARD "bus"
- */
-static const struct ecard_id *
-ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec)
-{
-	int i;
-
-	for (i = 0; ids[i].manufacturer != 65535; i++)
-		if (ec->cid.manufacturer == ids[i].manufacturer &&
-		    ec->cid.product == ids[i].product)
-			return ids + i;
-
-	return NULL;
-}
-
-static int ecard_drv_probe(struct device *dev)
-{
-	struct expansion_card *ec = ECARD_DEV(dev);
-	struct ecard_driver *drv = ECARD_DRV(dev->driver);
-	const struct ecard_id *id;
-	int ret;
-
-	id = ecard_match_device(drv->id_table, ec);
-
-	ec->claimed = 1;
-	ret = drv->probe(ec, id);
-	if (ret)
-		ec->claimed = 0;
-	return ret;
-}
-
-static int ecard_drv_remove(struct device *dev)
-{
-	struct expansion_card *ec = ECARD_DEV(dev);
-	struct ecard_driver *drv = ECARD_DRV(dev->driver);
-
-	drv->remove(ec);
-	ec->claimed = 0;
-
-	/*
-	 * Restore the default operations.  We ensure that the
-	 * ops are set before we change the data.
-	 */
-	ec->ops = &ecard_default_ops;
-	barrier();
-	ec->irq_data = NULL;
-
-	return 0;
-}
-
-/*
- * Before rebooting, we must make sure that the expansion card is in a
- * sensible state, so it can be re-detected.  This means that the first
- * page of the ROM must be visible.  We call the expansion cards reset
- * handler, if any.
- */
-static void ecard_drv_shutdown(struct device *dev)
-{
-	struct expansion_card *ec = ECARD_DEV(dev);
-	struct ecard_driver *drv = ECARD_DRV(dev->driver);
-	struct ecard_request req;
-
-	if (dev->driver) {
-		if (drv->shutdown)
-			drv->shutdown(ec);
-		ec->claimed = 0;
-	}
-
-	/*
-	 * If this card has a loader, call the reset handler.
-	 */
-	if (ec->loader) {
-		req.fn = ecard_task_reset;
-		req.ec = ec;
-		ecard_call(&req);
-	}
-}
-
-int ecard_register_driver(struct ecard_driver *drv)
-{
-	drv->drv.bus = &ecard_bus_type;
-
-	return driver_register(&drv->drv);
-}
-
-void ecard_remove_driver(struct ecard_driver *drv)
-{
-	driver_unregister(&drv->drv);
-}
-
-static int ecard_match(struct device *_dev, struct device_driver *_drv)
-{
-	struct expansion_card *ec = ECARD_DEV(_dev);
-	struct ecard_driver *drv = ECARD_DRV(_drv);
-	int ret;
-
-	if (drv->id_table) {
-		ret = ecard_match_device(drv->id_table, ec) != NULL;
-	} else {
-		ret = ec->cid.id == drv->id;
-	}
-
-	return ret;
-}
-
-struct bus_type ecard_bus_type = {
-	.name		= "ecard",
-	.dev_attrs	= ecard_dev_attrs,
-	.match		= ecard_match,
-	.probe		= ecard_drv_probe,
-	.remove		= ecard_drv_remove,
-	.shutdown	= ecard_drv_shutdown,
-};
-
-static int ecard_bus_init(void)
-{
-	return bus_register(&ecard_bus_type);
-}
-
-postcore_initcall(ecard_bus_init);
-
-EXPORT_SYMBOL(ecard_readchunk);
-EXPORT_SYMBOL(ecard_register_driver);
-EXPORT_SYMBOL(ecard_remove_driver);
-EXPORT_SYMBOL(ecard_bus_type);
diff --git a/arch/arm/kernel/elf.c b/arch/arm/kernel/elf.c
index ddba41d..d0d1e83 100644
--- a/arch/arm/kernel/elf.c
+++ b/arch/arm/kernel/elf.c
@@ -3,6 +3,7 @@
 #include <linux/personality.h>
 #include <linux/binfmts.h>
 #include <linux/elf.h>
+#include <asm/system_info.h>
 
 int elf_check_arch(const struct elf32_hdr *x)
 {
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index be16a48..7fd3ad0 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -15,16 +15,19 @@
  *  that causes it to save wrong values...  Be aware!
  */
 
+#include <asm/assembler.h>
 #include <asm/memory.h>
 #include <asm/glue-df.h>
 #include <asm/glue-pf.h>
 #include <asm/vfpmacros.h>
+#ifndef CONFIG_MULTI_IRQ_HANDLER
 #include <mach/entry-macro.S>
+#endif
 #include <asm/thread_notify.h>
 #include <asm/unwind.h>
 #include <asm/unistd.h>
 #include <asm/tls.h>
-#include <asm/system.h>
+#include <asm/system_info.h>
 
 #include "entry-header.S"
 #include <asm/entry-macro-multi.S>
@@ -1101,7 +1104,6 @@
  * get out of that mode without clobbering one register.
  */
 vector_fiq:
-	disable_fiq
 	subs	pc, lr, #4
 
 /*=============================================================================
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 9fd0ba9..54ee265 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -10,9 +10,15 @@
 
 #include <asm/unistd.h>
 #include <asm/ftrace.h>
-#include <mach/entry-macro.S>
 #include <asm/unwind.h>
 
+#ifdef CONFIG_NEED_RET_TO_USER
+#include <mach/entry-macro.S>
+#else
+	.macro  arch_ret_to_user, tmp1, tmp2
+	.endm
+#endif
+
 #include "entry-header.S"
 
 
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 4c164ec..c32f845 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -42,9 +42,9 @@
 #include <linux/seq_file.h>
 
 #include <asm/cacheflush.h>
+#include <asm/cp15.h>
 #include <asm/fiq.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 
 static unsigned long no_fiq_insn;
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
index c0062ad..df0bf0c 100644
--- a/arch/arm/kernel/ftrace.c
+++ b/arch/arm/kernel/ftrace.c
@@ -16,10 +16,13 @@
 #include <linux/uaccess.h>
 
 #include <asm/cacheflush.h>
+#include <asm/opcodes.h>
 #include <asm/ftrace.h>
 
+#include "insn.h"
+
 #ifdef CONFIG_THUMB2_KERNEL
-#define	NOP		0xeb04f85d	/* pop.w {lr} */
+#define	NOP		0xf85deb04	/* pop.w {lr} */
 #else
 #define	NOP		0xe8bd4000	/* pop {lr} */
 #endif
@@ -60,76 +63,31 @@
 }
 #endif
 
-#ifdef CONFIG_THUMB2_KERNEL
-static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,
-				       bool link)
-{
-	unsigned long s, j1, j2, i1, i2, imm10, imm11;
-	unsigned long first, second;
-	long offset;
-
-	offset = (long)addr - (long)(pc + 4);
-	if (offset < -16777216 || offset > 16777214) {
-		WARN_ON_ONCE(1);
-		return 0;
-	}
-
-	s	= (offset >> 24) & 0x1;
-	i1	= (offset >> 23) & 0x1;
-	i2	= (offset >> 22) & 0x1;
-	imm10	= (offset >> 12) & 0x3ff;
-	imm11	= (offset >>  1) & 0x7ff;
-
-	j1 = (!i1) ^ s;
-	j2 = (!i2) ^ s;
-
-	first = 0xf000 | (s << 10) | imm10;
-	second = 0x9000 | (j1 << 13) | (j2 << 11) | imm11;
-	if (link)
-		second |= 1 << 14;
-
-	return (second << 16) | first;
-}
-#else
-static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,
-				       bool link)
-{
-	unsigned long opcode = 0xea000000;
-	long offset;
-
-	if (link)
-		opcode |= 1 << 24;
-
-	offset = (long)addr - (long)(pc + 8);
-	if (unlikely(offset < -33554432 || offset > 33554428)) {
-		/* Can't generate branches that far (from ARM ARM). Ftrace
-		 * doesn't generate branches outside of kernel text.
-		 */
-		WARN_ON_ONCE(1);
-		return 0;
-	}
-
-	offset = (offset >> 2) & 0x00ffffff;
-
-	return opcode | offset;
-}
-#endif
-
 static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
 {
-	return ftrace_gen_branch(pc, addr, true);
+	return arm_gen_branch_link(pc, addr);
 }
 
 static int ftrace_modify_code(unsigned long pc, unsigned long old,
-			      unsigned long new)
+			      unsigned long new, bool validate)
 {
 	unsigned long replaced;
 
-	if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
-		return -EFAULT;
+	if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
+		old = __opcode_to_mem_thumb32(old);
+		new = __opcode_to_mem_thumb32(new);
+	} else {
+		old = __opcode_to_mem_arm(old);
+		new = __opcode_to_mem_arm(new);
+	}
 
-	if (replaced != old)
-		return -EINVAL;
+	if (validate) {
+		if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
+			return -EFAULT;
+
+		if (replaced != old)
+			return -EINVAL;
+	}
 
 	if (probe_kernel_write((void *)pc, &new, MCOUNT_INSN_SIZE))
 		return -EPERM;
@@ -141,23 +99,21 @@
 
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
-	unsigned long pc, old;
+	unsigned long pc;
 	unsigned long new;
 	int ret;
 
 	pc = (unsigned long)&ftrace_call;
-	memcpy(&old, &ftrace_call, MCOUNT_INSN_SIZE);
 	new = ftrace_call_replace(pc, (unsigned long)func);
 
-	ret = ftrace_modify_code(pc, old, new);
+	ret = ftrace_modify_code(pc, 0, new, false);
 
 #ifdef CONFIG_OLD_MCOUNT
 	if (!ret) {
 		pc = (unsigned long)&ftrace_call_old;
-		memcpy(&old, &ftrace_call_old, MCOUNT_INSN_SIZE);
 		new = ftrace_call_replace(pc, (unsigned long)func);
 
-		ret = ftrace_modify_code(pc, old, new);
+		ret = ftrace_modify_code(pc, 0, new, false);
 	}
 #endif
 
@@ -172,7 +128,7 @@
 	old = ftrace_nop_replace(rec);
 	new = ftrace_call_replace(ip, adjust_address(rec, addr));
 
-	return ftrace_modify_code(rec->ip, old, new);
+	return ftrace_modify_code(rec->ip, old, new, true);
 }
 
 int ftrace_make_nop(struct module *mod,
@@ -185,7 +141,7 @@
 
 	old = ftrace_call_replace(ip, adjust_address(rec, addr));
 	new = ftrace_nop_replace(rec);
-	ret = ftrace_modify_code(ip, old, new);
+	ret = ftrace_modify_code(ip, old, new, true);
 
 #ifdef CONFIG_OLD_MCOUNT
 	if (ret == -EINVAL && addr == MCOUNT_ADDR) {
@@ -193,7 +149,7 @@
 
 		old = ftrace_call_replace(ip, adjust_address(rec, addr));
 		new = ftrace_nop_replace(rec);
-		ret = ftrace_modify_code(ip, old, new);
+		ret = ftrace_modify_code(ip, old, new, true);
 	}
 #endif
 
@@ -249,12 +205,12 @@
 {
 	unsigned long caller_fn = (unsigned long) func;
 	unsigned long pc = (unsigned long) callsite;
-	unsigned long branch = ftrace_gen_branch(pc, caller_fn, false);
+	unsigned long branch = arm_gen_branch(pc, caller_fn);
 	unsigned long nop = 0xe1a00000;	/* mov r0, r0 */
 	unsigned long old = enable ? nop : branch;
 	unsigned long new = enable ? branch : nop;
 
-	return ftrace_modify_code(pc, old, new);
+	return ftrace_modify_code(pc, old, new, true);
 }
 
 static int ftrace_modify_graph_caller(bool enable)
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index d46f259..278cfc1 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -17,8 +17,8 @@
 #include <asm/assembler.h>
 #include <asm/ptrace.h>
 #include <asm/asm-offsets.h>
+#include <asm/cp15.h>
 #include <asm/thread_info.h>
-#include <asm/system.h>
 
 /*
  * Kernel startup entry point.
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 6d57911..3bf0c7f 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -15,12 +15,12 @@
 #include <linux/init.h>
 
 #include <asm/assembler.h>
+#include <asm/cp15.h>
 #include <asm/domain.h>
 #include <asm/ptrace.h>
 #include <asm/asm-offsets.h>
 #include <asm/memory.h>
 #include <asm/thread_info.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 
 #ifdef CONFIG_DEBUG_LL
@@ -265,7 +265,7 @@
 	str	r6, [r3]
 
 #ifdef CONFIG_DEBUG_LL
-#ifndef CONFIG_DEBUG_ICEDCC
+#if !defined(CONFIG_DEBUG_ICEDCC) && !defined(CONFIG_DEBUG_SEMIHOSTING)
 	/*
 	 * Map in IO space for serial debugging.
 	 * This allows debug messages to be output
@@ -297,10 +297,10 @@
 	cmp	r0, r6
 	blo	1b
 
-#else /* CONFIG_DEBUG_ICEDCC */
-	/* we don't need any serial debugging mappings for ICEDCC */
+#else /* CONFIG_DEBUG_ICEDCC || CONFIG_DEBUG_SEMIHOSTING */
+	/* we don't need any serial debugging mappings */
 	ldr	r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
-#endif /* !CONFIG_DEBUG_ICEDCC */
+#endif
 
 #if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS)
 	/*
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index d6a95ef..ba386bd 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -34,7 +34,6 @@
 #include <asm/current.h>
 #include <asm/hw_breakpoint.h>
 #include <asm/kdebug.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 
 /* Breakpoint currently in use for each BRP. */
diff --git a/arch/arm/kernel/insn.c b/arch/arm/kernel/insn.c
new file mode 100644
index 0000000..b760340
--- /dev/null
+++ b/arch/arm/kernel/insn.c
@@ -0,0 +1,62 @@
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <asm/opcodes.h>
+
+static unsigned long
+__arm_gen_branch_thumb2(unsigned long pc, unsigned long addr, bool link)
+{
+	unsigned long s, j1, j2, i1, i2, imm10, imm11;
+	unsigned long first, second;
+	long offset;
+
+	offset = (long)addr - (long)(pc + 4);
+	if (offset < -16777216 || offset > 16777214) {
+		WARN_ON_ONCE(1);
+		return 0;
+	}
+
+	s	= (offset >> 24) & 0x1;
+	i1	= (offset >> 23) & 0x1;
+	i2	= (offset >> 22) & 0x1;
+	imm10	= (offset >> 12) & 0x3ff;
+	imm11	= (offset >>  1) & 0x7ff;
+
+	j1 = (!i1) ^ s;
+	j2 = (!i2) ^ s;
+
+	first = 0xf000 | (s << 10) | imm10;
+	second = 0x9000 | (j1 << 13) | (j2 << 11) | imm11;
+	if (link)
+		second |= 1 << 14;
+
+	return __opcode_thumb32_compose(first, second);
+}
+
+static unsigned long
+__arm_gen_branch_arm(unsigned long pc, unsigned long addr, bool link)
+{
+	unsigned long opcode = 0xea000000;
+	long offset;
+
+	if (link)
+		opcode |= 1 << 24;
+
+	offset = (long)addr - (long)(pc + 8);
+	if (unlikely(offset < -33554432 || offset > 33554428)) {
+		WARN_ON_ONCE(1);
+		return 0;
+	}
+
+	offset = (offset >> 2) & 0x00ffffff;
+
+	return opcode | offset;
+}
+
+unsigned long
+__arm_gen_branch(unsigned long pc, unsigned long addr, bool link)
+{
+	if (IS_ENABLED(CONFIG_THUMB2_KERNEL))
+		return __arm_gen_branch_thumb2(pc, addr, link);
+	else
+		return __arm_gen_branch_arm(pc, addr, link);
+}
diff --git a/arch/arm/kernel/insn.h b/arch/arm/kernel/insn.h
new file mode 100644
index 0000000..e96065d
--- /dev/null
+++ b/arch/arm/kernel/insn.h
@@ -0,0 +1,29 @@
+#ifndef __ASM_ARM_INSN_H
+#define __ASM_ARM_INSN_H
+
+static inline unsigned long
+arm_gen_nop(void)
+{
+#ifdef CONFIG_THUMB2_KERNEL
+	return 0xf3af8000; /* nop.w */
+#else
+	return 0xe1a00000; /* mov r0, r0 */
+#endif
+}
+
+unsigned long
+__arm_gen_branch(unsigned long pc, unsigned long addr, bool link);
+
+static inline unsigned long
+arm_gen_branch(unsigned long pc, unsigned long addr)
+{
+	return __arm_gen_branch(pc, addr, false);
+}
+
+static inline unsigned long
+arm_gen_branch_link(unsigned long pc, unsigned long addr)
+{
+	return __arm_gen_branch(pc, addr, true);
+}
+
+#endif
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 3efd82c..71ccdbf 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -36,7 +36,6 @@
 #include <linux/proc_fs.h>
 
 #include <asm/exception.h>
-#include <asm/system.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
@@ -181,10 +180,7 @@
 	local_irq_save(flags);
 
 	for_each_irq_desc(i, desc) {
-		bool affinity_broken = false;
-
-		if (!desc)
-			continue;
+		bool affinity_broken;
 
 		raw_spin_lock(&desc->lock);
 		affinity_broken = migrate_one_irq(desc);
diff --git a/arch/arm/kernel/jump_label.c b/arch/arm/kernel/jump_label.c
new file mode 100644
index 0000000..4ce4f78
--- /dev/null
+++ b/arch/arm/kernel/jump_label.c
@@ -0,0 +1,39 @@
+#include <linux/kernel.h>
+#include <linux/jump_label.h>
+
+#include "insn.h"
+#include "patch.h"
+
+#ifdef HAVE_JUMP_LABEL
+
+static void __arch_jump_label_transform(struct jump_entry *entry,
+					enum jump_label_type type,
+					bool is_static)
+{
+	void *addr = (void *)entry->code;
+	unsigned int insn;
+
+	if (type == JUMP_LABEL_ENABLE)
+		insn = arm_gen_branch(entry->code, entry->target);
+	else
+		insn = arm_gen_nop();
+
+	if (is_static)
+		__patch_text(addr, insn);
+	else
+		patch_text(addr, insn);
+}
+
+void arch_jump_label_transform(struct jump_entry *entry,
+			       enum jump_label_type type)
+{
+	__arch_jump_label_transform(entry, type, false);
+}
+
+void arch_jump_label_transform_static(struct jump_entry *entry,
+				      enum jump_label_type type)
+{
+	__arch_jump_label_transform(entry, type, true);
+}
+
+#endif
diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c
index a5394fb4..18a7628 100644
--- a/arch/arm/kernel/kprobes-common.c
+++ b/arch/arm/kernel/kprobes-common.c
@@ -13,6 +13,7 @@
 
 #include <linux/kernel.h>
 #include <linux/kprobes.h>
+#include <asm/system_info.h>
 
 #include "kprobes.h"
 
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c
index 129c116..4dd41fc 100644
--- a/arch/arm/kernel/kprobes.c
+++ b/arch/arm/kernel/kprobes.c
@@ -29,6 +29,7 @@
 #include <asm/cacheflush.h>
 
 #include "kprobes.h"
+#include "patch.h"
 
 #define MIN_STACK_SIZE(addr) 				\
 	min((unsigned long)MAX_STACK_SIZE,		\
@@ -103,58 +104,34 @@
 	return 0;
 }
 
-#ifdef CONFIG_THUMB2_KERNEL
-
-/*
- * For a 32-bit Thumb breakpoint spanning two memory words we need to take
- * special precautions to insert the breakpoint atomically, especially on SMP
- * systems. This is achieved by calling this arming function using stop_machine.
- */
-static int __kprobes set_t32_breakpoint(void *addr)
-{
-	((u16 *)addr)[0] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION >> 16;
-	((u16 *)addr)[1] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION & 0xffff;
-	flush_insns(addr, 2*sizeof(u16));
-	return 0;
-}
-
 void __kprobes arch_arm_kprobe(struct kprobe *p)
 {
-	uintptr_t addr = (uintptr_t)p->addr & ~1; /* Remove any Thumb flag */
+	unsigned int brkp;
+	void *addr;
 
-	if (!is_wide_instruction(p->opcode)) {
-		*(u16 *)addr = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION;
-		flush_insns(addr, sizeof(u16));
-	} else if (addr & 2) {
-		/* A 32-bit instruction spanning two words needs special care */
-		stop_machine(set_t32_breakpoint, (void *)addr, &cpu_online_map);
+	if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
+		/* Remove any Thumb flag */
+		addr = (void *)((uintptr_t)p->addr & ~1);
+
+		if (is_wide_instruction(p->opcode))
+			brkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION;
+		else
+			brkp = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION;
 	} else {
-		/* Word aligned 32-bit instruction can be written atomically */
-		u32 bkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION;
-#ifndef __ARMEB__ /* Swap halfwords for little-endian */
-		bkp = (bkp >> 16) | (bkp << 16);
-#endif
-		*(u32 *)addr = bkp;
-		flush_insns(addr, sizeof(u32));
+		kprobe_opcode_t insn = p->opcode;
+
+		addr = p->addr;
+		brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION;
+
+		if (insn >= 0xe0000000)
+			brkp |= 0xe0000000;  /* Unconditional instruction */
+		else
+			brkp |= insn & 0xf0000000;  /* Copy condition from insn */
 	}
+
+	patch_text(addr, brkp);
 }
 
-#else /* !CONFIG_THUMB2_KERNEL */
-
-void __kprobes arch_arm_kprobe(struct kprobe *p)
-{
-	kprobe_opcode_t insn = p->opcode;
-	kprobe_opcode_t brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION;
-	if (insn >= 0xe0000000)
-		brkp |= 0xe0000000;  /* Unconditional instruction */
-	else
-		brkp |= insn & 0xf0000000;  /* Copy condition from insn */
-	*p->addr = brkp;
-	flush_insns(p->addr, sizeof(p->addr[0]));
-}
-
-#endif /* !CONFIG_THUMB2_KERNEL */
-
 /*
  * The actual disarming is done here on each CPU and synchronized using
  * stop_machine. This synchronization is necessary on SMP to avoid removing
@@ -166,31 +143,16 @@
 int __kprobes __arch_disarm_kprobe(void *p)
 {
 	struct kprobe *kp = p;
-#ifdef CONFIG_THUMB2_KERNEL
-	u16 *addr = (u16 *)((uintptr_t)kp->addr & ~1);
-	kprobe_opcode_t insn = kp->opcode;
-	unsigned int len;
+	void *addr = (void *)((uintptr_t)kp->addr & ~1);
 
-	if (is_wide_instruction(insn)) {
-		((u16 *)addr)[0] = insn>>16;
-		((u16 *)addr)[1] = insn;
-		len = 2*sizeof(u16);
-	} else {
-		((u16 *)addr)[0] = insn;
-		len = sizeof(u16);
-	}
-	flush_insns(addr, len);
+	__patch_text(addr, kp->opcode);
 
-#else /* !CONFIG_THUMB2_KERNEL */
-	*kp->addr = kp->opcode;
-	flush_insns(kp->addr, sizeof(kp->addr[0]));
-#endif
 	return 0;
 }
 
 void __kprobes arch_disarm_kprobe(struct kprobe *p)
 {
-	stop_machine(__arch_disarm_kprobe, p, &cpu_online_map);
+	stop_machine(__arch_disarm_kprobe, p, cpu_online_mask);
 }
 
 void __kprobes arch_remove_kprobe(struct kprobe *p)
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index 764bd45..dfcdb9f 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -7,12 +7,13 @@
 #include <linux/delay.h>
 #include <linux/reboot.h>
 #include <linux/io.h>
+#include <linux/irq.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
 #include <asm/cacheflush.h>
 #include <asm/mach-types.h>
-#include <asm/system.h>
+#include <asm/system_misc.h>
 
 extern const unsigned char relocate_new_kernel[];
 extern const unsigned int relocate_new_kernel_size;
@@ -53,6 +54,29 @@
 		cpu_relax();
 }
 
+static void machine_kexec_mask_interrupts(void)
+{
+	unsigned int i;
+	struct irq_desc *desc;
+
+	for_each_irq_desc(i, desc) {
+		struct irq_chip *chip;
+
+		chip = irq_desc_get_chip(desc);
+		if (!chip)
+			continue;
+
+		if (chip->irq_eoi && irqd_irq_inprogress(&desc->irq_data))
+			chip->irq_eoi(&desc->irq_data);
+
+		if (chip->irq_mask)
+			chip->irq_mask(&desc->irq_data);
+
+		if (chip->irq_disable && !irqd_irq_disabled(&desc->irq_data))
+			chip->irq_disable(&desc->irq_data);
+	}
+}
+
 void machine_crash_shutdown(struct pt_regs *regs)
 {
 	unsigned long msecs;
@@ -70,6 +94,7 @@
 		printk(KERN_WARNING "Non-crashing CPUs did not react to IPI\n");
 
 	crash_save_cpu(regs, smp_processor_id());
+	machine_kexec_mask_interrupts();
 
 	printk(KERN_INFO "Loading crashdump kernel...\n");
 }
diff --git a/arch/arm/kernel/patch.c b/arch/arm/kernel/patch.c
new file mode 100644
index 0000000..07314af
--- /dev/null
+++ b/arch/arm/kernel/patch.c
@@ -0,0 +1,75 @@
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/stop_machine.h>
+
+#include <asm/cacheflush.h>
+#include <asm/smp_plat.h>
+#include <asm/opcodes.h>
+
+#include "patch.h"
+
+struct patch {
+	void *addr;
+	unsigned int insn;
+};
+
+void __kprobes __patch_text(void *addr, unsigned int insn)
+{
+	bool thumb2 = IS_ENABLED(CONFIG_THUMB2_KERNEL);
+	int size;
+
+	if (thumb2 && __opcode_is_thumb16(insn)) {
+		*(u16 *)addr = __opcode_to_mem_thumb16(insn);
+		size = sizeof(u16);
+	} else if (thumb2 && ((uintptr_t)addr & 2)) {
+		u16 first = __opcode_thumb32_first(insn);
+		u16 second = __opcode_thumb32_second(insn);
+		u16 *addrh = addr;
+
+		addrh[0] = __opcode_to_mem_thumb16(first);
+		addrh[1] = __opcode_to_mem_thumb16(second);
+
+		size = sizeof(u32);
+	} else {
+		if (thumb2)
+			insn = __opcode_to_mem_thumb32(insn);
+		else
+			insn = __opcode_to_mem_arm(insn);
+
+		*(u32 *)addr = insn;
+		size = sizeof(u32);
+	}
+
+	flush_icache_range((uintptr_t)(addr),
+			   (uintptr_t)(addr) + size);
+}
+
+static int __kprobes patch_text_stop_machine(void *data)
+{
+	struct patch *patch = data;
+
+	__patch_text(patch->addr, patch->insn);
+
+	return 0;
+}
+
+void __kprobes patch_text(void *addr, unsigned int insn)
+{
+	struct patch patch = {
+		.addr = addr,
+		.insn = insn,
+	};
+
+	if (cache_ops_need_broadcast()) {
+		stop_machine(patch_text_stop_machine, &patch, cpu_online_mask);
+	} else {
+		bool straddles_word = IS_ENABLED(CONFIG_THUMB2_KERNEL)
+				      && __opcode_is_thumb32(insn)
+				      && ((uintptr_t)addr & 2);
+
+		if (straddles_word)
+			stop_machine(patch_text_stop_machine, &patch, NULL);
+		else
+			__patch_text(addr, insn);
+	}
+}
diff --git a/arch/arm/kernel/patch.h b/arch/arm/kernel/patch.h
new file mode 100644
index 0000000..b4731f2
--- /dev/null
+++ b/arch/arm/kernel/patch.h
@@ -0,0 +1,7 @@
+#ifndef _ARM_KERNEL_PATCH_H
+#define _ARM_KERNEL_PATCH_H
+
+void patch_text(void *addr, unsigned int insn);
+void __patch_text(void *addr, unsigned int insn);
+
+#endif
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 8a89d3b..186c8cb 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -738,6 +738,9 @@
 		case 0xC0F0:	/* Cortex-A15 */
 			cpu_pmu = armv7_a15_pmu_init();
 			break;
+		case 0xC070:	/* Cortex-A7 */
+			cpu_pmu = armv7_a7_pmu_init();
+			break;
 		}
 	/* Intel CPUs [xscale]. */
 	} else if (0x69 == implementor) {
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 4d7095a..00755d8 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -610,6 +610,130 @@
 };
 
 /*
+ * Cortex-A7 HW events mapping
+ */
+static const unsigned armv7_a7_perf_map[PERF_COUNT_HW_MAX] = {
+	[PERF_COUNT_HW_CPU_CYCLES]		= ARMV7_PERFCTR_CPU_CYCLES,
+	[PERF_COUNT_HW_INSTRUCTIONS]		= ARMV7_PERFCTR_INSTR_EXECUTED,
+	[PERF_COUNT_HW_CACHE_REFERENCES]	= ARMV7_PERFCTR_L1_DCACHE_ACCESS,
+	[PERF_COUNT_HW_CACHE_MISSES]		= ARMV7_PERFCTR_L1_DCACHE_REFILL,
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= ARMV7_PERFCTR_PC_WRITE,
+	[PERF_COUNT_HW_BRANCH_MISSES]		= ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+	[PERF_COUNT_HW_BUS_CYCLES]		= ARMV7_PERFCTR_BUS_CYCLES,
+	[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND]	= HW_OP_UNSUPPORTED,
+	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND]	= HW_OP_UNSUPPORTED,
+};
+
+static const unsigned armv7_a7_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+					[PERF_COUNT_HW_CACHE_OP_MAX]
+					[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+	[C(L1D)] = {
+		/*
+		 * The performance counters don't differentiate between read
+		 * and write accesses/misses so this isn't strictly correct,
+		 * but it's the best we can do. Writes and reads get
+		 * combined.
+		 */
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_L1_DCACHE_ACCESS,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_L1_DCACHE_REFILL,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_L1_DCACHE_ACCESS,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_L1_DCACHE_REFILL,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(L1I)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_L1_ICACHE_ACCESS,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_L1_ICACHE_REFILL,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_L1_ICACHE_ACCESS,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_L1_ICACHE_REFILL,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(LL)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_L2_CACHE_ACCESS,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_L2_CACHE_REFILL,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_L2_CACHE_ACCESS,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_L2_CACHE_REFILL,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(DTLB)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_DTLB_REFILL,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_DTLB_REFILL,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(ITLB)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_ITLB_REFILL,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_ITLB_REFILL,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(BPU)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_PC_BRANCH_PRED,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_PC_BRANCH_PRED,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(NODE)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+};
+
+/*
  * Perf Events' indices
  */
 #define	ARMV7_IDX_CYCLE_COUNTER	0
@@ -1104,6 +1228,12 @@
 				&armv7_a15_perf_cache_map, 0xFF);
 }
 
+static int armv7_a7_map_event(struct perf_event *event)
+{
+	return map_cpu_event(event, &armv7_a7_perf_map,
+				&armv7_a7_perf_cache_map, 0xFF);
+}
+
 static struct arm_pmu armv7pmu = {
 	.handle_irq		= armv7pmu_handle_irq,
 	.enable			= armv7pmu_enable_event,
@@ -1164,6 +1294,16 @@
 	armv7pmu.set_event_filter = armv7pmu_set_event_filter;
 	return &armv7pmu;
 }
+
+static struct arm_pmu *__init armv7_a7_pmu_init(void)
+{
+	armv7pmu.id		= ARM_PERF_PMU_ID_CA7;
+	armv7pmu.name		= "ARMv7 Cortex-A7";
+	armv7pmu.map_event	= armv7_a7_map_event;
+	armv7pmu.num_events	= armv7_read_num_pmnc_events();
+	armv7pmu.set_event_filter = armv7pmu_set_event_filter;
+	return &armv7pmu;
+}
 #else
 static struct arm_pmu *__init armv7_a8_pmu_init(void)
 {
@@ -1184,4 +1324,9 @@
 {
 	return NULL;
 }
+
+static struct arm_pmu *__init armv7_a7_pmu_init(void)
+{
+	return NULL;
+}
 #endif	/* CONFIG_CPU_V7 */
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index c2ae3cd..2b7b017 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -35,7 +35,6 @@
 #include <asm/cacheflush.h>
 #include <asm/leds.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/thread_notify.h>
 #include <asm/stacktrace.h>
 #include <asm/mach/time.h>
@@ -61,8 +60,6 @@
 
 static volatile int hlt_counter;
 
-#include <mach/system.h>
-
 void disable_hlt(void)
 {
 	hlt_counter++;
@@ -181,13 +178,17 @@
 EXPORT_SYMBOL_GPL(cpu_idle_wait);
 
 /*
- * This is our default idle handler.  We need to disable
- * interrupts here to ensure we don't miss a wakeup call.
+ * This is our default idle handler.
  */
+
+void (*arm_pm_idle)(void);
+
 static void default_idle(void)
 {
-	if (!need_resched())
-		arch_idle();
+	if (arm_pm_idle)
+		arm_pm_idle();
+	else
+		cpu_do_idle();
 	local_irq_enable();
 }
 
@@ -215,6 +216,10 @@
 				cpu_die();
 #endif
 
+			/*
+			 * We need to disable interrupts here
+			 * to ensure we don't miss a wakeup call.
+			 */
 			local_irq_disable();
 #ifdef CONFIG_PL310_ERRATA_769419
 			wmb();
@@ -222,19 +227,18 @@
 			if (hlt_counter) {
 				local_irq_enable();
 				cpu_relax();
-			} else {
+			} else if (!need_resched()) {
 				stop_critical_timings();
 				if (cpuidle_idle_call())
 					pm_idle();
 				start_critical_timings();
 				/*
-				 * This will eventually be removed - pm_idle
-				 * functions should always return with IRQs
-				 * enabled.
+				 * pm_idle functions must always
+				 * return with IRQs enabled.
 				 */
 				WARN_ON(irqs_disabled());
+			} else
 				local_irq_enable();
-			}
 		}
 		leds_event(led_idle_end);
 		rcu_idle_exit();
@@ -524,22 +528,39 @@
 #ifdef CONFIG_MMU
 /*
  * The vectors page is always readable from user space for the
- * atomic helpers and the signal restart code.  Let's declare a mapping
- * for it so it is visible through ptrace and /proc/<pid>/mem.
+ * atomic helpers and the signal restart code. Insert it into the
+ * gate_vma so that it is visible through ptrace and /proc/<pid>/mem.
  */
+static struct vm_area_struct gate_vma;
 
-int vectors_user_mapping(void)
+static int __init gate_vma_init(void)
 {
-	struct mm_struct *mm = current->mm;
-	return install_special_mapping(mm, 0xffff0000, PAGE_SIZE,
-				       VM_READ | VM_EXEC |
-				       VM_MAYREAD | VM_MAYEXEC |
-				       VM_ALWAYSDUMP | VM_RESERVED,
-				       NULL);
+	gate_vma.vm_start	= 0xffff0000;
+	gate_vma.vm_end		= 0xffff0000 + PAGE_SIZE;
+	gate_vma.vm_page_prot	= PAGE_READONLY_EXEC;
+	gate_vma.vm_flags	= VM_READ | VM_EXEC |
+				  VM_MAYREAD | VM_MAYEXEC;
+	return 0;
+}
+arch_initcall(gate_vma_init);
+
+struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
+{
+	return &gate_vma;
+}
+
+int in_gate_area(struct mm_struct *mm, unsigned long addr)
+{
+	return (addr >= gate_vma.vm_start) && (addr < gate_vma.vm_end);
+}
+
+int in_gate_area_no_mm(unsigned long addr)
+{
+	return in_gate_area(NULL, addr);
 }
 
 const char *arch_vma_name(struct vm_area_struct *vma)
 {
-	return (vma->vm_start == 0xffff0000) ? "[vectors]" : NULL;
+	return (vma == &gate_vma) ? "[vectors]" : NULL;
 }
 #endif
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index ede6443..80abafb 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -26,7 +26,6 @@
 #include <linux/audit.h>
 
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 
 #define REG_PC	15
@@ -257,7 +256,7 @@
 {
 	unsigned long tmp;
 
-	if (off & 3 || off >= sizeof(struct user))
+	if (off & 3)
 		return -EIO;
 
 	tmp = 0;
@@ -269,6 +268,8 @@
 		tmp = tsk->mm->end_code;
 	else if (off < sizeof(struct pt_regs))
 		tmp = get_user_reg(tsk, off >> 2);
+	else if (off >= sizeof(struct user))
+		return -EIO;
 
 	return put_user(tmp, ret);
 }
diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c
index 5416c7c..27d186a 100644
--- a/arch/arm/kernel/sched_clock.c
+++ b/arch/arm/kernel/sched_clock.c
@@ -10,6 +10,7 @@
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/syscore_ops.h>
 #include <linux/timer.h>
 
 #include <asm/sched_clock.h>
@@ -164,3 +165,20 @@
 
 	sched_clock_poll(sched_clock_timer.data);
 }
+
+static int sched_clock_suspend(void)
+{
+	sched_clock_poll(sched_clock_timer.data);
+	return 0;
+}
+
+static struct syscore_ops sched_clock_ops = {
+	.suspend = sched_clock_suspend,
+};
+
+static int __init sched_clock_syscore_init(void)
+{
+	register_syscore_ops(&sched_clock_ops);
+	return 0;
+}
+device_initcall(sched_clock_syscore_init);
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index a255c39..b914113 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -33,6 +33,7 @@
 #include <linux/sort.h>
 
 #include <asm/unified.h>
+#include <asm/cp15.h>
 #include <asm/cpu.h>
 #include <asm/cputype.h>
 #include <asm/elf.h>
@@ -44,12 +45,13 @@
 #include <asm/cacheflush.h>
 #include <asm/cachetype.h>
 #include <asm/tlbflush.h>
-#include <asm/system.h>
 
 #include <asm/prom.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
+#include <asm/system_info.h>
+#include <asm/system_misc.h>
 #include <asm/traps.h>
 #include <asm/unwind.h>
 #include <asm/memblock.h>
@@ -974,7 +976,6 @@
 	conswitchp = &dummy_con;
 #endif
 #endif
-	early_trap_init();
 
 	if (mdesc->init_early)
 		mdesc->init_early();
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 9e617bd..7cb532f 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -66,12 +66,13 @@
  */
 asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
 {
-	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sighand->siglock);
+	sigset_t blocked;
+
 	current->saved_sigmask = current->blocked;
-	siginitset(&current->blocked, mask);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+
+	mask &= _BLOCKABLE;
+	siginitset(&blocked, mask);
+	set_current_blocked(&blocked);
 
 	current->state = TASK_INTERRUPTIBLE;
 	schedule();
@@ -280,10 +281,7 @@
 	err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
 	if (err == 0) {
 		sigdelsetmask(&set, ~_BLOCKABLE);
-		spin_lock_irq(&current->sighand->siglock);
-		current->blocked = set;
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
+		set_current_blocked(&set);
 	}
 
 	__get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err);
@@ -636,13 +634,7 @@
 	/*
 	 * Block the signal if we were successful.
 	 */
-	spin_lock_irq(&tsk->sighand->siglock);
-	sigorsets(&tsk->blocked, &tsk->blocked,
-		  &ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&tsk->blocked, sig);
-	recalc_sigpending();
-	spin_unlock_irq(&tsk->sighand->siglock);
+	block_sigmask(ka, sig);
 
 	return 0;
 }
diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S
index 1f268bd..987dcf3 100644
--- a/arch/arm/kernel/sleep.S
+++ b/arch/arm/kernel/sleep.S
@@ -4,7 +4,6 @@
 #include <asm/assembler.h>
 #include <asm/glue-cache.h>
 #include <asm/glue-proc.h>
-#include <asm/system.h>
 	.text
 
 /*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index d616ed5..addbbe8 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -58,6 +58,8 @@
 	IPI_CPU_STOP,
 };
 
+static DECLARE_COMPLETION(cpu_running);
+
 int __cpuinit __cpu_up(unsigned int cpu)
 {
 	struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu);
@@ -98,20 +100,12 @@
 	 */
 	ret = boot_secondary(cpu, idle);
 	if (ret == 0) {
-		unsigned long timeout;
-
 		/*
 		 * CPU was successfully started, wait for it
 		 * to come online or time out.
 		 */
-		timeout = jiffies + HZ;
-		while (time_before(jiffies, timeout)) {
-			if (cpu_online(cpu))
-				break;
-
-			udelay(10);
-			barrier();
-		}
+		wait_for_completion_timeout(&cpu_running,
+						 msecs_to_jiffies(1000));
 
 		if (!cpu_online(cpu)) {
 			pr_crit("CPU%u: failed to come online\n", cpu);
@@ -246,6 +240,8 @@
 	store_cpu_topology(cpuid);
 }
 
+static void percpu_timer_setup(void);
+
 /*
  * This is the secondary CPU boot entry.  We're using this CPUs
  * idle thread stack, but a set of temporary page tables.
@@ -286,9 +282,10 @@
 	/*
 	 * OK, now it's safe to let the boot CPU continue.  Wait for
 	 * the CPU migration code to notice that the CPU is online
-	 * before we continue.
+	 * before we continue - which happens after __cpu_up returns.
 	 */
 	set_cpu_online(cpu, true);
+	complete(&cpu_running);
 
 	/*
 	 * Setup the percpu timer for this CPU.
@@ -352,7 +349,7 @@
 		 * re-initialize the map in platform_smp_prepare_cpus() if
 		 * present != possible (e.g. physical hotplug).
 		 */
-		init_cpu_present(&cpu_possible_map);
+		init_cpu_present(cpu_possible_mask);
 
 		/*
 		 * Initialise the SCU if there are more than one CPU
@@ -452,7 +449,20 @@
 	clockevents_register_device(evt);
 }
 
-void __cpuinit percpu_timer_setup(void)
+static struct local_timer_ops *lt_ops;
+
+#ifdef CONFIG_LOCAL_TIMERS
+int local_timer_register(struct local_timer_ops *ops)
+{
+	if (lt_ops)
+		return -EBUSY;
+
+	lt_ops = ops;
+	return 0;
+}
+#endif
+
+static void __cpuinit percpu_timer_setup(void)
 {
 	unsigned int cpu = smp_processor_id();
 	struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
@@ -460,7 +470,7 @@
 	evt->cpumask = cpumask_of(cpu);
 	evt->broadcast = smp_timer_broadcast;
 
-	if (local_timer_setup(evt))
+	if (!lt_ops || lt_ops->setup(evt))
 		broadcast_timer_setup(evt);
 }
 
@@ -475,7 +485,8 @@
 	unsigned int cpu = smp_processor_id();
 	struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
 
-	local_timer_stop(evt);
+	if (lt_ops)
+		lt_ops->stop(evt);
 }
 #endif
 
@@ -570,8 +581,9 @@
 	unsigned long timeout;
 
 	if (num_online_cpus() > 1) {
-		cpumask_t mask = cpu_online_map;
-		cpu_clear(smp_processor_id(), mask);
+		struct cpumask mask;
+		cpumask_copy(&mask, cpu_online_mask);
+		cpumask_clear_cpu(smp_processor_id(), &mask);
 
 		smp_cross_call(&mask, IPI_CPU_STOP);
 	}
diff --git a/arch/arm/kernel/smp_tlb.c b/arch/arm/kernel/smp_tlb.c
index 7dcb352..02c5d2c 100644
--- a/arch/arm/kernel/smp_tlb.c
+++ b/arch/arm/kernel/smp_tlb.c
@@ -13,18 +13,6 @@
 #include <asm/smp_plat.h>
 #include <asm/tlbflush.h>
 
-static void on_each_cpu_mask(void (*func)(void *), void *info, int wait,
-	const struct cpumask *mask)
-{
-	preempt_disable();
-
-	smp_call_function_many(mask, func, info, wait);
-	if (cpumask_test_cpu(smp_processor_id(), mask))
-		func(info);
-
-	preempt_enable();
-}
-
 /**********************************************************************/
 
 /*
@@ -87,7 +75,7 @@
 void flush_tlb_mm(struct mm_struct *mm)
 {
 	if (tlb_ops_need_broadcast())
-		on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, mm_cpumask(mm));
+		on_each_cpu_mask(mm_cpumask(mm), ipi_flush_tlb_mm, mm, 1);
 	else
 		local_flush_tlb_mm(mm);
 }
@@ -98,7 +86,8 @@
 		struct tlb_args ta;
 		ta.ta_vma = vma;
 		ta.ta_start = uaddr;
-		on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, mm_cpumask(vma->vm_mm));
+		on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_tlb_page,
+					&ta, 1);
 	} else
 		local_flush_tlb_page(vma, uaddr);
 }
@@ -121,7 +110,8 @@
 		ta.ta_vma = vma;
 		ta.ta_start = start;
 		ta.ta_end = end;
-		on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, mm_cpumask(vma->vm_mm));
+		on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_tlb_range,
+					&ta, 1);
 	} else
 		local_flush_tlb_range(vma, start, end);
 }
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 7a79b24..fef42b2 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -18,20 +18,23 @@
 #include <linux/smp.h>
 #include <linux/jiffies.h>
 #include <linux/clockchips.h>
-#include <linux/irq.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
 
 #include <asm/smp_twd.h>
 #include <asm/localtimer.h>
 #include <asm/hardware/gic.h>
 
 /* set up by the platform code */
-void __iomem *twd_base;
+static void __iomem *twd_base;
 
 static struct clk *twd_clk;
 static unsigned long twd_timer_rate;
 
 static struct clock_event_device __percpu **twd_evt;
+static int twd_ppi;
 
 static void twd_set_mode(enum clock_event_mode mode,
 			struct clock_event_device *clk)
@@ -77,7 +80,7 @@
  * If a local timer interrupt has occurred, acknowledge and return 1.
  * Otherwise, return 0.
  */
-int twd_timer_ack(void)
+static int twd_timer_ack(void)
 {
 	if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) {
 		__raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
@@ -87,7 +90,7 @@
 	return 0;
 }
 
-void twd_timer_stop(struct clock_event_device *clk)
+static void twd_timer_stop(struct clock_event_device *clk)
 {
 	twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
 	disable_percpu_irq(clk->irq);
@@ -222,28 +225,10 @@
 /*
  * Setup the local clock events for a CPU.
  */
-void __cpuinit twd_timer_setup(struct clock_event_device *clk)
+static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 {
 	struct clock_event_device **this_cpu_clk;
 
-	if (!twd_evt) {
-		int err;
-
-		twd_evt = alloc_percpu(struct clock_event_device *);
-		if (!twd_evt) {
-			pr_err("twd: can't allocate memory\n");
-			return;
-		}
-
-		err = request_percpu_irq(clk->irq, twd_handler,
-					 "twd", twd_evt);
-		if (err) {
-			pr_err("twd: can't register interrupt %d (%d)\n",
-			       clk->irq, err);
-			return;
-		}
-	}
-
 	if (!twd_clk)
 		twd_clk = twd_get_clock();
 
@@ -260,6 +245,7 @@
 	clk->rating = 350;
 	clk->set_mode = twd_set_mode;
 	clk->set_next_event = twd_set_next_event;
+	clk->irq = twd_ppi;
 
 	this_cpu_clk = __this_cpu_ptr(twd_evt);
 	*this_cpu_clk = clk;
@@ -267,4 +253,95 @@
 	clockevents_config_and_register(clk, twd_timer_rate,
 					0xf, 0xffffffff);
 	enable_percpu_irq(clk->irq, 0);
+
+	return 0;
 }
+
+static struct local_timer_ops twd_lt_ops __cpuinitdata = {
+	.setup	= twd_timer_setup,
+	.stop	= twd_timer_stop,
+};
+
+static int __init twd_local_timer_common_register(void)
+{
+	int err;
+
+	twd_evt = alloc_percpu(struct clock_event_device *);
+	if (!twd_evt) {
+		err = -ENOMEM;
+		goto out_free;
+	}
+
+	err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt);
+	if (err) {
+		pr_err("twd: can't register interrupt %d (%d)\n", twd_ppi, err);
+		goto out_free;
+	}
+
+	err = local_timer_register(&twd_lt_ops);
+	if (err)
+		goto out_irq;
+
+	return 0;
+
+out_irq:
+	free_percpu_irq(twd_ppi, twd_evt);
+out_free:
+	iounmap(twd_base);
+	twd_base = NULL;
+	free_percpu(twd_evt);
+
+	return err;
+}
+
+int __init twd_local_timer_register(struct twd_local_timer *tlt)
+{
+	if (twd_base || twd_evt)
+		return -EBUSY;
+
+	twd_ppi	= tlt->res[1].start;
+
+	twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0]));
+	if (!twd_base)
+		return -ENOMEM;
+
+	return twd_local_timer_common_register();
+}
+
+#ifdef CONFIG_OF
+const static struct of_device_id twd_of_match[] __initconst = {
+	{ .compatible = "arm,cortex-a9-twd-timer",	},
+	{ .compatible = "arm,cortex-a5-twd-timer",	},
+	{ .compatible = "arm,arm11mp-twd-timer",	},
+	{ },
+};
+
+void __init twd_local_timer_of_register(void)
+{
+	struct device_node *np;
+	int err;
+
+	np = of_find_matching_node(NULL, twd_of_match);
+	if (!np) {
+		err = -ENODEV;
+		goto out;
+	}
+
+	twd_ppi = irq_of_parse_and_map(np, 0);
+	if (!twd_ppi) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	twd_base = of_iomap(np, 0);
+	if (!twd_base) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	err = twd_local_timer_common_register();
+
+out:
+	WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
+}
+#endif
diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c
index 01ec453..30ae6bb 100644
--- a/arch/arm/kernel/tcm.c
+++ b/arch/arm/kernel/tcm.c
@@ -16,6 +16,7 @@
 #include <asm/cputype.h>
 #include <asm/mach/map.h>
 #include <asm/memory.h>
+#include <asm/system_info.h>
 #include "tcm.h"
 
 static struct gen_pool *tcm_pool;
diff --git a/arch/arm/kernel/thumbee.c b/arch/arm/kernel/thumbee.c
index 9cb7aac..aab8997 100644
--- a/arch/arm/kernel/thumbee.c
+++ b/arch/arm/kernel/thumbee.c
@@ -20,6 +20,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 
+#include <asm/system_info.h>
 #include <asm/thread_notify.h>
 
 /*
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 8c57dd3..fe31b22 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -25,8 +25,6 @@
 #include <linux/timer.h>
 #include <linux/irq.h>
 
-#include <linux/mc146818rtc.h>
-
 #include <asm/leds.h>
 #include <asm/thread_info.h>
 #include <asm/sched_clock.h>
@@ -149,8 +147,6 @@
 {
 	system_timer = machine_desc->timer;
 	system_timer->init();
-#ifdef CONFIG_HAVE_SCHED_CLOCK
 	sched_clock_postinit();
-#endif
 }
 
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index f84dfe6..7784547 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -29,11 +29,11 @@
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
 #include <asm/exception.h>
-#include <asm/system.h>
 #include <asm/unistd.h>
 #include <asm/traps.h>
 #include <asm/unwind.h>
 #include <asm/tls.h>
+#include <asm/system_misc.h>
 
 #include "signal.h"
 
@@ -227,6 +227,11 @@
 #else
 #define S_SMP ""
 #endif
+#ifdef CONFIG_THUMB2_KERNEL
+#define S_ISA " THUMB2"
+#else
+#define S_ISA " ARM"
+#endif
 
 static int __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs)
 {
@@ -234,8 +239,8 @@
 	static int die_counter;
 	int ret;
 
-	printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n",
-	       str, err, ++die_counter);
+	printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP
+	       S_ISA "\n", str, err, ++die_counter);
 
 	/* trap and error numbers are mostly meaningless on ARM */
 	ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV);
@@ -784,18 +789,16 @@
 		memcpy((void *)vectors + 0xfe0, (void *)vectors + 0xfe8, 4);
 }
 
-void __init early_trap_init(void)
+void __init early_trap_init(void *vectors_base)
 {
-#if defined(CONFIG_CPU_USE_DOMAINS)
-	unsigned long vectors = CONFIG_VECTORS_BASE;
-#else
-	unsigned long vectors = (unsigned long)vectors_page;
-#endif
+	unsigned long vectors = (unsigned long)vectors_base;
 	extern char __stubs_start[], __stubs_end[];
 	extern char __vectors_start[], __vectors_end[];
 	extern char __kuser_helper_start[], __kuser_helper_end[];
 	int kuser_sz = __kuser_helper_end - __kuser_helper_start;
 
+	vectors_page = vectors_base;
+
 	/*
 	 * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
 	 * into the vector page, mapped at 0xffff0000, and ensure these
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 71feb00..45db05d 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -20,9 +20,11 @@
 
 config AT91_SAM9_ALT_RESET
 	bool
+	default !ARCH_AT91X40
 
 config AT91_SAM9G45_RESET
 	bool
+	default !ARCH_AT91X40
 
 menu "Atmel AT91 System-on-Chip"
 
@@ -45,7 +47,6 @@
 	select HAVE_AT91_USART4
 	select HAVE_AT91_USART5
 	select HAVE_NET_MACB
-	select AT91_SAM9_ALT_RESET
 
 config ARCH_AT91SAM9261
 	bool "AT91SAM9261"
@@ -53,7 +54,6 @@
 	select GENERIC_CLOCKEVENTS
 	select HAVE_FB_ATMEL
 	select HAVE_AT91_DBGU0
-	select AT91_SAM9_ALT_RESET
 
 config ARCH_AT91SAM9G10
 	bool "AT91SAM9G10"
@@ -61,7 +61,6 @@
 	select GENERIC_CLOCKEVENTS
 	select HAVE_AT91_DBGU0
 	select HAVE_FB_ATMEL
-	select AT91_SAM9_ALT_RESET
 
 config ARCH_AT91SAM9263
 	bool "AT91SAM9263"
@@ -70,7 +69,6 @@
 	select HAVE_FB_ATMEL
 	select HAVE_NET_MACB
 	select HAVE_AT91_DBGU1
-	select AT91_SAM9_ALT_RESET
 
 config ARCH_AT91SAM9RL
 	bool "AT91SAM9RL"
@@ -79,7 +77,6 @@
 	select HAVE_AT91_USART3
 	select HAVE_FB_ATMEL
 	select HAVE_AT91_DBGU0
-	select AT91_SAM9_ALT_RESET
 
 config ARCH_AT91SAM9G20
 	bool "AT91SAM9G20"
@@ -90,7 +87,6 @@
 	select HAVE_AT91_USART4
 	select HAVE_AT91_USART5
 	select HAVE_NET_MACB
-	select AT91_SAM9_ALT_RESET
 
 config ARCH_AT91SAM9G45
 	bool "AT91SAM9G45"
@@ -100,16 +96,14 @@
 	select HAVE_FB_ATMEL
 	select HAVE_NET_MACB
 	select HAVE_AT91_DBGU1
-	select AT91_SAM9G45_RESET
 
-config ARCH_AT91CAP9
-	bool "AT91CAP9"
+config ARCH_AT91SAM9X5
+	bool "AT91SAM9x5 family"
 	select CPU_ARM926T
 	select GENERIC_CLOCKEVENTS
 	select HAVE_FB_ATMEL
 	select HAVE_NET_MACB
-	select HAVE_AT91_DBGU1
-	select AT91_SAM9G45_RESET
+	select HAVE_AT91_DBGU0
 
 config ARCH_AT91X40
 	bool "AT91x40"
@@ -447,21 +441,6 @@
 
 # ----------------------------------------------------------
 
-if ARCH_AT91CAP9
-
-comment "AT91CAP9 Board Type"
-
-config MACH_AT91CAP9ADK
-	bool "Atmel AT91CAP9A-DK Evaluation Kit"
-	select HAVE_AT91_DATAFLASH_CARD
-	help
-	  Select this if you are using Atmel's AT91CAP9A-DK Evaluation Kit.
-	  <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4138>
-
-endif
-
-# ----------------------------------------------------------
-
 if ARCH_AT91X40
 
 comment "AT91X40 Board Type"
@@ -544,7 +523,7 @@
 	depends on HAVE_AT91_DBGU0
 
 config AT91_EARLY_DBGU1
-	bool "DBGU on 9263, 9g45 and cap9"
+	bool "DBGU on 9263 and 9g45"
 	depends on HAVE_AT91_DBGU1
 
 config AT91_EARLY_USART0
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 705e1fb..8512e53 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -20,7 +20,7 @@
 obj-$(CONFIG_ARCH_AT91SAM9RL)	+= at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91SAM9G20)	+= at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91SAM9G45)	+= at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91CAP9)	+= at91cap9.o at91sam926x_time.o at91cap9_devices.o sam9_smc.o
+obj-$(CONFIG_ARCH_AT91SAM9X5)	+= at91sam9x5.o at91sam926x_time.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91X40)	+= at91x40.o at91x40_time.o
 
 # AT91RM9200 board-specific support
@@ -81,9 +81,6 @@
 # AT91SAM board with device-tree
 obj-$(CONFIG_MACH_AT91SAM_DT) += board-dt.o
 
-# AT91CAP9 board-specific support
-obj-$(CONFIG_MACH_AT91CAP9ADK)	+= board-cap9adk.o
-
 # AT91X40 board-specific support
 obj-$(CONFIG_MACH_AT91EB01)	+= board-eb01.o
 
diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
index 8ddafad..0da66ca 100644
--- a/arch/arm/mach-at91/Makefile.boot
+++ b/arch/arm/mach-at91/Makefile.boot
@@ -3,11 +3,7 @@
 #   PARAMS_PHYS must be within 4MB of ZRELADDR
 #   INITRD_PHYS must be in RAM
 
-ifeq ($(CONFIG_ARCH_AT91CAP9),y)
-   zreladdr-y	+= 0x70008000
-params_phys-y	:= 0x70000100
-initrd_phys-y	:= 0x70410000
-else ifeq ($(CONFIG_ARCH_AT91SAM9G45),y)
+ifeq ($(CONFIG_ARCH_AT91SAM9G45),y)
    zreladdr-y	+= 0x70008000
 params_phys-y	:= 0x70000100
 initrd_phys-y	:= 0x70410000
@@ -17,4 +13,10 @@
 initrd_phys-y	:= 0x20410000
 endif
 
-dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb usb_a9g20.dtb
+# Keep dtb files sorted alphabetically for each SoC
+# sam9g20
+dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb
+# sam9g45
+dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb
+# sam9x5
+dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb
diff --git a/arch/arm/mach-at91/at91cap9.c b/arch/arm/mach-at91/at91cap9.c
deleted file mode 100644
index a42edc2..0000000
--- a/arch/arm/mach-at91/at91cap9.c
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * arch/arm/mach-at91/at91cap9.c
- *
- *  Copyright (C) 2007 Stelian Pop <stelian.pop@leadtechdesign.com>
- *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
- *  Copyright (C) 2007 Atmel 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.
- *
- */
-
-#include <linux/module.h>
-
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <mach/cpu.h>
-#include <mach/at91cap9.h>
-#include <mach/at91_pmc.h>
-
-#include "soc.h"
-#include "generic.h"
-#include "clock.h"
-#include "sam9_smc.h"
-
-/* --------------------------------------------------------------------
- *  Clocks
- * -------------------------------------------------------------------- */
-
-/*
- * The peripheral clocks.
- */
-static struct clk pioABCD_clk = {
-	.name		= "pioABCD_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_PIOABCD,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk mpb0_clk = {
-	.name		= "mpb0_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_MPB0,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk mpb1_clk = {
-	.name		= "mpb1_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_MPB1,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk mpb2_clk = {
-	.name		= "mpb2_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_MPB2,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk mpb3_clk = {
-	.name		= "mpb3_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_MPB3,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk mpb4_clk = {
-	.name		= "mpb4_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_MPB4,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart0_clk = {
-	.name		= "usart0_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_US0,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart1_clk = {
-	.name		= "usart1_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_US1,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart2_clk = {
-	.name		= "usart2_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_US2,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc0_clk = {
-	.name		= "mci0_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_MCI0,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc1_clk = {
-	.name		= "mci1_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_MCI1,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk can_clk = {
-	.name		= "can_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_CAN,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi_clk = {
-	.name		= "twi_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_TWI,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi0_clk = {
-	.name		= "spi0_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_SPI0,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi1_clk = {
-	.name		= "spi1_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_SPI1,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc0_clk = {
-	.name		= "ssc0_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_SSC0,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc1_clk = {
-	.name		= "ssc1_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_SSC1,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk ac97_clk = {
-	.name		= "ac97_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_AC97C,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk tcb_clk = {
-	.name		= "tcb_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_TCB,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk pwm_clk = {
-	.name		= "pwm_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_PWMC,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk macb_clk = {
-	.name		= "pclk",
-	.pmc_mask	= 1 << AT91CAP9_ID_EMAC,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk aestdes_clk = {
-	.name		= "aestdes_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_AESTDES,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk adc_clk = {
-	.name		= "adc_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_ADC,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk isi_clk = {
-	.name		= "isi_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_ISI,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk lcdc_clk = {
-	.name		= "lcdc_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_LCDC,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk dma_clk = {
-	.name		= "dma_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_DMA,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk udphs_clk = {
-	.name		= "udphs_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_UDPHS,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk ohci_clk = {
-	.name		= "ohci_clk",
-	.pmc_mask	= 1 << AT91CAP9_ID_UHP,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-
-static struct clk *periph_clocks[] __initdata = {
-	&pioABCD_clk,
-	&mpb0_clk,
-	&mpb1_clk,
-	&mpb2_clk,
-	&mpb3_clk,
-	&mpb4_clk,
-	&usart0_clk,
-	&usart1_clk,
-	&usart2_clk,
-	&mmc0_clk,
-	&mmc1_clk,
-	&can_clk,
-	&twi_clk,
-	&spi0_clk,
-	&spi1_clk,
-	&ssc0_clk,
-	&ssc1_clk,
-	&ac97_clk,
-	&tcb_clk,
-	&pwm_clk,
-	&macb_clk,
-	&aestdes_clk,
-	&adc_clk,
-	&isi_clk,
-	&lcdc_clk,
-	&dma_clk,
-	&udphs_clk,
-	&ohci_clk,
-	// irq0 .. irq1
-};
-
-static struct clk_lookup periph_clocks_lookups[] = {
-	/* One additional fake clock for macb_hclk */
-	CLKDEV_CON_ID("hclk", &macb_clk),
-	CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk),
-	CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk),
-	CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
-	CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
-	CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
-	CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
-	CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
-	CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
-	CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
-	/* fake hclk clock */
-	CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
-	CLKDEV_CON_ID("pioA", &pioABCD_clk),
-	CLKDEV_CON_ID("pioB", &pioABCD_clk),
-	CLKDEV_CON_ID("pioC", &pioABCD_clk),
-	CLKDEV_CON_ID("pioD", &pioABCD_clk),
-};
-
-static struct clk_lookup usart_clocks_lookups[] = {
-	CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
-	CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
-	CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
-	CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
-};
-
-/*
- * The four programmable clocks.
- * You must configure pin multiplexing to bring these signals out.
- */
-static struct clk pck0 = {
-	.name		= "pck0",
-	.pmc_mask	= AT91_PMC_PCK0,
-	.type		= CLK_TYPE_PROGRAMMABLE,
-	.id		= 0,
-};
-static struct clk pck1 = {
-	.name		= "pck1",
-	.pmc_mask	= AT91_PMC_PCK1,
-	.type		= CLK_TYPE_PROGRAMMABLE,
-	.id		= 1,
-};
-static struct clk pck2 = {
-	.name		= "pck2",
-	.pmc_mask	= AT91_PMC_PCK2,
-	.type		= CLK_TYPE_PROGRAMMABLE,
-	.id		= 2,
-};
-static struct clk pck3 = {
-	.name		= "pck3",
-	.pmc_mask	= AT91_PMC_PCK3,
-	.type		= CLK_TYPE_PROGRAMMABLE,
-	.id		= 3,
-};
-
-static void __init at91cap9_register_clocks(void)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
-		clk_register(periph_clocks[i]);
-
-	clkdev_add_table(periph_clocks_lookups,
-			 ARRAY_SIZE(periph_clocks_lookups));
-	clkdev_add_table(usart_clocks_lookups,
-			 ARRAY_SIZE(usart_clocks_lookups));
-
-	clk_register(&pck0);
-	clk_register(&pck1);
-	clk_register(&pck2);
-	clk_register(&pck3);
-}
-
-static struct clk_lookup console_clock_lookup;
-
-void __init at91cap9_set_console_clock(int id)
-{
-	if (id >= ARRAY_SIZE(usart_clocks_lookups))
-		return;
-
-	console_clock_lookup.con_id = "usart";
-	console_clock_lookup.clk = usart_clocks_lookups[id].clk;
-	clkdev_add(&console_clock_lookup);
-}
-
-/* --------------------------------------------------------------------
- *  GPIO
- * -------------------------------------------------------------------- */
-
-static struct at91_gpio_bank at91cap9_gpio[] __initdata = {
-	{
-		.id		= AT91CAP9_ID_PIOABCD,
-		.regbase	= AT91CAP9_BASE_PIOA,
-	}, {
-		.id		= AT91CAP9_ID_PIOABCD,
-		.regbase	= AT91CAP9_BASE_PIOB,
-	}, {
-		.id		= AT91CAP9_ID_PIOABCD,
-		.regbase	= AT91CAP9_BASE_PIOC,
-	}, {
-		.id		= AT91CAP9_ID_PIOABCD,
-		.regbase	= AT91CAP9_BASE_PIOD,
-	}
-};
-
-/* --------------------------------------------------------------------
- *  AT91CAP9 processor initialization
- * -------------------------------------------------------------------- */
-
-static void __init at91cap9_map_io(void)
-{
-	at91_init_sram(0, AT91CAP9_SRAM_BASE, AT91CAP9_SRAM_SIZE);
-}
-
-static void __init at91cap9_ioremap_registers(void)
-{
-	at91_ioremap_shdwc(AT91CAP9_BASE_SHDWC);
-	at91_ioremap_rstc(AT91CAP9_BASE_RSTC);
-	at91sam926x_ioremap_pit(AT91CAP9_BASE_PIT);
-	at91sam9_ioremap_smc(0, AT91CAP9_BASE_SMC);
-}
-
-static void __init at91cap9_initialize(void)
-{
-	arm_pm_restart = at91sam9g45_restart;
-	at91_extern_irq = (1 << AT91CAP9_ID_IRQ0) | (1 << AT91CAP9_ID_IRQ1);
-
-	/* Register GPIO subsystem */
-	at91_gpio_init(at91cap9_gpio, 4);
-
-	/* Remember the silicon revision */
-	if (cpu_is_at91cap9_revB())
-		system_rev = 0xB;
-	else if (cpu_is_at91cap9_revC())
-		system_rev = 0xC;
-}
-
-/* --------------------------------------------------------------------
- *  Interrupt initialization
- * -------------------------------------------------------------------- */
-
-/*
- * The default interrupt priority levels (0 = lowest, 7 = highest).
- */
-static unsigned int at91cap9_default_irq_priority[NR_AIC_IRQS] __initdata = {
-	7,	/* Advanced Interrupt Controller (FIQ) */
-	7,	/* System Peripherals */
-	1,	/* Parallel IO Controller A, B, C and D */
-	0,	/* MP Block Peripheral 0 */
-	0,	/* MP Block Peripheral 1 */
-	0,	/* MP Block Peripheral 2 */
-	0,	/* MP Block Peripheral 3 */
-	0,	/* MP Block Peripheral 4 */
-	5,	/* USART 0 */
-	5,	/* USART 1 */
-	5,	/* USART 2 */
-	0,	/* Multimedia Card Interface 0 */
-	0,	/* Multimedia Card Interface 1 */
-	3,	/* CAN */
-	6,	/* Two-Wire Interface */
-	5,	/* Serial Peripheral Interface 0 */
-	5,	/* Serial Peripheral Interface 1 */
-	4,	/* Serial Synchronous Controller 0 */
-	4,	/* Serial Synchronous Controller 1 */
-	5,	/* AC97 Controller */
-	0,	/* Timer Counter 0, 1 and 2 */
-	0,	/* Pulse Width Modulation Controller */
-	3,	/* Ethernet */
-	0,	/* Advanced Encryption Standard, Triple DES*/
-	0,	/* Analog-to-Digital Converter */
-	0,	/* Image Sensor Interface */
-	3,	/* LCD Controller */
-	0,	/* DMA Controller */
-	2,	/* USB Device Port */
-	2,	/* USB Host port */
-	0,	/* Advanced Interrupt Controller (IRQ0) */
-	0,	/* Advanced Interrupt Controller (IRQ1) */
-};
-
-struct at91_init_soc __initdata at91cap9_soc = {
-	.map_io = at91cap9_map_io,
-	.default_irq_priority = at91cap9_default_irq_priority,
-	.ioremap_registers = at91cap9_ioremap_registers,
-	.register_clocks = at91cap9_register_clocks,
-	.init = at91cap9_initialize,
-};
diff --git a/arch/arm/mach-at91/at91cap9_devices.c b/arch/arm/mach-at91/at91cap9_devices.c
deleted file mode 100644
index d298fb7..0000000
--- a/arch/arm/mach-at91/at91cap9_devices.c
+++ /dev/null
@@ -1,1273 +0,0 @@
-/*
- * arch/arm/mach-at91/at91cap9_devices.c
- *
- *  Copyright (C) 2007 Stelian Pop <stelian.pop@leadtechdesign.com>
- *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
- *  Copyright (C) 2007 Atmel 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.
- *
- */
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/i2c-gpio.h>
-
-#include <video/atmel_lcdc.h>
-
-#include <mach/board.h>
-#include <mach/cpu.h>
-#include <mach/at91cap9.h>
-#include <mach/at91cap9_matrix.h>
-#include <mach/at91sam9_smc.h>
-
-#include "generic.h"
-
-
-/* --------------------------------------------------------------------
- *  USB Host
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-static u64 ohci_dmamask = DMA_BIT_MASK(32);
-static struct at91_usbh_data usbh_data;
-
-static struct resource usbh_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_UHP_BASE,
-		.end	= AT91CAP9_UHP_BASE + SZ_1M - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_UHP,
-		.end	= AT91CAP9_ID_UHP,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91_usbh_device = {
-	.name		= "at91_ohci",
-	.id		= -1,
-	.dev		= {
-				.dma_mask		= &ohci_dmamask,
-				.coherent_dma_mask	= DMA_BIT_MASK(32),
-				.platform_data		= &usbh_data,
-	},
-	.resource	= usbh_resources,
-	.num_resources	= ARRAY_SIZE(usbh_resources),
-};
-
-void __init at91_add_device_usbh(struct at91_usbh_data *data)
-{
-	int i;
-
-	if (!data)
-		return;
-
-	if (cpu_is_at91cap9_revB())
-		irq_set_irq_type(AT91CAP9_ID_UHP, IRQ_TYPE_LEVEL_HIGH);
-
-	/* Enable VBus control for UHP ports */
-	for (i = 0; i < data->ports; i++) {
-		if (gpio_is_valid(data->vbus_pin[i]))
-			at91_set_gpio_output(data->vbus_pin[i], 0);
-	}
-
-	/* Enable overcurrent notification */
-	for (i = 0; i < data->ports; i++) {
-		if (data->overcurrent_pin[i])
-			at91_set_gpio_input(data->overcurrent_pin[i], 1);
-	}
-
-	usbh_data = *data;
-	platform_device_register(&at91_usbh_device);
-}
-#else
-void __init at91_add_device_usbh(struct at91_usbh_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  USB HS Device (Gadget)
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_ATMEL_USBA) || defined(CONFIG_USB_ATMEL_USBA_MODULE)
-
-static struct resource usba_udc_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_UDPHS_FIFO,
-		.end	= AT91CAP9_UDPHS_FIFO + SZ_512K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_BASE_UDPHS,
-		.end	= AT91CAP9_BASE_UDPHS + SZ_1K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[2] = {
-		.start	= AT91CAP9_ID_UDPHS,
-		.end	= AT91CAP9_ID_UDPHS,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-#define EP(nam, idx, maxpkt, maxbk, dma, isoc)			\
-	[idx] = {						\
-		.name		= nam,				\
-		.index		= idx,				\
-		.fifo_size	= maxpkt,			\
-		.nr_banks	= maxbk,			\
-		.can_dma	= dma,				\
-		.can_isoc	= isoc,				\
-	}
-
-static struct usba_ep_data usba_udc_ep[] = {
-	EP("ep0", 0,   64, 1, 0, 0),
-	EP("ep1", 1, 1024, 3, 1, 1),
-	EP("ep2", 2, 1024, 3, 1, 1),
-	EP("ep3", 3, 1024, 2, 1, 1),
-	EP("ep4", 4, 1024, 2, 1, 1),
-	EP("ep5", 5, 1024, 2, 1, 0),
-	EP("ep6", 6, 1024, 2, 1, 0),
-	EP("ep7", 7, 1024, 2, 0, 0),
-};
-
-#undef EP
-
-/*
- * pdata doesn't have room for any endpoints, so we need to
- * append room for the ones we need right after it.
- */
-static struct {
-	struct usba_platform_data pdata;
-	struct usba_ep_data ep[8];
-} usba_udc_data;
-
-static struct platform_device at91_usba_udc_device = {
-	.name		= "atmel_usba_udc",
-	.id		= -1,
-	.dev		= {
-				.platform_data	= &usba_udc_data.pdata,
-	},
-	.resource	= usba_udc_resources,
-	.num_resources	= ARRAY_SIZE(usba_udc_resources),
-};
-
-void __init at91_add_device_usba(struct usba_platform_data *data)
-{
-	if (cpu_is_at91cap9_revB()) {
-		irq_set_irq_type(AT91CAP9_ID_UDPHS, IRQ_TYPE_LEVEL_HIGH);
-		at91_sys_write(AT91_MATRIX_UDPHS, AT91_MATRIX_SELECT_UDPHS |
-						  AT91_MATRIX_UDPHS_BYPASS_LOCK);
-	}
-	else
-		at91_sys_write(AT91_MATRIX_UDPHS, AT91_MATRIX_SELECT_UDPHS);
-
-	/*
-	 * Invalid pins are 0 on AT91, but the usba driver is shared
-	 * with AVR32, which use negative values instead. Once/if
-	 * gpio_is_valid() is ported to AT91, revisit this code.
-	 */
-	usba_udc_data.pdata.vbus_pin = -EINVAL;
-	usba_udc_data.pdata.num_ep = ARRAY_SIZE(usba_udc_ep);
-	memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));
-
-	if (data && gpio_is_valid(data->vbus_pin)) {
-		at91_set_gpio_input(data->vbus_pin, 0);
-		at91_set_deglitch(data->vbus_pin, 1);
-		usba_udc_data.pdata.vbus_pin = data->vbus_pin;
-	}
-
-	/* Pullup pin is handled internally by USB device peripheral */
-
-	platform_device_register(&at91_usba_udc_device);
-}
-#else
-void __init at91_add_device_usba(struct usba_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  Ethernet
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
-static u64 eth_dmamask = DMA_BIT_MASK(32);
-static struct macb_platform_data eth_data;
-
-static struct resource eth_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_EMAC,
-		.end	= AT91CAP9_BASE_EMAC + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_EMAC,
-		.end	= AT91CAP9_ID_EMAC,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91cap9_eth_device = {
-	.name		= "macb",
-	.id		= -1,
-	.dev		= {
-				.dma_mask		= &eth_dmamask,
-				.coherent_dma_mask	= DMA_BIT_MASK(32),
-				.platform_data		= &eth_data,
-	},
-	.resource	= eth_resources,
-	.num_resources	= ARRAY_SIZE(eth_resources),
-};
-
-void __init at91_add_device_eth(struct macb_platform_data *data)
-{
-	if (!data)
-		return;
-
-	if (gpio_is_valid(data->phy_irq_pin)) {
-		at91_set_gpio_input(data->phy_irq_pin, 0);
-		at91_set_deglitch(data->phy_irq_pin, 1);
-	}
-
-	/* Pins used for MII and RMII */
-	at91_set_A_periph(AT91_PIN_PB21, 0);	/* ETXCK_EREFCK */
-	at91_set_A_periph(AT91_PIN_PB22, 0);	/* ERXDV */
-	at91_set_A_periph(AT91_PIN_PB25, 0);	/* ERX0 */
-	at91_set_A_periph(AT91_PIN_PB26, 0);	/* ERX1 */
-	at91_set_A_periph(AT91_PIN_PB27, 0);	/* ERXER */
-	at91_set_A_periph(AT91_PIN_PB28, 0);	/* ETXEN */
-	at91_set_A_periph(AT91_PIN_PB23, 0);	/* ETX0 */
-	at91_set_A_periph(AT91_PIN_PB24, 0);	/* ETX1 */
-	at91_set_A_periph(AT91_PIN_PB30, 0);	/* EMDIO */
-	at91_set_A_periph(AT91_PIN_PB29, 0);	/* EMDC */
-
-	if (!data->is_rmii) {
-		at91_set_B_periph(AT91_PIN_PC25, 0);	/* ECRS */
-		at91_set_B_periph(AT91_PIN_PC26, 0);	/* ECOL */
-		at91_set_B_periph(AT91_PIN_PC22, 0);	/* ERX2 */
-		at91_set_B_periph(AT91_PIN_PC23, 0);	/* ERX3 */
-		at91_set_B_periph(AT91_PIN_PC27, 0);	/* ERXCK */
-		at91_set_B_periph(AT91_PIN_PC20, 0);	/* ETX2 */
-		at91_set_B_periph(AT91_PIN_PC21, 0);	/* ETX3 */
-		at91_set_B_periph(AT91_PIN_PC24, 0);	/* ETXER */
-	}
-
-	eth_data = *data;
-	platform_device_register(&at91cap9_eth_device);
-}
-#else
-void __init at91_add_device_eth(struct macb_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  MMC / SD
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
-static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct at91_mmc_data mmc0_data, mmc1_data;
-
-static struct resource mmc0_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_MCI0,
-		.end	= AT91CAP9_BASE_MCI0 + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_MCI0,
-		.end	= AT91CAP9_ID_MCI0,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91cap9_mmc0_device = {
-	.name		= "at91_mci",
-	.id		= 0,
-	.dev		= {
-				.dma_mask		= &mmc_dmamask,
-				.coherent_dma_mask	= DMA_BIT_MASK(32),
-				.platform_data		= &mmc0_data,
-	},
-	.resource	= mmc0_resources,
-	.num_resources	= ARRAY_SIZE(mmc0_resources),
-};
-
-static struct resource mmc1_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_MCI1,
-		.end	= AT91CAP9_BASE_MCI1 + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_MCI1,
-		.end	= AT91CAP9_ID_MCI1,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91cap9_mmc1_device = {
-	.name		= "at91_mci",
-	.id		= 1,
-	.dev		= {
-				.dma_mask		= &mmc_dmamask,
-				.coherent_dma_mask	= DMA_BIT_MASK(32),
-				.platform_data		= &mmc1_data,
-	},
-	.resource	= mmc1_resources,
-	.num_resources	= ARRAY_SIZE(mmc1_resources),
-};
-
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
-{
-	if (!data)
-		return;
-
-	/* input/irq */
-	if (gpio_is_valid(data->det_pin)) {
-		at91_set_gpio_input(data->det_pin, 1);
-		at91_set_deglitch(data->det_pin, 1);
-	}
-	if (gpio_is_valid(data->wp_pin))
-		at91_set_gpio_input(data->wp_pin, 1);
-	if (gpio_is_valid(data->vcc_pin))
-		at91_set_gpio_output(data->vcc_pin, 0);
-
-	if (mmc_id == 0) {		/* MCI0 */
-		/* CLK */
-		at91_set_A_periph(AT91_PIN_PA2, 0);
-
-		/* CMD */
-		at91_set_A_periph(AT91_PIN_PA1, 1);
-
-		/* DAT0, maybe DAT1..DAT3 */
-		at91_set_A_periph(AT91_PIN_PA0, 1);
-		if (data->wire4) {
-			at91_set_A_periph(AT91_PIN_PA3, 1);
-			at91_set_A_periph(AT91_PIN_PA4, 1);
-			at91_set_A_periph(AT91_PIN_PA5, 1);
-		}
-
-		mmc0_data = *data;
-		platform_device_register(&at91cap9_mmc0_device);
-	} else {			/* MCI1 */
-		/* CLK */
-		at91_set_A_periph(AT91_PIN_PA16, 0);
-
-		/* CMD */
-		at91_set_A_periph(AT91_PIN_PA17, 1);
-
-		/* DAT0, maybe DAT1..DAT3 */
-		at91_set_A_periph(AT91_PIN_PA18, 1);
-		if (data->wire4) {
-			at91_set_A_periph(AT91_PIN_PA19, 1);
-			at91_set_A_periph(AT91_PIN_PA20, 1);
-			at91_set_A_periph(AT91_PIN_PA21, 1);
-		}
-
-		mmc1_data = *data;
-		platform_device_register(&at91cap9_mmc1_device);
-	}
-}
-#else
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  NAND / SmartMedia
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE)
-static struct atmel_nand_data nand_data;
-
-#define NAND_BASE	AT91_CHIPSELECT_3
-
-static struct resource nand_resources[] = {
-	[0] = {
-		.start	= NAND_BASE,
-		.end	= NAND_BASE + SZ_256M - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_BASE_ECC,
-		.end	= AT91CAP9_BASE_ECC + SZ_512 - 1,
-		.flags	= IORESOURCE_MEM,
-	}
-};
-
-static struct platform_device at91cap9_nand_device = {
-	.name		= "atmel_nand",
-	.id		= -1,
-	.dev		= {
-				.platform_data	= &nand_data,
-	},
-	.resource	= nand_resources,
-	.num_resources	= ARRAY_SIZE(nand_resources),
-};
-
-void __init at91_add_device_nand(struct atmel_nand_data *data)
-{
-	unsigned long csa;
-
-	if (!data)
-		return;
-
-	csa = at91_sys_read(AT91_MATRIX_EBICSA);
-	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
-
-	/* enable pin */
-	if (gpio_is_valid(data->enable_pin))
-		at91_set_gpio_output(data->enable_pin, 1);
-
-	/* ready/busy pin */
-	if (gpio_is_valid(data->rdy_pin))
-		at91_set_gpio_input(data->rdy_pin, 1);
-
-	/* card detect pin */
-	if (gpio_is_valid(data->det_pin))
-		at91_set_gpio_input(data->det_pin, 1);
-
-	nand_data = *data;
-	platform_device_register(&at91cap9_nand_device);
-}
-#else
-void __init at91_add_device_nand(struct atmel_nand_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  TWI (i2c)
- * -------------------------------------------------------------------- */
-
-/*
- * Prefer the GPIO code since the TWI controller isn't robust
- * (gets overruns and underruns under load) and can only issue
- * repeated STARTs in one scenario (the driver doesn't yet handle them).
- */
-#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-
-static struct i2c_gpio_platform_data pdata = {
-	.sda_pin		= AT91_PIN_PB4,
-	.sda_is_open_drain	= 1,
-	.scl_pin		= AT91_PIN_PB5,
-	.scl_is_open_drain	= 1,
-	.udelay			= 2,		/* ~100 kHz */
-};
-
-static struct platform_device at91cap9_twi_device = {
-	.name			= "i2c-gpio",
-	.id			= -1,
-	.dev.platform_data	= &pdata,
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
-	at91_set_GPIO_periph(AT91_PIN_PB4, 1);		/* TWD (SDA) */
-	at91_set_multi_drive(AT91_PIN_PB4, 1);
-
-	at91_set_GPIO_periph(AT91_PIN_PB5, 1);		/* TWCK (SCL) */
-	at91_set_multi_drive(AT91_PIN_PB5, 1);
-
-	i2c_register_board_info(0, devices, nr_devices);
-	platform_device_register(&at91cap9_twi_device);
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-
-static struct resource twi_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_TWI,
-		.end	= AT91CAP9_BASE_TWI + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_TWI,
-		.end	= AT91CAP9_ID_TWI,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91cap9_twi_device = {
-	.name		= "at91_i2c",
-	.id		= -1,
-	.resource	= twi_resources,
-	.num_resources	= ARRAY_SIZE(twi_resources),
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
-	/* pins used for TWI interface */
-	at91_set_B_periph(AT91_PIN_PB4, 0);		/* TWD */
-	at91_set_multi_drive(AT91_PIN_PB4, 1);
-
-	at91_set_B_periph(AT91_PIN_PB5, 0);		/* TWCK */
-	at91_set_multi_drive(AT91_PIN_PB5, 1);
-
-	i2c_register_board_info(0, devices, nr_devices);
-	platform_device_register(&at91cap9_twi_device);
-}
-#else
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-/* --------------------------------------------------------------------
- *  SPI
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-static u64 spi_dmamask = DMA_BIT_MASK(32);
-
-static struct resource spi0_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_SPI0,
-		.end	= AT91CAP9_BASE_SPI0 + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_SPI0,
-		.end	= AT91CAP9_ID_SPI0,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91cap9_spi0_device = {
-	.name		= "atmel_spi",
-	.id		= 0,
-	.dev		= {
-				.dma_mask		= &spi_dmamask,
-				.coherent_dma_mask	= DMA_BIT_MASK(32),
-	},
-	.resource	= spi0_resources,
-	.num_resources	= ARRAY_SIZE(spi0_resources),
-};
-
-static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA5, AT91_PIN_PA3, AT91_PIN_PD0, AT91_PIN_PD1 };
-
-static struct resource spi1_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_SPI1,
-		.end	= AT91CAP9_BASE_SPI1 + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_SPI1,
-		.end	= AT91CAP9_ID_SPI1,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91cap9_spi1_device = {
-	.name		= "atmel_spi",
-	.id		= 1,
-	.dev		= {
-				.dma_mask		= &spi_dmamask,
-				.coherent_dma_mask	= DMA_BIT_MASK(32),
-	},
-	.resource	= spi1_resources,
-	.num_resources	= ARRAY_SIZE(spi1_resources),
-};
-
-static const unsigned spi1_standard_cs[4] = { AT91_PIN_PB15, AT91_PIN_PB16, AT91_PIN_PB17, AT91_PIN_PB18 };
-
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
-{
-	int i;
-	unsigned long cs_pin;
-	short enable_spi0 = 0;
-	short enable_spi1 = 0;
-
-	/* Choose SPI chip-selects */
-	for (i = 0; i < nr_devices; i++) {
-		if (devices[i].controller_data)
-			cs_pin = (unsigned long) devices[i].controller_data;
-		else if (devices[i].bus_num == 0)
-			cs_pin = spi0_standard_cs[devices[i].chip_select];
-		else
-			cs_pin = spi1_standard_cs[devices[i].chip_select];
-
-		if (devices[i].bus_num == 0)
-			enable_spi0 = 1;
-		else
-			enable_spi1 = 1;
-
-		/* enable chip-select pin */
-		at91_set_gpio_output(cs_pin, 1);
-
-		/* pass chip-select pin to driver */
-		devices[i].controller_data = (void *) cs_pin;
-	}
-
-	spi_register_board_info(devices, nr_devices);
-
-	/* Configure SPI bus(es) */
-	if (enable_spi0) {
-		at91_set_B_periph(AT91_PIN_PA0, 0);	/* SPI0_MISO */
-		at91_set_B_periph(AT91_PIN_PA1, 0);	/* SPI0_MOSI */
-		at91_set_B_periph(AT91_PIN_PA2, 0);	/* SPI0_SPCK */
-
-		platform_device_register(&at91cap9_spi0_device);
-	}
-	if (enable_spi1) {
-		at91_set_A_periph(AT91_PIN_PB12, 0);	/* SPI1_MISO */
-		at91_set_A_periph(AT91_PIN_PB13, 0);	/* SPI1_MOSI */
-		at91_set_A_periph(AT91_PIN_PB14, 0);	/* SPI1_SPCK */
-
-		platform_device_register(&at91cap9_spi1_device);
-	}
-}
-#else
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  Timer/Counter block
- * -------------------------------------------------------------------- */
-
-#ifdef CONFIG_ATMEL_TCLIB
-
-static struct resource tcb_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_TCB0,
-		.end	= AT91CAP9_BASE_TCB0 + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_TCB,
-		.end	= AT91CAP9_ID_TCB,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91cap9_tcb_device = {
-	.name		= "atmel_tcb",
-	.id		= 0,
-	.resource	= tcb_resources,
-	.num_resources	= ARRAY_SIZE(tcb_resources),
-};
-
-static void __init at91_add_device_tc(void)
-{
-	platform_device_register(&at91cap9_tcb_device);
-}
-#else
-static void __init at91_add_device_tc(void) { }
-#endif
-
-
-/* --------------------------------------------------------------------
- *  RTT
- * -------------------------------------------------------------------- */
-
-static struct resource rtt_resources[] = {
-	{
-		.start	= AT91CAP9_BASE_RTT,
-		.end	= AT91CAP9_BASE_RTT + SZ_16 - 1,
-		.flags	= IORESOURCE_MEM,
-	}
-};
-
-static struct platform_device at91cap9_rtt_device = {
-	.name		= "at91_rtt",
-	.id		= 0,
-	.resource	= rtt_resources,
-	.num_resources	= ARRAY_SIZE(rtt_resources),
-};
-
-static void __init at91_add_device_rtt(void)
-{
-	platform_device_register(&at91cap9_rtt_device);
-}
-
-
-/* --------------------------------------------------------------------
- *  Watchdog
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
-static struct resource wdt_resources[] = {
-	{
-		.start	= AT91CAP9_BASE_WDT,
-		.end	= AT91CAP9_BASE_WDT + SZ_16 - 1,
-		.flags	= IORESOURCE_MEM,
-	}
-};
-
-static struct platform_device at91cap9_wdt_device = {
-	.name		= "at91_wdt",
-	.id		= -1,
-	.resource	= wdt_resources,
-	.num_resources	= ARRAY_SIZE(wdt_resources),
-};
-
-static void __init at91_add_device_watchdog(void)
-{
-	platform_device_register(&at91cap9_wdt_device);
-}
-#else
-static void __init at91_add_device_watchdog(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  PWM
- * --------------------------------------------------------------------*/
-
-#if defined(CONFIG_ATMEL_PWM)
-static u32 pwm_mask;
-
-static struct resource pwm_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_PWMC,
-		.end	= AT91CAP9_BASE_PWMC + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_PWMC,
-		.end	= AT91CAP9_ID_PWMC,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91cap9_pwm0_device = {
-	.name	= "atmel_pwm",
-	.id	= -1,
-	.dev	= {
-		.platform_data		= &pwm_mask,
-	},
-	.resource	= pwm_resources,
-	.num_resources	= ARRAY_SIZE(pwm_resources),
-};
-
-void __init at91_add_device_pwm(u32 mask)
-{
-	if (mask & (1 << AT91_PWM0))
-		at91_set_A_periph(AT91_PIN_PB19, 1);	/* enable PWM0 */
-
-	if (mask & (1 << AT91_PWM1))
-		at91_set_B_periph(AT91_PIN_PB8, 1);	/* enable PWM1 */
-
-	if (mask & (1 << AT91_PWM2))
-		at91_set_B_periph(AT91_PIN_PC29, 1);	/* enable PWM2 */
-
-	if (mask & (1 << AT91_PWM3))
-		at91_set_B_periph(AT91_PIN_PA11, 1);	/* enable PWM3 */
-
-	pwm_mask = mask;
-
-	platform_device_register(&at91cap9_pwm0_device);
-}
-#else
-void __init at91_add_device_pwm(u32 mask) {}
-#endif
-
-
-
-/* --------------------------------------------------------------------
- *  AC97
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SND_ATMEL_AC97C) || defined(CONFIG_SND_ATMEL_AC97C_MODULE)
-static u64 ac97_dmamask = DMA_BIT_MASK(32);
-static struct ac97c_platform_data ac97_data;
-
-static struct resource ac97_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_AC97C,
-		.end	= AT91CAP9_BASE_AC97C + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_AC97C,
-		.end	= AT91CAP9_ID_AC97C,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91cap9_ac97_device = {
-	.name		= "atmel_ac97c",
-	.id		= 1,
-	.dev		= {
-				.dma_mask		= &ac97_dmamask,
-				.coherent_dma_mask	= DMA_BIT_MASK(32),
-				.platform_data		= &ac97_data,
-	},
-	.resource	= ac97_resources,
-	.num_resources	= ARRAY_SIZE(ac97_resources),
-};
-
-void __init at91_add_device_ac97(struct ac97c_platform_data *data)
-{
-	if (!data)
-		return;
-
-	at91_set_A_periph(AT91_PIN_PA6, 0);	/* AC97FS */
-	at91_set_A_periph(AT91_PIN_PA7, 0);	/* AC97CK */
-	at91_set_A_periph(AT91_PIN_PA8, 0);	/* AC97TX */
-	at91_set_A_periph(AT91_PIN_PA9, 0);	/* AC97RX */
-
-	/* reset */
-	if (gpio_is_valid(data->reset_pin))
-		at91_set_gpio_output(data->reset_pin, 0);
-
-	ac97_data = *data;
-	platform_device_register(&at91cap9_ac97_device);
-}
-#else
-void __init at91_add_device_ac97(struct ac97c_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  LCD Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-static u64 lcdc_dmamask = DMA_BIT_MASK(32);
-static struct atmel_lcdfb_info lcdc_data;
-
-static struct resource lcdc_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_LCDC_BASE,
-		.end	= AT91CAP9_LCDC_BASE + SZ_4K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_LCDC,
-		.end	= AT91CAP9_ID_LCDC,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91_lcdc_device = {
-	.name		= "atmel_lcdfb",
-	.id		= 0,
-	.dev		= {
-				.dma_mask		= &lcdc_dmamask,
-				.coherent_dma_mask	= DMA_BIT_MASK(32),
-				.platform_data		= &lcdc_data,
-	},
-	.resource	= lcdc_resources,
-	.num_resources	= ARRAY_SIZE(lcdc_resources),
-};
-
-void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
-{
-	if (!data)
-		return;
-
-	if (cpu_is_at91cap9_revB())
-		irq_set_irq_type(AT91CAP9_ID_LCDC, IRQ_TYPE_LEVEL_HIGH);
-
-	at91_set_A_periph(AT91_PIN_PC1, 0);	/* LCDHSYNC */
-	at91_set_A_periph(AT91_PIN_PC2, 0);	/* LCDDOTCK */
-	at91_set_A_periph(AT91_PIN_PC3, 0);	/* LCDDEN */
-	at91_set_B_periph(AT91_PIN_PB9, 0);	/* LCDCC */
-	at91_set_A_periph(AT91_PIN_PC6, 0);	/* LCDD2 */
-	at91_set_A_periph(AT91_PIN_PC7, 0);	/* LCDD3 */
-	at91_set_A_periph(AT91_PIN_PC8, 0);	/* LCDD4 */
-	at91_set_A_periph(AT91_PIN_PC9, 0);	/* LCDD5 */
-	at91_set_A_periph(AT91_PIN_PC10, 0);	/* LCDD6 */
-	at91_set_A_periph(AT91_PIN_PC11, 0);	/* LCDD7 */
-	at91_set_A_periph(AT91_PIN_PC14, 0);	/* LCDD10 */
-	at91_set_A_periph(AT91_PIN_PC15, 0);	/* LCDD11 */
-	at91_set_A_periph(AT91_PIN_PC16, 0);	/* LCDD12 */
-	at91_set_A_periph(AT91_PIN_PC17, 0);	/* LCDD13 */
-	at91_set_A_periph(AT91_PIN_PC18, 0);	/* LCDD14 */
-	at91_set_A_periph(AT91_PIN_PC19, 0);	/* LCDD15 */
-	at91_set_A_periph(AT91_PIN_PC22, 0);	/* LCDD18 */
-	at91_set_A_periph(AT91_PIN_PC23, 0);	/* LCDD19 */
-	at91_set_A_periph(AT91_PIN_PC24, 0);	/* LCDD20 */
-	at91_set_A_periph(AT91_PIN_PC25, 0);	/* LCDD21 */
-	at91_set_A_periph(AT91_PIN_PC26, 0);	/* LCDD22 */
-	at91_set_A_periph(AT91_PIN_PC27, 0);	/* LCDD23 */
-
-	lcdc_data = *data;
-	platform_device_register(&at91_lcdc_device);
-}
-#else
-void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  SSC -- Synchronous Serial Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
-static u64 ssc0_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc0_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_SSC0,
-		.end	= AT91CAP9_BASE_SSC0 + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_SSC0,
-		.end	= AT91CAP9_ID_SSC0,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91cap9_ssc0_device = {
-	.name	= "ssc",
-	.id	= 0,
-	.dev	= {
-		.dma_mask		= &ssc0_dmamask,
-		.coherent_dma_mask	= DMA_BIT_MASK(32),
-	},
-	.resource	= ssc0_resources,
-	.num_resources	= ARRAY_SIZE(ssc0_resources),
-};
-
-static inline void configure_ssc0_pins(unsigned pins)
-{
-	if (pins & ATMEL_SSC_TF)
-		at91_set_A_periph(AT91_PIN_PB0, 1);
-	if (pins & ATMEL_SSC_TK)
-		at91_set_A_periph(AT91_PIN_PB1, 1);
-	if (pins & ATMEL_SSC_TD)
-		at91_set_A_periph(AT91_PIN_PB2, 1);
-	if (pins & ATMEL_SSC_RD)
-		at91_set_A_periph(AT91_PIN_PB3, 1);
-	if (pins & ATMEL_SSC_RK)
-		at91_set_A_periph(AT91_PIN_PB4, 1);
-	if (pins & ATMEL_SSC_RF)
-		at91_set_A_periph(AT91_PIN_PB5, 1);
-}
-
-static u64 ssc1_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc1_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_SSC1,
-		.end	= AT91CAP9_BASE_SSC1 + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_SSC1,
-		.end	= AT91CAP9_ID_SSC1,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device at91cap9_ssc1_device = {
-	.name	= "ssc",
-	.id	= 1,
-	.dev	= {
-		.dma_mask		= &ssc1_dmamask,
-		.coherent_dma_mask	= DMA_BIT_MASK(32),
-	},
-	.resource	= ssc1_resources,
-	.num_resources	= ARRAY_SIZE(ssc1_resources),
-};
-
-static inline void configure_ssc1_pins(unsigned pins)
-{
-	if (pins & ATMEL_SSC_TF)
-		at91_set_A_periph(AT91_PIN_PB6, 1);
-	if (pins & ATMEL_SSC_TK)
-		at91_set_A_periph(AT91_PIN_PB7, 1);
-	if (pins & ATMEL_SSC_TD)
-		at91_set_A_periph(AT91_PIN_PB8, 1);
-	if (pins & ATMEL_SSC_RD)
-		at91_set_A_periph(AT91_PIN_PB9, 1);
-	if (pins & ATMEL_SSC_RK)
-		at91_set_A_periph(AT91_PIN_PB10, 1);
-	if (pins & ATMEL_SSC_RF)
-		at91_set_A_periph(AT91_PIN_PB11, 1);
-}
-
-/*
- * SSC controllers are accessed through library code, instead of any
- * kind of all-singing/all-dancing driver.  For example one could be
- * used by a particular I2S audio codec's driver, while another one
- * on the same system might be used by a custom data capture driver.
- */
-void __init at91_add_device_ssc(unsigned id, unsigned pins)
-{
-	struct platform_device *pdev;
-
-	/*
-	 * NOTE: caller is responsible for passing information matching
-	 * "pins" to whatever will be using each particular controller.
-	 */
-	switch (id) {
-	case AT91CAP9_ID_SSC0:
-		pdev = &at91cap9_ssc0_device;
-		configure_ssc0_pins(pins);
-		break;
-	case AT91CAP9_ID_SSC1:
-		pdev = &at91cap9_ssc1_device;
-		configure_ssc1_pins(pins);
-		break;
-	default:
-		return;
-	}
-
-	platform_device_register(pdev);
-}
-
-#else
-void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  UART
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SERIAL_ATMEL)
-static struct resource dbgu_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_DBGU,
-		.end	= AT91CAP9_BASE_DBGU + SZ_512 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91_ID_SYS,
-		.end	= AT91_ID_SYS,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct atmel_uart_data dbgu_data = {
-	.use_dma_tx	= 0,
-	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
-};
-
-static u64 dbgu_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91cap9_dbgu_device = {
-	.name		= "atmel_usart",
-	.id		= 0,
-	.dev		= {
-				.dma_mask		= &dbgu_dmamask,
-				.coherent_dma_mask	= DMA_BIT_MASK(32),
-				.platform_data		= &dbgu_data,
-	},
-	.resource	= dbgu_resources,
-	.num_resources	= ARRAY_SIZE(dbgu_resources),
-};
-
-static inline void configure_dbgu_pins(void)
-{
-	at91_set_A_periph(AT91_PIN_PC30, 0);		/* DRXD */
-	at91_set_A_periph(AT91_PIN_PC31, 1);		/* DTXD */
-}
-
-static struct resource uart0_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_US0,
-		.end	= AT91CAP9_BASE_US0 + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_US0,
-		.end	= AT91CAP9_ID_US0,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct atmel_uart_data uart0_data = {
-	.use_dma_tx	= 1,
-	.use_dma_rx	= 1,
-};
-
-static u64 uart0_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91cap9_uart0_device = {
-	.name		= "atmel_usart",
-	.id		= 1,
-	.dev		= {
-				.dma_mask		= &uart0_dmamask,
-				.coherent_dma_mask	= DMA_BIT_MASK(32),
-				.platform_data		= &uart0_data,
-	},
-	.resource	= uart0_resources,
-	.num_resources	= ARRAY_SIZE(uart0_resources),
-};
-
-static inline void configure_usart0_pins(unsigned pins)
-{
-	at91_set_A_periph(AT91_PIN_PA22, 1);		/* TXD0 */
-	at91_set_A_periph(AT91_PIN_PA23, 0);		/* RXD0 */
-
-	if (pins & ATMEL_UART_RTS)
-		at91_set_A_periph(AT91_PIN_PA24, 0);	/* RTS0 */
-	if (pins & ATMEL_UART_CTS)
-		at91_set_A_periph(AT91_PIN_PA25, 0);	/* CTS0 */
-}
-
-static struct resource uart1_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_US1,
-		.end	= AT91CAP9_BASE_US1 + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_US1,
-		.end	= AT91CAP9_ID_US1,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct atmel_uart_data uart1_data = {
-	.use_dma_tx	= 1,
-	.use_dma_rx	= 1,
-};
-
-static u64 uart1_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91cap9_uart1_device = {
-	.name		= "atmel_usart",
-	.id		= 2,
-	.dev		= {
-				.dma_mask		= &uart1_dmamask,
-				.coherent_dma_mask	= DMA_BIT_MASK(32),
-				.platform_data		= &uart1_data,
-	},
-	.resource	= uart1_resources,
-	.num_resources	= ARRAY_SIZE(uart1_resources),
-};
-
-static inline void configure_usart1_pins(unsigned pins)
-{
-	at91_set_A_periph(AT91_PIN_PD0, 1);		/* TXD1 */
-	at91_set_A_periph(AT91_PIN_PD1, 0);		/* RXD1 */
-
-	if (pins & ATMEL_UART_RTS)
-		at91_set_B_periph(AT91_PIN_PD7, 0);	/* RTS1 */
-	if (pins & ATMEL_UART_CTS)
-		at91_set_B_periph(AT91_PIN_PD8, 0);	/* CTS1 */
-}
-
-static struct resource uart2_resources[] = {
-	[0] = {
-		.start	= AT91CAP9_BASE_US2,
-		.end	= AT91CAP9_BASE_US2 + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= AT91CAP9_ID_US2,
-		.end	= AT91CAP9_ID_US2,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct atmel_uart_data uart2_data = {
-	.use_dma_tx	= 1,
-	.use_dma_rx	= 1,
-};
-
-static u64 uart2_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91cap9_uart2_device = {
-	.name		= "atmel_usart",
-	.id		= 3,
-	.dev		= {
-				.dma_mask		= &uart2_dmamask,
-				.coherent_dma_mask	= DMA_BIT_MASK(32),
-				.platform_data		= &uart2_data,
-	},
-	.resource	= uart2_resources,
-	.num_resources	= ARRAY_SIZE(uart2_resources),
-};
-
-static inline void configure_usart2_pins(unsigned pins)
-{
-	at91_set_A_periph(AT91_PIN_PD2, 1);		/* TXD2 */
-	at91_set_A_periph(AT91_PIN_PD3, 0);		/* RXD2 */
-
-	if (pins & ATMEL_UART_RTS)
-		at91_set_B_periph(AT91_PIN_PD5, 0);	/* RTS2 */
-	if (pins & ATMEL_UART_CTS)
-		at91_set_B_periph(AT91_PIN_PD6, 0);	/* CTS2 */
-}
-
-static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
-struct platform_device *atmel_default_console_device;	/* the serial console device */
-
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
-{
-	struct platform_device *pdev;
-	struct atmel_uart_data *pdata;
-
-	switch (id) {
-		case 0:		/* DBGU */
-			pdev = &at91cap9_dbgu_device;
-			configure_dbgu_pins();
-			break;
-		case AT91CAP9_ID_US0:
-			pdev = &at91cap9_uart0_device;
-			configure_usart0_pins(pins);
-			break;
-		case AT91CAP9_ID_US1:
-			pdev = &at91cap9_uart1_device;
-			configure_usart1_pins(pins);
-			break;
-		case AT91CAP9_ID_US2:
-			pdev = &at91cap9_uart2_device;
-			configure_usart2_pins(pins);
-			break;
-		default:
-			return;
-	}
-	pdata = pdev->dev.platform_data;
-	pdata->num = portnr;		/* update to mapped ID */
-
-	if (portnr < ATMEL_MAX_UART)
-		at91_uarts[portnr] = pdev;
-}
-
-void __init at91_set_serial_console(unsigned portnr)
-{
-	if (portnr < ATMEL_MAX_UART) {
-		atmel_default_console_device = at91_uarts[portnr];
-		at91cap9_set_console_clock(at91_uarts[portnr]->id);
-	}
-}
-
-void __init at91_add_device_serial(void)
-{
-	int i;
-
-	for (i = 0; i < ATMEL_MAX_UART; i++) {
-		if (at91_uarts[i])
-			platform_device_register(at91_uarts[i]);
-	}
-
-	if (!atmel_default_console_device)
-		printk(KERN_INFO "AT91: No default serial console defined.\n");
-}
-#else
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
-void __init at91_add_device_serial(void) {}
-#endif
-
-
-/* -------------------------------------------------------------------- */
-/*
- * These devices are always present and don't need any board-specific
- * setup.
- */
-static int __init at91_add_standard_devices(void)
-{
-	at91_add_device_rtt();
-	at91_add_device_watchdog();
-	at91_add_device_tc();
-	return 0;
-}
-
-arch_initcall(at91_add_standard_devices);
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index 99c3174..364c193 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -15,6 +15,7 @@
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/system_misc.h>
 #include <mach/at91rm9200.h>
 #include <mach/at91_pmc.h>
 #include <mach/at91_st.h>
@@ -289,13 +290,22 @@
 	}
 };
 
+static void at91rm9200_idle(void)
+{
+	/*
+	 * Disable the processor clock.  The processor will be automatically
+	 * re-enabled by an interrupt or by a reset.
+	 */
+	at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
+}
+
 static void at91rm9200_restart(char mode, const char *cmd)
 {
 	/*
 	 * Perform a hardware reset with the use of the Watchdog timer.
 	 */
-	at91_sys_write(AT91_ST_WDMR, AT91_ST_RSTEN | AT91_ST_EXTEN | 1);
-	at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
+	at91_st_write(AT91_ST_WDMR, AT91_ST_RSTEN | AT91_ST_EXTEN | 1);
+	at91_st_write(AT91_ST_CR, AT91_ST_WDRST);
 }
 
 /* --------------------------------------------------------------------
@@ -310,10 +320,13 @@
 
 static void __init at91rm9200_ioremap_registers(void)
 {
+	at91rm9200_ioremap_st(AT91RM9200_BASE_ST);
+	at91_ioremap_ramc(0, AT91RM9200_BASE_MC, 256);
 }
 
 static void __init at91rm9200_initialize(void)
 {
+	arm_pm_idle = at91rm9200_idle;
 	arm_pm_restart = at91rm9200_restart;
 	at91_extern_irq = (1 << AT91RM9200_ID_IRQ0) | (1 << AT91RM9200_ID_IRQ1)
 			| (1 << AT91RM9200_ID_IRQ2) | (1 << AT91RM9200_ID_IRQ3)
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index 97676bd..99ce5c9 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -21,6 +21,7 @@
 #include <mach/board.h>
 #include <mach/at91rm9200.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 
 #include "generic.h"
 
@@ -241,15 +242,15 @@
 	data->chipselect = 4;		/* can only use EBI ChipSelect 4 */
 
 	/* CF takes over CS4, CS5, CS6 */
-	csa = at91_sys_read(AT91_EBI_CSA);
-	at91_sys_write(AT91_EBI_CSA, csa | AT91_EBI_CS4A_SMC_COMPACTFLASH);
+	csa = at91_ramc_read(0, AT91_EBI_CSA);
+	at91_ramc_write(0, AT91_EBI_CSA, csa | AT91_EBI_CS4A_SMC_COMPACTFLASH);
 
 	/*
 	 * Static memory controller timing adjustments.
 	 * REVISIT:  these timings are in terms of MCK cycles, so
 	 * when MCK changes (cpufreq etc) so must these values...
 	 */
-	at91_sys_write(AT91_SMC_CSR(4),
+	at91_ramc_write(0, AT91_SMC_CSR(4),
 				  AT91_SMC_ACSS_STD
 				| AT91_SMC_DBW_16
 				| AT91_SMC_BAT
@@ -407,11 +408,11 @@
 		return;
 
 	/* enable the address range of CS3 */
-	csa = at91_sys_read(AT91_EBI_CSA);
-	at91_sys_write(AT91_EBI_CSA, csa | AT91_EBI_CS3A_SMC_SMARTMEDIA);
+	csa = at91_ramc_read(0, AT91_EBI_CSA);
+	at91_ramc_write(0, AT91_EBI_CSA, csa | AT91_EBI_CS3A_SMC_SMARTMEDIA);
 
 	/* set the bus interface characteristics */
-	at91_sys_write(AT91_SMC_CSR(3), AT91_SMC_ACSS_STD | AT91_SMC_DBW_8 | AT91_SMC_WSEN
+	at91_ramc_write(0, AT91_SMC_CSR(3), AT91_SMC_ACSS_STD | AT91_SMC_DBW_8 | AT91_SMC_WSEN
 		| AT91_SMC_NWS_(5)
 		| AT91_SMC_TDF_(1)
 		| AT91_SMC_RWSETUP_(0)	/* tDS Data Set up Time 30 - ns */
@@ -1114,7 +1115,6 @@
 }
 
 static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
-struct platform_device *atmel_default_console_device;	/* the serial console device */
 
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
diff --git a/arch/arm/mach-at91/at91rm9200_time.c b/arch/arm/mach-at91/at91rm9200_time.c
index a028cdf..dd7f782 100644
--- a/arch/arm/mach-at91/at91rm9200_time.c
+++ b/arch/arm/mach-at91/at91rm9200_time.c
@@ -43,9 +43,9 @@
 {
 	unsigned long x1, x2;
 
-	x1 = at91_sys_read(AT91_ST_CRTR);
+	x1 = at91_st_read(AT91_ST_CRTR);
 	do {
-		x2 = at91_sys_read(AT91_ST_CRTR);
+		x2 = at91_st_read(AT91_ST_CRTR);
 		if (x1 == x2)
 			break;
 		x1 = x2;
@@ -58,7 +58,7 @@
  */
 static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
 {
-	u32	sr = at91_sys_read(AT91_ST_SR) & irqmask;
+	u32	sr = at91_st_read(AT91_ST_SR) & irqmask;
 
 	/*
 	 * irqs should be disabled here, but as the irq is shared they are only
@@ -110,22 +110,22 @@
 clkevt32k_mode(enum clock_event_mode mode, struct clock_event_device *dev)
 {
 	/* Disable and flush pending timer interrupts */
-	at91_sys_write(AT91_ST_IDR, AT91_ST_PITS | AT91_ST_ALMS);
-	(void) at91_sys_read(AT91_ST_SR);
+	at91_st_write(AT91_ST_IDR, AT91_ST_PITS | AT91_ST_ALMS);
+	at91_st_read(AT91_ST_SR);
 
 	last_crtr = read_CRTR();
 	switch (mode) {
 	case CLOCK_EVT_MODE_PERIODIC:
 		/* PIT for periodic irqs; fixed rate of 1/HZ */
 		irqmask = AT91_ST_PITS;
-		at91_sys_write(AT91_ST_PIMR, RM9200_TIMER_LATCH);
+		at91_st_write(AT91_ST_PIMR, RM9200_TIMER_LATCH);
 		break;
 	case CLOCK_EVT_MODE_ONESHOT:
 		/* ALM for oneshot irqs, set by next_event()
 		 * before 32 seconds have passed
 		 */
 		irqmask = AT91_ST_ALMS;
-		at91_sys_write(AT91_ST_RTAR, last_crtr);
+		at91_st_write(AT91_ST_RTAR, last_crtr);
 		break;
 	case CLOCK_EVT_MODE_SHUTDOWN:
 	case CLOCK_EVT_MODE_UNUSED:
@@ -133,7 +133,7 @@
 		irqmask = 0;
 		break;
 	}
-	at91_sys_write(AT91_ST_IER, irqmask);
+	at91_st_write(AT91_ST_IER, irqmask);
 }
 
 static int
@@ -156,12 +156,12 @@
 	alm = read_CRTR();
 
 	/* Cancel any pending alarm; flush any pending IRQ */
-	at91_sys_write(AT91_ST_RTAR, alm);
-	(void) at91_sys_read(AT91_ST_SR);
+	at91_st_write(AT91_ST_RTAR, alm);
+	at91_st_read(AT91_ST_SR);
 
 	/* Schedule alarm by writing RTAR. */
 	alm += delta;
-	at91_sys_write(AT91_ST_RTAR, alm);
+	at91_st_write(AT91_ST_RTAR, alm);
 
 	return status;
 }
@@ -175,15 +175,24 @@
 	.set_mode	= clkevt32k_mode,
 };
 
+void __iomem *at91_st_base;
+
+void __init at91rm9200_ioremap_st(u32 addr)
+{
+	at91_st_base = ioremap(addr, 256);
+	if (!at91_st_base)
+		panic("Impossible to ioremap ST\n");
+}
+
 /*
  * ST (system timer) module supports both clockevents and clocksource.
  */
 void __init at91rm9200_timer_init(void)
 {
 	/* Disable all timer interrupts, and clear any pending ones */
-	at91_sys_write(AT91_ST_IDR,
+	at91_st_write(AT91_ST_IDR,
 		AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS);
-	(void) at91_sys_read(AT91_ST_SR);
+	at91_st_read(AT91_ST_SR);
 
 	/* Make IRQs happen for the system timer */
 	setup_irq(AT91_ID_SYS, &at91rm9200_timer_irq);
@@ -192,7 +201,7 @@
 	 * directly for the clocksource and all clockevents, after adjusting
 	 * its prescaler from the 1 Hz default.
 	 */
-	at91_sys_write(AT91_ST_RTMR, 1);
+	at91_st_write(AT91_ST_RTMR, 1);
 
 	/* Setup timer clockevent, with minimum of two ticks (important!!) */
 	clkevt.mult = div_sc(AT91_SLOW_CLOCK, NSEC_PER_SEC, clkevt.shift);
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index d4036ba..46f7742 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -12,9 +12,11 @@
 
 #include <linux/module.h>
 
+#include <asm/proc-fns.h>
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/system_misc.h>
 #include <mach/cpu.h>
 #include <mach/at91_dbgu.h>
 #include <mach/at91sam9260.h>
@@ -208,6 +210,14 @@
 	CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk),
 	CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk),
 	CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk),
+	/* more tc lookup table for DT entries */
+	CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
+	CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
+	CLKDEV_CON_DEV_ID("t2_clk", "fffa0000.timer", &tc2_clk),
+	CLKDEV_CON_DEV_ID("t0_clk", "fffdc000.timer", &tc3_clk),
+	CLKDEV_CON_DEV_ID("t1_clk", "fffdc000.timer", &tc4_clk),
+	CLKDEV_CON_DEV_ID("t2_clk", "fffdc000.timer", &tc5_clk),
+	CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &ohci_clk),
 	/* fake hclk clock */
 	CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
 	CLKDEV_CON_ID("pioA", &pioA_clk),
@@ -309,27 +319,27 @@
 
 static void __init at91sam9260_map_io(void)
 {
-	if (cpu_is_at91sam9xe()) {
+	if (cpu_is_at91sam9xe())
 		at91sam9xe_map_io();
-	} else if (cpu_is_at91sam9g20()) {
-		at91_init_sram(0, AT91SAM9G20_SRAM0_BASE, AT91SAM9G20_SRAM0_SIZE);
-		at91_init_sram(1, AT91SAM9G20_SRAM1_BASE, AT91SAM9G20_SRAM1_SIZE);
-	} else {
-		at91_init_sram(0, AT91SAM9260_SRAM0_BASE, AT91SAM9260_SRAM0_SIZE);
-		at91_init_sram(1, AT91SAM9260_SRAM1_BASE, AT91SAM9260_SRAM1_SIZE);
-	}
+	else if (cpu_is_at91sam9g20())
+		at91_init_sram(0, AT91SAM9G20_SRAM_BASE, AT91SAM9G20_SRAM_SIZE);
+	else
+		at91_init_sram(0, AT91SAM9260_SRAM_BASE, AT91SAM9260_SRAM_SIZE);
 }
 
 static void __init at91sam9260_ioremap_registers(void)
 {
 	at91_ioremap_shdwc(AT91SAM9260_BASE_SHDWC);
 	at91_ioremap_rstc(AT91SAM9260_BASE_RSTC);
+	at91_ioremap_ramc(0, AT91SAM9260_BASE_SDRAMC, 512);
 	at91sam926x_ioremap_pit(AT91SAM9260_BASE_PIT);
 	at91sam9_ioremap_smc(0, AT91SAM9260_BASE_SMC);
+	at91_ioremap_matrix(AT91SAM9260_BASE_MATRIX);
 }
 
 static void __init at91sam9260_initialize(void)
 {
+	arm_pm_idle = at91sam9_idle;
 	arm_pm_restart = at91sam9_alt_restart;
 	at91_extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1)
 			| (1 << AT91SAM9260_ID_IRQ2);
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 5a24f0b..5652dde 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -21,6 +21,7 @@
 #include <mach/cpu.h>
 #include <mach/at91sam9260.h>
 #include <mach/at91sam9260_matrix.h>
+#include <mach/at91_matrix.h>
 #include <mach/at91sam9_smc.h>
 
 #include "generic.h"
@@ -422,8 +423,8 @@
 	if (!data)
 		return;
 
-	csa = at91_sys_read(AT91_MATRIX_EBICSA);
-	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
+	csa = at91_matrix_read(AT91_MATRIX_EBICSA);
+	at91_matrix_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
 
 	/* enable pin */
 	if (gpio_is_valid(data->enable_pin))
@@ -597,6 +598,9 @@
 		else
 			cs_pin = spi1_standard_cs[devices[i].chip_select];
 
+		if (!gpio_is_valid(cs_pin))
+			continue;
+
 		if (devices[i].bus_num == 0)
 			enable_spi0 = 1;
 		else
@@ -641,7 +645,7 @@
 static struct resource tcb0_resources[] = {
 	[0] = {
 		.start	= AT91SAM9260_BASE_TCB0,
-		.end	= AT91SAM9260_BASE_TCB0 + SZ_16K - 1,
+		.end	= AT91SAM9260_BASE_TCB0 + SZ_256 - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -671,7 +675,7 @@
 static struct resource tcb1_resources[] = {
 	[0] = {
 		.start	= AT91SAM9260_BASE_TCB1,
-		.end	= AT91SAM9260_BASE_TCB1 + SZ_16K - 1,
+		.end	= AT91SAM9260_BASE_TCB1 + SZ_256 - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -698,8 +702,25 @@
 	.num_resources	= ARRAY_SIZE(tcb1_resources),
 };
 
+#if defined(CONFIG_OF)
+static struct of_device_id tcb_ids[] = {
+	{ .compatible = "atmel,at91rm9200-tcb" },
+	{ /*sentinel*/ }
+};
+#endif
+
 static void __init at91_add_device_tc(void)
 {
+#if defined(CONFIG_OF)
+	struct device_node *np;
+
+	np = of_find_matching_node(NULL, tcb_ids);
+	if (np) {
+		of_node_put(np);
+		return;
+	}
+#endif
+
 	platform_device_register(&at91sam9260_tcb0_device);
 	platform_device_register(&at91sam9260_tcb1_device);
 }
@@ -717,18 +738,42 @@
 		.start	= AT91SAM9260_BASE_RTT,
 		.end	= AT91SAM9260_BASE_RTT + SZ_16 - 1,
 		.flags	= IORESOURCE_MEM,
-	}
+	}, {
+		.flags	= IORESOURCE_MEM,
+	},
 };
 
 static struct platform_device at91sam9260_rtt_device = {
 	.name		= "at91_rtt",
 	.id		= 0,
 	.resource	= rtt_resources,
-	.num_resources	= ARRAY_SIZE(rtt_resources),
 };
 
+
+#if IS_ENABLED(CONFIG_RTC_DRV_AT91SAM9)
+static void __init at91_add_device_rtt_rtc(void)
+{
+	at91sam9260_rtt_device.name = "rtc-at91sam9";
+	/*
+	 * The second resource is needed:
+	 * GPBR will serve as the storage for RTC time offset
+	 */
+	at91sam9260_rtt_device.num_resources = 2;
+	rtt_resources[1].start = AT91SAM9260_BASE_GPBR +
+				 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR;
+	rtt_resources[1].end = rtt_resources[1].start + 3;
+}
+#else
+static void __init at91_add_device_rtt_rtc(void)
+{
+	/* Only one resource is needed: RTT not used as RTC */
+	at91sam9260_rtt_device.num_resources = 1;
+}
+#endif
+
 static void __init at91_add_device_rtt(void)
 {
+	at91_add_device_rtt_rtc();
 	platform_device_register(&at91sam9260_rtt_device);
 }
 
@@ -1139,7 +1184,6 @@
 }
 
 static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
-struct platform_device *atmel_default_console_device;	/* the serial console device */
 
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
@@ -1264,7 +1308,7 @@
 	if (!data)
 		return;
 
-	csa = at91_sys_read(AT91_MATRIX_EBICSA);
+	csa = at91_matrix_read(AT91_MATRIX_EBICSA);
 
 	switch (data->chipselect) {
 	case 4:
@@ -1287,7 +1331,7 @@
 		return;
 	}
 
-	at91_sys_write(AT91_MATRIX_EBICSA, csa);
+	at91_matrix_write(AT91_MATRIX_EBICSA, csa);
 
 	if (gpio_is_valid(data->rst_pin)) {
 		at91_set_multi_drive(data->rst_pin, 0);
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 023c2ff..7de81e6 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -12,9 +12,11 @@
 
 #include <linux/module.h>
 
+#include <asm/proc-fns.h>
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/system_misc.h>
 #include <mach/cpu.h>
 #include <mach/at91sam9261.h>
 #include <mach/at91_pmc.h>
@@ -282,12 +284,15 @@
 {
 	at91_ioremap_shdwc(AT91SAM9261_BASE_SHDWC);
 	at91_ioremap_rstc(AT91SAM9261_BASE_RSTC);
+	at91_ioremap_ramc(0, AT91SAM9261_BASE_SDRAMC, 512);
 	at91sam926x_ioremap_pit(AT91SAM9261_BASE_PIT);
 	at91sam9_ioremap_smc(0, AT91SAM9261_BASE_SMC);
+	at91_ioremap_matrix(AT91SAM9261_BASE_MATRIX);
 }
 
 static void __init at91sam9261_initialize(void)
 {
+	arm_pm_idle = at91sam9_idle;
 	arm_pm_restart = at91sam9_alt_restart;
 	at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1)
 			| (1 << AT91SAM9261_ID_IRQ2);
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 1e28bed..4db961a 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -24,6 +24,7 @@
 #include <mach/board.h>
 #include <mach/at91sam9261.h>
 #include <mach/at91sam9261_matrix.h>
+#include <mach/at91_matrix.h>
 #include <mach/at91sam9_smc.h>
 
 #include "generic.h"
@@ -236,8 +237,8 @@
 	if (!data)
 		return;
 
-	csa = at91_sys_read(AT91_MATRIX_EBICSA);
-	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
+	csa = at91_matrix_read(AT91_MATRIX_EBICSA);
+	at91_matrix_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
 
 	/* enable pin */
 	if (gpio_is_valid(data->enable_pin))
@@ -414,6 +415,9 @@
 		else
 			cs_pin = spi1_standard_cs[devices[i].chip_select];
 
+		if (!gpio_is_valid(cs_pin))
+			continue;
+
 		if (devices[i].bus_num == 0)
 			enable_spi0 = 1;
 		else
@@ -603,6 +607,8 @@
 		.start	= AT91SAM9261_BASE_RTT,
 		.end	= AT91SAM9261_BASE_RTT + SZ_16 - 1,
 		.flags	= IORESOURCE_MEM,
+	}, {
+		.flags	= IORESOURCE_MEM,
 	}
 };
 
@@ -610,11 +616,32 @@
 	.name		= "at91_rtt",
 	.id		= 0,
 	.resource	= rtt_resources,
-	.num_resources	= ARRAY_SIZE(rtt_resources),
 };
 
+#if IS_ENABLED(CONFIG_RTC_DRV_AT91SAM9)
+static void __init at91_add_device_rtt_rtc(void)
+{
+	at91sam9261_rtt_device.name = "rtc-at91sam9";
+	/*
+	 * The second resource is needed:
+	 * GPBR will serve as the storage for RTC time offset
+	 */
+	at91sam9261_rtt_device.num_resources = 2;
+	rtt_resources[1].start = AT91SAM9261_BASE_GPBR +
+				 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR;
+	rtt_resources[1].end = rtt_resources[1].start + 3;
+}
+#else
+static void __init at91_add_device_rtt_rtc(void)
+{
+	/* Only one resource is needed: RTT not used as RTC */
+	at91sam9261_rtt_device.num_resources = 1;
+}
+#endif
+
 static void __init at91_add_device_rtt(void)
 {
+	at91_add_device_rtt_rtc();
 	platform_device_register(&at91sam9261_rtt_device);
 }
 
@@ -991,7 +1018,6 @@
 }
 
 static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
-struct platform_device *atmel_default_console_device;	/* the serial console device */
 
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index 75e876c..ef301be 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -12,9 +12,11 @@
 
 #include <linux/module.h>
 
+#include <asm/proc-fns.h>
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/system_misc.h>
 #include <mach/at91sam9263.h>
 #include <mach/at91_pmc.h>
 #include <mach/at91_rstc.h>
@@ -302,13 +304,17 @@
 {
 	at91_ioremap_shdwc(AT91SAM9263_BASE_SHDWC);
 	at91_ioremap_rstc(AT91SAM9263_BASE_RSTC);
+	at91_ioremap_ramc(0, AT91SAM9263_BASE_SDRAMC0, 512);
+	at91_ioremap_ramc(1, AT91SAM9263_BASE_SDRAMC1, 512);
 	at91sam926x_ioremap_pit(AT91SAM9263_BASE_PIT);
 	at91sam9_ioremap_smc(0, AT91SAM9263_BASE_SMC0);
 	at91sam9_ioremap_smc(1, AT91SAM9263_BASE_SMC1);
+	at91_ioremap_matrix(AT91SAM9263_BASE_MATRIX);
 }
 
 static void __init at91sam9263_initialize(void)
 {
+	arm_pm_idle = at91sam9_idle;
 	arm_pm_restart = at91sam9_alt_restart;
 	at91_extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1);
 
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index 366a776..fe99206 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -23,6 +23,7 @@
 #include <mach/board.h>
 #include <mach/at91sam9263.h>
 #include <mach/at91sam9263_matrix.h>
+#include <mach/at91_matrix.h>
 #include <mach/at91sam9_smc.h>
 
 #include "generic.h"
@@ -71,7 +72,8 @@
 	/* Enable VBus control for UHP ports */
 	for (i = 0; i < data->ports; i++) {
 		if (gpio_is_valid(data->vbus_pin[i]))
-			at91_set_gpio_output(data->vbus_pin[i], 0);
+			at91_set_gpio_output(data->vbus_pin[i],
+					     data->vbus_pin_active_low[i]);
 	}
 
 	/* Enable overcurrent notification */
@@ -409,7 +411,7 @@
 	 * we assume SMC timings are configured by board code,
 	 * except True IDE where timings are controlled by driver
 	 */
-	ebi0_csa = at91_sys_read(AT91_MATRIX_EBI0CSA);
+	ebi0_csa = at91_matrix_read(AT91_MATRIX_EBI0CSA);
 	switch (data->chipselect) {
 	case 4:
 		at91_set_A_periph(AT91_PIN_PD6, 0);  /* EBI0_NCS4/CFCS0 */
@@ -428,7 +430,7 @@
 		       data->chipselect);
 		return;
 	}
-	at91_sys_write(AT91_MATRIX_EBI0CSA, ebi0_csa);
+	at91_matrix_write(AT91_MATRIX_EBI0CSA, ebi0_csa);
 
 	if (gpio_is_valid(data->det_pin)) {
 		at91_set_gpio_input(data->det_pin, 1);
@@ -496,8 +498,8 @@
 	if (!data)
 		return;
 
-	csa = at91_sys_read(AT91_MATRIX_EBI0CSA);
-	at91_sys_write(AT91_MATRIX_EBI0CSA, csa | AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA);
+	csa = at91_matrix_read(AT91_MATRIX_EBI0CSA);
+	at91_matrix_write(AT91_MATRIX_EBI0CSA, csa | AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA);
 
 	/* enable pin */
 	if (gpio_is_valid(data->enable_pin))
@@ -670,6 +672,9 @@
 		else
 			cs_pin = spi1_standard_cs[devices[i].chip_select];
 
+		if (!gpio_is_valid(cs_pin))
+			continue;
+
 		if (devices[i].bus_num == 0)
 			enable_spi0 = 1;
 		else
@@ -891,7 +896,8 @@
 	.num_resources	= ARRAY_SIZE(isi_resources),
 };
 
-void __init at91_add_device_isi(void)
+void __init at91_add_device_isi(struct isi_platform_data *data,
+		bool use_pck_as_mck)
 {
 	at91_set_A_periph(AT91_PIN_PE0, 0);	/* ISI_D0 */
 	at91_set_A_periph(AT91_PIN_PE1, 0);	/* ISI_D1 */
@@ -904,14 +910,20 @@
 	at91_set_A_periph(AT91_PIN_PE8, 0);	/* ISI_PCK */
 	at91_set_A_periph(AT91_PIN_PE9, 0);	/* ISI_HSYNC */
 	at91_set_A_periph(AT91_PIN_PE10, 0);	/* ISI_VSYNC */
-	at91_set_B_periph(AT91_PIN_PE11, 0);	/* ISI_MCK (PCK3) */
 	at91_set_B_periph(AT91_PIN_PE12, 0);	/* ISI_PD8 */
 	at91_set_B_periph(AT91_PIN_PE13, 0);	/* ISI_PD9 */
 	at91_set_B_periph(AT91_PIN_PE14, 0);	/* ISI_PD10 */
 	at91_set_B_periph(AT91_PIN_PE15, 0);	/* ISI_PD11 */
+
+	if (use_pck_as_mck) {
+		at91_set_B_periph(AT91_PIN_PE11, 0);	/* ISI_MCK (PCK3) */
+
+		/* TODO: register the PCK for ISI_MCK and set its parent */
+	}
 }
 #else
-void __init at91_add_device_isi(void) {}
+void __init at91_add_device_isi(struct isi_platform_data *data,
+		bool use_pck_as_mck) {}
 #endif
 
 
@@ -959,6 +971,8 @@
 		.start	= AT91SAM9263_BASE_RTT0,
 		.end	= AT91SAM9263_BASE_RTT0 + SZ_16 - 1,
 		.flags	= IORESOURCE_MEM,
+	}, {
+		.flags	= IORESOURCE_MEM,
 	}
 };
 
@@ -966,7 +980,6 @@
 	.name		= "at91_rtt",
 	.id		= 0,
 	.resource	= rtt0_resources,
-	.num_resources	= ARRAY_SIZE(rtt0_resources),
 };
 
 static struct resource rtt1_resources[] = {
@@ -974,6 +987,8 @@
 		.start	= AT91SAM9263_BASE_RTT1,
 		.end	= AT91SAM9263_BASE_RTT1 + SZ_16 - 1,
 		.flags	= IORESOURCE_MEM,
+	}, {
+		.flags	= IORESOURCE_MEM,
 	}
 };
 
@@ -981,11 +996,53 @@
 	.name		= "at91_rtt",
 	.id		= 1,
 	.resource	= rtt1_resources,
-	.num_resources	= ARRAY_SIZE(rtt1_resources),
 };
 
+#if IS_ENABLED(CONFIG_RTC_DRV_AT91SAM9)
+static void __init at91_add_device_rtt_rtc(void)
+{
+	struct platform_device *pdev;
+	struct resource *r;
+
+	switch (CONFIG_RTC_DRV_AT91SAM9_RTT) {
+	case 0:
+		/*
+		 * The second resource is needed only for the chosen RTT:
+		 * GPBR will serve as the storage for RTC time offset
+		 */
+		at91sam9263_rtt0_device.num_resources = 2;
+		at91sam9263_rtt1_device.num_resources = 1;
+		pdev = &at91sam9263_rtt0_device;
+		r = rtt0_resources;
+		break;
+	case 1:
+		at91sam9263_rtt0_device.num_resources = 1;
+		at91sam9263_rtt1_device.num_resources = 2;
+		pdev = &at91sam9263_rtt1_device;
+		r = rtt1_resources;
+		break;
+	default:
+		pr_err("at91sam9263: only supports 2 RTT (%d)\n",
+		       CONFIG_RTC_DRV_AT91SAM9_RTT);
+		return;
+	}
+
+	pdev->name = "rtc-at91sam9";
+	r[1].start = AT91SAM9263_BASE_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR;
+	r[1].end = r[1].start + 3;
+}
+#else
+static void __init at91_add_device_rtt_rtc(void)
+{
+	/* Only one resource is needed: RTT not used as RTC */
+	at91sam9263_rtt0_device.num_resources = 1;
+	at91sam9263_rtt1_device.num_resources = 1;
+}
+#endif
+
 static void __init at91_add_device_rtt(void)
 {
+	at91_add_device_rtt_rtc();
 	platform_device_register(&at91sam9263_rtt0_device);
 	platform_device_register(&at91sam9263_rtt1_device);
 }
@@ -1371,7 +1428,6 @@
 }
 
 static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
-struct platform_device *atmel_default_console_device;	/* the serial console device */
 
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c
index d89ead7..a94758b 100644
--- a/arch/arm/mach-at91/at91sam926x_time.c
+++ b/arch/arm/mach-at91/at91sam926x_time.c
@@ -14,6 +14,9 @@
 #include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/clockchips.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #include <asm/mach/time.h>
 
@@ -133,7 +136,8 @@
 static struct irqaction at91sam926x_pit_irq = {
 	.name		= "at91_tick",
 	.flags		= IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-	.handler	= at91sam926x_pit_interrupt
+	.handler	= at91sam926x_pit_interrupt,
+	.irq		= AT91_ID_SYS,
 };
 
 static void at91sam926x_pit_reset(void)
@@ -149,6 +153,51 @@
 	pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN);
 }
 
+#ifdef CONFIG_OF
+static struct of_device_id pit_timer_ids[] = {
+	{ .compatible = "atmel,at91sam9260-pit" },
+	{ /* sentinel */ }
+};
+
+static int __init of_at91sam926x_pit_init(void)
+{
+	struct device_node	*np;
+	int			ret;
+
+	np = of_find_matching_node(NULL, pit_timer_ids);
+	if (!np)
+		goto err;
+
+	pit_base_addr = of_iomap(np, 0);
+	if (!pit_base_addr)
+		goto node_err;
+
+	/* Get the interrupts property */
+	ret = irq_of_parse_and_map(np, 0);
+	if (!ret) {
+		pr_crit("AT91: PIT: Unable to get IRQ from DT\n");
+		goto ioremap_err;
+	}
+	at91sam926x_pit_irq.irq = ret;
+
+	of_node_put(np);
+
+	return 0;
+
+ioremap_err:
+	iounmap(pit_base_addr);
+node_err:
+	of_node_put(np);
+err:
+	return -EINVAL;
+}
+#else
+static int __init of_at91sam926x_pit_init(void)
+{
+	return -EINVAL;
+}
+#endif
+
 /*
  * Set up both clocksource and clockevent support.
  */
@@ -156,6 +205,10 @@
 {
 	unsigned long	pit_rate;
 	unsigned	bits;
+	int		ret;
+
+	/* For device tree enabled device: initialize here */
+	of_at91sam926x_pit_init();
 
 	/*
 	 * Use our actual MCK to figure out how many MCK/16 ticks per
@@ -177,7 +230,9 @@
 	clocksource_register_hz(&pit_clk, pit_rate);
 
 	/* Set up irq handler */
-	setup_irq(AT91_ID_SYS, &at91sam926x_pit_irq);
+	ret = setup_irq(at91sam926x_pit_irq.irq, &at91sam926x_pit_irq);
+	if (ret)
+		pr_crit("AT91: PIT: Unable to setup IRQ\n");
 
 	/* Set up and register clockevents */
 	pit_clkevt.mult = div_sc(pit_rate, NSEC_PER_SEC, pit_clkevt.shift);
@@ -193,6 +248,15 @@
 
 void __init at91sam926x_ioremap_pit(u32 addr)
 {
+#if defined(CONFIG_OF)
+	struct device_node *np =
+		of_find_matching_node(NULL, pit_timer_ids);
+
+	if (np) {
+		of_node_put(np);
+		return;
+	}
+#endif
 	pit_base_addr = ioremap(addr, 16);
 
 	if (!pit_base_addr)
diff --git a/arch/arm/mach-at91/at91sam9_alt_reset.S b/arch/arm/mach-at91/at91sam9_alt_reset.S
index 518e423..7af2e10 100644
--- a/arch/arm/mach-at91/at91sam9_alt_reset.S
+++ b/arch/arm/mach-at91/at91sam9_alt_reset.S
@@ -15,16 +15,17 @@
 
 #include <linux/linkage.h>
 #include <mach/hardware.h>
-#include <mach/at91sam9_sdramc.h>
+#include <mach/at91_ramc.h>
 #include <mach/at91_rstc.h>
 
 			.arm
 
 			.globl	at91sam9_alt_restart
 
-at91sam9_alt_restart:	ldr	r0, .at91_va_base_sdramc	@ preload constants
-			ldr	r1, =at91_rstc_base
-			ldr	r1, [r1]
+at91sam9_alt_restart:	ldr	r0, =at91_ramc_base		@ preload constants
+			ldr	r0, [r0]
+			ldr	r4, =at91_rstc_base
+			ldr	r1, [r4]
 
 			mov	r2, #1
 			mov	r3, #AT91_SDRAMC_LPCB_POWER_DOWN
@@ -37,6 +38,3 @@
 			str	r4, [r1, #AT91_RSTC_CR]		@ reset processor
 
 			b	.
-
-.at91_va_base_sdramc:
-	.word AT91_VA_BASE_SYS + AT91_SDRAMC0
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index 1cb6a96..d222f83 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -16,6 +16,7 @@
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/system_misc.h>
 #include <mach/at91sam9g45.h>
 #include <mach/at91_pmc.h>
 #include <mach/cpu.h>
@@ -229,6 +230,11 @@
 	CLKDEV_CON_DEV_ID("usart", "fff90000.serial", &usart1_clk),
 	CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk),
 	CLKDEV_CON_DEV_ID("usart", "fff98000.serial", &usart3_clk),
+	/* more tc lookup table for DT entries */
+	CLKDEV_CON_DEV_ID("t0_clk", "fff7c000.timer", &tcb0_clk),
+	CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),
+	CLKDEV_CON_DEV_ID("hclk", "700000.ohci", &uhphs_clk),
+	CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk),
 	/* fake hclk clock */
 	CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
 	CLKDEV_CON_ID("pioA", &pioA_clk),
@@ -331,12 +337,16 @@
 {
 	at91_ioremap_shdwc(AT91SAM9G45_BASE_SHDWC);
 	at91_ioremap_rstc(AT91SAM9G45_BASE_RSTC);
+	at91_ioremap_ramc(0, AT91SAM9G45_BASE_DDRSDRC1, 512);
+	at91_ioremap_ramc(1, AT91SAM9G45_BASE_DDRSDRC0, 512);
 	at91sam926x_ioremap_pit(AT91SAM9G45_BASE_PIT);
 	at91sam9_ioremap_smc(0, AT91SAM9G45_BASE_SMC);
+	at91_ioremap_matrix(AT91SAM9G45_BASE_MATRIX);
 }
 
 static void __init at91sam9g45_initialize(void)
 {
+	arm_pm_idle = at91sam9_idle;
 	arm_pm_restart = at91sam9g45_restart;
 	at91_extern_irq = (1 << AT91SAM9G45_ID_IRQ0);
 
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 96e2adc..6b008ae 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -14,6 +14,7 @@
 
 #include <linux/dma-mapping.h>
 #include <linux/gpio.h>
+#include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
 #include <linux/atmel-mci.h>
@@ -24,11 +25,15 @@
 #include <mach/board.h>
 #include <mach/at91sam9g45.h>
 #include <mach/at91sam9g45_matrix.h>
+#include <mach/at91_matrix.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at_hdmac.h>
 #include <mach/atmel-mci.h>
 
+#include <media/atmel-isi.h>
+
 #include "generic.h"
+#include "clock.h"
 
 
 /* --------------------------------------------------------------------
@@ -122,12 +127,13 @@
 	/* Enable VBus control for UHP ports */
 	for (i = 0; i < data->ports; i++) {
 		if (gpio_is_valid(data->vbus_pin[i]))
-			at91_set_gpio_output(data->vbus_pin[i], 0);
+			at91_set_gpio_output(data->vbus_pin[i],
+					     data->vbus_pin_active_low[i]);
 	}
 
 	/* Enable overcurrent notification */
 	for (i = 0; i < data->ports; i++) {
-		if (data->overcurrent_pin[i])
+		if (gpio_is_valid(data->overcurrent_pin[i]))
 			at91_set_gpio_input(data->overcurrent_pin[i], 1);
 	}
 
@@ -183,7 +189,8 @@
 	/* Enable VBus control for UHP ports */
 	for (i = 0; i < data->ports; i++) {
 		if (gpio_is_valid(data->vbus_pin[i]))
-			at91_set_gpio_output(data->vbus_pin[i], 0);
+			at91_set_gpio_output(data->vbus_pin[i],
+					     data->vbus_pin_active_low[i]);
 	}
 
 	usbh_ehci_data = *data;
@@ -432,7 +439,6 @@
 
 	/* DMA slave channel configuration */
 	atslave->dma_dev = &at_hdmac_device.dev;
-	atslave->reg_width = AT_DMA_SLAVE_WIDTH_32BIT;
 	atslave->cfg = ATC_FIFOCFG_HALFFIFO
 			| ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW;
 	atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16;
@@ -553,8 +559,8 @@
 	if (!data)
 		return;
 
-	csa = at91_sys_read(AT91_MATRIX_EBICSA);
-	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
+	csa = at91_matrix_read(AT91_MATRIX_EBICSA);
+	at91_matrix_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
 
 	/* enable pin */
 	if (gpio_is_valid(data->enable_pin))
@@ -781,6 +787,9 @@
 		else
 			cs_pin = spi1_standard_cs[devices[i].chip_select];
 
+		if (!gpio_is_valid(cs_pin))
+			continue;
+
 		if (devices[i].bus_num == 0)
 			enable_spi0 = 1;
 		else
@@ -870,6 +879,96 @@
 void __init at91_add_device_ac97(struct ac97c_platform_data *data) {}
 #endif
 
+/* --------------------------------------------------------------------
+ *  Image Sensor Interface
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE)
+static u64 isi_dmamask = DMA_BIT_MASK(32);
+static struct isi_platform_data isi_data;
+
+struct resource isi_resources[] = {
+	[0] = {
+		.start	= AT91SAM9G45_BASE_ISI,
+		.end	= AT91SAM9G45_BASE_ISI + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9G45_ID_ISI,
+		.end	= AT91SAM9G45_ID_ISI,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9g45_isi_device = {
+	.name		= "atmel_isi",
+	.id		= 0,
+	.dev		= {
+			.dma_mask		= &isi_dmamask,
+			.coherent_dma_mask	= DMA_BIT_MASK(32),
+			.platform_data		= &isi_data,
+	},
+	.resource	= isi_resources,
+	.num_resources	= ARRAY_SIZE(isi_resources),
+};
+
+static struct clk_lookup isi_mck_lookups[] = {
+	CLKDEV_CON_DEV_ID("isi_mck", "atmel_isi.0", NULL),
+};
+
+void __init at91_add_device_isi(struct isi_platform_data *data,
+		bool use_pck_as_mck)
+{
+	struct clk *pck;
+	struct clk *parent;
+
+	if (!data)
+		return;
+	isi_data = *data;
+
+	at91_set_A_periph(AT91_PIN_PB20, 0);	/* ISI_D0 */
+	at91_set_A_periph(AT91_PIN_PB21, 0);	/* ISI_D1 */
+	at91_set_A_periph(AT91_PIN_PB22, 0);	/* ISI_D2 */
+	at91_set_A_periph(AT91_PIN_PB23, 0);	/* ISI_D3 */
+	at91_set_A_periph(AT91_PIN_PB24, 0);	/* ISI_D4 */
+	at91_set_A_periph(AT91_PIN_PB25, 0);	/* ISI_D5 */
+	at91_set_A_periph(AT91_PIN_PB26, 0);	/* ISI_D6 */
+	at91_set_A_periph(AT91_PIN_PB27, 0);	/* ISI_D7 */
+	at91_set_A_periph(AT91_PIN_PB28, 0);	/* ISI_PCK */
+	at91_set_A_periph(AT91_PIN_PB30, 0);	/* ISI_HSYNC */
+	at91_set_A_periph(AT91_PIN_PB29, 0);	/* ISI_VSYNC */
+	at91_set_B_periph(AT91_PIN_PB8, 0);	/* ISI_PD8 */
+	at91_set_B_periph(AT91_PIN_PB9, 0);	/* ISI_PD9 */
+	at91_set_B_periph(AT91_PIN_PB10, 0);	/* ISI_PD10 */
+	at91_set_B_periph(AT91_PIN_PB11, 0);	/* ISI_PD11 */
+
+	platform_device_register(&at91sam9g45_isi_device);
+
+	if (use_pck_as_mck) {
+		at91_set_B_periph(AT91_PIN_PB31, 0);	/* ISI_MCK (PCK1) */
+
+		pck = clk_get(NULL, "pck1");
+		parent = clk_get(NULL, "plla");
+
+		BUG_ON(IS_ERR(pck) || IS_ERR(parent));
+
+		if (clk_set_parent(pck, parent)) {
+			pr_err("Failed to set PCK's parent\n");
+		} else {
+			/* Register PCK as ISI_MCK */
+			isi_mck_lookups[0].clk = pck;
+			clkdev_add_table(isi_mck_lookups,
+					ARRAY_SIZE(isi_mck_lookups));
+		}
+
+		clk_put(pck);
+		clk_put(parent);
+	}
+}
+#else
+void __init at91_add_device_isi(struct isi_platform_data *data,
+		bool use_pck_as_mck) {}
+#endif
+
 
 /* --------------------------------------------------------------------
  *  LCD Controller
@@ -957,7 +1056,7 @@
 static struct resource tcb0_resources[] = {
 	[0] = {
 		.start	= AT91SAM9G45_BASE_TCB0,
-		.end	= AT91SAM9G45_BASE_TCB0 + SZ_16K - 1,
+		.end	= AT91SAM9G45_BASE_TCB0 + SZ_256 - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -978,7 +1077,7 @@
 static struct resource tcb1_resources[] = {
 	[0] = {
 		.start	= AT91SAM9G45_BASE_TCB1,
-		.end	= AT91SAM9G45_BASE_TCB1 + SZ_16K - 1,
+		.end	= AT91SAM9G45_BASE_TCB1 + SZ_256 - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -995,8 +1094,25 @@
 	.num_resources	= ARRAY_SIZE(tcb1_resources),
 };
 
+#if defined(CONFIG_OF)
+static struct of_device_id tcb_ids[] = {
+	{ .compatible = "atmel,at91rm9200-tcb" },
+	{ /*sentinel*/ }
+};
+#endif
+
 static void __init at91_add_device_tc(void)
 {
+#if defined(CONFIG_OF)
+	struct device_node *np;
+
+	np = of_find_matching_node(NULL, tcb_ids);
+	if (np) {
+		of_node_put(np);
+		return;
+	}
+#endif
+
 	platform_device_register(&at91sam9g45_tcb0_device);
 	platform_device_register(&at91sam9g45_tcb1_device);
 }
@@ -1099,6 +1215,8 @@
 		.start	= AT91SAM9G45_BASE_RTT,
 		.end	= AT91SAM9G45_BASE_RTT + SZ_16 - 1,
 		.flags	= IORESOURCE_MEM,
+	}, {
+		.flags	= IORESOURCE_MEM,
 	}
 };
 
@@ -1106,11 +1224,32 @@
 	.name		= "at91_rtt",
 	.id		= 0,
 	.resource	= rtt_resources,
-	.num_resources	= ARRAY_SIZE(rtt_resources),
 };
 
+#if IS_ENABLED(CONFIG_RTC_DRV_AT91SAM9)
+static void __init at91_add_device_rtt_rtc(void)
+{
+	at91sam9g45_rtt_device.name = "rtc-at91sam9";
+	/*
+	 * The second resource is needed:
+	 * GPBR will serve as the storage for RTC time offset
+	 */
+	at91sam9g45_rtt_device.num_resources = 2;
+	rtt_resources[1].start = AT91SAM9G45_BASE_GPBR +
+				 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR;
+	rtt_resources[1].end = rtt_resources[1].start + 3;
+}
+#else
+static void __init at91_add_device_rtt_rtc(void)
+{
+	/* Only one resource is needed: RTT not used as RTC */
+	at91sam9g45_rtt_device.num_resources = 1;
+}
+#endif
+
 static void __init at91_add_device_rtt(void)
 {
+	at91_add_device_rtt_rtc();
 	platform_device_register(&at91sam9g45_rtt_device);
 }
 
@@ -1565,7 +1704,6 @@
 }
 
 static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
-struct platform_device *atmel_default_console_device;	/* the serial console device */
 
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
diff --git a/arch/arm/mach-at91/at91sam9g45_reset.S b/arch/arm/mach-at91/at91sam9g45_reset.S
index 0468be1..9d45718 100644
--- a/arch/arm/mach-at91/at91sam9g45_reset.S
+++ b/arch/arm/mach-at91/at91sam9g45_reset.S
@@ -12,7 +12,7 @@
 
 #include <linux/linkage.h>
 #include <mach/hardware.h>
-#include <mach/at91sam9_ddrsdr.h>
+#include <mach/at91_ramc.h>
 #include <mach/at91_rstc.h>
 
 			.arm
@@ -20,9 +20,10 @@
 			.globl	at91sam9g45_restart
 
 at91sam9g45_restart:
-			ldr	r0, .at91_va_base_sdramc0	@ preload constants
-			ldr	r1, =at91_rstc_base
-			ldr	r1, [r1]
+			ldr	r5, =at91_ramc_base		@ preload constants
+			ldr	r0, [r5]
+			ldr	r4, =at91_rstc_base
+			ldr	r1, [r4]
 
 			mov	r2, #1
 			mov	r3, #AT91_DDRSDRC_LPCB_POWER_DOWN
@@ -35,6 +36,3 @@
 			str	r4, [r1, #AT91_RSTC_CR]		@ reset processor
 
 			b	.
-
-.at91_va_base_sdramc0:
-	.word AT91_VA_BASE_SYS + AT91_DDRSDRC0
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index d2c91a8..d9f2774 100644
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ b/arch/arm/mach-at91/at91sam9rl.c
@@ -11,9 +11,11 @@
 
 #include <linux/module.h>
 
+#include <asm/proc-fns.h>
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/system_misc.h>
 #include <mach/cpu.h>
 #include <mach/at91_dbgu.h>
 #include <mach/at91sam9rl.h>
@@ -287,12 +289,15 @@
 {
 	at91_ioremap_shdwc(AT91SAM9RL_BASE_SHDWC);
 	at91_ioremap_rstc(AT91SAM9RL_BASE_RSTC);
+	at91_ioremap_ramc(0, AT91SAM9RL_BASE_SDRAMC, 512);
 	at91sam926x_ioremap_pit(AT91SAM9RL_BASE_PIT);
 	at91sam9_ioremap_smc(0, AT91SAM9RL_BASE_SMC);
+	at91_ioremap_matrix(AT91SAM9RL_BASE_MATRIX);
 }
 
 static void __init at91sam9rl_initialize(void)
 {
+	arm_pm_idle = at91sam9_idle;
 	arm_pm_restart = at91sam9_alt_restart;
 	at91_extern_irq = (1 << AT91SAM9RL_ID_IRQ0);
 
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index 9be71c1..fe4ae22 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -20,6 +20,7 @@
 #include <mach/board.h>
 #include <mach/at91sam9rl.h>
 #include <mach/at91sam9rl_matrix.h>
+#include <mach/at91_matrix.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at_hdmac.h>
 
@@ -265,8 +266,8 @@
 	if (!data)
 		return;
 
-	csa = at91_sys_read(AT91_MATRIX_EBICSA);
-	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
+	csa = at91_matrix_read(AT91_MATRIX_EBICSA);
+	at91_matrix_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
 
 	/* enable pin */
 	if (gpio_is_valid(data->enable_pin))
@@ -418,6 +419,9 @@
 		else
 			cs_pin = spi_standard_cs[devices[i].chip_select];
 
+		if (!gpio_is_valid(cs_pin))
+			continue;
+
 		/* enable chip-select pin */
 		at91_set_gpio_output(cs_pin, 1);
 
@@ -682,6 +686,8 @@
 		.start	= AT91SAM9RL_BASE_RTT,
 		.end	= AT91SAM9RL_BASE_RTT + SZ_16 - 1,
 		.flags	= IORESOURCE_MEM,
+	}, {
+		.flags	= IORESOURCE_MEM,
 	}
 };
 
@@ -689,11 +695,32 @@
 	.name		= "at91_rtt",
 	.id		= 0,
 	.resource	= rtt_resources,
-	.num_resources	= ARRAY_SIZE(rtt_resources),
 };
 
+#if IS_ENABLED(CONFIG_RTC_DRV_AT91SAM9)
+static void __init at91_add_device_rtt_rtc(void)
+{
+	at91sam9rl_rtt_device.name = "rtc-at91sam9";
+	/*
+	 * The second resource is needed:
+	 * GPBR will serve as the storage for RTC time offset
+	 */
+	at91sam9rl_rtt_device.num_resources = 2;
+	rtt_resources[1].start = AT91SAM9RL_BASE_GPBR +
+				 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR;
+	rtt_resources[1].end = rtt_resources[1].start + 3;
+}
+#else
+static void __init at91_add_device_rtt_rtc(void)
+{
+	/* Only one resource is needed: RTT not used as RTC */
+	at91sam9rl_rtt_device.num_resources = 1;
+}
+#endif
+
 static void __init at91_add_device_rtt(void)
 {
+	at91_add_device_rtt_rtc();
 	platform_device_register(&at91sam9rl_rtt_device);
 }
 
@@ -1128,7 +1155,6 @@
 }
 
 static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
-struct platform_device *atmel_default_console_device;	/* the serial console device */
 
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
new file mode 100644
index 0000000..13c8cae
--- /dev/null
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -0,0 +1,361 @@
+/*
+ *  Chip-specific setup code for the AT91SAM9x5 family
+ *
+ *  Copyright (C) 2010-2012 Atmel Corporation.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/at91sam9x5.h>
+#include <mach/at91_pmc.h>
+#include <mach/cpu.h>
+#include <mach/board.h>
+
+#include "soc.h"
+#include "generic.h"
+#include "clock.h"
+#include "sam9_smc.h"
+
+/* --------------------------------------------------------------------
+ *  Clocks
+ * -------------------------------------------------------------------- */
+
+/*
+ * The peripheral clocks.
+ */
+static struct clk pioAB_clk = {
+	.name		= "pioAB_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_PIOAB,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioCD_clk = {
+	.name		= "pioCD_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_PIOCD,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk smd_clk = {
+	.name		= "smd_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_SMD,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart0_clk = {
+	.name		= "usart0_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_USART0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart1_clk = {
+	.name		= "usart1_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_USART1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart2_clk = {
+	.name		= "usart2_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_USART2,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+/* USART3 clock - Only for sam9g25/sam9x25 */
+static struct clk usart3_clk = {
+	.name		= "usart3_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_USART3,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi0_clk = {
+	.name		= "twi0_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_TWI0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi1_clk = {
+	.name		= "twi1_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_TWI1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi2_clk = {
+	.name		= "twi2_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_TWI2,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc0_clk = {
+	.name		= "mci0_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_MCI0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi0_clk = {
+	.name		= "spi0_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_SPI0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi1_clk = {
+	.name		= "spi1_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_SPI1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk uart0_clk = {
+	.name		= "uart0_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_UART0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk uart1_clk = {
+	.name		= "uart1_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_UART1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tcb0_clk = {
+	.name		= "tcb0_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_TCB,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk pwm_clk = {
+	.name		= "pwm_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_PWM,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk adc_clk = {
+	.name		= "adc_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_ADC,
+	.type	= CLK_TYPE_PERIPHERAL,
+};
+static struct clk dma0_clk = {
+	.name		= "dma0_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_DMA0,
+	.type	= CLK_TYPE_PERIPHERAL,
+};
+static struct clk dma1_clk = {
+	.name		= "dma1_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_DMA1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk uhphs_clk = {
+	.name		= "uhphs",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_UHPHS,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk udphs_clk = {
+	.name		= "udphs_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_UDPHS,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+/* emac0 clock - Only for sam9g25/sam9x25/sam9g35/sam9x35 */
+static struct clk macb0_clk = {
+	.name		= "pclk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_EMAC0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+/* lcd clock - Only for sam9g15/sam9g35/sam9x35 */
+static struct clk lcdc_clk = {
+	.name		= "lcdc_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_LCDC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+/* isi clock - Only for sam9g25 */
+static struct clk isi_clk = {
+	.name		= "isi_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_ISI,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc1_clk = {
+	.name		= "mci1_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_MCI1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+/* emac1 clock - Only for sam9x25 */
+static struct clk macb1_clk = {
+	.name		= "pclk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_EMAC1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc_clk = {
+	.name		= "ssc_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_SSC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+/* can0 clock - Only for sam9x35 */
+static struct clk can0_clk = {
+	.name		= "can0_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_CAN0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+/* can1 clock - Only for sam9x35 */
+static struct clk can1_clk = {
+	.name		= "can1_clk",
+	.pmc_mask	= 1 << AT91SAM9X5_ID_CAN1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+
+static struct clk *periph_clocks[] __initdata = {
+	&pioAB_clk,
+	&pioCD_clk,
+	&smd_clk,
+	&usart0_clk,
+	&usart1_clk,
+	&usart2_clk,
+	&twi0_clk,
+	&twi1_clk,
+	&twi2_clk,
+	&mmc0_clk,
+	&spi0_clk,
+	&spi1_clk,
+	&uart0_clk,
+	&uart1_clk,
+	&tcb0_clk,
+	&pwm_clk,
+	&adc_clk,
+	&dma0_clk,
+	&dma1_clk,
+	&uhphs_clk,
+	&udphs_clk,
+	&mmc1_clk,
+	&ssc_clk,
+	// irq0
+};
+
+static struct clk_lookup periph_clocks_lookups[] = {
+	/* lookup table for DT entries */
+	CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
+	CLKDEV_CON_DEV_ID("usart", "f801c000.serial", &usart0_clk),
+	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("t0_clk", "f8008000.timer", &tcb0_clk),
+	CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),
+	CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk),
+	CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
+	CLKDEV_CON_ID("pioA", &pioAB_clk),
+	CLKDEV_CON_ID("pioB", &pioAB_clk),
+	CLKDEV_CON_ID("pioC", &pioCD_clk),
+	CLKDEV_CON_ID("pioD", &pioCD_clk),
+	/* additional fake clock for macb_hclk */
+	CLKDEV_CON_DEV_ID("hclk", "f802c000.ethernet", &macb0_clk),
+	CLKDEV_CON_DEV_ID("hclk", "f8030000.ethernet", &macb1_clk),
+	CLKDEV_CON_DEV_ID("hclk", "600000.ohci", &uhphs_clk),
+	CLKDEV_CON_DEV_ID("ohci_clk", "600000.ohci", &uhphs_clk),
+	CLKDEV_CON_DEV_ID("ehci_clk", "700000.ehci", &uhphs_clk),
+};
+
+/*
+ * The two programmable clocks.
+ * You must configure pin multiplexing to bring these signals out.
+ */
+static struct clk pck0 = {
+	.name		= "pck0",
+	.pmc_mask	= AT91_PMC_PCK0,
+	.type		= CLK_TYPE_PROGRAMMABLE,
+	.id		= 0,
+};
+static struct clk pck1 = {
+	.name		= "pck1",
+	.pmc_mask	= AT91_PMC_PCK1,
+	.type		= CLK_TYPE_PROGRAMMABLE,
+	.id		= 1,
+};
+
+static void __init at91sam9x5_register_clocks(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
+		clk_register(periph_clocks[i]);
+
+	clkdev_add_table(periph_clocks_lookups,
+			 ARRAY_SIZE(periph_clocks_lookups));
+
+	if (cpu_is_at91sam9g25()
+	|| cpu_is_at91sam9x25())
+		clk_register(&usart3_clk);
+
+	if (cpu_is_at91sam9g25()
+	|| cpu_is_at91sam9x25()
+	|| cpu_is_at91sam9g35()
+	|| cpu_is_at91sam9x35())
+		clk_register(&macb0_clk);
+
+	if (cpu_is_at91sam9g15()
+	|| cpu_is_at91sam9g35()
+	|| cpu_is_at91sam9x35())
+		clk_register(&lcdc_clk);
+
+	if (cpu_is_at91sam9g25())
+		clk_register(&isi_clk);
+
+	if (cpu_is_at91sam9x25())
+		clk_register(&macb1_clk);
+
+	if (cpu_is_at91sam9x25()
+	|| cpu_is_at91sam9x35()) {
+		clk_register(&can0_clk);
+		clk_register(&can1_clk);
+	}
+
+	clk_register(&pck0);
+	clk_register(&pck1);
+}
+
+/* --------------------------------------------------------------------
+ *  AT91SAM9x5 processor initialization
+ * -------------------------------------------------------------------- */
+
+static void __init at91sam9x5_map_io(void)
+{
+	at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE);
+}
+
+void __init at91sam9x5_initialize(void)
+{
+	at91_extern_irq = (1 << AT91SAM9X5_ID_IRQ0);
+
+	/* Register GPIO subsystem (using DT) */
+	at91_gpio_init(NULL, 0);
+}
+
+/* --------------------------------------------------------------------
+ *  Interrupt initialization
+ * -------------------------------------------------------------------- */
+/*
+ * The default interrupt priority levels (0 = lowest, 7 = highest).
+ */
+static unsigned int at91sam9x5_default_irq_priority[NR_AIC_IRQS] __initdata = {
+	7,	/* Advanced Interrupt Controller (FIQ) */
+	7,	/* System Peripherals */
+	1,	/* Parallel IO Controller A and B */
+	1,	/* Parallel IO Controller C and D */
+	4,	/* Soft Modem */
+	5,	/* USART 0 */
+	5,	/* USART 1 */
+	5,	/* USART 2 */
+	5,	/* USART 3 */
+	6,	/* Two-Wire Interface 0 */
+	6,	/* Two-Wire Interface 1 */
+	6,	/* Two-Wire Interface 2 */
+	0,	/* Multimedia Card Interface 0 */
+	5,	/* Serial Peripheral Interface 0 */
+	5,	/* Serial Peripheral Interface 1 */
+	5,	/* UART 0 */
+	5,	/* UART 1 */
+	0,	/* Timer Counter 0, 1, 2, 3, 4 and 5 */
+	0,	/* Pulse Width Modulation Controller */
+	0,	/* ADC Controller */
+	0,	/* DMA Controller 0 */
+	0,	/* DMA Controller 1 */
+	2,	/* USB Host High Speed port */
+	2,	/* USB Device High speed port */
+	3,	/* Ethernet MAC 0 */
+	3,	/* LDC Controller or Image Sensor Interface */
+	0,	/* Multimedia Card Interface 1 */
+	3,	/* Ethernet MAC 1 */
+	4,	/* Synchronous Serial Interface */
+	4,	/* CAN Controller 0 */
+	4,	/* CAN Controller 1 */
+	0,	/* Advanced Interrupt Controller (IRQ0) */
+};
+
+struct at91_init_soc __initdata at91sam9x5_soc = {
+	.map_io = at91sam9x5_map_io,
+	.default_irq_priority = at91sam9x5_default_irq_priority,
+	.register_clocks = at91sam9x5_register_clocks,
+	.init = at91sam9x5_initialize,
+};
diff --git a/arch/arm/mach-at91/at91x40.c b/arch/arm/mach-at91/at91x40.c
index 56ba3bd..d62fe09 100644
--- a/arch/arm/mach-at91/at91x40.c
+++ b/arch/arm/mach-at91/at91x40.c
@@ -13,6 +13,8 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <asm/proc-fns.h>
+#include <asm/system_misc.h>
 #include <asm/mach/arch.h>
 #include <mach/at91x40.h>
 #include <mach/at91_st.h>
@@ -37,8 +39,19 @@
 	return AT91X40_MASTER_CLOCK;
 }
 
+static void at91x40_idle(void)
+{
+	/*
+	 * Disable the processor clock.  The processor will be automatically
+	 * re-enabled by an interrupt or by a reset.
+	 */
+	__raw_writel(AT91_PS_CR_CPU, AT91_PS_CR);
+	cpu_do_idle();
+}
+
 void __init at91x40_initialize(unsigned long main_clock)
 {
+	arm_pm_idle = at91x40_idle;
 	at91_extern_irq = (1 << AT91X40_ID_IRQ0) | (1 << AT91X40_ID_IRQ1)
 			| (1 << AT91X40_ID_IRQ2);
 }
diff --git a/arch/arm/mach-at91/at91x40_time.c b/arch/arm/mach-at91/at91x40_time.c
index dfff289..6ca680a 100644
--- a/arch/arm/mach-at91/at91x40_time.c
+++ b/arch/arm/mach-at91/at91x40_time.c
@@ -28,6 +28,12 @@
 #include <asm/mach/time.h>
 #include <mach/at91_tc.h>
 
+#define at91_tc_read(field) \
+	__raw_readl(AT91_TC + field)
+
+#define at91_tc_write(field, value) \
+	__raw_writel(value, AT91_TC + field);
+
 /*
  *	3 counter/timer units present.
  */
@@ -37,12 +43,12 @@
 
 static unsigned long at91x40_gettimeoffset(void)
 {
-	return (at91_sys_read(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_CV) * 1000000 / (AT91X40_MASTER_CLOCK / 128));
+	return (at91_tc_read(AT91_TC_CLK1BASE + AT91_TC_CV) * 1000000 / (AT91X40_MASTER_CLOCK / 128));
 }
 
 static irqreturn_t at91x40_timer_interrupt(int irq, void *dev_id)
 {
-	at91_sys_read(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_SR);
+	at91_tc_read(AT91_TC_CLK1BASE + AT91_TC_SR);
 	timer_tick();
 	return IRQ_HANDLED;
 }
@@ -57,20 +63,20 @@
 {
 	unsigned int v;
 
-	at91_sys_write(AT91_TC + AT91_TC_BCR, 0);
-	v = at91_sys_read(AT91_TC + AT91_TC_BMR);
+	at91_tc_write(AT91_TC_BCR, 0);
+	v = at91_tc_read(AT91_TC_BMR);
 	v = (v & ~AT91_TC_TC1XC1S) | AT91_TC_TC1XC1S_NONE;
-	at91_sys_write(AT91_TC + AT91_TC_BMR, v);
+	at91_tc_write(AT91_TC_BMR, v);
 
-	at91_sys_write(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_CCR, AT91_TC_CLKDIS);
-	at91_sys_write(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_CMR, (AT91_TC_TIMER_CLOCK4 | AT91_TC_CPCTRG));
-	at91_sys_write(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_IDR, 0xffffffff);
-	at91_sys_write(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_RC, (AT91X40_MASTER_CLOCK / 128) / HZ - 1);
-	at91_sys_write(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_IER, (1<<4));
+	at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_CCR, AT91_TC_CLKDIS);
+	at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_CMR, (AT91_TC_TIMER_CLOCK4 | AT91_TC_CPCTRG));
+	at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_IDR, 0xffffffff);
+	at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_RC, (AT91X40_MASTER_CLOCK / 128) / HZ - 1);
+	at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_IER, (1<<4));
 
 	setup_irq(AT91X40_ID_TC1, &at91x40_timer_irq);
 
-	at91_sys_write(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_CCR, (AT91_TC_SWTRG | AT91_TC_CLKEN));
+	at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_CCR, (AT91_TC_SWTRG | AT91_TC_CLKEN));
 }
 
 struct sys_timer at91x40_timer = {
diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
index 3bb4069..161efba 100644
--- a/arch/arm/mach-at91/board-afeb-9260v1.c
+++ b/arch/arm/mach-at91/board-afeb-9260v1.c
@@ -138,6 +138,7 @@
 	.rdy_pin	= AT91_PIN_PC13,
 	.enable_pin	= AT91_PIN_PC14,
 	.bus_width_16	= 0,
+	.ecc_mode	= NAND_ECC_SOFT,
 	.parts		= afeb9260_nand_partition,
 	.num_parts	= ARRAY_SIZE(afeb9260_nand_partition),
 	.det_pin	= -EINVAL,
diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c
index 8510e9e..c6d44ee 100644
--- a/arch/arm/mach-at91/board-cam60.c
+++ b/arch/arm/mach-at91/board-cam60.c
@@ -140,6 +140,7 @@
 	.det_pin	= -EINVAL,
 	.rdy_pin	= AT91_PIN_PA9,
 	.enable_pin	= AT91_PIN_PA7,
+	.ecc_mode	= NAND_ECC_SOFT,
 	.parts		= cam60_nand_partition,
 	.num_parts	= ARRAY_SIZE(cam60_nand_partition),
 };
diff --git a/arch/arm/mach-at91/board-cap9adk.c b/arch/arm/mach-at91/board-cap9adk.c
deleted file mode 100644
index ac3de4f..0000000
--- a/arch/arm/mach-at91/board-cap9adk.c
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-cap9adk.c
- *
- *  Copyright (C) 2007 Stelian Pop <stelian.pop@leadtechdesign.com>
- *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
- *  Copyright (C) 2005 SAN People
- *  Copyright (C) 2007 Atmel 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
-#include <linux/fb.h>
-#include <linux/mtd/physmap.h>
-
-#include <video/atmel_lcdc.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <mach/board.h>
-#include <mach/at91cap9_matrix.h>
-#include <mach/at91sam9_smc.h>
-#include <mach/system_rev.h>
-
-#include "sam9_smc.h"
-#include "generic.h"
-
-
-static void __init cap9adk_init_early(void)
-{
-	/* Initialize processor: 12 MHz crystal */
-	at91_initialize(12000000);
-
-	/* Setup the LEDs: USER1 and USER2 LED for cpu/timer... */
-	at91_init_leds(AT91_PIN_PA10, AT91_PIN_PA11);
-	/* ... POWER LED always on */
-	at91_set_gpio_output(AT91_PIN_PC29, 1);
-
-	/* Setup the serial ports and console */
-	at91_register_uart(0, 0, 0);		/* DBGU = ttyS0 */
-	at91_set_serial_console(0);
-}
-
-/*
- * USB Host port
- */
-static struct at91_usbh_data __initdata cap9adk_usbh_data = {
-	.ports		= 2,
-	.vbus_pin	= {-EINVAL, -EINVAL},
-	.overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-/*
- * USB HS Device port
- */
-static struct usba_platform_data __initdata cap9adk_usba_udc_data = {
-	.vbus_pin	= AT91_PIN_PB31,
-};
-
-/*
- * ADS7846 Touchscreen
- */
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-static int ads7843_pendown_state(void)
-{
-	return !at91_get_gpio_value(AT91_PIN_PC4);	/* Touchscreen PENIRQ */
-}
-
-static struct ads7846_platform_data ads_info = {
-	.model			= 7843,
-	.x_min			= 150,
-	.x_max			= 3830,
-	.y_min			= 190,
-	.y_max			= 3830,
-	.vref_delay_usecs	= 100,
-	.x_plate_ohms		= 450,
-	.y_plate_ohms		= 250,
-	.pressure_max		= 15000,
-	.debounce_max		= 1,
-	.debounce_rep		= 0,
-	.debounce_tol		= (~0),
-	.get_pendown_state	= ads7843_pendown_state,
-};
-
-static void __init cap9adk_add_device_ts(void)
-{
-	at91_set_gpio_input(AT91_PIN_PC4, 1);	/* Touchscreen PENIRQ */
-	at91_set_gpio_input(AT91_PIN_PC5, 1);	/* Touchscreen BUSY */
-}
-#else
-static void __init cap9adk_add_device_ts(void) {}
-#endif
-
-
-/*
- * SPI devices.
- */
-static struct spi_board_info cap9adk_spi_devices[] = {
-#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
-	{	/* DataFlash card */
-		.modalias	= "mtd_dataflash",
-		.chip_select	= 0,
-		.max_speed_hz	= 15 * 1000 * 1000,
-		.bus_num	= 0,
-	},
-#endif
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-	{
-		.modalias	= "ads7846",
-		.chip_select	= 3,		/* can be 2 or 3, depending on J2 jumper */
-		.max_speed_hz	= 125000 * 26,	/* (max sample rate @ 3V) * (cmd + data + overhead) */
-		.bus_num	= 0,
-		.platform_data	= &ads_info,
-		.irq		= AT91_PIN_PC4,
-	},
-#endif
-};
-
-
-/*
- * MCI (SD/MMC)
- */
-static struct at91_mmc_data __initdata cap9adk_mmc_data = {
-	.wire4		= 1,
-	.det_pin	= -EINVAL,
-	.wp_pin		= -EINVAL,
-	.vcc_pin	= -EINVAL,
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct macb_platform_data __initdata cap9adk_macb_data = {
-	.phy_irq_pin	= -EINVAL,
-	.is_rmii	= 1,
-};
-
-
-/*
- * NAND flash
- */
-static struct mtd_partition __initdata cap9adk_nand_partitions[] = {
-	{
-		.name	= "NAND partition",
-		.offset	= 0,
-		.size	= MTDPART_SIZ_FULL,
-	},
-};
-
-static struct atmel_nand_data __initdata cap9adk_nand_data = {
-	.ale		= 21,
-	.cle		= 22,
-	.det_pin	= -EINVAL,
-	.rdy_pin	= -EINVAL,
-	.enable_pin	= AT91_PIN_PD15,
-	.parts		= cap9adk_nand_partitions,
-	.num_parts	= ARRAY_SIZE(cap9adk_nand_partitions),
-};
-
-static struct sam9_smc_config __initdata cap9adk_nand_smc_config = {
-	.ncs_read_setup		= 1,
-	.nrd_setup		= 2,
-	.ncs_write_setup	= 1,
-	.nwe_setup		= 2,
-
-	.ncs_read_pulse		= 6,
-	.nrd_pulse		= 4,
-	.ncs_write_pulse	= 6,
-	.nwe_pulse		= 4,
-
-	.read_cycle		= 8,
-	.write_cycle		= 8,
-
-	.mode			= AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
-	.tdf_cycles		= 1,
-};
-
-static void __init cap9adk_add_device_nand(void)
-{
-	unsigned long csa;
-
-	csa = at91_sys_read(AT91_MATRIX_EBICSA);
-	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
-
-	cap9adk_nand_data.bus_width_16 = board_have_nand_16bit();
-	/* setup bus-width (8 or 16) */
-	if (cap9adk_nand_data.bus_width_16)
-		cap9adk_nand_smc_config.mode |= AT91_SMC_DBW_16;
-	else
-		cap9adk_nand_smc_config.mode |= AT91_SMC_DBW_8;
-
-	/* configure chip-select 3 (NAND) */
-	sam9_smc_configure(0, 3, &cap9adk_nand_smc_config);
-
-	at91_add_device_nand(&cap9adk_nand_data);
-}
-
-
-/*
- * NOR flash
- */
-static struct mtd_partition cap9adk_nor_partitions[] = {
-	{
-		.name		= "NOR partition",
-		.offset		= 0,
-		.size		= MTDPART_SIZ_FULL,
-	},
-};
-
-static struct physmap_flash_data cap9adk_nor_data = {
-	.width		= 2,
-	.parts		= cap9adk_nor_partitions,
-	.nr_parts	= ARRAY_SIZE(cap9adk_nor_partitions),
-};
-
-#define NOR_BASE	AT91_CHIPSELECT_0
-#define NOR_SIZE	SZ_8M
-
-static struct resource nor_flash_resources[] = {
-	{
-		.start	= NOR_BASE,
-		.end	= NOR_BASE + NOR_SIZE - 1,
-		.flags	= IORESOURCE_MEM,
-	}
-};
-
-static struct platform_device cap9adk_nor_flash = {
-	.name		= "physmap-flash",
-	.id		= 0,
-	.dev		= {
-				.platform_data	= &cap9adk_nor_data,
-	},
-	.resource	= nor_flash_resources,
-	.num_resources	= ARRAY_SIZE(nor_flash_resources),
-};
-
-static struct sam9_smc_config __initdata cap9adk_nor_smc_config = {
-	.ncs_read_setup		= 2,
-	.nrd_setup		= 4,
-	.ncs_write_setup	= 2,
-	.nwe_setup		= 4,
-
-	.ncs_read_pulse		= 10,
-	.nrd_pulse		= 8,
-	.ncs_write_pulse	= 10,
-	.nwe_pulse		= 8,
-
-	.read_cycle		= 16,
-	.write_cycle		= 16,
-
-	.mode			= AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE | AT91_SMC_DBW_16,
-	.tdf_cycles		= 1,
-};
-
-static __init void cap9adk_add_device_nor(void)
-{
-	unsigned long csa;
-
-	csa = at91_sys_read(AT91_MATRIX_EBICSA);
-	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
-
-	/* configure chip-select 0 (NOR) */
-	sam9_smc_configure(0, 0, &cap9adk_nor_smc_config);
-
-	platform_device_register(&cap9adk_nor_flash);
-}
-
-
-/*
- * LCD Controller
- */
-#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-static struct fb_videomode at91_tft_vga_modes[] = {
-	{
-	        .name           = "TX09D50VM1CCA @ 60",
-		.refresh	= 60,
-		.xres		= 240,		.yres		= 320,
-		.pixclock	= KHZ2PICOS(4965),
-
-		.left_margin	= 1,		.right_margin	= 33,
-		.upper_margin	= 1,		.lower_margin	= 0,
-		.hsync_len	= 5,		.vsync_len	= 1,
-
-		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-		.vmode		= FB_VMODE_NONINTERLACED,
-	},
-};
-
-static struct fb_monspecs at91fb_default_monspecs = {
-	.manufacturer	= "HIT",
-	.monitor        = "TX09D70VM1CCA",
-
-	.modedb		= at91_tft_vga_modes,
-	.modedb_len	= ARRAY_SIZE(at91_tft_vga_modes),
-	.hfmin		= 15000,
-	.hfmax		= 64000,
-	.vfmin		= 50,
-	.vfmax		= 150,
-};
-
-#define AT91CAP9_DEFAULT_LCDCON2 	(ATMEL_LCDC_MEMOR_LITTLE \
-					| ATMEL_LCDC_DISTYPE_TFT    \
-					| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
-
-static void at91_lcdc_power_control(int on)
-{
-	if (on)
-		at91_set_gpio_value(AT91_PIN_PC0, 0);	/* power up */
-	else
-		at91_set_gpio_value(AT91_PIN_PC0, 1);	/* power down */
-}
-
-/* Driver datas */
-static struct atmel_lcdfb_info __initdata cap9adk_lcdc_data = {
-	.default_bpp			= 16,
-	.default_dmacon			= ATMEL_LCDC_DMAEN,
-	.default_lcdcon2		= AT91CAP9_DEFAULT_LCDCON2,
-	.default_monspecs		= &at91fb_default_monspecs,
-	.atmel_lcdfb_power_control	= at91_lcdc_power_control,
-	.guard_time			= 1,
-};
-
-#else
-static struct atmel_lcdfb_info __initdata cap9adk_lcdc_data;
-#endif
-
-
-/*
- * AC97
- */
-static struct ac97c_platform_data cap9adk_ac97_data = {
-	.reset_pin	= -EINVAL,
-};
-
-
-static void __init cap9adk_board_init(void)
-{
-	/* Serial */
-	at91_add_device_serial();
-	/* USB Host */
-	at91_add_device_usbh(&cap9adk_usbh_data);
-	/* USB HS */
-	at91_add_device_usba(&cap9adk_usba_udc_data);
-	/* SPI */
-	at91_add_device_spi(cap9adk_spi_devices, ARRAY_SIZE(cap9adk_spi_devices));
-	/* Touchscreen */
-	cap9adk_add_device_ts();
-	/* MMC */
-	at91_add_device_mmc(1, &cap9adk_mmc_data);
-	/* Ethernet */
-	at91_add_device_eth(&cap9adk_macb_data);
-	/* NAND */
-	cap9adk_add_device_nand();
-	/* NOR Flash */
-	cap9adk_add_device_nor();
-	/* I2C */
-	at91_add_device_i2c(NULL, 0);
-	/* LCD Controller */
-	at91_add_device_lcdc(&cap9adk_lcdc_data);
-	/* AC97 */
-	at91_add_device_ac97(&cap9adk_ac97_data);
-}
-
-MACHINE_START(AT91CAP9ADK, "Atmel AT91CAP9A-DK")
-	/* Maintainer: Stelian Pop <stelian.pop@leadtechdesign.com> */
-	.timer		= &at91sam926x_timer,
-	.map_io		= at91_map_io,
-	.init_early	= cap9adk_init_early,
-	.init_irq	= at91_init_irq_default,
-	.init_machine	= cap9adk_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
index 9ab3d1e..5f3680e 100644
--- a/arch/arm/mach-at91/board-cpu9krea.c
+++ b/arch/arm/mach-at91/board-cpu9krea.c
@@ -43,6 +43,7 @@
 #include <mach/board.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91sam9260_matrix.h>
+#include <mach/at91_matrix.h>
 
 #include "sam9_smc.h"
 #include "generic.h"
@@ -116,6 +117,7 @@
 	.enable_pin	= AT91_PIN_PC14,
 	.bus_width_16	= 0,
 	.det_pin	= -EINVAL,
+	.ecc_mode	= NAND_ECC_SOFT,
 };
 
 #ifdef CONFIG_MACH_CPU9260
@@ -238,8 +240,8 @@
 {
 	unsigned long csa;
 
-	csa = at91_sys_read(AT91_MATRIX_EBICSA);
-	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_VDDIOMSEL_3_3V);
+	csa = at91_matrix_read(AT91_MATRIX_EBICSA);
+	at91_matrix_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_VDDIOMSEL_3_3V);
 
 	/* configure chip-select 0 (NOR) */
 	sam9_smc_configure(0, 0, &cpu9krea_nor_smc_config);
diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
index 368e142..e094cc8 100644
--- a/arch/arm/mach-at91/board-cpuat91.c
+++ b/arch/arm/mach-at91/board-cpuat91.c
@@ -38,6 +38,7 @@
 
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 #include <mach/cpu.h>
 
 #include "generic.h"
diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
index bb6b434..c18d4d3 100644
--- a/arch/arm/mach-at91/board-dt.c
+++ b/arch/arm/mach-at91/board-dt.c
@@ -15,14 +15,11 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/gpio.h>
-#include <linux/irqdomain.h>
+#include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 
-#include <mach/hardware.h>
 #include <mach/board.h>
-#include <mach/system_rev.h>
-#include <mach/at91sam9_smc.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
@@ -30,85 +27,30 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
-#include "sam9_smc.h"
 #include "generic.h"
 
 
-static void __init ek_init_early(void)
-{
-	/* Initialize processor: 12.000 MHz crystal */
-	at91_initialize(12000000);
+static const struct of_device_id irq_of_match[] __initconst = {
 
-	/* DGBU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
-}
-
-/* det_pin is not connected */
-static struct atmel_nand_data __initdata ek_nand_data = {
-	.ale		= 21,
-	.cle		= 22,
-	.det_pin	= -EINVAL,
-	.rdy_pin	= AT91_PIN_PC8,
-	.enable_pin	= AT91_PIN_PC14,
-};
-
-static struct sam9_smc_config __initdata ek_nand_smc_config = {
-	.ncs_read_setup		= 0,
-	.nrd_setup		= 2,
-	.ncs_write_setup	= 0,
-	.nwe_setup		= 2,
-
-	.ncs_read_pulse		= 4,
-	.nrd_pulse		= 4,
-	.ncs_write_pulse	= 4,
-	.nwe_pulse		= 4,
-
-	.read_cycle		= 7,
-	.write_cycle		= 7,
-
-	.mode			= AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
-	.tdf_cycles		= 3,
-};
-
-static void __init ek_add_device_nand(void)
-{
-	ek_nand_data.bus_width_16 = board_have_nand_16bit();
-	/* setup bus-width (8 or 16) */
-	if (ek_nand_data.bus_width_16)
-		ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
-	else
-		ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
-
-	/* configure chip-select 3 (NAND) */
-	sam9_smc_configure(0, 3, &ek_nand_smc_config);
-
-	at91_add_device_nand(&ek_nand_data);
-}
-
-static const struct of_device_id aic_of_match[] __initconst = {
-	{ .compatible = "atmel,at91rm9200-aic", },
-	{},
+	{ .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init },
+	{ .compatible = "atmel,at91rm9200-gpio", .data = at91_gpio_of_irq_setup },
+	{ .compatible = "atmel,at91sam9x5-gpio", .data = at91_gpio_of_irq_setup },
+	{ /*sentinel*/ }
 };
 
 static void __init at91_dt_init_irq(void)
 {
-	irq_domain_generate_simple(aic_of_match, 0xfffff000, 0);
-	at91_init_irq_default();
+	of_irq_init(irq_of_match);
 }
 
 static void __init at91_dt_device_init(void)
 {
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-
-	/* NAND */
-	ek_add_device_nand();
 }
 
 static const char *at91_dt_board_compat[] __initdata = {
 	"atmel,at91sam9m10g45ek",
+	"atmel,at91sam9x5ek",
 	"calao,usb-a9g20",
 	NULL
 };
@@ -117,7 +59,7 @@
 	/* Maintainer: Atmel */
 	.timer		= &at91sam926x_timer,
 	.map_io		= at91_map_io,
-	.init_early	= ek_init_early,
+	.init_early	= at91_dt_initialize,
 	.init_irq	= at91_dt_init_irq,
 	.init_machine	= at91_dt_device_init,
 	.dt_compat	= at91_dt_board_compat,
diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
index 07ef35b..f23aabe 100644
--- a/arch/arm/mach-at91/board-eco920.c
+++ b/arch/arm/mach-at91/board-eco920.c
@@ -26,6 +26,7 @@
 
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 #include <mach/cpu.h>
 
 #include "generic.h"
@@ -110,7 +111,7 @@
 	at91_add_device_mmc(0, &eco920_mmc_data);
 	platform_device_register(&eco920_flash);
 
-	at91_sys_write(AT91_SMC_CSR(7),	AT91_SMC_RWHOLD_(1)
+	at91_ramc_write(0, AT91_SMC_CSR(7),	AT91_SMC_RWHOLD_(1)
 				| AT91_SMC_RWSETUP_(1)
 				| AT91_SMC_DBW_8
 				| AT91_SMC_WSEN
@@ -122,7 +123,7 @@
 	at91_set_deglitch(AT91_PIN_PA23, 1);
 
 /* Initialization of the Static Memory Controller for Chip Select 3 */
-	at91_sys_write(AT91_SMC_CSR(3),
+	at91_ramc_write(0, AT91_SMC_CSR(3),
 		AT91_SMC_DBW_16  |	/* 16 bit */
 		AT91_SMC_WSEN    |
 		AT91_SMC_NWS_(5) |	/* wait states */
diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
index eec02cd..1815152 100644
--- a/arch/arm/mach-at91/board-flexibity.c
+++ b/arch/arm/mach-at91/board-flexibity.c
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/mach-at91/board-flexibity.c
  *
- *  Copyright (C) 2010 Flexibity
+ *  Copyright (C) 2010-2011 Flexibity
  *  Copyright (C) 2005 SAN People
  *  Copyright (C) 2006 Atmel
  *
@@ -62,6 +62,13 @@
 	.pullup_pin	= -EINVAL,		/* pull-up driven by UDC */
 };
 
+/* I2C devices */
+static struct i2c_board_info __initdata flexibity_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("ds1307", 0x68),
+	},
+};
+
 /* SPI devices */
 static struct spi_board_info flexibity_spi_devices[] = {
 	{	/* DataFlash chip */
@@ -141,6 +148,9 @@
 	at91_add_device_usbh(&flexibity_usbh_data);
 	/* USB Device */
 	at91_add_device_udc(&flexibity_udc_data);
+	/* I2C */
+	at91_add_device_i2c(flexibity_i2c_devices,
+		ARRAY_SIZE(flexibity_i2c_devices));
 	/* SPI */
 	at91_add_device_spi(flexibity_spi_devices,
 		ARRAY_SIZE(flexibity_spi_devices));
diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
index d75a4a2..59b92aa 100644
--- a/arch/arm/mach-at91/board-kb9202.c
+++ b/arch/arm/mach-at91/board-kb9202.c
@@ -38,6 +38,7 @@
 #include <mach/board.h>
 #include <mach/cpu.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 
 #include "generic.h"
 
@@ -107,6 +108,7 @@
 	.det_pin	= -EINVAL,
 	.rdy_pin	= AT91_PIN_PC29,
 	.enable_pin	= AT91_PIN_PC28,
+	.ecc_mode	= NAND_ECC_SOFT,
 	.parts		= kb9202_nand_partition,
 	.num_parts	= ARRAY_SIZE(kb9202_nand_partition),
 };
diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
index 3f8617c..57d5f6a 100644
--- a/arch/arm/mach-at91/board-neocore926.c
+++ b/arch/arm/mach-at91/board-neocore926.c
@@ -190,6 +190,7 @@
 	.rdy_pin		= AT91_PIN_PB19,
 	.rdy_pin_active_low	= 1,
 	.enable_pin		= AT91_PIN_PD15,
+	.ecc_mode		= NAND_ECC_SOFT,
 	.parts			= neocore926_nand_partition,
 	.num_parts		= ARRAY_SIZE(neocore926_nand_partition),
 	.det_pin		= -EINVAL,
diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
index ab024fa..59e35dd 100644
--- a/arch/arm/mach-at91/board-picotux200.c
+++ b/arch/arm/mach-at91/board-picotux200.c
@@ -39,6 +39,7 @@
 
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 
 #include "generic.h"
 
diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
index e029d22..b6ed5ed 100644
--- a/arch/arm/mach-at91/board-qil-a9260.c
+++ b/arch/arm/mach-at91/board-qil-a9260.c
@@ -138,6 +138,8 @@
 	.det_pin	= -EINVAL,
 	.rdy_pin	= AT91_PIN_PC13,
 	.enable_pin	= AT91_PIN_PC14,
+	.ecc_mode	= NAND_ECC_SOFT,
+	.on_flash_bbt	= 1,
 	.parts		= ek_nand_partition,
 	.num_parts	= ARRAY_SIZE(ek_nand_partition),
 };
diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
index 782f379..01332aa 100644
--- a/arch/arm/mach-at91/board-rm9200dk.c
+++ b/arch/arm/mach-at91/board-rm9200dk.c
@@ -41,6 +41,7 @@
 #include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 
 #include "generic.h"
 
@@ -149,6 +150,8 @@
 	.det_pin	= AT91_PIN_PB1,
 	.rdy_pin	= AT91_PIN_PC2,
 	.enable_pin	= -EINVAL,
+	.ecc_mode	= NAND_ECC_SOFT,
+	.on_flash_bbt	= 1,
 	.parts		= dk_nand_partition,
 	.num_parts	= ARRAY_SIZE(dk_nand_partition),
 };
diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
index ef7c12a..11cbaa8 100644
--- a/arch/arm/mach-at91/board-rm9200ek.c
+++ b/arch/arm/mach-at91/board-rm9200ek.c
@@ -41,6 +41,7 @@
 #include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 
 #include "generic.h"
 
diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
index 84bce58..e8b116b 100644
--- a/arch/arm/mach-at91/board-sam9-l9260.c
+++ b/arch/arm/mach-at91/board-sam9-l9260.c
@@ -139,6 +139,7 @@
 	.det_pin	= -EINVAL,
 	.rdy_pin	= AT91_PIN_PC13,
 	.enable_pin	= AT91_PIN_PC14,
+	.ecc_mode	= NAND_ECC_SOFT,
 	.parts		= ek_nand_partition,
 	.num_parts	= ARRAY_SIZE(ek_nand_partition),
 };
diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
index be8233b..d5aec55 100644
--- a/arch/arm/mach-at91/board-sam9260ek.c
+++ b/arch/arm/mach-at91/board-sam9260ek.c
@@ -181,6 +181,8 @@
 	.det_pin	= -EINVAL,
 	.rdy_pin	= AT91_PIN_PC13,
 	.enable_pin	= AT91_PIN_PC14,
+	.ecc_mode	= NAND_ECC_SOFT,
+	.on_flash_bbt	= 1,
 	.parts		= ek_nand_partition,
 	.num_parts	= ARRAY_SIZE(ek_nand_partition),
 };
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index 4089507..c3f9944 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -187,6 +187,8 @@
 	.det_pin	= -EINVAL,
 	.rdy_pin	= AT91_PIN_PC15,
 	.enable_pin	= AT91_PIN_PC14,
+	.ecc_mode	= NAND_ECC_SOFT,
+	.on_flash_bbt	= 1,
 	.parts		= ek_nand_partition,
 	.num_parts	= ARRAY_SIZE(ek_nand_partition),
 };
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index 29f6605..2ffe50f 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -74,6 +74,7 @@
 static struct at91_usbh_data __initdata ek_usbh_data = {
 	.ports		= 2,
 	.vbus_pin	= { AT91_PIN_PA24, AT91_PIN_PA21 },
+	.vbus_pin_active_low = {1, 1},
 	.overcurrent_pin= {-EINVAL, -EINVAL},
 };
 
@@ -187,6 +188,8 @@
 	.det_pin	= -EINVAL,
 	.rdy_pin	= AT91_PIN_PA22,
 	.enable_pin	= AT91_PIN_PD15,
+	.ecc_mode	= NAND_ECC_SOFT,
+	.on_flash_bbt	= 1,
 	.parts		= ek_nand_partition,
 	.num_parts	= ARRAY_SIZE(ek_nand_partition),
 };
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
index 843d628..8923ec9 100644
--- a/arch/arm/mach-at91/board-sam9g20ek.c
+++ b/arch/arm/mach-at91/board-sam9g20ek.c
@@ -166,6 +166,8 @@
 	.rdy_pin	= AT91_PIN_PC13,
 	.enable_pin	= AT91_PIN_PC14,
 	.det_pin	= -EINVAL,
+	.ecc_mode	= NAND_ECC_SOFT,
+	.on_flash_bbt	= 1,
 	.parts		= ek_nand_partition,
 	.num_parts	= ARRAY_SIZE(ek_nand_partition),
 };
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
index ea0d1b9..c88e908 100644
--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
+++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
@@ -24,11 +24,13 @@
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 #include <linux/leds.h>
-#include <linux/clk.h>
 #include <linux/atmel-mci.h>
+#include <linux/delay.h>
 
 #include <mach/hardware.h>
 #include <video/atmel_lcdc.h>
+#include <media/soc_camera.h>
+#include <media/atmel-isi.h>
 
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -69,6 +71,7 @@
 static struct at91_usbh_data __initdata ek_usbh_hs_data = {
 	.ports		= 2,
 	.vbus_pin	= {AT91_PIN_PD1, AT91_PIN_PD3},
+	.vbus_pin_active_low = {1, 1},
 	.overcurrent_pin= {-EINVAL, -EINVAL},
 };
 
@@ -146,6 +149,8 @@
 	.rdy_pin	= AT91_PIN_PC8,
 	.enable_pin	= AT91_PIN_PC14,
 	.det_pin	= -EINVAL,
+	.ecc_mode	= NAND_ECC_SOFT,
+	.on_flash_bbt	= 1,
 	.parts		= ek_nand_partition,
 	.num_parts	= ARRAY_SIZE(ek_nand_partition),
 };
@@ -185,6 +190,71 @@
 
 
 /*
+ *  ISI
+ */
+static struct isi_platform_data __initdata isi_data = {
+	.frate			= ISI_CFG1_FRATE_CAPTURE_ALL,
+	/* to use codec and preview path simultaneously */
+	.full_mode		= 1,
+	.data_width_flags	= ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10,
+	/* ISI_MCK is provided by programmable clock or external clock */
+	.mck_hz			= 25000000,
+};
+
+
+/*
+ * soc-camera OV2640
+ */
+#if defined(CONFIG_SOC_CAMERA_OV2640) || \
+	defined(CONFIG_SOC_CAMERA_OV2640_MODULE)
+static unsigned long isi_camera_query_bus_param(struct soc_camera_link *link)
+{
+	/* ISI board for ek using default 8-bits connection */
+	return SOCAM_DATAWIDTH_8;
+}
+
+static int i2c_camera_power(struct device *dev, int on)
+{
+	/* enable or disable the camera */
+	pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE");
+	at91_set_gpio_output(AT91_PIN_PD13, !on);
+
+	if (!on)
+		goto out;
+
+	/* If enabled, give a reset impulse */
+	at91_set_gpio_output(AT91_PIN_PD12, 0);
+	msleep(20);
+	at91_set_gpio_output(AT91_PIN_PD12, 1);
+	msleep(100);
+
+out:
+	return 0;
+}
+
+static struct i2c_board_info i2c_camera = {
+	I2C_BOARD_INFO("ov2640", 0x30),
+};
+
+static struct soc_camera_link iclink_ov2640 = {
+	.bus_id			= 0,
+	.board_info		= &i2c_camera,
+	.i2c_adapter_id		= 0,
+	.power			= i2c_camera_power,
+	.query_bus_param	= isi_camera_query_bus_param,
+};
+
+static struct platform_device isi_ov2640 = {
+	.name	= "soc-camera-pdrv",
+	.id	= 0,
+	.dev	= {
+		.platform_data = &iclink_ov2640,
+	},
+};
+#endif
+
+
+/*
  * LCD Controller
  */
 #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
@@ -377,7 +447,12 @@
 #endif
 };
 
-
+static struct platform_device *devices[] __initdata = {
+#if defined(CONFIG_SOC_CAMERA_OV2640) || \
+	defined(CONFIG_SOC_CAMERA_OV2640_MODULE)
+	&isi_ov2640,
+#endif
+};
 
 static void __init ek_board_init(void)
 {
@@ -399,6 +474,8 @@
 	ek_add_device_nand();
 	/* I2C */
 	at91_add_device_i2c(0, NULL, 0);
+	/* ISI, using programmable clock as ISI_MCK */
+	at91_add_device_isi(&isi_data, true);
 	/* LCD Controller */
 	at91_add_device_lcdc(&ek_lcdc_data);
 	/* Touch Screen */
@@ -410,6 +487,8 @@
 	/* LEDs */
 	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
 	at91_pwm_leds(ek_pwm_led, ARRAY_SIZE(ek_pwm_led));
+	/* Other platform devices */
+	platform_add_devices(devices, ARRAY_SIZE(devices));
 }
 
 MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
index c1366d0..b109ce2 100644
--- a/arch/arm/mach-at91/board-sam9rlek.c
+++ b/arch/arm/mach-at91/board-sam9rlek.c
@@ -94,6 +94,8 @@
 	.det_pin	= -EINVAL,
 	.rdy_pin	= AT91_PIN_PD17,
 	.enable_pin	= AT91_PIN_PB6,
+	.ecc_mode	= NAND_ECC_SOFT,
+	.on_flash_bbt	= 1,
 	.parts		= ek_nand_partition,
 	.num_parts	= ARRAY_SIZE(ek_nand_partition),
 };
diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c
index 4770db0..ebc9d01 100644
--- a/arch/arm/mach-at91/board-snapper9260.c
+++ b/arch/arm/mach-at91/board-snapper9260.c
@@ -110,6 +110,7 @@
 	.bus_width_16	= 0,
 	.enable_pin	= -EINVAL,
 	.det_pin	= -EINVAL,
+	.ecc_mode	= NAND_ECC_SOFT,
 };
 
 static struct sam9_smc_config __initdata snapper9260_nand_smc_config = {
@@ -145,11 +146,11 @@
 		/* Audio codec */
 		I2C_BOARD_INFO("tlv320aic23", 0x1a),
 	},
-	{
+};
+
+static struct i2c_board_info __initdata snapper9260_i2c_isl1208 = {
 		/* RTC */
 		I2C_BOARD_INFO("isl1208", 0x6f),
-		.irq = gpio_to_irq(AT91_PIN_PA31),
-	},
 };
 
 static void __init snapper9260_add_device_nand(void)
@@ -163,6 +164,10 @@
 {
 	at91_add_device_i2c(snapper9260_i2c_devices,
 			    ARRAY_SIZE(snapper9260_i2c_devices));
+
+	snapper9260_i2c_isl1208.irq = gpio_to_irq(AT91_PIN_PA31);
+	i2c_register_board_info(0, &snapper9260_i2c_isl1208, 1);
+
 	at91_add_device_serial();
 	at91_add_device_usbh(&snapper9260_usbh_data);
 	at91_add_device_udc(&snapper9260_udc_data);
diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
index 72eb3b4..7640049 100644
--- a/arch/arm/mach-at91/board-stamp9g20.c
+++ b/arch/arm/mach-at91/board-stamp9g20.c
@@ -86,6 +86,7 @@
 	.enable_pin	= AT91_PIN_PC14,
 	.bus_width_16	= 0,
 	.det_pin	= -EINVAL,
+	.ecc_mode	= NAND_ECC_SOFT,
 };
 
 static struct sam9_smc_config __initdata nand_smc_config = {
diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c
index 26c36fc..b7483a3 100644
--- a/arch/arm/mach-at91/board-usb-a926x.c
+++ b/arch/arm/mach-at91/board-usb-a926x.c
@@ -198,6 +198,8 @@
 	.det_pin	= -EINVAL,
 	.rdy_pin	= AT91_PIN_PA22,
 	.enable_pin	= AT91_PIN_PD15,
+	.ecc_mode	= NAND_ECC_SOFT,
+	.on_flash_bbt	= 1,
 	.parts		= ek_nand_partition,
 	.num_parts	= ARRAY_SIZE(ek_nand_partition),
 };
diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
index bbd553e..38dd279 100644
--- a/arch/arm/mach-at91/board-yl-9200.c
+++ b/arch/arm/mach-at91/board-yl-9200.c
@@ -45,6 +45,7 @@
 #include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 #include <mach/cpu.h>
 
 #include "generic.h"
@@ -181,6 +182,7 @@
 	.det_pin	= -EINVAL,
 	.rdy_pin	= AT91_PIN_PC14,	/* R/!B (Sheet10) */
 	.enable_pin	= AT91_PIN_PC15,	/* !CE  (Sheet10) */
+	.ecc_mode	= NAND_ECC_SOFT,
 	.parts		= yl9200_nand_partition,
 	.num_parts	= ARRAY_SIZE(yl9200_nand_partition),
 };
@@ -393,7 +395,7 @@
 	at91_set_A_periph(AT91_PIN_PC6, 0);
 
 	/* Initialization of the Static Memory Controller for Chip Select 2 */
-	at91_sys_write(AT91_SMC_CSR(2), AT91_SMC_DBW_16		/* 16 bit */
+	at91_ramc_write(0, AT91_SMC_CSR(2), AT91_SMC_DBW_16		/* 16 bit */
 			| AT91_SMC_WSEN | AT91_SMC_NWS_(0x4)	/* wait states */
 			| AT91_SMC_TDF_(0x100)			/* float time */
 	);
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
index 61873f3..a0f4d74 100644
--- a/arch/arm/mach-at91/clock.c
+++ b/arch/arm/mach-at91/clock.c
@@ -23,14 +23,18 @@
 #include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/of_address.h>
 
 #include <mach/hardware.h>
 #include <mach/at91_pmc.h>
 #include <mach/cpu.h>
 
+#include <asm/proc-fns.h>
+
 #include "clock.h"
 #include "generic.h"
 
+void __iomem *at91_pmc_base;
 
 /*
  * There's a lot more which can be done with clocks, including cpufreq
@@ -47,26 +51,38 @@
 /*
  * Chips have some kind of clocks : group them by functionality
  */
-#define cpu_has_utmi()		(  cpu_is_at91cap9() \
-				|| cpu_is_at91sam9rl() \
-				|| cpu_is_at91sam9g45())
+#define cpu_has_utmi()		(  cpu_is_at91sam9rl() \
+				|| cpu_is_at91sam9g45() \
+				|| cpu_is_at91sam9x5())
 
 #define cpu_has_800M_plla()	(  cpu_is_at91sam9g20() \
-				|| cpu_is_at91sam9g45())
+				|| cpu_is_at91sam9g45() \
+				|| cpu_is_at91sam9x5())
 
 #define cpu_has_300M_plla()	(cpu_is_at91sam9g10())
 
 #define cpu_has_pllb()		(!(cpu_is_at91sam9rl() \
-				|| cpu_is_at91sam9g45()))
+				|| cpu_is_at91sam9g45() \
+				|| cpu_is_at91sam9x5()))
 
-#define cpu_has_upll()		(cpu_is_at91sam9g45())
+#define cpu_has_upll()		(cpu_is_at91sam9g45() \
+				|| cpu_is_at91sam9x5())
 
 /* USB host HS & FS */
 #define cpu_has_uhp()		(!cpu_is_at91sam9rl())
 
 /* USB device FS only */
 #define cpu_has_udpfs()		(!(cpu_is_at91sam9rl() \
-				|| cpu_is_at91sam9g45()))
+				|| cpu_is_at91sam9g45() \
+				|| cpu_is_at91sam9x5()))
+
+#define cpu_has_plladiv2()	(cpu_is_at91sam9g45() \
+				|| cpu_is_at91sam9x5())
+
+#define cpu_has_mdiv3()		(cpu_is_at91sam9g45() \
+				|| cpu_is_at91sam9x5())
+
+#define cpu_has_alt_prescaler()	(cpu_is_at91sam9x5())
 
 static LIST_HEAD(clocks);
 static DEFINE_SPINLOCK(clk_lock);
@@ -111,11 +127,11 @@
 		value = 0;
 
 	// REVISIT: Add work-around for AT91RM9200 Errata #26 ?
-	at91_sys_write(AT91_CKGR_PLLBR, value);
+	at91_pmc_write(AT91_CKGR_PLLBR, value);
 
 	do {
 		cpu_relax();
-	} while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != is_on);
+	} while ((at91_pmc_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != is_on);
 }
 
 static struct clk pllb = {
@@ -130,31 +146,24 @@
 static void pmc_sys_mode(struct clk *clk, int is_on)
 {
 	if (is_on)
-		at91_sys_write(AT91_PMC_SCER, clk->pmc_mask);
+		at91_pmc_write(AT91_PMC_SCER, clk->pmc_mask);
 	else
-		at91_sys_write(AT91_PMC_SCDR, clk->pmc_mask);
+		at91_pmc_write(AT91_PMC_SCDR, clk->pmc_mask);
 }
 
 static void pmc_uckr_mode(struct clk *clk, int is_on)
 {
-	unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR);
-
-	if (cpu_is_at91sam9g45()) {
-		if (is_on)
-			uckr |= AT91_PMC_BIASEN;
-		else
-			uckr &= ~AT91_PMC_BIASEN;
-	}
+	unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
 
 	if (is_on) {
 		is_on = AT91_PMC_LOCKU;
-		at91_sys_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask);
+		at91_pmc_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask);
 	} else
-		at91_sys_write(AT91_CKGR_UCKR, uckr & ~(clk->pmc_mask));
+		at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(clk->pmc_mask));
 
 	do {
 		cpu_relax();
-	} while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKU) != is_on);
+	} while ((at91_pmc_read(AT91_PMC_SR) & AT91_PMC_LOCKU) != is_on);
 }
 
 /* USB function clocks (PLLB must be 48 MHz) */
@@ -190,9 +199,9 @@
 static void pmc_periph_mode(struct clk *clk, int is_on)
 {
 	if (is_on)
-		at91_sys_write(AT91_PMC_PCER, clk->pmc_mask);
+		at91_pmc_write(AT91_PMC_PCER, clk->pmc_mask);
 	else
-		at91_sys_write(AT91_PMC_PCDR, clk->pmc_mask);
+		at91_pmc_write(AT91_PMC_PCDR, clk->pmc_mask);
 }
 
 static struct clk __init *at91_css_to_clk(unsigned long css)
@@ -210,11 +219,24 @@
 				return &utmi_clk;
 			else if (cpu_has_pllb())
 				return &pllb;
+			break;
+		/* alternate PMC: can use master clock */
+		case AT91_PMC_CSS_MASTER:
+			return &mck;
 	}
 
 	return NULL;
 }
 
+static int pmc_prescaler_divider(u32 reg)
+{
+	if (cpu_has_alt_prescaler()) {
+		return 1 << ((reg & AT91_PMC_ALT_PRES) >> PMC_ALT_PRES_OFFSET);
+	} else {
+		return 1 << ((reg & AT91_PMC_PRES) >> PMC_PRES_OFFSET);
+	}
+}
+
 static void __clk_enable(struct clk *clk)
 {
 	if (clk->parent)
@@ -316,12 +338,22 @@
 {
 	unsigned long	flags;
 	unsigned	prescale;
+	unsigned long	prescale_offset, css_mask;
 	unsigned long	actual;
 
 	if (!clk_is_programmable(clk))
 		return -EINVAL;
 	if (clk->users)
 		return -EBUSY;
+
+	if (cpu_has_alt_prescaler()) {
+		prescale_offset = PMC_ALT_PRES_OFFSET;
+		css_mask = AT91_PMC_ALT_PCKR_CSS;
+	} else {
+		prescale_offset = PMC_PRES_OFFSET;
+		css_mask = AT91_PMC_CSS;
+	}
+
 	spin_lock_irqsave(&clk_lock, flags);
 
 	actual = clk->parent->rate_hz;
@@ -329,10 +361,10 @@
 		if (actual && actual <= rate) {
 			u32	pckr;
 
-			pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
-			pckr &= AT91_PMC_CSS;	/* clock selection */
-			pckr |= prescale << 2;
-			at91_sys_write(AT91_PMC_PCKR(clk->id), pckr);
+			pckr = at91_pmc_read(AT91_PMC_PCKR(clk->id));
+			pckr &= css_mask;	/* keep clock selection */
+			pckr |= prescale << prescale_offset;
+			at91_pmc_write(AT91_PMC_PCKR(clk->id), pckr);
 			clk->rate_hz = actual;
 			break;
 		}
@@ -366,7 +398,7 @@
 
 	clk->rate_hz = parent->rate_hz;
 	clk->parent = parent;
-	at91_sys_write(AT91_PMC_PCKR(clk->id), parent->id);
+	at91_pmc_write(AT91_PMC_PCKR(clk->id), parent->id);
 
 	spin_unlock_irqrestore(&clk_lock, flags);
 	return 0;
@@ -378,11 +410,17 @@
 {
 	struct clk	*parent;
 	u32		pckr;
+	unsigned int	css_mask;
 
-	pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
-	parent = at91_css_to_clk(pckr & AT91_PMC_CSS);
+	if (cpu_has_alt_prescaler())
+		css_mask = AT91_PMC_ALT_PCKR_CSS;
+	else
+		css_mask = AT91_PMC_CSS;
+
+	pckr = at91_pmc_read(AT91_PMC_PCKR(clk->id));
+	parent = at91_css_to_clk(pckr & css_mask);
 	clk->parent = parent;
-	clk->rate_hz = parent->rate_hz / (1 << ((pckr & AT91_PMC_PRES) >> 2));
+	clk->rate_hz = parent->rate_hz / pmc_prescaler_divider(pckr);
 }
 
 #endif	/* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
@@ -396,19 +434,24 @@
 	u32		scsr, pcsr, uckr = 0, sr;
 	struct clk	*clk;
 
-	seq_printf(s, "SCSR = %8x\n", scsr = at91_sys_read(AT91_PMC_SCSR));
-	seq_printf(s, "PCSR = %8x\n", pcsr = at91_sys_read(AT91_PMC_PCSR));
-	seq_printf(s, "MOR  = %8x\n", at91_sys_read(AT91_CKGR_MOR));
-	seq_printf(s, "MCFR = %8x\n", at91_sys_read(AT91_CKGR_MCFR));
-	seq_printf(s, "PLLA = %8x\n", at91_sys_read(AT91_CKGR_PLLAR));
+	scsr = at91_pmc_read(AT91_PMC_SCSR);
+	pcsr = at91_pmc_read(AT91_PMC_PCSR);
+	sr = at91_pmc_read(AT91_PMC_SR);
+	seq_printf(s, "SCSR = %8x\n", scsr);
+	seq_printf(s, "PCSR = %8x\n", pcsr);
+	seq_printf(s, "MOR  = %8x\n", at91_pmc_read(AT91_CKGR_MOR));
+	seq_printf(s, "MCFR = %8x\n", at91_pmc_read(AT91_CKGR_MCFR));
+	seq_printf(s, "PLLA = %8x\n", at91_pmc_read(AT91_CKGR_PLLAR));
 	if (cpu_has_pllb())
-		seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR));
-	if (cpu_has_utmi())
-		seq_printf(s, "UCKR = %8x\n", uckr = at91_sys_read(AT91_CKGR_UCKR));
-	seq_printf(s, "MCKR = %8x\n", at91_sys_read(AT91_PMC_MCKR));
+		seq_printf(s, "PLLB = %8x\n", at91_pmc_read(AT91_CKGR_PLLBR));
+	if (cpu_has_utmi()) {
+		uckr = at91_pmc_read(AT91_CKGR_UCKR);
+		seq_printf(s, "UCKR = %8x\n", uckr);
+	}
+	seq_printf(s, "MCKR = %8x\n", at91_pmc_read(AT91_PMC_MCKR));
 	if (cpu_has_upll())
-		seq_printf(s, "USB  = %8x\n", at91_sys_read(AT91_PMC_USB));
-	seq_printf(s, "SR   = %8x\n", sr = at91_sys_read(AT91_PMC_SR));
+		seq_printf(s, "USB  = %8x\n", at91_pmc_read(AT91_PMC_USB));
+	seq_printf(s, "SR   = %8x\n", sr);
 
 	seq_printf(s, "\n");
 
@@ -596,16 +639,14 @@
 	if (cpu_is_at91rm9200()) {
 		uhpck.pmc_mask = AT91RM9200_PMC_UHP;
 		udpck.pmc_mask = AT91RM9200_PMC_UDP;
-		at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP);
+		at91_pmc_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP);
 	} else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() ||
 		   cpu_is_at91sam9263() || cpu_is_at91sam9g20() ||
 		   cpu_is_at91sam9g10()) {
 		uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
 		udpck.pmc_mask = AT91SAM926x_PMC_UDP;
-	} else if (cpu_is_at91cap9()) {
-		uhpck.pmc_mask = AT91CAP9_PMC_UHP;
 	}
-	at91_sys_write(AT91_CKGR_PLLBR, 0);
+	at91_pmc_write(AT91_CKGR_PLLBR, 0);
 
 	udpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init);
 	uhpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init);
@@ -622,16 +663,16 @@
 	/* Setup divider by 10 to reach 48 MHz */
 	usbr |= ((10 - 1) << 8) & AT91_PMC_OHCIUSBDIV;
 
-	at91_sys_write(AT91_PMC_USB, usbr);
+	at91_pmc_write(AT91_PMC_USB, usbr);
 
 	/* Now set uhpck values */
 	uhpck.parent = &utmi_clk;
 	uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
 	uhpck.rate_hz = utmi_clk.rate_hz;
-	uhpck.rate_hz /= 1 + ((at91_sys_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8);
+	uhpck.rate_hz /= 1 + ((at91_pmc_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8);
 }
 
-int __init at91_clock_init(unsigned long main_clock)
+static int __init at91_pmc_init(unsigned long main_clock)
 {
 	unsigned tmp, freq, mckr;
 	int i;
@@ -645,14 +686,14 @@
 	 */
 	if (!main_clock) {
 		do {
-			tmp = at91_sys_read(AT91_CKGR_MCFR);
+			tmp = at91_pmc_read(AT91_CKGR_MCFR);
 		} while (!(tmp & AT91_PMC_MAINRDY));
 		main_clock = (tmp & AT91_PMC_MAINF) * (AT91_SLOW_CLOCK / 16);
 	}
 	main_clk.rate_hz = main_clock;
 
 	/* report if PLLA is more than mildly overclocked */
-	plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_sys_read(AT91_CKGR_PLLAR));
+	plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_pmc_read(AT91_CKGR_PLLAR));
 	if (cpu_has_300M_plla()) {
 		if (plla.rate_hz > 300000000)
 			pll_overclock = true;
@@ -666,8 +707,8 @@
 	if (pll_overclock)
 		pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000);
 
-	if (cpu_is_at91sam9g45()) {
-		mckr = at91_sys_read(AT91_PMC_MCKR);
+	if (cpu_has_plladiv2()) {
+		mckr = at91_pmc_read(AT91_PMC_MCKR);
 		plla.rate_hz /= (1 << ((mckr & AT91_PMC_PLLADIV2) >> 12));	/* plla divisor by 2 */
 	}
 
@@ -688,6 +729,10 @@
 		 * (obtain the USB High Speed 480 MHz when input is 12 MHz)
 		 */
 		utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz;
+
+		/* UTMI bias and PLL are managed at the same time */
+		if (cpu_has_upll())
+			utmi_clk.pmc_mask |= AT91_PMC_BIASEN;
 	}
 
 	/*
@@ -703,10 +748,10 @@
 	 * MCK and CPU derive from one of those primary clocks.
 	 * For now, assume this parentage won't change.
 	 */
-	mckr = at91_sys_read(AT91_PMC_MCKR);
+	mckr = at91_pmc_read(AT91_PMC_MCKR);
 	mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS);
 	freq = mck.parent->rate_hz;
-	freq /= (1 << ((mckr & AT91_PMC_PRES) >> 2));				/* prescale */
+	freq /= pmc_prescaler_divider(mckr);					/* prescale */
 	if (cpu_is_at91rm9200()) {
 		mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8));	/* mdiv */
 	} else if (cpu_is_at91sam9g20()) {
@@ -714,13 +759,19 @@
 			freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq;	/* mdiv ; (x >> 7) = ((x >> 8) * 2) */
 		if (mckr & AT91_PMC_PDIV)
 			freq /= 2;		/* processor clock division */
-	} else if (cpu_is_at91sam9g45()) {
+	} else if (cpu_has_mdiv3()) {
 		mck.rate_hz = (mckr & AT91_PMC_MDIV) == AT91SAM9_PMC_MDIV_3 ?
 			freq / 3 : freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8));	/* mdiv */
 	} else {
 		mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8));		/* mdiv */
 	}
 
+	if (cpu_has_alt_prescaler()) {
+		/* Programmable clocks can use MCK */
+		mck.type |= CLK_TYPE_PRIMARY;
+		mck.id = 4;
+	}
+
 	/* Register the PMC's standard clocks */
 	for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++)
 		at91_clk_add(standard_pmc_clocks[i]);
@@ -748,6 +799,55 @@
 	return 0;
 }
 
+#if defined(CONFIG_OF)
+static struct of_device_id pmc_ids[] = {
+	{ .compatible = "atmel,at91rm9200-pmc" },
+	{ /*sentinel*/ }
+};
+
+static struct of_device_id osc_ids[] = {
+	{ .compatible = "atmel,osc" },
+	{ /*sentinel*/ }
+};
+
+int __init at91_dt_clock_init(void)
+{
+	struct device_node *np;
+	u32 main_clock = 0;
+
+	np = of_find_matching_node(NULL, pmc_ids);
+	if (!np)
+		panic("unable to find compatible pmc node in dtb\n");
+
+	at91_pmc_base = of_iomap(np, 0);
+	if (!at91_pmc_base)
+		panic("unable to map pmc cpu registers\n");
+
+	of_node_put(np);
+
+	/* retrieve the freqency of fixed clocks from device tree */
+	np = of_find_matching_node(NULL, osc_ids);
+	if (np) {
+		u32 rate;
+		if (!of_property_read_u32(np, "clock-frequency", &rate))
+			main_clock = rate;
+	}
+
+	of_node_put(np);
+
+	return at91_pmc_init(main_clock);
+}
+#endif
+
+int __init at91_clock_init(unsigned long main_clock)
+{
+	at91_pmc_base = ioremap(AT91_PMC, 256);
+	if (!at91_pmc_base)
+		panic("Impossible to ioremap AT91_PMC 0x%x\n", AT91_PMC);
+
+	return at91_pmc_init(main_clock);
+}
+
 /*
  * Several unused clocks may be active.  Turn them off.
  */
@@ -770,9 +870,15 @@
 		pr_debug("Clocks: disable unused %s\n", clk->name);
 	}
 
-	at91_sys_write(AT91_PMC_PCDR, pcdr);
-	at91_sys_write(AT91_PMC_SCDR, scdr);
+	at91_pmc_write(AT91_PMC_PCDR, pcdr);
+	at91_pmc_write(AT91_PMC_SCDR, scdr);
 
 	return 0;
 }
 late_initcall(at91_clock_reset);
+
+void at91sam9_idle(void)
+{
+	at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
+	cpu_do_idle();
+}
diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c
index a851e6c9..ece1f9a 100644
--- a/arch/arm/mach-at91/cpuidle.c
+++ b/arch/arm/mach-at91/cpuidle.c
@@ -17,9 +17,10 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/cpuidle.h>
-#include <asm/proc-fns.h>
 #include <linux/io.h>
 #include <linux/export.h>
+#include <asm/proc-fns.h>
+#include <asm/cpuidle.h>
 
 #include "pm.h"
 
@@ -27,66 +28,39 @@
 
 static DEFINE_PER_CPU(struct cpuidle_device, at91_cpuidle_device);
 
-static struct cpuidle_driver at91_idle_driver = {
-	.name =         "at91_idle",
-	.owner =        THIS_MODULE,
-};
-
 /* Actual code that puts the SoC in different idle states */
 static int at91_enter_idle(struct cpuidle_device *dev,
 			struct cpuidle_driver *drv,
 			       int index)
 {
-	struct timeval before, after;
-	int idle_time;
-	u32 saved_lpr;
+	at91_standby();
 
-	local_irq_disable();
-	do_gettimeofday(&before);
-	if (index == 0)
-		/* Wait for interrupt state */
-		cpu_do_idle();
-	else if (index == 1) {
-		asm("b 1f; .align 5; 1:");
-		asm("mcr p15, 0, r0, c7, c10, 4");	/* drain write buffer */
-		saved_lpr = sdram_selfrefresh_enable();
-		cpu_do_idle();
-		sdram_selfrefresh_disable(saved_lpr);
-	}
-	do_gettimeofday(&after);
-	local_irq_enable();
-	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
-			(after.tv_usec - before.tv_usec);
-
-	dev->last_residency = idle_time;
 	return index;
 }
 
+static struct cpuidle_driver at91_idle_driver = {
+	.name			= "at91_idle",
+	.owner			= THIS_MODULE,
+	.en_core_tk_irqen	= 1,
+	.states[0]		= ARM_CPUIDLE_WFI_STATE,
+	.states[1]		= {
+		.enter			= at91_enter_idle,
+		.exit_latency		= 10,
+		.target_residency	= 100000,
+		.flags			= CPUIDLE_FLAG_TIME_VALID,
+		.name			= "RAM_SR",
+		.desc			= "WFI and DDR Self Refresh",
+	},
+	.state_count = AT91_MAX_STATES,
+};
+
 /* Initialize CPU idle by registering the idle states */
 static int at91_init_cpuidle(void)
 {
 	struct cpuidle_device *device;
-	struct cpuidle_driver *driver = &at91_idle_driver;
 
 	device = &per_cpu(at91_cpuidle_device, smp_processor_id());
 	device->state_count = AT91_MAX_STATES;
-	driver->state_count = AT91_MAX_STATES;
-
-	/* Wait for interrupt state */
-	driver->states[0].enter = at91_enter_idle;
-	driver->states[0].exit_latency = 1;
-	driver->states[0].target_residency = 10000;
-	driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
-	strcpy(driver->states[0].name, "WFI");
-	strcpy(driver->states[0].desc, "Wait for interrupt");
-
-	/* Wait for interrupt and RAM self refresh state */
-	driver->states[1].enter = at91_enter_idle;
-	driver->states[1].exit_latency = 10;
-	driver->states[1].target_residency = 10000;
-	driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
-	strcpy(driver->states[1].name, "RAM_SR");
-	strcpy(driver->states[1].desc, "WFI and RAM Self Refresh");
 
 	cpuidle_register_driver(&at91_idle_driver);
 
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index 5941334..dd9b346 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clkdev.h>
+#include <linux/of.h>
 
  /* Map io */
 extern void __init at91_map_io(void);
@@ -19,15 +20,20 @@
 extern void __init at91rm9200_set_type(int type);
 extern void __init at91_initialize(unsigned long main_clock);
 extern void __init at91x40_initialize(unsigned long main_clock);
+extern void __init at91_dt_initialize(void);
 
  /* Interrupts */
 extern void __init at91_init_irq_default(void);
 extern void __init at91_init_interrupts(unsigned int priority[]);
 extern void __init at91x40_init_interrupts(unsigned int priority[]);
 extern void __init at91_aic_init(unsigned int priority[]);
+extern int  __init at91_aic_of_init(struct device_node *node,
+				    struct device_node *parent);
+
 
  /* Timer */
 struct sys_timer;
+extern void at91rm9200_ioremap_st(u32 addr);
 extern struct sys_timer at91rm9200_timer;
 extern void at91sam926x_ioremap_pit(u32 addr);
 extern struct sys_timer at91sam926x_timer;
@@ -45,9 +51,9 @@
 extern void __init at91sam9263_set_console_clock(int id);
 extern void __init at91sam9rl_set_console_clock(int id);
 extern void __init at91sam9g45_set_console_clock(int id);
-extern void __init at91cap9_set_console_clock(int id);
 #ifdef CONFIG_AT91_PMC_UNIT
 extern int __init at91_clock_init(unsigned long main_clock);
+extern int __init at91_dt_clock_init(void);
 #else
 static int inline at91_clock_init(unsigned long main_clock) { return 0; }
 #endif
@@ -57,6 +63,9 @@
 extern void at91_irq_suspend(void);
 extern void at91_irq_resume(void);
 
+/* idle */
+extern void at91sam9_idle(void);
+
 /* reset */
 extern void at91_ioremap_rstc(u32 base_addr);
 extern void at91sam9_alt_restart(char, const char *);
@@ -65,6 +74,12 @@
 /* shutdown */
 extern void at91_ioremap_shdwc(u32 base_addr);
 
+/* Matrix */
+extern void at91_ioremap_matrix(u32 base_addr);
+
+/* Ram Controler */
+extern void at91_ioremap_ramc(int id, u32 addr, u32 size);
+
  /* GPIO */
 #define AT91RM9200_PQFP		3	/* AT91RM9200 PQFP package has 3 banks */
 #define AT91RM9200_BGA		4	/* AT91RM9200 BGA package has 4 banks */
@@ -75,5 +90,7 @@
 };
 extern void __init at91_gpio_init(struct at91_gpio_bank *, int nr_banks);
 extern void __init at91_gpio_irq_setup(void);
+extern int  __init at91_gpio_of_irq_setup(struct device_node *node,
+					  struct device_node *parent);
 
 extern int at91_extern_irq;
diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
index 74d6783..325837a 100644
--- a/arch/arm/mach-at91/gpio.c
+++ b/arch/arm/mach-at91/gpio.c
@@ -11,6 +11,7 @@
 
 #include <linux/clk.h>
 #include <linux/errno.h>
+#include <linux/device.h>
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
@@ -20,6 +21,10 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/io.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
 
 #include <mach/hardware.h>
 #include <mach/at91_pio.h>
@@ -29,9 +34,12 @@
 struct at91_gpio_chip {
 	struct gpio_chip	chip;
 	struct at91_gpio_chip	*next;		/* Bank sharing same clock */
-	int			id;		/* ID of register bank */
-	void __iomem		*regbase;	/* Base of register bank */
+	int			pioc_hwirq;	/* PIO bank interrupt identifier on AIC */
+	int			pioc_virq;	/* PIO bank Linux virtual interrupt */
+	int			pioc_idx;	/* PIO bank index */
+	void __iomem		*regbase;	/* PIO bank virtual address */
 	struct clk		*clock;		/* associated clock */
+	struct irq_domain	*domain;	/* associated irq domain */
 };
 
 #define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
@@ -43,8 +51,9 @@
 					 unsigned offset, int val);
 static int at91_gpiolib_direction_input(struct gpio_chip *chip,
 					unsigned offset);
+static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
 
-#define AT91_GPIO_CHIP(name, base_gpio, nr_gpio)			\
+#define AT91_GPIO_CHIP(name, nr_gpio)					\
 	{								\
 		.chip = {						\
 			.label		  = name,			\
@@ -53,20 +62,28 @@
 			.get		  = at91_gpiolib_get,		\
 			.set		  = at91_gpiolib_set,		\
 			.dbg_show	  = at91_gpiolib_dbg_show,	\
-			.base		  = base_gpio,			\
+			.to_irq		  = at91_gpiolib_to_irq,	\
 			.ngpio		  = nr_gpio,			\
 		},							\
 	}
 
 static struct at91_gpio_chip gpio_chip[] = {
-	AT91_GPIO_CHIP("pioA", 0x00, 32),
-	AT91_GPIO_CHIP("pioB", 0x20, 32),
-	AT91_GPIO_CHIP("pioC", 0x40, 32),
-	AT91_GPIO_CHIP("pioD", 0x60, 32),
-	AT91_GPIO_CHIP("pioE", 0x80, 32),
+	AT91_GPIO_CHIP("pioA", 32),
+	AT91_GPIO_CHIP("pioB", 32),
+	AT91_GPIO_CHIP("pioC", 32),
+	AT91_GPIO_CHIP("pioD", 32),
+	AT91_GPIO_CHIP("pioE", 32),
 };
 
 static int gpio_banks;
+static unsigned long at91_gpio_caps;
+
+/* All PIO controllers support PIO3 features */
+#define AT91_GPIO_CAP_PIO3	(1 <<  0)
+
+#define has_pio3()	(at91_gpio_caps & AT91_GPIO_CAP_PIO3)
+
+/*--------------------------------------------------------------------------*/
 
 static inline void __iomem *pin_to_controller(unsigned pin)
 {
@@ -83,6 +100,25 @@
 }
 
 
+static char peripheral_function(void __iomem *pio, unsigned mask)
+{
+	char	ret = 'X';
+	u8	select;
+
+	if (pio) {
+		if (has_pio3()) {
+			select = !!(__raw_readl(pio + PIO_ABCDSR1) & mask);
+			select |= (!!(__raw_readl(pio + PIO_ABCDSR2) & mask) << 1);
+			ret = 'A' + select;
+		} else {
+			ret = __raw_readl(pio + PIO_ABSR) & mask ?
+							'B' : 'A';
+		}
+	}
+
+	return ret;
+}
+
 /*--------------------------------------------------------------------------*/
 
 /* Not all hardware capabilities are exposed through these calls; they
@@ -130,7 +166,14 @@
 
 	__raw_writel(mask, pio + PIO_IDR);
 	__raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
-	__raw_writel(mask, pio + PIO_ASR);
+	if (has_pio3()) {
+		__raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask,
+							pio + PIO_ABCDSR1);
+		__raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask,
+							pio + PIO_ABCDSR2);
+	} else {
+		__raw_writel(mask, pio + PIO_ASR);
+	}
 	__raw_writel(mask, pio + PIO_PDR);
 	return 0;
 }
@@ -150,7 +193,14 @@
 
 	__raw_writel(mask, pio + PIO_IDR);
 	__raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
-	__raw_writel(mask, pio + PIO_BSR);
+	if (has_pio3()) {
+		__raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask,
+							pio + PIO_ABCDSR1);
+		__raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask,
+							pio + PIO_ABCDSR2);
+	} else {
+		__raw_writel(mask, pio + PIO_BSR);
+	}
 	__raw_writel(mask, pio + PIO_PDR);
 	return 0;
 }
@@ -158,8 +208,50 @@
 
 
 /*
- * mux the pin to the gpio controller (instead of "A" or "B" peripheral), and
- * configure it for an input.
+ * mux the pin to the "C" internal peripheral role.
+ */
+int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup)
+{
+	void __iomem	*pio = pin_to_controller(pin);
+	unsigned	mask = pin_to_mask(pin);
+
+	if (!pio || !has_pio3())
+		return -EINVAL;
+
+	__raw_writel(mask, pio + PIO_IDR);
+	__raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
+	__raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1);
+	__raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
+	__raw_writel(mask, pio + PIO_PDR);
+	return 0;
+}
+EXPORT_SYMBOL(at91_set_C_periph);
+
+
+/*
+ * mux the pin to the "D" internal peripheral role.
+ */
+int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup)
+{
+	void __iomem	*pio = pin_to_controller(pin);
+	unsigned	mask = pin_to_mask(pin);
+
+	if (!pio || !has_pio3())
+		return -EINVAL;
+
+	__raw_writel(mask, pio + PIO_IDR);
+	__raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
+	__raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1);
+	__raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
+	__raw_writel(mask, pio + PIO_PDR);
+	return 0;
+}
+EXPORT_SYMBOL(at91_set_D_periph);
+
+
+/*
+ * mux the pin to the gpio controller (instead of "A", "B", "C"
+ * or "D" peripheral), and configure it for an input.
  */
 int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup)
 {
@@ -179,8 +271,8 @@
 
 
 /*
- * mux the pin to the gpio controller (instead of "A" or "B" peripheral),
- * and configure it for an output.
+ * mux the pin to the gpio controller (instead of "A", "B", "C"
+ * or "D" peripheral), and configure it for an output.
  */
 int __init_or_module at91_set_gpio_output(unsigned pin, int value)
 {
@@ -210,12 +302,37 @@
 
 	if (!pio)
 		return -EINVAL;
+
+	if (has_pio3() && is_on)
+		__raw_writel(mask, pio + PIO_IFSCDR);
 	__raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR));
 	return 0;
 }
 EXPORT_SYMBOL(at91_set_deglitch);
 
 /*
+ * enable/disable the debounce filter;
+ */
+int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div)
+{
+	void __iomem	*pio = pin_to_controller(pin);
+	unsigned	mask = pin_to_mask(pin);
+
+	if (!pio || !has_pio3())
+		return -EINVAL;
+
+	if (is_on) {
+		__raw_writel(mask, pio + PIO_IFSCER);
+		__raw_writel(div & PIO_SCDR_DIV, pio + PIO_SCDR);
+		__raw_writel(mask, pio + PIO_IFER);
+	} else {
+		__raw_writel(mask, pio + PIO_IFDR);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(at91_set_debounce);
+
+/*
  * enable/disable the multi-driver; This is only valid for output and
  * allows the output pin to run as an open collector output.
  */
@@ -233,6 +350,41 @@
 EXPORT_SYMBOL(at91_set_multi_drive);
 
 /*
+ * enable/disable the pull-down.
+ * If pull-up already enabled while calling the function, we disable it.
+ */
+int __init_or_module at91_set_pulldown(unsigned pin, int is_on)
+{
+	void __iomem	*pio = pin_to_controller(pin);
+	unsigned	mask = pin_to_mask(pin);
+
+	if (!pio || !has_pio3())
+		return -EINVAL;
+
+	/* Disable pull-up anyway */
+	__raw_writel(mask, pio + PIO_PUDR);
+	__raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR));
+	return 0;
+}
+EXPORT_SYMBOL(at91_set_pulldown);
+
+/*
+ * disable Schmitt trigger
+ */
+int __init_or_module at91_disable_schmitt_trig(unsigned pin)
+{
+	void __iomem	*pio = pin_to_controller(pin);
+	unsigned	mask = pin_to_mask(pin);
+
+	if (!pio || !has_pio3())
+		return -EINVAL;
+
+	__raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT);
+	return 0;
+}
+EXPORT_SYMBOL(at91_disable_schmitt_trig);
+
+/*
  * assuming the pin is muxed as a gpio output, set its value.
  */
 int at91_set_gpio_value(unsigned pin, int value)
@@ -273,9 +425,9 @@
 
 static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
 {
-	unsigned	pin = irq_to_gpio(d->irq);
-	unsigned	mask = pin_to_mask(pin);
-	unsigned	bank = pin / 32;
+	struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+	unsigned	mask = 1 << d->hwirq;
+	unsigned	bank = at91_gpio->pioc_idx;
 
 	if (unlikely(bank >= MAX_GPIO_BANKS))
 		return -EINVAL;
@@ -285,7 +437,7 @@
 	else
 		wakeups[bank] &= ~mask;
 
-	irq_set_irq_wake(gpio_chip[bank].id, state);
+	irq_set_irq_wake(at91_gpio->pioc_virq, state);
 
 	return 0;
 }
@@ -301,9 +453,10 @@
 		__raw_writel(backups[i], pio + PIO_IDR);
 		__raw_writel(wakeups[i], pio + PIO_IER);
 
-		if (!wakeups[i])
+		if (!wakeups[i]) {
+			clk_unprepare(gpio_chip[i].clock);
 			clk_disable(gpio_chip[i].clock);
-		else {
+		} else {
 #ifdef CONFIG_PM_DEBUG
 			printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", 'A'+i, wakeups[i]);
 #endif
@@ -318,8 +471,10 @@
 	for (i = 0; i < gpio_banks; i++) {
 		void __iomem	*pio = gpio_chip[i].regbase;
 
-		if (!wakeups[i])
-			clk_enable(gpio_chip[i].clock);
+		if (!wakeups[i]) {
+			if (clk_prepare(gpio_chip[i].clock) == 0)
+				clk_enable(gpio_chip[i].clock);
+		}
 
 		__raw_writel(wakeups[i], pio + PIO_IDR);
 		__raw_writel(backups[i], pio + PIO_IER);
@@ -335,7 +490,10 @@
  * To use any AT91_PIN_* as an externally triggered IRQ, first call
  * at91_set_gpio_input() then maybe enable its glitch filter.
  * Then just request_irq() with the pin ID; it works like any ARM IRQ
- * handler, though it always triggers on rising and falling edges.
+ * handler.
+ * First implementation always triggers on rising and falling edges
+ * whereas the newer PIO3 can be additionally configured to trigger on
+ * level, edge with any polarity.
  *
  * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after
  * configuring them with at91_set_a_periph() or at91_set_b_periph().
@@ -344,9 +502,9 @@
 
 static void gpio_irq_mask(struct irq_data *d)
 {
-	unsigned	pin = irq_to_gpio(d->irq);
-	void __iomem	*pio = pin_to_controller(pin);
-	unsigned	mask = pin_to_mask(pin);
+	struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+	void __iomem	*pio = at91_gpio->regbase;
+	unsigned	mask = 1 << d->hwirq;
 
 	if (pio)
 		__raw_writel(mask, pio + PIO_IDR);
@@ -354,9 +512,9 @@
 
 static void gpio_irq_unmask(struct irq_data *d)
 {
-	unsigned	pin = irq_to_gpio(d->irq);
-	void __iomem	*pio = pin_to_controller(pin);
-	unsigned	mask = pin_to_mask(pin);
+	struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+	void __iomem	*pio = at91_gpio->regbase;
+	unsigned	mask = 1 << d->hwirq;
 
 	if (pio)
 		__raw_writel(mask, pio + PIO_IER);
@@ -373,23 +531,66 @@
 	}
 }
 
+/* Alternate irq type for PIO3 support */
+static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
+{
+	struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+	void __iomem	*pio = at91_gpio->regbase;
+	unsigned	mask = 1 << d->hwirq;
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		__raw_writel(mask, pio + PIO_ESR);
+		__raw_writel(mask, pio + PIO_REHLSR);
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		__raw_writel(mask, pio + PIO_ESR);
+		__raw_writel(mask, pio + PIO_FELLSR);
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		__raw_writel(mask, pio + PIO_LSR);
+		__raw_writel(mask, pio + PIO_FELLSR);
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		__raw_writel(mask, pio + PIO_LSR);
+		__raw_writel(mask, pio + PIO_REHLSR);
+		break;
+	case IRQ_TYPE_EDGE_BOTH:
+		/*
+		 * disable additional interrupt modes:
+		 * fall back to default behavior
+		 */
+		__raw_writel(mask, pio + PIO_AIMDR);
+		return 0;
+	case IRQ_TYPE_NONE:
+	default:
+		pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq));
+		return -EINVAL;
+	}
+
+	/* enable additional interrupt modes */
+	__raw_writel(mask, pio + PIO_AIMER);
+
+	return 0;
+}
+
 static struct irq_chip gpio_irqchip = {
 	.name		= "GPIO",
 	.irq_disable	= gpio_irq_mask,
 	.irq_mask	= gpio_irq_mask,
 	.irq_unmask	= gpio_irq_unmask,
-	.irq_set_type	= gpio_irq_type,
+	/* .irq_set_type is set dynamically */
 	.irq_set_wake	= gpio_irq_set_wake,
 };
 
 static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
 {
-	unsigned	irq_pin;
 	struct irq_data *idata = irq_desc_get_irq_data(desc);
 	struct irq_chip *chip = irq_data_get_irq_chip(idata);
 	struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
 	void __iomem	*pio = at91_gpio->regbase;
-	u32		isr;
+	unsigned long	isr;
+	int		n;
 
 	/* temporarily mask (level sensitive) parent IRQ */
 	chip->irq_ack(idata);
@@ -407,13 +608,10 @@
 			continue;
 		}
 
-		irq_pin = gpio_to_irq(at91_gpio->chip.base);
-
-		while (isr) {
-			if (isr & 1)
-				generic_handle_irq(irq_pin);
-			irq_pin++;
-			isr >>= 1;
+		n = find_first_bit(&isr, BITS_PER_LONG);
+		while (n < BITS_PER_LONG) {
+			generic_handle_irq(irq_find_mapping(at91_gpio->domain, n));
+			n = find_next_bit(&isr, BITS_PER_LONG, n + 1);
 		}
 	}
 	chip->irq_unmask(idata);
@@ -424,6 +622,33 @@
 
 #ifdef CONFIG_DEBUG_FS
 
+static void gpio_printf(struct seq_file *s, void __iomem *pio, unsigned mask)
+{
+	char	*trigger = NULL;
+	char	*polarity = NULL;
+
+	if (__raw_readl(pio + PIO_IMR) & mask) {
+		if (!has_pio3() || !(__raw_readl(pio + PIO_AIMMR) & mask )) {
+			trigger = "edge";
+			polarity = "both";
+		} else {
+			if (__raw_readl(pio + PIO_ELSR) & mask) {
+				trigger = "level";
+				polarity = __raw_readl(pio + PIO_FRLHSR) & mask ?
+					"high" : "low";
+			} else {
+				trigger = "edge";
+				polarity = __raw_readl(pio + PIO_FRLHSR) & mask ?
+						"rising" : "falling";
+			}
+		}
+		seq_printf(s, "IRQ:%s-%s\t", trigger, polarity);
+	} else {
+		seq_printf(s, "GPIO:%s\t\t",
+				__raw_readl(pio + PIO_PDSR) & mask ? "1" : "0");
+	}
+}
+
 static int at91_gpio_show(struct seq_file *s, void *unused)
 {
 	int bank, j;
@@ -431,7 +656,7 @@
 	/* print heading */
 	seq_printf(s, "Pin\t");
 	for (bank = 0; bank < gpio_banks; bank++) {
-		seq_printf(s, "PIO%c\t", 'A' + bank);
+		seq_printf(s, "PIO%c\t\t", 'A' + bank);
 	};
 	seq_printf(s, "\n\n");
 
@@ -445,11 +670,10 @@
 			unsigned	mask = pin_to_mask(pin);
 
 			if (__raw_readl(pio + PIO_PSR) & mask)
-				seq_printf(s, "GPIO:%s", __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0");
+				gpio_printf(s, pio, mask);
 			else
-				seq_printf(s, "%s", __raw_readl(pio + PIO_ABSR) & mask ? "B" : "A");
-
-			seq_printf(s, "\t");
+				seq_printf(s, "%c\t\t",
+						peripheral_function(pio, mask));
 		}
 
 		seq_printf(s, "\n");
@@ -488,46 +712,152 @@
  */
 static struct lock_class_key gpio_lock_class;
 
+#if defined(CONFIG_OF)
+static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+							irq_hw_number_t hw)
+{
+	struct at91_gpio_chip	*at91_gpio = h->host_data;
+
+	irq_set_lockdep_class(virq, &gpio_lock_class);
+
+	/*
+	 * 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);
+	set_irq_flags(virq, IRQF_VALID);
+	irq_set_chip_data(virq, at91_gpio);
+
+	return 0;
+}
+
+static struct irq_domain_ops at91_gpio_ops = {
+	.map	= at91_gpio_irq_map,
+	.xlate	= irq_domain_xlate_twocell,
+};
+
+int __init at91_gpio_of_irq_setup(struct device_node *node,
+				     struct device_node *parent)
+{
+	struct at91_gpio_chip	*prev = NULL;
+	int			alias_idx = of_alias_get_id(node, "gpio");
+	struct at91_gpio_chip	*at91_gpio = &gpio_chip[alias_idx];
+
+	/* Setup proper .irq_set_type function */
+	if (has_pio3())
+		gpio_irqchip.irq_set_type = alt_gpio_irq_type;
+	else
+		gpio_irqchip.irq_set_type = gpio_irq_type;
+
+	/* Disable irqs of this PIO controller */
+	__raw_writel(~0, at91_gpio->regbase + PIO_IDR);
+
+	/* Setup irq domain */
+	at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
+						&at91_gpio_ops, at91_gpio);
+	if (!at91_gpio->domain)
+		panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
+			at91_gpio->pioc_idx);
+
+	/* Setup chained handler */
+	if (at91_gpio->pioc_idx)
+		prev = &gpio_chip[at91_gpio->pioc_idx - 1];
+
+	/* The toplevel handler handles one bank of GPIOs, except
+	 * on some SoC it can handles up to three...
+	 * We only set up the handler for the first of the list.
+	 */
+	if (prev && prev->next == at91_gpio)
+		return 0;
+
+	at91_gpio->pioc_virq = irq_create_mapping(irq_find_host(parent),
+							at91_gpio->pioc_hwirq);
+	irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
+	irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
+
+	return 0;
+}
+#else
+int __init at91_gpio_of_irq_setup(struct device_node *node,
+				     struct device_node *parent)
+{
+	return -EINVAL;
+}
+#endif
+
+/*
+ * irqdomain initialization: pile up irqdomains on top of AIC range
+ */
+static void __init at91_gpio_irqdomain(struct at91_gpio_chip *at91_gpio)
+{
+	int irq_base;
+
+	irq_base = irq_alloc_descs(-1, 0, at91_gpio->chip.ngpio, 0);
+	if (irq_base < 0)
+		panic("at91_gpio.%d: error %d: couldn't allocate IRQ numbers.\n",
+			at91_gpio->pioc_idx, irq_base);
+	at91_gpio->domain = irq_domain_add_legacy(NULL, at91_gpio->chip.ngpio,
+						  irq_base, 0,
+						  &irq_domain_simple_ops, NULL);
+	if (!at91_gpio->domain)
+		panic("at91_gpio.%d: couldn't allocate irq domain.\n",
+			at91_gpio->pioc_idx);
+}
+
 /*
  * Called from the processor-specific init to enable GPIO interrupt support.
  */
 void __init at91_gpio_irq_setup(void)
 {
-	unsigned		pioc, irq = gpio_to_irq(0);
+	unsigned		pioc;
+	int			gpio_irqnbr = 0;
 	struct at91_gpio_chip	*this, *prev;
 
+	/* Setup proper .irq_set_type function */
+	if (has_pio3())
+		gpio_irqchip.irq_set_type = alt_gpio_irq_type;
+	else
+		gpio_irqchip.irq_set_type = gpio_irq_type;
+
 	for (pioc = 0, this = gpio_chip, prev = NULL;
 			pioc++ < gpio_banks;
 			prev = this, this++) {
-		unsigned	id = this->id;
-		unsigned	i;
+		int offset;
 
 		__raw_writel(~0, this->regbase + PIO_IDR);
 
-		for (i = 0, irq = gpio_to_irq(this->chip.base); i < 32;
-		     i++, irq++) {
-			irq_set_lockdep_class(irq, &gpio_lock_class);
+		/* setup irq domain for this GPIO controller */
+		at91_gpio_irqdomain(this);
+
+		for (offset = 0; offset < this->chip.ngpio; offset++) {
+			unsigned int virq = irq_find_mapping(this->domain, offset);
+			irq_set_lockdep_class(virq, &gpio_lock_class);
 
 			/*
 			 * Can use the "simple" and not "edge" handler since it's
 			 * shorter, and the AIC handles interrupts sanely.
 			 */
-			irq_set_chip_and_handler(irq, &gpio_irqchip,
+			irq_set_chip_and_handler(virq, &gpio_irqchip,
 						 handle_simple_irq);
-			set_irq_flags(irq, IRQF_VALID);
+			set_irq_flags(virq, IRQF_VALID);
+			irq_set_chip_data(virq, this);
+
+			gpio_irqnbr++;
 		}
 
 		/* The toplevel handler handles one bank of GPIOs, except
-		 * AT91SAM9263_ID_PIOCDE handles three... PIOC is first in
-		 * the list, so we only set up that handler.
+		 * on some SoC it can handles up to three...
+		 * We only set up the handler for the first of the list.
 		 */
 		if (prev && prev->next == this)
 			continue;
 
-		irq_set_chip_data(id, this);
-		irq_set_chained_handler(id, gpio_irq_handler);
+		this->pioc_virq = irq_create_mapping(NULL, this->pioc_hwirq);
+		irq_set_chip_data(this->pioc_virq, this);
+		irq_set_chained_handler(this->pioc_virq, gpio_irq_handler);
 	}
-	pr_info("AT91: %d gpio irqs in %d banks\n", irq - gpio_to_irq(0), gpio_banks);
+	pr_info("AT91: %d gpio irqs in %d banks\n", gpio_irqnbr, gpio_banks);
 }
 
 /* gpiolib support */
@@ -593,48 +923,175 @@
 					   at91_get_gpio_value(pin) ?
 					   "set" : "clear");
 			else
-				seq_printf(s, "[periph %s]\n",
-					   __raw_readl(pio + PIO_ABSR) &
-					   mask ? "B" : "A");
+				seq_printf(s, "[periph %c]\n",
+					   peripheral_function(pio, mask));
 		}
 	}
 }
 
+static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+	int virq;
+
+	if (offset < chip->ngpio)
+		virq = irq_create_mapping(at91_gpio->domain, offset);
+	else
+		virq = -ENXIO;
+
+	dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
+				chip->label, offset + chip->base, virq);
+	return virq;
+}
+
+static int __init at91_gpio_setup_clk(int idx)
+{
+	struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
+
+	/* retreive PIO controller's clock */
+	at91_gpio->clock = clk_get_sys(NULL, at91_gpio->chip.label);
+	if (IS_ERR(at91_gpio->clock)) {
+		pr_err("at91_gpio.%d, failed to get clock, ignoring.\n", idx);
+		goto err;
+	}
+
+	if (clk_prepare(at91_gpio->clock))
+		goto clk_prep_err;
+
+	/* enable PIO controller's clock */
+	if (clk_enable(at91_gpio->clock)) {
+		pr_err("at91_gpio.%d, failed to enable clock, ignoring.\n", idx);
+		goto clk_err;
+	}
+
+	return 0;
+
+clk_err:
+	clk_unprepare(at91_gpio->clock);
+clk_prep_err:
+	clk_put(at91_gpio->clock);
+err:
+	return -EINVAL;
+}
+
+#ifdef CONFIG_OF_GPIO
+static void __init of_at91_gpio_init_one(struct device_node *np)
+{
+	int alias_idx;
+	struct at91_gpio_chip *at91_gpio;
+
+	if (!np)
+		return;
+
+	alias_idx = of_alias_get_id(np, "gpio");
+	if (alias_idx >= MAX_GPIO_BANKS) {
+		pr_err("at91_gpio, failed alias idx(%d) > MAX_GPIO_BANKS(%d), ignoring.\n",
+						alias_idx, MAX_GPIO_BANKS);
+		return;
+	}
+
+	at91_gpio = &gpio_chip[alias_idx];
+	at91_gpio->chip.base = alias_idx * at91_gpio->chip.ngpio;
+
+	at91_gpio->regbase = of_iomap(np, 0);
+	if (!at91_gpio->regbase) {
+		pr_err("at91_gpio.%d, failed to map registers, ignoring.\n",
+								alias_idx);
+		return;
+	}
+
+	/* Get the interrupts property */
+	if (of_property_read_u32(np, "interrupts", &at91_gpio->pioc_hwirq)) {
+		pr_err("at91_gpio.%d, failed to get interrupts property, ignoring.\n",
+								alias_idx);
+		goto ioremap_err;
+	}
+
+	/* Get capabilities from compatibility property */
+	if (of_device_is_compatible(np, "atmel,at91sam9x5-gpio"))
+		at91_gpio_caps |= AT91_GPIO_CAP_PIO3;
+
+	/* Setup clock */
+	if (at91_gpio_setup_clk(alias_idx))
+		goto ioremap_err;
+
+	at91_gpio->chip.of_node = np;
+	gpio_banks = max(gpio_banks, alias_idx + 1);
+	at91_gpio->pioc_idx = alias_idx;
+	return;
+
+ioremap_err:
+	iounmap(at91_gpio->regbase);
+}
+
+static int __init of_at91_gpio_init(void)
+{
+	struct device_node *np = NULL;
+
+	/*
+	 * This isn't ideal, but it gets things hooked up until this
+	 * driver is converted into a platform_device
+	 */
+	for_each_compatible_node(np, NULL, "atmel,at91rm9200-gpio")
+		of_at91_gpio_init_one(np);
+
+	return gpio_banks > 0 ? 0 : -EINVAL;
+}
+#else
+static int __init of_at91_gpio_init(void)
+{
+	return -EINVAL;
+}
+#endif
+
+static void __init at91_gpio_init_one(int idx, u32 regbase, int pioc_hwirq)
+{
+	struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
+
+	at91_gpio->chip.base = idx * at91_gpio->chip.ngpio;
+	at91_gpio->pioc_hwirq = pioc_hwirq;
+	at91_gpio->pioc_idx = idx;
+
+	at91_gpio->regbase = ioremap(regbase, 512);
+	if (!at91_gpio->regbase) {
+		pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", idx);
+		return;
+	}
+
+	if (at91_gpio_setup_clk(idx))
+		goto ioremap_err;
+
+	gpio_banks = max(gpio_banks, idx + 1);
+	return;
+
+ioremap_err:
+	iounmap(at91_gpio->regbase);
+}
+
 /*
  * Called from the processor-specific init to enable GPIO pin support.
  */
 void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
 {
-	unsigned		i;
+	unsigned i;
 	struct at91_gpio_chip *at91_gpio, *last = NULL;
 
 	BUG_ON(nr_banks > MAX_GPIO_BANKS);
 
-	gpio_banks = nr_banks;
+	if (of_at91_gpio_init() < 0) {
+		/* No GPIO controller found in device tree */
+		for (i = 0; i < nr_banks; i++)
+			at91_gpio_init_one(i, data[i].regbase, data[i].id);
+	}
 
-	for (i = 0; i < nr_banks; i++) {
+	for (i = 0; i < gpio_banks; i++) {
 		at91_gpio = &gpio_chip[i];
 
-		at91_gpio->id = data[i].id;
-		at91_gpio->chip.base = i * 32;
-
-		at91_gpio->regbase = ioremap(data[i].regbase, 512);
-		if (!at91_gpio->regbase) {
-			pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", i);
-			continue;
-		}
-
-		at91_gpio->clock = clk_get_sys(NULL, at91_gpio->chip.label);
-		if (!at91_gpio->clock) {
-			pr_err("at91_gpio.%d, failed to get clock, ignoring.\n", i);
-			continue;
-		}
-
-		/* enable PIO controller's clock */
-		clk_enable(at91_gpio->clock);
-
-		/* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */
-		if (last && last->id == at91_gpio->id)
+		/*
+		 * GPIO controller are grouped on some SoC:
+		 * PIOC, PIOD and PIOE can share the same IRQ line
+		 */
+		if (last && last->pioc_hwirq == at91_gpio->pioc_hwirq)
 			last->next = at91_gpio;
 		last = at91_gpio;
 
diff --git a/arch/arm/mach-at91/include/mach/at91_matrix.h b/arch/arm/mach-at91/include/mach/at91_matrix.h
new file mode 100644
index 0000000..02fae9d
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91_matrix.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2
+ */
+
+#ifndef __MACH_AT91_MATRIX_H__
+#define __MACH_AT91_MATRIX_H__
+
+#ifndef __ASSEMBLY__
+extern void __iomem *at91_matrix_base;
+
+#define at91_matrix_read(field) \
+	__raw_readl(at91_matrix_base + field)
+
+#define at91_matrix_write(field, value) \
+	__raw_writel(value, at91_matrix_base + field);
+
+#else
+.extern at91_matrix_base
+#endif
+
+#endif /* __MACH_AT91_MATRIX_H__ */
diff --git a/arch/arm/mach-at91/include/mach/at91_pio.h b/arch/arm/mach-at91/include/mach/at91_pio.h
index c6a31bf..732b11c 100644
--- a/arch/arm/mach-at91/include/mach/at91_pio.h
+++ b/arch/arm/mach-at91/include/mach/at91_pio.h
@@ -40,10 +40,35 @@
 #define PIO_PUER	0x64	/* Pull-up Enable Register */
 #define PIO_PUSR	0x68	/* Pull-up Status Register */
 #define PIO_ASR		0x70	/* Peripheral A Select Register */
+#define PIO_ABCDSR1	0x70	/* Peripheral ABCD Select Register 1 [some sam9 only] */
 #define PIO_BSR		0x74	/* Peripheral B Select Register */
+#define PIO_ABCDSR2	0x74	/* Peripheral ABCD Select Register 2 [some sam9 only] */
 #define PIO_ABSR	0x78	/* AB Status Register */
+#define PIO_IFSCDR	0x80	/* Input Filter Slow Clock Disable Register */
+#define PIO_IFSCER	0x84	/* Input Filter Slow Clock Enable Register */
+#define PIO_IFSCSR	0x88	/* Input Filter Slow Clock Status Register */
+#define PIO_SCDR	0x8c	/* Slow Clock Divider Debouncing Register */
+#define		PIO_SCDR_DIV	(0x3fff <<  0)		/* Slow Clock Divider Mask */
+#define PIO_PPDDR	0x90	/* Pad Pull-down Disable Register */
+#define PIO_PPDER	0x94	/* Pad Pull-down Enable Register */
+#define PIO_PPDSR	0x98	/* Pad Pull-down Status Register */
 #define PIO_OWER	0xa0	/* Output Write Enable Register */
 #define PIO_OWDR	0xa4	/* Output Write Disable Register */
 #define PIO_OWSR	0xa8	/* Output Write Status Register */
+#define PIO_AIMER	0xb0	/* Additional Interrupt Modes Enable Register */
+#define PIO_AIMDR	0xb4	/* Additional Interrupt Modes Disable Register */
+#define PIO_AIMMR	0xb8	/* Additional Interrupt Modes Mask Register */
+#define PIO_ESR		0xc0	/* Edge Select Register */
+#define PIO_LSR		0xc4	/* Level Select Register */
+#define PIO_ELSR	0xc8	/* Edge/Level Status Register */
+#define PIO_FELLSR	0xd0	/* Falling Edge/Low Level Select Register */
+#define PIO_REHLSR	0xd4	/* Rising Edge/ High Level Select Register */
+#define PIO_FRLHSR	0xd8	/* Fall/Rise - Low/High Status Register */
+#define PIO_SCHMITT	0x100	/* Schmitt Trigger Register */
+
+#define ABCDSR_PERIPH_A	0x0
+#define ABCDSR_PERIPH_B	0x1
+#define ABCDSR_PERIPH_C	0x2
+#define ABCDSR_PERIPH_D	0x3
 
 #endif
diff --git a/arch/arm/mach-at91/include/mach/at91_pmc.h b/arch/arm/mach-at91/include/mach/at91_pmc.h
index e46f93e..3660478 100644
--- a/arch/arm/mach-at91/include/mach/at91_pmc.h
+++ b/arch/arm/mach-at91/include/mach/at91_pmc.h
@@ -16,17 +16,27 @@
 #ifndef AT91_PMC_H
 #define AT91_PMC_H
 
-#define	AT91_PMC_SCER		(AT91_PMC + 0x00)	/* System Clock Enable Register */
-#define	AT91_PMC_SCDR		(AT91_PMC + 0x04)	/* System Clock Disable Register */
+#ifndef __ASSEMBLY__
+extern void __iomem *at91_pmc_base;
 
-#define	AT91_PMC_SCSR		(AT91_PMC + 0x08)	/* System Clock Status Register */
+#define at91_pmc_read(field) \
+	__raw_readl(at91_pmc_base + field)
+
+#define at91_pmc_write(field, value) \
+	__raw_writel(value, at91_pmc_base + field)
+#else
+.extern at91_aic_base
+#endif
+
+#define	AT91_PMC_SCER		0x00			/* System Clock Enable Register */
+#define	AT91_PMC_SCDR		0x04			/* System Clock Disable Register */
+
+#define	AT91_PMC_SCSR		0x08			/* System Clock Status Register */
 #define		AT91_PMC_PCK		(1 <<  0)		/* Processor Clock */
 #define		AT91RM9200_PMC_UDP	(1 <<  1)		/* USB Devcice Port Clock [AT91RM9200 only] */
 #define		AT91RM9200_PMC_MCKUDP	(1 <<  2)		/* USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] */
-#define		AT91CAP9_PMC_DDR	(1 <<  2)		/* DDR Clock [CAP9 revC & some SAM9 only] */
 #define		AT91RM9200_PMC_UHP	(1 <<  4)		/* USB Host Port Clock [AT91RM9200 only] */
 #define		AT91SAM926x_PMC_UHP	(1 <<  6)		/* USB Host Port Clock [AT91SAM926x only] */
-#define		AT91CAP9_PMC_UHP	(1 <<  6)		/* USB Host Port Clock [AT91CAP9 only] */
 #define		AT91SAM926x_PMC_UDP	(1 <<  7)		/* USB Devcice Port Clock [AT91SAM926x only] */
 #define		AT91_PMC_PCK0		(1 <<  8)		/* Programmable Clock 0 */
 #define		AT91_PMC_PCK1		(1 <<  9)		/* Programmable Clock 1 */
@@ -36,27 +46,31 @@
 #define		AT91_PMC_HCK0		(1 << 16)		/* AHB Clock (USB host) [AT91SAM9261 only] */
 #define		AT91_PMC_HCK1		(1 << 17)		/* AHB Clock (LCD) [AT91SAM9261 only] */
 
-#define	AT91_PMC_PCER		(AT91_PMC + 0x10)	/* Peripheral Clock Enable Register */
-#define	AT91_PMC_PCDR		(AT91_PMC + 0x14)	/* Peripheral Clock Disable Register */
-#define	AT91_PMC_PCSR		(AT91_PMC + 0x18)	/* Peripheral Clock Status Register */
+#define	AT91_PMC_PCER		0x10			/* Peripheral Clock Enable Register */
+#define	AT91_PMC_PCDR		0x14			/* Peripheral Clock Disable Register */
+#define	AT91_PMC_PCSR		0x18			/* Peripheral Clock Status Register */
 
-#define	AT91_CKGR_UCKR		(AT91_PMC + 0x1C)	/* UTMI Clock Register [some SAM9, CAP9] */
+#define	AT91_CKGR_UCKR		0x1C			/* UTMI Clock Register [some SAM9] */
 #define		AT91_PMC_UPLLEN		(1   << 16)		/* UTMI PLL Enable */
 #define		AT91_PMC_UPLLCOUNT	(0xf << 20)		/* UTMI PLL Start-up Time */
 #define		AT91_PMC_BIASEN		(1   << 24)		/* UTMI BIAS Enable */
 #define		AT91_PMC_BIASCOUNT	(0xf << 28)		/* UTMI BIAS Start-up Time */
 
-#define	AT91_CKGR_MOR		(AT91_PMC + 0x20)	/* Main Oscillator Register [not on SAM9RL] */
-#define		AT91_PMC_MOSCEN		(1    << 0)		/* Main Oscillator Enable */
-#define		AT91_PMC_OSCBYPASS	(1    << 1)		/* Oscillator Bypass [SAM9x, CAP9] */
-#define		AT91_PMC_OSCOUNT	(0xff << 8)		/* Main Oscillator Start-up Time */
+#define	AT91_CKGR_MOR		0x20			/* Main Oscillator Register [not on SAM9RL] */
+#define		AT91_PMC_MOSCEN		(1    <<  0)		/* Main Oscillator Enable */
+#define		AT91_PMC_OSCBYPASS	(1    <<  1)		/* Oscillator Bypass */
+#define		AT91_PMC_MOSCRCEN	(1    <<  3)		/* Main On-Chip RC Oscillator Enable [some SAM9] */
+#define		AT91_PMC_OSCOUNT	(0xff <<  8)		/* Main Oscillator Start-up Time */
+#define		AT91_PMC_KEY		(0x37 << 16)		/* MOR Writing Key */
+#define		AT91_PMC_MOSCSEL	(1    << 24)		/* Main Oscillator Selection [some SAM9] */
+#define		AT91_PMC_CFDEN		(1    << 25)		/* Clock Failure Detector Enable [some SAM9] */
 
-#define	AT91_CKGR_MCFR		(AT91_PMC + 0x24)	/* Main Clock Frequency Register */
+#define	AT91_CKGR_MCFR		0x24			/* Main Clock Frequency Register */
 #define		AT91_PMC_MAINF		(0xffff <<  0)		/* Main Clock Frequency */
 #define		AT91_PMC_MAINRDY	(1	<< 16)		/* Main Clock Ready */
 
-#define	AT91_CKGR_PLLAR		(AT91_PMC + 0x28)	/* PLL A Register */
-#define	AT91_CKGR_PLLBR		(AT91_PMC + 0x2c)	/* PLL B Register */
+#define	AT91_CKGR_PLLAR		0x28			/* PLL A Register */
+#define	AT91_CKGR_PLLBR		0x2c			/* PLL B Register */
 #define		AT91_PMC_DIV		(0xff  <<  0)		/* Divider */
 #define		AT91_PMC_PLLCOUNT	(0x3f  <<  8)		/* PLL Counter */
 #define		AT91_PMC_OUT		(3     << 14)		/* PLL Clock Frequency Range */
@@ -67,27 +81,37 @@
 #define			AT91_PMC_USBDIV_4		(2 << 28)
 #define		AT91_PMC_USB96M		(1     << 28)		/* Divider by 2 Enable (PLLB only) */
 
-#define	AT91_PMC_MCKR		(AT91_PMC + 0x30)	/* Master Clock Register */
+#define	AT91_PMC_MCKR		0x30			/* Master Clock Register */
 #define		AT91_PMC_CSS		(3 <<  0)		/* Master Clock Selection */
 #define			AT91_PMC_CSS_SLOW		(0 << 0)
 #define			AT91_PMC_CSS_MAIN		(1 << 0)
 #define			AT91_PMC_CSS_PLLA		(2 << 0)
 #define			AT91_PMC_CSS_PLLB		(3 << 0)
 #define			AT91_PMC_CSS_UPLL		(3 << 0)	/* [some SAM9 only] */
-#define		AT91_PMC_PRES		(7 <<  2)		/* Master Clock Prescaler */
-#define			AT91_PMC_PRES_1			(0 << 2)
-#define			AT91_PMC_PRES_2			(1 << 2)
-#define			AT91_PMC_PRES_4			(2 << 2)
-#define			AT91_PMC_PRES_8			(3 << 2)
-#define			AT91_PMC_PRES_16		(4 << 2)
-#define			AT91_PMC_PRES_32		(5 << 2)
-#define			AT91_PMC_PRES_64		(6 << 2)
+#define		PMC_PRES_OFFSET		2
+#define		AT91_PMC_PRES		(7 <<  PMC_PRES_OFFSET)		/* Master Clock Prescaler */
+#define			AT91_PMC_PRES_1			(0 << PMC_PRES_OFFSET)
+#define			AT91_PMC_PRES_2			(1 << PMC_PRES_OFFSET)
+#define			AT91_PMC_PRES_4			(2 << PMC_PRES_OFFSET)
+#define			AT91_PMC_PRES_8			(3 << PMC_PRES_OFFSET)
+#define			AT91_PMC_PRES_16		(4 << PMC_PRES_OFFSET)
+#define			AT91_PMC_PRES_32		(5 << PMC_PRES_OFFSET)
+#define			AT91_PMC_PRES_64		(6 << PMC_PRES_OFFSET)
+#define		PMC_ALT_PRES_OFFSET	4
+#define		AT91_PMC_ALT_PRES	(7 <<  PMC_ALT_PRES_OFFSET)		/* Master Clock Prescaler [alternate location] */
+#define			AT91_PMC_ALT_PRES_1		(0 << PMC_ALT_PRES_OFFSET)
+#define			AT91_PMC_ALT_PRES_2		(1 << PMC_ALT_PRES_OFFSET)
+#define			AT91_PMC_ALT_PRES_4		(2 << PMC_ALT_PRES_OFFSET)
+#define			AT91_PMC_ALT_PRES_8		(3 << PMC_ALT_PRES_OFFSET)
+#define			AT91_PMC_ALT_PRES_16		(4 << PMC_ALT_PRES_OFFSET)
+#define			AT91_PMC_ALT_PRES_32		(5 << PMC_ALT_PRES_OFFSET)
+#define			AT91_PMC_ALT_PRES_64		(6 << PMC_ALT_PRES_OFFSET)
 #define		AT91_PMC_MDIV		(3 <<  8)		/* Master Clock Division */
 #define			AT91RM9200_PMC_MDIV_1		(0 << 8)	/* [AT91RM9200 only] */
 #define			AT91RM9200_PMC_MDIV_2		(1 << 8)
 #define			AT91RM9200_PMC_MDIV_3		(2 << 8)
 #define			AT91RM9200_PMC_MDIV_4		(3 << 8)
-#define			AT91SAM9_PMC_MDIV_1		(0 << 8)	/* [SAM9,CAP9 only] */
+#define			AT91SAM9_PMC_MDIV_1		(0 << 8)	/* [SAM9 only] */
 #define			AT91SAM9_PMC_MDIV_2		(1 << 8)
 #define			AT91SAM9_PMC_MDIV_4		(2 << 8)
 #define			AT91SAM9_PMC_MDIV_6		(3 << 8)	/* [some SAM9 only] */
@@ -99,35 +123,55 @@
 #define			AT91_PMC_PLLADIV2_OFF		(0 << 12)
 #define			AT91_PMC_PLLADIV2_ON		(1 << 12)
 
-#define	AT91_PMC_USB		(AT91_PMC + 0x38)	/* USB Clock Register [some SAM9 only] */
+#define	AT91_PMC_USB		0x38			/* USB Clock Register [some SAM9 only] */
 #define		AT91_PMC_USBS		(0x1 <<  0)		/* USB OHCI Input clock selection */
 #define			AT91_PMC_USBS_PLLA		(0 << 0)
 #define			AT91_PMC_USBS_UPLL		(1 << 0)
 #define		AT91_PMC_OHCIUSBDIV	(0xF <<  8)		/* Divider for USB OHCI Clock */
 
-#define	AT91_PMC_PCKR(n)	(AT91_PMC + 0x40 + ((n) * 4))	/* Programmable Clock 0-N Registers */
+#define	AT91_PMC_SMD		0x3c			/* Soft Modem Clock Register [some SAM9 only] */
+#define		AT91_PMC_SMDS		(0x1  <<  0)		/* SMD input clock selection */
+#define		AT91_PMC_SMD_DIV	(0x1f <<  8)		/* SMD input clock divider */
+#define		AT91_PMC_SMDDIV(n)	(((n) <<  8) & AT91_PMC_SMD_DIV)
+
+#define	AT91_PMC_PCKR(n)	(0x40 + ((n) * 4))	/* Programmable Clock 0-N Registers */
+#define		AT91_PMC_ALT_PCKR_CSS	(0x7 <<  0)		/* Programmable Clock Source Selection [alternate length] */
+#define			AT91_PMC_CSS_MASTER		(4 << 0)	/* [some SAM9 only] */
 #define		AT91_PMC_CSSMCK		(0x1 <<  8)		/* CSS or Master Clock Selection */
 #define			AT91_PMC_CSSMCK_CSS		(0 << 8)
 #define			AT91_PMC_CSSMCK_MCK		(1 << 8)
 
-#define	AT91_PMC_IER		(AT91_PMC + 0x60)	/* Interrupt Enable Register */
-#define	AT91_PMC_IDR		(AT91_PMC + 0x64)	/* Interrupt Disable Register */
-#define	AT91_PMC_SR		(AT91_PMC + 0x68)	/* Status Register */
+#define	AT91_PMC_IER		0x60			/* Interrupt Enable Register */
+#define	AT91_PMC_IDR		0x64			/* Interrupt Disable Register */
+#define	AT91_PMC_SR		0x68			/* Status Register */
 #define		AT91_PMC_MOSCS		(1 <<  0)		/* MOSCS Flag */
 #define		AT91_PMC_LOCKA		(1 <<  1)		/* PLLA Lock */
 #define		AT91_PMC_LOCKB		(1 <<  2)		/* PLLB Lock */
 #define		AT91_PMC_MCKRDY		(1 <<  3)		/* Master Clock */
-#define		AT91_PMC_LOCKU		(1 <<  6)		/* UPLL Lock [some SAM9, AT91CAP9 only] */
-#define		AT91_PMC_OSCSEL		(1 <<  7)		/* Slow Clock Oscillator [AT91CAP9 revC only] */
+#define		AT91_PMC_LOCKU		(1 <<  6)		/* UPLL Lock [some SAM9] */
 #define		AT91_PMC_PCK0RDY	(1 <<  8)		/* Programmable Clock 0 */
 #define		AT91_PMC_PCK1RDY	(1 <<  9)		/* Programmable Clock 1 */
 #define		AT91_PMC_PCK2RDY	(1 << 10)		/* Programmable Clock 2 */
 #define		AT91_PMC_PCK3RDY	(1 << 11)		/* Programmable Clock 3 */
-#define	AT91_PMC_IMR		(AT91_PMC + 0x6c)	/* Interrupt Mask Register */
+#define		AT91_PMC_MOSCSELS	(1 << 16)		/* Main Oscillator Selection [some SAM9] */
+#define		AT91_PMC_MOSCRCS	(1 << 17)		/* Main On-Chip RC [some SAM9] */
+#define		AT91_PMC_CFDEV		(1 << 18)		/* Clock Failure Detector Event [some SAM9] */
+#define	AT91_PMC_IMR		0x6c			/* Interrupt Mask Register */
 
-#define AT91_PMC_PROT		(AT91_PMC + 0xe4)	/* Protect Register [AT91CAP9 revC only] */
-#define		AT91_PMC_PROTKEY	0x504d4301	/* Activation Code */
+#define AT91_PMC_PROT		0xe4			/* Write Protect Mode Register [some SAM9] */
+#define		AT91_PMC_WPEN		(0x1  <<  0)		/* Write Protect Enable */
+#define		AT91_PMC_WPKEY		(0xffffff << 8)		/* Write Protect Key */
+#define		AT91_PMC_PROTKEY	(0x504d43 << 8)		/* Activation Code */
 
-#define AT91_PMC_VER		(AT91_PMC + 0xfc)	/* PMC Module Version [AT91CAP9 only] */
+#define AT91_PMC_WPSR		0xe8			/* Write Protect Status Register [some SAM9] */
+#define		AT91_PMC_WPVS		(0x1  <<  0)		/* Write Protect Violation Status */
+#define		AT91_PMC_WPVSRC		(0xffff  <<  8)		/* Write Protect Violation Source */
+
+#define AT91_PMC_PCR		0x10c			/* Peripheral Control Register [some SAM9] */
+#define		AT91_PMC_PCR_PID	(0x3f  <<  0)		/* Peripheral ID */
+#define		AT91_PMC_PCR_CMD	(0x1  <<  12)		/* Command */
+#define		AT91_PMC_PCR_DIV	(0x3  <<  16)		/* Divisor Value */
+#define		AT91_PMC_PCRDIV(n)	(((n) <<  16) & AT91_PMC_PCR_DIV)
+#define		AT91_PMC_PCR_EN		(0x1  <<  28)		/* Enable */
 
 #endif
diff --git a/arch/arm/mach-at91/include/mach/at91_ramc.h b/arch/arm/mach-at91/include/mach/at91_ramc.h
new file mode 100644
index 0000000..d8aeb27
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91_ramc.h
@@ -0,0 +1,32 @@
+/*
+ * Header file for the Atmel RAM Controller
+ *
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2 only
+ */
+
+#ifndef __AT91_RAMC_H__
+#define __AT91_RAMC_H__
+
+#ifndef __ASSEMBLY__
+extern void __iomem *at91_ramc_base[];
+
+#define at91_ramc_read(id, field) \
+	__raw_readl(at91_ramc_base[id] + field)
+
+#define at91_ramc_write(id, field, value) \
+	__raw_writel(value, at91_ramc_base[id] + field)
+#else
+.extern at91_ramc_base
+#endif
+
+#define AT91_MEMCTRL_MC		0
+#define AT91_MEMCTRL_SDRAMC	1
+#define AT91_MEMCTRL_DDRSDR	2
+
+#include <mach/at91rm9200_sdramc.h>
+#include <mach/at91sam9_ddrsdr.h>
+#include <mach/at91sam9_sdramc.h>
+
+#endif /* __AT91_RAMC_H__ */
diff --git a/arch/arm/mach-at91/include/mach/at91_shdwc.h b/arch/arm/mach-at91/include/mach/at91_shdwc.h
index 1d4fe82..60478ea 100644
--- a/arch/arm/mach-at91/include/mach/at91_shdwc.h
+++ b/arch/arm/mach-at91/include/mach/at91_shdwc.h
@@ -36,9 +36,11 @@
 #define			AT91_SHDW_WKMODE0_HIGH		1
 #define			AT91_SHDW_WKMODE0_LOW		2
 #define			AT91_SHDW_WKMODE0_ANYLEVEL	3
-#define		AT91_SHDW_CPTWK0	(0xf << 4)		/* Counter On Wake Up 0 */
+#define		AT91_SHDW_CPTWK0_MAX	0xf			/* Maximum Counter On Wake Up 0 */
+#define		AT91_SHDW_CPTWK0	(AT91_SHDW_CPTWK0_MAX << 4) /* Counter On Wake Up 0 */
 #define			AT91_SHDW_CPTWK0_(x)	((x) << 4)
 #define		AT91_SHDW_RTTWKEN	(1   << 16)		/* Real Time Timer Wake-up Enable */
+#define		AT91_SHDW_RTCWKEN	(1   << 17)		/* Real Time Clock Wake-up Enable */
 
 #define AT91_SHDW_SR		0x08			/* Shut Down Status Register */
 #define		AT91_SHDW_WAKEUP0	(1 <<  0)		/* Wake-up 0 Status */
diff --git a/arch/arm/mach-at91/include/mach/at91_st.h b/arch/arm/mach-at91/include/mach/at91_st.h
index 8847173..969aac2 100644
--- a/arch/arm/mach-at91/include/mach/at91_st.h
+++ b/arch/arm/mach-at91/include/mach/at91_st.h
@@ -16,34 +16,46 @@
 #ifndef AT91_ST_H
 #define AT91_ST_H
 
-#define	AT91_ST_CR		(AT91_ST + 0x00)	/* Control Register */
+#ifndef __ASSEMBLY__
+extern void __iomem *at91_st_base;
+
+#define at91_st_read(field) \
+	__raw_readl(at91_st_base + field)
+
+#define at91_st_write(field, value) \
+	__raw_writel(value, at91_st_base + field);
+#else
+.extern at91_st_base
+#endif
+
+#define	AT91_ST_CR		0x00			/* Control Register */
 #define 	AT91_ST_WDRST		(1 << 0)		/* Watchdog Timer Restart */
 
-#define	AT91_ST_PIMR		(AT91_ST + 0x04)	/* Period Interval Mode Register */
+#define	AT91_ST_PIMR		0x04			/* Period Interval Mode Register */
 #define		AT91_ST_PIV		(0xffff <<  0)		/* Period Interval Value */
 
-#define	AT91_ST_WDMR		(AT91_ST + 0x08)	/* Watchdog Mode Register */
+#define	AT91_ST_WDMR		0x08			/* Watchdog Mode Register */
 #define		AT91_ST_WDV		(0xffff <<  0)		/* Watchdog Counter Value */
 #define		AT91_ST_RSTEN		(1	<< 16)		/* Reset Enable */
 #define		AT91_ST_EXTEN		(1	<< 17)		/* External Signal Assertion Enable */
 
-#define	AT91_ST_RTMR		(AT91_ST + 0x0c)	/* Real-time Mode Register */
+#define	AT91_ST_RTMR		0x0c			/* Real-time Mode Register */
 #define		AT91_ST_RTPRES		(0xffff <<  0)		/* Real-time Prescalar Value */
 
-#define	AT91_ST_SR		(AT91_ST + 0x10)	/* Status Register */
+#define	AT91_ST_SR		0x10			/* Status Register */
 #define		AT91_ST_PITS		(1 << 0)		/* Period Interval Timer Status */
 #define		AT91_ST_WDOVF		(1 << 1) 		/* Watchdog Overflow */
 #define		AT91_ST_RTTINC		(1 << 2) 		/* Real-time Timer Increment */
 #define		AT91_ST_ALMS		(1 << 3) 		/* Alarm Status */
 
-#define	AT91_ST_IER		(AT91_ST + 0x14)	/* Interrupt Enable Register */
-#define	AT91_ST_IDR		(AT91_ST + 0x18)	/* Interrupt Disable Register */
-#define	AT91_ST_IMR		(AT91_ST + 0x1c)	/* Interrupt Mask Register */
+#define	AT91_ST_IER		0x14			/* Interrupt Enable Register */
+#define	AT91_ST_IDR		0x18			/* Interrupt Disable Register */
+#define	AT91_ST_IMR		0x1c			/* Interrupt Mask Register */
 
-#define	AT91_ST_RTAR		(AT91_ST + 0x20)	/* Real-time Alarm Register */
+#define	AT91_ST_RTAR		0x20			/* Real-time Alarm Register */
 #define		AT91_ST_ALMV		(0xfffff << 0)		/* Alarm Value */
 
-#define	AT91_ST_CRTR		(AT91_ST + 0x24)	/* Current Real-time Register */
+#define	AT91_ST_CRTR		0x24			/* Current Real-time Register */
 #define		AT91_ST_CRTV		(0xfffff << 0)		/* Current Real-Time Value */
 
 #endif
diff --git a/arch/arm/mach-at91/include/mach/at91cap9.h b/arch/arm/mach-at91/include/mach/at91cap9.h
deleted file mode 100644
index 61d9529..0000000
--- a/arch/arm/mach-at91/include/mach/at91cap9.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91cap9.h
- *
- *  Copyright (C) 2007 Stelian Pop <stelian.pop@leadtechdesign.com>
- *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
- *  Copyright (C) 2007 Atmel Corporation.
- *
- * Common definitions.
- * Based on AT91CAP9 datasheet revision B (Preliminary).
- *
- * 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 AT91CAP9_H
-#define AT91CAP9_H
-
-/*
- * Peripheral identifiers/interrupts.
- */
-#define AT91CAP9_ID_PIOABCD	2	/* Parallel IO Controller A, B, C and D */
-#define AT91CAP9_ID_MPB0	3	/* MP Block Peripheral 0 */
-#define AT91CAP9_ID_MPB1	4	/* MP Block Peripheral 1 */
-#define AT91CAP9_ID_MPB2	5	/* MP Block Peripheral 2 */
-#define AT91CAP9_ID_MPB3	6	/* MP Block Peripheral 3 */
-#define AT91CAP9_ID_MPB4	7	/* MP Block Peripheral 4 */
-#define AT91CAP9_ID_US0		8	/* USART 0 */
-#define AT91CAP9_ID_US1		9	/* USART 1 */
-#define AT91CAP9_ID_US2		10	/* USART 2 */
-#define AT91CAP9_ID_MCI0	11	/* Multimedia Card Interface 0 */
-#define AT91CAP9_ID_MCI1	12	/* Multimedia Card Interface 1 */
-#define AT91CAP9_ID_CAN		13	/* CAN */
-#define AT91CAP9_ID_TWI		14	/* Two-Wire Interface */
-#define AT91CAP9_ID_SPI0	15	/* Serial Peripheral Interface 0 */
-#define AT91CAP9_ID_SPI1	16	/* Serial Peripheral Interface 0 */
-#define AT91CAP9_ID_SSC0	17	/* Serial Synchronous Controller 0 */
-#define AT91CAP9_ID_SSC1	18	/* Serial Synchronous Controller 1 */
-#define AT91CAP9_ID_AC97C	19	/* AC97 Controller */
-#define AT91CAP9_ID_TCB		20	/* Timer Counter 0, 1 and 2 */
-#define AT91CAP9_ID_PWMC	21	/* Pulse Width Modulation Controller */
-#define AT91CAP9_ID_EMAC	22	/* Ethernet */
-#define AT91CAP9_ID_AESTDES	23	/* Advanced Encryption Standard, Triple DES */
-#define AT91CAP9_ID_ADC		24	/* Analog-to-Digital Converter */
-#define AT91CAP9_ID_ISI		25	/* Image Sensor Interface */
-#define AT91CAP9_ID_LCDC	26	/* LCD Controller */
-#define AT91CAP9_ID_DMA		27	/* DMA Controller */
-#define AT91CAP9_ID_UDPHS	28	/* USB High Speed Device Port */
-#define AT91CAP9_ID_UHP		29	/* USB Host Port */
-#define AT91CAP9_ID_IRQ0	30	/* Advanced Interrupt Controller (IRQ0) */
-#define AT91CAP9_ID_IRQ1	31	/* Advanced Interrupt Controller (IRQ1) */
-
-/*
- * User Peripheral physical base addresses.
- */
-#define AT91CAP9_BASE_UDPHS		0xfff78000
-#define AT91CAP9_BASE_TCB0		0xfff7c000
-#define AT91CAP9_BASE_TC0		0xfff7c000
-#define AT91CAP9_BASE_TC1		0xfff7c040
-#define AT91CAP9_BASE_TC2		0xfff7c080
-#define AT91CAP9_BASE_MCI0		0xfff80000
-#define AT91CAP9_BASE_MCI1		0xfff84000
-#define AT91CAP9_BASE_TWI		0xfff88000
-#define AT91CAP9_BASE_US0		0xfff8c000
-#define AT91CAP9_BASE_US1		0xfff90000
-#define AT91CAP9_BASE_US2		0xfff94000
-#define AT91CAP9_BASE_SSC0		0xfff98000
-#define AT91CAP9_BASE_SSC1		0xfff9c000
-#define AT91CAP9_BASE_AC97C		0xfffa0000
-#define AT91CAP9_BASE_SPI0		0xfffa4000
-#define AT91CAP9_BASE_SPI1		0xfffa8000
-#define AT91CAP9_BASE_CAN		0xfffac000
-#define AT91CAP9_BASE_PWMC		0xfffb8000
-#define AT91CAP9_BASE_EMAC		0xfffbc000
-#define AT91CAP9_BASE_ADC		0xfffc0000
-#define AT91CAP9_BASE_ISI		0xfffc4000
-
-/*
- * System Peripherals (offset from AT91_BASE_SYS)
- */
-#define AT91_BCRAMC	(0xffffe400 - AT91_BASE_SYS)
-#define AT91_DDRSDRC0	(0xffffe600 - AT91_BASE_SYS)
-#define AT91_MATRIX	(0xffffea00 - AT91_BASE_SYS)
-#define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)
-#define AT91_GPBR	(cpu_is_at91cap9_revB() ?	\
-			(0xfffffd50 - AT91_BASE_SYS) :	\
-			(0xfffffd60 - AT91_BASE_SYS))
-
-#define AT91CAP9_BASE_ECC	0xffffe200
-#define AT91CAP9_BASE_DMA	0xffffec00
-#define AT91CAP9_BASE_SMC	0xffffe800
-#define AT91CAP9_BASE_DBGU	AT91_BASE_DBGU1
-#define AT91CAP9_BASE_PIOA	0xfffff200
-#define AT91CAP9_BASE_PIOB	0xfffff400
-#define AT91CAP9_BASE_PIOC	0xfffff600
-#define AT91CAP9_BASE_PIOD	0xfffff800
-#define AT91CAP9_BASE_RSTC	0xfffffd00
-#define AT91CAP9_BASE_SHDWC	0xfffffd10
-#define AT91CAP9_BASE_RTT	0xfffffd20
-#define AT91CAP9_BASE_PIT	0xfffffd30
-#define AT91CAP9_BASE_WDT	0xfffffd40
-
-#define AT91_USART0	AT91CAP9_BASE_US0
-#define AT91_USART1	AT91CAP9_BASE_US1
-#define AT91_USART2	AT91CAP9_BASE_US2
-
-
-/*
- * Internal Memory.
- */
-#define AT91CAP9_SRAM_BASE	0x00100000	/* Internal SRAM base address */
-#define AT91CAP9_SRAM_SIZE	(32 * SZ_1K)	/* Internal SRAM size (32Kb) */
-
-#define AT91CAP9_ROM_BASE	0x00400000	/* Internal ROM base address */
-#define AT91CAP9_ROM_SIZE	(32 * SZ_1K)	/* Internal ROM size (32Kb) */
-
-#define AT91CAP9_LCDC_BASE	0x00500000	/* LCD Controller */
-#define AT91CAP9_UDPHS_FIFO	0x00600000	/* USB High Speed Device Port */
-#define AT91CAP9_UHP_BASE	0x00700000	/* USB Host controller */
-
-#endif
diff --git a/arch/arm/mach-at91/include/mach/at91cap9_matrix.h b/arch/arm/mach-at91/include/mach/at91cap9_matrix.h
deleted file mode 100644
index 4b9d4af..0000000
--- a/arch/arm/mach-at91/include/mach/at91cap9_matrix.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91cap9_matrix.h
- *
- *  Copyright (C) 2007 Stelian Pop <stelian.pop@leadtechdesign.com>
- *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
- *  Copyright (C) 2006 Atmel Corporation.
- *
- * Memory Controllers (MATRIX, EBI) - System peripherals registers.
- * Based on AT91CAP9 datasheet revision B (Preliminary).
- *
- * 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 AT91CAP9_MATRIX_H
-#define AT91CAP9_MATRIX_H
-
-#define AT91_MATRIX_MCFG0	(AT91_MATRIX + 0x00)	/* Master Configuration Register 0 */
-#define AT91_MATRIX_MCFG1	(AT91_MATRIX + 0x04)	/* Master Configuration Register 1 */
-#define AT91_MATRIX_MCFG2	(AT91_MATRIX + 0x08)	/* Master Configuration Register 2 */
-#define AT91_MATRIX_MCFG3	(AT91_MATRIX + 0x0C)	/* Master Configuration Register 3 */
-#define AT91_MATRIX_MCFG4	(AT91_MATRIX + 0x10)	/* Master Configuration Register 4 */
-#define AT91_MATRIX_MCFG5	(AT91_MATRIX + 0x14)	/* Master Configuration Register 5 */
-#define AT91_MATRIX_MCFG6	(AT91_MATRIX + 0x18)	/* Master Configuration Register 6 */
-#define AT91_MATRIX_MCFG7	(AT91_MATRIX + 0x1C)	/* Master Configuration Register 7 */
-#define AT91_MATRIX_MCFG8	(AT91_MATRIX + 0x20)	/* Master Configuration Register 8 */
-#define AT91_MATRIX_MCFG9	(AT91_MATRIX + 0x24)	/* Master Configuration Register 9 */
-#define AT91_MATRIX_MCFG10	(AT91_MATRIX + 0x28)	/* Master Configuration Register 10 */
-#define AT91_MATRIX_MCFG11	(AT91_MATRIX + 0x2C)	/* Master Configuration Register 11 */
-#define		AT91_MATRIX_ULBT	(7 << 0)	/* Undefined Length Burst Type */
-#define			AT91_MATRIX_ULBT_INFINITE	(0 << 0)
-#define			AT91_MATRIX_ULBT_SINGLE		(1 << 0)
-#define			AT91_MATRIX_ULBT_FOUR		(2 << 0)
-#define			AT91_MATRIX_ULBT_EIGHT		(3 << 0)
-#define			AT91_MATRIX_ULBT_SIXTEEN	(4 << 0)
-
-#define AT91_MATRIX_SCFG0	(AT91_MATRIX + 0x40)	/* Slave Configuration Register 0 */
-#define AT91_MATRIX_SCFG1	(AT91_MATRIX + 0x44)	/* Slave Configuration Register 1 */
-#define AT91_MATRIX_SCFG2	(AT91_MATRIX + 0x48)	/* Slave Configuration Register 2 */
-#define AT91_MATRIX_SCFG3	(AT91_MATRIX + 0x4C)	/* Slave Configuration Register 3 */
-#define AT91_MATRIX_SCFG4	(AT91_MATRIX + 0x50)	/* Slave Configuration Register 4 */
-#define AT91_MATRIX_SCFG5	(AT91_MATRIX + 0x54)	/* Slave Configuration Register 5 */
-#define AT91_MATRIX_SCFG6	(AT91_MATRIX + 0x58)	/* Slave Configuration Register 6 */
-#define AT91_MATRIX_SCFG7	(AT91_MATRIX + 0x5C)	/* Slave Configuration Register 7 */
-#define AT91_MATRIX_SCFG8	(AT91_MATRIX + 0x60)	/* Slave Configuration Register 8 */
-#define AT91_MATRIX_SCFG9	(AT91_MATRIX + 0x64)	/* Slave Configuration Register 9 */
-#define		AT91_MATRIX_SLOT_CYCLE		(0xff << 0)	/* Maximum Number of Allowed Cycles for a Burst */
-#define		AT91_MATRIX_DEFMSTR_TYPE	(3    << 16)	/* Default Master Type */
-#define			AT91_MATRIX_DEFMSTR_TYPE_NONE	(0 << 16)
-#define			AT91_MATRIX_DEFMSTR_TYPE_LAST	(1 << 16)
-#define			AT91_MATRIX_DEFMSTR_TYPE_FIXED	(2 << 16)
-#define		AT91_MATRIX_FIXED_DEFMSTR	(0xf  << 18)	/* Fixed Index of Default Master */
-#define		AT91_MATRIX_ARBT		(3    << 24)	/* Arbitration Type */
-#define			AT91_MATRIX_ARBT_ROUND_ROBIN	(0 << 24)
-#define			AT91_MATRIX_ARBT_FIXED_PRIORITY	(1 << 24)
-
-#define AT91_MATRIX_PRAS0	(AT91_MATRIX + 0x80)	/* Priority Register A for Slave 0 */
-#define AT91_MATRIX_PRBS0	(AT91_MATRIX + 0x84)	/* Priority Register B for Slave 0 */
-#define AT91_MATRIX_PRAS1	(AT91_MATRIX + 0x88)	/* Priority Register A for Slave 1 */
-#define AT91_MATRIX_PRBS1	(AT91_MATRIX + 0x8C)	/* Priority Register B for Slave 1 */
-#define AT91_MATRIX_PRAS2	(AT91_MATRIX + 0x90)	/* Priority Register A for Slave 2 */
-#define AT91_MATRIX_PRBS2	(AT91_MATRIX + 0x94)	/* Priority Register B for Slave 2 */
-#define AT91_MATRIX_PRAS3	(AT91_MATRIX + 0x98)	/* Priority Register A for Slave 3 */
-#define AT91_MATRIX_PRBS3	(AT91_MATRIX + 0x9C)	/* Priority Register B for Slave 3 */
-#define AT91_MATRIX_PRAS4	(AT91_MATRIX + 0xA0)	/* Priority Register A for Slave 4 */
-#define AT91_MATRIX_PRBS4	(AT91_MATRIX + 0xA4)	/* Priority Register B for Slave 4 */
-#define AT91_MATRIX_PRAS5	(AT91_MATRIX + 0xA8)	/* Priority Register A for Slave 5 */
-#define AT91_MATRIX_PRBS5	(AT91_MATRIX + 0xAC)	/* Priority Register B for Slave 5 */
-#define AT91_MATRIX_PRAS6	(AT91_MATRIX + 0xB0)	/* Priority Register A for Slave 6 */
-#define AT91_MATRIX_PRBS6	(AT91_MATRIX + 0xB4)	/* Priority Register B for Slave 6 */
-#define AT91_MATRIX_PRAS7	(AT91_MATRIX + 0xB8)	/* Priority Register A for Slave 7 */
-#define AT91_MATRIX_PRBS7	(AT91_MATRIX + 0xBC)	/* Priority Register B for Slave 7 */
-#define AT91_MATRIX_PRAS8	(AT91_MATRIX + 0xC0)	/* Priority Register A for Slave 8 */
-#define AT91_MATRIX_PRBS8	(AT91_MATRIX + 0xC4)	/* Priority Register B for Slave 8 */
-#define AT91_MATRIX_PRAS9	(AT91_MATRIX + 0xC8)	/* Priority Register A for Slave 9 */
-#define AT91_MATRIX_PRBS9	(AT91_MATRIX + 0xCC)	/* Priority Register B for Slave 9 */
-#define		AT91_MATRIX_M0PR		(3 << 0)	/* Master 0 Priority */
-#define		AT91_MATRIX_M1PR		(3 << 4)	/* Master 1 Priority */
-#define		AT91_MATRIX_M2PR		(3 << 8)	/* Master 2 Priority */
-#define		AT91_MATRIX_M3PR		(3 << 12)	/* Master 3 Priority */
-#define		AT91_MATRIX_M4PR		(3 << 16)	/* Master 4 Priority */
-#define		AT91_MATRIX_M5PR		(3 << 20)	/* Master 5 Priority */
-#define		AT91_MATRIX_M6PR		(3 << 24)	/* Master 6 Priority */
-#define		AT91_MATRIX_M7PR		(3 << 28)	/* Master 7 Priority */
-#define		AT91_MATRIX_M8PR		(3 << 0)	/* Master 8 Priority (in Register B) */
-#define		AT91_MATRIX_M9PR		(3 << 4)	/* Master 9 Priority (in Register B) */
-#define		AT91_MATRIX_M10PR		(3 << 8)	/* Master 10 Priority (in Register B) */
-#define		AT91_MATRIX_M11PR		(3 << 12)	/* Master 11 Priority (in Register B) */
-
-#define AT91_MATRIX_MRCR	(AT91_MATRIX + 0x100)	/* Master Remap Control Register */
-#define		AT91_MATRIX_RCB0		(1 << 0)	/* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
-#define		AT91_MATRIX_RCB1		(1 << 1)	/* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
-#define		AT91_MATRIX_RCB2		(1 << 2)
-#define		AT91_MATRIX_RCB3		(1 << 3)
-#define		AT91_MATRIX_RCB4		(1 << 4)
-#define		AT91_MATRIX_RCB5		(1 << 5)
-#define		AT91_MATRIX_RCB6		(1 << 6)
-#define		AT91_MATRIX_RCB7		(1 << 7)
-#define		AT91_MATRIX_RCB8		(1 << 8)
-#define		AT91_MATRIX_RCB9		(1 << 9)
-#define		AT91_MATRIX_RCB10		(1 << 10)
-#define		AT91_MATRIX_RCB11		(1 << 11)
-
-#define AT91_MPBS0_SFR		(AT91_MATRIX + 0x114)	/* MPBlock Slave 0 Special Function Register */
-#define AT91_MPBS1_SFR		(AT91_MATRIX + 0x11C)	/* MPBlock Slave 1 Special Function Register */
-
-#define AT91_MATRIX_UDPHS	(AT91_MATRIX + 0x118)	/* USBHS Special Function Register [AT91CAP9 only] */
-#define		AT91_MATRIX_SELECT_UDPHS	(0 << 31)	/* select High Speed UDP */
-#define		AT91_MATRIX_SELECT_UDP		(1 << 31)	/* select standard UDP */
-#define		AT91_MATRIX_UDPHS_BYPASS_LOCK	(1 << 30)	/* bypass lock bit */
-
-#define AT91_MATRIX_EBICSA	(AT91_MATRIX + 0x120)	/* EBI Chip Select Assignment Register */
-#define		AT91_MATRIX_EBI_CS1A		(1 << 1)	/* Chip Select 1 Assignment */
-#define			AT91_MATRIX_EBI_CS1A_SMC		(0 << 1)
-#define			AT91_MATRIX_EBI_CS1A_BCRAMC		(1 << 1)
-#define		AT91_MATRIX_EBI_CS3A		(1 << 3)	/* Chip Select 3 Assignment */
-#define			AT91_MATRIX_EBI_CS3A_SMC		(0 << 3)
-#define			AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA	(1 << 3)
-#define		AT91_MATRIX_EBI_CS4A		(1 << 4)	/* Chip Select 4 Assignment */
-#define			AT91_MATRIX_EBI_CS4A_SMC		(0 << 4)
-#define			AT91_MATRIX_EBI_CS4A_SMC_CF1		(1 << 4)
-#define		AT91_MATRIX_EBI_CS5A		(1 << 5)	/* Chip Select 5 Assignment */
-#define			AT91_MATRIX_EBI_CS5A_SMC		(0 << 5)
-#define			AT91_MATRIX_EBI_CS5A_SMC_CF2		(1 << 5)
-#define		AT91_MATRIX_EBI_DBPUC		(1 << 8)	/* Data Bus Pull-up Configuration */
-#define		AT91_MATRIX_EBI_DQSPDC		(1 << 9)	/* Data Qualifier Strobe Pull-Down Configuration */
-#define		AT91_MATRIX_EBI_VDDIOMSEL	(1 << 16)	/* Memory voltage selection */
-#define			AT91_MATRIX_EBI_VDDIOMSEL_1_8V		(0 << 16)
-#define			AT91_MATRIX_EBI_VDDIOMSEL_3_3V		(1 << 16)
-
-#define AT91_MPBS2_SFR		(AT91_MATRIX + 0x12C)	/* MPBlock Slave 2 Special Function Register */
-#define AT91_MPBS3_SFR		(AT91_MATRIX + 0x130)	/* MPBlock Slave 3 Special Function Register */
-#define AT91_APB_SFR		(AT91_MATRIX + 0x134)	/* APB Bridge Special Function Register */
-
-#endif
diff --git a/arch/arm/mach-at91/include/mach/at91rm9200.h b/arch/arm/mach-at91/include/mach/at91rm9200.h
index bacb511..603e6aa 100644
--- a/arch/arm/mach-at91/include/mach/at91rm9200.h
+++ b/arch/arm/mach-at91/include/mach/at91rm9200.h
@@ -77,26 +77,22 @@
 
 
 /*
- * System Peripherals (offset from AT91_BASE_SYS)
+ * System Peripherals
  */
-#define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)	/* Power Management Controller */
-#define AT91_ST		(0xfffffd00 - AT91_BASE_SYS)	/* System Timer */
-#define AT91_MC		(0xffffff00 - AT91_BASE_SYS)	/* Memory Controllers */
-
 #define AT91RM9200_BASE_DBGU	AT91_BASE_DBGU0	/* Debug Unit */
 #define AT91RM9200_BASE_PIOA	0xfffff400	/* PIO Controller A */
 #define AT91RM9200_BASE_PIOB	0xfffff600	/* PIO Controller B */
 #define AT91RM9200_BASE_PIOC	0xfffff800	/* PIO Controller C */
 #define AT91RM9200_BASE_PIOD	0xfffffa00	/* PIO Controller D */
+#define AT91RM9200_BASE_ST	0xfffffd00	/* System Timer */
 #define AT91RM9200_BASE_RTC	0xfffffe00	/* Real-Time Clock */
+#define AT91RM9200_BASE_MC	0xffffff00	/* Memory Controllers */
 
 #define AT91_USART0	AT91RM9200_BASE_US0
 #define AT91_USART1	AT91RM9200_BASE_US1
 #define AT91_USART2	AT91RM9200_BASE_US2
 #define AT91_USART3	AT91RM9200_BASE_US3
 
-#define AT91_MATRIX	0	/* not supported */
-
 /*
  * Internal Memory.
  */
diff --git a/arch/arm/mach-at91/include/mach/at91rm9200_mc.h b/arch/arm/mach-at91/include/mach/at91rm9200_mc.h
index d34e4ed..aeaadfb 100644
--- a/arch/arm/mach-at91/include/mach/at91rm9200_mc.h
+++ b/arch/arm/mach-at91/include/mach/at91rm9200_mc.h
@@ -17,10 +17,10 @@
 #define AT91RM9200_MC_H
 
 /* Memory Controller */
-#define AT91_MC_RCR		(AT91_MC + 0x00)	/* MC Remap Control Register */
+#define AT91_MC_RCR		0x00			/* MC Remap Control Register */
 #define		AT91_MC_RCB		(1 <<  0)		/* Remap Command Bit */
 
-#define AT91_MC_ASR		(AT91_MC + 0x04)	/* MC Abort Status Register */
+#define AT91_MC_ASR		0x04			/* MC Abort Status Register */
 #define		AT91_MC_UNADD		(1 <<  0)		/* Undefined Address Abort Status */
 #define		AT91_MC_MISADD		(1 <<  1)		/* Misaligned Address Abort Status */
 #define		AT91_MC_ABTSZ		(3 <<  8)		/* Abort Size Status */
@@ -40,16 +40,16 @@
 #define		AT91_MC_SVMST2		(1 << 26)		/* Saved UHP Abort Source */
 #define		AT91_MC_SVMST3		(1 << 27)		/* Saved EMAC Abort Source */
 
-#define AT91_MC_AASR		(AT91_MC + 0x08)	/* MC Abort Address Status Register */
+#define AT91_MC_AASR		0x08			/* MC Abort Address Status Register */
 
-#define AT91_MC_MPR		(AT91_MC + 0x0c)	/* MC Master Priority Register */
+#define AT91_MC_MPR		0x0c			/* MC Master Priority Register */
 #define		AT91_MPR_MSTP0		(7 <<  0)		/* ARM920T Priority */
 #define		AT91_MPR_MSTP1		(7 <<  4)		/* PDC Priority */
 #define		AT91_MPR_MSTP2		(7 <<  8)		/* UHP Priority */
 #define		AT91_MPR_MSTP3		(7 << 12)		/* EMAC Priority */
 
 /* External Bus Interface (EBI) registers */
-#define AT91_EBI_CSA		(AT91_MC + 0x60)	/* Chip Select Assignment Register */
+#define AT91_EBI_CSA		0x60			/* Chip Select Assignment Register */
 #define		AT91_EBI_CS0A		(1 << 0)		/* Chip Select 0 Assignment */
 #define			AT91_EBI_CS0A_SMC		(0 << 0)
 #define			AT91_EBI_CS0A_BFC		(1 << 0)
@@ -66,7 +66,7 @@
 #define		AT91_EBI_DBPUC		(1 << 0)		/* Data Bus Pull-Up Configuration */
 
 /* Static Memory Controller (SMC) registers */
-#define	AT91_SMC_CSR(n)		(AT91_MC + 0x70 + ((n) * 4))/* SMC Chip Select Register */
+#define	AT91_SMC_CSR(n)		(0x70 + ((n) * 4))	/* SMC Chip Select Register */
 #define		AT91_SMC_NWS		(0x7f <<  0)		/* Number of Wait States */
 #define			AT91_SMC_NWS_(x)	((x) << 0)
 #define		AT91_SMC_WSEN		(1    <<  7)		/* Wait State Enable */
@@ -87,52 +87,8 @@
 #define		AT91_SMC_RWHOLD		(7 << 28)		/* Read & Write Signal Hold Time */
 #define			AT91_SMC_RWHOLD_(x)	((x) << 28)
 
-/* SDRAM Controller registers */
-#define AT91_SDRAMC_MR		(AT91_MC + 0x90)	/* Mode Register */
-#define		AT91_SDRAMC_MODE	(0xf << 0)		/* Command Mode */
-#define			AT91_SDRAMC_MODE_NORMAL		(0 << 0)
-#define			AT91_SDRAMC_MODE_NOP		(1 << 0)
-#define			AT91_SDRAMC_MODE_PRECHARGE	(2 << 0)
-#define			AT91_SDRAMC_MODE_LMR		(3 << 0)
-#define			AT91_SDRAMC_MODE_REFRESH	(4 << 0)
-#define		AT91_SDRAMC_DBW		(1   << 4)		/* Data Bus Width */
-#define			AT91_SDRAMC_DBW_32	(0 << 4)
-#define			AT91_SDRAMC_DBW_16	(1 << 4)
-
-#define AT91_SDRAMC_TR		(AT91_MC + 0x94)	/* Refresh Timer Register */
-#define		AT91_SDRAMC_COUNT	(0xfff << 0)		/* Refresh Timer Count */
-
-#define AT91_SDRAMC_CR		(AT91_MC + 0x98)	/* Configuration Register */
-#define		AT91_SDRAMC_NC		(3   <<  0)		/* Number of Column Bits */
-#define			AT91_SDRAMC_NC_8	(0 << 0)
-#define			AT91_SDRAMC_NC_9	(1 << 0)
-#define			AT91_SDRAMC_NC_10	(2 << 0)
-#define			AT91_SDRAMC_NC_11	(3 << 0)
-#define		AT91_SDRAMC_NR		(3   <<  2)		/* Number of Row Bits */
-#define			AT91_SDRAMC_NR_11	(0 << 2)
-#define			AT91_SDRAMC_NR_12	(1 << 2)
-#define			AT91_SDRAMC_NR_13	(2 << 2)
-#define		AT91_SDRAMC_NB		(1   <<  4)		/* Number of Banks */
-#define			AT91_SDRAMC_NB_2	(0 << 4)
-#define			AT91_SDRAMC_NB_4	(1 << 4)
-#define		AT91_SDRAMC_CAS		(3   <<  5)		/* CAS Latency */
-#define			AT91_SDRAMC_CAS_2	(2 << 5)
-#define		AT91_SDRAMC_TWR		(0xf <<  7)		/* Write Recovery Delay */
-#define		AT91_SDRAMC_TRC		(0xf << 11)		/* Row Cycle Delay */
-#define		AT91_SDRAMC_TRP		(0xf << 15)		/* Row Precharge Delay */
-#define		AT91_SDRAMC_TRCD	(0xf << 19)		/* Row to Column Delay */
-#define		AT91_SDRAMC_TRAS	(0xf << 23)		/* Active to Precharge Delay */
-#define		AT91_SDRAMC_TXSR	(0xf << 27)		/* Exit Self Refresh to Active Delay */
-
-#define AT91_SDRAMC_SRR		(AT91_MC + 0x9c)	/* Self Refresh Register */
-#define AT91_SDRAMC_LPR		(AT91_MC + 0xa0)	/* Low Power Register */
-#define AT91_SDRAMC_IER		(AT91_MC + 0xa4)	/* Interrupt Enable Register */
-#define AT91_SDRAMC_IDR		(AT91_MC + 0xa8)	/* Interrupt Disable Register */
-#define AT91_SDRAMC_IMR		(AT91_MC + 0xac)	/* Interrupt Mask Register */
-#define AT91_SDRAMC_ISR		(AT91_MC + 0xb0)	/* Interrupt Status Register */
-
 /* Burst Flash Controller register */
-#define AT91_BFC_MR		(AT91_MC + 0xc0)	/* Mode Register */
+#define AT91_BFC_MR		0xc0			/* Mode Register */
 #define		AT91_BFC_BFCOM		(3   <<  0)		/* Burst Flash Controller Operating Mode */
 #define			AT91_BFC_BFCOM_DISABLED	(0 << 0)
 #define			AT91_BFC_BFCOM_ASYNC	(1 << 0)
diff --git a/arch/arm/mach-at91/include/mach/at91rm9200_sdramc.h b/arch/arm/mach-at91/include/mach/at91rm9200_sdramc.h
new file mode 100644
index 0000000..aa047f45
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91rm9200_sdramc.h
@@ -0,0 +1,63 @@
+/*
+ * arch/arm/mach-at91/include/mach/at91rm9200_sdramc.h
+ *
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * Memory Controllers (SDRAMC only) - System peripherals registers.
+ * Based on AT91RM9200 datasheet revision E.
+ *
+ * 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 AT91RM9200_SDRAMC_H
+#define AT91RM9200_SDRAMC_H
+
+/* SDRAM Controller registers */
+#define AT91RM9200_SDRAMC_MR		0x90			/* Mode Register */
+#define		AT91RM9200_SDRAMC_MODE	(0xf << 0)		/* Command Mode */
+#define			AT91RM9200_SDRAMC_MODE_NORMAL		(0 << 0)
+#define			AT91RM9200_SDRAMC_MODE_NOP		(1 << 0)
+#define			AT91RM9200_SDRAMC_MODE_PRECHARGE	(2 << 0)
+#define			AT91RM9200_SDRAMC_MODE_LMR		(3 << 0)
+#define			AT91RM9200_SDRAMC_MODE_REFRESH	(4 << 0)
+#define		AT91RM9200_SDRAMC_DBW		(1   << 4)		/* Data Bus Width */
+#define			AT91RM9200_SDRAMC_DBW_32	(0 << 4)
+#define			AT91RM9200_SDRAMC_DBW_16	(1 << 4)
+
+#define AT91RM9200_SDRAMC_TR		0x94			/* Refresh Timer Register */
+#define		AT91RM9200_SDRAMC_COUNT	(0xfff << 0)		/* Refresh Timer Count */
+
+#define AT91RM9200_SDRAMC_CR		0x98			/* Configuration Register */
+#define		AT91RM9200_SDRAMC_NC		(3   <<  0)		/* Number of Column Bits */
+#define			AT91RM9200_SDRAMC_NC_8	(0 << 0)
+#define			AT91RM9200_SDRAMC_NC_9	(1 << 0)
+#define			AT91RM9200_SDRAMC_NC_10	(2 << 0)
+#define			AT91RM9200_SDRAMC_NC_11	(3 << 0)
+#define		AT91RM9200_SDRAMC_NR		(3   <<  2)		/* Number of Row Bits */
+#define			AT91RM9200_SDRAMC_NR_11	(0 << 2)
+#define			AT91RM9200_SDRAMC_NR_12	(1 << 2)
+#define			AT91RM9200_SDRAMC_NR_13	(2 << 2)
+#define		AT91RM9200_SDRAMC_NB		(1   <<  4)		/* Number of Banks */
+#define			AT91RM9200_SDRAMC_NB_2	(0 << 4)
+#define			AT91RM9200_SDRAMC_NB_4	(1 << 4)
+#define		AT91RM9200_SDRAMC_CAS		(3   <<  5)		/* CAS Latency */
+#define			AT91RM9200_SDRAMC_CAS_2	(2 << 5)
+#define		AT91RM9200_SDRAMC_TWR		(0xf <<  7)		/* Write Recovery Delay */
+#define		AT91RM9200_SDRAMC_TRC		(0xf << 11)		/* Row Cycle Delay */
+#define		AT91RM9200_SDRAMC_TRP		(0xf << 15)		/* Row Precharge Delay */
+#define		AT91RM9200_SDRAMC_TRCD	(0xf << 19)		/* Row to Column Delay */
+#define		AT91RM9200_SDRAMC_TRAS	(0xf << 23)		/* Active to Precharge Delay */
+#define		AT91RM9200_SDRAMC_TXSR	(0xf << 27)		/* Exit Self Refresh to Active Delay */
+
+#define AT91RM9200_SDRAMC_SRR		0x9c			/* Self Refresh Register */
+#define AT91RM9200_SDRAMC_LPR		0xa0			/* Low Power Register */
+#define AT91RM9200_SDRAMC_IER		0xa4			/* Interrupt Enable Register */
+#define AT91RM9200_SDRAMC_IDR		0xa8			/* Interrupt Disable Register */
+#define AT91RM9200_SDRAMC_IMR		0xac			/* Interrupt Mask Register */
+#define AT91RM9200_SDRAMC_ISR		0xb0			/* Interrupt Status Register */
+
+#endif
diff --git a/arch/arm/mach-at91/include/mach/at91sam9260.h b/arch/arm/mach-at91/include/mach/at91sam9260.h
index fa5ca27..08ae9af 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9260.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9260.h
@@ -78,15 +78,12 @@
 #define AT91SAM9260_BASE_ADC		0xfffe0000
 
 /*
- * System Peripherals (offset from AT91_BASE_SYS)
+ * System Peripherals
  */
-#define AT91_SDRAMC0	(0xffffea00 - AT91_BASE_SYS)
-#define AT91_MATRIX	(0xffffee00 - AT91_BASE_SYS)
-#define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)
-#define AT91_GPBR	(0xfffffd50 - AT91_BASE_SYS)
-
 #define AT91SAM9260_BASE_ECC	0xffffe800
+#define AT91SAM9260_BASE_SDRAMC	0xffffea00
 #define AT91SAM9260_BASE_SMC	0xffffec00
+#define AT91SAM9260_BASE_MATRIX	0xffffee00
 #define AT91SAM9260_BASE_DBGU	AT91_BASE_DBGU0
 #define AT91SAM9260_BASE_PIOA	0xfffff400
 #define AT91SAM9260_BASE_PIOB	0xfffff600
@@ -96,6 +93,7 @@
 #define AT91SAM9260_BASE_RTT	0xfffffd20
 #define AT91SAM9260_BASE_PIT	0xfffffd30
 #define AT91SAM9260_BASE_WDT	0xfffffd40
+#define AT91SAM9260_BASE_GPBR	0xfffffd50
 
 #define AT91_USART0	AT91SAM9260_BASE_US0
 #define AT91_USART1	AT91SAM9260_BASE_US1
@@ -115,6 +113,8 @@
 #define AT91SAM9260_SRAM0_SIZE	SZ_4K		/* Internal SRAM 0 size (4Kb) */
 #define AT91SAM9260_SRAM1_BASE	0x00300000	/* Internal SRAM 1 base address */
 #define AT91SAM9260_SRAM1_SIZE	SZ_4K		/* Internal SRAM 1 size (4Kb) */
+#define AT91SAM9260_SRAM_BASE	0x002FF000	/* Internal SRAM base address */
+#define AT91SAM9260_SRAM_SIZE	SZ_8K		/* Internal SRAM size (8Kb) */
 
 #define AT91SAM9260_UHP_BASE	0x00500000	/* USB Host controller */
 
@@ -128,6 +128,8 @@
 #define AT91SAM9G20_SRAM0_SIZE	SZ_16K		/* Internal SRAM 0 size (16Kb) */
 #define AT91SAM9G20_SRAM1_BASE	0x00300000	/* Internal SRAM 1 base address */
 #define AT91SAM9G20_SRAM1_SIZE	SZ_16K		/* Internal SRAM 1 size (16Kb) */
+#define AT91SAM9G20_SRAM_BASE	0x002FC000	/* Internal SRAM base address */
+#define AT91SAM9G20_SRAM_SIZE	SZ_32K		/* Internal SRAM size (32Kb) */
 
 #define AT91SAM9G20_UHP_BASE	0x00500000	/* USB Host controller */
 
diff --git a/arch/arm/mach-at91/include/mach/at91sam9260_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9260_matrix.h
index 020f02e..f459df4 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9260_matrix.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9260_matrix.h
@@ -15,12 +15,12 @@
 #ifndef AT91SAM9260_MATRIX_H
 #define AT91SAM9260_MATRIX_H
 
-#define AT91_MATRIX_MCFG0	(AT91_MATRIX + 0x00)	/* Master Configuration Register 0 */
-#define AT91_MATRIX_MCFG1	(AT91_MATRIX + 0x04)	/* Master Configuration Register 1 */
-#define AT91_MATRIX_MCFG2	(AT91_MATRIX + 0x08)	/* Master Configuration Register 2 */
-#define AT91_MATRIX_MCFG3	(AT91_MATRIX + 0x0C)	/* Master Configuration Register 3 */
-#define AT91_MATRIX_MCFG4	(AT91_MATRIX + 0x10)	/* Master Configuration Register 4 */
-#define AT91_MATRIX_MCFG5	(AT91_MATRIX + 0x14)	/* Master Configuration Register 5 */
+#define AT91_MATRIX_MCFG0	0x00			/* Master Configuration Register 0 */
+#define AT91_MATRIX_MCFG1	0x04			/* Master Configuration Register 1 */
+#define AT91_MATRIX_MCFG2	0x08			/* Master Configuration Register 2 */
+#define AT91_MATRIX_MCFG3	0x0C			/* Master Configuration Register 3 */
+#define AT91_MATRIX_MCFG4	0x10			/* Master Configuration Register 4 */
+#define AT91_MATRIX_MCFG5	0x14			/* Master Configuration Register 5 */
 #define		AT91_MATRIX_ULBT		(7 << 0)	/* Undefined Length Burst Type */
 #define			AT91_MATRIX_ULBT_INFINITE	(0 << 0)
 #define			AT91_MATRIX_ULBT_SINGLE		(1 << 0)
@@ -28,11 +28,11 @@
 #define			AT91_MATRIX_ULBT_EIGHT		(3 << 0)
 #define			AT91_MATRIX_ULBT_SIXTEEN	(4 << 0)
 
-#define AT91_MATRIX_SCFG0	(AT91_MATRIX + 0x40)	/* Slave Configuration Register 0 */
-#define AT91_MATRIX_SCFG1	(AT91_MATRIX + 0x44)	/* Slave Configuration Register 1 */
-#define AT91_MATRIX_SCFG2	(AT91_MATRIX + 0x48)	/* Slave Configuration Register 2 */
-#define AT91_MATRIX_SCFG3	(AT91_MATRIX + 0x4C)	/* Slave Configuration Register 3 */
-#define AT91_MATRIX_SCFG4	(AT91_MATRIX + 0x50)	/* Slave Configuration Register 4 */
+#define AT91_MATRIX_SCFG0	0x40			/* Slave Configuration Register 0 */
+#define AT91_MATRIX_SCFG1	0x44			/* Slave Configuration Register 1 */
+#define AT91_MATRIX_SCFG2	0x48			/* Slave Configuration Register 2 */
+#define AT91_MATRIX_SCFG3	0x4C			/* Slave Configuration Register 3 */
+#define AT91_MATRIX_SCFG4	0x50			/* Slave Configuration Register 4 */
 #define		AT91_MATRIX_SLOT_CYCLE		(0xff <<  0)	/* Maximum Number of Allowed Cycles for a Burst */
 #define		AT91_MATRIX_DEFMSTR_TYPE	(3    << 16)	/* Default Master Type */
 #define			AT91_MATRIX_DEFMSTR_TYPE_NONE	(0 << 16)
@@ -43,11 +43,11 @@
 #define			AT91_MATRIX_ARBT_ROUND_ROBIN	(0 << 24)
 #define			AT91_MATRIX_ARBT_FIXED_PRIORITY	(1 << 24)
 
-#define AT91_MATRIX_PRAS0	(AT91_MATRIX + 0x80)	/* Priority Register A for Slave 0 */
-#define AT91_MATRIX_PRAS1	(AT91_MATRIX + 0x88)	/* Priority Register A for Slave 1 */
-#define AT91_MATRIX_PRAS2	(AT91_MATRIX + 0x90)	/* Priority Register A for Slave 2 */
-#define AT91_MATRIX_PRAS3	(AT91_MATRIX + 0x98)	/* Priority Register A for Slave 3 */
-#define AT91_MATRIX_PRAS4	(AT91_MATRIX + 0xA0)	/* Priority Register A for Slave 4 */
+#define AT91_MATRIX_PRAS0	0x80			/* Priority Register A for Slave 0 */
+#define AT91_MATRIX_PRAS1	0x88			/* Priority Register A for Slave 1 */
+#define AT91_MATRIX_PRAS2	0x90			/* Priority Register A for Slave 2 */
+#define AT91_MATRIX_PRAS3	0x98			/* Priority Register A for Slave 3 */
+#define AT91_MATRIX_PRAS4	0xA0			/* Priority Register A for Slave 4 */
 #define		AT91_MATRIX_M0PR		(3 << 0)	/* Master 0 Priority */
 #define		AT91_MATRIX_M1PR		(3 << 4)	/* Master 1 Priority */
 #define		AT91_MATRIX_M2PR		(3 << 8)	/* Master 2 Priority */
@@ -55,11 +55,11 @@
 #define		AT91_MATRIX_M4PR		(3 << 16)	/* Master 4 Priority */
 #define		AT91_MATRIX_M5PR		(3 << 20)	/* Master 5 Priority */
 
-#define AT91_MATRIX_MRCR	(AT91_MATRIX + 0x100)	/* Master Remap Control Register */
+#define AT91_MATRIX_MRCR	0x100			/* Master Remap Control Register */
 #define		AT91_MATRIX_RCB0		(1 << 0)	/* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
 #define		AT91_MATRIX_RCB1		(1 << 1)	/* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
 
-#define AT91_MATRIX_EBICSA	(AT91_MATRIX + 0x11C)	/* EBI Chip Select Assignment Register */
+#define AT91_MATRIX_EBICSA	0x11C			/* EBI Chip Select Assignment Register */
 #define		AT91_MATRIX_CS1A		(1 << 1)	/* Chip Select 1 Assignment */
 #define			AT91_MATRIX_CS1A_SMC		(0 << 1)
 #define			AT91_MATRIX_CS1A_SDRAMC		(1 << 1)
diff --git a/arch/arm/mach-at91/include/mach/at91sam9261.h b/arch/arm/mach-at91/include/mach/at91sam9261.h
index 7cde2d3..44fbdc1 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9261.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9261.h
@@ -63,14 +63,11 @@
 
 
 /*
- * System Peripherals (offset from AT91_BASE_SYS)
+ * System Peripherals
  */
-#define AT91_SDRAMC0	(0xffffea00 - AT91_BASE_SYS)
-#define AT91_MATRIX	(0xffffee00 - AT91_BASE_SYS)
-#define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)
-#define AT91_GPBR	(0xfffffd50 - AT91_BASE_SYS)
-
 #define AT91SAM9261_BASE_SMC	0xffffec00
+#define AT91SAM9261_BASE_MATRIX	0xffffee00
+#define AT91SAM9261_BASE_SDRAMC	0xffffea00
 #define AT91SAM9261_BASE_DBGU	AT91_BASE_DBGU0
 #define AT91SAM9261_BASE_PIOA	0xfffff400
 #define AT91SAM9261_BASE_PIOB	0xfffff600
@@ -80,6 +77,7 @@
 #define AT91SAM9261_BASE_RTT	0xfffffd20
 #define AT91SAM9261_BASE_PIT	0xfffffd30
 #define AT91SAM9261_BASE_WDT	0xfffffd40
+#define AT91SAM9261_BASE_GPBR	0xfffffd50
 
 #define AT91_USART0	AT91SAM9261_BASE_US0
 #define AT91_USART1	AT91SAM9261_BASE_US1
diff --git a/arch/arm/mach-at91/include/mach/at91sam9261_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9261_matrix.h
index 69c6501..a50cdf8 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9261_matrix.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9261_matrix.h
@@ -15,15 +15,15 @@
 #ifndef AT91SAM9261_MATRIX_H
 #define AT91SAM9261_MATRIX_H
 
-#define AT91_MATRIX_MCFG	(AT91_MATRIX + 0x00)	/* Master Configuration Register */
+#define AT91_MATRIX_MCFG	0x00			/* Master Configuration Register */
 #define		AT91_MATRIX_RCB0	(1 << 0)		/* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
 #define		AT91_MATRIX_RCB1	(1 << 1)		/* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
 
-#define AT91_MATRIX_SCFG0	(AT91_MATRIX + 0x04)	/* Slave Configuration Register 0 */
-#define AT91_MATRIX_SCFG1	(AT91_MATRIX + 0x08)	/* Slave Configuration Register 1 */
-#define AT91_MATRIX_SCFG2	(AT91_MATRIX + 0x0C)	/* Slave Configuration Register 2 */
-#define AT91_MATRIX_SCFG3	(AT91_MATRIX + 0x10)	/* Slave Configuration Register 3 */
-#define AT91_MATRIX_SCFG4	(AT91_MATRIX + 0x14)	/* Slave Configuration Register 4 */
+#define AT91_MATRIX_SCFG0	0x04			/* Slave Configuration Register 0 */
+#define AT91_MATRIX_SCFG1	0x08			/* Slave Configuration Register 1 */
+#define AT91_MATRIX_SCFG2	0x0C			/* Slave Configuration Register 2 */
+#define AT91_MATRIX_SCFG3	0x10			/* Slave Configuration Register 3 */
+#define AT91_MATRIX_SCFG4	0x14			/* Slave Configuration Register 4 */
 #define		AT91_MATRIX_SLOT_CYCLE		(0xff << 0)	/* Maximum Number of Allowed Cycles for a Burst */
 #define		AT91_MATRIX_DEFMSTR_TYPE	(3    << 16)	/* Default Master Type */
 #define			AT91_MATRIX_DEFMSTR_TYPE_NONE	(0 << 16)
@@ -31,7 +31,7 @@
 #define			AT91_MATRIX_DEFMSTR_TYPE_FIXED	(2 << 16)
 #define		AT91_MATRIX_FIXED_DEFMSTR	(7    << 18)	/* Fixed Index of Default Master */
 
-#define AT91_MATRIX_TCR		(AT91_MATRIX + 0x24)	/* TCM Configuration Register */
+#define AT91_MATRIX_TCR		0x24			/* TCM Configuration Register */
 #define		AT91_MATRIX_ITCM_SIZE		(0xf << 0)	/* Size of ITCM enabled memory block */
 #define			AT91_MATRIX_ITCM_0		(0 << 0)
 #define			AT91_MATRIX_ITCM_16		(5 << 0)
@@ -43,7 +43,7 @@
 #define			AT91_MATRIX_DTCM_32		(6 << 4)
 #define			AT91_MATRIX_DTCM_64		(7 << 4)
 
-#define AT91_MATRIX_EBICSA	(AT91_MATRIX + 0x30)	/* EBI Chip Select Assignment Register */
+#define AT91_MATRIX_EBICSA	0x30			/* EBI Chip Select Assignment Register */
 #define		AT91_MATRIX_CS1A		(1 << 1)	/* Chip Select 1 Assignment */
 #define			AT91_MATRIX_CS1A_SMC		(0 << 1)
 #define			AT91_MATRIX_CS1A_SDRAMC		(1 << 1)
@@ -58,7 +58,7 @@
 #define			AT91_MATRIX_CS5A_SMC_CF2	(1 << 5)
 #define		AT91_MATRIX_DBPUC		(1 << 8)	/* Data Bus Pull-up Configuration */
 
-#define AT91_MATRIX_USBPUCR	(AT91_MATRIX + 0x34)	/* USB Pad Pull-Up Control Register */
+#define AT91_MATRIX_USBPUCR	0x34			/* USB Pad Pull-Up Control Register */
 #define		AT91_MATRIX_USBPUCR_PUON	(1 << 30)	/* USB Device PAD Pull-up Enable */
 
 #endif
diff --git a/arch/arm/mach-at91/include/mach/at91sam9263.h b/arch/arm/mach-at91/include/mach/at91sam9263.h
index 5949abd..d96cbb2 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9263.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9263.h
@@ -72,18 +72,15 @@
 #define AT91SAM9263_BASE_2DGE		0xfffc8000
 
 /*
- * System Peripherals (offset from AT91_BASE_SYS)
+ * System Peripherals
  */
-#define AT91_SDRAMC0	(0xffffe200 - AT91_BASE_SYS)
-#define AT91_SDRAMC1	(0xffffe800 - AT91_BASE_SYS)
-#define AT91_MATRIX	(0xffffec00 - AT91_BASE_SYS)
-#define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)
-#define AT91_GPBR	(0xfffffd60 - AT91_BASE_SYS)
-
 #define AT91SAM9263_BASE_ECC0	0xffffe000
+#define AT91SAM9263_BASE_SDRAMC0 0xffffe200
 #define AT91SAM9263_BASE_SMC0	0xffffe400
 #define AT91SAM9263_BASE_ECC1	0xffffe600
+#define AT91SAM9263_BASE_SDRAMC1 0xffffe800
 #define AT91SAM9263_BASE_SMC1	0xffffea00
+#define AT91SAM9263_BASE_MATRIX	0xffffec00
 #define AT91SAM9263_BASE_DBGU	AT91_BASE_DBGU1
 #define AT91SAM9263_BASE_PIOA	0xfffff200
 #define AT91SAM9263_BASE_PIOB	0xfffff400
@@ -96,6 +93,7 @@
 #define AT91SAM9263_BASE_PIT	0xfffffd30
 #define AT91SAM9263_BASE_WDT	0xfffffd40
 #define AT91SAM9263_BASE_RTT1	0xfffffd50
+#define AT91SAM9263_BASE_GPBR	0xfffffd60
 
 #define AT91_USART0	AT91SAM9263_BASE_US0
 #define AT91_USART1	AT91SAM9263_BASE_US1
diff --git a/arch/arm/mach-at91/include/mach/at91sam9263_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9263_matrix.h
index 9b3efd3..ebb5fdb 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9263_matrix.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9263_matrix.h
@@ -15,15 +15,15 @@
 #ifndef AT91SAM9263_MATRIX_H
 #define AT91SAM9263_MATRIX_H
 
-#define AT91_MATRIX_MCFG0	(AT91_MATRIX + 0x00)	/* Master Configuration Register 0 */
-#define AT91_MATRIX_MCFG1	(AT91_MATRIX + 0x04)	/* Master Configuration Register 1 */
-#define AT91_MATRIX_MCFG2	(AT91_MATRIX + 0x08)	/* Master Configuration Register 2 */
-#define AT91_MATRIX_MCFG3	(AT91_MATRIX + 0x0C)	/* Master Configuration Register 3 */
-#define AT91_MATRIX_MCFG4	(AT91_MATRIX + 0x10)	/* Master Configuration Register 4 */
-#define AT91_MATRIX_MCFG5	(AT91_MATRIX + 0x14)	/* Master Configuration Register 5 */
-#define AT91_MATRIX_MCFG6	(AT91_MATRIX + 0x18)	/* Master Configuration Register 6 */
-#define AT91_MATRIX_MCFG7	(AT91_MATRIX + 0x1C)	/* Master Configuration Register 7 */
-#define AT91_MATRIX_MCFG8	(AT91_MATRIX + 0x20)	/* Master Configuration Register 8 */
+#define AT91_MATRIX_MCFG0	0x00			/* Master Configuration Register 0 */
+#define AT91_MATRIX_MCFG1	0x04			/* Master Configuration Register 1 */
+#define AT91_MATRIX_MCFG2	0x08			/* Master Configuration Register 2 */
+#define AT91_MATRIX_MCFG3	0x0C			/* Master Configuration Register 3 */
+#define AT91_MATRIX_MCFG4	0x10			/* Master Configuration Register 4 */
+#define AT91_MATRIX_MCFG5	0x14			/* Master Configuration Register 5 */
+#define AT91_MATRIX_MCFG6	0x18			/* Master Configuration Register 6 */
+#define AT91_MATRIX_MCFG7	0x1C			/* Master Configuration Register 7 */
+#define AT91_MATRIX_MCFG8	0x20			/* Master Configuration Register 8 */
 #define		AT91_MATRIX_ULBT	(7 << 0)	/* Undefined Length Burst Type */
 #define			AT91_MATRIX_ULBT_INFINITE	(0 << 0)
 #define			AT91_MATRIX_ULBT_SINGLE		(1 << 0)
@@ -31,14 +31,14 @@
 #define			AT91_MATRIX_ULBT_EIGHT		(3 << 0)
 #define			AT91_MATRIX_ULBT_SIXTEEN	(4 << 0)
 
-#define AT91_MATRIX_SCFG0	(AT91_MATRIX + 0x40)	/* Slave Configuration Register 0 */
-#define AT91_MATRIX_SCFG1	(AT91_MATRIX + 0x44)	/* Slave Configuration Register 1 */
-#define AT91_MATRIX_SCFG2	(AT91_MATRIX + 0x48)	/* Slave Configuration Register 2 */
-#define AT91_MATRIX_SCFG3	(AT91_MATRIX + 0x4C)	/* Slave Configuration Register 3 */
-#define AT91_MATRIX_SCFG4	(AT91_MATRIX + 0x50)	/* Slave Configuration Register 4 */
-#define AT91_MATRIX_SCFG5	(AT91_MATRIX + 0x54)	/* Slave Configuration Register 5 */
-#define AT91_MATRIX_SCFG6	(AT91_MATRIX + 0x58)	/* Slave Configuration Register 6 */
-#define AT91_MATRIX_SCFG7	(AT91_MATRIX + 0x5C)	/* Slave Configuration Register 7 */
+#define AT91_MATRIX_SCFG0	0x40			/* Slave Configuration Register 0 */
+#define AT91_MATRIX_SCFG1	0x44			/* Slave Configuration Register 1 */
+#define AT91_MATRIX_SCFG2	0x48			/* Slave Configuration Register 2 */
+#define AT91_MATRIX_SCFG3	0x4C			/* Slave Configuration Register 3 */
+#define AT91_MATRIX_SCFG4	0x50			/* Slave Configuration Register 4 */
+#define AT91_MATRIX_SCFG5	0x54			/* Slave Configuration Register 5 */
+#define AT91_MATRIX_SCFG6	0x58			/* Slave Configuration Register 6 */
+#define AT91_MATRIX_SCFG7	0x5C			/* Slave Configuration Register 7 */
 #define		AT91_MATRIX_SLOT_CYCLE		(0xff << 0)	/* Maximum Number of Allowed Cycles for a Burst */
 #define		AT91_MATRIX_DEFMSTR_TYPE	(3    << 16)	/* Default Master Type */
 #define			AT91_MATRIX_DEFMSTR_TYPE_NONE	(0 << 16)
@@ -49,22 +49,22 @@
 #define			AT91_MATRIX_ARBT_ROUND_ROBIN	(0 << 24)
 #define			AT91_MATRIX_ARBT_FIXED_PRIORITY	(1 << 24)
 
-#define AT91_MATRIX_PRAS0	(AT91_MATRIX + 0x80)	/* Priority Register A for Slave 0 */
-#define AT91_MATRIX_PRBS0	(AT91_MATRIX + 0x84)	/* Priority Register B for Slave 0 */
-#define AT91_MATRIX_PRAS1	(AT91_MATRIX + 0x88)	/* Priority Register A for Slave 1 */
-#define AT91_MATRIX_PRBS1	(AT91_MATRIX + 0x8C)	/* Priority Register B for Slave 1 */
-#define AT91_MATRIX_PRAS2	(AT91_MATRIX + 0x90)	/* Priority Register A for Slave 2 */
-#define AT91_MATRIX_PRBS2	(AT91_MATRIX + 0x94)	/* Priority Register B for Slave 2 */
-#define AT91_MATRIX_PRAS3	(AT91_MATRIX + 0x98)	/* Priority Register A for Slave 3 */
-#define AT91_MATRIX_PRBS3	(AT91_MATRIX + 0x9C)	/* Priority Register B for Slave 3 */
-#define AT91_MATRIX_PRAS4	(AT91_MATRIX + 0xA0)	/* Priority Register A for Slave 4 */
-#define AT91_MATRIX_PRBS4	(AT91_MATRIX + 0xA4)	/* Priority Register B for Slave 4 */
-#define AT91_MATRIX_PRAS5	(AT91_MATRIX + 0xA8)	/* Priority Register A for Slave 5 */
-#define AT91_MATRIX_PRBS5	(AT91_MATRIX + 0xAC)	/* Priority Register B for Slave 5 */
-#define AT91_MATRIX_PRAS6	(AT91_MATRIX + 0xB0)	/* Priority Register A for Slave 6 */
-#define AT91_MATRIX_PRBS6	(AT91_MATRIX + 0xB4)	/* Priority Register B for Slave 6 */
-#define AT91_MATRIX_PRAS7	(AT91_MATRIX + 0xB8)	/* Priority Register A for Slave 7 */
-#define AT91_MATRIX_PRBS7	(AT91_MATRIX + 0xBC)	/* Priority Register B for Slave 7 */
+#define AT91_MATRIX_PRAS0	0x80			/* Priority Register A for Slave 0 */
+#define AT91_MATRIX_PRBS0	0x84			/* Priority Register B for Slave 0 */
+#define AT91_MATRIX_PRAS1	0x88			/* Priority Register A for Slave 1 */
+#define AT91_MATRIX_PRBS1	0x8C			/* Priority Register B for Slave 1 */
+#define AT91_MATRIX_PRAS2	0x90			/* Priority Register A for Slave 2 */
+#define AT91_MATRIX_PRBS2	0x94			/* Priority Register B for Slave 2 */
+#define AT91_MATRIX_PRAS3	0x98			/* Priority Register A for Slave 3 */
+#define AT91_MATRIX_PRBS3	0x9C			/* Priority Register B for Slave 3 */
+#define AT91_MATRIX_PRAS4	0xA0			/* Priority Register A for Slave 4 */
+#define AT91_MATRIX_PRBS4	0xA4			/* Priority Register B for Slave 4 */
+#define AT91_MATRIX_PRAS5	0xA8			/* Priority Register A for Slave 5 */
+#define AT91_MATRIX_PRBS5	0xAC			/* Priority Register B for Slave 5 */
+#define AT91_MATRIX_PRAS6	0xB0			/* Priority Register A for Slave 6 */
+#define AT91_MATRIX_PRBS6	0xB4			/* Priority Register B for Slave 6 */
+#define AT91_MATRIX_PRAS7	0xB8			/* Priority Register A for Slave 7 */
+#define AT91_MATRIX_PRBS7	0xBC			/* Priority Register B for Slave 7 */
 #define		AT91_MATRIX_M0PR		(3 << 0)	/* Master 0 Priority */
 #define		AT91_MATRIX_M1PR		(3 << 4)	/* Master 1 Priority */
 #define		AT91_MATRIX_M2PR		(3 << 8)	/* Master 2 Priority */
@@ -75,7 +75,7 @@
 #define		AT91_MATRIX_M7PR		(3 << 28)	/* Master 7 Priority */
 #define		AT91_MATRIX_M8PR		(3 << 0)	/* Master 8 Priority (in Register B) */
 
-#define AT91_MATRIX_MRCR	(AT91_MATRIX + 0x100)	/* Master Remap Control Register */
+#define AT91_MATRIX_MRCR	0x100			/* Master Remap Control Register */
 #define		AT91_MATRIX_RCB0		(1 << 0)	/* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
 #define		AT91_MATRIX_RCB1		(1 << 1)	/* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
 #define		AT91_MATRIX_RCB2		(1 << 2)
@@ -86,7 +86,7 @@
 #define		AT91_MATRIX_RCB7		(1 << 7)
 #define		AT91_MATRIX_RCB8		(1 << 8)
 
-#define AT91_MATRIX_TCMR	(AT91_MATRIX + 0x114)	/* TCM Configuration Register */
+#define AT91_MATRIX_TCMR	0x114			/* TCM Configuration Register */
 #define		AT91_MATRIX_ITCM_SIZE		(0xf << 0)	/* Size of ITCM enabled memory block */
 #define			AT91_MATRIX_ITCM_0		(0 << 0)
 #define			AT91_MATRIX_ITCM_16		(5 << 0)
@@ -96,7 +96,7 @@
 #define			AT91_MATRIX_DTCM_16		(5 << 4)
 #define			AT91_MATRIX_DTCM_32		(6 << 4)
 
-#define AT91_MATRIX_EBI0CSA	(AT91_MATRIX + 0x120)	/* EBI0 Chip Select Assignment Register */
+#define AT91_MATRIX_EBI0CSA	0x120			/* EBI0 Chip Select Assignment Register */
 #define		AT91_MATRIX_EBI0_CS1A		(1 << 1)	/* Chip Select 1 Assignment */
 #define			AT91_MATRIX_EBI0_CS1A_SMC		(0 << 1)
 #define			AT91_MATRIX_EBI0_CS1A_SDRAMC		(1 << 1)
@@ -114,7 +114,7 @@
 #define			AT91_MATRIX_EBI0_VDDIOMSEL_1_8V		(0 << 16)
 #define			AT91_MATRIX_EBI0_VDDIOMSEL_3_3V		(1 << 16)
 
-#define AT91_MATRIX_EBI1CSA	(AT91_MATRIX + 0x124)	/* EBI1 Chip Select Assignment Register */
+#define AT91_MATRIX_EBI1CSA	0x124			/* EBI1 Chip Select Assignment Register */
 #define		AT91_MATRIX_EBI1_CS1A		(1 << 1)	/* Chip Select 1 Assignment */
 #define			AT91_MATRIX_EBI1_CS1A_SMC		(0 << 1)
 #define			AT91_MATRIX_EBI1_CS1A_SDRAMC		(1 << 1)
diff --git a/arch/arm/mach-at91/include/mach/at91sam9_ddrsdr.h b/arch/arm/mach-at91/include/mach/at91sam9_ddrsdr.h
index e2f8da8..0210797 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9_ddrsdr.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9_ddrsdr.h
@@ -59,7 +59,6 @@
 #define		AT91_DDRSDRC_TRP	(0xf << 16)		/* Row precharge delay */
 #define		AT91_DDRSDRC_TRRD	(0xf << 20)		/* Active BankA to BankB */
 #define		AT91_DDRSDRC_TWTR	(0x7 << 24)		/* Internal Write to Read delay */
-#define		AT91CAP9_DDRSDRC_TWTR	(1   << 24)		/* Internal Write to Read delay */
 #define		AT91_DDRSDRC_RED_WRRD	(0x1 << 27)		/* Reduce Write to Read Delay [SAM9 Only] */
 #define		AT91_DDRSDRC_TMRD	(0xf << 28)		/* Load mode to active/refresh delay */
 
@@ -76,7 +75,6 @@
 #define		AT91_DDRSDRC_TRTP	(0x7  << 12)		/* Read to Precharge delay */
 
 #define AT91_DDRSDRC_LPR	0x1C	/* Low Power Register */
-#define AT91CAP9_DDRSDRC_LPR	0x18	/* Low Power Register */
 #define		AT91_DDRSDRC_LPCB	(3 << 0)		/* Low-power Configurations */
 #define			AT91_DDRSDRC_LPCB_DISABLE		0
 #define			AT91_DDRSDRC_LPCB_SELF_REFRESH		1
@@ -94,11 +92,9 @@
 #define		AT91_DDRSDRC_UPD_MR	(3 << 20)	 /* Update load mode register and extended mode register */
 
 #define AT91_DDRSDRC_MDR	0x20	/* Memory Device Register */
-#define AT91CAP9_DDRSDRC_MDR	0x1C	/* Memory Device Register */
 #define		AT91_DDRSDRC_MD		(3 << 0)		/* Memory Device Type */
 #define			AT91_DDRSDRC_MD_SDR		0
 #define			AT91_DDRSDRC_MD_LOW_POWER_SDR	1
-#define			AT91CAP9_DDRSDRC_MD_DDR		2
 #define			AT91_DDRSDRC_MD_LOW_POWER_DDR	3
 #define			AT91_DDRSDRC_MD_DDR2		6	/* [SAM9 Only] */
 #define		AT91_DDRSDRC_DBW	(1 << 4)		/* Data Bus Width */
@@ -106,16 +102,10 @@
 #define			AT91_DDRSDRC_DBW_16BITS		(1 <<  4)
 
 #define AT91_DDRSDRC_DLL	0x24	/* DLL Information Register */
-#define AT91CAP9_DDRSDRC_DLL	0x20	/* DLL Information Register */
 #define		AT91_DDRSDRC_MDINC	(1 << 0)		/* Master Delay increment */
 #define		AT91_DDRSDRC_MDDEC	(1 << 1)		/* Master Delay decrement */
 #define		AT91_DDRSDRC_MDOVF	(1 << 2)		/* Master Delay Overflow */
-#define		AT91CAP9_DDRSDRC_SDCOVF	(1 << 3)		/* Slave Delay Correction Overflow */
-#define		AT91CAP9_DDRSDRC_SDCUDF	(1 << 4)		/* Slave Delay Correction Underflow */
-#define		AT91CAP9_DDRSDRC_SDERF	(1 << 5)		/* Slave Delay Correction error */
 #define		AT91_DDRSDRC_MDVAL	(0xff <<  8)		/* Master Delay value */
-#define		AT91CAP9_DDRSDRC_SDVAL	(0xff << 16)		/* Slave Delay value */
-#define		AT91CAP9_DDRSDRC_SDCVAL	(0xff << 24)		/* Slave Delay Correction value */
 
 #define AT91_DDRSDRC_HS		0x2C	/* High Speed Register [SAM9 Only] */
 #define		AT91_DDRSDRC_DIS_ATCP_RD	(1 << 2)	/* Anticip read access is disabled */
@@ -131,10 +121,4 @@
 #define		AT91_DDRSDRC_WPVS	(1 << 0)		/* Write protect violation status */
 #define		AT91_DDRSDRC_WPVSRC	(0xffff << 8)		/* Write protect violation source */
 
-/* Register access macros */
-#define at91_ramc_read(num, reg) \
-	at91_sys_read(AT91_DDRSDRC##num + reg)
-#define at91_ramc_write(num, reg, value) \
-	at91_sys_write(AT91_DDRSDRC##num + reg, value)
-
 #endif
diff --git a/arch/arm/mach-at91/include/mach/at91sam9_sdramc.h b/arch/arm/mach-at91/include/mach/at91sam9_sdramc.h
index 100f5a5..3d085a9 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9_sdramc.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9_sdramc.h
@@ -82,10 +82,4 @@
 #define			AT91_SDRAMC_MD_SDRAM		0
 #define			AT91_SDRAMC_MD_LOW_POWER_SDRAM	1
 
-/* Register access macros */
-#define at91_ramc_read(num, reg) \
-	at91_sys_read(AT91_SDRAMC##num + reg)
-#define at91_ramc_write(num, reg, value) \
-	at91_sys_write(AT91_SDRAMC##num + reg, value)
-
 #endif
diff --git a/arch/arm/mach-at91/include/mach/at91sam9g45.h b/arch/arm/mach-at91/include/mach/at91sam9g45.h
index dd9c95e..d052abc 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9g45.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9g45.h
@@ -84,17 +84,14 @@
 #define AT91SAM9G45_BASE_TC5		0xfffd4080
 
 /*
- * System Peripherals (offset from AT91_BASE_SYS)
+ * System Peripherals
  */
-#define AT91_DDRSDRC1	(0xffffe400 - AT91_BASE_SYS)
-#define AT91_DDRSDRC0	(0xffffe600 - AT91_BASE_SYS)
-#define AT91_MATRIX	(0xffffea00 - AT91_BASE_SYS)
-#define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)
-#define AT91_GPBR	(0xfffffd60 - AT91_BASE_SYS)
-
 #define AT91SAM9G45_BASE_ECC	0xffffe200
+#define AT91SAM9G45_BASE_DDRSDRC1 0xffffe400
+#define AT91SAM9G45_BASE_DDRSDRC0 0xffffe600
 #define AT91SAM9G45_BASE_DMA	0xffffec00
 #define AT91SAM9G45_BASE_SMC	0xffffe800
+#define AT91SAM9G45_BASE_MATRIX	0xffffea00
 #define AT91SAM9G45_BASE_DBGU	AT91_BASE_DBGU1
 #define AT91SAM9G45_BASE_PIOA	0xfffff200
 #define AT91SAM9G45_BASE_PIOB	0xfffff400
@@ -107,6 +104,7 @@
 #define AT91SAM9G45_BASE_PIT	0xfffffd30
 #define AT91SAM9G45_BASE_WDT	0xfffffd40
 #define AT91SAM9G45_BASE_RTC	0xfffffdb0
+#define AT91SAM9G45_BASE_GPBR	0xfffffd60
 
 #define AT91_USART0	AT91SAM9G45_BASE_US0
 #define AT91_USART1	AT91SAM9G45_BASE_US1
diff --git a/arch/arm/mach-at91/include/mach/at91sam9g45_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9g45_matrix.h
index c972d60..b76e2ed 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9g45_matrix.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9g45_matrix.h
@@ -15,18 +15,18 @@
 #ifndef AT91SAM9G45_MATRIX_H
 #define AT91SAM9G45_MATRIX_H
 
-#define AT91_MATRIX_MCFG0	(AT91_MATRIX + 0x00)	/* Master Configuration Register 0 */
-#define AT91_MATRIX_MCFG1	(AT91_MATRIX + 0x04)	/* Master Configuration Register 1 */
-#define AT91_MATRIX_MCFG2	(AT91_MATRIX + 0x08)	/* Master Configuration Register 2 */
-#define AT91_MATRIX_MCFG3	(AT91_MATRIX + 0x0C)	/* Master Configuration Register 3 */
-#define AT91_MATRIX_MCFG4	(AT91_MATRIX + 0x10)	/* Master Configuration Register 4 */
-#define AT91_MATRIX_MCFG5	(AT91_MATRIX + 0x14)	/* Master Configuration Register 5 */
-#define AT91_MATRIX_MCFG6	(AT91_MATRIX + 0x18)	/* Master Configuration Register 6 */
-#define AT91_MATRIX_MCFG7	(AT91_MATRIX + 0x1C)	/* Master Configuration Register 7 */
-#define AT91_MATRIX_MCFG8	(AT91_MATRIX + 0x20)	/* Master Configuration Register 8 */
-#define AT91_MATRIX_MCFG9	(AT91_MATRIX + 0x24)	/* Master Configuration Register 9 */
-#define AT91_MATRIX_MCFG10	(AT91_MATRIX + 0x28)	/* Master Configuration Register 10 */
-#define AT91_MATRIX_MCFG11	(AT91_MATRIX + 0x2C)	/* Master Configuration Register 11 */
+#define AT91_MATRIX_MCFG0	0x00			/* Master Configuration Register 0 */
+#define AT91_MATRIX_MCFG1	0x04			/* Master Configuration Register 1 */
+#define AT91_MATRIX_MCFG2	0x08			/* Master Configuration Register 2 */
+#define AT91_MATRIX_MCFG3	0x0C			/* Master Configuration Register 3 */
+#define AT91_MATRIX_MCFG4	0x10			/* Master Configuration Register 4 */
+#define AT91_MATRIX_MCFG5	0x14			/* Master Configuration Register 5 */
+#define AT91_MATRIX_MCFG6	0x18			/* Master Configuration Register 6 */
+#define AT91_MATRIX_MCFG7	0x1C			/* Master Configuration Register 7 */
+#define AT91_MATRIX_MCFG8	0x20			/* Master Configuration Register 8 */
+#define AT91_MATRIX_MCFG9	0x24			/* Master Configuration Register 9 */
+#define AT91_MATRIX_MCFG10	0x28			/* Master Configuration Register 10 */
+#define AT91_MATRIX_MCFG11	0x2C			/* Master Configuration Register 11 */
 #define		AT91_MATRIX_ULBT	(7 << 0)	/* Undefined Length Burst Type */
 #define			AT91_MATRIX_ULBT_INFINITE	(0 << 0)
 #define			AT91_MATRIX_ULBT_SINGLE		(1 << 0)
@@ -37,14 +37,14 @@
 #define			AT91_MATRIX_ULBT_SIXTYFOUR	(6 << 0)
 #define			AT91_MATRIX_ULBT_128		(7 << 0)
 
-#define AT91_MATRIX_SCFG0	(AT91_MATRIX + 0x40)	/* Slave Configuration Register 0 */
-#define AT91_MATRIX_SCFG1	(AT91_MATRIX + 0x44)	/* Slave Configuration Register 1 */
-#define AT91_MATRIX_SCFG2	(AT91_MATRIX + 0x48)	/* Slave Configuration Register 2 */
-#define AT91_MATRIX_SCFG3	(AT91_MATRIX + 0x4C)	/* Slave Configuration Register 3 */
-#define AT91_MATRIX_SCFG4	(AT91_MATRIX + 0x50)	/* Slave Configuration Register 4 */
-#define AT91_MATRIX_SCFG5	(AT91_MATRIX + 0x54)	/* Slave Configuration Register 5 */
-#define AT91_MATRIX_SCFG6	(AT91_MATRIX + 0x58)	/* Slave Configuration Register 6 */
-#define AT91_MATRIX_SCFG7	(AT91_MATRIX + 0x5C)	/* Slave Configuration Register 7 */
+#define AT91_MATRIX_SCFG0	0x40			/* Slave Configuration Register 0 */
+#define AT91_MATRIX_SCFG1	0x44			/* Slave Configuration Register 1 */
+#define AT91_MATRIX_SCFG2	0x48			/* Slave Configuration Register 2 */
+#define AT91_MATRIX_SCFG3	0x4C			/* Slave Configuration Register 3 */
+#define AT91_MATRIX_SCFG4	0x50			/* Slave Configuration Register 4 */
+#define AT91_MATRIX_SCFG5	0x54			/* Slave Configuration Register 5 */
+#define AT91_MATRIX_SCFG6	0x58			/* Slave Configuration Register 6 */
+#define AT91_MATRIX_SCFG7	0x5C			/* Slave Configuration Register 7 */
 #define		AT91_MATRIX_SLOT_CYCLE		(0x1ff << 0)	/* Maximum Number of Allowed Cycles for a Burst */
 #define		AT91_MATRIX_DEFMSTR_TYPE	(3    << 16)	/* Default Master Type */
 #define			AT91_MATRIX_DEFMSTR_TYPE_NONE	(0 << 16)
@@ -52,22 +52,22 @@
 #define			AT91_MATRIX_DEFMSTR_TYPE_FIXED	(2 << 16)
 #define		AT91_MATRIX_FIXED_DEFMSTR	(0xf  << 18)	/* Fixed Index of Default Master */
 
-#define AT91_MATRIX_PRAS0	(AT91_MATRIX + 0x80)	/* Priority Register A for Slave 0 */
-#define AT91_MATRIX_PRBS0	(AT91_MATRIX + 0x84)	/* Priority Register B for Slave 0 */
-#define AT91_MATRIX_PRAS1	(AT91_MATRIX + 0x88)	/* Priority Register A for Slave 1 */
-#define AT91_MATRIX_PRBS1	(AT91_MATRIX + 0x8C)	/* Priority Register B for Slave 1 */
-#define AT91_MATRIX_PRAS2	(AT91_MATRIX + 0x90)	/* Priority Register A for Slave 2 */
-#define AT91_MATRIX_PRBS2	(AT91_MATRIX + 0x94)	/* Priority Register B for Slave 2 */
-#define AT91_MATRIX_PRAS3	(AT91_MATRIX + 0x98)	/* Priority Register A for Slave 3 */
-#define AT91_MATRIX_PRBS3	(AT91_MATRIX + 0x9C)	/* Priority Register B for Slave 3 */
-#define AT91_MATRIX_PRAS4	(AT91_MATRIX + 0xA0)	/* Priority Register A for Slave 4 */
-#define AT91_MATRIX_PRBS4	(AT91_MATRIX + 0xA4)	/* Priority Register B for Slave 4 */
-#define AT91_MATRIX_PRAS5	(AT91_MATRIX + 0xA8)	/* Priority Register A for Slave 5 */
-#define AT91_MATRIX_PRBS5	(AT91_MATRIX + 0xAC)	/* Priority Register B for Slave 5 */
-#define AT91_MATRIX_PRAS6	(AT91_MATRIX + 0xB0)	/* Priority Register A for Slave 6 */
-#define AT91_MATRIX_PRBS6	(AT91_MATRIX + 0xB4)	/* Priority Register B for Slave 6 */
-#define AT91_MATRIX_PRAS7	(AT91_MATRIX + 0xB8)	/* Priority Register A for Slave 7 */
-#define AT91_MATRIX_PRBS7	(AT91_MATRIX + 0xBC)	/* Priority Register B for Slave 7 */
+#define AT91_MATRIX_PRAS0	0x80			/* Priority Register A for Slave 0 */
+#define AT91_MATRIX_PRBS0	0x84			/* Priority Register B for Slave 0 */
+#define AT91_MATRIX_PRAS1	0x88			/* Priority Register A for Slave 1 */
+#define AT91_MATRIX_PRBS1	0x8C			/* Priority Register B for Slave 1 */
+#define AT91_MATRIX_PRAS2	0x90			/* Priority Register A for Slave 2 */
+#define AT91_MATRIX_PRBS2	0x94			/* Priority Register B for Slave 2 */
+#define AT91_MATRIX_PRAS3	0x98			/* Priority Register A for Slave 3 */
+#define AT91_MATRIX_PRBS3	0x9C			/* Priority Register B for Slave 3 */
+#define AT91_MATRIX_PRAS4	0xA0			/* Priority Register A for Slave 4 */
+#define AT91_MATRIX_PRBS4	0xA4			/* Priority Register B for Slave 4 */
+#define AT91_MATRIX_PRAS5	0xA8			/* Priority Register A for Slave 5 */
+#define AT91_MATRIX_PRBS5	0xAC			/* Priority Register B for Slave 5 */
+#define AT91_MATRIX_PRAS6	0xB0			/* Priority Register A for Slave 6 */
+#define AT91_MATRIX_PRBS6	0xB4			/* Priority Register B for Slave 6 */
+#define AT91_MATRIX_PRAS7	0xB8			/* Priority Register A for Slave 7 */
+#define AT91_MATRIX_PRBS7	0xBC			/* Priority Register B for Slave 7 */
 #define		AT91_MATRIX_M0PR		(3 << 0)	/* Master 0 Priority */
 #define		AT91_MATRIX_M1PR		(3 << 4)	/* Master 1 Priority */
 #define		AT91_MATRIX_M2PR		(3 << 8)	/* Master 2 Priority */
@@ -81,7 +81,7 @@
 #define		AT91_MATRIX_M10PR		(3 << 8)	/* Master 10 Priority (in Register B) */
 #define		AT91_MATRIX_M11PR		(3 << 12)	/* Master 11 Priority (in Register B) */
 
-#define AT91_MATRIX_MRCR	(AT91_MATRIX + 0x100)	/* Master Remap Control Register */
+#define AT91_MATRIX_MRCR	0x100			/* Master Remap Control Register */
 #define		AT91_MATRIX_RCB0		(1 << 0)	/* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
 #define		AT91_MATRIX_RCB1		(1 << 1)	/* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
 #define		AT91_MATRIX_RCB2		(1 << 2)
@@ -95,7 +95,7 @@
 #define		AT91_MATRIX_RCB10		(1 << 10)
 #define		AT91_MATRIX_RCB11		(1 << 11)
 
-#define AT91_MATRIX_TCMR	(AT91_MATRIX + 0x110)	/* TCM Configuration Register */
+#define AT91_MATRIX_TCMR	0x110			/* TCM Configuration Register */
 #define		AT91_MATRIX_ITCM_SIZE		(0xf << 0)	/* Size of ITCM enabled memory block */
 #define			AT91_MATRIX_ITCM_0		(0 << 0)
 #define			AT91_MATRIX_ITCM_32		(6 << 0)
@@ -107,12 +107,12 @@
 #define			AT91_MATRIX_TCM_NO_WS		(0x0 << 11)
 #define			AT91_MATRIX_TCM_ONE_WS		(0x1 << 11)
 
-#define AT91_MATRIX_VIDEO	(AT91_MATRIX + 0x118)	/* Video Mode Configuration Register */
+#define AT91_MATRIX_VIDEO	0x118			/* Video Mode Configuration Register */
 #define		AT91C_VDEC_SEL			(0x1 <<  0) /* Video Mode Selection */
 #define			AT91C_VDEC_SEL_OFF		(0 << 0)
 #define			AT91C_VDEC_SEL_ON		(1 << 0)
 
-#define AT91_MATRIX_EBICSA	(AT91_MATRIX + 0x128)	/* EBI Chip Select Assignment Register */
+#define AT91_MATRIX_EBICSA	0x128			/* EBI Chip Select Assignment Register */
 #define		AT91_MATRIX_EBI_CS1A		(1 << 1)	/* Chip Select 1 Assignment */
 #define			AT91_MATRIX_EBI_CS1A_SMC		(0 << 1)
 #define			AT91_MATRIX_EBI_CS1A_SDRAMC		(1 << 1)
@@ -138,13 +138,13 @@
 #define			AT91_MATRIX_EBI_DDR_IOSR_REDUCED	(0 << 18)
 #define			AT91_MATRIX_EBI_DDR_IOSR_NORMAL		(1 << 18)
 
-#define AT91_MATRIX_WPMR	(AT91_MATRIX + 0x1E4)	/* Write Protect Mode Register */
+#define AT91_MATRIX_WPMR	0x1E4			/* Write Protect Mode Register */
 #define		AT91_MATRIX_WPMR_WPEN		(1 << 0)	/* Write Protect ENable */
 #define			AT91_MATRIX_WPMR_WP_WPDIS		(0 << 0)
 #define			AT91_MATRIX_WPMR_WP_WPEN		(1 << 0)
 #define		AT91_MATRIX_WPMR_WPKEY		(0xFFFFFF << 8)	/* Write Protect KEY */
 
-#define AT91_MATRIX_WPSR	(AT91_MATRIX + 0x1E8)	/* Write Protect Status Register */
+#define AT91_MATRIX_WPSR	0x1E8			/* Write Protect Status Register */
 #define		AT91_MATRIX_WPSR_WPVS		(1 << 0)	/* Write Protect Violation Status */
 #define			AT91_MATRIX_WPSR_NO_WPV		(0 << 0)
 #define			AT91_MATRIX_WPSR_WPV		(1 << 0)
diff --git a/arch/arm/mach-at91/include/mach/at91sam9rl.h b/arch/arm/mach-at91/include/mach/at91sam9rl.h
index d7bead7..e0073eb 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9rl.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9rl.h
@@ -69,15 +69,13 @@
 /*
  * System Peripherals (offset from AT91_BASE_SYS)
  */
-#define AT91_SDRAMC0	(0xffffea00 - AT91_BASE_SYS)
-#define AT91_MATRIX	(0xffffee00 - AT91_BASE_SYS)
-#define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)
 #define AT91_SCKCR	(0xfffffd50 - AT91_BASE_SYS)
-#define AT91_GPBR	(0xfffffd60 - AT91_BASE_SYS)
 
 #define AT91SAM9RL_BASE_DMA	0xffffe600
 #define AT91SAM9RL_BASE_ECC	0xffffe800
+#define AT91SAM9RL_BASE_SDRAMC	0xffffea00
 #define AT91SAM9RL_BASE_SMC	0xffffec00
+#define AT91SAM9RL_BASE_MATRIX	0xffffee00
 #define AT91SAM9RL_BASE_DBGU	AT91_BASE_DBGU0
 #define AT91SAM9RL_BASE_PIOA	0xfffff400
 #define AT91SAM9RL_BASE_PIOB	0xfffff600
@@ -88,6 +86,7 @@
 #define AT91SAM9RL_BASE_RTT	0xfffffd20
 #define AT91SAM9RL_BASE_PIT	0xfffffd30
 #define AT91SAM9RL_BASE_WDT	0xfffffd40
+#define AT91SAM9RL_BASE_GPBR	0xfffffd60
 #define AT91SAM9RL_BASE_RTC	0xfffffe00
 
 #define AT91_USART0	AT91SAM9RL_BASE_US0
diff --git a/arch/arm/mach-at91/include/mach/at91sam9rl_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9rl_matrix.h
index 5f91490..6d160ada 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9rl_matrix.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9rl_matrix.h
@@ -14,12 +14,12 @@
 #ifndef AT91SAM9RL_MATRIX_H
 #define AT91SAM9RL_MATRIX_H
 
-#define AT91_MATRIX_MCFG0	(AT91_MATRIX + 0x00)	/* Master Configuration Register 0 */
-#define AT91_MATRIX_MCFG1	(AT91_MATRIX + 0x04)	/* Master Configuration Register 1 */
-#define AT91_MATRIX_MCFG2	(AT91_MATRIX + 0x08)	/* Master Configuration Register 2 */
-#define AT91_MATRIX_MCFG3	(AT91_MATRIX + 0x0C)	/* Master Configuration Register 3 */
-#define AT91_MATRIX_MCFG4	(AT91_MATRIX + 0x10)	/* Master Configuration Register 4 */
-#define AT91_MATRIX_MCFG5	(AT91_MATRIX + 0x14)	/* Master Configuration Register 5 */
+#define AT91_MATRIX_MCFG0	0x00			/* Master Configuration Register 0 */
+#define AT91_MATRIX_MCFG1	0x04			/* Master Configuration Register 1 */
+#define AT91_MATRIX_MCFG2	0x08			/* Master Configuration Register 2 */
+#define AT91_MATRIX_MCFG3	0x0C			/* Master Configuration Register 3 */
+#define AT91_MATRIX_MCFG4	0x10			/* Master Configuration Register 4 */
+#define AT91_MATRIX_MCFG5	0x14			/* Master Configuration Register 5 */
 #define		AT91_MATRIX_ULBT	(7 << 0)	/* Undefined Length Burst Type */
 #define			AT91_MATRIX_ULBT_INFINITE	(0 << 0)
 #define			AT91_MATRIX_ULBT_SINGLE		(1 << 0)
@@ -27,12 +27,12 @@
 #define			AT91_MATRIX_ULBT_EIGHT		(3 << 0)
 #define			AT91_MATRIX_ULBT_SIXTEEN	(4 << 0)
 
-#define AT91_MATRIX_SCFG0	(AT91_MATRIX + 0x40)	/* Slave Configuration Register 0 */
-#define AT91_MATRIX_SCFG1	(AT91_MATRIX + 0x44)	/* Slave Configuration Register 1 */
-#define AT91_MATRIX_SCFG2	(AT91_MATRIX + 0x48)	/* Slave Configuration Register 2 */
-#define AT91_MATRIX_SCFG3	(AT91_MATRIX + 0x4C)	/* Slave Configuration Register 3 */
-#define AT91_MATRIX_SCFG4	(AT91_MATRIX + 0x50)	/* Slave Configuration Register 4 */
-#define AT91_MATRIX_SCFG5	(AT91_MATRIX + 0x54)	/* Slave Configuration Register 5 */
+#define AT91_MATRIX_SCFG0	0x40			/* Slave Configuration Register 0 */
+#define AT91_MATRIX_SCFG1	0x44			/* Slave Configuration Register 1 */
+#define AT91_MATRIX_SCFG2	0x48			/* Slave Configuration Register 2 */
+#define AT91_MATRIX_SCFG3	0x4C			/* Slave Configuration Register 3 */
+#define AT91_MATRIX_SCFG4	0x50			/* Slave Configuration Register 4 */
+#define AT91_MATRIX_SCFG5	0x54			/* Slave Configuration Register 5 */
 #define		AT91_MATRIX_SLOT_CYCLE		(0xff << 0)	/* Maximum Number of Allowed Cycles for a Burst */
 #define		AT91_MATRIX_DEFMSTR_TYPE	(3    << 16)	/* Default Master Type */
 #define			AT91_MATRIX_DEFMSTR_TYPE_NONE	(0 << 16)
@@ -43,12 +43,12 @@
 #define			AT91_MATRIX_ARBT_ROUND_ROBIN	(0 << 24)
 #define			AT91_MATRIX_ARBT_FIXED_PRIORITY	(1 << 24)
 
-#define AT91_MATRIX_PRAS0	(AT91_MATRIX + 0x80)	/* Priority Register A for Slave 0 */
-#define AT91_MATRIX_PRAS1	(AT91_MATRIX + 0x88)	/* Priority Register A for Slave 1 */
-#define AT91_MATRIX_PRAS2	(AT91_MATRIX + 0x90)	/* Priority Register A for Slave 2 */
-#define AT91_MATRIX_PRAS3	(AT91_MATRIX + 0x98)	/* Priority Register A for Slave 3 */
-#define AT91_MATRIX_PRAS4	(AT91_MATRIX + 0xA0)	/* Priority Register A for Slave 4 */
-#define AT91_MATRIX_PRAS5	(AT91_MATRIX + 0xA8)	/* Priority Register A for Slave 5 */
+#define AT91_MATRIX_PRAS0	0x80			/* Priority Register A for Slave 0 */
+#define AT91_MATRIX_PRAS1	0x88			/* Priority Register A for Slave 1 */
+#define AT91_MATRIX_PRAS2	0x90			/* Priority Register A for Slave 2 */
+#define AT91_MATRIX_PRAS3	0x98			/* Priority Register A for Slave 3 */
+#define AT91_MATRIX_PRAS4	0xA0			/* Priority Register A for Slave 4 */
+#define AT91_MATRIX_PRAS5	0xA8			/* Priority Register A for Slave 5 */
 #define		AT91_MATRIX_M0PR		(3 << 0)	/* Master 0 Priority */
 #define		AT91_MATRIX_M1PR		(3 << 4)	/* Master 1 Priority */
 #define		AT91_MATRIX_M2PR		(3 << 8)	/* Master 2 Priority */
@@ -56,7 +56,7 @@
 #define		AT91_MATRIX_M4PR		(3 << 16)	/* Master 4 Priority */
 #define		AT91_MATRIX_M5PR		(3 << 20)	/* Master 5 Priority */
 
-#define AT91_MATRIX_MRCR	(AT91_MATRIX + 0x100)	/* Master Remap Control Register */
+#define AT91_MATRIX_MRCR	0x100			/* Master Remap Control Register */
 #define		AT91_MATRIX_RCB0		(1 << 0)	/* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
 #define		AT91_MATRIX_RCB1		(1 << 1)	/* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
 #define		AT91_MATRIX_RCB2		(1 << 2)
@@ -64,7 +64,7 @@
 #define		AT91_MATRIX_RCB4		(1 << 4)
 #define		AT91_MATRIX_RCB5		(1 << 5)
 
-#define AT91_MATRIX_TCMR	(AT91_MATRIX + 0x114)	/* TCM Configuration Register */
+#define AT91_MATRIX_TCMR	0x114			/* TCM Configuration Register */
 #define		AT91_MATRIX_ITCM_SIZE		(0xf << 0)	/* Size of ITCM enabled memory block */
 #define			AT91_MATRIX_ITCM_0		(0 << 0)
 #define			AT91_MATRIX_ITCM_16		(5 << 0)
@@ -74,7 +74,7 @@
 #define			AT91_MATRIX_DTCM_16		(5 << 4)
 #define			AT91_MATRIX_DTCM_32		(6 << 4)
 
-#define AT91_MATRIX_EBICSA	(AT91_MATRIX + 0x120)	/* EBI0 Chip Select Assignment Register */
+#define AT91_MATRIX_EBICSA	0x120			/* EBI0 Chip Select Assignment Register */
 #define		AT91_MATRIX_CS1A		(1 << 1)	/* Chip Select 1 Assignment */
 #define			AT91_MATRIX_CS1A_SMC		(0 << 1)
 #define			AT91_MATRIX_CS1A_SDRAMC		(1 << 1)
diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5.h b/arch/arm/mach-at91/include/mach/at91sam9x5.h
new file mode 100644
index 0000000..88e43d5
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h
@@ -0,0 +1,74 @@
+/*
+ * Chip-specific header file for the AT91SAM9x5 family
+ *
+ *  Copyright (C) 2009-2012 Atmel Corporation.
+ *
+ * Common definitions.
+ * Based on AT91SAM9x5 datasheet.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef AT91SAM9X5_H
+#define AT91SAM9X5_H
+
+/*
+ * Peripheral identifiers/interrupts.
+ */
+#define AT91SAM9X5_ID_PIOAB	2	/* Parallel I/O Controller A and B */
+#define AT91SAM9X5_ID_PIOCD	3	/* Parallel I/O Controller C and D */
+#define AT91SAM9X5_ID_SMD	4	/* SMD Soft Modem (SMD) */
+#define AT91SAM9X5_ID_USART0	5	/* USART 0 */
+#define AT91SAM9X5_ID_USART1	6	/* USART 1 */
+#define AT91SAM9X5_ID_USART2	7	/* USART 2 */
+#define AT91SAM9X5_ID_USART3	8	/* USART 3 */
+#define AT91SAM9X5_ID_TWI0	9	/* Two-Wire Interface 0 */
+#define AT91SAM9X5_ID_TWI1	10	/* Two-Wire Interface 1 */
+#define AT91SAM9X5_ID_TWI2	11	/* Two-Wire Interface 2 */
+#define AT91SAM9X5_ID_MCI0	12	/* High Speed Multimedia Card Interface 0 */
+#define AT91SAM9X5_ID_SPI0	13	/* Serial Peripheral Interface 0 */
+#define AT91SAM9X5_ID_SPI1	14	/* Serial Peripheral Interface 1 */
+#define AT91SAM9X5_ID_UART0	15	/* UART 0 */
+#define AT91SAM9X5_ID_UART1	16	/* UART 1 */
+#define AT91SAM9X5_ID_TCB	17	/* Timer Counter 0, 1, 2, 3, 4 and 5 */
+#define AT91SAM9X5_ID_PWM	18	/* Pulse Width Modulation Controller */
+#define AT91SAM9X5_ID_ADC	19	/* ADC Controller */
+#define AT91SAM9X5_ID_DMA0	20	/* DMA Controller 0 */
+#define AT91SAM9X5_ID_DMA1	21	/* DMA Controller 1 */
+#define AT91SAM9X5_ID_UHPHS	22	/* USB Host High Speed */
+#define AT91SAM9X5_ID_UDPHS	23	/* USB Device High Speed */
+#define AT91SAM9X5_ID_EMAC0	24	/* Ethernet MAC0 */
+#define AT91SAM9X5_ID_LCDC	25	/* LCD Controller */
+#define AT91SAM9X5_ID_ISI	25	/* Image Sensor Interface */
+#define AT91SAM9X5_ID_MCI1	26	/* High Speed Multimedia Card Interface 1 */
+#define AT91SAM9X5_ID_EMAC1	27	/* Ethernet MAC1 */
+#define AT91SAM9X5_ID_SSC	28	/* Synchronous Serial Controller */
+#define AT91SAM9X5_ID_CAN0	29	/* CAN Controller 0 */
+#define AT91SAM9X5_ID_CAN1	30	/* CAN Controller 1 */
+#define AT91SAM9X5_ID_IRQ0	31	/* Advanced Interrupt Controller */
+
+/*
+ * User Peripheral physical base addresses.
+ */
+#define AT91SAM9X5_BASE_USART0	0xf801c000
+#define AT91SAM9X5_BASE_USART1	0xf8020000
+#define AT91SAM9X5_BASE_USART2	0xf8024000
+
+/*
+ * Base addresses for early serial code (uncompress.h)
+ */
+#define AT91_DBGU	AT91_BASE_DBGU0
+#define AT91_USART0	AT91SAM9X5_BASE_USART0
+#define AT91_USART1	AT91SAM9X5_BASE_USART1
+#define AT91_USART2	AT91SAM9X5_BASE_USART2
+
+/*
+ * Internal Memory.
+ */
+#define AT91SAM9X5_SRAM_BASE	0x00300000	/* Internal SRAM base address */
+#define AT91SAM9X5_SRAM_SIZE	SZ_32K		/* Internal SRAM size (32Kb) */
+
+#define AT91SAM9X5_ROM_BASE	0x00400000	/* Internal ROM base address */
+#define AT91SAM9X5_ROM_SIZE	SZ_64K		/* Internal ROM size (64Kb) */
+
+#endif
diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h
new file mode 100644
index 0000000..a606d39
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h
@@ -0,0 +1,53 @@
+/*
+ * Matrix-centric header file for the AT91SAM9x5 family
+ *
+ *  Copyright (C) 2009-2012 Atmel Corporation.
+ *
+ * Only EBI related registers.
+ * Write Protect register definitions may be useful.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef AT91SAM9X5_MATRIX_H
+#define AT91SAM9X5_MATRIX_H
+
+#define AT91_MATRIX_EBICSA	(AT91_MATRIX + 0x120)	/* EBI Chip Select Assignment Register */
+#define		AT91_MATRIX_EBI_CS1A		(1 << 1)	/* Chip Select 1 Assignment */
+#define			AT91_MATRIX_EBI_CS1A_SMC		(0 << 1)
+#define			AT91_MATRIX_EBI_CS1A_SDRAMC		(1 << 1)
+#define		AT91_MATRIX_EBI_CS3A		(1 << 3)	/* Chip Select 3 Assignment */
+#define			AT91_MATRIX_EBI_CS3A_SMC		(0 << 3)
+#define			AT91_MATRIX_EBI_CS3A_SMC_NANDFLASH	(1 << 3)
+#define		AT91_MATRIX_EBI_DBPUC		(1 << 8)	/* Data Bus Pull-up Configuration */
+#define			AT91_MATRIX_EBI_DBPU_ON			(0 << 8)
+#define			AT91_MATRIX_EBI_DBPU_OFF		(1 << 8)
+#define		AT91_MATRIX_EBI_VDDIOMSEL	(1 << 16)	/* Memory voltage selection */
+#define			AT91_MATRIX_EBI_VDDIOMSEL_1_8V		(0 << 16)
+#define			AT91_MATRIX_EBI_VDDIOMSEL_3_3V		(1 << 16)
+#define		AT91_MATRIX_EBI_EBI_IOSR	(1 << 17)	/* EBI I/O slew rate selection */
+#define			AT91_MATRIX_EBI_EBI_IOSR_REDUCED	(0 << 17)
+#define			AT91_MATRIX_EBI_EBI_IOSR_NORMAL		(1 << 17)
+#define		AT91_MATRIX_EBI_DDR_IOSR	(1 << 18)	/* DDR2 dedicated port I/O slew rate selection */
+#define			AT91_MATRIX_EBI_DDR_IOSR_REDUCED	(0 << 18)
+#define			AT91_MATRIX_EBI_DDR_IOSR_NORMAL		(1 << 18)
+#define		AT91_MATRIX_NFD0_SELECT		(1 << 24)	/* NAND Flash Data Bus Selection */
+#define			AT91_MATRIX_NFD0_ON_D0			(0 << 24)
+#define			AT91_MATRIX_NFD0_ON_D16			(1 << 24)
+#define		AT91_MATRIX_DDR_MP_EN		(1 << 25)	/* DDR Multi-port Enable */
+#define			AT91_MATRIX_MP_OFF			(0 << 25)
+#define			AT91_MATRIX_MP_ON			(1 << 25)
+
+#define AT91_MATRIX_WPMR	(AT91_MATRIX + 0x1E4)	/* Write Protect Mode Register */
+#define		AT91_MATRIX_WPMR_WPEN		(1 << 0)	/* Write Protect ENable */
+#define			AT91_MATRIX_WPMR_WP_WPDIS		(0 << 0)
+#define			AT91_MATRIX_WPMR_WP_WPEN		(1 << 0)
+#define		AT91_MATRIX_WPMR_WPKEY		(0xFFFFFF << 8)	/* Write Protect KEY */
+
+#define AT91_MATRIX_WPSR	(AT91_MATRIX + 0x1E8)	/* Write Protect Status Register */
+#define		AT91_MATRIX_WPSR_WPVS		(1 << 0)	/* Write Protect Violation Status */
+#define			AT91_MATRIX_WPSR_NO_WPV		(0 << 0)
+#define			AT91_MATRIX_WPSR_WPV		(1 << 0)
+#define		AT91_MATRIX_WPSR_WPVSRC		(0xFFFF << 8)	/* Write Protect Violation Source */
+
+#endif
diff --git a/arch/arm/mach-at91/include/mach/at91x40.h b/arch/arm/mach-at91/include/mach/at91x40.h
index a57829f..9068021 100644
--- a/arch/arm/mach-at91/include/mach/at91x40.h
+++ b/arch/arm/mach-at91/include/mach/at91x40.h
@@ -28,18 +28,18 @@
 #define AT91X40_ID_IRQ2		18	/* External IRQ 2 */
 
 /*
- * System Peripherals (offset from AT91_BASE_SYS)
+ * System Peripherals
  */
 #define AT91_BASE_SYS	0xffc00000
 
-#define AT91_EBI	(0xffe00000 - AT91_BASE_SYS)	/* External Bus Interface */
-#define AT91_SF		(0xfff00000 - AT91_BASE_SYS)	/* Special Function */
-#define AT91_USART1	(0xfffcc000 - AT91_BASE_SYS)	/* USART 1 */
-#define AT91_USART0	(0xfffd0000 - AT91_BASE_SYS)	/* USART 0 */
-#define AT91_TC		(0xfffe0000 - AT91_BASE_SYS)	/* Timer Counter */
-#define AT91_PIOA	(0xffff0000 - AT91_BASE_SYS)	/* PIO Controller A */
-#define AT91_PS		(0xffff4000 - AT91_BASE_SYS)	/* Power Save */
-#define AT91_WD		(0xffff8000 - AT91_BASE_SYS)	/* Watchdog Timer */
+#define AT91_EBI	0xffe00000	/* External Bus Interface */
+#define AT91_SF		0xfff00000	/* Special Function */
+#define AT91_USART1	0xfffcc000	/* USART 1 */
+#define AT91_USART0	0xfffd0000	/* USART 0 */
+#define AT91_TC		0xfffe0000	/* Timer Counter */
+#define AT91_PIOA	0xffff0000	/* PIO Controller A */
+#define AT91_PS		0xffff4000	/* Power Save */
+#define AT91_WD		0xffff8000	/* Watchdog Timer */
 
 /*
  * The AT91x40 series doesn't have a debug unit like the other AT91 parts.
diff --git a/arch/arm/mach-at91/include/mach/at_hdmac.h b/arch/arm/mach-at91/include/mach/at_hdmac.h
index 187cb58..fff48d1 100644
--- a/arch/arm/mach-at91/include/mach/at_hdmac.h
+++ b/arch/arm/mach-at91/include/mach/at_hdmac.h
@@ -24,18 +24,6 @@
 };
 
 /**
- * enum at_dma_slave_width - DMA slave register access width.
- * @AT_DMA_SLAVE_WIDTH_8BIT: Do 8-bit slave register accesses
- * @AT_DMA_SLAVE_WIDTH_16BIT: Do 16-bit slave register accesses
- * @AT_DMA_SLAVE_WIDTH_32BIT: Do 32-bit slave register accesses
- */
-enum at_dma_slave_width {
-	AT_DMA_SLAVE_WIDTH_8BIT = 0,
-	AT_DMA_SLAVE_WIDTH_16BIT,
-	AT_DMA_SLAVE_WIDTH_32BIT,
-};
-
-/**
  * struct at_dma_slave - Controller-specific information about a slave
  * @dma_dev: required DMA master device
  * @tx_reg: physical address of data register used for
@@ -48,9 +36,6 @@
  */
 struct at_dma_slave {
 	struct device		*dma_dev;
-	dma_addr_t		tx_reg;
-	dma_addr_t		rx_reg;
-	enum at_dma_slave_width	reg_width;
 	u32			cfg;
 	u32			ctrla;
 };
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index 3b33f07..49a8211 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -41,6 +41,7 @@
 #include <sound/atmel-ac97c.h>
 #include <linux/serial.h>
 #include <linux/platform_data/macb.h>
+#include <linux/platform_data/atmel.h>
 
  /* USB Device */
 struct at91_udc_data {
@@ -85,31 +86,20 @@
 extern void __init at91_add_device_eth(struct macb_platform_data *data);
 
  /* USB Host */
+#define AT91_MAX_USBH_PORTS	3
 struct at91_usbh_data {
-	u8		ports;		/* number of ports on root hub */
-	int		vbus_pin[2];	/* port power-control pin */
-	u8              vbus_pin_active_low[2];
+	int		vbus_pin[AT91_MAX_USBH_PORTS];	/* port power-control pin */
+	int             overcurrent_pin[AT91_MAX_USBH_PORTS];
+	u8		ports;				/* number of ports on root hub */
 	u8              overcurrent_supported;
-	int             overcurrent_pin[2];
-	u8              overcurrent_status[2];
-	u8              overcurrent_changed[2];
+	u8              vbus_pin_active_low[AT91_MAX_USBH_PORTS];
+	u8              overcurrent_status[AT91_MAX_USBH_PORTS];
+	u8              overcurrent_changed[AT91_MAX_USBH_PORTS];
 };
 extern void __init at91_add_device_usbh(struct at91_usbh_data *data);
 extern void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data);
 extern void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data);
 
- /* NAND / SmartMedia */
-struct atmel_nand_data {
-	int		enable_pin;	/* chip enable */
-	int		det_pin;	/* card detect */
-	int		rdy_pin;	/* ready/busy */
-	u8              rdy_pin_active_low;     /* rdy_pin value is inverted */
-	u8		ale;		/* address line number connected to ALE */
-	u8		cle;		/* address line number connected to CLE */
-	u8		bus_width_16;	/* buswidth is 16 bit */
-	struct mtd_partition *parts;
-	unsigned int	num_parts;
-};
 extern void __init at91_add_device_nand(struct atmel_nand_data *data);
 
  /* I2C*/
@@ -179,7 +169,9 @@
 extern void __init at91_add_device_ac97(struct ac97c_platform_data *data);
 
  /* ISI */
-extern void __init at91_add_device_isi(void);
+struct isi_platform_data;
+extern void __init at91_add_device_isi(struct isi_platform_data *data,
+		bool use_pck_as_mck);
 
  /* Touchscreen Controller */
 struct at91_tsadcc_data {
diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h
index f6ce936..0118c33 100644
--- a/arch/arm/mach-at91/include/mach/cpu.h
+++ b/arch/arm/mach-at91/include/mach/cpu.h
@@ -25,7 +25,6 @@
 #define ARCH_ID_AT91SAM9G45MRL	0x819b05a2	/* aka 9G45-ES2 & non ES lots */
 #define ARCH_ID_AT91SAM9G45ES	0x819b05a1	/* 9G45-ES (Engineering Sample) */
 #define ARCH_ID_AT91SAM9X5	0x819a05a0
-#define ARCH_ID_AT91CAP9	0x039A03A0
 
 #define ARCH_ID_AT91SAM9XE128	0x329973a0
 #define ARCH_ID_AT91SAM9XE256	0x329a93a0
@@ -51,10 +50,6 @@
 #define ARCH_FAMILY_AT91SAM9	0x01900000
 #define ARCH_FAMILY_AT91SAM9XE	0x02900000
 
-/* PMC revision */
-#define ARCH_REVISION_CAP9_B	0x399
-#define ARCH_REVISION_CAP9_C	0x601
-
 /* RM9200 type */
 #define ARCH_REVISON_9200_BGA	(0 << 0)
 #define ARCH_REVISON_9200_PQFP	(1 << 0)
@@ -63,9 +58,6 @@
 	/* 920T */
 	AT91_SOC_RM9200,
 
-	/* CAP */
-	AT91_SOC_CAP9,
-
 	/* SAM92xx */
 	AT91_SOC_SAM9260, AT91_SOC_SAM9261, AT91_SOC_SAM9263,
 
@@ -86,9 +78,6 @@
 	/* RM9200 */
 	AT91_SOC_RM9200_BGA, AT91_SOC_RM9200_PQFP,
 
-	/* CAP9 */
-	AT91_SOC_CAP9_REV_B, AT91_SOC_CAP9_REV_C,
-
 	/* SAM9260 */
 	AT91_SOC_SAM9XE,
 
@@ -195,16 +184,6 @@
 #define cpu_is_at91sam9x25()	(0)
 #endif
 
-#ifdef CONFIG_ARCH_AT91CAP9
-#define cpu_is_at91cap9()	(at91_soc_initdata.type == AT91_SOC_CAP9)
-#define cpu_is_at91cap9_revB()	(at91_soc_initdata.subtype == AT91_SOC_CAP9_REV_B)
-#define cpu_is_at91cap9_revC()	(at91_soc_initdata.subtype == AT91_SOC_CAP9_REV_C)
-#else
-#define cpu_is_at91cap9()	(0)
-#define cpu_is_at91cap9_revB()	(0)
-#define cpu_is_at91cap9_revC()	(0)
-#endif
-
 /*
  * Since this is ARM, we will never run on any AVR32 CPU. But these
  * definitions may reduce clutter in common drivers.
diff --git a/arch/arm/mach-at91/include/mach/entry-macro.S b/arch/arm/mach-at91/include/mach/entry-macro.S
index 423eea0..903bf20 100644
--- a/arch/arm/mach-at91/include/mach/entry-macro.S
+++ b/arch/arm/mach-at91/include/mach/entry-macro.S
@@ -13,17 +13,11 @@
 #include <mach/hardware.h>
 #include <mach/at91_aic.h>
 
-	.macro	disable_fiq
-	.endm
-
 	.macro  get_irqnr_preamble, base, tmp
 	ldr	\base, =at91_aic_base		@ base virtual address of AIC peripheral
 	ldr	\base, [\base]
 	.endm
 
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
-
 	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 	ldr	\irqnr, [\base, #AT91_AIC_IVR]		@ read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt)
 	ldr	\irqstat, [\base, #AT91_AIC_ISR]	@ read interrupt source number
diff --git a/arch/arm/mach-at91/include/mach/gpio.h b/arch/arm/mach-at91/include/mach/gpio.h
index e3fd225..eed465a 100644
--- a/arch/arm/mach-at91/include/mach/gpio.h
+++ b/arch/arm/mach-at91/include/mach/gpio.h
@@ -191,10 +191,15 @@
 extern int __init_or_module at91_set_GPIO_periph(unsigned pin, int use_pullup);
 extern int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup);
 extern int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup);
+extern int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup);
+extern int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup);
 extern int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup);
 extern int __init_or_module at91_set_gpio_output(unsigned pin, int value);
 extern int __init_or_module at91_set_deglitch(unsigned pin, int is_on);
+extern int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div);
 extern int __init_or_module at91_set_multi_drive(unsigned pin, int is_on);
+extern int __init_or_module at91_set_pulldown(unsigned pin, int is_on);
+extern int __init_or_module at91_disable_schmitt_trig(unsigned pin);
 
 /* callable at any time */
 extern int at91_set_gpio_value(unsigned pin, int value);
@@ -204,18 +209,6 @@
 extern void at91_gpio_suspend(void);
 extern void at91_gpio_resume(void);
 
-/*-------------------------------------------------------------------------*/
-
-/* wrappers for "new style" GPIO calls. the old AT91-specific ones should
- * eventually be removed (along with this errno.h inclusion), and the
- * gpio request/free calls should probably be implemented.
- */
-
-#include <asm/errno.h>
-
-#define gpio_to_irq(gpio) (gpio + NR_AIC_IRQS)
-#define irq_to_gpio(irq)  (irq - NR_AIC_IRQS)
-
 #endif	/* __ASSEMBLY__ */
 
 #endif
diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
index 2d0e4e9..e9e29a6 100644
--- a/arch/arm/mach-at91/include/mach/hardware.h
+++ b/arch/arm/mach-at91/include/mach/hardware.h
@@ -19,7 +19,7 @@
 /* DBGU base */
 /* rm9200, 9260/9g20, 9261/9g10, 9rl */
 #define AT91_BASE_DBGU0	0xfffff200
-/* 9263, 9g45, cap9 */
+/* 9263, 9g45 */
 #define AT91_BASE_DBGU1	0xffffee00
 
 #if defined(CONFIG_ARCH_AT91RM9200)
@@ -34,8 +34,8 @@
 #include <mach/at91sam9rl.h>
 #elif defined(CONFIG_ARCH_AT91SAM9G45)
 #include <mach/at91sam9g45.h>
-#elif defined(CONFIG_ARCH_AT91CAP9)
-#include <mach/at91cap9.h>
+#elif defined(CONFIG_ARCH_AT91SAM9X5)
+#include <mach/at91sam9x5.h>
 #elif defined(CONFIG_ARCH_AT91X40)
 #include <mach/at91x40.h>
 #else
@@ -59,9 +59,10 @@
 
 /*
  * On all at91 have the Advanced Interrupt Controller starts at address
- * 0xfffff000
+ * 0xfffff000 and the Power Management Controller starts at 0xfffffc00
  */
 #define AT91_AIC	0xfffff000
+#define AT91_PMC	0xfffffc00
 
 /*
  * Peripheral identifiers/interrupts.
diff --git a/arch/arm/mach-at91/include/mach/io.h b/arch/arm/mach-at91/include/mach/io.h
index 4ca09ef..2d9ca04 100644
--- a/arch/arm/mach-at91/include/mach/io.h
+++ b/arch/arm/mach-at91/include/mach/io.h
@@ -21,29 +21,7 @@
 #ifndef __ASM_ARCH_IO_H
 #define __ASM_ARCH_IO_H
 
-#include <mach/hardware.h>
-
 #define IO_SPACE_LIMIT		0xFFFFFFFF
-
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#ifndef __ASSEMBLY__
-
-static inline unsigned int at91_sys_read(unsigned int reg_offset)
-{
-	void __iomem *addr = (void __iomem *)AT91_VA_BASE_SYS;
-
-	return __raw_readl(addr + reg_offset);
-}
-
-static inline void at91_sys_write(unsigned int reg_offset, unsigned long value)
-{
-	void __iomem *addr = (void __iomem *)AT91_VA_BASE_SYS;
-
-	__raw_writel(value, addr + reg_offset);
-}
-
-#endif
+#define __io(a)			__typesafe_io(a)
 
 #endif
diff --git a/arch/arm/mach-at91/include/mach/system.h b/arch/arm/mach-at91/include/mach/system.h
deleted file mode 100644
index cbd64f3..0000000
--- a/arch/arm/mach-at91/include/mach/system.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/system.h
- *
- *  Copyright (C) 2003 SAN People
- *
- * 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
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-#include <mach/hardware.h>
-#include <mach/at91_st.h>
-#include <mach/at91_dbgu.h>
-#include <mach/at91_pmc.h>
-
-static inline void arch_idle(void)
-{
-	/*
-	 * Disable the processor clock.  The processor will be automatically
-	 * re-enabled by an interrupt or by a reset.
-	 */
-#ifdef AT91_PS
-	at91_sys_write(AT91_PS_CR, AT91_PS_CR_CPU);
-#else
-	at91_sys_write(AT91_PMC_SCDR, AT91_PMC_PCK);
-#endif
-#ifndef CONFIG_CPU_ARM920T
-	/*
-	 * Set the processor (CP15) into 'Wait for Interrupt' mode.
-	 * Post-RM9200 processors need this in conjunction with the above
-	 * to save power when idle.
-	 */
-	cpu_do_idle();
-#endif
-}
-
-#endif
diff --git a/arch/arm/mach-at91/include/mach/system_rev.h b/arch/arm/mach-at91/include/mach/system_rev.h
index ec164a4..ef79a9a 100644
--- a/arch/arm/mach-at91/include/mach/system_rev.h
+++ b/arch/arm/mach-at91/include/mach/system_rev.h
@@ -7,6 +7,8 @@
 #ifndef __ARCH_SYSTEM_REV_H__
 #define __ARCH_SYSTEM_REV_H__
 
+#include <asm/system_info.h>
+
 /*
  * board revision encoding
  * mach specific
diff --git a/arch/arm/mach-at91/include/mach/uncompress.h b/arch/arm/mach-at91/include/mach/uncompress.h
index 0234fd9..4218647 100644
--- a/arch/arm/mach-at91/include/mach/uncompress.h
+++ b/arch/arm/mach-at91/include/mach/uncompress.h
@@ -23,6 +23,7 @@
 
 #include <linux/io.h>
 #include <linux/atmel_serial.h>
+#include <mach/hardware.h>
 
 #if defined(CONFIG_AT91_EARLY_DBGU0)
 #define UART_OFFSET AT91_BASE_DBGU0
diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
index be6b639..cfcfcbe 100644
--- a/arch/arm/mach-at91/irq.c
+++ b/arch/arm/mach-at91/irq.c
@@ -24,6 +24,12 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/types.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/err.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
@@ -34,22 +40,24 @@
 #include <asm/mach/map.h>
 
 void __iomem *at91_aic_base;
+static struct irq_domain *at91_aic_domain;
+static struct device_node *at91_aic_np;
 
 static void at91_aic_mask_irq(struct irq_data *d)
 {
 	/* Disable interrupt on AIC */
-	at91_aic_write(AT91_AIC_IDCR, 1 << d->irq);
+	at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq);
 }
 
 static void at91_aic_unmask_irq(struct irq_data *d)
 {
 	/* Enable interrupt on AIC */
-	at91_aic_write(AT91_AIC_IECR, 1 << d->irq);
+	at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq);
 }
 
 unsigned int at91_extern_irq;
 
-#define is_extern_irq(irq) ((1 << (irq)) & at91_extern_irq)
+#define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq)
 
 static int at91_aic_set_type(struct irq_data *d, unsigned type)
 {
@@ -63,13 +71,13 @@
 		srctype = AT91_AIC_SRCTYPE_RISING;
 		break;
 	case IRQ_TYPE_LEVEL_LOW:
-		if ((d->irq == AT91_ID_FIQ) || is_extern_irq(d->irq))		/* only supported on external interrupts */
+		if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq))		/* only supported on external interrupts */
 			srctype = AT91_AIC_SRCTYPE_LOW;
 		else
 			return -EINVAL;
 		break;
 	case IRQ_TYPE_EDGE_FALLING:
-		if ((d->irq == AT91_ID_FIQ) || is_extern_irq(d->irq))		/* only supported on external interrupts */
+		if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq))		/* only supported on external interrupts */
 			srctype = AT91_AIC_SRCTYPE_FALLING;
 		else
 			return -EINVAL;
@@ -78,8 +86,8 @@
 		return -EINVAL;
 	}
 
-	smr = at91_aic_read(AT91_AIC_SMR(d->irq)) & ~AT91_AIC_SRCTYPE;
-	at91_aic_write(AT91_AIC_SMR(d->irq), smr | srctype);
+	smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE;
+	at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
 	return 0;
 }
 
@@ -90,13 +98,13 @@
 
 static int at91_aic_set_wake(struct irq_data *d, unsigned value)
 {
-	if (unlikely(d->irq >= 32))
+	if (unlikely(d->hwirq >= NR_AIC_IRQS))
 		return -EINVAL;
 
 	if (value)
-		wakeups |= (1 << d->irq);
+		wakeups |= (1 << d->hwirq);
 	else
-		wakeups &= ~(1 << d->irq);
+		wakeups &= ~(1 << d->hwirq);
 
 	return 0;
 }
@@ -127,41 +135,23 @@
 	.irq_set_wake	= at91_aic_set_wake,
 };
 
-/*
- * Initialize the AIC interrupt controller.
- */
-void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
+static void __init at91_aic_hw_init(unsigned int spu_vector)
 {
-	unsigned int i;
-
-	at91_aic_base = ioremap(AT91_AIC, 512);
-
-	if (!at91_aic_base)
-		panic("Impossible to ioremap AT91_AIC\n");
+	int i;
 
 	/*
-	 * The IVR is used by macro get_irqnr_and_base to read and verify.
-	 * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
+	 * Perform 8 End Of Interrupt Command to make sure AIC
+	 * will not Lock out nIRQ
 	 */
-	for (i = 0; i < NR_AIC_IRQS; i++) {
-		/* Put irq number in Source Vector Register: */
-		at91_aic_write(AT91_AIC_SVR(i), i);
-		/* Active Low interrupt, with the specified priority */
-		at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
-
-		irq_set_chip_and_handler(i, &at91_aic_chip, handle_level_irq);
-		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
-
-		/* Perform 8 End Of Interrupt Command to make sure AIC will not Lock out nIRQ */
-		if (i < 8)
-			at91_aic_write(AT91_AIC_EOICR, 0);
-	}
+	for (i = 0; i < 8; i++)
+		at91_aic_write(AT91_AIC_EOICR, 0);
 
 	/*
-	 * Spurious Interrupt ID in Spurious Vector Register is NR_AIC_IRQS
-	 * When there is no current interrupt, the IRQ Vector Register reads the value stored in AIC_SPU
+	 * Spurious Interrupt ID in Spurious Vector Register.
+	 * When there is no current interrupt, the IRQ Vector Register
+	 * reads the value stored in AIC_SPU
 	 */
-	at91_aic_write(AT91_AIC_SPU, NR_AIC_IRQS);
+	at91_aic_write(AT91_AIC_SPU, spu_vector);
 
 	/* No debugging in AIC: Debug (Protect) Control Register */
 	at91_aic_write(AT91_AIC_DCR, 0);
@@ -170,3 +160,87 @@
 	at91_aic_write(AT91_AIC_IDCR, 0xFFFFFFFF);
 	at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
 }
+
+#if defined(CONFIG_OF)
+static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+							irq_hw_number_t hw)
+{
+	/* Put virq number in Source Vector Register */
+	at91_aic_write(AT91_AIC_SVR(hw), virq);
+
+	/* Active Low interrupt, without priority */
+	at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW);
+
+	irq_set_chip_and_handler(virq, &at91_aic_chip, handle_level_irq);
+	set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
+
+	return 0;
+}
+
+static struct irq_domain_ops at91_aic_irq_ops = {
+	.map	= at91_aic_irq_map,
+	.xlate	= irq_domain_xlate_twocell,
+};
+
+int __init at91_aic_of_init(struct device_node *node,
+				     struct device_node *parent)
+{
+	at91_aic_base = of_iomap(node, 0);
+	at91_aic_np = node;
+
+	at91_aic_domain = irq_domain_add_linear(at91_aic_np, NR_AIC_IRQS,
+						&at91_aic_irq_ops, NULL);
+	if (!at91_aic_domain)
+		panic("Unable to add AIC irq domain (DT)\n");
+
+	irq_set_default_host(at91_aic_domain);
+
+	at91_aic_hw_init(NR_AIC_IRQS);
+
+	return 0;
+}
+#endif
+
+/*
+ * Initialize the AIC interrupt controller.
+ */
+void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
+{
+	unsigned int i;
+	int irq_base;
+
+	at91_aic_base = ioremap(AT91_AIC, 512);
+	if (!at91_aic_base)
+		panic("Unable to ioremap AIC registers\n");
+
+	/* Add irq domain for AIC */
+	irq_base = irq_alloc_descs(-1, 0, NR_AIC_IRQS, 0);
+	if (irq_base < 0) {
+		WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n");
+		irq_base = 0;
+	}
+	at91_aic_domain = irq_domain_add_legacy(at91_aic_np, NR_AIC_IRQS,
+						irq_base, 0,
+						&irq_domain_simple_ops, NULL);
+
+	if (!at91_aic_domain)
+		panic("Unable to add AIC irq domain\n");
+
+	irq_set_default_host(at91_aic_domain);
+
+	/*
+	 * The IVR is used by macro get_irqnr_and_base to read and verify.
+	 * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
+	 */
+	for (i = 0; i < NR_AIC_IRQS; i++) {
+		/* Put hardware irq number in Source Vector Register: */
+		at91_aic_write(AT91_AIC_SVR(i), i);
+		/* Active Low interrupt, with the specified priority */
+		at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
+
+		irq_set_chip_and_handler(i, &at91_aic_chip, handle_level_irq);
+		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+	}
+
+	at91_aic_hw_init(NR_AIC_IRQS);
+}
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 1606379..f630250 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -136,7 +136,7 @@
 	unsigned long scsr;
 	int i;
 
-	scsr = at91_sys_read(AT91_PMC_SCSR);
+	scsr = at91_pmc_read(AT91_PMC_SCSR);
 
 	/* USB must not be using PLLB */
 	if (cpu_is_at91rm9200()) {
@@ -150,11 +150,6 @@
 			pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
 			return 0;
 		}
-	} else if (cpu_is_at91cap9()) {
-		if ((scsr & AT91CAP9_PMC_UHP) != 0) {
-			pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
-			return 0;
-		}
 	}
 
 #ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
@@ -165,7 +160,7 @@
 		if ((scsr & (AT91_PMC_PCK0 << i)) == 0)
 			continue;
 
-		css = at91_sys_read(AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
+		css = at91_pmc_read(AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
 		if (css != AT91_PMC_CSS_SLOW) {
 			pr_err("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css);
 			return 0;
@@ -193,23 +188,23 @@
 EXPORT_SYMBOL(at91_suspend_entering_slow_clock);
 
 
-static void (*slow_clock)(void);
+static void (*slow_clock)(void __iomem *pmc, void __iomem *ramc0,
+			  void __iomem *ramc1, int memctrl);
 
 #ifdef CONFIG_AT91_SLOW_CLOCK
-extern void at91_slow_clock(void);
+extern void at91_slow_clock(void __iomem *pmc, void __iomem *ramc0,
+			    void __iomem *ramc1, int memctrl);
 extern u32 at91_slow_clock_sz;
 #endif
 
-
 static int at91_pm_enter(suspend_state_t state)
 {
-	u32 saved_lpr;
 	at91_gpio_suspend();
 	at91_irq_suspend();
 
 	pr_debug("AT91: PM - wake mask %08x, pm state %d\n",
 			/* remember all the always-wake irqs */
-			(at91_sys_read(AT91_PMC_PCSR)
+			(at91_pmc_read(AT91_PMC_PCSR)
 					| (1 << AT91_ID_FIQ)
 					| (1 << AT91_ID_SYS)
 					| (at91_extern_irq))
@@ -234,11 +229,18 @@
 			 * turning off the main oscillator; reverse on wakeup.
 			 */
 			if (slow_clock) {
+				int memctrl = AT91_MEMCTRL_SDRAMC;
+
+				if (cpu_is_at91rm9200())
+					memctrl = AT91_MEMCTRL_MC;
+				else if (cpu_is_at91sam9g45())
+					memctrl = AT91_MEMCTRL_DDRSDR;
 #ifdef CONFIG_AT91_SLOW_CLOCK
 				/* copy slow_clock handler to SRAM, and call it */
 				memcpy(slow_clock, at91_slow_clock, at91_slow_clock_sz);
 #endif
-				slow_clock();
+				slow_clock(at91_pmc_base, at91_ramc_base[0],
+					   at91_ramc_base[1], memctrl);
 				break;
 			} else {
 				pr_info("AT91: PM - no slow clock mode enabled ...\n");
@@ -259,16 +261,7 @@
 			 * For ARM 926 based chips, this requirement is weaker
 			 * as at91sam9 can access a RAM in self-refresh mode.
 			 */
-			asm volatile (	"mov r0, #0\n\t"
-					"b 1f\n\t"
-					".align 5\n\t"
-					"1: mcr p15, 0, r0, c7, c10, 4\n\t"
-					: /* no output */
-					: /* no input */
-					: "r0");
-			saved_lpr = sdram_selfrefresh_enable();
-			wait_for_interrupt_enable();
-			sdram_selfrefresh_disable(saved_lpr);
+			at91_standby();
 			break;
 
 		case PM_SUSPEND_ON:
@@ -316,7 +309,7 @@
 
 #ifdef CONFIG_ARCH_AT91RM9200
 	/* AT91RM9200 SDRAM low-power mode cannot be used with self-refresh. */
-	at91_sys_write(AT91_SDRAMC_LPR, 0);
+	at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0);
 #endif
 
 	suspend_set_ops(&at91_pm_ops);
diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h
index 7eb40d2..89f56f3 100644
--- a/arch/arm/mach-at91/pm.h
+++ b/arch/arm/mach-at91/pm.h
@@ -1,5 +1,19 @@
+/*
+ * AT91 Power Management
+ *
+ * Copyright (C) 2005 David Brownell
+ *
+ * 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 __ARCH_ARM_MACH_AT91_PM
+#define __ARCH_ARM_MACH_AT91_PM
+
+#include <mach/at91_ramc.h>
 #ifdef CONFIG_ARCH_AT91RM9200
-#include <mach/at91rm9200_mc.h>
+#include <mach/at91rm9200_sdramc.h>
 
 /*
  * The AT91RM9200 goes into self-refresh mode with this command, and will
@@ -11,51 +25,37 @@
  * still in self-refresh is "not recommended", but seems to work.
  */
 
-static inline u32 sdram_selfrefresh_enable(void)
+static inline void at91rm9200_standby(void)
 {
-	u32 saved_lpr = at91_sys_read(AT91_SDRAMC_LPR);
+	u32 lpr = at91_ramc_read(0, AT91RM9200_SDRAMC_LPR);
 
-	at91_sys_write(AT91_SDRAMC_LPR, 0);
-	at91_sys_write(AT91_SDRAMC_SRR, 1);
-	return saved_lpr;
+	asm volatile(
+		"b    1f\n\t"
+		".align    5\n\t"
+		"1:  mcr    p15, 0, %0, c7, c10, 4\n\t"
+		"    str    %0, [%1, %2]\n\t"
+		"    str    %3, [%1, %4]\n\t"
+		"    mcr    p15, 0, %0, c7, c0, 4\n\t"
+		"    str    %5, [%1, %2]"
+		:
+		: "r" (0), "r" (AT91_BASE_SYS), "r" (AT91RM9200_SDRAMC_LPR),
+		  "r" (1), "r" (AT91RM9200_SDRAMC_SRR),
+		  "r" (lpr));
 }
 
-#define sdram_selfrefresh_disable(saved_lpr)	at91_sys_write(AT91_SDRAMC_LPR, saved_lpr)
-#define wait_for_interrupt_enable()		asm volatile ("mcr p15, 0, %0, c7, c0, 4" \
-								: : "r" (0))
-
-#elif defined(CONFIG_ARCH_AT91CAP9)
-#include <mach/at91sam9_ddrsdr.h>
-
-
-static inline u32 sdram_selfrefresh_enable(void)
-{
-	u32 saved_lpr, lpr;
-
-	saved_lpr = at91_ramc_read(0, AT91CAP9_DDRSDRC_LPR);
-
-	lpr = saved_lpr & ~AT91_DDRSDRC_LPCB;
-	at91_ramc_write(0, AT91CAP9_DDRSDRC_LPR, lpr | AT91_DDRSDRC_LPCB_SELF_REFRESH);
-	return saved_lpr;
-}
-
-#define sdram_selfrefresh_disable(saved_lpr)	at91_ramc_write(0, AT91CAP9_DDRSDRC_LPR, saved_lpr)
-#define wait_for_interrupt_enable()		cpu_do_idle()
+#define at91_standby at91rm9200_standby
 
 #elif defined(CONFIG_ARCH_AT91SAM9G45)
-#include <mach/at91sam9_ddrsdr.h>
 
 /* We manage both DDRAM/SDRAM controllers, we need more than one value to
  * remember.
  */
-static u32 saved_lpr1;
-
-static inline u32 sdram_selfrefresh_enable(void)
+static inline void at91sam9g45_standby(void)
 {
-	/* Those tow values allow us to delay self-refresh activation
+	/* Those two values allow us to delay self-refresh activation
 	 * to the maximum. */
 	u32 lpr0, lpr1;
-	u32 saved_lpr0;
+	u32 saved_lpr0, saved_lpr1;
 
 	saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR);
 	lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB;
@@ -69,18 +69,15 @@
 	at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0);
 	at91_ramc_write(1, AT91_DDRSDRC_LPR, lpr1);
 
-	return saved_lpr0;
+	cpu_do_idle();
+
+	at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0);
+	at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1);
 }
 
-#define sdram_selfrefresh_disable(saved_lpr0)	\
-	do { \
-		at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0); \
-		at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); \
-	} while (0)
-#define wait_for_interrupt_enable()		cpu_do_idle()
+#define at91_standby at91sam9g45_standby
 
 #else
-#include <mach/at91sam9_sdramc.h>
 
 #ifdef CONFIG_ARCH_AT91SAM9263
 /*
@@ -90,18 +87,23 @@
 #warning Assuming EB1 SDRAM controller is *NOT* used
 #endif
 
-static inline u32 sdram_selfrefresh_enable(void)
+static inline void at91sam9_standby(void)
 {
 	u32 saved_lpr, lpr;
 
 	saved_lpr = at91_ramc_read(0, AT91_SDRAMC_LPR);
 
 	lpr = saved_lpr & ~AT91_SDRAMC_LPCB;
-	at91_ramc_write(0, AT91_SDRAMC_LPR, lpr | AT91_SDRAMC_LPCB_SELF_REFRESH);
-	return saved_lpr;
+	at91_ramc_write(0, AT91_SDRAMC_LPR, lpr |
+			AT91_SDRAMC_LPCB_SELF_REFRESH);
+
+	cpu_do_idle();
+
+	at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr);
 }
 
-#define sdram_selfrefresh_disable(saved_lpr)	at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr)
-#define wait_for_interrupt_enable()		cpu_do_idle()
+#define at91_standby at91sam9_standby
+
+#endif
 
 #endif
diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S
index 92dfb84..db54521 100644
--- a/arch/arm/mach-at91/pm_slowclock.S
+++ b/arch/arm/mach-at91/pm_slowclock.S
@@ -15,15 +15,7 @@
 #include <linux/linkage.h>
 #include <mach/hardware.h>
 #include <mach/at91_pmc.h>
-
-#if defined(CONFIG_ARCH_AT91RM9200)
-#include <mach/at91rm9200_mc.h>
-#elif defined(CONFIG_ARCH_AT91CAP9) \
-	|| defined(CONFIG_ARCH_AT91SAM9G45)
-#include <mach/at91sam9_ddrsdr.h>
-#else
-#include <mach/at91sam9_sdramc.h>
-#endif
+#include <mach/at91_ramc.h>
 
 
 #ifdef CONFIG_ARCH_AT91SAM9263
@@ -47,17 +39,23 @@
 #define PLLALOCK_TIMEOUT	1000
 #define PLLBLOCK_TIMEOUT	1000
 
+pmc	.req	r0
+sdramc	.req	r1
+ramc1	.req	r2
+memctrl	.req	r3
+tmp1	.req	r4
+tmp2	.req	r5
 
 /*
  * Wait until master clock is ready (after switching master clock source)
  */
 	.macro wait_mckrdy
-	mov	r4, #MCKRDY_TIMEOUT
-1:	sub	r4, r4, #1
-	cmp	r4, #0
+	mov	tmp2, #MCKRDY_TIMEOUT
+1:	sub	tmp2, tmp2, #1
+	cmp	tmp2, #0
 	beq	2f
-	ldr	r3, [r1, #(AT91_PMC_SR - AT91_PMC)]
-	tst	r3, #AT91_PMC_MCKRDY
+	ldr	tmp1, [pmc, #AT91_PMC_SR]
+	tst	tmp1, #AT91_PMC_MCKRDY
 	beq	1b
 2:
 	.endm
@@ -66,12 +64,12 @@
  * Wait until master oscillator has stabilized.
  */
 	.macro wait_moscrdy
-	mov	r4, #MOSCRDY_TIMEOUT
-1:	sub	r4, r4, #1
-	cmp	r4, #0
+	mov	tmp2, #MOSCRDY_TIMEOUT
+1:	sub	tmp2, tmp2, #1
+	cmp	tmp2, #0
 	beq	2f
-	ldr	r3, [r1, #(AT91_PMC_SR - AT91_PMC)]
-	tst	r3, #AT91_PMC_MOSCS
+	ldr	tmp1, [pmc, #AT91_PMC_SR]
+	tst	tmp1, #AT91_PMC_MOSCS
 	beq	1b
 2:
 	.endm
@@ -80,12 +78,12 @@
  * Wait until PLLA has locked.
  */
 	.macro wait_pllalock
-	mov	r4, #PLLALOCK_TIMEOUT
-1:	sub	r4, r4, #1
-	cmp	r4, #0
+	mov	tmp2, #PLLALOCK_TIMEOUT
+1:	sub	tmp2, tmp2, #1
+	cmp	tmp2, #0
 	beq	2f
-	ldr	r3, [r1, #(AT91_PMC_SR - AT91_PMC)]
-	tst	r3, #AT91_PMC_LOCKA
+	ldr	tmp1, [pmc, #AT91_PMC_SR]
+	tst	tmp1, #AT91_PMC_LOCKA
 	beq	1b
 2:
 	.endm
@@ -94,80 +92,98 @@
  * Wait until PLLB has locked.
  */
 	.macro wait_pllblock
-	mov	r4, #PLLBLOCK_TIMEOUT
-1:	sub	r4, r4, #1
-	cmp	r4, #0
+	mov	tmp2, #PLLBLOCK_TIMEOUT
+1:	sub	tmp2, tmp2, #1
+	cmp	tmp2, #0
 	beq	2f
-	ldr	r3, [r1, #(AT91_PMC_SR - AT91_PMC)]
-	tst	r3, #AT91_PMC_LOCKB
+	ldr	tmp1, [pmc, #AT91_PMC_SR]
+	tst	tmp1, #AT91_PMC_LOCKB
 	beq	1b
 2:
 	.endm
 
 	.text
 
+/* void at91_slow_clock(void __iomem *pmc, void __iomem *sdramc,
+ *			void __iomem *ramc1, int memctrl)
+ */
 ENTRY(at91_slow_clock)
 	/* Save registers on stack */
-	stmfd	sp!, {r0 - r12, lr}
+	stmfd	sp!, {r4 - r12, lr}
 
 	/*
 	 * Register usage:
-	 *  R1 = Base address of AT91_PMC
-	 *  R2 = Base address of RAM Controller (SDRAM, DDRSDR, or AT91_SYS)
-	 *  R3 = temporary register
+	 *  R0 = Base address of AT91_PMC
+	 *  R1 = Base address of RAM Controller (SDRAM, DDRSDR, or AT91_SYS)
+	 *  R2 = Base address of second RAM Controller or 0 if not present
+	 *  R3 = Memory controller
 	 *  R4 = temporary register
-	 *  R5 = Base address of second RAM Controller or 0 if not present
+	 *  R5 = temporary register
 	 */
-	ldr	r1, .at91_va_base_pmc
-	ldr	r2, .at91_va_base_sdramc
-	ldr	r5, .at91_va_base_ramc1
 
 	/* Drain write buffer */
-	mov	r0, #0
-	mcr	p15, 0, r0, c7, c10, 4
+	mov	tmp1, #0
+	mcr	p15, 0, tmp1, c7, c10, 4
 
-#ifdef CONFIG_ARCH_AT91RM9200
+	cmp	memctrl, #AT91_MEMCTRL_MC
+	bne	ddr_sr_enable
+
+	/*
+	 * at91rm9200 Memory controller
+	 */
 	/* Put SDRAM in self-refresh mode */
-	mov	r3, #1
-	str	r3, [r2, #AT91_SDRAMC_SRR]
-#elif defined(CONFIG_ARCH_AT91CAP9) \
-	|| defined(CONFIG_ARCH_AT91SAM9G45)
+	mov	tmp1, #1
+	str	tmp1, [sdramc, #AT91RM9200_SDRAMC_SRR]
+	b	sdr_sr_done
+
+	/*
+	 * DDRSDR Memory controller
+	 */
+ddr_sr_enable:
+	cmp	memctrl, #AT91_MEMCTRL_DDRSDR
+	bne	sdr_sr_enable
 
 	/* prepare for DDRAM self-refresh mode */
-	ldr	r3, [r2, #AT91_DDRSDRC_LPR]
-	str	r3, .saved_sam9_lpr
-	bic	r3, #AT91_DDRSDRC_LPCB
-	orr	r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+	ldr	tmp1, [sdramc, #AT91_DDRSDRC_LPR]
+	str	tmp1, .saved_sam9_lpr
+	bic	tmp1, #AT91_DDRSDRC_LPCB
+	orr	tmp1, #AT91_DDRSDRC_LPCB_SELF_REFRESH
 
 	/* figure out if we use the second ram controller */
-	cmp	r5, #0
-	ldrne	r4, [r5, #AT91_DDRSDRC_LPR]
-	strne	r4, .saved_sam9_lpr1
-	bicne	r4, #AT91_DDRSDRC_LPCB
-	orrne	r4, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+	cmp	ramc1, #0
+	ldrne	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+	strne	tmp2, .saved_sam9_lpr1
+	bicne	tmp2, #AT91_DDRSDRC_LPCB
+	orrne	tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
 
 	/* Enable DDRAM self-refresh mode */
-	str	r3, [r2, #AT91_DDRSDRC_LPR]
-	strne	r4, [r5, #AT91_DDRSDRC_LPR]
-#else
+	str	tmp1, [sdramc, #AT91_DDRSDRC_LPR]
+	strne	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+
+	b	sdr_sr_done
+
+	/*
+	 * SDRAMC Memory controller
+	 */
+sdr_sr_enable:
 	/* Enable SDRAM self-refresh mode */
-	ldr	r3, [r2, #AT91_SDRAMC_LPR]
-	str	r3, .saved_sam9_lpr
+	ldr	tmp1, [sdramc, #AT91_SDRAMC_LPR]
+	str	tmp1, .saved_sam9_lpr
 
-	bic	r3, #AT91_SDRAMC_LPCB
-	orr	r3, #AT91_SDRAMC_LPCB_SELF_REFRESH
-	str	r3, [r2, #AT91_SDRAMC_LPR]
-#endif
+	bic	tmp1, #AT91_SDRAMC_LPCB
+	orr	tmp1, #AT91_SDRAMC_LPCB_SELF_REFRESH
+	str	tmp1, [sdramc, #AT91_SDRAMC_LPR]
 
+sdr_sr_done:
 	/* Save Master clock setting */
-	ldr	r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)]
-	str	r3, .saved_mckr
+	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
+	str	tmp1, .saved_mckr
 
 	/*
 	 * Set the Master clock source to slow clock
 	 */
-	bic	r3, r3, #AT91_PMC_CSS
-	str	r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)]
+	bic	tmp1, tmp1, #AT91_PMC_CSS
+	str	tmp1, [pmc, #AT91_PMC_MCKR]
 
 	wait_mckrdy
 
@@ -177,61 +193,61 @@
 	 *
 	 * See AT91RM9200 errata #27 and #28 for details.
 	 */
-	mov	r3, #0
-	str	r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)]
+	mov	tmp1, #0
+	str	tmp1, [pmc, #AT91_PMC_MCKR]
 
 	wait_mckrdy
 #endif
 
 	/* Save PLLA setting and disable it */
-	ldr	r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)]
-	str	r3, .saved_pllar
+	ldr	tmp1, [pmc, #AT91_CKGR_PLLAR]
+	str	tmp1, .saved_pllar
 
-	mov	r3, #AT91_PMC_PLLCOUNT
-	orr	r3, r3, #(1 << 29)		/* bit 29 always set */
-	str	r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)]
+	mov	tmp1, #AT91_PMC_PLLCOUNT
+	orr	tmp1, tmp1, #(1 << 29)		/* bit 29 always set */
+	str	tmp1, [pmc, #AT91_CKGR_PLLAR]
 
 	/* Save PLLB setting and disable it */
-	ldr	r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]
-	str	r3, .saved_pllbr
+	ldr	tmp1, [pmc, #AT91_CKGR_PLLBR]
+	str	tmp1, .saved_pllbr
 
-	mov	r3, #AT91_PMC_PLLCOUNT
-	str	r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]
+	mov	tmp1, #AT91_PMC_PLLCOUNT
+	str	tmp1, [pmc, #AT91_CKGR_PLLBR]
 
 	/* Turn off the main oscillator */
-	ldr	r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)]
-	bic	r3, r3, #AT91_PMC_MOSCEN
-	str	r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)]
+	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
+	bic	tmp1, tmp1, #AT91_PMC_MOSCEN
+	str	tmp1, [pmc, #AT91_CKGR_MOR]
 
 	/* Wait for interrupt */
-	mcr	p15, 0, r0, c7, c0, 4
+	mcr	p15, 0, tmp1, c7, c0, 4
 
 	/* Turn on the main oscillator */
-	ldr	r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)]
-	orr	r3, r3, #AT91_PMC_MOSCEN
-	str	r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)]
+	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
+	orr	tmp1, tmp1, #AT91_PMC_MOSCEN
+	str	tmp1, [pmc, #AT91_CKGR_MOR]
 
 	wait_moscrdy
 
 	/* Restore PLLB setting */
-	ldr	r3, .saved_pllbr
-	str	r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]
+	ldr	tmp1, .saved_pllbr
+	str	tmp1, [pmc, #AT91_CKGR_PLLBR]
 
-	tst	r3, #(AT91_PMC_MUL &  0xff0000)
+	tst	tmp1, #(AT91_PMC_MUL &  0xff0000)
 	bne	1f
-	tst	r3, #(AT91_PMC_MUL & ~0xff0000)
+	tst	tmp1, #(AT91_PMC_MUL & ~0xff0000)
 	beq	2f
 1:
 	wait_pllblock
 2:
 
 	/* Restore PLLA setting */
-	ldr	r3, .saved_pllar
-	str	r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)]
+	ldr	tmp1, .saved_pllar
+	str	tmp1, [pmc, #AT91_CKGR_PLLAR]
 
-	tst	r3, #(AT91_PMC_MUL &  0xff0000)
+	tst	tmp1, #(AT91_PMC_MUL &  0xff0000)
 	bne	3f
-	tst	r3, #(AT91_PMC_MUL & ~0xff0000)
+	tst	tmp1, #(AT91_PMC_MUL & ~0xff0000)
 	beq	4f
 3:
 	wait_pllalock
@@ -244,11 +260,11 @@
 	 *
 	 * See AT91RM9200 errata #27 and #28 for details.
 	 */
-	ldr	r3, .saved_mckr
-	tst	r3, #AT91_PMC_PRES
+	ldr	tmp1, .saved_mckr
+	tst	tmp1, #AT91_PMC_PRES
 	beq	2f
-	and	r3, r3, #AT91_PMC_PRES
-	str	r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)]
+	and	tmp1, tmp1, #AT91_PMC_PRES
+	str	tmp1, [pmc, #AT91_PMC_MCKR]
 
 	wait_mckrdy
 #endif
@@ -256,32 +272,45 @@
 	/*
 	 * Restore master clock setting
 	 */
-2:	ldr	r3, .saved_mckr
-	str	r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)]
+2:	ldr	tmp1, .saved_mckr
+	str	tmp1, [pmc, #AT91_PMC_MCKR]
 
 	wait_mckrdy
 
-#ifdef CONFIG_ARCH_AT91RM9200
-	/* Do nothing - self-refresh is automatically disabled. */
-#elif defined(CONFIG_ARCH_AT91CAP9) \
-	|| defined(CONFIG_ARCH_AT91SAM9G45)
+	/*
+	 * at91rm9200 Memory controller
+	 * Do nothing - self-refresh is automatically disabled.
+	 */
+	cmp	memctrl, #AT91_MEMCTRL_MC
+	beq	ram_restored
+
+	/*
+	 * DDRSDR Memory controller
+	 */
+	cmp	memctrl, #AT91_MEMCTRL_DDRSDR
+	bne	sdr_en_restore
 	/* Restore LPR on AT91 with DDRAM */
-	ldr	r3, .saved_sam9_lpr
-	str	r3, [r2, #AT91_DDRSDRC_LPR]
+	ldr	tmp1, .saved_sam9_lpr
+	str	tmp1, [sdramc, #AT91_DDRSDRC_LPR]
 
 	/* if we use the second ram controller */
-	cmp	r5, #0
-	ldrne	r4, .saved_sam9_lpr1
-	strne	r4, [r5, #AT91_DDRSDRC_LPR]
+	cmp	ramc1, #0
+	ldrne	tmp2, .saved_sam9_lpr1
+	strne	tmp2, [ramc1, #AT91_DDRSDRC_LPR]
 
-#else
+	b	ram_restored
+
+	/*
+	 * SDRAMC Memory controller
+	 */
+sdr_en_restore:
 	/* Restore LPR on AT91 with SDRAM */
-	ldr	r3, .saved_sam9_lpr
-	str	r3, [r2, #AT91_SDRAMC_LPR]
-#endif
+	ldr	tmp1, .saved_sam9_lpr
+	str	tmp1, [sdramc, #AT91_SDRAMC_LPR]
 
+ram_restored:
 	/* Restore registers, and return */
-	ldmfd	sp!, {r0 - r12, pc}
+	ldmfd	sp!, {r4 - r12, pc}
 
 
 .saved_mckr:
@@ -299,27 +328,5 @@
 .saved_sam9_lpr1:
 	.word 0
 
-.at91_va_base_pmc:
-	.word AT91_VA_BASE_SYS + AT91_PMC
-
-#ifdef CONFIG_ARCH_AT91RM9200
-.at91_va_base_sdramc:
-	.word AT91_VA_BASE_SYS
-#elif defined(CONFIG_ARCH_AT91CAP9) \
-	|| defined(CONFIG_ARCH_AT91SAM9G45)
-.at91_va_base_sdramc:
-	.word AT91_VA_BASE_SYS + AT91_DDRSDRC0
-#else
-.at91_va_base_sdramc:
-	.word AT91_VA_BASE_SYS + AT91_SDRAMC0
-#endif
-
-.at91_va_base_ramc1:
-#if defined(CONFIG_ARCH_AT91SAM9G45)
-	.word AT91_VA_BASE_SYS + AT91_DDRSDRC1
-#else
-	.word 0
-#endif
-
 ENTRY(at91_slow_clock_sz)
 	.word .-at91_slow_clock
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
index 69d3fc4..97cc04d 100644
--- a/arch/arm/mach-at91/setup.c
+++ b/arch/arm/mach-at91/setup.c
@@ -9,7 +9,9 @@
 #include <linux/io.h>
 #include <linux/mm.h>
 #include <linux/pm.h>
+#include <linux/of_address.h>
 
+#include <asm/system_misc.h>
 #include <asm/mach/map.h>
 
 #include <mach/hardware.h>
@@ -51,6 +53,19 @@
 	at91_gpio_irq_setup();
 }
 
+void __iomem *at91_ramc_base[2];
+
+void __init at91_ioremap_ramc(int id, u32 addr, u32 size)
+{
+	if (id < 0 || id > 1) {
+		pr_emerg("Wrong RAM controller id (%d), cannot continue\n", id);
+		BUG();
+	}
+	at91_ramc_base[id] = ioremap(addr, size);
+	if (!at91_ramc_base[id])
+		panic("Impossible to ioremap ramc.%d 0x%x\n", id, addr);
+}
+
 static struct map_desc sram_desc[2] __initdata;
 
 void __init at91_init_sram(int bank, unsigned long base, unsigned int length)
@@ -86,20 +101,6 @@
 	socid = cidr & ~AT91_CIDR_VERSION;
 
 	switch (socid) {
-	case ARCH_ID_AT91CAP9: {
-#ifdef CONFIG_AT91_PMC_UNIT
-		u32 pmc_ver = at91_sys_read(AT91_PMC_VER);
-
-		if (pmc_ver == ARCH_REVISION_CAP9_B)
-			at91_soc_initdata.subtype = AT91_SOC_CAP9_REV_B;
-		else if (pmc_ver == ARCH_REVISION_CAP9_C)
-			at91_soc_initdata.subtype = AT91_SOC_CAP9_REV_C;
-#endif
-		at91_soc_initdata.type = AT91_SOC_CAP9;
-		at91_boot_soc = at91cap9_soc;
-		break;
-	}
-
 	case ARCH_ID_AT91RM9200:
 		at91_soc_initdata.type = AT91_SOC_RM9200;
 		at91_boot_soc = at91rm9200_soc;
@@ -200,7 +201,6 @@
 
 static const char *soc_name[] = {
 	[AT91_SOC_RM9200]	= "at91rm9200",
-	[AT91_SOC_CAP9]		= "at91cap9",
 	[AT91_SOC_SAM9260]	= "at91sam9260",
 	[AT91_SOC_SAM9261]	= "at91sam9261",
 	[AT91_SOC_SAM9263]	= "at91sam9263",
@@ -221,8 +221,6 @@
 static const char *soc_subtype_name[] = {
 	[AT91_SOC_RM9200_BGA]	= "at91rm9200 BGA",
 	[AT91_SOC_RM9200_PQFP]	= "at91rm9200 PQFP",
-	[AT91_SOC_CAP9_REV_B]	= "at91cap9 revB",
-	[AT91_SOC_CAP9_REV_C]	= "at91cap9 revC",
 	[AT91_SOC_SAM9XE]	= "at91sam9xe",
 	[AT91_SOC_SAM9G45ES]	= "at91sam9g45es",
 	[AT91_SOC_SAM9M10]	= "at91sam9m10",
@@ -293,6 +291,159 @@
 		panic("Impossible to ioremap at91_rstc_base\n");
 }
 
+void __iomem *at91_matrix_base;
+
+void __init at91_ioremap_matrix(u32 base_addr)
+{
+	at91_matrix_base = ioremap(base_addr, 512);
+	if (!at91_matrix_base)
+		panic("Impossible to ioremap at91_matrix_base\n");
+}
+
+#if defined(CONFIG_OF)
+static struct of_device_id rstc_ids[] = {
+	{ .compatible = "atmel,at91sam9260-rstc", .data = at91sam9_alt_restart },
+	{ .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart },
+	{ /*sentinel*/ }
+};
+
+static void at91_dt_rstc(void)
+{
+	struct device_node *np;
+	const struct of_device_id *of_id;
+
+	np = of_find_matching_node(NULL, rstc_ids);
+	if (!np)
+		panic("unable to find compatible rstc node in dtb\n");
+
+	at91_rstc_base = of_iomap(np, 0);
+	if (!at91_rstc_base)
+		panic("unable to map rstc cpu registers\n");
+
+	of_id = of_match_node(rstc_ids, np);
+	if (!of_id)
+		panic("AT91: rtsc no restart function availlable\n");
+
+	arm_pm_restart = of_id->data;
+
+	of_node_put(np);
+}
+
+static struct of_device_id ramc_ids[] = {
+	{ .compatible = "atmel,at91sam9260-sdramc" },
+	{ .compatible = "atmel,at91sam9g45-ddramc" },
+	{ /*sentinel*/ }
+};
+
+static void at91_dt_ramc(void)
+{
+	struct device_node *np;
+
+	np = of_find_matching_node(NULL, ramc_ids);
+	if (!np)
+		panic("unable to find compatible ram conroller node in dtb\n");
+
+	at91_ramc_base[0] = of_iomap(np, 0);
+	if (!at91_ramc_base[0])
+		panic("unable to map ramc[0] cpu registers\n");
+	/* the controller may have 2 banks */
+	at91_ramc_base[1] = of_iomap(np, 1);
+
+	of_node_put(np);
+}
+
+static struct of_device_id shdwc_ids[] = {
+	{ .compatible = "atmel,at91sam9260-shdwc", },
+	{ .compatible = "atmel,at91sam9rl-shdwc", },
+	{ .compatible = "atmel,at91sam9x5-shdwc", },
+	{ /*sentinel*/ }
+};
+
+static const char *shdwc_wakeup_modes[] = {
+	[AT91_SHDW_WKMODE0_NONE]	= "none",
+	[AT91_SHDW_WKMODE0_HIGH]	= "high",
+	[AT91_SHDW_WKMODE0_LOW]		= "low",
+	[AT91_SHDW_WKMODE0_ANYLEVEL]	= "any",
+};
+
+const int at91_dtget_shdwc_wakeup_mode(struct device_node *np)
+{
+	const char *pm;
+	int err, i;
+
+	err = of_property_read_string(np, "atmel,wakeup-mode", &pm);
+	if (err < 0)
+		return AT91_SHDW_WKMODE0_ANYLEVEL;
+
+	for (i = 0; i < ARRAY_SIZE(shdwc_wakeup_modes); i++)
+		if (!strcasecmp(pm, shdwc_wakeup_modes[i]))
+			return i;
+
+	return -ENODEV;
+}
+
+static void at91_dt_shdwc(void)
+{
+	struct device_node *np;
+	int wakeup_mode;
+	u32 reg;
+	u32 mode = 0;
+
+	np = of_find_matching_node(NULL, shdwc_ids);
+	if (!np) {
+		pr_debug("AT91: unable to find compatible shutdown (shdwc) conroller node in dtb\n");
+		return;
+	}
+
+	at91_shdwc_base = of_iomap(np, 0);
+	if (!at91_shdwc_base)
+		panic("AT91: unable to map shdwc cpu registers\n");
+
+	wakeup_mode = at91_dtget_shdwc_wakeup_mode(np);
+	if (wakeup_mode < 0) {
+		pr_warn("AT91: shdwc unknown wakeup mode\n");
+		goto end;
+	}
+
+	if (!of_property_read_u32(np, "atmel,wakeup-counter", &reg)) {
+		if (reg > AT91_SHDW_CPTWK0_MAX) {
+			pr_warn("AT91: shdwc wakeup conter 0x%x > 0x%x reduce it to 0x%x\n",
+				reg, AT91_SHDW_CPTWK0_MAX, AT91_SHDW_CPTWK0_MAX);
+			reg = AT91_SHDW_CPTWK0_MAX;
+		}
+		mode |= AT91_SHDW_CPTWK0_(reg);
+	}
+
+	if (of_property_read_bool(np, "atmel,wakeup-rtc-timer"))
+			mode |= AT91_SHDW_RTCWKEN;
+
+	if (of_property_read_bool(np, "atmel,wakeup-rtt-timer"))
+			mode |= AT91_SHDW_RTTWKEN;
+
+	at91_shdwc_write(AT91_SHDW_MR, wakeup_mode | mode);
+
+end:
+	pm_power_off = at91sam9_poweroff;
+
+	of_node_put(np);
+}
+
+void __init at91_dt_initialize(void)
+{
+	at91_dt_rstc();
+	at91_dt_ramc();
+	at91_dt_shdwc();
+
+	/* Init clock subsystem */
+	at91_dt_clock_init();
+
+	/* Register the processor-specific clocks */
+	at91_boot_soc.register_clocks();
+
+	at91_boot_soc.init();
+}
+#endif
+
 void __init at91_initialize(unsigned long main_clock)
 {
 	at91_boot_soc.ioremap_registers();
diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
index 4588ae6..5db4aa4 100644
--- a/arch/arm/mach-at91/soc.h
+++ b/arch/arm/mach-at91/soc.h
@@ -13,7 +13,6 @@
 };
 
 extern struct at91_init_soc at91_boot_soc;
-extern struct at91_init_soc at91cap9_soc;
 extern struct at91_init_soc at91rm9200_soc;
 extern struct at91_init_soc at91sam9260_soc;
 extern struct at91_init_soc at91sam9261_soc;
@@ -27,10 +26,6 @@
 	return at91_boot_soc.init != NULL;
 }
 
-#if !defined(CONFIG_ARCH_AT91CAP9)
-#define at91cap9_soc	at91_boot_soc
-#endif
-
 #if !defined(CONFIG_ARCH_AT91RM9200)
 #define at91rm9200_soc	at91_boot_soc
 #endif
diff --git a/arch/arm/mach-bcmring/core.c b/arch/arm/mach-bcmring/core.c
index 6b67b7e..22e4e0a 100644
--- a/arch/arm/mach-bcmring/core.c
+++ b/arch/arm/mach-bcmring/core.c
@@ -52,27 +52,8 @@
 #include <mach/csp/chipcHw_inline.h>
 #include <mach/csp/tmrHw_reg.h>
 
-#define AMBA_DEVICE(name, initname, base, plat, size)       \
-static struct amba_device name##_device = {     \
-   .dev = {                                     \
-      .coherent_dma_mask = ~0,                  \
-      .init_name = initname,                    \
-      .platform_data = plat                     \
-   },                                           \
-   .res = {                                     \
-      .start = MM_ADDR_IO_##base,               \
-		.end = MM_ADDR_IO_##base + (size) - 1,    \
-      .flags = IORESOURCE_MEM                   \
-   },                                           \
-   .dma_mask = ~0,                              \
-   .irq = {                                     \
-      IRQ_##base                                \
-   }                                            \
-}
-
-
-AMBA_DEVICE(uartA, "uarta", UARTA, NULL, SZ_4K);
-AMBA_DEVICE(uartB, "uartb", UARTB, NULL, SZ_4K);
+static AMBA_APB_DEVICE(uartA, "uarta", MM_ADDR_IO_UARTA, { IRQ_UARTA }, NULL);
+static AMBA_APB_DEVICE(uartB, "uartb", MM_ADDR_IO_UARTB, { IRQ_UARTB }, NULL);
 
 static struct clk pll1_clk = {
 	.name = "PLL1",
diff --git a/arch/arm/mach-bcmring/include/mach/entry-macro.S b/arch/arm/mach-bcmring/include/mach/entry-macro.S
index 94c950d..2f316f0 100644
--- a/arch/arm/mach-bcmring/include/mach/entry-macro.S
+++ b/arch/arm/mach-bcmring/include/mach/entry-macro.S
@@ -21,9 +21,6 @@
 #include <mach/hardware.h>
 #include <mach/csp/mm_io.h>
 
-		.macro	disable_fiq
-		.endm
-
 		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 		ldr	\base, =(MM_IO_BASE_INTC0)
 		ldr	\irqstat, [\base, #0]		@ get status
@@ -77,6 +74,3 @@
 
 		.macro  get_irqnr_preamble, base, tmp
 		.endm
-
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
diff --git a/arch/arm/mach-bcmring/include/mach/io.h b/arch/arm/mach-bcmring/include/mach/io.h
deleted file mode 100644
index dae5e9b..0000000
--- a/arch/arm/mach-bcmring/include/mach/io.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *
- *  Copyright (C) 1999 ARM 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#include <mach/hardware.h>
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-/*
- * We don't actually have real ISA nor PCI buses, but there is so many
- * drivers out there that might just work if we fake them...
- */
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#endif
diff --git a/arch/arm/mach-bcmring/include/mach/system.h b/arch/arm/mach-bcmring/include/mach/system.h
deleted file mode 100644
index cb78250..0000000
--- a/arch/arm/mach-bcmring/include/mach/system.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-clps711x/common.c b/arch/arm/mach-clps711x/common.c
index ab1711b..3c5b5bb 100644
--- a/arch/arm/mach-clps711x/common.c
+++ b/arch/arm/mach-clps711x/common.c
@@ -37,6 +37,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
 #include <asm/hardware/clps7111.h>
+#include <asm/system_misc.h>
 
 /*
  * This maps the generic CLPS711x registers
@@ -225,3 +226,19 @@
 {
 	soft_restart(0);
 }
+
+static void clps711x_idle(void)
+{
+	clps_writel(1, HALT);
+	__asm__ __volatile__(
+	"mov    r0, r0\n\
+	mov     r0, r0");
+}
+
+static int __init clps711x_idle_init(void)
+{
+	arm_pm_idle = clps711x_idle;
+	return 0;
+}
+
+arch_initcall(clps711x_idle_init);
diff --git a/arch/arm/mach-clps711x/edb7211-mm.c b/arch/arm/mach-clps711x/edb7211-mm.c
index 0bea145..4372f06 100644
--- a/arch/arm/mach-clps711x/edb7211-mm.c
+++ b/arch/arm/mach-clps711x/edb7211-mm.c
@@ -21,6 +21,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/bug.h>
 
 #include <mach/hardware.h>
 #include <asm/page.h>
diff --git a/arch/arm/mach-clps711x/include/mach/entry-macro.S b/arch/arm/mach-clps711x/include/mach/entry-macro.S
index 90fa2f7..125af59 100644
--- a/arch/arm/mach-clps711x/include/mach/entry-macro.S
+++ b/arch/arm/mach-clps711x/include/mach/entry-macro.S
@@ -10,15 +10,9 @@
 #include <mach/hardware.h>
 #include <asm/hardware/clps7111.h>
 
-		.macro	disable_fiq
-		.endm
-
 		.macro	get_irqnr_preamble, base, tmp
 		.endm
 
-		.macro	arch_ret_to_user, tmp1, tmp2
-		.endm
-
 #if (INTSR2 - INTSR1) != (INTMR2 - INTMR1)
 #error INTSR stride != INTMR stride
 #endif
diff --git a/arch/arm/mach-clps711x/include/mach/io.h b/arch/arm/mach-clps711x/include/mach/io.h
deleted file mode 100644
index 2e0b3ce..0000000
--- a/arch/arm/mach-clps711x/include/mach/io.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *  arch/arm/mach-clps711x/include/mach/io.h
- *
- *  Copyright (C) 1999 ARM 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-/*
- * We don't support ins[lb]/outs[lb].  Make them fault.
- */
-#define __raw_readsb(p,d,l)	do { *(int *)0 = 0; } while (0)
-#define __raw_readsl(p,d,l)	do { *(int *)0 = 0; } while (0)
-#define __raw_writesb(p,d,l)	do { *(int *)0 = 0; } while (0)
-#define __raw_writesl(p,d,l)	do { *(int *)0 = 0; } while (0)
-
-#endif
diff --git a/arch/arm/mach-clps711x/include/mach/system.h b/arch/arm/mach-clps711x/include/mach/system.h
deleted file mode 100644
index 23d6ef8..0000000
--- a/arch/arm/mach-clps711x/include/mach/system.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *  arch/arm/mach-clps711x/include/mach/system.h
- *
- *  Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-#include <linux/io.h>
-#include <mach/hardware.h>
-#include <asm/hardware/clps7111.h>
-
-static inline void arch_idle(void)
-{
-	clps_writel(1, HALT);
-	__asm__ __volatile__(
-	"mov	r0, r0\n\
-	mov	r0, r0");
-}
-
-#endif
diff --git a/arch/arm/mach-clps711x/include/mach/uncompress.h b/arch/arm/mach-clps711x/include/mach/uncompress.h
index 7164310..35ed731 100644
--- a/arch/arm/mach-clps711x/include/mach/uncompress.h
+++ b/arch/arm/mach-clps711x/include/mach/uncompress.h
@@ -17,7 +17,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#include <mach/io.h>
 #include <mach/hardware.h>
 #include <asm/hardware/clps7111.h>
 
diff --git a/arch/arm/mach-clps711x/p720t-leds.c b/arch/arm/mach-clps711x/p720t-leds.c
index 1512144..dd9a6cd 100644
--- a/arch/arm/mach-clps711x/p720t-leds.c
+++ b/arch/arm/mach-clps711x/p720t-leds.c
@@ -25,7 +25,6 @@
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
-#include <asm/system.h>
 #include <asm/mach-types.h>
 
 #include <asm/hardware/clps7111.h>
diff --git a/arch/arm/mach-cns3xxx/core.c b/arch/arm/mach-cns3xxx/core.c
index 941a308..031805b 100644
--- a/arch/arm/mach-cns3xxx/core.c
+++ b/arch/arm/mach-cns3xxx/core.c
@@ -72,13 +72,13 @@
 /* used by entry-macro.S */
 void __init cns3xxx_init_irq(void)
 {
-	gic_init(0, 29, __io(CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT),
-		 __io(CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT));
+	gic_init(0, 29, IOMEM(CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT),
+		 IOMEM(CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT));
 }
 
 void cns3xxx_power_off(void)
 {
-	u32 __iomem *pm_base = __io(CNS3XXX_PM_BASE_VIRT);
+	u32 __iomem *pm_base = IOMEM(CNS3XXX_PM_BASE_VIRT);
 	u32 clkctrl;
 
 	printk(KERN_INFO "powering system down...\n");
@@ -237,7 +237,7 @@
 
 static void __init cns3xxx_timer_init(void)
 {
-	cns3xxx_tmr1 = __io(CNS3XXX_TIMER1_2_3_BASE_VIRT);
+	cns3xxx_tmr1 = IOMEM(CNS3XXX_TIMER1_2_3_BASE_VIRT);
 
 	__cns3xxx_timer_init(IRQ_CNS3XXX_TIMER0);
 }
diff --git a/arch/arm/mach-cns3xxx/devices.c b/arch/arm/mach-cns3xxx/devices.c
index 79d1fb0..1e40c99 100644
--- a/arch/arm/mach-cns3xxx/devices.c
+++ b/arch/arm/mach-cns3xxx/devices.c
@@ -98,7 +98,7 @@
 
 void __init cns3xxx_sdhci_init(void)
 {
-	u32 __iomem *gpioa = __io(CNS3XXX_MISC_BASE_VIRT + 0x0014);
+	u32 __iomem *gpioa = IOMEM(CNS3XXX_MISC_BASE_VIRT + 0x0014);
 	u32 gpioa_pins = __raw_readl(gpioa);
 
 	/* MMC/SD pins share with GPIOA */
diff --git a/arch/arm/mach-cns3xxx/include/mach/entry-macro.S b/arch/arm/mach-cns3xxx/include/mach/entry-macro.S
deleted file mode 100644
index 01c57df..0000000
--- a/arch/arm/mach-cns3xxx/include/mach/entry-macro.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Low-level IRQ helper macros for Cavium Networks platforms
- *
- * Copyright 2008 Cavium Networks
- *
- * This file 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.
- */
-
-		.macro	disable_fiq
-		.endm
-
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
diff --git a/arch/arm/mach-cns3xxx/include/mach/io.h b/arch/arm/mach-cns3xxx/include/mach/io.h
deleted file mode 100644
index 33b6fc1..0000000
--- a/arch/arm/mach-cns3xxx/include/mach/io.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright 2008 Cavium Networks
- * Copyright 2003 ARM Limited
- *
- * This file 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 __MACH_IO_H
-#define __MACH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a)			__typesafe_io(a)
-#define __mem_pci(a)		(a)
-
-#endif
diff --git a/arch/arm/mach-cns3xxx/include/mach/system.h b/arch/arm/mach-cns3xxx/include/mach/system.h
deleted file mode 100644
index 9e56b7d..0000000
--- a/arch/arm/mach-cns3xxx/include/mach/system.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2000 Deep Blue Solutions Ltd
- * Copyright 2003 ARM Limited
- * Copyright 2008 Cavium Networks
- *
- * This file 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 __MACH_SYSTEM_H
-#define __MACH_SYSTEM_H
-
-#include <asm/proc-fns.h>
-
-static inline void arch_idle(void)
-{
-	/*
-	 * This should do all the clock switching
-	 * and wait for interrupt tricks
-	 */
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c
index e159d69..79d001f 100644
--- a/arch/arm/mach-cns3xxx/pcie.c
+++ b/arch/arm/mach-cns3xxx/pcie.c
@@ -155,8 +155,8 @@
 	BUG_ON(request_resource(&iomem_resource, res_io) ||
 	       request_resource(&iomem_resource, res_mem));
 
-	pci_add_resource(&sys->resources, res_io);
-	pci_add_resource(&sys->resources, res_mem);
+	pci_add_resource_offset(&sys->resources, res_io, sys->io_offset);
+	pci_add_resource_offset(&sys->resources, res_mem, sys->mem_offset);
 
 	return 1;
 }
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index d508890..a70de24 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -36,6 +36,7 @@
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/system_info.h>
 
 #include <mach/cp_intc.h>
 #include <mach/da8xx.h>
diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c
index 275341f..82ed753 100644
--- a/arch/arm/mach-davinci/board-dm355-evm.c
+++ b/arch/arm/mach-davinci/board-dm355-evm.c
@@ -26,13 +26,14 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
-#include <mach/dm355.h>
 #include <mach/i2c.h>
 #include <mach/serial.h>
 #include <mach/nand.h>
 #include <mach/mmc.h>
 #include <mach/usb.h>
 
+#include "davinci.h"
+
 /* NOTE:  this is geared for the standard config, with a socketed
  * 2 GByte Micron NAND (MT29F16G08FAA) using 128KB sectors.  If you
  * swap chips, maybe with a different block size, partitioning may
diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c
index e99db28..d74a8b3 100644
--- a/arch/arm/mach-davinci/board-dm355-leopard.c
+++ b/arch/arm/mach-davinci/board-dm355-leopard.c
@@ -23,13 +23,14 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
-#include <mach/dm355.h>
 #include <mach/i2c.h>
 #include <mach/serial.h>
 #include <mach/nand.h>
 #include <mach/mmc.h>
 #include <mach/usb.h>
 
+#include "davinci.h"
+
 /* NOTE:  this is geared for the standard config, with a socketed
  * 2 GByte Micron NAND (MT29F16G08FAA) using 128KB sectors.  If you
  * swap chips, maybe with a different block size, partitioning may
diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c
index 849311d..5bce2b8 100644
--- a/arch/arm/mach-davinci/board-dm365-evm.c
+++ b/arch/arm/mach-davinci/board-dm365-evm.c
@@ -32,7 +32,6 @@
 #include <asm/mach/arch.h>
 
 #include <mach/mux.h>
-#include <mach/dm365.h>
 #include <mach/common.h>
 #include <mach/i2c.h>
 #include <mach/serial.h>
@@ -42,6 +41,8 @@
 
 #include <media/tvp514x.h>
 
+#include "davinci.h"
+
 static inline int have_imager(void)
 {
 	/* REVISIT when it's supported, trigger via Kconfig */
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index 1247ecd..3683306 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -30,7 +30,6 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
-#include <mach/dm644x.h>
 #include <mach/common.h>
 #include <mach/i2c.h>
 #include <mach/serial.h>
@@ -40,6 +39,8 @@
 #include <mach/usb.h>
 #include <mach/aemif.h>
 
+#include "davinci.h"
+
 #define DM644X_EVM_PHY_ID		"davinci_mdio-0:01"
 #define LXT971_PHY_ID	(0x001378e2)
 #define LXT971_PHY_MASK	(0xfffffff0)
@@ -189,7 +190,7 @@
 	.num_resources = 0,
 };
 
-static struct tvp514x_platform_data tvp5146_pdata = {
+static struct tvp514x_platform_data dm644xevm_tvp5146_pdata = {
 	.clk_polarity = 0,
 	.hs_polarity = 1,
 	.vs_polarity = 1
@@ -197,7 +198,7 @@
 
 #define TVP514X_STD_ALL	(V4L2_STD_NTSC | V4L2_STD_PAL)
 /* Inputs available at the TVP5146 */
-static struct v4l2_input tvp5146_inputs[] = {
+static struct v4l2_input dm644xevm_tvp5146_inputs[] = {
 	{
 		.index = 0,
 		.name = "Composite",
@@ -217,7 +218,7 @@
  * ouput that goes to vpfe. There is a one to one correspondence
  * with tvp5146_inputs
  */
-static struct vpfe_route tvp5146_routes[] = {
+static struct vpfe_route dm644xevm_tvp5146_routes[] = {
 	{
 		.input = INPUT_CVBS_VI2B,
 		.output = OUTPUT_10BIT_422_EMBEDDED_SYNC,
@@ -228,13 +229,13 @@
 	},
 };
 
-static struct vpfe_subdev_info vpfe_sub_devs[] = {
+static struct vpfe_subdev_info dm644xevm_vpfe_sub_devs[] = {
 	{
 		.name = "tvp5146",
 		.grp_id = 0,
-		.num_inputs = ARRAY_SIZE(tvp5146_inputs),
-		.inputs = tvp5146_inputs,
-		.routes = tvp5146_routes,
+		.num_inputs = ARRAY_SIZE(dm644xevm_tvp5146_inputs),
+		.inputs = dm644xevm_tvp5146_inputs,
+		.routes = dm644xevm_tvp5146_routes,
 		.can_route = 1,
 		.ccdc_if_params = {
 			.if_type = VPFE_BT656,
@@ -243,15 +244,15 @@
 		},
 		.board_info = {
 			I2C_BOARD_INFO("tvp5146", 0x5d),
-			.platform_data = &tvp5146_pdata,
+			.platform_data = &dm644xevm_tvp5146_pdata,
 		},
 	},
 };
 
-static struct vpfe_config vpfe_cfg = {
-	.num_subdevs = ARRAY_SIZE(vpfe_sub_devs),
+static struct vpfe_config dm644xevm_capture_cfg = {
+	.num_subdevs = ARRAY_SIZE(dm644xevm_vpfe_sub_devs),
 	.i2c_adapter_id = 1,
-	.sub_devs = vpfe_sub_devs,
+	.sub_devs = dm644xevm_vpfe_sub_devs,
 	.card_name = "DM6446 EVM",
 	.ccdc = "DM6446 CCDC",
 };
@@ -612,6 +613,113 @@
 	i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
 }
 
+#define VENC_STD_ALL	(V4L2_STD_NTSC | V4L2_STD_PAL)
+
+/* venc standard timings */
+static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = {
+	{
+		.name		= "ntsc",
+		.timings_type	= VPBE_ENC_STD,
+		.timings	= {V4L2_STD_525_60},
+		.interlaced	= 1,
+		.xres		= 720,
+		.yres		= 480,
+		.aspect		= {11, 10},
+		.fps		= {30000, 1001},
+		.left_margin	= 0x79,
+		.upper_margin	= 0x10,
+	},
+	{
+		.name		= "pal",
+		.timings_type	= VPBE_ENC_STD,
+		.timings	= {V4L2_STD_625_50},
+		.interlaced	= 1,
+		.xres		= 720,
+		.yres		= 576,
+		.aspect		= {54, 59},
+		.fps		= {25, 1},
+		.left_margin	= 0x7e,
+		.upper_margin	= 0x16,
+	},
+};
+
+/* venc dv preset timings */
+static struct vpbe_enc_mode_info dm644xevm_enc_preset_timing[] = {
+	{
+		.name		= "480p59_94",
+		.timings_type	= VPBE_ENC_DV_PRESET,
+		.timings	= {V4L2_DV_480P59_94},
+		.interlaced	= 0,
+		.xres		= 720,
+		.yres		= 480,
+		.aspect		= {1, 1},
+		.fps		= {5994, 100},
+		.left_margin	= 0x80,
+		.upper_margin	= 0x20,
+	},
+	{
+		.name		= "576p50",
+		.timings_type	= VPBE_ENC_DV_PRESET,
+		.timings	= {V4L2_DV_576P50},
+		.interlaced	= 0,
+		.xres		= 720,
+		.yres		= 576,
+		.aspect		= {1, 1},
+		.fps		= {50, 1},
+		.left_margin	= 0x7e,
+		.upper_margin	= 0x30,
+	},
+};
+
+/*
+ * The outputs available from VPBE + encoders. Keep the order same
+ * as that of encoders. First those from venc followed by that from
+ * encoders. Index in the output refers to index on a particular encoder.
+ * Driver uses this index to pass it to encoder when it supports more
+ * than one output. Userspace applications use index of the array to
+ * set an output.
+ */
+static struct vpbe_output dm644xevm_vpbe_outputs[] = {
+	{
+		.output		= {
+			.index		= 0,
+			.name		= "Composite",
+			.type		= V4L2_OUTPUT_TYPE_ANALOG,
+			.std		= VENC_STD_ALL,
+			.capabilities	= V4L2_OUT_CAP_STD,
+		},
+		.subdev_name	= VPBE_VENC_SUBDEV_NAME,
+		.default_mode	= "ntsc",
+		.num_modes	= ARRAY_SIZE(dm644xevm_enc_std_timing),
+		.modes		= dm644xevm_enc_std_timing,
+	},
+	{
+		.output		= {
+			.index		= 1,
+			.name		= "Component",
+			.type		= V4L2_OUTPUT_TYPE_ANALOG,
+			.capabilities	= V4L2_OUT_CAP_PRESETS,
+		},
+		.subdev_name	= VPBE_VENC_SUBDEV_NAME,
+		.default_mode	= "480p59_94",
+		.num_modes	= ARRAY_SIZE(dm644xevm_enc_preset_timing),
+		.modes		= dm644xevm_enc_preset_timing,
+	},
+};
+
+static struct vpbe_config dm644xevm_display_cfg = {
+	.module_name	= "dm644x-vpbe-display",
+	.i2c_adapter_id	= 1,
+	.osd		= {
+		.module_name	= VPBE_OSD_SUBDEV_NAME,
+	},
+	.venc		= {
+		.module_name	= VPBE_VENC_SUBDEV_NAME,
+	},
+	.num_outputs	= ARRAY_SIZE(dm644xevm_vpbe_outputs),
+	.outputs	= dm644xevm_vpbe_outputs,
+};
+
 static struct platform_device *davinci_evm_devices[] __initdata = {
 	&davinci_fb_device,
 	&rtc_dev,
@@ -624,8 +732,6 @@
 static void __init
 davinci_evm_map_io(void)
 {
-	/* setup input configuration for VPFE input devices */
-	dm644x_set_vpfe_config(&vpfe_cfg);
 	dm644x_init();
 }
 
@@ -697,6 +803,7 @@
 	evm_init_i2c();
 
 	davinci_setup_mmc(0, &dm6446evm_mmc_config);
+	dm644x_init_video(&dm644xevm_capture_cfg, &dm644xevm_display_cfg);
 
 	davinci_serial_init(&uart_config);
 	dm644x_init_asp(&dm644x_evm_snd_data);
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
index 872ac69..d72ab94 100644
--- a/arch/arm/mach-davinci/board-dm646x-evm.c
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -36,7 +36,6 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
-#include <mach/dm646x.h>
 #include <mach/common.h>
 #include <mach/serial.h>
 #include <mach/i2c.h>
@@ -45,6 +44,7 @@
 #include <mach/cdce949.h>
 #include <mach/aemif.h>
 
+#include "davinci.h"
 #include "clock.h"
 
 #define NAND_BLOCK_SIZE		SZ_128K
@@ -410,8 +410,6 @@
 	.bus_delay      = 0 /* usec */,
 };
 
-#define VIDCLKCTL_OFFSET	(DAVINCI_SYSTEM_MODULE_BASE + 0x38)
-#define VSCLKDIS_OFFSET		(DAVINCI_SYSTEM_MODULE_BASE + 0x6c)
 #define VCH2CLK_MASK		(BIT_MASK(10) | BIT_MASK(9) | BIT_MASK(8))
 #define VCH2CLK_SYSCLK8		(BIT(9))
 #define VCH2CLK_AUXCLK		(BIT(9) | BIT(8))
@@ -429,8 +427,6 @@
 #define TVP5147_CH0		"tvp514x-0"
 #define TVP5147_CH1		"tvp514x-1"
 
-static void __iomem *vpif_vidclkctl_reg;
-static void __iomem *vpif_vsclkdis_reg;
 /* spin lock for updating above registers */
 static spinlock_t vpif_reg_lock;
 
@@ -441,14 +437,14 @@
 	int val = 0;
 	int err = 0;
 
-	if (!vpif_vidclkctl_reg || !vpif_vsclkdis_reg || !cpld_client)
+	if (!cpld_client)
 		return -ENXIO;
 
 	/* disable the clock */
 	spin_lock_irqsave(&vpif_reg_lock, flags);
-	value = __raw_readl(vpif_vsclkdis_reg);
+	value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
 	value |= (VIDCH3CLK | VIDCH2CLK);
-	__raw_writel(value, vpif_vsclkdis_reg);
+	__raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
 	spin_unlock_irqrestore(&vpif_reg_lock, flags);
 
 	val = i2c_smbus_read_byte(cpld_client);
@@ -464,7 +460,7 @@
 	if (err)
 		return err;
 
-	value = __raw_readl(vpif_vidclkctl_reg);
+	value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VIDCLKCTL));
 	value &= ~(VCH2CLK_MASK);
 	value &= ~(VCH3CLK_MASK);
 
@@ -473,13 +469,13 @@
 	else
 		value |= (VCH2CLK_AUXCLK | VCH3CLK_AUXCLK);
 
-	__raw_writel(value, vpif_vidclkctl_reg);
+	__raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VIDCLKCTL));
 
 	spin_lock_irqsave(&vpif_reg_lock, flags);
-	value = __raw_readl(vpif_vsclkdis_reg);
+	value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
 	/* enable the clock */
 	value &= ~(VIDCH3CLK | VIDCH2CLK);
-	__raw_writel(value, vpif_vsclkdis_reg);
+	__raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
 	spin_unlock_irqrestore(&vpif_reg_lock, flags);
 
 	return 0;
@@ -564,7 +560,7 @@
 	int val;
 	u32 value;
 
-	if (!vpif_vidclkctl_reg || !cpld_client)
+	if (!cpld_client)
 		return -ENXIO;
 
 	val = i2c_smbus_read_byte(cpld_client);
@@ -572,7 +568,7 @@
 		return val;
 
 	spin_lock_irqsave(&vpif_reg_lock, flags);
-	value = __raw_readl(vpif_vidclkctl_reg);
+	value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VIDCLKCTL));
 	if (mux_mode) {
 		val &= VPIF_INPUT_TWO_CHANNEL;
 		value |= VIDCH1CLK;
@@ -580,7 +576,7 @@
 		val |= VPIF_INPUT_ONE_CHANNEL;
 		value &= ~VIDCH1CLK;
 	}
-	__raw_writel(value, vpif_vidclkctl_reg);
+	__raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VIDCLKCTL));
 	spin_unlock_irqrestore(&vpif_reg_lock, flags);
 
 	err = i2c_smbus_write_byte(cpld_client, val);
@@ -674,12 +670,6 @@
 
 static void __init evm_init_video(void)
 {
-	vpif_vidclkctl_reg = ioremap(VIDCLKCTL_OFFSET, 4);
-	vpif_vsclkdis_reg = ioremap(VSCLKDIS_OFFSET, 4);
-	if (!vpif_vidclkctl_reg || !vpif_vsclkdis_reg) {
-		pr_err("Can't map VPIF VIDCLKCTL or VSCLKDIS registers\n");
-		return;
-	}
 	spin_lock_init(&vpif_reg_lock);
 
 	dm646x_setup_vpif(&dm646x_vpif_display_config,
diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c
index 8d34f51..a772bb4 100644
--- a/arch/arm/mach-davinci/board-neuros-osd2.c
+++ b/arch/arm/mach-davinci/board-neuros-osd2.c
@@ -30,7 +30,6 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
-#include <mach/dm644x.h>
 #include <mach/common.h>
 #include <mach/i2c.h>
 #include <mach/serial.h>
@@ -39,6 +38,8 @@
 #include <mach/mmc.h>
 #include <mach/usb.h>
 
+#include "davinci.h"
+
 #define NEUROS_OSD2_PHY_ID		"davinci_mdio-0:01"
 #define LXT971_PHY_ID			0x001378e2
 #define LXT971_PHY_MASK			0xfffffff0
diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c
index 31da3c5..76e67509 100644
--- a/arch/arm/mach-davinci/board-sffsdr.c
+++ b/arch/arm/mach-davinci/board-sffsdr.c
@@ -35,13 +35,14 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
-#include <mach/dm644x.h>
 #include <mach/common.h>
 #include <mach/i2c.h>
 #include <mach/serial.h>
 #include <mach/mux.h>
 #include <mach/usb.h>
 
+#include "davinci.h"
+
 #define SFFSDR_PHY_ID		"davinci_mdio-0:01"
 static struct mtd_partition davinci_sffsdr_nandflash_partition[] = {
 	/* U-Boot Environment: Block 0
diff --git a/arch/arm/mach-davinci/cpufreq.c b/arch/arm/mach-davinci/cpufreq.c
index 5bba707..031048f 100644
--- a/arch/arm/mach-davinci/cpufreq.c
+++ b/arch/arm/mach-davinci/cpufreq.c
@@ -95,7 +95,7 @@
 	if (freqs.old == freqs.new)
 		return ret;
 
-	dev_dbg(&cpufreq.dev, "transition: %u --> %u\n", freqs.old, freqs.new);
+	dev_dbg(cpufreq.dev, "transition: %u --> %u\n", freqs.old, freqs.new);
 
 	ret = cpufreq_frequency_table_target(policy, pdata->freq_table,
 						freqs.new, relation, &idx);
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index a30c7c5..9107691 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -18,6 +18,7 @@
 #include <linux/io.h>
 #include <linux/export.h>
 #include <asm/proc-fns.h>
+#include <asm/cpuidle.h>
 
 #include <mach/cpuidle.h>
 #include <mach/ddr2.h>
@@ -30,12 +31,43 @@
 	u32 flags;
 };
 
+/* Actual code that puts the SoC in different idle states */
+static int davinci_enter_idle(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
+						int index)
+{
+	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+	struct davinci_ops *ops = cpuidle_get_statedata(state_usage);
+
+	if (ops && ops->enter)
+		ops->enter(ops->flags);
+
+	index = cpuidle_wrap_enter(dev,	drv, index,
+				arm_cpuidle_simple_enter);
+
+	if (ops && ops->exit)
+		ops->exit(ops->flags);
+
+	return index;
+}
+
 /* fields in davinci_ops.flags */
 #define DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN	BIT(0)
 
 static struct cpuidle_driver davinci_idle_driver = {
-	.name	= "cpuidle-davinci",
-	.owner	= THIS_MODULE,
+	.name			= "cpuidle-davinci",
+	.owner			= THIS_MODULE,
+	.en_core_tk_irqen	= 1,
+	.states[0]		= ARM_CPUIDLE_WFI_STATE,
+	.states[1]		= {
+		.enter			= davinci_enter_idle,
+		.exit_latency		= 10,
+		.target_residency	= 100000,
+		.flags			= CPUIDLE_FLAG_TIME_VALID,
+		.name			= "DDR SR",
+		.desc			= "WFI and DDR Self Refresh",
+	},
+	.state_count = DAVINCI_CPUIDLE_MAX_STATES,
 };
 
 static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device);
@@ -77,41 +109,10 @@
 	},
 };
 
-/* Actual code that puts the SoC in different idle states */
-static int davinci_enter_idle(struct cpuidle_device *dev,
-				struct cpuidle_driver *drv,
-						int index)
-{
-	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
-	struct davinci_ops *ops = cpuidle_get_statedata(state_usage);
-	struct timeval before, after;
-	int idle_time;
-
-	local_irq_disable();
-	do_gettimeofday(&before);
-
-	if (ops && ops->enter)
-		ops->enter(ops->flags);
-	/* Wait for interrupt state */
-	cpu_do_idle();
-	if (ops && ops->exit)
-		ops->exit(ops->flags);
-
-	do_gettimeofday(&after);
-	local_irq_enable();
-	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
-			(after.tv_usec - before.tv_usec);
-
-	dev->last_residency = idle_time;
-
-	return index;
-}
-
 static int __init davinci_cpuidle_probe(struct platform_device *pdev)
 {
 	int ret;
 	struct cpuidle_device *device;
-	struct cpuidle_driver *driver = &davinci_idle_driver;
 	struct davinci_cpuidle_config *pdata = pdev->dev.platform_data;
 
 	device = &per_cpu(davinci_cpuidle_device, smp_processor_id());
@@ -123,27 +124,11 @@
 
 	ddr2_reg_base = pdata->ddr2_ctlr_base;
 
-	/* Wait for interrupt state */
-	driver->states[0].enter = davinci_enter_idle;
-	driver->states[0].exit_latency = 1;
-	driver->states[0].target_residency = 10000;
-	driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
-	strcpy(driver->states[0].name, "WFI");
-	strcpy(driver->states[0].desc, "Wait for interrupt");
-
-	/* Wait for interrupt and DDR self refresh state */
-	driver->states[1].enter = davinci_enter_idle;
-	driver->states[1].exit_latency = 10;
-	driver->states[1].target_residency = 10000;
-	driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
-	strcpy(driver->states[1].name, "DDR SR");
-	strcpy(driver->states[1].desc, "WFI and DDR Self Refresh");
 	if (pdata->ddr2_pdown)
 		davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN;
 	cpuidle_set_statedata(&device->states_usage[1], &davinci_states[1]);
 
 	device->state_count = DAVINCI_CPUIDLE_MAX_STATES;
-	driver->state_count = DAVINCI_CPUIDLE_MAX_STATES;
 
 	ret = cpuidle_register_driver(&davinci_idle_driver);
 	if (ret) {
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 992c4c4..b44dc84 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -1026,7 +1026,7 @@
 }
 #endif
 
-int da850_register_pm(struct platform_device *pdev)
+int __init da850_register_pm(struct platform_device *pdev)
 {
 	int ret;
 	struct davinci_pm_config *pdata = pdev->dev.platform_data;
diff --git a/arch/arm/mach-davinci/davinci.h b/arch/arm/mach-davinci/davinci.h
new file mode 100644
index 0000000..3e519da
--- /dev/null
+++ b/arch/arm/mach-davinci/davinci.h
@@ -0,0 +1,102 @@
+/*
+ * This file contains the processor specific definitions
+ * of the TI DM644x, DM355, DM365, and DM646x.
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated
+ * Copyright (c) 2007 Deep Root Systems, LLC
+ *
+ * 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.
+ */
+#ifndef __DAVINCI_H
+#define __DAVINCI_H
+
+#include <linux/clk.h>
+#include <linux/videodev2.h>
+#include <linux/davinci_emac.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+#include <mach/asp.h>
+#include <mach/keyscan.h>
+#include <mach/hardware.h>
+
+#include <media/davinci/vpfe_capture.h>
+#include <media/davinci/vpif_types.h>
+#include <media/davinci/vpss.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe_venc.h>
+#include <media/davinci/vpbe.h>
+#include <media/davinci/vpbe_osd.h>
+
+#define DAVINCI_SYSTEM_MODULE_BASE	0x01c40000
+#define SYSMOD_VIDCLKCTL		0x38
+#define SYSMOD_VPSS_CLKCTL		0x44
+#define SYSMOD_VDD3P3VPWDN		0x48
+#define SYSMOD_VSCLKDIS			0x6c
+#define SYSMOD_PUPDCTL1			0x7c
+
+extern void __iomem *davinci_sysmod_base;
+#define DAVINCI_SYSMOD_VIRT(x)	(davinci_sysmod_base + (x))
+void davinci_map_sysmod(void);
+
+/* DM355 base addresses */
+#define DM355_ASYNC_EMIF_CONTROL_BASE	0x01e10000
+#define DM355_ASYNC_EMIF_DATA_CE0_BASE	0x02000000
+
+#define ASP1_TX_EVT_EN	1
+#define ASP1_RX_EVT_EN	2
+
+/* DM365 base addresses */
+#define DM365_ASYNC_EMIF_CONTROL_BASE	0x01d10000
+#define DM365_ASYNC_EMIF_DATA_CE0_BASE	0x02000000
+#define DM365_ASYNC_EMIF_DATA_CE1_BASE	0x04000000
+
+/* DM644x base addresses */
+#define DM644X_ASYNC_EMIF_CONTROL_BASE	0x01e00000
+#define DM644X_ASYNC_EMIF_DATA_CE0_BASE 0x02000000
+#define DM644X_ASYNC_EMIF_DATA_CE1_BASE 0x04000000
+#define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000
+#define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000
+
+/* DM646x base addresses */
+#define DM646X_ASYNC_EMIF_CONTROL_BASE	0x20008000
+#define DM646X_ASYNC_EMIF_CS2_SPACE_BASE 0x42000000
+
+/* DM355 function declarations */
+void __init dm355_init(void);
+void dm355_init_spi0(unsigned chipselect_mask,
+		struct spi_board_info *info, unsigned len);
+void __init dm355_init_asp1(u32 evt_enable, struct snd_platform_data *pdata);
+void dm355_set_vpfe_config(struct vpfe_config *cfg);
+
+/* DM365 function declarations */
+void __init dm365_init(void);
+void __init dm365_init_asp(struct snd_platform_data *pdata);
+void __init dm365_init_vc(struct snd_platform_data *pdata);
+void __init dm365_init_ks(struct davinci_ks_platform_data *pdata);
+void __init dm365_init_rtc(void);
+void dm365_init_spi0(unsigned chipselect_mask,
+			struct spi_board_info *info, unsigned len);
+void dm365_set_vpfe_config(struct vpfe_config *cfg);
+
+/* DM644x function declarations */
+void __init dm644x_init(void);
+void __init dm644x_init_asp(struct snd_platform_data *pdata);
+int __init dm644x_init_video(struct vpfe_config *, struct vpbe_config *);
+
+/* DM646x function declarations */
+void __init dm646x_init(void);
+void __init dm646x_init_mcasp0(struct snd_platform_data *pdata);
+void __init dm646x_init_mcasp1(struct snd_platform_data *pdata);
+int __init dm646x_init_edma(struct edma_rsv_info *rsv);
+void dm646x_video_init(void);
+void dm646x_setup_vpif(struct vpif_display_config *,
+		       struct vpif_capture_config *);
+#endif /*__DAVINCI_H */
diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c
index 50c0156..d2f96662 100644
--- a/arch/arm/mach-davinci/devices.c
+++ b/arch/arm/mach-davinci/devices.c
@@ -23,6 +23,7 @@
 #include <mach/mmc.h>
 #include <mach/time.h>
 
+#include "davinci.h"
 #include "clock.h"
 
 #define DAVINCI_I2C_BASE	     0x01C21000
@@ -33,8 +34,19 @@
 #define DM365_MMCSD0_BASE	     0x01D11000
 #define DM365_MMCSD1_BASE	     0x01D00000
 
-/* System control register offsets */
-#define DM64XX_VDD3P3V_PWDN	0x48
+void __iomem  *davinci_sysmod_base;
+
+void davinci_map_sysmod(void)
+{
+	davinci_sysmod_base = ioremap_nocache(DAVINCI_SYSTEM_MODULE_BASE,
+					      0x800);
+	/*
+	 * Throw a bug since a lot of board initialization code depends
+	 * on system module availability. ioremap() failing this early
+	 * need careful looking into anyway.
+	 */
+	BUG_ON(!davinci_sysmod_base);
+}
 
 static struct resource i2c_resources[] = {
 	{
@@ -212,12 +224,12 @@
 			davinci_cfg_reg(DM355_SD1_DATA2);
 			davinci_cfg_reg(DM355_SD1_DATA3);
 		} else if (cpu_is_davinci_dm365()) {
-			void __iomem *pupdctl1 =
-				IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE + 0x7c);
-
 			/* Configure pull down control */
-			__raw_writel((__raw_readl(pupdctl1) & ~0xfc0),
-					pupdctl1);
+			unsigned v;
+
+			v = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_PUPDCTL1));
+			__raw_writel(v & ~0xfc0,
+					DAVINCI_SYSMOD_VIRT(SYSMOD_PUPDCTL1));
 
 			mmcsd1_resources[0].start = DM365_MMCSD1_BASE;
 			mmcsd1_resources[0].end = DM365_MMCSD1_BASE +
@@ -246,11 +258,9 @@
 			mmcsd0_resources[2].start = IRQ_DM365_SDIOINT0;
 		} else if (cpu_is_davinci_dm644x()) {
 			/* REVISIT: should this be in board-init code? */
-			void __iomem *base =
-				IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE);
-
 			/* Power-on 3.3V IO cells */
-			__raw_writel(0, base + DM64XX_VDD3P3V_PWDN);
+			__raw_writel(0,
+				DAVINCI_SYSMOD_VIRT(SYSMOD_VDD3P3VPWDN));
 			/*Set up the pull regiter for MMC */
 			davinci_cfg_reg(DM644X_MSTK);
 		}
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index 19667cf..fd3d09a 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -18,7 +18,6 @@
 
 #include <asm/mach/map.h>
 
-#include <mach/dm355.h>
 #include <mach/cputype.h>
 #include <mach/edma.h>
 #include <mach/psc.h>
@@ -31,6 +30,7 @@
 #include <mach/spi.h>
 #include <mach/gpio-davinci.h>
 
+#include "davinci.h"
 #include "clock.h"
 #include "mux.h"
 
@@ -871,6 +871,7 @@
 void __init dm355_init(void)
 {
 	davinci_common_init(&davinci_soc_info_dm355);
+	davinci_map_sysmod();
 }
 
 static int __init dm355_init_devices(void)
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index f15b435..1a2e953 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -21,7 +21,6 @@
 
 #include <asm/mach/map.h>
 
-#include <mach/dm365.h>
 #include <mach/cputype.h>
 #include <mach/edma.h>
 #include <mach/psc.h>
@@ -35,11 +34,28 @@
 #include <mach/spi.h>
 #include <mach/gpio-davinci.h>
 
+#include "davinci.h"
 #include "clock.h"
 #include "mux.h"
 
 #define DM365_REF_FREQ		24000000	/* 24 MHz on the DM365 EVM */
 
+/* Base of key scan register bank */
+#define DM365_KEYSCAN_BASE		0x01c69400
+
+#define DM365_RTC_BASE			0x01c69000
+
+#define DAVINCI_DM365_VC_BASE		0x01d0c000
+#define DAVINCI_DMA_VC_TX		2
+#define DAVINCI_DMA_VC_RX		3
+
+#define DM365_EMAC_BASE			0x01d07000
+#define DM365_EMAC_MDIO_BASE		(DM365_EMAC_BASE + 0x4000)
+#define DM365_EMAC_CNTRL_OFFSET		0x0000
+#define DM365_EMAC_CNTRL_MOD_OFFSET	0x3000
+#define DM365_EMAC_CNTRL_RAM_OFFSET	0x1000
+#define DM365_EMAC_CNTRL_RAM_SIZE	0x2000
+
 static struct pll_data pll1_data = {
 	.num		= 1,
 	.phys_base	= DAVINCI_PLL1_BASE,
@@ -1122,6 +1138,7 @@
 void __init dm365_init(void)
 {
 	davinci_common_init(&davinci_soc_info_dm365);
+	davinci_map_sysmod();
 }
 
 static struct resource dm365_vpss_resources[] = {
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index 43a48ee..c8b8666 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -15,7 +15,6 @@
 
 #include <asm/mach/map.h>
 
-#include <mach/dm644x.h>
 #include <mach/cputype.h>
 #include <mach/edma.h>
 #include <mach/irqs.h>
@@ -27,6 +26,7 @@
 #include <mach/asp.h>
 #include <mach/gpio-davinci.h>
 
+#include "davinci.h"
 #include "clock.h"
 #include "mux.h"
 
@@ -35,6 +35,13 @@
  */
 #define DM644X_REF_FREQ		27000000
 
+#define DM644X_EMAC_BASE		0x01c80000
+#define DM644X_EMAC_MDIO_BASE		(DM644X_EMAC_BASE + 0x4000)
+#define DM644X_EMAC_CNTRL_OFFSET	0x0000
+#define DM644X_EMAC_CNTRL_MOD_OFFSET	0x1000
+#define DM644X_EMAC_CNTRL_RAM_OFFSET	0x2000
+#define DM644X_EMAC_CNTRL_RAM_SIZE	0x2000
+
 static struct pll_data pll1_data = {
 	.num       = 1,
 	.phys_base = DAVINCI_PLL1_BASE,
@@ -587,13 +594,15 @@
 	.resource	= dm644x_asp_resources,
 };
 
+#define DM644X_VPSS_BASE	0x01c73400
+
 static struct resource dm644x_vpss_resources[] = {
 	{
 		/* VPSS Base address */
 		.name		= "vpss",
-		.start          = 0x01c73400,
-		.end            = 0x01c73400 + 0xff,
-		.flags          = IORESOURCE_MEM,
+		.start		= DM644X_VPSS_BASE,
+		.end		= DM644X_VPSS_BASE + 0xff,
+		.flags		= IORESOURCE_MEM,
 	},
 };
 
@@ -605,7 +614,7 @@
 	.resource		= dm644x_vpss_resources,
 };
 
-static struct resource vpfe_resources[] = {
+static struct resource dm644x_vpfe_resources[] = {
 	{
 		.start          = IRQ_VDINT0,
 		.end            = IRQ_VDINT0,
@@ -618,7 +627,7 @@
 	},
 };
 
-static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32);
+static u64 dm644x_video_dma_mask = DMA_BIT_MASK(32);
 static struct resource dm644x_ccdc_resource[] = {
 	/* CCDC Base address */
 	{
@@ -634,27 +643,149 @@
 	.num_resources  = ARRAY_SIZE(dm644x_ccdc_resource),
 	.resource       = dm644x_ccdc_resource,
 	.dev = {
-		.dma_mask               = &vpfe_capture_dma_mask,
+		.dma_mask               = &dm644x_video_dma_mask,
 		.coherent_dma_mask      = DMA_BIT_MASK(32),
 	},
 };
 
-static struct platform_device vpfe_capture_dev = {
+static struct platform_device dm644x_vpfe_dev = {
 	.name		= CAPTURE_DRV_NAME,
 	.id		= -1,
-	.num_resources	= ARRAY_SIZE(vpfe_resources),
-	.resource	= vpfe_resources,
+	.num_resources	= ARRAY_SIZE(dm644x_vpfe_resources),
+	.resource	= dm644x_vpfe_resources,
 	.dev = {
-		.dma_mask		= &vpfe_capture_dma_mask,
+		.dma_mask		= &dm644x_video_dma_mask,
 		.coherent_dma_mask	= DMA_BIT_MASK(32),
 	},
 };
 
-void dm644x_set_vpfe_config(struct vpfe_config *cfg)
+#define DM644X_OSD_BASE		0x01c72600
+
+static struct resource dm644x_osd_resources[] = {
+	{
+		.start	= DM644X_OSD_BASE,
+		.end	= DM644X_OSD_BASE + 0x1ff,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct osd_platform_data dm644x_osd_data = {
+	.vpbe_type     = VPBE_VERSION_1,
+};
+
+static struct platform_device dm644x_osd_dev = {
+	.name		= VPBE_OSD_SUBDEV_NAME,
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(dm644x_osd_resources),
+	.resource	= dm644x_osd_resources,
+	.dev		= {
+		.dma_mask		= &dm644x_video_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+		.platform_data		= &dm644x_osd_data,
+	},
+};
+
+#define DM644X_VENC_BASE		0x01c72400
+
+static struct resource dm644x_venc_resources[] = {
+	{
+		.start	= DM644X_VENC_BASE,
+		.end	= DM644X_VENC_BASE + 0x17f,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+#define DM644X_VPSS_MUXSEL_PLL2_MODE          BIT(0)
+#define DM644X_VPSS_MUXSEL_VPBECLK_MODE       BIT(1)
+#define DM644X_VPSS_VENCLKEN                  BIT(3)
+#define DM644X_VPSS_DACCLKEN                  BIT(4)
+
+static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type,
+				   unsigned int mode)
 {
-	vpfe_capture_dev.dev.platform_data = cfg;
+	int ret = 0;
+	u32 v = DM644X_VPSS_VENCLKEN;
+
+	switch (type) {
+	case VPBE_ENC_STD:
+		v |= DM644X_VPSS_DACCLKEN;
+		writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL));
+		break;
+	case VPBE_ENC_DV_PRESET:
+		switch (mode) {
+		case V4L2_DV_480P59_94:
+		case V4L2_DV_576P50:
+			v |= DM644X_VPSS_MUXSEL_PLL2_MODE |
+			     DM644X_VPSS_DACCLKEN;
+			writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL));
+			break;
+		case V4L2_DV_720P60:
+		case V4L2_DV_1080I60:
+		case V4L2_DV_1080P30:
+			/*
+			 * For HD, use external clock source since
+			 * HD requires higher clock rate
+			 */
+			v |= DM644X_VPSS_MUXSEL_VPBECLK_MODE;
+			writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL));
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		break;
+	default:
+		ret  = -EINVAL;
+	}
+
+	return ret;
 }
 
+static struct resource dm644x_v4l2_disp_resources[] = {
+	{
+		.start	= IRQ_VENCINT,
+		.end	= IRQ_VENCINT,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device dm644x_vpbe_display = {
+	.name		= "vpbe-v4l2",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(dm644x_v4l2_disp_resources),
+	.resource	= dm644x_v4l2_disp_resources,
+	.dev		= {
+		.dma_mask		= &dm644x_video_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
+static struct venc_platform_data dm644x_venc_pdata = {
+	.venc_type	= VPBE_VERSION_1,
+	.setup_clock	= dm644x_venc_setup_clock,
+};
+
+static struct platform_device dm644x_venc_dev = {
+	.name		= VPBE_VENC_SUBDEV_NAME,
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(dm644x_venc_resources),
+	.resource	= dm644x_venc_resources,
+	.dev		= {
+		.dma_mask		= &dm644x_video_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+		.platform_data		= &dm644x_venc_pdata,
+	},
+};
+
+static struct platform_device dm644x_vpbe_dev = {
+	.name		= "vpbe_controller",
+	.id		= -1,
+	.dev		= {
+		.dma_mask		= &dm644x_video_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
 /*----------------------------------------------------------------------*/
 
 static struct map_desc dm644x_io_desc[] = {
@@ -779,6 +910,35 @@
 void __init dm644x_init(void)
 {
 	davinci_common_init(&davinci_soc_info_dm644x);
+	davinci_map_sysmod();
+}
+
+int __init dm644x_init_video(struct vpfe_config *vpfe_cfg,
+				struct vpbe_config *vpbe_cfg)
+{
+	if (vpfe_cfg || vpbe_cfg)
+		platform_device_register(&dm644x_vpss_device);
+
+	if (vpfe_cfg) {
+		dm644x_vpfe_dev.dev.platform_data = vpfe_cfg;
+		platform_device_register(&dm644x_ccdc_dev);
+		platform_device_register(&dm644x_vpfe_dev);
+		/* Add ccdc clock aliases */
+		clk_add_alias("master", dm644x_ccdc_dev.name,
+			      "vpss_master", NULL);
+		clk_add_alias("slave", dm644x_ccdc_dev.name,
+			      "vpss_slave", NULL);
+	}
+
+	if (vpbe_cfg) {
+		dm644x_vpbe_dev.dev.platform_data = vpbe_cfg;
+		platform_device_register(&dm644x_osd_dev);
+		platform_device_register(&dm644x_venc_dev);
+		platform_device_register(&dm644x_vpbe_dev);
+		platform_device_register(&dm644x_vpbe_display);
+	}
+
+	return 0;
 }
 
 static int __init dm644x_init_devices(void)
@@ -786,9 +946,6 @@
 	if (!cpu_is_davinci_dm644x())
 		return 0;
 
-	/* Add ccdc clock aliases */
-	clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL);
-	clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL);
 	platform_device_register(&dm644x_edma_device);
 
 	platform_device_register(&dm644x_mdio_device);
@@ -796,10 +953,6 @@
 	clk_add_alias(NULL, dev_name(&dm644x_mdio_device.dev),
 		      NULL, &dm644x_emac_device.dev);
 
-	platform_device_register(&dm644x_vpss_device);
-	platform_device_register(&dm644x_ccdc_dev);
-	platform_device_register(&vpfe_capture_dev);
-
 	return 0;
 }
 postcore_initcall(dm644x_init_devices);
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
index 00f7743..9eb87c1 100644
--- a/arch/arm/mach-davinci/dm646x.c
+++ b/arch/arm/mach-davinci/dm646x.c
@@ -16,7 +16,6 @@
 
 #include <asm/mach/map.h>
 
-#include <mach/dm646x.h>
 #include <mach/cputype.h>
 #include <mach/edma.h>
 #include <mach/irqs.h>
@@ -28,12 +27,11 @@
 #include <mach/asp.h>
 #include <mach/gpio-davinci.h>
 
+#include "davinci.h"
 #include "clock.h"
 #include "mux.h"
 
 #define DAVINCI_VPIF_BASE       (0x01C12000)
-#define VDD3P3V_PWDN_OFFSET	(0x48)
-#define VSCLKDIS_OFFSET		(0x6C)
 
 #define VDD3P3V_VID_MASK	(BIT_MASK(3) | BIT_MASK(2) | BIT_MASK(1) |\
 					BIT_MASK(0))
@@ -46,6 +44,13 @@
 #define DM646X_REF_FREQ		27000000
 #define DM646X_AUX_FREQ		24000000
 
+#define DM646X_EMAC_BASE		0x01c80000
+#define DM646X_EMAC_MDIO_BASE		(DM646X_EMAC_BASE + 0x4000)
+#define DM646X_EMAC_CNTRL_OFFSET	0x0000
+#define DM646X_EMAC_CNTRL_MOD_OFFSET	0x1000
+#define DM646X_EMAC_CNTRL_RAM_OFFSET	0x2000
+#define DM646X_EMAC_CNTRL_RAM_SIZE	0x2000
+
 static struct pll_data pll1_data = {
 	.num       = 1,
 	.phys_base = DAVINCI_PLL1_BASE,
@@ -873,15 +878,14 @@
 		       struct vpif_capture_config *capture_config)
 {
 	unsigned int value;
-	void __iomem *base = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE);
 
-	value = __raw_readl(base + VSCLKDIS_OFFSET);
+	value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
 	value &= ~VSCLKDIS_MASK;
-	__raw_writel(value, base + VSCLKDIS_OFFSET);
+	__raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
 
-	value = __raw_readl(base + VDD3P3V_PWDN_OFFSET);
+	value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VDD3P3VPWDN));
 	value &= ~VDD3P3V_VID_MASK;
-	__raw_writel(value, base + VDD3P3V_PWDN_OFFSET);
+	__raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VDD3P3VPWDN));
 
 	davinci_cfg_reg(DM646X_STSOMUX_DISABLE);
 	davinci_cfg_reg(DM646X_STSIMUX_DISABLE);
@@ -905,6 +909,7 @@
 void __init dm646x_init(void)
 {
 	davinci_common_init(&davinci_soc_info_dm646x);
+	davinci_map_sysmod();
 }
 
 static int __init dm646x_init_devices(void)
diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c
index da90103..fd33919 100644
--- a/arch/arm/mach-davinci/dma.c
+++ b/arch/arm/mach-davinci/dma.c
@@ -1508,12 +1508,8 @@
 			goto fail;
 		}
 
-		/* Everything lives on transfer controller 1 until otherwise
-		 * specified. This way, long transfers on the low priority queue
-		 * started by the codec engine will not cause audio defects.
-		 */
 		for (i = 0; i < edma_cc[j]->num_channels; i++)
-			map_dmach_queue(j, i, EVENTQ_1);
+			map_dmach_queue(j, i, info[j]->default_queue);
 
 		queue_tc_mapping = info[j]->queue_tc_mapping;
 		queue_priority_mapping = info[j]->queue_priority_mapping;
diff --git a/arch/arm/mach-davinci/include/mach/dm355.h b/arch/arm/mach-davinci/include/mach/dm355.h
deleted file mode 100644
index 36dff4a..0000000
--- a/arch/arm/mach-davinci/include/mach/dm355.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Chip specific defines for DM355 SoC
- *
- * Author: Kevin Hilman, Deep Root Systems, LLC
- *
- * 2007 (c) Deep Root Systems, LLC. 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 __ASM_ARCH_DM355_H
-#define __ASM_ARCH_DM355_H
-
-#include <mach/hardware.h>
-#include <mach/asp.h>
-#include <media/davinci/vpfe_capture.h>
-
-#define DM355_ASYNC_EMIF_CONTROL_BASE	0x01E10000
-#define DM355_ASYNC_EMIF_DATA_CE0_BASE	0x02000000
-
-#define ASP1_TX_EVT_EN	1
-#define ASP1_RX_EVT_EN	2
-
-struct spi_board_info;
-
-void __init dm355_init(void);
-void dm355_init_spi0(unsigned chipselect_mask,
-		struct spi_board_info *info, unsigned len);
-void __init dm355_init_asp1(u32 evt_enable, struct snd_platform_data *pdata);
-void dm355_set_vpfe_config(struct vpfe_config *cfg);
-
-#endif /* __ASM_ARCH_DM355_H */
diff --git a/arch/arm/mach-davinci/include/mach/dm365.h b/arch/arm/mach-davinci/include/mach/dm365.h
index 2563bf4..b9bf3d6 100644
--- a/arch/arm/mach-davinci/include/mach/dm365.h
+++ b/arch/arm/mach-davinci/include/mach/dm365.h
@@ -1,52 +1 @@
-/*
- * Copyright (C) 2009 Texas Instruments Incorporated
- *
- * 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.
- */
-#ifndef __ASM_ARCH_DM365_H
-#define __ASM_ARCH_DM665_H
-
-#include <linux/platform_device.h>
-#include <linux/davinci_emac.h>
-#include <mach/hardware.h>
-#include <mach/asp.h>
-#include <mach/keyscan.h>
-#include <media/davinci/vpfe_capture.h>
-
-#define DM365_EMAC_BASE			(0x01D07000)
-#define DM365_EMAC_MDIO_BASE		(DM365_EMAC_BASE + 0x4000)
-#define DM365_EMAC_CNTRL_OFFSET		(0x0000)
-#define DM365_EMAC_CNTRL_MOD_OFFSET	(0x3000)
-#define DM365_EMAC_CNTRL_RAM_OFFSET	(0x1000)
-#define DM365_EMAC_CNTRL_RAM_SIZE	(0x2000)
-
-/* Base of key scan register bank */
-#define DM365_KEYSCAN_BASE		(0x01C69400)
-
-#define DM365_RTC_BASE			(0x01C69000)
-
-#define DAVINCI_DM365_VC_BASE		(0x01D0C000)
-#define DAVINCI_DMA_VC_TX		2
-#define DAVINCI_DMA_VC_RX		3
-
-#define DM365_ASYNC_EMIF_CONTROL_BASE	0x01D10000
-#define DM365_ASYNC_EMIF_DATA_CE0_BASE	0x02000000
-#define DM365_ASYNC_EMIF_DATA_CE1_BASE	0x04000000
-
-void __init dm365_init(void);
-void __init dm365_init_asp(struct snd_platform_data *pdata);
-void __init dm365_init_vc(struct snd_platform_data *pdata);
-void __init dm365_init_ks(struct davinci_ks_platform_data *pdata);
-void __init dm365_init_rtc(void);
-void dm365_init_spi0(unsigned chipselect_mask,
-			struct spi_board_info *info, unsigned len);
-
-void dm365_set_vpfe_config(struct vpfe_config *cfg);
-#endif /* __ASM_ARCH_DM365_H */
+/* empty, remove once unused */
diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h
deleted file mode 100644
index 5a1b26d4..0000000
--- a/arch/arm/mach-davinci/include/mach/dm644x.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * This file contains the processor specific definitions
- * of the TI DM644x.
- *
- * Copyright (C) 2008 Texas Instruments.
- *
- * 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
- *
- */
-#ifndef __ASM_ARCH_DM644X_H
-#define __ASM_ARCH_DM644X_H
-
-#include <linux/davinci_emac.h>
-#include <mach/hardware.h>
-#include <mach/asp.h>
-#include <media/davinci/vpfe_capture.h>
-
-#define DM644X_EMAC_BASE		(0x01C80000)
-#define DM644X_EMAC_MDIO_BASE		(DM644X_EMAC_BASE + 0x4000)
-#define DM644X_EMAC_CNTRL_OFFSET	(0x0000)
-#define DM644X_EMAC_CNTRL_MOD_OFFSET	(0x1000)
-#define DM644X_EMAC_CNTRL_RAM_OFFSET	(0x2000)
-#define DM644X_EMAC_CNTRL_RAM_SIZE	(0x2000)
-
-#define DM644X_ASYNC_EMIF_CONTROL_BASE	0x01E00000
-#define DM644X_ASYNC_EMIF_DATA_CE0_BASE 0x02000000
-#define DM644X_ASYNC_EMIF_DATA_CE1_BASE 0x04000000
-#define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000
-#define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000
-
-void __init dm644x_init(void);
-void __init dm644x_init_asp(struct snd_platform_data *pdata);
-void dm644x_set_vpfe_config(struct vpfe_config *cfg);
-
-#endif /* __ASM_ARCH_DM644X_H */
diff --git a/arch/arm/mach-davinci/include/mach/dm646x.h b/arch/arm/mach-davinci/include/mach/dm646x.h
index a8ee6c9..b9bf3d6 100644
--- a/arch/arm/mach-davinci/include/mach/dm646x.h
+++ b/arch/arm/mach-davinci/include/mach/dm646x.h
@@ -1,41 +1 @@
-/*
- * Chip specific defines for DM646x SoC
- *
- * Author: Kevin Hilman, Deep Root Systems, LLC
- *
- * 2007 (c) Deep Root Systems, LLC. 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 __ASM_ARCH_DM646X_H
-#define __ASM_ARCH_DM646X_H
-
-#include <mach/hardware.h>
-#include <mach/asp.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <linux/davinci_emac.h>
-#include <media/davinci/vpif_types.h>
-
-#define DM646X_EMAC_BASE		(0x01C80000)
-#define DM646X_EMAC_MDIO_BASE		(DM646X_EMAC_BASE + 0x4000)
-#define DM646X_EMAC_CNTRL_OFFSET	(0x0000)
-#define DM646X_EMAC_CNTRL_MOD_OFFSET	(0x1000)
-#define DM646X_EMAC_CNTRL_RAM_OFFSET	(0x2000)
-#define DM646X_EMAC_CNTRL_RAM_SIZE	(0x2000)
-
-#define DM646X_ASYNC_EMIF_CONTROL_BASE	0x20008000
-#define DM646X_ASYNC_EMIF_CS2_SPACE_BASE 0x42000000
-
-void __init dm646x_init(void);
-void __init dm646x_init_mcasp0(struct snd_platform_data *pdata);
-void __init dm646x_init_mcasp1(struct snd_platform_data *pdata);
-int __init dm646x_init_edma(struct edma_rsv_info *rsv);
-
-void dm646x_video_init(void);
-
-void dm646x_setup_vpif(struct vpif_display_config *,
-		       struct vpif_capture_config *);
-
-#endif /* __ASM_ARCH_DM646X_H */
+/* empty, remove once unused */
diff --git a/arch/arm/mach-davinci/include/mach/edma.h b/arch/arm/mach-davinci/include/mach/edma.h
index 20c77f2..7e84c90 100644
--- a/arch/arm/mach-davinci/include/mach/edma.h
+++ b/arch/arm/mach-davinci/include/mach/edma.h
@@ -250,6 +250,11 @@
 	unsigned	n_slot;
 	unsigned	n_tc;
 	unsigned	n_cc;
+	/*
+	 * Default queue is expected to be a low-priority queue.
+	 * This way, long transfers on the default queue started
+	 * by the codec engine will not cause audio defects.
+	 */
 	enum dma_event_q	default_queue;
 
 	/* Resource reservation for other cores */
diff --git a/arch/arm/mach-davinci/include/mach/entry-macro.S b/arch/arm/mach-davinci/include/mach/entry-macro.S
index e14c0dc..768b3c0 100644
--- a/arch/arm/mach-davinci/include/mach/entry-macro.S
+++ b/arch/arm/mach-davinci/include/mach/entry-macro.S
@@ -8,20 +8,13 @@
  * is licensed "as is" without any warranty of any kind, whether express
  * or implied.
  */
-#include <mach/io.h>
 #include <mach/irqs.h>
 
-		.macro	disable_fiq
-		.endm
-
 		.macro  get_irqnr_preamble, base, tmp
 		ldr \base, =davinci_intc_base
 		ldr \base, [\base]
 		.endm
 
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
-
 		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 #if defined(CONFIG_AINTC) && defined(CONFIG_CP_INTC)
 		ldr \tmp, =davinci_intc_type
diff --git a/arch/arm/mach-davinci/include/mach/hardware.h b/arch/arm/mach-davinci/include/mach/hardware.h
index 414e0b9..2184691 100644
--- a/arch/arm/mach-davinci/include/mach/hardware.h
+++ b/arch/arm/mach-davinci/include/mach/hardware.h
@@ -19,8 +19,6 @@
  * and the chip/board init code should then explicitly include
  * <chipname>.h
  */
-#define DAVINCI_SYSTEM_MODULE_BASE        0x01C40000
-
 /*
  * I/O mapping
  */
@@ -32,10 +30,4 @@
 #define __IO_ADDRESS(x)			((x) + IO_OFFSET)
 #define IO_ADDRESS(pa)			IOMEM(__IO_ADDRESS(pa))
 
-#ifdef __ASSEMBLER__
-#define IOMEM(x)                	x
-#else
-#define IOMEM(x)                	((void __force __iomem *)(x))
-#endif
-
 #endif /* __ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/mach-davinci/include/mach/io.h b/arch/arm/mach-davinci/include/mach/io.h
deleted file mode 100644
index b2267d1..0000000
--- a/arch/arm/mach-davinci/include/mach/io.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * DaVinci IO address definitions
- *
- * Copied from include/asm/arm/arch-omap/io.h
- *
- * 2007 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#ifndef __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-/*
- * We don't actually have real ISA nor PCI buses, but there is so many
- * drivers out there that might just work if we fake them...
- */
-#define __io(a)			__typesafe_io(a)
-#define __mem_pci(a)		(a)
-#define __mem_isa(a)		(a)
-
-#endif /* __ASM_ARCH_IO_H */
diff --git a/arch/arm/mach-davinci/include/mach/system.h b/arch/arm/mach-davinci/include/mach/system.h
deleted file mode 100644
index fcb7a01..0000000
--- a/arch/arm/mach-davinci/include/mach/system.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * DaVinci system defines
- *
- * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
- *
- * 2007 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-#include <mach/common.h>
-
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
-#endif /* __ASM_ARCH_SYSTEM_H */
diff --git a/arch/arm/mach-davinci/include/mach/uncompress.h b/arch/arm/mach-davinci/include/mach/uncompress.h
index 9dc7cf9..da2fb2c 100644
--- a/arch/arm/mach-davinci/include/mach/uncompress.h
+++ b/arch/arm/mach-davinci/include/mach/uncompress.h
@@ -25,6 +25,8 @@
 
 #include <mach/serial.h>
 
+#define IOMEM(x)	((void __force __iomem *)(x))
+
 u32 *uart;
 
 /* PORT_16C550A, in polled non-fifo mode */
diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
index e1969ce..75da315 100644
--- a/arch/arm/mach-davinci/time.c
+++ b/arch/arm/mach-davinci/time.c
@@ -19,11 +19,14 @@
 #include <linux/err.h>
 #include <linux/platform_device.h>
 
-#include <mach/hardware.h>
+#include <asm/sched_clock.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
+
 #include <mach/cputype.h>
+#include <mach/hardware.h>
 #include <mach/time.h>
+
 #include "clock.h"
 
 static struct clock_event_device clockevent_davinci;
@@ -272,19 +275,9 @@
 	return (cycles_t)timer32_read(t);
 }
 
-/*
- * Kernel assumes that sched_clock can be called early but may not have
- * things ready yet.
- */
-static cycle_t read_dummy(struct clocksource *cs)
-{
-	return 0;
-}
-
-
 static struct clocksource clocksource_davinci = {
 	.rating		= 300,
-	.read		= read_dummy,
+	.read		= read_cycles,
 	.mask		= CLOCKSOURCE_MASK(32),
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
@@ -292,12 +285,9 @@
 /*
  * Overwrite weak default sched_clock with something more precise
  */
-unsigned long long notrace sched_clock(void)
+static u32 notrace davinci_read_sched_clock(void)
 {
-	const cycle_t cyc = clocksource_davinci.read(&clocksource_davinci);
-
-	return clocksource_cyc2ns(cyc, clocksource_davinci.mult,
-				clocksource_davinci.shift);
+	return timer32_read(&timers[TID_CLOCKSOURCE]);
 }
 
 /*
@@ -397,12 +387,14 @@
 	davinci_clock_tick_rate = clk_get_rate(timer_clk);
 
 	/* setup clocksource */
-	clocksource_davinci.read = read_cycles;
 	clocksource_davinci.name = id_to_name[clocksource_id];
 	if (clocksource_register_hz(&clocksource_davinci,
 				    davinci_clock_tick_rate))
 		printk(err, clocksource_davinci.name);
 
+	setup_sched_clock(davinci_read_sched_clock, 32,
+			  davinci_clock_tick_rate);
+
 	/* setup clockevent */
 	clockevent_davinci.name = id_to_name[timers[TID_CLOCKEVENT].id];
 	clockevent_davinci.mult = div_sc(davinci_clock_tick_rate, NSEC_PER_SEC,
diff --git a/arch/arm/mach-dove/addr-map.c b/arch/arm/mach-dove/addr-map.c
index 98b8c83..2a06c01 100644
--- a/arch/arm/mach-dove/addr-map.c
+++ b/arch/arm/mach-dove/addr-map.c
@@ -14,6 +14,7 @@
 #include <linux/io.h>
 #include <asm/mach/arch.h>
 #include <asm/setup.h>
+#include <mach/dove.h>
 #include <plat/addr-map.h>
 #include "common.h"
 
diff --git a/arch/arm/mach-dove/include/mach/entry-macro.S b/arch/arm/mach-dove/include/mach/entry-macro.S
index e84c78c..72d622ba 100644
--- a/arch/arm/mach-dove/include/mach/entry-macro.S
+++ b/arch/arm/mach-dove/include/mach/entry-macro.S
@@ -10,12 +10,6 @@
 
 #include <mach/bridge-regs.h>
 
-	.macro  disable_fiq
-	.endm
-
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
-
 	.macro  get_irqnr_preamble, base, tmp
 	ldr	\base, =IRQ_VIRT_BASE
 	.endm
diff --git a/arch/arm/mach-dove/include/mach/io.h b/arch/arm/mach-dove/include/mach/io.h
index eb4936f..29c8b85 100644
--- a/arch/arm/mach-dove/include/mach/io.h
+++ b/arch/arm/mach-dove/include/mach/io.h
@@ -15,6 +15,5 @@
 
 #define __io(a)  	((void __iomem *)(((a) - DOVE_PCIE0_IO_BUS_BASE) + \
 						 DOVE_PCIE0_IO_VIRT_BASE))
-#define __mem_pci(a)	(a)
 
 #endif
diff --git a/arch/arm/mach-dove/include/mach/system.h b/arch/arm/mach-dove/include/mach/system.h
deleted file mode 100644
index 3027954..0000000
--- a/arch/arm/mach-dove/include/mach/system.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/mach-dove/include/mach/system.h
- *
- * 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c
index 52e96d3..48a0320 100644
--- a/arch/arm/mach-dove/pcie.c
+++ b/arch/arm/mach-dove/pcie.c
@@ -69,7 +69,7 @@
 	pp->res[0].flags = IORESOURCE_IO;
 	if (request_resource(&ioport_resource, &pp->res[0]))
 		panic("Request PCIe IO resource failed\n");
-	pci_add_resource(&sys->resources, &pp->res[0]);
+	pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
 
 	/*
 	 * IORESOURCE_MEM
@@ -88,7 +88,7 @@
 	pp->res[1].flags = IORESOURCE_MEM;
 	if (request_resource(&iomem_resource, &pp->res[1]))
 		panic("Request PCIe Memory resource failed\n");
-	pci_add_resource(&sys->resources, &pp->res[1]);
+	pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
 
 	return 1;
 }
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index 294aad0..6f80686 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -22,7 +22,7 @@
 #include <asm/mach-types.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <asm/system.h>
+#include <asm/system_misc.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
@@ -30,10 +30,7 @@
 
 #include <asm/mach/time.h>
 
-#define IRQ_MASK		0xfe000000	/* read */
-#define IRQ_MSET		0xfe000000	/* write */
-#define IRQ_STAT		0xff000000	/* read */
-#define IRQ_MCLR		0xff000000	/* write */
+#include "core.h"
 
 static void ebsa110_mask_irq(struct irq_data *d)
 {
@@ -79,22 +76,22 @@
 	{	/* IRQ_STAT/IRQ_MCLR */
 		.virtual	= IRQ_STAT,
 		.pfn		= __phys_to_pfn(TRICK4_PHYS),
-		.length		= PGDIR_SIZE,
+		.length		= TRICK4_SIZE,
 		.type		= MT_DEVICE
 	}, {	/* IRQ_MASK/IRQ_MSET */
 		.virtual	= IRQ_MASK,
 		.pfn		= __phys_to_pfn(TRICK3_PHYS),
-		.length		= PGDIR_SIZE,
+		.length		= TRICK3_SIZE,
 		.type		= MT_DEVICE
 	}, {	/* SOFT_BASE */
 		.virtual	= SOFT_BASE,
 		.pfn		= __phys_to_pfn(TRICK1_PHYS),
-		.length		= PGDIR_SIZE,
+		.length		= TRICK1_SIZE,
 		.type		= MT_DEVICE
 	}, {	/* PIT_BASE */
 		.virtual	= PIT_BASE,
 		.pfn		= __phys_to_pfn(TRICK0_PHYS),
-		.length		= PGDIR_SIZE,
+		.length		= TRICK0_SIZE,
 		.type		= MT_DEVICE
 	},
 
@@ -119,6 +116,20 @@
 	iotable_init(ebsa110_io_desc, ARRAY_SIZE(ebsa110_io_desc));
 }
 
+static void __iomem *ebsa110_ioremap_caller(unsigned long cookie, size_t size,
+					    unsigned int flags, void *caller)
+{
+	return (void __iomem *)cookie;
+}
+
+static void ebsa110_iounmap(volatile void __iomem *io_addr)
+{}
+
+static void __init ebsa110_init_early(void)
+{
+	arch_ioremap_caller = ebsa110_ioremap_caller;
+	arch_iounmap = ebsa110_iounmap;
+}
 
 #define PIT_CTRL		(PIT_BASE + 0x0d)
 #define PIT_T2			(PIT_BASE + 0x09)
@@ -271,8 +282,33 @@
 	&am79c961_device,
 };
 
+/*
+ * EBSA110 idling methodology:
+ *
+ * We can not execute the "wait for interrupt" instruction since that
+ * will stop our MCLK signal (which provides the clock for the glue
+ * logic, and therefore the timer interrupt).
+ *
+ * Instead, we spin, polling the IRQ_STAT register for the occurrence
+ * of any interrupt with core clock down to the memory clock.
+ */
+static void ebsa110_idle(void)
+{
+	const char *irq_stat = (char *)0xff000000;
+
+	/* disable clock switching */
+	asm volatile ("mcr p15, 0, ip, c15, c2, 2" : : : "cc");
+
+	/* wait for an interrupt to occur */
+	while (!*irq_stat);
+
+	/* enable clock switching */
+	asm volatile ("mcr p15, 0, ip, c15, c1, 2" : : : "cc");
+}
+
 static int __init ebsa110_init(void)
 {
+	arm_pm_idle = ebsa110_idle;
 	return platform_add_devices(ebsa110_devices, ARRAY_SIZE(ebsa110_devices));
 }
 
@@ -290,6 +326,7 @@
 	.reserve_lp2	= 1,
 	.restart_mode	= 's',
 	.map_io		= ebsa110_map_io,
+	.init_early	= ebsa110_init_early,
 	.init_irq	= ebsa110_init_irq,
 	.timer		= &ebsa110_timer,
 	.restart	= ebsa110_restart,
diff --git a/arch/arm/mach-ebsa110/core.h b/arch/arm/mach-ebsa110/core.h
new file mode 100644
index 0000000..c93c9e4
--- /dev/null
+++ b/arch/arm/mach-ebsa110/core.h
@@ -0,0 +1,41 @@
+/*
+ *  Copyright (C) 1996-2000 Russell King.
+ *
+ * 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 contains the core hardware definitions of the EBSA-110.
+ */
+#ifndef CORE_H
+#define CORE_H
+
+/* Physical addresses/sizes */
+#define ISAMEM_PHYS		0xe0000000
+#define ISAMEM_SIZE		0x10000000
+
+#define ISAIO_PHYS		0xf0000000
+#define ISAIO_SIZE		PGDIR_SIZE
+
+#define TRICK0_PHYS		0xf2000000
+#define TRICK0_SIZE		PGDIR_SIZE
+#define TRICK1_PHYS		0xf2400000
+#define TRICK1_SIZE		PGDIR_SIZE
+#define TRICK2_PHYS		0xf2800000
+#define TRICK3_PHYS		0xf2c00000
+#define TRICK3_SIZE		PGDIR_SIZE
+#define TRICK4_PHYS		0xf3000000
+#define TRICK4_SIZE		PGDIR_SIZE
+#define TRICK5_PHYS		0xf3400000
+#define TRICK6_PHYS		0xf3800000
+#define TRICK7_PHYS		0xf3c00000
+
+/* Virtual addresses */
+#define PIT_BASE		0xfc000000	/* trick 0 */
+#define SOFT_BASE		0xfd000000	/* trick 1 */
+#define IRQ_MASK		0xfe000000	/* trick 3 - read */
+#define IRQ_MSET		0xfe000000	/* trick 3 - write */
+#define IRQ_STAT		0xff000000	/* trick 4 - read */
+#define IRQ_MCLR		0xff000000	/* trick 4 - write */
+
+#endif
diff --git a/arch/arm/mach-ebsa110/include/mach/entry-macro.S b/arch/arm/mach-ebsa110/include/mach/entry-macro.S
index cc3e599..14b110d 100644
--- a/arch/arm/mach-ebsa110/include/mach/entry-macro.S
+++ b/arch/arm/mach-ebsa110/include/mach/entry-macro.S
@@ -12,16 +12,10 @@
 
 #define IRQ_STAT		0xff000000	/* read */
 
-	.macro	disable_fiq
-	.endm
-
 	.macro  get_irqnr_preamble, base, tmp
 	mov	\base, #IRQ_STAT
 	.endm
 
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
-
 	.macro	get_irqnr_and_base, irqnr, stat, base, tmp
 	ldrb	\stat, [\base]			@ get interrupts
 	mov	\irqnr, #0
diff --git a/arch/arm/mach-ebsa110/include/mach/hardware.h b/arch/arm/mach-ebsa110/include/mach/hardware.h
index 4b2fb77..f4e5407 100644
--- a/arch/arm/mach-ebsa110/include/mach/hardware.h
+++ b/arch/arm/mach-ebsa110/include/mach/hardware.h
@@ -12,48 +12,9 @@
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
-/*
- * The EBSA110 has a weird "ISA IO" region:
- *
- * Region 0 (addr = 0xf0000000 + io << 2)
- * --------------------------------------------------------
- * Physical region	IO region
- * f0000fe0 - f0000ffc	3f8 - 3ff  ttyS0
- * f0000e60 - f0000e64	398 - 399
- * f0000de0 - f0000dfc	378 - 37f  lp0
- * f0000be0 - f0000bfc	2f8 - 2ff  ttyS1
- *
- * Region 1 (addr = 0xf0000000 + (io & ~1) << 1 + (io & 1))
- * --------------------------------------------------------
- * Physical region	IO region
- * f00014f1             a79        pnp write data
- * f00007c0 - f00007c1	3e0 - 3e1  pcmcia
- * f00004f1		279        pnp address
- * f0000440 - f000046c  220 - 236  eth0
- * f0000405		203        pnp read data
- */
-
-#define ISAMEM_PHYS		0xe0000000
-#define ISAMEM_SIZE		0x10000000
-
-#define ISAIO_PHYS		0xf0000000
-#define ISAIO_SIZE		PGDIR_SIZE
-
-#define TRICK0_PHYS		0xf2000000
-#define TRICK1_PHYS		0xf2400000
-#define TRICK2_PHYS		0xf2800000
-#define TRICK3_PHYS		0xf2c00000
-#define TRICK4_PHYS		0xf3000000
-#define TRICK5_PHYS		0xf3400000
-#define TRICK6_PHYS		0xf3800000
-#define TRICK7_PHYS		0xf3c00000
-
 #define ISAMEM_BASE		0xe0000000
 #define ISAIO_BASE		0xf0000000
 
-#define PIT_BASE		0xfc000000
-#define SOFT_BASE		0xfd000000
-
 /*
  * RAM definitions
  */
diff --git a/arch/arm/mach-ebsa110/include/mach/io.h b/arch/arm/mach-ebsa110/include/mach/io.h
index 44679db..11bb079 100644
--- a/arch/arm/mach-ebsa110/include/mach/io.h
+++ b/arch/arm/mach-ebsa110/include/mach/io.h
@@ -62,15 +62,6 @@
 #define writew(v,b)		__writew(v,b)
 #define writel(v,b)		__writel(v,b)
 
-static inline void __iomem *__arch_ioremap(unsigned long cookie, size_t size,
-					   unsigned int flags)
-{
-	return (void __iomem *)cookie;
-}
-
-#define __arch_ioremap		__arch_ioremap
-#define __arch_iounmap(cookie)	do { } while (0)
-
 extern void insb(unsigned int port, void *buf, int sz);
 extern void insw(unsigned int port, void *buf, int sz);
 extern void insl(unsigned int port, void *buf, int sz);
diff --git a/arch/arm/mach-ebsa110/include/mach/system.h b/arch/arm/mach-ebsa110/include/mach/system.h
deleted file mode 100644
index 2e4af65..0000000
--- a/arch/arm/mach-ebsa110/include/mach/system.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *  arch/arm/mach-ebsa110/include/mach/system.h
- *
- *  Copyright (C) 1996-2000 Russell King.
- *
- * 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-/*
- * EBSA110 idling methodology:
- *
- * We can not execute the "wait for interrupt" instruction since that
- * will stop our MCLK signal (which provides the clock for the glue
- * logic, and therefore the timer interrupt).
- *
- * Instead, we spin, polling the IRQ_STAT register for the occurrence
- * of any interrupt with core clock down to the memory clock.
- */
-static inline void arch_idle(void)
-{
-	const char *irq_stat = (char *)0xff000000;
-
-	/* disable clock switching */
-	asm volatile ("mcr p15, 0, ip, c15, c2, 2" : : : "cc");
-
-	/* wait for an interrupt to occur */
-	while (!*irq_stat);
-
-	/* enable clock switching */
-	asm volatile ("mcr p15, 0, ip, c15, c1, 2" : : : "cc");
-}
-
-#endif
diff --git a/arch/arm/mach-ebsa110/io.c b/arch/arm/mach-ebsa110/io.c
index c52e304..756cc37 100644
--- a/arch/arm/mach-ebsa110/io.c
+++ b/arch/arm/mach-ebsa110/io.c
@@ -177,6 +177,26 @@
 }
 EXPORT_SYMBOL(writesl);
 
+/*
+ * The EBSA110 has a weird "ISA IO" region:
+ *
+ * Region 0 (addr = 0xf0000000 + io << 2)
+ * --------------------------------------------------------
+ * Physical region	IO region
+ * f0000fe0 - f0000ffc	3f8 - 3ff  ttyS0
+ * f0000e60 - f0000e64	398 - 399
+ * f0000de0 - f0000dfc	378 - 37f  lp0
+ * f0000be0 - f0000bfc	2f8 - 2ff  ttyS1
+ *
+ * Region 1 (addr = 0xf0000000 + (io & ~1) << 1 + (io & 1))
+ * --------------------------------------------------------
+ * Physical region	IO region
+ * f00014f1             a79        pnp write data
+ * f00007c0 - f00007c1	3e0 - 3e1  pcmcia
+ * f00004f1		279        pnp address
+ * f0000440 - f000046c  220 - 236  eth0
+ * f0000405		203        pnp read data
+ */
 #define SUPERIO_PORT(p) \
 	(((p) >> 3) == (0x3f8 >> 3) || \
 	 ((p) >> 3) == (0x2f8 >> 3) || \
diff --git a/arch/arm/mach-ebsa110/leds.c b/arch/arm/mach-ebsa110/leds.c
index 6a6ea57..99e14e36 100644
--- a/arch/arm/mach-ebsa110/leds.c
+++ b/arch/arm/mach-ebsa110/leds.c
@@ -17,9 +17,10 @@
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
-#include <asm/system.h>
 #include <asm/mach-types.h>
 
+#include "core.h"
+
 static spinlock_t leds_lock;
 
 static void ebsa110_leds_event(led_event_t ledevt)
diff --git a/arch/arm/mach-ep93xx/Makefile b/arch/arm/mach-ep93xx/Makefile
index 574209d9..0dc51f9 100644
--- a/arch/arm/mach-ep93xx/Makefile
+++ b/arch/arm/mach-ep93xx/Makefile
@@ -8,6 +8,9 @@
 
 obj-$(CONFIG_EP93XX_DMA)	+= dma.o
 
+obj-$(CONFIG_CRUNCH)		+= crunch.o crunch-bits.o
+AFLAGS_crunch-bits.o		:= -Wa,-mcpu=ep9312
+
 obj-$(CONFIG_MACH_ADSSPHERE)	+= adssphere.o
 obj-$(CONFIG_MACH_EDB93XX)	+= edb93xx.o
 obj-$(CONFIG_MACH_GESBC9312)	+= gesbc9312.o
diff --git a/arch/arm/mach-ep93xx/adssphere.c b/arch/arm/mach-ep93xx/adssphere.c
index 681e939..2d45947 100644
--- a/arch/arm/mach-ep93xx/adssphere.c
+++ b/arch/arm/mach-ep93xx/adssphere.c
@@ -20,6 +20,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
 
 static struct ep93xx_eth_data __initdata adssphere_eth_data = {
 	.phy_id		= 1,
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index ca4de71..c95dbce 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -25,6 +25,7 @@
 
 #include <asm/div64.h>
 
+#include "soc.h"
 
 struct clk {
 	struct clk	*parent;
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 24203f9..8d25895 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -46,6 +46,7 @@
 
 #include <asm/hardware/vic.h>
 
+#include "soc.h"
 
 /*************************************************************************
  * Static I/O mappings that are needed for all EP93xx platforms
@@ -204,7 +205,6 @@
 
 	spin_unlock_irqrestore(&syscon_swlock, flags);
 }
-EXPORT_SYMBOL(ep93xx_syscon_swlocked_write);
 
 void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits)
 {
@@ -221,7 +221,6 @@
 
 	spin_unlock_irqrestore(&syscon_swlock, flags);
 }
-EXPORT_SYMBOL(ep93xx_devcfg_set_clear);
 
 /**
  * ep93xx_chip_revision() - returns the EP93xx chip revision
@@ -279,48 +278,14 @@
 	.set_mctrl	= ep93xx_uart_set_mctrl,
 };
 
-static struct amba_device uart1_device = {
-	.dev		= {
-		.init_name	= "apb:uart1",
-		.platform_data	= &ep93xx_uart_data,
-	},
-	.res		= {
-		.start	= EP93XX_UART1_PHYS_BASE,
-		.end	= EP93XX_UART1_PHYS_BASE + 0x0fff,
-		.flags	= IORESOURCE_MEM,
-	},
-	.irq		= { IRQ_EP93XX_UART1, NO_IRQ },
-	.periphid	= 0x00041010,
-};
+static AMBA_APB_DEVICE(uart1, "apb:uart1", 0x00041010, EP93XX_UART1_PHYS_BASE,
+	{ IRQ_EP93XX_UART1 }, &ep93xx_uart_data);
 
-static struct amba_device uart2_device = {
-	.dev		= {
-		.init_name	= "apb:uart2",
-		.platform_data	= &ep93xx_uart_data,
-	},
-	.res		= {
-		.start	= EP93XX_UART2_PHYS_BASE,
-		.end	= EP93XX_UART2_PHYS_BASE + 0x0fff,
-		.flags	= IORESOURCE_MEM,
-	},
-	.irq		= { IRQ_EP93XX_UART2, NO_IRQ },
-	.periphid	= 0x00041010,
-};
+static AMBA_APB_DEVICE(uart2, "apb:uart2", 0x00041010, EP93XX_UART2_PHYS_BASE,
+	{ IRQ_EP93XX_UART2 }, &ep93xx_uart_data);
 
-static struct amba_device uart3_device = {
-	.dev		= {
-		.init_name	= "apb:uart3",
-		.platform_data	= &ep93xx_uart_data,
-	},
-	.res		= {
-		.start	= EP93XX_UART3_PHYS_BASE,
-		.end	= EP93XX_UART3_PHYS_BASE + 0x0fff,
-		.flags	= IORESOURCE_MEM,
-	},
-	.irq		= { IRQ_EP93XX_UART3, NO_IRQ },
-	.periphid	= 0x00041010,
-};
-
+static AMBA_APB_DEVICE(uart3, "apb:uart3", 0x00041010, EP93XX_UART3_PHYS_BASE,
+	{ IRQ_EP93XX_UART3 }, &ep93xx_uart_data);
 
 static struct resource ep93xx_rtc_resource[] = {
 	{
@@ -682,9 +647,19 @@
 	.resource		= ep93xx_fb_resource,
 };
 
+/* The backlight use a single register in the framebuffer's register space */
+#define EP93XX_RASTER_REG_BRIGHTNESS 0x20
+
+static struct resource ep93xx_bl_resources[] = {
+	DEFINE_RES_MEM(EP93XX_RASTER_PHYS_BASE +
+		       EP93XX_RASTER_REG_BRIGHTNESS, 0x04),
+};
+
 static struct platform_device ep93xx_bl_device = {
 	.name		= "ep93xx-bl",
 	.id		= -1,
+	.num_resources	= ARRAY_SIZE(ep93xx_bl_resources),
+	.resource	= ep93xx_bl_resources,
 };
 
 /**
@@ -817,23 +792,12 @@
 #define EP93XX_I2SCLKDIV_MASK		(EP93XX_SYSCON_I2SCLKDIV_ORIDE | \
 					 EP93XX_SYSCON_I2SCLKDIV_SPOL)
 
-int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config)
+int ep93xx_i2s_acquire(void)
 {
 	unsigned val;
 
-	/* Sanity check */
-	if (i2s_pins & ~EP93XX_SYSCON_DEVCFG_I2S_MASK)
-		return -EINVAL;
-	if (i2s_config & ~EP93XX_I2SCLKDIV_MASK)
-		return -EINVAL;
-
-	/* Must have only one of I2SONSSP/I2SONAC97 set */
-	if ((i2s_pins & EP93XX_SYSCON_DEVCFG_I2SONSSP) ==
-	    (i2s_pins & EP93XX_SYSCON_DEVCFG_I2SONAC97))
-		return -EINVAL;
-
-	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2S_MASK);
-	ep93xx_devcfg_set_bits(i2s_pins);
+	ep93xx_devcfg_set_clear(EP93XX_SYSCON_DEVCFG_I2SONAC97,
+			EP93XX_SYSCON_DEVCFG_I2S_MASK);
 
 	/*
 	 * This is potentially racy with the clock api for i2s_mclk, sclk and 
@@ -843,7 +807,7 @@
 	 */
 	val = __raw_readl(EP93XX_SYSCON_I2SCLKDIV);
 	val &= ~EP93XX_I2SCLKDIV_MASK;
-	val |= i2s_config;
+	val |= EP93XX_SYSCON_I2SCLKDIV_ORIDE | EP93XX_SYSCON_I2SCLKDIV_SPOL;
 	ep93xx_syscon_swlocked_write(val, EP93XX_SYSCON_I2SCLKDIV);
 
 	return 0;
@@ -890,11 +854,32 @@
 	platform_device_register(&ep93xx_pcm_device);
 }
 
+/*************************************************************************
+ * EP93xx Watchdog
+ *************************************************************************/
+static struct resource ep93xx_wdt_resources[] = {
+	DEFINE_RES_MEM(EP93XX_WATCHDOG_PHYS_BASE, 0x08),
+};
+
+static struct platform_device ep93xx_wdt_device = {
+	.name		= "ep93xx-wdt",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(ep93xx_wdt_resources),
+	.resource	= ep93xx_wdt_resources,
+};
+
 void __init ep93xx_init_devices(void)
 {
 	/* Disallow access to MaverickCrunch initially */
 	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_CPENA);
 
+	/* Default all ports to GPIO */
+	ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS |
+			       EP93XX_SYSCON_DEVCFG_GONK |
+			       EP93XX_SYSCON_DEVCFG_EONIDE |
+			       EP93XX_SYSCON_DEVCFG_GONIDE |
+			       EP93XX_SYSCON_DEVCFG_HONIDE);
+
 	/* Get the GPIO working early, other devices need it */
 	platform_device_register(&ep93xx_gpio_device);
 
@@ -905,6 +890,7 @@
 	platform_device_register(&ep93xx_rtc_device);
 	platform_device_register(&ep93xx_ohci_device);
 	platform_device_register(&ep93xx_leds);
+	platform_device_register(&ep93xx_wdt_device);
 }
 
 void ep93xx_restart(char mode, const char *cmd)
diff --git a/arch/arm/kernel/crunch-bits.S b/arch/arm/mach-ep93xx/crunch-bits.S
similarity index 100%
rename from arch/arm/kernel/crunch-bits.S
rename to arch/arm/mach-ep93xx/crunch-bits.S
diff --git a/arch/arm/mach-ep93xx/crunch.c b/arch/arm/mach-ep93xx/crunch.c
new file mode 100644
index 0000000..74753e2
--- /dev/null
+++ b/arch/arm/mach-ep93xx/crunch.c
@@ -0,0 +1,90 @@
+/*
+ * arch/arm/kernel/crunch.c
+ * Cirrus MaverickCrunch context switching and handling
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * 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/types.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <asm/thread_notify.h>
+
+#include "soc.h"
+
+struct crunch_state *crunch_owner;
+
+void crunch_task_release(struct thread_info *thread)
+{
+	local_irq_disable();
+	if (crunch_owner == &thread->crunchstate)
+		crunch_owner = NULL;
+	local_irq_enable();
+}
+
+static int crunch_enabled(u32 devcfg)
+{
+	return !!(devcfg & EP93XX_SYSCON_DEVCFG_CPENA);
+}
+
+static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t)
+{
+	struct thread_info *thread = (struct thread_info *)t;
+	struct crunch_state *crunch_state;
+	u32 devcfg;
+
+	crunch_state = &thread->crunchstate;
+
+	switch (cmd) {
+	case THREAD_NOTIFY_FLUSH:
+		memset(crunch_state, 0, sizeof(*crunch_state));
+
+		/*
+		 * FALLTHROUGH: Ensure we don't try to overwrite our newly
+		 * initialised state information on the first fault.
+		 */
+
+	case THREAD_NOTIFY_EXIT:
+		crunch_task_release(thread);
+		break;
+
+	case THREAD_NOTIFY_SWITCH:
+		devcfg = __raw_readl(EP93XX_SYSCON_DEVCFG);
+		if (crunch_enabled(devcfg) || crunch_owner == crunch_state) {
+			/*
+			 * We don't use ep93xx_syscon_swlocked_write() here
+			 * because we are on the context switch path and
+			 * preemption is already disabled.
+			 */
+			devcfg ^= EP93XX_SYSCON_DEVCFG_CPENA;
+			__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
+			__raw_writel(devcfg, EP93XX_SYSCON_DEVCFG);
+		}
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block crunch_notifier_block = {
+	.notifier_call	= crunch_do,
+};
+
+static int __init crunch_init(void)
+{
+	thread_register_notifier(&crunch_notifier_block);
+	elf_hwcap |= HWCAP_CRUNCH;
+
+	return 0;
+}
+
+late_initcall(crunch_init);
diff --git a/arch/arm/mach-ep93xx/dma.c b/arch/arm/mach-ep93xx/dma.c
index 5a25708..16976d7 100644
--- a/arch/arm/mach-ep93xx/dma.c
+++ b/arch/arm/mach-ep93xx/dma.c
@@ -28,6 +28,8 @@
 #include <mach/dma.h>
 #include <mach/hardware.h>
 
+#include "soc.h"
+
 #define DMA_CHANNEL(_name, _base, _irq) \
 	{ .name = (_name), .base = (_base), .irq = (_irq) }
 
diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c
index d115653..da9047d 100644
--- a/arch/arm/mach-ep93xx/edb93xx.c
+++ b/arch/arm/mach-ep93xx/edb93xx.c
@@ -43,6 +43,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
 
 static void __init edb93xx_register_flash(void)
 {
diff --git a/arch/arm/mach-ep93xx/gesbc9312.c b/arch/arm/mach-ep93xx/gesbc9312.c
index af46970..fcdffbe49 100644
--- a/arch/arm/mach-ep93xx/gesbc9312.c
+++ b/arch/arm/mach-ep93xx/gesbc9312.c
@@ -20,6 +20,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
 
 static struct ep93xx_eth_data __initdata gesbc9312_eth_data = {
 	.phy_id		= 1,
diff --git a/arch/arm/mach-ep93xx/include/mach/entry-macro.S b/arch/arm/mach-ep93xx/include/mach/entry-macro.S
deleted file mode 100644
index 9be6edc..0000000
--- a/arch/arm/mach-ep93xx/include/mach/entry-macro.S
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/include/mach/entry-macro.S
- * IRQ demultiplexing for EP93xx
- *
- * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.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.
- */
-
-		.macro	disable_fiq
-		.endm
-
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index c4a7b84..c64d742 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -6,40 +6,6 @@
 #define __ASM_ARCH_EP93XX_REGS_H
 
 /*
- * EP93xx Physical Memory Map:
- *
- * The ASDO pin is sampled at system reset to select a synchronous or
- * asynchronous boot configuration.  When ASDO is "1" (i.e. pulled-up)
- * the synchronous boot mode is selected.  When ASDO is "0" (i.e
- * pulled-down) the asynchronous boot mode is selected.
- *
- * In synchronous boot mode nSDCE3 is decoded starting at physical address
- * 0x00000000 and nCS0 is decoded starting at 0xf0000000.  For asynchronous
- * boot mode they are swapped with nCS0 decoded at 0x00000000 ann nSDCE3
- * decoded at 0xf0000000.
- *
- * There is known errata for the EP93xx dealing with External Memory
- * Configurations.  Please refer to "AN273: EP93xx Silicon Rev E Design
- * Guidelines" for more information.  This document can be found at:
- *
- *	http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
- */
-
-#define EP93XX_CS0_PHYS_BASE_ASYNC	0x00000000	/* ASDO Pin = 0 */
-#define EP93XX_SDCE3_PHYS_BASE_SYNC	0x00000000	/* ASDO Pin = 1 */
-#define EP93XX_CS1_PHYS_BASE		0x10000000
-#define EP93XX_CS2_PHYS_BASE		0x20000000
-#define EP93XX_CS3_PHYS_BASE		0x30000000
-#define EP93XX_PCMCIA_PHYS_BASE		0x40000000
-#define EP93XX_CS6_PHYS_BASE		0x60000000
-#define EP93XX_CS7_PHYS_BASE		0x70000000
-#define EP93XX_SDCE0_PHYS_BASE		0xc0000000
-#define EP93XX_SDCE1_PHYS_BASE		0xd0000000
-#define EP93XX_SDCE2_PHYS_BASE		0xe0000000
-#define EP93XX_SDCE3_PHYS_BASE_ASYNC	0xf0000000	/* ASDO Pin = 0 */
-#define EP93XX_CS0_PHYS_BASE_SYNC	0xf0000000	/* ASDO Pin = 1 */
-
-/*
  * EP93xx linux memory map:
  *
  * virt		phys		size
@@ -62,58 +28,7 @@
 #define EP93XX_APB_PHYS(x)		(EP93XX_APB_PHYS_BASE + (x))
 #define EP93XX_APB_IOMEM(x)		IOMEM(EP93XX_APB_VIRT_BASE + (x))
 
-
-/* AHB peripherals */
-#define EP93XX_DMA_BASE			EP93XX_AHB_IOMEM(0x00000000)
-
-#define EP93XX_ETHERNET_PHYS_BASE	EP93XX_AHB_PHYS(0x00010000)
-#define EP93XX_ETHERNET_BASE		EP93XX_AHB_IOMEM(0x00010000)
-
-#define EP93XX_USB_PHYS_BASE		EP93XX_AHB_PHYS(0x00020000)
-#define EP93XX_USB_BASE			EP93XX_AHB_IOMEM(0x00020000)
-
-#define EP93XX_RASTER_PHYS_BASE		EP93XX_AHB_PHYS(0x00030000)
-#define EP93XX_RASTER_BASE		EP93XX_AHB_IOMEM(0x00030000)
-
-#define EP93XX_GRAPHICS_ACCEL_BASE	EP93XX_AHB_IOMEM(0x00040000)
-
-#define EP93XX_SDRAM_CONTROLLER_BASE	EP93XX_AHB_IOMEM(0x00060000)
-
-#define EP93XX_PCMCIA_CONTROLLER_BASE	EP93XX_AHB_IOMEM(0x00080000)
-
-#define EP93XX_BOOT_ROM_BASE		EP93XX_AHB_IOMEM(0x00090000)
-
-#define EP93XX_IDE_BASE			EP93XX_AHB_IOMEM(0x000a0000)
-
-#define EP93XX_VIC1_BASE		EP93XX_AHB_IOMEM(0x000b0000)
-
-#define EP93XX_VIC2_BASE		EP93XX_AHB_IOMEM(0x000c0000)
-
-
-/* APB peripherals */
-#define EP93XX_TIMER_BASE		EP93XX_APB_IOMEM(0x00010000)
-
-#define EP93XX_I2S_PHYS_BASE		EP93XX_APB_PHYS(0x00020000)
-#define EP93XX_I2S_BASE			EP93XX_APB_IOMEM(0x00020000)
-
-#define EP93XX_SECURITY_BASE		EP93XX_APB_IOMEM(0x00030000)
-
-#define EP93XX_GPIO_PHYS_BASE		EP93XX_APB_PHYS(0x00040000)
-#define EP93XX_GPIO_BASE		EP93XX_APB_IOMEM(0x00040000)
-#define EP93XX_GPIO_REG(x)		(EP93XX_GPIO_BASE + (x))
-#define EP93XX_GPIO_F_INT_STATUS	EP93XX_GPIO_REG(0x5c)
-#define EP93XX_GPIO_A_INT_STATUS	EP93XX_GPIO_REG(0xa0)
-#define EP93XX_GPIO_B_INT_STATUS	EP93XX_GPIO_REG(0xbc)
-#define EP93XX_GPIO_EEDRIVE		EP93XX_GPIO_REG(0xc8)
-
-#define EP93XX_AAC_PHYS_BASE		EP93XX_APB_PHYS(0x00080000)
-#define EP93XX_AAC_BASE			EP93XX_APB_IOMEM(0x00080000)
-
-#define EP93XX_SPI_PHYS_BASE		EP93XX_APB_PHYS(0x000a0000)
-#define EP93XX_SPI_BASE			EP93XX_APB_IOMEM(0x000a0000)
-
-#define EP93XX_IRDA_BASE		EP93XX_APB_IOMEM(0x000b0000)
-
+/* APB UARTs */
 #define EP93XX_UART1_PHYS_BASE		EP93XX_APB_PHYS(0x000c0000)
 #define EP93XX_UART1_BASE		EP93XX_APB_IOMEM(0x000c0000)
 
@@ -123,108 +38,4 @@
 #define EP93XX_UART3_PHYS_BASE		EP93XX_APB_PHYS(0x000e0000)
 #define EP93XX_UART3_BASE		EP93XX_APB_IOMEM(0x000e0000)
 
-#define EP93XX_KEY_MATRIX_PHYS_BASE	EP93XX_APB_PHYS(0x000f0000)
-#define EP93XX_KEY_MATRIX_BASE		EP93XX_APB_IOMEM(0x000f0000)
-
-#define EP93XX_ADC_BASE			EP93XX_APB_IOMEM(0x00100000)
-#define EP93XX_TOUCHSCREEN_BASE		EP93XX_APB_IOMEM(0x00100000)
-
-#define EP93XX_PWM_PHYS_BASE		EP93XX_APB_PHYS(0x00110000)
-#define EP93XX_PWM_BASE			EP93XX_APB_IOMEM(0x00110000)
-
-#define EP93XX_RTC_PHYS_BASE		EP93XX_APB_PHYS(0x00120000)
-#define EP93XX_RTC_BASE			EP93XX_APB_IOMEM(0x00120000)
-
-#define EP93XX_SYSCON_BASE		EP93XX_APB_IOMEM(0x00130000)
-#define EP93XX_SYSCON_REG(x)		(EP93XX_SYSCON_BASE + (x))
-#define EP93XX_SYSCON_POWER_STATE	EP93XX_SYSCON_REG(0x00)
-#define EP93XX_SYSCON_PWRCNT		EP93XX_SYSCON_REG(0x04)
-#define EP93XX_SYSCON_PWRCNT_FIR_EN	(1<<31)
-#define EP93XX_SYSCON_PWRCNT_UARTBAUD	(1<<29)
-#define EP93XX_SYSCON_PWRCNT_USH_EN	(1<<28)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2M1	(1<<27)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2M0	(1<<26)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P8	(1<<25)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P9	(1<<24)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P6	(1<<23)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P7	(1<<22)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P4	(1<<21)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P5	(1<<20)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P2	(1<<19)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P3	(1<<18)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P0	(1<<17)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P1	(1<<16)
-#define EP93XX_SYSCON_HALT		EP93XX_SYSCON_REG(0x08)
-#define EP93XX_SYSCON_STANDBY		EP93XX_SYSCON_REG(0x0c)
-#define EP93XX_SYSCON_CLKSET1		EP93XX_SYSCON_REG(0x20)
-#define EP93XX_SYSCON_CLKSET1_NBYP1	(1<<23)
-#define EP93XX_SYSCON_CLKSET2		EP93XX_SYSCON_REG(0x24)
-#define EP93XX_SYSCON_CLKSET2_NBYP2	(1<<19)
-#define EP93XX_SYSCON_CLKSET2_PLL2_EN	(1<<18)
-#define EP93XX_SYSCON_DEVCFG		EP93XX_SYSCON_REG(0x80)
-#define EP93XX_SYSCON_DEVCFG_SWRST	(1<<31)
-#define EP93XX_SYSCON_DEVCFG_D1ONG	(1<<30)
-#define EP93XX_SYSCON_DEVCFG_D0ONG	(1<<29)
-#define EP93XX_SYSCON_DEVCFG_IONU2	(1<<28)
-#define EP93XX_SYSCON_DEVCFG_GONK	(1<<27)
-#define EP93XX_SYSCON_DEVCFG_TONG	(1<<26)
-#define EP93XX_SYSCON_DEVCFG_MONG	(1<<25)
-#define EP93XX_SYSCON_DEVCFG_U3EN	(1<<24)
-#define EP93XX_SYSCON_DEVCFG_CPENA	(1<<23)
-#define EP93XX_SYSCON_DEVCFG_A2ONG	(1<<22)
-#define EP93XX_SYSCON_DEVCFG_A1ONG	(1<<21)
-#define EP93XX_SYSCON_DEVCFG_U2EN	(1<<20)
-#define EP93XX_SYSCON_DEVCFG_EXVC	(1<<19)
-#define EP93XX_SYSCON_DEVCFG_U1EN	(1<<18)
-#define EP93XX_SYSCON_DEVCFG_TIN	(1<<17)
-#define EP93XX_SYSCON_DEVCFG_HC3IN	(1<<15)
-#define EP93XX_SYSCON_DEVCFG_HC3EN	(1<<14)
-#define EP93XX_SYSCON_DEVCFG_HC1IN	(1<<13)
-#define EP93XX_SYSCON_DEVCFG_HC1EN	(1<<12)
-#define EP93XX_SYSCON_DEVCFG_HONIDE	(1<<11)
-#define EP93XX_SYSCON_DEVCFG_GONIDE	(1<<10)
-#define EP93XX_SYSCON_DEVCFG_PONG	(1<<9)
-#define EP93XX_SYSCON_DEVCFG_EONIDE	(1<<8)
-#define EP93XX_SYSCON_DEVCFG_I2SONSSP	(1<<7)
-#define EP93XX_SYSCON_DEVCFG_I2SONAC97	(1<<6)
-#define EP93XX_SYSCON_DEVCFG_RASONP3	(1<<4)
-#define EP93XX_SYSCON_DEVCFG_RAS	(1<<3)
-#define EP93XX_SYSCON_DEVCFG_ADCPD	(1<<2)
-#define EP93XX_SYSCON_DEVCFG_KEYS	(1<<1)
-#define EP93XX_SYSCON_DEVCFG_SHENA	(1<<0)
-#define EP93XX_SYSCON_VIDCLKDIV		EP93XX_SYSCON_REG(0x84)
-#define EP93XX_SYSCON_CLKDIV_ENABLE	(1<<15)
-#define EP93XX_SYSCON_CLKDIV_ESEL	(1<<14)
-#define EP93XX_SYSCON_CLKDIV_PSEL	(1<<13)
-#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT	8
-#define EP93XX_SYSCON_I2SCLKDIV		EP93XX_SYSCON_REG(0x8c)
-#define EP93XX_SYSCON_I2SCLKDIV_SENA	(1<<31)
-#define EP93XX_SYSCON_I2SCLKDIV_ORIDE   (1<<29)
-#define EP93XX_SYSCON_I2SCLKDIV_SPOL	(1<<19)
-#define EP93XX_I2SCLKDIV_SDIV		(1 << 16)
-#define EP93XX_I2SCLKDIV_LRDIV32	(0 << 17)
-#define EP93XX_I2SCLKDIV_LRDIV64	(1 << 17)
-#define EP93XX_I2SCLKDIV_LRDIV128 	(2 << 17)
-#define EP93XX_I2SCLKDIV_LRDIV_MASK 	(3 << 17)
-#define EP93XX_SYSCON_KEYTCHCLKDIV	EP93XX_SYSCON_REG(0x90)
-#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN	(1<<31)
-#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV	(1<<16)
-#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN	(1<<15)
-#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV	(1<<0)
-#define EP93XX_SYSCON_SYSCFG		EP93XX_SYSCON_REG(0x9c)
-#define EP93XX_SYSCON_SYSCFG_REV_MASK	(0xf0000000)
-#define EP93XX_SYSCON_SYSCFG_REV_SHIFT	(28)
-#define EP93XX_SYSCON_SYSCFG_SBOOT	(1<<8)
-#define EP93XX_SYSCON_SYSCFG_LCSN7	(1<<7)
-#define EP93XX_SYSCON_SYSCFG_LCSN6	(1<<6)
-#define EP93XX_SYSCON_SYSCFG_LASDO	(1<<5)
-#define EP93XX_SYSCON_SYSCFG_LEEDA	(1<<4)
-#define EP93XX_SYSCON_SYSCFG_LEECLK	(1<<3)
-#define EP93XX_SYSCON_SYSCFG_LCSN2	(1<<1)
-#define EP93XX_SYSCON_SYSCFG_LCSN1	(1<<0)
-#define EP93XX_SYSCON_SWLOCK		EP93XX_SYSCON_REG(0xc0)
-
-#define EP93XX_WATCHDOG_BASE		EP93XX_APB_IOMEM(0x00140000)
-
-
 #endif
diff --git a/arch/arm/mach-ep93xx/include/mach/gpio-ep93xx.h b/arch/arm/mach-ep93xx/include/mach/gpio-ep93xx.h
index 8aff2ea..6d7c571 100644
--- a/arch/arm/mach-ep93xx/include/mach/gpio-ep93xx.h
+++ b/arch/arm/mach-ep93xx/include/mach/gpio-ep93xx.h
@@ -3,6 +3,16 @@
 #ifndef __GPIO_EP93XX_H
 #define __GPIO_EP93XX_H
 
+#include <mach/ep93xx-regs.h>
+
+#define EP93XX_GPIO_PHYS_BASE		EP93XX_APB_PHYS(0x00040000)
+#define EP93XX_GPIO_BASE		EP93XX_APB_IOMEM(0x00040000)
+#define EP93XX_GPIO_REG(x)		(EP93XX_GPIO_BASE + (x))
+#define EP93XX_GPIO_F_INT_STATUS	EP93XX_GPIO_REG(0x5c)
+#define EP93XX_GPIO_A_INT_STATUS	EP93XX_GPIO_REG(0xa0)
+#define EP93XX_GPIO_B_INT_STATUS	EP93XX_GPIO_REG(0xbc)
+#define EP93XX_GPIO_EEDRIVE		EP93XX_GPIO_REG(0xc8)
+
 /* GPIO port A.  */
 #define EP93XX_GPIO_LINE_A(x)		((x) + 0)
 #define EP93XX_GPIO_LINE_EGPIO0		EP93XX_GPIO_LINE_A(0)
diff --git a/arch/arm/mach-ep93xx/include/mach/hardware.h b/arch/arm/mach-ep93xx/include/mach/hardware.h
index 4df8428..efcd478 100644
--- a/arch/arm/mach-ep93xx/include/mach/hardware.h
+++ b/arch/arm/mach-ep93xx/include/mach/hardware.h
@@ -5,7 +5,6 @@
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
-#include <mach/ep93xx-regs.h>
 #include <mach/platform.h>
 
 /*
diff --git a/arch/arm/mach-ep93xx/include/mach/io.h b/arch/arm/mach-ep93xx/include/mach/io.h
deleted file mode 100644
index 594b77f..0000000
--- a/arch/arm/mach-ep93xx/include/mach/io.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/include/mach/io.h
- */
-
-#ifndef __ASM_MACH_IO_H
-#define __ASM_MACH_IO_H
-
-#define IO_SPACE_LIMIT		0xffffffff
-
-#define __io(p)			__typesafe_io(p)
-#define __mem_pci(p)		(p)
-
-/*
- * A typesafe __io() variation for variable initialisers
- */
-#ifdef __ASSEMBLER__
-#define IOMEM(p)		p
-#else
-#define IOMEM(p)		((void __iomem __force *)(p))
-#endif
-
-#endif /* __ASM_MACH_IO_H */
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index d4c9349..602bd87 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -21,20 +21,6 @@
 void ep93xx_map_io(void);
 void ep93xx_init_irq(void);
 
-/* EP93xx System Controller software locked register write */
-void ep93xx_syscon_swlocked_write(unsigned int val, void __iomem *reg);
-void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits);
-
-static inline void ep93xx_devcfg_set_bits(unsigned int bits)
-{
-	ep93xx_devcfg_set_clear(bits, 0x00);
-}
-
-static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
-{
-	ep93xx_devcfg_set_clear(0x00, bits);
-}
-
 #define EP93XX_CHIP_REV_D0	3
 #define EP93XX_CHIP_REV_D1	4
 #define EP93XX_CHIP_REV_E0	5
@@ -59,7 +45,7 @@
 int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
 void ep93xx_keypad_release_gpio(struct platform_device *pdev);
 void ep93xx_register_i2s(void);
-int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config);
+int ep93xx_i2s_acquire(void);
 void ep93xx_i2s_release(void);
 void ep93xx_register_ac97(void);
 
diff --git a/arch/arm/mach-ep93xx/include/mach/system.h b/arch/arm/mach-ep93xx/include/mach/system.h
deleted file mode 100644
index b5bec7c..0000000
--- a/arch/arm/mach-ep93xx/include/mach/system.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/include/mach/system.h
- */
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
diff --git a/arch/arm/mach-ep93xx/micro9.c b/arch/arm/mach-ep93xx/micro9.c
index 7b98084..dc431c5 100644
--- a/arch/arm/mach-ep93xx/micro9.c
+++ b/arch/arm/mach-ep93xx/micro9.c
@@ -22,6 +22,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
 
 /*************************************************************************
  * Micro9 NOR Flash
diff --git a/arch/arm/mach-ep93xx/simone.c b/arch/arm/mach-ep93xx/simone.c
index f4e553e..f40c298 100644
--- a/arch/arm/mach-ep93xx/simone.c
+++ b/arch/arm/mach-ep93xx/simone.c
@@ -29,6 +29,8 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
+
 static struct ep93xx_eth_data __initdata simone_eth_data = {
 	.phy_id		= 1,
 };
diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c
index fd84633..0c00852 100644
--- a/arch/arm/mach-ep93xx/snappercl15.c
+++ b/arch/arm/mach-ep93xx/snappercl15.c
@@ -35,6 +35,8 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
+
 #define SNAPPERCL15_NAND_BASE	(EP93XX_CS7_PHYS_BASE + SZ_16M)
 
 #define SNAPPERCL15_NAND_WPN	(1 << 8)  /* Write protect (active low) */
diff --git a/arch/arm/mach-ep93xx/soc.h b/arch/arm/mach-ep93xx/soc.h
new file mode 100644
index 0000000..979fba7
--- /dev/null
+++ b/arch/arm/mach-ep93xx/soc.h
@@ -0,0 +1,213 @@
+/*
+ * arch/arm/mach-ep93xx/soc.h
+ *
+ * Copyright (C) 2012 Open Kernel Labs <www.ok-labs.com>
+ * Copyright (C) 2012 Ryan Mallon <rmallon@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 _EP93XX_SOC_H
+#define _EP93XX_SOC_H
+
+#include <mach/ep93xx-regs.h>
+
+/*
+ * EP93xx Physical Memory Map:
+ *
+ * The ASDO pin is sampled at system reset to select a synchronous or
+ * asynchronous boot configuration.  When ASDO is "1" (i.e. pulled-up)
+ * the synchronous boot mode is selected.  When ASDO is "0" (i.e
+ * pulled-down) the asynchronous boot mode is selected.
+ *
+ * In synchronous boot mode nSDCE3 is decoded starting at physical address
+ * 0x00000000 and nCS0 is decoded starting at 0xf0000000.  For asynchronous
+ * boot mode they are swapped with nCS0 decoded at 0x00000000 ann nSDCE3
+ * decoded at 0xf0000000.
+ *
+ * There is known errata for the EP93xx dealing with External Memory
+ * Configurations.  Please refer to "AN273: EP93xx Silicon Rev E Design
+ * Guidelines" for more information.  This document can be found at:
+ *
+ *	http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
+ */
+
+#define EP93XX_CS0_PHYS_BASE_ASYNC	0x00000000	/* ASDO Pin = 0 */
+#define EP93XX_SDCE3_PHYS_BASE_SYNC	0x00000000	/* ASDO Pin = 1 */
+#define EP93XX_CS1_PHYS_BASE		0x10000000
+#define EP93XX_CS2_PHYS_BASE		0x20000000
+#define EP93XX_CS3_PHYS_BASE		0x30000000
+#define EP93XX_PCMCIA_PHYS_BASE		0x40000000
+#define EP93XX_CS6_PHYS_BASE		0x60000000
+#define EP93XX_CS7_PHYS_BASE		0x70000000
+#define EP93XX_SDCE0_PHYS_BASE		0xc0000000
+#define EP93XX_SDCE1_PHYS_BASE		0xd0000000
+#define EP93XX_SDCE2_PHYS_BASE		0xe0000000
+#define EP93XX_SDCE3_PHYS_BASE_ASYNC	0xf0000000	/* ASDO Pin = 0 */
+#define EP93XX_CS0_PHYS_BASE_SYNC	0xf0000000	/* ASDO Pin = 1 */
+
+/* AHB peripherals */
+#define EP93XX_DMA_BASE			EP93XX_AHB_IOMEM(0x00000000)
+
+#define EP93XX_ETHERNET_PHYS_BASE	EP93XX_AHB_PHYS(0x00010000)
+#define EP93XX_ETHERNET_BASE		EP93XX_AHB_IOMEM(0x00010000)
+
+#define EP93XX_USB_PHYS_BASE		EP93XX_AHB_PHYS(0x00020000)
+#define EP93XX_USB_BASE			EP93XX_AHB_IOMEM(0x00020000)
+
+#define EP93XX_RASTER_PHYS_BASE		EP93XX_AHB_PHYS(0x00030000)
+#define EP93XX_RASTER_BASE		EP93XX_AHB_IOMEM(0x00030000)
+
+#define EP93XX_GRAPHICS_ACCEL_BASE	EP93XX_AHB_IOMEM(0x00040000)
+
+#define EP93XX_SDRAM_CONTROLLER_BASE	EP93XX_AHB_IOMEM(0x00060000)
+
+#define EP93XX_PCMCIA_CONTROLLER_BASE	EP93XX_AHB_IOMEM(0x00080000)
+
+#define EP93XX_BOOT_ROM_BASE		EP93XX_AHB_IOMEM(0x00090000)
+
+#define EP93XX_IDE_BASE			EP93XX_AHB_IOMEM(0x000a0000)
+
+#define EP93XX_VIC1_BASE		EP93XX_AHB_IOMEM(0x000b0000)
+
+#define EP93XX_VIC2_BASE		EP93XX_AHB_IOMEM(0x000c0000)
+
+/* APB peripherals */
+#define EP93XX_TIMER_BASE		EP93XX_APB_IOMEM(0x00010000)
+
+#define EP93XX_I2S_PHYS_BASE		EP93XX_APB_PHYS(0x00020000)
+#define EP93XX_I2S_BASE			EP93XX_APB_IOMEM(0x00020000)
+
+#define EP93XX_SECURITY_BASE		EP93XX_APB_IOMEM(0x00030000)
+
+#define EP93XX_AAC_PHYS_BASE		EP93XX_APB_PHYS(0x00080000)
+#define EP93XX_AAC_BASE			EP93XX_APB_IOMEM(0x00080000)
+
+#define EP93XX_SPI_PHYS_BASE		EP93XX_APB_PHYS(0x000a0000)
+#define EP93XX_SPI_BASE			EP93XX_APB_IOMEM(0x000a0000)
+
+#define EP93XX_IRDA_BASE		EP93XX_APB_IOMEM(0x000b0000)
+
+#define EP93XX_KEY_MATRIX_PHYS_BASE	EP93XX_APB_PHYS(0x000f0000)
+#define EP93XX_KEY_MATRIX_BASE		EP93XX_APB_IOMEM(0x000f0000)
+
+#define EP93XX_ADC_BASE			EP93XX_APB_IOMEM(0x00100000)
+#define EP93XX_TOUCHSCREEN_BASE		EP93XX_APB_IOMEM(0x00100000)
+
+#define EP93XX_PWM_PHYS_BASE		EP93XX_APB_PHYS(0x00110000)
+#define EP93XX_PWM_BASE			EP93XX_APB_IOMEM(0x00110000)
+
+#define EP93XX_RTC_PHYS_BASE		EP93XX_APB_PHYS(0x00120000)
+#define EP93XX_RTC_BASE			EP93XX_APB_IOMEM(0x00120000)
+
+#define EP93XX_WATCHDOG_PHYS_BASE	EP93XX_APB_PHYS(0x00140000)
+#define EP93XX_WATCHDOG_BASE		EP93XX_APB_IOMEM(0x00140000)
+
+/* System controller */
+#define EP93XX_SYSCON_BASE		EP93XX_APB_IOMEM(0x00130000)
+#define EP93XX_SYSCON_REG(x)		(EP93XX_SYSCON_BASE + (x))
+#define EP93XX_SYSCON_POWER_STATE	EP93XX_SYSCON_REG(0x00)
+#define EP93XX_SYSCON_PWRCNT		EP93XX_SYSCON_REG(0x04)
+#define EP93XX_SYSCON_PWRCNT_FIR_EN	(1<<31)
+#define EP93XX_SYSCON_PWRCNT_UARTBAUD	(1<<29)
+#define EP93XX_SYSCON_PWRCNT_USH_EN	(1<<28)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2M1	(1<<27)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2M0	(1<<26)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P8	(1<<25)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P9	(1<<24)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P6	(1<<23)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P7	(1<<22)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P4	(1<<21)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P5	(1<<20)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P2	(1<<19)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P3	(1<<18)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P0	(1<<17)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P1	(1<<16)
+#define EP93XX_SYSCON_HALT		EP93XX_SYSCON_REG(0x08)
+#define EP93XX_SYSCON_STANDBY		EP93XX_SYSCON_REG(0x0c)
+#define EP93XX_SYSCON_CLKSET1		EP93XX_SYSCON_REG(0x20)
+#define EP93XX_SYSCON_CLKSET1_NBYP1	(1<<23)
+#define EP93XX_SYSCON_CLKSET2		EP93XX_SYSCON_REG(0x24)
+#define EP93XX_SYSCON_CLKSET2_NBYP2	(1<<19)
+#define EP93XX_SYSCON_CLKSET2_PLL2_EN	(1<<18)
+#define EP93XX_SYSCON_DEVCFG		EP93XX_SYSCON_REG(0x80)
+#define EP93XX_SYSCON_DEVCFG_SWRST	(1<<31)
+#define EP93XX_SYSCON_DEVCFG_D1ONG	(1<<30)
+#define EP93XX_SYSCON_DEVCFG_D0ONG	(1<<29)
+#define EP93XX_SYSCON_DEVCFG_IONU2	(1<<28)
+#define EP93XX_SYSCON_DEVCFG_GONK	(1<<27)
+#define EP93XX_SYSCON_DEVCFG_TONG	(1<<26)
+#define EP93XX_SYSCON_DEVCFG_MONG	(1<<25)
+#define EP93XX_SYSCON_DEVCFG_U3EN	(1<<24)
+#define EP93XX_SYSCON_DEVCFG_CPENA	(1<<23)
+#define EP93XX_SYSCON_DEVCFG_A2ONG	(1<<22)
+#define EP93XX_SYSCON_DEVCFG_A1ONG	(1<<21)
+#define EP93XX_SYSCON_DEVCFG_U2EN	(1<<20)
+#define EP93XX_SYSCON_DEVCFG_EXVC	(1<<19)
+#define EP93XX_SYSCON_DEVCFG_U1EN	(1<<18)
+#define EP93XX_SYSCON_DEVCFG_TIN	(1<<17)
+#define EP93XX_SYSCON_DEVCFG_HC3IN	(1<<15)
+#define EP93XX_SYSCON_DEVCFG_HC3EN	(1<<14)
+#define EP93XX_SYSCON_DEVCFG_HC1IN	(1<<13)
+#define EP93XX_SYSCON_DEVCFG_HC1EN	(1<<12)
+#define EP93XX_SYSCON_DEVCFG_HONIDE	(1<<11)
+#define EP93XX_SYSCON_DEVCFG_GONIDE	(1<<10)
+#define EP93XX_SYSCON_DEVCFG_PONG	(1<<9)
+#define EP93XX_SYSCON_DEVCFG_EONIDE	(1<<8)
+#define EP93XX_SYSCON_DEVCFG_I2SONSSP	(1<<7)
+#define EP93XX_SYSCON_DEVCFG_I2SONAC97	(1<<6)
+#define EP93XX_SYSCON_DEVCFG_RASONP3	(1<<4)
+#define EP93XX_SYSCON_DEVCFG_RAS	(1<<3)
+#define EP93XX_SYSCON_DEVCFG_ADCPD	(1<<2)
+#define EP93XX_SYSCON_DEVCFG_KEYS	(1<<1)
+#define EP93XX_SYSCON_DEVCFG_SHENA	(1<<0)
+#define EP93XX_SYSCON_VIDCLKDIV		EP93XX_SYSCON_REG(0x84)
+#define EP93XX_SYSCON_CLKDIV_ENABLE	(1<<15)
+#define EP93XX_SYSCON_CLKDIV_ESEL	(1<<14)
+#define EP93XX_SYSCON_CLKDIV_PSEL	(1<<13)
+#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT	8
+#define EP93XX_SYSCON_I2SCLKDIV		EP93XX_SYSCON_REG(0x8c)
+#define EP93XX_SYSCON_I2SCLKDIV_SENA	(1<<31)
+#define EP93XX_SYSCON_I2SCLKDIV_ORIDE   (1<<29)
+#define EP93XX_SYSCON_I2SCLKDIV_SPOL	(1<<19)
+#define EP93XX_I2SCLKDIV_SDIV		(1 << 16)
+#define EP93XX_I2SCLKDIV_LRDIV32	(0 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV64	(1 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV128	(2 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV_MASK	(3 << 17)
+#define EP93XX_SYSCON_KEYTCHCLKDIV	EP93XX_SYSCON_REG(0x90)
+#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN	(1<<31)
+#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV	(1<<16)
+#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN	(1<<15)
+#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV	(1<<0)
+#define EP93XX_SYSCON_SYSCFG		EP93XX_SYSCON_REG(0x9c)
+#define EP93XX_SYSCON_SYSCFG_REV_MASK	(0xf0000000)
+#define EP93XX_SYSCON_SYSCFG_REV_SHIFT	(28)
+#define EP93XX_SYSCON_SYSCFG_SBOOT	(1<<8)
+#define EP93XX_SYSCON_SYSCFG_LCSN7	(1<<7)
+#define EP93XX_SYSCON_SYSCFG_LCSN6	(1<<6)
+#define EP93XX_SYSCON_SYSCFG_LASDO	(1<<5)
+#define EP93XX_SYSCON_SYSCFG_LEEDA	(1<<4)
+#define EP93XX_SYSCON_SYSCFG_LEECLK	(1<<3)
+#define EP93XX_SYSCON_SYSCFG_LCSN2	(1<<1)
+#define EP93XX_SYSCON_SYSCFG_LCSN1	(1<<0)
+#define EP93XX_SYSCON_SWLOCK		EP93XX_SYSCON_REG(0xc0)
+
+/* EP93xx System Controller software locked register write */
+void ep93xx_syscon_swlocked_write(unsigned int val, void __iomem *reg);
+void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits);
+
+static inline void ep93xx_devcfg_set_bits(unsigned int bits)
+{
+	ep93xx_devcfg_set_clear(bits, 0x00);
+}
+
+static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
+{
+	ep93xx_devcfg_set_clear(0x00, bits);
+}
+
+#endif /* _EP93XX_SOC_H */
diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
index 79f8ecf..5ea7909 100644
--- a/arch/arm/mach-ep93xx/ts72xx.c
+++ b/arch/arm/mach-ep93xx/ts72xx.c
@@ -28,6 +28,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
 
 static struct map_desc ts72xx_io_desc[] __initdata = {
 	{
diff --git a/arch/arm/mach-ep93xx/vision_ep9307.c b/arch/arm/mach-ep93xx/vision_ep9307.c
index d67d0b4..ba156eb 100644
--- a/arch/arm/mach-ep93xx/vision_ep9307.c
+++ b/arch/arm/mach-ep93xx/vision_ep9307.c
@@ -39,6 +39,8 @@
 #include <asm/mach/map.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
+
 /*************************************************************************
  * Static I/O mappings for the FPGA
  *************************************************************************/
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index dfad653..0491cee 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -11,18 +11,19 @@
 
 menu "SAMSUNG EXYNOS SoCs Support"
 
-choice
-	prompt "EXYNOS System Type"
-	default ARCH_EXYNOS4
-
 config ARCH_EXYNOS4
 	bool "SAMSUNG EXYNOS4"
+	default y
 	select HAVE_SMP
 	select MIGHT_HAVE_CACHE_L2X0
 	help
 	  Samsung EXYNOS4 SoCs based systems
 
-endchoice
+config ARCH_EXYNOS5
+	bool "SAMSUNG EXYNOS5"
+	select HAVE_SMP
+	help
+	  Samsung EXYNOS5 (Cortex-A15) SoC based systems
 
 comment "EXYNOS SoCs"
 
@@ -42,6 +43,7 @@
 	bool "SAMSUNG EXYNOS4212"
 	default y
 	depends on ARCH_EXYNOS4
+	select SAMSUNG_DMADEV
 	select S5P_PM if PM
 	select S5P_SLEEP if PM
 	help
@@ -51,9 +53,17 @@
 	bool "SAMSUNG EXYNOS4412"
 	default y
 	depends on ARCH_EXYNOS4
+	select SAMSUNG_DMADEV
 	help
 	  Enable EXYNOS4412 SoC support
 
+config SOC_EXYNOS5250
+	bool "SAMSUNG EXYNOS5250"
+	default y
+	depends on ARCH_EXYNOS5
+	help
+	  Enable EXYNOS5250 SoC support
+
 config EXYNOS4_MCT
 	bool
 	default y
@@ -179,7 +189,9 @@
 	select S5P_DEV_FIMC1
 	select S5P_DEV_FIMC2
 	select S5P_DEV_FIMC3
+	select S5P_DEV_G2D
 	select S5P_DEV_I2C_HDMIPHY
+	select S5P_DEV_JPEG
 	select S5P_DEV_MFC
 	select S5P_DEV_TV
 	select S5P_DEV_USB_EHCI
@@ -225,7 +237,9 @@
 	select S5P_DEV_FIMC1
 	select S5P_DEV_FIMC2
 	select S5P_DEV_FIMC3
+	select S5P_DEV_G2D
 	select S5P_DEV_CSIS0
+	select S5P_DEV_JPEG
 	select S5P_DEV_FIMD0
 	select S3C_DEV_HSMMC
 	select S3C_DEV_HSMMC2
@@ -262,11 +276,14 @@
 	select S3C_DEV_I2C1
 	select S3C_DEV_I2C3
 	select S3C_DEV_I2C5
+	select S3C_DEV_I2C6
 	select S5P_DEV_CSIS0
+	select S5P_DEV_JPEG
 	select S5P_DEV_FIMC0
 	select S5P_DEV_FIMC1
 	select S5P_DEV_FIMC2
 	select S5P_DEV_FIMC3
+	select S5P_DEV_G2D
 	select S5P_DEV_MFC
 	select S5P_DEV_USB_EHCI
 	select S5P_SETUP_MIPIPHY
@@ -276,6 +293,7 @@
 	select EXYNOS4_SETUP_I2C1
 	select EXYNOS4_SETUP_I2C3
 	select EXYNOS4_SETUP_I2C5
+	select EXYNOS4_SETUP_I2C6
 	select EXYNOS4_SETUP_SDHCI
 	select EXYNOS4_SETUP_USB_PHY
 	select S5P_SETUP_MIPIPHY
@@ -296,7 +314,9 @@
 	select S5P_DEV_FIMC2
 	select S5P_DEV_FIMC3
 	select S5P_DEV_FIMD0
+	select S5P_DEV_G2D
 	select S5P_DEV_I2C_HDMIPHY
+	select S5P_DEV_JPEG
 	select S5P_DEV_MFC
 	select S5P_DEV_TV
 	select S5P_DEV_USB_EHCI
@@ -325,6 +345,7 @@
 	select SAMSUNG_DEV_BACKLIGHT
 	select SAMSUNG_DEV_KEYPAD
 	select SAMSUNG_DEV_PWM
+	select EXYNOS4_DEV_DMA
 	select EXYNOS4_SETUP_I2C1
 	select EXYNOS4_SETUP_I2C3
 	select EXYNOS4_SETUP_I2C7
@@ -343,7 +364,7 @@
 	  Machine support for Samsung SMDK4412
 endif
 
-comment "Flattened Device Tree based board for Exynos4 based SoC"
+comment "Flattened Device Tree based board for EXYNOS SoCs"
 
 config MACH_EXYNOS4_DT
 	bool "Samsung Exynos4 Machine using device tree"
@@ -357,6 +378,15 @@
 	  Note: This is under development and not all peripherals can be supported
 	  with this machine file.
 
+config MACH_EXYNOS5_DT
+	bool "SAMSUNG EXYNOS5 Machine using device tree"
+	select SOC_EXYNOS5250
+	select USE_OF
+	select ARM_AMBA
+	help
+	  Machine support for Samsung Exynos4 machine with device tree enabled.
+	  Select this if a fdt blob is available for the EXYNOS4 SoC based board.
+
 if ARCH_EXYNOS4
 
 comment "Configuration for HSMMC 8-bit bus width"
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index d9191f9..8631840 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -12,7 +12,9 @@
 
 # Core
 
-obj-$(CONFIG_ARCH_EXYNOS4)	+= common.o clock.o
+obj-$(CONFIG_ARCH_EXYNOS)	+= common.o
+obj-$(CONFIG_ARCH_EXYNOS4)	+= clock-exynos4.o
+obj-$(CONFIG_ARCH_EXYNOS5)	+= clock-exynos5.o
 obj-$(CONFIG_CPU_EXYNOS4210)	+= clock-exynos4210.o
 obj-$(CONFIG_SOC_EXYNOS4212)	+= clock-exynos4212.o
 
@@ -41,9 +43,11 @@
 obj-$(CONFIG_MACH_SMDK4412)		+= mach-smdk4x12.o
 
 obj-$(CONFIG_MACH_EXYNOS4_DT)		+= mach-exynos4-dt.o
+obj-$(CONFIG_MACH_EXYNOS5_DT)		+= mach-exynos5-dt.o
 
 # device support
 
+obj-y					+= dev-uart.o
 obj-$(CONFIG_ARCH_EXYNOS4)		+= dev-audio.o
 obj-$(CONFIG_EXYNOS4_DEV_AHCI)		+= dev-ahci.o
 obj-$(CONFIG_EXYNOS4_DEV_SYSMMU)	+= dev-sysmmu.o
@@ -51,7 +55,7 @@
 obj-$(CONFIG_EXYNOS4_DEV_DMA)		+= dma.o
 obj-$(CONFIG_EXYNOS4_DEV_USB_OHCI)	+= dev-ohci.o
 
-obj-$(CONFIG_ARCH_EXYNOS4)		+= setup-i2c0.o
+obj-$(CONFIG_ARCH_EXYNOS)		+= setup-i2c0.o
 obj-$(CONFIG_EXYNOS4_SETUP_FIMC)	+= setup-fimc.o
 obj-$(CONFIG_EXYNOS4_SETUP_FIMD0)	+= setup-fimd0.o
 obj-$(CONFIG_EXYNOS4_SETUP_I2C1)	+= setup-i2c1.o
diff --git a/arch/arm/mach-exynos/clock-exynos4.c b/arch/arm/mach-exynos/clock-exynos4.c
new file mode 100644
index 0000000..df54c2a
--- /dev/null
+++ b/arch/arm/mach-exynos/clock-exynos4.c
@@ -0,0 +1,1581 @@
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * EXYNOS4 - Clock support
+ *
+ * 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/err.h>
+#include <linux/io.h>
+#include <linux/syscore_ops.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/pll.h>
+#include <plat/s5p-clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/pm.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/sysmmu.h>
+
+#include "common.h"
+#include "clock-exynos4.h"
+
+#ifdef CONFIG_PM_SLEEP
+static struct sleep_save exynos4_clock_save[] = {
+	SAVE_ITEM(EXYNOS4_CLKDIV_LEFTBUS),
+	SAVE_ITEM(EXYNOS4_CLKGATE_IP_LEFTBUS),
+	SAVE_ITEM(EXYNOS4_CLKDIV_RIGHTBUS),
+	SAVE_ITEM(EXYNOS4_CLKGATE_IP_RIGHTBUS),
+	SAVE_ITEM(EXYNOS4_CLKSRC_TOP0),
+	SAVE_ITEM(EXYNOS4_CLKSRC_TOP1),
+	SAVE_ITEM(EXYNOS4_CLKSRC_CAM),
+	SAVE_ITEM(EXYNOS4_CLKSRC_TV),
+	SAVE_ITEM(EXYNOS4_CLKSRC_MFC),
+	SAVE_ITEM(EXYNOS4_CLKSRC_G3D),
+	SAVE_ITEM(EXYNOS4_CLKSRC_LCD0),
+	SAVE_ITEM(EXYNOS4_CLKSRC_MAUDIO),
+	SAVE_ITEM(EXYNOS4_CLKSRC_FSYS),
+	SAVE_ITEM(EXYNOS4_CLKSRC_PERIL0),
+	SAVE_ITEM(EXYNOS4_CLKSRC_PERIL1),
+	SAVE_ITEM(EXYNOS4_CLKDIV_CAM),
+	SAVE_ITEM(EXYNOS4_CLKDIV_TV),
+	SAVE_ITEM(EXYNOS4_CLKDIV_MFC),
+	SAVE_ITEM(EXYNOS4_CLKDIV_G3D),
+	SAVE_ITEM(EXYNOS4_CLKDIV_LCD0),
+	SAVE_ITEM(EXYNOS4_CLKDIV_MAUDIO),
+	SAVE_ITEM(EXYNOS4_CLKDIV_FSYS0),
+	SAVE_ITEM(EXYNOS4_CLKDIV_FSYS1),
+	SAVE_ITEM(EXYNOS4_CLKDIV_FSYS2),
+	SAVE_ITEM(EXYNOS4_CLKDIV_FSYS3),
+	SAVE_ITEM(EXYNOS4_CLKDIV_PERIL0),
+	SAVE_ITEM(EXYNOS4_CLKDIV_PERIL1),
+	SAVE_ITEM(EXYNOS4_CLKDIV_PERIL2),
+	SAVE_ITEM(EXYNOS4_CLKDIV_PERIL3),
+	SAVE_ITEM(EXYNOS4_CLKDIV_PERIL4),
+	SAVE_ITEM(EXYNOS4_CLKDIV_PERIL5),
+	SAVE_ITEM(EXYNOS4_CLKDIV_TOP),
+	SAVE_ITEM(EXYNOS4_CLKSRC_MASK_TOP),
+	SAVE_ITEM(EXYNOS4_CLKSRC_MASK_CAM),
+	SAVE_ITEM(EXYNOS4_CLKSRC_MASK_TV),
+	SAVE_ITEM(EXYNOS4_CLKSRC_MASK_LCD0),
+	SAVE_ITEM(EXYNOS4_CLKSRC_MASK_MAUDIO),
+	SAVE_ITEM(EXYNOS4_CLKSRC_MASK_FSYS),
+	SAVE_ITEM(EXYNOS4_CLKSRC_MASK_PERIL0),
+	SAVE_ITEM(EXYNOS4_CLKSRC_MASK_PERIL1),
+	SAVE_ITEM(EXYNOS4_CLKDIV2_RATIO),
+	SAVE_ITEM(EXYNOS4_CLKGATE_SCLKCAM),
+	SAVE_ITEM(EXYNOS4_CLKGATE_IP_CAM),
+	SAVE_ITEM(EXYNOS4_CLKGATE_IP_TV),
+	SAVE_ITEM(EXYNOS4_CLKGATE_IP_MFC),
+	SAVE_ITEM(EXYNOS4_CLKGATE_IP_G3D),
+	SAVE_ITEM(EXYNOS4_CLKGATE_IP_LCD0),
+	SAVE_ITEM(EXYNOS4_CLKGATE_IP_FSYS),
+	SAVE_ITEM(EXYNOS4_CLKGATE_IP_GPS),
+	SAVE_ITEM(EXYNOS4_CLKGATE_IP_PERIL),
+	SAVE_ITEM(EXYNOS4_CLKGATE_BLOCK),
+	SAVE_ITEM(EXYNOS4_CLKSRC_MASK_DMC),
+	SAVE_ITEM(EXYNOS4_CLKSRC_DMC),
+	SAVE_ITEM(EXYNOS4_CLKDIV_DMC0),
+	SAVE_ITEM(EXYNOS4_CLKDIV_DMC1),
+	SAVE_ITEM(EXYNOS4_CLKGATE_IP_DMC),
+	SAVE_ITEM(EXYNOS4_CLKSRC_CPU),
+	SAVE_ITEM(EXYNOS4_CLKDIV_CPU),
+	SAVE_ITEM(EXYNOS4_CLKDIV_CPU + 0x4),
+	SAVE_ITEM(EXYNOS4_CLKGATE_SCLKCPU),
+	SAVE_ITEM(EXYNOS4_CLKGATE_IP_CPU),
+};
+#endif
+
+static struct clk exynos4_clk_sclk_hdmi27m = {
+	.name		= "sclk_hdmi27m",
+	.rate		= 27000000,
+};
+
+static struct clk exynos4_clk_sclk_hdmiphy = {
+	.name		= "sclk_hdmiphy",
+};
+
+static struct clk exynos4_clk_sclk_usbphy0 = {
+	.name		= "sclk_usbphy0",
+	.rate		= 27000000,
+};
+
+static struct clk exynos4_clk_sclk_usbphy1 = {
+	.name		= "sclk_usbphy1",
+};
+
+static struct clk dummy_apb_pclk = {
+	.name		= "apb_pclk",
+	.id		= -1,
+};
+
+static int exynos4_clksrc_mask_top_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_TOP, clk, enable);
+}
+
+static int exynos4_clksrc_mask_cam_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_CAM, clk, enable);
+}
+
+static int exynos4_clksrc_mask_lcd0_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_LCD0, clk, enable);
+}
+
+int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_FSYS, clk, enable);
+}
+
+static int exynos4_clksrc_mask_peril0_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_PERIL0, clk, enable);
+}
+
+static int exynos4_clksrc_mask_peril1_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_PERIL1, clk, enable);
+}
+
+static int exynos4_clk_ip_mfc_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4_CLKGATE_IP_MFC, clk, enable);
+}
+
+static int exynos4_clksrc_mask_tv_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_TV, clk, enable);
+}
+
+static int exynos4_clk_ip_cam_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4_CLKGATE_IP_CAM, clk, enable);
+}
+
+static int exynos4_clk_ip_tv_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4_CLKGATE_IP_TV, clk, enable);
+}
+
+static int exynos4_clk_ip_image_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4_CLKGATE_IP_IMAGE, clk, enable);
+}
+
+static int exynos4_clk_ip_lcd0_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4_CLKGATE_IP_LCD0, clk, enable);
+}
+
+int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4210_CLKGATE_IP_LCD1, clk, enable);
+}
+
+int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4_CLKGATE_IP_FSYS, clk, enable);
+}
+
+static int exynos4_clk_ip_peril_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4_CLKGATE_IP_PERIL, clk, enable);
+}
+
+static int exynos4_clk_ip_perir_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS4_CLKGATE_IP_PERIR, clk, enable);
+}
+
+static int exynos4_clk_hdmiphy_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_HDMI_PHY_CONTROL, clk, enable);
+}
+
+static int exynos4_clk_dac_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_DAC_PHY_CONTROL, clk, enable);
+}
+
+/* Core list of CMU_CPU side */
+
+static struct clksrc_clk exynos4_clk_mout_apll = {
+	.clk	= {
+		.name		= "mout_apll",
+	},
+	.sources = &clk_src_apll,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_CPU, .shift = 0, .size = 1 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_apll = {
+	.clk	= {
+		.name		= "sclk_apll",
+		.parent		= &exynos4_clk_mout_apll.clk,
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 24, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_mout_epll = {
+	.clk	= {
+		.name		= "mout_epll",
+	},
+	.sources = &clk_src_epll,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 4, .size = 1 },
+};
+
+struct clksrc_clk exynos4_clk_mout_mpll = {
+	.clk	= {
+		.name		= "mout_mpll",
+	},
+	.sources = &clk_src_mpll,
+
+	/* reg_src will be added in each SoCs' clock */
+};
+
+static struct clk *exynos4_clkset_moutcore_list[] = {
+	[0] = &exynos4_clk_mout_apll.clk,
+	[1] = &exynos4_clk_mout_mpll.clk,
+};
+
+static struct clksrc_sources exynos4_clkset_moutcore = {
+	.sources	= exynos4_clkset_moutcore_list,
+	.nr_sources	= ARRAY_SIZE(exynos4_clkset_moutcore_list),
+};
+
+static struct clksrc_clk exynos4_clk_moutcore = {
+	.clk	= {
+		.name		= "moutcore",
+	},
+	.sources = &exynos4_clkset_moutcore,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_CPU, .shift = 16, .size = 1 },
+};
+
+static struct clksrc_clk exynos4_clk_coreclk = {
+	.clk	= {
+		.name		= "core_clk",
+		.parent		= &exynos4_clk_moutcore.clk,
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 0, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_armclk = {
+	.clk	= {
+		.name		= "armclk",
+		.parent		= &exynos4_clk_coreclk.clk,
+	},
+};
+
+static struct clksrc_clk exynos4_clk_aclk_corem0 = {
+	.clk	= {
+		.name		= "aclk_corem0",
+		.parent		= &exynos4_clk_coreclk.clk,
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 4, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_aclk_cores = {
+	.clk	= {
+		.name		= "aclk_cores",
+		.parent		= &exynos4_clk_coreclk.clk,
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 4, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_aclk_corem1 = {
+	.clk	= {
+		.name		= "aclk_corem1",
+		.parent		= &exynos4_clk_coreclk.clk,
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 8, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_periphclk = {
+	.clk	= {
+		.name		= "periphclk",
+		.parent		= &exynos4_clk_coreclk.clk,
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 12, .size = 3 },
+};
+
+/* Core list of CMU_CORE side */
+
+static struct clk *exynos4_clkset_corebus_list[] = {
+	[0] = &exynos4_clk_mout_mpll.clk,
+	[1] = &exynos4_clk_sclk_apll.clk,
+};
+
+struct clksrc_sources exynos4_clkset_mout_corebus = {
+	.sources	= exynos4_clkset_corebus_list,
+	.nr_sources	= ARRAY_SIZE(exynos4_clkset_corebus_list),
+};
+
+static struct clksrc_clk exynos4_clk_mout_corebus = {
+	.clk	= {
+		.name		= "mout_corebus",
+	},
+	.sources = &exynos4_clkset_mout_corebus,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_DMC, .shift = 4, .size = 1 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_dmc = {
+	.clk	= {
+		.name		= "sclk_dmc",
+		.parent		= &exynos4_clk_mout_corebus.clk,
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_DMC0, .shift = 12, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_aclk_cored = {
+	.clk	= {
+		.name		= "aclk_cored",
+		.parent		= &exynos4_clk_sclk_dmc.clk,
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_DMC0, .shift = 16, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_aclk_corep = {
+	.clk	= {
+		.name		= "aclk_corep",
+		.parent		= &exynos4_clk_aclk_cored.clk,
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_DMC0, .shift = 20, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_aclk_acp = {
+	.clk	= {
+		.name		= "aclk_acp",
+		.parent		= &exynos4_clk_mout_corebus.clk,
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_DMC0, .shift = 0, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_pclk_acp = {
+	.clk	= {
+		.name		= "pclk_acp",
+		.parent		= &exynos4_clk_aclk_acp.clk,
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_DMC0, .shift = 4, .size = 3 },
+};
+
+/* Core list of CMU_TOP side */
+
+struct clk *exynos4_clkset_aclk_top_list[] = {
+	[0] = &exynos4_clk_mout_mpll.clk,
+	[1] = &exynos4_clk_sclk_apll.clk,
+};
+
+static struct clksrc_sources exynos4_clkset_aclk = {
+	.sources	= exynos4_clkset_aclk_top_list,
+	.nr_sources	= ARRAY_SIZE(exynos4_clkset_aclk_top_list),
+};
+
+static struct clksrc_clk exynos4_clk_aclk_200 = {
+	.clk	= {
+		.name		= "aclk_200",
+	},
+	.sources = &exynos4_clkset_aclk,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 12, .size = 1 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_TOP, .shift = 0, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_aclk_100 = {
+	.clk	= {
+		.name		= "aclk_100",
+	},
+	.sources = &exynos4_clkset_aclk,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 16, .size = 1 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_TOP, .shift = 4, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_aclk_160 = {
+	.clk	= {
+		.name		= "aclk_160",
+	},
+	.sources = &exynos4_clkset_aclk,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 20, .size = 1 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_TOP, .shift = 8, .size = 3 },
+};
+
+struct clksrc_clk exynos4_clk_aclk_133 = {
+	.clk	= {
+		.name		= "aclk_133",
+	},
+	.sources = &exynos4_clkset_aclk,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 24, .size = 1 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_TOP, .shift = 12, .size = 3 },
+};
+
+static struct clk *exynos4_clkset_vpllsrc_list[] = {
+	[0] = &clk_fin_vpll,
+	[1] = &exynos4_clk_sclk_hdmi27m,
+};
+
+static struct clksrc_sources exynos4_clkset_vpllsrc = {
+	.sources	= exynos4_clkset_vpllsrc_list,
+	.nr_sources	= ARRAY_SIZE(exynos4_clkset_vpllsrc_list),
+};
+
+static struct clksrc_clk exynos4_clk_vpllsrc = {
+	.clk	= {
+		.name		= "vpll_src",
+		.enable		= exynos4_clksrc_mask_top_ctrl,
+		.ctrlbit	= (1 << 0),
+	},
+	.sources = &exynos4_clkset_vpllsrc,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_TOP1, .shift = 0, .size = 1 },
+};
+
+static struct clk *exynos4_clkset_sclk_vpll_list[] = {
+	[0] = &exynos4_clk_vpllsrc.clk,
+	[1] = &clk_fout_vpll,
+};
+
+static struct clksrc_sources exynos4_clkset_sclk_vpll = {
+	.sources	= exynos4_clkset_sclk_vpll_list,
+	.nr_sources	= ARRAY_SIZE(exynos4_clkset_sclk_vpll_list),
+};
+
+static struct clksrc_clk exynos4_clk_sclk_vpll = {
+	.clk	= {
+		.name		= "sclk_vpll",
+	},
+	.sources = &exynos4_clkset_sclk_vpll,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 8, .size = 1 },
+};
+
+static struct clk exynos4_init_clocks_off[] = {
+	{
+		.name		= "timers",
+		.parent		= &exynos4_clk_aclk_100.clk,
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1<<24),
+	}, {
+		.name		= "csis",
+		.devname	= "s5p-mipi-csis.0",
+		.enable		= exynos4_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 4),
+	}, {
+		.name		= "csis",
+		.devname	= "s5p-mipi-csis.1",
+		.enable		= exynos4_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 5),
+	}, {
+		.name		= "jpeg",
+		.id		= 0,
+		.enable		= exynos4_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 6),
+	}, {
+		.name		= "fimc",
+		.devname	= "exynos4-fimc.0",
+		.enable		= exynos4_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 0),
+	}, {
+		.name		= "fimc",
+		.devname	= "exynos4-fimc.1",
+		.enable		= exynos4_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 1),
+	}, {
+		.name		= "fimc",
+		.devname	= "exynos4-fimc.2",
+		.enable		= exynos4_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 2),
+	}, {
+		.name		= "fimc",
+		.devname	= "exynos4-fimc.3",
+		.enable		= exynos4_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 3),
+	}, {
+		.name		= "hsmmc",
+		.devname	= "s3c-sdhci.0",
+		.parent		= &exynos4_clk_aclk_133.clk,
+		.enable		= exynos4_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 5),
+	}, {
+		.name		= "hsmmc",
+		.devname	= "s3c-sdhci.1",
+		.parent		= &exynos4_clk_aclk_133.clk,
+		.enable		= exynos4_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 6),
+	}, {
+		.name		= "hsmmc",
+		.devname	= "s3c-sdhci.2",
+		.parent		= &exynos4_clk_aclk_133.clk,
+		.enable		= exynos4_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 7),
+	}, {
+		.name		= "hsmmc",
+		.devname	= "s3c-sdhci.3",
+		.parent		= &exynos4_clk_aclk_133.clk,
+		.enable		= exynos4_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 8),
+	}, {
+		.name		= "dwmmc",
+		.parent		= &exynos4_clk_aclk_133.clk,
+		.enable		= exynos4_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 9),
+	}, {
+		.name		= "dac",
+		.devname	= "s5p-sdo",
+		.enable		= exynos4_clk_ip_tv_ctrl,
+		.ctrlbit	= (1 << 2),
+	}, {
+		.name		= "mixer",
+		.devname	= "s5p-mixer",
+		.enable		= exynos4_clk_ip_tv_ctrl,
+		.ctrlbit	= (1 << 1),
+	}, {
+		.name		= "vp",
+		.devname	= "s5p-mixer",
+		.enable		= exynos4_clk_ip_tv_ctrl,
+		.ctrlbit	= (1 << 0),
+	}, {
+		.name		= "hdmi",
+		.devname	= "exynos4-hdmi",
+		.enable		= exynos4_clk_ip_tv_ctrl,
+		.ctrlbit	= (1 << 3),
+	}, {
+		.name		= "hdmiphy",
+		.devname	= "exynos4-hdmi",
+		.enable		= exynos4_clk_hdmiphy_ctrl,
+		.ctrlbit	= (1 << 0),
+	}, {
+		.name		= "dacphy",
+		.devname	= "s5p-sdo",
+		.enable		= exynos4_clk_dac_ctrl,
+		.ctrlbit	= (1 << 0),
+	}, {
+		.name		= "adc",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 15),
+	}, {
+		.name		= "keypad",
+		.enable		= exynos4_clk_ip_perir_ctrl,
+		.ctrlbit	= (1 << 16),
+	}, {
+		.name		= "rtc",
+		.enable		= exynos4_clk_ip_perir_ctrl,
+		.ctrlbit	= (1 << 15),
+	}, {
+		.name		= "watchdog",
+		.parent		= &exynos4_clk_aclk_100.clk,
+		.enable		= exynos4_clk_ip_perir_ctrl,
+		.ctrlbit	= (1 << 14),
+	}, {
+		.name		= "usbhost",
+		.enable		= exynos4_clk_ip_fsys_ctrl ,
+		.ctrlbit	= (1 << 12),
+	}, {
+		.name		= "otg",
+		.enable		= exynos4_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 13),
+	}, {
+		.name		= "spi",
+		.devname	= "s3c64xx-spi.0",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 16),
+	}, {
+		.name		= "spi",
+		.devname	= "s3c64xx-spi.1",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 17),
+	}, {
+		.name		= "spi",
+		.devname	= "s3c64xx-spi.2",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 18),
+	}, {
+		.name		= "iis",
+		.devname	= "samsung-i2s.0",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 19),
+	}, {
+		.name		= "iis",
+		.devname	= "samsung-i2s.1",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 20),
+	}, {
+		.name		= "iis",
+		.devname	= "samsung-i2s.2",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 21),
+	}, {
+		.name		= "ac97",
+		.devname	= "samsung-ac97",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 27),
+	}, {
+		.name		= "fimg2d",
+		.enable		= exynos4_clk_ip_image_ctrl,
+		.ctrlbit	= (1 << 0),
+	}, {
+		.name		= "mfc",
+		.devname	= "s5p-mfc",
+		.enable		= exynos4_clk_ip_mfc_ctrl,
+		.ctrlbit	= (1 << 0),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.0",
+		.parent		= &exynos4_clk_aclk_100.clk,
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 6),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.1",
+		.parent		= &exynos4_clk_aclk_100.clk,
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 7),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.2",
+		.parent		= &exynos4_clk_aclk_100.clk,
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 8),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.3",
+		.parent		= &exynos4_clk_aclk_100.clk,
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 9),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.4",
+		.parent		= &exynos4_clk_aclk_100.clk,
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 10),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.5",
+		.parent		= &exynos4_clk_aclk_100.clk,
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 11),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.6",
+		.parent		= &exynos4_clk_aclk_100.clk,
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 12),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.7",
+		.parent		= &exynos4_clk_aclk_100.clk,
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 13),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-hdmiphy-i2c",
+		.parent		= &exynos4_clk_aclk_100.clk,
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 14),
+	}, {
+		.name		= "SYSMMU_MDMA",
+		.enable		= exynos4_clk_ip_image_ctrl,
+		.ctrlbit	= (1 << 5),
+	}, {
+		.name		= "SYSMMU_FIMC0",
+		.enable		= exynos4_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 7),
+	}, {
+		.name		= "SYSMMU_FIMC1",
+		.enable		= exynos4_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 8),
+	}, {
+		.name		= "SYSMMU_FIMC2",
+		.enable		= exynos4_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 9),
+	}, {
+		.name		= "SYSMMU_FIMC3",
+		.enable		= exynos4_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 10),
+	}, {
+		.name		= "SYSMMU_JPEG",
+		.enable		= exynos4_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 11),
+	}, {
+		.name		= "SYSMMU_FIMD0",
+		.enable		= exynos4_clk_ip_lcd0_ctrl,
+		.ctrlbit	= (1 << 4),
+	}, {
+		.name		= "SYSMMU_FIMD1",
+		.enable		= exynos4_clk_ip_lcd1_ctrl,
+		.ctrlbit	= (1 << 4),
+	}, {
+		.name		= "SYSMMU_PCIe",
+		.enable		= exynos4_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 18),
+	}, {
+		.name		= "SYSMMU_G2D",
+		.enable		= exynos4_clk_ip_image_ctrl,
+		.ctrlbit	= (1 << 3),
+	}, {
+		.name		= "SYSMMU_ROTATOR",
+		.enable		= exynos4_clk_ip_image_ctrl,
+		.ctrlbit	= (1 << 4),
+	}, {
+		.name		= "SYSMMU_TV",
+		.enable		= exynos4_clk_ip_tv_ctrl,
+		.ctrlbit	= (1 << 4),
+	}, {
+		.name		= "SYSMMU_MFC_L",
+		.enable		= exynos4_clk_ip_mfc_ctrl,
+		.ctrlbit	= (1 << 1),
+	}, {
+		.name		= "SYSMMU_MFC_R",
+		.enable		= exynos4_clk_ip_mfc_ctrl,
+		.ctrlbit	= (1 << 2),
+	}
+};
+
+static struct clk exynos4_init_clocks_on[] = {
+	{
+		.name		= "uart",
+		.devname	= "s5pv210-uart.0",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 0),
+	}, {
+		.name		= "uart",
+		.devname	= "s5pv210-uart.1",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 1),
+	}, {
+		.name		= "uart",
+		.devname	= "s5pv210-uart.2",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 2),
+	}, {
+		.name		= "uart",
+		.devname	= "s5pv210-uart.3",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 3),
+	}, {
+		.name		= "uart",
+		.devname	= "s5pv210-uart.4",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 4),
+	}, {
+		.name		= "uart",
+		.devname	= "s5pv210-uart.5",
+		.enable		= exynos4_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 5),
+	}
+};
+
+static struct clk exynos4_clk_pdma0 = {
+	.name		= "dma",
+	.devname	= "dma-pl330.0",
+	.enable		= exynos4_clk_ip_fsys_ctrl,
+	.ctrlbit	= (1 << 0),
+};
+
+static struct clk exynos4_clk_pdma1 = {
+	.name		= "dma",
+	.devname	= "dma-pl330.1",
+	.enable		= exynos4_clk_ip_fsys_ctrl,
+	.ctrlbit	= (1 << 1),
+};
+
+static struct clk exynos4_clk_mdma1 = {
+	.name		= "dma",
+	.devname	= "dma-pl330.2",
+	.enable		= exynos4_clk_ip_image_ctrl,
+	.ctrlbit	= ((1 << 8) | (1 << 5) | (1 << 2)),
+};
+
+static struct clk exynos4_clk_fimd0 = {
+	.name		= "fimd",
+	.devname	= "exynos4-fb.0",
+	.enable		= exynos4_clk_ip_lcd0_ctrl,
+	.ctrlbit	= (1 << 0),
+};
+
+struct clk *exynos4_clkset_group_list[] = {
+	[0] = &clk_ext_xtal_mux,
+	[1] = &clk_xusbxti,
+	[2] = &exynos4_clk_sclk_hdmi27m,
+	[3] = &exynos4_clk_sclk_usbphy0,
+	[4] = &exynos4_clk_sclk_usbphy1,
+	[5] = &exynos4_clk_sclk_hdmiphy,
+	[6] = &exynos4_clk_mout_mpll.clk,
+	[7] = &exynos4_clk_mout_epll.clk,
+	[8] = &exynos4_clk_sclk_vpll.clk,
+};
+
+struct clksrc_sources exynos4_clkset_group = {
+	.sources	= exynos4_clkset_group_list,
+	.nr_sources	= ARRAY_SIZE(exynos4_clkset_group_list),
+};
+
+static struct clk *exynos4_clkset_mout_g2d0_list[] = {
+	[0] = &exynos4_clk_mout_mpll.clk,
+	[1] = &exynos4_clk_sclk_apll.clk,
+};
+
+static struct clksrc_sources exynos4_clkset_mout_g2d0 = {
+	.sources	= exynos4_clkset_mout_g2d0_list,
+	.nr_sources	= ARRAY_SIZE(exynos4_clkset_mout_g2d0_list),
+};
+
+static struct clksrc_clk exynos4_clk_mout_g2d0 = {
+	.clk	= {
+		.name		= "mout_g2d0",
+	},
+	.sources = &exynos4_clkset_mout_g2d0,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 0, .size = 1 },
+};
+
+static struct clk *exynos4_clkset_mout_g2d1_list[] = {
+	[0] = &exynos4_clk_mout_epll.clk,
+	[1] = &exynos4_clk_sclk_vpll.clk,
+};
+
+static struct clksrc_sources exynos4_clkset_mout_g2d1 = {
+	.sources	= exynos4_clkset_mout_g2d1_list,
+	.nr_sources	= ARRAY_SIZE(exynos4_clkset_mout_g2d1_list),
+};
+
+static struct clksrc_clk exynos4_clk_mout_g2d1 = {
+	.clk	= {
+		.name		= "mout_g2d1",
+	},
+	.sources = &exynos4_clkset_mout_g2d1,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 4, .size = 1 },
+};
+
+static struct clk *exynos4_clkset_mout_g2d_list[] = {
+	[0] = &exynos4_clk_mout_g2d0.clk,
+	[1] = &exynos4_clk_mout_g2d1.clk,
+};
+
+static struct clksrc_sources exynos4_clkset_mout_g2d = {
+	.sources	= exynos4_clkset_mout_g2d_list,
+	.nr_sources	= ARRAY_SIZE(exynos4_clkset_mout_g2d_list),
+};
+
+static struct clk *exynos4_clkset_mout_mfc0_list[] = {
+	[0] = &exynos4_clk_mout_mpll.clk,
+	[1] = &exynos4_clk_sclk_apll.clk,
+};
+
+static struct clksrc_sources exynos4_clkset_mout_mfc0 = {
+	.sources	= exynos4_clkset_mout_mfc0_list,
+	.nr_sources	= ARRAY_SIZE(exynos4_clkset_mout_mfc0_list),
+};
+
+static struct clksrc_clk exynos4_clk_mout_mfc0 = {
+	.clk	= {
+		.name		= "mout_mfc0",
+	},
+	.sources = &exynos4_clkset_mout_mfc0,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_MFC, .shift = 0, .size = 1 },
+};
+
+static struct clk *exynos4_clkset_mout_mfc1_list[] = {
+	[0] = &exynos4_clk_mout_epll.clk,
+	[1] = &exynos4_clk_sclk_vpll.clk,
+};
+
+static struct clksrc_sources exynos4_clkset_mout_mfc1 = {
+	.sources	= exynos4_clkset_mout_mfc1_list,
+	.nr_sources	= ARRAY_SIZE(exynos4_clkset_mout_mfc1_list),
+};
+
+static struct clksrc_clk exynos4_clk_mout_mfc1 = {
+	.clk	= {
+		.name		= "mout_mfc1",
+	},
+	.sources = &exynos4_clkset_mout_mfc1,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_MFC, .shift = 4, .size = 1 },
+};
+
+static struct clk *exynos4_clkset_mout_mfc_list[] = {
+	[0] = &exynos4_clk_mout_mfc0.clk,
+	[1] = &exynos4_clk_mout_mfc1.clk,
+};
+
+static struct clksrc_sources exynos4_clkset_mout_mfc = {
+	.sources	= exynos4_clkset_mout_mfc_list,
+	.nr_sources	= ARRAY_SIZE(exynos4_clkset_mout_mfc_list),
+};
+
+static struct clk *exynos4_clkset_sclk_dac_list[] = {
+	[0] = &exynos4_clk_sclk_vpll.clk,
+	[1] = &exynos4_clk_sclk_hdmiphy,
+};
+
+static struct clksrc_sources exynos4_clkset_sclk_dac = {
+	.sources	= exynos4_clkset_sclk_dac_list,
+	.nr_sources	= ARRAY_SIZE(exynos4_clkset_sclk_dac_list),
+};
+
+static struct clksrc_clk exynos4_clk_sclk_dac = {
+	.clk		= {
+		.name		= "sclk_dac",
+		.enable		= exynos4_clksrc_mask_tv_ctrl,
+		.ctrlbit	= (1 << 8),
+	},
+	.sources = &exynos4_clkset_sclk_dac,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_TV, .shift = 8, .size = 1 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_pixel = {
+	.clk		= {
+		.name		= "sclk_pixel",
+		.parent		= &exynos4_clk_sclk_vpll.clk,
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_TV, .shift = 0, .size = 4 },
+};
+
+static struct clk *exynos4_clkset_sclk_hdmi_list[] = {
+	[0] = &exynos4_clk_sclk_pixel.clk,
+	[1] = &exynos4_clk_sclk_hdmiphy,
+};
+
+static struct clksrc_sources exynos4_clkset_sclk_hdmi = {
+	.sources	= exynos4_clkset_sclk_hdmi_list,
+	.nr_sources	= ARRAY_SIZE(exynos4_clkset_sclk_hdmi_list),
+};
+
+static struct clksrc_clk exynos4_clk_sclk_hdmi = {
+	.clk		= {
+		.name		= "sclk_hdmi",
+		.enable		= exynos4_clksrc_mask_tv_ctrl,
+		.ctrlbit	= (1 << 0),
+	},
+	.sources = &exynos4_clkset_sclk_hdmi,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_TV, .shift = 0, .size = 1 },
+};
+
+static struct clk *exynos4_clkset_sclk_mixer_list[] = {
+	[0] = &exynos4_clk_sclk_dac.clk,
+	[1] = &exynos4_clk_sclk_hdmi.clk,
+};
+
+static struct clksrc_sources exynos4_clkset_sclk_mixer = {
+	.sources	= exynos4_clkset_sclk_mixer_list,
+	.nr_sources	= ARRAY_SIZE(exynos4_clkset_sclk_mixer_list),
+};
+
+static struct clksrc_clk exynos4_clk_sclk_mixer = {
+	.clk	= {
+		.name		= "sclk_mixer",
+		.enable		= exynos4_clksrc_mask_tv_ctrl,
+		.ctrlbit	= (1 << 4),
+	},
+	.sources = &exynos4_clkset_sclk_mixer,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_TV, .shift = 4, .size = 1 },
+};
+
+static struct clksrc_clk *exynos4_sclk_tv[] = {
+	&exynos4_clk_sclk_dac,
+	&exynos4_clk_sclk_pixel,
+	&exynos4_clk_sclk_hdmi,
+	&exynos4_clk_sclk_mixer,
+};
+
+static struct clksrc_clk exynos4_clk_dout_mmc0 = {
+	.clk	= {
+		.name		= "dout_mmc0",
+	},
+	.sources = &exynos4_clkset_group,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 0, .size = 4 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_FSYS1, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_dout_mmc1 = {
+	.clk	= {
+		.name		= "dout_mmc1",
+	},
+	.sources = &exynos4_clkset_group,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 4, .size = 4 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_FSYS1, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_dout_mmc2 = {
+	.clk	= {
+		.name		= "dout_mmc2",
+	},
+	.sources = &exynos4_clkset_group,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 8, .size = 4 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_FSYS2, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_dout_mmc3 = {
+	.clk	= {
+		.name		= "dout_mmc3",
+	},
+	.sources = &exynos4_clkset_group,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 12, .size = 4 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_FSYS2, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_dout_mmc4 = {
+	.clk		= {
+		.name		= "dout_mmc4",
+	},
+	.sources = &exynos4_clkset_group,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 16, .size = 4 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_FSYS3, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clksrcs[] = {
+	{
+		.clk	= {
+			.name		= "sclk_pwm",
+			.enable		= exynos4_clksrc_mask_peril0_ctrl,
+			.ctrlbit	= (1 << 24),
+		},
+		.sources = &exynos4_clkset_group,
+		.reg_src = { .reg = EXYNOS4_CLKSRC_PERIL0, .shift = 24, .size = 4 },
+		.reg_div = { .reg = EXYNOS4_CLKDIV_PERIL3, .shift = 0, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_csis",
+			.devname	= "s5p-mipi-csis.0",
+			.enable		= exynos4_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 24),
+		},
+		.sources = &exynos4_clkset_group,
+		.reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 24, .size = 4 },
+		.reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 24, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_csis",
+			.devname	= "s5p-mipi-csis.1",
+			.enable		= exynos4_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 28),
+		},
+		.sources = &exynos4_clkset_group,
+		.reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 28, .size = 4 },
+		.reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 28, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_cam0",
+			.enable		= exynos4_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 16),
+		},
+		.sources = &exynos4_clkset_group,
+		.reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 16, .size = 4 },
+		.reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 16, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_cam1",
+			.enable		= exynos4_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 20),
+		},
+		.sources = &exynos4_clkset_group,
+		.reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 20, .size = 4 },
+		.reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 20, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_fimc",
+			.devname	= "exynos4-fimc.0",
+			.enable		= exynos4_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 0),
+		},
+		.sources = &exynos4_clkset_group,
+		.reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 0, .size = 4 },
+		.reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 0, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_fimc",
+			.devname	= "exynos4-fimc.1",
+			.enable		= exynos4_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 4),
+		},
+		.sources = &exynos4_clkset_group,
+		.reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 4, .size = 4 },
+		.reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 4, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_fimc",
+			.devname	= "exynos4-fimc.2",
+			.enable		= exynos4_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 8),
+		},
+		.sources = &exynos4_clkset_group,
+		.reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 8, .size = 4 },
+		.reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 8, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_fimc",
+			.devname	= "exynos4-fimc.3",
+			.enable		= exynos4_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 12),
+		},
+		.sources = &exynos4_clkset_group,
+		.reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 12, .size = 4 },
+		.reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 12, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_fimd",
+			.devname	= "exynos4-fb.0",
+			.enable		= exynos4_clksrc_mask_lcd0_ctrl,
+			.ctrlbit	= (1 << 0),
+		},
+		.sources = &exynos4_clkset_group,
+		.reg_src = { .reg = EXYNOS4_CLKSRC_LCD0, .shift = 0, .size = 4 },
+		.reg_div = { .reg = EXYNOS4_CLKDIV_LCD0, .shift = 0, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_fimg2d",
+		},
+		.sources = &exynos4_clkset_mout_g2d,
+		.reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 8, .size = 1 },
+		.reg_div = { .reg = EXYNOS4_CLKDIV_IMAGE, .shift = 0, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_mfc",
+			.devname	= "s5p-mfc",
+		},
+		.sources = &exynos4_clkset_mout_mfc,
+		.reg_src = { .reg = EXYNOS4_CLKSRC_MFC, .shift = 8, .size = 1 },
+		.reg_div = { .reg = EXYNOS4_CLKDIV_MFC, .shift = 0, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_dwmmc",
+			.parent		= &exynos4_clk_dout_mmc4.clk,
+			.enable		= exynos4_clksrc_mask_fsys_ctrl,
+			.ctrlbit	= (1 << 16),
+		},
+		.reg_div = { .reg = EXYNOS4_CLKDIV_FSYS3, .shift = 8, .size = 8 },
+	}
+};
+
+static struct clksrc_clk exynos4_clk_sclk_uart0 = {
+	.clk	= {
+		.name		= "uclk1",
+		.devname	= "exynos4210-uart.0",
+		.enable		= exynos4_clksrc_mask_peril0_ctrl,
+		.ctrlbit	= (1 << 0),
+	},
+	.sources = &exynos4_clkset_group,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_PERIL0, .shift = 0, .size = 4 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_PERIL0, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_uart1 = {
+	.clk	= {
+		.name		= "uclk1",
+		.devname	= "exynos4210-uart.1",
+		.enable		= exynos4_clksrc_mask_peril0_ctrl,
+		.ctrlbit	= (1 << 4),
+	},
+	.sources = &exynos4_clkset_group,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_PERIL0, .shift = 4, .size = 4 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_PERIL0, .shift = 4, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_uart2 = {
+	.clk	= {
+		.name		= "uclk1",
+		.devname	= "exynos4210-uart.2",
+		.enable		= exynos4_clksrc_mask_peril0_ctrl,
+		.ctrlbit	= (1 << 8),
+	},
+	.sources = &exynos4_clkset_group,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_PERIL0, .shift = 8, .size = 4 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_PERIL0, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_uart3 = {
+	.clk	= {
+		.name		= "uclk1",
+		.devname	= "exynos4210-uart.3",
+		.enable		= exynos4_clksrc_mask_peril0_ctrl,
+		.ctrlbit	= (1 << 12),
+	},
+	.sources = &exynos4_clkset_group,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_PERIL0, .shift = 12, .size = 4 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_PERIL0, .shift = 12, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_mmc0 = {
+	.clk	= {
+		.name		= "sclk_mmc",
+		.devname	= "s3c-sdhci.0",
+		.parent		= &exynos4_clk_dout_mmc0.clk,
+		.enable		= exynos4_clksrc_mask_fsys_ctrl,
+		.ctrlbit	= (1 << 0),
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_FSYS1, .shift = 8, .size = 8 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_mmc1 = {
+	.clk	= {
+		.name		= "sclk_mmc",
+		.devname	= "s3c-sdhci.1",
+		.parent		= &exynos4_clk_dout_mmc1.clk,
+		.enable		= exynos4_clksrc_mask_fsys_ctrl,
+		.ctrlbit	= (1 << 4),
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_FSYS1, .shift = 24, .size = 8 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_mmc2 = {
+	.clk	= {
+		.name		= "sclk_mmc",
+		.devname	= "s3c-sdhci.2",
+		.parent		= &exynos4_clk_dout_mmc2.clk,
+		.enable		= exynos4_clksrc_mask_fsys_ctrl,
+		.ctrlbit	= (1 << 8),
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_FSYS2, .shift = 8, .size = 8 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_mmc3 = {
+	.clk	= {
+		.name		= "sclk_mmc",
+		.devname	= "s3c-sdhci.3",
+		.parent		= &exynos4_clk_dout_mmc3.clk,
+		.enable		= exynos4_clksrc_mask_fsys_ctrl,
+		.ctrlbit	= (1 << 12),
+	},
+	.reg_div = { .reg = EXYNOS4_CLKDIV_FSYS2, .shift = 24, .size = 8 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_spi0 = {
+	.clk	= {
+		.name		= "sclk_spi",
+		.devname	= "s3c64xx-spi.0",
+		.enable		= exynos4_clksrc_mask_peril1_ctrl,
+		.ctrlbit	= (1 << 16),
+	},
+	.sources = &exynos4_clkset_group,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_PERIL1, .shift = 16, .size = 4 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_PERIL1, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_spi1 = {
+	.clk	= {
+		.name		= "sclk_spi",
+		.devname	= "s3c64xx-spi.1",
+		.enable		= exynos4_clksrc_mask_peril1_ctrl,
+		.ctrlbit	= (1 << 20),
+	},
+	.sources = &exynos4_clkset_group,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_PERIL1, .shift = 20, .size = 4 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_PERIL1, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_spi2 = {
+	.clk	= {
+		.name		= "sclk_spi",
+		.devname	= "s3c64xx-spi.2",
+		.enable		= exynos4_clksrc_mask_peril1_ctrl,
+		.ctrlbit	= (1 << 24),
+	},
+	.sources = &exynos4_clkset_group,
+	.reg_src = { .reg = EXYNOS4_CLKSRC_PERIL1, .shift = 24, .size = 4 },
+	.reg_div = { .reg = EXYNOS4_CLKDIV_PERIL2, .shift = 0, .size = 4 },
+};
+
+/* Clock initialization code */
+static struct clksrc_clk *exynos4_sysclks[] = {
+	&exynos4_clk_mout_apll,
+	&exynos4_clk_sclk_apll,
+	&exynos4_clk_mout_epll,
+	&exynos4_clk_mout_mpll,
+	&exynos4_clk_moutcore,
+	&exynos4_clk_coreclk,
+	&exynos4_clk_armclk,
+	&exynos4_clk_aclk_corem0,
+	&exynos4_clk_aclk_cores,
+	&exynos4_clk_aclk_corem1,
+	&exynos4_clk_periphclk,
+	&exynos4_clk_mout_corebus,
+	&exynos4_clk_sclk_dmc,
+	&exynos4_clk_aclk_cored,
+	&exynos4_clk_aclk_corep,
+	&exynos4_clk_aclk_acp,
+	&exynos4_clk_pclk_acp,
+	&exynos4_clk_vpllsrc,
+	&exynos4_clk_sclk_vpll,
+	&exynos4_clk_aclk_200,
+	&exynos4_clk_aclk_100,
+	&exynos4_clk_aclk_160,
+	&exynos4_clk_aclk_133,
+	&exynos4_clk_dout_mmc0,
+	&exynos4_clk_dout_mmc1,
+	&exynos4_clk_dout_mmc2,
+	&exynos4_clk_dout_mmc3,
+	&exynos4_clk_dout_mmc4,
+	&exynos4_clk_mout_mfc0,
+	&exynos4_clk_mout_mfc1,
+};
+
+static struct clk *exynos4_clk_cdev[] = {
+	&exynos4_clk_pdma0,
+	&exynos4_clk_pdma1,
+	&exynos4_clk_mdma1,
+	&exynos4_clk_fimd0,
+};
+
+static struct clksrc_clk *exynos4_clksrc_cdev[] = {
+	&exynos4_clk_sclk_uart0,
+	&exynos4_clk_sclk_uart1,
+	&exynos4_clk_sclk_uart2,
+	&exynos4_clk_sclk_uart3,
+	&exynos4_clk_sclk_mmc0,
+	&exynos4_clk_sclk_mmc1,
+	&exynos4_clk_sclk_mmc2,
+	&exynos4_clk_sclk_mmc3,
+	&exynos4_clk_sclk_spi0,
+	&exynos4_clk_sclk_spi1,
+	&exynos4_clk_sclk_spi2,
+
+};
+
+static struct clk_lookup exynos4_clk_lookup[] = {
+	CLKDEV_INIT("exynos4210-uart.0", "clk_uart_baud0", &exynos4_clk_sclk_uart0.clk),
+	CLKDEV_INIT("exynos4210-uart.1", "clk_uart_baud0", &exynos4_clk_sclk_uart1.clk),
+	CLKDEV_INIT("exynos4210-uart.2", "clk_uart_baud0", &exynos4_clk_sclk_uart2.clk),
+	CLKDEV_INIT("exynos4210-uart.3", "clk_uart_baud0", &exynos4_clk_sclk_uart3.clk),
+	CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &exynos4_clk_sclk_mmc0.clk),
+	CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &exynos4_clk_sclk_mmc1.clk),
+	CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &exynos4_clk_sclk_mmc2.clk),
+	CLKDEV_INIT("s3c-sdhci.3", "mmc_busclk.2", &exynos4_clk_sclk_mmc3.clk),
+	CLKDEV_INIT("exynos4-fb.0", "lcd", &exynos4_clk_fimd0),
+	CLKDEV_INIT("dma-pl330.0", "apb_pclk", &exynos4_clk_pdma0),
+	CLKDEV_INIT("dma-pl330.1", "apb_pclk", &exynos4_clk_pdma1),
+	CLKDEV_INIT("dma-pl330.2", "apb_pclk", &exynos4_clk_mdma1),
+	CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk0", &exynos4_clk_sclk_spi0.clk),
+	CLKDEV_INIT("s3c64xx-spi.1", "spi_busclk0", &exynos4_clk_sclk_spi1.clk),
+	CLKDEV_INIT("s3c64xx-spi.2", "spi_busclk0", &exynos4_clk_sclk_spi2.clk),
+};
+
+static int xtal_rate;
+
+static unsigned long exynos4_fout_apll_get_rate(struct clk *clk)
+{
+	if (soc_is_exynos4210())
+		return s5p_get_pll45xx(xtal_rate, __raw_readl(EXYNOS4_APLL_CON0),
+					pll_4508);
+	else if (soc_is_exynos4212() || soc_is_exynos4412())
+		return s5p_get_pll35xx(xtal_rate, __raw_readl(EXYNOS4_APLL_CON0));
+	else
+		return 0;
+}
+
+static struct clk_ops exynos4_fout_apll_ops = {
+	.get_rate = exynos4_fout_apll_get_rate,
+};
+
+static u32 exynos4_vpll_div[][8] = {
+	{  54000000, 3, 53, 3, 1024, 0, 17, 0 },
+	{ 108000000, 3, 53, 2, 1024, 0, 17, 0 },
+};
+
+static unsigned long exynos4_vpll_get_rate(struct clk *clk)
+{
+	return clk->rate;
+}
+
+static int exynos4_vpll_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned int vpll_con0, vpll_con1 = 0;
+	unsigned int i;
+
+	/* Return if nothing changed */
+	if (clk->rate == rate)
+		return 0;
+
+	vpll_con0 = __raw_readl(EXYNOS4_VPLL_CON0);
+	vpll_con0 &= ~(0x1 << 27 |					\
+			PLL90XX_MDIV_MASK << PLL46XX_MDIV_SHIFT |	\
+			PLL90XX_PDIV_MASK << PLL46XX_PDIV_SHIFT |	\
+			PLL90XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
+
+	vpll_con1 = __raw_readl(EXYNOS4_VPLL_CON1);
+	vpll_con1 &= ~(PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT |	\
+			PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT |	\
+			PLL4650C_KDIV_MASK << PLL46XX_KDIV_SHIFT);
+
+	for (i = 0; i < ARRAY_SIZE(exynos4_vpll_div); i++) {
+		if (exynos4_vpll_div[i][0] == rate) {
+			vpll_con0 |= exynos4_vpll_div[i][1] << PLL46XX_PDIV_SHIFT;
+			vpll_con0 |= exynos4_vpll_div[i][2] << PLL46XX_MDIV_SHIFT;
+			vpll_con0 |= exynos4_vpll_div[i][3] << PLL46XX_SDIV_SHIFT;
+			vpll_con1 |= exynos4_vpll_div[i][4] << PLL46XX_KDIV_SHIFT;
+			vpll_con1 |= exynos4_vpll_div[i][5] << PLL46XX_MFR_SHIFT;
+			vpll_con1 |= exynos4_vpll_div[i][6] << PLL46XX_MRR_SHIFT;
+			vpll_con0 |= exynos4_vpll_div[i][7] << 27;
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(exynos4_vpll_div)) {
+		printk(KERN_ERR "%s: Invalid Clock VPLL Frequency\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	__raw_writel(vpll_con0, EXYNOS4_VPLL_CON0);
+	__raw_writel(vpll_con1, EXYNOS4_VPLL_CON1);
+
+	/* Wait for VPLL lock */
+	while (!(__raw_readl(EXYNOS4_VPLL_CON0) & (1 << PLL46XX_LOCKED_SHIFT)))
+		continue;
+
+	clk->rate = rate;
+	return 0;
+}
+
+static struct clk_ops exynos4_vpll_ops = {
+	.get_rate = exynos4_vpll_get_rate,
+	.set_rate = exynos4_vpll_set_rate,
+};
+
+void __init_or_cpufreq exynos4_setup_clocks(void)
+{
+	struct clk *xtal_clk;
+	unsigned long apll = 0;
+	unsigned long mpll = 0;
+	unsigned long epll = 0;
+	unsigned long vpll = 0;
+	unsigned long vpllsrc;
+	unsigned long xtal;
+	unsigned long armclk;
+	unsigned long sclk_dmc;
+	unsigned long aclk_200;
+	unsigned long aclk_100;
+	unsigned long aclk_160;
+	unsigned long aclk_133;
+	unsigned int ptr;
+
+	printk(KERN_DEBUG "%s: registering clocks\n", __func__);
+
+	xtal_clk = clk_get(NULL, "xtal");
+	BUG_ON(IS_ERR(xtal_clk));
+
+	xtal = clk_get_rate(xtal_clk);
+
+	xtal_rate = xtal;
+
+	clk_put(xtal_clk);
+
+	printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
+
+	if (soc_is_exynos4210()) {
+		apll = s5p_get_pll45xx(xtal, __raw_readl(EXYNOS4_APLL_CON0),
+					pll_4508);
+		mpll = s5p_get_pll45xx(xtal, __raw_readl(EXYNOS4_MPLL_CON0),
+					pll_4508);
+		epll = s5p_get_pll46xx(xtal, __raw_readl(EXYNOS4_EPLL_CON0),
+					__raw_readl(EXYNOS4_EPLL_CON1), pll_4600);
+
+		vpllsrc = clk_get_rate(&exynos4_clk_vpllsrc.clk);
+		vpll = s5p_get_pll46xx(vpllsrc, __raw_readl(EXYNOS4_VPLL_CON0),
+					__raw_readl(EXYNOS4_VPLL_CON1), pll_4650c);
+	} else if (soc_is_exynos4212() || soc_is_exynos4412()) {
+		apll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS4_APLL_CON0));
+		mpll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS4_MPLL_CON0));
+		epll = s5p_get_pll36xx(xtal, __raw_readl(EXYNOS4_EPLL_CON0),
+					__raw_readl(EXYNOS4_EPLL_CON1));
+
+		vpllsrc = clk_get_rate(&exynos4_clk_vpllsrc.clk);
+		vpll = s5p_get_pll36xx(vpllsrc, __raw_readl(EXYNOS4_VPLL_CON0),
+					__raw_readl(EXYNOS4_VPLL_CON1));
+	} else {
+		/* nothing */
+	}
+
+	clk_fout_apll.ops = &exynos4_fout_apll_ops;
+	clk_fout_mpll.rate = mpll;
+	clk_fout_epll.rate = epll;
+	clk_fout_vpll.ops = &exynos4_vpll_ops;
+	clk_fout_vpll.rate = vpll;
+
+	printk(KERN_INFO "EXYNOS4: PLL settings, A=%ld, M=%ld, E=%ld V=%ld",
+			apll, mpll, epll, vpll);
+
+	armclk = clk_get_rate(&exynos4_clk_armclk.clk);
+	sclk_dmc = clk_get_rate(&exynos4_clk_sclk_dmc.clk);
+
+	aclk_200 = clk_get_rate(&exynos4_clk_aclk_200.clk);
+	aclk_100 = clk_get_rate(&exynos4_clk_aclk_100.clk);
+	aclk_160 = clk_get_rate(&exynos4_clk_aclk_160.clk);
+	aclk_133 = clk_get_rate(&exynos4_clk_aclk_133.clk);
+
+	printk(KERN_INFO "EXYNOS4: ARMCLK=%ld, DMC=%ld, ACLK200=%ld\n"
+			 "ACLK100=%ld, ACLK160=%ld, ACLK133=%ld\n",
+			armclk, sclk_dmc, aclk_200,
+			aclk_100, aclk_160, aclk_133);
+
+	clk_f.rate = armclk;
+	clk_h.rate = sclk_dmc;
+	clk_p.rate = aclk_100;
+
+	for (ptr = 0; ptr < ARRAY_SIZE(exynos4_clksrcs); ptr++)
+		s3c_set_clksrc(&exynos4_clksrcs[ptr], true);
+}
+
+static struct clk *exynos4_clks[] __initdata = {
+	&exynos4_clk_sclk_hdmi27m,
+	&exynos4_clk_sclk_hdmiphy,
+	&exynos4_clk_sclk_usbphy0,
+	&exynos4_clk_sclk_usbphy1,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int exynos4_clock_suspend(void)
+{
+	s3c_pm_do_save(exynos4_clock_save, ARRAY_SIZE(exynos4_clock_save));
+	return 0;
+}
+
+static void exynos4_clock_resume(void)
+{
+	s3c_pm_do_restore_core(exynos4_clock_save, ARRAY_SIZE(exynos4_clock_save));
+}
+
+#else
+#define exynos4_clock_suspend NULL
+#define exynos4_clock_resume NULL
+#endif
+
+static struct syscore_ops exynos4_clock_syscore_ops = {
+	.suspend	= exynos4_clock_suspend,
+	.resume		= exynos4_clock_resume,
+};
+
+void __init exynos4_register_clocks(void)
+{
+	int ptr;
+
+	s3c24xx_register_clocks(exynos4_clks, ARRAY_SIZE(exynos4_clks));
+
+	for (ptr = 0; ptr < ARRAY_SIZE(exynos4_sysclks); ptr++)
+		s3c_register_clksrc(exynos4_sysclks[ptr], 1);
+
+	for (ptr = 0; ptr < ARRAY_SIZE(exynos4_sclk_tv); ptr++)
+		s3c_register_clksrc(exynos4_sclk_tv[ptr], 1);
+
+	for (ptr = 0; ptr < ARRAY_SIZE(exynos4_clksrc_cdev); ptr++)
+		s3c_register_clksrc(exynos4_clksrc_cdev[ptr], 1);
+
+	s3c_register_clksrc(exynos4_clksrcs, ARRAY_SIZE(exynos4_clksrcs));
+	s3c_register_clocks(exynos4_init_clocks_on, ARRAY_SIZE(exynos4_init_clocks_on));
+
+	s3c24xx_register_clocks(exynos4_clk_cdev, ARRAY_SIZE(exynos4_clk_cdev));
+	for (ptr = 0; ptr < ARRAY_SIZE(exynos4_clk_cdev); ptr++)
+		s3c_disable_clocks(exynos4_clk_cdev[ptr], 1);
+
+	s3c_register_clocks(exynos4_init_clocks_off, ARRAY_SIZE(exynos4_init_clocks_off));
+	s3c_disable_clocks(exynos4_init_clocks_off, ARRAY_SIZE(exynos4_init_clocks_off));
+	clkdev_add_table(exynos4_clk_lookup, ARRAY_SIZE(exynos4_clk_lookup));
+
+	register_syscore_ops(&exynos4_clock_syscore_ops);
+	s3c24xx_register_clock(&dummy_apb_pclk);
+
+	s3c_pwmclk_init();
+}
diff --git a/arch/arm/mach-exynos/clock-exynos4.h b/arch/arm/mach-exynos/clock-exynos4.h
new file mode 100644
index 0000000..cb71c29
--- /dev/null
+++ b/arch/arm/mach-exynos/clock-exynos4.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Header file for exynos4 clock support
+ *
+ * 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 __ASM_ARCH_CLOCK_H
+#define __ASM_ARCH_CLOCK_H __FILE__
+
+#include <linux/clk.h>
+
+extern struct clksrc_clk exynos4_clk_aclk_133;
+extern struct clksrc_clk exynos4_clk_mout_mpll;
+
+extern struct clksrc_sources exynos4_clkset_mout_corebus;
+extern struct clksrc_sources exynos4_clkset_group;
+
+extern struct clk *exynos4_clkset_aclk_top_list[];
+extern struct clk *exynos4_clkset_group_list[];
+
+extern int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable);
+extern int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable);
+extern int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable);
+
+#endif /* __ASM_ARCH_CLOCK_H */
diff --git a/arch/arm/mach-exynos/clock-exynos4210.c b/arch/arm/mach-exynos/clock-exynos4210.c
index 13312cc..3b131e4 100644
--- a/arch/arm/mach-exynos/clock-exynos4210.c
+++ b/arch/arm/mach-exynos/clock-exynos4210.c
@@ -1,7 +1,5 @@
 /*
- * linux/arch/arm/mach-exynos4/clock-exynos4210.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com
  *
  * EXYNOS4210 - Clock support
@@ -28,20 +26,20 @@
 #include <mach/hardware.h>
 #include <mach/map.h>
 #include <mach/regs-clock.h>
-#include <mach/exynos4-clock.h>
 
 #include "common.h"
+#include "clock-exynos4.h"
 
 #ifdef CONFIG_PM_SLEEP
 static struct sleep_save exynos4210_clock_save[] = {
-	SAVE_ITEM(S5P_CLKSRC_IMAGE),
-	SAVE_ITEM(S5P_CLKSRC_LCD1),
-	SAVE_ITEM(S5P_CLKDIV_IMAGE),
-	SAVE_ITEM(S5P_CLKDIV_LCD1),
-	SAVE_ITEM(S5P_CLKSRC_MASK_LCD1),
-	SAVE_ITEM(S5P_CLKGATE_IP_IMAGE_4210),
-	SAVE_ITEM(S5P_CLKGATE_IP_LCD1),
-	SAVE_ITEM(S5P_CLKGATE_IP_PERIR_4210),
+	SAVE_ITEM(EXYNOS4_CLKSRC_IMAGE),
+	SAVE_ITEM(EXYNOS4_CLKDIV_IMAGE),
+	SAVE_ITEM(EXYNOS4210_CLKSRC_LCD1),
+	SAVE_ITEM(EXYNOS4210_CLKDIV_LCD1),
+	SAVE_ITEM(EXYNOS4210_CLKSRC_MASK_LCD1),
+	SAVE_ITEM(EXYNOS4210_CLKGATE_IP_IMAGE),
+	SAVE_ITEM(EXYNOS4210_CLKGATE_IP_LCD1),
+	SAVE_ITEM(EXYNOS4210_CLKGATE_IP_PERIR),
 };
 #endif
 
@@ -51,7 +49,7 @@
 
 static int exynos4_clksrc_mask_lcd1_ctrl(struct clk *clk, int enable)
 {
-	return s5p_gatectrl(S5P_CLKSRC_MASK_LCD1, clk, enable);
+	return s5p_gatectrl(EXYNOS4210_CLKSRC_MASK_LCD1, clk, enable);
 }
 
 static struct clksrc_clk clksrcs[] = {
@@ -62,9 +60,9 @@
 			.enable		= exynos4_clksrc_mask_fsys_ctrl,
 			.ctrlbit	= (1 << 24),
 		},
-		.sources = &clkset_mout_corebus,
-		.reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 24, .size = 1 },
-		.reg_div = { .reg = S5P_CLKDIV_FSYS0, .shift = 20, .size = 4 },
+		.sources = &exynos4_clkset_mout_corebus,
+		.reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 24, .size = 1 },
+		.reg_div = { .reg = EXYNOS4_CLKDIV_FSYS0, .shift = 20, .size = 4 },
 	}, {
 		.clk		= {
 			.name		= "sclk_fimd",
@@ -72,9 +70,9 @@
 			.enable		= exynos4_clksrc_mask_lcd1_ctrl,
 			.ctrlbit	= (1 << 0),
 		},
-		.sources = &clkset_group,
-		.reg_src = { .reg = S5P_CLKSRC_LCD1, .shift = 0, .size = 4 },
-		.reg_div = { .reg = S5P_CLKDIV_LCD1, .shift = 0, .size = 4 },
+		.sources = &exynos4_clkset_group,
+		.reg_src = { .reg = EXYNOS4210_CLKSRC_LCD1, .shift = 0, .size = 4 },
+		.reg_div = { .reg = EXYNOS4210_CLKDIV_LCD1, .shift = 0, .size = 4 },
 	},
 };
 
@@ -82,13 +80,13 @@
 	{
 		.name		= "sataphy",
 		.id		= -1,
-		.parent		= &clk_aclk_133.clk,
+		.parent		= &exynos4_clk_aclk_133.clk,
 		.enable		= exynos4_clk_ip_fsys_ctrl,
 		.ctrlbit	= (1 << 3),
 	}, {
 		.name		= "sata",
 		.id		= -1,
-		.parent		= &clk_aclk_133.clk,
+		.parent		= &exynos4_clk_aclk_133.clk,
 		.enable		= exynos4_clk_ip_fsys_ctrl,
 		.ctrlbit	= (1 << 10),
 	}, {
@@ -117,7 +115,7 @@
 #define exynos4210_clock_resume NULL
 #endif
 
-struct syscore_ops exynos4210_clock_syscore_ops = {
+static struct syscore_ops exynos4210_clock_syscore_ops = {
 	.suspend	= exynos4210_clock_suspend,
 	.resume		= exynos4210_clock_resume,
 };
@@ -126,9 +124,9 @@
 {
 	int ptr;
 
-	clk_mout_mpll.reg_src.reg = S5P_CLKSRC_CPU;
-	clk_mout_mpll.reg_src.shift = 8;
-	clk_mout_mpll.reg_src.size = 1;
+	exynos4_clk_mout_mpll.reg_src.reg = EXYNOS4_CLKSRC_CPU;
+	exynos4_clk_mout_mpll.reg_src.shift = 8;
+	exynos4_clk_mout_mpll.reg_src.size = 1;
 
 	for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
 		s3c_register_clksrc(sysclks[ptr], 1);
diff --git a/arch/arm/mach-exynos/clock-exynos4212.c b/arch/arm/mach-exynos/clock-exynos4212.c
index 48af285..3ecc01e 100644
--- a/arch/arm/mach-exynos/clock-exynos4212.c
+++ b/arch/arm/mach-exynos/clock-exynos4212.c
@@ -1,7 +1,5 @@
 /*
- * linux/arch/arm/mach-exynos4/clock-exynos4212.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com
  *
  * EXYNOS4212 - Clock support
@@ -28,22 +26,22 @@
 #include <mach/hardware.h>
 #include <mach/map.h>
 #include <mach/regs-clock.h>
-#include <mach/exynos4-clock.h>
 
 #include "common.h"
+#include "clock-exynos4.h"
 
 #ifdef CONFIG_PM_SLEEP
 static struct sleep_save exynos4212_clock_save[] = {
-	SAVE_ITEM(S5P_CLKSRC_IMAGE),
-	SAVE_ITEM(S5P_CLKDIV_IMAGE),
-	SAVE_ITEM(S5P_CLKGATE_IP_IMAGE_4212),
-	SAVE_ITEM(S5P_CLKGATE_IP_PERIR_4212),
+	SAVE_ITEM(EXYNOS4_CLKSRC_IMAGE),
+	SAVE_ITEM(EXYNOS4_CLKDIV_IMAGE),
+	SAVE_ITEM(EXYNOS4212_CLKGATE_IP_IMAGE),
+	SAVE_ITEM(EXYNOS4212_CLKGATE_IP_PERIR),
 };
 #endif
 
 static struct clk *clk_src_mpll_user_list[] = {
 	[0] = &clk_fin_mpll,
-	[1] = &clk_mout_mpll.clk,
+	[1] = &exynos4_clk_mout_mpll.clk,
 };
 
 static struct clksrc_sources clk_src_mpll_user = {
@@ -56,7 +54,7 @@
 		.name		= "mout_mpll_user",
 	},
 	.sources	= &clk_src_mpll_user,
-	.reg_src	= { .reg = S5P_CLKSRC_CPU, .shift = 24, .size = 1 },
+	.reg_src	= { .reg = EXYNOS4_CLKSRC_CPU, .shift = 24, .size = 1 },
 };
 
 static struct clksrc_clk *sysclks[] = {
@@ -89,7 +87,7 @@
 #define exynos4212_clock_resume NULL
 #endif
 
-struct syscore_ops exynos4212_clock_syscore_ops = {
+static struct syscore_ops exynos4212_clock_syscore_ops = {
 	.suspend	= exynos4212_clock_suspend,
 	.resume		= exynos4212_clock_resume,
 };
@@ -99,15 +97,15 @@
 	int ptr;
 
 	/* usbphy1 is removed */
-	clkset_group_list[4] = NULL;
+	exynos4_clkset_group_list[4] = NULL;
 
 	/* mout_mpll_user is used */
-	clkset_group_list[6] = &clk_mout_mpll_user.clk;
-	clkset_aclk_top_list[0] = &clk_mout_mpll_user.clk;
+	exynos4_clkset_group_list[6] = &clk_mout_mpll_user.clk;
+	exynos4_clkset_aclk_top_list[0] = &clk_mout_mpll_user.clk;
 
-	clk_mout_mpll.reg_src.reg = S5P_CLKSRC_DMC;
-	clk_mout_mpll.reg_src.shift = 12;
-	clk_mout_mpll.reg_src.size = 1;
+	exynos4_clk_mout_mpll.reg_src.reg = EXYNOS4_CLKSRC_DMC;
+	exynos4_clk_mout_mpll.reg_src.shift = 12;
+	exynos4_clk_mout_mpll.reg_src.size = 1;
 
 	for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
 		s3c_register_clksrc(sysclks[ptr], 1);
diff --git a/arch/arm/mach-exynos/clock-exynos5.c b/arch/arm/mach-exynos/clock-exynos5.c
new file mode 100644
index 0000000..d013982
--- /dev/null
+++ b/arch/arm/mach-exynos/clock-exynos5.c
@@ -0,0 +1,1247 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Clock support for EXYNOS5 SoCs
+ *
+ * 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/err.h>
+#include <linux/io.h>
+#include <linux/syscore_ops.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/pll.h>
+#include <plat/s5p-clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/pm.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/sysmmu.h>
+
+#include "common.h"
+
+#ifdef CONFIG_PM_SLEEP
+static struct sleep_save exynos5_clock_save[] = {
+	/* will be implemented */
+};
+#endif
+
+static struct clk exynos5_clk_sclk_dptxphy = {
+	.name		= "sclk_dptx",
+};
+
+static struct clk exynos5_clk_sclk_hdmi24m = {
+	.name		= "sclk_hdmi24m",
+	.rate		= 24000000,
+};
+
+static struct clk exynos5_clk_sclk_hdmi27m = {
+	.name		= "sclk_hdmi27m",
+	.rate		= 27000000,
+};
+
+static struct clk exynos5_clk_sclk_hdmiphy = {
+	.name		= "sclk_hdmiphy",
+};
+
+static struct clk exynos5_clk_sclk_usbphy = {
+	.name		= "sclk_usbphy",
+	.rate		= 48000000,
+};
+
+static int exynos5_clksrc_mask_top_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_TOP, clk, enable);
+}
+
+static int exynos5_clksrc_mask_disp1_0_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_DISP1_0, clk, enable);
+}
+
+static int exynos5_clksrc_mask_fsys_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_FSYS, clk, enable);
+}
+
+static int exynos5_clksrc_mask_gscl_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_GSCL, clk, enable);
+}
+
+static int exynos5_clksrc_mask_peric0_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_PERIC0, clk, enable);
+}
+
+static int exynos5_clk_ip_core_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_CORE, clk, enable);
+}
+
+static int exynos5_clk_ip_disp1_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_DISP1, clk, enable);
+}
+
+static int exynos5_clk_ip_fsys_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_FSYS, clk, enable);
+}
+
+static int exynos5_clk_block_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS5_CLKGATE_BLOCK, clk, enable);
+}
+
+static int exynos5_clk_ip_gen_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_GEN, clk, enable);
+}
+
+static int exynos5_clk_ip_gps_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_GPS, clk, enable);
+}
+
+static int exynos5_clk_ip_mfc_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_MFC, clk, enable);
+}
+
+static int exynos5_clk_ip_peric_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_PERIC, clk, enable);
+}
+
+static int exynos5_clk_ip_peris_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_PERIS, clk, enable);
+}
+
+/* Core list of CMU_CPU side */
+
+static struct clksrc_clk exynos5_clk_mout_apll = {
+	.clk	= {
+		.name		= "mout_apll",
+	},
+	.sources = &clk_src_apll,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_CPU, .shift = 0, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_apll = {
+	.clk	= {
+		.name		= "sclk_apll",
+		.parent		= &exynos5_clk_mout_apll.clk,
+	},
+	.reg_div = { .reg = EXYNOS5_CLKDIV_CPU0, .shift = 24, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_mout_bpll = {
+	.clk	= {
+		.name		= "mout_bpll",
+	},
+	.sources = &clk_src_bpll,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_CDREX, .shift = 0, .size = 1 },
+};
+
+static struct clk *exynos5_clk_src_bpll_user_list[] = {
+	[0] = &clk_fin_mpll,
+	[1] = &exynos5_clk_mout_bpll.clk,
+};
+
+static struct clksrc_sources exynos5_clk_src_bpll_user = {
+	.sources	= exynos5_clk_src_bpll_user_list,
+	.nr_sources	= ARRAY_SIZE(exynos5_clk_src_bpll_user_list),
+};
+
+static struct clksrc_clk exynos5_clk_mout_bpll_user = {
+	.clk	= {
+		.name		= "mout_bpll_user",
+	},
+	.sources = &exynos5_clk_src_bpll_user,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 24, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_mout_cpll = {
+	.clk	= {
+		.name		= "mout_cpll",
+	},
+	.sources = &clk_src_cpll,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 8, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_mout_epll = {
+	.clk	= {
+		.name		= "mout_epll",
+	},
+	.sources = &clk_src_epll,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 12, .size = 1 },
+};
+
+struct clksrc_clk exynos5_clk_mout_mpll = {
+	.clk = {
+		.name		= "mout_mpll",
+	},
+	.sources = &clk_src_mpll,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_CORE1, .shift = 8, .size = 1 },
+};
+
+static struct clk *exynos_clkset_vpllsrc_list[] = {
+	[0] = &clk_fin_vpll,
+	[1] = &exynos5_clk_sclk_hdmi27m,
+};
+
+static struct clksrc_sources exynos5_clkset_vpllsrc = {
+	.sources	= exynos_clkset_vpllsrc_list,
+	.nr_sources	= ARRAY_SIZE(exynos_clkset_vpllsrc_list),
+};
+
+static struct clksrc_clk exynos5_clk_vpllsrc = {
+	.clk	= {
+		.name		= "vpll_src",
+		.enable		= exynos5_clksrc_mask_top_ctrl,
+		.ctrlbit	= (1 << 0),
+	},
+	.sources = &exynos5_clkset_vpllsrc,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 0, .size = 1 },
+};
+
+static struct clk *exynos5_clkset_sclk_vpll_list[] = {
+	[0] = &exynos5_clk_vpllsrc.clk,
+	[1] = &clk_fout_vpll,
+};
+
+static struct clksrc_sources exynos5_clkset_sclk_vpll = {
+	.sources	= exynos5_clkset_sclk_vpll_list,
+	.nr_sources	= ARRAY_SIZE(exynos5_clkset_sclk_vpll_list),
+};
+
+static struct clksrc_clk exynos5_clk_sclk_vpll = {
+	.clk	= {
+		.name		= "sclk_vpll",
+	},
+	.sources = &exynos5_clkset_sclk_vpll,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 16, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_pixel = {
+	.clk	= {
+		.name		= "sclk_pixel",
+		.parent		= &exynos5_clk_sclk_vpll.clk,
+	},
+	.reg_div = { .reg = EXYNOS5_CLKDIV_DISP1_0, .shift = 28, .size = 4 },
+};
+
+static struct clk *exynos5_clkset_sclk_hdmi_list[] = {
+	[0] = &exynos5_clk_sclk_pixel.clk,
+	[1] = &exynos5_clk_sclk_hdmiphy,
+};
+
+static struct clksrc_sources exynos5_clkset_sclk_hdmi = {
+	.sources	= exynos5_clkset_sclk_hdmi_list,
+	.nr_sources	= ARRAY_SIZE(exynos5_clkset_sclk_hdmi_list),
+};
+
+static struct clksrc_clk exynos5_clk_sclk_hdmi = {
+	.clk	= {
+		.name		= "sclk_hdmi",
+		.enable		= exynos5_clksrc_mask_disp1_0_ctrl,
+		.ctrlbit	= (1 << 20),
+	},
+	.sources = &exynos5_clkset_sclk_hdmi,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_DISP1_0, .shift = 20, .size = 1 },
+};
+
+static struct clksrc_clk *exynos5_sclk_tv[] = {
+	&exynos5_clk_sclk_pixel,
+	&exynos5_clk_sclk_hdmi,
+};
+
+static struct clk *exynos5_clk_src_mpll_user_list[] = {
+	[0] = &clk_fin_mpll,
+	[1] = &exynos5_clk_mout_mpll.clk,
+};
+
+static struct clksrc_sources exynos5_clk_src_mpll_user = {
+	.sources	= exynos5_clk_src_mpll_user_list,
+	.nr_sources	= ARRAY_SIZE(exynos5_clk_src_mpll_user_list),
+};
+
+static struct clksrc_clk exynos5_clk_mout_mpll_user = {
+	.clk	= {
+		.name		= "mout_mpll_user",
+	},
+	.sources = &exynos5_clk_src_mpll_user,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 20, .size = 1 },
+};
+
+static struct clk *exynos5_clkset_mout_cpu_list[] = {
+	[0] = &exynos5_clk_mout_apll.clk,
+	[1] = &exynos5_clk_mout_mpll.clk,
+};
+
+static struct clksrc_sources exynos5_clkset_mout_cpu = {
+	.sources	= exynos5_clkset_mout_cpu_list,
+	.nr_sources	= ARRAY_SIZE(exynos5_clkset_mout_cpu_list),
+};
+
+static struct clksrc_clk exynos5_clk_mout_cpu = {
+	.clk	= {
+		.name		= "mout_cpu",
+	},
+	.sources = &exynos5_clkset_mout_cpu,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_CPU, .shift = 16, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_armclk = {
+	.clk	= {
+		.name		= "dout_armclk",
+		.parent		= &exynos5_clk_mout_cpu.clk,
+	},
+	.reg_div = { .reg = EXYNOS5_CLKDIV_CPU0, .shift = 0, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_arm2clk = {
+	.clk	= {
+		.name		= "dout_arm2clk",
+		.parent		= &exynos5_clk_dout_armclk.clk,
+	},
+	.reg_div = { .reg = EXYNOS5_CLKDIV_CPU0, .shift = 28, .size = 3 },
+};
+
+static struct clk exynos5_clk_armclk = {
+	.name		= "armclk",
+	.parent		= &exynos5_clk_dout_arm2clk.clk,
+};
+
+/* Core list of CMU_CDREX side */
+
+static struct clk *exynos5_clkset_cdrex_list[] = {
+	[0] = &exynos5_clk_mout_mpll.clk,
+	[1] = &exynos5_clk_mout_bpll.clk,
+};
+
+static struct clksrc_sources exynos5_clkset_cdrex = {
+	.sources	= exynos5_clkset_cdrex_list,
+	.nr_sources	= ARRAY_SIZE(exynos5_clkset_cdrex_list),
+};
+
+static struct clksrc_clk exynos5_clk_cdrex = {
+	.clk	= {
+		.name		= "clk_cdrex",
+	},
+	.sources = &exynos5_clkset_cdrex,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_CDREX, .shift = 4, .size = 1 },
+	.reg_div = { .reg = EXYNOS5_CLKDIV_CDREX, .shift = 16, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_acp = {
+	.clk	= {
+		.name		= "aclk_acp",
+		.parent		= &exynos5_clk_mout_mpll.clk,
+	},
+	.reg_div = { .reg = EXYNOS5_CLKDIV_ACP, .shift = 0, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_pclk_acp = {
+	.clk	= {
+		.name		= "pclk_acp",
+		.parent		= &exynos5_clk_aclk_acp.clk,
+	},
+	.reg_div = { .reg = EXYNOS5_CLKDIV_ACP, .shift = 4, .size = 3 },
+};
+
+/* Core list of CMU_TOP side */
+
+struct clk *exynos5_clkset_aclk_top_list[] = {
+	[0] = &exynos5_clk_mout_mpll_user.clk,
+	[1] = &exynos5_clk_mout_bpll_user.clk,
+};
+
+struct clksrc_sources exynos5_clkset_aclk = {
+	.sources	= exynos5_clkset_aclk_top_list,
+	.nr_sources	= ARRAY_SIZE(exynos5_clkset_aclk_top_list),
+};
+
+static struct clksrc_clk exynos5_clk_aclk_400 = {
+	.clk	= {
+		.name		= "aclk_400",
+	},
+	.sources = &exynos5_clkset_aclk,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 20, .size = 1 },
+	.reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 24, .size = 3 },
+};
+
+struct clk *exynos5_clkset_aclk_333_166_list[] = {
+	[0] = &exynos5_clk_mout_cpll.clk,
+	[1] = &exynos5_clk_mout_mpll_user.clk,
+};
+
+struct clksrc_sources exynos5_clkset_aclk_333_166 = {
+	.sources	= exynos5_clkset_aclk_333_166_list,
+	.nr_sources	= ARRAY_SIZE(exynos5_clkset_aclk_333_166_list),
+};
+
+static struct clksrc_clk exynos5_clk_aclk_333 = {
+	.clk	= {
+		.name		= "aclk_333",
+	},
+	.sources = &exynos5_clkset_aclk_333_166,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 16, .size = 1 },
+	.reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 20, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_166 = {
+	.clk	= {
+		.name		= "aclk_166",
+	},
+	.sources = &exynos5_clkset_aclk_333_166,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 8, .size = 1 },
+	.reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 8, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_266 = {
+	.clk	= {
+		.name		= "aclk_266",
+		.parent		= &exynos5_clk_mout_mpll_user.clk,
+	},
+	.reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 16, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_200 = {
+	.clk	= {
+		.name		= "aclk_200",
+	},
+	.sources = &exynos5_clkset_aclk,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 12, .size = 1 },
+	.reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 12, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_66_pre = {
+	.clk	= {
+		.name		= "aclk_66_pre",
+		.parent		= &exynos5_clk_mout_mpll_user.clk,
+	},
+	.reg_div = { .reg = EXYNOS5_CLKDIV_TOP1, .shift = 24, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_66 = {
+	.clk	= {
+		.name		= "aclk_66",
+		.parent		= &exynos5_clk_aclk_66_pre.clk,
+	},
+	.reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 0, .size = 3 },
+};
+
+static struct clk exynos5_init_clocks_off[] = {
+	{
+		.name		= "timers",
+		.parent		= &exynos5_clk_aclk_66.clk,
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 24),
+	}, {
+		.name		= "rtc",
+		.parent		= &exynos5_clk_aclk_66.clk,
+		.enable		= exynos5_clk_ip_peris_ctrl,
+		.ctrlbit	= (1 << 20),
+	}, {
+		.name		= "hsmmc",
+		.devname	= "s3c-sdhci.0",
+		.parent		= &exynos5_clk_aclk_200.clk,
+		.enable		= exynos5_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 12),
+	}, {
+		.name		= "hsmmc",
+		.devname	= "s3c-sdhci.1",
+		.parent		= &exynos5_clk_aclk_200.clk,
+		.enable		= exynos5_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 13),
+	}, {
+		.name		= "hsmmc",
+		.devname	= "s3c-sdhci.2",
+		.parent		= &exynos5_clk_aclk_200.clk,
+		.enable		= exynos5_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 14),
+	}, {
+		.name		= "hsmmc",
+		.devname	= "s3c-sdhci.3",
+		.parent		= &exynos5_clk_aclk_200.clk,
+		.enable		= exynos5_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 15),
+	}, {
+		.name		= "dwmci",
+		.parent		= &exynos5_clk_aclk_200.clk,
+		.enable		= exynos5_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 16),
+	}, {
+		.name		= "sata",
+		.devname	= "ahci",
+		.enable		= exynos5_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 6),
+	}, {
+		.name		= "sata_phy",
+		.enable		= exynos5_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 24),
+	}, {
+		.name		= "sata_phy_i2c",
+		.enable		= exynos5_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 25),
+	}, {
+		.name		= "mfc",
+		.devname	= "s5p-mfc",
+		.enable		= exynos5_clk_ip_mfc_ctrl,
+		.ctrlbit	= (1 << 0),
+	}, {
+		.name		= "hdmi",
+		.devname	= "exynos4-hdmi",
+		.enable		= exynos5_clk_ip_disp1_ctrl,
+		.ctrlbit	= (1 << 6),
+	}, {
+		.name		= "mixer",
+		.devname	= "s5p-mixer",
+		.enable		= exynos5_clk_ip_disp1_ctrl,
+		.ctrlbit	= (1 << 5),
+	}, {
+		.name		= "jpeg",
+		.enable		= exynos5_clk_ip_gen_ctrl,
+		.ctrlbit	= (1 << 2),
+	}, {
+		.name		= "dsim0",
+		.enable		= exynos5_clk_ip_disp1_ctrl,
+		.ctrlbit	= (1 << 3),
+	}, {
+		.name		= "iis",
+		.devname	= "samsung-i2s.1",
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 20),
+	}, {
+		.name		= "iis",
+		.devname	= "samsung-i2s.2",
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 21),
+	}, {
+		.name		= "pcm",
+		.devname	= "samsung-pcm.1",
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 22),
+	}, {
+		.name		= "pcm",
+		.devname	= "samsung-pcm.2",
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 23),
+	}, {
+		.name		= "spdif",
+		.devname	= "samsung-spdif",
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 26),
+	}, {
+		.name		= "ac97",
+		.devname	= "samsung-ac97",
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 27),
+	}, {
+		.name		= "usbhost",
+		.enable		= exynos5_clk_ip_fsys_ctrl ,
+		.ctrlbit	= (1 << 18),
+	}, {
+		.name		= "usbotg",
+		.enable		= exynos5_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 7),
+	}, {
+		.name		= "gps",
+		.enable		= exynos5_clk_ip_gps_ctrl,
+		.ctrlbit	= ((1 << 3) | (1 << 2) | (1 << 0)),
+	}, {
+		.name		= "nfcon",
+		.enable		= exynos5_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 22),
+	}, {
+		.name		= "iop",
+		.enable		= exynos5_clk_ip_fsys_ctrl,
+		.ctrlbit	= ((1 << 30) | (1 << 26) | (1 << 23)),
+	}, {
+		.name		= "core_iop",
+		.enable		= exynos5_clk_ip_core_ctrl,
+		.ctrlbit	= ((1 << 21) | (1 << 3)),
+	}, {
+		.name		= "mcu_iop",
+		.enable		= exynos5_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 0),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.0",
+		.parent		= &exynos5_clk_aclk_66.clk,
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 6),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.1",
+		.parent		= &exynos5_clk_aclk_66.clk,
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 7),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.2",
+		.parent		= &exynos5_clk_aclk_66.clk,
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 8),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.3",
+		.parent		= &exynos5_clk_aclk_66.clk,
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 9),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.4",
+		.parent		= &exynos5_clk_aclk_66.clk,
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 10),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.5",
+		.parent		= &exynos5_clk_aclk_66.clk,
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 11),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.6",
+		.parent		= &exynos5_clk_aclk_66.clk,
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 12),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-i2c.7",
+		.parent		= &exynos5_clk_aclk_66.clk,
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 13),
+	}, {
+		.name		= "i2c",
+		.devname	= "s3c2440-hdmiphy-i2c",
+		.parent		= &exynos5_clk_aclk_66.clk,
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 14),
+	}
+};
+
+static struct clk exynos5_init_clocks_on[] = {
+	{
+		.name		= "uart",
+		.devname	= "s5pv210-uart.0",
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 0),
+	}, {
+		.name		= "uart",
+		.devname	= "s5pv210-uart.1",
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 1),
+	}, {
+		.name		= "uart",
+		.devname	= "s5pv210-uart.2",
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 2),
+	}, {
+		.name		= "uart",
+		.devname	= "s5pv210-uart.3",
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 3),
+	}, {
+		.name		= "uart",
+		.devname	= "s5pv210-uart.4",
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 4),
+	}, {
+		.name		= "uart",
+		.devname	= "s5pv210-uart.5",
+		.enable		= exynos5_clk_ip_peric_ctrl,
+		.ctrlbit	= (1 << 5),
+	}
+};
+
+static struct clk exynos5_clk_pdma0 = {
+	.name		= "dma",
+	.devname	= "dma-pl330.0",
+	.enable		= exynos5_clk_ip_fsys_ctrl,
+	.ctrlbit	= (1 << 1),
+};
+
+static struct clk exynos5_clk_pdma1 = {
+	.name		= "dma",
+	.devname	= "dma-pl330.1",
+	.enable		= exynos5_clk_ip_fsys_ctrl,
+	.ctrlbit	= (1 << 1),
+};
+
+static struct clk exynos5_clk_mdma1 = {
+	.name		= "dma",
+	.devname	= "dma-pl330.2",
+	.enable		= exynos5_clk_ip_gen_ctrl,
+	.ctrlbit	= (1 << 4),
+};
+
+struct clk *exynos5_clkset_group_list[] = {
+	[0] = &clk_ext_xtal_mux,
+	[1] = NULL,
+	[2] = &exynos5_clk_sclk_hdmi24m,
+	[3] = &exynos5_clk_sclk_dptxphy,
+	[4] = &exynos5_clk_sclk_usbphy,
+	[5] = &exynos5_clk_sclk_hdmiphy,
+	[6] = &exynos5_clk_mout_mpll_user.clk,
+	[7] = &exynos5_clk_mout_epll.clk,
+	[8] = &exynos5_clk_sclk_vpll.clk,
+	[9] = &exynos5_clk_mout_cpll.clk,
+};
+
+struct clksrc_sources exynos5_clkset_group = {
+	.sources	= exynos5_clkset_group_list,
+	.nr_sources	= ARRAY_SIZE(exynos5_clkset_group_list),
+};
+
+/* Possible clock sources for aclk_266_gscl_sub Mux */
+static struct clk *clk_src_gscl_266_list[] = {
+	[0] = &clk_ext_xtal_mux,
+	[1] = &exynos5_clk_aclk_266.clk,
+};
+
+static struct clksrc_sources clk_src_gscl_266 = {
+	.sources	= clk_src_gscl_266_list,
+	.nr_sources	= ARRAY_SIZE(clk_src_gscl_266_list),
+};
+
+static struct clksrc_clk exynos5_clk_dout_mmc0 = {
+	.clk		= {
+		.name		= "dout_mmc0",
+	},
+	.sources = &exynos5_clkset_group,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 0, .size = 4 },
+	.reg_div = { .reg = EXYNOS5_CLKDIV_FSYS1, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_mmc1 = {
+	.clk		= {
+		.name		= "dout_mmc1",
+	},
+	.sources = &exynos5_clkset_group,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 4, .size = 4 },
+	.reg_div = { .reg = EXYNOS5_CLKDIV_FSYS1, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_mmc2 = {
+	.clk		= {
+		.name		= "dout_mmc2",
+	},
+	.sources = &exynos5_clkset_group,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 8, .size = 4 },
+	.reg_div = { .reg = EXYNOS5_CLKDIV_FSYS2, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_mmc3 = {
+	.clk		= {
+		.name		= "dout_mmc3",
+	},
+	.sources = &exynos5_clkset_group,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 12, .size = 4 },
+	.reg_div = { .reg = EXYNOS5_CLKDIV_FSYS2, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_mmc4 = {
+	.clk		= {
+		.name		= "dout_mmc4",
+	},
+	.sources = &exynos5_clkset_group,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 16, .size = 4 },
+	.reg_div = { .reg = EXYNOS5_CLKDIV_FSYS3, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_uart0 = {
+	.clk	= {
+		.name		= "uclk1",
+		.devname	= "exynos4210-uart.0",
+		.enable		= exynos5_clksrc_mask_peric0_ctrl,
+		.ctrlbit	= (1 << 0),
+	},
+	.sources = &exynos5_clkset_group,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_PERIC0, .shift = 0, .size = 4 },
+	.reg_div = { .reg = EXYNOS5_CLKDIV_PERIC0, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_uart1 = {
+	.clk	= {
+		.name		= "uclk1",
+		.devname	= "exynos4210-uart.1",
+		.enable		= exynos5_clksrc_mask_peric0_ctrl,
+		.ctrlbit	= (1 << 4),
+	},
+	.sources = &exynos5_clkset_group,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_PERIC0, .shift = 4, .size = 4 },
+	.reg_div = { .reg = EXYNOS5_CLKDIV_PERIC0, .shift = 4, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_uart2 = {
+	.clk	= {
+		.name		= "uclk1",
+		.devname	= "exynos4210-uart.2",
+		.enable		= exynos5_clksrc_mask_peric0_ctrl,
+		.ctrlbit	= (1 << 8),
+	},
+	.sources = &exynos5_clkset_group,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_PERIC0, .shift = 8, .size = 4 },
+	.reg_div = { .reg = EXYNOS5_CLKDIV_PERIC0, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_uart3 = {
+	.clk	= {
+		.name		= "uclk1",
+		.devname	= "exynos4210-uart.3",
+		.enable		= exynos5_clksrc_mask_peric0_ctrl,
+		.ctrlbit	= (1 << 12),
+	},
+	.sources = &exynos5_clkset_group,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_PERIC0, .shift = 12, .size = 4 },
+	.reg_div = { .reg = EXYNOS5_CLKDIV_PERIC0, .shift = 12, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_mmc0 = {
+	.clk	= {
+		.name		= "sclk_mmc",
+		.devname	= "s3c-sdhci.0",
+		.parent		= &exynos5_clk_dout_mmc0.clk,
+		.enable		= exynos5_clksrc_mask_fsys_ctrl,
+		.ctrlbit	= (1 << 0),
+	},
+	.reg_div = { .reg = EXYNOS5_CLKDIV_FSYS1, .shift = 8, .size = 8 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_mmc1 = {
+	.clk	= {
+		.name		= "sclk_mmc",
+		.devname	= "s3c-sdhci.1",
+		.parent		= &exynos5_clk_dout_mmc1.clk,
+		.enable		= exynos5_clksrc_mask_fsys_ctrl,
+		.ctrlbit	= (1 << 4),
+	},
+	.reg_div = { .reg = EXYNOS5_CLKDIV_FSYS1, .shift = 24, .size = 8 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_mmc2 = {
+	.clk	= {
+		.name		= "sclk_mmc",
+		.devname	= "s3c-sdhci.2",
+		.parent		= &exynos5_clk_dout_mmc2.clk,
+		.enable		= exynos5_clksrc_mask_fsys_ctrl,
+		.ctrlbit	= (1 << 8),
+	},
+	.reg_div = { .reg = EXYNOS5_CLKDIV_FSYS2, .shift = 8, .size = 8 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_mmc3 = {
+	.clk	= {
+		.name		= "sclk_mmc",
+		.devname	= "s3c-sdhci.3",
+		.parent		= &exynos5_clk_dout_mmc3.clk,
+		.enable		= exynos5_clksrc_mask_fsys_ctrl,
+		.ctrlbit	= (1 << 12),
+	},
+	.reg_div = { .reg = EXYNOS5_CLKDIV_FSYS2, .shift = 24, .size = 8 },
+};
+
+static struct clksrc_clk exynos5_clksrcs[] = {
+	{
+		.clk	= {
+			.name		= "sclk_dwmci",
+			.parent		= &exynos5_clk_dout_mmc4.clk,
+			.enable		= exynos5_clksrc_mask_fsys_ctrl,
+			.ctrlbit	= (1 << 16),
+		},
+		.reg_div = { .reg = EXYNOS5_CLKDIV_FSYS3, .shift = 8, .size = 8 },
+	}, {
+		.clk	= {
+			.name		= "sclk_fimd",
+			.devname	= "s3cfb.1",
+			.enable		= exynos5_clksrc_mask_disp1_0_ctrl,
+			.ctrlbit	= (1 << 0),
+		},
+		.sources = &exynos5_clkset_group,
+		.reg_src = { .reg = EXYNOS5_CLKSRC_DISP1_0, .shift = 0, .size = 4 },
+		.reg_div = { .reg = EXYNOS5_CLKDIV_DISP1_0, .shift = 0, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "aclk_266_gscl",
+		},
+		.sources = &clk_src_gscl_266,
+		.reg_src = { .reg = EXYNOS5_CLKSRC_TOP3, .shift = 8, .size = 1 },
+	}, {
+		.clk	= {
+			.name		= "sclk_g3d",
+			.devname	= "mali-t604.0",
+			.enable		= exynos5_clk_block_ctrl,
+			.ctrlbit	= (1 << 1),
+		},
+		.sources = &exynos5_clkset_aclk,
+		.reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 20, .size = 1 },
+		.reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 24, .size = 3 },
+	}, {
+		.clk	= {
+			.name		= "sclk_gscl_wrap",
+			.devname	= "s5p-mipi-csis.0",
+			.enable		= exynos5_clksrc_mask_gscl_ctrl,
+			.ctrlbit	= (1 << 24),
+		},
+		.sources = &exynos5_clkset_group,
+		.reg_src = { .reg = EXYNOS5_CLKSRC_GSCL, .shift = 24, .size = 4 },
+		.reg_div = { .reg = EXYNOS5_CLKDIV_GSCL, .shift = 24, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_gscl_wrap",
+			.devname	= "s5p-mipi-csis.1",
+			.enable		= exynos5_clksrc_mask_gscl_ctrl,
+			.ctrlbit	= (1 << 28),
+		},
+		.sources = &exynos5_clkset_group,
+		.reg_src = { .reg = EXYNOS5_CLKSRC_GSCL, .shift = 28, .size = 4 },
+		.reg_div = { .reg = EXYNOS5_CLKDIV_GSCL, .shift = 28, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_cam0",
+			.enable		= exynos5_clksrc_mask_gscl_ctrl,
+			.ctrlbit	= (1 << 16),
+		},
+		.sources = &exynos5_clkset_group,
+		.reg_src = { .reg = EXYNOS5_CLKSRC_GSCL, .shift = 16, .size = 4 },
+		.reg_div = { .reg = EXYNOS5_CLKDIV_GSCL, .shift = 16, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_cam1",
+			.enable		= exynos5_clksrc_mask_gscl_ctrl,
+			.ctrlbit	= (1 << 20),
+		},
+		.sources = &exynos5_clkset_group,
+		.reg_src = { .reg = EXYNOS5_CLKSRC_GSCL, .shift = 20, .size = 4 },
+		.reg_div = { .reg = EXYNOS5_CLKDIV_GSCL, .shift = 20, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_jpeg",
+			.parent		= &exynos5_clk_mout_cpll.clk,
+		},
+		.reg_div = { .reg = EXYNOS5_CLKDIV_GEN, .shift = 4, .size = 3 },
+	},
+};
+
+/* Clock initialization code */
+static struct clksrc_clk *exynos5_sysclks[] = {
+	&exynos5_clk_mout_apll,
+	&exynos5_clk_sclk_apll,
+	&exynos5_clk_mout_bpll,
+	&exynos5_clk_mout_bpll_user,
+	&exynos5_clk_mout_cpll,
+	&exynos5_clk_mout_epll,
+	&exynos5_clk_mout_mpll,
+	&exynos5_clk_mout_mpll_user,
+	&exynos5_clk_vpllsrc,
+	&exynos5_clk_sclk_vpll,
+	&exynos5_clk_mout_cpu,
+	&exynos5_clk_dout_armclk,
+	&exynos5_clk_dout_arm2clk,
+	&exynos5_clk_cdrex,
+	&exynos5_clk_aclk_400,
+	&exynos5_clk_aclk_333,
+	&exynos5_clk_aclk_266,
+	&exynos5_clk_aclk_200,
+	&exynos5_clk_aclk_166,
+	&exynos5_clk_aclk_66_pre,
+	&exynos5_clk_aclk_66,
+	&exynos5_clk_dout_mmc0,
+	&exynos5_clk_dout_mmc1,
+	&exynos5_clk_dout_mmc2,
+	&exynos5_clk_dout_mmc3,
+	&exynos5_clk_dout_mmc4,
+	&exynos5_clk_aclk_acp,
+	&exynos5_clk_pclk_acp,
+};
+
+static struct clk *exynos5_clk_cdev[] = {
+	&exynos5_clk_pdma0,
+	&exynos5_clk_pdma1,
+	&exynos5_clk_mdma1,
+};
+
+static struct clksrc_clk *exynos5_clksrc_cdev[] = {
+	&exynos5_clk_sclk_uart0,
+	&exynos5_clk_sclk_uart1,
+	&exynos5_clk_sclk_uart2,
+	&exynos5_clk_sclk_uart3,
+	&exynos5_clk_sclk_mmc0,
+	&exynos5_clk_sclk_mmc1,
+	&exynos5_clk_sclk_mmc2,
+	&exynos5_clk_sclk_mmc3,
+};
+
+static struct clk_lookup exynos5_clk_lookup[] = {
+	CLKDEV_INIT("exynos4210-uart.0", "clk_uart_baud0", &exynos5_clk_sclk_uart0.clk),
+	CLKDEV_INIT("exynos4210-uart.1", "clk_uart_baud0", &exynos5_clk_sclk_uart1.clk),
+	CLKDEV_INIT("exynos4210-uart.2", "clk_uart_baud0", &exynos5_clk_sclk_uart2.clk),
+	CLKDEV_INIT("exynos4210-uart.3", "clk_uart_baud0", &exynos5_clk_sclk_uart3.clk),
+	CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &exynos5_clk_sclk_mmc0.clk),
+	CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &exynos5_clk_sclk_mmc1.clk),
+	CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &exynos5_clk_sclk_mmc2.clk),
+	CLKDEV_INIT("s3c-sdhci.3", "mmc_busclk.2", &exynos5_clk_sclk_mmc3.clk),
+	CLKDEV_INIT("dma-pl330.0", "apb_pclk", &exynos5_clk_pdma0),
+	CLKDEV_INIT("dma-pl330.1", "apb_pclk", &exynos5_clk_pdma1),
+	CLKDEV_INIT("dma-pl330.2", "apb_pclk", &exynos5_clk_mdma1),
+};
+
+static unsigned long exynos5_epll_get_rate(struct clk *clk)
+{
+	return clk->rate;
+}
+
+static struct clk *exynos5_clks[] __initdata = {
+	&exynos5_clk_sclk_hdmi27m,
+	&exynos5_clk_sclk_hdmiphy,
+	&clk_fout_bpll,
+	&clk_fout_cpll,
+	&exynos5_clk_armclk,
+};
+
+static u32 epll_div[][6] = {
+	{ 192000000, 0, 48, 3, 1, 0 },
+	{ 180000000, 0, 45, 3, 1, 0 },
+	{  73728000, 1, 73, 3, 3, 47710 },
+	{  67737600, 1, 90, 4, 3, 20762 },
+	{  49152000, 0, 49, 3, 3, 9961 },
+	{  45158400, 0, 45, 3, 3, 10381 },
+	{ 180633600, 0, 45, 3, 1, 10381 },
+};
+
+static int exynos5_epll_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned int epll_con, epll_con_k;
+	unsigned int i;
+	unsigned int tmp;
+	unsigned int epll_rate;
+	unsigned int locktime;
+	unsigned int lockcnt;
+
+	/* Return if nothing changed */
+	if (clk->rate == rate)
+		return 0;
+
+	if (clk->parent)
+		epll_rate = clk_get_rate(clk->parent);
+	else
+		epll_rate = clk_ext_xtal_mux.rate;
+
+	if (epll_rate != 24000000) {
+		pr_err("Invalid Clock : recommended clock is 24MHz.\n");
+		return -EINVAL;
+	}
+
+	epll_con = __raw_readl(EXYNOS5_EPLL_CON0);
+	epll_con &= ~(0x1 << 27 | \
+			PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT |   \
+			PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT | \
+			PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
+
+	for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
+		if (epll_div[i][0] == rate) {
+			epll_con_k = epll_div[i][5] << 0;
+			epll_con |= epll_div[i][1] << 27;
+			epll_con |= epll_div[i][2] << PLL46XX_MDIV_SHIFT;
+			epll_con |= epll_div[i][3] << PLL46XX_PDIV_SHIFT;
+			epll_con |= epll_div[i][4] << PLL46XX_SDIV_SHIFT;
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(epll_div)) {
+		printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	epll_rate /= 1000000;
+
+	/* 3000 max_cycls : specification data */
+	locktime = 3000 / epll_rate * epll_div[i][3];
+	lockcnt = locktime * 10000 / (10000 / epll_rate);
+
+	__raw_writel(lockcnt, EXYNOS5_EPLL_LOCK);
+
+	__raw_writel(epll_con, EXYNOS5_EPLL_CON0);
+	__raw_writel(epll_con_k, EXYNOS5_EPLL_CON1);
+
+	do {
+		tmp = __raw_readl(EXYNOS5_EPLL_CON0);
+	} while (!(tmp & 0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT));
+
+	clk->rate = rate;
+
+	return 0;
+}
+
+static struct clk_ops exynos5_epll_ops = {
+	.get_rate = exynos5_epll_get_rate,
+	.set_rate = exynos5_epll_set_rate,
+};
+
+static int xtal_rate;
+
+static unsigned long exynos5_fout_apll_get_rate(struct clk *clk)
+{
+	return s5p_get_pll35xx(xtal_rate, __raw_readl(EXYNOS5_APLL_CON0));
+}
+
+static struct clk_ops exynos5_fout_apll_ops = {
+	.get_rate = exynos5_fout_apll_get_rate,
+};
+
+#ifdef CONFIG_PM
+static int exynos5_clock_suspend(void)
+{
+	s3c_pm_do_save(exynos5_clock_save, ARRAY_SIZE(exynos5_clock_save));
+
+	return 0;
+}
+
+static void exynos5_clock_resume(void)
+{
+	s3c_pm_do_restore_core(exynos5_clock_save, ARRAY_SIZE(exynos5_clock_save));
+}
+#else
+#define exynos5_clock_suspend NULL
+#define exynos5_clock_resume NULL
+#endif
+
+struct syscore_ops exynos5_clock_syscore_ops = {
+	.suspend	= exynos5_clock_suspend,
+	.resume		= exynos5_clock_resume,
+};
+
+void __init_or_cpufreq exynos5_setup_clocks(void)
+{
+	struct clk *xtal_clk;
+	unsigned long apll;
+	unsigned long bpll;
+	unsigned long cpll;
+	unsigned long mpll;
+	unsigned long epll;
+	unsigned long vpll;
+	unsigned long vpllsrc;
+	unsigned long xtal;
+	unsigned long armclk;
+	unsigned long mout_cdrex;
+	unsigned long aclk_400;
+	unsigned long aclk_333;
+	unsigned long aclk_266;
+	unsigned long aclk_200;
+	unsigned long aclk_166;
+	unsigned long aclk_66;
+	unsigned int ptr;
+
+	printk(KERN_DEBUG "%s: registering clocks\n", __func__);
+
+	xtal_clk = clk_get(NULL, "xtal");
+	BUG_ON(IS_ERR(xtal_clk));
+
+	xtal = clk_get_rate(xtal_clk);
+
+	xtal_rate = xtal;
+
+	clk_put(xtal_clk);
+
+	printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
+
+	apll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS5_APLL_CON0));
+	bpll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS5_BPLL_CON0));
+	cpll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS5_CPLL_CON0));
+	mpll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS5_MPLL_CON0));
+	epll = s5p_get_pll36xx(xtal, __raw_readl(EXYNOS5_EPLL_CON0),
+			__raw_readl(EXYNOS5_EPLL_CON1));
+
+	vpllsrc = clk_get_rate(&exynos5_clk_vpllsrc.clk);
+	vpll = s5p_get_pll36xx(vpllsrc, __raw_readl(EXYNOS5_VPLL_CON0),
+			__raw_readl(EXYNOS5_VPLL_CON1));
+
+	clk_fout_apll.ops = &exynos5_fout_apll_ops;
+	clk_fout_bpll.rate = bpll;
+	clk_fout_cpll.rate = cpll;
+	clk_fout_mpll.rate = mpll;
+	clk_fout_epll.rate = epll;
+	clk_fout_vpll.rate = vpll;
+
+	printk(KERN_INFO "EXYNOS5: PLL settings, A=%ld, B=%ld, C=%ld\n"
+			"M=%ld, E=%ld V=%ld",
+			apll, bpll, cpll, mpll, epll, vpll);
+
+	armclk = clk_get_rate(&exynos5_clk_armclk);
+	mout_cdrex = clk_get_rate(&exynos5_clk_cdrex.clk);
+
+	aclk_400 = clk_get_rate(&exynos5_clk_aclk_400.clk);
+	aclk_333 = clk_get_rate(&exynos5_clk_aclk_333.clk);
+	aclk_266 = clk_get_rate(&exynos5_clk_aclk_266.clk);
+	aclk_200 = clk_get_rate(&exynos5_clk_aclk_200.clk);
+	aclk_166 = clk_get_rate(&exynos5_clk_aclk_166.clk);
+	aclk_66 = clk_get_rate(&exynos5_clk_aclk_66.clk);
+
+	printk(KERN_INFO "EXYNOS5: ARMCLK=%ld, CDREX=%ld, ACLK400=%ld\n"
+			"ACLK333=%ld, ACLK266=%ld, ACLK200=%ld\n"
+			"ACLK166=%ld, ACLK66=%ld\n",
+			armclk, mout_cdrex, aclk_400,
+			aclk_333, aclk_266, aclk_200,
+			aclk_166, aclk_66);
+
+
+	clk_fout_epll.ops = &exynos5_epll_ops;
+
+	if (clk_set_parent(&exynos5_clk_mout_epll.clk, &clk_fout_epll))
+		printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+				clk_fout_epll.name, exynos5_clk_mout_epll.clk.name);
+
+	clk_set_rate(&exynos5_clk_sclk_apll.clk, 100000000);
+	clk_set_rate(&exynos5_clk_aclk_266.clk, 300000000);
+
+	clk_set_rate(&exynos5_clk_aclk_acp.clk, 267000000);
+	clk_set_rate(&exynos5_clk_pclk_acp.clk, 134000000);
+
+	for (ptr = 0; ptr < ARRAY_SIZE(exynos5_clksrcs); ptr++)
+		s3c_set_clksrc(&exynos5_clksrcs[ptr], true);
+}
+
+void __init exynos5_register_clocks(void)
+{
+	int ptr;
+
+	s3c24xx_register_clocks(exynos5_clks, ARRAY_SIZE(exynos5_clks));
+
+	for (ptr = 0; ptr < ARRAY_SIZE(exynos5_sysclks); ptr++)
+		s3c_register_clksrc(exynos5_sysclks[ptr], 1);
+
+	for (ptr = 0; ptr < ARRAY_SIZE(exynos5_sclk_tv); ptr++)
+		s3c_register_clksrc(exynos5_sclk_tv[ptr], 1);
+
+	for (ptr = 0; ptr < ARRAY_SIZE(exynos5_clksrc_cdev); ptr++)
+		s3c_register_clksrc(exynos5_clksrc_cdev[ptr], 1);
+
+	s3c_register_clksrc(exynos5_clksrcs, ARRAY_SIZE(exynos5_clksrcs));
+	s3c_register_clocks(exynos5_init_clocks_on, ARRAY_SIZE(exynos5_init_clocks_on));
+
+	s3c24xx_register_clocks(exynos5_clk_cdev, ARRAY_SIZE(exynos5_clk_cdev));
+	for (ptr = 0; ptr < ARRAY_SIZE(exynos5_clk_cdev); ptr++)
+		s3c_disable_clocks(exynos5_clk_cdev[ptr], 1);
+
+	s3c_register_clocks(exynos5_init_clocks_off, ARRAY_SIZE(exynos5_init_clocks_off));
+	s3c_disable_clocks(exynos5_init_clocks_off, ARRAY_SIZE(exynos5_init_clocks_off));
+	clkdev_add_table(exynos5_clk_lookup, ARRAY_SIZE(exynos5_clk_lookup));
+
+	register_syscore_ops(&exynos5_clock_syscore_ops);
+	s3c_pwmclk_init();
+}
diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c
deleted file mode 100644
index 187287a..0000000
--- a/arch/arm/mach-exynos/clock.c
+++ /dev/null
@@ -1,1564 +0,0 @@
-/* linux/arch/arm/mach-exynos4/clock.c
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * EXYNOS4 - Clock support
- *
- * 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/err.h>
-#include <linux/io.h>
-#include <linux/syscore_ops.h>
-
-#include <plat/cpu-freq.h>
-#include <plat/clock.h>
-#include <plat/cpu.h>
-#include <plat/pll.h>
-#include <plat/s5p-clock.h>
-#include <plat/clock-clksrc.h>
-#include <plat/pm.h>
-
-#include <mach/map.h>
-#include <mach/regs-clock.h>
-#include <mach/sysmmu.h>
-#include <mach/exynos4-clock.h>
-
-#include "common.h"
-
-#ifdef CONFIG_PM_SLEEP
-static struct sleep_save exynos4_clock_save[] = {
-	SAVE_ITEM(S5P_CLKDIV_LEFTBUS),
-	SAVE_ITEM(S5P_CLKGATE_IP_LEFTBUS),
-	SAVE_ITEM(S5P_CLKDIV_RIGHTBUS),
-	SAVE_ITEM(S5P_CLKGATE_IP_RIGHTBUS),
-	SAVE_ITEM(S5P_CLKSRC_TOP0),
-	SAVE_ITEM(S5P_CLKSRC_TOP1),
-	SAVE_ITEM(S5P_CLKSRC_CAM),
-	SAVE_ITEM(S5P_CLKSRC_TV),
-	SAVE_ITEM(S5P_CLKSRC_MFC),
-	SAVE_ITEM(S5P_CLKSRC_G3D),
-	SAVE_ITEM(S5P_CLKSRC_LCD0),
-	SAVE_ITEM(S5P_CLKSRC_MAUDIO),
-	SAVE_ITEM(S5P_CLKSRC_FSYS),
-	SAVE_ITEM(S5P_CLKSRC_PERIL0),
-	SAVE_ITEM(S5P_CLKSRC_PERIL1),
-	SAVE_ITEM(S5P_CLKDIV_CAM),
-	SAVE_ITEM(S5P_CLKDIV_TV),
-	SAVE_ITEM(S5P_CLKDIV_MFC),
-	SAVE_ITEM(S5P_CLKDIV_G3D),
-	SAVE_ITEM(S5P_CLKDIV_LCD0),
-	SAVE_ITEM(S5P_CLKDIV_MAUDIO),
-	SAVE_ITEM(S5P_CLKDIV_FSYS0),
-	SAVE_ITEM(S5P_CLKDIV_FSYS1),
-	SAVE_ITEM(S5P_CLKDIV_FSYS2),
-	SAVE_ITEM(S5P_CLKDIV_FSYS3),
-	SAVE_ITEM(S5P_CLKDIV_PERIL0),
-	SAVE_ITEM(S5P_CLKDIV_PERIL1),
-	SAVE_ITEM(S5P_CLKDIV_PERIL2),
-	SAVE_ITEM(S5P_CLKDIV_PERIL3),
-	SAVE_ITEM(S5P_CLKDIV_PERIL4),
-	SAVE_ITEM(S5P_CLKDIV_PERIL5),
-	SAVE_ITEM(S5P_CLKDIV_TOP),
-	SAVE_ITEM(S5P_CLKSRC_MASK_TOP),
-	SAVE_ITEM(S5P_CLKSRC_MASK_CAM),
-	SAVE_ITEM(S5P_CLKSRC_MASK_TV),
-	SAVE_ITEM(S5P_CLKSRC_MASK_LCD0),
-	SAVE_ITEM(S5P_CLKSRC_MASK_MAUDIO),
-	SAVE_ITEM(S5P_CLKSRC_MASK_FSYS),
-	SAVE_ITEM(S5P_CLKSRC_MASK_PERIL0),
-	SAVE_ITEM(S5P_CLKSRC_MASK_PERIL1),
-	SAVE_ITEM(S5P_CLKDIV2_RATIO),
-	SAVE_ITEM(S5P_CLKGATE_SCLKCAM),
-	SAVE_ITEM(S5P_CLKGATE_IP_CAM),
-	SAVE_ITEM(S5P_CLKGATE_IP_TV),
-	SAVE_ITEM(S5P_CLKGATE_IP_MFC),
-	SAVE_ITEM(S5P_CLKGATE_IP_G3D),
-	SAVE_ITEM(S5P_CLKGATE_IP_LCD0),
-	SAVE_ITEM(S5P_CLKGATE_IP_FSYS),
-	SAVE_ITEM(S5P_CLKGATE_IP_GPS),
-	SAVE_ITEM(S5P_CLKGATE_IP_PERIL),
-	SAVE_ITEM(S5P_CLKGATE_BLOCK),
-	SAVE_ITEM(S5P_CLKSRC_MASK_DMC),
-	SAVE_ITEM(S5P_CLKSRC_DMC),
-	SAVE_ITEM(S5P_CLKDIV_DMC0),
-	SAVE_ITEM(S5P_CLKDIV_DMC1),
-	SAVE_ITEM(S5P_CLKGATE_IP_DMC),
-	SAVE_ITEM(S5P_CLKSRC_CPU),
-	SAVE_ITEM(S5P_CLKDIV_CPU),
-	SAVE_ITEM(S5P_CLKDIV_CPU + 0x4),
-	SAVE_ITEM(S5P_CLKGATE_SCLKCPU),
-	SAVE_ITEM(S5P_CLKGATE_IP_CPU),
-};
-#endif
-
-struct clk clk_sclk_hdmi27m = {
-	.name		= "sclk_hdmi27m",
-	.rate		= 27000000,
-};
-
-struct clk clk_sclk_hdmiphy = {
-	.name		= "sclk_hdmiphy",
-};
-
-struct clk clk_sclk_usbphy0 = {
-	.name		= "sclk_usbphy0",
-	.rate		= 27000000,
-};
-
-struct clk clk_sclk_usbphy1 = {
-	.name		= "sclk_usbphy1",
-};
-
-static struct clk dummy_apb_pclk = {
-	.name		= "apb_pclk",
-	.id		= -1,
-};
-
-static int exynos4_clksrc_mask_top_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKSRC_MASK_TOP, clk, enable);
-}
-
-static int exynos4_clksrc_mask_cam_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKSRC_MASK_CAM, clk, enable);
-}
-
-static int exynos4_clksrc_mask_lcd0_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKSRC_MASK_LCD0, clk, enable);
-}
-
-int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKSRC_MASK_FSYS, clk, enable);
-}
-
-static int exynos4_clksrc_mask_peril0_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL0, clk, enable);
-}
-
-static int exynos4_clksrc_mask_peril1_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL1, clk, enable);
-}
-
-static int exynos4_clk_ip_mfc_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKGATE_IP_MFC, clk, enable);
-}
-
-static int exynos4_clksrc_mask_tv_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKSRC_MASK_TV, clk, enable);
-}
-
-static int exynos4_clk_ip_cam_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKGATE_IP_CAM, clk, enable);
-}
-
-static int exynos4_clk_ip_tv_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKGATE_IP_TV, clk, enable);
-}
-
-static int exynos4_clk_ip_image_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKGATE_IP_IMAGE, clk, enable);
-}
-
-static int exynos4_clk_ip_lcd0_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKGATE_IP_LCD0, clk, enable);
-}
-
-int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKGATE_IP_LCD1, clk, enable);
-}
-
-int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKGATE_IP_FSYS, clk, enable);
-}
-
-static int exynos4_clk_ip_peril_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKGATE_IP_PERIL, clk, enable);
-}
-
-static int exynos4_clk_ip_perir_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLKGATE_IP_PERIR, clk, enable);
-}
-
-static int exynos4_clk_hdmiphy_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_HDMI_PHY_CONTROL, clk, enable);
-}
-
-static int exynos4_clk_dac_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_DAC_PHY_CONTROL, clk, enable);
-}
-
-/* Core list of CMU_CPU side */
-
-static struct clksrc_clk clk_mout_apll = {
-	.clk	= {
-		.name		= "mout_apll",
-	},
-	.sources	= &clk_src_apll,
-	.reg_src	= { .reg = S5P_CLKSRC_CPU, .shift = 0, .size = 1 },
-};
-
-struct clksrc_clk clk_sclk_apll = {
-	.clk	= {
-		.name		= "sclk_apll",
-		.parent		= &clk_mout_apll.clk,
-	},
-	.reg_div	= { .reg = S5P_CLKDIV_CPU, .shift = 24, .size = 3 },
-};
-
-struct clksrc_clk clk_mout_epll = {
-	.clk	= {
-		.name		= "mout_epll",
-	},
-	.sources	= &clk_src_epll,
-	.reg_src	= { .reg = S5P_CLKSRC_TOP0, .shift = 4, .size = 1 },
-};
-
-struct clksrc_clk clk_mout_mpll = {
-	.clk = {
-		.name		= "mout_mpll",
-	},
-	.sources	= &clk_src_mpll,
-
-	/* reg_src will be added in each SoCs' clock */
-};
-
-static struct clk *clkset_moutcore_list[] = {
-	[0] = &clk_mout_apll.clk,
-	[1] = &clk_mout_mpll.clk,
-};
-
-static struct clksrc_sources clkset_moutcore = {
-	.sources	= clkset_moutcore_list,
-	.nr_sources	= ARRAY_SIZE(clkset_moutcore_list),
-};
-
-static struct clksrc_clk clk_moutcore = {
-	.clk	= {
-		.name		= "moutcore",
-	},
-	.sources	= &clkset_moutcore,
-	.reg_src	= { .reg = S5P_CLKSRC_CPU, .shift = 16, .size = 1 },
-};
-
-static struct clksrc_clk clk_coreclk = {
-	.clk	= {
-		.name		= "core_clk",
-		.parent		= &clk_moutcore.clk,
-	},
-	.reg_div	= { .reg = S5P_CLKDIV_CPU, .shift = 0, .size = 3 },
-};
-
-static struct clksrc_clk clk_armclk = {
-	.clk	= {
-		.name		= "armclk",
-		.parent		= &clk_coreclk.clk,
-	},
-};
-
-static struct clksrc_clk clk_aclk_corem0 = {
-	.clk	= {
-		.name		= "aclk_corem0",
-		.parent		= &clk_coreclk.clk,
-	},
-	.reg_div	= { .reg = S5P_CLKDIV_CPU, .shift = 4, .size = 3 },
-};
-
-static struct clksrc_clk clk_aclk_cores = {
-	.clk	= {
-		.name		= "aclk_cores",
-		.parent		= &clk_coreclk.clk,
-	},
-	.reg_div	= { .reg = S5P_CLKDIV_CPU, .shift = 4, .size = 3 },
-};
-
-static struct clksrc_clk clk_aclk_corem1 = {
-	.clk	= {
-		.name		= "aclk_corem1",
-		.parent		= &clk_coreclk.clk,
-	},
-	.reg_div	= { .reg = S5P_CLKDIV_CPU, .shift = 8, .size = 3 },
-};
-
-static struct clksrc_clk clk_periphclk = {
-	.clk	= {
-		.name		= "periphclk",
-		.parent		= &clk_coreclk.clk,
-	},
-	.reg_div	= { .reg = S5P_CLKDIV_CPU, .shift = 12, .size = 3 },
-};
-
-/* Core list of CMU_CORE side */
-
-struct clk *clkset_corebus_list[] = {
-	[0] = &clk_mout_mpll.clk,
-	[1] = &clk_sclk_apll.clk,
-};
-
-struct clksrc_sources clkset_mout_corebus = {
-	.sources	= clkset_corebus_list,
-	.nr_sources	= ARRAY_SIZE(clkset_corebus_list),
-};
-
-static struct clksrc_clk clk_mout_corebus = {
-	.clk	= {
-		.name		= "mout_corebus",
-	},
-	.sources	= &clkset_mout_corebus,
-	.reg_src	= { .reg = S5P_CLKSRC_DMC, .shift = 4, .size = 1 },
-};
-
-static struct clksrc_clk clk_sclk_dmc = {
-	.clk	= {
-		.name		= "sclk_dmc",
-		.parent		= &clk_mout_corebus.clk,
-	},
-	.reg_div	= { .reg = S5P_CLKDIV_DMC0, .shift = 12, .size = 3 },
-};
-
-static struct clksrc_clk clk_aclk_cored = {
-	.clk	= {
-		.name		= "aclk_cored",
-		.parent		= &clk_sclk_dmc.clk,
-	},
-	.reg_div	= { .reg = S5P_CLKDIV_DMC0, .shift = 16, .size = 3 },
-};
-
-static struct clksrc_clk clk_aclk_corep = {
-	.clk	= {
-		.name		= "aclk_corep",
-		.parent		= &clk_aclk_cored.clk,
-	},
-	.reg_div	= { .reg = S5P_CLKDIV_DMC0, .shift = 20, .size = 3 },
-};
-
-static struct clksrc_clk clk_aclk_acp = {
-	.clk	= {
-		.name		= "aclk_acp",
-		.parent		= &clk_mout_corebus.clk,
-	},
-	.reg_div	= { .reg = S5P_CLKDIV_DMC0, .shift = 0, .size = 3 },
-};
-
-static struct clksrc_clk clk_pclk_acp = {
-	.clk	= {
-		.name		= "pclk_acp",
-		.parent		= &clk_aclk_acp.clk,
-	},
-	.reg_div	= { .reg = S5P_CLKDIV_DMC0, .shift = 4, .size = 3 },
-};
-
-/* Core list of CMU_TOP side */
-
-struct clk *clkset_aclk_top_list[] = {
-	[0] = &clk_mout_mpll.clk,
-	[1] = &clk_sclk_apll.clk,
-};
-
-struct clksrc_sources clkset_aclk = {
-	.sources	= clkset_aclk_top_list,
-	.nr_sources	= ARRAY_SIZE(clkset_aclk_top_list),
-};
-
-static struct clksrc_clk clk_aclk_200 = {
-	.clk	= {
-		.name		= "aclk_200",
-	},
-	.sources	= &clkset_aclk,
-	.reg_src	= { .reg = S5P_CLKSRC_TOP0, .shift = 12, .size = 1 },
-	.reg_div	= { .reg = S5P_CLKDIV_TOP, .shift = 0, .size = 3 },
-};
-
-static struct clksrc_clk clk_aclk_100 = {
-	.clk	= {
-		.name		= "aclk_100",
-	},
-	.sources	= &clkset_aclk,
-	.reg_src	= { .reg = S5P_CLKSRC_TOP0, .shift = 16, .size = 1 },
-	.reg_div	= { .reg = S5P_CLKDIV_TOP, .shift = 4, .size = 4 },
-};
-
-static struct clksrc_clk clk_aclk_160 = {
-	.clk	= {
-		.name		= "aclk_160",
-	},
-	.sources	= &clkset_aclk,
-	.reg_src	= { .reg = S5P_CLKSRC_TOP0, .shift = 20, .size = 1 },
-	.reg_div	= { .reg = S5P_CLKDIV_TOP, .shift = 8, .size = 3 },
-};
-
-struct clksrc_clk clk_aclk_133 = {
-	.clk	= {
-		.name		= "aclk_133",
-	},
-	.sources	= &clkset_aclk,
-	.reg_src	= { .reg = S5P_CLKSRC_TOP0, .shift = 24, .size = 1 },
-	.reg_div	= { .reg = S5P_CLKDIV_TOP, .shift = 12, .size = 3 },
-};
-
-static struct clk *clkset_vpllsrc_list[] = {
-	[0] = &clk_fin_vpll,
-	[1] = &clk_sclk_hdmi27m,
-};
-
-static struct clksrc_sources clkset_vpllsrc = {
-	.sources	= clkset_vpllsrc_list,
-	.nr_sources	= ARRAY_SIZE(clkset_vpllsrc_list),
-};
-
-static struct clksrc_clk clk_vpllsrc = {
-	.clk	= {
-		.name		= "vpll_src",
-		.enable		= exynos4_clksrc_mask_top_ctrl,
-		.ctrlbit	= (1 << 0),
-	},
-	.sources	= &clkset_vpllsrc,
-	.reg_src	= { .reg = S5P_CLKSRC_TOP1, .shift = 0, .size = 1 },
-};
-
-static struct clk *clkset_sclk_vpll_list[] = {
-	[0] = &clk_vpllsrc.clk,
-	[1] = &clk_fout_vpll,
-};
-
-static struct clksrc_sources clkset_sclk_vpll = {
-	.sources	= clkset_sclk_vpll_list,
-	.nr_sources	= ARRAY_SIZE(clkset_sclk_vpll_list),
-};
-
-struct clksrc_clk clk_sclk_vpll = {
-	.clk	= {
-		.name		= "sclk_vpll",
-	},
-	.sources	= &clkset_sclk_vpll,
-	.reg_src	= { .reg = S5P_CLKSRC_TOP0, .shift = 8, .size = 1 },
-};
-
-static struct clk init_clocks_off[] = {
-	{
-		.name		= "timers",
-		.parent		= &clk_aclk_100.clk,
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1<<24),
-	}, {
-		.name		= "csis",
-		.devname	= "s5p-mipi-csis.0",
-		.enable		= exynos4_clk_ip_cam_ctrl,
-		.ctrlbit	= (1 << 4),
-	}, {
-		.name		= "csis",
-		.devname	= "s5p-mipi-csis.1",
-		.enable		= exynos4_clk_ip_cam_ctrl,
-		.ctrlbit	= (1 << 5),
-	}, {
-		.name		= "fimc",
-		.devname	= "exynos4-fimc.0",
-		.enable		= exynos4_clk_ip_cam_ctrl,
-		.ctrlbit	= (1 << 0),
-	}, {
-		.name		= "fimc",
-		.devname	= "exynos4-fimc.1",
-		.enable		= exynos4_clk_ip_cam_ctrl,
-		.ctrlbit	= (1 << 1),
-	}, {
-		.name		= "fimc",
-		.devname	= "exynos4-fimc.2",
-		.enable		= exynos4_clk_ip_cam_ctrl,
-		.ctrlbit	= (1 << 2),
-	}, {
-		.name		= "fimc",
-		.devname	= "exynos4-fimc.3",
-		.enable		= exynos4_clk_ip_cam_ctrl,
-		.ctrlbit	= (1 << 3),
-	}, {
-		.name		= "fimd",
-		.devname	= "exynos4-fb.0",
-		.enable		= exynos4_clk_ip_lcd0_ctrl,
-		.ctrlbit	= (1 << 0),
-	}, {
-		.name		= "hsmmc",
-		.devname	= "s3c-sdhci.0",
-		.parent		= &clk_aclk_133.clk,
-		.enable		= exynos4_clk_ip_fsys_ctrl,
-		.ctrlbit	= (1 << 5),
-	}, {
-		.name		= "hsmmc",
-		.devname	= "s3c-sdhci.1",
-		.parent		= &clk_aclk_133.clk,
-		.enable		= exynos4_clk_ip_fsys_ctrl,
-		.ctrlbit	= (1 << 6),
-	}, {
-		.name		= "hsmmc",
-		.devname	= "s3c-sdhci.2",
-		.parent		= &clk_aclk_133.clk,
-		.enable		= exynos4_clk_ip_fsys_ctrl,
-		.ctrlbit	= (1 << 7),
-	}, {
-		.name		= "hsmmc",
-		.devname	= "s3c-sdhci.3",
-		.parent		= &clk_aclk_133.clk,
-		.enable		= exynos4_clk_ip_fsys_ctrl,
-		.ctrlbit	= (1 << 8),
-	}, {
-		.name		= "dwmmc",
-		.parent		= &clk_aclk_133.clk,
-		.enable		= exynos4_clk_ip_fsys_ctrl,
-		.ctrlbit	= (1 << 9),
-	}, {
-		.name		= "dac",
-		.devname	= "s5p-sdo",
-		.enable		= exynos4_clk_ip_tv_ctrl,
-		.ctrlbit	= (1 << 2),
-	}, {
-		.name		= "mixer",
-		.devname	= "s5p-mixer",
-		.enable		= exynos4_clk_ip_tv_ctrl,
-		.ctrlbit	= (1 << 1),
-	}, {
-		.name		= "vp",
-		.devname	= "s5p-mixer",
-		.enable		= exynos4_clk_ip_tv_ctrl,
-		.ctrlbit	= (1 << 0),
-	}, {
-		.name		= "hdmi",
-		.devname	= "exynos4-hdmi",
-		.enable		= exynos4_clk_ip_tv_ctrl,
-		.ctrlbit	= (1 << 3),
-	}, {
-		.name		= "hdmiphy",
-		.devname	= "exynos4-hdmi",
-		.enable		= exynos4_clk_hdmiphy_ctrl,
-		.ctrlbit	= (1 << 0),
-	}, {
-		.name		= "dacphy",
-		.devname	= "s5p-sdo",
-		.enable		= exynos4_clk_dac_ctrl,
-		.ctrlbit	= (1 << 0),
-	}, {
-		.name		= "adc",
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 15),
-	}, {
-		.name		= "keypad",
-		.enable		= exynos4_clk_ip_perir_ctrl,
-		.ctrlbit	= (1 << 16),
-	}, {
-		.name		= "rtc",
-		.enable		= exynos4_clk_ip_perir_ctrl,
-		.ctrlbit	= (1 << 15),
-	}, {
-		.name		= "watchdog",
-		.parent		= &clk_aclk_100.clk,
-		.enable		= exynos4_clk_ip_perir_ctrl,
-		.ctrlbit	= (1 << 14),
-	}, {
-		.name		= "usbhost",
-		.enable		= exynos4_clk_ip_fsys_ctrl ,
-		.ctrlbit	= (1 << 12),
-	}, {
-		.name		= "otg",
-		.enable		= exynos4_clk_ip_fsys_ctrl,
-		.ctrlbit	= (1 << 13),
-	}, {
-		.name		= "spi",
-		.devname	= "s3c64xx-spi.0",
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 16),
-	}, {
-		.name		= "spi",
-		.devname	= "s3c64xx-spi.1",
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 17),
-	}, {
-		.name		= "spi",
-		.devname	= "s3c64xx-spi.2",
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 18),
-	}, {
-		.name		= "iis",
-		.devname	= "samsung-i2s.0",
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 19),
-	}, {
-		.name		= "iis",
-		.devname	= "samsung-i2s.1",
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 20),
-	}, {
-		.name		= "iis",
-		.devname	= "samsung-i2s.2",
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 21),
-	}, {
-		.name		= "ac97",
-		.devname	= "samsung-ac97",
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 27),
-	}, {
-		.name		= "fimg2d",
-		.enable		= exynos4_clk_ip_image_ctrl,
-		.ctrlbit	= (1 << 0),
-	}, {
-		.name		= "mfc",
-		.devname	= "s5p-mfc",
-		.enable		= exynos4_clk_ip_mfc_ctrl,
-		.ctrlbit	= (1 << 0),
-	}, {
-		.name		= "i2c",
-		.devname	= "s3c2440-i2c.0",
-		.parent		= &clk_aclk_100.clk,
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 6),
-	}, {
-		.name		= "i2c",
-		.devname	= "s3c2440-i2c.1",
-		.parent		= &clk_aclk_100.clk,
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 7),
-	}, {
-		.name		= "i2c",
-		.devname	= "s3c2440-i2c.2",
-		.parent		= &clk_aclk_100.clk,
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 8),
-	}, {
-		.name		= "i2c",
-		.devname	= "s3c2440-i2c.3",
-		.parent		= &clk_aclk_100.clk,
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 9),
-	}, {
-		.name		= "i2c",
-		.devname	= "s3c2440-i2c.4",
-		.parent		= &clk_aclk_100.clk,
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 10),
-	}, {
-		.name		= "i2c",
-		.devname	= "s3c2440-i2c.5",
-		.parent		= &clk_aclk_100.clk,
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 11),
-	}, {
-		.name		= "i2c",
-		.devname	= "s3c2440-i2c.6",
-		.parent		= &clk_aclk_100.clk,
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 12),
-	}, {
-		.name		= "i2c",
-		.devname	= "s3c2440-i2c.7",
-		.parent		= &clk_aclk_100.clk,
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 13),
-	}, {
-		.name		= "i2c",
-		.devname	= "s3c2440-hdmiphy-i2c",
-		.parent		= &clk_aclk_100.clk,
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 14),
-	}, {
-		.name		= "SYSMMU_MDMA",
-		.enable		= exynos4_clk_ip_image_ctrl,
-		.ctrlbit	= (1 << 5),
-	}, {
-		.name		= "SYSMMU_FIMC0",
-		.enable		= exynos4_clk_ip_cam_ctrl,
-		.ctrlbit	= (1 << 7),
-	}, {
-		.name		= "SYSMMU_FIMC1",
-		.enable		= exynos4_clk_ip_cam_ctrl,
-		.ctrlbit	= (1 << 8),
-	}, {
-		.name		= "SYSMMU_FIMC2",
-		.enable		= exynos4_clk_ip_cam_ctrl,
-		.ctrlbit	= (1 << 9),
-	}, {
-		.name		= "SYSMMU_FIMC3",
-		.enable		= exynos4_clk_ip_cam_ctrl,
-		.ctrlbit	= (1 << 10),
-	}, {
-		.name		= "SYSMMU_JPEG",
-		.enable		= exynos4_clk_ip_cam_ctrl,
-		.ctrlbit	= (1 << 11),
-	}, {
-		.name		= "SYSMMU_FIMD0",
-		.enable		= exynos4_clk_ip_lcd0_ctrl,
-		.ctrlbit	= (1 << 4),
-	}, {
-		.name		= "SYSMMU_FIMD1",
-		.enable		= exynos4_clk_ip_lcd1_ctrl,
-		.ctrlbit	= (1 << 4),
-	}, {
-		.name		= "SYSMMU_PCIe",
-		.enable		= exynos4_clk_ip_fsys_ctrl,
-		.ctrlbit	= (1 << 18),
-	}, {
-		.name		= "SYSMMU_G2D",
-		.enable		= exynos4_clk_ip_image_ctrl,
-		.ctrlbit	= (1 << 3),
-	}, {
-		.name		= "SYSMMU_ROTATOR",
-		.enable		= exynos4_clk_ip_image_ctrl,
-		.ctrlbit	= (1 << 4),
-	}, {
-		.name		= "SYSMMU_TV",
-		.enable		= exynos4_clk_ip_tv_ctrl,
-		.ctrlbit	= (1 << 4),
-	}, {
-		.name		= "SYSMMU_MFC_L",
-		.enable		= exynos4_clk_ip_mfc_ctrl,
-		.ctrlbit	= (1 << 1),
-	}, {
-		.name		= "SYSMMU_MFC_R",
-		.enable		= exynos4_clk_ip_mfc_ctrl,
-		.ctrlbit	= (1 << 2),
-	}
-};
-
-static struct clk init_clocks[] = {
-	{
-		.name		= "uart",
-		.devname	= "s5pv210-uart.0",
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 0),
-	}, {
-		.name		= "uart",
-		.devname	= "s5pv210-uart.1",
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 1),
-	}, {
-		.name		= "uart",
-		.devname	= "s5pv210-uart.2",
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 2),
-	}, {
-		.name		= "uart",
-		.devname	= "s5pv210-uart.3",
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 3),
-	}, {
-		.name		= "uart",
-		.devname	= "s5pv210-uart.4",
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 4),
-	}, {
-		.name		= "uart",
-		.devname	= "s5pv210-uart.5",
-		.enable		= exynos4_clk_ip_peril_ctrl,
-		.ctrlbit	= (1 << 5),
-	}
-};
-
-static struct clk clk_pdma0 = {
-	.name		= "dma",
-	.devname	= "dma-pl330.0",
-	.enable		= exynos4_clk_ip_fsys_ctrl,
-	.ctrlbit	= (1 << 0),
-};
-
-static struct clk clk_pdma1 = {
-	.name		= "dma",
-	.devname	= "dma-pl330.1",
-	.enable		= exynos4_clk_ip_fsys_ctrl,
-	.ctrlbit	= (1 << 1),
-};
-
-struct clk *clkset_group_list[] = {
-	[0] = &clk_ext_xtal_mux,
-	[1] = &clk_xusbxti,
-	[2] = &clk_sclk_hdmi27m,
-	[3] = &clk_sclk_usbphy0,
-	[4] = &clk_sclk_usbphy1,
-	[5] = &clk_sclk_hdmiphy,
-	[6] = &clk_mout_mpll.clk,
-	[7] = &clk_mout_epll.clk,
-	[8] = &clk_sclk_vpll.clk,
-};
-
-struct clksrc_sources clkset_group = {
-	.sources	= clkset_group_list,
-	.nr_sources	= ARRAY_SIZE(clkset_group_list),
-};
-
-static struct clk *clkset_mout_g2d0_list[] = {
-	[0] = &clk_mout_mpll.clk,
-	[1] = &clk_sclk_apll.clk,
-};
-
-static struct clksrc_sources clkset_mout_g2d0 = {
-	.sources	= clkset_mout_g2d0_list,
-	.nr_sources	= ARRAY_SIZE(clkset_mout_g2d0_list),
-};
-
-static struct clksrc_clk clk_mout_g2d0 = {
-	.clk	= {
-		.name		= "mout_g2d0",
-	},
-	.sources	= &clkset_mout_g2d0,
-	.reg_src	= { .reg = S5P_CLKSRC_IMAGE, .shift = 0, .size = 1 },
-};
-
-static struct clk *clkset_mout_g2d1_list[] = {
-	[0] = &clk_mout_epll.clk,
-	[1] = &clk_sclk_vpll.clk,
-};
-
-static struct clksrc_sources clkset_mout_g2d1 = {
-	.sources	= clkset_mout_g2d1_list,
-	.nr_sources	= ARRAY_SIZE(clkset_mout_g2d1_list),
-};
-
-static struct clksrc_clk clk_mout_g2d1 = {
-	.clk	= {
-		.name		= "mout_g2d1",
-	},
-	.sources	= &clkset_mout_g2d1,
-	.reg_src	= { .reg = S5P_CLKSRC_IMAGE, .shift = 4, .size = 1 },
-};
-
-static struct clk *clkset_mout_g2d_list[] = {
-	[0] = &clk_mout_g2d0.clk,
-	[1] = &clk_mout_g2d1.clk,
-};
-
-static struct clksrc_sources clkset_mout_g2d = {
-	.sources	= clkset_mout_g2d_list,
-	.nr_sources	= ARRAY_SIZE(clkset_mout_g2d_list),
-};
-
-static struct clk *clkset_mout_mfc0_list[] = {
-	[0] = &clk_mout_mpll.clk,
-	[1] = &clk_sclk_apll.clk,
-};
-
-static struct clksrc_sources clkset_mout_mfc0 = {
-	.sources	= clkset_mout_mfc0_list,
-	.nr_sources	= ARRAY_SIZE(clkset_mout_mfc0_list),
-};
-
-static struct clksrc_clk clk_mout_mfc0 = {
-	.clk	= {
-		.name		= "mout_mfc0",
-	},
-	.sources	= &clkset_mout_mfc0,
-	.reg_src	= { .reg = S5P_CLKSRC_MFC, .shift = 0, .size = 1 },
-};
-
-static struct clk *clkset_mout_mfc1_list[] = {
-	[0] = &clk_mout_epll.clk,
-	[1] = &clk_sclk_vpll.clk,
-};
-
-static struct clksrc_sources clkset_mout_mfc1 = {
-	.sources	= clkset_mout_mfc1_list,
-	.nr_sources	= ARRAY_SIZE(clkset_mout_mfc1_list),
-};
-
-static struct clksrc_clk clk_mout_mfc1 = {
-	.clk	= {
-		.name		= "mout_mfc1",
-	},
-	.sources	= &clkset_mout_mfc1,
-	.reg_src	= { .reg = S5P_CLKSRC_MFC, .shift = 4, .size = 1 },
-};
-
-static struct clk *clkset_mout_mfc_list[] = {
-	[0] = &clk_mout_mfc0.clk,
-	[1] = &clk_mout_mfc1.clk,
-};
-
-static struct clksrc_sources clkset_mout_mfc = {
-	.sources	= clkset_mout_mfc_list,
-	.nr_sources	= ARRAY_SIZE(clkset_mout_mfc_list),
-};
-
-static struct clk *clkset_sclk_dac_list[] = {
-	[0] = &clk_sclk_vpll.clk,
-	[1] = &clk_sclk_hdmiphy,
-};
-
-static struct clksrc_sources clkset_sclk_dac = {
-	.sources	= clkset_sclk_dac_list,
-	.nr_sources	= ARRAY_SIZE(clkset_sclk_dac_list),
-};
-
-static struct clksrc_clk clk_sclk_dac = {
-	.clk		= {
-		.name		= "sclk_dac",
-		.enable		= exynos4_clksrc_mask_tv_ctrl,
-		.ctrlbit	= (1 << 8),
-	},
-	.sources = &clkset_sclk_dac,
-	.reg_src = { .reg = S5P_CLKSRC_TV, .shift = 8, .size = 1 },
-};
-
-static struct clksrc_clk clk_sclk_pixel = {
-	.clk		= {
-		.name		= "sclk_pixel",
-		.parent = &clk_sclk_vpll.clk,
-	},
-	.reg_div = { .reg = S5P_CLKDIV_TV, .shift = 0, .size = 4 },
-};
-
-static struct clk *clkset_sclk_hdmi_list[] = {
-	[0] = &clk_sclk_pixel.clk,
-	[1] = &clk_sclk_hdmiphy,
-};
-
-static struct clksrc_sources clkset_sclk_hdmi = {
-	.sources	= clkset_sclk_hdmi_list,
-	.nr_sources	= ARRAY_SIZE(clkset_sclk_hdmi_list),
-};
-
-static struct clksrc_clk clk_sclk_hdmi = {
-	.clk		= {
-		.name		= "sclk_hdmi",
-		.enable		= exynos4_clksrc_mask_tv_ctrl,
-		.ctrlbit	= (1 << 0),
-	},
-	.sources = &clkset_sclk_hdmi,
-	.reg_src = { .reg = S5P_CLKSRC_TV, .shift = 0, .size = 1 },
-};
-
-static struct clk *clkset_sclk_mixer_list[] = {
-	[0] = &clk_sclk_dac.clk,
-	[1] = &clk_sclk_hdmi.clk,
-};
-
-static struct clksrc_sources clkset_sclk_mixer = {
-	.sources	= clkset_sclk_mixer_list,
-	.nr_sources	= ARRAY_SIZE(clkset_sclk_mixer_list),
-};
-
-static struct clksrc_clk clk_sclk_mixer = {
-	.clk		= {
-		.name		= "sclk_mixer",
-		.enable		= exynos4_clksrc_mask_tv_ctrl,
-		.ctrlbit	= (1 << 4),
-	},
-	.sources = &clkset_sclk_mixer,
-	.reg_src = { .reg = S5P_CLKSRC_TV, .shift = 4, .size = 1 },
-};
-
-static struct clksrc_clk *sclk_tv[] = {
-	&clk_sclk_dac,
-	&clk_sclk_pixel,
-	&clk_sclk_hdmi,
-	&clk_sclk_mixer,
-};
-
-static struct clksrc_clk clk_dout_mmc0 = {
-	.clk		= {
-		.name		= "dout_mmc0",
-	},
-	.sources = &clkset_group,
-	.reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 0, .size = 4 },
-	.reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 0, .size = 4 },
-};
-
-static struct clksrc_clk clk_dout_mmc1 = {
-	.clk		= {
-		.name		= "dout_mmc1",
-	},
-	.sources = &clkset_group,
-	.reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 4, .size = 4 },
-	.reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 16, .size = 4 },
-};
-
-static struct clksrc_clk clk_dout_mmc2 = {
-	.clk		= {
-		.name		= "dout_mmc2",
-	},
-	.sources = &clkset_group,
-	.reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 8, .size = 4 },
-	.reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 0, .size = 4 },
-};
-
-static struct clksrc_clk clk_dout_mmc3 = {
-	.clk		= {
-		.name		= "dout_mmc3",
-	},
-	.sources = &clkset_group,
-	.reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 12, .size = 4 },
-	.reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 16, .size = 4 },
-};
-
-static struct clksrc_clk clk_dout_mmc4 = {
-	.clk		= {
-		.name		= "dout_mmc4",
-	},
-	.sources = &clkset_group,
-	.reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 16, .size = 4 },
-	.reg_div = { .reg = S5P_CLKDIV_FSYS3, .shift = 0, .size = 4 },
-};
-
-static struct clksrc_clk clksrcs[] = {
-	{
-		.clk		= {
-			.name		= "sclk_pwm",
-			.enable		= exynos4_clksrc_mask_peril0_ctrl,
-			.ctrlbit	= (1 << 24),
-		},
-		.sources = &clkset_group,
-		.reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 24, .size = 4 },
-		.reg_div = { .reg = S5P_CLKDIV_PERIL3, .shift = 0, .size = 4 },
-	}, {
-		.clk		= {
-			.name		= "sclk_csis",
-			.devname	= "s5p-mipi-csis.0",
-			.enable		= exynos4_clksrc_mask_cam_ctrl,
-			.ctrlbit	= (1 << 24),
-		},
-		.sources = &clkset_group,
-		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 24, .size = 4 },
-		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 24, .size = 4 },
-	}, {
-		.clk		= {
-			.name		= "sclk_csis",
-			.devname	= "s5p-mipi-csis.1",
-			.enable		= exynos4_clksrc_mask_cam_ctrl,
-			.ctrlbit	= (1 << 28),
-		},
-		.sources = &clkset_group,
-		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 28, .size = 4 },
-		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 28, .size = 4 },
-	}, {
-		.clk		= {
-			.name		= "sclk_cam0",
-			.enable		= exynos4_clksrc_mask_cam_ctrl,
-			.ctrlbit	= (1 << 16),
-		},
-		.sources = &clkset_group,
-		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 16, .size = 4 },
-		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 16, .size = 4 },
-	}, {
-		.clk		= {
-			.name		= "sclk_cam1",
-			.enable		= exynos4_clksrc_mask_cam_ctrl,
-			.ctrlbit	= (1 << 20),
-		},
-		.sources = &clkset_group,
-		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 20, .size = 4 },
-		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 20, .size = 4 },
-	}, {
-		.clk		= {
-			.name		= "sclk_fimc",
-			.devname	= "exynos4-fimc.0",
-			.enable		= exynos4_clksrc_mask_cam_ctrl,
-			.ctrlbit	= (1 << 0),
-		},
-		.sources = &clkset_group,
-		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 0, .size = 4 },
-		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 0, .size = 4 },
-	}, {
-		.clk		= {
-			.name		= "sclk_fimc",
-			.devname	= "exynos4-fimc.1",
-			.enable		= exynos4_clksrc_mask_cam_ctrl,
-			.ctrlbit	= (1 << 4),
-		},
-		.sources = &clkset_group,
-		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 4, .size = 4 },
-		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 4, .size = 4 },
-	}, {
-		.clk		= {
-			.name		= "sclk_fimc",
-			.devname	= "exynos4-fimc.2",
-			.enable		= exynos4_clksrc_mask_cam_ctrl,
-			.ctrlbit	= (1 << 8),
-		},
-		.sources = &clkset_group,
-		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 8, .size = 4 },
-		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 8, .size = 4 },
-	}, {
-		.clk		= {
-			.name		= "sclk_fimc",
-			.devname	= "exynos4-fimc.3",
-			.enable		= exynos4_clksrc_mask_cam_ctrl,
-			.ctrlbit	= (1 << 12),
-		},
-		.sources = &clkset_group,
-		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 12, .size = 4 },
-		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 12, .size = 4 },
-	}, {
-		.clk		= {
-			.name		= "sclk_fimd",
-			.devname	= "exynos4-fb.0",
-			.enable		= exynos4_clksrc_mask_lcd0_ctrl,
-			.ctrlbit	= (1 << 0),
-		},
-		.sources = &clkset_group,
-		.reg_src = { .reg = S5P_CLKSRC_LCD0, .shift = 0, .size = 4 },
-		.reg_div = { .reg = S5P_CLKDIV_LCD0, .shift = 0, .size = 4 },
-	}, {
-		.clk		= {
-			.name		= "sclk_fimg2d",
-		},
-		.sources = &clkset_mout_g2d,
-		.reg_src = { .reg = S5P_CLKSRC_IMAGE, .shift = 8, .size = 1 },
-		.reg_div = { .reg = S5P_CLKDIV_IMAGE, .shift = 0, .size = 4 },
-	}, {
-		.clk		= {
-			.name		= "sclk_mfc",
-			.devname	= "s5p-mfc",
-		},
-		.sources = &clkset_mout_mfc,
-		.reg_src = { .reg = S5P_CLKSRC_MFC, .shift = 8, .size = 1 },
-		.reg_div = { .reg = S5P_CLKDIV_MFC, .shift = 0, .size = 4 },
-	}, {
-		.clk		= {
-			.name		= "sclk_dwmmc",
-			.parent         = &clk_dout_mmc4.clk,
-			.enable		= exynos4_clksrc_mask_fsys_ctrl,
-			.ctrlbit	= (1 << 16),
-		},
-		.reg_div = { .reg = S5P_CLKDIV_FSYS3, .shift = 8, .size = 8 },
-	}
-};
-
-static struct clksrc_clk clk_sclk_uart0 = {
-	.clk	= {
-		.name		= "uclk1",
-		.devname	= "exynos4210-uart.0",
-		.enable		= exynos4_clksrc_mask_peril0_ctrl,
-		.ctrlbit	= (1 << 0),
-	},
-	.sources = &clkset_group,
-	.reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 0, .size = 4 },
-	.reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 0, .size = 4 },
-};
-
-static struct clksrc_clk clk_sclk_uart1 = {
-	.clk		= {
-		.name		= "uclk1",
-		.devname	= "exynos4210-uart.1",
-		.enable		= exynos4_clksrc_mask_peril0_ctrl,
-		.ctrlbit	= (1 << 4),
-	},
-	.sources = &clkset_group,
-	.reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 4, .size = 4 },
-	.reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 4, .size = 4 },
-};
-
-static struct clksrc_clk clk_sclk_uart2 = {
-	.clk		= {
-		.name		= "uclk1",
-		.devname	= "exynos4210-uart.2",
-		.enable		= exynos4_clksrc_mask_peril0_ctrl,
-		.ctrlbit	= (1 << 8),
-	},
-	.sources = &clkset_group,
-	.reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 8, .size = 4 },
-	.reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 8, .size = 4 },
-};
-
-static struct clksrc_clk clk_sclk_uart3 = {
-	.clk		= {
-		.name		= "uclk1",
-		.devname	= "exynos4210-uart.3",
-		.enable		= exynos4_clksrc_mask_peril0_ctrl,
-		.ctrlbit	= (1 << 12),
-	},
-	.sources = &clkset_group,
-	.reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 12, .size = 4 },
-	.reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 12, .size = 4 },
-};
-
-static struct clksrc_clk clk_sclk_mmc0 = {
-	.clk		= {
-		.name		= "sclk_mmc",
-		.devname	= "s3c-sdhci.0",
-		.parent		= &clk_dout_mmc0.clk,
-		.enable		= exynos4_clksrc_mask_fsys_ctrl,
-		.ctrlbit	= (1 << 0),
-	},
-	.reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 8, .size = 8 },
-};
-
-static struct clksrc_clk clk_sclk_mmc1 = {
-	.clk		= {
-		.name		= "sclk_mmc",
-		.devname	= "s3c-sdhci.1",
-		.parent         = &clk_dout_mmc1.clk,
-		.enable		= exynos4_clksrc_mask_fsys_ctrl,
-		.ctrlbit	= (1 << 4),
-	},
-	.reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 24, .size = 8 },
-};
-
-static struct clksrc_clk clk_sclk_mmc2 = {
-	.clk		= {
-		.name		= "sclk_mmc",
-		.devname	= "s3c-sdhci.2",
-		.parent         = &clk_dout_mmc2.clk,
-		.enable		= exynos4_clksrc_mask_fsys_ctrl,
-		.ctrlbit	= (1 << 8),
-	},
-	.reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 8, .size = 8 },
-};
-
-static struct clksrc_clk clk_sclk_mmc3 = {
-	.clk		= {
-		.name		= "sclk_mmc",
-		.devname	= "s3c-sdhci.3",
-		.parent         = &clk_dout_mmc3.clk,
-		.enable		= exynos4_clksrc_mask_fsys_ctrl,
-		.ctrlbit	= (1 << 12),
-	},
-	.reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 24, .size = 8 },
-};
-
-static struct clksrc_clk clk_sclk_spi0 = {
-	.clk		= {
-		.name		= "sclk_spi",
-		.devname		= "s3c64xx-spi.0",
-		.enable		= exynos4_clksrc_mask_peril1_ctrl,
-		.ctrlbit		= (1 << 16),
-	},
-	.sources = &clkset_group,
-	.reg_src = { .reg = S5P_CLKSRC_PERIL1, .shift = 16, .size = 4 },
-	.reg_div = { .reg = S5P_CLKDIV_PERIL1, .shift = 0, .size = 4 },
-};
-
-static struct clksrc_clk clk_sclk_spi1 = {
-	.clk		= {
-		.name		= "sclk_spi",
-		.devname		= "s3c64xx-spi.1",
-		.enable		= exynos4_clksrc_mask_peril1_ctrl,
-		.ctrlbit		= (1 << 20),
-	},
-	.sources = &clkset_group,
-	.reg_src = { .reg = S5P_CLKSRC_PERIL1, .shift = 20, .size = 4 },
-	.reg_div = { .reg = S5P_CLKDIV_PERIL1, .shift = 16, .size = 4 },
-};
-
-static struct clksrc_clk clk_sclk_spi2 = {
-	.clk		= {
-		.name		= "sclk_spi",
-		.devname		= "s3c64xx-spi.2",
-		.enable		= exynos4_clksrc_mask_peril1_ctrl,
-		.ctrlbit		= (1 << 24),
-	},
-	.sources = &clkset_group,
-	.reg_src = { .reg = S5P_CLKSRC_PERIL1, .shift = 24, .size = 4 },
-	.reg_div = { .reg = S5P_CLKDIV_PERIL2, .shift = 0, .size = 4 },
-};
-
-/* Clock initialization code */
-static struct clksrc_clk *sysclks[] = {
-	&clk_mout_apll,
-	&clk_sclk_apll,
-	&clk_mout_epll,
-	&clk_mout_mpll,
-	&clk_moutcore,
-	&clk_coreclk,
-	&clk_armclk,
-	&clk_aclk_corem0,
-	&clk_aclk_cores,
-	&clk_aclk_corem1,
-	&clk_periphclk,
-	&clk_mout_corebus,
-	&clk_sclk_dmc,
-	&clk_aclk_cored,
-	&clk_aclk_corep,
-	&clk_aclk_acp,
-	&clk_pclk_acp,
-	&clk_vpllsrc,
-	&clk_sclk_vpll,
-	&clk_aclk_200,
-	&clk_aclk_100,
-	&clk_aclk_160,
-	&clk_aclk_133,
-	&clk_dout_mmc0,
-	&clk_dout_mmc1,
-	&clk_dout_mmc2,
-	&clk_dout_mmc3,
-	&clk_dout_mmc4,
-	&clk_mout_mfc0,
-	&clk_mout_mfc1,
-};
-
-static struct clk *clk_cdev[] = {
-	&clk_pdma0,
-	&clk_pdma1,
-};
-
-static struct clksrc_clk *clksrc_cdev[] = {
-	&clk_sclk_uart0,
-	&clk_sclk_uart1,
-	&clk_sclk_uart2,
-	&clk_sclk_uart3,
-	&clk_sclk_mmc0,
-	&clk_sclk_mmc1,
-	&clk_sclk_mmc2,
-	&clk_sclk_mmc3,
-	&clk_sclk_spi0,
-	&clk_sclk_spi1,
-	&clk_sclk_spi2,
-
-};
-
-static struct clk_lookup exynos4_clk_lookup[] = {
-	CLKDEV_INIT("exynos4210-uart.0", "clk_uart_baud0", &clk_sclk_uart0.clk),
-	CLKDEV_INIT("exynos4210-uart.1", "clk_uart_baud0", &clk_sclk_uart1.clk),
-	CLKDEV_INIT("exynos4210-uart.2", "clk_uart_baud0", &clk_sclk_uart2.clk),
-	CLKDEV_INIT("exynos4210-uart.3", "clk_uart_baud0", &clk_sclk_uart3.clk),
-	CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &clk_sclk_mmc0.clk),
-	CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_sclk_mmc1.clk),
-	CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
-	CLKDEV_INIT("s3c-sdhci.3", "mmc_busclk.2", &clk_sclk_mmc3.clk),
-	CLKDEV_INIT("dma-pl330.0", "apb_pclk", &clk_pdma0),
-	CLKDEV_INIT("dma-pl330.1", "apb_pclk", &clk_pdma1),
-	CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk0", &clk_sclk_spi0.clk),
-	CLKDEV_INIT("s3c64xx-spi.1", "spi_busclk0", &clk_sclk_spi1.clk),
-	CLKDEV_INIT("s3c64xx-spi.2", "spi_busclk0", &clk_sclk_spi2.clk),
-};
-
-static int xtal_rate;
-
-static unsigned long exynos4_fout_apll_get_rate(struct clk *clk)
-{
-	if (soc_is_exynos4210())
-		return s5p_get_pll45xx(xtal_rate, __raw_readl(S5P_APLL_CON0),
-					pll_4508);
-	else if (soc_is_exynos4212() || soc_is_exynos4412())
-		return s5p_get_pll35xx(xtal_rate, __raw_readl(S5P_APLL_CON0));
-	else
-		return 0;
-}
-
-static struct clk_ops exynos4_fout_apll_ops = {
-	.get_rate = exynos4_fout_apll_get_rate,
-};
-
-static u32 vpll_div[][8] = {
-	{  54000000, 3, 53, 3, 1024, 0, 17, 0 },
-	{ 108000000, 3, 53, 2, 1024, 0, 17, 0 },
-};
-
-static unsigned long exynos4_vpll_get_rate(struct clk *clk)
-{
-	return clk->rate;
-}
-
-static int exynos4_vpll_set_rate(struct clk *clk, unsigned long rate)
-{
-	unsigned int vpll_con0, vpll_con1 = 0;
-	unsigned int i;
-
-	/* Return if nothing changed */
-	if (clk->rate == rate)
-		return 0;
-
-	vpll_con0 = __raw_readl(S5P_VPLL_CON0);
-	vpll_con0 &= ~(0x1 << 27 |					\
-			PLL90XX_MDIV_MASK << PLL46XX_MDIV_SHIFT |	\
-			PLL90XX_PDIV_MASK << PLL46XX_PDIV_SHIFT |	\
-			PLL90XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
-
-	vpll_con1 = __raw_readl(S5P_VPLL_CON1);
-	vpll_con1 &= ~(PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT |	\
-			PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT |	\
-			PLL4650C_KDIV_MASK << PLL46XX_KDIV_SHIFT);
-
-	for (i = 0; i < ARRAY_SIZE(vpll_div); i++) {
-		if (vpll_div[i][0] == rate) {
-			vpll_con0 |= vpll_div[i][1] << PLL46XX_PDIV_SHIFT;
-			vpll_con0 |= vpll_div[i][2] << PLL46XX_MDIV_SHIFT;
-			vpll_con0 |= vpll_div[i][3] << PLL46XX_SDIV_SHIFT;
-			vpll_con1 |= vpll_div[i][4] << PLL46XX_KDIV_SHIFT;
-			vpll_con1 |= vpll_div[i][5] << PLL46XX_MFR_SHIFT;
-			vpll_con1 |= vpll_div[i][6] << PLL46XX_MRR_SHIFT;
-			vpll_con0 |= vpll_div[i][7] << 27;
-			break;
-		}
-	}
-
-	if (i == ARRAY_SIZE(vpll_div)) {
-		printk(KERN_ERR "%s: Invalid Clock VPLL Frequency\n",
-				__func__);
-		return -EINVAL;
-	}
-
-	__raw_writel(vpll_con0, S5P_VPLL_CON0);
-	__raw_writel(vpll_con1, S5P_VPLL_CON1);
-
-	/* Wait for VPLL lock */
-	while (!(__raw_readl(S5P_VPLL_CON0) & (1 << PLL46XX_LOCKED_SHIFT)))
-		continue;
-
-	clk->rate = rate;
-	return 0;
-}
-
-static struct clk_ops exynos4_vpll_ops = {
-	.get_rate = exynos4_vpll_get_rate,
-	.set_rate = exynos4_vpll_set_rate,
-};
-
-void __init_or_cpufreq exynos4_setup_clocks(void)
-{
-	struct clk *xtal_clk;
-	unsigned long apll = 0;
-	unsigned long mpll = 0;
-	unsigned long epll = 0;
-	unsigned long vpll = 0;
-	unsigned long vpllsrc;
-	unsigned long xtal;
-	unsigned long armclk;
-	unsigned long sclk_dmc;
-	unsigned long aclk_200;
-	unsigned long aclk_100;
-	unsigned long aclk_160;
-	unsigned long aclk_133;
-	unsigned int ptr;
-
-	printk(KERN_DEBUG "%s: registering clocks\n", __func__);
-
-	xtal_clk = clk_get(NULL, "xtal");
-	BUG_ON(IS_ERR(xtal_clk));
-
-	xtal = clk_get_rate(xtal_clk);
-
-	xtal_rate = xtal;
-
-	clk_put(xtal_clk);
-
-	printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
-
-	if (soc_is_exynos4210()) {
-		apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON0),
-					pll_4508);
-		mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON0),
-					pll_4508);
-		epll = s5p_get_pll46xx(xtal, __raw_readl(S5P_EPLL_CON0),
-					__raw_readl(S5P_EPLL_CON1), pll_4600);
-
-		vpllsrc = clk_get_rate(&clk_vpllsrc.clk);
-		vpll = s5p_get_pll46xx(vpllsrc, __raw_readl(S5P_VPLL_CON0),
-					__raw_readl(S5P_VPLL_CON1), pll_4650c);
-	} else if (soc_is_exynos4212() || soc_is_exynos4412()) {
-		apll = s5p_get_pll35xx(xtal, __raw_readl(S5P_APLL_CON0));
-		mpll = s5p_get_pll35xx(xtal, __raw_readl(S5P_MPLL_CON0));
-		epll = s5p_get_pll36xx(xtal, __raw_readl(S5P_EPLL_CON0),
-					__raw_readl(S5P_EPLL_CON1));
-
-		vpllsrc = clk_get_rate(&clk_vpllsrc.clk);
-		vpll = s5p_get_pll36xx(vpllsrc, __raw_readl(S5P_VPLL_CON0),
-					__raw_readl(S5P_VPLL_CON1));
-	} else {
-		/* nothing */
-	}
-
-	clk_fout_apll.ops = &exynos4_fout_apll_ops;
-	clk_fout_mpll.rate = mpll;
-	clk_fout_epll.rate = epll;
-	clk_fout_vpll.ops = &exynos4_vpll_ops;
-	clk_fout_vpll.rate = vpll;
-
-	printk(KERN_INFO "EXYNOS4: PLL settings, A=%ld, M=%ld, E=%ld V=%ld",
-			apll, mpll, epll, vpll);
-
-	armclk = clk_get_rate(&clk_armclk.clk);
-	sclk_dmc = clk_get_rate(&clk_sclk_dmc.clk);
-
-	aclk_200 = clk_get_rate(&clk_aclk_200.clk);
-	aclk_100 = clk_get_rate(&clk_aclk_100.clk);
-	aclk_160 = clk_get_rate(&clk_aclk_160.clk);
-	aclk_133 = clk_get_rate(&clk_aclk_133.clk);
-
-	printk(KERN_INFO "EXYNOS4: ARMCLK=%ld, DMC=%ld, ACLK200=%ld\n"
-			 "ACLK100=%ld, ACLK160=%ld, ACLK133=%ld\n",
-			armclk, sclk_dmc, aclk_200,
-			aclk_100, aclk_160, aclk_133);
-
-	clk_f.rate = armclk;
-	clk_h.rate = sclk_dmc;
-	clk_p.rate = aclk_100;
-
-	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
-		s3c_set_clksrc(&clksrcs[ptr], true);
-}
-
-static struct clk *clks[] __initdata = {
-	&clk_sclk_hdmi27m,
-	&clk_sclk_hdmiphy,
-	&clk_sclk_usbphy0,
-	&clk_sclk_usbphy1,
-};
-
-#ifdef CONFIG_PM_SLEEP
-static int exynos4_clock_suspend(void)
-{
-	s3c_pm_do_save(exynos4_clock_save, ARRAY_SIZE(exynos4_clock_save));
-	return 0;
-}
-
-static void exynos4_clock_resume(void)
-{
-	s3c_pm_do_restore_core(exynos4_clock_save, ARRAY_SIZE(exynos4_clock_save));
-}
-
-#else
-#define exynos4_clock_suspend NULL
-#define exynos4_clock_resume NULL
-#endif
-
-struct syscore_ops exynos4_clock_syscore_ops = {
-	.suspend	= exynos4_clock_suspend,
-	.resume		= exynos4_clock_resume,
-};
-
-void __init exynos4_register_clocks(void)
-{
-	int ptr;
-
-	s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
-
-	for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
-		s3c_register_clksrc(sysclks[ptr], 1);
-
-	for (ptr = 0; ptr < ARRAY_SIZE(sclk_tv); ptr++)
-		s3c_register_clksrc(sclk_tv[ptr], 1);
-
-	for (ptr = 0; ptr < ARRAY_SIZE(clksrc_cdev); ptr++)
-		s3c_register_clksrc(clksrc_cdev[ptr], 1);
-
-	s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
-	s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
-
-	s3c24xx_register_clocks(clk_cdev, ARRAY_SIZE(clk_cdev));
-	for (ptr = 0; ptr < ARRAY_SIZE(clk_cdev); ptr++)
-		s3c_disable_clocks(clk_cdev[ptr], 1);
-
-	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-	clkdev_add_table(exynos4_clk_lookup, ARRAY_SIZE(exynos4_clk_lookup));
-
-	register_syscore_ops(&exynos4_clock_syscore_ops);
-	s3c24xx_register_clock(&dummy_apb_pclk);
-
-	s3c_pwmclk_init();
-}
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index 6de298c..8614aab 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -26,10 +26,12 @@
 #include <asm/hardware/gic.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
+#include <asm/cacheflush.h>
 
 #include <mach/regs-irq.h>
 #include <mach/regs-pmu.h>
 #include <mach/regs-gpio.h>
+#include <mach/pmu.h>
 
 #include <plat/cpu.h>
 #include <plat/clock.h>
@@ -45,10 +47,20 @@
 #include <plat/regs-serial.h>
 
 #include "common.h"
+#define L2_AUX_VAL 0x7C470001
+#define L2_AUX_MASK 0xC200ffff
 
 static const char name_exynos4210[] = "EXYNOS4210";
 static const char name_exynos4212[] = "EXYNOS4212";
 static const char name_exynos4412[] = "EXYNOS4412";
+static const char name_exynos5250[] = "EXYNOS5250";
+
+static void exynos4_map_io(void);
+static void exynos5_map_io(void);
+static void exynos4_init_clocks(int xtal);
+static void exynos5_init_clocks(int xtal);
+static void exynos_init_uarts(struct s3c2410_uartcfg *cfg, int no);
+static int exynos_init(void);
 
 static struct cpu_table cpu_ids[] __initdata = {
 	{
@@ -56,7 +68,7 @@
 		.idmask		= EXYNOS4_CPU_MASK,
 		.map_io		= exynos4_map_io,
 		.init_clocks	= exynos4_init_clocks,
-		.init_uarts	= exynos4_init_uarts,
+		.init_uarts	= exynos_init_uarts,
 		.init		= exynos_init,
 		.name		= name_exynos4210,
 	}, {
@@ -64,7 +76,7 @@
 		.idmask		= EXYNOS4_CPU_MASK,
 		.map_io		= exynos4_map_io,
 		.init_clocks	= exynos4_init_clocks,
-		.init_uarts	= exynos4_init_uarts,
+		.init_uarts	= exynos_init_uarts,
 		.init		= exynos_init,
 		.name		= name_exynos4212,
 	}, {
@@ -72,9 +84,17 @@
 		.idmask		= EXYNOS4_CPU_MASK,
 		.map_io		= exynos4_map_io,
 		.init_clocks	= exynos4_init_clocks,
-		.init_uarts	= exynos4_init_uarts,
+		.init_uarts	= exynos_init_uarts,
 		.init		= exynos_init,
 		.name		= name_exynos4412,
+	}, {
+		.idcode		= EXYNOS5250_SOC_ID,
+		.idmask		= EXYNOS5_SOC_MASK,
+		.map_io		= exynos5_map_io,
+		.init_clocks	= exynos5_init_clocks,
+		.init_uarts	= exynos_init_uarts,
+		.init		= exynos_init,
+		.name		= name_exynos5250,
 	},
 };
 
@@ -83,10 +103,14 @@
 static struct map_desc exynos_iodesc[] __initdata = {
 	{
 		.virtual	= (unsigned long)S5P_VA_CHIPID,
-		.pfn		= __phys_to_pfn(EXYNOS4_PA_CHIPID),
+		.pfn		= __phys_to_pfn(EXYNOS_PA_CHIPID),
 		.length		= SZ_4K,
 		.type		= MT_DEVICE,
-	}, {
+	},
+};
+
+static struct map_desc exynos4_iodesc[] __initdata = {
+	{
 		.virtual	= (unsigned long)S3C_VA_SYS,
 		.pfn		= __phys_to_pfn(EXYNOS4_PA_SYSCON),
 		.length		= SZ_64K,
@@ -136,11 +160,7 @@
 		.pfn		= __phys_to_pfn(EXYNOS4_PA_UART),
 		.length		= SZ_512K,
 		.type		= MT_DEVICE,
-	},
-};
-
-static struct map_desc exynos4_iodesc[] __initdata = {
-	{
+	}, {
 		.virtual	= (unsigned long)S5P_VA_CMU,
 		.pfn		= __phys_to_pfn(EXYNOS4_PA_CMU),
 		.length		= SZ_128K,
@@ -156,24 +176,14 @@
 		.length		= SZ_4K,
 		.type		= MT_DEVICE,
 	}, {
-		.virtual	= (unsigned long)S5P_VA_GPIO1,
-		.pfn		= __phys_to_pfn(EXYNOS4_PA_GPIO1),
-		.length		= SZ_4K,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= (unsigned long)S5P_VA_GPIO2,
-		.pfn		= __phys_to_pfn(EXYNOS4_PA_GPIO2),
-		.length		= SZ_4K,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= (unsigned long)S5P_VA_GPIO3,
-		.pfn		= __phys_to_pfn(EXYNOS4_PA_GPIO3),
-		.length		= SZ_256,
-		.type		= MT_DEVICE,
-	}, {
 		.virtual	= (unsigned long)S5P_VA_DMC0,
 		.pfn		= __phys_to_pfn(EXYNOS4_PA_DMC0),
-		.length		= SZ_4K,
+		.length		= SZ_64K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_DMC1,
+		.pfn		= __phys_to_pfn(EXYNOS4_PA_DMC1),
+		.length		= SZ_64K,
 		.type		= MT_DEVICE,
 	}, {
 		.virtual	= (unsigned long)S3C_VA_USB_HSPHY,
@@ -201,19 +211,80 @@
 	},
 };
 
-static void exynos_idle(void)
-{
-	if (!need_resched())
-		cpu_do_idle();
-
-	local_irq_enable();
-}
+static struct map_desc exynos5_iodesc[] __initdata = {
+	{
+		.virtual	= (unsigned long)S3C_VA_SYS,
+		.pfn		= __phys_to_pfn(EXYNOS5_PA_SYSCON),
+		.length		= SZ_64K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S3C_VA_TIMER,
+		.pfn		= __phys_to_pfn(EXYNOS5_PA_TIMER),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S3C_VA_WATCHDOG,
+		.pfn		= __phys_to_pfn(EXYNOS5_PA_WATCHDOG),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_SROMC,
+		.pfn		= __phys_to_pfn(EXYNOS5_PA_SROMC),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_SYSTIMER,
+		.pfn		= __phys_to_pfn(EXYNOS5_PA_SYSTIMER),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_SYSRAM,
+		.pfn		= __phys_to_pfn(EXYNOS5_PA_SYSRAM),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_CMU,
+		.pfn		= __phys_to_pfn(EXYNOS5_PA_CMU),
+		.length		= 144 * SZ_1K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_PMU,
+		.pfn		= __phys_to_pfn(EXYNOS5_PA_PMU),
+		.length		= SZ_64K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_COMBINER_BASE,
+		.pfn		= __phys_to_pfn(EXYNOS5_PA_COMBINER),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S3C_VA_UART,
+		.pfn		= __phys_to_pfn(EXYNOS5_PA_UART),
+		.length		= SZ_512K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_GIC_CPU,
+		.pfn		= __phys_to_pfn(EXYNOS5_PA_GIC_CPU),
+		.length		= SZ_64K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_GIC_DIST,
+		.pfn		= __phys_to_pfn(EXYNOS5_PA_GIC_DIST),
+		.length		= SZ_64K,
+		.type		= MT_DEVICE,
+	},
+};
 
 void exynos4_restart(char mode, const char *cmd)
 {
 	__raw_writel(0x1, S5P_SWRESET);
 }
 
+void exynos5_restart(char mode, const char *cmd)
+{
+	__raw_writel(0x1, EXYNOS_SWRESET);
+}
+
 /*
  * exynos_map_io
  *
@@ -233,7 +304,7 @@
 	s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids));
 }
 
-void __init exynos4_map_io(void)
+static void __init exynos4_map_io(void)
 {
 	iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc));
 
@@ -264,7 +335,22 @@
 	s5p_hdmi_setname("exynos4-hdmi");
 }
 
-void __init exynos4_init_clocks(int xtal)
+static void __init exynos5_map_io(void)
+{
+	iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc));
+
+	s3c_device_i2c0.resource[0].start = EXYNOS5_PA_IIC(0);
+	s3c_device_i2c0.resource[0].end   = EXYNOS5_PA_IIC(0) + SZ_4K - 1;
+	s3c_device_i2c0.resource[1].start = EXYNOS5_IRQ_IIC;
+	s3c_device_i2c0.resource[1].end   = EXYNOS5_IRQ_IIC;
+
+	/* The I2C bus controllers are directly compatible with s3c2440 */
+	s3c_i2c0_setname("s3c2440-i2c");
+	s3c_i2c1_setname("s3c2440-i2c");
+	s3c_i2c2_setname("s3c2440-i2c");
+}
+
+static void __init exynos4_init_clocks(int xtal)
 {
 	printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
 
@@ -280,6 +366,17 @@
 	exynos4_setup_clocks();
 }
 
+static void __init exynos5_init_clocks(int xtal)
+{
+	printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
+
+	s3c24xx_register_baseclocks(xtal);
+	s5p_register_clocks(xtal);
+
+	exynos5_register_clocks();
+	exynos5_setup_clocks();
+}
+
 #define COMBINER_ENABLE_SET	0x0
 #define COMBINER_ENABLE_CLEAR	0x4
 #define COMBINER_INT_STATUS	0xC
@@ -353,7 +450,14 @@
 
 static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
 {
-	if (combiner_nr >= MAX_COMBINER_NR)
+	unsigned int max_nr;
+
+	if (soc_is_exynos5250())
+		max_nr = EXYNOS5_MAX_COMBINER_NR;
+	else
+		max_nr = EXYNOS4_MAX_COMBINER_NR;
+
+	if (combiner_nr >= max_nr)
 		BUG();
 	if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0)
 		BUG();
@@ -364,8 +468,14 @@
 			  unsigned int irq_start)
 {
 	unsigned int i;
+	unsigned int max_nr;
 
-	if (combiner_nr >= MAX_COMBINER_NR)
+	if (soc_is_exynos5250())
+		max_nr = EXYNOS5_MAX_COMBINER_NR;
+	else
+		max_nr = EXYNOS4_MAX_COMBINER_NR;
+
+	if (combiner_nr >= max_nr)
 		BUG();
 
 	combiner_data[combiner_nr].base = base;
@@ -408,7 +518,7 @@
 		of_irq_init(exynos4_dt_irq_match);
 #endif
 
-	for (irq = 0; irq < MAX_COMBINER_NR; irq++) {
+	for (irq = 0; irq < EXYNOS4_MAX_COMBINER_NR; irq++) {
 
 		combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
 				COMBINER_IRQ(irq, 0));
@@ -423,60 +533,145 @@
 	s5p_init_irq(NULL, 0);
 }
 
+void __init exynos5_init_irq(void)
+{
+	int irq;
+
+	gic_init(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU);
+
+	for (irq = 0; irq < EXYNOS5_MAX_COMBINER_NR; irq++) {
+		combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
+				COMBINER_IRQ(irq, 0));
+		combiner_cascade_irq(irq, IRQ_SPI(irq));
+	}
+
+	/*
+	 * The parameters of s5p_init_irq() are for VIC init.
+	 * Theses parameters should be NULL and 0 because EXYNOS4
+	 * uses GIC instead of VIC.
+	 */
+	s5p_init_irq(NULL, 0);
+}
+
 struct bus_type exynos4_subsys = {
 	.name		= "exynos4-core",
 	.dev_name	= "exynos4-core",
 };
 
+struct bus_type exynos5_subsys = {
+	.name		= "exynos5-core",
+	.dev_name	= "exynos5-core",
+};
+
 static struct device exynos4_dev = {
 	.bus	= &exynos4_subsys,
 };
 
-static int __init exynos4_core_init(void)
+static struct device exynos5_dev = {
+	.bus	= &exynos5_subsys,
+};
+
+static int __init exynos_core_init(void)
 {
-	return subsys_system_register(&exynos4_subsys, NULL);
+	if (soc_is_exynos5250())
+		return subsys_system_register(&exynos5_subsys, NULL);
+	else
+		return subsys_system_register(&exynos4_subsys, NULL);
 }
-core_initcall(exynos4_core_init);
+core_initcall(exynos_core_init);
 
 #ifdef CONFIG_CACHE_L2X0
 static int __init exynos4_l2x0_cache_init(void)
 {
-	/* TAG, Data Latency Control: 2cycle */
-	__raw_writel(0x110, S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
+	int ret;
 
-	if (soc_is_exynos4210())
-		__raw_writel(0x110, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
-	else if (soc_is_exynos4212() || soc_is_exynos4412())
-		__raw_writel(0x120, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
+	if (soc_is_exynos5250())
+		return 0;
 
-	/* L2X0 Prefetch Control */
-	__raw_writel(0x30000007, S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
+	ret = l2x0_of_init(L2_AUX_VAL, L2_AUX_MASK);
+	if (!ret) {
+		l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
+		clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long));
+		return 0;
+	}
 
-	/* L2X0 Power Control */
-	__raw_writel(L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN,
-		     S5P_VA_L2CC + L2X0_POWER_CTRL);
+	if (!(__raw_readl(S5P_VA_L2CC + L2X0_CTRL) & 0x1)) {
+		l2x0_saved_regs.phy_base = EXYNOS4_PA_L2CC;
+		/* TAG, Data Latency Control: 2 cycles */
+		l2x0_saved_regs.tag_latency = 0x110;
 
-	l2x0_init(S5P_VA_L2CC, 0x7C470001, 0xC200ffff);
+		if (soc_is_exynos4212() || soc_is_exynos4412())
+			l2x0_saved_regs.data_latency = 0x120;
+		else
+			l2x0_saved_regs.data_latency = 0x110;
 
+		l2x0_saved_regs.prefetch_ctrl = 0x30000007;
+		l2x0_saved_regs.pwr_ctrl =
+			(L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN);
+
+		l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
+
+		__raw_writel(l2x0_saved_regs.tag_latency,
+				S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
+		__raw_writel(l2x0_saved_regs.data_latency,
+				S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
+
+		/* L2X0 Prefetch Control */
+		__raw_writel(l2x0_saved_regs.prefetch_ctrl,
+				S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
+
+		/* L2X0 Power Control */
+		__raw_writel(l2x0_saved_regs.pwr_ctrl,
+				S5P_VA_L2CC + L2X0_POWER_CTRL);
+
+		clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long));
+		clean_dcache_area(&l2x0_saved_regs, sizeof(struct l2x0_regs));
+	}
+
+	l2x0_init(S5P_VA_L2CC, L2_AUX_VAL, L2_AUX_MASK);
 	return 0;
 }
-
 early_initcall(exynos4_l2x0_cache_init);
 #endif
 
-int __init exynos_init(void)
+static int __init exynos5_l2_cache_init(void)
+{
+	unsigned int val;
+
+	if (!soc_is_exynos5250())
+		return 0;
+
+	asm volatile("mrc p15, 0, %0, c1, c0, 0\n"
+		     "bic %0, %0, #(1 << 2)\n"	/* cache disable */
+		     "mcr p15, 0, %0, c1, c0, 0\n"
+		     "mrc p15, 1, %0, c9, c0, 2\n"
+		     : "=r"(val));
+
+	val |= (1 << 9) | (1 << 5) | (2 << 6) | (2 << 0);
+
+	asm volatile("mcr p15, 1, %0, c9, c0, 2\n" : : "r"(val));
+	asm volatile("mrc p15, 0, %0, c1, c0, 0\n"
+		     "orr %0, %0, #(1 << 2)\n"	/* cache enable */
+		     "mcr p15, 0, %0, c1, c0, 0\n"
+		     : : "r"(val));
+
+	return 0;
+}
+early_initcall(exynos5_l2_cache_init);
+
+static int __init exynos_init(void)
 {
 	printk(KERN_INFO "EXYNOS: Initializing architecture\n");
 
-	/* set idle function */
-	pm_idle = exynos_idle;
-
-	return device_register(&exynos4_dev);
+	if (soc_is_exynos5250())
+		return device_register(&exynos5_dev);
+	else
+		return device_register(&exynos4_dev);
 }
 
 /* uart registration process */
 
-void __init exynos4_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+static void __init exynos_init_uarts(struct s3c2410_uartcfg *cfg, int no)
 {
 	struct s3c2410_uartcfg *tcfg = cfg;
 	u32 ucnt;
@@ -484,69 +679,138 @@
 	for (ucnt = 0; ucnt < no; ucnt++, tcfg++)
 		tcfg->has_fracval = 1;
 
-	s3c24xx_init_uartdevs("exynos4210-uart", s5p_uart_resources, cfg, no);
+	if (soc_is_exynos5250())
+		s3c24xx_init_uartdevs("exynos4210-uart", exynos5_uart_resources, cfg, no);
+	else
+		s3c24xx_init_uartdevs("exynos4210-uart", exynos4_uart_resources, cfg, no);
 }
 
+static void __iomem *exynos_eint_base;
+
 static DEFINE_SPINLOCK(eint_lock);
 
 static unsigned int eint0_15_data[16];
 
-static unsigned int exynos4_get_irq_nr(unsigned int number)
+static inline int exynos4_irq_to_gpio(unsigned int irq)
 {
-	u32 ret = 0;
+	if (irq < IRQ_EINT(0))
+		return -EINVAL;
 
-	switch (number) {
-	case 0 ... 3:
-		ret = (number + IRQ_EINT0);
-		break;
-	case 4 ... 7:
-		ret = (number + (IRQ_EINT4 - 4));
-		break;
-	case 8 ... 15:
-		ret = (number + (IRQ_EINT8 - 8));
-		break;
-	default:
-		printk(KERN_ERR "number available : %d\n", number);
-	}
+	irq -= IRQ_EINT(0);
+	if (irq < 8)
+		return EXYNOS4_GPX0(irq);
 
-	return ret;
+	irq -= 8;
+	if (irq < 8)
+		return EXYNOS4_GPX1(irq);
+
+	irq -= 8;
+	if (irq < 8)
+		return EXYNOS4_GPX2(irq);
+
+	irq -= 8;
+	if (irq < 8)
+		return EXYNOS4_GPX3(irq);
+
+	return -EINVAL;
 }
 
-static inline void exynos4_irq_eint_mask(struct irq_data *data)
+static inline int exynos5_irq_to_gpio(unsigned int irq)
+{
+	if (irq < IRQ_EINT(0))
+		return -EINVAL;
+
+	irq -= IRQ_EINT(0);
+	if (irq < 8)
+		return EXYNOS5_GPX0(irq);
+
+	irq -= 8;
+	if (irq < 8)
+		return EXYNOS5_GPX1(irq);
+
+	irq -= 8;
+	if (irq < 8)
+		return EXYNOS5_GPX2(irq);
+
+	irq -= 8;
+	if (irq < 8)
+		return EXYNOS5_GPX3(irq);
+
+	return -EINVAL;
+}
+
+static unsigned int exynos4_eint0_15_src_int[16] = {
+	EXYNOS4_IRQ_EINT0,
+	EXYNOS4_IRQ_EINT1,
+	EXYNOS4_IRQ_EINT2,
+	EXYNOS4_IRQ_EINT3,
+	EXYNOS4_IRQ_EINT4,
+	EXYNOS4_IRQ_EINT5,
+	EXYNOS4_IRQ_EINT6,
+	EXYNOS4_IRQ_EINT7,
+	EXYNOS4_IRQ_EINT8,
+	EXYNOS4_IRQ_EINT9,
+	EXYNOS4_IRQ_EINT10,
+	EXYNOS4_IRQ_EINT11,
+	EXYNOS4_IRQ_EINT12,
+	EXYNOS4_IRQ_EINT13,
+	EXYNOS4_IRQ_EINT14,
+	EXYNOS4_IRQ_EINT15,
+};
+
+static unsigned int exynos5_eint0_15_src_int[16] = {
+	EXYNOS5_IRQ_EINT0,
+	EXYNOS5_IRQ_EINT1,
+	EXYNOS5_IRQ_EINT2,
+	EXYNOS5_IRQ_EINT3,
+	EXYNOS5_IRQ_EINT4,
+	EXYNOS5_IRQ_EINT5,
+	EXYNOS5_IRQ_EINT6,
+	EXYNOS5_IRQ_EINT7,
+	EXYNOS5_IRQ_EINT8,
+	EXYNOS5_IRQ_EINT9,
+	EXYNOS5_IRQ_EINT10,
+	EXYNOS5_IRQ_EINT11,
+	EXYNOS5_IRQ_EINT12,
+	EXYNOS5_IRQ_EINT13,
+	EXYNOS5_IRQ_EINT14,
+	EXYNOS5_IRQ_EINT15,
+};
+static inline void exynos_irq_eint_mask(struct irq_data *data)
 {
 	u32 mask;
 
 	spin_lock(&eint_lock);
-	mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
-	mask |= eint_irq_to_bit(data->irq);
-	__raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
+	mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq));
+	mask |= EINT_OFFSET_BIT(data->irq);
+	__raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq));
 	spin_unlock(&eint_lock);
 }
 
-static void exynos4_irq_eint_unmask(struct irq_data *data)
+static void exynos_irq_eint_unmask(struct irq_data *data)
 {
 	u32 mask;
 
 	spin_lock(&eint_lock);
-	mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
-	mask &= ~(eint_irq_to_bit(data->irq));
-	__raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
+	mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq));
+	mask &= ~(EINT_OFFSET_BIT(data->irq));
+	__raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq));
 	spin_unlock(&eint_lock);
 }
 
-static inline void exynos4_irq_eint_ack(struct irq_data *data)
+static inline void exynos_irq_eint_ack(struct irq_data *data)
 {
-	__raw_writel(eint_irq_to_bit(data->irq),
-		     S5P_EINT_PEND(EINT_REG_NR(data->irq)));
+	__raw_writel(EINT_OFFSET_BIT(data->irq),
+		     EINT_PEND(exynos_eint_base, data->irq));
 }
 
-static void exynos4_irq_eint_maskack(struct irq_data *data)
+static void exynos_irq_eint_maskack(struct irq_data *data)
 {
-	exynos4_irq_eint_mask(data);
-	exynos4_irq_eint_ack(data);
+	exynos_irq_eint_mask(data);
+	exynos_irq_eint_ack(data);
 }
 
-static int exynos4_irq_eint_set_type(struct irq_data *data, unsigned int type)
+static int exynos_irq_eint_set_type(struct irq_data *data, unsigned int type)
 {
 	int offs = EINT_OFFSET(data->irq);
 	int shift;
@@ -583,39 +847,27 @@
 	mask = 0x7 << shift;
 
 	spin_lock(&eint_lock);
-	ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->irq)));
+	ctrl = __raw_readl(EINT_CON(exynos_eint_base, data->irq));
 	ctrl &= ~mask;
 	ctrl |= newvalue << shift;
-	__raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->irq)));
+	__raw_writel(ctrl, EINT_CON(exynos_eint_base, data->irq));
 	spin_unlock(&eint_lock);
 
-	switch (offs) {
-	case 0 ... 7:
-		s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE);
-		break;
-	case 8 ... 15:
-		s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE);
-		break;
-	case 16 ... 23:
-		s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE);
-		break;
-	case 24 ... 31:
-		s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE);
-		break;
-	default:
-		printk(KERN_ERR "No such irq number %d", offs);
-	}
+	if (soc_is_exynos5250())
+		s3c_gpio_cfgpin(exynos5_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf));
+	else
+		s3c_gpio_cfgpin(exynos4_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf));
 
 	return 0;
 }
 
-static struct irq_chip exynos4_irq_eint = {
-	.name		= "exynos4-eint",
-	.irq_mask	= exynos4_irq_eint_mask,
-	.irq_unmask	= exynos4_irq_eint_unmask,
-	.irq_mask_ack	= exynos4_irq_eint_maskack,
-	.irq_ack	= exynos4_irq_eint_ack,
-	.irq_set_type	= exynos4_irq_eint_set_type,
+static struct irq_chip exynos_irq_eint = {
+	.name		= "exynos-eint",
+	.irq_mask	= exynos_irq_eint_mask,
+	.irq_unmask	= exynos_irq_eint_unmask,
+	.irq_mask_ack	= exynos_irq_eint_maskack,
+	.irq_ack	= exynos_irq_eint_ack,
+	.irq_set_type	= exynos_irq_eint_set_type,
 #ifdef CONFIG_PM
 	.irq_set_wake	= s3c_irqext_wake,
 #endif
@@ -630,12 +882,12 @@
  *
  * Each EINT pend/mask registers handle eight of them.
  */
-static inline void exynos4_irq_demux_eint(unsigned int start)
+static inline void exynos_irq_demux_eint(unsigned int start)
 {
 	unsigned int irq;
 
-	u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start)));
-	u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start)));
+	u32 status = __raw_readl(EINT_PEND(exynos_eint_base, start));
+	u32 mask = __raw_readl(EINT_MASK(exynos_eint_base, start));
 
 	status &= ~mask;
 	status &= 0xff;
@@ -647,16 +899,16 @@
 	}
 }
 
-static void exynos4_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
+static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
 {
 	struct irq_chip *chip = irq_get_chip(irq);
 	chained_irq_enter(chip, desc);
-	exynos4_irq_demux_eint(IRQ_EINT(16));
-	exynos4_irq_demux_eint(IRQ_EINT(24));
+	exynos_irq_demux_eint(IRQ_EINT(16));
+	exynos_irq_demux_eint(IRQ_EINT(24));
 	chained_irq_exit(chip, desc);
 }
 
-static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
+static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
 {
 	u32 *irq_data = irq_get_handler_data(irq);
 	struct irq_chip *chip = irq_get_chip(irq);
@@ -673,27 +925,44 @@
 	chained_irq_exit(chip, desc);
 }
 
-int __init exynos4_init_irq_eint(void)
+static int __init exynos_init_irq_eint(void)
 {
 	int irq;
 
+	if (soc_is_exynos5250())
+		exynos_eint_base = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
+	else
+		exynos_eint_base = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
+
+	if (exynos_eint_base == NULL) {
+		pr_err("unable to ioremap for EINT base address\n");
+		return -ENOMEM;
+	}
+
 	for (irq = 0 ; irq <= 31 ; irq++) {
-		irq_set_chip_and_handler(IRQ_EINT(irq), &exynos4_irq_eint,
+		irq_set_chip_and_handler(IRQ_EINT(irq), &exynos_irq_eint,
 					 handle_level_irq);
 		set_irq_flags(IRQ_EINT(irq), IRQF_VALID);
 	}
 
-	irq_set_chained_handler(IRQ_EINT16_31, exynos4_irq_demux_eint16_31);
+	irq_set_chained_handler(EXYNOS_IRQ_EINT16_31, exynos_irq_demux_eint16_31);
 
 	for (irq = 0 ; irq <= 15 ; irq++) {
 		eint0_15_data[irq] = IRQ_EINT(irq);
 
-		irq_set_handler_data(exynos4_get_irq_nr(irq),
-				     &eint0_15_data[irq]);
-		irq_set_chained_handler(exynos4_get_irq_nr(irq),
-					exynos4_irq_eint0_15);
+		if (soc_is_exynos5250()) {
+			irq_set_handler_data(exynos5_eint0_15_src_int[irq],
+					     &eint0_15_data[irq]);
+			irq_set_chained_handler(exynos5_eint0_15_src_int[irq],
+						exynos_irq_eint0_15);
+		} else {
+			irq_set_handler_data(exynos4_eint0_15_src_int[irq],
+					     &eint0_15_data[irq]);
+			irq_set_chained_handler(exynos4_eint0_15_src_int[irq],
+						exynos_irq_eint0_15);
+		}
 	}
 
 	return 0;
 }
-arch_initcall(exynos4_init_irq_eint);
+arch_initcall(exynos_init_irq_eint);
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index 1ac49de..677b546 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -12,30 +12,44 @@
 #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H
 #define __ARCH_ARM_MACH_EXYNOS_COMMON_H
 
+extern struct sys_timer exynos4_timer;
+
 void exynos_init_io(struct map_desc *mach_desc, int size);
 void exynos4_init_irq(void);
+void exynos5_init_irq(void);
+void exynos4_restart(char mode, const char *cmd);
+void exynos5_restart(char mode, const char *cmd);
 
+#ifdef CONFIG_ARCH_EXYNOS4
 void exynos4_register_clocks(void);
 void exynos4_setup_clocks(void);
 
-void exynos4210_register_clocks(void);
-void exynos4212_register_clocks(void);
+#else
+#define exynos4_register_clocks()
+#define exynos4_setup_clocks()
+#endif
 
-void exynos4_restart(char mode, const char *cmd);
-
-extern struct sys_timer exynos4_timer;
-
-#ifdef CONFIG_ARCH_EXYNOS
-extern  int exynos_init(void);
-extern void exynos4_map_io(void);
-extern void exynos4_init_clocks(int xtal);
-extern void exynos4_init_uarts(struct s3c2410_uartcfg *cfg, int no);
+#ifdef CONFIG_ARCH_EXYNOS5
+void exynos5_register_clocks(void);
+void exynos5_setup_clocks(void);
 
 #else
-#define exynos4_init_clocks NULL
-#define exynos4_init_uarts NULL
-#define exynos4_map_io NULL
-#define exynos_init NULL
+#define exynos5_register_clocks()
+#define exynos5_setup_clocks()
+#endif
+
+#ifdef CONFIG_CPU_EXYNOS4210
+void exynos4210_register_clocks(void);
+
+#else
+#define exynos4210_register_clocks()
+#endif
+
+#ifdef CONFIG_SOC_EXYNOS4212
+void exynos4212_register_clocks(void);
+
+#else
+#define exynos4212_register_clocks()
 #endif
 
 #endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */
diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c
index 4ebb382..33ab4e7 100644
--- a/arch/arm/mach-exynos/cpuidle.c
+++ b/arch/arm/mach-exynos/cpuidle.c
@@ -11,25 +11,53 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/cpuidle.h>
+#include <linux/cpu_pm.h>
 #include <linux/io.h>
 #include <linux/export.h>
 #include <linux/time.h>
 
 #include <asm/proc-fns.h>
+#include <asm/smp_scu.h>
+#include <asm/suspend.h>
+#include <asm/unified.h>
+#include <mach/regs-pmu.h>
+#include <mach/pmu.h>
+
+#include <plat/cpu.h>
+
+#define REG_DIRECTGO_ADDR	(samsung_rev() == EXYNOS4210_REV_1_1 ? \
+			S5P_INFORM7 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \
+			(S5P_VA_SYSRAM + 0x24) : S5P_INFORM0))
+#define REG_DIRECTGO_FLAG	(samsung_rev() == EXYNOS4210_REV_1_1 ? \
+			S5P_INFORM6 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \
+			(S5P_VA_SYSRAM + 0x20) : S5P_INFORM1))
+
+#define S5P_CHECK_AFTR		0xFCBA0D10
 
 static int exynos4_enter_idle(struct cpuidle_device *dev,
 			struct cpuidle_driver *drv,
 			      int index);
+static int exynos4_enter_lowpower(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
+				int index);
 
-static struct cpuidle_state exynos4_cpuidle_set[] = {
+static struct cpuidle_state exynos4_cpuidle_set[] __initdata = {
 	[0] = {
 		.enter			= exynos4_enter_idle,
 		.exit_latency		= 1,
 		.target_residency	= 100000,
 		.flags			= CPUIDLE_FLAG_TIME_VALID,
-		.name			= "IDLE",
+		.name			= "C0",
 		.desc			= "ARM clock gating(WFI)",
 	},
+	[1] = {
+		.enter			= exynos4_enter_lowpower,
+		.exit_latency		= 300,
+		.target_residency	= 100000,
+		.flags			= CPUIDLE_FLAG_TIME_VALID,
+		.name			= "C1",
+		.desc			= "ARM power down",
+	},
 };
 
 static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device);
@@ -39,9 +67,102 @@
 	.owner		= THIS_MODULE,
 };
 
+/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */
+static void exynos4_set_wakeupmask(void)
+{
+	__raw_writel(0x0000ff3e, S5P_WAKEUP_MASK);
+}
+
+static unsigned int g_pwr_ctrl, g_diag_reg;
+
+static void save_cpu_arch_register(void)
+{
+	/*read power control register*/
+	asm("mrc p15, 0, %0, c15, c0, 0" : "=r"(g_pwr_ctrl) : : "cc");
+	/*read diagnostic register*/
+	asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc");
+	return;
+}
+
+static void restore_cpu_arch_register(void)
+{
+	/*write power control register*/
+	asm("mcr p15, 0, %0, c15, c0, 0" : : "r"(g_pwr_ctrl) : "cc");
+	/*write diagnostic register*/
+	asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc");
+	return;
+}
+
+static int idle_finisher(unsigned long flags)
+{
+	cpu_do_idle();
+	return 1;
+}
+
+static int exynos4_enter_core0_aftr(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
+				int index)
+{
+	struct timeval before, after;
+	int idle_time;
+	unsigned long tmp;
+
+	local_irq_disable();
+	do_gettimeofday(&before);
+
+	exynos4_set_wakeupmask();
+
+	/* Set value of power down register for aftr mode */
+	exynos4_sys_powerdown_conf(SYS_AFTR);
+
+	__raw_writel(virt_to_phys(s3c_cpu_resume), REG_DIRECTGO_ADDR);
+	__raw_writel(S5P_CHECK_AFTR, REG_DIRECTGO_FLAG);
+
+	save_cpu_arch_register();
+
+	/* Setting Central Sequence Register for power down mode */
+	tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
+	tmp &= ~S5P_CENTRAL_LOWPWR_CFG;
+	__raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
+
+	cpu_pm_enter();
+	cpu_suspend(0, idle_finisher);
+
+#ifdef CONFIG_SMP
+	scu_enable(S5P_VA_SCU);
+#endif
+	cpu_pm_exit();
+
+	restore_cpu_arch_register();
+
+	/*
+	 * If PMU failed while entering sleep mode, WFI will be
+	 * ignored by PMU and then exiting cpu_do_idle().
+	 * S5P_CENTRAL_LOWPWR_CFG bit will not be set automatically
+	 * in this situation.
+	 */
+	tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
+	if (!(tmp & S5P_CENTRAL_LOWPWR_CFG)) {
+		tmp |= S5P_CENTRAL_LOWPWR_CFG;
+		__raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
+	}
+
+	/* Clear wakeup state register */
+	__raw_writel(0x0, S5P_WAKEUP_STAT);
+
+	do_gettimeofday(&after);
+
+	local_irq_enable();
+	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
+		    (after.tv_usec - before.tv_usec);
+
+	dev->last_residency = idle_time;
+	return index;
+}
+
 static int exynos4_enter_idle(struct cpuidle_device *dev,
 				struct cpuidle_driver *drv,
-			      int index)
+				int index)
 {
 	struct timeval before, after;
 	int idle_time;
@@ -60,6 +181,22 @@
 	return index;
 }
 
+static int exynos4_enter_lowpower(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
+				int index)
+{
+	int new_index = index;
+
+	/* This mode only can be entered when other core's are offline */
+	if (num_online_cpus() > 1)
+		new_index = drv->safe_state_index;
+
+	if (new_index == 0)
+		return exynos4_enter_idle(dev, drv, new_index);
+	else
+		return exynos4_enter_core0_aftr(dev, drv, new_index);
+}
+
 static int __init exynos4_init_cpuidle(void)
 {
 	int i, max_cpuidle_state, cpu_id;
@@ -74,19 +211,25 @@
 		memcpy(&drv->states[i], &exynos4_cpuidle_set[i],
 				sizeof(struct cpuidle_state));
 	}
+	drv->safe_state_index = 0;
 	cpuidle_register_driver(&exynos4_idle_driver);
 
 	for_each_cpu(cpu_id, cpu_online_mask) {
 		device = &per_cpu(exynos4_cpuidle_device, cpu_id);
 		device->cpu = cpu_id;
 
-		device->state_count = drv->state_count;
+		if (cpu_id == 0)
+			device->state_count = (sizeof(exynos4_cpuidle_set) /
+					       sizeof(struct cpuidle_state));
+		else
+			device->state_count = 1;	/* Support IDLE only */
 
 		if (cpuidle_register_device(device)) {
 			printk(KERN_ERR "CPUidle register device failed\n,");
 			return -EIO;
 		}
 	}
+
 	return 0;
 }
 device_initcall(exynos4_init_cpuidle);
diff --git a/arch/arm/mach-exynos/dev-ahci.c b/arch/arm/mach-exynos/dev-ahci.c
index f57a3de..50ce5b0 100644
--- a/arch/arm/mach-exynos/dev-ahci.c
+++ b/arch/arm/mach-exynos/dev-ahci.c
@@ -242,8 +242,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= IRQ_SATA,
-		.end	= IRQ_SATA,
+		.start	= EXYNOS4_IRQ_SATA,
+		.end	= EXYNOS4_IRQ_SATA,
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/arm/mach-exynos/dev-audio.c b/arch/arm/mach-exynos/dev-audio.c
index 5a9f9c2e..7199e1a 100644
--- a/arch/arm/mach-exynos/dev-audio.c
+++ b/arch/arm/mach-exynos/dev-audio.c
@@ -304,8 +304,8 @@
 		.flags	= IORESOURCE_DMA,
 	},
 	[4] = {
-		.start	= IRQ_AC97,
-		.end	= IRQ_AC97,
+		.start	= EXYNOS4_IRQ_AC97,
+		.end	= EXYNOS4_IRQ_AC97,
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/arm/mach-exynos/dev-uart.c b/arch/arm/mach-exynos/dev-uart.c
new file mode 100644
index 0000000..2e85c02
--- /dev/null
+++ b/arch/arm/mach-exynos/dev-uart.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Base EXYNOS UART resource and device definitions
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <mach/hardware.h>
+#include <mach/map.h>
+
+#include <plat/devs.h>
+
+#define EXYNOS_UART_RESOURCE(_series, _nr)	\
+static struct resource exynos##_series##_uart##_nr##_resource[] = {	\
+	[0] = DEFINE_RES_MEM(EXYNOS##_series##_PA_UART##_nr, EXYNOS##_series##_SZ_UART),	\
+	[1] = DEFINE_RES_IRQ(EXYNOS##_series##_IRQ_UART##_nr),	\
+};
+
+EXYNOS_UART_RESOURCE(4, 0)
+EXYNOS_UART_RESOURCE(4, 1)
+EXYNOS_UART_RESOURCE(4, 2)
+EXYNOS_UART_RESOURCE(4, 3)
+
+struct s3c24xx_uart_resources exynos4_uart_resources[] __initdata = {
+	[0] = {
+		.resources	= exynos4_uart0_resource,
+		.nr_resources	= ARRAY_SIZE(exynos4_uart0_resource),
+	},
+	[1] = {
+		.resources	= exynos4_uart1_resource,
+		.nr_resources	= ARRAY_SIZE(exynos4_uart1_resource),
+	},
+	[2] = {
+		.resources	= exynos4_uart2_resource,
+		.nr_resources	= ARRAY_SIZE(exynos4_uart2_resource),
+	},
+	[3] = {
+		.resources	= exynos4_uart3_resource,
+		.nr_resources	= ARRAY_SIZE(exynos4_uart3_resource),
+	},
+};
+
+EXYNOS_UART_RESOURCE(5, 0)
+EXYNOS_UART_RESOURCE(5, 1)
+EXYNOS_UART_RESOURCE(5, 2)
+EXYNOS_UART_RESOURCE(5, 3)
+
+struct s3c24xx_uart_resources exynos5_uart_resources[] __initdata = {
+	[0] = {
+		.resources	= exynos5_uart0_resource,
+		.nr_resources	= ARRAY_SIZE(exynos5_uart0_resource),
+	},
+	[1] = {
+		.resources	= exynos5_uart1_resource,
+		.nr_resources	= ARRAY_SIZE(exynos5_uart0_resource),
+	},
+	[2] = {
+		.resources	= exynos5_uart2_resource,
+		.nr_resources	= ARRAY_SIZE(exynos5_uart2_resource),
+	},
+	[3] = {
+		.resources	= exynos5_uart3_resource,
+		.nr_resources	= ARRAY_SIZE(exynos5_uart3_resource),
+	},
+};
diff --git a/arch/arm/mach-exynos/dma.c b/arch/arm/mach-exynos/dma.c
index b10fcd2..69aaa45 100644
--- a/arch/arm/mach-exynos/dma.c
+++ b/arch/arm/mach-exynos/dma.c
@@ -29,14 +29,13 @@
 #include <asm/irq.h>
 #include <plat/devs.h>
 #include <plat/irqs.h>
+#include <plat/cpu.h>
 
 #include <mach/map.h>
 #include <mach/irqs.h>
 #include <mach/dma.h>
 
-static u64 dma_dmamask = DMA_BIT_MASK(32);
-
-u8 pdma0_peri[] = {
+static u8 exynos4210_pdma0_peri[] = {
 	DMACH_PCM0_RX,
 	DMACH_PCM0_TX,
 	DMACH_PCM2_RX,
@@ -69,28 +68,47 @@
 	DMACH_AC97_PCMOUT,
 };
 
-struct dma_pl330_platdata exynos4_pdma0_pdata = {
-	.nr_valid_peri = ARRAY_SIZE(pdma0_peri),
-	.peri_id = pdma0_peri,
+static u8 exynos4212_pdma0_peri[] = {
+	DMACH_PCM0_RX,
+	DMACH_PCM0_TX,
+	DMACH_PCM2_RX,
+	DMACH_PCM2_TX,
+	DMACH_MIPI_HSI0,
+	DMACH_MIPI_HSI1,
+	DMACH_SPI0_RX,
+	DMACH_SPI0_TX,
+	DMACH_SPI2_RX,
+	DMACH_SPI2_TX,
+	DMACH_I2S0S_TX,
+	DMACH_I2S0_RX,
+	DMACH_I2S0_TX,
+	DMACH_I2S2_RX,
+	DMACH_I2S2_TX,
+	DMACH_UART0_RX,
+	DMACH_UART0_TX,
+	DMACH_UART2_RX,
+	DMACH_UART2_TX,
+	DMACH_UART4_RX,
+	DMACH_UART4_TX,
+	DMACH_SLIMBUS0_RX,
+	DMACH_SLIMBUS0_TX,
+	DMACH_SLIMBUS2_RX,
+	DMACH_SLIMBUS2_TX,
+	DMACH_SLIMBUS4_RX,
+	DMACH_SLIMBUS4_TX,
+	DMACH_AC97_MICIN,
+	DMACH_AC97_PCMIN,
+	DMACH_AC97_PCMOUT,
+	DMACH_MIPI_HSI4,
+	DMACH_MIPI_HSI5,
 };
 
-struct amba_device exynos4_device_pdma0 = {
-	.dev = {
-		.init_name = "dma-pl330.0",
-		.dma_mask = &dma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(32),
-		.platform_data = &exynos4_pdma0_pdata,
-	},
-	.res = {
-		.start = EXYNOS4_PA_PDMA0,
-		.end = EXYNOS4_PA_PDMA0 + SZ_4K,
-		.flags = IORESOURCE_MEM,
-	},
-	.irq = {IRQ_PDMA0, NO_IRQ},
-	.periphid = 0x00041330,
-};
+struct dma_pl330_platdata exynos4_pdma0_pdata;
 
-u8 pdma1_peri[] = {
+static AMBA_AHB_DEVICE(exynos4_pdma0, "dma-pl330.0", 0x00041330,
+	EXYNOS4_PA_PDMA0, {EXYNOS4_IRQ_PDMA0}, &exynos4_pdma0_pdata);
+
+static u8 exynos4210_pdma1_peri[] = {
 	DMACH_PCM0_RX,
 	DMACH_PCM0_TX,
 	DMACH_PCM1_RX,
@@ -118,39 +136,94 @@
 	DMACH_SLIMBUS5_TX,
 };
 
-struct dma_pl330_platdata exynos4_pdma1_pdata = {
-	.nr_valid_peri = ARRAY_SIZE(pdma1_peri),
-	.peri_id = pdma1_peri,
+static u8 exynos4212_pdma1_peri[] = {
+	DMACH_PCM0_RX,
+	DMACH_PCM0_TX,
+	DMACH_PCM1_RX,
+	DMACH_PCM1_TX,
+	DMACH_MIPI_HSI2,
+	DMACH_MIPI_HSI3,
+	DMACH_SPI1_RX,
+	DMACH_SPI1_TX,
+	DMACH_I2S0S_TX,
+	DMACH_I2S0_RX,
+	DMACH_I2S0_TX,
+	DMACH_I2S1_RX,
+	DMACH_I2S1_TX,
+	DMACH_UART0_RX,
+	DMACH_UART0_TX,
+	DMACH_UART1_RX,
+	DMACH_UART1_TX,
+	DMACH_UART3_RX,
+	DMACH_UART3_TX,
+	DMACH_SLIMBUS1_RX,
+	DMACH_SLIMBUS1_TX,
+	DMACH_SLIMBUS3_RX,
+	DMACH_SLIMBUS3_TX,
+	DMACH_SLIMBUS5_RX,
+	DMACH_SLIMBUS5_TX,
+	DMACH_SLIMBUS0AUX_RX,
+	DMACH_SLIMBUS0AUX_TX,
+	DMACH_SPDIF,
+	DMACH_MIPI_HSI6,
+	DMACH_MIPI_HSI7,
 };
 
-struct amba_device exynos4_device_pdma1 = {
-	.dev = {
-		.init_name = "dma-pl330.1",
-		.dma_mask = &dma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(32),
-		.platform_data = &exynos4_pdma1_pdata,
-	},
-	.res = {
-		.start = EXYNOS4_PA_PDMA1,
-		.end = EXYNOS4_PA_PDMA1 + SZ_4K,
-		.flags = IORESOURCE_MEM,
-	},
-	.irq = {IRQ_PDMA1, NO_IRQ},
-	.periphid = 0x00041330,
+static struct dma_pl330_platdata exynos4_pdma1_pdata;
+
+static AMBA_AHB_DEVICE(exynos4_pdma1,  "dma-pl330.1", 0x00041330,
+	EXYNOS4_PA_PDMA1, {EXYNOS4_IRQ_PDMA1}, &exynos4_pdma1_pdata);
+
+static u8 mdma_peri[] = {
+	DMACH_MTOM_0,
+	DMACH_MTOM_1,
+	DMACH_MTOM_2,
+	DMACH_MTOM_3,
+	DMACH_MTOM_4,
+	DMACH_MTOM_5,
+	DMACH_MTOM_6,
+	DMACH_MTOM_7,
 };
 
+static struct dma_pl330_platdata exynos4_mdma1_pdata = {
+	.nr_valid_peri = ARRAY_SIZE(mdma_peri),
+	.peri_id = mdma_peri,
+};
+
+static AMBA_AHB_DEVICE(exynos4_mdma1,  "dma-pl330.2", 0x00041330,
+	EXYNOS4_PA_MDMA1, {EXYNOS4_IRQ_MDMA1}, &exynos4_mdma1_pdata);
+
 static int __init exynos4_dma_init(void)
 {
 	if (of_have_populated_dt())
 		return 0;
 
+	if (soc_is_exynos4210()) {
+		exynos4_pdma0_pdata.nr_valid_peri =
+			ARRAY_SIZE(exynos4210_pdma0_peri);
+		exynos4_pdma0_pdata.peri_id = exynos4210_pdma0_peri;
+		exynos4_pdma1_pdata.nr_valid_peri =
+			ARRAY_SIZE(exynos4210_pdma1_peri);
+		exynos4_pdma1_pdata.peri_id = exynos4210_pdma1_peri;
+	} else if (soc_is_exynos4212() || soc_is_exynos4412()) {
+		exynos4_pdma0_pdata.nr_valid_peri =
+			ARRAY_SIZE(exynos4212_pdma0_peri);
+		exynos4_pdma0_pdata.peri_id = exynos4212_pdma0_peri;
+		exynos4_pdma1_pdata.nr_valid_peri =
+			ARRAY_SIZE(exynos4212_pdma1_peri);
+		exynos4_pdma1_pdata.peri_id = exynos4212_pdma1_peri;
+	}
+
 	dma_cap_set(DMA_SLAVE, exynos4_pdma0_pdata.cap_mask);
 	dma_cap_set(DMA_CYCLIC, exynos4_pdma0_pdata.cap_mask);
-	amba_device_register(&exynos4_device_pdma0, &iomem_resource);
+	amba_device_register(&exynos4_pdma0_device, &iomem_resource);
 
 	dma_cap_set(DMA_SLAVE, exynos4_pdma1_pdata.cap_mask);
 	dma_cap_set(DMA_CYCLIC, exynos4_pdma1_pdata.cap_mask);
-	amba_device_register(&exynos4_device_pdma1, &iomem_resource);
+	amba_device_register(&exynos4_pdma1_device, &iomem_resource);
+
+	dma_cap_set(DMA_MEMCPY, exynos4_mdma1_pdata.cap_mask);
+	amba_device_register(&exynos4_mdma1_device, &iomem_resource);
 
 	return 0;
 }
diff --git a/arch/arm/mach-exynos/hotplug.c b/arch/arm/mach-exynos/hotplug.c
index dd1ad55..9c17a0a 100644
--- a/arch/arm/mach-exynos/hotplug.c
+++ b/arch/arm/mach-exynos/hotplug.c
@@ -16,6 +16,7 @@
 #include <linux/io.h>
 
 #include <asm/cacheflush.h>
+#include <asm/cp15.h>
 #include <asm/smp_plat.h>
 
 #include <mach/regs-pmu.h>
diff --git a/arch/arm/mach-exynos/include/mach/cpufreq.h b/arch/arm/mach-exynos/include/mach/cpufreq.h
index 3df27f2..7517c3f 100644
--- a/arch/arm/mach-exynos/include/mach/cpufreq.h
+++ b/arch/arm/mach-exynos/include/mach/cpufreq.h
@@ -32,3 +32,5 @@
 };
 
 extern int exynos4210_cpufreq_init(struct exynos_dvfs_info *);
+extern int exynos4x12_cpufreq_init(struct exynos_dvfs_info *);
+extern int exynos5250_cpufreq_init(struct exynos_dvfs_info *);
diff --git a/arch/arm/mach-exynos/include/mach/debug-macro.S b/arch/arm/mach-exynos/include/mach/debug-macro.S
index 6cacf16..e0c86ea 100644
--- a/arch/arm/mach-exynos/include/mach/debug-macro.S
+++ b/arch/arm/mach-exynos/include/mach/debug-macro.S
@@ -21,8 +21,12 @@
 	 */
 
 	.macro addruart, rp, rv, tmp
-		ldr	\rp, = S3C_PA_UART
-		ldr	\rv, = S3C_VA_UART
+		mrc	p15, 0, \tmp, c0, c0, 0
+		and	\tmp, \tmp, #0xf0
+		teq	\tmp, #0xf0		@@ A15
+		ldreq	\rp, =EXYNOS5_PA_UART
+		movne	\rp, #EXYNOS4_PA_UART	@@ EXYNOS4
+		ldr	\rv, =S3C_VA_UART
 #if CONFIG_DEBUG_S3C_UART != 0
 		add	\rp, \rp, #(0x10000 * CONFIG_DEBUG_S3C_UART)
 		add	\rv, \rv, #(0x10000 * CONFIG_DEBUG_S3C_UART)
diff --git a/arch/arm/mach-exynos/include/mach/entry-macro.S b/arch/arm/mach-exynos/include/mach/entry-macro.S
deleted file mode 100644
index 3ba4f54..0000000
--- a/arch/arm/mach-exynos/include/mach/entry-macro.S
+++ /dev/null
@@ -1,16 +0,0 @@
-/* arch/arm/mach-exynos4/include/mach/entry-macro.S
- *
- * Cloned from arch/arm/mach-realview/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for EXYNOS4 platforms
- *
- * 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.
-*/
-
-		.macro	disable_fiq
-		.endm
-
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
diff --git a/arch/arm/mach-exynos/include/mach/exynos4-clock.h b/arch/arm/mach-exynos/include/mach/exynos4-clock.h
deleted file mode 100644
index a07fcbf..0000000
--- a/arch/arm/mach-exynos/include/mach/exynos4-clock.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * linux/arch/arm/mach-exynos4/include/mach/exynos4-clock.h
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * Header file for exynos4 clock support
- *
- * 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 __ASM_ARCH_CLOCK_H
-#define __ASM_ARCH_CLOCK_H __FILE__
-
-#include <linux/clk.h>
-
-extern struct clk clk_sclk_hdmi27m;
-extern struct clk clk_sclk_usbphy0;
-extern struct clk clk_sclk_usbphy1;
-extern struct clk clk_sclk_hdmiphy;
-
-extern struct clksrc_clk clk_sclk_apll;
-extern struct clksrc_clk clk_mout_mpll;
-extern struct clksrc_clk clk_aclk_133;
-extern struct clksrc_clk clk_mout_epll;
-extern struct clksrc_clk clk_sclk_vpll;
-
-extern struct clk *clkset_corebus_list[];
-extern struct clksrc_sources clkset_mout_corebus;
-
-extern struct clk *clkset_aclk_top_list[];
-extern struct clksrc_sources clkset_aclk;
-
-extern struct clk *clkset_group_list[];
-extern struct clksrc_sources clkset_group;
-
-extern int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable);
-extern int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable);
-extern int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable);
-
-#endif /* __ASM_ARCH_CLOCK_H */
diff --git a/arch/arm/mach-exynos/include/mach/gpio.h b/arch/arm/mach-exynos/include/mach/gpio.h
index 80523ca..d7498af 100644
--- a/arch/arm/mach-exynos/include/mach/gpio.h
+++ b/arch/arm/mach-exynos/include/mach/gpio.h
@@ -1,9 +1,8 @@
-/* linux/arch/arm/mach-exynos4/include/mach/gpio.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com
  *
- * EXYNOS4 - GPIO lib support
+ * EXYNOS - GPIO lib support
  *
  * 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
@@ -13,9 +12,13 @@
 #ifndef __ASM_ARCH_GPIO_H
 #define __ASM_ARCH_GPIO_H __FILE__
 
-/* Practically, GPIO banks up to GPZ are the configurable gpio banks */
+/* Macro for EXYNOS GPIO numbering */
 
-/* GPIO bank sizes */
+#define EXYNOS_GPIO_NEXT(__gpio) \
+	((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
+
+/* EXYNOS4 GPIO bank sizes */
+
 #define EXYNOS4_GPIO_A0_NR	(8)
 #define EXYNOS4_GPIO_A1_NR	(6)
 #define EXYNOS4_GPIO_B_NR	(8)
@@ -54,52 +57,50 @@
 #define EXYNOS4_GPIO_Y6_NR	(8)
 #define EXYNOS4_GPIO_Z_NR	(7)
 
-/* GPIO bank numbers */
+/* EXYNOS4 GPIO bank numbers */
 
-#define EXYNOS4_GPIO_NEXT(__gpio) \
-	((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
-
-enum s5p_gpio_number {
+enum exynos4_gpio_number {
 	EXYNOS4_GPIO_A0_START	= 0,
-	EXYNOS4_GPIO_A1_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_A0),
-	EXYNOS4_GPIO_B_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_A1),
-	EXYNOS4_GPIO_C0_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_B),
-	EXYNOS4_GPIO_C1_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_C0),
-	EXYNOS4_GPIO_D0_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_C1),
-	EXYNOS4_GPIO_D1_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_D0),
-	EXYNOS4_GPIO_E0_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_D1),
-	EXYNOS4_GPIO_E1_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_E0),
-	EXYNOS4_GPIO_E2_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_E1),
-	EXYNOS4_GPIO_E3_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_E2),
-	EXYNOS4_GPIO_E4_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_E3),
-	EXYNOS4_GPIO_F0_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_E4),
-	EXYNOS4_GPIO_F1_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_F0),
-	EXYNOS4_GPIO_F2_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_F1),
-	EXYNOS4_GPIO_F3_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_F2),
-	EXYNOS4_GPIO_J0_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_F3),
-	EXYNOS4_GPIO_J1_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_J0),
-	EXYNOS4_GPIO_K0_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_J1),
-	EXYNOS4_GPIO_K1_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_K0),
-	EXYNOS4_GPIO_K2_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_K1),
-	EXYNOS4_GPIO_K3_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_K2),
-	EXYNOS4_GPIO_L0_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_K3),
-	EXYNOS4_GPIO_L1_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_L0),
-	EXYNOS4_GPIO_L2_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_L1),
-	EXYNOS4_GPIO_X0_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_L2),
-	EXYNOS4_GPIO_X1_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_X0),
-	EXYNOS4_GPIO_X2_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_X1),
-	EXYNOS4_GPIO_X3_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_X2),
-	EXYNOS4_GPIO_Y0_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_X3),
-	EXYNOS4_GPIO_Y1_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y0),
-	EXYNOS4_GPIO_Y2_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y1),
-	EXYNOS4_GPIO_Y3_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y2),
-	EXYNOS4_GPIO_Y4_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y3),
-	EXYNOS4_GPIO_Y5_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y4),
-	EXYNOS4_GPIO_Y6_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y5),
-	EXYNOS4_GPIO_Z_START	= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y6),
+	EXYNOS4_GPIO_A1_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A0),
+	EXYNOS4_GPIO_B_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A1),
+	EXYNOS4_GPIO_C0_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_B),
+	EXYNOS4_GPIO_C1_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_C0),
+	EXYNOS4_GPIO_D0_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_C1),
+	EXYNOS4_GPIO_D1_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_D0),
+	EXYNOS4_GPIO_E0_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_D1),
+	EXYNOS4_GPIO_E1_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_E0),
+	EXYNOS4_GPIO_E2_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_E1),
+	EXYNOS4_GPIO_E3_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_E2),
+	EXYNOS4_GPIO_E4_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_E3),
+	EXYNOS4_GPIO_F0_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_E4),
+	EXYNOS4_GPIO_F1_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_F0),
+	EXYNOS4_GPIO_F2_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_F1),
+	EXYNOS4_GPIO_F3_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_F2),
+	EXYNOS4_GPIO_J0_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_F3),
+	EXYNOS4_GPIO_J1_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_J0),
+	EXYNOS4_GPIO_K0_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_J1),
+	EXYNOS4_GPIO_K1_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_K0),
+	EXYNOS4_GPIO_K2_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_K1),
+	EXYNOS4_GPIO_K3_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_K2),
+	EXYNOS4_GPIO_L0_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_K3),
+	EXYNOS4_GPIO_L1_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_L0),
+	EXYNOS4_GPIO_L2_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_L1),
+	EXYNOS4_GPIO_X0_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_L2),
+	EXYNOS4_GPIO_X1_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_X0),
+	EXYNOS4_GPIO_X2_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_X1),
+	EXYNOS4_GPIO_X3_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_X2),
+	EXYNOS4_GPIO_Y0_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_X3),
+	EXYNOS4_GPIO_Y1_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y0),
+	EXYNOS4_GPIO_Y2_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y1),
+	EXYNOS4_GPIO_Y3_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y2),
+	EXYNOS4_GPIO_Y4_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y3),
+	EXYNOS4_GPIO_Y5_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y4),
+	EXYNOS4_GPIO_Y6_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y5),
+	EXYNOS4_GPIO_Z_START	= EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y6),
 };
 
 /* EXYNOS4 GPIO number definitions */
+
 #define EXYNOS4_GPA0(_nr)	(EXYNOS4_GPIO_A0_START + (_nr))
 #define EXYNOS4_GPA1(_nr)	(EXYNOS4_GPIO_A1_START + (_nr))
 #define EXYNOS4_GPB(_nr)	(EXYNOS4_GPIO_B_START + (_nr))
@@ -139,11 +140,147 @@
 #define EXYNOS4_GPZ(_nr)	(EXYNOS4_GPIO_Z_START + (_nr))
 
 /* the end of the EXYNOS4 specific gpios */
-#define EXYNOS4_GPIO_END	(EXYNOS4_GPZ(EXYNOS4_GPIO_Z_NR) + 1)
-#define S3C_GPIO_END		EXYNOS4_GPIO_END
 
-/* define the number of gpios we need to the one after the GPZ() range */
-#define ARCH_NR_GPIOS		(EXYNOS4_GPZ(EXYNOS4_GPIO_Z_NR) +	\
-				 CONFIG_SAMSUNG_GPIO_EXTRA + 1)
+#define EXYNOS4_GPIO_END	(EXYNOS4_GPZ(EXYNOS4_GPIO_Z_NR) + 1)
+
+/* EXYNOS5 GPIO bank sizes */
+
+#define EXYNOS5_GPIO_A0_NR	(8)
+#define EXYNOS5_GPIO_A1_NR	(6)
+#define EXYNOS5_GPIO_A2_NR	(8)
+#define EXYNOS5_GPIO_B0_NR	(5)
+#define EXYNOS5_GPIO_B1_NR	(5)
+#define EXYNOS5_GPIO_B2_NR	(4)
+#define EXYNOS5_GPIO_B3_NR	(4)
+#define EXYNOS5_GPIO_C0_NR	(7)
+#define EXYNOS5_GPIO_C1_NR	(7)
+#define EXYNOS5_GPIO_C2_NR	(7)
+#define EXYNOS5_GPIO_C3_NR	(7)
+#define EXYNOS5_GPIO_D0_NR	(8)
+#define EXYNOS5_GPIO_D1_NR	(8)
+#define EXYNOS5_GPIO_Y0_NR	(6)
+#define EXYNOS5_GPIO_Y1_NR	(4)
+#define EXYNOS5_GPIO_Y2_NR	(6)
+#define EXYNOS5_GPIO_Y3_NR	(8)
+#define EXYNOS5_GPIO_Y4_NR	(8)
+#define EXYNOS5_GPIO_Y5_NR	(8)
+#define EXYNOS5_GPIO_Y6_NR	(8)
+#define EXYNOS5_GPIO_X0_NR	(8)
+#define EXYNOS5_GPIO_X1_NR	(8)
+#define EXYNOS5_GPIO_X2_NR	(8)
+#define EXYNOS5_GPIO_X3_NR	(8)
+#define EXYNOS5_GPIO_E0_NR	(8)
+#define EXYNOS5_GPIO_E1_NR	(2)
+#define EXYNOS5_GPIO_F0_NR	(4)
+#define EXYNOS5_GPIO_F1_NR	(4)
+#define EXYNOS5_GPIO_G0_NR	(8)
+#define EXYNOS5_GPIO_G1_NR	(8)
+#define EXYNOS5_GPIO_G2_NR	(2)
+#define EXYNOS5_GPIO_H0_NR	(4)
+#define EXYNOS5_GPIO_H1_NR	(8)
+#define EXYNOS5_GPIO_V0_NR	(8)
+#define EXYNOS5_GPIO_V1_NR	(8)
+#define EXYNOS5_GPIO_V2_NR	(8)
+#define EXYNOS5_GPIO_V3_NR	(8)
+#define EXYNOS5_GPIO_V4_NR	(2)
+#define EXYNOS5_GPIO_Z_NR	(7)
+
+/* EXYNOS5 GPIO bank numbers */
+
+enum exynos5_gpio_number {
+	EXYNOS5_GPIO_A0_START		= 0,
+	EXYNOS5_GPIO_A1_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_A0),
+	EXYNOS5_GPIO_A2_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_A1),
+	EXYNOS5_GPIO_B0_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_A2),
+	EXYNOS5_GPIO_B1_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_B0),
+	EXYNOS5_GPIO_B2_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_B1),
+	EXYNOS5_GPIO_B3_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_B2),
+	EXYNOS5_GPIO_C0_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_B3),
+	EXYNOS5_GPIO_C1_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C0),
+	EXYNOS5_GPIO_C2_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C1),
+	EXYNOS5_GPIO_C3_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C2),
+	EXYNOS5_GPIO_D0_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C3),
+	EXYNOS5_GPIO_D1_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_D0),
+	EXYNOS5_GPIO_Y0_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_D1),
+	EXYNOS5_GPIO_Y1_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y0),
+	EXYNOS5_GPIO_Y2_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y1),
+	EXYNOS5_GPIO_Y3_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y2),
+	EXYNOS5_GPIO_Y4_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y3),
+	EXYNOS5_GPIO_Y5_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y4),
+	EXYNOS5_GPIO_Y6_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y5),
+	EXYNOS5_GPIO_X0_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y6),
+	EXYNOS5_GPIO_X1_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_X0),
+	EXYNOS5_GPIO_X2_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_X1),
+	EXYNOS5_GPIO_X3_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_X2),
+	EXYNOS5_GPIO_E0_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_X3),
+	EXYNOS5_GPIO_E1_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_E0),
+	EXYNOS5_GPIO_F0_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_E1),
+	EXYNOS5_GPIO_F1_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_F0),
+	EXYNOS5_GPIO_G0_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_F1),
+	EXYNOS5_GPIO_G1_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_G0),
+	EXYNOS5_GPIO_G2_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_G1),
+	EXYNOS5_GPIO_H0_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_G2),
+	EXYNOS5_GPIO_H1_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_H0),
+	EXYNOS5_GPIO_V0_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_H1),
+	EXYNOS5_GPIO_V1_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_V0),
+	EXYNOS5_GPIO_V2_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_V1),
+	EXYNOS5_GPIO_V3_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_V2),
+	EXYNOS5_GPIO_V4_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_V3),
+	EXYNOS5_GPIO_Z_START		= EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_V4),
+};
+
+/* EXYNOS5 GPIO number definitions */
+
+#define EXYNOS5_GPA0(_nr)	(EXYNOS5_GPIO_A0_START + (_nr))
+#define EXYNOS5_GPA1(_nr)	(EXYNOS5_GPIO_A1_START + (_nr))
+#define EXYNOS5_GPA2(_nr)	(EXYNOS5_GPIO_A2_START + (_nr))
+#define EXYNOS5_GPB0(_nr)	(EXYNOS5_GPIO_B0_START + (_nr))
+#define EXYNOS5_GPB1(_nr)	(EXYNOS5_GPIO_B1_START + (_nr))
+#define EXYNOS5_GPB2(_nr)	(EXYNOS5_GPIO_B2_START + (_nr))
+#define EXYNOS5_GPB3(_nr)	(EXYNOS5_GPIO_B3_START + (_nr))
+#define EXYNOS5_GPC0(_nr)	(EXYNOS5_GPIO_C0_START + (_nr))
+#define EXYNOS5_GPC1(_nr)	(EXYNOS5_GPIO_C1_START + (_nr))
+#define EXYNOS5_GPC2(_nr)	(EXYNOS5_GPIO_C2_START + (_nr))
+#define EXYNOS5_GPC3(_nr)	(EXYNOS5_GPIO_C3_START + (_nr))
+#define EXYNOS5_GPD0(_nr)	(EXYNOS5_GPIO_D0_START + (_nr))
+#define EXYNOS5_GPD1(_nr)	(EXYNOS5_GPIO_D1_START + (_nr))
+#define EXYNOS5_GPY0(_nr)	(EXYNOS5_GPIO_Y0_START + (_nr))
+#define EXYNOS5_GPY1(_nr)	(EXYNOS5_GPIO_Y1_START + (_nr))
+#define EXYNOS5_GPY2(_nr)	(EXYNOS5_GPIO_Y2_START + (_nr))
+#define EXYNOS5_GPY3(_nr)	(EXYNOS5_GPIO_Y3_START + (_nr))
+#define EXYNOS5_GPY4(_nr)	(EXYNOS5_GPIO_Y4_START + (_nr))
+#define EXYNOS5_GPY5(_nr)	(EXYNOS5_GPIO_Y5_START + (_nr))
+#define EXYNOS5_GPY6(_nr)	(EXYNOS5_GPIO_Y6_START + (_nr))
+#define EXYNOS5_GPX0(_nr)	(EXYNOS5_GPIO_X0_START + (_nr))
+#define EXYNOS5_GPX1(_nr)	(EXYNOS5_GPIO_X1_START + (_nr))
+#define EXYNOS5_GPX2(_nr)	(EXYNOS5_GPIO_X2_START + (_nr))
+#define EXYNOS5_GPX3(_nr)	(EXYNOS5_GPIO_X3_START + (_nr))
+#define EXYNOS5_GPE0(_nr)	(EXYNOS5_GPIO_E0_START + (_nr))
+#define EXYNOS5_GPE1(_nr)	(EXYNOS5_GPIO_E1_START + (_nr))
+#define EXYNOS5_GPF0(_nr)	(EXYNOS5_GPIO_F0_START + (_nr))
+#define EXYNOS5_GPF1(_nr)	(EXYNOS5_GPIO_F1_START + (_nr))
+#define EXYNOS5_GPG0(_nr)	(EXYNOS5_GPIO_G0_START + (_nr))
+#define EXYNOS5_GPG1(_nr)	(EXYNOS5_GPIO_G1_START + (_nr))
+#define EXYNOS5_GPG2(_nr)	(EXYNOS5_GPIO_G2_START + (_nr))
+#define EXYNOS5_GPH0(_nr)	(EXYNOS5_GPIO_H0_START + (_nr))
+#define EXYNOS5_GPH1(_nr)	(EXYNOS5_GPIO_H1_START + (_nr))
+#define EXYNOS5_GPV0(_nr)	(EXYNOS5_GPIO_V0_START + (_nr))
+#define EXYNOS5_GPV1(_nr)	(EXYNOS5_GPIO_V1_START + (_nr))
+#define EXYNOS5_GPV2(_nr)	(EXYNOS5_GPIO_V2_START + (_nr))
+#define EXYNOS5_GPV3(_nr)	(EXYNOS5_GPIO_V3_START + (_nr))
+#define EXYNOS5_GPV4(_nr)	(EXYNOS5_GPIO_V4_START + (_nr))
+#define EXYNOS5_GPZ(_nr)	(EXYNOS5_GPIO_Z_START + (_nr))
+
+/* the end of the EXYNOS5 specific gpios */
+
+#define EXYNOS5_GPIO_END	(EXYNOS5_GPZ(EXYNOS5_GPIO_Z_NR) + 1)
+
+/* actually, EXYNOS5_GPIO_END is bigger than EXYNOS4 */
+
+#define S3C_GPIO_END		(EXYNOS5_GPIO_END)
+
+/* define the number of gpios */
+
+#define ARCH_NR_GPIOS		(CONFIG_SAMSUNG_GPIO_EXTRA + S3C_GPIO_END)
 
 #endif /* __ASM_ARCH_GPIO_H */
diff --git a/arch/arm/mach-exynos/include/mach/io.h b/arch/arm/mach-exynos/include/mach/io.h
deleted file mode 100644
index d5478d2..0000000
--- a/arch/arm/mach-exynos/include/mach/io.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* linux/arch/arm/mach-exynos4/include/mach/io.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * Copyright 2008-2010 Ben Dooks <ben-linux@fluff.org>
- *
- * Based on arch/arm/mach-s5p6442/include/mach/io.h
- *
- * Default IO routines for EXYNOS4
- *
- * 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 __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H __FILE__
-
-/* No current ISA/PCI bus support. */
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#define IO_SPACE_LIMIT (0xFFFFFFFF)
-
-#endif /* __ASM_ARM_ARCH_IO_H */
diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h
index f77bce0..9bee853 100644
--- a/arch/arm/mach-exynos/include/mach/irqs.h
+++ b/arch/arm/mach-exynos/include/mach/irqs.h
@@ -1,9 +1,8 @@
-/* linux/arch/arm/mach-exynos4/include/mach/irqs.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com
  *
- * EXYNOS4 - IRQ definitions
+ * EXYNOS - IRQ definitions
  *
  * 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
@@ -17,158 +16,450 @@
 
 /* PPI: Private Peripheral Interrupt */
 
-#define IRQ_PPI(x)		(x+16)
-
-#define IRQ_MCT_LOCALTIMER	IRQ_PPI(12)
+#define IRQ_PPI(x)			(x + 16)
 
 /* SPI: Shared Peripheral Interrupt */
 
-#define IRQ_SPI(x)		(x+32)
+#define IRQ_SPI(x)			(x + 32)
 
-#define IRQ_EINT0		IRQ_SPI(16)
-#define IRQ_EINT1		IRQ_SPI(17)
-#define IRQ_EINT2		IRQ_SPI(18)
-#define IRQ_EINT3		IRQ_SPI(19)
-#define IRQ_EINT4		IRQ_SPI(20)
-#define IRQ_EINT5		IRQ_SPI(21)
-#define IRQ_EINT6		IRQ_SPI(22)
-#define IRQ_EINT7		IRQ_SPI(23)
-#define IRQ_EINT8		IRQ_SPI(24)
-#define IRQ_EINT9		IRQ_SPI(25)
-#define IRQ_EINT10		IRQ_SPI(26)
-#define IRQ_EINT11		IRQ_SPI(27)
-#define IRQ_EINT12		IRQ_SPI(28)
-#define IRQ_EINT13		IRQ_SPI(29)
-#define IRQ_EINT14		IRQ_SPI(30)
-#define IRQ_EINT15		IRQ_SPI(31)
-#define IRQ_EINT16_31		IRQ_SPI(32)
+/* COMBINER */
 
-#define IRQ_PDMA0		IRQ_SPI(35)
-#define IRQ_PDMA1		IRQ_SPI(36)
-#define IRQ_TIMER0_VIC		IRQ_SPI(37)
-#define IRQ_TIMER1_VIC		IRQ_SPI(38)
-#define IRQ_TIMER2_VIC		IRQ_SPI(39)
-#define IRQ_TIMER3_VIC		IRQ_SPI(40)
-#define IRQ_TIMER4_VIC		IRQ_SPI(41)
-#define IRQ_MCT_L0		IRQ_SPI(42)
-#define IRQ_WDT			IRQ_SPI(43)
-#define IRQ_RTC_ALARM		IRQ_SPI(44)
-#define IRQ_RTC_TIC		IRQ_SPI(45)
-#define IRQ_GPIO_XB		IRQ_SPI(46)
-#define IRQ_GPIO_XA		IRQ_SPI(47)
-#define IRQ_MCT_L1		IRQ_SPI(48)
+#define MAX_IRQ_IN_COMBINER		8
+#define COMBINER_GROUP(x)		((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(128))
+#define COMBINER_IRQ(x, y)		(COMBINER_GROUP(x) + y)
 
-#define IRQ_UART0		IRQ_SPI(52)
-#define IRQ_UART1		IRQ_SPI(53)
-#define IRQ_UART2		IRQ_SPI(54)
-#define IRQ_UART3		IRQ_SPI(55)
-#define IRQ_UART4		IRQ_SPI(56)
-#define IRQ_MCT_G0		IRQ_SPI(57)
-#define IRQ_IIC			IRQ_SPI(58)
-#define IRQ_IIC1		IRQ_SPI(59)
-#define IRQ_IIC2		IRQ_SPI(60)
-#define IRQ_IIC3		IRQ_SPI(61)
-#define IRQ_IIC4		IRQ_SPI(62)
-#define IRQ_IIC5		IRQ_SPI(63)
-#define IRQ_IIC6		IRQ_SPI(64)
-#define IRQ_IIC7		IRQ_SPI(65)
-#define IRQ_SPI0		IRQ_SPI(66)
-#define IRQ_SPI1		IRQ_SPI(67)
-#define IRQ_SPI2		IRQ_SPI(68)
+/* For EXYNOS4 and EXYNOS5 */
 
-#define IRQ_USB_HOST		IRQ_SPI(70)
-#define IRQ_USB_HSOTG		IRQ_SPI(71)
-#define IRQ_MODEM_IF		IRQ_SPI(72)
-#define IRQ_HSMMC0		IRQ_SPI(73)
-#define IRQ_HSMMC1		IRQ_SPI(74)
-#define IRQ_HSMMC2		IRQ_SPI(75)
-#define IRQ_HSMMC3		IRQ_SPI(76)
-#define IRQ_DWMCI		IRQ_SPI(77)
+#define EXYNOS_IRQ_MCT_LOCALTIMER	IRQ_PPI(12)
 
-#define IRQ_MIPI_CSIS0		IRQ_SPI(78)
-#define IRQ_MIPI_CSIS1		IRQ_SPI(80)
+#define EXYNOS_IRQ_EINT16_31		IRQ_SPI(32)
 
-#define IRQ_ONENAND_AUDI	IRQ_SPI(82)
-#define IRQ_ROTATOR		IRQ_SPI(83)
-#define IRQ_FIMC0		IRQ_SPI(84)
-#define IRQ_FIMC1		IRQ_SPI(85)
-#define IRQ_FIMC2		IRQ_SPI(86)
-#define IRQ_FIMC3		IRQ_SPI(87)
-#define IRQ_JPEG		IRQ_SPI(88)
-#define IRQ_2D			IRQ_SPI(89)
-#define IRQ_PCIE		IRQ_SPI(90)
+/* For EXYNOS4 SoCs */
 
-#define IRQ_MIXER		IRQ_SPI(91)
-#define IRQ_HDMI		IRQ_SPI(92)
-#define IRQ_IIC_HDMIPHY		IRQ_SPI(93)
-#define IRQ_MFC			IRQ_SPI(94)
-#define IRQ_SDO			IRQ_SPI(95)
+#define EXYNOS4_IRQ_EINT0		IRQ_SPI(16)
+#define EXYNOS4_IRQ_EINT1		IRQ_SPI(17)
+#define EXYNOS4_IRQ_EINT2		IRQ_SPI(18)
+#define EXYNOS4_IRQ_EINT3		IRQ_SPI(19)
+#define EXYNOS4_IRQ_EINT4		IRQ_SPI(20)
+#define EXYNOS4_IRQ_EINT5		IRQ_SPI(21)
+#define EXYNOS4_IRQ_EINT6		IRQ_SPI(22)
+#define EXYNOS4_IRQ_EINT7		IRQ_SPI(23)
+#define EXYNOS4_IRQ_EINT8		IRQ_SPI(24)
+#define EXYNOS4_IRQ_EINT9		IRQ_SPI(25)
+#define EXYNOS4_IRQ_EINT10		IRQ_SPI(26)
+#define EXYNOS4_IRQ_EINT11		IRQ_SPI(27)
+#define EXYNOS4_IRQ_EINT12		IRQ_SPI(28)
+#define EXYNOS4_IRQ_EINT13		IRQ_SPI(29)
+#define EXYNOS4_IRQ_EINT14		IRQ_SPI(30)
+#define EXYNOS4_IRQ_EINT15		IRQ_SPI(31)
 
-#define IRQ_AUDIO_SS		IRQ_SPI(96)
-#define IRQ_I2S0		IRQ_SPI(97)
-#define IRQ_I2S1		IRQ_SPI(98)
-#define IRQ_I2S2		IRQ_SPI(99)
-#define IRQ_AC97		IRQ_SPI(100)
+#define EXYNOS4_IRQ_MDMA0		IRQ_SPI(33)
+#define EXYNOS4_IRQ_MDMA1		IRQ_SPI(34)
+#define EXYNOS4_IRQ_PDMA0		IRQ_SPI(35)
+#define EXYNOS4_IRQ_PDMA1		IRQ_SPI(36)
+#define EXYNOS4_IRQ_TIMER0_VIC		IRQ_SPI(37)
+#define EXYNOS4_IRQ_TIMER1_VIC		IRQ_SPI(38)
+#define EXYNOS4_IRQ_TIMER2_VIC		IRQ_SPI(39)
+#define EXYNOS4_IRQ_TIMER3_VIC		IRQ_SPI(40)
+#define EXYNOS4_IRQ_TIMER4_VIC		IRQ_SPI(41)
+#define EXYNOS4_IRQ_MCT_L0		IRQ_SPI(42)
+#define EXYNOS4_IRQ_WDT			IRQ_SPI(43)
+#define EXYNOS4_IRQ_RTC_ALARM		IRQ_SPI(44)
+#define EXYNOS4_IRQ_RTC_TIC		IRQ_SPI(45)
+#define EXYNOS4_IRQ_GPIO_XB		IRQ_SPI(46)
+#define EXYNOS4_IRQ_GPIO_XA		IRQ_SPI(47)
+#define EXYNOS4_IRQ_MCT_L1		IRQ_SPI(48)
 
-#define IRQ_SPDIF		IRQ_SPI(104)
-#define IRQ_ADC0		IRQ_SPI(105)
-#define IRQ_PEN0		IRQ_SPI(106)
-#define IRQ_ADC1		IRQ_SPI(107)
-#define IRQ_PEN1		IRQ_SPI(108)
-#define IRQ_KEYPAD		IRQ_SPI(109)
-#define IRQ_PMU			IRQ_SPI(110)
-#define IRQ_GPS			IRQ_SPI(111)
-#define IRQ_INTFEEDCTRL_SSS	IRQ_SPI(112)
-#define IRQ_SLIMBUS		IRQ_SPI(113)
+#define EXYNOS4_IRQ_UART0		IRQ_SPI(52)
+#define EXYNOS4_IRQ_UART1		IRQ_SPI(53)
+#define EXYNOS4_IRQ_UART2		IRQ_SPI(54)
+#define EXYNOS4_IRQ_UART3		IRQ_SPI(55)
+#define EXYNOS4_IRQ_UART4		IRQ_SPI(56)
+#define EXYNOS4_IRQ_MCT_G0		IRQ_SPI(57)
+#define EXYNOS4_IRQ_IIC			IRQ_SPI(58)
+#define EXYNOS4_IRQ_IIC1		IRQ_SPI(59)
+#define EXYNOS4_IRQ_IIC2		IRQ_SPI(60)
+#define EXYNOS4_IRQ_IIC3		IRQ_SPI(61)
+#define EXYNOS4_IRQ_IIC4		IRQ_SPI(62)
+#define EXYNOS4_IRQ_IIC5		IRQ_SPI(63)
+#define EXYNOS4_IRQ_IIC6		IRQ_SPI(64)
+#define EXYNOS4_IRQ_IIC7		IRQ_SPI(65)
+#define EXYNOS4_IRQ_SPI0		IRQ_SPI(66)
+#define EXYNOS4_IRQ_SPI1		IRQ_SPI(67)
+#define EXYNOS4_IRQ_SPI2		IRQ_SPI(68)
 
-#define IRQ_TSI			IRQ_SPI(115)
-#define IRQ_SATA		IRQ_SPI(116)
+#define EXYNOS4_IRQ_USB_HOST		IRQ_SPI(70)
+#define EXYNOS4_IRQ_USB_HSOTG		IRQ_SPI(71)
+#define EXYNOS4_IRQ_MODEM_IF		IRQ_SPI(72)
+#define EXYNOS4_IRQ_HSMMC0		IRQ_SPI(73)
+#define EXYNOS4_IRQ_HSMMC1		IRQ_SPI(74)
+#define EXYNOS4_IRQ_HSMMC2		IRQ_SPI(75)
+#define EXYNOS4_IRQ_HSMMC3		IRQ_SPI(76)
+#define EXYNOS4_IRQ_DWMCI		IRQ_SPI(77)
 
-#define MAX_IRQ_IN_COMBINER	8
-#define COMBINER_GROUP(x)	((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(128))
-#define COMBINER_IRQ(x, y)	(COMBINER_GROUP(x) + y)
+#define EXYNOS4_IRQ_MIPI_CSIS0		IRQ_SPI(78)
+#define EXYNOS4_IRQ_MIPI_CSIS1		IRQ_SPI(80)
 
-#define IRQ_SYSMMU_MDMA0_0	COMBINER_IRQ(4, 0)
-#define IRQ_SYSMMU_SSS_0	COMBINER_IRQ(4, 1)
-#define IRQ_SYSMMU_FIMC0_0	COMBINER_IRQ(4, 2)
-#define IRQ_SYSMMU_FIMC1_0	COMBINER_IRQ(4, 3)
-#define IRQ_SYSMMU_FIMC2_0	COMBINER_IRQ(4, 4)
-#define IRQ_SYSMMU_FIMC3_0	COMBINER_IRQ(4, 5)
-#define IRQ_SYSMMU_JPEG_0	COMBINER_IRQ(4, 6)
-#define IRQ_SYSMMU_2D_0		COMBINER_IRQ(4, 7)
+#define EXYNOS4_IRQ_ONENAND_AUDI	IRQ_SPI(82)
+#define EXYNOS4_IRQ_ROTATOR		IRQ_SPI(83)
+#define EXYNOS4_IRQ_FIMC0		IRQ_SPI(84)
+#define EXYNOS4_IRQ_FIMC1		IRQ_SPI(85)
+#define EXYNOS4_IRQ_FIMC2		IRQ_SPI(86)
+#define EXYNOS4_IRQ_FIMC3		IRQ_SPI(87)
+#define EXYNOS4_IRQ_JPEG		IRQ_SPI(88)
+#define EXYNOS4_IRQ_2D			IRQ_SPI(89)
+#define EXYNOS4_IRQ_PCIE		IRQ_SPI(90)
 
-#define IRQ_SYSMMU_ROTATOR_0	COMBINER_IRQ(5, 0)
-#define IRQ_SYSMMU_MDMA1_0	COMBINER_IRQ(5, 1)
-#define IRQ_SYSMMU_LCD0_M0_0	COMBINER_IRQ(5, 2)
-#define IRQ_SYSMMU_LCD1_M1_0	COMBINER_IRQ(5, 3)
-#define IRQ_SYSMMU_TV_M0_0	COMBINER_IRQ(5, 4)
-#define IRQ_SYSMMU_MFC_M0_0	COMBINER_IRQ(5, 5)
-#define IRQ_SYSMMU_MFC_M1_0	COMBINER_IRQ(5, 6)
-#define IRQ_SYSMMU_PCIE_0	COMBINER_IRQ(5, 7)
+#define EXYNOS4_IRQ_MIXER		IRQ_SPI(91)
+#define EXYNOS4_IRQ_HDMI		IRQ_SPI(92)
+#define EXYNOS4_IRQ_IIC_HDMIPHY		IRQ_SPI(93)
+#define EXYNOS4_IRQ_MFC			IRQ_SPI(94)
+#define EXYNOS4_IRQ_SDO			IRQ_SPI(95)
 
-#define IRQ_FIMD0_FIFO		COMBINER_IRQ(11, 0)
-#define IRQ_FIMD0_VSYNC		COMBINER_IRQ(11, 1)
-#define IRQ_FIMD0_SYSTEM	COMBINER_IRQ(11, 2)
+#define EXYNOS4_IRQ_AUDIO_SS		IRQ_SPI(96)
+#define EXYNOS4_IRQ_I2S0		IRQ_SPI(97)
+#define EXYNOS4_IRQ_I2S1		IRQ_SPI(98)
+#define EXYNOS4_IRQ_I2S2		IRQ_SPI(99)
+#define EXYNOS4_IRQ_AC97		IRQ_SPI(100)
 
-#define MAX_COMBINER_NR		16
+#define EXYNOS4_IRQ_SPDIF		IRQ_SPI(104)
+#define EXYNOS4_IRQ_ADC0		IRQ_SPI(105)
+#define EXYNOS4_IRQ_PEN0		IRQ_SPI(106)
+#define EXYNOS4_IRQ_ADC1		IRQ_SPI(107)
+#define EXYNOS4_IRQ_PEN1		IRQ_SPI(108)
+#define EXYNOS4_IRQ_KEYPAD		IRQ_SPI(109)
+#define EXYNOS4_IRQ_PMU			IRQ_SPI(110)
+#define EXYNOS4_IRQ_GPS			IRQ_SPI(111)
+#define EXYNOS4_IRQ_INTFEEDCTRL_SSS	IRQ_SPI(112)
+#define EXYNOS4_IRQ_SLIMBUS		IRQ_SPI(113)
 
-#define IRQ_ADC			IRQ_ADC0
-#define IRQ_TC			IRQ_PEN0
+#define EXYNOS4_IRQ_TSI			IRQ_SPI(115)
+#define EXYNOS4_IRQ_SATA		IRQ_SPI(116)
 
-#define S5P_IRQ_EINT_BASE	COMBINER_IRQ(MAX_COMBINER_NR, 0)
+#define EXYNOS4_IRQ_SYSMMU_MDMA0_0	COMBINER_IRQ(4, 0)
+#define EXYNOS4_IRQ_SYSMMU_SSS_0	COMBINER_IRQ(4, 1)
+#define EXYNOS4_IRQ_SYSMMU_FIMC0_0	COMBINER_IRQ(4, 2)
+#define EXYNOS4_IRQ_SYSMMU_FIMC1_0	COMBINER_IRQ(4, 3)
+#define EXYNOS4_IRQ_SYSMMU_FIMC2_0	COMBINER_IRQ(4, 4)
+#define EXYNOS4_IRQ_SYSMMU_FIMC3_0	COMBINER_IRQ(4, 5)
+#define EXYNOS4_IRQ_SYSMMU_JPEG_0	COMBINER_IRQ(4, 6)
+#define EXYNOS4_IRQ_SYSMMU_2D_0		COMBINER_IRQ(4, 7)
 
-#define S5P_EINT_BASE1		(S5P_IRQ_EINT_BASE + 0)
-#define S5P_EINT_BASE2		(S5P_IRQ_EINT_BASE + 16)
+#define EXYNOS4_IRQ_SYSMMU_ROTATOR_0	COMBINER_IRQ(5, 0)
+#define EXYNOS4_IRQ_SYSMMU_MDMA1_0	COMBINER_IRQ(5, 1)
+#define EXYNOS4_IRQ_SYSMMU_LCD0_M0_0	COMBINER_IRQ(5, 2)
+#define EXYNOS4_IRQ_SYSMMU_LCD1_M1_0	COMBINER_IRQ(5, 3)
+#define EXYNOS4_IRQ_SYSMMU_TV_M0_0	COMBINER_IRQ(5, 4)
+#define EXYNOS4_IRQ_SYSMMU_MFC_M0_0	COMBINER_IRQ(5, 5)
+#define EXYNOS4_IRQ_SYSMMU_MFC_M1_0	COMBINER_IRQ(5, 6)
+#define EXYNOS4_IRQ_SYSMMU_PCIE_0	COMBINER_IRQ(5, 7)
 
-/* optional GPIO interrupts */
-#define S5P_GPIOINT_BASE	(S5P_IRQ_EINT_BASE + 32)
-#define IRQ_GPIO1_NR_GROUPS	16
-#define IRQ_GPIO2_NR_GROUPS	9
-#define IRQ_GPIO_END		(S5P_GPIOINT_BASE + S5P_GPIOINT_COUNT)
+#define EXYNOS4_IRQ_FIMD0_FIFO		COMBINER_IRQ(11, 0)
+#define EXYNOS4_IRQ_FIMD0_VSYNC		COMBINER_IRQ(11, 1)
+#define EXYNOS4_IRQ_FIMD0_SYSTEM	COMBINER_IRQ(11, 2)
 
-#define IRQ_TIMER_BASE		(IRQ_GPIO_END + 64)
+#define EXYNOS4_MAX_COMBINER_NR		16
+
+#define EXYNOS4_IRQ_GPIO1_NR_GROUPS	16
+#define EXYNOS4_IRQ_GPIO2_NR_GROUPS	9
+
+/*
+ * For Compatibility:
+ * the default is for EXYNOS4, and
+ * for exynos5, should be re-mapped at function
+ */
+
+#define IRQ_TIMER0_VIC			EXYNOS4_IRQ_TIMER0_VIC
+#define IRQ_TIMER1_VIC			EXYNOS4_IRQ_TIMER1_VIC
+#define IRQ_TIMER2_VIC			EXYNOS4_IRQ_TIMER2_VIC
+#define IRQ_TIMER3_VIC			EXYNOS4_IRQ_TIMER3_VIC
+#define IRQ_TIMER4_VIC			EXYNOS4_IRQ_TIMER4_VIC
+
+#define IRQ_WDT				EXYNOS4_IRQ_WDT
+#define IRQ_RTC_ALARM			EXYNOS4_IRQ_RTC_ALARM
+#define IRQ_RTC_TIC			EXYNOS4_IRQ_RTC_TIC
+#define IRQ_GPIO_XB			EXYNOS4_IRQ_GPIO_XB
+#define IRQ_GPIO_XA			EXYNOS4_IRQ_GPIO_XA
+
+#define IRQ_IIC				EXYNOS4_IRQ_IIC
+#define IRQ_IIC1			EXYNOS4_IRQ_IIC1
+#define IRQ_IIC3			EXYNOS4_IRQ_IIC3
+#define IRQ_IIC5			EXYNOS4_IRQ_IIC5
+#define IRQ_IIC6			EXYNOS4_IRQ_IIC6
+#define IRQ_IIC7			EXYNOS4_IRQ_IIC7
+
+#define IRQ_USB_HOST			EXYNOS4_IRQ_USB_HOST
+
+#define IRQ_HSMMC0			EXYNOS4_IRQ_HSMMC0
+#define IRQ_HSMMC1			EXYNOS4_IRQ_HSMMC1
+#define IRQ_HSMMC2			EXYNOS4_IRQ_HSMMC2
+#define IRQ_HSMMC3			EXYNOS4_IRQ_HSMMC3
+
+#define IRQ_MIPI_CSIS0			EXYNOS4_IRQ_MIPI_CSIS0
+
+#define IRQ_ONENAND_AUDI		EXYNOS4_IRQ_ONENAND_AUDI
+
+#define IRQ_FIMC0			EXYNOS4_IRQ_FIMC0
+#define IRQ_FIMC1			EXYNOS4_IRQ_FIMC1
+#define IRQ_FIMC2			EXYNOS4_IRQ_FIMC2
+#define IRQ_FIMC3			EXYNOS4_IRQ_FIMC3
+#define IRQ_JPEG			EXYNOS4_IRQ_JPEG
+#define IRQ_2D				EXYNOS4_IRQ_2D
+
+#define IRQ_MIXER			EXYNOS4_IRQ_MIXER
+#define IRQ_HDMI			EXYNOS4_IRQ_HDMI
+#define IRQ_IIC_HDMIPHY			EXYNOS4_IRQ_IIC_HDMIPHY
+#define IRQ_MFC				EXYNOS4_IRQ_MFC
+#define IRQ_SDO				EXYNOS4_IRQ_SDO
+
+#define IRQ_ADC				EXYNOS4_IRQ_ADC0
+#define IRQ_TC				EXYNOS4_IRQ_PEN0
+
+#define IRQ_KEYPAD			EXYNOS4_IRQ_KEYPAD
+#define IRQ_PMU				EXYNOS4_IRQ_PMU
+
+#define IRQ_SYSMMU_MDMA0_0		EXYNOS4_IRQ_SYSMMU_MDMA0_0
+#define IRQ_SYSMMU_SSS_0                EXYNOS4_IRQ_SYSMMU_SSS_0
+#define IRQ_SYSMMU_FIMC0_0              EXYNOS4_IRQ_SYSMMU_FIMC0_0
+#define IRQ_SYSMMU_FIMC1_0              EXYNOS4_IRQ_SYSMMU_FIMC1_0
+#define IRQ_SYSMMU_FIMC2_0              EXYNOS4_IRQ_SYSMMU_FIMC2_0
+#define IRQ_SYSMMU_FIMC3_0              EXYNOS4_IRQ_SYSMMU_FIMC3_0
+#define IRQ_SYSMMU_JPEG_0               EXYNOS4_IRQ_SYSMMU_JPEG_0
+#define IRQ_SYSMMU_2D_0                 EXYNOS4_IRQ_SYSMMU_2D_0
+
+#define IRQ_SYSMMU_ROTATOR_0            EXYNOS4_IRQ_SYSMMU_ROTATOR_0
+#define IRQ_SYSMMU_MDMA1_0              EXYNOS4_IRQ_SYSMMU_MDMA1_0
+#define IRQ_SYSMMU_LCD0_M0_0            EXYNOS4_IRQ_SYSMMU_LCD0_M0_0
+#define IRQ_SYSMMU_LCD1_M1_0            EXYNOS4_IRQ_SYSMMU_LCD1_M1_0
+#define IRQ_SYSMMU_TV_M0_0              EXYNOS4_IRQ_SYSMMU_TV_M0_0
+#define IRQ_SYSMMU_MFC_M0_0             EXYNOS4_IRQ_SYSMMU_MFC_M0_0
+#define IRQ_SYSMMU_MFC_M1_0             EXYNOS4_IRQ_SYSMMU_MFC_M1_0
+#define IRQ_SYSMMU_PCIE_0               EXYNOS4_IRQ_SYSMMU_PCIE_0
+
+#define IRQ_FIMD0_FIFO			EXYNOS4_IRQ_FIMD0_FIFO
+#define IRQ_FIMD0_VSYNC			EXYNOS4_IRQ_FIMD0_VSYNC
+#define IRQ_FIMD0_SYSTEM		EXYNOS4_IRQ_FIMD0_SYSTEM
+
+#define IRQ_GPIO1_NR_GROUPS		EXYNOS4_IRQ_GPIO1_NR_GROUPS
+#define IRQ_GPIO2_NR_GROUPS		EXYNOS4_IRQ_GPIO2_NR_GROUPS
+
+/* For EXYNOS5 SoCs */
+
+#define EXYNOS5_IRQ_MDMA0		IRQ_SPI(33)
+#define EXYNOS5_IRQ_PDMA0		IRQ_SPI(34)
+#define EXYNOS5_IRQ_PDMA1		IRQ_SPI(35)
+#define EXYNOS5_IRQ_TIMER0_VIC		IRQ_SPI(36)
+#define EXYNOS5_IRQ_TIMER1_VIC		IRQ_SPI(37)
+#define EXYNOS5_IRQ_TIMER2_VIC		IRQ_SPI(38)
+#define EXYNOS5_IRQ_TIMER3_VIC		IRQ_SPI(39)
+#define EXYNOS5_IRQ_TIMER4_VIC		IRQ_SPI(40)
+#define EXYNOS5_IRQ_RTIC		IRQ_SPI(41)
+#define EXYNOS5_IRQ_WDT			IRQ_SPI(42)
+#define EXYNOS5_IRQ_RTC_ALARM		IRQ_SPI(43)
+#define EXYNOS5_IRQ_RTC_TIC		IRQ_SPI(44)
+#define EXYNOS5_IRQ_GPIO_XB		IRQ_SPI(45)
+#define EXYNOS5_IRQ_GPIO_XA		IRQ_SPI(46)
+#define EXYNOS5_IRQ_GPIO		IRQ_SPI(47)
+#define EXYNOS5_IRQ_IEM_IEC		IRQ_SPI(48)
+#define EXYNOS5_IRQ_IEM_APC		IRQ_SPI(49)
+#define EXYNOS5_IRQ_GPIO_C2C		IRQ_SPI(50)
+#define EXYNOS5_IRQ_UART0		IRQ_SPI(51)
+#define EXYNOS5_IRQ_UART1		IRQ_SPI(52)
+#define EXYNOS5_IRQ_UART2		IRQ_SPI(53)
+#define EXYNOS5_IRQ_UART3		IRQ_SPI(54)
+#define EXYNOS5_IRQ_UART4		IRQ_SPI(55)
+#define EXYNOS5_IRQ_IIC			IRQ_SPI(56)
+#define EXYNOS5_IRQ_IIC1		IRQ_SPI(57)
+#define EXYNOS5_IRQ_IIC2		IRQ_SPI(58)
+#define EXYNOS5_IRQ_IIC3		IRQ_SPI(59)
+#define EXYNOS5_IRQ_IIC4		IRQ_SPI(60)
+#define EXYNOS5_IRQ_IIC5		IRQ_SPI(61)
+#define EXYNOS5_IRQ_IIC6		IRQ_SPI(62)
+#define EXYNOS5_IRQ_IIC7		IRQ_SPI(63)
+#define EXYNOS5_IRQ_IIC_HDMIPHY		IRQ_SPI(64)
+#define EXYNOS5_IRQ_TMU			IRQ_SPI(65)
+#define EXYNOS5_IRQ_FIQ_0		IRQ_SPI(66)
+#define EXYNOS5_IRQ_FIQ_1		IRQ_SPI(67)
+#define EXYNOS5_IRQ_SPI0		IRQ_SPI(68)
+#define EXYNOS5_IRQ_SPI1		IRQ_SPI(69)
+#define EXYNOS5_IRQ_SPI2		IRQ_SPI(70)
+#define EXYNOS5_IRQ_USB_HOST		IRQ_SPI(71)
+#define EXYNOS5_IRQ_USB3_DRD		IRQ_SPI(72)
+#define EXYNOS5_IRQ_MIPI_HSI		IRQ_SPI(73)
+#define EXYNOS5_IRQ_USB_HSOTG		IRQ_SPI(74)
+#define EXYNOS5_IRQ_HSMMC0		IRQ_SPI(75)
+#define EXYNOS5_IRQ_HSMMC1		IRQ_SPI(76)
+#define EXYNOS5_IRQ_HSMMC2		IRQ_SPI(77)
+#define EXYNOS5_IRQ_HSMMC3		IRQ_SPI(78)
+#define EXYNOS5_IRQ_MIPICSI0		IRQ_SPI(79)
+#define EXYNOS5_IRQ_MIPICSI1		IRQ_SPI(80)
+#define EXYNOS5_IRQ_EFNFCON_DMA_ABORT	IRQ_SPI(81)
+#define EXYNOS5_IRQ_MIPIDSI0		IRQ_SPI(82)
+#define EXYNOS5_IRQ_ROTATOR		IRQ_SPI(84)
+#define EXYNOS5_IRQ_GSC0		IRQ_SPI(85)
+#define EXYNOS5_IRQ_GSC1		IRQ_SPI(86)
+#define EXYNOS5_IRQ_GSC2		IRQ_SPI(87)
+#define EXYNOS5_IRQ_GSC3		IRQ_SPI(88)
+#define EXYNOS5_IRQ_JPEG		IRQ_SPI(89)
+#define EXYNOS5_IRQ_EFNFCON_DMA		IRQ_SPI(90)
+#define EXYNOS5_IRQ_2D			IRQ_SPI(91)
+#define EXYNOS5_IRQ_SFMC0		IRQ_SPI(92)
+#define EXYNOS5_IRQ_SFMC1		IRQ_SPI(93)
+#define EXYNOS5_IRQ_MIXER		IRQ_SPI(94)
+#define EXYNOS5_IRQ_HDMI		IRQ_SPI(95)
+#define EXYNOS5_IRQ_MFC			IRQ_SPI(96)
+#define EXYNOS5_IRQ_AUDIO_SS		IRQ_SPI(97)
+#define EXYNOS5_IRQ_I2S0		IRQ_SPI(98)
+#define EXYNOS5_IRQ_I2S1		IRQ_SPI(99)
+#define EXYNOS5_IRQ_I2S2		IRQ_SPI(100)
+#define EXYNOS5_IRQ_AC97		IRQ_SPI(101)
+#define EXYNOS5_IRQ_PCM0		IRQ_SPI(102)
+#define EXYNOS5_IRQ_PCM1		IRQ_SPI(103)
+#define EXYNOS5_IRQ_PCM2		IRQ_SPI(104)
+#define EXYNOS5_IRQ_SPDIF		IRQ_SPI(105)
+#define EXYNOS5_IRQ_ADC0		IRQ_SPI(106)
+
+#define EXYNOS5_IRQ_SATA_PHY		IRQ_SPI(108)
+#define EXYNOS5_IRQ_SATA_PMEMREQ	IRQ_SPI(109)
+#define EXYNOS5_IRQ_CAM_C		IRQ_SPI(110)
+#define EXYNOS5_IRQ_EAGLE_PMU		IRQ_SPI(111)
+#define EXYNOS5_IRQ_INTFEEDCTRL_SSS	IRQ_SPI(112)
+#define EXYNOS5_IRQ_DP1_INTP1		IRQ_SPI(113)
+#define EXYNOS5_IRQ_CEC			IRQ_SPI(114)
+#define EXYNOS5_IRQ_SATA		IRQ_SPI(115)
+#define EXYNOS5_IRQ_NFCON		IRQ_SPI(116)
+
+#define EXYNOS5_IRQ_MMC44		IRQ_SPI(123)
+#define EXYNOS5_IRQ_MDMA1		IRQ_SPI(124)
+#define EXYNOS5_IRQ_FIMC_LITE0		IRQ_SPI(125)
+#define EXYNOS5_IRQ_FIMC_LITE1		IRQ_SPI(126)
+#define EXYNOS5_IRQ_RP_TIMER		IRQ_SPI(127)
+
+#define EXYNOS5_IRQ_PMU			COMBINER_IRQ(1, 2)
+#define EXYNOS5_IRQ_PMU_CPU1		COMBINER_IRQ(1, 6)
+
+#define EXYNOS5_IRQ_SYSMMU_GSC0_0	COMBINER_IRQ(2, 0)
+#define EXYNOS5_IRQ_SYSMMU_GSC0_1	COMBINER_IRQ(2, 1)
+#define EXYNOS5_IRQ_SYSMMU_GSC1_0	COMBINER_IRQ(2, 2)
+#define EXYNOS5_IRQ_SYSMMU_GSC1_1	COMBINER_IRQ(2, 3)
+#define EXYNOS5_IRQ_SYSMMU_GSC2_0	COMBINER_IRQ(2, 4)
+#define EXYNOS5_IRQ_SYSMMU_GSC2_1	COMBINER_IRQ(2, 5)
+#define EXYNOS5_IRQ_SYSMMU_GSC3_0	COMBINER_IRQ(2, 6)
+#define EXYNOS5_IRQ_SYSMMU_GSC3_1	COMBINER_IRQ(2, 7)
+
+#define EXYNOS5_IRQ_SYSMMU_FIMD1_0	COMBINER_IRQ(3, 2)
+#define EXYNOS5_IRQ_SYSMMU_FIMD1_1	COMBINER_IRQ(3, 3)
+#define EXYNOS5_IRQ_SYSMMU_LITE0_0	COMBINER_IRQ(3, 4)
+#define EXYNOS5_IRQ_SYSMMU_LITE0_1	COMBINER_IRQ(3, 5)
+#define EXYNOS5_IRQ_SYSMMU_SCALERPISP_0	COMBINER_IRQ(3, 6)
+#define EXYNOS5_IRQ_SYSMMU_SCALERPISP_1	COMBINER_IRQ(3, 7)
+
+#define EXYNOS5_IRQ_SYSMMU_ROTATOR_0	COMBINER_IRQ(4, 0)
+#define EXYNOS5_IRQ_SYSMMU_ROTATOR_1	COMBINER_IRQ(4, 1)
+#define EXYNOS5_IRQ_SYSMMU_JPEG_0	COMBINER_IRQ(4, 2)
+#define EXYNOS5_IRQ_SYSMMU_JPEG_1	COMBINER_IRQ(4, 3)
+
+#define EXYNOS5_IRQ_SYSMMU_FD_0		COMBINER_IRQ(5, 0)
+#define EXYNOS5_IRQ_SYSMMU_FD_1		COMBINER_IRQ(5, 1)
+#define EXYNOS5_IRQ_SYSMMU_SCALERCISP_0	COMBINER_IRQ(5, 2)
+#define EXYNOS5_IRQ_SYSMMU_SCALERCISP_1	COMBINER_IRQ(5, 3)
+#define EXYNOS5_IRQ_SYSMMU_MCUISP_0	COMBINER_IRQ(5, 4)
+#define EXYNOS5_IRQ_SYSMMU_MCUISP_1	COMBINER_IRQ(5, 5)
+#define EXYNOS5_IRQ_SYSMMU_3DNR_0	COMBINER_IRQ(5, 6)
+#define EXYNOS5_IRQ_SYSMMU_3DNR_1	COMBINER_IRQ(5, 7)
+
+#define EXYNOS5_IRQ_SYSMMU_ARM_0	COMBINER_IRQ(6, 0)
+#define EXYNOS5_IRQ_SYSMMU_ARM_1	COMBINER_IRQ(6, 1)
+#define EXYNOS5_IRQ_SYSMMU_MFC_L_0	COMBINER_IRQ(6, 2)
+#define EXYNOS5_IRQ_SYSMMU_MFC_L_1	COMBINER_IRQ(6, 3)
+#define EXYNOS5_IRQ_SYSMMU_RTIC_0	COMBINER_IRQ(6, 4)
+#define EXYNOS5_IRQ_SYSMMU_RTIC_1	COMBINER_IRQ(6, 5)
+#define EXYNOS5_IRQ_SYSMMU_SSS_0	COMBINER_IRQ(6, 6)
+#define EXYNOS5_IRQ_SYSMMU_SSS_1	COMBINER_IRQ(6, 7)
+
+#define EXYNOS5_IRQ_SYSMMU_MDMA0_0	COMBINER_IRQ(7, 0)
+#define EXYNOS5_IRQ_SYSMMU_MDMA0_1	COMBINER_IRQ(7, 1)
+#define EXYNOS5_IRQ_SYSMMU_MDMA1_0	COMBINER_IRQ(7, 2)
+#define EXYNOS5_IRQ_SYSMMU_MDMA1_1	COMBINER_IRQ(7, 3)
+#define EXYNOS5_IRQ_SYSMMU_TV_0		COMBINER_IRQ(7, 4)
+#define EXYNOS5_IRQ_SYSMMU_TV_1		COMBINER_IRQ(7, 5)
+#define EXYNOS5_IRQ_SYSMMU_GPSX_0	COMBINER_IRQ(7, 6)
+#define EXYNOS5_IRQ_SYSMMU_GPSX_1	COMBINER_IRQ(7, 7)
+
+#define EXYNOS5_IRQ_SYSMMU_MFC_R_0	COMBINER_IRQ(8, 5)
+#define EXYNOS5_IRQ_SYSMMU_MFC_R_1	COMBINER_IRQ(8, 6)
+
+#define EXYNOS5_IRQ_SYSMMU_DIS1_0	COMBINER_IRQ(9, 4)
+#define EXYNOS5_IRQ_SYSMMU_DIS1_1	COMBINER_IRQ(9, 5)
+
+#define EXYNOS5_IRQ_DP			COMBINER_IRQ(10, 3)
+#define EXYNOS5_IRQ_SYSMMU_DIS0_0	COMBINER_IRQ(10, 4)
+#define EXYNOS5_IRQ_SYSMMU_DIS0_1	COMBINER_IRQ(10, 5)
+#define EXYNOS5_IRQ_SYSMMU_ISP_0	COMBINER_IRQ(10, 6)
+#define EXYNOS5_IRQ_SYSMMU_ISP_1	COMBINER_IRQ(10, 7)
+
+#define EXYNOS5_IRQ_SYSMMU_ODC_0	COMBINER_IRQ(11, 0)
+#define EXYNOS5_IRQ_SYSMMU_ODC_1	COMBINER_IRQ(11, 1)
+#define EXYNOS5_IRQ_SYSMMU_DRC_0	COMBINER_IRQ(11, 6)
+#define EXYNOS5_IRQ_SYSMMU_DRC_1	COMBINER_IRQ(11, 7)
+
+#define EXYNOS5_IRQ_FIMD1_FIFO		COMBINER_IRQ(18, 4)
+#define EXYNOS5_IRQ_FIMD1_VSYNC		COMBINER_IRQ(18, 5)
+#define EXYNOS5_IRQ_FIMD1_SYSTEM	COMBINER_IRQ(18, 6)
+
+#define EXYNOS5_IRQ_EINT0		COMBINER_IRQ(23, 0)
+#define EXYNOS5_IRQ_MCT_L0		COMBINER_IRQ(23, 1)
+#define EXYNOS5_IRQ_MCT_L1		COMBINER_IRQ(23, 2)
+#define EXYNOS5_IRQ_MCT_G0		COMBINER_IRQ(23, 3)
+#define EXYNOS5_IRQ_MCT_G1		COMBINER_IRQ(23, 4)
+#define EXYNOS5_IRQ_MCT_G2		COMBINER_IRQ(23, 5)
+#define EXYNOS5_IRQ_MCT_G3		COMBINER_IRQ(23, 6)
+
+#define EXYNOS5_IRQ_EINT1		COMBINER_IRQ(24, 0)
+#define EXYNOS5_IRQ_SYSMMU_LITE1_0	COMBINER_IRQ(24, 1)
+#define EXYNOS5_IRQ_SYSMMU_LITE1_1	COMBINER_IRQ(24, 2)
+#define EXYNOS5_IRQ_SYSMMU_2D_0		COMBINER_IRQ(24, 5)
+#define EXYNOS5_IRQ_SYSMMU_2D_1		COMBINER_IRQ(24, 6)
+
+#define EXYNOS5_IRQ_EINT2		COMBINER_IRQ(25, 0)
+#define EXYNOS5_IRQ_EINT3		COMBINER_IRQ(25, 1)
+
+#define EXYNOS5_IRQ_EINT4		COMBINER_IRQ(26, 0)
+#define EXYNOS5_IRQ_EINT5		COMBINER_IRQ(26, 1)
+
+#define EXYNOS5_IRQ_EINT6		COMBINER_IRQ(27, 0)
+#define EXYNOS5_IRQ_EINT7		COMBINER_IRQ(27, 1)
+
+#define EXYNOS5_IRQ_EINT8		COMBINER_IRQ(28, 0)
+#define EXYNOS5_IRQ_EINT9		COMBINER_IRQ(28, 1)
+
+#define EXYNOS5_IRQ_EINT10		COMBINER_IRQ(29, 0)
+#define EXYNOS5_IRQ_EINT11		COMBINER_IRQ(29, 1)
+
+#define EXYNOS5_IRQ_EINT12		COMBINER_IRQ(30, 0)
+#define EXYNOS5_IRQ_EINT13		COMBINER_IRQ(30, 1)
+
+#define EXYNOS5_IRQ_EINT14		COMBINER_IRQ(31, 0)
+#define EXYNOS5_IRQ_EINT15		COMBINER_IRQ(31, 1)
+
+#define EXYNOS5_MAX_COMBINER_NR		32
+
+#define EXYNOS5_IRQ_GPIO1_NR_GROUPS	13
+#define EXYNOS5_IRQ_GPIO2_NR_GROUPS	9
+#define EXYNOS5_IRQ_GPIO3_NR_GROUPS	5
+#define EXYNOS5_IRQ_GPIO4_NR_GROUPS	1
+
+#define MAX_COMBINER_NR			(EXYNOS4_MAX_COMBINER_NR > EXYNOS5_MAX_COMBINER_NR ? \
+					EXYNOS4_MAX_COMBINER_NR : EXYNOS5_MAX_COMBINER_NR)
+
+#define S5P_EINT_BASE1			COMBINER_IRQ(MAX_COMBINER_NR, 0)
+#define S5P_EINT_BASE2			(S5P_EINT_BASE1 + 16)
+#define S5P_GPIOINT_BASE		(S5P_EINT_BASE1 + 32)
+#define IRQ_GPIO_END			(S5P_GPIOINT_BASE + S5P_GPIOINT_COUNT)
+#define IRQ_TIMER_BASE			(IRQ_GPIO_END + 64)
 
 /* Set the default NR_IRQS */
-#define NR_IRQS			(IRQ_TIMER_BASE + IRQ_TIMER_COUNT)
+
+#define NR_IRQS				(IRQ_TIMER_BASE + IRQ_TIMER_COUNT)
 
 #endif /* __ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index c754a22..024d38f 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -25,12 +25,17 @@
 
 #define EXYNOS4_PA_SYSRAM0		0x02025000
 #define EXYNOS4_PA_SYSRAM1		0x02020000
+#define EXYNOS5_PA_SYSRAM		0x02020000
 
 #define EXYNOS4_PA_FIMC0		0x11800000
 #define EXYNOS4_PA_FIMC1		0x11810000
 #define EXYNOS4_PA_FIMC2		0x11820000
 #define EXYNOS4_PA_FIMC3		0x11830000
 
+#define EXYNOS4_PA_JPEG			0x11840000
+
+#define EXYNOS4_PA_G2D			0x12800000
+
 #define EXYNOS4_PA_I2S0			0x03830000
 #define EXYNOS4_PA_I2S1			0xE3100000
 #define EXYNOS4_PA_I2S2			0xE2A00000
@@ -44,30 +49,44 @@
 #define EXYNOS4_PA_ONENAND		0x0C000000
 #define EXYNOS4_PA_ONENAND_DMA		0x0C600000
 
-#define EXYNOS4_PA_CHIPID		0x10000000
+#define EXYNOS_PA_CHIPID		0x10000000
 
 #define EXYNOS4_PA_SYSCON		0x10010000
+#define EXYNOS5_PA_SYSCON		0x10050100
+
 #define EXYNOS4_PA_PMU			0x10020000
+#define EXYNOS5_PA_PMU			0x10040000
+
 #define EXYNOS4_PA_CMU			0x10030000
+#define EXYNOS5_PA_CMU			0x10010000
 
 #define EXYNOS4_PA_SYSTIMER		0x10050000
+#define EXYNOS5_PA_SYSTIMER		0x101C0000
+
 #define EXYNOS4_PA_WATCHDOG		0x10060000
+#define EXYNOS5_PA_WATCHDOG		0x101D0000
+
 #define EXYNOS4_PA_RTC			0x10070000
 
 #define EXYNOS4_PA_KEYPAD		0x100A0000
 
 #define EXYNOS4_PA_DMC0			0x10400000
+#define EXYNOS4_PA_DMC1			0x10410000
 
 #define EXYNOS4_PA_COMBINER		0x10440000
+#define EXYNOS5_PA_COMBINER		0x10440000
 
 #define EXYNOS4_PA_GIC_CPU		0x10480000
 #define EXYNOS4_PA_GIC_DIST		0x10490000
+#define EXYNOS5_PA_GIC_CPU		0x10480000
+#define EXYNOS5_PA_GIC_DIST		0x10490000
 
 #define EXYNOS4_PA_COREPERI		0x10500000
 #define EXYNOS4_PA_TWD			0x10500600
 #define EXYNOS4_PA_L2CC			0x10502000
 
-#define EXYNOS4_PA_MDMA			0x10810000
+#define EXYNOS4_PA_MDMA0		0x10810000
+#define EXYNOS4_PA_MDMA1		0x12840000
 #define EXYNOS4_PA_PDMA0		0x12680000
 #define EXYNOS4_PA_PDMA1		0x12690000
 
@@ -91,10 +110,13 @@
 #define EXYNOS4_PA_SPI1			0x13930000
 #define EXYNOS4_PA_SPI2			0x13940000
 
-
 #define EXYNOS4_PA_GPIO1		0x11400000
 #define EXYNOS4_PA_GPIO2		0x11000000
 #define EXYNOS4_PA_GPIO3		0x03860000
+#define EXYNOS5_PA_GPIO1		0x11400000
+#define EXYNOS5_PA_GPIO2		0x13400000
+#define EXYNOS5_PA_GPIO3		0x10D10000
+#define EXYNOS5_PA_GPIO4		0x03860000
 
 #define EXYNOS4_PA_MIPI_CSIS0		0x11880000
 #define EXYNOS4_PA_MIPI_CSIS1		0x11890000
@@ -109,6 +131,7 @@
 #define EXYNOS4_PA_SATAPHY_CTRL		0x126B0000
 
 #define EXYNOS4_PA_SROMC		0x12570000
+#define EXYNOS5_PA_SROMC		0x12250000
 
 #define EXYNOS4_PA_EHCI			0x12580000
 #define EXYNOS4_PA_OHCI			0x12590000
@@ -116,6 +139,7 @@
 #define EXYNOS4_PA_MFC			0x13400000
 
 #define EXYNOS4_PA_UART			0x13800000
+#define EXYNOS5_PA_UART			0x12C00000
 
 #define EXYNOS4_PA_VP			0x12C00000
 #define EXYNOS4_PA_MIXER		0x12C10000
@@ -124,6 +148,7 @@
 #define EXYNOS4_PA_IIC_HDMIPHY		0x138E0000
 
 #define EXYNOS4_PA_IIC(x)		(0x13860000 + ((x) * 0x10000))
+#define EXYNOS5_PA_IIC(x)		(0x12C60000 + ((x) * 0x10000))
 
 #define EXYNOS4_PA_ADC			0x13910000
 #define EXYNOS4_PA_ADC1			0x13911000
@@ -133,8 +158,10 @@
 #define EXYNOS4_PA_SPDIF		0x139B0000
 
 #define EXYNOS4_PA_TIMER		0x139D0000
+#define EXYNOS5_PA_TIMER		0x12DD0000
 
 #define EXYNOS4_PA_SDRAM		0x40000000
+#define EXYNOS5_PA_SDRAM		0x40000000
 
 /* Compatibiltiy Defines */
 
@@ -152,7 +179,6 @@
 #define S3C_PA_IIC7			EXYNOS4_PA_IIC(7)
 #define S3C_PA_RTC			EXYNOS4_PA_RTC
 #define S3C_PA_WDT			EXYNOS4_PA_WATCHDOG
-#define S3C_PA_UART			EXYNOS4_PA_UART
 #define S3C_PA_SPI0			EXYNOS4_PA_SPI0
 #define S3C_PA_SPI1			EXYNOS4_PA_SPI1
 #define S3C_PA_SPI2			EXYNOS4_PA_SPI2
@@ -162,6 +188,8 @@
 #define S5P_PA_FIMC1			EXYNOS4_PA_FIMC1
 #define S5P_PA_FIMC2			EXYNOS4_PA_FIMC2
 #define S5P_PA_FIMC3			EXYNOS4_PA_FIMC3
+#define S5P_PA_JPEG			EXYNOS4_PA_JPEG
+#define S5P_PA_G2D			EXYNOS4_PA_G2D
 #define S5P_PA_FIMD0			EXYNOS4_PA_FIMD0
 #define S5P_PA_HDMI			EXYNOS4_PA_HDMI
 #define S5P_PA_IIC_HDMIPHY		EXYNOS4_PA_IIC_HDMIPHY
@@ -181,15 +209,18 @@
 
 /* Compatibility UART */
 
+#define EXYNOS4_PA_UART0		0x13800000
+#define EXYNOS4_PA_UART1		0x13810000
+#define EXYNOS4_PA_UART2		0x13820000
+#define EXYNOS4_PA_UART3		0x13830000
+#define EXYNOS4_SZ_UART			SZ_256
+
+#define EXYNOS5_PA_UART0		0x12C00000
+#define EXYNOS5_PA_UART1		0x12C10000
+#define EXYNOS5_PA_UART2		0x12C20000
+#define EXYNOS5_PA_UART3		0x12C30000
+#define EXYNOS5_SZ_UART			SZ_256
+
 #define S3C_VA_UARTx(x)			(S3C_VA_UART + ((x) * S3C_UART_OFFSET))
 
-#define S5P_PA_UART(x)			(EXYNOS4_PA_UART + ((x) * S3C_UART_OFFSET))
-#define S5P_PA_UART0			S5P_PA_UART(0)
-#define S5P_PA_UART1			S5P_PA_UART(1)
-#define S5P_PA_UART2			S5P_PA_UART(2)
-#define S5P_PA_UART3			S5P_PA_UART(3)
-#define S5P_PA_UART4			S5P_PA_UART(4)
-
-#define S5P_SZ_UART			SZ_256
-
 #endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-exynos/include/mach/pmu.h b/arch/arm/mach-exynos/include/mach/pmu.h
index 632dd56..e76b7fa 100644
--- a/arch/arm/mach-exynos/include/mach/pmu.h
+++ b/arch/arm/mach-exynos/include/mach/pmu.h
@@ -22,11 +22,13 @@
 	NUM_SYS_POWERDOWN,
 };
 
+extern unsigned long l2x0_regs_phys;
 struct exynos4_pmu_conf {
 	void __iomem *reg;
 	unsigned int val[NUM_SYS_POWERDOWN];
 };
 
 extern void exynos4_sys_powerdown_conf(enum sys_powerdown mode);
+extern void s3c_cpu_resume(void);
 
 #endif /* __ASM_ARCH_PMU_H */
diff --git a/arch/arm/mach-exynos/include/mach/regs-clock.h b/arch/arm/mach-exynos/include/mach/regs-clock.h
index 6c37ebe..e141c1f 100644
--- a/arch/arm/mach-exynos/include/mach/regs-clock.h
+++ b/arch/arm/mach-exynos/include/mach/regs-clock.h
@@ -16,195 +16,309 @@
 #include <plat/cpu.h>
 #include <mach/map.h>
 
-#define S5P_CLKREG(x)			(S5P_VA_CMU + (x))
+#define EXYNOS_CLKREG(x)			(S5P_VA_CMU + (x))
 
-#define S5P_CLKDIV_LEFTBUS		S5P_CLKREG(0x04500)
-#define S5P_CLKDIV_STAT_LEFTBUS		S5P_CLKREG(0x04600)
-#define S5P_CLKGATE_IP_LEFTBUS		S5P_CLKREG(0x04800)
+#define EXYNOS4_CLKDIV_LEFTBUS			EXYNOS_CLKREG(0x04500)
+#define EXYNOS4_CLKDIV_STAT_LEFTBUS		EXYNOS_CLKREG(0x04600)
+#define EXYNOS4_CLKGATE_IP_LEFTBUS		EXYNOS_CLKREG(0x04800)
 
-#define S5P_CLKDIV_RIGHTBUS		S5P_CLKREG(0x08500)
-#define S5P_CLKDIV_STAT_RIGHTBUS	S5P_CLKREG(0x08600)
-#define S5P_CLKGATE_IP_RIGHTBUS		S5P_CLKREG(0x08800)
+#define EXYNOS4_CLKDIV_RIGHTBUS			EXYNOS_CLKREG(0x08500)
+#define EXYNOS4_CLKDIV_STAT_RIGHTBUS		EXYNOS_CLKREG(0x08600)
+#define EXYNOS4_CLKGATE_IP_RIGHTBUS		EXYNOS_CLKREG(0x08800)
 
-#define S5P_EPLL_LOCK			S5P_CLKREG(0x0C010)
-#define S5P_VPLL_LOCK			S5P_CLKREG(0x0C020)
+#define EXYNOS4_EPLL_LOCK			EXYNOS_CLKREG(0x0C010)
+#define EXYNOS4_VPLL_LOCK			EXYNOS_CLKREG(0x0C020)
 
-#define S5P_EPLL_CON0			S5P_CLKREG(0x0C110)
-#define S5P_EPLL_CON1			S5P_CLKREG(0x0C114)
-#define S5P_VPLL_CON0			S5P_CLKREG(0x0C120)
-#define S5P_VPLL_CON1			S5P_CLKREG(0x0C124)
+#define EXYNOS4_EPLL_CON0			EXYNOS_CLKREG(0x0C110)
+#define EXYNOS4_EPLL_CON1			EXYNOS_CLKREG(0x0C114)
+#define EXYNOS4_VPLL_CON0			EXYNOS_CLKREG(0x0C120)
+#define EXYNOS4_VPLL_CON1			EXYNOS_CLKREG(0x0C124)
 
-#define S5P_CLKSRC_TOP0			S5P_CLKREG(0x0C210)
-#define S5P_CLKSRC_TOP1			S5P_CLKREG(0x0C214)
-#define S5P_CLKSRC_CAM			S5P_CLKREG(0x0C220)
-#define S5P_CLKSRC_TV			S5P_CLKREG(0x0C224)
-#define S5P_CLKSRC_MFC			S5P_CLKREG(0x0C228)
-#define S5P_CLKSRC_G3D			S5P_CLKREG(0x0C22C)
-#define S5P_CLKSRC_IMAGE		S5P_CLKREG(0x0C230)
-#define S5P_CLKSRC_LCD0			S5P_CLKREG(0x0C234)
-#define S5P_CLKSRC_MAUDIO		S5P_CLKREG(0x0C23C)
-#define S5P_CLKSRC_FSYS			S5P_CLKREG(0x0C240)
-#define S5P_CLKSRC_PERIL0		S5P_CLKREG(0x0C250)
-#define S5P_CLKSRC_PERIL1		S5P_CLKREG(0x0C254)
+#define EXYNOS4_CLKSRC_TOP0			EXYNOS_CLKREG(0x0C210)
+#define EXYNOS4_CLKSRC_TOP1			EXYNOS_CLKREG(0x0C214)
+#define EXYNOS4_CLKSRC_CAM			EXYNOS_CLKREG(0x0C220)
+#define EXYNOS4_CLKSRC_TV			EXYNOS_CLKREG(0x0C224)
+#define EXYNOS4_CLKSRC_MFC			EXYNOS_CLKREG(0x0C228)
+#define EXYNOS4_CLKSRC_G3D			EXYNOS_CLKREG(0x0C22C)
+#define EXYNOS4_CLKSRC_IMAGE			EXYNOS_CLKREG(0x0C230)
+#define EXYNOS4_CLKSRC_LCD0			EXYNOS_CLKREG(0x0C234)
+#define EXYNOS4_CLKSRC_MAUDIO			EXYNOS_CLKREG(0x0C23C)
+#define EXYNOS4_CLKSRC_FSYS			EXYNOS_CLKREG(0x0C240)
+#define EXYNOS4_CLKSRC_PERIL0			EXYNOS_CLKREG(0x0C250)
+#define EXYNOS4_CLKSRC_PERIL1			EXYNOS_CLKREG(0x0C254)
 
-#define S5P_CLKSRC_MASK_TOP		S5P_CLKREG(0x0C310)
-#define S5P_CLKSRC_MASK_CAM		S5P_CLKREG(0x0C320)
-#define S5P_CLKSRC_MASK_TV		S5P_CLKREG(0x0C324)
-#define S5P_CLKSRC_MASK_LCD0		S5P_CLKREG(0x0C334)
-#define S5P_CLKSRC_MASK_MAUDIO		S5P_CLKREG(0x0C33C)
-#define S5P_CLKSRC_MASK_FSYS		S5P_CLKREG(0x0C340)
-#define S5P_CLKSRC_MASK_PERIL0		S5P_CLKREG(0x0C350)
-#define S5P_CLKSRC_MASK_PERIL1		S5P_CLKREG(0x0C354)
+#define EXYNOS4_CLKSRC_MASK_TOP			EXYNOS_CLKREG(0x0C310)
+#define EXYNOS4_CLKSRC_MASK_CAM			EXYNOS_CLKREG(0x0C320)
+#define EXYNOS4_CLKSRC_MASK_TV			EXYNOS_CLKREG(0x0C324)
+#define EXYNOS4_CLKSRC_MASK_LCD0		EXYNOS_CLKREG(0x0C334)
+#define EXYNOS4_CLKSRC_MASK_MAUDIO		EXYNOS_CLKREG(0x0C33C)
+#define EXYNOS4_CLKSRC_MASK_FSYS		EXYNOS_CLKREG(0x0C340)
+#define EXYNOS4_CLKSRC_MASK_PERIL0		EXYNOS_CLKREG(0x0C350)
+#define EXYNOS4_CLKSRC_MASK_PERIL1		EXYNOS_CLKREG(0x0C354)
 
-#define S5P_CLKDIV_TOP			S5P_CLKREG(0x0C510)
-#define S5P_CLKDIV_CAM			S5P_CLKREG(0x0C520)
-#define S5P_CLKDIV_TV			S5P_CLKREG(0x0C524)
-#define S5P_CLKDIV_MFC			S5P_CLKREG(0x0C528)
-#define S5P_CLKDIV_G3D			S5P_CLKREG(0x0C52C)
-#define S5P_CLKDIV_IMAGE		S5P_CLKREG(0x0C530)
-#define S5P_CLKDIV_LCD0			S5P_CLKREG(0x0C534)
-#define S5P_CLKDIV_MAUDIO		S5P_CLKREG(0x0C53C)
-#define S5P_CLKDIV_FSYS0		S5P_CLKREG(0x0C540)
-#define S5P_CLKDIV_FSYS1		S5P_CLKREG(0x0C544)
-#define S5P_CLKDIV_FSYS2		S5P_CLKREG(0x0C548)
-#define S5P_CLKDIV_FSYS3		S5P_CLKREG(0x0C54C)
-#define S5P_CLKDIV_PERIL0		S5P_CLKREG(0x0C550)
-#define S5P_CLKDIV_PERIL1		S5P_CLKREG(0x0C554)
-#define S5P_CLKDIV_PERIL2		S5P_CLKREG(0x0C558)
-#define S5P_CLKDIV_PERIL3		S5P_CLKREG(0x0C55C)
-#define S5P_CLKDIV_PERIL4		S5P_CLKREG(0x0C560)
-#define S5P_CLKDIV_PERIL5		S5P_CLKREG(0x0C564)
-#define S5P_CLKDIV2_RATIO		S5P_CLKREG(0x0C580)
+#define EXYNOS4_CLKDIV_TOP			EXYNOS_CLKREG(0x0C510)
+#define EXYNOS4_CLKDIV_CAM			EXYNOS_CLKREG(0x0C520)
+#define EXYNOS4_CLKDIV_TV			EXYNOS_CLKREG(0x0C524)
+#define EXYNOS4_CLKDIV_MFC			EXYNOS_CLKREG(0x0C528)
+#define EXYNOS4_CLKDIV_G3D			EXYNOS_CLKREG(0x0C52C)
+#define EXYNOS4_CLKDIV_IMAGE			EXYNOS_CLKREG(0x0C530)
+#define EXYNOS4_CLKDIV_LCD0			EXYNOS_CLKREG(0x0C534)
+#define EXYNOS4_CLKDIV_MAUDIO			EXYNOS_CLKREG(0x0C53C)
+#define EXYNOS4_CLKDIV_FSYS0			EXYNOS_CLKREG(0x0C540)
+#define EXYNOS4_CLKDIV_FSYS1			EXYNOS_CLKREG(0x0C544)
+#define EXYNOS4_CLKDIV_FSYS2			EXYNOS_CLKREG(0x0C548)
+#define EXYNOS4_CLKDIV_FSYS3			EXYNOS_CLKREG(0x0C54C)
+#define EXYNOS4_CLKDIV_PERIL0			EXYNOS_CLKREG(0x0C550)
+#define EXYNOS4_CLKDIV_PERIL1			EXYNOS_CLKREG(0x0C554)
+#define EXYNOS4_CLKDIV_PERIL2			EXYNOS_CLKREG(0x0C558)
+#define EXYNOS4_CLKDIV_PERIL3			EXYNOS_CLKREG(0x0C55C)
+#define EXYNOS4_CLKDIV_PERIL4			EXYNOS_CLKREG(0x0C560)
+#define EXYNOS4_CLKDIV_PERIL5			EXYNOS_CLKREG(0x0C564)
+#define EXYNOS4_CLKDIV2_RATIO			EXYNOS_CLKREG(0x0C580)
 
-#define S5P_CLKDIV_STAT_TOP		S5P_CLKREG(0x0C610)
+#define EXYNOS4_CLKDIV_STAT_TOP			EXYNOS_CLKREG(0x0C610)
+#define EXYNOS4_CLKDIV_STAT_MFC			EXYNOS_CLKREG(0x0C628)
 
-#define S5P_CLKGATE_SCLKCAM		S5P_CLKREG(0x0C820)
-#define S5P_CLKGATE_IP_CAM		S5P_CLKREG(0x0C920)
-#define S5P_CLKGATE_IP_TV		S5P_CLKREG(0x0C924)
-#define S5P_CLKGATE_IP_MFC		S5P_CLKREG(0x0C928)
-#define S5P_CLKGATE_IP_G3D		S5P_CLKREG(0x0C92C)
-#define S5P_CLKGATE_IP_IMAGE		(soc_is_exynos4210() ? \
-					S5P_CLKREG(0x0C930) : \
-					S5P_CLKREG(0x04930))
-#define S5P_CLKGATE_IP_IMAGE_4210	S5P_CLKREG(0x0C930)
-#define S5P_CLKGATE_IP_IMAGE_4212	S5P_CLKREG(0x04930)
-#define S5P_CLKGATE_IP_LCD0		S5P_CLKREG(0x0C934)
-#define S5P_CLKGATE_IP_FSYS		S5P_CLKREG(0x0C940)
-#define S5P_CLKGATE_IP_GPS		S5P_CLKREG(0x0C94C)
-#define S5P_CLKGATE_IP_PERIL		S5P_CLKREG(0x0C950)
-#define S5P_CLKGATE_IP_PERIR		(soc_is_exynos4210() ? \
-					S5P_CLKREG(0x0C960) : \
-					S5P_CLKREG(0x08960))
-#define S5P_CLKGATE_IP_PERIR_4210	S5P_CLKREG(0x0C960)
-#define S5P_CLKGATE_IP_PERIR_4212	S5P_CLKREG(0x08960)
-#define S5P_CLKGATE_BLOCK		S5P_CLKREG(0x0C970)
+#define EXYNOS4_CLKGATE_SCLKCAM			EXYNOS_CLKREG(0x0C820)
+#define EXYNOS4_CLKGATE_IP_CAM			EXYNOS_CLKREG(0x0C920)
+#define EXYNOS4_CLKGATE_IP_TV			EXYNOS_CLKREG(0x0C924)
+#define EXYNOS4_CLKGATE_IP_MFC			EXYNOS_CLKREG(0x0C928)
+#define EXYNOS4_CLKGATE_IP_G3D			EXYNOS_CLKREG(0x0C92C)
+#define EXYNOS4_CLKGATE_IP_IMAGE		(soc_is_exynos4210() ? \
+						EXYNOS_CLKREG(0x0C930) : \
+						EXYNOS_CLKREG(0x04930))
+#define EXYNOS4210_CLKGATE_IP_IMAGE		EXYNOS_CLKREG(0x0C930)
+#define EXYNOS4212_CLKGATE_IP_IMAGE		EXYNOS_CLKREG(0x04930)
+#define EXYNOS4_CLKGATE_IP_LCD0			EXYNOS_CLKREG(0x0C934)
+#define EXYNOS4_CLKGATE_IP_FSYS			EXYNOS_CLKREG(0x0C940)
+#define EXYNOS4_CLKGATE_IP_GPS			EXYNOS_CLKREG(0x0C94C)
+#define EXYNOS4_CLKGATE_IP_PERIL		EXYNOS_CLKREG(0x0C950)
+#define EXYNOS4_CLKGATE_IP_PERIR		(soc_is_exynos4210() ? \
+						EXYNOS_CLKREG(0x0C960) : \
+						EXYNOS_CLKREG(0x08960))
+#define EXYNOS4210_CLKGATE_IP_PERIR		EXYNOS_CLKREG(0x0C960)
+#define EXYNOS4212_CLKGATE_IP_PERIR		EXYNOS_CLKREG(0x08960)
+#define EXYNOS4_CLKGATE_BLOCK			EXYNOS_CLKREG(0x0C970)
 
-#define S5P_CLKSRC_MASK_DMC		S5P_CLKREG(0x10300)
-#define S5P_CLKSRC_DMC			S5P_CLKREG(0x10200)
-#define S5P_CLKDIV_DMC0			S5P_CLKREG(0x10500)
-#define S5P_CLKDIV_DMC1			S5P_CLKREG(0x10504)
-#define S5P_CLKDIV_STAT_DMC0		S5P_CLKREG(0x10600)
-#define S5P_CLKGATE_IP_DMC		S5P_CLKREG(0x10900)
+#define EXYNOS4_CLKSRC_MASK_DMC			EXYNOS_CLKREG(0x10300)
+#define EXYNOS4_CLKSRC_DMC			EXYNOS_CLKREG(0x10200)
+#define EXYNOS4_CLKDIV_DMC0			EXYNOS_CLKREG(0x10500)
+#define EXYNOS4_CLKDIV_DMC1			EXYNOS_CLKREG(0x10504)
+#define EXYNOS4_CLKDIV_STAT_DMC0		EXYNOS_CLKREG(0x10600)
+#define EXYNOS4_CLKDIV_STAT_DMC1		EXYNOS_CLKREG(0x10604)
+#define EXYNOS4_CLKGATE_IP_DMC			EXYNOS_CLKREG(0x10900)
 
-#define S5P_APLL_LOCK			S5P_CLKREG(0x14000)
-#define S5P_MPLL_LOCK			(soc_is_exynos4210() ? \
-					S5P_CLKREG(0x14004) :  \
-					S5P_CLKREG(0x10008))
-#define S5P_APLL_CON0			S5P_CLKREG(0x14100)
-#define S5P_APLL_CON1			S5P_CLKREG(0x14104)
-#define S5P_MPLL_CON0			(soc_is_exynos4210() ? \
-					S5P_CLKREG(0x14108) : \
-					S5P_CLKREG(0x10108))
-#define S5P_MPLL_CON1			(soc_is_exynos4210() ? \
-					S5P_CLKREG(0x1410C) : \
-					S5P_CLKREG(0x1010C))
+#define EXYNOS4_DMC_PAUSE_CTRL			EXYNOS_CLKREG(0x11094)
+#define EXYNOS4_DMC_PAUSE_ENABLE		(1 << 0)
 
-#define S5P_CLKSRC_CPU			S5P_CLKREG(0x14200)
-#define S5P_CLKMUX_STATCPU		S5P_CLKREG(0x14400)
+#define EXYNOS4_APLL_LOCK			EXYNOS_CLKREG(0x14000)
+#define EXYNOS4_MPLL_LOCK			(soc_is_exynos4210() ? \
+						EXYNOS_CLKREG(0x14004) :  \
+						EXYNOS_CLKREG(0x10008))
+#define EXYNOS4_APLL_CON0			EXYNOS_CLKREG(0x14100)
+#define EXYNOS4_APLL_CON1			EXYNOS_CLKREG(0x14104)
+#define EXYNOS4_MPLL_CON0			(soc_is_exynos4210() ? \
+						EXYNOS_CLKREG(0x14108) : \
+						EXYNOS_CLKREG(0x10108))
+#define EXYNOS4_MPLL_CON1			(soc_is_exynos4210() ? \
+						EXYNOS_CLKREG(0x1410C) : \
+						EXYNOS_CLKREG(0x1010C))
 
-#define S5P_CLKDIV_CPU			S5P_CLKREG(0x14500)
-#define S5P_CLKDIV_CPU1			S5P_CLKREG(0x14504)
-#define S5P_CLKDIV_STATCPU		S5P_CLKREG(0x14600)
-#define S5P_CLKDIV_STATCPU1		S5P_CLKREG(0x14604)
+#define EXYNOS4_CLKSRC_CPU			EXYNOS_CLKREG(0x14200)
+#define EXYNOS4_CLKMUX_STATCPU			EXYNOS_CLKREG(0x14400)
 
-#define S5P_CLKGATE_SCLKCPU		S5P_CLKREG(0x14800)
-#define S5P_CLKGATE_IP_CPU		S5P_CLKREG(0x14900)
+#define EXYNOS4_CLKDIV_CPU			EXYNOS_CLKREG(0x14500)
+#define EXYNOS4_CLKDIV_CPU1			EXYNOS_CLKREG(0x14504)
+#define EXYNOS4_CLKDIV_STATCPU			EXYNOS_CLKREG(0x14600)
+#define EXYNOS4_CLKDIV_STATCPU1			EXYNOS_CLKREG(0x14604)
 
-#define S5P_APLL_LOCKTIME		(0x1C20)	/* 300us */
+#define EXYNOS4_CLKGATE_SCLKCPU			EXYNOS_CLKREG(0x14800)
+#define EXYNOS4_CLKGATE_IP_CPU			EXYNOS_CLKREG(0x14900)
 
-#define S5P_APLLCON0_ENABLE_SHIFT	(31)
-#define S5P_APLLCON0_LOCKED_SHIFT	(29)
-#define S5P_APLL_VAL_1000		((250 << 16) | (6 << 8) | 1)
-#define S5P_APLL_VAL_800		((200 << 16) | (6 << 8) | 1)
+#define EXYNOS4_APLL_LOCKTIME			(0x1C20)	/* 300us */
 
-#define S5P_EPLLCON0_ENABLE_SHIFT	(31)
-#define S5P_EPLLCON0_LOCKED_SHIFT	(29)
+#define EXYNOS4_APLLCON0_ENABLE_SHIFT		(31)
+#define EXYNOS4_APLLCON0_LOCKED_SHIFT		(29)
+#define EXYNOS4_APLL_VAL_1000			((250 << 16) | (6 << 8) | 1)
+#define EXYNOS4_APLL_VAL_800			((200 << 16) | (6 << 8) | 1)
 
-#define S5P_VPLLCON0_ENABLE_SHIFT	(31)
-#define S5P_VPLLCON0_LOCKED_SHIFT	(29)
+#define EXYNOS4_EPLLCON0_ENABLE_SHIFT		(31)
+#define EXYNOS4_EPLLCON0_LOCKED_SHIFT		(29)
 
-#define S5P_CLKSRC_CPU_MUXCORE_SHIFT	(16)
-#define S5P_CLKMUX_STATCPU_MUXCORE_MASK	(0x7 << S5P_CLKSRC_CPU_MUXCORE_SHIFT)
+#define EXYNOS4_VPLLCON0_ENABLE_SHIFT		(31)
+#define EXYNOS4_VPLLCON0_LOCKED_SHIFT		(29)
 
-#define S5P_CLKDIV_CPU0_CORE_SHIFT	(0)
-#define S5P_CLKDIV_CPU0_CORE_MASK	(0x7 << S5P_CLKDIV_CPU0_CORE_SHIFT)
-#define S5P_CLKDIV_CPU0_COREM0_SHIFT	(4)
-#define S5P_CLKDIV_CPU0_COREM0_MASK	(0x7 << S5P_CLKDIV_CPU0_COREM0_SHIFT)
-#define S5P_CLKDIV_CPU0_COREM1_SHIFT	(8)
-#define S5P_CLKDIV_CPU0_COREM1_MASK	(0x7 << S5P_CLKDIV_CPU0_COREM1_SHIFT)
-#define S5P_CLKDIV_CPU0_PERIPH_SHIFT	(12)
-#define S5P_CLKDIV_CPU0_PERIPH_MASK	(0x7 << S5P_CLKDIV_CPU0_PERIPH_SHIFT)
-#define S5P_CLKDIV_CPU0_ATB_SHIFT	(16)
-#define S5P_CLKDIV_CPU0_ATB_MASK	(0x7 << S5P_CLKDIV_CPU0_ATB_SHIFT)
-#define S5P_CLKDIV_CPU0_PCLKDBG_SHIFT	(20)
-#define S5P_CLKDIV_CPU0_PCLKDBG_MASK	(0x7 << S5P_CLKDIV_CPU0_PCLKDBG_SHIFT)
-#define S5P_CLKDIV_CPU0_APLL_SHIFT	(24)
-#define S5P_CLKDIV_CPU0_APLL_MASK	(0x7 << S5P_CLKDIV_CPU0_APLL_SHIFT)
+#define EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT	(16)
+#define EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK	(0x7 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT)
 
-#define S5P_CLKDIV_DMC0_ACP_SHIFT	(0)
-#define S5P_CLKDIV_DMC0_ACP_MASK	(0x7 << S5P_CLKDIV_DMC0_ACP_SHIFT)
-#define S5P_CLKDIV_DMC0_ACPPCLK_SHIFT	(4)
-#define S5P_CLKDIV_DMC0_ACPPCLK_MASK	(0x7 << S5P_CLKDIV_DMC0_ACPPCLK_SHIFT)
-#define S5P_CLKDIV_DMC0_DPHY_SHIFT	(8)
-#define S5P_CLKDIV_DMC0_DPHY_MASK	(0x7 << S5P_CLKDIV_DMC0_DPHY_SHIFT)
-#define S5P_CLKDIV_DMC0_DMC_SHIFT	(12)
-#define S5P_CLKDIV_DMC0_DMC_MASK	(0x7 << S5P_CLKDIV_DMC0_DMC_SHIFT)
-#define S5P_CLKDIV_DMC0_DMCD_SHIFT	(16)
-#define S5P_CLKDIV_DMC0_DMCD_MASK	(0x7 << S5P_CLKDIV_DMC0_DMCD_SHIFT)
-#define S5P_CLKDIV_DMC0_DMCP_SHIFT	(20)
-#define S5P_CLKDIV_DMC0_DMCP_MASK	(0x7 << S5P_CLKDIV_DMC0_DMCP_SHIFT)
-#define S5P_CLKDIV_DMC0_COPY2_SHIFT	(24)
-#define S5P_CLKDIV_DMC0_COPY2_MASK	(0x7 << S5P_CLKDIV_DMC0_COPY2_SHIFT)
-#define S5P_CLKDIV_DMC0_CORETI_SHIFT	(28)
-#define S5P_CLKDIV_DMC0_CORETI_MASK	(0x7 << S5P_CLKDIV_DMC0_CORETI_SHIFT)
+#define EXYNOS4_CLKDIV_CPU0_CORE_SHIFT		(0)
+#define EXYNOS4_CLKDIV_CPU0_CORE_MASK		(0x7 << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT)
+#define EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT	(4)
+#define EXYNOS4_CLKDIV_CPU0_COREM0_MASK		(0x7 << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT)
+#define EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT	(8)
+#define EXYNOS4_CLKDIV_CPU0_COREM1_MASK		(0x7 << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT)
+#define EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT	(12)
+#define EXYNOS4_CLKDIV_CPU0_PERIPH_MASK		(0x7 << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT)
+#define EXYNOS4_CLKDIV_CPU0_ATB_SHIFT		(16)
+#define EXYNOS4_CLKDIV_CPU0_ATB_MASK		(0x7 << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT)
+#define EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT	(20)
+#define EXYNOS4_CLKDIV_CPU0_PCLKDBG_MASK	(0x7 << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT)
+#define EXYNOS4_CLKDIV_CPU0_APLL_SHIFT		(24)
+#define EXYNOS4_CLKDIV_CPU0_APLL_MASK		(0x7 << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT)
+#define EXYNOS4_CLKDIV_CPU0_CORE2_SHIFT		28
+#define EXYNOS4_CLKDIV_CPU0_CORE2_MASK		(0x7 << EXYNOS4_CLKDIV_CPU0_CORE2_SHIFT)
 
-#define S5P_CLKDIV_TOP_ACLK200_SHIFT	(0)
-#define S5P_CLKDIV_TOP_ACLK200_MASK	(0x7 << S5P_CLKDIV_TOP_ACLK200_SHIFT)
-#define S5P_CLKDIV_TOP_ACLK100_SHIFT	(4)
-#define S5P_CLKDIV_TOP_ACLK100_MASK	(0xf << S5P_CLKDIV_TOP_ACLK100_SHIFT)
-#define S5P_CLKDIV_TOP_ACLK160_SHIFT	(8)
-#define S5P_CLKDIV_TOP_ACLK160_MASK	(0x7 << S5P_CLKDIV_TOP_ACLK160_SHIFT)
-#define S5P_CLKDIV_TOP_ACLK133_SHIFT	(12)
-#define S5P_CLKDIV_TOP_ACLK133_MASK	(0x7 << S5P_CLKDIV_TOP_ACLK133_SHIFT)
-#define S5P_CLKDIV_TOP_ONENAND_SHIFT	(16)
-#define S5P_CLKDIV_TOP_ONENAND_MASK	(0x7 << S5P_CLKDIV_TOP_ONENAND_SHIFT)
+#define EXYNOS4_CLKDIV_CPU1_COPY_SHIFT		0
+#define EXYNOS4_CLKDIV_CPU1_COPY_MASK		(0x7 << EXYNOS4_CLKDIV_CPU1_COPY_SHIFT)
+#define EXYNOS4_CLKDIV_CPU1_HPM_SHIFT		4
+#define EXYNOS4_CLKDIV_CPU1_HPM_MASK		(0x7 << EXYNOS4_CLKDIV_CPU1_HPM_SHIFT)
+#define EXYNOS4_CLKDIV_CPU1_CORES_SHIFT		8
+#define EXYNOS4_CLKDIV_CPU1_CORES_MASK		(0x7 << EXYNOS4_CLKDIV_CPU1_CORES_SHIFT)
 
-#define S5P_CLKDIV_BUS_GDLR_SHIFT	(0)
-#define S5P_CLKDIV_BUS_GDLR_MASK	(0x7 << S5P_CLKDIV_BUS_GDLR_SHIFT)
-#define S5P_CLKDIV_BUS_GPLR_SHIFT	(4)
-#define S5P_CLKDIV_BUS_GPLR_MASK	(0x7 << S5P_CLKDIV_BUS_GPLR_SHIFT)
+#define EXYNOS4_CLKDIV_DMC0_ACP_SHIFT		(0)
+#define EXYNOS4_CLKDIV_DMC0_ACP_MASK		(0x7 << EXYNOS4_CLKDIV_DMC0_ACP_SHIFT)
+#define EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT	(4)
+#define EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK	(0x7 << EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT)
+#define EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT		(8)
+#define EXYNOS4_CLKDIV_DMC0_DPHY_MASK		(0x7 << EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT)
+#define EXYNOS4_CLKDIV_DMC0_DMC_SHIFT		(12)
+#define EXYNOS4_CLKDIV_DMC0_DMC_MASK		(0x7 << EXYNOS4_CLKDIV_DMC0_DMC_SHIFT)
+#define EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT		(16)
+#define EXYNOS4_CLKDIV_DMC0_DMCD_MASK		(0x7 << EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT)
+#define EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT		(20)
+#define EXYNOS4_CLKDIV_DMC0_DMCP_MASK		(0x7 << EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT)
+#define EXYNOS4_CLKDIV_DMC0_COPY2_SHIFT		(24)
+#define EXYNOS4_CLKDIV_DMC0_COPY2_MASK		(0x7 << EXYNOS4_CLKDIV_DMC0_COPY2_SHIFT)
+#define EXYNOS4_CLKDIV_DMC0_CORETI_SHIFT	(28)
+#define EXYNOS4_CLKDIV_DMC0_CORETI_MASK		(0x7 << EXYNOS4_CLKDIV_DMC0_CORETI_SHIFT)
+
+#define EXYNOS4_CLKDIV_DMC1_G2D_ACP_SHIFT	(0)
+#define EXYNOS4_CLKDIV_DMC1_G2D_ACP_MASK	(0xf << EXYNOS4_CLKDIV_DMC1_G2D_ACP_SHIFT)
+#define EXYNOS4_CLKDIV_DMC1_C2C_SHIFT		(4)
+#define EXYNOS4_CLKDIV_DMC1_C2C_MASK		(0x7 << EXYNOS4_CLKDIV_DMC1_C2C_SHIFT)
+#define EXYNOS4_CLKDIV_DMC1_PWI_SHIFT		(8)
+#define EXYNOS4_CLKDIV_DMC1_PWI_MASK		(0xf << EXYNOS4_CLKDIV_DMC1_PWI_SHIFT)
+#define EXYNOS4_CLKDIV_DMC1_C2CACLK_SHIFT	(12)
+#define EXYNOS4_CLKDIV_DMC1_C2CACLK_MASK	(0x7 << EXYNOS4_CLKDIV_DMC1_C2CACLK_SHIFT)
+#define EXYNOS4_CLKDIV_DMC1_DVSEM_SHIFT		(16)
+#define EXYNOS4_CLKDIV_DMC1_DVSEM_MASK		(0x7f << EXYNOS4_CLKDIV_DMC1_DVSEM_SHIFT)
+#define EXYNOS4_CLKDIV_DMC1_DPM_SHIFT		(24)
+#define EXYNOS4_CLKDIV_DMC1_DPM_MASK		(0x7f << EXYNOS4_CLKDIV_DMC1_DPM_SHIFT)
+
+#define EXYNOS4_CLKDIV_MFC_SHIFT		(0)
+#define EXYNOS4_CLKDIV_MFC_MASK			(0x7 << EXYNOS4_CLKDIV_MFC_SHIFT)
+
+#define EXYNOS4_CLKDIV_TOP_ACLK200_SHIFT	(0)
+#define EXYNOS4_CLKDIV_TOP_ACLK200_MASK		(0x7 << EXYNOS4_CLKDIV_TOP_ACLK200_SHIFT)
+#define EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT	(4)
+#define EXYNOS4_CLKDIV_TOP_ACLK100_MASK		(0xF << EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT)
+#define EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT	(8)
+#define EXYNOS4_CLKDIV_TOP_ACLK160_MASK		(0x7 << EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT)
+#define EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT	(12)
+#define EXYNOS4_CLKDIV_TOP_ACLK133_MASK		(0x7 << EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT)
+#define EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT	(16)
+#define EXYNOS4_CLKDIV_TOP_ONENAND_MASK		(0x7 << EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT)
+#define EXYNOS4_CLKDIV_TOP_ACLK266_GPS_SHIFT	(20)
+#define EXYNOS4_CLKDIV_TOP_ACLK266_GPS_MASK	(0x7 << EXYNOS4_CLKDIV_TOP_ACLK266_GPS_SHIFT)
+#define EXYNOS4_CLKDIV_TOP_ACLK400_MCUISP_SHIFT	(24)
+#define EXYNOS4_CLKDIV_TOP_ACLK400_MCUISP_MASK	(0x7 << EXYNOS4_CLKDIV_TOP_ACLK400_MCUISP_SHIFT)
+
+#define EXYNOS4_CLKDIV_BUS_GDLR_SHIFT		(0)
+#define EXYNOS4_CLKDIV_BUS_GDLR_MASK		(0x7 << EXYNOS4_CLKDIV_BUS_GDLR_SHIFT)
+#define EXYNOS4_CLKDIV_BUS_GPLR_SHIFT		(4)
+#define EXYNOS4_CLKDIV_BUS_GPLR_MASK		(0x7 << EXYNOS4_CLKDIV_BUS_GPLR_SHIFT)
+
+#define EXYNOS4_CLKDIV_CAM_FIMC0_SHIFT		(0)
+#define EXYNOS4_CLKDIV_CAM_FIMC0_MASK		(0xf << EXYNOS4_CLKDIV_CAM_FIMC0_SHIFT)
+#define EXYNOS4_CLKDIV_CAM_FIMC1_SHIFT		(4)
+#define EXYNOS4_CLKDIV_CAM_FIMC1_MASK		(0xf << EXYNOS4_CLKDIV_CAM_FIMC1_SHIFT)
+#define EXYNOS4_CLKDIV_CAM_FIMC2_SHIFT		(8)
+#define EXYNOS4_CLKDIV_CAM_FIMC2_MASK		(0xf << EXYNOS4_CLKDIV_CAM_FIMC2_SHIFT)
+#define EXYNOS4_CLKDIV_CAM_FIMC3_SHIFT		(12)
+#define EXYNOS4_CLKDIV_CAM_FIMC3_MASK		(0xf << EXYNOS4_CLKDIV_CAM_FIMC3_SHIFT)
 
 /* Only for EXYNOS4210 */
 
-#define S5P_CLKSRC_LCD1			S5P_CLKREG(0x0C238)
-#define S5P_CLKSRC_MASK_LCD1		S5P_CLKREG(0x0C338)
-#define S5P_CLKDIV_LCD1			S5P_CLKREG(0x0C538)
-#define S5P_CLKGATE_IP_LCD1		S5P_CLKREG(0x0C938)
+#define EXYNOS4210_CLKSRC_LCD1			EXYNOS_CLKREG(0x0C238)
+#define EXYNOS4210_CLKSRC_MASK_LCD1		EXYNOS_CLKREG(0x0C338)
+#define EXYNOS4210_CLKDIV_LCD1			EXYNOS_CLKREG(0x0C538)
+#define EXYNOS4210_CLKGATE_IP_LCD1		EXYNOS_CLKREG(0x0C938)
+
+/* Only for EXYNOS4212 */
+
+#define EXYNOS4_CLKDIV_CAM1			EXYNOS_CLKREG(0x0C568)
+
+#define EXYNOS4_CLKDIV_STAT_CAM1		EXYNOS_CLKREG(0x0C668)
+
+#define EXYNOS4_CLKDIV_CAM1_JPEG_SHIFT		(0)
+#define EXYNOS4_CLKDIV_CAM1_JPEG_MASK		(0xf << EXYNOS4_CLKDIV_CAM1_JPEG_SHIFT)
+
+/* For EXYNOS5250 */
+
+#define EXYNOS5_APLL_CON0			EXYNOS_CLKREG(0x00100)
+#define EXYNOS5_CLKSRC_CPU			EXYNOS_CLKREG(0x00200)
+#define EXYNOS5_CLKDIV_CPU0			EXYNOS_CLKREG(0x00500)
+#define EXYNOS5_MPLL_CON0			EXYNOS_CLKREG(0x04100)
+#define EXYNOS5_CLKSRC_CORE1			EXYNOS_CLKREG(0x04204)
+
+#define EXYNOS5_CLKGATE_IP_CORE			EXYNOS_CLKREG(0x04900)
+
+#define EXYNOS5_CLKDIV_ACP			EXYNOS_CLKREG(0x08500)
+
+#define EXYNOS5_CLKSRC_TOP2			EXYNOS_CLKREG(0x10218)
+#define EXYNOS5_EPLL_CON0			EXYNOS_CLKREG(0x10130)
+#define EXYNOS5_EPLL_CON1			EXYNOS_CLKREG(0x10134)
+#define EXYNOS5_VPLL_CON0			EXYNOS_CLKREG(0x10140)
+#define EXYNOS5_VPLL_CON1			EXYNOS_CLKREG(0x10144)
+#define EXYNOS5_CPLL_CON0			EXYNOS_CLKREG(0x10120)
+
+#define EXYNOS5_CLKSRC_TOP0			EXYNOS_CLKREG(0x10210)
+#define EXYNOS5_CLKSRC_TOP3			EXYNOS_CLKREG(0x1021C)
+#define EXYNOS5_CLKSRC_GSCL			EXYNOS_CLKREG(0x10220)
+#define EXYNOS5_CLKSRC_DISP1_0			EXYNOS_CLKREG(0x1022C)
+#define EXYNOS5_CLKSRC_FSYS			EXYNOS_CLKREG(0x10244)
+#define EXYNOS5_CLKSRC_PERIC0			EXYNOS_CLKREG(0x10250)
+
+#define EXYNOS5_CLKSRC_MASK_TOP			EXYNOS_CLKREG(0x10310)
+#define EXYNOS5_CLKSRC_MASK_GSCL		EXYNOS_CLKREG(0x10320)
+#define EXYNOS5_CLKSRC_MASK_DISP1_0		EXYNOS_CLKREG(0x1032C)
+#define EXYNOS5_CLKSRC_MASK_FSYS		EXYNOS_CLKREG(0x10340)
+#define EXYNOS5_CLKSRC_MASK_PERIC0		EXYNOS_CLKREG(0x10350)
+
+#define EXYNOS5_CLKDIV_TOP0			EXYNOS_CLKREG(0x10510)
+#define EXYNOS5_CLKDIV_TOP1			EXYNOS_CLKREG(0x10514)
+#define EXYNOS5_CLKDIV_GSCL			EXYNOS_CLKREG(0x10520)
+#define EXYNOS5_CLKDIV_DISP1_0			EXYNOS_CLKREG(0x1052C)
+#define EXYNOS5_CLKDIV_GEN			EXYNOS_CLKREG(0x1053C)
+#define EXYNOS5_CLKDIV_FSYS0			EXYNOS_CLKREG(0x10548)
+#define EXYNOS5_CLKDIV_FSYS1			EXYNOS_CLKREG(0x1054C)
+#define EXYNOS5_CLKDIV_FSYS2			EXYNOS_CLKREG(0x10550)
+#define EXYNOS5_CLKDIV_FSYS3			EXYNOS_CLKREG(0x10554)
+#define EXYNOS5_CLKDIV_PERIC0			EXYNOS_CLKREG(0x10558)
+
+#define EXYNOS5_CLKGATE_IP_ACP			EXYNOS_CLKREG(0x08800)
+#define EXYNOS5_CLKGATE_IP_GSCL			EXYNOS_CLKREG(0x10920)
+#define EXYNOS5_CLKGATE_IP_DISP1		EXYNOS_CLKREG(0x10928)
+#define EXYNOS5_CLKGATE_IP_MFC			EXYNOS_CLKREG(0x1092C)
+#define EXYNOS5_CLKGATE_IP_GEN			EXYNOS_CLKREG(0x10934)
+#define EXYNOS5_CLKGATE_IP_FSYS			EXYNOS_CLKREG(0x10944)
+#define EXYNOS5_CLKGATE_IP_GPS			EXYNOS_CLKREG(0x1094C)
+#define EXYNOS5_CLKGATE_IP_PERIC		EXYNOS_CLKREG(0x10950)
+#define EXYNOS5_CLKGATE_IP_PERIS		EXYNOS_CLKREG(0x10960)
+#define EXYNOS5_CLKGATE_BLOCK			EXYNOS_CLKREG(0x10980)
+
+#define EXYNOS5_BPLL_CON0			EXYNOS_CLKREG(0x20110)
+#define EXYNOS5_CLKSRC_CDREX			EXYNOS_CLKREG(0x20200)
+#define EXYNOS5_CLKDIV_CDREX			EXYNOS_CLKREG(0x20500)
+
+#define EXYNOS5_EPLL_LOCK			EXYNOS_CLKREG(0x10030)
+
+#define EXYNOS5_EPLLCON0_LOCKED_SHIFT		(29)
 
 /* Compatibility defines and inclusion */
 
 #include <mach/regs-pmu.h>
 
-#define S5P_EPLL_CON			S5P_EPLL_CON0
+#define S5P_EPLL_CON				EXYNOS4_EPLL_CON0
 
 #endif /* __ASM_ARCH_REGS_CLOCK_H */
diff --git a/arch/arm/mach-exynos/include/mach/regs-gpio.h b/arch/arm/mach-exynos/include/mach/regs-gpio.h
index 1401b21..e4b5b60 100644
--- a/arch/arm/mach-exynos/include/mach/regs-gpio.h
+++ b/arch/arm/mach-exynos/include/mach/regs-gpio.h
@@ -16,6 +16,15 @@
 #include <mach/map.h>
 #include <mach/irqs.h>
 
+#define EINT_REG_NR(x)			(EINT_OFFSET(x) >> 3)
+#define EINT_CON(b, x)			(b + 0xE00 + (EINT_REG_NR(x) * 4))
+#define EINT_FLTCON(b, x)		(b + 0xE80 + (EINT_REG_NR(x) * 4))
+#define EINT_MASK(b, x)			(b + 0xF00 + (EINT_REG_NR(x) * 4))
+#define EINT_PEND(b, x)			(b + 0xF40 + (EINT_REG_NR(x) * 4))
+
+#define EINT_OFFSET_BIT(x)		(1 << (EINT_OFFSET(x) & 0x7))
+
+/* compatibility for plat-s5p/irq-pm.c */
 #define EXYNOS4_EINT40CON		(S5P_VA_GPIO2 + 0xE00)
 #define S5P_EINT_CON(x)			(EXYNOS4_EINT40CON + ((x) * 0x4))
 
@@ -28,15 +37,4 @@
 #define EXYNOS4_EINT40PEND		(S5P_VA_GPIO2 + 0xF40)
 #define S5P_EINT_PEND(x)		(EXYNOS4_EINT40PEND + ((x) * 0x4))
 
-#define EINT_REG_NR(x)			(EINT_OFFSET(x) >> 3)
-
-#define eint_irq_to_bit(irq)		(1 << (EINT_OFFSET(irq) & 0x7))
-
-#define EINT_MODE			S3C_GPIO_SFN(0xf)
-
-#define EINT_GPIO_0(x)			EXYNOS4_GPX0(x)
-#define EINT_GPIO_1(x)			EXYNOS4_GPX1(x)
-#define EINT_GPIO_2(x)			EXYNOS4_GPX2(x)
-#define EINT_GPIO_3(x)			EXYNOS4_GPX3(x)
-
 #endif /* __ASM_ARCH_REGS_GPIO_H */
diff --git a/arch/arm/mach-exynos/include/mach/regs-pmu.h b/arch/arm/mach-exynos/include/mach/regs-pmu.h
index 4fff8e9..4c53f38 100644
--- a/arch/arm/mach-exynos/include/mach/regs-pmu.h
+++ b/arch/arm/mach-exynos/include/mach/regs-pmu.h
@@ -31,6 +31,7 @@
 #define S5P_USE_STANDBYWFE_ISP_ARM		(1 << 26)
 
 #define S5P_SWRESET				S5P_PMUREG(0x0400)
+#define EXYNOS_SWRESET				S5P_PMUREG(0x0400)
 
 #define S5P_WAKEUP_STAT				S5P_PMUREG(0x0600)
 #define S5P_EINT_WAKEUP_MASK			S5P_PMUREG(0x0604)
diff --git a/arch/arm/mach-exynos/include/mach/system.h b/arch/arm/mach-exynos/include/mach/system.h
deleted file mode 100644
index 0063a6d..0000000
--- a/arch/arm/mach-exynos/include/mach/system.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* linux/arch/arm/mach-exynos4/include/mach/system.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * EXYNOS4 - system support 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 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H __FILE__
-
-static void arch_idle(void)
-{
-	/* nothing here yet */
-}
-#endif /* __ASM_ARCH_SYSTEM_H */
diff --git a/arch/arm/mach-exynos/include/mach/uncompress.h b/arch/arm/mach-exynos/include/mach/uncompress.h
index 21d97bc..2979995 100644
--- a/arch/arm/mach-exynos/include/mach/uncompress.h
+++ b/arch/arm/mach-exynos/include/mach/uncompress.h
@@ -1,9 +1,8 @@
-/* linux/arch/arm/mach-exynos4/include/mach/uncompress.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com
  *
- * EXYNOS4 - uncompress code
+ * EXYNOS - uncompress code
  *
  * 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
@@ -13,12 +12,35 @@
 #ifndef __ASM_ARCH_UNCOMPRESS_H
 #define __ASM_ARCH_UNCOMPRESS_H __FILE__
 
+#include <asm/mach-types.h>
+
 #include <mach/map.h>
+
+volatile u8 *uart_base;
+
 #include <plat/uncompress.h>
 
+static unsigned int __raw_readl(unsigned int ptr)
+{
+	return *((volatile unsigned int *)ptr);
+}
+
 static void arch_detect_cpu(void)
 {
-	/* we do not need to do any cpu detection here at the moment. */
+	u32 chip_id = __raw_readl(EXYNOS_PA_CHIPID);
+
+	/*
+	 * product_id is bits 31:12
+	 *    bits 23:20 describe the exynosX family
+	 *
+	 */
+	chip_id >>= 20;
+	chip_id &= 0xf;
+
+	if (chip_id == 0x5)
+		uart_base = (volatile u8 *)EXYNOS5_PA_UART + (S3C_UART_OFFSET * CONFIG_S3C_LOWLEVEL_UART_PORT);
+	else
+		uart_base = (volatile u8 *)EXYNOS4_PA_UART + (S3C_UART_OFFSET * CONFIG_S3C_LOWLEVEL_UART_PORT);
 
 	/*
 	 * For preventing FIFO overrun or infinite loop of UART console,
diff --git a/arch/arm/mach-exynos/mach-exynos4-dt.c b/arch/arm/mach-exynos/mach-exynos4-dt.c
index e6b02fd..8245f1c 100644
--- a/arch/arm/mach-exynos/mach-exynos4-dt.c
+++ b/arch/arm/mach-exynos/mach-exynos4-dt.c
@@ -37,13 +37,13 @@
  * data from the device tree.
  */
 static const struct of_dev_auxdata exynos4210_auxdata_lookup[] __initconst = {
-	OF_DEV_AUXDATA("samsung,exynos4210-uart", S5P_PA_UART0,
+	OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS4_PA_UART0,
 				"exynos4210-uart.0", NULL),
-	OF_DEV_AUXDATA("samsung,exynos4210-uart", S5P_PA_UART1,
+	OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS4_PA_UART1,
 				"exynos4210-uart.1", NULL),
-	OF_DEV_AUXDATA("samsung,exynos4210-uart", S5P_PA_UART2,
+	OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS4_PA_UART2,
 				"exynos4210-uart.2", NULL),
-	OF_DEV_AUXDATA("samsung,exynos4210-uart", S5P_PA_UART3,
+	OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS4_PA_UART3,
 				"exynos4210-uart.3", NULL),
 	OF_DEV_AUXDATA("samsung,exynos4210-sdhci", EXYNOS4_PA_HSMMC(0),
 				"exynos4-sdhci.0", NULL),
diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c
new file mode 100644
index 0000000..0d26f50
--- /dev/null
+++ b/arch/arm/mach-exynos/mach-exynos5-dt.c
@@ -0,0 +1,78 @@
+/*
+ * SAMSUNG EXYNOS5250 Flattened Device Tree enabled machine
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *		http://www.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/of_platform.h>
+#include <linux/serial_core.h>
+
+#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
+#include <mach/map.h>
+
+#include <plat/cpu.h>
+#include <plat/regs-serial.h>
+
+#include "common.h"
+
+/*
+ * The following lookup table is used to override device names when devices
+ * are registered from device tree. This is temporarily added to enable
+ * device tree support addition for the EXYNOS5 architecture.
+ *
+ * For drivers that require platform data to be provided from the machine
+ * file, a platform data pointer can also be supplied along with the
+ * devices names. Usually, the platform data elements that cannot be parsed
+ * from the device tree by the drivers (example: function pointers) are
+ * supplied. But it should be noted that this is a temporary mechanism and
+ * at some point, the drivers should be capable of parsing all the platform
+ * data from the device tree.
+ */
+static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = {
+	OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS5_PA_UART0,
+				"exynos4210-uart.0", NULL),
+	OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS5_PA_UART1,
+				"exynos4210-uart.1", NULL),
+	OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS5_PA_UART2,
+				"exynos4210-uart.2", NULL),
+	OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS5_PA_UART3,
+				"exynos4210-uart.3", NULL),
+	OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA0, "dma-pl330.0", NULL),
+	OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA1, "dma-pl330.1", NULL),
+	OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA1, "dma-pl330.2", NULL),
+	{},
+};
+
+static void __init exynos5250_dt_map_io(void)
+{
+	exynos_init_io(NULL, 0);
+	s3c24xx_init_clocks(24000000);
+}
+
+static void __init exynos5250_dt_machine_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table,
+				exynos5250_auxdata_lookup, NULL);
+}
+
+static char const *exynos5250_dt_compat[] __initdata = {
+	"samsung,exynos5250",
+	NULL
+};
+
+DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)")
+	/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
+	.init_irq	= exynos5_init_irq,
+	.map_io		= exynos5250_dt_map_io,
+	.handle_irq	= gic_handle_irq,
+	.init_machine	= exynos5250_dt_machine_init,
+	.timer		= &exynos4_timer,
+	.dt_compat	= exynos5250_dt_compat,
+	.restart        = exynos5_restart,
+MACHINE_END
diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
index aa37179..b3982c8 100644
--- a/arch/arm/mach-exynos/mach-nuri.c
+++ b/arch/arm/mach-exynos/mach-nuri.c
@@ -28,6 +28,7 @@
 
 #include <video/platform_lcd.h>
 #include <media/m5mols.h>
+#include <media/s5k6aa.h>
 #include <media/s5p_fimc.h>
 #include <media/v4l2-mediabus.h>
 
@@ -75,6 +76,7 @@
 	FIXED_REG_ID_MAX8903,
 	FIXED_REG_ID_CAM_A28V,
 	FIXED_REG_ID_CAM_12V,
+	FIXED_REG_ID_CAM_VT_15V,
 };
 
 static struct s3c2410_uartcfg nuri_uartcfgs[] __initdata = {
@@ -109,13 +111,13 @@
 	.max_width		= 8,
 	.host_caps		= (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA |
 				MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
-				MMC_CAP_DISABLE | MMC_CAP_ERASE),
+				MMC_CAP_ERASE),
 	.cd_type		= S3C_SDHCI_CD_PERMANENT,
 	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 };
 
 static struct regulator_consumer_supply emmc_supplies[] = {
-	REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"),
+	REGULATOR_SUPPLY("vmmc", "exynos4-sdhci.0"),
 	REGULATOR_SUPPLY("vmmc", "dw_mmc"),
 };
 
@@ -148,8 +150,7 @@
 static struct s3c_sdhci_platdata nuri_hsmmc2_data __initdata = {
 	.max_width		= 4,
 	.host_caps		= MMC_CAP_4_BIT_DATA |
-				MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
-				MMC_CAP_DISABLE,
+				MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
 	.ext_cd_gpio		= EXYNOS4_GPX3(3),	/* XEINT_27 */
 	.ext_cd_gpio_invert	= 1,
 	.cd_type		= S3C_SDHCI_CD_GPIO,
@@ -399,6 +400,9 @@
 static struct regulator_consumer_supply __initdata max8997_ldo5_[] = {
 	REGULATOR_SUPPLY("vhsic", "modemctl"), /* MODEM */
 };
+static struct regulator_consumer_supply nuri_max8997_ldo6_consumer[] = {
+	REGULATOR_SUPPLY("vdd_reg", "6-003c"), /* S5K6AA camera */
+};
 static struct regulator_consumer_supply __initdata max8997_ldo7_[] = {
 	REGULATOR_SUPPLY("dig_18", "0-001f"), /* HCD803 */
 };
@@ -413,7 +417,7 @@
 	REGULATOR_SUPPLY("vddio", "6-003c"), /* HDC802 */
 };
 static struct regulator_consumer_supply __initdata max8997_ldo13_[] = {
-	REGULATOR_SUPPLY("vmmc", "s3c-sdhci.2"), /* TFLASH */
+	REGULATOR_SUPPLY("vmmc", "exynos4-sdhci.2"), /* TFLASH */
 };
 static struct regulator_consumer_supply __initdata max8997_ldo14_[] = {
 	REGULATOR_SUPPLY("inmotor", "max8997-haptic"),
@@ -431,7 +435,7 @@
 	REGULATOR_SUPPLY("vdd_arm", NULL), /* CPUFREQ */
 };
 static struct regulator_consumer_supply __initdata max8997_buck2_[] = {
-	REGULATOR_SUPPLY("vdd_int", NULL), /* CPUFREQ */
+	REGULATOR_SUPPLY("vdd_int", "exynos4210-busfreq.0"), /* CPUFREQ */
 };
 static struct regulator_consumer_supply __initdata max8997_buck3_[] = {
 	REGULATOR_SUPPLY("vdd", "mali_dev.0"), /* G3D of Exynos 4 */
@@ -546,6 +550,8 @@
 			.enabled	= 1,
 		},
 	},
+	.num_consumer_supplies	= ARRAY_SIZE(nuri_max8997_ldo6_consumer),
+	.consumer_supplies	= nuri_max8997_ldo6_consumer,
 };
 
 static struct regulator_init_data __initdata max8997_ldo7_data = {
@@ -742,7 +748,7 @@
 	.constraints	= {
 		.name		= "VINT_1.1V_C210",
 		.min_uV		= 900000,
-		.max_uV		= 1100000,
+		.max_uV		= 1200000,
 		.valid_ops_mask	= REGULATOR_CHANGE_VOLTAGE,
 		.always_on	= 1,
 		.state_mem	= {
@@ -957,7 +963,6 @@
 	.regulators		= nuri_max8997_regulators,
 
 	.buck125_gpios = { EXYNOS4_GPX0(5), EXYNOS4_GPX0(6), EXYNOS4_GPL0(0) },
-	.buck2_gpiodvs = true,
 
 	.buck1_voltage[0] = 1350000, /* 1.35V */
 	.buck1_voltage[1] = 1300000, /* 1.3V */
@@ -1116,7 +1121,30 @@
 }
 
 /* CAMERA */
+static struct regulator_consumer_supply cam_vt_cam15_supply =
+	REGULATOR_SUPPLY("vdd_core", "6-003c");
+
+static struct regulator_init_data cam_vt_cam15_reg_init_data = {
+	.constraints = { .valid_ops_mask = REGULATOR_CHANGE_STATUS },
+	.num_consumer_supplies = 1,
+	.consumer_supplies = &cam_vt_cam15_supply,
+};
+
+static struct fixed_voltage_config cam_vt_cam15_fixed_voltage_cfg = {
+	.supply_name	= "VT_CAM_1.5V",
+	.microvolts	= 1500000,
+	.gpio		= EXYNOS4_GPE2(2), /* VT_CAM_1.5V_EN */
+	.enable_high	= 1,
+	.init_data	= &cam_vt_cam15_reg_init_data,
+};
+
+static struct platform_device cam_vt_cam15_fixed_rdev = {
+	.name = "reg-fixed-voltage", .id = FIXED_REG_ID_CAM_VT_15V,
+	.dev = { .platform_data	= &cam_vt_cam15_fixed_voltage_cfg },
+};
+
 static struct regulator_consumer_supply cam_vdda_supply[] = {
+	REGULATOR_SUPPLY("vdda", "6-003c"),
 	REGULATOR_SUPPLY("a_sensor", "0-001f"),
 };
 
@@ -1173,6 +1201,21 @@
 
 #define GPIO_CAM_MEGA_RST	EXYNOS4_GPY3(7) /* ISP_RESET */
 #define GPIO_CAM_8M_ISP_INT	EXYNOS4_GPL2(5)
+#define GPIO_CAM_VT_NSTBY	EXYNOS4_GPL2(0)
+#define GPIO_CAM_VT_NRST	EXYNOS4_GPL2(1)
+
+static struct s5k6aa_platform_data s5k6aa_pldata = {
+	.mclk_frequency	= 24000000UL,
+	.gpio_reset	= { GPIO_CAM_VT_NRST, 0 },
+	.gpio_stby	= { GPIO_CAM_VT_NSTBY, 0 },
+	.bus_type	= V4L2_MBUS_PARALLEL,
+	.horiz_flip	= 1,
+};
+
+static struct i2c_board_info s5k6aa_board_info = {
+	I2C_BOARD_INFO("S5K6AA", 0x3c),
+	.platform_data = &s5k6aa_pldata,
+};
 
 static struct m5mols_platform_data m5mols_platdata = {
 	.gpio_reset = GPIO_CAM_MEGA_RST,
@@ -1185,6 +1228,13 @@
 
 static struct s5p_fimc_isp_info nuri_camera_sensors[] = {
 	{
+		.flags		= V4L2_MBUS_PCLK_SAMPLE_RISING |
+				  V4L2_MBUS_VSYNC_ACTIVE_LOW,
+		.bus_type	= FIMC_ITU_601,
+		.board_info	= &s5k6aa_board_info,
+		.clk_frequency	= 24000000UL,
+		.i2c_bus_num	= 6,
+	}, {
 		.flags		= V4L2_MBUS_PCLK_SAMPLE_FALLING |
 				  V4L2_MBUS_VSYNC_ACTIVE_LOW,
 		.bus_type	= FIMC_MIPI_CSI2,
@@ -1200,11 +1250,13 @@
 };
 
 static struct gpio nuri_camera_gpios[] = {
+	{ GPIO_CAM_VT_NSTBY,	GPIOF_OUT_INIT_LOW, "CAM_VGA_NSTBY" },
+	{ GPIO_CAM_VT_NRST,	GPIOF_OUT_INIT_LOW, "CAM_VGA_NRST"  },
 	{ GPIO_CAM_8M_ISP_INT,	GPIOF_IN,           "8M_ISP_INT"  },
 	{ GPIO_CAM_MEGA_RST,	GPIOF_OUT_INIT_LOW, "CAM_8M_NRST" },
 };
 
-static void nuri_camera_init(void)
+static void __init nuri_camera_init(void)
 {
 	s3c_set_platdata(&mipi_csis_platdata, sizeof(mipi_csis_platdata),
 			 &s5p_device_mipi_csis0);
@@ -1224,6 +1276,8 @@
 		pr_err("%s: Failed to configure 8M_ISP_INT GPIO\n", __func__);
 
 	/* Free GPIOs controlled directly by the sensor drivers. */
+	gpio_free(GPIO_CAM_VT_NRST);
+	gpio_free(GPIO_CAM_VT_NSTBY);
 	gpio_free(GPIO_CAM_MEGA_RST);
 
 	if (exynos4_fimc_setup_gpio(S5P_CAMPORT_A)) {
@@ -1234,15 +1288,27 @@
 	s5p_gpio_set_drvstr(EXYNOS4_GPJ1(3), S5P_GPIO_DRVSTR_LV4);
 }
 
+static struct s3c2410_platform_i2c nuri_i2c6_platdata __initdata = {
+	.frequency	= 400000U,
+	.sda_delay	= 200,
+	.bus_num	= 6,
+};
+
 static struct s3c2410_platform_i2c nuri_i2c0_platdata __initdata = {
 	.frequency	= 400000U,
 	.sda_delay	= 200,
 };
 
+/* DEVFREQ controlling memory/bus */
+static struct platform_device exynos4_bus_devfreq = {
+	.name			= "exynos4210-busfreq",
+};
+
 static struct platform_device *nuri_devices[] __initdata = {
 	/* Samsung Platform Devices */
 	&s3c_device_i2c5, /* PMIC should initialize first */
 	&s3c_device_i2c0,
+	&s3c_device_i2c6,
 	&emmc_fixed_voltage,
 	&s5p_device_mipi_csis0,
 	&s5p_device_fimc0,
@@ -1259,6 +1325,8 @@
 	&s3c_device_i2c3,
 	&i2c9_gpio,
 	&s3c_device_adc,
+	&s5p_device_g2d,
+	&s5p_device_jpeg,
 	&s3c_device_rtc,
 	&s5p_device_mfc,
 	&s5p_device_mfc_l,
@@ -1271,8 +1339,10 @@
 	&nuri_backlight_device,
 	&max8903_fixed_reg_dev,
 	&nuri_max8903_device,
+	&cam_vt_cam15_fixed_rdev,
 	&cam_vdda_fixed_rdev,
 	&cam_8m_12v_fixed_rdev,
+	&exynos4_bus_devfreq,
 };
 
 static void __init nuri_map_io(void)
@@ -1302,6 +1372,7 @@
 	i2c_register_board_info(5, i2c5_devs, ARRAY_SIZE(i2c5_devs));
 	i2c9_devs[I2C9_MAX17042].irq = gpio_to_irq(EXYNOS4_GPX2(3));
 	i2c_register_board_info(9, i2c9_devs, ARRAY_SIZE(i2c9_devs));
+	s3c_i2c6_set_platdata(&nuri_i2c6_platdata);
 
 	s5p_fimd0_set_platdata(&nuri_fb_pdata);
 
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index fa5c4a5..878d4c9 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -20,6 +20,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/mfd/max8997.h>
 #include <linux/lcd.h>
+#include <linux/rfkill-gpio.h>
 
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
@@ -235,6 +236,7 @@
 		.min_uV		= 2800000,
 		.max_uV		= 2800000,
 		.apply_uV	= 1,
+		.always_on	= 1,
 		.valid_ops_mask	= REGULATOR_CHANGE_STATUS,
 		.state_mem	= {
 			.disabled	= 1,
@@ -278,6 +280,7 @@
 		.min_uV		= 1800000,
 		.max_uV		= 1800000,
 		.apply_uV	= 1,
+		.always_on	= 1,
 		.valid_ops_mask	= REGULATOR_CHANGE_STATUS,
 		.state_mem	= {
 			.disabled	= 1,
@@ -293,6 +296,7 @@
 		.min_uV		= 3300000,
 		.max_uV		= 3300000,
 		.apply_uV	= 1,
+		.always_on	= 1,
 		.valid_ops_mask	= REGULATOR_CHANGE_STATUS,
 		.state_mem	= {
 			.disabled	= 1,
@@ -412,7 +416,7 @@
 	{ MAX8997_BUCK7,	&max8997_buck7_data },
 };
 
-struct max8997_platform_data __initdata origen_max8997_pdata = {
+static struct max8997_platform_data __initdata origen_max8997_pdata = {
 	.num_regulators = ARRAY_SIZE(origen_max8997_regulators),
 	.regulators	= origen_max8997_regulators,
 
@@ -602,6 +606,23 @@
 	.setup_gpio	= exynos4_fimd0_gpio_setup_24bpp,
 };
 
+/* Bluetooth rfkill gpio platform data */
+struct rfkill_gpio_platform_data origen_bt_pdata = {
+	.reset_gpio	= EXYNOS4_GPX2(2),
+	.shutdown_gpio	= -1,
+	.type		= RFKILL_TYPE_BLUETOOTH,
+	.name		= "origen-bt",
+};
+
+/* Bluetooth Platform device */
+static struct platform_device origen_device_bluetooth = {
+	.name		= "rfkill_gpio",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &origen_bt_pdata,
+	},
+};
+
 static struct platform_device *origen_devices[] __initdata = {
 	&s3c_device_hsmmc2,
 	&s3c_device_hsmmc0,
@@ -613,9 +634,12 @@
 	&s5p_device_fimc1,
 	&s5p_device_fimc2,
 	&s5p_device_fimc3,
+	&s5p_device_fimc_md,
 	&s5p_device_fimd0,
+	&s5p_device_g2d,
 	&s5p_device_hdmi,
 	&s5p_device_i2c_hdmiphy,
+	&s5p_device_jpeg,
 	&s5p_device_mfc,
 	&s5p_device_mfc_l,
 	&s5p_device_mfc_r,
@@ -623,6 +647,7 @@
 	&exynos4_device_ohci,
 	&origen_device_gpiokeys,
 	&origen_lcd_hv070wsa,
+	&origen_device_bluetooth,
 };
 
 /* LCD Backlight data */
@@ -636,6 +661,16 @@
 	.pwm_period_ns	= 1000,
 };
 
+static void __init origen_bt_setup(void)
+{
+	gpio_request(EXYNOS4_GPA0(0), "GPIO BT_UART");
+	/* 4 UART Pins configuration */
+	s3c_gpio_cfgrange_nopull(EXYNOS4_GPA0(0), 4, S3C_GPIO_SFN(2));
+	/* Setup BT Reset, this gpio will be requesed by rfkill-gpio */
+	s3c_gpio_cfgpin(EXYNOS4_GPX2(2), S3C_GPIO_OUTPUT);
+	s3c_gpio_setpull(EXYNOS4_GPX2(2), S3C_GPIO_PULL_NONE);
+}
+
 static void s5p_tv_setup(void)
 {
 	/* Direct HPD to HDMI chip */
@@ -689,6 +724,8 @@
 	platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices));
 
 	samsung_bl_set(&origen_bl_gpio_info, &origen_bl_data);
+
+	origen_bt_setup();
 }
 
 MACHINE_START(ORIGEN, "ORIGEN")
diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c
index 5258b85..83b91fa 100644
--- a/arch/arm/mach-exynos/mach-smdkv310.c
+++ b/arch/arm/mach-exynos/mach-smdkv310.c
@@ -270,6 +270,9 @@
 	&s5p_device_fimc1,
 	&s5p_device_fimc2,
 	&s5p_device_fimc3,
+	&s5p_device_fimc_md,
+	&s5p_device_g2d,
+	&s5p_device_jpeg,
 	&exynos4_device_ac97,
 	&exynos4_device_i2s0,
 	&exynos4_device_ohci,
diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c
index b2d495b..6bb9dbd 100644
--- a/arch/arm/mach-exynos/mach-universal_c210.c
+++ b/arch/arm/mach-exynos/mach-universal_c210.c
@@ -47,6 +47,7 @@
 #include <media/v4l2-mediabus.h>
 #include <media/s5p_fimc.h>
 #include <media/m5mols.h>
+#include <media/s5k6aa.h>
 
 #include "common.h"
 
@@ -123,8 +124,10 @@
 static struct regulator_consumer_supply lp3974_buck2_consumer =
 	REGULATOR_SUPPLY("vddg3d", NULL);
 
-static struct regulator_consumer_supply lp3974_buck3_consumer =
-	REGULATOR_SUPPLY("vdet", "s5p-sdo");
+static struct regulator_consumer_supply lp3974_buck3_consumer[] = {
+	REGULATOR_SUPPLY("vdet", "s5p-sdo"),
+	REGULATOR_SUPPLY("vdd_reg", "0-003c"),
+};
 
 static struct regulator_init_data lp3974_buck1_data = {
 	.constraints	= {
@@ -169,8 +172,8 @@
 			.enabled	= 1,
 		},
 	},
-	.num_consumer_supplies = 1,
-	.consumer_supplies = &lp3974_buck3_consumer,
+	.num_consumer_supplies = ARRAY_SIZE(lp3974_buck3_consumer),
+	.consumer_supplies = lp3974_buck3_consumer,
 };
 
 static struct regulator_init_data lp3974_buck4_data = {
@@ -303,6 +306,9 @@
 	.consumer_supplies = lp3974_ldo8_consumer,
 };
 
+static struct regulator_consumer_supply lp3974_ldo9_consumer =
+	REGULATOR_SUPPLY("vddio", "0-003c");
+
 static struct regulator_init_data lp3974_ldo9_data = {
 	.constraints	= {
 		.name		= "VCC_2.8V",
@@ -314,6 +320,8 @@
 			.enabled	= 1,
 		},
 	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &lp3974_ldo9_consumer,
 };
 
 static struct regulator_init_data lp3974_ldo10_data = {
@@ -412,6 +420,7 @@
 };
 
 static struct regulator_consumer_supply lp3974_ldo16_consumer[] = {
+	REGULATOR_SUPPLY("vdda", "0-003c"),
 	REGULATOR_SUPPLY("a_sensor", "0-001f"),
 };
 
@@ -736,14 +745,13 @@
 static struct s3c_sdhci_platdata universal_hsmmc0_data __initdata = {
 	.max_width		= 8,
 	.host_caps		= (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA |
-				MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
-				MMC_CAP_DISABLE),
+				MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
 	.cd_type		= S3C_SDHCI_CD_PERMANENT,
 	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
 };
 
 static struct regulator_consumer_supply mmc0_supplies[] = {
-	REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"),
+	REGULATOR_SUPPLY("vmmc", "exynos4-sdhci.0"),
 };
 
 static struct regulator_init_data mmc0_fixed_voltage_init_data = {
@@ -775,8 +783,7 @@
 static struct s3c_sdhci_platdata universal_hsmmc2_data __initdata = {
 	.max_width		= 4,
 	.host_caps		= MMC_CAP_4_BIT_DATA |
-				MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
-				MMC_CAP_DISABLE,
+				MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
 	.ext_cd_gpio		= EXYNOS4_GPX3(4),      /* XEINT_28 */
 	.ext_cd_gpio_invert	= 1,
 	.cd_type		= S3C_SDHCI_CD_GPIO,
@@ -787,8 +794,7 @@
 static struct s3c_sdhci_platdata universal_hsmmc3_data __initdata = {
 	.max_width		= 4,
 	.host_caps		= MMC_CAP_4_BIT_DATA |
-				MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
-				MMC_CAP_DISABLE,
+				MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
 	.cd_type		= S3C_SDHCI_CD_EXTERNAL,
 };
 
@@ -819,6 +825,8 @@
 	},
 	.max_bpp	= 32,
 	.default_bpp	= 16,
+	.virtual_x	= 480,
+	.virtual_y	= 2 * 800,
 };
 
 static struct s3c_fb_platdata universal_lcd_pdata __initdata = {
@@ -830,6 +838,28 @@
 	.setup_gpio	= exynos4_fimd0_gpio_setup_24bpp,
 };
 
+static struct regulator_consumer_supply cam_vt_dio_supply =
+	REGULATOR_SUPPLY("vdd_core", "0-003c");
+
+static struct regulator_init_data cam_vt_dio_reg_init_data = {
+	.constraints = { .valid_ops_mask = REGULATOR_CHANGE_STATUS },
+	.num_consumer_supplies = 1,
+	.consumer_supplies = &cam_vt_dio_supply,
+};
+
+static struct fixed_voltage_config cam_vt_dio_fixed_voltage_cfg = {
+	.supply_name	= "CAM_VT_D_IO",
+	.microvolts	= 2800000,
+	.gpio		= EXYNOS4_GPE2(1), /* CAM_PWR_EN2 */
+	.enable_high	= 1,
+	.init_data	= &cam_vt_dio_reg_init_data,
+};
+
+static struct platform_device cam_vt_dio_fixed_reg_dev = {
+	.name = "reg-fixed-voltage", .id = FIXED_REG_ID_CAM_VT_DIO,
+	.dev = { .platform_data	= &cam_vt_dio_fixed_voltage_cfg },
+};
+
 static struct regulator_consumer_supply cam_i_core_supply =
 	REGULATOR_SUPPLY("core", "0-001f");
 
@@ -885,6 +915,28 @@
 #define GPIO_CAM_LEVEL_EN(n)	EXYNOS4_GPE4(n + 3)
 #define GPIO_CAM_8M_ISP_INT	EXYNOS4_GPX1(5)	/* XEINT_13 */
 #define GPIO_CAM_MEGA_nRST	EXYNOS4_GPE2(5)
+#define GPIO_CAM_VGA_NRST	EXYNOS4_GPE4(7)
+#define GPIO_CAM_VGA_NSTBY	EXYNOS4_GPE4(6)
+
+static int s5k6aa_set_power(int on)
+{
+	gpio_set_value(GPIO_CAM_LEVEL_EN(2), !!on);
+	return 0;
+}
+
+static struct s5k6aa_platform_data s5k6aa_platdata = {
+	.mclk_frequency	= 21600000UL,
+	.gpio_reset	= { GPIO_CAM_VGA_NRST, 0 },
+	.gpio_stby	= { GPIO_CAM_VGA_NSTBY, 0 },
+	.bus_type	= V4L2_MBUS_PARALLEL,
+	.horiz_flip	= 1,
+	.set_power	= s5k6aa_set_power,
+};
+
+static struct i2c_board_info s5k6aa_board_info = {
+	I2C_BOARD_INFO("S5K6AA", 0x3C),
+	.platform_data = &s5k6aa_platdata,
+};
 
 static int m5mols_set_power(struct device *dev, int on)
 {
@@ -909,6 +961,14 @@
 		.mux_id		= 0,
 		.flags		= V4L2_MBUS_PCLK_SAMPLE_FALLING |
 				  V4L2_MBUS_VSYNC_ACTIVE_LOW,
+		.bus_type	= FIMC_ITU_601,
+		.board_info	= &s5k6aa_board_info,
+		.i2c_bus_num	= 0,
+		.clk_frequency	= 24000000UL,
+	}, {
+		.mux_id		= 0,
+		.flags		= V4L2_MBUS_PCLK_SAMPLE_FALLING |
+				  V4L2_MBUS_VSYNC_ACTIVE_LOW,
 		.bus_type	= FIMC_MIPI_CSI2,
 		.board_info	= &m5mols_board_info,
 		.i2c_bus_num	= 0,
@@ -927,9 +987,11 @@
 	{ GPIO_CAM_LEVEL_EN(2),	GPIOF_OUT_INIT_LOW,  "CAM_LVL_EN2" },
 	{ GPIO_CAM_8M_ISP_INT,	GPIOF_IN,            "8M_ISP_INT"  },
 	{ GPIO_CAM_MEGA_nRST,	GPIOF_OUT_INIT_LOW,  "CAM_8M_NRST" },
+	{ GPIO_CAM_VGA_NRST,	GPIOF_OUT_INIT_LOW,  "CAM_VGA_NRST"  },
+	{ GPIO_CAM_VGA_NSTBY,	GPIOF_OUT_INIT_LOW,  "CAM_VGA_NSTBY" },
 };
 
-static void universal_camera_init(void)
+static void __init universal_camera_init(void)
 {
 	s3c_set_platdata(&mipi_csis_platdata, sizeof(mipi_csis_platdata),
 			 &s5p_device_mipi_csis0);
@@ -950,6 +1012,8 @@
 	/* Free GPIOs controlled directly by the sensor drivers. */
 	gpio_free(GPIO_CAM_MEGA_nRST);
 	gpio_free(GPIO_CAM_8M_ISP_INT);
+	gpio_free(GPIO_CAM_VGA_NRST);
+	gpio_free(GPIO_CAM_VGA_NSTBY);
 
 	if (exynos4_fimc_setup_gpio(S5P_CAMPORT_A))
 		pr_err("Camera port A setup failed\n");
@@ -962,6 +1026,7 @@
 	&s5p_device_fimc1,
 	&s5p_device_fimc2,
 	&s5p_device_fimc3,
+	&s5p_device_g2d,
 	&mmc0_fixed_voltage,
 	&s3c_device_hsmmc0,
 	&s3c_device_hsmmc2,
@@ -980,9 +1045,11 @@
 	&universal_gpio_keys,
 	&s5p_device_onenand,
 	&s5p_device_fimd0,
+	&s5p_device_jpeg,
 	&s5p_device_mfc,
 	&s5p_device_mfc_l,
 	&s5p_device_mfc_r,
+	&cam_vt_dio_fixed_reg_dev,
 	&cam_i_core_fixed_reg_dev,
 	&cam_s_if_fixed_reg_dev,
 	&s5p_device_fimc_md,
@@ -995,7 +1062,7 @@
 	s3c24xx_init_uarts(universal_uartcfgs, ARRAY_SIZE(universal_uartcfgs));
 }
 
-void s5p_tv_setup(void)
+static void s5p_tv_setup(void)
 {
 	/* direct HPD to HDMI chip */
 	gpio_request_one(EXYNOS4_GPX3(7), GPIOF_IN, "hpd-plug");
diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c
index 85b5527..897d9a9 100644
--- a/arch/arm/mach-exynos/mct.c
+++ b/arch/arm/mach-exynos/mct.c
@@ -21,6 +21,7 @@
 #include <linux/percpu.h>
 
 #include <asm/hardware/gic.h>
+#include <asm/localtimer.h>
 
 #include <plat/cpu.h>
 
@@ -29,12 +30,13 @@
 #include <mach/regs-mct.h>
 #include <asm/mach/time.h>
 
+#define TICK_BASE_CNT	1
+
 enum {
 	MCT_INT_SPI,
 	MCT_INT_PPI
 };
 
-static unsigned long clk_cnt_per_tick;
 static unsigned long clk_rate;
 static unsigned int mct_int_type;
 
@@ -205,11 +207,14 @@
 static void exynos4_comp_set_mode(enum clock_event_mode mode,
 				  struct clock_event_device *evt)
 {
+	unsigned long cycles_per_jiffy;
 	exynos4_mct_comp0_stop();
 
 	switch (mode) {
 	case CLOCK_EVT_MODE_PERIODIC:
-		exynos4_mct_comp0_start(mode, clk_cnt_per_tick);
+		cycles_per_jiffy =
+			(((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
+		exynos4_mct_comp0_start(mode, cycles_per_jiffy);
 		break;
 
 	case CLOCK_EVT_MODE_ONESHOT:
@@ -248,9 +253,7 @@
 
 static void exynos4_clockevent_init(void)
 {
-	clk_cnt_per_tick = clk_rate / 2	/ HZ;
-
-	clockevents_calc_mult_shift(&mct_comp_device, clk_rate / 2, 5);
+	clockevents_calc_mult_shift(&mct_comp_device, clk_rate, 5);
 	mct_comp_device.max_delta_ns =
 		clockevent_delta2ns(0xffffffff, &mct_comp_device);
 	mct_comp_device.min_delta_ns =
@@ -258,7 +261,10 @@
 	mct_comp_device.cpumask = cpumask_of(0);
 	clockevents_register_device(&mct_comp_device);
 
-	setup_irq(IRQ_MCT_G0, &mct_comp_event_irq);
+	if (soc_is_exynos5250())
+		setup_irq(EXYNOS5_IRQ_MCT_G0, &mct_comp_event_irq);
+	else
+		setup_irq(EXYNOS4_IRQ_MCT_G0, &mct_comp_event_irq);
 }
 
 #ifdef CONFIG_LOCAL_TIMERS
@@ -314,12 +320,15 @@
 					 struct clock_event_device *evt)
 {
 	struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
+	unsigned long cycles_per_jiffy;
 
 	exynos4_mct_tick_stop(mevt);
 
 	switch (mode) {
 	case CLOCK_EVT_MODE_PERIODIC:
-		exynos4_mct_tick_start(clk_cnt_per_tick, mevt);
+		cycles_per_jiffy =
+			(((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
+		exynos4_mct_tick_start(cycles_per_jiffy, mevt);
 		break;
 
 	case CLOCK_EVT_MODE_ONESHOT:
@@ -375,7 +384,7 @@
 	.handler	= exynos4_mct_tick_isr,
 };
 
-static void exynos4_mct_tick_init(struct clock_event_device *evt)
+static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt)
 {
 	struct mct_clock_event_device *mevt;
 	unsigned int cpu = smp_processor_id();
@@ -393,7 +402,7 @@
 	evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
 	evt->rating = 450;
 
-	clockevents_calc_mult_shift(evt, clk_rate / 2, 5);
+	clockevents_calc_mult_shift(evt, clk_rate / (TICK_BASE_CNT + 1), 5);
 	evt->max_delta_ns =
 		clockevent_delta2ns(0x7fffffff, evt);
 	evt->min_delta_ns =
@@ -401,33 +410,27 @@
 
 	clockevents_register_device(evt);
 
-	exynos4_mct_write(0x1, mevt->base + MCT_L_TCNTB_OFFSET);
+	exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
 
 	if (mct_int_type == MCT_INT_SPI) {
 		if (cpu == 0) {
 			mct_tick0_event_irq.dev_id = mevt;
-			evt->irq = IRQ_MCT_L0;
-			setup_irq(IRQ_MCT_L0, &mct_tick0_event_irq);
+			evt->irq = EXYNOS4_IRQ_MCT_L0;
+			setup_irq(EXYNOS4_IRQ_MCT_L0, &mct_tick0_event_irq);
 		} else {
 			mct_tick1_event_irq.dev_id = mevt;
-			evt->irq = IRQ_MCT_L1;
-			setup_irq(IRQ_MCT_L1, &mct_tick1_event_irq);
-			irq_set_affinity(IRQ_MCT_L1, cpumask_of(1));
+			evt->irq = EXYNOS4_IRQ_MCT_L1;
+			setup_irq(EXYNOS4_IRQ_MCT_L1, &mct_tick1_event_irq);
+			irq_set_affinity(EXYNOS4_IRQ_MCT_L1, cpumask_of(1));
 		}
 	} else {
-		enable_percpu_irq(IRQ_MCT_LOCALTIMER, 0);
+		enable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER, 0);
 	}
-}
-
-/* Setup the local clock events for a CPU */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	exynos4_mct_tick_init(evt);
 
 	return 0;
 }
 
-void local_timer_stop(struct clock_event_device *evt)
+static void exynos4_local_timer_stop(struct clock_event_device *evt)
 {
 	unsigned int cpu = smp_processor_id();
 	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
@@ -437,8 +440,13 @@
 		else
 			remove_irq(evt->irq, &mct_tick1_event_irq);
 	else
-		disable_percpu_irq(IRQ_MCT_LOCALTIMER);
+		disable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER);
 }
+
+static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = {
+	.setup	= exynos4_local_timer_setup,
+	.stop	= exynos4_local_timer_stop,
+};
 #endif /* CONFIG_LOCAL_TIMERS */
 
 static void __init exynos4_timer_resources(void)
@@ -452,12 +460,14 @@
 	if (mct_int_type == MCT_INT_PPI) {
 		int err;
 
-		err = request_percpu_irq(IRQ_MCT_LOCALTIMER,
+		err = request_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER,
 					 exynos4_mct_tick_isr, "MCT",
 					 &percpu_mct_tick);
 		WARN(err, "MCT: can't request IRQ %d (%d)\n",
-		     IRQ_MCT_LOCALTIMER, err);
+		     EXYNOS_IRQ_MCT_LOCALTIMER, err);
 	}
+
+	local_timer_register(&exynos4_mct_tick_ops);
 #endif /* CONFIG_LOCAL_TIMERS */
 }
 
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index 0f2035a..36c3984a 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -166,7 +166,10 @@
 	void __iomem *scu_base = scu_base_addr();
 	unsigned int i, ncores;
 
-	ncores = scu_base ? scu_get_core_count(scu_base) : 1;
+	if (soc_is_exynos5250())
+		ncores = 2;
+	else
+		ncores = scu_base ? scu_get_core_count(scu_base) : 1;
 
 	/* sanity check */
 	if (ncores > nr_cpu_ids) {
@@ -183,8 +186,8 @@
 
 void __init platform_smp_prepare_cpus(unsigned int max_cpus)
 {
-
-	scu_enable(scu_base_addr());
+	if (!soc_is_exynos5250())
+		scu_enable(scu_base_addr());
 
 	/*
 	 * Write the address of secondary startup into the
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index e190130..428cfeb 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -38,29 +38,29 @@
 #include <mach/pmu.h>
 
 static struct sleep_save exynos4_set_clksrc[] = {
-	{ .reg = S5P_CLKSRC_MASK_TOP			, .val = 0x00000001, },
-	{ .reg = S5P_CLKSRC_MASK_CAM			, .val = 0x11111111, },
-	{ .reg = S5P_CLKSRC_MASK_TV			, .val = 0x00000111, },
-	{ .reg = S5P_CLKSRC_MASK_LCD0			, .val = 0x00001111, },
-	{ .reg = S5P_CLKSRC_MASK_MAUDIO			, .val = 0x00000001, },
-	{ .reg = S5P_CLKSRC_MASK_FSYS			, .val = 0x01011111, },
-	{ .reg = S5P_CLKSRC_MASK_PERIL0			, .val = 0x01111111, },
-	{ .reg = S5P_CLKSRC_MASK_PERIL1			, .val = 0x01110111, },
-	{ .reg = S5P_CLKSRC_MASK_DMC			, .val = 0x00010000, },
+	{ .reg = EXYNOS4_CLKSRC_MASK_TOP		, .val = 0x00000001, },
+	{ .reg = EXYNOS4_CLKSRC_MASK_CAM		, .val = 0x11111111, },
+	{ .reg = EXYNOS4_CLKSRC_MASK_TV			, .val = 0x00000111, },
+	{ .reg = EXYNOS4_CLKSRC_MASK_LCD0		, .val = 0x00001111, },
+	{ .reg = EXYNOS4_CLKSRC_MASK_MAUDIO		, .val = 0x00000001, },
+	{ .reg = EXYNOS4_CLKSRC_MASK_FSYS		, .val = 0x01011111, },
+	{ .reg = EXYNOS4_CLKSRC_MASK_PERIL0		, .val = 0x01111111, },
+	{ .reg = EXYNOS4_CLKSRC_MASK_PERIL1		, .val = 0x01110111, },
+	{ .reg = EXYNOS4_CLKSRC_MASK_DMC		, .val = 0x00010000, },
 };
 
 static struct sleep_save exynos4210_set_clksrc[] = {
-	{ .reg = S5P_CLKSRC_MASK_LCD1			, .val = 0x00001111, },
+	{ .reg = EXYNOS4210_CLKSRC_MASK_LCD1		, .val = 0x00001111, },
 };
 
 static struct sleep_save exynos4_epll_save[] = {
-	SAVE_ITEM(S5P_EPLL_CON0),
-	SAVE_ITEM(S5P_EPLL_CON1),
+	SAVE_ITEM(EXYNOS4_EPLL_CON0),
+	SAVE_ITEM(EXYNOS4_EPLL_CON1),
 };
 
 static struct sleep_save exynos4_vpll_save[] = {
-	SAVE_ITEM(S5P_VPLL_CON0),
-	SAVE_ITEM(S5P_VPLL_CON1),
+	SAVE_ITEM(EXYNOS4_VPLL_CON0),
+	SAVE_ITEM(EXYNOS4_VPLL_CON1),
 };
 
 static struct sleep_save exynos4_core_save[] = {
@@ -155,13 +155,6 @@
 	SAVE_ITEM(S5P_SROM_BC3),
 };
 
-static struct sleep_save exynos4_l2cc_save[] = {
-	SAVE_ITEM(S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL),
-	SAVE_ITEM(S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL),
-	SAVE_ITEM(S5P_VA_L2CC + L2X0_PREFETCH_CTRL),
-	SAVE_ITEM(S5P_VA_L2CC + L2X0_POWER_CTRL),
-	SAVE_ITEM(S5P_VA_L2CC + L2X0_AUX_CTRL),
-};
 
 /* For Cortex-A9 Diagnostic and Power control register */
 static unsigned int save_arm_register[2];
@@ -182,7 +175,6 @@
 	u32 tmp;
 
 	s3c_pm_do_save(exynos4_core_save, ARRAY_SIZE(exynos4_core_save));
-	s3c_pm_do_save(exynos4_l2cc_save, ARRAY_SIZE(exynos4_l2cc_save));
 	s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save));
 	s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save));
 
@@ -239,7 +231,7 @@
 		locktime = (3000 / pll_in_rate) * p_div;
 		lockcnt = locktime * 10000 / (10000 / pll_in_rate);
 
-		__raw_writel(lockcnt, S5P_EPLL_LOCK);
+		__raw_writel(lockcnt, EXYNOS4_EPLL_LOCK);
 
 		s3c_pm_do_restore_core(exynos4_epll_save,
 					ARRAY_SIZE(exynos4_epll_save));
@@ -257,7 +249,7 @@
 		locktime = 750;
 		lockcnt = locktime * 10000 / (10000 / pll_in_rate);
 
-		__raw_writel(lockcnt, S5P_VPLL_LOCK);
+		__raw_writel(lockcnt, EXYNOS4_VPLL_LOCK);
 
 		s3c_pm_do_restore_core(exynos4_vpll_save,
 					ARRAY_SIZE(exynos4_vpll_save));
@@ -268,14 +260,14 @@
 
 	do {
 		if (epll_wait) {
-			pll_con = __raw_readl(S5P_EPLL_CON0);
-			if (pll_con & (1 << S5P_EPLLCON0_LOCKED_SHIFT))
+			pll_con = __raw_readl(EXYNOS4_EPLL_CON0);
+			if (pll_con & (1 << EXYNOS4_EPLLCON0_LOCKED_SHIFT))
 				epll_wait = 0;
 		}
 
 		if (vpll_wait) {
-			pll_con = __raw_readl(S5P_VPLL_CON0);
-			if (pll_con & (1 << S5P_VPLLCON0_LOCKED_SHIFT))
+			pll_con = __raw_readl(EXYNOS4_VPLL_CON0);
+			if (pll_con & (1 << EXYNOS4_VPLLCON0_LOCKED_SHIFT))
 				vpll_wait = 0;
 		}
 	} while (epll_wait || vpll_wait);
@@ -388,13 +380,6 @@
 	scu_enable(S5P_VA_SCU);
 #endif
 
-#ifdef CONFIG_CACHE_L2X0
-	s3c_pm_do_restore_core(exynos4_l2cc_save, ARRAY_SIZE(exynos4_l2cc_save));
-	outer_inv_all();
-	/* enable L2X0*/
-	writel_relaxed(1, S5P_VA_L2CC + L2X0_CTRL);
-#endif
-
 early_wakeup:
 	return;
 }
diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c
index 0b04af2..13b3068 100644
--- a/arch/arm/mach-exynos/pm_domains.c
+++ b/arch/arm/mach-exynos/pm_domains.c
@@ -183,6 +183,12 @@
 #ifdef CONFIG_S5P_DEV_CSIS1
 	exynos_pm_add_dev_to_genpd(&s5p_device_mipi_csis1, &exynos4_pd_cam);
 #endif
+#ifdef CONFIG_S5P_DEV_G2D
+	exynos_pm_add_dev_to_genpd(&s5p_device_g2d, &exynos4_pd_lcd0);
+#endif
+#ifdef CONFIG_S5P_DEV_JPEG
+	exynos_pm_add_dev_to_genpd(&s5p_device_jpeg, &exynos4_pd_cam);
+#endif
 	return 0;
 }
 arch_initcall(exynos4_pm_init_power_domain);
diff --git a/arch/arm/mach-exynos/setup-i2c0.c b/arch/arm/mach-exynos/setup-i2c0.c
index d395bd1..b90d94c 100644
--- a/arch/arm/mach-exynos/setup-i2c0.c
+++ b/arch/arm/mach-exynos/setup-i2c0.c
@@ -1,7 +1,5 @@
 /*
- * linux/arch/arm/mach-exynos4/setup-i2c0.c
- *
- * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2009-2012 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com/
  *
  * I2C0 GPIO configuration.
@@ -18,9 +16,14 @@
 #include <linux/gpio.h>
 #include <plat/iic.h>
 #include <plat/gpio-cfg.h>
+#include <plat/cpu.h>
 
 void s3c_i2c0_cfg_gpio(struct platform_device *dev)
 {
+	if (soc_is_exynos5250())
+		/* will be implemented with gpio function */
+		return;
+
 	s3c_gpio_cfgall_range(EXYNOS4_GPD1(0), 2,
 			      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
 }
diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c
index 41978ee..3e6aaa6 100644
--- a/arch/arm/mach-footbridge/common.c
+++ b/arch/arm/mach-footbridge/common.c
@@ -21,6 +21,7 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
+#include <asm/system_misc.h>
 #include <asm/hardware/dec21285.h>
 
 #include <asm/mach/irq.h>
diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c
index 121ad1d..3b54196 100644
--- a/arch/arm/mach-footbridge/dc21285-timer.c
+++ b/arch/arm/mach-footbridge/dc21285-timer.c
@@ -14,6 +14,7 @@
 
 #include <asm/hardware/dec21285.h>
 #include <asm/mach/time.h>
+#include <asm/system_info.h>
 
 #include "common.h"
 
diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c
index f685650..e17e11d 100644
--- a/arch/arm/mach-footbridge/dc21285.c
+++ b/arch/arm/mach-footbridge/dc21285.c
@@ -21,7 +21,6 @@
 #include <video/vga.h>
 
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/mach/pci.h>
 #include <asm/hardware/dec21285.h>
 
@@ -275,11 +274,13 @@
 	allocate_resource(&iomem_resource, &res[0], 0x40000000,
 			  0x80000000, 0xffffffff, 0x40000000, NULL, NULL);
 
-	pci_add_resource(&sys->resources, &ioport_resource);
-	pci_add_resource(&sys->resources, &res[0]);
-	pci_add_resource(&sys->resources, &res[1]);
 	sys->mem_offset  = DC21285_PCI_MEM;
 
+	pci_add_resource_offset(&sys->resources,
+				&ioport_resource, sys->io_offset);
+	pci_add_resource_offset(&sys->resources, &res[0], sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
+
 	return 1;
 }
 
diff --git a/arch/arm/mach-footbridge/ebsa285-leds.c b/arch/arm/mach-footbridge/ebsa285-leds.c
index 4e10090..5bd2667 100644
--- a/arch/arm/mach-footbridge/ebsa285-leds.c
+++ b/arch/arm/mach-footbridge/ebsa285-leds.c
@@ -24,7 +24,6 @@
 #include <mach/hardware.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/system.h>
 
 #define LED_STATE_ENABLED	1
 #define LED_STATE_CLAIMED	2
diff --git a/arch/arm/mach-footbridge/include/mach/entry-macro.S b/arch/arm/mach-footbridge/include/mach/entry-macro.S
index d3847be..dabbd5c 100644
--- a/arch/arm/mach-footbridge/include/mach/entry-macro.S
+++ b/arch/arm/mach-footbridge/include/mach/entry-macro.S
@@ -14,9 +14,6 @@
 		.equ	dc21285_high, ARMCSR_BASE & 0xff000000
 		.equ	dc21285_low, ARMCSR_BASE & 0x00ffffff
 
-		.macro	disable_fiq
-		.endm
-
 		.macro  get_irqnr_preamble, base, tmp
 		mov	\base, #dc21285_high
 		.if	dc21285_low
@@ -24,9 +21,6 @@
 		.endif
 		.endm
 
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
-
 		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 		ldr	\irqstat, [\base, #0x180]	@ get interrupts
 
diff --git a/arch/arm/mach-footbridge/include/mach/io.h b/arch/arm/mach-footbridge/include/mach/io.h
index 15a7039..aba531ee 100644
--- a/arch/arm/mach-footbridge/include/mach/io.h
+++ b/arch/arm/mach-footbridge/include/mach/io.h
@@ -27,18 +27,5 @@
  * Translation of various region addresses to virtual addresses
  */
 #define __io(a)			((void __iomem *)(PCIO_BASE + (a)))
-#if 1
-#define __mem_pci(a)		(a)
-#else
-
-static inline void __iomem *___mem_pci(void __iomem *p)
-{
-	unsigned long a = (unsigned long)p;
-	BUG_ON(a <= 0xc0000000 || a >= 0xe0000000);
-	return p;
-}
-
-#define __mem_pci(a)		___mem_pci(a)
-#endif
 
 #endif
diff --git a/arch/arm/mach-footbridge/include/mach/system.h b/arch/arm/mach-footbridge/include/mach/system.h
deleted file mode 100644
index a174a58..0000000
--- a/arch/arm/mach-footbridge/include/mach/system.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- *  arch/arm/mach-footbridge/include/mach/system.h
- *
- *  Copyright (C) 1996-1999 Russell King.
- *
- * 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.
- */
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c
index 80a1c5c..cac9f67 100644
--- a/arch/arm/mach-footbridge/netwinder-hw.c
+++ b/arch/arm/mach-footbridge/netwinder-hw.c
@@ -17,6 +17,7 @@
 #include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
+#include <asm/system_misc.h>
 
 #include <asm/mach/arch.h>
 
diff --git a/arch/arm/mach-footbridge/netwinder-leds.c b/arch/arm/mach-footbridge/netwinder-leds.c
index e57102e..5a2bd89 100644
--- a/arch/arm/mach-footbridge/netwinder-leds.c
+++ b/arch/arm/mach-footbridge/netwinder-leds.c
@@ -24,7 +24,6 @@
 #include <mach/hardware.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/system.h>
 
 #define LED_STATE_ENABLED	1
 #define LED_STATE_CLAIMED	2
diff --git a/arch/arm/mach-gemini/Makefile b/arch/arm/mach-gemini/Makefile
index c5b24b9..7355c0b 100644
--- a/arch/arm/mach-gemini/Makefile
+++ b/arch/arm/mach-gemini/Makefile
@@ -4,7 +4,7 @@
 
 # Object file lists.
 
-obj-y			:= irq.o mm.o time.o devices.o gpio.o
+obj-y			:= irq.o mm.o time.o devices.o gpio.o idle.o
 
 # Board-specific support
 obj-$(CONFIG_MACH_NAS4220B)	+= board-nas4220b.o
diff --git a/arch/arm/mach-gemini/idle.c b/arch/arm/mach-gemini/idle.c
new file mode 100644
index 0000000..92bbd6b
--- /dev/null
+++ b/arch/arm/mach-gemini/idle.c
@@ -0,0 +1,29 @@
+/*
+ * arch/arm/mach-gemini/idle.c
+ */
+
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/proc-fns.h>
+
+static void gemini_idle(void)
+{
+	/*
+	 * Because of broken hardware we have to enable interrupts or the CPU
+	 * will never wakeup... Acctualy it is not very good to enable
+	 * interrupts first since scheduler can miss a tick, but there is
+	 * no other way around this. Platforms that needs it for power saving
+	 * should call enable_hlt() in init code, since by default it is
+	 * disabled.
+	 */
+	local_irq_enable();
+	cpu_do_idle();
+}
+
+static int __init gemini_idle_init(void)
+{
+	arm_pm_idle = gemini_idle;
+	return 0;
+}
+
+arch_initcall(gemini_idle_init);
diff --git a/arch/arm/mach-gemini/include/mach/entry-macro.S b/arch/arm/mach-gemini/include/mach/entry-macro.S
index 1624f91..f044e43 100644
--- a/arch/arm/mach-gemini/include/mach/entry-macro.S
+++ b/arch/arm/mach-gemini/include/mach/entry-macro.S
@@ -12,15 +12,9 @@
 
 #define IRQ_STATUS	0x14
 
-	.macro  disable_fiq
-	.endm
-
 	.macro  get_irqnr_preamble, base, tmp
 	.endm
 
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
-
 	.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 	ldr     \irqstat, =IO_ADDRESS(GEMINI_INTERRUPT_BASE + IRQ_STATUS)
 	ldr     \irqnr, [\irqstat]
diff --git a/arch/arm/mach-gemini/include/mach/io.h b/arch/arm/mach-gemini/include/mach/io.h
deleted file mode 100644
index c548056..0000000
--- a/arch/arm/mach-gemini/include/mach/io.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- *  Copyright (C) 2001-2006 Storlink, Corp.
- *  Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
- *
- * 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 __MACH_IO_H
-#define __MACH_IO_H
-
-#define IO_SPACE_LIMIT	0xffffffff
-
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#endif /* __MACH_IO_H */
diff --git a/arch/arm/mach-gemini/include/mach/system.h b/arch/arm/mach-gemini/include/mach/system.h
index 4d9c1f8..a33b5a1 100644
--- a/arch/arm/mach-gemini/include/mach/system.h
+++ b/arch/arm/mach-gemini/include/mach/system.h
@@ -14,20 +14,6 @@
 #include <mach/hardware.h>
 #include <mach/global_reg.h>
 
-static inline void arch_idle(void)
-{
-	/*
-	 * Because of broken hardware we have to enable interrupts or the CPU
-	 * will never wakeup... Acctualy it is not very good to enable
-	 * interrupts here since scheduler can miss a tick, but there is
-	 * no other way around this. Platforms that needs it for power saving
-	 * should call enable_hlt() in init code, since by default it is
-	 * disabled.
-	 */
-	local_irq_enable();
-	cpu_do_idle();
-}
-
 static inline void arch_reset(char mode, const char *cmd)
 {
 	__raw_writel(RESET_GLOBAL | RESET_CPU1,
diff --git a/arch/arm/mach-gemini/irq.c b/arch/arm/mach-gemini/irq.c
index 9485a8f..ca70e5f 100644
--- a/arch/arm/mach-gemini/irq.c
+++ b/arch/arm/mach-gemini/irq.c
@@ -73,8 +73,8 @@
 	unsigned int i, mode = 0, level = 0;
 
 	/*
-	 * Disable arch_idle() by default since it is buggy
-	 * For more info see arch/arm/mach-gemini/include/mach/system.h
+	 * Disable the idle handler by default since it is buggy
+	 * For more info see arch/arm/mach-gemini/idle.c
 	 */
 	disable_hlt();
 
diff --git a/arch/arm/mach-h720x/common.c b/arch/arm/mach-h720x/common.c
index f8a2f6b..aa1331e 100644
--- a/arch/arm/mach-h720x/common.c
+++ b/arch/arm/mach-h720x/common.c
@@ -24,6 +24,7 @@
 #include <asm/dma.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
+#include <asm/system_misc.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/map.h>
 #include <mach/irqs.h>
@@ -247,3 +248,21 @@
 {
 	CPU_REG (PMU_BASE, PMU_STAT) |= PMU_WARMRESET;
 }
+
+static void h720x__idle(void)
+{
+	CPU_REG (PMU_BASE, PMU_MODE) = PMU_MODE_IDLE;
+	nop();
+	nop();
+	CPU_REG (PMU_BASE, PMU_MODE) = PMU_MODE_RUN;
+	nop();
+	nop();
+}
+
+static int __init h720x_idle_init(void)
+{
+	arm_pm_idle = h720x__idle;
+	return 0;
+}
+
+arch_initcall(h720x_idle_init);
diff --git a/arch/arm/mach-h720x/include/mach/entry-macro.S b/arch/arm/mach-h720x/include/mach/entry-macro.S
index c3948e5..75267fa 100644
--- a/arch/arm/mach-h720x/include/mach/entry-macro.S
+++ b/arch/arm/mach-h720x/include/mach/entry-macro.S
@@ -8,15 +8,9 @@
  * warranty of any kind, whether express or implied.
  */
 
-		.macro  disable_fiq
-		.endm
-
 		.macro  get_irqnr_preamble, base, tmp
 		.endm
 
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
-
 		.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 #if defined (CONFIG_CPU_H7201) || defined (CONFIG_CPU_H7202)
 		@ we could use the id register on H7202, but this is not
diff --git a/arch/arm/mach-h720x/include/mach/io.h b/arch/arm/mach-h720x/include/mach/io.h
deleted file mode 100644
index 2c8659c..0000000
--- a/arch/arm/mach-h720x/include/mach/io.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * arch/arm/mach-h720x/include/mach/io.h
- *
- * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
- *
- * Changelog:
- *
- *  09-19-2001	JJKIM
- *  		Created from arch/arm/mach-l7200/include/mach/io.h
- *
- *  03-27-2003  Robert Schwebel <r.schwebel@pengutronix.de>:
- *  		re-unified header files for h720x
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#endif
diff --git a/arch/arm/mach-h720x/include/mach/system.h b/arch/arm/mach-h720x/include/mach/system.h
deleted file mode 100644
index 16ac46e..0000000
--- a/arch/arm/mach-h720x/include/mach/system.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * arch/arm/mach-h720x/include/mach/system.h
- *
- * Copyright (C) 2001-2002 Jungjun Kim, Hynix Semiconductor 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.
- * arch/arm/mach-h720x/include/mach/system.h
- *
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-#include <mach/hardware.h>
-
-static void arch_idle(void)
-{
-	CPU_REG (PMU_BASE, PMU_MODE) = PMU_MODE_IDLE;
-	nop();
-	nop();
-	CPU_REG (PMU_BASE, PMU_MODE) = PMU_MODE_RUN;
-	nop();
-	nop();
-}
-
-#endif
diff --git a/arch/arm/mach-highbank/Makefile b/arch/arm/mach-highbank/Makefile
index 986958a..f8437dd2 100644
--- a/arch/arm/mach-highbank/Makefile
+++ b/arch/arm/mach-highbank/Makefile
@@ -1,6 +1,5 @@
 obj-y					:= clock.o highbank.o system.o
 obj-$(CONFIG_DEBUG_HIGHBANK_UART)	+= lluart.o
 obj-$(CONFIG_SMP)			+= platsmp.o
-obj-$(CONFIG_LOCAL_TIMERS)		+= localtimer.o
 obj-$(CONFIG_HOTPLUG_CPU)		+= hotplug.o
 obj-$(CONFIG_PM_SLEEP)			+= pm.o
diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c
index 8394d51..410a112 100644
--- a/arch/arm/mach-highbank/highbank.c
+++ b/arch/arm/mach-highbank/highbank.c
@@ -27,6 +27,7 @@
 #include <asm/cacheflush.h>
 #include <asm/smp_plat.h>
 #include <asm/smp_scu.h>
+#include <asm/smp_twd.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/timer-sp.h>
 #include <asm/hardware/gic.h>
@@ -34,7 +35,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
-#include <mach/irqs.h>
 
 #include "core.h"
 #include "sysregs.h"
@@ -109,8 +109,10 @@
 
 	highbank_clocks_init();
 
-	sp804_clocksource_init(timer_base + 0x20, "timer1");
+	sp804_clocksource_and_sched_clock_init(timer_base + 0x20, "timer1");
 	sp804_clockevents_init(timer_base, irq, "timer0");
+
+	twd_local_timer_of_register();
 }
 
 static struct sys_timer highbank_timer = {
diff --git a/arch/arm/mach-highbank/include/mach/entry-macro.S b/arch/arm/mach-highbank/include/mach/entry-macro.S
deleted file mode 100644
index a14f9e6..0000000
--- a/arch/arm/mach-highbank/include/mach/entry-macro.S
+++ /dev/null
@@ -1,5 +0,0 @@
-	.macro	disable_fiq
-	.endm
-
-	.macro	arch_ret_to_user, tmp1, tmp2
-	.endm
diff --git a/arch/arm/mach-highbank/include/mach/io.h b/arch/arm/mach-highbank/include/mach/io.h
deleted file mode 100644
index 70cfa3b..0000000
--- a/arch/arm/mach-highbank/include/mach/io.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __MACH_IO_H
-#define __MACH_IO_H
-
-#define __io(a)		({ (void)(a); __typesafe_io(0); })
-#define __mem_pci(a)	(a)
-
-#endif
diff --git a/arch/arm/mach-highbank/include/mach/irqs.h b/arch/arm/mach-highbank/include/mach/irqs.h
deleted file mode 100644
index 9746aab..0000000
--- a/arch/arm/mach-highbank/include/mach/irqs.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __MACH_IRQS_H
-#define __MACH_IRQS_H
-
-#define NR_IRQS			192
-
-#endif
diff --git a/arch/arm/mach-highbank/include/mach/memory.h b/arch/arm/mach-highbank/include/mach/memory.h
deleted file mode 100644
index 40a8c17..0000000
--- a/arch/arm/mach-highbank/include/mach/memory.h
+++ /dev/null
@@ -1 +0,0 @@
-/* empty */
diff --git a/arch/arm/mach-highbank/include/mach/system.h b/arch/arm/mach-highbank/include/mach/system.h
deleted file mode 100644
index b1d8b5f..0000000
--- a/arch/arm/mach-highbank/include/mach/system.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2010-2011 Calxeda, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef __MACH_SYSTEM_H
-#define __MACH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-highbank/localtimer.c b/arch/arm/mach-highbank/localtimer.c
deleted file mode 100644
index 5a00e79..0000000
--- a/arch/arm/mach-highbank/localtimer.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2010-2011 Calxeda, Inc.
- * Based on localtimer.c, Copyright (C) 2002 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * 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/init.h>
-#include <linux/clockchips.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-
-#include <asm/smp_twd.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	struct device_node *np;
-
-	np = of_find_compatible_node(NULL, NULL, "arm,smp-twd");
-	if (!twd_base) {
-		twd_base = of_iomap(np, 0);
-		WARN_ON(!twd_base);
-	}
-	evt->irq = irq_of_parse_and_map(np, 0);
-	twd_timer_setup(evt);
-	return 0;
-}
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 4defb97b..7561eca 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -1,6 +1,3 @@
-config IMX_HAVE_DMA_V1
-	bool
-
 config HAVE_IMX_GPC
 	bool
 
@@ -38,7 +35,6 @@
 	bool
 	select ARCH_MX1
 	select CPU_ARM920T
-	select IMX_HAVE_DMA_V1
 	select IMX_HAVE_IOMUX_V1
 	select MXC_AVIC
 
@@ -46,8 +42,6 @@
 	bool
 	select MACH_MX21
 	select CPU_ARM926T
-	select ARCH_MXC_AUDMUX_V1
-	select IMX_HAVE_DMA_V1
 	select IMX_HAVE_IOMUX_V1
 	select MXC_AVIC
 
@@ -55,7 +49,6 @@
 	bool
 	select ARCH_MX25
 	select CPU_ARM926T
-	select ARCH_MXC_AUDMUX_V2
 	select ARCH_MXC_IOMUX_V3
 	select MXC_AVIC
 
@@ -63,8 +56,6 @@
 	bool
 	select MACH_MX27
 	select CPU_ARM926T
-	select ARCH_MXC_AUDMUX_V1
-	select IMX_HAVE_DMA_V1
 	select IMX_HAVE_IOMUX_V1
 	select MXC_AVIC
 
@@ -72,7 +63,6 @@
 	bool
 	select CPU_V6
 	select IMX_HAVE_PLATFORM_MXC_RNGA
-	select ARCH_MXC_AUDMUX_V2
 	select MXC_AVIC
 	select SMP_ON_UP if SMP
 
@@ -80,7 +70,6 @@
 	bool
 	select CPU_V6
 	select ARCH_MXC_IOMUX_V3
-	select ARCH_MXC_AUDMUX_V2
 	select HAVE_EPIT
 	select MXC_AVIC
 	select SMP_ON_UP if SMP
@@ -89,7 +78,6 @@
 	select CPU_V7
 	select MXC_TZIC
 	select ARCH_MXC_IOMUX_V3
-	select ARCH_MXC_AUDMUX_V2
 	select ARCH_HAS_CPUFREQ
 	select ARCH_MX5
 	bool
@@ -304,6 +292,7 @@
 	select IMX_HAVE_PLATFORM_IMX_I2C
 	select IMX_HAVE_PLATFORM_IMX_KEYPAD
 	select IMX_HAVE_PLATFORM_IMX_UART
+	select IMX_HAVE_PLATFORM_MX2_CAMERA
 	select IMX_HAVE_PLATFORM_MXC_EHCI
 	select IMX_HAVE_PLATFORM_MXC_MMC
 	select IMX_HAVE_PLATFORM_SPI_IMX
@@ -320,8 +309,10 @@
 	select IMX_HAVE_PLATFORM_IMX_I2C
 	select IMX_HAVE_PLATFORM_IMX_SSI
 	select IMX_HAVE_PLATFORM_IMX_UART
-	select IMX_HAVE_PLATFORM_MXC_MMC
+	select IMX_HAVE_PLATFORM_MX2_CAMERA
 	select IMX_HAVE_PLATFORM_MXC_EHCI
+	select IMX_HAVE_PLATFORM_MXC_MMC
+	select LEDS_GPIO_REGISTER
 	help
 	  Include support for Visstrim_m10 platform and its different variants.
 	  This includes specific configurations for the board and its
@@ -376,6 +367,14 @@
 	  Include support for IMX27 IPCAM platform. This includes specific
 	  configurations for the board and its peripherals.
 
+config MACH_IMX27_DT
+	bool "Support i.MX27 platforms from device tree"
+	select SOC_IMX27
+	select USE_OF
+	help
+	  Include support for Freescale i.MX27 based platforms
+	  using the device tree for discovery
+
 endif
 
 if ARCH_IMX_V6_V7
@@ -492,6 +491,7 @@
 	bool "Support mx31moboard platforms (EPFL Mobots group)"
 	select SOC_IMX31
 	select IMX_HAVE_PLATFORM_FSL_USB2_UDC
+	select IMX_HAVE_PLATFORM_IMX2_WDT
 	select IMX_HAVE_PLATFORM_IMX_I2C
 	select IMX_HAVE_PLATFORM_IMX_UART
 	select IMX_HAVE_PLATFORM_IPU_CORE
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 55db9c4..ab939c5 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -1,5 +1,3 @@
-obj-$(CONFIG_IMX_HAVE_DMA_V1) += dma-v1.o
-
 obj-$(CONFIG_SOC_IMX1) += clock-imx1.o mm-imx1.o
 obj-$(CONFIG_SOC_IMX21) += clock-imx21.o mm-imx21.o
 
@@ -8,8 +6,8 @@
 obj-$(CONFIG_SOC_IMX27) += cpu-imx27.o pm-imx27.o
 obj-$(CONFIG_SOC_IMX27) += clock-imx27.o mm-imx27.o ehci-imx27.o
 
-obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clock-imx31.o iomux-imx31.o ehci-imx31.o
-obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clock-imx35.o ehci-imx35.o
+obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clock-imx31.o iomux-imx31.o ehci-imx31.o pm-imx3.o
+obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clock-imx35.o ehci-imx35.o pm-imx3.o
 
 obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clock-mx51-mx53.o ehci-imx5.o pm-imx5.o cpu_op-mx51.o
 
@@ -41,6 +39,7 @@
 obj-$(CONFIG_MACH_PCA100) += mach-pca100.o
 obj-$(CONFIG_MACH_MXT_TD60) += mach-mxt_td60.o
 obj-$(CONFIG_MACH_IMX27IPCAM) += mach-imx27ipcam.o
+obj-$(CONFIG_MACH_IMX27_DT) += imx27-dt.o
 
 # i.MX31 based machines
 obj-$(CONFIG_MACH_MX31ADS) += mach-mx31ads.o
@@ -71,7 +70,6 @@
 AFLAGS_head-v7.o :=-Wa,-march=armv7-a
 obj-$(CONFIG_SMP) += platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
-obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
 obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o
 
 ifeq ($(CONFIG_PM),y)
diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot
index 6dfdbcc..3851d8a 100644
--- a/arch/arm/mach-imx/Makefile.boot
+++ b/arch/arm/mach-imx/Makefile.boot
@@ -38,5 +38,8 @@
 params_phys-$(CONFIG_SOC_IMX6Q)	:= 0x10000100
 initrd_phys-$(CONFIG_SOC_IMX6Q)	:= 0x10800000
 
+dtb-$(CONFIG_MACH_IMX51_DT) += imx51-babbage.dtb
+dtb-$(CONFIG_MACH_IMX53_DT) += imx53-ard.dtb imx53-evk.dtb \
+			       imx53-qsb.dtb imx53-smd.dtb
 dtb-$(CONFIG_SOC_IMX6Q)	+= imx6q-arm2.dtb \
 			   imx6q-sabrelite.dtb
diff --git a/arch/arm/mach-imx/clock-imx27.c b/arch/arm/mach-imx/clock-imx27.c
index 88fe00a..98e04f5 100644
--- a/arch/arm/mach-imx/clock-imx27.c
+++ b/arch/arm/mach-imx/clock-imx27.c
@@ -22,6 +22,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/clkdev.h>
+#include <linux/of.h>
 
 #include <asm/div64.h>
 
@@ -662,6 +663,7 @@
 	_REGISTER_CLOCK(NULL, "rtic", rtic_clk)
 	_REGISTER_CLOCK(NULL, "brom", brom_clk)
 	_REGISTER_CLOCK(NULL, "emma", emma_clk)
+	_REGISTER_CLOCK("m2m-emmaprp.0", NULL, emma_clk)
 	_REGISTER_CLOCK(NULL, "slcdc", slcdc_clk)
 	_REGISTER_CLOCK("imx27-fec.0", NULL, fec_clk)
 	_REGISTER_CLOCK(NULL, "emi", emi_clk)
@@ -764,3 +766,20 @@
 	return 0;
 }
 
+#ifdef CONFIG_OF
+int __init mx27_clocks_init_dt(void)
+{
+	struct device_node *np;
+	u32 fref = 26000000; /* default */
+
+	for_each_compatible_node(np, NULL, "fixed-clock") {
+		if (!of_device_is_compatible(np, "fsl,imx-osc26m"))
+			continue;
+
+		if (!of_property_read_u32(np, "clock-frequency", &fref))
+			break;
+	}
+
+	return mx27_clocks_init(fref);
+}
+#endif
diff --git a/arch/arm/mach-imx/clock-imx31.c b/arch/arm/mach-imx/clock-imx31.c
index 988a281..3a943cd 100644
--- a/arch/arm/mach-imx/clock-imx31.c
+++ b/arch/arm/mach-imx/clock-imx31.c
@@ -32,7 +32,7 @@
 #include <mach/mx31.h>
 #include <mach/common.h>
 
-#include "crmregs-imx31.h"
+#include "crmregs-imx3.h"
 
 #define PRE_DIV_MIN_FREQ    10000000 /* Minimum Frequency after Predivider */
 
diff --git a/arch/arm/mach-imx/clock-imx35.c b/arch/arm/mach-imx/clock-imx35.c
index ac8238c..e56c1a8 100644
--- a/arch/arm/mach-imx/clock-imx35.c
+++ b/arch/arm/mach-imx/clock-imx35.c
@@ -27,23 +27,7 @@
 #include <mach/hardware.h>
 #include <mach/common.h>
 
-#define CCM_BASE	MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR)
-
-#define CCM_CCMR        0x00
-#define CCM_PDR0        0x04
-#define CCM_PDR1        0x08
-#define CCM_PDR2        0x0C
-#define CCM_PDR3        0x10
-#define CCM_PDR4        0x14
-#define CCM_RCSR        0x18
-#define CCM_MPCTL       0x1C
-#define CCM_PPCTL       0x20
-#define CCM_ACMR        0x24
-#define CCM_COSR        0x28
-#define CCM_CGR0        0x2C
-#define CCM_CGR1        0x30
-#define CCM_CGR2        0x34
-#define CCM_CGR3        0x38
+#include "crmregs-imx3.h"
 
 #ifdef HAVE_SET_RATE_SUPPORT
 static void calc_dividers(u32 div, u32 *pre, u32 *post, u32 maxpost)
@@ -111,14 +95,14 @@
 
 static unsigned long get_rate_mpll(void)
 {
-	ulong mpctl = __raw_readl(CCM_BASE + CCM_MPCTL);
+	ulong mpctl = __raw_readl(MX35_CCM_MPCTL);
 
 	return mxc_decode_pll(mpctl, 24000000);
 }
 
 static unsigned long get_rate_ppll(void)
 {
-	ulong ppctl = __raw_readl(CCM_BASE + CCM_PPCTL);
+	ulong ppctl = __raw_readl(MX35_CCM_PPCTL);
 
 	return mxc_decode_pll(ppctl, 24000000);
 }
@@ -148,7 +132,7 @@
 
 static unsigned long get_rate_arm(void)
 {
-	unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0);
+	unsigned long pdr0 = __raw_readl(MXC_CCM_PDR0);
 	struct arm_ahb_div *aad;
 	unsigned long fref = get_rate_mpll();
 
@@ -161,7 +145,7 @@
 
 static unsigned long get_rate_ahb(struct clk *clk)
 {
-	unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0);
+	unsigned long pdr0 = __raw_readl(MXC_CCM_PDR0);
 	struct arm_ahb_div *aad;
 	unsigned long fref = get_rate_arm();
 
@@ -177,8 +161,8 @@
 
 static unsigned long get_rate_uart(struct clk *clk)
 {
-	unsigned long pdr3 = __raw_readl(CCM_BASE + CCM_PDR3);
-	unsigned long pdr4 = __raw_readl(CCM_BASE + CCM_PDR4);
+	unsigned long pdr3 = __raw_readl(MX35_CCM_PDR3);
+	unsigned long pdr4 = __raw_readl(MX35_CCM_PDR4);
 	unsigned long div = ((pdr4 >> 10) & 0x3f) + 1;
 
 	if (pdr3 & (1 << 14))
@@ -189,7 +173,7 @@
 
 static unsigned long get_rate_sdhc(struct clk *clk)
 {
-	unsigned long pdr3 = __raw_readl(CCM_BASE + CCM_PDR3);
+	unsigned long pdr3 = __raw_readl(MX35_CCM_PDR3);
 	unsigned long div, rate;
 
 	if (pdr3 & (1 << 6))
@@ -215,7 +199,7 @@
 
 static unsigned long get_rate_mshc(struct clk *clk)
 {
-	unsigned long pdr1 = __raw_readl(CCM_BASE + CCM_PDR1);
+	unsigned long pdr1 = __raw_readl(MXC_CCM_PDR1);
 	unsigned long div1, div2, rate;
 
 	if (pdr1 & (1 << 7))
@@ -231,7 +215,7 @@
 
 static unsigned long get_rate_ssi(struct clk *clk)
 {
-	unsigned long pdr2 = __raw_readl(CCM_BASE + CCM_PDR2);
+	unsigned long pdr2 = __raw_readl(MX35_CCM_PDR2);
 	unsigned long div1, div2, rate;
 
 	if (pdr2 & (1 << 6))
@@ -256,7 +240,7 @@
 
 static unsigned long get_rate_csi(struct clk *clk)
 {
-	unsigned long pdr2 = __raw_readl(CCM_BASE + CCM_PDR2);
+	unsigned long pdr2 = __raw_readl(MX35_CCM_PDR2);
 	unsigned long rate;
 
 	if (pdr2 & (1 << 7))
@@ -269,7 +253,7 @@
 
 static unsigned long get_rate_otg(struct clk *clk)
 {
-	unsigned long pdr4 = __raw_readl(CCM_BASE + CCM_PDR4);
+	unsigned long pdr4 = __raw_readl(MX35_CCM_PDR4);
 	unsigned long rate;
 
 	if (pdr4 & (1 << 9))
@@ -282,8 +266,8 @@
 
 static unsigned long get_rate_ipg_per(struct clk *clk)
 {
-	unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0);
-	unsigned long pdr4 = __raw_readl(CCM_BASE + CCM_PDR4);
+	unsigned long pdr0 = __raw_readl(MXC_CCM_PDR0);
+	unsigned long pdr4 = __raw_readl(MX35_CCM_PDR4);
 	unsigned long div;
 
 	if (pdr0 & (1 << 26)) {
@@ -297,7 +281,7 @@
 
 static unsigned long get_rate_hsp(struct clk *clk)
 {
-	unsigned long hsp_podf = (__raw_readl(CCM_BASE + CCM_PDR0) >> 20) & 0x03;
+	unsigned long hsp_podf = (__raw_readl(MXC_CCM_PDR0) >> 20) & 0x03;
 	unsigned long fref = get_rate_mpll();
 
 	if (fref > 400 * 1000 * 1000) {
@@ -345,7 +329,7 @@
 #define DEFINE_CLOCK(name, i, er, es, gr, sr)		\
 	static struct clk name = {			\
 		.id		= i,			\
-		.enable_reg	= CCM_BASE + er,	\
+		.enable_reg	= er,			\
 		.enable_shift	= es,			\
 		.get_rate	= gr,			\
 		.set_rate	= sr,			\
@@ -353,59 +337,59 @@
 		.disable	= clk_cgr_disable,	\
 	}
 
-DEFINE_CLOCK(asrc_clk,   0, CCM_CGR0,  0, NULL, NULL);
-DEFINE_CLOCK(pata_clk,    0, CCM_CGR0,  2, get_rate_ipg, NULL);
-/* DEFINE_CLOCK(audmux_clk, 0, CCM_CGR0,  4, NULL, NULL); */
-DEFINE_CLOCK(can1_clk,   0, CCM_CGR0,  6, get_rate_ipg, NULL);
-DEFINE_CLOCK(can2_clk,   1, CCM_CGR0,  8, get_rate_ipg, NULL);
-DEFINE_CLOCK(cspi1_clk,  0, CCM_CGR0, 10, get_rate_ipg, NULL);
-DEFINE_CLOCK(cspi2_clk,  1, CCM_CGR0, 12, get_rate_ipg, NULL);
-DEFINE_CLOCK(ect_clk,    0, CCM_CGR0, 14, get_rate_ipg, NULL);
-DEFINE_CLOCK(edio_clk,   0, CCM_CGR0, 16, NULL, NULL);
-DEFINE_CLOCK(emi_clk,    0, CCM_CGR0, 18, get_rate_ipg, NULL);
-DEFINE_CLOCK(epit1_clk,  0, CCM_CGR0, 20, get_rate_ipg, NULL);
-DEFINE_CLOCK(epit2_clk,  1, CCM_CGR0, 22, get_rate_ipg, NULL);
-DEFINE_CLOCK(esai_clk,   0, CCM_CGR0, 24, NULL, NULL);
-DEFINE_CLOCK(esdhc1_clk, 0, CCM_CGR0, 26, get_rate_sdhc, NULL);
-DEFINE_CLOCK(esdhc2_clk, 1, CCM_CGR0, 28, get_rate_sdhc, NULL);
-DEFINE_CLOCK(esdhc3_clk, 2, CCM_CGR0, 30, get_rate_sdhc, NULL);
+DEFINE_CLOCK(asrc_clk,   0, MX35_CCM_CGR0,  0, NULL, NULL);
+DEFINE_CLOCK(pata_clk,    0, MX35_CCM_CGR0,  2, get_rate_ipg, NULL);
+/* DEFINE_CLOCK(audmux_clk, 0, MX35_CCM_CGR0,  4, NULL, NULL); */
+DEFINE_CLOCK(can1_clk,   0, MX35_CCM_CGR0,  6, get_rate_ipg, NULL);
+DEFINE_CLOCK(can2_clk,   1, MX35_CCM_CGR0,  8, get_rate_ipg, NULL);
+DEFINE_CLOCK(cspi1_clk,  0, MX35_CCM_CGR0, 10, get_rate_ipg, NULL);
+DEFINE_CLOCK(cspi2_clk,  1, MX35_CCM_CGR0, 12, get_rate_ipg, NULL);
+DEFINE_CLOCK(ect_clk,    0, MX35_CCM_CGR0, 14, get_rate_ipg, NULL);
+DEFINE_CLOCK(edio_clk,   0, MX35_CCM_CGR0, 16, NULL, NULL);
+DEFINE_CLOCK(emi_clk,    0, MX35_CCM_CGR0, 18, get_rate_ipg, NULL);
+DEFINE_CLOCK(epit1_clk,  0, MX35_CCM_CGR0, 20, get_rate_ipg, NULL);
+DEFINE_CLOCK(epit2_clk,  1, MX35_CCM_CGR0, 22, get_rate_ipg, NULL);
+DEFINE_CLOCK(esai_clk,   0, MX35_CCM_CGR0, 24, NULL, NULL);
+DEFINE_CLOCK(esdhc1_clk, 0, MX35_CCM_CGR0, 26, get_rate_sdhc, NULL);
+DEFINE_CLOCK(esdhc2_clk, 1, MX35_CCM_CGR0, 28, get_rate_sdhc, NULL);
+DEFINE_CLOCK(esdhc3_clk, 2, MX35_CCM_CGR0, 30, get_rate_sdhc, NULL);
 
-DEFINE_CLOCK(fec_clk,    0, CCM_CGR1,  0, get_rate_ipg, NULL);
-DEFINE_CLOCK(gpio1_clk,  0, CCM_CGR1,  2, NULL, NULL);
-DEFINE_CLOCK(gpio2_clk,  1, CCM_CGR1,  4, NULL, NULL);
-DEFINE_CLOCK(gpio3_clk,  2, CCM_CGR1,  6, NULL, NULL);
-DEFINE_CLOCK(gpt_clk,    0, CCM_CGR1,  8, get_rate_ipg, NULL);
-DEFINE_CLOCK(i2c1_clk,   0, CCM_CGR1, 10, get_rate_ipg_per, NULL);
-DEFINE_CLOCK(i2c2_clk,   1, CCM_CGR1, 12, get_rate_ipg_per, NULL);
-DEFINE_CLOCK(i2c3_clk,   2, CCM_CGR1, 14, get_rate_ipg_per, NULL);
-DEFINE_CLOCK(iomuxc_clk, 0, CCM_CGR1, 16, NULL, NULL);
-DEFINE_CLOCK(ipu_clk,    0, CCM_CGR1, 18, get_rate_hsp, NULL);
-DEFINE_CLOCK(kpp_clk,    0, CCM_CGR1, 20, get_rate_ipg, NULL);
-DEFINE_CLOCK(mlb_clk,    0, CCM_CGR1, 22, get_rate_ahb, NULL);
-DEFINE_CLOCK(mshc_clk,   0, CCM_CGR1, 24, get_rate_mshc, NULL);
-DEFINE_CLOCK(owire_clk,  0, CCM_CGR1, 26, get_rate_ipg_per, NULL);
-DEFINE_CLOCK(pwm_clk,    0, CCM_CGR1, 28, get_rate_ipg_per, NULL);
-DEFINE_CLOCK(rngc_clk,   0, CCM_CGR1, 30, get_rate_ipg, NULL);
+DEFINE_CLOCK(fec_clk,    0, MX35_CCM_CGR1,  0, get_rate_ipg, NULL);
+DEFINE_CLOCK(gpio1_clk,  0, MX35_CCM_CGR1,  2, NULL, NULL);
+DEFINE_CLOCK(gpio2_clk,  1, MX35_CCM_CGR1,  4, NULL, NULL);
+DEFINE_CLOCK(gpio3_clk,  2, MX35_CCM_CGR1,  6, NULL, NULL);
+DEFINE_CLOCK(gpt_clk,    0, MX35_CCM_CGR1,  8, get_rate_ipg, NULL);
+DEFINE_CLOCK(i2c1_clk,   0, MX35_CCM_CGR1, 10, get_rate_ipg_per, NULL);
+DEFINE_CLOCK(i2c2_clk,   1, MX35_CCM_CGR1, 12, get_rate_ipg_per, NULL);
+DEFINE_CLOCK(i2c3_clk,   2, MX35_CCM_CGR1, 14, get_rate_ipg_per, NULL);
+DEFINE_CLOCK(iomuxc_clk, 0, MX35_CCM_CGR1, 16, NULL, NULL);
+DEFINE_CLOCK(ipu_clk,    0, MX35_CCM_CGR1, 18, get_rate_hsp, NULL);
+DEFINE_CLOCK(kpp_clk,    0, MX35_CCM_CGR1, 20, get_rate_ipg, NULL);
+DEFINE_CLOCK(mlb_clk,    0, MX35_CCM_CGR1, 22, get_rate_ahb, NULL);
+DEFINE_CLOCK(mshc_clk,   0, MX35_CCM_CGR1, 24, get_rate_mshc, NULL);
+DEFINE_CLOCK(owire_clk,  0, MX35_CCM_CGR1, 26, get_rate_ipg_per, NULL);
+DEFINE_CLOCK(pwm_clk,    0, MX35_CCM_CGR1, 28, get_rate_ipg_per, NULL);
+DEFINE_CLOCK(rngc_clk,   0, MX35_CCM_CGR1, 30, get_rate_ipg, NULL);
 
-DEFINE_CLOCK(rtc_clk,    0, CCM_CGR2,  0, get_rate_ipg, NULL);
-DEFINE_CLOCK(rtic_clk,   0, CCM_CGR2,  2, get_rate_ahb, NULL);
-DEFINE_CLOCK(scc_clk,    0, CCM_CGR2,  4, get_rate_ipg, NULL);
-DEFINE_CLOCK(sdma_clk,   0, CCM_CGR2,  6, NULL, NULL);
-DEFINE_CLOCK(spba_clk,   0, CCM_CGR2,  8, get_rate_ipg, NULL);
-DEFINE_CLOCK(spdif_clk,  0, CCM_CGR2, 10, NULL, NULL);
-DEFINE_CLOCK(ssi1_clk,   0, CCM_CGR2, 12, get_rate_ssi, NULL);
-DEFINE_CLOCK(ssi2_clk,   1, CCM_CGR2, 14, get_rate_ssi, NULL);
-DEFINE_CLOCK(uart1_clk,  0, CCM_CGR2, 16, get_rate_uart, NULL);
-DEFINE_CLOCK(uart2_clk,  1, CCM_CGR2, 18, get_rate_uart, NULL);
-DEFINE_CLOCK(uart3_clk,  2, CCM_CGR2, 20, get_rate_uart, NULL);
-DEFINE_CLOCK(usbotg_clk, 0, CCM_CGR2, 22, get_rate_otg, NULL);
-DEFINE_CLOCK(wdog_clk,   0, CCM_CGR2, 24, NULL, NULL);
-DEFINE_CLOCK(max_clk,    0, CCM_CGR2, 26, NULL, NULL);
-DEFINE_CLOCK(audmux_clk, 0, CCM_CGR2, 30, NULL, NULL);
+DEFINE_CLOCK(rtc_clk,    0, MX35_CCM_CGR2,  0, get_rate_ipg, NULL);
+DEFINE_CLOCK(rtic_clk,   0, MX35_CCM_CGR2,  2, get_rate_ahb, NULL);
+DEFINE_CLOCK(scc_clk,    0, MX35_CCM_CGR2,  4, get_rate_ipg, NULL);
+DEFINE_CLOCK(sdma_clk,   0, MX35_CCM_CGR2,  6, NULL, NULL);
+DEFINE_CLOCK(spba_clk,   0, MX35_CCM_CGR2,  8, get_rate_ipg, NULL);
+DEFINE_CLOCK(spdif_clk,  0, MX35_CCM_CGR2, 10, NULL, NULL);
+DEFINE_CLOCK(ssi1_clk,   0, MX35_CCM_CGR2, 12, get_rate_ssi, NULL);
+DEFINE_CLOCK(ssi2_clk,   1, MX35_CCM_CGR2, 14, get_rate_ssi, NULL);
+DEFINE_CLOCK(uart1_clk,  0, MX35_CCM_CGR2, 16, get_rate_uart, NULL);
+DEFINE_CLOCK(uart2_clk,  1, MX35_CCM_CGR2, 18, get_rate_uart, NULL);
+DEFINE_CLOCK(uart3_clk,  2, MX35_CCM_CGR2, 20, get_rate_uart, NULL);
+DEFINE_CLOCK(usbotg_clk, 0, MX35_CCM_CGR2, 22, get_rate_otg, NULL);
+DEFINE_CLOCK(wdog_clk,   0, MX35_CCM_CGR2, 24, NULL, NULL);
+DEFINE_CLOCK(max_clk,    0, MX35_CCM_CGR2, 26, NULL, NULL);
+DEFINE_CLOCK(audmux_clk, 0, MX35_CCM_CGR2, 30, NULL, NULL);
 
-DEFINE_CLOCK(csi_clk,    0, CCM_CGR3,  0, get_rate_csi, NULL);
-DEFINE_CLOCK(iim_clk,    0, CCM_CGR3,  2, NULL, NULL);
-DEFINE_CLOCK(gpu2d_clk,  0, CCM_CGR3,  4, NULL, NULL);
+DEFINE_CLOCK(csi_clk,    0, MX35_CCM_CGR3,  0, get_rate_csi, NULL);
+DEFINE_CLOCK(iim_clk,    0, MX35_CCM_CGR3,  2, NULL, NULL);
+DEFINE_CLOCK(gpu2d_clk,  0, MX35_CCM_CGR3,  4, NULL, NULL);
 
 DEFINE_CLOCK(usbahb_clk, 0, 0,         0, get_rate_ahb, NULL);
 
@@ -422,7 +406,7 @@
 {
 	unsigned long div1;
 
-	div1 = (__raw_readl(CCM_BASE + CCM_PDR4) >> 28) + 1;
+	div1 = (__raw_readl(MX35_CCM_PDR4) >> 28) + 1;
 
 	return get_rate_ahb(NULL) / div1;
 }
@@ -499,7 +483,7 @@
 	_REGISTER_CLOCK("imx2-wdt.0", NULL, wdog_clk)
 	_REGISTER_CLOCK(NULL, "max", max_clk)
 	_REGISTER_CLOCK(NULL, "audmux", audmux_clk)
-	_REGISTER_CLOCK(NULL, "csi", csi_clk)
+	_REGISTER_CLOCK("mx3-camera.0", NULL, csi_clk)
 	_REGISTER_CLOCK(NULL, "iim", iim_clk)
 	_REGISTER_CLOCK(NULL, "gpu2d", gpu2d_clk)
 	_REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk)
@@ -518,11 +502,11 @@
 	/* Turn off all clocks except the ones we need to survive, namely:
 	 * EMI, GPIO1/2/3, GPT, IOMUX, MAX and eventually uart
 	 */
-	__raw_writel((3 << 18), CCM_BASE + CCM_CGR0);
+	__raw_writel((3 << 18), MX35_CCM_CGR0);
 	__raw_writel((3 << 2) | (3 << 4) | (3 << 6) | (3 << 8) | (3 << 16),
-			CCM_BASE + CCM_CGR1);
-	__raw_writel(cgr2, CCM_BASE + CCM_CGR2);
-	__raw_writel(0, CCM_BASE + CCM_CGR3);
+			MX35_CCM_CGR1);
+	__raw_writel(cgr2, MX35_CCM_CGR2);
+	__raw_writel(0, MX35_CCM_CGR3);
 
 	clk_enable(&iim_clk);
 	imx_print_silicon_rev("i.MX35", mx35_revision());
@@ -533,7 +517,7 @@
 	 * extra clocks turned on, otherwise the MX35 boot ROM code will
 	 * hang after a watchdog reset.
 	 */
-	if (!(__raw_readl(CCM_BASE + CCM_RCSR) & (3 << 10))) {
+	if (!(__raw_readl(MX35_CCM_RCSR) & (3 << 10))) {
 		/* Additionally turn on UART1, SCC, and IIM clocks */
 		clk_enable(&iim_clk);
 		clk_enable(&uart1_clk);
diff --git a/arch/arm/mach-imx/clock-imx6q.c b/arch/arm/mach-imx/clock-imx6q.c
index 2d88f8b..111c328 100644
--- a/arch/arm/mach-imx/clock-imx6q.c
+++ b/arch/arm/mach-imx/clock-imx6q.c
@@ -329,6 +329,12 @@
 #define BM_CLPCR_MASK_SCU_IDLE		(0x1 << 26)
 #define BM_CLPCR_MASK_L2CC_IDLE		(0x1 << 27)
 
+#define BP_CCOSR_CKO1_EN		7
+#define BP_CCOSR_CKO1_PODF		4
+#define BM_CCOSR_CKO1_PODF		(0x7 << 4)
+#define BP_CCOSR_CKO1_SEL		0
+#define BM_CCOSR_CKO1_SEL		(0xf << 0)
+
 #define FREQ_480M	480000000
 #define FREQ_528M	528000000
 #define FREQ_594M	594000000
@@ -393,6 +399,7 @@
 static struct clk ipu2_di0_clk;
 static struct clk ipu2_di1_clk;
 static struct clk enfc_clk;
+static struct clk cko1_clk;
 static struct clk dummy_clk = {};
 
 static unsigned long external_high_reference;
@@ -938,6 +945,24 @@
 	writel_relaxed(reg, clk->enable_reg);
 }
 
+static int _clk_enable_1b(struct clk *clk)
+{
+	u32 reg;
+	reg = readl_relaxed(clk->enable_reg);
+	reg |= 0x1 << clk->enable_shift;
+	writel_relaxed(reg, clk->enable_reg);
+
+	return 0;
+}
+
+static void _clk_disable_1b(struct clk *clk)
+{
+	u32 reg;
+	reg = readl_relaxed(clk->enable_reg);
+	reg &= ~(0x1 << clk->enable_shift);
+	writel_relaxed(reg, clk->enable_reg);
+}
+
 struct divider {
 	struct clk *clk;
 	void __iomem *reg;
@@ -983,6 +1008,7 @@
 DEF_CLK_DIV1(ipu2_di1_pre_div,	&ipu2_di1_pre_clk,	CSCDR2,	IPU2_DI1_PRE);
 DEF_CLK_DIV1(ipu1_div,		&ipu1_clk,		CSCDR3,	IPU1_HSP);
 DEF_CLK_DIV1(ipu2_div,		&ipu2_clk,		CSCDR3,	IPU2_HSP);
+DEF_CLK_DIV1(cko1_div,		&cko1_clk,		CCOSR, CKO1);
 
 #define DEF_CLK_DIV2(d, c, r, b)				\
 	static struct divider d = {				\
@@ -1038,6 +1064,7 @@
 	&enfc_div,
 	&spdif_div,
 	&asrc_serial_div,
+	&cko1_div,
 };
 
 static unsigned long ldb_di_clk_get_rate(struct clk *clk)
@@ -1625,6 +1652,32 @@
 DEF_IPU_MUX(1);
 DEF_IPU_MUX(2);
 
+static struct multiplexer cko1_mux = {
+	.clk = &cko1_clk,
+	.reg = CCOSR,
+	.bp = BP_CCOSR_CKO1_SEL,
+	.bm = BM_CCOSR_CKO1_SEL,
+	.parents = {
+		&pll3_usb_otg,
+		&pll2_bus,
+		&pll1_sys,
+		&pll5_video,
+		&dummy_clk,
+		&axi_clk,
+		&enfc_clk,
+		&ipu1_di0_clk,
+		&ipu1_di1_clk,
+		&ipu2_di0_clk,
+		&ipu2_di1_clk,
+		&ahb_clk,
+		&ipg_clk,
+		&ipg_perclk,
+		&ckil_clk,
+		&pll4_audio,
+		NULL
+	},
+};
+
 static struct multiplexer *multiplexers[] = {
 	&axi_mux,
 	&periph_mux,
@@ -1667,6 +1720,7 @@
 	&ipu2_di1_mux,
 	&ipu1_mux,
 	&ipu2_mux,
+	&cko1_mux,
 };
 
 static int _clk_set_parent(struct clk *clk, struct clk *parent)
@@ -1690,7 +1744,7 @@
 			break;
 		i++;
 	}
-	if (!m->parents[i])
+	if (!m->parents[i] || m->parents[i] == &dummy_clk)
 		return -EINVAL;
 
 	val = readl_relaxed(m->reg);
@@ -1745,6 +1799,20 @@
 		.secondary	= s,			\
 	}
 
+#define DEF_CLK_1B(name, er, es, p, s)			\
+	static struct clk name = {			\
+		.enable_reg	= er,			\
+		.enable_shift	= es,			\
+		.enable		= _clk_enable_1b,	\
+		.disable	= _clk_disable_1b,	\
+		.get_rate	= _clk_get_rate,	\
+		.set_rate	= _clk_set_rate,	\
+		.round_rate	= _clk_round_rate,	\
+		.set_parent	= _clk_set_parent,	\
+		.parent		= p,			\
+		.secondary	= s,			\
+	}
+
 DEF_CLK(aips_tz1_clk,	  CCGR0, CG0,  &ahb_clk,	  NULL);
 DEF_CLK(aips_tz2_clk,	  CCGR0, CG1,  &ahb_clk,	  NULL);
 DEF_CLK(apbh_dma_clk,	  CCGR0, CG2,  &ahb_clk,	  NULL);
@@ -1811,6 +1879,7 @@
 DEF_CLK(emi_slow_clk,	  CCGR6, CG5,  &axi_clk,	  NULL);
 DEF_CLK(vdo_axi_clk,	  CCGR6, CG6,  &axi_clk,	  NULL);
 DEF_CLK(vpu_clk,	  CCGR6, CG7,  &axi_clk,	  NULL);
+DEF_CLK_1B(cko1_clk,	  CCOSR, BP_CCOSR_CKO1_EN, &pll2_bus, NULL);
 
 static int pcie_clk_enable(struct clk *clk)
 {
@@ -1922,6 +1991,7 @@
 	_REGISTER_CLOCK(NULL, "gpmi_io_clk", gpmi_io_clk),
 	_REGISTER_CLOCK(NULL, "usboh3_clk", usboh3_clk),
 	_REGISTER_CLOCK(NULL, "sata_clk", sata_clk),
+	_REGISTER_CLOCK(NULL, "cko1_clk", cko1_clk),
 };
 
 int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
@@ -2029,6 +2099,8 @@
 	clk_set_rate(&usdhc3_clk, 49500000);
 	clk_set_rate(&usdhc4_clk, 49500000);
 
+	clk_set_parent(&cko1_clk, &ahb_clk);
+
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt");
 	base = of_iomap(np, 0);
 	WARN_ON(!base);
diff --git a/arch/arm/mach-imx/cpu-imx5.c b/arch/arm/mach-imx/cpu-imx5.c
index 5e2e7a8..aa15c51 100644
--- a/arch/arm/mach-imx/cpu-imx5.c
+++ b/arch/arm/mach-imx/cpu-imx5.c
@@ -149,39 +149,3 @@
 	return mx5_cpu_rev;
 }
 EXPORT_SYMBOL(mx50_revision);
-
-static int __init post_cpu_init(void)
-{
-	unsigned int reg;
-	void __iomem *base;
-
-	if (cpu_is_mx51() || cpu_is_mx53()) {
-		if (cpu_is_mx51())
-			base = MX51_IO_ADDRESS(MX51_AIPS1_BASE_ADDR);
-		else
-			base = MX53_IO_ADDRESS(MX53_AIPS1_BASE_ADDR);
-
-		__raw_writel(0x0, base + 0x40);
-		__raw_writel(0x0, base + 0x44);
-		__raw_writel(0x0, base + 0x48);
-		__raw_writel(0x0, base + 0x4C);
-		reg = __raw_readl(base + 0x50) & 0x00FFFFFF;
-		__raw_writel(reg, base + 0x50);
-
-		if (cpu_is_mx51())
-			base = MX51_IO_ADDRESS(MX51_AIPS2_BASE_ADDR);
-		else
-			base = MX53_IO_ADDRESS(MX53_AIPS2_BASE_ADDR);
-
-		__raw_writel(0x0, base + 0x40);
-		__raw_writel(0x0, base + 0x44);
-		__raw_writel(0x0, base + 0x48);
-		__raw_writel(0x0, base + 0x4C);
-		reg = __raw_readl(base + 0x50) & 0x00FFFFFF;
-		__raw_writel(reg, base + 0x50);
-	}
-
-	return 0;
-}
-
-postcore_initcall(post_cpu_init);
diff --git a/arch/arm/mach-imx/cpu_op-mx51.c b/arch/arm/mach-imx/cpu_op-mx51.c
index 9d34c3d..7b92cd6 100644
--- a/arch/arm/mach-imx/cpu_op-mx51.c
+++ b/arch/arm/mach-imx/cpu_op-mx51.c
@@ -11,6 +11,7 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
+#include <linux/bug.h>
 #include <linux/types.h>
 #include <mach/hardware.h>
 #include <linux/kernel.h>
diff --git a/arch/arm/mach-imx/crmregs-imx3.h b/arch/arm/mach-imx/crmregs-imx3.h
new file mode 100644
index 0000000..5314127
--- /dev/null
+++ b/arch/arm/mach-imx/crmregs-imx3.h
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef __ARCH_ARM_MACH_MX3_CRM_REGS_H__
+#define __ARCH_ARM_MACH_MX3_CRM_REGS_H__
+
+#define CKIH_CLK_FREQ           26000000
+#define CKIH_CLK_FREQ_27MHZ     27000000
+#define CKIL_CLK_FREQ           32768
+
+#define MXC_CCM_BASE		(cpu_is_mx31() ? \
+MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR) : MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR))
+
+/* Register addresses */
+#define MXC_CCM_CCMR		(MXC_CCM_BASE + 0x00)
+#define MXC_CCM_PDR0		(MXC_CCM_BASE + 0x04)
+#define MXC_CCM_PDR1		(MXC_CCM_BASE + 0x08)
+#define MX35_CCM_PDR2		(MXC_CCM_BASE + 0x0C)
+#define MXC_CCM_RCSR		(MXC_CCM_BASE + 0x0C)
+#define MX35_CCM_PDR3		(MXC_CCM_BASE + 0x10)
+#define MXC_CCM_MPCTL		(MXC_CCM_BASE + 0x10)
+#define MX35_CCM_PDR4		(MXC_CCM_BASE + 0x14)
+#define MXC_CCM_UPCTL		(MXC_CCM_BASE + 0x14)
+#define MX35_CCM_RCSR		(MXC_CCM_BASE + 0x18)
+#define MXC_CCM_SRPCTL		(MXC_CCM_BASE + 0x18)
+#define MX35_CCM_MPCTL		(MXC_CCM_BASE + 0x1C)
+#define MXC_CCM_COSR		(MXC_CCM_BASE + 0x1C)
+#define MX35_CCM_PPCTL		(MXC_CCM_BASE + 0x20)
+#define MXC_CCM_CGR0		(MXC_CCM_BASE + 0x20)
+#define MX35_CCM_ACMR		(MXC_CCM_BASE + 0x24)
+#define MXC_CCM_CGR1		(MXC_CCM_BASE + 0x24)
+#define MX35_CCM_COSR		(MXC_CCM_BASE + 0x28)
+#define MXC_CCM_CGR2		(MXC_CCM_BASE + 0x28)
+#define MX35_CCM_CGR0		(MXC_CCM_BASE + 0x2C)
+#define MXC_CCM_WIMR		(MXC_CCM_BASE + 0x2C)
+#define MX35_CCM_CGR1		(MXC_CCM_BASE + 0x30)
+#define MXC_CCM_LDC		(MXC_CCM_BASE + 0x30)
+#define MX35_CCM_CGR2		(MXC_CCM_BASE + 0x34)
+#define MXC_CCM_DCVR0		(MXC_CCM_BASE + 0x34)
+#define MX35_CCM_CGR3		(MXC_CCM_BASE + 0x38)
+#define MXC_CCM_DCVR1		(MXC_CCM_BASE + 0x38)
+#define MXC_CCM_DCVR2		(MXC_CCM_BASE + 0x3C)
+#define MXC_CCM_DCVR3		(MXC_CCM_BASE + 0x40)
+#define MXC_CCM_LTR0		(MXC_CCM_BASE + 0x44)
+#define MXC_CCM_LTR1		(MXC_CCM_BASE + 0x48)
+#define MXC_CCM_LTR2		(MXC_CCM_BASE + 0x4C)
+#define MXC_CCM_LTR3		(MXC_CCM_BASE + 0x50)
+#define MXC_CCM_LTBR0		(MXC_CCM_BASE + 0x54)
+#define MXC_CCM_LTBR1		(MXC_CCM_BASE + 0x58)
+#define MXC_CCM_PMCR0		(MXC_CCM_BASE + 0x5C)
+#define MXC_CCM_PMCR1		(MXC_CCM_BASE + 0x60)
+#define MXC_CCM_PDR2		(MXC_CCM_BASE + 0x64)
+
+/* Register bit definitions */
+#define MXC_CCM_CCMR_WBEN                       (1 << 27)
+#define MXC_CCM_CCMR_CSCS                       (1 << 25)
+#define MXC_CCM_CCMR_PERCS                      (1 << 24)
+#define MXC_CCM_CCMR_SSI1S_OFFSET               18
+#define MXC_CCM_CCMR_SSI1S_MASK                 (0x3 << 18)
+#define MXC_CCM_CCMR_SSI2S_OFFSET               21
+#define MXC_CCM_CCMR_SSI2S_MASK                 (0x3 << 21)
+#define MXC_CCM_CCMR_LPM_OFFSET                 14
+#define MXC_CCM_CCMR_LPM_MASK                   (0x3 << 14)
+#define MXC_CCM_CCMR_LPM_WAIT_MX35		(0x1 << 14)
+#define MXC_CCM_CCMR_FIRS_OFFSET                11
+#define MXC_CCM_CCMR_FIRS_MASK                  (0x3 << 11)
+#define MXC_CCM_CCMR_UPE                        (1 << 9)
+#define MXC_CCM_CCMR_SPE                        (1 << 8)
+#define MXC_CCM_CCMR_MDS                        (1 << 7)
+#define MXC_CCM_CCMR_SBYCS                      (1 << 4)
+#define MXC_CCM_CCMR_MPE                        (1 << 3)
+#define MXC_CCM_CCMR_PRCS_OFFSET                1
+#define MXC_CCM_CCMR_PRCS_MASK                  (0x3 << 1)
+
+#define MXC_CCM_PDR0_CSI_PODF_OFFSET            26
+#define MXC_CCM_PDR0_CSI_PODF_MASK              (0x3F << 26)
+#define MXC_CCM_PDR0_CSI_PRDF_OFFSET            23
+#define MXC_CCM_PDR0_CSI_PRDF_MASK              (0x7 << 23)
+#define MXC_CCM_PDR0_PER_PODF_OFFSET            16
+#define MXC_CCM_PDR0_PER_PODF_MASK              (0x1F << 16)
+#define MXC_CCM_PDR0_HSP_PODF_OFFSET            11
+#define MXC_CCM_PDR0_HSP_PODF_MASK              (0x7 << 11)
+#define MXC_CCM_PDR0_NFC_PODF_OFFSET            8
+#define MXC_CCM_PDR0_NFC_PODF_MASK              (0x7 << 8)
+#define MXC_CCM_PDR0_IPG_PODF_OFFSET            6
+#define MXC_CCM_PDR0_IPG_PODF_MASK              (0x3 << 6)
+#define MXC_CCM_PDR0_MAX_PODF_OFFSET            3
+#define MXC_CCM_PDR0_MAX_PODF_MASK              (0x7 << 3)
+#define MXC_CCM_PDR0_MCU_PODF_OFFSET            0
+#define MXC_CCM_PDR0_MCU_PODF_MASK              0x7
+
+#define MXC_CCM_PDR1_USB_PRDF_OFFSET            30
+#define MXC_CCM_PDR1_USB_PRDF_MASK              (0x3 << 30)
+#define MXC_CCM_PDR1_USB_PODF_OFFSET            27
+#define MXC_CCM_PDR1_USB_PODF_MASK              (0x7 << 27)
+#define MXC_CCM_PDR1_FIRI_PRE_PODF_OFFSET       24
+#define MXC_CCM_PDR1_FIRI_PRE_PODF_MASK         (0x7 << 24)
+#define MXC_CCM_PDR1_FIRI_PODF_OFFSET           18
+#define MXC_CCM_PDR1_FIRI_PODF_MASK             (0x3F << 18)
+#define MXC_CCM_PDR1_SSI2_PRE_PODF_OFFSET       15
+#define MXC_CCM_PDR1_SSI2_PRE_PODF_MASK         (0x7 << 15)
+#define MXC_CCM_PDR1_SSI2_PODF_OFFSET           9
+#define MXC_CCM_PDR1_SSI2_PODF_MASK             (0x3F << 9)
+#define MXC_CCM_PDR1_SSI1_PRE_PODF_OFFSET       6
+#define MXC_CCM_PDR1_SSI1_PRE_PODF_MASK         (0x7 << 6)
+#define MXC_CCM_PDR1_SSI1_PODF_OFFSET           0
+#define MXC_CCM_PDR1_SSI1_PODF_MASK             0x3F
+
+/* Bit definitions for RCSR */
+#define MXC_CCM_RCSR_NF16B			0x80000000
+
+/*
+ * LTR0 register offsets
+ */
+#define MXC_CCM_LTR0_DIV3CK_OFFSET              1
+#define MXC_CCM_LTR0_DIV3CK_MASK                (0x3 << 1)
+#define MXC_CCM_LTR0_DNTHR_OFFSET               16
+#define MXC_CCM_LTR0_DNTHR_MASK                 (0x3F << 16)
+#define MXC_CCM_LTR0_UPTHR_OFFSET               22
+#define MXC_CCM_LTR0_UPTHR_MASK                 (0x3F << 22)
+
+/*
+ * LTR1 register offsets
+ */
+#define MXC_CCM_LTR1_PNCTHR_OFFSET              0
+#define MXC_CCM_LTR1_PNCTHR_MASK                0x3F
+#define MXC_CCM_LTR1_UPCNT_OFFSET               6
+#define MXC_CCM_LTR1_UPCNT_MASK                 (0xFF << 6)
+#define MXC_CCM_LTR1_DNCNT_OFFSET               14
+#define MXC_CCM_LTR1_DNCNT_MASK                 (0xFF << 14)
+#define MXC_CCM_LTR1_LTBRSR_MASK                0x400000
+#define MXC_CCM_LTR1_LTBRSR_OFFSET              22
+#define MXC_CCM_LTR1_LTBRSR                     0x400000
+#define MXC_CCM_LTR1_LTBRSH                     0x800000
+
+/*
+ * LTR2 bit definitions. x ranges from 0 for WSW9 to 6 for WSW15
+ */
+#define MXC_CCM_LTR2_WSW_OFFSET(x)              (11 + (x) * 3)
+#define MXC_CCM_LTR2_WSW_MASK(x)                (0x7 << \
+					MXC_CCM_LTR2_WSW_OFFSET((x)))
+#define MXC_CCM_LTR2_EMAC_OFFSET                0
+#define MXC_CCM_LTR2_EMAC_MASK                  0x1FF
+
+/*
+ * LTR3 bit definitions. x ranges from 0 for WSW0 to 8 for WSW8
+ */
+#define MXC_CCM_LTR3_WSW_OFFSET(x)              (5 + (x) * 3)
+#define MXC_CCM_LTR3_WSW_MASK(x)                (0x7 << \
+					MXC_CCM_LTR3_WSW_OFFSET((x)))
+
+#define MXC_CCM_PMCR0_DFSUP1                    0x80000000
+#define MXC_CCM_PMCR0_DFSUP1_SPLL               (0 << 31)
+#define MXC_CCM_PMCR0_DFSUP1_MPLL               (1 << 31)
+#define MXC_CCM_PMCR0_DFSUP0                    0x40000000
+#define MXC_CCM_PMCR0_DFSUP0_PLL                (0 << 30)
+#define MXC_CCM_PMCR0_DFSUP0_PDR                (1 << 30)
+#define MXC_CCM_PMCR0_DFSUP_MASK                (0x3 << 30)
+
+#define DVSUP_TURBO				0
+#define DVSUP_HIGH				1
+#define DVSUP_MEDIUM				2
+#define DVSUP_LOW				3
+#define MXC_CCM_PMCR0_DVSUP_TURBO               (DVSUP_TURBO << 28)
+#define MXC_CCM_PMCR0_DVSUP_HIGH                (DVSUP_HIGH << 28)
+#define MXC_CCM_PMCR0_DVSUP_MEDIUM              (DVSUP_MEDIUM << 28)
+#define MXC_CCM_PMCR0_DVSUP_LOW                 (DVSUP_LOW << 28)
+#define MXC_CCM_PMCR0_DVSUP_OFFSET              28
+#define MXC_CCM_PMCR0_DVSUP_MASK                (0x3 << 28)
+#define MXC_CCM_PMCR0_UDSC                      0x08000000
+#define MXC_CCM_PMCR0_UDSC_MASK                 (1 << 27)
+#define MXC_CCM_PMCR0_UDSC_UP                   (1 << 27)
+#define MXC_CCM_PMCR0_UDSC_DOWN                 (0 << 27)
+
+#define MXC_CCM_PMCR0_VSCNT_1                   (0x0 << 24)
+#define MXC_CCM_PMCR0_VSCNT_2                   (0x1 << 24)
+#define MXC_CCM_PMCR0_VSCNT_3                   (0x2 << 24)
+#define MXC_CCM_PMCR0_VSCNT_4                   (0x3 << 24)
+#define MXC_CCM_PMCR0_VSCNT_5                   (0x4 << 24)
+#define MXC_CCM_PMCR0_VSCNT_6                   (0x5 << 24)
+#define MXC_CCM_PMCR0_VSCNT_7                   (0x6 << 24)
+#define MXC_CCM_PMCR0_VSCNT_8                   (0x7 << 24)
+#define MXC_CCM_PMCR0_VSCNT_OFFSET              24
+#define MXC_CCM_PMCR0_VSCNT_MASK                (0x7 << 24)
+#define MXC_CCM_PMCR0_DVFEV                     0x00800000
+#define MXC_CCM_PMCR0_DVFIS                     0x00400000
+#define MXC_CCM_PMCR0_LBMI                      0x00200000
+#define MXC_CCM_PMCR0_LBFL                      0x00100000
+#define MXC_CCM_PMCR0_LBCF_4                    (0x0 << 18)
+#define MXC_CCM_PMCR0_LBCF_8                    (0x1 << 18)
+#define MXC_CCM_PMCR0_LBCF_12                   (0x2 << 18)
+#define MXC_CCM_PMCR0_LBCF_16                   (0x3 << 18)
+#define MXC_CCM_PMCR0_LBCF_OFFSET               18
+#define MXC_CCM_PMCR0_LBCF_MASK                 (0x3 << 18)
+#define MXC_CCM_PMCR0_PTVIS                     0x00020000
+#define MXC_CCM_PMCR0_UPDTEN                    0x00010000
+#define MXC_CCM_PMCR0_UPDTEN_MASK               (0x1 << 16)
+#define MXC_CCM_PMCR0_FSVAIM                    0x00008000
+#define MXC_CCM_PMCR0_FSVAI_OFFSET              13
+#define MXC_CCM_PMCR0_FSVAI_MASK                (0x3 << 13)
+#define MXC_CCM_PMCR0_DPVCR                     0x00001000
+#define MXC_CCM_PMCR0_DPVV                      0x00000800
+#define MXC_CCM_PMCR0_WFIM                      0x00000400
+#define MXC_CCM_PMCR0_DRCE3                     0x00000200
+#define MXC_CCM_PMCR0_DRCE2                     0x00000100
+#define MXC_CCM_PMCR0_DRCE1                     0x00000080
+#define MXC_CCM_PMCR0_DRCE0                     0x00000040
+#define MXC_CCM_PMCR0_DCR                       0x00000020
+#define MXC_CCM_PMCR0_DVFEN                     0x00000010
+#define MXC_CCM_PMCR0_PTVAIM                    0x00000008
+#define MXC_CCM_PMCR0_PTVAI_OFFSET              1
+#define MXC_CCM_PMCR0_PTVAI_MASK                (0x3 << 1)
+#define MXC_CCM_PMCR0_DPTEN                     0x00000001
+
+#define MXC_CCM_PMCR1_DVGP_OFFSET               0
+#define MXC_CCM_PMCR1_DVGP_MASK                 (0xF)
+
+#define MXC_CCM_PMCR1_PLLRDIS                      (0x1 << 7)
+#define MXC_CCM_PMCR1_EMIRQ_EN                      (0x1 << 8)
+
+#define MXC_CCM_DCVR_ULV_MASK                   (0x3FF << 22)
+#define MXC_CCM_DCVR_ULV_OFFSET                 22
+#define MXC_CCM_DCVR_LLV_MASK                   (0x3FF << 12)
+#define MXC_CCM_DCVR_LLV_OFFSET                 12
+#define MXC_CCM_DCVR_ELV_MASK                   (0x3FF << 2)
+#define MXC_CCM_DCVR_ELV_OFFSET                 2
+
+#define MXC_CCM_PDR2_MST2_PDF_MASK              (0x3F << 7)
+#define MXC_CCM_PDR2_MST2_PDF_OFFSET            7
+#define MXC_CCM_PDR2_MST1_PDF_MASK              0x3F
+#define MXC_CCM_PDR2_MST1_PDF_OFFSET            0
+
+#define MXC_CCM_COSR_CLKOSEL_MASK               0x0F
+#define MXC_CCM_COSR_CLKOSEL_OFFSET             0
+#define MXC_CCM_COSR_CLKOUTDIV_MASK             (0x07 << 6)
+#define MXC_CCM_COSR_CLKOUTDIV_OFFSET           6
+#define MXC_CCM_COSR_CLKOEN                     (1 << 9)
+
+/*
+ * PMCR0 register offsets
+ */
+#define MXC_CCM_PMCR0_LBFL_OFFSET   20
+#define MXC_CCM_PMCR0_DFSUP0_OFFSET 30
+#define MXC_CCM_PMCR0_DFSUP1_OFFSET 31
+
+#endif				/* __ARCH_ARM_MACH_MX3_CRM_REGS_H__ */
diff --git a/arch/arm/mach-imx/crmregs-imx31.h b/arch/arm/mach-imx/crmregs-imx31.h
deleted file mode 100644
index 37a8a07..0000000
--- a/arch/arm/mach-imx/crmregs-imx31.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-#ifndef __ARCH_ARM_MACH_MX3_CRM_REGS_H__
-#define __ARCH_ARM_MACH_MX3_CRM_REGS_H__
-
-#define CKIH_CLK_FREQ           26000000
-#define CKIH_CLK_FREQ_27MHZ     27000000
-#define CKIL_CLK_FREQ           32768
-
-#define MXC_CCM_BASE		MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR)
-
-/* Register addresses */
-#define MXC_CCM_CCMR		(MXC_CCM_BASE + 0x00)
-#define MXC_CCM_PDR0		(MXC_CCM_BASE + 0x04)
-#define MXC_CCM_PDR1		(MXC_CCM_BASE + 0x08)
-#define MXC_CCM_RCSR		(MXC_CCM_BASE + 0x0C)
-#define MXC_CCM_MPCTL		(MXC_CCM_BASE + 0x10)
-#define MXC_CCM_UPCTL		(MXC_CCM_BASE + 0x14)
-#define MXC_CCM_SRPCTL		(MXC_CCM_BASE + 0x18)
-#define MXC_CCM_COSR		(MXC_CCM_BASE + 0x1C)
-#define MXC_CCM_CGR0		(MXC_CCM_BASE + 0x20)
-#define MXC_CCM_CGR1		(MXC_CCM_BASE + 0x24)
-#define MXC_CCM_CGR2		(MXC_CCM_BASE + 0x28)
-#define MXC_CCM_WIMR		(MXC_CCM_BASE + 0x2C)
-#define MXC_CCM_LDC		(MXC_CCM_BASE + 0x30)
-#define MXC_CCM_DCVR0		(MXC_CCM_BASE + 0x34)
-#define MXC_CCM_DCVR1		(MXC_CCM_BASE + 0x38)
-#define MXC_CCM_DCVR2		(MXC_CCM_BASE + 0x3C)
-#define MXC_CCM_DCVR3		(MXC_CCM_BASE + 0x40)
-#define MXC_CCM_LTR0		(MXC_CCM_BASE + 0x44)
-#define MXC_CCM_LTR1		(MXC_CCM_BASE + 0x48)
-#define MXC_CCM_LTR2		(MXC_CCM_BASE + 0x4C)
-#define MXC_CCM_LTR3		(MXC_CCM_BASE + 0x50)
-#define MXC_CCM_LTBR0		(MXC_CCM_BASE + 0x54)
-#define MXC_CCM_LTBR1		(MXC_CCM_BASE + 0x58)
-#define MXC_CCM_PMCR0		(MXC_CCM_BASE + 0x5C)
-#define MXC_CCM_PMCR1		(MXC_CCM_BASE + 0x60)
-#define MXC_CCM_PDR2		(MXC_CCM_BASE + 0x64)
-
-/* Register bit definitions */
-#define MXC_CCM_CCMR_WBEN                       (1 << 27)
-#define MXC_CCM_CCMR_CSCS                       (1 << 25)
-#define MXC_CCM_CCMR_PERCS                      (1 << 24)
-#define MXC_CCM_CCMR_SSI1S_OFFSET               18
-#define MXC_CCM_CCMR_SSI1S_MASK                 (0x3 << 18)
-#define MXC_CCM_CCMR_SSI2S_OFFSET               21
-#define MXC_CCM_CCMR_SSI2S_MASK                 (0x3 << 21)
-#define MXC_CCM_CCMR_LPM_OFFSET                 14
-#define MXC_CCM_CCMR_LPM_MASK                   (0x3 << 14)
-#define MXC_CCM_CCMR_FIRS_OFFSET                11
-#define MXC_CCM_CCMR_FIRS_MASK                  (0x3 << 11)
-#define MXC_CCM_CCMR_UPE                        (1 << 9)
-#define MXC_CCM_CCMR_SPE                        (1 << 8)
-#define MXC_CCM_CCMR_MDS                        (1 << 7)
-#define MXC_CCM_CCMR_SBYCS                      (1 << 4)
-#define MXC_CCM_CCMR_MPE                        (1 << 3)
-#define MXC_CCM_CCMR_PRCS_OFFSET                1
-#define MXC_CCM_CCMR_PRCS_MASK                  (0x3 << 1)
-
-#define MXC_CCM_PDR0_CSI_PODF_OFFSET            26
-#define MXC_CCM_PDR0_CSI_PODF_MASK              (0x3F << 26)
-#define MXC_CCM_PDR0_CSI_PRDF_OFFSET            23
-#define MXC_CCM_PDR0_CSI_PRDF_MASK              (0x7 << 23)
-#define MXC_CCM_PDR0_PER_PODF_OFFSET            16
-#define MXC_CCM_PDR0_PER_PODF_MASK              (0x1F << 16)
-#define MXC_CCM_PDR0_HSP_PODF_OFFSET            11
-#define MXC_CCM_PDR0_HSP_PODF_MASK              (0x7 << 11)
-#define MXC_CCM_PDR0_NFC_PODF_OFFSET            8
-#define MXC_CCM_PDR0_NFC_PODF_MASK              (0x7 << 8)
-#define MXC_CCM_PDR0_IPG_PODF_OFFSET            6
-#define MXC_CCM_PDR0_IPG_PODF_MASK              (0x3 << 6)
-#define MXC_CCM_PDR0_MAX_PODF_OFFSET            3
-#define MXC_CCM_PDR0_MAX_PODF_MASK              (0x7 << 3)
-#define MXC_CCM_PDR0_MCU_PODF_OFFSET            0
-#define MXC_CCM_PDR0_MCU_PODF_MASK              0x7
-
-#define MXC_CCM_PDR1_USB_PRDF_OFFSET            30
-#define MXC_CCM_PDR1_USB_PRDF_MASK              (0x3 << 30)
-#define MXC_CCM_PDR1_USB_PODF_OFFSET            27
-#define MXC_CCM_PDR1_USB_PODF_MASK              (0x7 << 27)
-#define MXC_CCM_PDR1_FIRI_PRE_PODF_OFFSET       24
-#define MXC_CCM_PDR1_FIRI_PRE_PODF_MASK         (0x7 << 24)
-#define MXC_CCM_PDR1_FIRI_PODF_OFFSET           18
-#define MXC_CCM_PDR1_FIRI_PODF_MASK             (0x3F << 18)
-#define MXC_CCM_PDR1_SSI2_PRE_PODF_OFFSET       15
-#define MXC_CCM_PDR1_SSI2_PRE_PODF_MASK         (0x7 << 15)
-#define MXC_CCM_PDR1_SSI2_PODF_OFFSET           9
-#define MXC_CCM_PDR1_SSI2_PODF_MASK             (0x3F << 9)
-#define MXC_CCM_PDR1_SSI1_PRE_PODF_OFFSET       6
-#define MXC_CCM_PDR1_SSI1_PRE_PODF_MASK         (0x7 << 6)
-#define MXC_CCM_PDR1_SSI1_PODF_OFFSET           0
-#define MXC_CCM_PDR1_SSI1_PODF_MASK             0x3F
-
-/* Bit definitions for RCSR */
-#define MXC_CCM_RCSR_NF16B			0x80000000
-
-/*
- * LTR0 register offsets
- */
-#define MXC_CCM_LTR0_DIV3CK_OFFSET              1
-#define MXC_CCM_LTR0_DIV3CK_MASK                (0x3 << 1)
-#define MXC_CCM_LTR0_DNTHR_OFFSET               16
-#define MXC_CCM_LTR0_DNTHR_MASK                 (0x3F << 16)
-#define MXC_CCM_LTR0_UPTHR_OFFSET               22
-#define MXC_CCM_LTR0_UPTHR_MASK                 (0x3F << 22)
-
-/*
- * LTR1 register offsets
- */
-#define MXC_CCM_LTR1_PNCTHR_OFFSET              0
-#define MXC_CCM_LTR1_PNCTHR_MASK                0x3F
-#define MXC_CCM_LTR1_UPCNT_OFFSET               6
-#define MXC_CCM_LTR1_UPCNT_MASK                 (0xFF << 6)
-#define MXC_CCM_LTR1_DNCNT_OFFSET               14
-#define MXC_CCM_LTR1_DNCNT_MASK                 (0xFF << 14)
-#define MXC_CCM_LTR1_LTBRSR_MASK                0x400000
-#define MXC_CCM_LTR1_LTBRSR_OFFSET              22
-#define MXC_CCM_LTR1_LTBRSR                     0x400000
-#define MXC_CCM_LTR1_LTBRSH                     0x800000
-
-/*
- * LTR2 bit definitions. x ranges from 0 for WSW9 to 6 for WSW15
- */
-#define MXC_CCM_LTR2_WSW_OFFSET(x)              (11 + (x) * 3)
-#define MXC_CCM_LTR2_WSW_MASK(x)                (0x7 << \
-					MXC_CCM_LTR2_WSW_OFFSET((x)))
-#define MXC_CCM_LTR2_EMAC_OFFSET                0
-#define MXC_CCM_LTR2_EMAC_MASK                  0x1FF
-
-/*
- * LTR3 bit definitions. x ranges from 0 for WSW0 to 8 for WSW8
- */
-#define MXC_CCM_LTR3_WSW_OFFSET(x)              (5 + (x) * 3)
-#define MXC_CCM_LTR3_WSW_MASK(x)                (0x7 << \
-					MXC_CCM_LTR3_WSW_OFFSET((x)))
-
-#define MXC_CCM_PMCR0_DFSUP1                    0x80000000
-#define MXC_CCM_PMCR0_DFSUP1_SPLL               (0 << 31)
-#define MXC_CCM_PMCR0_DFSUP1_MPLL               (1 << 31)
-#define MXC_CCM_PMCR0_DFSUP0                    0x40000000
-#define MXC_CCM_PMCR0_DFSUP0_PLL                (0 << 30)
-#define MXC_CCM_PMCR0_DFSUP0_PDR                (1 << 30)
-#define MXC_CCM_PMCR0_DFSUP_MASK                (0x3 << 30)
-
-#define DVSUP_TURBO				0
-#define DVSUP_HIGH				1
-#define DVSUP_MEDIUM				2
-#define DVSUP_LOW				3
-#define MXC_CCM_PMCR0_DVSUP_TURBO               (DVSUP_TURBO << 28)
-#define MXC_CCM_PMCR0_DVSUP_HIGH                (DVSUP_HIGH << 28)
-#define MXC_CCM_PMCR0_DVSUP_MEDIUM              (DVSUP_MEDIUM << 28)
-#define MXC_CCM_PMCR0_DVSUP_LOW                 (DVSUP_LOW << 28)
-#define MXC_CCM_PMCR0_DVSUP_OFFSET              28
-#define MXC_CCM_PMCR0_DVSUP_MASK                (0x3 << 28)
-#define MXC_CCM_PMCR0_UDSC                      0x08000000
-#define MXC_CCM_PMCR0_UDSC_MASK                 (1 << 27)
-#define MXC_CCM_PMCR0_UDSC_UP                   (1 << 27)
-#define MXC_CCM_PMCR0_UDSC_DOWN                 (0 << 27)
-
-#define MXC_CCM_PMCR0_VSCNT_1                   (0x0 << 24)
-#define MXC_CCM_PMCR0_VSCNT_2                   (0x1 << 24)
-#define MXC_CCM_PMCR0_VSCNT_3                   (0x2 << 24)
-#define MXC_CCM_PMCR0_VSCNT_4                   (0x3 << 24)
-#define MXC_CCM_PMCR0_VSCNT_5                   (0x4 << 24)
-#define MXC_CCM_PMCR0_VSCNT_6                   (0x5 << 24)
-#define MXC_CCM_PMCR0_VSCNT_7                   (0x6 << 24)
-#define MXC_CCM_PMCR0_VSCNT_8                   (0x7 << 24)
-#define MXC_CCM_PMCR0_VSCNT_OFFSET              24
-#define MXC_CCM_PMCR0_VSCNT_MASK                (0x7 << 24)
-#define MXC_CCM_PMCR0_DVFEV                     0x00800000
-#define MXC_CCM_PMCR0_DVFIS                     0x00400000
-#define MXC_CCM_PMCR0_LBMI                      0x00200000
-#define MXC_CCM_PMCR0_LBFL                      0x00100000
-#define MXC_CCM_PMCR0_LBCF_4                    (0x0 << 18)
-#define MXC_CCM_PMCR0_LBCF_8                    (0x1 << 18)
-#define MXC_CCM_PMCR0_LBCF_12                   (0x2 << 18)
-#define MXC_CCM_PMCR0_LBCF_16                   (0x3 << 18)
-#define MXC_CCM_PMCR0_LBCF_OFFSET               18
-#define MXC_CCM_PMCR0_LBCF_MASK                 (0x3 << 18)
-#define MXC_CCM_PMCR0_PTVIS                     0x00020000
-#define MXC_CCM_PMCR0_UPDTEN                    0x00010000
-#define MXC_CCM_PMCR0_UPDTEN_MASK               (0x1 << 16)
-#define MXC_CCM_PMCR0_FSVAIM                    0x00008000
-#define MXC_CCM_PMCR0_FSVAI_OFFSET              13
-#define MXC_CCM_PMCR0_FSVAI_MASK                (0x3 << 13)
-#define MXC_CCM_PMCR0_DPVCR                     0x00001000
-#define MXC_CCM_PMCR0_DPVV                      0x00000800
-#define MXC_CCM_PMCR0_WFIM                      0x00000400
-#define MXC_CCM_PMCR0_DRCE3                     0x00000200
-#define MXC_CCM_PMCR0_DRCE2                     0x00000100
-#define MXC_CCM_PMCR0_DRCE1                     0x00000080
-#define MXC_CCM_PMCR0_DRCE0                     0x00000040
-#define MXC_CCM_PMCR0_DCR                       0x00000020
-#define MXC_CCM_PMCR0_DVFEN                     0x00000010
-#define MXC_CCM_PMCR0_PTVAIM                    0x00000008
-#define MXC_CCM_PMCR0_PTVAI_OFFSET              1
-#define MXC_CCM_PMCR0_PTVAI_MASK                (0x3 << 1)
-#define MXC_CCM_PMCR0_DPTEN                     0x00000001
-
-#define MXC_CCM_PMCR1_DVGP_OFFSET               0
-#define MXC_CCM_PMCR1_DVGP_MASK                 (0xF)
-
-#define MXC_CCM_PMCR1_PLLRDIS                      (0x1 << 7)
-#define MXC_CCM_PMCR1_EMIRQ_EN                      (0x1 << 8)
-
-#define MXC_CCM_DCVR_ULV_MASK                   (0x3FF << 22)
-#define MXC_CCM_DCVR_ULV_OFFSET                 22
-#define MXC_CCM_DCVR_LLV_MASK                   (0x3FF << 12)
-#define MXC_CCM_DCVR_LLV_OFFSET                 12
-#define MXC_CCM_DCVR_ELV_MASK                   (0x3FF << 2)
-#define MXC_CCM_DCVR_ELV_OFFSET                 2
-
-#define MXC_CCM_PDR2_MST2_PDF_MASK              (0x3F << 7)
-#define MXC_CCM_PDR2_MST2_PDF_OFFSET            7
-#define MXC_CCM_PDR2_MST1_PDF_MASK              0x3F
-#define MXC_CCM_PDR2_MST1_PDF_OFFSET            0
-
-#define MXC_CCM_COSR_CLKOSEL_MASK               0x0F
-#define MXC_CCM_COSR_CLKOSEL_OFFSET             0
-#define MXC_CCM_COSR_CLKOUTDIV_MASK             (0x07 << 6)
-#define MXC_CCM_COSR_CLKOUTDIV_OFFSET           6
-#define MXC_CCM_COSR_CLKOEN                     (1 << 9)
-
-/*
- * PMCR0 register offsets
- */
-#define MXC_CCM_PMCR0_LBFL_OFFSET   20
-#define MXC_CCM_PMCR0_DFSUP0_OFFSET 30
-#define MXC_CCM_PMCR0_DFSUP1_OFFSET 31
-
-#endif				/* __ARCH_ARM_MACH_MX3_CRM_REGS_H__ */
diff --git a/arch/arm/mach-imx/devices-imx27.h b/arch/arm/mach-imx/devices-imx27.h
index 2f727d7..28537a5 100644
--- a/arch/arm/mach-imx/devices-imx27.h
+++ b/arch/arm/mach-imx/devices-imx27.h
@@ -50,6 +50,8 @@
 extern const struct imx_mx2_camera_data imx27_mx2_camera_data;
 #define imx27_add_mx2_camera(pdata)	\
 	imx_add_mx2_camera(&imx27_mx2_camera_data, pdata)
+#define imx27_add_mx2_emmaprp(pdata)	\
+	imx_add_mx2_emmaprp(&imx27_mx2_camera_data)
 
 extern const struct imx_mxc_ehci_data imx27_mxc_ehci_otg_data;
 #define imx27_add_mxc_ehci_otg(pdata)	\
diff --git a/arch/arm/mach-imx/dma-v1.c b/arch/arm/mach-imx/dma-v1.c
deleted file mode 100644
index 42afc29..0000000
--- a/arch/arm/mach-imx/dma-v1.c
+++ /dev/null
@@ -1,846 +0,0 @@
-/*
- *  linux/arch/arm/plat-mxc/dma-v1.c
- *
- *  i.MX DMA registration and IRQ dispatching
- *
- * Copyright 2006 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- * Copyright 2008 Juergen Beisert, <kernel@pengutronix.de>
- * Copyright 2008 Sascha Hauer, <s.hauer@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/clk.h>
-#include <linux/scatterlist.h>
-#include <linux/io.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <mach/dma-v1.h>
-
-#define DMA_DCR     0x00		/* Control Register */
-#define DMA_DISR    0x04		/* Interrupt status Register */
-#define DMA_DIMR    0x08		/* Interrupt mask Register */
-#define DMA_DBTOSR  0x0c		/* Burst timeout status Register */
-#define DMA_DRTOSR  0x10		/* Request timeout Register */
-#define DMA_DSESR   0x14		/* Transfer Error Status Register */
-#define DMA_DBOSR   0x18		/* Buffer overflow status Register */
-#define DMA_DBTOCR  0x1c		/* Burst timeout control Register */
-#define DMA_WSRA    0x40		/* W-Size Register A */
-#define DMA_XSRA    0x44		/* X-Size Register A */
-#define DMA_YSRA    0x48		/* Y-Size Register A */
-#define DMA_WSRB    0x4c		/* W-Size Register B */
-#define DMA_XSRB    0x50		/* X-Size Register B */
-#define DMA_YSRB    0x54		/* Y-Size Register B */
-#define DMA_SAR(x)  (0x80 + ((x) << 6))	/* Source Address Registers */
-#define DMA_DAR(x)  (0x84 + ((x) << 6))	/* Destination Address Registers */
-#define DMA_CNTR(x) (0x88 + ((x) << 6))	/* Count Registers */
-#define DMA_CCR(x)  (0x8c + ((x) << 6))	/* Control Registers */
-#define DMA_RSSR(x) (0x90 + ((x) << 6))	/* Request source select Registers */
-#define DMA_BLR(x)  (0x94 + ((x) << 6))	/* Burst length Registers */
-#define DMA_RTOR(x) (0x98 + ((x) << 6))	/* Request timeout Registers */
-#define DMA_BUCR(x) (0x98 + ((x) << 6))	/* Bus Utilization Registers */
-#define DMA_CCNR(x) (0x9C + ((x) << 6))	/* Channel counter Registers */
-
-#define DCR_DRST           (1<<1)
-#define DCR_DEN            (1<<0)
-#define DBTOCR_EN          (1<<15)
-#define DBTOCR_CNT(x)      ((x) & 0x7fff)
-#define CNTR_CNT(x)        ((x) & 0xffffff)
-#define CCR_ACRPT          (1<<14)
-#define CCR_DMOD_LINEAR    (0x0 << 12)
-#define CCR_DMOD_2D        (0x1 << 12)
-#define CCR_DMOD_FIFO      (0x2 << 12)
-#define CCR_DMOD_EOBFIFO   (0x3 << 12)
-#define CCR_SMOD_LINEAR    (0x0 << 10)
-#define CCR_SMOD_2D        (0x1 << 10)
-#define CCR_SMOD_FIFO      (0x2 << 10)
-#define CCR_SMOD_EOBFIFO   (0x3 << 10)
-#define CCR_MDIR_DEC       (1<<9)
-#define CCR_MSEL_B         (1<<8)
-#define CCR_DSIZ_32        (0x0 << 6)
-#define CCR_DSIZ_8         (0x1 << 6)
-#define CCR_DSIZ_16        (0x2 << 6)
-#define CCR_SSIZ_32        (0x0 << 4)
-#define CCR_SSIZ_8         (0x1 << 4)
-#define CCR_SSIZ_16        (0x2 << 4)
-#define CCR_REN            (1<<3)
-#define CCR_RPT            (1<<2)
-#define CCR_FRC            (1<<1)
-#define CCR_CEN            (1<<0)
-#define RTOR_EN            (1<<15)
-#define RTOR_CLK           (1<<14)
-#define RTOR_PSC           (1<<13)
-
-/*
- * struct imx_dma_channel - i.MX specific DMA extension
- * @name: name specified by DMA client
- * @irq_handler: client callback for end of transfer
- * @err_handler: client callback for error condition
- * @data: clients context data for callbacks
- * @dma_mode: direction of the transfer %DMA_MODE_READ or %DMA_MODE_WRITE
- * @sg: pointer to the actual read/written chunk for scatter-gather emulation
- * @resbytes: total residual number of bytes to transfer
- *            (it can be lower or same as sum of SG mapped chunk sizes)
- * @sgcount: number of chunks to be read/written
- *
- * Structure is used for IMX DMA processing. It would be probably good
- * @struct dma_struct in the future for external interfacing and use
- * @struct imx_dma_channel only as extension to it.
- */
-
-struct imx_dma_channel {
-	const char *name;
-	void (*irq_handler) (int, void *);
-	void (*err_handler) (int, void *, int errcode);
-	void (*prog_handler) (int, void *, struct scatterlist *);
-	void *data;
-	unsigned int dma_mode;
-	struct scatterlist *sg;
-	unsigned int resbytes;
-	int dma_num;
-
-	int in_use;
-
-	u32 ccr_from_device;
-	u32 ccr_to_device;
-
-	struct timer_list watchdog;
-
-	int hw_chaining;
-};
-
-static void __iomem *imx_dmav1_baseaddr;
-
-static void imx_dmav1_writel(unsigned val, unsigned offset)
-{
-	__raw_writel(val, imx_dmav1_baseaddr + offset);
-}
-
-static unsigned imx_dmav1_readl(unsigned offset)
-{
-	return __raw_readl(imx_dmav1_baseaddr + offset);
-}
-
-static struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
-
-static struct clk *dma_clk;
-
-static int imx_dma_hw_chain(struct imx_dma_channel *imxdma)
-{
-	if (cpu_is_mx27())
-		return imxdma->hw_chaining;
-	else
-		return 0;
-}
-
-/*
- * imx_dma_sg_next - prepare next chunk for scatter-gather DMA emulation
- */
-static inline int imx_dma_sg_next(int channel, struct scatterlist *sg)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
-	unsigned long now;
-
-	if (!imxdma->name) {
-		printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
-		       __func__, channel);
-		return 0;
-	}
-
-	now = min(imxdma->resbytes, sg->length);
-	if (imxdma->resbytes != IMX_DMA_LENGTH_LOOP)
-		imxdma->resbytes -= now;
-
-	if ((imxdma->dma_mode & DMA_MODE_MASK) == DMA_MODE_READ)
-		imx_dmav1_writel(sg->dma_address, DMA_DAR(channel));
-	else
-		imx_dmav1_writel(sg->dma_address, DMA_SAR(channel));
-
-	imx_dmav1_writel(now, DMA_CNTR(channel));
-
-	pr_debug("imxdma%d: next sg chunk dst 0x%08x, src 0x%08x, "
-		"size 0x%08x\n", channel,
-		 imx_dmav1_readl(DMA_DAR(channel)),
-		 imx_dmav1_readl(DMA_SAR(channel)),
-		 imx_dmav1_readl(DMA_CNTR(channel)));
-
-	return now;
-}
-
-/**
- * imx_dma_setup_single - setup i.MX DMA channel for linear memory to/from
- * device transfer
- *
- * @channel: i.MX DMA channel number
- * @dma_address: the DMA/physical memory address of the linear data block
- *		to transfer
- * @dma_length: length of the data block in bytes
- * @dev_addr: physical device port address
- * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory
- *           or %DMA_MODE_WRITE from memory to the device
- *
- * Return value: if incorrect parameters are provided -%EINVAL.
- *		Zero indicates success.
- */
-int
-imx_dma_setup_single(int channel, dma_addr_t dma_address,
-		     unsigned int dma_length, unsigned int dev_addr,
-		     unsigned int dmamode)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
-
-	imxdma->sg = NULL;
-	imxdma->dma_mode = dmamode;
-
-	if (!dma_address) {
-		printk(KERN_ERR "imxdma%d: imx_dma_setup_single null address\n",
-		       channel);
-		return -EINVAL;
-	}
-
-	if (!dma_length) {
-		printk(KERN_ERR "imxdma%d: imx_dma_setup_single zero length\n",
-		       channel);
-		return -EINVAL;
-	}
-
-	if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) {
-		pr_debug("imxdma%d: %s dma_addressg=0x%08x dma_length=%d "
-			"dev_addr=0x%08x for read\n",
-			channel, __func__, (unsigned int)dma_address,
-			dma_length, dev_addr);
-
-		imx_dmav1_writel(dev_addr, DMA_SAR(channel));
-		imx_dmav1_writel(dma_address, DMA_DAR(channel));
-		imx_dmav1_writel(imxdma->ccr_from_device, DMA_CCR(channel));
-	} else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) {
-		pr_debug("imxdma%d: %s dma_addressg=0x%08x dma_length=%d "
-			"dev_addr=0x%08x for write\n",
-			channel, __func__, (unsigned int)dma_address,
-			dma_length, dev_addr);
-
-		imx_dmav1_writel(dma_address, DMA_SAR(channel));
-		imx_dmav1_writel(dev_addr, DMA_DAR(channel));
-		imx_dmav1_writel(imxdma->ccr_to_device,
-				DMA_CCR(channel));
-	} else {
-		printk(KERN_ERR "imxdma%d: imx_dma_setup_single bad dmamode\n",
-		       channel);
-		return -EINVAL;
-	}
-
-	imx_dmav1_writel(dma_length, DMA_CNTR(channel));
-
-	return 0;
-}
-EXPORT_SYMBOL(imx_dma_setup_single);
-
-/**
- * imx_dma_setup_sg - setup i.MX DMA channel SG list to/from device transfer
- * @channel: i.MX DMA channel number
- * @sg: pointer to the scatter-gather list/vector
- * @sgcount: scatter-gather list hungs count
- * @dma_length: total length of the transfer request in bytes
- * @dev_addr: physical device port address
- * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory
- *           or %DMA_MODE_WRITE from memory to the device
- *
- * The function sets up DMA channel state and registers to be ready for
- * transfer specified by provided parameters. The scatter-gather emulation
- * is set up according to the parameters.
- *
- * The full preparation of the transfer requires setup of more register
- * by the caller before imx_dma_enable() can be called.
- *
- * %BLR(channel) holds transfer burst length in bytes, 0 means 64 bytes
- *
- * %RSSR(channel) has to be set to the DMA request line source %DMA_REQ_xxx
- *
- * %CCR(channel) has to specify transfer parameters, the next settings is
- * typical for linear or simple scatter-gather transfers if %DMA_MODE_READ is
- * specified
- *
- * %CCR_DMOD_LINEAR | %CCR_DSIZ_32 | %CCR_SMOD_FIFO | %CCR_SSIZ_x
- *
- * The typical setup for %DMA_MODE_WRITE is specified by next options
- * combination
- *
- * %CCR_SMOD_LINEAR | %CCR_SSIZ_32 | %CCR_DMOD_FIFO | %CCR_DSIZ_x
- *
- * Be careful here and do not mistakenly mix source and target device
- * port sizes constants, they are really different:
- * %CCR_SSIZ_8, %CCR_SSIZ_16, %CCR_SSIZ_32,
- * %CCR_DSIZ_8, %CCR_DSIZ_16, %CCR_DSIZ_32
- *
- * Return value: if incorrect parameters are provided -%EINVAL.
- * Zero indicates success.
- */
-int
-imx_dma_setup_sg(int channel,
-		 struct scatterlist *sg, unsigned int sgcount,
-		 unsigned int dma_length, unsigned int dev_addr,
-		 unsigned int dmamode)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
-
-	if (imxdma->in_use)
-		return -EBUSY;
-
-	imxdma->sg = sg;
-	imxdma->dma_mode = dmamode;
-	imxdma->resbytes = dma_length;
-
-	if (!sg || !sgcount) {
-		printk(KERN_ERR "imxdma%d: imx_dma_setup_sg empty sg list\n",
-		       channel);
-		return -EINVAL;
-	}
-
-	if (!sg->length) {
-		printk(KERN_ERR "imxdma%d: imx_dma_setup_sg zero length\n",
-		       channel);
-		return -EINVAL;
-	}
-
-	if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) {
-		pr_debug("imxdma%d: %s sg=%p sgcount=%d total length=%d "
-			"dev_addr=0x%08x for read\n",
-			channel, __func__, sg, sgcount, dma_length, dev_addr);
-
-		imx_dmav1_writel(dev_addr, DMA_SAR(channel));
-		imx_dmav1_writel(imxdma->ccr_from_device, DMA_CCR(channel));
-	} else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) {
-		pr_debug("imxdma%d: %s sg=%p sgcount=%d total length=%d "
-			"dev_addr=0x%08x for write\n",
-			channel, __func__, sg, sgcount, dma_length, dev_addr);
-
-		imx_dmav1_writel(dev_addr, DMA_DAR(channel));
-		imx_dmav1_writel(imxdma->ccr_to_device, DMA_CCR(channel));
-	} else {
-		printk(KERN_ERR "imxdma%d: imx_dma_setup_sg bad dmamode\n",
-		       channel);
-		return -EINVAL;
-	}
-
-	imx_dma_sg_next(channel, sg);
-
-	return 0;
-}
-EXPORT_SYMBOL(imx_dma_setup_sg);
-
-int
-imx_dma_config_channel(int channel, unsigned int config_port,
-	unsigned int config_mem, unsigned int dmareq, int hw_chaining)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
-	u32 dreq = 0;
-
-	imxdma->hw_chaining = 0;
-
-	if (hw_chaining) {
-		imxdma->hw_chaining = 1;
-		if (!imx_dma_hw_chain(imxdma))
-			return -EINVAL;
-	}
-
-	if (dmareq)
-		dreq = CCR_REN;
-
-	imxdma->ccr_from_device = config_port | (config_mem << 2) | dreq;
-	imxdma->ccr_to_device = config_mem | (config_port << 2) | dreq;
-
-	imx_dmav1_writel(dmareq, DMA_RSSR(channel));
-
-	return 0;
-}
-EXPORT_SYMBOL(imx_dma_config_channel);
-
-void imx_dma_config_burstlen(int channel, unsigned int burstlen)
-{
-	imx_dmav1_writel(burstlen, DMA_BLR(channel));
-}
-EXPORT_SYMBOL(imx_dma_config_burstlen);
-
-/**
- * imx_dma_setup_handlers - setup i.MX DMA channel end and error notification
- * handlers
- * @channel: i.MX DMA channel number
- * @irq_handler: the pointer to the function called if the transfer
- *		ends successfully
- * @err_handler: the pointer to the function called if the premature
- *		end caused by error occurs
- * @data: user specified value to be passed to the handlers
- */
-int
-imx_dma_setup_handlers(int channel,
-		       void (*irq_handler) (int, void *),
-		       void (*err_handler) (int, void *, int),
-		       void *data)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
-	unsigned long flags;
-
-	if (!imxdma->name) {
-		printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
-		       __func__, channel);
-		return -ENODEV;
-	}
-
-	local_irq_save(flags);
-	imx_dmav1_writel(1 << channel, DMA_DISR);
-	imxdma->irq_handler = irq_handler;
-	imxdma->err_handler = err_handler;
-	imxdma->data = data;
-	local_irq_restore(flags);
-	return 0;
-}
-EXPORT_SYMBOL(imx_dma_setup_handlers);
-
-/**
- * imx_dma_setup_progression_handler - setup i.MX DMA channel progression
- * handlers
- * @channel: i.MX DMA channel number
- * @prog_handler: the pointer to the function called if the transfer progresses
- */
-int
-imx_dma_setup_progression_handler(int channel,
-			void (*prog_handler) (int, void*, struct scatterlist*))
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
-	unsigned long flags;
-
-	if (!imxdma->name) {
-		printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
-		       __func__, channel);
-		return -ENODEV;
-	}
-
-	local_irq_save(flags);
-	imxdma->prog_handler = prog_handler;
-	local_irq_restore(flags);
-	return 0;
-}
-EXPORT_SYMBOL(imx_dma_setup_progression_handler);
-
-/**
- * imx_dma_enable - function to start i.MX DMA channel operation
- * @channel: i.MX DMA channel number
- *
- * The channel has to be allocated by driver through imx_dma_request()
- * or imx_dma_request_by_prio() function.
- * The transfer parameters has to be set to the channel registers through
- * call of the imx_dma_setup_single() or imx_dma_setup_sg() function
- * and registers %BLR(channel), %RSSR(channel) and %CCR(channel) has to
- * be set prior this function call by the channel user.
- */
-void imx_dma_enable(int channel)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
-	unsigned long flags;
-
-	pr_debug("imxdma%d: imx_dma_enable\n", channel);
-
-	if (!imxdma->name) {
-		printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
-		       __func__, channel);
-		return;
-	}
-
-	if (imxdma->in_use)
-		return;
-
-	local_irq_save(flags);
-
-	imx_dmav1_writel(1 << channel, DMA_DISR);
-	imx_dmav1_writel(imx_dmav1_readl(DMA_DIMR) & ~(1 << channel), DMA_DIMR);
-	imx_dmav1_writel(imx_dmav1_readl(DMA_CCR(channel)) | CCR_CEN |
-		CCR_ACRPT, DMA_CCR(channel));
-
-	if ((cpu_is_mx21() || cpu_is_mx27()) &&
-			imxdma->sg && imx_dma_hw_chain(imxdma)) {
-		imxdma->sg = sg_next(imxdma->sg);
-		if (imxdma->sg) {
-			u32 tmp;
-			imx_dma_sg_next(channel, imxdma->sg);
-			tmp = imx_dmav1_readl(DMA_CCR(channel));
-			imx_dmav1_writel(tmp | CCR_RPT | CCR_ACRPT,
-				DMA_CCR(channel));
-		}
-	}
-	imxdma->in_use = 1;
-
-	local_irq_restore(flags);
-}
-EXPORT_SYMBOL(imx_dma_enable);
-
-/**
- * imx_dma_disable - stop, finish i.MX DMA channel operatin
- * @channel: i.MX DMA channel number
- */
-void imx_dma_disable(int channel)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
-	unsigned long flags;
-
-	pr_debug("imxdma%d: imx_dma_disable\n", channel);
-
-	if (imx_dma_hw_chain(imxdma))
-		del_timer(&imxdma->watchdog);
-
-	local_irq_save(flags);
-	imx_dmav1_writel(imx_dmav1_readl(DMA_DIMR) | (1 << channel), DMA_DIMR);
-	imx_dmav1_writel(imx_dmav1_readl(DMA_CCR(channel)) & ~CCR_CEN,
-			DMA_CCR(channel));
-	imx_dmav1_writel(1 << channel, DMA_DISR);
-	imxdma->in_use = 0;
-	local_irq_restore(flags);
-}
-EXPORT_SYMBOL(imx_dma_disable);
-
-static void imx_dma_watchdog(unsigned long chno)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[chno];
-
-	imx_dmav1_writel(0, DMA_CCR(chno));
-	imxdma->in_use = 0;
-	imxdma->sg = NULL;
-
-	if (imxdma->err_handler)
-		imxdma->err_handler(chno, imxdma->data, IMX_DMA_ERR_TIMEOUT);
-}
-
-static irqreturn_t dma_err_handler(int irq, void *dev_id)
-{
-	int i, disr;
-	struct imx_dma_channel *imxdma;
-	unsigned int err_mask;
-	int errcode;
-
-	disr = imx_dmav1_readl(DMA_DISR);
-
-	err_mask = imx_dmav1_readl(DMA_DBTOSR) |
-		   imx_dmav1_readl(DMA_DRTOSR) |
-		   imx_dmav1_readl(DMA_DSESR)  |
-		   imx_dmav1_readl(DMA_DBOSR);
-
-	if (!err_mask)
-		return IRQ_HANDLED;
-
-	imx_dmav1_writel(disr & err_mask, DMA_DISR);
-
-	for (i = 0; i < IMX_DMA_CHANNELS; i++) {
-		if (!(err_mask & (1 << i)))
-			continue;
-		imxdma = &imx_dma_channels[i];
-		errcode = 0;
-
-		if (imx_dmav1_readl(DMA_DBTOSR) & (1 << i)) {
-			imx_dmav1_writel(1 << i, DMA_DBTOSR);
-			errcode |= IMX_DMA_ERR_BURST;
-		}
-		if (imx_dmav1_readl(DMA_DRTOSR) & (1 << i)) {
-			imx_dmav1_writel(1 << i, DMA_DRTOSR);
-			errcode |= IMX_DMA_ERR_REQUEST;
-		}
-		if (imx_dmav1_readl(DMA_DSESR) & (1 << i)) {
-			imx_dmav1_writel(1 << i, DMA_DSESR);
-			errcode |= IMX_DMA_ERR_TRANSFER;
-		}
-		if (imx_dmav1_readl(DMA_DBOSR) & (1 << i)) {
-			imx_dmav1_writel(1 << i, DMA_DBOSR);
-			errcode |= IMX_DMA_ERR_BUFFER;
-		}
-		if (imxdma->name && imxdma->err_handler) {
-			imxdma->err_handler(i, imxdma->data, errcode);
-			continue;
-		}
-
-		imx_dma_channels[i].sg = NULL;
-
-		printk(KERN_WARNING
-		       "DMA timeout on channel %d (%s) -%s%s%s%s\n",
-		       i, imxdma->name,
-		       errcode & IMX_DMA_ERR_BURST ?    " burst" : "",
-		       errcode & IMX_DMA_ERR_REQUEST ?  " request" : "",
-		       errcode & IMX_DMA_ERR_TRANSFER ? " transfer" : "",
-		       errcode & IMX_DMA_ERR_BUFFER ?   " buffer" : "");
-	}
-	return IRQ_HANDLED;
-}
-
-static void dma_irq_handle_channel(int chno)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[chno];
-
-	if (!imxdma->name) {
-		/*
-		 * IRQ for an unregistered DMA channel:
-		 * let's clear the interrupts and disable it.
-		 */
-		printk(KERN_WARNING
-		       "spurious IRQ for DMA channel %d\n", chno);
-		return;
-	}
-
-	if (imxdma->sg) {
-		u32 tmp;
-		struct scatterlist *current_sg = imxdma->sg;
-		imxdma->sg = sg_next(imxdma->sg);
-
-		if (imxdma->sg) {
-			imx_dma_sg_next(chno, imxdma->sg);
-
-			tmp = imx_dmav1_readl(DMA_CCR(chno));
-
-			if (imx_dma_hw_chain(imxdma)) {
-				/* FIXME: The timeout should probably be
-				 * configurable
-				 */
-				mod_timer(&imxdma->watchdog,
-					jiffies + msecs_to_jiffies(500));
-
-				tmp |= CCR_CEN | CCR_RPT | CCR_ACRPT;
-				imx_dmav1_writel(tmp, DMA_CCR(chno));
-			} else {
-				imx_dmav1_writel(tmp & ~CCR_CEN, DMA_CCR(chno));
-				tmp |= CCR_CEN;
-			}
-
-			imx_dmav1_writel(tmp, DMA_CCR(chno));
-
-			if (imxdma->prog_handler)
-				imxdma->prog_handler(chno, imxdma->data,
-						current_sg);
-
-			return;
-		}
-
-		if (imx_dma_hw_chain(imxdma)) {
-			del_timer(&imxdma->watchdog);
-			return;
-		}
-	}
-
-	imx_dmav1_writel(0, DMA_CCR(chno));
-	imxdma->in_use = 0;
-	if (imxdma->irq_handler)
-		imxdma->irq_handler(chno, imxdma->data);
-}
-
-static irqreturn_t dma_irq_handler(int irq, void *dev_id)
-{
-	int i, disr;
-
-	if (cpu_is_mx21() || cpu_is_mx27())
-		dma_err_handler(irq, dev_id);
-
-	disr = imx_dmav1_readl(DMA_DISR);
-
-	pr_debug("imxdma: dma_irq_handler called, disr=0x%08x\n",
-		     disr);
-
-	imx_dmav1_writel(disr, DMA_DISR);
-	for (i = 0; i < IMX_DMA_CHANNELS; i++) {
-		if (disr & (1 << i))
-			dma_irq_handle_channel(i);
-	}
-
-	return IRQ_HANDLED;
-}
-
-/**
- * imx_dma_request - request/allocate specified channel number
- * @channel: i.MX DMA channel number
- * @name: the driver/caller own non-%NULL identification
- */
-int imx_dma_request(int channel, const char *name)
-{
-	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
-	unsigned long flags;
-	int ret = 0;
-
-	/* basic sanity checks */
-	if (!name)
-		return -EINVAL;
-
-	if (channel >= IMX_DMA_CHANNELS) {
-		printk(KERN_CRIT "%s: called for  non-existed channel %d\n",
-		       __func__, channel);
-		return -EINVAL;
-	}
-
-	local_irq_save(flags);
-	if (imxdma->name) {
-		local_irq_restore(flags);
-		return -EBUSY;
-	}
-	memset(imxdma, 0, sizeof(*imxdma));
-	imxdma->name = name;
-	local_irq_restore(flags); /* request_irq() can block */
-
-	if (cpu_is_mx21() || cpu_is_mx27()) {
-		ret = request_irq(MX2x_INT_DMACH0 + channel,
-				dma_irq_handler, 0, "DMA", NULL);
-		if (ret) {
-			imxdma->name = NULL;
-			pr_crit("Can't register IRQ %d for DMA channel %d\n",
-					MX2x_INT_DMACH0 + channel, channel);
-			return ret;
-		}
-		init_timer(&imxdma->watchdog);
-		imxdma->watchdog.function = &imx_dma_watchdog;
-		imxdma->watchdog.data = channel;
-	}
-
-	return ret;
-}
-EXPORT_SYMBOL(imx_dma_request);
-
-/**
- * imx_dma_free - release previously acquired channel
- * @channel: i.MX DMA channel number
- */
-void imx_dma_free(int channel)
-{
-	unsigned long flags;
-	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
-
-	if (!imxdma->name) {
-		printk(KERN_CRIT
-		       "%s: trying to free free channel %d\n",
-		       __func__, channel);
-		return;
-	}
-
-	local_irq_save(flags);
-	/* Disable interrupts */
-	imx_dma_disable(channel);
-	imxdma->name = NULL;
-
-	if (cpu_is_mx21() || cpu_is_mx27())
-		free_irq(MX2x_INT_DMACH0 + channel, NULL);
-
-	local_irq_restore(flags);
-}
-EXPORT_SYMBOL(imx_dma_free);
-
-/**
- * imx_dma_request_by_prio - find and request some of free channels best
- * suiting requested priority
- * @channel: i.MX DMA channel number
- * @name: the driver/caller own non-%NULL identification
- *
- * This function tries to find a free channel in the specified priority group
- * if the priority cannot be achieved it tries to look for free channel
- * in the higher and then even lower priority groups.
- *
- * Return value: If there is no free channel to allocate, -%ENODEV is returned.
- *               On successful allocation channel is returned.
- */
-int imx_dma_request_by_prio(const char *name, enum imx_dma_prio prio)
-{
-	int i;
-	int best;
-
-	switch (prio) {
-	case (DMA_PRIO_HIGH):
-		best = 8;
-		break;
-	case (DMA_PRIO_MEDIUM):
-		best = 4;
-		break;
-	case (DMA_PRIO_LOW):
-	default:
-		best = 0;
-		break;
-	}
-
-	for (i = best; i < IMX_DMA_CHANNELS; i++)
-		if (!imx_dma_request(i, name))
-			return i;
-
-	for (i = best - 1; i >= 0; i--)
-		if (!imx_dma_request(i, name))
-			return i;
-
-	printk(KERN_ERR "%s: no free DMA channel found\n", __func__);
-
-	return -ENODEV;
-}
-EXPORT_SYMBOL(imx_dma_request_by_prio);
-
-static int __init imx_dma_init(void)
-{
-	int ret = 0;
-	int i;
-
-	if (cpu_is_mx1())
-		imx_dmav1_baseaddr = MX1_IO_ADDRESS(MX1_DMA_BASE_ADDR);
-	else if (cpu_is_mx21())
-		imx_dmav1_baseaddr = MX21_IO_ADDRESS(MX21_DMA_BASE_ADDR);
-	else if (cpu_is_mx27())
-		imx_dmav1_baseaddr = MX27_IO_ADDRESS(MX27_DMA_BASE_ADDR);
-	else
-		return 0;
-
-	dma_clk = clk_get(NULL, "dma");
-	if (IS_ERR(dma_clk))
-		return PTR_ERR(dma_clk);
-	clk_enable(dma_clk);
-
-	/* reset DMA module */
-	imx_dmav1_writel(DCR_DRST, DMA_DCR);
-
-	if (cpu_is_mx1()) {
-		ret = request_irq(MX1_DMA_INT, dma_irq_handler, 0, "DMA", NULL);
-		if (ret) {
-			pr_crit("Wow!  Can't register IRQ for DMA\n");
-			return ret;
-		}
-
-		ret = request_irq(MX1_DMA_ERR, dma_err_handler, 0, "DMA", NULL);
-		if (ret) {
-			pr_crit("Wow!  Can't register ERRIRQ for DMA\n");
-			free_irq(MX1_DMA_INT, NULL);
-			return ret;
-		}
-	}
-
-	/* enable DMA module */
-	imx_dmav1_writel(DCR_DEN, DMA_DCR);
-
-	/* clear all interrupts */
-	imx_dmav1_writel((1 << IMX_DMA_CHANNELS) - 1, DMA_DISR);
-
-	/* disable interrupts */
-	imx_dmav1_writel((1 << IMX_DMA_CHANNELS) - 1, DMA_DIMR);
-
-	for (i = 0; i < IMX_DMA_CHANNELS; i++) {
-		imx_dma_channels[i].sg = NULL;
-		imx_dma_channels[i].dma_num = i;
-	}
-
-	return ret;
-}
-
-arch_initcall(imx_dma_init);
diff --git a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
index 5db3e14..5f2f91d 100644
--- a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
@@ -32,7 +32,6 @@
 #include <mach/common.h>
 #include <mach/iomux-mx27.h>
 #include <mach/hardware.h>
-#include <mach/audmux.h>
 
 #include "devices-imx27.h"
 
@@ -306,25 +305,6 @@
 	mxc_gpio_setup_multiple_pins(eukrea_mbimx27_pins,
 		ARRAY_SIZE(eukrea_mbimx27_pins), "MBIMX27");
 
-#if defined(CONFIG_SND_SOC_EUKREA_TLV320) \
-	|| defined(CONFIG_SND_SOC_EUKREA_TLV320_MODULE)
-	/* SSI unit master I2S codec connected to SSI_PINS_4*/
-	mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
-			MXC_AUDMUX_V1_PCR_SYN |
-			MXC_AUDMUX_V1_PCR_TFSDIR |
-			MXC_AUDMUX_V1_PCR_TCLKDIR |
-			MXC_AUDMUX_V1_PCR_RFSDIR |
-			MXC_AUDMUX_V1_PCR_RCLKDIR |
-			MXC_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
-			MXC_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
-			MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4)
-	);
-	mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4,
-			MXC_AUDMUX_V1_PCR_SYN |
-			MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
-	);
-#endif
-
 	imx27_add_imx_uart1(&uart_pdata);
 	imx27_add_imx_uart2(&uart_pdata);
 #if !defined(MACH_EUKREA_CPUIMX27_USEUART4)
diff --git a/arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c
index d817fc8..aaa592fd 100644
--- a/arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c
@@ -37,7 +37,6 @@
 #include <mach/hardware.h>
 #include <mach/common.h>
 #include <mach/iomux-mx51.h>
-#include <mach/audmux.h>
 
 #include "devices-imx51.h"
 
diff --git a/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
index 66e8726..2cf603e 100644
--- a/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
@@ -31,7 +31,6 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/mx25.h>
-#include <mach/audmux.h>
 
 #include "devices-imx25.h"
 
@@ -241,22 +240,6 @@
 			ARRAY_SIZE(eukrea_mbimxsd_pads)))
 		printk(KERN_ERR "error setting mbimxsd pads !\n");
 
-#if defined(CONFIG_SND_SOC_EUKREA_TLV320)
-	/* SSI unit master I2S codec connected to SSI_AUD5*/
-	mxc_audmux_v2_configure_port(0,
-			MXC_AUDMUX_V2_PTCR_SYN |
-			MXC_AUDMUX_V2_PTCR_TFSDIR |
-			MXC_AUDMUX_V2_PTCR_TFSEL(4) |
-			MXC_AUDMUX_V2_PTCR_TCLKDIR |
-			MXC_AUDMUX_V2_PTCR_TCSEL(4),
-			MXC_AUDMUX_V2_PDCR_RXDSEL(4)
-	);
-	mxc_audmux_v2_configure_port(4,
-			MXC_AUDMUX_V2_PTCR_SYN,
-			MXC_AUDMUX_V2_PDCR_RXDSEL(0)
-	);
-#endif
-
 	imx25_add_imx_uart1(&uart_pdata);
 	imx25_add_imx_fb(&eukrea_mximxsd_fb_pdata);
 	imx25_add_imx_ssi(0, &eukrea_mbimxsd_ssi_pdata);
diff --git a/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
index 0f0af02..fd8bf8a 100644
--- a/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
@@ -38,7 +38,6 @@
 #include <mach/hardware.h>
 #include <mach/common.h>
 #include <mach/iomux-mx35.h>
-#include <mach/audmux.h>
 
 #include "devices-imx35.h"
 
@@ -252,22 +251,6 @@
 			ARRAY_SIZE(eukrea_mbimxsd_pads)))
 		printk(KERN_ERR "error setting mbimxsd pads !\n");
 
-#if defined(CONFIG_SND_SOC_EUKREA_TLV320)
-	/* SSI unit master I2S codec connected to SSI_AUD4 */
-	mxc_audmux_v2_configure_port(0,
-			MXC_AUDMUX_V2_PTCR_SYN |
-			MXC_AUDMUX_V2_PTCR_TFSDIR |
-			MXC_AUDMUX_V2_PTCR_TFSEL(3) |
-			MXC_AUDMUX_V2_PTCR_TCLKDIR |
-			MXC_AUDMUX_V2_PTCR_TCSEL(3),
-			MXC_AUDMUX_V2_PDCR_RXDSEL(3)
-	);
-	mxc_audmux_v2_configure_port(3,
-			MXC_AUDMUX_V2_PTCR_SYN,
-			MXC_AUDMUX_V2_PDCR_RXDSEL(0)
-	);
-#endif
-
 	imx35_add_imx_uart1(&uart_pdata);
 	imx35_add_ipu_core(&mx3_ipu_data);
 	imx35_add_mx3_sdc_fb(&mx3fb_pdata);
diff --git a/arch/arm/mach-imx/imx27-dt.c b/arch/arm/mach-imx/imx27-dt.c
new file mode 100644
index 0000000..861ceb8
--- /dev/null
+++ b/arch/arm/mach-imx/imx27-dt.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2012 Sascha Hauer, Pengutronix
+ *
+ * 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/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/common.h>
+#include <mach/mx27.h>
+
+static const struct of_dev_auxdata imx27_auxdata_lookup[] __initconst = {
+	OF_DEV_AUXDATA("fsl,imx27-uart", MX27_UART1_BASE_ADDR, "imx21-uart.0", NULL),
+	OF_DEV_AUXDATA("fsl,imx27-uart", MX27_UART2_BASE_ADDR, "imx21-uart.1", NULL),
+	OF_DEV_AUXDATA("fsl,imx27-uart", MX27_UART3_BASE_ADDR, "imx21-uart.2", NULL),
+	OF_DEV_AUXDATA("fsl,imx27-fec", MX27_FEC_BASE_ADDR, "imx27-fec.0", NULL),
+	OF_DEV_AUXDATA("fsl,imx27-i2c", MX27_I2C1_BASE_ADDR, "imx-i2c.0", NULL),
+	OF_DEV_AUXDATA("fsl,imx27-i2c", MX27_I2C2_BASE_ADDR, "imx-i2c.1", NULL),
+	OF_DEV_AUXDATA("fsl,imx27-cspi", MX27_CSPI1_BASE_ADDR, "imx27-cspi.0", NULL),
+	OF_DEV_AUXDATA("fsl,imx27-cspi", MX27_CSPI2_BASE_ADDR, "imx27-cspi.1", NULL),
+	OF_DEV_AUXDATA("fsl,imx27-cspi", MX27_CSPI3_BASE_ADDR, "imx27-cspi.2", NULL),
+	OF_DEV_AUXDATA("fsl,imx27-wdt", MX27_WDOG_BASE_ADDR, "imx2-wdt.0", NULL),
+	{ /* sentinel */ }
+};
+
+static int __init imx27_avic_add_irq_domain(struct device_node *np,
+				struct device_node *interrupt_parent)
+{
+	irq_domain_add_simple(np, 0);
+	return 0;
+}
+
+static int __init imx27_gpio_add_irq_domain(struct device_node *np,
+				struct device_node *interrupt_parent)
+{
+	static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS;
+
+	irq_domain_add_simple(np, gpio_irq_base);
+
+	return 0;
+}
+
+static const struct of_device_id imx27_irq_match[] __initconst = {
+	{ .compatible = "fsl,imx27-avic", .data = imx27_avic_add_irq_domain, },
+	{ .compatible = "fsl,imx27-gpio", .data = imx27_gpio_add_irq_domain, },
+	{ /* sentinel */ }
+};
+
+static void __init imx27_dt_init(void)
+{
+	of_irq_init(imx27_irq_match);
+
+	of_platform_populate(NULL, of_default_bus_match_table,
+			     imx27_auxdata_lookup, NULL);
+}
+
+static void __init imx27_timer_init(void)
+{
+	mx27_clocks_init_dt();
+}
+
+static struct sys_timer imx27_timer = {
+	.init = imx27_timer_init,
+};
+
+static const char *imx27_dt_board_compat[] __initdata = {
+	"fsl,imx27",
+	NULL
+};
+
+DT_MACHINE_START(IMX27_DT, "Freescale i.MX27 (Device Tree Support)")
+	.map_io		= mx27_map_io,
+	.init_early	= imx27_init_early,
+	.init_irq	= mx27_init_irq,
+	.handle_irq	= imx27_handle_irq,
+	.timer		= &imx27_timer,
+	.init_machine	= imx27_dt_init,
+	.dt_compat	= imx27_dt_board_compat,
+	.restart	= mxc_restart,
+MACHINE_END
diff --git a/arch/arm/mach-imx/imx51-dt.c b/arch/arm/mach-imx/imx51-dt.c
index 1e03ef4..5cca573 100644
--- a/arch/arm/mach-imx/imx51-dt.c
+++ b/arch/arm/mach-imx/imx51-dt.c
@@ -104,6 +104,7 @@
 
 static const char *imx51_dt_board_compat[] __initdata = {
 	"fsl,imx51-babbage",
+	"fsl,imx51",
 	NULL
 };
 
diff --git a/arch/arm/mach-imx/imx53-dt.c b/arch/arm/mach-imx/imx53-dt.c
index fd5be0f2..4172279 100644
--- a/arch/arm/mach-imx/imx53-dt.c
+++ b/arch/arm/mach-imx/imx53-dt.c
@@ -114,6 +114,7 @@
 	"fsl,imx53-evk",
 	"fsl,imx53-qsb",
 	"fsl,imx53-smd",
+	"fsl,imx53",
 	NULL
 };
 
diff --git a/arch/arm/mach-imx/include/mach/dma-v1.h b/arch/arm/mach-imx/include/mach/dma-v1.h
deleted file mode 100644
index ac6fd71..0000000
--- a/arch/arm/mach-imx/include/mach/dma-v1.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- *  linux/arch/arm/mach-imx/include/mach/dma-v1.h
- *
- *  i.MX DMA registration and IRQ dispatching
- *
- * Copyright 2006 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- * Copyright 2008 Juergen Beisert, <kernel@pengutronix.de>
- * Copyright 2008 Sascha Hauer, <s.hauer@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-#ifndef __MACH_DMA_V1_H__
-#define __MACH_DMA_V1_H__
-
-#define imx_has_dma_v1()	(cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27())
-
-#include <mach/dma.h>
-
-#define IMX_DMA_CHANNELS  16
-
-#define DMA_MODE_READ		0
-#define DMA_MODE_WRITE		1
-#define DMA_MODE_MASK		1
-
-#define MX1_DMA_REG(offset)	MX1_IO_ADDRESS(MX1_DMA_BASE_ADDR + (offset))
-
-/* DMA Interrupt Mask Register */
-#define MX1_DMA_DIMR		MX1_DMA_REG(0x08)
-
-/* Channel Control Register */
-#define MX1_DMA_CCR(x)		MX1_DMA_REG(0x8c + ((x) << 6))
-
-#define IMX_DMA_MEMSIZE_32	(0 << 4)
-#define IMX_DMA_MEMSIZE_8	(1 << 4)
-#define IMX_DMA_MEMSIZE_16	(2 << 4)
-#define IMX_DMA_TYPE_LINEAR	(0 << 10)
-#define IMX_DMA_TYPE_2D		(1 << 10)
-#define IMX_DMA_TYPE_FIFO	(2 << 10)
-
-#define IMX_DMA_ERR_BURST     (1 << 0)
-#define IMX_DMA_ERR_REQUEST   (1 << 1)
-#define IMX_DMA_ERR_TRANSFER  (1 << 2)
-#define IMX_DMA_ERR_BUFFER    (1 << 3)
-#define IMX_DMA_ERR_TIMEOUT   (1 << 4)
-
-int
-imx_dma_config_channel(int channel, unsigned int config_port,
-	unsigned int config_mem, unsigned int dmareq, int hw_chaining);
-
-void
-imx_dma_config_burstlen(int channel, unsigned int burstlen);
-
-int
-imx_dma_setup_single(int channel, dma_addr_t dma_address,
-		unsigned int dma_length, unsigned int dev_addr,
-		unsigned int dmamode);
-
-
-/*
- * Use this flag as the dma_length argument to imx_dma_setup_sg()
- * to create an endless running dma loop. The end of the scatterlist
- * must be linked to the beginning for this to work.
- */
-#define IMX_DMA_LENGTH_LOOP	((unsigned int)-1)
-
-int
-imx_dma_setup_sg(int channel, struct scatterlist *sg,
-		unsigned int sgcount, unsigned int dma_length,
-		unsigned int dev_addr, unsigned int dmamode);
-
-int
-imx_dma_setup_handlers(int channel,
-		void (*irq_handler) (int, void *),
-		void (*err_handler) (int, void *, int), void *data);
-
-int
-imx_dma_setup_progression_handler(int channel,
-		void (*prog_handler) (int, void*, struct scatterlist*));
-
-void imx_dma_enable(int channel);
-
-void imx_dma_disable(int channel);
-
-int imx_dma_request(int channel, const char *name);
-
-void imx_dma_free(int channel);
-
-int imx_dma_request_by_prio(const char *name, enum imx_dma_prio prio);
-
-#endif	/* __MACH_DMA_V1_H__ */
diff --git a/arch/arm/mach-imx/lluart.c b/arch/arm/mach-imx/lluart.c
index d4ab6f2..0213f8d 100644
--- a/arch/arm/mach-imx/lluart.c
+++ b/arch/arm/mach-imx/lluart.c
@@ -17,7 +17,7 @@
 #include <mach/hardware.h>
 
 static struct map_desc imx_lluart_desc = {
-#ifdef CONFIG_DEBUG_IMX6Q_UART
+#ifdef CONFIG_DEBUG_IMX6Q_UART4
 	.virtual	= MX6Q_IO_P2V(MX6Q_UART4_BASE_ADDR),
 	.pfn		= __phys_to_pfn(MX6Q_UART4_BASE_ADDR),
 	.length		= MX6Q_UART4_SIZE,
diff --git a/arch/arm/mach-imx/localtimer.c b/arch/arm/mach-imx/localtimer.c
deleted file mode 100644
index 3a16351..0000000
--- a/arch/arm/mach-imx/localtimer.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2011 Freescale Semiconductor, Inc.
- * Copyright 2011 Linaro Ltd.
- *
- * 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/init.h>
-#include <linux/clockchips.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <asm/smp_twd.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	struct device_node *np;
-
-	np = of_find_compatible_node(NULL, NULL, "arm,smp-twd");
-	if (!twd_base) {
-		twd_base = of_iomap(np, 0);
-		WARN_ON(!twd_base);
-	}
-	evt->irq = irq_of_parse_and_map(np, 0);
-	twd_timer_setup(evt);
-
-	return 0;
-}
diff --git a/arch/arm/mach-imx/mach-armadillo5x0.c b/arch/arm/mach-imx/mach-armadillo5x0.c
index e4f426a..c650145 100644
--- a/arch/arm/mach-imx/mach-armadillo5x0.c
+++ b/arch/arm/mach-imx/mach-armadillo5x0.c
@@ -38,6 +38,8 @@
 #include <linux/usb/otg.h>
 #include <linux/usb/ulpi.h>
 #include <linux/delay.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -51,7 +53,7 @@
 #include <mach/ulpi.h>
 
 #include "devices-imx31.h"
-#include "crmregs-imx31.h"
+#include "crmregs-imx3.h"
 
 static int armadillo5x0_pins[] = {
 	/* UART1 */
@@ -479,6 +481,11 @@
 	&armadillo5x0_smc911x_device,
 };
 
+static struct regulator_consumer_supply dummy_supplies[] = {
+	REGULATOR_SUPPLY("vdd33a", "smsc911x"),
+	REGULATOR_SUPPLY("vddvario", "smsc911x"),
+};
+
 /*
  * Perform board specific initializations
  */
@@ -489,6 +496,8 @@
 	mxc_iomux_setup_multiple_pins(armadillo5x0_pins,
 			ARRAY_SIZE(armadillo5x0_pins), "armadillo5x0");
 
+	regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
+
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 	imx_add_gpio_keys(&armadillo5x0_button_data);
 	imx31_add_imx_i2c1(NULL);
diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
index c2766ae..f7b074f 100644
--- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
+++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
@@ -30,6 +30,10 @@
 #include <linux/input.h>
 #include <linux/gpio.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/leds.h>
+#include <linux/memblock.h>
+#include <media/soc_camera.h>
 #include <sound/tlv320aic32x4.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -39,6 +43,8 @@
 
 #include "devices-imx27.h"
 
+#define TVP5150_RSTN (GPIO_PORTC + 18)
+#define TVP5150_PWDN (GPIO_PORTC + 19)
 #define OTG_PHY_CS_GPIO (GPIO_PORTF + 17)
 #define SDHC1_IRQ IRQ_GPIOB(25)
 
@@ -100,8 +106,99 @@
 	PE1_PF_USBOTG_STP,
 	PB23_PF_USB_PWR,
 	PB24_PF_USB_OC,
+	/* CSI */
+	PB10_PF_CSI_D0,
+	PB11_PF_CSI_D1,
+	PB12_PF_CSI_D2,
+	PB13_PF_CSI_D3,
+	PB14_PF_CSI_D4,
+	PB15_PF_CSI_MCLK,
+	PB16_PF_CSI_PIXCLK,
+	PB17_PF_CSI_D5,
+	PB18_PF_CSI_D6,
+	PB19_PF_CSI_D7,
+	PB20_PF_CSI_VSYNC,
+	PB21_PF_CSI_HSYNC,
 };
 
+/* Camera */
+static int visstrim_camera_power(struct device *dev, int on)
+{
+	gpio_set_value(TVP5150_PWDN, on);
+
+	return 0;
+};
+
+static int visstrim_camera_reset(struct device *dev)
+{
+	gpio_set_value(TVP5150_RSTN, 0);
+	ndelay(500);
+	gpio_set_value(TVP5150_RSTN, 1);
+
+	return 0;
+};
+
+static struct i2c_board_info visstrim_i2c_camera =  {
+	I2C_BOARD_INFO("tvp5150", 0x5d),
+};
+
+static struct soc_camera_link iclink_tvp5150 = {
+	.bus_id         = 0,
+	.board_info     = &visstrim_i2c_camera,
+	.i2c_adapter_id = 0,
+	.power = visstrim_camera_power,
+	.reset = visstrim_camera_reset,
+};
+
+static struct mx2_camera_platform_data visstrim_camera = {
+	.flags = MX2_CAMERA_CCIR | MX2_CAMERA_CCIR_INTERLACE |
+			MX2_CAMERA_SWAP16 | MX2_CAMERA_PCLK_SAMPLE_RISING,
+	.clk = 100000,
+};
+
+static phys_addr_t mx2_camera_base __initdata;
+#define MX2_CAMERA_BUF_SIZE SZ_8M
+
+static void __init visstrim_camera_init(void)
+{
+	struct platform_device *pdev;
+	int dma;
+
+	/* Initialize tvp5150 gpios */
+	mxc_gpio_mode(TVP5150_RSTN | GPIO_GPIO | GPIO_OUT);
+	mxc_gpio_mode(TVP5150_PWDN | GPIO_GPIO | GPIO_OUT);
+	gpio_set_value(TVP5150_RSTN, 1);
+	gpio_set_value(TVP5150_PWDN, 0);
+	ndelay(1);
+
+	gpio_set_value(TVP5150_PWDN, 1);
+	ndelay(1);
+	gpio_set_value(TVP5150_RSTN, 0);
+	ndelay(500);
+	gpio_set_value(TVP5150_RSTN, 1);
+	ndelay(200000);
+
+	pdev = imx27_add_mx2_camera(&visstrim_camera);
+	if (IS_ERR(pdev))
+		return;
+
+	dma = dma_declare_coherent_memory(&pdev->dev,
+				mx2_camera_base, mx2_camera_base,
+				MX2_CAMERA_BUF_SIZE,
+				DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+	if (!(dma & DMA_MEMORY_MAP))
+		return;
+}
+
+static void __init visstrim_reserve(void)
+{
+	/* reserve 4 MiB for mx2-camera */
+	mx2_camera_base = memblock_alloc(MX2_CAMERA_BUF_SIZE,
+			MX2_CAMERA_BUF_SIZE);
+	memblock_free(mx2_camera_base, MX2_CAMERA_BUF_SIZE);
+	memblock_remove(mx2_camera_base, MX2_CAMERA_BUF_SIZE);
+}
+
 /* GPIOs used as events for applications */
 static struct gpio_keys_button visstrim_gpio_keys[] = {
 	{
@@ -136,6 +233,35 @@
 	.nbuttons	= ARRAY_SIZE(visstrim_gpio_keys),
 };
 
+/* led */
+static const struct gpio_led visstrim_m10_leds[] __initconst = {
+	{
+		.name = "visstrim:ld0",
+		.default_trigger = "nand-disk",
+		.gpio = (GPIO_PORTC + 29),
+	},
+	{
+		.name = "visstrim:ld1",
+		.default_trigger = "nand-disk",
+		.gpio = (GPIO_PORTC + 24),
+	},
+	{
+		.name = "visstrim:ld2",
+		.default_trigger = "nand-disk",
+		.gpio = (GPIO_PORTC + 28),
+	},
+	{
+		.name = "visstrim:ld3",
+		.default_trigger = "nand-disk",
+		.gpio = (GPIO_PORTC + 25),
+	},
+};
+
+static const struct gpio_led_platform_data visstrim_m10_led_data __initconst = {
+	.leds = visstrim_m10_leds,
+	.num_leds = ARRAY_SIZE(visstrim_m10_leds),
+};
+
 /* Visstrim_SM10 has a microSD slot connected to sdhc1 */
 static int visstrim_m10_sdhc1_init(struct device *dev,
 		irq_handler_t detect_irq, void *data)
@@ -216,6 +342,9 @@
 	{
 		I2C_BOARD_INFO("tlv320aic32x4", 0x18),
 		.platform_data = &visstrim_m10_aic32x4_pdata,
+	},
+	{
+		 I2C_BOARD_INFO("m41t00", 0x68),
 	}
 };
 
@@ -254,15 +383,21 @@
 	imx27_add_imx_ssi(0, &visstrim_m10_ssi_pdata);
 	imx27_add_imx_uart0(&uart_pdata);
 
-	i2c_register_board_info(0, visstrim_m10_i2c_devices,
-				ARRAY_SIZE(visstrim_m10_i2c_devices));
 	imx27_add_imx_i2c(0, &visstrim_m10_i2c_data);
 	imx27_add_imx_i2c(1, &visstrim_m10_i2c_data);
+	i2c_register_board_info(0, visstrim_m10_i2c_devices,
+				ARRAY_SIZE(visstrim_m10_i2c_devices));
+
 	imx27_add_mxc_mmc(0, &visstrim_m10_sdhc_pdata);
 	imx27_add_mxc_ehci_otg(&visstrim_m10_usbotg_pdata);
 	imx27_add_fec(NULL);
 	imx_add_gpio_keys(&visstrim_gpio_keys_platform_data);
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+	imx_add_platform_device("mx27vis", 0, NULL, 0, NULL, 0);
+	platform_device_register_resndata(NULL, "soc-camera-pdrv", 0, NULL, 0,
+				      &iclink_tvp5150, sizeof(iclink_tvp5150));
+	gpio_led_register_device(0, &visstrim_m10_led_data);
+	visstrim_camera_init();
 }
 
 static void __init visstrim_m10_timer_init(void)
@@ -276,6 +411,7 @@
 
 MACHINE_START(IMX27_VISSTRIM_M10, "Vista Silicon Visstrim_M10")
 	.atag_offset = 0x100,
+	.reserve = visstrim_reserve,
 	.map_io = mx27_map_io,
 	.init_early = imx27_init_early,
 	.init_irq = mx27_init_irq,
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 6075d4d..da6c1d9 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -21,10 +21,12 @@
 #include <linux/of_platform.h>
 #include <linux/phy.h>
 #include <linux/micrel_phy.h>
+#include <asm/smp_twd.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
+#include <asm/system_misc.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
 
@@ -120,6 +122,7 @@
 static void __init imx6q_timer_init(void)
 {
 	mx6q_clocks_init();
+	twd_local_timer_of_register();
 }
 
 static struct sys_timer imx6q_timer = {
@@ -129,6 +132,7 @@
 static const char *imx6q_dt_compat[] __initdata = {
 	"fsl,imx6q-arm2",
 	"fsl,imx6q-sabrelite",
+	"fsl,imx6q",
 	NULL,
 };
 
diff --git a/arch/arm/mach-imx/mach-kzm_arm11_01.c b/arch/arm/mach-imx/mach-kzm_arm11_01.c
index fc78e80..15a26e9 100644
--- a/arch/arm/mach-imx/mach-kzm_arm11_01.c
+++ b/arch/arm/mach-imx/mach-kzm_arm11_01.c
@@ -24,6 +24,8 @@
 #include <linux/serial_8250.h>
 #include <linux/smsc911x.h>
 #include <linux/types.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
 
 #include <asm/irq.h>
 #include <asm/mach-types.h>
@@ -166,6 +168,11 @@
 			  },
 };
 
+static struct regulator_consumer_supply dummy_supplies[] = {
+	REGULATOR_SUPPLY("vdd33a", "smsc911x"),
+	REGULATOR_SUPPLY("vddvario", "smsc911x"),
+};
+
 static int __init kzm_init_smsc9118(void)
 {
 	/*
@@ -175,6 +182,8 @@
 	gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO1_2), "smsc9118-int");
 	gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO1_2));
 
+	regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
+
 	return platform_device_register(&kzm_smsc9118_device);
 }
 #else
diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c
index 8d9f955..e432d4a 100644
--- a/arch/arm/mach-imx/mach-mx21ads.c
+++ b/arch/arm/mach-imx/mach-mx21ads.c
@@ -37,8 +37,8 @@
 #define MX21ADS_REG_ADDR(offset)    (void __force __iomem *) \
 		(MX21ADS_MMIO_BASE_ADDR + (offset))
 
+#define MX21ADS_CS8900A_MMIO_SIZE   0x200000
 #define MX21ADS_CS8900A_IRQ         IRQ_GPIOE(11)
-#define MX21ADS_CS8900A_IOBASE_REG  MX21ADS_REG_ADDR(0x000000)
 #define MX21ADS_ST16C255_IOBASE_REG MX21ADS_REG_ADDR(0x200000)
 #define MX21ADS_VERSION_REG         MX21ADS_REG_ADDR(0x400000)
 #define MX21ADS_IO_REG              MX21ADS_REG_ADDR(0x800000)
@@ -159,6 +159,18 @@
 	.resource = &mx21ads_flash_resource,
 };
 
+static const struct resource mx21ads_cs8900_resources[] __initconst = {
+	DEFINE_RES_MEM(MX21_CS1_BASE_ADDR, MX21ADS_CS8900A_MMIO_SIZE),
+	DEFINE_RES_IRQ(MX21ADS_CS8900A_IRQ),
+};
+
+static const struct platform_device_info mx21ads_cs8900_devinfo __initconst = {
+	.name = "cs89x0",
+	.id = 0,
+	.res = mx21ads_cs8900_resources,
+	.num_res = ARRAY_SIZE(mx21ads_cs8900_resources),
+};
+
 static const struct imxuart_platform_data uart_pdata_rts __initconst = {
 	.flags = IMXUART_HAVE_RTSCTS,
 };
@@ -292,6 +304,8 @@
 	imx21_add_mxc_nand(&mx21ads_nand_board_info);
 
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+	platform_device_register_full(
+			(struct platform_device_info *)&mx21ads_cs8900_devinfo);
 }
 
 static void __init mx21ads_timer_init(void)
diff --git a/arch/arm/mach-imx/mach-mx27_3ds.c b/arch/arm/mach-imx/mach-mx27_3ds.c
index 18f3581..c6d385c 100644
--- a/arch/arm/mach-imx/mach-mx27_3ds.c
+++ b/arch/arm/mach-imx/mach-mx27_3ds.c
@@ -31,6 +31,8 @@
 #include <linux/regulator/machine.h>
 #include <linux/spi/l4f00242t03.h>
 
+#include <media/soc_camera.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
@@ -52,6 +54,8 @@
 #define SD1_CD			IMX_GPIO_NR(2, 26)
 #define LCD_RESET		IMX_GPIO_NR(1, 3)
 #define LCD_ENABLE		IMX_GPIO_NR(1, 31)
+#define CSI_PWRDWN		IMX_GPIO_NR(4, 19)
+#define CSI_RESET		IMX_GPIO_NR(3, 6)
 
 static const int mx27pdk_pins[] __initconst = {
 	/* UART1 */
@@ -141,6 +145,26 @@
 	PA30_PF_CONTRAST,
 	LCD_ENABLE | GPIO_GPIO | GPIO_OUT,
 	LCD_RESET | GPIO_GPIO | GPIO_OUT,
+	/* CSI */
+	PB10_PF_CSI_D0,
+	PB11_PF_CSI_D1,
+	PB12_PF_CSI_D2,
+	PB13_PF_CSI_D3,
+	PB14_PF_CSI_D4,
+	PB15_PF_CSI_MCLK,
+	PB16_PF_CSI_PIXCLK,
+	PB17_PF_CSI_D5,
+	PB18_PF_CSI_D6,
+	PB19_PF_CSI_D7,
+	PB20_PF_CSI_VSYNC,
+	PB21_PF_CSI_HSYNC,
+	CSI_PWRDWN | GPIO_GPIO | GPIO_OUT,
+	CSI_RESET | GPIO_GPIO | GPIO_OUT,
+};
+
+static struct gpio mx27_3ds_camera_gpios[] = {
+	{ CSI_PWRDWN, GPIOF_OUT_INIT_HIGH, "camera-power" },
+	{ CSI_RESET, GPIOF_OUT_INIT_HIGH, "camera-reset" },
 };
 
 static const struct imxuart_platform_data uart_pdata __initconst = {
@@ -242,6 +266,7 @@
 
 static struct regulator_consumer_supply vmmc1_consumers[] = {
 	REGULATOR_SUPPLY("vcore", "spi0.0"),
+	REGULATOR_SUPPLY("cmos_2v8", "soc-camera-pdrv.0"),
 };
 
 static struct regulator_init_data vmmc1_init = {
@@ -270,6 +295,22 @@
 	.consumer_supplies = vgen_consumers,
 };
 
+static struct regulator_consumer_supply vvib_consumers[] = {
+	REGULATOR_SUPPLY("cmos_vcore", "soc-camera-pdrv.0"),
+};
+
+static struct regulator_init_data vvib_init = {
+	.constraints = {
+		.min_uV = 1300000,
+		.max_uV = 1300000,
+		.apply_uV = 1,
+		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+				  REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies = ARRAY_SIZE(vvib_consumers),
+	.consumer_supplies = vvib_consumers,
+};
+
 static struct mc13xxx_regulator_init_data mx27_3ds_regulators[] = {
 	{
 		.id = MC13783_REG_VMMC1,
@@ -283,6 +324,9 @@
 	}, {
 		.id = MC13783_REG_GPO3, /* Turn on 3.3V */
 		.init_data = &gpo_init,
+	}, {
+		.id = MC13783_REG_VVIB,  /* Power OV2640 */
+		.init_data = &vvib_init,
 	},
 };
 
@@ -311,6 +355,51 @@
 	.num_chipselect	= ARRAY_SIZE(spi2_chipselect),
 };
 
+static int mx27_3ds_camera_power(struct device *dev, int on)
+{
+	/* enable or disable the camera */
+	pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE");
+	gpio_set_value(CSI_PWRDWN, on ? 0 : 1);
+
+	if (!on)
+		goto out;
+
+	/* If enabled, give a reset impulse */
+	gpio_set_value(CSI_RESET, 0);
+	msleep(20);
+	gpio_set_value(CSI_RESET, 1);
+	msleep(100);
+
+out:
+	return 0;
+}
+
+static struct i2c_board_info mx27_3ds_i2c_camera = {
+	I2C_BOARD_INFO("ov2640", 0x30),
+};
+
+static struct regulator_bulk_data mx27_3ds_camera_regs[] = {
+	{ .supply = "cmos_vcore" },
+	{ .supply = "cmos_2v8" },
+};
+
+static struct soc_camera_link iclink_ov2640 = {
+	.bus_id		= 0,
+	.board_info	= &mx27_3ds_i2c_camera,
+	.i2c_adapter_id	= 0,
+	.power		= mx27_3ds_camera_power,
+	.regulators	= mx27_3ds_camera_regs,
+	.num_regulators	= ARRAY_SIZE(mx27_3ds_camera_regs),
+};
+
+static struct platform_device mx27_3ds_ov2640 = {
+	.name	= "soc-camera-pdrv",
+	.id	= 0,
+	.dev	= {
+		.platform_data = &iclink_ov2640,
+	},
+};
+
 static struct imx_fb_videomode mx27_3ds_modes[] = {
 	{	/* 480x640 @ 60 Hz */
 		.mode = {
@@ -367,12 +456,21 @@
 	},
 };
 
+static struct platform_device *devices[] __initdata = {
+	&mx27_3ds_ov2640,
+};
+
+static const struct mx2_camera_platform_data mx27_3ds_cam_pdata __initconst = {
+	.clk = 26000000,
+};
+
 static const struct imxi2c_platform_data mx27_3ds_i2c0_data __initconst = {
 	.bitrate = 100000,
 };
 
 static void __init mx27pdk_init(void)
 {
+	int ret;
 	imx27_soc_init();
 
 	mxc_gpio_setup_multiple_pins(mx27pdk_pins, ARRAY_SIZE(mx27pdk_pins),
@@ -404,7 +502,17 @@
 	if (mxc_expio_init(MX27_CS5_BASE_ADDR, EXPIO_PARENT_INT))
 		pr_warn("Init of the debugboard failed, all devices on the debugboard are unusable.\n");
 	imx27_add_imx_i2c(0, &mx27_3ds_i2c0_data);
+	platform_add_devices(devices, ARRAY_SIZE(devices));
 	imx27_add_imx_fb(&mx27_3ds_fb_data);
+
+	ret = gpio_request_array(mx27_3ds_camera_gpios,
+				 ARRAY_SIZE(mx27_3ds_camera_gpios));
+	if (ret) {
+		pr_err("Failed to request camera gpios");
+		iclink_ov2640.power = NULL;
+	}
+
+	imx27_add_mx2_camera(&mx27_3ds_cam_pdata);
 }
 
 static void __init mx27pdk_timer_init(void)
diff --git a/arch/arm/mach-imx/mach-mx31ads.c b/arch/arm/mach-imx/mach-mx31ads.c
index 4917aab..4518e54 100644
--- a/arch/arm/mach-imx/mach-mx31ads.c
+++ b/arch/arm/mach-imx/mach-mx31ads.c
@@ -28,7 +28,6 @@
 #include <asm/memory.h>
 #include <asm/mach/map.h>
 #include <mach/common.h>
-#include <mach/board-mx31ads.h>
 #include <mach/iomux-mx3.h>
 
 #ifdef CONFIG_MACH_MX31ADS_WM1133_EV1
@@ -39,6 +38,9 @@
 
 #include "devices-imx31.h"
 
+/* Base address of PBC controller */
+#define PBC_BASE_ADDRESS	MX31_CS4_BASE_ADDR_VIRT
+
 /* PBC Board interrupt status register */
 #define PBC_INTSTATUS           0x000016
 
@@ -62,6 +64,7 @@
 #define PBC_INTMASK_CLEAR_REG	(PBC_INTMASK_CLEAR + PBC_BASE_ADDRESS)
 #define EXPIO_PARENT_INT	IOMUX_TO_IRQ(MX31_PIN_GPIO1_4)
 
+#define MXC_EXP_IO_BASE		MXC_BOARD_IRQ_START
 #define MXC_IRQ_TO_EXPIO(irq)	((irq) - MXC_EXP_IO_BASE)
 
 #define EXPIO_INT_XUART_INTA	(MXC_EXP_IO_BASE + 10)
@@ -69,6 +72,10 @@
 
 #define MXC_MAX_EXP_IO_LINES	16
 
+/* CS8900 */
+#define EXPIO_INT_ENET_INT	(MXC_EXP_IO_BASE + 8)
+#define CS4_CS8900_MMIO_START	0x20000
+
 /*
  * The serial port definition structure.
  */
@@ -101,11 +108,29 @@
 	},
 };
 
+static const struct resource mx31ads_cs8900_resources[] __initconst = {
+	DEFINE_RES_MEM(MX31_CS4_BASE_ADDR + CS4_CS8900_MMIO_START, SZ_64K),
+	DEFINE_RES_IRQ(EXPIO_INT_ENET_INT),
+};
+
+static const struct platform_device_info mx31ads_cs8900_devinfo __initconst = {
+	.name = "cs89x0",
+	.id = 0,
+	.res = mx31ads_cs8900_resources,
+	.num_res = ARRAY_SIZE(mx31ads_cs8900_resources),
+};
+
 static int __init mxc_init_extuart(void)
 {
 	return platform_device_register(&serial_device);
 }
 
+static void __init mxc_init_ext_ethernet(void)
+{
+	platform_device_register_full(
+		(struct platform_device_info *)&mx31ads_cs8900_devinfo);
+}
+
 static const struct imxuart_platform_data uart_pdata __initconst = {
 	.flags = IMXUART_HAVE_RTSCTS,
 };
@@ -492,12 +517,15 @@
 	mxc_iomux_setup_multiple_pins(ssi_pins, ARRAY_SIZE(ssi_pins), "ssi");
 }
 
-/* static mappings */
+/*
+ * Static mappings, starting from the CS4 start address up to the start address
+ * of the CS8900.
+ */
 static struct map_desc mx31ads_io_desc[] __initdata = {
 	{
 		.virtual	= MX31_CS4_BASE_ADDR_VIRT,
 		.pfn		= __phys_to_pfn(MX31_CS4_BASE_ADDR),
-		.length		= MX31_CS4_SIZE / 2,
+		.length		= CS4_CS8900_MMIO_START,
 		.type		= MT_DEVICE
 	},
 };
@@ -522,6 +550,7 @@
 	mxc_init_imx_uart();
 	mxc_init_i2c();
 	mxc_init_audio();
+	mxc_init_ext_ethernet();
 }
 
 static void __init mx31ads_timer_init(void)
diff --git a/arch/arm/mach-imx/mach-mx31lilly.c b/arch/arm/mach-imx/mach-mx31lilly.c
index 02401bb..83714b0 100644
--- a/arch/arm/mach-imx/mach-mx31lilly.c
+++ b/arch/arm/mach-imx/mach-mx31lilly.c
@@ -34,6 +34,8 @@
 #include <linux/mfd/mc13783.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/ulpi.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -242,6 +244,11 @@
 static int mx31lilly_baseboard;
 core_param(mx31lilly_baseboard, mx31lilly_baseboard, int, 0444);
 
+static struct regulator_consumer_supply dummy_supplies[] = {
+	REGULATOR_SUPPLY("vdd33a", "smsc911x"),
+	REGULATOR_SUPPLY("vddvario", "smsc911x"),
+};
+
 static void __init mx31lilly_board_init(void)
 {
 	imx31_soc_init();
@@ -280,6 +287,8 @@
 	imx31_add_spi_imx1(&spi1_pdata);
 	spi_register_board_info(&mc13783_dev, 1);
 
+	regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
+
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 
 	/* USB */
diff --git a/arch/arm/mach-imx/mach-mx31lite.c b/arch/arm/mach-imx/mach-mx31lite.c
index ef80751..0abef5f 100644
--- a/arch/arm/mach-imx/mach-mx31lite.c
+++ b/arch/arm/mach-imx/mach-mx31lite.c
@@ -29,6 +29,8 @@
 #include <linux/usb/ulpi.h>
 #include <linux/mtd/physmap.h>
 #include <linux/delay.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -226,6 +228,11 @@
 static int mx31lite_baseboard;
 core_param(mx31lite_baseboard, mx31lite_baseboard, int, 0444);
 
+static struct regulator_consumer_supply dummy_supplies[] = {
+	REGULATOR_SUPPLY("vdd33a", "smsc911x"),
+	REGULATOR_SUPPLY("vddvario", "smsc911x"),
+};
+
 static void __init mx31lite_init(void)
 {
 	int ret;
@@ -259,6 +266,8 @@
 	if (usbh2_pdata.otg)
 		imx31_add_mxc_ehci_hs(2, &usbh2_pdata);
 
+	regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
+
 	/* SMSC9117 IRQ pin */
 	ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_SFS6), "sms9117-irq");
 	if (ret)
diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c
index f225262..f17a15f 100644
--- a/arch/arm/mach-imx/mach-mx31moboard.c
+++ b/arch/arm/mach-imx/mach-mx31moboard.c
@@ -507,7 +507,7 @@
 	struct clk *clk = clk_get_sys("imx2-wdt.0", NULL);
 
 	if (!IS_ERR(clk))
-		clk_enable(clk);
+		clk_prepare_enable(clk);
 
 	mxc_iomux_mode(MX31_PIN_WATCHDOG_RST__WATCHDOG_RST);
 
@@ -530,6 +530,8 @@
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 	gpio_led_register_device(-1, &mx31moboard_led_pdata);
 
+	imx31_add_imx2_wdt(NULL);
+
 	imx31_add_imx_uart0(&uart0_pdata);
 	imx31_add_imx_uart4(&uart4_pdata);
 
@@ -590,7 +592,7 @@
 }
 
 MACHINE_START(MX31MOBOARD, "EPFL Mobots mx31moboard")
-	/* Maintainer: Valentin Longchamp, EPFL Mobots group */
+	/* Maintainer: Philippe Retornaz, EPFL Mobots group */
 	.atag_offset = 0x100,
 	.reserve = mx31moboard_reserve,
 	.map_io = mx31_map_io,
diff --git a/arch/arm/mach-imx/mach-mx35_3ds.c b/arch/arm/mach-imx/mach-mx35_3ds.c
index 0af6c9c..6ae51c6 100644
--- a/arch/arm/mach-imx/mach-mx35_3ds.c
+++ b/arch/arm/mach-imx/mach-mx35_3ds.c
@@ -4,6 +4,11 @@
  *
  * Author: Fabio Estevam <fabio.estevam@freescale.com>
  *
+ * Copyright (C) 2011 Meprolight, Ltd.
+ * Alex Gershgorin <alexg@meprolight.com>
+ *
+ * Modified from i.MX31 3-Stack Development System
+ *
  * 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
@@ -34,15 +39,102 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/mach/map.h>
+#include <asm/memblock.h>
 
 #include <mach/hardware.h>
 #include <mach/common.h>
 #include <mach/iomux-mx35.h>
 #include <mach/irqs.h>
 #include <mach/3ds_debugboard.h>
+#include <video/platform_lcd.h>
+
+#include <media/soc_camera.h>
 
 #include "devices-imx35.h"
 
+#define GPIO_MC9S08DZ60_GPS_ENABLE 0
+#define GPIO_MC9S08DZ60_HDD_ENABLE 4
+#define GPIO_MC9S08DZ60_WIFI_ENABLE 5
+#define GPIO_MC9S08DZ60_LCD_ENABLE 6
+#define GPIO_MC9S08DZ60_SPEAKER_ENABLE 8
+
+static const struct fb_videomode fb_modedb[] = {
+	{
+		 /* 800x480 @ 55 Hz */
+		.name = "Ceramate-CLAA070VC01",
+		.refresh = 55,
+		.xres = 800,
+		.yres = 480,
+		.pixclock = 40000,
+		.left_margin = 40,
+		.right_margin = 40,
+		.upper_margin = 5,
+		.lower_margin = 5,
+		.hsync_len = 20,
+		.vsync_len = 10,
+		.sync = FB_SYNC_OE_ACT_HIGH,
+		.vmode = FB_VMODE_NONINTERLACED,
+		.flag = 0,
+	 },
+};
+
+static const struct ipu_platform_data mx3_ipu_data __initconst = {
+	.irq_base = MXC_IPU_IRQ_START,
+};
+
+static struct mx3fb_platform_data mx3fb_pdata __initdata = {
+	.name = "Ceramate-CLAA070VC01",
+	.mode = fb_modedb,
+	.num_modes = ARRAY_SIZE(fb_modedb),
+};
+
+static struct i2c_board_info __initdata i2c_devices_3ds[] = {
+	{
+		I2C_BOARD_INFO("mc9s08dz60", 0x69),
+	},
+};
+
+static int lcd_power_gpio = -ENXIO;
+
+static int mc9s08dz60_gpiochip_match(struct gpio_chip *chip,
+						     const void *data)
+{
+	return !strcmp(chip->label, data);
+}
+
+static void mx35_3ds_lcd_set_power(
+				struct plat_lcd_data *pd, unsigned int power)
+{
+	struct gpio_chip *chip;
+
+	if (!gpio_is_valid(lcd_power_gpio)) {
+		chip = gpiochip_find(
+				"mc9s08dz60", mc9s08dz60_gpiochip_match);
+		if (chip) {
+			lcd_power_gpio =
+				chip->base + GPIO_MC9S08DZ60_LCD_ENABLE;
+			if (gpio_request(lcd_power_gpio, "lcd_power") < 0) {
+				pr_err("error: gpio already requested!\n");
+				lcd_power_gpio = -ENXIO;
+			}
+		} else {
+			pr_err("error: didn't find mc9s08dz60 gpio chip\n");
+		}
+	}
+
+	if (gpio_is_valid(lcd_power_gpio))
+		gpio_set_value_cansleep(lcd_power_gpio, power);
+}
+
+static struct plat_lcd_data mx35_3ds_lcd_data = {
+	.set_power = mx35_3ds_lcd_set_power,
+};
+
+static struct platform_device mx35_3ds_lcd = {
+	.name = "platform-lcd",
+	.dev.platform_data = &mx35_3ds_lcd_data,
+};
+
 #define EXPIO_PARENT_INT	gpio_to_irq(IMX_GPIO_NR(1, 1))
 
 static const struct imxuart_platform_data uart_pdata __initconst = {
@@ -120,6 +212,109 @@
 	/* I2C1 */
 	MX35_PAD_I2C1_CLK__I2C1_SCL,
 	MX35_PAD_I2C1_DAT__I2C1_SDA,
+	/* Display */
+	MX35_PAD_LD0__IPU_DISPB_DAT_0,
+	MX35_PAD_LD1__IPU_DISPB_DAT_1,
+	MX35_PAD_LD2__IPU_DISPB_DAT_2,
+	MX35_PAD_LD3__IPU_DISPB_DAT_3,
+	MX35_PAD_LD4__IPU_DISPB_DAT_4,
+	MX35_PAD_LD5__IPU_DISPB_DAT_5,
+	MX35_PAD_LD6__IPU_DISPB_DAT_6,
+	MX35_PAD_LD7__IPU_DISPB_DAT_7,
+	MX35_PAD_LD8__IPU_DISPB_DAT_8,
+	MX35_PAD_LD9__IPU_DISPB_DAT_9,
+	MX35_PAD_LD10__IPU_DISPB_DAT_10,
+	MX35_PAD_LD11__IPU_DISPB_DAT_11,
+	MX35_PAD_LD12__IPU_DISPB_DAT_12,
+	MX35_PAD_LD13__IPU_DISPB_DAT_13,
+	MX35_PAD_LD14__IPU_DISPB_DAT_14,
+	MX35_PAD_LD15__IPU_DISPB_DAT_15,
+	MX35_PAD_LD16__IPU_DISPB_DAT_16,
+	MX35_PAD_LD17__IPU_DISPB_DAT_17,
+	MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC,
+	MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK,
+	MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY,
+	MX35_PAD_CONTRAST__IPU_DISPB_CONTR,
+	MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC,
+	MX35_PAD_D3_REV__IPU_DISPB_D3_REV,
+	MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS,
+	/* CSI */
+	MX35_PAD_TX1__IPU_CSI_D_6,
+	MX35_PAD_TX0__IPU_CSI_D_7,
+	MX35_PAD_CSI_D8__IPU_CSI_D_8,
+	MX35_PAD_CSI_D9__IPU_CSI_D_9,
+	MX35_PAD_CSI_D10__IPU_CSI_D_10,
+	MX35_PAD_CSI_D11__IPU_CSI_D_11,
+	MX35_PAD_CSI_D12__IPU_CSI_D_12,
+	MX35_PAD_CSI_D13__IPU_CSI_D_13,
+	MX35_PAD_CSI_D14__IPU_CSI_D_14,
+	MX35_PAD_CSI_D15__IPU_CSI_D_15,
+	MX35_PAD_CSI_HSYNC__IPU_CSI_HSYNC,
+	MX35_PAD_CSI_MCLK__IPU_CSI_MCLK,
+	MX35_PAD_CSI_PIXCLK__IPU_CSI_PIXCLK,
+	MX35_PAD_CSI_VSYNC__IPU_CSI_VSYNC,
+};
+
+/*
+ * Camera support
+*/
+static phys_addr_t mx3_camera_base __initdata;
+#define MX35_3DS_CAMERA_BUF_SIZE SZ_8M
+
+static const struct mx3_camera_pdata mx35_3ds_camera_pdata __initconst = {
+	.flags = MX3_CAMERA_DATAWIDTH_8,
+	.mclk_10khz = 2000,
+};
+
+static int __init imx35_3ds_init_camera(void)
+{
+	int dma, ret = -ENOMEM;
+	struct platform_device *pdev =
+		imx35_alloc_mx3_camera(&mx35_3ds_camera_pdata);
+
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	if (!mx3_camera_base)
+		goto err;
+
+	dma = dma_declare_coherent_memory(&pdev->dev,
+					mx3_camera_base, mx3_camera_base,
+					MX35_3DS_CAMERA_BUF_SIZE,
+					DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+
+	if (!(dma & DMA_MEMORY_MAP))
+		goto err;
+
+	ret = platform_device_add(pdev);
+	if (ret)
+err:
+		platform_device_put(pdev);
+
+	return ret;
+}
+
+static const struct ipu_platform_data mx35_3ds_ipu_data __initconst = {
+	.irq_base = MXC_IPU_IRQ_START,
+};
+
+static struct i2c_board_info mx35_3ds_i2c_camera = {
+	I2C_BOARD_INFO("ov2640", 0x30),
+};
+
+static struct soc_camera_link iclink_ov2640 = {
+	.bus_id		= 0,
+	.board_info	= &mx35_3ds_i2c_camera,
+	.i2c_adapter_id	= 0,
+	.power		= NULL,
+};
+
+static struct platform_device mx35_3ds_ov2640 = {
+	.name	= "soc-camera-pdrv",
+	.id	= 0,
+	.dev	= {
+		.platform_data = &iclink_ov2640,
+	},
 };
 
 static int mx35_3ds_otg_init(struct platform_device *pdev)
@@ -179,6 +374,8 @@
  */
 static void __init mx35_3ds_init(void)
 {
+	struct platform_device *imx35_fb_pdev;
+
 	imx35_soc_init();
 
 	mxc_iomux_v3_setup_multiple_pads(mx35pdk_pads, ARRAY_SIZE(mx35pdk_pads));
@@ -204,6 +401,17 @@
 		pr_warn("Init of the debugboard failed, all "
 				"devices on the debugboard are unusable.\n");
 	imx35_add_imx_i2c0(&mx35_3ds_i2c0_data);
+
+	i2c_register_board_info(
+		0, i2c_devices_3ds, ARRAY_SIZE(i2c_devices_3ds));
+
+	imx35_add_ipu_core(&mx35_3ds_ipu_data);
+	platform_device_register(&mx35_3ds_ov2640);
+	imx35_3ds_init_camera();
+
+	imx35_fb_pdev = imx35_add_mx3_sdc_fb(&mx3fb_pdata);
+	mx35_3ds_lcd.dev.parent = &imx35_fb_pdev->dev;
+	platform_device_register(&mx35_3ds_lcd);
 }
 
 static void __init mx35pdk_timer_init(void)
@@ -215,6 +423,13 @@
 	.init	= mx35pdk_timer_init,
 };
 
+static void __init mx35_3ds_reserve(void)
+{
+	/* reserve MX35_3DS_CAMERA_BUF_SIZE bytes for mx3-camera */
+	mx3_camera_base = arm_memblock_steal(MX35_3DS_CAMERA_BUF_SIZE,
+					 MX35_3DS_CAMERA_BUF_SIZE);
+}
+
 MACHINE_START(MX35_3DS, "Freescale MX35PDK")
 	/* Maintainer: Freescale Semiconductor, Inc */
 	.atag_offset = 0x100,
@@ -224,5 +439,6 @@
 	.handle_irq = imx35_handle_irq,
 	.timer = &mx35pdk_timer,
 	.init_machine = mx35_3ds_init,
+	.reserve = mx35_3ds_reserve,
 	.restart	= mxc_restart,
 MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx51_efikamx.c b/arch/arm/mach-imx/mach-mx51_efikamx.c
index 3a5ed2d..586e9f8 100644
--- a/arch/arm/mach-imx/mach-mx51_efikamx.c
+++ b/arch/arm/mach-imx/mach-mx51_efikamx.c
@@ -33,6 +33,7 @@
 #include <mach/iomux-mx51.h>
 
 #include <asm/setup.h>
+#include <asm/system_info.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
diff --git a/arch/arm/mach-imx/mach-mx51_efikasb.c b/arch/arm/mach-imx/mach-mx51_efikasb.c
index ea5f65b..24aded9 100644
--- a/arch/arm/mach-imx/mach-mx51_efikasb.c
+++ b/arch/arm/mach-imx/mach-mx51_efikasb.c
@@ -36,6 +36,7 @@
 #include <mach/iomux-mx51.h>
 
 #include <asm/setup.h>
+#include <asm/system_info.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
diff --git a/arch/arm/mach-imx/mach-mx53_ard.c b/arch/arm/mach-imx/mach-mx53_ard.c
index 753f4fc..0564198 100644
--- a/arch/arm/mach-imx/mach-mx53_ard.c
+++ b/arch/arm/mach-imx/mach-mx53_ard.c
@@ -23,6 +23,8 @@
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/smsc911x.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
 
 #include <mach/common.h>
 #include <mach/hardware.h>
@@ -214,6 +216,11 @@
 	return 0;
 }
 
+static struct regulator_consumer_supply dummy_supplies[] = {
+	REGULATOR_SUPPLY("vdd33a", "smsc911x"),
+	REGULATOR_SUPPLY("vddvario", "smsc911x"),
+};
+
 void __init imx53_ard_common_init(void)
 {
 	mxc_iomux_v3_setup_multiple_pads(mx53_ard_pads,
@@ -232,6 +239,7 @@
 
 	imx53_ard_common_init();
 	mx53_ard_io_init();
+	regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 
 	imx53_add_sdhci_esdhc_imx(0, &mx53_ard_sd1_data);
diff --git a/arch/arm/mach-imx/mach-pca100.c b/arch/arm/mach-imx/mach-pca100.c
index d3b9c6b..541152e 100644
--- a/arch/arm/mach-imx/mach-pca100.c
+++ b/arch/arm/mach-imx/mach-pca100.c
@@ -36,7 +36,6 @@
 #include <mach/hardware.h>
 #include <mach/iomux-mx27.h>
 #include <asm/mach/time.h>
-#include <mach/audmux.h>
 #include <mach/irqs.h>
 #include <mach/ulpi.h>
 
@@ -359,18 +358,6 @@
 
 	imx27_soc_init();
 
-	/* SSI unit */
-	mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
-				  MXC_AUDMUX_V1_PCR_SYN | /* 4wire mode */
-				  MXC_AUDMUX_V1_PCR_TFCSEL(3) |
-				  MXC_AUDMUX_V1_PCR_TCLKDIR | /* clock is output */
-				  MXC_AUDMUX_V1_PCR_RXDSEL(3));
-	mxc_audmux_v1_configure_port(3,
-				  MXC_AUDMUX_V1_PCR_SYN | /* 4wire mode */
-				  MXC_AUDMUX_V1_PCR_TFCSEL(0) |
-				  MXC_AUDMUX_V1_PCR_TFSDIR |
-				  MXC_AUDMUX_V1_PCR_RXDSEL(0));
-
 	ret = mxc_gpio_setup_multiple_pins(pca100_pins,
 			ARRAY_SIZE(pca100_pins), "PCA100");
 	if (ret)
diff --git a/arch/arm/mach-imx/mach-pcm038.c b/arch/arm/mach-imx/mach-pcm038.c
index 16f126d..2f3debe 100644
--- a/arch/arm/mach-imx/mach-pcm038.c
+++ b/arch/arm/mach-imx/mach-pcm038.c
@@ -233,7 +233,7 @@
 
 static struct regulator_consumer_supply cam_consumers[] = {
 	{
-		.dev	= NULL,
+		.dev_name = NULL,
 		.supply	= "imx_cam_vcc",
 	},
 };
diff --git a/arch/arm/mach-imx/mach-pcm043.c b/arch/arm/mach-imx/mach-pcm043.c
index 06dc106..237474f 100644
--- a/arch/arm/mach-imx/mach-pcm043.c
+++ b/arch/arm/mach-imx/mach-pcm043.c
@@ -37,7 +37,6 @@
 #include <mach/common.h>
 #include <mach/iomux-mx35.h>
 #include <mach/ulpi.h>
-#include <mach/audmux.h>
 
 #include "devices-imx35.h"
 
@@ -362,18 +361,6 @@
 
 	mxc_iomux_v3_setup_multiple_pads(pcm043_pads, ARRAY_SIZE(pcm043_pads));
 
-	mxc_audmux_v2_configure_port(3,
-			MXC_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
-			MXC_AUDMUX_V2_PTCR_TFSEL(0) |
-			MXC_AUDMUX_V2_PTCR_TFSDIR,
-			MXC_AUDMUX_V2_PDCR_RXDSEL(0));
-
-	mxc_audmux_v2_configure_port(0,
-			MXC_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
-			MXC_AUDMUX_V2_PTCR_TCSEL(3) |
-			MXC_AUDMUX_V2_PTCR_TCLKDIR, /* clock is output */
-			MXC_AUDMUX_V2_PDCR_RXDSEL(3));
-
 	imx35_add_fec(NULL);
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 	imx35_add_imx2_wdt(NULL);
diff --git a/arch/arm/mach-imx/mm-imx21.c b/arch/arm/mach-imx/mm-imx21.c
index 3f05dfe..14d540e 100644
--- a/arch/arm/mach-imx/mm-imx21.c
+++ b/arch/arm/mach-imx/mm-imx21.c
@@ -75,6 +75,10 @@
 	mxc_init_irq(MX21_IO_ADDRESS(MX21_AVIC_BASE_ADDR));
 }
 
+static const struct resource imx21_audmux_res[] __initconst = {
+	DEFINE_RES_MEM(MX21_AUDMUX_BASE_ADDR, SZ_4K),
+};
+
 void __init imx21_soc_init(void)
 {
 	mxc_register_gpio("imx21-gpio", 0, MX21_GPIO1_BASE_ADDR, SZ_256, MX21_INT_GPIO, 0);
@@ -85,4 +89,6 @@
 	mxc_register_gpio("imx21-gpio", 5, MX21_GPIO6_BASE_ADDR, SZ_256, MX21_INT_GPIO, 0);
 
 	imx_add_imx_dma();
+	platform_device_register_simple("imx21-audmux", 0, imx21_audmux_res,
+					ARRAY_SIZE(imx21_audmux_res));
 }
diff --git a/arch/arm/mach-imx/mm-imx25.c b/arch/arm/mach-imx/mm-imx25.c
index cc4d152..153b457 100644
--- a/arch/arm/mach-imx/mm-imx25.c
+++ b/arch/arm/mach-imx/mm-imx25.c
@@ -83,6 +83,10 @@
 	.script_addrs = &imx25_sdma_script,
 };
 
+static const struct resource imx25_audmux_res[] __initconst = {
+	DEFINE_RES_MEM(MX25_AUDMUX_BASE_ADDR, SZ_16K),
+};
+
 void __init imx25_soc_init(void)
 {
 	/* i.mx25 has the i.mx31 type gpio */
@@ -93,4 +97,7 @@
 
 	/* i.mx25 has the i.mx35 type sdma */
 	imx_add_imx_sdma("imx35-sdma", MX25_SDMA_BASE_ADDR, MX25_INT_SDMA, &imx25_sdma_pdata);
+	/* i.mx25 has the i.mx31 type audmux */
+	platform_device_register_simple("imx31-audmux", 0, imx25_audmux_res,
+					ARRAY_SIZE(imx25_audmux_res));
 }
diff --git a/arch/arm/mach-imx/mm-imx27.c b/arch/arm/mach-imx/mm-imx27.c
index 96dd1f5..8cb3f5e 100644
--- a/arch/arm/mach-imx/mm-imx27.c
+++ b/arch/arm/mach-imx/mm-imx27.c
@@ -75,6 +75,10 @@
 	mxc_init_irq(MX27_IO_ADDRESS(MX27_AVIC_BASE_ADDR));
 }
 
+static const struct resource imx27_audmux_res[] __initconst = {
+	DEFINE_RES_MEM(MX27_AUDMUX_BASE_ADDR, SZ_4K),
+};
+
 void __init imx27_soc_init(void)
 {
 	/* i.mx27 has the i.mx21 type gpio */
@@ -86,4 +90,7 @@
 	mxc_register_gpio("imx21-gpio", 5, MX27_GPIO6_BASE_ADDR, SZ_256, MX27_INT_GPIO, 0);
 
 	imx_add_imx_dma();
+	/* imx27 has the imx21 type audmux */
+	platform_device_register_simple("imx21-audmux", 0, imx27_audmux_res,
+					ARRAY_SIZE(imx27_audmux_res));
 }
diff --git a/arch/arm/mach-imx/mm-imx3.c b/arch/arm/mach-imx/mm-imx3.c
index 31807d2..7412738 100644
--- a/arch/arm/mach-imx/mm-imx3.c
+++ b/arch/arm/mach-imx/mm-imx3.c
@@ -21,6 +21,7 @@
 #include <linux/err.h>
 
 #include <asm/pgtable.h>
+#include <asm/system_misc.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/mach/map.h>
 
@@ -34,35 +35,35 @@
 {
 	unsigned long reg = 0;
 
-	if (!need_resched())
-		__asm__ __volatile__(
-			/* disable I and D cache */
-			"mrc p15, 0, %0, c1, c0, 0\n"
-			"bic %0, %0, #0x00001000\n"
-			"bic %0, %0, #0x00000004\n"
-			"mcr p15, 0, %0, c1, c0, 0\n"
-			/* invalidate I cache */
-			"mov %0, #0\n"
-			"mcr p15, 0, %0, c7, c5, 0\n"
-			/* clear and invalidate D cache */
-			"mov %0, #0\n"
-			"mcr p15, 0, %0, c7, c14, 0\n"
-			/* WFI */
-			"mov %0, #0\n"
-			"mcr p15, 0, %0, c7, c0, 4\n"
-			"nop\n" "nop\n" "nop\n" "nop\n"
-			"nop\n" "nop\n" "nop\n"
-			/* enable I and D cache */
-			"mrc p15, 0, %0, c1, c0, 0\n"
-			"orr %0, %0, #0x00001000\n"
-			"orr %0, %0, #0x00000004\n"
-			"mcr p15, 0, %0, c1, c0, 0\n"
-			: "=r" (reg));
-	local_irq_enable();
+	mx3_cpu_lp_set(MX3_WAIT);
+
+	__asm__ __volatile__(
+		/* disable I and D cache */
+		"mrc p15, 0, %0, c1, c0, 0\n"
+		"bic %0, %0, #0x00001000\n"
+		"bic %0, %0, #0x00000004\n"
+		"mcr p15, 0, %0, c1, c0, 0\n"
+		/* invalidate I cache */
+		"mov %0, #0\n"
+		"mcr p15, 0, %0, c7, c5, 0\n"
+		/* clear and invalidate D cache */
+		"mov %0, #0\n"
+		"mcr p15, 0, %0, c7, c14, 0\n"
+		/* WFI */
+		"mov %0, #0\n"
+		"mcr p15, 0, %0, c7, c0, 4\n"
+		"nop\n" "nop\n" "nop\n" "nop\n"
+		"nop\n" "nop\n" "nop\n"
+		/* enable I and D cache */
+		"mrc p15, 0, %0, c1, c0, 0\n"
+		"orr %0, %0, #0x00001000\n"
+		"orr %0, %0, #0x00000004\n"
+		"mcr p15, 0, %0, c1, c0, 0\n"
+		: "=r" (reg));
 }
 
-static void __iomem *imx3_ioremap(unsigned long phys_addr, size_t size,
-				  unsigned int mtype)
+static void __iomem *imx3_ioremap_caller(unsigned long phys_addr, size_t size,
+					 unsigned int mtype, void *caller)
 {
 	if (mtype == MT_DEVICE) {
 		/*
@@ -75,10 +76,10 @@
 			mtype = MT_DEVICE_NONSHARED;
 	}
 
-	return __arm_ioremap(phys_addr, size, mtype);
+	return __arm_ioremap_caller(phys_addr, size, mtype, caller);
 }
 
-void imx3_init_l2x0(void)
+void __init imx3_init_l2x0(void)
 {
 	void __iomem *l2x0_base;
 	void __iomem *clkctl_base;
@@ -134,8 +135,8 @@
 {
 	mxc_set_cpu_type(MXC_CPU_MX31);
 	mxc_arch_reset_init(MX31_IO_ADDRESS(MX31_WDOG_BASE_ADDR));
-	pm_idle = imx3_idle;
-	imx_ioremap = imx3_ioremap;
+	arch_ioremap_caller = imx3_ioremap_caller;
+	arm_pm_idle = imx3_idle;
 }
 
 void __init mx31_init_irq(void)
@@ -158,6 +159,10 @@
 	.script_addrs = &imx31_to2_sdma_script,
 };
 
+static const struct resource imx31_audmux_res[] __initconst = {
+	DEFINE_RES_MEM(MX31_AUDMUX_BASE_ADDR, SZ_16K),
+};
+
 void __init imx31_soc_init(void)
 {
 	int to_version = mx31_revision() >> 4;
@@ -175,6 +180,12 @@
 	}
 
 	imx_add_imx_sdma("imx31-sdma", MX31_SDMA_BASE_ADDR, MX31_INT_SDMA, &imx31_sdma_pdata);
+
+	imx_set_aips(MX31_IO_ADDRESS(MX31_AIPS1_BASE_ADDR));
+	imx_set_aips(MX31_IO_ADDRESS(MX31_AIPS2_BASE_ADDR));
+
+	platform_device_register_simple("imx31-audmux", 0, imx31_audmux_res,
+					ARRAY_SIZE(imx31_audmux_res));
 }
 #endif /* ifdef CONFIG_SOC_IMX31 */
 
@@ -197,8 +208,8 @@
 	mxc_set_cpu_type(MXC_CPU_MX35);
 	mxc_iomux_v3_init(MX35_IO_ADDRESS(MX35_IOMUXC_BASE_ADDR));
 	mxc_arch_reset_init(MX35_IO_ADDRESS(MX35_WDOG_BASE_ADDR));
-	pm_idle = imx3_idle;
-	imx_ioremap = imx3_ioremap;
+	arm_pm_idle = imx3_idle;
+	arch_ioremap_caller = imx3_ioremap_caller;
 }
 
 void __init mx35_init_irq(void)
@@ -241,6 +252,10 @@
 	.script_addrs = &imx35_to2_sdma_script,
 };
 
+static const struct resource imx35_audmux_res[] __initconst = {
+	DEFINE_RES_MEM(MX35_AUDMUX_BASE_ADDR, SZ_16K),
+};
+
 void __init imx35_soc_init(void)
 {
 	int to_version = mx35_revision() >> 4;
@@ -259,5 +274,13 @@
 	}
 
 	imx_add_imx_sdma("imx35-sdma", MX35_SDMA_BASE_ADDR, MX35_INT_SDMA, &imx35_sdma_pdata);
+
+	/* Setup AIPS registers */
+	imx_set_aips(MX35_IO_ADDRESS(MX35_AIPS1_BASE_ADDR));
+	imx_set_aips(MX35_IO_ADDRESS(MX35_AIPS2_BASE_ADDR));
+
+	/* i.mx35 has the i.mx31 type audmux */
+	platform_device_register_simple("imx31-audmux", 0, imx35_audmux_res,
+					ARRAY_SIZE(imx35_audmux_res));
 }
 #endif /* ifdef CONFIG_SOC_IMX35 */
diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c
index bc17dfe..05250ae 100644
--- a/arch/arm/mach-imx/mm-imx5.c
+++ b/arch/arm/mach-imx/mm-imx5.c
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/clk.h>
 
+#include <asm/system_misc.h>
 #include <asm/mach/map.h>
 
 #include <mach/hardware.h>
@@ -26,23 +27,17 @@
 
 static void imx5_idle(void)
 {
-	if (!need_resched()) {
-		/* gpc clock is needed for SRPG */
-		if (gpc_dvfs_clk == NULL) {
-			gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
-			if (IS_ERR(gpc_dvfs_clk))
-				goto err0;
-		}
-		clk_enable(gpc_dvfs_clk);
-		mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
-		if (tzic_enable_wake())
-			goto err1;
-		cpu_do_idle();
-err1:
-		clk_disable(gpc_dvfs_clk);
+	/* gpc clock is needed for SRPG */
+	if (gpc_dvfs_clk == NULL) {
+		gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
+		if (IS_ERR(gpc_dvfs_clk))
+			return;
 	}
-err0:
-	local_irq_enable();
+	clk_enable(gpc_dvfs_clk);
+	mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
+	if (tzic_enable_wake() != 0)
+		cpu_do_idle();
+	clk_disable(gpc_dvfs_clk);
 }
 
 /*
@@ -108,7 +103,7 @@
 	mxc_set_cpu_type(MXC_CPU_MX51);
 	mxc_iomux_v3_init(MX51_IO_ADDRESS(MX51_IOMUXC_BASE_ADDR));
 	mxc_arch_reset_init(MX51_IO_ADDRESS(MX51_WDOG1_BASE_ADDR));
-	pm_idle = imx5_idle;
+	arm_pm_idle = imx5_idle;
 }
 
 void __init imx53_init_early(void)
@@ -170,6 +165,18 @@
 	.script_addrs = &imx53_sdma_script,
 };
 
+static const struct resource imx50_audmux_res[] __initconst = {
+	DEFINE_RES_MEM(MX50_AUDMUX_BASE_ADDR, SZ_16K),
+};
+
+static const struct resource imx51_audmux_res[] __initconst = {
+	DEFINE_RES_MEM(MX51_AUDMUX_BASE_ADDR, SZ_16K),
+};
+
+static const struct resource imx53_audmux_res[] __initconst = {
+	DEFINE_RES_MEM(MX53_AUDMUX_BASE_ADDR, SZ_16K),
+};
+
 void __init imx50_soc_init(void)
 {
 	/* i.mx50 has the i.mx31 type gpio */
@@ -179,6 +186,10 @@
 	mxc_register_gpio("imx31-gpio", 3, MX50_GPIO4_BASE_ADDR, SZ_16K, MX50_INT_GPIO4_LOW, MX50_INT_GPIO4_HIGH);
 	mxc_register_gpio("imx31-gpio", 4, MX50_GPIO5_BASE_ADDR, SZ_16K, MX50_INT_GPIO5_LOW, MX50_INT_GPIO5_HIGH);
 	mxc_register_gpio("imx31-gpio", 5, MX50_GPIO6_BASE_ADDR, SZ_16K, MX50_INT_GPIO6_LOW, MX50_INT_GPIO6_HIGH);
+
+	/* i.mx50 has the i.mx31 type audmux */
+	platform_device_register_simple("imx31-audmux", 0, imx50_audmux_res,
+					ARRAY_SIZE(imx50_audmux_res));
 }
 
 void __init imx51_soc_init(void)
@@ -191,6 +202,14 @@
 
 	/* i.mx51 has the i.mx35 type sdma */
 	imx_add_imx_sdma("imx35-sdma", MX51_SDMA_BASE_ADDR, MX51_INT_SDMA, &imx51_sdma_pdata);
+
+	/* Setup AIPS registers */
+	imx_set_aips(MX51_IO_ADDRESS(MX51_AIPS1_BASE_ADDR));
+	imx_set_aips(MX51_IO_ADDRESS(MX51_AIPS2_BASE_ADDR));
+
+	/* i.mx51 has the i.mx31 type audmux */
+	platform_device_register_simple("imx31-audmux", 0, imx51_audmux_res,
+					ARRAY_SIZE(imx51_audmux_res));
 }
 
 void __init imx53_soc_init(void)
@@ -206,4 +225,12 @@
 
 	/* i.mx53 has the i.mx35 type sdma */
 	imx_add_imx_sdma("imx35-sdma", MX53_SDMA_BASE_ADDR, MX53_INT_SDMA, &imx53_sdma_pdata);
+
+	/* Setup AIPS registers */
+	imx_set_aips(MX53_IO_ADDRESS(MX53_AIPS1_BASE_ADDR));
+	imx_set_aips(MX53_IO_ADDRESS(MX53_AIPS2_BASE_ADDR));
+
+	/* i.mx53 has the i.mx31 type audmux */
+	platform_device_register_simple("imx31-audmux", 0, imx53_audmux_res,
+					ARRAY_SIZE(imx53_audmux_res));
 }
diff --git a/arch/arm/mach-imx/pm-imx27.c b/arch/arm/mach-imx/pm-imx27.c
index e455d2f..6fcffa7 100644
--- a/arch/arm/mach-imx/pm-imx27.c
+++ b/arch/arm/mach-imx/pm-imx27.c
@@ -10,7 +10,6 @@
 #include <linux/kernel.h>
 #include <linux/suspend.h>
 #include <linux/io.h>
-#include <mach/system.h>
 #include <mach/hardware.h>
 
 static int mx27_suspend_enter(suspend_state_t state)
@@ -23,7 +22,7 @@
 		cscr &= 0xFFFFFFFC;
 		__raw_writel(cscr, MX27_IO_ADDRESS(MX27_CCM_BASE_ADDR));
 		/* Executes WFI */
-		arch_idle();
+		cpu_do_idle();
 		break;
 
 	default:
diff --git a/arch/arm/mach-imx/pm-imx3.c b/arch/arm/mach-imx/pm-imx3.c
new file mode 100644
index 0000000..b375243
--- /dev/null
+++ b/arch/arm/mach-imx/pm-imx3.c
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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/io.h>
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+#include "crmregs-imx3.h"
+
+/*
+ * Set cpu low power mode before WFI instruction. This function is called
+ * mx3 because it can be used for mx31 and mx35.
+ * Currently only WAIT_MODE is supported.
+ */
+void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode)
+{
+	int reg = __raw_readl(MXC_CCM_CCMR);
+	reg &= ~MXC_CCM_CCMR_LPM_MASK;
+
+	switch (mode) {
+	case MX3_WAIT:
+		if (cpu_is_mx35())
+			reg |= MXC_CCM_CCMR_LPM_WAIT_MX35;
+		__raw_writel(reg, MXC_CCM_CCMR);
+		break;
+	default:
+		pr_err("Unknown cpu power mode: %d\n", mode);
+		return;
+	}
+}
diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c
index 6dc0934..e26a9cb 100644
--- a/arch/arm/mach-imx/pm-imx5.c
+++ b/arch/arm/mach-imx/pm-imx5.c
@@ -89,7 +89,7 @@
 
 static int mx5_suspend_prepare(void)
 {
-	return clk_enable(gpc_dvfs_clk);
+	return clk_prepare_enable(gpc_dvfs_clk);
 }
 
 static int mx5_suspend_enter(suspend_state_t state)
@@ -119,7 +119,7 @@
 
 static void mx5_suspend_finish(void)
 {
-	clk_disable(gpc_dvfs_clk);
+	clk_disable_unprepare(gpc_dvfs_clk);
 }
 
 static int mx5_pm_valid(suspend_state_t state)
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index 019f0ab..eaf6c63 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -25,9 +25,9 @@
 
 #include <mach/hardware.h>
 #include <mach/platform.h>
-#include <asm/irq.h>
 #include <mach/cm.h>
-#include <asm/system.h>
+#include <mach/irqs.h>
+
 #include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/mach/time.h>
@@ -35,67 +35,23 @@
 
 static struct amba_pl010_data integrator_uart_data;
 
-static struct amba_device rtc_device = {
-	.dev		= {
-		.init_name = "mb:15",
-	},
-	.res		= {
-		.start	= INTEGRATOR_RTC_BASE,
-		.end	= INTEGRATOR_RTC_BASE + SZ_4K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	.irq		= { IRQ_RTCINT, NO_IRQ },
-};
+#define INTEGRATOR_RTC_IRQ	{ IRQ_RTCINT }
+#define INTEGRATOR_UART0_IRQ	{ IRQ_UARTINT0 }
+#define INTEGRATOR_UART1_IRQ	{ IRQ_UARTINT1 }
+#define KMI0_IRQ		{ IRQ_KMIINT0 }
+#define KMI1_IRQ		{ IRQ_KMIINT1 }
 
-static struct amba_device uart0_device = {
-	.dev		= {
-		.init_name = "mb:16",
-		.platform_data = &integrator_uart_data,
-	},
-	.res		= {
-		.start	= INTEGRATOR_UART0_BASE,
-		.end	= INTEGRATOR_UART0_BASE + SZ_4K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	.irq		= { IRQ_UARTINT0, NO_IRQ },
-};
+static AMBA_APB_DEVICE(rtc, "mb:15", 0,
+	INTEGRATOR_RTC_BASE, INTEGRATOR_RTC_IRQ, NULL);
 
-static struct amba_device uart1_device = {
-	.dev		= {
-		.init_name = "mb:17",
-		.platform_data = &integrator_uart_data,
-	},
-	.res		= {
-		.start	= INTEGRATOR_UART1_BASE,
-		.end	= INTEGRATOR_UART1_BASE + SZ_4K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	.irq		= { IRQ_UARTINT1, NO_IRQ },
-};
+static AMBA_APB_DEVICE(uart0, "mb:16", 0,
+	INTEGRATOR_UART0_BASE, INTEGRATOR_UART0_IRQ, &integrator_uart_data);
 
-static struct amba_device kmi0_device = {
-	.dev		= {
-		.init_name = "mb:18",
-	},
-	.res		= {
-		.start	= KMI0_BASE,
-		.end	= KMI0_BASE + SZ_4K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	.irq		= { IRQ_KMIINT0, NO_IRQ },
-};
+static AMBA_APB_DEVICE(uart1, "mb:17", 0,
+	INTEGRATOR_UART1_BASE, INTEGRATOR_UART1_IRQ, &integrator_uart_data);
 
-static struct amba_device kmi1_device = {
-	.dev		= {
-		.init_name = "mb:19",
-	},
-	.res		= {
-		.start	= KMI1_BASE,
-		.end	= KMI1_BASE + SZ_4K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	.irq		= { IRQ_KMIINT1, NO_IRQ },
-};
+static AMBA_APB_DEVICE(kmi0, "mb:18", 0, KMI0_BASE, KMI0_IRQ, NULL);
+static AMBA_APB_DEVICE(kmi1, "mb:19", 0, KMI1_BASE, KMI1_IRQ, NULL);
 
 static struct amba_device *amba_devs[] __initdata = {
 	&rtc_device,
diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c
index 8cbb75a..3e538da 100644
--- a/arch/arm/mach-integrator/impd1.c
+++ b/arch/arm/mach-integrator/impd1.c
@@ -401,24 +401,21 @@
 
 		pc_base = dev->resource.start + idev->offset;
 
-		d = kzalloc(sizeof(struct amba_device), GFP_KERNEL);
+		d = amba_device_alloc(NULL, pc_base, SZ_4K);
 		if (!d)
 			continue;
 
 		dev_set_name(&d->dev, "lm%x:%5.5lx", dev->id, idev->offset >> 12);
 		d->dev.parent	= &dev->dev;
-		d->res.start	= dev->resource.start + idev->offset;
-		d->res.end	= d->res.start + SZ_4K - 1;
-		d->res.flags	= IORESOURCE_MEM;
 		d->irq[0]	= dev->irq;
 		d->irq[1]	= dev->irq;
 		d->periphid	= idev->id;
 		d->dev.platform_data = idev->platform_data;
 
-		ret = amba_device_register(d, &dev->resource);
+		ret = amba_device_add(d, &dev->resource);
 		if (ret) {
 			dev_err(&d->dev, "unable to register device: %d\n", ret);
-			kfree(d);
+			amba_device_put(d);
 		}
 	}
 
diff --git a/arch/arm/mach-integrator/include/mach/entry-macro.S b/arch/arm/mach-integrator/include/mach/entry-macro.S
index 3d029c9..5cc7b85 100644
--- a/arch/arm/mach-integrator/include/mach/entry-macro.S
+++ b/arch/arm/mach-integrator/include/mach/entry-macro.S
@@ -11,15 +11,9 @@
 #include <mach/platform.h>
 #include <mach/irqs.h>
 
- 		.macro	disable_fiq
-		.endm
-
 		.macro  get_irqnr_preamble, base, tmp
 		.endm
 
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
-
 		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 /* FIXME: should not be using soo many LDRs here */
 		ldr	\base, =IO_ADDRESS(INTEGRATOR_IC_BASE)
diff --git a/arch/arm/mach-integrator/include/mach/io.h b/arch/arm/mach-integrator/include/mach/io.h
index 37beed3..8de70de 100644
--- a/arch/arm/mach-integrator/include/mach/io.h
+++ b/arch/arm/mach-integrator/include/mach/io.h
@@ -29,6 +29,5 @@
 #define PCI_IO_VADDR            0xee000000
 
 #define __io(a)			((void __iomem *)(PCI_IO_VADDR + (a)))
-#define __mem_pci(a)		(a)
 
 #endif
diff --git a/arch/arm/mach-integrator/include/mach/irqs.h b/arch/arm/mach-integrator/include/mach/irqs.h
index 1fbe6d1..a19a1a2 100644
--- a/arch/arm/mach-integrator/include/mach/irqs.h
+++ b/arch/arm/mach-integrator/include/mach/irqs.h
@@ -78,5 +78,6 @@
 #define IRQ_SIC_CP_LMINT7		46
 #define IRQ_SIC_END			46
 
-#define NR_IRQS                         47
+#define NR_IRQS_INTEGRATOR_AP		34
+#define NR_IRQS_INTEGRATOR_CP		47
 
diff --git a/arch/arm/mach-integrator/include/mach/system.h b/arch/arm/mach-integrator/include/mach/system.h
deleted file mode 100644
index 901514e..0000000
--- a/arch/arm/mach-integrator/include/mach/system.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  arch/arm/mach-integrator/include/mach/system.h
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	/*
-	 * This should do all the clock switching
-	 * and wait for interrupt tricks
-	 */
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 21a1d6c..871f148 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -38,12 +38,13 @@
 #include <mach/hardware.h>
 #include <mach/platform.h>
 #include <asm/hardware/arm_timer.h>
-#include <asm/irq.h>
 #include <asm/setup.h>
 #include <asm/param.h>		/* HZ */
 #include <asm/mach-types.h>
+#include <asm/sched_clock.h>
 
 #include <mach/lm.h>
+#include <mach/irqs.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
@@ -325,6 +326,11 @@
 
 static unsigned long timer_reload;
 
+static u32 notrace integrator_read_sched_clock(void)
+{
+	return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE);
+}
+
 static void integrator_clocksource_init(unsigned long inrate)
 {
 	void __iomem *base = (void __iomem *)TIMER2_VA_BASE;
@@ -341,6 +347,7 @@
 
 	clocksource_mmio_init(base + TIMER_VALUE, "timer2",
 			rate, 200, 16, clocksource_mmio_readl_down);
+	setup_sched_clock(integrator_read_sched_clock, 16, rate);
 }
 
 static void __iomem * const clkevt_base = (void __iomem *)TIMER1_VA_BASE;
@@ -468,6 +475,7 @@
 	.atag_offset	= 0x100,
 	.reserve	= integrator_reserve,
 	.map_io		= ap_map_io,
+	.nr_irqs	= NR_IRQS_INTEGRATOR_AP,
 	.init_early	= integrator_init_early,
 	.init_irq	= ap_init_irq,
 	.timer		= &ap_timer,
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index a8b6aa6..48a115a 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -26,7 +26,6 @@
 
 #include <mach/hardware.h>
 #include <mach/platform.h>
-#include <asm/irq.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/hardware/arm_timer.h>
@@ -34,6 +33,7 @@
 
 #include <mach/cm.h>
 #include <mach/lm.h>
+#include <mach/irqs.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
@@ -347,32 +347,14 @@
 	.gpio_cd	= -1,
 };
 
-static struct amba_device mmc_device = {
-	.dev		= {
-		.init_name = "mb:1c",
-		.platform_data = &mmc_data,
-	},
-	.res		= {
-		.start	= INTEGRATOR_CP_MMC_BASE,
-		.end	= INTEGRATOR_CP_MMC_BASE + SZ_4K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	.irq		= { IRQ_CP_MMCIINT0, IRQ_CP_MMCIINT1 },
-	.periphid	= 0,
-};
+#define INTEGRATOR_CP_MMC_IRQS	{ IRQ_CP_MMCIINT0, IRQ_CP_MMCIINT1 }
+#define INTEGRATOR_CP_AACI_IRQS	{ IRQ_CP_AACIINT }
 
-static struct amba_device aaci_device = {
-	.dev		= {
-		.init_name = "mb:1d",
-	},
-	.res		= {
-		.start	= INTEGRATOR_CP_AACI_BASE,
-		.end	= INTEGRATOR_CP_AACI_BASE + SZ_4K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	.irq		= { IRQ_CP_AACIINT, NO_IRQ },
-	.periphid	= 0,
-};
+static AMBA_APB_DEVICE(mmc, "mb:1c", 0, INTEGRATOR_CP_MMC_BASE,
+	INTEGRATOR_CP_MMC_IRQS, &mmc_data);
+
+static AMBA_APB_DEVICE(aaci, "mb:1d", 0, INTEGRATOR_CP_AACI_BASE,
+	INTEGRATOR_CP_AACI_IRQS, NULL);
 
 
 /*
@@ -425,21 +407,8 @@
 	.remove		= versatile_clcd_remove_dma,
 };
 
-static struct amba_device clcd_device = {
-	.dev		= {
-		.init_name = "mb:c0",
-		.coherent_dma_mask = ~0,
-		.platform_data = &clcd_data,
-	},
-	.res		= {
-		.start	= INTCP_PA_CLCD_BASE,
-		.end	= INTCP_PA_CLCD_BASE + SZ_4K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	.dma_mask	= ~0,
-	.irq		= { IRQ_CP_CLCDCINT, NO_IRQ },
-	.periphid	= 0,
-};
+static AMBA_AHB_DEVICE(clcd, "mb:c0", 0, INTCP_PA_CLCD_BASE,
+	{ IRQ_CP_CLCDCINT }, &clcd_data);
 
 static struct amba_device *amba_devs[] __initdata = {
 	&mmc_device,
@@ -495,6 +464,7 @@
 	.atag_offset	= 0x100,
 	.reserve	= integrator_reserve,
 	.map_io		= intcp_map_io,
+	.nr_irqs	= NR_IRQS_INTEGRATOR_CP,
 	.init_early	= intcp_init_early,
 	.init_irq	= intcp_init_irq,
 	.timer		= &cp_timer,
diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c
index 28be186..466defa 100644
--- a/arch/arm/mach-integrator/leds.c
+++ b/arch/arm/mach-integrator/leds.c
@@ -29,7 +29,6 @@
 #include <mach/hardware.h>
 #include <mach/platform.h>
 #include <asm/leds.h>
-#include <asm/system.h>
 #include <asm/mach-types.h>
 #include <mach/cm.h>
 
diff --git a/arch/arm/mach-integrator/pci.c b/arch/arm/mach-integrator/pci.c
index 520b6bf..f1ca9c1 100644
--- a/arch/arm/mach-integrator/pci.c
+++ b/arch/arm/mach-integrator/pci.c
@@ -26,11 +26,11 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 
-#include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/mach/pci.h>
 #include <asm/mach-types.h>
 
+#include <mach/irqs.h>
+
 /* 
  * A small note about bridges and interrupts.  The DECchip 21050 (and
  * later) adheres to the PCI-PCI bridge specification.  This says that
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
index 3c82566..67e6f9a 100644
--- a/arch/arm/mach-integrator/pci_v3.c
+++ b/arch/arm/mach-integrator/pci_v3.c
@@ -30,9 +30,9 @@
 
 #include <mach/hardware.h>
 #include <mach/platform.h>
-#include <asm/irq.h>
+#include <mach/irqs.h>
+
 #include <asm/signal.h>
-#include <asm/system.h>
 #include <asm/mach/pci.h>
 #include <asm/irq_regs.h>
 
@@ -378,9 +378,10 @@
 	 * the mem resource for this bus
 	 * the prefetch mem resource for this bus
 	 */
-	pci_add_resource(&sys->resources, &ioport_resource);
-	pci_add_resource(&sys->resources, &non_mem);
-	pci_add_resource(&sys->resources, &pre_mem);
+	pci_add_resource_offset(&sys->resources,
+				&ioport_resource, sys->io_offset);
+	pci_add_resource_offset(&sys->resources, &non_mem, sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, &pre_mem, sys->mem_offset);
 
 	return 1;
 }
diff --git a/arch/arm/mach-iop13xx/include/mach/entry-macro.S b/arch/arm/mach-iop13xx/include/mach/entry-macro.S
index a624a78..1a2d603 100644
--- a/arch/arm/mach-iop13xx/include/mach/entry-macro.S
+++ b/arch/arm/mach-iop13xx/include/mach/entry-macro.S
@@ -16,9 +16,6 @@
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  *
  */
-	.macro  disable_fiq
-	.endm
-
 	.macro get_irqnr_preamble, base, tmp
 	mrc	p15, 0, \tmp, c15, c1, 0
 	orr	\tmp, \tmp, #(1 << 6)
diff --git a/arch/arm/mach-iop13xx/include/mach/io.h b/arch/arm/mach-iop13xx/include/mach/io.h
index dffb234..f131885 100644
--- a/arch/arm/mach-iop13xx/include/mach/io.h
+++ b/arch/arm/mach-iop13xx/include/mach/io.h
@@ -22,20 +22,7 @@
 #define IO_SPACE_LIMIT 0xffffffff
 
 #define __io(a) __iop13xx_io(a)
-#define __mem_pci(a) (a)
-#define __mem_isa(a) (a)
 
 extern void __iomem * __iop13xx_io(unsigned long io_addr);
-extern void __iomem *__iop13xx_ioremap(unsigned long cookie, size_t size,
-	unsigned int mtype);
-extern void __iop13xx_iounmap(void __iomem *addr);
-
-extern u32 iop13xx_atue_mem_base;
-extern u32 iop13xx_atux_mem_base;
-extern size_t iop13xx_atue_mem_size;
-extern size_t iop13xx_atux_mem_size;
-
-#define __arch_ioremap	__iop13xx_ioremap
-#define __arch_iounmap	__iop13xx_iounmap
 
 #endif
diff --git a/arch/arm/mach-iop13xx/include/mach/iop13xx.h b/arch/arm/mach-iop13xx/include/mach/iop13xx.h
index 07e9ff7..e190dcd 100644
--- a/arch/arm/mach-iop13xx/include/mach/iop13xx.h
+++ b/arch/arm/mach-iop13xx/include/mach/iop13xx.h
@@ -5,6 +5,7 @@
 /* The ATU offsets can change based on the strapping */
 extern u32 iop13xx_atux_pmmr_offset;
 extern u32 iop13xx_atue_pmmr_offset;
+void iop13xx_init_early(void);
 void iop13xx_init_irq(void);
 void iop13xx_map_io(void);
 void iop13xx_platform_init(void);
diff --git a/arch/arm/mach-iop13xx/include/mach/system.h b/arch/arm/mach-iop13xx/include/mach/system.h
deleted file mode 100644
index 1f31ed3..0000000
--- a/arch/arm/mach-iop13xx/include/mach/system.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-iop13xx/include/mach/system.h
- *
- *  Copyright (C) 2004 Intel Corp.
- *
- * 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.
- */
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
diff --git a/arch/arm/mach-iop13xx/io.c b/arch/arm/mach-iop13xx/io.c
index 48642e6..3c36419 100644
--- a/arch/arm/mach-iop13xx/io.c
+++ b/arch/arm/mach-iop13xx/io.c
@@ -21,6 +21,8 @@
 #include <linux/io.h>
 #include <mach/hardware.h>
 
+#include "pci.h"
+
 void * __iomem __iop13xx_io(unsigned long io_addr)
 {
 	void __iomem * io_virt;
@@ -40,8 +42,8 @@
 }
 EXPORT_SYMBOL(__iop13xx_io);
 
-void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size,
-	unsigned int mtype)
+static void __iomem *__iop13xx_ioremap_caller(unsigned long cookie,
+	size_t size, unsigned int mtype, void *caller)
 {
 	void __iomem * retval;
 
@@ -76,17 +78,14 @@
 		break;
 	default:
 		retval = __arm_ioremap_caller(cookie, size, mtype,
-				__builtin_return_address(0));
+				caller);
 	}
 
 	return retval;
 }
-EXPORT_SYMBOL(__iop13xx_ioremap);
 
-void __iop13xx_iounmap(void __iomem *addr)
+static void __iop13xx_iounmap(volatile void __iomem *addr)
 {
-	extern void __iounmap(volatile void __iomem *addr);
-
 	if (iop13xx_atue_mem_base)
 		if (addr >= (void __iomem *) iop13xx_atue_mem_base &&
 	 	    addr < (void __iomem *) (iop13xx_atue_mem_base +
@@ -110,4 +109,9 @@
 skip:
 	return;
 }
-EXPORT_SYMBOL(__iop13xx_iounmap);
+
+void __init iop13xx_init_early(void)
+{
+	arch_ioremap_caller = __iop13xx_ioremap_caller;
+	arch_iounmap = __iop13xx_iounmap;
+}
diff --git a/arch/arm/mach-iop13xx/iq81340mc.c b/arch/arm/mach-iop13xx/iq81340mc.c
index abaee88..5c96b73 100644
--- a/arch/arm/mach-iop13xx/iq81340mc.c
+++ b/arch/arm/mach-iop13xx/iq81340mc.c
@@ -92,6 +92,7 @@
 MACHINE_START(IQ81340MC, "Intel IQ81340MC")
 	/* Maintainer: Dan Williams <dan.j.williams@intel.com> */
 	.atag_offset    = 0x100,
+	.init_early     = iop13xx_init_early,
 	.map_io         = iop13xx_map_io,
 	.init_irq       = iop13xx_init_irq,
 	.timer          = &iq81340mc_timer,
diff --git a/arch/arm/mach-iop13xx/iq81340sc.c b/arch/arm/mach-iop13xx/iq81340sc.c
index 690916a..aa4dd75 100644
--- a/arch/arm/mach-iop13xx/iq81340sc.c
+++ b/arch/arm/mach-iop13xx/iq81340sc.c
@@ -94,6 +94,7 @@
 MACHINE_START(IQ81340SC, "Intel IQ81340SC")
 	/* Maintainer: Dan Williams <dan.j.williams@intel.com> */
 	.atag_offset    = 0x100,
+	.init_early     = iop13xx_init_early,
 	.map_io         = iop13xx_map_io,
 	.init_irq       = iop13xx_init_irq,
 	.timer          = &iq81340sc_timer,
diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c
index b8f5a87..861cb12 100644
--- a/arch/arm/mach-iop13xx/pci.c
+++ b/arch/arm/mach-iop13xx/pci.c
@@ -1084,8 +1084,8 @@
 	request_resource(&ioport_resource, &res[0]);
 	request_resource(&iomem_resource, &res[1]);
 
-	pci_add_resource(&sys->resources, &res[0]);
-	pci_add_resource(&sys->resources, &res[1]);
+	pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
+	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
 
 	return 1;
 }
diff --git a/arch/arm/mach-iop13xx/pci.h b/arch/arm/mach-iop13xx/pci.h
new file mode 100644
index 0000000..c70cf5b
--- /dev/null
+++ b/arch/arm/mach-iop13xx/pci.h
@@ -0,0 +1,6 @@
+#include <linux/types.h>
+
+extern u32 iop13xx_atue_mem_base;
+extern u32 iop13xx_atux_mem_base;
+extern size_t iop13xx_atue_mem_size;
+extern size_t iop13xx_atux_mem_size;
diff --git a/arch/arm/mach-iop32x/include/mach/entry-macro.S b/arch/arm/mach-iop32x/include/mach/entry-macro.S
index b02fb56..ea13ae0 100644
--- a/arch/arm/mach-iop32x/include/mach/entry-macro.S
+++ b/arch/arm/mach-iop32x/include/mach/entry-macro.S
@@ -9,9 +9,6 @@
  */
 #include <mach/iop32x.h>
 
-	.macro	disable_fiq
-	.endm
-
 	.macro get_irqnr_preamble, base, tmp
 	mrc	p15, 0, \tmp, c15, c1, 0
 	orr	\tmp, \tmp, #(1 << 6)
diff --git a/arch/arm/mach-iop32x/include/mach/io.h b/arch/arm/mach-iop32x/include/mach/io.h
index 2d88264..e2ada26 100644
--- a/arch/arm/mach-iop32x/include/mach/io.h
+++ b/arch/arm/mach-iop32x/include/mach/io.h
@@ -15,6 +15,5 @@
 
 #define IO_SPACE_LIMIT		0xffffffff
 #define __io(p)		((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p))
-#define __mem_pci(a)		(a)
 
 #endif
diff --git a/arch/arm/mach-iop32x/include/mach/system.h b/arch/arm/mach-iop32x/include/mach/system.h
deleted file mode 100644
index 4a88727..0000000
--- a/arch/arm/mach-iop32x/include/mach/system.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-iop32x/include/mach/system.h
- *
- * Copyright (C) 2001 MontaVista Software, 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.
- */
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
diff --git a/arch/arm/mach-iop33x/include/mach/entry-macro.S b/arch/arm/mach-iop33x/include/mach/entry-macro.S
index 4e1f728..0a398fe 100644
--- a/arch/arm/mach-iop33x/include/mach/entry-macro.S
+++ b/arch/arm/mach-iop33x/include/mach/entry-macro.S
@@ -9,9 +9,6 @@
  */
 #include <mach/iop33x.h>
 
-	.macro	disable_fiq
-	.endm
-
 	.macro get_irqnr_preamble, base, tmp
 	mrc	p15, 0, \tmp, c15, c1, 0
 	orr	\tmp, \tmp, #(1 << 6)
diff --git a/arch/arm/mach-iop33x/include/mach/io.h b/arch/arm/mach-iop33x/include/mach/io.h
index a8a66fc..f7c1b65 100644
--- a/arch/arm/mach-iop33x/include/mach/io.h
+++ b/arch/arm/mach-iop33x/include/mach/io.h
@@ -15,6 +15,5 @@
 
 #define IO_SPACE_LIMIT		0xffffffff
 #define __io(p)		((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p))
-#define __mem_pci(a)		(a)
 
 #endif
diff --git a/arch/arm/mach-iop33x/include/mach/system.h b/arch/arm/mach-iop33x/include/mach/system.h
deleted file mode 100644
index 4f98e76..0000000
--- a/arch/arm/mach-iop33x/include/mach/system.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-iop33x/include/mach/system.h
- *
- * Copyright (C) 2001 MontaVista Software, 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.
- */
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
diff --git a/arch/arm/mach-iop33x/uart.c b/arch/arm/mach-iop33x/uart.c
index cdae24e..bbf54d79 100644
--- a/arch/arm/mach-iop33x/uart.c
+++ b/arch/arm/mach-iop33x/uart.c
@@ -22,7 +22,6 @@
 #include <asm/page.h>
 #include <asm/mach/map.h>
 #include <asm/setup.h>
-#include <asm/system.h>
 #include <asm/memory.h>
 #include <mach/hardware.h>
 #include <asm/hardware/iop3xx.h>
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index 81c4537..f214cdf 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -32,7 +32,6 @@
 #include <asm/memory.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/tlbflush.h>
 #include <asm/pgtable.h>
 
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
index e872d23..4867f40 100644
--- a/arch/arm/mach-ixp2000/enp2611.c
+++ b/arch/arm/mach-ixp2000/enp2611.c
@@ -36,7 +36,6 @@
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-ixp2000/include/mach/entry-macro.S b/arch/arm/mach-ixp2000/include/mach/entry-macro.S
index 5850ffc..c4444df 100644
--- a/arch/arm/mach-ixp2000/include/mach/entry-macro.S
+++ b/arch/arm/mach-ixp2000/include/mach/entry-macro.S
@@ -9,15 +9,9 @@
  */
 #include <mach/irqs.h>
 
-		.macro  disable_fiq
-		.endm
-
 		.macro  get_irqnr_preamble, base, tmp
 		.endm
 
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
-
 		.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 
 		mov	\irqnr, #0x0              @clear out irqnr as default
diff --git a/arch/arm/mach-ixp2000/include/mach/io.h b/arch/arm/mach-ixp2000/include/mach/io.h
index 859e5849..f6552d6 100644
--- a/arch/arm/mach-ixp2000/include/mach/io.h
+++ b/arch/arm/mach-ixp2000/include/mach/io.h
@@ -18,7 +18,6 @@
 #include <mach/hardware.h>
 
 #define IO_SPACE_LIMIT		0xffffffff
-#define __mem_pci(a)		(a)
 
 /*
  * The A? revisions of the IXP2000s assert byte lanes for PCI I/O
diff --git a/arch/arm/mach-ixp2000/include/mach/system.h b/arch/arm/mach-ixp2000/include/mach/system.h
deleted file mode 100644
index a7fb08b..0000000
--- a/arch/arm/mach-ixp2000/include/mach/system.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/system.h
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyricht (C) 2003-2005 MontaVista Software, 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.
- */
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
diff --git a/arch/arm/mach-ixp2000/ixdp2400.c b/arch/arm/mach-ixp2000/ixdp2400.c
index f53e911..915ad49 100644
--- a/arch/arm/mach-ixp2000/ixdp2400.c
+++ b/arch/arm/mach-ixp2000/ixdp2400.c
@@ -29,7 +29,6 @@
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 
@@ -134,11 +133,11 @@
 
 	if (ixdp2x00_master_npu()) {
 		dev = pci_get_bus_and_slot(1, IXDP2400_SLAVE_ENET_DEVFN);
-		pci_remove_bus_device(dev);
+		pci_stop_and_remove_bus_device(dev);
 		pci_dev_put(dev);
 	} else {
 		dev = pci_get_bus_and_slot(1, IXDP2400_MASTER_ENET_DEVFN);
-		pci_remove_bus_device(dev);
+		pci_stop_and_remove_bus_device(dev);
 		pci_dev_put(dev);
 
 		ixdp2x00_slave_pci_postinit();
diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c
index a2e7c39..a9f1819 100644
--- a/arch/arm/mach-ixp2000/ixdp2800.c
+++ b/arch/arm/mach-ixp2000/ixdp2800.c
@@ -29,7 +29,6 @@
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 
@@ -262,14 +261,14 @@
 		pci_common_init(&ixdp2800_pci);
 		if (ixdp2x00_master_npu()) {
 			dev = pci_get_bus_and_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
-			pci_remove_bus_device(dev);
+			pci_stop_and_remove_bus_device(dev);
 			pci_dev_put(dev);
 
 			ixdp2800_master_enable_slave();
 			ixdp2800_master_wait_for_slave_bus_scan();
 		} else {
 			dev = pci_get_bus_and_slot(1, IXDP2800_MASTER_ENET_DEVFN);
-			pci_remove_bus_device(dev);
+			pci_stop_and_remove_bus_device(dev);
 			pci_dev_put(dev);
 		}
 	}
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
index 634b6c8..421e38d 100644
--- a/arch/arm/mach-ixp2000/ixdp2x00.c
+++ b/arch/arm/mach-ixp2000/ixdp2x00.c
@@ -30,7 +30,6 @@
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 
@@ -239,12 +238,12 @@
 	 * Remove PMC device is there is one
 	 */
 	if((dev = pci_get_bus_and_slot(1, IXDP2X00_PMC_DEVFN))) {
-		pci_remove_bus_device(dev);
+		pci_stop_and_remove_bus_device(dev);
 		pci_dev_put(dev);
 	}
 
 	dev = pci_get_bus_and_slot(0, IXDP2X00_21555_DEVFN);
-	pci_remove_bus_device(dev);
+	pci_stop_and_remove_bus_device(dev);
 	pci_dev_put(dev);
 }
 
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
index 7632bea..5196c39 100644
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -34,7 +34,6 @@
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c
index 626fda4..9c02de9 100644
--- a/arch/arm/mach-ixp2000/pci.c
+++ b/arch/arm/mach-ixp2000/pci.c
@@ -26,7 +26,6 @@
 #include <linux/io.h>
 
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <mach/hardware.h>
 
 #include <asm/mach/pci.h>
@@ -243,8 +242,10 @@
 	if (nr >= 1)
 		return 0;
 
-	pci_add_resource(&sys->resources, &ixp2000_pci_io_space);
-	pci_add_resource(&sys->resources, &ixp2000_pci_mem_space);
+	pci_add_resource_offset(&sys->resources,
+				&ixp2000_pci_io_space, sys->io_offset);
+	pci_add_resource_offset(&sys->resources,
+				&ixp2000_pci_mem_space, sys->mem_offset);
 
 	return 1;
 }
diff --git a/arch/arm/mach-ixp23xx/core.c b/arch/arm/mach-ixp23xx/core.c
index 0923bb9..d345424 100644
--- a/arch/arm/mach-ixp23xx/core.c
+++ b/arch/arm/mach-ixp23xx/core.c
@@ -34,9 +34,9 @@
 #include <asm/memory.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/tlbflush.h>
 #include <asm/pgtable.h>
+#include <asm/system_misc.h>
 
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
@@ -441,6 +441,9 @@
 
 void __init ixp23xx_sys_init(void)
 {
+	/* by default, the idle code is disabled */
+	disable_hlt();
+
 	*IXP23XX_EXP_UNIT_FUSE |= 0xf;
 	platform_add_devices(ixp23xx_devices, ARRAY_SIZE(ixp23xx_devices));
 }
diff --git a/arch/arm/mach-ixp23xx/espresso.c b/arch/arm/mach-ixp23xx/espresso.c
index 8f2487e..d142d45 100644
--- a/arch/arm/mach-ixp23xx/espresso.c
+++ b/arch/arm/mach-ixp23xx/espresso.c
@@ -32,7 +32,6 @@
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/tlbflush.h>
 #include <asm/pgtable.h>
 
diff --git a/arch/arm/mach-ixp23xx/include/mach/entry-macro.S b/arch/arm/mach-ixp23xx/include/mach/entry-macro.S
index 3f5338a..3fd2cb9 100644
--- a/arch/arm/mach-ixp23xx/include/mach/entry-macro.S
+++ b/arch/arm/mach-ixp23xx/include/mach/entry-macro.S
@@ -2,15 +2,9 @@
  * arch/arm/mach-ixp23xx/include/mach/entry-macro.S
  */
 
-		.macro	disable_fiq
-		.endm
-
 		.macro  get_irqnr_preamble, base, tmp
 		.endm
 
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
-
 		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 		ldr	\irqnr, =(IXP23XX_INTC_VIRT + IXP23XX_INTR_IRQ_ENC_ST_OFFSET)
 		ldr	\irqnr, [\irqnr]	@ get interrupt number
diff --git a/arch/arm/mach-ixp23xx/include/mach/io.h b/arch/arm/mach-ixp23xx/include/mach/io.h
index 4ce4353..a7aceb5 100644
--- a/arch/arm/mach-ixp23xx/include/mach/io.h
+++ b/arch/arm/mach-ixp23xx/include/mach/io.h
@@ -18,6 +18,5 @@
 #define IO_SPACE_LIMIT 0xffffffff
 
 #define __io(p)		((void __iomem*)((p) + IXP23XX_PCI_IO_VIRT))
-#define __mem_pci(a)	(a)
 
 #endif
diff --git a/arch/arm/mach-ixp23xx/include/mach/system.h b/arch/arm/mach-ixp23xx/include/mach/system.h
deleted file mode 100644
index 277dda7..0000000
--- a/arch/arm/mach-ixp23xx/include/mach/system.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/system.h
- *
- * Copyright (C) 2003 Intel Corporation.
- *
- * 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.
- */
-static inline void arch_idle(void)
-{
-#if 0
-	if (!hlt_counter)
-		cpu_do_idle();
-#endif
-}
diff --git a/arch/arm/mach-ixp23xx/ixdp2351.c b/arch/arm/mach-ixp23xx/ixdp2351.c
index 5d5dd3e..b0e07db 100644
--- a/arch/arm/mach-ixp23xx/ixdp2351.c
+++ b/arch/arm/mach-ixp23xx/ixdp2351.c
@@ -36,7 +36,6 @@
 #include <asm/memory.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/system.h>
 #include <asm/tlbflush.h>
 #include <asm/pgtable.h>
 
diff --git a/arch/arm/mach-ixp23xx/pci.c b/arch/arm/mach-ixp23xx/pci.c
index 25b5c46..911f5a5 100644
--- a/arch/arm/mach-ixp23xx/pci.c
+++ b/arch/arm/mach-ixp23xx/pci.c
@@ -28,7 +28,6 @@
 
 #include <asm/irq.h>
 #include <asm/sizes.h>
-#include <asm/system.h>
 #include <asm/mach/pci.h>
 #include <mach/hardware.h>
 
@@ -281,8 +280,10 @@
 	if (nr >= 1)
 		return 0;
 
-	pci_add_resource(&sys->resources, &ixp23xx_pci_io_space);
-	pci_add_resource(&sys->resources, &ixp23xx_pci_mem_space);
+	pci_add_resource_offset(&sys->resources,
+				&ixp23xx_pci_io_space, sys->io_offset);
+	pci_add_resource_offset(&sys->resources,
+				&ixp23xx_pci_mem_space, sys->mem_offset);
 
 	return 1;
 }
diff --git a/arch/arm/mach-ixp23xx/roadrunner.c b/arch/arm/mach-ixp23xx/roadrunner.c
index 377283f..eaaa3fa 100644
--- a/arch/arm/mach-ixp23xx/roadrunner.c
+++ b/arch/arm/mach-ixp23xx/roadrunner.c
@@ -36,7 +36,6 @@
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/tlbflush.h>
 #include <asm/pgtable.h>
 
diff --git a/arch/arm/mach-ixp4xx/avila-setup.c b/arch/arm/mach-ixp4xx/avila-setup.c
index a7277ad..90e42e9 100644
--- a/arch/arm/mach-ixp4xx/avila-setup.c
+++ b/arch/arm/mach-ixp4xx/avila-setup.c
@@ -165,6 +165,7 @@
 MACHINE_START(AVILA, "Gateworks Avila Network Platform")
 	/* Maintainer: Deepak Saxena <dsaxena@plexity.net> */
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.atag_offset	= 0x100,
@@ -184,6 +185,7 @@
 MACHINE_START(LOFT, "Giant Shoulder Inc Loft board")
 	/* Maintainer: Tom Billman <kernel@giantshoulderinc.com> */
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c
index 5eff15f..d5719eb 100644
--- a/arch/arm/mach-ixp4xx/common-pci.c
+++ b/arch/arm/mach-ixp4xx/common-pci.c
@@ -32,7 +32,6 @@
 #include <asm/cputype.h>
 #include <asm/irq.h>
 #include <asm/sizes.h>
-#include <asm/system.h>
 #include <asm/mach/pci.h>
 #include <mach/hardware.h>
 
@@ -472,8 +471,8 @@
 	request_resource(&ioport_resource, &res[0]);
 	request_resource(&iomem_resource, &res[1]);
 
-	pci_add_resource(&sys->resources, &res[0]);
-	pci_add_resource(&sys->resources, &res[1]);
+	pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
+	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
 
 	platform_notify = ixp4xx_pci_platform_notify;
 	platform_notify_remove = ixp4xx_pci_platform_notify_remove;
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 3841ab4..ebbd7fc 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -31,11 +31,13 @@
 
 #include <mach/udc.h>
 #include <mach/hardware.h>
+#include <mach/io.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/irq.h>
 #include <asm/sched_clock.h>
+#include <asm/system_misc.h>
 
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
@@ -236,6 +238,12 @@
 {
 	int i = 0;
 
+	/*
+	 * ixp4xx does not implement the XScale PWRMODE register
+	 * so it must not call cpu_do_idle().
+	 */
+	disable_hlt();
+
 	/* Route all sources to IRQ instead of FIQ */
 	*IXP4XX_ICLR = 0x0;
 
@@ -511,3 +519,35 @@
 		*IXP4XX_OSWE = IXP4XX_WDT_RESET_ENABLE | IXP4XX_WDT_COUNT_ENABLE;
 	}
 }
+
+#ifdef CONFIG_IXP4XX_INDIRECT_PCI
+/*
+ * In the case of using indirect PCI, we simply return the actual PCI
+ * address and our read/write implementation use that to drive the
+ * access registers. If something outside of PCI is ioremap'd, we
+ * fallback to the default.
+ */
+
+static void __iomem *ixp4xx_ioremap_caller(unsigned long addr, size_t size,
+					   unsigned int mtype, void *caller)
+{
+	if (!is_pci_memory(addr))
+		return __arm_ioremap_caller(addr, size, mtype, caller);
+
+	return (void __iomem *)addr;
+}
+
+static void ixp4xx_iounmap(void __iomem *addr)
+{
+	if (!is_pci_memory((__force u32)addr))
+		__iounmap(addr);
+}
+
+void __init ixp4xx_init_early(void)
+{
+	arch_ioremap_caller = ixp4xx_ioremap_caller;
+	arch_iounmap = ixp4xx_iounmap;
+}
+#else
+void __init ixp4xx_init_early(void) {}
+#endif
diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c
index a74f86c..1b83110 100644
--- a/arch/arm/mach-ixp4xx/coyote-setup.c
+++ b/arch/arm/mach-ixp4xx/coyote-setup.c
@@ -110,6 +110,7 @@
 MACHINE_START(ADI_COYOTE, "ADI Engineering Coyote")
 	/* Maintainer: MontaVista Software, Inc. */
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.atag_offset	= 0x100,
@@ -129,6 +130,7 @@
 MACHINE_START(IXDPG425, "Intel IXDPG425")
 	/* Maintainer: MontaVista Software, Inc. */
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c
index 67be177..97a0af8 100644
--- a/arch/arm/mach-ixp4xx/dsmg600-setup.c
+++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c
@@ -280,6 +280,7 @@
 	/* Maintainer: www.nslu2-linux.org */
 	.atag_offset	= 0x100,
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer          = &dsmg600_timer,
 	.init_machine	= dsmg600_init,
diff --git a/arch/arm/mach-ixp4xx/fsg-setup.c b/arch/arm/mach-ixp4xx/fsg-setup.c
index 6d58182..9175a25 100644
--- a/arch/arm/mach-ixp4xx/fsg-setup.c
+++ b/arch/arm/mach-ixp4xx/fsg-setup.c
@@ -270,6 +270,7 @@
 MACHINE_START(FSG, "Freecom FSG-3")
 	/* Maintainer: www.nslu2-linux.org */
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-ixp4xx/gateway7001-setup.c b/arch/arm/mach-ixp4xx/gateway7001-setup.c
index 7ecf9b2..033c717 100644
--- a/arch/arm/mach-ixp4xx/gateway7001-setup.c
+++ b/arch/arm/mach-ixp4xx/gateway7001-setup.c
@@ -97,6 +97,7 @@
 MACHINE_START(GATEWAY7001, "Gateway 7001 AP")
 	/* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-ixp4xx/goramo_mlr.c b/arch/arm/mach-ixp4xx/goramo_mlr.c
index c0e3d69..46bb924 100644
--- a/arch/arm/mach-ixp4xx/goramo_mlr.c
+++ b/arch/arm/mach-ixp4xx/goramo_mlr.c
@@ -12,7 +12,6 @@
 #include <linux/pci.h>
 #include <linux/serial_8250.h>
 #include <asm/mach-types.h>
-#include <asm/system.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 #include <asm/mach/pci.h>
@@ -497,6 +496,7 @@
 MACHINE_START(GORAMO_MLR, "MultiLink")
 	/* Maintainer: Krzysztof Halasa */
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-ixp4xx/gtwx5715-setup.c b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
index a23f893..18ebc6b 100644
--- a/arch/arm/mach-ixp4xx/gtwx5715-setup.c
+++ b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
@@ -165,6 +165,7 @@
 MACHINE_START(GTWX5715, "Gemtek GTWX5715 (Linksys WRV54G)")
 	/* Maintainer: George Joseph */
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-ixp4xx/include/mach/entry-macro.S b/arch/arm/mach-ixp4xx/include/mach/entry-macro.S
index f2e14e9..79adf83 100644
--- a/arch/arm/mach-ixp4xx/include/mach/entry-macro.S
+++ b/arch/arm/mach-ixp4xx/include/mach/entry-macro.S
@@ -9,15 +9,9 @@
  */
 #include <mach/hardware.h>
 
-		.macro	disable_fiq
-		.endm
-
 		.macro  get_irqnr_preamble, base, tmp
 		.endm
 
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
-
 		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 		ldr	\irqstat, =(IXP4XX_INTC_BASE_VIRT+IXP4XX_ICIP_OFFSET)
 		ldr	\irqstat, [\irqstat]		@ get interrupts
diff --git a/arch/arm/mach-ixp4xx/include/mach/hardware.h b/arch/arm/mach-ixp4xx/include/mach/hardware.h
index c30e7e9..034bb2a 100644
--- a/arch/arm/mach-ixp4xx/include/mach/hardware.h
+++ b/arch/arm/mach-ixp4xx/include/mach/hardware.h
@@ -23,8 +23,6 @@
 #define PCIBIOS_MAX_MEM		0x4BFFFFFF
 #endif
 
-#define ARCH_HAS_DMA_SET_COHERENT_MASK
-
 /* Register locations and bits */
 #include "ixp4xx-regs.h"
 
diff --git a/arch/arm/mach-ixp4xx/include/mach/io.h b/arch/arm/mach-ixp4xx/include/mach/io.h
index ffb9d6a..5cf30d1 100644
--- a/arch/arm/mach-ixp4xx/include/mach/io.h
+++ b/arch/arm/mach-ixp4xx/include/mach/io.h
@@ -39,11 +39,7 @@
  *    but in some cases the performance hit is acceptable. In addition, you
  *    cannot mmap() PCI devices in this case.
  */
-#ifndef	CONFIG_IXP4XX_INDIRECT_PCI
-
-#define __mem_pci(a)		(a)
-
-#else
+#ifdef	CONFIG_IXP4XX_INDIRECT_PCI
 
 /*
  * In the case of using indirect PCI, we simply return the actual PCI
@@ -57,24 +53,6 @@
 	return (addr >= PCIBIOS_MIN_MEM) && (addr <= 0x4FFFFFFF);
 }
 
-static inline void __iomem * __indirect_ioremap(unsigned long addr, size_t size,
-						unsigned int mtype)
-{
-	if (!is_pci_memory(addr))
-		return __arm_ioremap(addr, size, mtype);
-
-	return (void __iomem *)addr;
-}
-
-static inline void __indirect_iounmap(void __iomem *addr)
-{
-	if (!is_pci_memory((__force u32)addr))
-		__iounmap(addr);
-}
-
-#define __arch_ioremap			__indirect_ioremap
-#define __arch_iounmap			__indirect_iounmap
-
 #define writeb(v, p)			__indirect_writeb(v, p)
 #define writew(v, p)			__indirect_writew(v, p)
 #define writel(v, p)			__indirect_writel(v, p)
diff --git a/arch/arm/mach-ixp4xx/include/mach/platform.h b/arch/arm/mach-ixp4xx/include/mach/platform.h
index df9250b..b66bedc 100644
--- a/arch/arm/mach-ixp4xx/include/mach/platform.h
+++ b/arch/arm/mach-ixp4xx/include/mach/platform.h
@@ -121,6 +121,7 @@
  * Functions used by platform-level setup code
  */
 extern void ixp4xx_map_io(void);
+extern void ixp4xx_init_early(void);
 extern void ixp4xx_init_irq(void);
 extern void ixp4xx_sys_init(void);
 extern void ixp4xx_timer_init(void);
diff --git a/arch/arm/mach-ixp4xx/include/mach/system.h b/arch/arm/mach-ixp4xx/include/mach/system.h
deleted file mode 100644
index 140a9be..0000000
--- a/arch/arm/mach-ixp4xx/include/mach/system.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/include/mach/system.h
- *
- * Copyright (C) 2002 Intel Corporation.
- *
- * 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.
- *
- */
-static inline void arch_idle(void)
-{
-	/* ixp4xx does not implement the XScale PWRMODE register,
-	 * so it must not call cpu_do_idle() here.
-	 */
-#if 0
-	cpu_do_idle();
-#endif
-}
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index 8a38b39..3d742ae 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -254,6 +254,7 @@
 MACHINE_START(IXDP425, "Intel IXDP425 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.atag_offset	= 0x100,
@@ -269,6 +270,7 @@
 MACHINE_START(IXDP465, "Intel IXDP465 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.atag_offset	= 0x100,
@@ -283,6 +285,7 @@
 MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.atag_offset	= 0x100,
@@ -297,6 +300,7 @@
 MACHINE_START(KIXRP435, "Intel KIXRP435 Reference Platform")
 	/* Maintainer: MontaVista Software, Inc. */
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c
index 1010eb7..33cb095 100644
--- a/arch/arm/mach-ixp4xx/nas100d-setup.c
+++ b/arch/arm/mach-ixp4xx/nas100d-setup.c
@@ -315,6 +315,7 @@
 	/* Maintainer: www.nslu2-linux.org */
 	.atag_offset	= 0x100,
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer          = &ixp4xx_timer,
 	.init_machine	= nas100d_init,
diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c
index aa355c3..e2903fa 100644
--- a/arch/arm/mach-ixp4xx/nslu2-setup.c
+++ b/arch/arm/mach-ixp4xx/nslu2-setup.c
@@ -301,6 +301,7 @@
 	/* Maintainer: www.nslu2-linux.org */
 	.atag_offset	= 0x100,
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer          = &nslu2_timer,
 	.init_machine	= nslu2_init,
diff --git a/arch/arm/mach-ixp4xx/omixp-setup.c b/arch/arm/mach-ixp4xx/omixp-setup.c
index 0940869..158ddb7 100644
--- a/arch/arm/mach-ixp4xx/omixp-setup.c
+++ b/arch/arm/mach-ixp4xx/omixp-setup.c
@@ -243,6 +243,7 @@
 MACHINE_START(DEVIXP, "Omicron DEVIXP")
 	.atag_offset    = 0x100,
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer          = &ixp4xx_timer,
 	.init_machine	= omixp_init,
@@ -254,6 +255,7 @@
 MACHINE_START(MICCPT, "Omicron MICCPT")
 	.atag_offset    = 0x100,
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer          = &ixp4xx_timer,
 	.init_machine	= omixp_init,
@@ -268,6 +270,7 @@
 MACHINE_START(MIC256, "Omicron MIC256")
 	.atag_offset    = 0x100,
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer          = &ixp4xx_timer,
 	.init_machine	= omixp_init,
diff --git a/arch/arm/mach-ixp4xx/vulcan-setup.c b/arch/arm/mach-ixp4xx/vulcan-setup.c
index 9dec206..2798f43 100644
--- a/arch/arm/mach-ixp4xx/vulcan-setup.c
+++ b/arch/arm/mach-ixp4xx/vulcan-setup.c
@@ -237,6 +237,7 @@
 MACHINE_START(ARCOM_VULCAN, "Arcom/Eurotech Vulcan")
 	/* Maintainer: Marc Zyngier <maz@misterjones.org> */
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-ixp4xx/wg302v2-setup.c b/arch/arm/mach-ixp4xx/wg302v2-setup.c
index 5ac0f0a..a785175 100644
--- a/arch/arm/mach-ixp4xx/wg302v2-setup.c
+++ b/arch/arm/mach-ixp4xx/wg302v2-setup.c
@@ -98,6 +98,7 @@
 MACHINE_START(WG302V2, "Netgear WG302 v2 / WAG302 v2")
 	/* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
 	.map_io		= ixp4xx_map_io,
+	.init_early	= ixp4xx_init_early,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.atag_offset	= 0x100,
diff --git a/arch/arm/mach-kirkwood/Kconfig b/arch/arm/mach-kirkwood/Kconfig
index 7fc603b..90ceab7 100644
--- a/arch/arm/mach-kirkwood/Kconfig
+++ b/arch/arm/mach-kirkwood/Kconfig
@@ -44,6 +44,20 @@
 	  Say 'Y' here if you want your kernel to support the
 	  Marvell GuruPlug Reference Board.
 
+config ARCH_KIRKWOOD_DT
+	bool "Marvell Kirkwood Flattened Device Tree"
+	select USE_OF
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Marvell Kirkwood using flattened device tree.
+
+config MACH_DREAMPLUG_DT
+	bool "Marvell DreamPlug (Flattened Device Tree)"
+	select ARCH_KIRKWOOD_DT
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Marvell DreamPlug (Flattened Device Tree).
+
 config MACH_TS219
 	bool "QNAP TS-110, TS-119, TS-119P+, TS-210, TS-219, TS-219P and TS-219P+ Turbo NAS"
 	help
diff --git a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile
index 5dcaa81..e299a95 100644
--- a/arch/arm/mach-kirkwood/Makefile
+++ b/arch/arm/mach-kirkwood/Makefile
@@ -20,3 +20,5 @@
 obj-$(CONFIG_MACH_T5325)		+= t5325-setup.o
 
 obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
+obj-$(CONFIG_ARCH_KIRKWOOD_DT)		+= board-dt.o
+obj-$(CONFIG_MACH_DREAMPLUG_DT)		+= board-dreamplug.o
diff --git a/arch/arm/mach-kirkwood/Makefile.boot b/arch/arm/mach-kirkwood/Makefile.boot
index 760a0ef..16f9385 100644
--- a/arch/arm/mach-kirkwood/Makefile.boot
+++ b/arch/arm/mach-kirkwood/Makefile.boot
@@ -1,3 +1,5 @@
    zreladdr-y	+= 0x00008000
 params_phys-y	:= 0x00000100
 initrd_phys-y	:= 0x00800000
+
+dtb-$(CONFIG_MACH_DREAMPLUG_DT) += kirkwood-dreamplug.dtb
diff --git a/arch/arm/mach-kirkwood/board-dreamplug.c b/arch/arm/mach-kirkwood/board-dreamplug.c
new file mode 100644
index 0000000..9854539
--- /dev/null
+++ b/arch/arm/mach-kirkwood/board-dreamplug.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2012 (C), Jason Cooper <jason@lakedaemon.net>
+ *
+ * arch/arm/mach-kirkwood/board-dreamplug.c
+ *
+ * Marvell DreamPlug Reference Board Init for drivers not converted to
+ * flattened device tree yet.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/partitions.h>
+#include <linux/ata_platform.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/orion_spi.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/kirkwood.h>
+#include <mach/bridge-regs.h>
+#include <plat/mvsdio.h>
+#include "common.h"
+#include "mpp.h"
+
+struct mtd_partition dreamplug_partitions[] = {
+	{
+		.name	= "u-boot",
+		.size	= SZ_512K,
+		.offset = 0,
+	},
+	{
+		.name	= "u-boot env",
+		.size	= SZ_64K,
+		.offset = SZ_512K + SZ_512K,
+	},
+	{
+		.name	= "dtb",
+		.size	= SZ_64K,
+		.offset = SZ_512K + SZ_512K + SZ_512K,
+	},
+};
+
+static const struct flash_platform_data dreamplug_spi_slave_data = {
+	.type		= "mx25l1606e",
+	.name		= "spi_flash",
+	.parts		= dreamplug_partitions,
+	.nr_parts	= ARRAY_SIZE(dreamplug_partitions),
+};
+
+static struct spi_board_info __initdata dreamplug_spi_slave_info[] = {
+	{
+		.modalias	= "m25p80",
+		.platform_data	= &dreamplug_spi_slave_data,
+		.irq		= -1,
+		.max_speed_hz	= 50000000,
+		.bus_num	= 0,
+		.chip_select	= 0,
+	},
+};
+
+static struct mv643xx_eth_platform_data dreamplug_ge00_data = {
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(0),
+};
+
+static struct mv643xx_eth_platform_data dreamplug_ge01_data = {
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(1),
+};
+
+static struct mv_sata_platform_data dreamplug_sata_data = {
+	.n_ports	= 1,
+};
+
+static struct mvsdio_platform_data dreamplug_mvsdio_data = {
+	/* unfortunately the CD signal has not been connected */
+};
+
+static struct gpio_led dreamplug_led_pins[] = {
+	{
+		.name			= "dreamplug:blue:bluetooth",
+		.gpio			= 47,
+		.active_low		= 1,
+	},
+	{
+		.name			= "dreamplug:green:wifi",
+		.gpio			= 48,
+		.active_low		= 1,
+	},
+	{
+		.name			= "dreamplug:green:wifi_ap",
+		.gpio			= 49,
+		.active_low		= 1,
+	},
+};
+
+static struct gpio_led_platform_data dreamplug_led_data = {
+	.leds		= dreamplug_led_pins,
+	.num_leds	= ARRAY_SIZE(dreamplug_led_pins),
+};
+
+static struct platform_device dreamplug_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &dreamplug_led_data,
+	}
+};
+
+static unsigned int dreamplug_mpp_config[] __initdata = {
+	MPP0_SPI_SCn,
+	MPP1_SPI_MOSI,
+	MPP2_SPI_SCK,
+	MPP3_SPI_MISO,
+	MPP47_GPIO,	/* Bluetooth LED */
+	MPP48_GPIO,	/* Wifi LED */
+	MPP49_GPIO,	/* Wifi AP LED */
+	0
+};
+
+void __init dreamplug_init(void)
+{
+	/*
+	 * Basic setup. Needs to be called early.
+	 */
+	kirkwood_mpp_conf(dreamplug_mpp_config);
+
+	spi_register_board_info(dreamplug_spi_slave_info,
+				ARRAY_SIZE(dreamplug_spi_slave_info));
+	kirkwood_spi_init();
+
+	kirkwood_ehci_init();
+	kirkwood_ge00_init(&dreamplug_ge00_data);
+	kirkwood_ge01_init(&dreamplug_ge01_data);
+	kirkwood_sata_init(&dreamplug_sata_data);
+	kirkwood_sdio_init(&dreamplug_mvsdio_data);
+
+	platform_device_register(&dreamplug_leds);
+}
diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c
new file mode 100644
index 0000000..1c672d9
--- /dev/null
+++ b/arch/arm/mach-kirkwood/board-dt.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2012 (C), Jason Cooper <jason@lakedaemon.net>
+ *
+ * arch/arm/mach-kirkwood/board-dt.c
+ *
+ * Flattened Device Tree board initialization
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/bridge-regs.h>
+#include "common.h"
+
+static struct of_device_id kirkwood_dt_match_table[] __initdata = {
+	{ .compatible = "simple-bus", },
+	{ }
+};
+
+static void __init kirkwood_dt_init(void)
+{
+	pr_info("Kirkwood: %s, TCLK=%d.\n", kirkwood_id(), kirkwood_tclk);
+
+	/*
+	 * Disable propagation of mbus errors to the CPU local bus,
+	 * as this causes mbus errors (which can occur for example
+	 * for PCI aborts) to throw CPU aborts, which we're not set
+	 * up to deal with.
+	 */
+	writel(readl(CPU_CONFIG) & ~CPU_CONFIG_ERROR_PROP, CPU_CONFIG);
+
+	kirkwood_setup_cpu_mbus();
+
+#ifdef CONFIG_CACHE_FEROCEON_L2
+	kirkwood_l2_init();
+#endif
+
+	/* internal devices that every board has */
+	kirkwood_wdt_init();
+	kirkwood_xor0_init();
+	kirkwood_xor1_init();
+	kirkwood_crypto_init();
+
+#ifdef CONFIG_KEXEC
+	kexec_reinit = kirkwood_enable_pcie;
+#endif
+
+	if (of_machine_is_compatible("globalscale,dreamplug"))
+		dreamplug_init();
+
+	of_platform_populate(NULL, kirkwood_dt_match_table, NULL, NULL);
+}
+
+static const char *kirkwood_dt_board_compat[] = {
+	"globalscale,dreamplug",
+	NULL
+};
+
+DT_MACHINE_START(KIRKWOOD_DT, "Marvell Kirkwood (Flattened Device Tree)")
+	/* Maintainer: Jason Cooper <jason@lakedaemon.net> */
+	.map_io		= kirkwood_map_io,
+	.init_early	= kirkwood_init_early,
+	.init_irq	= kirkwood_init_irq,
+	.timer		= &kirkwood_timer,
+	.init_machine	= kirkwood_dt_init,
+	.restart	= kirkwood_restart,
+	.dt_compat	= kirkwood_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index 77d4852..a02cae8 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -279,7 +279,7 @@
 /*****************************************************************************
  * XOR0
  ****************************************************************************/
-static void __init kirkwood_xor0_init(void)
+void __init kirkwood_xor0_init(void)
 {
 	kirkwood_clk_ctrl |= CGC_XOR0;
 
@@ -291,7 +291,7 @@
 /*****************************************************************************
  * XOR1
  ****************************************************************************/
-static void __init kirkwood_xor1_init(void)
+void __init kirkwood_xor1_init(void)
 {
 	kirkwood_clk_ctrl |= CGC_XOR1;
 
@@ -303,7 +303,7 @@
 /*****************************************************************************
  * Watchdog
  ****************************************************************************/
-static void __init kirkwood_wdt_init(void)
+void __init kirkwood_wdt_init(void)
 {
 	orion_wdt_init(kirkwood_tclk);
 }
@@ -392,7 +392,7 @@
 /*
  * Identify device ID and revision.
  */
-static char * __init kirkwood_id(void)
+char * __init kirkwood_id(void)
 {
 	u32 dev, rev;
 
@@ -435,7 +435,7 @@
 	}
 }
 
-static void __init kirkwood_l2_init(void)
+void __init kirkwood_l2_init(void)
 {
 #ifdef CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH
 	writel(readl(L2_CONFIG_REG) | L2_WRITETHROUGH, L2_CONFIG_REG);
@@ -450,7 +450,6 @@
 {
 	printk(KERN_INFO "Kirkwood: %s, TCLK=%d.\n",
 		kirkwood_id(), kirkwood_tclk);
-	kirkwood_i2s_data.tclk = kirkwood_tclk;
 
 	/*
 	 * Disable propagation of mbus errors to the CPU local bus,
diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h
index 9071a39..fa8e768 100644
--- a/arch/arm/mach-kirkwood/common.h
+++ b/arch/arm/mach-kirkwood/common.h
@@ -51,6 +51,21 @@
 void kirkwood_audio_init(void);
 void kirkwood_restart(char, const char *);
 
+/* board init functions for boards not fully converted to fdt */
+#ifdef CONFIG_MACH_DREAMPLUG_DT
+void dreamplug_init(void);
+#else
+static inline void dreamplug_init(void) {};
+#endif
+
+/* early init functions not converted to fdt yet */
+char *kirkwood_id(void);
+void kirkwood_l2_init(void);
+void kirkwood_wdt_init(void);
+void kirkwood_xor0_init(void);
+void kirkwood_xor1_init(void);
+void kirkwood_crypto_init(void);
+
 extern int kirkwood_tclk;
 extern struct sys_timer kirkwood_timer;
 
diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c
index 7088180..0f17109 100644
--- a/arch/arm/mach-kirkwood/cpuidle.c
+++ b/arch/arm/mach-kirkwood/cpuidle.c
@@ -20,77 +20,47 @@
 #include <linux/io.h>
 #include <linux/export.h>
 #include <asm/proc-fns.h>
+#include <asm/cpuidle.h>
 #include <mach/kirkwood.h>
 
 #define KIRKWOOD_MAX_STATES	2
 
-static struct cpuidle_driver kirkwood_idle_driver = {
-	.name =         "kirkwood_idle",
-	.owner =        THIS_MODULE,
-};
-
-static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device);
-
 /* Actual code that puts the SoC in different idle states */
 static int kirkwood_enter_idle(struct cpuidle_device *dev,
 				struct cpuidle_driver *drv,
 			       int index)
 {
-	struct timeval before, after;
-	int idle_time;
-
-	local_irq_disable();
-	do_gettimeofday(&before);
-	if (index == 0)
-		/* Wait for interrupt state */
-		cpu_do_idle();
-	else if (index == 1) {
-		/*
-		 * Following write will put DDR in self refresh.
-		 * Note that we have 256 cycles before DDR puts it
-		 * self in self-refresh, so the wait-for-interrupt
-		 * call afterwards won't get the DDR from self refresh
-		 * mode.
-		 */
-		writel(0x7, DDR_OPERATION_BASE);
-		cpu_do_idle();
-	}
-	do_gettimeofday(&after);
-	local_irq_enable();
-	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
-			(after.tv_usec - before.tv_usec);
-
-	/* Update last residency */
-	dev->last_residency = idle_time;
+	writel(0x7, DDR_OPERATION_BASE);
+	cpu_do_idle();
 
 	return index;
 }
 
+static struct cpuidle_driver kirkwood_idle_driver = {
+	.name			= "kirkwood_idle",
+	.owner			= THIS_MODULE,
+	.en_core_tk_irqen	= 1,
+	.states[0]		= ARM_CPUIDLE_WFI_STATE,
+	.states[1]		= {
+		.enter			= kirkwood_enter_idle,
+		.exit_latency		= 10,
+		.target_residency	= 100000,
+		.flags			= CPUIDLE_FLAG_TIME_VALID,
+		.name			= "DDR SR",
+		.desc			= "WFI and DDR Self Refresh",
+	},
+	.state_count = KIRKWOOD_MAX_STATES,
+};
+
+static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device);
+
 /* Initialize CPU idle by registering the idle states */
 static int kirkwood_init_cpuidle(void)
 {
 	struct cpuidle_device *device;
-	struct cpuidle_driver *driver = &kirkwood_idle_driver;
 
 	device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id());
 	device->state_count = KIRKWOOD_MAX_STATES;
-	driver->state_count = KIRKWOOD_MAX_STATES;
-
-	/* Wait for interrupt state */
-	driver->states[0].enter = kirkwood_enter_idle;
-	driver->states[0].exit_latency = 1;
-	driver->states[0].target_residency = 10000;
-	driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
-	strcpy(driver->states[0].name, "WFI");
-	strcpy(driver->states[0].desc, "Wait for interrupt");
-
-	/* Wait for interrupt and DDR self refresh state */
-	driver->states[1].enter = kirkwood_enter_idle;
-	driver->states[1].exit_latency = 10;
-	driver->states[1].target_residency = 10000;
-	driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
-	strcpy(driver->states[1].name, "DDR SR");
-	strcpy(driver->states[1].desc, "WFI and DDR Self Refresh");
 
 	cpuidle_register_driver(&kirkwood_idle_driver);
 	if (cpuidle_register_device(device)) {
diff --git a/arch/arm/mach-kirkwood/include/mach/entry-macro.S b/arch/arm/mach-kirkwood/include/mach/entry-macro.S
index 8939d36..82db29f 100644
--- a/arch/arm/mach-kirkwood/include/mach/entry-macro.S
+++ b/arch/arm/mach-kirkwood/include/mach/entry-macro.S
@@ -10,12 +10,6 @@
 
 #include <mach/bridge-regs.h>
 
-	.macro  disable_fiq
-	.endm
-
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
-
 	.macro  get_irqnr_preamble, base, tmp
 	ldr	\base, =IRQ_VIRT_BASE
 	.endm
diff --git a/arch/arm/mach-kirkwood/include/mach/io.h b/arch/arm/mach-kirkwood/include/mach/io.h
index 49dd0cb..5d0ab61 100644
--- a/arch/arm/mach-kirkwood/include/mach/io.h
+++ b/arch/arm/mach-kirkwood/include/mach/io.h
@@ -20,7 +20,5 @@
 }
 
 #define __io(a)			__io(a)
-#define __mem_pci(a)		(a)
-
 
 #endif
diff --git a/arch/arm/mach-kirkwood/include/mach/system.h b/arch/arm/mach-kirkwood/include/mach/system.h
deleted file mode 100644
index 5fddde0..0000000
--- a/arch/arm/mach-kirkwood/include/mach/system.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/mach-kirkwood/include/mach/system.h
- *
- * 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-kirkwood/openrd-setup.c b/arch/arm/mach-kirkwood/openrd-setup.c
index 01f8c89..7e99c3f 100644
--- a/arch/arm/mach-kirkwood/openrd-setup.c
+++ b/arch/arm/mach-kirkwood/openrd-setup.c
@@ -83,6 +83,11 @@
 	},
 };
 
+static struct platform_device openrd_client_audio_device = {
+	.name		= "openrd-client-audio",
+	.id		= -1,
+};
+
 static int __initdata uart1;
 
 static int __init sd_uart_selection(char *str)
@@ -172,6 +177,7 @@
 	kirkwood_i2c_init();
 
 	if (machine_is_openrd_client() || machine_is_openrd_ultimate()) {
+		platform_device_register(&openrd_client_audio_device);
 		i2c_register_board_info(0, i2c_board_info,
 			ARRAY_SIZE(i2c_board_info));
 		kirkwood_audio_init();
diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c
index a066a6d..f56a011 100644
--- a/arch/arm/mach-kirkwood/pcie.c
+++ b/arch/arm/mach-kirkwood/pcie.c
@@ -198,9 +198,9 @@
 	if (request_resource(&iomem_resource, &pp->res[1]))
 		panic("Request PCIe%d Memory resource failed\n", index);
 
-	pci_add_resource(&sys->resources, &pp->res[0]);
-	pci_add_resource(&sys->resources, &pp->res[1]);
 	sys->io_offset = 0;
+	pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
+	pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
 
 	/*
 	 * Generic PCIe unit setup.
diff --git a/arch/arm/mach-kirkwood/t5325-setup.c b/arch/arm/mach-kirkwood/t5325-setup.c
index 966b2b3..f9d2a11 100644
--- a/arch/arm/mach-kirkwood/t5325-setup.c
+++ b/arch/arm/mach-kirkwood/t5325-setup.c
@@ -106,6 +106,11 @@
 	}
 };
 
+static struct platform_device hp_t5325_audio_device = {
+	.name		= "t5325-audio",
+	.id		= -1,
+};
+
 static unsigned int hp_t5325_mpp_config[] __initdata = {
 	MPP0_NF_IO2,
 	MPP1_SPI_MOSI,
@@ -179,6 +184,7 @@
 	kirkwood_sata_init(&hp_t5325_sata_data);
 	kirkwood_ehci_init();
 	platform_device_register(&hp_t5325_button_device);
+	platform_device_register(&hp_t5325_audio_device);
 
 	i2c_register_board_info(0, i2c_board_info, ARRAY_SIZE(i2c_board_info));
 	kirkwood_audio_init();
diff --git a/arch/arm/mach-ks8695/include/mach/entry-macro.S b/arch/arm/mach-ks8695/include/mach/entry-macro.S
index b4fe0c1..8315b34 100644
--- a/arch/arm/mach-ks8695/include/mach/entry-macro.S
+++ b/arch/arm/mach-ks8695/include/mach/entry-macro.S
@@ -14,16 +14,10 @@
 #include <mach/hardware.h>
 #include <mach/regs-irq.h>
 
-	.macro	disable_fiq
-	.endm
-
 	.macro  get_irqnr_preamble, base, tmp
 		ldr	\base, =KS8695_IRQ_VA			@ Base address of interrupt controller
 	.endm
 
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
-
 	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 		ldr	\irqstat, [\base, #KS8695_INTMS]	@ Mask Status register
 
diff --git a/arch/arm/mach-ks8695/include/mach/io.h b/arch/arm/mach-ks8695/include/mach/io.h
deleted file mode 100644
index a7a63ac..0000000
--- a/arch/arm/mach-ks8695/include/mach/io.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-ks8695/include/mach/io.h
- *
- * Copyright (C) 2006 Andrew Victor
- *
- * 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 __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT		0xffffffff
-
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#endif
diff --git a/arch/arm/mach-ks8695/include/mach/system.h b/arch/arm/mach-ks8695/include/mach/system.h
deleted file mode 100644
index 59fe992..0000000
--- a/arch/arm/mach-ks8695/include/mach/system.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * arch/arm/mach-s3c2410/include/mach/system.h
- *
- * Copyright (C) 2006 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * KS8695 - System function defines and includes
- *
- * 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static void arch_idle(void)
-{
-	/*
-	 * This should do all the clock switching
-	 * and wait for interrupt tricks,
-	 */
-	cpu_do_idle();
-
-}
-
-#endif
diff --git a/arch/arm/mach-ks8695/pci.c b/arch/arm/mach-ks8695/pci.c
index b26f992..acc7014 100644
--- a/arch/arm/mach-ks8695/pci.c
+++ b/arch/arm/mach-ks8695/pci.c
@@ -169,8 +169,8 @@
 	request_resource(&iomem_resource, &pci_mem);
 	request_resource(&ioport_resource, &pci_io);
 
-	pci_add_resource(&sys->resources, &pci_io);
-	pci_add_resource(&sys->resources, &pci_mem);
+	pci_add_resource_offset(&sys->resources, &pci_io, sys->io_offset);
+	pci_add_resource_offset(&sys->resources, &pci_mem, sys->mem_offset);
 
 	/* Assign and enable processor bridge */
 	ks8695_local_writeconfig(PCI_BASE_ADDRESS_0, KS8695_PCIMEM_PA);
diff --git a/arch/arm/mach-ks8695/time.c b/arch/arm/mach-ks8695/time.c
index 37dfcd5..ec783a3 100644
--- a/arch/arm/mach-ks8695/time.c
+++ b/arch/arm/mach-ks8695/time.c
@@ -27,6 +27,7 @@
 #include <linux/io.h>
 
 #include <asm/mach/time.h>
+#include <asm/system_misc.h>
 
 #include <mach/regs-timer.h>
 #include <mach/regs-irq.h>
diff --git a/arch/arm/mach-lpc32xx/Kconfig b/arch/arm/mach-lpc32xx/Kconfig
index fde6635..75946ac 100644
--- a/arch/arm/mach-lpc32xx/Kconfig
+++ b/arch/arm/mach-lpc32xx/Kconfig
@@ -29,5 +29,30 @@
 
 endmenu
 
+menu "LPC32XX chip components"
+
+config ARCH_LPC32XX_IRAM_FOR_NET
+	bool "Use IRAM for network buffers"
+	default y
+	help
+	  Say Y here to use the LPC internal fast IRAM (i.e. 256KB SRAM) as
+	  network buffer.  If the total combined required buffer sizes is
+	  larger than the size of IRAM, then SDRAM will be used instead.
+
+	  This can be enabled safely if the IRAM is not intended for other
+	  uses.
+
+config ARCH_LPC32XX_MII_SUPPORT
+	bool "Check to enable MII support or leave disabled for RMII support"
+	help
+	  Say Y here to enable MII support, or N for RMII support. Regardless of
+	  which support is selected, the ethernet interface driver needs to be
+	  selected in the device driver networking section.
+
+	  The PHY3250 reference board uses RMII, so users of this board should
+	  say N.
+
+endmenu
+
 endif
 
diff --git a/arch/arm/mach-lpc32xx/clock.c b/arch/arm/mach-lpc32xx/clock.c
index 1e02751..2fc24ca 100644
--- a/arch/arm/mach-lpc32xx/clock.c
+++ b/arch/arm/mach-lpc32xx/clock.c
@@ -82,10 +82,12 @@
  *   will also impact the individual peripheral rates.
  */
 
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/device.h>
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/amba/bus.h>
@@ -97,9 +99,12 @@
 #include "clock.h"
 #include "common.h"
 
+static DEFINE_SPINLOCK(global_clkregs_lock);
+
+static int usb_pll_enable, usb_pll_valid;
+
 static struct clk clk_armpll;
 static struct clk clk_usbpll;
-static DEFINE_MUTEX(clkm_lock);
 
 /*
  * Post divider values for PLLs based on selected register value
@@ -127,7 +132,7 @@
 static int local_pll397_enable(struct clk *clk, int enable)
 {
 	u32 reg;
-	unsigned long timeout = 1 + msecs_to_jiffies(10);
+	unsigned long timeout = jiffies + msecs_to_jiffies(10);
 
 	reg = __raw_readl(LPC32XX_CLKPWR_PLL397_CTRL);
 
@@ -142,7 +147,7 @@
 		/* Wait for PLL397 lock */
 		while (((__raw_readl(LPC32XX_CLKPWR_PLL397_CTRL) &
 			LPC32XX_CLKPWR_SYSCTRL_PLL397_STS) == 0) &&
-			(timeout > jiffies))
+			time_before(jiffies, timeout))
 			cpu_relax();
 
 		if ((__raw_readl(LPC32XX_CLKPWR_PLL397_CTRL) &
@@ -156,7 +161,7 @@
 static int local_oscmain_enable(struct clk *clk, int enable)
 {
 	u32 reg;
-	unsigned long timeout = 1 + msecs_to_jiffies(10);
+	unsigned long timeout = jiffies + msecs_to_jiffies(10);
 
 	reg = __raw_readl(LPC32XX_CLKPWR_MAIN_OSC_CTRL);
 
@@ -171,7 +176,7 @@
 		/* Wait for main oscillator to start */
 		while (((__raw_readl(LPC32XX_CLKPWR_MAIN_OSC_CTRL) &
 			LPC32XX_CLKPWR_MOSC_DISABLE) != 0) &&
-			(timeout > jiffies))
+			time_before(jiffies, timeout))
 			cpu_relax();
 
 		if ((__raw_readl(LPC32XX_CLKPWR_MAIN_OSC_CTRL) &
@@ -382,30 +387,62 @@
 static int local_usbpll_enable(struct clk *clk, int enable)
 {
 	u32 reg;
-	int ret = -ENODEV;
-	unsigned long timeout = 1 + msecs_to_jiffies(10);
+	int ret = 0;
+	unsigned long timeout = jiffies + msecs_to_jiffies(20);
 
 	reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
 
-	if (enable == 0) {
-		reg &= ~(LPC32XX_CLKPWR_USBCTRL_CLK_EN1 |
-			LPC32XX_CLKPWR_USBCTRL_CLK_EN2);
-		__raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
-	} else if (reg & LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP) {
+	__raw_writel(reg & ~(LPC32XX_CLKPWR_USBCTRL_CLK_EN2 |
+		LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP),
+		LPC32XX_CLKPWR_USB_CTRL);
+	__raw_writel(reg & ~LPC32XX_CLKPWR_USBCTRL_CLK_EN1,
+		LPC32XX_CLKPWR_USB_CTRL);
+
+	if (enable && usb_pll_valid && usb_pll_enable) {
+		ret = -ENODEV;
+		/*
+		 * If the PLL rate has been previously set, then the rate
+		 * in the PLL register is valid and can be enabled here.
+		 * Otherwise, it needs to be enabled as part of setrate.
+		 */
+
+		/*
+		 * Gate clock into PLL
+		 */
 		reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN1;
 		__raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
 
-		/* Wait for PLL lock */
-		while ((timeout > jiffies) & (ret == -ENODEV)) {
+		/*
+		 * Enable PLL
+		 */
+		reg |= LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP;
+		__raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+
+		/*
+		 * Wait for PLL to lock
+		 */
+		while (time_before(jiffies, timeout) && (ret == -ENODEV)) {
 			reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
 			if (reg & LPC32XX_CLKPWR_USBCTRL_PLL_STS)
 				ret = 0;
+			else
+				udelay(10);
 		}
 
+		/*
+		 * Gate clock from PLL if PLL is locked
+		 */
 		if (ret == 0) {
-			reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN2;
-			__raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+			__raw_writel(reg | LPC32XX_CLKPWR_USBCTRL_CLK_EN2,
+				LPC32XX_CLKPWR_USB_CTRL);
+		} else {
+			__raw_writel(reg & ~(LPC32XX_CLKPWR_USBCTRL_CLK_EN1 |
+				LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP),
+				LPC32XX_CLKPWR_USB_CTRL);
 		}
+	} else if ((enable == 0) && usb_pll_valid  && usb_pll_enable) {
+		usb_pll_valid = 0;
+		usb_pll_enable = 0;
 	}
 
 	return ret;
@@ -423,7 +460,7 @@
 	 */
 	rate = rate * 1000;
 
-	clkin = clk->parent->rate;
+	clkin = clk->get_rate(clk);
 	usbdiv = (__raw_readl(LPC32XX_CLKPWR_USBCLK_PDIV) &
 		LPC32XX_CLKPWR_USBPDIV_PLL_MASK) + 1;
 	clkin = clkin / usbdiv;
@@ -437,7 +474,8 @@
 
 static int local_usbpll_set_rate(struct clk *clk, unsigned long rate)
 {
-	u32 clkin, reg, usbdiv;
+	int ret = -ENODEV;
+	u32 clkin, usbdiv;
 	struct clk_pll_setup pllsetup;
 
 	/*
@@ -446,7 +484,7 @@
 	 */
 	rate = rate * 1000;
 
-	clkin = clk->get_rate(clk);
+	clkin = clk->get_rate(clk->parent);
 	usbdiv = (__raw_readl(LPC32XX_CLKPWR_USBCLK_PDIV) &
 		LPC32XX_CLKPWR_USBPDIV_PLL_MASK) + 1;
 	clkin = clkin / usbdiv;
@@ -455,22 +493,25 @@
 	if (local_clk_find_pll_cfg(clkin, rate, &pllsetup) == 0)
 		return -EINVAL;
 
+	/*
+	 * Disable PLL clocks during PLL change
+	 */
 	local_usbpll_enable(clk, 0);
-
-	reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
-	reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN1;
-	__raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
-
-	pllsetup.analog_on = 1;
+	pllsetup.analog_on = 0;
 	local_clk_usbpll_setup(&pllsetup);
 
-	clk->rate = clk_check_pll_setup(clkin, &pllsetup);
+	/*
+	 * Start USB PLL and check PLL status
+	 */
 
-	reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
-	reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN2;
-	__raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+	usb_pll_valid = 1;
+	usb_pll_enable = 1;
 
-	return 0;
+	ret = local_usbpll_enable(clk, 1);
+	if (ret >= 0)
+		clk->rate = clk_check_pll_setup(clkin, &pllsetup);
+
+	return ret;
 }
 
 static struct clk clk_usbpll = {
@@ -719,6 +760,41 @@
 	.get_rate	= local_return_parent_rate,
 };
 
+static int adc_onoff_enable(struct clk *clk, int enable)
+{
+	u32 tmp;
+	u32 divider;
+
+	/* Use PERIPH_CLOCK */
+	tmp = __raw_readl(LPC32XX_CLKPWR_ADC_CLK_CTRL_1);
+	tmp |= LPC32XX_CLKPWR_ADCCTRL1_PCLK_SEL;
+	/*
+	 * Set clock divider so that we have equal to or less than
+	 * 4.5MHz clock at ADC
+	 */
+	divider = clk->get_rate(clk) / 4500000 + 1;
+	tmp |= divider;
+	__raw_writel(tmp, LPC32XX_CLKPWR_ADC_CLK_CTRL_1);
+
+	/* synchronize rate of this clock w/ actual HW setting */
+	clk->rate = clk->get_rate(clk->parent) / divider;
+
+	if (enable == 0)
+		__raw_writel(0, clk->enable_reg);
+	else
+		__raw_writel(clk->enable_mask, clk->enable_reg);
+
+	return 0;
+}
+
+static struct clk clk_adc = {
+	.parent		= &clk_pclk,
+	.enable		= adc_onoff_enable,
+	.enable_reg	= LPC32XX_CLKPWR_ADC_CLK_CTRL,
+	.enable_mask	= LPC32XX_CLKPWR_ADC32CLKCTRL_CLK_EN,
+	.get_rate	= local_return_parent_rate,
+};
+
 static int mmc_onoff_enable(struct clk *clk, int enable)
 {
 	u32 tmp;
@@ -891,20 +967,8 @@
 	.enable_mask	= LPC32XX_CLKPWR_LCDCTRL_CLK_EN,
 };
 
-static inline void clk_lock(void)
-{
-	mutex_lock(&clkm_lock);
-}
-
-static inline void clk_unlock(void)
-{
-	mutex_unlock(&clkm_lock);
-}
-
 static void local_clk_disable(struct clk *clk)
 {
-	WARN_ON(clk->usecount == 0);
-
 	/* Don't attempt to disable clock if it has no users */
 	if (clk->usecount > 0) {
 		clk->usecount--;
@@ -947,10 +1011,11 @@
 int clk_enable(struct clk *clk)
 {
 	int ret;
+	unsigned long flags;
 
-	clk_lock();
+	spin_lock_irqsave(&global_clkregs_lock, flags);
 	ret = local_clk_enable(clk);
-	clk_unlock();
+	spin_unlock_irqrestore(&global_clkregs_lock, flags);
 
 	return ret;
 }
@@ -961,9 +1026,11 @@
  */
 void clk_disable(struct clk *clk)
 {
-	clk_lock();
+	unsigned long flags;
+
+	spin_lock_irqsave(&global_clkregs_lock, flags);
 	local_clk_disable(clk);
-	clk_unlock();
+	spin_unlock_irqrestore(&global_clkregs_lock, flags);
 }
 EXPORT_SYMBOL(clk_disable);
 
@@ -972,13 +1039,7 @@
  */
 unsigned long clk_get_rate(struct clk *clk)
 {
-	unsigned long rate;
-
-	clk_lock();
-	rate = clk->get_rate(clk);
-	clk_unlock();
-
-	return rate;
+	return clk->get_rate(clk);
 }
 EXPORT_SYMBOL(clk_get_rate);
 
@@ -994,11 +1055,8 @@
 	 * the actual rate set as part of the peripheral dividers
 	 * instead of high level clock control
 	 */
-	if (clk->set_rate) {
-		clk_lock();
+	if (clk->set_rate)
 		ret = clk->set_rate(clk, rate);
-		clk_unlock();
-	}
 
 	return ret;
 }
@@ -1009,15 +1067,11 @@
  */
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
-	clk_lock();
-
 	if (clk->round_rate)
 		rate = clk->round_rate(clk, rate);
 	else
 		rate = clk->get_rate(clk);
 
-	clk_unlock();
-
 	return rate;
 }
 EXPORT_SYMBOL(clk_round_rate);
@@ -1075,11 +1129,12 @@
 	_REGISTER_CLOCK("dev:ssp1", NULL, clk_ssp1)
 	_REGISTER_CLOCK("lpc32xx_keys.0", NULL, clk_kscan)
 	_REGISTER_CLOCK("lpc32xx-nand.0", "nand_ck", clk_nand)
-	_REGISTER_CLOCK("tbd", "i2s0_ck", clk_i2s0)
-	_REGISTER_CLOCK("tbd", "i2s1_ck", clk_i2s1)
+	_REGISTER_CLOCK("lpc32xx-adc", NULL, clk_adc)
+	_REGISTER_CLOCK(NULL, "i2s0_ck", clk_i2s0)
+	_REGISTER_CLOCK(NULL, "i2s1_ck", clk_i2s1)
 	_REGISTER_CLOCK("ts-lpc32xx", NULL, clk_tsc)
-	_REGISTER_CLOCK("dev:mmc0", "MCLK", clk_mmc)
-	_REGISTER_CLOCK("lpc-net.0", NULL, clk_net)
+	_REGISTER_CLOCK("dev:mmc0", NULL, clk_mmc)
+	_REGISTER_CLOCK("lpc-eth.0", NULL, clk_net)
 	_REGISTER_CLOCK("dev:clcd", NULL, clk_lcd)
 	_REGISTER_CLOCK("lpc32xx_udc", "ck_usbd", clk_usbd)
 	_REGISTER_CLOCK("lpc32xx_rtc", NULL, clk_rtc)
diff --git a/arch/arm/mach-lpc32xx/common.c b/arch/arm/mach-lpc32xx/common.c
index 369b152..bbbf063 100644
--- a/arch/arm/mach-lpc32xx/common.c
+++ b/arch/arm/mach-lpc32xx/common.c
@@ -138,6 +138,75 @@
 };
 
 /*
+ * ADC support
+ */
+static struct resource adc_resources[] = {
+	{
+		.start = LPC32XX_ADC_BASE,
+		.end = LPC32XX_ADC_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	}, {
+		.start = IRQ_LPC32XX_TS_IRQ,
+		.end = IRQ_LPC32XX_TS_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device lpc32xx_adc_device = {
+	.name =  "lpc32xx-adc",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(adc_resources),
+	.resource = adc_resources,
+};
+
+/*
+ * USB support
+ */
+/* The dmamask must be set for OHCI to work */
+static u64 ohci_dmamask = ~(u32) 0;
+static struct resource ohci_resources[] = {
+	{
+		.start = IO_ADDRESS(LPC32XX_USB_BASE),
+		.end = IO_ADDRESS(LPC32XX_USB_BASE + 0x100 - 1),
+		.flags = IORESOURCE_MEM,
+	}, {
+		.start = IRQ_LPC32XX_USB_HOST,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+struct platform_device lpc32xx_ohci_device = {
+	.name = "usb-ohci",
+	.id = -1,
+	.dev = {
+		.dma_mask = &ohci_dmamask,
+		.coherent_dma_mask = 0xFFFFFFFF,
+	},
+	.num_resources = ARRAY_SIZE(ohci_resources),
+	.resource = ohci_resources,
+};
+
+/*
+ * Network Support
+ */
+static struct resource net_resources[] = {
+	[0] = DEFINE_RES_MEM(LPC32XX_ETHERNET_BASE, SZ_4K),
+	[1] = DEFINE_RES_MEM(LPC32XX_IRAM_BASE, SZ_128K),
+	[2] = DEFINE_RES_IRQ(IRQ_LPC32XX_ETHERNET),
+};
+
+static u64 lpc32xx_mac_dma_mask = 0xffffffffUL;
+struct platform_device lpc32xx_net_device = {
+	.name = "lpc-eth",
+	.id = 0,
+	.dev = {
+		.dma_mask = &lpc32xx_mac_dma_mask,
+		.coherent_dma_mask = 0xffffffffUL,
+	},
+	.num_resources = ARRAY_SIZE(net_resources),
+	.resource = net_resources,
+};
+
+/*
  * Returns the unique ID for the device
  */
 void lpc32xx_get_uid(u32 devid[4])
diff --git a/arch/arm/mach-lpc32xx/common.h b/arch/arm/mach-lpc32xx/common.h
index 4b4e700..68e45e8 100644
--- a/arch/arm/mach-lpc32xx/common.h
+++ b/arch/arm/mach-lpc32xx/common.h
@@ -19,6 +19,7 @@
 #ifndef __LPC32XX_COMMON_H
 #define __LPC32XX_COMMON_H
 
+#include <mach/board.h>
 #include <linux/platform_device.h>
 
 /*
@@ -29,7 +30,10 @@
 extern struct platform_device lpc32xx_i2c1_device;
 extern struct platform_device lpc32xx_i2c2_device;
 extern struct platform_device lpc32xx_tsc_device;
+extern struct platform_device lpc32xx_adc_device;
 extern struct platform_device lpc32xx_rtc_device;
+extern struct platform_device lpc32xx_ohci_device;
+extern struct platform_device lpc32xx_net_device;
 
 /*
  * Other arch specific structures and functions
@@ -65,9 +69,7 @@
  */
 extern void lpc32xx_get_uid(u32 devid[4]);
 
-extern void lpc32xx_watchdog_reset(void);
 extern u32 lpc32xx_return_iram_size(void);
-
 /*
  * Pointers used for sizing and copying suspend function data
  */
diff --git a/arch/arm/mach-lpc32xx/include/mach/board.h b/arch/arm/mach-lpc32xx/include/mach/board.h
new file mode 100644
index 0000000..52531ca
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/board.h
@@ -0,0 +1,24 @@
+/*
+ * arm/arch/mach-lpc32xx/include/mach/board.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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 __ASM_ARCH_BOARD_H
+#define __ASM_ARCH_BOARD_H
+
+extern u32 lpc32xx_return_iram_size(void);
+
+#endif  /* __ASM_ARCH_BOARD_H */
diff --git a/arch/arm/mach-lpc32xx/include/mach/entry-macro.S b/arch/arm/mach-lpc32xx/include/mach/entry-macro.S
index b725f6c..24ca11b 100644
--- a/arch/arm/mach-lpc32xx/include/mach/entry-macro.S
+++ b/arch/arm/mach-lpc32xx/include/mach/entry-macro.S
@@ -21,16 +21,10 @@
 
 #define LPC32XX_INTC_MASKED_STATUS_OFS	0x8
 
-	.macro	disable_fiq
-	.endm
-
 	.macro  get_irqnr_preamble, base, tmp
 	ldr	\base, =IO_ADDRESS(LPC32XX_MIC_BASE)
 	.endm
 
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
-
 /*
  * Return IRQ number in irqnr. Also return processor Z flag status in CPSR
  * as set if an interrupt is pending.
diff --git a/arch/arm/mach-lpc32xx/include/mach/io.h b/arch/arm/mach-lpc32xx/include/mach/io.h
deleted file mode 100644
index 9b59ab5..0000000
--- a/arch/arm/mach-lpc32xx/include/mach/io.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * arch/arm/mach-lpc32xx/include/mach/io.h
- *
- * Author: Kevin Wells <kevin.wells@nxp.com>
- *
- * Copyright (C) 2010 NXP Semiconductors
- *
- * 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 __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT	0xffffffff
-
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/platform.h b/arch/arm/mach-lpc32xx/include/mach/platform.h
index 14ea8d1..c584f5b 100644
--- a/arch/arm/mach-lpc32xx/include/mach/platform.h
+++ b/arch/arm/mach-lpc32xx/include/mach/platform.h
@@ -591,42 +591,42 @@
 /*
  * Timer/counter register offsets
  */
-#define LCP32XX_TIMER_IR(x)			io_p2v((x) + 0x00)
-#define LCP32XX_TIMER_TCR(x)			io_p2v((x) + 0x04)
-#define LCP32XX_TIMER_TC(x)			io_p2v((x) + 0x08)
-#define LCP32XX_TIMER_PR(x)			io_p2v((x) + 0x0C)
-#define LCP32XX_TIMER_PC(x)			io_p2v((x) + 0x10)
-#define LCP32XX_TIMER_MCR(x)			io_p2v((x) + 0x14)
-#define LCP32XX_TIMER_MR0(x)			io_p2v((x) + 0x18)
-#define LCP32XX_TIMER_MR1(x)			io_p2v((x) + 0x1C)
-#define LCP32XX_TIMER_MR2(x)			io_p2v((x) + 0x20)
-#define LCP32XX_TIMER_MR3(x)			io_p2v((x) + 0x24)
-#define LCP32XX_TIMER_CCR(x)			io_p2v((x) + 0x28)
-#define LCP32XX_TIMER_CR0(x)			io_p2v((x) + 0x2C)
-#define LCP32XX_TIMER_CR1(x)			io_p2v((x) + 0x30)
-#define LCP32XX_TIMER_CR2(x)			io_p2v((x) + 0x34)
-#define LCP32XX_TIMER_CR3(x)			io_p2v((x) + 0x38)
-#define LCP32XX_TIMER_EMR(x)			io_p2v((x) + 0x3C)
-#define LCP32XX_TIMER_CTCR(x)			io_p2v((x) + 0x70)
+#define LPC32XX_TIMER_IR(x)			io_p2v((x) + 0x00)
+#define LPC32XX_TIMER_TCR(x)			io_p2v((x) + 0x04)
+#define LPC32XX_TIMER_TC(x)			io_p2v((x) + 0x08)
+#define LPC32XX_TIMER_PR(x)			io_p2v((x) + 0x0C)
+#define LPC32XX_TIMER_PC(x)			io_p2v((x) + 0x10)
+#define LPC32XX_TIMER_MCR(x)			io_p2v((x) + 0x14)
+#define LPC32XX_TIMER_MR0(x)			io_p2v((x) + 0x18)
+#define LPC32XX_TIMER_MR1(x)			io_p2v((x) + 0x1C)
+#define LPC32XX_TIMER_MR2(x)			io_p2v((x) + 0x20)
+#define LPC32XX_TIMER_MR3(x)			io_p2v((x) + 0x24)
+#define LPC32XX_TIMER_CCR(x)			io_p2v((x) + 0x28)
+#define LPC32XX_TIMER_CR0(x)			io_p2v((x) + 0x2C)
+#define LPC32XX_TIMER_CR1(x)			io_p2v((x) + 0x30)
+#define LPC32XX_TIMER_CR2(x)			io_p2v((x) + 0x34)
+#define LPC32XX_TIMER_CR3(x)			io_p2v((x) + 0x38)
+#define LPC32XX_TIMER_EMR(x)			io_p2v((x) + 0x3C)
+#define LPC32XX_TIMER_CTCR(x)			io_p2v((x) + 0x70)
 
 /*
  * ir register definitions
  */
-#define LCP32XX_TIMER_CNTR_MTCH_BIT(n)		(1 << ((n) & 0x3))
-#define LCP32XX_TIMER_CNTR_CAPT_BIT(n)		(1 << (4 + ((n) & 0x3)))
+#define LPC32XX_TIMER_CNTR_MTCH_BIT(n)		(1 << ((n) & 0x3))
+#define LPC32XX_TIMER_CNTR_CAPT_BIT(n)		(1 << (4 + ((n) & 0x3)))
 
 /*
  * tcr register definitions
  */
-#define LCP32XX_TIMER_CNTR_TCR_EN		0x1
-#define LCP32XX_TIMER_CNTR_TCR_RESET		0x2
+#define LPC32XX_TIMER_CNTR_TCR_EN		0x1
+#define LPC32XX_TIMER_CNTR_TCR_RESET		0x2
 
 /*
  * mcr register definitions
  */
-#define LCP32XX_TIMER_CNTR_MCR_MTCH(n)		(0x1 << ((n) * 3))
-#define LCP32XX_TIMER_CNTR_MCR_RESET(n)		(0x1 << (((n) * 3) + 1))
-#define LCP32XX_TIMER_CNTR_MCR_STOP(n)		(0x1 << (((n) * 3) + 2))
+#define LPC32XX_TIMER_CNTR_MCR_MTCH(n)		(0x1 << ((n) * 3))
+#define LPC32XX_TIMER_CNTR_MCR_RESET(n)		(0x1 << (((n) * 3) + 1))
+#define LPC32XX_TIMER_CNTR_MCR_STOP(n)		(0x1 << (((n) * 3) + 2))
 
 /*
  * Standard UART register offsets
@@ -690,5 +690,8 @@
 #define LPC32XX_GPIO_P1_MUX_SET			_GPREG(0x130)
 #define LPC32XX_GPIO_P1_MUX_CLR			_GPREG(0x134)
 #define LPC32XX_GPIO_P1_MUX_STATE		_GPREG(0x138)
+#define LPC32XX_GPIO_P2_MUX_SET			_GPREG(0x028)
+#define LPC32XX_GPIO_P2_MUX_CLR			_GPREG(0x02C)
+#define LPC32XX_GPIO_P2_MUX_STATE		_GPREG(0x030)
 
 #endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/system.h b/arch/arm/mach-lpc32xx/include/mach/system.h
deleted file mode 100644
index bf176c9..0000000
--- a/arch/arm/mach-lpc32xx/include/mach/system.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * arch/arm/mach-lpc32xx/include/mach/system.h
- *
- * Author: Kevin Wells <kevin.wells@nxp.com>
- *
- * Copyright (C) 2010 NXP Semiconductors
- *
- * 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-lpc32xx/irq.c b/arch/arm/mach-lpc32xx/irq.c
index c74de01..d080cb1 100644
--- a/arch/arm/mach-lpc32xx/irq.c
+++ b/arch/arm/mach-lpc32xx/irq.c
@@ -150,6 +150,10 @@
 		.event_group = &lpc32xx_event_int_regs,
 		.mask = LPC32XX_CLKPWR_INTSRC_KEY_BIT,
 	},
+	[IRQ_LPC32XX_ETHERNET] = {
+		.event_group = &lpc32xx_event_int_regs,
+		.mask = LPC32XX_CLKPWR_INTSRC_MAC_BIT,
+	},
 	[IRQ_LPC32XX_USB_OTG_ATX] = {
 		.event_group = &lpc32xx_event_int_regs,
 		.mask = LPC32XX_CLKPWR_INTSRC_USBATXINT_BIT,
diff --git a/arch/arm/mach-lpc32xx/phy3250.c b/arch/arm/mach-lpc32xx/phy3250.c
index bfee5b4..7f7401e 100644
--- a/arch/arm/mach-lpc32xx/phy3250.c
+++ b/arch/arm/mach-lpc32xx/phy3250.c
@@ -37,6 +37,7 @@
 
 #include <mach/hardware.h>
 #include <mach/platform.h>
+#include <mach/board.h>
 #include <mach/gpio-lpc32xx.h>
 #include "common.h"
 
@@ -149,20 +150,8 @@
 	.remove		= lpc32xx_clcd_remove,
 };
 
-static struct amba_device lpc32xx_clcd_device = {
-	.dev				= {
-		.coherent_dma_mask	= ~0,
-		.init_name		= "dev:clcd",
-		.platform_data		= &lpc32xx_clcd_data,
-	},
-	.res				= {
-		.start			= LPC32XX_LCD_BASE,
-		.end			= (LPC32XX_LCD_BASE + SZ_4K - 1),
-		.flags			= IORESOURCE_MEM,
-	},
-	.dma_mask			= ~0,
-	.irq				= {IRQ_LPC32XX_LCD, NO_IRQ},
-};
+static AMBA_AHB_DEVICE(lpc32xx_clcd, "dev:clcd", 0,
+	LPC32XX_LCD_BASE, { IRQ_LPC32XX_LCD }, &lpc32xx_clcd_data);
 
 /*
  * AMBA SSP (SPI)
@@ -191,20 +180,8 @@
 	.enable_dma		= 0,
 };
 
-static struct amba_device lpc32xx_ssp0_device = {
-	.dev				= {
-		.coherent_dma_mask	= ~0,
-		.init_name		= "dev:ssp0",
-		.platform_data		= &lpc32xx_ssp0_data,
-	},
-	.res				= {
-		.start			= LPC32XX_SSP0_BASE,
-		.end			= (LPC32XX_SSP0_BASE + SZ_4K - 1),
-		.flags			= IORESOURCE_MEM,
-	},
-	.dma_mask			= ~0,
-	.irq				= {IRQ_LPC32XX_SSP0, NO_IRQ},
-};
+static AMBA_APB_DEVICE(lpc32xx_ssp0, "dev:ssp0", 0,
+	LPC32XX_SSP0_BASE, { IRQ_LPC32XX_SSP0 }, &lpc32xx_ssp0_data);
 
 /* AT25 driver registration */
 static int __init phy3250_spi_board_register(void)
@@ -271,11 +248,16 @@
 };
 
 static struct platform_device *phy3250_devs[] __initdata = {
+	&lpc32xx_rtc_device,
+	&lpc32xx_tsc_device,
 	&lpc32xx_i2c0_device,
 	&lpc32xx_i2c1_device,
 	&lpc32xx_i2c2_device,
 	&lpc32xx_watchdog_device,
 	&lpc32xx_gpio_led_device,
+	&lpc32xx_adc_device,
+	&lpc32xx_ohci_device,
+	&lpc32xx_net_device,
 };
 
 static struct amba_device *amba_devs[] __initdata = {
diff --git a/arch/arm/mach-lpc32xx/pm.c b/arch/arm/mach-lpc32xx/pm.c
index b9c8059..207e812 100644
--- a/arch/arm/mach-lpc32xx/pm.c
+++ b/arch/arm/mach-lpc32xx/pm.c
@@ -13,7 +13,7 @@
 /*
  * LPC32XX CPU and system power management
  *
- * The LCP32XX has three CPU modes for controlling system power: run,
+ * The LPC32XX has three CPU modes for controlling system power: run,
  * direct-run, and halt modes. When switching between halt and run modes,
  * the CPU transistions through direct-run mode. For Linux, direct-run
  * mode is not used in normal operation. Halt mode is used when the
diff --git a/arch/arm/mach-lpc32xx/timer.c b/arch/arm/mach-lpc32xx/timer.c
index b42c909b..c40667c 100644
--- a/arch/arm/mach-lpc32xx/timer.c
+++ b/arch/arm/mach-lpc32xx/timer.c
@@ -34,11 +34,11 @@
 static int lpc32xx_clkevt_next_event(unsigned long delta,
     struct clock_event_device *dev)
 {
-	__raw_writel(LCP32XX_TIMER_CNTR_TCR_RESET,
-		LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
-	__raw_writel(delta, LCP32XX_TIMER_PR(LPC32XX_TIMER0_BASE));
-	__raw_writel(LCP32XX_TIMER_CNTR_TCR_EN,
-		LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+	__raw_writel(LPC32XX_TIMER_CNTR_TCR_RESET,
+		LPC32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+	__raw_writel(delta, LPC32XX_TIMER_PR(LPC32XX_TIMER0_BASE));
+	__raw_writel(LPC32XX_TIMER_CNTR_TCR_EN,
+		LPC32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
 
 	return 0;
 }
@@ -58,7 +58,7 @@
 		 * disable the timer to wait for the first call to
 		 * set_next_event().
 		 */
-		__raw_writel(0, LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+		__raw_writel(0, LPC32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
 		break;
 
 	case CLOCK_EVT_MODE_UNUSED:
@@ -81,8 +81,8 @@
 	struct clock_event_device *evt = &lpc32xx_clkevt;
 
 	/* Clear match */
-	__raw_writel(LCP32XX_TIMER_CNTR_MTCH_BIT(0),
-		LCP32XX_TIMER_IR(LPC32XX_TIMER0_BASE));
+	__raw_writel(LPC32XX_TIMER_CNTR_MTCH_BIT(0),
+		LPC32XX_TIMER_IR(LPC32XX_TIMER0_BASE));
 
 	evt->event_handler(evt);
 
@@ -128,14 +128,14 @@
 	clkrate = clkrate / clk_get_pclk_div();
 
 	/* Initial timer setup */
-	__raw_writel(0, LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
-	__raw_writel(LCP32XX_TIMER_CNTR_MTCH_BIT(0),
-		LCP32XX_TIMER_IR(LPC32XX_TIMER0_BASE));
-	__raw_writel(1, LCP32XX_TIMER_MR0(LPC32XX_TIMER0_BASE));
-	__raw_writel(LCP32XX_TIMER_CNTR_MCR_MTCH(0) |
-		LCP32XX_TIMER_CNTR_MCR_STOP(0) |
-		LCP32XX_TIMER_CNTR_MCR_RESET(0),
-		LCP32XX_TIMER_MCR(LPC32XX_TIMER0_BASE));
+	__raw_writel(0, LPC32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+	__raw_writel(LPC32XX_TIMER_CNTR_MTCH_BIT(0),
+		LPC32XX_TIMER_IR(LPC32XX_TIMER0_BASE));
+	__raw_writel(1, LPC32XX_TIMER_MR0(LPC32XX_TIMER0_BASE));
+	__raw_writel(LPC32XX_TIMER_CNTR_MCR_MTCH(0) |
+		LPC32XX_TIMER_CNTR_MCR_STOP(0) |
+		LPC32XX_TIMER_CNTR_MCR_RESET(0),
+		LPC32XX_TIMER_MCR(LPC32XX_TIMER0_BASE));
 
 	/* Setup tick interrupt */
 	setup_irq(IRQ_LPC32XX_TIMER0, &lpc32xx_timer_irq);
@@ -151,14 +151,14 @@
 	clockevents_register_device(&lpc32xx_clkevt);
 
 	/* Use timer1 as clock source. */
-	__raw_writel(LCP32XX_TIMER_CNTR_TCR_RESET,
-		LCP32XX_TIMER_TCR(LPC32XX_TIMER1_BASE));
-	__raw_writel(0, LCP32XX_TIMER_PR(LPC32XX_TIMER1_BASE));
-	__raw_writel(0, LCP32XX_TIMER_MCR(LPC32XX_TIMER1_BASE));
-	__raw_writel(LCP32XX_TIMER_CNTR_TCR_EN,
-		LCP32XX_TIMER_TCR(LPC32XX_TIMER1_BASE));
+	__raw_writel(LPC32XX_TIMER_CNTR_TCR_RESET,
+		LPC32XX_TIMER_TCR(LPC32XX_TIMER1_BASE));
+	__raw_writel(0, LPC32XX_TIMER_PR(LPC32XX_TIMER1_BASE));
+	__raw_writel(0, LPC32XX_TIMER_MCR(LPC32XX_TIMER1_BASE));
+	__raw_writel(LPC32XX_TIMER_CNTR_TCR_EN,
+		LPC32XX_TIMER_TCR(LPC32XX_TIMER1_BASE));
 
-	clocksource_mmio_init(LCP32XX_TIMER_TC(LPC32XX_TIMER1_BASE),
+	clocksource_mmio_init(LPC32XX_TIMER_TC(LPC32XX_TIMER1_BASE),
 		"lpc32xx_clksrc", clkrate, 300, 32, clocksource_mmio_readl_up);
 }
 
diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig
index 323d4c9..5a90b9a 100644
--- a/arch/arm/mach-mmp/Kconfig
+++ b/arch/arm/mach-mmp/Kconfig
@@ -2,6 +2,16 @@
 
 menu "Marvell PXA168/910/MMP2 Implmentations"
 
+config MACH_MMP_DT
+	bool "Support MMP2 platforms from device tree"
+	select CPU_PXA168
+	select CPU_PXA910
+	select USE_OF
+	help
+	  Include support for Marvell MMP2 based platforms using
+	  the device tree. Needn't select any other machine while
+	  MACH_MMP_DT is enabled.
+
 config MACH_ASPENITE
 	bool "Marvell's PXA168 Aspenite Development Board"
 	select CPU_PXA168
diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
index ba254a7..4fc0ff5 100644
--- a/arch/arm/mach-mmp/Makefile
+++ b/arch/arm/mach-mmp/Makefile
@@ -18,5 +18,6 @@
 obj-$(CONFIG_MACH_BROWNSTONE)	+= brownstone.o
 obj-$(CONFIG_MACH_FLINT)	+= flint.o
 obj-$(CONFIG_MACH_MARVELL_JASPER) += jasper.o
+obj-$(CONFIG_MACH_MMP_DT)	+= mmp-dt.o
 obj-$(CONFIG_MACH_TETON_BGA)	+= teton_bga.o
 obj-$(CONFIG_MACH_GPLUGD)	+= gplugd.o
diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c
index 3588a55..bf5d8e1 100644
--- a/arch/arm/mach-mmp/aspenite.c
+++ b/arch/arm/mach-mmp/aspenite.c
@@ -23,6 +23,7 @@
 #include <mach/addr-map.h>
 #include <mach/mfp-pxa168.h>
 #include <mach/pxa168.h>
+#include <mach/irqs.h>
 #include <video/pxa168fb.h>
 #include <linux/input.h>
 #include <plat/pxa27x_keypad.h>
@@ -239,7 +240,7 @@
 
 MACHINE_START(ASPENITE, "PXA168-based Aspenite Development Platform")
 	.map_io		= mmp_map_io,
-	.nr_irqs	= IRQ_BOARD_START,
+	.nr_irqs	= MMP_NR_IRQS,
 	.init_irq       = pxa168_init_irq,
 	.timer          = &pxa168_timer,
 	.init_machine   = common_init,
@@ -248,7 +249,7 @@
 
 MACHINE_START(ZYLONITE2, "PXA168-based Zylonite2 Development Platform")
 	.map_io		= mmp_map_io,
-	.nr_irqs	= IRQ_BOARD_START,
+	.nr_irqs	= MMP_NR_IRQS,
 	.init_irq       = pxa168_init_irq,
 	.timer          = &pxa168_timer,
 	.init_machine   = common_init,
diff --git a/arch/arm/mach-mmp/avengers_lite.c b/arch/arm/mach-mmp/avengers_lite.c
index b148a9d..603542a 100644
--- a/arch/arm/mach-mmp/avengers_lite.c
+++ b/arch/arm/mach-mmp/avengers_lite.c
@@ -43,6 +43,7 @@
 
 MACHINE_START(AVENGERS_LITE, "PXA168 Avengers lite Development Platform")
 	.map_io		= mmp_map_io,
+	.nr_irqs	= MMP_NR_IRQS,
 	.init_irq       = pxa168_init_irq,
 	.timer          = &pxa168_timer,
 	.init_machine   = avengers_lite_init,
diff --git a/arch/arm/mach-mmp/brownstone.c b/arch/arm/mach-mmp/brownstone.c
index d839fe6..5cb769c 100644
--- a/arch/arm/mach-mmp/brownstone.c
+++ b/arch/arm/mach-mmp/brownstone.c
@@ -28,7 +28,7 @@
 
 #include "common.h"
 
-#define BROWNSTONE_NR_IRQS	(IRQ_BOARD_START + 40)
+#define BROWNSTONE_NR_IRQS	(MMP_NR_IRQS + 40)
 
 #define GPIO_5V_ENABLE		(89)
 
@@ -158,7 +158,7 @@
 };
 
 static struct max8925_platform_data brownstone_max8925_info = {
-	.irq_base		= IRQ_BOARD_START,
+	.irq_base		= MMP_NR_IRQS,
 };
 
 static struct i2c_board_info brownstone_twsi1_info[] = {
diff --git a/arch/arm/mach-mmp/common.c b/arch/arm/mach-mmp/common.c
index 062b5b9..9292b79 100644
--- a/arch/arm/mach-mmp/common.c
+++ b/arch/arm/mach-mmp/common.c
@@ -14,6 +14,7 @@
 
 #include <asm/page.h>
 #include <asm/mach/map.h>
+#include <asm/system_misc.h>
 #include <mach/addr-map.h>
 #include <mach/cputype.h>
 
diff --git a/arch/arm/mach-mmp/flint.c b/arch/arm/mach-mmp/flint.c
index 2ee8cd7..8059cc0 100644
--- a/arch/arm/mach-mmp/flint.c
+++ b/arch/arm/mach-mmp/flint.c
@@ -23,10 +23,11 @@
 #include <mach/addr-map.h>
 #include <mach/mfp-mmp2.h>
 #include <mach/mmp2.h>
+#include <mach/irqs.h>
 
 #include "common.h"
 
-#define FLINT_NR_IRQS	(IRQ_BOARD_START + 48)
+#define FLINT_NR_IRQS	(MMP_NR_IRQS + 48)
 
 static unsigned long flint_pin_config[] __initdata = {
 	/* UART1 */
diff --git a/arch/arm/mach-mmp/gplugd.c b/arch/arm/mach-mmp/gplugd.c
index 8776546..f516e74 100644
--- a/arch/arm/mach-mmp/gplugd.c
+++ b/arch/arm/mach-mmp/gplugd.c
@@ -191,7 +191,7 @@
 
 MACHINE_START(GPLUGD, "PXA168-based GuruPlug Display (gplugD) Platform")
 	.map_io		= mmp_map_io,
-	.nr_irqs	= IRQ_BOARD_START,
+	.nr_irqs	= MMP_NR_IRQS,
 	.init_irq       = pxa168_init_irq,
 	.timer          = &pxa168_timer,
 	.init_machine   = gplugd_init,
diff --git a/arch/arm/mach-mmp/include/mach/addr-map.h b/arch/arm/mach-mmp/include/mach/addr-map.h
index 3e404ac..b1ece08 100644
--- a/arch/arm/mach-mmp/include/mach/addr-map.h
+++ b/arch/arm/mach-mmp/include/mach/addr-map.h
@@ -11,12 +11,6 @@
 #ifndef __ASM_MACH_ADDR_MAP_H
 #define __ASM_MACH_ADDR_MAP_H
 
-#ifndef __ASSEMBLER__
-#define IOMEM(x)	((void __iomem *)(x))
-#else
-#define IOMEM(x)	(x)
-#endif
-
 /* APB - Application Subsystem Peripheral Bus
  *
  * NOTE: the DMA controller registers are actually on the AXI fabric #1
diff --git a/arch/arm/mach-mmp/include/mach/entry-macro.S b/arch/arm/mach-mmp/include/mach/entry-macro.S
index c42d9d4..9cff9e7 100644
--- a/arch/arm/mach-mmp/include/mach/entry-macro.S
+++ b/arch/arm/mach-mmp/include/mach/entry-macro.S
@@ -8,12 +8,6 @@
 
 #include <mach/regs-icu.h>
 
-	.macro	disable_fiq
-	.endm
-
-	.macro	arch_ret_to_user, tmp1, tmp2
-	.endm
-
 	.macro	get_irqnr_preamble, base, tmp
 	mrc	p15, 0, \tmp, c0, c0, 0		@ CPUID
 	and	\tmp, \tmp, #0xff00
diff --git a/arch/arm/mach-mmp/include/mach/io.h b/arch/arm/mach-mmp/include/mach/io.h
deleted file mode 100644
index e7adf3d..0000000
--- a/arch/arm/mach-mmp/include/mach/io.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * linux/arch/arm/mach-mmp/include/mach/io.h
- *
- * 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 __ASM_MACH_IO_H
-#define __ASM_MACH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-/*
- * We don't actually have real ISA nor PCI buses, but there is so many
- * drivers out there that might just work if we fake them...
- */
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#endif /* __ASM_MACH_IO_H */
diff --git a/arch/arm/mach-mmp/include/mach/irqs.h b/arch/arm/mach-mmp/include/mach/irqs.h
index 34635a0..d0e7466 100644
--- a/arch/arm/mach-mmp/include/mach/irqs.h
+++ b/arch/arm/mach-mmp/include/mach/irqs.h
@@ -223,7 +223,6 @@
 #define MMP_GPIO_TO_IRQ(gpio)		(IRQ_GPIO_START + (gpio))
 
 #define IRQ_BOARD_START			(IRQ_GPIO_START + MMP_NR_BUILTIN_GPIO)
-
-#define NR_IRQS				(IRQ_BOARD_START)
+#define MMP_NR_IRQS			IRQ_BOARD_START
 
 #endif /* __ASM_MACH_IRQS_H */
diff --git a/arch/arm/mach-mmp/include/mach/pxa910.h b/arch/arm/mach-mmp/include/mach/pxa910.h
index 4de13ab..e2e1f1e 100644
--- a/arch/arm/mach-mmp/include/mach/pxa910.h
+++ b/arch/arm/mach-mmp/include/mach/pxa910.h
@@ -22,6 +22,7 @@
 extern struct pxa_device_desc pxa910_device_nand;
 
 extern struct platform_device pxa910_device_gpio;
+extern struct platform_device pxa910_device_rtc;
 
 static inline int pxa910_add_uart(int id)
 {
diff --git a/arch/arm/mach-mmp/include/mach/regs-apbc.h b/arch/arm/mach-mmp/include/mach/regs-apbc.h
index 1a96585..8a37fb0 100644
--- a/arch/arm/mach-mmp/include/mach/regs-apbc.h
+++ b/arch/arm/mach-mmp/include/mach/regs-apbc.h
@@ -57,6 +57,7 @@
 #define APBC_PXA910_SSP1	APBC_REG(0x01c)
 #define APBC_PXA910_SSP2	APBC_REG(0x020)
 #define APBC_PXA910_IPC		APBC_REG(0x024)
+#define APBC_PXA910_RTC		APBC_REG(0x028)
 #define APBC_PXA910_TWSI0	APBC_REG(0x02c)
 #define APBC_PXA910_KPC		APBC_REG(0x030)
 #define APBC_PXA910_TIMERS	APBC_REG(0x034)
diff --git a/arch/arm/mach-mmp/include/mach/regs-rtc.h b/arch/arm/mach-mmp/include/mach/regs-rtc.h
new file mode 100644
index 0000000..5bff886
--- /dev/null
+++ b/arch/arm/mach-mmp/include/mach/regs-rtc.h
@@ -0,0 +1,23 @@
+#ifndef __ASM_MACH_REGS_RTC_H
+#define __ASM_MACH_REGS_RTC_H
+
+#include <mach/addr-map.h>
+
+#define RTC_VIRT_BASE	(APB_VIRT_BASE + 0x10000)
+#define RTC_REG(x)	(*((volatile u32 __iomem *)(RTC_VIRT_BASE + (x))))
+
+/*
+ * Real Time Clock
+ */
+
+#define RCNR		RTC_REG(0x00)	/* RTC Count Register */
+#define RTAR		RTC_REG(0x04)	/* RTC Alarm Register */
+#define RTSR		RTC_REG(0x08)	/* RTC Status Register */
+#define RTTR		RTC_REG(0x0C)	/* RTC Timer Trim Register */
+
+#define RTSR_HZE	(1 << 3)	/* HZ interrupt enable */
+#define RTSR_ALE	(1 << 2)	/* RTC alarm interrupt enable */
+#define RTSR_HZ		(1 << 1)	/* HZ rising-edge detected */
+#define RTSR_AL		(1 << 0)	/* RTC alarm detected */
+
+#endif /* __ASM_MACH_REGS_RTC_H */
diff --git a/arch/arm/mach-mmp/include/mach/system.h b/arch/arm/mach-mmp/include/mach/system.h
deleted file mode 100644
index 1d001ea..0000000
--- a/arch/arm/mach-mmp/include/mach/system.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * linux/arch/arm/mach-mmp/include/mach/system.h
- *
- * 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 __ASM_MACH_SYSTEM_H
-#define __ASM_MACH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
-#endif /* __ASM_MACH_SYSTEM_H */
diff --git a/arch/arm/mach-mmp/irq-mmp2.c b/arch/arm/mach-mmp/irq-mmp2.c
index d21c544..7895d27 100644
--- a/arch/arm/mach-mmp/irq-mmp2.c
+++ b/arch/arm/mach-mmp/irq-mmp2.c
@@ -15,6 +15,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 
+#include <mach/irqs.h>
 #include <mach/regs-icu.h>
 #include <mach/mmp2.h>
 
diff --git a/arch/arm/mach-mmp/jasper.c b/arch/arm/mach-mmp/jasper.c
index 96cf5c8..ff73249 100644
--- a/arch/arm/mach-mmp/jasper.c
+++ b/arch/arm/mach-mmp/jasper.c
@@ -19,6 +19,7 @@
 #include <linux/mfd/max8925.h>
 #include <linux/interrupt.h>
 
+#include <mach/irqs.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/addr-map.h>
@@ -27,7 +28,7 @@
 
 #include "common.h"
 
-#define JASPER_NR_IRQS		(IRQ_BOARD_START + 48)
+#define JASPER_NR_IRQS		(MMP_NR_IRQS + 48)
 
 static unsigned long jasper_pin_config[] __initdata = {
 	/* UART1 */
@@ -135,7 +136,7 @@
 static struct max8925_platform_data jasper_max8925_info = {
 	.backlight		= &jasper_backlight_data,
 	.power			= &jasper_power_data,
-	.irq_base		= IRQ_BOARD_START,
+	.irq_base		= MMP_NR_IRQS,
 };
 
 static struct i2c_board_info jasper_twsi1_info[] = {
diff --git a/arch/arm/mach-mmp/mmp-dt.c b/arch/arm/mach-mmp/mmp-dt.c
new file mode 100644
index 0000000..6707539
--- /dev/null
+++ b/arch/arm/mach-mmp/mmp-dt.c
@@ -0,0 +1,75 @@
+/*
+ *  linux/arch/arm/mach-mmp/mmp-dt.c
+ *
+ *  Copyright (C) 2012 Marvell Technology Group Ltd.
+ *  Author: Haojian Zhuang <haojian.zhuang@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
+ *  publishhed by the Free Software Foundation.
+ */
+
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <mach/irqs.h>
+
+#include "common.h"
+
+extern struct sys_timer pxa168_timer;
+extern void __init icu_init_irq(void);
+
+static const struct of_dev_auxdata mmp_auxdata_lookup[] __initconst = {
+	OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4026000, "pxa2xx-uart.2", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4025000, "pxa2xx-i2c.1", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-gpio", 0xd4019000, "pxa-gpio", NULL),
+	OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
+	{}
+};
+
+static int __init mmp_intc_add_irq_domain(struct device_node *np,
+					   struct device_node *parent)
+{
+	irq_domain_add_simple(np, 0);
+	return 0;
+}
+
+static int __init mmp_gpio_add_irq_domain(struct device_node *np,
+					   struct device_node *parent)
+{
+	irq_domain_add_simple(np, IRQ_GPIO_START);
+	return 0;
+}
+
+static const struct of_device_id mmp_irq_match[] __initconst = {
+	{ .compatible = "mrvl,mmp-intc", .data = mmp_intc_add_irq_domain, },
+	{ .compatible = "mrvl,mmp-gpio", .data = mmp_gpio_add_irq_domain, },
+	{}
+};
+
+static void __init mmp_dt_init(void)
+{
+
+	of_irq_init(mmp_irq_match);
+
+	of_platform_populate(NULL, of_default_bus_match_table,
+			     mmp_auxdata_lookup, NULL);
+}
+
+static const char *pxa168_dt_board_compat[] __initdata = {
+	"mrvl,pxa168-aspenite",
+	NULL,
+};
+
+DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)")
+	.map_io		= mmp_map_io,
+	.init_irq	= icu_init_irq,
+	.timer		= &pxa168_timer,
+	.init_machine	= mmp_dt_init,
+	.dt_compat	= pxa168_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c
index 617c60a..c709a24 100644
--- a/arch/arm/mach-mmp/mmp2.c
+++ b/arch/arm/mach-mmp/mmp2.c
@@ -223,6 +223,7 @@
 	}, {
 		.start	= IRQ_MMP2_GPIO,
 		.end	= IRQ_MMP2_GPIO,
+		.name	= "gpio_mux",
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index ada1213..b24d2c3 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -16,6 +16,7 @@
 #include <linux/platform_device.h>
 
 #include <asm/mach/time.h>
+#include <asm/system_misc.h>
 #include <mach/addr-map.h>
 #include <mach/cputype.h>
 #include <mach/regs-apbc.h>
@@ -64,6 +65,7 @@
 static APBC_CLK(ssp5, PXA168_SSP5, 4, 0);
 static APBC_CLK(gpio, PXA168_GPIO, 0, 13000000);
 static APBC_CLK(keypad, PXA168_KPC, 0, 32000);
+static APBC_CLK(rtc, PXA168_RTC, 8, 32768);
 
 static APMU_CLK(nand, NAND, 0x19b, 156000000);
 static APMU_CLK(lcd, LCD, 0x7f, 312000000);
@@ -92,6 +94,7 @@
 	INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL),
 	INIT_CLKREG(&clk_eth, "pxa168-eth", "MFUCLK"),
 	INIT_CLKREG(&clk_usb, "pxa168-ehci", "PXA168-USBCLK"),
+	INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
 };
 
 static int __init pxa168_init(void)
@@ -166,6 +169,7 @@
 	}, {
 		.start	= IRQ_PXA168_GPIOX,
 		.end	= IRQ_PXA168_GPIOX,
+		.name	= "gpio_mux",
 		.flags	= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index 3241a25..43f8bcc 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -92,6 +92,7 @@
 static APBC_CLK(pwm3, PXA910_PWM3, 1, 13000000);
 static APBC_CLK(pwm4, PXA910_PWM4, 1, 13000000);
 static APBC_CLK(gpio, PXA910_GPIO, 0, 13000000);
+static APBC_CLK(rtc, PXA910_RTC, 8, 32768);
 
 static APMU_CLK(nand, NAND, 0x19b, 156000000);
 static APMU_CLK(u2o, USB, 0x1b, 480000000);
@@ -109,6 +110,7 @@
 	INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
 	INIT_CLKREG(&clk_gpio, "pxa-gpio", NULL),
 	INIT_CLKREG(&clk_u2o, "pxa-u2o", "U2OCLK"),
+	INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
 };
 
 static int __init pxa910_init(void)
@@ -173,6 +175,7 @@
 	}, {
 		.start	= IRQ_PXA910_AP_GPIO,
 		.end	= IRQ_PXA910_AP_GPIO,
+		.name	= "gpio_mux",
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -183,3 +186,28 @@
 	.num_resources	= ARRAY_SIZE(pxa910_resource_gpio),
 	.resource	= pxa910_resource_gpio,
 };
+
+static struct resource pxa910_resource_rtc[] = {
+	{
+		.start	= 0xd4010000,
+		.end	= 0xd401003f,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_PXA910_RTC_INT,
+		.end	= IRQ_PXA910_RTC_INT,
+		.name	= "rtc 1Hz",
+		.flags	= IORESOURCE_IRQ,
+	}, {
+		.start	= IRQ_PXA910_RTC_ALARM,
+		.end	= IRQ_PXA910_RTC_ALARM,
+		.name	= "rtc alarm",
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device pxa910_device_rtc = {
+	.name		= "sa1100-rtc",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(pxa910_resource_rtc),
+	.resource	= pxa910_resource_rtc,
+};
diff --git a/arch/arm/mach-mmp/tavorevb.c b/arch/arm/mach-mmp/tavorevb.c
index bc97170..b28f908 100644
--- a/arch/arm/mach-mmp/tavorevb.c
+++ b/arch/arm/mach-mmp/tavorevb.c
@@ -101,6 +101,7 @@
 
 MACHINE_START(TAVOREVB, "PXA910 Evaluation Board (aka TavorEVB)")
 	.map_io		= mmp_map_io,
+	.nr_irqs	= MMP_NR_IRQS,
 	.init_irq       = pxa910_init_irq,
 	.timer          = &pxa910_timer,
 	.init_machine   = tavorevb_init,
diff --git a/arch/arm/mach-mmp/teton_bga.c b/arch/arm/mach-mmp/teton_bga.c
index 0523e42..42bef66 100644
--- a/arch/arm/mach-mmp/teton_bga.c
+++ b/arch/arm/mach-mmp/teton_bga.c
@@ -26,6 +26,7 @@
 #include <mach/mfp-pxa168.h>
 #include <mach/pxa168.h>
 #include <mach/teton_bga.h>
+#include <mach/irqs.h>
 
 #include "common.h"
 
@@ -83,7 +84,7 @@
 
 MACHINE_START(TETON_BGA, "PXA168-based Teton BGA Development Platform")
 	.map_io		= mmp_map_io,
-	.nr_irqs	= IRQ_BOARD_START,
+	.nr_irqs	= MMP_NR_IRQS,
 	.init_irq       = pxa168_init_irq,
 	.timer          = &pxa168_timer,
 	.init_machine   = teton_bga_init,
diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
index 5ac5d58..3fc9ed2 100644
--- a/arch/arm/mach-mmp/ttc_dkb.c
+++ b/arch/arm/mach-mmp/ttc_dkb.c
@@ -38,7 +38,7 @@
  * 16 board interrupts -- PCA9575 GPIO expander
  * 24 board interrupts -- 88PM860x PMIC
  */
-#define TTCDKB_NR_IRQS		(IRQ_BOARD_START + 16 + 16 + 24)
+#define TTCDKB_NR_IRQS		(MMP_NR_IRQS + 16 + 16 + 24)
 
 static unsigned long ttc_dkb_pin_config[] __initdata = {
 	/* UART2 */
@@ -124,13 +124,14 @@
 
 static struct platform_device *ttc_dkb_devices[] = {
 	&pxa910_device_gpio,
+	&pxa910_device_rtc,
 	&ttc_dkb_device_onenand,
 };
 
 static struct pca953x_platform_data max7312_data[] = {
 	{
 		.gpio_base	= TTCDKB_GPIO_EXT0(0),
-		.irq_base	= IRQ_BOARD_START,
+		.irq_base	= MMP_NR_IRQS,
 	},
 };
 
diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c
index a60ab6d..3698a37 100644
--- a/arch/arm/mach-msm/board-halibut.c
+++ b/arch/arm/mach-msm/board-halibut.c
@@ -68,6 +68,11 @@
 
 extern struct sys_timer msm_timer;
 
+static void __init halibut_init_early(void)
+{
+	arch_ioremap_caller = __msm_ioremap_caller;
+}
+
 static void __init halibut_init_irq(void)
 {
 	msm_init_irq();
@@ -96,6 +101,7 @@
 	.atag_offset	= 0x100,
 	.fixup		= halibut_fixup,
 	.map_io		= halibut_map_io,
+	.init_early	= halibut_init_early,
 	.init_irq	= halibut_init_irq,
 	.init_machine	= halibut_init,
 	.timer		= &msm_timer,
diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c
index 97b8191..4a8ea0d 100644
--- a/arch/arm/mach-msm/board-sapphire.c
+++ b/arch/arm/mach-msm/board-sapphire.c
@@ -27,7 +27,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/flash.h>
-#include <asm/system.h>
 #include <mach/system.h>
 #include <mach/vreg.h>
 #include <mach/board.h>
diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c
index 6b9b227..5414f76 100644
--- a/arch/arm/mach-msm/board-trout.c
+++ b/arch/arm/mach-msm/board-trout.c
@@ -43,6 +43,11 @@
 
 extern struct sys_timer msm_timer;
 
+static void __init trout_init_early(void)
+{
+	arch_ioremap_caller = __msm_ioremap_caller;
+}
+
 static void __init trout_init_irq(void)
 {
 	msm_init_irq();
@@ -96,6 +101,7 @@
 	.atag_offset	= 0x100,
 	.fixup		= trout_fixup,
 	.map_io		= trout_map_io,
+	.init_early	= trout_init_early,
 	.init_irq	= trout_init_irq,
 	.init_machine	= trout_init,
 	.timer		= &msm_timer,
diff --git a/arch/arm/mach-msm/idle.S b/arch/arm/mach-msm/idle.S
deleted file mode 100644
index 6a94f05..0000000
--- a/arch/arm/mach-msm/idle.S
+++ /dev/null
@@ -1,36 +0,0 @@
-/* arch/arm/mach-msm/include/mach/idle.S
- *
- * Idle processing for MSM7K - work around bugs with SWFI.
- *
- * Copyright (c) 2007 QUALCOMM Incorporated.
- * Copyright (C) 2007 Google, Inc. 
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */ 
-		
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-
-ENTRY(arch_idle)
-#ifdef CONFIG_MSM7X00A_IDLE
-	mrc     p15, 0, r1, c1, c0, 0    /* read current CR    */
-	bic     r0, r1, #(1 << 2)        /* clear dcache bit   */
-	bic     r0, r0, #(1 << 12)       /* clear icache bit   */
-	mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */
-
-	mov     r0, #0                   /* prepare wfi value  */
-	mcr     p15, 0, r0, c7, c10, 0   /* flush the cache    */
-	mcr     p15, 0, r0, c7, c10, 4   /* memory barrier     */
-	mcr     p15, 0, r0, c7, c0, 4    /* wait for interrupt */
-
-	mcr     p15, 0, r1, c1, c0, 0    /* restore d/i cache  */
-#endif
-	mov     pc, lr
diff --git a/arch/arm/mach-msm/idle.c b/arch/arm/mach-msm/idle.c
new file mode 100644
index 0000000..0c9e13c
--- /dev/null
+++ b/arch/arm/mach-msm/idle.c
@@ -0,0 +1,49 @@
+/* arch/arm/mach-msm/idle.c
+ *
+ * Idle processing for MSM7K - work around bugs with SWFI.
+ *
+ * Copyright (c) 2007 QUALCOMM Incorporated.
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <asm/system.h>
+
+static void msm_idle(void)
+{
+#ifdef CONFIG_MSM7X00A_IDLE
+	asm volatile (
+
+	"mrc     p15, 0, r1, c1, c0, 0    /* read current CR    */ \n\t"
+	"bic     r0, r1, #(1 << 2)        /* clear dcache bit   */ \n\t"
+	"bic     r0, r0, #(1 << 12)       /* clear icache bit   */ \n\t"
+	"mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */ \n\t"
+
+	"mov     r0, #0                   /* prepare wfi value  */ \n\t"
+	"mcr     p15, 0, r0, c7, c10, 0   /* flush the cache    */ \n\t"
+	"mcr     p15, 0, r0, c7, c10, 4   /* memory barrier     */ \n\t"
+	"mcr     p15, 0, r0, c7, c0, 4    /* wait for interrupt */ \n\t"
+
+	"mcr     p15, 0, r1, c1, c0, 0    /* restore d/i cache  */ \n\t"
+
+	: : : "r0","r1" );
+#endif
+}
+
+static int __init msm_idle_init(void)
+{
+	arm_pm_idle = msm_idle;
+	return 0;
+}
+
+arch_initcall(msm_idle_init);
diff --git a/arch/arm/mach-msm/include/mach/entry-macro.S b/arch/arm/mach-msm/include/mach/entry-macro.S
index 41f7003..f2ae9087 100644
--- a/arch/arm/mach-msm/include/mach/entry-macro.S
+++ b/arch/arm/mach-msm/include/mach/entry-macro.S
@@ -16,12 +16,6 @@
  *
  */
 
-	.macro	disable_fiq
-	.endm
-
-	.macro	arch_ret_to_user, tmp1, tmp2
-	.endm
-
 #if !defined(CONFIG_ARM_GIC)
 #include <mach/msm_iomap.h>
 
diff --git a/arch/arm/mach-msm/include/mach/io.h b/arch/arm/mach-msm/include/mach/io.h
deleted file mode 100644
index dc1b928..0000000
--- a/arch/arm/mach-msm/include/mach/io.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* arch/arm/mach-msm/include/mach/io.h
- *
- * Copyright (C) 2007 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __arch_ioremap __msm_ioremap
-#define __arch_iounmap __iounmap
-
-void __iomem *__msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype);
-
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)    (a)
-
-void msm_map_qsd8x50_io(void);
-void msm_map_msm7x30_io(void);
-void msm_map_msm8x60_io(void);
-void msm_map_msm8960_io(void);
-
-extern unsigned int msm_shared_ram_phys;
-
-#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h b/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h
index 8af4612..6c4046c 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h
@@ -38,12 +38,6 @@
  *
  */
 
-#ifdef __ASSEMBLY__
-#define IOMEM(x)	x
-#else
-#define IOMEM(x)	((void __force __iomem *)(x))
-#endif
-
 #define MSM_VIC_BASE          IOMEM(0xE0000000)
 #define MSM_VIC_PHYS          0xC0000000
 #define MSM_VIC_SIZE          SZ_4K
@@ -111,5 +105,11 @@
 #define MSM_AD5_PHYS          0xAC000000
 #define MSM_AD5_SIZE          (SZ_1M*13)
 
+#ifndef __ASSEMBLY__
+
+extern void __iomem *__msm_ioremap_caller(unsigned long phys_addr, size_t size,
+					  unsigned int mtype, void *caller);
+
+#endif
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h b/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
index 198202c..f944fe6 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
@@ -100,4 +100,8 @@
 #define MSM_HSUSB_PHYS        0xA3600000
 #define MSM_HSUSB_SIZE        SZ_1K
 
+#ifndef __ASSEMBLY__
+extern void msm_map_msm7x30_io(void);
+#endif
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8960.h b/arch/arm/mach-msm/include/mach/msm_iomap-8960.h
index 800b557..a1752c0 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8960.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8960.h
@@ -50,4 +50,8 @@
 #define MSM_DEBUG_UART_PHYS	0x16440000
 #endif
 
+#ifndef __ASSEMBLY__
+extern void msm_map_msm8960_io(void);
+#endif
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h
index 0faa894..da77cc1 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h
@@ -122,4 +122,8 @@
 #define MSM_SDC4_PHYS          0xA0600000
 #define MSM_SDC4_SIZE          SZ_4K
 
+#ifndef __ASSEMBLY__
+extern void msm_map_qsd8x50_io(void);
+#endif
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
index 54e12ca..5aed57d 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
@@ -67,4 +67,8 @@
 #define MSM_DEBUG_UART_PHYS	0x19C40000
 #endif
 
+#ifndef __ASSEMBLY__
+extern void msm_map_msm8x60_io(void);
+#endif
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 90682f4..00afdfb 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -37,12 +37,6 @@
  *
  */
 
-#ifdef __ASSEMBLY__
-#define IOMEM(x)	x
-#else
-#define IOMEM(x)	((void __force __iomem *)(x))
-#endif
-
 #if defined(CONFIG_ARCH_MSM7X30)
 #include "msm_iomap-7x30.h"
 #elif defined(CONFIG_ARCH_QSD8X50)
diff --git a/arch/arm/mach-msm/include/mach/system.h b/arch/arm/mach-msm/include/mach/system.h
index 311db2b..f5fb2ec 100644
--- a/arch/arm/mach-msm/include/mach/system.h
+++ b/arch/arm/mach-msm/include/mach/system.h
@@ -12,7 +12,6 @@
  * GNU General Public License for more details.
  *
  */
-void arch_idle(void);
 
 /* low level hardware reset hook -- for example, hitting the
  * PSHOLD line on the PMIC to hard reset the system
diff --git a/arch/arm/mach-msm/include/mach/uncompress.h b/arch/arm/mach-msm/include/mach/uncompress.h
index 169a840..c14011f 100644
--- a/arch/arm/mach-msm/include/mach/uncompress.h
+++ b/arch/arm/mach-msm/include/mach/uncompress.h
@@ -16,6 +16,7 @@
 #ifndef __ASM_ARCH_MSM_UNCOMPRESS_H
 #define __ASM_ARCH_MSM_UNCOMPRESS_H
 
+#include <asm/barrier.h>
 #include <asm/processor.h>
 #include <mach/msm_iomap.h>
 
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 578b04e..a1e7b11 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -172,8 +172,8 @@
 }
 #endif /* CONFIG_ARCH_MSM7X30 */
 
-void __iomem *
-__msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
+void __iomem *__msm_ioremap_caller(unsigned long phys_addr, size_t size,
+				   unsigned int mtype, void *caller)
 {
 	if (mtype == MT_DEVICE) {
 		/* The peripherals in the 88000000 - D0000000 range
@@ -184,7 +184,5 @@
 			mtype = MT_DEVICE_NONSHARED;
 	}
 
-	return __arm_ioremap_caller(phys_addr, size, mtype,
-		__builtin_return_address(0));
+	return __arm_ioremap_caller(phys_addr, size, mtype, caller);
 }
-EXPORT_SYMBOL(__msm_ioremap);
diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c
index 0c56a5a..c56df9e 100644
--- a/arch/arm/mach-msm/smd_debug.c
+++ b/arch/arm/mach-msm/smd_debug.c
@@ -203,15 +203,9 @@
 	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
 }
 
-static int debug_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static const struct file_operations debug_ops = {
 	.read = debug_read,
-	.open = debug_open,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 11d0d8f..81280825 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -24,6 +24,7 @@
 #include <asm/mach/time.h>
 #include <asm/hardware/gic.h>
 #include <asm/localtimer.h>
+#include <asm/sched_clock.h>
 
 #include <mach/msm_iomap.h>
 #include <mach/cpu.h>
@@ -105,12 +106,12 @@
 
 static void __iomem *source_base;
 
-static cycle_t msm_read_timer_count(struct clocksource *cs)
+static notrace cycle_t msm_read_timer_count(struct clocksource *cs)
 {
 	return readl_relaxed(source_base + TIMER_COUNT_VAL);
 }
 
-static cycle_t msm_read_timer_count_shift(struct clocksource *cs)
+static notrace cycle_t msm_read_timer_count_shift(struct clocksource *cs)
 {
 	/*
 	 * Shift timer count down by a constant due to unreliable lower bits
@@ -127,6 +128,50 @@
 	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
+#ifdef CONFIG_LOCAL_TIMERS
+static int __cpuinit msm_local_timer_setup(struct clock_event_device *evt)
+{
+	/* Use existing clock_event for cpu 0 */
+	if (!smp_processor_id())
+		return 0;
+
+	writel_relaxed(0, event_base + TIMER_ENABLE);
+	writel_relaxed(0, event_base + TIMER_CLEAR);
+	writel_relaxed(~0, event_base + TIMER_MATCH_VAL);
+	evt->irq = msm_clockevent.irq;
+	evt->name = "local_timer";
+	evt->features = msm_clockevent.features;
+	evt->rating = msm_clockevent.rating;
+	evt->set_mode = msm_timer_set_mode;
+	evt->set_next_event = msm_timer_set_next_event;
+	evt->shift = msm_clockevent.shift;
+	evt->mult = div_sc(GPT_HZ, NSEC_PER_SEC, evt->shift);
+	evt->max_delta_ns = clockevent_delta2ns(0xf0000000, evt);
+	evt->min_delta_ns = clockevent_delta2ns(4, evt);
+
+	*__this_cpu_ptr(msm_evt.percpu_evt) = evt;
+	clockevents_register_device(evt);
+	enable_percpu_irq(evt->irq, 0);
+	return 0;
+}
+
+static void msm_local_timer_stop(struct clock_event_device *evt)
+{
+	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
+	disable_percpu_irq(evt->irq);
+}
+
+static struct local_timer_ops msm_local_timer_ops __cpuinitdata = {
+	.setup	= msm_local_timer_setup,
+	.stop	= msm_local_timer_stop,
+};
+#endif /* CONFIG_LOCAL_TIMERS */
+
+static notrace u32 msm_sched_clock_read(void)
+{
+	return msm_clocksource.read(&msm_clocksource);
+}
+
 static void __init msm_timer_init(void)
 {
 	struct clock_event_device *ce = &msm_clockevent;
@@ -173,8 +218,12 @@
 		*__this_cpu_ptr(msm_evt.percpu_evt) = ce;
 		res = request_percpu_irq(ce->irq, msm_timer_interrupt,
 					 ce->name, msm_evt.percpu_evt);
-		if (!res)
+		if (!res) {
 			enable_percpu_irq(ce->irq, 0);
+#ifdef CONFIG_LOCAL_TIMERS
+			local_timer_register(&msm_local_timer_ops);
+#endif
+		}
 	} else {
 		msm_evt.evt = ce;
 		res = request_irq(ce->irq, msm_timer_interrupt,
@@ -189,42 +238,10 @@
 	res = clocksource_register_hz(cs, dgt_hz);
 	if (res)
 		pr_err("clocksource_register failed\n");
+	setup_sched_clock(msm_sched_clock_read,
+			cpu_is_msm7x01() ? 32 - MSM_DGT_SHIFT : 32, dgt_hz);
 }
 
-#ifdef CONFIG_LOCAL_TIMERS
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	/* Use existing clock_event for cpu 0 */
-	if (!smp_processor_id())
-		return 0;
-
-	writel_relaxed(0, event_base + TIMER_ENABLE);
-	writel_relaxed(0, event_base + TIMER_CLEAR);
-	writel_relaxed(~0, event_base + TIMER_MATCH_VAL);
-	evt->irq = msm_clockevent.irq;
-	evt->name = "local_timer";
-	evt->features = msm_clockevent.features;
-	evt->rating = msm_clockevent.rating;
-	evt->set_mode = msm_timer_set_mode;
-	evt->set_next_event = msm_timer_set_next_event;
-	evt->shift = msm_clockevent.shift;
-	evt->mult = div_sc(GPT_HZ, NSEC_PER_SEC, evt->shift);
-	evt->max_delta_ns = clockevent_delta2ns(0xf0000000, evt);
-	evt->min_delta_ns = clockevent_delta2ns(4, evt);
-
-	*__this_cpu_ptr(msm_evt.percpu_evt) = evt;
-	clockevents_register_device(evt);
-	enable_percpu_irq(evt->irq, 0);
-	return 0;
-}
-
-void local_timer_stop(struct clock_event_device *evt)
-{
-	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
-	disable_percpu_irq(evt->irq);
-}
-#endif /* CONFIG_LOCAL_TIMERS */
-
 struct sys_timer msm_timer = {
 	.init = msm_timer_init
 };
diff --git a/arch/arm/mach-mv78xx0/include/mach/entry-macro.S b/arch/arm/mach-mv78xx0/include/mach/entry-macro.S
index 66ae2d2..6b1f088 100644
--- a/arch/arm/mach-mv78xx0/include/mach/entry-macro.S
+++ b/arch/arm/mach-mv78xx0/include/mach/entry-macro.S
@@ -10,12 +10,6 @@
 
 #include <mach/bridge-regs.h>
 
-	.macro  disable_fiq
-	.endm
-
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
-
 	.macro  get_irqnr_preamble, base, tmp
 	ldr	\base, =IRQ_VIRT_BASE
 	.endm
diff --git a/arch/arm/mach-mv78xx0/include/mach/io.h b/arch/arm/mach-mv78xx0/include/mach/io.h
index 450e0e1..c7d9d00 100644
--- a/arch/arm/mach-mv78xx0/include/mach/io.h
+++ b/arch/arm/mach-mv78xx0/include/mach/io.h
@@ -20,7 +20,5 @@
 }
 
 #define __io(a)			__io(a)
-#define __mem_pci(a)		(a)
-
 
 #endif
diff --git a/arch/arm/mach-mv78xx0/include/mach/system.h b/arch/arm/mach-mv78xx0/include/mach/system.h
deleted file mode 100644
index 8c3a538..0000000
--- a/arch/arm/mach-mv78xx0/include/mach/system.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/mach-mv78xx0/include/mach/system.h
- *
- * 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-mv78xx0/pcie.c b/arch/arm/mach-mv78xx0/pcie.c
index 8459f6d..df3e380 100644
--- a/arch/arm/mach-mv78xx0/pcie.c
+++ b/arch/arm/mach-mv78xx0/pcie.c
@@ -155,8 +155,8 @@
 	orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
 	orion_pcie_setup(pp->base);
 
-	pci_add_resource(&sys->resources, &pp->res[0]);
-	pci_add_resource(&sys->resources, &pp->res[1]);
+	pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
+	pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
 
 	return 1;
 }
diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index cf00b3e..c57f996 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -83,6 +83,18 @@
 	select MXS_HAVE_PLATFORM_MXSFB
 	select MXS_OCOTP
 
+config MODULE_APX4
+	bool
+	select SOC_IMX28
+	select LEDS_GPIO_REGISTER
+	select MXS_HAVE_AMBA_DUART
+	select MXS_HAVE_PLATFORM_AUART
+	select MXS_HAVE_PLATFORM_FEC
+	select MXS_HAVE_PLATFORM_MXS_I2C
+	select MXS_HAVE_PLATFORM_MXS_MMC
+	select MXS_HAVE_PLATFORM_MXS_SAIF
+	select MXS_OCOTP
+
 config MACH_TX28
 	bool "Ka-Ro TX28 module"
 	select MODULE_TX28
@@ -91,4 +103,8 @@
 	bool "Support DENX M28EVK Platform"
 	select MODULE_M28
 
+config MACH_APX4DEVKIT
+	bool "Support Bluegiga APX4 Development Kit"
+	select MODULE_APX4
+
 endif
diff --git a/arch/arm/mach-mxs/Makefile b/arch/arm/mach-mxs/Makefile
index 8c93b24..908bf9a 100644
--- a/arch/arm/mach-mxs/Makefile
+++ b/arch/arm/mach-mxs/Makefile
@@ -11,6 +11,7 @@
 obj-$(CONFIG_MACH_MX23EVK) += mach-mx23evk.o
 obj-$(CONFIG_MACH_MX28EVK) += mach-mx28evk.o
 obj-$(CONFIG_MACH_M28EVK)    += mach-m28evk.o
+obj-$(CONFIG_MACH_APX4DEVKIT) += mach-apx4devkit.o
 obj-$(CONFIG_MODULE_TX28) += module-tx28.o
 obj-$(CONFIG_MACH_TX28)    += mach-tx28.o
 
diff --git a/arch/arm/mach-mxs/clock-mx23.c b/arch/arm/mach-mxs/clock-mx23.c
index e12e112..e3ac52c 100644
--- a/arch/arm/mach-mxs/clock-mx23.c
+++ b/arch/arm/mach-mxs/clock-mx23.c
@@ -223,7 +223,6 @@
 {
 	u32 reg, bm_busy, div_max, d, f, div, frac;
 	unsigned long diff, parent_rate, calc_rate;
-	int i;
 
 	parent_rate = clk_get_rate(clk->parent);
 
@@ -275,14 +274,7 @@
 	reg |= div << BP_CLKCTRL_CPU_DIV_CPU;
 	__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU);
 
-	for (i = 10000; i; i--)
-		if (!(__raw_readl(CLKCTRL_BASE_ADDR +
-					HW_CLKCTRL_CPU) & bm_busy))
-			break;
-	if (!i)	{
-		pr_err("%s: divider writing timeout\n", __func__);
-		return -ETIMEDOUT;
-	}
+	mxs_clkctrl_timeout(HW_CLKCTRL_CPU, bm_busy);
 
 	return 0;
 }
@@ -292,7 +284,6 @@
 {									\
 	u32 reg, div_max, div;						\
 	unsigned long parent_rate;					\
-	int i;								\
 									\
 	parent_rate = clk_get_rate(clk->parent);			\
 	div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV;	\
@@ -310,15 +301,7 @@
 	}								\
 	__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr);		\
 									\
-	for (i = 10000; i; i--)						\
-		if (!(__raw_readl(CLKCTRL_BASE_ADDR +			\
-			HW_CLKCTRL_##dr) & BM_CLKCTRL_##dr##_BUSY))	\
-			break;						\
-	if (!i)	{							\
-		pr_err("%s: divider writing timeout\n", __func__);	\
-		return -ETIMEDOUT;					\
-	}								\
-									\
+	mxs_clkctrl_timeout(HW_CLKCTRL_##dr, BM_CLKCTRL_##dr##_BUSY);	\
 	return 0;							\
 }
 
@@ -456,12 +439,13 @@
 	_REGISTER_CLOCK("mxs-pwm.3", NULL, pwm_clk)
 	_REGISTER_CLOCK("mxs-pwm.4", NULL, pwm_clk)
 	_REGISTER_CLOCK("imx23-fb", NULL, lcdif_clk)
+	_REGISTER_CLOCK("imx23-gpmi-nand", NULL, gpmi_clk)
 };
 
 static int clk_misc_init(void)
 {
 	u32 reg;
-	int i;
+	int ret;
 
 	/* Fix up parent per register setting */
 	reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ);
@@ -510,14 +494,7 @@
 	reg |= 3 << BP_CLKCTRL_HBUS_DIV;
 	__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
 
-	for (i = 10000; i; i--)
-		if (!(__raw_readl(CLKCTRL_BASE_ADDR +
-			HW_CLKCTRL_HBUS) & BM_CLKCTRL_HBUS_BUSY))
-			break;
-	if (!i) {
-		pr_err("%s: divider writing timeout\n", __func__);
-		return -ETIMEDOUT;
-	}
+	ret = mxs_clkctrl_timeout(HW_CLKCTRL_HBUS, BM_CLKCTRL_HBUS_BUSY);
 
 	/* Gate off cpu clock in WFI for power saving */
 	__raw_writel(BM_CLKCTRL_CPU_INTERRUPT_WAIT,
@@ -532,7 +509,7 @@
 	reg |= 30 << BP_CLKCTRL_FRAC_IOFRAC;
 	__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC);
 
-	return 0;
+	return ret;
 }
 
 int __init mx23_clocks_init(void)
diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c
index 5d68e41..cea29c9 100644
--- a/arch/arm/mach-mxs/clock-mx28.c
+++ b/arch/arm/mach-mxs/clock-mx28.c
@@ -322,7 +322,6 @@
 {									\
 	u32 reg, bm_busy, div_max, d, f, div, frac;			\
 	unsigned long diff, parent_rate, calc_rate;			\
-	int i;								\
 									\
 	div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV;	\
 	bm_busy = BM_CLKCTRL_##dr##_BUSY;				\
@@ -396,16 +395,7 @@
 	}								\
 	__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr);		\
 									\
-	for (i = 10000; i; i--)						\
-		if (!(__raw_readl(CLKCTRL_BASE_ADDR +			\
-			HW_CLKCTRL_##dr) & bm_busy))			\
-			break;						\
-	if (!i)	{							\
-		pr_err("%s: divider writing timeout\n", __func__);	\
-		return -ETIMEDOUT;					\
-	}								\
-									\
-	return 0;							\
+	return mxs_clkctrl_timeout(HW_CLKCTRL_##dr, bm_busy);		\
 }
 
 _CLK_SET_RATE(cpu_clk, CPU, FRAC0, CPU)
@@ -421,7 +411,6 @@
 {									\
 	u32 reg, div_max, div;						\
 	unsigned long parent_rate;					\
-	int i;								\
 									\
 	parent_rate = clk_get_rate(clk->parent);			\
 	div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV;	\
@@ -439,16 +428,7 @@
 	}								\
 	__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr);		\
 									\
-	for (i = 10000; i; i--)						\
-		if (!(__raw_readl(CLKCTRL_BASE_ADDR +			\
-			HW_CLKCTRL_##dr) & BM_CLKCTRL_##dr##_BUSY))	\
-			break;						\
-	if (!i)	{							\
-		pr_err("%s: divider writing timeout\n", __func__);	\
-		return -ETIMEDOUT;					\
-	}								\
-									\
-	return 0;							\
+	return mxs_clkctrl_timeout(HW_CLKCTRL_##dr, BM_CLKCTRL_##dr##_BUSY);\
 }
 
 _CLK_SET_RATE1(xbus_clk, XBUS)
@@ -461,7 +441,6 @@
 	u32 reg;							\
 	u64 lrate;							\
 	unsigned long parent_rate;					\
-	int i;								\
 									\
 	parent_rate = clk_get_rate(clk->parent);			\
 	if (rate > parent_rate)						\
@@ -477,18 +456,13 @@
 	reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs);		\
 	reg &= ~BM_CLKCTRL_##rs##_DIV;					\
 	reg |= div << BP_CLKCTRL_##rs##_DIV;				\
+	if (reg & (1 << clk->enable_shift)) {				\
+		pr_err("%s: clock is gated\n", __func__);		\
+		return -EINVAL;						\
+	}								\
 	__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs);		\
 									\
-	for (i = 10000; i; i--)						\
-		if (!(__raw_readl(CLKCTRL_BASE_ADDR +			\
-			HW_CLKCTRL_##rs) & BM_CLKCTRL_##rs##_BUSY))	\
-			break;						\
-	if (!i) {							\
-		pr_err("%s: divider writing timeout\n", __func__);	\
-		return -ETIMEDOUT;					\
-	}								\
-									\
-	return 0;							\
+	return mxs_clkctrl_timeout(HW_CLKCTRL_##rs, BM_CLKCTRL_##rs##_BUSY);\
 }
 
 _CLK_SET_RATE_SAIF(saif0_clk, SAIF0)
@@ -643,6 +617,7 @@
 	_REGISTER_CLOCK("duart", NULL, uart_clk)
 	_REGISTER_CLOCK("imx28-fec.0", NULL, fec_clk)
 	_REGISTER_CLOCK("imx28-fec.1", NULL, fec_clk)
+	_REGISTER_CLOCK("imx28-gpmi-nand", NULL, gpmi_clk)
 	_REGISTER_CLOCK("mxs-auart.0", NULL, uart_clk)
 	_REGISTER_CLOCK("mxs-auart.1", NULL, uart_clk)
 	_REGISTER_CLOCK("mxs-auart.2", NULL, uart_clk)
@@ -654,6 +629,8 @@
 	_REGISTER_CLOCK("mxs-dma-apbx", NULL, xbus_clk)
 	_REGISTER_CLOCK("mxs-mmc.0", NULL, ssp0_clk)
 	_REGISTER_CLOCK("mxs-mmc.1", NULL, ssp1_clk)
+	_REGISTER_CLOCK("mxs-mmc.2", NULL, ssp2_clk)
+	_REGISTER_CLOCK("mxs-mmc.3", NULL, ssp3_clk)
 	_REGISTER_CLOCK("flexcan.0", NULL, can0_clk)
 	_REGISTER_CLOCK("flexcan.1", NULL, can1_clk)
 	_REGISTER_CLOCK(NULL, "usb0", usb0_clk)
@@ -676,7 +653,7 @@
 static int clk_misc_init(void)
 {
 	u32 reg;
-	int i;
+	int ret;
 
 	/* Fix up parent per register setting */
 	reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ);
@@ -756,14 +733,7 @@
 	reg |= 3 << BP_CLKCTRL_HBUS_DIV;
 	__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
 
-	for (i = 10000; i; i--)
-		if (!(__raw_readl(CLKCTRL_BASE_ADDR +
-			HW_CLKCTRL_HBUS) & BM_CLKCTRL_HBUS_ASM_BUSY))
-			break;
-	if (!i) {
-		pr_err("%s: divider writing timeout\n", __func__);
-		return -ETIMEDOUT;
-	}
+	ret = mxs_clkctrl_timeout(HW_CLKCTRL_HBUS, BM_CLKCTRL_HBUS_ASM_BUSY);
 
 	/* Gate off cpu clock in WFI for power saving */
 	__raw_writel(BM_CLKCTRL_CPU_INTERRUPT_WAIT,
@@ -790,7 +760,7 @@
 	reg |= 30 << BP_CLKCTRL_FRAC0_IO0FRAC;
 	__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC0);
 
-	return 0;
+	return ret;
 }
 
 int __init mx28_clocks_init(void)
@@ -803,6 +773,8 @@
 	 */
 	clk_set_parent(&ssp0_clk, &ref_io0_clk);
 	clk_set_parent(&ssp1_clk, &ref_io0_clk);
+	clk_set_parent(&ssp2_clk, &ref_io1_clk);
+	clk_set_parent(&ssp3_clk, &ref_io1_clk);
 
 	clk_prepare_enable(&cpu_clk);
 	clk_prepare_enable(&hbus_clk);
diff --git a/arch/arm/mach-mxs/devices-mx23.h b/arch/arm/mach-mxs/devices-mx23.h
index 3fa651d..4d1329d 100644
--- a/arch/arm/mach-mxs/devices-mx23.h
+++ b/arch/arm/mach-mxs/devices-mx23.h
@@ -21,6 +21,10 @@
 #define mx23_add_auart0()		mx23_add_auart(0)
 #define mx23_add_auart1()		mx23_add_auart(1)
 
+extern const struct mxs_gpmi_nand_data mx23_gpmi_nand_data __initconst;
+#define mx23_add_gpmi_nand(pdata)	\
+	mxs_add_gpmi_nand(pdata, &mx23_gpmi_nand_data)
+
 extern const struct mxs_mxs_mmc_data mx23_mxs_mmc_data[] __initconst;
 #define mx23_add_mxs_mmc(id, pdata) \
 	mxs_add_mxs_mmc(&mx23_mxs_mmc_data[id], pdata)
diff --git a/arch/arm/mach-mxs/devices-mx28.h b/arch/arm/mach-mxs/devices-mx28.h
index 4f50094..9dbeae1 100644
--- a/arch/arm/mach-mxs/devices-mx28.h
+++ b/arch/arm/mach-mxs/devices-mx28.h
@@ -34,6 +34,10 @@
 #define mx28_add_flexcan0(pdata)	mx28_add_flexcan(0, pdata)
 #define mx28_add_flexcan1(pdata)	mx28_add_flexcan(1, pdata)
 
+extern const struct mxs_gpmi_nand_data mx28_gpmi_nand_data __initconst;
+#define mx28_add_gpmi_nand(pdata)	\
+	mxs_add_gpmi_nand(pdata, &mx28_gpmi_nand_data)
+
 extern const struct mxs_mxs_i2c_data mx28_mxs_i2c_data[] __initconst;
 #define mx28_add_mxs_i2c(id)		mxs_add_mxs_i2c(&mx28_mxs_i2c_data[id])
 
diff --git a/arch/arm/mach-mxs/devices.c b/arch/arm/mach-mxs/devices.c
index fe3e847..01faffe 100644
--- a/arch/arm/mach-mxs/devices.c
+++ b/arch/arm/mach-mxs/devices.c
@@ -77,16 +77,18 @@
 
 int __init mxs_add_amba_device(const struct amba_device *dev)
 {
-	struct amba_device *adev = kmalloc(sizeof(*adev), GFP_KERNEL);
+	struct amba_device *adev = amba_device_alloc(dev->dev.init_name,
+		dev->res.start, resource_size(&dev->res));
 
 	if (!adev) {
 		pr_err("%s: failed to allocate memory", __func__);
 		return -ENOMEM;
 	}
 
-	*adev = *dev;
+	adev->irq[0] = dev->irq[0];
+	adev->irq[1] = dev->irq[1];
 
-	return amba_device_register(adev, &iomem_resource);
+	return amba_device_add(adev, &iomem_resource);
 }
 
 struct device mxs_apbh_bus = {
diff --git a/arch/arm/mach-mxs/devices/Kconfig b/arch/arm/mach-mxs/devices/Kconfig
index 18b6bf5..b8913df 100644
--- a/arch/arm/mach-mxs/devices/Kconfig
+++ b/arch/arm/mach-mxs/devices/Kconfig
@@ -12,6 +12,9 @@
 	select HAVE_CAN_FLEXCAN if CAN
 	bool
 
+config MXS_HAVE_PLATFORM_GPMI_NAND
+	bool
+
 config MXS_HAVE_PLATFORM_MXS_I2C
 	bool
 
diff --git a/arch/arm/mach-mxs/devices/Makefile b/arch/arm/mach-mxs/devices/Makefile
index f52e3e5..c8f5c95 100644
--- a/arch/arm/mach-mxs/devices/Makefile
+++ b/arch/arm/mach-mxs/devices/Makefile
@@ -3,6 +3,7 @@
 obj-y += platform-dma.o
 obj-$(CONFIG_MXS_HAVE_PLATFORM_FEC) += platform-fec.o
 obj-$(CONFIG_MXS_HAVE_PLATFORM_FLEXCAN) += platform-flexcan.o
+obj-$(CONFIG_MXS_HAVE_PLATFORM_GPMI_NAND) += platform-gpmi-nand.o
 obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_I2C) += platform-mxs-i2c.o
 obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_MMC) += platform-mxs-mmc.o
 obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_PWM) += platform-mxs-pwm.o
diff --git a/arch/arm/mach-mxs/devices/amba-duart.c b/arch/arm/mach-mxs/devices/amba-duart.c
index a559db0..a5479f7 100644
--- a/arch/arm/mach-mxs/devices/amba-duart.c
+++ b/arch/arm/mach-mxs/devices/amba-duart.c
@@ -23,7 +23,7 @@
 		.end = (soc ## _DUART_BASE_ADDR) + SZ_8K - 1,	\
 		.flags = IORESOURCE_MEM,			\
 	},							\
-	.irq = {soc ## _INT_DUART, NO_IRQ},			\
+	.irq = {soc ## _INT_DUART},				\
 }
 
 #ifdef CONFIG_SOC_IMX23
diff --git a/arch/arm/mach-mxs/devices/platform-gpmi-nand.c b/arch/arm/mach-mxs/devices/platform-gpmi-nand.c
new file mode 100644
index 0000000..3e22df5
--- /dev/null
+++ b/arch/arm/mach-mxs/devices/platform-gpmi-nand.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+#include <asm/sizes.h>
+#include <mach/mx23.h>
+#include <mach/mx28.h>
+#include <mach/devices-common.h>
+#include <linux/dma-mapping.h>
+
+#ifdef CONFIG_SOC_IMX23
+const struct mxs_gpmi_nand_data mx23_gpmi_nand_data __initconst = {
+	.devid = "imx23-gpmi-nand",
+	.res = {
+		/* GPMI */
+		DEFINE_RES_MEM_NAMED(MX23_GPMI_BASE_ADDR, SZ_8K,
+					GPMI_NAND_GPMI_REGS_ADDR_RES_NAME),
+		DEFINE_RES_IRQ_NAMED(MX23_INT_GPMI_ATTENTION,
+					GPMI_NAND_GPMI_INTERRUPT_RES_NAME),
+		/* BCH */
+		DEFINE_RES_MEM_NAMED(MX23_BCH_BASE_ADDR, SZ_8K,
+					GPMI_NAND_BCH_REGS_ADDR_RES_NAME),
+		DEFINE_RES_IRQ_NAMED(MX23_INT_BCH,
+					GPMI_NAND_BCH_INTERRUPT_RES_NAME),
+		/* DMA */
+		DEFINE_RES_NAMED(MX23_DMA_GPMI0,
+					MX23_DMA_GPMI3 - MX23_DMA_GPMI0 + 1,
+					GPMI_NAND_DMA_CHANNELS_RES_NAME,
+					IORESOURCE_DMA),
+		DEFINE_RES_IRQ_NAMED(MX23_INT_GPMI_DMA,
+					GPMI_NAND_DMA_INTERRUPT_RES_NAME),
+	},
+};
+#endif
+
+#ifdef CONFIG_SOC_IMX28
+const struct mxs_gpmi_nand_data mx28_gpmi_nand_data __initconst = {
+	.devid = "imx28-gpmi-nand",
+	.res = {
+		/* GPMI */
+		DEFINE_RES_MEM_NAMED(MX28_GPMI_BASE_ADDR, SZ_8K,
+					GPMI_NAND_GPMI_REGS_ADDR_RES_NAME),
+		DEFINE_RES_IRQ_NAMED(MX28_INT_GPMI,
+					GPMI_NAND_GPMI_INTERRUPT_RES_NAME),
+		/* BCH */
+		DEFINE_RES_MEM_NAMED(MX28_BCH_BASE_ADDR, SZ_8K,
+					GPMI_NAND_BCH_REGS_ADDR_RES_NAME),
+		DEFINE_RES_IRQ_NAMED(MX28_INT_BCH,
+					GPMI_NAND_BCH_INTERRUPT_RES_NAME),
+		/* DMA */
+		DEFINE_RES_NAMED(MX28_DMA_GPMI0,
+					MX28_DMA_GPMI7 - MX28_DMA_GPMI0 + 1,
+					GPMI_NAND_DMA_CHANNELS_RES_NAME,
+					IORESOURCE_DMA),
+		DEFINE_RES_IRQ_NAMED(MX28_INT_GPMI_DMA,
+					GPMI_NAND_DMA_INTERRUPT_RES_NAME),
+	},
+};
+#endif
+
+struct platform_device *__init
+mxs_add_gpmi_nand(const struct gpmi_nand_platform_data *pdata,
+		const struct mxs_gpmi_nand_data *data)
+{
+	return mxs_add_platform_device_dmamask(data->devid, -1,
+				data->res, GPMI_NAND_RES_SIZE,
+				pdata, sizeof(*pdata), DMA_BIT_MASK(32));
+}
diff --git a/arch/arm/mach-mxs/devices/platform-mxs-mmc.c b/arch/arm/mach-mxs/devices/platform-mxs-mmc.c
index 382dacb..bef9d92 100644
--- a/arch/arm/mach-mxs/devices/platform-mxs-mmc.c
+++ b/arch/arm/mach-mxs/devices/platform-mxs-mmc.c
@@ -41,6 +41,8 @@
 const struct mxs_mxs_mmc_data mx28_mxs_mmc_data[] __initconst = {
 	mxs_mxs_mmc_data_entry(MX28, 0, 0),
 	mxs_mxs_mmc_data_entry(MX28, 1, 1),
+	mxs_mxs_mmc_data_entry(MX28, 2, 2),
+	mxs_mxs_mmc_data_entry(MX28, 3, 3),
 };
 #endif
 
diff --git a/arch/arm/mach-mxs/include/mach/common.h b/arch/arm/mach-mxs/include/mach/common.h
index e1237ab..c50c3ea 100644
--- a/arch/arm/mach-mxs/include/mach/common.h
+++ b/arch/arm/mach-mxs/include/mach/common.h
@@ -31,4 +31,6 @@
 
 extern void icoll_init_irq(void);
 
+extern int mxs_clkctrl_timeout(unsigned int reg_offset, unsigned int mask);
+
 #endif /* __MACH_MXS_COMMON_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/devices-common.h b/arch/arm/mach-mxs/include/mach/devices-common.h
index dc369c1..f2e3839 100644
--- a/arch/arm/mach-mxs/include/mach/devices-common.h
+++ b/arch/arm/mach-mxs/include/mach/devices-common.h
@@ -66,6 +66,16 @@
 		const struct mxs_flexcan_data *data,
 		const struct flexcan_platform_data *pdata);
 
+/* gpmi-nand */
+#include <linux/mtd/gpmi-nand.h>
+struct mxs_gpmi_nand_data {
+	const char *devid;
+	const struct resource res[GPMI_NAND_RES_SIZE];
+};
+struct platform_device *__init
+mxs_add_gpmi_nand(const struct gpmi_nand_platform_data *pdata,
+		const struct mxs_gpmi_nand_data *data);
+
 /* i2c */
 struct mxs_mxs_i2c_data {
 	int id;
diff --git a/arch/arm/mach-mxs/include/mach/digctl.h b/arch/arm/mach-mxs/include/mach/digctl.h
index 49a888c..1796406 100644
--- a/arch/arm/mach-mxs/include/mach/digctl.h
+++ b/arch/arm/mach-mxs/include/mach/digctl.h
@@ -18,4 +18,5 @@
 #define HW_DIGCTL_CTRL			0x0
 #define  BP_DIGCTL_CTRL_SAIF_CLKMUX	10
 #define  BM_DIGCTL_CTRL_SAIF_CLKMUX	(0x3 << 10)
+#define HW_DIGCTL_CHIPID		0x310
 #endif
diff --git a/arch/arm/mach-mxs/include/mach/entry-macro.S b/arch/arm/mach-mxs/include/mach/entry-macro.S
index 9f0da12..0c14259 100644
--- a/arch/arm/mach-mxs/include/mach/entry-macro.S
+++ b/arch/arm/mach-mxs/include/mach/entry-macro.S
@@ -23,9 +23,6 @@
 #define MXS_ICOLL_VBASE		MXS_IO_ADDRESS(MXS_ICOLL_BASE_ADDR)
 #define HW_ICOLL_STAT_OFFSET	0x70
 
-	.macro	disable_fiq
-	.endm
-
 	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 	ldr	\irqnr, [\base, #HW_ICOLL_STAT_OFFSET]
 	cmp	\irqnr, #0x7F
@@ -36,6 +33,3 @@
 	.macro  get_irqnr_preamble, base, tmp
 	ldr	\base, =MXS_ICOLL_VBASE
 	.endm
-
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
diff --git a/arch/arm/mach-mxs/include/mach/hardware.h b/arch/arm/mach-mxs/include/mach/hardware.h
index 53e89a0..4c0e8a6 100644
--- a/arch/arm/mach-mxs/include/mach/hardware.h
+++ b/arch/arm/mach-mxs/include/mach/hardware.h
@@ -20,10 +20,4 @@
 #ifndef __MACH_MXS_HARDWARE_H__
 #define __MACH_MXS_HARDWARE_H__
 
-#ifdef __ASSEMBLER__
-#define IOMEM(addr)	(addr)
-#else
-#define IOMEM(addr)	((void __force __iomem *)(addr))
-#endif
-
 #endif /* __MACH_MXS_HARDWARE_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/io.h b/arch/arm/mach-mxs/include/mach/io.h
deleted file mode 100644
index 289b722..0000000
--- a/arch/arm/mach-mxs/include/mach/io.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- *  Copyright 2004-2007 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 version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __MACH_MXS_IO_H__
-#define __MACH_MXS_IO_H__
-
-/* Allow IO space to be anywhere in the memory */
-#define IO_SPACE_LIMIT 0xffffffff
-
-/* io address mapping macro */
-#define __io(a)		__typesafe_io(a)
-
-#define __mem_pci(a)	(a)
-
-#endif /* __MACH_MXS_IO_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/mxs.h b/arch/arm/mach-mxs/include/mach/mxs.h
index bde5f66..7d4fb6d 100644
--- a/arch/arm/mach-mxs/include/mach/mxs.h
+++ b/arch/arm/mach-mxs/include/mach/mxs.h
@@ -23,22 +23,10 @@
 #include <linux/io.h>
 #endif
 #include <asm/mach-types.h>
+#include <mach/digctl.h>
 #include <mach/hardware.h>
 
 /*
- * MXS CPU types
- */
-#define cpu_is_mx23()		(					\
-		machine_is_mx23evk() ||					\
-		machine_is_stmp378x() ||				\
-		0)
-#define cpu_is_mx28()		(					\
-		machine_is_mx28evk() ||					\
-		machine_is_m28evk() ||					\
-		machine_is_tx28() ||					\
-		0)
-
-/*
  * IO addresses common to MXS-based
  */
 #define MXS_IO_BASE_ADDR		0x80000000
@@ -109,6 +97,21 @@
 {
 	__raw_writel(mask, reg + MXS_TOG_ADDR);
 }
+
+/*
+ * MXS CPU types
+ */
+#define MXS_CHIPID (MXS_IO_ADDRESS(MXS_DIGCTL_BASE_ADDR) + HW_DIGCTL_CHIPID)
+
+static inline int cpu_is_mx23(void)
+{
+	return ((__raw_readl(MXS_CHIPID) >> 16) == 0x3780);
+}
+
+static inline int cpu_is_mx28(void)
+{
+	return ((__raw_readl(MXS_CHIPID) >> 16) == 0x2800);
+}
 #endif
 
 #endif /* __MACH_MXS_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/system.h b/arch/arm/mach-mxs/include/mach/system.h
deleted file mode 100644
index e7ad1bb..0000000
--- a/arch/arm/mach-mxs/include/mach/system.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *  Copyright 2004-2008 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.
- */
-
-#ifndef __MACH_MXS_SYSTEM_H__
-#define __MACH_MXS_SYSTEM_H__
-
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
-#endif /* __MACH_MXS_SYSTEM_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/uncompress.h b/arch/arm/mach-mxs/include/mach/uncompress.h
index 6777674..ef28114 100644
--- a/arch/arm/mach-mxs/include/mach/uncompress.h
+++ b/arch/arm/mach-mxs/include/mach/uncompress.h
@@ -18,8 +18,6 @@
 #ifndef __MACH_MXS_UNCOMPRESS_H__
 #define __MACH_MXS_UNCOMPRESS_H__
 
-#include <asm/mach-types.h>
-
 unsigned long mxs_duart_base;
 
 #define MXS_DUART(x)	(*(volatile unsigned long *)(mxs_duart_base + (x)))
@@ -55,16 +53,17 @@
 
 #define MX23_DUART_BASE_ADDR	0x80070000
 #define MX28_DUART_BASE_ADDR	0x80074000
+#define MXS_DIGCTL_CHIPID	0x8001c310
 
 static inline void __arch_decomp_setup(unsigned long arch_id)
 {
-	switch (arch_id) {
-	case MACH_TYPE_MX23EVK:
+	u16 chipid = (*(volatile unsigned long *) MXS_DIGCTL_CHIPID) >> 16;
+
+	switch (chipid) {
+	case 0x3780:
 		mxs_duart_base = MX23_DUART_BASE_ADDR;
 		break;
-	case MACH_TYPE_MX28EVK:
-	case MACH_TYPE_M28EVK:
-	case MACH_TYPE_TX28:
+	case 0x2800:
 		mxs_duart_base = MX28_DUART_BASE_ADDR;
 		break;
 	default:
diff --git a/arch/arm/mach-mxs/mach-apx4devkit.c b/arch/arm/mach-mxs/mach-apx4devkit.c
new file mode 100644
index 0000000..48a7fab
--- /dev/null
+++ b/arch/arm/mach-mxs/mach-apx4devkit.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2011-2012
+ * Lauri Hintsala, Bluegiga, <lauri.hintsala@bluegiga.com>
+ * Veli-Pekka Peltola, Bluegiga, <veli-pekka.peltola@bluegiga.com>
+ *
+ * based on: mach-mx28evk.c
+ * Copyright 2010 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/micrel_phy.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include <mach/common.h>
+#include <mach/digctl.h>
+#include <mach/iomux-mx28.h>
+
+#include "devices-mx28.h"
+
+#define APX4DEVKIT_GPIO_USERLED	MXS_GPIO_NR(3, 28)
+
+static const iomux_cfg_t apx4devkit_pads[] __initconst = {
+	/* duart */
+	MX28_PAD_PWM0__DUART_RX | MXS_PAD_CTRL,
+	MX28_PAD_PWM1__DUART_TX | MXS_PAD_CTRL,
+
+	/* auart0 */
+	MX28_PAD_AUART0_RX__AUART0_RX | MXS_PAD_CTRL,
+	MX28_PAD_AUART0_TX__AUART0_TX | MXS_PAD_CTRL,
+	MX28_PAD_AUART0_CTS__AUART0_CTS | MXS_PAD_CTRL,
+	MX28_PAD_AUART0_RTS__AUART0_RTS | MXS_PAD_CTRL,
+
+	/* auart1 */
+	MX28_PAD_AUART1_RX__AUART1_RX | MXS_PAD_CTRL,
+	MX28_PAD_AUART1_TX__AUART1_TX | MXS_PAD_CTRL,
+
+	/* auart2 */
+	MX28_PAD_SSP2_SCK__AUART2_RX | MXS_PAD_CTRL,
+	MX28_PAD_SSP2_MOSI__AUART2_TX | MXS_PAD_CTRL,
+
+	/* auart3 */
+	MX28_PAD_SSP2_MISO__AUART3_RX | MXS_PAD_CTRL,
+	MX28_PAD_SSP2_SS0__AUART3_TX | MXS_PAD_CTRL,
+
+#define MXS_PAD_FEC	(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP)
+	/* fec0 */
+	MX28_PAD_ENET0_MDC__ENET0_MDC | MXS_PAD_FEC,
+	MX28_PAD_ENET0_MDIO__ENET0_MDIO | MXS_PAD_FEC,
+	MX28_PAD_ENET0_RX_EN__ENET0_RX_EN | MXS_PAD_FEC,
+	MX28_PAD_ENET0_RXD0__ENET0_RXD0 | MXS_PAD_FEC,
+	MX28_PAD_ENET0_RXD1__ENET0_RXD1 | MXS_PAD_FEC,
+	MX28_PAD_ENET0_TX_EN__ENET0_TX_EN | MXS_PAD_FEC,
+	MX28_PAD_ENET0_TXD0__ENET0_TXD0 | MXS_PAD_FEC,
+	MX28_PAD_ENET0_TXD1__ENET0_TXD1 | MXS_PAD_FEC,
+	MX28_PAD_ENET_CLK__CLKCTRL_ENET | MXS_PAD_FEC,
+
+	/* i2c */
+	MX28_PAD_I2C0_SCL__I2C0_SCL,
+	MX28_PAD_I2C0_SDA__I2C0_SDA,
+
+	/* mmc0 */
+	MX28_PAD_SSP0_DATA0__SSP0_D0 |
+		(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SSP0_DATA1__SSP0_D1 |
+		(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SSP0_DATA2__SSP0_D2 |
+		(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SSP0_DATA3__SSP0_D3 |
+		(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SSP0_DATA4__SSP0_D4 |
+		(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SSP0_DATA5__SSP0_D5 |
+		(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SSP0_DATA6__SSP0_D6 |
+		(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SSP0_DATA7__SSP0_D7 |
+		(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SSP0_CMD__SSP0_CMD |
+		(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT |
+		(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_NOPULL),
+	MX28_PAD_SSP0_SCK__SSP0_SCK |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_NOPULL),
+
+	/* led */
+	MX28_PAD_PWM3__GPIO_3_28 | MXS_PAD_CTRL,
+
+	/* saif0 & saif1 */
+	MX28_PAD_SAIF0_MCLK__SAIF0_MCLK |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SAIF0_LRCLK__SAIF0_LRCLK |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SAIF0_BITCLK__SAIF0_BITCLK |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SAIF0_SDATA0__SAIF0_SDATA0 |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SAIF1_SDATA0__SAIF1_SDATA0 |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+};
+
+/* led */
+static const struct gpio_led apx4devkit_leds[] __initconst = {
+	{
+		.name = "user-led",
+		.default_trigger = "heartbeat",
+		.gpio = APX4DEVKIT_GPIO_USERLED,
+	},
+};
+
+static const struct gpio_led_platform_data apx4devkit_led_data __initconst = {
+	.leds = apx4devkit_leds,
+	.num_leds = ARRAY_SIZE(apx4devkit_leds),
+};
+
+static const struct fec_platform_data mx28_fec_pdata __initconst = {
+	.phy = PHY_INTERFACE_MODE_RMII,
+};
+
+static const struct mxs_mmc_platform_data apx4devkit_mmc_pdata __initconst = {
+	.wp_gpio = -EINVAL,
+	.flags = SLOTF_4_BIT_CAPABLE,
+};
+
+static const struct i2c_board_info apx4devkit_i2c_boardinfo[] __initconst = {
+	{ I2C_BOARD_INFO("sgtl5000", 0x0a) }, /* ASoC */
+	{ I2C_BOARD_INFO("pcf8563", 0x51) }, /* RTC */
+};
+
+#if defined(CONFIG_REGULATOR_FIXED_VOLTAGE) || \
+		defined(CONFIG_REGULATOR_FIXED_VOLTAGE_MODULE)
+static struct regulator_consumer_supply apx4devkit_audio_consumer_supplies[] = {
+	REGULATOR_SUPPLY("VDDA", "0-000a"),
+	REGULATOR_SUPPLY("VDDIO", "0-000a"),
+};
+
+static struct regulator_init_data apx4devkit_vdd_reg_init_data = {
+	.constraints	= {
+		.name	= "3V3",
+		.always_on = 1,
+	},
+	.consumer_supplies = apx4devkit_audio_consumer_supplies,
+	.num_consumer_supplies = ARRAY_SIZE(apx4devkit_audio_consumer_supplies),
+};
+
+static struct fixed_voltage_config apx4devkit_vdd_pdata = {
+	.supply_name	= "board-3V3",
+	.microvolts	= 3300000,
+	.gpio		= -EINVAL,
+	.enabled_at_boot = 1,
+	.init_data	= &apx4devkit_vdd_reg_init_data,
+};
+
+static struct platform_device apx4devkit_voltage_regulator = {
+	.name		= "reg-fixed-voltage",
+	.id		= -1,
+	.num_resources	= 0,
+	.dev		= {
+		.platform_data	= &apx4devkit_vdd_pdata,
+	},
+};
+
+static void __init apx4devkit_add_regulators(void)
+{
+	platform_device_register(&apx4devkit_voltage_regulator);
+}
+#else
+static void __init apx4devkit_add_regulators(void) {}
+#endif
+
+static const struct mxs_saif_platform_data
+			apx4devkit_mxs_saif_pdata[] __initconst = {
+	/* working on EXTMSTR0 mode (saif0 master, saif1 slave) */
+	{
+		.master_mode = 1,
+		.master_id = 0,
+	}, {
+		.master_mode = 0,
+		.master_id = 0,
+	},
+};
+
+static int apx4devkit_phy_fixup(struct phy_device *phy)
+{
+	phy->dev_flags |= MICREL_PHY_50MHZ_CLK;
+	return 0;
+}
+
+static void __init apx4devkit_init(void)
+{
+	mxs_iomux_setup_multiple_pads(apx4devkit_pads,
+			ARRAY_SIZE(apx4devkit_pads));
+
+	mx28_add_duart();
+	mx28_add_auart0();
+	mx28_add_auart1();
+	mx28_add_auart2();
+	mx28_add_auart3();
+
+	/*
+	 * Register fixup for the Micrel KS8031 PHY clock
+	 * (shares same ID with KS8051)
+	 */
+	phy_register_fixup_for_uid(PHY_ID_KS8051, MICREL_PHY_ID_MASK,
+			apx4devkit_phy_fixup);
+
+	mx28_add_fec(0, &mx28_fec_pdata);
+
+	mx28_add_mxs_mmc(0, &apx4devkit_mmc_pdata);
+
+	gpio_led_register_device(0, &apx4devkit_led_data);
+
+	mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0);
+	mx28_add_saif(0, &apx4devkit_mxs_saif_pdata[0]);
+	mx28_add_saif(1, &apx4devkit_mxs_saif_pdata[1]);
+
+	apx4devkit_add_regulators();
+
+	mx28_add_mxs_i2c(0);
+	i2c_register_board_info(0, apx4devkit_i2c_boardinfo,
+			ARRAY_SIZE(apx4devkit_i2c_boardinfo));
+
+	mxs_add_platform_device("mxs-sgtl5000", 0, NULL, 0, NULL, 0);
+}
+
+static void __init apx4devkit_timer_init(void)
+{
+	mx28_clocks_init();
+}
+
+static struct sys_timer apx4devkit_timer = {
+	.init	= apx4devkit_timer_init,
+};
+
+MACHINE_START(APX4DEVKIT, "Bluegiga APX4 Development Kit")
+	.map_io		= mx28_map_io,
+	.init_irq	= mx28_init_irq,
+	.timer		= &apx4devkit_timer,
+	.init_machine	= apx4devkit_init,
+	.restart	= mxs_restart,
+MACHINE_END
diff --git a/arch/arm/mach-mxs/mach-m28evk.c b/arch/arm/mach-mxs/mach-m28evk.c
index 2f27582..06d7996 100644
--- a/arch/arm/mach-mxs/mach-m28evk.c
+++ b/arch/arm/mach-mxs/mach-m28evk.c
@@ -247,18 +247,15 @@
 	u32 val;
 	const u32 *ocotp = mxs_get_ocotp();
 
-	if (!ocotp) {
-		pr_err("%s: timeout when reading fec mac from OCOTP\n",
-			__func__);
+	if (!ocotp)
 		return -ETIMEDOUT;
-	}
 
 	/*
 	 * OCOTP only stores the last 4 octets for each mac address,
 	 * so hard-code DENX OUI (C0:E5:4E) here.
 	 */
 	for (i = 0; i < 2; i++) {
-		val = ocotp[i * 4];
+		val = ocotp[i];
 		mx28_fec_pdata[i].mac[0] = 0xC0;
 		mx28_fec_pdata[i].mac[1] = 0xE5;
 		mx28_fec_pdata[i].mac[2] = 0x4E;
diff --git a/arch/arm/mach-mxs/mach-mx28evk.c b/arch/arm/mach-mxs/mach-mx28evk.c
index fdb0a56..e386c14 100644
--- a/arch/arm/mach-mxs/mach-mx28evk.c
+++ b/arch/arm/mach-mxs/mach-mx28evk.c
@@ -223,7 +223,6 @@
 /* fec */
 static void __init mx28evk_fec_reset(void)
 {
-	int ret;
 	struct clk *clk;
 
 	/* Enable fec phy clock */
@@ -231,32 +230,7 @@
 	if (!IS_ERR(clk))
 		clk_prepare_enable(clk);
 
-	/* Power up fec phy */
-	ret = gpio_request(MX28EVK_FEC_PHY_POWER, "fec-phy-power");
-	if (ret) {
-		pr_err("Failed to request gpio fec-phy-%s: %d\n", "power", ret);
-		return;
-	}
-
-	ret = gpio_direction_output(MX28EVK_FEC_PHY_POWER, 0);
-	if (ret) {
-		pr_err("Failed to drive gpio fec-phy-%s: %d\n", "power", ret);
-		return;
-	}
-
-	/* Reset fec phy */
-	ret = gpio_request(MX28EVK_FEC_PHY_RESET, "fec-phy-reset");
-	if (ret) {
-		pr_err("Failed to request gpio fec-phy-%s: %d\n", "reset", ret);
-		return;
-	}
-
-	gpio_direction_output(MX28EVK_FEC_PHY_RESET, 0);
-	if (ret) {
-		pr_err("Failed to drive gpio fec-phy-%s: %d\n", "reset", ret);
-		return;
-	}
-
+	gpio_set_value(MX28EVK_FEC_PHY_RESET, 0);
 	mdelay(1);
 	gpio_set_value(MX28EVK_FEC_PHY_RESET, 1);
 }
@@ -278,14 +252,14 @@
 	const u32 *ocotp = mxs_get_ocotp();
 
 	if (!ocotp)
-		goto error;
+		return -ETIMEDOUT;
 
 	/*
 	 * OCOTP only stores the last 4 octets for each mac address,
 	 * so hard-code Freescale OUI (00:04:9f) here.
 	 */
 	for (i = 0; i < 2; i++) {
-		val = ocotp[i * 4];
+		val = ocotp[i];
 		mx28_fec_pdata[i].mac[0] = 0x00;
 		mx28_fec_pdata[i].mac[1] = 0x04;
 		mx28_fec_pdata[i].mac[2] = 0x9f;
@@ -295,10 +269,6 @@
 	}
 
 	return 0;
-
-error:
-	pr_err("%s: timeout when reading fec mac from OCOTP\n", __func__);
-	return -ETIMEDOUT;
 }
 
 /*
@@ -417,9 +387,14 @@
 static void __init mx28evk_add_regulators(void) {}
 #endif
 
-static struct gpio mx28evk_lcd_gpios[] = {
+static const struct gpio mx28evk_gpios[] __initconst = {
 	{ MX28EVK_LCD_ENABLE, GPIOF_OUT_INIT_HIGH, "lcd-enable" },
 	{ MX28EVK_BL_ENABLE, GPIOF_OUT_INIT_HIGH, "bl-enable" },
+	{ MX28EVK_FLEXCAN_SWITCH, GPIOF_DIR_OUT, "flexcan-switch" },
+	{ MX28EVK_MMC0_SLOT_POWER, GPIOF_OUT_INIT_LOW, "mmc0-slot-power" },
+	{ MX28EVK_MMC1_SLOT_POWER, GPIOF_OUT_INIT_LOW, "mmc1-slot-power" },
+	{ MX28EVK_FEC_PHY_POWER, GPIOF_OUT_INIT_LOW, "fec-phy-power" },
+	{ MX28EVK_FEC_PHY_RESET, GPIOF_DIR_OUT, "fec-phy-reset" },
 };
 
 static const struct mxs_saif_platform_data
@@ -447,25 +422,18 @@
 	if (mx28evk_fec_get_mac())
 		pr_warn("%s: failed on fec mac setup\n", __func__);
 
+	ret = gpio_request_array(mx28evk_gpios, ARRAY_SIZE(mx28evk_gpios));
+	if (ret)
+		pr_err("One or more GPIOs failed to be requested: %d\n", ret);
+
 	mx28evk_fec_reset();
 	mx28_add_fec(0, &mx28_fec_pdata[0]);
 	mx28_add_fec(1, &mx28_fec_pdata[1]);
 
-	ret = gpio_request_one(MX28EVK_FLEXCAN_SWITCH, GPIOF_DIR_OUT,
-				"flexcan-switch");
-	if (ret) {
-		pr_err("failed to request gpio flexcan-switch: %d\n", ret);
-	} else {
-		mx28_add_flexcan(0, &mx28evk_flexcan_pdata[0]);
-		mx28_add_flexcan(1, &mx28evk_flexcan_pdata[1]);
-	}
+	mx28_add_flexcan(0, &mx28evk_flexcan_pdata[0]);
+	mx28_add_flexcan(1, &mx28evk_flexcan_pdata[1]);
 
-	ret = gpio_request_array(mx28evk_lcd_gpios,
-				 ARRAY_SIZE(mx28evk_lcd_gpios));
-	if (ret)
-		pr_warn("failed to request gpio pins for lcd: %d\n", ret);
-	else
-		mx28_add_mxsfb(&mx28evk_mxsfb_pdata);
+	mx28_add_mxsfb(&mx28evk_mxsfb_pdata);
 
 	mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0);
 	mx28_add_saif(0, &mx28evk_mxs_saif_pdata[0]);
@@ -480,20 +448,8 @@
 	mxs_add_platform_device("mxs-sgtl5000", 0, NULL, 0,
 			NULL, 0);
 
-	/* power on mmc slot by writing 0 to the gpio */
-	ret = gpio_request_one(MX28EVK_MMC0_SLOT_POWER, GPIOF_OUT_INIT_LOW,
-			       "mmc0-slot-power");
-	if (ret)
-		pr_warn("failed to request gpio mmc0-slot-power: %d\n", ret);
-	else
-		mx28_add_mxs_mmc(0, &mx28evk_mmc_pdata[0]);
-
-	ret = gpio_request_one(MX28EVK_MMC1_SLOT_POWER, GPIOF_OUT_INIT_LOW,
-			       "mmc1-slot-power");
-	if (ret)
-		pr_warn("failed to request gpio mmc1-slot-power: %d\n", ret);
-	else
-		mx28_add_mxs_mmc(1, &mx28evk_mmc_pdata[1]);
+	mx28_add_mxs_mmc(0, &mx28evk_mmc_pdata[0]);
+	mx28_add_mxs_mmc(1, &mx28evk_mmc_pdata[1]);
 
 	mx28_add_rtc_stmp3xxx();
 
diff --git a/arch/arm/mach-mxs/pm.c b/arch/arm/mach-mxs/pm.c
index fb042da..a9b4bbc 100644
--- a/arch/arm/mach-mxs/pm.c
+++ b/arch/arm/mach-mxs/pm.c
@@ -15,13 +15,12 @@
 #include <linux/kernel.h>
 #include <linux/suspend.h>
 #include <linux/io.h>
-#include <mach/system.h>
 
 static int mxs_suspend_enter(suspend_state_t state)
 {
 	switch (state) {
 	case PM_SUSPEND_MEM:
-		arch_idle();
+		cpu_do_idle();
 		break;
 
 	default:
diff --git a/arch/arm/mach-mxs/system.c b/arch/arm/mach-mxs/system.c
index 54f91ad..80ac1fc 100644
--- a/arch/arm/mach-mxs/system.c
+++ b/arch/arm/mach-mxs/system.c
@@ -25,7 +25,7 @@
 #include <linux/module.h>
 
 #include <asm/proc-fns.h>
-#include <asm/system.h>
+#include <asm/system_misc.h>
 
 #include <mach/mxs.h>
 #include <mach/common.h>
@@ -37,6 +37,8 @@
 #define MXS_MODULE_CLKGATE		(1 << 30)
 #define MXS_MODULE_SFTRST		(1 << 31)
 
+#define CLKCTRL_TIMEOUT		10	/* 10 ms */
+
 static void __iomem *mxs_clkctrl_reset_addr;
 
 /*
@@ -137,3 +139,17 @@
 	return -ETIMEDOUT;
 }
 EXPORT_SYMBOL(mxs_reset_block);
+
+int mxs_clkctrl_timeout(unsigned int reg_offset, unsigned int mask)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(CLKCTRL_TIMEOUT);
+	while (readl_relaxed(MXS_IO_ADDRESS(MXS_CLKCTRL_BASE_ADDR)
+						+ reg_offset) & mask) {
+		if (time_after(jiffies, timeout)) {
+			pr_err("Timeout at CLKCTRL + 0x%x\n", reg_offset);
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
diff --git a/arch/arm/mach-netx/fb.c b/arch/arm/mach-netx/fb.c
index b991323..2cdf6ef 100644
--- a/arch/arm/mach-netx/fb.c
+++ b/arch/arm/mach-netx/fb.c
@@ -92,18 +92,7 @@
 {
 }
 
-static struct amba_device fb_device = {
-	.dev		= {
-		.init_name = "fb",
-		.coherent_dma_mask = ~0,
-	},
-	.res		= {
-		.start	= 0x00104000,
-		.end	= 0x00104fff,
-		.flags	= IORESOURCE_MEM,
-	},
-	.irq		= { NETX_IRQ_LCD, NO_IRQ },
-};
+static AMBA_AHB_DEVICE(fb, "fb", 0, 0x00104000, { NETX_IRQ_LCD }, NULL);
 
 int netx_fb_init(struct clcd_board *board, struct clcd_panel *panel)
 {
diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c
index 59e6797..aa62746 100644
--- a/arch/arm/mach-netx/generic.c
+++ b/arch/arm/mach-netx/generic.c
@@ -168,7 +168,7 @@
 {
 	int irq;
 
-	vic_init(__io(io_p2v(NETX_PA_VIC)), 0, ~0, 0);
+	vic_init(io_p2v(NETX_PA_VIC), 0, ~0, 0);
 
 	for (irq = NETX_IRQ_HIF_CHAINED(0); irq <= NETX_IRQ_HIF_LAST; irq++) {
 		irq_set_chip_and_handler(irq, &netx_hif_chip,
diff --git a/arch/arm/mach-netx/include/mach/entry-macro.S b/arch/arm/mach-netx/include/mach/entry-macro.S
deleted file mode 100644
index 6e9f1cb..0000000
--- a/arch/arm/mach-netx/include/mach/entry-macro.S
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * arch/arm/mach-netx/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for Hilscher netX based platforms
- *
- * Copyright (C) 2005 Sascha Hauer <s.hauer@pengutronix.de>, 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-
-		.macro  disable_fiq
-		.endm
-
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
diff --git a/arch/arm/mach-netx/include/mach/hardware.h b/arch/arm/mach-netx/include/mach/hardware.h
index 517a2bd..b661af2 100644
--- a/arch/arm/mach-netx/include/mach/hardware.h
+++ b/arch/arm/mach-netx/include/mach/hardware.h
@@ -33,7 +33,7 @@
 #define XMAC_MEM_SIZE 0x1000
 #define SRAM_MEM_SIZE 0x8000
 
-#define io_p2v(x) ((x) - NETX_IO_PHYS + NETX_IO_VIRT)
+#define io_p2v(x) IOMEM((x) - NETX_IO_PHYS + NETX_IO_VIRT)
 #define io_v2p(x) ((x) - NETX_IO_VIRT + NETX_IO_PHYS)
 
 #endif
diff --git a/arch/arm/mach-netx/include/mach/io.h b/arch/arm/mach-netx/include/mach/io.h
deleted file mode 100644
index c3921cb..0000000
--- a/arch/arm/mach-netx/include/mach/io.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *  arch/arm/mach-netx/include/mach/io.h
- *
- * Copyright (C) 2005 Sascha Hauer <s.hauer@pengutronix.de>, 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)            (a)
-
-#endif
diff --git a/arch/arm/mach-netx/include/mach/netx-regs.h b/arch/arm/mach-netx/include/mach/netx-regs.h
index 5a03e7c..fdde22b 100644
--- a/arch/arm/mach-netx/include/mach/netx-regs.h
+++ b/arch/arm/mach-netx/include/mach/netx-regs.h
@@ -115,7 +115,7 @@
  *********************************/
 
 /* Registers */
-#define NETX_SYSTEM_REG(ofs)            __io(NETX_VA_SYSTEM + (ofs))
+#define NETX_SYSTEM_REG(ofs)            IOMEM(NETX_VA_SYSTEM + (ofs))
 #define NETX_SYSTEM_BOO_SR          NETX_SYSTEM_REG(0x00)
 #define NETX_SYSTEM_IOC_CR          NETX_SYSTEM_REG(0x04)
 #define NETX_SYSTEM_IOC_MR          NETX_SYSTEM_REG(0x08)
@@ -185,7 +185,7 @@
  *******************************/
 
 /* Registers */
-#define NETX_GPIO_REG(ofs)                     __io(NETX_VA_GPIO + (ofs))
+#define NETX_GPIO_REG(ofs)                     IOMEM(NETX_VA_GPIO + (ofs))
 #define NETX_GPIO_CFG(gpio)                NETX_GPIO_REG(0x0  + ((gpio)<<2))
 #define NETX_GPIO_THRESHOLD_CAPTURE(gpio)  NETX_GPIO_REG(0x40 + ((gpio)<<2))
 #define NETX_GPIO_COUNTER_CTRL(counter)    NETX_GPIO_REG(0x80 + ((counter)<<2))
@@ -230,7 +230,7 @@
  *******************************/
 
 /* Registers */
-#define NETX_PIO_REG(ofs)        __io(NETX_VA_PIO + (ofs))
+#define NETX_PIO_REG(ofs)        IOMEM(NETX_VA_PIO + (ofs))
 #define NETX_PIO_INPIO       NETX_PIO_REG(0x0)
 #define NETX_PIO_OUTPIO      NETX_PIO_REG(0x4)
 #define NETX_PIO_OEPIO       NETX_PIO_REG(0x8)
@@ -240,7 +240,7 @@
  *******************************/
 
 /* Registers */
-#define NETX_MIIMU           __io(NETX_VA_MIIMU)
+#define NETX_MIIMU           IOMEM(NETX_VA_MIIMU)
 
 /* Bits */
 #define MIIMU_SNRDY        (1<<0)
@@ -317,7 +317,7 @@
  *******************************/
 
 /* Registers */
-#define NETX_PFIFO_REG(ofs)               __io(NETX_VA_PFIFO + (ofs))
+#define NETX_PFIFO_REG(ofs)               IOMEM(NETX_VA_PFIFO + (ofs))
 #define NETX_PFIFO_BASE(pfifo)        NETX_PFIFO_REG(0x00 + ((pfifo)<<2))
 #define NETX_PFIFO_BORDER_BASE(pfifo) NETX_PFIFO_REG(0x80 + ((pfifo)<<2))
 #define NETX_PFIFO_RESET              NETX_PFIFO_REG(0x100)
@@ -334,7 +334,7 @@
  *******************************/
 
 /* Registers */
-#define NETX_MEMCR_REG(ofs)               __io(NETX_VA_MEMCR + (ofs))
+#define NETX_MEMCR_REG(ofs)               IOMEM(NETX_VA_MEMCR + (ofs))
 #define NETX_MEMCR_SRAM_CTRL(cs)      NETX_MEMCR_REG(0x0 + 4 * (cs)) /* SRAM for CS 0..2 */
 #define NETX_MEMCR_SDRAM_CFG_CTRL     NETX_MEMCR_REG(0x40)
 #define NETX_MEMCR_SDRAM_TIMING_CTRL  NETX_MEMCR_REG(0x44)
@@ -355,7 +355,7 @@
  *******************************/
 
 /* Registers */
-#define NETX_DPMAS_REG(ofs)               __io(NETX_VA_DPMAS + (ofs))
+#define NETX_DPMAS_REG(ofs)               IOMEM(NETX_VA_DPMAS + (ofs))
 #define NETX_DPMAS_SYS_STAT           NETX_DPMAS_REG(0x4d8)
 #define NETX_DPMAS_INT_STAT           NETX_DPMAS_REG(0x4e0)
 #define NETX_DPMAS_INT_EN             NETX_DPMAS_REG(0x4f0)
@@ -425,7 +425,7 @@
 /*******************************
  * I2C                         *
  *******************************/
-#define NETX_I2C_REG(ofs)	__io(NETX_VA_I2C, (ofs))
+#define NETX_I2C_REG(ofs)	IOMEM(NETX_VA_I2C, (ofs))
 #define NETX_I2C_CTRL	NETX_I2C_REG(0x0)
 #define NETX_I2C_DATA	NETX_I2C_REG(0x4)
 
diff --git a/arch/arm/mach-netx/include/mach/system.h b/arch/arm/mach-netx/include/mach/system.h
deleted file mode 100644
index b38fa36..0000000
--- a/arch/arm/mach-netx/include/mach/system.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * arch/arm/mach-netx/include/mach/system.h
- *
- * Copyright (C) 2005 Sascha Hauer <s.hauer@pengutronix.de>, 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
-#endif
-
diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c
index 7c878bf..58cacaf 100644
--- a/arch/arm/mach-nomadik/board-nhk8815.c
+++ b/arch/arm/mach-nomadik/board-nhk8815.c
@@ -27,11 +27,11 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/flash.h>
+#include <asm/mach/time.h>
 
 #include <plat/gpio-nomadik.h>
 #include <plat/mtu.h>
 
-#include <mach/setup.h>
 #include <mach/nand.h>
 #include <mach/fsmc.h>
 
@@ -185,20 +185,11 @@
 #endif
 }
 
-#define __MEM_4K_RESOURCE(x) \
-	.res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
+static AMBA_APB_DEVICE(uart0, "uart0", 0, NOMADIK_UART0_BASE,
+	{ IRQ_UART0 }, NULL);
 
-static struct amba_device uart0_device = {
-	.dev = { .init_name = "uart0" },
-	__MEM_4K_RESOURCE(NOMADIK_UART0_BASE),
-	.irq = {IRQ_UART0, NO_IRQ},
-};
-
-static struct amba_device uart1_device = {
-	.dev = { .init_name = "uart1" },
-	__MEM_4K_RESOURCE(NOMADIK_UART1_BASE),
-	.irq = {IRQ_UART1, NO_IRQ},
-};
+static AMBA_APB_DEVICE(uart1, "uart1", 0, NOMADIK_UART1_BASE,
+	{ IRQ_UART1 }, NULL);
 
 static struct amba_device *amba_devs[] __initdata = {
 	&uart0_device,
@@ -255,10 +246,7 @@
 	src_cr |= SRC_CR_INIT_VAL;
 	writel(src_cr, io_p2v(NOMADIK_SRC_BASE));
 
-	/* Save global pointer to mtu, used by platform timer code */
-	mtu_base = io_p2v(NOMADIK_MTU0_BASE);
-
-	nmdk_timer_init();
+	nmdk_timer_init(io_p2v(NOMADIK_MTU0_BASE));
 }
 
 static struct sys_timer nomadik_timer = {
diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c
index 65df7b4..27f43a4 100644
--- a/arch/arm/mach-nomadik/cpu-8815.c
+++ b/arch/arm/mach-nomadik/cpu-8815.c
@@ -97,12 +97,7 @@
 	GPIO_DEVICE(3),
 };
 
-static struct amba_device cpu8815_amba_rng = {
-	.dev = {
-		.init_name = "rng",
-	},
-	__MEM_4K_RESOURCE(NOMADIK_RNG_BASE),
-};
+static AMBA_APB_DEVICE(cpu8815_amba_rng, "rng", 0, NOMADIK_RNG_BASE, { }, NULL);
 
 static struct platform_device *platform_devs[] __initdata = {
 	cpu8815_platform_gpio + 0,
@@ -112,7 +107,7 @@
 };
 
 static struct amba_device *amba_devs[] __initdata = {
-	&cpu8815_amba_rng
+	&cpu8815_amba_rng_device
 };
 
 static int __init cpu8815_init(void)
diff --git a/arch/arm/mach-nomadik/include/mach/entry-macro.S b/arch/arm/mach-nomadik/include/mach/entry-macro.S
deleted file mode 100644
index 98ea1c1..0000000
--- a/arch/arm/mach-nomadik/include/mach/entry-macro.S
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Low-level IRQ helper macros for Nomadik platforms
- *
- * 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.
- */
-
-	.macro	disable_fiq
-	.endm
-
-	.macro	arch_ret_to_user, tmp1, tmp2
-	.endm
diff --git a/arch/arm/mach-nomadik/include/mach/io.h b/arch/arm/mach-nomadik/include/mach/io.h
deleted file mode 100644
index 2e1eca1..0000000
--- a/arch/arm/mach-nomadik/include/mach/io.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * arch/arm/mach-nomadik/include/mach/io.h   (copied from mach-sa1100)
- *
- * Copyright (C) 1997-1999 Russell King
- *
- * Modifications:
- *  06-12-1997  RMK     Created.
- *  07-04-1999  RMK     Major cleanup
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-/*
- * We don't actually have real ISA nor PCI buses, but there is so many
- * drivers out there that might just work if we fake them...
- */
-#define __io(a)         __typesafe_io(a)
-#define __mem_pci(a)    (a)
-
-#endif
diff --git a/arch/arm/mach-nomadik/include/mach/setup.h b/arch/arm/mach-nomadik/include/mach/setup.h
deleted file mode 100644
index bcaeaf4..0000000
--- a/arch/arm/mach-nomadik/include/mach/setup.h
+++ /dev/null
@@ -1,19 +0,0 @@
-
-/*
- * These symbols are needed for board-specific files to call their
- * own cpu-specific files
- */
-
-#ifndef __ASM_ARCH_SETUP_H
-#define __ASM_ARCH_SETUP_H
-
-#include <asm/mach/time.h>
-#include <linux/init.h>
-
-#ifdef CONFIG_NOMADIK_8815
-
-extern void nmdk_timer_init(void);
-
-#endif /* NOMADIK_8815 */
-
-#endif /*  __ASM_ARCH_SETUP_H */
diff --git a/arch/arm/mach-nomadik/include/mach/system.h b/arch/arm/mach-nomadik/include/mach/system.h
deleted file mode 100644
index 25e198b..0000000
--- a/arch/arm/mach-nomadik/include/mach/system.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *  mach-nomadik/include/mach/system.h
- *
- *  Copyright (C) 2008 STMicroelectronics
- *
- * 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
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	/*
-	 * This should do all the clock switching
-	 * and wait for interrupt tricks
-	 */
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index 4f8d66f..dfab466 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -37,7 +37,6 @@
 config MACH_OMAP_INNOVATOR
 	bool "TI Innovator"
 	depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX)
-	select OMAP_MCBSP
 	help
           TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
           have such a board.
@@ -45,7 +44,6 @@
 config MACH_OMAP_H2
 	bool "TI H2 Support"
 	depends on ARCH_OMAP1 && ARCH_OMAP16XX
-	select OMAP_MCBSP
     	help
 	  TI OMAP 1610/1611B H2 board support. Say Y here if you have such
 	  a board.
@@ -72,7 +70,6 @@
 config MACH_OMAP_OSK
 	bool "TI OSK Support"
 	depends on ARCH_OMAP1 && ARCH_OMAP16XX
-	select OMAP_MCBSP
     	help
 	  TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
           if you have such a board.
@@ -155,6 +152,10 @@
 	bool "Amstrad E3 (Delta)"
 	depends on ARCH_OMAP1 && ARCH_OMAP15XX
 	select FIQ
+	select GPIO_GENERIC_PLATFORM
+	select LEDS_GPIO_REGISTER
+	select REGULATOR
+	select REGULATOR_FIXED_VOLTAGE
 	help
 	  Support for the Amstrad E3 (codename Delta) videophone. Say Y here
 	  if you have such a device.
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index 11c85cd2..9923f92 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -6,7 +6,9 @@
 obj-y := io.o id.o sram.o time.o irq.o mux.o flash.o serial.o devices.o dma.o
 obj-y += clock.o clock_data.o opp_data.o reset.o pm_bus.o timer.o
 
-obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
+ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
+obj-y += mcbsp.o
+endif
 
 obj-$(CONFIG_OMAP_32K_TIMER)	+= timer32k.o
 
diff --git a/arch/arm/mach-omap1/ams-delta-fiq-handler.S b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
index c1c5fb6..a051cb8 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq-handler.S
+++ b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
@@ -14,12 +14,14 @@
  */
 
 #include <linux/linkage.h>
+#include <asm/assembler.h>
 
-#include <plat/io.h>
 #include <plat/board-ams-delta.h>
 
 #include <mach/ams-delta-fiq.h>
 
+#include "iomap.h"
+
 /*
  * GPIO related definitions, copied from arch/arm/plat-omap/gpio.c.
  * Unfortunately, those were not placed in a separate header file.
diff --git a/arch/arm/mach-omap1/ams-delta-fiq.c b/arch/arm/mach-omap1/ams-delta-fiq.c
index 152b32c..fcce7ff 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq.c
+++ b/arch/arm/mach-omap1/ams-delta-fiq.c
@@ -22,6 +22,7 @@
 #include <plat/board-ams-delta.h>
 
 #include <asm/fiq.h>
+
 #include <mach/ams-delta-fiq.h>
 
 static struct fiq_handler fh = {
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
index 88909cc..c1b681e 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -11,6 +11,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/basic_mmio_gpio.h>
 #include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -18,30 +19,33 @@
 #include <linux/interrupt.h>
 #include <linux/leds.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 #include <linux/serial_8250.h>
 #include <linux/export.h>
+#include <linux/omapfb.h>
+#include <linux/io.h>
 
 #include <media/soc_camera.h>
 
 #include <asm/serial.h>
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/io.h>
 #include <plat/board-ams-delta.h>
 #include <plat/keypad.h>
 #include <plat/mux.h>
 #include <plat/usb.h>
 #include <plat/board.h>
-#include "common.h"
+
+#include <mach/hardware.h>
+#include <mach/ams-delta-fiq.h>
 #include <mach/camera.h>
 
-#include <mach/ams-delta-fiq.h>
-
-static u8 ams_delta_latch1_reg;
-static u16 ams_delta_latch2_reg;
+#include "iomap.h"
+#include "common.h"
 
 static const unsigned int ams_delta_keymap[] = {
 	KEY(0, 0, KEY_F1),		/* Advert    */
@@ -121,58 +125,188 @@
 	KEY(7, 3, KEY_LEFTCTRL),	/* Vol down  */
 };
 
-void ams_delta_latch1_write(u8 mask, u8 value)
-{
-	ams_delta_latch1_reg &= ~mask;
-	ams_delta_latch1_reg |= value;
-	*(volatile __u8 *) AMS_DELTA_LATCH1_VIRT = ams_delta_latch1_reg;
-}
-
-void ams_delta_latch2_write(u16 mask, u16 value)
-{
-	ams_delta_latch2_reg &= ~mask;
-	ams_delta_latch2_reg |= value;
-	*(volatile __u16 *) AMS_DELTA_LATCH2_VIRT = ams_delta_latch2_reg;
-}
+#define LATCH1_PHYS	0x01000000
+#define LATCH1_VIRT	0xEA000000
+#define MODEM_PHYS	0x04000000
+#define MODEM_VIRT	0xEB000000
+#define LATCH2_PHYS	0x08000000
+#define LATCH2_VIRT	0xEC000000
 
 static struct map_desc ams_delta_io_desc[] __initdata = {
 	/* AMS_DELTA_LATCH1 */
 	{
-		.virtual	= AMS_DELTA_LATCH1_VIRT,
-		.pfn		= __phys_to_pfn(AMS_DELTA_LATCH1_PHYS),
+		.virtual	= LATCH1_VIRT,
+		.pfn		= __phys_to_pfn(LATCH1_PHYS),
 		.length		= 0x01000000,
 		.type		= MT_DEVICE
 	},
 	/* AMS_DELTA_LATCH2 */
 	{
-		.virtual	= AMS_DELTA_LATCH2_VIRT,
-		.pfn		= __phys_to_pfn(AMS_DELTA_LATCH2_PHYS),
+		.virtual	= LATCH2_VIRT,
+		.pfn		= __phys_to_pfn(LATCH2_PHYS),
 		.length		= 0x01000000,
 		.type		= MT_DEVICE
 	},
 	/* AMS_DELTA_MODEM */
 	{
-		.virtual	= AMS_DELTA_MODEM_VIRT,
-		.pfn		= __phys_to_pfn(AMS_DELTA_MODEM_PHYS),
+		.virtual	= MODEM_VIRT,
+		.pfn		= __phys_to_pfn(MODEM_PHYS),
 		.length		= 0x01000000,
 		.type		= MT_DEVICE
 	}
 };
 
-static struct omap_lcd_config ams_delta_lcd_config = {
+static struct omap_lcd_config ams_delta_lcd_config __initdata = {
 	.ctrl_name	= "internal",
 };
 
-static struct omap_usb_config ams_delta_usb_config __initdata = {
+static struct omap_usb_config ams_delta_usb_config = {
 	.register_host	= 1,
 	.hmc_mode	= 16,
 	.pins[0]	= 2,
 };
 
-static struct omap_board_config_kernel ams_delta_config[] __initdata = {
-	{ OMAP_TAG_LCD,		&ams_delta_lcd_config },
+#define LATCH1_GPIO_BASE	232
+#define LATCH1_NGPIO		8
+
+static struct resource latch1_resources[] = {
+	[0] = {
+		.name	= "dat",
+		.start	= LATCH1_PHYS,
+		.end	= LATCH1_PHYS + (LATCH1_NGPIO - 1) / 8,
+		.flags	= IORESOURCE_MEM,
+	},
 };
 
+static struct bgpio_pdata latch1_pdata = {
+	.base	= LATCH1_GPIO_BASE,
+	.ngpio	= LATCH1_NGPIO,
+};
+
+static struct platform_device latch1_gpio_device = {
+	.name		= "basic-mmio-gpio",
+	.id		= 0,
+	.resource	= latch1_resources,
+	.num_resources	= ARRAY_SIZE(latch1_resources),
+	.dev		= {
+		.platform_data	= &latch1_pdata,
+	},
+};
+
+static struct resource latch2_resources[] = {
+	[0] = {
+		.name	= "dat",
+		.start	= LATCH2_PHYS,
+		.end	= LATCH2_PHYS + (AMS_DELTA_LATCH2_NGPIO - 1) / 8,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct bgpio_pdata latch2_pdata = {
+	.base	= AMS_DELTA_LATCH2_GPIO_BASE,
+	.ngpio	= AMS_DELTA_LATCH2_NGPIO,
+};
+
+static struct platform_device latch2_gpio_device = {
+	.name		= "basic-mmio-gpio",
+	.id		= 1,
+	.resource	= latch2_resources,
+	.num_resources	= ARRAY_SIZE(latch2_resources),
+	.dev		= {
+		.platform_data	= &latch2_pdata,
+	},
+};
+
+static const struct gpio latch_gpios[] __initconst = {
+	{
+		.gpio	= LATCH1_GPIO_BASE + 6,
+		.flags	= GPIOF_OUT_INIT_LOW,
+		.label	= "dockit1",
+	},
+	{
+		.gpio	= LATCH1_GPIO_BASE + 7,
+		.flags	= GPIOF_OUT_INIT_LOW,
+		.label	= "dockit2",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_SCARD_RSTIN,
+		.flags	= GPIOF_OUT_INIT_LOW,
+		.label	= "scard_rstin",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_SCARD_CMDVCC,
+		.flags	= GPIOF_OUT_INIT_LOW,
+		.label	= "scard_cmdvcc",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_MODEM_CODEC,
+		.flags	= GPIOF_OUT_INIT_LOW,
+		.label	= "modem_codec",
+	},
+	{
+		.gpio	= AMS_DELTA_LATCH2_GPIO_BASE + 14,
+		.flags	= GPIOF_OUT_INIT_LOW,
+		.label	= "hookflash1",
+	},
+	{
+		.gpio	= AMS_DELTA_LATCH2_GPIO_BASE + 15,
+		.flags	= GPIOF_OUT_INIT_LOW,
+		.label	= "hookflash2",
+	},
+};
+
+static struct regulator_consumer_supply modem_nreset_consumers[] = {
+	REGULATOR_SUPPLY("RESET#", "serial8250.1"),
+	REGULATOR_SUPPLY("POR", "cx20442-codec"),
+};
+
+static struct regulator_init_data modem_nreset_data = {
+	.constraints		= {
+		.valid_ops_mask		= REGULATOR_CHANGE_STATUS,
+		.boot_on		= 1,
+	},
+	.num_consumer_supplies	= ARRAY_SIZE(modem_nreset_consumers),
+	.consumer_supplies	= modem_nreset_consumers,
+};
+
+static struct fixed_voltage_config modem_nreset_config = {
+	.supply_name		= "modem_nreset",
+	.microvolts		= 3300000,
+	.gpio			= AMS_DELTA_GPIO_PIN_MODEM_NRESET,
+	.startup_delay		= 25000,
+	.enable_high		= 1,
+	.enabled_at_boot	= 1,
+	.init_data		= &modem_nreset_data,
+};
+
+static struct platform_device modem_nreset_device = {
+	.name	= "reg-fixed-voltage",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &modem_nreset_config,
+	},
+};
+
+struct modem_private_data {
+	struct regulator *regulator;
+};
+
+static struct modem_private_data modem_priv;
+
+void ams_delta_latch_write(int base, int ngpio, u16 mask, u16 value)
+{
+	int bit = 0;
+	u16 bitpos = 1 << bit;
+
+	for (; bit < ngpio; bit++, bitpos = bitpos << 1) {
+		if (!(mask & bitpos))
+			continue;
+		else
+			gpio_set_value(base + bit, (value & bitpos) != 0);
+	}
+}
+EXPORT_SYMBOL(ams_delta_latch_write);
+
 static struct resource ams_delta_nand_resources[] = {
 	[0] = {
 		.start	= OMAP1_MPUIO_BASE,
@@ -202,7 +336,7 @@
 	.keymap_size	= ARRAY_SIZE(ams_delta_keymap),
 };
 
-static struct omap_kp_platform_data ams_delta_kp_data __initdata = {
+static struct omap_kp_platform_data ams_delta_kp_data = {
 	.rows		= 8,
 	.cols		= 8,
 	.keymap_data	= &ams_delta_keymap_data,
@@ -224,9 +358,45 @@
 	.id	= -1,
 };
 
-static struct platform_device ams_delta_led_device = {
-	.name	= "ams-delta-led",
-	.id	= -1
+static const struct gpio_led gpio_leds[] __initconst = {
+	{
+		.name		 = "camera",
+		.gpio		 = LATCH1_GPIO_BASE + 0,
+		.default_state	 = LEDS_GPIO_DEFSTATE_OFF,
+#ifdef CONFIG_LEDS_TRIGGERS
+		.default_trigger = "ams_delta_camera",
+#endif
+	},
+	{
+		.name		 = "advert",
+		.gpio		 = LATCH1_GPIO_BASE + 1,
+		.default_state	 = LEDS_GPIO_DEFSTATE_OFF,
+	},
+	{
+		.name		 = "email",
+		.gpio		 = LATCH1_GPIO_BASE + 2,
+		.default_state	 = LEDS_GPIO_DEFSTATE_OFF,
+	},
+	{
+		.name		 = "handsfree",
+		.gpio		 = LATCH1_GPIO_BASE + 3,
+		.default_state	 = LEDS_GPIO_DEFSTATE_OFF,
+	},
+	{
+		.name		 = "voicemail",
+		.gpio		 = LATCH1_GPIO_BASE + 4,
+		.default_state	 = LEDS_GPIO_DEFSTATE_OFF,
+	},
+	{
+		.name		 = "voice",
+		.gpio		 = LATCH1_GPIO_BASE + 5,
+		.default_state	 = LEDS_GPIO_DEFSTATE_OFF,
+	},
+};
+
+static const struct gpio_led_platform_data leds_pdata __initconst = {
+	.leds		= gpio_leds,
+	.num_leds	= ARRAY_SIZE(gpio_leds),
 };
 
 static struct i2c_board_info ams_delta_camera_board_info[] = {
@@ -275,13 +445,17 @@
 };
 
 static struct platform_device *ams_delta_devices[] __initdata = {
-	&ams_delta_nand_device,
+	&latch1_gpio_device,
+	&latch2_gpio_device,
 	&ams_delta_kp_device,
-	&ams_delta_lcd_device,
-	&ams_delta_led_device,
 	&ams_delta_camera_device,
 };
 
+static struct platform_device *late_devices[] __initdata = {
+	&ams_delta_nand_device,
+	&ams_delta_lcd_device,
+};
+
 static void __init ams_delta_init(void)
 {
 	/* mux pins for uarts */
@@ -302,37 +476,53 @@
 	omap_cfg_reg(J19_1610_CAM_D6);
 	omap_cfg_reg(J18_1610_CAM_D7);
 
-	omap_board_config = ams_delta_config;
-	omap_board_config_size = ARRAY_SIZE(ams_delta_config);
 	omap_serial_init();
 	omap_register_i2c_bus(1, 100, NULL, 0);
 
-	/* Clear latch2 (NAND, LCD, modem enable) */
-	ams_delta_latch2_write(~0, 0);
-
 	omap1_usb_init(&ams_delta_usb_config);
 	omap1_set_camera_info(&ams_delta_camera_platform_data);
 #ifdef CONFIG_LEDS_TRIGGERS
 	led_trigger_register_simple("ams_delta_camera",
 			&ams_delta_camera_led_trigger);
 #endif
+	gpio_led_register_device(-1, &leds_pdata);
 	platform_add_devices(ams_delta_devices, ARRAY_SIZE(ams_delta_devices));
 
 	ams_delta_init_fiq();
 
 	omap_writew(omap_readw(ARM_RSTCT1) | 0x0004, ARM_RSTCT1);
+
+	omapfb_set_lcd_config(&ams_delta_lcd_config);
+}
+
+static void modem_pm(struct uart_port *port, unsigned int state, unsigned old)
+{
+	struct modem_private_data *priv = port->private_data;
+
+	if (IS_ERR(priv->regulator))
+		return;
+
+	if (state == old)
+		return;
+
+	if (state == 0)
+		regulator_enable(priv->regulator);
+	else if (old == 0)
+		regulator_disable(priv->regulator);
 }
 
 static struct plat_serial8250_port ams_delta_modem_ports[] = {
 	{
-		.membase	= IOMEM(AMS_DELTA_MODEM_VIRT),
-		.mapbase	= AMS_DELTA_MODEM_PHYS,
+		.membase	= IOMEM(MODEM_VIRT),
+		.mapbase	= MODEM_PHYS,
 		.irq		= -EINVAL, /* changed later */
 		.flags		= UPF_BOOT_AUTOCONF,
 		.irqflags	= IRQF_TRIGGER_RISING,
 		.iotype		= UPIO_MEM,
 		.regshift	= 1,
 		.uartclk	= BASE_BAUD * 16,
+		.pm		= modem_pm,
+		.private_data	= &modem_priv,
 	},
 	{ },
 };
@@ -345,13 +535,27 @@
 	},
 };
 
-static int __init ams_delta_modem_init(void)
+static int __init late_init(void)
 {
 	int err;
 
 	if (!machine_is_ams_delta())
 		return -ENODEV;
 
+	err = gpio_request_array(latch_gpios, ARRAY_SIZE(latch_gpios));
+	if (err) {
+		pr_err("Couldn't take over latch1/latch2 GPIO pins\n");
+		return err;
+	}
+
+	platform_add_devices(late_devices, ARRAY_SIZE(late_devices));
+
+	err = platform_device_register(&modem_nreset_device);
+	if (err) {
+		pr_err("Couldn't register the modem regulator device\n");
+		return err;
+	}
+
 	omap_cfg_reg(M14_1510_GPIO2);
 	ams_delta_modem_ports[0].irq =
 			gpio_to_irq(AMS_DELTA_GPIO_PIN_MODEM_IRQ);
@@ -363,13 +567,35 @@
 	}
 	gpio_direction_input(AMS_DELTA_GPIO_PIN_MODEM_IRQ);
 
-	ams_delta_latch2_write(
-		AMS_DELTA_LATCH2_MODEM_NRESET | AMS_DELTA_LATCH2_MODEM_CODEC,
-		AMS_DELTA_LATCH2_MODEM_NRESET | AMS_DELTA_LATCH2_MODEM_CODEC);
+	/* Initialize the modem_nreset regulator consumer before use */
+	modem_priv.regulator = ERR_PTR(-ENODEV);
 
-	return platform_device_register(&ams_delta_modem_device);
+	ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC,
+			AMS_DELTA_LATCH2_MODEM_CODEC);
+
+	err = platform_device_register(&ams_delta_modem_device);
+	if (err)
+		goto gpio_free;
+
+	/*
+	 * Once the modem device is registered, the modem_nreset
+	 * regulator can be requested on behalf of that device.
+	 */
+	modem_priv.regulator = regulator_get(&ams_delta_modem_device.dev,
+			"RESET#");
+	if (IS_ERR(modem_priv.regulator)) {
+		err = PTR_ERR(modem_priv.regulator);
+		goto unregister;
+	}
+	return 0;
+
+unregister:
+	platform_device_unregister(&ams_delta_modem_device);
+gpio_free:
+	gpio_free(AMS_DELTA_GPIO_PIN_MODEM_IRQ);
+	return err;
 }
-arch_initcall(ams_delta_modem_init);
+late_initcall(late_init);
 
 static void __init ams_delta_map_io(void)
 {
@@ -388,6 +614,3 @@
 	.timer		= &omap1_timer,
 	.restart	= omap1_restart,
 MACHINE_END
-
-EXPORT_SYMBOL(ams_delta_latch1_write);
-EXPORT_SYMBOL(ams_delta_latch2_write);
diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
index 0b9464b..80bd43c 100644
--- a/arch/arm/mach-omap1/board-fsample.c
+++ b/arch/arm/mach-omap1/board-fsample.c
@@ -21,8 +21,8 @@
 #include <linux/mtd/physmap.h>
 #include <linux/input.h>
 #include <linux/smc91x.h>
+#include <linux/omapfb.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -32,9 +32,13 @@
 #include <plat/flash.h>
 #include <plat/fpga.h>
 #include <plat/keypad.h>
-#include "common.h"
 #include <plat/board.h>
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
+#include "common.h"
+
 /* fsample is pretty close to p2-sample */
 
 #define fsample_cpld_read(reg) __raw_readb(reg)
@@ -273,27 +277,17 @@
 	.resource	= kp_resources,
 };
 
-static struct platform_device lcd_device = {
-	.name		= "lcd_p2",
-	.id		= -1,
-};
-
 static struct platform_device *devices[] __initdata = {
 	&nor_device,
 	&nand_device,
 	&smc91x_device,
 	&kp_device,
-	&lcd_device,
 };
 
 static struct omap_lcd_config fsample_lcd_config = {
 	.ctrl_name	= "internal",
 };
 
-static struct omap_board_config_kernel fsample_config[] __initdata = {
-	{ OMAP_TAG_LCD,		&fsample_lcd_config },
-};
-
 static void __init omap_fsample_init(void)
 {
 	/* Early, board-dependent init */
@@ -352,10 +346,10 @@
 
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 
-	omap_board_config = fsample_config;
-	omap_board_config_size = ARRAY_SIZE(fsample_config);
 	omap_serial_init();
 	omap_register_i2c_bus(1, 100, NULL, 0);
+
+	omapfb_set_lcd_config(&fsample_lcd_config);
 }
 
 /* Only FPGA needs to be mapped here. All others are done with ioremap */
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 00ad6b2..553a2e5 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -30,8 +30,7 @@
 #include <linux/input.h>
 #include <linux/i2c/tps65010.h>
 #include <linux/smc91x.h>
-
-#include <mach/hardware.h>
+#include <linux/omapfb.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -43,9 +42,11 @@
 #include <plat/irda.h>
 #include <plat/usb.h>
 #include <plat/keypad.h>
-#include "common.h"
 #include <plat/flash.h>
 
+#include <mach/hardware.h>
+
+#include "common.h"
 #include "board-h2.h"
 
 /* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
@@ -244,8 +245,6 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= OMAP_GPIO_IRQ(0),
-		.end	= OMAP_GPIO_IRQ(0),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
 	},
 };
@@ -325,18 +324,12 @@
 	.resource	= h2_irda_resources,
 };
 
-static struct platform_device h2_lcd_device = {
-	.name		= "lcd_h2",
-	.id		= -1,
-};
-
 static struct platform_device *h2_devices[] __initdata = {
 	&h2_nor_device,
 	&h2_nand_device,
 	&h2_smc91x_device,
 	&h2_irda_device,
 	&h2_kp_device,
-	&h2_lcd_device,
 };
 
 static void __init h2_init_smc91x(void)
@@ -364,11 +357,9 @@
 static struct i2c_board_info __initdata h2_i2c_board_info[] = {
 	{
 		I2C_BOARD_INFO("tps65010", 0x48),
-		.irq            = OMAP_GPIO_IRQ(58),
 		.platform_data	= &tps_board,
 	}, {
 		I2C_BOARD_INFO("isp1301_omap", 0x2d),
-		.irq		= OMAP_GPIO_IRQ(2),
 	},
 };
 
@@ -391,10 +382,6 @@
 	.ctrl_name	= "internal",
 };
 
-static struct omap_board_config_kernel h2_config[] __initdata = {
-	{ OMAP_TAG_LCD,		&h2_lcd_config },
-};
-
 static void __init h2_init(void)
 {
 	h2_init_smc91x();
@@ -437,14 +424,18 @@
 	omap_cfg_reg(E19_1610_KBR4);
 	omap_cfg_reg(N19_1610_KBR5);
 
+	h2_smc91x_resources[1].start = gpio_to_irq(0);
+	h2_smc91x_resources[1].end = gpio_to_irq(0);
 	platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
-	omap_board_config = h2_config;
-	omap_board_config_size = ARRAY_SIZE(h2_config);
 	omap_serial_init();
+	h2_i2c_board_info[0].irq = gpio_to_irq(58);
+	h2_i2c_board_info[1].irq = gpio_to_irq(2);
 	omap_register_i2c_bus(1, 100, h2_i2c_board_info,
 			      ARRAY_SIZE(h2_i2c_board_info));
 	omap1_usb_init(&h2_usb_config);
 	h2_mmc_init();
+
+	omapfb_set_lcd_config(&h2_lcd_config);
 }
 
 MACHINE_START(OMAP_H2, "TI-H2")
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 4a7f251..4c19f4c 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -30,24 +30,25 @@
 #include <linux/spi/spi.h>
 #include <linux/i2c/tps65010.h>
 #include <linux/smc91x.h>
+#include <linux/omapfb.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
-#include <mach/hardware.h>
-
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <mach/irqs.h>
 #include <plat/mux.h>
 #include <plat/tc.h>
 #include <plat/usb.h>
 #include <plat/keypad.h>
 #include <plat/dma.h>
-#include "common.h"
 #include <plat/flash.h>
 
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
+#include "common.h"
 #include "board-h3.h"
 
 /* In OMAP1710 H3 the Ethernet is directly connected to CS1 */
@@ -246,8 +247,6 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= OMAP_GPIO_IRQ(40),
-		.end	= OMAP_GPIO_IRQ(40),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
 	},
 };
@@ -337,7 +336,6 @@
 		.modalias	= "tsc2101",
 		.bus_num	= 2,
 		.chip_select	= 0,
-		.irq		= OMAP_GPIO_IRQ(H3_TS_GPIO),
 		.max_speed_hz	= 16000000,
 		/* .platform_data	= &tsc_platform_data, */
 	},
@@ -370,18 +368,12 @@
 	.ctrl_name	= "internal",
 };
 
-static struct omap_board_config_kernel h3_config[] __initdata = {
-	{ OMAP_TAG_LCD,		&h3_lcd_config },
-};
-
 static struct i2c_board_info __initdata h3_i2c_board_info[] = {
        {
 		I2C_BOARD_INFO("tps65013", 0x48),
-               /* .irq         = OMAP_GPIO_IRQ(??), */
        },
 	{
 		I2C_BOARD_INFO("isp1301_omap", 0x2d),
-		.irq		= OMAP_GPIO_IRQ(14),
 	},
 };
 
@@ -423,16 +415,20 @@
 	omap_cfg_reg(E19_1610_KBR4);
 	omap_cfg_reg(N19_1610_KBR5);
 
+	smc91x_resources[1].start = gpio_to_irq(40);
+	smc91x_resources[1].end = gpio_to_irq(40);
 	platform_add_devices(devices, ARRAY_SIZE(devices));
+	h3_spi_board_info[0].irq = gpio_to_irq(H3_TS_GPIO);
 	spi_register_board_info(h3_spi_board_info,
 				ARRAY_SIZE(h3_spi_board_info));
-	omap_board_config = h3_config;
-	omap_board_config_size = ARRAY_SIZE(h3_config);
 	omap_serial_init();
+	h3_i2c_board_info[1].irq = gpio_to_irq(14);
 	omap_register_i2c_bus(1, 100, h3_i2c_board_info,
 			      ARRAY_SIZE(h3_i2c_board_info));
 	omap1_usb_init(&h3_usb_config);
 	h3_mmc_init();
+
+	omapfb_set_lcd_config(&h3_lcd_config);
 }
 
 MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
diff --git a/arch/arm/mach-omap1/board-htcherald.c b/arch/arm/mach-omap1/board-htcherald.c
index 731cc3d..60c06ee 100644
--- a/arch/arm/mach-omap1/board-htcherald.c
+++ b/arch/arm/mach-omap1/board-htcherald.c
@@ -27,7 +27,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
-#include <linux/io.h>
+#include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/i2c.h>
@@ -36,12 +36,12 @@
 #include <linux/leds.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
+#include <linux/omapfb.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
 #include <plat/omap7xx.h>
-#include "common.h"
 #include <plat/board.h>
 #include <plat/keypad.h>
 #include <plat/usb.h>
@@ -49,7 +49,7 @@
 
 #include <mach/irqs.h>
 
-#include <linux/delay.h>
+#include "common.h"
 
 /* LCD register definition */
 #define       OMAP_LCDC_CONTROL               (0xfffec000 + 0x00)
@@ -324,8 +324,6 @@
 
 static struct resource htcpld_resources[] = {
 	[0] = {
-		.start  = OMAP_GPIO_IRQ(HTCHERALD_GIRQ_BTNS),
-		.end    = OMAP_GPIO_IRQ(HTCHERALD_GIRQ_BTNS),
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -398,10 +396,6 @@
 	.ctrl_name	= "internal",
 };
 
-static struct omap_board_config_kernel htcherald_config[] __initdata = {
-	{ OMAP_TAG_LCD, &htcherald_lcd_config },
-};
-
 static struct platform_device lcd_device = {
 	.name           = "lcd_htcherald",
 	.id             = -1,
@@ -454,7 +448,6 @@
 	{
 		.modalias		= "ads7846",
 		.platform_data		= &htcherald_ts_platform_data,
-		.irq			= OMAP_GPIO_IRQ(HTCHERALD_GPIO_TS),
 		.max_speed_hz		= 2500000,
 		.bus_num		= 2,
 		.chip_select		= 1,
@@ -580,8 +573,8 @@
 	printk(KERN_INFO "HTC Herald init.\n");
 
 	/* Do board initialization before we register all the devices */
-	omap_board_config = htcherald_config;
-	omap_board_config_size = ARRAY_SIZE(htcherald_config);
+	htcpld_resources[0].start = gpio_to_irq(HTCHERALD_GIRQ_BTNS);
+	htcpld_resources[0].end = gpio_to_irq(HTCHERALD_GIRQ_BTNS);
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 
 	htcherald_disable_watchdog();
@@ -589,6 +582,7 @@
 	htcherald_usb_enable();
 	omap1_usb_init(&htcherald_usb_config);
 
+	htcherald_spi_board_info[0].irq = gpio_to_irq(HTCHERALD_GPIO_TS);
 	spi_register_board_info(htcherald_spi_board_info,
 		ARRAY_SIZE(htcherald_spi_board_info));
 
@@ -598,6 +592,8 @@
 	htc_mmc_data[0] = &htc_mmc1_data;
 	omap1_init_mmc(htc_mmc_data, 1);
 #endif
+
+	omapfb_set_lcd_config(&htcherald_lcd_config);
 }
 
 MACHINE_START(HERALD, "HTC Herald")
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index be2002f..67d7fd5 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -25,8 +25,8 @@
 #include <linux/mtd/physmap.h>
 #include <linux/input.h>
 #include <linux/smc91x.h>
+#include <linux/omapfb.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -37,9 +37,13 @@
 #include <plat/tc.h>
 #include <plat/usb.h>
 #include <plat/keypad.h>
-#include "common.h"
 #include <plat/mmc.h>
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
+#include "common.h"
+
 /* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
 #define INNOVATOR1610_ETHR_START	0x04000300
 
@@ -244,8 +248,6 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= OMAP_GPIO_IRQ(0),
-		.end	= OMAP_GPIO_IRQ(0),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
 	},
 };
@@ -370,10 +372,6 @@
 }
 #endif
 
-static struct omap_board_config_kernel innovator_config[] = {
-	{ OMAP_TAG_LCD,		NULL },
-};
-
 static void __init innovator_init(void)
 {
 	if (cpu_is_omap1510())
@@ -409,6 +407,8 @@
 #endif
 #ifdef CONFIG_ARCH_OMAP16XX
 	if (!cpu_is_omap1510()) {
+		innovator1610_smc91x_resources[1].start = gpio_to_irq(0);
+		innovator1610_smc91x_resources[1].end = gpio_to_irq(0);
 		platform_add_devices(innovator1610_devices, ARRAY_SIZE(innovator1610_devices));
 	}
 #endif
@@ -416,17 +416,15 @@
 #ifdef CONFIG_ARCH_OMAP15XX
 	if (cpu_is_omap1510()) {
 		omap1_usb_init(&innovator1510_usb_config);
-		innovator_config[0].data = &innovator1510_lcd_config;
+		omapfb_set_lcd_config(&innovator1510_lcd_config);
 	}
 #endif
 #ifdef CONFIG_ARCH_OMAP16XX
 	if (cpu_is_omap1610()) {
 		omap1_usb_init(&h2_usb_config);
-		innovator_config[0].data = &innovator1610_lcd_config;
+		omapfb_set_lcd_config(&innovator1610_lcd_config);
 	}
 #endif
-	omap_board_config = innovator_config;
-	omap_board_config_size = ARRAY_SIZE(innovator_config);
 	omap_serial_init();
 	omap_register_i2c_bus(1, 100, NULL, 0);
 	innovator_mmc_init();
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index f9efc03..d21dcc2 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -21,7 +21,6 @@
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -30,12 +29,14 @@
 #include <plat/usb.h>
 #include <plat/board.h>
 #include <plat/keypad.h>
-#include "common.h"
-#include <plat/hwa742.h>
 #include <plat/lcd_mipid.h>
 #include <plat/mmc.h>
 #include <plat/clock.h>
 
+#include <mach/hardware.h>
+
+#include "common.h"
+
 #define ADS7846_PENDOWN_GPIO	15
 
 static const unsigned int nokia770_keymap[] = {
@@ -99,15 +100,16 @@
 	.shutdown = mipid_shutdown,
 };
 
+static struct omap_lcd_config nokia770_lcd_config __initdata = {
+	.ctrl_name	= "hwa742",
+};
+
 static void __init mipid_dev_init(void)
 {
-	const struct omap_lcd_config *conf;
+	nokia770_mipid_platform_data.nreset_gpio = 13;
+	nokia770_mipid_platform_data.data_lines = 16;
 
-	conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
-	if (conf != NULL) {
-		nokia770_mipid_platform_data.nreset_gpio = conf->nreset_gpio;
-		nokia770_mipid_platform_data.data_lines = conf->data_lines;
-	}
+	omapfb_set_lcd_config(&nokia770_lcd_config);
 }
 
 static void __init ads7846_dev_init(void)
@@ -145,19 +147,13 @@
 		.bus_num        = 2,
 		.chip_select    = 0,
 		.max_speed_hz   = 2500000,
-		.irq		= OMAP_GPIO_IRQ(15),
 		.platform_data	= &nokia770_ads7846_platform_data,
 	},
 };
 
-static struct hwa742_platform_data nokia770_hwa742_platform_data = {
-	.te_connected		= 1,
-};
-
 static void __init hwa742_dev_init(void)
 {
 	clk_add_alias("hwa_sys_ck", NULL, "bclk", NULL);
-	omapfb_set_ctrl_platform_data(&nokia770_hwa742_platform_data);
 }
 
 /* assume no Mini-AB port */
@@ -240,6 +236,7 @@
 	omap_writew((omap_readw(0xfffb5004) & ~2), 0xfffb5004);
 
 	platform_add_devices(nokia770_devices, ARRAY_SIZE(nokia770_devices));
+	nokia770_spi_board_info[1].irq = gpio_to_irq(15);
 	spi_register_board_info(nokia770_spi_board_info,
 				ARRAY_SIZE(nokia770_spi_board_info));
 	omap_serial_init();
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index 675de06..a5f85dd 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -34,15 +34,12 @@
 #include <linux/i2c.h>
 #include <linux/leds.h>
 #include <linux/smc91x.h>
-
+#include <linux/omapfb.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
-
 #include <linux/i2c/tps65010.h>
 
-#include <mach/hardware.h>
-
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -51,6 +48,9 @@
 #include <plat/usb.h>
 #include <plat/mux.h>
 #include <plat/tc.h>
+
+#include <mach/hardware.h>
+
 #include "common.h"
 
 /* At OMAP5912 OSK the Ethernet is directly connected to CS1 */
@@ -129,8 +129,6 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= OMAP_GPIO_IRQ(0),
-		.end	= OMAP_GPIO_IRQ(0),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
 	},
 };
@@ -147,8 +145,6 @@
 
 static struct resource osk5912_cf_resources[] = {
 	[0] = {
-		.start	= OMAP_GPIO_IRQ(62),
-		.end	= OMAP_GPIO_IRQ(62),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -240,7 +236,6 @@
 static struct i2c_board_info __initdata osk_i2c_board_info[] = {
 	{
 		I2C_BOARD_INFO("tps65010", 0x48),
-		.irq		= OMAP_GPIO_IRQ(OMAP_MPUIO(1)),
 		.platform_data	= &tps_board,
 
 	},
@@ -300,12 +295,6 @@
 };
 #endif
 
-static struct omap_board_config_kernel osk_config[] __initdata = {
-#ifdef	CONFIG_OMAP_OSK_MISTRAL
-	{ OMAP_TAG_LCD,			&osk_lcd_config },
-#endif
-};
-
 #ifdef	CONFIG_OMAP_OSK_MISTRAL
 
 #include <linux/input.h>
@@ -414,7 +403,6 @@
 	/* MicroWire (bus 2) CS0 has an ads7846e */
 	.modalias		= "ads7846",
 	.platform_data		= &mistral_ts_info,
-	.irq			= OMAP_GPIO_IRQ(4),
 	.max_speed_hz		= 120000 /* max sample rate at 3V */
 					* 26 /* command + data + overhead */,
 	.bus_num		= 2,
@@ -477,6 +465,7 @@
 	gpio_direction_input(4);
 	irq_set_irq_type(gpio_to_irq(4), IRQ_TYPE_EDGE_FALLING);
 
+	mistral_boardinfo[0].irq = gpio_to_irq(4);
 	spi_register_board_info(mistral_boardinfo,
 			ARRAY_SIZE(mistral_boardinfo));
 
@@ -548,9 +537,11 @@
 
 	osk_flash_resource.end = osk_flash_resource.start = omap_cs3_phys();
 	osk_flash_resource.end += SZ_32M - 1;
+	osk5912_smc91x_resources[1].start = gpio_to_irq(0);
+	osk5912_smc91x_resources[1].end = gpio_to_irq(0);
+	osk5912_cf_resources[0].start = gpio_to_irq(62);
+	osk5912_cf_resources[0].end = gpio_to_irq(62);
 	platform_add_devices(osk5912_devices, ARRAY_SIZE(osk5912_devices));
-	omap_board_config = osk_config;
-	omap_board_config_size = ARRAY_SIZE(osk_config);
 
 	l = omap_readl(USB_TRANSCEIVER_CTRL);
 	l |= (3 << 1);
@@ -564,9 +555,15 @@
 		gpio_direction_input(OMAP_MPUIO(1));
 
 	omap_serial_init();
+	osk_i2c_board_info[0].irq = gpio_to_irq(OMAP_MPUIO(1));
 	omap_register_i2c_bus(1, 400, osk_i2c_board_info,
 			      ARRAY_SIZE(osk_i2c_board_info));
 	osk_mistral_init();
+
+#ifdef	CONFIG_OMAP_OSK_MISTRAL
+	omapfb_set_lcd_config(&osk_lcd_config);
+#endif
+
 }
 
 MACHINE_START(OMAP_OSK, "TI-OSK")
diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c
index 81fa27f..a60e6c2 100644
--- a/arch/arm/mach-omap1/board-palmte.c
+++ b/arch/arm/mach-omap1/board-palmte.c
@@ -27,8 +27,8 @@
 #include <linux/spi/spi.h>
 #include <linux/interrupt.h>
 #include <linux/apm-emulation.h>
+#include <linux/omapfb.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -41,6 +41,9 @@
 #include <plat/board.h>
 #include <plat/irda.h>
 #include <plat/keypad.h>
+
+#include <mach/hardware.h>
+
 #include "common.h"
 
 #define PALMTE_USBDETECT_GPIO	0
@@ -209,16 +212,11 @@
 	.ctrl_name	= "internal",
 };
 
-static struct omap_board_config_kernel palmte_config[] __initdata = {
-	{ OMAP_TAG_LCD,		&palmte_lcd_config },
-};
-
 static struct spi_board_info palmte_spi_info[] __initdata = {
 	{
 		.modalias	= "tsc2102",
 		.bus_num	= 2,	/* uWire (officially) */
 		.chip_select	= 0,	/* As opposed to 3 */
-		.irq		= OMAP_GPIO_IRQ(PALMTE_PINTDAV_GPIO),
 		.max_speed_hz	= 8000000,
 	},
 };
@@ -250,16 +248,16 @@
 	omap_cfg_reg(UART3_TX);
 	omap_cfg_reg(UART3_RX);
 
-	omap_board_config = palmte_config;
-	omap_board_config_size = ARRAY_SIZE(palmte_config);
-
 	platform_add_devices(palmte_devices, ARRAY_SIZE(palmte_devices));
 
+	palmte_spi_info[0].irq = gpio_to_irq(PALMTE_PINTDAV_GPIO);
 	spi_register_board_info(palmte_spi_info, ARRAY_SIZE(palmte_spi_info));
 	palmte_misc_gpio_setup();
 	omap_serial_init();
 	omap1_usb_init(&palmte_usb_config);
 	omap_register_i2c_bus(1, 100, NULL, 0);
+
+	omapfb_set_lcd_config(&palmte_lcd_config);
 }
 
 MACHINE_START(OMAP_PALMTE, "OMAP310 based Palm Tungsten E")
diff --git a/arch/arm/mach-omap1/board-palmtt.c b/arch/arm/mach-omap1/board-palmtt.c
index 81cb821..8d85487 100644
--- a/arch/arm/mach-omap1/board-palmtt.c
+++ b/arch/arm/mach-omap1/board-palmtt.c
@@ -24,8 +24,10 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/leds.h>
+#include <linux/omapfb.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -39,10 +41,10 @@
 #include <plat/board.h>
 #include <plat/irda.h>
 #include <plat/keypad.h>
-#include "common.h"
 
-#include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
+#include <mach/hardware.h>
+
+#include "common.h"
 
 #define PALMTT_USBDETECT_GPIO	0
 #define PALMTT_CABLE_GPIO	1
@@ -255,7 +257,6 @@
 		/* MicroWire (bus 2) CS0 has an ads7846e */
 		.modalias	= "ads7846",
 		.platform_data	= &palmtt_ts_info,
-		.irq		= OMAP_GPIO_IRQ(6),
 		.max_speed_hz	= 120000	/* max sample rate at 3V */
 					* 26	/* command + data + overhead */,
 		.bus_num	= 2,
@@ -273,10 +274,6 @@
 	.ctrl_name	= "internal",
 };
 
-static struct omap_board_config_kernel palmtt_config[] __initdata = {
-	{ OMAP_TAG_LCD,		&palmtt_lcd_config	},
-};
-
 static void __init omap_mpu_wdt_mode(int mode) {
 	if (mode)
 		omap_writew(0x8000, OMAP_WDT_TIMER_MODE);
@@ -298,15 +295,15 @@
 
 	omap_mpu_wdt_mode(0);
 
-	omap_board_config = palmtt_config;
-	omap_board_config_size = ARRAY_SIZE(palmtt_config);
-
 	platform_add_devices(palmtt_devices, ARRAY_SIZE(palmtt_devices));
 
+	palmtt_boardinfo[0].irq = gpio_to_irq(6);
 	spi_register_board_info(palmtt_boardinfo,ARRAY_SIZE(palmtt_boardinfo));
 	omap_serial_init();
 	omap1_usb_init(&palmtt_usb_config);
 	omap_register_i2c_bus(1, 100, NULL, 0);
+
+	omapfb_set_lcd_config(&palmtt_lcd_config);
 }
 
 MACHINE_START(OMAP_PALMTT, "OMAP1510 based Palm Tungsten|T")
diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c
index e881945..a2c5abc 100644
--- a/arch/arm/mach-omap1/board-palmz71.c
+++ b/arch/arm/mach-omap1/board-palmz71.c
@@ -27,8 +27,10 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
+#include <linux/omapfb.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -41,10 +43,10 @@
 #include <plat/board.h>
 #include <plat/irda.h>
 #include <plat/keypad.h>
-#include "common.h"
 
-#include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
+#include <mach/hardware.h>
+
+#include "common.h"
 
 #define PALMZ71_USBDETECT_GPIO	0
 #define PALMZ71_PENIRQ_GPIO	6
@@ -222,7 +224,6 @@
 	/* MicroWire (bus 2) CS0 has an ads7846e */
 	.modalias	= "ads7846",
 	.platform_data	= &palmz71_ts_info,
-	.irq		= OMAP_GPIO_IRQ(PALMZ71_PENIRQ_GPIO),
 	.max_speed_hz	= 120000	/* max sample rate at 3V */
 				* 26	/* command + data + overhead */,
 	.bus_num	= 2,
@@ -239,10 +240,6 @@
 	.ctrl_name = "internal",
 };
 
-static struct omap_board_config_kernel palmz71_config[] __initdata = {
-	{OMAP_TAG_LCD,	&palmz71_lcd_config},
-};
-
 static irqreturn_t
 palmz71_powercable(int irq, void *dev_id)
 {
@@ -313,17 +310,17 @@
 	palmz71_gpio_setup(1);
 	omap_mpu_wdt_mode(0);
 
-	omap_board_config = palmz71_config;
-	omap_board_config_size = ARRAY_SIZE(palmz71_config);
-
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 
+	palmz71_boardinfo[0].irq = gpio_to_irq(PALMZ71_PENIRQ_GPIO);
 	spi_register_board_info(palmz71_boardinfo,
 				ARRAY_SIZE(palmz71_boardinfo));
 	omap1_usb_init(&palmz71_usb_config);
 	omap_serial_init();
 	omap_register_i2c_bus(1, 100, NULL, 0);
 	palmz71_gpio_setup(0);
+
+	omapfb_set_lcd_config(&palmz71_lcd_config);
 }
 
 MACHINE_START(OMAP_PALMZ71, "OMAP310 based Palm Zire71")
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index c000bed..76d4ee0 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -21,8 +21,8 @@
 #include <linux/mtd/physmap.h>
 #include <linux/input.h>
 #include <linux/smc91x.h>
+#include <linux/omapfb.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -32,9 +32,13 @@
 #include <plat/fpga.h>
 #include <plat/flash.h>
 #include <plat/keypad.h>
-#include "common.h"
 #include <plat/board.h>
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
+#include "common.h"
+
 static const unsigned int p2_keymap[] = {
 	KEY(0, 0, KEY_UP),
 	KEY(1, 0, KEY_RIGHT),
@@ -232,27 +236,17 @@
 	.resource	= kp_resources,
 };
 
-static struct platform_device lcd_device = {
-	.name		= "lcd_p2",
-	.id		= -1,
-};
-
 static struct platform_device *devices[] __initdata = {
 	&nor_device,
 	&nand_device,
 	&smc91x_device,
 	&kp_device,
-	&lcd_device,
 };
 
 static struct omap_lcd_config perseus2_lcd_config __initdata = {
 	.ctrl_name	= "internal",
 };
 
-static struct omap_board_config_kernel perseus2_config[] __initdata = {
-	{ OMAP_TAG_LCD,		&perseus2_lcd_config },
-};
-
 static void __init perseus2_init_smc91x(void)
 {
 	fpga_write(1, H2P2_DBG_FPGA_LAN_RESET);
@@ -320,10 +314,10 @@
 
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 
-	omap_board_config = perseus2_config;
-	omap_board_config_size = ARRAY_SIZE(perseus2_config);
 	omap_serial_init();
 	omap_register_i2c_bus(1, 100, NULL, 0);
+
+	omapfb_set_lcd_config(&perseus2_lcd_config);
 }
 
 /* Only FPGA needs to be mapped here. All others are done with ioremap */
diff --git a/arch/arm/mach-omap1/board-sx1.c b/arch/arm/mach-omap1/board-sx1.c
index 7bcd82a..f34cb74 100644
--- a/arch/arm/mach-omap1/board-sx1.c
+++ b/arch/arm/mach-omap1/board-sx1.c
@@ -27,8 +27,8 @@
 #include <linux/i2c.h>
 #include <linux/errno.h>
 #include <linux/export.h>
+#include <linux/omapfb.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -40,10 +40,13 @@
 #include <plat/usb.h>
 #include <plat/tc.h>
 #include <plat/board.h>
-#include "common.h"
 #include <plat/keypad.h>
 #include <plat/board-sx1.h>
 
+#include <mach/hardware.h>
+
+#include "common.h"
+
 /* Write to I2C device */
 int sx1_i2c_write_byte(u8 devaddr, u8 regoffset, u8 value)
 {
@@ -355,11 +358,6 @@
 
 /*----------- LCD -------------------------*/
 
-static struct platform_device sx1_lcd_device = {
-	.name		= "lcd_sx1",
-	.id		= -1,
-};
-
 static struct omap_lcd_config sx1_lcd_config __initdata = {
 	.ctrl_name	= "internal",
 };
@@ -368,14 +366,8 @@
 static struct platform_device *sx1_devices[] __initdata = {
 	&sx1_flash_device,
 	&sx1_kp_device,
-	&sx1_lcd_device,
 	&sx1_irda_device,
 };
-/*-----------------------------------------*/
-
-static struct omap_board_config_kernel sx1_config[] __initdata = {
-	{ OMAP_TAG_LCD,	&sx1_lcd_config },
-};
 
 /*-----------------------------------------*/
 
@@ -391,8 +383,6 @@
 
 	platform_add_devices(sx1_devices, ARRAY_SIZE(sx1_devices));
 
-	omap_board_config = sx1_config;
-	omap_board_config_size = ARRAY_SIZE(sx1_config);
 	omap_serial_init();
 	omap_register_i2c_bus(1, 100, NULL, 0);
 	omap1_usb_init(&sx1_usb_config);
@@ -406,6 +396,8 @@
 	gpio_direction_output(1, 1);	/*A_IRDA_OFF = 1 */
 	gpio_direction_output(11, 0);	/*A_SWITCH = 0 */
 	gpio_direction_output(15, 0);	/*A_USB_ON = 0 */
+
+	omapfb_set_lcd_config(&sx1_lcd_config);
 }
 
 MACHINE_START(SX1, "OMAP310 based Siemens SX1")
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index f83a502d..37232d0 100644
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -27,22 +27,23 @@
 #include <linux/smc91x.h>
 #include <linux/export.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
 #include <plat/board-voiceblue.h>
-#include "common.h"
 #include <plat/flash.h>
 #include <plat/mux.h>
 #include <plat/tc.h>
 #include <plat/usb.h>
 
+#include <mach/hardware.h>
+
+#include "common.h"
+
 static struct plat_serial8250_port voiceblue_ports[] = {
 	{
 		.mapbase	= (unsigned long)(OMAP_CS1_PHYS + 0x40000),
-		.irq		= OMAP_GPIO_IRQ(12),
 		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
 		.iotype		= UPIO_MEM,
 		.regshift	= 1,
@@ -50,7 +51,6 @@
 	},
 	{
 		.mapbase	= (unsigned long)(OMAP_CS1_PHYS + 0x50000),
-		.irq		= OMAP_GPIO_IRQ(13),
 		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
 		.iotype		= UPIO_MEM,
 		.regshift	= 1,
@@ -58,7 +58,6 @@
 	},
 	{
 		.mapbase	= (unsigned long)(OMAP_CS1_PHYS + 0x60000),
-		.irq		= OMAP_GPIO_IRQ(14),
 		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
 		.iotype		= UPIO_MEM,
 		.regshift	= 1,
@@ -66,7 +65,6 @@
 	},
 	{
 		.mapbase	= (unsigned long)(OMAP_CS1_PHYS + 0x70000),
-		.irq		= OMAP_GPIO_IRQ(15),
 		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
 		.iotype		= UPIO_MEM,
 		.regshift	= 1,
@@ -78,9 +76,6 @@
 static struct platform_device serial_device = {
 	.name			= "serial8250",
 	.id			= PLAT8250_DEV_PLATFORM1,
-	.dev			= {
-		.platform_data	= voiceblue_ports,
-	},
 };
 
 static int __init ext_uart_init(void)
@@ -88,6 +83,11 @@
 	if (!machine_is_voiceblue())
 		return -ENODEV;
 
+	voiceblue_ports[0].irq = gpio_to_irq(12);
+	voiceblue_ports[1].irq = gpio_to_irq(13);
+	voiceblue_ports[2].irq = gpio_to_irq(14);
+	voiceblue_ports[3].irq = gpio_to_irq(15);
+	serial_device.dev.platform_data = voiceblue_ports;
 	return platform_device_register(&serial_device);
 }
 arch_initcall(ext_uart_init);
@@ -126,8 +126,6 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= OMAP_GPIO_IRQ(8),
-		.end	= OMAP_GPIO_IRQ(8),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
 	},
 };
@@ -273,6 +271,8 @@
 	irq_set_irq_type(gpio_to_irq(14), IRQ_TYPE_EDGE_RISING);
 	irq_set_irq_type(gpio_to_irq(15), IRQ_TYPE_EDGE_RISING);
 
+	voiceblue_smc91x_resources[1].start = gpio_to_irq(8);
+	voiceblue_smc91x_resources[1].end = gpio_to_irq(8);
 	platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices));
 	omap_board_config = voiceblue_config;
 	omap_board_config_size = ARRAY_SIZE(voiceblue_config);
diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
index 0c50df0..67382dd 100644
--- a/arch/arm/mach-omap1/clock.c
+++ b/arch/arm/mach-omap1/clock.c
@@ -15,8 +15,8 @@
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/err.h>
-#include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/clk.h>
 #include <linux/clkdev.h>
 
 #include <asm/mach-types.h>
@@ -27,6 +27,9 @@
 #include <plat/sram.h>
 #include <plat/clkdev_omap.h>
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
 #include "clock.h"
 #include "opp.h"
 
diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c
index 94699a8..c6ce93f 100644
--- a/arch/arm/mach-omap1/clock_data.c
+++ b/arch/arm/mach-omap1/clock_data.c
@@ -15,10 +15,10 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/cpufreq.h>
 #include <linux/delay.h>
-#include <linux/io.h>
 
 #include <asm/mach-types.h>  /* for machine_is_* */
 
@@ -28,6 +28,9 @@
 #include <plat/sram.h>	/* for omap_sram_reprogram_clock() */
 #include <plat/usb.h>   /* for OTG_BASE */
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
 #include "clock.h"
 
 /* Some ARM_IDLECT1 bit shifts - used in struct arm_idlect1_clk */
diff --git a/arch/arm/mach-omap1/common.h b/arch/arm/mach-omap1/common.h
index a9a5146..af658ad 100644
--- a/arch/arm/mach-omap1/common.h
+++ b/arch/arm/mach-omap1/common.h
@@ -58,5 +58,6 @@
 
 extern struct sys_timer omap1_timer;
 extern bool omap_32k_timer_init(void);
+extern void __init omap_init_consistent_dma_size(void);
 
 #endif /* __ARCH_ARM_MACH_OMAP1_COMMON_H */
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index 1d76a63..dcd8ddb 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -15,21 +15,20 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/io.h>
 #include <linux/spi/spi.h>
 
-#include <mach/camera.h>
-#include <mach/hardware.h>
 #include <asm/mach/map.h>
 
-#include "common.h"
 #include <plat/tc.h>
 #include <plat/board.h>
 #include <plat/mux.h>
 #include <plat/mmc.h>
 #include <plat/omap7xx.h>
-#include <plat/mcbsp.h>
 
+#include <mach/camera.h>
+#include <mach/hardware.h>
+
+#include "common.h"
 #include "clock.h"
 
 /*-------------------------------------------------------------------------*/
@@ -250,16 +249,8 @@
 	.id	= -1,
 };
 
-OMAP_MCBSP_PLATFORM_DEVICE(1);
-OMAP_MCBSP_PLATFORM_DEVICE(2);
-OMAP_MCBSP_PLATFORM_DEVICE(3);
-
 static void omap_init_audio(void)
 {
-	platform_device_register(&omap_mcbsp1);
-	platform_device_register(&omap_mcbsp2);
-	if (!cpu_is_omap7xx())
-		platform_device_register(&omap_mcbsp3);
 	platform_device_register(&omap_pcm);
 }
 
diff --git a/arch/arm/mach-omap1/dma.c b/arch/arm/mach-omap1/dma.c
index f5a5220..3ef7d52 100644
--- a/arch/arm/mach-omap1/dma.c
+++ b/arch/arm/mach-omap1/dma.c
@@ -19,11 +19,11 @@
  */
 
 #include <linux/err.h>
-#include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/io.h>
 
 #include <plat/dma.h>
 #include <plat/tc.h>
diff --git a/arch/arm/mach-omap1/flash.c b/arch/arm/mach-omap1/flash.c
index 1749cb3..401eb3c 100644
--- a/arch/arm/mach-omap1/flash.c
+++ b/arch/arm/mach-omap1/flash.c
@@ -6,29 +6,23 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 
-#include <plat/io.h>
 #include <plat/tc.h>
 #include <plat/flash.h>
 
+#include <mach/hardware.h>
+
 void omap1_set_vpp(struct platform_device *pdev, int enable)
 {
-	static int count;
 	u32 l;
 
-	if (enable) {
-		if (count++ == 0) {
-			l = omap_readl(EMIFS_CONFIG);
-			l |= OMAP_EMIFS_CONFIG_WP;
-			omap_writel(l, EMIFS_CONFIG);
-		}
-	} else {
-		if (count && (--count == 0)) {
-			l = omap_readl(EMIFS_CONFIG);
-			l &= ~OMAP_EMIFS_CONFIG_WP;
-			omap_writel(l, EMIFS_CONFIG);
-		}
-	}
+	l = omap_readl(EMIFS_CONFIG);
+	if (enable)
+		l |= OMAP_EMIFS_CONFIG_WP;
+	else
+		l &= ~OMAP_EMIFS_CONFIG_WP;
+	omap_writel(l, EMIFS_CONFIG);
 }
diff --git a/arch/arm/mach-omap1/fpga.c b/arch/arm/mach-omap1/fpga.c
index 0a17a1a..76c67b3 100644
--- a/arch/arm/mach-omap1/fpga.c
+++ b/arch/arm/mach-omap1/fpga.c
@@ -24,12 +24,15 @@
 #include <linux/errno.h>
 #include <linux/io.h>
 
-#include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 
 #include <plat/fpga.h>
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
+
 static void fpga_mask_irq(struct irq_data *d)
 {
 	unsigned int irq = d->irq - OMAP_FPGA_IRQ_BASE;
diff --git a/arch/arm/mach-omap1/gpio15xx.c b/arch/arm/mach-omap1/gpio15xx.c
index 399da4c..634903e 100644
--- a/arch/arm/mach-omap1/gpio15xx.c
+++ b/arch/arm/mach-omap1/gpio15xx.c
@@ -42,11 +42,12 @@
 	.irqstatus	= OMAP_MPUIO_GPIO_INT,
 	.irqenable	= OMAP_MPUIO_GPIO_MASKIT,
 	.irqenable_inv	= true,
+	.irqctrl	= OMAP_MPUIO_GPIO_INT_EDGE,
 };
 
 static struct __initdata omap_gpio_platform_data omap15xx_mpu_gpio_config = {
 	.virtual_irq_start	= IH_MPUIO_BASE,
-	.bank_type		= METHOD_MPUIO,
+	.is_mpuio		= true,
 	.bank_width		= 16,
 	.bank_stride		= 1,
 	.regs			= &omap15xx_mpuio_regs,
@@ -83,11 +84,12 @@
 	.irqstatus	= OMAP1510_GPIO_INT_STATUS,
 	.irqenable	= OMAP1510_GPIO_INT_MASK,
 	.irqenable_inv	= true,
+	.irqctrl	= OMAP1510_GPIO_INT_CONTROL,
+	.pinctrl	= OMAP1510_GPIO_PIN_CONTROL,
 };
 
 static struct __initdata omap_gpio_platform_data omap15xx_gpio_config = {
 	.virtual_irq_start	= IH_GPIO_BASE,
-	.bank_type		= METHOD_GPIO_1510,
 	.bank_width		= 16,
 	.regs                   = &omap15xx_gpio_regs,
 };
@@ -115,7 +117,6 @@
 	platform_device_register(&omap15xx_mpu_gpio);
 	platform_device_register(&omap15xx_gpio);
 
-	gpio_bank_count = 2;
 	return 0;
 }
 postcore_initcall(omap15xx_gpio_init);
diff --git a/arch/arm/mach-omap1/gpio16xx.c b/arch/arm/mach-omap1/gpio16xx.c
index 0f399bd..1fb3b9a 100644
--- a/arch/arm/mach-omap1/gpio16xx.c
+++ b/arch/arm/mach-omap1/gpio16xx.c
@@ -24,6 +24,9 @@
 #define OMAP1610_GPIO4_BASE		0xfffbbc00
 #define OMAP1_MPUIO_VBASE		OMAP1_MPUIO_BASE
 
+/* smart idle, enable wakeup */
+#define SYSCONFIG_WORD			0x14
+
 /* mpu gpio */
 static struct __initdata resource omap16xx_mpu_gpio_resources[] = {
 	{
@@ -45,11 +48,12 @@
 	.irqstatus	= OMAP_MPUIO_GPIO_INT,
 	.irqenable	= OMAP_MPUIO_GPIO_MASKIT,
 	.irqenable_inv	= true,
+	.irqctrl	= OMAP_MPUIO_GPIO_INT_EDGE,
 };
 
 static struct __initdata omap_gpio_platform_data omap16xx_mpu_gpio_config = {
 	.virtual_irq_start	= IH_MPUIO_BASE,
-	.bank_type		= METHOD_MPUIO,
+	.is_mpuio		= true,
 	.bank_width		= 16,
 	.bank_stride		= 1,
 	.regs                   = &omap16xx_mpuio_regs,
@@ -89,11 +93,13 @@
 	.irqenable	= OMAP1610_GPIO_IRQENABLE1,
 	.set_irqenable	= OMAP1610_GPIO_SET_IRQENABLE1,
 	.clr_irqenable	= OMAP1610_GPIO_CLEAR_IRQENABLE1,
+	.wkup_en	= OMAP1610_GPIO_WAKEUPENABLE,
+	.edgectrl1	= OMAP1610_GPIO_EDGE_CTRL1,
+	.edgectrl2	= OMAP1610_GPIO_EDGE_CTRL2,
 };
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio1_config = {
 	.virtual_irq_start	= IH_GPIO_BASE,
-	.bank_type		= METHOD_GPIO_1610,
 	.bank_width		= 16,
 	.regs                   = &omap16xx_gpio_regs,
 };
@@ -123,7 +129,6 @@
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio2_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 16,
-	.bank_type		= METHOD_GPIO_1610,
 	.bank_width		= 16,
 	.regs                   = &omap16xx_gpio_regs,
 };
@@ -153,7 +158,6 @@
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio3_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 32,
-	.bank_type		= METHOD_GPIO_1610,
 	.bank_width		= 16,
 	.regs                   = &omap16xx_gpio_regs,
 };
@@ -183,7 +187,6 @@
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio4_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 48,
-	.bank_type		= METHOD_GPIO_1610,
 	.bank_width		= 16,
 	.regs                   = &omap16xx_gpio_regs,
 };
@@ -214,14 +217,42 @@
 static int __init omap16xx_gpio_init(void)
 {
 	int i;
+	void __iomem *base;
+	struct resource *res;
+	struct platform_device *pdev;
+	struct omap_gpio_platform_data *pdata;
 
 	if (!cpu_is_omap16xx())
 		return -EINVAL;
 
-	for (i = 0; i < ARRAY_SIZE(omap16xx_gpio_dev); i++)
-		platform_device_register(omap16xx_gpio_dev[i]);
+	/*
+	 * Enable system clock for GPIO module.
+	 * The CAM_CLK_CTRL *is* really the right place.
+	 */
+	omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04,
+					ULPD_CAM_CLK_CTRL);
 
-	gpio_bank_count = ARRAY_SIZE(omap16xx_gpio_dev);
+	for (i = 0; i < ARRAY_SIZE(omap16xx_gpio_dev); i++) {
+		pdev = omap16xx_gpio_dev[i];
+		pdata = pdev->dev.platform_data;
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (unlikely(!res)) {
+			dev_err(&pdev->dev, "Invalid mem resource.\n");
+			return -ENODEV;
+		}
+
+		base = ioremap(res->start, resource_size(res));
+		if (unlikely(!base)) {
+			dev_err(&pdev->dev, "ioremap failed.\n");
+			return -ENOMEM;
+		}
+
+		__raw_writel(SYSCONFIG_WORD, base + OMAP1610_GPIO_SYSCONFIG);
+		iounmap(base);
+
+		platform_device_register(omap16xx_gpio_dev[i]);
+	}
 
 	return 0;
 }
diff --git a/arch/arm/mach-omap1/gpio7xx.c b/arch/arm/mach-omap1/gpio7xx.c
index 5ab63ea..4771d6b 100644
--- a/arch/arm/mach-omap1/gpio7xx.c
+++ b/arch/arm/mach-omap1/gpio7xx.c
@@ -47,12 +47,13 @@
 	.irqstatus	= OMAP_MPUIO_GPIO_INT / 2,
 	.irqenable	= OMAP_MPUIO_GPIO_MASKIT / 2,
 	.irqenable_inv	= true,
+	.irqctrl	= OMAP_MPUIO_GPIO_INT_EDGE >> 1,
 };
 
 static struct __initdata omap_gpio_platform_data omap7xx_mpu_gpio_config = {
 	.virtual_irq_start	= IH_MPUIO_BASE,
-	.bank_type		= METHOD_MPUIO,
-	.bank_width		= 32,
+	.is_mpuio		= true,
+	.bank_width		= 16,
 	.bank_stride		= 2,
 	.regs                   = &omap7xx_mpuio_regs,
 };
@@ -88,11 +89,11 @@
 	.irqstatus	= OMAP7XX_GPIO_INT_STATUS,
 	.irqenable	= OMAP7XX_GPIO_INT_MASK,
 	.irqenable_inv	= true,
+	.irqctrl	= OMAP7XX_GPIO_INT_CONTROL,
 };
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio1_config = {
 	.virtual_irq_start	= IH_GPIO_BASE,
-	.bank_type		= METHOD_GPIO_7XX,
 	.bank_width		= 32,
 	.regs			= &omap7xx_gpio_regs,
 };
@@ -122,7 +123,6 @@
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio2_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 32,
-	.bank_type		= METHOD_GPIO_7XX,
 	.bank_width		= 32,
 	.regs			= &omap7xx_gpio_regs,
 };
@@ -152,7 +152,6 @@
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio3_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 64,
-	.bank_type		= METHOD_GPIO_7XX,
 	.bank_width		= 32,
 	.regs			= &omap7xx_gpio_regs,
 };
@@ -182,7 +181,6 @@
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio4_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 96,
-	.bank_type		= METHOD_GPIO_7XX,
 	.bank_width		= 32,
 	.regs			= &omap7xx_gpio_regs,
 };
@@ -212,7 +210,6 @@
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio5_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 128,
-	.bank_type		= METHOD_GPIO_7XX,
 	.bank_width		= 32,
 	.regs			= &omap7xx_gpio_regs,
 };
@@ -242,7 +239,6 @@
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio6_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 160,
-	.bank_type		= METHOD_GPIO_7XX,
 	.bank_width		= 32,
 	.regs			= &omap7xx_gpio_regs,
 };
@@ -282,8 +278,6 @@
 	for (i = 0; i < ARRAY_SIZE(omap7xx_gpio_dev); i++)
 		platform_device_register(omap7xx_gpio_dev[i]);
 
-	gpio_bank_count = ARRAY_SIZE(omap7xx_gpio_dev);
-
 	return 0;
 }
 postcore_initcall(omap7xx_gpio_init);
diff --git a/arch/arm/mach-omap1/id.c b/arch/arm/mach-omap1/id.c
index a0e3560..2b28e1d 100644
--- a/arch/arm/mach-omap1/id.c
+++ b/arch/arm/mach-omap1/id.c
@@ -15,8 +15,12 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <asm/system_info.h>
+
 #include <plat/cpu.h>
 
+#include <mach/hardware.h>
+
 #define OMAP_DIE_ID_0		0xfffe1800
 #define OMAP_DIE_ID_1		0xfffe1804
 #define OMAP_PRODUCTION_ID_0	0xfffe2000
diff --git a/arch/arm/mach-omap1/include/mach/entry-macro.S b/arch/arm/mach-omap1/include/mach/entry-macro.S
index bfb4fb1..88f08ca 100644
--- a/arch/arm/mach-omap1/include/mach/entry-macro.S
+++ b/arch/arm/mach-omap1/include/mach/entry-macro.S
@@ -9,20 +9,15 @@
  * License version 2. This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
  */
-#include <mach/hardware.h>
-#include <mach/io.h>
-#include <mach/irqs.h>
-#include <asm/hardware/gic.h>
 
- 		.macro	disable_fiq
-		.endm
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
+#include "../../iomap.h"
 
 		.macro  get_irqnr_preamble, base, tmp
 		.endm
 
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
-
 		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 		ldr	\base, =OMAP1_IO_ADDRESS(OMAP_IH1_BASE)
 		ldr	\irqnr, [\base, #IRQ_ITR_REG_OFFSET]
diff --git a/arch/arm/mach-omap1/include/mach/hardware.h b/arch/arm/mach-omap1/include/mach/hardware.h
index a3f6287..01e35fa 100644
--- a/arch/arm/mach-omap1/include/mach/hardware.h
+++ b/arch/arm/mach-omap1/include/mach/hardware.h
@@ -2,4 +2,40 @@
  * arch/arm/mach-omap1/include/mach/hardware.h
  */
 
+#ifndef __MACH_HARDWARE_H
+#define __MACH_HARDWARE_H
+
+#ifndef __ASSEMBLER__
+/*
+ * NOTE: Please use ioremap + __raw_read/write where possible instead of these
+ */
+extern u8 omap_readb(u32 pa);
+extern u16 omap_readw(u32 pa);
+extern u32 omap_readl(u32 pa);
+extern void omap_writeb(u8 v, u32 pa);
+extern void omap_writew(u16 v, u32 pa);
+extern void omap_writel(u32 v, u32 pa);
+
+#include <plat/tc.h>
+
+/* Almost all documentation for chip and board memory maps assumes
+ * BM is clear.  Most devel boards have a switch to control booting
+ * from NOR flash (using external chipselect 3) rather than mask ROM,
+ * which uses BM to interchange the physical CS0 and CS3 addresses.
+ */
+static inline u32 omap_cs0m_phys(void)
+{
+	return (omap_readl(EMIFS_CONFIG) & OMAP_EMIFS_CONFIG_BM)
+			?  OMAP_CS3_PHYS : 0;
+}
+
+static inline u32 omap_cs3_phys(void)
+{
+	return (omap_readl(EMIFS_CONFIG) & OMAP_EMIFS_CONFIG_BM)
+			? 0 : OMAP_CS3_PHYS;
+}
+
+#endif
+#endif
+
 #include <plat/hardware.h>
diff --git a/arch/arm/mach-omap1/include/mach/io.h b/arch/arm/mach-omap1/include/mach/io.h
index 57bdf74..ce4f800 100644
--- a/arch/arm/mach-omap1/include/mach/io.h
+++ b/arch/arm/mach-omap1/include/mach/io.h
@@ -1,5 +1,45 @@
 /*
  * arch/arm/mach-omap1/include/mach/io.h
+ *
+ * IO definitions for TI OMAP processors and boards
+ *
+ * Copied from arch/arm/mach-sa1100/include/mach/io.h
+ * Copyright (C) 1997-1999 Russell King
+ *
+ * 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 SOFTWARE IS PROVIDED ``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 AUTHOR 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, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Modifications:
+ *  06-12-1997	RMK	Created.
+ *  07-04-1999	RMK	Major cleanup
  */
 
-#include <plat/io.h>
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*
+ * We don't actually have real ISA nor PCI buses, but there is so many
+ * drivers out there that might just work if we fake them...
+ */
+#define __io(a)		__typesafe_io(a)
+
+#endif
diff --git a/arch/arm/mach-omap1/include/mach/memory.h b/arch/arm/mach-omap1/include/mach/memory.h
index c633764..901082d 100644
--- a/arch/arm/mach-omap1/include/mach/memory.h
+++ b/arch/arm/mach-omap1/include/mach/memory.h
@@ -18,7 +18,8 @@
  * Note that the is_lbus_device() test is not very efficient on 1510
  * because of the strncmp().
  */
-#ifdef CONFIG_ARCH_OMAP15XX
+#if defined(CONFIG_ARCH_OMAP15XX) && !defined(__ASSEMBLER__)
+#include <plat/cpu.h>
 
 /*
  * OMAP-1510 Local Bus address offset
diff --git a/arch/arm/mach-omap1/include/mach/system.h b/arch/arm/mach-omap1/include/mach/system.h
deleted file mode 100644
index a6c1b3a..0000000
--- a/arch/arm/mach-omap1/include/mach/system.h
+++ /dev/null
@@ -1,5 +0,0 @@
-/*
- * arch/arm/mach-omap1/include/mach/system.h
- */
-
-#include <plat/system.h>
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
index 8e55b6f..d969a72 100644
--- a/arch/arm/mach-omap1/io.c
+++ b/arch/arm/mach-omap1/io.c
@@ -15,9 +15,12 @@
 
 #include <asm/tlb.h>
 #include <asm/mach/map.h>
+
 #include <plat/mux.h>
 #include <plat/tc.h>
 
+#include "iomap.h"
+#include "common.h"
 #include "clock.h"
 
 extern void omap_check_revision(void);
@@ -118,7 +121,7 @@
 /*
  * Common low-level hardware init for omap1.
  */
-void omap1_init_early(void)
+void __init omap1_init_early(void)
 {
 	omap_check_revision();
 
diff --git a/arch/arm/mach-omap1/iomap.h b/arch/arm/mach-omap1/iomap.h
new file mode 100644
index 0000000..330c471
--- /dev/null
+++ b/arch/arm/mach-omap1/iomap.h
@@ -0,0 +1,36 @@
+/*
+ * IO mappings for OMAP1
+ *
+ * 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 SOFTWARE IS PROVIDED ``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 AUTHOR 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, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define OMAP1_IO_OFFSET		0x01000000	/* Virtual IO = 0xfefb0000 */
+#define OMAP1_IO_ADDRESS(pa)	IOMEM((pa) - OMAP1_IO_OFFSET)
+
+/*
+ * ----------------------------------------------------------------------------
+ * Omap1 specific IO mapping
+ * ----------------------------------------------------------------------------
+ */
+
+#define OMAP1_IO_PHYS		0xFFFB0000
+#define OMAP1_IO_SIZE		0x40000
+#define OMAP1_IO_VIRT		(OMAP1_IO_PHYS - OMAP1_IO_OFFSET)
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
index e5b104b..4448114 100644
--- a/arch/arm/mach-omap1/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -42,11 +42,13 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 
-#include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
+
 #include <plat/cpu.h>
 
+#include <mach/hardware.h>
+
 #define IRQ_BANK(irq) ((irq) >> 5)
 #define IRQ_BIT(irq)  ((irq) & 0x1f)
 
diff --git a/arch/arm/mach-omap1/lcd_dma.c b/arch/arm/mach-omap1/lcd_dma.c
index 4c5ce7d..86ace9a 100644
--- a/arch/arm/mach-omap1/lcd_dma.c
+++ b/arch/arm/mach-omap1/lcd_dma.c
@@ -27,9 +27,10 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 
+#include <plat/dma.h>
+
 #include <mach/hardware.h>
 #include <mach/lcdc.h>
-#include <plat/dma.h>
 
 int omap_lcd_dma_running(void)
 {
diff --git a/arch/arm/mach-omap1/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c
index 4b818eb..f6b14a1 100644
--- a/arch/arm/mach-omap1/leds-h2p2-debug.c
+++ b/arch/arm/mach-omap1/leds-h2p2-debug.c
@@ -17,7 +17,6 @@
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
-#include <asm/system.h>
 #include <asm/mach-types.h>
 
 #include <plat/fpga.h>
diff --git a/arch/arm/mach-omap1/leds-innovator.c b/arch/arm/mach-omap1/leds-innovator.c
index 9b99c28..3a066ee 100644
--- a/arch/arm/mach-omap1/leds-innovator.c
+++ b/arch/arm/mach-omap1/leds-innovator.c
@@ -5,7 +5,6 @@
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
-#include <asm/system.h>
 
 #include "leds.h"
 
diff --git a/arch/arm/mach-omap1/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c
index da09f43..936ed42 100644
--- a/arch/arm/mach-omap1/leds-osk.c
+++ b/arch/arm/mach-omap1/leds-osk.c
@@ -8,7 +8,6 @@
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
-#include <asm/system.h>
 
 #include "leds.h"
 
diff --git a/arch/arm/mach-omap1/mcbsp.c b/arch/arm/mach-omap1/mcbsp.c
index 91f9abb..adf0097 100644
--- a/arch/arm/mach-omap1/mcbsp.c
+++ b/arch/arm/mach-omap1/mcbsp.c
@@ -19,12 +19,15 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
-#include <mach/irqs.h>
 #include <plat/dma.h>
 #include <plat/mux.h>
 #include <plat/cpu.h>
 #include <plat/mcbsp.h>
 
+#include <mach/irqs.h>
+
+#include "iomap.h"
+
 #define DPS_RSTCT2_PER_EN	(1 << 0)
 #define DSP_RSTCT2_WD_PER_EN	(1 << 1)
 
@@ -420,18 +423,6 @@
 		return -ENODEV;
 
 	if (cpu_is_omap7xx())
-		omap_mcbsp_count = OMAP7XX_MCBSP_COUNT;
-	else if (cpu_is_omap15xx())
-		omap_mcbsp_count = OMAP15XX_MCBSP_COUNT;
-	else if (cpu_is_omap16xx())
-		omap_mcbsp_count = OMAP16XX_MCBSP_COUNT;
-
-	mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *),
-								GFP_KERNEL);
-	if (!mcbsp_ptr)
-		return -ENOMEM;
-
-	if (cpu_is_omap7xx())
 		omap_mcbsp_register_board_cfg(omap7xx_mcbsp_res_0,
 					OMAP7XX_MCBSP_RES_SZ,
 					omap7xx_mcbsp_pdata,
@@ -449,7 +440,7 @@
 					omap16xx_mcbsp_pdata,
 					OMAP16XX_MCBSP_COUNT);
 
-	return omap_mcbsp_init();
+	return 0;
 }
 
 arch_initcall(omap1_mcbsp_init);
diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c
index 5fdef7a..087dba0 100644
--- a/arch/arm/mach-omap1/mux.c
+++ b/arch/arm/mach-omap1/mux.c
@@ -27,7 +27,6 @@
 #include <linux/io.h>
 #include <linux/spinlock.h>
 
-#include <asm/system.h>
 
 #include <plat/mux.h>
 
diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
index 89ea20c..f66c329 100644
--- a/arch/arm/mach-omap1/pm.c
+++ b/arch/arm/mach-omap1/pm.c
@@ -42,14 +42,14 @@
 #include <linux/sysfs.h>
 #include <linux/module.h>
 #include <linux/io.h>
-
-#include <asm/irq.h>
 #include <linux/atomic.h>
+
+#include <asm/system_misc.h>
+#include <asm/irq.h>
 #include <asm/mach/time.h>
 #include <asm/mach/irq.h>
 
 #include <plat/cpu.h>
-#include <mach/irqs.h>
 #include <plat/clock.h>
 #include <plat/sram.h>
 #include <plat/tc.h>
@@ -57,6 +57,9 @@
 #include <plat/dma.h>
 #include <plat/dmtimer.h>
 
+#include <mach/irqs.h>
+
+#include "iomap.h"
 #include "pm.h"
 
 static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
@@ -108,13 +111,7 @@
 	__u32 use_idlect1 = arm_idlect1_mask;
 	int do_sleep = 0;
 
-	local_irq_disable();
 	local_fiq_disable();
-	if (need_resched()) {
-		local_fiq_enable();
-		local_irq_enable();
-		return;
-	}
 
 #if defined(CONFIG_OMAP_MPU_TIMER) && !defined(CONFIG_OMAP_DM_TIMER)
 #warning Enable 32kHz OS timer in order to allow sleep states in idle
@@ -157,14 +154,12 @@
 		omap_writel(saved_idlect1, ARM_IDLECT1);
 
 		local_fiq_enable();
-		local_irq_enable();
 		return;
 	}
 	omap_sram_suspend(omap_readl(ARM_IDLECT1),
 			  omap_readl(ARM_IDLECT2));
 
 	local_fiq_enable();
-	local_irq_enable();
 }
 
 /*
@@ -583,8 +578,6 @@
 
 #endif /* DEBUG && CONFIG_PROC_FS */
 
-static void (*saved_idle)(void) = NULL;
-
 /*
  *	omap_pm_prepare - Do preliminary suspend work.
  *
@@ -592,8 +585,7 @@
 static int omap_pm_prepare(void)
 {
 	/* We cannot sleep in idle until we have resumed */
-	saved_idle = pm_idle;
-	pm_idle = NULL;
+	disable_hlt();
 
 	return 0;
 }
@@ -630,7 +622,7 @@
 
 static void omap_pm_finish(void)
 {
-	pm_idle = saved_idle;
+	enable_hlt();
 }
 
 
@@ -687,7 +679,7 @@
 		return -ENODEV;
 	}
 
-	pm_idle = omap1_pm_idle;
+	arm_pm_idle = omap1_pm_idle;
 
 	if (cpu_is_omap7xx())
 		setup_irq(INT_7XX_WAKE_UP_REQ, &omap_wakeup_irq);
diff --git a/arch/arm/mach-omap1/reset.c b/arch/arm/mach-omap1/reset.c
index 91d199b..f255b15 100644
--- a/arch/arm/mach-omap1/reset.c
+++ b/arch/arm/mach-omap1/reset.c
@@ -4,9 +4,10 @@
 #include <linux/kernel.h>
 #include <linux/io.h>
 
-#include <mach/hardware.h>
 #include <plat/prcm.h>
 
+#include <mach/hardware.h>
+
 void omap1_restart(char mode, const char *cmd)
 {
 	/*
diff --git a/arch/arm/mach-omap1/sleep.S b/arch/arm/mach-omap1/sleep.S
index c875bdc..0e62874 100644
--- a/arch/arm/mach-omap1/sleep.S
+++ b/arch/arm/mach-omap1/sleep.S
@@ -33,8 +33,10 @@
  */
 
 #include <linux/linkage.h>
+
 #include <asm/assembler.h>
-#include <mach/io.h>
+
+#include "iomap.h"
 #include "pm.h"
 
 		.text
diff --git a/arch/arm/mach-omap1/sram.S b/arch/arm/mach-omap1/sram.S
index 692587d..00e9d9e 100644
--- a/arch/arm/mach-omap1/sram.S
+++ b/arch/arm/mach-omap1/sram.S
@@ -9,10 +9,13 @@
  */
 
 #include <linux/linkage.h>
+
 #include <asm/assembler.h>
-#include <mach/io.h>
+
 #include <mach/hardware.h>
 
+#include "iomap.h"
+
 	.text
 
 /*
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index b8faffa..4d8dd9a 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -44,15 +44,15 @@
 #include <linux/clockchips.h>
 #include <linux/io.h>
 
-#include <asm/system.h>
-#include <mach/hardware.h>
 #include <asm/leds.h>
 #include <asm/irq.h>
 #include <asm/sched_clock.h>
 
+#include <mach/hardware.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 
+#include "iomap.h"
 #include "common.h"
 
 #ifdef CONFIG_OMAP_MPU_TIMER
diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c
index 9a54ef4..325b9a0 100644
--- a/arch/arm/mach-omap1/timer32k.c
+++ b/arch/arm/mach-omap1/timer32k.c
@@ -46,15 +46,17 @@
 #include <linux/clockchips.h>
 #include <linux/io.h>
 
-#include <asm/system.h>
-#include <mach/hardware.h>
 #include <asm/leds.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
-#include "common.h"
+
 #include <plat/dmtimer.h>
 
+#include <mach/hardware.h>
+
+#include "common.h"
+
 /*
  * ---------------------------------------------------------------------------
  * 32KHz OS timer
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index e20c8ab..8141b76 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -32,7 +32,7 @@
 	depends on ARCH_OMAP2PLUS
 	default y
 	select CPU_V7
-	select USB_ARCH_HAS_EHCI
+	select USB_ARCH_HAS_EHCI if USB_SUPPORT
 	select ARCH_HAS_OPP
 	select PM_OPP if PM
 	select ARM_CPU_SUSPEND if PM
@@ -52,7 +52,7 @@
 	select ARM_ERRATA_720789
 	select ARCH_HAS_OPP
 	select PM_OPP if PM
-	select USB_ARCH_HAS_EHCI
+	select USB_ARCH_HAS_EHCI if USB_SUPPORT
 	select ARM_CPU_SUSPEND if PM
 
 comment "OMAP Core Type"
@@ -117,7 +117,6 @@
 config MACH_OMAP_GENERIC
 	bool "Generic OMAP2+ board"
 	depends on ARCH_OMAP2PLUS
-	select USE_OF
 	default y
 	help
 	  Support for generic TI OMAP2+ boards using Flattened Device Tree.
@@ -245,10 +244,11 @@
 	select MACH_NOKIA_N810_WIMAX
 
 config MACH_NOKIA_RM680
-	bool "Nokia RM-680 board"
+	bool "Nokia RM-680/696 board"
 	depends on ARCH_OMAP3
 	default y
 	select OMAP_PACKAGE_CBB
+	select MACH_NOKIA_RM696
 
 config MACH_NOKIA_RX51
 	bool "Nokia RX-51 board"
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index bd76394..49f92bc1 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -4,7 +4,7 @@
 
 # Common support
 obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer.o pm.o \
-	 common.o gpio.o dma.o wd_timer.o display.o
+	 common.o gpio.o dma.o wd_timer.o display.o i2c.o
 
 omap-2-3-common				= irq.o sdrc.o
 hwmod-common				= omap_hwmod.o \
@@ -17,13 +17,14 @@
 obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(hwmod-common) $(secure-common)
 obj-$(CONFIG_ARCH_OMAP4) += prm44xx.o $(hwmod-common) $(secure-common)
 
-obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
+ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
+obj-y += mcbsp.o
+endif
 
 obj-$(CONFIG_TWL4030_CORE) += omap_twl.o
 
 # SMP support ONLY available for OMAP4
 obj-$(CONFIG_SMP)			+= omap-smp.o omap-headsmp.o
-obj-$(CONFIG_LOCAL_TIMERS)		+= timer-mpu.o
 obj-$(CONFIG_HOTPLUG_CPU)		+= omap-hotplug.o
 obj-$(CONFIG_ARCH_OMAP4)		+= omap4-common.o omap-wakeupgen.o \
 					   sleep44xx.o
@@ -182,9 +183,6 @@
 iommu-$(CONFIG_OMAP_IOMMU)		:= omap-iommu.o
 obj-y					+= $(iommu-m) $(iommu-y)
 
-i2c-omap-$(CONFIG_I2C_OMAP)		:= i2c.o
-obj-y					+= $(i2c-omap-m) $(i2c-omap-y)
-
 ifneq ($(CONFIG_TIDSPBRIDGE),)
 obj-y					+= dsp.o
 endif
@@ -268,6 +266,11 @@
 
 smsc911x-$(CONFIG_SMSC911X)		:= gpmc-smsc911x.o
 obj-y					+= $(smsc911x-m) $(smsc911x-y)
-obj-$(CONFIG_ARCH_OMAP4)		+= hwspinlock.o
+ifneq ($(CONFIG_HWSPINLOCK_OMAP),)
+obj-y					+= hwspinlock.o
+endif
+
+emac-$(CONFIG_TI_DAVINCI_EMAC)		:= am35xx-emac.o
+obj-y					+= $(emac-m) $(emac-y)
 
 obj-y					+= common-board-devices.o twl-common.o
diff --git a/arch/arm/mach-omap2/am35xx-emac.c b/arch/arm/mach-omap2/am35xx-emac.c
new file mode 100644
index 0000000..1f97e74
--- /dev/null
+++ b/arch/arm/mach-omap2/am35xx-emac.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2011 Ilya Yanok, Emcraft Systems
+ *
+ * Based on mach-omap2/board-am3517evm.c
+ * Copyright (C) 2009 Texas Instruments Incorporated
+ * Author: Ranjith Lohithakshan <ranjithl@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
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/davinci_emac.h>
+#include <linux/platform_device.h>
+#include <plat/irqs.h>
+#include <mach/am35xx.h>
+
+#include "control.h"
+
+static struct mdio_platform_data am35xx_emac_mdio_pdata;
+
+static struct resource am35xx_emac_mdio_resources[] = {
+	DEFINE_RES_MEM(AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET, SZ_4K),
+};
+
+static struct platform_device am35xx_emac_mdio_device = {
+	.name		= "davinci_mdio",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(am35xx_emac_mdio_resources),
+	.resource	= am35xx_emac_mdio_resources,
+	.dev.platform_data = &am35xx_emac_mdio_pdata,
+};
+
+static void am35xx_enable_emac_int(void)
+{
+	u32 regval;
+
+	regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+	regval = (regval | AM35XX_CPGMAC_C0_RX_PULSE_CLR |
+		  AM35XX_CPGMAC_C0_TX_PULSE_CLR |
+		  AM35XX_CPGMAC_C0_MISC_PULSE_CLR |
+		  AM35XX_CPGMAC_C0_RX_THRESH_CLR);
+	omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
+	regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+}
+
+static void am35xx_disable_emac_int(void)
+{
+	u32 regval;
+
+	regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+	regval = (regval | AM35XX_CPGMAC_C0_RX_PULSE_CLR |
+		  AM35XX_CPGMAC_C0_TX_PULSE_CLR);
+	omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
+	regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+}
+
+static struct emac_platform_data am35xx_emac_pdata = {
+	.ctrl_reg_offset	= AM35XX_EMAC_CNTRL_OFFSET,
+	.ctrl_mod_reg_offset	= AM35XX_EMAC_CNTRL_MOD_OFFSET,
+	.ctrl_ram_offset	= AM35XX_EMAC_CNTRL_RAM_OFFSET,
+	.ctrl_ram_size		= AM35XX_EMAC_CNTRL_RAM_SIZE,
+	.hw_ram_addr		= AM35XX_EMAC_HW_RAM_ADDR,
+	.version		= EMAC_VERSION_2,
+	.interrupt_enable	= am35xx_enable_emac_int,
+	.interrupt_disable	= am35xx_disable_emac_int,
+};
+
+static struct resource am35xx_emac_resources[] = {
+	DEFINE_RES_MEM(AM35XX_IPSS_EMAC_BASE, 0x30000),
+	DEFINE_RES_IRQ(INT_35XX_EMAC_C0_RXTHRESH_IRQ),
+	DEFINE_RES_IRQ(INT_35XX_EMAC_C0_RX_PULSE_IRQ),
+	DEFINE_RES_IRQ(INT_35XX_EMAC_C0_TX_PULSE_IRQ),
+	DEFINE_RES_IRQ(INT_35XX_EMAC_C0_MISC_PULSE_IRQ),
+};
+
+static struct platform_device am35xx_emac_device = {
+	.name		= "davinci_emac",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(am35xx_emac_resources),
+	.resource	= am35xx_emac_resources,
+	.dev		= {
+		.platform_data	= &am35xx_emac_pdata,
+	},
+};
+
+void __init am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en)
+{
+	unsigned int regval;
+	int err;
+
+	am35xx_emac_pdata.rmii_en = rmii_en;
+	am35xx_emac_mdio_pdata.bus_freq = mdio_bus_freq;
+	err = platform_device_register(&am35xx_emac_device);
+	if (err) {
+		pr_err("AM35x: failed registering EMAC device: %d\n", err);
+		return;
+	}
+
+	err = platform_device_register(&am35xx_emac_mdio_device);
+	if (err) {
+		pr_err("AM35x: failed registering EMAC MDIO device: %d\n", err);
+		platform_device_unregister(&am35xx_emac_device);
+		return;
+	}
+
+	regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
+	regval = regval & (~(AM35XX_CPGMACSS_SW_RST));
+	omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
+	regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
+}
diff --git a/arch/arm/mach-omap2/am35xx-emac.h b/arch/arm/mach-omap2/am35xx-emac.h
new file mode 100644
index 0000000..15c6f9c
--- /dev/null
+++ b/arch/arm/mach-omap2/am35xx-emac.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2011 Ilya Yanok, Emcraft Systems
+ *
+ * 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 AM35XX_DEFAULT_MDIO_FREQUENCY	1000000
+
+#if defined(CONFIG_TI_DAVINCI_EMAC) || defined(CONFIG_TI_DAVINCI_EMAC_MODULE)
+void am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en);
+#else
+static inline void am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en) {}
+#endif
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index 7370983..e658f83 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -230,12 +230,12 @@
 	{
 		I2C_BOARD_INFO("isp1301_omap", 0x2D),
 		.flags = I2C_CLIENT_WAKE,
-		.irq = OMAP_GPIO_IRQ(78),
 	},
 };
 
 static int __init omap2430_i2c_init(void)
 {
+	sdp2430_i2c1_boardinfo[0].irq = gpio_to_irq(78);
 	omap_register_i2c_bus(1, 100, sdp2430_i2c1_boardinfo,
 			ARRAY_SIZE(sdp2430_i2c1_boardinfo));
 	omap_pmic_init(2, 100, "twl4030", INT_24XX_SYS_NIRQ,
@@ -279,7 +279,7 @@
 	platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices));
 	omap_serial_init();
 	omap_sdrc_init(NULL, NULL);
-	omap2_hsmmc_init(mmc);
+	omap_hsmmc_init(mmc);
 	omap2_usbfs_init(&sdp2430_usb_config);
 
 	omap_mux_init_signal("usb0hs_stp", OMAP_PULL_ENA | OMAP_PULL_UP);
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index 383717b..da75f23 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -232,11 +232,13 @@
 		 */
 		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
 		.gpio_wp	= 4,
+		.deferred	= true,
 	},
 	{
 		.mmc		= 2,
 		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
 		.gpio_wp	= 7,
+		.deferred	= true,
 	},
 	{}	/* Terminator */
 };
@@ -249,7 +251,7 @@
 	 */
 	mmc[0].gpio_cd = gpio + 0;
 	mmc[1].gpio_cd = gpio + 1;
-	omap2_hsmmc_init(mmc);
+	omap_hsmmc_late_init(mmc);
 
 	/* gpio + 7 is "sub_lcd_en_bkl" (output/PWM1) */
 	gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "sub_lcd_en_bkl");
@@ -606,6 +608,7 @@
 	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
 	omap_board_config = sdp3430_config;
 	omap_board_config_size = ARRAY_SIZE(sdp3430_config);
+	omap_hsmmc_init(mmc);
 	omap3430_i2c_init();
 	omap_display_init(&sdp3430_dss_data);
 	if (omap_rev() > OMAP3430_REV_ES1_0)
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index 4e90715..a39fc4b 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -25,6 +25,7 @@
 #include <linux/regulator/fixed.h>
 #include <linux/leds.h>
 #include <linux/leds_pwm.h>
+#include <linux/platform_data/omap4-keypad.h>
 
 #include <mach/hardware.h>
 #include <asm/hardware/gic.h>
@@ -41,6 +42,7 @@
 #include <video/omap-panel-nokia-dsi.h>
 #include <video/omap-panel-picodlp.h>
 #include <linux/wl12xx.h>
+#include <linux/platform_data/omap-abe-twl6040.h>
 
 #include "mux.h"
 #include "hsmmc.h"
@@ -322,7 +324,10 @@
 		.bus_num                = 1,
 		.chip_select            = 0,
 		.max_speed_hz           = 24000000,
-		.irq                    = ETH_KS8851_IRQ,
+		/*
+		 * .irq is set to gpio_to_irq(ETH_KS8851_IRQ)
+		 * in omap_4430sdp_init
+		 */
 	},
 };
 
@@ -378,12 +383,40 @@
 	.id	= -1,
 };
 
+static struct omap_abe_twl6040_data sdp4430_abe_audio_data = {
+	.card_name = "SDP4430",
+	.has_hs		= ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT,
+	.has_hf		= ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT,
+	.has_ep		= 1,
+	.has_aux	= ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT,
+	.has_vibra	= ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT,
+
+	.has_dmic	= 1,
+	.has_hsmic	= 1,
+	.has_mainmic	= 1,
+	.has_submic	= 1,
+	.has_afm	= ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT,
+
+	.jack_detection = 1,
+	/* MCLK input is 38.4MHz */
+	.mclk_freq	= 38400000,
+};
+
+static struct platform_device sdp4430_abe_audio = {
+	.name		= "omap-abe-twl6040",
+	.id		= -1,
+	.dev = {
+		.platform_data = &sdp4430_abe_audio_data,
+	},
+};
+
 static struct platform_device *sdp4430_devices[] __initdata = {
 	&sdp4430_gpio_keys_device,
 	&sdp4430_leds_gpio,
 	&sdp4430_leds_pwm,
 	&sdp4430_vbat,
 	&sdp4430_dmic_codec,
+	&sdp4430_abe_audio,
 };
 
 static struct omap_musb_board_data musb_board_data = {
@@ -457,21 +490,22 @@
 
 static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 {
-	int ret = 0;
+	int irq = 0;
 	struct platform_device *pdev = container_of(dev,
 				struct platform_device, dev);
 	struct omap_mmc_platform_data *pdata = dev->platform_data;
 
 	/* Setting MMC1 Card detect Irq */
 	if (pdev->id == 0) {
-		ret = twl6030_mmc_card_detect_config();
-		if (ret)
+		irq = twl6030_mmc_card_detect_config();
+		if (irq < 0) {
 			pr_err("Failed configuring MMC1 card detect\n");
-		pdata->slots[0].card_detect_irq = TWL6030_IRQ_BASE +
-						MMCDETECT_INTR_OFFSET;
+			return irq;
+		}
+		pdata->slots[0].card_detect_irq = irq;
 		pdata->slots[0].card_detect = twl6030_mmc_card_detect;
 	}
-	return ret;
+	return 0;
 }
 
 static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
@@ -491,9 +525,9 @@
 {
 	struct omap2_hsmmc_info *c;
 
-	omap2_hsmmc_init(controllers);
+	omap_hsmmc_init(controllers);
 	for (c = controllers; c->mmc; c++)
-		omap4_twl6030_hsmmc_set_late_init(c->dev);
+		omap4_twl6030_hsmmc_set_late_init(&c->pdev->dev);
 
 	return 0;
 }
@@ -873,7 +907,6 @@
 }
 
 static struct wl12xx_platform_data omap4_sdp4430_wlan_data __initdata = {
-	.irq = OMAP_GPIO_IRQ(GPIO_WIFI_IRQ),
 	.board_ref_clock = WL12XX_REFCLOCK_26,
 	.board_tcxo_clock = WL12XX_TCXOCLOCK_26,
 };
@@ -883,6 +916,7 @@
 	int ret;
 
 	omap4_sdp4430_wifi_mux_init();
+	omap4_sdp4430_wlan_data.irq = gpio_to_irq(GPIO_WIFI_IRQ);
 	ret = wl12xx_set_platform_data(&omap4_sdp4430_wlan_data);
 	if (ret)
 		pr_err("Error setting wl12xx data: %d\n", ret);
diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c
index 4b1cfe3..3645285 100644
--- a/arch/arm/mach-omap2/board-am3517evm.c
+++ b/arch/arm/mach-omap2/board-am3517evm.c
@@ -39,124 +39,11 @@
 #include <video/omap-panel-generic-dpi.h>
 #include <video/omap-panel-dvi.h>
 
+#include "am35xx-emac.h"
 #include "mux.h"
 #include "control.h"
 #include "hsmmc.h"
 
-#define AM35XX_EVM_MDIO_FREQUENCY	(1000000)
-
-static struct mdio_platform_data am3517_evm_mdio_pdata = {
-	.bus_freq	= AM35XX_EVM_MDIO_FREQUENCY,
-};
-
-static struct resource am3517_mdio_resources[] = {
-	{
-		.start  = AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET,
-		.end    = AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET +
-			  SZ_4K - 1,
-		.flags  = IORESOURCE_MEM,
-	},
-};
-
-static struct platform_device am3517_mdio_device = {
-	.name		= "davinci_mdio",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(am3517_mdio_resources),
-	.resource	= am3517_mdio_resources,
-	.dev.platform_data = &am3517_evm_mdio_pdata,
-};
-
-static struct emac_platform_data am3517_evm_emac_pdata = {
-	.rmii_en	= 1,
-};
-
-static struct resource am3517_emac_resources[] = {
-	{
-		.start  = AM35XX_IPSS_EMAC_BASE,
-		.end    = AM35XX_IPSS_EMAC_BASE + 0x2FFFF,
-		.flags  = IORESOURCE_MEM,
-	},
-	{
-		.start  = INT_35XX_EMAC_C0_RXTHRESH_IRQ,
-		.end    = INT_35XX_EMAC_C0_RXTHRESH_IRQ,
-		.flags  = IORESOURCE_IRQ,
-	},
-	{
-		.start  = INT_35XX_EMAC_C0_RX_PULSE_IRQ,
-		.end    = INT_35XX_EMAC_C0_RX_PULSE_IRQ,
-		.flags  = IORESOURCE_IRQ,
-	},
-	{
-		.start  = INT_35XX_EMAC_C0_TX_PULSE_IRQ,
-		.end    = INT_35XX_EMAC_C0_TX_PULSE_IRQ,
-		.flags  = IORESOURCE_IRQ,
-	},
-	{
-		.start  = INT_35XX_EMAC_C0_MISC_PULSE_IRQ,
-		.end    = INT_35XX_EMAC_C0_MISC_PULSE_IRQ,
-		.flags  = IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device am3517_emac_device = {
-	.name		= "davinci_emac",
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(am3517_emac_resources),
-	.resource	= am3517_emac_resources,
-};
-
-static void am3517_enable_ethernet_int(void)
-{
-	u32 regval;
-
-	regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
-	regval = (regval | AM35XX_CPGMAC_C0_RX_PULSE_CLR |
-		AM35XX_CPGMAC_C0_TX_PULSE_CLR |
-		AM35XX_CPGMAC_C0_MISC_PULSE_CLR |
-		AM35XX_CPGMAC_C0_RX_THRESH_CLR);
-	omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
-	regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
-}
-
-static void am3517_disable_ethernet_int(void)
-{
-	u32 regval;
-
-	regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
-	regval = (regval | AM35XX_CPGMAC_C0_RX_PULSE_CLR |
-		AM35XX_CPGMAC_C0_TX_PULSE_CLR);
-	omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
-	regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
-}
-
-static void am3517_evm_ethernet_init(struct emac_platform_data *pdata)
-{
-	unsigned int regval;
-
-	pdata->ctrl_reg_offset		= AM35XX_EMAC_CNTRL_OFFSET;
-	pdata->ctrl_mod_reg_offset	= AM35XX_EMAC_CNTRL_MOD_OFFSET;
-	pdata->ctrl_ram_offset		= AM35XX_EMAC_CNTRL_RAM_OFFSET;
-	pdata->ctrl_ram_size		= AM35XX_EMAC_CNTRL_RAM_SIZE;
-	pdata->version			= EMAC_VERSION_2;
-	pdata->hw_ram_addr		= AM35XX_EMAC_HW_RAM_ADDR;
-	pdata->interrupt_enable		= am3517_enable_ethernet_int;
-	pdata->interrupt_disable	= am3517_disable_ethernet_int;
-	am3517_emac_device.dev.platform_data	= pdata;
-	platform_device_register(&am3517_emac_device);
-	platform_device_register(&am3517_mdio_device);
-	clk_add_alias(NULL, dev_name(&am3517_mdio_device.dev),
-		      NULL, &am3517_emac_device.dev);
-
-	regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
-	regval = regval & (~(AM35XX_CPGMACSS_SW_RST));
-	omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
-	regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
-
-	return ;
-}
-
-
-
 #define LCD_PANEL_PWR		176
 #define LCD_PANEL_BKLIGHT_PWR	182
 #define LCD_PANEL_PWM		181
@@ -498,13 +385,13 @@
 	i2c_register_board_info(1, am3517evm_i2c1_boardinfo,
 				ARRAY_SIZE(am3517evm_i2c1_boardinfo));
 	/*Ethernet*/
-	am3517_evm_ethernet_init(&am3517_evm_emac_pdata);
+	am35xx_emac_init(AM35XX_DEFAULT_MDIO_FREQUENCY, 1);
 
 	/* MUSB */
 	am3517_evm_musb_init();
 
 	/* MMC init function */
-	omap2_hsmmc_init(mmc);
+	omap_hsmmc_init(mmc);
 }
 
 MACHINE_START(OMAP3517EVM, "OMAP3517/AM3517 EVM")
diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c
index ac77382..768ece2 100644
--- a/arch/arm/mach-omap2/board-apollon.c
+++ b/arch/arm/mach-omap2/board-apollon.c
@@ -136,8 +136,6 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ),
-		.end	= OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ),
 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
 	},
 };
@@ -341,6 +339,8 @@
 	 * You have to mux them off in device drivers later on
 	 * if not needed.
 	 */
+	apollon_smc91x_resources[1].start = gpio_to_irq(APOLLON_ETHR_GPIO_IRQ);
+	apollon_smc91x_resources[1].end = gpio_to_irq(APOLLON_ETHR_GPIO_IRQ);
 	platform_add_devices(apollon_devices, ARRAY_SIZE(apollon_devices));
 	omap_serial_init();
 	omap_sdrc_init(NULL, NULL);
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index d73316e..909a8b9 100644
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -26,6 +26,7 @@
 
 #include <linux/i2c/at24.h>
 #include <linux/i2c/twl.h>
+#include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 #include <linux/mmc/host.h>
 
@@ -81,8 +82,23 @@
 	.flags		= SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
 };
 
+static struct regulator_consumer_supply cm_t35_smsc911x_supplies[] = {
+	REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
+	REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
+};
+
+static struct regulator_consumer_supply sb_t35_smsc911x_supplies[] = {
+	REGULATOR_SUPPLY("vddvario", "smsc911x.1"),
+	REGULATOR_SUPPLY("vdd33a", "smsc911x.1"),
+};
+
 static void __init cm_t35_init_ethernet(void)
 {
+	regulator_register_fixed(0, cm_t35_smsc911x_supplies,
+				 ARRAY_SIZE(cm_t35_smsc911x_supplies));
+	regulator_register_fixed(1, sb_t35_smsc911x_supplies,
+				 ARRAY_SIZE(sb_t35_smsc911x_supplies));
+
 	gpmc_smsc911x_init(&cm_t35_smsc911x_cfg);
 	gpmc_smsc911x_init(&sb_t35_smsc911x_cfg);
 }
@@ -280,7 +296,6 @@
 
 static struct omap2_mcspi_device_config tdo24m_mcspi_config = {
 	.turbo_mode	= 0,
-	.single_channel	= 1,	/* 0: slave, 1: master */
 };
 
 static struct tdo24m_platform_data tdo24m_config = {
@@ -413,7 +428,7 @@
 		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
-
+		.deferred	= true,
 	},
 	{
 		.mmc		= 2,
@@ -471,7 +486,7 @@
 
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
 	mmc[0].gpio_cd = gpio + 0;
-	omap2_hsmmc_init(mmc);
+	omap_hsmmc_late_init(mmc);
 
 	return 0;
 }
@@ -639,6 +654,7 @@
 	omap_serial_init();
 	omap_sdrc_init(mt46h32m32lf6_sdrc_params,
 			     mt46h32m32lf6_sdrc_params);
+	omap_hsmmc_init(mmc);
 	cm_t35_init_i2c();
 	omap_ads7846_init(1, CM_T35_GPIO_PENDOWN, 0, NULL);
 	cm_t35_init_ethernet();
diff --git a/arch/arm/mach-omap2/board-cm-t3517.c b/arch/arm/mach-omap2/board-cm-t3517.c
index f36d694..9e66e16 100644
--- a/arch/arm/mach-omap2/board-cm-t3517.c
+++ b/arch/arm/mach-omap2/board-cm-t3517.c
@@ -49,6 +49,7 @@
 #include "mux.h"
 #include "control.h"
 #include "common-board-devices.h"
+#include "am35xx-emac.h"
 
 #if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
 static struct gpio_led cm_t3517_leds[] = {
@@ -291,6 +292,7 @@
 	cm_t3517_init_rtc();
 	cm_t3517_init_usbh();
 	cm_t3517_init_hecc();
+	am35xx_emac_init(AM35XX_DEFAULT_MDIO_FREQUENCY, 1);
 }
 
 MACHINE_START(CM_T3517, "Compulab CM-T3517")
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index e873063..a2010f0 100644
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -100,6 +100,7 @@
 		.mmc		= 1,
 		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
 		.gpio_wp	= 29,
+		.deferred	= true,
 	},
 	{}	/* Terminator */
 };
@@ -228,7 +229,7 @@
 
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
 	mmc[0].gpio_cd = gpio + 0;
-	omap2_hsmmc_init(mmc);
+	omap_hsmmc_late_init(mmc);
 
 	/* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
 	gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
@@ -410,7 +411,6 @@
 		.flags		= IORESOURCE_MEM,
 	},
 	[2] = {
-		.start		= OMAP_GPIO_IRQ(OMAP_DM9000_GPIO_IRQ),
 		.flags		= IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
 	},
 };
@@ -636,7 +636,9 @@
 
 	omap_dm9000_init();
 
+	omap_hsmmc_init(mmc);
 	devkit8000_i2c_init();
+	omap_dm9000_resources[2].start = gpio_to_irq(OMAP_DM9000_GPIO_IRQ);
 	platform_add_devices(devkit8000_devices,
 			ARRAY_SIZE(devkit8000_devices));
 
diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c
index 30a6f52..0349fd2 100644
--- a/arch/arm/mach-omap2/board-flash.c
+++ b/arch/arm/mach-omap2/board-flash.c
@@ -189,7 +189,7 @@
  *
  * @return - void.
  */
-void board_flash_init(struct flash_partitions partition_info[],
+void __init board_flash_init(struct flash_partitions partition_info[],
 			char chip_sel_board[][GPMC_CS_NUM], int nand_type)
 {
 	u8		cs = 0;
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
index 45fdfe2..74e1687 100644
--- a/arch/arm/mach-omap2/board-generic.c
+++ b/arch/arm/mach-omap2/board-generic.c
@@ -12,6 +12,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/io.h>
+#include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/irqdomain.h>
 #include <linux/i2c/twl.h>
@@ -24,20 +25,73 @@
 #include "common.h"
 #include "common-board-devices.h"
 
-/*
- * XXX: Still needed to boot until the i2c & twl driver is adapted to
- * device-tree
- */
-#ifdef CONFIG_ARCH_OMAP4
-static struct twl4030_platform_data sdp4430_twldata = {
-	.irq_base	= TWL6030_IRQ_BASE,
-	.irq_end	= TWL6030_IRQ_END,
+#if !(defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3))
+#define omap_intc_of_init	NULL
+#endif
+#ifndef CONFIG_ARCH_OMAP4
+#define gic_of_init		NULL
+#endif
+
+static struct of_device_id irq_match[] __initdata = {
+	{ .compatible = "ti,omap2-intc", .data = omap_intc_of_init, },
+	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+	{ }
 };
 
-static void __init omap4_i2c_init(void)
+static void __init omap_init_irq(void)
 {
-	omap4_pmic_init("twl6030", &sdp4430_twldata);
+	of_irq_init(irq_match);
 }
+
+static struct of_device_id omap_dt_match_table[] __initdata = {
+	{ .compatible = "simple-bus", },
+	{ .compatible = "ti,omap-infra", },
+	{ }
+};
+
+static void __init omap_generic_init(void)
+{
+	omap_sdrc_init(NULL, NULL);
+
+	of_platform_populate(NULL, omap_dt_match_table, NULL, NULL);
+}
+
+#ifdef CONFIG_SOC_OMAP2420
+static const char *omap242x_boards_compat[] __initdata = {
+	"ti,omap2420",
+	NULL,
+};
+
+DT_MACHINE_START(OMAP242X_DT, "Generic OMAP2420 (Flattened Device Tree)")
+	.reserve	= omap_reserve,
+	.map_io		= omap242x_map_io,
+	.init_early	= omap2420_init_early,
+	.init_irq	= omap_init_irq,
+	.handle_irq	= omap2_intc_handle_irq,
+	.init_machine	= omap_generic_init,
+	.timer		= &omap2_timer,
+	.dt_compat	= omap242x_boards_compat,
+	.restart	= omap_prcm_restart,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_SOC_OMAP2430
+static const char *omap243x_boards_compat[] __initdata = {
+	"ti,omap2430",
+	NULL,
+};
+
+DT_MACHINE_START(OMAP243X_DT, "Generic OMAP2430 (Flattened Device Tree)")
+	.reserve	= omap_reserve,
+	.map_io		= omap243x_map_io,
+	.init_early	= omap2430_init_early,
+	.init_irq	= omap_init_irq,
+	.handle_irq	= omap2_intc_handle_irq,
+	.init_machine	= omap_generic_init,
+	.timer		= &omap2_timer,
+	.dt_compat	= omap243x_boards_compat,
+	.restart	= omap_prcm_restart,
+MACHINE_END
 #endif
 
 #ifdef CONFIG_ARCH_OMAP3
@@ -50,99 +104,23 @@
 {
 	omap3_pmic_init("twl4030", &beagle_twldata);
 }
-#endif
 
-static struct of_device_id omap_dt_match_table[] __initdata = {
-	{ .compatible = "simple-bus", },
-	{ .compatible = "ti,omap-infra", },
-	{ }
-};
-
-static struct of_device_id intc_match[] __initdata = {
-	{ .compatible = "ti,omap3-intc", },
-	{ .compatible = "arm,cortex-a9-gic", },
-	{ }
-};
-
-static void __init omap_generic_init(void)
-{
-	struct device_node *node = of_find_matching_node(NULL, intc_match);
-	if (node)
-		irq_domain_add_legacy(node, 32, 0, 0, &irq_domain_simple_ops, NULL);
-
-	omap_sdrc_init(NULL, NULL);
-
-	of_platform_populate(NULL, omap_dt_match_table, NULL, NULL);
-}
-
-#ifdef CONFIG_ARCH_OMAP4
-static void __init omap4_init(void)
-{
-	omap4_i2c_init();
-	omap_generic_init();
-}
-#endif
-
-#ifdef CONFIG_ARCH_OMAP3
 static void __init omap3_init(void)
 {
 	omap3_i2c_init();
 	omap_generic_init();
 }
-#endif
 
-#if defined(CONFIG_SOC_OMAP2420)
-static const char *omap242x_boards_compat[] __initdata = {
-	"ti,omap2420",
-	NULL,
-};
-
-DT_MACHINE_START(OMAP242X_DT, "Generic OMAP2420 (Flattened Device Tree)")
-	.atag_offset	= 0x100,
-	.reserve	= omap_reserve,
-	.map_io		= omap242x_map_io,
-	.init_early	= omap2420_init_early,
-	.init_irq	= omap2_init_irq,
-	.handle_irq	= omap2_intc_handle_irq,
-	.init_machine	= omap_generic_init,
-	.timer		= &omap2_timer,
-	.dt_compat	= omap242x_boards_compat,
-	.restart	= omap_prcm_restart,
-MACHINE_END
-#endif
-
-#if defined(CONFIG_SOC_OMAP2430)
-static const char *omap243x_boards_compat[] __initdata = {
-	"ti,omap2430",
-	NULL,
-};
-
-DT_MACHINE_START(OMAP243X_DT, "Generic OMAP2430 (Flattened Device Tree)")
-	.atag_offset	= 0x100,
-	.reserve	= omap_reserve,
-	.map_io		= omap243x_map_io,
-	.init_early	= omap2430_init_early,
-	.init_irq	= omap2_init_irq,
-	.handle_irq	= omap2_intc_handle_irq,
-	.init_machine	= omap_generic_init,
-	.timer		= &omap2_timer,
-	.dt_compat	= omap243x_boards_compat,
-	.restart	= omap_prcm_restart,
-MACHINE_END
-#endif
-
-#if defined(CONFIG_ARCH_OMAP3)
 static const char *omap3_boards_compat[] __initdata = {
 	"ti,omap3",
 	NULL,
 };
 
 DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)")
-	.atag_offset	= 0x100,
 	.reserve	= omap_reserve,
 	.map_io		= omap3_map_io,
 	.init_early	= omap3430_init_early,
-	.init_irq	= omap3_init_irq,
+	.init_irq	= omap_init_irq,
 	.handle_irq	= omap3_intc_handle_irq,
 	.init_machine	= omap3_init,
 	.timer		= &omap3_timer,
@@ -151,18 +129,33 @@
 MACHINE_END
 #endif
 
-#if defined(CONFIG_ARCH_OMAP4)
+#ifdef CONFIG_ARCH_OMAP4
+static struct twl4030_platform_data sdp4430_twldata = {
+	.irq_base	= TWL6030_IRQ_BASE,
+	.irq_end	= TWL6030_IRQ_END,
+};
+
+static void __init omap4_i2c_init(void)
+{
+	omap4_pmic_init("twl6030", &sdp4430_twldata);
+}
+
+static void __init omap4_init(void)
+{
+	omap4_i2c_init();
+	omap_generic_init();
+}
+
 static const char *omap4_boards_compat[] __initdata = {
 	"ti,omap4",
 	NULL,
 };
 
 DT_MACHINE_START(OMAP4_DT, "Generic OMAP4 (Flattened Device Tree)")
-	.atag_offset	= 0x100,
 	.reserve	= omap_reserve,
 	.map_io		= omap4_map_io,
 	.init_early	= omap4430_init_early,
-	.init_irq	= gic_init_irq,
+	.init_irq	= omap_init_irq,
 	.handle_irq	= gic_handle_irq,
 	.init_machine	= omap4_init,
 	.timer		= &omap4_timer,
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index 54af800..0bbbabe 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -348,7 +348,6 @@
 static struct i2c_board_info __initdata h4_i2c_board_info[] = {
 	{
 		I2C_BOARD_INFO("isp1301_omap", 0x2d),
-		.irq		= OMAP_GPIO_IRQ(125),
 	},
 	{	/* EEPROM on mainboard */
 		I2C_BOARD_INFO("24c01", 0x52),
@@ -377,6 +376,7 @@
 	 */
 
 	board_mkp_init();
+	h4_i2c_board_info[0].irq = gpio_to_irq(125);
 	i2c_register_board_info(1, h4_i2c_board_info,
 			ARRAY_SIZE(h4_i2c_board_info));
 
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
index a59ace0..930c0d3 100644
--- a/arch/arm/mach-omap2/board-igep0020.c
+++ b/arch/arm/mach-omap2/board-igep0020.c
@@ -295,6 +295,7 @@
 		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
+		.deferred	= true,
 	},
 #if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
 	{
@@ -402,7 +403,7 @@
 
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
 	mmc[0].gpio_cd = gpio + 0;
-	omap2_hsmmc_init(mmc);
+	omap_hsmmc_late_init(mmc);
 
 	/* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
 #if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
@@ -633,12 +634,21 @@
 static inline void __init igep_wlan_bt_init(void) { }
 #endif
 
+static struct regulator_consumer_supply dummy_supplies[] = {
+	REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
+	REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
+};
+
 static void __init igep_init(void)
 {
+	regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
 	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
 
 	/* Get IGEP2 hardware revision */
 	igep2_get_revision();
+
+	omap_hsmmc_init(mmc);
+
 	/* Register I2C busses and drivers */
 	igep_i2c_init();
 	platform_add_devices(igep_devices, ARRAY_SIZE(igep_devices));
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index 2d2a61f..1b60495 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -22,12 +22,12 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/spi/spi.h>
+#include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
 #include <linux/mmc/host.h>
-#include <linux/gpio.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -411,8 +411,14 @@
 
 };
 
+static struct regulator_consumer_supply dummy_supplies[] = {
+	REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
+	REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
+};
+
 static void __init omap_ldp_init(void)
 {
+	regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
 	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
 	ldp_init_smsc911x();
 	omap_i2c_init();
@@ -424,7 +430,7 @@
 	board_nand_init(ldp_nand_partitions,
 		ARRAY_SIZE(ldp_nand_partitions), ZOOM_NAND_CS, 0);
 
-	omap2_hsmmc_init(mmc);
+	omap_hsmmc_init(mmc);
 	ldp_display_init();
 }
 
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
index 6722627..518091c 100644
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -36,10 +36,6 @@
 
 #include "mux.h"
 
-static int slot1_cover_open;
-static int slot2_cover_open;
-static struct device *mmc_device;
-
 #define TUSB6010_ASYNC_CS	1
 #define TUSB6010_SYNC_CS	4
 #define TUSB6010_GPIO_INT	58
@@ -137,7 +133,6 @@
 
 static struct omap2_mcspi_device_config p54spi_mcspi_config = {
 	.turbo_mode	= 0,
-	.single_channel = 1,
 };
 
 static struct spi_board_info n800_spi_board_info[] __initdata = {
@@ -211,6 +206,10 @@
 #define N810_EMMC_VSD_GPIO	23
 #define N810_EMMC_VIO_GPIO	9
 
+static int slot1_cover_open;
+static int slot2_cover_open;
+static struct device *mmc_device;
+
 static int n8x0_mmc_switch_slot(struct device *dev, int slot)
 {
 #ifdef CONFIG_MMC_DEBUG
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 7ffcd28..7be8d65 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -253,6 +253,7 @@
 		.mmc		= 1,
 		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
 		.gpio_wp	= -EINVAL,
+		.deferred	= true,
 	},
 	{}	/* Terminator */
 };
@@ -272,12 +273,10 @@
 {
 	int r;
 
-	if (beagle_config.mmc1_gpio_wp != -EINVAL)
-		omap_mux_init_gpio(beagle_config.mmc1_gpio_wp, OMAP_PIN_INPUT);
 	mmc[0].gpio_wp = beagle_config.mmc1_gpio_wp;
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
 	mmc[0].gpio_cd = gpio + 0;
-	omap2_hsmmc_init(mmc);
+	omap_hsmmc_late_init(mmc);
 
 	/*
 	 * TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, XM active
@@ -521,6 +520,11 @@
 {
 	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
 	omap3_beagle_init_rev();
+
+	if (beagle_config.mmc1_gpio_wp != -EINVAL)
+		omap_mux_init_gpio(beagle_config.mmc1_gpio_wp, OMAP_PIN_INPUT);
+	omap_hsmmc_init(mmc);
+
 	omap3_beagle_i2c_init();
 
 	gpio_buttons[0].gpio = beagle_config.usr_button_gpio;
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index c877236..49df127 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -114,15 +114,6 @@
 
 static inline void __init omap3evm_init_smsc911x(void)
 {
-	struct clk *l3ck;
-	unsigned int rate;
-
-	l3ck = clk_get(NULL, "l3_ck");
-	if (IS_ERR(l3ck))
-		rate = 100000000;
-	else
-		rate = clk_get_rate(l3ck);
-
 	/* Configure ethernet controller reset gpio */
 	if (cpu_is_omap3430()) {
 		if (get_omap3_evm_rev() == OMAP3EVM_BOARD_GEN_1)
@@ -317,6 +308,7 @@
 		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= 63,
+		.deferred	= true,
 	},
 #ifdef CONFIG_WL12XX_PLATFORM_DATA
 	{
@@ -361,9 +353,8 @@
 	int r, lcd_bl_en;
 
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
-	omap_mux_init_gpio(63, OMAP_PIN_INPUT);
 	mmc[0].gpio_cd = gpio + 0;
-	omap2_hsmmc_init(mmc);
+	omap_hsmmc_late_init(mmc);
 
 	/*
 	 * Most GPIOs are for USB OTG.  Some are mostly sent to
@@ -487,7 +478,6 @@
 };
 
 struct wl12xx_platform_data omap3evm_wlan_data __initdata = {
-	.irq = OMAP_GPIO_IRQ(OMAP3EVM_WLAN_IRQ_GPIO),
 	.board_ref_clock = WL12XX_REFCLOCK_38, /* 38.4 MHz */
 };
 #endif
@@ -623,6 +613,7 @@
 	int ret;
 
 	/* WL12xx WLAN Init */
+	omap3evm_wlan_data.irq = gpio_to_irq(OMAP3EVM_WLAN_IRQ_GPIO);
 	ret = wl12xx_set_platform_data(&omap3evm_wlan_data);
 	if (ret)
 		pr_err("error setting wl12xx data: %d\n", ret);
@@ -632,9 +623,15 @@
 #endif
 }
 
+static struct regulator_consumer_supply dummy_supplies[] = {
+	REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
+	REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
+};
+
 static void __init omap3_evm_init(void)
 {
 	omap3_evm_get_revision();
+	regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
 
 	if (cpu_is_omap3630())
 		omap3_mux_init(omap36x_board_mux, OMAP_PACKAGE_CBB);
@@ -644,6 +641,9 @@
 	omap_board_config = omap3_evm_config;
 	omap_board_config_size = ARRAY_SIZE(omap3_evm_config);
 
+	omap_mux_init_gpio(63, OMAP_PIN_INPUT);
+	omap_hsmmc_init(mmc);
+
 	omap3_evm_i2c_init();
 
 	omap_display_init(&omap3_evm_dss_data);
diff --git a/arch/arm/mach-omap2/board-omap3logic.c b/arch/arm/mach-omap2/board-omap3logic.c
index 4198dd0..9b3c141 100644
--- a/arch/arm/mach-omap2/board-omap3logic.c
+++ b/arch/arm/mach-omap2/board-omap3logic.c
@@ -23,6 +23,7 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 
+#include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 
 #include <linux/i2c/twl.h>
@@ -128,7 +129,7 @@
 		return;
 	}
 
-	omap2_hsmmc_init(board_mmc_info);
+	omap_hsmmc_init(board_mmc_info);
 }
 
 static struct omap_smsc911x_platform_data __initdata board_smsc911x_data = {
@@ -188,8 +189,14 @@
 };
 #endif
 
+static struct regulator_consumer_supply dummy_supplies[] = {
+	REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
+	REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
+};
+
 static void __init omap3logic_init(void)
 {
+	regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
 	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
 	omap3torpedo_fix_pbias_voltage();
 	omap3logic_i2c_init();
@@ -205,6 +212,7 @@
 
 MACHINE_START(OMAP3_TORPEDO, "Logic OMAP3 Torpedo board")
 	.atag_offset	= 0x100,
+	.reserve	= omap_reserve,
 	.map_io		= omap3_map_io,
 	.init_early	= omap35xx_init_early,
 	.init_irq	= omap3_init_irq,
@@ -216,6 +224,7 @@
 
 MACHINE_START(OMAP3530_LV_SOM, "OMAP Logic 3530 LV SOM board")
 	.atag_offset	= 0x100,
+	.reserve	= omap_reserve,
 	.map_io		= omap3_map_io,
 	.init_early	= omap35xx_init_early,
 	.init_irq	= omap3_init_irq,
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index 1644b73..33d995d 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -121,6 +121,11 @@
 	},
 };
 
+static struct platform_device pandora_backlight = {
+	.name	= "pandora-backlight",
+	.id	= -1,
+};
+
 #define GPIO_BUTTON(gpio_num, ev_type, ev_code, act_low, descr)	\
 {								\
 	.gpio		= gpio_num,				\
@@ -273,6 +278,7 @@
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= 126,
 		.ext_clock	= 0,
+		.deferred	= true,
 	},
 	{
 		.mmc		= 2,
@@ -281,6 +287,7 @@
 		.gpio_wp	= 127,
 		.ext_clock	= 1,
 		.transceiver	= true,
+		.deferred	= true,
 	},
 	{
 		.mmc		= 3,
@@ -300,7 +307,7 @@
 	/* gpio + {0,1} is "mmc{0,1}_cd" (input/IRQ) */
 	omap3pandora_mmc[0].gpio_cd = gpio + 0;
 	omap3pandora_mmc[1].gpio_cd = gpio + 1;
-	omap2_hsmmc_init(omap3pandora_mmc);
+	omap_hsmmc_late_init(omap3pandora_mmc);
 
 	/* gpio + 13 drives 32kHz buffer for wifi module */
 	gpio_32khz = gpio + 13;
@@ -343,7 +350,7 @@
 };
 
 static struct regulator_consumer_supply pandora_usb_phy_supply[] = {
-	REGULATOR_SUPPLY("hsusb0", "ehci-omap.0"),
+	REGULATOR_SUPPLY("hsusb1", "ehci-omap.0"),
 };
 
 /* ads7846 on SPI and 2 nub controllers on I2C */
@@ -476,6 +483,10 @@
 
 static struct twl4030_bci_platform_data pandora_bci_data;
 
+static struct twl4030_power_data pandora_power_data = {
+	.use_poweroff	= true,
+};
+
 static struct twl4030_platform_data omap3pandora_twldata = {
 	.gpio		= &omap3pandora_gpio_data,
 	.vmmc1		= &pandora_vmmc1,
@@ -486,6 +497,7 @@
 	.vsim		= &pandora_vsim,
 	.keypad		= &pandora_kp_data,
 	.bci		= &pandora_bci_data,
+	.power		= &pandora_power_data,
 };
 
 static struct i2c_board_info __initdata omap3pandora_i2c3_boardinfo[] = {
@@ -557,17 +569,18 @@
 	&pandora_leds_gpio,
 	&pandora_keys_gpio,
 	&pandora_vwlan_device,
+	&pandora_backlight,
 };
 
 static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
 
-	.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
-	.port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
+	.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
+	.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
 	.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
 
 	.phy_reset  = true,
-	.reset_gpio_port[0]  = 16,
-	.reset_gpio_port[1]  = -EINVAL,
+	.reset_gpio_port[0]  = -EINVAL,
+	.reset_gpio_port[1]  = 16,
 	.reset_gpio_port[2]  = -EINVAL
 };
 
@@ -580,6 +593,7 @@
 static void __init omap3pandora_init(void)
 {
 	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+	omap_hsmmc_init(omap3pandora_mmc);
 	omap3pandora_i2c_init();
 	pandora_wl1251_init();
 	platform_add_devices(omap3pandora_devices,
diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c
index cb089a4..4dffc95 100644
--- a/arch/arm/mach-omap2/board-omap3stalker.c
+++ b/arch/arm/mach-omap2/board-omap3stalker.c
@@ -24,6 +24,7 @@
 #include <linux/input.h>
 #include <linux/gpio_keys.h>
 
+#include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
 #include <linux/mmc/host.h>
@@ -72,15 +73,6 @@
 
 static inline void __init omap3stalker_init_eth(void)
 {
-	struct clk *l3ck;
-	unsigned int rate;
-
-	l3ck = clk_get(NULL, "l3_ck");
-	if (IS_ERR(l3ck))
-		rate = 100000000;
-	else
-		rate = clk_get_rate(l3ck);
-
 	omap_mux_init_gpio(19, OMAP_PIN_INPUT_PULLUP);
 	gpmc_smsc911x_init(&smsc911x_cfg);
 }
@@ -209,10 +201,11 @@
 
 static struct omap2_hsmmc_info mmc[] = {
 	{
-	 .mmc		= 1,
-	 .caps		= MMC_CAP_4_BIT_DATA,
-	 .gpio_cd	= -EINVAL,
-	 .gpio_wp	= 23,
+		.mmc		= 1,
+		.caps		= MMC_CAP_4_BIT_DATA,
+		.gpio_cd	= -EINVAL,
+		.gpio_wp	= 23,
+		.deferred	= true,
 	 },
 	{}			/* Terminator */
 };
@@ -282,9 +275,8 @@
 			    unsigned gpio, unsigned ngpio)
 {
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
-	omap_mux_init_gpio(23, OMAP_PIN_INPUT);
 	mmc[0].gpio_cd = gpio + 0;
-	omap2_hsmmc_init(mmc);
+	omap_hsmmc_late_init(mmc);
 
 	/*
 	 * Most GPIOs are for USB OTG.  Some are mostly sent to
@@ -419,12 +411,21 @@
 };
 #endif
 
+static struct regulator_consumer_supply dummy_supplies[] = {
+	REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
+	REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
+};
+
 static void __init omap3_stalker_init(void)
 {
+	regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
 	omap3_mux_init(board_mux, OMAP_PACKAGE_CUS);
 	omap_board_config = omap3_stalker_config;
 	omap_board_config_size = ARRAY_SIZE(omap3_stalker_config);
 
+	omap_mux_init_gpio(23, OMAP_PIN_INPUT);
+	omap_hsmmc_init(mmc);
+
 	omap3_stalker_i2c_init();
 
 	platform_add_devices(omap3_stalker_devices,
diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c
index a0b851a..ae2251f 100644
--- a/arch/arm/mach-omap2/board-omap3touchbook.c
+++ b/arch/arm/mach-omap2/board-omap3touchbook.c
@@ -42,6 +42,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/flash.h>
+#include <asm/system_info.h>
 
 #include <plat/board.h>
 #include "common.h"
@@ -100,6 +101,7 @@
 		.mmc		= 1,
 		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
 		.gpio_wp	= 29,
+		.deferred	= true,
 	},
 	{}	/* Terminator */
 };
@@ -117,15 +119,9 @@
 static int touchbook_twl_gpio_setup(struct device *dev,
 		unsigned gpio, unsigned ngpio)
 {
-	if (system_rev >= 0x20 && system_rev <= 0x34301000) {
-		omap_mux_init_gpio(23, OMAP_PIN_INPUT);
-		mmc[0].gpio_wp = 23;
-	} else {
-		omap_mux_init_gpio(29, OMAP_PIN_INPUT);
-	}
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
 	mmc[0].gpio_cd = gpio + 0;
-	omap2_hsmmc_init(mmc);
+	omap_hsmmc_late_init(mmc);
 
 	/* REVISIT: need ehci-omap hooks for external VBUS
 	 * power switch and overcurrent detect
@@ -351,6 +347,14 @@
 
 	pm_power_off = omap3_touchbook_poweroff;
 
+	if (system_rev >= 0x20 && system_rev <= 0x34301000) {
+		omap_mux_init_gpio(23, OMAP_PIN_INPUT);
+		mmc[0].gpio_wp = 23;
+	} else {
+		omap_mux_init_gpio(29, OMAP_PIN_INPUT);
+	}
+	omap_hsmmc_init(mmc);
+
 	omap3_touchbook_i2c_init();
 	platform_add_devices(omap3_touchbook_devices,
 			ARRAY_SIZE(omap3_touchbook_devices));
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 28fc271..d8c0e89 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -28,6 +28,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/regulator/fixed.h>
 #include <linux/wl12xx.h>
+#include <linux/platform_data/omap-abe-twl6040.h>
 
 #include <mach/hardware.h>
 #include <asm/hardware/gic.h>
@@ -91,9 +92,40 @@
 	},
 };
 
+static struct omap_abe_twl6040_data panda_abe_audio_data = {
+	/* Audio out */
+	.has_hs		= ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT,
+	/* HandsFree through expasion connector */
+	.has_hf		= ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT,
+	/* PandaBoard: FM TX, PandaBoardES: can be connected to audio out */
+	.has_aux	= ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT,
+	/* PandaBoard: FM RX, PandaBoardES: audio in */
+	.has_afm	= ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT,
+	/* No jack detection. */
+	.jack_detection	= 0,
+	/* MCLK input is 38.4MHz */
+	.mclk_freq	= 38400000,
+
+};
+
+static struct platform_device panda_abe_audio = {
+	.name		= "omap-abe-twl6040",
+	.id		= -1,
+	.dev = {
+		.platform_data = &panda_abe_audio_data,
+	},
+};
+
+static struct platform_device btwilink_device = {
+	.name	= "btwilink",
+	.id	= -1,
+};
+
 static struct platform_device *panda_devices[] __initdata = {
 	&leds_gpio,
 	&wl1271_device,
+	&panda_abe_audio,
+	&btwilink_device,
 };
 
 static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
@@ -199,14 +231,13 @@
 };
 
 struct wl12xx_platform_data omap_panda_wlan_data  __initdata = {
-	.irq = OMAP_GPIO_IRQ(GPIO_WIFI_IRQ),
 	/* PANDA ref clock is 38.4 MHz */
 	.board_ref_clock = 2,
 };
 
 static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 {
-	int ret = 0;
+	int irq = 0;
 	struct platform_device *pdev = container_of(dev,
 				struct platform_device, dev);
 	struct omap_mmc_platform_data *pdata = dev->platform_data;
@@ -217,14 +248,15 @@
 	}
 	/* Setting MMC1 Card detect Irq */
 	if (pdev->id == 0) {
-		ret = twl6030_mmc_card_detect_config();
-		 if (ret)
+		irq = twl6030_mmc_card_detect_config();
+		if (irq < 0) {
 			dev_err(dev, "%s: Error card detect config(%d)\n",
-				__func__, ret);
-		 else
-			pdata->slots[0].card_detect = twl6030_mmc_card_detect;
+				__func__, irq);
+			return irq;
+		}
+		pdata->slots[0].card_detect = twl6030_mmc_card_detect;
 	}
-	return ret;
+	return 0;
 }
 
 static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
@@ -245,15 +277,32 @@
 {
 	struct omap2_hsmmc_info *c;
 
-	omap2_hsmmc_init(controllers);
+	omap_hsmmc_init(controllers);
 	for (c = controllers; c->mmc; c++)
-		omap4_twl6030_hsmmc_set_late_init(c->dev);
+		omap4_twl6030_hsmmc_set_late_init(&c->pdev->dev);
 
 	return 0;
 }
 
+static struct twl4030_codec_data twl6040_codec = {
+	/* single-step ramp for headset and handsfree */
+	.hs_left_step	= 0x0f,
+	.hs_right_step	= 0x0f,
+	.hf_left_step	= 0x1d,
+	.hf_right_step	= 0x1d,
+};
+
+static struct twl4030_audio_data twl6040_audio = {
+	.codec		= &twl6040_codec,
+	.audpwron_gpio	= 127,
+	.naudint_irq	= OMAP44XX_IRQ_SYS_2N,
+	.irq_base	= TWL6040_CODEC_IRQ_BASE,
+};
+
 /* Panda board uses the common PMIC configuration */
-static struct twl4030_platform_data omap4_panda_twldata;
+static struct twl4030_platform_data omap4_panda_twldata = {
+	.audio		= &twl6040_audio,
+};
 
 /*
  * Display monitor features are burnt in their EEPROM as EDID data. The EEPROM
@@ -461,7 +510,7 @@
 	.default_device	= &omap4_panda_dvi_device,
 };
 
-void omap4_panda_display_init(void)
+void __init omap4_panda_display_init(void)
 {
 	int r;
 
@@ -485,6 +534,20 @@
 	omap_mux_init_gpio(HDMI_GPIO_HPD, OMAP_PIN_INPUT_PULLDOWN);
 }
 
+static void omap4_panda_init_rev(void)
+{
+	if (cpu_is_omap443x()) {
+		/* PandaBoard 4430 */
+		/* ASoC audio configuration */
+		panda_abe_audio_data.card_name = "PandaBoard";
+		panda_abe_audio_data.has_hsmic = 1;
+	} else {
+		/* PandaBoard ES */
+		/* ASoC audio configuration */
+		panda_abe_audio_data.card_name = "PandaBoardES";
+	}
+}
+
 static void __init omap4_panda_init(void)
 {
 	int package = OMAP_PACKAGE_CBS;
@@ -494,10 +557,12 @@
 		package = OMAP_PACKAGE_CBL;
 	omap4_mux_init(board_mux, NULL, package);
 
+	omap_panda_wlan_data.irq = gpio_to_irq(GPIO_WIFI_IRQ);
 	ret = wl12xx_set_platform_data(&omap_panda_wlan_data);
 	if (ret)
 		pr_err("error setting wl12xx data: %d\n", ret);
 
+	omap4_panda_init_rev();
 	omap4_panda_i2c_init();
 	platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices));
 	platform_device_register(&omap_vwlan_device);
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 52c0cef..33aa391 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -407,8 +407,6 @@
 static int overo_twl_gpio_setup(struct device *dev,
 		unsigned gpio, unsigned ngpio)
 {
-	omap2_hsmmc_init(mmc);
-
 #if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
 	/* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
 	gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
@@ -500,11 +498,20 @@
 	{ OVERO_GPIO_BT_NRESET, GPIOF_OUT_INIT_HIGH,	"lcd bl enable" },
 };
 
+static struct regulator_consumer_supply dummy_supplies[] = {
+	REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
+	REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
+	REGULATOR_SUPPLY("vddvario", "smsc911x.1"),
+	REGULATOR_SUPPLY("vdd33a", "smsc911x.1"),
+};
+
 static void __init overo_init(void)
 {
 	int ret;
 
+	regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
 	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+	omap_hsmmc_init(mmc);
 	overo_i2c_init();
 	omap_display_init(&overo_dss_data);
 	omap_serial_init();
diff --git a/arch/arm/mach-omap2/board-rm680.c b/arch/arm/mach-omap2/board-rm680.c
index 8678b38..ae53d71 100644
--- a/arch/arm/mach-omap2/board-rm680.c
+++ b/arch/arm/mach-omap2/board-rm680.c
@@ -1,5 +1,5 @@
 /*
- * Board support file for Nokia RM-680.
+ * Board support file for Nokia RM-680/696.
  *
  * Copyright (C) 2010 Nokia
  *
@@ -120,7 +120,7 @@
 				ARRAY_SIZE(rm680_peripherals_devices));
 	rm680_i2c_init();
 	gpmc_onenand_init(board_onenand_data);
-	omap2_hsmmc_init(mmc);
+	omap_hsmmc_init(mmc);
 }
 
 #ifdef CONFIG_OMAP_MUX
@@ -154,3 +154,15 @@
 	.timer		= &omap3_timer,
 	.restart	= omap_prcm_restart,
 MACHINE_END
+
+MACHINE_START(NOKIA_RM696, "Nokia RM-696 board")
+	.atag_offset	= 0x100,
+	.reserve	= omap_reserve,
+	.map_io		= omap3_map_io,
+	.init_early	= omap3630_init_early,
+	.init_irq	= omap3_init_irq,
+	.handle_irq	= omap3_intc_handle_irq,
+	.init_machine	= rm680_init,
+	.timer		= &omap3_timer,
+	.restart	= omap_prcm_restart,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index acb4e77..d87ee06 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -25,6 +25,7 @@
 #include <linux/gpio_keys.h>
 #include <linux/mmc/host.h>
 #include <linux/power/isp1704_charger.h>
+#include <asm/system_info.h>
 
 #include <plat/mcspi.h>
 #include <plat/board.h>
@@ -138,17 +139,14 @@
 
 static struct omap2_mcspi_device_config wl1251_mcspi_config = {
 	.turbo_mode	= 0,
-	.single_channel	= 1,
 };
 
 static struct omap2_mcspi_device_config mipid_mcspi_config = {
 	.turbo_mode	= 0,
-	.single_channel	= 1,
 };
 
 static struct omap2_mcspi_device_config tsc2005_mcspi_config = {
 	.turbo_mode	= 0,
-	.single_channel	= 1,
 };
 
 static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = {
@@ -172,7 +170,6 @@
 		.modalias		= "tsc2005",
 		.bus_num		= 1,
 		.chip_select		= 0,
-		.irq			= OMAP_GPIO_IRQ(RX51_TSC2005_IRQ_GPIO),
 		.max_speed_hz		= 6000000,
 		.controller_data	= &tsc2005_mcspi_config,
 		.platform_data		= &tsc2005_pdata,
@@ -1105,6 +1102,11 @@
 	.esd_timeout_ms		= 8000,
 };
 
+static struct gpio rx51_tsc2005_gpios[] __initdata = {
+	{ RX51_TSC2005_IRQ_GPIO,   GPIOF_IN,		"tsc2005 IRQ"	},
+	{ RX51_TSC2005_RESET_GPIO, GPIOF_OUT_INIT_HIGH,	"tsc2005 reset"	},
+};
+
 static void rx51_tsc2005_set_reset(bool enable)
 {
 	gpio_set_value(RX51_TSC2005_RESET_GPIO, enable);
@@ -1114,20 +1116,20 @@
 {
 	int r;
 
-	r = gpio_request_one(RX51_TSC2005_IRQ_GPIO, GPIOF_IN, "tsc2005 IRQ");
+	omap_mux_init_gpio(RX51_TSC2005_RESET_GPIO, OMAP_PIN_OUTPUT);
+	omap_mux_init_gpio(RX51_TSC2005_IRQ_GPIO, OMAP_PIN_INPUT_PULLUP);
+
+	r = gpio_request_array(rx51_tsc2005_gpios,
+			       ARRAY_SIZE(rx51_tsc2005_gpios));
 	if (r < 0) {
-		printk(KERN_ERR "unable to get %s GPIO\n", "tsc2005 IRQ");
-		rx51_peripherals_spi_board_info[RX51_SPI_TSC2005].irq = 0;
+		printk(KERN_ERR "tsc2005 board initialization failed\n");
+		tsc2005_pdata.esd_timeout_ms = 0;
+		return;
 	}
 
-	r = gpio_request_one(RX51_TSC2005_RESET_GPIO, GPIOF_OUT_INIT_HIGH,
-		"tsc2005 reset");
-	if (r >= 0) {
-		tsc2005_pdata.set_reset = rx51_tsc2005_set_reset;
-	} else {
-		printk(KERN_ERR "unable to get %s GPIO\n", "tsc2005 reset");
-		tsc2005_pdata.esd_timeout_ms = 0;
-	}
+	tsc2005_pdata.set_reset = rx51_tsc2005_set_reset;
+	rx51_peripherals_spi_board_info[RX51_SPI_TSC2005].irq =
+				gpio_to_irq(RX51_TSC2005_IRQ_GPIO);
 }
 
 void __init rx51_peripherals_init(void)
@@ -1145,7 +1147,7 @@
 
 	partition = omap_mux_get("core");
 	if (partition)
-		omap2_hsmmc_init(mmc);
+		omap_hsmmc_init(mmc);
 
 	rx51_charger_init();
 }
diff --git a/arch/arm/mach-omap2/board-zoom-debugboard.c b/arch/arm/mach-omap2/board-zoom-debugboard.c
index 369c2eb..f64f441 100644
--- a/arch/arm/mach-omap2/board-zoom-debugboard.c
+++ b/arch/arm/mach-omap2/board-zoom-debugboard.c
@@ -14,6 +14,9 @@
 #include <linux/smsc911x.h>
 #include <linux/interrupt.h>
 
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
+
 #include <plat/gpmc.h>
 #include <plat/gpmc-smsc911x.h>
 
@@ -43,7 +46,6 @@
 static struct plat_serial8250_port serial_platform_data[] = {
 	{
 		.mapbase	= ZOOM_UART_BASE,
-		.irq		= OMAP_GPIO_IRQ(102),
 		.flags		= UPF_BOOT_AUTOCONF|UPF_IOREMAP|UPF_SHARE_IRQ,
 		.irqflags	= IRQF_SHARED | IRQF_TRIGGER_RISING,
 		.iotype		= UPIO_MEM,
@@ -89,6 +91,8 @@
 	if (gpio_request_one(quart_gpio, GPIOF_IN, "TL16CP754C GPIO") < 0)
 		printk(KERN_ERR "Failed to request GPIO%d for TL16CP754C\n",
 								quart_gpio);
+
+	serial_platform_data[0].irq = gpio_to_irq(102);
 }
 
 static inline int omap_zoom_debugboard_detect(void)
@@ -116,11 +120,17 @@
 	&zoom_debugboard_serial_device,
 };
 
+static struct regulator_consumer_supply dummy_supplies[] = {
+	REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
+	REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
+};
+
 int __init zoom_debugboard_init(void)
 {
 	if (!omap_zoom_debugboard_detect())
 		return 0;
 
+	regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
 	zoom_init_smsc911x();
 	zoom_init_quaduart();
 	return platform_add_devices(zoom_devices, ARRAY_SIZE(zoom_devices));
diff --git a/arch/arm/mach-omap2/board-zoom-display.c b/arch/arm/mach-omap2/board-zoom-display.c
index d4683ba..a43a765 100644
--- a/arch/arm/mach-omap2/board-zoom-display.c
+++ b/arch/arm/mach-omap2/board-zoom-display.c
@@ -55,6 +55,7 @@
 
 static int zoom_set_bl_intensity(struct omap_dss_device *dssdev, int level)
 {
+#ifdef CONFIG_TWL4030_CORE
 	unsigned char c;
 	u8 mux_pwm, enb_pwm;
 
@@ -90,6 +91,9 @@
 	c = ((50 * (100 - level)) / 100) + 1;
 	twl_i2c_write_u8(TWL4030_MODULE_PWM1, 0x7F, TWL_LED_PWMOFF);
 	twl_i2c_write_u8(TWL4030_MODULE_PWM1, c, TWL_LED_PWMON);
+#else
+	pr_warn("Backlight not enabled\n");
+#endif
 
 	return 0;
 }
@@ -117,7 +121,6 @@
 
 static struct omap2_mcspi_device_config dss_lcd_mcspi_config = {
 	.turbo_mode		= 1,
-	.single_channel	= 1,  /* 0: slave, 1: master */
 };
 
 static struct spi_board_info nec_8048_spi_board_info[] __initdata = {
diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c
index c126461..b797cb2 100644
--- a/arch/arm/mach-omap2/board-zoom-peripherals.c
+++ b/arch/arm/mach-omap2/board-zoom-peripherals.c
@@ -193,7 +193,6 @@
 };
 
 static struct wl12xx_platform_data omap_zoom_wlan_data __initdata = {
-	.irq = OMAP_GPIO_IRQ(OMAP_ZOOM_WLAN_IRQ_GPIO),
 	/* ZOOM ref clock is 26 MHz */
 	.board_ref_clock = 1,
 };
@@ -205,6 +204,7 @@
 		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_wp	= -EINVAL,
 		.power_saving	= true,
+		.deferred	= true,
 	},
 	{
 		.name		= "internal",
@@ -233,7 +233,7 @@
 
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
 	mmc[0].gpio_cd = gpio + 0;
-	omap2_hsmmc_init(mmc);
+	omap_hsmmc_late_init(mmc);
 
 	ret = gpio_request_one(LCD_PANEL_ENABLE_GPIO, GPIOF_OUT_INIT_LOW,
 			       "lcd enable");
@@ -296,11 +296,15 @@
 
 void __init zoom_peripherals_init(void)
 {
-	int ret = wl12xx_set_platform_data(&omap_zoom_wlan_data);
+	int ret;
+
+	omap_zoom_wlan_data.irq = gpio_to_irq(OMAP_ZOOM_WLAN_IRQ_GPIO);
+	ret = wl12xx_set_platform_data(&omap_zoom_wlan_data);
 
 	if (ret)
 		pr_err("error setting wl12xx data: %d\n", ret);
 
+	omap_hsmmc_init(mmc);
 	omap_i2c_init();
 	platform_device_register(&omap_vwlan_device);
 	usb_musb_init(NULL);
diff --git a/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c b/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c
index 39f9d5a..7072e0d 100644
--- a/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c
+++ b/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c
@@ -33,6 +33,7 @@
 #include <linux/cpufreq.h>
 #include <linux/slab.h>
 
+#include <plat/cpu.h>
 #include <plat/clock.h>
 #include <plat/sram.h>
 #include <plat/sdrc.h>
diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c
index e25364d..04d551b 100644
--- a/arch/arm/mach-omap2/clkt_clksel.c
+++ b/arch/arm/mach-omap2/clkt_clksel.c
@@ -43,6 +43,7 @@
 #include <linux/errno.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/bug.h>
 
 #include <plat/clock.h>
 
diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c
index e069a9b..cd7fd0f 100644
--- a/arch/arm/mach-omap2/clkt_dpll.c
+++ b/arch/arm/mach-omap2/clkt_dpll.c
@@ -22,6 +22,7 @@
 #include <asm/div64.h>
 
 #include <plat/clock.h>
+#include <plat/cpu.h>
 
 #include "clock.h"
 #include "cm-regbits-24xx.h"
diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c
index 61ad385..bace930 100644
--- a/arch/arm/mach-omap2/clock2420_data.c
+++ b/arch/arm/mach-omap2/clock2420_data.c
@@ -14,11 +14,14 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/list.h>
 
+#include <plat/hardware.h>
 #include <plat/clkdev_omap.h>
 
+#include "iomap.h"
 #include "clock.h"
 #include "clock2xxx.h"
 #include "opp2xxx.h"
diff --git a/arch/arm/mach-omap2/clock2430.c b/arch/arm/mach-omap2/clock2430.c
index d87bc9c..dfda9a3 100644
--- a/arch/arm/mach-omap2/clock2430.c
+++ b/arch/arm/mach-omap2/clock2430.c
@@ -21,8 +21,10 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 
+#include <plat/hardware.h>
 #include <plat/clock.h>
 
+#include "iomap.h"
 #include "clock.h"
 #include "clock2xxx.h"
 #include "cm2xxx_3xxx.h"
diff --git a/arch/arm/mach-omap2/clock2430_data.c b/arch/arm/mach-omap2/clock2430_data.c
index 0cc1287..3b4d09a 100644
--- a/arch/arm/mach-omap2/clock2430_data.c
+++ b/arch/arm/mach-omap2/clock2430_data.c
@@ -17,8 +17,10 @@
 #include <linux/clk.h>
 #include <linux/list.h>
 
+#include <plat/hardware.h>
 #include <plat/clkdev_omap.h>
 
+#include "iomap.h"
 #include "clock.h"
 #include "clock2xxx.h"
 #include "opp2xxx.h"
diff --git a/arch/arm/mach-omap2/clock2xxx.c b/arch/arm/mach-omap2/clock2xxx.c
index 80bb0f0..1250009 100644
--- a/arch/arm/mach-omap2/clock2xxx.c
+++ b/arch/arm/mach-omap2/clock2xxx.c
@@ -22,6 +22,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 
+#include <plat/cpu.h>
 #include <plat/clock.h>
 
 #include "clock.h"
diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c
index 952c3e0..794d827 100644
--- a/arch/arm/mach-omap2/clock3xxx.c
+++ b/arch/arm/mach-omap2/clock3xxx.c
@@ -21,6 +21,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 
+#include <plat/hardware.h>
 #include <plat/clock.h>
 
 #include "clock.h"
diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index d75e5f6..f4a626f7 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -19,15 +19,17 @@
 #include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/list.h>
+#include <linux/io.h>
 
+#include <plat/hardware.h>
 #include <plat/clkdev_omap.h>
 
+#include "iomap.h"
 #include "clock.h"
 #include "clock3xxx.h"
 #include "clock34xx.h"
 #include "clock36xx.h"
 #include "clock3517.h"
-
 #include "cm2xxx_3xxx.h"
 #include "cm-regbits-34xx.h"
 #include "prm2xxx_3xxx.h"
@@ -745,7 +747,7 @@
 	.parent		= &dpll4_ck,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_CLKSEL),
-	.clksel_mask	= OMAP3430_CLKSEL_TV_MASK,
+	.clksel_mask	= OMAP3630_CLKSEL_TV_MASK,
 	.clksel		= dpll4_clksel,
 	.clkdm_name	= "dpll4_clkdm",
 	.recalc		= &omap2_clksel_recalc,
@@ -830,7 +832,7 @@
 	.parent		= &dpll4_ck,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_CLKSEL),
-	.clksel_mask	= OMAP3430_CLKSEL_DSS1_MASK,
+	.clksel_mask	= OMAP3630_CLKSEL_DSS1_MASK,
 	.clksel		= dpll4_clksel,
 	.clkdm_name	= "dpll4_clkdm",
 	.recalc		= &omap2_clksel_recalc,
@@ -857,7 +859,7 @@
 	.parent		= &dpll4_ck,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_CLKSEL),
-	.clksel_mask	= OMAP3430_CLKSEL_CAM_MASK,
+	.clksel_mask	= OMAP3630_CLKSEL_CAM_MASK,
 	.clksel		= dpll4_clksel,
 	.clkdm_name	= "dpll4_clkdm",
 	.set_rate	= &omap2_clksel_set_rate,
@@ -884,7 +886,7 @@
 	.parent		= &dpll4_ck,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
-	.clksel_mask	= OMAP3430_DIV_DPLL4_MASK,
+	.clksel_mask	= OMAP3630_DIV_DPLL4_MASK,
 	.clksel		= dpll4_clksel,
 	.clkdm_name	= "dpll4_clkdm",
 	.recalc		= &omap2_clksel_recalc,
@@ -1392,6 +1394,7 @@
 	.name		= "cpefuse_fck",
 	.ops		= &clkops_omap2_dflt,
 	.parent		= &sys_ck,
+	.clkdm_name	= "core_l4_clkdm",
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, OMAP3430ES2_CM_FCLKEN3),
 	.enable_bit	= OMAP3430ES2_EN_CPEFUSE_SHIFT,
 	.recalc		= &followparent_recalc,
@@ -1401,6 +1404,7 @@
 	.name		= "ts_fck",
 	.ops		= &clkops_omap2_dflt,
 	.parent		= &omap_32k_fck,
+	.clkdm_name	= "core_l4_clkdm",
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, OMAP3430ES2_CM_FCLKEN3),
 	.enable_bit	= OMAP3430ES2_EN_TS_SHIFT,
 	.recalc		= &followparent_recalc,
@@ -1410,6 +1414,7 @@
 	.name		= "usbtll_fck",
 	.ops		= &clkops_omap2_dflt_wait,
 	.parent		= &dpll5_m2_ck,
+	.clkdm_name	= "core_l4_clkdm",
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, OMAP3430ES2_CM_FCLKEN3),
 	.enable_bit	= OMAP3430ES2_EN_USBTLL_SHIFT,
 	.recalc		= &followparent_recalc,
@@ -1615,6 +1620,7 @@
 	.name		= "fshostusb_fck",
 	.ops		= &clkops_omap2_dflt_wait,
 	.parent		= &core_48m_fck,
+	.clkdm_name	= "core_l4_clkdm",
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP3430ES1_EN_FSHOSTUSB_SHIFT,
 	.recalc		= &followparent_recalc,
@@ -2041,6 +2047,7 @@
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
 	.enable_bit	= OMAP3430_EN_OMAPCTRL_SHIFT,
 	.flags		= ENABLE_ON_INIT,
+	.clkdm_name	= "core_l4_clkdm",
 	.recalc		= &followparent_recalc,
 };
 
@@ -2092,6 +2099,7 @@
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
 	.clksel_mask	= OMAP3430ES1_CLKSEL_FSHOSTUSB_MASK,
 	.clksel		= usb_l4_clksel,
+	.clkdm_name	= "core_l4_clkdm",
 	.recalc		= &omap2_clksel_recalc,
 };
 
@@ -3465,8 +3473,8 @@
 	CLK(NULL,	"ipss_ick",	&ipss_ick,	CK_AM35XX),
 	CLK(NULL,	"rmii_ck",	&rmii_ck,	CK_AM35XX),
 	CLK(NULL,	"pclk_ck",	&pclk_ck,	CK_AM35XX),
-	CLK("davinci_emac",	"emac_clk",	&emac_ick,	CK_AM35XX),
-	CLK("davinci_emac",	"phy_clk",	&emac_fck,	CK_AM35XX),
+	CLK("davinci_emac",	NULL,	&emac_ick,	CK_AM35XX),
+	CLK("davinci_mdio.0",	NULL,	&emac_fck,	CK_AM35XX),
 	CLK("vpfe-capture",	"master",	&vpfe_ick,	CK_AM35XX),
 	CLK("vpfe-capture",	"slave",	&vpfe_fck,	CK_AM35XX),
 	CLK("musb-am35x",	"ick",		&hsotgusb_ick_am35xx,	CK_AM35XX),
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index 08e86d7..fa6ea65 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -26,8 +26,12 @@
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/clk.h>
+#include <linux/io.h>
+
+#include <plat/hardware.h>
 #include <plat/clkdev_omap.h>
 
+#include "iomap.h"
 #include "clock.h"
 #include "clock44xx.h"
 #include "cm1_44xx.h"
@@ -953,8 +957,8 @@
 	.modes		= (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
 	.autoidle_reg	= OMAP4430_CM_AUTOIDLE_DPLL_USB,
 	.idlest_reg	= OMAP4430_CM_IDLEST_DPLL_USB,
-	.mult_mask	= OMAP4430_DPLL_MULT_MASK,
-	.div1_mask	= OMAP4430_DPLL_DIV_MASK,
+	.mult_mask	= OMAP4430_DPLL_MULT_USB_MASK,
+	.div1_mask	= OMAP4430_DPLL_DIV_0_7_MASK,
 	.enable_mask	= OMAP4430_DPLL_EN_MASK,
 	.autoidle_mask	= OMAP4430_AUTO_DPLL_MODE_MASK,
 	.idlest_mask	= OMAP4430_ST_DPLL_CLK_MASK,
@@ -974,6 +978,7 @@
 	.recalc		= &omap3_dpll_recalc,
 	.round_rate	= &omap2_dpll_round_rate,
 	.set_rate	= &omap3_noncore_dpll_set_rate,
+	.clkdm_name	= "l3_init_clkdm",
 };
 
 static struct clk dpll_usb_clkdcoldo_ck = {
diff --git a/arch/arm/mach-omap2/clockdomains44xx_data.c b/arch/arm/mach-omap2/clockdomains44xx_data.c
index 9299ac2..bd7ed13 100644
--- a/arch/arm/mach-omap2/clockdomains44xx_data.c
+++ b/arch/arm/mach-omap2/clockdomains44xx_data.c
@@ -390,7 +390,7 @@
 	.prcm_partition	  = OMAP4430_PRM_PARTITION,
 	.cm_inst	  = OMAP4430_PRM_EMU_CM_INST,
 	.clkdm_offs	  = OMAP4430_PRM_EMU_CM_EMU_CDOFFS,
-	.flags		  = CLKDM_CAN_HWSUP,
+	.flags		  = CLKDM_CAN_ENABLE_AUTO | CLKDM_CAN_FORCE_WAKEUP,
 };
 
 static struct clockdomain l3_dma_44xx_clkdm = {
diff --git a/arch/arm/mach-omap2/cm2xxx_3xxx.c b/arch/arm/mach-omap2/cm2xxx_3xxx.c
index 04d39cd..389f9f8 100644
--- a/arch/arm/mach-omap2/cm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/cm2xxx_3xxx.c
@@ -18,8 +18,10 @@
 #include <linux/err.h>
 #include <linux/io.h>
 
-#include "common.h"
+#include <plat/hardware.h>
 
+#include "iomap.h"
+#include "common.h"
 #include "cm.h"
 #include "cm2xxx_3xxx.h"
 #include "cm-regbits-24xx.h"
diff --git a/arch/arm/mach-omap2/cm44xx.c b/arch/arm/mach-omap2/cm44xx.c
index 6a83630..535d66e 100644
--- a/arch/arm/mach-omap2/cm44xx.c
+++ b/arch/arm/mach-omap2/cm44xx.c
@@ -18,8 +18,8 @@
 #include <linux/err.h>
 #include <linux/io.h>
 
+#include "iomap.h"
 #include "common.h"
-
 #include "cm.h"
 #include "cm1_44xx.h"
 #include "cm2_44xx.h"
diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c
index 6204dea..bd8810c 100644
--- a/arch/arm/mach-omap2/cminst44xx.c
+++ b/arch/arm/mach-omap2/cminst44xx.c
@@ -20,8 +20,8 @@
 #include <linux/err.h>
 #include <linux/io.h>
 
+#include "iomap.h"
 #include "common.h"
-
 #include "cm.h"
 #include "cm1_44xx.h"
 #include "cm2_44xx.h"
diff --git a/arch/arm/mach-omap2/common-board-devices.c b/arch/arm/mach-omap2/common-board-devices.c
index bcb0c58..1706ebc 100644
--- a/arch/arm/mach-omap2/common-board-devices.c
+++ b/arch/arm/mach-omap2/common-board-devices.c
@@ -33,7 +33,6 @@
 	defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
 static struct omap2_mcspi_device_config ads7846_mcspi_config = {
 	.turbo_mode	= 0,
-	.single_channel	= 1,	/* 0: slave, 1: master */
 };
 
 static struct ads7846_platform_data ads7846_config = {
@@ -76,13 +75,15 @@
 			gpio_set_debounce(gpio_pendown, gpio_debounce);
 	}
 
-	ads7846_config.gpio_pendown = gpio_pendown;
-
 	spi_bi->bus_num	= bus_num;
-	spi_bi->irq	= OMAP_GPIO_IRQ(gpio_pendown);
+	spi_bi->irq	= gpio_to_irq(gpio_pendown);
 
-	if (board_pdata)
+	if (board_pdata) {
+		board_pdata->gpio_pendown = gpio_pendown;
 		spi_bi->platform_data = board_pdata;
+	} else {
+		ads7846_config.gpio_pendown = gpio_pendown;
+	}
 
 	spi_register_board_info(&ads7846_spi_board_info, 1);
 }
diff --git a/arch/arm/mach-omap2/common.c b/arch/arm/mach-omap2/common.c
index aaf4211..1549c11 100644
--- a/arch/arm/mach-omap2/common.c
+++ b/arch/arm/mach-omap2/common.c
@@ -17,12 +17,13 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 
-#include "common.h"
+#include <plat/hardware.h>
 #include <plat/board.h>
 #include <plat/mux.h>
-
 #include <plat/clock.h>
 
+#include "iomap.h"
+#include "common.h"
 #include "sdrc.h"
 #include "control.h"
 
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 7e9338e..57da7f4 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -134,6 +134,8 @@
 void ti81xx_map_io(void);
 void omap_barriers_init(void);
 
+extern void __init omap_init_consistent_dma_size(void);
+
 /**
  * omap_test_timeout - busy-loop, testing a condition
  * @cond: condition to test until it evaluates to true
@@ -175,6 +177,18 @@
 extern void __iomem *omap4_get_l2cache_base(void);
 #endif
 
+struct device_node;
+#ifdef CONFIG_OF
+int __init omap_intc_of_init(struct device_node *node,
+			     struct device_node *parent);
+#else
+int __init omap_intc_of_init(struct device_node *node,
+			     struct device_node *parent)
+{
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_SMP
 extern void __iomem *omap4_get_scu_base(void);
 #else
@@ -236,5 +250,10 @@
 	return 0;
 }
 #endif
+
+struct omap_sdrc_params;
+extern void omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
+				      struct omap_sdrc_params *sdrc_cs1);
+
 #endif /* __ASSEMBLER__ */
 #endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */
diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
index 114c037..08e674b 100644
--- a/arch/arm/mach-omap2/control.c
+++ b/arch/arm/mach-omap2/control.c
@@ -15,9 +15,11 @@
 #include <linux/kernel.h>
 #include <linux/io.h>
 
-#include "common.h"
+#include <plat/hardware.h>
 #include <plat/sdrc.h>
 
+#include "iomap.h"
+#include "common.h"
 #include "cm-regbits-34xx.h"
 #include "prm-regbits-34xx.h"
 #include "prm2xxx_3xxx.h"
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index 0ba68d3..a406fd0 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -16,7 +16,6 @@
 #ifndef __ARCH_ARM_MACH_OMAP2_CONTROL_H
 #define __ARCH_ARM_MACH_OMAP2_CONTROL_H
 
-#include <mach/io.h>
 #include <mach/ctrl_module_core_44xx.h>
 #include <mach/ctrl_module_wkup_44xx.h>
 #include <mach/ctrl_module_pad_core_44xx.h>
@@ -339,6 +338,11 @@
 #define AM35XX_VPFE_PCLK_SW_RST		BIT(4)
 
 /*
+ * CONTROL AM33XX STATUS register
+ */
+#define AM33XX_CONTROL_STATUS		0x040
+
+/*
  * CONTROL OMAP STATUS register to identify OMAP3 features
  */
 #define OMAP3_CONTROL_OMAP_STATUS	0x044c
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 464cffd..5358664 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -87,29 +87,14 @@
 	return 0;
 }
 
-/**
- * omap3_enter_idle - Programs OMAP3 to enter the specified state
- * @dev: cpuidle device
- * @drv: cpuidle driver
- * @index: the index of state to be entered
- *
- * Called from the CPUidle framework to program the device to the
- * specified target state selected by the governor.
- */
-static int omap3_enter_idle(struct cpuidle_device *dev,
+static int __omap3_enter_idle(struct cpuidle_device *dev,
 				struct cpuidle_driver *drv,
 				int index)
 {
 	struct omap3_idle_statedata *cx =
 			cpuidle_get_statedata(&dev->states_usage[index]);
-	struct timespec ts_preidle, ts_postidle, ts_idle;
 	u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
-	int idle_time;
 
-	/* Used to keep track of the total time in idle */
-	getnstimeofday(&ts_preidle);
-
-	local_irq_disable();
 	local_fiq_disable();
 
 	pwrdm_set_next_pwrst(mpu_pd, mpu_state);
@@ -148,22 +133,29 @@
 	}
 
 return_sleep_time:
-	getnstimeofday(&ts_postidle);
-	ts_idle = timespec_sub(ts_postidle, ts_preidle);
 
-	local_irq_enable();
 	local_fiq_enable();
 
-	idle_time = ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * \
-								USEC_PER_SEC;
-
-	/* Update cpuidle counters */
-	dev->last_residency = idle_time;
-
 	return index;
 }
 
 /**
+ * omap3_enter_idle - Programs OMAP3 to enter the specified state
+ * @dev: cpuidle device
+ * @drv: cpuidle driver
+ * @index: the index of state to be entered
+ *
+ * Called from the CPUidle framework to program the device to the
+ * specified target state selected by the governor.
+ */
+static inline int omap3_enter_idle(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
+				int index)
+{
+	return cpuidle_wrap_enter(dev, drv, index, __omap3_enter_idle);
+}
+
+/**
  * next_valid_state - Find next valid C-state
  * @dev: cpuidle device
  * @drv: cpuidle driver
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c
index 72e018b..f386cbe 100644
--- a/arch/arm/mach-omap2/cpuidle44xx.c
+++ b/arch/arm/mach-omap2/cpuidle44xx.c
@@ -62,15 +62,9 @@
 {
 	struct omap4_idle_statedata *cx =
 			cpuidle_get_statedata(&dev->states_usage[index]);
-	struct timespec ts_preidle, ts_postidle, ts_idle;
 	u32 cpu1_state;
-	int idle_time;
 	int cpu_id = smp_processor_id();
 
-	/* Used to keep track of the total time in idle */
-	getnstimeofday(&ts_preidle);
-
-	local_irq_disable();
 	local_fiq_disable();
 
 	/*
@@ -128,26 +122,17 @@
 	if (index > 0)
 		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id);
 
-	getnstimeofday(&ts_postidle);
-	ts_idle = timespec_sub(ts_postidle, ts_preidle);
-
-	local_irq_enable();
 	local_fiq_enable();
 
-	idle_time = ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * \
-								USEC_PER_SEC;
-
-	/* Update cpuidle counters */
-	dev->last_residency = idle_time;
-
 	return index;
 }
 
 DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev);
 
 struct cpuidle_driver omap4_idle_driver = {
-	.name =		"omap4_idle",
-	.owner =	THIS_MODULE,
+	.name				= "omap4_idle",
+	.owner				= THIS_MODULE,
+	.en_core_tk_irqen		= 1,
 };
 
 static inline void _fill_cstate(struct cpuidle_driver *drv,
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 283d11e..e433603 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -17,6 +17,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/platform_data/omap4-keypad.h>
 
 #include <mach/hardware.h>
 #include <mach/irqs.h>
@@ -24,9 +25,8 @@
 #include <asm/mach/map.h>
 #include <asm/pmu.h>
 
-#include <plat/tc.h>
+#include "iomap.h"
 #include <plat/board.h>
-#include <plat/mcbsp.h>
 #include <plat/mmc.h>
 #include <plat/dma.h>
 #include <plat/omap_hwmod.h>
@@ -276,7 +276,7 @@
 }
 
 #if defined(CONFIG_OMAP_MBOX_FWK) || defined(CONFIG_OMAP_MBOX_FWK_MODULE)
-static inline void omap_init_mbox(void)
+static inline void __init omap_init_mbox(void)
 {
 	struct omap_hwmod *oh;
 	struct platform_device *pdev;
@@ -304,29 +304,8 @@
 	.id	= -1,
 };
 
-/*
- * OMAP2420 has 2 McBSP ports
- * OMAP2430 has 5 McBSP ports
- * OMAP3 has 5 McBSP ports
- * OMAP4 has 4 McBSP ports
- */
-OMAP_MCBSP_PLATFORM_DEVICE(1);
-OMAP_MCBSP_PLATFORM_DEVICE(2);
-OMAP_MCBSP_PLATFORM_DEVICE(3);
-OMAP_MCBSP_PLATFORM_DEVICE(4);
-OMAP_MCBSP_PLATFORM_DEVICE(5);
-
 static void omap_init_audio(void)
 {
-	platform_device_register(&omap_mcbsp1);
-	platform_device_register(&omap_mcbsp2);
-	if (cpu_is_omap243x() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
-		platform_device_register(&omap_mcbsp3);
-		platform_device_register(&omap_mcbsp4);
-	}
-	if (cpu_is_omap243x() || cpu_is_omap34xx())
-		platform_device_register(&omap_mcbsp5);
-
 	platform_device_register(&omap_pcm);
 }
 
@@ -337,7 +316,7 @@
 #if defined(CONFIG_SND_OMAP_SOC_MCPDM) || \
 		defined(CONFIG_SND_OMAP_SOC_MCPDM_MODULE)
 
-static void omap_init_mcpdm(void)
+static void __init omap_init_mcpdm(void)
 {
 	struct omap_hwmod *oh;
 	struct platform_device *pdev;
@@ -358,7 +337,7 @@
 #if defined(CONFIG_SND_OMAP_SOC_DMIC) || \
 		defined(CONFIG_SND_OMAP_SOC_DMIC_MODULE)
 
-static void omap_init_dmic(void)
+static void __init omap_init_dmic(void)
 {
 	struct omap_hwmod *oh;
 	struct platform_device *pdev;
@@ -380,7 +359,7 @@
 
 #include <plat/mcspi.h>
 
-static int omap_mcspi_init(struct omap_hwmod *oh, void *unused)
+static int __init omap_mcspi_init(struct omap_hwmod *oh, void *unused)
 {
 	struct platform_device *pdev;
 	char *name = "omap2_mcspi";
@@ -654,9 +633,7 @@
 /*-------------------------------------------------------------------------*/
 
 #if defined(CONFIG_HDQ_MASTER_OMAP) || defined(CONFIG_HDQ_MASTER_OMAP_MODULE)
-#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430)
 #define OMAP_HDQ_BASE	0x480B2000
-#endif
 static struct resource omap_hdq_resources[] = {
 	{
 		.start		= OMAP_HDQ_BASE,
@@ -679,7 +656,10 @@
 };
 static inline void omap_hdq_init(void)
 {
-	(void) platform_device_register(&omap_hdq_dev);
+	if (cpu_is_omap2420())
+		return;
+
+	platform_device_register(&omap_hdq_dev);
 }
 #else
 static inline void omap_hdq_init(void) {}
diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c
index 3677b1f..db5a88a 100644
--- a/arch/arm/mach-omap2/display.c
+++ b/arch/arm/mach-omap2/display.c
@@ -30,6 +30,7 @@
 #include <plat/omap-pm.h>
 #include "common.h"
 
+#include "iomap.h"
 #include "mux.h"
 #include "control.h"
 #include "display.h"
@@ -98,7 +99,7 @@
 	{ "dss_hdmi", "omapdss_hdmi", -1 },
 };
 
-static void omap4_hdmi_mux_pads(enum omap_hdmi_flags flags)
+static void __init omap4_hdmi_mux_pads(enum omap_hdmi_flags flags)
 {
 	u32 reg;
 	u16 control_i2c_1;
@@ -157,7 +158,7 @@
 	return 0;
 }
 
-int omap_hdmi_init(enum omap_hdmi_flags flags)
+int __init omap_hdmi_init(enum omap_hdmi_flags flags)
 {
 	if (cpu_is_omap44xx())
 		omap4_hdmi_mux_pads(flags);
diff --git a/arch/arm/mach-omap2/dma.c b/arch/arm/mach-omap2/dma.c
index a59a45a..b19d849 100644
--- a/arch/arm/mach-omap2/dma.c
+++ b/arch/arm/mach-omap2/dma.c
@@ -227,7 +227,7 @@
 
 	dma_stride		= OMAP2_DMA_STRIDE;
 	dma_common_ch_start	= CSDP;
-	if (cpu_is_omap3630() || cpu_is_omap4430())
+	if (cpu_is_omap3630() || cpu_is_omap44xx())
 		dma_common_ch_end = CCDN;
 	else
 		dma_common_ch_end = CCFN;
diff --git a/arch/arm/mach-omap2/emu.c b/arch/arm/mach-omap2/emu.c
index 9c442e2..e28e761 100644
--- a/arch/arm/mach-omap2/emu.c
+++ b/arch/arm/mach-omap2/emu.c
@@ -21,6 +21,10 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alexander Shishkin");
 
@@ -30,29 +34,8 @@
 #define ETB_BASE	(L4_EMU_34XX_PHYS + 0x1b000)
 #define DAPCTL		(L4_EMU_34XX_PHYS + 0x1d000)
 
-static struct amba_device omap3_etb_device = {
-	.dev		= {
-		.init_name = "etb",
-	},
-	.res		= {
-		.start	= ETB_BASE,
-		.end	= ETB_BASE + SZ_4K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	.periphid	= 0x000bb907,
-};
-
-static struct amba_device omap3_etm_device = {
-	.dev		= {
-		.init_name = "etm",
-	},
-	.res		= {
-		.start	= ETM_BASE,
-		.end	= ETM_BASE + SZ_4K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	.periphid	= 0x102bb921,
-};
+static AMBA_APB_DEVICE(omap3_etb, "etb", 0x000bb907, ETB_BASE, { }, NULL);
+static AMBA_APB_DEVICE(omap3_etm, "etm", 0x102bb921, ETM_BASE, { }, NULL);
 
 static int __init emu_init(void)
 {
@@ -66,4 +49,3 @@
 }
 
 subsys_initcall(emu_init);
-
diff --git a/arch/arm/mach-omap2/gpio.c b/arch/arm/mach-omap2/gpio.c
index 8cbfbc2..2f994e5 100644
--- a/arch/arm/mach-omap2/gpio.c
+++ b/arch/arm/mach-omap2/gpio.c
@@ -23,14 +23,18 @@
 
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
+#include <plat/omap-pm.h>
 
-static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
+#include "powerdomain.h"
+
+static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 {
 	struct platform_device *pdev;
 	struct omap_gpio_platform_data *pdata;
 	struct omap_gpio_dev_attr *dev_attr;
 	char *name = "omap_gpio";
 	int id;
+	struct powerdomain *pwrdm;
 
 	/*
 	 * extract the device id from name field available in the
@@ -52,7 +56,7 @@
 	pdata->bank_width = dev_attr->bank_width;
 	pdata->dbck_flag = dev_attr->dbck_flag;
 	pdata->virtual_irq_start = IH_GPIO_BASE + 32 * (id - 1);
-
+	pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
 	pdata->regs = kzalloc(sizeof(struct omap_gpio_reg_offs), GFP_KERNEL);
 	if (!pdata) {
 		pr_err("gpio%d: Memory allocation failed\n", id);
@@ -61,8 +65,15 @@
 
 	switch (oh->class->rev) {
 	case 0:
+		if (id == 1)
+			/* non-wakeup GPIO pins for OMAP2 Bank1 */
+			pdata->non_wakeup_gpios = 0xe203ffc0;
+		else if (id == 2)
+			/* non-wakeup GPIO pins for OMAP2 Bank2 */
+			pdata->non_wakeup_gpios = 0x08700040;
+		/* fall through */
+
 	case 1:
-		pdata->bank_type = METHOD_GPIO_24XX;
 		pdata->regs->revision = OMAP24XX_GPIO_REVISION;
 		pdata->regs->direction = OMAP24XX_GPIO_OE;
 		pdata->regs->datain = OMAP24XX_GPIO_DATAIN;
@@ -72,13 +83,19 @@
 		pdata->regs->irqstatus = OMAP24XX_GPIO_IRQSTATUS1;
 		pdata->regs->irqstatus2 = OMAP24XX_GPIO_IRQSTATUS2;
 		pdata->regs->irqenable = OMAP24XX_GPIO_IRQENABLE1;
+		pdata->regs->irqenable2 = OMAP24XX_GPIO_IRQENABLE2;
 		pdata->regs->set_irqenable = OMAP24XX_GPIO_SETIRQENABLE1;
 		pdata->regs->clr_irqenable = OMAP24XX_GPIO_CLEARIRQENABLE1;
 		pdata->regs->debounce = OMAP24XX_GPIO_DEBOUNCE_VAL;
 		pdata->regs->debounce_en = OMAP24XX_GPIO_DEBOUNCE_EN;
+		pdata->regs->ctrl = OMAP24XX_GPIO_CTRL;
+		pdata->regs->wkup_en = OMAP24XX_GPIO_WAKE_EN;
+		pdata->regs->leveldetect0 = OMAP24XX_GPIO_LEVELDETECT0;
+		pdata->regs->leveldetect1 = OMAP24XX_GPIO_LEVELDETECT1;
+		pdata->regs->risingdetect = OMAP24XX_GPIO_RISINGDETECT;
+		pdata->regs->fallingdetect = OMAP24XX_GPIO_FALLINGDETECT;
 		break;
 	case 2:
-		pdata->bank_type = METHOD_GPIO_44XX;
 		pdata->regs->revision = OMAP4_GPIO_REVISION;
 		pdata->regs->direction = OMAP4_GPIO_OE;
 		pdata->regs->datain = OMAP4_GPIO_DATAIN;
@@ -88,10 +105,17 @@
 		pdata->regs->irqstatus = OMAP4_GPIO_IRQSTATUS0;
 		pdata->regs->irqstatus2 = OMAP4_GPIO_IRQSTATUS1;
 		pdata->regs->irqenable = OMAP4_GPIO_IRQSTATUSSET0;
+		pdata->regs->irqenable2 = OMAP4_GPIO_IRQSTATUSSET1;
 		pdata->regs->set_irqenable = OMAP4_GPIO_IRQSTATUSSET0;
 		pdata->regs->clr_irqenable = OMAP4_GPIO_IRQSTATUSCLR0;
 		pdata->regs->debounce = OMAP4_GPIO_DEBOUNCINGTIME;
 		pdata->regs->debounce_en = OMAP4_GPIO_DEBOUNCENABLE;
+		pdata->regs->ctrl = OMAP4_GPIO_CTRL;
+		pdata->regs->wkup_en = OMAP4_GPIO_IRQWAKEN0;
+		pdata->regs->leveldetect0 = OMAP4_GPIO_LEVELDETECT0;
+		pdata->regs->leveldetect1 = OMAP4_GPIO_LEVELDETECT1;
+		pdata->regs->risingdetect = OMAP4_GPIO_RISINGDETECT;
+		pdata->regs->fallingdetect = OMAP4_GPIO_FALLINGDETECT;
 		break;
 	default:
 		WARN(1, "Invalid gpio bank_type\n");
@@ -99,6 +123,9 @@
 		return -EINVAL;
 	}
 
+	pwrdm = omap_hwmod_get_pwrdm(oh);
+	pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
+
 	pdev = omap_device_build(name, id - 1, oh, pdata,
 				sizeof(*pdata),	NULL, 0, false);
 	kfree(pdata);
@@ -109,9 +136,6 @@
 		return PTR_ERR(pdev);
 	}
 
-	omap_device_disable_idle_on_suspend(pdev);
-
-	gpio_bank_count++;
 	return 0;
 }
 
diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 8ad210b..386dec8 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -16,6 +16,7 @@
 
 #include <asm/mach/flash.h>
 
+#include <plat/cpu.h>
 #include <plat/nand.h>
 #include <plat/board.h>
 #include <plat/gpmc.h>
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 5cdce10..385b3e0 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -18,6 +18,7 @@
 
 #include <asm/mach/flash.h>
 
+#include <plat/cpu.h>
 #include <plat/onenand.h>
 #include <plat/board.h>
 #include <plat/gpmc.h>
diff --git a/arch/arm/mach-omap2/gpmc-smsc911x.c b/arch/arm/mach-omap2/gpmc-smsc911x.c
index bbb870c..b6c77be 100644
--- a/arch/arm/mach-omap2/gpmc-smsc911x.c
+++ b/arch/arm/mach-omap2/gpmc-smsc911x.c
@@ -19,15 +19,11 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
-#include <linux/regulator/fixed.h>
-#include <linux/regulator/machine.h>
 
 #include <plat/board.h>
 #include <plat/gpmc.h>
 #include <plat/gpmc-smsc911x.h>
 
-static struct omap_smsc911x_platform_data *gpmc_cfg;
-
 static struct resource gpmc_smsc911x_resources[] = {
 	[0] = {
 		.flags		= IORESOURCE_MEM,
@@ -41,51 +37,6 @@
 	.phy_interface	= PHY_INTERFACE_MODE_MII,
 	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
 	.irq_type	= SMSC911X_IRQ_TYPE_OPEN_DRAIN,
-	.flags		= SMSC911X_USE_16BIT,
-};
-
-static struct regulator_consumer_supply gpmc_smsc911x_supply[] = {
-	REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
-	REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
-};
-
-/* Generic regulator definition to satisfy smsc911x */
-static struct regulator_init_data gpmc_smsc911x_reg_init_data = {
-	.constraints = {
-		.min_uV			= 3300000,
-		.max_uV			= 3300000,
-		.valid_modes_mask	= REGULATOR_MODE_NORMAL
-					| REGULATOR_MODE_STANDBY,
-		.valid_ops_mask		= REGULATOR_CHANGE_MODE
-					| REGULATOR_CHANGE_STATUS,
-	},
-	.num_consumer_supplies	= ARRAY_SIZE(gpmc_smsc911x_supply),
-	.consumer_supplies	= gpmc_smsc911x_supply,
-};
-
-static struct fixed_voltage_config gpmc_smsc911x_fixed_reg_data = {
-	.supply_name		= "gpmc_smsc911x",
-	.microvolts		= 3300000,
-	.gpio			= -EINVAL,
-	.startup_delay		= 0,
-	.enable_high		= 0,
-	.enabled_at_boot	= 1,
-	.init_data		= &gpmc_smsc911x_reg_init_data,
-};
-
-/*
- * Platform device id of 42 is a temporary fix to avoid conflicts
- * with other reg-fixed-voltage devices. The real fix should
- * involve the driver core providing a way of dynamically
- * assigning a unique id on registration for platform devices
- * in the same name space.
- */
-static struct platform_device gpmc_smsc911x_regulator = {
-	.name		= "reg-fixed-voltage",
-	.id		= 42,
-	.dev = {
-		.platform_data	= &gpmc_smsc911x_fixed_reg_data,
-	},
 };
 
 /*
@@ -93,20 +44,12 @@
  * assume that pin multiplexing is done in the board-*.c file,
  * or in the bootloader.
  */
-void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *board_data)
+void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *gpmc_cfg)
 {
 	struct platform_device *pdev;
 	unsigned long cs_mem_base;
 	int ret;
 
-	gpmc_cfg = board_data;
-
-	ret = platform_device_register(&gpmc_smsc911x_regulator);
-	if (ret < 0) {
-		pr_err("Unable to register smsc911x regulators: %d\n", ret);
-		return;
-	}
-
 	if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
 		pr_err("Failed to request GPMC mem region\n");
 		return;
@@ -136,8 +79,7 @@
 		gpio_set_value(gpmc_cfg->gpio_reset, 1);
 	}
 
-	if (gpmc_cfg->flags)
-		gpmc_smsc911x_config.flags = gpmc_cfg->flags;
+	gpmc_smsc911x_config.flags = gpmc_cfg->flags ? : SMSC911X_USE_16BIT;
 
 	pdev = platform_device_register_resndata(NULL, "smsc911x", gpmc_cfg->id,
 		 gpmc_smsc911x_resources, ARRAY_SIZE(gpmc_smsc911x_resources),
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index dfffbbf..00d5108 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -888,6 +888,7 @@
 	gpmc_write_reg(GPMC_ECC_CONFIG, val);
 	return 0;
 }
+EXPORT_SYMBOL_GPL(gpmc_enable_hwecc);
 
 /**
  * gpmc_calculate_ecc - generate non-inverted ecc bytes
@@ -918,3 +919,4 @@
 	gpmc_ecc_used = -EINVAL;
 	return 0;
 }
+EXPORT_SYMBOL_GPL(gpmc_calculate_ecc);
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 19dd165..b0268ea 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -293,8 +293,8 @@
 	}
 }
 
-static int omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
-				 struct omap_mmc_platform_data *mmc)
+static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
+					struct omap_mmc_platform_data *mmc)
 {
 	char *hc_name;
 
@@ -316,6 +316,7 @@
 	mmc->slots[0].pm_caps = c->pm_caps;
 	mmc->slots[0].internal_clock = !c->ext_clock;
 	mmc->dma_mask = 0xffffffff;
+	mmc->max_freq = c->max_freq;
 	if (cpu_is_omap44xx())
 		mmc->reg_offset = OMAP4_MMC_REG_OFFSET;
 	else
@@ -429,66 +430,138 @@
 }
 
 static int omap_hsmmc_done;
+
+void omap_hsmmc_late_init(struct omap2_hsmmc_info *c)
+{
+	struct platform_device *pdev;
+	struct omap_mmc_platform_data *mmc_pdata;
+	int res;
+
+	if (omap_hsmmc_done != 1)
+		return;
+
+	omap_hsmmc_done++;
+
+	for (; c->mmc; c++) {
+		if (!c->deferred)
+			continue;
+
+		pdev = c->pdev;
+		if (!pdev)
+			continue;
+
+		mmc_pdata = pdev->dev.platform_data;
+		if (!mmc_pdata)
+			continue;
+
+		mmc_pdata->slots[0].switch_pin = c->gpio_cd;
+		mmc_pdata->slots[0].gpio_wp = c->gpio_wp;
+
+		res = omap_device_register(pdev);
+		if (res)
+			pr_err("Could not late init MMC %s\n",
+			       c->name);
+	}
+}
+
 #define MAX_OMAP_MMC_HWMOD_NAME_LEN		16
 
-void omap_init_hsmmc(struct omap2_hsmmc_info *hsmmcinfo, int ctrl_nr)
+static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo,
+					int ctrl_nr)
 {
 	struct omap_hwmod *oh;
+	struct omap_hwmod *ohs[1];
+	struct omap_device *od;
 	struct platform_device *pdev;
 	char oh_name[MAX_OMAP_MMC_HWMOD_NAME_LEN];
 	struct omap_mmc_platform_data *mmc_data;
 	struct omap_mmc_dev_attr *mmc_dev_attr;
 	char *name;
-	int l;
+	int res;
 
 	mmc_data = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL);
 	if (!mmc_data) {
 		pr_err("Cannot allocate memory for mmc device!\n");
-		goto done;
+		return;
 	}
 
-	if (omap_hsmmc_pdata_init(hsmmcinfo, mmc_data) < 0) {
-		pr_err("%s fails!\n", __func__);
-		goto done;
-	}
+	res = omap_hsmmc_pdata_init(hsmmcinfo, mmc_data);
+	if (res < 0)
+		goto free_mmc;
+
 	omap_hsmmc_mux(mmc_data, (ctrl_nr - 1));
 
 	name = "omap_hsmmc";
-
-	l = snprintf(oh_name, MAX_OMAP_MMC_HWMOD_NAME_LEN,
+	res = snprintf(oh_name, MAX_OMAP_MMC_HWMOD_NAME_LEN,
 		     "mmc%d", ctrl_nr);
-	WARN(l >= MAX_OMAP_MMC_HWMOD_NAME_LEN,
+	WARN(res >= MAX_OMAP_MMC_HWMOD_NAME_LEN,
 	     "String buffer overflow in MMC%d device setup\n", ctrl_nr);
+
 	oh = omap_hwmod_lookup(oh_name);
 	if (!oh) {
 		pr_err("Could not look up %s\n", oh_name);
-		kfree(mmc_data->slots[0].name);
-		goto done;
+		goto free_name;
 	}
-
+	ohs[0] = oh;
 	if (oh->dev_attr != NULL) {
 		mmc_dev_attr = oh->dev_attr;
 		mmc_data->controller_flags = mmc_dev_attr->flags;
+		/*
+		 * erratum 2.1.1.128 doesn't apply if board has
+		 * a transceiver is attached
+		 */
+		if (hsmmcinfo->transceiver)
+			mmc_data->controller_flags &=
+				~OMAP_HSMMC_BROKEN_MULTIBLOCK_READ;
 	}
 
-	pdev = omap_device_build(name, ctrl_nr - 1, oh, mmc_data,
-		sizeof(struct omap_mmc_platform_data), NULL, 0, false);
-	if (IS_ERR(pdev)) {
-		WARN(1, "Can't build omap_device for %s:%s.\n", name, oh->name);
-		kfree(mmc_data->slots[0].name);
-		goto done;
+	pdev = platform_device_alloc(name, ctrl_nr - 1);
+	if (!pdev) {
+		pr_err("Could not allocate pdev for %s\n", name);
+		goto free_name;
 	}
-	/*
-	 * return device handle to board setup code
-	 * required to populate for regulator framework structure
-	 */
-	hsmmcinfo->dev = &pdev->dev;
+	dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
 
-done:
+	od = omap_device_alloc(pdev, ohs, 1, NULL, 0);
+	if (!od) {
+		pr_err("Could not allocate od for %s\n", name);
+		goto put_pdev;
+	}
+
+	res = platform_device_add_data(pdev, mmc_data,
+			      sizeof(struct omap_mmc_platform_data));
+	if (res) {
+		pr_err("Could not add pdata for %s\n", name);
+		goto put_pdev;
+	}
+
+	hsmmcinfo->pdev = pdev;
+
+	if (hsmmcinfo->deferred)
+		goto free_mmc;
+
+	res = omap_device_register(pdev);
+	if (res) {
+		pr_err("Could not register od for %s\n", name);
+		goto free_od;
+	}
+
+	goto free_mmc;
+
+free_od:
+	omap_device_delete(od);
+
+put_pdev:
+	platform_device_put(pdev);
+
+free_name:
+	kfree(mmc_data->slots[0].name);
+
+free_mmc:
 	kfree(mmc_data);
 }
 
-void omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
+void __init omap_hsmmc_init(struct omap2_hsmmc_info *controllers)
 {
 	u32 reg;
 
@@ -521,7 +594,7 @@
 	}
 
 	for (; controllers->mmc; controllers++)
-		omap_init_hsmmc(controllers, controllers->mmc);
+		omap_hsmmc_init_one(controllers, controllers->mmc);
 
 }
 
diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h
index c440973..7f2e790 100644
--- a/arch/arm/mach-omap2/hsmmc.h
+++ b/arch/arm/mach-omap2/hsmmc.h
@@ -21,11 +21,14 @@
 	bool	no_off;		/* power_saving and power is not to go off */
 	bool	no_off_init;	/* no power off when not in MMC sleep state */
 	bool	vcc_aux_disable_is_sleep; /* Regulator off remapped to sleep */
+	bool	deferred;	/* mmc needs a deferred probe */
 	int	gpio_cd;	/* or -EINVAL */
 	int	gpio_wp;	/* or -EINVAL */
 	char	*name;		/* or NULL for default */
-	struct device *dev;	/* returned: pointer to mmc adapter */
+	struct platform_device *pdev;	/* mmc controller instance */
 	int	ocr_mask;	/* temporary HACK */
+	int	max_freq;	/* maximum clock, if constrained by external
+				 * circuitry, or 0 for default */
 	/* Remux (pad configuration) when powering on/off */
 	void (*remux)(struct device *dev, int slot, int power_on);
 	/* init some special card */
@@ -34,11 +37,16 @@
 
 #if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
 
-void omap2_hsmmc_init(struct omap2_hsmmc_info *);
+void omap_hsmmc_init(struct omap2_hsmmc_info *);
+void omap_hsmmc_late_init(struct omap2_hsmmc_info *);
 
 #else
 
-static inline void omap2_hsmmc_init(struct omap2_hsmmc_info *info)
+static inline void omap_hsmmc_init(struct omap2_hsmmc_info *info)
+{
+}
+
+static inline void omap_hsmmc_late_init(struct omap2_hsmmc_info *info)
 {
 }
 
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index 719ee42..0e79b7b 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -29,7 +29,7 @@
 #include "control.h"
 
 static unsigned int omap_revision;
-
+static const char *cpu_rev;
 u32 omap_features;
 
 unsigned int omap_rev(void)
@@ -44,6 +44,8 @@
 
 	if (cpu_is_omap24xx()) {
 		val = omap_ctrl_readl(OMAP24XX_CONTROL_STATUS);
+	} else if (cpu_is_am33xx()) {
+		val = omap_ctrl_readl(AM33XX_CONTROL_STATUS);
 	} else if (cpu_is_omap34xx()) {
 		val = omap_ctrl_readl(OMAP343X_CONTROL_STATUS);
 	} else if (cpu_is_omap44xx()) {
@@ -112,7 +114,7 @@
 	odi->id_3 = read_tap_reg(OMAP_TAP_DIE_ID_3);
 }
 
-static void __init omap24xx_check_revision(void)
+void __init omap2xxx_check_revision(void)
 {
 	int i, j;
 	u32 idcode, prod_id;
@@ -166,13 +168,63 @@
 	pr_info("\n");
 }
 
+#define OMAP3_SHOW_FEATURE(feat)		\
+	if (omap3_has_ ##feat())		\
+		printk(#feat" ");
+
+static void __init omap3_cpuinfo(void)
+{
+	const char *cpu_name;
+
+	/*
+	 * OMAP3430 and OMAP3530 are assumed to be same.
+	 *
+	 * OMAP3525, OMAP3515 and OMAP3503 can be detected only based
+	 * on available features. Upon detection, update the CPU id
+	 * and CPU class bits.
+	 */
+	if (cpu_is_omap3630()) {
+		cpu_name = "OMAP3630";
+	} else if (cpu_is_omap3517()) {
+		/* AM35xx devices */
+		cpu_name = (omap3_has_sgx()) ? "AM3517" : "AM3505";
+	} else if (cpu_is_ti816x()) {
+		cpu_name = "TI816X";
+	} else if (cpu_is_am335x()) {
+		cpu_name =  "AM335X";
+	} else if (cpu_is_ti814x()) {
+		cpu_name = "TI814X";
+	} else if (omap3_has_iva() && omap3_has_sgx()) {
+		/* OMAP3430, OMAP3525, OMAP3515, OMAP3503 devices */
+		cpu_name = "OMAP3430/3530";
+	} else if (omap3_has_iva()) {
+		cpu_name = "OMAP3525";
+	} else if (omap3_has_sgx()) {
+		cpu_name = "OMAP3515";
+	} else {
+		cpu_name = "OMAP3503";
+	}
+
+	/* Print verbose information */
+	pr_info("%s ES%s (", cpu_name, cpu_rev);
+
+	OMAP3_SHOW_FEATURE(l2cache);
+	OMAP3_SHOW_FEATURE(iva);
+	OMAP3_SHOW_FEATURE(sgx);
+	OMAP3_SHOW_FEATURE(neon);
+	OMAP3_SHOW_FEATURE(isp);
+	OMAP3_SHOW_FEATURE(192mhz_clk);
+
+	printk(")\n");
+}
+
 #define OMAP3_CHECK_FEATURE(status,feat)				\
 	if (((status & OMAP3_ ##feat## _MASK) 				\
 		>> OMAP3_ ##feat## _SHIFT) != FEAT_ ##feat## _NONE) { 	\
 		omap_features |= OMAP3_HAS_ ##feat;			\
 	}
 
-static void __init omap3_check_features(void)
+void __init omap3xxx_check_features(void)
 {
 	u32 status;
 
@@ -199,9 +251,11 @@
 	 * TODO: Get additional info (where applicable)
 	 *       e.g. Size of L2 cache.
 	 */
+
+	omap3_cpuinfo();
 }
 
-static void __init omap4_check_features(void)
+void __init omap4xxx_check_features(void)
 {
 	u32 si_type;
 
@@ -226,12 +280,13 @@
 	}
 }
 
-static void __init ti81xx_check_features(void)
+void __init ti81xx_check_features(void)
 {
 	omap_features = OMAP3_HAS_NEON;
+	omap3_cpuinfo();
 }
 
-static void __init omap3_check_revision(const char **cpu_rev)
+void __init omap3xxx_check_revision(void)
 {
 	u32 cpuid, idcode;
 	u16 hawkeye;
@@ -245,7 +300,7 @@
 	cpuid = read_cpuid(CPUID_ID);
 	if ((((cpuid >> 4) & 0xfff) == 0xc08) && ((cpuid & 0xf) == 0x0)) {
 		omap_revision = OMAP3430_REV_ES1_0;
-		*cpu_rev = "1.0";
+		cpu_rev = "1.0";
 		return;
 	}
 
@@ -266,26 +321,26 @@
 		case 0: /* Take care of early samples */
 		case 1:
 			omap_revision = OMAP3430_REV_ES2_0;
-			*cpu_rev = "2.0";
+			cpu_rev = "2.0";
 			break;
 		case 2:
 			omap_revision = OMAP3430_REV_ES2_1;
-			*cpu_rev = "2.1";
+			cpu_rev = "2.1";
 			break;
 		case 3:
 			omap_revision = OMAP3430_REV_ES3_0;
-			*cpu_rev = "3.0";
+			cpu_rev = "3.0";
 			break;
 		case 4:
 			omap_revision = OMAP3430_REV_ES3_1;
-			*cpu_rev = "3.1";
+			cpu_rev = "3.1";
 			break;
 		case 7:
 		/* FALLTHROUGH */
 		default:
 			/* Use the latest known revision as default */
 			omap_revision = OMAP3430_REV_ES3_1_2;
-			*cpu_rev = "3.1.2";
+			cpu_rev = "3.1.2";
 		}
 		break;
 	case 0xb868:
@@ -298,13 +353,13 @@
 		switch (rev) {
 		case 0:
 			omap_revision = OMAP3517_REV_ES1_0;
-			*cpu_rev = "1.0";
+			cpu_rev = "1.0";
 			break;
 		case 1:
 		/* FALLTHROUGH */
 		default:
 			omap_revision = OMAP3517_REV_ES1_1;
-			*cpu_rev = "1.1";
+			cpu_rev = "1.1";
 		}
 		break;
 	case 0xb891:
@@ -313,36 +368,36 @@
 		switch(rev) {
 		case 0: /* Take care of early samples */
 			omap_revision = OMAP3630_REV_ES1_0;
-			*cpu_rev = "1.0";
+			cpu_rev = "1.0";
 			break;
 		case 1:
 			omap_revision = OMAP3630_REV_ES1_1;
-			*cpu_rev = "1.1";
+			cpu_rev = "1.1";
 			break;
 		case 2:
 		/* FALLTHROUGH */
 		default:
 			omap_revision = OMAP3630_REV_ES1_2;
-			*cpu_rev = "1.2";
+			cpu_rev = "1.2";
 		}
 		break;
 	case 0xb81e:
 		switch (rev) {
 		case 0:
 			omap_revision = TI8168_REV_ES1_0;
-			*cpu_rev = "1.0";
+			cpu_rev = "1.0";
 			break;
 		case 1:
 		/* FALLTHROUGH */
 		default:
 			omap_revision = TI8168_REV_ES1_1;
-			*cpu_rev = "1.1";
+			cpu_rev = "1.1";
 			break;
 		}
 		break;
 	case 0xb944:
 		omap_revision = AM335X_REV_ES1_0;
-		*cpu_rev = "1.0";
+		cpu_rev = "1.0";
 		break;
 	case 0xb8f2:
 		switch (rev) {
@@ -350,29 +405,29 @@
 		/* FALLTHROUGH */
 		case 1:
 			omap_revision = TI8148_REV_ES1_0;
-			*cpu_rev = "1.0";
+			cpu_rev = "1.0";
 			break;
 		case 2:
 			omap_revision = TI8148_REV_ES2_0;
-			*cpu_rev = "2.0";
+			cpu_rev = "2.0";
 			break;
 		case 3:
 		/* FALLTHROUGH */
 		default:
 			omap_revision = TI8148_REV_ES2_1;
-			*cpu_rev = "2.1";
+			cpu_rev = "2.1";
 			break;
 		}
 		break;
 	default:
 		/* Unknown default to latest silicon rev as default */
 		omap_revision = OMAP3630_REV_ES1_2;
-		*cpu_rev = "1.2";
+		cpu_rev = "1.2";
 		pr_warn("Warning: unknown chip type; assuming OMAP3630ES1.2\n");
 	}
 }
 
-static void __init omap4_check_revision(void)
+void __init omap4xxx_check_revision(void)
 {
 	u32 idcode;
 	u16 hawkeye;
@@ -445,89 +500,6 @@
 		((omap_rev() >> 12) & 0xf), ((omap_rev() >> 8) & 0xf));
 }
 
-#define OMAP3_SHOW_FEATURE(feat)		\
-	if (omap3_has_ ##feat())		\
-		printk(#feat" ");
-
-static void __init omap3_cpuinfo(const char *cpu_rev)
-{
-	const char *cpu_name;
-
-	/*
-	 * OMAP3430 and OMAP3530 are assumed to be same.
-	 *
-	 * OMAP3525, OMAP3515 and OMAP3503 can be detected only based
-	 * on available features. Upon detection, update the CPU id
-	 * and CPU class bits.
-	 */
-	if (cpu_is_omap3630()) {
-		cpu_name = "OMAP3630";
-	} else if (cpu_is_omap3517()) {
-		/* AM35xx devices */
-		cpu_name = (omap3_has_sgx()) ? "AM3517" : "AM3505";
-	} else if (cpu_is_ti816x()) {
-		cpu_name = "TI816X";
-	} else if (cpu_is_am335x()) {
-		cpu_name =  "AM335X";
-	} else if (cpu_is_ti814x()) {
-		cpu_name = "TI814X";
-	} else if (omap3_has_iva() && omap3_has_sgx()) {
-		/* OMAP3430, OMAP3525, OMAP3515, OMAP3503 devices */
-		cpu_name = "OMAP3430/3530";
-	} else if (omap3_has_iva()) {
-		cpu_name = "OMAP3525";
-	} else if (omap3_has_sgx()) {
-		cpu_name = "OMAP3515";
-	} else {
-		cpu_name = "OMAP3503";
-	}
-
-	/* Print verbose information */
-	pr_info("%s ES%s (", cpu_name, cpu_rev);
-
-	OMAP3_SHOW_FEATURE(l2cache);
-	OMAP3_SHOW_FEATURE(iva);
-	OMAP3_SHOW_FEATURE(sgx);
-	OMAP3_SHOW_FEATURE(neon);
-	OMAP3_SHOW_FEATURE(isp);
-	OMAP3_SHOW_FEATURE(192mhz_clk);
-
-	printk(")\n");
-}
-
-/*
- * Try to detect the exact revision of the omap we're running on
- */
-void __init omap2_check_revision(void)
-{
-	const char *cpu_rev;
-
-	/*
-	 * At this point we have an idea about the processor revision set
-	 * earlier with omap2_set_globals_tap().
-	 */
-	if (cpu_is_omap24xx()) {
-		omap24xx_check_revision();
-	} else if (cpu_is_omap34xx()) {
-		omap3_check_revision(&cpu_rev);
-
-		/* TI81XX doesn't have feature register */
-		if (!cpu_is_ti81xx())
-			omap3_check_features();
-		else
-			ti81xx_check_features();
-
-		omap3_cpuinfo(cpu_rev);
-		return;
-	} else if (cpu_is_omap44xx()) {
-		omap4_check_revision();
-		omap4_check_features();
-		return;
-	} else {
-		pr_err("OMAP revision unknown, please fix!\n");
-	}
-}
-
 /*
  * Set up things for map_io and processor detection later on. Gets called
  * pretty much first thing from board init. For multi-omap, this gets
diff --git a/arch/arm/mach-omap2/include/mach/barriers.h b/arch/arm/mach-omap2/include/mach/barriers.h
index 4fa72c7..1c582a8 100644
--- a/arch/arm/mach-omap2/include/mach/barriers.h
+++ b/arch/arm/mach-omap2/include/mach/barriers.h
@@ -22,6 +22,8 @@
 #ifndef __MACH_BARRIERS_H
 #define __MACH_BARRIERS_H
 
+#include <asm/outercache.h>
+
 extern void omap_bus_sync(void);
 
 #define rmb()		dsb()
diff --git a/arch/arm/mach-omap2/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S
deleted file mode 100644
index 56964a0..0000000
--- a/arch/arm/mach-omap2/include/mach/entry-macro.S
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * arch/arm/plat-omap/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for OMAP-based platforms
- *
- * Copyright (C) 2009 Texas Instruments
- * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.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.
- */
-
-		.macro	disable_fiq
-		.endm
-
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
diff --git a/arch/arm/mach-omap2/include/mach/io.h b/arch/arm/mach-omap2/include/mach/io.h
deleted file mode 100644
index fd78f31..0000000
--- a/arch/arm/mach-omap2/include/mach/io.h
+++ /dev/null
@@ -1,5 +0,0 @@
-/*
- * arch/arm/mach-omap2/include/mach/io.h
- */
-
-#include <plat/io.h>
diff --git a/arch/arm/mach-omap2/include/mach/system.h b/arch/arm/mach-omap2/include/mach/system.h
deleted file mode 100644
index d488721..0000000
--- a/arch/arm/mach-omap2/include/mach/system.h
+++ /dev/null
@@ -1,5 +0,0 @@
-/*
- * arch/arm/mach-omap2/include/mach/system.h
- */
-
-#include <plat/system.h>
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index fb11b44..065bd76 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -21,36 +21,32 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/clk.h>
-#include <linux/omapfb.h>
 
 #include <asm/tlb.h>
-
 #include <asm/mach/map.h>
 
 #include <plat/sram.h>
 #include <plat/sdrc.h>
 #include <plat/serial.h>
+#include <plat/omap-pm.h>
+#include <plat/omap_hwmod.h>
+#include <plat/multi.h>
 
+#include "iomap.h"
+#include "voltage.h"
+#include "powerdomain.h"
+#include "clockdomain.h"
+#include "common.h"
 #include "clock2xxx.h"
 #include "clock3xxx.h"
 #include "clock44xx.h"
 
-#include "common.h"
-#include <plat/omap-pm.h>
-#include "voltage.h"
-#include "powerdomain.h"
-
-#include "clockdomain.h"
-#include <plat/omap_hwmod.h>
-#include <plat/multi.h>
-#include "common.h"
-
 /*
  * The machine specific code may provide the extra mapping besides the
  * default mapping provided here.
  */
 
-#ifdef CONFIG_ARCH_OMAP2
+#if defined(CONFIG_SOC_OMAP2420) || defined(CONFIG_SOC_OMAP2430)
 static struct map_desc omap24xx_io_desc[] __initdata = {
 	{
 		.virtual	= L3_24XX_VIRT,
@@ -352,7 +348,6 @@
 
 static void __init omap_common_init_early(void)
 {
-	omap2_check_revision();
 	omap_init_consistent_dma_size();
 }
 
@@ -393,6 +388,7 @@
 void __init omap2420_init_early(void)
 {
 	omap2_set_globals_242x();
+	omap2xxx_check_revision();
 	omap_common_init_early();
 	omap2xxx_voltagedomains_init();
 	omap242x_powerdomains_init();
@@ -407,6 +403,7 @@
 void __init omap2430_init_early(void)
 {
 	omap2_set_globals_243x();
+	omap2xxx_check_revision();
 	omap_common_init_early();
 	omap2xxx_voltagedomains_init();
 	omap243x_powerdomains_init();
@@ -425,6 +422,8 @@
 void __init omap3_init_early(void)
 {
 	omap2_set_globals_3xxx();
+	omap3xxx_check_revision();
+	omap3xxx_check_features();
 	omap_common_init_early();
 	omap3xxx_voltagedomains_init();
 	omap3xxx_powerdomains_init();
@@ -457,6 +456,8 @@
 void __init ti81xx_init_early(void)
 {
 	omap2_set_globals_ti81xx();
+	omap3xxx_check_revision();
+	ti81xx_check_features();
 	omap_common_init_early();
 	omap3xxx_voltagedomains_init();
 	omap3xxx_powerdomains_init();
@@ -471,6 +472,8 @@
 void __init omap4430_init_early(void)
 {
 	omap2_set_globals_443x();
+	omap4xxx_check_revision();
+	omap4xxx_check_features();
 	omap_common_init_early();
 	omap44xx_voltagedomains_init();
 	omap44xx_powerdomains_init();
@@ -491,43 +494,3 @@
 		_omap2_init_reprogram_sdrc();
 	}
 }
-
-/*
- * NOTE: Please use ioremap + __raw_read/write where possible instead of these
- */
-
-u8 omap_readb(u32 pa)
-{
-	return __raw_readb(OMAP2_L4_IO_ADDRESS(pa));
-}
-EXPORT_SYMBOL(omap_readb);
-
-u16 omap_readw(u32 pa)
-{
-	return __raw_readw(OMAP2_L4_IO_ADDRESS(pa));
-}
-EXPORT_SYMBOL(omap_readw);
-
-u32 omap_readl(u32 pa)
-{
-	return __raw_readl(OMAP2_L4_IO_ADDRESS(pa));
-}
-EXPORT_SYMBOL(omap_readl);
-
-void omap_writeb(u8 v, u32 pa)
-{
-	__raw_writeb(v, OMAP2_L4_IO_ADDRESS(pa));
-}
-EXPORT_SYMBOL(omap_writeb);
-
-void omap_writew(u16 v, u32 pa)
-{
-	__raw_writew(v, OMAP2_L4_IO_ADDRESS(pa));
-}
-EXPORT_SYMBOL(omap_writew);
-
-void omap_writel(u32 v, u32 pa)
-{
-	__raw_writel(v, OMAP2_L4_IO_ADDRESS(pa));
-}
-EXPORT_SYMBOL(omap_writel);
diff --git a/arch/arm/mach-omap2/iomap.h b/arch/arm/mach-omap2/iomap.h
new file mode 100644
index 0000000..0812b15
--- /dev/null
+++ b/arch/arm/mach-omap2/iomap.h
@@ -0,0 +1,197 @@
+/*
+ * IO mappings for OMAP2+
+ *
+ * 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 SOFTWARE IS PROVIDED ``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 AUTHOR 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, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define OMAP2_L3_IO_OFFSET	0x90000000
+#define OMAP2_L3_IO_ADDRESS(pa)	IOMEM((pa) + OMAP2_L3_IO_OFFSET) /* L3 */
+
+#define OMAP2_L4_IO_OFFSET	0xb2000000
+#define OMAP2_L4_IO_ADDRESS(pa)	IOMEM((pa) + OMAP2_L4_IO_OFFSET) /* L4 */
+
+#define OMAP4_L3_IO_OFFSET	0xb4000000
+#define OMAP4_L3_IO_ADDRESS(pa)	IOMEM((pa) + OMAP4_L3_IO_OFFSET) /* L3 */
+
+#define AM33XX_L4_WK_IO_OFFSET	0xb5000000
+#define AM33XX_L4_WK_IO_ADDRESS(pa)	IOMEM((pa) + AM33XX_L4_WK_IO_OFFSET)
+
+#define OMAP4_L3_PER_IO_OFFSET	0xb1100000
+#define OMAP4_L3_PER_IO_ADDRESS(pa)	IOMEM((pa) + OMAP4_L3_PER_IO_OFFSET)
+
+#define OMAP4_GPMC_IO_OFFSET		0xa9000000
+#define OMAP4_GPMC_IO_ADDRESS(pa)	IOMEM((pa) + OMAP4_GPMC_IO_OFFSET)
+
+#define OMAP2_EMU_IO_OFFSET		0xaa800000	/* Emulation */
+#define OMAP2_EMU_IO_ADDRESS(pa)	IOMEM((pa) + OMAP2_EMU_IO_OFFSET)
+
+/*
+ * ----------------------------------------------------------------------------
+ * Omap2 specific IO mapping
+ * ----------------------------------------------------------------------------
+ */
+
+/* We map both L3 and L4 on OMAP2 */
+#define L3_24XX_PHYS	L3_24XX_BASE	/* 0x68000000 --> 0xf8000000*/
+#define L3_24XX_VIRT	(L3_24XX_PHYS + OMAP2_L3_IO_OFFSET)
+#define L3_24XX_SIZE	SZ_1M		/* 44kB of 128MB used, want 1MB sect */
+#define L4_24XX_PHYS	L4_24XX_BASE	/* 0x48000000 --> 0xfa000000 */
+#define L4_24XX_VIRT	(L4_24XX_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_24XX_SIZE	SZ_1M		/* 1MB of 128MB used, want 1MB sect */
+
+#define L4_WK_243X_PHYS		L4_WK_243X_BASE	/* 0x49000000 --> 0xfb000000 */
+#define L4_WK_243X_VIRT		(L4_WK_243X_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_WK_243X_SIZE		SZ_1M
+#define OMAP243X_GPMC_PHYS	OMAP243X_GPMC_BASE
+#define OMAP243X_GPMC_VIRT	(OMAP243X_GPMC_PHYS + OMAP2_L3_IO_OFFSET)
+						/* 0x6e000000 --> 0xfe000000 */
+#define OMAP243X_GPMC_SIZE	SZ_1M
+#define OMAP243X_SDRC_PHYS	OMAP243X_SDRC_BASE
+						/* 0x6D000000 --> 0xfd000000 */
+#define OMAP243X_SDRC_VIRT	(OMAP243X_SDRC_PHYS + OMAP2_L3_IO_OFFSET)
+#define OMAP243X_SDRC_SIZE	SZ_1M
+#define OMAP243X_SMS_PHYS	OMAP243X_SMS_BASE
+						/* 0x6c000000 --> 0xfc000000 */
+#define OMAP243X_SMS_VIRT	(OMAP243X_SMS_PHYS + OMAP2_L3_IO_OFFSET)
+#define OMAP243X_SMS_SIZE	SZ_1M
+
+/* 2420 IVA */
+#define DSP_MEM_2420_PHYS	OMAP2420_DSP_MEM_BASE
+						/* 0x58000000 --> 0xfc100000 */
+#define DSP_MEM_2420_VIRT	0xfc100000
+#define DSP_MEM_2420_SIZE	0x28000
+#define DSP_IPI_2420_PHYS	OMAP2420_DSP_IPI_BASE
+						/* 0x59000000 --> 0xfc128000 */
+#define DSP_IPI_2420_VIRT	0xfc128000
+#define DSP_IPI_2420_SIZE	SZ_4K
+#define DSP_MMU_2420_PHYS	OMAP2420_DSP_MMU_BASE
+						/* 0x5a000000 --> 0xfc129000 */
+#define DSP_MMU_2420_VIRT	0xfc129000
+#define DSP_MMU_2420_SIZE	SZ_4K
+
+/* 2430 IVA2.1 - currently unmapped */
+
+/*
+ * ----------------------------------------------------------------------------
+ * Omap3 specific IO mapping
+ * ----------------------------------------------------------------------------
+ */
+
+/* We map both L3 and L4 on OMAP3 */
+#define L3_34XX_PHYS		L3_34XX_BASE	/* 0x68000000 --> 0xf8000000 */
+#define L3_34XX_VIRT		(L3_34XX_PHYS + OMAP2_L3_IO_OFFSET)
+#define L3_34XX_SIZE		SZ_1M   /* 44kB of 128MB used, want 1MB sect */
+
+#define L4_34XX_PHYS		L4_34XX_BASE	/* 0x48000000 --> 0xfa000000 */
+#define L4_34XX_VIRT		(L4_34XX_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_34XX_SIZE		SZ_4M   /* 1MB of 128MB used, want 1MB sect */
+
+/*
+ * ----------------------------------------------------------------------------
+ * AM33XX specific IO mapping
+ * ----------------------------------------------------------------------------
+ */
+#define L4_WK_AM33XX_PHYS	L4_WK_AM33XX_BASE
+#define L4_WK_AM33XX_VIRT	(L4_WK_AM33XX_PHYS + AM33XX_L4_WK_IO_OFFSET)
+#define L4_WK_AM33XX_SIZE	SZ_4M   /* 1MB of 128MB used, want 1MB sect */
+
+/*
+ * Need to look at the Size 4M for L4.
+ * VPOM3430 was not working for Int controller
+ */
+
+#define L4_PER_34XX_PHYS	L4_PER_34XX_BASE
+						/* 0x49000000 --> 0xfb000000 */
+#define L4_PER_34XX_VIRT	(L4_PER_34XX_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_PER_34XX_SIZE	SZ_1M
+
+#define L4_EMU_34XX_PHYS	L4_EMU_34XX_BASE
+						/* 0x54000000 --> 0xfe800000 */
+#define L4_EMU_34XX_VIRT	(L4_EMU_34XX_PHYS + OMAP2_EMU_IO_OFFSET)
+#define L4_EMU_34XX_SIZE	SZ_8M
+
+#define OMAP34XX_GPMC_PHYS	OMAP34XX_GPMC_BASE
+						/* 0x6e000000 --> 0xfe000000 */
+#define OMAP34XX_GPMC_VIRT	(OMAP34XX_GPMC_PHYS + OMAP2_L3_IO_OFFSET)
+#define OMAP34XX_GPMC_SIZE	SZ_1M
+
+#define OMAP343X_SMS_PHYS	OMAP343X_SMS_BASE
+						/* 0x6c000000 --> 0xfc000000 */
+#define OMAP343X_SMS_VIRT	(OMAP343X_SMS_PHYS + OMAP2_L3_IO_OFFSET)
+#define OMAP343X_SMS_SIZE	SZ_1M
+
+#define OMAP343X_SDRC_PHYS	OMAP343X_SDRC_BASE
+						/* 0x6D000000 --> 0xfd000000 */
+#define OMAP343X_SDRC_VIRT	(OMAP343X_SDRC_PHYS + OMAP2_L3_IO_OFFSET)
+#define OMAP343X_SDRC_SIZE	SZ_1M
+
+/* 3430 IVA - currently unmapped */
+
+/*
+ * ----------------------------------------------------------------------------
+ * Omap4 specific IO mapping
+ * ----------------------------------------------------------------------------
+ */
+
+/* We map both L3 and L4 on OMAP4 */
+#define L3_44XX_PHYS		L3_44XX_BASE	/* 0x44000000 --> 0xf8000000 */
+#define L3_44XX_VIRT		(L3_44XX_PHYS + OMAP4_L3_IO_OFFSET)
+#define L3_44XX_SIZE		SZ_1M
+
+#define L4_44XX_PHYS		L4_44XX_BASE	/* 0x4a000000 --> 0xfc000000 */
+#define L4_44XX_VIRT		(L4_44XX_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_44XX_SIZE		SZ_4M
+
+#define L4_PER_44XX_PHYS	L4_PER_44XX_BASE
+						/* 0x48000000 --> 0xfa000000 */
+#define L4_PER_44XX_VIRT	(L4_PER_44XX_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_PER_44XX_SIZE	SZ_4M
+
+#define L4_ABE_44XX_PHYS	L4_ABE_44XX_BASE
+						/* 0x49000000 --> 0xfb000000 */
+#define L4_ABE_44XX_VIRT	(L4_ABE_44XX_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_ABE_44XX_SIZE	SZ_1M
+
+#define L4_EMU_44XX_PHYS	L4_EMU_44XX_BASE
+						/* 0x54000000 --> 0xfe800000 */
+#define L4_EMU_44XX_VIRT	(L4_EMU_44XX_PHYS + OMAP2_EMU_IO_OFFSET)
+#define L4_EMU_44XX_SIZE	SZ_8M
+
+#define OMAP44XX_GPMC_PHYS	OMAP44XX_GPMC_BASE
+						/* 0x50000000 --> 0xf9000000 */
+#define OMAP44XX_GPMC_VIRT	(OMAP44XX_GPMC_PHYS + OMAP4_GPMC_IO_OFFSET)
+#define OMAP44XX_GPMC_SIZE	SZ_1M
+
+
+#define OMAP44XX_EMIF1_PHYS	OMAP44XX_EMIF1_BASE
+						/* 0x4c000000 --> 0xfd100000 */
+#define OMAP44XX_EMIF1_VIRT	(OMAP44XX_EMIF1_PHYS + OMAP4_L3_PER_IO_OFFSET)
+#define OMAP44XX_EMIF1_SIZE	SZ_1M
+
+#define OMAP44XX_EMIF2_PHYS	OMAP44XX_EMIF2_BASE
+						/* 0x4d000000 --> 0xfd200000 */
+#define OMAP44XX_EMIF2_SIZE	SZ_1M
+#define OMAP44XX_EMIF2_VIRT	(OMAP44XX_EMIF1_VIRT + OMAP44XX_EMIF1_SIZE)
+
+#define OMAP44XX_DMM_PHYS	OMAP44XX_DMM_BASE
+						/* 0x4e000000 --> 0xfd300000 */
+#define OMAP44XX_DMM_SIZE	SZ_1M
+#define OMAP44XX_DMM_VIRT	(OMAP44XX_EMIF2_VIRT + OMAP44XX_EMIF2_SIZE)
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 1fef061..65f0d257 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -11,13 +11,20 @@
  * for more details.
  */
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
-#include <mach/hardware.h>
+
 #include <asm/exception.h>
 #include <asm/mach/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
 
 /* selected INTC register offsets */
 
@@ -57,6 +64,8 @@
 	},
 };
 
+static struct irq_domain *domain;
+
 /* Structure to save interrupt controller context */
 struct omap3_intc_regs {
 	u32 sysconfig;
@@ -147,17 +156,27 @@
 				IRQ_NOREQUEST | IRQ_NOPROBE, 0);
 }
 
-static void __init omap_init_irq(u32 base, int nr_irqs)
+static void __init omap_init_irq(u32 base, int nr_irqs,
+				 struct device_node *node)
 {
 	void __iomem *omap_irq_base;
 	unsigned long nr_of_irqs = 0;
 	unsigned int nr_banks = 0;
-	int i, j;
+	int i, j, irq_base;
 
 	omap_irq_base = ioremap(base, SZ_4K);
 	if (WARN_ON(!omap_irq_base))
 		return;
 
+	irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+	if (irq_base < 0) {
+		pr_warn("Couldn't allocate IRQ numbers\n");
+		irq_base = 0;
+	}
+
+	domain = irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
+				       &irq_domain_simple_ops, NULL);
+
 	for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
 		struct omap_irq_bank *bank = irq_banks + i;
 
@@ -166,36 +185,36 @@
 		/* Static mapping, never released */
 		bank->base_reg = ioremap(base, SZ_4K);
 		if (!bank->base_reg) {
-			printk(KERN_ERR "Could not ioremap irq bank%i\n", i);
+			pr_err("Could not ioremap irq bank%i\n", i);
 			continue;
 		}
 
 		omap_irq_bank_init_one(bank);
 
 		for (j = 0; j < bank->nr_irqs; j += 32)
-			omap_alloc_gc(bank->base_reg + j, j, 32);
+			omap_alloc_gc(bank->base_reg + j, j + irq_base, 32);
 
 		nr_of_irqs += bank->nr_irqs;
 		nr_banks++;
 	}
 
-	printk(KERN_INFO "Total of %ld interrupts on %d active controller%s\n",
-	       nr_of_irqs, nr_banks, nr_banks > 1 ? "s" : "");
+	pr_info("Total of %ld interrupts on %d active controller%s\n",
+		nr_of_irqs, nr_banks, nr_banks > 1 ? "s" : "");
 }
 
 void __init omap2_init_irq(void)
 {
-	omap_init_irq(OMAP24XX_IC_BASE, 96);
+	omap_init_irq(OMAP24XX_IC_BASE, 96, NULL);
 }
 
 void __init omap3_init_irq(void)
 {
-	omap_init_irq(OMAP34XX_IC_BASE, 96);
+	omap_init_irq(OMAP34XX_IC_BASE, 96, NULL);
 }
 
 void __init ti81xx_init_irq(void)
 {
-	omap_init_irq(OMAP34XX_IC_BASE, 128);
+	omap_init_irq(OMAP34XX_IC_BASE, 128, NULL);
 }
 
 static inline void omap_intc_handle_irq(void __iomem *base_addr, struct pt_regs *regs)
@@ -225,8 +244,10 @@
 		irqnr = readl_relaxed(base_addr + INTCPS_SIR_IRQ_OFFSET);
 		irqnr &= ACTIVEIRQ_MASK;
 
-		if (irqnr)
+		if (irqnr) {
+			irqnr = irq_find_mapping(domain, irqnr);
 			handle_IRQ(irqnr, regs);
+		}
 	} while (irqnr);
 }
 
@@ -236,6 +257,28 @@
 	omap_intc_handle_irq(base_addr, regs);
 }
 
+int __init omap_intc_of_init(struct device_node *node,
+			     struct device_node *parent)
+{
+	struct resource res;
+	u32 nr_irqs = 96;
+
+	if (WARN_ON(!node))
+		return -ENODEV;
+
+	if (of_address_to_resource(node, 0, &res)) {
+		WARN(1, "unable to get intc registers\n");
+		return -EINVAL;
+	}
+
+	if (of_property_read_u32(node, "ti,intc-size", &nr_irqs))
+		pr_warn("unable to get intc-size, default to %d\n", nr_irqs);
+
+	omap_init_irq(res.start, nr_irqs, of_node_get(node));
+
+	return 0;
+}
+
 #ifdef CONFIG_ARCH_OMAP3
 static struct omap3_intc_regs intc_context[ARRAY_SIZE(irq_banks)];
 
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c
index fb4bcf8..577cb77 100644
--- a/arch/arm/mach-omap2/mcbsp.c
+++ b/arch/arm/mach-omap2/mcbsp.c
@@ -34,7 +34,7 @@
 #include "cm2xxx_3xxx.h"
 #include "cm-regbits-34xx.h"
 
-/* McBSP internal signal muxing function */
+/* McBSP1 internal signal muxing function for OMAP2/3 */
 static int omap2_mcbsp1_mux_rx_clk(struct device *dev, const char *signal,
 				   const char *src)
 {
@@ -65,6 +65,42 @@
 	return 0;
 }
 
+/* McBSP4 internal signal muxing function for OMAP4 */
+#define OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_FSX	(1 << 31)
+#define OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_CLKX	(1 << 30)
+static int omap4_mcbsp4_mux_rx_clk(struct device *dev, const char *signal,
+				   const char *src)
+{
+	u32 v;
+
+	/*
+	 * In CONTROL_MCBSPLP register only bit 30 (CLKR mux), and bit 31 (FSR
+	 * mux) is used */
+	v = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MCBSPLP);
+
+	if (!strcmp(signal, "clkr")) {
+		if (!strcmp(src, "clkr"))
+			v &= ~OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_CLKX;
+		else if (!strcmp(src, "clkx"))
+			v |= OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_CLKX;
+		else
+			return -EINVAL;
+	} else if (!strcmp(signal, "fsr")) {
+		if (!strcmp(src, "fsr"))
+			v &= ~OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_FSX;
+		else if (!strcmp(src, "fsx"))
+			v |= OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_FSX;
+		else
+			return -EINVAL;
+	} else {
+		return -EINVAL;
+	}
+
+	omap4_ctrl_pad_writel(v, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MCBSPLP);
+
+	return 0;
+}
+
 /* McBSP CLKS source switching function */
 static int omap2_mcbsp_set_clk_src(struct device *dev, struct clk *clk,
 				   const char *src)
@@ -122,7 +158,7 @@
 	return 0;
 }
 
-static int omap_init_mcbsp(struct omap_hwmod *oh, void *unused)
+static int __init omap_init_mcbsp(struct omap_hwmod *oh, void *unused)
 {
 	int id, count = 1;
 	char *name = "omap-mcbsp";
@@ -146,9 +182,15 @@
 		pdata->has_ccr = true;
 	}
 	pdata->set_clk_src = omap2_mcbsp_set_clk_src;
-	if (id == 1)
+
+	/* On OMAP2/3 the McBSP1 port has 6 pin configuration */
+	if (id == 1 && oh->class->rev < MCBSP_CONFIG_TYPE4)
 		pdata->mux_signal = omap2_mcbsp1_mux_rx_clk;
 
+	/* On OMAP4 the McBSP4 port has 6 pin configuration */
+	if (id == 4 && oh->class->rev == MCBSP_CONFIG_TYPE4)
+		pdata->mux_signal = omap4_mcbsp4_mux_rx_clk;
+
 	if (oh->class->rev == MCBSP_CONFIG_TYPE3) {
 		if (id == 2)
 			/* The FIFO has 1024 + 256 locations */
@@ -180,7 +222,6 @@
 					name, oh->name);
 		return PTR_ERR(pdev);
 	}
-	omap_mcbsp_count++;
 	return 0;
 }
 
@@ -188,11 +229,6 @@
 {
 	omap_hwmod_for_each_by_class("mcbsp", omap_init_mcbsp, NULL);
 
-	mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *),
-								GFP_KERNEL);
-	if (!mcbsp_ptr)
-		return -ENOMEM;
-
-	return omap_mcbsp_init();
+	return 0;
 }
 arch_initcall(omap2_mcbsp_init);
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 611a0e3..65c3391 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -35,7 +35,6 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 
-#include <asm/system.h>
 
 #include <plat/omap_hwmod.h>
 
@@ -100,8 +99,8 @@
 
 static char *omap_mux_options;
 
-static int _omap_mux_init_gpio(struct omap_mux_partition *partition,
-			       int gpio, int val)
+static int __init _omap_mux_init_gpio(struct omap_mux_partition *partition,
+				      int gpio, int val)
 {
 	struct omap_mux_entry *e;
 	struct omap_mux *gpio_mux = NULL;
@@ -145,7 +144,7 @@
 	return 0;
 }
 
-int omap_mux_init_gpio(int gpio, int val)
+int __init omap_mux_init_gpio(int gpio, int val)
 {
 	struct omap_mux_partition *partition;
 	int ret;
@@ -159,9 +158,9 @@
 	return -ENODEV;
 }
 
-static int _omap_mux_get_by_name(struct omap_mux_partition *partition,
-				 const char *muxname,
-				 struct omap_mux **found_mux)
+static int __init _omap_mux_get_by_name(struct omap_mux_partition *partition,
+					const char *muxname,
+					struct omap_mux **found_mux)
 {
 	struct omap_mux *mux = NULL;
 	struct omap_mux_entry *e;
@@ -218,7 +217,7 @@
 	return -ENODEV;
 }
 
-static int
+static int __init
 omap_mux_get_by_name(const char *muxname,
 			struct omap_mux_partition **found_partition,
 			struct omap_mux **found_mux)
@@ -240,7 +239,7 @@
 	return -ENODEV;
 }
 
-int omap_mux_init_signal(const char *muxname, int val)
+int __init omap_mux_init_signal(const char *muxname, int val)
 {
 	struct omap_mux_partition *partition = NULL;
 	struct omap_mux *mux = NULL;
diff --git a/arch/arm/mach-omap2/mux.h b/arch/arm/mach-omap2/mux.h
index 2132308..69fe060 100644
--- a/arch/arm/mach-omap2/mux.h
+++ b/arch/arm/mach-omap2/mux.h
@@ -246,7 +246,7 @@
 {
 }
 
-static struct omap_board_mux *board_mux __initdata __maybe_unused;
+static struct omap_board_mux *board_mux __maybe_unused;
 
 #endif
 
diff --git a/arch/arm/mach-omap2/omap-hotplug.c b/arch/arm/mach-omap2/omap-hotplug.c
index adbe4d8..56c345b 100644
--- a/arch/arm/mach-omap2/omap-hotplug.c
+++ b/arch/arm/mach-omap2/omap-hotplug.c
@@ -33,7 +33,7 @@
  * platform-specific code to shutdown a CPU
  * Called with IRQs disabled
  */
-void platform_cpu_die(unsigned int cpu)
+void __ref platform_cpu_die(unsigned int cpu)
 {
 	unsigned int this_cpu;
 
diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index 1d5d010..13670aa 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -46,7 +46,6 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm/smp_scu.h>
-#include <asm/system.h>
 #include <asm/pgalloc.h>
 #include <asm/suspend.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -263,12 +262,10 @@
 	 * In MPUSS OSWR or device OFF, interrupt controller  contest is lost.
 	 */
 	mpuss_clear_prev_logic_pwrst();
-	pwrdm_clear_all_prev_pwrst(mpuss_pd);
 	if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
 		(pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF))
 		save_state = 2;
 
-	clear_cpu_prev_pwrst(cpu);
 	cpu_clear_prev_logic_pwrst(cpu);
 	set_cpu_next_pwrst(cpu, power_state);
 	set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume));
@@ -300,7 +297,7 @@
  * @cpu : CPU ID
  * @power_state: CPU low power state.
  */
-int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
+int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
 {
 	unsigned int cpu_state = 0;
 
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index c1bf3ef..deffbf1 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -23,11 +23,12 @@
 #include <asm/cacheflush.h>
 #include <asm/hardware/gic.h>
 #include <asm/smp_scu.h>
+
 #include <mach/hardware.h>
 #include <mach/omap-secure.h>
 
+#include "iomap.h"
 #include "common.h"
-
 #include "clockdomain.h"
 
 /* SCU base address */
diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c
index d3d8971..42cd7fb 100644
--- a/arch/arm/mach-omap2/omap-wakeupgen.c
+++ b/arch/arm/mach-omap2/omap-wakeupgen.c
@@ -43,7 +43,6 @@
 
 static void __iomem *wakeupgen_base;
 static void __iomem *sar_base;
-static DEFINE_PER_CPU(u32 [NR_REG_BANKS], irqmasks);
 static DEFINE_SPINLOCK(wakeupgen_lock);
 static unsigned int irq_target_cpu[NR_IRQS];
 
@@ -67,14 +66,6 @@
 	__raw_writel(val, sar_base + offset + (idx * 4));
 }
 
-static void _wakeupgen_set_all(unsigned int cpu, unsigned int reg)
-{
-	u8 i;
-
-	for (i = 0; i < NR_REG_BANKS; i++)
-		wakeupgen_writel(reg, i, cpu);
-}
-
 static inline int _wakeupgen_get_irq_info(u32 irq, u32 *bit_posn, u8 *reg_index)
 {
 	unsigned int spi_irq;
@@ -130,22 +121,6 @@
 	wakeupgen_writel(val, i, cpu);
 }
 
-static void _wakeupgen_save_masks(unsigned int cpu)
-{
-	u8 i;
-
-	for (i = 0; i < NR_REG_BANKS; i++)
-		per_cpu(irqmasks, cpu)[i] = wakeupgen_readl(i, cpu);
-}
-
-static void _wakeupgen_restore_masks(unsigned int cpu)
-{
-	u8 i;
-
-	for (i = 0; i < NR_REG_BANKS; i++)
-		wakeupgen_writel(per_cpu(irqmasks, cpu)[i], i, cpu);
-}
-
 /*
  * Architecture specific Mask extension
  */
@@ -170,6 +145,33 @@
 	spin_unlock_irqrestore(&wakeupgen_lock, flags);
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static DEFINE_PER_CPU(u32 [NR_REG_BANKS], irqmasks);
+
+static void _wakeupgen_save_masks(unsigned int cpu)
+{
+	u8 i;
+
+	for (i = 0; i < NR_REG_BANKS; i++)
+		per_cpu(irqmasks, cpu)[i] = wakeupgen_readl(i, cpu);
+}
+
+static void _wakeupgen_restore_masks(unsigned int cpu)
+{
+	u8 i;
+
+	for (i = 0; i < NR_REG_BANKS; i++)
+		wakeupgen_writel(per_cpu(irqmasks, cpu)[i], i, cpu);
+}
+
+static void _wakeupgen_set_all(unsigned int cpu, unsigned int reg)
+{
+	u8 i;
+
+	for (i = 0; i < NR_REG_BANKS; i++)
+		wakeupgen_writel(reg, i, cpu);
+}
+
 /*
  * Mask or unmask all interrupts on given CPU.
  *	0 = Mask all interrupts on the 'cpu'
@@ -191,6 +193,7 @@
 	}
 	spin_unlock_irqrestore(&wakeupgen_lock, flags);
 }
+#endif
 
 #ifdef CONFIG_CPU_PM
 /*
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index eba6cd3..2c27fdb 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1395,7 +1395,7 @@
  */
 static int _ocp_softreset(struct omap_hwmod *oh)
 {
-	u32 v;
+	u32 v, softrst_mask;
 	int c = 0;
 	int ret = 0;
 
@@ -1427,11 +1427,13 @@
 						    oh->class->sysc->syss_offs)
 				   & SYSS_RESETDONE_MASK),
 				  MAX_MODULE_SOFTRESET_WAIT, c);
-	else if (oh->class->sysc->sysc_flags & SYSC_HAS_RESET_STATUS)
+	else if (oh->class->sysc->sysc_flags & SYSC_HAS_RESET_STATUS) {
+		softrst_mask = (0x1 << oh->class->sysc->sysc_fields->srst_shift);
 		omap_test_timeout(!(omap_hwmod_read(oh,
 						     oh->class->sysc->sysc_offs)
-				   & SYSC_TYPE2_SOFTRESET_MASK),
+				   & softrst_mask),
 				  MAX_MODULE_SOFTRESET_WAIT, c);
+	}
 
 	if (c == MAX_MODULE_SOFTRESET_WAIT)
 		pr_warning("omap_hwmod: %s: softreset failed (waited %d usec)\n",
@@ -1477,6 +1479,11 @@
 
 	ret = (oh->class->reset) ? oh->class->reset(oh) : _ocp_softreset(oh);
 
+	if (oh->class->sysc) {
+		_update_sysc_cache(oh);
+		_enable_sysc(oh);
+	}
+
 	return ret;
 }
 
@@ -1786,20 +1793,9 @@
 		return 0;
 	}
 
-	if (!(oh->flags & HWMOD_INIT_NO_RESET)) {
+	if (!(oh->flags & HWMOD_INIT_NO_RESET))
 		_reset(oh);
 
-		/*
-		 * OCP_SYSCONFIG bits need to be reprogrammed after a softreset.
-		 * The _enable() function should be split to
-		 * avoid the rewrite of the OCP_SYSCONFIG register.
-		 */
-		if (oh->class->sysc) {
-			_update_sysc_cache(oh);
-			_enable_sysc(oh);
-		}
-	}
-
 	postsetup_state = oh->_postsetup_state;
 	if (postsetup_state == _HWMOD_STATE_UNKNOWN)
 		postsetup_state = _HWMOD_STATE_ENABLED;
@@ -1907,20 +1903,10 @@
  */
 int omap_hwmod_softreset(struct omap_hwmod *oh)
 {
-	u32 v;
-	int ret;
-
-	if (!oh || !(oh->_sysc_cache))
+	if (!oh)
 		return -EINVAL;
 
-	v = oh->_sysc_cache;
-	ret = _set_softreset(oh, &v);
-	if (ret)
-		goto error;
-	_write_sysconfig(v, oh);
-
-error:
-	return ret;
+	return _ocp_softreset(oh);
 }
 
 /**
@@ -2463,26 +2449,28 @@
  * @oh: struct omap_hwmod *
  *
  * Sets the module OCP socket ENAWAKEUP bit to allow the module to
- * send wakeups to the PRCM.  Eventually this should sets PRCM wakeup
- * registers to cause the PRCM to receive wakeup events from the
- * module.  Does not set any wakeup routing registers beyond this
- * point - if the module is to wake up any other module or subsystem,
- * that must be set separately.  Called by omap_device code.  Returns
- * -EINVAL on error or 0 upon success.
+ * send wakeups to the PRCM, and enable I/O ring wakeup events for
+ * this IP block if it has dynamic mux entries.  Eventually this
+ * should set PRCM wakeup registers to cause the PRCM to receive
+ * wakeup events from the module.  Does not set any wakeup routing
+ * registers beyond this point - if the module is to wake up any other
+ * module or subsystem, that must be set separately.  Called by
+ * omap_device code.  Returns -EINVAL on error or 0 upon success.
  */
 int omap_hwmod_enable_wakeup(struct omap_hwmod *oh)
 {
 	unsigned long flags;
 	u32 v;
 
-	if (!oh->class->sysc ||
-	    !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
-		return -EINVAL;
-
 	spin_lock_irqsave(&oh->_lock, flags);
-	v = oh->_sysc_cache;
-	_enable_wakeup(oh, &v);
-	_write_sysconfig(v, oh);
+
+	if (oh->class->sysc &&
+	    (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) {
+		v = oh->_sysc_cache;
+		_enable_wakeup(oh, &v);
+		_write_sysconfig(v, oh);
+	}
+
 	_set_idle_ioring_wakeup(oh, true);
 	spin_unlock_irqrestore(&oh->_lock, flags);
 
@@ -2494,26 +2482,28 @@
  * @oh: struct omap_hwmod *
  *
  * Clears the module OCP socket ENAWAKEUP bit to prevent the module
- * from sending wakeups to the PRCM.  Eventually this should clear
- * PRCM wakeup registers to cause the PRCM to ignore wakeup events
- * from the module.  Does not set any wakeup routing registers beyond
- * this point - if the module is to wake up any other module or
- * subsystem, that must be set separately.  Called by omap_device
- * code.  Returns -EINVAL on error or 0 upon success.
+ * from sending wakeups to the PRCM, and disable I/O ring wakeup
+ * events for this IP block if it has dynamic mux entries.  Eventually
+ * this should clear PRCM wakeup registers to cause the PRCM to ignore
+ * wakeup events from the module.  Does not set any wakeup routing
+ * registers beyond this point - if the module is to wake up any other
+ * module or subsystem, that must be set separately.  Called by
+ * omap_device code.  Returns -EINVAL on error or 0 upon success.
  */
 int omap_hwmod_disable_wakeup(struct omap_hwmod *oh)
 {
 	unsigned long flags;
 	u32 v;
 
-	if (!oh->class->sysc ||
-	    !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
-		return -EINVAL;
-
 	spin_lock_irqsave(&oh->_lock, flags);
-	v = oh->_sysc_cache;
-	_disable_wakeup(oh, &v);
-	_write_sysconfig(v, oh);
+
+	if (oh->class->sysc &&
+	    (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) {
+		v = oh->_sysc_cache;
+		_disable_wakeup(oh, &v);
+		_write_sysconfig(v, oh);
+	}
+
 	_set_idle_ioring_wakeup(oh, false);
 	spin_unlock_irqrestore(&oh->_lock, flags);
 
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 3c8dd92..34b9766d 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -29,6 +29,7 @@
 
 #include "omap_hwmod_common_data.h"
 
+#include "smartreflex.h"
 #include "prm-regbits-34xx.h"
 #include "cm-regbits-34xx.h"
 #include "wd_timer.h"
@@ -376,6 +377,16 @@
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+static struct omap_hwmod_irq_info omap3_smartreflex_mpu_irqs[] = {
+	{ .irq = 18},
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod_irq_info omap3_smartreflex_core_irqs[] = {
+	{ .irq = 19},
+	{ .irq = -1 }
+};
+
 /* L4 CORE -> SR1 interface */
 static struct omap_hwmod_addr_space omap3_sr1_addr_space[] = {
 	{
@@ -2664,6 +2675,10 @@
 };
 
 /* SR1 */
+static struct omap_smartreflex_dev_attr sr1_dev_attr = {
+	.sensor_voltdm_name   = "mpu_iva",
+};
+
 static struct omap_hwmod_ocp_if *omap3_sr1_slaves[] = {
 	&omap3_l4_core__sr1,
 };
@@ -2672,7 +2687,6 @@
 	.name		= "sr1_hwmod",
 	.class		= &omap34xx_smartreflex_hwmod_class,
 	.main_clk	= "sr1_fck",
-	.vdd_name	= "mpu_iva",
 	.prcm		= {
 		.omap2 = {
 			.prcm_reg_id = 1,
@@ -2684,6 +2698,8 @@
 	},
 	.slaves		= omap3_sr1_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3_sr1_slaves),
+	.dev_attr	= &sr1_dev_attr,
+	.mpu_irqs	= omap3_smartreflex_mpu_irqs,
 	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
 };
 
@@ -2691,7 +2707,6 @@
 	.name		= "sr1_hwmod",
 	.class		= &omap36xx_smartreflex_hwmod_class,
 	.main_clk	= "sr1_fck",
-	.vdd_name	= "mpu_iva",
 	.prcm		= {
 		.omap2 = {
 			.prcm_reg_id = 1,
@@ -2703,9 +2718,15 @@
 	},
 	.slaves		= omap3_sr1_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3_sr1_slaves),
+	.dev_attr	= &sr1_dev_attr,
+	.mpu_irqs	= omap3_smartreflex_mpu_irqs,
 };
 
 /* SR2 */
+static struct omap_smartreflex_dev_attr sr2_dev_attr = {
+	.sensor_voltdm_name	= "core",
+};
+
 static struct omap_hwmod_ocp_if *omap3_sr2_slaves[] = {
 	&omap3_l4_core__sr2,
 };
@@ -2714,7 +2735,6 @@
 	.name		= "sr2_hwmod",
 	.class		= &omap34xx_smartreflex_hwmod_class,
 	.main_clk	= "sr2_fck",
-	.vdd_name	= "core",
 	.prcm		= {
 		.omap2 = {
 			.prcm_reg_id = 1,
@@ -2726,6 +2746,8 @@
 	},
 	.slaves		= omap3_sr2_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3_sr2_slaves),
+	.dev_attr	= &sr2_dev_attr,
+	.mpu_irqs	= omap3_smartreflex_core_irqs,
 	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
 };
 
@@ -2733,7 +2755,6 @@
 	.name		= "sr2_hwmod",
 	.class		= &omap36xx_smartreflex_hwmod_class,
 	.main_clk	= "sr2_fck",
-	.vdd_name	= "core",
 	.prcm		= {
 		.omap2 = {
 			.prcm_reg_id = 1,
@@ -2745,6 +2766,8 @@
 	},
 	.slaves		= omap3_sr2_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3_sr2_slaves),
+	.dev_attr	= &sr2_dev_attr,
+	.mpu_irqs	= omap3_smartreflex_core_irqs,
 };
 
 /*
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index ef0524c..cc9bd10 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -28,12 +28,12 @@
 #include <plat/mcspi.h>
 #include <plat/mcbsp.h>
 #include <plat/mmc.h>
-#include <plat/i2c.h>
 #include <plat/dmtimer.h>
 #include <plat/common.h>
 
 #include "omap_hwmod_common_data.h"
 
+#include "smartreflex.h"
 #include "cm1_44xx.h"
 #include "cm2_44xx.h"
 #include "prm44xx.h"
@@ -2996,6 +2996,11 @@
 	&omap44xx_l4_abe__mcbsp1_dma,
 };
 
+static struct omap_hwmod_opt_clk mcbsp1_opt_clks[] = {
+	{ .role = "pad_fck", .clk = "pad_clks_ck" },
+	{ .role = "prcm_clk", .clk = "mcbsp1_sync_mux_ck" },
+};
+
 static struct omap_hwmod omap44xx_mcbsp1_hwmod = {
 	.name		= "mcbsp1",
 	.class		= &omap44xx_mcbsp_hwmod_class,
@@ -3012,6 +3017,8 @@
 	},
 	.slaves		= omap44xx_mcbsp1_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_mcbsp1_slaves),
+	.opt_clks	= mcbsp1_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(mcbsp1_opt_clks),
 };
 
 /* mcbsp2 */
@@ -3071,6 +3078,11 @@
 	&omap44xx_l4_abe__mcbsp2_dma,
 };
 
+static struct omap_hwmod_opt_clk mcbsp2_opt_clks[] = {
+	{ .role = "pad_fck", .clk = "pad_clks_ck" },
+	{ .role = "prcm_clk", .clk = "mcbsp2_sync_mux_ck" },
+};
+
 static struct omap_hwmod omap44xx_mcbsp2_hwmod = {
 	.name		= "mcbsp2",
 	.class		= &omap44xx_mcbsp_hwmod_class,
@@ -3087,6 +3099,8 @@
 	},
 	.slaves		= omap44xx_mcbsp2_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_mcbsp2_slaves),
+	.opt_clks	= mcbsp2_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(mcbsp2_opt_clks),
 };
 
 /* mcbsp3 */
@@ -3146,6 +3160,11 @@
 	&omap44xx_l4_abe__mcbsp3_dma,
 };
 
+static struct omap_hwmod_opt_clk mcbsp3_opt_clks[] = {
+	{ .role = "pad_fck", .clk = "pad_clks_ck" },
+	{ .role = "prcm_clk", .clk = "mcbsp3_sync_mux_ck" },
+};
+
 static struct omap_hwmod omap44xx_mcbsp3_hwmod = {
 	.name		= "mcbsp3",
 	.class		= &omap44xx_mcbsp_hwmod_class,
@@ -3162,6 +3181,8 @@
 	},
 	.slaves		= omap44xx_mcbsp3_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_mcbsp3_slaves),
+	.opt_clks	= mcbsp3_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(mcbsp3_opt_clks),
 };
 
 /* mcbsp4 */
@@ -3200,6 +3221,11 @@
 	&omap44xx_l4_per__mcbsp4,
 };
 
+static struct omap_hwmod_opt_clk mcbsp4_opt_clks[] = {
+	{ .role = "pad_fck", .clk = "pad_clks_ck" },
+	{ .role = "prcm_clk", .clk = "mcbsp4_sync_mux_ck" },
+};
+
 static struct omap_hwmod omap44xx_mcbsp4_hwmod = {
 	.name		= "mcbsp4",
 	.class		= &omap44xx_mcbsp_hwmod_class,
@@ -3216,6 +3242,8 @@
 	},
 	.slaves		= omap44xx_mcbsp4_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_mcbsp4_slaves),
+	.opt_clks	= mcbsp4_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(mcbsp4_opt_clks),
 };
 
 /*
@@ -3963,6 +3991,10 @@
 };
 
 /* smartreflex_core */
+static struct omap_smartreflex_dev_attr smartreflex_core_dev_attr = {
+	.sensor_voltdm_name   = "core",
+};
+
 static struct omap_hwmod omap44xx_smartreflex_core_hwmod;
 static struct omap_hwmod_irq_info omap44xx_smartreflex_core_irqs[] = {
 	{ .irq = 19 + OMAP44XX_IRQ_GIC_START },
@@ -3999,7 +4031,6 @@
 	.mpu_irqs	= omap44xx_smartreflex_core_irqs,
 
 	.main_clk	= "smartreflex_core_fck",
-	.vdd_name	= "core",
 	.prcm = {
 		.omap4 = {
 			.clkctrl_offs = OMAP4_CM_ALWON_SR_CORE_CLKCTRL_OFFSET,
@@ -4009,9 +4040,14 @@
 	},
 	.slaves		= omap44xx_smartreflex_core_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_smartreflex_core_slaves),
+	.dev_attr	= &smartreflex_core_dev_attr,
 };
 
 /* smartreflex_iva */
+static struct omap_smartreflex_dev_attr smartreflex_iva_dev_attr = {
+	.sensor_voltdm_name	= "iva",
+};
+
 static struct omap_hwmod omap44xx_smartreflex_iva_hwmod;
 static struct omap_hwmod_irq_info omap44xx_smartreflex_iva_irqs[] = {
 	{ .irq = 102 + OMAP44XX_IRQ_GIC_START },
@@ -4047,7 +4083,6 @@
 	.clkdm_name	= "l4_ao_clkdm",
 	.mpu_irqs	= omap44xx_smartreflex_iva_irqs,
 	.main_clk	= "smartreflex_iva_fck",
-	.vdd_name	= "iva",
 	.prcm = {
 		.omap4 = {
 			.clkctrl_offs = OMAP4_CM_ALWON_SR_IVA_CLKCTRL_OFFSET,
@@ -4057,9 +4092,14 @@
 	},
 	.slaves		= omap44xx_smartreflex_iva_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_smartreflex_iva_slaves),
+	.dev_attr	= &smartreflex_iva_dev_attr,
 };
 
 /* smartreflex_mpu */
+static struct omap_smartreflex_dev_attr smartreflex_mpu_dev_attr = {
+	.sensor_voltdm_name	= "mpu",
+};
+
 static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod;
 static struct omap_hwmod_irq_info omap44xx_smartreflex_mpu_irqs[] = {
 	{ .irq = 18 + OMAP44XX_IRQ_GIC_START },
@@ -4095,7 +4135,6 @@
 	.clkdm_name	= "l4_ao_clkdm",
 	.mpu_irqs	= omap44xx_smartreflex_mpu_irqs,
 	.main_clk	= "smartreflex_mpu_fck",
-	.vdd_name	= "mpu",
 	.prcm = {
 		.omap4 = {
 			.clkctrl_offs = OMAP4_CM_ALWON_SR_MPU_CLKCTRL_OFFSET,
@@ -4105,6 +4144,7 @@
 	},
 	.slaves		= omap44xx_smartreflex_mpu_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap44xx_smartreflex_mpu_slaves),
+	.dev_attr	= &smartreflex_mpu_dev_attr,
 };
 
 /*
diff --git a/arch/arm/mach-omap2/opp.c b/arch/arm/mach-omap2/opp.c
index 9262a6b..de6d464 100644
--- a/arch/arm/mach-omap2/opp.c
+++ b/arch/arm/mach-omap2/opp.c
@@ -64,10 +64,10 @@
 		}
 		oh = omap_hwmod_lookup(opp_def->hwmod_name);
 		if (!oh || !oh->od) {
-			pr_warn("%s: no hwmod or odev for %s, [%d] "
+			pr_debug("%s: no hwmod or odev for %s, [%d] "
 				"cannot add OPPs.\n", __func__,
 				opp_def->hwmod_name, i);
-			return -EINVAL;
+			continue;
 		}
 		dev = &oh->od->pdev->dev;
 
diff --git a/arch/arm/mach-omap2/opp2420_data.c b/arch/arm/mach-omap2/opp2420_data.c
index e6dda69..5037e76 100644
--- a/arch/arm/mach-omap2/opp2420_data.c
+++ b/arch/arm/mach-omap2/opp2420_data.c
@@ -28,6 +28,8 @@
  *     http://repository.maemo.org/pool/diablo/free/k/kernel-source-diablo/
  */
 
+#include <plat/hardware.h>
+
 #include "opp2xxx.h"
 #include "sdrc.h"
 #include "clock.h"
diff --git a/arch/arm/mach-omap2/opp2430_data.c b/arch/arm/mach-omap2/opp2430_data.c
index 1b9596a..750805c 100644
--- a/arch/arm/mach-omap2/opp2430_data.c
+++ b/arch/arm/mach-omap2/opp2430_data.c
@@ -26,6 +26,8 @@
  * This is technically part of the OMAP2xxx clock code.
  */
 
+#include <plat/hardware.h>
+
 #include "opp2xxx.h"
 #include "sdrc.h"
 #include "clock.h"
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
index 4411163..814bcd9 100644
--- a/arch/arm/mach-omap2/pm-debug.c
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -220,8 +220,8 @@
 		return 0;
 
 	d = debugfs_create_dir(pwrdm->name, (struct dentry *)dir);
-
-	(void) debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d,
+	if (!(IS_ERR_OR_NULL(d)))
+		(void) debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d,
 			(void *)pwrdm, &pwrdm_suspend_fops);
 
 	return 0;
@@ -264,7 +264,7 @@
 		return 0;
 
 	d = debugfs_create_dir("pm_debug", NULL);
-	if (IS_ERR(d))
+	if (IS_ERR_OR_NULL(d))
 		return PTR_ERR(d);
 
 	(void) debugfs_create_file("count", S_IRUGO,
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 5a65dd0..d0c1c96 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -15,11 +15,15 @@
 #include <linux/err.h>
 #include <linux/opp.h>
 #include <linux/export.h>
+#include <linux/suspend.h>
+
+#include <asm/system_misc.h>
 
 #include <plat/omap-pm.h>
 #include <plat/omap_device.h>
 #include "common.h"
 
+#include "prcm-common.h"
 #include "voltage.h"
 #include "powerdomain.h"
 #include "clockdomain.h"
@@ -28,7 +32,13 @@
 
 static struct omap_device_pm_latency *pm_lats;
 
-static int _init_omap_device(char *name)
+/*
+ * omap_pm_suspend: points to a function that does the SoC-specific
+ * suspend work
+ */
+int (*omap_pm_suspend)(void);
+
+static int __init _init_omap_device(char *name)
 {
 	struct omap_hwmod *oh;
 	struct platform_device *pdev;
@@ -49,7 +59,7 @@
 /*
  * Build omap_devices for processors and bus.
  */
-static void omap2_init_processor_devices(void)
+static void __init omap2_init_processor_devices(void)
 {
 	_init_omap_device("mpu");
 	if (omap3_has_iva())
@@ -68,32 +78,41 @@
 #define FORCEWAKEUP_SWITCH	0
 #define LOWPOWERSTATE_SWITCH	1
 
+int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused)
+{
+	if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
+		clkdm_allow_idle(clkdm);
+	else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
+		 atomic_read(&clkdm->usecount) == 0)
+		clkdm_sleep(clkdm);
+	return 0;
+}
+
 /*
  * This sets pwrdm state (other than mpu & core. Currently only ON &
  * RET are supported.
  */
-int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
+int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst)
 {
-	u32 cur_state;
-	int sleep_switch = -1;
-	int ret = 0;
-	int hwsup = 0;
+	u8 curr_pwrst, next_pwrst;
+	int sleep_switch = -1, ret = 0, hwsup = 0;
 
-	if (pwrdm == NULL || IS_ERR(pwrdm))
+	if (!pwrdm || IS_ERR(pwrdm))
 		return -EINVAL;
 
-	while (!(pwrdm->pwrsts & (1 << state))) {
-		if (state == PWRDM_POWER_OFF)
+	while (!(pwrdm->pwrsts & (1 << pwrst))) {
+		if (pwrst == PWRDM_POWER_OFF)
 			return ret;
-		state--;
+		pwrst--;
 	}
 
-	cur_state = pwrdm_read_next_pwrst(pwrdm);
-	if (cur_state == state)
+	next_pwrst = pwrdm_read_next_pwrst(pwrdm);
+	if (next_pwrst == pwrst)
 		return ret;
 
-	if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
-		if ((pwrdm_read_pwrst(pwrdm) > state) &&
+	curr_pwrst = pwrdm_read_pwrst(pwrdm);
+	if (curr_pwrst < PWRDM_POWER_ON) {
+		if ((curr_pwrst > pwrst) &&
 			(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
 			sleep_switch = LOWPOWERSTATE_SWITCH;
 		} else {
@@ -103,12 +122,10 @@
 		}
 	}
 
-	ret = pwrdm_set_next_pwrst(pwrdm, state);
-	if (ret) {
-		pr_err("%s: unable to set state of powerdomain: %s\n",
+	ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
+	if (ret)
+		pr_err("%s: unable to set power state of powerdomain: %s\n",
 		       __func__, pwrdm->name);
-		goto err;
-	}
 
 	switch (sleep_switch) {
 	case FORCEWAKEUP_SWITCH:
@@ -119,16 +136,16 @@
 		break;
 	case LOWPOWERSTATE_SWITCH:
 		pwrdm_set_lowpwrstchange(pwrdm);
+		pwrdm_wait_transition(pwrdm);
+		pwrdm_state_switch(pwrdm);
 		break;
-	default:
-		return ret;
 	}
 
-	pwrdm_state_switch(pwrdm);
-err:
 	return ret;
 }
 
+
+
 /*
  * This API is to be called during init to set the various voltage
  * domains to the voltage as per the opp table. Typically we boot up
@@ -199,6 +216,56 @@
 	return -EINVAL;
 }
 
+#ifdef CONFIG_SUSPEND
+static int omap_pm_enter(suspend_state_t suspend_state)
+{
+	int ret = 0;
+
+	if (!omap_pm_suspend)
+		return -ENOENT; /* XXX doublecheck */
+
+	switch (suspend_state) {
+	case PM_SUSPEND_STANDBY:
+	case PM_SUSPEND_MEM:
+		ret = omap_pm_suspend();
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int omap_pm_begin(suspend_state_t state)
+{
+	disable_hlt();
+	if (cpu_is_omap34xx())
+		omap_prcm_irq_prepare();
+	return 0;
+}
+
+static void omap_pm_end(void)
+{
+	enable_hlt();
+	return;
+}
+
+static void omap_pm_finish(void)
+{
+	if (cpu_is_omap34xx())
+		omap_prcm_irq_complete();
+}
+
+static const struct platform_suspend_ops omap_pm_ops = {
+	.begin		= omap_pm_begin,
+	.end		= omap_pm_end,
+	.enter		= omap_pm_enter,
+	.finish		= omap_pm_finish,
+	.valid		= suspend_valid_only_mem,
+};
+
+#endif /* CONFIG_SUSPEND */
+
 static void __init omap3_init_voltages(void)
 {
 	if (!cpu_is_omap34xx())
@@ -230,6 +297,14 @@
 
 static int __init omap2_common_pm_late_init(void)
 {
+	/*
+	 * In the case of DT, the PMIC and SR initialization will be done using
+	 * a completely different mechanism.
+	 * Disable this part if a DT blob is available.
+	 */
+	if (of_have_populated_dt())
+		return 0;
+
 	/* Init the voltage layer */
 	omap_pmic_late_init();
 	omap_voltage_late_init();
@@ -241,6 +316,10 @@
 	/* Smartreflex device init */
 	omap_devinit_smartreflex();
 
+#ifdef CONFIG_SUSPEND
+	suspend_set_ops(&omap_pm_ops);
+#endif
+
 	return 0;
 }
 late_initcall(omap2_common_pm_late_init);
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index b737b11..36fa90b 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -18,10 +18,11 @@
 extern void *omap3_secure_ram_storage;
 extern void omap3_pm_off_mode_enable(int);
 extern void omap_sram_idle(void);
-extern int omap3_can_sleep(void);
 extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
 extern int omap3_idle_init(void);
 extern int omap4_idle_init(void);
+extern int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused);
+extern int (*omap_pm_suspend)(void);
 
 #if defined(CONFIG_PM_OPP)
 extern int omap3_opp_init(void);
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index 23de98d..95442b6 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -26,7 +26,6 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
-#include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/time.h>
 #include <linux/gpio.h>
@@ -34,13 +33,15 @@
 #include <asm/mach/time.h>
 #include <asm/mach/irq.h>
 #include <asm/mach-types.h>
+#include <asm/system_misc.h>
 
-#include <mach/irqs.h>
 #include <plat/clock.h>
 #include <plat/sram.h>
 #include <plat/dma.h>
 #include <plat/board.h>
 
+#include <mach/irqs.h>
+
 #include "common.h"
 #include "prm2xxx_3xxx.h"
 #include "prm-regbits-24xx.h"
@@ -49,23 +50,9 @@
 #include "sdrc.h"
 #include "pm.h"
 #include "control.h"
-
 #include "powerdomain.h"
 #include "clockdomain.h"
 
-#ifdef CONFIG_SUSPEND
-static suspend_state_t suspend_state = PM_SUSPEND_ON;
-static inline bool is_suspending(void)
-{
-	return (suspend_state != PM_SUSPEND_ON);
-}
-#else
-static inline bool is_suspending(void)
-{
-	return false;
-}
-#endif
-
 static void (*omap2_sram_idle)(void);
 static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
 				  void __iomem *sdrc_power);
@@ -85,7 +72,7 @@
 	return (f1 | f2) ? 1 : 0;
 }
 
-static void omap2_enter_full_retention(void)
+static int omap2_enter_full_retention(void)
 {
 	u32 l;
 
@@ -148,6 +135,8 @@
 
 	/* Mask future PRCM-to-MPU interrupts */
 	omap2_prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+
+	return 0;
 }
 
 static int omap2_i2c_active(void)
@@ -226,7 +215,6 @@
 
 static void omap2_pm_idle(void)
 {
-	local_irq_disable();
 	local_fiq_disable();
 
 	if (!omap2_can_sleep()) {
@@ -243,78 +231,6 @@
 
 out:
 	local_fiq_enable();
-	local_irq_enable();
-}
-
-#ifdef CONFIG_SUSPEND
-static int omap2_pm_begin(suspend_state_t state)
-{
-	disable_hlt();
-	suspend_state = state;
-	return 0;
-}
-
-static int omap2_pm_suspend(void)
-{
-	u32 wken_wkup, mir1;
-
-	wken_wkup = omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN);
-	wken_wkup &= ~OMAP24XX_EN_GPT1_MASK;
-	omap2_prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN);
-
-	/* Mask GPT1 */
-	mir1 = omap_readl(0x480fe0a4);
-	omap_writel(1 << 5, 0x480fe0ac);
-
-	omap2_enter_full_retention();
-
-	omap_writel(mir1, 0x480fe0a4);
-	omap2_prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN);
-
-	return 0;
-}
-
-static int omap2_pm_enter(suspend_state_t state)
-{
-	int ret = 0;
-
-	switch (state) {
-	case PM_SUSPEND_STANDBY:
-	case PM_SUSPEND_MEM:
-		ret = omap2_pm_suspend();
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static void omap2_pm_end(void)
-{
-	suspend_state = PM_SUSPEND_ON;
-	enable_hlt();
-}
-
-static const struct platform_suspend_ops omap_pm_ops = {
-	.begin		= omap2_pm_begin,
-	.enter		= omap2_pm_enter,
-	.end		= omap2_pm_end,
-	.valid		= suspend_valid_only_mem,
-};
-#else
-static const struct platform_suspend_ops __initdata omap_pm_ops;
-#endif /* CONFIG_SUSPEND */
-
-/* XXX This function should be shareable between OMAP2xxx and OMAP3 */
-static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
-{
-	if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
-		clkdm_allow_idle(clkdm);
-	else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
-		 atomic_read(&clkdm->usecount) == 0)
-		clkdm_sleep(clkdm);
-	return 0;
 }
 
 static void __init prcm_setup_regs(void)
@@ -358,9 +274,13 @@
 	clkdm_sleep(gfx_clkdm);
 
 	/* Enable hardware-supervised idle for all clkdms */
-	clkdm_for_each(clkdms_setup, NULL);
+	clkdm_for_each(omap_pm_clkdms_setup, NULL);
 	clkdm_add_wkdep(mpu_clkdm, wkup_clkdm);
 
+#ifdef CONFIG_SUSPEND
+	omap_pm_suspend = omap2_enter_full_retention;
+#endif
+
 	/* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
 	 * stabilisation */
 	omap2_prm_write_mod_reg(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
@@ -461,8 +381,7 @@
 						    omap24xx_cpu_suspend_sz);
 	}
 
-	suspend_set_ops(&omap_pm_ops);
-	pm_idle = omap2_pm_idle;
+	arm_pm_idle = omap2_pm_idle;
 
 	return 0;
 }
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index fc69875..703bd10 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -31,6 +31,7 @@
 #include <trace/events/power.h>
 
 #include <asm/suspend.h>
+#include <asm/system_misc.h>
 
 #include <plat/sram.h>
 #include "clockdomain.h"
@@ -50,10 +51,6 @@
 #include "sdrc.h"
 #include "control.h"
 
-#ifdef CONFIG_SUSPEND
-static suspend_state_t suspend_state = PM_SUSPEND_ON;
-#endif
-
 /* pm34xx errata defined in pm.h */
 u16 pm34xx_errata;
 
@@ -75,16 +72,6 @@
 static struct powerdomain *core_pwrdm, *per_pwrdm;
 static struct powerdomain *cam_pwrdm;
 
-static inline void omap3_per_save_context(void)
-{
-	omap_gpio_save_context();
-}
-
-static inline void omap3_per_restore_context(void)
-{
-	omap_gpio_restore_context();
-}
-
 static void omap3_enable_io_chain(void)
 {
 	int timeout = 0;
@@ -166,8 +153,7 @@
 		pwrdm_set_next_pwrst(mpu_pwrdm, mpu_next_state);
 		/* Following is for error tracking, it should not happen */
 		if (ret) {
-			printk(KERN_ERR "save_secure_sram() returns %08x\n",
-				ret);
+			pr_err("save_secure_sram() returns %08x\n", ret);
 			while (1)
 				;
 		}
@@ -290,11 +276,6 @@
 	int core_prev_state, per_prev_state;
 	u32 sdrc_pwr = 0;
 
-	pwrdm_clear_all_prev_pwrst(mpu_pwrdm);
-	pwrdm_clear_all_prev_pwrst(neon_pwrdm);
-	pwrdm_clear_all_prev_pwrst(core_pwrdm);
-	pwrdm_clear_all_prev_pwrst(per_pwrdm);
-
 	mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
 	switch (mpu_next_state) {
 	case PWRDM_POWER_ON:
@@ -307,7 +288,7 @@
 		break;
 	default:
 		/* Invalid state */
-		printk(KERN_ERR "Invalid mpu state in sram_idle\n");
+		pr_err("Invalid mpu state in sram_idle\n");
 		return;
 	}
 
@@ -332,8 +313,6 @@
 	if (per_next_state < PWRDM_POWER_ON) {
 		per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
 		omap2_gpio_prepare_for_idle(per_going_off);
-		if (per_next_state == PWRDM_POWER_OFF)
-				omap3_per_save_context();
 	}
 
 	/* CORE */
@@ -399,8 +378,6 @@
 	if (per_next_state < PWRDM_POWER_ON) {
 		per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);
 		omap2_gpio_resume_after_idle();
-		if (per_prev_state == PWRDM_POWER_OFF)
-			omap3_per_restore_context();
 	}
 
 	/* Disable IO-PAD and IO-CHAIN wakeup */
@@ -418,10 +395,9 @@
 
 static void omap3_pm_idle(void)
 {
-	local_irq_disable();
 	local_fiq_disable();
 
-	if (omap_irq_pending() || need_resched())
+	if (omap_irq_pending())
 		goto out;
 
 	trace_power_start(POWER_CSTATE, 1, smp_processor_id());
@@ -434,7 +410,6 @@
 
 out:
 	local_fiq_enable();
-	local_irq_enable();
 }
 
 #ifdef CONFIG_SUSPEND
@@ -463,66 +438,21 @@
 	list_for_each_entry(pwrst, &pwrst_list, node) {
 		state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
 		if (state > pwrst->next_state) {
-			printk(KERN_INFO "Powerdomain (%s) didn't enter "
-			       "target state %d\n",
+			pr_info("Powerdomain (%s) didn't enter "
+				"target state %d\n",
 			       pwrst->pwrdm->name, pwrst->next_state);
 			ret = -1;
 		}
 		omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
 	}
 	if (ret)
-		printk(KERN_ERR "Could not enter target state in pm_suspend\n");
+		pr_err("Could not enter target state in pm_suspend\n");
 	else
-		printk(KERN_INFO "Successfully put all powerdomains "
-		       "to target state\n");
+		pr_info("Successfully put all powerdomains to target state\n");
 
 	return ret;
 }
 
-static int omap3_pm_enter(suspend_state_t unused)
-{
-	int ret = 0;
-
-	switch (suspend_state) {
-	case PM_SUSPEND_STANDBY:
-	case PM_SUSPEND_MEM:
-		ret = omap3_pm_suspend();
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-/* Hooks to enable / disable UART interrupts during suspend */
-static int omap3_pm_begin(suspend_state_t state)
-{
-	disable_hlt();
-	suspend_state = state;
-	omap_prcm_irq_prepare();
-	return 0;
-}
-
-static void omap3_pm_end(void)
-{
-	suspend_state = PM_SUSPEND_ON;
-	enable_hlt();
-	return;
-}
-
-static void omap3_pm_finish(void)
-{
-	omap_prcm_irq_complete();
-}
-
-static const struct platform_suspend_ops omap_pm_ops = {
-	.begin		= omap3_pm_begin,
-	.end		= omap3_pm_end,
-	.enter		= omap3_pm_enter,
-	.finish		= omap3_pm_finish,
-	.valid		= suspend_valid_only_mem,
-};
 #endif /* CONFIG_SUSPEND */
 
 
@@ -743,21 +673,6 @@
 }
 
 /*
- * Enable hw supervised mode for all clockdomains if it's
- * supported. Initiate sleep transition for other clockdomains, if
- * they are not used
- */
-static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
-{
-	if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
-		clkdm_allow_idle(clkdm);
-	else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
-		 atomic_read(&clkdm->usecount) == 0)
-		clkdm_sleep(clkdm);
-	return 0;
-}
-
-/*
  * Push functions to SRAM
  *
  * The minimum set of functions is pushed to SRAM for execution:
@@ -817,21 +732,22 @@
 
 	if (ret) {
 		pr_err("pm: Failed to request pm_io irq\n");
-		goto err1;
+		goto err2;
 	}
 
 	ret = pwrdm_for_each(pwrdms_setup, NULL);
 	if (ret) {
-		printk(KERN_ERR "Failed to setup powerdomains\n");
-		goto err2;
+		pr_err("Failed to setup powerdomains\n");
+		goto err3;
 	}
 
-	(void) clkdm_for_each(clkdms_setup, NULL);
+	(void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
 
 	mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
 	if (mpu_pwrdm == NULL) {
-		printk(KERN_ERR "Failed to get mpu_pwrdm\n");
-		goto err2;
+		pr_err("Failed to get mpu_pwrdm\n");
+		ret = -EINVAL;
+		goto err3;
 	}
 
 	neon_pwrdm = pwrdm_lookup("neon_pwrdm");
@@ -845,10 +761,10 @@
 	core_clkdm = clkdm_lookup("core_clkdm");
 
 #ifdef CONFIG_SUSPEND
-	suspend_set_ops(&omap_pm_ops);
-#endif /* CONFIG_SUSPEND */
+	omap_pm_suspend = omap3_pm_suspend;
+#endif
 
-	pm_idle = omap3_pm_idle;
+	arm_pm_idle = omap3_pm_idle;
 	omap3_idle_init();
 
 	/*
@@ -864,8 +780,8 @@
 		omap3_secure_ram_storage =
 			kmalloc(0x803F, GFP_KERNEL);
 		if (!omap3_secure_ram_storage)
-			printk(KERN_ERR "Memory allocation failed when"
-					"allocating for secure sram context\n");
+			pr_err("Memory allocation failed when "
+			       "allocating for secure sram context\n");
 
 		local_irq_disable();
 		local_fiq_disable();
@@ -879,14 +795,17 @@
 	}
 
 	omap3_save_scratchpad_contents();
-err1:
 	return ret;
-err2:
-	free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
+
+err3:
 	list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
 		list_del(&pwrst->node);
 		kfree(pwrst);
 	}
+	free_irq(omap_prcm_event_to_irq("io"), omap3_pm_init);
+err2:
+	free_irq(omap_prcm_event_to_irq("wkup"), NULL);
+err1:
 	return ret;
 }
 
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index c264ef7..8856253 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -16,6 +16,7 @@
 #include <linux/list.h>
 #include <linux/err.h>
 #include <linux/slab.h>
+#include <asm/system_misc.h>
 
 #include "common.h"
 #include "clockdomain.h"
@@ -83,59 +84,8 @@
 
 	return 0;
 }
-
-static int omap4_pm_enter(suspend_state_t suspend_state)
-{
-	int ret = 0;
-
-	switch (suspend_state) {
-	case PM_SUSPEND_STANDBY:
-	case PM_SUSPEND_MEM:
-		ret = omap4_pm_suspend();
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static int omap4_pm_begin(suspend_state_t state)
-{
-	disable_hlt();
-	return 0;
-}
-
-static void omap4_pm_end(void)
-{
-	enable_hlt();
-	return;
-}
-
-static const struct platform_suspend_ops omap_pm_ops = {
-	.begin		= omap4_pm_begin,
-	.end		= omap4_pm_end,
-	.enter		= omap4_pm_enter,
-	.valid		= suspend_valid_only_mem,
-};
 #endif /* CONFIG_SUSPEND */
 
-/*
- * Enable hardware supervised mode for all clockdomains if it's
- * supported. Initiate sleep transition for other clockdomains, if
- * they are not used
- */
-static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
-{
-	if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
-		clkdm_allow_idle(clkdm);
-	else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
-			atomic_read(&clkdm->usecount) == 0)
-		clkdm_sleep(clkdm);
-	return 0;
-}
-
-
 static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 {
 	struct power_state *pwrst;
@@ -173,18 +123,16 @@
  * omap_default_idle - OMAP4 default ilde routine.'
  *
  * Implements OMAP4 memory, IO ordering requirements which can't be addressed
- * with default arch_idle() hook. Used by all CPUs with !CONFIG_CPUIDLE and
+ * with default cpu_do_idle() hook. Used by all CPUs with !CONFIG_CPUIDLE and
  * by secondary CPU with CONFIG_CPUIDLE.
  */
 static void omap_default_idle(void)
 {
-	local_irq_disable();
 	local_fiq_disable();
 
 	omap_do_wfi();
 
 	local_fiq_enable();
-	local_irq_enable();
 }
 
 /**
@@ -196,7 +144,7 @@
 static int __init omap4_pm_init(void)
 {
 	int ret;
-	struct clockdomain *emif_clkdm, *mpuss_clkdm, *l3_1_clkdm;
+	struct clockdomain *emif_clkdm, *mpuss_clkdm, *l3_1_clkdm, *l4wkup;
 	struct clockdomain *ducati_clkdm, *l3_2_clkdm, *l4_per_clkdm;
 
 	if (!cpu_is_omap44xx())
@@ -220,14 +168,19 @@
 	 * MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as
 	 * expected. The hardware recommendation is to enable static
 	 * dependencies for these to avoid system lock ups or random crashes.
+	 * The L4 wakeup depedency is added to workaround the OCP sync hardware
+	 * BUG with 32K synctimer which lead to incorrect timer value read
+	 * from the 32K counter. The BUG applies for GPTIMER1 and WDT2 which
+	 * are part of L4 wakeup clockdomain.
 	 */
 	mpuss_clkdm = clkdm_lookup("mpuss_clkdm");
 	emif_clkdm = clkdm_lookup("l3_emif_clkdm");
 	l3_1_clkdm = clkdm_lookup("l3_1_clkdm");
 	l3_2_clkdm = clkdm_lookup("l3_2_clkdm");
 	l4_per_clkdm = clkdm_lookup("l4_per_clkdm");
+	l4wkup = clkdm_lookup("l4_wkup_clkdm");
 	ducati_clkdm = clkdm_lookup("ducati_clkdm");
-	if ((!mpuss_clkdm) || (!emif_clkdm) || (!l3_1_clkdm) ||
+	if ((!mpuss_clkdm) || (!emif_clkdm) || (!l3_1_clkdm) || (!l4wkup) ||
 		(!l3_2_clkdm) || (!ducati_clkdm) || (!l4_per_clkdm))
 		goto err2;
 
@@ -235,6 +188,7 @@
 	ret |= clkdm_add_wkdep(mpuss_clkdm, l3_1_clkdm);
 	ret |= clkdm_add_wkdep(mpuss_clkdm, l3_2_clkdm);
 	ret |= clkdm_add_wkdep(mpuss_clkdm, l4_per_clkdm);
+	ret |= clkdm_add_wkdep(mpuss_clkdm, l4wkup);
 	ret |= clkdm_add_wkdep(ducati_clkdm, l3_1_clkdm);
 	ret |= clkdm_add_wkdep(ducati_clkdm, l3_2_clkdm);
 	if (ret) {
@@ -249,14 +203,14 @@
 		goto err2;
 	}
 
-	(void) clkdm_for_each(clkdms_setup, NULL);
+	(void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
 
 #ifdef CONFIG_SUSPEND
-	suspend_set_ops(&omap_pm_ops);
-#endif /* CONFIG_SUSPEND */
+	omap_pm_suspend = omap4_pm_suspend;
+#endif
 
-	/* Overwrite the default arch_idle() */
-	pm_idle = omap_default_idle;
+	/* Overwrite the default cpu_do_idle() */
+	arm_pm_idle = omap_default_idle;
 
 	omap4_idle_init();
 
diff --git a/arch/arm/mach-omap2/powerdomain-common.c b/arch/arm/mach-omap2/powerdomain-common.c
index f97afff..c0aeabf 100644
--- a/arch/arm/mach-omap2/powerdomain-common.c
+++ b/arch/arm/mach-omap2/powerdomain-common.c
@@ -13,6 +13,7 @@
 
 #include <linux/errno.h>
 #include <linux/kernel.h>
+#include <linux/bug.h>
 #include "pm.h"
 #include "cm.h"
 #include "cm-regbits-34xx.h"
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 8a18d1b..96ad3dbe 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -972,7 +972,13 @@
 
 int pwrdm_state_switch(struct powerdomain *pwrdm)
 {
-	return _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
+	int ret;
+
+	ret = pwrdm_wait_transition(pwrdm);
+	if (!ret)
+		ret = _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
+
+	return ret;
 }
 
 int pwrdm_clkdm_state_switch(struct clockdomain *clkdm)
diff --git a/arch/arm/mach-omap2/powerdomain2xxx_3xxx.c b/arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
index 6a17e4c..0f0a9f1 100644
--- a/arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
@@ -15,6 +15,7 @@
 #include <linux/io.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
+#include <linux/bug.h>
 
 #include <plat/prcm.h>
 
diff --git a/arch/arm/mach-omap2/powerdomain44xx.c b/arch/arm/mach-omap2/powerdomain44xx.c
index a7880af..601325b 100644
--- a/arch/arm/mach-omap2/powerdomain44xx.c
+++ b/arch/arm/mach-omap2/powerdomain44xx.c
@@ -15,6 +15,7 @@
 #include <linux/io.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
+#include <linux/bug.h>
 
 #include "powerdomain.h"
 #include <plat/prcm.h>
diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c
index 8ef26da..b7ea468 100644
--- a/arch/arm/mach-omap2/powerdomains3xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c
@@ -13,6 +13,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/bug.h>
 
 #include <plat/cpu.h>
 
diff --git a/arch/arm/mach-omap2/prcm_mpu44xx.c b/arch/arm/mach-omap2/prcm_mpu44xx.c
index ca669b5..928dbd4 100644
--- a/arch/arm/mach-omap2/prcm_mpu44xx.c
+++ b/arch/arm/mach-omap2/prcm_mpu44xx.c
@@ -15,8 +15,8 @@
 #include <linux/err.h>
 #include <linux/io.h>
 
+#include "iomap.h"
 #include "common.h"
-
 #include "prcm_mpu44xx.h"
 #include "cm-regbits-44xx.h"
 
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
index a1d6154..f106d21 100644
--- a/arch/arm/mach-omap2/prm44xx.c
+++ b/arch/arm/mach-omap2/prm44xx.c
@@ -17,11 +17,12 @@
 #include <linux/err.h>
 #include <linux/io.h>
 
-#include "common.h"
 #include <plat/cpu.h>
 #include <plat/irqs.h>
 #include <plat/prcm.h>
 
+#include "iomap.h"
+#include "common.h"
 #include "vp.h"
 #include "prm44xx.h"
 #include "prm-regbits-44xx.h"
@@ -146,8 +147,9 @@
 	u32 mask, st;
 
 	/* XXX read mask from RAM? */
-	mask = omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST, irqen_offs);
-	st = omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST, irqst_offs);
+	mask = omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
+				       irqen_offs);
+	st = omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, irqst_offs);
 
 	return mask & st;
 }
@@ -179,7 +181,7 @@
  */
 void omap44xx_prm_ocp_barrier(void)
 {
-	omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+	omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
 				OMAP4_REVISION_PRM_OFFSET);
 }
 
@@ -197,19 +199,19 @@
 void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask)
 {
 	saved_mask[0] =
-		omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+		omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
 					OMAP4_PRM_IRQSTATUS_MPU_OFFSET);
 	saved_mask[1] =
-		omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+		omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
 					OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET);
 
-	omap4_prm_write_inst_reg(0, OMAP4430_PRM_DEVICE_INST,
+	omap4_prm_write_inst_reg(0, OMAP4430_PRM_OCP_SOCKET_INST,
 				 OMAP4_PRM_IRQENABLE_MPU_OFFSET);
-	omap4_prm_write_inst_reg(0, OMAP4430_PRM_DEVICE_INST,
+	omap4_prm_write_inst_reg(0, OMAP4430_PRM_OCP_SOCKET_INST,
 				 OMAP4_PRM_IRQENABLE_MPU_2_OFFSET);
 
 	/* OCP barrier */
-	omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+	omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
 				OMAP4_REVISION_PRM_OFFSET);
 }
 
@@ -225,9 +227,9 @@
  */
 void omap44xx_prm_restore_irqen(u32 *saved_mask)
 {
-	omap4_prm_write_inst_reg(saved_mask[0], OMAP4430_PRM_DEVICE_INST,
+	omap4_prm_write_inst_reg(saved_mask[0], OMAP4430_PRM_OCP_SOCKET_INST,
 				 OMAP4_PRM_IRQENABLE_MPU_OFFSET);
-	omap4_prm_write_inst_reg(saved_mask[1], OMAP4430_PRM_DEVICE_INST,
+	omap4_prm_write_inst_reg(saved_mask[1], OMAP4430_PRM_OCP_SOCKET_INST,
 				 OMAP4_PRM_IRQENABLE_MPU_2_OFFSET);
 }
 
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
index 860118a..d28f848 100644
--- a/arch/arm/mach-omap2/prm_common.c
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -24,7 +24,6 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 
-#include <mach/system.h>
 #include <plat/common.h>
 #include <plat/prcm.h>
 #include <plat/irqs.h>
@@ -291,7 +290,7 @@
 		goto err;
 	}
 
-	for (i = 0; i <= irq_setup->nr_regs; i++) {
+	for (i = 0; i < irq_setup->nr_regs; i++) {
 		gc = irq_alloc_generic_chip("PRCM", 1,
 			irq_setup->base_irq + i * 32, prm_base,
 			handle_level_irq);
diff --git a/arch/arm/mach-omap2/prminst44xx.c b/arch/arm/mach-omap2/prminst44xx.c
index f6de5bc..9b3898a 100644
--- a/arch/arm/mach-omap2/prminst44xx.c
+++ b/arch/arm/mach-omap2/prminst44xx.c
@@ -16,8 +16,8 @@
 #include <linux/err.h>
 #include <linux/io.h>
 
+#include "iomap.h"
 #include "common.h"
-
 #include "prm44xx.h"
 #include "prminst44xx.h"
 #include "prm-regbits-44xx.h"
diff --git a/arch/arm/mach-omap2/sdram-nokia.c b/arch/arm/mach-omap2/sdram-nokia.c
index 7479d7e..845c4fd 100644
--- a/arch/arm/mach-omap2/sdram-nokia.c
+++ b/arch/arm/mach-omap2/sdram-nokia.c
@@ -17,7 +17,6 @@
 #include <linux/err.h>
 #include <linux/io.h>
 
-#include <plat/io.h>
 #include "common.h"
 #include <plat/clock.h>
 #include <plat/sdrc.h>
diff --git a/arch/arm/mach-omap2/sdrc2xxx.c b/arch/arm/mach-omap2/sdrc2xxx.c
index 791a63c..1133bb2 100644
--- a/arch/arm/mach-omap2/sdrc2xxx.c
+++ b/arch/arm/mach-omap2/sdrc2xxx.c
@@ -24,13 +24,15 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 
-#include "common.h"
+#include <plat/hardware.h>
 #include <plat/clock.h>
 #include <plat/sram.h>
+#include <plat/sdrc.h>
 
+#include "iomap.h"
+#include "common.h"
 #include "prm2xxx_3xxx.h"
 #include "clock.h"
-#include <plat/sdrc.h>
 #include "sdrc.h"
 
 /* Memory timing, DLL mode flags */
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index f590afc..0cdd359 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -54,11 +54,9 @@
 
 struct omap_uart_state {
 	int num;
-	int can_sleep;
 
 	struct list_head node;
 	struct omap_hwmod *oh;
-	struct platform_device *pdev;
 };
 
 static LIST_HEAD(uart_list);
@@ -381,8 +379,6 @@
 
 	oh->mux = omap_hwmod_mux_init(bdata->pads, bdata->pads_cnt);
 
-	uart->pdev = pdev;
-
 	oh->dev_attr = uart;
 
 	if (((cpu_is_omap34xx() || cpu_is_omap44xx()) && bdata->pads)
diff --git a/arch/arm/mach-omap2/sleep24xx.S b/arch/arm/mach-omap2/sleep24xx.S
index b5071a4..d4bf904 100644
--- a/arch/arm/mach-omap2/sleep24xx.S
+++ b/arch/arm/mach-omap2/sleep24xx.S
@@ -27,7 +27,6 @@
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <mach/io.h>
 
 #include <plat/omap24xx.h>
 
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
index f2ea1bd..1f62f23 100644
--- a/arch/arm/mach-omap2/sleep34xx.S
+++ b/arch/arm/mach-omap2/sleep34xx.S
@@ -23,10 +23,13 @@
  * MA 02111-1307 USA
  */
 #include <linux/linkage.h>
-#include <asm/assembler.h>
-#include <plat/sram.h>
-#include <mach/io.h>
 
+#include <asm/assembler.h>
+
+#include <plat/hardware.h>
+#include <plat/sram.h>
+
+#include "iomap.h"
 #include "cm2xxx_3xxx.h"
 #include "prm2xxx_3xxx.h"
 #include "sdrc.h"
diff --git a/arch/arm/mach-omap2/sleep44xx.S b/arch/arm/mach-omap2/sleep44xx.S
index abd2834..9f6b83d 100644
--- a/arch/arm/mach-omap2/sleep44xx.S
+++ b/arch/arm/mach-omap2/sleep44xx.S
@@ -10,7 +10,6 @@
  */
 
 #include <linux/linkage.h>
-#include <asm/system.h>
 #include <asm/smp_scu.h>
 #include <asm/memory.h>
 #include <asm/hardware/cache-l2x0.h>
diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
index 53d9d0a..955566ee 100644
--- a/arch/arm/mach-omap2/smartreflex-class3.c
+++ b/arch/arm/mach-omap2/smartreflex-class3.c
@@ -29,6 +29,7 @@
 
 static int sr_class3_disable(struct voltagedomain *voltdm, int is_volt_reset)
 {
+	sr_disable_errgen(voltdm);
 	omap_vp_disable(voltdm);
 	sr_disable(voltdm);
 	if (is_volt_reset)
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 7e755bb..008fbd7 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -36,6 +36,12 @@
 #define SR_DISABLE_TIMEOUT	200
 
 struct omap_sr {
+	struct list_head		node;
+	struct platform_device		*pdev;
+	struct omap_sr_nvalue_table	*nvalue_table;
+	struct voltagedomain		*voltdm;
+	struct dentry			*dbg_dir;
+	unsigned int			irq;
 	int				srid;
 	int				ip_type;
 	int				nvalue_count;
@@ -49,13 +55,7 @@
 	u32				senp_avgweight;
 	u32				senp_mod;
 	u32				senn_mod;
-	unsigned int			irq;
 	void __iomem			*base;
-	struct platform_device		*pdev;
-	struct list_head		node;
-	struct omap_sr_nvalue_table	*nvalue_table;
-	struct voltagedomain		*voltdm;
-	struct dentry			*dbg_dir;
 };
 
 /* sr_list contains all the instances of smartreflex module */
@@ -74,10 +74,6 @@
 					u32 value)
 {
 	u32 reg_val;
-	u32 errconfig_offs = 0, errconfig_mask = 0;
-
-	reg_val = __raw_readl(sr->base + offset);
-	reg_val &= ~mask;
 
 	/*
 	 * Smartreflex error config register is special as it contains
@@ -88,16 +84,15 @@
 	 * if they are currently set, but does allow the caller to write
 	 * those bits.
 	 */
-	if (sr->ip_type == SR_TYPE_V1) {
-		errconfig_offs = ERRCONFIG_V1;
-		errconfig_mask = ERRCONFIG_STATUS_V1_MASK;
-	} else if (sr->ip_type == SR_TYPE_V2) {
-		errconfig_offs = ERRCONFIG_V2;
-		errconfig_mask = ERRCONFIG_VPBOUNDINTST_V2;
-	}
+	if (sr->ip_type == SR_TYPE_V1 && offset == ERRCONFIG_V1)
+		mask |= ERRCONFIG_STATUS_V1_MASK;
+	else if (sr->ip_type == SR_TYPE_V2 && offset == ERRCONFIG_V2)
+		mask |= ERRCONFIG_VPBOUNDINTST_V2;
 
-	if (offset == errconfig_offs)
-		reg_val &= ~errconfig_mask;
+	reg_val = __raw_readl(sr->base + offset);
+	reg_val &= ~mask;
+
+	value &= mask;
 
 	reg_val |= value;
 
@@ -128,21 +123,28 @@
 
 static irqreturn_t sr_interrupt(int irq, void *data)
 {
-	struct omap_sr *sr_info = (struct omap_sr *)data;
+	struct omap_sr *sr_info = data;
 	u32 status = 0;
 
-	if (sr_info->ip_type == SR_TYPE_V1) {
+	switch (sr_info->ip_type) {
+	case SR_TYPE_V1:
 		/* Read the status bits */
 		status = sr_read_reg(sr_info, ERRCONFIG_V1);
 
 		/* Clear them by writing back */
 		sr_write_reg(sr_info, ERRCONFIG_V1, status);
-	} else if (sr_info->ip_type == SR_TYPE_V2) {
+		break;
+	case SR_TYPE_V2:
 		/* Read the status bits */
 		status = sr_read_reg(sr_info, IRQSTATUS);
 
 		/* Clear them by writing back */
 		sr_write_reg(sr_info, IRQSTATUS, status);
+		break;
+	default:
+		dev_err(&sr_info->pdev->dev, "UNKNOWN IP type %d\n",
+			sr_info->ip_type);
+		return IRQ_NONE;
 	}
 
 	if (sr_class->notify)
@@ -166,6 +168,7 @@
 			__func__);
 		return;
 	}
+
 	sys_clk_speed = clk_get_rate(sys_ck);
 	clk_put(sys_ck);
 
@@ -267,7 +270,7 @@
 			goto error;
 		}
 		ret = request_irq(sr_info->irq, sr_interrupt,
-				0, name, (void *)sr_info);
+				0, name, sr_info);
 		if (ret)
 			goto error;
 		disable_irq(sr_info->irq);
@@ -288,12 +291,15 @@
 		"not function as desired\n", __func__);
 	kfree(name);
 	kfree(sr_info);
+
 	return ret;
 }
 
 static void sr_v1_disable(struct omap_sr *sr)
 {
 	int timeout = 0;
+	int errconf_val = ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST |
+			ERRCONFIG_MCUBOUNDINTST;
 
 	/* Enable MCUDisableAcknowledge interrupt */
 	sr_modify_reg(sr, ERRCONFIG_V1,
@@ -302,13 +308,13 @@
 	/* SRCONFIG - disable SR */
 	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
 
-	/* Disable all other SR interrupts and clear the status */
+	/* Disable all other SR interrupts and clear the status as needed */
+	if (sr_read_reg(sr, ERRCONFIG_V1) & ERRCONFIG_VPBOUNDINTST_V1)
+		errconf_val |= ERRCONFIG_VPBOUNDINTST_V1;
 	sr_modify_reg(sr, ERRCONFIG_V1,
 			(ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
 			ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_VPBOUNDINTEN_V1),
-			(ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST |
-			ERRCONFIG_MCUBOUNDINTST |
-			ERRCONFIG_VPBOUNDINTST_V1));
+			errconf_val);
 
 	/*
 	 * Wait for SR to be disabled.
@@ -337,9 +343,17 @@
 	/* SRCONFIG - disable SR */
 	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
 
-	/* Disable all other SR interrupts and clear the status */
-	sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
+	/*
+	 * Disable all other SR interrupts and clear the status
+	 * write to status register ONLY on need basis - only if status
+	 * is set.
+	 */
+	if (sr_read_reg(sr, ERRCONFIG_V2) & ERRCONFIG_VPBOUNDINTST_V2)
+		sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
 			ERRCONFIG_VPBOUNDINTST_V2);
+	else
+		sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
+				0x0);
 	sr_write_reg(sr, IRQENABLE_CLR, (IRQENABLE_MCUACCUMINT |
 			IRQENABLE_MCUVALIDINT |
 			IRQENABLE_MCUBOUNDSINT));
@@ -398,15 +412,16 @@
  */
 int sr_configure_errgen(struct voltagedomain *voltdm)
 {
-	u32 sr_config, sr_errconfig, errconfig_offs, vpboundint_en;
-	u32 vpboundint_st, senp_en = 0, senn_en = 0;
+	u32 sr_config, sr_errconfig, errconfig_offs;
+	u32 vpboundint_en, vpboundint_st;
+	u32 senp_en = 0, senn_en = 0;
 	u8 senp_shift, senn_shift;
 	struct omap_sr *sr = _sr_lookup(voltdm);
 
 	if (IS_ERR(sr)) {
 		pr_warning("%s: omap_sr struct for sr_%s not found\n",
 			__func__, voltdm->name);
-		return -EINVAL;
+		return PTR_ERR(sr);
 	}
 
 	if (!sr->clk_length)
@@ -418,20 +433,23 @@
 	sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
 		SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN;
 
-	if (sr->ip_type == SR_TYPE_V1) {
+	switch (sr->ip_type) {
+	case SR_TYPE_V1:
 		sr_config |= SRCONFIG_DELAYCTRL;
 		senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
 		senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
 		errconfig_offs = ERRCONFIG_V1;
 		vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;
 		vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1;
-	} else if (sr->ip_type == SR_TYPE_V2) {
+		break;
+	case SR_TYPE_V2:
 		senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
 		senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
 		errconfig_offs = ERRCONFIG_V2;
 		vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;
 		vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2;
-	} else {
+		break;
+	default:
 		dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
 			"module without specifying the ip\n", __func__);
 		return -EINVAL;
@@ -447,8 +465,55 @@
 		sr_errconfig);
 
 	/* Enabling the interrupts if the ERROR module is used */
-	sr_modify_reg(sr, errconfig_offs,
-		vpboundint_en, (vpboundint_en | vpboundint_st));
+	sr_modify_reg(sr, errconfig_offs, (vpboundint_en | vpboundint_st),
+		      vpboundint_en);
+
+	return 0;
+}
+
+/**
+ * sr_disable_errgen() - Disables SmartReflex AVS module's errgen component
+ * @voltdm:	VDD pointer to which the SR module to be configured belongs to.
+ *
+ * This API is to be called from the smartreflex class driver to
+ * disable the error generator module inside the smartreflex module.
+ *
+ * Returns 0 on success and error value in case of failure.
+ */
+int sr_disable_errgen(struct voltagedomain *voltdm)
+{
+	u32 errconfig_offs;
+	u32 vpboundint_en, vpboundint_st;
+	struct omap_sr *sr = _sr_lookup(voltdm);
+
+	if (IS_ERR(sr)) {
+		pr_warning("%s: omap_sr struct for sr_%s not found\n",
+			__func__, voltdm->name);
+		return PTR_ERR(sr);
+	}
+
+	switch (sr->ip_type) {
+	case SR_TYPE_V1:
+		errconfig_offs = ERRCONFIG_V1;
+		vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;
+		vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1;
+		break;
+	case SR_TYPE_V2:
+		errconfig_offs = ERRCONFIG_V2;
+		vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;
+		vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2;
+		break;
+	default:
+		dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
+			"module without specifying the ip\n", __func__);
+		return -EINVAL;
+	}
+
+	/* Disable the interrupts of ERROR module */
+	sr_modify_reg(sr, errconfig_offs, vpboundint_en | vpboundint_st, 0);
+
+	/* Disable the Sensor and errorgen */
+	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN, 0);
 
 	return 0;
 }
@@ -475,7 +540,7 @@
 	if (IS_ERR(sr)) {
 		pr_warning("%s: omap_sr struct for sr_%s not found\n",
 			__func__, voltdm->name);
-		return -EINVAL;
+		return PTR_ERR(sr);
 	}
 
 	if (!sr->clk_length)
@@ -488,14 +553,17 @@
 		SRCONFIG_SENENABLE |
 		(sr->accum_data << SRCONFIG_ACCUMDATA_SHIFT);
 
-	if (sr->ip_type == SR_TYPE_V1) {
+	switch (sr->ip_type) {
+	case SR_TYPE_V1:
 		sr_config |= SRCONFIG_DELAYCTRL;
 		senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
 		senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
-	} else if (sr->ip_type == SR_TYPE_V2) {
+		break;
+	case SR_TYPE_V2:
 		senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
 		senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
-	} else {
+		break;
+	default:
 		dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
 			"module without specifying the ip\n", __func__);
 		return -EINVAL;
@@ -511,20 +579,27 @@
 	 * Enabling the interrupts if MINMAXAVG module is used.
 	 * TODO: check if all the interrupts are mandatory
 	 */
-	if (sr->ip_type == SR_TYPE_V1) {
+	switch (sr->ip_type) {
+	case SR_TYPE_V1:
 		sr_modify_reg(sr, ERRCONFIG_V1,
 			(ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
 			ERRCONFIG_MCUBOUNDINTEN),
 			(ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUACCUMINTST |
 			 ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUVALIDINTST |
 			 ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST));
-	} else if (sr->ip_type == SR_TYPE_V2) {
+		break;
+	case SR_TYPE_V2:
 		sr_write_reg(sr, IRQSTATUS,
 			IRQSTATUS_MCUACCUMINT | IRQSTATUS_MCVALIDINT |
 			IRQSTATUS_MCBOUNDSINT | IRQSTATUS_MCUDISABLEACKINT);
 		sr_write_reg(sr, IRQENABLE_SET,
 			IRQENABLE_MCUACCUMINT | IRQENABLE_MCUVALIDINT |
 			IRQENABLE_MCUBOUNDSINT | IRQENABLE_MCUDISABLEACKINT);
+		break;
+	default:
+		dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
+			"module without specifying the ip\n", __func__);
+		return -EINVAL;
 	}
 
 	return 0;
@@ -543,15 +618,15 @@
  */
 int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
 {
-	u32 nvalue_reciprocal;
 	struct omap_volt_data *volt_data;
 	struct omap_sr *sr = _sr_lookup(voltdm);
+	u32 nvalue_reciprocal;
 	int ret;
 
 	if (IS_ERR(sr)) {
 		pr_warning("%s: omap_sr struct for sr_%s not found\n",
 			__func__, voltdm->name);
-		return -EINVAL;
+		return PTR_ERR(sr);
 	}
 
 	volt_data = omap_voltage_get_voltdata(sr->voltdm, volt);
@@ -559,7 +634,7 @@
 	if (IS_ERR(volt_data)) {
 		dev_warn(&sr->pdev->dev, "%s: Unable to get voltage table"
 			"for nominal voltage %ld\n", __func__, volt);
-		return -ENODATA;
+		return PTR_ERR(volt_data);
 	}
 
 	nvalue_reciprocal = sr_retrieve_nvalue(sr, volt_data->sr_efuse_offs);
@@ -617,10 +692,17 @@
 	 * disable the clocks.
 	 */
 	if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE) {
-		if (sr->ip_type == SR_TYPE_V1)
+		switch (sr->ip_type) {
+		case SR_TYPE_V1:
 			sr_v1_disable(sr);
-		else if (sr->ip_type == SR_TYPE_V2)
+			break;
+		case SR_TYPE_V2:
 			sr_v2_disable(sr);
+			break;
+		default:
+			dev_err(&sr->pdev->dev, "UNKNOWN IP type %d\n",
+				sr->ip_type);
+		}
 	}
 
 	pm_runtime_put_sync_suspend(&sr->pdev->dev);
@@ -779,10 +861,10 @@
 	sr_pmic_data = pmic_data;
 }
 
-/* PM Debug Fs enteries to enable disable smartreflex. */
+/* PM Debug FS entries to enable and disable smartreflex. */
 static int omap_sr_autocomp_show(void *data, u64 *val)
 {
-	struct omap_sr *sr_info = (struct omap_sr *) data;
+	struct omap_sr *sr_info = data;
 
 	if (!sr_info) {
 		pr_warning("%s: omap_sr struct not found\n", __func__);
@@ -796,7 +878,7 @@
 
 static int omap_sr_autocomp_store(void *data, u64 val)
 {
-	struct omap_sr *sr_info = (struct omap_sr *) data;
+	struct omap_sr *sr_info = data;
 
 	if (!sr_info) {
 		pr_warning("%s: omap_sr struct not found\n", __func__);
@@ -804,7 +886,7 @@
 	}
 
 	/* Sanity check */
-	if (val && (val != 1)) {
+	if (val > 1) {
 		pr_warning("%s: Invalid argument %lld\n", __func__, val);
 		return -EINVAL;
 	}
@@ -821,11 +903,11 @@
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(pm_sr_fops, omap_sr_autocomp_show,
-		omap_sr_autocomp_store, "%llu\n");
+			omap_sr_autocomp_store, "%llu\n");
 
 static int __init omap_sr_probe(struct platform_device *pdev)
 {
-	struct omap_sr *sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
+	struct omap_sr *sr_info;
 	struct omap_sr_data *pdata = pdev->dev.platform_data;
 	struct resource *mem, *irq;
 	struct dentry *nvalue_dir;
@@ -833,12 +915,15 @@
 	int i, ret = 0;
 	char *name;
 
+	sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
 	if (!sr_info) {
 		dev_err(&pdev->dev, "%s: unable to allocate sr_info\n",
 			__func__);
 		return -ENOMEM;
 	}
 
+	platform_set_drvdata(pdev, sr_info);
+
 	if (!pdata) {
 		dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
 		ret = -EINVAL;
@@ -904,7 +989,7 @@
 	dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);
 	if (!sr_dbg_dir) {
 		sr_dbg_dir = debugfs_create_dir("smartreflex", NULL);
-		if (!sr_dbg_dir) {
+		if (IS_ERR_OR_NULL(sr_dbg_dir)) {
 			ret = PTR_ERR(sr_dbg_dir);
 			pr_err("%s:sr debugfs dir creation failed(%d)\n",
 				__func__, ret);
@@ -921,7 +1006,7 @@
 	}
 	sr_info->dbg_dir = debugfs_create_dir(name, sr_dbg_dir);
 	kfree(name);
-	if (IS_ERR(sr_info->dbg_dir)) {
+	if (IS_ERR_OR_NULL(sr_info->dbg_dir)) {
 		dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
 			__func__);
 		ret = PTR_ERR(sr_info->dbg_dir);
@@ -938,7 +1023,7 @@
 			&sr_info->err_minlimit);
 
 	nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir);
-	if (IS_ERR(nvalue_dir)) {
+	if (IS_ERR_OR_NULL(nvalue_dir)) {
 		dev_err(&pdev->dev, "%s: Unable to create debugfs directory"
 			"for n-values\n", __func__);
 		ret = PTR_ERR(nvalue_dir);
@@ -994,7 +1079,7 @@
 	if (IS_ERR(sr_info)) {
 		dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
 			__func__);
-		return -EINVAL;
+		return PTR_ERR(sr_info);
 	}
 
 	if (sr_info->autocomp_active)
@@ -1011,8 +1096,32 @@
 	return 0;
 }
 
+static void __devexit omap_sr_shutdown(struct platform_device *pdev)
+{
+	struct omap_sr_data *pdata = pdev->dev.platform_data;
+	struct omap_sr *sr_info;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
+		return;
+	}
+
+	sr_info = _sr_lookup(pdata->voltdm);
+	if (IS_ERR(sr_info)) {
+		dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
+			__func__);
+		return;
+	}
+
+	if (sr_info->autocomp_active)
+		sr_stop_vddautocomp(sr_info);
+
+	return;
+}
+
 static struct platform_driver smartreflex_driver = {
-	.remove         = omap_sr_remove,
+	.remove         = __devexit_p(omap_sr_remove),
+	.shutdown	= __devexit_p(omap_sr_shutdown),
 	.driver		= {
 		.name	= "smartreflex",
 	},
@@ -1042,12 +1151,12 @@
 
 	return 0;
 }
+late_initcall(sr_init);
 
 static void __exit sr_exit(void)
 {
 	platform_driver_unregister(&smartreflex_driver);
 }
-late_initcall(sr_init);
 module_exit(sr_exit);
 
 MODULE_DESCRIPTION("OMAP Smartreflex Driver");
diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h
index 5f35b9e..5809141 100644
--- a/arch/arm/mach-omap2/smartreflex.h
+++ b/arch/arm/mach-omap2/smartreflex.h
@@ -152,6 +152,15 @@
 	void (*sr_pmic_init) (void);
 };
 
+/**
+ * struct omap_smartreflex_dev_attr - Smartreflex Device attribute.
+ *
+ * @sensor_voltdm_name:       Name of voltdomain of SR instance
+ */
+struct omap_smartreflex_dev_attr {
+	const char      *sensor_voltdm_name;
+};
+
 #ifdef CONFIG_OMAP_SMARTREFLEX
 /*
  * The smart reflex driver supports CLASS1 CLASS2 and CLASS3 SR.
@@ -231,6 +240,7 @@
 int sr_enable(struct voltagedomain *voltdm, unsigned long volt);
 void sr_disable(struct voltagedomain *voltdm);
 int sr_configure_errgen(struct voltagedomain *voltdm);
+int sr_disable_errgen(struct voltagedomain *voltdm);
 int sr_configure_minmax(struct voltagedomain *voltdm);
 
 /* API to register the smartreflex class driver with the smartreflex driver */
diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c
index 9f43fcc..a503e1e 100644
--- a/arch/arm/mach-omap2/sr_device.c
+++ b/arch/arm/mach-omap2/sr_device.c
@@ -69,11 +69,12 @@
 	sr_data->nvalue_count = count;
 }
 
-static int sr_dev_init(struct omap_hwmod *oh, void *user)
+static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
 {
 	struct omap_sr_data *sr_data;
 	struct platform_device *pdev;
 	struct omap_volt_data *volt_data;
+	struct omap_smartreflex_dev_attr *sr_dev_attr;
 	char *name = "smartreflex";
 	static int i;
 
@@ -84,9 +85,11 @@
 		return -ENOMEM;
 	}
 
-	if (!oh->vdd_name) {
+	sr_dev_attr = (struct omap_smartreflex_dev_attr *)oh->dev_attr;
+	if (!sr_dev_attr || !sr_dev_attr->sensor_voltdm_name) {
 		pr_err("%s: No voltage domain specified for %s."
-			"Cannot initialize\n", __func__, oh->name);
+				"Cannot initialize\n", __func__,
+					oh->name);
 		goto exit;
 	}
 
@@ -94,10 +97,10 @@
 	sr_data->senn_mod = 0x1;
 	sr_data->senp_mod = 0x1;
 
-	sr_data->voltdm = voltdm_lookup(oh->vdd_name);
+	sr_data->voltdm = voltdm_lookup(sr_dev_attr->sensor_voltdm_name);
 	if (IS_ERR(sr_data->voltdm)) {
 		pr_err("%s: Unable to get voltage domain pointer for VDD %s\n",
-			__func__, oh->vdd_name);
+			__func__, sr_dev_attr->sensor_voltdm_name);
 		goto exit;
 	}
 
diff --git a/arch/arm/mach-omap2/sram242x.S b/arch/arm/mach-omap2/sram242x.S
index ff9b9db..ee0bfcc 100644
--- a/arch/arm/mach-omap2/sram242x.S
+++ b/arch/arm/mach-omap2/sram242x.S
@@ -29,10 +29,12 @@
  * These crashes may be intermittent.
  */
 #include <linux/linkage.h>
+
 #include <asm/assembler.h>
-#include <mach/io.h>
+
 #include <mach/hardware.h>
 
+#include "iomap.h"
 #include "prm2xxx_3xxx.h"
 #include "cm2xxx_3xxx.h"
 #include "sdrc.h"
diff --git a/arch/arm/mach-omap2/sram243x.S b/arch/arm/mach-omap2/sram243x.S
index 7673020..d4d39ef 100644
--- a/arch/arm/mach-omap2/sram243x.S
+++ b/arch/arm/mach-omap2/sram243x.S
@@ -29,10 +29,12 @@
  * These crashes may be intermittent.
  */
 #include <linux/linkage.h>
+
 #include <asm/assembler.h>
-#include <mach/io.h>
+
 #include <mach/hardware.h>
 
+#include "iomap.h"
 #include "prm2xxx_3xxx.h"
 #include "cm2xxx_3xxx.h"
 #include "sdrc.h"
diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S
index 6f5849a..df5a213 100644
--- a/arch/arm/mach-omap2/sram34xx.S
+++ b/arch/arm/mach-omap2/sram34xx.S
@@ -26,11 +26,12 @@
  * MA 02111-1307 USA
  */
 #include <linux/linkage.h>
+
 #include <asm/assembler.h>
+
 #include <mach/hardware.h>
 
-#include <mach/io.h>
-
+#include "iomap.h"
 #include "sdrc.h"
 #include "cm2xxx_3xxx.h"
 
diff --git a/arch/arm/mach-omap2/timer-mpu.c b/arch/arm/mach-omap2/timer-mpu.c
deleted file mode 100644
index 31c0ac4..0000000
--- a/arch/arm/mach-omap2/timer-mpu.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * The MPU local timer source file. In OMAP4, both cortex-a9 cores have
- * own timer in it's MPU domain. These timers will be driving the
- * linux kernel SMP tick framework when active. These timers are not
- * part of the wake up domain.
- *
- * Copyright (C) 2009 Texas Instruments, Inc.
- *
- * Author:
- *      Santosh Shilimkar <santosh.shilimkar@ti.com>
- *
- * This file is based on arm realview smp platform file.
- * Copyright (C) 2002 ARM Ltd.
- *
- * 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/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-#include <asm/irq.h>
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	/* Local timers are not supprted on OMAP4430 ES1.0 */
-	if (omap_rev() == OMAP4430_REV_ES1_0)
-		return -ENXIO;
-
-	evt->irq = OMAP44XX_IRQ_LOCALTIMER;
-	twd_timer_setup(evt);
-	return 0;
-}
-
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 5c9acea..c512bac 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -39,7 +39,7 @@
 
 #include <asm/mach/time.h>
 #include <plat/dmtimer.h>
-#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
 #include <asm/sched_clock.h>
 #include "common.h"
 #include <plat/omap_hwmod.h>
@@ -324,14 +324,26 @@
 #endif
 
 #ifdef CONFIG_ARCH_OMAP4
+#ifdef CONFIG_LOCAL_TIMERS
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
+			      OMAP44XX_LOCAL_TWD_BASE,
+			      OMAP44XX_IRQ_LOCALTIMER);
+#endif
+
 static void __init omap4_timer_init(void)
 {
-#ifdef CONFIG_LOCAL_TIMERS
-	twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_256);
-	BUG_ON(!twd_base);
-#endif
 	omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE);
 	omap2_gp_clocksource_init(2, OMAP4_MPU_SOURCE);
+#ifdef CONFIG_LOCAL_TIMERS
+	/* Local timers are not supprted on OMAP4430 ES1.0 */
+	if (omap_rev() != OMAP4430_REV_ES1_0) {
+		int err;
+
+		err = twd_local_timer_register(&twd_local_timer);
+		if (err)
+			pr_err("twd_local_timer_register failed %d\n", err);
+	}
+#endif
 }
 OMAP_SYS_TIMER(4)
 #endif
diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c
index f51348d..dde8a11 100644
--- a/arch/arm/mach-omap2/usb-host.c
+++ b/arch/arm/mach-omap2/usb-host.c
@@ -54,7 +54,7 @@
 /*
  * setup_ehci_io_mux - initialize IO pad mux for USBHOST
  */
-static void setup_ehci_io_mux(const enum usbhs_omap_port_mode *port_mode)
+static void __init setup_ehci_io_mux(const enum usbhs_omap_port_mode *port_mode)
 {
 	switch (port_mode[0]) {
 	case OMAP_EHCI_PORT_MODE_PHY:
@@ -197,7 +197,8 @@
 	return;
 }
 
-static void setup_4430ehci_io_mux(const enum usbhs_omap_port_mode *port_mode)
+static
+void __init setup_4430ehci_io_mux(const enum usbhs_omap_port_mode *port_mode)
 {
 	switch (port_mode[0]) {
 	case OMAP_EHCI_PORT_MODE_PHY:
@@ -315,7 +316,7 @@
 	}
 }
 
-static void setup_ohci_io_mux(const enum usbhs_omap_port_mode *port_mode)
+static void __init setup_ohci_io_mux(const enum usbhs_omap_port_mode *port_mode)
 {
 	switch (port_mode[0]) {
 	case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
@@ -412,7 +413,8 @@
 	}
 }
 
-static void setup_4430ohci_io_mux(const enum usbhs_omap_port_mode *port_mode)
+static
+void __init setup_4430ohci_io_mux(const enum usbhs_omap_port_mode *port_mode)
 {
 	switch (port_mode[0]) {
 	case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c
index 175b7d8..84da34f 100644
--- a/arch/arm/mach-omap2/vc.c
+++ b/arch/arm/mach-omap2/vc.c
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/bug.h>
 
 #include <plat/cpu.h>
 
diff --git a/arch/arm/mach-omap2/vp.c b/arch/arm/mach-omap2/vp.c
index 0df8882..f95c1ba 100644
--- a/arch/arm/mach-omap2/vp.c
+++ b/arch/arm/mach-omap2/vp.c
@@ -61,8 +61,8 @@
 	vddmin = voltdm->pmic->vp_vddmin;
 	vddmax = voltdm->pmic->vp_vddmax;
 
-	waittime = ((voltdm->pmic->step_size / voltdm->pmic->slew_rate) *
-		    sys_clk_rate) / 1000;
+	waittime = DIV_ROUND_UP(voltdm->pmic->step_size * sys_clk_rate,
+				1000 * voltdm->pmic->slew_rate);
 	vstepmin = voltdm->pmic->vp_vstepmin;
 	vstepmax = voltdm->pmic->vp_vstepmax;
 
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index 5dad38e..2448166 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -21,6 +21,7 @@
 #include <net/dsa.h>
 #include <asm/page.h>
 #include <asm/setup.h>
+#include <asm/system_misc.h>
 #include <asm/timex.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h
index d2513ac..2e6454c 100644
--- a/arch/arm/mach-orion5x/common.h
+++ b/arch/arm/mach-orion5x/common.h
@@ -57,5 +57,14 @@
 struct tag;
 extern void __init tag_fixup_mem32(struct tag *, char **, struct meminfo *);
 
+/*****************************************************************************
+ * Helpers to access Orion registers
+ ****************************************************************************/
+/*
+ * These are not preempt-safe.  Locks, if needed, must be taken
+ * care of by the caller.
+ */
+#define orion5x_setbits(r, mask)	writel(readl(r) | (mask), (r))
+#define orion5x_clrbits(r, mask)	writel(readl(r) & ~(mask), (r))
 
 #endif
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c
index 91b0f47..c3ed15b 100644
--- a/arch/arm/mach-orion5x/dns323-setup.c
+++ b/arch/arm/mach-orion5x/dns323-setup.c
@@ -32,6 +32,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/pci.h>
+#include <asm/system_info.h>
 #include <mach/orion5x.h>
 #include "common.h"
 #include "mpp.h"
diff --git a/arch/arm/mach-orion5x/include/mach/entry-macro.S b/arch/arm/mach-orion5x/include/mach/entry-macro.S
index d658992..79eb502 100644
--- a/arch/arm/mach-orion5x/include/mach/entry-macro.S
+++ b/arch/arm/mach-orion5x/include/mach/entry-macro.S
@@ -10,12 +10,6 @@
 
 #include <mach/bridge-regs.h>
 
-	.macro  disable_fiq
-	.endm
-
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
-
 	.macro  get_irqnr_preamble, base, tmp
 	ldr	\base, =MAIN_IRQ_CAUSE
 	.endm
diff --git a/arch/arm/mach-orion5x/include/mach/io.h b/arch/arm/mach-orion5x/include/mach/io.h
deleted file mode 100644
index e9d9afd..0000000
--- a/arch/arm/mach-orion5x/include/mach/io.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * arch/arm/mach-orion5x/include/mach/io.h
- *
- * Tzachi Perelstein <tzachi@marvell.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.
- */
-
-#ifndef __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#include "orion5x.h"
-
-#define IO_SPACE_LIMIT		0xffffffff
-
-#define __io(a)			__typesafe_io(a)
-#define __mem_pci(a)		(a)
-
-
-/*****************************************************************************
- * Helpers to access Orion registers
- ****************************************************************************/
-/*
- * These are not preempt-safe.  Locks, if needed, must be taken
- * care of by the caller.
- */
-#define orion5x_setbits(r, mask)	writel(readl(r) | (mask), (r))
-#define orion5x_clrbits(r, mask)	writel(readl(r) & ~(mask), (r))
-
-
-#endif
diff --git a/arch/arm/mach-orion5x/include/mach/system.h b/arch/arm/mach-orion5x/include/mach/system.h
deleted file mode 100644
index 825a265..0000000
--- a/arch/arm/mach-orion5x/include/mach/system.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-orion5x/include/mach/system.h
- *
- * Tzachi Perelstein <tzachi@marvell.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.
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-orion5x/ls-chl-setup.c b/arch/arm/mach-orion5x/ls-chl-setup.c
index 5272131..0c9e413 100644
--- a/arch/arm/mach-orion5x/ls-chl-setup.c
+++ b/arch/arm/mach-orion5x/ls-chl-setup.c
@@ -22,7 +22,6 @@
 #include <linux/gpio.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/system.h>
 #include <mach/orion5x.h>
 #include "common.h"
 #include "mpp.h"
diff --git a/arch/arm/mach-orion5x/ls_hgl-setup.c b/arch/arm/mach-orion5x/ls_hgl-setup.c
index 9a8697b..c1b5d8a 100644
--- a/arch/arm/mach-orion5x/ls_hgl-setup.c
+++ b/arch/arm/mach-orion5x/ls_hgl-setup.c
@@ -21,7 +21,6 @@
 #include <linux/gpio.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/system.h>
 #include <mach/orion5x.h>
 #include "common.h"
 #include "mpp.h"
diff --git a/arch/arm/mach-orion5x/lsmini-setup.c b/arch/arm/mach-orion5x/lsmini-setup.c
index 09c7365..949eaa8 100644
--- a/arch/arm/mach-orion5x/lsmini-setup.c
+++ b/arch/arm/mach-orion5x/lsmini-setup.c
@@ -21,7 +21,6 @@
 #include <linux/gpio.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/system.h>
 #include <mach/orion5x.h>
 #include "common.h"
 #include "mpp.h"
diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c
index 09a045f..cb19e16 100644
--- a/arch/arm/mach-orion5x/pci.c
+++ b/arch/arm/mach-orion5x/pci.c
@@ -19,6 +19,7 @@
 #include <asm/mach/pci.h>
 #include <plat/pcie.h>
 #include <plat/addr-map.h>
+#include <mach/orion5x.h>
 #include "common.h"
 
 /*****************************************************************************
@@ -171,13 +172,14 @@
 	/*
 	 * IORESOURCE_IO
 	 */
+	sys->io_offset = 0;
 	res[0].name = "PCIe I/O Space";
 	res[0].flags = IORESOURCE_IO;
 	res[0].start = ORION5X_PCIE_IO_BUS_BASE;
 	res[0].end = res[0].start + ORION5X_PCIE_IO_SIZE - 1;
 	if (request_resource(&ioport_resource, &res[0]))
 		panic("Request PCIe IO resource failed\n");
-	pci_add_resource(&sys->resources, &res[0]);
+	pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
 
 	/*
 	 * IORESOURCE_MEM
@@ -188,9 +190,7 @@
 	res[1].end = res[1].start + ORION5X_PCIE_MEM_SIZE - 1;
 	if (request_resource(&iomem_resource, &res[1]))
 		panic("Request PCIe Memory resource failed\n");
-	pci_add_resource(&sys->resources, &res[1]);
-
-	sys->io_offset = 0;
+	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
 
 	return 1;
 }
@@ -499,13 +499,14 @@
 	/*
 	 * IORESOURCE_IO
 	 */
+	sys->io_offset = 0;
 	res[0].name = "PCI I/O Space";
 	res[0].flags = IORESOURCE_IO;
 	res[0].start = ORION5X_PCI_IO_BUS_BASE;
 	res[0].end = res[0].start + ORION5X_PCI_IO_SIZE - 1;
 	if (request_resource(&ioport_resource, &res[0]))
 		panic("Request PCI IO resource failed\n");
-	pci_add_resource(&sys->resources, &res[0]);
+	pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
 
 	/*
 	 * IORESOURCE_MEM
@@ -516,9 +517,7 @@
 	res[1].end = res[1].start + ORION5X_PCI_MEM_SIZE - 1;
 	if (request_resource(&iomem_resource, &res[1]))
 		panic("Request PCI Memory resource failed\n");
-	pci_add_resource(&sys->resources, &res[1]);
-
-	sys->io_offset = 0;
+	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
 
 	return 1;
 }
diff --git a/arch/arm/mach-orion5x/tsx09-common.c b/arch/arm/mach-orion5x/tsx09-common.c
index c9abb8f..7189827 100644
--- a/arch/arm/mach-orion5x/tsx09-common.c
+++ b/arch/arm/mach-orion5x/tsx09-common.c
@@ -15,6 +15,7 @@
 #include <linux/mv643xx_eth.h>
 #include <linux/timex.h>
 #include <linux/serial_reg.h>
+#include <mach/orion5x.h>
 #include "tsx09-common.h"
 #include "common.h"
 
diff --git a/arch/arm/mach-picoxcell/include/mach/entry-macro.S b/arch/arm/mach-picoxcell/include/mach/entry-macro.S
deleted file mode 100644
index 9b505ac..0000000
--- a/arch/arm/mach-picoxcell/include/mach/entry-macro.S
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * entry-macro.S
- *
- * Copyright (c) 2011 Picochip Ltd., Jamie Iles
- *
- * Low-level IRQ helper macros for picoXcell platforms
- *
- * 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.
- */
-	.macro  disable_fiq
-	.endm
-
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
diff --git a/arch/arm/mach-picoxcell/include/mach/io.h b/arch/arm/mach-picoxcell/include/mach/io.h
deleted file mode 100644
index 7573ec7..0000000
--- a/arch/arm/mach-picoxcell/include/mach/io.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2011 Picochip Ltd., Jamie Iles
- *
- * 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 __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/* No ioports, but needed for driver compatibility. */
-#define __io(a)			__typesafe_io(a)
-/* No PCI possible on picoxcell. */
-#define __mem_pci(a)		(a)
-
-#endif /* __ASM_ARM_ARCH_IO_H */
diff --git a/arch/arm/mach-picoxcell/include/mach/irqs.h b/arch/arm/mach-picoxcell/include/mach/irqs.h
deleted file mode 100644
index 59eac1e..0000000
--- a/arch/arm/mach-picoxcell/include/mach/irqs.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2011 Picochip Ltd., Jamie Iles
- *
- * 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 __MACH_IRQS_H
-#define __MACH_IRQS_H
-
-/* We dynamically allocate our irq_desc's. */
-#define NR_IRQS				0
-
-#endif /* __MACH_IRQS_H */
diff --git a/arch/arm/mach-picoxcell/include/mach/system.h b/arch/arm/mach-picoxcell/include/mach/system.h
deleted file mode 100644
index 1a5d8cb..0000000
--- a/arch/arm/mach-picoxcell/include/mach/system.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2011 Picochip Ltd., Jamie Iles
- *
- * 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	/*
-	 * This should do all the clock switching and wait for interrupt
-	 * tricks.
-	 */
-	cpu_do_idle();
-}
-
-#endif /* __ASM_ARCH_SYSTEM_H */
diff --git a/arch/arm/mach-pnx4008/core.c b/arch/arm/mach-pnx4008/core.c
index 4cfb40b..be4c928 100644
--- a/arch/arm/mach-pnx4008/core.c
+++ b/arch/arm/mach-pnx4008/core.c
@@ -32,7 +32,7 @@
 #include <asm/mach-types.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <asm/system.h>
+#include <asm/system_misc.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-pnx4008/dma.c b/arch/arm/mach-pnx4008/dma.c
index 7fa4bf2..a4739e9 100644
--- a/arch/arm/mach-pnx4008/dma.c
+++ b/arch/arm/mach-pnx4008/dma.c
@@ -24,7 +24,6 @@
 #include <linux/io.h>
 #include <linux/gfp.h>
 
-#include <asm/system.h>
 #include <mach/hardware.h>
 #include <mach/dma.h>
 #include <asm/dma-mapping.h>
diff --git a/arch/arm/mach-pnx4008/include/mach/entry-macro.S b/arch/arm/mach-pnx4008/include/mach/entry-macro.S
index db7eeeb..77a5558 100644
--- a/arch/arm/mach-pnx4008/include/mach/entry-macro.S
+++ b/arch/arm/mach-pnx4008/include/mach/entry-macro.S
@@ -25,15 +25,9 @@
 #define SIC1_BASE_INT   32
 #define SIC2_BASE_INT   64
 
-		.macro	disable_fiq
-		.endm
-
 		.macro  get_irqnr_preamble, base, tmp
 		.endm
 
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
-
 		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 /* decode the MIC interrupt numbers */
 		ldr	\base, =IO_ADDRESS(PNX4008_INTCTRLMIC_BASE)
diff --git a/arch/arm/mach-pnx4008/include/mach/io.h b/arch/arm/mach-pnx4008/include/mach/io.h
deleted file mode 100644
index cbf0904..0000000
--- a/arch/arm/mach-pnx4008/include/mach/io.h
+++ /dev/null
@@ -1,21 +0,0 @@
-
-/*
- *  arch/arm/mach-pnx4008/include/mach/io.h
- *
- * Author: Dmitry Chigirev <chigirev@ru.mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#endif
diff --git a/arch/arm/mach-pnx4008/include/mach/system.h b/arch/arm/mach-pnx4008/include/mach/system.h
deleted file mode 100644
index 60cfe71..0000000
--- a/arch/arm/mach-pnx4008/include/mach/system.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/include/mach/system.h
- *
- * Copyright (C) 2003 Philips Semiconductors
- * Copyright (C) 2005 MontaVista Software, Inc.
- *
- * 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
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-pnx4008/irq.c b/arch/arm/mach-pnx4008/irq.c
index 7608c7a..41e4201 100644
--- a/arch/arm/mach-pnx4008/irq.c
+++ b/arch/arm/mach-pnx4008/irq.c
@@ -28,7 +28,6 @@
 #include <asm/setup.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
index 0c8aad4..0cfe8af 100644
--- a/arch/arm/mach-pnx4008/time.c
+++ b/arch/arm/mach-pnx4008/time.c
@@ -24,7 +24,6 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 
-#include <asm/system.h>
 #include <mach/hardware.h>
 #include <asm/leds.h>
 #include <asm/mach/time.h>
diff --git a/arch/arm/mach-prima2/include/mach/entry-macro.S b/arch/arm/mach-prima2/include/mach/entry-macro.S
index 1c8a50f..86434e7 100644
--- a/arch/arm/mach-prima2/include/mach/entry-macro.S
+++ b/arch/arm/mach-prima2/include/mach/entry-macro.S
@@ -20,10 +20,3 @@
 	cmp \irqnr, #0x40			@ the irq num can't be larger than 0x3f
 	movges \irqnr, #0
 	.endm
-
-	.macro  disable_fiq
-	.endm
-
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
-
diff --git a/arch/arm/mach-prima2/include/mach/io.h b/arch/arm/mach-prima2/include/mach/io.h
deleted file mode 100644
index 6c31e9e..0000000
--- a/arch/arm/mach-prima2/include/mach/io.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * arch/arm/mach-prima2/include/mach/io.h
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- *
- * Licensed under GPLv2 or later.
- */
-
-#ifndef __MACH_PRIMA2_IO_H
-#define __MACH_PRIMA2_IO_H
-
-#define IO_SPACE_LIMIT ((resource_size_t)0)
-
-#define __mem_pci(a)            (a)
-
-#endif
diff --git a/arch/arm/mach-prima2/include/mach/system.h b/arch/arm/mach-prima2/include/mach/system.h
deleted file mode 100644
index 2c7d2a9..0000000
--- a/arch/arm/mach-prima2/include/mach/system.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/mach-prima2/include/mach/system.h
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- *
- * Licensed under GPLv2 or later.
- */
-
-#ifndef __MACH_SYSTEM_H__
-#define __MACH_SYSTEM_H__
-
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer.c
index b7a6091..0d024b1 100644
--- a/arch/arm/mach-prima2/timer.c
+++ b/arch/arm/mach-prima2/timer.c
@@ -18,6 +18,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <mach/map.h>
+#include <asm/sched_clock.h>
 #include <asm/mach/time.h>
 
 #define SIRFSOC_TIMER_COUNTER_LO	0x0000
@@ -165,21 +166,9 @@
 };
 
 /* Overwrite weak default sched_clock with more precise one */
-unsigned long long notrace sched_clock(void)
+static u32 notrace sirfsoc_read_sched_clock(void)
 {
-	static int is_mapped;
-
-	/*
-	 * sched_clock is called earlier than .init of sys_timer
-	 * if we map timer memory in .init of sys_timer, system
-	 * will panic due to illegal memory access
-	 */
-	if (!is_mapped) {
-		sirfsoc_of_timer_map();
-		is_mapped = 1;
-	}
-
-	return sirfsoc_timer_read(NULL) * (NSEC_PER_SEC / CLOCK_TICK_RATE);
+	return (u32)(sirfsoc_timer_read(NULL) & 0xffffffff);
 }
 
 static void __init sirfsoc_clockevent_init(void)
@@ -210,6 +199,8 @@
 	BUG_ON(rate < CLOCK_TICK_RATE);
 	BUG_ON(rate % CLOCK_TICK_RATE);
 
+	sirfsoc_of_timer_map();
+
 	writel_relaxed(rate / CLOCK_TICK_RATE / 2 - 1, sirfsoc_timer_base + SIRFSOC_TIMER_DIV);
 	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
 	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
@@ -217,6 +208,8 @@
 
 	BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE));
 
+	setup_sched_clock(sirfsoc_read_sched_clock, 32, CLOCK_TICK_RATE);
+
 	BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq));
 
 	sirfsoc_clockevent_init();
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 61d3c72..fe2d1f8 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -108,10 +108,12 @@
 
 config MACH_ARMCORE
 	bool "CompuLab CM-X255/CM-X270 modules"
+	select ARCH_HAS_DMA_SET_COHERENT_MASK if PCI
 	select PXA27x
 	select IWMMXT
 	select PXA25x
 	select MIGHT_HAVE_PCI
+	select NEED_MACH_IO_H if PCI
 
 config MACH_EM_X270
 	bool "CompuLab EM-x270 platform"
diff --git a/arch/arm/mach-pxa/capc7117.c b/arch/arm/mach-pxa/capc7117.c
index c91727d..9a8760b 100644
--- a/arch/arm/mach-pxa/capc7117.c
+++ b/arch/arm/mach-pxa/capc7117.c
@@ -150,6 +150,7 @@
 	      "Embedian CAPC-7117 evaluation kit based on the MXM-8x10 CoM")
 	.atag_offset = 0x100,
 	.map_io = pxa3xx_map_io,
+	.nr_irqs = PXA_NR_IRQS,
 	.init_irq = pxa3xx_init_irq,
 	.handle_irq = pxa3xx_handle_irq,
 	.timer = &pxa_timer,
diff --git a/arch/arm/mach-pxa/clock-pxa2xx.c b/arch/arm/mach-pxa/clock-pxa2xx.c
index 1d5859d..9ee2ad6 100644
--- a/arch/arm/mach-pxa/clock-pxa2xx.c
+++ b/arch/arm/mach-pxa/clock-pxa2xx.c
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/syscore_ops.h>
 
 #include <mach/pxa2xx-regs.h>
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index 4b981b8..3132740 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -44,6 +44,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/setup.h>
+#include <asm/system_info.h>
 
 #include <mach/pxa300.h>
 #include <mach/pxa27x-udc.h>
@@ -713,7 +714,6 @@
 
 static struct regulator_consumer_supply buck2_consumers[] = {
 	{
-		.dev = NULL,
 		.supply = "vcc_core",
 	},
 };
@@ -853,6 +853,7 @@
 MACHINE_START(CM_X300, "CM-X300 module")
 	.atag_offset	= 0x100,
 	.map_io		= pxa3xx_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa3xx_init_irq,
 	.handle_irq	= pxa3xx_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/colibri-pxa270.c b/arch/arm/mach-pxa/colibri-pxa270.c
index 29d5d54..b2f227d 100644
--- a/arch/arm/mach-pxa/colibri-pxa270.c
+++ b/arch/arm/mach-pxa/colibri-pxa270.c
@@ -310,6 +310,7 @@
 	.atag_offset	= 0x100,
 	.init_machine	= colibri_pxa270_init,
 	.map_io		= pxa27x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.timer		= &pxa_timer,
@@ -320,6 +321,7 @@
 	.atag_offset	= 0x100,
 	.init_machine	= colibri_pxa270_income_init,
 	.map_io		= pxa27x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/colibri-pxa300.c b/arch/arm/mach-pxa/colibri-pxa300.c
index 0846d21..bb6def8 100644
--- a/arch/arm/mach-pxa/colibri-pxa300.c
+++ b/arch/arm/mach-pxa/colibri-pxa300.c
@@ -186,6 +186,7 @@
 	.atag_offset	= 0x100,
 	.init_machine	= colibri_pxa300_init,
 	.map_io		= pxa3xx_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa3xx_init_irq,
 	.handle_irq	= pxa3xx_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/colibri-pxa320.c b/arch/arm/mach-pxa/colibri-pxa320.c
index 6ad3359..d88e7b3 100644
--- a/arch/arm/mach-pxa/colibri-pxa320.c
+++ b/arch/arm/mach-pxa/colibri-pxa320.c
@@ -256,6 +256,7 @@
 	.atag_offset	= 0x100,
 	.init_machine	= colibri_pxa320_init,
 	.map_io		= pxa3xx_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa3xx_init_irq,
 	.handle_irq	= pxa3xx_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c
index 2b8ca0d..68cc75f 100644
--- a/arch/arm/mach-pxa/colibri-pxa3xx.c
+++ b/arch/arm/mach-pxa/colibri-pxa3xx.c
@@ -18,6 +18,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <asm/sizes.h>
+#include <asm/system_info.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 #include <mach/pxa3xx-regs.h>
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index 11f1e73..c1fe32d 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -40,7 +40,6 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -730,6 +729,7 @@
 MACHINE_START(CORGI, "SHARP Corgi")
 	.fixup		= fixup_corgi,
 	.map_io		= pxa25x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa25x_init_irq,
 	.handle_irq	= pxa25x_handle_irq,
 	.init_machine	= corgi_init,
@@ -742,6 +742,7 @@
 MACHINE_START(SHEPHERD, "SHARP Shepherd")
 	.fixup		= fixup_corgi,
 	.map_io		= pxa25x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa25x_init_irq,
 	.handle_irq	= pxa25x_handle_irq,
 	.init_machine	= corgi_init,
@@ -754,6 +755,7 @@
 MACHINE_START(HUSKY, "SHARP Husky")
 	.fixup		= fixup_corgi,
 	.map_io		= pxa25x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa25x_init_irq,
 	.handle_irq	= pxa25x_handle_irq,
 	.init_machine	= corgi_init,
diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c
index 39e265c..048c429 100644
--- a/arch/arm/mach-pxa/corgi_pm.c
+++ b/arch/arm/mach-pxa/corgi_pm.c
@@ -19,6 +19,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/apm-emulation.h>
+#include <linux/io.h>
 
 #include <asm/irq.h>
 #include <asm/mach-types.h>
diff --git a/arch/arm/mach-pxa/cpufreq-pxa3xx.c b/arch/arm/mach-pxa/cpufreq-pxa3xx.c
index 88fbec0..b85b4ab 100644
--- a/arch/arm/mach-pxa/cpufreq-pxa3xx.c
+++ b/arch/arm/mach-pxa/cpufreq-pxa3xx.c
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/cpufreq.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 
 #include <mach/pxa3xx-regs.h>
 
diff --git a/arch/arm/mach-pxa/csb726.c b/arch/arm/mach-pxa/csb726.c
index fb5a51d..67f0de3 100644
--- a/arch/arm/mach-pxa/csb726.c
+++ b/arch/arm/mach-pxa/csb726.c
@@ -274,6 +274,7 @@
 MACHINE_START(CSB726, "Cogent CSB726")
 	.atag_offset	= 0x100,
 	.map_io         = pxa27x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq       = pxa27x_init_irq,
 	.handle_irq       = pxa27x_handle_irq,
 	.init_machine   = csb726_init,
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index 5bc1312..166eee5 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -12,6 +12,7 @@
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/irda.h>
+#include <mach/irqs.h>
 #include <mach/ohci.h>
 #include <plat/pxa27x_keypad.h>
 #include <mach/camera.h>
@@ -406,20 +407,17 @@
 	[1] = {
 		.start  = IRQ_RTC1Hz,
 		.end    = IRQ_RTC1Hz,
+		.name	= "rtc 1Hz",
 		.flags  = IORESOURCE_IRQ,
 	},
 	[2] = {
 		.start  = IRQ_RTCAlrm,
 		.end    = IRQ_RTCAlrm,
+		.name	= "rtc alarm",
 		.flags  = IORESOURCE_IRQ,
 	},
 };
 
-struct platform_device sa1100_device_rtc = {
-	.name		= "sa1100-rtc",
-	.id		= -1,
-};
-
 struct platform_device pxa_device_rtc = {
 	.name		= "pxa-rtc",
 	.id		= -1,
@@ -427,6 +425,27 @@
 	.resource       = pxa_rtc_resources,
 };
 
+static struct resource sa1100_rtc_resources[] = {
+	{
+		.start  = IRQ_RTC1Hz,
+		.end    = IRQ_RTC1Hz,
+		.name	= "rtc 1Hz",
+		.flags  = IORESOURCE_IRQ,
+	}, {
+		.start  = IRQ_RTCAlrm,
+		.end    = IRQ_RTCAlrm,
+		.name	= "rtc alarm",
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device sa1100_device_rtc = {
+	.name		= "sa1100-rtc",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(sa1100_rtc_resources),
+	.resource	= sa1100_rtc_resources,
+};
+
 static struct resource pxa_ac97_resources[] = {
 	[0] = {
 		.start  = 0x40500000,
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index d80c0ba..16ec557 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -1083,19 +1083,19 @@
 }
 
 /* DA9030 related initializations */
-#define REGULATOR_CONSUMER(_name, _dev, _supply)			       \
+#define REGULATOR_CONSUMER(_name, _dev_name, _supply)		        \
 	static struct regulator_consumer_supply _name##_consumers[] = {	\
 		{							\
-			.dev = _dev,					\
+			.dev_name = _dev_name,				\
 			.supply = _supply,				\
 		},							\
 	}
 
-REGULATOR_CONSUMER(ldo3, &em_x270_gps_userspace_consumer.dev, "vcc gps");
+REGULATOR_CONSUMER(ldo3, "reg-userspace-consumer.0", "vcc gps");
 REGULATOR_CONSUMER(ldo5, NULL, "vcc cam");
-REGULATOR_CONSUMER(ldo10, &pxa_device_mci.dev, "vcc sdio");
+REGULATOR_CONSUMER(ldo10, "pxa2xx-mci", "vcc sdio");
 REGULATOR_CONSUMER(ldo12, NULL, "vcc usb");
-REGULATOR_CONSUMER(ldo19, &em_x270_gprs_userspace_consumer.dev, "vcc gprs");
+REGULATOR_CONSUMER(ldo19, "reg-userspace-consumer.1", "vcc gprs");
 REGULATOR_CONSUMER(buck2, NULL, "vcc_core");
 
 #define REGULATOR_INIT(_ldo, _min_uV, _max_uV, _ops_mask)		\
@@ -1301,6 +1301,7 @@
 MACHINE_START(EM_X270, "Compulab EM-X270")
 	.atag_offset	= 0x100,
 	.map_io		= pxa27x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.timer		= &pxa_timer,
@@ -1311,6 +1312,7 @@
 MACHINE_START(EXEDA, "Compulab eXeda")
 	.atag_offset	= 0x100,
 	.map_io		= pxa27x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index 5432ecb..4225417 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -22,7 +22,6 @@
 #include <linux/init.h>
 
 #include <mach/hardware.h>
-#include <asm/system.h>
 #include <asm/mach/map.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-pxa/gumstix.c b/arch/arm/mach-pxa/gumstix.c
index ac3b1ce..e529a35 100644
--- a/arch/arm/mach-pxa/gumstix.c
+++ b/arch/arm/mach-pxa/gumstix.c
@@ -235,6 +235,7 @@
 MACHINE_START(GUMSTIX, "Gumstix")
 	.atag_offset	= 0x100, /* match u-boot bi_boot_params */
 	.map_io		= pxa25x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa25x_init_irq,
 	.handle_irq	= pxa25x_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/h5000.c b/arch/arm/mach-pxa/h5000.c
index fde6b4c..e7dec58 100644
--- a/arch/arm/mach-pxa/h5000.c
+++ b/arch/arm/mach-pxa/h5000.c
@@ -205,6 +205,7 @@
 MACHINE_START(H5400, "HP iPAQ H5000")
 	.atag_offset = 0x100,
 	.map_io = pxa25x_map_io,
+	.nr_irqs = PXA_NR_IRQS,
 	.init_irq = pxa25x_init_irq,
 	.handle_irq = pxa25x_handle_irq,
 	.timer = &pxa_timer,
diff --git a/arch/arm/mach-pxa/himalaya.c b/arch/arm/mach-pxa/himalaya.c
index 26d069a..2962de8 100644
--- a/arch/arm/mach-pxa/himalaya.c
+++ b/arch/arm/mach-pxa/himalaya.c
@@ -160,6 +160,7 @@
 MACHINE_START(HIMALAYA, "HTC Himalaya")
 	.atag_offset = 0x100,
 	.map_io = pxa25x_map_io,
+	.nr_irqs = PXA_NR_IRQS,
 	.init_irq = pxa25x_init_irq,
 	.handle_irq = pxa25x_handle_irq,
 	.init_machine = himalaya_init,
diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c
index 208eef1..b83b95a 100644
--- a/arch/arm/mach-pxa/hx4700.c
+++ b/arch/arm/mach-pxa/hx4700.c
@@ -28,7 +28,8 @@
 #include <linux/mtd/physmap.h>
 #include <linux/pda_power.h>
 #include <linux/pwm_backlight.h>
-#include <linux/regulator/bq24022.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/gpio-regulator.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/max1586.h>
 #include <linux/spi/ads7846.h>
@@ -97,9 +98,9 @@
 
 	/* BTUART */
 	GPIO42_BTUART_RXD,
-	GPIO43_BTUART_TXD,
+	GPIO43_BTUART_TXD_LPM_LOW,
 	GPIO44_BTUART_CTS,
-	GPIO45_BTUART_RTS,
+	GPIO45_BTUART_RTS_LPM_LOW,
 
 	/* PWM 1 (Backlight) */
 	GPIO17_PWM1_OUT,
@@ -245,6 +246,21 @@
 	ASIC3_GPIOD15_nPIOW,
 };
 
+static struct asic3_led asic3_leds[ASIC3_NUM_LEDS] = {
+	[0] = {
+		.name = "hx4700:amber",
+		.default_trigger = "ds2760-battery.0-charging-blink-full-solid",
+	},
+	[1] = {
+		.name = "hx4700:green",
+		.default_trigger = "unused",
+	},
+	[2] = {
+		.name = "hx4700:blue",
+		.default_trigger = "hx4700-radio",
+	},
+};
+
 static struct resource asic3_resources[] = {
 	/* GPIO part */
 	[0] = {
@@ -275,6 +291,7 @@
 	.gpio_config_num = ARRAY_SIZE(asic3_gpio_config),
 	.irq_base        = IRQ_BOARD_START,
 	.gpio_base       = HX4700_ASIC3_GPIO_BASE,
+	.leds            = asic3_leds,
 };
 
 static struct platform_device asic3 = {
@@ -664,11 +681,9 @@
 
 static struct regulator_consumer_supply bq24022_consumers[] = {
 	{
-		.dev = &gpio_vbus.dev,
 		.supply = "vbus_draw",
 	},
 	{
-		.dev = &power_supply.dev,
 		.supply = "ac_draw",
 	},
 };
@@ -682,14 +697,34 @@
 	.consumer_supplies      = bq24022_consumers,
 };
 
-static struct bq24022_mach_info bq24022_info = {
-	.gpio_nce   = GPIO72_HX4700_BQ24022_nCHARGE_EN,
-	.gpio_iset2 = GPIO96_HX4700_BQ24022_ISET2,
-	.init_data  = &bq24022_init_data,
+static struct gpio bq24022_gpios[] = {
+	{ GPIO96_HX4700_BQ24022_ISET2, GPIOF_OUT_INIT_LOW, "bq24022_iset2" },
+};
+
+static struct gpio_regulator_state bq24022_states[] = {
+	{ .value = 100000, .gpios = (0 << 0) },
+	{ .value = 500000, .gpios = (1 << 0) },
+};
+
+static struct gpio_regulator_config bq24022_info = {
+	.supply_name = "bq24022",
+
+	.enable_gpio = GPIO72_HX4700_BQ24022_nCHARGE_EN,
+	.enable_high = 0,
+	.enabled_at_boot = 0,
+
+	.gpios = bq24022_gpios,
+	.nr_gpios = ARRAY_SIZE(bq24022_gpios),
+
+	.states = bq24022_states,
+	.nr_states = ARRAY_SIZE(bq24022_states),
+
+	.type = REGULATOR_CURRENT,
+	.init_data = &bq24022_init_data,
 };
 
 static struct platform_device bq24022 = {
-	.name = "bq24022",
+	.name = "gpio-regulator",
 	.id   = -1,
 	.dev  = {
 		.platform_data = &bq24022_info,
@@ -705,10 +740,9 @@
 	gpio_set_value(GPIO91_HX4700_FLASH_VPEN, vpp);
 }
 
-static struct resource strataflash_resource = {
-	.start = PXA_CS0_PHYS,
-	.end   = PXA_CS0_PHYS + SZ_128M - 1,
-	.flags = IORESOURCE_MEM,
+static struct resource strataflash_resource[] = {
+	[0] = DEFINE_RES_MEM(PXA_CS0_PHYS, SZ_64M),
+	[1] = DEFINE_RES_MEM(PXA_CS0_PHYS + SZ_64M, SZ_64M),
 };
 
 static struct physmap_flash_data strataflash_data = {
@@ -719,8 +753,8 @@
 static struct platform_device strataflash = {
 	.name          = "physmap-flash",
 	.id            = -1,
-	.resource      = &strataflash_resource,
-	.num_resources = 1,
+	.resource      = strataflash_resource,
+	.num_resources = ARRAY_SIZE(strataflash_resource),
 	.dev = {
 		.platform_data = &strataflash_data,
 	},
@@ -788,17 +822,6 @@
 
 
 /*
- * PCMCIA
- */
-
-static struct platform_device pcmcia = {
-	.name = "hx4700-pcmcia",
-	.dev  = {
-		.parent = &asic3.dev,
-	},
-};
-
-/*
  * Platform devices
  */
 
@@ -814,7 +837,6 @@
 	&power_supply,
 	&strataflash,
 	&audio,
-	&pcmcia,
 };
 
 static struct gpio global_gpios[] = {
@@ -830,7 +852,6 @@
 	{ GPIO32_HX4700_RS232_ON,         GPIOF_OUT_INIT_HIGH, "RS232_ON" },
 	{ GPIO71_HX4700_ASIC3_nRESET,     GPIOF_OUT_INIT_HIGH, "ASIC3_nRESET" },
 	{ GPIO82_HX4700_EUART_RESET,      GPIOF_OUT_INIT_HIGH, "EUART_RESET" },
-	{ GPIO105_HX4700_nIR_ON,          GPIOF_OUT_INIT_HIGH, "nIR_EN" },
 };
 
 static void __init hx4700_init(void)
diff --git a/arch/arm/mach-pxa/icontrol.c b/arch/arm/mach-pxa/icontrol.c
index 6740019..1d02eab 100644
--- a/arch/arm/mach-pxa/icontrol.c
+++ b/arch/arm/mach-pxa/icontrol.c
@@ -193,6 +193,7 @@
 MACHINE_START(ICONTROL, "iControl/SafeTcam boards using Embedian MXM-8x10 CoM")
 	.atag_offset	= 0x100,
 	.map_io		= pxa3xx_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa3xx_init_irq,
 	.handle_irq	= pxa3xx_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
index 8af1840..6ff466b 100644
--- a/arch/arm/mach-pxa/idp.c
+++ b/arch/arm/mach-pxa/idp.c
@@ -195,6 +195,7 @@
 MACHINE_START(PXA_IDP, "Vibren PXA255 IDP")
 	/* Maintainer: Vibren Technologies */
 	.map_io		= idp_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa25x_init_irq,
 	.handle_irq	= pxa25x_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/include/mach/balloon3.h b/arch/arm/mach-pxa/include/mach/balloon3.h
index f02fa1e..954641e 100644
--- a/arch/arm/mach-pxa/include/mach/balloon3.h
+++ b/arch/arm/mach-pxa/include/mach/balloon3.h
@@ -174,7 +174,6 @@
 
 #define BALLOON3_AUX_NIRQ	PXA_GPIO_TO_IRQ(BALLOON3_GPIO_AUX_NIRQ)
 #define BALLOON3_CODEC_IRQ	PXA_GPIO_TO_IRQ(BALLOON3_GPIO_CODEC_IRQ)
-#define BALLOON3_S0_CD_IRQ	PXA_GPIO_TO_IRQ(BALLOON3_GPIO_S0_CD)
 
 #define BALLOON3_NR_IRQS	(IRQ_BOARD_START + 16)
 
diff --git a/arch/arm/mach-pxa/include/mach/entry-macro.S b/arch/arm/mach-pxa/include/mach/entry-macro.S
deleted file mode 100644
index 260c0c1..0000000
--- a/arch/arm/mach-pxa/include/mach/entry-macro.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * arch/arm/mach-pxa/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for PXA-based platforms
- *
- * 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.
- */
-
-		.macro	disable_fiq
-		.endm
-
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
diff --git a/arch/arm/mach-pxa/include/mach/hardware.h b/arch/arm/mach-pxa/include/mach/hardware.h
index 8184669..56d92e5 100644
--- a/arch/arm/mach-pxa/include/mach/hardware.h
+++ b/arch/arm/mach-pxa/include/mach/hardware.h
@@ -40,7 +40,6 @@
 #define io_p2v(x) IOMEM(0xf2000000 + ((x) & 0x01ffffff) + (((x) & 0x1c000000) >> 1))
 
 #ifndef __ASSEMBLY__
-# define IOMEM(x) ((void __iomem *)(x))
 # define __REG(x)	(*((volatile u32 __iomem *)io_p2v(x)))
 
 /* With indexed regs we don't want to feed the index through io_p2v()
@@ -52,7 +51,6 @@
 
 #else
 
-# define IOMEM(x)	x 
 # define __REG(x)	io_p2v(x)
 # define __PREG(x)	io_v2p(x)
 
@@ -337,8 +335,4 @@
 extern unsigned long get_clock_tick_rate(void);
 #endif
 
-#if defined(CONFIG_MACH_ARMCORE) && defined(CONFIG_PCI)
-#define ARCH_HAS_DMA_SET_COHERENT_MASK
-#endif
-
 #endif  /* _ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/mach-pxa/include/mach/io.h b/arch/arm/mach-pxa/include/mach/io.h
index fdca3be..cd78b7f 100644
--- a/arch/arm/mach-pxa/include/mach/io.h
+++ b/arch/arm/mach-pxa/include/mach/io.h
@@ -6,8 +6,6 @@
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-#include <mach/hardware.h>
-
 #define IO_SPACE_LIMIT 0xffffffff
 
 /*
@@ -15,6 +13,5 @@
  * drivers out there that might just work if we fake them...
  */
 #define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
 
 #endif
diff --git a/arch/arm/mach-pxa/include/mach/irqs.h b/arch/arm/mach-pxa/include/mach/irqs.h
index 32975ad..8765782 100644
--- a/arch/arm/mach-pxa/include/mach/irqs.h
+++ b/arch/arm/mach-pxa/include/mach/irqs.h
@@ -100,7 +100,7 @@
  */
 #define IRQ_BOARD_START		(PXA_GPIO_IRQ_BASE + PXA_NR_BUILTIN_GPIO)
 
-#define NR_IRQS			(IRQ_BOARD_START)
+#define PXA_NR_IRQS		(IRQ_BOARD_START)
 
 #ifndef __ASSEMBLY__
 struct irq_data;
diff --git a/arch/arm/mach-pxa/include/mach/mainstone.h b/arch/arm/mach-pxa/include/mach/mainstone.h
index 4c2d11c..1bfc4e8 100644
--- a/arch/arm/mach-pxa/include/mach/mainstone.h
+++ b/arch/arm/mach-pxa/include/mach/mainstone.h
@@ -13,6 +13,8 @@
 #ifndef ASM_ARCH_MAINSTONE_H
 #define ASM_ARCH_MAINSTONE_H
 
+#include <mach/irqs.h>
+
 #define MST_ETH_PHYS		PXA_CS4_PHYS
 
 #define MST_FPGA_PHYS		PXA_CS2_PHYS
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h b/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
index ec0f0b0..a658672 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
+++ b/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
@@ -158,7 +158,9 @@
 #define GPIO44_BTUART_CTS	MFP_CFG_IN(GPIO44, AF1)
 #define GPIO42_BTUART_RXD	MFP_CFG_IN(GPIO42, AF1)
 #define GPIO45_BTUART_RTS	MFP_CFG_OUT(GPIO45, AF2, DRIVE_HIGH)
+#define GPIO45_BTUART_RTS_LPM_LOW	MFP_CFG_OUT(GPIO45, AF2, DRIVE_LOW)
 #define GPIO43_BTUART_TXD	MFP_CFG_OUT(GPIO43, AF2, DRIVE_HIGH)
+#define GPIO43_BTUART_TXD_LPM_LOW	MFP_CFG_OUT(GPIO43, AF2, DRIVE_LOW)
 
 /* STUART */
 #define GPIO46_STUART_RXD	MFP_CFG_IN(GPIO46, AF2)
diff --git a/arch/arm/mach-pxa/include/mach/system.h b/arch/arm/mach-pxa/include/mach/system.h
deleted file mode 100644
index c5afacd..0000000
--- a/arch/arm/mach-pxa/include/mach/system.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * arch/arm/mach-pxa/include/mach/system.h
- *
- * Author:	Nicolas Pitre
- * Created:	Jun 15, 2001
- * Copyright:	MontaVista Software 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.
- */
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
diff --git a/arch/arm/mach-pxa/leds-idp.c b/arch/arm/mach-pxa/leds-idp.c
index 8b9c171..06b0600 100644
--- a/arch/arm/mach-pxa/leds-idp.c
+++ b/arch/arm/mach-pxa/leds-idp.c
@@ -16,7 +16,6 @@
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
-#include <asm/system.h>
 
 #include <mach/pxa25x.h>
 #include <mach/idp.h>
diff --git a/arch/arm/mach-pxa/leds-lubbock.c b/arch/arm/mach-pxa/leds-lubbock.c
index e26d5ef..0bd85c8 100644
--- a/arch/arm/mach-pxa/leds-lubbock.c
+++ b/arch/arm/mach-pxa/leds-lubbock.c
@@ -15,7 +15,6 @@
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
-#include <asm/system.h>
 #include <mach/pxa25x.h>
 #include <mach/lubbock.h>
 
diff --git a/arch/arm/mach-pxa/leds-mainstone.c b/arch/arm/mach-pxa/leds-mainstone.c
index db4af5e..4058ab3 100644
--- a/arch/arm/mach-pxa/leds-mainstone.c
+++ b/arch/arm/mach-pxa/leds-mainstone.c
@@ -14,7 +14,6 @@
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
-#include <asm/system.h>
 
 #include <mach/pxa27x.h>
 #include <mach/mainstone.h>
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 6ebd276..6bb3f47 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -223,6 +223,7 @@
 
 static struct sa1111_platform_data sa1111_info = {
 	.irq_base	= LUBBOCK_SA1111_IRQ_BASE,
+	.disable_devs	= SA1111_DEVID_SAC,
 };
 
 static struct platform_device sa1111_device = {
diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
index 3d6baf9..8de0651 100644
--- a/arch/arm/mach-pxa/magician.c
+++ b/arch/arm/mach-pxa/magician.c
@@ -25,7 +25,8 @@
 #include <linux/mtd/physmap.h>
 #include <linux/pda_power.h>
 #include <linux/pwm_backlight.h>
-#include <linux/regulator/bq24022.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/gpio-regulator.h>
 #include <linux/regulator/machine.h>
 #include <linux/usb/gpio_vbus.h>
 #include <linux/i2c/pxa-i2c.h>
@@ -33,6 +34,7 @@
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/system_info.h>
 
 #include <mach/pxa27x.h>
 #include <mach/magician.h>
@@ -578,11 +580,9 @@
 
 static struct regulator_consumer_supply bq24022_consumers[] = {
 	{
-		.dev = &gpio_vbus.dev,
 		.supply = "vbus_draw",
 	},
 	{
-		.dev = &power_supply.dev,
 		.supply = "ac_draw",
 	},
 };
@@ -596,14 +596,34 @@
 	.consumer_supplies      = bq24022_consumers,
 };
 
-static struct bq24022_mach_info bq24022_info = {
-	.gpio_nce   = GPIO30_MAGICIAN_BQ24022_nCHARGE_EN,
-	.gpio_iset2 = EGPIO_MAGICIAN_BQ24022_ISET2,
-	.init_data  = &bq24022_init_data,
+static struct gpio bq24022_gpios[] = {
+	{ EGPIO_MAGICIAN_BQ24022_ISET2, GPIOF_OUT_INIT_LOW, "bq24022_iset2" },
+};
+
+static struct gpio_regulator_state bq24022_states[] = {
+	{ .value = 100000, .gpios = (0 << 0) },
+	{ .value = 500000, .gpios = (1 << 0) },
+};
+
+static struct gpio_regulator_config bq24022_info = {
+	.supply_name = "bq24022",
+
+	.enable_gpio = GPIO30_MAGICIAN_BQ24022_nCHARGE_EN,
+	.enable_high = 0,
+	.enabled_at_boot = 0,
+
+	.gpios = bq24022_gpios,
+	.nr_gpios = ARRAY_SIZE(bq24022_gpios),
+
+	.states = bq24022_states,
+	.nr_states = ARRAY_SIZE(bq24022_states),
+
+	.type = REGULATOR_CURRENT,
+	.init_data = &bq24022_init_data,
 };
 
 static struct platform_device bq24022 = {
-	.name = "bq24022",
+	.name = "gpio-regulator",
 	.id   = -1,
 	.dev  = {
 		.platform_data = &bq24022_info,
diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c
index 29b62af..b0a8428 100644
--- a/arch/arm/mach-pxa/mfp-pxa2xx.c
+++ b/arch/arm/mach-pxa/mfp-pxa2xx.c
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/syscore_ops.h>
 
 #include <mach/pxa2xx-regs.h>
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index e80a3db..061d570 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -758,6 +758,7 @@
 	.atag_offset	= 0x100,
 	.restart_mode	= 's',
 	.map_io		= &pxa27x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= &pxa27x_init_irq,
 	.handle_irq	= &pxa27x_handle_irq,
 	.init_machine	= mioa701_machine_init,
diff --git a/arch/arm/mach-pxa/mp900.c b/arch/arm/mach-pxa/mp900.c
index 169bf8f..152efbf 100644
--- a/arch/arm/mach-pxa/mp900.c
+++ b/arch/arm/mach-pxa/mp900.c
@@ -95,6 +95,7 @@
 	.atag_offset	= 0x220100,
 	.timer		= &pxa_timer,
 	.map_io		= pxa25x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa25x_init_irq,
 	.handle_irq	= pxa25x_handle_irq,
 	.init_machine	= mp900c_init,
diff --git a/arch/arm/mach-pxa/palmld.c b/arch/arm/mach-pxa/palmld.c
index 1fa80f4f..31e0433 100644
--- a/arch/arm/mach-pxa/palmld.c
+++ b/arch/arm/mach-pxa/palmld.c
@@ -344,6 +344,7 @@
 MACHINE_START(PALMLD, "Palm LifeDrive")
 	.atag_offset	= 0x100,
 	.map_io		= palmld_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/palmt5.c b/arch/arm/mach-pxa/palmt5.c
index 5ba1431..0f6bd4f 100644
--- a/arch/arm/mach-pxa/palmt5.c
+++ b/arch/arm/mach-pxa/palmt5.c
@@ -205,6 +205,7 @@
 	.atag_offset	= 0x100,
 	.map_io		= pxa27x_map_io,
 	.reserve	= palmt5_reserve,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/palmtc.c b/arch/arm/mach-pxa/palmtc.c
index 29b51b4..e2d97ee 100644
--- a/arch/arm/mach-pxa/palmtc.c
+++ b/arch/arm/mach-pxa/palmtc.c
@@ -539,6 +539,7 @@
 MACHINE_START(PALMTC, "Palm Tungsten|C")
 	.atag_offset 	= 0x100,
 	.map_io		= pxa25x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa25x_init_irq,
 	.handle_irq	= pxa25x_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/palmte2.c b/arch/arm/mach-pxa/palmte2.c
index 5ebf49acb..c054827 100644
--- a/arch/arm/mach-pxa/palmte2.c
+++ b/arch/arm/mach-pxa/palmte2.c
@@ -358,6 +358,7 @@
 MACHINE_START(PALMTE2, "Palm Tungsten|E2")
 	.atag_offset	= 0x100,
 	.map_io		= pxa25x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa25x_init_irq,
 	.handle_irq	= pxa25x_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/palmtreo.c b/arch/arm/mach-pxa/palmtreo.c
index ec82491..fbdebee 100644
--- a/arch/arm/mach-pxa/palmtreo.c
+++ b/arch/arm/mach-pxa/palmtreo.c
@@ -448,6 +448,7 @@
 	.atag_offset    = 0x100,
 	.map_io         = pxa27x_map_io,
 	.reserve	= treo_reserve,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq       = pxa27x_init_irq,
 	.handle_irq       = pxa27x_handle_irq,
 	.timer          = &pxa_timer,
@@ -461,6 +462,7 @@
 	.atag_offset    = 0x100,
 	.map_io         = pxa27x_map_io,
 	.reserve	= treo_reserve,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq       = pxa27x_init_irq,
 	.handle_irq       = pxa27x_handle_irq,
 	.timer          = &pxa_timer,
diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c
index 6170d76..9507605 100644
--- a/arch/arm/mach-pxa/palmtx.c
+++ b/arch/arm/mach-pxa/palmtx.c
@@ -366,6 +366,7 @@
 MACHINE_START(PALMTX, "Palm T|X")
 	.atag_offset	= 0x100,
 	.map_io		= palmtx_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c
index b2dff9d..a97b599 100644
--- a/arch/arm/mach-pxa/palmz72.c
+++ b/arch/arm/mach-pxa/palmz72.c
@@ -401,6 +401,7 @@
 MACHINE_START(PALMZ72, "Palm Zire72")
 	.atag_offset	= 0x100,
 	.map_io		= pxa27x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index 744baee..89d98c8 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -34,7 +34,6 @@
 #include <asm/mach-types.h>
 #include <asm/irq.h>
 #include <asm/setup.h>
-#include <asm/system.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-pxa/pxa2xx.c b/arch/arm/mach-pxa/pxa2xx.c
index 8682704..f8ec854 100644
--- a/arch/arm/mach-pxa/pxa2xx.c
+++ b/arch/arm/mach-pxa/pxa2xx.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <mach/pxa2xx-regs.h>
diff --git a/arch/arm/mach-pxa/pxa300.c b/arch/arm/mach-pxa/pxa300.c
index 40bb165..17cbc0c 100644
--- a/arch/arm/mach-pxa/pxa300.c
+++ b/arch/arm/mach-pxa/pxa300.c
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <mach/pxa300.h>
 
diff --git a/arch/arm/mach-pxa/pxa320.c b/arch/arm/mach-pxa/pxa320.c
index 8d614ec..6dc99d4 100644
--- a/arch/arm/mach-pxa/pxa320.c
+++ b/arch/arm/mach-pxa/pxa320.c
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <mach/pxa320.h>
 
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 3918a67..dffb7e8 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -31,6 +31,7 @@
 #include <mach/pm.h>
 #include <mach/dma.h>
 #include <mach/smemc.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -89,6 +90,7 @@
 	INIT_CLKREG(&clk_pxa3xx_mmc2, "pxa2xx-mci.1", NULL),
 	INIT_CLKREG(&clk_pxa3xx_smemc, "pxa2xx-pcmcia", NULL),
 	INIT_CLKREG(&clk_pxa3xx_gpio, "pxa-gpio", NULL),
+	INIT_CLKREG(&clk_dummy, "sa1100-rtc", NULL),
 };
 
 #ifdef CONFIG_PM
diff --git a/arch/arm/mach-pxa/pxa95x.c b/arch/arm/mach-pxa/pxa95x.c
index 5ce434b..47601f8 100644
--- a/arch/arm/mach-pxa/pxa95x.c
+++ b/arch/arm/mach-pxa/pxa95x.c
@@ -231,6 +231,7 @@
 	INIT_CLKREG(&clk_pxa95x_pwm0, "pxa27x-pwm.0", NULL),
 	INIT_CLKREG(&clk_pxa95x_pwm1, "pxa27x-pwm.1", NULL),
 	INIT_CLKREG(&clk_pxa95x_gpio, "pxa-gpio", NULL),
+	INIT_CLKREG(&clk_dummy, "sa1100-rtc", NULL),
 };
 
 void __init pxa95x_init_irq(void)
diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
index 22818c7..5905ed1 100644
--- a/arch/arm/mach-pxa/raumfeld.c
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -43,6 +43,8 @@
 #include <linux/regulator/consumer.h>
 #include <linux/delay.h>
 
+#include <asm/system_info.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
@@ -1090,6 +1092,7 @@
 	.atag_offset	= 0x100,
 	.init_machine	= raumfeld_controller_init,
 	.map_io		= pxa3xx_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa3xx_init_irq,
 	.handle_irq	= pxa3xx_handle_irq,
 	.timer		= &pxa_timer,
@@ -1102,6 +1105,7 @@
 	.atag_offset	= 0x100,
 	.init_machine	= raumfeld_connector_init,
 	.map_io		= pxa3xx_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa3xx_init_irq,
 	.handle_irq	= pxa3xx_handle_irq,
 	.timer		= &pxa_timer,
@@ -1114,6 +1118,7 @@
 	.atag_offset	= 0x100,
 	.init_machine	= raumfeld_speaker_init,
 	.map_io		= pxa3xx_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa3xx_init_irq,
 	.handle_irq	= pxa3xx_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/reset.c b/arch/arm/mach-pxa/reset.c
index c8497b0..b452889 100644
--- a/arch/arm/mach-pxa/reset.c
+++ b/arch/arm/mach-pxa/reset.c
@@ -9,6 +9,7 @@
 #include <linux/gpio.h>
 #include <linux/io.h>
 #include <asm/proc-fns.h>
+#include <asm/system_misc.h>
 
 #include <mach/regs-ost.h>
 #include <mach/reset.h>
diff --git a/arch/arm/mach-pxa/saar.c b/arch/arm/mach-pxa/saar.c
index 0fe354e..86c95a5 100644
--- a/arch/arm/mach-pxa/saar.c
+++ b/arch/arm/mach-pxa/saar.c
@@ -598,6 +598,7 @@
 	/* Maintainer: Eric Miao <eric.miao@marvell.com> */
 	.atag_offset    = 0x100,
 	.map_io         = pxa3xx_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq       = pxa3xx_init_irq,
 	.handle_irq       = pxa3xx_handle_irq,
 	.timer          = &pxa_timer,
diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c
index 30989ba..bdf4cb8 100644
--- a/arch/arm/mach-pxa/sharpsl_pm.c
+++ b/arch/arm/mach-pxa/sharpsl_pm.c
@@ -24,6 +24,7 @@
 #include <linux/leds.h>
 #include <linux/suspend.h>
 #include <linux/gpio.h>
+#include <linux/io.h>
 
 #include <asm/mach-types.h>
 #include <mach/pm.h>
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index abf355d..df2ab0f 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -984,6 +984,7 @@
 	.restart_mode	= 'g',
 	.fixup		= spitz_fixup,
 	.map_io		= pxa27x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.init_machine	= spitz_init,
@@ -997,6 +998,7 @@
 	.restart_mode	= 'g',
 	.fixup		= spitz_fixup,
 	.map_io		= pxa27x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.init_machine	= spitz_init,
@@ -1010,6 +1012,7 @@
 	.restart_mode	= 'g',
 	.fixup		= spitz_fixup,
 	.map_io		= pxa27x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.init_machine	= spitz_init,
diff --git a/arch/arm/mach-pxa/stargate2.c b/arch/arm/mach-pxa/stargate2.c
index b0656e15..4cd645e 100644
--- a/arch/arm/mach-pxa/stargate2.c
+++ b/arch/arm/mach-pxa/stargate2.c
@@ -152,7 +152,7 @@
 
 static struct regulator_consumer_supply stargate2_sensor_3_con[] = {
 	{
-		.dev = &sht15.dev,
+		.dev_name = "sht15",
 		.supply = "vcc",
 	},
 };
@@ -1006,6 +1006,7 @@
 #ifdef CONFIG_MACH_INTELMOTE2
 MACHINE_START(INTELMOTE2, "IMOTE 2")
 	.map_io		= pxa27x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/tavorevb.c b/arch/arm/mach-pxa/tavorevb.c
index 9fb38e8..736bfdc 100644
--- a/arch/arm/mach-pxa/tavorevb.c
+++ b/arch/arm/mach-pxa/tavorevb.c
@@ -491,6 +491,7 @@
 	/* Maintainer: Eric Miao <eric.miao@marvell.com> */
 	.atag_offset    = 0x100,
 	.map_io         = pxa3xx_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq       = pxa3xx_init_irq,
 	.handle_irq       = pxa3xx_handle_irq,
 	.timer          = &pxa_timer,
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index b503049..3d6c9bd 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -22,6 +22,7 @@
 #include <asm/mach/time.h>
 #include <asm/sched_clock.h>
 #include <mach/regs-ost.h>
+#include <mach/irqs.h>
 
 /*
  * This is PXA's sched_clock implementation. This has a resolution
diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c
index 0f30af6..2b6ac00 100644
--- a/arch/arm/mach-pxa/trizeps4.c
+++ b/arch/arm/mach-pxa/trizeps4.c
@@ -558,6 +558,7 @@
 	.atag_offset	= 0x100,
 	.init_machine	= trizeps4_init,
 	.map_io		= trizeps4_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.timer		= &pxa_timer,
@@ -569,6 +570,7 @@
 	.atag_offset	= 0x100,
 	.init_machine	= trizeps4_init,
 	.map_io		= trizeps4_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c
index 023d6ca..130379f 100644
--- a/arch/arm/mach-pxa/viper.c
+++ b/arch/arm/mach-pxa/viper.c
@@ -57,6 +57,7 @@
 #include <asm/mach-types.h>
 #include <asm/irq.h>
 #include <asm/sizes.h>
+#include <asm/system_info.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -994,6 +995,7 @@
 	/* Maintainer: Marc Zyngier <maz@misterjones.org> */
 	.atag_offset	= 0x100,
 	.map_io		= viper_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= viper_init_irq,
 	.handle_irq	= pxa25x_handle_irq,
 	.timer          = &pxa_timer,
diff --git a/arch/arm/mach-pxa/vpac270.c b/arch/arm/mach-pxa/vpac270.c
index 1f5cfa9..c57ab63 100644
--- a/arch/arm/mach-pxa/vpac270.c
+++ b/arch/arm/mach-pxa/vpac270.c
@@ -718,6 +718,7 @@
 MACHINE_START(VPAC270, "Voipac PXA270")
 	.atag_offset	= 0x100,
 	.map_io		= pxa27x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/xcep.c b/arch/arm/mach-pxa/xcep.c
index 4bbe9a3..4275713 100644
--- a/arch/arm/mach-pxa/xcep.c
+++ b/arch/arm/mach-pxa/xcep.c
@@ -182,6 +182,7 @@
 	.atag_offset	= 0x100,
 	.init_machine	= xcep_init,
 	.map_io		= pxa25x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa25x_init_irq,
 	.handle_irq	= pxa25x_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/z2.c b/arch/arm/mach-pxa/z2.c
index b647684..fa86199 100644
--- a/arch/arm/mach-pxa/z2.c
+++ b/arch/arm/mach-pxa/z2.c
@@ -721,6 +721,7 @@
 MACHINE_START(ZIPIT2, "Zipit Z2")
 	.atag_offset	= 0x100,
 	.map_io		= pxa27x_map_io,
+	.nr_irqs	= PXA_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.handle_irq	= pxa27x_handle_irq,
 	.timer		= &pxa_timer,
diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c
index a4dd1c3..af3d4f7 100644
--- a/arch/arm/mach-pxa/zeus.c
+++ b/arch/arm/mach-pxa/zeus.c
@@ -32,6 +32,7 @@
 
 #include <asm/mach-types.h>
 #include <asm/suspend.h>
+#include <asm/system_info.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index acd329a..45868bb 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -33,7 +33,6 @@
 #include <linux/clkdev.h>
 #include <linux/mtd/physmap.h>
 
-#include <asm/system.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/leds.h>
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
index 735b57a..f8f2c0a 100644
--- a/arch/arm/mach-realview/core.h
+++ b/arch/arm/mach-realview/core.h
@@ -28,21 +28,11 @@
 #include <asm/setup.h>
 #include <asm/leds.h>
 
-#define AMBA_DEVICE(name,busid,base,plat)			\
-static struct amba_device name##_device = {			\
-	.dev		= {					\
-		.coherent_dma_mask = ~0,			\
-		.init_name = busid,				\
-		.platform_data = plat,				\
-	},							\
-	.res		= {					\
-		.start	= REALVIEW_##base##_BASE,		\
-		.end	= (REALVIEW_##base##_BASE) + SZ_4K - 1,	\
-		.flags	= IORESOURCE_MEM,			\
-	},							\
-	.dma_mask	= ~0,					\
-	.irq		= base##_IRQ,				\
-}
+#define APB_DEVICE(name, busid, base, plat)			\
+static AMBA_APB_DEVICE(name, busid, 0, REALVIEW_##base##_BASE, base##_IRQ, plat)
+
+#define AHB_DEVICE(name, busid, base, plat)			\
+static AMBA_AHB_DEVICE(name, busid, 0, REALVIEW_##base##_BASE, base##_IRQ, plat)
 
 struct machine_desc;
 
diff --git a/arch/arm/mach-realview/hotplug.c b/arch/arm/mach-realview/hotplug.c
index eb55f05..57d9efb 100644
--- a/arch/arm/mach-realview/hotplug.c
+++ b/arch/arm/mach-realview/hotplug.c
@@ -13,6 +13,7 @@
 #include <linux/smp.h>
 
 #include <asm/cacheflush.h>
+#include <asm/cp15.h>
 #include <asm/smp_plat.h>
 
 extern volatile int pen_release;
diff --git a/arch/arm/mach-realview/include/mach/entry-macro.S b/arch/arm/mach-realview/include/mach/entry-macro.S
deleted file mode 100644
index e8a5179..0000000
--- a/arch/arm/mach-realview/include/mach/entry-macro.S
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * arch/arm/mach-realview/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for RealView platforms
- *
- * 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.
- */
-
-		.macro	disable_fiq
-		.endm
-
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
-
diff --git a/arch/arm/mach-realview/include/mach/hardware.h b/arch/arm/mach-realview/include/mach/hardware.h
index 8a638d1..281e71c 100644
--- a/arch/arm/mach-realview/include/mach/hardware.h
+++ b/arch/arm/mach-realview/include/mach/hardware.h
@@ -37,6 +37,6 @@
 #else
 #define IO_ADDRESS(x)		(x)
 #endif
-#define __io_address(n)		__io(IO_ADDRESS(n))
+#define __io_address(n)		IOMEM(IO_ADDRESS(n))
 
 #endif
diff --git a/arch/arm/mach-realview/include/mach/io.h b/arch/arm/mach-realview/include/mach/io.h
deleted file mode 100644
index f05bcdf..0000000
--- a/arch/arm/mach-realview/include/mach/io.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *  arch/arm/mach-realview/include/mach/io.h
- *
- *  Copyright (C) 2003 ARM 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#endif
diff --git a/arch/arm/mach-realview/include/mach/irqs-eb.h b/arch/arm/mach-realview/include/mach/irqs-eb.h
index 204d537..d6b5073 100644
--- a/arch/arm/mach-realview/include/mach/irqs-eb.h
+++ b/arch/arm/mach-realview/include/mach/irqs-eb.h
@@ -96,16 +96,19 @@
 #define IRQ_EB11MP_L220_SLAVE	(IRQ_EB_GIC_START + 30)
 #define IRQ_EB11MP_L220_DECODE	(IRQ_EB_GIC_START + 31)
 
-#define IRQ_EB11MP_UART2	-1
-#define IRQ_EB11MP_UART3	-1
-#define IRQ_EB11MP_CLCD		-1
-#define IRQ_EB11MP_DMA		-1
-#define IRQ_EB11MP_WDOG		-1
-#define IRQ_EB11MP_GPIO0	-1
-#define IRQ_EB11MP_GPIO1	-1
-#define IRQ_EB11MP_GPIO2	-1
-#define IRQ_EB11MP_SCI		-1
-#define IRQ_EB11MP_SSP		-1
+/*
+ * The 11MPcore tile leaves the following unconnected.
+ */
+#define IRQ_EB11MP_UART2	0
+#define IRQ_EB11MP_UART3	0
+#define IRQ_EB11MP_CLCD		0
+#define IRQ_EB11MP_DMA		0
+#define IRQ_EB11MP_WDOG		0
+#define IRQ_EB11MP_GPIO0	0
+#define IRQ_EB11MP_GPIO1	0
+#define IRQ_EB11MP_GPIO2	0
+#define IRQ_EB11MP_SCI		0
+#define IRQ_EB11MP_SSP		0
 
 #define NR_GIC_EB11MP		2
 
diff --git a/arch/arm/mach-realview/include/mach/irqs-pb1176.h b/arch/arm/mach-realview/include/mach/irqs-pb1176.h
index 5c3c625..708f841 100644
--- a/arch/arm/mach-realview/include/mach/irqs-pb1176.h
+++ b/arch/arm/mach-realview/include/mach/irqs-pb1176.h
@@ -40,6 +40,7 @@
 #define IRQ_DC1176_L2CC		(IRQ_DC1176_GIC_START + 13)
 #define IRQ_DC1176_RTC		(IRQ_DC1176_GIC_START + 14)
 #define IRQ_DC1176_CLCD		(IRQ_DC1176_GIC_START + 15)	/* CLCD controller */
+#define IRQ_DC1176_GPIO0	(IRQ_DC1176_GIC_START + 16)
 #define IRQ_DC1176_SSP		(IRQ_DC1176_GIC_START + 17)	/* SSP port */
 #define IRQ_DC1176_UART0	(IRQ_DC1176_GIC_START + 18)	/* UART 0 on development chip */
 #define IRQ_DC1176_UART1	(IRQ_DC1176_GIC_START + 19)	/* UART 1 on development chip */
@@ -73,7 +74,6 @@
 #define IRQ_PB1176_DMAC		(IRQ_PB1176_GIC_START + 24)	/* DMA controller */
 #define IRQ_PB1176_RTC		(IRQ_PB1176_GIC_START + 25)	/* Real Time Clock */
 
-#define IRQ_PB1176_GPIO0	-1
 #define IRQ_PB1176_SCTL		-1
 
 #define NR_GIC_PB1176		2
diff --git a/arch/arm/mach-realview/include/mach/system.h b/arch/arm/mach-realview/include/mach/system.h
deleted file mode 100644
index 471b671..0000000
--- a/arch/arm/mach-realview/include/mach/system.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  arch/arm/mach-realview/include/mach/system.h
- *
- *  Copyright (C) 2003 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	/*
-	 * This should do all the clock switching
-	 * and wait for interrupt tricks
-	 */
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 9578145..baf382c 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -36,7 +36,7 @@
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
-#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -135,63 +135,63 @@
 /*
  * These devices are connected via the core APB bridge
  */
-#define GPIO2_IRQ	{ IRQ_EB_GPIO2, NO_IRQ }
-#define GPIO3_IRQ	{ IRQ_EB_GPIO3, NO_IRQ }
+#define GPIO2_IRQ	{ IRQ_EB_GPIO2 }
+#define GPIO3_IRQ	{ IRQ_EB_GPIO3 }
 
-#define AACI_IRQ	{ IRQ_EB_AACI, NO_IRQ }
+#define AACI_IRQ	{ IRQ_EB_AACI }
 #define MMCI0_IRQ	{ IRQ_EB_MMCI0A, IRQ_EB_MMCI0B }
-#define KMI0_IRQ	{ IRQ_EB_KMI0, NO_IRQ }
-#define KMI1_IRQ	{ IRQ_EB_KMI1, NO_IRQ }
+#define KMI0_IRQ	{ IRQ_EB_KMI0 }
+#define KMI1_IRQ	{ IRQ_EB_KMI1 }
 
 /*
  * These devices are connected directly to the multi-layer AHB switch
  */
-#define EB_SMC_IRQ	{ NO_IRQ, NO_IRQ }
-#define MPMC_IRQ	{ NO_IRQ, NO_IRQ }
-#define EB_CLCD_IRQ	{ IRQ_EB_CLCD, NO_IRQ }
-#define DMAC_IRQ	{ IRQ_EB_DMA, NO_IRQ }
+#define EB_SMC_IRQ	{ }
+#define MPMC_IRQ	{ }
+#define EB_CLCD_IRQ	{ IRQ_EB_CLCD }
+#define DMAC_IRQ	{ IRQ_EB_DMA }
 
 /*
  * These devices are connected via the core APB bridge
  */
-#define SCTL_IRQ	{ NO_IRQ, NO_IRQ }
-#define EB_WATCHDOG_IRQ	{ IRQ_EB_WDOG, NO_IRQ }
-#define EB_GPIO0_IRQ	{ IRQ_EB_GPIO0, NO_IRQ }
-#define GPIO1_IRQ	{ IRQ_EB_GPIO1, NO_IRQ }
-#define EB_RTC_IRQ	{ IRQ_EB_RTC, NO_IRQ }
+#define SCTL_IRQ	{ }
+#define EB_WATCHDOG_IRQ	{ IRQ_EB_WDOG }
+#define EB_GPIO0_IRQ	{ IRQ_EB_GPIO0 }
+#define GPIO1_IRQ	{ IRQ_EB_GPIO1 }
+#define EB_RTC_IRQ	{ IRQ_EB_RTC }
 
 /*
  * These devices are connected via the DMA APB bridge
  */
-#define SCI_IRQ		{ IRQ_EB_SCI, NO_IRQ }
-#define EB_UART0_IRQ	{ IRQ_EB_UART0, NO_IRQ }
-#define EB_UART1_IRQ	{ IRQ_EB_UART1, NO_IRQ }
-#define EB_UART2_IRQ	{ IRQ_EB_UART2, NO_IRQ }
-#define EB_UART3_IRQ	{ IRQ_EB_UART3, NO_IRQ }
-#define EB_SSP_IRQ	{ IRQ_EB_SSP, NO_IRQ }
+#define SCI_IRQ		{ IRQ_EB_SCI }
+#define EB_UART0_IRQ	{ IRQ_EB_UART0 }
+#define EB_UART1_IRQ	{ IRQ_EB_UART1 }
+#define EB_UART2_IRQ	{ IRQ_EB_UART2 }
+#define EB_UART3_IRQ	{ IRQ_EB_UART3 }
+#define EB_SSP_IRQ	{ IRQ_EB_SSP }
 
 /* FPGA Primecells */
-AMBA_DEVICE(aaci,  "fpga:aaci",  AACI,     NULL);
-AMBA_DEVICE(mmc0,  "fpga:mmc0",  MMCI0,    &realview_mmc0_plat_data);
-AMBA_DEVICE(kmi0,  "fpga:kmi0",  KMI0,     NULL);
-AMBA_DEVICE(kmi1,  "fpga:kmi1",  KMI1,     NULL);
-AMBA_DEVICE(uart3, "fpga:uart3", EB_UART3, NULL);
+APB_DEVICE(aaci,  "fpga:aaci",  AACI,     NULL);
+APB_DEVICE(mmc0,  "fpga:mmc0",  MMCI0,    &realview_mmc0_plat_data);
+APB_DEVICE(kmi0,  "fpga:kmi0",  KMI0,     NULL);
+APB_DEVICE(kmi1,  "fpga:kmi1",  KMI1,     NULL);
+APB_DEVICE(uart3, "fpga:uart3", EB_UART3, NULL);
 
 /* DevChip Primecells */
-AMBA_DEVICE(smc,   "dev:smc",   EB_SMC,   NULL);
-AMBA_DEVICE(clcd,  "dev:clcd",  EB_CLCD,  &clcd_plat_data);
-AMBA_DEVICE(dmac,  "dev:dmac",  DMAC,     NULL);
-AMBA_DEVICE(sctl,  "dev:sctl",  SCTL,     NULL);
-AMBA_DEVICE(wdog,  "dev:wdog",  EB_WATCHDOG, NULL);
-AMBA_DEVICE(gpio0, "dev:gpio0", EB_GPIO0, &gpio0_plat_data);
-AMBA_DEVICE(gpio1, "dev:gpio1", GPIO1,    &gpio1_plat_data);
-AMBA_DEVICE(gpio2, "dev:gpio2", GPIO2,    &gpio2_plat_data);
-AMBA_DEVICE(rtc,   "dev:rtc",   EB_RTC,   NULL);
-AMBA_DEVICE(sci0,  "dev:sci0",  SCI,      NULL);
-AMBA_DEVICE(uart0, "dev:uart0", EB_UART0, NULL);
-AMBA_DEVICE(uart1, "dev:uart1", EB_UART1, NULL);
-AMBA_DEVICE(uart2, "dev:uart2", EB_UART2, NULL);
-AMBA_DEVICE(ssp0,  "dev:ssp0",  EB_SSP,   &ssp0_plat_data);
+AHB_DEVICE(smc,   "dev:smc",   EB_SMC,   NULL);
+AHB_DEVICE(clcd,  "dev:clcd",  EB_CLCD,  &clcd_plat_data);
+AHB_DEVICE(dmac,  "dev:dmac",  DMAC,     NULL);
+AHB_DEVICE(sctl,  "dev:sctl",  SCTL,     NULL);
+APB_DEVICE(wdog,  "dev:wdog",  EB_WATCHDOG, NULL);
+APB_DEVICE(gpio0, "dev:gpio0", EB_GPIO0, &gpio0_plat_data);
+APB_DEVICE(gpio1, "dev:gpio1", GPIO1,    &gpio1_plat_data);
+APB_DEVICE(gpio2, "dev:gpio2", GPIO2,    &gpio2_plat_data);
+APB_DEVICE(rtc,   "dev:rtc",   EB_RTC,   NULL);
+APB_DEVICE(sci0,  "dev:sci0",  SCI,      NULL);
+APB_DEVICE(uart0, "dev:uart0", EB_UART0, NULL);
+APB_DEVICE(uart1, "dev:uart1", EB_UART1, NULL);
+APB_DEVICE(uart2, "dev:uart2", EB_UART2, NULL);
+APB_DEVICE(ssp0,  "dev:ssp0",  EB_SSP,   &ssp0_plat_data);
 
 static struct amba_device *amba_devs[] __initdata = {
 	&dmac_device,
@@ -383,6 +383,23 @@
 	realview_eb_isp1761_resources[1].end	= IRQ_EB11MP_USB;
 }
 
+#ifdef CONFIG_HAVE_ARM_TWD
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
+			      REALVIEW_EB11MP_TWD_BASE,
+			      IRQ_LOCALTIMER);
+
+static void __init realview_eb_twd_init(void)
+{
+	if (core_tile_eb11mp() || core_tile_a9mp()) {
+		int err = twd_local_timer_register(&twd_local_timer);
+		if (err)
+			pr_err("twd_local_timer_register failed %d\n", err);
+	}
+}
+#else
+#define realview_eb_twd_init()	do { } while(0)
+#endif
+
 static void __init realview_eb_timer_init(void)
 {
 	unsigned int timer_irq;
@@ -392,15 +409,13 @@
 	timer2_va_base = __io_address(REALVIEW_EB_TIMER2_3_BASE);
 	timer3_va_base = __io_address(REALVIEW_EB_TIMER2_3_BASE) + 0x20;
 
-	if (core_tile_eb11mp() || core_tile_a9mp()) {
-#ifdef CONFIG_LOCAL_TIMERS
-		twd_base = __io_address(REALVIEW_EB11MP_TWD_BASE);
-#endif
+	if (core_tile_eb11mp() || core_tile_a9mp())
 		timer_irq = IRQ_EB11MP_TIMER0_1;
-	} else
+	else
 		timer_irq = IRQ_EB_TIMER0_1;
 
 	realview_timer_init(timer_irq);
+	realview_eb_twd_init();
 }
 
 static struct sys_timer realview_eb_timer = {
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index e4abe94..b1d7caf 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -132,50 +132,50 @@
 /*
  * RealView PB1176 AMBA devices
  */
-#define GPIO2_IRQ	{ IRQ_PB1176_GPIO2, NO_IRQ }
-#define GPIO3_IRQ	{ IRQ_PB1176_GPIO3, NO_IRQ }
-#define AACI_IRQ	{ IRQ_PB1176_AACI, NO_IRQ }
+#define GPIO2_IRQ	{ IRQ_PB1176_GPIO2 }
+#define GPIO3_IRQ	{ IRQ_PB1176_GPIO3 }
+#define AACI_IRQ	{ IRQ_PB1176_AACI }
 #define MMCI0_IRQ	{ IRQ_PB1176_MMCI0A, IRQ_PB1176_MMCI0B }
-#define KMI0_IRQ	{ IRQ_PB1176_KMI0, NO_IRQ }
-#define KMI1_IRQ	{ IRQ_PB1176_KMI1, NO_IRQ }
-#define PB1176_SMC_IRQ	{ NO_IRQ, NO_IRQ }
-#define MPMC_IRQ	{ NO_IRQ, NO_IRQ }
-#define PB1176_CLCD_IRQ	{ IRQ_DC1176_CLCD, NO_IRQ }
-#define SCTL_IRQ	{ NO_IRQ, NO_IRQ }
-#define PB1176_WATCHDOG_IRQ	{ IRQ_DC1176_WATCHDOG, NO_IRQ }
-#define PB1176_GPIO0_IRQ	{ IRQ_PB1176_GPIO0, NO_IRQ }
-#define GPIO1_IRQ	{ IRQ_PB1176_GPIO1, NO_IRQ }
-#define PB1176_RTC_IRQ	{ IRQ_DC1176_RTC, NO_IRQ }
-#define SCI_IRQ		{ IRQ_PB1176_SCI, NO_IRQ }
-#define PB1176_UART0_IRQ	{ IRQ_DC1176_UART0, NO_IRQ }
-#define PB1176_UART1_IRQ	{ IRQ_DC1176_UART1, NO_IRQ }
-#define PB1176_UART2_IRQ	{ IRQ_DC1176_UART2, NO_IRQ }
-#define PB1176_UART3_IRQ	{ IRQ_DC1176_UART3, NO_IRQ }
-#define PB1176_UART4_IRQ	{ IRQ_PB1176_UART4, NO_IRQ }
-#define PB1176_SSP_IRQ		{ IRQ_DC1176_SSP, NO_IRQ }
+#define KMI0_IRQ	{ IRQ_PB1176_KMI0 }
+#define KMI1_IRQ	{ IRQ_PB1176_KMI1 }
+#define PB1176_SMC_IRQ	{ }
+#define MPMC_IRQ	{ }
+#define PB1176_CLCD_IRQ	{ IRQ_DC1176_CLCD }
+#define SCTL_IRQ	{ }
+#define PB1176_WATCHDOG_IRQ	{ IRQ_DC1176_WATCHDOG }
+#define PB1176_GPIO0_IRQ	{ IRQ_DC1176_GPIO0 }
+#define GPIO1_IRQ	{ IRQ_PB1176_GPIO1 }
+#define PB1176_RTC_IRQ	{ IRQ_DC1176_RTC }
+#define SCI_IRQ		{ IRQ_PB1176_SCI }
+#define PB1176_UART0_IRQ	{ IRQ_DC1176_UART0 }
+#define PB1176_UART1_IRQ	{ IRQ_DC1176_UART1 }
+#define PB1176_UART2_IRQ	{ IRQ_DC1176_UART2 }
+#define PB1176_UART3_IRQ	{ IRQ_DC1176_UART3 }
+#define PB1176_UART4_IRQ	{ IRQ_PB1176_UART4 }
+#define PB1176_SSP_IRQ		{ IRQ_DC1176_SSP }
 
 /* FPGA Primecells */
-AMBA_DEVICE(aaci,	"fpga:aaci",	AACI,		NULL);
-AMBA_DEVICE(mmc0,	"fpga:mmc0",	MMCI0,		&realview_mmc0_plat_data);
-AMBA_DEVICE(kmi0,	"fpga:kmi0",	KMI0,		NULL);
-AMBA_DEVICE(kmi1,	"fpga:kmi1",	KMI1,		NULL);
-AMBA_DEVICE(uart4,	"fpga:uart4",	PB1176_UART4,	NULL);
+APB_DEVICE(aaci,	"fpga:aaci",	AACI,		NULL);
+APB_DEVICE(mmc0,	"fpga:mmc0",	MMCI0,		&realview_mmc0_plat_data);
+APB_DEVICE(kmi0,	"fpga:kmi0",	KMI0,		NULL);
+APB_DEVICE(kmi1,	"fpga:kmi1",	KMI1,		NULL);
+APB_DEVICE(uart4,	"fpga:uart4",	PB1176_UART4,	NULL);
 
 /* DevChip Primecells */
-AMBA_DEVICE(smc,	"dev:smc",	PB1176_SMC,	NULL);
-AMBA_DEVICE(sctl,	"dev:sctl",	SCTL,		NULL);
-AMBA_DEVICE(wdog,	"dev:wdog",	PB1176_WATCHDOG,	NULL);
-AMBA_DEVICE(gpio0,	"dev:gpio0",	PB1176_GPIO0,	&gpio0_plat_data);
-AMBA_DEVICE(gpio1,	"dev:gpio1",	GPIO1,		&gpio1_plat_data);
-AMBA_DEVICE(gpio2,	"dev:gpio2",	GPIO2,		&gpio2_plat_data);
-AMBA_DEVICE(rtc,	"dev:rtc",	PB1176_RTC,	NULL);
-AMBA_DEVICE(sci0,	"dev:sci0",	SCI,		NULL);
-AMBA_DEVICE(uart0,	"dev:uart0",	PB1176_UART0,	NULL);
-AMBA_DEVICE(uart1,	"dev:uart1",	PB1176_UART1,	NULL);
-AMBA_DEVICE(uart2,	"dev:uart2",	PB1176_UART2,	NULL);
-AMBA_DEVICE(uart3,	"dev:uart3",	PB1176_UART3,	NULL);
-AMBA_DEVICE(ssp0,	"dev:ssp0",	PB1176_SSP,	&ssp0_plat_data);
-AMBA_DEVICE(clcd,	"dev:clcd",	PB1176_CLCD,	&clcd_plat_data);
+AHB_DEVICE(smc,		"dev:smc",	PB1176_SMC,	NULL);
+AHB_DEVICE(sctl,	"dev:sctl",	SCTL,		NULL);
+APB_DEVICE(wdog,	"dev:wdog",	PB1176_WATCHDOG,	NULL);
+APB_DEVICE(gpio0,	"dev:gpio0",	PB1176_GPIO0,	&gpio0_plat_data);
+APB_DEVICE(gpio1,	"dev:gpio1",	GPIO1,		&gpio1_plat_data);
+APB_DEVICE(gpio2,	"dev:gpio2",	GPIO2,		&gpio2_plat_data);
+APB_DEVICE(rtc,		"dev:rtc",	PB1176_RTC,	NULL);
+APB_DEVICE(sci0,	"dev:sci0",	SCI,		NULL);
+APB_DEVICE(uart0,	"dev:uart0",	PB1176_UART0,	NULL);
+APB_DEVICE(uart1,	"dev:uart1",	PB1176_UART1,	NULL);
+APB_DEVICE(uart2,	"dev:uart2",	PB1176_UART2,	NULL);
+APB_DEVICE(uart3,	"dev:uart3",	PB1176_UART3,	NULL);
+APB_DEVICE(ssp0,	"dev:ssp0",	PB1176_SSP,	&ssp0_plat_data);
+AHB_DEVICE(clcd,	"dev:clcd",	PB1176_CLCD,	&clcd_plat_data);
 
 static struct amba_device *amba_devs[] __initdata = {
 	&uart0_device,
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index 2147335..a98c536 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -36,7 +36,7 @@
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
-#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
@@ -127,52 +127,52 @@
  * RealView PB11MPCore AMBA devices
  */
 
-#define GPIO2_IRQ		{ IRQ_PB11MP_GPIO2, NO_IRQ }
-#define GPIO3_IRQ		{ IRQ_PB11MP_GPIO3, NO_IRQ }
-#define AACI_IRQ		{ IRQ_TC11MP_AACI, NO_IRQ }
+#define GPIO2_IRQ		{ IRQ_PB11MP_GPIO2 }
+#define GPIO3_IRQ		{ IRQ_PB11MP_GPIO3 }
+#define AACI_IRQ		{ IRQ_TC11MP_AACI }
 #define MMCI0_IRQ		{ IRQ_TC11MP_MMCI0A, IRQ_TC11MP_MMCI0B }
-#define KMI0_IRQ		{ IRQ_TC11MP_KMI0, NO_IRQ }
-#define KMI1_IRQ		{ IRQ_TC11MP_KMI1, NO_IRQ }
-#define PB11MP_SMC_IRQ		{ NO_IRQ, NO_IRQ }
-#define MPMC_IRQ		{ NO_IRQ, NO_IRQ }
-#define PB11MP_CLCD_IRQ		{ IRQ_PB11MP_CLCD, NO_IRQ }
-#define DMAC_IRQ		{ IRQ_PB11MP_DMAC, NO_IRQ }
-#define SCTL_IRQ		{ NO_IRQ, NO_IRQ }
-#define PB11MP_WATCHDOG_IRQ	{ IRQ_PB11MP_WATCHDOG, NO_IRQ }
-#define PB11MP_GPIO0_IRQ	{ IRQ_PB11MP_GPIO0, NO_IRQ }
-#define GPIO1_IRQ		{ IRQ_PB11MP_GPIO1, NO_IRQ }
-#define PB11MP_RTC_IRQ		{ IRQ_TC11MP_RTC, NO_IRQ }
-#define SCI_IRQ			{ IRQ_PB11MP_SCI, NO_IRQ }
-#define PB11MP_UART0_IRQ	{ IRQ_TC11MP_UART0, NO_IRQ }
-#define PB11MP_UART1_IRQ	{ IRQ_TC11MP_UART1, NO_IRQ }
-#define PB11MP_UART2_IRQ	{ IRQ_PB11MP_UART2, NO_IRQ }
-#define PB11MP_UART3_IRQ	{ IRQ_PB11MP_UART3, NO_IRQ }
-#define PB11MP_SSP_IRQ		{ IRQ_PB11MP_SSP, NO_IRQ }
+#define KMI0_IRQ		{ IRQ_TC11MP_KMI0 }
+#define KMI1_IRQ		{ IRQ_TC11MP_KMI1 }
+#define PB11MP_SMC_IRQ		{ }
+#define MPMC_IRQ		{ }
+#define PB11MP_CLCD_IRQ		{ IRQ_PB11MP_CLCD }
+#define DMAC_IRQ		{ IRQ_PB11MP_DMAC }
+#define SCTL_IRQ		{ }
+#define PB11MP_WATCHDOG_IRQ	{ IRQ_PB11MP_WATCHDOG }
+#define PB11MP_GPIO0_IRQ	{ IRQ_PB11MP_GPIO0 }
+#define GPIO1_IRQ		{ IRQ_PB11MP_GPIO1 }
+#define PB11MP_RTC_IRQ		{ IRQ_TC11MP_RTC }
+#define SCI_IRQ			{ IRQ_PB11MP_SCI }
+#define PB11MP_UART0_IRQ	{ IRQ_TC11MP_UART0 }
+#define PB11MP_UART1_IRQ	{ IRQ_TC11MP_UART1 }
+#define PB11MP_UART2_IRQ	{ IRQ_PB11MP_UART2 }
+#define PB11MP_UART3_IRQ	{ IRQ_PB11MP_UART3 }
+#define PB11MP_SSP_IRQ		{ IRQ_PB11MP_SSP }
 
 /* FPGA Primecells */
-AMBA_DEVICE(aaci,	"fpga:aaci",	AACI,		NULL);
-AMBA_DEVICE(mmc0,	"fpga:mmc0",	MMCI0,		&realview_mmc0_plat_data);
-AMBA_DEVICE(kmi0,	"fpga:kmi0",	KMI0,		NULL);
-AMBA_DEVICE(kmi1,	"fpga:kmi1",	KMI1,		NULL);
-AMBA_DEVICE(uart3,	"fpga:uart3",	PB11MP_UART3,	NULL);
+APB_DEVICE(aaci,	"fpga:aaci",	AACI,		NULL);
+APB_DEVICE(mmc0,	"fpga:mmc0",	MMCI0,		&realview_mmc0_plat_data);
+APB_DEVICE(kmi0,	"fpga:kmi0",	KMI0,		NULL);
+APB_DEVICE(kmi1,	"fpga:kmi1",	KMI1,		NULL);
+APB_DEVICE(uart3,	"fpga:uart3",	PB11MP_UART3,	NULL);
 
 /* DevChip Primecells */
-AMBA_DEVICE(smc,	"dev:smc",	PB11MP_SMC,	NULL);
-AMBA_DEVICE(sctl,	"dev:sctl",	SCTL,		NULL);
-AMBA_DEVICE(wdog,	"dev:wdog",	PB11MP_WATCHDOG, NULL);
-AMBA_DEVICE(gpio0,	"dev:gpio0",	PB11MP_GPIO0,	&gpio0_plat_data);
-AMBA_DEVICE(gpio1,	"dev:gpio1",	GPIO1,		&gpio1_plat_data);
-AMBA_DEVICE(gpio2,	"dev:gpio2",	GPIO2,		&gpio2_plat_data);
-AMBA_DEVICE(rtc,	"dev:rtc",	PB11MP_RTC,	NULL);
-AMBA_DEVICE(sci0,	"dev:sci0",	SCI,		NULL);
-AMBA_DEVICE(uart0,	"dev:uart0",	PB11MP_UART0,	NULL);
-AMBA_DEVICE(uart1,	"dev:uart1",	PB11MP_UART1,	NULL);
-AMBA_DEVICE(uart2,	"dev:uart2",	PB11MP_UART2,	NULL);
-AMBA_DEVICE(ssp0,	"dev:ssp0",	PB11MP_SSP,	&ssp0_plat_data);
+AHB_DEVICE(smc,		"dev:smc",	PB11MP_SMC,	NULL);
+AHB_DEVICE(sctl,	"dev:sctl",	SCTL,		NULL);
+APB_DEVICE(wdog,	"dev:wdog",	PB11MP_WATCHDOG, NULL);
+APB_DEVICE(gpio0,	"dev:gpio0",	PB11MP_GPIO0,	&gpio0_plat_data);
+APB_DEVICE(gpio1,	"dev:gpio1",	GPIO1,		&gpio1_plat_data);
+APB_DEVICE(gpio2,	"dev:gpio2",	GPIO2,		&gpio2_plat_data);
+APB_DEVICE(rtc,		"dev:rtc",	PB11MP_RTC,	NULL);
+APB_DEVICE(sci0,	"dev:sci0",	SCI,		NULL);
+APB_DEVICE(uart0,	"dev:uart0",	PB11MP_UART0,	NULL);
+APB_DEVICE(uart1,	"dev:uart1",	PB11MP_UART1,	NULL);
+APB_DEVICE(uart2,	"dev:uart2",	PB11MP_UART2,	NULL);
+APB_DEVICE(ssp0,	"dev:ssp0",	PB11MP_SSP,	&ssp0_plat_data);
 
 /* Primecells on the NEC ISSP chip */
-AMBA_DEVICE(clcd,	"issp:clcd",	PB11MP_CLCD,	&clcd_plat_data);
-AMBA_DEVICE(dmac,	"issp:dmac",	DMAC,		NULL);
+AHB_DEVICE(clcd,	"issp:clcd",	PB11MP_CLCD,	&clcd_plat_data);
+AHB_DEVICE(dmac,	"issp:dmac",	DMAC,		NULL);
 
 static struct amba_device *amba_devs[] __initdata = {
 	&dmac_device,
@@ -290,6 +290,21 @@
 	gic_cascade_irq(1, IRQ_TC11MP_PB_IRQ1);
 }
 
+#ifdef CONFIG_HAVE_ARM_TWD
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
+			      REALVIEW_TC11MP_TWD_BASE,
+			      IRQ_LOCALTIMER);
+
+static void __init realview_pb11mp_twd_init(void)
+{
+	int err = twd_local_timer_register(&twd_local_timer);
+	if (err)
+		pr_err("twd_local_timer_register failed %d\n", err);
+}
+#else
+#define realview_pb11mp_twd_init()	do {} while(0)
+#endif
+
 static void __init realview_pb11mp_timer_init(void)
 {
 	timer0_va_base = __io_address(REALVIEW_PB11MP_TIMER0_1_BASE);
@@ -297,10 +312,8 @@
 	timer2_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE);
 	timer3_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE) + 0x20;
 
-#ifdef CONFIG_LOCAL_TIMERS
-	twd_base = __io_address(REALVIEW_TC11MP_TWD_BASE);
-#endif
 	realview_timer_init(IRQ_TC11MP_TIMER0_1);
+	realview_pb11mp_twd_init();
 }
 
 static struct sys_timer realview_pb11mp_timer = {
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
index 25b2e59..5965017 100644
--- a/arch/arm/mach-realview/realview_pba8.c
+++ b/arch/arm/mach-realview/realview_pba8.c
@@ -122,52 +122,52 @@
  * RealView PBA8Core AMBA devices
  */
 
-#define GPIO2_IRQ		{ IRQ_PBA8_GPIO2, NO_IRQ }
-#define GPIO3_IRQ		{ IRQ_PBA8_GPIO3, NO_IRQ }
-#define AACI_IRQ		{ IRQ_PBA8_AACI, NO_IRQ }
+#define GPIO2_IRQ		{ IRQ_PBA8_GPIO2 }
+#define GPIO3_IRQ		{ IRQ_PBA8_GPIO3 }
+#define AACI_IRQ		{ IRQ_PBA8_AACI }
 #define MMCI0_IRQ		{ IRQ_PBA8_MMCI0A, IRQ_PBA8_MMCI0B }
-#define KMI0_IRQ		{ IRQ_PBA8_KMI0, NO_IRQ }
-#define KMI1_IRQ		{ IRQ_PBA8_KMI1, NO_IRQ }
-#define PBA8_SMC_IRQ		{ NO_IRQ, NO_IRQ }
-#define MPMC_IRQ		{ NO_IRQ, NO_IRQ }
-#define PBA8_CLCD_IRQ		{ IRQ_PBA8_CLCD, NO_IRQ }
-#define DMAC_IRQ		{ IRQ_PBA8_DMAC, NO_IRQ }
-#define SCTL_IRQ		{ NO_IRQ, NO_IRQ }
-#define PBA8_WATCHDOG_IRQ	{ IRQ_PBA8_WATCHDOG, NO_IRQ }
-#define PBA8_GPIO0_IRQ		{ IRQ_PBA8_GPIO0, NO_IRQ }
-#define GPIO1_IRQ		{ IRQ_PBA8_GPIO1, NO_IRQ }
-#define PBA8_RTC_IRQ		{ IRQ_PBA8_RTC, NO_IRQ }
-#define SCI_IRQ			{ IRQ_PBA8_SCI, NO_IRQ }
-#define PBA8_UART0_IRQ		{ IRQ_PBA8_UART0, NO_IRQ }
-#define PBA8_UART1_IRQ		{ IRQ_PBA8_UART1, NO_IRQ }
-#define PBA8_UART2_IRQ		{ IRQ_PBA8_UART2, NO_IRQ }
-#define PBA8_UART3_IRQ		{ IRQ_PBA8_UART3, NO_IRQ }
-#define PBA8_SSP_IRQ		{ IRQ_PBA8_SSP, NO_IRQ }
+#define KMI0_IRQ		{ IRQ_PBA8_KMI0 }
+#define KMI1_IRQ		{ IRQ_PBA8_KMI1 }
+#define PBA8_SMC_IRQ		{ }
+#define MPMC_IRQ		{ }
+#define PBA8_CLCD_IRQ		{ IRQ_PBA8_CLCD }
+#define DMAC_IRQ		{ IRQ_PBA8_DMAC }
+#define SCTL_IRQ		{ }
+#define PBA8_WATCHDOG_IRQ	{ IRQ_PBA8_WATCHDOG }
+#define PBA8_GPIO0_IRQ		{ IRQ_PBA8_GPIO0 }
+#define GPIO1_IRQ		{ IRQ_PBA8_GPIO1 }
+#define PBA8_RTC_IRQ		{ IRQ_PBA8_RTC }
+#define SCI_IRQ			{ IRQ_PBA8_SCI }
+#define PBA8_UART0_IRQ		{ IRQ_PBA8_UART0 }
+#define PBA8_UART1_IRQ		{ IRQ_PBA8_UART1 }
+#define PBA8_UART2_IRQ		{ IRQ_PBA8_UART2 }
+#define PBA8_UART3_IRQ		{ IRQ_PBA8_UART3 }
+#define PBA8_SSP_IRQ		{ IRQ_PBA8_SSP }
 
 /* FPGA Primecells */
-AMBA_DEVICE(aaci,	"fpga:aaci",	AACI,		NULL);
-AMBA_DEVICE(mmc0,	"fpga:mmc0",	MMCI0,		&realview_mmc0_plat_data);
-AMBA_DEVICE(kmi0,	"fpga:kmi0",	KMI0,		NULL);
-AMBA_DEVICE(kmi1,	"fpga:kmi1",	KMI1,		NULL);
-AMBA_DEVICE(uart3,	"fpga:uart3",	PBA8_UART3,	NULL);
+APB_DEVICE(aaci,	"fpga:aaci",	AACI,		NULL);
+APB_DEVICE(mmc0,	"fpga:mmc0",	MMCI0,		&realview_mmc0_plat_data);
+APB_DEVICE(kmi0,	"fpga:kmi0",	KMI0,		NULL);
+APB_DEVICE(kmi1,	"fpga:kmi1",	KMI1,		NULL);
+APB_DEVICE(uart3,	"fpga:uart3",	PBA8_UART3,	NULL);
 
 /* DevChip Primecells */
-AMBA_DEVICE(smc,	"dev:smc",	PBA8_SMC,	NULL);
-AMBA_DEVICE(sctl,	"dev:sctl",	SCTL,		NULL);
-AMBA_DEVICE(wdog,	"dev:wdog",	PBA8_WATCHDOG, NULL);
-AMBA_DEVICE(gpio0,	"dev:gpio0",	PBA8_GPIO0,	&gpio0_plat_data);
-AMBA_DEVICE(gpio1,	"dev:gpio1",	GPIO1,		&gpio1_plat_data);
-AMBA_DEVICE(gpio2,	"dev:gpio2",	GPIO2,		&gpio2_plat_data);
-AMBA_DEVICE(rtc,	"dev:rtc",	PBA8_RTC,	NULL);
-AMBA_DEVICE(sci0,	"dev:sci0",	SCI,		NULL);
-AMBA_DEVICE(uart0,	"dev:uart0",	PBA8_UART0,	NULL);
-AMBA_DEVICE(uart1,	"dev:uart1",	PBA8_UART1,	NULL);
-AMBA_DEVICE(uart2,	"dev:uart2",	PBA8_UART2,	NULL);
-AMBA_DEVICE(ssp0,	"dev:ssp0",	PBA8_SSP,	&ssp0_plat_data);
+AHB_DEVICE(smc,		"dev:smc",	PBA8_SMC,	NULL);
+AHB_DEVICE(sctl,	"dev:sctl",	SCTL,		NULL);
+APB_DEVICE(wdog,	"dev:wdog",	PBA8_WATCHDOG, NULL);
+APB_DEVICE(gpio0,	"dev:gpio0",	PBA8_GPIO0,	&gpio0_plat_data);
+APB_DEVICE(gpio1,	"dev:gpio1",	GPIO1,		&gpio1_plat_data);
+APB_DEVICE(gpio2,	"dev:gpio2",	GPIO2,		&gpio2_plat_data);
+APB_DEVICE(rtc,		"dev:rtc",	PBA8_RTC,	NULL);
+APB_DEVICE(sci0,	"dev:sci0",	SCI,		NULL);
+APB_DEVICE(uart0,	"dev:uart0",	PBA8_UART0,	NULL);
+APB_DEVICE(uart1,	"dev:uart1",	PBA8_UART1,	NULL);
+APB_DEVICE(uart2,	"dev:uart2",	PBA8_UART2,	NULL);
+APB_DEVICE(ssp0,	"dev:ssp0",	PBA8_SSP,	&ssp0_plat_data);
 
 /* Primecells on the NEC ISSP chip */
-AMBA_DEVICE(clcd,	"issp:clcd",	PBA8_CLCD,	&clcd_plat_data);
-AMBA_DEVICE(dmac,	"issp:dmac",	DMAC,		NULL);
+AHB_DEVICE(clcd,	"issp:clcd",	PBA8_CLCD,	&clcd_plat_data);
+AHB_DEVICE(dmac,	"issp:dmac",	DMAC,		NULL);
 
 static struct amba_device *amba_devs[] __initdata = {
 	&dmac_device,
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index ac71564..3f2f605 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -144,52 +144,52 @@
  * RealView PBXCore AMBA devices
  */
 
-#define GPIO2_IRQ		{ IRQ_PBX_GPIO2, NO_IRQ }
-#define GPIO3_IRQ		{ IRQ_PBX_GPIO3, NO_IRQ }
-#define AACI_IRQ		{ IRQ_PBX_AACI, NO_IRQ }
+#define GPIO2_IRQ		{ IRQ_PBX_GPIO2 }
+#define GPIO3_IRQ		{ IRQ_PBX_GPIO3 }
+#define AACI_IRQ		{ IRQ_PBX_AACI }
 #define MMCI0_IRQ		{ IRQ_PBX_MMCI0A, IRQ_PBX_MMCI0B }
-#define KMI0_IRQ		{ IRQ_PBX_KMI0, NO_IRQ }
-#define KMI1_IRQ		{ IRQ_PBX_KMI1, NO_IRQ }
-#define PBX_SMC_IRQ		{ NO_IRQ, NO_IRQ }
-#define MPMC_IRQ		{ NO_IRQ, NO_IRQ }
-#define PBX_CLCD_IRQ		{ IRQ_PBX_CLCD, NO_IRQ }
-#define DMAC_IRQ		{ IRQ_PBX_DMAC, NO_IRQ }
-#define SCTL_IRQ		{ NO_IRQ, NO_IRQ }
-#define PBX_WATCHDOG_IRQ	{ IRQ_PBX_WATCHDOG, NO_IRQ }
-#define PBX_GPIO0_IRQ		{ IRQ_PBX_GPIO0, NO_IRQ }
-#define GPIO1_IRQ		{ IRQ_PBX_GPIO1, NO_IRQ }
-#define PBX_RTC_IRQ		{ IRQ_PBX_RTC, NO_IRQ }
-#define SCI_IRQ			{ IRQ_PBX_SCI, NO_IRQ }
-#define PBX_UART0_IRQ		{ IRQ_PBX_UART0, NO_IRQ }
-#define PBX_UART1_IRQ		{ IRQ_PBX_UART1, NO_IRQ }
-#define PBX_UART2_IRQ		{ IRQ_PBX_UART2, NO_IRQ }
-#define PBX_UART3_IRQ		{ IRQ_PBX_UART3, NO_IRQ }
-#define PBX_SSP_IRQ		{ IRQ_PBX_SSP, NO_IRQ }
+#define KMI0_IRQ		{ IRQ_PBX_KMI0 }
+#define KMI1_IRQ		{ IRQ_PBX_KMI1 }
+#define PBX_SMC_IRQ		{ }
+#define MPMC_IRQ		{ }
+#define PBX_CLCD_IRQ		{ IRQ_PBX_CLCD }
+#define DMAC_IRQ		{ IRQ_PBX_DMAC }
+#define SCTL_IRQ		{ }
+#define PBX_WATCHDOG_IRQ	{ IRQ_PBX_WATCHDOG }
+#define PBX_GPIO0_IRQ		{ IRQ_PBX_GPIO0 }
+#define GPIO1_IRQ		{ IRQ_PBX_GPIO1 }
+#define PBX_RTC_IRQ		{ IRQ_PBX_RTC }
+#define SCI_IRQ			{ IRQ_PBX_SCI }
+#define PBX_UART0_IRQ		{ IRQ_PBX_UART0 }
+#define PBX_UART1_IRQ		{ IRQ_PBX_UART1 }
+#define PBX_UART2_IRQ		{ IRQ_PBX_UART2 }
+#define PBX_UART3_IRQ		{ IRQ_PBX_UART3 }
+#define PBX_SSP_IRQ		{ IRQ_PBX_SSP }
 
 /* FPGA Primecells */
-AMBA_DEVICE(aaci,	"fpga:aaci",	AACI,		NULL);
-AMBA_DEVICE(mmc0,	"fpga:mmc0",	MMCI0,		&realview_mmc0_plat_data);
-AMBA_DEVICE(kmi0,	"fpga:kmi0",	KMI0,		NULL);
-AMBA_DEVICE(kmi1,	"fpga:kmi1",	KMI1,		NULL);
-AMBA_DEVICE(uart3,	"fpga:uart3",	PBX_UART3,	NULL);
+APB_DEVICE(aaci,	"fpga:aaci",	AACI,		NULL);
+APB_DEVICE(mmc0,	"fpga:mmc0",	MMCI0,		&realview_mmc0_plat_data);
+APB_DEVICE(kmi0,	"fpga:kmi0",	KMI0,		NULL);
+APB_DEVICE(kmi1,	"fpga:kmi1",	KMI1,		NULL);
+APB_DEVICE(uart3,	"fpga:uart3",	PBX_UART3,	NULL);
 
 /* DevChip Primecells */
-AMBA_DEVICE(smc,	"dev:smc",	PBX_SMC,	NULL);
-AMBA_DEVICE(sctl,	"dev:sctl",	SCTL,		NULL);
-AMBA_DEVICE(wdog,	"dev:wdog",	PBX_WATCHDOG, 	NULL);
-AMBA_DEVICE(gpio0,	"dev:gpio0",	PBX_GPIO0,	&gpio0_plat_data);
-AMBA_DEVICE(gpio1,	"dev:gpio1",	GPIO1,		&gpio1_plat_data);
-AMBA_DEVICE(gpio2,	"dev:gpio2",	GPIO2,		&gpio2_plat_data);
-AMBA_DEVICE(rtc,	"dev:rtc",	PBX_RTC,	NULL);
-AMBA_DEVICE(sci0,	"dev:sci0",	SCI,		NULL);
-AMBA_DEVICE(uart0,	"dev:uart0",	PBX_UART0,	NULL);
-AMBA_DEVICE(uart1,	"dev:uart1",	PBX_UART1,	NULL);
-AMBA_DEVICE(uart2,	"dev:uart2",	PBX_UART2,	NULL);
-AMBA_DEVICE(ssp0,	"dev:ssp0",	PBX_SSP,	&ssp0_plat_data);
+AHB_DEVICE(smc,	"dev:smc",	PBX_SMC,	NULL);
+AHB_DEVICE(sctl,	"dev:sctl",	SCTL,		NULL);
+APB_DEVICE(wdog,	"dev:wdog",	PBX_WATCHDOG, 	NULL);
+APB_DEVICE(gpio0,	"dev:gpio0",	PBX_GPIO0,	&gpio0_plat_data);
+APB_DEVICE(gpio1,	"dev:gpio1",	GPIO1,		&gpio1_plat_data);
+APB_DEVICE(gpio2,	"dev:gpio2",	GPIO2,		&gpio2_plat_data);
+APB_DEVICE(rtc,		"dev:rtc",	PBX_RTC,	NULL);
+APB_DEVICE(sci0,	"dev:sci0",	SCI,		NULL);
+APB_DEVICE(uart0,	"dev:uart0",	PBX_UART0,	NULL);
+APB_DEVICE(uart1,	"dev:uart1",	PBX_UART1,	NULL);
+APB_DEVICE(uart2,	"dev:uart2",	PBX_UART2,	NULL);
+APB_DEVICE(ssp0,	"dev:ssp0",	PBX_SSP,	&ssp0_plat_data);
 
 /* Primecells on the NEC ISSP chip */
-AMBA_DEVICE(clcd,	"issp:clcd",	PBX_CLCD,	&clcd_plat_data);
-AMBA_DEVICE(dmac,	"issp:dmac",	DMAC,		NULL);
+AHB_DEVICE(clcd,	"issp:clcd",	PBX_CLCD,	&clcd_plat_data);
+AHB_DEVICE(dmac,	"issp:dmac",	DMAC,		NULL);
 
 static struct amba_device *amba_devs[] __initdata = {
 	&dmac_device,
@@ -298,6 +298,21 @@
 	}
 }
 
+#ifdef CONFIG_HAVE_ARM_TWD
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
+			      REALVIEW_PBX_TILE_TWD_BASE,
+			      IRQ_LOCALTIMER);
+
+static void __init realview_pbx_twd_init(void)
+{
+	int err = twd_local_timer_register(&twd_local_timer);
+	if (err)
+		pr_err("twd_local_timer_register failed %d\n", err);
+}
+#else
+#define realview_pbx_twd_init()	do { } while(0)
+#endif
+
 static void __init realview_pbx_timer_init(void)
 {
 	timer0_va_base = __io_address(REALVIEW_PBX_TIMER0_1_BASE);
@@ -305,11 +320,8 @@
 	timer2_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE);
 	timer3_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE) + 0x20;
 
-#ifdef CONFIG_LOCAL_TIMERS
-	if (core_tile_pbx11mp() || core_tile_pbxa9mp())
-		twd_base = __io_address(REALVIEW_PBX_TILE_TWD_BASE);
-#endif
 	realview_timer_init(IRQ_PBX_TIMER0_1);
+	realview_pbx_twd_init();
 }
 
 static struct sys_timer realview_pbx_timer = {
diff --git a/arch/arm/mach-rpc/Makefile b/arch/arm/mach-rpc/Makefile
index aa77bc9..992e28b 100644
--- a/arch/arm/mach-rpc/Makefile
+++ b/arch/arm/mach-rpc/Makefile
@@ -4,7 +4,7 @@
 
 # Object file lists.
 
-obj-y			:= dma.o irq.o riscpc.o
+obj-y			:= dma.o ecard.o fiq.o irq.o riscpc.o time.o
 obj-m			:=
 obj-n			:=
 obj-			:=
diff --git a/arch/arm/mach-rpc/ecard.c b/arch/arm/mach-rpc/ecard.c
new file mode 100644
index 0000000..b91bc87
--- /dev/null
+++ b/arch/arm/mach-rpc/ecard.c
@@ -0,0 +1,1138 @@
+/*
+ *  linux/arch/arm/kernel/ecard.c
+ *
+ *  Copyright 1995-2001 Russell King
+ *
+ * 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.
+ *
+ *  Find all installed expansion cards, and handle interrupts from them.
+ *
+ *  Created from information from Acorns RiscOS3 PRMs
+ *
+ *  08-Dec-1996	RMK	Added code for the 9'th expansion card - the ether
+ *			podule slot.
+ *  06-May-1997	RMK	Added blacklist for cards whose loader doesn't work.
+ *  12-Sep-1997	RMK	Created new handling of interrupt enables/disables
+ *			- cards can now register their own routine to control
+ *			interrupts (recommended).
+ *  29-Sep-1997	RMK	Expansion card interrupt hardware not being re-enabled
+ *			on reset from Linux. (Caused cards not to respond
+ *			under RiscOS without hard reset).
+ *  15-Feb-1998	RMK	Added DMA support
+ *  12-Sep-1998	RMK	Added EASI support
+ *  10-Jan-1999	RMK	Run loaders in a simulated RISC OS environment.
+ *  17-Apr-1999	RMK	Support for EASI Type C cycles.
+ */
+#define ECARD_C
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/reboot.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mmu_context.h>
+#include <asm/mach/irq.h>
+#include <asm/tlbflush.h>
+
+#include "ecard.h"
+
+struct ecard_request {
+	void		(*fn)(struct ecard_request *);
+	ecard_t		*ec;
+	unsigned int	address;
+	unsigned int	length;
+	unsigned int	use_loader;
+	void		*buffer;
+	struct completion *complete;
+};
+
+struct expcard_blacklist {
+	unsigned short	 manufacturer;
+	unsigned short	 product;
+	const char	*type;
+};
+
+static ecard_t *cards;
+static ecard_t *slot_to_expcard[MAX_ECARDS];
+static unsigned int ectcr;
+
+/* List of descriptions of cards which don't have an extended
+ * identification, or chunk directories containing a description.
+ */
+static struct expcard_blacklist __initdata blacklist[] = {
+	{ MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" }
+};
+
+asmlinkage extern int
+ecard_loader_reset(unsigned long base, loader_t loader);
+asmlinkage extern int
+ecard_loader_read(int off, unsigned long base, loader_t loader);
+
+static inline unsigned short ecard_getu16(unsigned char *v)
+{
+	return v[0] | v[1] << 8;
+}
+
+static inline signed long ecard_gets24(unsigned char *v)
+{
+	return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
+}
+
+static inline ecard_t *slot_to_ecard(unsigned int slot)
+{
+	return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL;
+}
+
+/* ===================== Expansion card daemon ======================== */
+/*
+ * Since the loader programs on the expansion cards need to be run
+ * in a specific environment, create a separate task with this
+ * environment up, and pass requests to this task as and when we
+ * need to.
+ *
+ * This should allow 99% of loaders to be called from Linux.
+ *
+ * From a security standpoint, we trust the card vendors.  This
+ * may be a misplaced trust.
+ */
+static void ecard_task_reset(struct ecard_request *req)
+{
+	struct expansion_card *ec = req->ec;
+	struct resource *res;
+
+	res = ec->slot_no == 8
+		? &ec->resource[ECARD_RES_MEMC]
+		: ec->easi
+		  ? &ec->resource[ECARD_RES_EASI]
+		  : &ec->resource[ECARD_RES_IOCSYNC];
+
+	ecard_loader_reset(res->start, ec->loader);
+}
+
+static void ecard_task_readbytes(struct ecard_request *req)
+{
+	struct expansion_card *ec = req->ec;
+	unsigned char *buf = req->buffer;
+	unsigned int len = req->length;
+	unsigned int off = req->address;
+
+	if (ec->slot_no == 8) {
+		void __iomem *base = (void __iomem *)
+				ec->resource[ECARD_RES_MEMC].start;
+
+		/*
+		 * The card maintains an index which increments the address
+		 * into a 4096-byte page on each access.  We need to keep
+		 * track of the counter.
+		 */
+		static unsigned int index;
+		unsigned int page;
+
+		page = (off >> 12) * 4;
+		if (page > 256 * 4)
+			return;
+
+		off &= 4095;
+
+		/*
+		 * If we are reading offset 0, or our current index is
+		 * greater than the offset, reset the hardware index counter.
+		 */
+		if (off == 0 || index > off) {
+			writeb(0, base);
+			index = 0;
+		}
+
+		/*
+		 * Increment the hardware index counter until we get to the
+		 * required offset.  The read bytes are discarded.
+		 */
+		while (index < off) {
+			readb(base + page);
+			index += 1;
+		}
+
+		while (len--) {
+			*buf++ = readb(base + page);
+			index += 1;
+		}
+	} else {
+		unsigned long base = (ec->easi
+			 ? &ec->resource[ECARD_RES_EASI]
+			 : &ec->resource[ECARD_RES_IOCSYNC])->start;
+		void __iomem *pbase = (void __iomem *)base;
+
+		if (!req->use_loader || !ec->loader) {
+			off *= 4;
+			while (len--) {
+				*buf++ = readb(pbase + off);
+				off += 4;
+			}
+		} else {
+			while(len--) {
+				/*
+				 * The following is required by some
+				 * expansion card loader programs.
+				 */
+				*(unsigned long *)0x108 = 0;
+				*buf++ = ecard_loader_read(off++, base,
+							   ec->loader);
+			}
+		}
+	}
+
+}
+
+static DECLARE_WAIT_QUEUE_HEAD(ecard_wait);
+static struct ecard_request *ecard_req;
+static DEFINE_MUTEX(ecard_mutex);
+
+/*
+ * Set up the expansion card daemon's page tables.
+ */
+static void ecard_init_pgtables(struct mm_struct *mm)
+{
+	struct vm_area_struct vma;
+
+	/* We want to set up the page tables for the following mapping:
+	 *  Virtual	Physical
+	 *  0x03000000	0x03000000
+	 *  0x03010000	unmapped
+	 *  0x03210000	0x03210000
+	 *  0x03400000	unmapped
+	 *  0x08000000	0x08000000
+	 *  0x10000000	unmapped
+	 *
+	 * FIXME: we don't follow this 100% yet.
+	 */
+	pgd_t *src_pgd, *dst_pgd;
+
+	src_pgd = pgd_offset(mm, (unsigned long)IO_BASE);
+	dst_pgd = pgd_offset(mm, IO_START);
+
+	memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE));
+
+	src_pgd = pgd_offset(mm, (unsigned long)EASI_BASE);
+	dst_pgd = pgd_offset(mm, EASI_START);
+
+	memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (EASI_SIZE / PGDIR_SIZE));
+
+	vma.vm_flags = VM_EXEC;
+	vma.vm_mm = mm;
+
+	flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE);
+	flush_tlb_range(&vma, EASI_START, EASI_START + EASI_SIZE);
+}
+
+static int ecard_init_mm(void)
+{
+	struct mm_struct * mm = mm_alloc();
+	struct mm_struct *active_mm = current->active_mm;
+
+	if (!mm)
+		return -ENOMEM;
+
+	current->mm = mm;
+	current->active_mm = mm;
+	activate_mm(active_mm, mm);
+	mmdrop(active_mm);
+	ecard_init_pgtables(mm);
+	return 0;
+}
+
+static int
+ecard_task(void * unused)
+{
+	/*
+	 * Allocate a mm.  We're not a lazy-TLB kernel task since we need
+	 * to set page table entries where the user space would be.  Note
+	 * that this also creates the page tables.  Failure is not an
+	 * option here.
+	 */
+	if (ecard_init_mm())
+		panic("kecardd: unable to alloc mm\n");
+
+	while (1) {
+		struct ecard_request *req;
+
+		wait_event_interruptible(ecard_wait, ecard_req != NULL);
+
+		req = xchg(&ecard_req, NULL);
+		if (req != NULL) {
+			req->fn(req);
+			complete(req->complete);
+		}
+	}
+}
+
+/*
+ * Wake the expansion card daemon to action our request.
+ *
+ * FIXME: The test here is not sufficient to detect if the
+ * kcardd is running.
+ */
+static void ecard_call(struct ecard_request *req)
+{
+	DECLARE_COMPLETION_ONSTACK(completion);
+
+	req->complete = &completion;
+
+	mutex_lock(&ecard_mutex);
+	ecard_req = req;
+	wake_up(&ecard_wait);
+
+	/*
+	 * Now wait for kecardd to run.
+	 */
+	wait_for_completion(&completion);
+	mutex_unlock(&ecard_mutex);
+}
+
+/* ======================= Mid-level card control ===================== */
+
+static void
+ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
+{
+	struct ecard_request req;
+
+	req.fn		= ecard_task_readbytes;
+	req.ec		= ec;
+	req.address	= off;
+	req.length	= len;
+	req.use_loader	= useld;
+	req.buffer	= addr;
+
+	ecard_call(&req);
+}
+
+int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
+{
+	struct ex_chunk_dir excd;
+	int index = 16;
+	int useld = 0;
+
+	if (!ec->cid.cd)
+		return 0;
+
+	while(1) {
+		ecard_readbytes(&excd, ec, index, 8, useld);
+		index += 8;
+		if (c_id(&excd) == 0) {
+			if (!useld && ec->loader) {
+				useld = 1;
+				index = 0;
+				continue;
+			}
+			return 0;
+		}
+		if (c_id(&excd) == 0xf0) { /* link */
+			index = c_start(&excd);
+			continue;
+		}
+		if (c_id(&excd) == 0x80) { /* loader */
+			if (!ec->loader) {
+				ec->loader = kmalloc(c_len(&excd),
+							       GFP_KERNEL);
+				if (ec->loader)
+					ecard_readbytes(ec->loader, ec,
+							(int)c_start(&excd),
+							c_len(&excd), useld);
+				else
+					return 0;
+			}
+			continue;
+		}
+		if (c_id(&excd) == id && num-- == 0)
+			break;
+	}
+
+	if (c_id(&excd) & 0x80) {
+		switch (c_id(&excd) & 0x70) {
+		case 0x70:
+			ecard_readbytes((unsigned char *)excd.d.string, ec,
+					(int)c_start(&excd), c_len(&excd),
+					useld);
+			break;
+		case 0x00:
+			break;
+		}
+	}
+	cd->start_offset = c_start(&excd);
+	memcpy(cd->d.string, excd.d.string, 256);
+	return 1;
+}
+
+/* ======================= Interrupt control ============================ */
+
+static void ecard_def_irq_enable(ecard_t *ec, int irqnr)
+{
+}
+
+static void ecard_def_irq_disable(ecard_t *ec, int irqnr)
+{
+}
+
+static int ecard_def_irq_pending(ecard_t *ec)
+{
+	return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask;
+}
+
+static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr)
+{
+	panic("ecard_def_fiq_enable called - impossible");
+}
+
+static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr)
+{
+	panic("ecard_def_fiq_disable called - impossible");
+}
+
+static int ecard_def_fiq_pending(ecard_t *ec)
+{
+	return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask;
+}
+
+static expansioncard_ops_t ecard_default_ops = {
+	ecard_def_irq_enable,
+	ecard_def_irq_disable,
+	ecard_def_irq_pending,
+	ecard_def_fiq_enable,
+	ecard_def_fiq_disable,
+	ecard_def_fiq_pending
+};
+
+/*
+ * Enable and disable interrupts from expansion cards.
+ * (interrupts are disabled for these functions).
+ *
+ * They are not meant to be called directly, but via enable/disable_irq.
+ */
+static void ecard_irq_unmask(struct irq_data *d)
+{
+	ecard_t *ec = irq_data_get_irq_chip_data(d);
+
+	if (ec) {
+		if (!ec->ops)
+			ec->ops = &ecard_default_ops;
+
+		if (ec->claimed && ec->ops->irqenable)
+			ec->ops->irqenable(ec, d->irq);
+		else
+			printk(KERN_ERR "ecard: rejecting request to "
+				"enable IRQs for %d\n", d->irq);
+	}
+}
+
+static void ecard_irq_mask(struct irq_data *d)
+{
+	ecard_t *ec = irq_data_get_irq_chip_data(d);
+
+	if (ec) {
+		if (!ec->ops)
+			ec->ops = &ecard_default_ops;
+
+		if (ec->ops && ec->ops->irqdisable)
+			ec->ops->irqdisable(ec, d->irq);
+	}
+}
+
+static struct irq_chip ecard_chip = {
+	.name		= "ECARD",
+	.irq_ack	= ecard_irq_mask,
+	.irq_mask	= ecard_irq_mask,
+	.irq_unmask	= ecard_irq_unmask,
+};
+
+void ecard_enablefiq(unsigned int fiqnr)
+{
+	ecard_t *ec = slot_to_ecard(fiqnr);
+
+	if (ec) {
+		if (!ec->ops)
+			ec->ops = &ecard_default_ops;
+
+		if (ec->claimed && ec->ops->fiqenable)
+			ec->ops->fiqenable(ec, fiqnr);
+		else
+			printk(KERN_ERR "ecard: rejecting request to "
+				"enable FIQs for %d\n", fiqnr);
+	}
+}
+
+void ecard_disablefiq(unsigned int fiqnr)
+{
+	ecard_t *ec = slot_to_ecard(fiqnr);
+
+	if (ec) {
+		if (!ec->ops)
+			ec->ops = &ecard_default_ops;
+
+		if (ec->ops->fiqdisable)
+			ec->ops->fiqdisable(ec, fiqnr);
+	}
+}
+
+static void ecard_dump_irq_state(void)
+{
+	ecard_t *ec;
+
+	printk("Expansion card IRQ state:\n");
+
+	for (ec = cards; ec; ec = ec->next) {
+		if (ec->slot_no == 8)
+			continue;
+
+		printk("  %d: %sclaimed, ",
+		       ec->slot_no, ec->claimed ? "" : "not ");
+
+		if (ec->ops && ec->ops->irqpending &&
+		    ec->ops != &ecard_default_ops)
+			printk("irq %spending\n",
+			       ec->ops->irqpending(ec) ? "" : "not ");
+		else
+			printk("irqaddr %p, mask = %02X, status = %02X\n",
+			       ec->irqaddr, ec->irqmask, readb(ec->irqaddr));
+	}
+}
+
+static void ecard_check_lockup(struct irq_desc *desc)
+{
+	static unsigned long last;
+	static int lockup;
+
+	/*
+	 * If the timer interrupt has not run since the last million
+	 * unrecognised expansion card interrupts, then there is
+	 * something seriously wrong.  Disable the expansion card
+	 * interrupts so at least we can continue.
+	 *
+	 * Maybe we ought to start a timer to re-enable them some time
+	 * later?
+	 */
+	if (last == jiffies) {
+		lockup += 1;
+		if (lockup > 1000000) {
+			printk(KERN_ERR "\nInterrupt lockup detected - "
+			       "disabling all expansion card interrupts\n");
+
+			desc->irq_data.chip->irq_mask(&desc->irq_data);
+			ecard_dump_irq_state();
+		}
+	} else
+		lockup = 0;
+
+	/*
+	 * If we did not recognise the source of this interrupt,
+	 * warn the user, but don't flood the user with these messages.
+	 */
+	if (!last || time_after(jiffies, last + 5*HZ)) {
+		last = jiffies;
+		printk(KERN_WARNING "Unrecognised interrupt from backplane\n");
+		ecard_dump_irq_state();
+	}
+}
+
+static void
+ecard_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	ecard_t *ec;
+	int called = 0;
+
+	desc->irq_data.chip->irq_mask(&desc->irq_data);
+	for (ec = cards; ec; ec = ec->next) {
+		int pending;
+
+		if (!ec->claimed || !ec->irq || ec->slot_no == 8)
+			continue;
+
+		if (ec->ops && ec->ops->irqpending)
+			pending = ec->ops->irqpending(ec);
+		else
+			pending = ecard_default_ops.irqpending(ec);
+
+		if (pending) {
+			generic_handle_irq(ec->irq);
+			called ++;
+		}
+	}
+	desc->irq_data.chip->irq_unmask(&desc->irq_data);
+
+	if (called == 0)
+		ecard_check_lockup(desc);
+}
+
+static void __iomem *__ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
+{
+	void __iomem *address = NULL;
+	int slot = ec->slot_no;
+
+	if (ec->slot_no == 8)
+		return ECARD_MEMC8_BASE;
+
+	ectcr &= ~(1 << slot);
+
+	switch (type) {
+	case ECARD_MEMC:
+		if (slot < 4)
+			address = ECARD_MEMC_BASE + (slot << 14);
+		break;
+
+	case ECARD_IOC:
+		if (slot < 4)
+			address = ECARD_IOC_BASE + (slot << 14);
+		else
+			address = ECARD_IOC4_BASE + ((slot - 4) << 14);
+		if (address)
+			address += speed << 19;
+		break;
+
+	case ECARD_EASI:
+		address = ECARD_EASI_BASE + (slot << 24);
+		if (speed == ECARD_FAST)
+			ectcr |= 1 << slot;
+		break;
+
+	default:
+		break;
+	}
+
+#ifdef IOMD_ECTCR
+	iomd_writeb(ectcr, IOMD_ECTCR);
+#endif
+	return address;
+}
+
+static int ecard_prints(struct seq_file *m, ecard_t *ec)
+{
+	seq_printf(m, "  %d: %s ", ec->slot_no, ec->easi ? "EASI" : "    ");
+
+	if (ec->cid.id == 0) {
+		struct in_chunk_dir incd;
+
+		seq_printf(m, "[%04X:%04X] ",
+			ec->cid.manufacturer, ec->cid.product);
+
+		if (!ec->card_desc && ec->cid.cd &&
+		    ecard_readchunk(&incd, ec, 0xf5, 0)) {
+			ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL);
+
+			if (ec->card_desc)
+				strcpy((char *)ec->card_desc, incd.d.string);
+		}
+
+		seq_printf(m, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*");
+	} else
+		seq_printf(m, "Simple card %d\n", ec->cid.id);
+
+	return 0;
+}
+
+static int ecard_devices_proc_show(struct seq_file *m, void *v)
+{
+	ecard_t *ec = cards;
+
+	while (ec) {
+		ecard_prints(m, ec);
+		ec = ec->next;
+	}
+	return 0;
+}
+
+static int ecard_devices_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ecard_devices_proc_show, NULL);
+}
+
+static const struct file_operations bus_ecard_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= ecard_devices_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static struct proc_dir_entry *proc_bus_ecard_dir = NULL;
+
+static void ecard_proc_init(void)
+{
+	proc_bus_ecard_dir = proc_mkdir("bus/ecard", NULL);
+	proc_create("devices", 0, proc_bus_ecard_dir, &bus_ecard_proc_fops);
+}
+
+#define ec_set_resource(ec,nr,st,sz)				\
+	do {							\
+		(ec)->resource[nr].name = dev_name(&ec->dev);	\
+		(ec)->resource[nr].start = st;			\
+		(ec)->resource[nr].end = (st) + (sz) - 1;	\
+		(ec)->resource[nr].flags = IORESOURCE_MEM;	\
+	} while (0)
+
+static void __init ecard_free_card(struct expansion_card *ec)
+{
+	int i;
+
+	for (i = 0; i < ECARD_NUM_RESOURCES; i++)
+		if (ec->resource[i].flags)
+			release_resource(&ec->resource[i]);
+
+	kfree(ec);
+}
+
+static struct expansion_card *__init ecard_alloc_card(int type, int slot)
+{
+	struct expansion_card *ec;
+	unsigned long base;
+	int i;
+
+	ec = kzalloc(sizeof(ecard_t), GFP_KERNEL);
+	if (!ec) {
+		ec = ERR_PTR(-ENOMEM);
+		goto nomem;
+	}
+
+	ec->slot_no = slot;
+	ec->easi = type == ECARD_EASI;
+	ec->irq = 0;
+	ec->fiq = 0;
+	ec->dma = NO_DMA;
+	ec->ops = &ecard_default_ops;
+
+	dev_set_name(&ec->dev, "ecard%d", slot);
+	ec->dev.parent = NULL;
+	ec->dev.bus = &ecard_bus_type;
+	ec->dev.dma_mask = &ec->dma_mask;
+	ec->dma_mask = (u64)0xffffffff;
+	ec->dev.coherent_dma_mask = ec->dma_mask;
+
+	if (slot < 4) {
+		ec_set_resource(ec, ECARD_RES_MEMC,
+				PODSLOT_MEMC_BASE + (slot << 14),
+				PODSLOT_MEMC_SIZE);
+		base = PODSLOT_IOC0_BASE + (slot << 14);
+	} else
+		base = PODSLOT_IOC4_BASE + ((slot - 4) << 14);
+
+#ifdef CONFIG_ARCH_RPC
+	if (slot < 8) {
+		ec_set_resource(ec, ECARD_RES_EASI,
+				PODSLOT_EASI_BASE + (slot << 24),
+				PODSLOT_EASI_SIZE);
+	}
+
+	if (slot == 8) {
+		ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE);
+	} else
+#endif
+
+	for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++)
+		ec_set_resource(ec, i + ECARD_RES_IOCSLOW,
+				base + (i << 19), PODSLOT_IOC_SIZE);
+
+	for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
+		if (ec->resource[i].flags &&
+		    request_resource(&iomem_resource, &ec->resource[i])) {
+			dev_err(&ec->dev, "resource(s) not available\n");
+			ec->resource[i].end -= ec->resource[i].start;
+			ec->resource[i].start = 0;
+			ec->resource[i].flags = 0;
+		}
+	}
+
+ nomem:
+	return ec;
+}
+
+static ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	return sprintf(buf, "%u\n", ec->irq);
+}
+
+static ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	return sprintf(buf, "%u\n", ec->dma);
+}
+
+static ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	char *str = buf;
+	int i;
+
+	for (i = 0; i < ECARD_NUM_RESOURCES; i++)
+		str += sprintf(str, "%08x %08x %08lx\n",
+				ec->resource[i].start,
+				ec->resource[i].end,
+				ec->resource[i].flags);
+
+	return str - buf;
+}
+
+static ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	return sprintf(buf, "%u\n", ec->cid.manufacturer);
+}
+
+static ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	return sprintf(buf, "%u\n", ec->cid.product);
+}
+
+static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC");
+}
+
+static struct device_attribute ecard_dev_attrs[] = {
+	__ATTR(device,   S_IRUGO, ecard_show_device,    NULL),
+	__ATTR(dma,      S_IRUGO, ecard_show_dma,       NULL),
+	__ATTR(irq,      S_IRUGO, ecard_show_irq,       NULL),
+	__ATTR(resource, S_IRUGO, ecard_show_resources, NULL),
+	__ATTR(type,     S_IRUGO, ecard_show_type,      NULL),
+	__ATTR(vendor,   S_IRUGO, ecard_show_vendor,    NULL),
+	__ATTR_NULL,
+};
+
+
+int ecard_request_resources(struct expansion_card *ec)
+{
+	int i, err = 0;
+
+	for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
+		if (ecard_resource_end(ec, i) &&
+		    !request_mem_region(ecard_resource_start(ec, i),
+					ecard_resource_len(ec, i),
+					ec->dev.driver->name)) {
+			err = -EBUSY;
+			break;
+		}
+	}
+
+	if (err) {
+		while (i--)
+			if (ecard_resource_end(ec, i))
+				release_mem_region(ecard_resource_start(ec, i),
+						   ecard_resource_len(ec, i));
+	}
+	return err;
+}
+EXPORT_SYMBOL(ecard_request_resources);
+
+void ecard_release_resources(struct expansion_card *ec)
+{
+	int i;
+
+	for (i = 0; i < ECARD_NUM_RESOURCES; i++)
+		if (ecard_resource_end(ec, i))
+			release_mem_region(ecard_resource_start(ec, i),
+					   ecard_resource_len(ec, i));
+}
+EXPORT_SYMBOL(ecard_release_resources);
+
+void ecard_setirq(struct expansion_card *ec, const struct expansion_card_ops *ops, void *irq_data)
+{
+	ec->irq_data = irq_data;
+	barrier();
+	ec->ops = ops;
+}
+EXPORT_SYMBOL(ecard_setirq);
+
+void __iomem *ecardm_iomap(struct expansion_card *ec, unsigned int res,
+			   unsigned long offset, unsigned long maxsize)
+{
+	unsigned long start = ecard_resource_start(ec, res);
+	unsigned long end = ecard_resource_end(ec, res);
+
+	if (offset > (end - start))
+		return NULL;
+
+	start += offset;
+	if (maxsize && end - start > maxsize)
+		end = start + maxsize;
+	
+	return devm_ioremap(&ec->dev, start, end - start);
+}
+EXPORT_SYMBOL(ecardm_iomap);
+
+/*
+ * Probe for an expansion card.
+ *
+ * If bit 1 of the first byte of the card is set, then the
+ * card does not exist.
+ */
+static int __init ecard_probe(int slot, unsigned irq, card_type_t type)
+{
+	ecard_t **ecp;
+	ecard_t *ec;
+	struct ex_ecid cid;
+	void __iomem *addr;
+	int i, rc;
+
+	ec = ecard_alloc_card(type, slot);
+	if (IS_ERR(ec)) {
+		rc = PTR_ERR(ec);
+		goto nomem;
+	}
+
+	rc = -ENODEV;
+	if ((addr = __ecard_address(ec, type, ECARD_SYNC)) == NULL)
+		goto nodev;
+
+	cid.r_zero = 1;
+	ecard_readbytes(&cid, ec, 0, 16, 0);
+	if (cid.r_zero)
+		goto nodev;
+
+	ec->cid.id	= cid.r_id;
+	ec->cid.cd	= cid.r_cd;
+	ec->cid.is	= cid.r_is;
+	ec->cid.w	= cid.r_w;
+	ec->cid.manufacturer = ecard_getu16(cid.r_manu);
+	ec->cid.product = ecard_getu16(cid.r_prod);
+	ec->cid.country = cid.r_country;
+	ec->cid.irqmask = cid.r_irqmask;
+	ec->cid.irqoff  = ecard_gets24(cid.r_irqoff);
+	ec->cid.fiqmask = cid.r_fiqmask;
+	ec->cid.fiqoff  = ecard_gets24(cid.r_fiqoff);
+	ec->fiqaddr	=
+	ec->irqaddr	= addr;
+
+	if (ec->cid.is) {
+		ec->irqmask = ec->cid.irqmask;
+		ec->irqaddr += ec->cid.irqoff;
+		ec->fiqmask = ec->cid.fiqmask;
+		ec->fiqaddr += ec->cid.fiqoff;
+	} else {
+		ec->irqmask = 1;
+		ec->fiqmask = 4;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(blacklist); i++)
+		if (blacklist[i].manufacturer == ec->cid.manufacturer &&
+		    blacklist[i].product == ec->cid.product) {
+			ec->card_desc = blacklist[i].type;
+			break;
+		}
+
+	ec->irq = irq;
+
+	/*
+	 * hook the interrupt handlers
+	 */
+	if (slot < 8) {
+		irq_set_chip_and_handler(ec->irq, &ecard_chip,
+					 handle_level_irq);
+		irq_set_chip_data(ec->irq, ec);
+		set_irq_flags(ec->irq, IRQF_VALID);
+	}
+
+#ifdef CONFIG_ARCH_RPC
+	/* On RiscPC, only first two slots have DMA capability */
+	if (slot < 2)
+		ec->dma = 2 + slot;
+#endif
+
+	for (ecp = &cards; *ecp; ecp = &(*ecp)->next);
+
+	*ecp = ec;
+	slot_to_expcard[slot] = ec;
+
+	device_register(&ec->dev);
+
+	return 0;
+
+ nodev:
+	ecard_free_card(ec);
+ nomem:
+	return rc;
+}
+
+/*
+ * Initialise the expansion card system.
+ * Locate all hardware - interrupt management and
+ * actual cards.
+ */
+static int __init ecard_init(void)
+{
+	struct task_struct *task;
+	int slot, irqbase;
+
+	irqbase = irq_alloc_descs(-1, 0, 8, -1);
+	if (irqbase < 0)
+		return irqbase;
+
+	task = kthread_run(ecard_task, NULL, "kecardd");
+	if (IS_ERR(task)) {
+		printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n",
+		       PTR_ERR(task));
+		irq_free_descs(irqbase, 8);
+		return PTR_ERR(task);
+	}
+
+	printk("Probing expansion cards\n");
+
+	for (slot = 0; slot < 8; slot ++) {
+		if (ecard_probe(slot, irqbase + slot, ECARD_EASI) == -ENODEV)
+			ecard_probe(slot, irqbase + slot, ECARD_IOC);
+	}
+
+	ecard_probe(8, 11, ECARD_IOC);
+
+	irq_set_chained_handler(IRQ_EXPANSIONCARD, ecard_irq_handler);
+
+	ecard_proc_init();
+
+	return 0;
+}
+
+subsys_initcall(ecard_init);
+
+/*
+ *	ECARD "bus"
+ */
+static const struct ecard_id *
+ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec)
+{
+	int i;
+
+	for (i = 0; ids[i].manufacturer != 65535; i++)
+		if (ec->cid.manufacturer == ids[i].manufacturer &&
+		    ec->cid.product == ids[i].product)
+			return ids + i;
+
+	return NULL;
+}
+
+static int ecard_drv_probe(struct device *dev)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct ecard_driver *drv = ECARD_DRV(dev->driver);
+	const struct ecard_id *id;
+	int ret;
+
+	id = ecard_match_device(drv->id_table, ec);
+
+	ec->claimed = 1;
+	ret = drv->probe(ec, id);
+	if (ret)
+		ec->claimed = 0;
+	return ret;
+}
+
+static int ecard_drv_remove(struct device *dev)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct ecard_driver *drv = ECARD_DRV(dev->driver);
+
+	drv->remove(ec);
+	ec->claimed = 0;
+
+	/*
+	 * Restore the default operations.  We ensure that the
+	 * ops are set before we change the data.
+	 */
+	ec->ops = &ecard_default_ops;
+	barrier();
+	ec->irq_data = NULL;
+
+	return 0;
+}
+
+/*
+ * Before rebooting, we must make sure that the expansion card is in a
+ * sensible state, so it can be re-detected.  This means that the first
+ * page of the ROM must be visible.  We call the expansion cards reset
+ * handler, if any.
+ */
+static void ecard_drv_shutdown(struct device *dev)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct ecard_driver *drv = ECARD_DRV(dev->driver);
+	struct ecard_request req;
+
+	if (dev->driver) {
+		if (drv->shutdown)
+			drv->shutdown(ec);
+		ec->claimed = 0;
+	}
+
+	/*
+	 * If this card has a loader, call the reset handler.
+	 */
+	if (ec->loader) {
+		req.fn = ecard_task_reset;
+		req.ec = ec;
+		ecard_call(&req);
+	}
+}
+
+int ecard_register_driver(struct ecard_driver *drv)
+{
+	drv->drv.bus = &ecard_bus_type;
+
+	return driver_register(&drv->drv);
+}
+
+void ecard_remove_driver(struct ecard_driver *drv)
+{
+	driver_unregister(&drv->drv);
+}
+
+static int ecard_match(struct device *_dev, struct device_driver *_drv)
+{
+	struct expansion_card *ec = ECARD_DEV(_dev);
+	struct ecard_driver *drv = ECARD_DRV(_drv);
+	int ret;
+
+	if (drv->id_table) {
+		ret = ecard_match_device(drv->id_table, ec) != NULL;
+	} else {
+		ret = ec->cid.id == drv->id;
+	}
+
+	return ret;
+}
+
+struct bus_type ecard_bus_type = {
+	.name		= "ecard",
+	.dev_attrs	= ecard_dev_attrs,
+	.match		= ecard_match,
+	.probe		= ecard_drv_probe,
+	.remove		= ecard_drv_remove,
+	.shutdown	= ecard_drv_shutdown,
+};
+
+static int ecard_bus_init(void)
+{
+	return bus_register(&ecard_bus_type);
+}
+
+postcore_initcall(ecard_bus_init);
+
+EXPORT_SYMBOL(ecard_readchunk);
+EXPORT_SYMBOL(ecard_register_driver);
+EXPORT_SYMBOL(ecard_remove_driver);
+EXPORT_SYMBOL(ecard_bus_type);
diff --git a/arch/arm/kernel/ecard.h b/arch/arm/mach-rpc/ecard.h
similarity index 100%
rename from arch/arm/kernel/ecard.h
rename to arch/arm/mach-rpc/ecard.h
diff --git a/arch/arm/mach-rpc/fiq.S b/arch/arm/mach-rpc/fiq.S
new file mode 100644
index 0000000..48ddd57
--- /dev/null
+++ b/arch/arm/mach-rpc/fiq.S
@@ -0,0 +1,16 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/hardware.h>
+#include <mach/entry-macro.S>
+
+	.text
+
+	.global	rpc_default_fiq_end
+ENTRY(rpc_default_fiq_start)
+	mov	r12, #ioc_base_high
+	.if	ioc_base_low
+	orr	r12, r12, #ioc_base_low
+	.endif
+	strb	r12, [r12, #0x38]	@ Disable FIQ register
+	subs	pc, lr, #4
+rpc_default_fiq_end:
diff --git a/arch/arm/mach-rpc/include/mach/entry-macro.S b/arch/arm/mach-rpc/include/mach/entry-macro.S
index 4e7e541..7178368 100644
--- a/arch/arm/mach-rpc/include/mach/entry-macro.S
+++ b/arch/arm/mach-rpc/include/mach/entry-macro.S
@@ -10,7 +10,3 @@
 	orr	\base, \base, #ioc_base_low
 	.endif
 	.endm
-
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
-
diff --git a/arch/arm/mach-rpc/include/mach/hardware.h b/arch/arm/mach-rpc/include/mach/hardware.h
index 050d63c..257166b 100644
--- a/arch/arm/mach-rpc/include/mach/hardware.h
+++ b/arch/arm/mach-rpc/include/mach/hardware.h
@@ -14,12 +14,6 @@
 
 #include <mach/memory.h>
 
-#ifndef __ASSEMBLY__
-#define IOMEM(x) ((void __iomem *)(unsigned long)(x))
-#else
-#define IOMEM(x) x
-#endif /* __ASSEMBLY__ */
-
 /*
  * What hardware must be present
  */
diff --git a/arch/arm/mach-rpc/include/mach/io.h b/arch/arm/mach-rpc/include/mach/io.h
index 695f4ed..707071a 100644
--- a/arch/arm/mach-rpc/include/mach/io.h
+++ b/arch/arm/mach-rpc/include/mach/io.h
@@ -28,9 +28,4 @@
  */
 #define __io(a)		(PCIO_BASE + ((a) << 2))
 
-/*
- * 1:1 mapping for ioremapped regions.
- */
-#define __mem_pci(x)	(x)
-
 #endif
diff --git a/arch/arm/mach-rpc/include/mach/irqs.h b/arch/arm/mach-rpc/include/mach/irqs.h
index 3d20374..6868e17 100644
--- a/arch/arm/mach-rpc/include/mach/irqs.h
+++ b/arch/arm/mach-rpc/include/mach/irqs.h
@@ -42,6 +42,4 @@
  */
 #define FIQ_START		64
 
-#define IRQ_TIMER		IRQ_TIMER0
-
 #define NR_IRQS			128
diff --git a/arch/arm/mach-rpc/include/mach/system.h b/arch/arm/mach-rpc/include/mach/system.h
deleted file mode 100644
index 359bab9..0000000
--- a/arch/arm/mach-rpc/include/mach/system.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- *  arch/arm/mach-rpc/include/mach/system.h
- *
- *  Copyright (C) 1996-1999 Russell King.
- *
- * 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.
- */
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
diff --git a/arch/arm/mach-rpc/irq.c b/arch/arm/mach-rpc/irq.c
index 2e1b530..cf0e669 100644
--- a/arch/arm/mach-rpc/irq.c
+++ b/arch/arm/mach-rpc/irq.c
@@ -5,6 +5,7 @@
 #include <asm/mach/irq.h>
 #include <asm/hardware/iomd.h>
 #include <asm/irq.h>
+#include <asm/fiq.h>
 
 static void iomd_ack_irq_a(struct irq_data *d)
 {
@@ -112,6 +113,8 @@
 	.irq_unmask	= iomd_unmask_irq_fiq,
 };
 
+extern unsigned char rpc_default_fiq_start, rpc_default_fiq_end;
+
 void __init rpc_init_irq(void)
 {
 	unsigned int irq, flags;
@@ -121,6 +124,9 @@
 	iomd_writeb(0, IOMD_FIQMASK);
 	iomd_writeb(0, IOMD_DMAMASK);
 
+	set_fiq_handler(&rpc_default_fiq_start,
+		&rpc_default_fiq_end - &rpc_default_fiq_start);
+
 	for (irq = 0; irq < NR_IRQS; irq++) {
 		flags = IRQF_VALID;
 
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index 3d44a59..f3fa259c 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -28,6 +28,7 @@
 #include <asm/page.h>
 #include <asm/domain.h>
 #include <asm/setup.h>
+#include <asm/system_misc.h>
 
 #include <asm/mach/map.h>
 #include <asm/mach/arch.h>
@@ -98,15 +99,9 @@
 }
 
 static struct resource acornfb_resources[] = {
-	{	/* VIDC */
-		.start		= 0x03400000,
-		.end		= 0x035fffff,
-		.flags		= IORESOURCE_MEM,
-	}, {
-		.start		= IRQ_VSYNCPULSE,
-		.end		= IRQ_VSYNCPULSE,
-		.flags		= IORESOURCE_IRQ,
-	},
+	/* VIDC */
+	DEFINE_RES_MEM(0x03400000, 0x00200000),
+	DEFINE_RES_IRQ(IRQ_VSYNCPULSE),
 };
 
 static struct platform_device acornfb_device = {
@@ -120,11 +115,7 @@
 };
 
 static struct resource iomd_resources[] = {
-	{
-		.start		= 0x03200000,
-		.end		= 0x0320ffff,
-		.flags		= IORESOURCE_MEM,
-	},
+	DEFINE_RES_MEM(0x03200000, 0x10000),
 };
 
 static struct platform_device iomd_device = {
@@ -134,18 +125,25 @@
 	.resource		= iomd_resources,
 };
 
+static struct resource iomd_kart_resources[] = {
+	DEFINE_RES_IRQ(IRQ_KEYBOARDRX),
+	DEFINE_RES_IRQ(IRQ_KEYBOARDTX),
+};
+
 static struct platform_device kbd_device = {
 	.name			= "kart",
 	.id			= -1,
 	.dev			= {
 		.parent 	= &iomd_device.dev,
 	},
+	.num_resources		= ARRAY_SIZE(iomd_kart_resources),
+	.resource		= iomd_kart_resources,
 };
 
 static struct plat_serial8250_port serial_platform_data[] = {
 	{
 		.mapbase	= 0x03010fe0,
-		.irq		= 10,
+		.irq		= IRQ_SERIALPORT,
 		.uartclk	= 1843200,
 		.regshift	= 2,
 		.iotype		= UPIO_MEM,
@@ -167,21 +165,9 @@
 };
 
 static struct resource pata_resources[] = {
-	[0] = {
-		.start		= 0x030107c0,
-		.end		= 0x030107df,
-		.flags		= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start		= 0x03010fd8,
-		.end		= 0x03010fdb,
-		.flags		= IORESOURCE_MEM,
-	},
-	[2] = {
-		.start		= IRQ_HARDDISK,
-		.end		= IRQ_HARDDISK,
-		.flags		= IORESOURCE_IRQ,
-	},
+	DEFINE_RES_MEM(0x030107c0, 0x20),
+	DEFINE_RES_MEM(0x03010fd8, 0x04),
+	DEFINE_RES_IRQ(IRQ_HARDDISK),
 };
 
 static struct platform_device pata_device = {
diff --git a/arch/arm/mach-rpc/time.c b/arch/arm/mach-rpc/time.c
new file mode 100644
index 0000000..581fca9
--- /dev/null
+++ b/arch/arm/mach-rpc/time.c
@@ -0,0 +1,95 @@
+/*
+ *  linux/arch/arm/common/time-acorn.c
+ *
+ *  Copyright (c) 1996-2000 Russell King.
+ *
+ * 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.
+ *
+ *  Changelog:
+ *   24-Sep-1996	RMK	Created
+ *   10-Oct-1996	RMK	Brought up to date with arch-sa110eval
+ *   04-Dec-1997	RMK	Updated for new arch/arm/time.c
+ *   13=Jun-2004	DS	Moved to arch/arm/common b/c shared w/CLPS7500
+ */
+#include <linux/timex.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/ioc.h>
+
+#include <asm/mach/time.h>
+
+unsigned long ioc_timer_gettimeoffset(void)
+{
+	unsigned int count1, count2, status;
+	long offset;
+
+	ioc_writeb (0, IOC_T0LATCH);
+	barrier ();
+	count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
+	barrier ();
+	status = ioc_readb(IOC_IRQREQA);
+	barrier ();
+	ioc_writeb (0, IOC_T0LATCH);
+	barrier ();
+	count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
+
+	offset = count2;
+	if (count2 < count1) {
+		/*
+		 * We have not had an interrupt between reading count1
+		 * and count2.
+		 */
+		if (status & (1 << 5))
+			offset -= LATCH;
+	} else if (count2 > count1) {
+		/*
+		 * We have just had another interrupt between reading
+		 * count1 and count2.
+		 */
+		offset -= LATCH;
+	}
+
+	offset = (LATCH - offset) * (tick_nsec / 1000);
+	return (offset + LATCH/2) / LATCH;
+}
+
+void __init ioctime_init(void)
+{
+	ioc_writeb(LATCH & 255, IOC_T0LTCHL);
+	ioc_writeb(LATCH >> 8, IOC_T0LTCHH);
+	ioc_writeb(0, IOC_T0GO);
+}
+
+static irqreturn_t
+ioc_timer_interrupt(int irq, void *dev_id)
+{
+	timer_tick();
+	return IRQ_HANDLED;
+}
+
+static struct irqaction ioc_timer_irq = {
+	.name		= "timer",
+	.flags		= IRQF_DISABLED,
+	.handler	= ioc_timer_interrupt
+};
+
+/*
+ * Set up timer interrupt.
+ */
+static void __init ioc_timer_init(void)
+{
+	ioctime_init();
+	setup_irq(IRQ_TIMER0, &ioc_timer_irq);
+}
+
+struct sys_timer ioc_timer = {
+	.init		= ioc_timer_init,
+	.offset		= ioc_timer_gettimeoffset,
+};
+
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index 5261a7e..68d89cb 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -2,42 +2,6 @@
 #
 # Licensed under GPLv2
 
-config CPU_S3C2410
-	bool
-	depends on ARCH_S3C2410
-	select CPU_ARM920T
-	select S3C2410_CLOCK
-	select CPU_LLSERIAL_S3C2410
-	select S3C2410_PM if PM
-	select S3C2410_CPUFREQ if CPU_FREQ_S3C24XX
-	help
-	  Support for S3C2410 and S3C2410A family from the S3C24XX line
-	  of Samsung Mobile CPUs.
-
-config CPU_S3C2410_DMA
-	bool
-	depends on S3C2410_DMA && (CPU_S3C2410 || CPU_S3C2442)
-	default y if CPU_S3C2410 || CPU_S3C2442
-	help
-	  DMA device selection for S3C2410 and compatible CPUs
-
-config S3C2410_PM
-	bool
-	help
-	  Power Management code common to S3C2410 and better
-
-config SIMTEC_NOR
-	bool
-	help
-	  Internal node to specify machine has simtec NOR mapping
-
-config MACH_BAST_IDE
-	bool
-	select HAVE_PATA_PLATFORM
-	help
-	  Internal node for machines with an BAST style IDE
-	  interface
-
 # cpu frequency scaling support
 
 config S3C2410_CPUFREQ
@@ -54,121 +18,3 @@
 	help
 	  Select the PLL table for the S3C2410
 
-menu "S3C2410 Machines"
-
-config ARCH_SMDK2410
-	bool "SMDK2410/A9M2410"
-	select CPU_S3C2410
-	select MACH_SMDK
-	help
-	   Say Y here if you are using the SMDK2410 or the derived module A9M2410
-           <http://www.fsforth.de>
-
-config ARCH_H1940
-	bool "IPAQ H1940"
-	select CPU_S3C2410
-	select PM_H1940 if PM
-	select S3C_DEV_USB_HOST
-	select S3C_DEV_NAND
-	select S3C2410_SETUP_TS
-	help
-	  Say Y here if you are using the HP IPAQ H1940
-
-config H1940BT
-        tristate "Control the state of H1940 bluetooth chip"
-        depends on ARCH_H1940
-        select RFKILL
-        help
-          This is a simple driver that is able to control
-          the state of built in bluetooth chip on h1940.
-
-config PM_H1940
-	bool
-	help
-	  Internal node for H1940 and related PM
-
-config MACH_N30
-	bool "Acer N30 family"
-	select CPU_S3C2410
-	select MACH_N35
-	select S3C_DEV_USB_HOST
-	select S3C_DEV_NAND
-	help
-	  Say Y here if you want suppt for the Acer N30, Acer N35,
-	  Navman PiN570, Yakumo AlphaX or Airis NC05 PDAs.
-
-config MACH_N35
-	bool
-	help
-	  Internal node in order to enable support for Acer N35 if Acer N30 is
-	  selected.
-
-config ARCH_BAST
-	bool "Simtec Electronics BAST (EB2410ITX)"
-	select CPU_S3C2410
-	select S3C2410_IOTIMING if S3C2410_CPUFREQ
-	select PM_SIMTEC if PM
-	select SIMTEC_NOR
-	select MACH_BAST_IDE
-	select S3C24XX_DCLK
-	select ISA
-	select S3C_DEV_HWMON
-	select S3C_DEV_USB_HOST
-	select S3C_DEV_NAND
-	help
-	  Say Y here if you are using the Simtec Electronics EB2410ITX
-	  development board (also known as BAST)
-
-config MACH_OTOM
- 	bool "NexVision OTOM Board"
- 	select CPU_S3C2410
-	select S3C_DEV_USB_HOST
-	select S3C_DEV_NAND
-	help
- 	  Say Y here if you are using the Nex Vision OTOM board
-
-config MACH_AML_M5900
-	bool "AML M5900 Series"
-	select CPU_S3C2410
-	select PM_SIMTEC if PM
-	select S3C_DEV_USB_HOST
-	help
-	   Say Y here if you are using the American Microsystems M5900 Series
-           <http://www.amltd.com>
-
-config BAST_PC104_IRQ
-	bool "BAST PC104 IRQ support"
-	depends on ARCH_BAST
-	default y
-	help
-	  Say Y	here to enable the PC104 IRQ routing on the
-	  Simtec BAST (EB2410ITX)
-
-config MACH_TCT_HAMMER
-	bool "TCT Hammer Board"
-	select CPU_S3C2410
-	select S3C_DEV_USB_HOST
-	help
-	   Say Y here if you are using the TinCanTools Hammer Board
-           <http://www.tincantools.com>
-
-config MACH_VR1000
-	bool "Thorcom VR1000"
-	select PM_SIMTEC if PM
-	select S3C24XX_DCLK
-	select SIMTEC_NOR
-	select MACH_BAST_IDE
-	select CPU_S3C2410
-	select S3C_DEV_USB_HOST
-	help
-	  Say Y here if you are using the Thorcom VR1000 board.
-
-config MACH_QT2410
-	bool "QT2410"
-	select CPU_S3C2410
-	select S3C_DEV_USB_HOST
-	select S3C_DEV_NAND
-	help
-	   Say Y here if you are using the Armzone QT2410
-
-endmenu
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index 782fd81..6b9a316 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -9,32 +9,6 @@
 obj-n				:=
 obj-				:=
 
-obj-$(CONFIG_CPU_S3C2410)	+= s3c2410.o
-obj-$(CONFIG_CPU_S3C2410_DMA)	+= dma.o
-obj-$(CONFIG_CPU_S3C2410_DMA)	+= dma.o
-obj-$(CONFIG_S3C2410_PM)	+= pm.o sleep.o
 obj-$(CONFIG_S3C2410_CPUFREQ)	+= cpu-freq.o
 obj-$(CONFIG_S3C2410_PLLTABLE)	+= pll.o
 
-# Machine support
-
-obj-$(CONFIG_ARCH_SMDK2410)	+= mach-smdk2410.o
-obj-$(CONFIG_ARCH_H1940)	+= mach-h1940.o
-obj-$(CONFIG_H1940BT)		+= h1940-bluetooth.o
-obj-$(CONFIG_PM_H1940)		+= pm-h1940.o
-obj-$(CONFIG_MACH_N30)		+= mach-n30.o
-obj-$(CONFIG_ARCH_BAST)		+= mach-bast.o usb-simtec.o
-obj-$(CONFIG_MACH_OTOM)		+= mach-otom.o
-obj-$(CONFIG_MACH_AML_M5900)	+= mach-amlm5900.o
-obj-$(CONFIG_BAST_PC104_IRQ)	+= bast-irq.o
-obj-$(CONFIG_MACH_TCT_HAMMER)	+= mach-tct_hammer.o
-obj-$(CONFIG_MACH_VR1000)	+= mach-vr1000.o usb-simtec.o
-obj-$(CONFIG_MACH_QT2410)	+= mach-qt2410.o
-
-# Common bits of machine support
-
-obj-$(CONFIG_SIMTEC_NOR)	+= nor-simtec.o
-
-# machine additions
-
-obj-$(CONFIG_MACH_BAST_IDE)	+= bast-ide.o
diff --git a/arch/arm/mach-s3c2410/common.h b/arch/arm/mach-s3c2410/common.h
deleted file mode 100644
index f65dc80..0000000
--- a/arch/arm/mach-s3c2410/common.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * Common Header for S3C2410 machines
- *
- * 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 __ARCH_ARM_MACH_S3C2410_COMMON_H
-#define __ARCH_ARM_MACH_S3C2410_COMMON_H
-
-void s3c2410_restart(char mode, const char *cmd);
-
-#endif /* __ARCH_ARM_MACH_S3C2410_COMMON_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/entry-macro.S b/arch/arm/mach-s3c2410/include/mach/entry-macro.S
deleted file mode 100644
index 473b3cd..0000000
--- a/arch/arm/mach-s3c2410/include/mach/entry-macro.S
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * arch/arm/mach-s3c2410/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for S3C2410-based platforms
- *
- * 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.
-*/
-
-/* We have a problem that the INTOFFSET register does not always
- * show one interrupt. Occasionally we get two interrupts through
- * the prioritiser, and this causes the INTOFFSET register to show
- * what looks like the logical-or of the two interrupt numbers.
- *
- * Thanks to Klaus, Shannon, et al for helping to debug this problem
-*/
-
-#define INTPND		(0x10)
-#define INTOFFSET	(0x14)
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-	.macro  get_irqnr_preamble, base, tmp
-	.endm
-
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
-
-	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
-
-		mov	\base, #S3C24XX_VA_IRQ
-
-		@@ try the interrupt offset register, since it is there
-
-		ldr	\irqstat, [ \base, #INTPND ]
-		teq	\irqstat, #0
-		beq	1002f
-		ldr	\irqnr, [ \base, #INTOFFSET ]
-		mov	\tmp, #1
-		tst	\irqstat, \tmp, lsl \irqnr
-		bne	1001f
-
-		@@ the number specified is not a valid irq, so try
-		@@ and work it out for ourselves
-
-		mov	\irqnr, #0		@@ start here
-
-		@@ work out which irq (if any) we got
-
-		movs	\tmp, \irqstat, lsl#16
-		addeq	\irqnr, \irqnr, #16
-		moveq	\irqstat, \irqstat, lsr#16
-		tst	\irqstat, #0xff
-		addeq	\irqnr, \irqnr, #8
-		moveq	\irqstat, \irqstat, lsr#8
-		tst	\irqstat, #0xf
-		addeq	\irqnr, \irqnr, #4
-		moveq	\irqstat, \irqstat, lsr#4
-		tst	\irqstat, #0x3
-		addeq	\irqnr, \irqnr, #2
-		moveq	\irqstat, \irqstat, lsr#2
-		tst	\irqstat, #0x1
-		addeq	\irqnr, \irqnr, #1
-
-		@@ we have the value
-1001:
-		adds	\irqnr, \irqnr, #IRQ_EINT0
-1002:
-		@@ exit here, Z flag unset if IRQ
-
-	.endm
-
-		/* currently don't need an disable_fiq macro */
-
-		.macro	disable_fiq
-		.endm
diff --git a/arch/arm/mach-s3c2410/include/mach/io.h b/arch/arm/mach-s3c2410/include/mach/io.h
deleted file mode 100644
index 118749f..0000000
--- a/arch/arm/mach-s3c2410/include/mach/io.h
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * arch/arm/mach-s3c2410/include/mach/io.h
- *  from arch/arm/mach-rpc/include/mach/io.h
- *
- * Copyright (C) 1997 Russell King
- *	     (C) 2003 Simtec Electronics
-*/
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#include <mach/hardware.h>
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-/*
- * We use two different types of addressing - PC style addresses, and ARM
- * addresses.  PC style accesses the PC hardware with the normal PC IO
- * addresses, eg 0x3f8 for serial#1.  ARM addresses are above A28
- * and are translated to the start of IO.  Note that all addresses are
- * not shifted left!
- */
-
-#define __PORT_PCIO(x)	((x) < (1<<28))
-
-#define PCIO_BASE	 (S3C24XX_VA_ISA_WORD)
-#define PCIO_BASE_b	 (S3C24XX_VA_ISA_BYTE)
-#define PCIO_BASE_w	 (S3C24XX_VA_ISA_WORD)
-#define PCIO_BASE_l	 (S3C24XX_VA_ISA_WORD)
-/*
- * Dynamic IO functions - let the compiler
- * optimize the expressions
- */
-
-#define DECLARE_DYN_OUT(sz,fnsuffix,instr) \
-static inline void __out##fnsuffix (unsigned int val, unsigned int port) \
-{ \
-	unsigned long temp;				      \
-	__asm__ __volatile__(				      \
-	"cmp	%2, #(1<<28)\n\t"			      \
-	"mov	%0, %2\n\t"				      \
-	"addcc	%0, %0, %3\n\t"				      \
-	"str" instr " %1, [%0, #0 ]	@ out" #fnsuffix      \
-	: "=&r" (temp)					      \
-	: "r" (val), "r" (port), "Ir" (PCIO_BASE_##fnsuffix)  \
-	: "cc");					      \
-}
-
-
-#define DECLARE_DYN_IN(sz,fnsuffix,instr)				\
-static inline unsigned sz __in##fnsuffix (unsigned int port)		\
-{									\
-	unsigned long temp, value;					\
-	__asm__ __volatile__(						\
-	"cmp	%2, #(1<<28)\n\t"					\
-	"mov	%0, %2\n\t"						\
-	"addcc	%0, %0, %3\n\t"						\
-	"ldr" instr "	%1, [%0, #0 ]	@ in" #fnsuffix		\
-	: "=&r" (temp), "=r" (value)					\
-	: "r" (port), "Ir" (PCIO_BASE_##fnsuffix)	\
-	: "cc");							\
-	return (unsigned sz)value;					\
-}
-
-static inline void __iomem *__ioaddr (unsigned long port)
-{
-	return __PORT_PCIO(port) ? (PCIO_BASE + port) : (void __iomem *)port;
-}
-
-#define DECLARE_IO(sz,fnsuffix,instr)	\
-	DECLARE_DYN_IN(sz,fnsuffix,instr) \
-	DECLARE_DYN_OUT(sz,fnsuffix,instr)
-
-DECLARE_IO(char,b,"b")
-DECLARE_IO(short,w,"h")
-DECLARE_IO(int,l,"")
-
-#undef DECLARE_IO
-#undef DECLARE_DYN_IN
-
-/*
- * Constant address IO functions
- *
- * These have to be macros for the 'J' constraint to work -
- * +/-4096 immediate operand.
- */
-#define __outbc(value,port)						\
-({									\
-	if (__PORT_PCIO((port)))					\
-		__asm__ __volatile__(					\
-		"strb	%0, [%1, %2]	@ outbc"			\
-		: : "r" (value), "r" (PCIO_BASE), "Jr" ((port)));	\
-	else								\
-		__asm__ __volatile__(					\
-		"strb	%0, [%1, #0]	@ outbc"			\
-		: : "r" (value), "r" ((port)));				\
-})
-
-#define __inbc(port)							\
-({									\
-	unsigned char result;						\
-	if (__PORT_PCIO((port)))					\
-		__asm__ __volatile__(					\
-		"ldrb	%0, [%1, %2]	@ inbc"				\
-		: "=r" (result) : "r" (PCIO_BASE), "Jr" ((port)));	\
-	else								\
-		__asm__ __volatile__(					\
-		"ldrb	%0, [%1, #0]	@ inbc"				\
-		: "=r" (result) : "r" ((port)));			\
-	result;								\
-})
-
-#define __outwc(value,port)						\
-({									\
-	unsigned long v = value;					\
-	if (__PORT_PCIO((port))) {					\
-		if ((port) < 256 && (port) > -256)			\
-			__asm__ __volatile__(				\
-			"strh	%0, [%1, %2]	@ outwc"		\
-			: : "r" (v), "r" (PCIO_BASE), "Jr" ((port)));	\
-		else if ((port) > 0)					\
-			__asm__ __volatile__(				\
-			"strh	%0, [%1, %2]	@ outwc"		\
-			: : "r" (v),					\
-			    "r" (PCIO_BASE + ((port) & ~0xff)),		\
-			     "Jr" (((port) & 0xff)));			\
-		else							\
-			__asm__ __volatile__(				\
-			"strh	%0, [%1, #0]	@ outwc"		\
-			: : "r" (v),					\
-			    "r" (PCIO_BASE + (port)));			\
-	} else								\
-		__asm__ __volatile__(					\
-		"strh	%0, [%1, #0]	@ outwc"			\
-		: : "r" (v), "r" ((port)));				\
-})
-
-#define __inwc(port)							\
-({									\
-	unsigned short result;						\
-	if (__PORT_PCIO((port))) {					\
-		if ((port) < 256 && (port) > -256 )			\
-			__asm__ __volatile__(				\
-			"ldrh	%0, [%1, %2]	@ inwc"			\
-			: "=r" (result)					\
-			: "r" (PCIO_BASE),				\
-			  "Jr" ((port)));				\
-		else if ((port) > 0)					\
-			__asm__ __volatile__(				\
-			"ldrh	%0, [%1, %2]	@ inwc"			\
-			: "=r" (result)					\
-			: "r" (PCIO_BASE + ((port) & ~0xff)),		\
-			  "Jr" (((port) & 0xff)));			\
-		else							\
-			__asm__ __volatile__(				\
-			"ldrh	%0, [%1, #0]	@ inwc"			\
-			: "=r" (result)					\
-			: "r" (PCIO_BASE + ((port))));			\
-	} else								\
-		__asm__ __volatile__(					\
-		"ldrh	%0, [%1, #0]	@ inwc"				\
-		: "=r" (result) : "r" ((port)));			\
-	result;								\
-})
-
-#define __outlc(value,port)						\
-({									\
-	unsigned long v = value;					\
-	if (__PORT_PCIO((port)))					\
-		__asm__ __volatile__(					\
-		"str	%0, [%1, %2]	@ outlc"			\
-		: : "r" (v), "r" (PCIO_BASE), "Jr" ((port)));	\
-	else								\
-		__asm__ __volatile__(					\
-		"str	%0, [%1, #0]	@ outlc"			\
-		: : "r" (v), "r" ((port)));		\
-})
-
-#define __inlc(port)							\
-({									\
-	unsigned long result;						\
-	if (__PORT_PCIO((port)))					\
-		__asm__ __volatile__(					\
-		"ldr	%0, [%1, %2]	@ inlc"				\
-		: "=r" (result) : "r" (PCIO_BASE), "Jr" ((port)));	\
-	else								\
-		__asm__ __volatile__(					\
-		"ldr	%0, [%1, #0]	@ inlc"				\
-		: "=r" (result) : "r" ((port)));		\
-	result;								\
-})
-
-#define __ioaddrc(port)	((__PORT_PCIO(port) ? PCIO_BASE + (port) : (void __iomem *)(port)))
-
-#define inb(p)		(__builtin_constant_p((p)) ? __inbc(p)	   : __inb(p))
-#define inw(p)		(__builtin_constant_p((p)) ? __inwc(p)	   : __inw(p))
-#define inl(p)		(__builtin_constant_p((p)) ? __inlc(p)	   : __inl(p))
-#define outb(v,p)	(__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p))
-#define outw(v,p)	(__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p))
-#define outl(v,p)	(__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p))
-#define __ioaddr(p)	(__builtin_constant_p((p)) ? __ioaddr(p)  : __ioaddrc(p))
-
-#define insb(p,d,l)	__raw_readsb(__ioaddr(p),d,l)
-#define insw(p,d,l)	__raw_readsw(__ioaddr(p),d,l)
-#define insl(p,d,l)	__raw_readsl(__ioaddr(p),d,l)
-
-#define outsb(p,d,l)	__raw_writesb(__ioaddr(p),d,l)
-#define outsw(p,d,l)	__raw_writesw(__ioaddr(p),d,l)
-#define outsl(p,d,l)	__raw_writesl(__ioaddr(p),d,l)
-
-/*
- * 1:1 mapping for ioremapped regions.
- */
-#define __mem_pci(x)	(x)
-
-#endif
diff --git a/arch/arm/mach-s3c2410/include/mach/spi.h b/arch/arm/mach-s3c2410/include/mach/spi.h
deleted file mode 100644
index 4d95883..0000000
--- a/arch/arm/mach-s3c2410/include/mach/spi.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/spi.h
- *
- * Copyright (c) 2006 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 - SPI Controller platform_device info
- *
- * 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 __ASM_ARCH_SPI_H
-#define __ASM_ARCH_SPI_H __FILE__
-
-struct s3c2410_spi_info {
-	int			 pin_cs;	/* simple gpio cs */
-	unsigned int		 num_cs;	/* total chipselects */
-	int			 bus_num;       /* bus number to use. */
-
-	unsigned int		 use_fiq:1;	/* use fiq */
-
-	void (*gpio_setup)(struct s3c2410_spi_info *spi, int enable);
-	void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
-};
-
-/* Standard setup / suspend routines for SPI GPIO pins. */
-
-extern void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi,
-						 int enable);
-
-extern void s3c24xx_spi_gpiocfg_bus1_gpg5_6_7(struct s3c2410_spi_info *spi,
-					      int enable);
-
-extern void s3c24xx_spi_gpiocfg_bus1_gpd8_9_10(struct s3c2410_spi_info *spi,
-					       int enable);
-
-#endif /* __ASM_ARCH_SPI_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/system.h b/arch/arm/mach-s3c2410/include/mach/system.h
deleted file mode 100644
index 5e215c1..0000000
--- a/arch/arm/mach-s3c2410/include/mach/system.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/system.h
- *
- * Copyright (c) 2003 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 - System function defines and includes
- *
- * 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/io.h>
-#include <mach/hardware.h>
-
-#include <mach/map.h>
-#include <mach/idle.h>
-
-#include <mach/regs-clock.h>
-
-void (*s3c24xx_idle)(void);
-
-void s3c24xx_default_idle(void)
-{
-	unsigned long tmp;
-	int i;
-
-	/* idle the system by using the idle mode which will wait for an
-	 * interrupt to happen before restarting the system.
-	 */
-
-	/* Warning: going into idle state upsets jtag scanning */
-
-	__raw_writel(__raw_readl(S3C2410_CLKCON) | S3C2410_CLKCON_IDLE,
-		     S3C2410_CLKCON);
-
-	/* the samsung port seems to do a loop and then unset idle.. */
-	for (i = 0; i < 50; i++) {
-		tmp += __raw_readl(S3C2410_CLKCON); /* ensure loop not optimised out */
-	}
-
-	/* this bit is not cleared on re-start... */
-
-	__raw_writel(__raw_readl(S3C2410_CLKCON) & ~S3C2410_CLKCON_IDLE,
-		     S3C2410_CLKCON);
-}
-
-static void arch_idle(void)
-{
-	if (s3c24xx_idle != NULL)
-		(s3c24xx_idle)();
-	else
-		s3c24xx_default_idle();
-}
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
deleted file mode 100644
index feeaf73..0000000
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ /dev/null
@@ -1,645 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/mach-bast.c
- *
- * Copyright 2003-2008 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * http://www.simtec.co.uk/products/EB2410ITX/
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/syscore_ops.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/dm9000.h>
-#include <linux/ata_platform.h>
-#include <linux/i2c.h>
-#include <linux/io.h>
-
-#include <net/ax88796.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/bast-map.h>
-#include <mach/bast-irq.h>
-#include <mach/bast-cpld.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-//#include <asm/debug-ll.h>
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
-#include <mach/regs-lcd.h>
-
-#include <plat/hwmon.h>
-#include <plat/nand.h>
-#include <plat/iic.h>
-#include <mach/fb.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <linux/serial_8250.h>
-
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/cpu-freq.h>
-#include <plat/gpio-cfg.h>
-#include <plat/audio-simtec.h>
-
-#include "usb-simtec.h"
-#include "nor-simtec.h"
-#include "common.h"
-
-#define COPYRIGHT ", Copyright 2004-2008 Simtec Electronics"
-
-/* macros for virtual address mods for the io space entries */
-#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5)
-#define VA_C4(item) ((unsigned long)(item) + BAST_VAM_CS4)
-#define VA_C3(item) ((unsigned long)(item) + BAST_VAM_CS3)
-#define VA_C2(item) ((unsigned long)(item) + BAST_VAM_CS2)
-
-/* macros to modify the physical addresses for io space */
-
-#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2))
-#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3))
-#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4))
-#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5))
-
-static struct map_desc bast_iodesc[] __initdata = {
-  /* ISA IO areas */
-  {
-	  .virtual	= (u32)S3C24XX_VA_ISA_BYTE,
-	  .pfn		= PA_CS2(BAST_PA_ISAIO),
-	  .length	= SZ_16M,
-	  .type		= MT_DEVICE,
-  }, {
-	  .virtual	= (u32)S3C24XX_VA_ISA_WORD,
-	  .pfn		= PA_CS3(BAST_PA_ISAIO),
-	  .length	= SZ_16M,
-	  .type		= MT_DEVICE,
-  },
-  /* bast CPLD control registers, and external interrupt controls */
-  {
-	  .virtual	= (u32)BAST_VA_CTRL1,
-	  .pfn		= __phys_to_pfn(BAST_PA_CTRL1),
-	  .length	= SZ_1M,
-	  .type		= MT_DEVICE,
-  }, {
-	  .virtual	= (u32)BAST_VA_CTRL2,
-	  .pfn		= __phys_to_pfn(BAST_PA_CTRL2),
-	  .length	= SZ_1M,
-	  .type		= MT_DEVICE,
-  }, {
-	  .virtual	= (u32)BAST_VA_CTRL3,
-	  .pfn		= __phys_to_pfn(BAST_PA_CTRL3),
-	  .length	= SZ_1M,
-	  .type		= MT_DEVICE,
-  }, {
-	  .virtual	= (u32)BAST_VA_CTRL4,
-	  .pfn		= __phys_to_pfn(BAST_PA_CTRL4),
-	  .length	= SZ_1M,
-	  .type		= MT_DEVICE,
-  },
-  /* PC104 IRQ mux */
-  {
-	  .virtual	= (u32)BAST_VA_PC104_IRQREQ,
-	  .pfn		= __phys_to_pfn(BAST_PA_PC104_IRQREQ),
-	  .length	= SZ_1M,
-	  .type		= MT_DEVICE,
-  }, {
-	  .virtual	= (u32)BAST_VA_PC104_IRQRAW,
-	  .pfn		= __phys_to_pfn(BAST_PA_PC104_IRQRAW),
-	  .length	= SZ_1M,
-	  .type		= MT_DEVICE,
-  }, {
-	  .virtual	= (u32)BAST_VA_PC104_IRQMASK,
-	  .pfn		= __phys_to_pfn(BAST_PA_PC104_IRQMASK),
-	  .length	= SZ_1M,
-	  .type		= MT_DEVICE,
-  },
-
-  /* peripheral space... one for each of fast/slow/byte/16bit */
-  /* note, ide is only decoded in word space, even though some registers
-   * are only 8bit */
-
-  /* slow, byte */
-  { VA_C2(BAST_VA_ISAIO),   PA_CS2(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
-  { VA_C2(BAST_VA_ISAMEM),  PA_CS2(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
-  { VA_C2(BAST_VA_SUPERIO), PA_CS2(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
-
-  /* slow, word */
-  { VA_C3(BAST_VA_ISAIO),   PA_CS3(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
-  { VA_C3(BAST_VA_ISAMEM),  PA_CS3(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
-  { VA_C3(BAST_VA_SUPERIO), PA_CS3(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
-
-  /* fast, byte */
-  { VA_C4(BAST_VA_ISAIO),   PA_CS4(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
-  { VA_C4(BAST_VA_ISAMEM),  PA_CS4(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
-  { VA_C4(BAST_VA_SUPERIO), PA_CS4(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
-
-  /* fast, word */
-  { VA_C5(BAST_VA_ISAIO),   PA_CS5(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
-  { VA_C5(BAST_VA_ISAMEM),  PA_CS5(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
-  { VA_C5(BAST_VA_SUPERIO), PA_CS5(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
-};
-
-#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg bast_uartcfgs[] __initdata = {
-	[0] = {
-		.hwport	     = 0,
-		.flags	     = 0,
-		.ucon	     = UCON,
-		.ulcon	     = ULCON,
-		.ufcon	     = UFCON,
-	},
-	[1] = {
-		.hwport	     = 1,
-		.flags	     = 0,
-		.ucon	     = UCON,
-		.ulcon	     = ULCON,
-		.ufcon	     = UFCON,
-	},
-	/* port 2 is not actually used */
-	[2] = {
-		.hwport	     = 2,
-		.flags	     = 0,
-		.ucon	     = UCON,
-		.ulcon	     = ULCON,
-		.ufcon	     = UFCON,
-	}
-};
-
-/* NAND Flash on BAST board */
-
-#ifdef CONFIG_PM
-static int bast_pm_suspend(void)
-{
-	/* ensure that an nRESET is not generated on resume. */
-	gpio_direction_output(S3C2410_GPA(21), 1);
-	return 0;
-}
-
-static void bast_pm_resume(void)
-{
-	s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
-}
-
-#else
-#define bast_pm_suspend NULL
-#define bast_pm_resume NULL
-#endif
-
-static struct syscore_ops bast_pm_syscore_ops = {
-	.suspend	= bast_pm_suspend,
-	.resume		= bast_pm_resume,
-};
-
-static int smartmedia_map[] = { 0 };
-static int chip0_map[] = { 1 };
-static int chip1_map[] = { 2 };
-static int chip2_map[] = { 3 };
-
-static struct mtd_partition __initdata bast_default_nand_part[] = {
-	[0] = {
-		.name	= "Boot Agent",
-		.size	= SZ_16K,
-		.offset	= 0,
-	},
-	[1] = {
-		.name	= "/boot",
-		.size	= SZ_4M - SZ_16K,
-		.offset	= SZ_16K,
-	},
-	[2] = {
-		.name	= "user",
-		.offset	= SZ_4M,
-		.size	= MTDPART_SIZ_FULL,
-	}
-};
-
-/* the bast has 4 selectable slots for nand-flash, the three
- * on-board chip areas, as well as the external SmartMedia
- * slot.
- *
- * Note, there is no current hot-plug support for the SmartMedia
- * socket.
-*/
-
-static struct s3c2410_nand_set __initdata bast_nand_sets[] = {
-	[0] = {
-		.name		= "SmartMedia",
-		.nr_chips	= 1,
-		.nr_map		= smartmedia_map,
-		.options        = NAND_SCAN_SILENT_NODEV,
-		.nr_partitions	= ARRAY_SIZE(bast_default_nand_part),
-		.partitions	= bast_default_nand_part,
-	},
-	[1] = {
-		.name		= "chip0",
-		.nr_chips	= 1,
-		.nr_map		= chip0_map,
-		.nr_partitions	= ARRAY_SIZE(bast_default_nand_part),
-		.partitions	= bast_default_nand_part,
-	},
-	[2] = {
-		.name		= "chip1",
-		.nr_chips	= 1,
-		.nr_map		= chip1_map,
-		.options        = NAND_SCAN_SILENT_NODEV,
-		.nr_partitions	= ARRAY_SIZE(bast_default_nand_part),
-		.partitions	= bast_default_nand_part,
-	},
-	[3] = {
-		.name		= "chip2",
-		.nr_chips	= 1,
-		.nr_map		= chip2_map,
-		.options        = NAND_SCAN_SILENT_NODEV,
-		.nr_partitions	= ARRAY_SIZE(bast_default_nand_part),
-		.partitions	= bast_default_nand_part,
-	}
-};
-
-static void bast_nand_select(struct s3c2410_nand_set *set, int slot)
-{
-	unsigned int tmp;
-
-	slot = set->nr_map[slot] & 3;
-
-	pr_debug("bast_nand: selecting slot %d (set %p,%p)\n",
-		 slot, set, set->nr_map);
-
-	tmp = __raw_readb(BAST_VA_CTRL2);
-	tmp &= BAST_CPLD_CTLR2_IDERST;
-	tmp |= slot;
-	tmp |= BAST_CPLD_CTRL2_WNAND;
-
-	pr_debug("bast_nand: ctrl2 now %02x\n", tmp);
-
-	__raw_writeb(tmp, BAST_VA_CTRL2);
-}
-
-static struct s3c2410_platform_nand __initdata bast_nand_info = {
-	.tacls		= 30,
-	.twrph0		= 60,
-	.twrph1		= 60,
-	.nr_sets	= ARRAY_SIZE(bast_nand_sets),
-	.sets		= bast_nand_sets,
-	.select_chip	= bast_nand_select,
-};
-
-/* DM9000 */
-
-static struct resource bast_dm9k_resource[] = {
-	[0] = {
-		.start = S3C2410_CS5 + BAST_PA_DM9000,
-		.end   = S3C2410_CS5 + BAST_PA_DM9000 + 3,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = S3C2410_CS5 + BAST_PA_DM9000 + 0x40,
-		.end   = S3C2410_CS5 + BAST_PA_DM9000 + 0x40 + 0x3f,
-		.flags = IORESOURCE_MEM,
-	},
-	[2] = {
-		.start = IRQ_DM9000,
-		.end   = IRQ_DM9000,
-		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
-	}
-
-};
-
-/* for the moment we limit ourselves to 16bit IO until some
- * better IO routines can be written and tested
-*/
-
-static struct dm9000_plat_data bast_dm9k_platdata = {
-	.flags		= DM9000_PLATF_16BITONLY,
-};
-
-static struct platform_device bast_device_dm9k = {
-	.name		= "dm9000",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(bast_dm9k_resource),
-	.resource	= bast_dm9k_resource,
-	.dev		= {
-		.platform_data = &bast_dm9k_platdata,
-	}
-};
-
-/* serial devices */
-
-#define SERIAL_BASE  (S3C2410_CS2 + BAST_PA_SUPERIO)
-#define SERIAL_FLAGS (UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SHARE_IRQ)
-#define SERIAL_CLK   (1843200)
-
-static struct plat_serial8250_port bast_sio_data[] = {
-	[0] = {
-		.mapbase	= SERIAL_BASE + 0x2f8,
-		.irq		= IRQ_PCSERIAL1,
-		.flags		= SERIAL_FLAGS,
-		.iotype		= UPIO_MEM,
-		.regshift	= 0,
-		.uartclk	= SERIAL_CLK,
-	},
-	[1] = {
-		.mapbase	= SERIAL_BASE + 0x3f8,
-		.irq		= IRQ_PCSERIAL2,
-		.flags		= SERIAL_FLAGS,
-		.iotype		= UPIO_MEM,
-		.regshift	= 0,
-		.uartclk	= SERIAL_CLK,
-	},
-	{ }
-};
-
-static struct platform_device bast_sio = {
-	.name			= "serial8250",
-	.id			= PLAT8250_DEV_PLATFORM,
-	.dev			= {
-		.platform_data	= &bast_sio_data,
-	},
-};
-
-/* we have devices on the bus which cannot work much over the
- * standard 100KHz i2c bus frequency
-*/
-
-static struct s3c2410_platform_i2c __initdata bast_i2c_info = {
-	.flags		= 0,
-	.slave_addr	= 0x10,
-	.frequency	= 100*1000,
-};
-
-/* Asix AX88796 10/100 ethernet controller */
-
-static struct ax_plat_data bast_asix_platdata = {
-	.flags		= AXFLG_MAC_FROMDEV,
-	.wordlength	= 2,
-	.dcr_val	= 0x48,
-	.rcr_val	= 0x40,
-};
-
-static struct resource bast_asix_resource[] = {
-	[0] = {
-		.start = S3C2410_CS5 + BAST_PA_ASIXNET,
-		.end   = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20) - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20),
-		.end   = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20),
-		.flags = IORESOURCE_MEM,
-	},
-	[2] = {
-		.start = IRQ_ASIX,
-		.end   = IRQ_ASIX,
-		.flags = IORESOURCE_IRQ
-	}
-};
-
-static struct platform_device bast_device_asix = {
-	.name		= "ax88796",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(bast_asix_resource),
-	.resource	= bast_asix_resource,
-	.dev		= {
-		.platform_data = &bast_asix_platdata
-	}
-};
-
-/* Asix AX88796 10/100 ethernet controller parallel port */
-
-static struct resource bast_asixpp_resource[] = {
-	[0] = {
-		.start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20),
-		.end   = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1b * 0x20) - 1,
-		.flags = IORESOURCE_MEM,
-	}
-};
-
-static struct platform_device bast_device_axpp = {
-	.name		= "ax88796-pp",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(bast_asixpp_resource),
-	.resource	= bast_asixpp_resource,
-};
-
-/* LCD/VGA controller */
-
-static struct s3c2410fb_display __initdata bast_lcd_info[] = {
-	{
-		.type		= S3C2410_LCDCON1_TFT,
-		.width		= 640,
-		.height		= 480,
-
-		.pixclock	= 33333,
-		.xres		= 640,
-		.yres		= 480,
-		.bpp		= 4,
-		.left_margin	= 40,
-		.right_margin	= 20,
-		.hsync_len	= 88,
-		.upper_margin	= 30,
-		.lower_margin	= 32,
-		.vsync_len	= 3,
-
-		.lcdcon5	= 0x00014b02,
-	},
-	{
-		.type		= S3C2410_LCDCON1_TFT,
-		.width		= 640,
-		.height		= 480,
-
-		.pixclock	= 33333,
-		.xres		= 640,
-		.yres		= 480,
-		.bpp		= 8,
-		.left_margin	= 40,
-		.right_margin	= 20,
-		.hsync_len	= 88,
-		.upper_margin	= 30,
-		.lower_margin	= 32,
-		.vsync_len	= 3,
-
-		.lcdcon5	= 0x00014b02,
-	},
-	{
-		.type		= S3C2410_LCDCON1_TFT,
-		.width		= 640,
-		.height		= 480,
-
-		.pixclock	= 33333,
-		.xres		= 640,
-		.yres		= 480,
-		.bpp		= 16,
-		.left_margin	= 40,
-		.right_margin	= 20,
-		.hsync_len	= 88,
-		.upper_margin	= 30,
-		.lower_margin	= 32,
-		.vsync_len	= 3,
-
-		.lcdcon5	= 0x00014b02,
-	},
-};
-
-/* LCD/VGA controller */
-
-static struct s3c2410fb_mach_info __initdata bast_fb_info = {
-
-	.displays = bast_lcd_info,
-	.num_displays = ARRAY_SIZE(bast_lcd_info),
-	.default_display = 1,
-};
-
-/* I2C devices fitted. */
-
-static struct i2c_board_info bast_i2c_devs[] __initdata = {
-	{
-		I2C_BOARD_INFO("tlv320aic23", 0x1a),
-	}, {
-		I2C_BOARD_INFO("simtec-pmu", 0x6b),
-	}, {
-		I2C_BOARD_INFO("ch7013", 0x75),
-	},
-};
-
-static struct s3c_hwmon_pdata bast_hwmon_info = {
-	/* LCD contrast (0-6.6V) */
-	.in[0] = &(struct s3c_hwmon_chcfg) {
-		.name		= "lcd-contrast",
-		.mult		= 3300,
-		.div		= 512,
-	},
-	/* LED current feedback */
-	.in[1] = &(struct s3c_hwmon_chcfg) {
-		.name		= "led-feedback",
-		.mult		= 3300,
-		.div		= 1024,
-	},
-	/* LCD feedback (0-6.6V) */
-	.in[2] = &(struct s3c_hwmon_chcfg) {
-		.name		= "lcd-feedback",
-		.mult		= 3300,
-		.div		= 512,
-	},
-	/* Vcore (1.8-2.0V), Vref 3.3V  */
-	.in[3] = &(struct s3c_hwmon_chcfg) {
-		.name		= "vcore",
-		.mult		= 3300,
-		.div		= 1024,
-	},
-};
-
-/* Standard BAST devices */
-// cat /sys/devices/platform/s3c24xx-adc/s3c-hwmon/in_0
-
-static struct platform_device *bast_devices[] __initdata = {
-	&s3c_device_ohci,
-	&s3c_device_lcd,
-	&s3c_device_wdt,
-	&s3c_device_i2c0,
- 	&s3c_device_rtc,
-	&s3c_device_nand,
-	&s3c_device_adc,
-	&s3c_device_hwmon,
-	&bast_device_dm9k,
-	&bast_device_asix,
-	&bast_device_axpp,
-	&bast_sio,
-};
-
-static struct clk *bast_clocks[] __initdata = {
-	&s3c24xx_dclk0,
-	&s3c24xx_dclk1,
-	&s3c24xx_clkout0,
-	&s3c24xx_clkout1,
-	&s3c24xx_uclk,
-};
-
-static struct s3c_cpufreq_board __initdata bast_cpufreq = {
-	.refresh	= 7800, /* 7.8usec */
-	.auto_io	= 1,
-	.need_io	= 1,
-};
-
-static struct s3c24xx_audio_simtec_pdata __initdata bast_audio = {
-	.have_mic	= 1,
-	.have_lout	= 1,
-};
-
-static void __init bast_map_io(void)
-{
-	/* initialise the clocks */
-
-	s3c24xx_dclk0.parent = &clk_upll;
-	s3c24xx_dclk0.rate   = 12*1000*1000;
-
-	s3c24xx_dclk1.parent = &clk_upll;
-	s3c24xx_dclk1.rate   = 24*1000*1000;
-
-	s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
-	s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
-
-	s3c24xx_uclk.parent  = &s3c24xx_clkout1;
-
-	s3c24xx_register_clocks(bast_clocks, ARRAY_SIZE(bast_clocks));
-
-	s3c_hwmon_set_platdata(&bast_hwmon_info);
-
-	s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc));
-	s3c24xx_init_clocks(0);
-	s3c24xx_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs));
-}
-
-static void __init bast_init(void)
-{
-	register_syscore_ops(&bast_pm_syscore_ops);
-
-	s3c_i2c0_set_platdata(&bast_i2c_info);
-	s3c_nand_set_platdata(&bast_nand_info);
-	s3c24xx_fb_set_platdata(&bast_fb_info);
-	platform_add_devices(bast_devices, ARRAY_SIZE(bast_devices));
-
-	i2c_register_board_info(0, bast_i2c_devs,
-				ARRAY_SIZE(bast_i2c_devs));
-
-	usb_simtec_init();
-	nor_simtec_init();
-	simtec_audio_add(NULL, true, &bast_audio);
-
-	WARN_ON(gpio_request(S3C2410_GPA(21), "bast nreset"));
-	
-	s3c_cpufreq_setboard(&bast_cpufreq);
-}
-
-MACHINE_START(BAST, "Simtec-BAST")
-	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-	.atag_offset	= 0x100,
-	.map_io		= bast_map_io,
-	.init_irq	= s3c24xx_init_irq,
-	.init_machine	= bast_init,
-	.timer		= &s3c24xx_timer,
-	.restart	= s3c2410_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
deleted file mode 100644
index 41245a6..0000000
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ /dev/null
@@ -1,757 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/mach-h1940.c
- *
- * Copyright (c) 2003-2005 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * http://www.handhelds.org/projects/h1940.html
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/memblock.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/input.h>
-#include <linux/gpio_keys.h>
-#include <linux/pwm_backlight.h>
-#include <linux/i2c.h>
-#include <linux/leds.h>
-#include <linux/pda_power.h>
-#include <linux/s3c_adc_battery.h>
-#include <linux/delay.h>
-
-#include <video/platform_lcd.h>
-
-#include <linux/mmc/host.h>
-#include <linux/export.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-lcd.h>
-#include <mach/regs-clock.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/gpio-fns.h>
-#include <mach/gpio-nrs.h>
-
-#include <mach/h1940.h>
-#include <mach/h1940-latch.h>
-#include <mach/fb.h>
-#include <plat/udc.h>
-#include <plat/iic.h>
-
-#include <plat/gpio-cfg.h>
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/pll.h>
-#include <plat/pm.h>
-#include <plat/mci.h>
-#include <plat/ts.h>
-
-#include <sound/uda1380.h>
-
-#include "common.h"
-
-#define H1940_LATCH		((void __force __iomem *)0xF8000000)
-
-#define H1940_PA_LATCH		S3C2410_CS2
-
-#define H1940_LATCH_BIT(x)	(1 << ((x) + 16 - S3C_GPIO_END))
-
-static struct map_desc h1940_iodesc[] __initdata = {
-	[0] = {
-		.virtual	= (unsigned long)H1940_LATCH,
-		.pfn		= __phys_to_pfn(H1940_PA_LATCH),
-		.length		= SZ_16K,
-		.type		= MT_DEVICE
-	},
-};
-
-#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg h1940_uartcfgs[] __initdata = {
-	[0] = {
-		.hwport	     = 0,
-		.flags	     = 0,
-		.ucon	     = 0x3c5,
-		.ulcon	     = 0x03,
-		.ufcon	     = 0x51,
-	},
-	[1] = {
-		.hwport	     = 1,
-		.flags	     = 0,
-		.ucon	     = 0x245,
-		.ulcon	     = 0x03,
-		.ufcon	     = 0x00,
-	},
-	/* IR port */
-	[2] = {
-		.hwport	     = 2,
-		.flags	     = 0,
-		.uart_flags  = UPF_CONS_FLOW,
-		.ucon	     = 0x3c5,
-		.ulcon	     = 0x43,
-		.ufcon	     = 0x51,
-	}
-};
-
-/* Board control latch control */
-
-static unsigned int latch_state;
-
-static void h1940_latch_control(unsigned int clear, unsigned int set)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	latch_state &= ~clear;
-	latch_state |= set;
-
-	__raw_writel(latch_state, H1940_LATCH);
-
-	local_irq_restore(flags);
-}
-
-static inline int h1940_gpiolib_to_latch(int offset)
-{
-	return 1 << (offset + 16);
-}
-
-static void h1940_gpiolib_latch_set(struct gpio_chip *chip,
-					unsigned offset, int value)
-{
-	int latch_bit = h1940_gpiolib_to_latch(offset);
-
-	h1940_latch_control(value ? 0 : latch_bit,
-		value ? latch_bit : 0);
-}
-
-static int h1940_gpiolib_latch_output(struct gpio_chip *chip,
-					unsigned offset, int value)
-{
-	h1940_gpiolib_latch_set(chip, offset, value);
-	return 0;
-}
-
-static int h1940_gpiolib_latch_get(struct gpio_chip *chip,
-					unsigned offset)
-{
-	return (latch_state >> (offset + 16)) & 1;
-}
-
-struct gpio_chip h1940_latch_gpiochip = {
-	.base			= H1940_LATCH_GPIO(0),
-	.owner			= THIS_MODULE,
-	.label			= "H1940_LATCH",
-	.ngpio			= 16,
-	.direction_output	= h1940_gpiolib_latch_output,
-	.set			= h1940_gpiolib_latch_set,
-	.get			= h1940_gpiolib_latch_get,
-};
-
-static struct s3c2410_udc_mach_info h1940_udc_cfg __initdata = {
-	.vbus_pin		= S3C2410_GPG(5),
-	.vbus_pin_inverted	= 1,
-	.pullup_pin		= H1940_LATCH_USB_DP,
-};
-
-static struct s3c2410_ts_mach_info h1940_ts_cfg __initdata = {
-		.delay = 10000,
-		.presc = 49,
-		.oversampling_shift = 2,
-		.cfg_gpio = s3c24xx_ts_cfg_gpio,
-};
-
-/**
- * Set lcd on or off
- **/
-static struct s3c2410fb_display h1940_lcd __initdata = {
-	.lcdcon5=	S3C2410_LCDCON5_FRM565 | \
-			S3C2410_LCDCON5_INVVLINE | \
-			S3C2410_LCDCON5_HWSWP,
-
-	.type =		S3C2410_LCDCON1_TFT,
-	.width =	240,
-	.height =	320,
-	.pixclock =	260000,
-	.xres =		240,
-	.yres =		320,
-	.bpp =		16,
-	.left_margin =	8,
-	.right_margin =	20,
-	.hsync_len =	4,
-	.upper_margin =	8,
-	.lower_margin = 7,
-	.vsync_len =	1,
-};
-
-static struct s3c2410fb_mach_info h1940_fb_info __initdata = {
-	.displays = &h1940_lcd,
-	.num_displays = 1,
-	.default_display = 0,
-
-	.lpcsel =	0x02,
-	.gpccon =	0xaa940659,
-	.gpccon_mask =	0xffffc0f0,
-	.gpcup =	0x0000ffff,
-	.gpcup_mask =	0xffffffff,
-	.gpdcon =	0xaa84aaa0,
-	.gpdcon_mask =	0xffffffff,
-	.gpdup =	0x0000faff,
-	.gpdup_mask =	0xffffffff,
-};
-
-static int power_supply_init(struct device *dev)
-{
-	return gpio_request(S3C2410_GPF(2), "cable plugged");
-}
-
-static int h1940_is_ac_online(void)
-{
-	return !gpio_get_value(S3C2410_GPF(2));
-}
-
-static void power_supply_exit(struct device *dev)
-{
-	gpio_free(S3C2410_GPF(2));
-}
-
-static char *h1940_supplicants[] = {
-	"main-battery",
-	"backup-battery",
-};
-
-static struct pda_power_pdata power_supply_info = {
-	.init			= power_supply_init,
-	.is_ac_online		= h1940_is_ac_online,
-	.exit			= power_supply_exit,
-	.supplied_to		= h1940_supplicants,
-	.num_supplicants	= ARRAY_SIZE(h1940_supplicants),
-};
-
-static struct resource power_supply_resources[] = {
-	[0] = {
-			.name	= "ac",
-			.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE |
-					  IORESOURCE_IRQ_HIGHEDGE,
-			.start	= IRQ_EINT2,
-			.end	= IRQ_EINT2,
-	},
-};
-
-static struct platform_device power_supply = {
-	.name		= "pda-power",
-	.id		= -1,
-	.dev		= {
-				.platform_data =
-					&power_supply_info,
-	},
-	.resource	= power_supply_resources,
-	.num_resources	= ARRAY_SIZE(power_supply_resources),
-};
-
-static const struct s3c_adc_bat_thresh bat_lut_noac[] = {
-	{ .volt = 4070, .cur = 162, .level = 100},
-	{ .volt = 4040, .cur = 165, .level = 95},
-	{ .volt = 4016, .cur = 164, .level = 90},
-	{ .volt = 3996, .cur = 166, .level = 85},
-	{ .volt = 3971, .cur = 168, .level = 80},
-	{ .volt = 3951, .cur = 168, .level = 75},
-	{ .volt = 3931, .cur = 170, .level = 70},
-	{ .volt = 3903, .cur = 172, .level = 65},
-	{ .volt = 3886, .cur = 172, .level = 60},
-	{ .volt = 3858, .cur = 176, .level = 55},
-	{ .volt = 3842, .cur = 176, .level = 50},
-	{ .volt = 3818, .cur = 176, .level = 45},
-	{ .volt = 3789, .cur = 180, .level = 40},
-	{ .volt = 3769, .cur = 180, .level = 35},
-	{ .volt = 3749, .cur = 184, .level = 30},
-	{ .volt = 3732, .cur = 184, .level = 25},
-	{ .volt = 3716, .cur = 184, .level = 20},
-	{ .volt = 3708, .cur = 184, .level = 15},
-	{ .volt = 3716, .cur = 96, .level = 10},
-	{ .volt = 3700, .cur = 96, .level = 5},
-	{ .volt = 3684, .cur = 96, .level = 0},
-};
-
-static const struct s3c_adc_bat_thresh bat_lut_acin[] = {
-	{ .volt = 4130, .cur = 0, .level = 100},
-	{ .volt = 3982, .cur = 0, .level = 50},
-	{ .volt = 3854, .cur = 0, .level = 10},
-	{ .volt = 3841, .cur = 0, .level = 0},
-};
-
-int h1940_bat_init(void)
-{
-	int ret;
-
-	ret = gpio_request(H1940_LATCH_SM803_ENABLE, "h1940-charger-enable");
-	if (ret)
-		return ret;
-	gpio_direction_output(H1940_LATCH_SM803_ENABLE, 0);
-
-	return 0;
-
-}
-
-void h1940_bat_exit(void)
-{
-	gpio_free(H1940_LATCH_SM803_ENABLE);
-}
-
-void h1940_enable_charger(void)
-{
-	gpio_set_value(H1940_LATCH_SM803_ENABLE, 1);
-}
-
-void h1940_disable_charger(void)
-{
-	gpio_set_value(H1940_LATCH_SM803_ENABLE, 0);
-}
-
-static struct s3c_adc_bat_pdata h1940_bat_cfg = {
-	.init = h1940_bat_init,
-	.exit = h1940_bat_exit,
-	.enable_charger = h1940_enable_charger,
-	.disable_charger = h1940_disable_charger,
-	.gpio_charge_finished = S3C2410_GPF(3),
-	.gpio_inverted = 1,
-	.lut_noac = bat_lut_noac,
-	.lut_noac_cnt = ARRAY_SIZE(bat_lut_noac),
-	.lut_acin = bat_lut_acin,
-	.lut_acin_cnt = ARRAY_SIZE(bat_lut_acin),
-	.volt_channel = 0,
-	.current_channel = 1,
-	.volt_mult = 4056,
-	.current_mult = 1893,
-	.internal_impedance = 200,
-	.backup_volt_channel = 3,
-	/* TODO Check backup volt multiplier */
-	.backup_volt_mult = 4056,
-	.backup_volt_min = 0,
-	.backup_volt_max = 4149288
-};
-
-static struct platform_device h1940_battery = {
-	.name             = "s3c-adc-battery",
-	.id               = -1,
-	.dev = {
-		.parent = &s3c_device_adc.dev,
-		.platform_data = &h1940_bat_cfg,
-	},
-};
-
-DEFINE_SPINLOCK(h1940_blink_spin);
-
-int h1940_led_blink_set(unsigned gpio, int state,
-	unsigned long *delay_on, unsigned long *delay_off)
-{
-	int blink_gpio, check_gpio1, check_gpio2;
-
-	switch (gpio) {
-	case H1940_LATCH_LED_GREEN:
-		blink_gpio = S3C2410_GPA(7);
-		check_gpio1 = S3C2410_GPA(1);
-		check_gpio2 = S3C2410_GPA(3);
-		break;
-	case H1940_LATCH_LED_RED:
-		blink_gpio = S3C2410_GPA(1);
-		check_gpio1 = S3C2410_GPA(7);
-		check_gpio2 = S3C2410_GPA(3);
-		break;
-	default:
-		blink_gpio = S3C2410_GPA(3);
-		check_gpio1 = S3C2410_GPA(1);
-		check_gpio1 = S3C2410_GPA(7);
-		break;
-	}
-
-	if (delay_on && delay_off && !*delay_on && !*delay_off)
-		*delay_on = *delay_off = 500;
-
-	spin_lock(&h1940_blink_spin);
-
-	switch (state) {
-	case GPIO_LED_NO_BLINK_LOW:
-	case GPIO_LED_NO_BLINK_HIGH:
-		if (!gpio_get_value(check_gpio1) &&
-		    !gpio_get_value(check_gpio2))
-			gpio_set_value(H1940_LATCH_LED_FLASH, 0);
-		gpio_set_value(blink_gpio, 0);
-		if (gpio_is_valid(gpio))
-			gpio_set_value(gpio, state);
-		break;
-	case GPIO_LED_BLINK:
-		if (gpio_is_valid(gpio))
-			gpio_set_value(gpio, 0);
-		gpio_set_value(H1940_LATCH_LED_FLASH, 1);
-		gpio_set_value(blink_gpio, 1);
-		break;
-	}
-
-	spin_unlock(&h1940_blink_spin);
-
-	return 0;
-}
-EXPORT_SYMBOL(h1940_led_blink_set);
-
-static struct gpio_led h1940_leds_desc[] = {
-	{
-		.name			= "Green",
-		.default_trigger	= "main-battery-full",
-		.gpio			= H1940_LATCH_LED_GREEN,
-		.retain_state_suspended	= 1,
-	},
-	{
-		.name			= "Red",
-		.default_trigger
-			= "main-battery-charging-blink-full-solid",
-		.gpio			= H1940_LATCH_LED_RED,
-		.retain_state_suspended	= 1,
-	},
-};
-
-static struct gpio_led_platform_data h1940_leds_pdata = {
-	.num_leds	= ARRAY_SIZE(h1940_leds_desc),
-	.leds		= h1940_leds_desc,
-	.gpio_blink_set	= h1940_led_blink_set,
-};
-
-static struct platform_device h1940_device_leds = {
-	.name	= "leds-gpio",
-	.id	= -1,
-	.dev	= {
-			.platform_data = &h1940_leds_pdata,
-	},
-};
-
-static struct platform_device h1940_device_bluetooth = {
-	.name             = "h1940-bt",
-	.id               = -1,
-};
-
-static void h1940_set_mmc_power(unsigned char power_mode, unsigned short vdd)
-{
-	switch (power_mode) {
-	case MMC_POWER_OFF:
-		gpio_set_value(H1940_LATCH_SD_POWER, 0);
-		break;
-	case MMC_POWER_UP:
-	case MMC_POWER_ON:
-		gpio_set_value(H1940_LATCH_SD_POWER, 1);
-		break;
-	default:
-		break;
-	};
-}
-
-static struct s3c24xx_mci_pdata h1940_mmc_cfg __initdata = {
-	.gpio_detect   = S3C2410_GPF(5),
-	.gpio_wprotect = S3C2410_GPH(8),
-	.set_power     = h1940_set_mmc_power,
-	.ocr_avail     = MMC_VDD_32_33,
-};
-
-static int h1940_backlight_init(struct device *dev)
-{
-	gpio_request(S3C2410_GPB(0), "Backlight");
-
-	gpio_direction_output(S3C2410_GPB(0), 0);
-	s3c_gpio_setpull(S3C2410_GPB(0), S3C_GPIO_PULL_NONE);
-	s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
-	gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 1);
-
-	return 0;
-}
-
-static int h1940_backlight_notify(struct device *dev, int brightness)
-{
-	if (!brightness) {
-		gpio_direction_output(S3C2410_GPB(0), 1);
-		gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
-	} else {
-		gpio_direction_output(S3C2410_GPB(0), 0);
-		s3c_gpio_setpull(S3C2410_GPB(0), S3C_GPIO_PULL_NONE);
-		s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
-		gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 1);
-	}
-	return brightness;
-}
-
-static void h1940_backlight_exit(struct device *dev)
-{
-	gpio_direction_output(S3C2410_GPB(0), 1);
-	gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
-}
-
-
-static struct platform_pwm_backlight_data backlight_data = {
-	.pwm_id         = 0,
-	.max_brightness = 100,
-	.dft_brightness = 50,
-	/* tcnt = 0x31 */
-	.pwm_period_ns  = 36296,
-	.init           = h1940_backlight_init,
-	.notify		= h1940_backlight_notify,
-	.exit           = h1940_backlight_exit,
-};
-
-static struct platform_device h1940_backlight = {
-	.name = "pwm-backlight",
-	.dev  = {
-		.parent = &s3c_device_timer[0].dev,
-		.platform_data = &backlight_data,
-	},
-	.id   = -1,
-};
-
-static void h1940_lcd_power_set(struct plat_lcd_data *pd,
-					unsigned int power)
-{
-	int value, retries = 100;
-
-	if (!power) {
-		gpio_set_value(S3C2410_GPC(0), 0);
-		/* wait for 3ac */
-		do {
-			value = gpio_get_value(S3C2410_GPC(6));
-		} while (value && retries--);
-
-		gpio_set_value(H1940_LATCH_LCD_P2, 0);
-		gpio_set_value(H1940_LATCH_LCD_P3, 0);
-		gpio_set_value(H1940_LATCH_LCD_P4, 0);
-
-		gpio_direction_output(S3C2410_GPC(1), 0);
-		gpio_direction_output(S3C2410_GPC(4), 0);
-
-		gpio_set_value(H1940_LATCH_LCD_P1, 0);
-		gpio_set_value(H1940_LATCH_LCD_P0, 0);
-
-		gpio_set_value(S3C2410_GPC(5), 0);
-
-	} else {
-		gpio_set_value(H1940_LATCH_LCD_P0, 1);
-		gpio_set_value(H1940_LATCH_LCD_P1, 1);
-
-		gpio_direction_input(S3C2410_GPC(1));
-		gpio_direction_input(S3C2410_GPC(4));
-		mdelay(10);
-		s3c_gpio_cfgpin(S3C2410_GPC(1), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S3C2410_GPC(4), S3C_GPIO_SFN(2));
-
-		gpio_set_value(S3C2410_GPC(5), 1);
-		gpio_set_value(S3C2410_GPC(0), 1);
-
-		gpio_set_value(H1940_LATCH_LCD_P3, 1);
-		gpio_set_value(H1940_LATCH_LCD_P2, 1);
-		gpio_set_value(H1940_LATCH_LCD_P4, 1);
-	}
-}
-
-static struct plat_lcd_data h1940_lcd_power_data = {
-	.set_power      = h1940_lcd_power_set,
-};
-
-static struct platform_device h1940_lcd_powerdev = {
-	.name                   = "platform-lcd",
-	.dev.parent             = &s3c_device_lcd.dev,
-	.dev.platform_data      = &h1940_lcd_power_data,
-};
-
-static struct uda1380_platform_data uda1380_info = {
-	.gpio_power	= H1940_LATCH_UDA_POWER,
-	.gpio_reset	= S3C2410_GPA(12),
-	.dac_clk	= UDA1380_DAC_CLK_SYSCLK,
-};
-
-static struct i2c_board_info h1940_i2c_devices[] = {
-	{
-		I2C_BOARD_INFO("uda1380", 0x1a),
-		.platform_data = &uda1380_info,
-	},
-};
-
-#define DECLARE_BUTTON(p, k, n, w)	\
-	{				\
-		.gpio		= p,	\
-		.code		= k,	\
-		.desc		= n,	\
-		.wakeup		= w,	\
-		.active_low	= 1,	\
-	}
-
-static struct gpio_keys_button h1940_buttons[] = {
-	DECLARE_BUTTON(S3C2410_GPF(0),       KEY_POWER,          "Power", 1),
-	DECLARE_BUTTON(S3C2410_GPF(6),       KEY_ENTER,         "Select", 1),
-	DECLARE_BUTTON(S3C2410_GPF(7),      KEY_RECORD,         "Record", 0),
-	DECLARE_BUTTON(S3C2410_GPG(0),         KEY_F11,       "Calendar", 0),
-	DECLARE_BUTTON(S3C2410_GPG(2),         KEY_F12,       "Contacts", 0),
-	DECLARE_BUTTON(S3C2410_GPG(3),        KEY_MAIL,           "Mail", 0),
-	DECLARE_BUTTON(S3C2410_GPG(6),        KEY_LEFT,     "Left_arrow", 0),
-	DECLARE_BUTTON(S3C2410_GPG(7),    KEY_HOMEPAGE,           "Home", 0),
-	DECLARE_BUTTON(S3C2410_GPG(8),       KEY_RIGHT,    "Right_arrow", 0),
-	DECLARE_BUTTON(S3C2410_GPG(9),          KEY_UP,       "Up_arrow", 0),
-	DECLARE_BUTTON(S3C2410_GPG(10),       KEY_DOWN,     "Down_arrow", 0),
-};
-
-static struct gpio_keys_platform_data h1940_buttons_data = {
-	.buttons	= h1940_buttons,
-	.nbuttons	= ARRAY_SIZE(h1940_buttons),
-};
-
-static struct platform_device h1940_dev_buttons = {
-	.name		= "gpio-keys",
-	.id		= -1,
-	.dev		= {
-		.platform_data  = &h1940_buttons_data,
-	}
-};
-
-static struct platform_device *h1940_devices[] __initdata = {
-	&h1940_dev_buttons,
-	&s3c_device_ohci,
-	&s3c_device_lcd,
-	&s3c_device_wdt,
-	&s3c_device_i2c0,
-	&s3c_device_iis,
-	&samsung_asoc_dma,
-	&s3c_device_usbgadget,
-	&h1940_device_leds,
-	&h1940_device_bluetooth,
-	&s3c_device_sdi,
-	&s3c_device_rtc,
-	&s3c_device_timer[0],
-	&h1940_backlight,
-	&h1940_lcd_powerdev,
-	&s3c_device_adc,
-	&s3c_device_ts,
-	&power_supply,
-	&h1940_battery,
-};
-
-static void __init h1940_map_io(void)
-{
-	s3c24xx_init_io(h1940_iodesc, ARRAY_SIZE(h1940_iodesc));
-	s3c24xx_init_clocks(0);
-	s3c24xx_init_uarts(h1940_uartcfgs, ARRAY_SIZE(h1940_uartcfgs));
-
-	/* setup PM */
-
-#ifdef CONFIG_PM_H1940
-	memcpy(phys_to_virt(H1940_SUSPEND_RESUMEAT), h1940_pm_return, 1024);
-#endif
-	s3c_pm_init();
-
-	/* Add latch gpio chip, set latch initial value */
-	h1940_latch_control(0, 0);
-	WARN_ON(gpiochip_add(&h1940_latch_gpiochip));
-}
-
-/* H1940 and RX3715 need to reserve this for suspend */
-static void __init h1940_reserve(void)
-{
-	memblock_reserve(0x30003000, 0x1000);
-	memblock_reserve(0x30081000, 0x1000);
-}
-
-static void __init h1940_init_irq(void)
-{
-	s3c24xx_init_irq();
-}
-
-static void __init h1940_init(void)
-{
-	u32 tmp;
-
-	s3c24xx_fb_set_platdata(&h1940_fb_info);
-	s3c24xx_mci_set_platdata(&h1940_mmc_cfg);
- 	s3c24xx_udc_set_platdata(&h1940_udc_cfg);
-	s3c24xx_ts_set_platdata(&h1940_ts_cfg);
-	s3c_i2c0_set_platdata(NULL);
-
-	/* Turn off suspend on both USB ports, and switch the
-	 * selectable USB port to USB device mode. */
-
-	s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
-			      S3C2410_MISCCR_USBSUSPND0 |
-			      S3C2410_MISCCR_USBSUSPND1, 0x0);
-
-	tmp =   (0x78 << S3C24XX_PLL_MDIV_SHIFT)
-	      | (0x02 << S3C24XX_PLL_PDIV_SHIFT)
-	      | (0x03 << S3C24XX_PLL_SDIV_SHIFT);
-	writel(tmp, S3C2410_UPLLCON);
-
-	gpio_request(S3C2410_GPC(0), "LCD power");
-	gpio_request(S3C2410_GPC(1), "LCD power");
-	gpio_request(S3C2410_GPC(4), "LCD power");
-	gpio_request(S3C2410_GPC(5), "LCD power");
-	gpio_request(S3C2410_GPC(6), "LCD power");
-	gpio_request(H1940_LATCH_LCD_P0, "LCD power");
-	gpio_request(H1940_LATCH_LCD_P1, "LCD power");
-	gpio_request(H1940_LATCH_LCD_P2, "LCD power");
-	gpio_request(H1940_LATCH_LCD_P3, "LCD power");
-	gpio_request(H1940_LATCH_LCD_P4, "LCD power");
-	gpio_request(H1940_LATCH_MAX1698_nSHUTDOWN, "LCD power");
-	gpio_direction_output(S3C2410_GPC(0), 0);
-	gpio_direction_output(S3C2410_GPC(1), 0);
-	gpio_direction_output(S3C2410_GPC(4), 0);
-	gpio_direction_output(S3C2410_GPC(5), 0);
-	gpio_direction_input(S3C2410_GPC(6));
-	gpio_direction_output(H1940_LATCH_LCD_P0, 0);
-	gpio_direction_output(H1940_LATCH_LCD_P1, 0);
-	gpio_direction_output(H1940_LATCH_LCD_P2, 0);
-	gpio_direction_output(H1940_LATCH_LCD_P3, 0);
-	gpio_direction_output(H1940_LATCH_LCD_P4, 0);
-	gpio_direction_output(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
-
-	gpio_request(H1940_LATCH_SD_POWER, "SD power");
-	gpio_direction_output(H1940_LATCH_SD_POWER, 0);
-
-	platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));
-
-	gpio_request(S3C2410_GPA(1), "Red LED blink");
-	gpio_request(S3C2410_GPA(3), "Blue LED blink");
-	gpio_request(S3C2410_GPA(7), "Green LED blink");
-	gpio_request(H1940_LATCH_LED_FLASH, "LED blink");
-	gpio_direction_output(S3C2410_GPA(1), 0);
-	gpio_direction_output(S3C2410_GPA(3), 0);
-	gpio_direction_output(S3C2410_GPA(7), 0);
-	gpio_direction_output(H1940_LATCH_LED_FLASH, 0);
-
-	i2c_register_board_info(0, h1940_i2c_devices,
-		ARRAY_SIZE(h1940_i2c_devices));
-}
-
-MACHINE_START(H1940, "IPAQ-H1940")
-	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-	.atag_offset	= 0x100,
-	.map_io		= h1940_map_io,
-	.reserve	= h1940_reserve,
-	.init_irq	= h1940_init_irq,
-	.init_machine	= h1940_init,
-	.timer		= &s3c24xx_timer,
-	.restart	= s3c2410_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
deleted file mode 100644
index dbe668a..0000000
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ /dev/null
@@ -1,386 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/mach-vr1000.c
- *
- * Copyright (c) 2003-2008 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * Machine support for Thorcom VR1000 board. Designed for Thorcom by
- * Simtec Electronics, http://www.simtec.co.uk/
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/dm9000.h>
-#include <linux/i2c.h>
-
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_reg.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/bast-map.h>
-#include <mach/vr1000-map.h>
-#include <mach/vr1000-irq.h>
-#include <mach/vr1000-cpld.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/leds-gpio.h>
-
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/iic.h>
-#include <plat/audio-simtec.h>
-
-#include "usb-simtec.h"
-#include "nor-simtec.h"
-#include "common.h"
-
-/* macros for virtual address mods for the io space entries */
-#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5)
-#define VA_C4(item) ((unsigned long)(item) + BAST_VAM_CS4)
-#define VA_C3(item) ((unsigned long)(item) + BAST_VAM_CS3)
-#define VA_C2(item) ((unsigned long)(item) + BAST_VAM_CS2)
-
-/* macros to modify the physical addresses for io space */
-
-#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2))
-#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3))
-#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4))
-#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5))
-
-static struct map_desc vr1000_iodesc[] __initdata = {
-  /* ISA IO areas */
-  {
-	  .virtual	= (u32)S3C24XX_VA_ISA_BYTE,
-	  .pfn		= PA_CS2(BAST_PA_ISAIO),
-	  .length	= SZ_16M,
-	  .type		= MT_DEVICE,
-  }, {
-	  .virtual	= (u32)S3C24XX_VA_ISA_WORD,
-	  .pfn		= PA_CS3(BAST_PA_ISAIO),
-	  .length	= SZ_16M,
-	  .type		= MT_DEVICE,
-  },
-
-  /*  CPLD control registers, and external interrupt controls */
-  {
-	  .virtual	= (u32)VR1000_VA_CTRL1,
-	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL1),
-	  .length	= SZ_1M,
-	  .type		= MT_DEVICE,
-  }, {
-	  .virtual	= (u32)VR1000_VA_CTRL2,
-	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL2),
-	  .length	= SZ_1M,
-	  .type		= MT_DEVICE,
-  }, {
-	  .virtual	= (u32)VR1000_VA_CTRL3,
-	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL3),
-	  .length	= SZ_1M,
-	  .type		= MT_DEVICE,
-  }, {
-	  .virtual	= (u32)VR1000_VA_CTRL4,
-	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL4),
-	  .length	= SZ_1M,
-	  .type		= MT_DEVICE,
-  },
-};
-
-#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg vr1000_uartcfgs[] __initdata = {
-	[0] = {
-		.hwport	     = 0,
-		.flags	     = 0,
-		.ucon	     = UCON,
-		.ulcon	     = ULCON,
-		.ufcon	     = UFCON,
-	},
-	[1] = {
-		.hwport	     = 1,
-		.flags	     = 0,
-		.ucon	     = UCON,
-		.ulcon	     = ULCON,
-		.ufcon	     = UFCON,
-	},
-	/* port 2 is not actually used */
-	[2] = {
-		.hwport	     = 2,
-		.flags	     = 0,
-		.ucon	     = UCON,
-		.ulcon	     = ULCON,
-		.ufcon	     = UFCON,
-	}
-};
-
-/* definitions for the vr1000 extra 16550 serial ports */
-
-#define VR1000_BAUDBASE (3692307)
-
-#define VR1000_SERIAL_MAPBASE(x) (VR1000_PA_SERIAL + 0x80 + ((x) << 5))
-
-static struct plat_serial8250_port serial_platform_data[] = {
-	[0] = {
-		.mapbase	= VR1000_SERIAL_MAPBASE(0),
-		.irq		= IRQ_VR1000_SERIAL + 0,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
-		.iotype		= UPIO_MEM,
-		.regshift	= 0,
-		.uartclk	= VR1000_BAUDBASE,
-	},
-	[1] = {
-		.mapbase	= VR1000_SERIAL_MAPBASE(1),
-		.irq		= IRQ_VR1000_SERIAL + 1,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
-		.iotype		= UPIO_MEM,
-		.regshift	= 0,
-		.uartclk	= VR1000_BAUDBASE,
-	},
-	[2] = {
-		.mapbase	= VR1000_SERIAL_MAPBASE(2),
-		.irq		= IRQ_VR1000_SERIAL + 2,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
-		.iotype		= UPIO_MEM,
-		.regshift	= 0,
-		.uartclk	= VR1000_BAUDBASE,
-	},
-	[3] = {
-		.mapbase	= VR1000_SERIAL_MAPBASE(3),
-		.irq		= IRQ_VR1000_SERIAL + 3,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
-		.iotype		= UPIO_MEM,
-		.regshift	= 0,
-		.uartclk	= VR1000_BAUDBASE,
-	},
-	{ },
-};
-
-static struct platform_device serial_device = {
-	.name			= "serial8250",
-	.id			= PLAT8250_DEV_PLATFORM,
-	.dev			= {
-		.platform_data	= serial_platform_data,
-	},
-};
-
-/* DM9000 ethernet devices */
-
-static struct resource vr1000_dm9k0_resource[] = {
-	[0] = {
-		.start = S3C2410_CS5 + VR1000_PA_DM9000,
-		.end   = S3C2410_CS5 + VR1000_PA_DM9000 + 3,
-		.flags = IORESOURCE_MEM
-	},
-	[1] = {
-		.start = S3C2410_CS5 + VR1000_PA_DM9000 + 0x40,
-		.end   = S3C2410_CS5 + VR1000_PA_DM9000 + 0x7f,
-		.flags = IORESOURCE_MEM
-	},
-	[2] = {
-		.start = IRQ_VR1000_DM9000A,
-		.end   = IRQ_VR1000_DM9000A,
-		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
-	}
-
-};
-
-static struct resource vr1000_dm9k1_resource[] = {
-	[0] = {
-		.start = S3C2410_CS5 + VR1000_PA_DM9000 + 0x80,
-		.end   = S3C2410_CS5 + VR1000_PA_DM9000 + 0x83,
-		.flags = IORESOURCE_MEM
-	},
-	[1] = {
-		.start = S3C2410_CS5 + VR1000_PA_DM9000 + 0xC0,
-		.end   = S3C2410_CS5 + VR1000_PA_DM9000 + 0xFF,
-		.flags = IORESOURCE_MEM
-	},
-	[2] = {
-		.start = IRQ_VR1000_DM9000N,
-		.end   = IRQ_VR1000_DM9000N,
-		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
-	}
-};
-
-/* for the moment we limit ourselves to 16bit IO until some
- * better IO routines can be written and tested
-*/
-
-static struct dm9000_plat_data vr1000_dm9k_platdata = {
-	.flags		= DM9000_PLATF_16BITONLY,
-};
-
-static struct platform_device vr1000_dm9k0 = {
-	.name		= "dm9000",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(vr1000_dm9k0_resource),
-	.resource	= vr1000_dm9k0_resource,
-	.dev		= {
-		.platform_data = &vr1000_dm9k_platdata,
-	}
-};
-
-static struct platform_device vr1000_dm9k1 = {
-	.name		= "dm9000",
-	.id		= 1,
-	.num_resources	= ARRAY_SIZE(vr1000_dm9k1_resource),
-	.resource	= vr1000_dm9k1_resource,
-	.dev		= {
-		.platform_data = &vr1000_dm9k_platdata,
-	}
-};
-
-/* LEDS */
-
-static struct s3c24xx_led_platdata vr1000_led1_pdata = {
-	.name		= "led1",
-	.gpio		= S3C2410_GPB(0),
-	.def_trigger	= "",
-};
-
-static struct s3c24xx_led_platdata vr1000_led2_pdata = {
-	.name		= "led2",
-	.gpio		= S3C2410_GPB(1),
-	.def_trigger	= "",
-};
-
-static struct s3c24xx_led_platdata vr1000_led3_pdata = {
-	.name		= "led3",
-	.gpio		= S3C2410_GPB(2),
-	.def_trigger	= "",
-};
-
-static struct platform_device vr1000_led1 = {
-	.name		= "s3c24xx_led",
-	.id		= 1,
-	.dev		= {
-		.platform_data	= &vr1000_led1_pdata,
-	},
-};
-
-static struct platform_device vr1000_led2 = {
-	.name		= "s3c24xx_led",
-	.id		= 2,
-	.dev		= {
-		.platform_data	= &vr1000_led2_pdata,
-	},
-};
-
-static struct platform_device vr1000_led3 = {
-	.name		= "s3c24xx_led",
-	.id		= 3,
-	.dev		= {
-		.platform_data	= &vr1000_led3_pdata,
-	},
-};
-
-/* I2C devices. */
-
-static struct i2c_board_info vr1000_i2c_devs[] __initdata = {
-	{
-		I2C_BOARD_INFO("tlv320aic23", 0x1a),
-	}, {
-		I2C_BOARD_INFO("tmp101", 0x48),
-	}, {
-		I2C_BOARD_INFO("m41st87", 0x68),
-	},
-};
-
-/* devices for this board */
-
-static struct platform_device *vr1000_devices[] __initdata = {
-	&s3c_device_ohci,
-	&s3c_device_lcd,
-	&s3c_device_wdt,
-	&s3c_device_i2c0,
-	&s3c_device_adc,
-	&serial_device,
-	&vr1000_dm9k0,
-	&vr1000_dm9k1,
-	&vr1000_led1,
-	&vr1000_led2,
-	&vr1000_led3,
-};
-
-static struct clk *vr1000_clocks[] __initdata = {
-	&s3c24xx_dclk0,
-	&s3c24xx_dclk1,
-	&s3c24xx_clkout0,
-	&s3c24xx_clkout1,
-	&s3c24xx_uclk,
-};
-
-static void vr1000_power_off(void)
-{
-	gpio_direction_output(S3C2410_GPB(9), 1);
-}
-
-static void __init vr1000_map_io(void)
-{
-	/* initialise clock sources */
-
-	s3c24xx_dclk0.parent = &clk_upll;
-	s3c24xx_dclk0.rate   = 12*1000*1000;
-
-	s3c24xx_dclk1.parent = NULL;
-	s3c24xx_dclk1.rate   = 3692307;
-
-	s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
-	s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
-
-	s3c24xx_uclk.parent  = &s3c24xx_clkout1;
-
-	s3c24xx_register_clocks(vr1000_clocks, ARRAY_SIZE(vr1000_clocks));
-
-	pm_power_off = vr1000_power_off;
-
-	s3c24xx_init_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc));
-	s3c24xx_init_clocks(0);
-	s3c24xx_init_uarts(vr1000_uartcfgs, ARRAY_SIZE(vr1000_uartcfgs));
-}
-
-static void __init vr1000_init(void)
-{
-	s3c_i2c0_set_platdata(NULL);
-	platform_add_devices(vr1000_devices, ARRAY_SIZE(vr1000_devices));
-
-	i2c_register_board_info(0, vr1000_i2c_devs,
-				ARRAY_SIZE(vr1000_i2c_devs));
-
-	nor_simtec_init();
-	simtec_audio_add(NULL, true, NULL);
-
-	WARN_ON(gpio_request(S3C2410_GPB(9), "power off"));
-}
-
-MACHINE_START(VR1000, "Thorcom-VR1000")
-	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-	.atag_offset	= 0x100,
-	.map_io		= vr1000_map_io,
-	.init_machine	= vr1000_init,
-	.init_irq	= s3c24xx_init_irq,
-	.timer		= &s3c24xx_timer,
-	.restart	= s3c2410_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2410/nor-simtec.c b/arch/arm/mach-s3c2410/nor-simtec.c
deleted file mode 100644
index ad9f750..0000000
--- a/arch/arm/mach-s3c2410/nor-simtec.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/nor-simtec.c
- *
- * Copyright (c) 2008 Simtec Electronics
- *	http://armlinux.simtec.co.uk/
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * Simtec NOR mapping
- *
- * 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/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/physmap.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/map.h>
-#include <mach/bast-map.h>
-#include <mach/bast-cpld.h>
-
-#include "nor-simtec.h"
-
-static void simtec_nor_vpp(struct platform_device *pdev, int vpp)
-{
-	unsigned int val;
-	unsigned long flags;
-
-	local_irq_save(flags);
-	val = __raw_readb(BAST_VA_CTRL3);
-
-	printk(KERN_DEBUG "%s(%d)\n", __func__, vpp);
-
-	if (vpp)
-		val |= BAST_CPLD_CTRL3_ROMWEN;
-	else
-		val &= ~BAST_CPLD_CTRL3_ROMWEN;
-
-	__raw_writeb(val, BAST_VA_CTRL3);
-	local_irq_restore(flags);
-}
-
-static struct physmap_flash_data simtec_nor_pdata = {
-	.width		= 2,
-	.set_vpp	= simtec_nor_vpp,
-	.nr_parts	= 0,
-};
-
-static struct resource simtec_nor_resource[] = {
-	[0] = {
-		.start = S3C2410_CS1 + 0x4000000,
-		.end   = S3C2410_CS1 + 0x4000000 + SZ_8M - 1,
-		.flags = IORESOURCE_MEM,
-	}
-};
-
-static struct platform_device simtec_device_nor = {
-	.name		= "physmap-flash",
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(simtec_nor_resource),
-	.resource	= simtec_nor_resource,
-	.dev		= {
-		.platform_data = &simtec_nor_pdata,
-	},
-};
-
-void __init nor_simtec_init(void)
-{
-	int ret;
-
-	ret = platform_device_register(&simtec_device_nor);
-	if (ret < 0)
-		printk(KERN_ERR "failed to register physmap-flash device\n");
-	else
-		simtec_nor_vpp(NULL, 1);
-}
diff --git a/arch/arm/mach-s3c2410/nor-simtec.h b/arch/arm/mach-s3c2410/nor-simtec.h
deleted file mode 100644
index f619c1e..0000000
--- a/arch/arm/mach-s3c2410/nor-simtec.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/nor-simtec.h
- *
- * Copyright (c) 2008 Simtec Electronics
- *	http://armlinux.simtec.co.uk/
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * Simtec NOR mapping
- *
- * 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.
-*/
-
-extern void nor_simtec_init(void);
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
deleted file mode 100644
index 061b6bb..0000000
--- a/arch/arm/mach-s3c2410/s3c2410.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/s3c2410.c
- *
- * Copyright (c) 2003-2005 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * http://www.simtec.co.uk/products/EB2410ITX/
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/clk.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <plat/cpu-freq.h>
-
-#include <mach/regs-clock.h>
-#include <plat/regs-serial.h>
-
-#include <plat/s3c2410.h>
-#include <plat/cpu.h>
-#include <plat/devs.h>
-#include <plat/clock.h>
-#include <plat/pll.h>
-#include <plat/pm.h>
-#include <plat/watchdog-reset.h>
-
-#include <plat/gpio-core.h>
-#include <plat/gpio-cfg.h>
-#include <plat/gpio-cfg-helpers.h>
-
-/* Initial IO mappings */
-
-static struct map_desc s3c2410_iodesc[] __initdata = {
-	IODESC_ENT(CLKPWR),
-	IODESC_ENT(TIMER),
-	IODESC_ENT(WATCHDOG),
-};
-
-/* our uart devices */
-
-/* uart registration process */
-
-void __init s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-	s3c24xx_init_uartdevs("s3c2410-uart", s3c2410_uart_resources, cfg, no);
-}
-
-/* s3c2410_map_io
- *
- * register the standard cpu IO areas, and any passed in from the
- * machine specific initialisation.
-*/
-
-void __init s3c2410_map_io(void)
-{
-	s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1up;
-	s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1up;
-
-	iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc));
-}
-
-void __init_or_cpufreq s3c2410_setup_clocks(void)
-{
-	struct clk *xtal_clk;
-	unsigned long tmp;
-	unsigned long xtal;
-	unsigned long fclk;
-	unsigned long hclk;
-	unsigned long pclk;
-
-	xtal_clk = clk_get(NULL, "xtal");
-	xtal = clk_get_rate(xtal_clk);
-	clk_put(xtal_clk);
-
-	/* now we've got our machine bits initialised, work out what
-	 * clocks we've got */
-
-	fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);
-
-	tmp = __raw_readl(S3C2410_CLKDIVN);
-
-	/* work out clock scalings */
-
-	hclk = fclk / ((tmp & S3C2410_CLKDIVN_HDIVN) ? 2 : 1);
-	pclk = hclk / ((tmp & S3C2410_CLKDIVN_PDIVN) ? 2 : 1);
-
-	/* print brieft summary of clocks, etc */
-
-	printk("S3C2410: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
-	       print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
-
-	/* initialise the clocks here, to allow other things like the
-	 * console to use them
-	 */
-
-	s3c24xx_setup_clocks(fclk, hclk, pclk);
-}
-
-/* fake ARMCLK for use with cpufreq, etc. */
-
-static struct clk s3c2410_armclk = {
-	.name	= "armclk",
-	.parent	= &clk_f,
-	.id	= -1,
-};
-
-static struct clk_lookup s3c2410_clk_lookup[] = {
-	CLKDEV_INIT(NULL, "clk_uart_baud0", &clk_p),
-	CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
-};
-
-void __init s3c2410_init_clocks(int xtal)
-{
-	s3c24xx_register_baseclocks(xtal);
-	s3c2410_setup_clocks();
-	s3c2410_baseclk_add();
-	s3c24xx_register_clock(&s3c2410_armclk);
-	clkdev_add_table(s3c2410_clk_lookup, ARRAY_SIZE(s3c2410_clk_lookup));
-}
-
-struct bus_type s3c2410_subsys = {
-	.name = "s3c2410-core",
-	.dev_name = "s3c2410-core",
-};
-
-/* Note, we would have liked to name this s3c2410-core, but we cannot
- * register two subsystems with the same name.
- */
-struct bus_type s3c2410a_subsys = {
-	.name = "s3c2410a-core",
-	.dev_name = "s3c2410a-core",
-};
-
-static struct device s3c2410_dev = {
-	.bus		= &s3c2410_subsys,
-};
-
-/* need to register the subsystem before we actually register the device, and
- * we also need to ensure that it has been initialised before any of the
- * drivers even try to use it (even if not on an s3c2410 based system)
- * as a driver which may support both 2410 and 2440 may try and use it.
-*/
-
-static int __init s3c2410_core_init(void)
-{
-	return subsys_system_register(&s3c2410_subsys, NULL);
-}
-
-core_initcall(s3c2410_core_init);
-
-static int __init s3c2410a_core_init(void)
-{
-	return subsys_system_register(&s3c2410a_subsys, NULL);
-}
-
-core_initcall(s3c2410a_core_init);
-
-int __init s3c2410_init(void)
-{
-	printk("S3C2410: Initialising architecture\n");
-
-#ifdef CONFIG_PM
-	register_syscore_ops(&s3c2410_pm_syscore_ops);
-#endif
-	register_syscore_ops(&s3c24xx_irq_syscore_ops);
-
-	return device_register(&s3c2410_dev);
-}
-
-int __init s3c2410a_init(void)
-{
-	s3c2410_dev.bus = &s3c2410a_subsys;
-	return s3c2410_init();
-}
-
-void s3c2410_restart(char mode, const char *cmd)
-{
-	if (mode == 's') {
-		soft_restart(0);
-	}
-
-	arch_wdt_reset();
-
-	/* we'll take a jump through zero as a poor second */
-	soft_restart(0);
-}
diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c
deleted file mode 100644
index 29bd3d9..0000000
--- a/arch/arm/mach-s3c2410/usb-simtec.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/usb-simtec.c
- *
- * Copyright 2004-2005 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * http://www.simtec.co.uk/products/EB2410ITX/
- *
- * Simtec BAST and Thorcom VR1000 USB port support functions
- *
- * 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 DEBUG
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/gpio.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/bast-map.h>
-#include <mach/bast-irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <plat/usb-control.h>
-#include <plat/devs.h>
-
-#include "usb-simtec.h"
-
-/* control power and monitor over-current events on various Simtec
- * designed boards.
-*/
-
-static unsigned int power_state[2];
-
-static void
-usb_simtec_powercontrol(int port, int to)
-{
-	pr_debug("usb_simtec_powercontrol(%d,%d)\n", port, to);
-
-	power_state[port] = to;
-
-	if (power_state[0] && power_state[1])
-		gpio_set_value(S3C2410_GPB(4), 0);
-	else
-		gpio_set_value(S3C2410_GPB(4), 1);
-}
-
-static irqreturn_t
-usb_simtec_ocirq(int irq, void *pw)
-{
-	struct s3c2410_hcd_info *info = pw;
-
-	if (gpio_get_value(S3C2410_GPG(10)) == 0) {
-		pr_debug("usb_simtec: over-current irq (oc detected)\n");
-		s3c2410_usb_report_oc(info, 3);
-	} else {
-		pr_debug("usb_simtec: over-current irq (oc cleared)\n");
-		s3c2410_usb_report_oc(info, 0);
-	}
-
-	return IRQ_HANDLED;
-}
-
-static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on)
-{
-	int ret;
-
-	if (on) {
-		ret = request_irq(IRQ_USBOC, usb_simtec_ocirq,
-				  IRQF_DISABLED | IRQF_TRIGGER_RISING |
-				   IRQF_TRIGGER_FALLING,
-				  "USB Over-current", info);
-		if (ret != 0) {
-			printk(KERN_ERR "failed to request usb oc irq\n");
-		}
-	} else {
-		free_irq(IRQ_USBOC, info);
-	}
-}
-
-static struct s3c2410_hcd_info usb_simtec_info __initdata = {
-	.port[0]	= {
-		.flags	= S3C_HCDFLG_USED
-	},
-	.port[1]	= {
-		.flags	= S3C_HCDFLG_USED
-	},
-
-	.power_control	= usb_simtec_powercontrol,
-	.enable_oc	= usb_simtec_enableoc,
-};
-
-
-int usb_simtec_init(void)
-{
-	int ret;
-
-	printk("USB Power Control, Copyright 2004 Simtec Electronics\n");
-
-	ret = gpio_request(S3C2410_GPB(4), "USB power control");
-	if (ret < 0) {
-		pr_err("%s: failed to get GPB4\n", __func__);
-		return ret;
-	}
-
-	ret = gpio_request(S3C2410_GPG(10), "USB overcurrent");
-	if (ret < 0) {
-		pr_err("%s: failed to get GPG10\n", __func__);
-		gpio_free(S3C2410_GPB(4));
-		return ret;
-	}
-
-	/* turn power on */
-	gpio_direction_output(S3C2410_GPB(4), 1);
-	gpio_direction_input(S3C2410_GPG(10));
-
-	s3c_ohci_set_platdata(&usb_simtec_info);
-	return 0;
-}
diff --git a/arch/arm/mach-s3c2410/usb-simtec.h b/arch/arm/mach-s3c2410/usb-simtec.h
deleted file mode 100644
index 03842ed..0000000
--- a/arch/arm/mach-s3c2410/usb-simtec.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/usb-simtec.h
- *
- * Copyright (c) 2004 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * http://www.simtec.co.uk/products/EB2410ITX/
- *
- * Simtec BAST and Thorcom VR1000 USB port support functions
- *
- * 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.
-*/
-
-extern int usb_simtec_init(void);
-
diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig
index b8b9029..c5256f4 100644
--- a/arch/arm/mach-s3c2412/Kconfig
+++ b/arch/arm/mach-s3c2412/Kconfig
@@ -2,41 +2,6 @@
 #
 # Licensed under GPLv2
 
-config CPU_S3C2412
-	bool
-	depends on ARCH_S3C2410
-	select CPU_ARM926T
-	select CPU_LLSERIAL_S3C2440
-	select S3C2412_PM if PM
-	select S3C2412_DMA if S3C2410_DMA
-	help
-	  Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
-
-config CPU_S3C2412_ONLY
-	bool
-	depends on ARCH_S3C2410 && !CPU_S3C2410 && \
-		   !CPU_S3C2416 && !CPU_S3C2440 && !CPU_S3C2442 && \
-		   !CPU_S3C2443 && CPU_S3C2412
-	default y if CPU_S3C2412
-
-config S3C2412_DMA
-	bool
-	depends on CPU_S3C2412
-	help
-	  Internal config node for S3C2412 DMA support
-
-config S3C2412_PM
-	bool
-	select S3C2412_PM_SLEEP
-	help
-	  Internal config node to apply S3C2412 power management
-
-config S3C2412_PM_SLEEP
-	bool
-	help
-	  Internal config node to apply sleep for S3C2412 power management.
-	  Can be selected by another SoCs with similar sleep procedure.
-
 # Note, the S3C2412 IOtiming support is in plat-s3c24xx
 
 config S3C2412_CPUFREQ
@@ -46,53 +11,3 @@
 	default y
 	help
 	  CPU Frequency scaling support for S3C2412 and S3C2413 SoC CPUs.
-
-menu "S3C2412 Machines"
-
-config MACH_JIVE
-	bool "Logitech Jive"
-	select CPU_S3C2412
-	select S3C_DEV_USB_HOST
-	select S3C_DEV_NAND
-	help
-	  Say Y here if you are using the Logitech Jive.
-
-config MACH_JIVE_SHOW_BOOTLOADER
-	bool "Allow access to bootloader partitions in MTD (EXPERIMENTAL)"
-	depends on MACH_JIVE && EXPERIMENTAL
-
-config MACH_SMDK2413
-	bool "SMDK2413"
-	select CPU_S3C2412
-	select MACH_S3C2413
-	select MACH_SMDK
-	select S3C_DEV_USB_HOST
-	select S3C_DEV_NAND
-	help
-	  Say Y here if you are using an SMDK2413
-
-config MACH_S3C2413
-	bool
-	help
-	  Internal node for S3C2413 version of SMDK2413, so that
-	  machine_is_s3c2413() will work when MACH_SMDK2413 is
-	  selected
-
-config MACH_SMDK2412
-	bool "SMDK2412"
-	select MACH_SMDK2413
-	help
-	  Say Y here if you are using an SMDK2412
-
-	  Note, this shares support with SMDK2413, so will automatically
-	  select MACH_SMDK2413.
-
-config MACH_VSTMS
-	bool "VMSTMS"
-	select CPU_S3C2412
-	select S3C_DEV_USB_HOST
-	select S3C_DEV_NAND
-	help
-	  Say Y here if you are using an VSTMS board
-
-endmenu
diff --git a/arch/arm/mach-s3c2412/Makefile b/arch/arm/mach-s3c2412/Makefile
index 7e4d95f..41a6c27 100644
--- a/arch/arm/mach-s3c2412/Makefile
+++ b/arch/arm/mach-s3c2412/Makefile
@@ -9,16 +9,4 @@
 obj-n				:=
 obj-				:=
 
-obj-$(CONFIG_CPU_S3C2412)	+= s3c2412.o
-obj-$(CONFIG_CPU_S3C2412)	+= irq.o
-obj-$(CONFIG_CPU_S3C2412)	+= clock.o
-obj-$(CONFIG_S3C2412_DMA)	+= dma.o
-obj-$(CONFIG_S3C2412_PM)	+= pm.o
-obj-$(CONFIG_S3C2412_PM_SLEEP)	+= sleep.o
 obj-$(CONFIG_S3C2412_CPUFREQ)	+= cpu-freq.o
-
-# Machine support
-
-obj-$(CONFIG_MACH_JIVE)		+= mach-jive.o
-obj-$(CONFIG_MACH_SMDK2413)	+= mach-smdk2413.o
-obj-$(CONFIG_MACH_VSTMS)	+= mach-vstms.o
diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c
deleted file mode 100644
index aff6e85..0000000
--- a/arch/arm/mach-s3c2412/s3c2412.c
+++ /dev/null
@@ -1,253 +0,0 @@
-/* linux/arch/arm/mach-s3c2412/s3c2412.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * http://armlinux.simtec.co.uk/.
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/proc-fns.h>
-#include <asm/irq.h>
-
-#include <mach/idle.h>
-
-#include <plat/cpu-freq.h>
-
-#include <mach/regs-clock.h>
-#include <plat/regs-serial.h>
-#include <mach/regs-power.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-gpioj.h>
-#include <mach/regs-dsc.h>
-#include <plat/regs-spi.h>
-#include <mach/regs-s3c2412.h>
-
-#include <plat/s3c2412.h>
-#include <plat/cpu.h>
-#include <plat/devs.h>
-#include <plat/clock.h>
-#include <plat/pm.h>
-#include <plat/pll.h>
-#include <plat/nand-core.h>
-
-#ifndef CONFIG_CPU_S3C2412_ONLY
-void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
-
-static inline void s3c2412_init_gpio2(void)
-{
-	s3c24xx_va_gpio2 = S3C24XX_VA_GPIO + 0x10;
-}
-#else
-#define s3c2412_init_gpio2() do { } while(0)
-#endif
-
-/* Initial IO mappings */
-
-static struct map_desc s3c2412_iodesc[] __initdata = {
-	IODESC_ENT(CLKPWR),
-	IODESC_ENT(TIMER),
-	IODESC_ENT(WATCHDOG),
-	{
-		.virtual = (unsigned long)S3C2412_VA_SSMC,
-		.pfn	 = __phys_to_pfn(S3C2412_PA_SSMC),
-		.length	 = SZ_1M,
-		.type	 = MT_DEVICE,
-	},
-	{
-		.virtual = (unsigned long)S3C2412_VA_EBI,
-		.pfn	 = __phys_to_pfn(S3C2412_PA_EBI),
-		.length	 = SZ_1M,
-		.type	 = MT_DEVICE,
-	},
-};
-
-/* uart registration process */
-
-void __init s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-	s3c24xx_init_uartdevs("s3c2412-uart", s3c2410_uart_resources, cfg, no);
-
-	/* rename devices that are s3c2412/s3c2413 specific */
-	s3c_device_sdi.name  = "s3c2412-sdi";
-	s3c_device_lcd.name  = "s3c2412-lcd";
-	s3c_nand_setname("s3c2412-nand");
-
-	/* alter IRQ of SDI controller */
-
-	s3c_device_sdi.resource[1].start = IRQ_S3C2412_SDI;
-	s3c_device_sdi.resource[1].end   = IRQ_S3C2412_SDI;
-
-	/* spi channel related changes, s3c2412/13 specific */
-	s3c_device_spi0.name = "s3c2412-spi";
-	s3c_device_spi0.resource[0].end = S3C24XX_PA_SPI + 0x24;
-	s3c_device_spi1.name = "s3c2412-spi";
-	s3c_device_spi1.resource[0].start = S3C24XX_PA_SPI + S3C2412_SPI1;
-	s3c_device_spi1.resource[0].end = S3C24XX_PA_SPI + S3C2412_SPI1 + 0x24;
-
-}
-
-/* s3c2412_idle
- *
- * use the standard idle call by ensuring the idle mode
- * in power config, then issuing the idle co-processor
- * instruction
-*/
-
-static void s3c2412_idle(void)
-{
-	unsigned long tmp;
-
-	/* ensure our idle mode is to go to idle */
-
-	tmp = __raw_readl(S3C2412_PWRCFG);
-	tmp &= ~S3C2412_PWRCFG_STANDBYWFI_MASK;
-	tmp |= S3C2412_PWRCFG_STANDBYWFI_IDLE;
-	__raw_writel(tmp, S3C2412_PWRCFG);
-
-	cpu_do_idle();
-}
-
-void s3c2412_restart(char mode, const char *cmd)
-{
-	if (mode == 's')
-		soft_restart(0);
-
-	/* errata "Watch-dog/Software Reset Problem" specifies that
-	 * this reset must be done with the SYSCLK sourced from
-	 * EXTCLK instead of FOUT to avoid a glitch in the reset
-	 * mechanism.
-	 *
-	 * See the watchdog section of the S3C2412 manual for more
-	 * information on this fix.
-	 */
-
-	__raw_writel(0x00, S3C2412_CLKSRC);
-	__raw_writel(S3C2412_SWRST_RESET, S3C2412_SWRST);
-
-	mdelay(1);
-}
-
-/* s3c2412_map_io
- *
- * register the standard cpu IO areas, and any passed in from the
- * machine specific initialisation.
-*/
-
-void __init s3c2412_map_io(void)
-{
-	/* move base of IO */
-
-	s3c2412_init_gpio2();
-
-	/* set our idle function */
-
-	s3c24xx_idle = s3c2412_idle;
-
-	/* register our io-tables */
-
-	iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc));
-}
-
-void __init_or_cpufreq s3c2412_setup_clocks(void)
-{
-	struct clk *xtal_clk;
-	unsigned long tmp;
-	unsigned long xtal;
-	unsigned long fclk;
-	unsigned long hclk;
-	unsigned long pclk;
-
-	xtal_clk = clk_get(NULL, "xtal");
-	xtal = clk_get_rate(xtal_clk);
-	clk_put(xtal_clk);
-
-	/* now we've got our machine bits initialised, work out what
-	 * clocks we've got */
-
-	fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal * 2);
-
-	clk_mpll.rate = fclk;
-
-	tmp = __raw_readl(S3C2410_CLKDIVN);
-
-	/* work out clock scalings */
-
-	hclk = fclk / ((tmp & S3C2412_CLKDIVN_HDIVN_MASK) + 1);
-	hclk /= ((tmp & S3C2412_CLKDIVN_ARMDIVN) ? 2 : 1);
-	pclk = hclk / ((tmp & S3C2412_CLKDIVN_PDIVN) ? 2 : 1);
-
-	/* print brieft summary of clocks, etc */
-
-	printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
-	       print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
-
-	s3c24xx_setup_clocks(fclk, hclk, pclk);
-}
-
-void __init s3c2412_init_clocks(int xtal)
-{
-	/* initialise the clocks here, to allow other things like the
-	 * console to use them
-	 */
-
-	s3c24xx_register_baseclocks(xtal);
-	s3c2412_setup_clocks();
-	s3c2412_baseclk_add();
-}
-
-/* need to register the subsystem before we actually register the device, and
- * we also need to ensure that it has been initialised before any of the
- * drivers even try to use it (even if not on an s3c2412 based system)
- * as a driver which may support both 2410 and 2440 may try and use it.
-*/
-
-struct bus_type s3c2412_subsys = {
-	.name = "s3c2412-core",
-	.dev_name = "s3c2412-core",
-};
-
-static int __init s3c2412_core_init(void)
-{
-	return subsys_system_register(&s3c2412_subsys, NULL);
-}
-
-core_initcall(s3c2412_core_init);
-
-static struct device s3c2412_dev = {
-	.bus		= &s3c2412_subsys,
-};
-
-int __init s3c2412_init(void)
-{
-	printk("S3C2412: Initialising architecture\n");
-
-#ifdef CONFIG_PM
-	register_syscore_ops(&s3c2412_pm_syscore_ops);
-#endif
-	register_syscore_ops(&s3c24xx_irq_syscore_ops);
-
-	return device_register(&s3c2412_dev);
-}
diff --git a/arch/arm/mach-s3c2416/Kconfig b/arch/arm/mach-s3c2416/Kconfig
deleted file mode 100644
index 84c7b03..0000000
--- a/arch/arm/mach-s3c2416/Kconfig
+++ /dev/null
@@ -1,60 +0,0 @@
-# arch/arm/mach-s3c2416/Kconfig
-#
-# Copyright 2009 Yauhen Kharuzhy <jekhor@gmail.com>
-#
-# Licensed under GPLv2
-
-# note, this also supports the S3C2450 which is so similar it has the same
-# ID code as the S3C2416.
-
-config CPU_S3C2416
-	bool
-	depends on ARCH_S3C2410
-	select CPU_ARM926T
-	select S3C2416_DMA if S3C2410_DMA
-	select CPU_LLSERIAL_S3C2440
-	select SAMSUNG_CLKSRC
-	select S3C2443_CLOCK
-	help
-	  Support for the S3C2416 SoC from the S3C24XX line
-
-config S3C2416_DMA
-	bool
-	depends on CPU_S3C2416
-	help
-	  Internal config node for S3C2416 DMA support
-
-config S3C2416_PM
-	bool
-	select S3C2412_PM_SLEEP
-	help
-	  Internal config node to apply S3C2416 power management
-
-config S3C2416_SETUP_SDHCI
-	bool
-	select S3C2416_SETUP_SDHCI_GPIO
-	help
-	  Internal helper functions for S3C2416 based SDHCI systems
-
-config S3C2416_SETUP_SDHCI_GPIO
-	bool
-	help
-	  Common setup code for SDHCI gpio.
-
-menu "S3C2416 Machines"
-
-config MACH_SMDK2416
-	bool "SMDK2416"
-	select CPU_S3C2416
-	select MACH_SMDK
-	select S3C_DEV_FB
-	select S3C_DEV_HSMMC
-	select S3C_DEV_HSMMC1
-	select S3C_DEV_NAND
-	select S3C_DEV_USB_HOST
-	select S3C2416_SETUP_SDHCI
-	select S3C2416_PM if PM
-	help
-	  Say Y here if you are using an SMDK2416
-
-endmenu
diff --git a/arch/arm/mach-s3c2416/Makefile b/arch/arm/mach-s3c2416/Makefile
deleted file mode 100644
index ca0cd22..0000000
--- a/arch/arm/mach-s3c2416/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-# arch/arm/mach-s3c2416/Makefile
-#
-# Copyright 2009 Yauhen Kharuzhy <jekhor@gmail.com>
-#
-# Licensed under GPLv2
-
-obj-y				:=
-obj-m				:=
-obj-n				:=
-obj-				:=
-
-obj-$(CONFIG_CPU_S3C2416)	+= s3c2416.o clock.o
-obj-$(CONFIG_CPU_S3C2416)	+= irq.o
-obj-$(CONFIG_S3C2416_PM)	+= pm.o
-#obj-$(CONFIG_S3C2416_DMA)	+= dma.o
-
-# Device setup
-obj-$(CONFIG_S3C2416_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
-
-# Machine support
-
-obj-$(CONFIG_MACH_SMDK2416)	+= mach-smdk2416.o
diff --git a/arch/arm/mach-s3c2416/clock.c b/arch/arm/mach-s3c2416/clock.c
deleted file mode 100644
index 59f54d1..0000000
--- a/arch/arm/mach-s3c2416/clock.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/* linux/arch/arm/mach-s3c2416/clock.c
- *
- * Copyright (c) 2010 Simtec Electronics
- * Copyright (c) 2010 Ben Dooks <ben-linux@fluff.org>
- *
- * S3C2416 Clock control support
- *
- * 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/init.h>
-#include <linux/clk.h>
-
-#include <plat/s3c2416.h>
-#include <plat/s3c2443.h>
-#include <plat/clock.h>
-#include <plat/clock-clksrc.h>
-#include <plat/cpu.h>
-
-#include <plat/cpu-freq.h>
-#include <plat/pll.h>
-
-#include <asm/mach/map.h>
-
-#include <mach/regs-clock.h>
-#include <mach/regs-s3c2443-clock.h>
-
-/* armdiv
- *
- * this clock is sourced from msysclk and can have a number of
- * divider values applied to it to then be fed into armclk.
- * The real clock definition is done in s3c2443-clock.c,
- * only the armdiv divisor table must be defined here.
-*/
-
-static unsigned int armdiv[8] = {
-	[0] = 1,
-	[1] = 2,
-	[2] = 3,
-	[3] = 4,
-	[5] = 6,
-	[7] = 8,
-};
-
-static struct clksrc_clk hsspi_eplldiv = {
-	.clk = {
-		.name	= "hsspi-eplldiv",
-		.parent	= &clk_esysclk.clk,
-		.ctrlbit = (1 << 14),
-		.enable = s3c2443_clkcon_enable_s,
-	},
-	.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 24 },
-};
-
-static struct clk *hsspi_sources[] = {
-	[0] = &hsspi_eplldiv.clk,
-	[1] = NULL, /* to fix */
-};
-
-static struct clksrc_clk hsspi_mux = {
-	.clk	= {
-		.name	= "hsspi-if",
-	},
-	.sources = &(struct clksrc_sources) {
-		.sources = hsspi_sources,
-		.nr_sources = ARRAY_SIZE(hsspi_sources),
-	},
-	.reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 18 },
-};
-
-static struct clksrc_clk hsmmc_div[] = {
-	[0] = {
-		.clk = {
-			.name	= "hsmmc-div",
-			.devname	= "s3c-sdhci.0",
-			.parent	= &clk_esysclk.clk,
-		},
-		.reg_div = { .reg = S3C2416_CLKDIV2, .size = 2, .shift = 6 },
-	},
-	[1] = {
-		.clk = {
-			.name	= "hsmmc-div",
-			.devname	= "s3c-sdhci.1",
-			.parent	= &clk_esysclk.clk,
-		},
-		.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
-	},
-};
-
-static struct clksrc_clk hsmmc_mux0 = {
-	.clk	= {
-		.name		= "hsmmc-if",
-		.devname	= "s3c-sdhci.0",
-		.ctrlbit	= (1 << 6),
-		.enable		= s3c2443_clkcon_enable_s,
-	},
-	.sources	= &(struct clksrc_sources) {
-		.nr_sources	= 2,
-		.sources	= (struct clk * []) {
-			[0]	= &hsmmc_div[0].clk,
-			[1]	= NULL, /* to fix */
-		},
-	},
-	.reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 16 },
-};
-
-static struct clksrc_clk hsmmc_mux1 = {
-	.clk	= {
-		.name		= "hsmmc-if",
-		.devname	= "s3c-sdhci.1",
-		.ctrlbit	= (1 << 12),
-		.enable		= s3c2443_clkcon_enable_s,
-	},
-	.sources	= &(struct clksrc_sources) {
-		.nr_sources	= 2,
-		.sources	= (struct clk * []) {
-			[0]	= &hsmmc_div[1].clk,
-			[1]	= NULL, /* to fix */
-		},
-	},
-	.reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 17 },
-};
-
-static struct clk hsmmc0_clk = {
-	.name		= "hsmmc",
-	.devname	= "s3c-sdhci.0",
-	.parent		= &clk_h,
-	.enable		= s3c2443_clkcon_enable_h,
-	.ctrlbit	= S3C2416_HCLKCON_HSMMC0,
-};
-
-void __init_or_cpufreq s3c2416_setup_clocks(void)
-{
-	s3c2443_common_setup_clocks(s3c2416_get_pll);
-}
-
-
-static struct clksrc_clk *clksrcs[] __initdata = {
-	&hsspi_eplldiv,
-	&hsspi_mux,
-	&hsmmc_div[0],
-	&hsmmc_div[1],
-	&hsmmc_mux0,
-	&hsmmc_mux1,
-};
-
-static struct clk_lookup s3c2416_clk_lookup[] = {
-	CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &hsmmc0_clk),
-	CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &hsmmc_mux0.clk),
-	CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &hsmmc_mux1.clk),
-};
-
-void __init s3c2416_init_clocks(int xtal)
-{
-	u32 epllcon = __raw_readl(S3C2443_EPLLCON);
-	u32 epllcon1 = __raw_readl(S3C2443_EPLLCON+4);
-	int ptr;
-
-	/* s3c2416 EPLL compatible with s3c64xx */
-	clk_epll.rate = s3c_get_pll6553x(xtal, epllcon, epllcon1);
-
-	clk_epll.parent = &clk_epllref.clk;
-
-	s3c2443_common_init_clocks(xtal, s3c2416_get_pll,
-				   armdiv, ARRAY_SIZE(armdiv),
-				   S3C2416_CLKDIV0_ARMDIV_MASK);
-
-	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
-		s3c_register_clksrc(clksrcs[ptr], 1);
-
-	s3c24xx_register_clock(&hsmmc0_clk);
-	clkdev_add_table(s3c2416_clk_lookup, ARRAY_SIZE(s3c2416_clk_lookup));
-
-	s3c_pwmclk_init();
-
-}
diff --git a/arch/arm/mach-s3c2416/mach-smdk2416.c b/arch/arm/mach-s3c2416/mach-smdk2416.c
deleted file mode 100644
index eebe1e7..0000000
--- a/arch/arm/mach-s3c2416/mach-smdk2416.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/* linux/arch/arm/mach-s3c2416/mach-hanlin_v3c.c
- *
- * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
- *	as part of OpenInkpot project
- * Copyright (c) 2009 Promwad Innovation Company
- *	Yauhen Kharuzhy <yauhen.kharuzhy@promwad.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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/mtd/partitions.h>
-#include <linux/gpio.h>
-#include <linux/fb.h>
-#include <linux/delay.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-lcd.h>
-#include <mach/regs-s3c2443-clock.h>
-
-#include <mach/idle.h>
-#include <mach/leds-gpio.h>
-#include <plat/iic.h>
-
-#include <plat/s3c2416.h>
-#include <plat/gpio-cfg.h>
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/nand.h>
-#include <plat/sdhci.h>
-#include <plat/udc.h>
-#include <linux/platform_data/s3c-hsudc.h>
-
-#include <plat/regs-fb-v4.h>
-#include <plat/fb.h>
-
-#include <plat/common-smdk.h>
-
-static struct map_desc smdk2416_iodesc[] __initdata = {
-	/* ISA IO Space map (memory space selected by A24) */
-
-	{
-		.virtual	= (u32)S3C24XX_VA_ISA_WORD,
-		.pfn		= __phys_to_pfn(S3C2410_CS2),
-		.length		= 0x10000,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= (u32)S3C24XX_VA_ISA_WORD + 0x10000,
-		.pfn		= __phys_to_pfn(S3C2410_CS2 + (1<<24)),
-		.length		= SZ_4M,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= (u32)S3C24XX_VA_ISA_BYTE,
-		.pfn		= __phys_to_pfn(S3C2410_CS2),
-		.length		= 0x10000,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= (u32)S3C24XX_VA_ISA_BYTE + 0x10000,
-		.pfn		= __phys_to_pfn(S3C2410_CS2 + (1<<24)),
-		.length		= SZ_4M,
-		.type		= MT_DEVICE,
-	}
-};
-
-#define UCON (S3C2410_UCON_DEFAULT	| \
-		S3C2440_UCON_PCLK	| \
-		S3C2443_UCON_RXERR_IRQEN)
-
-#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE)
-
-#define UFCON (S3C2410_UFCON_RXTRIG8	| \
-		S3C2410_UFCON_FIFOMODE	| \
-		S3C2440_UFCON_TXTRIG16)
-
-static struct s3c2410_uartcfg smdk2416_uartcfgs[] __initdata = {
-	[0] = {
-		.hwport	     = 0,
-		.flags	     = 0,
-		.ucon	     = UCON,
-		.ulcon	     = ULCON,
-		.ufcon	     = UFCON,
-	},
-	[1] = {
-		.hwport	     = 1,
-		.flags	     = 0,
-		.ucon	     = UCON,
-		.ulcon	     = ULCON,
-		.ufcon	     = UFCON,
-	},
-	/* IR port */
-	[2] = {
-		.hwport	     = 2,
-		.flags	     = 0,
-		.ucon	     = UCON,
-		.ulcon	     = ULCON | 0x50,
-		.ufcon	     = UFCON,
-	},
-	[3] = {
-		.hwport	     = 3,
-		.flags	     = 0,
-		.ucon	     = UCON,
-		.ulcon	     = ULCON,
-		.ufcon	     = UFCON,
-	}
-};
-
-void smdk2416_hsudc_gpio_init(void)
-{
-	s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_UP);
-	s3c_gpio_setpull(S3C2410_GPF(2), S3C_GPIO_PULL_NONE);
-	s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(1));
-	s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 0);
-}
-
-void smdk2416_hsudc_gpio_uninit(void)
-{
-	s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 1);
-	s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_NONE);
-	s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(0));
-}
-
-struct s3c24xx_hsudc_platdata smdk2416_hsudc_platdata = {
-	.epnum = 9,
-	.gpio_init = smdk2416_hsudc_gpio_init,
-	.gpio_uninit = smdk2416_hsudc_gpio_uninit,
-};
-
-struct s3c_fb_pd_win smdk2416_fb_win[] = {
-	[0] = {
-		/* think this is the same as the smdk6410 */
-		.win_mode	= {
-			.pixclock	= 41094,
-			.left_margin	= 8,
-			.right_margin	= 13,
-			.upper_margin	= 7,
-			.lower_margin	= 5,
-			.hsync_len	= 3,
-			.vsync_len	= 1,
-			.xres           = 800,
-			.yres           = 480,
-		},
-		.default_bpp	= 16,
-		.max_bpp	= 32,
-	},
-};
-
-static void s3c2416_fb_gpio_setup_24bpp(void)
-{
-	unsigned int gpio;
-
-	for (gpio = S3C2410_GPC(1); gpio <= S3C2410_GPC(4); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
-
-	for (gpio = S3C2410_GPC(8); gpio <= S3C2410_GPC(15); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
-
-	for (gpio = S3C2410_GPD(0); gpio <= S3C2410_GPD(15); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
-}
-
-static struct s3c_fb_platdata smdk2416_fb_platdata = {
-	.win[0]		= &smdk2416_fb_win[0],
-	.setup_gpio	= s3c2416_fb_gpio_setup_24bpp,
-	.vidcon0	= VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
-	.vidcon1	= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
-};
-
-static struct s3c_sdhci_platdata smdk2416_hsmmc0_pdata __initdata = {
-	.max_width		= 4,
-	.cd_type		= S3C_SDHCI_CD_GPIO,
-	.ext_cd_gpio		= S3C2410_GPF(1),
-	.ext_cd_gpio_invert	= 1,
-};
-
-static struct s3c_sdhci_platdata smdk2416_hsmmc1_pdata __initdata = {
-	.max_width		= 4,
-	.cd_type		= S3C_SDHCI_CD_NONE,
-};
-
-static struct platform_device *smdk2416_devices[] __initdata = {
-	&s3c_device_fb,
-	&s3c_device_wdt,
-	&s3c_device_ohci,
-	&s3c_device_i2c0,
-	&s3c_device_hsmmc0,
-	&s3c_device_hsmmc1,
-	&s3c_device_usb_hsudc,
-};
-
-static void __init smdk2416_map_io(void)
-{
-	s3c24xx_init_io(smdk2416_iodesc, ARRAY_SIZE(smdk2416_iodesc));
-	s3c24xx_init_clocks(12000000);
-	s3c24xx_init_uarts(smdk2416_uartcfgs, ARRAY_SIZE(smdk2416_uartcfgs));
-}
-
-static void __init smdk2416_machine_init(void)
-{
-	s3c_i2c0_set_platdata(NULL);
-	s3c_fb_set_platdata(&smdk2416_fb_platdata);
-
-	s3c_sdhci0_set_platdata(&smdk2416_hsmmc0_pdata);
-	s3c_sdhci1_set_platdata(&smdk2416_hsmmc1_pdata);
-
-	s3c24xx_hsudc_set_platdata(&smdk2416_hsudc_platdata);
-
-	gpio_request(S3C2410_GPB(4), "USBHost Power");
-	gpio_direction_output(S3C2410_GPB(4), 1);
-
-	gpio_request(S3C2410_GPB(3), "Display Power");
-	gpio_direction_output(S3C2410_GPB(3), 1);
-
-	gpio_request(S3C2410_GPB(1), "Display Reset");
-	gpio_direction_output(S3C2410_GPB(1), 1);
-
-	platform_add_devices(smdk2416_devices, ARRAY_SIZE(smdk2416_devices));
-	smdk_machine_init();
-}
-
-MACHINE_START(SMDK2416, "SMDK2416")
-	/* Maintainer: Yauhen Kharuzhy <jekhor@gmail.com> */
-	.atag_offset	= 0x100,
-
-	.init_irq	= s3c24xx_init_irq,
-	.map_io		= smdk2416_map_io,
-	.init_machine	= smdk2416_machine_init,
-	.timer		= &s3c24xx_timer,
-	.restart	= s3c2416_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2416/s3c2416.c b/arch/arm/mach-s3c2416/s3c2416.c
deleted file mode 100644
index 5287d28..0000000
--- a/arch/arm/mach-s3c2416/s3c2416.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/* linux/arch/arm/mach-s3c2416/s3c2416.c
- *
- * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
- *	as part of OpenInkpot project
- * Copyright (c) 2009 Promwad Innovation Company
- *	Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com>
- *
- * Samsung S3C2416 Mobile CPU support
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/proc-fns.h>
-#include <asm/irq.h>
-
-#include <mach/idle.h>
-#include <mach/regs-s3c2443-clock.h>
-
-#include <plat/gpio-core.h>
-#include <plat/gpio-cfg.h>
-#include <plat/gpio-cfg-helpers.h>
-#include <plat/s3c2416.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/sdhci.h>
-#include <plat/pm.h>
-
-#include <plat/iic-core.h>
-#include <plat/fb-core.h>
-#include <plat/nand-core.h>
-#include <plat/adc-core.h>
-
-static struct map_desc s3c2416_iodesc[] __initdata = {
-	IODESC_ENT(WATCHDOG),
-	IODESC_ENT(CLKPWR),
-	IODESC_ENT(TIMER),
-};
-
-struct bus_type s3c2416_subsys = {
-	.name = "s3c2416-core",
-	.dev_name = "s3c2416-core",
-};
-
-static struct device s3c2416_dev = {
-	.bus		= &s3c2416_subsys,
-};
-
-void s3c2416_restart(char mode, const char *cmd)
-{
-	if (mode == 's')
-		soft_restart(0);
-
-	__raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST);
-}
-
-int __init s3c2416_init(void)
-{
-	printk(KERN_INFO "S3C2416: Initializing architecture\n");
-
-	/* s3c24xx_idle = s3c2416_idle;	*/
-
-	/* change WDT IRQ number */
-	s3c_device_wdt.resource[1].start = IRQ_S3C2443_WDT;
-	s3c_device_wdt.resource[1].end   = IRQ_S3C2443_WDT;
-
-	/* the i2c devices are directly compatible with s3c2440 */
-	s3c_i2c0_setname("s3c2440-i2c");
-	s3c_i2c1_setname("s3c2440-i2c");
-
-	s3c_fb_setname("s3c2443-fb");
-
-	s3c_adc_setname("s3c2416-adc");
-
-#ifdef CONFIG_PM
-	register_syscore_ops(&s3c2416_pm_syscore_ops);
-#endif
-	register_syscore_ops(&s3c24xx_irq_syscore_ops);
-
-	return device_register(&s3c2416_dev);
-}
-
-void __init s3c2416_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-	s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
-
-	s3c_nand_setname("s3c2412-nand");
-}
-
-/* s3c2416_map_io
- *
- * register the standard cpu IO areas, and any passed in from the
- * machine specific initialisation.
- */
-
-void __init s3c2416_map_io(void)
-{
-	s3c24xx_gpiocfg_default.set_pull = samsung_gpio_setpull_updown;
-	s3c24xx_gpiocfg_default.get_pull = samsung_gpio_getpull_updown;
-
-	/* initialize device information early */
-	s3c2416_default_sdhci0();
-	s3c2416_default_sdhci1();
-
-	iotable_init(s3c2416_iodesc, ARRAY_SIZE(s3c2416_iodesc));
-}
-
-/* need to register the subsystem before we actually register the device, and
- * we also need to ensure that it has been initialised before any of the
- * drivers even try to use it (even if not on an s3c2416 based system)
- * as a driver which may support both 2443 and 2440 may try and use it.
-*/
-
-static int __init s3c2416_core_init(void)
-{
-	return subsys_system_register(&s3c2416_subsys, NULL);
-}
-
-core_initcall(s3c2416_core_init);
diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig
index 914e620..ece7a10 100644
--- a/arch/arm/mach-s3c2440/Kconfig
+++ b/arch/arm/mach-s3c2440/Kconfig
@@ -2,35 +2,6 @@
 #
 # Licensed under GPLv2
 
-config CPU_S3C2440
-	bool
-	select CPU_ARM920T
-	select S3C2410_CLOCK
-	select S3C2410_PM if PM
-	select S3C2440_DMA if S3C2410_DMA
-	select CPU_S3C244X
-	select CPU_LLSERIAL_S3C2440
-	help
-	  Support for S3C2440 Samsung Mobile CPU based systems.
-
-config CPU_S3C2442
-	bool
-	select CPU_ARM920T
-	select S3C2410_CLOCK
-	select S3C2410_PM if PM
-	select CPU_S3C244X
-	select CPU_LLSERIAL_S3C2440
-	help
-	  Support for S3C2442 Samsung Mobile CPU based systems.
-
-config CPU_S3C244X
-	bool
-	depends on CPU_S3C2440 || CPU_S3C2442
-	help
-	  Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems.
-
-
-
 config S3C2440_CPUFREQ
 	bool "S3C2440/S3C2442 CPU Frequency scaling support"
 	depends on CPU_FREQ_S3C24XX && (CPU_S3C2440 || CPU_S3C2442)
@@ -64,139 +35,3 @@
 	default y if CPU_FREQ_S3C24XX_PLL
 	help
 	  PLL tables for S3C2440 or S3C2442 CPUs with 16.934MHz crystals.
-
-config S3C2440_DMA
-	bool
-	depends on CPU_S3C2440
-	help
-	  Support for S3C2440 specific DMA code5A
-
-menu "S3C2440 and S3C2442 Machines"
-
-config MACH_ANUBIS
-	bool "Simtec Electronics ANUBIS"
-	select CPU_S3C2440
-	select S3C24XX_DCLK
-	select PM_SIMTEC if PM
-	select HAVE_PATA_PLATFORM
-	select S3C24XX_GPIO_EXTRA64
-	select S3C2440_XTAL_12000000
-	select S3C_DEV_USB_HOST
-	help
-	  Say Y here if you are using the Simtec Electronics ANUBIS
-	  development system
-
-config MACH_NEO1973_GTA02
-	bool "Openmoko GTA02 / Freerunner phone"
-	select CPU_S3C2442
-	select MFD_PCF50633
-	select PCF50633_GPIO
-	select I2C
-	select POWER_SUPPLY
-	select MACH_NEO1973
-	select S3C2410_PWM
-	select S3C_DEV_USB_HOST
-	help
-	   Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone
-
-config MACH_OSIRIS
-	bool "Simtec IM2440D20 (OSIRIS) module"
-	select CPU_S3C2440
-	select S3C24XX_DCLK
-	select PM_SIMTEC if PM
-	select S3C24XX_GPIO_EXTRA128
-	select S3C2440_XTAL_12000000
-	select S3C2410_IOTIMING if S3C2440_CPUFREQ
-	select S3C_DEV_USB_HOST
-	select S3C_DEV_NAND
-	help
-	  Say Y here if you are using the Simtec IM2440D20 module, also
-	  known as the Osiris.
-
-config MACH_OSIRIS_DVS
-	tristate "Simtec IM2440D20 (OSIRIS) Dynamic Voltage Scaling driver"
-	depends on MACH_OSIRIS
-	select TPS65010
-	help
-	  Say Y/M here if you want to have dynamic voltage scaling support
-	  on the Simtec IM2440D20 (OSIRIS) module via the TPS65011.
-
-	  The DVS driver alters the voltage supplied to the ARM core
-	  depending on the frequency it is running at. The driver itself
-	  does not do any of the frequency alteration, which is left up
-	  to the cpufreq driver.
-
-config MACH_RX3715
-	bool "HP iPAQ rx3715"
-	select CPU_S3C2440
-	select S3C2440_XTAL_16934400
-	select PM_H1940 if PM
-	select S3C_DEV_NAND
-	help
-	  Say Y here if you are using the HP iPAQ rx3715.
-
-config ARCH_S3C2440
-	bool "SMDK2440"
-	select CPU_S3C2440
-	select S3C2440_XTAL_16934400
-	select MACH_SMDK
-	select S3C_DEV_USB_HOST
-	select S3C_DEV_NAND
-	help
-	  Say Y here if you are using the SMDK2440.
-
-config MACH_NEXCODER_2440
- 	bool "NexVision NEXCODER 2440 Light Board"
- 	select CPU_S3C2440
-	select S3C2440_XTAL_12000000
-	select S3C_DEV_USB_HOST
-	select S3C_DEV_NAND
-	help
- 	  Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
-
-config SMDK2440_CPU2440
-	bool "SMDK2440 with S3C2440 CPU module"
-	default y if ARCH_S3C2440
-	select S3C2440_XTAL_16934400
-	select CPU_S3C2440
-
-config SMDK2440_CPU2442
-	bool "SMDM2440 with S3C2442 CPU module"
-	select CPU_S3C2442
-
-config MACH_AT2440EVB
-	bool "Avantech AT2440EVB development board"
-	select CPU_S3C2440
-	select S3C_DEV_USB_HOST
-	select S3C_DEV_NAND
-	help
-	  Say Y here if you are using the AT2440EVB development board
-
-config MACH_MINI2440
-	bool "MINI2440 development board"
-	select CPU_S3C2440
-	select EEPROM_AT24
-	select NEW_LEDS
-	select LEDS_CLASS
-	select LEDS_TRIGGER
-	select LEDS_TRIGGER_BACKLIGHT
-	select S3C_DEV_NAND
-	select S3C_DEV_USB_HOST
-	help
-	  Say Y here to select support for the MINI2440. Is a 10cm x 10cm board
-	  available via various sources. It can come with a 3.5" or 7" touch LCD.
-
-config MACH_RX1950
-	bool "HP iPAQ rx1950"
-	select CPU_S3C2442
-	select S3C24XX_DCLK
-	select PM_H1940 if PM
-	select I2C
-	select S3C2410_PWM
-	select S3C_DEV_NAND
-	select S3C2410_IOTIMING if S3C2440_CPUFREQ
-	select S3C2440_XTAL_16934400
-	help
-	   Say Y here if you're using HP iPAQ rx1950
-
-endmenu
diff --git a/arch/arm/mach-s3c2440/Makefile b/arch/arm/mach-s3c2440/Makefile
index d5440fa..c460924 100644
--- a/arch/arm/mach-s3c2440/Makefile
+++ b/arch/arm/mach-s3c2440/Makefile
@@ -9,33 +9,9 @@
 obj-n				:=
 obj-				:=
 
-obj-$(CONFIG_CPU_S3C2440)	+= s3c2440.o dsc.o
-obj-$(CONFIG_CPU_S3C2442)	+= s3c2442.o
+obj-$(CONFIG_CPU_S3C2440)	+= dsc.o
 
-obj-$(CONFIG_CPU_S3C2440)	+= irq.o
-obj-$(CONFIG_CPU_S3C2440)	+= clock.o
-obj-$(CONFIG_S3C2440_DMA)	+= dma.o
-
-obj-$(CONFIG_CPU_S3C244X)	+= s3c244x.o
-obj-$(CONFIG_CPU_S3C244X)	+= s3c244x-irq.o
-obj-$(CONFIG_CPU_S3C244X)	+= s3c244x-clock.o
 obj-$(CONFIG_S3C2440_CPUFREQ)	+= s3c2440-cpufreq.o
 
 obj-$(CONFIG_S3C2440_PLL_12000000) += s3c2440-pll-12000000.o
 obj-$(CONFIG_S3C2440_PLL_16934400) += s3c2440-pll-16934400.o
-
-# Machine support
-
-obj-$(CONFIG_MACH_ANUBIS)	+= mach-anubis.o
-obj-$(CONFIG_MACH_OSIRIS)	+= mach-osiris.o
-obj-$(CONFIG_MACH_RX3715)	+= mach-rx3715.o
-obj-$(CONFIG_ARCH_S3C2440)	+= mach-smdk2440.o
-obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o
-obj-$(CONFIG_MACH_AT2440EVB) += mach-at2440evb.o
-obj-$(CONFIG_MACH_MINI2440) += mach-mini2440.o
-obj-$(CONFIG_MACH_NEO1973_GTA02) += mach-gta02.o
-obj-$(CONFIG_MACH_RX1950) += mach-rx1950.o
-
-# extra machine support
-
-obj-$(CONFIG_MACH_OSIRIS_DVS)	+= mach-osiris-dvs.o
diff --git a/arch/arm/mach-s3c2440/common.h b/arch/arm/mach-s3c2440/common.h
deleted file mode 100644
index 0c1eb1d..0000000
--- a/arch/arm/mach-s3c2440/common.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * Common Header for S3C2440 machines
- *
- * 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 __ARCH_ARM_MACH_S3C2440_COMMON_H
-#define __ARCH_ARM_MACH_S3C2440_COMMON_H
-
-void s3c244x_restart(char mode, const char *cmd);
-
-#endif /* __ARCH_ARM_MACH_S3C2440_COMMON_H */
diff --git a/arch/arm/mach-s3c2440/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c
deleted file mode 100644
index 19b577b..0000000
--- a/arch/arm/mach-s3c2440/mach-anubis.c
+++ /dev/null
@@ -1,491 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/mach-anubis.c
- *
- * Copyright 2003-2009 Simtec Electronics
- *	http://armlinux.simtec.co.uk/
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/ata_platform.h>
-#include <linux/i2c.h>
-#include <linux/io.h>
-#include <linux/sm501.h>
-#include <linux/sm501-regs.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/anubis-map.h>
-#include <mach/anubis-irq.h>
-#include <mach/anubis-cpld.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
-#include <mach/regs-lcd.h>
-#include <plat/nand.h>
-#include <plat/iic.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <net/ax88796.h>
-
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/audio-simtec.h>
-
-#include "common.h"
-
-#define COPYRIGHT ", Copyright 2005-2009 Simtec Electronics"
-
-static struct map_desc anubis_iodesc[] __initdata = {
-  /* ISA IO areas */
-
-  {
-	.virtual	= (u32)S3C24XX_VA_ISA_BYTE,
-	.pfn		= __phys_to_pfn(0x0),
-	.length		= SZ_4M,
-	.type		= MT_DEVICE,
-  }, {
-	.virtual	= (u32)S3C24XX_VA_ISA_WORD,
-	.pfn		= __phys_to_pfn(0x0),
-	.length 	= SZ_4M,
-	.type		= MT_DEVICE,
-  },
-
-  /* we could possibly compress the next set down into a set of smaller tables
-   * pagetables, but that would mean using an L2 section, and it still means
-   * we cannot actually feed the same register to an LDR due to 16K spacing
-   */
-
-  /* CPLD control registers */
-
-  {
-	.virtual	= (u32)ANUBIS_VA_CTRL1,
-	.pfn		= __phys_to_pfn(ANUBIS_PA_CTRL1),
-	.length		= SZ_4K,
-	.type		= MT_DEVICE,
-  }, {
-	.virtual	= (u32)ANUBIS_VA_IDREG,
-	.pfn		= __phys_to_pfn(ANUBIS_PA_IDREG),
-	.length		= SZ_4K,
-	.type		= MT_DEVICE,
-  },
-};
-
-#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg anubis_uartcfgs[] __initdata = {
-	[0] = {
-		.hwport	     = 0,
-		.flags	     = 0,
-		.ucon	     = UCON,
-		.ulcon	     = ULCON,
-		.ufcon	     = UFCON,
-		.clk_sel	= S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
-	},
-	[1] = {
-		.hwport	     = 2,
-		.flags	     = 0,
-		.ucon	     = UCON,
-		.ulcon	     = ULCON,
-		.ufcon	     = UFCON,
-		.clk_sel	= S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
-	},
-};
-
-/* NAND Flash on Anubis board */
-
-static int external_map[]   = { 2 };
-static int chip0_map[]      = { 0 };
-static int chip1_map[]      = { 1 };
-
-static struct mtd_partition __initdata anubis_default_nand_part[] = {
-	[0] = {
-		.name	= "Boot Agent",
-		.size	= SZ_16K,
-		.offset	= 0,
-	},
-	[1] = {
-		.name	= "/boot",
-		.size	= SZ_4M - SZ_16K,
-		.offset	= SZ_16K,
-	},
-	[2] = {
-		.name	= "user1",
-		.offset	= SZ_4M,
-		.size	= SZ_32M - SZ_4M,
-	},
-	[3] = {
-		.name	= "user2",
-		.offset	= SZ_32M,
-		.size	= MTDPART_SIZ_FULL,
-	}
-};
-
-static struct mtd_partition __initdata anubis_default_nand_part_large[] = {
-	[0] = {
-		.name	= "Boot Agent",
-		.size	= SZ_128K,
-		.offset	= 0,
-	},
-	[1] = {
-		.name	= "/boot",
-		.size	= SZ_4M - SZ_128K,
-		.offset	= SZ_128K,
-	},
-	[2] = {
-		.name	= "user1",
-		.offset	= SZ_4M,
-		.size	= SZ_32M - SZ_4M,
-	},
-	[3] = {
-		.name	= "user2",
-		.offset	= SZ_32M,
-		.size	= MTDPART_SIZ_FULL,
-	}
-};
-
-/* the Anubis has 3 selectable slots for nand-flash, the two
- * on-board chip areas, as well as the external slot.
- *
- * Note, there is no current hot-plug support for the External
- * socket.
-*/
-
-static struct s3c2410_nand_set __initdata anubis_nand_sets[] = {
-	[1] = {
-		.name		= "External",
-		.nr_chips	= 1,
-		.nr_map		= external_map,
-		.nr_partitions	= ARRAY_SIZE(anubis_default_nand_part),
-		.partitions	= anubis_default_nand_part,
-	},
-	[0] = {
-		.name		= "chip0",
-		.nr_chips	= 1,
-		.nr_map		= chip0_map,
-		.nr_partitions	= ARRAY_SIZE(anubis_default_nand_part),
-		.partitions	= anubis_default_nand_part,
-	},
-	[2] = {
-		.name		= "chip1",
-		.nr_chips	= 1,
-		.nr_map		= chip1_map,
-		.nr_partitions	= ARRAY_SIZE(anubis_default_nand_part),
-		.partitions	= anubis_default_nand_part,
-	},
-};
-
-static void anubis_nand_select(struct s3c2410_nand_set *set, int slot)
-{
-	unsigned int tmp;
-
-	slot = set->nr_map[slot] & 3;
-
-	pr_debug("anubis_nand: selecting slot %d (set %p,%p)\n",
-		 slot, set, set->nr_map);
-
-	tmp = __raw_readb(ANUBIS_VA_CTRL1);
-	tmp &= ~ANUBIS_CTRL1_NANDSEL;
-	tmp |= slot;
-
-	pr_debug("anubis_nand: ctrl1 now %02x\n", tmp);
-
-	__raw_writeb(tmp, ANUBIS_VA_CTRL1);
-}
-
-static struct s3c2410_platform_nand __initdata anubis_nand_info = {
-	.tacls		= 25,
-	.twrph0		= 55,
-	.twrph1		= 40,
-	.nr_sets	= ARRAY_SIZE(anubis_nand_sets),
-	.sets		= anubis_nand_sets,
-	.select_chip	= anubis_nand_select,
-};
-
-/* IDE channels */
-
-static struct pata_platform_info anubis_ide_platdata = {
-	.ioport_shift	= 5,
-};
-
-static struct resource anubis_ide0_resource[] = {
-	{
-		.start	= S3C2410_CS3,
-		.end	= S3C2410_CS3 + (8*32) - 1,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= S3C2410_CS3 + (1<<26) + (6*32),
-		.end	= S3C2410_CS3 + (1<<26) + (7*32) - 1,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= IRQ_IDE0,
-		.end	= IRQ_IDE0,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device anubis_device_ide0 = {
-	.name		= "pata_platform",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(anubis_ide0_resource),
-	.resource	= anubis_ide0_resource,
-	.dev	= {
-		.platform_data = &anubis_ide_platdata,
-		.coherent_dma_mask = ~0,
-	},
-};
-
-static struct resource anubis_ide1_resource[] = {
-	{
-		.start	= S3C2410_CS4,
-		.end	= S3C2410_CS4 + (8*32) - 1,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= S3C2410_CS4 + (1<<26) + (6*32),
-		.end	= S3C2410_CS4 + (1<<26) + (7*32) - 1,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= IRQ_IDE0,
-		.end	= IRQ_IDE0,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device anubis_device_ide1 = {
-	.name		= "pata_platform",
-	.id		= 1,
-	.num_resources	= ARRAY_SIZE(anubis_ide1_resource),
-	.resource	= anubis_ide1_resource,
-	.dev	= {
-		.platform_data = &anubis_ide_platdata,
-		.coherent_dma_mask = ~0,
-	},
-};
-
-/* Asix AX88796 10/100 ethernet controller */
-
-static struct ax_plat_data anubis_asix_platdata = {
-	.flags		= AXFLG_MAC_FROMDEV,
-	.wordlength	= 2,
-	.dcr_val	= 0x48,
-	.rcr_val	= 0x40,
-};
-
-static struct resource anubis_asix_resource[] = {
-	[0] = {
-		.start = S3C2410_CS5,
-		.end   = S3C2410_CS5 + (0x20 * 0x20) -1,
-		.flags = IORESOURCE_MEM
-	},
-	[1] = {
-		.start = IRQ_ASIX,
-		.end   = IRQ_ASIX,
-		.flags = IORESOURCE_IRQ
-	}
-};
-
-static struct platform_device anubis_device_asix = {
-	.name		= "ax88796",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(anubis_asix_resource),
-	.resource	= anubis_asix_resource,
-	.dev		= {
-		.platform_data = &anubis_asix_platdata,
-	}
-};
-
-/* SM501 */
-
-static struct resource anubis_sm501_resource[] = {
-	[0] = {
-		.start	= S3C2410_CS2,
-		.end	= S3C2410_CS2 + SZ_8M,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= S3C2410_CS2 + SZ_64M - SZ_2M,
-		.end	= S3C2410_CS2 + SZ_64M - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[2] = {
-		.start	= IRQ_EINT0,
-		.end	= IRQ_EINT0,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct sm501_initdata anubis_sm501_initdata = {
-	.gpio_high	= {
-		.set	= 0x3F000000,		/* 24bit panel */
-		.mask	= 0x0,
-	},
-	.misc_timing	= {
-		.set	= 0x010100,		/* SDRAM timing */
-		.mask	= 0x1F1F00,
-	},
-	.misc_control	= {
-		.set	= SM501_MISC_PNL_24BIT,
-		.mask	= 0,
-	},
-
-	.devices	= SM501_USE_GPIO,
-
-	/* set the SDRAM and bus clocks */
-	.mclk		= 72 * MHZ,
-	.m1xclk		= 144 * MHZ,
-};
-
-static struct sm501_platdata_gpio_i2c anubis_sm501_gpio_i2c[] = {
-	[0] = {
-		.bus_num	= 1,
-		.pin_scl	= 44,
-		.pin_sda	= 45,
-	},
-	[1] = {
-		.bus_num	= 2,
-		.pin_scl	= 40,
-		.pin_sda	= 41,
-	},
-};
-
-static struct sm501_platdata anubis_sm501_platdata = {
-	.init		= &anubis_sm501_initdata,
-	.gpio_base	= -1,
-	.gpio_i2c	= anubis_sm501_gpio_i2c,
-	.gpio_i2c_nr	= ARRAY_SIZE(anubis_sm501_gpio_i2c),
-};
-
-static struct platform_device anubis_device_sm501 = {
-	.name		= "sm501",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(anubis_sm501_resource),
-	.resource	= anubis_sm501_resource,
-	.dev		= {
-		.platform_data = &anubis_sm501_platdata,
-	},
-};
-
-/* Standard Anubis devices */
-
-static struct platform_device *anubis_devices[] __initdata = {
-	&s3c_device_ohci,
-	&s3c_device_wdt,
-	&s3c_device_adc,
-	&s3c_device_i2c0,
- 	&s3c_device_rtc,
-	&s3c_device_nand,
-	&anubis_device_ide0,
-	&anubis_device_ide1,
-	&anubis_device_asix,
-	&anubis_device_sm501,
-};
-
-static struct clk *anubis_clocks[] __initdata = {
-	&s3c24xx_dclk0,
-	&s3c24xx_dclk1,
-	&s3c24xx_clkout0,
-	&s3c24xx_clkout1,
-	&s3c24xx_uclk,
-};
-
-/* I2C devices. */
-
-static struct i2c_board_info anubis_i2c_devs[] __initdata = {
-	{
-		I2C_BOARD_INFO("tps65011", 0x48),
-		.irq	= IRQ_EINT20,
-	}
-};
-
-/* Audio setup */
-static struct s3c24xx_audio_simtec_pdata __initdata anubis_audio = {
-	.have_mic	= 1,
-	.have_lout	= 1,
-	.output_cdclk	= 1,
-	.use_mpllin	= 1,
-	.amp_gpio	= S3C2410_GPB(2),
-	.amp_gain[0]	= S3C2410_GPD(10),
-	.amp_gain[1]	= S3C2410_GPD(11),
-};
-
-static void __init anubis_map_io(void)
-{
-	/* initialise the clocks */
-
-	s3c24xx_dclk0.parent = &clk_upll;
-	s3c24xx_dclk0.rate   = 12*1000*1000;
-
-	s3c24xx_dclk1.parent = &clk_upll;
-	s3c24xx_dclk1.rate   = 24*1000*1000;
-
-	s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
-	s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
-
-	s3c24xx_uclk.parent  = &s3c24xx_clkout1;
-
-	s3c24xx_register_clocks(anubis_clocks, ARRAY_SIZE(anubis_clocks));
-
-	s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc));
-	s3c24xx_init_clocks(0);
-	s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs));
-
-	/* check for the newer revision boards with large page nand */
-
-	if ((__raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK) >= 4) {
-		printk(KERN_INFO "ANUBIS-B detected (revision %d)\n",
-		       __raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK);
-		anubis_nand_sets[0].partitions = anubis_default_nand_part_large;
-		anubis_nand_sets[0].nr_partitions = ARRAY_SIZE(anubis_default_nand_part_large);
-	} else {
-		/* ensure that the GPIO is setup */
-		s3c2410_gpio_setpin(S3C2410_GPA(0), 1);
-	}
-}
-
-static void __init anubis_init(void)
-{
-	s3c_i2c0_set_platdata(NULL);
-	s3c_nand_set_platdata(&anubis_nand_info);
-	simtec_audio_add(NULL, false, &anubis_audio);
-
-	platform_add_devices(anubis_devices, ARRAY_SIZE(anubis_devices));
-
-	i2c_register_board_info(0, anubis_i2c_devs,
-				ARRAY_SIZE(anubis_i2c_devs));
-}
-
-
-MACHINE_START(ANUBIS, "Simtec-Anubis")
-	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-	.atag_offset	= 0x100,
-	.map_io		= anubis_map_io,
-	.init_machine	= anubis_init,
-	.init_irq	= s3c24xx_init_irq,
-	.timer		= &s3c24xx_timer,
-	.restart	= s3c244x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
deleted file mode 100644
index 9a4a5bc..0000000
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ /dev/null
@@ -1,605 +0,0 @@
-/*
- * linux/arch/arm/mach-s3c2442/mach-gta02.c
- *
- * S3C2442 Machine Support for Openmoko GTA02 / FreeRunner.
- *
- * Copyright (C) 2006-2009 by Openmoko, Inc.
- * Authors: Harald Welte <laforge@openmoko.org>
- *          Andy Green <andy@openmoko.org>
- *          Werner Almesberger <werner@openmoko.org>
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/serial_core.h>
-#include <linux/spi/spi.h>
-
-#include <linux/mmc/host.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <linux/io.h>
-
-#include <linux/i2c.h>
-#include <linux/regulator/machine.h>
-
-#include <linux/mfd/pcf50633/core.h>
-#include <linux/mfd/pcf50633/mbc.h>
-#include <linux/mfd/pcf50633/adc.h>
-#include <linux/mfd/pcf50633/gpio.h>
-#include <linux/mfd/pcf50633/pmic.h>
-#include <linux/mfd/pcf50633/backlight.h>
-
-#include <linux/input.h>
-#include <linux/gpio_keys.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <mach/regs-irq.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-gpioj.h>
-#include <mach/fb.h>
-
-#include <mach/spi.h>
-#include <plat/usb-control.h>
-#include <mach/regs-mem.h>
-#include <mach/hardware.h>
-
-#include <mach/gta02.h>
-
-#include <plat/regs-serial.h>
-#include <plat/nand.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/udc.h>
-#include <plat/gpio-cfg.h>
-#include <plat/iic.h>
-#include <plat/ts.h>
-
-#include "common.h"
-
-static struct pcf50633 *gta02_pcf;
-
-/*
- * This gets called frequently when we paniced.
- */
-
-static long gta02_panic_blink(int state)
-{
-	long delay = 0;
-	char led;
-
-	led = (state) ? 1 : 0;
-	gpio_direction_output(GTA02_GPIO_AUX_LED, led);
-
-	return delay;
-}
-
-
-static struct map_desc gta02_iodesc[] __initdata = {
-	{
-		.virtual	= 0xe0000000,
-		.pfn		= __phys_to_pfn(S3C2410_CS3 + 0x01000000),
-		.length		= SZ_1M,
-		.type		= MT_DEVICE
-	},
-};
-
-#define UCON (S3C2410_UCON_DEFAULT | S3C2443_UCON_RXERR_IRQEN)
-#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
-#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
-
-static struct s3c2410_uartcfg gta02_uartcfgs[] = {
-	[0] = {
-		.hwport		= 0,
-		.flags		= 0,
-		.ucon		= UCON,
-		.ulcon		= ULCON,
-		.ufcon		= UFCON,
-	},
-	[1] = {
-		.hwport		= 1,
-		.flags		= 0,
-		.ucon		= UCON,
-		.ulcon		= ULCON,
-		.ufcon		= UFCON,
-	},
-	[2] = {
-		.hwport		= 2,
-		.flags		= 0,
-		.ucon		= UCON,
-		.ulcon		= ULCON,
-		.ufcon		= UFCON,
-	},
-};
-
-#ifdef CONFIG_CHARGER_PCF50633
-/*
- * On GTA02 the 1A charger features a 48K resistor to 0V on the ID pin.
- * We use this to recognize that we can pull 1A from the USB socket.
- *
- * These constants are the measured pcf50633 ADC levels with the 1A
- * charger / 48K resistor, and with no pulldown resistor.
- */
-
-#define ADC_NOM_CHG_DETECT_1A 6
-#define ADC_NOM_CHG_DETECT_USB 43
-
-static void
-gta02_configure_pmu_for_charger(struct pcf50633 *pcf, void *unused, int res)
-{
-	int  ma;
-
-	/* Interpret charger type */
-	if (res < ((ADC_NOM_CHG_DETECT_USB + ADC_NOM_CHG_DETECT_1A) / 2)) {
-
-		/*
-		 * Sanity - stop GPO driving out now that we have a 1A charger
-		 * GPO controls USB Host power generation on GTA02
-		 */
-		pcf50633_gpio_set(pcf, PCF50633_GPO, 0);
-
-		ma = 1000;
-	} else
-		ma = 100;
-
-	pcf50633_mbc_usb_curlim_set(pcf, ma);
-}
-
-static struct delayed_work gta02_charger_work;
-static int gta02_usb_vbus_draw;
-
-static void gta02_charger_worker(struct work_struct *work)
-{
-	if (gta02_usb_vbus_draw) {
-		pcf50633_mbc_usb_curlim_set(gta02_pcf, gta02_usb_vbus_draw);
-		return;
-	}
-
-#ifdef CONFIG_PCF50633_ADC
-	pcf50633_adc_async_read(gta02_pcf,
-				PCF50633_ADCC1_MUX_ADCIN1,
-				PCF50633_ADCC1_AVERAGE_16,
-				gta02_configure_pmu_for_charger,
-				NULL);
-#else
-	/*
-	 * If the PCF50633 ADC is disabled we fallback to a
-	 * 100mA limit for safety.
-	 */
-	pcf50633_mbc_usb_curlim_set(pcf, 100);
-#endif
-}
-
-#define GTA02_CHARGER_CONFIGURE_TIMEOUT ((3000 * HZ) / 1000)
-
-static void gta02_pmu_event_callback(struct pcf50633 *pcf, int irq)
-{
-	if (irq == PCF50633_IRQ_USBINS) {
-		schedule_delayed_work(&gta02_charger_work,
-				      GTA02_CHARGER_CONFIGURE_TIMEOUT);
-
-		return;
-	}
-
-	if (irq == PCF50633_IRQ_USBREM) {
-		cancel_delayed_work_sync(&gta02_charger_work);
-		gta02_usb_vbus_draw = 0;
-	}
-}
-
-static void gta02_udc_vbus_draw(unsigned int ma)
-{
-	if (!gta02_pcf)
-		return;
-
-	gta02_usb_vbus_draw = ma;
-
-	schedule_delayed_work(&gta02_charger_work,
-			      GTA02_CHARGER_CONFIGURE_TIMEOUT);
-}
-#else /* !CONFIG_CHARGER_PCF50633 */
-#define gta02_pmu_event_callback	NULL
-#define gta02_udc_vbus_draw		NULL
-#endif
-
-/*
- * This is called when pc50633 is probed, unfortunately quite late in the
- * day since it is an I2C bus device. Here we can belatedly define some
- * platform devices with the advantage that we can mark the pcf50633 as the
- * parent. This makes them get suspended and resumed with their parent
- * the pcf50633 still around.
- */
-
-static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf);
-
-
-static char *gta02_batteries[] = {
-	"battery",
-};
-
-static struct pcf50633_bl_platform_data gta02_backlight_data = {
-	.default_brightness = 0x3f,
-	.default_brightness_limit = 0,
-	.ramp_time = 5,
-};
-
-struct pcf50633_platform_data gta02_pcf_pdata = {
-	.resumers = {
-		[0] =	PCF50633_INT1_USBINS |
-			PCF50633_INT1_USBREM |
-			PCF50633_INT1_ALARM,
-		[1] =	PCF50633_INT2_ONKEYF,
-		[2] =	PCF50633_INT3_ONKEY1S,
-		[3] =	PCF50633_INT4_LOWSYS |
-			PCF50633_INT4_LOWBAT |
-			PCF50633_INT4_HIGHTMP,
-	},
-
-	.batteries = gta02_batteries,
-	.num_batteries = ARRAY_SIZE(gta02_batteries),
-
-	.charger_reference_current_ma = 1000,
-
-	.backlight_data = &gta02_backlight_data,
-
-	.reg_init_data = {
-		[PCF50633_REGULATOR_AUTO] = {
-			.constraints = {
-				.min_uV = 3300000,
-				.max_uV = 3300000,
-				.valid_modes_mask = REGULATOR_MODE_NORMAL,
-				.always_on = 1,
-				.apply_uV = 1,
-			},
-		},
-		[PCF50633_REGULATOR_DOWN1] = {
-			.constraints = {
-				.min_uV = 1300000,
-				.max_uV = 1600000,
-				.valid_modes_mask = REGULATOR_MODE_NORMAL,
-				.always_on = 1,
-				.apply_uV = 1,
-			},
-		},
-		[PCF50633_REGULATOR_DOWN2] = {
-			.constraints = {
-				.min_uV = 1800000,
-				.max_uV = 1800000,
-				.valid_modes_mask = REGULATOR_MODE_NORMAL,
-				.apply_uV = 1,
-				.always_on = 1,
-			},
-		},
-		[PCF50633_REGULATOR_HCLDO] = {
-			.constraints = {
-				.min_uV = 2000000,
-				.max_uV = 3300000,
-				.valid_modes_mask = REGULATOR_MODE_NORMAL,
-				.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
-						REGULATOR_CHANGE_STATUS,
-			},
-		},
-		[PCF50633_REGULATOR_LDO1] = {
-			.constraints = {
-				.min_uV = 3300000,
-				.max_uV = 3300000,
-				.valid_modes_mask = REGULATOR_MODE_NORMAL,
-				.valid_ops_mask = REGULATOR_CHANGE_STATUS,
-				.apply_uV = 1,
-			},
-		},
-		[PCF50633_REGULATOR_LDO2] = {
-			.constraints = {
-				.min_uV = 3300000,
-				.max_uV = 3300000,
-				.valid_modes_mask = REGULATOR_MODE_NORMAL,
-				.apply_uV = 1,
-			},
-		},
-		[PCF50633_REGULATOR_LDO3] = {
-			.constraints = {
-				.min_uV = 3000000,
-				.max_uV = 3000000,
-				.valid_modes_mask = REGULATOR_MODE_NORMAL,
-				.apply_uV = 1,
-			},
-		},
-		[PCF50633_REGULATOR_LDO4] = {
-			.constraints = {
-				.min_uV = 3200000,
-				.max_uV = 3200000,
-				.valid_modes_mask = REGULATOR_MODE_NORMAL,
-				.valid_ops_mask = REGULATOR_CHANGE_STATUS,
-				.apply_uV = 1,
-			},
-		},
-		[PCF50633_REGULATOR_LDO5] = {
-			.constraints = {
-				.min_uV = 3000000,
-				.max_uV = 3000000,
-				.valid_modes_mask = REGULATOR_MODE_NORMAL,
-				.valid_ops_mask = REGULATOR_CHANGE_STATUS,
-				.apply_uV = 1,
-			},
-		},
-		[PCF50633_REGULATOR_LDO6] = {
-			.constraints = {
-				.min_uV = 3000000,
-				.max_uV = 3000000,
-				.valid_modes_mask = REGULATOR_MODE_NORMAL,
-			},
-		},
-		[PCF50633_REGULATOR_MEMLDO] = {
-			.constraints = {
-				.min_uV = 1800000,
-				.max_uV = 1800000,
-				.valid_modes_mask = REGULATOR_MODE_NORMAL,
-			},
-		},
-
-	},
-	.probe_done = gta02_pmu_attach_child_devices,
-	.mbc_event_callback = gta02_pmu_event_callback,
-};
-
-
-/* NOR Flash. */
-
-#define GTA02_FLASH_BASE	0x18000000 /* GCS3 */
-#define GTA02_FLASH_SIZE	0x200000 /* 2MBytes */
-
-static struct physmap_flash_data gta02_nor_flash_data = {
-	.width		= 2,
-};
-
-static struct resource gta02_nor_flash_resource = {
-	.start		= GTA02_FLASH_BASE,
-	.end		= GTA02_FLASH_BASE + GTA02_FLASH_SIZE - 1,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device gta02_nor_flash = {
-	.name		= "physmap-flash",
-	.id		= 0,
-	.dev		= {
-		.platform_data	= &gta02_nor_flash_data,
-	},
-	.resource	= &gta02_nor_flash_resource,
-	.num_resources	= 1,
-};
-
-
-struct platform_device s3c24xx_pwm_device = {
-	.name		= "s3c24xx_pwm",
-	.num_resources	= 0,
-};
-
-static struct platform_device gta02_dfbmcs320_device = {
-	.name = "dfbmcs320",
-};
-
-static struct i2c_board_info gta02_i2c_devs[] __initdata = {
-	{
-		I2C_BOARD_INFO("pcf50633", 0x73),
-		.irq = GTA02_IRQ_PCF50633,
-		.platform_data = &gta02_pcf_pdata,
-	},
-	{
-		I2C_BOARD_INFO("wm8753", 0x1a),
-	},
-};
-
-static struct s3c2410_nand_set __initdata gta02_nand_sets[] = {
-	[0] = {
-		/*
-		 * This name is also hard-coded in the boot loaders, so
-		 * changing it would would require all users to upgrade
-		 * their boot loaders, some of which are stored in a NOR
-		 * that is considered to be immutable.
-		 */
-		.name		= "neo1973-nand",
-		.nr_chips	= 1,
-		.flash_bbt	= 1,
-	},
-};
-
-/*
- * Choose a set of timings derived from S3C@2442B MCP54
- * data sheet (K5D2G13ACM-D075 MCP Memory).
- */
-
-static struct s3c2410_platform_nand __initdata gta02_nand_info = {
-	.tacls		= 0,
-	.twrph0		= 25,
-	.twrph1		= 15,
-	.nr_sets	= ARRAY_SIZE(gta02_nand_sets),
-	.sets		= gta02_nand_sets,
-};
-
-
-/* Get PMU to set USB current limit accordingly. */
-static struct s3c2410_udc_mach_info gta02_udc_cfg __initdata = {
-	.vbus_draw	= gta02_udc_vbus_draw,
-	.pullup_pin = GTA02_GPIO_USB_PULLUP,
-};
-
-/* USB */
-static struct s3c2410_hcd_info gta02_usb_info __initdata = {
-	.port[0]	= {
-		.flags	= S3C_HCDFLG_USED,
-	},
-	.port[1]	= {
-		.flags	= 0,
-	},
-};
-
-/* Touchscreen */
-static struct s3c2410_ts_mach_info gta02_ts_info = {
-	.delay			= 10000,
-	.presc			= 0xff, /* slow as we can go */
-	.oversampling_shift	= 2,
-};
-
-/* Buttons */
-static struct gpio_keys_button gta02_buttons[] = {
-	{
-		.gpio = GTA02_GPIO_AUX_KEY,
-		.code = KEY_PHONE,
-		.desc = "Aux",
-		.type = EV_KEY,
-		.debounce_interval = 100,
-	},
-	{
-		.gpio = GTA02_GPIO_HOLD_KEY,
-		.code = KEY_PAUSE,
-		.desc = "Hold",
-		.type = EV_KEY,
-		.debounce_interval = 100,
-	},
-};
-
-static struct gpio_keys_platform_data gta02_buttons_pdata = {
-	.buttons = gta02_buttons,
-	.nbuttons = ARRAY_SIZE(gta02_buttons),
-};
-
-static struct platform_device gta02_buttons_device = {
-	.name = "gpio-keys",
-	.id = -1,
-	.dev = {
-		.platform_data = &gta02_buttons_pdata,
-	},
-};
-
-static void __init gta02_map_io(void)
-{
-	s3c24xx_init_io(gta02_iodesc, ARRAY_SIZE(gta02_iodesc));
-	s3c24xx_init_clocks(12000000);
-	s3c24xx_init_uarts(gta02_uartcfgs, ARRAY_SIZE(gta02_uartcfgs));
-}
-
-
-/* These are the guys that don't need to be children of PMU. */
-
-static struct platform_device *gta02_devices[] __initdata = {
-	&s3c_device_ohci,
-	&s3c_device_wdt,
-	&s3c_device_sdi,
-	&s3c_device_usbgadget,
-	&s3c_device_nand,
-	&gta02_nor_flash,
-	&s3c24xx_pwm_device,
-	&s3c_device_iis,
-	&samsung_asoc_dma,
-	&s3c_device_i2c0,
-	&gta02_dfbmcs320_device,
-	&gta02_buttons_device,
-	&s3c_device_adc,
-	&s3c_device_ts,
-};
-
-/* These guys DO need to be children of PMU. */
-
-static struct platform_device *gta02_devices_pmu_children[] = {
-};
-
-
-/*
- * This is called when pc50633 is probed, quite late in the day since it is an
- * I2C bus device.  Here we can define platform devices with the advantage that
- * we can mark the pcf50633 as the parent.  This makes them get suspended and
- * resumed with their parent the pcf50633 still around.  All devices whose
- * operation depends on something from pcf50633 must have this relationship
- * made explicit like this, or suspend and resume will become an unreliable
- * hellworld.
- */
-
-static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf)
-{
-	int n;
-
-	/* Grab a copy of the now probed PMU pointer. */
-	gta02_pcf = pcf;
-
-	for (n = 0; n < ARRAY_SIZE(gta02_devices_pmu_children); n++)
-		gta02_devices_pmu_children[n]->dev.parent = pcf->dev;
-
-	platform_add_devices(gta02_devices_pmu_children,
-			     ARRAY_SIZE(gta02_devices_pmu_children));
-}
-
-static void gta02_poweroff(void)
-{
-	pcf50633_reg_set_bit_mask(gta02_pcf, PCF50633_REG_OOCSHDWN, 1, 1);
-}
-
-static void __init gta02_machine_init(void)
-{
-	/* Set the panic callback to turn AUX LED on or off. */
-	panic_blink = gta02_panic_blink;
-
-	s3c_pm_init();
-
-#ifdef CONFIG_CHARGER_PCF50633
-	INIT_DELAYED_WORK(&gta02_charger_work, gta02_charger_worker);
-#endif
-
-	s3c24xx_udc_set_platdata(&gta02_udc_cfg);
-	s3c24xx_ts_set_platdata(&gta02_ts_info);
-	s3c_ohci_set_platdata(&gta02_usb_info);
-	s3c_nand_set_platdata(&gta02_nand_info);
-	s3c_i2c0_set_platdata(NULL);
-
-	i2c_register_board_info(0, gta02_i2c_devs, ARRAY_SIZE(gta02_i2c_devs));
-
-	platform_add_devices(gta02_devices, ARRAY_SIZE(gta02_devices));
-	pm_power_off = gta02_poweroff;
-
-	regulator_has_full_constraints();
-}
-
-
-MACHINE_START(NEO1973_GTA02, "GTA02")
-	/* Maintainer: Nelson Castillo <arhuaco@freaks-unidos.net> */
-	.atag_offset	= 0x100,
-	.map_io		= gta02_map_io,
-	.init_irq	= s3c24xx_init_irq,
-	.init_machine	= gta02_machine_init,
-	.timer		= &s3c24xx_timer,
-	.restart	= s3c244x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-rx1950.c b/arch/arm/mach-s3c2440/mach-rx1950.c
deleted file mode 100644
index 6f68abf..0000000
--- a/arch/arm/mach-s3c2440/mach-rx1950.c
+++ /dev/null
@@ -1,826 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/mach-rx1950.c
- *
- * Copyright (c) 2006-2009 Victor Chukhantsev, Denis Grigoriev,
- * Copyright (c) 2007-2010 Vasily Khoruzhick
- *
- * based on smdk2440 written by Ben Dooks
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/memblock.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/serial_core.h>
-#include <linux/input.h>
-#include <linux/gpio_keys.h>
-#include <linux/device.h>
-#include <linux/pda_power.h>
-#include <linux/pwm_backlight.h>
-#include <linux/pwm.h>
-#include <linux/s3c_adc_battery.h>
-#include <linux/leds.h>
-#include <linux/i2c.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-
-#include <linux/mmc/host.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach-types.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/regs-gpioj.h>
-#include <mach/regs-lcd.h>
-#include <mach/h1940.h>
-#include <mach/fb.h>
-
-#include <plat/clock.h>
-#include <plat/regs-serial.h>
-#include <plat/regs-iic.h>
-#include <plat/mci.h>
-#include <plat/udc.h>
-#include <plat/nand.h>
-#include <plat/iic.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/irq.h>
-#include <plat/ts.h>
-
-#include <sound/uda1380.h>
-
-#include "common.h"
-
-#define LCD_PWM_PERIOD 192960
-#define LCD_PWM_DUTY 127353
-
-static struct map_desc rx1950_iodesc[] __initdata = {
-};
-
-static struct s3c2410_uartcfg rx1950_uartcfgs[] __initdata = {
-	[0] = {
-	       .hwport = 0,
-	       .flags = 0,
-	       .ucon = 0x3c5,
-	       .ulcon = 0x03,
-	       .ufcon = 0x51,
-		.clk_sel = S3C2410_UCON_CLKSEL3,
-	},
-	[1] = {
-	       .hwport = 1,
-	       .flags = 0,
-	       .ucon = 0x3c5,
-	       .ulcon = 0x03,
-	       .ufcon = 0x51,
-		.clk_sel = S3C2410_UCON_CLKSEL3,
-	},
-	/* IR port */
-	[2] = {
-	       .hwport = 2,
-	       .flags = 0,
-	       .ucon = 0x3c5,
-	       .ulcon = 0x43,
-	       .ufcon = 0xf1,
-		.clk_sel = S3C2410_UCON_CLKSEL3,
-	},
-};
-
-static struct s3c2410fb_display rx1950_display = {
-	.type = S3C2410_LCDCON1_TFT,
-	.width = 240,
-	.height = 320,
-	.xres = 240,
-	.yres = 320,
-	.bpp = 16,
-
-	.pixclock = 260000,
-	.left_margin = 10,
-	.right_margin = 20,
-	.hsync_len = 10,
-	.upper_margin = 2,
-	.lower_margin = 2,
-	.vsync_len = 2,
-
-	.lcdcon5 = S3C2410_LCDCON5_FRM565 |
-			   S3C2410_LCDCON5_INVVCLK |
-			   S3C2410_LCDCON5_INVVLINE |
-			   S3C2410_LCDCON5_INVVFRAME |
-			   S3C2410_LCDCON5_HWSWP |
-			   (0x02 << 13) |
-			   (0x02 << 15),
-
-};
-
-static int power_supply_init(struct device *dev)
-{
-	return gpio_request(S3C2410_GPF(2), "cable plugged");
-}
-
-static int rx1950_is_ac_online(void)
-{
-	return !gpio_get_value(S3C2410_GPF(2));
-}
-
-static void power_supply_exit(struct device *dev)
-{
-	gpio_free(S3C2410_GPF(2));
-}
-
-static char *rx1950_supplicants[] = {
-	"main-battery"
-};
-
-static struct pda_power_pdata power_supply_info = {
-	.init			= power_supply_init,
-	.is_ac_online		= rx1950_is_ac_online,
-	.exit			= power_supply_exit,
-	.supplied_to		= rx1950_supplicants,
-	.num_supplicants	= ARRAY_SIZE(rx1950_supplicants),
-};
-
-static struct resource power_supply_resources[] = {
-	[0] = {
-			.name	= "ac",
-			.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE |
-					  IORESOURCE_IRQ_HIGHEDGE,
-			.start	= IRQ_EINT2,
-			.end	= IRQ_EINT2,
-	},
-};
-
-static struct platform_device power_supply = {
-	.name			= "pda-power",
-	.id			= -1,
-	.dev			= {
-					.platform_data =
-						&power_supply_info,
-	},
-	.resource		= power_supply_resources,
-	.num_resources		= ARRAY_SIZE(power_supply_resources),
-};
-
-static const struct s3c_adc_bat_thresh bat_lut_noac[] = {
-	{ .volt = 4100, .cur = 156, .level = 100},
-	{ .volt = 4050, .cur = 156, .level = 95},
-	{ .volt = 4025, .cur = 141, .level = 90},
-	{ .volt = 3995, .cur = 144, .level = 85},
-	{ .volt = 3957, .cur = 162, .level = 80},
-	{ .volt = 3931, .cur = 147, .level = 75},
-	{ .volt = 3902, .cur = 147, .level = 70},
-	{ .volt = 3863, .cur = 153, .level = 65},
-	{ .volt = 3838, .cur = 150, .level = 60},
-	{ .volt = 3800, .cur = 153, .level = 55},
-	{ .volt = 3765, .cur = 153, .level = 50},
-	{ .volt = 3748, .cur = 172, .level = 45},
-	{ .volt = 3740, .cur = 153, .level = 40},
-	{ .volt = 3714, .cur = 175, .level = 35},
-	{ .volt = 3710, .cur = 156, .level = 30},
-	{ .volt = 3963, .cur = 156, .level = 25},
-	{ .volt = 3672, .cur = 178, .level = 20},
-	{ .volt = 3651, .cur = 178, .level = 15},
-	{ .volt = 3629, .cur = 178, .level = 10},
-	{ .volt = 3612, .cur = 162, .level = 5},
-	{ .volt = 3605, .cur = 162, .level = 0},
-};
-
-static const struct s3c_adc_bat_thresh bat_lut_acin[] = {
-	{ .volt = 4200, .cur = 0, .level = 100},
-	{ .volt = 4190, .cur = 0, .level = 99},
-	{ .volt = 4178, .cur = 0, .level = 95},
-	{ .volt = 4110, .cur = 0, .level = 70},
-	{ .volt = 4076, .cur = 0, .level = 65},
-	{ .volt = 4046, .cur = 0, .level = 60},
-	{ .volt = 4021, .cur = 0, .level = 55},
-	{ .volt = 3999, .cur = 0, .level = 50},
-	{ .volt = 3982, .cur = 0, .level = 45},
-	{ .volt = 3965, .cur = 0, .level = 40},
-	{ .volt = 3957, .cur = 0, .level = 35},
-	{ .volt = 3948, .cur = 0, .level = 30},
-	{ .volt = 3936, .cur = 0, .level = 25},
-	{ .volt = 3927, .cur = 0, .level = 20},
-	{ .volt = 3906, .cur = 0, .level = 15},
-	{ .volt = 3880, .cur = 0, .level = 10},
-	{ .volt = 3829, .cur = 0, .level = 5},
-	{ .volt = 3820, .cur = 0, .level = 0},
-};
-
-int rx1950_bat_init(void)
-{
-	int ret;
-
-	ret = gpio_request(S3C2410_GPJ(2), "rx1950-charger-enable-1");
-	if (ret)
-		goto err_gpio1;
-	ret = gpio_request(S3C2410_GPJ(3), "rx1950-charger-enable-2");
-	if (ret)
-		goto err_gpio2;
-
-	return 0;
-
-err_gpio2:
-	gpio_free(S3C2410_GPJ(2));
-err_gpio1:
-	return ret;
-}
-
-void rx1950_bat_exit(void)
-{
-	gpio_free(S3C2410_GPJ(2));
-	gpio_free(S3C2410_GPJ(3));
-}
-
-void rx1950_enable_charger(void)
-{
-	gpio_direction_output(S3C2410_GPJ(2), 1);
-	gpio_direction_output(S3C2410_GPJ(3), 1);
-}
-
-void rx1950_disable_charger(void)
-{
-	gpio_direction_output(S3C2410_GPJ(2), 0);
-	gpio_direction_output(S3C2410_GPJ(3), 0);
-}
-
-DEFINE_SPINLOCK(rx1950_blink_spin);
-
-static int rx1950_led_blink_set(unsigned gpio, int state,
-	unsigned long *delay_on, unsigned long *delay_off)
-{
-	int blink_gpio, check_gpio;
-
-	switch (gpio) {
-	case S3C2410_GPA(6):
-		blink_gpio = S3C2410_GPA(4);
-		check_gpio = S3C2410_GPA(3);
-		break;
-	case S3C2410_GPA(7):
-		blink_gpio = S3C2410_GPA(3);
-		check_gpio = S3C2410_GPA(4);
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
-
-	if (delay_on && delay_off && !*delay_on && !*delay_off)
-		*delay_on = *delay_off = 500;
-
-	spin_lock(&rx1950_blink_spin);
-
-	switch (state) {
-	case GPIO_LED_NO_BLINK_LOW:
-	case GPIO_LED_NO_BLINK_HIGH:
-		if (!gpio_get_value(check_gpio))
-			gpio_set_value(S3C2410_GPJ(6), 0);
-		gpio_set_value(blink_gpio, 0);
-		gpio_set_value(gpio, state);
-		break;
-	case GPIO_LED_BLINK:
-		gpio_set_value(gpio, 0);
-		gpio_set_value(S3C2410_GPJ(6), 1);
-		gpio_set_value(blink_gpio, 1);
-		break;
-	}
-
-	spin_unlock(&rx1950_blink_spin);
-
-	return 0;
-}
-
-static struct gpio_led rx1950_leds_desc[] = {
-	{
-		.name			= "Green",
-		.default_trigger	= "main-battery-full",
-		.gpio			= S3C2410_GPA(6),
-		.retain_state_suspended	= 1,
-	},
-	{
-		.name			= "Red",
-		.default_trigger
-			= "main-battery-charging-blink-full-solid",
-		.gpio			= S3C2410_GPA(7),
-		.retain_state_suspended	= 1,
-	},
-	{
-		.name			= "Blue",
-		.default_trigger	= "rx1950-acx-mem",
-		.gpio			= S3C2410_GPA(11),
-		.retain_state_suspended	= 1,
-	},
-};
-
-static struct gpio_led_platform_data rx1950_leds_pdata = {
-	.num_leds	= ARRAY_SIZE(rx1950_leds_desc),
-	.leds		= rx1950_leds_desc,
-	.gpio_blink_set	= rx1950_led_blink_set,
-};
-
-static struct platform_device rx1950_leds = {
-	.name	= "leds-gpio",
-	.id		= -1,
-	.dev	= {
-				.platform_data = &rx1950_leds_pdata,
-	},
-};
-
-static struct s3c_adc_bat_pdata rx1950_bat_cfg = {
-	.init = rx1950_bat_init,
-	.exit = rx1950_bat_exit,
-	.enable_charger = rx1950_enable_charger,
-	.disable_charger = rx1950_disable_charger,
-	.gpio_charge_finished = S3C2410_GPF(3),
-	.lut_noac = bat_lut_noac,
-	.lut_noac_cnt = ARRAY_SIZE(bat_lut_noac),
-	.lut_acin = bat_lut_acin,
-	.lut_acin_cnt = ARRAY_SIZE(bat_lut_acin),
-	.volt_channel = 0,
-	.current_channel = 1,
-	.volt_mult = 4235,
-	.current_mult = 2900,
-	.internal_impedance = 200,
-};
-
-static struct platform_device rx1950_battery = {
-	.name             = "s3c-adc-battery",
-	.id               = -1,
-	.dev = {
-		.parent = &s3c_device_adc.dev,
-		.platform_data = &rx1950_bat_cfg,
-	},
-};
-
-static struct s3c2410fb_mach_info rx1950_lcd_cfg = {
-	.displays = &rx1950_display,
-	.num_displays = 1,
-	.default_display = 0,
-
-	.lpcsel = 0x02,
-	.gpccon = 0xaa9556a9,
-	.gpccon_mask = 0xffc003fc,
-	.gpcup = 0x0000ffff,
-	.gpcup_mask = 0xffffffff,
-
-	.gpdcon = 0xaa90aaa1,
-	.gpdcon_mask = 0xffc0fff0,
-	.gpdup = 0x0000fcfd,
-	.gpdup_mask = 0xffffffff,
-
-};
-
-static struct pwm_device *lcd_pwm;
-
-void rx1950_lcd_power(int enable)
-{
-	int i;
-	static int enabled;
-	if (enabled == enable)
-		return;
-	if (!enable) {
-
-		/* GPC11-GPC15->OUTPUT */
-		for (i = 11; i < 16; i++)
-			gpio_direction_output(S3C2410_GPC(i), 1);
-
-		/* Wait a bit here... */
-		mdelay(100);
-
-		/* GPD2-GPD7->OUTPUT */
-		/* GPD11-GPD15->OUTPUT */
-		/* GPD2-GPD7->1, GPD11-GPD15->1 */
-		for (i = 2; i < 8; i++)
-			gpio_direction_output(S3C2410_GPD(i), 1);
-		for (i = 11; i < 16; i++)
-			gpio_direction_output(S3C2410_GPD(i), 1);
-
-		/* Wait a bit here...*/
-		mdelay(100);
-
-		/* GPB0->OUTPUT, GPB0->0 */
-		gpio_direction_output(S3C2410_GPB(0), 0);
-
-		/* GPC1-GPC4->OUTPUT, GPC1-4->0 */
-		for (i = 1; i < 5; i++)
-			gpio_direction_output(S3C2410_GPC(i), 0);
-
-		/* GPC15-GPC11->0 */
-		for (i = 11; i < 16; i++)
-			gpio_direction_output(S3C2410_GPC(i), 0);
-
-		/* GPD15-GPD11->0, GPD2->GPD7->0 */
-		for (i = 11; i < 16; i++)
-			gpio_direction_output(S3C2410_GPD(i), 0);
-
-		for (i = 2; i < 8; i++)
-			gpio_direction_output(S3C2410_GPD(i), 0);
-
-		/* GPC6->0, GPC7->0, GPC5->0 */
-		gpio_direction_output(S3C2410_GPC(6), 0);
-		gpio_direction_output(S3C2410_GPC(7), 0);
-		gpio_direction_output(S3C2410_GPC(5), 0);
-
-		/* GPB1->OUTPUT, GPB1->0 */
-		gpio_direction_output(S3C2410_GPB(1), 0);
-		pwm_config(lcd_pwm, 0, LCD_PWM_PERIOD);
-		pwm_disable(lcd_pwm);
-
-		/* GPC0->0, GPC10->0 */
-		gpio_direction_output(S3C2410_GPC(0), 0);
-		gpio_direction_output(S3C2410_GPC(10), 0);
-	} else {
-		pwm_config(lcd_pwm, LCD_PWM_DUTY, LCD_PWM_PERIOD);
-		pwm_enable(lcd_pwm);
-
-		gpio_direction_output(S3C2410_GPC(0), 1);
-		gpio_direction_output(S3C2410_GPC(5), 1);
-
-		s3c_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPB1_TOUT1);
-		gpio_direction_output(S3C2410_GPC(7), 1);
-
-		for (i = 1; i < 5; i++)
-			s3c_gpio_cfgpin(S3C2410_GPC(i), S3C_GPIO_SFN(2));
-
-		for (i = 11; i < 16; i++)
-			s3c_gpio_cfgpin(S3C2410_GPC(i), S3C_GPIO_SFN(2));
-
-		for (i = 2; i < 8; i++)
-			s3c_gpio_cfgpin(S3C2410_GPD(i), S3C_GPIO_SFN(2));
-
-		for (i = 11; i < 16; i++)
-			s3c_gpio_cfgpin(S3C2410_GPD(i), S3C_GPIO_SFN(2));
-
-		gpio_direction_output(S3C2410_GPC(10), 1);
-		gpio_direction_output(S3C2410_GPC(6), 1);
-	}
-	enabled = enable;
-}
-
-static void rx1950_bl_power(int enable)
-{
-	static int enabled;
-	if (enabled == enable)
-		return;
-	if (!enable) {
-			gpio_direction_output(S3C2410_GPB(0), 0);
-	} else {
-			/* LED driver need a "push" to power on */
-			gpio_direction_output(S3C2410_GPB(0), 1);
-			/* Warm up backlight for one period of PWM.
-			 * Without this trick its almost impossible to
-			 * enable backlight with low brightness value
-			 */
-			ndelay(48000);
-			s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
-	}
-	enabled = enable;
-}
-
-static int rx1950_backlight_init(struct device *dev)
-{
-	WARN_ON(gpio_request(S3C2410_GPB(0), "Backlight"));
-	lcd_pwm = pwm_request(1, "RX1950 LCD");
-	if (IS_ERR(lcd_pwm)) {
-		dev_err(dev, "Unable to request PWM for LCD power!\n");
-		return PTR_ERR(lcd_pwm);
-	}
-
-	rx1950_lcd_power(1);
-	rx1950_bl_power(1);
-
-	return 0;
-}
-
-static void rx1950_backlight_exit(struct device *dev)
-{
-	rx1950_bl_power(0);
-	rx1950_lcd_power(0);
-
-	pwm_free(lcd_pwm);
-	gpio_free(S3C2410_GPB(0));
-}
-
-
-static int rx1950_backlight_notify(struct device *dev, int brightness)
-{
-	if (!brightness) {
-		rx1950_bl_power(0);
-		rx1950_lcd_power(0);
-	} else {
-		rx1950_lcd_power(1);
-		rx1950_bl_power(1);
-	}
-	return brightness;
-}
-
-static struct platform_pwm_backlight_data rx1950_backlight_data = {
-	.pwm_id = 0,
-	.max_brightness = 24,
-	.dft_brightness = 4,
-	.pwm_period_ns = 48000,
-	.init = rx1950_backlight_init,
-	.notify = rx1950_backlight_notify,
-	.exit = rx1950_backlight_exit,
-};
-
-static struct platform_device rx1950_backlight = {
-	.name = "pwm-backlight",
-	.dev = {
-		.parent = &s3c_device_timer[0].dev,
-		.platform_data = &rx1950_backlight_data,
-	},
-};
-
-static void rx1950_set_mmc_power(unsigned char power_mode, unsigned short vdd)
-{
-	switch (power_mode) {
-	case MMC_POWER_OFF:
-		gpio_direction_output(S3C2410_GPJ(1), 0);
-		break;
-	case MMC_POWER_UP:
-	case MMC_POWER_ON:
-		gpio_direction_output(S3C2410_GPJ(1), 1);
-		break;
-	default:
-		break;
-	}
-}
-
-static struct s3c24xx_mci_pdata rx1950_mmc_cfg __initdata = {
-	.gpio_detect = S3C2410_GPF(5),
-	.gpio_wprotect = S3C2410_GPH(8),
-	.set_power = rx1950_set_mmc_power,
-	.ocr_avail = MMC_VDD_32_33,
-};
-
-static struct mtd_partition rx1950_nand_part[] = {
-	[0] = {
-			.name = "Boot0",
-			.offset = 0,
-			.size = 0x4000,
-			.mask_flags = MTD_WRITEABLE,
-	},
-	[1] = {
-			.name = "Boot1",
-			.offset = MTDPART_OFS_APPEND,
-			.size = 0x40000,
-			.mask_flags = MTD_WRITEABLE,
-	},
-	[2] = {
-			.name = "Kernel",
-			.offset = MTDPART_OFS_APPEND,
-			.size = 0x300000,
-			.mask_flags = 0,
-	},
-	[3] = {
-			.name = "Filesystem",
-			.offset = MTDPART_OFS_APPEND,
-			.size = MTDPART_SIZ_FULL,
-			.mask_flags = 0,
-	},
-};
-
-static struct s3c2410_nand_set rx1950_nand_sets[] = {
-	[0] = {
-			.name = "Internal",
-			.nr_chips = 1,
-			.nr_partitions = ARRAY_SIZE(rx1950_nand_part),
-			.partitions = rx1950_nand_part,
-	},
-};
-
-static struct s3c2410_platform_nand rx1950_nand_info = {
-	.tacls = 25,
-	.twrph0 = 50,
-	.twrph1 = 15,
-	.nr_sets = ARRAY_SIZE(rx1950_nand_sets),
-	.sets = rx1950_nand_sets,
-};
-
-static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {
-	.vbus_pin = S3C2410_GPG(5),
-	.vbus_pin_inverted = 1,
-	.pullup_pin = S3C2410_GPJ(5),
-};
-
-static struct s3c2410_ts_mach_info rx1950_ts_cfg __initdata = {
-	.delay = 10000,
-	.presc = 49,
-	.oversampling_shift = 3,
-};
-
-static struct gpio_keys_button rx1950_gpio_keys_table[] = {
-	{
-		.code		= KEY_POWER,
-		.gpio		= S3C2410_GPF(0),
-		.active_low	= 1,
-		.desc		= "Power button",
-		.wakeup		= 1,
-	},
-	{
-		.code		= KEY_F5,
-		.gpio		= S3C2410_GPF(7),
-		.active_low	= 1,
-		.desc		= "Record button",
-	},
-	{
-		.code		= KEY_F1,
-		.gpio		= S3C2410_GPG(0),
-		.active_low	= 1,
-		.desc		= "Calendar button",
-	},
-	{
-		.code		= KEY_F2,
-		.gpio		= S3C2410_GPG(2),
-		.active_low	= 1,
-		.desc		= "Contacts button",
-	},
-	{
-		.code		= KEY_F3,
-		.gpio		= S3C2410_GPG(3),
-		.active_low	= 1,
-		.desc		= "Mail button",
-	},
-	{
-		.code		= KEY_F4,
-		.gpio		= S3C2410_GPG(7),
-		.active_low	= 1,
-		.desc		= "WLAN button",
-	},
-	{
-		.code		= KEY_LEFT,
-		.gpio		= S3C2410_GPG(10),
-		.active_low	= 1,
-		.desc		= "Left button",
-	},
-	{
-		.code		= KEY_RIGHT,
-		.gpio		= S3C2410_GPG(11),
-		.active_low	= 1,
-		.desc		= "Right button",
-	},
-	{
-		.code		= KEY_UP,
-		.gpio		= S3C2410_GPG(4),
-		.active_low	= 1,
-		.desc		= "Up button",
-	},
-	{
-		.code		= KEY_DOWN,
-		.gpio		= S3C2410_GPG(6),
-		.active_low	= 1,
-		.desc		= "Down button",
-	},
-	{
-		.code		= KEY_ENTER,
-		.gpio		= S3C2410_GPG(9),
-		.active_low	= 1,
-		.desc		= "Ok button"
-	},
-};
-
-static struct gpio_keys_platform_data rx1950_gpio_keys_data = {
-	.buttons = rx1950_gpio_keys_table,
-	.nbuttons = ARRAY_SIZE(rx1950_gpio_keys_table),
-};
-
-static struct platform_device rx1950_device_gpiokeys = {
-	.name = "gpio-keys",
-	.dev.platform_data = &rx1950_gpio_keys_data,
-};
-
-static struct uda1380_platform_data uda1380_info = {
-	.gpio_power	= S3C2410_GPJ(0),
-	.gpio_reset	= S3C2410_GPD(0),
-	.dac_clk	= UDA1380_DAC_CLK_SYSCLK,
-};
-
-static struct i2c_board_info rx1950_i2c_devices[] = {
-	{
-		I2C_BOARD_INFO("uda1380", 0x1a),
-		.platform_data = &uda1380_info,
-	},
-};
-
-static struct platform_device *rx1950_devices[] __initdata = {
-	&s3c_device_lcd,
-	&s3c_device_wdt,
-	&s3c_device_i2c0,
-	&s3c_device_iis,
-	&samsung_asoc_dma,
-	&s3c_device_usbgadget,
-	&s3c_device_rtc,
-	&s3c_device_nand,
-	&s3c_device_sdi,
-	&s3c_device_adc,
-	&s3c_device_ts,
-	&s3c_device_timer[0],
-	&s3c_device_timer[1],
-	&rx1950_backlight,
-	&rx1950_device_gpiokeys,
-	&power_supply,
-	&rx1950_battery,
-	&rx1950_leds,
-};
-
-static struct clk *rx1950_clocks[] __initdata = {
-	&s3c24xx_clkout0,
-	&s3c24xx_clkout1,
-};
-
-static void __init rx1950_map_io(void)
-{
-	s3c24xx_clkout0.parent  = &clk_h;
-	s3c24xx_clkout1.parent  = &clk_f;
-
-	s3c24xx_register_clocks(rx1950_clocks, ARRAY_SIZE(rx1950_clocks));
-
-	s3c24xx_init_io(rx1950_iodesc, ARRAY_SIZE(rx1950_iodesc));
-	s3c24xx_init_clocks(16934000);
-	s3c24xx_init_uarts(rx1950_uartcfgs, ARRAY_SIZE(rx1950_uartcfgs));
-
-	/* setup PM */
-
-#ifdef CONFIG_PM_H1940
-	memcpy(phys_to_virt(H1940_SUSPEND_RESUMEAT), h1940_pm_return, 8);
-#endif
-
-	s3c_pm_init();
-}
-
-static void __init rx1950_init_machine(void)
-{
-	int i;
-
-	s3c24xx_fb_set_platdata(&rx1950_lcd_cfg);
-	s3c24xx_udc_set_platdata(&rx1950_udc_cfg);
-	s3c24xx_ts_set_platdata(&rx1950_ts_cfg);
-	s3c24xx_mci_set_platdata(&rx1950_mmc_cfg);
-	s3c_i2c0_set_platdata(NULL);
-	s3c_nand_set_platdata(&rx1950_nand_info);
-
-	/* Turn off suspend on both USB ports, and switch the
-	 * selectable USB port to USB device mode. */
-	s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
-						S3C2410_MISCCR_USBSUSPND0 |
-						S3C2410_MISCCR_USBSUSPND1, 0x0);
-
-	/* mmc power is disabled by default */
-	WARN_ON(gpio_request(S3C2410_GPJ(1), "MMC power"));
-	gpio_direction_output(S3C2410_GPJ(1), 0);
-
-	for (i = 0; i < 8; i++)
-		WARN_ON(gpio_request(S3C2410_GPC(i), "LCD power"));
-
-	for (i = 10; i < 16; i++)
-		WARN_ON(gpio_request(S3C2410_GPC(i), "LCD power"));
-
-	for (i = 2; i < 8; i++)
-		WARN_ON(gpio_request(S3C2410_GPD(i), "LCD power"));
-
-	for (i = 11; i < 16; i++)
-		WARN_ON(gpio_request(S3C2410_GPD(i), "LCD power"));
-
-	WARN_ON(gpio_request(S3C2410_GPB(1), "LCD power"));
-
-	WARN_ON(gpio_request(S3C2410_GPA(3), "Red blink"));
-	WARN_ON(gpio_request(S3C2410_GPA(4), "Green blink"));
-	WARN_ON(gpio_request(S3C2410_GPJ(6), "LED blink"));
-	gpio_direction_output(S3C2410_GPA(3), 0);
-	gpio_direction_output(S3C2410_GPA(4), 0);
-	gpio_direction_output(S3C2410_GPJ(6), 0);
-
-	platform_add_devices(rx1950_devices, ARRAY_SIZE(rx1950_devices));
-
-	i2c_register_board_info(0, rx1950_i2c_devices,
-		ARRAY_SIZE(rx1950_i2c_devices));
-}
-
-/* H1940 and RX3715 need to reserve this for suspend */
-static void __init rx1950_reserve(void)
-{
-	memblock_reserve(0x30003000, 0x1000);
-	memblock_reserve(0x30081000, 0x1000);
-}
-
-MACHINE_START(RX1950, "HP iPAQ RX1950")
-    /* Maintainers: Vasily Khoruzhick */
-	.atag_offset = 0x100,
-	.map_io = rx1950_map_io,
-	.reserve	= rx1950_reserve,
-	.init_irq = s3c24xx_init_irq,
-	.init_machine = rx1950_init_machine,
-	.timer = &s3c24xx_timer,
-	.restart	= s3c244x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2440/s3c244x.c b/arch/arm/mach-s3c2440/s3c244x.c
deleted file mode 100644
index d15852f..0000000
--- a/arch/arm/mach-s3c2440/s3c244x.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/s3c244x.c
- *
- * Copyright (c) 2004-2006 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * Samsung S3C2440 and S3C2442 Mobile CPU support (not S3C2443)
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <plat/cpu-freq.h>
-
-#include <mach/regs-clock.h>
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-gpioj.h>
-#include <mach/regs-dsc.h>
-
-#include <plat/s3c2410.h>
-#include <plat/s3c244x.h>
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/pll.h>
-#include <plat/nand-core.h>
-#include <plat/watchdog-reset.h>
-
-static struct map_desc s3c244x_iodesc[] __initdata = {
-	IODESC_ENT(CLKPWR),
-	IODESC_ENT(TIMER),
-	IODESC_ENT(WATCHDOG),
-};
-
-/* uart initialisation */
-
-void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-	s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
-}
-
-void __init s3c244x_map_io(void)
-{
-	/* register our io-tables */
-
-	iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
-
-	/* rename any peripherals used differing from the s3c2410 */
-
-	s3c_device_sdi.name  = "s3c2440-sdi";
-	s3c_device_i2c0.name  = "s3c2440-i2c";
-	s3c_nand_setname("s3c2440-nand");
-	s3c_device_ts.name = "s3c2440-ts";
-	s3c_device_usbgadget.name = "s3c2440-usbgadget";
-}
-
-void __init_or_cpufreq s3c244x_setup_clocks(void)
-{
-	struct clk *xtal_clk;
-	unsigned long clkdiv;
-	unsigned long camdiv;
-	unsigned long xtal;
-	unsigned long hclk, fclk, pclk;
-	int hdiv = 1;
-
-	xtal_clk = clk_get(NULL, "xtal");
-	xtal = clk_get_rate(xtal_clk);
-	clk_put(xtal_clk);
-
-	fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
-
-	clkdiv = __raw_readl(S3C2410_CLKDIVN);
-	camdiv = __raw_readl(S3C2440_CAMDIVN);
-
-	/* work out clock scalings */
-
-	switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
-	case S3C2440_CLKDIVN_HDIVN_1:
-		hdiv = 1;
-		break;
-
-	case S3C2440_CLKDIVN_HDIVN_2:
-		hdiv = 2;
-		break;
-
-	case S3C2440_CLKDIVN_HDIVN_4_8:
-		hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
-		break;
-
-	case S3C2440_CLKDIVN_HDIVN_3_6:
-		hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
-		break;
-	}
-
-	hclk = fclk / hdiv;
-	pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN) ? 2 : 1);
-
-	/* print brief summary of clocks, etc */
-
-	printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
-	       print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
-
-	s3c24xx_setup_clocks(fclk, hclk, pclk);
-}
-
-void __init s3c244x_init_clocks(int xtal)
-{
-	/* initialise the clocks here, to allow other things like the
-	 * console to use them, and to add new ones after the initialisation
-	 */
-
-	s3c24xx_register_baseclocks(xtal);
-	s3c244x_setup_clocks();
-	s3c2410_baseclk_add();
-}
-
-/* Since the S3C2442 and S3C2440 share items, put both subsystems here */
-
-struct bus_type s3c2440_subsys = {
-	.name		= "s3c2440-core",
-	.dev_name	= "s3c2440-core",
-};
-
-struct bus_type s3c2442_subsys = {
-	.name		= "s3c2442-core",
-	.dev_name	= "s3c2442-core",
-};
-
-/* need to register the subsystem before we actually register the device, and
- * we also need to ensure that it has been initialised before any of the
- * drivers even try to use it (even if not on an s3c2440 based system)
- * as a driver which may support both 2410 and 2440 may try and use it.
-*/
-
-static int __init s3c2440_core_init(void)
-{
-	return subsys_system_register(&s3c2440_subsys, NULL);
-}
-
-core_initcall(s3c2440_core_init);
-
-static int __init s3c2442_core_init(void)
-{
-	return subsys_system_register(&s3c2442_subsys, NULL);
-}
-
-core_initcall(s3c2442_core_init);
-
-
-#ifdef CONFIG_PM
-static struct sleep_save s3c244x_sleep[] = {
-	SAVE_ITEM(S3C2440_DSC0),
-	SAVE_ITEM(S3C2440_DSC1),
-	SAVE_ITEM(S3C2440_GPJDAT),
-	SAVE_ITEM(S3C2440_GPJCON),
-	SAVE_ITEM(S3C2440_GPJUP)
-};
-
-static int s3c244x_suspend(void)
-{
-	s3c_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
-	return 0;
-}
-
-static void s3c244x_resume(void)
-{
-	s3c_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
-}
-#else
-#define s3c244x_suspend NULL
-#define s3c244x_resume  NULL
-#endif
-
-struct syscore_ops s3c244x_pm_syscore_ops = {
-	.suspend	= s3c244x_suspend,
-	.resume		= s3c244x_resume,
-};
-
-void s3c244x_restart(char mode, const char *cmd)
-{
-	if (mode == 's')
-		soft_restart(0);
-
-	arch_wdt_reset();
-
-	/* we'll take a jump through zero as a poor second */
-	soft_restart(0);
-}
diff --git a/arch/arm/mach-s3c2443/Kconfig b/arch/arm/mach-s3c2443/Kconfig
deleted file mode 100644
index 8814031..0000000
--- a/arch/arm/mach-s3c2443/Kconfig
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright 2007 Simtec Electronics
-#
-# Licensed under GPLv2
-
-config CPU_S3C2443
-	bool
-	depends on ARCH_S3C2410
-	select CPU_ARM920T
-	select S3C2443_DMA if S3C2410_DMA
-	select CPU_LLSERIAL_S3C2440
-	select SAMSUNG_CLKSRC
-	select S3C2443_CLOCK
-	help
-	  Support for the S3C2443 SoC from the S3C24XX line
-
-config S3C2443_DMA
-	bool
-	depends on CPU_S3C2443
-	help
-	  Internal config node for S3C2443 DMA support
-
-menu "S3C2443 Machines"
-
-config MACH_SMDK2443
-	bool "SMDK2443"
-	select CPU_S3C2443
-	select MACH_SMDK
-	select S3C_DEV_HSMMC1
-	help
-	  Say Y here if you are using an SMDK2443
-
-endmenu
diff --git a/arch/arm/mach-s3c2443/Makefile b/arch/arm/mach-s3c2443/Makefile
deleted file mode 100644
index d1843c9..0000000
--- a/arch/arm/mach-s3c2443/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-# arch/arm/mach-s3c2443/Makefile
-#
-# Copyright 2007 Simtec Electronics
-#
-# Licensed under GPLv2
-
-obj-y				:=
-obj-m				:=
-obj-n				:=
-obj-				:=
-
-obj-$(CONFIG_CPU_S3C2443)	+= s3c2443.o
-obj-$(CONFIG_CPU_S3C2443)	+= irq.o
-obj-$(CONFIG_CPU_S3C2443)	+= clock.o
-
-obj-$(CONFIG_S3C2443_DMA)	+= dma.o
-
-# Machine support
-
-obj-$(CONFIG_MACH_SMDK2443)	+= mach-smdk2443.o
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c
deleted file mode 100644
index 6dde269..0000000
--- a/arch/arm/mach-s3c2443/clock.c
+++ /dev/null
@@ -1,222 +0,0 @@
-/* linux/arch/arm/mach-s3c2443/clock.c
- *
- * Copyright (c) 2007, 2010 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2443 Clock control support
- *
- * 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/init.h>
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/clk.h>
-#include <linux/mutex.h>
-#include <linux/serial_core.h>
-#include <linux/io.h>
-
-#include <asm/mach/map.h>
-
-#include <mach/hardware.h>
-
-#include <mach/regs-s3c2443-clock.h>
-
-#include <plat/cpu-freq.h>
-
-#include <plat/s3c2443.h>
-#include <plat/clock.h>
-#include <plat/clock-clksrc.h>
-#include <plat/cpu.h>
-
-/* We currently have to assume that the system is running
- * from the XTPll input, and that all ***REFCLKs are being
- * fed from it, as we cannot read the state of OM[4] from
- * software.
- *
- * It would be possible for each board initialisation to
- * set the correct muxing at initialisation
-*/
-
-/* clock selections */
-
-/* armdiv
- *
- * this clock is sourced from msysclk and can have a number of
- * divider values applied to it to then be fed into armclk.
- * The real clock definition is done in s3c2443-clock.c,
- * only the armdiv divisor table must be defined here.
-*/
-
-static unsigned int armdiv[16] = {
-	[S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 1,
-	[S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 2,
-	[S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 3,
-	[S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 4,
-	[S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 6,
-	[S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 8,
-	[S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 12,
-	[S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 16,
-};
-
-/* hsspi
- *
- * high-speed spi clock, sourced from esysclk
-*/
-
-static struct clksrc_clk clk_hsspi = {
-	.clk	= {
-		.name		= "hsspi-if",
-		.parent		= &clk_esysclk.clk,
-		.ctrlbit	= S3C2443_SCLKCON_HSSPICLK,
-		.enable		= s3c2443_clkcon_enable_s,
-	},
-	.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
-};
-
-
-/* clk_hsmcc_div
- *
- * this clock is sourced from epll, and is fed through a divider,
- * to a mux controlled by sclkcon where either it or a extclk can
- * be fed to the hsmmc block
-*/
-
-static struct clksrc_clk clk_hsmmc_div = {
-	.clk	= {
-		.name		= "hsmmc-div",
-		.devname	= "s3c-sdhci.1",
-		.parent		= &clk_esysclk.clk,
-	},
-	.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
-};
-
-static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
-{
-	unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
-
-	clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
-		    S3C2443_SCLKCON_HSMMCCLK_EPLL);
-
-	if (parent == &clk_epll)
-		clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
-	else if (parent == &clk_ext)
-		clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
-	else
-		return -EINVAL;
-
-	if (clk->usage > 0) {
-		__raw_writel(clksrc, S3C2443_SCLKCON);
-	}
-
-	clk->parent = parent;
-	return 0;
-}
-
-static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
-{
-	return s3c2443_setparent_hsmmc(clk, clk->parent);
-}
-
-static struct clk clk_hsmmc = {
-	.name		= "hsmmc-if",
-	.devname	= "s3c-sdhci.1",
-	.parent		= &clk_hsmmc_div.clk,
-	.enable		= s3c2443_enable_hsmmc,
-	.ops		= &(struct clk_ops) {
-		.set_parent	= s3c2443_setparent_hsmmc,
-	},
-};
-
-/* standard clock definitions */
-
-static struct clk init_clocks_off[] = {
-	{
-		.name		= "sdi",
-		.parent		= &clk_p,
-		.enable		= s3c2443_clkcon_enable_p,
-		.ctrlbit	= S3C2443_PCLKCON_SDI,
-	}, {
-		.name		= "spi",
-		.devname	= "s3c2410-spi.0",
-		.parent		= &clk_p,
-		.enable		= s3c2443_clkcon_enable_p,
-		.ctrlbit	= S3C2443_PCLKCON_SPI0,
-	}, {
-		.name		= "spi",
-		.devname	= "s3c2410-spi.1",
-		.parent		= &clk_p,
-		.enable		= s3c2443_clkcon_enable_p,
-		.ctrlbit	= S3C2443_PCLKCON_SPI1,
-	}
-};
-
-/* clocks to add straight away */
-
-static struct clksrc_clk *clksrcs[] __initdata = {
-	&clk_hsspi,
-	&clk_hsmmc_div,
-};
-
-static struct clk *clks[] __initdata = {
-	&clk_hsmmc,
-};
-
-void __init_or_cpufreq s3c2443_setup_clocks(void)
-{
-	s3c2443_common_setup_clocks(s3c2443_get_mpll);
-}
-
-void __init s3c2443_init_clocks(int xtal)
-{
-	unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
-	int ptr;
-
-	clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
-	clk_epll.parent = &clk_epllref.clk;
-
-	s3c2443_common_init_clocks(xtal, s3c2443_get_mpll,
-				   armdiv, ARRAY_SIZE(armdiv),
-				   S3C2443_CLKDIV0_ARMDIV_MASK);
-
-	s3c2443_setup_clocks();
-
-	s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
-
-	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
-		s3c_register_clksrc(clksrcs[ptr], 1);
-
-	/* We must be careful disabling the clocks we are not intending to
-	 * be using at boot time, as subsystems such as the LCD which do
-	 * their own DMA requests to the bus can cause the system to lockup
-	 * if they where in the middle of requesting bus access.
-	 *
-	 * Disabling the LCD clock if the LCD is active is very dangerous,
-	 * and therefore the bootloader should be careful to not enable
-	 * the LCD clock if it is not needed.
-	*/
-
-	/* install (and disable) the clocks we do not need immediately */
-
-	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-
-	s3c_pwmclk_init();
-}
diff --git a/arch/arm/mach-s3c2443/dma.c b/arch/arm/mach-s3c2443/dma.c
deleted file mode 100644
index 1422451..0000000
--- a/arch/arm/mach-s3c2443/dma.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/* linux/arch/arm/mach-s3c2443/dma.c
- *
- * Copyright (c) 2007 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2443 DMA selection
- *
- * http://armlinux.simtec.co.uk/
- *
- * 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/device.h>
-#include <linux/serial_core.h>
-#include <linux/io.h>
-
-#include <mach/dma.h>
-
-#include <plat/dma-s3c24xx.h>
-#include <plat/cpu.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
-#include <plat/regs-dma.h>
-#include <mach/regs-mem.h>
-#include <mach/regs-lcd.h>
-#include <mach/regs-sdi.h>
-#include <plat/regs-iis.h>
-#include <plat/regs-spi.h>
-
-#define MAP(x) { \
-		[0]	= (x) | DMA_CH_VALID,	\
-		[1]	= (x) | DMA_CH_VALID,	\
-		[2]	= (x) | DMA_CH_VALID,	\
-		[3]	= (x) | DMA_CH_VALID,	\
-		[4]	= (x) | DMA_CH_VALID,	\
-		[5]     = (x) | DMA_CH_VALID,	\
-	}
-
-static struct s3c24xx_dma_map __initdata s3c2443_dma_mappings[] = {
-	[DMACH_XD0] = {
-		.name		= "xdreq0",
-		.channels	= MAP(S3C2443_DMAREQSEL_XDREQ0),
-	},
-	[DMACH_XD1] = {
-		.name		= "xdreq1",
-		.channels	= MAP(S3C2443_DMAREQSEL_XDREQ1),
-	},
-	[DMACH_SDI] = {
-		.name		= "sdi",
-		.channels	= MAP(S3C2443_DMAREQSEL_SDI),
-	},
-	[DMACH_SPI0] = {
-		.name		= "spi0",
-		.channels	= MAP(S3C2443_DMAREQSEL_SPI0TX),
-	},
-	[DMACH_SPI1] = {
-		.name		= "spi1",
-		.channels	= MAP(S3C2443_DMAREQSEL_SPI1TX),
-	},
-	[DMACH_UART0] = {
-		.name		= "uart0",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART0_0),
-	},
-	[DMACH_UART1] = {
-		.name		= "uart1",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART1_0),
-	},
-      	[DMACH_UART2] = {
-		.name		= "uart2",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART2_0),
-	},
-      	[DMACH_UART3] = {
-		.name		= "uart3",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART3_0),
-	},
-	[DMACH_UART0_SRC2] = {
-		.name		= "uart0",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART0_1),
-	},
-	[DMACH_UART1_SRC2] = {
-		.name		= "uart1",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART1_1),
-	},
-      	[DMACH_UART2_SRC2] = {
-		.name		= "uart2",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART2_1),
-	},
-      	[DMACH_UART3_SRC2] = {
-		.name		= "uart3",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART3_1),
-	},
-	[DMACH_TIMER] = {
-		.name		= "timer",
-		.channels	= MAP(S3C2443_DMAREQSEL_TIMER),
-	},
-	[DMACH_I2S_IN] = {
-		.name		= "i2s-sdi",
-		.channels	= MAP(S3C2443_DMAREQSEL_I2SRX),
-	},
-	[DMACH_I2S_OUT] = {
-		.name		= "i2s-sdo",
-		.channels	= MAP(S3C2443_DMAREQSEL_I2STX),
-	},
-	[DMACH_PCM_IN] = {
-		.name		= "pcm-in",
-		.channels	= MAP(S3C2443_DMAREQSEL_PCMIN),
-	},
-	[DMACH_PCM_OUT] = {
-		.name		= "pcm-out",
-		.channels	= MAP(S3C2443_DMAREQSEL_PCMOUT),
-	},
-	[DMACH_MIC_IN] = {
-		.name		= "mic-in",
-		.channels	= MAP(S3C2443_DMAREQSEL_MICIN),
-	},
-};
-
-static void s3c2443_dma_select(struct s3c2410_dma_chan *chan,
-			       struct s3c24xx_dma_map *map)
-{
-	writel(map->channels[0] | S3C2443_DMAREQSEL_HW,
-	       chan->regs + S3C2443_DMA_DMAREQSEL);
-}
-
-static struct s3c24xx_dma_selection __initdata s3c2443_dma_sel = {
-	.select		= s3c2443_dma_select,
-	.dcon_mask	= 0,
-	.map		= s3c2443_dma_mappings,
-	.map_size	= ARRAY_SIZE(s3c2443_dma_mappings),
-};
-
-static int __init s3c2443_dma_add(struct device *dev,
-				  struct subsys_interface *sif)
-{
-	s3c24xx_dma_init(6, IRQ_S3C2443_DMA0, 0x100);
-	return s3c24xx_dma_init_map(&s3c2443_dma_sel);
-}
-
-static struct subsys_interface s3c2443_dma_interface = {
-	.name		= "s3c2443_dma",
-	.subsys		= &s3c2443_subsys,
-	.add_dev	= s3c2443_dma_add,
-};
-
-static int __init s3c2443_dma_init(void)
-{
-	return subsys_interface_register(&s3c2443_dma_interface);
-}
-
-arch_initcall(s3c2443_dma_init);
diff --git a/arch/arm/mach-s3c2443/s3c2443.c b/arch/arm/mach-s3c2443/s3c2443.c
deleted file mode 100644
index b9deaeb..0000000
--- a/arch/arm/mach-s3c2443/s3c2443.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/* linux/arch/arm/mach-s3c2443/s3c2443.c
- *
- * Copyright (c) 2007 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * Samsung S3C2443 Mobile CPU support
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <mach/regs-s3c2443-clock.h>
-
-#include <plat/gpio-core.h>
-#include <plat/gpio-cfg.h>
-#include <plat/gpio-cfg-helpers.h>
-#include <plat/s3c2443.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/fb-core.h>
-#include <plat/nand-core.h>
-#include <plat/adc-core.h>
-
-static struct map_desc s3c2443_iodesc[] __initdata = {
-	IODESC_ENT(WATCHDOG),
-	IODESC_ENT(CLKPWR),
-	IODESC_ENT(TIMER),
-};
-
-struct bus_type s3c2443_subsys = {
-	.name = "s3c2443-core",
-	.dev_name = "s3c2443-core",
-};
-
-static struct device s3c2443_dev = {
-	.bus		= &s3c2443_subsys,
-};
-
-void s3c2443_restart(char mode, const char *cmd)
-{
-	if (mode == 's')
-		soft_restart(0);
-
-	__raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST);
-}
-
-int __init s3c2443_init(void)
-{
-	printk("S3C2443: Initialising architecture\n");
-
-	s3c_nand_setname("s3c2412-nand");
-	s3c_fb_setname("s3c2443-fb");
-
-	s3c_adc_setname("s3c2443-adc");
-
-	/* change WDT IRQ number */
-	s3c_device_wdt.resource[1].start = IRQ_S3C2443_WDT;
-	s3c_device_wdt.resource[1].end   = IRQ_S3C2443_WDT;
-
-	return device_register(&s3c2443_dev);
-}
-
-void __init s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-	s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
-}
-
-/* s3c2443_map_io
- *
- * register the standard cpu IO areas, and any passed in from the
- * machine specific initialisation.
- */
-
-void __init s3c2443_map_io(void)
-{
-	s3c24xx_gpiocfg_default.set_pull = s3c2443_gpio_setpull;
-	s3c24xx_gpiocfg_default.get_pull = s3c2443_gpio_getpull;
-
-	iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc));
-}
-
-/* need to register the subsystem before we actually register the device, and
- * we also need to ensure that it has been initialised before any of the
- * drivers even try to use it (even if not on an s3c2443 based system)
- * as a driver which may support both 2443 and 2440 may try and use it.
-*/
-
-static int __init s3c2443_core_init(void)
-{
-	return subsys_system_register(&s3c2443_subsys, NULL);
-}
-
-core_initcall(s3c2443_core_init);
diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig
new file mode 100644
index 0000000..0f3a327
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/Kconfig
@@ -0,0 +1,538 @@
+# arch/arm/mach-s3c24xx/Kconfig
+#
+# Copyright (c) 2012 Samsung Electronics Co., Ltd.
+#		http://www.samsung.com/
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+if ARCH_S3C24XX
+
+menu "SAMSUNG S3C24XX SoCs Support"
+
+comment "S3C24XX SoCs"
+
+config CPU_S3C2410
+	bool "SAMSUNG S3C2410"
+	default y
+	select CPU_ARM920T
+	select S3C2410_CLOCK
+	select CPU_LLSERIAL_S3C2410
+	select S3C2410_PM if PM
+	select S3C2410_CPUFREQ if CPU_FREQ_S3C24XX
+	help
+	  Support for S3C2410 and S3C2410A family from the S3C24XX line
+	  of Samsung Mobile CPUs.
+
+config CPU_S3C2412
+	bool "SAMSUNG S3C2412"
+	depends on ARCH_S3C24XX
+	select CPU_ARM926T
+	select CPU_LLSERIAL_S3C2440
+	select S3C2412_PM if PM
+	select S3C2412_DMA if S3C24XX_DMA
+	help
+	  Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
+
+config CPU_S3C2416
+	bool "SAMSUNG S3C2416/S3C2450"
+	depends on ARCH_S3C24XX
+	select CPU_ARM926T
+	select CPU_LLSERIAL_S3C2440
+	select SAMSUNG_CLKSRC
+	select S3C2443_COMMON
+	select S3C2443_DMA if S3C24XX_DMA
+	select S3C2416_PM if PM
+	help
+	  Support for the S3C2416 SoC from the S3C24XX line
+
+config CPU_S3C2440
+	bool "SAMSUNG S3C2440"
+	select CPU_ARM920T
+	select CPU_LLSERIAL_S3C2440
+	select S3C2410_CLOCK
+	select S3C2410_PM if PM
+	select S3C2440_DMA if S3C24XX_DMA
+	help
+	  Support for S3C2440 Samsung Mobile CPU based systems.
+
+config CPU_S3C2442
+	bool "SAMSUNG S3C2442"
+	select CPU_ARM920T
+	select CPU_LLSERIAL_S3C2440
+	select S3C2410_CLOCK
+	select S3C2410_PM if PM
+	help
+	  Support for S3C2442 Samsung Mobile CPU based systems.
+
+config CPU_S3C244X
+	def_bool y
+	depends on CPU_S3C2440 || CPU_S3C2442
+
+config CPU_S3C2443
+	bool "SAMSUNG S3C2443"
+	depends on ARCH_S3C24XX
+	select CPU_ARM920T
+	select CPU_LLSERIAL_S3C2440
+	select SAMSUNG_CLKSRC
+	select S3C2443_COMMON
+	select S3C2443_DMA if S3C24XX_DMA
+	help
+	  Support for the S3C2443 SoC from the S3C24XX line
+
+# common code
+
+config S3C24XX_SMDK
+	bool
+	help
+	  Common machine code for SMDK2410 and SMDK2440
+
+config S3C24XX_SIMTEC_AUDIO
+	bool
+	depends on (ARCH_BAST || MACH_VR1000 || MACH_OSIRIS || MACH_ANUBIS)
+	default y
+	help
+	  Add audio devices for common Simtec S3C24XX boards
+
+config S3C24XX_SIMTEC_PM
+	bool
+	help
+	  Common power management code for systems that are
+	  compatible with the Simtec style of power management
+
+config S3C24XX_SIMTEC_USB
+	bool
+	help
+	  USB management code for common Simtec S3C24XX boards
+
+config S3C24XX_SETUP_TS
+	bool
+	help
+	  Compile in platform device definition for Samsung TouchScreen.
+
+# cpu-specific sections
+
+if CPU_S3C2410
+
+config S3C2410_DMA
+	bool
+	depends on S3C24XX_DMA && (CPU_S3C2410 || CPU_S3C2442)
+	default y if CPU_S3C2410 || CPU_S3C2442
+	help
+	  DMA device selection for S3C2410 and compatible CPUs
+
+config S3C2410_PM
+	bool
+	help
+	  Power Management code common to S3C2410 and better
+
+config S3C24XX_SIMTEC_NOR
+	bool
+	help
+	  Internal node to specify machine has simtec NOR mapping
+
+config MACH_BAST_IDE
+	bool
+	select HAVE_PATA_PLATFORM
+	help
+	  Internal node for machines with an BAST style IDE
+	  interface
+
+comment "S3C2410 Boards"
+
+#
+# The "S3C2410 Boards" list is ordered alphabetically by option text.
+# (without ARCH_ or MACH_)
+#
+
+config MACH_AML_M5900
+	bool "AML M5900 Series"
+	select S3C24XX_SIMTEC_PM if PM
+	select S3C_DEV_USB_HOST
+	help
+	  Say Y here if you are using the American Microsystems M5900 Series
+	  <http://www.amltd.com>
+
+config ARCH_BAST
+	bool "Simtec Electronics BAST (EB2410ITX)"
+	select S3C2410_IOTIMING if S3C2410_CPUFREQ
+	select S3C24XX_SIMTEC_PM if PM
+	select S3C24XX_SIMTEC_NOR
+	select S3C24XX_SIMTEC_USB
+	select MACH_BAST_IDE
+	select S3C24XX_DCLK
+	select ISA
+	select S3C_DEV_HWMON
+	select S3C_DEV_USB_HOST
+	select S3C_DEV_NAND
+	help
+	  Say Y here if you are using the Simtec Electronics EB2410ITX
+	  development board (also known as BAST)
+
+config BAST_PC104_IRQ
+	bool "BAST PC104 IRQ support"
+	depends on ARCH_BAST
+	default y
+	help
+	  Say Y	here to enable the PC104 IRQ routing on the
+	  Simtec BAST (EB2410ITX)
+
+config ARCH_H1940
+	bool "IPAQ H1940"
+	select PM_H1940 if PM
+	select S3C_DEV_USB_HOST
+	select S3C_DEV_NAND
+	select S3C24XX_SETUP_TS
+	help
+	  Say Y here if you are using the HP IPAQ H1940
+
+config H1940BT
+	tristate "Control the state of H1940 bluetooth chip"
+	depends on ARCH_H1940
+	select RFKILL
+	help
+	  This is a simple driver that is able to control
+	  the state of built in bluetooth chip on h1940.
+
+config PM_H1940
+	bool
+	help
+	  Internal node for H1940 and related PM
+
+config MACH_N30
+	bool "Acer N30 family"
+	select MACH_N35
+	select S3C_DEV_USB_HOST
+	select S3C_DEV_NAND
+	help
+	  Say Y here if you want suppt for the Acer N30, Acer N35,
+	  Navman PiN570, Yakumo AlphaX or Airis NC05 PDAs.
+
+config MACH_OTOM
+	bool "NexVision OTOM Board"
+	select S3C_DEV_USB_HOST
+	select S3C_DEV_NAND
+	help
+	  Say Y here if you are using the Nex Vision OTOM board
+
+config MACH_QT2410
+	bool "QT2410"
+	select S3C_DEV_USB_HOST
+	select S3C_DEV_NAND
+	help
+	  Say Y here if you are using the Armzone QT2410
+
+config ARCH_SMDK2410
+	bool "SMDK2410/A9M2410"
+	select S3C24XX_SMDK
+	help
+	  Say Y here if you are using the SMDK2410 or the derived module A9M2410
+	  <http://www.fsforth.de>
+
+config MACH_TCT_HAMMER
+	bool "TCT Hammer Board"
+	select S3C_DEV_USB_HOST
+	help
+	  Say Y here if you are using the TinCanTools Hammer Board
+	  <http://www.tincantools.com>
+
+config MACH_VR1000
+	bool "Thorcom VR1000"
+	select S3C24XX_SIMTEC_PM if PM
+	select S3C24XX_DCLK
+	select S3C24XX_SIMTEC_NOR
+	select MACH_BAST_IDE
+	select S3C_DEV_USB_HOST
+	select S3C24XX_SIMTEC_USB
+	help
+	  Say Y here if you are using the Thorcom VR1000 board.
+
+endif	# CPU_S3C2410
+
+config S3C2412_PM_SLEEP
+	bool
+	help
+	  Internal config node to apply sleep for S3C2412 power management.
+	  Can be selected by another SoCs such as S3C2416 with similar
+	  sleep procedure.
+
+if CPU_S3C2412
+
+config CPU_S3C2412_ONLY
+	bool
+	depends on ARCH_S3C24XX && !CPU_S3C2410 && \
+		   !CPU_S3C2416 && !CPU_S3C2440 && !CPU_S3C2442 && \
+		   !CPU_S3C2443 && CPU_S3C2412
+	default y
+
+config S3C2412_DMA
+	bool
+	help
+	  Internal config node for S3C2412 DMA support
+
+config S3C2412_PM
+	bool
+	help
+	  Internal config node to apply S3C2412 power management
+
+comment "S3C2412 Boards"
+
+#
+# The "S3C2412 Boards" list is ordered alphabetically by option text.
+# (without ARCH_ or MACH_)
+#
+
+config MACH_JIVE
+	bool "Logitech Jive"
+	select S3C_DEV_USB_HOST
+	select S3C_DEV_NAND
+	help
+	  Say Y here if you are using the Logitech Jive.
+
+config MACH_JIVE_SHOW_BOOTLOADER
+	bool "Allow access to bootloader partitions in MTD (EXPERIMENTAL)"
+	depends on MACH_JIVE && EXPERIMENTAL
+
+config MACH_S3C2413
+	bool
+	help
+	  Internal node for S3C2413 version of SMDK2413, so that
+	  machine_is_s3c2413() will work when MACH_SMDK2413 is
+	  selected
+
+config MACH_SMDK2412
+	bool "SMDK2412"
+	select MACH_SMDK2413
+	help
+	  Say Y here if you are using an SMDK2412
+
+	  Note, this shares support with SMDK2413, so will automatically
+	  select MACH_SMDK2413.
+
+config MACH_SMDK2413
+	bool "SMDK2413"
+	select MACH_S3C2413
+	select S3C24XX_SMDK
+	select S3C_DEV_USB_HOST
+	select S3C_DEV_NAND
+	help
+	  Say Y here if you are using an SMDK2413
+
+config MACH_VSTMS
+	bool "VMSTMS"
+	select S3C_DEV_USB_HOST
+	select S3C_DEV_NAND
+	help
+	  Say Y here if you are using an VSTMS board
+
+endif	# CPU_S3C2412
+
+if CPU_S3C2416
+
+config S3C2416_PM
+	bool
+	select S3C2412_PM_SLEEP
+	help
+	  Internal config node to apply S3C2416 power management
+
+config S3C2416_SETUP_SDHCI
+	bool
+	select S3C2416_SETUP_SDHCI_GPIO
+	help
+	  Internal helper functions for S3C2416 based SDHCI systems
+
+config S3C2416_SETUP_SDHCI_GPIO
+	bool
+	help
+	  Common setup code for SDHCI gpio.
+
+comment "S3C2416 Boards"
+
+config MACH_SMDK2416
+	bool "SMDK2416"
+	select S3C24XX_SMDK
+	select S3C_DEV_FB
+	select S3C_DEV_HSMMC
+	select S3C_DEV_HSMMC1
+	select S3C_DEV_NAND
+	select S3C_DEV_USB_HOST
+	select S3C2416_SETUP_SDHCI
+	help
+	  Say Y here if you are using an SMDK2416
+
+endif	# CPU_S3C2416
+
+if CPU_S3C2440
+
+config S3C2440_DMA
+	bool
+	help
+	  Support for S3C2440 specific DMA code5A
+
+comment "S3C2440 Boards"
+
+#
+# The "S3C2440 Boards" list is ordered alphabetically by option text.
+# (without ARCH_ or MACH_)
+#
+
+config MACH_ANUBIS
+	bool "Simtec Electronics ANUBIS"
+	select S3C24XX_DCLK
+	select S3C24XX_SIMTEC_PM if PM
+	select HAVE_PATA_PLATFORM
+	select S3C24XX_GPIO_EXTRA64
+	select S3C2440_XTAL_12000000
+	select S3C_DEV_USB_HOST
+	help
+	  Say Y here if you are using the Simtec Electronics ANUBIS
+	  development system
+
+config MACH_AT2440EVB
+	bool "Avantech AT2440EVB development board"
+	select S3C_DEV_USB_HOST
+	select S3C_DEV_NAND
+	help
+	  Say Y here if you are using the AT2440EVB development board
+
+config MACH_MINI2440
+	bool "MINI2440 development board"
+	select EEPROM_AT24
+	select NEW_LEDS
+	select LEDS_CLASS
+	select LEDS_TRIGGER
+	select LEDS_TRIGGER_BACKLIGHT
+	select S3C_DEV_NAND
+	select S3C_DEV_USB_HOST
+	help
+	  Say Y here to select support for the MINI2440. Is a 10cm x 10cm board
+	  available via various sources. It can come with a 3.5" or 7" touch LCD.
+
+config MACH_NEXCODER_2440
+	bool "NexVision NEXCODER 2440 Light Board"
+	select S3C2440_XTAL_12000000
+	select S3C_DEV_USB_HOST
+	select S3C_DEV_NAND
+	help
+	  Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
+
+config MACH_OSIRIS
+	bool "Simtec IM2440D20 (OSIRIS) module"
+	select S3C24XX_DCLK
+	select S3C24XX_SIMTEC_PM if PM
+	select S3C24XX_GPIO_EXTRA128
+	select S3C2440_XTAL_12000000
+	select S3C2410_IOTIMING if S3C2440_CPUFREQ
+	select S3C_DEV_USB_HOST
+	select S3C_DEV_NAND
+	help
+	  Say Y here if you are using the Simtec IM2440D20 module, also
+	  known as the Osiris.
+
+config MACH_OSIRIS_DVS
+	tristate "Simtec IM2440D20 (OSIRIS) Dynamic Voltage Scaling driver"
+	depends on MACH_OSIRIS
+	select TPS65010
+	help
+	  Say Y/M here if you want to have dynamic voltage scaling support
+	  on the Simtec IM2440D20 (OSIRIS) module via the TPS65011.
+
+	  The DVS driver alters the voltage supplied to the ARM core
+	  depending on the frequency it is running at. The driver itself
+	  does not do any of the frequency alteration, which is left up
+	  to the cpufreq driver.
+
+config MACH_RX3715
+	bool "HP iPAQ rx3715"
+	select S3C2440_XTAL_16934400
+	select PM_H1940 if PM
+	select S3C_DEV_NAND
+	help
+	  Say Y here if you are using the HP iPAQ rx3715.
+
+config ARCH_S3C2440
+	bool "SMDK2440"
+	select S3C2440_XTAL_16934400
+	select S3C24XX_SMDK
+	select S3C_DEV_USB_HOST
+	select S3C_DEV_NAND
+	help
+	  Say Y here if you are using the SMDK2440.
+
+config SMDK2440_CPU2440
+	bool "SMDK2440 with S3C2440 CPU module"
+	default y if ARCH_S3C2440
+	select S3C2440_XTAL_16934400
+
+endif	# CPU_S3C2440
+
+if CPU_S3C2442
+
+comment "S3C2442 Boards"
+
+#
+# The "S3C2442 Boards" list is ordered alphabetically by option text.
+# (without ARCH_ or MACH_)
+#
+
+config MACH_NEO1973_GTA02
+	bool "Openmoko GTA02 / Freerunner phone"
+	select MFD_PCF50633
+	select PCF50633_GPIO
+	select I2C
+	select POWER_SUPPLY
+	select MACH_NEO1973
+	select S3C2410_PWM
+	select S3C_DEV_USB_HOST
+	help
+	   Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone
+
+config MACH_RX1950
+	bool "HP iPAQ rx1950"
+	select S3C24XX_DCLK
+	select PM_H1940 if PM
+	select I2C
+	select S3C2410_PWM
+	select S3C_DEV_NAND
+	select S3C2410_IOTIMING if S3C2440_CPUFREQ
+	select S3C2440_XTAL_16934400
+	help
+	   Say Y here if you're using HP iPAQ rx1950
+
+config SMDK2440_CPU2442
+	bool "SMDM2440 with S3C2442 CPU module"
+
+endif	# CPU_S3C2440
+
+if CPU_S3C2443 || CPU_S3C2416
+
+config S3C2443_COMMON
+	bool
+	help
+	  Common code for the S3C2443 and similar processors, which includes
+	  the S3C2416 and S3C2450.
+
+config S3C2443_DMA
+	bool
+	help
+	  Internal config node for S3C2443 DMA support
+
+endif	# CPU_S3C2443 || CPU_S3C2416
+
+if CPU_S3C2443
+
+comment "S3C2443 Boards"
+
+config MACH_SMDK2443
+	bool "SMDK2443"
+	select S3C24XX_SMDK
+	select S3C_DEV_HSMMC1
+	help
+	  Say Y here if you are using an SMDK2443
+
+endif	# CPU_S3C2443
+
+endmenu	# SAMSUNG S3C24XX SoCs Support
+
+endif	# ARCH_S3C24XX
diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile
new file mode 100644
index 0000000..3518fe8
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/Makefile
@@ -0,0 +1,95 @@
+# arch/arm/mach-s3c24xx/Makefile
+#
+# Copyright (c) 2012 Samsung Electronics Co., Ltd.
+#		http://www.samsung.com/
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+obj-y				:=
+obj-m				:=
+obj-n				:=
+obj-				:=
+
+# core
+
+obj-$(CONFIG_CPU_S3C2410)	+= s3c2410.o
+obj-$(CONFIG_S3C2410_DMA)	+= dma-s3c2410.o
+obj-$(CONFIG_S3C2410_PM)	+= pm-s3c2410.o sleep-s3c2410.o
+
+obj-$(CONFIG_CPU_S3C2412)	+= s3c2412.o irq-s3c2412.o clock-s3c2412.o
+obj-$(CONFIG_S3C2412_DMA)	+= dma-s3c2412.o
+obj-$(CONFIG_S3C2412_PM)	+= pm-s3c2412.o
+obj-$(CONFIG_S3C2412_PM_SLEEP)	+= sleep-s3c2412.o
+
+obj-$(CONFIG_CPU_S3C2416)	+= s3c2416.o irq-s3c2416.o clock-s3c2416.o
+obj-$(CONFIG_S3C2416_PM)	+= pm-s3c2416.o
+
+obj-$(CONFIG_CPU_S3C2440)	+= s3c2440.o irq-s3c2440.o clock-s3c2440.o
+obj-$(CONFIG_CPU_S3C2442)	+= s3c2442.o
+obj-$(CONFIG_CPU_S3C244X)	+= s3c244x.o irq-s3c244x.o clock-s3c244x.o
+obj-$(CONFIG_S3C2440_DMA)	+= dma-s3c2440.o
+
+obj-$(CONFIG_CPU_S3C2443)	+= s3c2443.o irq-s3c2443.o clock-s3c2443.o
+
+# common code
+
+obj-$(CONFIG_S3C2443_COMMON)	+= common-s3c2443.o
+obj-$(CONFIG_S3C2443_DMA)	+= dma-s3c2443.o
+
+#
+# machine support
+# following is ordered alphabetically by option text.
+#
+
+obj-$(CONFIG_MACH_AML_M5900)		+= mach-amlm5900.o
+obj-$(CONFIG_ARCH_BAST)			+= mach-bast.o
+obj-$(CONFIG_BAST_PC104_IRQ)		+= bast-irq.o
+obj-$(CONFIG_ARCH_H1940)		+= mach-h1940.o
+obj-$(CONFIG_H1940BT)			+= h1940-bluetooth.o
+obj-$(CONFIG_PM_H1940)			+= pm-h1940.o
+obj-$(CONFIG_MACH_N30)			+= mach-n30.o
+obj-$(CONFIG_MACH_OTOM)			+= mach-otom.o
+obj-$(CONFIG_MACH_QT2410)		+= mach-qt2410.o
+obj-$(CONFIG_ARCH_SMDK2410)		+= mach-smdk2410.o
+obj-$(CONFIG_MACH_TCT_HAMMER)		+= mach-tct_hammer.o
+obj-$(CONFIG_MACH_VR1000)		+= mach-vr1000.o
+
+obj-$(CONFIG_MACH_JIVE)			+= mach-jive.o
+obj-$(CONFIG_MACH_SMDK2413)		+= mach-smdk2413.o
+obj-$(CONFIG_MACH_VSTMS)		+= mach-vstms.o
+
+obj-$(CONFIG_MACH_SMDK2416)		+= mach-smdk2416.o
+
+obj-$(CONFIG_MACH_ANUBIS)		+= mach-anubis.o
+obj-$(CONFIG_MACH_AT2440EVB)		+= mach-at2440evb.o
+obj-$(CONFIG_MACH_MINI2440)		+= mach-mini2440.o
+obj-$(CONFIG_MACH_NEXCODER_2440)	+= mach-nexcoder.o
+obj-$(CONFIG_MACH_OSIRIS)		+= mach-osiris.o
+obj-$(CONFIG_MACH_RX3715)		+= mach-rx3715.o
+obj-$(CONFIG_ARCH_S3C2440)		+= mach-smdk2440.o
+
+obj-$(CONFIG_MACH_NEO1973_GTA02)	+= mach-gta02.o
+obj-$(CONFIG_MACH_RX1950)		+= mach-rx1950.o
+
+obj-$(CONFIG_MACH_SMDK2443)		+= mach-smdk2443.o
+
+# common bits of machine support
+
+obj-$(CONFIG_S3C24XX_SMDK)		+= common-smdk.o
+obj-$(CONFIG_S3C24XX_SIMTEC_AUDIO)	+= simtec-audio.o
+obj-$(CONFIG_S3C24XX_SIMTEC_NOR)	+= simtec-nor.o
+obj-$(CONFIG_S3C24XX_SIMTEC_PM)		+= simtec-pm.o
+obj-$(CONFIG_S3C24XX_SIMTEC_USB)	+= simtec-usb.o
+
+# machine additions
+
+obj-$(CONFIG_MACH_BAST_IDE)		+= bast-ide.o
+obj-$(CONFIG_MACH_OSIRIS_DVS)		+= mach-osiris-dvs.o
+
+# device setup
+
+obj-$(CONFIG_S3C2416_SETUP_SDHCI_GPIO)	+= setup-sdhci-gpio.o
+obj-$(CONFIG_ARCH_S3C24XX)		+= setup-i2c.o
+obj-$(CONFIG_S3C24XX_SETUP_TS)		+= setup-ts.o
diff --git a/arch/arm/mach-s3c2410/Makefile.boot b/arch/arm/mach-s3c24xx/Makefile.boot
similarity index 100%
rename from arch/arm/mach-s3c2410/Makefile.boot
rename to arch/arm/mach-s3c24xx/Makefile.boot
diff --git a/arch/arm/mach-s3c2410/bast-ide.c b/arch/arm/mach-s3c24xx/bast-ide.c
similarity index 100%
rename from arch/arm/mach-s3c2410/bast-ide.c
rename to arch/arm/mach-s3c24xx/bast-ide.c
diff --git a/arch/arm/mach-s3c2410/bast-irq.c b/arch/arm/mach-s3c24xx/bast-irq.c
similarity index 100%
rename from arch/arm/mach-s3c2410/bast-irq.c
rename to arch/arm/mach-s3c24xx/bast-irq.c
diff --git a/arch/arm/mach-s3c2412/clock.c b/arch/arm/mach-s3c24xx/clock-s3c2412.c
similarity index 100%
rename from arch/arm/mach-s3c2412/clock.c
rename to arch/arm/mach-s3c24xx/clock-s3c2412.c
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2416.c b/arch/arm/mach-s3c24xx/clock-s3c2416.c
new file mode 100644
index 0000000..dbc9ab4
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/clock-s3c2416.c
@@ -0,0 +1,172 @@
+/* linux/arch/arm/mach-s3c2416/clock.c
+ *
+ * Copyright (c) 2010 Simtec Electronics
+ * Copyright (c) 2010 Ben Dooks <ben-linux@fluff.org>
+ *
+ * S3C2416 Clock control support
+ *
+ * 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/init.h>
+#include <linux/clk.h>
+
+#include <plat/s3c2416.h>
+#include <plat/clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/cpu.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/pll.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/regs-clock.h>
+#include <mach/regs-s3c2443-clock.h>
+
+/* armdiv
+ *
+ * this clock is sourced from msysclk and can have a number of
+ * divider values applied to it to then be fed into armclk.
+ * The real clock definition is done in s3c2443-clock.c,
+ * only the armdiv divisor table must be defined here.
+*/
+
+static unsigned int armdiv[8] = {
+	[0] = 1,
+	[1] = 2,
+	[2] = 3,
+	[3] = 4,
+	[5] = 6,
+	[7] = 8,
+};
+
+static struct clksrc_clk hsspi_eplldiv = {
+	.clk = {
+		.name	= "hsspi-eplldiv",
+		.parent	= &clk_esysclk.clk,
+		.ctrlbit = (1 << 14),
+		.enable = s3c2443_clkcon_enable_s,
+	},
+	.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 24 },
+};
+
+static struct clk *hsspi_sources[] = {
+	[0] = &hsspi_eplldiv.clk,
+	[1] = NULL, /* to fix */
+};
+
+static struct clksrc_clk hsspi_mux = {
+	.clk	= {
+		.name	= "hsspi-if",
+	},
+	.sources = &(struct clksrc_sources) {
+		.sources = hsspi_sources,
+		.nr_sources = ARRAY_SIZE(hsspi_sources),
+	},
+	.reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 18 },
+};
+
+static struct clksrc_clk hsmmc_div[] = {
+	[0] = {
+		.clk = {
+			.name	= "hsmmc-div",
+			.devname	= "s3c-sdhci.0",
+			.parent	= &clk_esysclk.clk,
+		},
+		.reg_div = { .reg = S3C2416_CLKDIV2, .size = 2, .shift = 6 },
+	},
+	[1] = {
+		.clk = {
+			.name	= "hsmmc-div",
+			.devname	= "s3c-sdhci.1",
+			.parent	= &clk_esysclk.clk,
+		},
+		.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
+	},
+};
+
+static struct clksrc_clk hsmmc_mux0 = {
+	.clk	= {
+		.name		= "hsmmc-if",
+		.devname	= "s3c-sdhci.0",
+		.ctrlbit	= (1 << 6),
+		.enable		= s3c2443_clkcon_enable_s,
+	},
+	.sources	= &(struct clksrc_sources) {
+		.nr_sources	= 2,
+		.sources	= (struct clk * []) {
+			[0]	= &hsmmc_div[0].clk,
+			[1]	= NULL, /* to fix */
+		},
+	},
+	.reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 16 },
+};
+
+static struct clksrc_clk hsmmc_mux1 = {
+	.clk	= {
+		.name		= "hsmmc-if",
+		.devname	= "s3c-sdhci.1",
+		.ctrlbit	= (1 << 12),
+		.enable		= s3c2443_clkcon_enable_s,
+	},
+	.sources	= &(struct clksrc_sources) {
+		.nr_sources	= 2,
+		.sources	= (struct clk * []) {
+			[0]	= &hsmmc_div[1].clk,
+			[1]	= NULL, /* to fix */
+		},
+	},
+	.reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 17 },
+};
+
+static struct clk hsmmc0_clk = {
+	.name		= "hsmmc",
+	.devname	= "s3c-sdhci.0",
+	.parent		= &clk_h,
+	.enable		= s3c2443_clkcon_enable_h,
+	.ctrlbit	= S3C2416_HCLKCON_HSMMC0,
+};
+
+static struct clksrc_clk *clksrcs[] __initdata = {
+	&hsspi_eplldiv,
+	&hsspi_mux,
+	&hsmmc_div[0],
+	&hsmmc_div[1],
+	&hsmmc_mux0,
+	&hsmmc_mux1,
+};
+
+static struct clk_lookup s3c2416_clk_lookup[] = {
+	CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &hsmmc0_clk),
+	CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &hsmmc_mux0.clk),
+	CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &hsmmc_mux1.clk),
+};
+
+void __init s3c2416_init_clocks(int xtal)
+{
+	u32 epllcon = __raw_readl(S3C2443_EPLLCON);
+	u32 epllcon1 = __raw_readl(S3C2443_EPLLCON+4);
+	int ptr;
+
+	/* s3c2416 EPLL compatible with s3c64xx */
+	clk_epll.rate = s3c_get_pll6553x(xtal, epllcon, epllcon1);
+
+	clk_epll.parent = &clk_epllref.clk;
+
+	s3c2443_common_init_clocks(xtal, s3c2416_get_pll,
+				   armdiv, ARRAY_SIZE(armdiv),
+				   S3C2416_CLKDIV0_ARMDIV_MASK);
+
+	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
+		s3c_register_clksrc(clksrcs[ptr], 1);
+
+	s3c24xx_register_clock(&hsmmc0_clk);
+	clkdev_add_table(s3c2416_clk_lookup, ARRAY_SIZE(s3c2416_clk_lookup));
+
+	s3c_pwmclk_init();
+
+}
diff --git a/arch/arm/mach-s3c2440/clock.c b/arch/arm/mach-s3c24xx/clock-s3c2440.c
similarity index 100%
rename from arch/arm/mach-s3c2440/clock.c
rename to arch/arm/mach-s3c24xx/clock-s3c2440.c
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2443.c b/arch/arm/mach-s3c24xx/clock-s3c2443.c
new file mode 100644
index 0000000..efb3ac3
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/clock-s3c2443.c
@@ -0,0 +1,215 @@
+/* linux/arch/arm/mach-s3c2443/clock.c
+ *
+ * Copyright (c) 2007, 2010 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2443 Clock control support
+ *
+ * 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/init.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+
+#include <mach/regs-s3c2443-clock.h>
+
+#include <plat/cpu-freq.h>
+
+#include <plat/s3c2443.h>
+#include <plat/clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/cpu.h>
+
+/* We currently have to assume that the system is running
+ * from the XTPll input, and that all ***REFCLKs are being
+ * fed from it, as we cannot read the state of OM[4] from
+ * software.
+ *
+ * It would be possible for each board initialisation to
+ * set the correct muxing at initialisation
+*/
+
+/* clock selections */
+
+/* armdiv
+ *
+ * this clock is sourced from msysclk and can have a number of
+ * divider values applied to it to then be fed into armclk.
+ * The real clock definition is done in s3c2443-clock.c,
+ * only the armdiv divisor table must be defined here.
+*/
+
+static unsigned int armdiv[16] = {
+	[S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 1,
+	[S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 2,
+	[S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 3,
+	[S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 4,
+	[S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 6,
+	[S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 8,
+	[S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 12,
+	[S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 16,
+};
+
+/* hsspi
+ *
+ * high-speed spi clock, sourced from esysclk
+*/
+
+static struct clksrc_clk clk_hsspi = {
+	.clk	= {
+		.name		= "hsspi-if",
+		.parent		= &clk_esysclk.clk,
+		.ctrlbit	= S3C2443_SCLKCON_HSSPICLK,
+		.enable		= s3c2443_clkcon_enable_s,
+	},
+	.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
+};
+
+
+/* clk_hsmcc_div
+ *
+ * this clock is sourced from epll, and is fed through a divider,
+ * to a mux controlled by sclkcon where either it or a extclk can
+ * be fed to the hsmmc block
+*/
+
+static struct clksrc_clk clk_hsmmc_div = {
+	.clk	= {
+		.name		= "hsmmc-div",
+		.devname	= "s3c-sdhci.1",
+		.parent		= &clk_esysclk.clk,
+	},
+	.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
+};
+
+static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
+{
+	unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
+
+	clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
+		    S3C2443_SCLKCON_HSMMCCLK_EPLL);
+
+	if (parent == &clk_epll)
+		clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
+	else if (parent == &clk_ext)
+		clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
+	else
+		return -EINVAL;
+
+	if (clk->usage > 0) {
+		__raw_writel(clksrc, S3C2443_SCLKCON);
+	}
+
+	clk->parent = parent;
+	return 0;
+}
+
+static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
+{
+	return s3c2443_setparent_hsmmc(clk, clk->parent);
+}
+
+static struct clk clk_hsmmc = {
+	.name		= "hsmmc-if",
+	.devname	= "s3c-sdhci.1",
+	.parent		= &clk_hsmmc_div.clk,
+	.enable		= s3c2443_enable_hsmmc,
+	.ops		= &(struct clk_ops) {
+		.set_parent	= s3c2443_setparent_hsmmc,
+	},
+};
+
+/* standard clock definitions */
+
+static struct clk init_clocks_off[] = {
+	{
+		.name		= "sdi",
+		.parent		= &clk_p,
+		.enable		= s3c2443_clkcon_enable_p,
+		.ctrlbit	= S3C2443_PCLKCON_SDI,
+	}, {
+		.name		= "spi",
+		.devname	= "s3c2410-spi.0",
+		.parent		= &clk_p,
+		.enable		= s3c2443_clkcon_enable_p,
+		.ctrlbit	= S3C2443_PCLKCON_SPI0,
+	}, {
+		.name		= "spi",
+		.devname	= "s3c2410-spi.1",
+		.parent		= &clk_p,
+		.enable		= s3c2443_clkcon_enable_p,
+		.ctrlbit	= S3C2443_PCLKCON_SPI1,
+	}
+};
+
+/* clocks to add straight away */
+
+static struct clksrc_clk *clksrcs[] __initdata = {
+	&clk_hsspi,
+	&clk_hsmmc_div,
+};
+
+static struct clk *clks[] __initdata = {
+	&clk_hsmmc,
+};
+
+void __init s3c2443_init_clocks(int xtal)
+{
+	unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
+	int ptr;
+
+	clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
+	clk_epll.parent = &clk_epllref.clk;
+
+	s3c2443_common_init_clocks(xtal, s3c2443_get_mpll,
+				   armdiv, ARRAY_SIZE(armdiv),
+				   S3C2443_CLKDIV0_ARMDIV_MASK);
+
+	s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
+
+	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
+		s3c_register_clksrc(clksrcs[ptr], 1);
+
+	/* We must be careful disabling the clocks we are not intending to
+	 * be using at boot time, as subsystems such as the LCD which do
+	 * their own DMA requests to the bus can cause the system to lockup
+	 * if they where in the middle of requesting bus access.
+	 *
+	 * Disabling the LCD clock if the LCD is active is very dangerous,
+	 * and therefore the bootloader should be careful to not enable
+	 * the LCD clock if it is not needed.
+	*/
+
+	/* install (and disable) the clocks we do not need immediately */
+
+	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+
+	s3c_pwmclk_init();
+}
diff --git a/arch/arm/mach-s3c2440/s3c244x-clock.c b/arch/arm/mach-s3c24xx/clock-s3c244x.c
similarity index 100%
rename from arch/arm/mach-s3c2440/s3c244x-clock.c
rename to arch/arm/mach-s3c24xx/clock-s3c244x.c
diff --git a/arch/arm/mach-s3c24xx/common-s3c2443.c b/arch/arm/mach-s3c24xx/common-s3c2443.c
new file mode 100644
index 0000000..4604315
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/common-s3c2443.c
@@ -0,0 +1,670 @@
+/*
+ * Common code for SoCs starting with the S3C2443
+ *
+ * Copyright (c) 2007, 2010 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * 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/clk.h>
+#include <linux/io.h>
+
+#include <mach/regs-s3c2443-clock.h>
+
+#include <plat/clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/cpu.h>
+
+#include <plat/cpu-freq.h>
+
+
+static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable)
+{
+	u32 ctrlbit = clk->ctrlbit;
+	u32 con = __raw_readl(reg);
+
+	if (enable)
+		con |= ctrlbit;
+	else
+		con &= ~ctrlbit;
+
+	__raw_writel(con, reg);
+	return 0;
+}
+
+int s3c2443_clkcon_enable_h(struct clk *clk, int enable)
+{
+	return s3c2443_gate(S3C2443_HCLKCON, clk, enable);
+}
+
+int s3c2443_clkcon_enable_p(struct clk *clk, int enable)
+{
+	return s3c2443_gate(S3C2443_PCLKCON, clk, enable);
+}
+
+int s3c2443_clkcon_enable_s(struct clk *clk, int enable)
+{
+	return s3c2443_gate(S3C2443_SCLKCON, clk, enable);
+}
+
+/* mpllref is a direct descendant of clk_xtal by default, but it is not
+ * elided as the EPLL can be either sourced by the XTAL or EXTCLK and as
+ * such directly equating the two source clocks is impossible.
+ */
+static struct clk clk_mpllref = {
+	.name		= "mpllref",
+	.parent		= &clk_xtal,
+};
+
+static struct clk *clk_epllref_sources[] = {
+	[0] = &clk_mpllref,
+	[1] = &clk_mpllref,
+	[2] = &clk_xtal,
+	[3] = &clk_ext,
+};
+
+struct clksrc_clk clk_epllref = {
+	.clk	= {
+		.name		= "epllref",
+	},
+	.sources = &(struct clksrc_sources) {
+		.sources = clk_epllref_sources,
+		.nr_sources = ARRAY_SIZE(clk_epllref_sources),
+	},
+	.reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 },
+};
+
+/* esysclk
+ *
+ * this is sourced from either the EPLL or the EPLLref clock
+*/
+
+static struct clk *clk_sysclk_sources[] = {
+	[0] = &clk_epllref.clk,
+	[1] = &clk_epll,
+};
+
+struct clksrc_clk clk_esysclk = {
+	.clk	= {
+		.name		= "esysclk",
+		.parent		= &clk_epll,
+	},
+	.sources = &(struct clksrc_sources) {
+		.sources = clk_sysclk_sources,
+		.nr_sources = ARRAY_SIZE(clk_sysclk_sources),
+	},
+	.reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 },
+};
+
+static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
+{
+	unsigned long parent_rate = clk_get_rate(clk->parent);
+	unsigned long div = __raw_readl(S3C2443_CLKDIV0);
+
+	div  &= S3C2443_CLKDIV0_EXTDIV_MASK;
+	div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1);	/* x2 */
+
+	return parent_rate / (div + 1);
+}
+
+static struct clk clk_mdivclk = {
+	.name		= "mdivclk",
+	.parent		= &clk_mpllref,
+	.ops		= &(struct clk_ops) {
+		.get_rate	= s3c2443_getrate_mdivclk,
+	},
+};
+
+static struct clk *clk_msysclk_sources[] = {
+	[0] = &clk_mpllref,
+	[1] = &clk_mpll,
+	[2] = &clk_mdivclk,
+	[3] = &clk_mpllref,
+};
+
+struct clksrc_clk clk_msysclk = {
+	.clk	= {
+		.name		= "msysclk",
+		.parent		= &clk_xtal,
+	},
+	.sources = &(struct clksrc_sources) {
+		.sources = clk_msysclk_sources,
+		.nr_sources = ARRAY_SIZE(clk_msysclk_sources),
+	},
+	.reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 },
+};
+
+/* prediv
+ *
+ * this divides the msysclk down to pass to h/p/etc.
+ */
+
+static unsigned long s3c2443_prediv_getrate(struct clk *clk)
+{
+	unsigned long rate = clk_get_rate(clk->parent);
+	unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
+
+	clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
+	clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
+
+	return rate / (clkdiv0 + 1);
+}
+
+static struct clk clk_prediv = {
+	.name		= "prediv",
+	.parent		= &clk_msysclk.clk,
+	.ops		= &(struct clk_ops) {
+		.get_rate	= s3c2443_prediv_getrate,
+	},
+};
+
+/* hclk divider
+ *
+ * divides the prediv and provides the hclk.
+ */
+
+static unsigned long s3c2443_hclkdiv_getrate(struct clk *clk)
+{
+	unsigned long rate = clk_get_rate(clk->parent);
+	unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
+
+	clkdiv0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
+
+	return rate / (clkdiv0 + 1);
+}
+
+static struct clk_ops clk_h_ops = {
+	.get_rate	= s3c2443_hclkdiv_getrate,
+};
+
+/* pclk divider
+ *
+ * divides the hclk and provides the pclk.
+ */
+
+static unsigned long s3c2443_pclkdiv_getrate(struct clk *clk)
+{
+	unsigned long rate = clk_get_rate(clk->parent);
+	unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
+
+	clkdiv0 = ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 1 : 0);
+
+	return rate / (clkdiv0 + 1);
+}
+
+static struct clk_ops clk_p_ops = {
+	.get_rate	= s3c2443_pclkdiv_getrate,
+};
+
+/* armdiv
+ *
+ * this clock is sourced from msysclk and can have a number of
+ * divider values applied to it to then be fed into armclk.
+*/
+
+static unsigned int *armdiv;
+static int nr_armdiv;
+static int armdivmask;
+
+static unsigned long s3c2443_armclk_roundrate(struct clk *clk,
+					      unsigned long rate)
+{
+	unsigned long parent = clk_get_rate(clk->parent);
+	unsigned long calc;
+	unsigned best = 256; /* bigger than any value */
+	unsigned div;
+	int ptr;
+
+	if (!nr_armdiv)
+		return -EINVAL;
+
+	for (ptr = 0; ptr < nr_armdiv; ptr++) {
+		div = armdiv[ptr];
+		if (div) {
+			/* cpufreq provides 266mhz as 266666000 not 266666666 */
+			calc = (parent / div / 1000) * 1000;
+			if (calc <= rate && div < best)
+				best = div;
+		}
+	}
+
+	return parent / best;
+}
+
+static unsigned long s3c2443_armclk_getrate(struct clk *clk)
+{
+	unsigned long rate = clk_get_rate(clk->parent);
+	unsigned long clkcon0;
+	int val;
+
+	if (!nr_armdiv || !armdivmask)
+		return -EINVAL;
+
+	clkcon0 = __raw_readl(S3C2443_CLKDIV0);
+	clkcon0 &= armdivmask;
+	val = clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT;
+
+	return rate / armdiv[val];
+}
+
+static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate)
+{
+	unsigned long parent = clk_get_rate(clk->parent);
+	unsigned long calc;
+	unsigned div;
+	unsigned best = 256; /* bigger than any value */
+	int ptr;
+	int val = -1;
+
+	if (!nr_armdiv || !armdivmask)
+		return -EINVAL;
+
+	for (ptr = 0; ptr < nr_armdiv; ptr++) {
+		div = armdiv[ptr];
+		if (div) {
+			/* cpufreq provides 266mhz as 266666000 not 266666666 */
+			calc = (parent / div / 1000) * 1000;
+			if (calc <= rate && div < best) {
+				best = div;
+				val = ptr;
+			}
+		}
+	}
+
+	if (val >= 0) {
+		unsigned long clkcon0;
+
+		clkcon0 = __raw_readl(S3C2443_CLKDIV0);
+		clkcon0 &= ~armdivmask;
+		clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT;
+		__raw_writel(clkcon0, S3C2443_CLKDIV0);
+	}
+
+	return (val == -1) ? -EINVAL : 0;
+}
+
+static struct clk clk_armdiv = {
+	.name		= "armdiv",
+	.parent		= &clk_msysclk.clk,
+	.ops		= &(struct clk_ops) {
+		.round_rate = s3c2443_armclk_roundrate,
+		.get_rate = s3c2443_armclk_getrate,
+		.set_rate = s3c2443_armclk_setrate,
+	},
+};
+
+/* armclk
+ *
+ * this is the clock fed into the ARM core itself, from armdiv or from hclk.
+ */
+
+static struct clk *clk_arm_sources[] = {
+	[0] = &clk_armdiv,
+	[1] = &clk_h,
+};
+
+static struct clksrc_clk clk_arm = {
+	.clk	= {
+		.name		= "armclk",
+	},
+	.sources = &(struct clksrc_sources) {
+		.sources = clk_arm_sources,
+		.nr_sources = ARRAY_SIZE(clk_arm_sources),
+	},
+	.reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 },
+};
+
+/* usbhost
+ *
+ * usb host bus-clock, usually 48MHz to provide USB bus clock timing
+*/
+
+static struct clksrc_clk clk_usb_bus_host = {
+	.clk	= {
+		.name		= "usb-bus-host-parent",
+		.parent		= &clk_esysclk.clk,
+		.ctrlbit	= S3C2443_SCLKCON_USBHOST,
+		.enable		= s3c2443_clkcon_enable_s,
+	},
+	.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
+};
+
+/* common clksrc clocks */
+
+static struct clksrc_clk clksrc_clks[] = {
+	{
+		/* camera interface bus-clock, divided down from esysclk */
+		.clk	= {
+			.name		= "camif-upll",	/* same as 2440 name */
+			.parent		= &clk_esysclk.clk,
+			.ctrlbit	= S3C2443_SCLKCON_CAMCLK,
+			.enable		= s3c2443_clkcon_enable_s,
+		},
+		.reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
+	}, {
+		.clk	= {
+			.name		= "display-if",
+			.parent		= &clk_esysclk.clk,
+			.ctrlbit	= S3C2443_SCLKCON_DISPCLK,
+			.enable		= s3c2443_clkcon_enable_s,
+		},
+		.reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
+	},
+};
+
+static struct clksrc_clk clk_esys_uart = {
+	/* ART baud-rate clock sourced from esysclk via a divisor */
+	.clk	= {
+		.name		= "uartclk",
+		.parent		= &clk_esysclk.clk,
+	},
+	.reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
+};
+
+static struct clk clk_i2s_ext = {
+	.name		= "i2s-ext",
+};
+
+/* i2s_eplldiv
+ *
+ * This clock is the output from the I2S divisor of ESYSCLK, and is separate
+ * from the mux that comes after it (cannot merge into one single clock)
+*/
+
+static struct clksrc_clk clk_i2s_eplldiv = {
+	.clk	= {
+		.name		= "i2s-eplldiv",
+		.parent		= &clk_esysclk.clk,
+	},
+	.reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
+};
+
+/* i2s-ref
+ *
+ * i2s bus reference clock, selectable from external, esysclk or epllref
+ *
+ * Note, this used to be two clocks, but was compressed into one.
+*/
+
+static struct clk *clk_i2s_srclist[] = {
+	[0] = &clk_i2s_eplldiv.clk,
+	[1] = &clk_i2s_ext,
+	[2] = &clk_epllref.clk,
+	[3] = &clk_epllref.clk,
+};
+
+static struct clksrc_clk clk_i2s = {
+	.clk	= {
+		.name		= "i2s-if",
+		.ctrlbit	= S3C2443_SCLKCON_I2SCLK,
+		.enable		= s3c2443_clkcon_enable_s,
+
+	},
+	.sources = &(struct clksrc_sources) {
+		.sources = clk_i2s_srclist,
+		.nr_sources = ARRAY_SIZE(clk_i2s_srclist),
+	},
+	.reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
+};
+
+static struct clk init_clocks_off[] = {
+	{
+		.name		= "iis",
+		.parent		= &clk_p,
+		.enable		= s3c2443_clkcon_enable_p,
+		.ctrlbit	= S3C2443_PCLKCON_IIS,
+	}, {
+		.name		= "hsspi",
+		.parent		= &clk_p,
+		.enable		= s3c2443_clkcon_enable_p,
+		.ctrlbit	= S3C2443_PCLKCON_HSSPI,
+	}, {
+		.name		= "adc",
+		.parent		= &clk_p,
+		.enable		= s3c2443_clkcon_enable_p,
+		.ctrlbit	= S3C2443_PCLKCON_ADC,
+	}, {
+		.name		= "i2c",
+		.parent		= &clk_p,
+		.enable		= s3c2443_clkcon_enable_p,
+		.ctrlbit	= S3C2443_PCLKCON_IIC,
+	}
+};
+
+static struct clk init_clocks[] = {
+	{
+		.name		= "dma",
+		.parent		= &clk_h,
+		.enable		= s3c2443_clkcon_enable_h,
+		.ctrlbit	= S3C2443_HCLKCON_DMA0,
+	}, {
+		.name		= "dma",
+		.parent		= &clk_h,
+		.enable		= s3c2443_clkcon_enable_h,
+		.ctrlbit	= S3C2443_HCLKCON_DMA1,
+	}, {
+		.name		= "dma",
+		.parent		= &clk_h,
+		.enable		= s3c2443_clkcon_enable_h,
+		.ctrlbit	= S3C2443_HCLKCON_DMA2,
+	}, {
+		.name		= "dma",
+		.parent		= &clk_h,
+		.enable		= s3c2443_clkcon_enable_h,
+		.ctrlbit	= S3C2443_HCLKCON_DMA3,
+	}, {
+		.name		= "dma",
+		.parent		= &clk_h,
+		.enable		= s3c2443_clkcon_enable_h,
+		.ctrlbit	= S3C2443_HCLKCON_DMA4,
+	}, {
+		.name		= "dma",
+		.parent		= &clk_h,
+		.enable		= s3c2443_clkcon_enable_h,
+		.ctrlbit	= S3C2443_HCLKCON_DMA5,
+	}, {
+		.name		= "gpio",
+		.parent		= &clk_p,
+		.enable		= s3c2443_clkcon_enable_p,
+		.ctrlbit	= S3C2443_PCLKCON_GPIO,
+	}, {
+		.name		= "usb-host",
+		.parent		= &clk_h,
+		.enable		= s3c2443_clkcon_enable_h,
+		.ctrlbit	= S3C2443_HCLKCON_USBH,
+	}, {
+		.name		= "usb-device",
+		.parent		= &clk_h,
+		.enable		= s3c2443_clkcon_enable_h,
+		.ctrlbit	= S3C2443_HCLKCON_USBD,
+	}, {
+		.name		= "lcd",
+		.parent		= &clk_h,
+		.enable		= s3c2443_clkcon_enable_h,
+		.ctrlbit	= S3C2443_HCLKCON_LCDC,
+
+	}, {
+		.name		= "timers",
+		.parent		= &clk_p,
+		.enable		= s3c2443_clkcon_enable_p,
+		.ctrlbit	= S3C2443_PCLKCON_PWMT,
+	}, {
+		.name		= "cfc",
+		.parent		= &clk_h,
+		.enable		= s3c2443_clkcon_enable_h,
+		.ctrlbit	= S3C2443_HCLKCON_CFC,
+	}, {
+		.name		= "ssmc",
+		.parent		= &clk_h,
+		.enable		= s3c2443_clkcon_enable_h,
+		.ctrlbit	= S3C2443_HCLKCON_SSMC,
+	}, {
+		.name		= "uart",
+		.devname	= "s3c2440-uart.0",
+		.parent		= &clk_p,
+		.enable		= s3c2443_clkcon_enable_p,
+		.ctrlbit	= S3C2443_PCLKCON_UART0,
+	}, {
+		.name		= "uart",
+		.devname	= "s3c2440-uart.1",
+		.parent		= &clk_p,
+		.enable		= s3c2443_clkcon_enable_p,
+		.ctrlbit	= S3C2443_PCLKCON_UART1,
+	}, {
+		.name		= "uart",
+		.devname	= "s3c2440-uart.2",
+		.parent		= &clk_p,
+		.enable		= s3c2443_clkcon_enable_p,
+		.ctrlbit	= S3C2443_PCLKCON_UART2,
+	}, {
+		.name		= "uart",
+		.devname	= "s3c2440-uart.3",
+		.parent		= &clk_p,
+		.enable		= s3c2443_clkcon_enable_p,
+		.ctrlbit	= S3C2443_PCLKCON_UART3,
+	}, {
+		.name		= "rtc",
+		.parent		= &clk_p,
+		.enable		= s3c2443_clkcon_enable_p,
+		.ctrlbit	= S3C2443_PCLKCON_RTC,
+	}, {
+		.name		= "watchdog",
+		.parent		= &clk_p,
+		.ctrlbit	= S3C2443_PCLKCON_WDT,
+	}, {
+		.name		= "ac97",
+		.parent		= &clk_p,
+		.ctrlbit	= S3C2443_PCLKCON_AC97,
+	}, {
+		.name		= "nand",
+		.parent		= &clk_h,
+	}, {
+		.name		= "usb-bus-host",
+		.parent		= &clk_usb_bus_host.clk,
+	}
+};
+
+static struct clk hsmmc1_clk = {
+	.name		= "hsmmc",
+	.devname	= "s3c-sdhci.1",
+	.parent		= &clk_h,
+	.enable		= s3c2443_clkcon_enable_h,
+	.ctrlbit	= S3C2443_HCLKCON_HSMMC,
+};
+
+/* EPLLCON compatible enough to get on/off information */
+
+void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll)
+{
+	unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
+	unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
+	struct clk *xtal_clk;
+	unsigned long xtal;
+	unsigned long pll;
+	int ptr;
+
+	xtal_clk = clk_get(NULL, "xtal");
+	xtal = clk_get_rate(xtal_clk);
+	clk_put(xtal_clk);
+
+	pll = get_mpll(mpllcon, xtal);
+	clk_msysclk.clk.rate = pll;
+	clk_mpll.rate = pll;
+
+	printk("CPU: MPLL %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
+	       (mpllcon & S3C2443_PLLCON_OFF) ? "off" : "on",
+	       print_mhz(pll), print_mhz(clk_get_rate(&clk_armdiv)),
+	       print_mhz(clk_get_rate(&clk_h)),
+	       print_mhz(clk_get_rate(&clk_p)));
+
+	for (ptr = 0; ptr < ARRAY_SIZE(clksrc_clks); ptr++)
+		s3c_set_clksrc(&clksrc_clks[ptr], true);
+
+	/* ensure usb bus clock is within correct rate of 48MHz */
+
+	if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
+		printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
+		clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
+	}
+
+	printk("CPU: EPLL %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
+	       (epllcon & S3C2443_PLLCON_OFF) ? "off" : "on",
+	       print_mhz(clk_get_rate(&clk_epll)),
+	       print_mhz(clk_get_rate(&clk_usb_bus)));
+}
+
+static struct clk *clks[] __initdata = {
+	&clk_prediv,
+	&clk_mpllref,
+	&clk_mdivclk,
+	&clk_ext,
+	&clk_epll,
+	&clk_usb_bus,
+	&clk_armdiv,
+	&hsmmc1_clk,
+};
+
+static struct clksrc_clk *clksrcs[] __initdata = {
+	&clk_i2s_eplldiv,
+	&clk_i2s,
+	&clk_usb_bus_host,
+	&clk_epllref,
+	&clk_esysclk,
+	&clk_msysclk,
+	&clk_arm,
+};
+
+static struct clk_lookup s3c2443_clk_lookup[] = {
+	CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
+	CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
+	CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_esys_uart.clk),
+	CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &hsmmc1_clk),
+};
+
+void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
+				       unsigned int *divs, int nr_divs,
+				       int divmask)
+{
+	int ptr;
+
+	armdiv = divs;
+	nr_armdiv = nr_divs;
+	armdivmask = divmask;
+
+	/* s3c2443 parents h clock from prediv */
+	clk_h.parent = &clk_prediv;
+	clk_h.ops = &clk_h_ops;
+
+	/* and p clock from h clock */
+	clk_p.parent = &clk_h;
+	clk_p.ops = &clk_p_ops;
+
+	clk_usb_bus.parent = &clk_usb_bus_host.clk;
+	clk_epll.parent = &clk_epllref.clk;
+
+	s3c24xx_register_baseclocks(xtal);
+	s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
+
+	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
+		s3c_register_clksrc(clksrcs[ptr], 1);
+
+	s3c_register_clksrc(clksrc_clks, ARRAY_SIZE(clksrc_clks));
+	s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
+
+	/* See s3c2443/etc notes on disabling clocks at init time */
+	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+	clkdev_add_table(s3c2443_clk_lookup, ARRAY_SIZE(s3c2443_clk_lookup));
+
+	s3c2443_common_setup_clocks(get_mpll);
+}
diff --git a/arch/arm/plat-s3c24xx/common-smdk.c b/arch/arm/mach-s3c24xx/common-smdk.c
similarity index 100%
rename from arch/arm/plat-s3c24xx/common-smdk.c
rename to arch/arm/mach-s3c24xx/common-smdk.c
diff --git a/arch/arm/mach-s3c24xx/common.h b/arch/arm/mach-s3c24xx/common.h
new file mode 100644
index 0000000..c2f596e
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/common.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Common Header for S3C24XX SoCs
+ *
+ * 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 __ARCH_ARM_MACH_S3C24XX_COMMON_H
+#define __ARCH_ARM_MACH_S3C24XX_COMMON_H __FILE__
+
+void s3c2410_restart(char mode, const char *cmd);
+void s3c244x_restart(char mode, const char *cmd);
+
+#endif /* __ARCH_ARM_MACH_S3C24XX_COMMON_H */
diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c24xx/dma-s3c2410.c
similarity index 100%
rename from arch/arm/mach-s3c2410/dma.c
rename to arch/arm/mach-s3c24xx/dma-s3c2410.c
diff --git a/arch/arm/mach-s3c2412/dma.c b/arch/arm/mach-s3c24xx/dma-s3c2412.c
similarity index 100%
rename from arch/arm/mach-s3c2412/dma.c
rename to arch/arm/mach-s3c24xx/dma-s3c2412.c
diff --git a/arch/arm/mach-s3c2440/dma.c b/arch/arm/mach-s3c24xx/dma-s3c2440.c
similarity index 100%
rename from arch/arm/mach-s3c2440/dma.c
rename to arch/arm/mach-s3c24xx/dma-s3c2440.c
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2443.c b/arch/arm/mach-s3c24xx/dma-s3c2443.c
new file mode 100644
index 0000000..e227c47
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/dma-s3c2443.c
@@ -0,0 +1,174 @@
+/* linux/arch/arm/mach-s3c2443/dma.c
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2443 DMA selection
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * 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/device.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+#include <mach/dma.h>
+
+#include <plat/dma-s3c24xx.h>
+#include <plat/cpu.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <plat/regs-ac97.h>
+#include <plat/regs-dma.h>
+#include <mach/regs-mem.h>
+#include <mach/regs-lcd.h>
+#include <mach/regs-sdi.h>
+#include <plat/regs-iis.h>
+#include <plat/regs-spi.h>
+
+#define MAP(x) { \
+		[0]	= (x) | DMA_CH_VALID,	\
+		[1]	= (x) | DMA_CH_VALID,	\
+		[2]	= (x) | DMA_CH_VALID,	\
+		[3]	= (x) | DMA_CH_VALID,	\
+		[4]	= (x) | DMA_CH_VALID,	\
+		[5]     = (x) | DMA_CH_VALID,	\
+	}
+
+static struct s3c24xx_dma_map __initdata s3c2443_dma_mappings[] = {
+	[DMACH_XD0] = {
+		.name		= "xdreq0",
+		.channels	= MAP(S3C2443_DMAREQSEL_XDREQ0),
+	},
+	[DMACH_XD1] = {
+		.name		= "xdreq1",
+		.channels	= MAP(S3C2443_DMAREQSEL_XDREQ1),
+	},
+	[DMACH_SDI] = { /* only on S3C2443 */
+		.name		= "sdi",
+		.channels	= MAP(S3C2443_DMAREQSEL_SDI),
+	},
+	[DMACH_SPI0] = {
+		.name		= "spi0",
+		.channels	= MAP(S3C2443_DMAREQSEL_SPI0TX),
+	},
+	[DMACH_SPI1] = { /* only on S3C2443/S3C2450 */
+		.name		= "spi1",
+		.channels	= MAP(S3C2443_DMAREQSEL_SPI1TX),
+	},
+	[DMACH_UART0] = {
+		.name		= "uart0",
+		.channels	= MAP(S3C2443_DMAREQSEL_UART0_0),
+	},
+	[DMACH_UART1] = {
+		.name		= "uart1",
+		.channels	= MAP(S3C2443_DMAREQSEL_UART1_0),
+	},
+	[DMACH_UART2] = {
+		.name		= "uart2",
+		.channels	= MAP(S3C2443_DMAREQSEL_UART2_0),
+	},
+	[DMACH_UART3] = {
+		.name		= "uart3",
+		.channels	= MAP(S3C2443_DMAREQSEL_UART3_0),
+	},
+	[DMACH_UART0_SRC2] = {
+		.name		= "uart0",
+		.channels	= MAP(S3C2443_DMAREQSEL_UART0_1),
+	},
+	[DMACH_UART1_SRC2] = {
+		.name		= "uart1",
+		.channels	= MAP(S3C2443_DMAREQSEL_UART1_1),
+	},
+	[DMACH_UART2_SRC2] = {
+		.name		= "uart2",
+		.channels	= MAP(S3C2443_DMAREQSEL_UART2_1),
+	},
+	[DMACH_UART3_SRC2] = {
+		.name		= "uart3",
+		.channels	= MAP(S3C2443_DMAREQSEL_UART3_1),
+	},
+	[DMACH_TIMER] = {
+		.name		= "timer",
+		.channels	= MAP(S3C2443_DMAREQSEL_TIMER),
+	},
+	[DMACH_I2S_IN] = {
+		.name		= "i2s-sdi",
+		.channels	= MAP(S3C2443_DMAREQSEL_I2SRX),
+	},
+	[DMACH_I2S_OUT] = {
+		.name		= "i2s-sdo",
+		.channels	= MAP(S3C2443_DMAREQSEL_I2STX),
+	},
+	[DMACH_PCM_IN] = {
+		.name		= "pcm-in",
+		.channels	= MAP(S3C2443_DMAREQSEL_PCMIN),
+	},
+	[DMACH_PCM_OUT] = {
+		.name		= "pcm-out",
+		.channels	= MAP(S3C2443_DMAREQSEL_PCMOUT),
+	},
+	[DMACH_MIC_IN] = {
+		.name		= "mic-in",
+		.channels	= MAP(S3C2443_DMAREQSEL_MICIN),
+	},
+};
+
+static void s3c2443_dma_select(struct s3c2410_dma_chan *chan,
+			       struct s3c24xx_dma_map *map)
+{
+	writel(map->channels[0] | S3C2443_DMAREQSEL_HW,
+	       chan->regs + S3C2443_DMA_DMAREQSEL);
+}
+
+static struct s3c24xx_dma_selection __initdata s3c2443_dma_sel = {
+	.select		= s3c2443_dma_select,
+	.dcon_mask	= 0,
+	.map		= s3c2443_dma_mappings,
+	.map_size	= ARRAY_SIZE(s3c2443_dma_mappings),
+};
+
+static int __init s3c2443_dma_add(struct device *dev,
+				  struct subsys_interface *sif)
+{
+	s3c24xx_dma_init(6, IRQ_S3C2443_DMA0, 0x100);
+	return s3c24xx_dma_init_map(&s3c2443_dma_sel);
+}
+
+#ifdef CONFIG_CPU_S3C2416
+/* S3C2416 DMA contains the same selection table as the S3C2443 */
+static struct subsys_interface s3c2416_dma_interface = {
+	.name		= "s3c2416_dma",
+	.subsys		= &s3c2416_subsys,
+	.add_dev	= s3c2443_dma_add,
+};
+
+static int __init s3c2416_dma_init(void)
+{
+	return subsys_interface_register(&s3c2416_dma_interface);
+}
+
+arch_initcall(s3c2416_dma_init);
+#endif
+
+#ifdef CONFIG_CPU_S3C2443
+static struct subsys_interface s3c2443_dma_interface = {
+	.name		= "s3c2443_dma",
+	.subsys		= &s3c2443_subsys,
+	.add_dev	= s3c2443_dma_add,
+};
+
+static int __init s3c2443_dma_init(void)
+{
+	return subsys_interface_register(&s3c2443_dma_interface);
+}
+
+arch_initcall(s3c2443_dma_init);
+#endif
diff --git a/arch/arm/mach-s3c2410/h1940-bluetooth.c b/arch/arm/mach-s3c24xx/h1940-bluetooth.c
similarity index 100%
rename from arch/arm/mach-s3c2410/h1940-bluetooth.c
rename to arch/arm/mach-s3c24xx/h1940-bluetooth.c
diff --git a/arch/arm/mach-s3c2410/include/mach/anubis-cpld.h b/arch/arm/mach-s3c24xx/include/mach/anubis-cpld.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/anubis-cpld.h
rename to arch/arm/mach-s3c24xx/include/mach/anubis-cpld.h
diff --git a/arch/arm/mach-s3c2410/include/mach/anubis-irq.h b/arch/arm/mach-s3c24xx/include/mach/anubis-irq.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/anubis-irq.h
rename to arch/arm/mach-s3c24xx/include/mach/anubis-irq.h
diff --git a/arch/arm/mach-s3c2410/include/mach/anubis-map.h b/arch/arm/mach-s3c24xx/include/mach/anubis-map.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/anubis-map.h
rename to arch/arm/mach-s3c24xx/include/mach/anubis-map.h
diff --git a/arch/arm/mach-s3c2410/include/mach/bast-cpld.h b/arch/arm/mach-s3c24xx/include/mach/bast-cpld.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/bast-cpld.h
rename to arch/arm/mach-s3c24xx/include/mach/bast-cpld.h
diff --git a/arch/arm/mach-s3c2410/include/mach/bast-irq.h b/arch/arm/mach-s3c24xx/include/mach/bast-irq.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/bast-irq.h
rename to arch/arm/mach-s3c24xx/include/mach/bast-irq.h
diff --git a/arch/arm/mach-s3c2410/include/mach/bast-map.h b/arch/arm/mach-s3c24xx/include/mach/bast-map.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/bast-map.h
rename to arch/arm/mach-s3c24xx/include/mach/bast-map.h
diff --git a/arch/arm/mach-s3c2410/include/mach/bast-pmu.h b/arch/arm/mach-s3c24xx/include/mach/bast-pmu.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/bast-pmu.h
rename to arch/arm/mach-s3c24xx/include/mach/bast-pmu.h
diff --git a/arch/arm/mach-s3c2410/include/mach/debug-macro.S b/arch/arm/mach-s3c24xx/include/mach/debug-macro.S
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/debug-macro.S
rename to arch/arm/mach-s3c24xx/include/mach/debug-macro.S
diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c24xx/include/mach/dma.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/dma.h
rename to arch/arm/mach-s3c24xx/include/mach/dma.h
diff --git a/arch/arm/mach-s3c24xx/include/mach/entry-macro.S b/arch/arm/mach-s3c24xx/include/mach/entry-macro.S
new file mode 100644
index 0000000..7615a14
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/include/mach/entry-macro.S
@@ -0,0 +1,70 @@
+/*
+ * arch/arm/mach-s3c2410/include/mach/entry-macro.S
+ *
+ * Low-level IRQ helper macros for S3C2410-based platforms
+ *
+ * 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.
+*/
+
+/* We have a problem that the INTOFFSET register does not always
+ * show one interrupt. Occasionally we get two interrupts through
+ * the prioritiser, and this causes the INTOFFSET register to show
+ * what looks like the logical-or of the two interrupt numbers.
+ *
+ * Thanks to Klaus, Shannon, et al for helping to debug this problem
+*/
+
+#define INTPND		(0x10)
+#define INTOFFSET	(0x14)
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+	.macro  get_irqnr_preamble, base, tmp
+	.endm
+
+	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
+
+		mov	\base, #S3C24XX_VA_IRQ
+
+		@@ try the interrupt offset register, since it is there
+
+		ldr	\irqstat, [ \base, #INTPND ]
+		teq	\irqstat, #0
+		beq	1002f
+		ldr	\irqnr, [ \base, #INTOFFSET ]
+		mov	\tmp, #1
+		tst	\irqstat, \tmp, lsl \irqnr
+		bne	1001f
+
+		@@ the number specified is not a valid irq, so try
+		@@ and work it out for ourselves
+
+		mov	\irqnr, #0		@@ start here
+
+		@@ work out which irq (if any) we got
+
+		movs	\tmp, \irqstat, lsl#16
+		addeq	\irqnr, \irqnr, #16
+		moveq	\irqstat, \irqstat, lsr#16
+		tst	\irqstat, #0xff
+		addeq	\irqnr, \irqnr, #8
+		moveq	\irqstat, \irqstat, lsr#8
+		tst	\irqstat, #0xf
+		addeq	\irqnr, \irqnr, #4
+		moveq	\irqstat, \irqstat, lsr#4
+		tst	\irqstat, #0x3
+		addeq	\irqnr, \irqnr, #2
+		moveq	\irqstat, \irqstat, lsr#2
+		tst	\irqstat, #0x1
+		addeq	\irqnr, \irqnr, #1
+
+		@@ we have the value
+1001:
+		adds	\irqnr, \irqnr, #IRQ_EINT0
+1002:
+		@@ exit here, Z flag unset if IRQ
+
+	.endm
diff --git a/arch/arm/mach-s3c2410/include/mach/fb.h b/arch/arm/mach-s3c24xx/include/mach/fb.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/fb.h
rename to arch/arm/mach-s3c24xx/include/mach/fb.h
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio-fns.h b/arch/arm/mach-s3c24xx/include/mach/gpio-fns.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/gpio-fns.h
rename to arch/arm/mach-s3c24xx/include/mach/gpio-fns.h
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio-nrs.h b/arch/arm/mach-s3c24xx/include/mach/gpio-nrs.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
rename to arch/arm/mach-s3c24xx/include/mach/gpio-nrs.h
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio-track.h b/arch/arm/mach-s3c24xx/include/mach/gpio-track.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/gpio-track.h
rename to arch/arm/mach-s3c24xx/include/mach/gpio-track.h
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio.h b/arch/arm/mach-s3c24xx/include/mach/gpio.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/gpio.h
rename to arch/arm/mach-s3c24xx/include/mach/gpio.h
diff --git a/arch/arm/mach-s3c2440/include/mach/gta02.h b/arch/arm/mach-s3c24xx/include/mach/gta02.h
similarity index 100%
rename from arch/arm/mach-s3c2440/include/mach/gta02.h
rename to arch/arm/mach-s3c24xx/include/mach/gta02.h
diff --git a/arch/arm/mach-s3c2410/include/mach/h1940-latch.h b/arch/arm/mach-s3c24xx/include/mach/h1940-latch.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/h1940-latch.h
rename to arch/arm/mach-s3c24xx/include/mach/h1940-latch.h
diff --git a/arch/arm/mach-s3c2410/include/mach/h1940.h b/arch/arm/mach-s3c24xx/include/mach/h1940.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/h1940.h
rename to arch/arm/mach-s3c24xx/include/mach/h1940.h
diff --git a/arch/arm/mach-s3c2410/include/mach/hardware.h b/arch/arm/mach-s3c24xx/include/mach/hardware.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/hardware.h
rename to arch/arm/mach-s3c24xx/include/mach/hardware.h
diff --git a/arch/arm/mach-s3c2410/include/mach/idle.h b/arch/arm/mach-s3c24xx/include/mach/idle.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/idle.h
rename to arch/arm/mach-s3c24xx/include/mach/idle.h
diff --git a/arch/arm/mach-s3c24xx/include/mach/io.h b/arch/arm/mach-s3c24xx/include/mach/io.h
new file mode 100644
index 0000000..5dd1db4
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/include/mach/io.h
@@ -0,0 +1,211 @@
+/*
+ * arch/arm/mach-s3c2410/include/mach/io.h
+ *  from arch/arm/mach-rpc/include/mach/io.h
+ *
+ * Copyright (C) 1997 Russell King
+ *	     (C) 2003 Simtec Electronics
+*/
+
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#include <mach/hardware.h>
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*
+ * We use two different types of addressing - PC style addresses, and ARM
+ * addresses.  PC style accesses the PC hardware with the normal PC IO
+ * addresses, eg 0x3f8 for serial#1.  ARM addresses are above A28
+ * and are translated to the start of IO.  Note that all addresses are
+ * not shifted left!
+ */
+
+#define __PORT_PCIO(x)	((x) < (1<<28))
+
+#define PCIO_BASE	 (S3C24XX_VA_ISA_WORD)
+#define PCIO_BASE_b	 (S3C24XX_VA_ISA_BYTE)
+#define PCIO_BASE_w	 (S3C24XX_VA_ISA_WORD)
+#define PCIO_BASE_l	 (S3C24XX_VA_ISA_WORD)
+/*
+ * Dynamic IO functions - let the compiler
+ * optimize the expressions
+ */
+
+#define DECLARE_DYN_OUT(sz,fnsuffix,instr) \
+static inline void __out##fnsuffix (unsigned int val, unsigned int port) \
+{ \
+	unsigned long temp;				      \
+	__asm__ __volatile__(				      \
+	"cmp	%2, #(1<<28)\n\t"			      \
+	"mov	%0, %2\n\t"				      \
+	"addcc	%0, %0, %3\n\t"				      \
+	"str" instr " %1, [%0, #0 ]	@ out" #fnsuffix      \
+	: "=&r" (temp)					      \
+	: "r" (val), "r" (port), "Ir" (PCIO_BASE_##fnsuffix)  \
+	: "cc");					      \
+}
+
+
+#define DECLARE_DYN_IN(sz,fnsuffix,instr)				\
+static inline unsigned sz __in##fnsuffix (unsigned int port)		\
+{									\
+	unsigned long temp, value;					\
+	__asm__ __volatile__(						\
+	"cmp	%2, #(1<<28)\n\t"					\
+	"mov	%0, %2\n\t"						\
+	"addcc	%0, %0, %3\n\t"						\
+	"ldr" instr "	%1, [%0, #0 ]	@ in" #fnsuffix		\
+	: "=&r" (temp), "=r" (value)					\
+	: "r" (port), "Ir" (PCIO_BASE_##fnsuffix)	\
+	: "cc");							\
+	return (unsigned sz)value;					\
+}
+
+static inline void __iomem *__ioaddr (unsigned long port)
+{
+	return __PORT_PCIO(port) ? (PCIO_BASE + port) : (void __iomem *)port;
+}
+
+#define DECLARE_IO(sz,fnsuffix,instr)	\
+	DECLARE_DYN_IN(sz,fnsuffix,instr) \
+	DECLARE_DYN_OUT(sz,fnsuffix,instr)
+
+DECLARE_IO(char,b,"b")
+DECLARE_IO(short,w,"h")
+DECLARE_IO(int,l,"")
+
+#undef DECLARE_IO
+#undef DECLARE_DYN_IN
+
+/*
+ * Constant address IO functions
+ *
+ * These have to be macros for the 'J' constraint to work -
+ * +/-4096 immediate operand.
+ */
+#define __outbc(value,port)						\
+({									\
+	if (__PORT_PCIO((port)))					\
+		__asm__ __volatile__(					\
+		"strb	%0, [%1, %2]	@ outbc"			\
+		: : "r" (value), "r" (PCIO_BASE), "Jr" ((port)));	\
+	else								\
+		__asm__ __volatile__(					\
+		"strb	%0, [%1, #0]	@ outbc"			\
+		: : "r" (value), "r" ((port)));				\
+})
+
+#define __inbc(port)							\
+({									\
+	unsigned char result;						\
+	if (__PORT_PCIO((port)))					\
+		__asm__ __volatile__(					\
+		"ldrb	%0, [%1, %2]	@ inbc"				\
+		: "=r" (result) : "r" (PCIO_BASE), "Jr" ((port)));	\
+	else								\
+		__asm__ __volatile__(					\
+		"ldrb	%0, [%1, #0]	@ inbc"				\
+		: "=r" (result) : "r" ((port)));			\
+	result;								\
+})
+
+#define __outwc(value,port)						\
+({									\
+	unsigned long v = value;					\
+	if (__PORT_PCIO((port))) {					\
+		if ((port) < 256 && (port) > -256)			\
+			__asm__ __volatile__(				\
+			"strh	%0, [%1, %2]	@ outwc"		\
+			: : "r" (v), "r" (PCIO_BASE), "Jr" ((port)));	\
+		else if ((port) > 0)					\
+			__asm__ __volatile__(				\
+			"strh	%0, [%1, %2]	@ outwc"		\
+			: : "r" (v),					\
+			    "r" (PCIO_BASE + ((port) & ~0xff)),		\
+			     "Jr" (((port) & 0xff)));			\
+		else							\
+			__asm__ __volatile__(				\
+			"strh	%0, [%1, #0]	@ outwc"		\
+			: : "r" (v),					\
+			    "r" (PCIO_BASE + (port)));			\
+	} else								\
+		__asm__ __volatile__(					\
+		"strh	%0, [%1, #0]	@ outwc"			\
+		: : "r" (v), "r" ((port)));				\
+})
+
+#define __inwc(port)							\
+({									\
+	unsigned short result;						\
+	if (__PORT_PCIO((port))) {					\
+		if ((port) < 256 && (port) > -256 )			\
+			__asm__ __volatile__(				\
+			"ldrh	%0, [%1, %2]	@ inwc"			\
+			: "=r" (result)					\
+			: "r" (PCIO_BASE),				\
+			  "Jr" ((port)));				\
+		else if ((port) > 0)					\
+			__asm__ __volatile__(				\
+			"ldrh	%0, [%1, %2]	@ inwc"			\
+			: "=r" (result)					\
+			: "r" (PCIO_BASE + ((port) & ~0xff)),		\
+			  "Jr" (((port) & 0xff)));			\
+		else							\
+			__asm__ __volatile__(				\
+			"ldrh	%0, [%1, #0]	@ inwc"			\
+			: "=r" (result)					\
+			: "r" (PCIO_BASE + ((port))));			\
+	} else								\
+		__asm__ __volatile__(					\
+		"ldrh	%0, [%1, #0]	@ inwc"				\
+		: "=r" (result) : "r" ((port)));			\
+	result;								\
+})
+
+#define __outlc(value,port)						\
+({									\
+	unsigned long v = value;					\
+	if (__PORT_PCIO((port)))					\
+		__asm__ __volatile__(					\
+		"str	%0, [%1, %2]	@ outlc"			\
+		: : "r" (v), "r" (PCIO_BASE), "Jr" ((port)));	\
+	else								\
+		__asm__ __volatile__(					\
+		"str	%0, [%1, #0]	@ outlc"			\
+		: : "r" (v), "r" ((port)));		\
+})
+
+#define __inlc(port)							\
+({									\
+	unsigned long result;						\
+	if (__PORT_PCIO((port)))					\
+		__asm__ __volatile__(					\
+		"ldr	%0, [%1, %2]	@ inlc"				\
+		: "=r" (result) : "r" (PCIO_BASE), "Jr" ((port)));	\
+	else								\
+		__asm__ __volatile__(					\
+		"ldr	%0, [%1, #0]	@ inlc"				\
+		: "=r" (result) : "r" ((port)));		\
+	result;								\
+})
+
+#define __ioaddrc(port)	((__PORT_PCIO(port) ? PCIO_BASE + (port) : (void __iomem *)(port)))
+
+#define inb(p)		(__builtin_constant_p((p)) ? __inbc(p)	   : __inb(p))
+#define inw(p)		(__builtin_constant_p((p)) ? __inwc(p)	   : __inw(p))
+#define inl(p)		(__builtin_constant_p((p)) ? __inlc(p)	   : __inl(p))
+#define outb(v,p)	(__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p))
+#define outw(v,p)	(__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p))
+#define outl(v,p)	(__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p))
+#define __ioaddr(p)	(__builtin_constant_p((p)) ? __ioaddr(p)  : __ioaddrc(p))
+
+#define insb(p,d,l)	__raw_readsb(__ioaddr(p),d,l)
+#define insw(p,d,l)	__raw_readsw(__ioaddr(p),d,l)
+#define insl(p,d,l)	__raw_readsl(__ioaddr(p),d,l)
+
+#define outsb(p,d,l)	__raw_writesb(__ioaddr(p),d,l)
+#define outsw(p,d,l)	__raw_writesw(__ioaddr(p),d,l)
+#define outsl(p,d,l)	__raw_writesl(__ioaddr(p),d,l)
+
+#endif
diff --git a/arch/arm/mach-s3c2410/include/mach/irqs.h b/arch/arm/mach-s3c24xx/include/mach/irqs.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/irqs.h
rename to arch/arm/mach-s3c24xx/include/mach/irqs.h
diff --git a/arch/arm/mach-s3c2410/include/mach/leds-gpio.h b/arch/arm/mach-s3c24xx/include/mach/leds-gpio.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/leds-gpio.h
rename to arch/arm/mach-s3c24xx/include/mach/leds-gpio.h
diff --git a/arch/arm/mach-s3c2410/include/mach/map.h b/arch/arm/mach-s3c24xx/include/mach/map.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/map.h
rename to arch/arm/mach-s3c24xx/include/mach/map.h
diff --git a/arch/arm/mach-s3c2410/include/mach/osiris-cpld.h b/arch/arm/mach-s3c24xx/include/mach/osiris-cpld.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/osiris-cpld.h
rename to arch/arm/mach-s3c24xx/include/mach/osiris-cpld.h
diff --git a/arch/arm/mach-s3c2410/include/mach/osiris-map.h b/arch/arm/mach-s3c24xx/include/mach/osiris-map.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/osiris-map.h
rename to arch/arm/mach-s3c24xx/include/mach/osiris-map.h
diff --git a/arch/arm/mach-s3c2410/include/mach/otom-map.h b/arch/arm/mach-s3c24xx/include/mach/otom-map.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/otom-map.h
rename to arch/arm/mach-s3c24xx/include/mach/otom-map.h
diff --git a/arch/arm/mach-s3c2410/include/mach/pm-core.h b/arch/arm/mach-s3c24xx/include/mach/pm-core.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/pm-core.h
rename to arch/arm/mach-s3c24xx/include/mach/pm-core.h
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-clock.h b/arch/arm/mach-s3c24xx/include/mach/regs-clock.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/regs-clock.h
rename to arch/arm/mach-s3c24xx/include/mach/regs-clock.h
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-dsc.h b/arch/arm/mach-s3c24xx/include/mach/regs-dsc.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/regs-dsc.h
rename to arch/arm/mach-s3c24xx/include/mach/regs-dsc.h
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-gpio.h b/arch/arm/mach-s3c24xx/include/mach/regs-gpio.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/regs-gpio.h
rename to arch/arm/mach-s3c24xx/include/mach/regs-gpio.h
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-gpioj.h b/arch/arm/mach-s3c24xx/include/mach/regs-gpioj.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/regs-gpioj.h
rename to arch/arm/mach-s3c24xx/include/mach/regs-gpioj.h
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-irq.h b/arch/arm/mach-s3c24xx/include/mach/regs-irq.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/regs-irq.h
rename to arch/arm/mach-s3c24xx/include/mach/regs-irq.h
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-lcd.h b/arch/arm/mach-s3c24xx/include/mach/regs-lcd.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/regs-lcd.h
rename to arch/arm/mach-s3c24xx/include/mach/regs-lcd.h
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-mem.h b/arch/arm/mach-s3c24xx/include/mach/regs-mem.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/regs-mem.h
rename to arch/arm/mach-s3c24xx/include/mach/regs-mem.h
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-power.h b/arch/arm/mach-s3c24xx/include/mach/regs-power.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/regs-power.h
rename to arch/arm/mach-s3c24xx/include/mach/regs-power.h
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-s3c2412-mem.h b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2412-mem.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/regs-s3c2412-mem.h
rename to arch/arm/mach-s3c24xx/include/mach/regs-s3c2412-mem.h
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-s3c2412.h b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2412.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/regs-s3c2412.h
rename to arch/arm/mach-s3c24xx/include/mach/regs-s3c2412.h
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-s3c2416-mem.h b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2416-mem.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/regs-s3c2416-mem.h
rename to arch/arm/mach-s3c24xx/include/mach/regs-s3c2416-mem.h
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-s3c2416.h b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2416.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/regs-s3c2416.h
rename to arch/arm/mach-s3c24xx/include/mach/regs-s3c2416.h
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2443-clock.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h
rename to arch/arm/mach-s3c24xx/include/mach/regs-s3c2443-clock.h
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-sdi.h b/arch/arm/mach-s3c24xx/include/mach/regs-sdi.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/regs-sdi.h
rename to arch/arm/mach-s3c24xx/include/mach/regs-sdi.h
diff --git a/arch/arm/mach-s3c2410/include/mach/tick.h b/arch/arm/mach-s3c24xx/include/mach/tick.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/tick.h
rename to arch/arm/mach-s3c24xx/include/mach/tick.h
diff --git a/arch/arm/mach-s3c2410/include/mach/timex.h b/arch/arm/mach-s3c24xx/include/mach/timex.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/timex.h
rename to arch/arm/mach-s3c24xx/include/mach/timex.h
diff --git a/arch/arm/mach-s3c2410/include/mach/uncompress.h b/arch/arm/mach-s3c24xx/include/mach/uncompress.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/uncompress.h
rename to arch/arm/mach-s3c24xx/include/mach/uncompress.h
diff --git a/arch/arm/mach-s3c2410/include/mach/vr1000-cpld.h b/arch/arm/mach-s3c24xx/include/mach/vr1000-cpld.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/vr1000-cpld.h
rename to arch/arm/mach-s3c24xx/include/mach/vr1000-cpld.h
diff --git a/arch/arm/mach-s3c2410/include/mach/vr1000-irq.h b/arch/arm/mach-s3c24xx/include/mach/vr1000-irq.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/vr1000-irq.h
rename to arch/arm/mach-s3c24xx/include/mach/vr1000-irq.h
diff --git a/arch/arm/mach-s3c2410/include/mach/vr1000-map.h b/arch/arm/mach-s3c24xx/include/mach/vr1000-map.h
similarity index 100%
rename from arch/arm/mach-s3c2410/include/mach/vr1000-map.h
rename to arch/arm/mach-s3c24xx/include/mach/vr1000-map.h
diff --git a/arch/arm/mach-s3c2412/irq.c b/arch/arm/mach-s3c24xx/irq-s3c2412.c
similarity index 100%
rename from arch/arm/mach-s3c2412/irq.c
rename to arch/arm/mach-s3c24xx/irq-s3c2412.c
diff --git a/arch/arm/mach-s3c2416/irq.c b/arch/arm/mach-s3c24xx/irq-s3c2416.c
similarity index 100%
rename from arch/arm/mach-s3c2416/irq.c
rename to arch/arm/mach-s3c24xx/irq-s3c2416.c
diff --git a/arch/arm/mach-s3c2440/irq.c b/arch/arm/mach-s3c24xx/irq-s3c2440.c
similarity index 100%
rename from arch/arm/mach-s3c2440/irq.c
rename to arch/arm/mach-s3c24xx/irq-s3c2440.c
diff --git a/arch/arm/mach-s3c2443/irq.c b/arch/arm/mach-s3c24xx/irq-s3c2443.c
similarity index 100%
rename from arch/arm/mach-s3c2443/irq.c
rename to arch/arm/mach-s3c24xx/irq-s3c2443.c
diff --git a/arch/arm/mach-s3c2440/s3c244x-irq.c b/arch/arm/mach-s3c24xx/irq-s3c244x.c
similarity index 100%
rename from arch/arm/mach-s3c2440/s3c244x-irq.c
rename to arch/arm/mach-s3c24xx/irq-s3c244x.c
diff --git a/arch/arm/mach-s3c2410/mach-amlm5900.c b/arch/arm/mach-s3c24xx/mach-amlm5900.c
similarity index 100%
rename from arch/arm/mach-s3c2410/mach-amlm5900.c
rename to arch/arm/mach-s3c24xx/mach-amlm5900.c
diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c
new file mode 100644
index 0000000..60c72c5
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/mach-anubis.c
@@ -0,0 +1,492 @@
+/* linux/arch/arm/mach-s3c2440/mach-anubis.c
+ *
+ * Copyright 2003-2009 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/sm501.h>
+#include <linux/sm501-regs.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/anubis-map.h>
+#include <mach/anubis-irq.h>
+#include <mach/anubis-cpld.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-mem.h>
+#include <mach/regs-lcd.h>
+#include <plat/nand.h>
+#include <plat/iic.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <net/ax88796.h>
+
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/audio-simtec.h>
+
+#include "simtec.h"
+#include "common.h"
+
+#define COPYRIGHT ", Copyright 2005-2009 Simtec Electronics"
+
+static struct map_desc anubis_iodesc[] __initdata = {
+  /* ISA IO areas */
+
+  {
+	.virtual	= (u32)S3C24XX_VA_ISA_BYTE,
+	.pfn		= __phys_to_pfn(0x0),
+	.length		= SZ_4M,
+	.type		= MT_DEVICE,
+  }, {
+	.virtual	= (u32)S3C24XX_VA_ISA_WORD,
+	.pfn		= __phys_to_pfn(0x0),
+	.length 	= SZ_4M,
+	.type		= MT_DEVICE,
+  },
+
+  /* we could possibly compress the next set down into a set of smaller tables
+   * pagetables, but that would mean using an L2 section, and it still means
+   * we cannot actually feed the same register to an LDR due to 16K spacing
+   */
+
+  /* CPLD control registers */
+
+  {
+	.virtual	= (u32)ANUBIS_VA_CTRL1,
+	.pfn		= __phys_to_pfn(ANUBIS_PA_CTRL1),
+	.length		= SZ_4K,
+	.type		= MT_DEVICE,
+  }, {
+	.virtual	= (u32)ANUBIS_VA_IDREG,
+	.pfn		= __phys_to_pfn(ANUBIS_PA_IDREG),
+	.length		= SZ_4K,
+	.type		= MT_DEVICE,
+  },
+};
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg anubis_uartcfgs[] __initdata = {
+	[0] = {
+		.hwport	     = 0,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+		.clk_sel	= S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
+	},
+	[1] = {
+		.hwport	     = 2,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+		.clk_sel	= S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
+	},
+};
+
+/* NAND Flash on Anubis board */
+
+static int external_map[]   = { 2 };
+static int chip0_map[]      = { 0 };
+static int chip1_map[]      = { 1 };
+
+static struct mtd_partition __initdata anubis_default_nand_part[] = {
+	[0] = {
+		.name	= "Boot Agent",
+		.size	= SZ_16K,
+		.offset	= 0,
+	},
+	[1] = {
+		.name	= "/boot",
+		.size	= SZ_4M - SZ_16K,
+		.offset	= SZ_16K,
+	},
+	[2] = {
+		.name	= "user1",
+		.offset	= SZ_4M,
+		.size	= SZ_32M - SZ_4M,
+	},
+	[3] = {
+		.name	= "user2",
+		.offset	= SZ_32M,
+		.size	= MTDPART_SIZ_FULL,
+	}
+};
+
+static struct mtd_partition __initdata anubis_default_nand_part_large[] = {
+	[0] = {
+		.name	= "Boot Agent",
+		.size	= SZ_128K,
+		.offset	= 0,
+	},
+	[1] = {
+		.name	= "/boot",
+		.size	= SZ_4M - SZ_128K,
+		.offset	= SZ_128K,
+	},
+	[2] = {
+		.name	= "user1",
+		.offset	= SZ_4M,
+		.size	= SZ_32M - SZ_4M,
+	},
+	[3] = {
+		.name	= "user2",
+		.offset	= SZ_32M,
+		.size	= MTDPART_SIZ_FULL,
+	}
+};
+
+/* the Anubis has 3 selectable slots for nand-flash, the two
+ * on-board chip areas, as well as the external slot.
+ *
+ * Note, there is no current hot-plug support for the External
+ * socket.
+*/
+
+static struct s3c2410_nand_set __initdata anubis_nand_sets[] = {
+	[1] = {
+		.name		= "External",
+		.nr_chips	= 1,
+		.nr_map		= external_map,
+		.nr_partitions	= ARRAY_SIZE(anubis_default_nand_part),
+		.partitions	= anubis_default_nand_part,
+	},
+	[0] = {
+		.name		= "chip0",
+		.nr_chips	= 1,
+		.nr_map		= chip0_map,
+		.nr_partitions	= ARRAY_SIZE(anubis_default_nand_part),
+		.partitions	= anubis_default_nand_part,
+	},
+	[2] = {
+		.name		= "chip1",
+		.nr_chips	= 1,
+		.nr_map		= chip1_map,
+		.nr_partitions	= ARRAY_SIZE(anubis_default_nand_part),
+		.partitions	= anubis_default_nand_part,
+	},
+};
+
+static void anubis_nand_select(struct s3c2410_nand_set *set, int slot)
+{
+	unsigned int tmp;
+
+	slot = set->nr_map[slot] & 3;
+
+	pr_debug("anubis_nand: selecting slot %d (set %p,%p)\n",
+		 slot, set, set->nr_map);
+
+	tmp = __raw_readb(ANUBIS_VA_CTRL1);
+	tmp &= ~ANUBIS_CTRL1_NANDSEL;
+	tmp |= slot;
+
+	pr_debug("anubis_nand: ctrl1 now %02x\n", tmp);
+
+	__raw_writeb(tmp, ANUBIS_VA_CTRL1);
+}
+
+static struct s3c2410_platform_nand __initdata anubis_nand_info = {
+	.tacls		= 25,
+	.twrph0		= 55,
+	.twrph1		= 40,
+	.nr_sets	= ARRAY_SIZE(anubis_nand_sets),
+	.sets		= anubis_nand_sets,
+	.select_chip	= anubis_nand_select,
+};
+
+/* IDE channels */
+
+static struct pata_platform_info anubis_ide_platdata = {
+	.ioport_shift	= 5,
+};
+
+static struct resource anubis_ide0_resource[] = {
+	{
+		.start	= S3C2410_CS3,
+		.end	= S3C2410_CS3 + (8*32) - 1,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= S3C2410_CS3 + (1<<26) + (6*32),
+		.end	= S3C2410_CS3 + (1<<26) + (7*32) - 1,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_IDE0,
+		.end	= IRQ_IDE0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device anubis_device_ide0 = {
+	.name		= "pata_platform",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(anubis_ide0_resource),
+	.resource	= anubis_ide0_resource,
+	.dev	= {
+		.platform_data = &anubis_ide_platdata,
+		.coherent_dma_mask = ~0,
+	},
+};
+
+static struct resource anubis_ide1_resource[] = {
+	{
+		.start	= S3C2410_CS4,
+		.end	= S3C2410_CS4 + (8*32) - 1,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= S3C2410_CS4 + (1<<26) + (6*32),
+		.end	= S3C2410_CS4 + (1<<26) + (7*32) - 1,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_IDE0,
+		.end	= IRQ_IDE0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device anubis_device_ide1 = {
+	.name		= "pata_platform",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(anubis_ide1_resource),
+	.resource	= anubis_ide1_resource,
+	.dev	= {
+		.platform_data = &anubis_ide_platdata,
+		.coherent_dma_mask = ~0,
+	},
+};
+
+/* Asix AX88796 10/100 ethernet controller */
+
+static struct ax_plat_data anubis_asix_platdata = {
+	.flags		= AXFLG_MAC_FROMDEV,
+	.wordlength	= 2,
+	.dcr_val	= 0x48,
+	.rcr_val	= 0x40,
+};
+
+static struct resource anubis_asix_resource[] = {
+	[0] = {
+		.start = S3C2410_CS5,
+		.end   = S3C2410_CS5 + (0x20 * 0x20) -1,
+		.flags = IORESOURCE_MEM
+	},
+	[1] = {
+		.start = IRQ_ASIX,
+		.end   = IRQ_ASIX,
+		.flags = IORESOURCE_IRQ
+	}
+};
+
+static struct platform_device anubis_device_asix = {
+	.name		= "ax88796",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(anubis_asix_resource),
+	.resource	= anubis_asix_resource,
+	.dev		= {
+		.platform_data = &anubis_asix_platdata,
+	}
+};
+
+/* SM501 */
+
+static struct resource anubis_sm501_resource[] = {
+	[0] = {
+		.start	= S3C2410_CS2,
+		.end	= S3C2410_CS2 + SZ_8M,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= S3C2410_CS2 + SZ_64M - SZ_2M,
+		.end	= S3C2410_CS2 + SZ_64M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[2] = {
+		.start	= IRQ_EINT0,
+		.end	= IRQ_EINT0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct sm501_initdata anubis_sm501_initdata = {
+	.gpio_high	= {
+		.set	= 0x3F000000,		/* 24bit panel */
+		.mask	= 0x0,
+	},
+	.misc_timing	= {
+		.set	= 0x010100,		/* SDRAM timing */
+		.mask	= 0x1F1F00,
+	},
+	.misc_control	= {
+		.set	= SM501_MISC_PNL_24BIT,
+		.mask	= 0,
+	},
+
+	.devices	= SM501_USE_GPIO,
+
+	/* set the SDRAM and bus clocks */
+	.mclk		= 72 * MHZ,
+	.m1xclk		= 144 * MHZ,
+};
+
+static struct sm501_platdata_gpio_i2c anubis_sm501_gpio_i2c[] = {
+	[0] = {
+		.bus_num	= 1,
+		.pin_scl	= 44,
+		.pin_sda	= 45,
+	},
+	[1] = {
+		.bus_num	= 2,
+		.pin_scl	= 40,
+		.pin_sda	= 41,
+	},
+};
+
+static struct sm501_platdata anubis_sm501_platdata = {
+	.init		= &anubis_sm501_initdata,
+	.gpio_base	= -1,
+	.gpio_i2c	= anubis_sm501_gpio_i2c,
+	.gpio_i2c_nr	= ARRAY_SIZE(anubis_sm501_gpio_i2c),
+};
+
+static struct platform_device anubis_device_sm501 = {
+	.name		= "sm501",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(anubis_sm501_resource),
+	.resource	= anubis_sm501_resource,
+	.dev		= {
+		.platform_data = &anubis_sm501_platdata,
+	},
+};
+
+/* Standard Anubis devices */
+
+static struct platform_device *anubis_devices[] __initdata = {
+	&s3c_device_ohci,
+	&s3c_device_wdt,
+	&s3c_device_adc,
+	&s3c_device_i2c0,
+ 	&s3c_device_rtc,
+	&s3c_device_nand,
+	&anubis_device_ide0,
+	&anubis_device_ide1,
+	&anubis_device_asix,
+	&anubis_device_sm501,
+};
+
+static struct clk *anubis_clocks[] __initdata = {
+	&s3c24xx_dclk0,
+	&s3c24xx_dclk1,
+	&s3c24xx_clkout0,
+	&s3c24xx_clkout1,
+	&s3c24xx_uclk,
+};
+
+/* I2C devices. */
+
+static struct i2c_board_info anubis_i2c_devs[] __initdata = {
+	{
+		I2C_BOARD_INFO("tps65011", 0x48),
+		.irq	= IRQ_EINT20,
+	}
+};
+
+/* Audio setup */
+static struct s3c24xx_audio_simtec_pdata __initdata anubis_audio = {
+	.have_mic	= 1,
+	.have_lout	= 1,
+	.output_cdclk	= 1,
+	.use_mpllin	= 1,
+	.amp_gpio	= S3C2410_GPB(2),
+	.amp_gain[0]	= S3C2410_GPD(10),
+	.amp_gain[1]	= S3C2410_GPD(11),
+};
+
+static void __init anubis_map_io(void)
+{
+	/* initialise the clocks */
+
+	s3c24xx_dclk0.parent = &clk_upll;
+	s3c24xx_dclk0.rate   = 12*1000*1000;
+
+	s3c24xx_dclk1.parent = &clk_upll;
+	s3c24xx_dclk1.rate   = 24*1000*1000;
+
+	s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
+	s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
+
+	s3c24xx_uclk.parent  = &s3c24xx_clkout1;
+
+	s3c24xx_register_clocks(anubis_clocks, ARRAY_SIZE(anubis_clocks));
+
+	s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc));
+	s3c24xx_init_clocks(0);
+	s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs));
+
+	/* check for the newer revision boards with large page nand */
+
+	if ((__raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK) >= 4) {
+		printk(KERN_INFO "ANUBIS-B detected (revision %d)\n",
+		       __raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK);
+		anubis_nand_sets[0].partitions = anubis_default_nand_part_large;
+		anubis_nand_sets[0].nr_partitions = ARRAY_SIZE(anubis_default_nand_part_large);
+	} else {
+		/* ensure that the GPIO is setup */
+		s3c2410_gpio_setpin(S3C2410_GPA(0), 1);
+	}
+}
+
+static void __init anubis_init(void)
+{
+	s3c_i2c0_set_platdata(NULL);
+	s3c_nand_set_platdata(&anubis_nand_info);
+	simtec_audio_add(NULL, false, &anubis_audio);
+
+	platform_add_devices(anubis_devices, ARRAY_SIZE(anubis_devices));
+
+	i2c_register_board_info(0, anubis_i2c_devs,
+				ARRAY_SIZE(anubis_i2c_devs));
+}
+
+
+MACHINE_START(ANUBIS, "Simtec-Anubis")
+	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
+	.atag_offset	= 0x100,
+	.map_io		= anubis_map_io,
+	.init_machine	= anubis_init,
+	.init_irq	= s3c24xx_init_irq,
+	.timer		= &s3c24xx_timer,
+	.restart	= s3c244x_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c
similarity index 100%
rename from arch/arm/mach-s3c2440/mach-at2440evb.c
rename to arch/arm/mach-s3c24xx/mach-at2440evb.c
diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c
new file mode 100644
index 0000000..53219c0
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/mach-bast.c
@@ -0,0 +1,644 @@
+/* linux/arch/arm/mach-s3c2410/mach-bast.c
+ *
+ * Copyright 2003-2008 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.simtec.co.uk/products/EB2410ITX/
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/syscore_ops.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/dm9000.h>
+#include <linux/ata_platform.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+
+#include <net/ax88796.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/bast-map.h>
+#include <mach/bast-irq.h>
+#include <mach/bast-cpld.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+//#include <asm/debug-ll.h>
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-mem.h>
+#include <mach/regs-lcd.h>
+
+#include <plat/hwmon.h>
+#include <plat/nand.h>
+#include <plat/iic.h>
+#include <mach/fb.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/serial_8250.h>
+
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/cpu-freq.h>
+#include <plat/gpio-cfg.h>
+#include <plat/audio-simtec.h>
+
+#include "simtec.h"
+#include "common.h"
+
+#define COPYRIGHT ", Copyright 2004-2008 Simtec Electronics"
+
+/* macros for virtual address mods for the io space entries */
+#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5)
+#define VA_C4(item) ((unsigned long)(item) + BAST_VAM_CS4)
+#define VA_C3(item) ((unsigned long)(item) + BAST_VAM_CS3)
+#define VA_C2(item) ((unsigned long)(item) + BAST_VAM_CS2)
+
+/* macros to modify the physical addresses for io space */
+
+#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2))
+#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3))
+#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4))
+#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5))
+
+static struct map_desc bast_iodesc[] __initdata = {
+  /* ISA IO areas */
+  {
+	  .virtual	= (u32)S3C24XX_VA_ISA_BYTE,
+	  .pfn		= PA_CS2(BAST_PA_ISAIO),
+	  .length	= SZ_16M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)S3C24XX_VA_ISA_WORD,
+	  .pfn		= PA_CS3(BAST_PA_ISAIO),
+	  .length	= SZ_16M,
+	  .type		= MT_DEVICE,
+  },
+  /* bast CPLD control registers, and external interrupt controls */
+  {
+	  .virtual	= (u32)BAST_VA_CTRL1,
+	  .pfn		= __phys_to_pfn(BAST_PA_CTRL1),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)BAST_VA_CTRL2,
+	  .pfn		= __phys_to_pfn(BAST_PA_CTRL2),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)BAST_VA_CTRL3,
+	  .pfn		= __phys_to_pfn(BAST_PA_CTRL3),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)BAST_VA_CTRL4,
+	  .pfn		= __phys_to_pfn(BAST_PA_CTRL4),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  },
+  /* PC104 IRQ mux */
+  {
+	  .virtual	= (u32)BAST_VA_PC104_IRQREQ,
+	  .pfn		= __phys_to_pfn(BAST_PA_PC104_IRQREQ),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)BAST_VA_PC104_IRQRAW,
+	  .pfn		= __phys_to_pfn(BAST_PA_PC104_IRQRAW),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)BAST_VA_PC104_IRQMASK,
+	  .pfn		= __phys_to_pfn(BAST_PA_PC104_IRQMASK),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  },
+
+  /* peripheral space... one for each of fast/slow/byte/16bit */
+  /* note, ide is only decoded in word space, even though some registers
+   * are only 8bit */
+
+  /* slow, byte */
+  { VA_C2(BAST_VA_ISAIO),   PA_CS2(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
+  { VA_C2(BAST_VA_ISAMEM),  PA_CS2(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
+  { VA_C2(BAST_VA_SUPERIO), PA_CS2(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
+
+  /* slow, word */
+  { VA_C3(BAST_VA_ISAIO),   PA_CS3(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
+  { VA_C3(BAST_VA_ISAMEM),  PA_CS3(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
+  { VA_C3(BAST_VA_SUPERIO), PA_CS3(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
+
+  /* fast, byte */
+  { VA_C4(BAST_VA_ISAIO),   PA_CS4(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
+  { VA_C4(BAST_VA_ISAMEM),  PA_CS4(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
+  { VA_C4(BAST_VA_SUPERIO), PA_CS4(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
+
+  /* fast, word */
+  { VA_C5(BAST_VA_ISAIO),   PA_CS5(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
+  { VA_C5(BAST_VA_ISAMEM),  PA_CS5(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
+  { VA_C5(BAST_VA_SUPERIO), PA_CS5(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
+};
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg bast_uartcfgs[] __initdata = {
+	[0] = {
+		.hwport	     = 0,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+	},
+	[1] = {
+		.hwport	     = 1,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+	},
+	/* port 2 is not actually used */
+	[2] = {
+		.hwport	     = 2,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+	}
+};
+
+/* NAND Flash on BAST board */
+
+#ifdef CONFIG_PM
+static int bast_pm_suspend(void)
+{
+	/* ensure that an nRESET is not generated on resume. */
+	gpio_direction_output(S3C2410_GPA(21), 1);
+	return 0;
+}
+
+static void bast_pm_resume(void)
+{
+	s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
+}
+
+#else
+#define bast_pm_suspend NULL
+#define bast_pm_resume NULL
+#endif
+
+static struct syscore_ops bast_pm_syscore_ops = {
+	.suspend	= bast_pm_suspend,
+	.resume		= bast_pm_resume,
+};
+
+static int smartmedia_map[] = { 0 };
+static int chip0_map[] = { 1 };
+static int chip1_map[] = { 2 };
+static int chip2_map[] = { 3 };
+
+static struct mtd_partition __initdata bast_default_nand_part[] = {
+	[0] = {
+		.name	= "Boot Agent",
+		.size	= SZ_16K,
+		.offset	= 0,
+	},
+	[1] = {
+		.name	= "/boot",
+		.size	= SZ_4M - SZ_16K,
+		.offset	= SZ_16K,
+	},
+	[2] = {
+		.name	= "user",
+		.offset	= SZ_4M,
+		.size	= MTDPART_SIZ_FULL,
+	}
+};
+
+/* the bast has 4 selectable slots for nand-flash, the three
+ * on-board chip areas, as well as the external SmartMedia
+ * slot.
+ *
+ * Note, there is no current hot-plug support for the SmartMedia
+ * socket.
+*/
+
+static struct s3c2410_nand_set __initdata bast_nand_sets[] = {
+	[0] = {
+		.name		= "SmartMedia",
+		.nr_chips	= 1,
+		.nr_map		= smartmedia_map,
+		.options        = NAND_SCAN_SILENT_NODEV,
+		.nr_partitions	= ARRAY_SIZE(bast_default_nand_part),
+		.partitions	= bast_default_nand_part,
+	},
+	[1] = {
+		.name		= "chip0",
+		.nr_chips	= 1,
+		.nr_map		= chip0_map,
+		.nr_partitions	= ARRAY_SIZE(bast_default_nand_part),
+		.partitions	= bast_default_nand_part,
+	},
+	[2] = {
+		.name		= "chip1",
+		.nr_chips	= 1,
+		.nr_map		= chip1_map,
+		.options        = NAND_SCAN_SILENT_NODEV,
+		.nr_partitions	= ARRAY_SIZE(bast_default_nand_part),
+		.partitions	= bast_default_nand_part,
+	},
+	[3] = {
+		.name		= "chip2",
+		.nr_chips	= 1,
+		.nr_map		= chip2_map,
+		.options        = NAND_SCAN_SILENT_NODEV,
+		.nr_partitions	= ARRAY_SIZE(bast_default_nand_part),
+		.partitions	= bast_default_nand_part,
+	}
+};
+
+static void bast_nand_select(struct s3c2410_nand_set *set, int slot)
+{
+	unsigned int tmp;
+
+	slot = set->nr_map[slot] & 3;
+
+	pr_debug("bast_nand: selecting slot %d (set %p,%p)\n",
+		 slot, set, set->nr_map);
+
+	tmp = __raw_readb(BAST_VA_CTRL2);
+	tmp &= BAST_CPLD_CTLR2_IDERST;
+	tmp |= slot;
+	tmp |= BAST_CPLD_CTRL2_WNAND;
+
+	pr_debug("bast_nand: ctrl2 now %02x\n", tmp);
+
+	__raw_writeb(tmp, BAST_VA_CTRL2);
+}
+
+static struct s3c2410_platform_nand __initdata bast_nand_info = {
+	.tacls		= 30,
+	.twrph0		= 60,
+	.twrph1		= 60,
+	.nr_sets	= ARRAY_SIZE(bast_nand_sets),
+	.sets		= bast_nand_sets,
+	.select_chip	= bast_nand_select,
+};
+
+/* DM9000 */
+
+static struct resource bast_dm9k_resource[] = {
+	[0] = {
+		.start = S3C2410_CS5 + BAST_PA_DM9000,
+		.end   = S3C2410_CS5 + BAST_PA_DM9000 + 3,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = S3C2410_CS5 + BAST_PA_DM9000 + 0x40,
+		.end   = S3C2410_CS5 + BAST_PA_DM9000 + 0x40 + 0x3f,
+		.flags = IORESOURCE_MEM,
+	},
+	[2] = {
+		.start = IRQ_DM9000,
+		.end   = IRQ_DM9000,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	}
+
+};
+
+/* for the moment we limit ourselves to 16bit IO until some
+ * better IO routines can be written and tested
+*/
+
+static struct dm9000_plat_data bast_dm9k_platdata = {
+	.flags		= DM9000_PLATF_16BITONLY,
+};
+
+static struct platform_device bast_device_dm9k = {
+	.name		= "dm9000",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(bast_dm9k_resource),
+	.resource	= bast_dm9k_resource,
+	.dev		= {
+		.platform_data = &bast_dm9k_platdata,
+	}
+};
+
+/* serial devices */
+
+#define SERIAL_BASE  (S3C2410_CS2 + BAST_PA_SUPERIO)
+#define SERIAL_FLAGS (UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SHARE_IRQ)
+#define SERIAL_CLK   (1843200)
+
+static struct plat_serial8250_port bast_sio_data[] = {
+	[0] = {
+		.mapbase	= SERIAL_BASE + 0x2f8,
+		.irq		= IRQ_PCSERIAL1,
+		.flags		= SERIAL_FLAGS,
+		.iotype		= UPIO_MEM,
+		.regshift	= 0,
+		.uartclk	= SERIAL_CLK,
+	},
+	[1] = {
+		.mapbase	= SERIAL_BASE + 0x3f8,
+		.irq		= IRQ_PCSERIAL2,
+		.flags		= SERIAL_FLAGS,
+		.iotype		= UPIO_MEM,
+		.regshift	= 0,
+		.uartclk	= SERIAL_CLK,
+	},
+	{ }
+};
+
+static struct platform_device bast_sio = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev			= {
+		.platform_data	= &bast_sio_data,
+	},
+};
+
+/* we have devices on the bus which cannot work much over the
+ * standard 100KHz i2c bus frequency
+*/
+
+static struct s3c2410_platform_i2c __initdata bast_i2c_info = {
+	.flags		= 0,
+	.slave_addr	= 0x10,
+	.frequency	= 100*1000,
+};
+
+/* Asix AX88796 10/100 ethernet controller */
+
+static struct ax_plat_data bast_asix_platdata = {
+	.flags		= AXFLG_MAC_FROMDEV,
+	.wordlength	= 2,
+	.dcr_val	= 0x48,
+	.rcr_val	= 0x40,
+};
+
+static struct resource bast_asix_resource[] = {
+	[0] = {
+		.start = S3C2410_CS5 + BAST_PA_ASIXNET,
+		.end   = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20) - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20),
+		.end   = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20),
+		.flags = IORESOURCE_MEM,
+	},
+	[2] = {
+		.start = IRQ_ASIX,
+		.end   = IRQ_ASIX,
+		.flags = IORESOURCE_IRQ
+	}
+};
+
+static struct platform_device bast_device_asix = {
+	.name		= "ax88796",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(bast_asix_resource),
+	.resource	= bast_asix_resource,
+	.dev		= {
+		.platform_data = &bast_asix_platdata
+	}
+};
+
+/* Asix AX88796 10/100 ethernet controller parallel port */
+
+static struct resource bast_asixpp_resource[] = {
+	[0] = {
+		.start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20),
+		.end   = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1b * 0x20) - 1,
+		.flags = IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device bast_device_axpp = {
+	.name		= "ax88796-pp",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(bast_asixpp_resource),
+	.resource	= bast_asixpp_resource,
+};
+
+/* LCD/VGA controller */
+
+static struct s3c2410fb_display __initdata bast_lcd_info[] = {
+	{
+		.type		= S3C2410_LCDCON1_TFT,
+		.width		= 640,
+		.height		= 480,
+
+		.pixclock	= 33333,
+		.xres		= 640,
+		.yres		= 480,
+		.bpp		= 4,
+		.left_margin	= 40,
+		.right_margin	= 20,
+		.hsync_len	= 88,
+		.upper_margin	= 30,
+		.lower_margin	= 32,
+		.vsync_len	= 3,
+
+		.lcdcon5	= 0x00014b02,
+	},
+	{
+		.type		= S3C2410_LCDCON1_TFT,
+		.width		= 640,
+		.height		= 480,
+
+		.pixclock	= 33333,
+		.xres		= 640,
+		.yres		= 480,
+		.bpp		= 8,
+		.left_margin	= 40,
+		.right_margin	= 20,
+		.hsync_len	= 88,
+		.upper_margin	= 30,
+		.lower_margin	= 32,
+		.vsync_len	= 3,
+
+		.lcdcon5	= 0x00014b02,
+	},
+	{
+		.type		= S3C2410_LCDCON1_TFT,
+		.width		= 640,
+		.height		= 480,
+
+		.pixclock	= 33333,
+		.xres		= 640,
+		.yres		= 480,
+		.bpp		= 16,
+		.left_margin	= 40,
+		.right_margin	= 20,
+		.hsync_len	= 88,
+		.upper_margin	= 30,
+		.lower_margin	= 32,
+		.vsync_len	= 3,
+
+		.lcdcon5	= 0x00014b02,
+	},
+};
+
+/* LCD/VGA controller */
+
+static struct s3c2410fb_mach_info __initdata bast_fb_info = {
+
+	.displays = bast_lcd_info,
+	.num_displays = ARRAY_SIZE(bast_lcd_info),
+	.default_display = 1,
+};
+
+/* I2C devices fitted. */
+
+static struct i2c_board_info bast_i2c_devs[] __initdata = {
+	{
+		I2C_BOARD_INFO("tlv320aic23", 0x1a),
+	}, {
+		I2C_BOARD_INFO("simtec-pmu", 0x6b),
+	}, {
+		I2C_BOARD_INFO("ch7013", 0x75),
+	},
+};
+
+static struct s3c_hwmon_pdata bast_hwmon_info = {
+	/* LCD contrast (0-6.6V) */
+	.in[0] = &(struct s3c_hwmon_chcfg) {
+		.name		= "lcd-contrast",
+		.mult		= 3300,
+		.div		= 512,
+	},
+	/* LED current feedback */
+	.in[1] = &(struct s3c_hwmon_chcfg) {
+		.name		= "led-feedback",
+		.mult		= 3300,
+		.div		= 1024,
+	},
+	/* LCD feedback (0-6.6V) */
+	.in[2] = &(struct s3c_hwmon_chcfg) {
+		.name		= "lcd-feedback",
+		.mult		= 3300,
+		.div		= 512,
+	},
+	/* Vcore (1.8-2.0V), Vref 3.3V  */
+	.in[3] = &(struct s3c_hwmon_chcfg) {
+		.name		= "vcore",
+		.mult		= 3300,
+		.div		= 1024,
+	},
+};
+
+/* Standard BAST devices */
+// cat /sys/devices/platform/s3c24xx-adc/s3c-hwmon/in_0
+
+static struct platform_device *bast_devices[] __initdata = {
+	&s3c_device_ohci,
+	&s3c_device_lcd,
+	&s3c_device_wdt,
+	&s3c_device_i2c0,
+ 	&s3c_device_rtc,
+	&s3c_device_nand,
+	&s3c_device_adc,
+	&s3c_device_hwmon,
+	&bast_device_dm9k,
+	&bast_device_asix,
+	&bast_device_axpp,
+	&bast_sio,
+};
+
+static struct clk *bast_clocks[] __initdata = {
+	&s3c24xx_dclk0,
+	&s3c24xx_dclk1,
+	&s3c24xx_clkout0,
+	&s3c24xx_clkout1,
+	&s3c24xx_uclk,
+};
+
+static struct s3c_cpufreq_board __initdata bast_cpufreq = {
+	.refresh	= 7800, /* 7.8usec */
+	.auto_io	= 1,
+	.need_io	= 1,
+};
+
+static struct s3c24xx_audio_simtec_pdata __initdata bast_audio = {
+	.have_mic	= 1,
+	.have_lout	= 1,
+};
+
+static void __init bast_map_io(void)
+{
+	/* initialise the clocks */
+
+	s3c24xx_dclk0.parent = &clk_upll;
+	s3c24xx_dclk0.rate   = 12*1000*1000;
+
+	s3c24xx_dclk1.parent = &clk_upll;
+	s3c24xx_dclk1.rate   = 24*1000*1000;
+
+	s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
+	s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
+
+	s3c24xx_uclk.parent  = &s3c24xx_clkout1;
+
+	s3c24xx_register_clocks(bast_clocks, ARRAY_SIZE(bast_clocks));
+
+	s3c_hwmon_set_platdata(&bast_hwmon_info);
+
+	s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc));
+	s3c24xx_init_clocks(0);
+	s3c24xx_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs));
+}
+
+static void __init bast_init(void)
+{
+	register_syscore_ops(&bast_pm_syscore_ops);
+
+	s3c_i2c0_set_platdata(&bast_i2c_info);
+	s3c_nand_set_platdata(&bast_nand_info);
+	s3c24xx_fb_set_platdata(&bast_fb_info);
+	platform_add_devices(bast_devices, ARRAY_SIZE(bast_devices));
+
+	i2c_register_board_info(0, bast_i2c_devs,
+				ARRAY_SIZE(bast_i2c_devs));
+
+	usb_simtec_init();
+	nor_simtec_init();
+	simtec_audio_add(NULL, true, &bast_audio);
+
+	WARN_ON(gpio_request(S3C2410_GPA(21), "bast nreset"));
+	
+	s3c_cpufreq_setboard(&bast_cpufreq);
+}
+
+MACHINE_START(BAST, "Simtec-BAST")
+	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
+	.atag_offset	= 0x100,
+	.map_io		= bast_map_io,
+	.init_irq	= s3c24xx_init_irq,
+	.init_machine	= bast_init,
+	.timer		= &s3c24xx_timer,
+	.restart	= s3c2410_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c
new file mode 100644
index 0000000..ba5d853
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/mach-gta02.c
@@ -0,0 +1,605 @@
+/*
+ * linux/arch/arm/mach-s3c2442/mach-gta02.c
+ *
+ * S3C2442 Machine Support for Openmoko GTA02 / FreeRunner.
+ *
+ * Copyright (C) 2006-2009 by Openmoko, Inc.
+ * Authors: Harald Welte <laforge@openmoko.org>
+ *          Andy Green <andy@openmoko.org>
+ *          Werner Almesberger <werner@openmoko.org>
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/s3c24xx.h>
+
+#include <linux/mmc/host.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/io.h>
+
+#include <linux/i2c.h>
+#include <linux/regulator/machine.h>
+
+#include <linux/mfd/pcf50633/core.h>
+#include <linux/mfd/pcf50633/mbc.h>
+#include <linux/mfd/pcf50633/adc.h>
+#include <linux/mfd/pcf50633/gpio.h>
+#include <linux/mfd/pcf50633/pmic.h>
+#include <linux/mfd/pcf50633/backlight.h>
+
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <mach/regs-irq.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-gpioj.h>
+#include <mach/fb.h>
+
+#include <plat/usb-control.h>
+#include <mach/regs-mem.h>
+#include <mach/hardware.h>
+
+#include <mach/gta02.h>
+
+#include <plat/regs-serial.h>
+#include <plat/nand.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/udc.h>
+#include <plat/gpio-cfg.h>
+#include <plat/iic.h>
+#include <plat/ts.h>
+
+#include "common.h"
+
+static struct pcf50633 *gta02_pcf;
+
+/*
+ * This gets called frequently when we paniced.
+ */
+
+static long gta02_panic_blink(int state)
+{
+	long delay = 0;
+	char led;
+
+	led = (state) ? 1 : 0;
+	gpio_direction_output(GTA02_GPIO_AUX_LED, led);
+
+	return delay;
+}
+
+
+static struct map_desc gta02_iodesc[] __initdata = {
+	{
+		.virtual	= 0xe0000000,
+		.pfn		= __phys_to_pfn(S3C2410_CS3 + 0x01000000),
+		.length		= SZ_1M,
+		.type		= MT_DEVICE
+	},
+};
+
+#define UCON (S3C2410_UCON_DEFAULT | S3C2443_UCON_RXERR_IRQEN)
+#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
+#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
+
+static struct s3c2410_uartcfg gta02_uartcfgs[] = {
+	[0] = {
+		.hwport		= 0,
+		.flags		= 0,
+		.ucon		= UCON,
+		.ulcon		= ULCON,
+		.ufcon		= UFCON,
+	},
+	[1] = {
+		.hwport		= 1,
+		.flags		= 0,
+		.ucon		= UCON,
+		.ulcon		= ULCON,
+		.ufcon		= UFCON,
+	},
+	[2] = {
+		.hwport		= 2,
+		.flags		= 0,
+		.ucon		= UCON,
+		.ulcon		= ULCON,
+		.ufcon		= UFCON,
+	},
+};
+
+#ifdef CONFIG_CHARGER_PCF50633
+/*
+ * On GTA02 the 1A charger features a 48K resistor to 0V on the ID pin.
+ * We use this to recognize that we can pull 1A from the USB socket.
+ *
+ * These constants are the measured pcf50633 ADC levels with the 1A
+ * charger / 48K resistor, and with no pulldown resistor.
+ */
+
+#define ADC_NOM_CHG_DETECT_1A 6
+#define ADC_NOM_CHG_DETECT_USB 43
+
+static void
+gta02_configure_pmu_for_charger(struct pcf50633 *pcf, void *unused, int res)
+{
+	int  ma;
+
+	/* Interpret charger type */
+	if (res < ((ADC_NOM_CHG_DETECT_USB + ADC_NOM_CHG_DETECT_1A) / 2)) {
+
+		/*
+		 * Sanity - stop GPO driving out now that we have a 1A charger
+		 * GPO controls USB Host power generation on GTA02
+		 */
+		pcf50633_gpio_set(pcf, PCF50633_GPO, 0);
+
+		ma = 1000;
+	} else
+		ma = 100;
+
+	pcf50633_mbc_usb_curlim_set(pcf, ma);
+}
+
+static struct delayed_work gta02_charger_work;
+static int gta02_usb_vbus_draw;
+
+static void gta02_charger_worker(struct work_struct *work)
+{
+	if (gta02_usb_vbus_draw) {
+		pcf50633_mbc_usb_curlim_set(gta02_pcf, gta02_usb_vbus_draw);
+		return;
+	}
+
+#ifdef CONFIG_PCF50633_ADC
+	pcf50633_adc_async_read(gta02_pcf,
+				PCF50633_ADCC1_MUX_ADCIN1,
+				PCF50633_ADCC1_AVERAGE_16,
+				gta02_configure_pmu_for_charger,
+				NULL);
+#else
+	/*
+	 * If the PCF50633 ADC is disabled we fallback to a
+	 * 100mA limit for safety.
+	 */
+	pcf50633_mbc_usb_curlim_set(pcf, 100);
+#endif
+}
+
+#define GTA02_CHARGER_CONFIGURE_TIMEOUT ((3000 * HZ) / 1000)
+
+static void gta02_pmu_event_callback(struct pcf50633 *pcf, int irq)
+{
+	if (irq == PCF50633_IRQ_USBINS) {
+		schedule_delayed_work(&gta02_charger_work,
+				      GTA02_CHARGER_CONFIGURE_TIMEOUT);
+
+		return;
+	}
+
+	if (irq == PCF50633_IRQ_USBREM) {
+		cancel_delayed_work_sync(&gta02_charger_work);
+		gta02_usb_vbus_draw = 0;
+	}
+}
+
+static void gta02_udc_vbus_draw(unsigned int ma)
+{
+	if (!gta02_pcf)
+		return;
+
+	gta02_usb_vbus_draw = ma;
+
+	schedule_delayed_work(&gta02_charger_work,
+			      GTA02_CHARGER_CONFIGURE_TIMEOUT);
+}
+#else /* !CONFIG_CHARGER_PCF50633 */
+#define gta02_pmu_event_callback	NULL
+#define gta02_udc_vbus_draw		NULL
+#endif
+
+/*
+ * This is called when pc50633 is probed, unfortunately quite late in the
+ * day since it is an I2C bus device. Here we can belatedly define some
+ * platform devices with the advantage that we can mark the pcf50633 as the
+ * parent. This makes them get suspended and resumed with their parent
+ * the pcf50633 still around.
+ */
+
+static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf);
+
+
+static char *gta02_batteries[] = {
+	"battery",
+};
+
+static struct pcf50633_bl_platform_data gta02_backlight_data = {
+	.default_brightness = 0x3f,
+	.default_brightness_limit = 0,
+	.ramp_time = 5,
+};
+
+static struct pcf50633_platform_data gta02_pcf_pdata = {
+	.resumers = {
+		[0] =	PCF50633_INT1_USBINS |
+			PCF50633_INT1_USBREM |
+			PCF50633_INT1_ALARM,
+		[1] =	PCF50633_INT2_ONKEYF,
+		[2] =	PCF50633_INT3_ONKEY1S,
+		[3] =	PCF50633_INT4_LOWSYS |
+			PCF50633_INT4_LOWBAT |
+			PCF50633_INT4_HIGHTMP,
+	},
+
+	.batteries = gta02_batteries,
+	.num_batteries = ARRAY_SIZE(gta02_batteries),
+
+	.charger_reference_current_ma = 1000,
+
+	.backlight_data = &gta02_backlight_data,
+
+	.reg_init_data = {
+		[PCF50633_REGULATOR_AUTO] = {
+			.constraints = {
+				.min_uV = 3300000,
+				.max_uV = 3300000,
+				.valid_modes_mask = REGULATOR_MODE_NORMAL,
+				.always_on = 1,
+				.apply_uV = 1,
+			},
+		},
+		[PCF50633_REGULATOR_DOWN1] = {
+			.constraints = {
+				.min_uV = 1300000,
+				.max_uV = 1600000,
+				.valid_modes_mask = REGULATOR_MODE_NORMAL,
+				.always_on = 1,
+				.apply_uV = 1,
+			},
+		},
+		[PCF50633_REGULATOR_DOWN2] = {
+			.constraints = {
+				.min_uV = 1800000,
+				.max_uV = 1800000,
+				.valid_modes_mask = REGULATOR_MODE_NORMAL,
+				.apply_uV = 1,
+				.always_on = 1,
+			},
+		},
+		[PCF50633_REGULATOR_HCLDO] = {
+			.constraints = {
+				.min_uV = 2000000,
+				.max_uV = 3300000,
+				.valid_modes_mask = REGULATOR_MODE_NORMAL,
+				.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+						REGULATOR_CHANGE_STATUS,
+			},
+		},
+		[PCF50633_REGULATOR_LDO1] = {
+			.constraints = {
+				.min_uV = 3300000,
+				.max_uV = 3300000,
+				.valid_modes_mask = REGULATOR_MODE_NORMAL,
+				.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+				.apply_uV = 1,
+			},
+		},
+		[PCF50633_REGULATOR_LDO2] = {
+			.constraints = {
+				.min_uV = 3300000,
+				.max_uV = 3300000,
+				.valid_modes_mask = REGULATOR_MODE_NORMAL,
+				.apply_uV = 1,
+			},
+		},
+		[PCF50633_REGULATOR_LDO3] = {
+			.constraints = {
+				.min_uV = 3000000,
+				.max_uV = 3000000,
+				.valid_modes_mask = REGULATOR_MODE_NORMAL,
+				.apply_uV = 1,
+			},
+		},
+		[PCF50633_REGULATOR_LDO4] = {
+			.constraints = {
+				.min_uV = 3200000,
+				.max_uV = 3200000,
+				.valid_modes_mask = REGULATOR_MODE_NORMAL,
+				.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+				.apply_uV = 1,
+			},
+		},
+		[PCF50633_REGULATOR_LDO5] = {
+			.constraints = {
+				.min_uV = 3000000,
+				.max_uV = 3000000,
+				.valid_modes_mask = REGULATOR_MODE_NORMAL,
+				.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+				.apply_uV = 1,
+			},
+		},
+		[PCF50633_REGULATOR_LDO6] = {
+			.constraints = {
+				.min_uV = 3000000,
+				.max_uV = 3000000,
+				.valid_modes_mask = REGULATOR_MODE_NORMAL,
+			},
+		},
+		[PCF50633_REGULATOR_MEMLDO] = {
+			.constraints = {
+				.min_uV = 1800000,
+				.max_uV = 1800000,
+				.valid_modes_mask = REGULATOR_MODE_NORMAL,
+			},
+		},
+
+	},
+	.probe_done = gta02_pmu_attach_child_devices,
+	.mbc_event_callback = gta02_pmu_event_callback,
+};
+
+
+/* NOR Flash. */
+
+#define GTA02_FLASH_BASE	0x18000000 /* GCS3 */
+#define GTA02_FLASH_SIZE	0x200000 /* 2MBytes */
+
+static struct physmap_flash_data gta02_nor_flash_data = {
+	.width		= 2,
+};
+
+static struct resource gta02_nor_flash_resource = {
+	.start		= GTA02_FLASH_BASE,
+	.end		= GTA02_FLASH_BASE + GTA02_FLASH_SIZE - 1,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device gta02_nor_flash = {
+	.name		= "physmap-flash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &gta02_nor_flash_data,
+	},
+	.resource	= &gta02_nor_flash_resource,
+	.num_resources	= 1,
+};
+
+
+static struct platform_device s3c24xx_pwm_device = {
+	.name		= "s3c24xx_pwm",
+	.num_resources	= 0,
+};
+
+static struct platform_device gta02_dfbmcs320_device = {
+	.name = "dfbmcs320",
+};
+
+static struct i2c_board_info gta02_i2c_devs[] __initdata = {
+	{
+		I2C_BOARD_INFO("pcf50633", 0x73),
+		.irq = GTA02_IRQ_PCF50633,
+		.platform_data = &gta02_pcf_pdata,
+	},
+	{
+		I2C_BOARD_INFO("wm8753", 0x1a),
+	},
+};
+
+static struct s3c2410_nand_set __initdata gta02_nand_sets[] = {
+	[0] = {
+		/*
+		 * This name is also hard-coded in the boot loaders, so
+		 * changing it would would require all users to upgrade
+		 * their boot loaders, some of which are stored in a NOR
+		 * that is considered to be immutable.
+		 */
+		.name		= "neo1973-nand",
+		.nr_chips	= 1,
+		.flash_bbt	= 1,
+	},
+};
+
+/*
+ * Choose a set of timings derived from S3C@2442B MCP54
+ * data sheet (K5D2G13ACM-D075 MCP Memory).
+ */
+
+static struct s3c2410_platform_nand __initdata gta02_nand_info = {
+	.tacls		= 0,
+	.twrph0		= 25,
+	.twrph1		= 15,
+	.nr_sets	= ARRAY_SIZE(gta02_nand_sets),
+	.sets		= gta02_nand_sets,
+};
+
+
+/* Get PMU to set USB current limit accordingly. */
+static struct s3c2410_udc_mach_info gta02_udc_cfg __initdata = {
+	.vbus_draw	= gta02_udc_vbus_draw,
+	.pullup_pin = GTA02_GPIO_USB_PULLUP,
+};
+
+/* USB */
+static struct s3c2410_hcd_info gta02_usb_info __initdata = {
+	.port[0]	= {
+		.flags	= S3C_HCDFLG_USED,
+	},
+	.port[1]	= {
+		.flags	= 0,
+	},
+};
+
+/* Touchscreen */
+static struct s3c2410_ts_mach_info gta02_ts_info = {
+	.delay			= 10000,
+	.presc			= 0xff, /* slow as we can go */
+	.oversampling_shift	= 2,
+};
+
+/* Buttons */
+static struct gpio_keys_button gta02_buttons[] = {
+	{
+		.gpio = GTA02_GPIO_AUX_KEY,
+		.code = KEY_PHONE,
+		.desc = "Aux",
+		.type = EV_KEY,
+		.debounce_interval = 100,
+	},
+	{
+		.gpio = GTA02_GPIO_HOLD_KEY,
+		.code = KEY_PAUSE,
+		.desc = "Hold",
+		.type = EV_KEY,
+		.debounce_interval = 100,
+	},
+};
+
+static struct gpio_keys_platform_data gta02_buttons_pdata = {
+	.buttons = gta02_buttons,
+	.nbuttons = ARRAY_SIZE(gta02_buttons),
+};
+
+static struct platform_device gta02_buttons_device = {
+	.name = "gpio-keys",
+	.id = -1,
+	.dev = {
+		.platform_data = &gta02_buttons_pdata,
+	},
+};
+
+static void __init gta02_map_io(void)
+{
+	s3c24xx_init_io(gta02_iodesc, ARRAY_SIZE(gta02_iodesc));
+	s3c24xx_init_clocks(12000000);
+	s3c24xx_init_uarts(gta02_uartcfgs, ARRAY_SIZE(gta02_uartcfgs));
+}
+
+
+/* These are the guys that don't need to be children of PMU. */
+
+static struct platform_device *gta02_devices[] __initdata = {
+	&s3c_device_ohci,
+	&s3c_device_wdt,
+	&s3c_device_sdi,
+	&s3c_device_usbgadget,
+	&s3c_device_nand,
+	&gta02_nor_flash,
+	&s3c24xx_pwm_device,
+	&s3c_device_iis,
+	&samsung_asoc_dma,
+	&s3c_device_i2c0,
+	&gta02_dfbmcs320_device,
+	&gta02_buttons_device,
+	&s3c_device_adc,
+	&s3c_device_ts,
+};
+
+/* These guys DO need to be children of PMU. */
+
+static struct platform_device *gta02_devices_pmu_children[] = {
+};
+
+
+/*
+ * This is called when pc50633 is probed, quite late in the day since it is an
+ * I2C bus device.  Here we can define platform devices with the advantage that
+ * we can mark the pcf50633 as the parent.  This makes them get suspended and
+ * resumed with their parent the pcf50633 still around.  All devices whose
+ * operation depends on something from pcf50633 must have this relationship
+ * made explicit like this, or suspend and resume will become an unreliable
+ * hellworld.
+ */
+
+static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf)
+{
+	int n;
+
+	/* Grab a copy of the now probed PMU pointer. */
+	gta02_pcf = pcf;
+
+	for (n = 0; n < ARRAY_SIZE(gta02_devices_pmu_children); n++)
+		gta02_devices_pmu_children[n]->dev.parent = pcf->dev;
+
+	platform_add_devices(gta02_devices_pmu_children,
+			     ARRAY_SIZE(gta02_devices_pmu_children));
+}
+
+static void gta02_poweroff(void)
+{
+	pcf50633_reg_set_bit_mask(gta02_pcf, PCF50633_REG_OOCSHDWN, 1, 1);
+}
+
+static void __init gta02_machine_init(void)
+{
+	/* Set the panic callback to turn AUX LED on or off. */
+	panic_blink = gta02_panic_blink;
+
+	s3c_pm_init();
+
+#ifdef CONFIG_CHARGER_PCF50633
+	INIT_DELAYED_WORK(&gta02_charger_work, gta02_charger_worker);
+#endif
+
+	s3c24xx_udc_set_platdata(&gta02_udc_cfg);
+	s3c24xx_ts_set_platdata(&gta02_ts_info);
+	s3c_ohci_set_platdata(&gta02_usb_info);
+	s3c_nand_set_platdata(&gta02_nand_info);
+	s3c_i2c0_set_platdata(NULL);
+
+	i2c_register_board_info(0, gta02_i2c_devs, ARRAY_SIZE(gta02_i2c_devs));
+
+	platform_add_devices(gta02_devices, ARRAY_SIZE(gta02_devices));
+	pm_power_off = gta02_poweroff;
+
+	regulator_has_full_constraints();
+}
+
+
+MACHINE_START(NEO1973_GTA02, "GTA02")
+	/* Maintainer: Nelson Castillo <arhuaco@freaks-unidos.net> */
+	.atag_offset	= 0x100,
+	.map_io		= gta02_map_io,
+	.init_irq	= s3c24xx_init_irq,
+	.init_machine	= gta02_machine_init,
+	.timer		= &s3c24xx_timer,
+	.restart	= s3c244x_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c
new file mode 100644
index 0000000..6b21ba1
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/mach-h1940.c
@@ -0,0 +1,757 @@
+/* linux/arch/arm/mach-s3c2410/mach-h1940.c
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.handhelds.org/projects/h1940.html
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/memblock.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/pwm_backlight.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/pda_power.h>
+#include <linux/s3c_adc_battery.h>
+#include <linux/delay.h>
+
+#include <video/platform_lcd.h>
+
+#include <linux/mmc/host.h>
+#include <linux/export.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-lcd.h>
+#include <mach/regs-clock.h>
+
+#include <mach/regs-gpio.h>
+#include <mach/gpio-fns.h>
+#include <mach/gpio-nrs.h>
+
+#include <mach/h1940.h>
+#include <mach/h1940-latch.h>
+#include <mach/fb.h>
+#include <plat/udc.h>
+#include <plat/iic.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pll.h>
+#include <plat/pm.h>
+#include <plat/mci.h>
+#include <plat/ts.h>
+
+#include <sound/uda1380.h>
+
+#include "common.h"
+
+#define H1940_LATCH		((void __force __iomem *)0xF8000000)
+
+#define H1940_PA_LATCH		S3C2410_CS2
+
+#define H1940_LATCH_BIT(x)	(1 << ((x) + 16 - S3C_GPIO_END))
+
+static struct map_desc h1940_iodesc[] __initdata = {
+	[0] = {
+		.virtual	= (unsigned long)H1940_LATCH,
+		.pfn		= __phys_to_pfn(H1940_PA_LATCH),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE
+	},
+};
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg h1940_uartcfgs[] __initdata = {
+	[0] = {
+		.hwport	     = 0,
+		.flags	     = 0,
+		.ucon	     = 0x3c5,
+		.ulcon	     = 0x03,
+		.ufcon	     = 0x51,
+	},
+	[1] = {
+		.hwport	     = 1,
+		.flags	     = 0,
+		.ucon	     = 0x245,
+		.ulcon	     = 0x03,
+		.ufcon	     = 0x00,
+	},
+	/* IR port */
+	[2] = {
+		.hwport	     = 2,
+		.flags	     = 0,
+		.uart_flags  = UPF_CONS_FLOW,
+		.ucon	     = 0x3c5,
+		.ulcon	     = 0x43,
+		.ufcon	     = 0x51,
+	}
+};
+
+/* Board control latch control */
+
+static unsigned int latch_state;
+
+static void h1940_latch_control(unsigned int clear, unsigned int set)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	latch_state &= ~clear;
+	latch_state |= set;
+
+	__raw_writel(latch_state, H1940_LATCH);
+
+	local_irq_restore(flags);
+}
+
+static inline int h1940_gpiolib_to_latch(int offset)
+{
+	return 1 << (offset + 16);
+}
+
+static void h1940_gpiolib_latch_set(struct gpio_chip *chip,
+					unsigned offset, int value)
+{
+	int latch_bit = h1940_gpiolib_to_latch(offset);
+
+	h1940_latch_control(value ? 0 : latch_bit,
+		value ? latch_bit : 0);
+}
+
+static int h1940_gpiolib_latch_output(struct gpio_chip *chip,
+					unsigned offset, int value)
+{
+	h1940_gpiolib_latch_set(chip, offset, value);
+	return 0;
+}
+
+static int h1940_gpiolib_latch_get(struct gpio_chip *chip,
+					unsigned offset)
+{
+	return (latch_state >> (offset + 16)) & 1;
+}
+
+static struct gpio_chip h1940_latch_gpiochip = {
+	.base			= H1940_LATCH_GPIO(0),
+	.owner			= THIS_MODULE,
+	.label			= "H1940_LATCH",
+	.ngpio			= 16,
+	.direction_output	= h1940_gpiolib_latch_output,
+	.set			= h1940_gpiolib_latch_set,
+	.get			= h1940_gpiolib_latch_get,
+};
+
+static struct s3c2410_udc_mach_info h1940_udc_cfg __initdata = {
+	.vbus_pin		= S3C2410_GPG(5),
+	.vbus_pin_inverted	= 1,
+	.pullup_pin		= H1940_LATCH_USB_DP,
+};
+
+static struct s3c2410_ts_mach_info h1940_ts_cfg __initdata = {
+		.delay = 10000,
+		.presc = 49,
+		.oversampling_shift = 2,
+		.cfg_gpio = s3c24xx_ts_cfg_gpio,
+};
+
+/**
+ * Set lcd on or off
+ **/
+static struct s3c2410fb_display h1940_lcd __initdata = {
+	.lcdcon5=	S3C2410_LCDCON5_FRM565 | \
+			S3C2410_LCDCON5_INVVLINE | \
+			S3C2410_LCDCON5_HWSWP,
+
+	.type =		S3C2410_LCDCON1_TFT,
+	.width =	240,
+	.height =	320,
+	.pixclock =	260000,
+	.xres =		240,
+	.yres =		320,
+	.bpp =		16,
+	.left_margin =	8,
+	.right_margin =	20,
+	.hsync_len =	4,
+	.upper_margin =	8,
+	.lower_margin = 7,
+	.vsync_len =	1,
+};
+
+static struct s3c2410fb_mach_info h1940_fb_info __initdata = {
+	.displays = &h1940_lcd,
+	.num_displays = 1,
+	.default_display = 0,
+
+	.lpcsel =	0x02,
+	.gpccon =	0xaa940659,
+	.gpccon_mask =	0xffffc0f0,
+	.gpcup =	0x0000ffff,
+	.gpcup_mask =	0xffffffff,
+	.gpdcon =	0xaa84aaa0,
+	.gpdcon_mask =	0xffffffff,
+	.gpdup =	0x0000faff,
+	.gpdup_mask =	0xffffffff,
+};
+
+static int power_supply_init(struct device *dev)
+{
+	return gpio_request(S3C2410_GPF(2), "cable plugged");
+}
+
+static int h1940_is_ac_online(void)
+{
+	return !gpio_get_value(S3C2410_GPF(2));
+}
+
+static void power_supply_exit(struct device *dev)
+{
+	gpio_free(S3C2410_GPF(2));
+}
+
+static char *h1940_supplicants[] = {
+	"main-battery",
+	"backup-battery",
+};
+
+static struct pda_power_pdata power_supply_info = {
+	.init			= power_supply_init,
+	.is_ac_online		= h1940_is_ac_online,
+	.exit			= power_supply_exit,
+	.supplied_to		= h1940_supplicants,
+	.num_supplicants	= ARRAY_SIZE(h1940_supplicants),
+};
+
+static struct resource power_supply_resources[] = {
+	[0] = {
+			.name	= "ac",
+			.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE |
+					  IORESOURCE_IRQ_HIGHEDGE,
+			.start	= IRQ_EINT2,
+			.end	= IRQ_EINT2,
+	},
+};
+
+static struct platform_device power_supply = {
+	.name		= "pda-power",
+	.id		= -1,
+	.dev		= {
+				.platform_data =
+					&power_supply_info,
+	},
+	.resource	= power_supply_resources,
+	.num_resources	= ARRAY_SIZE(power_supply_resources),
+};
+
+static const struct s3c_adc_bat_thresh bat_lut_noac[] = {
+	{ .volt = 4070, .cur = 162, .level = 100},
+	{ .volt = 4040, .cur = 165, .level = 95},
+	{ .volt = 4016, .cur = 164, .level = 90},
+	{ .volt = 3996, .cur = 166, .level = 85},
+	{ .volt = 3971, .cur = 168, .level = 80},
+	{ .volt = 3951, .cur = 168, .level = 75},
+	{ .volt = 3931, .cur = 170, .level = 70},
+	{ .volt = 3903, .cur = 172, .level = 65},
+	{ .volt = 3886, .cur = 172, .level = 60},
+	{ .volt = 3858, .cur = 176, .level = 55},
+	{ .volt = 3842, .cur = 176, .level = 50},
+	{ .volt = 3818, .cur = 176, .level = 45},
+	{ .volt = 3789, .cur = 180, .level = 40},
+	{ .volt = 3769, .cur = 180, .level = 35},
+	{ .volt = 3749, .cur = 184, .level = 30},
+	{ .volt = 3732, .cur = 184, .level = 25},
+	{ .volt = 3716, .cur = 184, .level = 20},
+	{ .volt = 3708, .cur = 184, .level = 15},
+	{ .volt = 3716, .cur = 96, .level = 10},
+	{ .volt = 3700, .cur = 96, .level = 5},
+	{ .volt = 3684, .cur = 96, .level = 0},
+};
+
+static const struct s3c_adc_bat_thresh bat_lut_acin[] = {
+	{ .volt = 4130, .cur = 0, .level = 100},
+	{ .volt = 3982, .cur = 0, .level = 50},
+	{ .volt = 3854, .cur = 0, .level = 10},
+	{ .volt = 3841, .cur = 0, .level = 0},
+};
+
+static int h1940_bat_init(void)
+{
+	int ret;
+
+	ret = gpio_request(H1940_LATCH_SM803_ENABLE, "h1940-charger-enable");
+	if (ret)
+		return ret;
+	gpio_direction_output(H1940_LATCH_SM803_ENABLE, 0);
+
+	return 0;
+
+}
+
+static void h1940_bat_exit(void)
+{
+	gpio_free(H1940_LATCH_SM803_ENABLE);
+}
+
+static void h1940_enable_charger(void)
+{
+	gpio_set_value(H1940_LATCH_SM803_ENABLE, 1);
+}
+
+static void h1940_disable_charger(void)
+{
+	gpio_set_value(H1940_LATCH_SM803_ENABLE, 0);
+}
+
+static struct s3c_adc_bat_pdata h1940_bat_cfg = {
+	.init = h1940_bat_init,
+	.exit = h1940_bat_exit,
+	.enable_charger = h1940_enable_charger,
+	.disable_charger = h1940_disable_charger,
+	.gpio_charge_finished = S3C2410_GPF(3),
+	.gpio_inverted = 1,
+	.lut_noac = bat_lut_noac,
+	.lut_noac_cnt = ARRAY_SIZE(bat_lut_noac),
+	.lut_acin = bat_lut_acin,
+	.lut_acin_cnt = ARRAY_SIZE(bat_lut_acin),
+	.volt_channel = 0,
+	.current_channel = 1,
+	.volt_mult = 4056,
+	.current_mult = 1893,
+	.internal_impedance = 200,
+	.backup_volt_channel = 3,
+	/* TODO Check backup volt multiplier */
+	.backup_volt_mult = 4056,
+	.backup_volt_min = 0,
+	.backup_volt_max = 4149288
+};
+
+static struct platform_device h1940_battery = {
+	.name             = "s3c-adc-battery",
+	.id               = -1,
+	.dev = {
+		.parent = &s3c_device_adc.dev,
+		.platform_data = &h1940_bat_cfg,
+	},
+};
+
+static DEFINE_SPINLOCK(h1940_blink_spin);
+
+int h1940_led_blink_set(unsigned gpio, int state,
+	unsigned long *delay_on, unsigned long *delay_off)
+{
+	int blink_gpio, check_gpio1, check_gpio2;
+
+	switch (gpio) {
+	case H1940_LATCH_LED_GREEN:
+		blink_gpio = S3C2410_GPA(7);
+		check_gpio1 = S3C2410_GPA(1);
+		check_gpio2 = S3C2410_GPA(3);
+		break;
+	case H1940_LATCH_LED_RED:
+		blink_gpio = S3C2410_GPA(1);
+		check_gpio1 = S3C2410_GPA(7);
+		check_gpio2 = S3C2410_GPA(3);
+		break;
+	default:
+		blink_gpio = S3C2410_GPA(3);
+		check_gpio1 = S3C2410_GPA(1);
+		check_gpio1 = S3C2410_GPA(7);
+		break;
+	}
+
+	if (delay_on && delay_off && !*delay_on && !*delay_off)
+		*delay_on = *delay_off = 500;
+
+	spin_lock(&h1940_blink_spin);
+
+	switch (state) {
+	case GPIO_LED_NO_BLINK_LOW:
+	case GPIO_LED_NO_BLINK_HIGH:
+		if (!gpio_get_value(check_gpio1) &&
+		    !gpio_get_value(check_gpio2))
+			gpio_set_value(H1940_LATCH_LED_FLASH, 0);
+		gpio_set_value(blink_gpio, 0);
+		if (gpio_is_valid(gpio))
+			gpio_set_value(gpio, state);
+		break;
+	case GPIO_LED_BLINK:
+		if (gpio_is_valid(gpio))
+			gpio_set_value(gpio, 0);
+		gpio_set_value(H1940_LATCH_LED_FLASH, 1);
+		gpio_set_value(blink_gpio, 1);
+		break;
+	}
+
+	spin_unlock(&h1940_blink_spin);
+
+	return 0;
+}
+EXPORT_SYMBOL(h1940_led_blink_set);
+
+static struct gpio_led h1940_leds_desc[] = {
+	{
+		.name			= "Green",
+		.default_trigger	= "main-battery-full",
+		.gpio			= H1940_LATCH_LED_GREEN,
+		.retain_state_suspended	= 1,
+	},
+	{
+		.name			= "Red",
+		.default_trigger
+			= "main-battery-charging-blink-full-solid",
+		.gpio			= H1940_LATCH_LED_RED,
+		.retain_state_suspended	= 1,
+	},
+};
+
+static struct gpio_led_platform_data h1940_leds_pdata = {
+	.num_leds	= ARRAY_SIZE(h1940_leds_desc),
+	.leds		= h1940_leds_desc,
+	.gpio_blink_set	= h1940_led_blink_set,
+};
+
+static struct platform_device h1940_device_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+			.platform_data = &h1940_leds_pdata,
+	},
+};
+
+static struct platform_device h1940_device_bluetooth = {
+	.name             = "h1940-bt",
+	.id               = -1,
+};
+
+static void h1940_set_mmc_power(unsigned char power_mode, unsigned short vdd)
+{
+	switch (power_mode) {
+	case MMC_POWER_OFF:
+		gpio_set_value(H1940_LATCH_SD_POWER, 0);
+		break;
+	case MMC_POWER_UP:
+	case MMC_POWER_ON:
+		gpio_set_value(H1940_LATCH_SD_POWER, 1);
+		break;
+	default:
+		break;
+	};
+}
+
+static struct s3c24xx_mci_pdata h1940_mmc_cfg __initdata = {
+	.gpio_detect   = S3C2410_GPF(5),
+	.gpio_wprotect = S3C2410_GPH(8),
+	.set_power     = h1940_set_mmc_power,
+	.ocr_avail     = MMC_VDD_32_33,
+};
+
+static int h1940_backlight_init(struct device *dev)
+{
+	gpio_request(S3C2410_GPB(0), "Backlight");
+
+	gpio_direction_output(S3C2410_GPB(0), 0);
+	s3c_gpio_setpull(S3C2410_GPB(0), S3C_GPIO_PULL_NONE);
+	s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
+	gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 1);
+
+	return 0;
+}
+
+static int h1940_backlight_notify(struct device *dev, int brightness)
+{
+	if (!brightness) {
+		gpio_direction_output(S3C2410_GPB(0), 1);
+		gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
+	} else {
+		gpio_direction_output(S3C2410_GPB(0), 0);
+		s3c_gpio_setpull(S3C2410_GPB(0), S3C_GPIO_PULL_NONE);
+		s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
+		gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 1);
+	}
+	return brightness;
+}
+
+static void h1940_backlight_exit(struct device *dev)
+{
+	gpio_direction_output(S3C2410_GPB(0), 1);
+	gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
+}
+
+
+static struct platform_pwm_backlight_data backlight_data = {
+	.pwm_id         = 0,
+	.max_brightness = 100,
+	.dft_brightness = 50,
+	/* tcnt = 0x31 */
+	.pwm_period_ns  = 36296,
+	.init           = h1940_backlight_init,
+	.notify		= h1940_backlight_notify,
+	.exit           = h1940_backlight_exit,
+};
+
+static struct platform_device h1940_backlight = {
+	.name = "pwm-backlight",
+	.dev  = {
+		.parent = &s3c_device_timer[0].dev,
+		.platform_data = &backlight_data,
+	},
+	.id   = -1,
+};
+
+static void h1940_lcd_power_set(struct plat_lcd_data *pd,
+					unsigned int power)
+{
+	int value, retries = 100;
+
+	if (!power) {
+		gpio_set_value(S3C2410_GPC(0), 0);
+		/* wait for 3ac */
+		do {
+			value = gpio_get_value(S3C2410_GPC(6));
+		} while (value && retries--);
+
+		gpio_set_value(H1940_LATCH_LCD_P2, 0);
+		gpio_set_value(H1940_LATCH_LCD_P3, 0);
+		gpio_set_value(H1940_LATCH_LCD_P4, 0);
+
+		gpio_direction_output(S3C2410_GPC(1), 0);
+		gpio_direction_output(S3C2410_GPC(4), 0);
+
+		gpio_set_value(H1940_LATCH_LCD_P1, 0);
+		gpio_set_value(H1940_LATCH_LCD_P0, 0);
+
+		gpio_set_value(S3C2410_GPC(5), 0);
+
+	} else {
+		gpio_set_value(H1940_LATCH_LCD_P0, 1);
+		gpio_set_value(H1940_LATCH_LCD_P1, 1);
+
+		gpio_direction_input(S3C2410_GPC(1));
+		gpio_direction_input(S3C2410_GPC(4));
+		mdelay(10);
+		s3c_gpio_cfgpin(S3C2410_GPC(1), S3C_GPIO_SFN(2));
+		s3c_gpio_cfgpin(S3C2410_GPC(4), S3C_GPIO_SFN(2));
+
+		gpio_set_value(S3C2410_GPC(5), 1);
+		gpio_set_value(S3C2410_GPC(0), 1);
+
+		gpio_set_value(H1940_LATCH_LCD_P3, 1);
+		gpio_set_value(H1940_LATCH_LCD_P2, 1);
+		gpio_set_value(H1940_LATCH_LCD_P4, 1);
+	}
+}
+
+static struct plat_lcd_data h1940_lcd_power_data = {
+	.set_power      = h1940_lcd_power_set,
+};
+
+static struct platform_device h1940_lcd_powerdev = {
+	.name                   = "platform-lcd",
+	.dev.parent             = &s3c_device_lcd.dev,
+	.dev.platform_data      = &h1940_lcd_power_data,
+};
+
+static struct uda1380_platform_data uda1380_info = {
+	.gpio_power	= H1940_LATCH_UDA_POWER,
+	.gpio_reset	= S3C2410_GPA(12),
+	.dac_clk	= UDA1380_DAC_CLK_SYSCLK,
+};
+
+static struct i2c_board_info h1940_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("uda1380", 0x1a),
+		.platform_data = &uda1380_info,
+	},
+};
+
+#define DECLARE_BUTTON(p, k, n, w)	\
+	{				\
+		.gpio		= p,	\
+		.code		= k,	\
+		.desc		= n,	\
+		.wakeup		= w,	\
+		.active_low	= 1,	\
+	}
+
+static struct gpio_keys_button h1940_buttons[] = {
+	DECLARE_BUTTON(S3C2410_GPF(0),       KEY_POWER,          "Power", 1),
+	DECLARE_BUTTON(S3C2410_GPF(6),       KEY_ENTER,         "Select", 1),
+	DECLARE_BUTTON(S3C2410_GPF(7),      KEY_RECORD,         "Record", 0),
+	DECLARE_BUTTON(S3C2410_GPG(0),         KEY_F11,       "Calendar", 0),
+	DECLARE_BUTTON(S3C2410_GPG(2),         KEY_F12,       "Contacts", 0),
+	DECLARE_BUTTON(S3C2410_GPG(3),        KEY_MAIL,           "Mail", 0),
+	DECLARE_BUTTON(S3C2410_GPG(6),        KEY_LEFT,     "Left_arrow", 0),
+	DECLARE_BUTTON(S3C2410_GPG(7),    KEY_HOMEPAGE,           "Home", 0),
+	DECLARE_BUTTON(S3C2410_GPG(8),       KEY_RIGHT,    "Right_arrow", 0),
+	DECLARE_BUTTON(S3C2410_GPG(9),          KEY_UP,       "Up_arrow", 0),
+	DECLARE_BUTTON(S3C2410_GPG(10),       KEY_DOWN,     "Down_arrow", 0),
+};
+
+static struct gpio_keys_platform_data h1940_buttons_data = {
+	.buttons	= h1940_buttons,
+	.nbuttons	= ARRAY_SIZE(h1940_buttons),
+};
+
+static struct platform_device h1940_dev_buttons = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.dev		= {
+		.platform_data  = &h1940_buttons_data,
+	}
+};
+
+static struct platform_device *h1940_devices[] __initdata = {
+	&h1940_dev_buttons,
+	&s3c_device_ohci,
+	&s3c_device_lcd,
+	&s3c_device_wdt,
+	&s3c_device_i2c0,
+	&s3c_device_iis,
+	&samsung_asoc_dma,
+	&s3c_device_usbgadget,
+	&h1940_device_leds,
+	&h1940_device_bluetooth,
+	&s3c_device_sdi,
+	&s3c_device_rtc,
+	&s3c_device_timer[0],
+	&h1940_backlight,
+	&h1940_lcd_powerdev,
+	&s3c_device_adc,
+	&s3c_device_ts,
+	&power_supply,
+	&h1940_battery,
+};
+
+static void __init h1940_map_io(void)
+{
+	s3c24xx_init_io(h1940_iodesc, ARRAY_SIZE(h1940_iodesc));
+	s3c24xx_init_clocks(0);
+	s3c24xx_init_uarts(h1940_uartcfgs, ARRAY_SIZE(h1940_uartcfgs));
+
+	/* setup PM */
+
+#ifdef CONFIG_PM_H1940
+	memcpy(phys_to_virt(H1940_SUSPEND_RESUMEAT), h1940_pm_return, 1024);
+#endif
+	s3c_pm_init();
+
+	/* Add latch gpio chip, set latch initial value */
+	h1940_latch_control(0, 0);
+	WARN_ON(gpiochip_add(&h1940_latch_gpiochip));
+}
+
+/* H1940 and RX3715 need to reserve this for suspend */
+static void __init h1940_reserve(void)
+{
+	memblock_reserve(0x30003000, 0x1000);
+	memblock_reserve(0x30081000, 0x1000);
+}
+
+static void __init h1940_init_irq(void)
+{
+	s3c24xx_init_irq();
+}
+
+static void __init h1940_init(void)
+{
+	u32 tmp;
+
+	s3c24xx_fb_set_platdata(&h1940_fb_info);
+	s3c24xx_mci_set_platdata(&h1940_mmc_cfg);
+ 	s3c24xx_udc_set_platdata(&h1940_udc_cfg);
+	s3c24xx_ts_set_platdata(&h1940_ts_cfg);
+	s3c_i2c0_set_platdata(NULL);
+
+	/* Turn off suspend on both USB ports, and switch the
+	 * selectable USB port to USB device mode. */
+
+	s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
+			      S3C2410_MISCCR_USBSUSPND0 |
+			      S3C2410_MISCCR_USBSUSPND1, 0x0);
+
+	tmp =   (0x78 << S3C24XX_PLL_MDIV_SHIFT)
+	      | (0x02 << S3C24XX_PLL_PDIV_SHIFT)
+	      | (0x03 << S3C24XX_PLL_SDIV_SHIFT);
+	writel(tmp, S3C2410_UPLLCON);
+
+	gpio_request(S3C2410_GPC(0), "LCD power");
+	gpio_request(S3C2410_GPC(1), "LCD power");
+	gpio_request(S3C2410_GPC(4), "LCD power");
+	gpio_request(S3C2410_GPC(5), "LCD power");
+	gpio_request(S3C2410_GPC(6), "LCD power");
+	gpio_request(H1940_LATCH_LCD_P0, "LCD power");
+	gpio_request(H1940_LATCH_LCD_P1, "LCD power");
+	gpio_request(H1940_LATCH_LCD_P2, "LCD power");
+	gpio_request(H1940_LATCH_LCD_P3, "LCD power");
+	gpio_request(H1940_LATCH_LCD_P4, "LCD power");
+	gpio_request(H1940_LATCH_MAX1698_nSHUTDOWN, "LCD power");
+	gpio_direction_output(S3C2410_GPC(0), 0);
+	gpio_direction_output(S3C2410_GPC(1), 0);
+	gpio_direction_output(S3C2410_GPC(4), 0);
+	gpio_direction_output(S3C2410_GPC(5), 0);
+	gpio_direction_input(S3C2410_GPC(6));
+	gpio_direction_output(H1940_LATCH_LCD_P0, 0);
+	gpio_direction_output(H1940_LATCH_LCD_P1, 0);
+	gpio_direction_output(H1940_LATCH_LCD_P2, 0);
+	gpio_direction_output(H1940_LATCH_LCD_P3, 0);
+	gpio_direction_output(H1940_LATCH_LCD_P4, 0);
+	gpio_direction_output(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
+
+	gpio_request(H1940_LATCH_SD_POWER, "SD power");
+	gpio_direction_output(H1940_LATCH_SD_POWER, 0);
+
+	platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));
+
+	gpio_request(S3C2410_GPA(1), "Red LED blink");
+	gpio_request(S3C2410_GPA(3), "Blue LED blink");
+	gpio_request(S3C2410_GPA(7), "Green LED blink");
+	gpio_request(H1940_LATCH_LED_FLASH, "LED blink");
+	gpio_direction_output(S3C2410_GPA(1), 0);
+	gpio_direction_output(S3C2410_GPA(3), 0);
+	gpio_direction_output(S3C2410_GPA(7), 0);
+	gpio_direction_output(H1940_LATCH_LED_FLASH, 0);
+
+	i2c_register_board_info(0, h1940_i2c_devices,
+		ARRAY_SIZE(h1940_i2c_devices));
+}
+
+MACHINE_START(H1940, "IPAQ-H1940")
+	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
+	.atag_offset	= 0x100,
+	.map_io		= h1940_map_io,
+	.reserve	= h1940_reserve,
+	.init_irq	= h1940_init_irq,
+	.init_machine	= h1940_init,
+	.timer		= &s3c24xx_timer,
+	.restart	= s3c2410_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c2412/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c
similarity index 100%
rename from arch/arm/mach-s3c2412/mach-jive.c
rename to arch/arm/mach-s3c24xx/mach-jive.c
diff --git a/arch/arm/mach-s3c2440/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c
similarity index 100%
rename from arch/arm/mach-s3c2440/mach-mini2440.c
rename to arch/arm/mach-s3c24xx/mach-mini2440.c
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c24xx/mach-n30.c
similarity index 100%
rename from arch/arm/mach-s3c2410/mach-n30.c
rename to arch/arm/mach-s3c24xx/mach-n30.c
diff --git a/arch/arm/mach-s3c2440/mach-nexcoder.c b/arch/arm/mach-s3c24xx/mach-nexcoder.c
similarity index 100%
rename from arch/arm/mach-s3c2440/mach-nexcoder.c
rename to arch/arm/mach-s3c24xx/mach-nexcoder.c
diff --git a/arch/arm/mach-s3c2440/mach-osiris-dvs.c b/arch/arm/mach-s3c24xx/mach-osiris-dvs.c
similarity index 100%
rename from arch/arm/mach-s3c2440/mach-osiris-dvs.c
rename to arch/arm/mach-s3c24xx/mach-osiris-dvs.c
diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c
similarity index 100%
rename from arch/arm/mach-s3c2440/mach-osiris.c
rename to arch/arm/mach-s3c24xx/mach-osiris.c
diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c24xx/mach-otom.c
similarity index 100%
rename from arch/arm/mach-s3c2410/mach-otom.c
rename to arch/arm/mach-s3c24xx/mach-otom.c
diff --git a/arch/arm/mach-s3c2410/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c
similarity index 100%
rename from arch/arm/mach-s3c2410/mach-qt2410.c
rename to arch/arm/mach-s3c24xx/mach-qt2410.c
diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c
new file mode 100644
index 0000000..200debb
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/mach-rx1950.c
@@ -0,0 +1,826 @@
+/* linux/arch/arm/mach-s3c2440/mach-rx1950.c
+ *
+ * Copyright (c) 2006-2009 Victor Chukhantsev, Denis Grigoriev,
+ * Copyright (c) 2007-2010 Vasily Khoruzhick
+ *
+ * based on smdk2440 written by Ben Dooks
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/memblock.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/device.h>
+#include <linux/pda_power.h>
+#include <linux/pwm_backlight.h>
+#include <linux/pwm.h>
+#include <linux/s3c_adc_battery.h>
+#include <linux/leds.h>
+#include <linux/i2c.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/mmc/host.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+
+#include <mach/regs-gpio.h>
+#include <mach/regs-gpioj.h>
+#include <mach/regs-lcd.h>
+#include <mach/h1940.h>
+#include <mach/fb.h>
+
+#include <plat/clock.h>
+#include <plat/regs-serial.h>
+#include <plat/regs-iic.h>
+#include <plat/mci.h>
+#include <plat/udc.h>
+#include <plat/nand.h>
+#include <plat/iic.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/irq.h>
+#include <plat/ts.h>
+
+#include <sound/uda1380.h>
+
+#include "common.h"
+
+#define LCD_PWM_PERIOD 192960
+#define LCD_PWM_DUTY 127353
+
+static struct map_desc rx1950_iodesc[] __initdata = {
+};
+
+static struct s3c2410_uartcfg rx1950_uartcfgs[] __initdata = {
+	[0] = {
+	       .hwport = 0,
+	       .flags = 0,
+	       .ucon = 0x3c5,
+	       .ulcon = 0x03,
+	       .ufcon = 0x51,
+		.clk_sel = S3C2410_UCON_CLKSEL3,
+	},
+	[1] = {
+	       .hwport = 1,
+	       .flags = 0,
+	       .ucon = 0x3c5,
+	       .ulcon = 0x03,
+	       .ufcon = 0x51,
+		.clk_sel = S3C2410_UCON_CLKSEL3,
+	},
+	/* IR port */
+	[2] = {
+	       .hwport = 2,
+	       .flags = 0,
+	       .ucon = 0x3c5,
+	       .ulcon = 0x43,
+	       .ufcon = 0xf1,
+		.clk_sel = S3C2410_UCON_CLKSEL3,
+	},
+};
+
+static struct s3c2410fb_display rx1950_display = {
+	.type = S3C2410_LCDCON1_TFT,
+	.width = 240,
+	.height = 320,
+	.xres = 240,
+	.yres = 320,
+	.bpp = 16,
+
+	.pixclock = 260000,
+	.left_margin = 10,
+	.right_margin = 20,
+	.hsync_len = 10,
+	.upper_margin = 2,
+	.lower_margin = 2,
+	.vsync_len = 2,
+
+	.lcdcon5 = S3C2410_LCDCON5_FRM565 |
+			   S3C2410_LCDCON5_INVVCLK |
+			   S3C2410_LCDCON5_INVVLINE |
+			   S3C2410_LCDCON5_INVVFRAME |
+			   S3C2410_LCDCON5_HWSWP |
+			   (0x02 << 13) |
+			   (0x02 << 15),
+
+};
+
+static int power_supply_init(struct device *dev)
+{
+	return gpio_request(S3C2410_GPF(2), "cable plugged");
+}
+
+static int rx1950_is_ac_online(void)
+{
+	return !gpio_get_value(S3C2410_GPF(2));
+}
+
+static void power_supply_exit(struct device *dev)
+{
+	gpio_free(S3C2410_GPF(2));
+}
+
+static char *rx1950_supplicants[] = {
+	"main-battery"
+};
+
+static struct pda_power_pdata power_supply_info = {
+	.init			= power_supply_init,
+	.is_ac_online		= rx1950_is_ac_online,
+	.exit			= power_supply_exit,
+	.supplied_to		= rx1950_supplicants,
+	.num_supplicants	= ARRAY_SIZE(rx1950_supplicants),
+};
+
+static struct resource power_supply_resources[] = {
+	[0] = {
+			.name	= "ac",
+			.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE |
+					  IORESOURCE_IRQ_HIGHEDGE,
+			.start	= IRQ_EINT2,
+			.end	= IRQ_EINT2,
+	},
+};
+
+static struct platform_device power_supply = {
+	.name			= "pda-power",
+	.id			= -1,
+	.dev			= {
+					.platform_data =
+						&power_supply_info,
+	},
+	.resource		= power_supply_resources,
+	.num_resources		= ARRAY_SIZE(power_supply_resources),
+};
+
+static const struct s3c_adc_bat_thresh bat_lut_noac[] = {
+	{ .volt = 4100, .cur = 156, .level = 100},
+	{ .volt = 4050, .cur = 156, .level = 95},
+	{ .volt = 4025, .cur = 141, .level = 90},
+	{ .volt = 3995, .cur = 144, .level = 85},
+	{ .volt = 3957, .cur = 162, .level = 80},
+	{ .volt = 3931, .cur = 147, .level = 75},
+	{ .volt = 3902, .cur = 147, .level = 70},
+	{ .volt = 3863, .cur = 153, .level = 65},
+	{ .volt = 3838, .cur = 150, .level = 60},
+	{ .volt = 3800, .cur = 153, .level = 55},
+	{ .volt = 3765, .cur = 153, .level = 50},
+	{ .volt = 3748, .cur = 172, .level = 45},
+	{ .volt = 3740, .cur = 153, .level = 40},
+	{ .volt = 3714, .cur = 175, .level = 35},
+	{ .volt = 3710, .cur = 156, .level = 30},
+	{ .volt = 3963, .cur = 156, .level = 25},
+	{ .volt = 3672, .cur = 178, .level = 20},
+	{ .volt = 3651, .cur = 178, .level = 15},
+	{ .volt = 3629, .cur = 178, .level = 10},
+	{ .volt = 3612, .cur = 162, .level = 5},
+	{ .volt = 3605, .cur = 162, .level = 0},
+};
+
+static const struct s3c_adc_bat_thresh bat_lut_acin[] = {
+	{ .volt = 4200, .cur = 0, .level = 100},
+	{ .volt = 4190, .cur = 0, .level = 99},
+	{ .volt = 4178, .cur = 0, .level = 95},
+	{ .volt = 4110, .cur = 0, .level = 70},
+	{ .volt = 4076, .cur = 0, .level = 65},
+	{ .volt = 4046, .cur = 0, .level = 60},
+	{ .volt = 4021, .cur = 0, .level = 55},
+	{ .volt = 3999, .cur = 0, .level = 50},
+	{ .volt = 3982, .cur = 0, .level = 45},
+	{ .volt = 3965, .cur = 0, .level = 40},
+	{ .volt = 3957, .cur = 0, .level = 35},
+	{ .volt = 3948, .cur = 0, .level = 30},
+	{ .volt = 3936, .cur = 0, .level = 25},
+	{ .volt = 3927, .cur = 0, .level = 20},
+	{ .volt = 3906, .cur = 0, .level = 15},
+	{ .volt = 3880, .cur = 0, .level = 10},
+	{ .volt = 3829, .cur = 0, .level = 5},
+	{ .volt = 3820, .cur = 0, .level = 0},
+};
+
+static int rx1950_bat_init(void)
+{
+	int ret;
+
+	ret = gpio_request(S3C2410_GPJ(2), "rx1950-charger-enable-1");
+	if (ret)
+		goto err_gpio1;
+	ret = gpio_request(S3C2410_GPJ(3), "rx1950-charger-enable-2");
+	if (ret)
+		goto err_gpio2;
+
+	return 0;
+
+err_gpio2:
+	gpio_free(S3C2410_GPJ(2));
+err_gpio1:
+	return ret;
+}
+
+static void rx1950_bat_exit(void)
+{
+	gpio_free(S3C2410_GPJ(2));
+	gpio_free(S3C2410_GPJ(3));
+}
+
+static void rx1950_enable_charger(void)
+{
+	gpio_direction_output(S3C2410_GPJ(2), 1);
+	gpio_direction_output(S3C2410_GPJ(3), 1);
+}
+
+static void rx1950_disable_charger(void)
+{
+	gpio_direction_output(S3C2410_GPJ(2), 0);
+	gpio_direction_output(S3C2410_GPJ(3), 0);
+}
+
+static DEFINE_SPINLOCK(rx1950_blink_spin);
+
+static int rx1950_led_blink_set(unsigned gpio, int state,
+	unsigned long *delay_on, unsigned long *delay_off)
+{
+	int blink_gpio, check_gpio;
+
+	switch (gpio) {
+	case S3C2410_GPA(6):
+		blink_gpio = S3C2410_GPA(4);
+		check_gpio = S3C2410_GPA(3);
+		break;
+	case S3C2410_GPA(7):
+		blink_gpio = S3C2410_GPA(3);
+		check_gpio = S3C2410_GPA(4);
+		break;
+	default:
+		return -EINVAL;
+		break;
+	}
+
+	if (delay_on && delay_off && !*delay_on && !*delay_off)
+		*delay_on = *delay_off = 500;
+
+	spin_lock(&rx1950_blink_spin);
+
+	switch (state) {
+	case GPIO_LED_NO_BLINK_LOW:
+	case GPIO_LED_NO_BLINK_HIGH:
+		if (!gpio_get_value(check_gpio))
+			gpio_set_value(S3C2410_GPJ(6), 0);
+		gpio_set_value(blink_gpio, 0);
+		gpio_set_value(gpio, state);
+		break;
+	case GPIO_LED_BLINK:
+		gpio_set_value(gpio, 0);
+		gpio_set_value(S3C2410_GPJ(6), 1);
+		gpio_set_value(blink_gpio, 1);
+		break;
+	}
+
+	spin_unlock(&rx1950_blink_spin);
+
+	return 0;
+}
+
+static struct gpio_led rx1950_leds_desc[] = {
+	{
+		.name			= "Green",
+		.default_trigger	= "main-battery-full",
+		.gpio			= S3C2410_GPA(6),
+		.retain_state_suspended	= 1,
+	},
+	{
+		.name			= "Red",
+		.default_trigger
+			= "main-battery-charging-blink-full-solid",
+		.gpio			= S3C2410_GPA(7),
+		.retain_state_suspended	= 1,
+	},
+	{
+		.name			= "Blue",
+		.default_trigger	= "rx1950-acx-mem",
+		.gpio			= S3C2410_GPA(11),
+		.retain_state_suspended	= 1,
+	},
+};
+
+static struct gpio_led_platform_data rx1950_leds_pdata = {
+	.num_leds	= ARRAY_SIZE(rx1950_leds_desc),
+	.leds		= rx1950_leds_desc,
+	.gpio_blink_set	= rx1950_led_blink_set,
+};
+
+static struct platform_device rx1950_leds = {
+	.name	= "leds-gpio",
+	.id		= -1,
+	.dev	= {
+				.platform_data = &rx1950_leds_pdata,
+	},
+};
+
+static struct s3c_adc_bat_pdata rx1950_bat_cfg = {
+	.init = rx1950_bat_init,
+	.exit = rx1950_bat_exit,
+	.enable_charger = rx1950_enable_charger,
+	.disable_charger = rx1950_disable_charger,
+	.gpio_charge_finished = S3C2410_GPF(3),
+	.lut_noac = bat_lut_noac,
+	.lut_noac_cnt = ARRAY_SIZE(bat_lut_noac),
+	.lut_acin = bat_lut_acin,
+	.lut_acin_cnt = ARRAY_SIZE(bat_lut_acin),
+	.volt_channel = 0,
+	.current_channel = 1,
+	.volt_mult = 4235,
+	.current_mult = 2900,
+	.internal_impedance = 200,
+};
+
+static struct platform_device rx1950_battery = {
+	.name             = "s3c-adc-battery",
+	.id               = -1,
+	.dev = {
+		.parent = &s3c_device_adc.dev,
+		.platform_data = &rx1950_bat_cfg,
+	},
+};
+
+static struct s3c2410fb_mach_info rx1950_lcd_cfg = {
+	.displays = &rx1950_display,
+	.num_displays = 1,
+	.default_display = 0,
+
+	.lpcsel = 0x02,
+	.gpccon = 0xaa9556a9,
+	.gpccon_mask = 0xffc003fc,
+	.gpcup = 0x0000ffff,
+	.gpcup_mask = 0xffffffff,
+
+	.gpdcon = 0xaa90aaa1,
+	.gpdcon_mask = 0xffc0fff0,
+	.gpdup = 0x0000fcfd,
+	.gpdup_mask = 0xffffffff,
+
+};
+
+static struct pwm_device *lcd_pwm;
+
+static void rx1950_lcd_power(int enable)
+{
+	int i;
+	static int enabled;
+	if (enabled == enable)
+		return;
+	if (!enable) {
+
+		/* GPC11-GPC15->OUTPUT */
+		for (i = 11; i < 16; i++)
+			gpio_direction_output(S3C2410_GPC(i), 1);
+
+		/* Wait a bit here... */
+		mdelay(100);
+
+		/* GPD2-GPD7->OUTPUT */
+		/* GPD11-GPD15->OUTPUT */
+		/* GPD2-GPD7->1, GPD11-GPD15->1 */
+		for (i = 2; i < 8; i++)
+			gpio_direction_output(S3C2410_GPD(i), 1);
+		for (i = 11; i < 16; i++)
+			gpio_direction_output(S3C2410_GPD(i), 1);
+
+		/* Wait a bit here...*/
+		mdelay(100);
+
+		/* GPB0->OUTPUT, GPB0->0 */
+		gpio_direction_output(S3C2410_GPB(0), 0);
+
+		/* GPC1-GPC4->OUTPUT, GPC1-4->0 */
+		for (i = 1; i < 5; i++)
+			gpio_direction_output(S3C2410_GPC(i), 0);
+
+		/* GPC15-GPC11->0 */
+		for (i = 11; i < 16; i++)
+			gpio_direction_output(S3C2410_GPC(i), 0);
+
+		/* GPD15-GPD11->0, GPD2->GPD7->0 */
+		for (i = 11; i < 16; i++)
+			gpio_direction_output(S3C2410_GPD(i), 0);
+
+		for (i = 2; i < 8; i++)
+			gpio_direction_output(S3C2410_GPD(i), 0);
+
+		/* GPC6->0, GPC7->0, GPC5->0 */
+		gpio_direction_output(S3C2410_GPC(6), 0);
+		gpio_direction_output(S3C2410_GPC(7), 0);
+		gpio_direction_output(S3C2410_GPC(5), 0);
+
+		/* GPB1->OUTPUT, GPB1->0 */
+		gpio_direction_output(S3C2410_GPB(1), 0);
+		pwm_config(lcd_pwm, 0, LCD_PWM_PERIOD);
+		pwm_disable(lcd_pwm);
+
+		/* GPC0->0, GPC10->0 */
+		gpio_direction_output(S3C2410_GPC(0), 0);
+		gpio_direction_output(S3C2410_GPC(10), 0);
+	} else {
+		pwm_config(lcd_pwm, LCD_PWM_DUTY, LCD_PWM_PERIOD);
+		pwm_enable(lcd_pwm);
+
+		gpio_direction_output(S3C2410_GPC(0), 1);
+		gpio_direction_output(S3C2410_GPC(5), 1);
+
+		s3c_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPB1_TOUT1);
+		gpio_direction_output(S3C2410_GPC(7), 1);
+
+		for (i = 1; i < 5; i++)
+			s3c_gpio_cfgpin(S3C2410_GPC(i), S3C_GPIO_SFN(2));
+
+		for (i = 11; i < 16; i++)
+			s3c_gpio_cfgpin(S3C2410_GPC(i), S3C_GPIO_SFN(2));
+
+		for (i = 2; i < 8; i++)
+			s3c_gpio_cfgpin(S3C2410_GPD(i), S3C_GPIO_SFN(2));
+
+		for (i = 11; i < 16; i++)
+			s3c_gpio_cfgpin(S3C2410_GPD(i), S3C_GPIO_SFN(2));
+
+		gpio_direction_output(S3C2410_GPC(10), 1);
+		gpio_direction_output(S3C2410_GPC(6), 1);
+	}
+	enabled = enable;
+}
+
+static void rx1950_bl_power(int enable)
+{
+	static int enabled;
+	if (enabled == enable)
+		return;
+	if (!enable) {
+			gpio_direction_output(S3C2410_GPB(0), 0);
+	} else {
+			/* LED driver need a "push" to power on */
+			gpio_direction_output(S3C2410_GPB(0), 1);
+			/* Warm up backlight for one period of PWM.
+			 * Without this trick its almost impossible to
+			 * enable backlight with low brightness value
+			 */
+			ndelay(48000);
+			s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
+	}
+	enabled = enable;
+}
+
+static int rx1950_backlight_init(struct device *dev)
+{
+	WARN_ON(gpio_request(S3C2410_GPB(0), "Backlight"));
+	lcd_pwm = pwm_request(1, "RX1950 LCD");
+	if (IS_ERR(lcd_pwm)) {
+		dev_err(dev, "Unable to request PWM for LCD power!\n");
+		return PTR_ERR(lcd_pwm);
+	}
+
+	rx1950_lcd_power(1);
+	rx1950_bl_power(1);
+
+	return 0;
+}
+
+static void rx1950_backlight_exit(struct device *dev)
+{
+	rx1950_bl_power(0);
+	rx1950_lcd_power(0);
+
+	pwm_free(lcd_pwm);
+	gpio_free(S3C2410_GPB(0));
+}
+
+
+static int rx1950_backlight_notify(struct device *dev, int brightness)
+{
+	if (!brightness) {
+		rx1950_bl_power(0);
+		rx1950_lcd_power(0);
+	} else {
+		rx1950_lcd_power(1);
+		rx1950_bl_power(1);
+	}
+	return brightness;
+}
+
+static struct platform_pwm_backlight_data rx1950_backlight_data = {
+	.pwm_id = 0,
+	.max_brightness = 24,
+	.dft_brightness = 4,
+	.pwm_period_ns = 48000,
+	.init = rx1950_backlight_init,
+	.notify = rx1950_backlight_notify,
+	.exit = rx1950_backlight_exit,
+};
+
+static struct platform_device rx1950_backlight = {
+	.name = "pwm-backlight",
+	.dev = {
+		.parent = &s3c_device_timer[0].dev,
+		.platform_data = &rx1950_backlight_data,
+	},
+};
+
+static void rx1950_set_mmc_power(unsigned char power_mode, unsigned short vdd)
+{
+	switch (power_mode) {
+	case MMC_POWER_OFF:
+		gpio_direction_output(S3C2410_GPJ(1), 0);
+		break;
+	case MMC_POWER_UP:
+	case MMC_POWER_ON:
+		gpio_direction_output(S3C2410_GPJ(1), 1);
+		break;
+	default:
+		break;
+	}
+}
+
+static struct s3c24xx_mci_pdata rx1950_mmc_cfg __initdata = {
+	.gpio_detect = S3C2410_GPF(5),
+	.gpio_wprotect = S3C2410_GPH(8),
+	.set_power = rx1950_set_mmc_power,
+	.ocr_avail = MMC_VDD_32_33,
+};
+
+static struct mtd_partition rx1950_nand_part[] = {
+	[0] = {
+			.name = "Boot0",
+			.offset = 0,
+			.size = 0x4000,
+			.mask_flags = MTD_WRITEABLE,
+	},
+	[1] = {
+			.name = "Boot1",
+			.offset = MTDPART_OFS_APPEND,
+			.size = 0x40000,
+			.mask_flags = MTD_WRITEABLE,
+	},
+	[2] = {
+			.name = "Kernel",
+			.offset = MTDPART_OFS_APPEND,
+			.size = 0x300000,
+			.mask_flags = 0,
+	},
+	[3] = {
+			.name = "Filesystem",
+			.offset = MTDPART_OFS_APPEND,
+			.size = MTDPART_SIZ_FULL,
+			.mask_flags = 0,
+	},
+};
+
+static struct s3c2410_nand_set rx1950_nand_sets[] = {
+	[0] = {
+			.name = "Internal",
+			.nr_chips = 1,
+			.nr_partitions = ARRAY_SIZE(rx1950_nand_part),
+			.partitions = rx1950_nand_part,
+	},
+};
+
+static struct s3c2410_platform_nand rx1950_nand_info = {
+	.tacls = 25,
+	.twrph0 = 50,
+	.twrph1 = 15,
+	.nr_sets = ARRAY_SIZE(rx1950_nand_sets),
+	.sets = rx1950_nand_sets,
+};
+
+static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {
+	.vbus_pin = S3C2410_GPG(5),
+	.vbus_pin_inverted = 1,
+	.pullup_pin = S3C2410_GPJ(5),
+};
+
+static struct s3c2410_ts_mach_info rx1950_ts_cfg __initdata = {
+	.delay = 10000,
+	.presc = 49,
+	.oversampling_shift = 3,
+};
+
+static struct gpio_keys_button rx1950_gpio_keys_table[] = {
+	{
+		.code		= KEY_POWER,
+		.gpio		= S3C2410_GPF(0),
+		.active_low	= 1,
+		.desc		= "Power button",
+		.wakeup		= 1,
+	},
+	{
+		.code		= KEY_F5,
+		.gpio		= S3C2410_GPF(7),
+		.active_low	= 1,
+		.desc		= "Record button",
+	},
+	{
+		.code		= KEY_F1,
+		.gpio		= S3C2410_GPG(0),
+		.active_low	= 1,
+		.desc		= "Calendar button",
+	},
+	{
+		.code		= KEY_F2,
+		.gpio		= S3C2410_GPG(2),
+		.active_low	= 1,
+		.desc		= "Contacts button",
+	},
+	{
+		.code		= KEY_F3,
+		.gpio		= S3C2410_GPG(3),
+		.active_low	= 1,
+		.desc		= "Mail button",
+	},
+	{
+		.code		= KEY_F4,
+		.gpio		= S3C2410_GPG(7),
+		.active_low	= 1,
+		.desc		= "WLAN button",
+	},
+	{
+		.code		= KEY_LEFT,
+		.gpio		= S3C2410_GPG(10),
+		.active_low	= 1,
+		.desc		= "Left button",
+	},
+	{
+		.code		= KEY_RIGHT,
+		.gpio		= S3C2410_GPG(11),
+		.active_low	= 1,
+		.desc		= "Right button",
+	},
+	{
+		.code		= KEY_UP,
+		.gpio		= S3C2410_GPG(4),
+		.active_low	= 1,
+		.desc		= "Up button",
+	},
+	{
+		.code		= KEY_DOWN,
+		.gpio		= S3C2410_GPG(6),
+		.active_low	= 1,
+		.desc		= "Down button",
+	},
+	{
+		.code		= KEY_ENTER,
+		.gpio		= S3C2410_GPG(9),
+		.active_low	= 1,
+		.desc		= "Ok button"
+	},
+};
+
+static struct gpio_keys_platform_data rx1950_gpio_keys_data = {
+	.buttons = rx1950_gpio_keys_table,
+	.nbuttons = ARRAY_SIZE(rx1950_gpio_keys_table),
+};
+
+static struct platform_device rx1950_device_gpiokeys = {
+	.name = "gpio-keys",
+	.dev.platform_data = &rx1950_gpio_keys_data,
+};
+
+static struct uda1380_platform_data uda1380_info = {
+	.gpio_power	= S3C2410_GPJ(0),
+	.gpio_reset	= S3C2410_GPD(0),
+	.dac_clk	= UDA1380_DAC_CLK_SYSCLK,
+};
+
+static struct i2c_board_info rx1950_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("uda1380", 0x1a),
+		.platform_data = &uda1380_info,
+	},
+};
+
+static struct platform_device *rx1950_devices[] __initdata = {
+	&s3c_device_lcd,
+	&s3c_device_wdt,
+	&s3c_device_i2c0,
+	&s3c_device_iis,
+	&samsung_asoc_dma,
+	&s3c_device_usbgadget,
+	&s3c_device_rtc,
+	&s3c_device_nand,
+	&s3c_device_sdi,
+	&s3c_device_adc,
+	&s3c_device_ts,
+	&s3c_device_timer[0],
+	&s3c_device_timer[1],
+	&rx1950_backlight,
+	&rx1950_device_gpiokeys,
+	&power_supply,
+	&rx1950_battery,
+	&rx1950_leds,
+};
+
+static struct clk *rx1950_clocks[] __initdata = {
+	&s3c24xx_clkout0,
+	&s3c24xx_clkout1,
+};
+
+static void __init rx1950_map_io(void)
+{
+	s3c24xx_clkout0.parent  = &clk_h;
+	s3c24xx_clkout1.parent  = &clk_f;
+
+	s3c24xx_register_clocks(rx1950_clocks, ARRAY_SIZE(rx1950_clocks));
+
+	s3c24xx_init_io(rx1950_iodesc, ARRAY_SIZE(rx1950_iodesc));
+	s3c24xx_init_clocks(16934000);
+	s3c24xx_init_uarts(rx1950_uartcfgs, ARRAY_SIZE(rx1950_uartcfgs));
+
+	/* setup PM */
+
+#ifdef CONFIG_PM_H1940
+	memcpy(phys_to_virt(H1940_SUSPEND_RESUMEAT), h1940_pm_return, 8);
+#endif
+
+	s3c_pm_init();
+}
+
+static void __init rx1950_init_machine(void)
+{
+	int i;
+
+	s3c24xx_fb_set_platdata(&rx1950_lcd_cfg);
+	s3c24xx_udc_set_platdata(&rx1950_udc_cfg);
+	s3c24xx_ts_set_platdata(&rx1950_ts_cfg);
+	s3c24xx_mci_set_platdata(&rx1950_mmc_cfg);
+	s3c_i2c0_set_platdata(NULL);
+	s3c_nand_set_platdata(&rx1950_nand_info);
+
+	/* Turn off suspend on both USB ports, and switch the
+	 * selectable USB port to USB device mode. */
+	s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
+						S3C2410_MISCCR_USBSUSPND0 |
+						S3C2410_MISCCR_USBSUSPND1, 0x0);
+
+	/* mmc power is disabled by default */
+	WARN_ON(gpio_request(S3C2410_GPJ(1), "MMC power"));
+	gpio_direction_output(S3C2410_GPJ(1), 0);
+
+	for (i = 0; i < 8; i++)
+		WARN_ON(gpio_request(S3C2410_GPC(i), "LCD power"));
+
+	for (i = 10; i < 16; i++)
+		WARN_ON(gpio_request(S3C2410_GPC(i), "LCD power"));
+
+	for (i = 2; i < 8; i++)
+		WARN_ON(gpio_request(S3C2410_GPD(i), "LCD power"));
+
+	for (i = 11; i < 16; i++)
+		WARN_ON(gpio_request(S3C2410_GPD(i), "LCD power"));
+
+	WARN_ON(gpio_request(S3C2410_GPB(1), "LCD power"));
+
+	WARN_ON(gpio_request(S3C2410_GPA(3), "Red blink"));
+	WARN_ON(gpio_request(S3C2410_GPA(4), "Green blink"));
+	WARN_ON(gpio_request(S3C2410_GPJ(6), "LED blink"));
+	gpio_direction_output(S3C2410_GPA(3), 0);
+	gpio_direction_output(S3C2410_GPA(4), 0);
+	gpio_direction_output(S3C2410_GPJ(6), 0);
+
+	platform_add_devices(rx1950_devices, ARRAY_SIZE(rx1950_devices));
+
+	i2c_register_board_info(0, rx1950_i2c_devices,
+		ARRAY_SIZE(rx1950_i2c_devices));
+}
+
+/* H1940 and RX3715 need to reserve this for suspend */
+static void __init rx1950_reserve(void)
+{
+	memblock_reserve(0x30003000, 0x1000);
+	memblock_reserve(0x30081000, 0x1000);
+}
+
+MACHINE_START(RX1950, "HP iPAQ RX1950")
+    /* Maintainers: Vasily Khoruzhick */
+	.atag_offset = 0x100,
+	.map_io = rx1950_map_io,
+	.reserve	= rx1950_reserve,
+	.init_irq = s3c24xx_init_irq,
+	.init_machine = rx1950_init_machine,
+	.timer = &s3c24xx_timer,
+	.restart	= s3c244x_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c
similarity index 100%
rename from arch/arm/mach-s3c2440/mach-rx3715.c
rename to arch/arm/mach-s3c24xx/mach-rx3715.c
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c24xx/mach-smdk2410.c
similarity index 100%
rename from arch/arm/mach-s3c2410/mach-smdk2410.c
rename to arch/arm/mach-s3c24xx/mach-smdk2410.c
diff --git a/arch/arm/mach-s3c2412/mach-smdk2413.c b/arch/arm/mach-s3c24xx/mach-smdk2413.c
similarity index 100%
rename from arch/arm/mach-s3c2412/mach-smdk2413.c
rename to arch/arm/mach-s3c24xx/mach-smdk2413.c
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2416.c b/arch/arm/mach-s3c24xx/mach-smdk2416.c
new file mode 100644
index 0000000..30a44f8
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/mach-smdk2416.c
@@ -0,0 +1,256 @@
+/* linux/arch/arm/mach-s3c2416/mach-hanlin_v3c.c
+ *
+ * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
+ *	as part of OpenInkpot project
+ * Copyright (c) 2009 Promwad Innovation Company
+ *	Yauhen Kharuzhy <yauhen.kharuzhy@promwad.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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/mtd/partitions.h>
+#include <linux/gpio.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-lcd.h>
+#include <mach/regs-s3c2443-clock.h>
+
+#include <mach/idle.h>
+#include <mach/leds-gpio.h>
+#include <plat/iic.h>
+
+#include <plat/s3c2416.h>
+#include <plat/gpio-cfg.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/nand.h>
+#include <plat/sdhci.h>
+#include <plat/udc.h>
+#include <linux/platform_data/s3c-hsudc.h>
+
+#include <plat/regs-fb-v4.h>
+#include <plat/fb.h>
+
+#include <plat/common-smdk.h>
+
+static struct map_desc smdk2416_iodesc[] __initdata = {
+	/* ISA IO Space map (memory space selected by A24) */
+
+	{
+		.virtual	= (u32)S3C24XX_VA_ISA_WORD,
+		.pfn		= __phys_to_pfn(S3C2410_CS2),
+		.length		= 0x10000,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (u32)S3C24XX_VA_ISA_WORD + 0x10000,
+		.pfn		= __phys_to_pfn(S3C2410_CS2 + (1<<24)),
+		.length		= SZ_4M,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (u32)S3C24XX_VA_ISA_BYTE,
+		.pfn		= __phys_to_pfn(S3C2410_CS2),
+		.length		= 0x10000,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (u32)S3C24XX_VA_ISA_BYTE + 0x10000,
+		.pfn		= __phys_to_pfn(S3C2410_CS2 + (1<<24)),
+		.length		= SZ_4M,
+		.type		= MT_DEVICE,
+	}
+};
+
+#define UCON (S3C2410_UCON_DEFAULT	| \
+		S3C2440_UCON_PCLK	| \
+		S3C2443_UCON_RXERR_IRQEN)
+
+#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE)
+
+#define UFCON (S3C2410_UFCON_RXTRIG8	| \
+		S3C2410_UFCON_FIFOMODE	| \
+		S3C2440_UFCON_TXTRIG16)
+
+static struct s3c2410_uartcfg smdk2416_uartcfgs[] __initdata = {
+	[0] = {
+		.hwport	     = 0,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+	},
+	[1] = {
+		.hwport	     = 1,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+	},
+	/* IR port */
+	[2] = {
+		.hwport	     = 2,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON | 0x50,
+		.ufcon	     = UFCON,
+	},
+	[3] = {
+		.hwport	     = 3,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+	}
+};
+
+static void smdk2416_hsudc_gpio_init(void)
+{
+	s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_UP);
+	s3c_gpio_setpull(S3C2410_GPF(2), S3C_GPIO_PULL_NONE);
+	s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(1));
+	s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 0);
+}
+
+static void smdk2416_hsudc_gpio_uninit(void)
+{
+	s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 1);
+	s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_NONE);
+	s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(0));
+}
+
+static struct s3c24xx_hsudc_platdata smdk2416_hsudc_platdata = {
+	.epnum = 9,
+	.gpio_init = smdk2416_hsudc_gpio_init,
+	.gpio_uninit = smdk2416_hsudc_gpio_uninit,
+};
+
+static struct s3c_fb_pd_win smdk2416_fb_win[] = {
+	[0] = {
+		/* think this is the same as the smdk6410 */
+		.win_mode	= {
+			.pixclock	= 41094,
+			.left_margin	= 8,
+			.right_margin	= 13,
+			.upper_margin	= 7,
+			.lower_margin	= 5,
+			.hsync_len	= 3,
+			.vsync_len	= 1,
+			.xres           = 800,
+			.yres           = 480,
+		},
+		.default_bpp	= 16,
+		.max_bpp	= 32,
+	},
+};
+
+static void s3c2416_fb_gpio_setup_24bpp(void)
+{
+	unsigned int gpio;
+
+	for (gpio = S3C2410_GPC(1); gpio <= S3C2410_GPC(4); gpio++) {
+		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+	}
+
+	for (gpio = S3C2410_GPC(8); gpio <= S3C2410_GPC(15); gpio++) {
+		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+	}
+
+	for (gpio = S3C2410_GPD(0); gpio <= S3C2410_GPD(15); gpio++) {
+		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+	}
+}
+
+static struct s3c_fb_platdata smdk2416_fb_platdata = {
+	.win[0]		= &smdk2416_fb_win[0],
+	.setup_gpio	= s3c2416_fb_gpio_setup_24bpp,
+	.vidcon0	= VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+	.vidcon1	= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+};
+
+static struct s3c_sdhci_platdata smdk2416_hsmmc0_pdata __initdata = {
+	.max_width		= 4,
+	.cd_type		= S3C_SDHCI_CD_GPIO,
+	.ext_cd_gpio		= S3C2410_GPF(1),
+	.ext_cd_gpio_invert	= 1,
+};
+
+static struct s3c_sdhci_platdata smdk2416_hsmmc1_pdata __initdata = {
+	.max_width		= 4,
+	.cd_type		= S3C_SDHCI_CD_NONE,
+};
+
+static struct platform_device *smdk2416_devices[] __initdata = {
+	&s3c_device_fb,
+	&s3c_device_wdt,
+	&s3c_device_ohci,
+	&s3c_device_i2c0,
+	&s3c_device_hsmmc0,
+	&s3c_device_hsmmc1,
+	&s3c_device_usb_hsudc,
+};
+
+static void __init smdk2416_map_io(void)
+{
+	s3c24xx_init_io(smdk2416_iodesc, ARRAY_SIZE(smdk2416_iodesc));
+	s3c24xx_init_clocks(12000000);
+	s3c24xx_init_uarts(smdk2416_uartcfgs, ARRAY_SIZE(smdk2416_uartcfgs));
+}
+
+static void __init smdk2416_machine_init(void)
+{
+	s3c_i2c0_set_platdata(NULL);
+	s3c_fb_set_platdata(&smdk2416_fb_platdata);
+
+	s3c_sdhci0_set_platdata(&smdk2416_hsmmc0_pdata);
+	s3c_sdhci1_set_platdata(&smdk2416_hsmmc1_pdata);
+
+	s3c24xx_hsudc_set_platdata(&smdk2416_hsudc_platdata);
+
+	gpio_request(S3C2410_GPB(4), "USBHost Power");
+	gpio_direction_output(S3C2410_GPB(4), 1);
+
+	gpio_request(S3C2410_GPB(3), "Display Power");
+	gpio_direction_output(S3C2410_GPB(3), 1);
+
+	gpio_request(S3C2410_GPB(1), "Display Reset");
+	gpio_direction_output(S3C2410_GPB(1), 1);
+
+	platform_add_devices(smdk2416_devices, ARRAY_SIZE(smdk2416_devices));
+	smdk_machine_init();
+}
+
+MACHINE_START(SMDK2416, "SMDK2416")
+	/* Maintainer: Yauhen Kharuzhy <jekhor@gmail.com> */
+	.atag_offset	= 0x100,
+
+	.init_irq	= s3c24xx_init_irq,
+	.map_io		= smdk2416_map_io,
+	.init_machine	= smdk2416_machine_init,
+	.timer		= &s3c24xx_timer,
+	.restart	= s3c2416_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-smdk2440.c b/arch/arm/mach-s3c24xx/mach-smdk2440.c
similarity index 100%
rename from arch/arm/mach-s3c2440/mach-smdk2440.c
rename to arch/arm/mach-s3c24xx/mach-smdk2440.c
diff --git a/arch/arm/mach-s3c2443/mach-smdk2443.c b/arch/arm/mach-s3c24xx/mach-smdk2443.c
similarity index 100%
rename from arch/arm/mach-s3c2443/mach-smdk2443.c
rename to arch/arm/mach-s3c24xx/mach-smdk2443.c
diff --git a/arch/arm/mach-s3c2410/mach-tct_hammer.c b/arch/arm/mach-s3c24xx/mach-tct_hammer.c
similarity index 100%
rename from arch/arm/mach-s3c2410/mach-tct_hammer.c
rename to arch/arm/mach-s3c24xx/mach-tct_hammer.c
diff --git a/arch/arm/mach-s3c24xx/mach-vr1000.c b/arch/arm/mach-s3c24xx/mach-vr1000.c
new file mode 100644
index 0000000..87608d4
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/mach-vr1000.c
@@ -0,0 +1,385 @@
+/* linux/arch/arm/mach-s3c2410/mach-vr1000.c
+ *
+ * Copyright (c) 2003-2008 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * Machine support for Thorcom VR1000 board. Designed for Thorcom by
+ * Simtec Electronics, http://www.simtec.co.uk/
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/dm9000.h>
+#include <linux/i2c.h>
+
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/bast-map.h>
+#include <mach/vr1000-map.h>
+#include <mach/vr1000-irq.h>
+#include <mach/vr1000-cpld.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/leds-gpio.h>
+
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/iic.h>
+#include <plat/audio-simtec.h>
+
+#include "simtec.h"
+#include "common.h"
+
+/* macros for virtual address mods for the io space entries */
+#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5)
+#define VA_C4(item) ((unsigned long)(item) + BAST_VAM_CS4)
+#define VA_C3(item) ((unsigned long)(item) + BAST_VAM_CS3)
+#define VA_C2(item) ((unsigned long)(item) + BAST_VAM_CS2)
+
+/* macros to modify the physical addresses for io space */
+
+#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2))
+#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3))
+#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4))
+#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5))
+
+static struct map_desc vr1000_iodesc[] __initdata = {
+  /* ISA IO areas */
+  {
+	  .virtual	= (u32)S3C24XX_VA_ISA_BYTE,
+	  .pfn		= PA_CS2(BAST_PA_ISAIO),
+	  .length	= SZ_16M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)S3C24XX_VA_ISA_WORD,
+	  .pfn		= PA_CS3(BAST_PA_ISAIO),
+	  .length	= SZ_16M,
+	  .type		= MT_DEVICE,
+  },
+
+  /*  CPLD control registers, and external interrupt controls */
+  {
+	  .virtual	= (u32)VR1000_VA_CTRL1,
+	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL1),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)VR1000_VA_CTRL2,
+	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL2),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)VR1000_VA_CTRL3,
+	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL3),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)VR1000_VA_CTRL4,
+	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL4),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  },
+};
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg vr1000_uartcfgs[] __initdata = {
+	[0] = {
+		.hwport	     = 0,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+	},
+	[1] = {
+		.hwport	     = 1,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+	},
+	/* port 2 is not actually used */
+	[2] = {
+		.hwport	     = 2,
+		.flags	     = 0,
+		.ucon	     = UCON,
+		.ulcon	     = ULCON,
+		.ufcon	     = UFCON,
+	}
+};
+
+/* definitions for the vr1000 extra 16550 serial ports */
+
+#define VR1000_BAUDBASE (3692307)
+
+#define VR1000_SERIAL_MAPBASE(x) (VR1000_PA_SERIAL + 0x80 + ((x) << 5))
+
+static struct plat_serial8250_port serial_platform_data[] = {
+	[0] = {
+		.mapbase	= VR1000_SERIAL_MAPBASE(0),
+		.irq		= IRQ_VR1000_SERIAL + 0,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 0,
+		.uartclk	= VR1000_BAUDBASE,
+	},
+	[1] = {
+		.mapbase	= VR1000_SERIAL_MAPBASE(1),
+		.irq		= IRQ_VR1000_SERIAL + 1,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 0,
+		.uartclk	= VR1000_BAUDBASE,
+	},
+	[2] = {
+		.mapbase	= VR1000_SERIAL_MAPBASE(2),
+		.irq		= IRQ_VR1000_SERIAL + 2,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 0,
+		.uartclk	= VR1000_BAUDBASE,
+	},
+	[3] = {
+		.mapbase	= VR1000_SERIAL_MAPBASE(3),
+		.irq		= IRQ_VR1000_SERIAL + 3,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 0,
+		.uartclk	= VR1000_BAUDBASE,
+	},
+	{ },
+};
+
+static struct platform_device serial_device = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev			= {
+		.platform_data	= serial_platform_data,
+	},
+};
+
+/* DM9000 ethernet devices */
+
+static struct resource vr1000_dm9k0_resource[] = {
+	[0] = {
+		.start = S3C2410_CS5 + VR1000_PA_DM9000,
+		.end   = S3C2410_CS5 + VR1000_PA_DM9000 + 3,
+		.flags = IORESOURCE_MEM
+	},
+	[1] = {
+		.start = S3C2410_CS5 + VR1000_PA_DM9000 + 0x40,
+		.end   = S3C2410_CS5 + VR1000_PA_DM9000 + 0x7f,
+		.flags = IORESOURCE_MEM
+	},
+	[2] = {
+		.start = IRQ_VR1000_DM9000A,
+		.end   = IRQ_VR1000_DM9000A,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	}
+
+};
+
+static struct resource vr1000_dm9k1_resource[] = {
+	[0] = {
+		.start = S3C2410_CS5 + VR1000_PA_DM9000 + 0x80,
+		.end   = S3C2410_CS5 + VR1000_PA_DM9000 + 0x83,
+		.flags = IORESOURCE_MEM
+	},
+	[1] = {
+		.start = S3C2410_CS5 + VR1000_PA_DM9000 + 0xC0,
+		.end   = S3C2410_CS5 + VR1000_PA_DM9000 + 0xFF,
+		.flags = IORESOURCE_MEM
+	},
+	[2] = {
+		.start = IRQ_VR1000_DM9000N,
+		.end   = IRQ_VR1000_DM9000N,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	}
+};
+
+/* for the moment we limit ourselves to 16bit IO until some
+ * better IO routines can be written and tested
+*/
+
+static struct dm9000_plat_data vr1000_dm9k_platdata = {
+	.flags		= DM9000_PLATF_16BITONLY,
+};
+
+static struct platform_device vr1000_dm9k0 = {
+	.name		= "dm9000",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(vr1000_dm9k0_resource),
+	.resource	= vr1000_dm9k0_resource,
+	.dev		= {
+		.platform_data = &vr1000_dm9k_platdata,
+	}
+};
+
+static struct platform_device vr1000_dm9k1 = {
+	.name		= "dm9000",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(vr1000_dm9k1_resource),
+	.resource	= vr1000_dm9k1_resource,
+	.dev		= {
+		.platform_data = &vr1000_dm9k_platdata,
+	}
+};
+
+/* LEDS */
+
+static struct s3c24xx_led_platdata vr1000_led1_pdata = {
+	.name		= "led1",
+	.gpio		= S3C2410_GPB(0),
+	.def_trigger	= "",
+};
+
+static struct s3c24xx_led_platdata vr1000_led2_pdata = {
+	.name		= "led2",
+	.gpio		= S3C2410_GPB(1),
+	.def_trigger	= "",
+};
+
+static struct s3c24xx_led_platdata vr1000_led3_pdata = {
+	.name		= "led3",
+	.gpio		= S3C2410_GPB(2),
+	.def_trigger	= "",
+};
+
+static struct platform_device vr1000_led1 = {
+	.name		= "s3c24xx_led",
+	.id		= 1,
+	.dev		= {
+		.platform_data	= &vr1000_led1_pdata,
+	},
+};
+
+static struct platform_device vr1000_led2 = {
+	.name		= "s3c24xx_led",
+	.id		= 2,
+	.dev		= {
+		.platform_data	= &vr1000_led2_pdata,
+	},
+};
+
+static struct platform_device vr1000_led3 = {
+	.name		= "s3c24xx_led",
+	.id		= 3,
+	.dev		= {
+		.platform_data	= &vr1000_led3_pdata,
+	},
+};
+
+/* I2C devices. */
+
+static struct i2c_board_info vr1000_i2c_devs[] __initdata = {
+	{
+		I2C_BOARD_INFO("tlv320aic23", 0x1a),
+	}, {
+		I2C_BOARD_INFO("tmp101", 0x48),
+	}, {
+		I2C_BOARD_INFO("m41st87", 0x68),
+	},
+};
+
+/* devices for this board */
+
+static struct platform_device *vr1000_devices[] __initdata = {
+	&s3c_device_ohci,
+	&s3c_device_lcd,
+	&s3c_device_wdt,
+	&s3c_device_i2c0,
+	&s3c_device_adc,
+	&serial_device,
+	&vr1000_dm9k0,
+	&vr1000_dm9k1,
+	&vr1000_led1,
+	&vr1000_led2,
+	&vr1000_led3,
+};
+
+static struct clk *vr1000_clocks[] __initdata = {
+	&s3c24xx_dclk0,
+	&s3c24xx_dclk1,
+	&s3c24xx_clkout0,
+	&s3c24xx_clkout1,
+	&s3c24xx_uclk,
+};
+
+static void vr1000_power_off(void)
+{
+	gpio_direction_output(S3C2410_GPB(9), 1);
+}
+
+static void __init vr1000_map_io(void)
+{
+	/* initialise clock sources */
+
+	s3c24xx_dclk0.parent = &clk_upll;
+	s3c24xx_dclk0.rate   = 12*1000*1000;
+
+	s3c24xx_dclk1.parent = NULL;
+	s3c24xx_dclk1.rate   = 3692307;
+
+	s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
+	s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
+
+	s3c24xx_uclk.parent  = &s3c24xx_clkout1;
+
+	s3c24xx_register_clocks(vr1000_clocks, ARRAY_SIZE(vr1000_clocks));
+
+	pm_power_off = vr1000_power_off;
+
+	s3c24xx_init_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc));
+	s3c24xx_init_clocks(0);
+	s3c24xx_init_uarts(vr1000_uartcfgs, ARRAY_SIZE(vr1000_uartcfgs));
+}
+
+static void __init vr1000_init(void)
+{
+	s3c_i2c0_set_platdata(NULL);
+	platform_add_devices(vr1000_devices, ARRAY_SIZE(vr1000_devices));
+
+	i2c_register_board_info(0, vr1000_i2c_devs,
+				ARRAY_SIZE(vr1000_i2c_devs));
+
+	nor_simtec_init();
+	simtec_audio_add(NULL, true, NULL);
+
+	WARN_ON(gpio_request(S3C2410_GPB(9), "power off"));
+}
+
+MACHINE_START(VR1000, "Thorcom-VR1000")
+	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
+	.atag_offset	= 0x100,
+	.map_io		= vr1000_map_io,
+	.init_machine	= vr1000_init,
+	.init_irq	= s3c24xx_init_irq,
+	.timer		= &s3c24xx_timer,
+	.restart	= s3c2410_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c2412/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c
similarity index 100%
rename from arch/arm/mach-s3c2412/mach-vstms.c
rename to arch/arm/mach-s3c24xx/mach-vstms.c
diff --git a/arch/arm/mach-s3c2410/pm-h1940.S b/arch/arm/mach-s3c24xx/pm-h1940.S
similarity index 100%
rename from arch/arm/mach-s3c2410/pm-h1940.S
rename to arch/arm/mach-s3c24xx/pm-h1940.S
diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c24xx/pm-s3c2410.c
similarity index 100%
rename from arch/arm/mach-s3c2410/pm.c
rename to arch/arm/mach-s3c24xx/pm-s3c2410.c
diff --git a/arch/arm/mach-s3c2412/pm.c b/arch/arm/mach-s3c24xx/pm-s3c2412.c
similarity index 100%
rename from arch/arm/mach-s3c2412/pm.c
rename to arch/arm/mach-s3c24xx/pm-s3c2412.c
diff --git a/arch/arm/mach-s3c2416/pm.c b/arch/arm/mach-s3c24xx/pm-s3c2416.c
similarity index 100%
rename from arch/arm/mach-s3c2416/pm.c
rename to arch/arm/mach-s3c24xx/pm-s3c2416.c
diff --git a/arch/arm/mach-s3c24xx/s3c2410.c b/arch/arm/mach-s3c24xx/s3c2410.c
new file mode 100644
index 0000000..a3c5cb0
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/s3c2410.c
@@ -0,0 +1,207 @@
+/* linux/arch/arm/mach-s3c2410/s3c2410.c
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.simtec.co.uk/products/EB2410ITX/
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/syscore_ops.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/system_misc.h>
+
+#include <plat/cpu-freq.h>
+
+#include <mach/regs-clock.h>
+#include <plat/regs-serial.h>
+
+#include <plat/s3c2410.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+#include <plat/pll.h>
+#include <plat/pm.h>
+#include <plat/watchdog-reset.h>
+
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
+
+/* Initial IO mappings */
+
+static struct map_desc s3c2410_iodesc[] __initdata = {
+	IODESC_ENT(CLKPWR),
+	IODESC_ENT(TIMER),
+	IODESC_ENT(WATCHDOG),
+};
+
+/* our uart devices */
+
+/* uart registration process */
+
+void __init s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+	s3c24xx_init_uartdevs("s3c2410-uart", s3c2410_uart_resources, cfg, no);
+}
+
+/* s3c2410_map_io
+ *
+ * register the standard cpu IO areas, and any passed in from the
+ * machine specific initialisation.
+*/
+
+void __init s3c2410_map_io(void)
+{
+	s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1up;
+	s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1up;
+
+	iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc));
+}
+
+void __init_or_cpufreq s3c2410_setup_clocks(void)
+{
+	struct clk *xtal_clk;
+	unsigned long tmp;
+	unsigned long xtal;
+	unsigned long fclk;
+	unsigned long hclk;
+	unsigned long pclk;
+
+	xtal_clk = clk_get(NULL, "xtal");
+	xtal = clk_get_rate(xtal_clk);
+	clk_put(xtal_clk);
+
+	/* now we've got our machine bits initialised, work out what
+	 * clocks we've got */
+
+	fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);
+
+	tmp = __raw_readl(S3C2410_CLKDIVN);
+
+	/* work out clock scalings */
+
+	hclk = fclk / ((tmp & S3C2410_CLKDIVN_HDIVN) ? 2 : 1);
+	pclk = hclk / ((tmp & S3C2410_CLKDIVN_PDIVN) ? 2 : 1);
+
+	/* print brieft summary of clocks, etc */
+
+	printk("S3C2410: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
+	       print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
+
+	/* initialise the clocks here, to allow other things like the
+	 * console to use them
+	 */
+
+	s3c24xx_setup_clocks(fclk, hclk, pclk);
+}
+
+/* fake ARMCLK for use with cpufreq, etc. */
+
+static struct clk s3c2410_armclk = {
+	.name	= "armclk",
+	.parent	= &clk_f,
+	.id	= -1,
+};
+
+static struct clk_lookup s3c2410_clk_lookup[] = {
+	CLKDEV_INIT(NULL, "clk_uart_baud0", &clk_p),
+	CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
+};
+
+void __init s3c2410_init_clocks(int xtal)
+{
+	s3c24xx_register_baseclocks(xtal);
+	s3c2410_setup_clocks();
+	s3c2410_baseclk_add();
+	s3c24xx_register_clock(&s3c2410_armclk);
+	clkdev_add_table(s3c2410_clk_lookup, ARRAY_SIZE(s3c2410_clk_lookup));
+}
+
+struct bus_type s3c2410_subsys = {
+	.name = "s3c2410-core",
+	.dev_name = "s3c2410-core",
+};
+
+/* Note, we would have liked to name this s3c2410-core, but we cannot
+ * register two subsystems with the same name.
+ */
+struct bus_type s3c2410a_subsys = {
+	.name = "s3c2410a-core",
+	.dev_name = "s3c2410a-core",
+};
+
+static struct device s3c2410_dev = {
+	.bus		= &s3c2410_subsys,
+};
+
+/* need to register the subsystem before we actually register the device, and
+ * we also need to ensure that it has been initialised before any of the
+ * drivers even try to use it (even if not on an s3c2410 based system)
+ * as a driver which may support both 2410 and 2440 may try and use it.
+*/
+
+static int __init s3c2410_core_init(void)
+{
+	return subsys_system_register(&s3c2410_subsys, NULL);
+}
+
+core_initcall(s3c2410_core_init);
+
+static int __init s3c2410a_core_init(void)
+{
+	return subsys_system_register(&s3c2410a_subsys, NULL);
+}
+
+core_initcall(s3c2410a_core_init);
+
+int __init s3c2410_init(void)
+{
+	printk("S3C2410: Initialising architecture\n");
+
+#ifdef CONFIG_PM
+	register_syscore_ops(&s3c2410_pm_syscore_ops);
+#endif
+	register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
+	return device_register(&s3c2410_dev);
+}
+
+int __init s3c2410a_init(void)
+{
+	s3c2410_dev.bus = &s3c2410a_subsys;
+	return s3c2410_init();
+}
+
+void s3c2410_restart(char mode, const char *cmd)
+{
+	if (mode == 's') {
+		soft_restart(0);
+	}
+
+	arch_wdt_reset();
+
+	/* we'll take a jump through zero as a poor second */
+	soft_restart(0);
+}
diff --git a/arch/arm/mach-s3c24xx/s3c2412.c b/arch/arm/mach-s3c24xx/s3c2412.c
new file mode 100644
index 0000000..d4bc7f9
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/s3c2412.c
@@ -0,0 +1,252 @@
+/* linux/arch/arm/mach-s3c2412/s3c2412.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://armlinux.simtec.co.uk/.
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/syscore_ops.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/proc-fns.h>
+#include <asm/irq.h>
+#include <asm/system_misc.h>
+
+#include <plat/cpu-freq.h>
+
+#include <mach/regs-clock.h>
+#include <plat/regs-serial.h>
+#include <mach/regs-power.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-gpioj.h>
+#include <mach/regs-dsc.h>
+#include <plat/regs-spi.h>
+#include <mach/regs-s3c2412.h>
+
+#include <plat/s3c2412.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+#include <plat/pm.h>
+#include <plat/pll.h>
+#include <plat/nand-core.h>
+
+#ifndef CONFIG_CPU_S3C2412_ONLY
+void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
+
+static inline void s3c2412_init_gpio2(void)
+{
+	s3c24xx_va_gpio2 = S3C24XX_VA_GPIO + 0x10;
+}
+#else
+#define s3c2412_init_gpio2() do { } while(0)
+#endif
+
+/* Initial IO mappings */
+
+static struct map_desc s3c2412_iodesc[] __initdata = {
+	IODESC_ENT(CLKPWR),
+	IODESC_ENT(TIMER),
+	IODESC_ENT(WATCHDOG),
+	{
+		.virtual = (unsigned long)S3C2412_VA_SSMC,
+		.pfn	 = __phys_to_pfn(S3C2412_PA_SSMC),
+		.length	 = SZ_1M,
+		.type	 = MT_DEVICE,
+	},
+	{
+		.virtual = (unsigned long)S3C2412_VA_EBI,
+		.pfn	 = __phys_to_pfn(S3C2412_PA_EBI),
+		.length	 = SZ_1M,
+		.type	 = MT_DEVICE,
+	},
+};
+
+/* uart registration process */
+
+void __init s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+	s3c24xx_init_uartdevs("s3c2412-uart", s3c2410_uart_resources, cfg, no);
+
+	/* rename devices that are s3c2412/s3c2413 specific */
+	s3c_device_sdi.name  = "s3c2412-sdi";
+	s3c_device_lcd.name  = "s3c2412-lcd";
+	s3c_nand_setname("s3c2412-nand");
+
+	/* alter IRQ of SDI controller */
+
+	s3c_device_sdi.resource[1].start = IRQ_S3C2412_SDI;
+	s3c_device_sdi.resource[1].end   = IRQ_S3C2412_SDI;
+
+	/* spi channel related changes, s3c2412/13 specific */
+	s3c_device_spi0.name = "s3c2412-spi";
+	s3c_device_spi0.resource[0].end = S3C24XX_PA_SPI + 0x24;
+	s3c_device_spi1.name = "s3c2412-spi";
+	s3c_device_spi1.resource[0].start = S3C24XX_PA_SPI + S3C2412_SPI1;
+	s3c_device_spi1.resource[0].end = S3C24XX_PA_SPI + S3C2412_SPI1 + 0x24;
+
+}
+
+/* s3c2412_idle
+ *
+ * use the standard idle call by ensuring the idle mode
+ * in power config, then issuing the idle co-processor
+ * instruction
+*/
+
+static void s3c2412_idle(void)
+{
+	unsigned long tmp;
+
+	/* ensure our idle mode is to go to idle */
+
+	tmp = __raw_readl(S3C2412_PWRCFG);
+	tmp &= ~S3C2412_PWRCFG_STANDBYWFI_MASK;
+	tmp |= S3C2412_PWRCFG_STANDBYWFI_IDLE;
+	__raw_writel(tmp, S3C2412_PWRCFG);
+
+	cpu_do_idle();
+}
+
+void s3c2412_restart(char mode, const char *cmd)
+{
+	if (mode == 's')
+		soft_restart(0);
+
+	/* errata "Watch-dog/Software Reset Problem" specifies that
+	 * this reset must be done with the SYSCLK sourced from
+	 * EXTCLK instead of FOUT to avoid a glitch in the reset
+	 * mechanism.
+	 *
+	 * See the watchdog section of the S3C2412 manual for more
+	 * information on this fix.
+	 */
+
+	__raw_writel(0x00, S3C2412_CLKSRC);
+	__raw_writel(S3C2412_SWRST_RESET, S3C2412_SWRST);
+
+	mdelay(1);
+}
+
+/* s3c2412_map_io
+ *
+ * register the standard cpu IO areas, and any passed in from the
+ * machine specific initialisation.
+*/
+
+void __init s3c2412_map_io(void)
+{
+	/* move base of IO */
+
+	s3c2412_init_gpio2();
+
+	/* set our idle function */
+
+	arm_pm_idle = s3c2412_idle;
+
+	/* register our io-tables */
+
+	iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc));
+}
+
+void __init_or_cpufreq s3c2412_setup_clocks(void)
+{
+	struct clk *xtal_clk;
+	unsigned long tmp;
+	unsigned long xtal;
+	unsigned long fclk;
+	unsigned long hclk;
+	unsigned long pclk;
+
+	xtal_clk = clk_get(NULL, "xtal");
+	xtal = clk_get_rate(xtal_clk);
+	clk_put(xtal_clk);
+
+	/* now we've got our machine bits initialised, work out what
+	 * clocks we've got */
+
+	fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal * 2);
+
+	clk_mpll.rate = fclk;
+
+	tmp = __raw_readl(S3C2410_CLKDIVN);
+
+	/* work out clock scalings */
+
+	hclk = fclk / ((tmp & S3C2412_CLKDIVN_HDIVN_MASK) + 1);
+	hclk /= ((tmp & S3C2412_CLKDIVN_ARMDIVN) ? 2 : 1);
+	pclk = hclk / ((tmp & S3C2412_CLKDIVN_PDIVN) ? 2 : 1);
+
+	/* print brieft summary of clocks, etc */
+
+	printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
+	       print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
+
+	s3c24xx_setup_clocks(fclk, hclk, pclk);
+}
+
+void __init s3c2412_init_clocks(int xtal)
+{
+	/* initialise the clocks here, to allow other things like the
+	 * console to use them
+	 */
+
+	s3c24xx_register_baseclocks(xtal);
+	s3c2412_setup_clocks();
+	s3c2412_baseclk_add();
+}
+
+/* need to register the subsystem before we actually register the device, and
+ * we also need to ensure that it has been initialised before any of the
+ * drivers even try to use it (even if not on an s3c2412 based system)
+ * as a driver which may support both 2410 and 2440 may try and use it.
+*/
+
+struct bus_type s3c2412_subsys = {
+	.name = "s3c2412-core",
+	.dev_name = "s3c2412-core",
+};
+
+static int __init s3c2412_core_init(void)
+{
+	return subsys_system_register(&s3c2412_subsys, NULL);
+}
+
+core_initcall(s3c2412_core_init);
+
+static struct device s3c2412_dev = {
+	.bus		= &s3c2412_subsys,
+};
+
+int __init s3c2412_init(void)
+{
+	printk("S3C2412: Initialising architecture\n");
+
+#ifdef CONFIG_PM
+	register_syscore_ops(&s3c2412_pm_syscore_ops);
+#endif
+	register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
+	return device_register(&s3c2412_dev);
+}
diff --git a/arch/arm/mach-s3c24xx/s3c2416.c b/arch/arm/mach-s3c24xx/s3c2416.c
new file mode 100644
index 0000000..7743fad
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/s3c2416.c
@@ -0,0 +1,149 @@
+/* linux/arch/arm/mach-s3c2416/s3c2416.c
+ *
+ * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
+ *	as part of OpenInkpot project
+ * Copyright (c) 2009 Promwad Innovation Company
+ *	Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com>
+ *
+ * Samsung S3C2416 Mobile CPU support
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/device.h>
+#include <linux/syscore_ops.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/proc-fns.h>
+#include <asm/irq.h>
+#include <asm/system_misc.h>
+
+#include <mach/regs-s3c2443-clock.h>
+
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
+#include <plat/s3c2416.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/sdhci.h>
+#include <plat/pm.h>
+
+#include <plat/iic-core.h>
+#include <plat/fb-core.h>
+#include <plat/nand-core.h>
+#include <plat/adc-core.h>
+#include <plat/rtc-core.h>
+
+static struct map_desc s3c2416_iodesc[] __initdata = {
+	IODESC_ENT(WATCHDOG),
+	IODESC_ENT(CLKPWR),
+	IODESC_ENT(TIMER),
+};
+
+struct bus_type s3c2416_subsys = {
+	.name = "s3c2416-core",
+	.dev_name = "s3c2416-core",
+};
+
+static struct device s3c2416_dev = {
+	.bus		= &s3c2416_subsys,
+};
+
+void s3c2416_restart(char mode, const char *cmd)
+{
+	if (mode == 's')
+		soft_restart(0);
+
+	__raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST);
+}
+
+int __init s3c2416_init(void)
+{
+	printk(KERN_INFO "S3C2416: Initializing architecture\n");
+
+	/* change WDT IRQ number */
+	s3c_device_wdt.resource[1].start = IRQ_S3C2443_WDT;
+	s3c_device_wdt.resource[1].end   = IRQ_S3C2443_WDT;
+
+	/* the i2c devices are directly compatible with s3c2440 */
+	s3c_i2c0_setname("s3c2440-i2c");
+	s3c_i2c1_setname("s3c2440-i2c");
+
+	s3c_fb_setname("s3c2443-fb");
+
+	s3c_adc_setname("s3c2416-adc");
+	s3c_rtc_setname("s3c2416-rtc");
+
+#ifdef CONFIG_PM
+	register_syscore_ops(&s3c2416_pm_syscore_ops);
+#endif
+	register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
+	return device_register(&s3c2416_dev);
+}
+
+void __init s3c2416_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+	s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
+
+	s3c_nand_setname("s3c2412-nand");
+}
+
+/* s3c2416_map_io
+ *
+ * register the standard cpu IO areas, and any passed in from the
+ * machine specific initialisation.
+ */
+
+void __init s3c2416_map_io(void)
+{
+	s3c24xx_gpiocfg_default.set_pull = samsung_gpio_setpull_updown;
+	s3c24xx_gpiocfg_default.get_pull = samsung_gpio_getpull_updown;
+
+	/* initialize device information early */
+	s3c2416_default_sdhci0();
+	s3c2416_default_sdhci1();
+
+	iotable_init(s3c2416_iodesc, ARRAY_SIZE(s3c2416_iodesc));
+}
+
+/* need to register the subsystem before we actually register the device, and
+ * we also need to ensure that it has been initialised before any of the
+ * drivers even try to use it (even if not on an s3c2416 based system)
+ * as a driver which may support both 2443 and 2440 may try and use it.
+*/
+
+static int __init s3c2416_core_init(void)
+{
+	return subsys_system_register(&s3c2416_subsys, NULL);
+}
+
+core_initcall(s3c2416_core_init);
diff --git a/arch/arm/mach-s3c2440/s3c2440.c b/arch/arm/mach-s3c24xx/s3c2440.c
similarity index 100%
rename from arch/arm/mach-s3c2440/s3c2440.c
rename to arch/arm/mach-s3c24xx/s3c2440.c
diff --git a/arch/arm/mach-s3c2440/s3c2442.c b/arch/arm/mach-s3c24xx/s3c2442.c
similarity index 100%
rename from arch/arm/mach-s3c2440/s3c2442.c
rename to arch/arm/mach-s3c24xx/s3c2442.c
diff --git a/arch/arm/mach-s3c24xx/s3c2443.c b/arch/arm/mach-s3c24xx/s3c2443.c
new file mode 100644
index 0000000..ab648ad
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/s3c2443.c
@@ -0,0 +1,117 @@
+/* linux/arch/arm/mach-s3c2443/s3c2443.c
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C2443 Mobile CPU support
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/system_misc.h>
+
+#include <mach/regs-s3c2443-clock.h>
+
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
+#include <plat/s3c2443.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/fb-core.h>
+#include <plat/nand-core.h>
+#include <plat/adc-core.h>
+#include <plat/rtc-core.h>
+
+static struct map_desc s3c2443_iodesc[] __initdata = {
+	IODESC_ENT(WATCHDOG),
+	IODESC_ENT(CLKPWR),
+	IODESC_ENT(TIMER),
+};
+
+struct bus_type s3c2443_subsys = {
+	.name = "s3c2443-core",
+	.dev_name = "s3c2443-core",
+};
+
+static struct device s3c2443_dev = {
+	.bus		= &s3c2443_subsys,
+};
+
+void s3c2443_restart(char mode, const char *cmd)
+{
+	if (mode == 's')
+		soft_restart(0);
+
+	__raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST);
+}
+
+int __init s3c2443_init(void)
+{
+	printk("S3C2443: Initialising architecture\n");
+
+	s3c_nand_setname("s3c2412-nand");
+	s3c_fb_setname("s3c2443-fb");
+
+	s3c_adc_setname("s3c2443-adc");
+	s3c_rtc_setname("s3c2443-rtc");
+
+	/* change WDT IRQ number */
+	s3c_device_wdt.resource[1].start = IRQ_S3C2443_WDT;
+	s3c_device_wdt.resource[1].end   = IRQ_S3C2443_WDT;
+
+	return device_register(&s3c2443_dev);
+}
+
+void __init s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+	s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
+}
+
+/* s3c2443_map_io
+ *
+ * register the standard cpu IO areas, and any passed in from the
+ * machine specific initialisation.
+ */
+
+void __init s3c2443_map_io(void)
+{
+	s3c24xx_gpiocfg_default.set_pull = s3c2443_gpio_setpull;
+	s3c24xx_gpiocfg_default.get_pull = s3c2443_gpio_getpull;
+
+	iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc));
+}
+
+/* need to register the subsystem before we actually register the device, and
+ * we also need to ensure that it has been initialised before any of the
+ * drivers even try to use it (even if not on an s3c2443 based system)
+ * as a driver which may support both 2443 and 2440 may try and use it.
+*/
+
+static int __init s3c2443_core_init(void)
+{
+	return subsys_system_register(&s3c2443_subsys, NULL);
+}
+
+core_initcall(s3c2443_core_init);
diff --git a/arch/arm/mach-s3c24xx/s3c244x.c b/arch/arm/mach-s3c24xx/s3c244x.c
new file mode 100644
index 0000000..6f74118
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/s3c244x.c
@@ -0,0 +1,211 @@
+/* linux/arch/arm/plat-s3c24xx/s3c244x.c
+ *
+ * Copyright (c) 2004-2006 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C2440 and S3C2442 Mobile CPU support (not S3C2443)
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/syscore_ops.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/system_misc.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <plat/cpu-freq.h>
+
+#include <mach/regs-clock.h>
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-gpioj.h>
+#include <mach/regs-dsc.h>
+
+#include <plat/s3c2410.h>
+#include <plat/s3c244x.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/pll.h>
+#include <plat/nand-core.h>
+#include <plat/watchdog-reset.h>
+
+static struct map_desc s3c244x_iodesc[] __initdata = {
+	IODESC_ENT(CLKPWR),
+	IODESC_ENT(TIMER),
+	IODESC_ENT(WATCHDOG),
+};
+
+/* uart initialisation */
+
+void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+	s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
+}
+
+void __init s3c244x_map_io(void)
+{
+	/* register our io-tables */
+
+	iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
+
+	/* rename any peripherals used differing from the s3c2410 */
+
+	s3c_device_sdi.name  = "s3c2440-sdi";
+	s3c_device_i2c0.name  = "s3c2440-i2c";
+	s3c_nand_setname("s3c2440-nand");
+	s3c_device_ts.name = "s3c2440-ts";
+	s3c_device_usbgadget.name = "s3c2440-usbgadget";
+}
+
+void __init_or_cpufreq s3c244x_setup_clocks(void)
+{
+	struct clk *xtal_clk;
+	unsigned long clkdiv;
+	unsigned long camdiv;
+	unsigned long xtal;
+	unsigned long hclk, fclk, pclk;
+	int hdiv = 1;
+
+	xtal_clk = clk_get(NULL, "xtal");
+	xtal = clk_get_rate(xtal_clk);
+	clk_put(xtal_clk);
+
+	fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
+
+	clkdiv = __raw_readl(S3C2410_CLKDIVN);
+	camdiv = __raw_readl(S3C2440_CAMDIVN);
+
+	/* work out clock scalings */
+
+	switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
+	case S3C2440_CLKDIVN_HDIVN_1:
+		hdiv = 1;
+		break;
+
+	case S3C2440_CLKDIVN_HDIVN_2:
+		hdiv = 2;
+		break;
+
+	case S3C2440_CLKDIVN_HDIVN_4_8:
+		hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
+		break;
+
+	case S3C2440_CLKDIVN_HDIVN_3_6:
+		hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
+		break;
+	}
+
+	hclk = fclk / hdiv;
+	pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN) ? 2 : 1);
+
+	/* print brief summary of clocks, etc */
+
+	printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
+	       print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
+
+	s3c24xx_setup_clocks(fclk, hclk, pclk);
+}
+
+void __init s3c244x_init_clocks(int xtal)
+{
+	/* initialise the clocks here, to allow other things like the
+	 * console to use them, and to add new ones after the initialisation
+	 */
+
+	s3c24xx_register_baseclocks(xtal);
+	s3c244x_setup_clocks();
+	s3c2410_baseclk_add();
+}
+
+/* Since the S3C2442 and S3C2440 share items, put both subsystems here */
+
+struct bus_type s3c2440_subsys = {
+	.name		= "s3c2440-core",
+	.dev_name	= "s3c2440-core",
+};
+
+struct bus_type s3c2442_subsys = {
+	.name		= "s3c2442-core",
+	.dev_name	= "s3c2442-core",
+};
+
+/* need to register the subsystem before we actually register the device, and
+ * we also need to ensure that it has been initialised before any of the
+ * drivers even try to use it (even if not on an s3c2440 based system)
+ * as a driver which may support both 2410 and 2440 may try and use it.
+*/
+
+static int __init s3c2440_core_init(void)
+{
+	return subsys_system_register(&s3c2440_subsys, NULL);
+}
+
+core_initcall(s3c2440_core_init);
+
+static int __init s3c2442_core_init(void)
+{
+	return subsys_system_register(&s3c2442_subsys, NULL);
+}
+
+core_initcall(s3c2442_core_init);
+
+
+#ifdef CONFIG_PM
+static struct sleep_save s3c244x_sleep[] = {
+	SAVE_ITEM(S3C2440_DSC0),
+	SAVE_ITEM(S3C2440_DSC1),
+	SAVE_ITEM(S3C2440_GPJDAT),
+	SAVE_ITEM(S3C2440_GPJCON),
+	SAVE_ITEM(S3C2440_GPJUP)
+};
+
+static int s3c244x_suspend(void)
+{
+	s3c_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
+	return 0;
+}
+
+static void s3c244x_resume(void)
+{
+	s3c_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
+}
+#else
+#define s3c244x_suspend NULL
+#define s3c244x_resume  NULL
+#endif
+
+struct syscore_ops s3c244x_pm_syscore_ops = {
+	.suspend	= s3c244x_suspend,
+	.resume		= s3c244x_resume,
+};
+
+void s3c244x_restart(char mode, const char *cmd)
+{
+	if (mode == 's')
+		soft_restart(0);
+
+	arch_wdt_reset();
+
+	/* we'll take a jump through zero as a poor second */
+	soft_restart(0);
+}
diff --git a/arch/arm/plat-s3c24xx/setup-i2c.c b/arch/arm/mach-s3c24xx/setup-i2c.c
similarity index 100%
rename from arch/arm/plat-s3c24xx/setup-i2c.c
rename to arch/arm/mach-s3c24xx/setup-i2c.c
diff --git a/arch/arm/mach-s3c2416/setup-sdhci-gpio.c b/arch/arm/mach-s3c24xx/setup-sdhci-gpio.c
similarity index 100%
rename from arch/arm/mach-s3c2416/setup-sdhci-gpio.c
rename to arch/arm/mach-s3c24xx/setup-sdhci-gpio.c
diff --git a/arch/arm/plat-s3c24xx/setup-ts.c b/arch/arm/mach-s3c24xx/setup-ts.c
similarity index 100%
rename from arch/arm/plat-s3c24xx/setup-ts.c
rename to arch/arm/mach-s3c24xx/setup-ts.c
diff --git a/arch/arm/mach-s3c24xx/simtec-audio.c b/arch/arm/mach-s3c24xx/simtec-audio.c
new file mode 100644
index 0000000..11881c9
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/simtec-audio.c
@@ -0,0 +1,79 @@
+/* linux/arch/arm/plat-s3c24xx/simtec-audio.c
+ *
+ * Copyright (c) 2009 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * Audio setup for various Simtec S3C24XX implementations
+ *
+ * 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/interrupt.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include <mach/bast-map.h>
+#include <mach/bast-irq.h>
+#include <mach/bast-cpld.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/audio-simtec.h>
+#include <plat/devs.h>
+
+#include "simtec.h"
+
+/* platform ops for audio */
+
+static void simtec_audio_startup_lrroute(void)
+{
+	unsigned int tmp;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	tmp = __raw_readb(BAST_VA_CTRL1);
+	tmp &= ~BAST_CPLD_CTRL1_LRMASK;
+	tmp |= BAST_CPLD_CTRL1_LRCDAC;
+	__raw_writeb(tmp, BAST_VA_CTRL1);
+
+	local_irq_restore(flags);
+}
+
+static struct s3c24xx_audio_simtec_pdata simtec_audio_platdata;
+static char our_name[32];
+
+static struct platform_device simtec_audio_dev = {
+	.name	= our_name,
+	.id	= -1,
+	.dev	= {
+		.parent		= &s3c_device_iis.dev,
+		.platform_data	= &simtec_audio_platdata,
+	},
+};
+
+int __init simtec_audio_add(const char *name, bool has_lr_routing,
+			    struct s3c24xx_audio_simtec_pdata *spd)
+{
+	if (!name)
+		name = "tlv320aic23";
+
+	snprintf(our_name, sizeof(our_name)-1, "s3c24xx-simtec-%s", name);
+
+	/* copy platform data so the source can be __initdata */
+	if (spd)
+		simtec_audio_platdata = *spd;
+
+	if (has_lr_routing)
+		simtec_audio_platdata.startup = simtec_audio_startup_lrroute;
+
+	platform_device_register(&s3c_device_iis);
+	platform_device_register(&simtec_audio_dev);
+	return 0;
+}
diff --git a/arch/arm/mach-s3c24xx/simtec-nor.c b/arch/arm/mach-s3c24xx/simtec-nor.c
new file mode 100644
index 0000000..b9d6d4f
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/simtec-nor.c
@@ -0,0 +1,84 @@
+/* linux/arch/arm/mach-s3c2410/nor-simtec.c
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * Simtec NOR mapping
+ *
+ * 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/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/map.h>
+#include <mach/bast-map.h>
+#include <mach/bast-cpld.h>
+
+#include "simtec.h"
+
+static void simtec_nor_vpp(struct platform_device *pdev, int vpp)
+{
+	unsigned int val;
+
+	val = __raw_readb(BAST_VA_CTRL3);
+
+	printk(KERN_DEBUG "%s(%d)\n", __func__, vpp);
+
+	if (vpp)
+		val |= BAST_CPLD_CTRL3_ROMWEN;
+	else
+		val &= ~BAST_CPLD_CTRL3_ROMWEN;
+
+	__raw_writeb(val, BAST_VA_CTRL3);
+}
+
+static struct physmap_flash_data simtec_nor_pdata = {
+	.width		= 2,
+	.set_vpp	= simtec_nor_vpp,
+	.nr_parts	= 0,
+};
+
+static struct resource simtec_nor_resource[] = {
+	[0] = {
+		.start = S3C2410_CS1 + 0x4000000,
+		.end   = S3C2410_CS1 + 0x4000000 + SZ_8M - 1,
+		.flags = IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device simtec_device_nor = {
+	.name		= "physmap-flash",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(simtec_nor_resource),
+	.resource	= simtec_nor_resource,
+	.dev		= {
+		.platform_data = &simtec_nor_pdata,
+	},
+};
+
+void __init nor_simtec_init(void)
+{
+	int ret;
+
+	ret = platform_device_register(&simtec_device_nor);
+	if (ret < 0)
+		printk(KERN_ERR "failed to register physmap-flash device\n");
+	else
+		simtec_nor_vpp(NULL, 1);
+}
diff --git a/arch/arm/plat-s3c24xx/pm-simtec.c b/arch/arm/mach-s3c24xx/simtec-pm.c
similarity index 100%
rename from arch/arm/plat-s3c24xx/pm-simtec.c
rename to arch/arm/mach-s3c24xx/simtec-pm.c
diff --git a/arch/arm/mach-s3c24xx/simtec-usb.c b/arch/arm/mach-s3c24xx/simtec-usb.c
new file mode 100644
index 0000000..d91c1a7
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/simtec-usb.c
@@ -0,0 +1,132 @@
+/* linux/arch/arm/mach-s3c2410/usb-simtec.c
+ *
+ * Copyright 2004-2005 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.simtec.co.uk/products/EB2410ITX/
+ *
+ * Simtec BAST and Thorcom VR1000 USB port support functions
+ *
+ * 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 DEBUG
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/gpio.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/bast-map.h>
+#include <mach/bast-irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <plat/usb-control.h>
+#include <plat/devs.h>
+
+#include "simtec.h"
+
+/* control power and monitor over-current events on various Simtec
+ * designed boards.
+*/
+
+static unsigned int power_state[2];
+
+static void
+usb_simtec_powercontrol(int port, int to)
+{
+	pr_debug("usb_simtec_powercontrol(%d,%d)\n", port, to);
+
+	power_state[port] = to;
+
+	if (power_state[0] && power_state[1])
+		gpio_set_value(S3C2410_GPB(4), 0);
+	else
+		gpio_set_value(S3C2410_GPB(4), 1);
+}
+
+static irqreturn_t
+usb_simtec_ocirq(int irq, void *pw)
+{
+	struct s3c2410_hcd_info *info = pw;
+
+	if (gpio_get_value(S3C2410_GPG(10)) == 0) {
+		pr_debug("usb_simtec: over-current irq (oc detected)\n");
+		s3c2410_usb_report_oc(info, 3);
+	} else {
+		pr_debug("usb_simtec: over-current irq (oc cleared)\n");
+		s3c2410_usb_report_oc(info, 0);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on)
+{
+	int ret;
+
+	if (on) {
+		ret = request_irq(IRQ_USBOC, usb_simtec_ocirq,
+				  IRQF_DISABLED | IRQF_TRIGGER_RISING |
+				   IRQF_TRIGGER_FALLING,
+				  "USB Over-current", info);
+		if (ret != 0) {
+			printk(KERN_ERR "failed to request usb oc irq\n");
+		}
+	} else {
+		free_irq(IRQ_USBOC, info);
+	}
+}
+
+static struct s3c2410_hcd_info usb_simtec_info __initdata = {
+	.port[0]	= {
+		.flags	= S3C_HCDFLG_USED
+	},
+	.port[1]	= {
+		.flags	= S3C_HCDFLG_USED
+	},
+
+	.power_control	= usb_simtec_powercontrol,
+	.enable_oc	= usb_simtec_enableoc,
+};
+
+
+int usb_simtec_init(void)
+{
+	int ret;
+
+	printk("USB Power Control, Copyright 2004 Simtec Electronics\n");
+
+	ret = gpio_request(S3C2410_GPB(4), "USB power control");
+	if (ret < 0) {
+		pr_err("%s: failed to get GPB4\n", __func__);
+		return ret;
+	}
+
+	ret = gpio_request(S3C2410_GPG(10), "USB overcurrent");
+	if (ret < 0) {
+		pr_err("%s: failed to get GPG10\n", __func__);
+		gpio_free(S3C2410_GPB(4));
+		return ret;
+	}
+
+	/* turn power on */
+	gpio_direction_output(S3C2410_GPB(4), 1);
+	gpio_direction_input(S3C2410_GPG(10));
+
+	s3c_ohci_set_platdata(&usb_simtec_info);
+	return 0;
+}
diff --git a/arch/arm/mach-s3c24xx/simtec.h b/arch/arm/mach-s3c24xx/simtec.h
new file mode 100644
index 0000000..ae8f4f9
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/simtec.h
@@ -0,0 +1,21 @@
+/* linux/arch/arm/mach-s3c2410/nor-simtec.h
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * Simtec common functions
+ *
+ * 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 s3c24xx_audio_simtec_pdata;
+
+extern void nor_simtec_init(void);
+
+extern int usb_simtec_init(void);
+
+extern int simtec_audio_add(const char *codec_name, bool has_lr_routing,
+			    struct s3c24xx_audio_simtec_pdata *pdata);
diff --git a/arch/arm/mach-s3c2410/sleep.S b/arch/arm/mach-s3c24xx/sleep-s3c2410.S
similarity index 100%
rename from arch/arm/mach-s3c2410/sleep.S
rename to arch/arm/mach-s3c24xx/sleep-s3c2410.S
diff --git a/arch/arm/mach-s3c2412/sleep.S b/arch/arm/mach-s3c24xx/sleep-s3c2412.S
similarity index 100%
rename from arch/arm/mach-s3c2412/sleep.S
rename to arch/arm/mach-s3c24xx/sleep-s3c2412.S
diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig
index dd20c66..82c0915 100644
--- a/arch/arm/mach-s3c64xx/Kconfig
+++ b/arch/arm/mach-s3c64xx/Kconfig
@@ -83,6 +83,11 @@
 	help
 	 Common setup code for SPI GPIO configurations
 
+config S3C64XX_SETUP_USB_PHY
+	bool
+	help
+	  Common setup code for USB PHY controller
+
 # S36400 Macchine support
 
 config MACH_SMDK6400
@@ -157,6 +162,7 @@
 	select S3C64XX_SETUP_IDE
 	select S3C64XX_SETUP_FB_24BPP
 	select S3C64XX_SETUP_KEYPAD
+	select S3C64XX_SETUP_USB_PHY
 	help
 	  Machine support for the Samsung SMDK6410
 
@@ -256,6 +262,7 @@
 	select S3C_DEV_USB_HOST
 	select S3C64XX_SETUP_SDHCI
 	select S3C64XX_SETUP_FB_24BPP
+	select S3C64XX_SETUP_USB_PHY
 	select SAMSUNG_DEV_ADC
 	select SAMSUNG_DEV_PWM
 	select SAMSUNG_DEV_TS
@@ -283,6 +290,7 @@
 	select S3C64XX_SETUP_FB_24BPP
 	select S3C64XX_SETUP_KEYPAD
 	select S3C64XX_SETUP_SPI
+	select S3C64XX_SETUP_USB_PHY
 	select SAMSUNG_DEV_ADC
 	select SAMSUNG_DEV_KEYPAD
 	select S3C_DEV_USB_HOST
@@ -296,5 +304,6 @@
 	select S3C64XX_DEV_SPI0
 	select SAMSUNG_GPIO_EXTRA128
 	select I2C
+	select LEDS_GPIO_REGISTER
 	help
 	  Machine support for the Wolfson Cragganmore S3C6410 variant.
diff --git a/arch/arm/mach-s3c64xx/Makefile b/arch/arm/mach-s3c64xx/Makefile
index 1822ac2..f9ce1dc 100644
--- a/arch/arm/mach-s3c64xx/Makefile
+++ b/arch/arm/mach-s3c64xx/Makefile
@@ -22,6 +22,7 @@
 # PM
 
 obj-$(CONFIG_PM)		+= pm.o irq-pm.o sleep.o
+obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 
 # DMA support
 
@@ -42,6 +43,7 @@
 obj-$(CONFIG_S3C64XX_SETUP_KEYPAD)	+= setup-keypad.o
 obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO)	+= setup-sdhci-gpio.o
 obj-$(CONFIG_S3C64XX_SETUP_SPI)		+= setup-spi.o
+obj-$(CONFIG_S3C64XX_SETUP_USB_PHY) += setup-usb-phy.o
 
 # Machine support
 
diff --git a/arch/arm/mach-s3c64xx/clock.c b/arch/arm/mach-s3c64xx/clock.c
index aebbcc2..52f079a 100644
--- a/arch/arm/mach-s3c64xx/clock.c
+++ b/arch/arm/mach-s3c64xx/clock.c
@@ -207,6 +207,15 @@
 		.enable		= s3c64xx_sclk_ctrl,
 		.ctrlbit	= S3C_CLKCON_SCLK_MMC2_48,
 	}, {
+		.name		= "ac97",
+		.parent		= &clk_p,
+		.ctrlbit	= S3C_CLKCON_PCLK_AC97,
+	}, {
+		.name		= "cfcon",
+		.parent		= &clk_h,
+		.enable		= s3c64xx_hclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_HCLK_IHOST,
+	}, {
 		.name		= "dma0",
 		.parent		= &clk_h,
 		.enable		= s3c64xx_hclk_ctrl,
@@ -216,6 +225,107 @@
 		.parent		= &clk_h,
 		.enable		= s3c64xx_hclk_ctrl,
 		.ctrlbit	= S3C_CLKCON_HCLK_DMA1,
+	}, {
+		.name		= "3dse",
+		.parent		= &clk_h,
+		.enable		= s3c64xx_hclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_HCLK_3DSE,
+	}, {
+		.name		= "hclk_secur",
+		.parent		= &clk_h,
+		.enable		= s3c64xx_hclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_HCLK_SECUR,
+	}, {
+		.name		= "sdma1",
+		.parent		= &clk_h,
+		.enable		= s3c64xx_hclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_HCLK_SDMA1,
+	}, {
+		.name		= "sdma0",
+		.parent		= &clk_h,
+		.enable		= s3c64xx_hclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_HCLK_SDMA0,
+	}, {
+		.name		= "hclk_jpeg",
+		.parent		= &clk_h,
+		.enable		= s3c64xx_hclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_HCLK_JPEG,
+	}, {
+		.name		= "camif",
+		.parent		= &clk_h,
+		.enable		= s3c64xx_hclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_HCLK_CAMIF,
+	}, {
+		.name		= "hclk_scaler",
+		.parent		= &clk_h,
+		.enable		= s3c64xx_hclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_HCLK_SCALER,
+	}, {
+		.name		= "2d",
+		.parent		= &clk_h,
+		.enable		= s3c64xx_hclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_HCLK_2D,
+	}, {
+		.name		= "tv",
+		.parent		= &clk_h,
+		.enable		= s3c64xx_hclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_HCLK_TV,
+	}, {
+		.name		= "post0",
+		.parent		= &clk_h,
+		.enable		= s3c64xx_hclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_HCLK_POST0,
+	}, {
+		.name		= "rot",
+		.parent		= &clk_h,
+		.enable		= s3c64xx_hclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_HCLK_ROT,
+	}, {
+		.name		= "hclk_mfc",
+		.parent		= &clk_h,
+		.enable		= s3c64xx_hclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_HCLK_MFC,
+	}, {
+		.name		= "pclk_mfc",
+		.parent		= &clk_p,
+		.enable		= s3c64xx_pclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_PCLK_MFC,
+	}, {
+		.name		= "dac27",
+		.enable		= s3c64xx_sclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_SCLK_DAC27,
+	}, {
+		.name		= "tv27",
+		.enable		= s3c64xx_sclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_SCLK_TV27,
+	}, {
+		.name		= "scaler27",
+		.enable		= s3c64xx_sclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_SCLK_SCALER27,
+	}, {
+		.name		= "sclk_scaler",
+		.enable		= s3c64xx_sclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_SCLK_SCALER,
+	}, {
+		.name		= "post0_27",
+		.enable		= s3c64xx_sclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_SCLK_POST0_27,
+	}, {
+		.name		= "secur",
+		.enable		= s3c64xx_sclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_SCLK_SECUR,
+	}, {
+		.name		= "sclk_mfc",
+		.enable		= s3c64xx_sclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_SCLK_MFC,
+	}, {
+		.name		= "cam",
+		.enable		= s3c64xx_sclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_SCLK_CAM,
+	}, {
+		.name		= "sclk_jpeg",
+		.enable		= s3c64xx_sclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_SCLK_JPEG,
 	},
 };
 
@@ -289,16 +399,7 @@
 		.name		= "watchdog",
 		.parent		= &clk_p,
 		.ctrlbit	= S3C_CLKCON_PCLK_WDT,
-	}, {
-		.name		= "ac97",
-		.parent		= &clk_p,
-		.ctrlbit	= S3C_CLKCON_PCLK_AC97,
-	}, {
-		.name		= "cfcon",
-		.parent		= &clk_h,
-		.enable		= s3c64xx_hclk_ctrl,
-		.ctrlbit	= S3C_CLKCON_HCLK_IHOST,
-	}
+	},
 };
 
 static struct clk clk_hsmmc0 = {
diff --git a/arch/arm/mach-s3c64xx/common.c b/arch/arm/mach-s3c64xx/common.c
index bee7dcd..b313380 100644
--- a/arch/arm/mach-s3c64xx/common.c
+++ b/arch/arm/mach-s3c64xx/common.c
@@ -29,6 +29,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/hardware/vic.h>
+#include <asm/system_misc.h>
 
 #include <mach/map.h>
 #include <mach/hardware.h>
diff --git a/arch/arm/mach-s3c64xx/common.h b/arch/arm/mach-s3c64xx/common.h
index 5eb9c9a..7a10be6 100644
--- a/arch/arm/mach-s3c64xx/common.h
+++ b/arch/arm/mach-s3c64xx/common.h
@@ -25,8 +25,6 @@
 
 void s3c64xx_restart(char mode, const char *cmd);
 
-extern struct syscore_ops s3c64xx_irq_syscore_ops;
-
 #ifdef CONFIG_CPU_S3C6400
 
 extern  int s3c6400_init(void);
diff --git a/arch/arm/mach-s3c64xx/cpuidle.c b/arch/arm/mach-s3c64xx/cpuidle.c
new file mode 100644
index 0000000..179460f
--- /dev/null
+++ b/arch/arm/mach-s3c64xx/cpuidle.c
@@ -0,0 +1,91 @@
+/* linux/arch/arm/mach-s3c64xx/cpuidle.c
+ *
+ * Copyright (c) 2011 Wolfson Microelectronics, plc
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.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/kernel.h>
+#include <linux/init.h>
+#include <linux/cpuidle.h>
+#include <linux/io.h>
+#include <linux/export.h>
+#include <linux/time.h>
+
+#include <asm/proc-fns.h>
+
+#include <mach/map.h>
+
+#include <mach/regs-sys.h>
+#include <mach/regs-syscon-power.h>
+
+static int s3c64xx_enter_idle(struct cpuidle_device *dev,
+			      struct cpuidle_driver *drv,
+			      int index)
+{
+	struct timeval before, after;
+	unsigned long tmp;
+	int idle_time;
+
+	local_irq_disable();
+	do_gettimeofday(&before);
+
+	/* Setup PWRCFG to enter idle mode */
+	tmp = __raw_readl(S3C64XX_PWR_CFG);
+	tmp &= ~S3C64XX_PWRCFG_CFG_WFI_MASK;
+	tmp |= S3C64XX_PWRCFG_CFG_WFI_IDLE;
+	__raw_writel(tmp, S3C64XX_PWR_CFG);
+
+	cpu_do_idle();
+
+	do_gettimeofday(&after);
+	local_irq_enable();
+	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
+		    (after.tv_usec - before.tv_usec);
+
+	dev->last_residency = idle_time;
+	return index;
+}
+
+static struct cpuidle_state s3c64xx_cpuidle_set[] = {
+	[0] = {
+		.enter			= s3c64xx_enter_idle,
+		.exit_latency		= 1,
+		.target_residency	= 1,
+		.flags			= CPUIDLE_FLAG_TIME_VALID,
+		.name			= "IDLE",
+		.desc			= "System active, ARM gated",
+	},
+};
+
+static struct cpuidle_driver s3c64xx_cpuidle_driver = {
+	.name		= "s3c64xx_cpuidle",
+	.owner		= THIS_MODULE,
+	.state_count	= ARRAY_SIZE(s3c64xx_cpuidle_set),
+};
+
+static struct cpuidle_device s3c64xx_cpuidle_device = {
+	.state_count	= ARRAY_SIZE(s3c64xx_cpuidle_set),
+};
+
+static int __init s3c64xx_init_cpuidle(void)
+{
+	int ret;
+
+	memcpy(s3c64xx_cpuidle_driver.states, s3c64xx_cpuidle_set,
+	       sizeof(s3c64xx_cpuidle_set));
+	cpuidle_register_driver(&s3c64xx_cpuidle_driver);
+
+	ret = cpuidle_register_device(&s3c64xx_cpuidle_device);
+	if (ret) {
+		pr_err("Failed to register cpuidle device: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+device_initcall(s3c64xx_init_cpuidle);
diff --git a/arch/arm/mach-s3c64xx/include/mach/entry-macro.S b/arch/arm/mach-s3c64xx/include/mach/entry-macro.S
deleted file mode 100644
index dc2bc15..0000000
--- a/arch/arm/mach-s3c64xx/include/mach/entry-macro.S
+++ /dev/null
@@ -1,19 +0,0 @@
-/* arch/arm/mach-s3c6400/include/mach/entry-macro.S
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *	http://armlinux.simtec.co.uk/
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * Low-level IRQ helper macros for the Samsung S3C64XX series
- *
- * 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.
-*/
-
-		.macro  disable_fiq
-		.endm
-
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
diff --git a/arch/arm/mach-s3c64xx/include/mach/io.h b/arch/arm/mach-s3c64xx/include/mach/io.h
deleted file mode 100644
index de5716db..0000000
--- a/arch/arm/mach-s3c64xx/include/mach/io.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* arch/arm/mach-s3c64xxinclude/mach/io.h
- *
- * Copyright 2008 Simtec Electronics
- *	Ben Dooks <ben-linux@fluff.org>
- *
- * Default IO routines for S3C64XX based
- */
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/* No current ISA/PCI bus support. */
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#define IO_SPACE_LIMIT (0xFFFFFFFF)
-
-#endif
diff --git a/arch/arm/mach-s3c64xx/include/mach/system.h b/arch/arm/mach-s3c64xx/include/mach/system.h
deleted file mode 100644
index 353ed43..0000000
--- a/arch/arm/mach-s3c64xx/include/mach/system.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* linux/arch/arm/mach-s3c6400/include/mach/system.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *      Ben Dooks <ben@simtec.co.uk>
- *      http://armlinux.simtec.co.uk/
- *
- * S3C6400 - system implementation
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H __FILE__
-
-static void arch_idle(void)
-{
-	/* nothing here yet */
-}
-
-#endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-s3c64xx/irq-pm.c b/arch/arm/mach-s3c64xx/irq-pm.c
index 8bec61e..0c7e1d9 100644
--- a/arch/arm/mach-s3c64xx/irq-pm.c
+++ b/arch/arm/mach-s3c64xx/irq-pm.c
@@ -96,7 +96,7 @@
 	S3C_PMDBG("%s: IRQ configuration restored\n", __func__);
 }
 
-struct syscore_ops s3c64xx_irq_syscore_ops = {
+static struct syscore_ops s3c64xx_irq_syscore_ops = {
 	.suspend = s3c64xx_irq_pm_suspend,
 	.resume	 = s3c64xx_irq_pm_resume,
 };
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/arch/arm/mach-s3c64xx/mach-crag6410-module.c
index cd3c97e..0ace108 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410-module.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410-module.c
@@ -11,18 +11,38 @@
 #include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
+#include <linux/spi/spi.h>
 
 #include <linux/mfd/wm831x/irq.h>
 #include <linux/mfd/wm831x/gpio.h>
 #include <linux/mfd/wm8994/pdata.h>
 
+#include <linux/regulator/machine.h>
+
 #include <sound/wm5100.h>
 #include <sound/wm8996.h>
 #include <sound/wm8962.h>
 #include <sound/wm9081.h>
 
+#include <plat/s3c64xx-spi.h>
+
 #include <mach/crag6410.h>
 
+static struct s3c64xx_spi_csinfo wm0010_spi_csinfo = {
+	.set_level = gpio_set_value,
+	.line = S3C64XX_GPC(3),
+};
+
+static struct spi_board_info wm1253_devs[] = {
+	[0] = {
+		.modalias	= "wm0010",
+		.bus_num	= 0,
+		.chip_select	= 0,
+		.mode		= SPI_MODE_0,
+		.controller_data = &wm0010_spi_csinfo,
+	},
+};
+
 static struct wm5100_pdata wm5100_pdata = {
 	.ldo_ena = S3C64XX_GPN(7),
 	.irq_flags = IRQF_TRIGGER_HIGH,
@@ -102,6 +122,7 @@
 		0x8000 | WM8962_GPIO_FN_DMICDAT,
 		WM8962_GPIO_FN_IRQ,    /* Open drain mode */
 	},
+	.in4_dc_measure = true,
 };
 
 static struct wm9081_pdata wm9081_pdata __initdata = {
@@ -134,6 +155,14 @@
 	},
 };
 
+static struct regulator_init_data wm8994_ldo1 = {
+	.supply_regulator = "WALLVDD",
+};
+
+static struct regulator_init_data wm8994_ldo2 = {
+	.supply_regulator = "WALLVDD",
+};
+
 static struct wm8994_pdata wm8994_pdata = {
 	.gpio_base = CODEC_GPIO_BASE,
 	.gpio_defaults = {
@@ -141,8 +170,8 @@
 	},
 	.irq_base = CODEC_IRQ_BASE,
 	.ldo = {
-		{ .supply = "WALLVDD" },
-		{ .supply = "WALLVDD" },
+		 { .init_data = &wm8994_ldo1, },
+		 { .init_data = &wm8994_ldo2, },
 	},
 };
 
@@ -158,14 +187,21 @@
 	const char *name;
 	const struct i2c_board_info *i2c_devs;
 	int num_i2c_devs;
+	const struct spi_board_info *spi_devs;
+	int num_spi_devs;
 } gf_mods[] = {
 	{ .id = 0x01, .name = "1250-EV1 Springbank" },
 	{ .id = 0x02, .name = "1251-EV1 Jura" },
 	{ .id = 0x03, .name = "1252-EV1 Glenlivet" },
 	{ .id = 0x11, .name = "6249-EV2 Glenfarclas", },
+	{ .id = 0x14, .name = "6271-EV1 Lochnagar" },
+	{ .id = 0x15, .name = "XXXX-EV1 Bells" },
 	{ .id = 0x21, .name = "1275-EV1 Mortlach" },
 	{ .id = 0x25, .name = "1274-EV1 Glencadam" },
-	{ .id = 0x31, .name = "1253-EV1 Tomatin", },
+	{ .id = 0x31, .name = "1253-EV1 Tomatin",
+	  .spi_devs = wm1253_devs, .num_spi_devs = ARRAY_SIZE(wm1253_devs) },
+	{ .id = 0x32, .name = "XXXX-EV1 Caol Illa" },
+	{ .id = 0x33, .name = "XXXX-EV1 Oban" },
 	{ .id = 0x39, .name = "1254-EV1 Dallas Dhu",
 	  .i2c_devs = wm1254_devs, .num_i2c_devs = ARRAY_SIZE(wm1254_devs) },
 	{ .id = 0x3a, .name = "1259-EV1 Tobermory",
@@ -197,12 +233,16 @@
 	if (i < ARRAY_SIZE(gf_mods)) {
 		dev_info(&i2c->dev, "%s revision %d\n",
 			 gf_mods[i].name, rev + 1);
+
 		for (j = 0; j < gf_mods[i].num_i2c_devs; j++) {
 			if (!i2c_new_device(i2c->adapter,
 					    &(gf_mods[i].i2c_devs[j])))
 				dev_err(&i2c->dev,
 					"Failed to register dev: %d\n", ret);
 		}
+
+		spi_register_board_info(gf_mods[i].spi_devs,
+					gf_mods[i].num_spi_devs);
 	} else {
 		dev_warn(&i2c->dev, "Unknown module ID 0x%x revision %d\n",
 			 id, rev + 1);
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c
index 8077f65..e20bf58 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410.c
@@ -19,7 +19,9 @@
 #include <linux/io.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
+#include <linux/leds.h>
 #include <linux/delay.h>
+#include <linux/mmc/host.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/fixed.h>
 #include <linux/pwm_backlight.h>
@@ -59,6 +61,7 @@
 #include <plat/sdhci.h>
 #include <plat/gpio-cfg.h>
 #include <plat/s3c64xx-spi.h>
+#include <plat/udc-hs.h>
 
 #include <plat/keypad.h>
 #include <plat/clock.h>
@@ -298,6 +301,7 @@
 };
 
 static struct regulator_consumer_supply wallvdd_consumers[] = {
+	REGULATOR_SUPPLY("SPKVDD", "1-001a"),
 	REGULATOR_SUPPLY("SPKVDD1", "1-001a"),
 	REGULATOR_SUPPLY("SPKVDD2", "1-001a"),
 	REGULATOR_SUPPLY("SPKVDDL", "1-001a"),
@@ -574,11 +578,19 @@
 	.frequency = 400000,
 };
 
+static struct regulator_consumer_supply pvdd_1v2_consumers[] __initdata = {
+	REGULATOR_SUPPLY("DCVDD", "spi0.0"),
+	REGULATOR_SUPPLY("AVDD", "spi0.0"),
+};
+
 static struct regulator_init_data pvdd_1v2 __initdata = {
 	.constraints = {
 		.name = "PVDD_1V2",
-		.always_on = 1,
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
 	},
+
+	.consumer_supplies = pvdd_1v2_consumers,
+	.num_consumer_supplies = ARRAY_SIZE(pvdd_1v2_consumers),
 };
 
 static struct regulator_consumer_supply pvdd_1v8_consumers[] __initdata = {
@@ -592,6 +604,7 @@
 	REGULATOR_SUPPLY("AVDD2", "1-001a"),
 	REGULATOR_SUPPLY("DCVDD", "1-001a"),
 	REGULATOR_SUPPLY("AVDD", "1-001a"),
+	REGULATOR_SUPPLY("DBVDD", "spi0.0"),
 };
 
 static struct regulator_init_data pvdd_1v8 __initdata = {
@@ -681,6 +694,7 @@
 static struct s3c_sdhci_platdata crag6410_hsmmc2_pdata = {
 	.max_width		= 4,
 	.cd_type		= S3C_SDHCI_CD_PERMANENT,
+	.host_caps		= MMC_CAP_POWER_OFF_CARD,
 };
 
 static void crag6410_cfg_sdhci0(struct platform_device *dev, int width)
@@ -696,8 +710,59 @@
 	.max_width		= 4,
 	.cd_type		= S3C_SDHCI_CD_INTERNAL,
 	.cfg_gpio		= crag6410_cfg_sdhci0,
+	.host_caps		= MMC_CAP_POWER_OFF_CARD,
 };
 
+static const struct gpio_led gpio_leds[] = {
+	{
+		.name = "d13:green:",
+		.gpio = MMGPIO_GPIO_BASE + 0,
+		.default_state = LEDS_GPIO_DEFSTATE_ON,
+	},
+	{
+		.name = "d14:green:",
+		.gpio = MMGPIO_GPIO_BASE + 1,
+		.default_state = LEDS_GPIO_DEFSTATE_ON,
+	},
+	{
+		.name = "d15:green:",
+		.gpio = MMGPIO_GPIO_BASE + 2,
+		.default_state = LEDS_GPIO_DEFSTATE_ON,
+	},
+	{
+		.name = "d16:green:",
+		.gpio = MMGPIO_GPIO_BASE + 3,
+		.default_state = LEDS_GPIO_DEFSTATE_ON,
+	},
+	{
+		.name = "d17:green:",
+		.gpio = MMGPIO_GPIO_BASE + 4,
+		.default_state = LEDS_GPIO_DEFSTATE_ON,
+	},
+	{
+		.name = "d18:green:",
+		.gpio = MMGPIO_GPIO_BASE + 5,
+		.default_state = LEDS_GPIO_DEFSTATE_ON,
+	},
+	{
+		.name = "d19:green:",
+		.gpio = MMGPIO_GPIO_BASE + 6,
+		.default_state = LEDS_GPIO_DEFSTATE_ON,
+	},
+	{
+		.name = "d20:green:",
+		.gpio = MMGPIO_GPIO_BASE + 7,
+		.default_state = LEDS_GPIO_DEFSTATE_ON,
+	},
+};
+
+static const struct gpio_led_platform_data gpio_leds_pdata = {
+	.leds = gpio_leds,
+	.num_leds = ARRAY_SIZE(gpio_leds),
+};
+
+static struct s3c_hsotg_plat crag6410_hsotg_pdata;
+
 static void __init crag6410_machine_init(void)
 {
 	/* Open drain IRQs need pullups */
@@ -722,14 +787,18 @@
 	s3c_i2c0_set_platdata(&i2c0_pdata);
 	s3c_i2c1_set_platdata(&i2c1_pdata);
 	s3c_fb_set_platdata(&crag6410_lcd_pdata);
+	s3c_hsotg_set_platdata(&crag6410_hsotg_pdata);
 
 	i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
 	i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
 
 	samsung_keypad_set_platdata(&crag6410_keypad_data);
+	s3c64xx_spi0_set_platdata(&s3c64xx_spi0_pdata, 0, 1);
 
 	platform_add_devices(crag6410_devices, ARRAY_SIZE(crag6410_devices));
 
+	gpio_led_register_device(-1, &gpio_leds_pdata);
+
 	regulator_has_full_constraints();
 
 	s3c64xx_pm_init();
diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c
index ce31db1..ce745e1 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq.c
@@ -187,6 +187,8 @@
 	},
 };
 
+static struct s3c_hsotg_plat smartq_hsotg_pdata;
+
 static int __init smartq_lcd_setup_gpio(void)
 {
 	int ret;
@@ -383,6 +385,7 @@
 void __init smartq_machine_init(void)
 {
 	s3c_i2c0_set_platdata(NULL);
+	s3c_hsotg_set_platdata(&smartq_hsotg_pdata);
 	s3c_hwmon_set_platdata(&smartq_hwmon_pdata);
 	s3c_sdhci1_set_platdata(&smartq_internal_hsmmc_pdata);
 	s3c_sdhci2_set_platdata(&smartq_internal_hsmmc_pdata);
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
index ca6fc20..d55bc96 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
@@ -72,6 +72,7 @@
 #include <plat/keypad.h>
 #include <plat/backlight.h>
 #include <plat/regs-fb-v4.h>
+#include <plat/udc-hs.h>
 
 #include "common.h"
 
@@ -631,6 +632,8 @@
 	.pwm_id = 1,
 };
 
+static struct s3c_hsotg_plat smdk6410_hsotg_pdata;
+
 static void __init smdk6410_map_io(void)
 {
 	u32 tmp;
@@ -659,6 +662,7 @@
 	s3c_i2c0_set_platdata(NULL);
 	s3c_i2c1_set_platdata(NULL);
 	s3c_fb_set_platdata(&smdk6410_lcd_pdata);
+	s3c_hsotg_set_platdata(&smdk6410_hsotg_pdata);
 
 	samsung_keypad_set_platdata(&smdk6410_keypad_data);
 
diff --git a/arch/arm/mach-s3c64xx/setup-usb-phy.c b/arch/arm/mach-s3c64xx/setup-usb-phy.c
new file mode 100644
index 0000000..f6757e0
--- /dev/null
+++ b/arch/arm/mach-s3c64xx/setup-usb-phy.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@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/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <mach/map.h>
+#include <mach/regs-sys.h>
+#include <plat/cpu.h>
+#include <plat/regs-usb-hsotg-phy.h>
+#include <plat/usb-phy.h>
+
+static int s3c_usb_otgphy_init(struct platform_device *pdev)
+{
+	struct clk *xusbxti;
+	u32 phyclk;
+
+	writel(readl(S3C64XX_OTHERS) | S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS);
+
+	/* set clock frequency for PLL */
+	phyclk = readl(S3C_PHYCLK) & ~S3C_PHYCLK_CLKSEL_MASK;
+
+	xusbxti = clk_get(&pdev->dev, "xusbxti");
+	if (xusbxti && !IS_ERR(xusbxti)) {
+		switch (clk_get_rate(xusbxti)) {
+		case 12 * MHZ:
+			phyclk |= S3C_PHYCLK_CLKSEL_12M;
+			break;
+		case 24 * MHZ:
+			phyclk |= S3C_PHYCLK_CLKSEL_24M;
+			break;
+		default:
+		case 48 * MHZ:
+			/* default reference clock */
+			break;
+		}
+		clk_put(xusbxti);
+	}
+
+	/* TODO: select external clock/oscillator */
+	writel(phyclk | S3C_PHYCLK_CLK_FORCE, S3C_PHYCLK);
+
+	/* set to normal OTG PHY */
+	writel((readl(S3C_PHYPWR) & ~S3C_PHYPWR_NORMAL_MASK), S3C_PHYPWR);
+	mdelay(1);
+
+	/* reset OTG PHY and Link */
+	writel(S3C_RSTCON_PHY | S3C_RSTCON_HCLK | S3C_RSTCON_PHYCLK,
+			S3C_RSTCON);
+	udelay(20);	/* at-least 10uS */
+	writel(0, S3C_RSTCON);
+
+	return 0;
+}
+
+static int s3c_usb_otgphy_exit(struct platform_device *pdev)
+{
+	writel((readl(S3C_PHYPWR) | S3C_PHYPWR_ANALOG_POWERDOWN |
+				S3C_PHYPWR_OTG_DISABLE), S3C_PHYPWR);
+
+	writel(readl(S3C64XX_OTHERS) & ~S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS);
+
+	return 0;
+}
+
+int s5p_usb_phy_init(struct platform_device *pdev, int type)
+{
+	if (type == S5P_USB_PHY_DEVICE)
+		return s3c_usb_otgphy_init(pdev);
+
+	return -EINVAL;
+}
+
+int s5p_usb_phy_exit(struct platform_device *pdev, int type)
+{
+	if (type == S5P_USB_PHY_DEVICE)
+		return s3c_usb_otgphy_exit(pdev);
+
+	return -EINVAL;
+}
diff --git a/arch/arm/mach-s5p64x0/clock.c b/arch/arm/mach-s5p64x0/clock.c
index 241d0e6..57e7189 100644
--- a/arch/arm/mach-s5p64x0/clock.c
+++ b/arch/arm/mach-s5p64x0/clock.c
@@ -73,7 +73,7 @@
 	{L2 * 1000, (3 << ARM_DIV_RATIO_SHIFT), (0 << S5P64X0_CLKDIV0_HCLK_SHIFT)},
 };
 
-unsigned long s5p64x0_armclk_get_rate(struct clk *clk)
+static unsigned long s5p64x0_armclk_get_rate(struct clk *clk)
 {
 	unsigned long rate = clk_get_rate(clk->parent);
 	u32 clkdiv;
@@ -84,7 +84,8 @@
 	return rate / (clkdiv + 1);
 }
 
-unsigned long s5p64x0_armclk_round_rate(struct clk *clk, unsigned long rate)
+static unsigned long s5p64x0_armclk_round_rate(struct clk *clk,
+					       unsigned long rate)
 {
 	u32 iter;
 
@@ -96,7 +97,7 @@
 	return clock_table[ARRAY_SIZE(clock_table) - 1][0];
 }
 
-int s5p64x0_armclk_set_rate(struct clk *clk, unsigned long rate)
+static int s5p64x0_armclk_set_rate(struct clk *clk, unsigned long rate)
 {
 	u32 round_tmp;
 	u32 iter;
@@ -148,7 +149,7 @@
 	return 0;
 }
 
-struct clk_ops s5p64x0_clkarm_ops = {
+static struct clk_ops s5p64x0_clkarm_ops = {
 	.get_rate	= s5p64x0_armclk_get_rate,
 	.set_rate	= s5p64x0_armclk_set_rate,
 	.round_rate	= s5p64x0_armclk_round_rate,
@@ -173,7 +174,7 @@
 	.reg_div	= { .reg = S5P64X0_CLK_DIV0, .shift = 4, .size = 1 },
 };
 
-struct clk *clkset_hclk_low_list[] = {
+static struct clk *clkset_hclk_low_list[] = {
 	&clk_mout_apll.clk,
 	&clk_mout_mpll.clk,
 };
diff --git a/arch/arm/mach-s5p64x0/common.c b/arch/arm/mach-s5p64x0/common.c
index 52b89a3..6e6a0a9 100644
--- a/arch/arm/mach-s5p64x0/common.c
+++ b/arch/arm/mach-s5p64x0/common.c
@@ -27,6 +27,7 @@
 
 #include <asm/irq.h>
 #include <asm/proc-fns.h>
+#include <asm/system_misc.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
@@ -146,15 +147,12 @@
 {
 	unsigned long val;
 
-	if (!need_resched()) {
-		val = __raw_readl(S5P64X0_PWR_CFG);
-		val &= ~(0x3 << 5);
-		val |= (0x1 << 5);
-		__raw_writel(val, S5P64X0_PWR_CFG);
+	val = __raw_readl(S5P64X0_PWR_CFG);
+	val &= ~(0x3 << 5);
+	val |= (0x1 << 5);
+	__raw_writel(val, S5P64X0_PWR_CFG);
 
-		cpu_do_idle();
-	}
-	local_irq_enable();
+	cpu_do_idle();
 }
 
 /*
@@ -286,7 +284,7 @@
 	printk(KERN_INFO "S5P64X0(S5P6440/S5P6450): Initializing architecture\n");
 
 	/* set idle function */
-	pm_idle = s5p64x0_idle;
+	arm_pm_idle = s5p64x0_idle;
 
 	return device_register(&s5p64x0_dev);
 }
diff --git a/arch/arm/mach-s5p64x0/dma.c b/arch/arm/mach-s5p64x0/dma.c
index f820c07..2ee5dc0 100644
--- a/arch/arm/mach-s5p64x0/dma.c
+++ b/arch/arm/mach-s5p64x0/dma.c
@@ -38,7 +38,7 @@
 
 static u64 dma_dmamask = DMA_BIT_MASK(32);
 
-u8 s5p6440_pdma_peri[] = {
+static u8 s5p6440_pdma_peri[] = {
 	DMACH_UART0_RX,
 	DMACH_UART0_TX,
 	DMACH_UART1_RX,
@@ -63,12 +63,12 @@
 	DMACH_SPI1_RX,
 };
 
-struct dma_pl330_platdata s5p6440_pdma_pdata = {
+static struct dma_pl330_platdata s5p6440_pdma_pdata = {
 	.nr_valid_peri = ARRAY_SIZE(s5p6440_pdma_peri),
 	.peri_id = s5p6440_pdma_peri,
 };
 
-u8 s5p6450_pdma_peri[] = {
+static u8 s5p6450_pdma_peri[] = {
 	DMACH_UART0_RX,
 	DMACH_UART0_TX,
 	DMACH_UART1_RX,
@@ -103,39 +103,27 @@
 	DMACH_UART5_TX,
 };
 
-struct dma_pl330_platdata s5p6450_pdma_pdata = {
+static struct dma_pl330_platdata s5p6450_pdma_pdata = {
 	.nr_valid_peri = ARRAY_SIZE(s5p6450_pdma_peri),
 	.peri_id = s5p6450_pdma_peri,
 };
 
-struct amba_device s5p64x0_device_pdma = {
-	.dev = {
-		.init_name = "dma-pl330",
-		.dma_mask = &dma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(32),
-	},
-	.res = {
-		.start = S5P64X0_PA_PDMA,
-		.end = S5P64X0_PA_PDMA + SZ_4K,
-		.flags = IORESOURCE_MEM,
-	},
-	.irq = {IRQ_DMA0, NO_IRQ},
-	.periphid = 0x00041330,
-};
+static AMBA_AHB_DEVICE(s5p64x0_pdma, "dma-pl330", 0x00041330,
+	S5P64X0_PA_PDMA, {IRQ_DMA0}, NULL);
 
 static int __init s5p64x0_dma_init(void)
 {
 	if (soc_is_s5p6450()) {
 		dma_cap_set(DMA_SLAVE, s5p6450_pdma_pdata.cap_mask);
 		dma_cap_set(DMA_CYCLIC, s5p6450_pdma_pdata.cap_mask);
-		s5p64x0_device_pdma.dev.platform_data = &s5p6450_pdma_pdata;
+		s5p64x0_pdma_device.dev.platform_data = &s5p6450_pdma_pdata;
 	} else {
 		dma_cap_set(DMA_SLAVE, s5p6440_pdma_pdata.cap_mask);
 		dma_cap_set(DMA_CYCLIC, s5p6440_pdma_pdata.cap_mask);
-		s5p64x0_device_pdma.dev.platform_data = &s5p6440_pdma_pdata;
+		s5p64x0_pdma_device.dev.platform_data = &s5p6440_pdma_pdata;
 	}
 
-	amba_device_register(&s5p64x0_device_pdma, &iomem_resource);
+	amba_device_register(&s5p64x0_pdma_device, &iomem_resource);
 
 	return 0;
 }
diff --git a/arch/arm/mach-s5p64x0/include/mach/entry-macro.S b/arch/arm/mach-s5p64x0/include/mach/entry-macro.S
deleted file mode 100644
index fbb246d..0000000
--- a/arch/arm/mach-s5p64x0/include/mach/entry-macro.S
+++ /dev/null
@@ -1,17 +0,0 @@
-/* linux/arch/arm/mach-s5p64x0/include/mach/entry-macro.S
- *
- * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * Low-level IRQ helper macros for the Samsung S5P64X0
- *
- * 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.
-*/
-
-		.macro  disable_fiq
-		.endm
-
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
diff --git a/arch/arm/mach-s5p64x0/include/mach/io.h b/arch/arm/mach-s5p64x0/include/mach/io.h
deleted file mode 100644
index a3e095c..0000000
--- a/arch/arm/mach-s5p64x0/include/mach/io.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* linux/arch/arm/mach-s5p64x0/include/mach/io.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * Copyright 2008 Simtec Electronics
- *	Ben Dooks <ben-linux@fluff.org>
- *
- * Default IO routines for S5P64X0 based
- *
- * 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 __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/* No current ISA/PCI bus support. */
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#define IO_SPACE_LIMIT (0xFFFFFFFF)
-
-#endif
diff --git a/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h b/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h
index ff85b4b..0ef47d1 100644
--- a/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h
+++ b/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h
@@ -22,16 +22,9 @@
 extern int s5p64x0_epll_enable(struct clk *clk, int enable);
 extern unsigned long s5p64x0_epll_get_rate(struct clk *clk);
 
-extern unsigned long s5p64x0_armclk_get_rate(struct clk *clk);
-extern unsigned long s5p64x0_armclk_round_rate(struct clk *clk, unsigned long rate);
-extern int s5p64x0_armclk_set_rate(struct clk *clk, unsigned long rate);
-
-extern struct clk_ops s5p64x0_clkarm_ops;
-
 extern struct clksrc_clk clk_armclk;
 extern struct clksrc_clk clk_dout_mpll;
 
-extern struct clk *clkset_hclk_low_list[];
 extern struct clksrc_sources clkset_hclk_low;
 
 extern int s5p64x0_pclk_ctrl(struct clk *clk, int enable);
diff --git a/arch/arm/mach-s5p64x0/include/mach/system.h b/arch/arm/mach-s5p64x0/include/mach/system.h
deleted file mode 100644
index cf26e09..0000000
--- a/arch/arm/mach-s5p64x0/include/mach/system.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* linux/arch/arm/mach-s5p64x0/include/mach/system.h
- *
- * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * S5P64X0 - system support 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 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H __FILE__
-
-static void arch_idle(void)
-{
-	/* nothing here yet */
-}
-
-#endif /* __ASM_ARCH_SYSTEM_H */
diff --git a/arch/arm/mach-s5pc100/clock.c b/arch/arm/mach-s5pc100/clock.c
index 247194d..16eca4e 100644
--- a/arch/arm/mach-s5pc100/clock.c
+++ b/arch/arm/mach-s5pc100/clock.c
@@ -170,7 +170,7 @@
 	[1] = &clk_div_apll2.clk,
 };
 
-struct clksrc_sources clk_src_mout_am = {
+static struct clksrc_sources clk_src_mout_am = {
 	.sources	= clk_src_mout_am_list,
 	.nr_sources	= ARRAY_SIZE(clk_src_mout_am_list),
 };
@@ -212,7 +212,7 @@
 	[1] = &clk_div_d1_bus.clk,
 };
 
-struct clksrc_sources clk_src_mout_onenand = {
+static struct clksrc_sources clk_src_mout_onenand = {
 	.sources	= clk_src_mout_onenand_list,
 	.nr_sources	= ARRAY_SIZE(clk_src_mout_onenand_list),
 };
@@ -756,7 +756,7 @@
 	[3] = &clk_mout_hpll.clk,
 };
 
-struct clksrc_sources clk_src_group1 = {
+static struct clksrc_sources clk_src_group1 = {
 	.sources	= clk_src_group1_list,
 	.nr_sources	= ARRAY_SIZE(clk_src_group1_list),
 };
@@ -766,7 +766,7 @@
 	[1] = &clk_div_mpll.clk,
 };
 
-struct clksrc_sources clk_src_group2 = {
+static struct clksrc_sources clk_src_group2 = {
 	.sources	= clk_src_group2_list,
 	.nr_sources	= ARRAY_SIZE(clk_src_group2_list),
 };
@@ -780,7 +780,7 @@
 	[5] = &clk_mout_hpll.clk,
 };
 
-struct clksrc_sources clk_src_group3 = {
+static struct clksrc_sources clk_src_group3 = {
 	.sources	= clk_src_group3_list,
 	.nr_sources	= ARRAY_SIZE(clk_src_group3_list),
 };
@@ -806,7 +806,7 @@
 	[5] = &clk_mout_hpll.clk,
 };
 
-struct clksrc_sources clk_src_group4 = {
+static struct clksrc_sources clk_src_group4 = {
 	.sources	= clk_src_group4_list,
 	.nr_sources	= ARRAY_SIZE(clk_src_group4_list),
 };
@@ -831,7 +831,7 @@
 	[4] = &clk_mout_hpll.clk,
 };
 
-struct clksrc_sources clk_src_group5 = {
+static struct clksrc_sources clk_src_group5 = {
 	.sources	= clk_src_group5_list,
 	.nr_sources	= ARRAY_SIZE(clk_src_group5_list),
 };
@@ -854,7 +854,7 @@
 	[2] = &clk_div_hdmi.clk,
 };
 
-struct clksrc_sources clk_src_group6 = {
+static struct clksrc_sources clk_src_group6 = {
 	.sources	= clk_src_group6_list,
 	.nr_sources	= ARRAY_SIZE(clk_src_group6_list),
 };
@@ -866,7 +866,7 @@
 	[3] = &clk_vclk54m,
 };
 
-struct clksrc_sources clk_src_group7 = {
+static struct clksrc_sources clk_src_group7 = {
 	.sources	= clk_src_group7_list,
 	.nr_sources	= ARRAY_SIZE(clk_src_group7_list),
 };
@@ -877,7 +877,7 @@
 	[2] = &clk_fin_epll,
 };
 
-struct clksrc_sources clk_src_mmc0 = {
+static struct clksrc_sources clk_src_mmc0 = {
 	.sources	= clk_src_mmc0_list,
 	.nr_sources	= ARRAY_SIZE(clk_src_mmc0_list),
 };
@@ -889,7 +889,7 @@
 	[3] = &clk_mout_hpll.clk,
 };
 
-struct clksrc_sources clk_src_mmc12 = {
+static struct clksrc_sources clk_src_mmc12 = {
 	.sources	= clk_src_mmc12_list,
 	.nr_sources	= ARRAY_SIZE(clk_src_mmc12_list),
 };
@@ -901,7 +901,7 @@
 	[3] = &clk_mout_hpll.clk,
 };
 
-struct clksrc_sources clk_src_irda_usb = {
+static struct clksrc_sources clk_src_irda_usb = {
 	.sources	= clk_src_irda_usb_list,
 	.nr_sources	= ARRAY_SIZE(clk_src_irda_usb_list),
 };
@@ -912,7 +912,7 @@
 	[2] = &clk_div_mpll.clk,
 };
 
-struct clksrc_sources clk_src_pwi = {
+static struct clksrc_sources clk_src_pwi = {
 	.sources	= clk_src_pwi_list,
 	.nr_sources	= ARRAY_SIZE(clk_src_pwi_list),
 };
@@ -923,7 +923,7 @@
 	[2] = &clk_sclk_audio2.clk,
 };
 
-struct clksrc_sources clk_src_sclk_spdif = {
+static struct clksrc_sources clk_src_sclk_spdif = {
 	.sources	= clk_sclk_spdif_list,
 	.nr_sources	= ARRAY_SIZE(clk_sclk_spdif_list),
 };
diff --git a/arch/arm/mach-s5pc100/common.c b/arch/arm/mach-s5pc100/common.c
index c909573..6219086 100644
--- a/arch/arm/mach-s5pc100/common.c
+++ b/arch/arm/mach-s5pc100/common.c
@@ -27,6 +27,7 @@
 
 #include <asm/irq.h>
 #include <asm/proc-fns.h>
+#include <asm/system_misc.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
@@ -129,14 +130,6 @@
 	}
 };
 
-static void s5pc100_idle(void)
-{
-	if (!need_resched())
-		cpu_do_idle();
-
-	local_irq_enable();
-}
-
 /*
  * s5pc100_map_io
  *
@@ -210,10 +203,6 @@
 int __init s5pc100_init(void)
 {
 	printk(KERN_INFO "S5PC100: Initializing architecture\n");
-
-	/* set idle function */
-	pm_idle = s5pc100_idle;
-
 	return device_register(&s5pc100_dev);
 }
 
diff --git a/arch/arm/mach-s5pc100/dma.c b/arch/arm/mach-s5pc100/dma.c
index c841f4d3..afd8db2 100644
--- a/arch/arm/mach-s5pc100/dma.c
+++ b/arch/arm/mach-s5pc100/dma.c
@@ -35,7 +35,7 @@
 
 static u64 dma_dmamask = DMA_BIT_MASK(32);
 
-u8 pdma0_peri[] = {
+static u8 pdma0_peri[] = {
 	DMACH_UART0_RX,
 	DMACH_UART0_TX,
 	DMACH_UART1_RX,
@@ -68,28 +68,15 @@
 	DMACH_HSI_TX,
 };
 
-struct dma_pl330_platdata s5pc100_pdma0_pdata = {
+static struct dma_pl330_platdata s5pc100_pdma0_pdata = {
 	.nr_valid_peri = ARRAY_SIZE(pdma0_peri),
 	.peri_id = pdma0_peri,
 };
 
-struct amba_device s5pc100_device_pdma0 = {
-	.dev = {
-		.init_name = "dma-pl330.0",
-		.dma_mask = &dma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(32),
-		.platform_data = &s5pc100_pdma0_pdata,
-	},
-	.res = {
-		.start = S5PC100_PA_PDMA0,
-		.end = S5PC100_PA_PDMA0 + SZ_4K,
-		.flags = IORESOURCE_MEM,
-	},
-	.irq = {IRQ_PDMA0, NO_IRQ},
-	.periphid = 0x00041330,
-};
+static AMBA_AHB_DEVICE(s5pc100_pdma0,  "dma-pl330.0", 0x00041330,
+	S5PC100_PA_PDMA0, {IRQ_PDMA0}, &s5pc100_pdma0_pdata);
 
-u8 pdma1_peri[] = {
+static u8 pdma1_peri[] = {
 	DMACH_UART0_RX,
 	DMACH_UART0_TX,
 	DMACH_UART1_RX,
@@ -122,36 +109,23 @@
 	DMACH_MSM_REQ3,
 };
 
-struct dma_pl330_platdata s5pc100_pdma1_pdata = {
+static struct dma_pl330_platdata s5pc100_pdma1_pdata = {
 	.nr_valid_peri = ARRAY_SIZE(pdma1_peri),
 	.peri_id = pdma1_peri,
 };
 
-struct amba_device s5pc100_device_pdma1 = {
-	.dev = {
-		.init_name = "dma-pl330.1",
-		.dma_mask = &dma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(32),
-		.platform_data = &s5pc100_pdma1_pdata,
-	},
-	.res = {
-		.start = S5PC100_PA_PDMA1,
-		.end = S5PC100_PA_PDMA1 + SZ_4K,
-		.flags = IORESOURCE_MEM,
-	},
-	.irq = {IRQ_PDMA1, NO_IRQ},
-	.periphid = 0x00041330,
-};
+static AMBA_AHB_DEVICE(s5pc100_pdma1, "dma-pl330.1", 0x00041330,
+	S5PC100_PA_PDMA1, {IRQ_PDMA1}, &s5pc100_pdma1_pdata);
 
 static int __init s5pc100_dma_init(void)
 {
 	dma_cap_set(DMA_SLAVE, s5pc100_pdma0_pdata.cap_mask);
 	dma_cap_set(DMA_CYCLIC, s5pc100_pdma0_pdata.cap_mask);
-	amba_device_register(&s5pc100_device_pdma0, &iomem_resource);
+	amba_device_register(&s5pc100_pdma0_device, &iomem_resource);
 
 	dma_cap_set(DMA_SLAVE, s5pc100_pdma1_pdata.cap_mask);
 	dma_cap_set(DMA_CYCLIC, s5pc100_pdma1_pdata.cap_mask);
-	amba_device_register(&s5pc100_device_pdma1, &iomem_resource);
+	amba_device_register(&s5pc100_pdma1_device, &iomem_resource);
 
 	return 0;
 }
diff --git a/arch/arm/mach-s5pc100/include/mach/entry-macro.S b/arch/arm/mach-s5pc100/include/mach/entry-macro.S
index b8c242e..bad0700 100644
--- a/arch/arm/mach-s5pc100/include/mach/entry-macro.S
+++ b/arch/arm/mach-s5pc100/include/mach/entry-macro.S
@@ -12,14 +12,8 @@
  * warranty of any kind, whether express or implied.
 */
 
-	.macro	disable_fiq
-	.endm
-
 	.macro	get_irqnr_preamble, base, tmp
 	.endm
 
-	.macro	arch_ret_to_user, tmp1, tmp2
-	.endm
-
 	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 	.endm
diff --git a/arch/arm/mach-s5pc100/include/mach/io.h b/arch/arm/mach-s5pc100/include/mach/io.h
deleted file mode 100644
index 819acf5..0000000
--- a/arch/arm/mach-s5pc100/include/mach/io.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* arch/arm/mach-s5pc100/include/mach/io.h
- *
- * Copyright 2008 Simtec Electronics
- *	Ben Dooks <ben-linux@fluff.org>
- *
- * Default IO routines for S5PC100 systems
- */
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/* No current ISA/PCI bus support. */
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#define IO_SPACE_LIMIT (0xFFFFFFFF)
-
-#endif
diff --git a/arch/arm/mach-s5pc100/include/mach/system.h b/arch/arm/mach-s5pc100/include/mach/system.h
deleted file mode 100644
index afc96c2..0000000
--- a/arch/arm/mach-s5pc100/include/mach/system.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* linux/arch/arm/mach-s5pc100/include/mach/system.h
- *
- * Copyright 2009 Samsung Electronics Co.
- *      Byungho Min <bhmin@samsung.com>
- *
- * S5PC100 - system implementation
- *
- * Based on mach-s3c6400/include/mach/system.h
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H __FILE__
-
-static void arch_idle(void)
-{
-	/* nothing here yet */
-}
-
-#endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 2cdc42e..29594fc 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -65,6 +65,11 @@
 	help
 	  Common setup code for SPI GPIO configurations.
 
+config S5PV210_SETUP_USB_PHY
+	bool
+	help
+	  Common setup code for USB PHY controller
+
 menu "S5PC110 Machines"
 
 config MACH_AQUILA
@@ -107,6 +112,7 @@
 	select S5PV210_SETUP_KEYPAD
 	select S5PV210_SETUP_SDHCI
 	select S5PV210_SETUP_FIMC
+	select S5PV210_SETUP_USB_PHY
 	help
 	  Machine support for Samsung GONI board
 	  S5PC110(MCP) is one of package option of S5PV210
@@ -118,6 +124,10 @@
 	select S3C_DEV_I2C2
 	select S3C_DEV_RTC
 	select S3C_DEV_WDT
+	select S5P_DEV_FIMC0
+	select S5P_DEV_FIMC1
+	select S5P_DEV_FIMC2
+	select S5P_DEV_MFC
 	select SAMSUNG_DEV_IDE
 	select S5PV210_SETUP_I2C1
 	select S5PV210_SETUP_I2C2
@@ -142,6 +152,11 @@
 	select S3C_DEV_I2C2
 	select S3C_DEV_RTC
 	select S3C_DEV_WDT
+	select S5P_DEV_FIMC0
+	select S5P_DEV_FIMC1
+	select S5P_DEV_FIMC2
+	select S5P_DEV_JPEG
+	select S5P_DEV_MFC
 	select SAMSUNG_DEV_ADC
 	select SAMSUNG_DEV_BACKLIGHT
 	select SAMSUNG_DEV_IDE
diff --git a/arch/arm/mach-s5pv210/Makefile b/arch/arm/mach-s5pv210/Makefile
index 76a121d..1c4e419 100644
--- a/arch/arm/mach-s5pv210/Makefile
+++ b/arch/arm/mach-s5pv210/Makefile
@@ -39,3 +39,4 @@
 obj-$(CONFIG_S5PV210_SETUP_KEYPAD)	+= setup-keypad.o
 obj-$(CONFIG_S5PV210_SETUP_SDHCI_GPIO)	+= setup-sdhci-gpio.o
 obj-$(CONFIG_S5PV210_SETUP_SPI)		+= setup-spi.o
+obj-$(CONFIG_S5PV210_SETUP_USB_PHY) += setup-usb-phy.o
diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c
index b9ec0c3..09609d5 100644
--- a/arch/arm/mach-s5pv210/clock.c
+++ b/arch/arm/mach-s5pv210/clock.c
@@ -340,6 +340,11 @@
 		.enable		= s5pv210_clk_ip0_ctrl,
 		.ctrlbit	= (1 << 26),
 	}, {
+		.name		= "jpeg",
+		.parent		= &clk_hclk_dsys.clk,
+		.enable		= s5pv210_clk_ip0_ctrl,
+		.ctrlbit	= (1 << 28),
+	}, {
 		.name		= "mfc",
 		.devname	= "s5p-mfc",
 		.parent		= &clk_pclk_psys.clk,
diff --git a/arch/arm/mach-s5pv210/common.c b/arch/arm/mach-s5pv210/common.c
index 9c1bcdc..4c9e902 100644
--- a/arch/arm/mach-s5pv210/common.c
+++ b/arch/arm/mach-s5pv210/common.c
@@ -142,14 +142,6 @@
 	}
 };
 
-static void s5pv210_idle(void)
-{
-	if (!need_resched())
-		cpu_do_idle();
-
-	local_irq_enable();
-}
-
 void s5pv210_restart(char mode, const char *cmd)
 {
 	__raw_writel(0x1, S5P_SWRESET);
@@ -247,10 +239,6 @@
 int __init s5pv210_init(void)
 {
 	printk(KERN_INFO "S5PV210: Initializing architecture\n");
-
-	/* set idle function */
-	pm_idle = s5pv210_idle;
-
 	return device_register(&s5pv210_dev);
 }
 
diff --git a/arch/arm/mach-s5pv210/dma.c b/arch/arm/mach-s5pv210/dma.c
index a6113e0..86ce62f 100644
--- a/arch/arm/mach-s5pv210/dma.c
+++ b/arch/arm/mach-s5pv210/dma.c
@@ -35,7 +35,7 @@
 
 static u64 dma_dmamask = DMA_BIT_MASK(32);
 
-u8 pdma0_peri[] = {
+static u8 pdma0_peri[] = {
 	DMACH_UART0_RX,
 	DMACH_UART0_TX,
 	DMACH_UART1_RX,
@@ -66,28 +66,15 @@
 	DMACH_SPDIF,
 };
 
-struct dma_pl330_platdata s5pv210_pdma0_pdata = {
+static struct dma_pl330_platdata s5pv210_pdma0_pdata = {
 	.nr_valid_peri = ARRAY_SIZE(pdma0_peri),
 	.peri_id = pdma0_peri,
 };
 
-struct amba_device s5pv210_device_pdma0 = {
-	.dev = {
-		.init_name = "dma-pl330.0",
-		.dma_mask = &dma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(32),
-		.platform_data = &s5pv210_pdma0_pdata,
-	},
-	.res = {
-		.start = S5PV210_PA_PDMA0,
-		.end = S5PV210_PA_PDMA0 + SZ_4K,
-		.flags = IORESOURCE_MEM,
-	},
-	.irq = {IRQ_PDMA0, NO_IRQ},
-	.periphid = 0x00041330,
-};
+static AMBA_AHB_DEVICE(s5pv210_pdma0, "dma-pl330.0", 0x00041330,
+	S5PV210_PA_PDMA0, {IRQ_PDMA0}, &s5pv210_pdma0_pdata);
 
-u8 pdma1_peri[] = {
+static u8 pdma1_peri[] = {
 	DMACH_UART0_RX,
 	DMACH_UART0_TX,
 	DMACH_UART1_RX,
@@ -122,36 +109,23 @@
 	DMACH_PCM2_TX,
 };
 
-struct dma_pl330_platdata s5pv210_pdma1_pdata = {
+static struct dma_pl330_platdata s5pv210_pdma1_pdata = {
 	.nr_valid_peri = ARRAY_SIZE(pdma1_peri),
 	.peri_id = pdma1_peri,
 };
 
-struct amba_device s5pv210_device_pdma1 = {
-	.dev = {
-		.init_name = "dma-pl330.1",
-		.dma_mask = &dma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(32),
-		.platform_data = &s5pv210_pdma1_pdata,
-	},
-	.res = {
-		.start = S5PV210_PA_PDMA1,
-		.end = S5PV210_PA_PDMA1 + SZ_4K,
-		.flags = IORESOURCE_MEM,
-	},
-	.irq = {IRQ_PDMA1, NO_IRQ},
-	.periphid = 0x00041330,
-};
+static AMBA_AHB_DEVICE(s5pv210_pdma1, "dma-pl330.1", 0x00041330,
+	S5PV210_PA_PDMA1, {IRQ_PDMA1}, &s5pv210_pdma1_pdata);
 
 static int __init s5pv210_dma_init(void)
 {
 	dma_cap_set(DMA_SLAVE, s5pv210_pdma0_pdata.cap_mask);
 	dma_cap_set(DMA_CYCLIC, s5pv210_pdma0_pdata.cap_mask);
-	amba_device_register(&s5pv210_device_pdma0, &iomem_resource);
+	amba_device_register(&s5pv210_pdma0_device, &iomem_resource);
 
 	dma_cap_set(DMA_SLAVE, s5pv210_pdma1_pdata.cap_mask);
 	dma_cap_set(DMA_CYCLIC, s5pv210_pdma1_pdata.cap_mask);
-	amba_device_register(&s5pv210_device_pdma1, &iomem_resource);
+	amba_device_register(&s5pv210_pdma1_device, &iomem_resource);
 
 	return 0;
 }
diff --git a/arch/arm/mach-s5pv210/include/mach/entry-macro.S b/arch/arm/mach-s5pv210/include/mach/entry-macro.S
deleted file mode 100644
index bebca1b..0000000
--- a/arch/arm/mach-s5pv210/include/mach/entry-macro.S
+++ /dev/null
@@ -1,17 +0,0 @@
-/* linux/arch/arm/mach-s5pv210/include/mach/entry-macro.S
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * Low-level IRQ helper macros for the Samsung S5PV210
- *
- * 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.
-*/
-
-	.macro	disable_fiq
-	.endm
-
-	.macro	arch_ret_to_user, tmp1, tmp2
-	.endm
diff --git a/arch/arm/mach-s5pv210/include/mach/io.h b/arch/arm/mach-s5pv210/include/mach/io.h
deleted file mode 100644
index 5ab9d56..0000000
--- a/arch/arm/mach-s5pv210/include/mach/io.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* linux/arch/arm/mach-s5pv210/include/mach/io.h
- *
- * Copyright 2008-2010 Ben Dooks <ben-linux@fluff.org>
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * Based on arch/arm/mach-s5p6442/include/mach/io.h
- *
- * Default IO routines for S5PV210
- *
- * 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 __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H __FILE__
-
-/* No current ISA/PCI bus support. */
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#define IO_SPACE_LIMIT (0xFFFFFFFF)
-
-#endif /* __ASM_ARM_ARCH_IO_H */
diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-s5pv210/include/mach/map.h
index 89c34b8..b7c8a19 100644
--- a/arch/arm/mach-s5pv210/include/mach/map.h
+++ b/arch/arm/mach-s5pv210/include/mach/map.h
@@ -90,6 +90,8 @@
 #define S5PV210_PA_FIMC1		0xFB300000
 #define S5PV210_PA_FIMC2		0xFB400000
 
+#define S5PV210_PA_JPEG			0xFB600000
+
 #define S5PV210_PA_SDO			0xF9000000
 #define S5PV210_PA_VP			0xF9100000
 #define S5PV210_PA_MIXER		0xF9200000
@@ -132,6 +134,8 @@
 #define S5P_PA_SYSCON			S5PV210_PA_SYSCON
 #define S5P_PA_TIMER			S5PV210_PA_TIMER
 
+#define S5P_PA_JPEG			S5PV210_PA_JPEG
+
 #define SAMSUNG_PA_ADC			S5PV210_PA_ADC
 #define SAMSUNG_PA_CFCON		S5PV210_PA_CFCON
 #define SAMSUNG_PA_KEYPAD		S5PV210_PA_KEYPAD
diff --git a/arch/arm/mach-s5pv210/include/mach/regs-sys.h b/arch/arm/mach-s5pv210/include/mach/regs-sys.h
index 26691d3..cccb1ed 100644
--- a/arch/arm/mach-s5pv210/include/mach/regs-sys.h
+++ b/arch/arm/mach-s5pv210/include/mach/regs-sys.h
@@ -13,7 +13,3 @@
 #define S5PV210_USB_PHY_CON	(S3C_VA_SYS + 0xE80C)
 #define S5PV210_USB_PHY0_EN	(1 << 0)
 #define S5PV210_USB_PHY1_EN	(1 << 1)
-
-/* compatibility defines for s3c-hsotg driver */
-#define S3C64XX_OTHERS		S5PV210_USB_PHY_CON
-#define S3C64XX_OTHERS_USBMASK	S5PV210_USB_PHY0_EN
diff --git a/arch/arm/mach-s5pv210/include/mach/system.h b/arch/arm/mach-s5pv210/include/mach/system.h
deleted file mode 100644
index bf288ce..0000000
--- a/arch/arm/mach-s5pv210/include/mach/system.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* linux/arch/arm/mach-s5pv210/include/mach/system.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * S5PV210 - system support 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 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H __FILE__
-
-static void arch_idle(void)
-{
-	/* nothing here yet */
-}
-
-#endif /* __ASM_ARCH_SYSTEM_H */
diff --git a/arch/arm/mach-s5pv210/mach-aquila.c b/arch/arm/mach-s5pv210/mach-aquila.c
index 5e734d0..a9ea64e 100644
--- a/arch/arm/mach-s5pv210/mach-aquila.c
+++ b/arch/arm/mach-s5pv210/mach-aquila.c
@@ -616,6 +616,7 @@
 	&s5p_device_fimc0,
 	&s5p_device_fimc1,
 	&s5p_device_fimc2,
+	&s5p_device_fimc_md,
 	&s5pv210_device_iis0,
 	&wm8994_fixed_voltage0,
 	&wm8994_fixed_voltage1,
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
index ff91526..2cf5ed7 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -844,7 +844,7 @@
 	},
 };
 
-struct s5p_platform_fimc goni_fimc_md_platdata __initdata = {
+static struct s5p_platform_fimc goni_fimc_md_platdata __initdata = {
 	.isp_info	= goni_camera_sensors,
 	.num_clients	= ARRAY_SIZE(goni_camera_sensors),
 };
diff --git a/arch/arm/mach-s5pv210/mach-smdkc110.c b/arch/arm/mach-s5pv210/mach-smdkc110.c
index b323983..dfc2923 100644
--- a/arch/arm/mach-s5pv210/mach-smdkc110.c
+++ b/arch/arm/mach-s5pv210/mach-smdkc110.c
@@ -31,6 +31,7 @@
 #include <plat/iic.h>
 #include <plat/pm.h>
 #include <plat/s5p-time.h>
+#include <plat/mfc.h>
 
 #include "common.h"
 
@@ -94,6 +95,13 @@
 	&s3c_device_i2c2,
 	&s3c_device_rtc,
 	&s3c_device_wdt,
+	&s5p_device_fimc0,
+	&s5p_device_fimc1,
+	&s5p_device_fimc2,
+	&s5p_device_fimc_md,
+	&s5p_device_mfc,
+	&s5p_device_mfc_l,
+	&s5p_device_mfc_r,
 };
 
 static struct i2c_board_info smdkc110_i2c_devs0[] __initdata = {
@@ -117,6 +125,11 @@
 	s5p_set_timer_source(S5P_PWM3, S5P_PWM4);
 }
 
+static void __init smdkc110_reserve(void)
+{
+	s5p_mfc_reserve_mem(0x43000000, 8 << 20, 0x51000000, 8 << 20);
+}
+
 static void __init smdkc110_machine_init(void)
 {
 	s3c_pm_init();
@@ -145,4 +158,5 @@
 	.init_machine	= smdkc110_machine_init,
 	.timer		= &s5p_timer,
 	.restart	= s5pv210_restart,
+	.reserve	= &smdkc110_reserve,
 MACHINE_END
diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c
index dff9ea7..91d4ad8 100644
--- a/arch/arm/mach-s5pv210/mach-smdkv210.c
+++ b/arch/arm/mach-s5pv210/mach-smdkv210.c
@@ -46,6 +46,7 @@
 #include <plat/s5p-time.h>
 #include <plat/backlight.h>
 #include <plat/regs-fb-v4.h>
+#include <plat/mfc.h>
 
 #include "common.h"
 
@@ -140,7 +141,7 @@
 	.dev_addr	= { 0x00, 0x09, 0xc0, 0xff, 0xec, 0x48 },
 };
 
-struct platform_device smdkv210_dm9000 = {
+static struct platform_device smdkv210_dm9000 = {
 	.name		= "dm9000",
 	.id		= -1,
 	.num_resources	= ARRAY_SIZE(smdkv210_dm9000_resources),
@@ -223,6 +224,14 @@
 	&s3c_device_rtc,
 	&s3c_device_ts,
 	&s3c_device_wdt,
+	&s5p_device_fimc0,
+	&s5p_device_fimc1,
+	&s5p_device_fimc2,
+	&s5p_device_fimc_md,
+	&s5p_device_jpeg,
+	&s5p_device_mfc,
+	&s5p_device_mfc_l,
+	&s5p_device_mfc_r,
 	&s5pv210_device_ac97,
 	&s5pv210_device_iis0,
 	&s5pv210_device_spdif,
@@ -282,6 +291,11 @@
 	s5p_set_timer_source(S5P_PWM2, S5P_PWM4);
 }
 
+static void __init smdkv210_reserve(void)
+{
+	s5p_mfc_reserve_mem(0x43000000, 8 << 20, 0x51000000, 8 << 20);
+}
+
 static void __init smdkv210_machine_init(void)
 {
 	s3c_pm_init();
@@ -319,4 +333,5 @@
 	.init_machine	= smdkv210_machine_init,
 	.timer		= &s5p_timer,
 	.restart	= s5pv210_restart,
+	.reserve	= &smdkv210_reserve,
 MACHINE_END
diff --git a/arch/arm/mach-s5pv210/setup-usb-phy.c b/arch/arm/mach-s5pv210/setup-usb-phy.c
new file mode 100644
index 0000000..be39cf4
--- /dev/null
+++ b/arch/arm/mach-s5pv210/setup-usb-phy.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@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 Foundationr
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <mach/map.h>
+#include <mach/regs-sys.h>
+#include <plat/cpu.h>
+#include <plat/regs-usb-hsotg-phy.h>
+#include <plat/usb-phy.h>
+
+static int s5pv210_usb_otgphy_init(struct platform_device *pdev)
+{
+	struct clk *xusbxti;
+	u32 phyclk;
+
+	writel(readl(S5PV210_USB_PHY_CON) | S5PV210_USB_PHY0_EN,
+			S5PV210_USB_PHY_CON);
+
+	/* set clock frequency for PLL */
+	phyclk = readl(S3C_PHYCLK) & ~S3C_PHYCLK_CLKSEL_MASK;
+
+	xusbxti = clk_get(&pdev->dev, "xusbxti");
+	if (xusbxti && !IS_ERR(xusbxti)) {
+		switch (clk_get_rate(xusbxti)) {
+		case 12 * MHZ:
+			phyclk |= S3C_PHYCLK_CLKSEL_12M;
+			break;
+		case 24 * MHZ:
+			phyclk |= S3C_PHYCLK_CLKSEL_24M;
+			break;
+		default:
+		case 48 * MHZ:
+			/* default reference clock */
+			break;
+		}
+		clk_put(xusbxti);
+	}
+
+	/* TODO: select external clock/oscillator */
+	writel(phyclk | S3C_PHYCLK_CLK_FORCE, S3C_PHYCLK);
+
+	/* set to normal OTG PHY */
+	writel((readl(S3C_PHYPWR) & ~S3C_PHYPWR_NORMAL_MASK), S3C_PHYPWR);
+	mdelay(1);
+
+	/* reset OTG PHY and Link */
+	writel(S3C_RSTCON_PHY | S3C_RSTCON_HCLK | S3C_RSTCON_PHYCLK,
+			S3C_RSTCON);
+	udelay(20);	/* at-least 10uS */
+	writel(0, S3C_RSTCON);
+
+	return 0;
+}
+
+static int s5pv210_usb_otgphy_exit(struct platform_device *pdev)
+{
+	writel((readl(S3C_PHYPWR) | S3C_PHYPWR_ANALOG_POWERDOWN |
+				S3C_PHYPWR_OTG_DISABLE), S3C_PHYPWR);
+
+	writel(readl(S5PV210_USB_PHY_CON) & ~S5PV210_USB_PHY0_EN,
+			S5PV210_USB_PHY_CON);
+
+	return 0;
+}
+
+int s5p_usb_phy_init(struct platform_device *pdev, int type)
+{
+	if (type == S5P_USB_PHY_DEVICE)
+		return s5pv210_usb_otgphy_init(pdev);
+
+	return -EINVAL;
+}
+
+int s5p_usb_phy_exit(struct platform_device *pdev, int type)
+{
+	if (type == S5P_USB_PHY_DEVICE)
+		return s5pv210_usb_otgphy_exit(pdev);
+
+	return -EINVAL;
+}
diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile
index ed7408d..60b97ec 100644
--- a/arch/arm/mach-sa1100/Makefile
+++ b/arch/arm/mach-sa1100/Makefile
@@ -3,7 +3,7 @@
 #
 
 # Common support
-obj-y := clock.o generic.o irq.o dma.o time.o #nmi-oopser.o
+obj-y := clock.o generic.o irq.o time.o #nmi-oopser.o
 obj-m :=
 obj-n :=
 obj-  :=
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index 0c4b76a..375d3f7 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -15,14 +15,16 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/serial_core.h>
+#include <linux/mfd/ucb1x00.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
 
+#include <video/sa1100fb.h>
+
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/irq.h>
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgtable-hwdef.h>
@@ -36,17 +38,18 @@
 #include <asm/mach/serial_sa1100.h>
 #include <mach/assabet.h>
 #include <mach/mcp.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
 #define ASSABET_BCR_DB1110 \
-	(ASSABET_BCR_SPK_OFF    | ASSABET_BCR_QMUTE     | \
+	(ASSABET_BCR_SPK_OFF    | \
 	 ASSABET_BCR_LED_GREEN  | ASSABET_BCR_LED_RED   | \
 	 ASSABET_BCR_RS232EN    | ASSABET_BCR_LCD_12RGB | \
 	 ASSABET_BCR_IRDA_MD0)
 
 #define ASSABET_BCR_DB1111 \
-	(ASSABET_BCR_SPK_OFF    | ASSABET_BCR_QMUTE     | \
+	(ASSABET_BCR_SPK_OFF    | \
 	 ASSABET_BCR_LED_GREEN  | ASSABET_BCR_LED_RED   | \
 	 ASSABET_BCR_RS232EN    | ASSABET_BCR_LCD_12RGB | \
 	 ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_STEREO_LB | \
@@ -69,31 +72,10 @@
 
 EXPORT_SYMBOL(ASSABET_BCR_frob);
 
-static void assabet_backlight_power(int on)
+static void assabet_ucb1x00_reset(enum ucb1x00_reset state)
 {
-#ifndef ASSABET_PAL_VIDEO
-	if (on)
-		ASSABET_BCR_set(ASSABET_BCR_LIGHT_ON);
-	else
-#endif
-		ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
-}
-
-/*
- * Turn on/off the backlight.  When turning the backlight on,
- * we wait 500us after turning it on so we don't cause the
- * supplies to droop when we enable the LCD controller (and
- * cause a hard reset.)
- */
-static void assabet_lcd_power(int on)
-{
-#ifndef ASSABET_PAL_VIDEO
-	if (on) {
-		ASSABET_BCR_set(ASSABET_BCR_LCD_ON);
-		udelay(500);
-	} else
-#endif
-		ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
+	if (state == UCB_RST_PROBE)
+		ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
 }
 
 
@@ -152,15 +134,8 @@
 };
 
 static struct resource assabet_flash_resources[] = {
-	{
-		.start	= SA1100_CS0_PHYS,
-		.end	= SA1100_CS0_PHYS + SZ_32M - 1,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= SA1100_CS1_PHYS,
-		.end	= SA1100_CS1_PHYS + SZ_32M - 1,
-		.flags	= IORESOURCE_MEM,
-	}
+	DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M),
+	DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_32M),
 };
 
 
@@ -199,18 +174,126 @@
 	.set_speed	= assabet_irda_set_speed,
 };
 
+static struct ucb1x00_plat_data assabet_ucb1x00_data = {
+	.reset		= assabet_ucb1x00_reset,
+	.gpio_base	= -1,
+};
+
 static struct mcp_plat_data assabet_mcp_data = {
 	.mccr0		= MCCR0_ADM,
 	.sclk_rate	= 11981000,
+	.codec_pdata	= &assabet_ucb1x00_data,
 };
 
+static void assabet_lcd_set_visual(u32 visual)
+{
+	u_int is_true_color = visual == FB_VISUAL_TRUECOLOR;
+
+	if (machine_is_assabet()) {
+#if 1		// phase 4 or newer Assabet's
+		if (is_true_color)
+			ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
+		else
+			ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
+#else
+		// older Assabet's
+		if (is_true_color)
+			ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
+		else
+			ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
+#endif
+	}
+}
+
+#ifndef ASSABET_PAL_VIDEO
+static void assabet_lcd_backlight_power(int on)
+{
+	if (on)
+		ASSABET_BCR_set(ASSABET_BCR_LIGHT_ON);
+	else
+		ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
+}
+
+/*
+ * Turn on/off the backlight.  When turning the backlight on, we wait
+ * 500us after turning it on so we don't cause the supplies to droop
+ * when we enable the LCD controller (and cause a hard reset.)
+ */
+static void assabet_lcd_power(int on)
+{
+	if (on) {
+		ASSABET_BCR_set(ASSABET_BCR_LCD_ON);
+		udelay(500);
+	} else
+		ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
+}
+
+/*
+ * The assabet uses a sharp LQ039Q2DS54 LCD module.  It is actually
+ * takes an RGB666 signal, but we provide it with an RGB565 signal
+ * instead (def_rgb_16).
+ */
+static struct sa1100fb_mach_info lq039q2ds54_info = {
+	.pixclock	= 171521,	.bpp		= 16,
+	.xres		= 320,		.yres		= 240,
+
+	.hsync_len	= 5,		.vsync_len	= 1,
+	.left_margin	= 61,		.upper_margin	= 3,
+	.right_margin	= 9,		.lower_margin	= 0,
+
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+
+	.backlight_power = assabet_lcd_backlight_power,
+	.lcd_power = assabet_lcd_power,
+	.set_visual = assabet_lcd_set_visual,
+};
+#else
+static void assabet_pal_backlight_power(int on)
+{
+	ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
+}
+
+static void assabet_pal_power(int on)
+{
+	ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
+}
+
+static struct sa1100fb_mach_info pal_info = {
+	.pixclock	= 67797,	.bpp		= 16,
+	.xres		= 640,		.yres		= 512,
+
+	.hsync_len	= 64,		.vsync_len	= 6,
+	.left_margin	= 125,		.upper_margin	= 70,
+	.right_margin	= 115,		.lower_margin	= 36,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
+
+	.backlight_power = assabet_pal_backlight_power,
+	.lcd_power = assabet_pal_power,
+	.set_visual = assabet_lcd_set_visual,
+};
+#endif
+
+#ifdef CONFIG_ASSABET_NEPONSET
+static struct resource neponset_resources[] = {
+	DEFINE_RES_MEM(0x10000000, 0x08000000),
+	DEFINE_RES_MEM(0x18000000, 0x04000000),
+	DEFINE_RES_MEM(0x40000000, SZ_8K),
+	DEFINE_RES_IRQ(IRQ_GPIO25),
+};
+#endif
+
 static void __init assabet_init(void)
 {
 	/*
 	 * Ensure that the power supply is in "high power" mode.
 	 */
-	GPDR |= GPIO_GPIO16;
 	GPSR = GPIO_GPIO16;
+	GPDR |= GPIO_GPIO16;
 
 	/*
 	 * Ensure that these pins are set as outputs and are driving
@@ -218,8 +301,16 @@
 	 * the WS latch in the CPLD, and we don't float causing
 	 * excessive power drain.  --rmk
 	 */
-	GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
 	GPCR = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
+	GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
+
+	/*
+	 * Also set GPIO27 as an output; this is used to clock UART3
+	 * via the FPGA and as otherwise has no pullups or pulldowns,
+	 * so stop it floating.
+	 */
+	GPCR = GPIO_GPIO27;
+	GPDR |= GPIO_GPIO27;
 
 	/*
 	 * Set up registers for sleep mode.
@@ -231,8 +322,7 @@
 	PPDR |= PPC_TXD3 | PPC_TXD1;
 	PPSR |= PPC_TXD3 | PPC_TXD1;
 
-	sa1100fb_lcd_power = assabet_lcd_power;
-	sa1100fb_backlight_power = assabet_backlight_power;
+	sa11x0_ppc_configure_mcp();
 
 	if (machine_has_neponset()) {
 		/*
@@ -246,9 +336,17 @@
 #ifndef CONFIG_ASSABET_NEPONSET
 		printk( "Warning: Neponset detected but full support "
 			"hasn't been configured in the kernel\n" );
+#else
+		platform_device_register_simple("neponset", 0,
+			neponset_resources, ARRAY_SIZE(neponset_resources));
 #endif
 	}
 
+#ifndef ASSABET_PAL_VIDEO
+	sa11x0_register_lcd(&lq039q2ds54_info);
+#else
+	sa11x0_register_lcd(&pal_video);
+#endif
 	sa11x0_register_mtd(&assabet_flash_data, assabet_flash_resources,
 			    ARRAY_SIZE(assabet_flash_resources));
 	sa11x0_register_irda(&assabet_irda_data);
@@ -412,21 +510,8 @@
 	 */
 	Ser1SDCR0 |= SDCR0_SUS;
 
-	if (machine_has_neponset()) {
-#ifdef CONFIG_ASSABET_NEPONSET
-		extern void neponset_map_io(void);
-
-		/*
-		 * We map Neponset registers even if it isn't present since
-		 * many drivers will try to probe their stuff (and fail).
-		 * This is still more friendly than a kernel paging request
-		 * crash.
-		 */
-		neponset_map_io();
-#endif
-	} else {
+	if (!machine_has_neponset())
 		sa1100_register_uart_fns(&assabet_port_fns);
-	}
 
 	/*
 	 * When Neponset is attached, the first UART should be
@@ -449,6 +534,7 @@
 	.atag_offset	= 0x100,
 	.fixup		= fixup_assabet,
 	.map_io		= assabet_map_io,
+	.nr_irqs	= SA1100_NR_IRQS,
 	.init_irq	= sa1100_init_irq,
 	.timer		= &sa1100_timer,
 	.init_machine	= assabet_init,
diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
index b07a2c0..e0f0c03 100644
--- a/arch/arm/mach-sa1100/badge4.c
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -39,20 +39,27 @@
 #include "generic.h"
 
 static struct resource sa1111_resources[] = {
-	[0] = {
-		.start		= BADGE4_SA1111_BASE,
-		.end		= BADGE4_SA1111_BASE + 0x00001fff,
-		.flags		= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start		= BADGE4_IRQ_GPIO_SA1111,
-		.end		= BADGE4_IRQ_GPIO_SA1111,
-		.flags		= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(BADGE4_SA1111_BASE, 0x2000),
+	[1] = DEFINE_RES_IRQ(BADGE4_IRQ_GPIO_SA1111),
 };
 
+static int badge4_sa1111_enable(void *data, unsigned devid)
+{
+	if (devid == SA1111_DEVID_USB)
+		badge4_set_5V(BADGE4_5V_USB, 1);
+	return 0;
+}
+
+static void badge4_sa1111_disable(void *data, unsigned devid)
+{
+	if (devid == SA1111_DEVID_USB)
+		badge4_set_5V(BADGE4_5V_USB, 0);
+}
+
 static struct sa1111_platform_data sa1111_info = {
-	.irq_base	= IRQ_BOARD_END,
+	.disable_devs	= SA1111_DEVID_PS2_MSE,
+	.enable		= badge4_sa1111_enable,
+	.disable	= badge4_sa1111_disable,
 };
 
 static u64 sa1111_dmamask = 0xffffffffUL;
@@ -121,11 +128,8 @@
 	.nr_parts	= ARRAY_SIZE(badge4_partitions),
 };
 
-static struct resource badge4_flash_resource = {
-	.start		= SA1100_CS0_PHYS,
-	.end		= SA1100_CS0_PHYS + SZ_64M - 1,
-	.flags		= IORESOURCE_MEM,
-};
+static struct resource badge4_flash_resource =
+	DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_64M);
 
 static int five_v_on __initdata = 0;
 
@@ -269,11 +273,6 @@
 		.pfn		= __phys_to_pfn(0x10000000),
 		.length		= 0x00100000,
 		.type		= MT_DEVICE
-	}, {	/* SA-1111      */
-		.virtual	= 0xf4000000,
-		.pfn		= __phys_to_pfn(0x48000000),
-		.length		= 0x00100000,
-		.type		= MT_DEVICE
 	}
 };
 
@@ -304,6 +303,7 @@
 MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4")
 	.atag_offset	= 0x100,
 	.map_io		= badge4_map_io,
+	.nr_irqs	= SA1100_NR_IRQS,
 	.init_irq	= sa1100_init_irq,
 	.timer		= &sa1100_timer,
 #ifdef CONFIG_SA1111
diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c
index 11bb6d0..4a61f60 100644
--- a/arch/arm/mach-sa1100/cerf.c
+++ b/arch/arm/mach-sa1100/cerf.c
@@ -18,7 +18,6 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
-#include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/setup.h>
 
@@ -30,14 +29,11 @@
 
 #include <mach/cerf.h>
 #include <mach/mcp.h>
+#include <mach/irqs.h>
 #include "generic.h"
 
 static struct resource cerfuart2_resources[] = {
-	[0] = {
-		.start	= 0x80030000,
-		.end	= 0x8003ffff,
-		.flags	= IORESOURCE_MEM,
-	},
+	[0] = DEFINE_RES_MEM(0x80030000, SZ_64K),
 };
 
 static struct platform_device cerfuart2_device = {
@@ -87,11 +83,8 @@
 	.nr_parts	= ARRAY_SIZE(cerf_partitions),
 };
 
-static struct resource cerf_flash_resource = {
-	.start		= SA1100_CS0_PHYS,
-	.end		= SA1100_CS0_PHYS + SZ_32M - 1,
-	.flags		= IORESOURCE_MEM,
-};
+static struct resource cerf_flash_resource =
+	DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
 
 static void __init cerf_init_irq(void)
 {
@@ -128,6 +121,7 @@
 
 static void __init cerf_init(void)
 {
+	sa11x0_ppc_configure_mcp();
 	platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
 	sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1);
 	sa11x0_register_mcp(&cerf_mcp_data);
@@ -136,6 +130,7 @@
 MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube")
 	/* Maintainer: support@intrinsyc.com */
 	.map_io		= cerf_map_io,
+	.nr_irqs	= SA1100_NR_IRQS,
 	.init_irq	= cerf_init_irq,
 	.timer		= &sa1100_timer,
 	.init_machine	= cerf_init,
diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c
index dab3c63..172ebd0 100644
--- a/arch/arm/mach-sa1100/clock.c
+++ b/arch/arm/mach-sa1100/clock.c
@@ -11,17 +11,29 @@
 #include <linux/clk.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
 
 #include <mach/hardware.h>
 
-/*
- * Very simple clock implementation - we only have one clock to deal with.
- */
+struct clkops {
+	void			(*enable)(struct clk *);
+	void			(*disable)(struct clk *);
+};
+
 struct clk {
+	const struct clkops	*ops;
 	unsigned int		enabled;
 };
 
-static void clk_gpio27_enable(void)
+#define DEFINE_CLK(_name, _ops)				\
+struct clk clk_##_name = {				\
+		.ops	= _ops,				\
+	}
+
+static DEFINE_SPINLOCK(clocks_lock);
+
+static void clk_gpio27_enable(struct clk *clk)
 {
 	/*
 	 * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
@@ -32,38 +44,24 @@
 	TUCR = TUCR_3_6864MHz;
 }
 
-static void clk_gpio27_disable(void)
+static void clk_gpio27_disable(struct clk *clk)
 {
 	TUCR = 0;
 	GPDR &= ~GPIO_32_768kHz;
 	GAFR &= ~GPIO_32_768kHz;
 }
 
-static struct clk clk_gpio27;
-
-static DEFINE_SPINLOCK(clocks_lock);
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-	const char *devname = dev_name(dev);
-
-	return strcmp(devname, "sa1111.0") ? ERR_PTR(-ENOENT) : &clk_gpio27;
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_put);
-
 int clk_enable(struct clk *clk)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&clocks_lock, flags);
-	if (clk->enabled++ == 0)
-		clk_gpio27_enable();
-	spin_unlock_irqrestore(&clocks_lock, flags);
+	if (clk) {
+		spin_lock_irqsave(&clocks_lock, flags);
+		if (clk->enabled++ == 0)
+			clk->ops->enable(clk);
+		spin_unlock_irqrestore(&clocks_lock, flags);
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL(clk_enable);
@@ -72,17 +70,31 @@
 {
 	unsigned long flags;
 
-	WARN_ON(clk->enabled == 0);
-
-	spin_lock_irqsave(&clocks_lock, flags);
-	if (--clk->enabled == 0)
-		clk_gpio27_disable();
-	spin_unlock_irqrestore(&clocks_lock, flags);
+	if (clk) {
+		WARN_ON(clk->enabled == 0);
+		spin_lock_irqsave(&clocks_lock, flags);
+		if (--clk->enabled == 0)
+			clk->ops->disable(clk);
+		spin_unlock_irqrestore(&clocks_lock, flags);
+	}
 }
 EXPORT_SYMBOL(clk_disable);
 
-unsigned long clk_get_rate(struct clk *clk)
+const struct clkops clk_gpio27_ops = {
+	.enable		= clk_gpio27_enable,
+	.disable	= clk_gpio27_disable,
+};
+
+static DEFINE_CLK(gpio27, &clk_gpio27_ops);
+
+static struct clk_lookup sa11xx_clkregs[] = {
+	CLKDEV_INIT("sa1111.0", NULL, &clk_gpio27),
+	CLKDEV_INIT("sa1100-rtc", NULL, NULL),
+};
+
+static int __init sa11xx_clk_init(void)
 {
-	return 3686400;
+	clkdev_add_table(sa11xx_clkregs, ARRAY_SIZE(sa11xx_clkregs));
+	return 0;
 }
-EXPORT_SYMBOL(clk_get_rate);
+core_initcall(sa11xx_clk_init);
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index fd56521..c7f418b 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -22,15 +22,17 @@
 #include <linux/tty.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/ucb1x00.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/timer.h>
 #include <linux/gpio.h>
 #include <linux/pda_power.h>
 
+#include <video/sa1100fb.h>
+
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/setup.h>
 #include <mach/collie.h>
@@ -44,15 +46,12 @@
 #include <asm/mach/sharpsl_param.h>
 #include <asm/hardware/locomo.h>
 #include <mach/mcp.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
 static struct resource collie_scoop_resources[] = {
-	[0] = {
-		.start		= 0x40800000,
-		.end		= 0x40800fff,
-		.flags		= IORESOURCE_MEM,
-	},
+	[0] = DEFINE_RES_MEM(0x40800000, SZ_4K),
 };
 
 static struct scoop_config collie_scoop_setup = {
@@ -85,10 +84,14 @@
 	.num_devs	= 1,
 };
 
+static struct ucb1x00_plat_data collie_ucb1x00_data = {
+	.gpio_base	= COLLIE_TC35143_GPIO_BASE,
+};
+
 static struct mcp_plat_data collie_mcp_data = {
 	.mccr0		= MCCR0_ADM | MCCR0_ExtClk,
 	.sclk_rate	= 9216000,
-	.gpio_base	= COLLIE_TC35143_GPIO_BASE,
+	.codec_pdata	= &collie_ucb1x00_data,
 };
 
 /*
@@ -221,16 +224,8 @@
 
 
 static struct resource locomo_resources[] = {
-	[0] = {
-		.start		= 0x40000000,
-		.end		= 0x40001fff,
-		.flags		= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start		= IRQ_GPIO25,
-		.end		= IRQ_GPIO25,
-		.flags		= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(0x40000000, SZ_8K),
+	[1] = DEFINE_RES_IRQ(IRQ_GPIO25),
 };
 
 static struct locomo_platform_data locomo_info = {
@@ -303,11 +298,25 @@
 };
 
 static struct resource collie_flash_resources[] = {
-	{
-		.start	= SA1100_CS0_PHYS,
-		.end	= SA1100_CS0_PHYS + SZ_32M - 1,
-		.flags	= IORESOURCE_MEM,
-	}
+	DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M),
+};
+
+static struct sa1100fb_mach_info collie_lcd_info = {
+	.pixclock	= 171521,	.bpp		= 16,
+	.xres		= 320,		.yres		= 240,
+
+	.hsync_len	= 5,		.vsync_len	= 1,
+	.left_margin	= 11,		.upper_margin	= 2,
+	.right_margin	= 30,		.lower_margin	= 0,
+
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+
+#ifdef CONFIG_BACKLIGHT_LOCOMO
+	.lcd_power	= locomolcd_power
+#endif
 };
 
 static void __init collie_init(void)
@@ -341,6 +350,10 @@
 
 	collie_power_resource[0].start = gpio_to_irq(COLLIE_GPIO_AC_IN);
 	collie_power_resource[0].end = gpio_to_irq(COLLIE_GPIO_AC_IN);
+
+	sa11x0_ppc_configure_mcp();
+
+
 	platform_scoop_config = &collie_pcmcia_config;
 
 	ret = platform_add_devices(devices, ARRAY_SIZE(devices));
@@ -348,6 +361,7 @@
 		printk(KERN_WARNING "collie: Unable to register LoCoMo device\n");
 	}
 
+	sa11x0_register_lcd(&collie_lcd_info);
 	sa11x0_register_mtd(&collie_flash_data, collie_flash_resources,
 			    ARRAY_SIZE(collie_flash_resources));
 	sa11x0_register_mcp(&collie_mcp_data);
@@ -383,6 +397,7 @@
 
 MACHINE_START(COLLIE, "Sharp-Collie")
 	.map_io		= collie_map_io,
+	.nr_irqs	= SA1100_NR_IRQS,
 	.init_irq	= sa1100_init_irq,
 	.timer		= &sa1100_timer,
 	.init_machine	= collie_init,
diff --git a/arch/arm/mach-sa1100/dma.c b/arch/arm/mach-sa1100/dma.c
deleted file mode 100644
index ad66035..0000000
--- a/arch/arm/mach-sa1100/dma.c
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * arch/arm/mach-sa1100/dma.c
- *
- * Support functions for the SA11x0 internal DMA channels.
- *
- * Copyright (C) 2000, 2001 by Nicolas Pitre
- *
- * 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/interrupt.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <mach/dma.h>
-
-
-#undef DEBUG
-#ifdef DEBUG
-#define DPRINTK( s, arg... )  printk( "dma<%p>: " s, regs , ##arg )
-#else
-#define DPRINTK( x... )
-#endif
-
-
-typedef struct {
-	const char *device_id;		/* device name */
-	u_long device;			/* this channel device, 0  if unused*/
-	dma_callback_t callback;	/* to call when DMA completes */
-	void *data;			/* ... with private data ptr */
-} sa1100_dma_t;
-
-static sa1100_dma_t dma_chan[SA1100_DMA_CHANNELS];
-
-static DEFINE_SPINLOCK(dma_list_lock);
-
-
-static irqreturn_t dma_irq_handler(int irq, void *dev_id)
-{
-	dma_regs_t *dma_regs = dev_id;
-	sa1100_dma_t *dma = dma_chan + (((u_int)dma_regs >> 5) & 7);
-	int status = dma_regs->RdDCSR;
-
-	if (status & (DCSR_ERROR)) {
-		printk(KERN_CRIT "DMA on \"%s\" caused an error\n", dma->device_id);
-		dma_regs->ClrDCSR = DCSR_ERROR;
-	}
-
-	dma_regs->ClrDCSR = status & (DCSR_DONEA | DCSR_DONEB);
-	if (dma->callback) {
-		if (status & DCSR_DONEA)
-			dma->callback(dma->data);
-		if (status & DCSR_DONEB)
-			dma->callback(dma->data);
-	}
-	return IRQ_HANDLED;
-}
-
-
-/**
- *	sa1100_request_dma - allocate one of the SA11x0's DMA channels
- *	@device: The SA11x0 peripheral targeted by this request
- *	@device_id: An ascii name for the claiming device
- *	@callback: Function to be called when the DMA completes
- *	@data: A cookie passed back to the callback function
- *	@dma_regs: Pointer to the location of the allocated channel's identifier
- *
- * 	This function will search for a free DMA channel and returns the
- * 	address of the hardware registers for that channel as the channel
- * 	identifier. This identifier is written to the location pointed by
- * 	@dma_regs. The list of possible values for @device are listed into
- * 	arch/arm/mach-sa1100/include/mach/dma.h as a dma_device_t enum.
- *
- * 	Note that reading from a port and writing to the same port are
- * 	actually considered as two different streams requiring separate
- * 	DMA registrations.
- *
- * 	The @callback function is called from interrupt context when one
- * 	of the two possible DMA buffers in flight has terminated. That
- * 	function has to be small and efficient while posponing more complex
- * 	processing to a lower priority execution context.
- *
- * 	If no channels are available, or if the desired @device is already in
- * 	use by another DMA channel, then an error code is returned.  This
- * 	function must be called before any other DMA calls.
- **/
-
-int sa1100_request_dma (dma_device_t device, const char *device_id,
-			dma_callback_t callback, void *data,
-			dma_regs_t **dma_regs)
-{
-	sa1100_dma_t *dma = NULL;
-	dma_regs_t *regs;
-	int i, err;
-
-	*dma_regs = NULL;
-
-	err = 0;
-	spin_lock(&dma_list_lock);
-	for (i = 0; i < SA1100_DMA_CHANNELS; i++) {
-		if (dma_chan[i].device == device) {
-			err = -EBUSY;
-			break;
-		} else if (!dma_chan[i].device && !dma) {
-			dma = &dma_chan[i];
-		}
-	}
-	if (!err) {
-		if (dma)
-			dma->device = device;
-		else
-			err = -ENOSR;
-	}
-	spin_unlock(&dma_list_lock);
-	if (err)
-		return err;
-
-	i = dma - dma_chan;
-	regs = (dma_regs_t *)&DDAR(i);
-	err = request_irq(IRQ_DMA0 + i, dma_irq_handler, IRQF_DISABLED,
-			  device_id, regs);
-	if (err) {
-		printk(KERN_ERR
-		       "%s: unable to request IRQ %d for %s\n",
-		       __func__, IRQ_DMA0 + i, device_id);
-		dma->device = 0;
-		return err;
-	}
-
-	*dma_regs = regs;
-	dma->device_id = device_id;
-	dma->callback = callback;
-	dma->data = data;
-
-	regs->ClrDCSR =
-		(DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
-		 DCSR_IE | DCSR_ERROR | DCSR_RUN);
-	regs->DDAR = device;
-
-	return 0;
-}
-
-
-/**
- * 	sa1100_free_dma - free a SA11x0 DMA channel
- * 	@regs: identifier for the channel to free
- *
- * 	This clears all activities on a given DMA channel and releases it
- * 	for future requests.  The @regs identifier is provided by a
- * 	successful call to sa1100_request_dma().
- **/
-
-void sa1100_free_dma(dma_regs_t *regs)
-{
-	int i;
-
-	for (i = 0; i < SA1100_DMA_CHANNELS; i++)
-		if (regs == (dma_regs_t *)&DDAR(i))
-			break;
-	if (i >= SA1100_DMA_CHANNELS) {
-		printk(KERN_ERR "%s: bad DMA identifier\n", __func__);
-		return;
-	}
-
-	if (!dma_chan[i].device) {
-		printk(KERN_ERR "%s: Trying to free free DMA\n", __func__);
-		return;
-	}
-
-	regs->ClrDCSR =
-		(DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
-		 DCSR_IE | DCSR_ERROR | DCSR_RUN);
-	free_irq(IRQ_DMA0 + i, regs);
-	dma_chan[i].device = 0;
-}
-
-
-/**
- * 	sa1100_start_dma - submit a data buffer for DMA
- * 	@regs: identifier for the channel to use
- * 	@dma_ptr: buffer physical (or bus) start address
- * 	@size: buffer size
- *
- * 	This function hands the given data buffer to the hardware for DMA
- * 	access. If another buffer is already in flight then this buffer
- * 	will be queued so the DMA engine will switch to it automatically
- * 	when the previous one is done.  The DMA engine is actually toggling
- * 	between two buffers so at most 2 successful calls can be made before
- * 	one of them terminates and the callback function is called.
- *
- * 	The @regs identifier is provided by a successful call to
- * 	sa1100_request_dma().
- *
- * 	The @size must not be larger than %MAX_DMA_SIZE.  If a given buffer
- * 	is larger than that then it's the caller's responsibility to split
- * 	it into smaller chunks and submit them separately. If this is the
- * 	case then a @size of %CUT_DMA_SIZE is recommended to avoid ending
- * 	up with too small chunks. The callback function can be used to chain
- * 	submissions of buffer chunks.
- *
- * 	Error return values:
- * 	%-EOVERFLOW:	Given buffer size is too big.
- * 	%-EBUSY:	Both DMA buffers are already in use.
- * 	%-EAGAIN:	Both buffers were busy but one of them just completed
- * 			but the interrupt handler has to execute first.
- *
- * 	This function returs 0 on success.
- **/
-
-int sa1100_start_dma(dma_regs_t *regs, dma_addr_t dma_ptr, u_int size)
-{
-	unsigned long flags;
-	u_long status;
-	int ret;
-
-	if (dma_ptr & 3)
-		printk(KERN_WARNING "DMA: unaligned start address (0x%08lx)\n",
-		       (unsigned long)dma_ptr);
-
-	if (size > MAX_DMA_SIZE)
-		return -EOVERFLOW;
-
-	local_irq_save(flags);
-	status = regs->RdDCSR;
-
-	/* If both DMA buffers are started, there's nothing else we can do. */
-	if ((status & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB)) {
-		DPRINTK("start: st %#x busy\n", status);
-		ret = -EBUSY;
-		goto out;
-	}
-
-	if (((status & DCSR_BIU) && (status & DCSR_STRTB)) ||
-	    (!(status & DCSR_BIU) && !(status & DCSR_STRTA))) {
-		if (status & DCSR_DONEA) {
-			/* give a chance for the interrupt to be processed */
-			ret = -EAGAIN;
-			goto out;
-		}
-		regs->DBSA = dma_ptr;
-		regs->DBTA = size;
-		regs->SetDCSR = DCSR_STRTA | DCSR_IE | DCSR_RUN;
-		DPRINTK("start a=%#x s=%d on A\n", dma_ptr, size);
-	} else {
-		if (status & DCSR_DONEB) {
-			/* give a chance for the interrupt to be processed */
-			ret = -EAGAIN;
-			goto out;
-		}
-		regs->DBSB = dma_ptr;
-		regs->DBTB = size;
-		regs->SetDCSR = DCSR_STRTB | DCSR_IE | DCSR_RUN;
-		DPRINTK("start a=%#x s=%d on B\n", dma_ptr, size);
-	}
-	ret = 0;
-
-out:
-	local_irq_restore(flags);
-	return ret;
-}
-
-
-/**
- * 	sa1100_get_dma_pos - return current DMA position
- * 	@regs: identifier for the channel to use
- *
- * 	This function returns the current physical (or bus) address for the
- * 	given DMA channel.  If the channel is running i.e. not in a stopped
- * 	state then the caller must disable interrupts prior calling this
- * 	function and process the returned value before re-enabling them to
- * 	prevent races with the completion interrupt handler and the callback
- * 	function. The validation of the returned value is the caller's
- * 	responsibility as well -- the hardware seems to return out of range
- * 	values when the DMA engine completes a buffer.
- *
- * 	The @regs identifier is provided by a successful call to
- * 	sa1100_request_dma().
- **/
-
-dma_addr_t sa1100_get_dma_pos(dma_regs_t *regs)
-{
-	int status;
-
-	/*
-	 * We must determine whether buffer A or B is active.
-	 * Two possibilities: either we are in the middle of
-	 * a buffer, or the DMA controller just switched to the
-	 * next toggle but the interrupt hasn't been serviced yet.
-	 * The former case is straight forward.  In the later case,
-	 * we'll do like if DMA is just at the end of the previous
-	 * toggle since all registers haven't been reset yet.
-	 * This goes around the edge case and since we're always
-	 * a little behind anyways it shouldn't make a big difference.
-	 * If DMA has been stopped prior calling this then the
-	 * position is exact.
-	 */
-	status = regs->RdDCSR;
-	if ((!(status & DCSR_BIU) &&  (status & DCSR_STRTA)) ||
-	    ( (status & DCSR_BIU) && !(status & DCSR_STRTB)))
-		return regs->DBSA;
-	else
-		return regs->DBSB;
-}
-
-
-/**
- * 	sa1100_reset_dma - reset a DMA channel
- * 	@regs: identifier for the channel to use
- *
- * 	This function resets and reconfigure the given DMA channel. This is
- * 	particularly useful after a sleep/wakeup event.
- *
- * 	The @regs identifier is provided by a successful call to
- * 	sa1100_request_dma().
- **/
-
-void sa1100_reset_dma(dma_regs_t *regs)
-{
-	int i;
-
-	for (i = 0; i < SA1100_DMA_CHANNELS; i++)
-		if (regs == (dma_regs_t *)&DDAR(i))
-			break;
-	if (i >= SA1100_DMA_CHANNELS) {
-		printk(KERN_ERR "%s: bad DMA identifier\n", __func__);
-		return;
-	}
-
-	regs->ClrDCSR =
-		(DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
-		 DCSR_IE | DCSR_ERROR | DCSR_RUN);
-	regs->DDAR = dma_chan[i].device;
-}
-
-
-EXPORT_SYMBOL(sa1100_request_dma);
-EXPORT_SYMBOL(sa1100_free_dma);
-EXPORT_SYMBOL(sa1100_start_dma);
-EXPORT_SYMBOL(sa1100_get_dma_pos);
-EXPORT_SYMBOL(sa1100_reset_dma);
-
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index bb10ee2..7c524b4 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -14,17 +14,22 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/pm.h>
 #include <linux/cpufreq.h>
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 
+#include <video/sa1100fb.h>
+
 #include <asm/div64.h>
-#include <mach/hardware.h>
-#include <asm/system.h>
 #include <asm/mach/map.h>
 #include <asm/mach/flash.h>
 #include <asm/irq.h>
+#include <asm/system_misc.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -149,16 +154,8 @@
 
 
 static struct resource sa11x0udc_resources[] = {
-	[0] = {
-		.start	= __PREG(Ser0UDCCR),
-		.end	= __PREG(Ser0UDCCR) + 0xffff,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_Ser0UDC,
-		.end	= IRQ_Ser0UDC,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(__PREG(Ser0UDCCR), SZ_64K),
+	[1] = DEFINE_RES_IRQ(IRQ_Ser0UDC),
 };
 
 static u64 sa11x0udc_dma_mask = 0xffffffffUL;
@@ -175,16 +172,8 @@
 };
 
 static struct resource sa11x0uart1_resources[] = {
-	[0] = {
-		.start	= __PREG(Ser1UTCR0),
-		.end	= __PREG(Ser1UTCR0) + 0xffff,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_Ser1UART,
-		.end	= IRQ_Ser1UART,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(__PREG(Ser1UTCR0), SZ_64K),
+	[1] = DEFINE_RES_IRQ(IRQ_Ser1UART),
 };
 
 static struct platform_device sa11x0uart1_device = {
@@ -195,16 +184,8 @@
 };
 
 static struct resource sa11x0uart3_resources[] = {
-	[0] = {
-		.start	= __PREG(Ser3UTCR0),
-		.end	= __PREG(Ser3UTCR0) + 0xffff,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_Ser3UART,
-		.end	= IRQ_Ser3UART,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(__PREG(Ser3UTCR0), SZ_64K),
+	[1] = DEFINE_RES_IRQ(IRQ_Ser3UART),
 };
 
 static struct platform_device sa11x0uart3_device = {
@@ -215,16 +196,9 @@
 };
 
 static struct resource sa11x0mcp_resources[] = {
-	[0] = {
-		.start	= __PREG(Ser4MCCR0),
-		.end	= __PREG(Ser4MCCR0) + 0xffff,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_Ser4MCP,
-		.end	= IRQ_Ser4MCP,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(__PREG(Ser4MCCR0), SZ_64K),
+	[1] = DEFINE_RES_MEM(__PREG(Ser4MCCR1), 4),
+	[2] = DEFINE_RES_IRQ(IRQ_Ser4MCP),
 };
 
 static u64 sa11x0mcp_dma_mask = 0xffffffffUL;
@@ -240,22 +214,24 @@
 	.resource	= sa11x0mcp_resources,
 };
 
+void __init sa11x0_ppc_configure_mcp(void)
+{
+	/* Setup the PPC unit for the MCP */
+	PPDR &= ~PPC_RXD4;
+	PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+	PSDR |= PPC_RXD4;
+	PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+	PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+}
+
 void sa11x0_register_mcp(struct mcp_plat_data *data)
 {
 	sa11x0_register_device(&sa11x0mcp_device, data);
 }
 
 static struct resource sa11x0ssp_resources[] = {
-	[0] = {
-		.start	= 0x80070000,
-		.end	= 0x8007ffff,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_Ser4SSP,
-		.end	= IRQ_Ser4SSP,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(0x80070000, SZ_64K),
+	[1] = DEFINE_RES_IRQ(IRQ_Ser4SSP),
 };
 
 static u64 sa11x0ssp_dma_mask = 0xffffffffUL;
@@ -272,16 +248,8 @@
 };
 
 static struct resource sa11x0fb_resources[] = {
-	[0] = {
-		.start	= 0xb0100000,
-		.end	= 0xb010ffff,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_LCD,
-		.end	= IRQ_LCD,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(0xb0100000, SZ_64K),
+	[1] = DEFINE_RES_IRQ(IRQ_LCD),
 };
 
 static struct platform_device sa11x0fb_device = {
@@ -294,6 +262,11 @@
 	.resource	= sa11x0fb_resources,
 };
 
+void sa11x0_register_lcd(struct sa1100fb_mach_info *inf)
+{
+	sa11x0_register_device(&sa11x0fb_device, inf);
+}
+
 static struct platform_device sa11x0pcmcia_device = {
 	.name		= "sa11x0-pcmcia",
 	.id		= -1,
@@ -314,23 +287,10 @@
 }
 
 static struct resource sa11x0ir_resources[] = {
-	{
-		.start	= __PREG(Ser2UTCR0),
-		.end	= __PREG(Ser2UTCR0) + 0x24 - 1,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= __PREG(Ser2HSCR0),
-		.end	= __PREG(Ser2HSCR0) + 0x1c - 1,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= __PREG(Ser2HSCR2),
-		.end	= __PREG(Ser2HSCR2) + 0x04 - 1,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= IRQ_Ser2ICP,
-		.end	= IRQ_Ser2ICP,
-		.flags	= IORESOURCE_IRQ,
-	}
+	DEFINE_RES_MEM(__PREG(Ser2UTCR0), 0x24),
+	DEFINE_RES_MEM(__PREG(Ser2HSCR0), 0x1c),
+	DEFINE_RES_MEM(__PREG(Ser2HSCR2), 0x04),
+	DEFINE_RES_IRQ(IRQ_Ser2ICP),
 };
 
 static struct platform_device sa11x0ir_device = {
@@ -345,9 +305,40 @@
 	sa11x0_register_device(&sa11x0ir_device, irda);
 }
 
+static struct resource sa1100_rtc_resources[] = {
+	DEFINE_RES_MEM(0x90010000, 0x9001003f),
+	DEFINE_RES_IRQ_NAMED(IRQ_RTC1Hz, "rtc 1Hz"),
+	DEFINE_RES_IRQ_NAMED(IRQ_RTCAlrm, "rtc alarm"),
+};
+
 static struct platform_device sa11x0rtc_device = {
 	.name		= "sa1100-rtc",
 	.id		= -1,
+	.num_resources	= ARRAY_SIZE(sa1100_rtc_resources),
+	.resource	= sa1100_rtc_resources,
+};
+
+static struct resource sa11x0dma_resources[] = {
+	DEFINE_RES_MEM(DMA_PHYS, DMA_SIZE),
+	DEFINE_RES_IRQ(IRQ_DMA0),
+	DEFINE_RES_IRQ(IRQ_DMA1),
+	DEFINE_RES_IRQ(IRQ_DMA2),
+	DEFINE_RES_IRQ(IRQ_DMA3),
+	DEFINE_RES_IRQ(IRQ_DMA4),
+	DEFINE_RES_IRQ(IRQ_DMA5),
+};
+
+static u64 sa11x0dma_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device sa11x0dma_device = {
+	.name		= "sa11x0-dma",
+	.id		= -1,
+	.dev = {
+		.dma_mask = &sa11x0dma_dma_mask,
+		.coherent_dma_mask = 0xffffffff,
+	},
+	.num_resources	= ARRAY_SIZE(sa11x0dma_resources),
+	.resource	= sa11x0dma_resources,
 };
 
 static struct platform_device *sa11x0_devices[] __initdata = {
@@ -356,8 +347,8 @@
 	&sa11x0uart3_device,
 	&sa11x0ssp_device,
 	&sa11x0pcmcia_device,
-	&sa11x0fb_device,
 	&sa11x0rtc_device,
+	&sa11x0dma_device,
 };
 
 static int __init sa1100_init(void)
@@ -368,12 +359,6 @@
 
 arch_initcall(sa1100_init);
 
-void (*sa1100fb_backlight_power)(int on);
-void (*sa1100fb_lcd_power)(int on);
-
-EXPORT_SYMBOL(sa1100fb_backlight_power);
-EXPORT_SYMBOL(sa1100fb_lcd_power);
-
 
 /*
  * Common I/O mapping:
@@ -428,7 +413,7 @@
  * the MBGNT signal false to ensure the SA1111 doesn't own the
  * SDRAM bus.
  */
-void __init sa1110_mb_disable(void)
+void sa1110_mb_disable(void)
 {
 	unsigned long flags;
 
@@ -447,7 +432,7 @@
  * If the system is going to use the SA-1111 DMA engines, set up
  * the memory bus request/grant pins.
  */
-void __devinit sa1110_mb_enable(void)
+void sa1110_mb_enable(void)
 {
 	unsigned long flags;
 
diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h
index 33268cf..9eb3b3c 100644
--- a/arch/arm/mach-sa1100/generic.h
+++ b/arch/arm/mach-sa1100/generic.h
@@ -16,9 +16,6 @@
 	mi->bank[__nr].start = (__start), \
 	mi->bank[__nr].size = (__size)
 
-extern void (*sa1100fb_backlight_power)(int on);
-extern void (*sa1100fb_lcd_power)(int on);
-
 extern void sa1110_mb_enable(void);
 extern void sa1110_mb_disable(void);
 
@@ -39,4 +36,8 @@
 void sa11x0_register_irda(struct irda_platform_data *irda);
 
 struct mcp_plat_data;
+void sa11x0_ppc_configure_mcp(void);
 void sa11x0_register_mcp(struct mcp_plat_data *data);
+
+struct sa1100fb_mach_info;
+void sa11x0_register_lcd(struct sa1100fb_mach_info *inf);
diff --git a/arch/arm/mach-sa1100/h3100.c b/arch/arm/mach-sa1100/h3100.c
index 1e6b3c1..b2e8d0f 100644
--- a/arch/arm/mach-sa1100/h3100.c
+++ b/arch/arm/mach-sa1100/h3100.c
@@ -14,11 +14,14 @@
 #include <linux/kernel.h>
 #include <linux/gpio.h>
 
+#include <video/sa1100fb.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irda.h>
 
 #include <mach/h3xxx.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -36,13 +39,28 @@
 	}
 }
 
+static struct sa1100fb_mach_info h3100_lcd_info = {
+	.pixclock	= 406977, 	.bpp		= 4,
+	.xres		= 320,		.yres		= 240,
+
+	.hsync_len	= 26,		.vsync_len	= 41,
+	.left_margin	= 4,		.upper_margin	= 0,
+	.right_margin	= 4,		.lower_margin	= 0,
+
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.cmap_greyscale	= 1,
+	.cmap_inverse	= 1,
+
+	.lccr0		= LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+
+	.lcd_power = h3100_lcd_power,
+};
 
 static void __init h3100_map_io(void)
 {
 	h3xxx_map_io();
 
-	sa1100fb_lcd_power = h3100_lcd_power;
-
 	/* Older bootldrs put GPIO2-9 in alternate mode on the
 	   assumption that they are used for video */
 	GAFR &= ~0x000001fb;
@@ -80,12 +98,15 @@
 {
 	h3xxx_init_gpio(h3100_default_gpio, ARRAY_SIZE(h3100_default_gpio));
 	h3xxx_mach_init();
+
+	sa11x0_register_lcd(&h3100_lcd_info);
 	sa11x0_register_irda(&h3100_irda_data);
 }
 
 MACHINE_START(H3100, "Compaq iPAQ H3100")
 	.atag_offset	= 0x100,
 	.map_io		= h3100_map_io,
+	.nr_irqs	= SA1100_NR_IRQS,
 	.init_irq	= sa1100_init_irq,
 	.timer		= &sa1100_timer,
 	.init_machine	= h3100_mach_init,
diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
index 6b58e74..cb6659f 100644
--- a/arch/arm/mach-sa1100/h3600.c
+++ b/arch/arm/mach-sa1100/h3600.c
@@ -14,11 +14,14 @@
 #include <linux/kernel.h>
 #include <linux/gpio.h>
 
+#include <video/sa1100fb.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irda.h>
 
 #include <mach/h3xxx.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -56,11 +59,35 @@
 err1:	return;
 }
 
+static const struct sa1100fb_rgb h3600_rgb_16 = {
+	.red	= { .offset = 12, .length = 4, },
+	.green	= { .offset = 7,  .length = 4, },
+	.blue	= { .offset = 1,  .length = 4, },
+	.transp	= { .offset = 0,  .length = 0, },
+};
+
+static struct sa1100fb_mach_info h3600_lcd_info = {
+	.pixclock	= 174757, 	.bpp		= 16,
+	.xres		= 320,		.yres		= 240,
+
+	.hsync_len	= 3,		.vsync_len	= 3,
+	.left_margin	= 12,		.upper_margin	= 10,
+	.right_margin	= 17,		.lower_margin	= 1,
+
+	.cmap_static	= 1,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+
+	.rgb[RGB_16] = &h3600_rgb_16,
+
+	.lcd_power = h3600_lcd_power,
+};
+
+
 static void __init h3600_map_io(void)
 {
 	h3xxx_map_io();
-
-	sa1100fb_lcd_power = h3600_lcd_power;
 }
 
 /*
@@ -121,12 +148,15 @@
 {
 	h3xxx_init_gpio(h3600_default_gpio, ARRAY_SIZE(h3600_default_gpio));
 	h3xxx_mach_init();
+
+	sa11x0_register_lcd(&h3600_lcd_info);
 	sa11x0_register_irda(&h3600_irda_data);
 }
 
 MACHINE_START(H3600, "Compaq iPAQ H3600")
 	.atag_offset	= 0x100,
 	.map_io		= h3600_map_io,
+	.nr_irqs	= SA1100_NR_IRQS,
 	.init_irq	= sa1100_init_irq,
 	.timer		= &sa1100_timer,
 	.init_machine	= h3600_mach_init,
diff --git a/arch/arm/mach-sa1100/h3xxx.c b/arch/arm/mach-sa1100/h3xxx.c
index b0784c9..63150e1 100644
--- a/arch/arm/mach-sa1100/h3xxx.c
+++ b/arch/arm/mach-sa1100/h3xxx.c
@@ -109,11 +109,8 @@
 	.nr_parts	= ARRAY_SIZE(h3xxx_partitions),
 };
 
-static struct resource h3xxx_flash_resource = {
-	.start		= SA1100_CS0_PHYS,
-	.end		= SA1100_CS0_PHYS + SZ_32M - 1,
-	.flags		= IORESOURCE_MEM,
-};
+static struct resource h3xxx_flash_resource =
+	DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
 
 
 /*
@@ -186,11 +183,7 @@
  */
 
 static struct resource egpio_resources[] = {
-	[0] = {
-		.start	= H3600_EGPIO_PHYS,
-		.end	= H3600_EGPIO_PHYS + 0x4 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
+	[0] = DEFINE_RES_MEM(H3600_EGPIO_PHYS, 0x4),
 };
 
 static struct htc_egpio_chip egpio_chips[] = {
diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c
index c01bb36..5535475 100644
--- a/arch/arm/mach-sa1100/hackkit.c
+++ b/arch/arm/mach-sa1100/hackkit.c
@@ -22,12 +22,10 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/irq.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
@@ -35,6 +33,9 @@
 #include <asm/mach/irq.h>
 #include <asm/mach/serial_sa1100.h>
 
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
 #include "generic.h"
 
 /**********************************************************************
@@ -179,11 +180,8 @@
 	.nr_parts	= ARRAY_SIZE(hackkit_partitions),
 };
 
-static struct resource hackkit_flash_resource = {
-	.start		= SA1100_CS0_PHYS,
-	.end		= SA1100_CS0_PHYS + SZ_32M,
-	.flags		= IORESOURCE_MEM,
-};
+static struct resource hackkit_flash_resource =
+	DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
 
 static void __init hackkit_init(void)
 {
@@ -197,6 +195,7 @@
 MACHINE_START(HACKKIT, "HackKit Cpu Board")
 	.atag_offset	= 0x100,
 	.map_io		= hackkit_map_io,
+	.nr_irqs	= SA1100_NR_IRQS,
 	.init_irq	= sa1100_init_irq,
 	.timer		= &sa1100_timer,
 	.init_machine	= hackkit_init,
diff --git a/arch/arm/mach-sa1100/include/mach/SA-1100.h b/arch/arm/mach-sa1100/include/mach/SA-1100.h
index bae8296..3f2d1b6 100644
--- a/arch/arm/mach-sa1100/include/mach/SA-1100.h
+++ b/arch/arm/mach-sa1100/include/mach/SA-1100.h
@@ -1590,224 +1590,9 @@
 
 /*
  * Direct Memory Access (DMA) control registers
- *
- * Registers
- *    DDAR0     	Direct Memory Access (DMA) Device Address Register
- *              	channel 0 (read/write).
- *    DCSR0     	Direct Memory Access (DMA) Control and Status
- *              	Register channel 0 (read/write).
- *    DBSA0     	Direct Memory Access (DMA) Buffer Start address
- *              	register A channel 0 (read/write).
- *    DBTA0     	Direct Memory Access (DMA) Buffer Transfer count
- *              	register A channel 0 (read/write).
- *    DBSB0     	Direct Memory Access (DMA) Buffer Start address
- *              	register B channel 0 (read/write).
- *    DBTB0     	Direct Memory Access (DMA) Buffer Transfer count
- *              	register B channel 0 (read/write).
- *
- *    DDAR1     	Direct Memory Access (DMA) Device Address Register
- *              	channel 1 (read/write).
- *    DCSR1     	Direct Memory Access (DMA) Control and Status
- *              	Register channel 1 (read/write).
- *    DBSA1     	Direct Memory Access (DMA) Buffer Start address
- *              	register A channel 1 (read/write).
- *    DBTA1     	Direct Memory Access (DMA) Buffer Transfer count
- *              	register A channel 1 (read/write).
- *    DBSB1     	Direct Memory Access (DMA) Buffer Start address
- *              	register B channel 1 (read/write).
- *    DBTB1     	Direct Memory Access (DMA) Buffer Transfer count
- *              	register B channel 1 (read/write).
- *
- *    DDAR2     	Direct Memory Access (DMA) Device Address Register
- *              	channel 2 (read/write).
- *    DCSR2     	Direct Memory Access (DMA) Control and Status
- *              	Register channel 2 (read/write).
- *    DBSA2     	Direct Memory Access (DMA) Buffer Start address
- *              	register A channel 2 (read/write).
- *    DBTA2     	Direct Memory Access (DMA) Buffer Transfer count
- *              	register A channel 2 (read/write).
- *    DBSB2     	Direct Memory Access (DMA) Buffer Start address
- *              	register B channel 2 (read/write).
- *    DBTB2     	Direct Memory Access (DMA) Buffer Transfer count
- *              	register B channel 2 (read/write).
- *
- *    DDAR3     	Direct Memory Access (DMA) Device Address Register
- *              	channel 3 (read/write).
- *    DCSR3     	Direct Memory Access (DMA) Control and Status
- *              	Register channel 3 (read/write).
- *    DBSA3     	Direct Memory Access (DMA) Buffer Start address
- *              	register A channel 3 (read/write).
- *    DBTA3     	Direct Memory Access (DMA) Buffer Transfer count
- *              	register A channel 3 (read/write).
- *    DBSB3     	Direct Memory Access (DMA) Buffer Start address
- *              	register B channel 3 (read/write).
- *    DBTB3     	Direct Memory Access (DMA) Buffer Transfer count
- *              	register B channel 3 (read/write).
- *
- *    DDAR4     	Direct Memory Access (DMA) Device Address Register
- *              	channel 4 (read/write).
- *    DCSR4     	Direct Memory Access (DMA) Control and Status
- *              	Register channel 4 (read/write).
- *    DBSA4     	Direct Memory Access (DMA) Buffer Start address
- *              	register A channel 4 (read/write).
- *    DBTA4     	Direct Memory Access (DMA) Buffer Transfer count
- *              	register A channel 4 (read/write).
- *    DBSB4     	Direct Memory Access (DMA) Buffer Start address
- *              	register B channel 4 (read/write).
- *    DBTB4     	Direct Memory Access (DMA) Buffer Transfer count
- *              	register B channel 4 (read/write).
- *
- *    DDAR5     	Direct Memory Access (DMA) Device Address Register
- *              	channel 5 (read/write).
- *    DCSR5     	Direct Memory Access (DMA) Control and Status
- *              	Register channel 5 (read/write).
- *    DBSA5     	Direct Memory Access (DMA) Buffer Start address
- *              	register A channel 5 (read/write).
- *    DBTA5     	Direct Memory Access (DMA) Buffer Transfer count
- *              	register A channel 5 (read/write).
- *    DBSB5     	Direct Memory Access (DMA) Buffer Start address
- *              	register B channel 5 (read/write).
- *    DBTB5     	Direct Memory Access (DMA) Buffer Transfer count
- *              	register B channel 5 (read/write).
  */
-
-#define DMASp   	0x00000020	/* DMA control reg. Space [byte]   */
-
-#define DDAR(Nb)	__REG(0xB0000000 + (Nb)*DMASp)  /* DMA Device Address Reg. channel [0..5] */
-#define SetDCSR(Nb)	__REG(0xB0000004 + (Nb)*DMASp)  /* Set DMA Control & Status Reg. channel [0..5] (write) */
-#define ClrDCSR(Nb)	__REG(0xB0000008 + (Nb)*DMASp)  /* Clear DMA Control & Status Reg. channel [0..5] (write) */
-#define RdDCSR(Nb)	__REG(0xB000000C + (Nb)*DMASp)  /* Read DMA Control & Status Reg. channel [0..5] (read) */
-#define DBSA(Nb)	__REG(0xB0000010 + (Nb)*DMASp)  /* DMA Buffer Start address reg. A channel [0..5] */
-#define DBTA(Nb)	__REG(0xB0000014 + (Nb)*DMASp)  /* DMA Buffer Transfer count reg. A channel [0..5] */
-#define DBSB(Nb)	__REG(0xB0000018 + (Nb)*DMASp)  /* DMA Buffer Start address reg. B channel [0..5] */
-#define DBTB(Nb)	__REG(0xB000001C + (Nb)*DMASp)  /* DMA Buffer Transfer count reg. B channel [0..5] */
-
-#define DDAR_RW 	0x00000001	/* device data Read/Write          */
-#define DDAR_DevWr	(DDAR_RW*0)	/*  Device data Write              */
-                	        	/*  (memory -> device)             */
-#define DDAR_DevRd	(DDAR_RW*1)	/*  Device data Read               */
-                	        	/*  (device -> memory)             */
-#define DDAR_E  	0x00000002	/* big/little Endian device        */
-#define DDAR_LtlEnd	(DDAR_E*0)	/*  Little Endian device           */
-#define DDAR_BigEnd	(DDAR_E*1)	/*  Big Endian device              */
-#define DDAR_BS 	0x00000004	/* device Burst Size               */
-#define DDAR_Brst4	(DDAR_BS*0)	/*  Burst-of-4 device              */
-#define DDAR_Brst8	(DDAR_BS*1)	/*  Burst-of-8 device              */
-#define DDAR_DW 	0x00000008	/* device Data Width               */
-#define DDAR_8BitDev	(DDAR_DW*0)	/*  8-Bit Device                   */
-#define DDAR_16BitDev	(DDAR_DW*1)	/*  16-Bit Device                  */
-#define DDAR_DS 	Fld (4, 4)	/* Device Select                   */
-#define DDAR_Ser0UDCTr	        	/*  Ser. port 0 UDC Transmit       */ \
-                	(0x0 << FShft (DDAR_DS))
-#define DDAR_Ser0UDCRc	        	/*  Ser. port 0 UDC Receive        */ \
-                	(0x1 << FShft (DDAR_DS))
-#define DDAR_Ser1SDLCTr	        	/*  Ser. port 1 SDLC Transmit      */ \
-                	(0x2 << FShft (DDAR_DS))
-#define DDAR_Ser1SDLCRc	        	/*  Ser. port 1 SDLC Receive       */ \
-                	(0x3 << FShft (DDAR_DS))
-#define DDAR_Ser1UARTTr	        	/*  Ser. port 1 UART Transmit      */ \
-                	(0x4 << FShft (DDAR_DS))
-#define DDAR_Ser1UARTRc	        	/*  Ser. port 1 UART Receive       */ \
-                	(0x5 << FShft (DDAR_DS))
-#define DDAR_Ser2ICPTr	        	/*  Ser. port 2 ICP Transmit       */ \
-                	(0x6 << FShft (DDAR_DS))
-#define DDAR_Ser2ICPRc	        	/*  Ser. port 2 ICP Receive        */ \
-                	(0x7 << FShft (DDAR_DS))
-#define DDAR_Ser3UARTTr	        	/*  Ser. port 3 UART Transmit      */ \
-                	(0x8 << FShft (DDAR_DS))
-#define DDAR_Ser3UARTRc	        	/*  Ser. port 3 UART Receive       */ \
-                	(0x9 << FShft (DDAR_DS))
-#define DDAR_Ser4MCP0Tr	        	/*  Ser. port 4 MCP 0 Transmit     */ \
-                	        	/*  (audio)                        */ \
-                	(0xA << FShft (DDAR_DS))
-#define DDAR_Ser4MCP0Rc	        	/*  Ser. port 4 MCP 0 Receive      */ \
-                	        	/*  (audio)                        */ \
-                	(0xB << FShft (DDAR_DS))
-#define DDAR_Ser4MCP1Tr	        	/*  Ser. port 4 MCP 1 Transmit     */ \
-                	        	/*  (telecom)                      */ \
-                	(0xC << FShft (DDAR_DS))
-#define DDAR_Ser4MCP1Rc	        	/*  Ser. port 4 MCP 1 Receive      */ \
-                	        	/*  (telecom)                      */ \
-                	(0xD << FShft (DDAR_DS))
-#define DDAR_Ser4SSPTr	        	/*  Ser. port 4 SSP Transmit       */ \
-                	(0xE << FShft (DDAR_DS))
-#define DDAR_Ser4SSPRc	        	/*  Ser. port 4 SSP Receive        */ \
-                	(0xF << FShft (DDAR_DS))
-#define DDAR_DA 	Fld (24, 8)	/* Device Address                  */
-#define DDAR_DevAdd(Add)        	/*  Device Address                 */ \
-                	(((Add) & 0xF0000000) | \
-                	 (((Add) & 0X003FFFFC) << (FShft (DDAR_DA) - 2)))
-#define DDAR_Ser0UDCWr	        	/* Ser. port 0 UDC Write           */ \
-                	(DDAR_DevWr + DDAR_Brst8 + DDAR_8BitDev + \
-                	 DDAR_Ser0UDCTr + DDAR_DevAdd (__PREG(Ser0UDCDR)))
-#define DDAR_Ser0UDCRd	        	/* Ser. port 0 UDC Read            */ \
-                	(DDAR_DevRd + DDAR_Brst8 + DDAR_8BitDev + \
-                	 DDAR_Ser0UDCRc + DDAR_DevAdd (__PREG(Ser0UDCDR)))
-#define DDAR_Ser1UARTWr	        	/* Ser. port 1 UART Write          */ \
-                	(DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
-                	 DDAR_Ser1UARTTr + DDAR_DevAdd (__PREG(Ser1UTDR)))
-#define DDAR_Ser1UARTRd	        	/* Ser. port 1 UART Read           */ \
-                	(DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
-                	 DDAR_Ser1UARTRc + DDAR_DevAdd (__PREG(Ser1UTDR)))
-#define DDAR_Ser1SDLCWr	        	/* Ser. port 1 SDLC Write          */ \
-                	(DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
-                	 DDAR_Ser1SDLCTr + DDAR_DevAdd (__PREG(Ser1SDDR)))
-#define DDAR_Ser1SDLCRd	        	/* Ser. port 1 SDLC Read           */ \
-                	(DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
-                	 DDAR_Ser1SDLCRc + DDAR_DevAdd (__PREG(Ser1SDDR)))
-#define DDAR_Ser2UARTWr	        	/* Ser. port 2 UART Write          */ \
-                	(DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
-                	 DDAR_Ser2ICPTr + DDAR_DevAdd (__PREG(Ser2UTDR)))
-#define DDAR_Ser2UARTRd	        	/* Ser. port 2 UART Read           */ \
-                	(DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
-                	 DDAR_Ser2ICPRc + DDAR_DevAdd (__PREG(Ser2UTDR)))
-#define DDAR_Ser2HSSPWr	        	/* Ser. port 2 HSSP Write          */ \
-                	(DDAR_DevWr + DDAR_Brst8 + DDAR_8BitDev + \
-                	 DDAR_Ser2ICPTr + DDAR_DevAdd (__PREG(Ser2HSDR)))
-#define DDAR_Ser2HSSPRd	        	/* Ser. port 2 HSSP Read           */ \
-                	(DDAR_DevRd + DDAR_Brst8 + DDAR_8BitDev + \
-                	 DDAR_Ser2ICPRc + DDAR_DevAdd (__PREG(Ser2HSDR)))
-#define DDAR_Ser3UARTWr	        	/* Ser. port 3 UART Write          */ \
-                	(DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
-                	 DDAR_Ser3UARTTr + DDAR_DevAdd (__PREG(Ser3UTDR)))
-#define DDAR_Ser3UARTRd	        	/* Ser. port 3 UART Read           */ \
-                	(DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
-                	 DDAR_Ser3UARTRc + DDAR_DevAdd (__PREG(Ser3UTDR)))
-#define DDAR_Ser4MCP0Wr	        	/* Ser. port 4 MCP 0 Write (audio) */ \
-                	(DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \
-                	 DDAR_Ser4MCP0Tr + DDAR_DevAdd (__PREG(Ser4MCDR0)))
-#define DDAR_Ser4MCP0Rd	        	/* Ser. port 4 MCP 0 Read (audio)  */ \
-                	(DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \
-                	 DDAR_Ser4MCP0Rc + DDAR_DevAdd (__PREG(Ser4MCDR0)))
-#define DDAR_Ser4MCP1Wr	        	/* Ser. port 4 MCP 1 Write         */ \
-                	        	/* (telecom)                       */ \
-                	(DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \
-                	 DDAR_Ser4MCP1Tr + DDAR_DevAdd (__PREG(Ser4MCDR1)))
-#define DDAR_Ser4MCP1Rd	        	/* Ser. port 4 MCP 1 Read          */ \
-                	        	/* (telecom)                       */ \
-                	(DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \
-                	 DDAR_Ser4MCP1Rc + DDAR_DevAdd (__PREG(Ser4MCDR1)))
-#define DDAR_Ser4SSPWr	        	/* Ser. port 4 SSP Write (16 bits) */ \
-                	(DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \
-                	 DDAR_Ser4SSPTr + DDAR_DevAdd (__PREG(Ser4SSDR)))
-#define DDAR_Ser4SSPRd	        	/* Ser. port 4 SSP Read (16 bits)  */ \
-                	(DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \
-                	 DDAR_Ser4SSPRc + DDAR_DevAdd (__PREG(Ser4SSDR)))
-
-#define DCSR_RUN	0x00000001	/* DMA running                     */
-#define DCSR_IE 	0x00000002	/* DMA Interrupt Enable            */
-#define DCSR_ERROR	0x00000004	/* DMA ERROR                       */
-#define DCSR_DONEA	0x00000008	/* DONE DMA transfer buffer A      */
-#define DCSR_STRTA	0x00000010	/* STaRTed DMA transfer buffer A   */
-#define DCSR_DONEB	0x00000020	/* DONE DMA transfer buffer B      */
-#define DCSR_STRTB	0x00000040	/* STaRTed DMA transfer buffer B   */
-#define DCSR_BIU	0x00000080	/* DMA Buffer In Use               */
-#define DCSR_BufA	(DCSR_BIU*0)	/*  DMA Buffer A in use            */
-#define DCSR_BufB	(DCSR_BIU*1)	/*  DMA Buffer B in use            */
-
-#define DBT_TC  	Fld (13, 0)	/* Transfer Count                  */
-#define DBTA_TCA	DBT_TC  	/* Transfer Count buffer A         */
-#define DBTB_TCB	DBT_TC  	/* Transfer Count buffer B         */
+#define DMA_SIZE	(6 * 0x20)
+#define DMA_PHYS	0xb0000000
 
 
 /*
@@ -1903,16 +1688,6 @@
 #define LCD_Int100_0A	0xF     	/* LCD Intensity = 100.0% =  1     */
                 	        	/* (Alternative)                   */
 
-#define LCCR0		__REG(0xB0100000)  /* LCD Control Reg. 0 */
-#define LCSR		__REG(0xB0100004)  /* LCD Status Reg. */
-#define DBAR1		__REG(0xB0100010)  /* LCD DMA Base Address Reg. channel 1 */
-#define DCAR1		__REG(0xB0100014)  /* LCD DMA Current Address Reg. channel 1 */
-#define DBAR2		__REG(0xB0100018)  /* LCD DMA Base Address Reg.  channel 2 */
-#define DCAR2		__REG(0xB010001C)  /* LCD DMA Current Address Reg. channel 2 */
-#define LCCR1		__REG(0xB0100020)  /* LCD Control Reg. 1 */
-#define LCCR2		__REG(0xB0100024)  /* LCD Control Reg. 2 */
-#define LCCR3		__REG(0xB0100028)  /* LCD Control Reg. 3 */
-
 #define LCCR0_LEN	0x00000001	/* LCD ENable                      */
 #define LCCR0_CMS	0x00000002	/* Color/Monochrome display Select */
 #define LCCR0_Color	(LCCR0_CMS*0)	/*  Color display                  */
diff --git a/arch/arm/mach-sa1100/include/mach/assabet.h b/arch/arm/mach-sa1100/include/mach/assabet.h
index 28c2cf5..3073914 100644
--- a/arch/arm/mach-sa1100/include/mach/assabet.h
+++ b/arch/arm/mach-sa1100/include/mach/assabet.h
@@ -85,21 +85,18 @@
 #define ASSABET_BSR_RAD_RI	(1 << 31)
 
 
-/* GPIOs for which the generic definition doesn't say much */
+/* GPIOs (bitmasks) for which the generic definition doesn't say much */
 #define ASSABET_GPIO_RADIO_IRQ		GPIO_GPIO (14)	/* Radio interrupt request  */
 #define ASSABET_GPIO_PS_MODE_SYNC	GPIO_GPIO (16)	/* Power supply mode/sync   */
 #define ASSABET_GPIO_STEREO_64FS_CLK	GPIO_GPIO (19)	/* SSP UDA1341 clock input  */
-#define ASSABET_GPIO_CF_IRQ		GPIO_GPIO (21)	/* CF IRQ   */
-#define ASSABET_GPIO_CF_CD		GPIO_GPIO (22)	/* CF CD */
-#define ASSABET_GPIO_CF_BVD2		GPIO_GPIO (24)	/* CF BVD */
 #define ASSABET_GPIO_GFX_IRQ		GPIO_GPIO (24)	/* Graphics IRQ */
-#define ASSABET_GPIO_CF_BVD1		GPIO_GPIO (25)	/* CF BVD */
 #define ASSABET_GPIO_BATT_LOW		GPIO_GPIO (26)	/* Low battery */
 #define ASSABET_GPIO_RCLK		GPIO_GPIO (26)	/* CCLK/2  */
 
-#define ASSABET_IRQ_GPIO_CF_IRQ		IRQ_GPIO21
-#define ASSABET_IRQ_GPIO_CF_CD		IRQ_GPIO22
-#define ASSABET_IRQ_GPIO_CF_BVD2	IRQ_GPIO24
-#define ASSABET_IRQ_GPIO_CF_BVD1	IRQ_GPIO25
+/* These are gpiolib GPIO numbers, not bitmasks */
+#define ASSABET_GPIO_CF_IRQ		21	/* CF IRQ */
+#define ASSABET_GPIO_CF_CD		22	/* CF CD  */
+#define ASSABET_GPIO_CF_BVD2		24	/* CF BVD / IOSPKR */
+#define ASSABET_GPIO_CF_BVD1		25	/* CF BVD / IOSTSCHG */
 
 #endif
diff --git a/arch/arm/mach-sa1100/include/mach/cerf.h b/arch/arm/mach-sa1100/include/mach/cerf.h
index c3ac3d0..88fd9c0 100644
--- a/arch/arm/mach-sa1100/include/mach/cerf.h
+++ b/arch/arm/mach-sa1100/include/mach/cerf.h
@@ -14,15 +14,10 @@
 #define CERF_ETH_IO			0xf0000000
 #define CERF_ETH_IRQ IRQ_GPIO26
 
-#define CERF_GPIO_CF_BVD2		GPIO_GPIO (19)
-#define CERF_GPIO_CF_BVD1		GPIO_GPIO (20)
-#define CERF_GPIO_CF_RESET		GPIO_GPIO (21)
-#define CERF_GPIO_CF_IRQ		GPIO_GPIO (22)
-#define CERF_GPIO_CF_CD			GPIO_GPIO (23)
-
-#define CERF_IRQ_GPIO_CF_BVD2		IRQ_GPIO19
-#define CERF_IRQ_GPIO_CF_BVD1		IRQ_GPIO20
-#define CERF_IRQ_GPIO_CF_IRQ		IRQ_GPIO22
-#define CERF_IRQ_GPIO_CF_CD		IRQ_GPIO23
+#define CERF_GPIO_CF_BVD2		19
+#define CERF_GPIO_CF_BVD1		20
+#define CERF_GPIO_CF_RESET		21
+#define CERF_GPIO_CF_IRQ		22
+#define CERF_GPIO_CF_CD			23
 
 #endif // _INCLUDE_CERF_H_
diff --git a/arch/arm/mach-sa1100/include/mach/collie.h b/arch/arm/mach-sa1100/include/mach/collie.h
index 52acda7..f33679d 100644
--- a/arch/arm/mach-sa1100/include/mach/collie.h
+++ b/arch/arm/mach-sa1100/include/mach/collie.h
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-sa1100/include/mach/collie.h
  *
- * This file contains the hardware specific definitions for Assabet
+ * This file contains the hardware specific definitions for Collie
  * Only include this file from SA1100-specific files.
  *
  * ChangeLog:
@@ -13,6 +13,7 @@
 #ifndef __ASM_ARCH_COLLIE_H
 #define __ASM_ARCH_COLLIE_H
 
+extern void locomolcd_power(int on);
 
 #define COLLIE_SCOOP_GPIO_BASE	(GPIO_MAX + 1)
 #define COLLIE_GPIO_CHARGE_ON	(COLLIE_SCOOP_GPIO_BASE + 0)
diff --git a/arch/arm/mach-sa1100/include/mach/dma.h b/arch/arm/mach-sa1100/include/mach/dma.h
deleted file mode 100644
index dda1b35..0000000
--- a/arch/arm/mach-sa1100/include/mach/dma.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * arch/arm/mach-sa1100/include/mach/dma.h
- *
- * Generic SA1100 DMA support
- *
- * Copyright (C) 2000 Nicolas Pitre
- *
- */
-
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-#include "hardware.h"
-
-
-/*
- * The SA1100 has six internal DMA channels.
- */
-#define SA1100_DMA_CHANNELS	6
-
-/*
- * Maximum physical DMA buffer size
- */
-#define MAX_DMA_SIZE		0x1fff
-#define CUT_DMA_SIZE		0x1000
-
-/*
- * All possible SA1100 devices a DMA channel can be attached to.
- */
-typedef enum {
-	DMA_Ser0UDCWr  = DDAR_Ser0UDCWr,   /* Ser. port 0 UDC Write */
-	DMA_Ser0UDCRd  = DDAR_Ser0UDCRd,   /* Ser. port 0 UDC Read */
-	DMA_Ser1UARTWr = DDAR_Ser1UARTWr,  /* Ser. port 1 UART Write */
-	DMA_Ser1UARTRd = DDAR_Ser1UARTRd,  /* Ser. port 1 UART Read */
-	DMA_Ser1SDLCWr = DDAR_Ser1SDLCWr,  /* Ser. port 1 SDLC Write */
-	DMA_Ser1SDLCRd = DDAR_Ser1SDLCRd,  /* Ser. port 1 SDLC Read */
-	DMA_Ser2UARTWr = DDAR_Ser2UARTWr,  /* Ser. port 2 UART Write */
-	DMA_Ser2UARTRd = DDAR_Ser2UARTRd,  /* Ser. port 2 UART Read */
-	DMA_Ser2HSSPWr = DDAR_Ser2HSSPWr,  /* Ser. port 2 HSSP Write */
-	DMA_Ser2HSSPRd = DDAR_Ser2HSSPRd,  /* Ser. port 2 HSSP Read */
-	DMA_Ser3UARTWr = DDAR_Ser3UARTWr,  /* Ser. port 3 UART Write */
-	DMA_Ser3UARTRd = DDAR_Ser3UARTRd,  /* Ser. port 3 UART Read */
-	DMA_Ser4MCP0Wr = DDAR_Ser4MCP0Wr,  /* Ser. port 4 MCP 0 Write (audio) */
-	DMA_Ser4MCP0Rd = DDAR_Ser4MCP0Rd,  /* Ser. port 4 MCP 0 Read (audio) */
-	DMA_Ser4MCP1Wr = DDAR_Ser4MCP1Wr,  /* Ser. port 4 MCP 1 Write */
-	DMA_Ser4MCP1Rd = DDAR_Ser4MCP1Rd,  /* Ser. port 4 MCP 1 Read */
-	DMA_Ser4SSPWr  = DDAR_Ser4SSPWr,   /* Ser. port 4 SSP Write (16 bits) */
-	DMA_Ser4SSPRd  = DDAR_Ser4SSPRd    /* Ser. port 4 SSP Read (16 bits) */
-} dma_device_t;
-
-typedef struct {
-	volatile u_long DDAR;
-	volatile u_long SetDCSR;
-	volatile u_long ClrDCSR;
-	volatile u_long RdDCSR;
-	volatile dma_addr_t DBSA;
-	volatile u_long DBTA;
-	volatile dma_addr_t DBSB;
-	volatile u_long DBTB;
-} dma_regs_t;
-
-typedef void (*dma_callback_t)(void *data);
-
-/*
- * DMA function prototypes
- */
-
-extern int sa1100_request_dma( dma_device_t device, const char *device_id,
-			       dma_callback_t callback, void *data,
-			       dma_regs_t **regs );
-extern void sa1100_free_dma( dma_regs_t *regs );
-extern int sa1100_start_dma( dma_regs_t *regs, dma_addr_t dma_ptr, u_int size );
-extern dma_addr_t sa1100_get_dma_pos(dma_regs_t *regs);
-extern void sa1100_reset_dma(dma_regs_t *regs);
-
-/**
- * 	sa1100_stop_dma - stop DMA in progress
- * 	@regs: identifier for the channel to use
- *
- * 	This stops DMA without clearing buffer pointers. Unlike
- * 	sa1100_clear_dma() this allows subsequent use of sa1100_resume_dma()
- * 	or sa1100_get_dma_pos().
- *
- * 	The @regs identifier is provided by a successful call to
- * 	sa1100_request_dma().
- **/
-
-#define sa1100_stop_dma(regs)	((regs)->ClrDCSR = DCSR_IE|DCSR_RUN)
-
-/**
- * 	sa1100_resume_dma - resume DMA on a stopped channel
- * 	@regs: identifier for the channel to use
- *
- * 	This resumes DMA on a channel previously stopped with
- * 	sa1100_stop_dma().
- *
- * 	The @regs identifier is provided by a successful call to
- * 	sa1100_request_dma().
- **/
-
-#define sa1100_resume_dma(regs)	((regs)->SetDCSR = DCSR_IE|DCSR_RUN)
-
-/**
- * 	sa1100_clear_dma - clear DMA pointers
- * 	@regs: identifier for the channel to use
- *
- * 	This clear any DMA state so the DMA engine is ready to restart
- * 	with new buffers through sa1100_start_dma(). Any buffers in flight
- * 	are discarded.
- *
- * 	The @regs identifier is provided by a successful call to
- * 	sa1100_request_dma().
- **/
-
-#define sa1100_clear_dma(regs)	((regs)->ClrDCSR = DCSR_IE|DCSR_RUN|DCSR_STRTA|DCSR_STRTB)
-
-#endif /* _ASM_ARCH_DMA_H */
diff --git a/arch/arm/mach-sa1100/include/mach/entry-macro.S b/arch/arm/mach-sa1100/include/mach/entry-macro.S
index 6aa13c4..8cf7630 100644
--- a/arch/arm/mach-sa1100/include/mach/entry-macro.S
+++ b/arch/arm/mach-sa1100/include/mach/entry-macro.S
@@ -8,17 +8,11 @@
  * warranty of any kind, whether express or implied.
  */
 
- 		.macro	disable_fiq
-		.endm
-
 		.macro  get_irqnr_preamble, base, tmp
 		mov	\base, #0xfa000000		@ ICIP = 0xfa050000
 		add	\base, \base, #0x00050000
 		.endm
 
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
-
 		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 		ldr	\irqstat, [\base]		@ get irqs
 		ldr	\irqnr, [\base, #4]		@ ICMR = 0xfa050004
diff --git a/arch/arm/mach-sa1100/include/mach/io.h b/arch/arm/mach-sa1100/include/mach/io.h
deleted file mode 100644
index dfc27ff..0000000
--- a/arch/arm/mach-sa1100/include/mach/io.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * arch/arm/mach-sa1100/include/mach/io.h
- *
- * Copyright (C) 1997-1999 Russell King
- *
- * Modifications:
- *  06-12-1997	RMK	Created.
- *  07-04-1999	RMK	Major cleanup
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/*
- * __io() is required to be an equivalent mapping to __mem_pci() for
- * SOC_COMMON to work.
- */
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#endif
diff --git a/arch/arm/mach-sa1100/include/mach/irqs.h b/arch/arm/mach-sa1100/include/mach/irqs.h
index d18f21a..3790298 100644
--- a/arch/arm/mach-sa1100/include/mach/irqs.h
+++ b/arch/arm/mach-sa1100/include/mach/irqs.h
@@ -71,22 +71,19 @@
 /*
  * Figure out the MAX IRQ number.
  *
- * If we have an SA1111, the max IRQ is S1_BVD1_STSCHG+1.
- * If we have an LoCoMo, the max IRQ is IRQ_BOARD_START + 4
- * Otherwise, we have the standard IRQs only.
+ * Neponset, SA1111 and UCB1x00 are sparse IRQ aware, so can dynamically
+ * allocate their IRQs above NR_IRQS.
+ *
+ * LoCoMo has 4 additional IRQs, but is not sparse IRQ aware, and so has
+ * to be included in the NR_IRQS calculation.
  */
-#ifdef CONFIG_SA1111
-#define NR_IRQS			(IRQ_BOARD_END + 55)
-#elif defined(CONFIG_SHARP_LOCOMO)
-#define NR_IRQS			(IRQ_BOARD_START + 4)
+#ifdef CONFIG_SHARP_LOCOMO
+#define NR_IRQS_LOCOMO		4
 #else
-#define NR_IRQS			(IRQ_BOARD_START)
+#define NR_IRQS_LOCOMO		0
 #endif
 
-/*
- * Board specific IRQs.  Define them here.
- * Do not surround them with ifdefs.
- */
-#define IRQ_NEPONSET_SMC9196	(IRQ_BOARD_START + 0)
-#define IRQ_NEPONSET_USAR	(IRQ_BOARD_START + 1)
-#define IRQ_NEPONSET_SA1111	(IRQ_BOARD_START + 2)
+#ifndef NR_IRQS
+#define NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO)
+#endif
+#define SA1100_NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO)
diff --git a/arch/arm/mach-sa1100/include/mach/mcp.h b/arch/arm/mach-sa1100/include/mach/mcp.h
index ed1a331..4b2860ae 100644
--- a/arch/arm/mach-sa1100/include/mach/mcp.h
+++ b/arch/arm/mach-sa1100/include/mach/mcp.h
@@ -16,7 +16,7 @@
 	u32 mccr0;
 	u32 mccr1;
 	unsigned int sclk_rate;
-	int gpio_base;
+	void *codec_pdata;
 };
 
 #endif
diff --git a/arch/arm/mach-sa1100/include/mach/nanoengine.h b/arch/arm/mach-sa1100/include/mach/nanoengine.h
index 14f8382..5ebd469 100644
--- a/arch/arm/mach-sa1100/include/mach/nanoengine.h
+++ b/arch/arm/mach-sa1100/include/mach/nanoengine.h
@@ -16,12 +16,12 @@
 
 #include <mach/irqs.h>
 
-#define GPIO_PC_READY0	GPIO_GPIO(11) /* ready for socket 0 (active high)*/
-#define GPIO_PC_READY1	GPIO_GPIO(12) /* ready for socket 1 (active high) */
-#define GPIO_PC_CD0	GPIO_GPIO(13) /* detect for socket 0 (active low) */
-#define GPIO_PC_CD1	GPIO_GPIO(14) /* detect for socket 1 (active low) */
-#define GPIO_PC_RESET0	GPIO_GPIO(15) /* reset socket 0 */
-#define GPIO_PC_RESET1	GPIO_GPIO(16) /* reset socket 1 */
+#define GPIO_PC_READY0	11 /* ready for socket 0 (active high)*/
+#define GPIO_PC_READY1	12 /* ready for socket 1 (active high) */
+#define GPIO_PC_CD0	13 /* detect for socket 0 (active low) */
+#define GPIO_PC_CD1	14 /* detect for socket 1 (active low) */
+#define GPIO_PC_RESET0	15 /* reset socket 0 */
+#define GPIO_PC_RESET1	16 /* reset socket 1 */
 
 #define NANOENGINE_IRQ_GPIO_PCI		IRQ_GPIO0
 #define NANOENGINE_IRQ_GPIO_PC_READY0	IRQ_GPIO11
diff --git a/arch/arm/mach-sa1100/include/mach/neponset.h b/arch/arm/mach-sa1100/include/mach/neponset.h
index ffe2bc4..5516a52 100644
--- a/arch/arm/mach-sa1100/include/mach/neponset.h
+++ b/arch/arm/mach-sa1100/include/mach/neponset.h
@@ -15,54 +15,6 @@
 /*
  * Neponset definitions: 
  */
-
-#define NEPONSET_CPLD_BASE      (0x10000000)
-#define Nep_p2v( x )            ((x) - NEPONSET_CPLD_BASE + 0xf3000000)
-#define Nep_v2p( x )            ((x) - 0xf3000000 + NEPONSET_CPLD_BASE)
-
-#define _IRR                    0x10000024      /* Interrupt Reason Register */
-#define _AUD_CTL                0x100000c0      /* Audio controls (RW)       */
-#define _MDM_CTL_0              0x100000b0      /* Modem control 0 (RW)      */
-#define _MDM_CTL_1              0x100000b4      /* Modem control 1 (RW)      */
-#define _NCR_0	                0x100000a0      /* Control Register (RW)     */
-#define _KP_X_OUT               0x10000090      /* Keypad row write (RW)     */
-#define _KP_Y_IN                0x10000080      /* Keypad column read (RO)   */
-#define _SWPK                   0x10000020      /* Switch pack (RO)          */
-#define _WHOAMI                 0x10000000      /* System ID Register (RO)   */
-
-#define _LEDS                   0x10000010      /* LEDs [31:0] (WO)          */
-
-#define IRR                     (*((volatile u_char *) Nep_p2v(_IRR)))
-#define AUD_CTL                 (*((volatile u_char *) Nep_p2v(_AUD_CTL)))
-#define MDM_CTL_0               (*((volatile u_char *) Nep_p2v(_MDM_CTL_0)))
-#define MDM_CTL_1               (*((volatile u_char *) Nep_p2v(_MDM_CTL_1)))
-#define NCR_0			(*((volatile u_char *) Nep_p2v(_NCR_0)))
-#define KP_X_OUT                (*((volatile u_char *) Nep_p2v(_KP_X_OUT)))
-#define KP_Y_IN                 (*((volatile u_char *) Nep_p2v(_KP_Y_IN)))
-#define SWPK                    (*((volatile u_char *) Nep_p2v(_SWPK)))
-#define WHOAMI                  (*((volatile u_char *) Nep_p2v(_WHOAMI)))
-
-#define LEDS                    (*((volatile Word   *) Nep_p2v(_LEDS)))
-
-#define IRR_ETHERNET		(1<<0)
-#define IRR_USAR		(1<<1)
-#define IRR_SA1111		(1<<2)
-
-#define AUD_SEL_1341            (1<<0)
-#define AUD_MUTE_1341           (1<<1)
-
-#define MDM_CTL0_RTS1		(1 << 0)
-#define MDM_CTL0_DTR1		(1 << 1)
-#define MDM_CTL0_RTS2		(1 << 2)
-#define MDM_CTL0_DTR2		(1 << 3)
-
-#define MDM_CTL1_CTS1		(1 << 0)
-#define MDM_CTL1_DSR1		(1 << 1)
-#define MDM_CTL1_DCD1		(1 << 2)
-#define MDM_CTL1_CTS2		(1 << 3)
-#define MDM_CTL1_DSR2		(1 << 4)
-#define MDM_CTL1_DCD2		(1 << 5)
-
 #define NCR_GP01_OFF		(1<<0)
 #define NCR_TP_PWR_EN		(1<<1)
 #define NCR_MS_PWR_EN		(1<<2)
@@ -71,4 +23,8 @@
 #define NCR_A0VPP		(1<<5)
 #define NCR_A1VPP		(1<<6)
 
+void neponset_ncr_frob(unsigned int, unsigned int);
+#define neponset_ncr_set(v)	neponset_ncr_frob(0, v)
+#define neponset_ncr_clear(v)	neponset_ncr_frob(v, 0)
+
 #endif
diff --git a/arch/arm/mach-sa1100/include/mach/shannon.h b/arch/arm/mach-sa1100/include/mach/shannon.h
index ec27d6e..fff39e0 100644
--- a/arch/arm/mach-sa1100/include/mach/shannon.h
+++ b/arch/arm/mach-sa1100/include/mach/shannon.h
@@ -21,16 +21,12 @@
 #define SHANNON_GPIO_U3_RTS		GPIO_GPIO (19)	/* ?? */
 #define SHANNON_GPIO_U3_CTS		GPIO_GPIO (20)	/* ?? */
 #define SHANNON_GPIO_SENSE_12V		GPIO_GPIO (21)	/* Input, 12v flash unprotect detected */
-#define SHANNON_GPIO_DISP_EN		GPIO_GPIO (22)	/* out */
+#define SHANNON_GPIO_DISP_EN		22		/* out */
 /* XXX GPIO 23 unaccounted for */
-#define SHANNON_GPIO_EJECT_0		GPIO_GPIO (24)	/* in */
-#define SHANNON_IRQ_GPIO_EJECT_0	IRQ_GPIO24
-#define SHANNON_GPIO_EJECT_1		GPIO_GPIO (25)	/* in */
-#define SHANNON_IRQ_GPIO_EJECT_1	IRQ_GPIO25
-#define SHANNON_GPIO_RDY_0		GPIO_GPIO (26)	/* in */
-#define SHANNON_IRQ_GPIO_RDY_0		IRQ_GPIO26
-#define SHANNON_GPIO_RDY_1		GPIO_GPIO (27)	/* in */
-#define SHANNON_IRQ_GPIO_RDY_1		IRQ_GPIO27
+#define SHANNON_GPIO_EJECT_0		24		/* in */
+#define SHANNON_GPIO_EJECT_1		25		/* in */
+#define SHANNON_GPIO_RDY_0		26		/* in */
+#define SHANNON_GPIO_RDY_1		27		/* in */
 
 /* MCP UCB codec GPIO pins... */
 
diff --git a/arch/arm/mach-sa1100/include/mach/simpad.h b/arch/arm/mach-sa1100/include/mach/simpad.h
index db28118..cdea671 100644
--- a/arch/arm/mach-sa1100/include/mach/simpad.h
+++ b/arch/arm/mach-sa1100/include/mach/simpad.h
@@ -39,10 +39,8 @@
 
 
 /*---  PCMCIA  ---*/
-#define GPIO_CF_CD              GPIO_GPIO24
-#define GPIO_CF_IRQ             GPIO_GPIO1
-#define IRQ_GPIO_CF_IRQ         IRQ_GPIO1
-#define IRQ_GPIO_CF_CD          IRQ_GPIO24
+#define GPIO_CF_CD              24
+#define GPIO_CF_IRQ             1
 
 /*--- SmartCard ---*/
 #define GPIO_SMART_CARD		GPIO_GPIO10
diff --git a/arch/arm/mach-sa1100/include/mach/system.h b/arch/arm/mach-sa1100/include/mach/system.h
deleted file mode 100644
index e17b208..0000000
--- a/arch/arm/mach-sa1100/include/mach/system.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * arch/arm/mach-sa1100/include/mach/system.h
- *
- * Copyright (c) 1999 Nicolas Pitre <nico@fluxnic.net>
- */
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
index dfbf824..516ccc2 100644
--- a/arch/arm/mach-sa1100/irq.c
+++ b/arch/arm/mach-sa1100/irq.c
@@ -17,6 +17,7 @@
 #include <linux/syscore_ops.h>
 
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 #include <asm/mach/irq.h>
 
 #include "generic.h"
@@ -221,11 +222,8 @@
 	.irq_set_wake	= sa1100_set_wake,
 };
 
-static struct resource irq_resource = {
-	.name	= "irqs",
-	.start	= 0x90050000,
-	.end	= 0x9005ffff,
-};
+static struct resource irq_resource =
+	DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs");
 
 static struct sa1100irq_state {
 	unsigned int	saved;
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
index ee121d6..ca7a7e8 100644
--- a/arch/arm/mach-sa1100/jornada720.c
+++ b/arch/arm/mach-sa1100/jornada720.c
@@ -23,9 +23,7 @@
 #include <linux/mtd/partitions.h>
 #include <video/s1d13xxxfb.h>
 
-#include <mach/hardware.h>
 #include <asm/hardware/sa1111.h>
-#include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
@@ -34,6 +32,9 @@
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
 
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
 #include "generic.h"
 
 /*
@@ -46,7 +47,7 @@
 
 /* memory space (line 52 of HP's doc) */
 #define SA1111REGSTART	0x40000000
-#define SA1111REGLEN	0x00001fff
+#define SA1111REGLEN	0x00002000
 #define EPSONREGSTART	0x48000000
 #define EPSONREGLEN	0x00100000
 #define EPSONFBSTART	0x48200000
@@ -174,16 +175,8 @@
 };
 
 static struct resource s1d13xxxfb_resources[] = {
-	[0] = {
-		.start	= EPSONFBSTART,
-		.end	= EPSONFBSTART + EPSONFBLEN,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= EPSONREGSTART,
-		.end	= EPSONREGSTART + EPSONREGLEN,
-		.flags	= IORESOURCE_MEM,
-	}
+	[0] = DEFINE_RES_MEM(EPSONFBSTART, EPSONFBLEN),
+	[1] = DEFINE_RES_MEM(EPSONREGSTART, EPSONREGLEN),
 };
 
 static struct platform_device s1d13xxxfb_device = {
@@ -197,20 +190,12 @@
 };
 
 static struct resource sa1111_resources[] = {
-	[0] = {
-		.start		= SA1111REGSTART,
-		.end		= SA1111REGSTART + SA1111REGLEN,
-		.flags		= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start		= IRQ_GPIO1,
-		.end		= IRQ_GPIO1,
-		.flags		= IORESOURCE_IRQ,
-	},
+	[0] = DEFINE_RES_MEM(SA1111REGSTART, SA1111REGLEN),
+	[1] = DEFINE_RES_IRQ(IRQ_GPIO1),
 };
 
 static struct sa1111_platform_data sa1111_info = {
-	.irq_base	= IRQ_BOARD_END,
+	.disable_devs	= SA1111_DEVID_PS2_MSE,
 };
 
 static u64 sa1111_dmamask = 0xffffffffUL;
@@ -284,11 +269,6 @@
 		.pfn		= __phys_to_pfn(EPSONFBSTART),
 		.length		= EPSONFBLEN,
 		.type		= MT_DEVICE
-	}, {	/* SA-1111 */
-		.virtual	= 0xf4000000,
-		.pfn		= __phys_to_pfn(SA1111REGSTART),
-		.length		= SA1111REGLEN,
-		.type		= MT_DEVICE
 	}
 };
 
@@ -352,11 +332,8 @@
 	.nr_parts	= ARRAY_SIZE(jornada720_partitions),
 };
 
-static struct resource jornada720_flash_resource = {
-	.start		= SA1100_CS0_PHYS,
-	.end		= SA1100_CS0_PHYS + SZ_32M - 1,
-	.flags		= IORESOURCE_MEM,
-};
+static struct resource jornada720_flash_resource =
+	DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
 
 static void __init jornada720_mach_init(void)
 {
@@ -367,6 +344,7 @@
 	/* Maintainer: Kristoffer Ericson <Kristoffer.Ericson@gmail.com> */
 	.atag_offset	= 0x100,
 	.map_io		= jornada720_map_io,
+	.nr_irqs	= SA1100_NR_IRQS,
 	.init_irq	= sa1100_init_irq,
 	.timer		= &sa1100_timer,
 	.init_machine	= jornada720_mach_init,
diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c
index af4e276..eb6534e 100644
--- a/arch/arm/mach-sa1100/lart.c
+++ b/arch/arm/mach-sa1100/lart.c
@@ -6,6 +6,8 @@
 #include <linux/kernel.h>
 #include <linux/tty.h>
 
+#include <video/sa1100fb.h>
+
 #include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -15,6 +17,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
 #include <mach/mcp.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -26,8 +29,86 @@
 	.sclk_rate	= 11981000,
 };
 
+#ifdef LART_GREY_LCD
+static struct sa1100fb_mach_info lart_grey_info = {
+	.pixclock	= 150000,	.bpp		= 4,
+	.xres		= 320,		.yres		= 240,
+
+	.hsync_len	= 1,		.vsync_len	= 1,
+	.left_margin	= 4,		.upper_margin	= 0,
+	.right_margin	= 2,		.lower_margin	= 0,
+
+	.cmap_greyscale	= 1,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	.lccr0		= LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+#ifdef LART_COLOR_LCD
+static struct sa1100fb_mach_info lart_color_info = {
+	.pixclock	= 150000,	.bpp		= 16,
+	.xres		= 320,		.yres		= 240,
+
+	.hsync_len	= 2,		.vsync_len	= 3,
+	.left_margin	= 69,		.upper_margin	= 14,
+	.right_margin	= 8,		.lower_margin	= 4,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+#ifdef LART_VIDEO_OUT
+static struct sa1100fb_mach_info lart_video_info = {
+	.pixclock	= 39721,	.bpp		= 16,
+	.xres		= 640,		.yres		= 480,
+
+	.hsync_len	= 95,		.vsync_len	= 2,
+	.left_margin	= 40,		.upper_margin	= 32,
+	.right_margin	= 24,		.lower_margin	= 11,
+
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+
+#ifdef LART_KIT01_LCD
+static struct sa1100fb_mach_info lart_kit01_info = {
+	.pixclock	= 63291,	.bpp		= 16,
+	.xres		= 640,		.yres		= 480,
+
+	.hsync_len	= 64,		.vsync_len	= 3,
+	.left_margin	= 122,		.upper_margin	= 45,
+	.right_margin	= 10,		.lower_margin	= 10,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixFlEdg
+};
+#endif
+
 static void __init lart_init(void)
 {
+	struct sa1100fb_mach_info *inf = NULL;
+
+#ifdef LART_GREY_LCD
+	inf = &lart_grey_info;
+#endif
+#ifdef LART_COLOR_LCD
+	inf = &lart_color_info;
+#endif
+#ifdef LART_VIDEO_OUT
+	inf = &lart_video_info;
+#endif
+#ifdef LART_KIT01_LCD
+	inf = &lart_kit01_info;
+#endif
+
+	if (inf)
+		sa11x0_register_lcd(inf);
+
+	sa11x0_ppc_configure_mcp();
 	sa11x0_register_mcp(&lart_mcp_data);
 }
 
@@ -63,6 +144,7 @@
 MACHINE_START(LART, "LART")
 	.atag_offset	= 0x100,
 	.map_io		= lart_map_io,
+	.nr_irqs	= SA1100_NR_IRQS,
 	.init_irq	= sa1100_init_irq,
 	.init_machine	= lart_init,
 	.timer		= &sa1100_timer,
diff --git a/arch/arm/mach-sa1100/leds-assabet.c b/arch/arm/mach-sa1100/leds-assabet.c
index 64e9b4b..3699176 100644
--- a/arch/arm/mach-sa1100/leds-assabet.c
+++ b/arch/arm/mach-sa1100/leds-assabet.c
@@ -13,7 +13,6 @@
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
-#include <asm/system.h>
 #include <mach/assabet.h>
 
 #include "leds.h"
diff --git a/arch/arm/mach-sa1100/leds-badge4.c b/arch/arm/mach-sa1100/leds-badge4.c
index cf1e384..f99fac3 100644
--- a/arch/arm/mach-sa1100/leds-badge4.c
+++ b/arch/arm/mach-sa1100/leds-badge4.c
@@ -14,7 +14,6 @@
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
-#include <asm/system.h>
 
 #include "leds.h"
 
diff --git a/arch/arm/mach-sa1100/leds-cerf.c b/arch/arm/mach-sa1100/leds-cerf.c
index 259b48e..040540f 100644
--- a/arch/arm/mach-sa1100/leds-cerf.c
+++ b/arch/arm/mach-sa1100/leds-cerf.c
@@ -7,7 +7,6 @@
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
-#include <asm/system.h>
 
 #include "leds.h"
 
diff --git a/arch/arm/mach-sa1100/leds-hackkit.c b/arch/arm/mach-sa1100/leds-hackkit.c
index 2bce137..6a23524 100644
--- a/arch/arm/mach-sa1100/leds-hackkit.c
+++ b/arch/arm/mach-sa1100/leds-hackkit.c
@@ -13,7 +13,6 @@
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
-#include <asm/system.h>
 
 #include "leds.h"
 
diff --git a/arch/arm/mach-sa1100/leds-lart.c b/arch/arm/mach-sa1100/leds-lart.c
index 0505a1f..a51830c 100644
--- a/arch/arm/mach-sa1100/leds-lart.c
+++ b/arch/arm/mach-sa1100/leds-lart.c
@@ -13,7 +13,6 @@
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
-#include <asm/system.h>
 
 #include "leds.h"
 
diff --git a/arch/arm/mach-sa1100/nanoengine.c b/arch/arm/mach-sa1100/nanoengine.c
index 85f6ee6..8f6446b 100644
--- a/arch/arm/mach-sa1100/nanoengine.c
+++ b/arch/arm/mach-sa1100/nanoengine.c
@@ -28,6 +28,7 @@
 
 #include <mach/hardware.h>
 #include <mach/nanoengine.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -58,15 +59,8 @@
 };
 
 static struct resource nanoengine_flash_resources[] = {
-	{
-		.start	= SA1100_CS0_PHYS,
-		.end	= SA1100_CS0_PHYS + SZ_32M - 1,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= SA1100_CS1_PHYS,
-		.end	= SA1100_CS1_PHYS + SZ_32M - 1,
-		.flags	= IORESOURCE_MEM,
-	}
+	DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M),
+	DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_32M),
 };
 
 static struct map_desc nanoengine_io_desc[] __initdata = {
@@ -114,6 +108,7 @@
 MACHINE_START(NANOENGINE, "BSE nanoEngine")
 	.atag_offset	= 0x100,
 	.map_io		= nanoengine_map_io,
+	.nr_irqs	= SA1100_NR_IRQS,
 	.init_irq	= sa1100_init_irq,
 	.timer		= &sa1100_timer,
 	.init_machine	= nanoengine_init,
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index b4fa53a..6c58f01 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -1,89 +1,104 @@
 /*
  * linux/arch/arm/mach-sa1100/neponset.c
- *
  */
-#include <linux/kernel.h>
+#include <linux/err.h>
 #include <linux/init.h>
-#include <linux/tty.h>
 #include <linux/ioport.h>
-#include <linux/serial_core.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/irq.h>
 #include <asm/mach/map.h>
-#include <asm/mach/irq.h>
 #include <asm/mach/serial_sa1100.h>
-#include <mach/assabet.h>
-#include <mach/neponset.h>
 #include <asm/hardware/sa1111.h>
 #include <asm/sizes.h>
 
-/*
- * Install handler for Neponset IRQ.  Note that we have to loop here
- * since the ETHERNET and USAR IRQs are level based, and we need to
- * ensure that the IRQ signal is deasserted before returning.  This
- * is rather unfortunate.
- */
-static void
-neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
+#include <mach/hardware.h>
+#include <mach/assabet.h>
+#include <mach/neponset.h>
+#include <mach/irqs.h>
+
+#define NEP_IRQ_SMC91X	0
+#define NEP_IRQ_USAR	1
+#define NEP_IRQ_SA1111	2
+#define NEP_IRQ_NR	3
+
+#define WHOAMI		0x00
+#define LEDS		0x10
+#define SWPK		0x20
+#define IRR		0x24
+#define KP_Y_IN		0x80
+#define KP_X_OUT	0x90
+#define NCR_0		0xa0
+#define MDM_CTL_0	0xb0
+#define MDM_CTL_1	0xb4
+#define AUD_CTL		0xc0
+
+#define IRR_ETHERNET	(1 << 0)
+#define IRR_USAR	(1 << 1)
+#define IRR_SA1111	(1 << 2)
+
+#define MDM_CTL0_RTS1	(1 << 0)
+#define MDM_CTL0_DTR1	(1 << 1)
+#define MDM_CTL0_RTS2	(1 << 2)
+#define MDM_CTL0_DTR2	(1 << 3)
+
+#define MDM_CTL1_CTS1	(1 << 0)
+#define MDM_CTL1_DSR1	(1 << 1)
+#define MDM_CTL1_DCD1	(1 << 2)
+#define MDM_CTL1_CTS2	(1 << 3)
+#define MDM_CTL1_DSR2	(1 << 4)
+#define MDM_CTL1_DCD2	(1 << 5)
+
+#define AUD_SEL_1341	(1 << 0)
+#define AUD_MUTE_1341	(1 << 1)
+
+extern void sa1110_mb_disable(void);
+
+struct neponset_drvdata {
+	void __iomem *base;
+	struct platform_device *sa1111;
+	struct platform_device *smc91x;
+	unsigned irq_base;
+#ifdef CONFIG_PM_SLEEP
+	u32 ncr0;
+	u32 mdm_ctl_0;
+#endif
+};
+
+static void __iomem *nep_base;
+
+void neponset_ncr_frob(unsigned int mask, unsigned int val)
 {
-	unsigned int irr;
+	void __iomem *base = nep_base;
 
-	while (1) {
-		/*
-		 * Acknowledge the parent IRQ.
-		 */
-		desc->irq_data.chip->irq_ack(&desc->irq_data);
+	if (base) {
+		unsigned long flags;
+		unsigned v;
 
-		/*
-		 * Read the interrupt reason register.  Let's have all
-		 * active IRQ bits high.  Note: there is a typo in the
-		 * Neponset user's guide for the SA1111 IRR level.
-		 */
-		irr = IRR ^ (IRR_ETHERNET | IRR_USAR);
-
-		if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
-			break;
-
-		/*
-		 * Since there is no individual mask, we have to
-		 * mask the parent IRQ.  This is safe, since we'll
-		 * recheck the register for any pending IRQs.
-		 */
-		if (irr & (IRR_ETHERNET | IRR_USAR)) {
-			desc->irq_data.chip->irq_mask(&desc->irq_data);
-
-			/*
-			 * Ack the interrupt now to prevent re-entering
-			 * this neponset handler.  Again, this is safe
-			 * since we'll check the IRR register prior to
-			 * leaving.
-			 */
-			desc->irq_data.chip->irq_ack(&desc->irq_data);
-
-			if (irr & IRR_ETHERNET) {
-				generic_handle_irq(IRQ_NEPONSET_SMC9196);
-			}
-
-			if (irr & IRR_USAR) {
-				generic_handle_irq(IRQ_NEPONSET_USAR);
-			}
-
-			desc->irq_data.chip->irq_unmask(&desc->irq_data);
-		}
-
-		if (irr & IRR_SA1111) {
-			generic_handle_irq(IRQ_NEPONSET_SA1111);
-		}
+		local_irq_save(flags);
+		v = readb_relaxed(base + NCR_0);
+		writeb_relaxed((v & ~mask) | val, base + NCR_0);
+		local_irq_restore(flags);
+	} else {
+		WARN(1, "nep_base unset\n");
 	}
 }
 
 static void neponset_set_mctrl(struct uart_port *port, u_int mctrl)
 {
-	u_int mdm_ctl0 = MDM_CTL_0;
+	void __iomem *base = nep_base;
+	u_int mdm_ctl0;
 
+	if (!base)
+		return;
+
+	mdm_ctl0 = readb_relaxed(base + MDM_CTL_0);
 	if (port->mapbase == _Ser1UTCR0) {
 		if (mctrl & TIOCM_RTS)
 			mdm_ctl0 &= ~MDM_CTL0_RTS2;
@@ -106,14 +121,19 @@
 			mdm_ctl0 |= MDM_CTL0_DTR1;
 	}
 
-	MDM_CTL_0 = mdm_ctl0;
+	writeb_relaxed(mdm_ctl0, base + MDM_CTL_0);
 }
 
 static u_int neponset_get_mctrl(struct uart_port *port)
 {
+	void __iomem *base = nep_base;
 	u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
-	u_int mdm_ctl1 = MDM_CTL_1;
+	u_int mdm_ctl1;
 
+	if (!base)
+		return ret;
+
+	mdm_ctl1 = readb_relaxed(base + MDM_CTL_1);
 	if (port->mapbase == _Ser1UTCR0) {
 		if (mdm_ctl1 & MDM_CTL1_DCD2)
 			ret &= ~TIOCM_CD;
@@ -138,209 +158,278 @@
 	.get_mctrl	= neponset_get_mctrl,
 };
 
+/*
+ * Install handler for Neponset IRQ.  Note that we have to loop here
+ * since the ETHERNET and USAR IRQs are level based, and we need to
+ * ensure that the IRQ signal is deasserted before returning.  This
+ * is rather unfortunate.
+ */
+static void neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct neponset_drvdata *d = irq_desc_get_handler_data(desc);
+	unsigned int irr;
+
+	while (1) {
+		/*
+		 * Acknowledge the parent IRQ.
+		 */
+		desc->irq_data.chip->irq_ack(&desc->irq_data);
+
+		/*
+		 * Read the interrupt reason register.  Let's have all
+		 * active IRQ bits high.  Note: there is a typo in the
+		 * Neponset user's guide for the SA1111 IRR level.
+		 */
+		irr = readb_relaxed(d->base + IRR);
+		irr ^= IRR_ETHERNET | IRR_USAR;
+
+		if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
+			break;
+
+		/*
+		 * Since there is no individual mask, we have to
+		 * mask the parent IRQ.  This is safe, since we'll
+		 * recheck the register for any pending IRQs.
+		 */
+		if (irr & (IRR_ETHERNET | IRR_USAR)) {
+			desc->irq_data.chip->irq_mask(&desc->irq_data);
+
+			/*
+			 * Ack the interrupt now to prevent re-entering
+			 * this neponset handler.  Again, this is safe
+			 * since we'll check the IRR register prior to
+			 * leaving.
+			 */
+			desc->irq_data.chip->irq_ack(&desc->irq_data);
+
+			if (irr & IRR_ETHERNET)
+				generic_handle_irq(d->irq_base + NEP_IRQ_SMC91X);
+
+			if (irr & IRR_USAR)
+				generic_handle_irq(d->irq_base + NEP_IRQ_USAR);
+
+			desc->irq_data.chip->irq_unmask(&desc->irq_data);
+		}
+
+		if (irr & IRR_SA1111)
+			generic_handle_irq(d->irq_base + NEP_IRQ_SA1111);
+	}
+}
+
+/* Yes, we really do not have any kind of masking or unmasking */
+static void nochip_noop(struct irq_data *irq)
+{
+}
+
+static struct irq_chip nochip = {
+	.name = "neponset",
+	.irq_ack = nochip_noop,
+	.irq_mask = nochip_noop,
+	.irq_unmask = nochip_noop,
+};
+
+static struct sa1111_platform_data sa1111_info = {
+	.disable_devs	= SA1111_DEVID_PS2_MSE,
+};
+
 static int __devinit neponset_probe(struct platform_device *dev)
 {
-	sa1100_register_uart_fns(&neponset_port_fns);
+	struct neponset_drvdata *d;
+	struct resource *nep_res, *sa1111_res, *smc91x_res;
+	struct resource sa1111_resources[] = {
+		DEFINE_RES_MEM(0x40000000, SZ_8K),
+		{ .flags = IORESOURCE_IRQ },
+	};
+	struct platform_device_info sa1111_devinfo = {
+		.parent = &dev->dev,
+		.name = "sa1111",
+		.id = 0,
+		.res = sa1111_resources,
+		.num_res = ARRAY_SIZE(sa1111_resources),
+		.data = &sa1111_info,
+		.size_data = sizeof(sa1111_info),
+		.dma_mask = 0xffffffffUL,
+	};
+	struct resource smc91x_resources[] = {
+		DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS,
+			0x02000000, "smc91x-regs"),
+		DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000,
+			0x02000000, "smc91x-attrib"),
+		{ .flags = IORESOURCE_IRQ },
+	};
+	struct platform_device_info smc91x_devinfo = {
+		.parent = &dev->dev,
+		.name = "smc91x",
+		.id = 0,
+		.res = smc91x_resources,
+		.num_res = ARRAY_SIZE(smc91x_resources),
+	};
+	int ret, irq;
+
+	if (nep_base)
+		return -EBUSY;
+
+	irq = ret = platform_get_irq(dev, 0);
+	if (ret < 0)
+		goto err_alloc;
+
+	nep_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	smc91x_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
+	sa1111_res = platform_get_resource(dev, IORESOURCE_MEM, 2);
+	if (!nep_res || !smc91x_res || !sa1111_res) {
+		ret = -ENXIO;
+		goto err_alloc;
+	}
+
+	d = kzalloc(sizeof(*d), GFP_KERNEL);
+	if (!d) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	d->base = ioremap(nep_res->start, SZ_4K);
+	if (!d->base) {
+		ret = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	if (readb_relaxed(d->base + WHOAMI) != 0x11) {
+		dev_warn(&dev->dev, "Neponset board detected, but wrong ID: %02x\n",
+			 readb_relaxed(d->base + WHOAMI));
+		ret = -ENODEV;
+		goto err_id;
+	}
+
+	ret = irq_alloc_descs(-1, IRQ_BOARD_START, NEP_IRQ_NR, -1);
+	if (ret <= 0) {
+		dev_err(&dev->dev, "unable to allocate %u irqs: %d\n",
+			NEP_IRQ_NR, ret);
+		if (ret == 0)
+			ret = -ENOMEM;
+		goto err_irq_alloc;
+	}
+
+	d->irq_base = ret;
+
+	irq_set_chip_and_handler(d->irq_base + NEP_IRQ_SMC91X, &nochip,
+		handle_simple_irq);
+	set_irq_flags(d->irq_base + NEP_IRQ_SMC91X, IRQF_VALID | IRQF_PROBE);
+	irq_set_chip_and_handler(d->irq_base + NEP_IRQ_USAR, &nochip,
+		handle_simple_irq);
+	set_irq_flags(d->irq_base + NEP_IRQ_USAR, IRQF_VALID | IRQF_PROBE);
+	irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip);
+
+	irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
+	irq_set_handler_data(irq, d);
+	irq_set_chained_handler(irq, neponset_irq_handler);
 
 	/*
-	 * Install handler for GPIO25.
-	 */
-	irq_set_irq_type(IRQ_GPIO25, IRQ_TYPE_EDGE_RISING);
-	irq_set_chained_handler(IRQ_GPIO25, neponset_irq_handler);
-
-	/*
-	 * We would set IRQ_GPIO25 to be a wake-up IRQ, but
-	 * unfortunately something on the Neponset activates
-	 * this IRQ on sleep (ethernet?)
+	 * We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately
+	 * something on the Neponset activates this IRQ on sleep (eth?)
 	 */
 #if 0
-	enable_irq_wake(IRQ_GPIO25);
+	enable_irq_wake(irq);
 #endif
 
-	/*
-	 * Setup other Neponset IRQs.  SA1111 will be done by the
-	 * generic SA1111 code.
-	 */
-	irq_set_handler(IRQ_NEPONSET_SMC9196, handle_simple_irq);
-	set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE);
-	irq_set_handler(IRQ_NEPONSET_USAR, handle_simple_irq);
-	set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE);
+	dev_info(&dev->dev, "Neponset daughter board, providing IRQ%u-%u\n",
+		 d->irq_base, d->irq_base + NEP_IRQ_NR - 1);
+	nep_base = d->base;
 
-	/*
-	 * Disable GPIO 0/1 drivers so the buttons work on the module.
-	 */
-	NCR_0 = NCR_GP01_OFF;
+	sa1100_register_uart_fns(&neponset_port_fns);
+
+	/* Ensure that the memory bus request/grant signals are setup */
+	sa1110_mb_disable();
+
+	/* Disable GPIO 0/1 drivers so the buttons work on the Assabet */
+	writeb_relaxed(NCR_GP01_OFF, d->base + NCR_0);
+
+	sa1111_resources[0].parent = sa1111_res;
+	sa1111_resources[1].start = d->irq_base + NEP_IRQ_SA1111;
+	sa1111_resources[1].end = d->irq_base + NEP_IRQ_SA1111;
+	d->sa1111 = platform_device_register_full(&sa1111_devinfo);
+
+	smc91x_resources[0].parent = smc91x_res;
+	smc91x_resources[1].parent = smc91x_res;
+	smc91x_resources[2].start = d->irq_base + NEP_IRQ_SMC91X;
+	smc91x_resources[2].end = d->irq_base + NEP_IRQ_SMC91X;
+	d->smc91x = platform_device_register_full(&smc91x_devinfo);
+
+	platform_set_drvdata(dev, d);
 
 	return 0;
+
+ err_irq_alloc:
+ err_id:
+	iounmap(d->base);
+ err_ioremap:
+	kfree(d);
+ err_alloc:
+	return ret;
 }
 
-#ifdef CONFIG_PM
-
-/*
- * LDM power management.
- */
-static unsigned int neponset_saved_state;
-
-static int neponset_suspend(struct platform_device *dev, pm_message_t state)
+static int __devexit neponset_remove(struct platform_device *dev)
 {
-	/*
-	 * Save state.
-	 */
-	neponset_saved_state = NCR_0;
+	struct neponset_drvdata *d = platform_get_drvdata(dev);
+	int irq = platform_get_irq(dev, 0);
+
+	if (!IS_ERR(d->sa1111))
+		platform_device_unregister(d->sa1111);
+	if (!IS_ERR(d->smc91x))
+		platform_device_unregister(d->smc91x);
+	irq_set_chained_handler(irq, NULL);
+	irq_free_descs(d->irq_base, NEP_IRQ_NR);
+	nep_base = NULL;
+	iounmap(d->base);
+	kfree(d);
 
 	return 0;
 }
 
-static int neponset_resume(struct platform_device *dev)
+#ifdef CONFIG_PM_SLEEP
+static int neponset_suspend(struct device *dev)
 {
-	NCR_0 = neponset_saved_state;
+	struct neponset_drvdata *d = dev_get_drvdata(dev);
+
+	d->ncr0 = readb_relaxed(d->base + NCR_0);
+	d->mdm_ctl_0 = readb_relaxed(d->base + MDM_CTL_0);
 
 	return 0;
 }
 
+static int neponset_resume(struct device *dev)
+{
+	struct neponset_drvdata *d = dev_get_drvdata(dev);
+
+	writeb_relaxed(d->ncr0, d->base + NCR_0);
+	writeb_relaxed(d->mdm_ctl_0, d->base + MDM_CTL_0);
+
+	return 0;
+}
+
+static const struct dev_pm_ops neponset_pm_ops = {
+	.suspend_noirq = neponset_suspend,
+	.resume_noirq = neponset_resume,
+	.freeze_noirq = neponset_suspend,
+	.restore_noirq = neponset_resume,
+};
+#define PM_OPS &neponset_pm_ops
 #else
-#define neponset_suspend NULL
-#define neponset_resume  NULL
+#define PM_OPS NULL
 #endif
 
 static struct platform_driver neponset_device_driver = {
 	.probe		= neponset_probe,
-	.suspend	= neponset_suspend,
-	.resume		= neponset_resume,
+	.remove		= __devexit_p(neponset_remove),
 	.driver		= {
 		.name	= "neponset",
+		.owner	= THIS_MODULE,
+		.pm	= PM_OPS,
 	},
 };
 
-static struct resource neponset_resources[] = {
-	[0] = {
-		.start	= 0x10000000,
-		.end	= 0x17ffffff,
-		.flags	= IORESOURCE_MEM,
-	},
-};
-
-static struct platform_device neponset_device = {
-	.name		= "neponset",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(neponset_resources),
-	.resource	= neponset_resources,
-};
-
-static struct resource sa1111_resources[] = {
-	[0] = {
-		.start	= 0x40000000,
-		.end	= 0x40001fff,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_NEPONSET_SA1111,
-		.end	= IRQ_NEPONSET_SA1111,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct sa1111_platform_data sa1111_info = {
-	.irq_base	= IRQ_BOARD_END,
-};
-
-static u64 sa1111_dmamask = 0xffffffffUL;
-
-static struct platform_device sa1111_device = {
-	.name		= "sa1111",
-	.id		= 0,
-	.dev		= {
-		.dma_mask = &sa1111_dmamask,
-		.coherent_dma_mask = 0xffffffff,
-		.platform_data = &sa1111_info,
-	},
-	.num_resources	= ARRAY_SIZE(sa1111_resources),
-	.resource	= sa1111_resources,
-};
-
-static struct resource smc91x_resources[] = {
-	[0] = {
-		.name	= "smc91x-regs",
-		.start	= SA1100_CS3_PHYS,
-		.end	= SA1100_CS3_PHYS + 0x01ffffff,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_NEPONSET_SMC9196,
-		.end	= IRQ_NEPONSET_SMC9196,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[2] = {
-		.name	= "smc91x-attrib",
-		.start	= SA1100_CS3_PHYS + 0x02000000,
-		.end	= SA1100_CS3_PHYS + 0x03ffffff,
-		.flags	= IORESOURCE_MEM,
-	},
-};
-
-static struct platform_device smc91x_device = {
-	.name		= "smc91x",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(smc91x_resources),
-	.resource	= smc91x_resources,
-};
-
-static struct platform_device *devices[] __initdata = {
-	&neponset_device,
-	&sa1111_device,
-	&smc91x_device,
-};
-
-extern void sa1110_mb_disable(void);
-
 static int __init neponset_init(void)
 {
-	platform_driver_register(&neponset_device_driver);
-
-	/*
-	 * The Neponset is only present on the Assabet machine type.
-	 */
-	if (!machine_is_assabet())
-		return -ENODEV;
-
-	/*
-	 * Ensure that the memory bus request/grant signals are setup,
-	 * and the grant is held in its inactive state, whether or not
-	 * we actually have a Neponset attached.
-	 */
-	sa1110_mb_disable();
-
-	if (!machine_has_neponset()) {
-		printk(KERN_DEBUG "Neponset expansion board not present\n");
-		return -ENODEV;
-	}
-
-	if (WHOAMI != 0x11) {
-		printk(KERN_WARNING "Neponset board detected, but "
-			"wrong ID: %02x\n", WHOAMI);
-		return -ENODEV;
-	}
-
-	return platform_add_devices(devices, ARRAY_SIZE(devices));
+	return platform_driver_register(&neponset_device_driver);
 }
 
 subsys_initcall(neponset_init);
-
-static struct map_desc neponset_io_desc[] __initdata = {
-	{	/* System Registers */
-		.virtual	=  0xf3000000,
-		.pfn		= __phys_to_pfn(0x10000000),
-		.length		= SZ_1M,
-		.type		= MT_DEVICE
-	}, {	/* SA-1111 */
-		.virtual	=  0xf4000000,
-		.pfn		= __phys_to_pfn(0x40000000),
-		.length		= SZ_1M,
-		.type		= MT_DEVICE
-	}
-};
-
-void __init neponset_map_io(void)
-{
-	iotable_init(neponset_io_desc, ARRAY_SIZE(neponset_io_desc));
-}
diff --git a/arch/arm/mach-sa1100/pci-nanoengine.c b/arch/arm/mach-sa1100/pci-nanoengine.c
index 0d01ca7..b49108b 100644
--- a/arch/arm/mach-sa1100/pci-nanoengine.c
+++ b/arch/arm/mach-sa1100/pci-nanoengine.c
@@ -135,12 +135,8 @@
 				 &sys->resources);
 }
 
-static struct resource pci_io_ports = {
-	.name	= "PCI IO",
-	.start	= 0x400,
-	.end	= 0x7FF,
-	.flags	= IORESOURCE_IO,
-};
+static struct resource pci_io_ports =
+	DEFINE_RES_IO_NAMED(0x400, 0x400, "PCI IO");
 
 static struct resource pci_non_prefetchable_memory = {
 	.name	= "PCI non-prefetchable",
@@ -244,9 +240,11 @@
 		printk(KERN_ERR "PCI: unable to allocate prefetchable\n");
 		return -EBUSY;
 	}
-	pci_add_resource(&sys->resources, &pci_io_ports);
-	pci_add_resource(&sys->resources, &pci_non_prefetchable_memory);
-	pci_add_resource(&sys->resources, &pci_prefetchable_memory);
+	pci_add_resource_offset(&sys->resources, &pci_io_ports, sys->io_offset);
+	pci_add_resource_offset(&sys->resources,
+				&pci_non_prefetchable_memory, sys->mem_offset);
+	pci_add_resource_offset(&sys->resources,
+				&pci_prefetchable_memory, sys->mem_offset);
 
 	return 1;
 }
diff --git a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c
index 9307df0..1602575 100644
--- a/arch/arm/mach-sa1100/pleb.c
+++ b/arch/arm/mach-sa1100/pleb.c
@@ -37,17 +37,9 @@
 #define IRQ_GPIO_ETH0_IRQ	IRQ_GPIO21
 
 static struct resource smc91x_resources[] = {
-	[0] = {
-		.start	= PLEB_ETH0_P,
-		.end	= PLEB_ETH0_P | 0x03ffffff,
-		.flags	= IORESOURCE_MEM,
-	},
+	[0] = DEFINE_RES_MEM(PLEB_ETH0_P, 0x04000000),
 #if 0 /* Autoprobe instead, to get rising/falling edge characteristic right */
-	[1] = {
-		.start	= IRQ_GPIO_ETH0_IRQ,
-		.end	= IRQ_GPIO_ETH0_IRQ,
-		.flags	= IORESOURCE_IRQ,
-	},
+	[1] = DEFINE_RES_IRQ(IRQ_GPIO_ETH0_IRQ),
 #endif
 };
 
@@ -70,16 +62,8 @@
  * the two SA1100 lowest chip select outputs.
  */
 static struct resource pleb_flash_resources[] = {
-	[0] = {
-		.start = SA1100_CS0_PHYS,
-		.end   = SA1100_CS0_PHYS + SZ_8M - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = SA1100_CS1_PHYS,
-		.end   = SA1100_CS1_PHYS + SZ_8M - 1,
-		.flags = IORESOURCE_MEM,
-	}
+	[0] = DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_8M),
+	[1] = DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_8M),
 };
 
 
@@ -147,6 +131,7 @@
 
 MACHINE_START(PLEB, "PLEB")
 	.map_io		= pleb_map_io,
+	.nr_irqs	= SA1100_NR_IRQS,
 	.init_irq	= sa1100_init_irq,
 	.timer		= &sa1100_timer,
 	.init_machine   = pleb_init,
diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c
index bf85b8b..2fa499e 100644
--- a/arch/arm/mach-sa1100/pm.c
+++ b/arch/arm/mach-sa1100/pm.c
@@ -30,7 +30,6 @@
 #include <mach/hardware.h>
 #include <asm/memory.h>
 #include <asm/suspend.h>
-#include <asm/system.h>
 #include <asm/mach/time.h>
 
 extern int sa1100_finish_suspend(unsigned long);
diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c
index 318b2b7..ca8bf59 100644
--- a/arch/arm/mach-sa1100/shannon.c
+++ b/arch/arm/mach-sa1100/shannon.c
@@ -9,6 +9,8 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
+#include <video/sa1100fb.h>
+
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
@@ -19,6 +21,7 @@
 #include <asm/mach/serial_sa1100.h>
 #include <mach/mcp.h>
 #include <mach/shannon.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -46,19 +49,32 @@
 	.nr_parts	= ARRAY_SIZE(shannon_partitions),
 };
 
-static struct resource shannon_flash_resource = {
-	.start		= SA1100_CS0_PHYS,
-	.end		= SA1100_CS0_PHYS + SZ_4M - 1,
-	.flags		= IORESOURCE_MEM,
-};
+static struct resource shannon_flash_resource =
+	DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_4M);
 
 static struct mcp_plat_data shannon_mcp_data = {
 	.mccr0		= MCCR0_ADM,
 	.sclk_rate	= 11981000,
 };
 
+static struct sa1100fb_mach_info shannon_lcd_info = {
+	.pixclock	= 152500,	.bpp		= 8,
+	.xres		= 640,		.yres		= 480,
+
+	.hsync_len	= 4,		.vsync_len	= 3,
+	.left_margin	= 2,		.upper_margin	= 0,
+	.right_margin	= 1,		.lower_margin	= 0,
+
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	.lccr0		= LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
+	.lccr3		= LCCR3_ACBsDiv(512),
+};
+
 static void __init shannon_init(void)
 {
+	sa11x0_ppc_configure_mcp();
+	sa11x0_register_lcd(&shannon_lcd_info);
 	sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1);
 	sa11x0_register_mcp(&shannon_mcp_data);
 }
@@ -84,6 +100,7 @@
 MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)")
 	.atag_offset	= 0x100,
 	.map_io		= shannon_map_io,
+	.nr_irqs	= SA1100_NR_IRQS,
 	.init_irq	= sa1100_init_irq,
 	.timer		= &sa1100_timer,
 	.init_machine	= shannon_init,
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index e17c04d..3efae03 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -7,15 +7,15 @@
 #include <linux/kernel.h>
 #include <linux/tty.h>
 #include <linux/proc_fs.h>
-#include <linux/string.h> 
+#include <linux/string.h>
 #include <linux/pm.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/ucb1x00.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
 
-#include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/setup.h>
 
@@ -26,6 +26,7 @@
 #include <asm/mach/serial_sa1100.h>
 #include <mach/mcp.h>
 #include <mach/simpad.h>
+#include <mach/irqs.h>
 
 #include <linux/serial_core.h>
 #include <linux/ioport.h>
@@ -176,21 +177,18 @@
 
 
 static struct resource simpad_flash_resources [] = {
-	{
-		.start     = SA1100_CS0_PHYS,
-		.end       = SA1100_CS0_PHYS + SZ_16M -1,
-		.flags     = IORESOURCE_MEM,
-	}, {
-		.start     = SA1100_CS1_PHYS,
-		.end       = SA1100_CS1_PHYS + SZ_16M -1,
-		.flags     = IORESOURCE_MEM,
-	}
+	DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_16M),
+	DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_16M),
+};
+
+static struct ucb1x00_plat_data simpad_ucb1x00_data = {
+	.gpio_base	= SIMPAD_UCB1X00_GPIO_BASE,
 };
 
 static struct mcp_plat_data simpad_mcp_data = {
 	.mccr0		= MCCR0_ADM,
 	.sclk_rate	= 11981000,
-	.gpio_base	= SIMPAD_UCB1X00_GPIO_BASE,
+	.codec_pdata	= &simpad_ucb1x00_data,
 };
 
 
@@ -376,6 +374,7 @@
 
 	pm_power_off = simpad_power_off;
 
+	sa11x0_ppc_configure_mcp();
 	sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources,
 			      ARRAY_SIZE(simpad_flash_resources));
 	sa11x0_register_mcp(&simpad_mcp_data);
@@ -394,6 +393,7 @@
 	/* Maintainer: Holger Freyther */
 	.atag_offset	= 0x100,
 	.map_io		= simpad_map_io,
+	.nr_irqs	= SA1100_NR_IRQS,
 	.init_irq	= sa1100_init_irq,
 	.timer		= &sa1100_timer,
 	.restart	= sa11x0_restart,
diff --git a/arch/arm/mach-sa1100/sleep.S b/arch/arm/mach-sa1100/sleep.S
index e822331..30cc672 100644
--- a/arch/arm/mach-sa1100/sleep.S
+++ b/arch/arm/mach-sa1100/sleep.S
@@ -26,27 +26,36 @@
  *
  * Causes sa11x0 to enter sleep state
  *
+ * Must be aligned to a cacheline.
  */
-
+	.balign	32
 ENTRY(sa1100_finish_suspend)
 	@ disable clock switching
 	mcr	p15, 0, r1, c15, c2, 2
 
-        @ Adjust memory timing before lowering CPU clock
-	@ Clock speed adjustment without changing memory timing makes
-	@ CPU hang in some cases
-        ldr     r0, =MDREFR
-        ldr     r1, [r0]
-        orr     r1, r1, #MDREFR_K1DB2
-        str     r1, [r0]
+	ldr	r6, =MDREFR
+	ldr	r4, [r6]
+	orr     r4, r4, #MDREFR_K1DB2
+	ldr	r5, =PPCR
+
+	@ Pre-load __udelay into the I-cache
+	mov	r0, #1
+	bl	__udelay
+	mov	r0, r0
+
+	@ The following must all exist in a single cache line to
+	@ avoid accessing memory until this sequence is complete,
+	@ otherwise we occasionally hang.
+
+	@ Adjust memory timing before lowering CPU clock
+	str     r4, [r6]
 
 	@ delay 90us and set CPU PLL to lowest speed
 	@ fixes resume problem on high speed SA1110
 	mov	r0, #90
 	bl	__udelay
-	ldr	r0, =PPCR
 	mov	r1, #0
-	str	r1, [r0]
+	str	r1, [r5]
 	mov	r0, #90
 	bl	__udelay
 
@@ -85,12 +94,10 @@
 	bic	r5, r5, #FMsk(MSC_RT)
 	bic	r5, r5, #FMsk(MSC_RT)<<16
 
-	ldr	r6, =MDREFR
-
 	ldr	r7, [r6]
-bic	r7, r7, #0x0000FF00
-bic	r7, r7, #0x000000F0
-orr	r8, r7, #MDREFR_SLFRSH
+	bic	r7, r7, #0x0000FF00
+	bic	r7, r7, #0x000000F0
+	orr	r8, r7, #MDREFR_SLFRSH
 
 	ldr	r9, =MDCNFG
 	ldr	r10, [r9]
diff --git a/arch/arm/mach-sa1100/ssp.c b/arch/arm/mach-sa1100/ssp.c
index b20ff93..e22fca9 100644
--- a/arch/arm/mach-sa1100/ssp.c
+++ b/arch/arm/mach-sa1100/ssp.c
@@ -19,8 +19,8 @@
 #include <linux/init.h>
 #include <linux/io.h>
 
-#include <asm/irq.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 #include <asm/hardware/ssp.h>
 
 #define TIMEOUT 100000
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index 69e3353..6af26e8 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -18,6 +18,7 @@
 #include <asm/mach/time.h>
 #include <asm/sched_clock.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 
 static u32 notrace sa1100_read_sched_clock(void)
 {
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index a851c25..2704bcd 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -15,6 +15,7 @@
 #include <asm/mach-types.h>
 #include <asm/leds.h>
 #include <asm/param.h>
+#include <asm/system_misc.h>
 
 #include <asm/mach/map.h>
 #include <asm/mach/arch.h>
@@ -149,10 +150,16 @@
 	.init		= shark_timer_init,
 };
 
+static void shark_init_early(void)
+{
+	disable_hlt();
+}
+
 MACHINE_START(SHARK, "Shark")
 	/* Maintainer: Alexander Schulz */
 	.atag_offset	= 0x3000,
 	.map_io		= shark_map_io,
+	.init_early	= shark_init_early,
 	.init_irq	= shark_init_irq,
 	.timer		= &shark_timer,
 	.dma_zone_size	= SZ_4M,
diff --git a/arch/arm/mach-shark/include/mach/entry-macro.S b/arch/arm/mach-shark/include/mach/entry-macro.S
index 0bb6cc6..5901b09 100644
--- a/arch/arm/mach-shark/include/mach/entry-macro.S
+++ b/arch/arm/mach-shark/include/mach/entry-macro.S
@@ -7,16 +7,10 @@
  * License version 2. This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
  */
-		.macro	disable_fiq
-		.endm
-
 		.macro  get_irqnr_preamble, base, tmp
 		mov	\base, #0xe0000000
 		.endm
 
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
-
 		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 
 		mov	\irqstat, #0x0C
diff --git a/arch/arm/mach-shark/include/mach/io.h b/arch/arm/mach-shark/include/mach/io.h
index 9ccbcec..1a45fc0 100644
--- a/arch/arm/mach-shark/include/mach/io.h
+++ b/arch/arm/mach-shark/include/mach/io.h
@@ -15,6 +15,4 @@
 
 #define __io(a)                 ((void __iomem *)(0xe0000000 + (a)))
 
-#define __mem_pci(addr) (addr)
-
 #endif
diff --git a/arch/arm/mach-shark/include/mach/system.h b/arch/arm/mach-shark/include/mach/system.h
deleted file mode 100644
index 1b2f2c5..0000000
--- a/arch/arm/mach-shark/include/mach/system.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-shark/include/mach/system.h
- *
- * by Alexander Schulz
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-}
-
-#endif
diff --git a/arch/arm/mach-shark/leds.c b/arch/arm/mach-shark/leds.c
index ccd4918..2560907 100644
--- a/arch/arm/mach-shark/leds.c
+++ b/arch/arm/mach-shark/leds.c
@@ -23,7 +23,6 @@
 #include <linux/io.h>
 
 #include <asm/leds.h>
-#include <asm/system.h>
 
 #define LED_STATE_ENABLED	1
 #define LED_STATE_CLAIMED	2
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 060e564..34560ca 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -100,6 +100,10 @@
 
 comment "SH-Mobile System Configuration"
 
+config CPU_HAS_INTEVT
+        bool
+	default y
+
 menu "Memory configuration"
 
 config MEMORY_START
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index 7ad6954..e7c2590 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -16,7 +16,6 @@
 # SMP objects
 smp-y				:= platsmp.o headsmp.o
 smp-$(CONFIG_HOTPLUG_CPU)	+= hotplug.o
-smp-$(CONFIG_LOCAL_TIMERS)	+= localtimer.o
 smp-$(CONFIG_ARCH_SH73A0)	+= smp-sh73a0.o
 smp-$(CONFIG_ARCH_R8A7779)	+= smp-r8a7779.o
 
diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c
index 8aea3a2..cb224a3 100644
--- a/arch/arm/mach-shmobile/board-ag5evm.c
+++ b/arch/arm/mach-shmobile/board-ag5evm.c
@@ -43,12 +43,11 @@
 #include <video/sh_mipi_dsi.h>
 #include <sound/sh_fsi.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 #include <mach/sh73a0.h>
 #include <mach/common.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/traps.h>
@@ -230,16 +229,6 @@
 	gpio_set_value(GPIO_PORT235, 1);
 }
 
-static void lcd_on(void *board_data, struct fb_info *info)
-{
-	lcd_backlight_on();
-}
-
-static void lcd_off(void *board_data)
-{
-	lcd_backlight_reset();
-}
-
 /* LCDC0 */
 static const struct fb_videomode lcdc0_modes[] = {
 	{
@@ -263,14 +252,14 @@
 		.interface_type = RGB24,
 		.clock_divider = 1,
 		.flags = LCDC_FLAGS_DWPOL,
-		.lcd_size_cfg.width = 44,
-		.lcd_size_cfg.height = 79,
 		.fourcc = V4L2_PIX_FMT_RGB565,
-		.lcd_cfg = lcdc0_modes,
-		.num_cfg = ARRAY_SIZE(lcdc0_modes),
-		.board_cfg = {
-			.display_on = lcd_on,
-			.display_off = lcd_off,
+		.lcd_modes = lcdc0_modes,
+		.num_modes = ARRAY_SIZE(lcdc0_modes),
+		.panel_cfg = {
+			.width = 44,
+			.height = 79,
+			.display_on = lcd_backlight_on,
+			.display_off = lcd_backlight_reset,
 		},
 	}
 };
@@ -487,27 +476,6 @@
 	&sdhi1_device,
 };
 
-static struct map_desc ag5evm_io_desc[] __initdata = {
-	/* create a 1:1 entity map for 0xe6xxxxxx
-	 * used by CPGA, INTC and PFC.
-	 */
-	{
-		.virtual	= 0xe6000000,
-		.pfn		= __phys_to_pfn(0xe6000000),
-		.length		= 256 << 20,
-		.type		= MT_DEVICE_NONSHARED
-	},
-};
-
-static void __init ag5evm_map_io(void)
-{
-	iotable_init(ag5evm_io_desc, ARRAY_SIZE(ag5evm_io_desc));
-
-	/* setup early devices and console here as well */
-	sh73a0_add_early_devices();
-	shmobile_setup_console();
-}
-
 static void __init ag5evm_init(void)
 {
 	sh73a0_pinmux_init();
@@ -617,28 +585,18 @@
 
 #ifdef CONFIG_CACHE_L2X0
 	/* Shared attribute override enable, 64K*8way */
-	l2x0_init(__io(0xf0100000), 0x00460000, 0xc2000fff);
+	l2x0_init(IOMEM(0xf0100000), 0x00460000, 0xc2000fff);
 #endif
 	sh73a0_add_standard_devices();
 	platform_add_devices(ag5evm_devices, ARRAY_SIZE(ag5evm_devices));
 }
 
-static void __init ag5evm_timer_init(void)
-{
-	sh73a0_clock_init();
-	shmobile_timer.init();
-	return;
-}
-
-struct sys_timer ag5evm_timer = {
-	.init	= ag5evm_timer_init,
-};
-
 MACHINE_START(AG5EVM, "ag5evm")
-	.map_io		= ag5evm_map_io,
+	.map_io		= sh73a0_map_io,
+	.init_early	= sh73a0_add_early_devices,
 	.nr_irqs	= NR_IRQS_LEGACY,
 	.init_irq	= sh73a0_init_irq,
 	.handle_irq	= gic_handle_irq,
 	.init_machine	= ag5evm_init,
-	.timer		= &ag5evm_timer,
+	.timer		= &shmobile_timer,
 MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index b4718b0..b56dde2 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -61,8 +61,6 @@
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
 #include <asm/setup.h>
 
 /*
@@ -258,10 +256,16 @@
 
 static struct resource meram_resources[] = {
 	[0] = {
-		.name   = "MERAM",
-		.start  = 0xe8000000,
-		.end    = 0xe81fffff,
-		.flags  = IORESOURCE_MEM,
+		.name	= "regs",
+		.start	= 0xe8000000,
+		.end	= 0xe807ffff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "meram",
+		.start	= 0xe8080000,
+		.end	= 0xe81fffff,
+		.flags	= IORESOURCE_MEM,
 	},
 };
 
@@ -437,82 +441,6 @@
 	.resource	= usb1_host_resources,
 };
 
-static const struct fb_videomode ap4evb_lcdc_modes[] = {
-	{
-#ifdef CONFIG_AP4EVB_QHD
-		.name		= "R63302(QHD)",
-		.xres		= 544,
-		.yres		= 961,
-		.left_margin	= 72,
-		.right_margin	= 600,
-		.hsync_len	= 16,
-		.upper_margin	= 8,
-		.lower_margin	= 8,
-		.vsync_len	= 2,
-		.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
-#else
-		.name		= "WVGA Panel",
-		.xres		= 800,
-		.yres		= 480,
-		.left_margin	= 220,
-		.right_margin	= 110,
-		.hsync_len	= 70,
-		.upper_margin	= 20,
-		.lower_margin	= 5,
-		.vsync_len	= 5,
-		.sync		= 0,
-#endif
-	},
-};
-static struct sh_mobile_meram_cfg lcd_meram_cfg = {
-	.icb[0] = {
-		.marker_icb     = 28,
-		.cache_icb      = 24,
-		.meram_offset   = 0x0,
-		.meram_size     = 0x40,
-	},
-	.icb[1] = {
-		.marker_icb     = 29,
-		.cache_icb      = 25,
-		.meram_offset   = 0x40,
-		.meram_size     = 0x40,
-	},
-};
-
-static struct sh_mobile_lcdc_info lcdc_info = {
-	.meram_dev = &meram_info,
-	.ch[0] = {
-		.chan = LCDC_CHAN_MAINLCD,
-		.fourcc = V4L2_PIX_FMT_RGB565,
-		.lcd_cfg = ap4evb_lcdc_modes,
-		.num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes),
-		.meram_cfg = &lcd_meram_cfg,
-	}
-};
-
-static struct resource lcdc_resources[] = {
-	[0] = {
-		.name	= "LCDC",
-		.start	= 0xfe940000, /* P4-only space */
-		.end	= 0xfe943fff,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= intcs_evt2irq(0x580),
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device lcdc_device = {
-	.name		= "sh_mobile_lcdc_fb",
-	.num_resources	= ARRAY_SIZE(lcdc_resources),
-	.resource	= lcdc_resources,
-	.dev	= {
-		.platform_data	= &lcdc_info,
-		.coherent_dma_mask = ~0,
-	},
-};
-
 /*
  * QHD display
  */
@@ -556,20 +484,25 @@
 };
 
 /* MIPI-DSI */
-#define PHYCTRL		0x0070
 static int sh_mipi_set_dot_clock(struct platform_device *pdev,
 				 void __iomem *base,
 				 int enable)
 {
 	struct clk *pck = clk_get(&pdev->dev, "dsip_clk");
-	void __iomem *phy =  base + PHYCTRL;
 
 	if (IS_ERR(pck))
 		return PTR_ERR(pck);
 
 	if (enable) {
+		/*
+		 * DSIPCLK	= 24MHz
+		 * D-PHY	= DSIPCLK * ((0x6*2)+1) = 312MHz (see .phyctrl)
+		 * HsByteCLK	= D-PHY/8 = 39MHz
+		 *
+		 *  X * Y * FPS =
+		 * (544+72+600+16) * (961+8+8+2) * 30 = 36.1MHz
+		 */
 		clk_set_rate(pck, clk_round_rate(pck, 24000000));
-		iowrite32(ioread32(phy) | (0xb << 8), phy);
 		clk_enable(pck);
 	} else {
 		clk_disable(pck);
@@ -593,11 +526,14 @@
 	},
 };
 
+static struct sh_mobile_lcdc_info lcdc_info;
+
 static struct sh_mipi_dsi_info mipidsi0_info = {
 	.data_format	= MIPI_RGB888,
 	.lcd_chan	= &lcdc_info.ch[0],
 	.lane		= 2,
 	.vsynw_offset	= 17,
+	.phyctrl	= 0x6 << 8,
 	.flags		= SH_MIPI_DSI_SYNC_PULSES_MODE |
 			  SH_MIPI_DSI_HSbyteCLK,
 	.set_dot_clock	= sh_mipi_set_dot_clock,
@@ -619,6 +555,81 @@
 };
 #endif /* CONFIG_AP4EVB_QHD */
 
+/* LCDC0 */
+static const struct fb_videomode ap4evb_lcdc_modes[] = {
+	{
+#ifdef CONFIG_AP4EVB_QHD
+		.name		= "R63302(QHD)",
+		.xres		= 544,
+		.yres		= 961,
+		.left_margin	= 72,
+		.right_margin	= 600,
+		.hsync_len	= 16,
+		.upper_margin	= 8,
+		.lower_margin	= 8,
+		.vsync_len	= 2,
+		.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
+#else
+		.name		= "WVGA Panel",
+		.xres		= 800,
+		.yres		= 480,
+		.left_margin	= 220,
+		.right_margin	= 110,
+		.hsync_len	= 70,
+		.upper_margin	= 20,
+		.lower_margin	= 5,
+		.vsync_len	= 5,
+		.sync		= 0,
+#endif
+	},
+};
+
+static const struct sh_mobile_meram_cfg lcd_meram_cfg = {
+	.icb[0] = {
+		.meram_size     = 0x40,
+	},
+	.icb[1] = {
+		.meram_size     = 0x40,
+	},
+};
+
+static struct sh_mobile_lcdc_info lcdc_info = {
+	.meram_dev = &meram_info,
+	.ch[0] = {
+		.chan = LCDC_CHAN_MAINLCD,
+		.fourcc = V4L2_PIX_FMT_RGB565,
+		.lcd_modes = ap4evb_lcdc_modes,
+		.num_modes = ARRAY_SIZE(ap4evb_lcdc_modes),
+		.meram_cfg = &lcd_meram_cfg,
+#ifdef CONFIG_AP4EVB_QHD
+		.tx_dev = &mipidsi0_device,
+#endif
+	}
+};
+
+static struct resource lcdc_resources[] = {
+	[0] = {
+		.name	= "LCDC",
+		.start	= 0xfe940000, /* P4-only space */
+		.end	= 0xfe943fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= intcs_evt2irq(0x580),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device lcdc_device = {
+	.name		= "sh_mobile_lcdc_fb",
+	.num_resources	= ARRAY_SIZE(lcdc_resources),
+	.resource	= lcdc_resources,
+	.dev	= {
+		.platform_data	= &lcdc_info,
+		.coherent_dma_mask = ~0,
+	},
+};
+
 /* FSI */
 #define IRQ_FSI		evt2irq(0x1840)
 static int __fsi_set_rate(struct clk *clk, long rate, int enable)
@@ -737,26 +748,18 @@
 	return ret;
 }
 
-static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable)
-{
-	int ret;
-
-	if (is_porta)
-		ret = fsi_ak4642_set_rate(dev, rate, enable);
-	else
-		ret = fsi_hdmi_set_rate(dev, rate, enable);
-
-	return ret;
-}
-
 static struct sh_fsi_platform_info fsi_info = {
-	.porta_flags = SH_FSI_BRS_INV,
-
-	.portb_flags = SH_FSI_BRS_INV |
-		       SH_FSI_BRM_INV |
-		       SH_FSI_LRS_INV |
-		       SH_FSI_FMT_SPDIF,
-	.set_rate = fsi_set_rate,
+	.port_a = {
+		.flags		= SH_FSI_BRS_INV,
+		.set_rate	= fsi_ak4642_set_rate,
+	},
+	.port_b = {
+		.flags		= SH_FSI_BRS_INV |
+				  SH_FSI_BRM_INV |
+				  SH_FSI_LRS_INV |
+				  SH_FSI_FMT_SPDIF,
+		.set_rate	= fsi_hdmi_set_rate,
+	},
 };
 
 static struct resource fsi_resources[] = {
@@ -798,65 +801,11 @@
 	},
 };
 
-static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
-	.icb[0] = {
-		.marker_icb     = 30,
-		.cache_icb      = 26,
-		.meram_offset   = 0x80,
-		.meram_size     = 0x100,
-	},
-	.icb[1] = {
-		.marker_icb     = 31,
-		.cache_icb      = 27,
-		.meram_offset   = 0x180,
-		.meram_size     = 0x100,
-	},
-};
-
-static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = {
-	.clock_source = LCDC_CLK_EXTERNAL,
-	.meram_dev = &meram_info,
-	.ch[0] = {
-		.chan = LCDC_CHAN_MAINLCD,
-		.fourcc = V4L2_PIX_FMT_RGB565,
-		.interface_type = RGB24,
-		.clock_divider = 1,
-		.flags = LCDC_FLAGS_DWPOL,
-		.meram_cfg = &hdmi_meram_cfg,
-	}
-};
-
-static struct resource lcdc1_resources[] = {
-	[0] = {
-		.name	= "LCDC1",
-		.start	= 0xfe944000,
-		.end	= 0xfe947fff,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= intcs_evt2irq(0x1780),
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device lcdc1_device = {
-	.name		= "sh_mobile_lcdc_fb",
-	.num_resources	= ARRAY_SIZE(lcdc1_resources),
-	.resource	= lcdc1_resources,
-	.id             = 1,
-	.dev	= {
-		.platform_data	= &sh_mobile_lcdc1_info,
-		.coherent_dma_mask = ~0,
-	},
-};
-
+/* LCDC1 */
 static long ap4evb_clk_optimize(unsigned long target, unsigned long *best_freq,
 				unsigned long *parent_freq);
 
-
 static struct sh_mobile_hdmi_info hdmi_info = {
-	.lcd_chan = &sh_mobile_lcdc1_info.ch[0],
-	.lcd_dev = &lcdc1_device.dev,
 	.flags = HDMI_SND_SRC_SPDIF,
 	.clk_optimize_parent = ap4evb_clk_optimize,
 };
@@ -885,10 +834,6 @@
 	},
 };
 
-static struct platform_device fsi_hdmi_device = {
-	.name		= "sh_fsi2_b_hdmi",
-};
-
 static long ap4evb_clk_optimize(unsigned long target, unsigned long *best_freq,
 				unsigned long *parent_freq)
 {
@@ -908,6 +853,57 @@
 	return error;
 }
 
+static const struct sh_mobile_meram_cfg hdmi_meram_cfg = {
+	.icb[0] = {
+		.meram_size     = 0x100,
+	},
+	.icb[1] = {
+		.meram_size     = 0x100,
+	},
+};
+
+static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = {
+	.clock_source = LCDC_CLK_EXTERNAL,
+	.meram_dev = &meram_info,
+	.ch[0] = {
+		.chan = LCDC_CHAN_MAINLCD,
+		.fourcc = V4L2_PIX_FMT_RGB565,
+		.interface_type = RGB24,
+		.clock_divider = 1,
+		.flags = LCDC_FLAGS_DWPOL,
+		.meram_cfg = &hdmi_meram_cfg,
+		.tx_dev = &hdmi_device,
+	}
+};
+
+static struct resource lcdc1_resources[] = {
+	[0] = {
+		.name	= "LCDC1",
+		.start	= 0xfe944000,
+		.end	= 0xfe947fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= intcs_evt2irq(0x1780),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device lcdc1_device = {
+	.name		= "sh_mobile_lcdc_fb",
+	.num_resources	= ARRAY_SIZE(lcdc1_resources),
+	.resource	= lcdc1_resources,
+	.id             = 1,
+	.dev	= {
+		.platform_data	= &sh_mobile_lcdc1_info,
+		.coherent_dma_mask = ~0,
+	},
+};
+
+static struct platform_device fsi_hdmi_device = {
+	.name		= "sh_fsi2_b_hdmi",
+};
+
 static struct gpio_led ap4evb_leds[] = {
 	{
 		.name			= "led4",
@@ -1042,9 +1038,9 @@
 	&fsi_ak4643_device,
 	&fsi_hdmi_device,
 	&sh_mmcif_device,
-	&lcdc1_device,
-	&lcdc_device,
 	&hdmi_device,
+	&lcdc_device,
+	&lcdc1_device,
 	&ceu_device,
 	&ap4evb_camera,
 	&meram_device,
@@ -1190,26 +1186,6 @@
 	},
 };
 
-static struct map_desc ap4evb_io_desc[] __initdata = {
-	/* create a 1:1 entity map for 0xe6xxxxxx
-	 * used by CPGA, INTC and PFC.
-	 */
-	{
-		.virtual	= 0xe6000000,
-		.pfn		= __phys_to_pfn(0xe6000000),
-		.length		= 256 << 20,
-		.type		= MT_DEVICE_NONSHARED
-	},
-};
-
-static void __init ap4evb_map_io(void)
-{
-	iotable_init(ap4evb_io_desc, ARRAY_SIZE(ap4evb_io_desc));
-
-	/* setup early devices and console here as well */
-	sh7372_add_early_devices();
-	shmobile_setup_console();
-}
 
 #define GPIO_PORT9CR	0xE6051009
 #define GPIO_PORT10CR	0xE605100A
@@ -1219,6 +1195,9 @@
 	u32 srcr4;
 	struct clk *clk;
 
+	/* External clock source */
+	clk_set_rate(&sh7372_dv_clki_clk, 27000000);
+
 	sh7372_pinmux_init();
 
 	/* enable SCIFA0 */
@@ -1355,8 +1334,8 @@
 	lcdc_info.ch[0].interface_type		= RGB24;
 	lcdc_info.ch[0].clock_divider		= 1;
 	lcdc_info.ch[0].flags			= LCDC_FLAGS_DWPOL;
-	lcdc_info.ch[0].lcd_size_cfg.width	= 44;
-	lcdc_info.ch[0].lcd_size_cfg.height	= 79;
+	lcdc_info.ch[0].panel_cfg.width		= 44;
+	lcdc_info.ch[0].panel_cfg.height	= 79;
 
 	platform_add_devices(qhd_devices, ARRAY_SIZE(qhd_devices));
 
@@ -1397,8 +1376,8 @@
 	lcdc_info.ch[0].interface_type		= RGB18;
 	lcdc_info.ch[0].clock_divider		= 3;
 	lcdc_info.ch[0].flags			= 0;
-	lcdc_info.ch[0].lcd_size_cfg.width	= 152;
-	lcdc_info.ch[0].lcd_size_cfg.height	= 91;
+	lcdc_info.ch[0].panel_cfg.width		= 152;
+	lcdc_info.ch[0].panel_cfg.height	= 91;
 
 	/* enable TouchScreen */
 	irq_set_irq_type(IRQ7, IRQ_TYPE_LEVEL_LOW);
@@ -1455,23 +1434,11 @@
 	pm_clk_add(&lcdc1_device.dev, "hdmi");
 }
 
-static void __init ap4evb_timer_init(void)
-{
-	sh7372_clock_init();
-	shmobile_timer.init();
-
-	/* External clock source */
-	clk_set_rate(&sh7372_dv_clki_clk, 27000000);
-}
-
-static struct sys_timer ap4evb_timer = {
-	.init		= ap4evb_timer_init,
-};
-
 MACHINE_START(AP4EVB, "ap4evb")
-	.map_io		= ap4evb_map_io,
+	.map_io		= sh7372_map_io,
+	.init_early	= sh7372_add_early_devices,
 	.init_irq	= sh7372_init_irq,
 	.handle_irq	= shmobile_handle_irq_intc,
 	.init_machine	= ap4evb_init,
-	.timer		= &ap4evb_timer,
+	.timer		= &shmobile_timer,
 MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c
index 4bd1162..81fd95f 100644
--- a/arch/arm/mach-shmobile/board-bonito.c
+++ b/arch/arm/mach-shmobile/board-bonito.c
@@ -35,6 +35,7 @@
 #include <asm/mach/time.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <mach/r8a7740.h>
+#include <mach/irqs.h>
 #include <video/sh_mobile_lcdc.h>
 
 /*
@@ -246,9 +247,9 @@
 		.interface_type		= RGB24,
 		.clock_divider		= 5,
 		.flags			= 0,
-		.lcd_cfg		= &lcdc0_mode,
-		.num_cfg		= 1,
-		.lcd_size_cfg = {
+		.lcd_modes		= &lcdc0_mode,
+		.num_modes		= 1,
+		.panel_cfg = {
 			.width	= 152,
 			.height = 91,
 		},
@@ -328,28 +329,6 @@
  * map I/O
  */
 static struct map_desc bonito_io_desc[] __initdata = {
-	 /*
-	  * for CPGA/INTC/PFC
-	  * 0xe6000000-0xefffffff -> 0xe6000000-0xefffffff
-	  */
-	{
-		.virtual	= 0xe6000000,
-		.pfn		= __phys_to_pfn(0xe6000000),
-		.length		= 160 << 20,
-		.type		= MT_DEVICE_NONSHARED
-	},
-#ifdef CONFIG_CACHE_L2X0
-	/*
-	 * for l2x0_init()
-	 * 0xf0100000-0xf0101000 -> 0xf0002000-0xf0003000
-	 */
-	{
-		.virtual	= 0xf0002000,
-		.pfn		= __phys_to_pfn(0xf0100000),
-		.length		= PAGE_SIZE,
-		.type		= MT_DEVICE_NONSHARED
-	},
-#endif
 	/*
 	 * for FPGA (0x1800000-0x19ffffff)
 	 * 0x18000000-0x18002000 -> 0xf0003000-0xf0005000
@@ -364,11 +343,8 @@
 
 static void __init bonito_map_io(void)
 {
+	r8a7740_map_io();
 	iotable_init(bonito_io_desc, ARRAY_SIZE(bonito_io_desc));
-
-	/* setup early devices and console here as well */
-	r8a7740_add_early_devices();
-	shmobile_setup_console();
 }
 
 /*
@@ -395,7 +371,7 @@
 
 #ifdef CONFIG_CACHE_L2X0
 	/* Early BRESP enable, Shared attribute override enable, 32K*8way */
-	l2x0_init(__io(0xf0002000), 0x40440000, 0x82000fff);
+	l2x0_init(IOMEM(0xf0002000), 0x40440000, 0x82000fff);
 #endif
 
 	r8a7740_add_standard_devices();
@@ -492,7 +468,7 @@
 	}
 }
 
-static void __init bonito_timer_init(void)
+static void __init bonito_earlytimer_init(void)
 {
 	u16 val;
 	u8 md_ck = 0;
@@ -507,17 +483,22 @@
 		md_ck |= MD_CK0;
 
 	r8a7740_clock_init(md_ck);
-	shmobile_timer.init();
+	shmobile_earlytimer_init();
 }
 
-struct sys_timer bonito_timer = {
-	.init	= bonito_timer_init,
-};
+void __init bonito_add_early_devices(void)
+{
+	r8a7740_add_early_devices();
+
+	/* override timer setup with board-specific code */
+	shmobile_timer.init = bonito_earlytimer_init;
+}
 
 MACHINE_START(BONITO, "bonito")
 	.map_io		= bonito_map_io,
+	.init_early	= bonito_add_early_devices,
 	.init_irq	= r8a7740_init_irq,
 	.handle_irq	= shmobile_handle_irq_intc,
 	.init_machine	= bonito_init,
-	.timer		= &bonito_timer,
+	.timer		= &shmobile_timer,
 MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-g3evm.c b/arch/arm/mach-shmobile/board-g3evm.c
index 72d5572..39b6cf8 100644
--- a/arch/arm/mach-shmobile/board-g3evm.c
+++ b/arch/arm/mach-shmobile/board-g3evm.c
@@ -33,12 +33,11 @@
 #include <linux/input.h>
 #include <linux/input/sh_keysc.h>
 #include <linux/dma-mapping.h>
+#include <mach/irqs.h>
 #include <mach/sh7367.h>
 #include <mach/common.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
 
 /*
  * IrDA
@@ -246,27 +245,6 @@
 	&irda_device,
 };
 
-static struct map_desc g3evm_io_desc[] __initdata = {
-	/* create a 1:1 entity map for 0xe6xxxxxx
-	 * used by CPGA, INTC and PFC.
-	 */
-	{
-		.virtual	= 0xe6000000,
-		.pfn		= __phys_to_pfn(0xe6000000),
-		.length		= 256 << 20,
-		.type		= MT_DEVICE_NONSHARED
-	},
-};
-
-static void __init g3evm_map_io(void)
-{
-	iotable_init(g3evm_io_desc, ARRAY_SIZE(g3evm_io_desc));
-
-	/* setup early devices and console here as well */
-	sh7367_add_early_devices();
-	shmobile_setup_console();
-}
-
 static void __init g3evm_init(void)
 {
 	sh7367_pinmux_init();
@@ -354,20 +332,11 @@
 	platform_add_devices(g3evm_devices, ARRAY_SIZE(g3evm_devices));
 }
 
-static void __init g3evm_timer_init(void)
-{
-	sh7367_clock_init();
-	shmobile_timer.init();
-}
-
-static struct sys_timer g3evm_timer = {
-	.init		= g3evm_timer_init,
-};
-
 MACHINE_START(G3EVM, "g3evm")
-	.map_io		= g3evm_map_io,
+	.map_io		= sh7367_map_io,
+	.init_early	= sh7367_add_early_devices,
 	.init_irq	= sh7367_init_irq,
 	.handle_irq	= shmobile_handle_irq_intc,
 	.init_machine	= g3evm_init,
-	.timer		= &g3evm_timer,
+	.timer		= &shmobile_timer,
 MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-g4evm.c b/arch/arm/mach-shmobile/board-g4evm.c
index 2220b88..0e5a39c 100644
--- a/arch/arm/mach-shmobile/board-g4evm.c
+++ b/arch/arm/mach-shmobile/board-g4evm.c
@@ -34,12 +34,11 @@
 #include <linux/mmc/sh_mobile_sdhi.h>
 #include <linux/gpio.h>
 #include <linux/dma-mapping.h>
+#include <mach/irqs.h>
 #include <mach/sh7377.h>
 #include <mach/common.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
 
 /*
  * SDHI
@@ -260,27 +259,6 @@
 	&sdhi1_device,
 };
 
-static struct map_desc g4evm_io_desc[] __initdata = {
-	/* create a 1:1 entity map for 0xe6xxxxxx
-	 * used by CPGA, INTC and PFC.
-	 */
-	{
-		.virtual	= 0xe6000000,
-		.pfn		= __phys_to_pfn(0xe6000000),
-		.length		= 256 << 20,
-		.type		= MT_DEVICE_NONSHARED
-	},
-};
-
-static void __init g4evm_map_io(void)
-{
-	iotable_init(g4evm_io_desc, ARRAY_SIZE(g4evm_io_desc));
-
-	/* setup early devices and console here as well */
-	sh7377_add_early_devices();
-	shmobile_setup_console();
-}
-
 #define GPIO_SDHID0_D0	0xe60520fc
 #define GPIO_SDHID0_D1	0xe60520fd
 #define GPIO_SDHID0_D2	0xe60520fe
@@ -397,20 +375,11 @@
 	platform_add_devices(g4evm_devices, ARRAY_SIZE(g4evm_devices));
 }
 
-static void __init g4evm_timer_init(void)
-{
-	sh7377_clock_init();
-	shmobile_timer.init();
-}
-
-static struct sys_timer g4evm_timer = {
-	.init		= g4evm_timer_init,
-};
-
 MACHINE_START(G4EVM, "g4evm")
-	.map_io		= g4evm_map_io,
+	.map_io		= sh7377_map_io,
+	.init_early	= sh7377_add_early_devices,
 	.init_irq	= sh7377_init_irq,
 	.handle_irq	= shmobile_handle_irq_intc,
 	.init_machine	= g4evm_init,
-	.timer		= &g4evm_timer,
+	.timer		= &shmobile_timer,
 MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c
index c8e7ca2..200dcd4 100644
--- a/arch/arm/mach-shmobile/board-kota2.c
+++ b/arch/arm/mach-shmobile/board-kota2.c
@@ -39,11 +39,11 @@
 #include <linux/mfd/tmio.h>
 #include <linux/mmc/sh_mobile_sdhi.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 #include <mach/sh73a0.h>
 #include <mach/common.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/map.h>
 #include <asm/mach/time.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -409,27 +409,6 @@
 	&sdhi1_device,
 };
 
-static struct map_desc kota2_io_desc[] __initdata = {
-	/* create a 1:1 entity map for 0xe6xxxxxx
-	 * used by CPGA, INTC and PFC.
-	 */
-	{
-		.virtual	= 0xe6000000,
-		.pfn		= __phys_to_pfn(0xe6000000),
-		.length		= 256 << 20,
-		.type		= MT_DEVICE_NONSHARED
-	},
-};
-
-static void __init kota2_map_io(void)
-{
-	iotable_init(kota2_io_desc, ARRAY_SIZE(kota2_io_desc));
-
-	/* setup early devices and console here as well */
-	sh73a0_add_early_devices();
-	shmobile_setup_console();
-}
-
 static void __init kota2_init(void)
 {
 	sh73a0_pinmux_init();
@@ -529,28 +508,18 @@
 
 #ifdef CONFIG_CACHE_L2X0
 	/* Early BRESP enable, Shared attribute override enable, 64K*8way */
-	l2x0_init(__io(0xf0100000), 0x40460000, 0x82000fff);
+	l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff);
 #endif
 	sh73a0_add_standard_devices();
 	platform_add_devices(kota2_devices, ARRAY_SIZE(kota2_devices));
 }
 
-static void __init kota2_timer_init(void)
-{
-	sh73a0_clock_init();
-	shmobile_timer.init();
-	return;
-}
-
-struct sys_timer kota2_timer = {
-	.init	= kota2_timer_init,
-};
-
 MACHINE_START(KOTA2, "kota2")
-	.map_io		= kota2_map_io,
+	.map_io		= sh73a0_map_io,
+	.init_early	= sh73a0_add_early_devices,
 	.nr_irqs	= NR_IRQS_LEGACY,
 	.init_irq	= sh73a0_init_irq,
 	.handle_irq	= gic_handle_irq,
 	.init_machine	= kota2_init,
-	.timer		= &kota2_timer,
+	.timer		= &shmobile_timer,
 MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index 7b53cda..f49e28a 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -39,6 +39,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
+#include <linux/mtd/sh_flctl.h>
 #include <linux/pm_clock.h>
 #include <linux/smsc911x.h>
 #include <linux/sh_intc.h>
@@ -54,11 +55,10 @@
 #include <sound/sh_fsi.h>
 
 #include <mach/common.h>
+#include <mach/irqs.h>
 #include <mach/sh7372.h>
 
 #include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-#include <asm/mach/map.h>
 #include <asm/mach-types.h>
 
 /*
@@ -318,8 +318,14 @@
 
 static struct resource meram_resources[] = {
 	[0] = {
-		.name	= "MERAM",
+		.name	= "regs",
 		.start	= 0xe8000000,
+		.end	= 0xe807ffff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "meram",
+		.start	= 0xe8080000,
 		.end	= 0xe81fffff,
 		.flags	= IORESOURCE_MEM,
 	},
@@ -351,29 +357,23 @@
 	},
 };
 
-static int mackerel_set_brightness(void *board_data, int brightness)
+static int mackerel_set_brightness(int brightness)
 {
 	gpio_set_value(GPIO_PORT31, brightness);
 
 	return 0;
 }
 
-static int mackerel_get_brightness(void *board_data)
+static int mackerel_get_brightness(void)
 {
 	return gpio_get_value(GPIO_PORT31);
 }
 
-static struct sh_mobile_meram_cfg lcd_meram_cfg = {
+static const struct sh_mobile_meram_cfg lcd_meram_cfg = {
 	.icb[0] = {
-		.marker_icb     = 28,
-		.cache_icb      = 24,
-		.meram_offset   = 0x0,
 		.meram_size     = 0x40,
 	},
 	.icb[1] = {
-		.marker_icb     = 29,
-		.cache_icb      = 25,
-		.meram_offset   = 0x40,
 		.meram_size     = 0x40,
 	},
 };
@@ -384,20 +384,20 @@
 	.ch[0] = {
 		.chan = LCDC_CHAN_MAINLCD,
 		.fourcc = V4L2_PIX_FMT_RGB565,
-		.lcd_cfg = mackerel_lcdc_modes,
-		.num_cfg = ARRAY_SIZE(mackerel_lcdc_modes),
+		.lcd_modes = mackerel_lcdc_modes,
+		.num_modes = ARRAY_SIZE(mackerel_lcdc_modes),
 		.interface_type		= RGB24,
 		.clock_divider		= 3,
 		.flags			= 0,
-		.lcd_size_cfg.width	= 152,
-		.lcd_size_cfg.height	= 91,
-		.board_cfg = {
-			.set_brightness = mackerel_set_brightness,
-			.get_brightness = mackerel_get_brightness,
+		.panel_cfg = {
+			.width		= 152,
+			.height		= 91,
 		},
 		.bl_info = {
 			.name = "sh_mobile_lcdc_bl",
 			.max_brightness = 1,
+			.set_brightness = mackerel_set_brightness,
+			.get_brightness = mackerel_get_brightness,
 		},
 		.meram_cfg = &lcd_meram_cfg,
 	}
@@ -426,61 +426,8 @@
 	},
 };
 
-static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
-	.icb[0] = {
-		.marker_icb     = 30,
-		.cache_icb      = 26,
-		.meram_offset   = 0x80,
-		.meram_size     = 0x100,
-	},
-	.icb[1] = {
-		.marker_icb     = 31,
-		.cache_icb      = 27,
-		.meram_offset   = 0x180,
-		.meram_size     = 0x100,
-	},
-};
 /* HDMI */
-static struct sh_mobile_lcdc_info hdmi_lcdc_info = {
-	.meram_dev = &mackerel_meram_info,
-	.clock_source = LCDC_CLK_EXTERNAL,
-	.ch[0] = {
-		.chan = LCDC_CHAN_MAINLCD,
-		.fourcc = V4L2_PIX_FMT_RGB565,
-		.interface_type = RGB24,
-		.clock_divider = 1,
-		.flags = LCDC_FLAGS_DWPOL,
-		.meram_cfg = &hdmi_meram_cfg,
-	}
-};
-
-static struct resource hdmi_lcdc_resources[] = {
-	[0] = {
-		.name	= "LCDC1",
-		.start	= 0xfe944000,
-		.end	= 0xfe947fff,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= intcs_evt2irq(0x1780),
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device hdmi_lcdc_device = {
-	.name		= "sh_mobile_lcdc_fb",
-	.num_resources	= ARRAY_SIZE(hdmi_lcdc_resources),
-	.resource	= hdmi_lcdc_resources,
-	.id		= 1,
-	.dev	= {
-		.platform_data	= &hdmi_lcdc_info,
-		.coherent_dma_mask = ~0,
-	},
-};
-
 static struct sh_mobile_hdmi_info hdmi_info = {
-	.lcd_chan	= &hdmi_lcdc_info.ch[0],
-	.lcd_dev	= &hdmi_lcdc_device.dev,
 	.flags		= HDMI_SND_SRC_SPDIF,
 };
 
@@ -508,6 +455,53 @@
 	},
 };
 
+static const struct sh_mobile_meram_cfg hdmi_meram_cfg = {
+	.icb[0] = {
+		.meram_size     = 0x100,
+	},
+	.icb[1] = {
+		.meram_size     = 0x100,
+	},
+};
+
+static struct sh_mobile_lcdc_info hdmi_lcdc_info = {
+	.meram_dev = &mackerel_meram_info,
+	.clock_source = LCDC_CLK_EXTERNAL,
+	.ch[0] = {
+		.chan = LCDC_CHAN_MAINLCD,
+		.fourcc = V4L2_PIX_FMT_RGB565,
+		.interface_type = RGB24,
+		.clock_divider = 1,
+		.flags = LCDC_FLAGS_DWPOL,
+		.meram_cfg = &hdmi_meram_cfg,
+		.tx_dev = &hdmi_device,
+	}
+};
+
+static struct resource hdmi_lcdc_resources[] = {
+	[0] = {
+		.name	= "LCDC1",
+		.start	= 0xfe944000,
+		.end	= 0xfe947fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= intcs_evt2irq(0x1780),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device hdmi_lcdc_device = {
+	.name		= "sh_mobile_lcdc_fb",
+	.num_resources	= ARRAY_SIZE(hdmi_lcdc_resources),
+	.resource	= hdmi_lcdc_resources,
+	.id		= 1,
+	.dev	= {
+		.platform_data	= &hdmi_lcdc_info,
+		.coherent_dma_mask = ~0,
+	},
+};
+
 static struct platform_device fsi_hdmi_device = {
 	.name		= "sh_fsi2_b_hdmi",
 };
@@ -860,7 +854,7 @@
 	return clk_enable(clk);
 }
 
-static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable)
+static int fsi_b_set_rate(struct device *dev, int rate, int enable)
 {
 	struct clk *fsib_clk;
 	struct clk *fdiv_clk = &sh7372_fsidivb_clk;
@@ -869,10 +863,6 @@
 	int ackmd_bpfmd;
 	int ret;
 
-	/* FSIA is slave mode. nothing to do here */
-	if (is_porta)
-		return 0;
-
 	/* clock start */
 	switch (rate) {
 	case 44100:
@@ -916,14 +906,16 @@
 }
 
 static struct sh_fsi_platform_info fsi_info = {
-	.porta_flags =	SH_FSI_BRS_INV,
-
-	.portb_flags =	SH_FSI_BRS_INV	|
+	.port_a = {
+		.flags = SH_FSI_BRS_INV,
+	},
+	.port_b = {
+		.flags = SH_FSI_BRS_INV	|
 			SH_FSI_BRM_INV	|
 			SH_FSI_LRS_INV	|
 			SH_FSI_FMT_SPDIF,
-
-	.set_rate = fsi_set_rate,
+		.set_rate = fsi_b_set_rate,
+	}
 };
 
 static struct resource fsi_resources[] = {
@@ -965,6 +957,50 @@
 	},
 };
 
+/* FLCTL */
+static struct mtd_partition nand_partition_info[] = {
+	{
+		.name	= "system",
+		.offset	= 0,
+		.size	= 128 * 1024 * 1024,
+	},
+	{
+		.name	= "userdata",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= 256 * 1024 * 1024,
+	},
+	{
+		.name	= "cache",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= 128 * 1024 * 1024,
+	},
+};
+
+static struct resource nand_flash_resources[] = {
+	[0] = {
+		.start	= 0xe6a30000,
+		.end	= 0xe6a3009b,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct sh_flctl_platform_data nand_flash_data = {
+	.parts		= nand_partition_info,
+	.nr_parts	= ARRAY_SIZE(nand_partition_info),
+	.flcmncr_val	= CLK_16B_12L_4H | TYPESEL_SET
+			| SHBUSSEL | SEL_16BIT | SNAND_E,
+	.use_holden	= 1,
+};
+
+static struct platform_device nand_flash_device = {
+	.name		= "sh_flctl",
+	.resource	= nand_flash_resources,
+	.num_resources	= ARRAY_SIZE(nand_flash_resources),
+	.dev		= {
+		.platform_data = &nand_flash_data,
+	},
+};
+
 /*
  * The card detect pin of the top SD/MMC slot (CN7) is active low and is
  * connected to GPIO A22 of SH7372 (GPIO_PORT41).
@@ -1268,6 +1304,7 @@
 	&fsi_device,
 	&fsi_ak4643_device,
 	&fsi_hdmi_device,
+	&nand_flash_device,
 	&sdhi0_device,
 #if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
 	&sdhi1_device,
@@ -1276,8 +1313,8 @@
 	&sh_mmcif_device,
 	&ceu_device,
 	&mackerel_camera,
-	&hdmi_lcdc_device,
 	&hdmi_device,
+	&hdmi_lcdc_device,
 	&meram_device,
 };
 
@@ -1337,31 +1374,6 @@
 	},
 };
 
-static struct map_desc mackerel_io_desc[] __initdata = {
-	/* create a 1:1 entity map for 0xe6xxxxxx
-	 * used by CPGA, INTC and PFC.
-	 */
-	{
-		.virtual	= 0xe6000000,
-		.pfn		= __phys_to_pfn(0xe6000000),
-		.length		= 256 << 20,
-		.type		= MT_DEVICE_NONSHARED
-	},
-};
-
-static void __init mackerel_map_io(void)
-{
-	iotable_init(mackerel_io_desc, ARRAY_SIZE(mackerel_io_desc));
-	/* DMA memory at 0xff200000 - 0xffdfffff. The default 2MB size isn't
-	 * enough to allocate the frame buffer memory.
-	 */
-	init_consistent_dma_size(12 << 20);
-
-	/* setup early devices and console here as well */
-	sh7372_add_early_devices();
-	shmobile_setup_console();
-}
-
 #define GPIO_PORT9CR	0xE6051009
 #define GPIO_PORT10CR	0xE605100A
 #define GPIO_PORT167CR	0xE60520A7
@@ -1374,6 +1386,9 @@
 	struct clk *clk;
 	int ret;
 
+	/* External clock source */
+	clk_set_rate(&sh7372_dv_clki_clk, 27000000);
+
 	sh7372_pinmux_init();
 
 	/* enable SCIFA0 */
@@ -1519,6 +1534,30 @@
 	gpio_request(GPIO_FN_MMCCMD0, NULL);
 	gpio_request(GPIO_FN_MMCCLK0, NULL);
 
+	/* FLCTL */
+	gpio_request(GPIO_FN_D0_NAF0, NULL);
+	gpio_request(GPIO_FN_D1_NAF1, NULL);
+	gpio_request(GPIO_FN_D2_NAF2, NULL);
+	gpio_request(GPIO_FN_D3_NAF3, NULL);
+	gpio_request(GPIO_FN_D4_NAF4, NULL);
+	gpio_request(GPIO_FN_D5_NAF5, NULL);
+	gpio_request(GPIO_FN_D6_NAF6, NULL);
+	gpio_request(GPIO_FN_D7_NAF7, NULL);
+	gpio_request(GPIO_FN_D8_NAF8, NULL);
+	gpio_request(GPIO_FN_D9_NAF9, NULL);
+	gpio_request(GPIO_FN_D10_NAF10, NULL);
+	gpio_request(GPIO_FN_D11_NAF11, NULL);
+	gpio_request(GPIO_FN_D12_NAF12, NULL);
+	gpio_request(GPIO_FN_D13_NAF13, NULL);
+	gpio_request(GPIO_FN_D14_NAF14, NULL);
+	gpio_request(GPIO_FN_D15_NAF15, NULL);
+	gpio_request(GPIO_FN_FCE0, NULL);
+	gpio_request(GPIO_FN_WE0_FWE, NULL);
+	gpio_request(GPIO_FN_FRB, NULL);
+	gpio_request(GPIO_FN_A4_FOE, NULL);
+	gpio_request(GPIO_FN_A5_FCDE, NULL);
+	gpio_request(GPIO_FN_RD_FSC, NULL);
+
 	/* enable GPS module (GT-720F) */
 	gpio_request(GPIO_FN_SCIFA2_TXD1, NULL);
 	gpio_request(GPIO_FN_SCIFA2_RXD1, NULL);
@@ -1563,6 +1602,7 @@
 	sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device);
 	sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs0_device);
 	sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs1_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &nand_flash_device);
 	sh7372_add_device_to_domain(&sh7372_a3sp, &sh_mmcif_device);
 	sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi0_device);
 #if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
@@ -1577,23 +1617,11 @@
 	pm_clk_add(&hdmi_lcdc_device.dev, "hdmi");
 }
 
-static void __init mackerel_timer_init(void)
-{
-	sh7372_clock_init();
-	shmobile_timer.init();
-
-	/* External clock source */
-	clk_set_rate(&sh7372_dv_clki_clk, 27000000);
-}
-
-static struct sys_timer mackerel_timer = {
-	.init		= mackerel_timer_init,
-};
-
 MACHINE_START(MACKEREL, "mackerel")
-	.map_io		= mackerel_map_io,
+	.map_io		= sh7372_map_io,
+	.init_early	= sh7372_add_early_devices,
 	.init_irq	= sh7372_init_irq,
 	.handle_irq	= shmobile_handle_irq_intc,
 	.init_machine	= mackerel_init,
-	.timer		= &mackerel_timer,
+	.timer		= &shmobile_timer,
 MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-marzen.c b/arch/arm/mach-shmobile/board-marzen.c
index f0e02c0..ef0e13b 100644
--- a/arch/arm/mach-shmobile/board-marzen.c
+++ b/arch/arm/mach-shmobile/board-marzen.c
@@ -31,10 +31,9 @@
 #include <mach/hardware.h>
 #include <mach/r8a7779.h>
 #include <mach/common.h>
+#include <mach/irqs.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
 #include <asm/hardware/gic.h>
 #include <asm/traps.h>
 
@@ -72,49 +71,6 @@
 	&eth_device,
 };
 
-static struct map_desc marzen_io_desc[] __initdata = {
-	/* 2M entity map for 0xf0000000 (MPCORE) */
-	{
-		.virtual	= 0xf0000000,
-		.pfn		= __phys_to_pfn(0xf0000000),
-		.length		= SZ_2M,
-		.type		= MT_DEVICE_NONSHARED
-	},
-	/* 16M entity map for 0xfexxxxxx (DMAC-S/HPBREG/INTC2/LRAM/DBSC) */
-	{
-		.virtual	= 0xfe000000,
-		.pfn		= __phys_to_pfn(0xfe000000),
-		.length		= SZ_16M,
-		.type		= MT_DEVICE_NONSHARED
-	},
-};
-
-static void __init marzen_map_io(void)
-{
-	iotable_init(marzen_io_desc, ARRAY_SIZE(marzen_io_desc));
-}
-
-static void __init marzen_init_early(void)
-{
-	r8a7779_add_early_devices();
-
-	/* Early serial console setup is not included here due to
-	 * memory map collisions. The SCIF serial ports in r8a7779
-	 * are difficult to entity map 1:1 due to collision with the
-	 * virtual memory range used by the coherent DMA code on ARM.
-	 *
-	 * Anyone wanting to debug early can remove UPF_IOREMAP from
-	 * the sh-sci serial console platform data, adjust mapbase
-	 * to a static M:N virt:phys mapping that needs to be added to
-	 * the mappings passed with iotable_init() above.
-	 *
-	 * Then add a call to shmobile_setup_console() from this function.
-	 *
-	 * As a final step pass earlyprint=sh-sci.2,115200 on the kernel
-	 * command line.
-	 */
-}
-
 static void __init marzen_init(void)
 {
 	r8a7779_pinmux_init();
@@ -135,23 +91,12 @@
 	platform_add_devices(marzen_devices, ARRAY_SIZE(marzen_devices));
 }
 
-static void __init marzen_timer_init(void)
-{
-	r8a7779_clock_init();
-	shmobile_timer.init();
-	return;
-}
-
-struct sys_timer marzen_timer = {
-	.init	= marzen_timer_init,
-};
-
 MACHINE_START(MARZEN, "marzen")
-	.map_io		= marzen_map_io,
-	.init_early	= marzen_init_early,
+	.map_io		= r8a7779_map_io,
+	.init_early	= r8a7779_add_early_devices,
 	.nr_irqs	= NR_IRQS_LEGACY,
 	.init_irq	= r8a7779_init_irq,
 	.handle_irq	= gic_handle_irq,
 	.init_machine	= marzen_init,
-	.timer		= &marzen_timer,
+	.timer		= &shmobile_timer,
 MACHINE_END
diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c
index 3b35b9a..99c4d74 100644
--- a/arch/arm/mach-shmobile/clock-r8a7740.c
+++ b/arch/arm/mach-shmobile/clock-r8a7740.c
@@ -93,7 +93,7 @@
 	return clk->parent->rate / (int)(clk->priv);
 }
 
-static struct clk_ops div_clk_ops = {
+static struct sh_clk_ops div_clk_ops = {
 	.recalc	= div_recalc,
 };
 
@@ -125,7 +125,7 @@
 	.parent	= &extal2_clk,
 };
 
-static struct clk_ops followparent_clk_ops = {
+static struct sh_clk_ops followparent_clk_ops = {
 	.recalc	= followparent_recalc,
 };
 
@@ -156,7 +156,7 @@
 	return clk->parent->rate * mult;
 }
 
-static struct clk_ops pllc01_clk_ops = {
+static struct sh_clk_ops pllc01_clk_ops = {
 	.recalc		= pllc01_recalc,
 };
 
@@ -376,7 +376,7 @@
 	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
 	if (!ret)
-		clk_init();
+		shmobile_clk_init();
 	else
 		panic("failed to setup r8a7740 clocks\n");
 }
diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c
index b4b0e8c..7d6e9fe 100644
--- a/arch/arm/mach-shmobile/clock-r8a7779.c
+++ b/arch/arm/mach-shmobile/clock-r8a7779.c
@@ -107,7 +107,7 @@
 	return clk->parent->rate * 4;
 }
 
-static struct clk_ops mul4_clk_ops = {
+static struct sh_clk_ops mul4_clk_ops = {
 	.recalc		= mul4_recalc,
 };
 
@@ -170,7 +170,7 @@
 	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
 	if (!ret)
-		clk_init();
+		shmobile_clk_init();
 	else
 		panic("failed to setup r8a7779 clocks\n");
 }
diff --git a/arch/arm/mach-shmobile/clock-sh7367.c b/arch/arm/mach-shmobile/clock-sh7367.c
index 5218c34..006e7b5 100644
--- a/arch/arm/mach-shmobile/clock-sh7367.c
+++ b/arch/arm/mach-shmobile/clock-sh7367.c
@@ -74,7 +74,7 @@
 	return clk->parent->rate / 2;
 }
 
-static struct clk_ops div2_clk_ops = {
+static struct sh_clk_ops div2_clk_ops = {
 	.recalc		= div2_recalc,
 };
 
@@ -101,7 +101,7 @@
 	return clk->parent->rate * mult;
 }
 
-static struct clk_ops pllc1_clk_ops = {
+static struct sh_clk_ops pllc1_clk_ops = {
 	.recalc		= pllc1_recalc,
 };
 
@@ -128,7 +128,7 @@
 	return clk->parent->rate * mult;
 }
 
-static struct clk_ops pllc2_clk_ops = {
+static struct sh_clk_ops pllc2_clk_ops = {
 	.recalc		= pllc2_recalc,
 };
 
@@ -349,7 +349,7 @@
 	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
 	if (!ret)
-		clk_init();
+		shmobile_clk_init();
 	else
 		panic("failed to setup sh7367 clocks\n");
 }
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c
index 293456d..94d1f88 100644
--- a/arch/arm/mach-shmobile/clock-sh7372.c
+++ b/arch/arm/mach-shmobile/clock-sh7372.c
@@ -89,7 +89,7 @@
 	return clk->parent->rate / 2;
 }
 
-static struct clk_ops div2_clk_ops = {
+static struct sh_clk_ops div2_clk_ops = {
 	.recalc		= div2_recalc,
 };
 
@@ -128,7 +128,7 @@
 	return clk->parent->rate * mult;
 }
 
-static struct clk_ops pllc01_clk_ops = {
+static struct sh_clk_ops pllc01_clk_ops = {
 	.recalc		= pllc01_recalc,
 };
 
@@ -276,7 +276,7 @@
 	return 0;
 }
 
-static struct clk_ops pllc2_clk_ops = {
+static struct sh_clk_ops pllc2_clk_ops = {
 	.recalc		= pllc2_recalc,
 	.round_rate	= pllc2_round_rate,
 	.set_rate	= pllc2_set_rate,
@@ -468,7 +468,7 @@
 	return 0;
 }
 
-static struct clk_ops fsidiv_clk_ops = {
+static struct sh_clk_ops fsidiv_clk_ops = {
 	.recalc		= fsidiv_recalc,
 	.round_rate	= fsidiv_round_rate,
 	.set_rate	= fsidiv_set_rate,
@@ -511,7 +511,7 @@
        MSTP223,
        MSTP218, MSTP217, MSTP216, MSTP214, MSTP208, MSTP207,
        MSTP206, MSTP205, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
-       MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312,
+	MSTP328, MSTP323, MSTP322, MSTP315, MSTP314, MSTP313, MSTP312,
        MSTP423, MSTP415, MSTP413, MSTP411, MSTP410, MSTP407, MSTP406,
        MSTP405, MSTP404, MSTP403, MSTP400,
        MSTP_NR };
@@ -553,6 +553,7 @@
 	[MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, 0), /* FSI2 */
 	[MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */
 	[MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */
+	[MSTP315] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 15, 0), /* FLCTL*/
 	[MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */
 	[MSTP313] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */
 	[MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMC */
@@ -653,6 +654,7 @@
 	CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USB0 */
 	CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USB0 */
 	CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP322]), /* USB0 */
+	CLKDEV_DEV_ID("sh_flctl.0", &mstp_clks[MSTP315]), /* FLCTL */
 	CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
 	CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
 	CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */
@@ -710,7 +712,7 @@
 	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
 	if (!ret)
-		clk_init();
+		shmobile_clk_init();
 	else
 		panic("failed to setup sh7372 clocks\n");
 
diff --git a/arch/arm/mach-shmobile/clock-sh7377.c b/arch/arm/mach-shmobile/clock-sh7377.c
index 8cee7b1..0798a15 100644
--- a/arch/arm/mach-shmobile/clock-sh7377.c
+++ b/arch/arm/mach-shmobile/clock-sh7377.c
@@ -77,7 +77,7 @@
 	return clk->parent->rate / 2;
 }
 
-static struct clk_ops div2_clk_ops = {
+static struct sh_clk_ops div2_clk_ops = {
 	.recalc		= div2_recalc,
 };
 
@@ -110,7 +110,7 @@
 	return clk->parent->rate * mult;
 }
 
-static struct clk_ops pllc1_clk_ops = {
+static struct sh_clk_ops pllc1_clk_ops = {
 	.recalc		= pllc1_recalc,
 };
 
@@ -137,7 +137,7 @@
 	return clk->parent->rate * mult;
 }
 
-static struct clk_ops pllc2_clk_ops = {
+static struct sh_clk_ops pllc2_clk_ops = {
 	.recalc		= pllc2_recalc,
 };
 
@@ -360,7 +360,7 @@
 	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
 	if (!ret)
-		clk_init();
+		shmobile_clk_init();
 	else
 		panic("failed to setup sh7377 clocks\n");
 }
diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c
index 7727cca..472d1f5 100644
--- a/arch/arm/mach-shmobile/clock-sh73a0.c
+++ b/arch/arm/mach-shmobile/clock-sh73a0.c
@@ -88,7 +88,7 @@
 	return clk->parent->rate / 2;
 }
 
-static struct clk_ops div2_clk_ops = {
+static struct sh_clk_ops div2_clk_ops = {
 	.recalc		= div2_recalc,
 };
 
@@ -97,7 +97,7 @@
 	return clk->parent->rate / 7;
 }
 
-static struct clk_ops div7_clk_ops = {
+static struct sh_clk_ops div7_clk_ops = {
 	.recalc		= div7_recalc,
 };
 
@@ -106,7 +106,7 @@
 	return clk->parent->rate / 13;
 }
 
-static struct clk_ops div13_clk_ops = {
+static struct sh_clk_ops div13_clk_ops = {
 	.recalc		= div13_recalc,
 };
 
@@ -122,7 +122,7 @@
 	.parent		= &sh73a0_extal2_clk,
 };
 
-static struct clk_ops main_clk_ops = {
+static struct sh_clk_ops main_clk_ops = {
 	.recalc		= followparent_recalc,
 };
 
@@ -156,7 +156,7 @@
 	return clk->parent->rate * mult;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
 	.recalc		= pll_recalc,
 };
 
@@ -438,7 +438,7 @@
 	return 0;
 }
 
-static struct clk_ops dsiphy_clk_ops = {
+static struct sh_clk_ops dsiphy_clk_ops = {
 	.recalc		= dsiphy_recalc,
 	.round_rate	= dsiphy_round_rate,
 	.set_rate	= dsiphy_set_rate,
@@ -620,7 +620,7 @@
 	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
 	if (!ret)
-		clk_init();
+		shmobile_clk_init();
 	else
 		panic("failed to setup sh73a0 clocks\n");
 }
diff --git a/arch/arm/mach-shmobile/clock.c b/arch/arm/mach-shmobile/clock.c
index 31654d7..e816ca9 100644
--- a/arch/arm/mach-shmobile/clock.c
+++ b/arch/arm/mach-shmobile/clock.c
@@ -24,7 +24,7 @@
 #include <linux/sh_clk.h>
 #include <linux/export.h>
 
-int __init clk_init(void)
+int __init shmobile_clk_init(void)
 {
 	/* Kick the child clocks.. */
 	recalculate_root_clocks();
diff --git a/arch/arm/mach-shmobile/cpuidle.c b/arch/arm/mach-shmobile/cpuidle.c
index 1b23342..7e65591 100644
--- a/arch/arm/mach-shmobile/cpuidle.c
+++ b/arch/arm/mach-shmobile/cpuidle.c
@@ -13,7 +13,7 @@
 #include <linux/suspend.h>
 #include <linux/module.h>
 #include <linux/err.h>
-#include <asm/system.h>
+#include <asm/cpuidle.h>
 #include <asm/io.h>
 
 static void shmobile_enter_wfi(void)
@@ -29,37 +29,19 @@
 				  struct cpuidle_driver *drv,
 				  int index)
 {
-	ktime_t before, after;
-
-	before = ktime_get();
-
-	local_irq_disable();
-	local_fiq_disable();
-
 	shmobile_cpuidle_modes[index]();
 
-	local_irq_enable();
-	local_fiq_enable();
-
-	after = ktime_get();
-	dev->last_residency = ktime_to_ns(ktime_sub(after, before)) >> 10;
-
 	return index;
 }
 
 static struct cpuidle_device shmobile_cpuidle_dev;
 static struct cpuidle_driver shmobile_cpuidle_driver = {
-	.name =		"shmobile_cpuidle",
-	.owner =	THIS_MODULE,
-	.states[0] = {
-		.name = "C1",
-		.desc = "WFI",
-		.exit_latency = 1,
-		.target_residency = 1 * 2,
-		.flags = CPUIDLE_FLAG_TIME_VALID,
-	},
-	.safe_state_index = 0, /* C1 */
-	.state_count = 1,
+	.name			= "shmobile_cpuidle",
+	.owner			= THIS_MODULE,
+	.en_core_tk_irqen	= 1,
+	.states[0]		= ARM_CPUIDLE_WFI_STATE,
+	.safe_state_index	= 0, /* C1 */
+	.state_count		= 1,
 };
 
 void (*shmobile_cpuidle_setup)(struct cpuidle_driver *drv);
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index e4b945e..83ad3fe 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -1,12 +1,15 @@
 #ifndef __ARCH_MACH_COMMON_H
 #define __ARCH_MACH_COMMON_H
 
+extern void shmobile_earlytimer_init(void);
 extern struct sys_timer shmobile_timer;
+struct twd_local_timer;
+void shmobile_twd_init(struct twd_local_timer *twd_local_timer);
 extern void shmobile_setup_console(void);
 extern void shmobile_secondary_vector(void);
 extern int shmobile_platform_cpu_kill(unsigned int cpu);
 struct clk;
-extern int clk_init(void);
+extern int shmobile_clk_init(void);
 extern void shmobile_handle_irq_intc(struct pt_regs *);
 extern struct platform_suspend_ops shmobile_suspend_ops;
 struct cpuidle_driver;
@@ -14,6 +17,7 @@
 extern void (*shmobile_cpuidle_setup)(struct cpuidle_driver *drv);
 
 extern void sh7367_init_irq(void);
+extern void sh7367_map_io(void);
 extern void sh7367_add_early_devices(void);
 extern void sh7367_add_standard_devices(void);
 extern void sh7367_clock_init(void);
@@ -22,6 +26,7 @@
 extern struct clk sh7367_extal2_clk;
 
 extern void sh7377_init_irq(void);
+extern void sh7377_map_io(void);
 extern void sh7377_add_early_devices(void);
 extern void sh7377_add_standard_devices(void);
 extern void sh7377_clock_init(void);
@@ -30,6 +35,7 @@
 extern struct clk sh7377_extal2_clk;
 
 extern void sh7372_init_irq(void);
+extern void sh7372_map_io(void);
 extern void sh7372_add_early_devices(void);
 extern void sh7372_add_standard_devices(void);
 extern void sh7372_clock_init(void);
@@ -41,6 +47,7 @@
 extern struct clk sh7372_extal2_clk;
 
 extern void sh73a0_init_irq(void);
+extern void sh73a0_map_io(void);
 extern void sh73a0_add_early_devices(void);
 extern void sh73a0_add_standard_devices(void);
 extern void sh73a0_clock_init(void);
@@ -56,12 +63,14 @@
 extern void sh73a0_smp_prepare_cpus(void);
 
 extern void r8a7740_init_irq(void);
+extern void r8a7740_map_io(void);
 extern void r8a7740_add_early_devices(void);
 extern void r8a7740_add_standard_devices(void);
 extern void r8a7740_clock_init(u8 md_ck);
 extern void r8a7740_pinmux_init(void);
 
 extern void r8a7779_init_irq(void);
+extern void r8a7779_map_io(void);
 extern void r8a7779_add_early_devices(void);
 extern void r8a7779_add_standard_devices(void);
 extern void r8a7779_clock_init(void);
diff --git a/arch/arm/mach-shmobile/include/mach/entry-macro.S b/arch/arm/mach-shmobile/include/mach/entry-macro.S
deleted file mode 100644
index 2a57b29..0000000
--- a/arch/arm/mach-shmobile/include/mach/entry-macro.S
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2010  Paul Mundt
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-	.macro  disable_fiq
-	.endm
-
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
diff --git a/arch/arm/mach-shmobile/include/mach/io.h b/arch/arm/mach-shmobile/include/mach/io.h
deleted file mode 100644
index 7339fe4..0000000
--- a/arch/arm/mach-shmobile/include/mach/io.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __ASM_MACH_IO_H
-#define __ASM_MACH_IO_H
-
-#define IO_SPACE_LIMIT		0xffffffff
-
-#define __io(a)			((void __iomem *)(a))
-#define __mem_pci(a)		(a)
-
-#endif /* __ASM_MACH_IO_H */
diff --git a/arch/arm/mach-shmobile/include/mach/irqs.h b/arch/arm/mach-shmobile/include/mach/irqs.h
index dcb714f..4e686cc2 100644
--- a/arch/arm/mach-shmobile/include/mach/irqs.h
+++ b/arch/arm/mach-shmobile/include/mach/irqs.h
@@ -1,15 +1,11 @@
 #ifndef __ASM_MACH_IRQS_H
 #define __ASM_MACH_IRQS_H
 
-#define NR_IRQS         1024
+#include <linux/sh_intc.h>
 
 /* GIC */
 #define gic_spi(nr)		((nr) + 32)
 
-/* INTCA */
-#define evt2irq(evt)		(((evt) >> 5) - 16)
-#define irq2evt(irq)		(((irq) + 16) << 5)
-
 /* INTCS */
 #define INTCS_VECT_BASE		0x2200
 #define INTCS_VECT(n, vect)	INTC_VECT((n), INTCS_VECT_BASE + (vect))
diff --git a/arch/arm/mach-shmobile/include/mach/system.h b/arch/arm/mach-shmobile/include/mach/system.h
index 956ac18..540eaff 100644
--- a/arch/arm/mach-shmobile/include/mach/system.h
+++ b/arch/arm/mach-shmobile/include/mach/system.h
@@ -1,10 +1,7 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
+#include <asm/system_misc.h>
 
 static inline void arch_reset(char mode, const char *cmd)
 {
diff --git a/arch/arm/mach-shmobile/intc-r8a7740.c b/arch/arm/mach-shmobile/intc-r8a7740.c
index 272c84c..09c42af 100644
--- a/arch/arm/mach-shmobile/intc-r8a7740.c
+++ b/arch/arm/mach-shmobile/intc-r8a7740.c
@@ -25,6 +25,7 @@
 #include <linux/io.h>
 #include <linux/sh_intc.h>
 #include <mach/intc.h>
+#include <mach/irqs.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
diff --git a/arch/arm/mach-shmobile/intc-r8a7779.c b/arch/arm/mach-shmobile/intc-r8a7779.c
index 5d92fcd..550b23d 100644
--- a/arch/arm/mach-shmobile/intc-r8a7779.c
+++ b/arch/arm/mach-shmobile/intc-r8a7779.c
@@ -42,8 +42,8 @@
 
 void __init r8a7779_init_irq(void)
 {
-	void __iomem *gic_dist_base = __io(0xf0001000);
-	void __iomem *gic_cpu_base = __io(0xf0000100);
+	void __iomem *gic_dist_base = IOMEM(0xf0001000);
+	void __iomem *gic_cpu_base = IOMEM(0xf0000100);
 
 	/* use GIC to handle interrupts */
 	gic_init(0, 29, gic_dist_base, gic_cpu_base);
diff --git a/arch/arm/mach-shmobile/intc-sh7367.c b/arch/arm/mach-shmobile/intc-sh7367.c
index cfde9bf..5bf7764 100644
--- a/arch/arm/mach-shmobile/intc-sh7367.c
+++ b/arch/arm/mach-shmobile/intc-sh7367.c
@@ -23,6 +23,7 @@
 #include <linux/io.h>
 #include <linux/sh_intc.h>
 #include <mach/intc.h>
+#include <mach/irqs.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c
index 89afcab..6447e0a 100644
--- a/arch/arm/mach-shmobile/intc-sh7372.c
+++ b/arch/arm/mach-shmobile/intc-sh7372.c
@@ -23,6 +23,7 @@
 #include <linux/io.h>
 #include <linux/sh_intc.h>
 #include <mach/intc.h>
+#include <mach/irqs.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
diff --git a/arch/arm/mach-shmobile/intc-sh7377.c b/arch/arm/mach-shmobile/intc-sh7377.c
index 2af4e6e..b84a460 100644
--- a/arch/arm/mach-shmobile/intc-sh7377.c
+++ b/arch/arm/mach-shmobile/intc-sh7377.c
@@ -23,6 +23,7 @@
 #include <linux/io.h>
 #include <linux/sh_intc.h>
 #include <mach/intc.h>
+#include <mach/irqs.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c
index 9857595..ee44740 100644
--- a/arch/arm/mach-shmobile/intc-sh73a0.c
+++ b/arch/arm/mach-shmobile/intc-sh73a0.c
@@ -24,6 +24,7 @@
 #include <linux/io.h>
 #include <linux/sh_intc.h>
 #include <mach/intc.h>
+#include <mach/irqs.h>
 #include <mach/sh73a0.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach-types.h>
@@ -420,8 +421,8 @@
 
 void __init sh73a0_init_irq(void)
 {
-	void __iomem *gic_dist_base = __io(0xf0001000);
-	void __iomem *gic_cpu_base = __io(0xf0000100);
+	void __iomem *gic_dist_base = IOMEM(0xf0001000);
+	void __iomem *gic_cpu_base = IOMEM(0xf0000100);
 	void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE);
 	int k, n;
 
diff --git a/arch/arm/mach-shmobile/localtimer.c b/arch/arm/mach-shmobile/localtimer.c
deleted file mode 100644
index ad9ccc9..0000000
--- a/arch/arm/mach-shmobile/localtimer.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SMP support for R-Mobile / SH-Mobile - local timer portion
- *
- * Copyright (C) 2010  Magnus Damm
- *
- * Based on vexpress, Copyright (C) 2002 ARM Ltd, 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/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	evt->irq = 29;
-	twd_timer_setup(evt);
-	return 0;
-}
diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c
index 9933812..45fa392 100644
--- a/arch/arm/mach-shmobile/platsmp.c
+++ b/arch/arm/mach-shmobile/platsmp.c
@@ -17,7 +17,6 @@
 #include <linux/smp.h>
 #include <linux/io.h>
 #include <asm/hardware/gic.h>
-#include <asm/localtimer.h>
 #include <asm/mach-types.h>
 #include <mach/common.h>
 
diff --git a/arch/arm/mach-shmobile/pm-r8a7779.c b/arch/arm/mach-shmobile/pm-r8a7779.c
index c38ba7b..a18a4ae 100644
--- a/arch/arm/mach-shmobile/pm-r8a7779.c
+++ b/arch/arm/mach-shmobile/pm-r8a7779.c
@@ -18,7 +18,6 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/console.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <mach/common.h>
 #include <mach/r8a7779.h>
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
index fcf8b17..a3bdb12 100644
--- a/arch/arm/mach-shmobile/pm-sh7372.c
+++ b/arch/arm/mach-shmobile/pm-sh7372.c
@@ -21,7 +21,6 @@
 #include <linux/irq.h>
 #include <linux/bitrev.h>
 #include <linux/console.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/tlbflush.h>
 #include <asm/suspend.h>
diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c
index 986dca6..14edb5c 100644
--- a/arch/arm/mach-shmobile/setup-r8a7740.c
+++ b/arch/arm/mach-shmobile/setup-r8a7740.c
@@ -25,8 +25,42 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
 #include <mach/r8a7740.h>
+#include <mach/common.h>
+#include <mach/irqs.h>
 #include <asm/mach-types.h>
+#include <asm/mach/map.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+static struct map_desc r8a7740_io_desc[] __initdata = {
+	 /*
+	  * for CPGA/INTC/PFC
+	  * 0xe6000000-0xefffffff -> 0xe6000000-0xefffffff
+	  */
+	{
+		.virtual	= 0xe6000000,
+		.pfn		= __phys_to_pfn(0xe6000000),
+		.length		= 160 << 20,
+		.type		= MT_DEVICE_NONSHARED
+	},
+#ifdef CONFIG_CACHE_L2X0
+	/*
+	 * for l2x0_init()
+	 * 0xf0100000-0xf0101000 -> 0xf0002000-0xf0003000
+	 */
+	{
+		.virtual	= 0xf0002000,
+		.pfn		= __phys_to_pfn(0xf0100000),
+		.length		= PAGE_SIZE,
+		.type		= MT_DEVICE_NONSHARED
+	},
+#endif
+};
+
+void __init r8a7740_map_io(void)
+{
+	iotable_init(r8a7740_io_desc, ARRAY_SIZE(r8a7740_io_desc));
+}
 
 /* SCIFA0 */
 static struct plat_sci_port scif0_platform_data = {
@@ -345,8 +379,20 @@
 			     ARRAY_SIZE(r8a7740_late_devices));
 }
 
+static void __init r8a7740_earlytimer_init(void)
+{
+	r8a7740_clock_init(0);
+	shmobile_earlytimer_init();
+}
+
 void __init r8a7740_add_early_devices(void)
 {
 	early_platform_add_devices(r8a7740_early_devices,
 				   ARRAY_SIZE(r8a7740_early_devices));
+
+	/* setup early console here as well */
+	shmobile_setup_console();
+
+	/* override timer setup with soc-specific code */
+	shmobile_timer.init = r8a7740_earlytimer_init;
 }
diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c
index 4725663..12c6f52 100644
--- a/arch/arm/mach-shmobile/setup-r8a7779.c
+++ b/arch/arm/mach-shmobile/setup-r8a7779.c
@@ -29,10 +29,36 @@
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 #include <mach/r8a7779.h>
 #include <mach/common.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/cache-l2x0.h>
+
+static struct map_desc r8a7779_io_desc[] __initdata = {
+	/* 2M entity map for 0xf0000000 (MPCORE) */
+	{
+		.virtual	= 0xf0000000,
+		.pfn		= __phys_to_pfn(0xf0000000),
+		.length		= SZ_2M,
+		.type		= MT_DEVICE_NONSHARED
+	},
+	/* 16M entity map for 0xfexxxxxx (DMAC-S/HPBREG/INTC2/LRAM/DBSC) */
+	{
+		.virtual	= 0xfe000000,
+		.pfn		= __phys_to_pfn(0xfe000000),
+		.length		= SZ_16M,
+		.type		= MT_DEVICE_NONSHARED
+	},
+};
+
+void __init r8a7779_map_io(void)
+{
+	iotable_init(r8a7779_io_desc, ARRAY_SIZE(r8a7779_io_desc));
+}
 
 static struct plat_sci_port scif0_platform_data = {
 	.mapbase	= 0xffe40000,
@@ -219,6 +245,10 @@
 
 void __init r8a7779_add_standard_devices(void)
 {
+#ifdef CONFIG_CACHE_L2X0
+	/* Early BRESP enable, Shared attribute override enable, 64K*16way */
+	l2x0_init((void __iomem __force *)(0xf0100000), 0x40470000, 0x82000fff);
+#endif
 	r8a7779_pm_init();
 
 	r8a7779_init_pm_domain(&r8a7779_sh4a);
@@ -232,8 +262,33 @@
 			    ARRAY_SIZE(r8a7779_late_devices));
 }
 
+static void __init r8a7779_earlytimer_init(void)
+{
+	r8a7779_clock_init();
+	shmobile_earlytimer_init();
+}
+
 void __init r8a7779_add_early_devices(void)
 {
 	early_platform_add_devices(r8a7779_early_devices,
 				   ARRAY_SIZE(r8a7779_early_devices));
+
+	/* Early serial console setup is not included here due to
+	 * memory map collisions. The SCIF serial ports in r8a7779
+	 * are difficult to entity map 1:1 due to collision with the
+	 * virtual memory range used by the coherent DMA code on ARM.
+	 *
+	 * Anyone wanting to debug early can remove UPF_IOREMAP from
+	 * the sh-sci serial console platform data, adjust mapbase
+	 * to a static M:N virt:phys mapping that needs to be added to
+	 * the mappings passed with iotable_init() above.
+	 *
+	 * Then add a call to shmobile_setup_console() from this function.
+	 *
+	 * As a final step pass earlyprint=sh-sci.2,115200 on the kernel
+	 * command line in case of the marzen board.
+	 */
+
+	/* override timer setup with soc-specific code */
+	shmobile_timer.init = r8a7779_earlytimer_init;
 }
diff --git a/arch/arm/mach-shmobile/setup-sh7367.c b/arch/arm/mach-shmobile/setup-sh7367.c
index e546017..2e3074a 100644
--- a/arch/arm/mach-shmobile/setup-sh7367.c
+++ b/arch/arm/mach-shmobile/setup-sh7367.c
@@ -29,8 +29,29 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
 #include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/irqs.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+static struct map_desc sh7367_io_desc[] __initdata = {
+	/* create a 1:1 entity map for 0xe6xxxxxx
+	 * used by CPGA, INTC and PFC.
+	 */
+	{
+		.virtual	= 0xe6000000,
+		.pfn		= __phys_to_pfn(0xe6000000),
+		.length		= 256 << 20,
+		.type		= MT_DEVICE_NONSHARED
+	},
+};
+
+void __init sh7367_map_io(void)
+{
+	iotable_init(sh7367_io_desc, ARRAY_SIZE(sh7367_io_desc));
+}
 
 /* SCIFA0 */
 static struct plat_sci_port scif0_platform_data = {
@@ -435,6 +456,12 @@
 			    ARRAY_SIZE(sh7367_devices));
 }
 
+static void __init sh7367_earlytimer_init(void)
+{
+	sh7367_clock_init();
+	shmobile_earlytimer_init();
+}
+
 #define SYMSTPCR2 0xe6158048
 #define SYMSTPCR2_CMT1 (1 << 29)
 
@@ -445,4 +472,10 @@
 
 	early_platform_add_devices(sh7367_early_devices,
 				   ARRAY_SIZE(sh7367_early_devices));
+
+	/* setup early console here as well */
+	shmobile_setup_console();
+
+	/* override timer setup with soc-specific code */
+	shmobile_timer.init = sh7367_earlytimer_init;
 }
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c
index cccf91b..2fe8f83 100644
--- a/arch/arm/mach-shmobile/setup-sh7372.c
+++ b/arch/arm/mach-shmobile/setup-sh7372.c
@@ -31,10 +31,38 @@
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
 #include <linux/pm_domain.h>
+#include <linux/dma-mapping.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 #include <mach/sh7372.h>
+#include <mach/common.h>
+#include <asm/mach/map.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+static struct map_desc sh7372_io_desc[] __initdata = {
+	/* create a 1:1 entity map for 0xe6xxxxxx
+	 * used by CPGA, INTC and PFC.
+	 */
+	{
+		.virtual	= 0xe6000000,
+		.pfn		= __phys_to_pfn(0xe6000000),
+		.length		= 256 << 20,
+		.type		= MT_DEVICE_NONSHARED
+	},
+};
+
+void __init sh7372_map_io(void)
+{
+	iotable_init(sh7372_io_desc, ARRAY_SIZE(sh7372_io_desc));
+
+	/*
+	 * DMA memory at 0xff200000 - 0xffdfffff. The default 2MB size isn't
+	 * enough to allocate the frame buffer memory.
+	 */
+	init_consistent_dma_size(12 << 20);
+}
 
 /* SCIFA0 */
 static struct plat_sci_port scif0_platform_data = {
@@ -1047,8 +1075,20 @@
 	sh7372_add_device_to_domain(&sh7372_a4r, &tmu01_device);
 }
 
+static void __init sh7372_earlytimer_init(void)
+{
+	sh7372_clock_init();
+	shmobile_earlytimer_init();
+}
+
 void __init sh7372_add_early_devices(void)
 {
 	early_platform_add_devices(sh7372_early_devices,
 				   ARRAY_SIZE(sh7372_early_devices));
+
+	/* setup early console here as well */
+	shmobile_setup_console();
+
+	/* override timer setup with soc-specific code */
+	shmobile_timer.init = sh7372_earlytimer_init;
 }
diff --git a/arch/arm/mach-shmobile/setup-sh7377.c b/arch/arm/mach-shmobile/setup-sh7377.c
index bb405b8..d576a6a 100644
--- a/arch/arm/mach-shmobile/setup-sh7377.c
+++ b/arch/arm/mach-shmobile/setup-sh7377.c
@@ -30,8 +30,29 @@
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
 #include <mach/hardware.h>
+#include <mach/common.h>
+#include <asm/mach/map.h>
+#include <mach/irqs.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+static struct map_desc sh7377_io_desc[] __initdata = {
+	/* create a 1:1 entity map for 0xe6xxxxxx
+	 * used by CPGA, INTC and PFC.
+	 */
+	{
+		.virtual	= 0xe6000000,
+		.pfn		= __phys_to_pfn(0xe6000000),
+		.length		= 256 << 20,
+		.type		= MT_DEVICE_NONSHARED
+	},
+};
+
+void __init sh7377_map_io(void)
+{
+	iotable_init(sh7377_io_desc, ARRAY_SIZE(sh7377_io_desc));
+}
 
 /* SCIFA0 */
 static struct plat_sci_port scif0_platform_data = {
@@ -456,6 +477,12 @@
 			    ARRAY_SIZE(sh7377_devices));
 }
 
+static void __init sh7377_earlytimer_init(void)
+{
+	sh7377_clock_init();
+	shmobile_earlytimer_init();
+}
+
 #define SMSTPCR3 0xe615013c
 #define SMSTPCR3_CMT1 (1 << 29)
 
@@ -466,4 +493,10 @@
 
 	early_platform_add_devices(sh7377_early_devices,
 				   ARRAY_SIZE(sh7377_early_devices));
+
+	/* setup early console here as well */
+	shmobile_setup_console();
+
+	/* override timer setup with soc-specific code */
+	shmobile_timer.init = sh7377_earlytimer_init;
 }
diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c
index 20e71e5..5bebffc 100644
--- a/arch/arm/mach-shmobile/setup-sh73a0.c
+++ b/arch/arm/mach-shmobile/setup-sh73a0.c
@@ -31,9 +31,30 @@
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 #include <mach/sh73a0.h>
+#include <mach/common.h>
 #include <asm/mach-types.h>
+#include <asm/mach/map.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+static struct map_desc sh73a0_io_desc[] __initdata = {
+	/* create a 1:1 entity map for 0xe6xxxxxx
+	 * used by CPGA, INTC and PFC.
+	 */
+	{
+		.virtual	= 0xe6000000,
+		.pfn		= __phys_to_pfn(0xe6000000),
+		.length		= 256 << 20,
+		.type		= MT_DEVICE_NONSHARED
+	},
+};
+
+void __init sh73a0_map_io(void)
+{
+	iotable_init(sh73a0_io_desc, ARRAY_SIZE(sh73a0_io_desc));
+}
 
 static struct plat_sci_port scif0_platform_data = {
 	.mapbase	= 0xe6c40000,
@@ -667,8 +688,20 @@
 			    ARRAY_SIZE(sh73a0_late_devices));
 }
 
+static void __init sh73a0_earlytimer_init(void)
+{
+	sh73a0_clock_init();
+	shmobile_earlytimer_init();
+}
+
 void __init sh73a0_add_early_devices(void)
 {
 	early_platform_add_devices(sh73a0_early_devices,
 				   ARRAY_SIZE(sh73a0_early_devices));
+
+	/* setup early console here as well */
+	shmobile_setup_console();
+
+	/* override timer setup with soc-specific code */
+	shmobile_timer.init = sh73a0_earlytimer_init;
 }
diff --git a/arch/arm/mach-shmobile/smp-r8a7779.c b/arch/arm/mach-shmobile/smp-r8a7779.c
index 4fe2e9e..b62e19d 100644
--- a/arch/arm/mach-shmobile/smp-r8a7779.c
+++ b/arch/arm/mach-shmobile/smp-r8a7779.c
@@ -30,7 +30,7 @@
 #include <asm/smp_twd.h>
 #include <asm/hardware/gic.h>
 
-#define AVECR 0xfe700040
+#define AVECR IOMEM(0xfe700040)
 
 static struct r8a7779_pm_ch r8a7779_ch_cpu1 = {
 	.chan_offs = 0x40, /* PWRSR0 .. PWRER0 */
@@ -64,6 +64,8 @@
 static DEFINE_SPINLOCK(scu_lock);
 static unsigned long tmp;
 
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, 0xf0000600, 29);
+
 static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
 {
 	void __iomem *scu_base = scu_base_addr();
@@ -82,11 +84,7 @@
 {
 	void __iomem *scu_base = scu_base_addr();
 
-#ifdef CONFIG_HAVE_ARM_TWD
-	/* twd_base needs to be initialized before percpu_timer_setup() */
-	twd_base = (void __iomem *)0xf0000600;
-#endif
-
+	shmobile_twd_init(&twd_local_timer);
 	return scu_get_core_count(scu_base);
 }
 
@@ -140,7 +138,7 @@
 	scu_enable(scu_base_addr());
 
 	/* Map the reset vector (in headsmp.S) */
-	__raw_writel(__pa(shmobile_secondary_vector), __io(AVECR));
+	__raw_writel(__pa(shmobile_secondary_vector), AVECR);
 
 	/* enable cache coherency on CPU0 */
 	modify_scu_cpu_psr(0, 3 << (cpu * 8));
diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c
index 2d0d421..14ad8b05 100644
--- a/arch/arm/mach-shmobile/smp-sh73a0.c
+++ b/arch/arm/mach-shmobile/smp-sh73a0.c
@@ -28,11 +28,11 @@
 #include <asm/smp_twd.h>
 #include <asm/hardware/gic.h>
 
-#define WUPCR		0xe6151010
-#define SRESCR		0xe6151018
-#define PSTR		0xe6151040
-#define SBAR            0xe6180020
-#define APARMBAREA      0xe6f10020
+#define WUPCR		IOMEM(0xe6151010)
+#define SRESCR		IOMEM(0xe6151018)
+#define PSTR		IOMEM(0xe6151040)
+#define SBAR		IOMEM(0xe6180020)
+#define APARMBAREA	IOMEM(0xe6f10020)
 
 static void __iomem *scu_base_addr(void)
 {
@@ -42,6 +42,8 @@
 static DEFINE_SPINLOCK(scu_lock);
 static unsigned long tmp;
 
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, 0xf0000600, 29);
+
 static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
 {
 	void __iomem *scu_base = scu_base_addr();
@@ -60,11 +62,7 @@
 {
 	void __iomem *scu_base = scu_base_addr();
 
-#ifdef CONFIG_HAVE_ARM_TWD
-	/* twd_base needs to be initialized before percpu_timer_setup() */
-	twd_base = (void __iomem *)0xf0000600;
-#endif
-
+	shmobile_twd_init(&twd_local_timer);
 	return scu_get_core_count(scu_base);
 }
 
@@ -80,10 +78,10 @@
 	/* enable cache coherency */
 	modify_scu_cpu_psr(0, 3 << (cpu * 8));
 
-	if (((__raw_readl(__io(PSTR)) >> (4 * cpu)) & 3) == 3)
-		__raw_writel(1 << cpu, __io(WUPCR));	/* wake up */
+	if (((__raw_readl(PSTR) >> (4 * cpu)) & 3) == 3)
+		__raw_writel(1 << cpu, WUPCR);	/* wake up */
 	else
-		__raw_writel(1 << cpu, __io(SRESCR));	/* reset */
+		__raw_writel(1 << cpu, SRESCR);	/* reset */
 
 	return 0;
 }
@@ -95,8 +93,8 @@
 	scu_enable(scu_base_addr());
 
 	/* Map the reset vector (in headsmp.S) */
-	__raw_writel(0, __io(APARMBAREA));      /* 4k */
-	__raw_writel(__pa(shmobile_secondary_vector), __io(SBAR));
+	__raw_writel(0, APARMBAREA);      /* 4k */
+	__raw_writel(__pa(shmobile_secondary_vector), SBAR);
 
 	/* enable cache coherency on CPU0 */
 	modify_scu_cpu_psr(0, 3 << (cpu * 8));
diff --git a/arch/arm/mach-shmobile/suspend.c b/arch/arm/mach-shmobile/suspend.c
index c1febe1..4d1b86a 100644
--- a/arch/arm/mach-shmobile/suspend.c
+++ b/arch/arm/mach-shmobile/suspend.c
@@ -12,8 +12,8 @@
 #include <linux/suspend.h>
 #include <linux/module.h>
 #include <linux/err.h>
-#include <asm/system.h>
 #include <asm/io.h>
+#include <asm/system_misc.h>
 
 static int shmobile_suspend_default_enter(suspend_state_t suspend_state)
 {
diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c
index 895794b..2fba5f3 100644
--- a/arch/arm/mach-shmobile/timer.c
+++ b/arch/arm/mach-shmobile/timer.c
@@ -20,6 +20,7 @@
  */
 #include <linux/platform_device.h>
 #include <asm/mach/time.h>
+#include <asm/smp_twd.h>
 
 static void __init shmobile_late_time_init(void)
 {
@@ -36,11 +37,24 @@
 	early_platform_driver_probe("earlytimer", 2, 0);
 }
 
-static void __init shmobile_timer_init(void)
+void __init shmobile_earlytimer_init(void)
 {
 	late_time_init = shmobile_late_time_init;
 }
 
+static void __init shmobile_timer_init(void)
+{
+}
+
+void __init shmobile_twd_init(struct twd_local_timer *twd_local_timer)
+{
+#ifdef CONFIG_HAVE_ARM_TWD
+	int err = twd_local_timer_register(twd_local_timer);
+	if (err)
+		pr_err("twd_local_timer_register failed %d\n", err);
+#endif
+}
+
 struct sys_timer shmobile_timer = {
 	.init		= shmobile_timer_init,
 };
diff --git a/arch/arm/mach-spear3xx/clock.c b/arch/arm/mach-spear3xx/clock.c
index f67860c..6c4841f 100644
--- a/arch/arm/mach-spear3xx/clock.c
+++ b/arch/arm/mach-spear3xx/clock.c
@@ -12,6 +12,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <asm/mach-types.h>
 #include <plat/clock.h>
diff --git a/arch/arm/mach-spear3xx/include/mach/entry-macro.S b/arch/arm/mach-spear3xx/include/mach/entry-macro.S
deleted file mode 100644
index de3bb41..0000000
--- a/arch/arm/mach-spear3xx/include/mach/entry-macro.S
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for SPEAr3xx machine family
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.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.
- */
-
-		.macro	disable_fiq
-		.endm
-
-		.macro	arch_ret_to_user, tmp1, tmp2
-		.endm
diff --git a/arch/arm/mach-spear3xx/include/mach/io.h b/arch/arm/mach-spear3xx/include/mach/io.h
deleted file mode 100644
index 30cff8a..0000000
--- a/arch/arm/mach-spear3xx/include/mach/io.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/include/mach/io.h
- *
- * IO definitions for SPEAr3xx machine family
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.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.
- */
-
-#ifndef __MACH_IO_H
-#define __MACH_IO_H
-
-#include <plat/io.h>
-
-#endif /* __MACH_IO_H */
diff --git a/arch/arm/mach-spear3xx/include/mach/system.h b/arch/arm/mach-spear3xx/include/mach/system.h
deleted file mode 100644
index 92cee633..0000000
--- a/arch/arm/mach-spear3xx/include/mach/system.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/include/mach/system.h
- *
- * SPEAr3xx Machine family specific architecture functions
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.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.
- */
-
-#ifndef __MACH_SYSTEM_H
-#define __MACH_SYSTEM_H
-
-#include <plat/system.h>
-
-#endif /* __MACH_SYSTEM_H */
diff --git a/arch/arm/mach-spear3xx/spear300.c b/arch/arm/mach-spear3xx/spear300.c
index 4f7f518..f7db668 100644
--- a/arch/arm/mach-spear3xx/spear300.c
+++ b/arch/arm/mach-spear3xx/spear300.c
@@ -430,18 +430,8 @@
 	.irq_base	= SPEAR300_GPIO1_INT_BASE,
 };
 
-struct amba_device spear300_gpio1_device = {
-	.dev = {
-		.init_name = "gpio1",
-		.platform_data = &gpio1_plat_data,
-	},
-	.res = {
-		.start = SPEAR300_GPIO_BASE,
-		.end = SPEAR300_GPIO_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	.irq = {SPEAR300_VIRQ_GPIO1, NO_IRQ},
-};
+AMBA_APB_DEVICE(spear300_gpio1, "gpio1", 0, SPEAR300_GPIO_BASE,
+	{SPEAR300_VIRQ_GPIO1}, &gpio1_plat_data);
 
 /* spear300 routines */
 void __init spear300_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
diff --git a/arch/arm/mach-spear3xx/spear3xx.c b/arch/arm/mach-spear3xx/spear3xx.c
index 10af45d..b1733c3 100644
--- a/arch/arm/mach-spear3xx/spear3xx.c
+++ b/arch/arm/mach-spear3xx/spear3xx.c
@@ -28,31 +28,12 @@
 	.irq_base	= SPEAR3XX_GPIO_INT_BASE,
 };
 
-struct amba_device spear3xx_gpio_device = {
-	.dev = {
-		.init_name = "gpio",
-		.platform_data = &gpio_plat_data,
-	},
-	.res = {
-		.start = SPEAR3XX_ICM3_GPIO_BASE,
-		.end = SPEAR3XX_ICM3_GPIO_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	.irq = {SPEAR3XX_IRQ_BASIC_GPIO, NO_IRQ},
-};
+AMBA_APB_DEVICE(spear3xx_gpio, "gpio", 0, SPEAR3XX_ICM3_GPIO_BASE,
+	{SPEAR3XX_IRQ_BASIC_GPIO}, &gpio_plat_data);
 
 /* uart device registration */
-struct amba_device spear3xx_uart_device = {
-	.dev = {
-		.init_name = "uart",
-	},
-	.res = {
-		.start = SPEAR3XX_ICM1_UART_BASE,
-		.end = SPEAR3XX_ICM1_UART_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	.irq = {SPEAR3XX_IRQ_UART, NO_IRQ},
-};
+AMBA_APB_DEVICE(spear3xx_uart, "uart", 0, SPEAR3XX_ICM1_UART_BASE,
+	{SPEAR3XX_IRQ_UART}, NULL);
 
 /* Do spear3xx familiy common initialization part here */
 void __init spear3xx_init(void)
diff --git a/arch/arm/mach-spear6xx/Kconfig b/arch/arm/mach-spear6xx/Kconfig
index ff4ae5b..fbe298b 100644
--- a/arch/arm/mach-spear6xx/Kconfig
+++ b/arch/arm/mach-spear6xx/Kconfig
@@ -5,11 +5,12 @@
 if ARCH_SPEAR6XX
 
 menu "SPEAr6xx Implementations"
-config BOARD_SPEAR600_EVB
-	bool "SPEAr600 Evaluation Board"
+config BOARD_SPEAR600_DT
+	bool "SPEAr600 generic board configured via device-tree"
 	select MACH_SPEAR600
+	select USE_OF
 	help
-	  Supports ST SPEAr600 Evaluation Board
+	  Supports ST SPEAr600 boards configured via the device-tree
 
 endmenu
 
diff --git a/arch/arm/mach-spear6xx/Makefile b/arch/arm/mach-spear6xx/Makefile
index cc1a4d8..76e5750 100644
--- a/arch/arm/mach-spear6xx/Makefile
+++ b/arch/arm/mach-spear6xx/Makefile
@@ -4,9 +4,3 @@
 
 # common files
 obj-y	+= clock.o spear6xx.o
-
-# spear600 specific files
-obj-$(CONFIG_MACH_SPEAR600) += spear600.o
-
-# spear600 boards files
-obj-$(CONFIG_BOARD_SPEAR600_EVB) += spear600_evb.o
diff --git a/arch/arm/mach-spear6xx/clock.c b/arch/arm/mach-spear6xx/clock.c
index ac70e0d..a86499a 100644
--- a/arch/arm/mach-spear6xx/clock.c
+++ b/arch/arm/mach-spear6xx/clock.c
@@ -12,6 +12,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <plat/clock.h>
 #include <mach/misc_regs.h>
@@ -641,8 +642,8 @@
 	{ .con_id = "gpt0_synth_clk",	.clk = &gpt0_synth_clk},
 	{ .con_id = "gpt2_synth_clk",	.clk = &gpt2_synth_clk},
 	{ .con_id = "gpt3_synth_clk",	.clk = &gpt3_synth_clk},
-	{ .dev_id = "uart0",		.clk = &uart0_clk},
-	{ .dev_id = "uart1",		.clk = &uart1_clk},
+	{ .dev_id = "d0000000.serial",	.clk = &uart0_clk},
+	{ .dev_id = "d0080000.serial",	.clk = &uart1_clk},
 	{ .dev_id = "firda",		.clk = &firda_clk},
 	{ .dev_id = "clcd",		.clk = &clcd_clk},
 	{ .dev_id = "gpt0",		.clk = &gpt0_clk},
@@ -655,20 +656,20 @@
 	{ .con_id = "usbh.1_clk",	.clk = &usbh1_clk},
 	/* clock derived from ahb clk */
 	{ .con_id = "apb_clk",		.clk = &apb_clk},
-	{ .dev_id = "i2c_designware.0",	.clk = &i2c_clk},
+	{ .dev_id = "d0200000.i2c",	.clk = &i2c_clk},
 	{ .dev_id = "dma",		.clk = &dma_clk},
 	{ .dev_id = "jpeg",		.clk = &jpeg_clk},
 	{ .dev_id = "gmac",		.clk = &gmac_clk},
 	{ .dev_id = "smi",		.clk = &smi_clk},
-	{ .con_id = "fsmc",		.clk = &fsmc_clk},
+	{ .dev_id = "fsmc-nand",	.clk = &fsmc_clk},
 	/* clock derived from apb clk */
 	{ .dev_id = "adc",		.clk = &adc_clk},
 	{ .dev_id = "ssp-pl022.0",	.clk = &ssp0_clk},
 	{ .dev_id = "ssp-pl022.1",	.clk = &ssp1_clk},
 	{ .dev_id = "ssp-pl022.2",	.clk = &ssp2_clk},
-	{ .dev_id = "gpio0",		.clk = &gpio0_clk},
-	{ .dev_id = "gpio1",		.clk = &gpio1_clk},
-	{ .dev_id = "gpio2",		.clk = &gpio2_clk},
+	{ .dev_id = "f0100000.gpio",	.clk = &gpio0_clk},
+	{ .dev_id = "fc980000.gpio",	.clk = &gpio1_clk},
+	{ .dev_id = "d8100000.gpio",	.clk = &gpio2_clk},
 };
 
 void __init spear6xx_clk_init(void)
diff --git a/arch/arm/mach-spear6xx/include/mach/entry-macro.S b/arch/arm/mach-spear6xx/include/mach/entry-macro.S
deleted file mode 100644
index d490a91..0000000
--- a/arch/arm/mach-spear6xx/include/mach/entry-macro.S
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * arch/arm/mach-spear6xx/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for SPEAr6xx machine family
- *
- * Copyright (C) 2009 ST Microelectronics
- * Rajeev Kumar<rajeev-dlh.kumar@st.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.
- */
-
-		.macro	disable_fiq
-		.endm
-
-		.macro	arch_ret_to_user, tmp1, tmp2
-		.endm
diff --git a/arch/arm/mach-spear6xx/include/mach/io.h b/arch/arm/mach-spear6xx/include/mach/io.h
deleted file mode 100644
index fb7c106..0000000
--- a/arch/arm/mach-spear6xx/include/mach/io.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * arch/arm/mach-spear6xx/include/mach/io.h
- *
- * IO definitions for SPEAr6xx machine family
- *
- * Copyright (C) 2009 ST Microelectronics
- * Rajeev Kumar Kumar<rajeev-dlh.kumar@st.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.
- */
-
-#ifndef __MACH_IO_H
-#define __MACH_IO_H
-
-#include <plat/io.h>
-
-#endif	/* __MACH_IO_H */
-
diff --git a/arch/arm/mach-spear6xx/include/mach/system.h b/arch/arm/mach-spear6xx/include/mach/system.h
deleted file mode 100644
index 0b1d2be..0000000
--- a/arch/arm/mach-spear6xx/include/mach/system.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-spear6xx/include/mach/system.h
- *
- * SPEAr6xx Machine family specific architecture functions
- *
- * Copyright (C) 2009 ST Microelectronics
- * Rajeev Kumar<rajeev-dlh.kumar@st.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.
- */
-
-#ifndef __MACH_SYSTEM_H
-#define __MACH_SYSTEM_H
-
-#include <plat/system.h>
-
-#endif	/* __MACH_SYSTEM_H */
diff --git a/arch/arm/mach-spear6xx/spear600.c b/arch/arm/mach-spear6xx/spear600.c
deleted file mode 100644
index d0e6eea..0000000
--- a/arch/arm/mach-spear6xx/spear600.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * arch/arm/mach-spear6xx/spear600.c
- *
- * SPEAr600 machine source file
- *
- * Copyright (C) 2009 ST Microelectronics
- * Rajeev Kumar<rajeev-dlh.kumar@st.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/ptrace.h>
-#include <asm/irq.h>
-#include <mach/generic.h>
-#include <mach/hardware.h>
-
-/* Add spear600 specific devices here */
-
-void __init spear600_init(void)
-{
-	/* call spear6xx family common init function */
-	spear6xx_init();
-}
diff --git a/arch/arm/mach-spear6xx/spear600_evb.c b/arch/arm/mach-spear6xx/spear600_evb.c
deleted file mode 100644
index c6e4254..0000000
--- a/arch/arm/mach-spear6xx/spear600_evb.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * arch/arm/mach-spear6xx/spear600_evb.c
- *
- * SPEAr600 evaluation board source file
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.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 <asm/hardware/vic.h>
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-#include <mach/generic.h>
-#include <mach/hardware.h>
-
-static struct amba_device *amba_devs[] __initdata = {
-	&gpio_device[0],
-	&gpio_device[1],
-	&gpio_device[2],
-	&uart_device[0],
-	&uart_device[1],
-};
-
-static struct platform_device *plat_devs[] __initdata = {
-};
-
-static void __init spear600_evb_init(void)
-{
-	unsigned int i;
-
-	/* call spear600 machine init function */
-	spear600_init();
-
-	/* Add Platform Devices */
-	platform_add_devices(plat_devs, ARRAY_SIZE(plat_devs));
-
-	/* Add Amba Devices */
-	for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
-		amba_device_register(amba_devs[i], &iomem_resource);
-}
-
-MACHINE_START(SPEAR600, "ST-SPEAR600-EVB")
-	.atag_offset	=	0x100,
-	.map_io		=	spear6xx_map_io,
-	.init_irq	=	spear6xx_init_irq,
-	.handle_irq	=	vic_handle_irq,
-	.timer		=	&spear6xx_timer,
-	.init_machine	=	spear600_evb_init,
-	.restart	=	spear_restart,
-MACHINE_END
diff --git a/arch/arm/mach-spear6xx/spear6xx.c b/arch/arm/mach-spear6xx/spear6xx.c
index e0f6628..2ed8b14 100644
--- a/arch/arm/mach-spear6xx/spear6xx.c
+++ b/arch/arm/mach-spear6xx/spear6xx.c
@@ -6,111 +6,21 @@
  * Copyright (C) 2009 ST Microelectronics
  * Rajeev Kumar<rajeev-dlh.kumar@st.com>
  *
+ * Copyright 2012 Stefan Roese <sr@denx.de>
+ *
  * 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/types.h>
-#include <linux/amba/pl061.h>
-#include <linux/ptrace.h>
-#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
 #include <asm/hardware/vic.h>
-#include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <mach/generic.h>
 #include <mach/hardware.h>
-#include <mach/irqs.h>
-
-/* Add spear6xx machines common devices here */
-/* uart device registration */
-struct amba_device uart_device[] = {
-	{
-		.dev = {
-			.init_name = "uart0",
-		},
-		.res = {
-			.start = SPEAR6XX_ICM1_UART0_BASE,
-			.end = SPEAR6XX_ICM1_UART0_BASE + SZ_4K - 1,
-			.flags = IORESOURCE_MEM,
-		},
-		.irq = {IRQ_UART_0, NO_IRQ},
-	}, {
-		.dev = {
-			.init_name = "uart1",
-		},
-		.res = {
-			.start = SPEAR6XX_ICM1_UART1_BASE,
-			.end = SPEAR6XX_ICM1_UART1_BASE + SZ_4K - 1,
-			.flags = IORESOURCE_MEM,
-		},
-		.irq = {IRQ_UART_1, NO_IRQ},
-	}
-};
-
-/* gpio device registration */
-static struct pl061_platform_data gpio_plat_data[] = {
-	{
-		.gpio_base	= 0,
-		.irq_base	= SPEAR_GPIO0_INT_BASE,
-	}, {
-		.gpio_base	= 8,
-		.irq_base	= SPEAR_GPIO1_INT_BASE,
-	}, {
-		.gpio_base	= 16,
-		.irq_base	= SPEAR_GPIO2_INT_BASE,
-	},
-};
-
-struct amba_device gpio_device[] = {
-	{
-		.dev = {
-			.init_name = "gpio0",
-			.platform_data = &gpio_plat_data[0],
-		},
-		.res = {
-			.start = SPEAR6XX_CPU_GPIO_BASE,
-			.end = SPEAR6XX_CPU_GPIO_BASE + SZ_4K - 1,
-			.flags = IORESOURCE_MEM,
-		},
-		.irq = {IRQ_LOCAL_GPIO, NO_IRQ},
-	}, {
-		.dev = {
-			.init_name = "gpio1",
-			.platform_data = &gpio_plat_data[1],
-		},
-		.res = {
-			.start = SPEAR6XX_ICM3_GPIO_BASE,
-			.end = SPEAR6XX_ICM3_GPIO_BASE + SZ_4K - 1,
-			.flags = IORESOURCE_MEM,
-		},
-		.irq = {IRQ_BASIC_GPIO, NO_IRQ},
-	}, {
-		.dev = {
-			.init_name = "gpio2",
-			.platform_data = &gpio_plat_data[2],
-		},
-		.res = {
-			.start = SPEAR6XX_ICM2_GPIO_BASE,
-			.end = SPEAR6XX_ICM2_GPIO_BASE + SZ_4K - 1,
-			.flags = IORESOURCE_MEM,
-		},
-		.irq = {IRQ_APPL_GPIO, NO_IRQ},
-	}
-};
-
-/* This will add devices, and do machine specific tasks */
-void __init spear6xx_init(void)
-{
-	/* nothing to do for now */
-}
-
-/* This will initialize vic */
-void __init spear6xx_init_irq(void)
-{
-	vic_init((void __iomem *)VA_SPEAR6XX_CPU_VIC_PRI_BASE, 0, ~0, 0);
-	vic_init((void __iomem *)VA_SPEAR6XX_CPU_VIC_SEC_BASE, 32, ~0, 0);
-}
 
 /* Following will create static virtual/physical mappings */
 static struct map_desc spear6xx_io_desc[] __initdata = {
@@ -181,3 +91,33 @@
 struct sys_timer spear6xx_timer = {
 	.init = spear6xx_timer_init,
 };
+
+static void __init spear600_dt_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *spear600_dt_board_compat[] = {
+	"st,spear600",
+	NULL
+};
+
+static const struct of_device_id vic_of_match[] __initconst = {
+	{ .compatible = "arm,pl190-vic", .data = vic_of_init, },
+	{ /* Sentinel */ }
+};
+
+static void __init spear6xx_dt_init_irq(void)
+{
+	of_irq_init(vic_of_match);
+}
+
+DT_MACHINE_START(SPEAR600_DT, "ST SPEAr600 (Flattened Device Tree)")
+	.map_io		=	spear6xx_map_io,
+	.init_irq	=	spear6xx_dt_init_irq,
+	.handle_irq	=	vic_handle_irq,
+	.timer		=	&spear6xx_timer,
+	.init_machine	=	spear600_dt_init,
+	.restart	=	spear_restart,
+	.dt_compat	=	spear600_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 373652d..d0f2546 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -7,9 +7,19 @@
 	select CPU_V7
 	select ARM_GIC
 	select ARCH_REQUIRE_GPIOLIB
+	select PINCTRL
+	select PINCTRL_TEGRA20
 	select USB_ARCH_HAS_EHCI if USB_SUPPORT
-	select USB_ULPI if USB_SUPPORT
+	select USB_ULPI if USB
 	select USB_ULPI_VIEWPORT if USB_SUPPORT
+	select ARM_ERRATA_720789
+	select ARM_ERRATA_742230
+	select ARM_ERRATA_751472
+	select ARM_ERRATA_754327
+	select ARM_ERRATA_764369
+	select PL310_ERRATA_727915 if CACHE_L2X0
+	select PL310_ERRATA_769419 if CACHE_L2X0
+	select CPU_FREQ_TABLE if CPU_FREQ
 	help
 	  Support for NVIDIA Tegra AP20 and T20 processors, based on the
 	  ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
@@ -19,10 +29,18 @@
 	select CPU_V7
 	select ARM_GIC
 	select ARCH_REQUIRE_GPIOLIB
+	select PINCTRL
+	select PINCTRL_TEGRA30
 	select USB_ARCH_HAS_EHCI if USB_SUPPORT
-	select USB_ULPI if USB_SUPPORT
+	select USB_ULPI if USB
 	select USB_ULPI_VIEWPORT if USB_SUPPORT
 	select USE_OF
+	select ARM_ERRATA_743622
+	select ARM_ERRATA_751472
+	select ARM_ERRATA_754322
+	select ARM_ERRATA_764369
+	select PL310_ERRATA_769419 if CACHE_L2X0
+	select CPU_FREQ_TABLE if CPU_FREQ
 	help
 	  Support for NVIDIA Tegra T30 processor family, based on the
 	  ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index e120ff5..d87d968 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -7,15 +7,21 @@
 obj-y                                   += timer.o
 obj-y                                   += pinmux.o
 obj-y					+= fuse.o
+obj-y					+= pmc.o
+obj-y					+= flowctrl.o
+obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
+obj-$(CONFIG_CPU_IDLE)			+= sleep.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= powergate.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra2_clocks.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= tegra2_emc.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= pinmux-tegra20-tables.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= pinmux-tegra30-tables.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= board-dt-tegra30.o
-obj-$(CONFIG_SMP)                       += platsmp.o localtimer.o headsmp.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks.o
+obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o
+obj-$(CONFIG_SMP)                       += reset.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
-obj-$(CONFIG_TEGRA_SYSTEM_DMA)		+= dma.o
+obj-$(CONFIG_TEGRA_SYSTEM_DMA)		+= dma.o apbio.o
 obj-$(CONFIG_CPU_FREQ)                  += cpu-tegra.o
 obj-$(CONFIG_TEGRA_PCI)			+= pcie.o
 obj-$(CONFIG_USB_SUPPORT)		+= usb_phy.o
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
new file mode 100644
index 0000000..e75451e
--- /dev/null
+++ b/arch/arm/mach-tegra/apbio.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2010 NVIDIA Corporation.
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+
+#include <mach/dma.h>
+#include <mach/iomap.h>
+
+#include "apbio.h"
+
+static DEFINE_MUTEX(tegra_apb_dma_lock);
+
+static struct tegra_dma_channel *tegra_apb_dma;
+static u32 *tegra_apb_bb;
+static dma_addr_t tegra_apb_bb_phys;
+static DECLARE_COMPLETION(tegra_apb_wait);
+
+bool tegra_apb_init(void)
+{
+	struct tegra_dma_channel *ch;
+
+	mutex_lock(&tegra_apb_dma_lock);
+
+	/* Check to see if we raced to setup */
+	if (tegra_apb_dma)
+		goto out;
+
+	ch = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
+		TEGRA_DMA_SHARED);
+
+	if (!ch)
+		goto out_fail;
+
+	tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32),
+		&tegra_apb_bb_phys, GFP_KERNEL);
+	if (!tegra_apb_bb) {
+		pr_err("%s: can not allocate bounce buffer\n", __func__);
+		tegra_dma_free_channel(ch);
+		goto out_fail;
+	}
+
+	tegra_apb_dma = ch;
+out:
+	mutex_unlock(&tegra_apb_dma_lock);
+	return true;
+
+out_fail:
+	mutex_unlock(&tegra_apb_dma_lock);
+	return false;
+}
+
+static void apb_dma_complete(struct tegra_dma_req *req)
+{
+	complete(&tegra_apb_wait);
+}
+
+u32 tegra_apb_readl(unsigned long offset)
+{
+	struct tegra_dma_req req;
+	int ret;
+
+	if (!tegra_apb_dma && !tegra_apb_init())
+		return readl(IO_TO_VIRT(offset));
+
+	mutex_lock(&tegra_apb_dma_lock);
+	req.complete = apb_dma_complete;
+	req.to_memory = 1;
+	req.dest_addr = tegra_apb_bb_phys;
+	req.dest_bus_width = 32;
+	req.dest_wrap = 1;
+	req.source_addr = offset;
+	req.source_bus_width = 32;
+	req.source_wrap = 4;
+	req.req_sel = TEGRA_DMA_REQ_SEL_CNTR;
+	req.size = 4;
+
+	INIT_COMPLETION(tegra_apb_wait);
+
+	tegra_dma_enqueue_req(tegra_apb_dma, &req);
+
+	ret = wait_for_completion_timeout(&tegra_apb_wait,
+		msecs_to_jiffies(50));
+
+	if (WARN(ret == 0, "apb read dma timed out")) {
+		tegra_dma_dequeue_req(tegra_apb_dma, &req);
+		*(u32 *)tegra_apb_bb = 0;
+	}
+
+	mutex_unlock(&tegra_apb_dma_lock);
+	return *((u32 *)tegra_apb_bb);
+}
+
+void tegra_apb_writel(u32 value, unsigned long offset)
+{
+	struct tegra_dma_req req;
+	int ret;
+
+	if (!tegra_apb_dma && !tegra_apb_init()) {
+		writel(value, IO_TO_VIRT(offset));
+		return;
+	}
+
+	mutex_lock(&tegra_apb_dma_lock);
+	*((u32 *)tegra_apb_bb) = value;
+	req.complete = apb_dma_complete;
+	req.to_memory = 0;
+	req.dest_addr = offset;
+	req.dest_wrap = 4;
+	req.dest_bus_width = 32;
+	req.source_addr = tegra_apb_bb_phys;
+	req.source_bus_width = 32;
+	req.source_wrap = 1;
+	req.req_sel = TEGRA_DMA_REQ_SEL_CNTR;
+	req.size = 4;
+
+	INIT_COMPLETION(tegra_apb_wait);
+
+	tegra_dma_enqueue_req(tegra_apb_dma, &req);
+
+	ret = wait_for_completion_timeout(&tegra_apb_wait,
+		msecs_to_jiffies(50));
+
+	if (WARN(ret == 0, "apb write dma timed out"))
+		tegra_dma_dequeue_req(tegra_apb_dma, &req);
+
+	mutex_unlock(&tegra_apb_dma_lock);
+}
diff --git a/arch/arm/mach-tegra/apbio.h b/arch/arm/mach-tegra/apbio.h
new file mode 100644
index 0000000..8b49e8c
--- /dev/null
+++ b/arch/arm/mach-tegra/apbio.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2010 NVIDIA Corporation.
+ * 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 __MACH_TEGRA_APBIO_H
+#define __MACH_TEGRA_APBIO_H
+
+#ifdef CONFIG_TEGRA_SYSTEM_DMA
+
+u32 tegra_apb_readl(unsigned long offset);
+void tegra_apb_writel(u32 value, unsigned long offset);
+
+#else
+#include <asm/io.h>
+#include <mach/io.h>
+
+static inline u32 tegra_apb_readl(unsigned long offset)
+{
+        return readl(IO_TO_VIRT(offset));
+}
+
+static inline void tegra_apb_writel(u32 value, unsigned long offset)
+{
+        writel(value, IO_TO_VIRT(offset));
+}
+#endif
+
+#endif
diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c
index 7a95e0b..0952494 100644
--- a/arch/arm/mach-tegra/board-dt-tegra20.c
+++ b/arch/arm/mach-tegra/board-dt-tegra20.c
@@ -68,11 +68,11 @@
 	OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra-i2s.1", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra-das", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB_BASE, "tegra-ehci.0",
-		       &tegra_ehci1_device.dev.platform_data),
+		       &tegra_ehci1_pdata),
 	OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB2_BASE, "tegra-ehci.1",
-		       &tegra_ehci2_device.dev.platform_data),
+		       &tegra_ehci2_pdata),
 	OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2",
-		       &tegra_ehci3_device.dev.platform_data),
+		       &tegra_ehci3_pdata),
 	{}
 };
 
@@ -131,11 +131,7 @@
 }
 
 static const char *tegra20_dt_board_compat[] = {
-	"compulab,trimslice",
-	"nvidia,harmony",
-	"compal,paz00",
-	"nvidia,seaboard",
-	"nvidia,ventana",
+	"nvidia,tegra20",
 	NULL
 };
 
diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c
index 3c197e2..5f7c03e 100644
--- a/arch/arm/mach-tegra/board-dt-tegra30.c
+++ b/arch/arm/mach-tegra/board-dt-tegra30.c
@@ -34,20 +34,42 @@
 #include <asm/hardware/gic.h>
 
 #include "board.h"
+#include "clock.h"
 
 static struct of_device_id tegra_dt_match_table[] __initdata = {
 	{ .compatible = "simple-bus", },
 	{}
 };
 
+struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000000, "sdhci-tegra.0", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000200, "sdhci-tegra.1", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000400, "sdhci-tegra.2", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000600, "sdhci-tegra.3", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C000, "tegra-i2c.0", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C400, "tegra-i2c.1", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C500, "tegra-i2c.2", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C700, "tegra-i2c.3", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL),
+	{}
+};
+
+static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
+	/* name		parent		rate		enabled */
+	{ "uarta",	"pll_p",	408000000,	true },
+	{ NULL,		NULL,		0,		0},
+};
+
 static void __init tegra30_dt_init(void)
 {
+	tegra_clk_init_from_table(tegra_dt_clk_init_table);
+
 	of_platform_populate(NULL, tegra_dt_match_table,
-				NULL, NULL);
+				tegra30_auxdata_lookup, NULL);
 }
 
 static const char *tegra30_dt_board_compat[] = {
-	"nvidia,cardhu",
+	"nvidia,tegra30",
 	NULL
 };
 
diff --git a/arch/arm/mach-tegra/board-harmony-pinmux.c b/arch/arm/mach-tegra/board-harmony-pinmux.c
index 465808c..1af85bccc 100644
--- a/arch/arm/mach-tegra/board-harmony-pinmux.c
+++ b/arch/arm/mach-tegra/board-harmony-pinmux.c
@@ -53,7 +53,7 @@
 	{TEGRA_PINGROUP_GME,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
 	{TEGRA_PINGROUP_GPU,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
 	{TEGRA_PINGROUP_GPU7,  TEGRA_MUX_RTCK,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-	{TEGRA_PINGROUP_GPV,   TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+	{TEGRA_PINGROUP_GPV,   TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
 	{TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
 	{TEGRA_PINGROUP_I2CP,  TEGRA_MUX_I2C,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
 	{TEGRA_PINGROUP_IRRX,  TEGRA_MUX_UARTA,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
@@ -112,10 +112,10 @@
 	{TEGRA_PINGROUP_SDC,   TEGRA_MUX_PWM,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
 	{TEGRA_PINGROUP_SDD,   TEGRA_MUX_PWM,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
 	{TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SLXA,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+	{TEGRA_PINGROUP_SLXA,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
 	{TEGRA_PINGROUP_SLXC,  TEGRA_MUX_SPDIF,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
 	{TEGRA_PINGROUP_SLXD,  TEGRA_MUX_SPDIF,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-	{TEGRA_PINGROUP_SLXK,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+	{TEGRA_PINGROUP_SLXK,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
 	{TEGRA_PINGROUP_SPDI,  TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
 	{TEGRA_PINGROUP_SPDO,  TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
 	{TEGRA_PINGROUP_SPIA,  TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
diff --git a/arch/arm/mach-tegra/board-harmony-power.c b/arch/arm/mach-tegra/board-harmony-power.c
index 21d1285..82f32300 100644
--- a/arch/arm/mach-tegra/board-harmony-power.c
+++ b/arch/arm/mach-tegra/board-harmony-power.c
@@ -18,31 +18,27 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
-#include <linux/io.h>
 #include <linux/regulator/machine.h>
 #include <linux/mfd/tps6586x.h>
 
-#include <mach/iomap.h>
 #include <mach/irqs.h>
 
 #include "board-harmony.h"
 
-#define PMC_CTRL		0x0
-#define PMC_CTRL_INTR_LOW	(1 << 17)
-
 static struct regulator_consumer_supply tps658621_ldo0_supply[] = {
 	REGULATOR_SUPPLY("pex_clk", NULL),
 };
 
 static struct regulator_init_data ldo0_data = {
 	.constraints = {
-		.min_uV = 1250 * 1000,
+		.min_uV = 3300 * 1000,
 		.max_uV = 3300 * 1000,
 		.valid_modes_mask = (REGULATOR_MODE_NORMAL |
 				     REGULATOR_MODE_STANDBY),
 		.valid_ops_mask = (REGULATOR_CHANGE_MODE |
 				   REGULATOR_CHANGE_STATUS |
 				   REGULATOR_CHANGE_VOLTAGE),
+		.apply_uV = 1,
 	},
 	.num_consumer_supplies = ARRAY_SIZE(tps658621_ldo0_supply),
 	.consumer_supplies = tps658621_ldo0_supply,
@@ -114,16 +110,6 @@
 
 int __init harmony_regulator_init(void)
 {
-	void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
-	u32 pmc_ctrl;
-
-	/*
-	 * Configure the power management controller to trigger PMU
-	 * interrupts when low
-	 */
-	pmc_ctrl = readl(pmc + PMC_CTRL);
-	writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL);
-
 	i2c_register_board_info(3, harmony_regulators, 1);
 
 	return 0;
diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c
index 789bdc9..c00aadb 100644
--- a/arch/arm/mach-tegra/board-harmony.c
+++ b/arch/arm/mach-tegra/board-harmony.c
@@ -101,7 +101,6 @@
 static struct i2c_board_info __initdata wm8903_board_info = {
 	I2C_BOARD_INFO("wm8903", 0x1a),
 	.platform_data = &harmony_wm8903_pdata,
-	.irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ),
 };
 
 static void __init harmony_i2c_init(void)
@@ -111,6 +110,7 @@
 	platform_device_register(&tegra_i2c_device3);
 	platform_device_register(&tegra_i2c_device4);
 
+	wm8903_board_info.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ);
 	i2c_register_board_info(0, &wm8903_board_info, 1);
 }
 
diff --git a/arch/arm/mach-tegra/board-seaboard.c b/arch/arm/mach-tegra/board-seaboard.c
index ebac65f..d669847 100644
--- a/arch/arm/mach-tegra/board-seaboard.c
+++ b/arch/arm/mach-tegra/board-seaboard.c
@@ -159,7 +159,6 @@
 
 static struct i2c_board_info __initdata isl29018_device = {
 	I2C_BOARD_INFO("isl29018", 0x44),
-	.irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_ISL29018_IRQ),
 };
 
 static struct i2c_board_info __initdata adt7461_device = {
@@ -183,7 +182,6 @@
 static struct i2c_board_info __initdata wm8903_device = {
 	I2C_BOARD_INFO("wm8903", 0x1a),
 	.platform_data = &wm8903_pdata,
-	.irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ),
 };
 
 static int seaboard_ehci_init(void)
@@ -214,7 +212,10 @@
 	gpio_request(TEGRA_GPIO_ISL29018_IRQ, "isl29018");
 	gpio_direction_input(TEGRA_GPIO_ISL29018_IRQ);
 
+	isl29018_device.irq = gpio_to_irq(TEGRA_GPIO_ISL29018_IRQ);
 	i2c_register_board_info(0, &isl29018_device, 1);
+
+	wm8903_device.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ);
 	i2c_register_board_info(0, &wm8903_device, 1);
 
 	i2c_register_board_info(3, &adt7461_device, 1);
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 8337068..8dad8d1 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -399,6 +399,28 @@
 }
 EXPORT_SYMBOL(tegra_periph_reset_assert);
 
+/* Several extended clock configuration bits (e.g., clock routing, clock
+ * phase control) are included in PLL and peripheral clock source
+ * registers. */
+int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&c->spinlock, flags);
+
+	if (!c->ops || !c->ops->clk_cfg_ex) {
+		ret = -ENOSYS;
+		goto out;
+	}
+	ret = c->ops->clk_cfg_ex(c, p, setting);
+
+out:
+	spin_unlock_irqrestore(&c->spinlock, flags);
+
+	return ret;
+}
+
 #ifdef CONFIG_DEBUG_FS
 
 static int __clk_lock_all_spinlocks(void)
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index 5c44106..bc30065 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -24,6 +24,8 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
+#include <mach/clk.h>
+
 #define DIV_BUS			(1 << 0)
 #define DIV_U71			(1 << 1)
 #define DIV_U71_FIXED		(1 << 2)
@@ -39,7 +41,16 @@
 #define PERIPH_MANUAL_RESET	(1 << 12)
 #define PLL_ALT_MISC_REG	(1 << 13)
 #define PLLU			(1 << 14)
+#define PLLX                    (1 << 15)
+#define MUX_PWM                 (1 << 16)
+#define MUX8                    (1 << 17)
+#define DIV_U71_UART            (1 << 18)
+#define MUX_CLK_OUT             (1 << 19)
+#define PLLM                    (1 << 20)
+#define DIV_U71_INT             (1 << 21)
+#define DIV_U71_IDLE            (1 << 22)
 #define ENABLE_ON_INIT		(1 << 28)
+#define PERIPH_ON_APB           (1 << 29)
 
 struct clk;
 
@@ -65,6 +76,8 @@
 	int		(*set_rate)(struct clk *, unsigned long);
 	long		(*round_rate)(struct clk *, unsigned long);
 	void		(*reset)(struct clk *, bool);
+	int		(*clk_cfg_ex)(struct clk *,
+				enum tegra_clk_ex_param, u32);
 };
 
 enum clk_state {
@@ -114,6 +127,7 @@
 			unsigned long			vco_max;
 			const struct clk_pll_freq_table	*freq_table;
 			int				lock_delay;
+			unsigned long			fixed_rate;
 		} pll;
 		struct {
 			u32				sel;
@@ -146,6 +160,7 @@
 };
 
 void tegra2_init_clocks(void);
+void tegra30_init_clocks(void);
 void clk_init(struct clk *clk);
 struct clk *tegra_get_clock_by_name(const char *name);
 int clk_reparent(struct clk *c, struct clk *parent);
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index a2eb901..22df10f 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -27,11 +27,29 @@
 #include <asm/hardware/gic.h>
 
 #include <mach/iomap.h>
-#include <mach/system.h>
+#include <mach/powergate.h>
 
 #include "board.h"
 #include "clock.h"
 #include "fuse.h"
+#include "pmc.h"
+
+/*
+ * Storage for debug-macro.S's state.
+ *
+ * This must be in .data not .bss so that it gets initialized each time the
+ * kernel is loaded. The data is declared here rather than debug-macro.S so
+ * that multiple inclusions of debug-macro.S point at the same data.
+ */
+#define TEGRA_DEBUG_UART_OFFSET (TEGRA_DEBUG_UART_BASE & 0xFFFF)
+u32 tegra_uart_config[3] = {
+	/* Debug UART initialization required */
+	1,
+	/* Debug UART physical address */
+	(u32)(IO_APB_PHYS + TEGRA_DEBUG_UART_OFFSET),
+	/* Debug UART virtual address */
+	(u32)(IO_APB_VIRT + TEGRA_DEBUG_UART_OFFSET),
+};
 
 #ifdef CONFIG_OF
 static const struct of_device_id tegra_dt_irq_match[] __initconst = {
@@ -100,11 +118,17 @@
 	tegra2_init_clocks();
 	tegra_clk_init_from_table(tegra20_clk_init_table);
 	tegra_init_cache(0x331, 0x441);
+	tegra_pmc_init();
+	tegra_powergate_init();
 }
 #endif
 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
 void __init tegra30_init_early(void)
 {
+	tegra_init_fuse();
+	tegra30_init_clocks();
 	tegra_init_cache(0x441, 0x551);
+	tegra_pmc_init();
+	tegra_powergate_init();
 }
 #endif
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index bb5ce39..7a065f0 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -30,7 +30,6 @@
 #include <linux/io.h>
 #include <linux/suspend.h>
 
-#include <asm/system.h>
 
 #include <mach/clk.h>
 
diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c
new file mode 100644
index 0000000..d83a8c0
--- /dev/null
+++ b/arch/arm/mach-tegra/cpuidle.c
@@ -0,0 +1,107 @@
+/*
+ * arch/arm/mach-tegra/cpuidle.c
+ *
+ * CPU idle driver for Tegra CPUs
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation.
+ * Copyright (c) 2011 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *         Gary King <gking@nvidia.com>
+ *
+ * Rework for 3.3 by Peter De Schrijver <pdeschrijver@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; 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/kernel.h>
+#include <linux/module.h>
+#include <linux/cpu.h>
+#include <linux/cpuidle.h>
+#include <linux/hrtimer.h>
+
+#include <mach/iomap.h>
+
+extern void tegra_cpu_wfi(void);
+
+static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv, int index);
+
+struct cpuidle_driver tegra_idle_driver = {
+	.name = "tegra_idle",
+	.owner = THIS_MODULE,
+	.state_count = 1,
+	.states = {
+		[0] = {
+			.enter			= tegra_idle_enter_lp3,
+			.exit_latency		= 10,
+			.target_residency	= 10,
+			.power_usage		= 600,
+			.flags			= CPUIDLE_FLAG_TIME_VALID,
+			.name			= "LP3",
+			.desc			= "CPU flow-controlled",
+		},
+	},
+};
+
+static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
+
+static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
+	struct cpuidle_driver *drv, int index)
+{
+	ktime_t enter, exit;
+	s64 us;
+
+	local_irq_disable();
+	local_fiq_disable();
+
+	enter = ktime_get();
+
+	tegra_cpu_wfi();
+
+	exit = ktime_sub(ktime_get(), enter);
+	us = ktime_to_us(exit);
+
+	local_fiq_enable();
+	local_irq_enable();
+
+	dev->last_residency = us;
+
+	return index;
+}
+
+static int __init tegra_cpuidle_init(void)
+{
+	int ret;
+	unsigned int cpu;
+	struct cpuidle_device *dev;
+	struct cpuidle_driver *drv = &tegra_idle_driver;
+
+	ret = cpuidle_register_driver(&tegra_idle_driver);
+	if (ret) {
+		pr_err("CPUidle driver registration failed\n");
+		return ret;
+	}
+
+	for_each_possible_cpu(cpu) {
+		dev = &per_cpu(tegra_idle_device, cpu);
+		dev->cpu = cpu;
+
+		dev->state_count = drv->state_count;
+		ret = cpuidle_register_device(dev);
+		if (ret) {
+			pr_err("CPU%u: CPUidle device registration failed\n",
+				cpu);
+			return ret;
+		}
+	}
+	return 0;
+}
+device_initcall(tegra_cpuidle_init);
diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
index 7a2a02d..5f6b867 100644
--- a/arch/arm/mach-tegra/devices.c
+++ b/arch/arm/mach-tegra/devices.c
@@ -23,7 +23,6 @@
 #include <linux/fsl_devices.h>
 #include <linux/serial_8250.h>
 #include <linux/i2c-tegra.h>
-#include <linux/platform_data/tegra_usb.h>
 #include <asm/pmu.h>
 #include <mach/irqs.h>
 #include <mach/iomap.h>
@@ -446,18 +445,18 @@
 	.clk = "cdev2",
 };
 
-static struct tegra_ehci_platform_data tegra_ehci1_pdata = {
+struct tegra_ehci_platform_data tegra_ehci1_pdata = {
 	.operating_mode = TEGRA_USB_OTG,
 	.power_down_on_bus_suspend = 1,
 };
 
-static struct tegra_ehci_platform_data tegra_ehci2_pdata = {
+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,
 };
 
-static struct tegra_ehci_platform_data tegra_ehci3_pdata = {
+struct tegra_ehci_platform_data tegra_ehci3_pdata = {
 	.operating_mode = TEGRA_USB_HOST,
 	.power_down_on_bus_suspend = 1,
 };
diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h
index 873ecb2..ec45567 100644
--- a/arch/arm/mach-tegra/devices.h
+++ b/arch/arm/mach-tegra/devices.h
@@ -20,6 +20,11 @@
 #define __MACH_TEGRA_DEVICES_H
 
 #include <linux/platform_device.h>
+#include <linux/platform_data/tegra_usb.h>
+
+extern struct tegra_ehci_platform_data tegra_ehci1_pdata;
+extern struct tegra_ehci_platform_data tegra_ehci2_pdata;
+extern struct tegra_ehci_platform_data tegra_ehci3_pdata;
 
 extern struct platform_device tegra_gpio_device;
 extern struct platform_device tegra_pinmux_device;
diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c
index c0cf967..abea4f6 100644
--- a/arch/arm/mach-tegra/dma.c
+++ b/arch/arm/mach-tegra/dma.c
@@ -33,6 +33,8 @@
 #include <mach/iomap.h>
 #include <mach/suspend.h>
 
+#include "apbio.h"
+
 #define APB_DMA_GEN				0x000
 #define GEN_ENABLE				(1<<31)
 
@@ -50,8 +52,6 @@
 #define CSR_ONCE				(1<<27)
 #define CSR_FLOW				(1<<21)
 #define CSR_REQ_SEL_SHIFT			16
-#define CSR_REQ_SEL_MASK			(0x1F<<CSR_REQ_SEL_SHIFT)
-#define CSR_REQ_SEL_INVALID			(31<<CSR_REQ_SEL_SHIFT)
 #define CSR_WCOUNT_SHIFT			2
 #define CSR_WCOUNT_MASK				0xFFFC
 
@@ -133,6 +133,7 @@
 
 static bool tegra_dma_initialized;
 static DEFINE_MUTEX(tegra_dma_lock);
+static DEFINE_SPINLOCK(enable_lock);
 
 static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS);
 static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS];
@@ -180,36 +181,94 @@
 
 static int tegra_dma_cancel(struct tegra_dma_channel *ch)
 {
-	u32 csr;
 	unsigned long irq_flags;
 
 	spin_lock_irqsave(&ch->lock, irq_flags);
 	while (!list_empty(&ch->list))
 		list_del(ch->list.next);
 
-	csr = readl(ch->addr + APB_DMA_CHAN_CSR);
-	csr &= ~CSR_REQ_SEL_MASK;
-	csr |= CSR_REQ_SEL_INVALID;
-	writel(csr, ch->addr + APB_DMA_CHAN_CSR);
-
 	tegra_dma_stop(ch);
 
 	spin_unlock_irqrestore(&ch->lock, irq_flags);
 	return 0;
 }
 
+static unsigned int get_channel_status(struct tegra_dma_channel *ch,
+			struct tegra_dma_req *req, bool is_stop_dma)
+{
+	void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
+	unsigned int status;
+
+	if (is_stop_dma) {
+		/*
+		 * STOP the DMA and get the transfer count.
+		 * Getting the transfer count is tricky.
+		 *  - Globally disable DMA on all channels
+		 *  - Read the channel's status register to know the number
+		 *    of pending bytes to be transfered.
+		 *  - Stop the dma channel
+		 *  - Globally re-enable DMA to resume other transfers
+		 */
+		spin_lock(&enable_lock);
+		writel(0, addr + APB_DMA_GEN);
+		udelay(20);
+		status = readl(ch->addr + APB_DMA_CHAN_STA);
+		tegra_dma_stop(ch);
+		writel(GEN_ENABLE, addr + APB_DMA_GEN);
+		spin_unlock(&enable_lock);
+		if (status & STA_ISE_EOC) {
+			pr_err("Got Dma Int here clearing");
+			writel(status, ch->addr + APB_DMA_CHAN_STA);
+		}
+		req->status = TEGRA_DMA_REQ_ERROR_ABORTED;
+	} else {
+		status = readl(ch->addr + APB_DMA_CHAN_STA);
+	}
+	return status;
+}
+
+/* should be called with the channel lock held */
+static unsigned int dma_active_count(struct tegra_dma_channel *ch,
+	struct tegra_dma_req *req, unsigned int status)
+{
+	unsigned int to_transfer;
+	unsigned int req_transfer_count;
+	unsigned int bytes_transferred;
+
+	to_transfer = ((status & STA_COUNT_MASK) >> STA_COUNT_SHIFT) + 1;
+	req_transfer_count = ch->req_transfer_count + 1;
+	bytes_transferred = req_transfer_count;
+	if (status & STA_BUSY)
+		bytes_transferred -= to_transfer;
+	/*
+	 * In continuous transfer mode, DMA only tracks the count of the
+	 * half DMA buffer. So, if the DMA already finished half the DMA
+	 * then add the half buffer to the completed count.
+	 */
+	if (ch->mode & TEGRA_DMA_MODE_CONTINOUS) {
+		if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL)
+			bytes_transferred += req_transfer_count;
+		if (status & STA_ISE_EOC)
+			bytes_transferred += req_transfer_count;
+	}
+	bytes_transferred *= 4;
+	return bytes_transferred;
+}
+
 int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
 	struct tegra_dma_req *_req)
 {
-	unsigned int csr;
 	unsigned int status;
 	struct tegra_dma_req *req = NULL;
 	int found = 0;
 	unsigned long irq_flags;
-	int to_transfer;
-	int req_transfer_count;
+	int stop = 0;
 
 	spin_lock_irqsave(&ch->lock, irq_flags);
+
+	if (list_entry(ch->list.next, struct tegra_dma_req, node) == _req)
+		stop = 1;
+
 	list_for_each_entry(req, &ch->list, node) {
 		if (req == _req) {
 			list_del(&req->node);
@@ -222,47 +281,12 @@
 		return 0;
 	}
 
-	/* STOP the DMA and get the transfer count.
-	 * Getting the transfer count is tricky.
-	 *  - Change the source selector to invalid to stop the DMA from
-	 *    FIFO to memory.
-	 *  - Read the status register to know the number of pending
-	 *    bytes to be transferred.
-	 *  - Finally stop or program the DMA to the next buffer in the
-	 *    list.
-	 */
-	csr = readl(ch->addr + APB_DMA_CHAN_CSR);
-	csr &= ~CSR_REQ_SEL_MASK;
-	csr |= CSR_REQ_SEL_INVALID;
-	writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+	if (!stop)
+		goto skip_stop_dma;
 
-	/* Get the transfer count */
-	status = readl(ch->addr + APB_DMA_CHAN_STA);
-	to_transfer = (status & STA_COUNT_MASK) >> STA_COUNT_SHIFT;
-	req_transfer_count = ch->req_transfer_count;
-	req_transfer_count += 1;
-	to_transfer += 1;
+	status = get_channel_status(ch, req, true);
+	req->bytes_transferred = dma_active_count(ch, req, status);
 
-	req->bytes_transferred = req_transfer_count;
-
-	if (status & STA_BUSY)
-		req->bytes_transferred -= to_transfer;
-
-	/* In continuous transfer mode, DMA only tracks the count of the
-	 * half DMA buffer. So, if the DMA already finished half the DMA
-	 * then add the half buffer to the completed count.
-	 *
-	 *	FIXME: There can be a race here. What if the req to
-	 *	dequue happens at the same time as the DMA just moved to
-	 *	the new buffer and SW didn't yet received the interrupt?
-	 */
-	if (ch->mode & TEGRA_DMA_MODE_CONTINOUS)
-		if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL)
-			req->bytes_transferred += req_transfer_count;
-
-	req->bytes_transferred *= 4;
-
-	tegra_dma_stop(ch);
 	if (!list_empty(&ch->list)) {
 		/* if the list is not empty, queue the next request */
 		struct tegra_dma_req *next_req;
@@ -270,6 +294,8 @@
 			typeof(*next_req), node);
 		tegra_dma_update_hw(ch, next_req);
 	}
+
+skip_stop_dma:
 	req->status = -TEGRA_DMA_REQ_ERROR_ABORTED;
 
 	spin_unlock_irqrestore(&ch->lock, irq_flags);
@@ -357,7 +383,7 @@
 	int channel;
 	struct tegra_dma_channel *ch = NULL;
 
-	if (WARN_ON(!tegra_dma_initialized))
+	if (!tegra_dma_initialized)
 		return NULL;
 
 	mutex_lock(&tegra_dma_lock);
diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c
new file mode 100644
index 0000000..fef66a7
--- /dev/null
+++ b/arch/arm/mach-tegra/flowctrl.c
@@ -0,0 +1,62 @@
+/*
+ * arch/arm/mach-tegra/flowctrl.c
+ *
+ * functions and macros to control the flowcontroller
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#include <mach/iomap.h>
+
+#include "flowctrl.h"
+
+u8 flowctrl_offset_halt_cpu[] = {
+	FLOW_CTRL_HALT_CPU0_EVENTS,
+	FLOW_CTRL_HALT_CPU1_EVENTS,
+	FLOW_CTRL_HALT_CPU1_EVENTS + 8,
+	FLOW_CTRL_HALT_CPU1_EVENTS + 16,
+};
+
+u8 flowctrl_offset_cpu_csr[] = {
+	FLOW_CTRL_CPU0_CSR,
+	FLOW_CTRL_CPU1_CSR,
+	FLOW_CTRL_CPU1_CSR + 8,
+	FLOW_CTRL_CPU1_CSR + 16,
+};
+
+static void flowctrl_update(u8 offset, u32 value)
+{
+	void __iomem *addr = IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + offset;
+
+	writel(value, addr);
+
+	/* ensure the update has reached the flow controller */
+	wmb();
+	readl_relaxed(addr);
+}
+
+void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value)
+{
+	return flowctrl_update(flowctrl_offset_halt_cpu[cpuid], value);
+}
+
+void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value)
+{
+	return flowctrl_update(flowctrl_offset_cpu_csr[cpuid], value);
+}
diff --git a/arch/arm/mach-tegra/flowctrl.h b/arch/arm/mach-tegra/flowctrl.h
new file mode 100644
index 0000000..1942817
--- /dev/null
+++ b/arch/arm/mach-tegra/flowctrl.h
@@ -0,0 +1,42 @@
+/*
+ * arch/arm/mach-tegra/flowctrl.h
+ *
+ * functions and macros to control the flowcontroller
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * 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/>.
+ */
+
+#ifndef __MACH_TEGRA_FLOWCTRL_H
+#define __MACH_TEGRA_FLOWCTRL_H
+
+#define FLOW_CTRL_HALT_CPU0_EVENTS	0x0
+#define FLOW_CTRL_WAITEVENT		(2 << 29)
+#define FLOW_CTRL_WAIT_FOR_INTERRUPT	(4 << 29)
+#define FLOW_CTRL_JTAG_RESUME		(1 << 28)
+#define FLOW_CTRL_HALT_CPU_IRQ		(1 << 10)
+#define	FLOW_CTRL_HALT_CPU_FIQ		(1 << 8)
+#define FLOW_CTRL_CPU0_CSR		0x8
+#define	FLOW_CTRL_CSR_INTR_FLAG		(1 << 15)
+#define FLOW_CTRL_CSR_EVENT_FLAG	(1 << 14)
+#define FLOW_CTRL_CSR_ENABLE		(1 << 0)
+#define FLOW_CTRL_HALT_CPU1_EVENTS	0x14
+#define FLOW_CTRL_CPU1_CSR		0x18
+
+#ifndef __ASSEMBLY__
+void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value);
+void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value);
+#endif
+
+#endif
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index ea49bd9..f946d12 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -19,68 +19,113 @@
 
 #include <linux/kernel.h>
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 #include <mach/iomap.h>
 
 #include "fuse.h"
+#include "apbio.h"
 
 #define FUSE_UID_LOW		0x108
 #define FUSE_UID_HIGH		0x10c
 #define FUSE_SKU_INFO		0x110
 #define FUSE_SPARE_BIT		0x200
 
-static inline u32 fuse_readl(unsigned long offset)
+int tegra_sku_id;
+int tegra_cpu_process_id;
+int tegra_core_process_id;
+int tegra_chip_id;
+enum tegra_revision tegra_revision;
+
+/* The BCT to use at boot is specified by board straps that can be read
+ * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs.
+ */
+int tegra_bct_strapping;
+
+#define STRAP_OPT 0x008
+#define GMI_AD0 (1 << 4)
+#define GMI_AD1 (1 << 5)
+#define RAM_ID_MASK (GMI_AD0 | GMI_AD1)
+#define RAM_CODE_SHIFT 4
+
+static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
+	[TEGRA_REVISION_UNKNOWN] = "unknown",
+	[TEGRA_REVISION_A01]     = "A01",
+	[TEGRA_REVISION_A02]     = "A02",
+	[TEGRA_REVISION_A03]     = "A03",
+	[TEGRA_REVISION_A03p]    = "A03 prime",
+	[TEGRA_REVISION_A04]     = "A04",
+};
+
+static inline u32 tegra_fuse_readl(unsigned long offset)
 {
-	return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
+	return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
 }
 
-static inline void fuse_writel(u32 value, unsigned long offset)
+static inline bool get_spare_fuse(int bit)
 {
-	writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
+	return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4);
+}
+
+static enum tegra_revision tegra_get_revision(u32 id)
+{
+	u32 minor_rev = (id >> 16) & 0xf;
+
+	switch (minor_rev) {
+	case 1:
+		return TEGRA_REVISION_A01;
+	case 2:
+		return TEGRA_REVISION_A02;
+	case 3:
+		if (tegra_chip_id == TEGRA20 &&
+			(get_spare_fuse(18) || get_spare_fuse(19)))
+			return TEGRA_REVISION_A03p;
+		else
+			return TEGRA_REVISION_A03;
+	case 4:
+		return TEGRA_REVISION_A04;
+	default:
+		return TEGRA_REVISION_UNKNOWN;
+	}
 }
 
 void tegra_init_fuse(void)
 {
+	u32 id;
+
 	u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
 	reg |= 1 << 28;
 	writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
 
-	pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n",
-		tegra_sku_id(), tegra_cpu_process_id(),
-		tegra_core_process_id());
+	reg = tegra_fuse_readl(FUSE_SKU_INFO);
+	tegra_sku_id = reg & 0xFF;
+
+	reg = tegra_fuse_readl(FUSE_SPARE_BIT);
+	tegra_cpu_process_id = (reg >> 6) & 3;
+
+	reg = tegra_fuse_readl(FUSE_SPARE_BIT);
+	tegra_core_process_id = (reg >> 12) & 3;
+
+	reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT);
+	tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT;
+
+	id = readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
+	tegra_chip_id = (id >> 8) & 0xff;
+
+	tegra_revision = tegra_get_revision(id);
+
+	pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
+		tegra_revision_name[tegra_revision],
+		tegra_sku_id, tegra_cpu_process_id,
+		tegra_core_process_id);
 }
 
 unsigned long long tegra_chip_uid(void)
 {
 	unsigned long long lo, hi;
 
-	lo = fuse_readl(FUSE_UID_LOW);
-	hi = fuse_readl(FUSE_UID_HIGH);
+	lo = tegra_fuse_readl(FUSE_UID_LOW);
+	hi = tegra_fuse_readl(FUSE_UID_HIGH);
 	return (hi << 32ull) | lo;
 }
 EXPORT_SYMBOL(tegra_chip_uid);
-
-int tegra_sku_id(void)
-{
-	int sku_id;
-	u32 reg = fuse_readl(FUSE_SKU_INFO);
-	sku_id = reg & 0xFF;
-	return sku_id;
-}
-
-int tegra_cpu_process_id(void)
-{
-	int cpu_process_id;
-	u32 reg = fuse_readl(FUSE_SPARE_BIT);
-	cpu_process_id = (reg >> 6) & 3;
-	return cpu_process_id;
-}
-
-int tegra_core_process_id(void)
-{
-	int core_process_id;
-	u32 reg = fuse_readl(FUSE_SPARE_BIT);
-	core_process_id = (reg >> 12) & 3;
-	return core_process_id;
-}
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
index 584b2e2..d2107b2 100644
--- a/arch/arm/mach-tegra/fuse.h
+++ b/arch/arm/mach-tegra/fuse.h
@@ -1,6 +1,4 @@
 /*
- * arch/arm/mach-tegra/fuse.c
- *
  * Copyright (C) 2010 Google, Inc.
  *
  * Author:
@@ -17,8 +15,38 @@
  *
  */
 
+#ifndef __MACH_TEGRA_FUSE_H
+#define __MACH_TEGRA_FUSE_H
+
+enum tegra_revision {
+	TEGRA_REVISION_UNKNOWN = 0,
+	TEGRA_REVISION_A01,
+	TEGRA_REVISION_A02,
+	TEGRA_REVISION_A03,
+	TEGRA_REVISION_A03p,
+	TEGRA_REVISION_A04,
+	TEGRA_REVISION_MAX,
+};
+
+#define SKU_ID_T20	8
+#define SKU_ID_T25SE	20
+#define SKU_ID_AP25	23
+#define SKU_ID_T25	24
+#define SKU_ID_AP25E	27
+#define SKU_ID_T25E	28
+
+#define TEGRA20		0x20
+#define TEGRA30		0x30
+
+extern int tegra_sku_id;
+extern int tegra_cpu_process_id;
+extern int tegra_core_process_id;
+extern int tegra_chip_id;
+extern enum tegra_revision tegra_revision;
+
+extern int tegra_bct_strapping;
+
 unsigned long long tegra_chip_uid(void);
-int tegra_sku_id(void);
-int tegra_cpu_process_id(void);
-int tegra_core_process_id(void);
 void tegra_init_fuse(void);
+
+#endif
diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S
index b5349b2..fef9c2c 100644
--- a/arch/arm/mach-tegra/headsmp.S
+++ b/arch/arm/mach-tegra/headsmp.S
@@ -1,6 +1,23 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 
+#include <asm/cache.h>
+
+#include <mach/iomap.h>
+
+#include "flowctrl.h"
+#include "reset.h"
+
+#define APB_MISC_GP_HIDREV	0x804
+#define PMC_SCRATCH41	0x140
+
+#define RESET_DATA(x)	((TEGRA_RESET_##x)*4)
+
+	.macro mov32, reg, val
+	movw	\reg, #:lower16:\val
+	movt	\reg, #:upper16:\val
+	.endm
+
         .section ".text.head", "ax"
 	__CPUINIT
 
@@ -47,15 +64,149 @@
         mov     pc, lr
 ENDPROC(v7_invalidate_l1)
 
+
 ENTRY(tegra_secondary_startup)
-	msr	cpsr_fsxc, #0xd3
         bl      v7_invalidate_l1
-	mrc	p15, 0, r0, c0, c0, 5
-        and	r0, r0, #15
-        ldr     r1, =0x6000f100
-        str     r0, [r1]
-1:      ldr     r2, [r1]
-        cmp     r0, r2
-        beq     1b
+	/* Enable coresight */
+	mov32	r0, 0xC5ACCE55
+	mcr	p14, 0, r0, c7, c12, 6
         b       secondary_startup
 ENDPROC(tegra_secondary_startup)
+
+	.align L1_CACHE_SHIFT
+ENTRY(__tegra_cpu_reset_handler_start)
+
+/*
+ * __tegra_cpu_reset_handler:
+ *
+ * Common handler for all CPU reset events.
+ *
+ * Register usage within the reset handler:
+ *
+ *      R7  = CPU present (to the OS) mask
+ *      R8  = CPU in LP1 state mask
+ *      R9  = CPU in LP2 state mask
+ *      R10 = CPU number
+ *      R11 = CPU mask
+ *      R12 = pointer to reset handler data
+ *
+ * NOTE: This code is copied to IRAM. All code and data accesses
+ *       must be position-independent.
+ */
+
+	.align L1_CACHE_SHIFT
+ENTRY(__tegra_cpu_reset_handler)
+
+	cpsid	aif, 0x13			@ SVC mode, interrupts disabled
+	mrc	p15, 0, r10, c0, c0, 5		@ MPIDR
+	and	r10, r10, #0x3			@ R10 = CPU number
+	mov	r11, #1
+	mov	r11, r11, lsl r10  		@ R11 = CPU mask
+	adr	r12, __tegra_cpu_reset_handler_data
+
+#ifdef CONFIG_SMP
+	/* Does the OS know about this CPU? */
+	ldr	r7, [r12, #RESET_DATA(MASK_PRESENT)]
+	tst	r7, r11 			@ if !present
+	bleq	__die				@ CPU not present (to OS)
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+	/* Are we on Tegra20? */
+	mov32	r6, TEGRA_APB_MISC_BASE
+	ldr	r0, [r6, #APB_MISC_GP_HIDREV]
+	and	r0, r0, #0xff00
+	cmp	r0, #(0x20 << 8)
+	bne	1f
+	/* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
+	mov32	r6, TEGRA_PMC_BASE
+	mov	r0, #0
+	cmp	r10, #0
+	strne	r0, [r6, #PMC_SCRATCH41]
+1:
+#endif
+
+#ifdef CONFIG_SMP
+	/*
+	 * Can only be secondary boot (initial or hotplug) but CPU 0
+	 * cannot be here.
+	 */
+	cmp	r10, #0
+	bleq	__die				@ CPU0 cannot be here
+	ldr	lr, [r12, #RESET_DATA(STARTUP_SECONDARY)]
+	cmp	lr, #0
+	bleq	__die				@ no secondary startup handler
+	bx	lr
+#endif
+
+/*
+ * We don't know why the CPU reset. Just kill it.
+ * The LR register will contain the address we died at + 4.
+ */
+
+__die:
+	sub	lr, lr, #4
+	mov32	r7, TEGRA_PMC_BASE
+	str	lr, [r7, #PMC_SCRATCH41]
+
+	mov32	r7, TEGRA_CLK_RESET_BASE
+
+	/* Are we on Tegra20? */
+	mov32	r6, TEGRA_APB_MISC_BASE
+	ldr	r0, [r6, #APB_MISC_GP_HIDREV]
+	and	r0, r0, #0xff00
+	cmp	r0, #(0x20 << 8)
+	bne	1f
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+	mov32	r0, 0x1111
+	mov	r1, r0, lsl r10
+	str	r1, [r7, #0x340]		@ CLK_RST_CPU_CMPLX_SET
+#endif
+1:
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+	mov32	r6, TEGRA_FLOW_CTRL_BASE
+
+	cmp	r10, #0
+	moveq	r1, #FLOW_CTRL_HALT_CPU0_EVENTS
+	moveq	r2, #FLOW_CTRL_CPU0_CSR
+	movne	r1, r10, lsl #3
+	addne	r2, r1, #(FLOW_CTRL_CPU1_CSR-8)
+	addne	r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8)
+
+	/* Clear CPU "event" and "interrupt" flags and power gate
+	   it when halting but not before it is in the "WFI" state. */
+	ldr	r0, [r6, +r2]
+	orr	r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
+	orr	r0, r0, #FLOW_CTRL_CSR_ENABLE
+	str	r0, [r6, +r2]
+
+	/* Unconditionally halt this CPU */
+	mov	r0, #FLOW_CTRL_WAITEVENT
+	str	r0, [r6, +r1]
+	ldr	r0, [r6, +r1]			@ memory barrier
+
+	dsb
+	isb
+	wfi					@ CPU should be power gated here
+
+	/* If the CPU didn't power gate above just kill it's clock. */
+
+	mov	r0, r11, lsl #8
+	str	r0, [r7, #348]			@ CLK_CPU_CMPLX_SET
+#endif
+
+	/* If the CPU still isn't dead, just spin here. */
+	b	.
+ENDPROC(__tegra_cpu_reset_handler)
+
+	.align L1_CACHE_SHIFT
+	.type	__tegra_cpu_reset_handler_data, %object
+	.globl	__tegra_cpu_reset_handler_data
+__tegra_cpu_reset_handler_data:
+	.rept	TEGRA_RESET_DATA_SIZE
+	.long	0
+	.endr
+	.align L1_CACHE_SHIFT
+
+ENTRY(__tegra_cpu_reset_handler_end)
diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c
index f329404..d8dc9dd 100644
--- a/arch/arm/mach-tegra/hotplug.c
+++ b/arch/arm/mach-tegra/hotplug.c
@@ -13,6 +13,7 @@
 #include <linux/smp.h>
 
 #include <asm/cacheflush.h>
+#include <asm/cp15.h>
 
 static inline void cpu_enter_lowpower(void)
 {
diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h
index fc3ecb6..d97e403 100644
--- a/arch/arm/mach-tegra/include/mach/clk.h
+++ b/arch/arm/mach-tegra/include/mach/clk.h
@@ -22,10 +22,20 @@
 
 struct clk;
 
+enum tegra_clk_ex_param {
+	TEGRA_CLK_VI_INP_SEL,
+	TEGRA_CLK_DTV_INVERT,
+	TEGRA_CLK_NAND_PAD_DIV2_ENB,
+	TEGRA_CLK_PLLD_CSI_OUT_ENB,
+	TEGRA_CLK_PLLD_DSI_OUT_ENB,
+	TEGRA_CLK_PLLD_MIPI_MUX_SEL,
+};
+
 void tegra_periph_reset_deassert(struct clk *c);
 void tegra_periph_reset_assert(struct clk *c);
 
 unsigned long clk_get_rate_all_locked(struct clk *c);
 void tegra2_sdmmc_tap_delay(struct clk *c, int delay);
+int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting);
 
 #endif
diff --git a/arch/arm/mach-tegra/include/mach/debug-macro.S b/arch/arm/mach-tegra/include/mach/debug-macro.S
index 619abc6..8ce0661 100644
--- a/arch/arm/mach-tegra/include/mach/debug-macro.S
+++ b/arch/arm/mach-tegra/include/mach/debug-macro.S
@@ -1,11 +1,17 @@
 /*
  * arch/arm/mach-tegra/include/mach/debug-macro.S
  *
- * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2010,2011 Google, Inc.
+ * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved.
  *
  * Author:
  *	Colin Cross <ccross@google.com>
  *	Erik Gilling <konkers@google.com>
+ *	Doug Anderson <dianders@chromium.org>
+ *	Stephen Warren <swarren@nvidia.com>
+ *
+ * Portions based on mach-omap2's debug-macro.S
+ * Copyright (C) 1994-1999 Russell King
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -18,18 +24,77 @@
  *
  */
 
-#include <mach/io.h>
+#include <linux/serial_reg.h>
+
 #include <mach/iomap.h>
+#include <mach/irammap.h>
 
-	.macro  addruart, rp, rv, tmp
-        ldr     \rp, =IO_APB_PHYS       @ physical
-        ldr     \rv, =IO_APB_VIRT        @ virtual
-	orr	\rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF)
-	orr	\rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF00)
-	orr	\rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF)
-	orr	\rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF00)
-	.endm
+		.macro  addruart, rp, rv, tmp
+		adr	\rp, 99f		@ actual addr of 99f
+		ldr	\rv, [\rp]		@ linked addr is stored there
+		sub	\rv, \rv, \rp		@ offset between the two
+		ldr	\rp, [\rp, #4]		@ linked tegra_uart_config
+		sub	\tmp, \rp, \rv		@ actual tegra_uart_config
+		ldr	\rp, [\tmp]		@ Load tegra_uart_config
+		cmp	\rp, #1			@ needs intitialization?
+		bne	100f			@ no; go load the addresses
+		mov	\rv, #0			@ yes; record init is done
+		str	\rv, [\tmp]
+		mov	\rp, #TEGRA_IRAM_BASE	@ See if cookie is in IRAM
+		ldr	\rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET]
+		movw	\rp, #TEGRA_IRAM_DEBUG_UART_COOKIE & 0xffff
+		movt	\rp, #TEGRA_IRAM_DEBUG_UART_COOKIE >> 16
+		cmp	\rv, \rp		@ Cookie present?
+		bne	100f			@ No, use default UART
+		mov	\rp, #TEGRA_IRAM_BASE	@ Load UART address from IRAM
+		ldr	\rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET + 4]
+		str	\rv, [\tmp, #4]		@ Store in tegra_uart_phys
+		sub	\rv, \rv, #IO_APB_PHYS	@ Calculate virt address
+		add	\rv, \rv, #IO_APB_VIRT
+		str	\rv, [\tmp, #8]		@ Store in tegra_uart_virt
+		b	100f
 
-#define UART_SHIFT	2
-#include <asm/hardware/debug-8250.S>
+		.align
+99:		.word	.
+		.word	tegra_uart_config
+		.ltorg
 
+100:		ldr	\rp, [\tmp, #4]		@ Load tegra_uart_phys
+		ldr	\rv, [\tmp, #8]		@ Load tegra_uart_virt
+		.endm
+
+#define UART_SHIFT 2
+
+/*
+ * Code below is swiped from <asm/hardware/debug-8250.S>, but add an extra
+ * check to make sure that we aren't in the CONFIG_TEGRA_DEBUG_UART_NONE case.
+ * We use the fact that all 5 valid UART addresses all have something in the
+ * 2nd-to-lowest byte.
+ */
+
+		.macro	senduart, rd, rx
+		tst	\rx, #0x0000ff00
+		strneb	\rd, [\rx, #UART_TX << UART_SHIFT]
+1001:
+		.endm
+
+		.macro	busyuart, rd, rx
+		tst	\rx, #0x0000ff00
+		beq	1002f
+1001:		ldrb	\rd, [\rx, #UART_LSR << UART_SHIFT]
+		and	\rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
+		teq	\rd, #UART_LSR_TEMT | UART_LSR_THRE
+		bne	1001b
+1002:
+		.endm
+
+		.macro	waituart, rd, rx
+#ifdef FLOW_CONTROL
+		tst	\rx, #0x0000ff00
+		beq	1002f
+1001:		ldrb	\rd, [\rx, #UART_MSR << UART_SHIFT]
+		tst	\rd, #UART_MSR_CTS
+		beq	1001b
+1002:
+#endif
+		.endm
diff --git a/arch/arm/mach-tegra/include/mach/entry-macro.S b/arch/arm/mach-tegra/include/mach/entry-macro.S
deleted file mode 100644
index e577cfe..0000000
--- a/arch/arm/mach-tegra/include/mach/entry-macro.S
+++ /dev/null
@@ -1,20 +0,0 @@
-/* arch/arm/mach-tegra/include/mach/entry-macro.S
- *
- * Copyright (C) 2009 Palm, 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.
- *
- */
-
-	.macro	disable_fiq
-	.endm
-
-	.macro	arch_ret_to_user, tmp1, tmp2
-	.endm
diff --git a/arch/arm/mach-tegra/include/mach/gpio-tegra.h b/arch/arm/mach-tegra/include/mach/gpio-tegra.h
index 87d37fd..6140820 100644
--- a/arch/arm/mach-tegra/include/mach/gpio-tegra.h
+++ b/arch/arm/mach-tegra/include/mach/gpio-tegra.h
@@ -25,8 +25,6 @@
 
 #define TEGRA_NR_GPIOS		INT_GPIO_NR
 
-#define TEGRA_GPIO_TO_IRQ(gpio) (INT_GPIO_BASE + (gpio))
-
 struct tegra_gpio_table {
 	int	gpio;	/* GPIO number */
 	bool	enable;	/* Enable for GPIO at init? */
diff --git a/arch/arm/mach-tegra/include/mach/io.h b/arch/arm/mach-tegra/include/mach/io.h
index f15deff..fe700f9 100644
--- a/arch/arm/mach-tegra/include/mach/io.h
+++ b/arch/arm/mach-tegra/include/mach/io.h
@@ -23,56 +23,8 @@
 
 #define IO_SPACE_LIMIT 0xffff
 
-/* On TEGRA, many peripherals are very closely packed in
- * two 256MB io windows (that actually only use about 64KB
- * at the start of each).
- *
- * We will just map the first 1MB of each window (to minimize
- * pt entries needed) and provide a macro to transform physical
- * io addresses to an appropriate void __iomem *.
- *
- */
-
-#ifdef __ASSEMBLY__
-#define IOMEM(x)	(x)
-#else
-#define IOMEM(x)	((void __force __iomem *)(x))
-#endif
-
-#define IO_IRAM_PHYS	0x40000000
-#define IO_IRAM_VIRT	IOMEM(0xFE400000)
-#define IO_IRAM_SIZE	SZ_256K
-
-#define IO_CPU_PHYS     0x50040000
-#define IO_CPU_VIRT     IOMEM(0xFE000000)
-#define IO_CPU_SIZE	SZ_16K
-
-#define IO_PPSB_PHYS	0x60000000
-#define IO_PPSB_VIRT	IOMEM(0xFE200000)
-#define IO_PPSB_SIZE	SZ_1M
-
-#define IO_APB_PHYS	0x70000000
-#define IO_APB_VIRT	IOMEM(0xFE300000)
-#define IO_APB_SIZE	SZ_1M
-
-#define IO_TO_VIRT_BETWEEN(p, st, sz)	((p) >= (st) && (p) < ((st) + (sz)))
-#define IO_TO_VIRT_XLATE(p, pst, vst)	(((p) - (pst) + (vst)))
-
-#define IO_TO_VIRT(n) ( \
-	IO_TO_VIRT_BETWEEN((n), IO_PPSB_PHYS, IO_PPSB_SIZE) ?		\
-		IO_TO_VIRT_XLATE((n), IO_PPSB_PHYS, IO_PPSB_VIRT) :	\
-	IO_TO_VIRT_BETWEEN((n), IO_APB_PHYS, IO_APB_SIZE) ?		\
-		IO_TO_VIRT_XLATE((n), IO_APB_PHYS, IO_APB_VIRT) :	\
-	IO_TO_VIRT_BETWEEN((n), IO_CPU_PHYS, IO_CPU_SIZE) ?		\
-		IO_TO_VIRT_XLATE((n), IO_CPU_PHYS, IO_CPU_VIRT) :	\
-	IO_TO_VIRT_BETWEEN((n), IO_IRAM_PHYS, IO_IRAM_SIZE) ?		\
-		IO_TO_VIRT_XLATE((n), IO_IRAM_PHYS, IO_IRAM_VIRT) :	\
-	NULL)
-
 #ifndef __ASSEMBLER__
 
-#define IO_ADDRESS(n) (IO_TO_VIRT(n))
-
 #ifdef CONFIG_TEGRA_PCI
 extern void __iomem *tegra_pcie_io_base;
 
@@ -88,7 +40,6 @@
 #endif
 
 #define __io(a)         __io(a)
-#define __mem_pci(a)    (a)
 
 #endif
 
diff --git a/arch/arm/mach-tegra/include/mach/iomap.h b/arch/arm/mach-tegra/include/mach/iomap.h
index 19dec3a..7e76da7 100644
--- a/arch/arm/mach-tegra/include/mach/iomap.h
+++ b/arch/arm/mach-tegra/include/mach/iomap.h
@@ -74,6 +74,9 @@
 #define TEGRA_QUATERNARY_ICTLR_BASE	0x60004300
 #define TEGRA_QUATERNARY_ICTLR_SIZE	SZ_64
 
+#define TEGRA_QUINARY_ICTLR_BASE	0x60004400
+#define TEGRA_QUINARY_ICTLR_SIZE	SZ_64
+
 #define TEGRA_TMR1_BASE			0x60005000
 #define TEGRA_TMR1_SIZE			SZ_8
 
@@ -110,6 +113,9 @@
 #define TEGRA_AHB_GIZMO_BASE		0x6000C004
 #define TEGRA_AHB_GIZMO_SIZE		0x10C
 
+#define TEGRA_SB_BASE			0x6000C200
+#define TEGRA_SB_SIZE			256
+
 #define TEGRA_STATMON_BASE		0x6000C400
 #define TEGRA_STATMON_SIZE		SZ_1K
 
@@ -271,4 +277,46 @@
 # define TEGRA_DEBUG_UART_BASE TEGRA_UARTE_BASE
 #endif
 
+/* On TEGRA, many peripherals are very closely packed in
+ * two 256MB io windows (that actually only use about 64KB
+ * at the start of each).
+ *
+ * We will just map the first 1MB of each window (to minimize
+ * pt entries needed) and provide a macro to transform physical
+ * io addresses to an appropriate void __iomem *.
+ *
+ */
+
+#define IO_IRAM_PHYS	0x40000000
+#define IO_IRAM_VIRT	IOMEM(0xFE400000)
+#define IO_IRAM_SIZE	SZ_256K
+
+#define IO_CPU_PHYS     0x50040000
+#define IO_CPU_VIRT     IOMEM(0xFE000000)
+#define IO_CPU_SIZE	SZ_16K
+
+#define IO_PPSB_PHYS	0x60000000
+#define IO_PPSB_VIRT	IOMEM(0xFE200000)
+#define IO_PPSB_SIZE	SZ_1M
+
+#define IO_APB_PHYS	0x70000000
+#define IO_APB_VIRT	IOMEM(0xFE300000)
+#define IO_APB_SIZE	SZ_1M
+
+#define IO_TO_VIRT_BETWEEN(p, st, sz)	((p) >= (st) && (p) < ((st) + (sz)))
+#define IO_TO_VIRT_XLATE(p, pst, vst)	(((p) - (pst) + (vst)))
+
+#define IO_TO_VIRT(n) ( \
+	IO_TO_VIRT_BETWEEN((n), IO_PPSB_PHYS, IO_PPSB_SIZE) ?		\
+		IO_TO_VIRT_XLATE((n), IO_PPSB_PHYS, IO_PPSB_VIRT) :	\
+	IO_TO_VIRT_BETWEEN((n), IO_APB_PHYS, IO_APB_SIZE) ?		\
+		IO_TO_VIRT_XLATE((n), IO_APB_PHYS, IO_APB_VIRT) :	\
+	IO_TO_VIRT_BETWEEN((n), IO_CPU_PHYS, IO_CPU_SIZE) ?		\
+		IO_TO_VIRT_XLATE((n), IO_CPU_PHYS, IO_CPU_VIRT) :	\
+	IO_TO_VIRT_BETWEEN((n), IO_IRAM_PHYS, IO_IRAM_SIZE) ?		\
+		IO_TO_VIRT_XLATE((n), IO_IRAM_PHYS, IO_IRAM_VIRT) :	\
+	NULL)
+
+#define IO_ADDRESS(n) (IO_TO_VIRT(n))
+
 #endif
diff --git a/arch/arm/mach-tegra/include/mach/irammap.h b/arch/arm/mach-tegra/include/mach/irammap.h
new file mode 100644
index 0000000..0cbe632
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/irammap.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MACH_TEGRA_IRAMMAP_H
+#define __MACH_TEGRA_IRAMMAP_H
+
+#include <asm/sizes.h>
+
+/* The first 1K of IRAM is permanently reserved for the CPU reset handler */
+#define TEGRA_IRAM_RESET_HANDLER_OFFSET	0
+#define TEGRA_IRAM_RESET_HANDLER_SIZE	SZ_1K
+
+/*
+ * These locations are written to by uncompress.h, and read by debug-macro.S.
+ * The first word holds the cookie value if the data is valid. The second
+ * word holds the UART physical address.
+ */
+#define TEGRA_IRAM_DEBUG_UART_OFFSET	SZ_1K
+#define TEGRA_IRAM_DEBUG_UART_SIZE	8
+#define TEGRA_IRAM_DEBUG_UART_COOKIE	0x55415254
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/irqs.h b/arch/arm/mach-tegra/include/mach/irqs.h
index a2146cd..aad1a2c 100644
--- a/arch/arm/mach-tegra/include/mach/irqs.h
+++ b/arch/arm/mach-tegra/include/mach/irqs.h
@@ -165,11 +165,12 @@
 #define INT_QUAD_RES_30			(INT_QUAD_BASE + 30)
 #define INT_QUAD_RES_31			(INT_QUAD_BASE + 31)
 
-#define INT_MAIN_NR			(INT_QUAD_BASE + 32 - INT_PRI_BASE)
-
+/* Tegra30 has 5 banks of 32 IRQs */
+#define INT_MAIN_NR			(32 * 5)
 #define INT_GPIO_BASE			(INT_PRI_BASE + INT_MAIN_NR)
 
-#define INT_GPIO_NR			(28 * 8)
+/* Tegra30 has 8 banks of 32 GPIOs */
+#define INT_GPIO_NR			(32 * 8)
 
 #define TEGRA_NR_IRQS			(INT_GPIO_BASE + INT_GPIO_NR)
 
diff --git a/arch/arm/mach-tegra/include/mach/kbc.h b/arch/arm/mach-tegra/include/mach/kbc.h
index 20bb054..a130256 100644
--- a/arch/arm/mach-tegra/include/mach/kbc.h
+++ b/arch/arm/mach-tegra/include/mach/kbc.h
@@ -24,20 +24,21 @@
 #include <linux/types.h>
 #include <linux/input/matrix_keypad.h>
 
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
 #define KBC_MAX_GPIO	24
 #define KBC_MAX_KPENT	8
-#else
-#define KBC_MAX_GPIO	20
-#define KBC_MAX_KPENT	7
-#endif
 
 #define KBC_MAX_ROW	16
 #define KBC_MAX_COL	8
 #define KBC_MAX_KEY	(KBC_MAX_ROW * KBC_MAX_COL)
 
+enum tegra_pin_type {
+	PIN_CFG_IGNORE,
+	PIN_CFG_COL,
+	PIN_CFG_ROW,
+};
+
 struct tegra_kbc_pin_cfg {
-	bool is_row;
+	enum tegra_pin_type type;
 	unsigned char num;
 };
 
diff --git a/arch/arm/mach-tegra/include/mach/pinconf-tegra.h b/arch/arm/mach-tegra/include/mach/pinconf-tegra.h
new file mode 100644
index 0000000..1f24d30
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/pinconf-tegra.h
@@ -0,0 +1,63 @@
+/*
+ * pinctrl configuration definitions for the NVIDIA Tegra pinmux
+ *
+ * Copyright (c) 2011, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __PINCONF_TEGRA_H__
+#define __PINCONF_TEGRA_H__
+
+enum tegra_pinconf_param {
+	/* argument: tegra_pinconf_pull */
+	TEGRA_PINCONF_PARAM_PULL,
+	/* argument: tegra_pinconf_tristate */
+	TEGRA_PINCONF_PARAM_TRISTATE,
+	/* argument: Boolean */
+	TEGRA_PINCONF_PARAM_ENABLE_INPUT,
+	/* argument: Boolean */
+	TEGRA_PINCONF_PARAM_OPEN_DRAIN,
+	/* argument: Boolean */
+	TEGRA_PINCONF_PARAM_LOCK,
+	/* argument: Boolean */
+	TEGRA_PINCONF_PARAM_IORESET,
+	/* argument: Boolean */
+	TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE,
+	/* argument: Boolean */
+	TEGRA_PINCONF_PARAM_SCHMITT,
+	/* argument: Boolean */
+	TEGRA_PINCONF_PARAM_LOW_POWER_MODE,
+	/* argument: Integer, range is HW-dependant */
+	TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH,
+	/* argument: Integer, range is HW-dependant */
+	TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH,
+	/* argument: Integer, range is HW-dependant */
+	TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING,
+	/* argument: Integer, range is HW-dependant */
+	TEGRA_PINCONF_PARAM_SLEW_RATE_RISING,
+};
+
+enum tegra_pinconf_pull {
+	TEGRA_PINCONFIG_PULL_NONE,
+	TEGRA_PINCONFIG_PULL_DOWN,
+	TEGRA_PINCONFIG_PULL_UP,
+};
+
+enum tegra_pinconf_tristate {
+	TEGRA_PINCONFIG_DRIVEN,
+	TEGRA_PINCONFIG_TRISTATE,
+};
+
+#define TEGRA_PINCONF_PACK(_param_, _arg_) ((_param_) << 16 | (_arg_))
+#define TEGRA_PINCONF_UNPACK_PARAM(_conf_) ((_conf_) >> 16)
+#define TEGRA_PINCONF_UNPACK_ARG(_conf_) ((_conf_) & 0xffff)
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/powergate.h b/arch/arm/mach-tegra/include/mach/powergate.h
index 39c396d..4752b1a68 100644
--- a/arch/arm/mach-tegra/include/mach/powergate.h
+++ b/arch/arm/mach-tegra/include/mach/powergate.h
@@ -27,8 +27,21 @@
 #define TEGRA_POWERGATE_VDEC	4
 #define TEGRA_POWERGATE_L2	5
 #define TEGRA_POWERGATE_MPE	6
-#define TEGRA_NUM_POWERGATE	7
+#define TEGRA_POWERGATE_HEG	7
+#define TEGRA_POWERGATE_SATA	8
+#define TEGRA_POWERGATE_CPU1	9
+#define TEGRA_POWERGATE_CPU2	10
+#define TEGRA_POWERGATE_CPU3	11
+#define TEGRA_POWERGATE_CELP	12
+#define TEGRA_POWERGATE_3D1	13
 
+#define TEGRA_POWERGATE_CPU0	TEGRA_POWERGATE_CPU
+#define TEGRA_POWERGATE_3D0	TEGRA_POWERGATE_3D
+
+int  __init tegra_powergate_init(void);
+
+int tegra_cpu_powergate_id(int cpuid);
+int tegra_powergate_is_powered(int id);
 int tegra_powergate_power_on(int id);
 int tegra_powergate_power_off(int id);
 int tegra_powergate_remove_clamping(int id);
diff --git a/arch/arm/mach-tegra/include/mach/smmu.h b/arch/arm/mach-tegra/include/mach/smmu.h
new file mode 100644
index 0000000..dad403a
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/smmu.h
@@ -0,0 +1,63 @@
+/*
+ * IOMMU API for SMMU in Tegra30
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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	MACH_SMMU_H
+#define	MACH_SMMU_H
+
+enum smmu_hwgrp {
+	HWGRP_AFI,
+	HWGRP_AVPC,
+	HWGRP_DC,
+	HWGRP_DCB,
+	HWGRP_EPP,
+	HWGRP_G2,
+	HWGRP_HC,
+	HWGRP_HDA,
+	HWGRP_ISP,
+	HWGRP_MPE,
+	HWGRP_NV,
+	HWGRP_NV2,
+	HWGRP_PPCS,
+	HWGRP_SATA,
+	HWGRP_VDE,
+	HWGRP_VI,
+
+	HWGRP_COUNT,
+
+	HWGRP_END = ~0,
+};
+
+#define HWG_AFI		(1 << HWGRP_AFI)
+#define HWG_AVPC	(1 << HWGRP_AVPC)
+#define HWG_DC		(1 << HWGRP_DC)
+#define HWG_DCB		(1 << HWGRP_DCB)
+#define HWG_EPP		(1 << HWGRP_EPP)
+#define HWG_G2		(1 << HWGRP_G2)
+#define HWG_HC		(1 << HWGRP_HC)
+#define HWG_HDA		(1 << HWGRP_HDA)
+#define HWG_ISP		(1 << HWGRP_ISP)
+#define HWG_MPE		(1 << HWGRP_MPE)
+#define HWG_NV		(1 << HWGRP_NV)
+#define HWG_NV2		(1 << HWGRP_NV2)
+#define HWG_PPCS	(1 << HWGRP_PPCS)
+#define HWG_SATA	(1 << HWGRP_SATA)
+#define HWG_VDE		(1 << HWGRP_VDE)
+#define HWG_VI		(1 << HWGRP_VI)
+
+#endif	/* MACH_SMMU_H */
diff --git a/arch/arm/mach-tegra/include/mach/system.h b/arch/arm/mach-tegra/include/mach/system.h
deleted file mode 100644
index a312988..0000000
--- a/arch/arm/mach-tegra/include/mach/system.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * arch/arm/mach-tegra/include/mach/system.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- *	Colin Cross <ccross@google.com>
- *	Erik Gilling <konkers@google.com>
- *
- * 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 __MACH_TEGRA_SYSTEM_H
-#define __MACH_TEGRA_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-}
-
-#endif
diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h
index 4e83237..5a440f3 100644
--- a/arch/arm/mach-tegra/include/mach/uncompress.h
+++ b/arch/arm/mach-tegra/include/mach/uncompress.h
@@ -2,10 +2,14 @@
  * arch/arm/mach-tegra/include/mach/uncompress.h
  *
  * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved.
  *
  * Author:
  *	Colin Cross <ccross@google.com>
  *	Erik Gilling <konkers@google.com>
+ *	Doug Anderson <dianders@chromium.org>
+ *	Stephen Warren <swarren@nvidia.com>
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -25,36 +29,130 @@
 #include <linux/serial_reg.h>
 
 #include <mach/iomap.h>
+#include <mach/irammap.h>
+
+#define BIT(x) (1 << (x))
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+#define DEBUG_UART_SHIFT 2
+
+volatile u8 *uart;
 
 static void putc(int c)
 {
-	volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
-	int shift = 2;
-
 	if (uart == NULL)
 		return;
 
-	while (!(uart[UART_LSR << shift] & UART_LSR_THRE))
+	while (!(uart[UART_LSR << DEBUG_UART_SHIFT] & UART_LSR_THRE))
 		barrier();
-	uart[UART_TX << shift] = c;
+	uart[UART_TX << DEBUG_UART_SHIFT] = c;
 }
 
 static inline void flush(void)
 {
 }
 
+static inline void save_uart_address(void)
+{
+	u32 *buf = (u32 *)(TEGRA_IRAM_BASE + TEGRA_IRAM_DEBUG_UART_OFFSET);
+
+	if (uart) {
+		buf[0] = TEGRA_IRAM_DEBUG_UART_COOKIE;
+		buf[1] = (u32)uart;
+	} else
+		buf[0] = 0;
+}
+
+/*
+ * Setup before decompression.  This is where we do UART selection for
+ * earlyprintk and init the uart_base register.
+ */
 static inline void arch_decomp_setup(void)
 {
-	volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
-	int shift = 2;
+	static const struct {
+		u32 base;
+		u32 reset_reg;
+		u32 clock_reg;
+		u32 bit;
+	} uarts[] = {
+		{
+			TEGRA_UARTA_BASE,
+			TEGRA_CLK_RESET_BASE + 0x04,
+			TEGRA_CLK_RESET_BASE + 0x10,
+			6,
+		},
+		{
+			TEGRA_UARTB_BASE,
+			TEGRA_CLK_RESET_BASE + 0x04,
+			TEGRA_CLK_RESET_BASE + 0x10,
+			7,
+		},
+		{
+			TEGRA_UARTC_BASE,
+			TEGRA_CLK_RESET_BASE + 0x08,
+			TEGRA_CLK_RESET_BASE + 0x14,
+			23,
+		},
+		{
+			TEGRA_UARTD_BASE,
+			TEGRA_CLK_RESET_BASE + 0x0c,
+			TEGRA_CLK_RESET_BASE + 0x18,
+			1,
+		},
+		{
+			TEGRA_UARTE_BASE,
+			TEGRA_CLK_RESET_BASE + 0x0c,
+			TEGRA_CLK_RESET_BASE + 0x18,
+			2,
+		},
+	};
+	int i;
+	volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE;
+	u32 chip, div;
 
+	/*
+	 * Look for the first UART that:
+	 * a) Is not in reset.
+	 * b) Is clocked.
+	 * c) Has a 'D' in the scratchpad register.
+	 *
+	 * Note that on Tegra30, the first two conditions are required, since
+	 * if not true, accesses to the UART scratch register will hang.
+	 * Tegra20 doesn't have this issue.
+	 *
+	 * The intent is that the bootloader will tell the kernel which UART
+	 * to use by setting up those conditions. If nothing found, we'll fall
+	 * back to what's specified in TEGRA_DEBUG_UART_BASE.
+	 */
+	for (i = 0; i < ARRAY_SIZE(uarts); i++) {
+		if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit))
+			continue;
+
+		if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit)))
+			continue;
+
+		uart = (volatile u8 *)uarts[i].base;
+		if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D')
+			continue;
+
+		break;
+	}
+	if (i == ARRAY_SIZE(uarts))
+		uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
+	save_uart_address();
 	if (uart == NULL)
 		return;
 
-	uart[UART_LCR << shift] |= UART_LCR_DLAB;
-	uart[UART_DLL << shift] = 0x75;
-	uart[UART_DLM << shift] = 0x0;
-	uart[UART_LCR << shift] = 3;
+	chip = (apb_misc[0x804 / 4] >> 8) & 0xff;
+	if (chip == 0x20)
+		div = 0x0075;
+	else
+		div = 0x00dd;
+
+	uart[UART_LCR << DEBUG_UART_SHIFT] |= UART_LCR_DLAB;
+	uart[UART_DLL << DEBUG_UART_SHIFT] = div & 0xff;
+	uart[UART_DLM << DEBUG_UART_SHIFT] = div >> 8;
+	uart[UART_LCR << DEBUG_UART_SHIFT] = 3;
 }
 
 static inline void arch_decomp_wdog(void)
diff --git a/arch/arm/mach-tegra/io.c b/arch/arm/mach-tegra/io.c
index d23ee2d..58b4baf 100644
--- a/arch/arm/mach-tegra/io.c
+++ b/arch/arm/mach-tegra/io.c
@@ -26,6 +26,7 @@
 
 #include <asm/page.h>
 #include <asm/mach/map.h>
+#include <mach/iomap.h>
 
 #include "board.h"
 
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
index 4e1afcd..2f5bd2d 100644
--- a/arch/arm/mach-tegra/irq.c
+++ b/arch/arm/mach-tegra/irq.c
@@ -44,14 +44,16 @@
 #define ICTLR_COP_IER_CLR	0x38
 #define ICTLR_COP_IEP_CLASS	0x3c
 
-#define NUM_ICTLRS 4
 #define FIRST_LEGACY_IRQ 32
 
+static int num_ictlrs;
+
 static void __iomem *ictlr_reg_base[] = {
 	IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE),
 	IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE),
 	IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE),
 	IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE),
+	IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE),
 };
 
 static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg)
@@ -60,7 +62,7 @@
 	u32 mask;
 
 	BUG_ON(irq < FIRST_LEGACY_IRQ ||
-		irq >= FIRST_LEGACY_IRQ + NUM_ICTLRS * 32);
+		irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32);
 
 	base = ictlr_reg_base[(irq - FIRST_LEGACY_IRQ) / 32];
 	mask = BIT((irq - FIRST_LEGACY_IRQ) % 32);
@@ -113,8 +115,18 @@
 void __init tegra_init_irq(void)
 {
 	int i;
+	void __iomem *distbase;
 
-	for (i = 0; i < NUM_ICTLRS; i++) {
+	distbase = IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE);
+	num_ictlrs = readl_relaxed(distbase + GIC_DIST_CTR) & 0x1f;
+
+	if (num_ictlrs > ARRAY_SIZE(ictlr_reg_base)) {
+		WARN(1, "Too many (%d) interrupt controllers found. Maximum is %d.",
+			num_ictlrs, ARRAY_SIZE(ictlr_reg_base));
+		num_ictlrs = ARRAY_SIZE(ictlr_reg_base);
+	}
+
+	for (i = 0; i < num_ictlrs; i++) {
 		void __iomem *ictlr = ictlr_reg_base[i];
 		writel(~0, ictlr + ICTLR_CPU_IER_CLR);
 		writel(0, ictlr + ICTLR_CPU_IEP_CLASS);
@@ -131,6 +143,6 @@
 	 * initialized elsewhere under DT.
 	 */
 	if (!of_have_populated_dt())
-		gic_init(0, 29, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE),
+		gic_init(0, 29, distbase,
 			IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
 }
diff --git a/arch/arm/mach-tegra/localtimer.c b/arch/arm/mach-tegra/localtimer.c
deleted file mode 100644
index e91d681..0000000
--- a/arch/arm/mach-tegra/localtimer.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  arch/arm/mach-tegra/localtimer.c
- *
- *  Copyright (C) 2002 ARM Ltd.
- *  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/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-#include <asm/irq.h>
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	evt->irq = IRQ_LOCALTIMER;
-	twd_timer_setup(evt);
-	return 0;
-}
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index af8b634..54a816f 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -408,7 +408,7 @@
 	pp->res[0].flags = IORESOURCE_IO;
 	if (request_resource(&ioport_resource, &pp->res[0]))
 		panic("Request PCIe IO resource failed\n");
-	pci_add_resource(&sys->resources, &pp->res[0]);
+	pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
 
 	/*
 	 * IORESOURCE_MEM
@@ -427,7 +427,7 @@
 	pp->res[1].flags = IORESOURCE_MEM;
 	if (request_resource(&iomem_resource, &pp->res[1]))
 		panic("Request PCIe Memory resource failed\n");
-	pci_add_resource(&sys->resources, &pp->res[1]);
+	pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
 
 	/*
 	 * IORESOURCE_MEM | IORESOURCE_PREFETCH
@@ -446,7 +446,7 @@
 	pp->res[2].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
 	if (request_resource(&iomem_resource, &pp->res[2]))
 		panic("Request PCIe Prefetch Memory resource failed\n");
-	pci_add_resource(&sys->resources, &pp->res[2]);
+	pci_add_resource_offset(&sys->resources, &pp->res[2], sys->mem_offset);
 
 	return 1;
 }
@@ -585,10 +585,10 @@
 	afi_writel(0, AFI_MSI_BAR_SZ);
 }
 
-static void tegra_pcie_enable_controller(void)
+static int tegra_pcie_enable_controller(void)
 {
 	u32 val, reg;
-	int i;
+	int i, timeout;
 
 	/* Enable slot clock and pulse the reset signals */
 	for (i = 0, reg = AFI_PEX0_CTRL; i < 2; i++, reg += 0x8) {
@@ -639,8 +639,14 @@
 	pads_writel(0xfa5cfa5c, 0xc8);
 
 	/* Wait for the PLL to lock */
+	timeout = 300;
 	do {
 		val = pads_readl(PADS_PLL_CTL);
+		usleep_range(1000, 1000);
+		if (--timeout == 0) {
+			pr_err("Tegra PCIe error: timeout waiting for PLL\n");
+			return -EBUSY;
+		}
 	} while (!(val & PADS_PLL_CTL_LOCKDET));
 
 	/* turn off IDDQ override */
@@ -671,7 +677,7 @@
 	/* Disable all execptions */
 	afi_writel(0, AFI_FPCI_ERROR_MASKS);
 
-	return;
+	return 0;
 }
 
 static void tegra_pcie_xclk_clamp(bool clamp)
@@ -921,7 +927,9 @@
 	if (err)
 		return err;
 
-	tegra_pcie_enable_controller();
+	err = tegra_pcie_enable_controller();
+	if (err)
+		return err;
 
 	/* setup the AFI address translations */
 	tegra_pcie_setup_translations();
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 7d2b5d0..1a208db 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -24,19 +24,31 @@
 #include <asm/mach-types.h>
 #include <asm/smp_scu.h>
 
+#include <mach/clk.h>
 #include <mach/iomap.h>
+#include <mach/powergate.h>
+
+#include "fuse.h"
+#include "flowctrl.h"
+#include "reset.h"
 
 extern void tegra_secondary_startup(void);
 
-static DEFINE_SPINLOCK(boot_lock);
 static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE);
 
 #define EVP_CPU_RESET_VECTOR \
 	(IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100)
 #define CLK_RST_CONTROLLER_CLK_CPU_CMPLX \
 	(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x4c)
+#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET \
+	(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x340)
 #define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR \
 	(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x344)
+#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR \
+	(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x34c)
+
+#define CPU_CLOCK(cpu)	(0x1<<(8+cpu))
+#define CPU_RESET(cpu)	(0x1111ul<<(cpu))
 
 void __cpuinit platform_secondary_init(unsigned int cpu)
 {
@@ -47,63 +59,106 @@
 	 */
 	gic_secondary_init(0);
 
-	/*
-	 * Synchronise with the boot thread.
-	 */
-	spin_lock(&boot_lock);
-	spin_unlock(&boot_lock);
+}
+
+static int tegra20_power_up_cpu(unsigned int cpu)
+{
+	u32 reg;
+
+	/* Enable the CPU clock. */
+	reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+	writel(reg & ~CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+	barrier();
+	reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+
+	/* Clear flow controller CSR. */
+	flowctrl_write_cpu_csr(cpu, 0);
+
+	return 0;
+}
+
+static int tegra30_power_up_cpu(unsigned int cpu)
+{
+	u32 reg;
+	int ret, pwrgateid;
+	unsigned long timeout;
+
+	pwrgateid = tegra_cpu_powergate_id(cpu);
+	if (pwrgateid < 0)
+		return pwrgateid;
+
+	/* If this is the first boot, toggle powergates directly. */
+	if (!tegra_powergate_is_powered(pwrgateid)) {
+		ret = tegra_powergate_power_on(pwrgateid);
+		if (ret)
+			return ret;
+
+		/* Wait for the power to come up. */
+		timeout = jiffies + 10*HZ;
+		while (tegra_powergate_is_powered(pwrgateid)) {
+			if (time_after(jiffies, timeout))
+				return -ETIMEDOUT;
+			udelay(10);
+		}
+	}
+
+	/* CPU partition is powered. Enable the CPU clock. */
+	writel(CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
+	reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
+	udelay(10);
+
+	/* Remove I/O clamps. */
+	ret = tegra_powergate_remove_clamping(pwrgateid);
+	udelay(10);
+
+	/* Clear flow controller CSR. */
+	flowctrl_write_cpu_csr(cpu, 0);
+
+	return 0;
 }
 
 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
-	unsigned long old_boot_vector;
-	unsigned long boot_vector;
-	unsigned long timeout;
-	u32 reg;
+	int status;
 
 	/*
-	 * set synchronisation state between this boot processor
-	 * and the secondary one
+	 * Force the CPU into reset. The CPU must remain in reset when the
+	 * flow controller state is cleared (which will cause the flow
+	 * controller to stop driving reset if the CPU has been power-gated
+	 * via the flow controller). This will have no effect on first boot
+	 * of the CPU since it should already be in reset.
 	 */
-	spin_lock(&boot_lock);
+	writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
+	dmb();
 
+	/*
+	 * Unhalt the CPU. If the flow controller was used to power-gate the
+	 * CPU this will cause the flow controller to stop driving reset.
+	 * The CPU will remain in reset because the clock and reset block
+	 * is now driving reset.
+	 */
+	flowctrl_write_cpu_halt(cpu, 0);
 
-	/* set the reset vector to point to the secondary_startup routine */
-
-	boot_vector = virt_to_phys(tegra_secondary_startup);
-	old_boot_vector = readl(EVP_CPU_RESET_VECTOR);
-	writel(boot_vector, EVP_CPU_RESET_VECTOR);
-
-	/* enable cpu clock on cpu1 */
-	reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-	writel(reg & ~(1<<9), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-
-	reg = (1<<13) | (1<<9) | (1<<5) | (1<<1);
-	writel(reg, CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
-
-	smp_wmb();
-	flush_cache_all();
-
-	/* unhalt the cpu */
-	writel(0, IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + 0x14);
-
-	timeout = jiffies + (1 * HZ);
-	while (time_before(jiffies, timeout)) {
-		if (readl(EVP_CPU_RESET_VECTOR) != boot_vector)
-			break;
-		udelay(10);
+	switch (tegra_chip_id) {
+	case TEGRA20:
+		status = tegra20_power_up_cpu(cpu);
+		break;
+	case TEGRA30:
+		status = tegra30_power_up_cpu(cpu);
+		break;
+	default:
+		status = -EINVAL;
+		break;
 	}
 
-	/* put the old boot vector back */
-	writel(old_boot_vector, EVP_CPU_RESET_VECTOR);
+	if (status)
+		goto done;
 
-	/*
-	 * now the secondary core is starting up let it run its
-	 * calibrations, then wait for it to finish
-	 */
-	spin_unlock(&boot_lock);
-
-	return 0;
+	/* Take the CPU out of reset. */
+	writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
+	wmb();
+done:
+	return status;
 }
 
 /*
@@ -128,6 +183,6 @@
 
 void __init platform_smp_prepare_cpus(unsigned int max_cpus)
 {
-
+	tegra_cpu_reset_handler_init();
 	scu_enable(scu_base);
 }
diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c
new file mode 100644
index 0000000..7af6a54
--- /dev/null
+++ b/arch/arm/mach-tegra/pmc.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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/kernel.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <mach/iomap.h>
+
+#define PMC_CTRL		0x0
+#define PMC_CTRL_INTR_LOW	(1 << 17)
+
+static inline u32 tegra_pmc_readl(u32 reg)
+{
+	return readl(IO_ADDRESS(TEGRA_PMC_BASE + reg));
+}
+
+static inline void tegra_pmc_writel(u32 val, u32 reg)
+{
+	writel(val, IO_ADDRESS(TEGRA_PMC_BASE + reg));
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id matches[] __initconst = {
+	{ .compatible = "nvidia,tegra20-pmc" },
+	{ }
+};
+#endif
+
+void __init tegra_pmc_init(void)
+{
+	/*
+	 * For now, Harmony is the only board that uses the PMC, and it wants
+	 * the signal inverted. Seaboard would too if it used the PMC.
+	 * Hopefully by the time other boards want to use the PMC, everything
+	 * will be device-tree, or they also want it inverted.
+	 */
+	bool invert_interrupt = true;
+	u32 val;
+
+#ifdef CONFIG_OF
+	if (of_have_populated_dt()) {
+		struct device_node *np;
+
+		invert_interrupt = false;
+
+		np = of_find_matching_node(NULL, matches);
+		if (np) {
+			if (of_find_property(np, "nvidia,invert-interrupt",
+						NULL))
+				invert_interrupt = true;
+		}
+	}
+#endif
+
+	val = tegra_pmc_readl(PMC_CTRL);
+	if (invert_interrupt)
+		val |= PMC_CTRL_INTR_LOW;
+	else
+		val &= ~PMC_CTRL_INTR_LOW;
+	tegra_pmc_writel(val, PMC_CTRL);
+}
diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h
new file mode 100644
index 0000000..8995ee4
--- /dev/null
+++ b/arch/arm/mach-tegra/pmc.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __MACH_TEGRA_PMC_H
+#define __MACH_TEGRA_PMC_H
+
+void tegra_pmc_init(void);
+
+#endif
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
index 9483064..c238699 100644
--- a/arch/arm/mach-tegra/powergate.c
+++ b/arch/arm/mach-tegra/powergate.c
@@ -31,6 +31,8 @@
 #include <mach/iomap.h>
 #include <mach/powergate.h>
 
+#include "fuse.h"
+
 #define PWRGATE_TOGGLE		0x30
 #define  PWRGATE_TOGGLE_START	(1 << 8)
 
@@ -38,6 +40,16 @@
 
 #define PWRGATE_STATUS		0x38
 
+static int tegra_num_powerdomains;
+static int tegra_num_cpu_domains;
+static u8 *tegra_cpu_domains;
+static u8 tegra30_cpu_domains[] = {
+	TEGRA_POWERGATE_CPU0,
+	TEGRA_POWERGATE_CPU1,
+	TEGRA_POWERGATE_CPU2,
+	TEGRA_POWERGATE_CPU3,
+};
+
 static DEFINE_SPINLOCK(tegra_powergate_lock);
 
 static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
@@ -75,7 +87,7 @@
 
 int tegra_powergate_power_on(int id)
 {
-	if (id < 0 || id >= TEGRA_NUM_POWERGATE)
+	if (id < 0 || id >= tegra_num_powerdomains)
 		return -EINVAL;
 
 	return tegra_powergate_set(id, true);
@@ -83,17 +95,18 @@
 
 int tegra_powergate_power_off(int id)
 {
-	if (id < 0 || id >= TEGRA_NUM_POWERGATE)
+	if (id < 0 || id >= tegra_num_powerdomains)
 		return -EINVAL;
 
 	return tegra_powergate_set(id, false);
 }
 
-static bool tegra_powergate_is_powered(int id)
+int tegra_powergate_is_powered(int id)
 {
 	u32 status;
 
-	WARN_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
+	if (id < 0 || id >= tegra_num_powerdomains)
+		return -EINVAL;
 
 	status = pmc_read(PWRGATE_STATUS) & (1 << id);
 	return !!status;
@@ -103,7 +116,7 @@
 {
 	u32 mask;
 
-	if (id < 0 || id >= TEGRA_NUM_POWERGATE)
+	if (id < 0 || id >= tegra_num_powerdomains)
 		return -EINVAL;
 
 	/*
@@ -156,6 +169,34 @@
 	return ret;
 }
 
+int tegra_cpu_powergate_id(int cpuid)
+{
+	if (cpuid > 0 && cpuid < tegra_num_cpu_domains)
+		return tegra_cpu_domains[cpuid];
+
+	return -EINVAL;
+}
+
+int __init tegra_powergate_init(void)
+{
+	switch (tegra_chip_id) {
+	case TEGRA20:
+		tegra_num_powerdomains = 7;
+		break;
+	case TEGRA30:
+		tegra_num_powerdomains = 14;
+		tegra_num_cpu_domains = 4;
+		tegra_cpu_domains = tegra30_cpu_domains;
+		break;
+	default:
+		/* Unknown Tegra variant. Disable powergating */
+		tegra_num_powerdomains = 0;
+		break;
+	}
+
+	return 0;
+}
+
 #ifdef CONFIG_DEBUG_FS
 
 static const char * const powergate_name[] = {
@@ -175,7 +216,7 @@
 	seq_printf(s, " powergate powered\n");
 	seq_printf(s, "------------------\n");
 
-	for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
+	for (i = 0; i < tegra_num_powerdomains; i++)
 		seq_printf(s, " %9s %7s\n", powergate_name[i],
 			tegra_powergate_is_powered(i) ? "yes" : "no");
 	return 0;
diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c
new file mode 100644
index 0000000..4d6a2ee
--- /dev/null
+++ b/arch/arm/mach-tegra/reset.c
@@ -0,0 +1,84 @@
+/*
+ * arch/arm/mach-tegra/reset.c
+ *
+ * Copyright (C) 2011,2012 NVIDIA Corporation.
+ *
+ * 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/init.h>
+#include <linux/io.h>
+#include <linux/cpumask.h>
+#include <linux/bitops.h>
+
+#include <asm/cacheflush.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#include <mach/iomap.h>
+#include <mach/irammap.h>
+
+#include "reset.h"
+#include "fuse.h"
+
+#define TEGRA_IRAM_RESET_BASE (TEGRA_IRAM_BASE + \
+				TEGRA_IRAM_RESET_HANDLER_OFFSET)
+
+static bool is_enabled;
+
+static void tegra_cpu_reset_handler_enable(void)
+{
+	void __iomem *iram_base = IO_ADDRESS(TEGRA_IRAM_RESET_BASE);
+	void __iomem *evp_cpu_reset =
+		IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE + 0x100);
+	void __iomem *sb_ctrl = IO_ADDRESS(TEGRA_SB_BASE);
+	u32 reg;
+
+	BUG_ON(is_enabled);
+	BUG_ON(tegra_cpu_reset_handler_size > TEGRA_IRAM_RESET_HANDLER_SIZE);
+
+	memcpy(iram_base, (void *)__tegra_cpu_reset_handler_start,
+			tegra_cpu_reset_handler_size);
+
+	/*
+	 * NOTE: This must be the one and only write to the EVP CPU reset
+	 *       vector in the entire system.
+	 */
+	writel(TEGRA_IRAM_RESET_BASE + tegra_cpu_reset_handler_offset,
+			evp_cpu_reset);
+	wmb();
+	reg = readl(evp_cpu_reset);
+
+	/*
+	 * Prevent further modifications to the physical reset vector.
+	 *  NOTE: Has no effect on chips prior to Tegra30.
+	 */
+	if (tegra_chip_id != TEGRA20) {
+		reg = readl(sb_ctrl);
+		reg |= 2;
+		writel(reg, sb_ctrl);
+		wmb();
+	}
+
+	is_enabled = true;
+}
+
+void __init tegra_cpu_reset_handler_init(void)
+{
+
+#ifdef CONFIG_SMP
+	__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_PRESENT] =
+		*((u32 *)cpu_present_mask);
+	__tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_SECONDARY] =
+		virt_to_phys((void *)tegra_secondary_startup);
+#endif
+
+	tegra_cpu_reset_handler_enable();
+}
diff --git a/arch/arm/mach-tegra/reset.h b/arch/arm/mach-tegra/reset.h
new file mode 100644
index 0000000..de88bf8
--- /dev/null
+++ b/arch/arm/mach-tegra/reset.h
@@ -0,0 +1,50 @@
+/*
+ * arch/arm/mach-tegra/reset.h
+ *
+ * CPU reset dispatcher.
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * 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 __MACH_TEGRA_RESET_H
+#define __MACH_TEGRA_RESET_H
+
+#define TEGRA_RESET_MASK_PRESENT	0
+#define TEGRA_RESET_MASK_LP1		1
+#define TEGRA_RESET_MASK_LP2		2
+#define TEGRA_RESET_STARTUP_SECONDARY	3
+#define TEGRA_RESET_STARTUP_LP2		4
+#define TEGRA_RESET_STARTUP_LP1		5
+#define TEGRA_RESET_DATA_SIZE		6
+
+#ifndef __ASSEMBLY__
+
+extern unsigned long __tegra_cpu_reset_handler_data[TEGRA_RESET_DATA_SIZE];
+
+void __tegra_cpu_reset_handler_start(void);
+void __tegra_cpu_reset_handler(void);
+void __tegra_cpu_reset_handler_end(void);
+void tegra_secondary_startup(void);
+
+#define tegra_cpu_reset_handler_offset \
+		((u32)__tegra_cpu_reset_handler - \
+		 (u32)__tegra_cpu_reset_handler_start)
+
+#define tegra_cpu_reset_handler_size \
+		(__tegra_cpu_reset_handler_end - \
+		 __tegra_cpu_reset_handler_start)
+
+void __init tegra_cpu_reset_handler_init(void);
+
+#endif
+#endif
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
new file mode 100644
index 0000000..5b20197
--- /dev/null
+++ b/arch/arm/mach-tegra/sleep.S
@@ -0,0 +1,93 @@
+/*
+ * arch/arm/mach-tegra/sleep.S
+ *
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
+ * Copyright (c) 2011, Google, Inc.
+ *
+ * Author: Colin Cross <ccross@android.com>
+ *         Gary King <gking@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; 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.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+
+#include <mach/iomap.h>
+
+#include "flowctrl.h"
+
+#define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \
+					+ IO_PPSB_VIRT)
+
+/* returns the offset of the flow controller halt register for a cpu */
+.macro cpu_to_halt_reg rd, rcpu
+	cmp	\rcpu, #0
+	subne	\rd, \rcpu, #1
+	movne	\rd, \rd, lsl #3
+	addne	\rd, \rd, #0x14
+	moveq	\rd, #0
+.endm
+
+/* returns the offset of the flow controller csr register for a cpu */
+.macro cpu_to_csr_reg rd, rcpu
+	cmp	\rcpu, #0
+	subne	\rd, \rcpu, #1
+	movne	\rd, \rd, lsl #3
+	addne	\rd, \rd, #0x18
+	moveq	\rd, #8
+.endm
+
+/* returns the ID of the current processor */
+.macro cpu_id, rd
+	mrc	p15, 0, \rd, c0, c0, 5
+	and	\rd, \rd, #0xF
+.endm
+
+/* loads a 32-bit value into a register without a data access */
+.macro mov32, reg, val
+	movw	\reg, #:lower16:\val
+	movt	\reg, #:upper16:\val
+.endm
+
+/*
+ * tegra_cpu_wfi
+ *
+ * puts current CPU in clock-gated wfi using the flow controller
+ *
+ * corrupts r0-r3
+ * must be called with MMU on
+ */
+
+ENTRY(tegra_cpu_wfi)
+	cpu_id	r0
+	cpu_to_halt_reg r1, r0
+	cpu_to_csr_reg r2, r0
+	mov32	r0, TEGRA_FLOW_CTRL_VIRT
+	mov	r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
+	str	r3, [r0, r2]	@ clear event & interrupt status
+	mov	r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT | FLOW_CTRL_JTAG_RESUME
+	str	r3, [r0, r1]	@ put flow controller in wait irq mode
+	dsb
+	wfi
+	mov	r3, #0
+	str	r3, [r0, r1]	@ clear flow controller halt status
+	mov	r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
+	str	r3, [r0, r2]	@ clear event & interrupt status
+	dsb
+	mov	pc, lr
+ENDPROC(tegra_cpu_wfi)
+
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index ff9e6b6..592a4ee 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -720,7 +720,7 @@
 {
 	tegra2_pll_clk_init(c);
 
-	if (tegra_sku_id() == 7)
+	if (tegra_sku_id == 7)
 		c->max_rate = 750000000;
 }
 
@@ -1143,15 +1143,35 @@
 
 static long tegra2_emc_clk_round_rate(struct clk *c, unsigned long rate)
 {
-	long new_rate = rate;
+	long emc_rate;
+	long clk_rate;
 
-	new_rate = tegra_emc_round_rate(new_rate);
-	if (new_rate < 0)
+	/*
+	 * The slowest entry in the EMC clock table that is at least as
+	 * fast as rate.
+	 */
+	emc_rate = tegra_emc_round_rate(rate);
+	if (emc_rate < 0)
 		return c->max_rate;
 
-	BUG_ON(new_rate != tegra2_periph_clk_round_rate(c, new_rate));
+	/*
+	 * The fastest rate the PLL will generate that is at most the
+	 * requested rate.
+	 */
+	clk_rate = tegra2_periph_clk_round_rate(c, emc_rate);
 
-	return new_rate;
+	/*
+	 * If this fails, and emc_rate > clk_rate, it's because the maximum
+	 * rate in the EMC tables is larger than the maximum rate of the EMC
+	 * clock. The EMC clock's max rate is the rate it was running when the
+	 * kernel booted. Such a mismatch is probably due to using the wrong
+	 * BCT, i.e. using a Tegra20 BCT with an EMC table written for Tegra25.
+	 */
+	WARN_ONCE(emc_rate != clk_rate,
+		"emc_rate %ld != clk_rate %ld",
+		emc_rate, clk_rate);
+
+	return emc_rate;
 }
 
 static int tegra2_emc_clk_set_rate(struct clk *c, unsigned long rate)
diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c
index 0f7ae6e..5070d83 100644
--- a/arch/arm/mach-tegra/tegra2_emc.c
+++ b/arch/arm/mach-tegra/tegra2_emc.c
@@ -16,14 +16,19 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/device.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/tegra_emc.h>
 
 #include <mach/iomap.h>
 
 #include "tegra2_emc.h"
+#include "fuse.h"
 
 #ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE
 static bool emc_enable = true;
@@ -32,18 +37,17 @@
 #endif
 module_param(emc_enable, bool, 0644);
 
-static void __iomem *emc = IO_ADDRESS(TEGRA_EMC_BASE);
-static const struct tegra_emc_table *tegra_emc_table;
-static int tegra_emc_table_size;
+static struct platform_device *emc_pdev;
+static void __iomem *emc_regbase;
 
 static inline void emc_writel(u32 val, unsigned long addr)
 {
-	writel(val, emc + addr);
+	writel(val, emc_regbase + addr);
 }
 
 static inline u32 emc_readl(unsigned long addr)
 {
-	return readl(emc + addr);
+	return readl(emc_regbase + addr);
 }
 
 static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = {
@@ -98,15 +102,15 @@
 /* Select the closest EMC rate that is higher than the requested rate */
 long tegra_emc_round_rate(unsigned long rate)
 {
+	struct tegra_emc_pdata *pdata;
 	int i;
 	int best = -1;
 	unsigned long distance = ULONG_MAX;
 
-	if (!tegra_emc_table)
+	if (!emc_pdev)
 		return -EINVAL;
 
-	if (!emc_enable)
-		return -EINVAL;
+	pdata = emc_pdev->dev.platform_data;
 
 	pr_debug("%s: %lu\n", __func__, rate);
 
@@ -116,10 +120,10 @@
 	 */
 	rate = rate / 2 / 1000;
 
-	for (i = 0; i < tegra_emc_table_size; i++) {
-		if (tegra_emc_table[i].rate >= rate &&
-		    (tegra_emc_table[i].rate - rate) < distance) {
-			distance = tegra_emc_table[i].rate - rate;
+	for (i = 0; i < pdata->num_tables; i++) {
+		if (pdata->tables[i].rate >= rate &&
+		    (pdata->tables[i].rate - rate) < distance) {
+			distance = pdata->tables[i].rate - rate;
 			best = i;
 		}
 	}
@@ -127,9 +131,9 @@
 	if (best < 0)
 		return -EINVAL;
 
-	pr_debug("%s: using %lu\n", __func__, tegra_emc_table[best].rate);
+	pr_debug("%s: using %lu\n", __func__, pdata->tables[best].rate);
 
-	return tegra_emc_table[best].rate * 2 * 1000;
+	return pdata->tables[best].rate * 2 * 1000;
 }
 
 /*
@@ -142,37 +146,211 @@
  */
 int tegra_emc_set_rate(unsigned long rate)
 {
+	struct tegra_emc_pdata *pdata;
 	int i;
 	int j;
 
-	if (!tegra_emc_table)
+	if (!emc_pdev)
 		return -EINVAL;
 
+	pdata = emc_pdev->dev.platform_data;
+
 	/*
 	 * The EMC clock rate is twice the bus rate, and the bus rate is
 	 * measured in kHz
 	 */
 	rate = rate / 2 / 1000;
 
-	for (i = 0; i < tegra_emc_table_size; i++)
-		if (tegra_emc_table[i].rate == rate)
+	for (i = 0; i < pdata->num_tables; i++)
+		if (pdata->tables[i].rate == rate)
 			break;
 
-	if (i >= tegra_emc_table_size)
+	if (i >= pdata->num_tables)
 		return -EINVAL;
 
 	pr_debug("%s: setting to %lu\n", __func__, rate);
 
 	for (j = 0; j < TEGRA_EMC_NUM_REGS; j++)
-		emc_writel(tegra_emc_table[i].regs[j], emc_reg_addr[j]);
+		emc_writel(pdata->tables[i].regs[j], emc_reg_addr[j]);
 
-	emc_readl(tegra_emc_table[i].regs[TEGRA_EMC_NUM_REGS - 1]);
+	emc_readl(pdata->tables[i].regs[TEGRA_EMC_NUM_REGS - 1]);
 
 	return 0;
 }
 
-void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
+#ifdef CONFIG_OF
+static struct device_node *tegra_emc_ramcode_devnode(struct device_node *np)
 {
-	tegra_emc_table = table;
-	tegra_emc_table_size = table_size;
+	struct device_node *iter;
+	u32 reg;
+
+	for_each_child_of_node(np, iter) {
+		if (of_property_read_u32(np, "nvidia,ram-code", &reg))
+			continue;
+		if (reg == tegra_bct_strapping)
+			return of_node_get(iter);
+	}
+
+	return NULL;
 }
+
+static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata(
+		struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *tnp, *iter;
+	struct tegra_emc_pdata *pdata;
+	int ret, i, num_tables;
+
+	if (!np)
+		return NULL;
+
+	if (of_find_property(np, "nvidia,use-ram-code", NULL)) {
+		tnp = tegra_emc_ramcode_devnode(np);
+		if (!tnp)
+			dev_warn(&pdev->dev,
+				 "can't find emc table for ram-code 0x%02x\n",
+				 tegra_bct_strapping);
+	} else
+		tnp = of_node_get(np);
+
+	if (!tnp)
+		return NULL;
+
+	num_tables = 0;
+	for_each_child_of_node(tnp, iter)
+		if (of_device_is_compatible(iter, "nvidia,tegra20-emc-table"))
+			num_tables++;
+
+	if (!num_tables) {
+		pdata = NULL;
+		goto out;
+	}
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	pdata->tables = devm_kzalloc(&pdev->dev,
+				     sizeof(*pdata->tables) * num_tables,
+				     GFP_KERNEL);
+
+	i = 0;
+	for_each_child_of_node(tnp, iter) {
+		u32 prop;
+
+		ret = of_property_read_u32(iter, "clock-frequency", &prop);
+		if (ret) {
+			dev_err(&pdev->dev, "no clock-frequency in %s\n",
+				iter->full_name);
+			continue;
+		}
+		pdata->tables[i].rate = prop;
+
+		ret = of_property_read_u32_array(iter, "nvidia,emc-registers",
+						 pdata->tables[i].regs,
+						 TEGRA_EMC_NUM_REGS);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"malformed emc-registers property in %s\n",
+				iter->full_name);
+			continue;
+		}
+
+		i++;
+	}
+	pdata->num_tables = i;
+
+out:
+	of_node_put(tnp);
+	return pdata;
+}
+#else
+static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata(
+		struct platform_device *pdev)
+{
+	return NULL;
+}
+#endif
+
+static struct tegra_emc_pdata __devinit *tegra_emc_fill_pdata(struct platform_device *pdev)
+{
+	struct clk *c = clk_get_sys(NULL, "emc");
+	struct tegra_emc_pdata *pdata;
+	unsigned long khz;
+	int i;
+
+	WARN_ON(pdev->dev.platform_data);
+	BUG_ON(IS_ERR_OR_NULL(c));
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	pdata->tables = devm_kzalloc(&pdev->dev, sizeof(*pdata->tables),
+				     GFP_KERNEL);
+
+	pdata->tables[0].rate = clk_get_rate(c) / 2 / 1000;
+
+	for (i = 0; i < TEGRA_EMC_NUM_REGS; i++)
+		pdata->tables[0].regs[i] = emc_readl(emc_reg_addr[i]);
+
+	pdata->num_tables = 1;
+
+	khz = pdata->tables[0].rate;
+	dev_info(&pdev->dev, "no tables provided, using %ld kHz emc, "
+		 "%ld kHz mem\n", khz * 2, khz);
+
+	return pdata;
+}
+
+static int __devinit tegra_emc_probe(struct platform_device *pdev)
+{
+	struct tegra_emc_pdata *pdata;
+	struct resource *res;
+
+	if (!emc_enable) {
+		dev_err(&pdev->dev, "disabled per module parameter\n");
+		return -ENODEV;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "missing register base\n");
+		return -ENOMEM;
+	}
+
+	emc_regbase = devm_request_and_ioremap(&pdev->dev, res);
+	if (!emc_regbase) {
+		dev_err(&pdev->dev, "failed to remap registers\n");
+		return -ENOMEM;
+	}
+
+	pdata = pdev->dev.platform_data;
+
+	if (!pdata)
+		pdata = tegra_emc_dt_parse_pdata(pdev);
+
+	if (!pdata)
+		pdata = tegra_emc_fill_pdata(pdev);
+
+	pdev->dev.platform_data = pdata;
+
+	emc_pdev = pdev;
+
+	return 0;
+}
+
+static struct of_device_id tegra_emc_of_match[] __devinitdata = {
+	{ .compatible = "nvidia,tegra20-emc", },
+	{ },
+};
+
+static struct platform_driver tegra_emc_driver = {
+	.driver         = {
+		.name   = "tegra-emc",
+		.owner  = THIS_MODULE,
+		.of_match_table = tegra_emc_of_match,
+	},
+	.probe          = tegra_emc_probe,
+};
+
+static int __init tegra_emc_init(void)
+{
+	return platform_driver_register(&tegra_emc_driver);
+}
+device_initcall(tegra_emc_init);
diff --git a/arch/arm/mach-tegra/tegra2_emc.h b/arch/arm/mach-tegra/tegra2_emc.h
index 19f08cb..f61409b 100644
--- a/arch/arm/mach-tegra/tegra2_emc.h
+++ b/arch/arm/mach-tegra/tegra2_emc.h
@@ -15,13 +15,10 @@
  *
  */
 
-#define TEGRA_EMC_NUM_REGS 46
-
-struct tegra_emc_table {
-	unsigned long rate;
-	u32 regs[TEGRA_EMC_NUM_REGS];
-};
+#ifndef __MACH_TEGRA_TEGRA2_EMC_H_
+#define __MACH_TEGRA_TEGRA2_EMC_H
 
 int tegra_emc_set_rate(unsigned long rate);
 long tegra_emc_round_rate(unsigned long rate);
-void tegra_init_emc(const struct tegra_emc_table *table, int table_size);
+
+#endif
diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c
new file mode 100644
index 0000000..6d08b53
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30_clocks.c
@@ -0,0 +1,3099 @@
+/*
+ * arch/arm/mach-tegra/tegra30_clocks.c
+ *
+ * Copyright (c) 2010-2011 NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/syscore_ops.h>
+
+#include <asm/clkdev.h>
+
+#include <mach/iomap.h>
+
+#include "clock.h"
+#include "fuse.h"
+
+#define USE_PLL_LOCK_BITS 0
+
+#define RST_DEVICES_L			0x004
+#define RST_DEVICES_H			0x008
+#define RST_DEVICES_U			0x00C
+#define RST_DEVICES_V			0x358
+#define RST_DEVICES_W			0x35C
+#define RST_DEVICES_SET_L		0x300
+#define RST_DEVICES_CLR_L		0x304
+#define RST_DEVICES_SET_V		0x430
+#define RST_DEVICES_CLR_V		0x434
+#define RST_DEVICES_NUM			5
+
+#define CLK_OUT_ENB_L			0x010
+#define CLK_OUT_ENB_H			0x014
+#define CLK_OUT_ENB_U			0x018
+#define CLK_OUT_ENB_V			0x360
+#define CLK_OUT_ENB_W			0x364
+#define CLK_OUT_ENB_SET_L		0x320
+#define CLK_OUT_ENB_CLR_L		0x324
+#define CLK_OUT_ENB_SET_V		0x440
+#define CLK_OUT_ENB_CLR_V		0x444
+#define CLK_OUT_ENB_NUM			5
+
+#define RST_DEVICES_V_SWR_CPULP_RST_DIS	(0x1 << 1)
+#define CLK_OUT_ENB_V_CLK_ENB_CPULP_EN	(0x1 << 1)
+
+#define PERIPH_CLK_TO_BIT(c)		(1 << (c->u.periph.clk_num % 32))
+#define PERIPH_CLK_TO_RST_REG(c)	\
+	periph_clk_to_reg((c), RST_DEVICES_L, RST_DEVICES_V, 4)
+#define PERIPH_CLK_TO_RST_SET_REG(c)	\
+	periph_clk_to_reg((c), RST_DEVICES_SET_L, RST_DEVICES_SET_V, 8)
+#define PERIPH_CLK_TO_RST_CLR_REG(c)	\
+	periph_clk_to_reg((c), RST_DEVICES_CLR_L, RST_DEVICES_CLR_V, 8)
+
+#define PERIPH_CLK_TO_ENB_REG(c)	\
+	periph_clk_to_reg((c), CLK_OUT_ENB_L, CLK_OUT_ENB_V, 4)
+#define PERIPH_CLK_TO_ENB_SET_REG(c)	\
+	periph_clk_to_reg((c), CLK_OUT_ENB_SET_L, CLK_OUT_ENB_SET_V, 8)
+#define PERIPH_CLK_TO_ENB_CLR_REG(c)	\
+	periph_clk_to_reg((c), CLK_OUT_ENB_CLR_L, CLK_OUT_ENB_CLR_V, 8)
+
+#define CLK_MASK_ARM			0x44
+#define MISC_CLK_ENB			0x48
+
+#define OSC_CTRL			0x50
+#define OSC_CTRL_OSC_FREQ_MASK		(0xF<<28)
+#define OSC_CTRL_OSC_FREQ_13MHZ		(0x0<<28)
+#define OSC_CTRL_OSC_FREQ_19_2MHZ	(0x4<<28)
+#define OSC_CTRL_OSC_FREQ_12MHZ		(0x8<<28)
+#define OSC_CTRL_OSC_FREQ_26MHZ		(0xC<<28)
+#define OSC_CTRL_OSC_FREQ_16_8MHZ	(0x1<<28)
+#define OSC_CTRL_OSC_FREQ_38_4MHZ	(0x5<<28)
+#define OSC_CTRL_OSC_FREQ_48MHZ		(0x9<<28)
+#define OSC_CTRL_MASK			(0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
+
+#define OSC_CTRL_PLL_REF_DIV_MASK	(3<<26)
+#define OSC_CTRL_PLL_REF_DIV_1		(0<<26)
+#define OSC_CTRL_PLL_REF_DIV_2		(1<<26)
+#define OSC_CTRL_PLL_REF_DIV_4		(2<<26)
+
+#define OSC_FREQ_DET			0x58
+#define OSC_FREQ_DET_TRIG		(1<<31)
+
+#define OSC_FREQ_DET_STATUS		0x5C
+#define OSC_FREQ_DET_BUSY		(1<<31)
+#define OSC_FREQ_DET_CNT_MASK		0xFFFF
+
+#define PERIPH_CLK_SOURCE_I2S1		0x100
+#define PERIPH_CLK_SOURCE_EMC		0x19c
+#define PERIPH_CLK_SOURCE_OSC		0x1fc
+#define PERIPH_CLK_SOURCE_NUM1 \
+	((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
+
+#define PERIPH_CLK_SOURCE_G3D2		0x3b0
+#define PERIPH_CLK_SOURCE_SE		0x42c
+#define PERIPH_CLK_SOURCE_NUM2 \
+	((PERIPH_CLK_SOURCE_SE - PERIPH_CLK_SOURCE_G3D2) / 4 + 1)
+
+#define AUDIO_DLY_CLK			0x49c
+#define AUDIO_SYNC_CLK_SPDIF		0x4b4
+#define PERIPH_CLK_SOURCE_NUM3 \
+	((AUDIO_SYNC_CLK_SPDIF - AUDIO_DLY_CLK) / 4 + 1)
+
+#define PERIPH_CLK_SOURCE_NUM		(PERIPH_CLK_SOURCE_NUM1 + \
+					 PERIPH_CLK_SOURCE_NUM2 + \
+					 PERIPH_CLK_SOURCE_NUM3)
+
+#define CPU_SOFTRST_CTRL		0x380
+
+#define PERIPH_CLK_SOURCE_DIVU71_MASK	0xFF
+#define PERIPH_CLK_SOURCE_DIVU16_MASK	0xFFFF
+#define PERIPH_CLK_SOURCE_DIV_SHIFT	0
+#define PERIPH_CLK_SOURCE_DIVIDLE_SHIFT	8
+#define PERIPH_CLK_SOURCE_DIVIDLE_VAL	50
+#define PERIPH_CLK_UART_DIV_ENB		(1<<24)
+#define PERIPH_CLK_VI_SEL_EX_SHIFT	24
+#define PERIPH_CLK_VI_SEL_EX_MASK	(0x3<<PERIPH_CLK_VI_SEL_EX_SHIFT)
+#define PERIPH_CLK_NAND_DIV_EX_ENB	(1<<8)
+#define PERIPH_CLK_DTV_POLARITY_INV	(1<<25)
+
+#define AUDIO_SYNC_SOURCE_MASK		0x0F
+#define AUDIO_SYNC_DISABLE_BIT		0x10
+#define AUDIO_SYNC_TAP_NIBBLE_SHIFT(c)	((c->reg_shift - 24) * 4)
+
+#define PLL_BASE			0x0
+#define PLL_BASE_BYPASS			(1<<31)
+#define PLL_BASE_ENABLE			(1<<30)
+#define PLL_BASE_REF_ENABLE		(1<<29)
+#define PLL_BASE_OVERRIDE		(1<<28)
+#define PLL_BASE_LOCK			(1<<27)
+#define PLL_BASE_DIVP_MASK		(0x7<<20)
+#define PLL_BASE_DIVP_SHIFT		20
+#define PLL_BASE_DIVN_MASK		(0x3FF<<8)
+#define PLL_BASE_DIVN_SHIFT		8
+#define PLL_BASE_DIVM_MASK		(0x1F)
+#define PLL_BASE_DIVM_SHIFT		0
+
+#define PLL_OUT_RATIO_MASK		(0xFF<<8)
+#define PLL_OUT_RATIO_SHIFT		8
+#define PLL_OUT_OVERRIDE		(1<<2)
+#define PLL_OUT_CLKEN			(1<<1)
+#define PLL_OUT_RESET_DISABLE		(1<<0)
+
+#define PLL_MISC(c)			\
+	(((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
+#define PLL_MISC_LOCK_ENABLE(c)	\
+	(((c)->flags & (PLLU | PLLD)) ? (1<<22) : (1<<18))
+
+#define PLL_MISC_DCCON_SHIFT		20
+#define PLL_MISC_CPCON_SHIFT		8
+#define PLL_MISC_CPCON_MASK		(0xF<<PLL_MISC_CPCON_SHIFT)
+#define PLL_MISC_LFCON_SHIFT		4
+#define PLL_MISC_LFCON_MASK		(0xF<<PLL_MISC_LFCON_SHIFT)
+#define PLL_MISC_VCOCON_SHIFT		0
+#define PLL_MISC_VCOCON_MASK		(0xF<<PLL_MISC_VCOCON_SHIFT)
+#define PLLD_MISC_CLKENABLE		(1<<30)
+
+#define PLLU_BASE_POST_DIV		(1<<20)
+
+#define PLLD_BASE_DSIB_MUX_SHIFT	25
+#define PLLD_BASE_DSIB_MUX_MASK		(1<<PLLD_BASE_DSIB_MUX_SHIFT)
+#define PLLD_BASE_CSI_CLKENABLE		(1<<26)
+#define PLLD_MISC_DSI_CLKENABLE		(1<<30)
+#define PLLD_MISC_DIV_RST		(1<<23)
+#define PLLD_MISC_DCCON_SHIFT		12
+
+#define PLLDU_LFCON_SET_DIVN		600
+
+/* FIXME: OUT_OF_TABLE_CPCON per pll */
+#define OUT_OF_TABLE_CPCON		0x8
+
+#define SUPER_CLK_MUX			0x00
+#define SUPER_STATE_SHIFT		28
+#define SUPER_STATE_MASK		(0xF << SUPER_STATE_SHIFT)
+#define SUPER_STATE_STANDBY		(0x0 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_IDLE		(0x1 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_RUN			(0x2 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_IRQ			(0x3 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_FIQ			(0x4 << SUPER_STATE_SHIFT)
+#define SUPER_LP_DIV2_BYPASS		(0x1 << 16)
+#define SUPER_SOURCE_MASK		0xF
+#define	SUPER_FIQ_SOURCE_SHIFT		12
+#define	SUPER_IRQ_SOURCE_SHIFT		8
+#define	SUPER_RUN_SOURCE_SHIFT		4
+#define	SUPER_IDLE_SOURCE_SHIFT		0
+
+#define SUPER_CLK_DIVIDER		0x04
+#define SUPER_CLOCK_DIV_U71_SHIFT	16
+#define SUPER_CLOCK_DIV_U71_MASK	(0xff << SUPER_CLOCK_DIV_U71_SHIFT)
+/* guarantees safe cpu backup */
+#define SUPER_CLOCK_DIV_U71_MIN		0x2
+
+#define BUS_CLK_DISABLE			(1<<3)
+#define BUS_CLK_DIV_MASK		0x3
+
+#define PMC_CTRL			0x0
+ #define PMC_CTRL_BLINK_ENB		(1 << 7)
+
+#define PMC_DPD_PADS_ORIDE		0x1c
+ #define PMC_DPD_PADS_ORIDE_BLINK_ENB	(1 << 20)
+
+#define PMC_BLINK_TIMER_DATA_ON_SHIFT	0
+#define PMC_BLINK_TIMER_DATA_ON_MASK	0x7fff
+#define PMC_BLINK_TIMER_ENB		(1 << 15)
+#define PMC_BLINK_TIMER_DATA_OFF_SHIFT	16
+#define PMC_BLINK_TIMER_DATA_OFF_MASK	0xffff
+
+#define PMC_PLLP_WB0_OVERRIDE				0xf8
+#define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE		(1 << 12)
+
+#define UTMIP_PLL_CFG2					0x488
+#define UTMIP_PLL_CFG2_STABLE_COUNT(x)			(((x) & 0xfff) << 6)
+#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x)		(((x) & 0x3f) << 18)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN	(1 << 0)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN	(1 << 2)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN	(1 << 4)
+
+#define UTMIP_PLL_CFG1					0x484
+#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x)		(((x) & 0x1f) << 27)
+#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x)		(((x) & 0xfff) << 0)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN	(1 << 14)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN	(1 << 12)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN		(1 << 16)
+
+#define PLLE_BASE_CML_ENABLE		(1<<31)
+#define PLLE_BASE_ENABLE		(1<<30)
+#define PLLE_BASE_DIVCML_SHIFT		24
+#define PLLE_BASE_DIVCML_MASK		(0xf<<PLLE_BASE_DIVCML_SHIFT)
+#define PLLE_BASE_DIVP_SHIFT		16
+#define PLLE_BASE_DIVP_MASK		(0x3f<<PLLE_BASE_DIVP_SHIFT)
+#define PLLE_BASE_DIVN_SHIFT		8
+#define PLLE_BASE_DIVN_MASK		(0xFF<<PLLE_BASE_DIVN_SHIFT)
+#define PLLE_BASE_DIVM_SHIFT		0
+#define PLLE_BASE_DIVM_MASK		(0xFF<<PLLE_BASE_DIVM_SHIFT)
+#define PLLE_BASE_DIV_MASK		\
+	(PLLE_BASE_DIVCML_MASK | PLLE_BASE_DIVP_MASK | \
+	 PLLE_BASE_DIVN_MASK | PLLE_BASE_DIVM_MASK)
+#define PLLE_BASE_DIV(m, n, p, cml)		\
+	 (((cml)<<PLLE_BASE_DIVCML_SHIFT) | ((p)<<PLLE_BASE_DIVP_SHIFT) | \
+	  ((n)<<PLLE_BASE_DIVN_SHIFT) | ((m)<<PLLE_BASE_DIVM_SHIFT))
+
+#define PLLE_MISC_SETUP_BASE_SHIFT	16
+#define PLLE_MISC_SETUP_BASE_MASK	(0xFFFF<<PLLE_MISC_SETUP_BASE_SHIFT)
+#define PLLE_MISC_READY			(1<<15)
+#define PLLE_MISC_LOCK			(1<<11)
+#define PLLE_MISC_LOCK_ENABLE		(1<<9)
+#define PLLE_MISC_SETUP_EX_SHIFT	2
+#define PLLE_MISC_SETUP_EX_MASK		(0x3<<PLLE_MISC_SETUP_EX_SHIFT)
+#define PLLE_MISC_SETUP_MASK		\
+	  (PLLE_MISC_SETUP_BASE_MASK | PLLE_MISC_SETUP_EX_MASK)
+#define PLLE_MISC_SETUP_VALUE		\
+	  ((0x7<<PLLE_MISC_SETUP_BASE_SHIFT) | (0x0<<PLLE_MISC_SETUP_EX_SHIFT))
+
+#define PLLE_SS_CTRL			0x68
+#define	PLLE_SS_INCINTRV_SHIFT		24
+#define	PLLE_SS_INCINTRV_MASK		(0x3f<<PLLE_SS_INCINTRV_SHIFT)
+#define	PLLE_SS_INC_SHIFT		16
+#define	PLLE_SS_INC_MASK		(0xff<<PLLE_SS_INC_SHIFT)
+#define	PLLE_SS_MAX_SHIFT		0
+#define	PLLE_SS_MAX_MASK		(0x1ff<<PLLE_SS_MAX_SHIFT)
+#define PLLE_SS_COEFFICIENTS_MASK	\
+	(PLLE_SS_INCINTRV_MASK | PLLE_SS_INC_MASK | PLLE_SS_MAX_MASK)
+#define PLLE_SS_COEFFICIENTS_12MHZ	\
+	((0x18<<PLLE_SS_INCINTRV_SHIFT) | (0x1<<PLLE_SS_INC_SHIFT) | \
+	 (0x24<<PLLE_SS_MAX_SHIFT))
+#define PLLE_SS_DISABLE			((1<<12) | (1<<11) | (1<<10))
+
+#define PLLE_AUX			0x48c
+#define PLLE_AUX_PLLP_SEL		(1<<2)
+#define PLLE_AUX_CML_SATA_ENABLE	(1<<1)
+#define PLLE_AUX_CML_PCIE_ENABLE	(1<<0)
+
+#define	PMC_SATA_PWRGT			0x1ac
+#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE	(1<<5)
+#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL	(1<<4)
+
+#define ROUND_DIVIDER_UP	0
+#define ROUND_DIVIDER_DOWN	1
+
+/* FIXME: recommended safety delay after lock is detected */
+#define PLL_POST_LOCK_DELAY		100
+
+/**
+* Structure defining the fields for USB UTMI clocks Parameters.
+*/
+struct utmi_clk_param {
+	/* Oscillator Frequency in KHz */
+	u32 osc_frequency;
+	/* UTMIP PLL Enable Delay Count  */
+	u8 enable_delay_count;
+	/* UTMIP PLL Stable count */
+	u8 stable_count;
+	/*  UTMIP PLL Active delay count */
+	u8 active_delay_count;
+	/* UTMIP PLL Xtal frequency count */
+	u8 xtal_freq_count;
+};
+
+static const struct utmi_clk_param utmi_parameters[] = {
+	{
+		.osc_frequency = 13000000,
+		.enable_delay_count = 0x02,
+		.stable_count = 0x33,
+		.active_delay_count = 0x05,
+		.xtal_freq_count = 0x7F
+	},
+	{
+		.osc_frequency = 19200000,
+		.enable_delay_count = 0x03,
+		.stable_count = 0x4B,
+		.active_delay_count = 0x06,
+		.xtal_freq_count = 0xBB},
+	{
+		.osc_frequency = 12000000,
+		.enable_delay_count = 0x02,
+		.stable_count = 0x2F,
+		.active_delay_count = 0x04,
+		.xtal_freq_count = 0x76
+	},
+	{
+		.osc_frequency = 26000000,
+		.enable_delay_count = 0x04,
+		.stable_count = 0x66,
+		.active_delay_count = 0x09,
+		.xtal_freq_count = 0xFE
+	},
+	{
+		.osc_frequency = 16800000,
+		.enable_delay_count = 0x03,
+		.stable_count = 0x41,
+		.active_delay_count = 0x0A,
+		.xtal_freq_count = 0xA4
+	},
+};
+
+static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+static void __iomem *misc_gp_hidrev_base = IO_ADDRESS(TEGRA_APB_MISC_BASE);
+
+#define MISC_GP_HIDREV                  0x804
+
+/*
+ * Some peripheral clocks share an enable bit, so refcount the enable bits
+ * in registers CLK_ENABLE_L, ... CLK_ENABLE_W
+ */
+static int tegra_periph_clk_enable_refcount[CLK_OUT_ENB_NUM * 32];
+
+#define clk_writel(value, reg) \
+	__raw_writel(value, (u32)reg_clk_base + (reg))
+#define clk_readl(reg) \
+	__raw_readl((u32)reg_clk_base + (reg))
+#define pmc_writel(value, reg) \
+	__raw_writel(value, (u32)reg_pmc_base + (reg))
+#define pmc_readl(reg) \
+	__raw_readl((u32)reg_pmc_base + (reg))
+#define chipid_readl() \
+	__raw_readl((u32)misc_gp_hidrev_base + MISC_GP_HIDREV)
+
+#define clk_writel_delay(value, reg)					\
+	do {								\
+		__raw_writel((value), (u32)reg_clk_base + (reg));	\
+		udelay(2);						\
+	} while (0)
+
+
+static inline int clk_set_div(struct clk *c, u32 n)
+{
+	return clk_set_rate(c, (clk_get_rate(c->parent) + n-1) / n);
+}
+
+static inline u32 periph_clk_to_reg(
+	struct clk *c, u32 reg_L, u32 reg_V, int offs)
+{
+	u32 reg = c->u.periph.clk_num / 32;
+	BUG_ON(reg >= RST_DEVICES_NUM);
+	if (reg < 3)
+		reg = reg_L + (reg * offs);
+	else
+		reg = reg_V + ((reg - 3) * offs);
+	return reg;
+}
+
+static unsigned long clk_measure_input_freq(void)
+{
+	u32 clock_autodetect;
+	clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET);
+	do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY);
+	clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS);
+	if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) {
+		return 12000000;
+	} else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) {
+		return 13000000;
+	} else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) {
+		return 19200000;
+	} else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) {
+		return 26000000;
+	} else if (clock_autodetect >= 1025 - 3 && clock_autodetect <= 1025 + 3) {
+		return 16800000;
+	} else if (clock_autodetect >= 2344 - 3 && clock_autodetect <= 2344 + 3) {
+		return 38400000;
+	} else if (clock_autodetect >= 2928 - 3 && clock_autodetect <= 2928 + 3) {
+		return 48000000;
+	} else {
+		pr_err("%s: Unexpected clock autodetect value %d", __func__,
+			clock_autodetect);
+		BUG();
+		return 0;
+	}
+}
+
+static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate,
+				 u32 flags, u32 round_mode)
+{
+	s64 divider_u71 = parent_rate;
+	if (!rate)
+		return -EINVAL;
+
+	if (!(flags & DIV_U71_INT))
+		divider_u71 *= 2;
+	if (round_mode == ROUND_DIVIDER_UP)
+		divider_u71 += rate - 1;
+	do_div(divider_u71, rate);
+	if (flags & DIV_U71_INT)
+		divider_u71 *= 2;
+
+	if (divider_u71 - 2 < 0)
+		return 0;
+
+	if (divider_u71 - 2 > 255)
+		return -EINVAL;
+
+	return divider_u71 - 2;
+}
+
+static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
+{
+	s64 divider_u16;
+
+	divider_u16 = parent_rate;
+	if (!rate)
+		return -EINVAL;
+	divider_u16 += rate - 1;
+	do_div(divider_u16, rate);
+
+	if (divider_u16 - 1 < 0)
+		return 0;
+
+	if (divider_u16 - 1 > 0xFFFF)
+		return -EINVAL;
+
+	return divider_u16 - 1;
+}
+
+/* clk_m functions */
+static unsigned long tegra30_clk_m_autodetect_rate(struct clk *c)
+{
+	u32 osc_ctrl = clk_readl(OSC_CTRL);
+	u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK;
+	u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK;
+
+	c->rate = clk_measure_input_freq();
+	switch (c->rate) {
+	case 12000000:
+		auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
+		BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+		break;
+	case 13000000:
+		auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ;
+		BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+		break;
+	case 19200000:
+		auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ;
+		BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+		break;
+	case 26000000:
+		auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ;
+		BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+		break;
+	case 16800000:
+		auto_clock_control |= OSC_CTRL_OSC_FREQ_16_8MHZ;
+		BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+		break;
+	case 38400000:
+		auto_clock_control |= OSC_CTRL_OSC_FREQ_38_4MHZ;
+		BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_2);
+		break;
+	case 48000000:
+		auto_clock_control |= OSC_CTRL_OSC_FREQ_48MHZ;
+		BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4);
+		break;
+	default:
+		pr_err("%s: Unexpected clock rate %ld", __func__, c->rate);
+		BUG();
+	}
+	clk_writel(auto_clock_control, OSC_CTRL);
+	return c->rate;
+}
+
+static void tegra30_clk_m_init(struct clk *c)
+{
+	pr_debug("%s on clock %s\n", __func__, c->name);
+	tegra30_clk_m_autodetect_rate(c);
+}
+
+static int tegra30_clk_m_enable(struct clk *c)
+{
+	pr_debug("%s on clock %s\n", __func__, c->name);
+	return 0;
+}
+
+static void tegra30_clk_m_disable(struct clk *c)
+{
+	pr_debug("%s on clock %s\n", __func__, c->name);
+	WARN(1, "Attempting to disable main SoC clock\n");
+}
+
+static struct clk_ops tegra_clk_m_ops = {
+	.init		= tegra30_clk_m_init,
+	.enable		= tegra30_clk_m_enable,
+	.disable	= tegra30_clk_m_disable,
+};
+
+static struct clk_ops tegra_clk_m_div_ops = {
+	.enable		= tegra30_clk_m_enable,
+};
+
+/* PLL reference divider functions */
+static void tegra30_pll_ref_init(struct clk *c)
+{
+	u32 pll_ref_div = clk_readl(OSC_CTRL) & OSC_CTRL_PLL_REF_DIV_MASK;
+	pr_debug("%s on clock %s\n", __func__, c->name);
+
+	switch (pll_ref_div) {
+	case OSC_CTRL_PLL_REF_DIV_1:
+		c->div = 1;
+		break;
+	case OSC_CTRL_PLL_REF_DIV_2:
+		c->div = 2;
+		break;
+	case OSC_CTRL_PLL_REF_DIV_4:
+		c->div = 4;
+		break;
+	default:
+		pr_err("%s: Invalid pll ref divider %d", __func__, pll_ref_div);
+		BUG();
+	}
+	c->mul = 1;
+	c->state = ON;
+}
+
+static struct clk_ops tegra_pll_ref_ops = {
+	.init		= tegra30_pll_ref_init,
+	.enable		= tegra30_clk_m_enable,
+	.disable	= tegra30_clk_m_disable,
+};
+
+/* super clock functions */
+/* "super clocks" on tegra30 have two-stage muxes, fractional 7.1 divider and
+ * clock skipping super divider.  We will ignore the clock skipping divider,
+ * since we can't lower the voltage when using the clock skip, but we can if
+ * we lower the PLL frequency. We will use 7.1 divider for CPU super-clock
+ * only when its parent is a fixed rate PLL, since we can't change PLL rate
+ * in this case.
+ */
+static void tegra30_super_clk_init(struct clk *c)
+{
+	u32 val;
+	int source;
+	int shift;
+	const struct clk_mux_sel *sel;
+	val = clk_readl(c->reg + SUPER_CLK_MUX);
+	c->state = ON;
+	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+	shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
+		SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
+	source = (val >> shift) & SUPER_SOURCE_MASK;
+	if (c->flags & DIV_2)
+		source |= val & SUPER_LP_DIV2_BYPASS;
+	for (sel = c->inputs; sel->input != NULL; sel++) {
+		if (sel->value == source)
+			break;
+	}
+	BUG_ON(sel->input == NULL);
+	c->parent = sel->input;
+
+	if (c->flags & DIV_U71) {
+		/* Init safe 7.1 divider value (does not affect PLLX path) */
+		clk_writel(SUPER_CLOCK_DIV_U71_MIN << SUPER_CLOCK_DIV_U71_SHIFT,
+			   c->reg + SUPER_CLK_DIVIDER);
+		c->mul = 2;
+		c->div = 2;
+		if (!(c->parent->flags & PLLX))
+			c->div += SUPER_CLOCK_DIV_U71_MIN;
+	} else
+		clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
+}
+
+static int tegra30_super_clk_enable(struct clk *c)
+{
+	return 0;
+}
+
+static void tegra30_super_clk_disable(struct clk *c)
+{
+	/* since tegra 3 has 2 CPU super clocks - low power lp-mode clock and
+	   geared up g-mode super clock - mode switch may request to disable
+	   either of them; accept request with no affect on h/w */
+}
+
+static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p)
+{
+	u32 val;
+	const struct clk_mux_sel *sel;
+	int shift;
+
+	val = clk_readl(c->reg + SUPER_CLK_MUX);
+	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+	shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
+		SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
+	for (sel = c->inputs; sel->input != NULL; sel++) {
+		if (sel->input == p) {
+			/* For LP mode super-clock switch between PLLX direct
+			   and divided-by-2 outputs is allowed only when other
+			   than PLLX clock source is current parent */
+			if ((c->flags & DIV_2) && (p->flags & PLLX) &&
+			    ((sel->value ^ val) & SUPER_LP_DIV2_BYPASS)) {
+				if (c->parent->flags & PLLX)
+					return -EINVAL;
+				val ^= SUPER_LP_DIV2_BYPASS;
+				clk_writel_delay(val, c->reg);
+			}
+			val &= ~(SUPER_SOURCE_MASK << shift);
+			val |= (sel->value & SUPER_SOURCE_MASK) << shift;
+
+			/* 7.1 divider for CPU super-clock does not affect
+			   PLLX path */
+			if (c->flags & DIV_U71) {
+				u32 div = 0;
+				if (!(p->flags & PLLX)) {
+					div = clk_readl(c->reg +
+							SUPER_CLK_DIVIDER);
+					div &= SUPER_CLOCK_DIV_U71_MASK;
+					div >>= SUPER_CLOCK_DIV_U71_SHIFT;
+				}
+				c->div = div + 2;
+				c->mul = 2;
+			}
+
+			if (c->refcnt)
+				clk_enable(p);
+
+			clk_writel_delay(val, c->reg);
+
+			if (c->refcnt && c->parent)
+				clk_disable(c->parent);
+
+			clk_reparent(c, p);
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+/*
+ * Do not use super clocks "skippers", since dividing using a clock skipper
+ * does not allow the voltage to be scaled down. Instead adjust the rate of
+ * the parent clock. This requires that the parent of a super clock have no
+ * other children, otherwise the rate will change underneath the other
+ * children. Special case: if fixed rate PLL is CPU super clock parent the
+ * rate of this PLL can't be changed, and it has many other children. In
+ * this case use 7.1 fractional divider to adjust the super clock rate.
+ */
+static int tegra30_super_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	if ((c->flags & DIV_U71) && (c->parent->flags & PLL_FIXED)) {
+		int div = clk_div71_get_divider(c->parent->u.pll.fixed_rate,
+					rate, c->flags, ROUND_DIVIDER_DOWN);
+		div = max(div, SUPER_CLOCK_DIV_U71_MIN);
+
+		clk_writel(div << SUPER_CLOCK_DIV_U71_SHIFT,
+			   c->reg + SUPER_CLK_DIVIDER);
+		c->div = div + 2;
+		c->mul = 2;
+		return 0;
+	}
+	return clk_set_rate(c->parent, rate);
+}
+
+static struct clk_ops tegra_super_ops = {
+	.init			= tegra30_super_clk_init,
+	.enable			= tegra30_super_clk_enable,
+	.disable		= tegra30_super_clk_disable,
+	.set_parent		= tegra30_super_clk_set_parent,
+	.set_rate		= tegra30_super_clk_set_rate,
+};
+
+static int tegra30_twd_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	/* The input value 'rate' is the clock rate of the CPU complex. */
+	c->rate = (rate * c->mul) / c->div;
+	return 0;
+}
+
+static struct clk_ops tegra30_twd_ops = {
+	.set_rate	= tegra30_twd_clk_set_rate,
+};
+
+/* Blink output functions */
+
+static void tegra30_blink_clk_init(struct clk *c)
+{
+	u32 val;
+
+	val = pmc_readl(PMC_CTRL);
+	c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
+	c->mul = 1;
+	val = pmc_readl(c->reg);
+
+	if (val & PMC_BLINK_TIMER_ENB) {
+		unsigned int on_off;
+
+		on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
+			PMC_BLINK_TIMER_DATA_ON_MASK;
+		val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+		val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+		on_off += val;
+		/* each tick in the blink timer is 4 32KHz clocks */
+		c->div = on_off * 4;
+	} else {
+		c->div = 1;
+	}
+}
+
+static int tegra30_blink_clk_enable(struct clk *c)
+{
+	u32 val;
+
+	val = pmc_readl(PMC_DPD_PADS_ORIDE);
+	pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
+
+	val = pmc_readl(PMC_CTRL);
+	pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL);
+
+	return 0;
+}
+
+static void tegra30_blink_clk_disable(struct clk *c)
+{
+	u32 val;
+
+	val = pmc_readl(PMC_CTRL);
+	pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL);
+
+	val = pmc_readl(PMC_DPD_PADS_ORIDE);
+	pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
+}
+
+static int tegra30_blink_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	unsigned long parent_rate = clk_get_rate(c->parent);
+	if (rate >= parent_rate) {
+		c->div = 1;
+		pmc_writel(0, c->reg);
+	} else {
+		unsigned int on_off;
+		u32 val;
+
+		on_off = DIV_ROUND_UP(parent_rate / 8, rate);
+		c->div = on_off * 8;
+
+		val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) <<
+			PMC_BLINK_TIMER_DATA_ON_SHIFT;
+		on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+		on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+		val |= on_off;
+		val |= PMC_BLINK_TIMER_ENB;
+		pmc_writel(val, c->reg);
+	}
+
+	return 0;
+}
+
+static struct clk_ops tegra_blink_clk_ops = {
+	.init			= &tegra30_blink_clk_init,
+	.enable			= &tegra30_blink_clk_enable,
+	.disable		= &tegra30_blink_clk_disable,
+	.set_rate		= &tegra30_blink_clk_set_rate,
+};
+
+/* PLL Functions */
+static int tegra30_pll_clk_wait_for_lock(struct clk *c, u32 lock_reg,
+					 u32 lock_bit)
+{
+#if USE_PLL_LOCK_BITS
+	int i;
+	for (i = 0; i < c->u.pll.lock_delay; i++) {
+		if (clk_readl(lock_reg) & lock_bit) {
+			udelay(PLL_POST_LOCK_DELAY);
+			return 0;
+		}
+		udelay(2);		/* timeout = 2 * lock time */
+	}
+	pr_err("Timed out waiting for lock bit on pll %s", c->name);
+	return -1;
+#endif
+	udelay(c->u.pll.lock_delay);
+
+	return 0;
+}
+
+
+static void tegra30_utmi_param_configure(struct clk *c)
+{
+	u32 reg;
+	int i;
+	unsigned long main_rate =
+		clk_get_rate(c->parent->parent);
+
+	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
+		if (main_rate == utmi_parameters[i].osc_frequency)
+			break;
+	}
+
+	if (i >= ARRAY_SIZE(utmi_parameters)) {
+		pr_err("%s: Unexpected main rate %lu\n", __func__, main_rate);
+		return;
+	}
+
+	reg = clk_readl(UTMIP_PLL_CFG2);
+
+	/* Program UTMIP PLL stable and active counts */
+	/* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */
+	reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+	reg |= UTMIP_PLL_CFG2_STABLE_COUNT(
+			utmi_parameters[i].stable_count);
+
+	reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+
+	reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
+			utmi_parameters[i].active_delay_count);
+
+	/* Remove power downs from UTMIP PLL control bits */
+	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
+
+	clk_writel(reg, UTMIP_PLL_CFG2);
+
+	/* Program UTMIP PLL delay and oscillator frequency counts */
+	reg = clk_readl(UTMIP_PLL_CFG1);
+	reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+
+	reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
+		utmi_parameters[i].enable_delay_count);
+
+	reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+	reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
+		utmi_parameters[i].xtal_freq_count);
+
+	/* Remove power downs from UTMIP PLL control bits */
+	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
+	reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
+
+	clk_writel(reg, UTMIP_PLL_CFG1);
+}
+
+static void tegra30_pll_clk_init(struct clk *c)
+{
+	u32 val = clk_readl(c->reg + PLL_BASE);
+
+	c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
+
+	if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
+		const struct clk_pll_freq_table *sel;
+		unsigned long input_rate = clk_get_rate(c->parent);
+		for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+			if (sel->input_rate == input_rate &&
+				sel->output_rate == c->u.pll.fixed_rate) {
+				c->mul = sel->n;
+				c->div = sel->m * sel->p;
+				return;
+			}
+		}
+		pr_err("Clock %s has unknown fixed frequency\n", c->name);
+		BUG();
+	} else if (val & PLL_BASE_BYPASS) {
+		c->mul = 1;
+		c->div = 1;
+	} else {
+		c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
+		c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
+		if (c->flags & PLLU)
+			c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
+		else
+			c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >>
+					PLL_BASE_DIVP_SHIFT));
+		if (c->flags & PLL_FIXED) {
+			unsigned long rate = clk_get_rate_locked(c);
+			BUG_ON(rate != c->u.pll.fixed_rate);
+		}
+	}
+
+	if (c->flags & PLLU)
+		tegra30_utmi_param_configure(c);
+}
+
+static int tegra30_pll_clk_enable(struct clk *c)
+{
+	u32 val;
+	pr_debug("%s on clock %s\n", __func__, c->name);
+
+#if USE_PLL_LOCK_BITS
+	val = clk_readl(c->reg + PLL_MISC(c));
+	val |= PLL_MISC_LOCK_ENABLE(c);
+	clk_writel(val, c->reg + PLL_MISC(c));
+#endif
+	val = clk_readl(c->reg + PLL_BASE);
+	val &= ~PLL_BASE_BYPASS;
+	val |= PLL_BASE_ENABLE;
+	clk_writel(val, c->reg + PLL_BASE);
+
+	if (c->flags & PLLM) {
+		val = pmc_readl(PMC_PLLP_WB0_OVERRIDE);
+		val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
+		pmc_writel(val, PMC_PLLP_WB0_OVERRIDE);
+	}
+
+	tegra30_pll_clk_wait_for_lock(c, c->reg + PLL_BASE, PLL_BASE_LOCK);
+
+	return 0;
+}
+
+static void tegra30_pll_clk_disable(struct clk *c)
+{
+	u32 val;
+	pr_debug("%s on clock %s\n", __func__, c->name);
+
+	val = clk_readl(c->reg);
+	val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
+	clk_writel(val, c->reg);
+
+	if (c->flags & PLLM) {
+		val = pmc_readl(PMC_PLLP_WB0_OVERRIDE);
+		val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
+		pmc_writel(val, PMC_PLLP_WB0_OVERRIDE);
+	}
+}
+
+static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	u32 val, p_div, old_base;
+	unsigned long input_rate;
+	const struct clk_pll_freq_table *sel;
+	struct clk_pll_freq_table cfg;
+
+	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+	if (c->flags & PLL_FIXED) {
+		int ret = 0;
+		if (rate != c->u.pll.fixed_rate) {
+			pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
+			       __func__, c->name, c->u.pll.fixed_rate, rate);
+			ret = -EINVAL;
+		}
+		return ret;
+	}
+
+	if (c->flags & PLLM) {
+		if (rate != clk_get_rate_locked(c)) {
+			pr_err("%s: Can not change memory %s rate in flight\n",
+			       __func__, c->name);
+			return -EINVAL;
+		}
+		return 0;
+	}
+
+	p_div = 0;
+	input_rate = clk_get_rate(c->parent);
+
+	/* Check if the target rate is tabulated */
+	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+		if (sel->input_rate == input_rate && sel->output_rate == rate) {
+			if (c->flags & PLLU) {
+				BUG_ON(sel->p < 1 || sel->p > 2);
+				if (sel->p == 1)
+					p_div = PLLU_BASE_POST_DIV;
+			} else {
+				BUG_ON(sel->p < 1);
+				for (val = sel->p; val > 1; val >>= 1)
+					p_div++;
+				p_div <<= PLL_BASE_DIVP_SHIFT;
+			}
+			break;
+		}
+	}
+
+	/* Configure out-of-table rate */
+	if (sel->input_rate == 0) {
+		unsigned long cfreq;
+		BUG_ON(c->flags & PLLU);
+		sel = &cfg;
+
+		switch (input_rate) {
+		case 12000000:
+		case 26000000:
+			cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000;
+			break;
+		case 13000000:
+			cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000;
+			break;
+		case 16800000:
+		case 19200000:
+			cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000;
+			break;
+		default:
+			pr_err("%s: Unexpected reference rate %lu\n",
+			       __func__, input_rate);
+			BUG();
+		}
+
+		/* Raise VCO to guarantee 0.5% accuracy */
+		for (cfg.output_rate = rate; cfg.output_rate < 200 * cfreq;
+		      cfg.output_rate <<= 1)
+			p_div++;
+
+		cfg.p = 0x1 << p_div;
+		cfg.m = input_rate / cfreq;
+		cfg.n = cfg.output_rate / cfreq;
+		cfg.cpcon = OUT_OF_TABLE_CPCON;
+
+		if ((cfg.m > (PLL_BASE_DIVM_MASK >> PLL_BASE_DIVM_SHIFT)) ||
+		    (cfg.n > (PLL_BASE_DIVN_MASK >> PLL_BASE_DIVN_SHIFT)) ||
+		    (p_div > (PLL_BASE_DIVP_MASK >> PLL_BASE_DIVP_SHIFT)) ||
+		    (cfg.output_rate > c->u.pll.vco_max)) {
+			pr_err("%s: Failed to set %s out-of-table rate %lu\n",
+			       __func__, c->name, rate);
+			return -EINVAL;
+		}
+		p_div <<= PLL_BASE_DIVP_SHIFT;
+	}
+
+	c->mul = sel->n;
+	c->div = sel->m * sel->p;
+
+	old_base = val = clk_readl(c->reg + PLL_BASE);
+	val &= ~(PLL_BASE_DIVM_MASK | PLL_BASE_DIVN_MASK |
+		 ((c->flags & PLLU) ? PLLU_BASE_POST_DIV : PLL_BASE_DIVP_MASK));
+	val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
+		(sel->n << PLL_BASE_DIVN_SHIFT) | p_div;
+	if (val == old_base)
+		return 0;
+
+	if (c->state == ON) {
+		tegra30_pll_clk_disable(c);
+		val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
+	}
+	clk_writel(val, c->reg + PLL_BASE);
+
+	if (c->flags & PLL_HAS_CPCON) {
+		val = clk_readl(c->reg + PLL_MISC(c));
+		val &= ~PLL_MISC_CPCON_MASK;
+		val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
+		if (c->flags & (PLLU | PLLD)) {
+			val &= ~PLL_MISC_LFCON_MASK;
+			if (sel->n >= PLLDU_LFCON_SET_DIVN)
+				val |= 0x1 << PLL_MISC_LFCON_SHIFT;
+		} else if (c->flags & (PLLX | PLLM)) {
+			val &= ~(0x1 << PLL_MISC_DCCON_SHIFT);
+			if (rate >= (c->u.pll.vco_max >> 1))
+				val |= 0x1 << PLL_MISC_DCCON_SHIFT;
+		}
+		clk_writel(val, c->reg + PLL_MISC(c));
+	}
+
+	if (c->state == ON)
+		tegra30_pll_clk_enable(c);
+
+	return 0;
+}
+
+static struct clk_ops tegra_pll_ops = {
+	.init			= tegra30_pll_clk_init,
+	.enable			= tegra30_pll_clk_enable,
+	.disable		= tegra30_pll_clk_disable,
+	.set_rate		= tegra30_pll_clk_set_rate,
+};
+
+static int
+tegra30_plld_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+	u32 val, mask, reg;
+
+	switch (p) {
+	case TEGRA_CLK_PLLD_CSI_OUT_ENB:
+		mask = PLLD_BASE_CSI_CLKENABLE;
+		reg = c->reg + PLL_BASE;
+		break;
+	case TEGRA_CLK_PLLD_DSI_OUT_ENB:
+		mask = PLLD_MISC_DSI_CLKENABLE;
+		reg = c->reg + PLL_MISC(c);
+		break;
+	case TEGRA_CLK_PLLD_MIPI_MUX_SEL:
+		if (!(c->flags & PLL_ALT_MISC_REG)) {
+			mask = PLLD_BASE_DSIB_MUX_MASK;
+			reg = c->reg + PLL_BASE;
+			break;
+		}
+	/* fall through - error since PLLD2 does not have MUX_SEL control */
+	default:
+		return -EINVAL;
+	}
+
+	val = clk_readl(reg);
+	if (setting)
+		val |= mask;
+	else
+		val &= ~mask;
+	clk_writel(val, reg);
+	return 0;
+}
+
+static struct clk_ops tegra_plld_ops = {
+	.init			= tegra30_pll_clk_init,
+	.enable			= tegra30_pll_clk_enable,
+	.disable		= tegra30_pll_clk_disable,
+	.set_rate		= tegra30_pll_clk_set_rate,
+	.clk_cfg_ex		= tegra30_plld_clk_cfg_ex,
+};
+
+static void tegra30_plle_clk_init(struct clk *c)
+{
+	u32 val;
+
+	val = clk_readl(PLLE_AUX);
+	c->parent = (val & PLLE_AUX_PLLP_SEL) ?
+		tegra_get_clock_by_name("pll_p") :
+		tegra_get_clock_by_name("pll_ref");
+
+	val = clk_readl(c->reg + PLL_BASE);
+	c->state = (val & PLLE_BASE_ENABLE) ? ON : OFF;
+	c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT;
+	c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT;
+	c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT;
+}
+
+static void tegra30_plle_clk_disable(struct clk *c)
+{
+	u32 val;
+	pr_debug("%s on clock %s\n", __func__, c->name);
+
+	val = clk_readl(c->reg + PLL_BASE);
+	val &= ~(PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE);
+	clk_writel(val, c->reg + PLL_BASE);
+}
+
+static void tegra30_plle_training(struct clk *c)
+{
+	u32 val;
+
+	/* PLLE is already disabled, and setup cleared;
+	 * create falling edge on PLLE IDDQ input */
+	val = pmc_readl(PMC_SATA_PWRGT);
+	val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
+	pmc_writel(val, PMC_SATA_PWRGT);
+
+	val = pmc_readl(PMC_SATA_PWRGT);
+	val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL;
+	pmc_writel(val, PMC_SATA_PWRGT);
+
+	val = pmc_readl(PMC_SATA_PWRGT);
+	val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
+	pmc_writel(val, PMC_SATA_PWRGT);
+
+	do {
+		val = clk_readl(c->reg + PLL_MISC(c));
+	} while (!(val & PLLE_MISC_READY));
+}
+
+static int tegra30_plle_configure(struct clk *c, bool force_training)
+{
+	u32 val;
+	const struct clk_pll_freq_table *sel;
+	unsigned long rate = c->u.pll.fixed_rate;
+	unsigned long input_rate = clk_get_rate(c->parent);
+
+	for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+		if (sel->input_rate == input_rate && sel->output_rate == rate)
+			break;
+	}
+
+	if (sel->input_rate == 0)
+		return -ENOSYS;
+
+	/* disable PLLE, clear setup fiels */
+	tegra30_plle_clk_disable(c);
+
+	val = clk_readl(c->reg + PLL_MISC(c));
+	val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK);
+	clk_writel(val, c->reg + PLL_MISC(c));
+
+	/* training */
+	val = clk_readl(c->reg + PLL_MISC(c));
+	if (force_training || (!(val & PLLE_MISC_READY)))
+		tegra30_plle_training(c);
+
+	/* configure dividers, setup, disable SS */
+	val = clk_readl(c->reg + PLL_BASE);
+	val &= ~PLLE_BASE_DIV_MASK;
+	val |= PLLE_BASE_DIV(sel->m, sel->n, sel->p, sel->cpcon);
+	clk_writel(val, c->reg + PLL_BASE);
+	c->mul = sel->n;
+	c->div = sel->m * sel->p;
+
+	val = clk_readl(c->reg + PLL_MISC(c));
+	val |= PLLE_MISC_SETUP_VALUE;
+	val |= PLLE_MISC_LOCK_ENABLE;
+	clk_writel(val, c->reg + PLL_MISC(c));
+
+	val = clk_readl(PLLE_SS_CTRL);
+	val |= PLLE_SS_DISABLE;
+	clk_writel(val, PLLE_SS_CTRL);
+
+	/* enable and lock PLLE*/
+	val = clk_readl(c->reg + PLL_BASE);
+	val |= (PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE);
+	clk_writel(val, c->reg + PLL_BASE);
+
+	tegra30_pll_clk_wait_for_lock(c, c->reg + PLL_MISC(c), PLLE_MISC_LOCK);
+
+	return 0;
+}
+
+static int tegra30_plle_clk_enable(struct clk *c)
+{
+	pr_debug("%s on clock %s\n", __func__, c->name);
+	return tegra30_plle_configure(c, !c->set);
+}
+
+static struct clk_ops tegra_plle_ops = {
+	.init			= tegra30_plle_clk_init,
+	.enable			= tegra30_plle_clk_enable,
+	.disable		= tegra30_plle_clk_disable,
+};
+
+/* Clock divider ops */
+static void tegra30_pll_div_clk_init(struct clk *c)
+{
+	if (c->flags & DIV_U71) {
+		u32 divu71;
+		u32 val = clk_readl(c->reg);
+		val >>= c->reg_shift;
+		c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
+		if (!(val & PLL_OUT_RESET_DISABLE))
+			c->state = OFF;
+
+		divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
+		c->div = (divu71 + 2);
+		c->mul = 2;
+	} else if (c->flags & DIV_2) {
+		c->state = ON;
+		if (c->flags & (PLLD | PLLX)) {
+			c->div = 2;
+			c->mul = 1;
+		} else
+			BUG();
+	} else {
+		c->state = ON;
+		c->div = 1;
+		c->mul = 1;
+	}
+}
+
+static int tegra30_pll_div_clk_enable(struct clk *c)
+{
+	u32 val;
+	u32 new_val;
+
+	pr_debug("%s: %s\n", __func__, c->name);
+	if (c->flags & DIV_U71) {
+		val = clk_readl(c->reg);
+		new_val = val >> c->reg_shift;
+		new_val &= 0xFFFF;
+
+		new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
+
+		val &= ~(0xFFFF << c->reg_shift);
+		val |= new_val << c->reg_shift;
+		clk_writel_delay(val, c->reg);
+		return 0;
+	} else if (c->flags & DIV_2) {
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static void tegra30_pll_div_clk_disable(struct clk *c)
+{
+	u32 val;
+	u32 new_val;
+
+	pr_debug("%s: %s\n", __func__, c->name);
+	if (c->flags & DIV_U71) {
+		val = clk_readl(c->reg);
+		new_val = val >> c->reg_shift;
+		new_val &= 0xFFFF;
+
+		new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE);
+
+		val &= ~(0xFFFF << c->reg_shift);
+		val |= new_val << c->reg_shift;
+		clk_writel_delay(val, c->reg);
+	}
+}
+
+static int tegra30_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	u32 val;
+	u32 new_val;
+	int divider_u71;
+	unsigned long parent_rate = clk_get_rate(c->parent);
+
+	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+	if (c->flags & DIV_U71) {
+		divider_u71 = clk_div71_get_divider(
+			parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
+		if (divider_u71 >= 0) {
+			val = clk_readl(c->reg);
+			new_val = val >> c->reg_shift;
+			new_val &= 0xFFFF;
+			if (c->flags & DIV_U71_FIXED)
+				new_val |= PLL_OUT_OVERRIDE;
+			new_val &= ~PLL_OUT_RATIO_MASK;
+			new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT;
+
+			val &= ~(0xFFFF << c->reg_shift);
+			val |= new_val << c->reg_shift;
+			clk_writel_delay(val, c->reg);
+			c->div = divider_u71 + 2;
+			c->mul = 2;
+			return 0;
+		}
+	} else if (c->flags & DIV_2)
+		return clk_set_rate(c->parent, rate * 2);
+
+	return -EINVAL;
+}
+
+static long tegra30_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
+{
+	int divider;
+	unsigned long parent_rate = clk_get_rate(c->parent);
+	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+	if (c->flags & DIV_U71) {
+		divider = clk_div71_get_divider(
+			parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
+		if (divider < 0)
+			return divider;
+		return DIV_ROUND_UP(parent_rate * 2, divider + 2);
+	} else if (c->flags & DIV_2)
+		/* no rounding - fixed DIV_2 dividers pass rate to parent PLL */
+		return rate;
+
+	return -EINVAL;
+}
+
+static struct clk_ops tegra_pll_div_ops = {
+	.init			= tegra30_pll_div_clk_init,
+	.enable			= tegra30_pll_div_clk_enable,
+	.disable		= tegra30_pll_div_clk_disable,
+	.set_rate		= tegra30_pll_div_clk_set_rate,
+	.round_rate		= tegra30_pll_div_clk_round_rate,
+};
+
+/* Periph clk ops */
+static inline u32 periph_clk_source_mask(struct clk *c)
+{
+	if (c->flags & MUX8)
+		return 7 << 29;
+	else if (c->flags & MUX_PWM)
+		return 3 << 28;
+	else if (c->flags & MUX_CLK_OUT)
+		return 3 << (c->u.periph.clk_num + 4);
+	else if (c->flags & PLLD)
+		return PLLD_BASE_DSIB_MUX_MASK;
+	else
+		return 3 << 30;
+}
+
+static inline u32 periph_clk_source_shift(struct clk *c)
+{
+	if (c->flags & MUX8)
+		return 29;
+	else if (c->flags & MUX_PWM)
+		return 28;
+	else if (c->flags & MUX_CLK_OUT)
+		return c->u.periph.clk_num + 4;
+	else if (c->flags & PLLD)
+		return PLLD_BASE_DSIB_MUX_SHIFT;
+	else
+		return 30;
+}
+
+static void tegra30_periph_clk_init(struct clk *c)
+{
+	u32 val = clk_readl(c->reg);
+	const struct clk_mux_sel *mux = 0;
+	const struct clk_mux_sel *sel;
+	if (c->flags & MUX) {
+		for (sel = c->inputs; sel->input != NULL; sel++) {
+			if (((val & periph_clk_source_mask(c)) >>
+			    periph_clk_source_shift(c)) == sel->value)
+				mux = sel;
+		}
+		BUG_ON(!mux);
+
+		c->parent = mux->input;
+	} else {
+		c->parent = c->inputs[0].input;
+	}
+
+	if (c->flags & DIV_U71) {
+		u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
+		if ((c->flags & DIV_U71_UART) &&
+		    (!(val & PERIPH_CLK_UART_DIV_ENB))) {
+			divu71 = 0;
+		}
+		if (c->flags & DIV_U71_IDLE) {
+			val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK <<
+				PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
+			val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL <<
+				PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
+			clk_writel(val, c->reg);
+		}
+		c->div = divu71 + 2;
+		c->mul = 2;
+	} else if (c->flags & DIV_U16) {
+		u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
+		c->div = divu16 + 1;
+		c->mul = 1;
+	} else {
+		c->div = 1;
+		c->mul = 1;
+	}
+
+	c->state = ON;
+	if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
+		c->state = OFF;
+	if (!(c->flags & PERIPH_NO_RESET))
+		if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & PERIPH_CLK_TO_BIT(c))
+			c->state = OFF;
+}
+
+static int tegra30_periph_clk_enable(struct clk *c)
+{
+	pr_debug("%s on clock %s\n", __func__, c->name);
+
+	tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
+	if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
+		return 0;
+
+	clk_writel_delay(PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_SET_REG(c));
+	if (!(c->flags & PERIPH_NO_RESET) &&
+		 !(c->flags & PERIPH_MANUAL_RESET)) {
+		if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) &
+			 PERIPH_CLK_TO_BIT(c)) {
+			udelay(5);	/* reset propagation delay */
+			clk_writel(PERIPH_CLK_TO_BIT(c),
+				 PERIPH_CLK_TO_RST_CLR_REG(c));
+		}
+	}
+	return 0;
+}
+
+static void tegra30_periph_clk_disable(struct clk *c)
+{
+	unsigned long val;
+	pr_debug("%s on clock %s\n", __func__, c->name);
+
+	if (c->refcnt)
+		tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
+
+	if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] == 0) {
+		/* If peripheral is in the APB bus then read the APB bus to
+		 * flush the write operation in apb bus. This will avoid the
+		 * peripheral access after disabling clock*/
+		if (c->flags & PERIPH_ON_APB)
+			val = chipid_readl();
+
+		clk_writel_delay(
+			PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c));
+	}
+}
+
+static void tegra30_periph_clk_reset(struct clk *c, bool assert)
+{
+	unsigned long val;
+	pr_debug("%s %s on clock %s\n", __func__,
+		 assert ? "assert" : "deassert", c->name);
+
+	if (!(c->flags & PERIPH_NO_RESET)) {
+		if (assert) {
+			/* If peripheral is in the APB bus then read the APB
+			 * bus to flush the write operation in apb bus. This
+			 * will avoid the peripheral access after disabling
+			 * clock */
+			if (c->flags & PERIPH_ON_APB)
+				val = chipid_readl();
+
+			clk_writel(PERIPH_CLK_TO_BIT(c),
+				   PERIPH_CLK_TO_RST_SET_REG(c));
+		} else
+			clk_writel(PERIPH_CLK_TO_BIT(c),
+				   PERIPH_CLK_TO_RST_CLR_REG(c));
+	}
+}
+
+static int tegra30_periph_clk_set_parent(struct clk *c, struct clk *p)
+{
+	u32 val;
+	const struct clk_mux_sel *sel;
+	pr_debug("%s: %s %s\n", __func__, c->name, p->name);
+
+	if (!(c->flags & MUX))
+		return (p == c->parent) ? 0 : (-EINVAL);
+
+	for (sel = c->inputs; sel->input != NULL; sel++) {
+		if (sel->input == p) {
+			val = clk_readl(c->reg);
+			val &= ~periph_clk_source_mask(c);
+			val |= (sel->value << periph_clk_source_shift(c));
+
+			if (c->refcnt)
+				clk_enable(p);
+
+			clk_writel_delay(val, c->reg);
+
+			if (c->refcnt && c->parent)
+				clk_disable(c->parent);
+
+			clk_reparent(c, p);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int tegra30_periph_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	u32 val;
+	int divider;
+	unsigned long parent_rate = clk_get_rate(c->parent);
+
+	if (c->flags & DIV_U71) {
+		divider = clk_div71_get_divider(
+			parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
+		if (divider >= 0) {
+			val = clk_readl(c->reg);
+			val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
+			val |= divider;
+			if (c->flags & DIV_U71_UART) {
+				if (divider)
+					val |= PERIPH_CLK_UART_DIV_ENB;
+				else
+					val &= ~PERIPH_CLK_UART_DIV_ENB;
+			}
+			clk_writel_delay(val, c->reg);
+			c->div = divider + 2;
+			c->mul = 2;
+			return 0;
+		}
+	} else if (c->flags & DIV_U16) {
+		divider = clk_div16_get_divider(parent_rate, rate);
+		if (divider >= 0) {
+			val = clk_readl(c->reg);
+			val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
+			val |= divider;
+			clk_writel_delay(val, c->reg);
+			c->div = divider + 1;
+			c->mul = 1;
+			return 0;
+		}
+	} else if (parent_rate <= rate) {
+		c->div = 1;
+		c->mul = 1;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static long tegra30_periph_clk_round_rate(struct clk *c,
+	unsigned long rate)
+{
+	int divider;
+	unsigned long parent_rate = clk_get_rate(c->parent);
+	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+	if (c->flags & DIV_U71) {
+		divider = clk_div71_get_divider(
+			parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
+		if (divider < 0)
+			return divider;
+
+		return DIV_ROUND_UP(parent_rate * 2, divider + 2);
+	} else if (c->flags & DIV_U16) {
+		divider = clk_div16_get_divider(parent_rate, rate);
+		if (divider < 0)
+			return divider;
+		return DIV_ROUND_UP(parent_rate, divider + 1);
+	}
+	return -EINVAL;
+}
+
+static struct clk_ops tegra_periph_clk_ops = {
+	.init			= &tegra30_periph_clk_init,
+	.enable			= &tegra30_periph_clk_enable,
+	.disable		= &tegra30_periph_clk_disable,
+	.set_parent		= &tegra30_periph_clk_set_parent,
+	.set_rate		= &tegra30_periph_clk_set_rate,
+	.round_rate		= &tegra30_periph_clk_round_rate,
+	.reset			= &tegra30_periph_clk_reset,
+};
+
+
+/* Periph extended clock configuration ops */
+static int
+tegra30_vi_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+	if (p == TEGRA_CLK_VI_INP_SEL) {
+		u32 val = clk_readl(c->reg);
+		val &= ~PERIPH_CLK_VI_SEL_EX_MASK;
+		val |= (setting << PERIPH_CLK_VI_SEL_EX_SHIFT) &
+			PERIPH_CLK_VI_SEL_EX_MASK;
+		clk_writel(val, c->reg);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static struct clk_ops tegra_vi_clk_ops = {
+	.init			= &tegra30_periph_clk_init,
+	.enable			= &tegra30_periph_clk_enable,
+	.disable		= &tegra30_periph_clk_disable,
+	.set_parent		= &tegra30_periph_clk_set_parent,
+	.set_rate		= &tegra30_periph_clk_set_rate,
+	.round_rate		= &tegra30_periph_clk_round_rate,
+	.clk_cfg_ex		= &tegra30_vi_clk_cfg_ex,
+	.reset			= &tegra30_periph_clk_reset,
+};
+
+static int
+tegra30_nand_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+	if (p == TEGRA_CLK_NAND_PAD_DIV2_ENB) {
+		u32 val = clk_readl(c->reg);
+		if (setting)
+			val |= PERIPH_CLK_NAND_DIV_EX_ENB;
+		else
+			val &= ~PERIPH_CLK_NAND_DIV_EX_ENB;
+		clk_writel(val, c->reg);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static struct clk_ops tegra_nand_clk_ops = {
+	.init			= &tegra30_periph_clk_init,
+	.enable			= &tegra30_periph_clk_enable,
+	.disable		= &tegra30_periph_clk_disable,
+	.set_parent		= &tegra30_periph_clk_set_parent,
+	.set_rate		= &tegra30_periph_clk_set_rate,
+	.round_rate		= &tegra30_periph_clk_round_rate,
+	.clk_cfg_ex		= &tegra30_nand_clk_cfg_ex,
+	.reset			= &tegra30_periph_clk_reset,
+};
+
+
+static int
+tegra30_dtv_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+	if (p == TEGRA_CLK_DTV_INVERT) {
+		u32 val = clk_readl(c->reg);
+		if (setting)
+			val |= PERIPH_CLK_DTV_POLARITY_INV;
+		else
+			val &= ~PERIPH_CLK_DTV_POLARITY_INV;
+		clk_writel(val, c->reg);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static struct clk_ops tegra_dtv_clk_ops = {
+	.init			= &tegra30_periph_clk_init,
+	.enable			= &tegra30_periph_clk_enable,
+	.disable		= &tegra30_periph_clk_disable,
+	.set_parent		= &tegra30_periph_clk_set_parent,
+	.set_rate		= &tegra30_periph_clk_set_rate,
+	.round_rate		= &tegra30_periph_clk_round_rate,
+	.clk_cfg_ex		= &tegra30_dtv_clk_cfg_ex,
+	.reset			= &tegra30_periph_clk_reset,
+};
+
+static int tegra30_dsib_clk_set_parent(struct clk *c, struct clk *p)
+{
+	const struct clk_mux_sel *sel;
+	struct clk *d = tegra_get_clock_by_name("pll_d");
+
+	pr_debug("%s: %s %s\n", __func__, c->name, p->name);
+
+	for (sel = c->inputs; sel->input != NULL; sel++) {
+		if (sel->input == p) {
+			if (c->refcnt)
+				clk_enable(p);
+
+			/* The DSIB parent selection bit is in PLLD base
+			   register - can not do direct r-m-w, must be
+			   protected by PLLD lock */
+			tegra_clk_cfg_ex(
+				d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, sel->value);
+
+			if (c->refcnt && c->parent)
+				clk_disable(c->parent);
+
+			clk_reparent(c, p);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static struct clk_ops tegra_dsib_clk_ops = {
+	.init			= &tegra30_periph_clk_init,
+	.enable			= &tegra30_periph_clk_enable,
+	.disable		= &tegra30_periph_clk_disable,
+	.set_parent		= &tegra30_dsib_clk_set_parent,
+	.set_rate		= &tegra30_periph_clk_set_rate,
+	.round_rate		= &tegra30_periph_clk_round_rate,
+	.reset			= &tegra30_periph_clk_reset,
+};
+
+/* pciex clock support only reset function */
+static struct clk_ops tegra_pciex_clk_ops = {
+	.reset    = tegra30_periph_clk_reset,
+};
+
+/* Output clock ops */
+
+static DEFINE_SPINLOCK(clk_out_lock);
+
+static void tegra30_clk_out_init(struct clk *c)
+{
+	const struct clk_mux_sel *mux = 0;
+	const struct clk_mux_sel *sel;
+	u32 val = pmc_readl(c->reg);
+
+	c->state = (val & (0x1 << c->u.periph.clk_num)) ? ON : OFF;
+	c->mul = 1;
+	c->div = 1;
+
+	for (sel = c->inputs; sel->input != NULL; sel++) {
+		if (((val & periph_clk_source_mask(c)) >>
+		     periph_clk_source_shift(c)) == sel->value)
+			mux = sel;
+	}
+	BUG_ON(!mux);
+	c->parent = mux->input;
+}
+
+static int tegra30_clk_out_enable(struct clk *c)
+{
+	u32 val;
+	unsigned long flags;
+
+	pr_debug("%s on clock %s\n", __func__, c->name);
+
+	spin_lock_irqsave(&clk_out_lock, flags);
+	val = pmc_readl(c->reg);
+	val |= (0x1 << c->u.periph.clk_num);
+	pmc_writel(val, c->reg);
+	spin_unlock_irqrestore(&clk_out_lock, flags);
+
+	return 0;
+}
+
+static void tegra30_clk_out_disable(struct clk *c)
+{
+	u32 val;
+	unsigned long flags;
+
+	pr_debug("%s on clock %s\n", __func__, c->name);
+
+	spin_lock_irqsave(&clk_out_lock, flags);
+	val = pmc_readl(c->reg);
+	val &= ~(0x1 << c->u.periph.clk_num);
+	pmc_writel(val, c->reg);
+	spin_unlock_irqrestore(&clk_out_lock, flags);
+}
+
+static int tegra30_clk_out_set_parent(struct clk *c, struct clk *p)
+{
+	u32 val;
+	unsigned long flags;
+	const struct clk_mux_sel *sel;
+
+	pr_debug("%s: %s %s\n", __func__, c->name, p->name);
+
+	for (sel = c->inputs; sel->input != NULL; sel++) {
+		if (sel->input == p) {
+			if (c->refcnt)
+				clk_enable(p);
+
+			spin_lock_irqsave(&clk_out_lock, flags);
+			val = pmc_readl(c->reg);
+			val &= ~periph_clk_source_mask(c);
+			val |= (sel->value << periph_clk_source_shift(c));
+			pmc_writel(val, c->reg);
+			spin_unlock_irqrestore(&clk_out_lock, flags);
+
+			if (c->refcnt && c->parent)
+				clk_disable(c->parent);
+
+			clk_reparent(c, p);
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static struct clk_ops tegra_clk_out_ops = {
+	.init			= &tegra30_clk_out_init,
+	.enable			= &tegra30_clk_out_enable,
+	.disable		= &tegra30_clk_out_disable,
+	.set_parent		= &tegra30_clk_out_set_parent,
+};
+
+
+/* Clock doubler ops */
+static void tegra30_clk_double_init(struct clk *c)
+{
+	u32 val = clk_readl(c->reg);
+	c->mul = val & (0x1 << c->reg_shift) ? 1 : 2;
+	c->div = 1;
+	c->state = ON;
+	if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
+		c->state = OFF;
+};
+
+static int tegra30_clk_double_set_rate(struct clk *c, unsigned long rate)
+{
+	u32 val;
+	unsigned long parent_rate = clk_get_rate(c->parent);
+	if (rate == parent_rate) {
+		val = clk_readl(c->reg) | (0x1 << c->reg_shift);
+		clk_writel(val, c->reg);
+		c->mul = 1;
+		c->div = 1;
+		return 0;
+	} else if (rate == 2 * parent_rate) {
+		val = clk_readl(c->reg) & (~(0x1 << c->reg_shift));
+		clk_writel(val, c->reg);
+		c->mul = 2;
+		c->div = 1;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static struct clk_ops tegra_clk_double_ops = {
+	.init			= &tegra30_clk_double_init,
+	.enable			= &tegra30_periph_clk_enable,
+	.disable		= &tegra30_periph_clk_disable,
+	.set_rate		= &tegra30_clk_double_set_rate,
+};
+
+/* Audio sync clock ops */
+static int tegra30_sync_source_set_rate(struct clk *c, unsigned long rate)
+{
+	c->rate = rate;
+	return 0;
+}
+
+static struct clk_ops tegra_sync_source_ops = {
+	.set_rate		= &tegra30_sync_source_set_rate,
+};
+
+static void tegra30_audio_sync_clk_init(struct clk *c)
+{
+	int source;
+	const struct clk_mux_sel *sel;
+	u32 val = clk_readl(c->reg);
+	c->state = (val & AUDIO_SYNC_DISABLE_BIT) ? OFF : ON;
+	source = val & AUDIO_SYNC_SOURCE_MASK;
+	for (sel = c->inputs; sel->input != NULL; sel++)
+		if (sel->value == source)
+			break;
+	BUG_ON(sel->input == NULL);
+	c->parent = sel->input;
+}
+
+static int tegra30_audio_sync_clk_enable(struct clk *c)
+{
+	u32 val = clk_readl(c->reg);
+	clk_writel((val & (~AUDIO_SYNC_DISABLE_BIT)), c->reg);
+	return 0;
+}
+
+static void tegra30_audio_sync_clk_disable(struct clk *c)
+{
+	u32 val = clk_readl(c->reg);
+	clk_writel((val | AUDIO_SYNC_DISABLE_BIT), c->reg);
+}
+
+static int tegra30_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
+{
+	u32 val;
+	const struct clk_mux_sel *sel;
+	for (sel = c->inputs; sel->input != NULL; sel++) {
+		if (sel->input == p) {
+			val = clk_readl(c->reg);
+			val &= ~AUDIO_SYNC_SOURCE_MASK;
+			val |= sel->value;
+
+			if (c->refcnt)
+				clk_enable(p);
+
+			clk_writel(val, c->reg);
+
+			if (c->refcnt && c->parent)
+				clk_disable(c->parent);
+
+			clk_reparent(c, p);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static struct clk_ops tegra_audio_sync_clk_ops = {
+	.init       = tegra30_audio_sync_clk_init,
+	.enable     = tegra30_audio_sync_clk_enable,
+	.disable    = tegra30_audio_sync_clk_disable,
+	.set_parent = tegra30_audio_sync_clk_set_parent,
+};
+
+/* cml0 (pcie), and cml1 (sata) clock ops */
+static void tegra30_cml_clk_init(struct clk *c)
+{
+	u32 val = clk_readl(c->reg);
+	c->state = val & (0x1 << c->u.periph.clk_num) ? ON : OFF;
+}
+
+static int tegra30_cml_clk_enable(struct clk *c)
+{
+	u32 val = clk_readl(c->reg);
+	val |= (0x1 << c->u.periph.clk_num);
+	clk_writel(val, c->reg);
+	return 0;
+}
+
+static void tegra30_cml_clk_disable(struct clk *c)
+{
+	u32 val = clk_readl(c->reg);
+	val &= ~(0x1 << c->u.periph.clk_num);
+	clk_writel(val, c->reg);
+}
+
+static struct clk_ops tegra_cml_clk_ops = {
+	.init			= &tegra30_cml_clk_init,
+	.enable			= &tegra30_cml_clk_enable,
+	.disable		= &tegra30_cml_clk_disable,
+};
+
+/* Clock definitions */
+static struct clk tegra_clk_32k = {
+	.name = "clk_32k",
+	.rate = 32768,
+	.ops  = NULL,
+	.max_rate = 32768,
+};
+
+static struct clk tegra_clk_m = {
+	.name      = "clk_m",
+	.flags     = ENABLE_ON_INIT,
+	.ops       = &tegra_clk_m_ops,
+	.reg       = 0x1fc,
+	.reg_shift = 28,
+	.max_rate  = 48000000,
+};
+
+static struct clk tegra_clk_m_div2 = {
+	.name      = "clk_m_div2",
+	.ops       = &tegra_clk_m_div_ops,
+	.parent    = &tegra_clk_m,
+	.mul       = 1,
+	.div       = 2,
+	.state     = ON,
+	.max_rate  = 24000000,
+};
+
+static struct clk tegra_clk_m_div4 = {
+	.name      = "clk_m_div4",
+	.ops       = &tegra_clk_m_div_ops,
+	.parent    = &tegra_clk_m,
+	.mul       = 1,
+	.div       = 4,
+	.state     = ON,
+	.max_rate  = 12000000,
+};
+
+static struct clk tegra_pll_ref = {
+	.name      = "pll_ref",
+	.flags     = ENABLE_ON_INIT,
+	.ops       = &tegra_pll_ref_ops,
+	.parent    = &tegra_clk_m,
+	.max_rate  = 26000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
+	{ 12000000, 1040000000, 520,  6, 1, 8},
+	{ 13000000, 1040000000, 480,  6, 1, 8},
+	{ 16800000, 1040000000, 495,  8, 1, 8},		/* actual: 1039.5 MHz */
+	{ 19200000, 1040000000, 325,  6, 1, 6},
+	{ 26000000, 1040000000, 520, 13, 1, 8},
+
+	{ 12000000, 832000000, 416,  6, 1, 8},
+	{ 13000000, 832000000, 832, 13, 1, 8},
+	{ 16800000, 832000000, 396,  8, 1, 8},		/* actual: 831.6 MHz */
+	{ 19200000, 832000000, 260,  6, 1, 8},
+	{ 26000000, 832000000, 416, 13, 1, 8},
+
+	{ 12000000, 624000000, 624, 12, 1, 8},
+	{ 13000000, 624000000, 624, 13, 1, 8},
+	{ 16800000, 600000000, 520, 14, 1, 8},
+	{ 19200000, 624000000, 520, 16, 1, 8},
+	{ 26000000, 624000000, 624, 26, 1, 8},
+
+	{ 12000000, 600000000, 600, 12, 1, 8},
+	{ 13000000, 600000000, 600, 13, 1, 8},
+	{ 16800000, 600000000, 500, 14, 1, 8},
+	{ 19200000, 600000000, 375, 12, 1, 6},
+	{ 26000000, 600000000, 600, 26, 1, 8},
+
+	{ 12000000, 520000000, 520, 12, 1, 8},
+	{ 13000000, 520000000, 520, 13, 1, 8},
+	{ 16800000, 520000000, 495, 16, 1, 8},		/* actual: 519.75 MHz */
+	{ 19200000, 520000000, 325, 12, 1, 6},
+	{ 26000000, 520000000, 520, 26, 1, 8},
+
+	{ 12000000, 416000000, 416, 12, 1, 8},
+	{ 13000000, 416000000, 416, 13, 1, 8},
+	{ 16800000, 416000000, 396, 16, 1, 8},		/* actual: 415.8 MHz */
+	{ 19200000, 416000000, 260, 12, 1, 6},
+	{ 26000000, 416000000, 416, 26, 1, 8},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_c = {
+	.name      = "pll_c",
+	.flags	   = PLL_HAS_CPCON,
+	.ops       = &tegra_pll_ops,
+	.reg       = 0x80,
+	.parent    = &tegra_pll_ref,
+	.max_rate  = 1400000000,
+	.u.pll = {
+		.input_min = 2000000,
+		.input_max = 31000000,
+		.cf_min    = 1000000,
+		.cf_max    = 6000000,
+		.vco_min   = 20000000,
+		.vco_max   = 1400000000,
+		.freq_table = tegra_pll_c_freq_table,
+		.lock_delay = 300,
+	},
+};
+
+static struct clk tegra_pll_c_out1 = {
+	.name      = "pll_c_out1",
+	.ops       = &tegra_pll_div_ops,
+	.flags     = DIV_U71,
+	.parent    = &tegra_pll_c,
+	.reg       = 0x84,
+	.reg_shift = 0,
+	.max_rate  = 700000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
+	{ 12000000, 666000000, 666, 12, 1, 8},
+	{ 13000000, 666000000, 666, 13, 1, 8},
+	{ 16800000, 666000000, 555, 14, 1, 8},
+	{ 19200000, 666000000, 555, 16, 1, 8},
+	{ 26000000, 666000000, 666, 26, 1, 8},
+	{ 12000000, 600000000, 600, 12, 1, 8},
+	{ 13000000, 600000000, 600, 13, 1, 8},
+	{ 16800000, 600000000, 500, 14, 1, 8},
+	{ 19200000, 600000000, 375, 12, 1, 6},
+	{ 26000000, 600000000, 600, 26, 1, 8},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_m = {
+	.name      = "pll_m",
+	.flags     = PLL_HAS_CPCON | PLLM,
+	.ops       = &tegra_pll_ops,
+	.reg       = 0x90,
+	.parent    = &tegra_pll_ref,
+	.max_rate  = 800000000,
+	.u.pll = {
+		.input_min = 2000000,
+		.input_max = 31000000,
+		.cf_min    = 1000000,
+		.cf_max    = 6000000,
+		.vco_min   = 20000000,
+		.vco_max   = 1200000000,
+		.freq_table = tegra_pll_m_freq_table,
+		.lock_delay = 300,
+	},
+};
+
+static struct clk tegra_pll_m_out1 = {
+	.name      = "pll_m_out1",
+	.ops       = &tegra_pll_div_ops,
+	.flags     = DIV_U71,
+	.parent    = &tegra_pll_m,
+	.reg       = 0x94,
+	.reg_shift = 0,
+	.max_rate  = 600000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
+	{ 12000000, 216000000, 432, 12, 2, 8},
+	{ 13000000, 216000000, 432, 13, 2, 8},
+	{ 16800000, 216000000, 360, 14, 2, 8},
+	{ 19200000, 216000000, 360, 16, 2, 8},
+	{ 26000000, 216000000, 432, 26, 2, 8},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_p = {
+	.name      = "pll_p",
+	.flags     = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON,
+	.ops       = &tegra_pll_ops,
+	.reg       = 0xa0,
+	.parent    = &tegra_pll_ref,
+	.max_rate  = 432000000,
+	.u.pll = {
+		.input_min = 2000000,
+		.input_max = 31000000,
+		.cf_min    = 1000000,
+		.cf_max    = 6000000,
+		.vco_min   = 20000000,
+		.vco_max   = 1400000000,
+		.freq_table = tegra_pll_p_freq_table,
+		.lock_delay = 300,
+		.fixed_rate = 408000000,
+	},
+};
+
+static struct clk tegra_pll_p_out1 = {
+	.name      = "pll_p_out1",
+	.ops       = &tegra_pll_div_ops,
+	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+	.parent    = &tegra_pll_p,
+	.reg       = 0xa4,
+	.reg_shift = 0,
+	.max_rate  = 432000000,
+};
+
+static struct clk tegra_pll_p_out2 = {
+	.name      = "pll_p_out2",
+	.ops       = &tegra_pll_div_ops,
+	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+	.parent    = &tegra_pll_p,
+	.reg       = 0xa4,
+	.reg_shift = 16,
+	.max_rate  = 432000000,
+};
+
+static struct clk tegra_pll_p_out3 = {
+	.name      = "pll_p_out3",
+	.ops       = &tegra_pll_div_ops,
+	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+	.parent    = &tegra_pll_p,
+	.reg       = 0xa8,
+	.reg_shift = 0,
+	.max_rate  = 432000000,
+};
+
+static struct clk tegra_pll_p_out4 = {
+	.name      = "pll_p_out4",
+	.ops       = &tegra_pll_div_ops,
+	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+	.parent    = &tegra_pll_p,
+	.reg       = 0xa8,
+	.reg_shift = 16,
+	.max_rate  = 432000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
+	{ 9600000, 564480000, 294, 5, 1, 4},
+	{ 9600000, 552960000, 288, 5, 1, 4},
+	{ 9600000, 24000000,  5,   2, 1, 1},
+
+	{ 28800000, 56448000, 49, 25, 1, 1},
+	{ 28800000, 73728000, 64, 25, 1, 1},
+	{ 28800000, 24000000,  5,  6, 1, 1},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_a = {
+	.name      = "pll_a",
+	.flags     = PLL_HAS_CPCON,
+	.ops       = &tegra_pll_ops,
+	.reg       = 0xb0,
+	.parent    = &tegra_pll_p_out1,
+	.max_rate  = 700000000,
+	.u.pll = {
+		.input_min = 2000000,
+		.input_max = 31000000,
+		.cf_min    = 1000000,
+		.cf_max    = 6000000,
+		.vco_min   = 20000000,
+		.vco_max   = 1400000000,
+		.freq_table = tegra_pll_a_freq_table,
+		.lock_delay = 300,
+	},
+};
+
+static struct clk tegra_pll_a_out0 = {
+	.name      = "pll_a_out0",
+	.ops       = &tegra_pll_div_ops,
+	.flags     = DIV_U71,
+	.parent    = &tegra_pll_a,
+	.reg       = 0xb4,
+	.reg_shift = 0,
+	.max_rate  = 100000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
+	{ 12000000, 216000000, 216, 12, 1, 4},
+	{ 13000000, 216000000, 216, 13, 1, 4},
+	{ 16800000, 216000000, 180, 14, 1, 4},
+	{ 19200000, 216000000, 180, 16, 1, 4},
+	{ 26000000, 216000000, 216, 26, 1, 4},
+
+	{ 12000000, 594000000, 594, 12, 1, 8},
+	{ 13000000, 594000000, 594, 13, 1, 8},
+	{ 16800000, 594000000, 495, 14, 1, 8},
+	{ 19200000, 594000000, 495, 16, 1, 8},
+	{ 26000000, 594000000, 594, 26, 1, 8},
+
+	{ 12000000, 1000000000, 1000, 12, 1, 12},
+	{ 13000000, 1000000000, 1000, 13, 1, 12},
+	{ 19200000, 1000000000, 625,  12, 1, 8},
+	{ 26000000, 1000000000, 1000, 26, 1, 12},
+
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_d = {
+	.name      = "pll_d",
+	.flags     = PLL_HAS_CPCON | PLLD,
+	.ops       = &tegra_plld_ops,
+	.reg       = 0xd0,
+	.parent    = &tegra_pll_ref,
+	.max_rate  = 1000000000,
+	.u.pll = {
+		.input_min = 2000000,
+		.input_max = 40000000,
+		.cf_min    = 1000000,
+		.cf_max    = 6000000,
+		.vco_min   = 40000000,
+		.vco_max   = 1000000000,
+		.freq_table = tegra_pll_d_freq_table,
+		.lock_delay = 1000,
+	},
+};
+
+static struct clk tegra_pll_d_out0 = {
+	.name      = "pll_d_out0",
+	.ops       = &tegra_pll_div_ops,
+	.flags     = DIV_2 | PLLD,
+	.parent    = &tegra_pll_d,
+	.max_rate  = 500000000,
+};
+
+static struct clk tegra_pll_d2 = {
+	.name      = "pll_d2",
+	.flags     = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLD,
+	.ops       = &tegra_plld_ops,
+	.reg       = 0x4b8,
+	.parent    = &tegra_pll_ref,
+	.max_rate  = 1000000000,
+	.u.pll = {
+		.input_min = 2000000,
+		.input_max = 40000000,
+		.cf_min    = 1000000,
+		.cf_max    = 6000000,
+		.vco_min   = 40000000,
+		.vco_max   = 1000000000,
+		.freq_table = tegra_pll_d_freq_table,
+		.lock_delay = 1000,
+	},
+};
+
+static struct clk tegra_pll_d2_out0 = {
+	.name      = "pll_d2_out0",
+	.ops       = &tegra_pll_div_ops,
+	.flags     = DIV_2 | PLLD,
+	.parent    = &tegra_pll_d2,
+	.max_rate  = 500000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
+	{ 12000000, 480000000, 960, 12, 2, 12},
+	{ 13000000, 480000000, 960, 13, 2, 12},
+	{ 16800000, 480000000, 400, 7,  2, 5},
+	{ 19200000, 480000000, 200, 4,  2, 3},
+	{ 26000000, 480000000, 960, 26, 2, 12},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_u = {
+	.name      = "pll_u",
+	.flags     = PLL_HAS_CPCON | PLLU,
+	.ops       = &tegra_pll_ops,
+	.reg       = 0xc0,
+	.parent    = &tegra_pll_ref,
+	.max_rate  = 480000000,
+	.u.pll = {
+		.input_min = 2000000,
+		.input_max = 40000000,
+		.cf_min    = 1000000,
+		.cf_max    = 6000000,
+		.vco_min   = 480000000,
+		.vco_max   = 960000000,
+		.freq_table = tegra_pll_u_freq_table,
+		.lock_delay = 1000,
+	},
+};
+
+static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
+	/* 1.7 GHz */
+	{ 12000000, 1700000000, 850,  6,  1, 8},
+	{ 13000000, 1700000000, 915,  7,  1, 8},	/* actual: 1699.2 MHz */
+	{ 16800000, 1700000000, 708,  7,  1, 8},	/* actual: 1699.2 MHz */
+	{ 19200000, 1700000000, 885,  10, 1, 8},	/* actual: 1699.2 MHz */
+	{ 26000000, 1700000000, 850,  13, 1, 8},
+
+	/* 1.6 GHz */
+	{ 12000000, 1600000000, 800,  6,  1, 8},
+	{ 13000000, 1600000000, 738,  6,  1, 8},	/* actual: 1599.0 MHz */
+	{ 16800000, 1600000000, 857,  9,  1, 8},	/* actual: 1599.7 MHz */
+	{ 19200000, 1600000000, 500,  6,  1, 8},
+	{ 26000000, 1600000000, 800,  13, 1, 8},
+
+	/* 1.5 GHz */
+	{ 12000000, 1500000000, 750,  6,  1, 8},
+	{ 13000000, 1500000000, 923,  8,  1, 8},	/* actual: 1499.8 MHz */
+	{ 16800000, 1500000000, 625,  7,  1, 8},
+	{ 19200000, 1500000000, 625,  8,  1, 8},
+	{ 26000000, 1500000000, 750,  13, 1, 8},
+
+	/* 1.4 GHz */
+	{ 12000000, 1400000000, 700,  6,  1, 8},
+	{ 13000000, 1400000000, 969,  9,  1, 8},	/* actual: 1399.7 MHz */
+	{ 16800000, 1400000000, 1000, 12, 1, 8},
+	{ 19200000, 1400000000, 875,  12, 1, 8},
+	{ 26000000, 1400000000, 700,  13, 1, 8},
+
+	/* 1.3 GHz */
+	{ 12000000, 1300000000, 975,  9,  1, 8},
+	{ 13000000, 1300000000, 1000, 10, 1, 8},
+	{ 16800000, 1300000000, 928,  12, 1, 8},	/* actual: 1299.2 MHz */
+	{ 19200000, 1300000000, 812,  12, 1, 8},	/* actual: 1299.2 MHz */
+	{ 26000000, 1300000000, 650,  13, 1, 8},
+
+	/* 1.2 GHz */
+	{ 12000000, 1200000000, 1000, 10, 1, 8},
+	{ 13000000, 1200000000, 923,  10, 1, 8},	/* actual: 1199.9 MHz */
+	{ 16800000, 1200000000, 1000, 14, 1, 8},
+	{ 19200000, 1200000000, 1000, 16, 1, 8},
+	{ 26000000, 1200000000, 600,  13, 1, 8},
+
+	/* 1.1 GHz */
+	{ 12000000, 1100000000, 825,  9,  1, 8},
+	{ 13000000, 1100000000, 846,  10, 1, 8},	/* actual: 1099.8 MHz */
+	{ 16800000, 1100000000, 982,  15, 1, 8},	/* actual: 1099.8 MHz */
+	{ 19200000, 1100000000, 859,  15, 1, 8},	/* actual: 1099.5 MHz */
+	{ 26000000, 1100000000, 550,  13, 1, 8},
+
+	/* 1 GHz */
+	{ 12000000, 1000000000, 1000, 12, 1, 8},
+	{ 13000000, 1000000000, 1000, 13, 1, 8},
+	{ 16800000, 1000000000, 833,  14, 1, 8},	/* actual: 999.6 MHz */
+	{ 19200000, 1000000000, 625,  12, 1, 8},
+	{ 26000000, 1000000000, 1000, 26, 1, 8},
+
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_x = {
+	.name      = "pll_x",
+	.flags     = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLX,
+	.ops       = &tegra_pll_ops,
+	.reg       = 0xe0,
+	.parent    = &tegra_pll_ref,
+	.max_rate  = 1700000000,
+	.u.pll = {
+		.input_min = 2000000,
+		.input_max = 31000000,
+		.cf_min    = 1000000,
+		.cf_max    = 6000000,
+		.vco_min   = 20000000,
+		.vco_max   = 1700000000,
+		.freq_table = tegra_pll_x_freq_table,
+		.lock_delay = 300,
+	},
+};
+
+static struct clk tegra_pll_x_out0 = {
+	.name      = "pll_x_out0",
+	.ops       = &tegra_pll_div_ops,
+	.flags     = DIV_2 | PLLX,
+	.parent    = &tegra_pll_x,
+	.max_rate  = 850000000,
+};
+
+
+static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
+	/* PLLE special case: use cpcon field to store cml divider value */
+	{ 12000000,  100000000, 150, 1,  18, 11},
+	{ 216000000, 100000000, 200, 18, 24, 13},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_e = {
+	.name      = "pll_e",
+	.flags     = PLL_ALT_MISC_REG,
+	.ops       = &tegra_plle_ops,
+	.reg       = 0xe8,
+	.max_rate  = 100000000,
+	.u.pll = {
+		.input_min = 12000000,
+		.input_max = 216000000,
+		.cf_min    = 12000000,
+		.cf_max    = 12000000,
+		.vco_min   = 1200000000,
+		.vco_max   = 2400000000U,
+		.freq_table = tegra_pll_e_freq_table,
+		.lock_delay = 300,
+		.fixed_rate = 100000000,
+	},
+};
+
+static struct clk tegra_cml0_clk = {
+	.name      = "cml0",
+	.parent    = &tegra_pll_e,
+	.ops       = &tegra_cml_clk_ops,
+	.reg       = PLLE_AUX,
+	.max_rate  = 100000000,
+	.u.periph  = {
+		.clk_num = 0,
+	},
+};
+
+static struct clk tegra_cml1_clk = {
+	.name      = "cml1",
+	.parent    = &tegra_pll_e,
+	.ops       = &tegra_cml_clk_ops,
+	.reg       = PLLE_AUX,
+	.max_rate  = 100000000,
+	.u.periph  = {
+		.clk_num   = 1,
+	},
+};
+
+static struct clk tegra_pciex_clk = {
+	.name      = "pciex",
+	.parent    = &tegra_pll_e,
+	.ops       = &tegra_pciex_clk_ops,
+	.max_rate  = 100000000,
+	.u.periph  = {
+		.clk_num   = 74,
+	},
+};
+
+/* Audio sync clocks */
+#define SYNC_SOURCE(_id)				\
+	{						\
+		.name      = #_id "_sync",		\
+		.rate      = 24000000,			\
+		.max_rate  = 24000000,			\
+		.ops       = &tegra_sync_source_ops	\
+	}
+static struct clk tegra_sync_source_list[] = {
+	SYNC_SOURCE(spdif_in),
+	SYNC_SOURCE(i2s0),
+	SYNC_SOURCE(i2s1),
+	SYNC_SOURCE(i2s2),
+	SYNC_SOURCE(i2s3),
+	SYNC_SOURCE(i2s4),
+	SYNC_SOURCE(vimclk),
+};
+
+static struct clk_mux_sel mux_audio_sync_clk[] = {
+	{ .input = &tegra_sync_source_list[0],	.value = 0},
+	{ .input = &tegra_sync_source_list[1],	.value = 1},
+	{ .input = &tegra_sync_source_list[2],	.value = 2},
+	{ .input = &tegra_sync_source_list[3],	.value = 3},
+	{ .input = &tegra_sync_source_list[4],	.value = 4},
+	{ .input = &tegra_sync_source_list[5],	.value = 5},
+	{ .input = &tegra_pll_a_out0,		.value = 6},
+	{ .input = &tegra_sync_source_list[6],	.value = 7},
+	{ 0, 0 }
+};
+
+#define AUDIO_SYNC_CLK(_id, _index)			\
+	{						\
+		.name      = #_id,			\
+		.inputs    = mux_audio_sync_clk,	\
+		.reg       = 0x4A0 + (_index) * 4,	\
+		.max_rate  = 24000000,			\
+		.ops       = &tegra_audio_sync_clk_ops	\
+	}
+static struct clk tegra_clk_audio_list[] = {
+	AUDIO_SYNC_CLK(audio0, 0),
+	AUDIO_SYNC_CLK(audio1, 1),
+	AUDIO_SYNC_CLK(audio2, 2),
+	AUDIO_SYNC_CLK(audio3, 3),
+	AUDIO_SYNC_CLK(audio4, 4),
+	AUDIO_SYNC_CLK(audio, 5),	/* SPDIF */
+};
+
+#define AUDIO_SYNC_2X_CLK(_id, _index)				\
+	{							\
+		.name      = #_id "_2x",			\
+		.flags     = PERIPH_NO_RESET,			\
+		.max_rate  = 48000000,				\
+		.ops       = &tegra_clk_double_ops,		\
+		.reg       = 0x49C,				\
+		.reg_shift = 24 + (_index),			\
+		.parent    = &tegra_clk_audio_list[(_index)],	\
+		.u.periph = {					\
+			.clk_num = 113 + (_index),		\
+		},						\
+	}
+static struct clk tegra_clk_audio_2x_list[] = {
+	AUDIO_SYNC_2X_CLK(audio0, 0),
+	AUDIO_SYNC_2X_CLK(audio1, 1),
+	AUDIO_SYNC_2X_CLK(audio2, 2),
+	AUDIO_SYNC_2X_CLK(audio3, 3),
+	AUDIO_SYNC_2X_CLK(audio4, 4),
+	AUDIO_SYNC_2X_CLK(audio, 5),	/* SPDIF */
+};
+
+#define MUX_I2S_SPDIF(_id, _index)					\
+static struct clk_mux_sel mux_pllaout0_##_id##_2x_pllp_clkm[] = {	\
+	{.input = &tegra_pll_a_out0, .value = 0},			\
+	{.input = &tegra_clk_audio_2x_list[(_index)], .value = 1},	\
+	{.input = &tegra_pll_p, .value = 2},				\
+	{.input = &tegra_clk_m, .value = 3},				\
+	{ 0, 0},							\
+}
+MUX_I2S_SPDIF(audio0, 0);
+MUX_I2S_SPDIF(audio1, 1);
+MUX_I2S_SPDIF(audio2, 2);
+MUX_I2S_SPDIF(audio3, 3);
+MUX_I2S_SPDIF(audio4, 4);
+MUX_I2S_SPDIF(audio, 5);		/* SPDIF */
+
+/* External clock outputs (through PMC) */
+#define MUX_EXTERN_OUT(_id)						\
+static struct clk_mux_sel mux_clkm_clkm2_clkm4_extern##_id[] = {	\
+	{.input = &tegra_clk_m,		.value = 0},			\
+	{.input = &tegra_clk_m_div2,	.value = 1},			\
+	{.input = &tegra_clk_m_div4,	.value = 2},			\
+	{.input = NULL,			.value = 3}, /* placeholder */	\
+	{ 0, 0},							\
+}
+MUX_EXTERN_OUT(1);
+MUX_EXTERN_OUT(2);
+MUX_EXTERN_OUT(3);
+
+static struct clk_mux_sel *mux_extern_out_list[] = {
+	mux_clkm_clkm2_clkm4_extern1,
+	mux_clkm_clkm2_clkm4_extern2,
+	mux_clkm_clkm2_clkm4_extern3,
+};
+
+#define CLK_OUT_CLK(_id)					\
+	{							\
+		.name      = "clk_out_" #_id,			\
+		.lookup    = {					\
+			.dev_id    = "clk_out_" #_id,		\
+			.con_id	   = "extern" #_id,		\
+		},						\
+		.ops       = &tegra_clk_out_ops,		\
+		.reg       = 0x1a8,				\
+		.inputs    = mux_clkm_clkm2_clkm4_extern##_id,	\
+		.flags     = MUX_CLK_OUT,			\
+		.max_rate  = 216000000,				\
+		.u.periph = {					\
+			.clk_num   = (_id - 1) * 8 + 2,		\
+		},						\
+	}
+static struct clk tegra_clk_out_list[] = {
+	CLK_OUT_CLK(1),
+	CLK_OUT_CLK(2),
+	CLK_OUT_CLK(3),
+};
+
+/* called after peripheral external clocks are initialized */
+static void init_clk_out_mux(void)
+{
+	int i;
+	struct clk *c;
+
+	/* output clock con_id is the name of peripheral
+	   external clock connected to input 3 of the output mux */
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++) {
+		c = tegra_get_clock_by_name(
+			tegra_clk_out_list[i].lookup.con_id);
+		if (!c)
+			pr_err("%s: could not find clk %s\n", __func__,
+			       tegra_clk_out_list[i].lookup.con_id);
+		mux_extern_out_list[i][3].input = c;
+	}
+}
+
+/* Peripheral muxes */
+static struct clk_mux_sel mux_sclk[] = {
+	{ .input = &tegra_clk_m,	.value = 0},
+	{ .input = &tegra_pll_c_out1,	.value = 1},
+	{ .input = &tegra_pll_p_out4,	.value = 2},
+	{ .input = &tegra_pll_p_out3,	.value = 3},
+	{ .input = &tegra_pll_p_out2,	.value = 4},
+	/* { .input = &tegra_clk_d,	.value = 5}, - no use on tegra30 */
+	{ .input = &tegra_clk_32k,	.value = 6},
+	{ .input = &tegra_pll_m_out1,	.value = 7},
+	{ 0, 0},
+};
+
+static struct clk tegra_clk_sclk = {
+	.name	= "sclk",
+	.inputs	= mux_sclk,
+	.reg	= 0x28,
+	.ops	= &tegra_super_ops,
+	.max_rate = 334000000,
+	.min_rate = 40000000,
+};
+
+static struct clk tegra_clk_blink = {
+	.name		= "blink",
+	.parent		= &tegra_clk_32k,
+	.reg		= 0x40,
+	.ops		= &tegra_blink_clk_ops,
+	.max_rate	= 32768,
+};
+
+static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
+	{ .input = &tegra_pll_m, .value = 0},
+	{ .input = &tegra_pll_c, .value = 1},
+	{ .input = &tegra_pll_p, .value = 2},
+	{ .input = &tegra_pll_a_out0, .value = 3},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = {
+	{ .input = &tegra_pll_p, .value = 0},
+	{ .input = &tegra_pll_c, .value = 1},
+	{ .input = &tegra_pll_m, .value = 2},
+	{ .input = &tegra_clk_m, .value = 3},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_clkm[] = {
+	{ .input = &tegra_pll_p, .value = 0},
+	{ .input = &tegra_clk_m, .value = 3},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = {
+	{.input = &tegra_pll_p, .value = 0},
+	{.input = &tegra_pll_d_out0, .value = 1},
+	{.input = &tegra_pll_c, .value = 2},
+	{.input = &tegra_clk_m, .value = 3},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = {
+	{.input = &tegra_pll_p, .value = 0},
+	{.input = &tegra_pll_m, .value = 1},
+	{.input = &tegra_pll_d_out0, .value = 2},
+	{.input = &tegra_pll_a_out0, .value = 3},
+	{.input = &tegra_pll_c, .value = 4},
+	{.input = &tegra_pll_d2_out0, .value = 5},
+	{.input = &tegra_clk_m, .value = 6},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_plla_pllc_pllp_clkm[] = {
+	{ .input = &tegra_pll_a_out0, .value = 0},
+	/* { .input = &tegra_pll_c, .value = 1}, no use on tegra30 */
+	{ .input = &tegra_pll_p, .value = 2},
+	{ .input = &tegra_clk_m, .value = 3},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllc_clk32_clkm[] = {
+	{.input = &tegra_pll_p,     .value = 0},
+	{.input = &tegra_pll_c,     .value = 1},
+	{.input = &tegra_clk_32k,   .value = 2},
+	{.input = &tegra_clk_m,     .value = 3},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllc_clkm_clk32[] = {
+	{.input = &tegra_pll_p,     .value = 0},
+	{.input = &tegra_pll_c,     .value = 1},
+	{.input = &tegra_clk_m,     .value = 2},
+	{.input = &tegra_clk_32k,   .value = 3},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllc_pllm[] = {
+	{.input = &tegra_pll_p,     .value = 0},
+	{.input = &tegra_pll_c,     .value = 1},
+	{.input = &tegra_pll_m,     .value = 2},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_clk_m[] = {
+	{ .input = &tegra_clk_m, .value = 0},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_out3[] = {
+	{ .input = &tegra_pll_p_out3, .value = 0},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_plld_out0[] = {
+	{ .input = &tegra_pll_d_out0, .value = 0},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_plld_out0_plld2_out0[] = {
+	{ .input = &tegra_pll_d_out0,  .value = 0},
+	{ .input = &tegra_pll_d2_out0, .value = 1},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_clk_32k[] = {
+	{ .input = &tegra_clk_32k, .value = 0},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_plla_clk32_pllp_clkm_plle[] = {
+	{ .input = &tegra_pll_a_out0, .value = 0},
+	{ .input = &tegra_clk_32k,    .value = 1},
+	{ .input = &tegra_pll_p,      .value = 2},
+	{ .input = &tegra_clk_m,      .value = 3},
+	{ .input = &tegra_pll_e,      .value = 4},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_cclk_g[] = {
+	{ .input = &tegra_clk_m,        .value = 0},
+	{ .input = &tegra_pll_c,        .value = 1},
+	{ .input = &tegra_clk_32k,      .value = 2},
+	{ .input = &tegra_pll_m,        .value = 3},
+	{ .input = &tegra_pll_p,        .value = 4},
+	{ .input = &tegra_pll_p_out4,   .value = 5},
+	{ .input = &tegra_pll_p_out3,   .value = 6},
+	{ .input = &tegra_pll_x,        .value = 8},
+	{ 0, 0},
+};
+
+static struct clk tegra_clk_cclk_g = {
+	.name	= "cclk_g",
+	.flags	= DIV_U71 | DIV_U71_INT,
+	.inputs = mux_cclk_g,
+	.reg	= 0x368,
+	.ops	= &tegra_super_ops,
+	.max_rate = 1700000000,
+};
+
+static struct clk tegra30_clk_twd = {
+	.parent	  = &tegra_clk_cclk_g,
+	.name     = "twd",
+	.ops      = &tegra30_twd_ops,
+	.max_rate = 1400000000,	/* Same as tegra_clk_cpu_cmplx.max_rate */
+	.mul      = 1,
+	.div      = 2,
+};
+
+#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
+	{						\
+		.name      = _name,			\
+		.lookup    = {				\
+			.dev_id    = _dev,		\
+			.con_id	   = _con,		\
+		},					\
+		.ops       = &tegra_periph_clk_ops,	\
+		.reg       = _reg,			\
+		.inputs    = _inputs,			\
+		.flags     = _flags,			\
+		.max_rate  = _max,			\
+		.u.periph = {				\
+			.clk_num   = _clk_num,		\
+		},					\
+	}
+
+#define PERIPH_CLK_EX(_name, _dev, _con, _clk_num, _reg, _max, _inputs,	\
+			_flags, _ops)					\
+	{						\
+		.name      = _name,			\
+		.lookup    = {				\
+			.dev_id    = _dev,		\
+			.con_id	   = _con,		\
+		},					\
+		.ops       = _ops,			\
+		.reg       = _reg,			\
+		.inputs    = _inputs,			\
+		.flags     = _flags,			\
+		.max_rate  = _max,			\
+		.u.periph = {				\
+			.clk_num   = _clk_num,		\
+		},					\
+	}
+
+#define SHARED_CLK(_name, _dev, _con, _parent, _id, _div, _mode)\
+	{						\
+		.name      = _name,			\
+		.lookup    = {				\
+			.dev_id    = _dev,		\
+			.con_id    = _con,		\
+		},					\
+		.ops       = &tegra_clk_shared_bus_ops,	\
+		.parent = _parent,			\
+		.u.shared_bus_user = {			\
+			.client_id = _id,		\
+			.client_div = _div,		\
+			.mode = _mode,			\
+		},					\
+	}
+struct clk tegra_list_clks[] = {
+	PERIPH_CLK("apbdma",	"tegra-dma",		NULL,	34,	0,	26000000,  mux_clk_m,			0),
+	PERIPH_CLK("rtc",	"rtc-tegra",		NULL,	4,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET | PERIPH_ON_APB),
+	PERIPH_CLK("kbc",	"tegra-kbc",		NULL,	36,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET | PERIPH_ON_APB),
+	PERIPH_CLK("timer",	"timer",		NULL,	5,	0,	26000000,  mux_clk_m,			0),
+	PERIPH_CLK("kfuse",	"kfuse-tegra",		NULL,	40,	0,	26000000,  mux_clk_m,			0),
+	PERIPH_CLK("fuse",	"fuse-tegra",		"fuse",	39,	0,	26000000,  mux_clk_m,			PERIPH_ON_APB),
+	PERIPH_CLK("fuse_burn",	"fuse-tegra",		"fuse_burn",	39,	0,	26000000,  mux_clk_m,		PERIPH_ON_APB),
+	PERIPH_CLK("apbif",	"tegra30-ahub",		"apbif", 107,	0,	26000000,  mux_clk_m,			0),
+	PERIPH_CLK("i2s0",	"tegra30-i2s.0",	NULL,	30,	0x1d8,	26000000,  mux_pllaout0_audio0_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("i2s1",	"tegra30-i2s.1",	NULL,	11,	0x100,	26000000,  mux_pllaout0_audio1_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("i2s2",	"tegra30-i2s.2",	NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("i2s3",	"tegra30-i2s.3",	NULL,	101,	0x3bc,	26000000,  mux_pllaout0_audio3_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("i2s4",	"tegra30-i2s.4",	NULL,	102,	0x3c0,	26000000,  mux_pllaout0_audio4_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("spdif_out",	"tegra30-spdif",	"spdif_out",	10,	0x108,	100000000, mux_pllaout0_audio_2x_pllp_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("spdif_in",	"tegra30-spdif",	"spdif_in",	10,	0x10c,	100000000, mux_pllp_pllc_pllm,		MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("pwm",	"pwm",			NULL,	17,	0x110,	432000000, mux_pllp_pllc_clk32_clkm,	MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("d_audio",	"tegra30-ahub",		"d_audio", 106,	0x3d0,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("dam0",	"tegra30-dam.0",	NULL,   108,	0x3d8,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("dam1",	"tegra30-dam.1",	NULL,   109,	0x3dc,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("dam2",	"tegra30-dam.2",	NULL,   110,	0x3e0,	48000000,  mux_plla_pllc_pllp_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("hda",	"tegra30-hda",		"hda",   125,	0x428,	108000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("hda2codec_2x",	"tegra30-hda",	"hda2codec",   111,	0x3e4,	48000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("hda2hdmi",	"tegra30-hda",		"hda2hdmi",	128,	0,	48000000,  mux_clk_m,			0),
+	PERIPH_CLK("sbc1",	"spi_tegra.0",		NULL,	41,	0x134,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("sbc2",	"spi_tegra.1",		NULL,	44,	0x118,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("sbc3",	"spi_tegra.2",		NULL,	46,	0x11c,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("sbc4",	"spi_tegra.3",		NULL,	68,	0x1b4,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("sbc5",	"spi_tegra.4",		NULL,	104,	0x3c8,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("sbc6",	"spi_tegra.5",		NULL,	105,	0x3cc,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("sata_oob",	"tegra_sata_oob",	NULL,	123,	0x420,	216000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("sata",	"tegra_sata",		NULL,	124,	0x424,	216000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("sata_cold",	"tegra_sata_cold",	NULL,	129,	0,	48000000,  mux_clk_m,			0),
+	PERIPH_CLK_EX("ndflash", "tegra_nand",		NULL,	13,	0x160,	240000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71,	&tegra_nand_clk_ops),
+	PERIPH_CLK("ndspeed",	"tegra_nand_speed",	NULL,	80,	0x3f8,	240000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("vfir",	"vfir",			NULL,	7,	0x168,	72000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("sdmmc1",	"sdhci-tegra.0",	NULL,	14,	0x150,	208000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
+	PERIPH_CLK("sdmmc2",	"sdhci-tegra.1",	NULL,	9,	0x154,	104000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
+	PERIPH_CLK("sdmmc3",	"sdhci-tegra.2",	NULL,	69,	0x1bc,	208000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
+	PERIPH_CLK("sdmmc4",	"sdhci-tegra.3",	NULL,	15,	0x164,	104000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
+	PERIPH_CLK("vcp",	"tegra-avp",		"vcp",	29,	0,	250000000, mux_clk_m,			0),
+	PERIPH_CLK("bsea",	"tegra-avp",		"bsea",	62,	0,	250000000, mux_clk_m,			0),
+	PERIPH_CLK("bsev",	"tegra-aes",		"bsev",	63,	0,	250000000, mux_clk_m,			0),
+	PERIPH_CLK("vde",	"vde",			NULL,	61,	0x1c8,	520000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_INT),
+	PERIPH_CLK("csite",	"csite",		NULL,	73,	0x1d4,	144000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* max rate ??? */
+	PERIPH_CLK("la",	"la",			NULL,	76,	0x1f8,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("owr",	"tegra_w1",		NULL,	71,	0x1cc,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("nor",	"nor",			NULL,	42,	0x1d0,	127000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* requires min voltage */
+	PERIPH_CLK("mipi",	"mipi",			NULL,	50,	0x174,	60000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | PERIPH_ON_APB), /* scales with voltage */
+	PERIPH_CLK("i2c1",	"tegra-i2c.0",		NULL,	12,	0x124,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
+	PERIPH_CLK("i2c2",	"tegra-i2c.1",		NULL,	54,	0x198,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
+	PERIPH_CLK("i2c3",	"tegra-i2c.2",		NULL,	67,	0x1b8,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
+	PERIPH_CLK("i2c4",	"tegra-i2c.3",		NULL,	103,	0x3c4,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
+	PERIPH_CLK("i2c5",	"tegra-i2c.4",		NULL,	47,	0x128,	26000000,  mux_pllp_clkm,		MUX | DIV_U16 | PERIPH_ON_APB),
+	PERIPH_CLK("uarta",	"tegra_uart.0",		NULL,	6,	0x178,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+	PERIPH_CLK("uartb",	"tegra_uart.1",		NULL,	7,	0x17c,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+	PERIPH_CLK("uartc",	"tegra_uart.2",		NULL,	55,	0x1a0,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+	PERIPH_CLK("uartd",	"tegra_uart.3",		NULL,	65,	0x1c0,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+	PERIPH_CLK("uarte",	"tegra_uart.4",		NULL,	66,	0x1c4,	800000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+	PERIPH_CLK("uarta_dbg",	"serial8250.0",		"uarta", 6,	0x178,	800000000, mux_pllp_clkm,		MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+	PERIPH_CLK("uartb_dbg",	"serial8250.0",		"uartb", 7,	0x17c,	800000000, mux_pllp_clkm,		MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+	PERIPH_CLK("uartc_dbg",	"serial8250.0",		"uartc", 55,	0x1a0,	800000000, mux_pllp_clkm,		MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+	PERIPH_CLK("uartd_dbg",	"serial8250.0",		"uartd", 65,	0x1c0,	800000000, mux_pllp_clkm,		MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+	PERIPH_CLK("uarte_dbg",	"serial8250.0",		"uarte", 66,	0x1c4,	800000000, mux_pllp_clkm,		MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+	PERIPH_CLK_EX("vi",	"tegra_camera",		"vi",	20,	0x148,	425000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT,	&tegra_vi_clk_ops),
+	PERIPH_CLK("3d",	"3d",			NULL,	24,	0x158,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
+	PERIPH_CLK("3d2",       "3d2",			NULL,	98,	0x3b0,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
+	PERIPH_CLK("2d",	"2d",			NULL,	21,	0x15c,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE),
+	PERIPH_CLK("vi_sensor",	"tegra_camera",		"vi_sensor",	20,	0x1a8,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_NO_RESET),
+	PERIPH_CLK("epp",	"epp",			NULL,	19,	0x16c,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT),
+	PERIPH_CLK("mpe",	"mpe",			NULL,	60,	0x170,	520000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT),
+	PERIPH_CLK("host1x",	"host1x",		NULL,	28,	0x180,	260000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | DIV_U71_INT),
+	PERIPH_CLK("cve",	"cve",			NULL,	49,	0x140,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
+	PERIPH_CLK("tvo",	"tvo",			NULL,	49,	0x188,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
+	PERIPH_CLK_EX("dtv",	"dtv",			NULL,	79,	0x1dc,	250000000, mux_clk_m,			0,		&tegra_dtv_clk_ops),
+	PERIPH_CLK("hdmi",	"hdmi",			NULL,	51,	0x18c,	148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,	MUX | MUX8 | DIV_U71),
+	PERIPH_CLK("tvdac",	"tvdac",		NULL,	53,	0x194,	220000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
+	PERIPH_CLK("disp1",	"tegradc.0",		NULL,	27,	0x138,	600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,	MUX | MUX8),
+	PERIPH_CLK("disp2",	"tegradc.1",		NULL,	26,	0x13c,	600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,	MUX | MUX8),
+	PERIPH_CLK("usbd",	"fsl-tegra-udc",	NULL,	22,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
+	PERIPH_CLK("usb2",	"tegra-ehci.1",		NULL,	58,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
+	PERIPH_CLK("usb3",	"tegra-ehci.2",		NULL,	59,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
+	PERIPH_CLK("dsia",	"tegradc.0",		"dsia",	48,	0,	500000000, mux_plld_out0,		0),
+	PERIPH_CLK_EX("dsib",	"tegradc.1",		"dsib",	82,	0xd0,	500000000, mux_plld_out0_plld2_out0,	MUX | PLLD,	&tegra_dsib_clk_ops),
+	PERIPH_CLK("csi",	"tegra_camera",		"csi",	52,	0,	102000000, mux_pllp_out3,		0),
+	PERIPH_CLK("isp",	"tegra_camera",		"isp",	23,	0,	150000000, mux_clk_m,			0), /* same frequency as VI */
+	PERIPH_CLK("csus",	"tegra_camera",		"csus",	92,	0,	150000000, mux_clk_m,			PERIPH_NO_RESET),
+
+	PERIPH_CLK("tsensor",	"tegra-tsensor",	NULL,	100,	0x3b8,	216000000, mux_pllp_pllc_clkm_clk32,	MUX | DIV_U71),
+	PERIPH_CLK("actmon",	"actmon",		NULL,	119,	0x3e8,	216000000, mux_pllp_pllc_clk32_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("extern1",	"extern1",		NULL,	120,	0x3ec,	216000000, mux_plla_clk32_pllp_clkm_plle,	MUX | MUX8 | DIV_U71),
+	PERIPH_CLK("extern2",	"extern2",		NULL,	121,	0x3f0,	216000000, mux_plla_clk32_pllp_clkm_plle,	MUX | MUX8 | DIV_U71),
+	PERIPH_CLK("extern3",	"extern3",		NULL,	122,	0x3f4,	216000000, mux_plla_clk32_pllp_clkm_plle,	MUX | MUX8 | DIV_U71),
+	PERIPH_CLK("i2cslow",	"i2cslow",		NULL,	81,	0x3fc,	26000000,  mux_pllp_pllc_clk32_clkm,	MUX | DIV_U71 | PERIPH_ON_APB),
+	PERIPH_CLK("pcie",	"tegra-pcie",		"pcie",	70,	0,	250000000, mux_clk_m,			0),
+	PERIPH_CLK("afi",	"tegra-pcie",		"afi",	72,	0,	250000000, mux_clk_m,			0),
+	PERIPH_CLK("se",	"se",			NULL,	127,	0x42c,	520000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71 | DIV_U71_INT),
+};
+
+#define CLK_DUPLICATE(_name, _dev, _con)		\
+	{						\
+		.name	= _name,			\
+		.lookup	= {				\
+			.dev_id	= _dev,			\
+			.con_id		= _con,		\
+		},					\
+	}
+
+/* Some clocks may be used by different drivers depending on the board
+ * configuration.  List those here to register them twice in the clock lookup
+ * table under two names.
+ */
+struct clk_duplicate tegra_clk_duplicates[] = {
+	CLK_DUPLICATE("usbd", "utmip-pad", NULL),
+	CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
+	CLK_DUPLICATE("usbd", "tegra-otg", NULL),
+	CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
+	CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
+	CLK_DUPLICATE("dsib", "tegradc.0", "dsib"),
+	CLK_DUPLICATE("dsia", "tegradc.1", "dsia"),
+	CLK_DUPLICATE("pwm", "tegra_pwm.0", NULL),
+	CLK_DUPLICATE("pwm", "tegra_pwm.1", NULL),
+	CLK_DUPLICATE("pwm", "tegra_pwm.2", NULL),
+	CLK_DUPLICATE("pwm", "tegra_pwm.3", NULL),
+	CLK_DUPLICATE("bsev", "tegra-avp", "bsev"),
+	CLK_DUPLICATE("bsev", "nvavp", "bsev"),
+	CLK_DUPLICATE("vde", "tegra-aes", "vde"),
+	CLK_DUPLICATE("bsea", "tegra-aes", "bsea"),
+	CLK_DUPLICATE("bsea", "nvavp", "bsea"),
+	CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL),
+	CLK_DUPLICATE("cml0", "tegra_pcie", "cml"),
+	CLK_DUPLICATE("pciex", "tegra_pcie", "pciex"),
+	CLK_DUPLICATE("i2c1", "tegra-i2c-slave.0", NULL),
+	CLK_DUPLICATE("i2c2", "tegra-i2c-slave.1", NULL),
+	CLK_DUPLICATE("i2c3", "tegra-i2c-slave.2", NULL),
+	CLK_DUPLICATE("i2c4", "tegra-i2c-slave.3", NULL),
+	CLK_DUPLICATE("i2c5", "tegra-i2c-slave.4", NULL),
+	CLK_DUPLICATE("sbc1", "spi_slave_tegra.0", NULL),
+	CLK_DUPLICATE("sbc2", "spi_slave_tegra.1", NULL),
+	CLK_DUPLICATE("sbc3", "spi_slave_tegra.2", NULL),
+	CLK_DUPLICATE("sbc4", "spi_slave_tegra.3", NULL),
+	CLK_DUPLICATE("sbc5", "spi_slave_tegra.4", NULL),
+	CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL),
+	CLK_DUPLICATE("twd", "smp_twd", NULL),
+	CLK_DUPLICATE("vcp", "nvavp", "vcp"),
+};
+
+struct clk *tegra_ptr_clks[] = {
+	&tegra_clk_32k,
+	&tegra_clk_m,
+	&tegra_clk_m_div2,
+	&tegra_clk_m_div4,
+	&tegra_pll_ref,
+	&tegra_pll_m,
+	&tegra_pll_m_out1,
+	&tegra_pll_c,
+	&tegra_pll_c_out1,
+	&tegra_pll_p,
+	&tegra_pll_p_out1,
+	&tegra_pll_p_out2,
+	&tegra_pll_p_out3,
+	&tegra_pll_p_out4,
+	&tegra_pll_a,
+	&tegra_pll_a_out0,
+	&tegra_pll_d,
+	&tegra_pll_d_out0,
+	&tegra_pll_d2,
+	&tegra_pll_d2_out0,
+	&tegra_pll_u,
+	&tegra_pll_x,
+	&tegra_pll_x_out0,
+	&tegra_pll_e,
+	&tegra_clk_cclk_g,
+	&tegra_cml0_clk,
+	&tegra_cml1_clk,
+	&tegra_pciex_clk,
+	&tegra_clk_sclk,
+	&tegra_clk_blink,
+	&tegra30_clk_twd,
+};
+
+
+static void tegra30_init_one_clock(struct clk *c)
+{
+	clk_init(c);
+	INIT_LIST_HEAD(&c->shared_bus_list);
+	if (!c->lookup.dev_id && !c->lookup.con_id)
+		c->lookup.con_id = c->name;
+	c->lookup.clk = c;
+	clkdev_add(&c->lookup);
+}
+
+void __init tegra30_init_clocks(void)
+{
+	int i;
+	struct clk *c;
+
+	for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
+		tegra30_init_one_clock(tegra_ptr_clks[i]);
+
+	for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
+		tegra30_init_one_clock(&tegra_list_clks[i]);
+
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
+		c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
+		if (!c) {
+			pr_err("%s: Unknown duplicate clock %s\n", __func__,
+				tegra_clk_duplicates[i].name);
+			continue;
+		}
+
+		tegra_clk_duplicates[i].lookup.clk = c;
+		clkdev_add(&tegra_clk_duplicates[i].lookup);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(tegra_sync_source_list); i++)
+		tegra30_init_one_clock(&tegra_sync_source_list[i]);
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_list); i++)
+		tegra30_init_one_clock(&tegra_clk_audio_list[i]);
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_2x_list); i++)
+		tegra30_init_one_clock(&tegra_clk_audio_2x_list[i]);
+
+	init_clk_out_mux();
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++)
+		tegra30_init_one_clock(&tegra_clk_out_list[i]);
+
+}
diff --git a/arch/arm/mach-tegra/timer.c b/arch/arm/mach-tegra/timer.c
index 1d1acda..1eed8d4 100644
--- a/arch/arm/mach-tegra/timer.c
+++ b/arch/arm/mach-tegra/timer.c
@@ -28,7 +28,7 @@
 #include <linux/io.h>
 
 #include <asm/mach/time.h>
-#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
 #include <asm/sched_clock.h>
 
 #include <mach/iomap.h>
@@ -162,6 +162,21 @@
 	.irq		= INT_TMR3,
 };
 
+#ifdef CONFIG_HAVE_ARM_TWD
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
+			      TEGRA_ARM_PERIF_BASE + 0x600,
+			      IRQ_LOCALTIMER);
+
+static void __init tegra_twd_init(void)
+{
+	int err = twd_local_timer_register(&twd_local_timer);
+	if (err)
+		pr_err("twd_local_timer_register failed %d\n", err);
+}
+#else
+#define tegra_twd_init()	do {} while(0)
+#endif
+
 static void __init tegra_init_timer(void)
 {
 	struct clk *clk;
@@ -188,10 +203,6 @@
 	else
 		clk_enable(clk);
 
-#ifdef CONFIG_HAVE_ARM_TWD
-	twd_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x600);
-#endif
-
 	switch (rate) {
 	case 12000000:
 		timer_writel(0x000b, TIMERUS_USEC_CFG);
@@ -231,6 +242,7 @@
 	tegra_clockevent.cpumask = cpu_all_mask;
 	tegra_clockevent.irq = tegra_timer_irq.irq;
 	clockevents_register_device(&tegra_clockevent);
+	tegra_twd_init();
 }
 
 struct sys_timer tegra_timer = {
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
index ad321f9..c5b2ac0 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -22,6 +22,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/err.h>
+#include <linux/export.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
@@ -730,6 +731,7 @@
 	kfree(phy);
 	return ERR_PTR(err);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_open);
 
 int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
 {
@@ -738,6 +740,7 @@
 	else
 		return utmi_phy_power_on(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_power_on);
 
 void tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
 {
@@ -746,18 +749,21 @@
 	else
 		utmi_phy_power_off(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_power_off);
 
 void tegra_usb_phy_preresume(struct tegra_usb_phy *phy)
 {
 	if (!phy_is_ulpi(phy))
 		utmi_phy_preresume(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume);
 
 void tegra_usb_phy_postresume(struct tegra_usb_phy *phy)
 {
 	if (!phy_is_ulpi(phy))
 		utmi_phy_postresume(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume);
 
 void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
 				 enum tegra_usb_phy_port_speed port_speed)
@@ -765,24 +771,28 @@
 	if (!phy_is_ulpi(phy))
 		utmi_phy_restore_start(phy, port_speed);
 }
+EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start);
 
 void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy)
 {
 	if (!phy_is_ulpi(phy))
 		utmi_phy_restore_end(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end);
 
 void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy)
 {
 	if (!phy_is_ulpi(phy))
 		utmi_phy_clk_disable(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_disable);
 
 void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy)
 {
 	if (!phy_is_ulpi(phy))
 		utmi_phy_clk_enable(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_enable);
 
 void tegra_usb_phy_close(struct tegra_usb_phy *phy)
 {
@@ -794,3 +804,4 @@
 	clk_put(phy->pll_u);
 	kfree(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_close);
diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile
index 2855381..fd3a5c3 100644
--- a/arch/arm/mach-u300/Makefile
+++ b/arch/arm/mach-u300/Makefile
@@ -8,7 +8,6 @@
 obj-		:=
 
 obj-$(CONFIG_ARCH_U300)	          += u300.o
-obj-$(CONFIG_MMC)                 += mmc.o
 obj-$(CONFIG_SPI_PL022)           += spi.o
 obj-$(CONFIG_MACH_U300_SPIDUMMY)  += dummyspichip.o
 obj-$(CONFIG_I2C_STU300)          += i2c.o
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c
index b4c6926..1621ad0 100644
--- a/arch/arm/mach-u300/core.c
+++ b/arch/arm/mach-u300/core.c
@@ -18,6 +18,7 @@
 #include <linux/termios.h>
 #include <linux/dmaengine.h>
 #include <linux/amba/bus.h>
+#include <linux/amba/mmci.h>
 #include <linux/amba/serial.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
@@ -26,7 +27,8 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/fsmc.h>
 #include <linux/pinctrl/machine.h>
-#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinconf-generic.h>
 #include <linux/dma-mapping.h>
 
 #include <asm/types.h>
@@ -43,9 +45,9 @@
 #include <mach/gpio-u300.h>
 
 #include "clock.h"
-#include "mmc.h"
 #include "spi.h"
 #include "i2c.h"
+#include "u300-gpio.h"
 
 /*
  * Static I/O mappings that are needed for booting the U300 platforms. The
@@ -94,19 +96,9 @@
 #endif
 };
 
-static struct amba_device uart0_device = {
-	.dev = {
-		.coherent_dma_mask = ~0,
-		.init_name = "uart0", /* Slow device at 0x3000 offset */
-		.platform_data = &uart0_plat_data,
-	},
-	.res = {
-		.start = U300_UART0_BASE,
-		.end   = U300_UART0_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	.irq = { IRQ_U300_UART0, NO_IRQ },
-};
+/* Slow device at 0x3000 offset */
+static AMBA_APB_DEVICE(uart0, "uart0", 0, U300_UART0_BASE,
+	{ IRQ_U300_UART0 }, &uart0_plat_data);
 
 /* The U335 have an additional UART1 on the APP CPU */
 #ifdef CONFIG_MACH_U300_BS335
@@ -118,71 +110,41 @@
 #endif
 };
 
-static struct amba_device uart1_device = {
-	.dev = {
-		.coherent_dma_mask = ~0,
-		.init_name = "uart1", /* Fast device at 0x7000 offset */
-		.platform_data = &uart1_plat_data,
-	},
-	.res = {
-		.start = U300_UART1_BASE,
-		.end   = U300_UART1_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	.irq = { IRQ_U300_UART1, NO_IRQ },
-};
+/* Fast device at 0x7000 offset */
+static AMBA_APB_DEVICE(uart1, "uart1", 0, U300_UART1_BASE,
+	{ IRQ_U300_UART1 }, &uart1_plat_data);
 #endif
 
-static struct amba_device pl172_device = {
-	.dev = {
-		.init_name = "pl172", /* AHB device at 0x4000 offset */
-		.platform_data = NULL,
-	},
-	.res = {
-		.start = U300_EMIF_CFG_BASE,
-		.end   = U300_EMIF_CFG_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	},
-};
+/* AHB device at 0x4000 offset */
+static AMBA_APB_DEVICE(pl172, "pl172", 0, U300_EMIF_CFG_BASE, { }, NULL);
 
+/* Fast device at 0x6000 offset */
+static AMBA_APB_DEVICE(pl022, "pl022", 0, U300_SPI_BASE,
+	{ IRQ_U300_SPI }, NULL);
 
-/*
- * Everything within this next ifdef deals with external devices connected to
- * the APP SPI bus.
- */
-static struct amba_device pl022_device = {
-	.dev = {
-		.coherent_dma_mask = ~0,
-		.init_name = "pl022", /* Fast device at 0x6000 offset */
-	},
-	.res = {
-		.start = U300_SPI_BASE,
-		.end   = U300_SPI_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	.irq = {IRQ_U300_SPI, NO_IRQ },
+/* Fast device at 0x1000 offset */
+#define U300_MMCSD_IRQS	{ IRQ_U300_MMCSD_MCIINTR0, IRQ_U300_MMCSD_MCIINTR1 }
+
+static struct mmci_platform_data mmcsd_platform_data = {
 	/*
-	 * This device has a DMA channel but the Linux driver does not use
-	 * it currently.
+	 * Do not set ocr_mask or voltage translation function,
+	 * we have a regulator we can control instead.
 	 */
+	.f_max = 24000000,
+	.gpio_wp = -1,
+	.gpio_cd = U300_GPIO_PIN_MMC_CD,
+	.cd_invert = true,
+	.capabilities = MMC_CAP_MMC_HIGHSPEED |
+	MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+#ifdef CONFIG_COH901318
+	.dma_filter = coh901318_filter_id,
+	.dma_rx_param = (void *) U300_DMA_MMCSD_RX_TX,
+	/* Don't specify a TX channel, this RX channel is bidirectional */
+#endif
 };
 
-static struct amba_device mmcsd_device = {
-	.dev = {
-		.init_name = "mmci", /* Fast device at 0x1000 offset */
-		.platform_data = NULL, /* Added later */
-	},
-	.res = {
-		.start = U300_MMCSD_BASE,
-		.end   = U300_MMCSD_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	.irq = {IRQ_U300_MMCSD_MCIINTR0, IRQ_U300_MMCSD_MCIINTR1 },
-	/*
-	 * This device has a DMA channel but the Linux driver does not use
-	 * it currently.
-	 */
-};
+static AMBA_APB_DEVICE(mmcsd, "mmci", 0, U300_MMCSD_BASE,
+	U300_MMCSD_IRQS, &mmcsd_platform_data);
 
 /*
  * The order of device declaration may be important, since some devices
@@ -1477,7 +1439,7 @@
 	.max_channels = U300_DMA_CHANNELS,
 };
 
-static struct resource pinmux_resources[] = {
+static struct resource pinctrl_resources[] = {
 	{
 		.start = U300_SYSCON_BASE,
 		.end   = U300_SYSCON_BASE + SZ_4K - 1,
@@ -1506,6 +1468,13 @@
 	.resource = i2c1_resources,
 };
 
+static struct platform_device pinctrl_device = {
+	.name = "pinctrl-u300",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(pinctrl_resources),
+	.resource = pinctrl_resources,
+};
+
 /*
  * The different variants have a few different versions of the
  * GPIO block, with different number of ports.
@@ -1525,6 +1494,7 @@
 #endif
 	.gpio_base = 0,
 	.gpio_irq_base = IRQ_U300_GPIO_BASE,
+	.pinctrl_device = &pinctrl_device,
 };
 
 static struct platform_device gpio_device = {
@@ -1574,6 +1544,8 @@
 	.nr_partitions = ARRAY_SIZE(u300_partitions),
 	.options = NAND_SKIP_BBTSCAN,
 	.width = FSMC_NAND_BW8,
+	.ale_off = PLAT_NAND_ALE,
+	.cle_off = PLAT_NAND_CLE,
 };
 
 static struct platform_device nand_device = {
@@ -1597,71 +1569,67 @@
 	},
 };
 
-static struct platform_device pinmux_device = {
-	.name = "pinmux-u300",
-	.id = -1,
-	.num_resources = ARRAY_SIZE(pinmux_resources),
-	.resource = pinmux_resources,
+static unsigned long pin_pullup_conf[] = {
+	PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_UP, 1),
 };
 
-/* Pinmux settings */
-static struct pinmux_map __initdata u300_pinmux_map[] = {
+static unsigned long pin_highz_conf[] = {
+	PIN_CONF_PACKED(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0),
+};
+
+/* Pin control settings */
+static struct pinctrl_map __initdata u300_pinmux_map[] = {
 	/* anonymous maps for chip power and EMIFs */
-	PINMUX_MAP_SYS_HOG("POWER", "pinmux-u300", "power"),
-	PINMUX_MAP_SYS_HOG("EMIF0", "pinmux-u300", "emif0"),
-	PINMUX_MAP_SYS_HOG("EMIF1", "pinmux-u300", "emif1"),
+	PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-u300", NULL, "power"),
+	PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-u300", NULL, "emif0"),
+	PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-u300", NULL, "emif1"),
 	/* per-device maps for MMC/SD, SPI and UART */
-	PINMUX_MAP("MMCSD", "pinmux-u300", "mmc0", "mmci"),
-	PINMUX_MAP("SPI", "pinmux-u300", "spi0", "pl022"),
-	PINMUX_MAP("UART0", "pinmux-u300", "uart0", "uart0"),
+	PIN_MAP_MUX_GROUP_DEFAULT("mmci",  "pinctrl-u300", NULL, "mmc0"),
+	PIN_MAP_MUX_GROUP_DEFAULT("pl022", "pinctrl-u300", NULL, "spi0"),
+	PIN_MAP_MUX_GROUP_DEFAULT("uart0", "pinctrl-u300", NULL, "uart0"),
+	/* This pin is used for clock return rather than GPIO */
+	PIN_MAP_CONFIGS_PIN_DEFAULT("mmci", "pinctrl-u300", "PIO APP GPIO 11",
+				    pin_pullup_conf),
+	/* This pin is used for card detect */
+	PIN_MAP_CONFIGS_PIN_DEFAULT("mmci", "pinctrl-u300", "PIO MS INS",
+				    pin_highz_conf),
 };
 
 struct u300_mux_hog {
-	const char *name;
 	struct device *dev;
-	struct pinmux *pmx;
+	struct pinctrl *p;
 };
 
 static struct u300_mux_hog u300_mux_hogs[] = {
 	{
-		.name = "uart0",
 		.dev = &uart0_device.dev,
 	},
 	{
-		.name = "spi0",
 		.dev = &pl022_device.dev,
 	},
 	{
-		.name = "mmc0",
 		.dev = &mmcsd_device.dev,
 	},
 };
 
-static int __init u300_pinmux_fetch(void)
+static int __init u300_pinctrl_fetch(void)
 {
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(u300_mux_hogs); i++) {
-		struct pinmux *pmx;
-		int ret;
+		struct pinctrl *p;
 
-		pmx = pinmux_get(u300_mux_hogs[i].dev, NULL);
-		if (IS_ERR(pmx)) {
-			pr_err("u300: could not get pinmux hog %s\n",
-			       u300_mux_hogs[i].name);
+		p = pinctrl_get_select_default(u300_mux_hogs[i].dev);
+		if (IS_ERR(p)) {
+			pr_err("u300: could not get pinmux hog for dev %s\n",
+			       dev_name(u300_mux_hogs[i].dev));
 			continue;
 		}
-		ret = pinmux_enable(pmx);
-		if (ret) {
-			pr_err("u300: could enable pinmux hog %s\n",
-			       u300_mux_hogs[i].name);
-			continue;
-		}
-		u300_mux_hogs[i].pmx = pmx;
+		u300_mux_hogs[i].p = p;
 	}
 	return 0;
 }
-subsys_initcall(u300_pinmux_fetch);
+subsys_initcall(u300_pinctrl_fetch);
 
 /*
  * Notice that AMBA devices are initialized before platform devices.
@@ -1676,7 +1644,6 @@
 	&gpio_device,
 	&nand_device,
 	&wdog_device,
-	&pinmux_device,
 };
 
 /*
@@ -1861,8 +1828,8 @@
 	u300_assign_physmem();
 
 	/* Initialize pinmuxing */
-	pinmux_register_mappings(u300_pinmux_map,
-				 ARRAY_SIZE(u300_pinmux_map));
+	pinctrl_register_mappings(u300_pinmux_map,
+				  ARRAY_SIZE(u300_pinmux_map));
 
 	/* Register subdevices on the I2C buses */
 	u300_i2c_register_board_devices();
@@ -1879,16 +1846,6 @@
 	writew(val, U300_SYSCON_VBASE + U300_SYSCON_SMCR);
 }
 
-static int core_module_init(void)
-{
-	/*
-	 * This needs to be initialized later: it needs the input framework
-	 * to be initialized first.
-	 */
-	return mmc_init(&mmcsd_device);
-}
-module_init(core_module_init);
-
 /* Forward declare this function from the watchdog */
 void coh901327_watchdog_reset(void);
 
diff --git a/arch/arm/mach-u300/include/mach/entry-macro.S b/arch/arm/mach-u300/include/mach/entry-macro.S
deleted file mode 100644
index 7181d6a..0000000
--- a/arch/arm/mach-u300/include/mach/entry-macro.S
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *
- * arch-arm/mach-u300/include/mach/entry-macro.S
- *
- *
- * Copyright (C) 2006-2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * Low-level IRQ helper macros for ST-Ericsson U300
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-
-	.macro	disable_fiq
-	.endm
-
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
diff --git a/arch/arm/mach-u300/include/mach/gpio-u300.h b/arch/arm/mach-u300/include/mach/gpio-u300.h
index bf4c793..e81400c 100644
--- a/arch/arm/mach-u300/include/mach/gpio-u300.h
+++ b/arch/arm/mach-u300/include/mach/gpio-u300.h
@@ -24,12 +24,14 @@
  * @ports: number of GPIO block ports
  * @gpio_base: first GPIO number for this block (use a free range)
  * @gpio_irq_base: first GPIO IRQ number for this block (use a free range)
+ * @pinctrl_device: pin control device to spawn as child
  */
 struct u300_gpio_platform {
 	enum u300_gpio_variant variant;
 	u8 ports;
 	int gpio_base;
 	int gpio_irq_base;
+	struct platform_device *pinctrl_device;
 };
 
 #endif /* __MACH_U300_GPIO_U300_H */
diff --git a/arch/arm/mach-u300/include/mach/io.h b/arch/arm/mach-u300/include/mach/io.h
deleted file mode 100644
index 5d6b4c1..0000000
--- a/arch/arm/mach-u300/include/mach/io.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/include/mach/io.h
- *
- *
- * Copyright (C) 2006-2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * Dummy IO map for being able to use writew()/readw(),
- * writel()/readw() and similar accessor functions.
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-#ifndef __MACH_IO_H
-#define __MACH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#endif
diff --git a/arch/arm/mach-u300/include/mach/system.h b/arch/arm/mach-u300/include/mach/system.h
deleted file mode 100644
index 574d46e..0000000
--- a/arch/arm/mach-u300/include/mach/system.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/include/mach/system.h
- *
- *
- * Copyright (C) 2007-2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * System shutdown and reset functions.
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
diff --git a/arch/arm/mach-u300/include/mach/u300-regs.h b/arch/arm/mach-u300/include/mach/u300-regs.h
index 035fdc9..65f87c5 100644
--- a/arch/arm/mach-u300/include/mach/u300-regs.h
+++ b/arch/arm/mach-u300/include/mach/u300-regs.h
@@ -18,18 +18,17 @@
  * the defines are used for setting up the I/O memory mapping.
  */
 
-#ifdef __ASSEMBLER__
-#define IOMEM(a) (a)
-#else
-#define IOMEM(a) (void __iomem *) a
-#endif
-
 /* NAND Flash CS0 */
 #define U300_NAND_CS0_PHYS_BASE		0x80000000
 
 /* NFIF */
 #define U300_NAND_IF_PHYS_BASE		0x9f800000
 
+/* ALE, CLE offset for FSMC NAND */
+#define PLAT_NAND_CLE			(1 << 16)
+#define PLAT_NAND_ALE			(1 << 17)
+
+
 /* AHB Peripherals */
 #define U300_AHB_PER_PHYS_BASE		0xa0000000
 #define U300_AHB_PER_VIRT_BASE		0xff010000
diff --git a/arch/arm/mach-u300/mmc.c b/arch/arm/mach-u300/mmc.c
deleted file mode 100644
index 05abd6a..0000000
--- a/arch/arm/mach-u300/mmc.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/mmc.c
- *
- *
- * Copyright (C) 2009 ST-Ericsson SA
- * License terms: GNU General Public License (GPL) version 2
- *
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- * Author: Johan Lundin
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
- */
-#include <linux/device.h>
-#include <linux/amba/bus.h>
-#include <linux/mmc/host.h>
-#include <linux/dmaengine.h>
-#include <linux/amba/mmci.h>
-#include <linux/slab.h>
-#include <mach/coh901318.h>
-#include <mach/dma_channels.h>
-
-#include "u300-gpio.h"
-#include "mmc.h"
-
-static struct mmci_platform_data mmc0_plat_data = {
-	/*
-	 * Do not set ocr_mask or voltage translation function,
-	 * we have a regulator we can control instead.
-	 */
-	/* Nominally 2.85V on our platform */
-	.f_max = 24000000,
-	.gpio_wp = -1,
-	.gpio_cd = U300_GPIO_PIN_MMC_CD,
-	.cd_invert = true,
-	.capabilities = MMC_CAP_MMC_HIGHSPEED |
-	MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
-#ifdef CONFIG_COH901318
-	.dma_filter = coh901318_filter_id,
-	.dma_rx_param = (void *) U300_DMA_MMCSD_RX_TX,
-	/* Don't specify a TX channel, this RX channel is bidirectional */
-#endif
-};
-
-int __devinit mmc_init(struct amba_device *adev)
-{
-	struct device *mmcsd_device = &adev->dev;
-	int ret = 0;
-
-	mmcsd_device->platform_data = &mmc0_plat_data;
-
-	return ret;
-}
diff --git a/arch/arm/mach-u300/mmc.h b/arch/arm/mach-u300/mmc.h
deleted file mode 100644
index 92b8512..0000000
--- a/arch/arm/mach-u300/mmc.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/mmc.h
- *
- *
- * Copyright (C) 2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- *
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
- */
-#ifndef MMC_H
-#define MMC_H
-
-#include <linux/amba/bus.h>
-
-int __devinit mmc_init(struct amba_device *adev);
-
-#endif
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index c59e8b8..880d02e 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -8,47 +8,62 @@
 	select PL310_ERRATA_753970
 	select ARM_ERRATA_754322
 	select ARM_ERRATA_764369
-
-menu "Ux500 SoC"
+	select CACHE_L2X0
 
 config UX500_SOC_DB5500
-	bool "DB5500"
+	bool
 	select MFD_DB5500_PRCMU
 
 config UX500_SOC_DB8500
-	bool "DB8500"
+	bool
 	select MFD_DB8500_PRCMU
 	select REGULATOR_DB8500_PRCMU
-
-endmenu
+	select CPU_FREQ_TABLE if CPU_FREQ
 
 menu "Ux500 target platform (boards)"
 
-config MACH_U8500
-	bool "U8500 Development platform"
-	depends on UX500_SOC_DB8500
-	select TPS6105X
+config MACH_MOP500
+	bool "U8500 Development platform, MOP500 versions"
+	select UX500_SOC_DB8500
+	select I2C
+	select I2C_NOMADIK
+	select SOC_BUS
 	help
-	  Include support for the mop500 development platform.
+	  Include support for the MOP500 development platform.
 
 config MACH_HREFV60
-       bool "U85000 Development platform, HREFv60 version"
-       depends on UX500_SOC_DB8500
-       help
-         Include support for the HREFv60 new development platform.
+	bool "U8500 Development platform, HREFv60 version"
+	select MACH_MOP500
+	help
+	  Include support for the HREFv60 new development platform.
+	  Includes HREFv70, v71 etc.
 
 config MACH_SNOWBALL
 	bool "U8500 Snowball platform"
-	depends on UX500_SOC_DB8500
-	select MACH_U8500
+	select MACH_MOP500
 	help
 	  Include support for the snowball development platform.
 
 config MACH_U5500
 	bool "U5500 Development platform"
-	depends on UX500_SOC_DB5500
+	select UX500_SOC_DB5500
 	help
 	  Include support for the U5500 development platform.
+
+config UX500_AUTO_PLATFORM
+	def_bool y
+	depends on !MACH_U5500
+	select MACH_MOP500
+	help
+	  At least one platform needs to be selected in order to build
+	  a working kernel. If everything else is disabled, this
+	  automatically enables MACH_MOP500.
+
+config MACH_UX500_DT
+	bool "Generic U8500 support using device tree"
+	depends on MACH_MOP500
+	select USE_OF
+
 endmenu
 
 config UX500_DEBUG_UART
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index 6bd2f45..465b9ec 100644
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -7,7 +7,7 @@
 obj-$(CONFIG_CACHE_L2X0)	+= cache-l2x0.o
 obj-$(CONFIG_UX500_SOC_DB5500)	+= cpu-db5500.o dma-db5500.o
 obj-$(CONFIG_UX500_SOC_DB8500)	+= cpu-db8500.o devices-db8500.o
-obj-$(CONFIG_MACH_U8500)	+= board-mop500.o board-mop500-sdi.o \
+obj-$(CONFIG_MACH_MOP500)	+= board-mop500.o board-mop500-sdi.o \
 				board-mop500-regulators.o \
 				board-mop500-uib.o board-mop500-stuib.o \
 				board-mop500-u8500uib.o \
@@ -15,7 +15,6 @@
 obj-$(CONFIG_MACH_U5500)	+= board-u5500.o board-u5500-sdi.o
 obj-$(CONFIG_SMP)		+= platsmp.o headsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)	+= hotplug.o
-obj-$(CONFIG_LOCAL_TIMERS)	+= localtimer.o
 obj-$(CONFIG_U5500_MODEM_IRQ)	+= modem-irq-db5500.o
 obj-$(CONFIG_U5500_MBOX)	+= mbox-db5500.o
 
diff --git a/arch/arm/mach-ux500/Makefile.boot b/arch/arm/mach-ux500/Makefile.boot
index ff0a4b5..dd5cd00 100644
--- a/arch/arm/mach-ux500/Makefile.boot
+++ b/arch/arm/mach-ux500/Makefile.boot
@@ -2,3 +2,4 @@
 params_phys-y	:= 0x00000100
 initrd_phys-y	:= 0x00800000
 
+dtb-$(CONFIG_MACH_SNOWBALL) += snowball.dtb
diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c
index 74bfcff..f5413dc 100644
--- a/arch/arm/mach-ux500/board-mop500-pins.c
+++ b/arch/arm/mach-ux500/board-mop500-pins.c
@@ -6,6 +6,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/bug.h>
 
 #include <asm/mach-types.h>
 #include <plat/pincfg.h>
diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c
index 2735d03..52426a4 100644
--- a/arch/arm/mach-ux500/board-mop500-regulators.c
+++ b/arch/arm/mach-ux500/board-mop500-regulators.c
@@ -74,6 +74,26 @@
 	REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"),
 };
 
+static struct regulator_consumer_supply ab8500_vaud_consumers[] = {
+	/* AB8500 audio-codec main supply */
+	REGULATOR_SUPPLY("vaud", "ab8500-codec.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vamic1_consumers[] = {
+	/* AB8500 audio-codec Mic1 supply */
+	REGULATOR_SUPPLY("vamic1", "ab8500-codec.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vamic2_consumers[] = {
+	/* AB8500 audio-codec Mic2 supply */
+	REGULATOR_SUPPLY("vamic2", "ab8500-codec.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vdmic_consumers[] = {
+	/* AB8500 audio-codec DMic supply */
+	REGULATOR_SUPPLY("vdmic", "ab8500-codec.0"),
+};
+
 static struct regulator_consumer_supply ab8500_vintcore_consumers[] = {
 	/* SoC core supply, no device */
 	REGULATOR_SUPPLY("v-intcore", NULL),
@@ -323,6 +343,8 @@
 			.name = "V-AUD",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
 		},
+		.num_consumer_supplies = ARRAY_SIZE(ab8500_vaud_consumers),
+		.consumer_supplies = ab8500_vaud_consumers,
 	},
 	/* supply for v-anamic1 VAMic1-LDO */
 	[AB8500_LDO_ANAMIC1] = {
@@ -330,6 +352,8 @@
 			.name = "V-AMIC1",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
 		},
+		.num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers),
+		.consumer_supplies = ab8500_vamic1_consumers,
 	},
 	/* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
 	[AB8500_LDO_ANAMIC2] = {
@@ -337,6 +361,8 @@
 			.name = "V-AMIC2",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
 		},
+		.num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers),
+		.consumer_supplies = ab8500_vamic2_consumers,
 	},
 	/* supply for v-dmic, VDMIC LDO */
 	[AB8500_LDO_DMIC] = {
@@ -344,6 +370,8 @@
 			.name = "V-DMIC",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
 		},
+		.num_consumer_supplies = ARRAY_SIZE(ab8500_vdmic_consumers),
+		.consumer_supplies = ab8500_vdmic_consumers,
 	},
 	/* supply for v-intcore12, VINTCORE12 LDO */
 	[AB8500_LDO_INTCORE] = {
diff --git a/arch/arm/mach-ux500/board-mop500-sdi.c b/arch/arm/mach-ux500/board-mop500-sdi.c
index 5dde4d4..920251c 100644
--- a/arch/arm/mach-ux500/board-mop500-sdi.c
+++ b/arch/arm/mach-ux500/board-mop500-sdi.c
@@ -31,21 +31,13 @@
  * SDI 0 (MicroSD slot)
  */
 
-/* MMCIPOWER bits */
-#define MCI_DATA2DIREN		(1 << 2)
-#define MCI_CMDDIREN		(1 << 3)
-#define MCI_DATA0DIREN		(1 << 4)
-#define MCI_DATA31DIREN		(1 << 5)
-#define MCI_FBCLKEN		(1 << 7)
-
 /* GPIO pins used by the sdi0 level shifter */
 static int sdi0_en = -1;
 static int sdi0_vsel = -1;
 
-static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd,
-				   unsigned char power_mode)
+static int mop500_sdi0_ios_handler(struct device *dev, struct mmc_ios *ios)
 {
-	switch (power_mode) {
+	switch (ios->power_mode) {
 	case MMC_POWER_UP:
 	case MMC_POWER_ON:
 		/*
@@ -65,8 +57,7 @@
 		break;
 	}
 
-	return MCI_FBCLKEN | MCI_CMDDIREN | MCI_DATA0DIREN |
-	       MCI_DATA2DIREN | MCI_DATA31DIREN;
+	return 0;
 }
 
 #ifdef CONFIG_STE_DMA40
@@ -90,13 +81,17 @@
 #endif
 
 static struct mmci_platform_data mop500_sdi0_data = {
-	.vdd_handler	= mop500_sdi0_vdd_handler,
+	.ios_handler	= mop500_sdi0_ios_handler,
 	.ocr_mask	= MMC_VDD_29_30,
 	.f_max		= 50000000,
 	.capabilities	= MMC_CAP_4_BIT_DATA |
 				MMC_CAP_SD_HIGHSPEED |
 				MMC_CAP_MMC_HIGHSPEED,
 	.gpio_wp	= -1,
+	.sigdir		= MCI_ST_FBCLKEN |
+				MCI_ST_CMDDIREN |
+				MCI_ST_DATA0DIREN |
+				MCI_ST_DATA2DIREN,
 #ifdef CONFIG_STE_DMA40
 	.dma_filter	= stedma40_filter,
 	.dma_rx_param	= &mop500_sdi0_dma_cfg_rx,
@@ -104,7 +99,7 @@
 #endif
 };
 
-static void sdi0_configure(void)
+static void sdi0_configure(struct device *parent)
 {
 	int ret;
 
@@ -123,15 +118,15 @@
 	gpio_direction_output(sdi0_en, 1);
 
 	/* Add the device, force v2 to subrevision 1 */
-	db8500_add_sdi0(&mop500_sdi0_data, U8500_SDI_V2_PERIPHID);
+	db8500_add_sdi0(parent, &mop500_sdi0_data, U8500_SDI_V2_PERIPHID);
 }
 
-void mop500_sdi_tc35892_init(void)
+void mop500_sdi_tc35892_init(struct device *parent)
 {
 	mop500_sdi0_data.gpio_cd = GPIO_SDMMC_CD;
 	sdi0_en = GPIO_SDMMC_EN;
 	sdi0_vsel = GPIO_SDMMC_1V8_3V_SEL;
-	sdi0_configure();
+	sdi0_configure(parent);
 }
 
 /*
@@ -246,12 +241,13 @@
 #endif
 };
 
-void __init mop500_sdi_init(void)
+void __init mop500_sdi_init(struct device *parent)
 {
 	/* PoP:ed eMMC */
-	db8500_add_sdi2(&mop500_sdi2_data, U8500_SDI_V2_PERIPHID);
+	db8500_add_sdi2(parent, &mop500_sdi2_data, U8500_SDI_V2_PERIPHID);
 	/* On-board eMMC */
-	db8500_add_sdi4(&mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
+	db8500_add_sdi4(parent, &mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
+
 	/*
 	 * On boards with the TC35892 GPIO expander, sdi0 will finally
 	 * be added when the TC35892 initializes and calls
@@ -259,31 +255,31 @@
 	 */
 }
 
-void __init snowball_sdi_init(void)
+void __init snowball_sdi_init(struct device *parent)
 {
 	/* On Snowball MMC_CAP_SD_HIGHSPEED isn't supported (Hardware issue?) */
 	mop500_sdi0_data.capabilities &= ~MMC_CAP_SD_HIGHSPEED;
 	/* On-board eMMC */
-	db8500_add_sdi4(&mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
+	db8500_add_sdi4(parent, &mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
 	/* External Micro SD slot */
 	mop500_sdi0_data.gpio_cd = SNOWBALL_SDMMC_CD_GPIO;
 	mop500_sdi0_data.cd_invert = true;
 	sdi0_en = SNOWBALL_SDMMC_EN_GPIO;
 	sdi0_vsel = SNOWBALL_SDMMC_1V8_3V_GPIO;
-	sdi0_configure();
+	sdi0_configure(parent);
 }
 
-void __init hrefv60_sdi_init(void)
+void __init hrefv60_sdi_init(struct device *parent)
 {
 	/* PoP:ed eMMC */
-	db8500_add_sdi2(&mop500_sdi2_data, U8500_SDI_V2_PERIPHID);
+	db8500_add_sdi2(parent, &mop500_sdi2_data, U8500_SDI_V2_PERIPHID);
 	/* On-board eMMC */
-	db8500_add_sdi4(&mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
+	db8500_add_sdi4(parent, &mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
 	/* External Micro SD slot */
 	mop500_sdi0_data.gpio_cd = HREFV60_SDMMC_CD_GPIO;
 	sdi0_en = HREFV60_SDMMC_EN_GPIO;
 	sdi0_vsel = HREFV60_SDMMC_1V8_3V_GPIO;
-	sdi0_configure();
+	sdi0_configure(parent);
 	/* WLAN SDIO channel */
-	db8500_add_sdi1(&mop500_sdi1_data, U8500_SDI_V2_PERIPHID);
+	db8500_add_sdi1(parent, &mop500_sdi1_data, U8500_SDI_V2_PERIPHID);
 }
diff --git a/arch/arm/mach-ux500/board-mop500-u8500uib.c b/arch/arm/mach-ux500/board-mop500-u8500uib.c
index feb5744..ead91c9 100644
--- a/arch/arm/mach-ux500/board-mop500-u8500uib.c
+++ b/arch/arm/mach-ux500/board-mop500-u8500uib.c
@@ -8,7 +8,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
-#include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/mfd/tc3589x.h>
 #include <linux/input/matrix_keypad.h>
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index 5c00712..77d03c1 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -30,6 +30,9 @@
 #include <linux/gpio_keys.h>
 #include <linux/delay.h>
 
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
 #include <linux/leds.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -72,7 +75,7 @@
 };
 
 static struct ab8500_gpio_platform_data ab8500_gpio_pdata = {
-	.gpio_base		= MOP500_AB8500_GPIO(0),
+	.gpio_base		= MOP500_AB8500_PIN_GPIO(1),
 	.irq_base		= MOP500_AB8500_VIR_GPIO_IRQ_BASE,
 	/* config_reg is the initial configuration of ab8500 pins.
 	 * The pins can be configured as GPIO or alt functions based
@@ -226,7 +229,12 @@
 
 static void mop500_tc35892_init(struct tc3589x *tc3589x, unsigned int base)
 {
-	mop500_sdi_tc35892_init();
+	struct device *parent = NULL;
+#if 0
+	/* FIXME: Is the sdi actually part of tc3589x? */
+	parent = tc3589x->dev;
+#endif
+	mop500_sdi_tc35892_init(parent);
 }
 
 static struct tc3589x_gpio_platform_data mop500_tc35892_gpio_data = {
@@ -353,12 +361,12 @@
 U8500_I2C_CONTROLLER(2,	0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
 U8500_I2C_CONTROLLER(3,	0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
 
-static void __init mop500_i2c_init(void)
+static void __init mop500_i2c_init(struct device *parent)
 {
-	db8500_add_i2c0(&u8500_i2c0_data);
-	db8500_add_i2c1(&u8500_i2c1_data);
-	db8500_add_i2c2(&u8500_i2c2_data);
-	db8500_add_i2c3(&u8500_i2c3_data);
+	db8500_add_i2c0(parent, &u8500_i2c0_data);
+	db8500_add_i2c1(parent, &u8500_i2c1_data);
+	db8500_add_i2c2(parent, &u8500_i2c2_data);
+	db8500_add_i2c3(parent, &u8500_i2c3_data);
 }
 
 static struct gpio_keys_button mop500_gpio_keys[] = {
@@ -435,7 +443,7 @@
 };
 #endif
 
-static struct pl022_ssp_controller ssp0_platform_data = {
+static struct pl022_ssp_controller ssp0_plat = {
 	.bus_id = 0,
 #ifdef CONFIG_STE_DMA40
 	.enable_dma = 1,
@@ -451,9 +459,9 @@
 	.num_chipselect = 5,
 };
 
-static void __init mop500_spi_init(void)
+static void __init mop500_spi_init(struct device *parent)
 {
-	db8500_add_ssp0(&ssp0_platform_data);
+	db8500_add_ssp0(parent, &ssp0_plat);
 }
 
 #ifdef CONFIG_STE_DMA40
@@ -587,11 +595,11 @@
 #endif
 };
 
-static void __init mop500_uart_init(void)
+static void __init mop500_uart_init(struct device *parent)
 {
-	db8500_add_uart0(&uart0_plat);
-	db8500_add_uart1(&uart1_plat);
-	db8500_add_uart2(&uart2_plat);
+	db8500_add_uart0(parent, &uart0_plat);
+	db8500_add_uart1(parent, &uart1_plat);
+	db8500_add_uart2(parent, &uart2_plat);
 }
 
 static struct platform_device *snowball_platform_devs[] __initdata = {
@@ -603,21 +611,27 @@
 
 static void __init mop500_init_machine(void)
 {
+	struct device *parent = NULL;
 	int i2c0_devs;
+	int i;
 
 	mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR;
 
-	u8500_init_devices();
+	parent = u8500_init_devices();
 
 	mop500_pins_init();
 
+	/* FIXME: parent of ab8500 should be prcmu */
+	for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
+		mop500_platform_devs[i]->dev.parent = parent;
+
 	platform_add_devices(mop500_platform_devs,
 			ARRAY_SIZE(mop500_platform_devs));
 
-	mop500_i2c_init();
-	mop500_sdi_init();
-	mop500_spi_init();
-	mop500_uart_init();
+	mop500_i2c_init(parent);
+	mop500_sdi_init(parent);
+	mop500_spi_init(parent);
+	mop500_uart_init(parent);
 
 	i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
 
@@ -631,19 +645,24 @@
 
 static void __init snowball_init_machine(void)
 {
+	struct device *parent = NULL;
 	int i2c0_devs;
+	int i;
 
-	u8500_init_devices();
+	parent = u8500_init_devices();
 
 	snowball_pins_init();
 
+	for (i = 0; i < ARRAY_SIZE(snowball_platform_devs); i++)
+		snowball_platform_devs[i]->dev.parent = parent;
+
 	platform_add_devices(snowball_platform_devs,
 			ARRAY_SIZE(snowball_platform_devs));
 
-	mop500_i2c_init();
-	snowball_sdi_init();
-	mop500_spi_init();
-	mop500_uart_init();
+	mop500_i2c_init(parent);
+	snowball_sdi_init(parent);
+	mop500_spi_init(parent);
+	mop500_uart_init(parent);
 
 	i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
 	i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
@@ -656,7 +675,9 @@
 
 static void __init hrefv60_init_machine(void)
 {
+	struct device *parent = NULL;
 	int i2c0_devs;
+	int i;
 
 	/*
 	 * The HREFv60 board removed a GPIO expander and routed
@@ -665,17 +686,20 @@
 	 */
 	mop500_gpio_keys[0].gpio = HREFV60_PROX_SENSE_GPIO;
 
-	u8500_init_devices();
+	parent = u8500_init_devices();
 
 	hrefv60_pins_init();
 
+	for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
+		mop500_platform_devs[i]->dev.parent = parent;
+
 	platform_add_devices(mop500_platform_devs,
 			ARRAY_SIZE(mop500_platform_devs));
 
-	mop500_i2c_init();
-	hrefv60_sdi_init();
-	mop500_spi_init();
-	mop500_uart_init();
+	mop500_i2c_init(parent);
+	hrefv60_sdi_init(parent);
+	mop500_spi_init(parent);
+	mop500_uart_init(parent);
 
 	i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
 
@@ -718,3 +742,94 @@
 	.handle_irq	= gic_handle_irq,
 	.init_machine	= snowball_init_machine,
 MACHINE_END
+
+#ifdef CONFIG_MACH_UX500_DT
+
+struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("arm,pl011", 0x80120000, "uart0", &uart0_plat),
+	OF_DEV_AUXDATA("arm,pl011", 0x80121000, "uart1", &uart1_plat),
+	OF_DEV_AUXDATA("arm,pl011", 0x80007000, "uart2", &uart2_plat),
+	OF_DEV_AUXDATA("arm,pl022", 0x80002000, "ssp0",  &ssp0_plat),
+	{},
+};
+
+static const struct of_device_id u8500_soc_node[] = {
+	/* only create devices below soc node */
+	{ .compatible = "stericsson,db8500", },
+	{ },
+};
+
+static void __init u8500_init_machine(void)
+{
+	struct device *parent = NULL;
+	int i2c0_devs;
+	int i;
+
+	parent = u8500_init_devices();
+	i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
+
+	for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
+		mop500_platform_devs[i]->dev.parent = parent;
+	for (i = 0; i < ARRAY_SIZE(snowball_platform_devs); i++)
+		snowball_platform_devs[i]->dev.parent = parent;
+
+	/* automatically probe child nodes of db8500 device */
+	of_platform_populate(NULL, u8500_soc_node, u8500_auxdata_lookup, parent);
+
+	if (of_machine_is_compatible("st-ericsson,mop500")) {
+		mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR;
+		mop500_pins_init();
+
+		platform_add_devices(mop500_platform_devs,
+				ARRAY_SIZE(mop500_platform_devs));
+
+		mop500_sdi_init(parent);
+	} else if (of_machine_is_compatible("calaosystems,snowball-a9500")) {
+		snowball_pins_init();
+		platform_add_devices(snowball_platform_devs,
+				ARRAY_SIZE(snowball_platform_devs));
+
+		snowball_sdi_init(parent);
+	} else if (of_machine_is_compatible("st-ericsson,hrefv60+")) {
+		/*
+		 * The HREFv60 board removed a GPIO expander and routed
+		 * all these GPIO pins to the internal GPIO controller
+		 * instead.
+		 */
+		mop500_gpio_keys[0].gpio = HREFV60_PROX_SENSE_GPIO;
+		i2c0_devs -= NUM_PRE_V60_I2C0_DEVICES;
+		hrefv60_pins_init();
+		platform_add_devices(mop500_platform_devs,
+				ARRAY_SIZE(mop500_platform_devs));
+
+		hrefv60_sdi_init(parent);
+	}
+	mop500_i2c_init(parent);
+
+	i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
+	i2c_register_board_info(2, mop500_i2c2_devices,
+				ARRAY_SIZE(mop500_i2c2_devices));
+
+	/* This board has full regulator constraints */
+	regulator_has_full_constraints();
+}
+
+static const char * u8500_dt_board_compat[] = {
+	"calaosystems,snowball-a9500",
+	"st-ericsson,hrefv60+",
+	"st-ericsson,u8500",
+	"st-ericsson,mop500",
+	NULL,
+};
+
+
+DT_MACHINE_START(U8500_DT, "ST-Ericsson U8500 platform (Device Tree Support)")
+	.map_io		= u8500_map_io,
+	.init_irq	= ux500_init_irq,
+	/* we re-use nomadik timer here */
+	.timer		= &ux500_timer,
+	.handle_irq	= gic_handle_irq,
+	.init_machine	= u8500_init_machine,
+	.dt_compat      = u8500_dt_board_compat,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h
index f926d3d..fdcfa87 100644
--- a/arch/arm/mach-ux500/board-mop500.h
+++ b/arch/arm/mach-ux500/board-mop500.h
@@ -63,7 +63,7 @@
  * because the AB8500 GPIO pins are enumbered starting from 1, so the value in
  * parens matches the GPIO pin number in the data sheet.
  */
-#define MOP500_AB8500_GPIO(x)		(MOP500_EGPIO_END + (x) - 1)
+#define MOP500_AB8500_PIN_GPIO(x)	(MOP500_EGPIO_END + (x) - 1)
 /*Snowball AB8500 GPIO */
 #define SNOWBALL_VSMPS2_1V8_GPIO	MOP500_AB8500_PIN_GPIO(1)	/* SYSCLKREQ2/GPIO1 */
 #define SNOWBALL_PM_GPIO1_GPIO		MOP500_AB8500_PIN_GPIO(2)	/* SYSCLKREQ3/GPIO2 */
@@ -75,10 +75,10 @@
 
 struct i2c_board_info;
 
-extern void mop500_sdi_init(void);
-extern void snowball_sdi_init(void);
-extern void hrefv60_sdi_init(void);
-extern void mop500_sdi_tc35892_init(void);
+extern void mop500_sdi_init(struct device *parent);
+extern void snowball_sdi_init(struct device *parent);
+extern void hrefv60_sdi_init(struct device *parent);
+extern void mop500_sdi_tc35892_init(struct device *parent);
 void __init mop500_u8500uib_init(void);
 void __init mop500_stuib_init(void);
 void __init mop500_pins_init(void);
diff --git a/arch/arm/mach-ux500/board-u5500-sdi.c b/arch/arm/mach-ux500/board-u5500-sdi.c
index 63c3f80..836112e 100644
--- a/arch/arm/mach-ux500/board-u5500-sdi.c
+++ b/arch/arm/mach-ux500/board-u5500-sdi.c
@@ -66,9 +66,9 @@
 #endif
 };
 
-void __init u5500_sdi_init(void)
+void __init u5500_sdi_init(struct device *parent)
 {
 	nmk_config_pins(u5500_sdi_pins, ARRAY_SIZE(u5500_sdi_pins));
 
-	db5500_add_sdi0(&u5500_sdi0_data);
+	db5500_add_sdi0(parent, &u5500_sdi0_data);
 }
diff --git a/arch/arm/mach-ux500/board-u5500.c b/arch/arm/mach-ux500/board-u5500.c
index 9de9e9c..0ff4be7 100644
--- a/arch/arm/mach-ux500/board-u5500.c
+++ b/arch/arm/mach-ux500/board-u5500.c
@@ -97,9 +97,9 @@
 	},
 };
 
-static void __init u5500_i2c_init(void)
+static void __init u5500_i2c_init(struct device *parent)
 {
-	db5500_add_i2c2(&u5500_i2c2_data);
+	db5500_add_i2c2(parent, &u5500_i2c2_data);
 	i2c_register_board_info(2, ARRAY_AND_SIZE(u5500_i2c2_devices));
 }
 
@@ -126,20 +126,27 @@
 	&ab5500_device,
 };
 
-static void __init u5500_uart_init(void)
+static void __init u5500_uart_init(struct device *parent)
 {
-	db5500_add_uart0(NULL);
-	db5500_add_uart1(NULL);
-	db5500_add_uart2(NULL);
+	db5500_add_uart0(parent, NULL);
+	db5500_add_uart1(parent, NULL);
+	db5500_add_uart2(parent, NULL);
 }
 
 static void __init u5500_init_machine(void)
 {
-	u5500_init_devices();
+	struct device *parent = NULL;
+	int i;
+
+	parent = u5500_init_devices();
 	nmk_config_pins(u5500_pins, ARRAY_SIZE(u5500_pins));
-	u5500_i2c_init();
-	u5500_sdi_init();
-	u5500_uart_init();
+
+	u5500_i2c_init(parent);
+	u5500_sdi_init(parent);
+	u5500_uart_init(parent);
+
+	for (i = 0; i < ARRAY_SIZE(u5500_platform_devices); i++)
+		u5500_platform_devices[i]->dev.parent = parent;
 
 	platform_add_devices(u5500_platform_devices,
 		ARRAY_SIZE(u5500_platform_devices));
diff --git a/arch/arm/mach-ux500/cache-l2x0.c b/arch/arm/mach-ux500/cache-l2x0.c
index da5569d..77a75ed 100644
--- a/arch/arm/mach-ux500/cache-l2x0.c
+++ b/arch/arm/mach-ux500/cache-l2x0.c
@@ -5,6 +5,8 @@
  */
 
 #include <linux/io.h>
+#include <linux/of.h>
+
 #include <asm/cacheflush.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <mach/hardware.h>
@@ -45,7 +47,10 @@
 	ux500_l2x0_unlock();
 
 	/* 64KB way size, 8 way associativity, force WA */
-	l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff);
+	if (of_have_populated_dt())
+		l2x0_of_init(0x3e060000, 0xc0000fff);
+	else
+		l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff);
 
 	/*
 	 * We can't disable l2 as we are in non secure mode, currently
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c
index 7379075..ec35f0a 100644
--- a/arch/arm/mach-ux500/clock.c
+++ b/arch/arm/mach-ux500/clock.c
@@ -223,6 +223,13 @@
 }
 EXPORT_SYMBOL(clk_set_rate);
 
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	/*TODO*/
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
 static void clk_prcmu_enable(struct clk *clk)
 {
 	void __iomem *cg_set_reg = __io_address(U8500_PRCMU_BASE)
diff --git a/arch/arm/mach-ux500/clock.h b/arch/arm/mach-ux500/clock.h
index 0744907..d776ada 100644
--- a/arch/arm/mach-ux500/clock.h
+++ b/arch/arm/mach-ux500/clock.h
@@ -21,6 +21,7 @@
 	void (*enable) (struct clk *);
 	void (*disable) (struct clk *);
 	unsigned long (*get_rate) (struct clk *);
+	int (*set_parent)(struct clk *, struct clk *);
 };
 
 /**
diff --git a/arch/arm/mach-ux500/cpu-db5500.c b/arch/arm/mach-ux500/cpu-db5500.c
index 18aa5c05..bca47f3 100644
--- a/arch/arm/mach-ux500/cpu-db5500.c
+++ b/arch/arm/mach-ux500/cpu-db5500.c
@@ -147,13 +147,13 @@
 	U5500_GPIOBANK7_BASE,
 };
 
-static void __init db5500_add_gpios(void)
+static void __init db5500_add_gpios(struct device *parent)
 {
 	struct nmk_gpio_platform_data pdata = {
 		/* No custom data yet */
 	};
 
-	dbx500_add_gpios(ARRAY_AND_SIZE(db5500_gpio_base),
+	dbx500_add_gpios(parent, ARRAY_AND_SIZE(db5500_gpio_base),
 			 IRQ_DB5500_GPIO0, &pdata);
 }
 
@@ -212,14 +212,36 @@
 	DB5500_DMA_DEV38_USB_OTG_OEP_8
 };
 
-void __init u5500_init_devices(void)
+static const char *db5500_read_soc_id(void)
 {
-	db5500_add_gpios();
+	return kasprintf(GFP_KERNEL, "u5500 currently unsupported\n");
+}
+
+static struct device * __init db5500_soc_device_init(void)
+{
+	const char *soc_id = db5500_read_soc_id();
+
+	return ux500_soc_device_init(soc_id);
+}
+
+struct device * __init u5500_init_devices(void)
+{
+	struct device *parent;
+	int i;
+
+	parent = db5500_soc_device_init();
+
+	db5500_add_gpios(parent);
 	db5500_pmu_init();
-	db5500_dma_init();
-	db5500_add_rtc();
-	db5500_add_usb(usb_db5500_rx_dma_cfg, usb_db5500_tx_dma_cfg);
+	db5500_dma_init(parent);
+	db5500_add_rtc(parent);
+	db5500_add_usb(parent, usb_db5500_rx_dma_cfg, usb_db5500_tx_dma_cfg);
+
+	for (i = 0; i < ARRAY_SIZE(db5500_platform_devs); i++)
+		db5500_platform_devs[i]->dev.parent = parent;
 
 	platform_add_devices(db5500_platform_devs,
 			     ARRAY_SIZE(db5500_platform_devs));
+
+	return parent;
 }
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index 7176ee7..9bd8163 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -24,6 +24,7 @@
 #include <mach/setup.h>
 #include <mach/devices.h>
 #include <mach/usb.h>
+#include <mach/db8500-regs.h>
 
 #include "devices-db8500.h"
 #include "ste-dma40-db8500.h"
@@ -132,13 +133,13 @@
 	U8500_GPIOBANK8_BASE,
 };
 
-static void __init db8500_add_gpios(void)
+static void __init db8500_add_gpios(struct device *parent)
 {
 	struct nmk_gpio_platform_data pdata = {
 		.supports_sleepmode = true,
 	};
 
-	dbx500_add_gpios(ARRAY_AND_SIZE(db8500_gpio_base),
+	dbx500_add_gpios(parent, ARRAY_AND_SIZE(db8500_gpio_base),
 			 IRQ_DB8500_GPIO0, &pdata);
 }
 
@@ -164,17 +165,44 @@
 	DB8500_DMA_DEV39_USB_OTG_OEP_8
 };
 
+static const char *db8500_read_soc_id(void)
+{
+	void __iomem *uid = __io_address(U8500_BB_UID_BASE);
+
+	return kasprintf(GFP_KERNEL, "%08x%08x%08x%08x%08x",
+			 readl((u32 *)uid+1),
+			 readl((u32 *)uid+1), readl((u32 *)uid+2),
+			 readl((u32 *)uid+3), readl((u32 *)uid+4));
+}
+
+static struct device * __init db8500_soc_device_init(void)
+{
+	const char *soc_id = db8500_read_soc_id();
+
+	return ux500_soc_device_init(soc_id);
+}
+
 /*
  * This function is called from the board init
  */
-void __init u8500_init_devices(void)
+struct device * __init u8500_init_devices(void)
 {
-	db8500_add_rtc();
-	db8500_add_gpios();
-	db8500_add_usb(usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg);
+	struct device *parent;
+	int i;
 
-	platform_device_register_simple("cpufreq-u8500", -1, NULL, 0);
+	parent = db8500_soc_device_init();
+
+	db8500_add_rtc(parent);
+	db8500_add_gpios(parent);
+	db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg);
+
+	platform_device_register_data(parent,
+		"cpufreq-u8500", -1, NULL, 0);
+
+	for (i = 0; i < ARRAY_SIZE(platform_devs); i++)
+		platform_devs[i]->dev.parent = parent;
+
 	platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
 
-	return ;
+	return parent;
 }
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c
index f418574..d11f389 100644
--- a/arch/arm/mach-ux500/cpu.c
+++ b/arch/arm/mach-ux500/cpu.c
@@ -2,6 +2,7 @@
  * Copyright (C) ST-Ericsson SA 2010
  *
  * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * Author: Lee Jones <lee.jones@linaro.org> for ST-Ericsson
  * License terms: GNU General Public License (GPL) version 2
  */
 
@@ -11,10 +12,15 @@
 #include <linux/mfd/db8500-prcmu.h>
 #include <linux/mfd/db5500-prcmu.h>
 #include <linux/clksrc-dbx500-prcmu.h>
+#include <linux/sys_soc.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
 
 #include <asm/hardware/gic.h>
 #include <asm/mach/map.h>
-#include <asm/localtimer.h>
 
 #include <mach/hardware.h>
 #include <mach/setup.h>
@@ -24,6 +30,11 @@
 
 void __iomem *_PRCMU_BASE;
 
+static const struct of_device_id ux500_dt_irq_match[] = {
+	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+	{},
+};
+
 void __init ux500_init_irq(void)
 {
 	void __iomem *dist_base;
@@ -38,7 +49,12 @@
 	} else
 		ux500_unknown_soc();
 
-	gic_init(0, 29, dist_base, cpu_base);
+#ifdef CONFIG_OF
+	if (of_have_populated_dt())
+		of_irq_init(ux500_dt_irq_match);
+	else
+#endif
+		gic_init(0, 29, dist_base, cpu_base);
 
 	/*
 	 * Init clocks here so that they are available for system timer
@@ -50,3 +66,73 @@
 		db8500_prcmu_early_init();
 	clk_init();
 }
+
+static const char * __init ux500_get_machine(void)
+{
+	return kasprintf(GFP_KERNEL, "DB%4x", dbx500_partnumber());
+}
+
+static const char * __init ux500_get_family(void)
+{
+	return kasprintf(GFP_KERNEL, "ux500");
+}
+
+static const char * __init ux500_get_revision(void)
+{
+	unsigned int rev = dbx500_revision();
+
+	if (rev == 0x01)
+		return kasprintf(GFP_KERNEL, "%s", "ED");
+	else if (rev >= 0xA0)
+		return kasprintf(GFP_KERNEL, "%d.%d",
+				 (rev >> 4) - 0xA + 1, rev & 0xf);
+
+	return kasprintf(GFP_KERNEL, "%s", "Unknown");
+}
+
+static ssize_t ux500_get_process(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	if (dbx500_id.process == 0x00)
+		return sprintf(buf, "Standard\n");
+
+	return sprintf(buf, "%02xnm\n", dbx500_id.process);
+}
+
+static void __init soc_info_populate(struct soc_device_attribute *soc_dev_attr,
+				     const char *soc_id)
+{
+	soc_dev_attr->soc_id   = soc_id;
+	soc_dev_attr->machine  = ux500_get_machine();
+	soc_dev_attr->family   = ux500_get_family();
+	soc_dev_attr->revision = ux500_get_revision();
+}
+
+struct device_attribute ux500_soc_attr =
+	__ATTR(process,  S_IRUGO, ux500_get_process,  NULL);
+
+struct device * __init ux500_soc_device_init(const char *soc_id)
+{
+	struct device *parent;
+	struct soc_device *soc_dev;
+	struct soc_device_attribute *soc_dev_attr;
+
+	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+	if (!soc_dev_attr)
+		return ERR_PTR(-ENOMEM);
+
+	soc_info_populate(soc_dev_attr, soc_id);
+
+	soc_dev = soc_device_register(soc_dev_attr);
+	if (IS_ERR_OR_NULL(soc_dev)) {
+	        kfree(soc_dev_attr);
+		return NULL;
+	}
+
+	parent = soc_device_to_device(soc_dev);
+	if (!IS_ERR_OR_NULL(parent))
+		device_create_file(parent, &ux500_soc_attr);
+
+	return parent;
+}
diff --git a/arch/arm/mach-ux500/devices-common.c b/arch/arm/mach-ux500/devices-common.c
index c563e54..c5312a4 100644
--- a/arch/arm/mach-ux500/devices-common.c
+++ b/arch/arm/mach-ux500/devices-common.c
@@ -20,35 +20,31 @@
 #include "devices-common.h"
 
 struct amba_device *
-dbx500_add_amba_device(const char *name, resource_size_t base,
-		       int irq, void *pdata, unsigned int periphid)
+dbx500_add_amba_device(struct device *parent, const char *name,
+		       resource_size_t base, int irq, void *pdata,
+		       unsigned int periphid)
 {
 	struct amba_device *dev;
 	int ret;
 
-	dev = kzalloc(sizeof *dev, GFP_KERNEL);
+	dev = amba_device_alloc(name, base, SZ_4K);
 	if (!dev)
 		return ERR_PTR(-ENOMEM);
 
-	dev->dev.init_name = name;
-
-	dev->res.start = base;
-	dev->res.end = base + SZ_4K - 1;
-	dev->res.flags = IORESOURCE_MEM;
-
 	dev->dma_mask = DMA_BIT_MASK(32);
 	dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
 
 	dev->irq[0] = irq;
-	dev->irq[1] = NO_IRQ;
 
 	dev->periphid = periphid;
 
 	dev->dev.platform_data = pdata;
 
-	ret = amba_device_register(dev, &iomem_resource);
+	dev->dev.parent = parent;
+
+	ret = amba_device_add(dev, &iomem_resource);
 	if (ret) {
-		kfree(dev);
+		amba_device_put(dev);
 		return ERR_PTR(ret);
 	}
 
@@ -56,60 +52,7 @@
 }
 
 static struct platform_device *
-dbx500_add_platform_device(const char *name, int id, void *pdata,
-			   struct resource *res, int resnum)
-{
-	struct platform_device *dev;
-	int ret;
-
-	dev = platform_device_alloc(name, id);
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-	dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
-
-	ret = platform_device_add_resources(dev, res, resnum);
-	if (ret)
-		goto out_free;
-
-	dev->dev.platform_data = pdata;
-
-	ret = platform_device_add(dev);
-	if (ret)
-		goto out_free;
-
-	return dev;
-
-out_free:
-	platform_device_put(dev);
-	return ERR_PTR(ret);
-}
-
-struct platform_device *
-dbx500_add_platform_device_4k1irq(const char *name, int id,
-				  resource_size_t base,
-				  int irq, void *pdata)
-{
-	struct resource resources[] = {
-		[0] = {
-			.start	= base,
-			.end	= base + SZ_4K - 1,
-			.flags	= IORESOURCE_MEM,
-		},
-		[1] = {
-			.start	= irq,
-			.end	= irq,
-			.flags	= IORESOURCE_IRQ,
-		}
-	};
-
-	return dbx500_add_platform_device(name, id, pdata, resources,
-					  ARRAY_SIZE(resources));
-}
-
-static struct platform_device *
-dbx500_add_gpio(int id, resource_size_t addr, int irq,
+dbx500_add_gpio(struct device *parent, int id, resource_size_t addr, int irq,
 		struct nmk_gpio_platform_data *pdata)
 {
 	struct resource resources[] = {
@@ -125,13 +68,18 @@
 		}
 	};
 
-	return platform_device_register_resndata(NULL, "gpio", id,
-				resources, ARRAY_SIZE(resources),
-				pdata, sizeof(*pdata));
+	return platform_device_register_resndata(
+		parent,
+		"gpio",
+		id,
+		resources,
+		ARRAY_SIZE(resources),
+		pdata,
+		sizeof(*pdata));
 }
 
-void dbx500_add_gpios(resource_size_t *base, int num, int irq,
-		      struct nmk_gpio_platform_data *pdata)
+void dbx500_add_gpios(struct device *parent, resource_size_t *base, int num,
+		      int irq, struct nmk_gpio_platform_data *pdata)
 {
 	int first = 0;
 	int i;
@@ -141,6 +89,6 @@
 		pdata->first_irq = NOMADIK_GPIO_TO_IRQ(first);
 		pdata->num_gpio = 32;
 
-		dbx500_add_gpio(i, base[i], irq, pdata);
+		dbx500_add_gpio(parent, i, base[i], irq, pdata);
 	}
 }
diff --git a/arch/arm/mach-ux500/devices-common.h b/arch/arm/mach-ux500/devices-common.h
index 7825705..39c74ec 100644
--- a/arch/arm/mach-ux500/devices-common.h
+++ b/arch/arm/mach-ux500/devices-common.h
@@ -8,80 +8,89 @@
 #ifndef __DEVICES_COMMON_H
 #define __DEVICES_COMMON_H
 
-extern struct amba_device *
-dbx500_add_amba_device(const char *name, resource_size_t base,
-		       int irq, void *pdata, unsigned int periphid);
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/sys_soc.h>
+#include <plat/i2c.h>
 
-extern struct platform_device *
-dbx500_add_platform_device_4k1irq(const char *name, int id,
-				  resource_size_t base,
-				  int irq, void *pdata);
+extern struct amba_device *
+dbx500_add_amba_device(struct device *parent, const char *name,
+		       resource_size_t base, int irq, void *pdata,
+		       unsigned int periphid);
 
 struct spi_master_cntlr;
 
 static inline struct amba_device *
-dbx500_add_msp_spi(const char *name, resource_size_t base, int irq,
+dbx500_add_msp_spi(struct device *parent, const char *name,
+		   resource_size_t base, int irq,
 		   struct spi_master_cntlr *pdata)
 {
-	return dbx500_add_amba_device(name, base, irq, pdata, 0);
+	return dbx500_add_amba_device(parent, name, base, irq,
+				      pdata, 0);
 }
 
 static inline struct amba_device *
-dbx500_add_spi(const char *name, resource_size_t base, int irq,
-	       struct spi_master_cntlr *pdata,
+dbx500_add_spi(struct device *parent, const char *name, resource_size_t base,
+	       int irq, struct spi_master_cntlr *pdata,
 	       u32 periphid)
 {
-	return dbx500_add_amba_device(name, base, irq, pdata, periphid);
+	return dbx500_add_amba_device(parent, name, base, irq,
+				      pdata, periphid);
 }
 
 struct mmci_platform_data;
 
 static inline struct amba_device *
-dbx500_add_sdi(const char *name, resource_size_t base, int irq,
-	       struct mmci_platform_data *pdata,
-	       u32 periphid)
+dbx500_add_sdi(struct device *parent, const char *name, resource_size_t base,
+	       int irq, struct mmci_platform_data *pdata, u32 periphid)
 {
-	return dbx500_add_amba_device(name, base, irq, pdata, periphid);
+	return dbx500_add_amba_device(parent, name, base, irq,
+				      pdata, periphid);
 }
 
 struct amba_pl011_data;
 
 static inline struct amba_device *
-dbx500_add_uart(const char *name, resource_size_t base, int irq,
-		struct amba_pl011_data *pdata)
+dbx500_add_uart(struct device *parent, const char *name, resource_size_t base,
+		int irq, struct amba_pl011_data *pdata)
 {
-	return dbx500_add_amba_device(name, base, irq, pdata, 0);
+	return dbx500_add_amba_device(parent, name, base, irq, pdata, 0);
 }
 
 struct nmk_i2c_controller;
 
 static inline struct platform_device *
-dbx500_add_i2c(int id, resource_size_t base, int irq,
-	       struct nmk_i2c_controller *pdata)
+dbx500_add_i2c(struct device *parent, int id, resource_size_t base, int irq,
+	       struct nmk_i2c_controller *data)
 {
-	return dbx500_add_platform_device_4k1irq("nmk-i2c", id, base, irq,
-						 pdata);
-}
+	struct resource res[] = {
+		DEFINE_RES_MEM(base, SZ_4K),
+		DEFINE_RES_IRQ(irq),
+	};
 
-struct msp_i2s_platform_data;
+	struct platform_device_info pdevinfo = {
+		.parent = parent,
+		.name = "nmk-i2c",
+		.id = id,
+		.res = res,
+		.num_res = ARRAY_SIZE(res),
+		.data = data,
+		.size_data = sizeof(*data),
+		.dma_mask = DMA_BIT_MASK(32),
+	};
 
-static inline struct platform_device *
-dbx500_add_msp_i2s(int id, resource_size_t base, int irq,
-		   struct msp_i2s_platform_data *pdata)
-{
-	return dbx500_add_platform_device_4k1irq("MSP_I2S", id, base, irq,
-						 pdata);
+	return platform_device_register_full(&pdevinfo);
 }
 
 static inline struct amba_device *
-dbx500_add_rtc(resource_size_t base, int irq)
+dbx500_add_rtc(struct device *parent, resource_size_t base, int irq)
 {
-	return dbx500_add_amba_device("rtc-pl031", base, irq, NULL, 0);
+	return dbx500_add_amba_device(parent, "rtc-pl031", base, irq, NULL, 0);
 }
 
 struct nmk_gpio_platform_data;
 
-void dbx500_add_gpios(resource_size_t *base, int num, int irq,
-		      struct nmk_gpio_platform_data *pdata);
+void dbx500_add_gpios(struct device *parent, resource_size_t *base, int num,
+		      int irq, struct nmk_gpio_platform_data *pdata);
 
 #endif
diff --git a/arch/arm/mach-ux500/devices-db5500.h b/arch/arm/mach-ux500/devices-db5500.h
index 0c4bccd..e709555 100644
--- a/arch/arm/mach-ux500/devices-db5500.h
+++ b/arch/arm/mach-ux500/devices-db5500.h
@@ -10,70 +10,90 @@
 
 #include "devices-common.h"
 
-#define db5500_add_i2c1(pdata) \
-	dbx500_add_i2c(1, U5500_I2C1_BASE, IRQ_DB5500_I2C1, pdata)
-#define db5500_add_i2c2(pdata) \
-	dbx500_add_i2c(2, U5500_I2C2_BASE, IRQ_DB5500_I2C2, pdata)
-#define db5500_add_i2c3(pdata) \
-	dbx500_add_i2c(3, U5500_I2C3_BASE, IRQ_DB5500_I2C3, pdata)
+#define db5500_add_i2c1(parent, pdata) \
+	dbx500_add_i2c(parent, 1, U5500_I2C1_BASE, IRQ_DB5500_I2C1, pdata)
+#define db5500_add_i2c2(parent, pdata) \
+	dbx500_add_i2c(parent, 2, U5500_I2C2_BASE, IRQ_DB5500_I2C2, pdata)
+#define db5500_add_i2c3(parent, pdata) \
+	dbx500_add_i2c(parent, 3, U5500_I2C3_BASE, IRQ_DB5500_I2C3, pdata)
 
-#define db5500_add_msp0_i2s(pdata) \
-	dbx500_add_msp_i2s(0, U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata)
-#define db5500_add_msp1_i2s(pdata) \
-	dbx500_add_msp_i2s(1, U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata)
-#define db5500_add_msp2_i2s(pdata) \
-	dbx500_add_msp_i2s(2, U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata)
+#define db5500_add_msp0_spi(parent, pdata) \
+	dbx500_add_msp_spi(parent, "msp0", U5500_MSP0_BASE, \
+			   IRQ_DB5500_MSP0, pdata)
+#define db5500_add_msp1_spi(parent, pdata) \
+	dbx500_add_msp_spi(parent, "msp1", U5500_MSP1_BASE, \
+			   IRQ_DB5500_MSP1, pdata)
+#define db5500_add_msp2_spi(parent, pdata) \
+	dbx500_add_msp_spi(parent, "msp2", U5500_MSP2_BASE, \
+			   IRQ_DB5500_MSP2, pdata)
 
-#define db5500_add_msp0_spi(pdata) \
-	dbx500_add_msp_spi("msp0", U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata)
-#define db5500_add_msp1_spi(pdata) \
-	dbx500_add_msp_spi("msp1", U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata)
-#define db5500_add_msp2_spi(pdata) \
-	dbx500_add_msp_spi("msp2", U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata)
+#define db5500_add_msp0_spi(parent, pdata) \
+	dbx500_add_msp_spi(parent, "msp0", U5500_MSP0_BASE, \
+			  IRQ_DB5500_MSP0, pdata)
+#define db5500_add_msp1_spi(parent, pdata) \
+	dbx500_add_msp_spi(parent, "msp1", U5500_MSP1_BASE, \
+			  IRQ_DB5500_MSP1, pdata)
+#define db5500_add_msp2_spi(parent, pdata) \
+	dbx500_add_msp_spi(parent, "msp2", U5500_MSP2_BASE, \
+			  IRQ_DB5500_MSP2, pdata)
 
-#define db5500_add_rtc() \
-	dbx500_add_rtc(U5500_RTC_BASE, IRQ_DB5500_RTC);
+#define db5500_add_rtc(parent) \
+	dbx500_add_rtc(parent, U5500_RTC_BASE, IRQ_DB5500_RTC);
 
-#define db5500_add_usb(rx_cfg, tx_cfg) \
-	ux500_add_usb(U5500_USBOTG_BASE, IRQ_DB5500_USBOTG, rx_cfg, tx_cfg)
+#define db5500_add_usb(parent, rx_cfg, tx_cfg) \
+	ux500_add_usb(parent, U5500_USBOTG_BASE, \
+		      IRQ_DB5500_USBOTG, rx_cfg, tx_cfg)
 
-#define db5500_add_sdi0(pdata) \
-	dbx500_add_sdi("sdi0", U5500_SDI0_BASE, IRQ_DB5500_SDMMC0, pdata, \
+#define db5500_add_sdi0(parent, pdata) \
+	dbx500_add_sdi(parent, "sdi0", U5500_SDI0_BASE, \
+		       IRQ_DB5500_SDMMC0, pdata,	\
 		       0x10480180)
-#define db5500_add_sdi1(pdata) \
-	dbx500_add_sdi("sdi1", U5500_SDI1_BASE, IRQ_DB5500_SDMMC1, pdata, \
+#define db5500_add_sdi1(parent, pdata) \
+	dbx500_add_sdi(parent, "sdi1", U5500_SDI1_BASE, \
+		       IRQ_DB5500_SDMMC1, pdata,	\
 		       0x10480180)
-#define db5500_add_sdi2(pdata) \
-	dbx500_add_sdi("sdi2", U5500_SDI2_BASE, IRQ_DB5500_SDMMC2, pdata \
+#define db5500_add_sdi2(parent, pdata) \
+	dbx500_add_sdi(parent, "sdi2", U5500_SDI2_BASE, \
+		       IRQ_DB5500_SDMMC2, pdata		\
 		       0x10480180)
-#define db5500_add_sdi3(pdata) \
-	dbx500_add_sdi("sdi3", U5500_SDI3_BASE, IRQ_DB5500_SDMMC3, pdata \
+#define db5500_add_sdi3(parent, pdata) \
+	dbx500_add_sdi(parent, "sdi3", U5500_SDI3_BASE, \
+		       IRQ_DB5500_SDMMC3, pdata		\
 		       0x10480180)
-#define db5500_add_sdi4(pdata) \
-	dbx500_add_sdi("sdi4", U5500_SDI4_BASE, IRQ_DB5500_SDMMC4, pdata \
+#define db5500_add_sdi4(parent, pdata) \
+	dbx500_add_sdi(parent, "sdi4", U5500_SDI4_BASE, \
+		       IRQ_DB5500_SDMMC4, pdata		\
 		       0x10480180)
 
 /* This one has a bad peripheral ID in the U5500 silicon */
-#define db5500_add_spi0(pdata) \
-	dbx500_add_spi("spi0", U5500_SPI0_BASE, IRQ_DB5500_SPI0, pdata, \
+#define db5500_add_spi0(parent, pdata) \
+	dbx500_add_spi(parent, "spi0", U5500_SPI0_BASE, \
+		       IRQ_DB5500_SPI0, pdata,		\
 		       0x10080023)
-#define db5500_add_spi1(pdata) \
-	dbx500_add_spi("spi1", U5500_SPI1_BASE, IRQ_DB5500_SPI1, pdata, \
+#define db5500_add_spi1(parent, pdata) \
+	dbx500_add_spi(parent, "spi1", U5500_SPI1_BASE, \
+		       IRQ_DB5500_SPI1, pdata,		\
 		       0x10080023)
-#define db5500_add_spi2(pdata) \
-	dbx500_add_spi("spi2", U5500_SPI2_BASE, IRQ_DB5500_SPI2, pdata \
+#define db5500_add_spi2(parent, pdata) \
+	dbx500_add_spi(parent, "spi2", U5500_SPI2_BASE, \
+		       IRQ_DB5500_SPI2, pdata		\
 		       0x10080023)
-#define db5500_add_spi3(pdata) \
-	dbx500_add_spi("spi3", U5500_SPI3_BASE, IRQ_DB5500_SPI3, pdata \
+#define db5500_add_spi3(parent, pdata) \
+	dbx500_add_spi(parent, "spi3", U5500_SPI3_BASE, \
+		       IRQ_DB5500_SPI3, pdata		\
 		       0x10080023)
 
-#define db5500_add_uart0(plat) \
-	dbx500_add_uart("uart0", U5500_UART0_BASE, IRQ_DB5500_UART0, plat)
-#define db5500_add_uart1(plat) \
-	dbx500_add_uart("uart1", U5500_UART1_BASE, IRQ_DB5500_UART1, plat)
-#define db5500_add_uart2(plat) \
-	dbx500_add_uart("uart2", U5500_UART2_BASE, IRQ_DB5500_UART2, plat)
-#define db5500_add_uart3(plat) \
-	dbx500_add_uart("uart3", U5500_UART3_BASE, IRQ_DB5500_UART3, plat)
+#define db5500_add_uart0(parent, plat) \
+	dbx500_add_uart(parent, "uart0", U5500_UART0_BASE, \
+			IRQ_DB5500_UART0, plat)
+#define db5500_add_uart1(parent, plat) \
+	dbx500_add_uart(parent, "uart1", U5500_UART1_BASE, \
+			IRQ_DB5500_UART1, plat)
+#define db5500_add_uart2(parent, plat) \
+	dbx500_add_uart(parent, "uart2", U5500_UART2_BASE, \
+			IRQ_DB5500_UART2, plat)
+#define db5500_add_uart3(parent, plat) \
+	dbx500_add_uart(parent, "uart3", U5500_UART3_BASE, \
+			IRQ_DB5500_UART3, plat)
 
 #endif
diff --git a/arch/arm/mach-ux500/devices-db8500.c b/arch/arm/mach-ux500/devices-db8500.c
index a7c6cdc..6e66d37 100644
--- a/arch/arm/mach-ux500/devices-db8500.c
+++ b/arch/arm/mach-ux500/devices-db8500.c
@@ -101,6 +101,9 @@
 	[DB8500_DMA_DEV41_SD_MM3_TX] = -1,
 	[DB8500_DMA_DEV42_SD_MM4_TX] = -1,
 	[DB8500_DMA_DEV43_SD_MM5_TX] = -1,
+	[DB8500_DMA_DEV14_MSP2_TX] = U8500_MSP2_BASE + MSP_TX_RX_REG_OFFSET,
+	[DB8500_DMA_DEV30_MSP1_TX] = U8500_MSP1_BASE + MSP_TX_RX_REG_OFFSET,
+	[DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX] = U8500_MSP0_BASE + MSP_TX_RX_REG_OFFSET,
 };
 
 /* Mapping between source event lines and physical device address */
@@ -133,6 +136,9 @@
 	[DB8500_DMA_DEV41_SD_MM3_RX] = -1,
 	[DB8500_DMA_DEV42_SD_MM4_RX] = -1,
 	[DB8500_DMA_DEV43_SD_MM5_RX] = -1,
+	[DB8500_DMA_DEV14_MSP2_RX] = U8500_MSP2_BASE + MSP_TX_RX_REG_OFFSET,
+	[DB8500_DMA_DEV30_MSP3_RX] = U8500_MSP3_BASE + MSP_TX_RX_REG_OFFSET,
+	[DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX] = U8500_MSP0_BASE + MSP_TX_RX_REG_OFFSET,
 };
 
 /* Reserved event lines for memcpy only */
diff --git a/arch/arm/mach-ux500/devices-db8500.h b/arch/arm/mach-ux500/devices-db8500.h
index cbd4a9a..9fd93e9 100644
--- a/arch/arm/mach-ux500/devices-db8500.h
+++ b/arch/arm/mach-ux500/devices-db8500.h
@@ -14,88 +14,114 @@
 struct pl022_ssp_controller;
 
 static inline struct platform_device *
-db8500_add_ske_keypad(struct ske_keypad_platform_data *pdata)
+db8500_add_ske_keypad(struct device *parent,
+		      struct ske_keypad_platform_data *pdata,
+		      size_t size)
 {
-	return dbx500_add_platform_device_4k1irq("nmk-ske-keypad", -1,
-						 U8500_SKE_BASE,
-						 IRQ_DB8500_KB, pdata);
+	struct resource resources[] = {
+		DEFINE_RES_MEM(U8500_SKE_BASE, SZ_4K),
+		DEFINE_RES_IRQ(IRQ_DB8500_KB),
+	};
+
+	return platform_device_register_resndata(parent, "nmk-ske-keypad", -1,
+						 resources, 2, pdata, size);
 }
 
 static inline struct amba_device *
-db8500_add_ssp(const char *name, resource_size_t base, int irq,
-	       struct pl022_ssp_controller *pdata)
+db8500_add_ssp(struct device *parent, const char *name, resource_size_t base,
+	       int irq, struct pl022_ssp_controller *pdata)
 {
-	return dbx500_add_amba_device(name, base, irq, pdata, 0);
+	return dbx500_add_amba_device(parent, name, base, irq, pdata, 0);
 }
 
 
-#define db8500_add_i2c0(pdata) \
-	dbx500_add_i2c(0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata)
-#define db8500_add_i2c1(pdata) \
-	dbx500_add_i2c(1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata)
-#define db8500_add_i2c2(pdata) \
-	dbx500_add_i2c(2, U8500_I2C2_BASE, IRQ_DB8500_I2C2, pdata)
-#define db8500_add_i2c3(pdata) \
-	dbx500_add_i2c(3, U8500_I2C3_BASE, IRQ_DB8500_I2C3, pdata)
-#define db8500_add_i2c4(pdata) \
-	dbx500_add_i2c(4, U8500_I2C4_BASE, IRQ_DB8500_I2C4, pdata)
+#define db8500_add_i2c0(parent, pdata) \
+	dbx500_add_i2c(parent, 0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata)
+#define db8500_add_i2c1(parent, pdata) \
+	dbx500_add_i2c(parent, 1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata)
+#define db8500_add_i2c2(parent, pdata) \
+	dbx500_add_i2c(parent, 2, U8500_I2C2_BASE, IRQ_DB8500_I2C2, pdata)
+#define db8500_add_i2c3(parent, pdata) \
+	dbx500_add_i2c(parent, 3, U8500_I2C3_BASE, IRQ_DB8500_I2C3, pdata)
+#define db8500_add_i2c4(parent, pdata) \
+	dbx500_add_i2c(parent, 4, U8500_I2C4_BASE, IRQ_DB8500_I2C4, pdata)
 
-#define db8500_add_msp0_i2s(pdata) \
-	dbx500_add_msp_i2s(0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata)
-#define db8500_add_msp1_i2s(pdata) \
-	dbx500_add_msp_i2s(1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata)
-#define db8500_add_msp2_i2s(pdata) \
-	dbx500_add_msp_i2s(2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata)
-#define db8500_add_msp3_i2s(pdata) \
-	dbx500_add_msp_i2s(3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata)
+#define db8500_add_msp0_i2s(parent, pdata) \
+	dbx500_add_msp_i2s(parent, 0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata)
+#define db8500_add_msp1_i2s(parent, pdata) \
+	dbx500_add_msp_i2s(parent, 1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata)
+#define db8500_add_msp2_i2s(parent, pdata) \
+	dbx500_add_msp_i2s(parent, 2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata)
+#define db8500_add_msp3_i2s(parent, pdata) \
+	dbx500_add_msp_i2s(parent, 3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata)
 
-#define db8500_add_msp0_spi(pdata) \
-	dbx500_add_msp_spi("msp0", U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata)
-#define db8500_add_msp1_spi(pdata) \
-	dbx500_add_msp_spi("msp1", U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata)
-#define db8500_add_msp2_spi(pdata) \
-	dbx500_add_msp_spi("msp2", U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata)
-#define db8500_add_msp3_spi(pdata) \
-	dbx500_add_msp_spi("msp3", U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata)
+#define db8500_add_msp0_spi(parent, pdata) \
+	dbx500_add_msp_spi(parent, "msp0", U8500_MSP0_BASE, \
+			   IRQ_DB8500_MSP0, pdata)
+#define db8500_add_msp1_spi(parent, pdata) \
+	dbx500_add_msp_spi(parent, "msp1", U8500_MSP1_BASE, \
+			   IRQ_DB8500_MSP1, pdata)
+#define db8500_add_msp2_spi(parent, pdata) \
+	dbx500_add_msp_spi(parent, "msp2", U8500_MSP2_BASE, \
+			   IRQ_DB8500_MSP2, pdata)
+#define db8500_add_msp3_spi(parent, pdata) \
+	dbx500_add_msp_spi(parent, "msp3", U8500_MSP3_BASE, \
+			   IRQ_DB8500_MSP1, pdata)
 
-#define db8500_add_rtc() \
-	dbx500_add_rtc(U8500_RTC_BASE, IRQ_DB8500_RTC);
+#define db8500_add_rtc(parent) \
+	dbx500_add_rtc(parent, U8500_RTC_BASE, IRQ_DB8500_RTC);
 
-#define db8500_add_usb(rx_cfg, tx_cfg) \
-	ux500_add_usb(U8500_USBOTG_BASE, IRQ_DB8500_USBOTG, rx_cfg, tx_cfg)
+#define db8500_add_usb(parent, rx_cfg, tx_cfg) \
+	ux500_add_usb(parent, U8500_USBOTG_BASE, \
+		      IRQ_DB8500_USBOTG, rx_cfg, tx_cfg)
 
-#define db8500_add_sdi0(pdata, pid) \
-	dbx500_add_sdi("sdi0", U8500_SDI0_BASE, IRQ_DB8500_SDMMC0, pdata, pid)
-#define db8500_add_sdi1(pdata, pid) \
-	dbx500_add_sdi("sdi1", U8500_SDI1_BASE, IRQ_DB8500_SDMMC1, pdata, pid)
-#define db8500_add_sdi2(pdata, pid) \
-	dbx500_add_sdi("sdi2", U8500_SDI2_BASE, IRQ_DB8500_SDMMC2, pdata, pid)
-#define db8500_add_sdi3(pdata, pid) \
-	dbx500_add_sdi("sdi3", U8500_SDI3_BASE, IRQ_DB8500_SDMMC3, pdata, pid)
-#define db8500_add_sdi4(pdata, pid) \
-	dbx500_add_sdi("sdi4", U8500_SDI4_BASE, IRQ_DB8500_SDMMC4, pdata, pid)
-#define db8500_add_sdi5(pdata, pid) \
-	dbx500_add_sdi("sdi5", U8500_SDI5_BASE, IRQ_DB8500_SDMMC5, pdata, pid)
+#define db8500_add_sdi0(parent, pdata, pid) \
+	dbx500_add_sdi(parent, "sdi0", U8500_SDI0_BASE, \
+		       IRQ_DB8500_SDMMC0, pdata, pid)
+#define db8500_add_sdi1(parent, pdata, pid) \
+	dbx500_add_sdi(parent, "sdi1", U8500_SDI1_BASE, \
+		       IRQ_DB8500_SDMMC1, pdata, pid)
+#define db8500_add_sdi2(parent, pdata, pid) \
+	dbx500_add_sdi(parent, "sdi2", U8500_SDI2_BASE, \
+		       IRQ_DB8500_SDMMC2, pdata, pid)
+#define db8500_add_sdi3(parent, pdata, pid) \
+	dbx500_add_sdi(parent, "sdi3", U8500_SDI3_BASE, \
+		       IRQ_DB8500_SDMMC3, pdata, pid)
+#define db8500_add_sdi4(parent, pdata, pid) \
+	dbx500_add_sdi(parent, "sdi4", U8500_SDI4_BASE, \
+		       IRQ_DB8500_SDMMC4, pdata, pid)
+#define db8500_add_sdi5(parent, pdata, pid) \
+	dbx500_add_sdi(parent, "sdi5", U8500_SDI5_BASE, \
+		       IRQ_DB8500_SDMMC5, pdata, pid)
 
-#define db8500_add_ssp0(pdata) \
-	db8500_add_ssp("ssp0", U8500_SSP0_BASE, IRQ_DB8500_SSP0, pdata)
-#define db8500_add_ssp1(pdata) \
-	db8500_add_ssp("ssp1", U8500_SSP1_BASE, IRQ_DB8500_SSP1, pdata)
+#define db8500_add_ssp0(parent, pdata) \
+	db8500_add_ssp(parent, "ssp0", U8500_SSP0_BASE, \
+		       IRQ_DB8500_SSP0, pdata)
+#define db8500_add_ssp1(parent, pdata) \
+	db8500_add_ssp(parent, "ssp1", U8500_SSP1_BASE, \
+		       IRQ_DB8500_SSP1, pdata)
 
-#define db8500_add_spi0(pdata) \
-	dbx500_add_spi("spi0", U8500_SPI0_BASE, IRQ_DB8500_SPI0, pdata, 0)
-#define db8500_add_spi1(pdata) \
-	dbx500_add_spi("spi1", U8500_SPI1_BASE, IRQ_DB8500_SPI1, pdata, 0)
-#define db8500_add_spi2(pdata) \
-	dbx500_add_spi("spi2", U8500_SPI2_BASE, IRQ_DB8500_SPI2, pdata, 0)
-#define db8500_add_spi3(pdata) \
-	dbx500_add_spi("spi3", U8500_SPI3_BASE, IRQ_DB8500_SPI3, pdata, 0)
+#define db8500_add_spi0(parent, pdata) \
+	dbx500_add_spi(parent, "spi0", U8500_SPI0_BASE, \
+		       IRQ_DB8500_SPI0, pdata, 0)
+#define db8500_add_spi1(parent, pdata) \
+	dbx500_add_spi(parent, "spi1", U8500_SPI1_BASE, \
+		       IRQ_DB8500_SPI1, pdata, 0)
+#define db8500_add_spi2(parent, pdata) \
+	dbx500_add_spi(parent, "spi2", U8500_SPI2_BASE, \
+		       IRQ_DB8500_SPI2, pdata, 0)
+#define db8500_add_spi3(parent, pdata) \
+	dbx500_add_spi(parent, "spi3", U8500_SPI3_BASE, \
+		       IRQ_DB8500_SPI3, pdata, 0)
 
-#define db8500_add_uart0(pdata) \
-	dbx500_add_uart("uart0", U8500_UART0_BASE, IRQ_DB8500_UART0, pdata)
-#define db8500_add_uart1(pdata) \
-	dbx500_add_uart("uart1", U8500_UART1_BASE, IRQ_DB8500_UART1, pdata)
-#define db8500_add_uart2(pdata) \
-	dbx500_add_uart("uart2", U8500_UART2_BASE, IRQ_DB8500_UART2, pdata)
+#define db8500_add_uart0(parent, pdata) \
+	dbx500_add_uart(parent, "uart0", U8500_UART0_BASE, \
+			IRQ_DB8500_UART0, pdata)
+#define db8500_add_uart1(parent, pdata) \
+	dbx500_add_uart(parent, "uart1", U8500_UART1_BASE, \
+			IRQ_DB8500_UART1, pdata)
+#define db8500_add_uart2(parent, pdata) \
+	dbx500_add_uart(parent, "uart2", U8500_UART2_BASE, \
+			IRQ_DB8500_UART2, pdata)
 
 #endif
diff --git a/arch/arm/mach-ux500/dma-db5500.c b/arch/arm/mach-ux500/dma-db5500.c
index 1cfab68..41e9470 100644
--- a/arch/arm/mach-ux500/dma-db5500.c
+++ b/arch/arm/mach-ux500/dma-db5500.c
@@ -125,10 +125,11 @@
 	.resource	= dma40_resources
 };
 
-void __init db5500_dma_init(void)
+void __init db5500_dma_init(struct device *parent)
 {
 	int ret;
 
+	dma40_device.dev.parent = parent;
 	ret = platform_device_register(&dma40_device);
 	if (ret)
 		dev_err(&dma40_device.dev, "unable to register device: %d\n", ret);
diff --git a/arch/arm/mach-ux500/include/mach/db8500-regs.h b/arch/arm/mach-ux500/include/mach/db8500-regs.h
index 80e10f5..9ec20b9 100644
--- a/arch/arm/mach-ux500/include/mach/db8500-regs.h
+++ b/arch/arm/mach-ux500/include/mach/db8500-regs.h
@@ -161,4 +161,7 @@
 #define U8500_MODEM_BASE	0xe000000
 #define U8500_APE_BASE		0x6000000
 
+/* SoC identification number information */
+#define U8500_BB_UID_BASE      (U8500_BACKUPRAM1_BASE + 0xFC0)
+
 #endif
diff --git a/arch/arm/mach-ux500/include/mach/entry-macro.S b/arch/arm/mach-ux500/include/mach/entry-macro.S
deleted file mode 100644
index e16299e..0000000
--- a/arch/arm/mach-ux500/include/mach/entry-macro.S
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Low-level IRQ helper macros for U8500 platforms
- *
- * Copyright (C) 2009 ST-Ericsson.
- *
- * This file is a copy of ARM Realview platform.
- *	-just satisfied checkpatch script.
- *
- * 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.
- */
-
-		.macro	disable_fiq
-		.endm
-
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
diff --git a/arch/arm/mach-ux500/include/mach/hardware.h b/arch/arm/mach-ux500/include/mach/hardware.h
index b6ba26a..f846989 100644
--- a/arch/arm/mach-ux500/include/mach/hardware.h
+++ b/arch/arm/mach-ux500/include/mach/hardware.h
@@ -23,13 +23,15 @@
 	(((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + U8500_IO_VIRTUAL)
 
 /* typesafe io address */
-#define __io_address(n)		__io(IO_ADDRESS(n))
+#define __io_address(n)		IOMEM(IO_ADDRESS(n))
 /* Used by some plat-nomadik code */
 #define io_p2v(n)		__io_address(n)
 
 #include <mach/db8500-regs.h>
 #include <mach/db5500-regs.h>
 
+#define MSP_TX_RX_REG_OFFSET	0
+
 #ifndef __ASSEMBLY__
 
 #include <mach/id.h>
diff --git a/arch/arm/mach-ux500/include/mach/io.h b/arch/arm/mach-ux500/include/mach/io.h
deleted file mode 100644
index 1cf3f44..0000000
--- a/arch/arm/mach-ux500/include/mach/io.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * arch/arm/mach-u8500/include/mach/io.h
- *
- * Copyright (C) 1997-1999 Russell King
- *
- * Modifications:
- *  06-12-1997	RMK	Created.
- *  07-04-1999	RMK	Major cleanup
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-/*
- * We don't actually have real ISA nor PCI buses, but there is so many
- * drivers out there that might just work if we fake them...
- */
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
index d2d4131..7d34c52 100644
--- a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
+++ b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
@@ -13,7 +13,7 @@
 
 #define MOP500_AB8500_IRQ_BASE		IRQ_BOARD_START
 #define MOP500_AB8500_IRQ_END		(MOP500_AB8500_IRQ_BASE \
-					 + AB8500_NR_IRQS)
+					 + AB8500_MAX_NR_IRQS)
 
 /* TC35892 */
 #define TC35892_NR_INTERNAL_IRQS	8
diff --git a/arch/arm/mach-ux500/include/mach/irqs.h b/arch/arm/mach-ux500/include/mach/irqs.h
index 9db68d2..c23a6b5 100644
--- a/arch/arm/mach-ux500/include/mach/irqs.h
+++ b/arch/arm/mach-ux500/include/mach/irqs.h
@@ -43,7 +43,7 @@
 /* This will be overridden by board-specific irq headers */
 #define IRQ_BOARD_END		IRQ_BOARD_START
 
-#ifdef CONFIG_MACH_U8500
+#ifdef CONFIG_MACH_MOP500
 #include <mach/irqs-board-mop500.h>
 #endif
 
diff --git a/arch/arm/mach-ux500/include/mach/setup.h b/arch/arm/mach-ux500/include/mach/setup.h
index a7d363f..3dc00ff 100644
--- a/arch/arm/mach-ux500/include/mach/setup.h
+++ b/arch/arm/mach-ux500/include/mach/setup.h
@@ -18,17 +18,16 @@
 extern void __init u5500_map_io(void);
 extern void __init u8500_map_io(void);
 
-extern void __init u5500_init_devices(void);
-extern void __init u8500_init_devices(void);
+extern struct device * __init u5500_init_devices(void);
+extern struct device * __init u8500_init_devices(void);
 
 extern void __init ux500_init_irq(void);
 
-extern void __init u5500_sdi_init(void);
+extern void __init u5500_sdi_init(struct device *parent);
 
-extern void __init db5500_dma_init(void);
+extern void __init db5500_dma_init(struct device *parent);
 
-/* We re-use nomadik_timer for this platform */
-extern void nmdk_timer_init(void);
+extern struct device *ux500_soc_device_init(const char *soc_id);
 
 struct amba_device;
 extern void __init amba_add_devices(struct amba_device *devs[], int num);
diff --git a/arch/arm/mach-ux500/include/mach/system.h b/arch/arm/mach-ux500/include/mach/system.h
deleted file mode 100644
index 258e5c9..0000000
--- a/arch/arm/mach-ux500/include/mach/system.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2009 ST-Ericsson.
- *
- * 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	/*
-	 * This should do all the clock switching
-	 * and wait for interrupt tricks
-	 */
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-ux500/include/mach/usb.h b/arch/arm/mach-ux500/include/mach/usb.h
index d3739d4..4c1cc50 100644
--- a/arch/arm/mach-ux500/include/mach/usb.h
+++ b/arch/arm/mach-ux500/include/mach/usb.h
@@ -20,6 +20,6 @@
 	bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
 };
 
-void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg,
-	int *dma_tx_cfg);
+void ux500_add_usb(struct device *parent, resource_size_t base,
+		   int irq, int *dma_rx_cfg, int *dma_tx_cfg);
 #endif
diff --git a/arch/arm/mach-ux500/localtimer.c b/arch/arm/mach-ux500/localtimer.c
deleted file mode 100644
index 5ba1133..0000000
--- a/arch/arm/mach-ux500/localtimer.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2008-2009 ST-Ericsson
- * Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
- *
- * This file is heavily based on relaview platform, almost a copy.
- *
- * Copyright (C) 2002 ARM Ltd.
- *
- * 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/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-
-#include <asm/irq.h>
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	evt->irq = IRQ_LOCALTIMER;
-	twd_timer_setup(evt);
-	return 0;
-}
diff --git a/arch/arm/mach-ux500/timer.c b/arch/arm/mach-ux500/timer.c
index aea467d..d37df98 100644
--- a/arch/arm/mach-ux500/timer.c
+++ b/arch/arm/mach-ux500/timer.c
@@ -7,29 +7,52 @@
 #include <linux/io.h>
 #include <linux/errno.h>
 #include <linux/clksrc-dbx500-prcmu.h>
+#include <linux/of.h>
 
-#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
 
 #include <plat/mtu.h>
 
 #include <mach/setup.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
+
+#ifdef CONFIG_HAVE_ARM_TWD
+static DEFINE_TWD_LOCAL_TIMER(u5500_twd_local_timer,
+			      U5500_TWD_BASE, IRQ_LOCALTIMER);
+static DEFINE_TWD_LOCAL_TIMER(u8500_twd_local_timer,
+			      U8500_TWD_BASE, IRQ_LOCALTIMER);
+
+static void __init ux500_twd_init(void)
+{
+	struct twd_local_timer *twd_local_timer;
+	int err;
+
+	twd_local_timer = cpu_is_u5500() ? &u5500_twd_local_timer :
+					   &u8500_twd_local_timer;
+
+	if (of_have_populated_dt())
+		twd_local_timer_of_register();
+	else {
+		err = twd_local_timer_register(twd_local_timer);
+		if (err)
+			pr_err("twd_local_timer_register failed %d\n", err);
+	}
+}
+#else
+#define ux500_twd_init()	do { } while(0)
+#endif
 
 static void __init ux500_timer_init(void)
 {
+	void __iomem *mtu_timer_base;
 	void __iomem *prcmu_timer_base;
 
 	if (cpu_is_u5500()) {
-#ifdef CONFIG_LOCAL_TIMERS
-		twd_base = __io_address(U5500_TWD_BASE);
-#endif
-		mtu_base = __io_address(U5500_MTU0_BASE);
+		mtu_timer_base = __io_address(U5500_MTU0_BASE);
 		prcmu_timer_base = __io_address(U5500_PRCMU_TIMER_3_BASE);
 	} else if (cpu_is_u8500()) {
-#ifdef CONFIG_LOCAL_TIMERS
-		twd_base = __io_address(U8500_TWD_BASE);
-#endif
-		mtu_base = __io_address(U8500_MTU0_BASE);
+		mtu_timer_base = __io_address(U8500_MTU0_BASE);
 		prcmu_timer_base = __io_address(U8500_PRCMU_TIMER_4_BASE);
 	} else {
 		ux500_unknown_soc();
@@ -52,8 +75,9 @@
 	 *
 	 */
 
-	nmdk_timer_init();
+	nmdk_timer_init(mtu_timer_base);
 	clksrc_dbx500_prcmu_init(prcmu_timer_base);
+	ux500_twd_init();
 }
 
 static void ux500_timer_reset(void)
diff --git a/arch/arm/mach-ux500/usb.c b/arch/arm/mach-ux500/usb.c
index 9f9e1c2..a74af38 100644
--- a/arch/arm/mach-ux500/usb.c
+++ b/arch/arm/mach-ux500/usb.c
@@ -7,6 +7,7 @@
 #include <linux/platform_device.h>
 #include <linux/usb/musb.h>
 #include <linux/dma-mapping.h>
+
 #include <plat/ste_dma40.h>
 #include <mach/hardware.h>
 #include <mach/usb.h>
@@ -140,8 +141,8 @@
 		musb_dma_tx_ch[idx].dst_dev_type = dst_dev_type[idx];
 }
 
-void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg,
-	int *dma_tx_cfg)
+void ux500_add_usb(struct device *parent, resource_size_t base, int irq,
+		   int *dma_rx_cfg, int *dma_tx_cfg)
 {
 	ux500_musb_device.resource[0].start = base;
 	ux500_musb_device.resource[0].end = base + SZ_64K - 1;
@@ -151,5 +152,7 @@
 	ux500_usb_dma_update_rx_ch_config(dma_rx_cfg);
 	ux500_usb_dma_update_tx_ch_config(dma_tx_cfg);
 
+	ux500_musb_device.dev.parent = parent;
+
 	platform_device_register(&ux500_musb_device);
 }
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 008ce22..6bbd74e 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -36,7 +36,6 @@
 #include <linux/clkdev.h>
 #include <linux/mtd/physmap.h>
 
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/leds.h>
 #include <asm/hardware/arm_timer.h>
@@ -585,58 +584,58 @@
 	.num_chipselect = 1,
 };
 
-#define AACI_IRQ	{ IRQ_AACI, NO_IRQ }
+#define AACI_IRQ	{ IRQ_AACI }
 #define MMCI0_IRQ	{ IRQ_MMCI0A,IRQ_SIC_MMCI0B }
-#define KMI0_IRQ	{ IRQ_SIC_KMI0, NO_IRQ }
-#define KMI1_IRQ	{ IRQ_SIC_KMI1, NO_IRQ }
+#define KMI0_IRQ	{ IRQ_SIC_KMI0 }
+#define KMI1_IRQ	{ IRQ_SIC_KMI1 }
 
 /*
  * These devices are connected directly to the multi-layer AHB switch
  */
-#define SMC_IRQ		{ NO_IRQ, NO_IRQ }
-#define MPMC_IRQ	{ NO_IRQ, NO_IRQ }
-#define CLCD_IRQ	{ IRQ_CLCDINT, NO_IRQ }
-#define DMAC_IRQ	{ IRQ_DMAINT, NO_IRQ }
+#define SMC_IRQ		{ }
+#define MPMC_IRQ	{ }
+#define CLCD_IRQ	{ IRQ_CLCDINT }
+#define DMAC_IRQ	{ IRQ_DMAINT }
 
 /*
  * These devices are connected via the core APB bridge
  */
-#define SCTL_IRQ	{ NO_IRQ, NO_IRQ }
-#define WATCHDOG_IRQ	{ IRQ_WDOGINT, NO_IRQ }
-#define GPIO0_IRQ	{ IRQ_GPIOINT0, NO_IRQ }
-#define GPIO1_IRQ	{ IRQ_GPIOINT1, NO_IRQ }
-#define RTC_IRQ		{ IRQ_RTCINT, NO_IRQ }
+#define SCTL_IRQ	{ }
+#define WATCHDOG_IRQ	{ IRQ_WDOGINT }
+#define GPIO0_IRQ	{ IRQ_GPIOINT0 }
+#define GPIO1_IRQ	{ IRQ_GPIOINT1 }
+#define RTC_IRQ		{ IRQ_RTCINT }
 
 /*
  * These devices are connected via the DMA APB bridge
  */
-#define SCI_IRQ		{ IRQ_SCIINT, NO_IRQ }
-#define UART0_IRQ	{ IRQ_UARTINT0, NO_IRQ }
-#define UART1_IRQ	{ IRQ_UARTINT1, NO_IRQ }
-#define UART2_IRQ	{ IRQ_UARTINT2, NO_IRQ }
-#define SSP_IRQ		{ IRQ_SSPINT, NO_IRQ }
+#define SCI_IRQ		{ IRQ_SCIINT }
+#define UART0_IRQ	{ IRQ_UARTINT0 }
+#define UART1_IRQ	{ IRQ_UARTINT1 }
+#define UART2_IRQ	{ IRQ_UARTINT2 }
+#define SSP_IRQ		{ IRQ_SSPINT }
 
 /* FPGA Primecells */
-AMBA_DEVICE(aaci,  "fpga:04", AACI,     NULL);
-AMBA_DEVICE(mmc0,  "fpga:05", MMCI0,    &mmc0_plat_data);
-AMBA_DEVICE(kmi0,  "fpga:06", KMI0,     NULL);
-AMBA_DEVICE(kmi1,  "fpga:07", KMI1,     NULL);
+APB_DEVICE(aaci,  "fpga:04", AACI,     NULL);
+APB_DEVICE(mmc0,  "fpga:05", MMCI0,    &mmc0_plat_data);
+APB_DEVICE(kmi0,  "fpga:06", KMI0,     NULL);
+APB_DEVICE(kmi1,  "fpga:07", KMI1,     NULL);
 
 /* DevChip Primecells */
-AMBA_DEVICE(smc,   "dev:00",  SMC,      NULL);
-AMBA_DEVICE(mpmc,  "dev:10",  MPMC,     NULL);
-AMBA_DEVICE(clcd,  "dev:20",  CLCD,     &clcd_plat_data);
-AMBA_DEVICE(dmac,  "dev:30",  DMAC,     NULL);
-AMBA_DEVICE(sctl,  "dev:e0",  SCTL,     NULL);
-AMBA_DEVICE(wdog,  "dev:e1",  WATCHDOG, NULL);
-AMBA_DEVICE(gpio0, "dev:e4",  GPIO0,    &gpio0_plat_data);
-AMBA_DEVICE(gpio1, "dev:e5",  GPIO1,    &gpio1_plat_data);
-AMBA_DEVICE(rtc,   "dev:e8",  RTC,      NULL);
-AMBA_DEVICE(sci0,  "dev:f0",  SCI,      NULL);
-AMBA_DEVICE(uart0, "dev:f1",  UART0,    NULL);
-AMBA_DEVICE(uart1, "dev:f2",  UART1,    NULL);
-AMBA_DEVICE(uart2, "dev:f3",  UART2,    NULL);
-AMBA_DEVICE(ssp0,  "dev:f4",  SSP,      &ssp0_plat_data);
+AHB_DEVICE(smc,   "dev:00",  SMC,      NULL);
+AHB_DEVICE(mpmc,  "dev:10",  MPMC,     NULL);
+AHB_DEVICE(clcd,  "dev:20",  CLCD,     &clcd_plat_data);
+AHB_DEVICE(dmac,  "dev:30",  DMAC,     NULL);
+APB_DEVICE(sctl,  "dev:e0",  SCTL,     NULL);
+APB_DEVICE(wdog,  "dev:e1",  WATCHDOG, NULL);
+APB_DEVICE(gpio0, "dev:e4",  GPIO0,    &gpio0_plat_data);
+APB_DEVICE(gpio1, "dev:e5",  GPIO1,    &gpio1_plat_data);
+APB_DEVICE(rtc,   "dev:e8",  RTC,      NULL);
+APB_DEVICE(sci0,  "dev:f0",  SCI,      NULL);
+APB_DEVICE(uart0, "dev:f1",  UART0,    NULL);
+APB_DEVICE(uart1, "dev:f2",  UART1,    NULL);
+APB_DEVICE(uart2, "dev:f3",  UART2,    NULL);
+APB_DEVICE(ssp0,  "dev:f4",  SSP,      &ssp0_plat_data);
 
 static struct amba_device *amba_devs[] __initdata = {
 	&dmac_device,
diff --git a/arch/arm/mach-versatile/core.h b/arch/arm/mach-versatile/core.h
index 2ef2f55..683e607 100644
--- a/arch/arm/mach-versatile/core.h
+++ b/arch/arm/mach-versatile/core.h
@@ -36,20 +36,10 @@
 extern struct of_dev_auxdata versatile_auxdata_lookup[];
 #endif
 
-#define AMBA_DEVICE(name,busid,base,plat)			\
-static struct amba_device name##_device = {			\
-	.dev		= {					\
-		.coherent_dma_mask = ~0,			\
-		.init_name = busid,				\
-		.platform_data = plat,				\
-	},							\
-	.res		= {					\
-		.start	= VERSATILE_##base##_BASE,		\
-		.end	= (VERSATILE_##base##_BASE) + SZ_4K - 1,\
-		.flags	= IORESOURCE_MEM,			\
-	},							\
-	.dma_mask	= ~0,					\
-	.irq		= base##_IRQ,				\
-}
+#define APB_DEVICE(name, busid, base, plat)	\
+static AMBA_APB_DEVICE(name, busid, 0, VERSATILE_##base##_BASE, base##_IRQ, plat)
+
+#define AHB_DEVICE(name, busid, base, plat)	\
+static AMBA_AHB_DEVICE(name, busid, 0, VERSATILE_##base##_BASE, base##_IRQ, plat)
 
 #endif
diff --git a/arch/arm/mach-versatile/include/mach/entry-macro.S b/arch/arm/mach-versatile/include/mach/entry-macro.S
deleted file mode 100644
index b6f0dbf..0000000
--- a/arch/arm/mach-versatile/include/mach/entry-macro.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * arch/arm/mach-versatile/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for Versatile platforms
- *
- * 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.
- */
-
-		.macro	disable_fiq
-		.endm
-
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
diff --git a/arch/arm/mach-versatile/include/mach/io.h b/arch/arm/mach-versatile/include/mach/io.h
deleted file mode 100644
index f067c14..0000000
--- a/arch/arm/mach-versatile/include/mach/io.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *  arch/arm/mach-versatile/include/mach/io.h
- *
- *  Copyright (C) 2003 ARM 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#endif
diff --git a/arch/arm/mach-versatile/include/mach/system.h b/arch/arm/mach-versatile/include/mach/system.h
deleted file mode 100644
index f3fa347..0000000
--- a/arch/arm/mach-versatile/include/mach/system.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  arch/arm/mach-versatile/include/mach/system.h
- *
- *  Copyright (C) 2003 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	/*
-	 * This should do all the clock switching
-	 * and wait for interrupt tricks
-	 */
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c
index 90069bc..d2268be8 100644
--- a/arch/arm/mach-versatile/pci.c
+++ b/arch/arm/mach-versatile/pci.c
@@ -24,7 +24,6 @@
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/mach/pci.h>
 
 /*
@@ -191,7 +190,7 @@
 	.flags	= IORESOURCE_MEM | IORESOURCE_PREFETCH,
 };
 
-static int __init pci_versatile_setup_resources(struct list_head *resources)
+static int __init pci_versatile_setup_resources(struct pci_sys_data *sys)
 {
 	int ret = 0;
 
@@ -219,9 +218,9 @@
 	 * the mem resource for this bus
 	 * the prefetch mem resource for this bus
 	 */
-	pci_add_resource(resources, &io_mem);
-	pci_add_resource(resources, &non_mem);
-	pci_add_resource(resources, &pre_mem);
+	pci_add_resource_offset(&sys->resources, &io_mem, sys->io_offset);
+	pci_add_resource_offset(&sys->resources, &non_mem, sys->mem_offset);
+	pci_add_resource_offset(&sys->resources, &pre_mem, sys->mem_offset);
 
 	goto out;
 
@@ -250,7 +249,7 @@
 
 	if (nr == 0) {
 		sys->mem_offset = 0;
-		ret = pci_versatile_setup_resources(&sys->resources);
+		ret = pci_versatile_setup_resources(sys);
 		if (ret < 0) {
 			printk("pci_versatile_setup: resources... oops?\n");
 			goto out;
diff --git a/arch/arm/mach-versatile/versatile_pb.c b/arch/arm/mach-versatile/versatile_pb.c
index 9581c19..1973833 100644
--- a/arch/arm/mach-versatile/versatile_pb.c
+++ b/arch/arm/mach-versatile/versatile_pb.c
@@ -58,28 +58,28 @@
 	.irq_base	= IRQ_GPIO3_START,
 };
 
-#define UART3_IRQ	{ IRQ_SIC_UART3, NO_IRQ }
-#define SCI1_IRQ	{ IRQ_SIC_SCI3, NO_IRQ }
+#define UART3_IRQ	{ IRQ_SIC_UART3 }
+#define SCI1_IRQ	{ IRQ_SIC_SCI3 }
 #define MMCI1_IRQ	{ IRQ_MMCI1A, IRQ_SIC_MMCI1B }
 
 /*
  * These devices are connected via the core APB bridge
  */
-#define GPIO2_IRQ	{ IRQ_GPIOINT2, NO_IRQ }
-#define GPIO3_IRQ	{ IRQ_GPIOINT3, NO_IRQ }
+#define GPIO2_IRQ	{ IRQ_GPIOINT2 }
+#define GPIO3_IRQ	{ IRQ_GPIOINT3 }
 
 /*
  * These devices are connected via the DMA APB bridge
  */
 
 /* FPGA Primecells */
-AMBA_DEVICE(uart3, "fpga:09", UART3,    NULL);
-AMBA_DEVICE(sci1,  "fpga:0a", SCI1,     NULL);
-AMBA_DEVICE(mmc1,  "fpga:0b", MMCI1,    &mmc1_plat_data);
+APB_DEVICE(uart3, "fpga:09", UART3,    NULL);
+APB_DEVICE(sci1,  "fpga:0a", SCI1,     NULL);
+APB_DEVICE(mmc1,  "fpga:0b", MMCI1,    &mmc1_plat_data);
 
 /* DevChip Primecells */
-AMBA_DEVICE(gpio2, "dev:e6",  GPIO2,    &gpio2_plat_data);
-AMBA_DEVICE(gpio3, "dev:e7",  GPIO3,    &gpio3_plat_data);
+APB_DEVICE(gpio2, "dev:e6",  GPIO2,    &gpio2_plat_data);
+APB_DEVICE(gpio3, "dev:e7",  GPIO3,    &gpio3_plat_data);
 
 static struct amba_device *amba_devs[] __initdata = {
 	&uart3_device,
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index 88c3ba1..cf8730d 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -1,14 +1,55 @@
 menu "Versatile Express platform type"
 	depends on ARCH_VEXPRESS
 
-config ARCH_VEXPRESS_CA9X4
-	bool "Versatile Express Cortex-A9x4 tile"
-	select CPU_V7
-	select ARM_GIC
+config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
+	bool
 	select ARM_ERRATA_720789
 	select ARM_ERRATA_751472
-	select PL310_ERRATA_753970
+	select PL310_ERRATA_753970 if CACHE_PL310
+	help
+	  Provides common dependencies for Versatile Express platforms
+	  based on Cortex-A5 and Cortex-A9 processors. In order to
+	  build a working kernel, you must also enable relevant core
+	  tile support or Flattened Device Tree based support options.
+
+config ARCH_VEXPRESS_CA9X4
+	bool "Versatile Express Cortex-A9x4 tile"
+	select ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
+	select ARM_GIC
+	select CPU_V7
 	select HAVE_SMP
 	select MIGHT_HAVE_CACHE_L2X0
 
+config ARCH_VEXPRESS_DT
+	bool "Device Tree support for Versatile Express platforms"
+	select ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
+	select ARM_GIC
+	select ARM_PATCH_PHYS_VIRT
+	select AUTO_ZRELADDR
+	select CPU_V7
+	select HAVE_SMP
+	select MIGHT_HAVE_CACHE_L2X0
+	select USE_OF
+	help
+	  New Versatile Express platforms require Flattened Device Tree to
+	  be passed to the kernel.
+
+	  This option enables support for systems using Cortex processor based
+	  ARM core and logic (FPGA) tiles on the Versatile Express motherboard,
+	  for example:
+
+	  - CoreTile Express A5x2 (V2P-CA5s)
+	  - CoreTile Express A9x4 (V2P-CA9)
+	  - CoreTile Express A15x2 (V2P-CA15)
+	  - LogicTile Express 13MG (V2F-2XV6) with A5, A7, A9 or A15 SMMs
+	    (Soft Macrocell Models)
+	  - Versatile Express RTSMs (Models)
+
+	  You must boot using a Flattened Device Tree in order to use these
+	  platforms. The traditional (ATAGs) boot method is not usable on
+	  these boards with this option.
+
+	  If your bootloader supports Flattened Device Tree based booting,
+	  say Y here.
+
 endmenu
diff --git a/arch/arm/mach-vexpress/Makefile.boot b/arch/arm/mach-vexpress/Makefile.boot
index 8630b3d..909f85e 100644
--- a/arch/arm/mach-vexpress/Makefile.boot
+++ b/arch/arm/mach-vexpress/Makefile.boot
@@ -1,3 +1,9 @@
+# Those numbers are used only by the non-DT V2P-CA9 platform
+# The DT-enabled ones require CONFIG_AUTO_ZRELADDR=y
    zreladdr-y	+= 0x60008000
 params_phys-y	:= 0x60000100
 initrd_phys-y	:= 0x60800000
+
+dtb-$(CONFIG_ARCH_VEXPRESS_DT)	+= vexpress-v2p-ca5s.dtb \
+				   vexpress-v2p-ca9.dtb \
+				   vexpress-v2p-ca15-tc1.dtb
diff --git a/arch/arm/mach-vexpress/core.h b/arch/arm/mach-vexpress/core.h
index f439715..a3a4980 100644
--- a/arch/arm/mach-vexpress/core.h
+++ b/arch/arm/mach-vexpress/core.h
@@ -1,19 +1,7 @@
-#define __MMIO_P2V(x)	(((x) & 0xfffff) | (((x) & 0x0f000000) >> 4) | 0xf8000000)
-#define MMIO_P2V(x)	((void __iomem *)__MMIO_P2V(x))
+/* 2MB large area for motherboard's peripherals static mapping */
+#define V2M_PERIPH 0xf8000000
 
-#define AMBA_DEVICE(name,busid,base,plat)	\
-struct amba_device name##_device = {		\
-	.dev		= {			\
-		.coherent_dma_mask = ~0UL,	\
-		.init_name = busid,		\
-		.platform_data = plat,		\
-	},					\
-	.res		= {			\
-		.start	= base,			\
-		.end	= base + SZ_4K - 1,	\
-		.flags	= IORESOURCE_MEM,	\
-	},					\
-	.dma_mask	= ~0UL,			\
-	.irq		= IRQ_##base,		\
-	/* .dma		= DMA_##base,*/		\
-}
+/* Tile's peripherals static mappings should start here */
+#define V2T_PERIPH 0xf8200000
+
+void vexpress_dt_smp_map_io(void);
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index b1e87c1..c65cc3b 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -30,57 +30,40 @@
 
 #include <plat/clcd.h>
 
-#define V2M_PA_CS7	0x10000000
-
 static struct map_desc ct_ca9x4_io_desc[] __initdata = {
 	{
-		.virtual	= __MMIO_P2V(CT_CA9X4_MPIC),
-		.pfn		= __phys_to_pfn(CT_CA9X4_MPIC),
-		.length		= SZ_16K,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= __MMIO_P2V(CT_CA9X4_SP804_TIMER),
-		.pfn		= __phys_to_pfn(CT_CA9X4_SP804_TIMER),
-		.length		= SZ_4K,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= __MMIO_P2V(CT_CA9X4_L2CC),
-		.pfn		= __phys_to_pfn(CT_CA9X4_L2CC),
-		.length		= SZ_4K,
-		.type		= MT_DEVICE,
+		.virtual        = V2T_PERIPH,
+		.pfn            = __phys_to_pfn(CT_CA9X4_MPIC),
+		.length         = SZ_8K,
+		.type           = MT_DEVICE,
 	},
 };
 
 static void __init ct_ca9x4_map_io(void)
 {
-#ifdef CONFIG_LOCAL_TIMERS
-	twd_base = MMIO_P2V(A9_MPCORE_TWD);
-#endif
 	iotable_init(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc));
 }
 
+#ifdef CONFIG_HAVE_ARM_TWD
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, A9_MPCORE_TWD, IRQ_LOCALTIMER);
+
+static void __init ca9x4_twd_init(void)
+{
+	int err = twd_local_timer_register(&twd_local_timer);
+	if (err)
+		pr_err("twd_local_timer_register failed %d\n", err);
+}
+#else
+#define ca9x4_twd_init()	do {} while(0)
+#endif
+
 static void __init ct_ca9x4_init_irq(void)
 {
-	gic_init(0, 29, MMIO_P2V(A9_MPCORE_GIC_DIST),
-		 MMIO_P2V(A9_MPCORE_GIC_CPU));
+	gic_init(0, 29, ioremap(A9_MPCORE_GIC_DIST, SZ_4K),
+		 ioremap(A9_MPCORE_GIC_CPU, SZ_256));
+	ca9x4_twd_init();
 }
 
-#if 0
-static void __init ct_ca9x4_timer_init(void)
-{
-	writel(0, MMIO_P2V(CT_CA9X4_TIMER0) + TIMER_CTRL);
-	writel(0, MMIO_P2V(CT_CA9X4_TIMER1) + TIMER_CTRL);
-
-	sp804_clocksource_init(MMIO_P2V(CT_CA9X4_TIMER1), "ct-timer1");
-	sp804_clockevents_init(MMIO_P2V(CT_CA9X4_TIMER0), IRQ_CT_CA9X4_TIMER0,
-		"ct-timer0");
-}
-
-static struct sys_timer ct_ca9x4_timer = {
-	.init	= ct_ca9x4_timer_init,
-};
-#endif
-
 static void ct_ca9x4_clcd_enable(struct clcd_fb *fb)
 {
 	v2m_cfg_write(SYS_CFG_MUXFPGA | SYS_CFG_SITE_DB1, 0);
@@ -109,10 +92,10 @@
 	.remove		= versatile_clcd_remove_dma,
 };
 
-static AMBA_DEVICE(clcd, "ct:clcd", CT_CA9X4_CLCDC, &ct_ca9x4_clcd_data);
-static AMBA_DEVICE(dmc, "ct:dmc", CT_CA9X4_DMC, NULL);
-static AMBA_DEVICE(smc, "ct:smc", CT_CA9X4_SMC, NULL);
-static AMBA_DEVICE(gpio, "ct:gpio", CT_CA9X4_GPIO, NULL);
+static AMBA_AHB_DEVICE(clcd, "ct:clcd", 0, CT_CA9X4_CLCDC, IRQ_CT_CA9X4_CLCDC, &ct_ca9x4_clcd_data);
+static AMBA_APB_DEVICE(dmc, "ct:dmc", 0, CT_CA9X4_DMC, IRQ_CT_CA9X4_DMC, NULL);
+static AMBA_APB_DEVICE(smc, "ct:smc", 0, CT_CA9X4_SMC, IRQ_CT_CA9X4_SMC, NULL);
+static AMBA_APB_DEVICE(gpio, "ct:gpio", 0, CT_CA9X4_GPIO, IRQ_CT_CA9X4_GPIO, NULL);
 
 static struct amba_device *ct_ca9x4_amba_devs[] __initdata = {
 	&clcd_device,
@@ -201,7 +184,7 @@
 	int i;
 
 #ifdef CONFIG_CACHE_L2X0
-	void __iomem *l2x0_base = MMIO_P2V(CT_CA9X4_L2CC);
+	void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K);
 
 	/* set RAM latencies to 1 cycle for this core tile. */
 	writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL);
@@ -217,9 +200,17 @@
 }
 
 #ifdef CONFIG_SMP
+static void *ct_ca9x4_scu_base __initdata;
+
 static void __init ct_ca9x4_init_cpu_map(void)
 {
-	int i, ncores = scu_get_core_count(MMIO_P2V(A9_MPCORE_SCU));
+	int i, ncores;
+
+	ct_ca9x4_scu_base = ioremap(A9_MPCORE_SCU, SZ_128);
+	if (WARN_ON(!ct_ca9x4_scu_base))
+		return;
+
+	ncores = scu_get_core_count(ct_ca9x4_scu_base);
 
 	if (ncores > nr_cpu_ids) {
 		pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
@@ -235,7 +226,7 @@
 
 static void __init ct_ca9x4_smp_enable(unsigned int max_cpus)
 {
-	scu_enable(MMIO_P2V(A9_MPCORE_SCU));
+	scu_enable(ct_ca9x4_scu_base);
 }
 #endif
 
diff --git a/arch/arm/mach-vexpress/hotplug.c b/arch/arm/mach-vexpress/hotplug.c
index 3034a4d..c504a72 100644
--- a/arch/arm/mach-vexpress/hotplug.c
+++ b/arch/arm/mach-vexpress/hotplug.c
@@ -14,7 +14,7 @@
 
 #include <asm/cacheflush.h>
 #include <asm/smp_plat.h>
-#include <asm/system.h>
+#include <asm/cp15.h>
 
 extern volatile int pen_release;
 
diff --git a/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h b/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h
index a34d3d4..84acf84 100644
--- a/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h
+++ b/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h
@@ -22,9 +22,6 @@
 #define CT_CA9X4_SYSWDT		(0x1e007000)
 #define CT_CA9X4_L2CC		(0x1e00a000)
 
-#define CT_CA9X4_TIMER0		(CT_CA9X4_SP804_TIMER + 0x000)
-#define CT_CA9X4_TIMER1		(CT_CA9X4_SP804_TIMER + 0x020)
-
 #define A9_MPCORE_SCU		(CT_CA9X4_MPIC + 0x0000)
 #define A9_MPCORE_GIC_CPU	(CT_CA9X4_MPIC + 0x0100)
 #define A9_MPCORE_GIT		(CT_CA9X4_MPIC + 0x0200)
@@ -35,7 +32,7 @@
  * Interrupts.  Those in {} are for AMBA devices
  */
 #define IRQ_CT_CA9X4_CLCDC	{ 76 }
-#define IRQ_CT_CA9X4_DMC	{ -1 }
+#define IRQ_CT_CA9X4_DMC	{ 0 }
 #define IRQ_CT_CA9X4_SMC	{ 77, 78 }
 #define IRQ_CT_CA9X4_TIMER0	80
 #define IRQ_CT_CA9X4_TIMER1	81
diff --git a/arch/arm/mach-vexpress/include/mach/debug-macro.S b/arch/arm/mach-vexpress/include/mach/debug-macro.S
index fd9e6c7..fa82247 100644
--- a/arch/arm/mach-vexpress/include/mach/debug-macro.S
+++ b/arch/arm/mach-vexpress/include/mach/debug-macro.S
@@ -10,12 +10,34 @@
  * published by the Free Software Foundation.
  */
 
-#define DEBUG_LL_UART_OFFSET	0x00009000
+#define DEBUG_LL_PHYS_BASE		0x10000000
+#define DEBUG_LL_UART_OFFSET		0x00009000
+
+#define DEBUG_LL_PHYS_BASE_RS1		0x1c000000
+#define DEBUG_LL_UART_OFFSET_RS1	0x00090000
+
+#define DEBUG_LL_VIRT_BASE		0xf8000000
 
 		.macro	addruart,rp,rv,tmp
-		mov	\rp, #DEBUG_LL_UART_OFFSET
-		orr	\rv, \rp, #0xf8000000	@ virtual base
-		orr	\rp, \rp, #0x10000000	@ physical base
+
+		@ Make an educated guess regarding the memory map:
+		@ - the original A9 core tile, which has MPCore peripherals
+		@   located at 0x1e000000, should use UART at 0x10009000
+		@ - all other (RS1 complaint) tiles use UART mapped
+		@   at 0x1c090000
+		mrc	p15, 4, \tmp, c15, c0, 0
+		cmp	\tmp, #0x1e000000
+
+		@ Original memory map
+		moveq	\rp, #DEBUG_LL_UART_OFFSET
+		orreq	\rv, \rp, #DEBUG_LL_VIRT_BASE
+		orreq	\rp, \rp, #DEBUG_LL_PHYS_BASE
+
+		@ RS1 memory map
+		movne	\rp, #DEBUG_LL_UART_OFFSET_RS1
+		orrne	\rv, \rp, #DEBUG_LL_VIRT_BASE
+		orrne	\rp, \rp, #DEBUG_LL_PHYS_BASE_RS1
+
 		.endm
 
 #include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/mach-vexpress/include/mach/entry-macro.S b/arch/arm/mach-vexpress/include/mach/entry-macro.S
deleted file mode 100644
index a14f9e6..0000000
--- a/arch/arm/mach-vexpress/include/mach/entry-macro.S
+++ /dev/null
@@ -1,5 +0,0 @@
-	.macro	disable_fiq
-	.endm
-
-	.macro	arch_ret_to_user, tmp1, tmp2
-	.endm
diff --git a/arch/arm/mach-vexpress/include/mach/io.h b/arch/arm/mach-vexpress/include/mach/io.h
deleted file mode 100644
index 13522d8..0000000
--- a/arch/arm/mach-vexpress/include/mach/io.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  arch/arm/mach-vexpress/include/mach/io.h
- *
- *  Copyright (C) 2003 ARM 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#endif
diff --git a/arch/arm/mach-vexpress/include/mach/irqs.h b/arch/arm/mach-vexpress/include/mach/irqs.h
index 7054cbf..4b10ee7 100644
--- a/arch/arm/mach-vexpress/include/mach/irqs.h
+++ b/arch/arm/mach-vexpress/include/mach/irqs.h
@@ -1,4 +1,4 @@
 #define IRQ_LOCALTIMER		29
 #define IRQ_LOCALWDOG		30
 
-#define NR_IRQS	128
+#define NR_IRQS	256
diff --git a/arch/arm/mach-vexpress/include/mach/motherboard.h b/arch/arm/mach-vexpress/include/mach/motherboard.h
index 0a3a375..31a9289 100644
--- a/arch/arm/mach-vexpress/include/mach/motherboard.h
+++ b/arch/arm/mach-vexpress/include/mach/motherboard.h
@@ -39,33 +39,30 @@
 #define V2M_CF			(V2M_PA_CS7 + 0x0001a000)
 #define V2M_CLCD		(V2M_PA_CS7 + 0x0001f000)
 
-#define V2M_SYS_ID		(V2M_SYSREGS + 0x000)
-#define V2M_SYS_SW		(V2M_SYSREGS + 0x004)
-#define V2M_SYS_LED		(V2M_SYSREGS + 0x008)
-#define V2M_SYS_100HZ		(V2M_SYSREGS + 0x024)
-#define V2M_SYS_FLAGS		(V2M_SYSREGS + 0x030)
-#define V2M_SYS_FLAGSSET	(V2M_SYSREGS + 0x030)
-#define V2M_SYS_FLAGSCLR	(V2M_SYSREGS + 0x034)
-#define V2M_SYS_NVFLAGS		(V2M_SYSREGS + 0x038)
-#define V2M_SYS_NVFLAGSSET	(V2M_SYSREGS + 0x038)
-#define V2M_SYS_NVFLAGSCLR	(V2M_SYSREGS + 0x03c)
-#define V2M_SYS_MCI		(V2M_SYSREGS + 0x048)
-#define V2M_SYS_FLASH		(V2M_SYSREGS + 0x03c)
-#define V2M_SYS_CFGSW		(V2M_SYSREGS + 0x058)
-#define V2M_SYS_24MHZ		(V2M_SYSREGS + 0x05c)
-#define V2M_SYS_MISC		(V2M_SYSREGS + 0x060)
-#define V2M_SYS_DMA		(V2M_SYSREGS + 0x064)
-#define V2M_SYS_PROCID0		(V2M_SYSREGS + 0x084)
-#define V2M_SYS_PROCID1		(V2M_SYSREGS + 0x088)
-#define V2M_SYS_CFGDATA		(V2M_SYSREGS + 0x0a0)
-#define V2M_SYS_CFGCTRL		(V2M_SYSREGS + 0x0a4)
-#define V2M_SYS_CFGSTAT		(V2M_SYSREGS + 0x0a8)
-
-#define V2M_TIMER0		(V2M_TIMER01 + 0x000)
-#define V2M_TIMER1		(V2M_TIMER01 + 0x020)
-
-#define V2M_TIMER2		(V2M_TIMER23 + 0x000)
-#define V2M_TIMER3		(V2M_TIMER23 + 0x020)
+/*
+ * Offsets from SYSREGS base
+ */
+#define V2M_SYS_ID		0x000
+#define V2M_SYS_SW		0x004
+#define V2M_SYS_LED		0x008
+#define V2M_SYS_100HZ		0x024
+#define V2M_SYS_FLAGS		0x030
+#define V2M_SYS_FLAGSSET	0x030
+#define V2M_SYS_FLAGSCLR	0x034
+#define V2M_SYS_NVFLAGS		0x038
+#define V2M_SYS_NVFLAGSSET	0x038
+#define V2M_SYS_NVFLAGSCLR	0x03c
+#define V2M_SYS_MCI		0x048
+#define V2M_SYS_FLASH		0x03c
+#define V2M_SYS_CFGSW		0x058
+#define V2M_SYS_24MHZ		0x05c
+#define V2M_SYS_MISC		0x060
+#define V2M_SYS_DMA		0x064
+#define V2M_SYS_PROCID0		0x084
+#define V2M_SYS_PROCID1		0x088
+#define V2M_SYS_CFGDATA		0x0a0
+#define V2M_SYS_CFGCTRL		0x0a4
+#define V2M_SYS_CFGSTAT		0x0a8
 
 
 /*
@@ -117,6 +114,13 @@
 
 int v2m_cfg_write(u32 devfn, u32 data);
 int v2m_cfg_read(u32 devfn, u32 *data);
+void v2m_flags_set(u32 data);
+
+/*
+ * Miscellaneous
+ */
+#define SYS_MISC_MASTERSITE	(1 << 14)
+#define SYS_PROCIDx_HBI_MASK	0xfff
 
 /*
  * Core tile IDs
diff --git a/arch/arm/mach-vexpress/include/mach/system.h b/arch/arm/mach-vexpress/include/mach/system.h
deleted file mode 100644
index f653a8e..0000000
--- a/arch/arm/mach-vexpress/include/mach/system.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  arch/arm/mach-vexpress/include/mach/system.h
- *
- *  Copyright (C) 2003 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	/*
-	 * This should do all the clock switching
-	 * and wait for interrupt tricks
-	 */
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-vexpress/include/mach/uncompress.h b/arch/arm/mach-vexpress/include/mach/uncompress.h
index 7972c57..7dab559 100644
--- a/arch/arm/mach-vexpress/include/mach/uncompress.h
+++ b/arch/arm/mach-vexpress/include/mach/uncompress.h
@@ -22,7 +22,27 @@
 #define AMBA_UART_CR(base)	(*(volatile unsigned char *)((base) + 0x30))
 #define AMBA_UART_FR(base)	(*(volatile unsigned char *)((base) + 0x18))
 
-#define get_uart_base()	(0x10000000 + 0x00009000)
+#define UART_BASE	0x10009000
+#define UART_BASE_RS1	0x1c090000
+
+static unsigned long get_uart_base(void)
+{
+	unsigned long mpcore_periph;
+
+	/*
+	 * Make an educated guess regarding the memory map:
+	 * - the original A9 core tile, which has MPCore peripherals
+	 *   located at 0x1e000000, should use UART at 0x10009000
+	 * - all other (RS1 complaint) tiles use UART mapped
+	 *   at 0x1c090000
+	 */
+	asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (mpcore_periph));
+
+	if (mpcore_periph == 0x1e000000)
+		return UART_BASE;
+	else
+		return UART_BASE_RS1;
+}
 
 /*
  * This does not append a newline
diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c
index 124ffb1..14ba112 100644
--- a/arch/arm/mach-vexpress/platsmp.c
+++ b/arch/arm/mach-vexpress/platsmp.c
@@ -12,21 +12,168 @@
 #include <linux/errno.h>
 #include <linux/smp.h>
 #include <linux/io.h>
+#include <linux/of_fdt.h>
+
+#include <asm/smp_scu.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/map.h>
 
 #include <mach/motherboard.h>
-#define V2M_PA_CS7 0x10000000
 
 #include "core.h"
 
 extern void versatile_secondary_startup(void);
 
+#if defined(CONFIG_OF)
+
+static enum {
+	GENERIC_SCU,
+	CORTEX_A9_SCU,
+} vexpress_dt_scu __initdata = GENERIC_SCU;
+
+static struct map_desc vexpress_dt_cortex_a9_scu_map __initdata = {
+	.virtual	= V2T_PERIPH,
+	/* .pfn	set in vexpress_dt_init_cortex_a9_scu() */
+	.length		= SZ_128,
+	.type		= MT_DEVICE,
+};
+
+static void *vexpress_dt_cortex_a9_scu_base __initdata;
+
+const static char *vexpress_dt_cortex_a9_match[] __initconst = {
+	"arm,cortex-a5-scu",
+	"arm,cortex-a9-scu",
+	NULL
+};
+
+static int __init vexpress_dt_find_scu(unsigned long node,
+		const char *uname, int depth, void *data)
+{
+	if (of_flat_dt_match(node, vexpress_dt_cortex_a9_match)) {
+		phys_addr_t phys_addr;
+		__be32 *reg = of_get_flat_dt_prop(node, "reg", NULL);
+
+		if (WARN_ON(!reg))
+			return -EINVAL;
+
+		phys_addr = be32_to_cpup(reg);
+		vexpress_dt_scu = CORTEX_A9_SCU;
+
+		vexpress_dt_cortex_a9_scu_map.pfn = __phys_to_pfn(phys_addr);
+		iotable_init(&vexpress_dt_cortex_a9_scu_map, 1);
+		vexpress_dt_cortex_a9_scu_base = ioremap(phys_addr, SZ_256);
+		if (WARN_ON(!vexpress_dt_cortex_a9_scu_base))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+void __init vexpress_dt_smp_map_io(void)
+{
+	if (initial_boot_params)
+		WARN_ON(of_scan_flat_dt(vexpress_dt_find_scu, NULL));
+}
+
+static int __init vexpress_dt_cpus_num(unsigned long node, const char *uname,
+		int depth, void *data)
+{
+	static int prev_depth = -1;
+	static int nr_cpus = -1;
+
+	if (prev_depth > depth && nr_cpus > 0)
+		return nr_cpus;
+
+	if (nr_cpus < 0 && strcmp(uname, "cpus") == 0)
+		nr_cpus = 0;
+
+	if (nr_cpus >= 0) {
+		const char *device_type = of_get_flat_dt_prop(node,
+				"device_type", NULL);
+
+		if (device_type && strcmp(device_type, "cpu") == 0)
+			nr_cpus++;
+	}
+
+	prev_depth = depth;
+
+	return 0;
+}
+
+static void __init vexpress_dt_smp_init_cpus(void)
+{
+	int ncores = 0, i;
+
+	switch (vexpress_dt_scu) {
+	case GENERIC_SCU:
+		ncores = of_scan_flat_dt(vexpress_dt_cpus_num, NULL);
+		break;
+	case CORTEX_A9_SCU:
+		ncores = scu_get_core_count(vexpress_dt_cortex_a9_scu_base);
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	}
+
+	if (ncores < 2)
+		return;
+
+	if (ncores > nr_cpu_ids) {
+		pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
+				ncores, nr_cpu_ids);
+		ncores = nr_cpu_ids;
+	}
+
+	for (i = 0; i < ncores; ++i)
+		set_cpu_possible(i, true);
+
+	set_smp_cross_call(gic_raise_softirq);
+}
+
+static void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus)
+{
+	int i;
+
+	switch (vexpress_dt_scu) {
+	case GENERIC_SCU:
+		for (i = 0; i < max_cpus; i++)
+			set_cpu_present(i, true);
+		break;
+	case CORTEX_A9_SCU:
+		scu_enable(vexpress_dt_cortex_a9_scu_base);
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	}
+}
+
+#else
+
+static void __init vexpress_dt_smp_init_cpus(void)
+{
+	WARN_ON(1);
+}
+
+void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus)
+{
+	WARN_ON(1);
+}
+
+#endif
+
 /*
  * Initialise the CPU possible map early - this describes the CPUs
  * which may be present or become present in the system.
  */
 void __init smp_init_cpus(void)
 {
-	ct_desc->init_cpu_map();
+	if (ct_desc)
+		ct_desc->init_cpu_map();
+	else
+		vexpress_dt_smp_init_cpus();
+
 }
 
 void __init platform_smp_prepare_cpus(unsigned int max_cpus)
@@ -35,7 +182,10 @@
 	 * Initialise the present map, which describes the set of CPUs
 	 * actually populated at the present time.
 	 */
-	ct_desc->smp_enable(max_cpus);
+	if (ct_desc)
+		ct_desc->smp_enable(max_cpus);
+	else
+		vexpress_dt_smp_prepare_cpus(max_cpus);
 
 	/*
 	 * Write the address of secondary startup into the
@@ -43,7 +193,5 @@
 	 * until it receives a soft interrupt, and then the
 	 * secondary CPU branches to this address.
 	 */
-	writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR));
-	writel(virt_to_phys(versatile_secondary_startup),
-		MMIO_P2V(V2M_SYS_FLAGSSET));
+	v2m_flags_set(virt_to_phys(versatile_secondary_startup));
 }
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index b4a28ca..47cdcca 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -6,6 +6,10 @@
 #include <linux/amba/mmci.h>
 #include <linux/io.h>
 #include <linux/init.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/ata_platform.h>
 #include <linux/smsc911x.h>
@@ -21,6 +25,8 @@
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
 #include <asm/hardware/arm_timer.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/hardware/gic.h>
 #include <asm/hardware/timer-sp.h>
 #include <asm/hardware/sp810.h>
 #include <asm/hardware/gic.h>
@@ -40,29 +46,45 @@
 
 static struct map_desc v2m_io_desc[] __initdata = {
 	{
-		.virtual	= __MMIO_P2V(V2M_PA_CS7),
+		.virtual	= V2M_PERIPH,
 		.pfn		= __phys_to_pfn(V2M_PA_CS7),
 		.length		= SZ_128K,
 		.type		= MT_DEVICE,
 	},
 };
 
-static void __init v2m_timer_init(void)
+static void __iomem *v2m_sysreg_base;
+
+static void __init v2m_sysctl_init(void __iomem *base)
 {
 	u32 scctrl;
 
+	if (WARN_ON(!base))
+		return;
+
 	/* Select 1MHz TIMCLK as the reference clock for SP804 timers */
-	scctrl = readl(MMIO_P2V(V2M_SYSCTL + SCCTRL));
+	scctrl = readl(base + SCCTRL);
 	scctrl |= SCCTRL_TIMEREN0SEL_TIMCLK;
 	scctrl |= SCCTRL_TIMEREN1SEL_TIMCLK;
-	writel(scctrl, MMIO_P2V(V2M_SYSCTL + SCCTRL));
+	writel(scctrl, base + SCCTRL);
+}
 
-	writel(0, MMIO_P2V(V2M_TIMER0) + TIMER_CTRL);
-	writel(0, MMIO_P2V(V2M_TIMER1) + TIMER_CTRL);
+static void __init v2m_sp804_init(void __iomem *base, unsigned int irq)
+{
+	if (WARN_ON(!base || irq == NO_IRQ))
+		return;
 
-	sp804_clocksource_init(MMIO_P2V(V2M_TIMER1), "v2m-timer1");
-	sp804_clockevents_init(MMIO_P2V(V2M_TIMER0), IRQ_V2M_TIMER0,
-		"v2m-timer0");
+	writel(0, base + TIMER_1_BASE + TIMER_CTRL);
+	writel(0, base + TIMER_2_BASE + TIMER_CTRL);
+
+	sp804_clocksource_init(base + TIMER_2_BASE, "v2m-timer1");
+	sp804_clockevents_init(base + TIMER_1_BASE, irq, "v2m-timer0");
+}
+
+static void __init v2m_timer_init(void)
+{
+	v2m_sysctl_init(ioremap(V2M_SYSCTL, SZ_4K));
+	v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0);
 }
 
 static struct sys_timer v2m_timer = {
@@ -82,14 +104,14 @@
 	devfn |= SYS_CFG_START | SYS_CFG_WRITE;
 
 	spin_lock(&v2m_cfg_lock);
-	val = readl(MMIO_P2V(V2M_SYS_CFGSTAT));
-	writel(val & ~SYS_CFG_COMPLETE, MMIO_P2V(V2M_SYS_CFGSTAT));
+	val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
+	writel(val & ~SYS_CFG_COMPLETE, v2m_sysreg_base + V2M_SYS_CFGSTAT);
 
-	writel(data, MMIO_P2V(V2M_SYS_CFGDATA));
-	writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL));
+	writel(data, v2m_sysreg_base +  V2M_SYS_CFGDATA);
+	writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
 
 	do {
-		val = readl(MMIO_P2V(V2M_SYS_CFGSTAT));
+		val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
 	} while (val == 0);
 	spin_unlock(&v2m_cfg_lock);
 
@@ -103,22 +125,28 @@
 	devfn |= SYS_CFG_START;
 
 	spin_lock(&v2m_cfg_lock);
-	writel(0, MMIO_P2V(V2M_SYS_CFGSTAT));
-	writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL));
+	writel(0, v2m_sysreg_base + V2M_SYS_CFGSTAT);
+	writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
 
 	mb();
 
 	do {
 		cpu_relax();
-		val = readl(MMIO_P2V(V2M_SYS_CFGSTAT));
+		val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
 	} while (val == 0);
 
-	*data = readl(MMIO_P2V(V2M_SYS_CFGDATA));
+	*data = readl(v2m_sysreg_base + V2M_SYS_CFGDATA);
 	spin_unlock(&v2m_cfg_lock);
 
 	return !!(val & SYS_CFG_ERR);
 }
 
+void __init v2m_flags_set(u32 data)
+{
+	writel(~0, v2m_sysreg_base + V2M_SYS_FLAGSCLR);
+	writel(data, v2m_sysreg_base + V2M_SYS_FLAGSSET);
+}
+
 
 static struct resource v2m_pcie_i2c_resource = {
 	.start	= V2M_SERIAL_BUS_PCI,
@@ -204,7 +232,7 @@
 
 static void v2m_flash_set_vpp(struct platform_device *pdev, int on)
 {
-	writel(on != 0, MMIO_P2V(V2M_SYS_FLASH));
+	writel(on != 0, v2m_sysreg_base + V2M_SYS_FLASH);
 }
 
 static struct physmap_flash_data v2m_flash_data = {
@@ -258,7 +286,7 @@
 
 static unsigned int v2m_mmci_status(struct device *dev)
 {
-	return readl(MMIO_P2V(V2M_SYS_MCI)) & (1 << 0);
+	return readl(v2m_sysreg_base + V2M_SYS_MCI) & (1 << 0);
 }
 
 static struct mmci_platform_data v2m_mmci_data = {
@@ -266,16 +294,16 @@
 	.status		= v2m_mmci_status,
 };
 
-static AMBA_DEVICE(aaci,  "mb:aaci",  V2M_AACI, NULL);
-static AMBA_DEVICE(mmci,  "mb:mmci",  V2M_MMCI, &v2m_mmci_data);
-static AMBA_DEVICE(kmi0,  "mb:kmi0",  V2M_KMI0, NULL);
-static AMBA_DEVICE(kmi1,  "mb:kmi1",  V2M_KMI1, NULL);
-static AMBA_DEVICE(uart0, "mb:uart0", V2M_UART0, NULL);
-static AMBA_DEVICE(uart1, "mb:uart1", V2M_UART1, NULL);
-static AMBA_DEVICE(uart2, "mb:uart2", V2M_UART2, NULL);
-static AMBA_DEVICE(uart3, "mb:uart3", V2M_UART3, NULL);
-static AMBA_DEVICE(wdt,   "mb:wdt",   V2M_WDT, NULL);
-static AMBA_DEVICE(rtc,   "mb:rtc",   V2M_RTC, NULL);
+static AMBA_APB_DEVICE(aaci,  "mb:aaci",  0, V2M_AACI, IRQ_V2M_AACI, NULL);
+static AMBA_APB_DEVICE(mmci,  "mb:mmci",  0, V2M_MMCI, IRQ_V2M_MMCI, &v2m_mmci_data);
+static AMBA_APB_DEVICE(kmi0,  "mb:kmi0",  0, V2M_KMI0, IRQ_V2M_KMI0, NULL);
+static AMBA_APB_DEVICE(kmi1,  "mb:kmi1",  0, V2M_KMI1, IRQ_V2M_KMI1, NULL);
+static AMBA_APB_DEVICE(uart0, "mb:uart0", 0, V2M_UART0, IRQ_V2M_UART0, NULL);
+static AMBA_APB_DEVICE(uart1, "mb:uart1", 0, V2M_UART1, IRQ_V2M_UART1, NULL);
+static AMBA_APB_DEVICE(uart2, "mb:uart2", 0, V2M_UART2, IRQ_V2M_UART2, NULL);
+static AMBA_APB_DEVICE(uart3, "mb:uart3", 0, V2M_UART3, IRQ_V2M_UART3, NULL);
+static AMBA_APB_DEVICE(wdt,   "mb:wdt",   0, V2M_WDT, IRQ_V2M_WDT, NULL);
+static AMBA_APB_DEVICE(rtc,   "mb:rtc",   0, V2M_RTC, IRQ_V2M_RTC, NULL);
 
 static struct amba_device *v2m_amba_devs[] __initdata = {
 	&aaci_device,
@@ -371,7 +399,7 @@
 {
 	ct_desc->init_early();
 	clkdev_add_table(v2m_lookups, ARRAY_SIZE(v2m_lookups));
-	versatile_sched_clock_init(MMIO_P2V(V2M_SYS_24MHZ), 24000000);
+	versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
 }
 
 static void v2m_power_off(void)
@@ -400,20 +428,23 @@
 	u32 current_tile_id;
 
 	ct_desc = NULL;
-	current_tile_id = readl(MMIO_P2V(V2M_SYS_PROCID0)) & V2M_CT_ID_MASK;
+	current_tile_id = readl(v2m_sysreg_base + V2M_SYS_PROCID0)
+				& V2M_CT_ID_MASK;
 
 	for (i = 0; i < ARRAY_SIZE(ct_descs) && !ct_desc; ++i)
 		if (ct_descs[i]->id == current_tile_id)
 			ct_desc = ct_descs[i];
 
 	if (!ct_desc)
-		panic("vexpress: failed to populate core tile description "
-		      "for tile ID 0x%8x\n", current_tile_id);
+		panic("vexpress: this kernel does not support core tile ID 0x%08x when booting via ATAGs.\n"
+		      "You may need a device tree blob or a different kernel to boot on this board.\n",
+		      current_tile_id);
 }
 
 static void __init v2m_map_io(void)
 {
 	iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
+	v2m_sysreg_base = ioremap(V2M_SYSREGS, SZ_4K);
 	v2m_populate_ct_desc();
 	ct_desc->map_io();
 }
@@ -452,3 +483,205 @@
 	.init_machine	= v2m_init,
 	.restart	= v2m_restart,
 MACHINE_END
+
+#if defined(CONFIG_ARCH_VEXPRESS_DT)
+
+static struct map_desc v2m_rs1_io_desc __initdata = {
+	.virtual	= V2M_PERIPH,
+	.pfn		= __phys_to_pfn(0x1c000000),
+	.length		= SZ_2M,
+	.type		= MT_DEVICE,
+};
+
+static int __init v2m_dt_scan_memory_map(unsigned long node, const char *uname,
+		int depth, void *data)
+{
+	const char **map = data;
+
+	if (strcmp(uname, "motherboard") != 0)
+		return 0;
+
+	*map = of_get_flat_dt_prop(node, "arm,v2m-memory-map", NULL);
+
+	return 1;
+}
+
+void __init v2m_dt_map_io(void)
+{
+	const char *map = NULL;
+
+	of_scan_flat_dt(v2m_dt_scan_memory_map, &map);
+
+	if (map && strcmp(map, "rs1") == 0)
+		iotable_init(&v2m_rs1_io_desc, 1);
+	else
+		iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
+
+#if defined(CONFIG_SMP)
+	vexpress_dt_smp_map_io();
+#endif
+}
+
+static struct clk_lookup v2m_dt_lookups[] = {
+	{	/* AMBA bus clock */
+		.con_id		= "apb_pclk",
+		.clk		= &dummy_apb_pclk,
+	}, {	/* SP804 timers */
+		.dev_id		= "sp804",
+		.con_id		= "v2m-timer0",
+		.clk		= &v2m_sp804_clk,
+	}, {	/* SP804 timers */
+		.dev_id		= "sp804",
+		.con_id		= "v2m-timer1",
+		.clk		= &v2m_sp804_clk,
+	}, {	/* PL180 MMCI */
+		.dev_id		= "mb:mmci", /* 10005000.mmci */
+		.clk		= &osc2_clk,
+	}, {	/* PL050 KMI0 */
+		.dev_id		= "10006000.kmi",
+		.clk		= &osc2_clk,
+	}, {	/* PL050 KMI1 */
+		.dev_id		= "10007000.kmi",
+		.clk		= &osc2_clk,
+	}, {	/* PL011 UART0 */
+		.dev_id		= "10009000.uart",
+		.clk		= &osc2_clk,
+	}, {	/* PL011 UART1 */
+		.dev_id		= "1000a000.uart",
+		.clk		= &osc2_clk,
+	}, {	/* PL011 UART2 */
+		.dev_id		= "1000b000.uart",
+		.clk		= &osc2_clk,
+	}, {	/* PL011 UART3 */
+		.dev_id		= "1000c000.uart",
+		.clk		= &osc2_clk,
+	}, {	/* SP805 WDT */
+		.dev_id		= "1000f000.wdt",
+		.clk		= &v2m_ref_clk,
+	}, {	/* PL111 CLCD */
+		.dev_id		= "1001f000.clcd",
+		.clk		= &osc1_clk,
+	},
+	/* RS1 memory map */
+	{	/* PL180 MMCI */
+		.dev_id		= "mb:mmci", /* 1c050000.mmci */
+		.clk		= &osc2_clk,
+	}, {	/* PL050 KMI0 */
+		.dev_id		= "1c060000.kmi",
+		.clk		= &osc2_clk,
+	}, {	/* PL050 KMI1 */
+		.dev_id		= "1c070000.kmi",
+		.clk		= &osc2_clk,
+	}, {	/* PL011 UART0 */
+		.dev_id		= "1c090000.uart",
+		.clk		= &osc2_clk,
+	}, {	/* PL011 UART1 */
+		.dev_id		= "1c0a0000.uart",
+		.clk		= &osc2_clk,
+	}, {	/* PL011 UART2 */
+		.dev_id		= "1c0b0000.uart",
+		.clk		= &osc2_clk,
+	}, {	/* PL011 UART3 */
+		.dev_id		= "1c0c0000.uart",
+		.clk		= &osc2_clk,
+	}, {	/* SP805 WDT */
+		.dev_id		= "1c0f0000.wdt",
+		.clk		= &v2m_ref_clk,
+	}, {	/* PL111 CLCD */
+		.dev_id		= "1c1f0000.clcd",
+		.clk		= &osc1_clk,
+	},
+};
+
+void __init v2m_dt_init_early(void)
+{
+	struct device_node *node;
+	u32 dt_hbi;
+
+	node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg");
+	v2m_sysreg_base = of_iomap(node, 0);
+	if (WARN_ON(!v2m_sysreg_base))
+		return;
+
+	/* Confirm board type against DT property, if available */
+	if (of_property_read_u32(allnodes, "arm,hbi", &dt_hbi) == 0) {
+		u32 misc = readl(v2m_sysreg_base + V2M_SYS_MISC);
+		u32 id = readl(v2m_sysreg_base + (misc & SYS_MISC_MASTERSITE ?
+				V2M_SYS_PROCID1 : V2M_SYS_PROCID0));
+		u32 hbi = id & SYS_PROCIDx_HBI_MASK;
+
+		if (WARN_ON(dt_hbi != hbi))
+			pr_warning("vexpress: DT HBI (%x) is not matching "
+					"hardware (%x)!\n", dt_hbi, hbi);
+	}
+
+	clkdev_add_table(v2m_dt_lookups, ARRAY_SIZE(v2m_dt_lookups));
+	versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
+}
+
+static  struct of_device_id vexpress_irq_match[] __initdata = {
+	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+	{}
+};
+
+static void __init v2m_dt_init_irq(void)
+{
+	of_irq_init(vexpress_irq_match);
+}
+
+static void __init v2m_dt_timer_init(void)
+{
+	struct device_node *node;
+	const char *path;
+	int err;
+
+	node = of_find_compatible_node(NULL, NULL, "arm,sp810");
+	v2m_sysctl_init(of_iomap(node, 0));
+
+	err = of_property_read_string(of_aliases, "arm,v2m_timer", &path);
+	if (WARN_ON(err))
+		return;
+	node = of_find_node_by_path(path);
+	v2m_sp804_init(of_iomap(node, 0), irq_of_parse_and_map(node, 0));
+}
+
+static struct sys_timer v2m_dt_timer = {
+	.init = v2m_dt_timer_init,
+};
+
+static struct of_dev_auxdata v2m_dt_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("arm,vexpress-flash", V2M_NOR0, "physmap-flash",
+			&v2m_flash_data),
+	OF_DEV_AUXDATA("arm,primecell", V2M_MMCI, "mb:mmci", &v2m_mmci_data),
+	/* RS1 memory map */
+	OF_DEV_AUXDATA("arm,vexpress-flash", 0x08000000, "physmap-flash",
+			&v2m_flash_data),
+	OF_DEV_AUXDATA("arm,primecell", 0x1c050000, "mb:mmci", &v2m_mmci_data),
+	{}
+};
+
+static void __init v2m_dt_init(void)
+{
+	l2x0_of_init(0x00400000, 0xfe0fffff);
+	of_platform_populate(NULL, of_default_bus_match_table,
+			v2m_dt_auxdata_lookup, NULL);
+	pm_power_off = v2m_power_off;
+}
+
+const static char *v2m_dt_match[] __initconst = {
+	"arm,vexpress",
+	NULL,
+};
+
+DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express")
+	.dt_compat	= v2m_dt_match,
+	.map_io		= v2m_dt_map_io,
+	.init_early	= v2m_dt_init_early,
+	.init_irq	= v2m_dt_init_irq,
+	.timer		= &v2m_dt_timer,
+	.init_machine	= v2m_dt_init,
+	.handle_irq	= gic_handle_irq,
+	.restart	= v2m_restart,
+MACHINE_END
+
+#endif
diff --git a/arch/arm/mach-vt8500/include/mach/entry-macro.S b/arch/arm/mach-vt8500/include/mach/entry-macro.S
index 92684c7..367d1b5 100644
--- a/arch/arm/mach-vt8500/include/mach/entry-macro.S
+++ b/arch/arm/mach-vt8500/include/mach/entry-macro.S
@@ -8,18 +8,12 @@
  * warranty of any kind, whether express or implied.
  */
 
-	.macro	disable_fiq
-	.endm
-
 	.macro  get_irqnr_preamble, base, tmp
 	@ physical 0xd8140000 is virtual 0xf8140000
 	mov	\base, #0xf8000000
 	orr	\base, \base, #0x00140000
 	.endm
 
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
-
 	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 	ldr	\irqnr, [\base]
 	cmp	\irqnr, #63 @ may be false positive, check interrupt status
diff --git a/arch/arm/mach-vt8500/include/mach/io.h b/arch/arm/mach-vt8500/include/mach/io.h
deleted file mode 100644
index 46181ee..0000000
--- a/arch/arm/mach-vt8500/include/mach/io.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  arch/arm/mach-vt8500/include/mach/io.h
- *
- *  Copyright (C) 2010 Alexey Charkov
- *
- * 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
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define __io(a)		__typesafe_io((a) + 0xf0000000)
-#define __mem_pci(a)	(a)
-
-#endif
diff --git a/arch/arm/mach-vt8500/include/mach/system.h b/arch/arm/mach-vt8500/include/mach/system.h
index d6c757e..58fa801 100644
--- a/arch/arm/mach-vt8500/include/mach/system.h
+++ b/arch/arm/mach-vt8500/include/mach/system.h
@@ -7,11 +7,6 @@
 /* PM Software Reset request register */
 #define VT8500_PMSR_VIRT	0xf8130060
 
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
 static inline void arch_reset(char mode, const char *cmd)
 {
 	writel(1, VT8500_PMSR_VIRT);
diff --git a/arch/arm/mach-w90x900/cpu.c b/arch/arm/mach-w90x900/cpu.c
index 9a06619..9e4dd8b 100644
--- a/arch/arm/mach-w90x900/cpu.c
+++ b/arch/arm/mach-w90x900/cpu.c
@@ -28,6 +28,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 #include <asm/irq.h>
+#include <asm/system_misc.h>
 
 #include <mach/hardware.h>
 #include <mach/regs-serial.h>
diff --git a/arch/arm/mach-w90x900/dev.c b/arch/arm/mach-w90x900/dev.c
index 78110be..48f5b9f 100644
--- a/arch/arm/mach-w90x900/dev.c
+++ b/arch/arm/mach-w90x900/dev.c
@@ -27,6 +27,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 
+#include <asm/system_misc.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
@@ -530,6 +531,7 @@
 
 void __init nuc900_board_init(struct platform_device **device, int size)
 {
+	disable_hlt();
 	platform_add_devices(device, size);
 	platform_add_devices(nuc900_public_dev, ARRAY_SIZE(nuc900_public_dev));
 	spi_register_board_info(nuc900_spi_board_info,
diff --git a/arch/arm/mach-w90x900/include/mach/entry-macro.S b/arch/arm/mach-w90x900/include/mach/entry-macro.S
index d39aca5..e286dac 100644
--- a/arch/arm/mach-w90x900/include/mach/entry-macro.S
+++ b/arch/arm/mach-w90x900/include/mach/entry-macro.S
@@ -15,9 +15,6 @@
 	.macro  get_irqnr_preamble, base, tmp
 	.endm
 
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
-
 	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 
 		mov	\base, #AIC_BA
@@ -27,8 +24,3 @@
 		cmp	\irqnr, #0
 
 	.endm
-
-	/* currently don't need an disable_fiq macro */
-
-	.macro	disable_fiq
-	.endm
diff --git a/arch/arm/mach-w90x900/include/mach/io.h b/arch/arm/mach-w90x900/include/mach/io.h
deleted file mode 100644
index d96ab99..0000000
--- a/arch/arm/mach-w90x900/include/mach/io.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * arch/arm/mach-w90x900/include/mach/io.h
- *
- * Copyright (c) 2008 Nuvoton technology corporation
- * All rights reserved.
- *
- * Wan ZongShun <mcuos.com@gmail.com>
- *
- * Based on arch/arm/mach-s3c2410/include/mach/io.h
- *
- * 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 __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT	0xffffffff
-
-/*
- * 1:1 mapping for ioremapped regions.
- */
-
-#define __mem_pci(a)	(a)
-#define __io(a)		__typesafe_io(a)
-
-#endif
diff --git a/arch/arm/mach-w90x900/include/mach/system.h b/arch/arm/mach-w90x900/include/mach/system.h
deleted file mode 100644
index 2aaeb93..0000000
--- a/arch/arm/mach-w90x900/include/mach/system.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-w90x900/include/mach/system.h
- *
- * Copyright (c) 2008 Nuvoton technology corporation
- * All rights reserved.
- *
- * Wan ZongShun <mcuos.com@gmail.com>
- *
- * Based on arch/arm/mach-s3c2410/include/mach/system.h
- *
- * 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.
- *
- */
-static void arch_idle(void)
-{
-}
diff --git a/arch/arm/mach-zynq/include/mach/entry-macro.S b/arch/arm/mach-zynq/include/mach/entry-macro.S
deleted file mode 100644
index d621fb7..0000000
--- a/arch/arm/mach-zynq/include/mach/entry-macro.S
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * arch/arm/mach-zynq/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros
- *
- *  Copyright (C) 2011 Xilinx
- *
- * based on arch/plat-mxc/include/mach/entry-macro.S
- *
- *  Copyright (C) 2007 Lennert Buytenhek <buytenh@wantstofly.org>
- *  Copyright 2004-2007 Freescale 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.
- */
-
-		.macro  disable_fiq
-		.endm
-
-		.macro  arch_ret_to_user, tmp1, tmp2
-		.endm
diff --git a/arch/arm/mach-zynq/include/mach/io.h b/arch/arm/mach-zynq/include/mach/io.h
deleted file mode 100644
index 39d9885..0000000
--- a/arch/arm/mach-zynq/include/mach/io.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* arch/arm/mach-zynq/include/mach/io.h
- *
- *  Copyright (C) 2011 Xilinx
- *
- * 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 __MACH_IO_H__
-#define __MACH_IO_H__
-
-/* Allow IO space to be anywhere in the memory */
-
-#define IO_SPACE_LIMIT 0xffff
-
-/* IO address mapping macros, nothing special at this time but required */
-
-#ifdef __ASSEMBLER__
-#define IOMEM(x)		(x)
-#else
-#define IOMEM(x)		((void __force __iomem *)(x))
-#endif
-
-#define __io(a)			__typesafe_io(a)
-#define __mem_pci(a)		(a)
-
-#endif
diff --git a/arch/arm/mach-zynq/include/mach/system.h b/arch/arm/mach-zynq/include/mach/system.h
deleted file mode 100644
index 8e88e0b..0000000
--- a/arch/arm/mach-zynq/include/mach/system.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* arch/arm/mach-zynq/include/mach/system.h
- *
- *  Copyright (C) 2011 Xilinx
- *
- * 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 __MACH_SYSTEM_H__
-#define __MACH_SYSTEM_H__
-
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index caf14dc..9107231 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -22,7 +22,8 @@
 #include <linux/sched.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
+#include <asm/cp15.h>
+#include <asm/system_info.h>
 #include <asm/unaligned.h>
 
 #include "fault.h"
diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c
index e0b0e7a..dd3d591 100644
--- a/arch/arm/mm/cache-feroceon-l2.c
+++ b/arch/arm/mm/cache-feroceon-l2.c
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/highmem.h>
 #include <asm/cacheflush.h>
+#include <asm/cp15.h>
 #include <plat/cache-feroceon-l2.h>
 
 /*
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index b1e192b..a53fd2a 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -30,13 +30,13 @@
 
 static void __iomem *l2x0_base;
 static DEFINE_RAW_SPINLOCK(l2x0_lock);
-static uint32_t l2x0_way_mask;	/* Bitmask of active ways */
-static uint32_t l2x0_size;
+static u32 l2x0_way_mask;	/* Bitmask of active ways */
+static u32 l2x0_size;
 
 struct l2x0_regs l2x0_saved_regs;
 
 struct l2x0_of_data {
-	void (*setup)(const struct device_node *, __u32 *, __u32 *);
+	void (*setup)(const struct device_node *, u32 *, u32 *);
 	void (*save)(void);
 	void (*resume)(void);
 };
@@ -288,7 +288,7 @@
 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
 }
 
-static void l2x0_unlock(__u32 cache_id)
+static void l2x0_unlock(u32 cache_id)
 {
 	int lockregs;
 	int i;
@@ -307,11 +307,11 @@
 	}
 }
 
-void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
+void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 {
-	__u32 aux;
-	__u32 cache_id;
-	__u32 way_size = 0;
+	u32 aux;
+	u32 cache_id;
+	u32 way_size = 0;
 	int ways;
 	const char *type;
 
@@ -388,7 +388,7 @@
 
 #ifdef CONFIG_OF
 static void __init l2x0_of_setup(const struct device_node *np,
-				 __u32 *aux_val, __u32 *aux_mask)
+				 u32 *aux_val, u32 *aux_mask)
 {
 	u32 data[2] = { 0, 0 };
 	u32 tag = 0;
@@ -422,7 +422,7 @@
 }
 
 static void __init pl310_of_setup(const struct device_node *np,
-				  __u32 *aux_val, __u32 *aux_mask)
+				  u32 *aux_val, u32 *aux_mask)
 {
 	u32 data[3] = { 0, 0, 0 };
 	u32 tag[3] = { 0, 0, 0 };
@@ -548,7 +548,7 @@
 	{}
 };
 
-int __init l2x0_of_init(__u32 aux_val, __u32 aux_mask)
+int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 {
 	struct device_node *np;
 	struct l2x0_of_data *data;
diff --git a/arch/arm/mm/cache-tauros2.c b/arch/arm/mm/cache-tauros2.c
index 5086865..1fbca05 100644
--- a/arch/arm/mm/cache-tauros2.c
+++ b/arch/arm/mm/cache-tauros2.c
@@ -16,6 +16,7 @@
 
 #include <linux/init.h>
 #include <asm/cacheflush.h>
+#include <asm/cp15.h>
 #include <asm/hardware/cache-tauros2.h>
 
 
diff --git a/arch/arm/mm/cache-xsc3l2.c b/arch/arm/mm/cache-xsc3l2.c
index 5a32020..6c3edeb 100644
--- a/arch/arm/mm/cache-xsc3l2.c
+++ b/arch/arm/mm/cache-xsc3l2.c
@@ -18,7 +18,7 @@
  */
 #include <linux/init.h>
 #include <linux/highmem.h>
-#include <asm/system.h>
+#include <asm/cp15.h>
 #include <asm/cputype.h>
 #include <asm/cacheflush.h>
 
diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c
index ec8c3be..1267e64 100644
--- a/arch/arm/mm/copypage-v4mc.c
+++ b/arch/arm/mm/copypage-v4mc.c
@@ -23,10 +23,6 @@
 
 #include "mm.h"
 
-/*
- * 0xffff8000 to 0xffffffff is reserved for any ARM architecture
- * specific hacks for copying pages efficiently.
- */
 #define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
 				  L_PTE_MT_MINICACHE)
 
@@ -78,10 +74,9 @@
 
 	raw_spin_lock(&minicache_lock);
 
-	set_pte_ext(TOP_PTE(0xffff8000), pfn_pte(page_to_pfn(from), minicache_pgprot), 0);
-	flush_tlb_kernel_page(0xffff8000);
+	set_top_pte(COPYPAGE_MINICACHE, mk_pte(from, minicache_pgprot));
 
-	mc_copy_user_page((void *)0xffff8000, kto);
+	mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto);
 
 	raw_spin_unlock(&minicache_lock);
 
diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c
index 8b03a58..b9bcc9d 100644
--- a/arch/arm/mm/copypage-v6.c
+++ b/arch/arm/mm/copypage-v6.c
@@ -24,9 +24,6 @@
 #error FIX ME
 #endif
 
-#define from_address	(0xffff8000)
-#define to_address	(0xffffc000)
-
 static DEFINE_RAW_SPINLOCK(v6_lock);
 
 /*
@@ -90,14 +87,11 @@
 	 */
 	raw_spin_lock(&v6_lock);
 
-	set_pte_ext(TOP_PTE(from_address) + offset, pfn_pte(page_to_pfn(from), PAGE_KERNEL), 0);
-	set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(page_to_pfn(to), PAGE_KERNEL), 0);
+	kfrom = COPYPAGE_V6_FROM + (offset << PAGE_SHIFT);
+	kto   = COPYPAGE_V6_TO + (offset << PAGE_SHIFT);
 
-	kfrom = from_address + (offset << PAGE_SHIFT);
-	kto   = to_address + (offset << PAGE_SHIFT);
-
-	flush_tlb_kernel_page(kfrom);
-	flush_tlb_kernel_page(kto);
+	set_top_pte(kfrom, mk_pte(from, PAGE_KERNEL));
+	set_top_pte(kto, mk_pte(to, PAGE_KERNEL));
 
 	copy_page((void *)kto, (void *)kfrom);
 
@@ -111,8 +105,7 @@
  */
 static void v6_clear_user_highpage_aliasing(struct page *page, unsigned long vaddr)
 {
-	unsigned int offset = CACHE_COLOUR(vaddr);
-	unsigned long to = to_address + (offset << PAGE_SHIFT);
+	unsigned long to = COPYPAGE_V6_TO + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
 
 	/* FIXME: not highmem safe */
 	discard_old_kernel_data(page_address(page));
@@ -123,8 +116,7 @@
 	 */
 	raw_spin_lock(&v6_lock);
 
-	set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(page_to_pfn(page), PAGE_KERNEL), 0);
-	flush_tlb_kernel_page(to);
+	set_top_pte(to, mk_pte(page, PAGE_KERNEL));
 	clear_page((void *)to);
 
 	raw_spin_unlock(&v6_lock);
diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c
index 439d106..0fb8502 100644
--- a/arch/arm/mm/copypage-xscale.c
+++ b/arch/arm/mm/copypage-xscale.c
@@ -23,12 +23,6 @@
 
 #include "mm.h"
 
-/*
- * 0xffff8000 to 0xffffffff is reserved for any ARM architecture
- * specific hacks for copying pages efficiently.
- */
-#define COPYPAGE_MINICACHE	0xffff8000
-
 #define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
 				  L_PTE_MT_MINICACHE)
 
@@ -100,8 +94,7 @@
 
 	raw_spin_lock(&minicache_lock);
 
-	set_pte_ext(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(page_to_pfn(from), minicache_pgprot), 0);
-	flush_tlb_kernel_page(COPYPAGE_MINICACHE);
+	set_top_pte(COPYPAGE_MINICACHE, mk_pte(from, minicache_pgprot));
 
 	mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto);
 
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 1aa664a..db23ae4 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -214,7 +214,8 @@
 core_initcall(consistent_init);
 
 static void *
-__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot)
+__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
+	const void *caller)
 {
 	struct arm_vmregion *c;
 	size_t align;
@@ -241,7 +242,7 @@
 	 * Allocate a virtual address in the consistent mapping region.
 	 */
 	c = arm_vmregion_alloc(&consistent_head, align, size,
-			    gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
+			    gfp & ~(__GFP_DMA | __GFP_HIGHMEM), caller);
 	if (c) {
 		pte_t *pte;
 		int idx = CONSISTENT_PTE_INDEX(c->vm_start);
@@ -320,14 +321,14 @@
 
 #else	/* !CONFIG_MMU */
 
-#define __dma_alloc_remap(page, size, gfp, prot)	page_address(page)
+#define __dma_alloc_remap(page, size, gfp, prot, c)	page_address(page)
 #define __dma_free_remap(addr, size)			do { } while (0)
 
 #endif	/* CONFIG_MMU */
 
 static void *
 __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
-	    pgprot_t prot)
+	    pgprot_t prot, const void *caller)
 {
 	struct page *page;
 	void *addr;
@@ -349,7 +350,7 @@
 		return NULL;
 
 	if (!arch_is_coherent())
-		addr = __dma_alloc_remap(page, size, gfp, prot);
+		addr = __dma_alloc_remap(page, size, gfp, prot, caller);
 	else
 		addr = page_address(page);
 
@@ -374,7 +375,8 @@
 		return memory;
 
 	return __dma_alloc(dev, size, handle, gfp,
-			   pgprot_dmacoherent(pgprot_kernel));
+			   pgprot_dmacoherent(pgprot_kernel),
+			   __builtin_return_address(0));
 }
 EXPORT_SYMBOL(dma_alloc_coherent);
 
@@ -386,7 +388,8 @@
 dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
 {
 	return __dma_alloc(dev, size, handle, gfp,
-			   pgprot_writecombine(pgprot_kernel));
+			   pgprot_writecombine(pgprot_kernel),
+			   __builtin_return_address(0));
 }
 EXPORT_SYMBOL(dma_alloc_writecombine);
 
@@ -723,6 +726,9 @@
 
 static int __init dma_debug_do_init(void)
 {
+#ifdef CONFIG_MMU
+	arm_vmregion_create_proc("dma-mappings", &consistent_head);
+#endif
 	dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
 	return 0;
 }
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index bb7eac3..9055b5a 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -21,8 +21,9 @@
 #include <linux/perf_event.h>
 
 #include <asm/exception.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
+#include <asm/system_misc.h>
+#include <asm/system_info.h>
 #include <asm/tlbflush.h>
 
 #include "fault.h"
@@ -164,7 +165,8 @@
 	struct siginfo si;
 
 #ifdef CONFIG_DEBUG_USER
-	if (user_debug & UDBG_SEGV) {
+	if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
+	    ((user_debug & UDBG_BUS)  && (sig == SIGBUS))) {
 		printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n",
 		       tsk->comm, sig, addr, fsr);
 		show_pte(tsk->mm, addr);
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 1a8d4aa..7745854 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -16,22 +16,18 @@
 #include <asm/cachetype.h>
 #include <asm/highmem.h>
 #include <asm/smp_plat.h>
-#include <asm/system.h>
 #include <asm/tlbflush.h>
 
 #include "mm.h"
 
 #ifdef CONFIG_CPU_CACHE_VIPT
 
-#define ALIAS_FLUSH_START	0xffff4000
-
 static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
 {
-	unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
+	unsigned long to = FLUSH_ALIAS_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
 	const int zero = 0;
 
-	set_pte_ext(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL), 0);
-	flush_tlb_kernel_page(to);
+	set_top_pte(to, pfn_pte(pfn, PAGE_KERNEL));
 
 	asm(	"mcrr	p15, 0, %1, %0, c14\n"
 	"	mcr	p15, 0, %2, c7, c10, 4"
@@ -42,13 +38,12 @@
 
 static void flush_icache_alias(unsigned long pfn, unsigned long vaddr, unsigned long len)
 {
-	unsigned long colour = CACHE_COLOUR(vaddr);
+	unsigned long va = FLUSH_ALIAS_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
 	unsigned long offset = vaddr & (PAGE_SIZE - 1);
 	unsigned long to;
 
-	set_pte_ext(TOP_PTE(ALIAS_FLUSH_START) + colour, pfn_pte(pfn, PAGE_KERNEL), 0);
-	to = ALIAS_FLUSH_START + (colour << PAGE_SHIFT) + offset;
-	flush_tlb_kernel_page(to);
+	set_top_pte(va, pfn_pte(pfn, PAGE_KERNEL));
+	to = va + offset;
 	flush_icache_range(to, to + len);
 }
 
diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c
index 5a21505..21b9e1b 100644
--- a/arch/arm/mm/highmem.c
+++ b/arch/arm/mm/highmem.c
@@ -69,15 +69,14 @@
 	 * With debugging enabled, kunmap_atomic forces that entry to 0.
 	 * Make sure it was indeed properly unmapped.
 	 */
-	BUG_ON(!pte_none(*(TOP_PTE(vaddr))));
+	BUG_ON(!pte_none(get_top_pte(vaddr)));
 #endif
-	set_pte_ext(TOP_PTE(vaddr), mk_pte(page, kmap_prot), 0);
 	/*
 	 * When debugging is off, kunmap_atomic leaves the previous mapping
-	 * in place, so this TLB flush ensures the TLB is updated with the
-	 * new mapping.
+	 * in place, so the contained TLB flush ensures the TLB is updated
+	 * with the new mapping.
 	 */
-	local_flush_tlb_kernel_page(vaddr);
+	set_top_pte(vaddr, mk_pte(page, kmap_prot));
 
 	return (void *)vaddr;
 }
@@ -96,8 +95,7 @@
 			__cpuc_flush_dcache_area((void *)vaddr, PAGE_SIZE);
 #ifdef CONFIG_DEBUG_HIGHMEM
 		BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
-		set_pte_ext(TOP_PTE(vaddr), __pte(0), 0);
-		local_flush_tlb_kernel_page(vaddr);
+		set_top_pte(vaddr, __pte(0));
 #else
 		(void) idx;  /* to kill a warning */
 #endif
@@ -121,10 +119,9 @@
 	idx = type + KM_TYPE_NR * smp_processor_id();
 	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
-	BUG_ON(!pte_none(*(TOP_PTE(vaddr))));
+	BUG_ON(!pte_none(get_top_pte(vaddr)));
 #endif
-	set_pte_ext(TOP_PTE(vaddr), pfn_pte(pfn, kmap_prot), 0);
-	local_flush_tlb_kernel_page(vaddr);
+	set_top_pte(vaddr, pfn_pte(pfn, kmap_prot));
 
 	return (void *)vaddr;
 }
@@ -132,11 +129,9 @@
 struct page *kmap_atomic_to_page(const void *ptr)
 {
 	unsigned long vaddr = (unsigned long)ptr;
-	pte_t *pte;
 
 	if (vaddr < FIXADDR_START)
 		return virt_to_page(ptr);
 
-	pte = TOP_PTE(vaddr);
-	return pte_page(*pte);
+	return pte_page(get_top_pte(vaddr));
 }
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
index feacf4c..ab88ed4 100644
--- a/arch/arm/mm/idmap.c
+++ b/arch/arm/mm/idmap.c
@@ -5,6 +5,7 @@
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/sections.h>
+#include <asm/system_info.h>
 
 pgd_t *idmap_pgd;
 
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 245a55a..595079f 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -658,7 +658,9 @@
 #ifdef CONFIG_HIGHMEM
 			"    pkmap   : 0x%08lx - 0x%08lx   (%4ld MB)\n"
 #endif
+#ifdef CONFIG_MODULES
 			"    modules : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+#endif
 			"      .text : 0x%p" " - 0x%p" "   (%4d kB)\n"
 			"      .init : 0x%p" " - 0x%p" "   (%4d kB)\n"
 			"      .data : 0x%p" " - 0x%p" "   (%4d kB)\n"
@@ -677,7 +679,9 @@
 			MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) *
 				(PAGE_SIZE)),
 #endif
+#ifdef CONFIG_MODULES
 			MLM(MODULES_VADDR, MODULES_END),
+#endif
 
 			MLK_ROUNDUP(_text, _etext),
 			MLK_ROUNDUP(__init_begin, __init_end),
diff --git a/arch/arm/mm/iomap.c b/arch/arm/mm/iomap.c
index e62956e..4614208 100644
--- a/arch/arm/mm/iomap.c
+++ b/arch/arm/mm/iomap.c
@@ -32,9 +32,6 @@
 unsigned long pcibios_min_mem = 0x01000000;
 EXPORT_SYMBOL(pcibios_min_mem);
 
-unsigned int pci_flags = PCI_REASSIGN_ALL_RSRC;
-EXPORT_SYMBOL(pci_flags);
-
 void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
 {
 	if ((unsigned long)addr >= VMALLOC_START &&
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 80632e8..4f55f50 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -26,12 +26,14 @@
 #include <linux/vmalloc.h>
 #include <linux/io.h>
 
+#include <asm/cp15.h>
 #include <asm/cputype.h>
 #include <asm/cacheflush.h>
 #include <asm/mmu_context.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/sizes.h>
+#include <asm/system_info.h>
 
 #include <asm/mach/map.h>
 #include "mm.h"
@@ -306,11 +308,15 @@
 }
 EXPORT_SYMBOL(__arm_ioremap_pfn);
 
+void __iomem * (*arch_ioremap_caller)(unsigned long, size_t,
+				      unsigned int, void *) =
+	__arm_ioremap_caller;
+
 void __iomem *
 __arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
 {
-	return __arm_ioremap_caller(phys_addr, size, mtype,
-			__builtin_return_address(0));
+	return arch_ioremap_caller(phys_addr, size, mtype,
+		__builtin_return_address(0));
 }
 EXPORT_SYMBOL(__arm_ioremap);
 
@@ -369,4 +375,11 @@
 
 	vunmap(addr);
 }
-EXPORT_SYMBOL(__iounmap);
+
+void (*arch_iounmap)(volatile void __iomem *) = __iounmap;
+
+void __arm_iounmap(volatile void __iomem *io_addr)
+{
+	arch_iounmap(io_addr);
+}
+EXPORT_SYMBOL(__arm_iounmap);
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index 70f6d3ea..27f4a61 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -3,7 +3,31 @@
 /* the upper-most page table pointer */
 extern pmd_t *top_pmd;
 
-#define TOP_PTE(x)	pte_offset_kernel(top_pmd, x)
+/*
+ * 0xffff8000 to 0xffffffff is reserved for any ARM architecture
+ * specific hacks for copying pages efficiently, while 0xffff4000
+ * is reserved for VIPT aliasing flushing by generic code.
+ *
+ * Note that we don't allow VIPT aliasing caches with SMP.
+ */
+#define COPYPAGE_MINICACHE	0xffff8000
+#define COPYPAGE_V6_FROM	0xffff8000
+#define COPYPAGE_V6_TO		0xffffc000
+/* PFN alias flushing, for VIPT caches */
+#define FLUSH_ALIAS_START	0xffff4000
+
+static inline void set_top_pte(unsigned long va, pte_t pte)
+{
+	pte_t *ptep = pte_offset_kernel(top_pmd, va);
+	set_pte_ext(ptep, pte, 0);
+	local_flush_tlb_kernel_page(va);
+}
+
+static inline pte_t get_top_pte(unsigned long va)
+{
+	pte_t *ptep = pte_offset_kernel(top_pmd, va);
+	return *ptep;
+}
 
 static inline pmd_t *pmd_off_k(unsigned long virt)
 {
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 94c5a0c..b86f893 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -17,6 +17,7 @@
 #include <linux/fs.h>
 #include <linux/vmalloc.h>
 
+#include <asm/cp15.h>
 #include <asm/cputype.h>
 #include <asm/sections.h>
 #include <asm/cachetype.h>
@@ -25,6 +26,7 @@
 #include <asm/smp_plat.h>
 #include <asm/tlb.h>
 #include <asm/highmem.h>
+#include <asm/system_info.h>
 #include <asm/traps.h>
 
 #include <asm/mach/arch.h>
@@ -997,11 +999,14 @@
 {
 	struct map_desc map;
 	unsigned long addr;
+	void *vectors;
 
 	/*
 	 * Allocate the vector page early.
 	 */
-	vectors_page = early_alloc(PAGE_SIZE);
+	vectors = early_alloc(PAGE_SIZE);
+
+	early_trap_init(vectors);
 
 	for (addr = VMALLOC_START; addr; addr += PMD_SIZE)
 		pmd_clear(pmd_off_k(addr));
@@ -1041,7 +1046,7 @@
 	 * location (0xffff0000).  If we aren't using high-vectors, also
 	 * create a mapping at the low-vectors virtual address.
 	 */
-	map.pfn = __phys_to_pfn(virt_to_phys(vectors_page));
+	map.pfn = __phys_to_pfn(virt_to_phys(vectors));
 	map.virtual = 0xffff0000;
 	map.length = PAGE_SIZE;
 	map.type = MT_HIGH_VECTORS;
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index 4fc6794..6486d2f 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -86,13 +86,17 @@
 }
 EXPORT_SYMBOL(__arm_ioremap);
 
+void __iomem * (*arch_ioremap_caller)(unsigned long, size_t, unsigned int, void *);
+
 void __iomem *__arm_ioremap_caller(unsigned long phys_addr, size_t size,
 				   unsigned int mtype, void *caller)
 {
 	return __arm_ioremap(phys_addr, size, mtype);
 }
 
-void __iounmap(volatile void __iomem *addr)
+void (*arch_iounmap)(volatile void __iomem *);
+
+void __arm_iounmap(volatile void __iomem *addr)
 {
 }
-EXPORT_SYMBOL(__iounmap);
+EXPORT_SYMBOL(__arm_iounmap);
diff --git a/arch/arm/mm/pgd.c b/arch/arm/mm/pgd.c
index a3e78cc..0acb089 100644
--- a/arch/arm/mm/pgd.c
+++ b/arch/arm/mm/pgd.c
@@ -12,6 +12,7 @@
 #include <linux/highmem.h>
 #include <linux/slab.h>
 
+#include <asm/cp15.h>
 #include <asm/pgalloc.h>
 #include <asm/page.h>
 #include <asm/tlbflush.h>
diff --git a/arch/arm/mm/proc-fa526.S b/arch/arm/mm/proc-fa526.S
index 272558a..d217e97 100644
--- a/arch/arm/mm/proc-fa526.S
+++ b/arch/arm/mm/proc-fa526.S
@@ -22,7 +22,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 
 #include "proc-macros.S"
 
diff --git a/arch/arm/mm/vmregion.c b/arch/arm/mm/vmregion.c
index 036fdbf..a631016 100644
--- a/arch/arm/mm/vmregion.c
+++ b/arch/arm/mm/vmregion.c
@@ -1,5 +1,8 @@
+#include <linux/fs.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 
 #include "vmregion.h"
@@ -36,7 +39,7 @@
 
 struct arm_vmregion *
 arm_vmregion_alloc(struct arm_vmregion_head *head, size_t align,
-		   size_t size, gfp_t gfp)
+		   size_t size, gfp_t gfp, const void *caller)
 {
 	unsigned long start = head->vm_start, addr = head->vm_end;
 	unsigned long flags;
@@ -52,6 +55,8 @@
 	if (!new)
 		goto out;
 
+	new->caller = caller;
+
 	spin_lock_irqsave(&head->vm_lock, flags);
 
 	addr = rounddown(addr - size, align);
@@ -129,3 +134,72 @@
 
 	kfree(c);
 }
+
+#ifdef CONFIG_PROC_FS
+static int arm_vmregion_show(struct seq_file *m, void *p)
+{
+	struct arm_vmregion *c = list_entry(p, struct arm_vmregion, vm_list);
+
+	seq_printf(m, "0x%08lx-0x%08lx %7lu", c->vm_start, c->vm_end,
+		c->vm_end - c->vm_start);
+	if (c->caller)
+		seq_printf(m, " %pS", (void *)c->caller);
+	seq_putc(m, '\n');
+	return 0;
+}
+
+static void *arm_vmregion_start(struct seq_file *m, loff_t *pos)
+{
+	struct arm_vmregion_head *h = m->private;
+	spin_lock_irq(&h->vm_lock);
+	return seq_list_start(&h->vm_list, *pos);
+}
+
+static void *arm_vmregion_next(struct seq_file *m, void *p, loff_t *pos)
+{
+	struct arm_vmregion_head *h = m->private;
+	return seq_list_next(p, &h->vm_list, pos);
+}
+
+static void arm_vmregion_stop(struct seq_file *m, void *p)
+{
+	struct arm_vmregion_head *h = m->private;
+	spin_unlock_irq(&h->vm_lock);
+}
+
+static const struct seq_operations arm_vmregion_ops = {
+	.start	= arm_vmregion_start,
+	.stop	= arm_vmregion_stop,
+	.next	= arm_vmregion_next,
+	.show	= arm_vmregion_show,
+};
+
+static int arm_vmregion_open(struct inode *inode, struct file *file)
+{
+	struct arm_vmregion_head *h = PDE(inode)->data;
+	int ret = seq_open(file, &arm_vmregion_ops);
+	if (!ret) {
+		struct seq_file *m = file->private_data;
+		m->private = h;
+	}
+	return ret;
+}
+
+static const struct file_operations arm_vmregion_fops = {
+	.open	= arm_vmregion_open,
+	.read	= seq_read,
+	.llseek	= seq_lseek,
+	.release = seq_release,
+};
+
+int arm_vmregion_create_proc(const char *path, struct arm_vmregion_head *h)
+{
+	proc_create_data(path, S_IRUSR, NULL, &arm_vmregion_fops, h);
+	return 0;
+}
+#else
+int arm_vmregion_create_proc(const char *path, struct arm_vmregion_head *h)
+{
+	return 0;
+}
+#endif
diff --git a/arch/arm/mm/vmregion.h b/arch/arm/mm/vmregion.h
index 15e9f04..162be66 100644
--- a/arch/arm/mm/vmregion.h
+++ b/arch/arm/mm/vmregion.h
@@ -19,11 +19,14 @@
 	unsigned long		vm_end;
 	struct page		*vm_pages;
 	int			vm_active;
+	const void		*caller;
 };
 
-struct arm_vmregion *arm_vmregion_alloc(struct arm_vmregion_head *, size_t, size_t, gfp_t);
+struct arm_vmregion *arm_vmregion_alloc(struct arm_vmregion_head *, size_t, size_t, gfp_t, const void *);
 struct arm_vmregion *arm_vmregion_find(struct arm_vmregion_head *, unsigned long);
 struct arm_vmregion *arm_vmregion_find_remove(struct arm_vmregion_head *, unsigned long);
 void arm_vmregion_free(struct arm_vmregion_head *, struct arm_vmregion *);
 
+int arm_vmregion_create_proc(const char *, struct arm_vmregion_head *);
+
 #endif
diff --git a/arch/arm/net/Makefile b/arch/arm/net/Makefile
new file mode 100644
index 0000000..c2c1084
--- /dev/null
+++ b/arch/arm/net/Makefile
@@ -0,0 +1,3 @@
+# ARM-specific networking code
+
+obj-$(CONFIG_BPF_JIT) += bpf_jit_32.o
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
new file mode 100644
index 0000000..62135849
--- /dev/null
+++ b/arch/arm/net/bpf_jit_32.c
@@ -0,0 +1,915 @@
+/*
+ * Just-In-Time compiler for BPF filters on 32bit ARM
+ *
+ * Copyright (c) 2011 Mircea Gherzan <mgherzan@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; version 2 of the License.
+ */
+
+#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/filter.h>
+#include <linux/moduleloader.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/cacheflush.h>
+#include <asm/hwcap.h>
+
+#include "bpf_jit_32.h"
+
+/*
+ * ABI:
+ *
+ * r0	scratch register
+ * r4	BPF register A
+ * r5	BPF register X
+ * r6	pointer to the skb
+ * r7	skb->data
+ * r8	skb_headlen(skb)
+ */
+
+#define r_scratch	ARM_R0
+/* r1-r3 are (also) used for the unaligned loads on the non-ARMv7 slowpath */
+#define r_off		ARM_R1
+#define r_A		ARM_R4
+#define r_X		ARM_R5
+#define r_skb		ARM_R6
+#define r_skb_data	ARM_R7
+#define r_skb_hl	ARM_R8
+
+#define SCRATCH_SP_OFFSET	0
+#define SCRATCH_OFF(k)		(SCRATCH_SP_OFFSET + (k))
+
+#define SEEN_MEM		((1 << BPF_MEMWORDS) - 1)
+#define SEEN_MEM_WORD(k)	(1 << (k))
+#define SEEN_X			(1 << BPF_MEMWORDS)
+#define SEEN_CALL		(1 << (BPF_MEMWORDS + 1))
+#define SEEN_SKB		(1 << (BPF_MEMWORDS + 2))
+#define SEEN_DATA		(1 << (BPF_MEMWORDS + 3))
+
+#define FLAG_NEED_X_RESET	(1 << 0)
+
+struct jit_ctx {
+	const struct sk_filter *skf;
+	unsigned idx;
+	unsigned prologue_bytes;
+	int ret0_fp_idx;
+	u32 seen;
+	u32 flags;
+	u32 *offsets;
+	u32 *target;
+#if __LINUX_ARM_ARCH__ < 7
+	u16 epilogue_bytes;
+	u16 imm_count;
+	u32 *imms;
+#endif
+};
+
+int bpf_jit_enable __read_mostly;
+
+static u64 jit_get_skb_b(struct sk_buff *skb, unsigned offset)
+{
+	u8 ret;
+	int err;
+
+	err = skb_copy_bits(skb, offset, &ret, 1);
+
+	return (u64)err << 32 | ret;
+}
+
+static u64 jit_get_skb_h(struct sk_buff *skb, unsigned offset)
+{
+	u16 ret;
+	int err;
+
+	err = skb_copy_bits(skb, offset, &ret, 2);
+
+	return (u64)err << 32 | ntohs(ret);
+}
+
+static u64 jit_get_skb_w(struct sk_buff *skb, unsigned offset)
+{
+	u32 ret;
+	int err;
+
+	err = skb_copy_bits(skb, offset, &ret, 4);
+
+	return (u64)err << 32 | ntohl(ret);
+}
+
+/*
+ * Wrapper that handles both OABI and EABI and assures Thumb2 interworking
+ * (where the assembly routines like __aeabi_uidiv could cause problems).
+ */
+static u32 jit_udiv(u32 dividend, u32 divisor)
+{
+	return dividend / divisor;
+}
+
+static inline void _emit(int cond, u32 inst, struct jit_ctx *ctx)
+{
+	if (ctx->target != NULL)
+		ctx->target[ctx->idx] = inst | (cond << 28);
+
+	ctx->idx++;
+}
+
+/*
+ * Emit an instruction that will be executed unconditionally.
+ */
+static inline void emit(u32 inst, struct jit_ctx *ctx)
+{
+	_emit(ARM_COND_AL, inst, ctx);
+}
+
+static u16 saved_regs(struct jit_ctx *ctx)
+{
+	u16 ret = 0;
+
+	if ((ctx->skf->len > 1) ||
+	    (ctx->skf->insns[0].code == BPF_S_RET_A))
+		ret |= 1 << r_A;
+
+#ifdef CONFIG_FRAME_POINTER
+	ret |= (1 << ARM_FP) | (1 << ARM_IP) | (1 << ARM_LR) | (1 << ARM_PC);
+#else
+	if (ctx->seen & SEEN_CALL)
+		ret |= 1 << ARM_LR;
+#endif
+	if (ctx->seen & (SEEN_DATA | SEEN_SKB))
+		ret |= 1 << r_skb;
+	if (ctx->seen & SEEN_DATA)
+		ret |= (1 << r_skb_data) | (1 << r_skb_hl);
+	if (ctx->seen & SEEN_X)
+		ret |= 1 << r_X;
+
+	return ret;
+}
+
+static inline int mem_words_used(struct jit_ctx *ctx)
+{
+	/* yes, we do waste some stack space IF there are "holes" in the set" */
+	return fls(ctx->seen & SEEN_MEM);
+}
+
+static inline bool is_load_to_a(u16 inst)
+{
+	switch (inst) {
+	case BPF_S_LD_W_LEN:
+	case BPF_S_LD_W_ABS:
+	case BPF_S_LD_H_ABS:
+	case BPF_S_LD_B_ABS:
+	case BPF_S_ANC_CPU:
+	case BPF_S_ANC_IFINDEX:
+	case BPF_S_ANC_MARK:
+	case BPF_S_ANC_PROTOCOL:
+	case BPF_S_ANC_RXHASH:
+	case BPF_S_ANC_QUEUE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void build_prologue(struct jit_ctx *ctx)
+{
+	u16 reg_set = saved_regs(ctx);
+	u16 first_inst = ctx->skf->insns[0].code;
+	u16 off;
+
+#ifdef CONFIG_FRAME_POINTER
+	emit(ARM_MOV_R(ARM_IP, ARM_SP), ctx);
+	emit(ARM_PUSH(reg_set), ctx);
+	emit(ARM_SUB_I(ARM_FP, ARM_IP, 4), ctx);
+#else
+	if (reg_set)
+		emit(ARM_PUSH(reg_set), ctx);
+#endif
+
+	if (ctx->seen & (SEEN_DATA | SEEN_SKB))
+		emit(ARM_MOV_R(r_skb, ARM_R0), ctx);
+
+	if (ctx->seen & SEEN_DATA) {
+		off = offsetof(struct sk_buff, data);
+		emit(ARM_LDR_I(r_skb_data, r_skb, off), ctx);
+		/* headlen = len - data_len */
+		off = offsetof(struct sk_buff, len);
+		emit(ARM_LDR_I(r_skb_hl, r_skb, off), ctx);
+		off = offsetof(struct sk_buff, data_len);
+		emit(ARM_LDR_I(r_scratch, r_skb, off), ctx);
+		emit(ARM_SUB_R(r_skb_hl, r_skb_hl, r_scratch), ctx);
+	}
+
+	if (ctx->flags & FLAG_NEED_X_RESET)
+		emit(ARM_MOV_I(r_X, 0), ctx);
+
+	/* do not leak kernel data to userspace */
+	if ((first_inst != BPF_S_RET_K) && !(is_load_to_a(first_inst)))
+		emit(ARM_MOV_I(r_A, 0), ctx);
+
+	/* stack space for the BPF_MEM words */
+	if (ctx->seen & SEEN_MEM)
+		emit(ARM_SUB_I(ARM_SP, ARM_SP, mem_words_used(ctx) * 4), ctx);
+}
+
+static void build_epilogue(struct jit_ctx *ctx)
+{
+	u16 reg_set = saved_regs(ctx);
+
+	if (ctx->seen & SEEN_MEM)
+		emit(ARM_ADD_I(ARM_SP, ARM_SP, mem_words_used(ctx) * 4), ctx);
+
+	reg_set &= ~(1 << ARM_LR);
+
+#ifdef CONFIG_FRAME_POINTER
+	/* the first instruction of the prologue was: mov ip, sp */
+	reg_set &= ~(1 << ARM_IP);
+	reg_set |= (1 << ARM_SP);
+	emit(ARM_LDM(ARM_SP, reg_set), ctx);
+#else
+	if (reg_set) {
+		if (ctx->seen & SEEN_CALL)
+			reg_set |= 1 << ARM_PC;
+		emit(ARM_POP(reg_set), ctx);
+	}
+
+	if (!(ctx->seen & SEEN_CALL))
+		emit(ARM_BX(ARM_LR), ctx);
+#endif
+}
+
+static int16_t imm8m(u32 x)
+{
+	u32 rot;
+
+	for (rot = 0; rot < 16; rot++)
+		if ((x & ~ror32(0xff, 2 * rot)) == 0)
+			return rol32(x, 2 * rot) | (rot << 8);
+
+	return -1;
+}
+
+#if __LINUX_ARM_ARCH__ < 7
+
+static u16 imm_offset(u32 k, struct jit_ctx *ctx)
+{
+	unsigned i = 0, offset;
+	u16 imm;
+
+	/* on the "fake" run we just count them (duplicates included) */
+	if (ctx->target == NULL) {
+		ctx->imm_count++;
+		return 0;
+	}
+
+	while ((i < ctx->imm_count) && ctx->imms[i]) {
+		if (ctx->imms[i] == k)
+			break;
+		i++;
+	}
+
+	if (ctx->imms[i] == 0)
+		ctx->imms[i] = k;
+
+	/* constants go just after the epilogue */
+	offset =  ctx->offsets[ctx->skf->len];
+	offset += ctx->prologue_bytes;
+	offset += ctx->epilogue_bytes;
+	offset += i * 4;
+
+	ctx->target[offset / 4] = k;
+
+	/* PC in ARM mode == address of the instruction + 8 */
+	imm = offset - (8 + ctx->idx * 4);
+
+	return imm;
+}
+
+#endif /* __LINUX_ARM_ARCH__ */
+
+/*
+ * Move an immediate that's not an imm8m to a core register.
+ */
+static inline void emit_mov_i_no8m(int rd, u32 val, struct jit_ctx *ctx)
+{
+#if __LINUX_ARM_ARCH__ < 7
+	emit(ARM_LDR_I(rd, ARM_PC, imm_offset(val, ctx)), ctx);
+#else
+	emit(ARM_MOVW(rd, val & 0xffff), ctx);
+	if (val > 0xffff)
+		emit(ARM_MOVT(rd, val >> 16), ctx);
+#endif
+}
+
+static inline void emit_mov_i(int rd, u32 val, struct jit_ctx *ctx)
+{
+	int imm12 = imm8m(val);
+
+	if (imm12 >= 0)
+		emit(ARM_MOV_I(rd, imm12), ctx);
+	else
+		emit_mov_i_no8m(rd, val, ctx);
+}
+
+#if __LINUX_ARM_ARCH__ < 6
+
+static void emit_load_be32(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
+{
+	_emit(cond, ARM_LDRB_I(ARM_R3, r_addr, 1), ctx);
+	_emit(cond, ARM_LDRB_I(ARM_R1, r_addr, 0), ctx);
+	_emit(cond, ARM_LDRB_I(ARM_R2, r_addr, 3), ctx);
+	_emit(cond, ARM_LSL_I(ARM_R3, ARM_R3, 16), ctx);
+	_emit(cond, ARM_LDRB_I(ARM_R0, r_addr, 2), ctx);
+	_emit(cond, ARM_ORR_S(ARM_R3, ARM_R3, ARM_R1, SRTYPE_LSL, 24), ctx);
+	_emit(cond, ARM_ORR_R(ARM_R3, ARM_R3, ARM_R2), ctx);
+	_emit(cond, ARM_ORR_S(r_res, ARM_R3, ARM_R0, SRTYPE_LSL, 8), ctx);
+}
+
+static void emit_load_be16(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
+{
+	_emit(cond, ARM_LDRB_I(ARM_R1, r_addr, 0), ctx);
+	_emit(cond, ARM_LDRB_I(ARM_R2, r_addr, 1), ctx);
+	_emit(cond, ARM_ORR_S(r_res, ARM_R2, ARM_R1, SRTYPE_LSL, 8), ctx);
+}
+
+static inline void emit_swap16(u8 r_dst, u8 r_src, struct jit_ctx *ctx)
+{
+	emit(ARM_LSL_R(ARM_R1, r_src, 8), ctx);
+	emit(ARM_ORR_S(r_dst, ARM_R1, r_src, SRTYPE_LSL, 8), ctx);
+	emit(ARM_LSL_I(r_dst, r_dst, 8), ctx);
+	emit(ARM_LSL_R(r_dst, r_dst, 8), ctx);
+}
+
+#else  /* ARMv6+ */
+
+static void emit_load_be32(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
+{
+	_emit(cond, ARM_LDR_I(r_res, r_addr, 0), ctx);
+#ifdef __LITTLE_ENDIAN
+	_emit(cond, ARM_REV(r_res, r_res), ctx);
+#endif
+}
+
+static void emit_load_be16(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
+{
+	_emit(cond, ARM_LDRH_I(r_res, r_addr, 0), ctx);
+#ifdef __LITTLE_ENDIAN
+	_emit(cond, ARM_REV16(r_res, r_res), ctx);
+#endif
+}
+
+static inline void emit_swap16(u8 r_dst __maybe_unused,
+			       u8 r_src __maybe_unused,
+			       struct jit_ctx *ctx __maybe_unused)
+{
+#ifdef __LITTLE_ENDIAN
+	emit(ARM_REV16(r_dst, r_src), ctx);
+#endif
+}
+
+#endif /* __LINUX_ARM_ARCH__ < 6 */
+
+
+/* Compute the immediate value for a PC-relative branch. */
+static inline u32 b_imm(unsigned tgt, struct jit_ctx *ctx)
+{
+	u32 imm;
+
+	if (ctx->target == NULL)
+		return 0;
+	/*
+	 * BPF allows only forward jumps and the offset of the target is
+	 * still the one computed during the first pass.
+	 */
+	imm  = ctx->offsets[tgt] + ctx->prologue_bytes - (ctx->idx * 4 + 8);
+
+	return imm >> 2;
+}
+
+#define OP_IMM3(op, r1, r2, imm_val, ctx)				\
+	do {								\
+		imm12 = imm8m(imm_val);					\
+		if (imm12 < 0) {					\
+			emit_mov_i_no8m(r_scratch, imm_val, ctx);	\
+			emit(op ## _R((r1), (r2), r_scratch), ctx);	\
+		} else {						\
+			emit(op ## _I((r1), (r2), imm12), ctx);		\
+		}							\
+	} while (0)
+
+static inline void emit_err_ret(u8 cond, struct jit_ctx *ctx)
+{
+	if (ctx->ret0_fp_idx >= 0) {
+		_emit(cond, ARM_B(b_imm(ctx->ret0_fp_idx, ctx)), ctx);
+		/* NOP to keep the size constant between passes */
+		emit(ARM_MOV_R(ARM_R0, ARM_R0), ctx);
+	} else {
+		_emit(cond, ARM_MOV_I(ARM_R0, 0), ctx);
+		_emit(cond, ARM_B(b_imm(ctx->skf->len, ctx)), ctx);
+	}
+}
+
+static inline void emit_blx_r(u8 tgt_reg, struct jit_ctx *ctx)
+{
+#if __LINUX_ARM_ARCH__ < 5
+	emit(ARM_MOV_R(ARM_LR, ARM_PC), ctx);
+
+	if (elf_hwcap & HWCAP_THUMB)
+		emit(ARM_BX(tgt_reg), ctx);
+	else
+		emit(ARM_MOV_R(ARM_PC, tgt_reg), ctx);
+#else
+	emit(ARM_BLX_R(tgt_reg), ctx);
+#endif
+}
+
+static inline void emit_udiv(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx)
+{
+#if __LINUX_ARM_ARCH__ == 7
+	if (elf_hwcap & HWCAP_IDIVA) {
+		emit(ARM_UDIV(rd, rm, rn), ctx);
+		return;
+	}
+#endif
+	if (rm != ARM_R0)
+		emit(ARM_MOV_R(ARM_R0, rm), ctx);
+	if (rn != ARM_R1)
+		emit(ARM_MOV_R(ARM_R1, rn), ctx);
+
+	ctx->seen |= SEEN_CALL;
+	emit_mov_i(ARM_R3, (u32)jit_udiv, ctx);
+	emit_blx_r(ARM_R3, ctx);
+
+	if (rd != ARM_R0)
+		emit(ARM_MOV_R(rd, ARM_R0), ctx);
+}
+
+static inline void update_on_xread(struct jit_ctx *ctx)
+{
+	if (!(ctx->seen & SEEN_X))
+		ctx->flags |= FLAG_NEED_X_RESET;
+
+	ctx->seen |= SEEN_X;
+}
+
+static int build_body(struct jit_ctx *ctx)
+{
+	void *load_func[] = {jit_get_skb_b, jit_get_skb_h, jit_get_skb_w};
+	const struct sk_filter *prog = ctx->skf;
+	const struct sock_filter *inst;
+	unsigned i, load_order, off, condt;
+	int imm12;
+	u32 k;
+
+	for (i = 0; i < prog->len; i++) {
+		inst = &(prog->insns[i]);
+		/* K as an immediate value operand */
+		k = inst->k;
+
+		/* compute offsets only in the fake pass */
+		if (ctx->target == NULL)
+			ctx->offsets[i] = ctx->idx * 4;
+
+		switch (inst->code) {
+		case BPF_S_LD_IMM:
+			emit_mov_i(r_A, k, ctx);
+			break;
+		case BPF_S_LD_W_LEN:
+			ctx->seen |= SEEN_SKB;
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
+			emit(ARM_LDR_I(r_A, r_skb,
+				       offsetof(struct sk_buff, len)), ctx);
+			break;
+		case BPF_S_LD_MEM:
+			/* A = scratch[k] */
+			ctx->seen |= SEEN_MEM_WORD(k);
+			emit(ARM_LDR_I(r_A, ARM_SP, SCRATCH_OFF(k)), ctx);
+			break;
+		case BPF_S_LD_W_ABS:
+			load_order = 2;
+			goto load;
+		case BPF_S_LD_H_ABS:
+			load_order = 1;
+			goto load;
+		case BPF_S_LD_B_ABS:
+			load_order = 0;
+load:
+			/* the interpreter will deal with the negative K */
+			if ((int)k < 0)
+				return -ENOTSUPP;
+			emit_mov_i(r_off, k, ctx);
+load_common:
+			ctx->seen |= SEEN_DATA | SEEN_CALL;
+
+			if (load_order > 0) {
+				emit(ARM_SUB_I(r_scratch, r_skb_hl,
+					       1 << load_order), ctx);
+				emit(ARM_CMP_R(r_scratch, r_off), ctx);
+				condt = ARM_COND_HS;
+			} else {
+				emit(ARM_CMP_R(r_skb_hl, r_off), ctx);
+				condt = ARM_COND_HI;
+			}
+
+			_emit(condt, ARM_ADD_R(r_scratch, r_off, r_skb_data),
+			      ctx);
+
+			if (load_order == 0)
+				_emit(condt, ARM_LDRB_I(r_A, r_scratch, 0),
+				      ctx);
+			else if (load_order == 1)
+				emit_load_be16(condt, r_A, r_scratch, ctx);
+			else if (load_order == 2)
+				emit_load_be32(condt, r_A, r_scratch, ctx);
+
+			_emit(condt, ARM_B(b_imm(i + 1, ctx)), ctx);
+
+			/* the slowpath */
+			emit_mov_i(ARM_R3, (u32)load_func[load_order], ctx);
+			emit(ARM_MOV_R(ARM_R0, r_skb), ctx);
+			/* the offset is already in R1 */
+			emit_blx_r(ARM_R3, ctx);
+			/* check the result of skb_copy_bits */
+			emit(ARM_CMP_I(ARM_R1, 0), ctx);
+			emit_err_ret(ARM_COND_NE, ctx);
+			emit(ARM_MOV_R(r_A, ARM_R0), ctx);
+			break;
+		case BPF_S_LD_W_IND:
+			load_order = 2;
+			goto load_ind;
+		case BPF_S_LD_H_IND:
+			load_order = 1;
+			goto load_ind;
+		case BPF_S_LD_B_IND:
+			load_order = 0;
+load_ind:
+			OP_IMM3(ARM_ADD, r_off, r_X, k, ctx);
+			goto load_common;
+		case BPF_S_LDX_IMM:
+			ctx->seen |= SEEN_X;
+			emit_mov_i(r_X, k, ctx);
+			break;
+		case BPF_S_LDX_W_LEN:
+			ctx->seen |= SEEN_X | SEEN_SKB;
+			emit(ARM_LDR_I(r_X, r_skb,
+				       offsetof(struct sk_buff, len)), ctx);
+			break;
+		case BPF_S_LDX_MEM:
+			ctx->seen |= SEEN_X | SEEN_MEM_WORD(k);
+			emit(ARM_LDR_I(r_X, ARM_SP, SCRATCH_OFF(k)), ctx);
+			break;
+		case BPF_S_LDX_B_MSH:
+			/* x = ((*(frame + k)) & 0xf) << 2; */
+			ctx->seen |= SEEN_X | SEEN_DATA | SEEN_CALL;
+			/* the interpreter should deal with the negative K */
+			if (k < 0)
+				return -1;
+			/* offset in r1: we might have to take the slow path */
+			emit_mov_i(r_off, k, ctx);
+			emit(ARM_CMP_R(r_skb_hl, r_off), ctx);
+
+			/* load in r0: common with the slowpath */
+			_emit(ARM_COND_HI, ARM_LDRB_R(ARM_R0, r_skb_data,
+						      ARM_R1), ctx);
+			/*
+			 * emit_mov_i() might generate one or two instructions,
+			 * the same holds for emit_blx_r()
+			 */
+			_emit(ARM_COND_HI, ARM_B(b_imm(i + 1, ctx) - 2), ctx);
+
+			emit(ARM_MOV_R(ARM_R0, r_skb), ctx);
+			/* r_off is r1 */
+			emit_mov_i(ARM_R3, (u32)jit_get_skb_b, ctx);
+			emit_blx_r(ARM_R3, ctx);
+			/* check the return value of skb_copy_bits */
+			emit(ARM_CMP_I(ARM_R1, 0), ctx);
+			emit_err_ret(ARM_COND_NE, ctx);
+
+			emit(ARM_AND_I(r_X, ARM_R0, 0x00f), ctx);
+			emit(ARM_LSL_I(r_X, r_X, 2), ctx);
+			break;
+		case BPF_S_ST:
+			ctx->seen |= SEEN_MEM_WORD(k);
+			emit(ARM_STR_I(r_A, ARM_SP, SCRATCH_OFF(k)), ctx);
+			break;
+		case BPF_S_STX:
+			update_on_xread(ctx);
+			ctx->seen |= SEEN_MEM_WORD(k);
+			emit(ARM_STR_I(r_X, ARM_SP, SCRATCH_OFF(k)), ctx);
+			break;
+		case BPF_S_ALU_ADD_K:
+			/* A += K */
+			OP_IMM3(ARM_ADD, r_A, r_A, k, ctx);
+			break;
+		case BPF_S_ALU_ADD_X:
+			update_on_xread(ctx);
+			emit(ARM_ADD_R(r_A, r_A, r_X), ctx);
+			break;
+		case BPF_S_ALU_SUB_K:
+			/* A -= K */
+			OP_IMM3(ARM_SUB, r_A, r_A, k, ctx);
+			break;
+		case BPF_S_ALU_SUB_X:
+			update_on_xread(ctx);
+			emit(ARM_SUB_R(r_A, r_A, r_X), ctx);
+			break;
+		case BPF_S_ALU_MUL_K:
+			/* A *= K */
+			emit_mov_i(r_scratch, k, ctx);
+			emit(ARM_MUL(r_A, r_A, r_scratch), ctx);
+			break;
+		case BPF_S_ALU_MUL_X:
+			update_on_xread(ctx);
+			emit(ARM_MUL(r_A, r_A, r_X), ctx);
+			break;
+		case BPF_S_ALU_DIV_K:
+			/* current k == reciprocal_value(userspace k) */
+			emit_mov_i(r_scratch, k, ctx);
+			/* A = top 32 bits of the product */
+			emit(ARM_UMULL(r_scratch, r_A, r_A, r_scratch), ctx);
+			break;
+		case BPF_S_ALU_DIV_X:
+			update_on_xread(ctx);
+			emit(ARM_CMP_I(r_X, 0), ctx);
+			emit_err_ret(ARM_COND_EQ, ctx);
+			emit_udiv(r_A, r_A, r_X, ctx);
+			break;
+		case BPF_S_ALU_OR_K:
+			/* A |= K */
+			OP_IMM3(ARM_ORR, r_A, r_A, k, ctx);
+			break;
+		case BPF_S_ALU_OR_X:
+			update_on_xread(ctx);
+			emit(ARM_ORR_R(r_A, r_A, r_X), ctx);
+			break;
+		case BPF_S_ALU_AND_K:
+			/* A &= K */
+			OP_IMM3(ARM_AND, r_A, r_A, k, ctx);
+			break;
+		case BPF_S_ALU_AND_X:
+			update_on_xread(ctx);
+			emit(ARM_AND_R(r_A, r_A, r_X), ctx);
+			break;
+		case BPF_S_ALU_LSH_K:
+			if (unlikely(k > 31))
+				return -1;
+			emit(ARM_LSL_I(r_A, r_A, k), ctx);
+			break;
+		case BPF_S_ALU_LSH_X:
+			update_on_xread(ctx);
+			emit(ARM_LSL_R(r_A, r_A, r_X), ctx);
+			break;
+		case BPF_S_ALU_RSH_K:
+			if (unlikely(k > 31))
+				return -1;
+			emit(ARM_LSR_I(r_A, r_A, k), ctx);
+			break;
+		case BPF_S_ALU_RSH_X:
+			update_on_xread(ctx);
+			emit(ARM_LSR_R(r_A, r_A, r_X), ctx);
+			break;
+		case BPF_S_ALU_NEG:
+			/* A = -A */
+			emit(ARM_RSB_I(r_A, r_A, 0), ctx);
+			break;
+		case BPF_S_JMP_JA:
+			/* pc += K */
+			emit(ARM_B(b_imm(i + k + 1, ctx)), ctx);
+			break;
+		case BPF_S_JMP_JEQ_K:
+			/* pc += (A == K) ? pc->jt : pc->jf */
+			condt  = ARM_COND_EQ;
+			goto cmp_imm;
+		case BPF_S_JMP_JGT_K:
+			/* pc += (A > K) ? pc->jt : pc->jf */
+			condt  = ARM_COND_HI;
+			goto cmp_imm;
+		case BPF_S_JMP_JGE_K:
+			/* pc += (A >= K) ? pc->jt : pc->jf */
+			condt  = ARM_COND_HS;
+cmp_imm:
+			imm12 = imm8m(k);
+			if (imm12 < 0) {
+				emit_mov_i_no8m(r_scratch, k, ctx);
+				emit(ARM_CMP_R(r_A, r_scratch), ctx);
+			} else {
+				emit(ARM_CMP_I(r_A, imm12), ctx);
+			}
+cond_jump:
+			if (inst->jt)
+				_emit(condt, ARM_B(b_imm(i + inst->jt + 1,
+						   ctx)), ctx);
+			if (inst->jf)
+				_emit(condt ^ 1, ARM_B(b_imm(i + inst->jf + 1,
+							     ctx)), ctx);
+			break;
+		case BPF_S_JMP_JEQ_X:
+			/* pc += (A == X) ? pc->jt : pc->jf */
+			condt   = ARM_COND_EQ;
+			goto cmp_x;
+		case BPF_S_JMP_JGT_X:
+			/* pc += (A > X) ? pc->jt : pc->jf */
+			condt   = ARM_COND_HI;
+			goto cmp_x;
+		case BPF_S_JMP_JGE_X:
+			/* pc += (A >= X) ? pc->jt : pc->jf */
+			condt   = ARM_COND_CS;
+cmp_x:
+			update_on_xread(ctx);
+			emit(ARM_CMP_R(r_A, r_X), ctx);
+			goto cond_jump;
+		case BPF_S_JMP_JSET_K:
+			/* pc += (A & K) ? pc->jt : pc->jf */
+			condt  = ARM_COND_NE;
+			/* not set iff all zeroes iff Z==1 iff EQ */
+
+			imm12 = imm8m(k);
+			if (imm12 < 0) {
+				emit_mov_i_no8m(r_scratch, k, ctx);
+				emit(ARM_TST_R(r_A, r_scratch), ctx);
+			} else {
+				emit(ARM_TST_I(r_A, imm12), ctx);
+			}
+			goto cond_jump;
+		case BPF_S_JMP_JSET_X:
+			/* pc += (A & X) ? pc->jt : pc->jf */
+			update_on_xread(ctx);
+			condt  = ARM_COND_NE;
+			emit(ARM_TST_R(r_A, r_X), ctx);
+			goto cond_jump;
+		case BPF_S_RET_A:
+			emit(ARM_MOV_R(ARM_R0, r_A), ctx);
+			goto b_epilogue;
+		case BPF_S_RET_K:
+			if ((k == 0) && (ctx->ret0_fp_idx < 0))
+				ctx->ret0_fp_idx = i;
+			emit_mov_i(ARM_R0, k, ctx);
+b_epilogue:
+			if (i != ctx->skf->len - 1)
+				emit(ARM_B(b_imm(prog->len, ctx)), ctx);
+			break;
+		case BPF_S_MISC_TAX:
+			/* X = A */
+			ctx->seen |= SEEN_X;
+			emit(ARM_MOV_R(r_X, r_A), ctx);
+			break;
+		case BPF_S_MISC_TXA:
+			/* A = X */
+			update_on_xread(ctx);
+			emit(ARM_MOV_R(r_A, r_X), ctx);
+			break;
+		case BPF_S_ANC_PROTOCOL:
+			/* A = ntohs(skb->protocol) */
+			ctx->seen |= SEEN_SKB;
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
+						  protocol) != 2);
+			off = offsetof(struct sk_buff, protocol);
+			emit(ARM_LDRH_I(r_scratch, r_skb, off), ctx);
+			emit_swap16(r_A, r_scratch, ctx);
+			break;
+		case BPF_S_ANC_CPU:
+			/* r_scratch = current_thread_info() */
+			OP_IMM3(ARM_BIC, r_scratch, ARM_SP, THREAD_SIZE - 1, ctx);
+			/* A = current_thread_info()->cpu */
+			BUILD_BUG_ON(FIELD_SIZEOF(struct thread_info, cpu) != 4);
+			off = offsetof(struct thread_info, cpu);
+			emit(ARM_LDR_I(r_A, r_scratch, off), ctx);
+			break;
+		case BPF_S_ANC_IFINDEX:
+			/* A = skb->dev->ifindex */
+			ctx->seen |= SEEN_SKB;
+			off = offsetof(struct sk_buff, dev);
+			emit(ARM_LDR_I(r_scratch, r_skb, off), ctx);
+
+			emit(ARM_CMP_I(r_scratch, 0), ctx);
+			emit_err_ret(ARM_COND_EQ, ctx);
+
+			BUILD_BUG_ON(FIELD_SIZEOF(struct net_device,
+						  ifindex) != 4);
+			off = offsetof(struct net_device, ifindex);
+			emit(ARM_LDR_I(r_A, r_scratch, off), ctx);
+			break;
+		case BPF_S_ANC_MARK:
+			ctx->seen |= SEEN_SKB;
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
+			off = offsetof(struct sk_buff, mark);
+			emit(ARM_LDR_I(r_A, r_skb, off), ctx);
+			break;
+		case BPF_S_ANC_RXHASH:
+			ctx->seen |= SEEN_SKB;
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
+			off = offsetof(struct sk_buff, rxhash);
+			emit(ARM_LDR_I(r_A, r_skb, off), ctx);
+			break;
+		case BPF_S_ANC_QUEUE:
+			ctx->seen |= SEEN_SKB;
+			BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
+						  queue_mapping) != 2);
+			BUILD_BUG_ON(offsetof(struct sk_buff,
+					      queue_mapping) > 0xff);
+			off = offsetof(struct sk_buff, queue_mapping);
+			emit(ARM_LDRH_I(r_A, r_skb, off), ctx);
+			break;
+		default:
+			return -1;
+		}
+	}
+
+	/* compute offsets only during the first pass */
+	if (ctx->target == NULL)
+		ctx->offsets[i] = ctx->idx * 4;
+
+	return 0;
+}
+
+
+void bpf_jit_compile(struct sk_filter *fp)
+{
+	struct jit_ctx ctx;
+	unsigned tmp_idx;
+	unsigned alloc_size;
+
+	if (!bpf_jit_enable)
+		return;
+
+	memset(&ctx, 0, sizeof(ctx));
+	ctx.skf		= fp;
+	ctx.ret0_fp_idx = -1;
+
+	ctx.offsets = kzalloc(GFP_KERNEL, 4 * (ctx.skf->len + 1));
+	if (ctx.offsets == NULL)
+		return;
+
+	/* fake pass to fill in the ctx->seen */
+	if (unlikely(build_body(&ctx)))
+		goto out;
+
+	tmp_idx = ctx.idx;
+	build_prologue(&ctx);
+	ctx.prologue_bytes = (ctx.idx - tmp_idx) * 4;
+
+#if __LINUX_ARM_ARCH__ < 7
+	tmp_idx = ctx.idx;
+	build_epilogue(&ctx);
+	ctx.epilogue_bytes = (ctx.idx - tmp_idx) * 4;
+
+	ctx.idx += ctx.imm_count;
+	if (ctx.imm_count) {
+		ctx.imms = kzalloc(GFP_KERNEL, 4 * ctx.imm_count);
+		if (ctx.imms == NULL)
+			goto out;
+	}
+#else
+	/* there's nothing after the epilogue on ARMv7 */
+	build_epilogue(&ctx);
+#endif
+
+	alloc_size = 4 * ctx.idx;
+	ctx.target = module_alloc(max(sizeof(struct work_struct),
+				      alloc_size));
+	if (unlikely(ctx.target == NULL))
+		goto out;
+
+	ctx.idx = 0;
+	build_prologue(&ctx);
+	build_body(&ctx);
+	build_epilogue(&ctx);
+
+	flush_icache_range((u32)ctx.target, (u32)(ctx.target + ctx.idx));
+
+#if __LINUX_ARM_ARCH__ < 7
+	if (ctx.imm_count)
+		kfree(ctx.imms);
+#endif
+
+	if (bpf_jit_enable > 1)
+		print_hex_dump(KERN_INFO, "BPF JIT code: ",
+			       DUMP_PREFIX_ADDRESS, 16, 4, ctx.target,
+			       alloc_size, false);
+
+	fp->bpf_func = (void *)ctx.target;
+out:
+	kfree(ctx.offsets);
+	return;
+}
+
+static void bpf_jit_free_worker(struct work_struct *work)
+{
+	module_free(NULL, work);
+}
+
+void bpf_jit_free(struct sk_filter *fp)
+{
+	struct work_struct *work;
+
+	if (fp->bpf_func != sk_run_filter) {
+		work = (struct work_struct *)fp->bpf_func;
+
+		INIT_WORK(work, bpf_jit_free_worker);
+		schedule_work(work);
+	}
+}
diff --git a/arch/arm/net/bpf_jit_32.h b/arch/arm/net/bpf_jit_32.h
new file mode 100644
index 0000000..99ae5e3
--- /dev/null
+++ b/arch/arm/net/bpf_jit_32.h
@@ -0,0 +1,190 @@
+/*
+ * Just-In-Time compiler for BPF filters on 32bit ARM
+ *
+ * Copyright (c) 2011 Mircea Gherzan <mgherzan@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; version 2 of the License.
+ */
+
+#ifndef PFILTER_OPCODES_ARM_H
+#define PFILTER_OPCODES_ARM_H
+
+#define ARM_R0	0
+#define ARM_R1	1
+#define ARM_R2	2
+#define ARM_R3	3
+#define ARM_R4	4
+#define ARM_R5	5
+#define ARM_R6	6
+#define ARM_R7	7
+#define ARM_R8	8
+#define ARM_R9	9
+#define ARM_R10	10
+#define ARM_FP	11
+#define ARM_IP	12
+#define ARM_SP	13
+#define ARM_LR	14
+#define ARM_PC	15
+
+#define ARM_COND_EQ		0x0
+#define ARM_COND_NE		0x1
+#define ARM_COND_CS		0x2
+#define ARM_COND_HS		ARM_COND_CS
+#define ARM_COND_CC		0x3
+#define ARM_COND_LO		ARM_COND_CC
+#define ARM_COND_MI		0x4
+#define ARM_COND_PL		0x5
+#define ARM_COND_VS		0x6
+#define ARM_COND_VC		0x7
+#define ARM_COND_HI		0x8
+#define ARM_COND_LS		0x9
+#define ARM_COND_GE		0xa
+#define ARM_COND_LT		0xb
+#define ARM_COND_GT		0xc
+#define ARM_COND_LE		0xd
+#define ARM_COND_AL		0xe
+
+/* register shift types */
+#define SRTYPE_LSL		0
+#define SRTYPE_LSR		1
+#define SRTYPE_ASR		2
+#define SRTYPE_ROR		3
+
+#define ARM_INST_ADD_R		0x00800000
+#define ARM_INST_ADD_I		0x02800000
+
+#define ARM_INST_AND_R		0x00000000
+#define ARM_INST_AND_I		0x02000000
+
+#define ARM_INST_BIC_R		0x01c00000
+#define ARM_INST_BIC_I		0x03c00000
+
+#define ARM_INST_B		0x0a000000
+#define ARM_INST_BX		0x012FFF10
+#define ARM_INST_BLX_R		0x012fff30
+
+#define ARM_INST_CMP_R		0x01500000
+#define ARM_INST_CMP_I		0x03500000
+
+#define ARM_INST_LDRB_I		0x05d00000
+#define ARM_INST_LDRB_R		0x07d00000
+#define ARM_INST_LDRH_I		0x01d000b0
+#define ARM_INST_LDR_I		0x05900000
+
+#define ARM_INST_LDM		0x08900000
+
+#define ARM_INST_LSL_I		0x01a00000
+#define ARM_INST_LSL_R		0x01a00010
+
+#define ARM_INST_LSR_I		0x01a00020
+#define ARM_INST_LSR_R		0x01a00030
+
+#define ARM_INST_MOV_R		0x01a00000
+#define ARM_INST_MOV_I		0x03a00000
+#define ARM_INST_MOVW		0x03000000
+#define ARM_INST_MOVT		0x03400000
+
+#define ARM_INST_MUL		0x00000090
+
+#define ARM_INST_POP		0x08bd0000
+#define ARM_INST_PUSH		0x092d0000
+
+#define ARM_INST_ORR_R		0x01800000
+#define ARM_INST_ORR_I		0x03800000
+
+#define ARM_INST_REV		0x06bf0f30
+#define ARM_INST_REV16		0x06bf0fb0
+
+#define ARM_INST_RSB_I		0x02600000
+
+#define ARM_INST_SUB_R		0x00400000
+#define ARM_INST_SUB_I		0x02400000
+
+#define ARM_INST_STR_I		0x05800000
+
+#define ARM_INST_TST_R		0x01100000
+#define ARM_INST_TST_I		0x03100000
+
+#define ARM_INST_UDIV		0x0730f010
+
+#define ARM_INST_UMULL		0x00800090
+
+/* register */
+#define _AL3_R(op, rd, rn, rm)	((op ## _R) | (rd) << 12 | (rn) << 16 | (rm))
+/* immediate */
+#define _AL3_I(op, rd, rn, imm)	((op ## _I) | (rd) << 12 | (rn) << 16 | (imm))
+
+#define ARM_ADD_R(rd, rn, rm)	_AL3_R(ARM_INST_ADD, rd, rn, rm)
+#define ARM_ADD_I(rd, rn, imm)	_AL3_I(ARM_INST_ADD, rd, rn, imm)
+
+#define ARM_AND_R(rd, rn, rm)	_AL3_R(ARM_INST_AND, rd, rn, rm)
+#define ARM_AND_I(rd, rn, imm)	_AL3_I(ARM_INST_AND, rd, rn, imm)
+
+#define ARM_BIC_R(rd, rn, rm)	_AL3_R(ARM_INST_BIC, rd, rn, rm)
+#define ARM_BIC_I(rd, rn, imm)	_AL3_I(ARM_INST_BIC, rd, rn, imm)
+
+#define ARM_B(imm24)		(ARM_INST_B | ((imm24) & 0xffffff))
+#define ARM_BX(rm)		(ARM_INST_BX | (rm))
+#define ARM_BLX_R(rm)		(ARM_INST_BLX_R | (rm))
+
+#define ARM_CMP_R(rn, rm)	_AL3_R(ARM_INST_CMP, 0, rn, rm)
+#define ARM_CMP_I(rn, imm)	_AL3_I(ARM_INST_CMP, 0, rn, imm)
+
+#define ARM_LDR_I(rt, rn, off)	(ARM_INST_LDR_I | (rt) << 12 | (rn) << 16 \
+				 | (off))
+#define ARM_LDRB_I(rt, rn, off)	(ARM_INST_LDRB_I | (rt) << 12 | (rn) << 16 \
+				 | (off))
+#define ARM_LDRB_R(rt, rn, rm)	(ARM_INST_LDRB_R | (rt) << 12 | (rn) << 16 \
+				 | (rm))
+#define ARM_LDRH_I(rt, rn, off)	(ARM_INST_LDRH_I | (rt) << 12 | (rn) << 16 \
+				 | (((off) & 0xf0) << 4) | ((off) & 0xf))
+
+#define ARM_LDM(rn, regs)	(ARM_INST_LDM | (rn) << 16 | (regs))
+
+#define ARM_LSL_R(rd, rn, rm)	(_AL3_R(ARM_INST_LSL, rd, 0, rn) | (rm) << 8)
+#define ARM_LSL_I(rd, rn, imm)	(_AL3_I(ARM_INST_LSL, rd, 0, rn) | (imm) << 7)
+
+#define ARM_LSR_R(rd, rn, rm)	(_AL3_R(ARM_INST_LSR, rd, 0, rn) | (rm) << 8)
+#define ARM_LSR_I(rd, rn, imm)	(_AL3_I(ARM_INST_LSR, rd, 0, rn) | (imm) << 7)
+
+#define ARM_MOV_R(rd, rm)	_AL3_R(ARM_INST_MOV, rd, 0, rm)
+#define ARM_MOV_I(rd, imm)	_AL3_I(ARM_INST_MOV, rd, 0, imm)
+
+#define ARM_MOVW(rd, imm)	\
+	(ARM_INST_MOVW | ((imm) >> 12) << 16 | (rd) << 12 | ((imm) & 0x0fff))
+
+#define ARM_MOVT(rd, imm)	\
+	(ARM_INST_MOVT | ((imm) >> 12) << 16 | (rd) << 12 | ((imm) & 0x0fff))
+
+#define ARM_MUL(rd, rm, rn)	(ARM_INST_MUL | (rd) << 16 | (rm) << 8 | (rn))
+
+#define ARM_POP(regs)		(ARM_INST_POP | (regs))
+#define ARM_PUSH(regs)		(ARM_INST_PUSH | (regs))
+
+#define ARM_ORR_R(rd, rn, rm)	_AL3_R(ARM_INST_ORR, rd, rn, rm)
+#define ARM_ORR_I(rd, rn, imm)	_AL3_I(ARM_INST_ORR, rd, rn, imm)
+#define ARM_ORR_S(rd, rn, rm, type, rs)	\
+	(ARM_ORR_R(rd, rn, rm) | (type) << 5 | (rs) << 7)
+
+#define ARM_REV(rd, rm)		(ARM_INST_REV | (rd) << 12 | (rm))
+#define ARM_REV16(rd, rm)	(ARM_INST_REV16 | (rd) << 12 | (rm))
+
+#define ARM_RSB_I(rd, rn, imm)	_AL3_I(ARM_INST_RSB, rd, rn, imm)
+
+#define ARM_SUB_R(rd, rn, rm)	_AL3_R(ARM_INST_SUB, rd, rn, rm)
+#define ARM_SUB_I(rd, rn, imm)	_AL3_I(ARM_INST_SUB, rd, rn, imm)
+
+#define ARM_STR_I(rt, rn, off)	(ARM_INST_STR_I | (rt) << 12 | (rn) << 16 \
+				 | (off))
+
+#define ARM_TST_R(rn, rm)	_AL3_R(ARM_INST_TST, 0, rn, rm)
+#define ARM_TST_I(rn, imm)	_AL3_I(ARM_INST_TST, 0, rn, imm)
+
+#define ARM_UDIV(rd, rn, rm)	(ARM_INST_UDIV | (rd) << 16 | (rn) | (rm) << 8)
+
+#define ARM_UMULL(rd_lo, rd_hi, rn, rm)	(ARM_INST_UMULL | (rd_hi) << 16 \
+					 | (rd_lo) << 12 | (rm) << 8 | rn)
+
+#endif /* PFILTER_OPCODES_ARM_H */
diff --git a/arch/arm/nwfpe/fpa11.c b/arch/arm/nwfpe/fpa11.c
index cc60acd..2782ebc 100644
--- a/arch/arm/nwfpe/fpa11.c
+++ b/arch/arm/nwfpe/fpa11.c
@@ -28,7 +28,6 @@
 
 #include <linux/compiler.h>
 #include <linux/string.h>
-#include <asm/system.h>
 
 /* Reset the FPA11 chip.  Called to initialize and reset the emulator. */
 static void resetFPA11(void)
diff --git a/arch/arm/plat-iop/i2c.c b/arch/arm/plat-iop/i2c.c
index 4efe392..88215ad 100644
--- a/arch/arm/plat-iop/i2c.c
+++ b/arch/arm/plat-iop/i2c.c
@@ -23,7 +23,6 @@
 #include <asm/page.h>
 #include <asm/mach/map.h>
 #include <asm/setup.h>
-#include <asm/system.h>
 #include <asm/memory.h>
 #include <mach/hardware.h>
 #include <asm/hardware/iop3xx.h>
diff --git a/arch/arm/plat-iop/pci.c b/arch/arm/plat-iop/pci.c
index f4d40a2..0da4205 100644
--- a/arch/arm/plat-iop/pci.c
+++ b/arch/arm/plat-iop/pci.c
@@ -20,7 +20,6 @@
 #include <linux/io.h>
 #include <asm/irq.h>
 #include <asm/signal.h>
-#include <asm/system.h>
 #include <mach/hardware.h>
 #include <asm/mach/pci.h>
 #include <asm/hardware/iop3xx.h>
@@ -215,8 +214,8 @@
 	sys->mem_offset = IOP3XX_PCI_LOWER_MEM_PA - *IOP3XX_OMWTVR0;
 	sys->io_offset  = IOP3XX_PCI_LOWER_IO_PA - *IOP3XX_OIOWTVR;
 
-	pci_add_resource(&sys->resources, &res[0]);
-	pci_add_resource(&sys->resources, &res[1]);
+	pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
+	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
 
 	return 1;
 }
diff --git a/arch/arm/plat-iop/restart.c b/arch/arm/plat-iop/restart.c
index 6a85a0c..33fa699 100644
--- a/arch/arm/plat-iop/restart.c
+++ b/arch/arm/plat-iop/restart.c
@@ -8,6 +8,7 @@
  * published by the Free Software Foundation.
  */
 #include <asm/hardware/iop3xx.h>
+#include <asm/system_misc.h>
 #include <mach/hardware.h>
 
 void iop3xx_restart(char mode, const char *cmd)
diff --git a/arch/arm/plat-mxc/3ds_debugboard.c b/arch/arm/plat-mxc/3ds_debugboard.c
index d1e31fa..5cac2c5 100644
--- a/arch/arm/plat-mxc/3ds_debugboard.c
+++ b/arch/arm/plat-mxc/3ds_debugboard.c
@@ -80,7 +80,7 @@
 
 static struct platform_device smsc_lan9217_device = {
 	.name = "smsc911x",
-	.id = 0,
+	.id = -1,
 	.dev = {
 		.platform_data = &smsc911x_config,
 	},
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
index dcebb12..c722f9c 100644
--- a/arch/arm/plat-mxc/Kconfig
+++ b/arch/arm/plat-mxc/Kconfig
@@ -88,12 +88,6 @@
 config ARCH_MXC_IOMUX_V3
 	bool
 
-config ARCH_MXC_AUDMUX_V1
-	bool
-
-config ARCH_MXC_AUDMUX_V2
-	bool
-
 config IRAM_ALLOC
 	bool
 	select GENERIC_ALLOCATOR
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
index 076db84f..e81290c 100644
--- a/arch/arm/plat-mxc/Makefile
+++ b/arch/arm/plat-mxc/Makefile
@@ -14,8 +14,6 @@
 obj-$(CONFIG_MXC_PWM)  += pwm.o
 obj-$(CONFIG_MXC_ULPI) += ulpi.o
 obj-$(CONFIG_MXC_USE_EPIT) += epit.o
-obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o
-obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o
 obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
 obj-$(CONFIG_CPU_FREQ_IMX)    += cpufreq.o
 ifdef CONFIG_SND_IMX_SOC
diff --git a/arch/arm/plat-mxc/audmux-v1.c b/arch/arm/plat-mxc/audmux-v1.c
deleted file mode 100644
index 1180bef..0000000
--- a/arch/arm/plat-mxc/audmux-v1.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
- *
- * Initial development of this code was funded by
- * Phytec Messtechnik GmbH, http://www.phytec.de
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <mach/audmux.h>
-#include <mach/hardware.h>
-
-static void __iomem *audmux_base;
-
-static unsigned char port_mapping[] = {
-	0x0, 0x4, 0x8, 0x10, 0x14, 0x1c,
-};
-
-int mxc_audmux_v1_configure_port(unsigned int port, unsigned int pcr)
-{
-	if (!audmux_base) {
-		printk("%s: not configured\n", __func__);
-		return -ENOSYS;
-	}
-
-	if (port >= ARRAY_SIZE(port_mapping))
-		return -EINVAL;
-
-	writel(pcr, audmux_base + port_mapping[port]);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(mxc_audmux_v1_configure_port);
-
-static int mxc_audmux_v1_init(void)
-{
-#ifdef CONFIG_MACH_MX21
-	if (cpu_is_mx21())
-		audmux_base = MX21_IO_ADDRESS(MX21_AUDMUX_BASE_ADDR);
-	else
-#endif
-#ifdef CONFIG_MACH_MX27
-	if (cpu_is_mx27())
-		audmux_base = MX27_IO_ADDRESS(MX27_AUDMUX_BASE_ADDR);
-	else
-#endif
-		(void)0;
-	
-	return 0;
-}
-
-postcore_initcall(mxc_audmux_v1_init);
diff --git a/arch/arm/plat-mxc/audmux-v2.c b/arch/arm/plat-mxc/audmux-v2.c
deleted file mode 100644
index 8cced35..0000000
--- a/arch/arm/plat-mxc/audmux-v2.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
- *
- * Initial development of this code was funded by
- * Phytec Messtechnik GmbH, http://www.phytec.de
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/debugfs.h>
-#include <linux/slab.h>
-#include <mach/audmux.h>
-#include <mach/hardware.h>
-
-static struct clk *audmux_clk;
-static void __iomem *audmux_base;
-
-#define MXC_AUDMUX_V2_PTCR(x)		((x) * 8)
-#define MXC_AUDMUX_V2_PDCR(x)		((x) * 8 + 4)
-
-#ifdef CONFIG_DEBUG_FS
-static struct dentry *audmux_debugfs_root;
-
-static int audmux_open_file(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-/* There is an annoying discontinuity in the SSI numbering with regard
- * to the Linux number of the devices */
-static const char *audmux_port_string(int port)
-{
-	switch (port) {
-	case MX31_AUDMUX_PORT1_SSI0:
-		return "imx-ssi.0";
-	case MX31_AUDMUX_PORT2_SSI1:
-		return "imx-ssi.1";
-	case MX31_AUDMUX_PORT3_SSI_PINS_3:
-		return "SSI3";
-	case MX31_AUDMUX_PORT4_SSI_PINS_4:
-		return "SSI4";
-	case MX31_AUDMUX_PORT5_SSI_PINS_5:
-		return "SSI5";
-	case MX31_AUDMUX_PORT6_SSI_PINS_6:
-		return "SSI6";
-	default:
-		return "UNKNOWN";
-	}
-}
-
-static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
-				size_t count, loff_t *ppos)
-{
-	ssize_t ret;
-	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-	int port = (int)file->private_data;
-	u32 pdcr, ptcr;
-
-	if (!buf)
-		return -ENOMEM;
-
-	if (audmux_clk)
-		clk_enable(audmux_clk);
-
-	ptcr = readl(audmux_base + MXC_AUDMUX_V2_PTCR(port));
-	pdcr = readl(audmux_base + MXC_AUDMUX_V2_PDCR(port));
-
-	if (audmux_clk)
-		clk_disable(audmux_clk);
-
-	ret = snprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n",
-		       pdcr, ptcr);
-
-	if (ptcr & MXC_AUDMUX_V2_PTCR_TFSDIR)
-		ret += snprintf(buf + ret, PAGE_SIZE - ret,
-				"TxFS output from %s, ",
-				audmux_port_string((ptcr >> 27) & 0x7));
-	else
-		ret += snprintf(buf + ret, PAGE_SIZE - ret,
-				"TxFS input, ");
-
-	if (ptcr & MXC_AUDMUX_V2_PTCR_TCLKDIR)
-		ret += snprintf(buf + ret, PAGE_SIZE - ret,
-				"TxClk output from %s",
-				audmux_port_string((ptcr >> 22) & 0x7));
-	else
-		ret += snprintf(buf + ret, PAGE_SIZE - ret,
-				"TxClk input");
-
-	ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
-
-	if (ptcr & MXC_AUDMUX_V2_PTCR_SYN) {
-		ret += snprintf(buf + ret, PAGE_SIZE - ret,
-				"Port is symmetric");
-	} else {
-		if (ptcr & MXC_AUDMUX_V2_PTCR_RFSDIR)
-			ret += snprintf(buf + ret, PAGE_SIZE - ret,
-					"RxFS output from %s, ",
-					audmux_port_string((ptcr >> 17) & 0x7));
-		else
-			ret += snprintf(buf + ret, PAGE_SIZE - ret,
-					"RxFS input, ");
-
-		if (ptcr & MXC_AUDMUX_V2_PTCR_RCLKDIR)
-			ret += snprintf(buf + ret, PAGE_SIZE - ret,
-					"RxClk output from %s",
-					audmux_port_string((ptcr >> 12) & 0x7));
-		else
-			ret += snprintf(buf + ret, PAGE_SIZE - ret,
-					"RxClk input");
-	}
-
-	ret += snprintf(buf + ret, PAGE_SIZE - ret,
-			"\nData received from %s\n",
-			audmux_port_string((pdcr >> 13) & 0x7));
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
-
-	kfree(buf);
-
-	return ret;
-}
-
-static const struct file_operations audmux_debugfs_fops = {
-	.open = audmux_open_file,
-	.read = audmux_read_file,
-	.llseek = default_llseek,
-};
-
-static void audmux_debugfs_init(void)
-{
-	int i;
-	char buf[20];
-
-	audmux_debugfs_root = debugfs_create_dir("audmux", NULL);
-	if (!audmux_debugfs_root) {
-		pr_warning("Failed to create AUDMUX debugfs root\n");
-		return;
-	}
-
-	for (i = 1; i < 8; i++) {
-		snprintf(buf, sizeof(buf), "ssi%d", i);
-		if (!debugfs_create_file(buf, 0444, audmux_debugfs_root,
-					 (void *)i, &audmux_debugfs_fops))
-			pr_warning("Failed to create AUDMUX port %d debugfs file\n",
-				   i);
-	}
-}
-#else
-static inline void audmux_debugfs_init(void)
-{
-}
-#endif
-
-int mxc_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
-		unsigned int pdcr)
-{
-	if (!audmux_base)
-		return -ENOSYS;
-
-	if (audmux_clk)
-		clk_enable(audmux_clk);
-
-	writel(ptcr, audmux_base + MXC_AUDMUX_V2_PTCR(port));
-	writel(pdcr, audmux_base + MXC_AUDMUX_V2_PDCR(port));
-
-	if (audmux_clk)
-		clk_disable(audmux_clk);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(mxc_audmux_v2_configure_port);
-
-static int mxc_audmux_v2_init(void)
-{
-	int ret;
-	if (cpu_is_mx51()) {
-		audmux_base = MX51_IO_ADDRESS(MX51_AUDMUX_BASE_ADDR);
-	} else if (cpu_is_mx31()) {
-		audmux_base = MX31_IO_ADDRESS(MX31_AUDMUX_BASE_ADDR);
-	} else if (cpu_is_mx35()) {
-		audmux_clk = clk_get(NULL, "audmux");
-		if (IS_ERR(audmux_clk)) {
-			ret = PTR_ERR(audmux_clk);
-			printk(KERN_ERR "%s: cannot get clock: %d\n", __func__,
-					ret);
-			return ret;
-		}
-		audmux_base = MX35_IO_ADDRESS(MX35_AUDMUX_BASE_ADDR);
-	} else if (cpu_is_mx25()) {
-		audmux_clk = clk_get(NULL, "audmux");
-		if (IS_ERR(audmux_clk)) {
-			ret = PTR_ERR(audmux_clk);
-			printk(KERN_ERR "%s: cannot get clock: %d\n", __func__,
-					ret);
-			return ret;
-		}
-		audmux_base = MX25_IO_ADDRESS(MX25_AUDMUX_BASE_ADDR);
-	}
-
-	audmux_debugfs_init();
-
-	return 0;
-}
-
-postcore_initcall(mxc_audmux_v2_init);
diff --git a/arch/arm/plat-mxc/avic.c b/arch/arm/plat-mxc/avic.c
index 55f1569..689f81f 100644
--- a/arch/arm/plat-mxc/avic.c
+++ b/arch/arm/plat-mxc/avic.c
@@ -60,7 +60,7 @@
 	unsigned int mask = 0x0F << irq % 8 * 4;
 
 	if (irq >= AVIC_NUM_IRQS)
-		return -EINVAL;;
+		return -EINVAL;
 
 	temp = __raw_readl(avic_base + AVIC_NIPRIORITY(irq / 8));
 	temp &= ~mask;
diff --git a/arch/arm/plat-mxc/cpu.c b/arch/arm/plat-mxc/cpu.c
index f5b7e0f..220dd6f 100644
--- a/arch/arm/plat-mxc/cpu.c
+++ b/arch/arm/plat-mxc/cpu.c
@@ -1,5 +1,6 @@
 
 #include <linux/module.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 
 unsigned int __mxc_cpu_type;
@@ -18,3 +19,26 @@
 		pr_info("CPU identified as %s, silicon rev %d.%d\n",
 				cpu, (srev >> 4) & 0xf, srev & 0xf);
 }
+
+void __init imx_set_aips(void __iomem *base)
+{
+	unsigned int reg;
+/*
+ * Set all MPROTx to be non-bufferable, trusted for R/W,
+ * not forced to user-mode.
+ */
+	__raw_writel(0x77777777, base + 0x0);
+	__raw_writel(0x77777777, base + 0x4);
+
+/*
+ * Set all OPACRx to be non-bufferable, to not require
+ * supervisor privilege level for access, allow for
+ * write access and untrusted master access.
+ */
+	__raw_writel(0x0, base + 0x40);
+	__raw_writel(0x0, base + 0x44);
+	__raw_writel(0x0, base + 0x48);
+	__raw_writel(0x0, base + 0x4C);
+	reg = __raw_readl(base + 0x50) & 0x00FFFFFF;
+	__raw_writel(reg, base + 0x50);
+}
diff --git a/arch/arm/plat-mxc/devices/platform-ahci-imx.c b/arch/arm/plat-mxc/devices/platform-ahci-imx.c
index d8a56ae..ade4a1c 100644
--- a/arch/arm/plat-mxc/devices/platform-ahci-imx.c
+++ b/arch/arm/plat-mxc/devices/platform-ahci-imx.c
@@ -60,9 +60,9 @@
 		dev_err(dev, "no sata clock.\n");
 		return PTR_ERR(sata_clk);
 	}
-	ret = clk_enable(sata_clk);
+	ret = clk_prepare_enable(sata_clk);
 	if (ret) {
-		dev_err(dev, "can't enable sata clock.\n");
+		dev_err(dev, "can't prepare/enable sata clock.\n");
 		goto put_sata_clk;
 	}
 
@@ -73,9 +73,9 @@
 		ret = PTR_ERR(sata_ref_clk);
 		goto release_sata_clk;
 	}
-	ret = clk_enable(sata_ref_clk);
+	ret = clk_prepare_enable(sata_ref_clk);
 	if (ret) {
-		dev_err(dev, "can't enable sata ref clock.\n");
+		dev_err(dev, "can't prepare/enable sata ref clock.\n");
 		goto put_sata_ref_clk;
 	}
 
@@ -104,11 +104,11 @@
 	return 0;
 
 release_sata_ref_clk:
-	clk_disable(sata_ref_clk);
+	clk_disable_unprepare(sata_ref_clk);
 put_sata_ref_clk:
 	clk_put(sata_ref_clk);
 release_sata_clk:
-	clk_disable(sata_clk);
+	clk_disable_unprepare(sata_clk);
 put_sata_clk:
 	clk_put(sata_clk);
 
@@ -117,10 +117,10 @@
 
 static void imx_sata_exit(struct device *dev)
 {
-	clk_disable(sata_ref_clk);
+	clk_disable_unprepare(sata_ref_clk);
 	clk_put(sata_ref_clk);
 
-	clk_disable(sata_clk);
+	clk_disable_unprepare(sata_clk);
 	clk_put(sata_clk);
 
 }
diff --git a/arch/arm/plat-mxc/devices/platform-mx2-camera.c b/arch/arm/plat-mxc/devices/platform-mx2-camera.c
index b3f4828..11eace9 100644
--- a/arch/arm/plat-mxc/devices/platform-mx2-camera.c
+++ b/arch/arm/plat-mxc/devices/platform-mx2-camera.c
@@ -62,3 +62,21 @@
 			res, data->iobaseemmaprp ? 4 : 2,
 			pdata, sizeof(*pdata), DMA_BIT_MASK(32));
 }
+
+struct platform_device *__init imx_add_mx2_emmaprp(
+		const struct imx_mx2_camera_data *data)
+{
+	struct resource res[] = {
+		{
+			.start = data->iobaseemmaprp,
+			.end = data->iobaseemmaprp + data->iosizeemmaprp - 1,
+			.flags = IORESOURCE_MEM,
+		}, {
+			.start = data->irqemmaprp,
+			.end = data->irqemmaprp,
+			.flags = IORESOURCE_IRQ,
+		},
+	};
+	return imx_add_platform_device_dmamask("m2m-emmaprp", 0,
+			res, 2, NULL, 0, DMA_BIT_MASK(32));
+}
diff --git a/arch/arm/plat-mxc/epit.c b/arch/arm/plat-mxc/epit.c
index d3467f8..9129c9e 100644
--- a/arch/arm/plat-mxc/epit.c
+++ b/arch/arm/plat-mxc/epit.c
@@ -203,7 +203,7 @@
 
 void __init epit_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
 {
-	clk_enable(timer_clk);
+	clk_prepare_enable(timer_clk);
 
 	timer_base = base;
 
diff --git a/arch/arm/plat-mxc/include/mach/audmux.h b/arch/arm/plat-mxc/include/mach/audmux.h
deleted file mode 100644
index 6fda788..0000000
--- a/arch/arm/plat-mxc/include/mach/audmux.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef __MACH_AUDMUX_H
-#define __MACH_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 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 MXC_AUDMUX_V1_PCR_INMMASK(x)	((x) & 0xff)
-#define MXC_AUDMUX_V1_PCR_INMEN		(1 << 8)
-#define MXC_AUDMUX_V1_PCR_TXRXEN	(1 << 10)
-#define MXC_AUDMUX_V1_PCR_SYN		(1 << 12)
-#define MXC_AUDMUX_V1_PCR_RXDSEL(x)	(((x) & 0x7) << 13)
-#define MXC_AUDMUX_V1_PCR_RFCSEL(x)	(((x) & 0xf) << 20)
-#define MXC_AUDMUX_V1_PCR_RCLKDIR	(1 << 24)
-#define MXC_AUDMUX_V1_PCR_RFSDIR	(1 << 25)
-#define MXC_AUDMUX_V1_PCR_TFCSEL(x)	(((x) & 0xf) << 26)
-#define MXC_AUDMUX_V1_PCR_TCLKDIR	(1 << 30)
-#define MXC_AUDMUX_V1_PCR_TFSDIR	(1 << 31)
-
-/* Register definitions for the i.MX25/31/35/51 Digital Audio Multiplexer */
-#define MXC_AUDMUX_V2_PTCR_TFSDIR	(1 << 31)
-#define MXC_AUDMUX_V2_PTCR_TFSEL(x)	(((x) & 0xf) << 27)
-#define MXC_AUDMUX_V2_PTCR_TCLKDIR	(1 << 26)
-#define MXC_AUDMUX_V2_PTCR_TCSEL(x)	(((x) & 0xf) << 22)
-#define MXC_AUDMUX_V2_PTCR_RFSDIR	(1 << 21)
-#define MXC_AUDMUX_V2_PTCR_RFSEL(x)	(((x) & 0xf) << 17)
-#define MXC_AUDMUX_V2_PTCR_RCLKDIR	(1 << 16)
-#define MXC_AUDMUX_V2_PTCR_RCSEL(x)	(((x) & 0xf) << 12)
-#define MXC_AUDMUX_V2_PTCR_SYN		(1 << 11)
-
-#define MXC_AUDMUX_V2_PDCR_RXDSEL(x)	(((x) & 0x7) << 13)
-#define MXC_AUDMUX_V2_PDCR_TXRXEN	(1 << 12)
-#define MXC_AUDMUX_V2_PDCR_MODE(x)	(((x) & 0x3) << 8)
-#define MXC_AUDMUX_V2_PDCR_INMMASK(x)	((x) & 0xff)
-
-int mxc_audmux_v1_configure_port(unsigned int port, unsigned int pcr);
-
-int mxc_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
-		unsigned int pdcr);
-
-#endif /* __MACH_AUDMUX_H */
diff --git a/arch/arm/plat-mxc/include/mach/board-mx31ads.h b/arch/arm/plat-mxc/include/mach/board-mx31ads.h
deleted file mode 100644
index 94b60dd4..0000000
--- a/arch/arm/plat-mxc/include/mach/board-mx31ads.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2005-2007 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 version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __ASM_ARCH_MXC_BOARD_MX31ADS_H__
-#define __ASM_ARCH_MXC_BOARD_MX31ADS_H__
-
-#include <mach/hardware.h>
-
-/*
- * These symbols are used by drivers/net/cs89x0.c.
- * This is ugly as hell, but we have to provide them until
- * someone fixed the driver.
- */
-
-/* Base address of PBC controller */
-#define PBC_BASE_ADDRESS        MX31_CS4_BASE_ADDR_VIRT
-/* Offsets for the PBC Controller register */
-
-/* Ethernet Controller IO base address */
-#define PBC_CS8900A_IOBASE      0x020000
-
-#define MXC_EXP_IO_BASE		(MXC_BOARD_IRQ_START)
-
-#define EXPIO_INT_ENET_INT	(MXC_EXP_IO_BASE + 8)
-
-#endif /* __ASM_ARCH_MXC_BOARD_MX31ADS_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h
index 1bf0df8..0319c4a 100644
--- a/arch/arm/plat-mxc/include/mach/common.h
+++ b/arch/arm/plat-mxc/include/mach/common.h
@@ -65,6 +65,7 @@
 			unsigned long ckih1, unsigned long ckih2);
 extern int mx53_clocks_init(unsigned long ckil, unsigned long osc,
 			unsigned long ckih1, unsigned long ckih2);
+extern int mx27_clocks_init_dt(void);
 extern int mx51_clocks_init_dt(void);
 extern int mx53_clocks_init_dt(void);
 extern int mx6q_clocks_init(void);
@@ -75,6 +76,7 @@
 extern void mxc_arch_reset_init(void __iomem *);
 extern int mx53_revision(void);
 extern int mx53_display_revision(void);
+extern void imx_set_aips(void __iomem *);
 
 enum mxc_cpu_pwr_mode {
 	WAIT_CLOCKED,		/* wfi only */
@@ -84,6 +86,14 @@
 	STOP_POWER_OFF,		/* STOP + SRPG */
 };
 
+enum mx3_cpu_pwr_mode {
+	MX3_RUN,
+	MX3_WAIT,
+	MX3_DOZE,
+	MX3_SLEEP,
+};
+
+extern void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode);
 extern void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode);
 extern void imx_print_silicon_rev(const char *cpu, int srev);
 
diff --git a/arch/arm/plat-mxc/include/mach/debug-macro.S b/arch/arm/plat-mxc/include/mach/debug-macro.S
index 6e192c4..8ddda36 100644
--- a/arch/arm/plat-mxc/include/mach/debug-macro.S
+++ b/arch/arm/plat-mxc/include/mach/debug-macro.S
@@ -24,7 +24,7 @@
 #define UART_PADDR	MX51_UART1_BASE_ADDR
 #elif defined (CONFIG_DEBUG_IMX50_IMX53_UART)
 #define UART_PADDR	MX53_UART1_BASE_ADDR
-#elif defined (CONFIG_DEBUG_IMX6Q_UART)
+#elif defined (CONFIG_DEBUG_IMX6Q_UART4)
 #define UART_PADDR	MX6Q_UART4_BASE_ADDR
 #endif
 
diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h
index def9ba5..1b2258d 100644
--- a/arch/arm/plat-mxc/include/mach/devices-common.h
+++ b/arch/arm/plat-mxc/include/mach/devices-common.h
@@ -223,6 +223,8 @@
 struct platform_device *__init imx_add_mx2_camera(
 		const struct imx_mx2_camera_data *data,
 		const struct mx2_camera_platform_data *pdata);
+struct platform_device *__init imx_add_mx2_emmaprp(
+		const struct imx_mx2_camera_data *data);
 
 #include <mach/mxc_ehci.h>
 struct imx_mxc_ehci_data {
diff --git a/arch/arm/plat-mxc/include/mach/dma.h b/arch/arm/plat-mxc/include/mach/dma.h
index 233d0a5..1b90803 100644
--- a/arch/arm/plat-mxc/include/mach/dma.h
+++ b/arch/arm/plat-mxc/include/mach/dma.h
@@ -60,8 +60,7 @@
 
 static inline int imx_dma_is_general_purpose(struct dma_chan *chan)
 {
-	return !strcmp(dev_name(chan->device->dev), "imx31-sdma") ||
-		!strcmp(dev_name(chan->device->dev), "imx35-sdma") ||
+	return strstr(dev_name(chan->device->dev), "sdma") ||
 		!strcmp(dev_name(chan->device->dev), "imx-dma");
 }
 
diff --git a/arch/arm/plat-mxc/include/mach/entry-macro.S b/arch/arm/plat-mxc/include/mach/entry-macro.S
deleted file mode 100644
index def5d30..0000000
--- a/arch/arm/plat-mxc/include/mach/entry-macro.S
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *  Copyright (C) 2007 Lennert Buytenhek <buytenh@wantstofly.org>
- *  Copyright 2004-2009 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 version 2 as
- * published by the Free Software Foundation.
- */
-
-	.macro	disable_fiq
-	.endm
-
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
diff --git a/arch/arm/plat-mxc/include/mach/hardware.h b/arch/arm/plat-mxc/include/mach/hardware.h
index a599f01..0630513 100644
--- a/arch/arm/plat-mxc/include/mach/hardware.h
+++ b/arch/arm/plat-mxc/include/mach/hardware.h
@@ -22,11 +22,8 @@
 
 #include <asm/sizes.h>
 
-#ifdef __ASSEMBLER__
-#define IOMEM(addr)	(addr)
-#else
-#define IOMEM(addr)	((void __force __iomem *)(addr))
-#endif
+#define addr_in_module(addr, mod) \
+	((unsigned long)(addr) - mod ## _BASE_ADDR < mod ## _SIZE)
 
 #define IMX_IO_P2V_MODULE(addr, module)					\
 	(((addr) - module ## _BASE_ADDR) < module ## _SIZE ?		\
diff --git a/arch/arm/plat-mxc/include/mach/io.h b/arch/arm/plat-mxc/include/mach/io.h
deleted file mode 100644
index 338300b18..0000000
--- a/arch/arm/plat-mxc/include/mach/io.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- *  Copyright 2004-2007 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 version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __ASM_ARCH_MXC_IO_H__
-#define __ASM_ARCH_MXC_IO_H__
-
-/* Allow IO space to be anywhere in the memory */
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __arch_ioremap __imx_ioremap
-#define __arch_iounmap __iounmap
-
-#define addr_in_module(addr, mod) \
-	((unsigned long)(addr) - mod ## _BASE_ADDR < mod ## _SIZE)
-
-extern void __iomem *(*imx_ioremap)(unsigned long, size_t, unsigned int);
-
-static inline void __iomem *
-__imx_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
-{
-	if (imx_ioremap != NULL)
-		return imx_ioremap(phys_addr, size, mtype);
-	else
-		return __arm_ioremap(phys_addr, size, mtype);
-}
-
-/* io address mapping macro */
-#define __io(a)		__typesafe_io(a)
-
-#define __mem_pci(a)	(a)
-
-#endif
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx25.h b/arch/arm/plat-mxc/include/mach/iomux-mx25.h
index f0726d4..c61ec0f 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx25.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx25.h
@@ -139,15 +139,15 @@
 #define MX25_PAD_NFRB__GPIO_3_31	IOMUX_PAD(0x27c, 0x084, 0x15, 0, 0, NO_PAD_CTRL)
 
 #define MX25_PAD_D15__D15		IOMUX_PAD(0x280, 0x088, 0x00, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_D15__LD16		IOMUX_PAD(0x280, 0x088, 0x01, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_D15__LD16		IOMUX_PAD(0x280, 0x088, 0x01, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_D15__GPIO_4_5		IOMUX_PAD(0x280, 0x088, 0x05, 0, 0, NO_PAD_CTRL)
 
 #define MX25_PAD_D14__D14		IOMUX_PAD(0x284, 0x08c, 0x00, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_D14__LD17		IOMUX_PAD(0x284, 0x08c, 0x01, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_D14__LD17		IOMUX_PAD(0x284, 0x08c, 0x01, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_D14__GPIO_4_6		IOMUX_PAD(0x284, 0x08c, 0x05, 0, 0, NO_PAD_CTRL)
 
 #define MX25_PAD_D13__D13		IOMUX_PAD(0x288, 0x090, 0x00, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_D13__LD18		IOMUX_PAD(0x288, 0x090, 0x01, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_D13__LD18		IOMUX_PAD(0x288, 0x090, 0x01, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_D13__GPIO_4_7		IOMUX_PAD(0x288, 0x090, 0x05, 0, 0, NO_PAD_CTRL)
 
 #define MX25_PAD_D12__D12		IOMUX_PAD(0x28c, 0x094, 0x00, 0, 0, NO_PAD_CTRL)
@@ -192,54 +192,54 @@
 #define MX25_PAD_D0__D0			IOMUX_PAD(0x2bc, 0x0c4, 0x00, 0, 0, NO_PAD_CTRL)
 #define MX25_PAD_D0__GPIO_4_20		IOMUX_PAD(0x2bc, 0x0c4, 0x05, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD0__LD0		IOMUX_PAD(0x2c0, 0x0c8, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD0__LD0		IOMUX_PAD(0x2c0, 0x0c8, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD0__CSI_D0		IOMUX_PAD(0x2c0, 0x0c8, 0x12, 0x488, 0, NO_PAD_CTRL)
 #define MX25_PAD_LD0__GPIO_2_15		IOMUX_PAD(0x2c0, 0x0c8, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD1__LD1		IOMUX_PAD(0x2c4, 0x0cc, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD1__LD1		IOMUX_PAD(0x2c4, 0x0cc, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD1__CSI_D1		IOMUX_PAD(0x2c4, 0x0cc, 0x12, 0x48c, 0, NO_PAD_CTRL)
 #define MX25_PAD_LD1__GPIO_2_16		IOMUX_PAD(0x2c4, 0x0cc, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD2__LD2		IOMUX_PAD(0x2c8, 0x0d0, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD2__LD2		IOMUX_PAD(0x2c8, 0x0d0, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD2__GPIO_2_17		IOMUX_PAD(0x2c8, 0x0d0, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD3__LD3		IOMUX_PAD(0x2cc, 0x0d4, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD3__LD3		IOMUX_PAD(0x2cc, 0x0d4, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD3__GPIO_2_18		IOMUX_PAD(0x2cc, 0x0d4, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD4__LD4		IOMUX_PAD(0x2d0, 0x0d8, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD4__LD4		IOMUX_PAD(0x2d0, 0x0d8, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD4__GPIO_2_19		IOMUX_PAD(0x2d0, 0x0d8, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD5__LD5		IOMUX_PAD(0x2d4, 0x0dc, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD5__LD5		IOMUX_PAD(0x2d4, 0x0dc, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD5__GPIO_1_19		IOMUX_PAD(0x2d4, 0x0dc, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD6__LD6		IOMUX_PAD(0x2d8, 0x0e0, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD6__LD6		IOMUX_PAD(0x2d8, 0x0e0, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD6__GPIO_1_20		IOMUX_PAD(0x2d8, 0x0e0, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD7__LD7		IOMUX_PAD(0x2dc, 0x0e4, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD7__LD7		IOMUX_PAD(0x2dc, 0x0e4, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD7__GPIO_1_21		IOMUX_PAD(0x2dc, 0x0e4, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD8__LD8		IOMUX_PAD(0x2e0, 0x0e8, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD8__LD8		IOMUX_PAD(0x2e0, 0x0e8, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD8__FEC_TX_ERR	IOMUX_PAD(0x2e0, 0x0e8, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD9__LD9		IOMUX_PAD(0x2e4, 0x0ec, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD9__LD9		IOMUX_PAD(0x2e4, 0x0ec, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD9__FEC_COL		IOMUX_PAD(0x2e4, 0x0ec, 0x15, 0x504, 1, NO_PAD_CTRL)
 
-#define MX25_PAD_LD10__LD10		IOMUX_PAD(0x2e8, 0x0f0, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD10__LD10		IOMUX_PAD(0x2e8, 0x0f0, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD10__FEC_RX_ER	IOMUX_PAD(0x2e8, 0x0f0, 0x15, 0x518, 1, NO_PAD_CTRL)
 
-#define MX25_PAD_LD11__LD11		IOMUX_PAD(0x2ec, 0x0f4, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD11__LD11		IOMUX_PAD(0x2ec, 0x0f4, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD11__FEC_RDATA2	IOMUX_PAD(0x2ec, 0x0f4, 0x15, 0x50c, 1, NO_PAD_CTRL)
 
-#define MX25_PAD_LD12__LD12		IOMUX_PAD(0x2f0, 0x0f8, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD12__LD12		IOMUX_PAD(0x2f0, 0x0f8, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD12__FEC_RDATA3	IOMUX_PAD(0x2f0, 0x0f8, 0x15, 0x510, 1, NO_PAD_CTRL)
 
-#define MX25_PAD_LD13__LD13		IOMUX_PAD(0x2f4, 0x0fc, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD13__LD13		IOMUX_PAD(0x2f4, 0x0fc, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD13__FEC_TDATA2	IOMUX_PAD(0x2f4, 0x0fc, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD14__LD14		IOMUX_PAD(0x2f8, 0x100, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD14__LD14		IOMUX_PAD(0x2f8, 0x100, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD14__FEC_TDATA3	IOMUX_PAD(0x2f8, 0x100, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD15__LD15		IOMUX_PAD(0x2fc, 0x104, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD15__LD15		IOMUX_PAD(0x2fc, 0x104, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD15__FEC_RX_CLK	IOMUX_PAD(0x2fc, 0x104, 0x15, 0x514, 1, NO_PAD_CTRL)
 
 #define MX25_PAD_HSYNC__HSYNC		IOMUX_PAD(0x300, 0x108, 0x10, 0, 0, NO_PAD_CTRL)
@@ -468,11 +468,11 @@
 #define MX25_PAD_GPIO_C__CAN2_TX	IOMUX_PAD(0x3f8, 0x1fc, 0x16, 0, 0, PAD_CTL_PUS_22K_UP)
 
 #define MX25_PAD_GPIO_D__GPIO_D		IOMUX_PAD(0x3fc, 0x200, 0x10, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_GPIO_E__LD16		IOMUX_PAD(0x400, 0x204, 0x02, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_GPIO_E__LD16		IOMUX_PAD(0x400, 0x204, 0x02, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_GPIO_D__CAN2_RX	IOMUX_PAD(0x3fc, 0x200, 0x16, 0x484, 1, PAD_CTL_PUS_22K_UP)
 
 #define MX25_PAD_GPIO_E__GPIO_E		IOMUX_PAD(0x400, 0x204, 0x10, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_GPIO_F__LD17		IOMUX_PAD(0x404, 0x208, 0x02, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_GPIO_F__LD17		IOMUX_PAD(0x404, 0x208, 0x02, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_GPIO_E__AUD7_TXD	IOMUX_PAD(0x400, 0x204, 0x14, 0, 0, NO_PAD_CTRL)
 
 #define MX25_PAD_GPIO_F__GPIO_F		IOMUX_PAD(0x404, 0x208, 0x10, 0, 0, NO_PAD_CTRL)
diff --git a/arch/arm/plat-mxc/include/mach/system.h b/arch/arm/plat-mxc/include/mach/system.h
deleted file mode 100644
index 13ad0df..0000000
--- a/arch/arm/plat-mxc/include/mach/system.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *  Copyright 2004-2008 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.
- */
-
-#ifndef __ASM_ARCH_MXC_SYSTEM_H__
-#define __ASM_ARCH_MXC_SYSTEM_H__
-
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
-#endif /* __ASM_ARCH_MXC_SYSTEM_H__ */
diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c
index e032717..c0cab22 100644
--- a/arch/arm/plat-mxc/pwm.c
+++ b/arch/arm/plat-mxc/pwm.c
@@ -132,7 +132,7 @@
 	int rc = 0;
 
 	if (!pwm->clk_enabled) {
-		rc = clk_enable(pwm->clk);
+		rc = clk_prepare_enable(pwm->clk);
 		if (!rc)
 			pwm->clk_enabled = 1;
 	}
@@ -145,7 +145,7 @@
 	writel(0, pwm->mmio_base + MX3_PWMCR);
 
 	if (pwm->clk_enabled) {
-		clk_disable(pwm->clk);
+		clk_disable_unprepare(pwm->clk);
 		pwm->clk_enabled = 0;
 	}
 }
diff --git a/arch/arm/plat-mxc/system.c b/arch/arm/plat-mxc/system.c
index 3599bf2..1996c3e 100644
--- a/arch/arm/plat-mxc/system.c
+++ b/arch/arm/plat-mxc/system.c
@@ -25,8 +25,8 @@
 
 #include <mach/hardware.h>
 #include <mach/common.h>
+#include <asm/system_misc.h>
 #include <asm/proc-fns.h>
-#include <asm/system.h>
 #include <asm/mach-types.h>
 
 void __iomem *(*imx_ioremap)(unsigned long, size_t, unsigned int) = NULL;
@@ -48,7 +48,7 @@
 
 		clk = clk_get_sys("imx2-wdt.0", NULL);
 		if (!IS_ERR(clk))
-			clk_enable(clk);
+			clk_prepare_enable(clk);
 		wcr_enable = (1 << 2);
 	}
 
diff --git a/arch/arm/plat-mxc/time.c b/arch/arm/plat-mxc/time.c
index 1c96cdb..7daf7c9 100644
--- a/arch/arm/plat-mxc/time.c
+++ b/arch/arm/plat-mxc/time.c
@@ -283,7 +283,7 @@
 {
 	uint32_t tctl_val;
 
-	clk_enable(timer_clk);
+	clk_prepare_enable(timer_clk);
 
 	timer_base = base;
 
diff --git a/arch/arm/plat-nomadik/Kconfig b/arch/arm/plat-nomadik/Kconfig
index bca4914..4c48c8b 100644
--- a/arch/arm/plat-nomadik/Kconfig
+++ b/arch/arm/plat-nomadik/Kconfig
@@ -23,7 +23,6 @@
 config NOMADIK_MTU_SCHED_CLOCK
 	bool
 	depends on HAS_MTU
-	select HAVE_SCHED_CLOCK
 	help
 	  Use the Multi Timer Unit as the sched_clock.
 
diff --git a/arch/arm/plat-nomadik/include/plat/mtu.h b/arch/arm/plat-nomadik/include/plat/mtu.h
index 6508e76..582641f 100644
--- a/arch/arm/plat-nomadik/include/plat/mtu.h
+++ b/arch/arm/plat-nomadik/include/plat/mtu.h
@@ -1,9 +1,7 @@
 #ifndef __PLAT_MTU_H
 #define __PLAT_MTU_H
 
-/* should be set by the platform code */
-extern void __iomem *mtu_base;
-
+void nmdk_timer_init(void __iomem *base);
 void nmdk_clkevt_reset(void);
 void nmdk_clksrc_reset(void);
 
diff --git a/arch/arm/plat-nomadik/include/plat/ste_dma40.h b/arch/arm/plat-nomadik/include/plat/ste_dma40.h
index fd0ee84..9ff93b0 100644
--- a/arch/arm/plat-nomadik/include/plat/ste_dma40.h
+++ b/arch/arm/plat-nomadik/include/plat/ste_dma40.h
@@ -200,8 +200,7 @@
 	sg.dma_address = addr;
 	sg.length = size;
 
-	return chan->device->device_prep_slave_sg(chan, &sg, 1,
-						  direction, flags);
+	return dmaengine_prep_slave_sg(chan, &sg, 1, direction, flags);
 }
 
 #else
diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c
index ad1b45b..9222e55 100644
--- a/arch/arm/plat-nomadik/timer.c
+++ b/arch/arm/plat-nomadik/timer.c
@@ -21,12 +21,6 @@
 #include <asm/sched_clock.h>
 
 /*
- * Guaranteed runtime conversion range in seconds for
- * the clocksource and clockevent.
- */
-#define MTU_MIN_RANGE 4
-
-/*
  * The MTU device hosts four different counters, with 4 set of
  * registers. These are register names.
  */
@@ -66,12 +60,11 @@
 #define MTU_PCELL2	0xff8
 #define MTU_PCELL3	0xffC
 
+static void __iomem *mtu_base;
 static bool clkevt_periodic;
 static u32 clk_prescale;
 static u32 nmdk_cycle;		/* write-once */
 
-void __iomem *mtu_base; /* Assigned by machine code */
-
 #ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK
 /*
  * Override the global weak sched_clock symbol with this
@@ -103,7 +96,6 @@
 void nmdk_clkevt_reset(void)
 {
 	if (clkevt_periodic) {
-
 		/* Timer: configure load and background-load, and fire it up */
 		writel(nmdk_cycle, mtu_base + MTU_LR(1));
 		writel(nmdk_cycle, mtu_base + MTU_BGLR(1));
@@ -121,7 +113,6 @@
 static void nmdk_clkevt_mode(enum clock_event_mode mode,
 			     struct clock_event_device *dev)
 {
-
 	switch (mode) {
 	case CLOCK_EVT_MODE_PERIODIC:
 		clkevt_periodic = true;
@@ -183,15 +174,16 @@
 	       mtu_base + MTU_CR(0));
 }
 
-void __init nmdk_timer_init(void)
+void __init nmdk_timer_init(void __iomem *base)
 {
 	unsigned long rate;
 	struct clk *clk0;
 
+	mtu_base = base;
 	clk0 = clk_get_sys("mtu0", NULL);
 	BUG_ON(IS_ERR(clk0));
-
-	clk_enable(clk0);
+	BUG_ON(clk_prepare(clk0) < 0);
+	BUG_ON(clk_enable(clk0) < 0);
 
 	/*
 	 * Tick rate is 2.4MHz for Nomadik and 2.4Mhz, 100MHz or 133 MHz
@@ -224,17 +216,8 @@
 	setup_sched_clock(nomadik_read_sched_clock, 32, rate);
 #endif
 
-	/* Timer 1 is used for events */
-
-	clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE);
-
-	nmdk_clkevt.max_delta_ns =
-		clockevent_delta2ns(0xffffffff, &nmdk_clkevt);
-	nmdk_clkevt.min_delta_ns =
-		clockevent_delta2ns(0x00000002, &nmdk_clkevt);
-	nmdk_clkevt.cpumask	= cpumask_of(0);
-
-	/* Register irq and clockevents */
+	/* Timer 1 is used for events, register irq and clockevents */
 	setup_irq(IRQ_MTU0, &nmdk_timer_irq);
-	clockevents_register_device(&nmdk_clkevt);
+	nmdk_clkevt.cpumask = cpumask_of(0);
+	clockevents_config_and_register(&nmdk_clkevt, rate, 2, 0xffffffffU);
 }
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index aa59f42..ad95c7a 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -14,8 +14,10 @@
 	select CLKDEV_LOOKUP
 	select CLKSRC_MMIO
 	select GENERIC_IRQ_CHIP
+	select IRQ_DOMAIN
 	select HAVE_IDE
 	select NEED_MACH_MEMORY_H
+	select NEED_MACH_IO_H if PCCARD
 	help
 	  "Systems based on omap7xx, omap15xx or omap16xx"
 
@@ -24,6 +26,8 @@
 	select CLKDEV_LOOKUP
 	select GENERIC_IRQ_CHIP
 	select OMAP_DM_TIMER
+	select USE_OF
+	select PROC_DEVICETREE if PROC_FS
 	help
 	  "Systems based on OMAP2, OMAP3 or OMAP4"
 
@@ -110,14 +114,6 @@
 	  to change the pin multiplexing setup.	 When there are no warnings
 	  printed, it's safe to deselect OMAP_MUX for your product.
 
-config OMAP_MCBSP
-	bool "McBSP support"
-	depends on ARCH_OMAP
-	default y
-	help
-	  Say Y here if you want support for the OMAP Multichannel
-	  Buffered Serial Port.
-
 config OMAP_MBOX_FWK
 	tristate "Mailbox framework support"
 	depends on ARCH_OMAP
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 9a58461..c0fe275 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -17,8 +17,6 @@
 obj-$(CONFIG_ARCH_OMAP3) += omap_device.o
 obj-$(CONFIG_ARCH_OMAP4) += omap_device.o
 
-obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
-
 obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
 obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o
 obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index 567e4b5..8506cbb 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -20,7 +20,6 @@
 #include <linux/clk.h>
 #include <linux/mutex.h>
 #include <linux/cpufreq.h>
-#include <linux/debugfs.h>
 #include <linux/io.h>
 
 #include <plat/clock.h>
@@ -442,6 +441,8 @@
 		return 0;
 
 	pr_info("clock: disabling unused clocks to save power\n");
+
+	spin_lock_irqsave(&clockfw_lock, flags);
 	list_for_each_entry(ck, &clocks, node) {
 		if (ck->ops == &clkops_null)
 			continue;
@@ -449,10 +450,9 @@
 		if (ck->usecount > 0 || !ck->enable_reg)
 			continue;
 
-		spin_lock_irqsave(&clockfw_lock, flags);
 		arch_clock->clk_disable_unused(ck);
-		spin_unlock_irqrestore(&clockfw_lock, flags);
 	}
+	spin_unlock_irqrestore(&clockfw_lock, flags);
 
 	return 0;
 }
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index 4de7d1e..f1e46ea 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -15,7 +15,6 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
-#include <linux/omapfb.h>
 
 #include <plat/common.h>
 #include <plat/board.h>
@@ -65,7 +64,6 @@
 
 void __init omap_reserve(void)
 {
-	omapfb_reserve_sdram_memblock();
 	omap_vram_reserve_sdram_memblock();
 	omap_dsp_reserve_sdram_memblock();
 	omap_secure_ram_reserve_memblock();
diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c
index 5f0f229..5068fe5 100644
--- a/arch/arm/plat-omap/counter_32k.c
+++ b/arch/arm/plat-omap/counter_32k.c
@@ -21,6 +21,7 @@
 
 #include <asm/sched_clock.h>
 
+#include <plat/hardware.h>
 #include <plat/common.h>
 #include <plat/board.h>
 
diff --git a/arch/arm/plat-omap/debug-leds.c b/arch/arm/plat-omap/debug-leds.c
index 61a1ec2..39407cb 100644
--- a/arch/arm/plat-omap/debug-leds.c
+++ b/arch/arm/plat-omap/debug-leds.c
@@ -15,7 +15,6 @@
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
-#include <asm/system.h>
 #include <asm/mach-types.h>
 
 #include <plat/fpga.h>
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 002fb4d..ecdb3da 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -36,7 +36,6 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 
-#include <asm/system.h>
 #include <mach/hardware.h>
 #include <plat/dma.h>
 
@@ -164,6 +163,8 @@
 }
 #else
 #define set_gdma_dev(req, dev)	do {} while (0)
+#define omap_readl(reg)		0
+#define omap_writel(val, reg)	do {} while (0)
 #endif
 
 void omap_set_dma_priority(int lch, int dst_port, int priority)
@@ -2125,7 +2126,7 @@
 
 static struct platform_driver omap_system_dma_driver = {
 	.probe		= omap_system_dma_probe,
-	.remove		= omap_system_dma_remove,
+	.remove		= __devexit_p(omap_system_dma_remove),
 	.driver		= {
 		.name	= "omap_dma_system"
 	},
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index af3b92b..652139c 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -43,6 +43,8 @@
 
 #include <plat/dmtimer.h>
 
+#include <mach/hardware.h>
+
 static LIST_HEAD(omap_timer_list);
 static DEFINE_SPINLOCK(dm_timer_lock);
 
@@ -80,9 +82,9 @@
 
 static void omap_timer_restore_context(struct omap_dm_timer *timer)
 {
-	omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET,
-				timer->context.tiocp_cfg);
-	if (timer->revision > 1)
+	__raw_writel(timer->context.tiocp_cfg,
+			timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
+	if (timer->revision == 1)
 		__raw_writel(timer->context.tistat, timer->sys_stat);
 
 	__raw_writel(timer->context.tisr, timer->irq_stat);
@@ -357,6 +359,19 @@
 
 	__omap_dm_timer_stop(timer, timer->posted, rate);
 
+	if (timer->loses_context && timer->get_context_loss_count)
+		timer->ctx_loss_count =
+			timer->get_context_loss_count(&timer->pdev->dev);
+
+	/*
+	 * Since the register values are computed and written within
+	 * __omap_dm_timer_stop, we need to use read to retrieve the
+	 * context.
+	 */
+	timer->context.tclr =
+			omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+	timer->context.tisr = __raw_readl(timer->irq_stat);
+	omap_dm_timer_disable(timer);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c
index c9e5d72..dd6f92c 100644
--- a/arch/arm/plat-omap/fb.c
+++ b/arch/arm/plat-omap/fb.c
@@ -34,15 +34,11 @@
 #include <asm/mach/map.h>
 
 #include <plat/board.h>
-#include <plat/sram.h>
-
-#include "fb.h"
 
 #if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
 
+static bool omapfb_lcd_configured;
 static struct omapfb_platform_data omapfb_config;
-static int config_invalid;
-static int configured_regions;
 
 static u64 omap_fb_dma_mask = ~(u32)0;
 
@@ -57,301 +53,20 @@
 	.num_resources = 0,
 };
 
-void omapfb_set_platform_data(struct omapfb_platform_data *data)
+void __init omapfb_set_lcd_config(const struct omap_lcd_config *config)
 {
-}
-
-static inline int ranges_overlap(unsigned long start1, unsigned long size1,
-				 unsigned long start2, unsigned long size2)
-{
-	return (start1 >= start2 && start1 < start2 + size2) ||
-	       (start2 >= start1 && start2 < start1 + size1);
-}
-
-static inline int range_included(unsigned long start1, unsigned long size1,
-				 unsigned long start2, unsigned long size2)
-{
-	return start1 >= start2 && start1 + size1 <= start2 + size2;
-}
-
-
-/* Check if there is an overlapping region. */
-static int fbmem_region_reserved(unsigned long start, size_t size)
-{
-	struct omapfb_mem_region *rg;
-	int i;
-
-	rg = &omapfb_config.mem_desc.region[0];
-	for (i = 0; i < OMAPFB_PLANE_NUM; i++, rg++) {
-		if (!rg->paddr)
-			/* Empty slot. */
-			continue;
-		if (ranges_overlap(start, size, rg->paddr, rg->size))
-			return 1;
-	}
-	return 0;
-}
-
-/*
- * Get the region_idx`th region from board config/ATAG and convert it to
- * our internal format.
- */
-static int __init get_fbmem_region(int region_idx, struct omapfb_mem_region *rg)
-{
-	const struct omap_fbmem_config	*conf;
-	u32				paddr;
-
-	conf = omap_get_nr_config(OMAP_TAG_FBMEM,
-				  struct omap_fbmem_config, region_idx);
-	if (conf == NULL)
-		return -ENOENT;
-
-	paddr = conf->start;
-	/*
-	 * Low bits encode the page allocation mode, if high bits
-	 * are zero. Otherwise we need a page aligned fixed
-	 * address.
-	 */
-	memset(rg, 0, sizeof(*rg));
-	rg->type = paddr & ~PAGE_MASK;
-	rg->paddr = paddr & PAGE_MASK;
-	rg->size = PAGE_ALIGN(conf->size);
-	return 0;
-}
-
-static int set_fbmem_region_type(struct omapfb_mem_region *rg, int mem_type,
-				  unsigned long mem_start,
-				  unsigned long mem_size)
-{
-	/*
-	 * Check if the configuration specifies the type explicitly.
-	 * type = 0 && paddr = 0, a default don't care case maps to
-	 * the SDRAM type.
-	 */
-	if (rg->type || !rg->paddr)
-		return 0;
-	if (ranges_overlap(rg->paddr, rg->size, mem_start, mem_size)) {
-		rg->type = mem_type;
-		return 0;
-	}
-	/* Can't determine it. */
-	return -1;
-}
-
-static int check_fbmem_region(int region_idx, struct omapfb_mem_region *rg,
-			      unsigned long start_avail, unsigned size_avail)
-{
-	unsigned long	paddr = rg->paddr;
-	size_t		size = rg->size;
-
-	if (rg->type > OMAPFB_MEMTYPE_MAX) {
-		printk(KERN_ERR
-			"Invalid start address for FB region %d\n", region_idx);
-		return -EINVAL;
-	}
-
-	if (!rg->size) {
-		printk(KERN_ERR "Zero size for FB region %d\n", region_idx);
-		return -EINVAL;
-	}
-
-	if (!paddr)
-		/* Allocate this dynamically, leave paddr 0 for now. */
-		return 0;
-
-	/*
-	 * Fixed region for the given RAM range. Check if it's already
-	 * reserved by the FB code or someone else.
-	 */
-	if (fbmem_region_reserved(paddr, size) ||
-	    !range_included(paddr, size, start_avail, size_avail)) {
-		printk(KERN_ERR "Trying to use reserved memory "
-			"for FB region %d\n", region_idx);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int valid_sdram(unsigned long addr, unsigned long size)
-{
-	return memblock_is_region_memory(addr, size);
-}
-
-static int reserve_sdram(unsigned long addr, unsigned long size)
-{
-	if (memblock_is_region_reserved(addr, size))
-		return -EBUSY;
-	if (memblock_reserve(addr, size))
-		return -ENOMEM;
-	return 0;
-}
-
-/*
- * Called from map_io. We need to call to this early enough so that we
- * can reserve the fixed SDRAM regions before VM could get hold of them.
- */
-void __init omapfb_reserve_sdram_memblock(void)
-{
-	unsigned long reserved = 0;
-	int i;
-
-	if (config_invalid)
-		return;
-
-	for (i = 0; ; i++) {
-		struct omapfb_mem_region rg;
-
-		if (get_fbmem_region(i, &rg) < 0)
-			break;
-
-		if (i == OMAPFB_PLANE_NUM) {
-			pr_err("Extraneous FB mem configuration entries\n");
-			config_invalid = 1;
-			return;
-		}
-
-		/* Check if it's our memory type. */
-		if (rg.type != OMAPFB_MEMTYPE_SDRAM)
-			continue;
-
-		/* Check if the region falls within SDRAM */
-		if (rg.paddr && !valid_sdram(rg.paddr, rg.size))
-			continue;
-
-		if (rg.size == 0) {
-			pr_err("Zero size for FB region %d\n", i);
-			config_invalid = 1;
-			return;
-		}
-
-		if (rg.paddr) {
-			if (reserve_sdram(rg.paddr, rg.size)) {
-				pr_err("Trying to use reserved memory for FB region %d\n",
-					i);
-				config_invalid = 1;
-				return;
-			}
-			reserved += rg.size;
-		}
-
-		if (omapfb_config.mem_desc.region[i].size) {
-			pr_err("FB region %d already set\n", i);
-			config_invalid = 1;
-			return;
-		}
-
-		omapfb_config.mem_desc.region[i] = rg;
-		configured_regions++;
-	}
-	omapfb_config.mem_desc.region_cnt = i;
-	if (reserved)
-		pr_info("Reserving %lu bytes SDRAM for frame buffer\n",
-			 reserved);
-}
-
-/*
- * Called at sram init time, before anything is pushed to the SRAM stack.
- * Because of the stack scheme, we will allocate everything from the
- * start of the lowest address region to the end of SRAM. This will also
- * include padding for page alignment and possible holes between regions.
- *
- * As opposed to the SDRAM case, we'll also do any dynamic allocations at
- * this point, since the driver built as a module would have problem with
- * freeing / reallocating the regions.
- */
-unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart,
-				  unsigned long sram_vstart,
-				  unsigned long sram_size,
-				  unsigned long pstart_avail,
-				  unsigned long size_avail)
-{
-	struct omapfb_mem_region	rg;
-	unsigned long			pend_avail;
-	unsigned long			reserved;
-	int				i;
-
-	if (config_invalid)
-		return 0;
-
-	reserved = 0;
-	pend_avail = pstart_avail + size_avail;
-	for (i = 0; ; i++) {
-		if (get_fbmem_region(i, &rg) < 0)
-			break;
-		if (i == OMAPFB_PLANE_NUM) {
-			printk(KERN_ERR
-				"Extraneous FB mem configuration entries\n");
-			config_invalid = 1;
-			return 0;
-		}
-
-		/* Check if it's our memory type. */
-		if (set_fbmem_region_type(&rg, OMAPFB_MEMTYPE_SRAM,
-				          sram_pstart, sram_size) < 0 ||
-		    (rg.type != OMAPFB_MEMTYPE_SRAM))
-			continue;
-		BUG_ON(omapfb_config.mem_desc.region[i].size);
-
-		if (check_fbmem_region(i, &rg, pstart_avail, size_avail) < 0) {
-			config_invalid = 1;
-			return 0;
-		}
-
-		if (!rg.paddr) {
-			/* Dynamic allocation */
-			if ((size_avail & PAGE_MASK) < rg.size) {
-				printk("Not enough SRAM for FB region %d\n",
-					i);
-				config_invalid = 1;
-				return 0;
-			}
-			size_avail = (size_avail - rg.size) & PAGE_MASK;
-			rg.paddr = pstart_avail + size_avail;
-		}
-		/* Reserve everything above the start of the region. */
-		if (pend_avail - rg.paddr > reserved)
-			reserved = pend_avail - rg.paddr;
-		size_avail = pend_avail - reserved - pstart_avail;
-
-		/*
-		 * We have a kernel mapping for this already, so the
-		 * driver won't have to make one.
-		 */
-		rg.vaddr = (void *)(sram_vstart + rg.paddr - sram_pstart);
-		omapfb_config.mem_desc.region[i] = rg;
-		configured_regions++;
-	}
-	omapfb_config.mem_desc.region_cnt = i;
-	if (reserved)
-		pr_info("Reserving %lu bytes SRAM for frame buffer\n",
-			 reserved);
-	return reserved;
-}
-
-void omapfb_set_ctrl_platform_data(void *data)
-{
-	omapfb_config.ctrl_platform_data = data;
+	omapfb_config.lcd = *config;
+	omapfb_lcd_configured = true;
 }
 
 static int __init omap_init_fb(void)
 {
-	const struct omap_lcd_config *conf;
-
-	if (config_invalid)
+	/*
+	 * If the board file has not set the lcd config with
+	 * omapfb_set_lcd_config(), don't bother registering the omapfb device
+	 */
+	if (!omapfb_lcd_configured)
 		return 0;
-	if (configured_regions != omapfb_config.mem_desc.region_cnt) {
-		printk(KERN_ERR "Invalid FB mem configuration entries\n");
-		return 0;
-	}
-	conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
-	if (conf == NULL) {
-		if (configured_regions)
-			/* FB mem config, but no LCD config? */
-			printk(KERN_ERR "Missing LCD configuration\n");
-		return 0;
-	}
-	omapfb_config.lcd = *conf;
 
 	return platform_device_register(&omap_fb_device);
 }
@@ -374,11 +89,6 @@
 	.num_resources = 0,
 };
 
-void omapfb_set_platform_data(struct omapfb_platform_data *data)
-{
-	omapfb_config = *data;
-}
-
 static int __init omap_init_fb(void)
 {
 	return platform_device_register(&omap_fb_device);
@@ -386,36 +96,10 @@
 
 arch_initcall(omap_init_fb);
 
-void omapfb_reserve_sdram_memblock(void)
-{
-}
-
-unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart,
-				  unsigned long sram_vstart,
-				  unsigned long sram_size,
-				  unsigned long start_avail,
-				  unsigned long size_avail)
-{
-	return 0;
-}
-
 #else
 
-void omapfb_set_platform_data(struct omapfb_platform_data *data)
+void __init omapfb_set_lcd_config(const struct omap_lcd_config *config)
 {
 }
 
-void omapfb_reserve_sdram_memblock(void)
-{
-}
-
-unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart,
-				  unsigned long sram_vstart,
-				  unsigned long sram_size,
-				  unsigned long start_avail,
-				  unsigned long size_avail)
-{
-	return 0;
-}
-
 #endif
diff --git a/arch/arm/plat-omap/fb.h b/arch/arm/plat-omap/fb.h
deleted file mode 100644
index d765d0b..0000000
--- a/arch/arm/plat-omap/fb.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __PLAT_OMAP_FB_H__
-#define __PLAT_OMAP_FB_H__
-
-extern unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
-					 unsigned long sram_vstart,
-					 unsigned long sram_size,
-					 unsigned long pstart_avail,
-					 unsigned long size_avail);
-
-#endif /* __PLAT_OMAP_FB_H__ */
diff --git a/arch/arm/plat-omap/include/plat/blizzard.h b/arch/arm/plat-omap/include/plat/blizzard.h
deleted file mode 100644
index 56e7f2e..0000000
--- a/arch/arm/plat-omap/include/plat/blizzard.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _BLIZZARD_H
-#define _BLIZZARD_H
-
-struct blizzard_platform_data {
-	void		(*power_up)(struct device *dev);
-	void		(*power_down)(struct device *dev);
-	unsigned long	(*get_clock_rate)(struct device *dev);
-
-	unsigned	te_connected:1;
-};
-
-#endif
diff --git a/arch/arm/plat-omap/include/plat/board-ams-delta.h b/arch/arm/plat-omap/include/plat/board-ams-delta.h
index 51b102d..ad6f865 100644
--- a/arch/arm/plat-omap/include/plat/board-ams-delta.h
+++ b/arch/arm/plat-omap/include/plat/board-ams-delta.h
@@ -28,33 +28,8 @@
 
 #if defined (CONFIG_MACH_AMS_DELTA)
 
-#define AMS_DELTA_LATCH1_PHYS		0x01000000
-#define AMS_DELTA_LATCH1_VIRT		0xEA000000
-#define AMS_DELTA_MODEM_PHYS		0x04000000
-#define AMS_DELTA_MODEM_VIRT		0xEB000000
-#define AMS_DELTA_LATCH2_PHYS		0x08000000
-#define AMS_DELTA_LATCH2_VIRT		0xEC000000
-
-#define AMS_DELTA_LATCH1_LED_CAMERA	0x01
-#define AMS_DELTA_LATCH1_LED_ADVERT	0x02
-#define AMS_DELTA_LATCH1_LED_EMAIL	0x04
-#define AMS_DELTA_LATCH1_LED_HANDSFREE	0x08
-#define AMS_DELTA_LATCH1_LED_VOICEMAIL	0x10
-#define AMS_DELTA_LATCH1_LED_VOICE	0x20
-
-#define AMS_DELTA_LATCH2_LCD_VBLEN	0x0001
-#define AMS_DELTA_LATCH2_LCD_NDISP	0x0002
-#define AMS_DELTA_LATCH2_NAND_NCE	0x0004
-#define AMS_DELTA_LATCH2_NAND_NRE	0x0008
-#define AMS_DELTA_LATCH2_NAND_NWP	0x0010
-#define AMS_DELTA_LATCH2_NAND_NWE	0x0020
-#define AMS_DELTA_LATCH2_NAND_ALE	0x0040
-#define AMS_DELTA_LATCH2_NAND_CLE	0x0080
-#define AMD_DELTA_LATCH2_KEYBRD_PWR	0x0100
-#define AMD_DELTA_LATCH2_KEYBRD_DATA	0x0200
 #define AMD_DELTA_LATCH2_SCARD_RSTIN	0x0400
 #define AMD_DELTA_LATCH2_SCARD_CMDVCC	0x0800
-#define AMS_DELTA_LATCH2_MODEM_NRESET	0x1000
 #define AMS_DELTA_LATCH2_MODEM_CODEC	0x2000
 
 #define AMS_DELTA_GPIO_PIN_KEYBRD_DATA	0
@@ -66,9 +41,29 @@
 #define AMS_DELTA_GPIO_PIN_CONFIG	11
 #define AMS_DELTA_GPIO_PIN_NAND_RB	12
 
+#define AMS_DELTA_GPIO_PIN_LCD_VBLEN		240
+#define AMS_DELTA_GPIO_PIN_LCD_NDISP		241
+#define AMS_DELTA_GPIO_PIN_NAND_NCE		242
+#define AMS_DELTA_GPIO_PIN_NAND_NRE		243
+#define AMS_DELTA_GPIO_PIN_NAND_NWP		244
+#define AMS_DELTA_GPIO_PIN_NAND_NWE		245
+#define AMS_DELTA_GPIO_PIN_NAND_ALE		246
+#define AMS_DELTA_GPIO_PIN_NAND_CLE		247
+#define AMS_DELTA_GPIO_PIN_KEYBRD_PWR		248
+#define AMS_DELTA_GPIO_PIN_KEYBRD_DATAOUT	249
+#define AMS_DELTA_GPIO_PIN_SCARD_RSTIN		250
+#define AMS_DELTA_GPIO_PIN_SCARD_CMDVCC		251
+#define AMS_DELTA_GPIO_PIN_MODEM_NRESET		252
+#define AMS_DELTA_GPIO_PIN_MODEM_CODEC		253
+
+#define AMS_DELTA_LATCH2_GPIO_BASE	AMS_DELTA_GPIO_PIN_LCD_VBLEN
+#define AMS_DELTA_LATCH2_NGPIO		16
+
 #ifndef __ASSEMBLY__
-void ams_delta_latch1_write(u8 mask, u8 value);
-void ams_delta_latch2_write(u16 mask, u16 value);
+void ams_delta_latch_write(int base, int ngpio, u16 mask, u16 value);
+#define ams_delta_latch2_write(mask, value) \
+	ams_delta_latch_write(AMS_DELTA_LATCH2_GPIO_BASE, \
+			AMS_DELTA_LATCH2_NGPIO, (mask), (value))
 #endif
 
 #endif /* CONFIG_MACH_AMS_DELTA */
diff --git a/arch/arm/plat-omap/include/plat/board.h b/arch/arm/plat-omap/include/plat/board.h
index 97126df..d5eb4c8 100644
--- a/arch/arm/plat-omap/include/plat/board.h
+++ b/arch/arm/plat-omap/include/plat/board.h
@@ -28,9 +28,7 @@
 
 /* Different peripheral ids */
 #define OMAP_TAG_CLOCK		0x4f01
-#define OMAP_TAG_LCD		0x4f05
 #define OMAP_TAG_GPIO_SWITCH	0x4f06
-#define OMAP_TAG_FBMEM		0x4f08
 #define OMAP_TAG_STI_CONSOLE	0x4f09
 #define OMAP_TAG_CAMERA_SENSOR	0x4f0a
 
diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h
index 6b51086..dc6a86b 100644
--- a/arch/arm/plat-omap/include/plat/cpu.h
+++ b/arch/arm/plat-omap/include/plat/cpu.h
@@ -250,7 +250,6 @@
  * cpu_is_omap2423():	True for OMAP2423
  * cpu_is_omap2430():	True for OMAP2430
  * cpu_is_omap3430():	True for OMAP3430
- * cpu_is_omap4430():	True for OMAP4430
  * cpu_is_omap3505():	True for OMAP3505
  * cpu_is_omap3517():	True for OMAP3517
  */
@@ -299,7 +298,6 @@
 #define cpu_is_omap3505()		0
 #define cpu_is_omap3517()		0
 #define cpu_is_omap3430()		0
-#define cpu_is_omap4430()		0
 #define cpu_is_omap3630()		0
 
 /*
@@ -451,7 +449,12 @@
 #define OMAP447X_CLASS		0x44700044
 #define OMAP4470_REV_ES1_0	(OMAP447X_CLASS | (0x10 << 8))
 
-void omap2_check_revision(void);
+void omap2xxx_check_revision(void);
+void omap3xxx_check_revision(void);
+void omap4xxx_check_revision(void);
+void omap3xxx_check_features(void);
+void ti81xx_check_features(void);
+void omap4xxx_check_features(void);
 
 /*
  * Runtime detection of OMAP3 features
diff --git a/arch/arm/plat-omap/include/plat/gpio.h b/arch/arm/plat-omap/include/plat/gpio.h
index 9e86ee0..2f6e992 100644
--- a/arch/arm/plat-omap/include/plat/gpio.h
+++ b/arch/arm/plat-omap/include/plat/gpio.h
@@ -158,17 +158,6 @@
 #define OMAP_MPUIO(nr)		(OMAP_MAX_GPIO_LINES + (nr))
 #define OMAP_GPIO_IS_MPUIO(nr)	((nr) >= OMAP_MAX_GPIO_LINES)
 
-#define OMAP_GPIO_IRQ(nr)	(OMAP_GPIO_IS_MPUIO(nr) ? \
-				 IH_MPUIO_BASE + ((nr) & 0x0f) : \
-				 IH_GPIO_BASE + (nr))
-
-#define METHOD_MPUIO		0
-#define METHOD_GPIO_1510	1
-#define METHOD_GPIO_1610	2
-#define METHOD_GPIO_7XX		3
-#define METHOD_GPIO_24XX	5
-#define METHOD_GPIO_44XX	6
-
 struct omap_gpio_dev_attr {
 	int bank_width;		/* GPIO bank width */
 	bool dbck_flag;		/* dbck required or not - True for OMAP3&4 */
@@ -184,10 +173,21 @@
 	u16 irqstatus;
 	u16 irqstatus2;
 	u16 irqenable;
+	u16 irqenable2;
 	u16 set_irqenable;
 	u16 clr_irqenable;
 	u16 debounce;
 	u16 debounce_en;
+	u16 ctrl;
+	u16 wkup_en;
+	u16 leveldetect0;
+	u16 leveldetect1;
+	u16 risingdetect;
+	u16 fallingdetect;
+	u16 irqctrl;
+	u16 edgectrl1;
+	u16 edgectrl2;
+	u16 pinctrl;
 
 	bool irqenable_inv;
 };
@@ -198,45 +198,30 @@
 	int bank_width;		/* GPIO bank width */
 	int bank_stride;	/* Only needed for omap1 MPUIO */
 	bool dbck_flag;		/* dbck required or not - True for OMAP3&4 */
+	bool loses_context;	/* whether the bank would ever lose context */
+	bool is_mpuio;		/* whether the bank is of type MPUIO */
+	u32 non_wakeup_gpios;
 
 	struct omap_gpio_reg_offs *regs;
-};
 
-/* TODO: Analyze removing gpio_bank_count usage from driver code */
-extern int gpio_bank_count;
+	/* Return context loss count due to PM states changing */
+	int (*get_context_loss_count)(struct device *dev);
+};
 
 extern void omap2_gpio_prepare_for_idle(int off_mode);
 extern void omap2_gpio_resume_after_idle(void);
 extern void omap_set_gpio_debounce(int gpio, int enable);
 extern void omap_set_gpio_debounce_time(int gpio, int enable);
-extern void omap_gpio_save_context(void);
-extern void omap_gpio_restore_context(void);
 /*-------------------------------------------------------------------------*/
 
-/* Wrappers for "new style" GPIO calls, using the new infrastructure
+/*
+ * Wrappers for "new style" GPIO calls, using the new infrastructure
  * which lets us plug in FPGA, I2C, and other implementations.
- * *
+ *
  * The original OMAP-specific calls should eventually be removed.
  */
 
 #include <linux/errno.h>
 #include <asm-generic/gpio.h>
 
-static inline int irq_to_gpio(unsigned irq)
-{
-	int tmp;
-
-	/* omap1 SOC mpuio */
-	if (cpu_class_is_omap1() && (irq < (IH_MPUIO_BASE + 16)))
-		return (irq - IH_MPUIO_BASE) + OMAP_MAX_GPIO_LINES;
-
-	/* SOC gpio */
-	tmp = irq - IH_GPIO_BASE;
-	if (tmp < OMAP_MAX_GPIO_LINES)
-		return tmp;
-
-	/* we don't supply reverse mappings for non-SOC gpios */
-	return -EIO;
-}
-
 #endif
diff --git a/arch/arm/plat-omap/include/plat/hwa742.h b/arch/arm/plat-omap/include/plat/hwa742.h
deleted file mode 100644
index 886248d..0000000
--- a/arch/arm/plat-omap/include/plat/hwa742.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _HWA742_H
-#define _HWA742_H
-
-struct hwa742_platform_data {
-	unsigned	te_connected:1;
-};
-
-#endif
diff --git a/arch/arm/plat-omap/include/plat/io.h b/arch/arm/plat-omap/include/plat/io.h
deleted file mode 100644
index 0696bae..0000000
--- a/arch/arm/plat-omap/include/plat/io.h
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * arch/arm/plat-omap/include/mach/io.h
- *
- * IO definitions for TI OMAP processors and boards
- *
- * Copied from arch/arm/mach-sa1100/include/mach/io.h
- * Copyright (C) 1997-1999 Russell King
- *
- * Copyright (C) 2009 Texas Instruments
- * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.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 SOFTWARE IS PROVIDED ``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 AUTHOR 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, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Modifications:
- *  06-12-1997	RMK	Created.
- *  07-04-1999	RMK	Major cleanup
- */
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#include <mach/hardware.h>
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-/*
- * We don't actually have real ISA nor PCI buses, but there is so many
- * drivers out there that might just work if we fake them...
- */
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-/*
- * ----------------------------------------------------------------------------
- * I/O mapping
- * ----------------------------------------------------------------------------
- */
-
-#ifdef __ASSEMBLER__
-#define IOMEM(x)		(x)
-#else
-#define IOMEM(x)		((void __force __iomem *)(x))
-#endif
-
-#define OMAP1_IO_OFFSET		0x01000000	/* Virtual IO = 0xfefb0000 */
-#define OMAP1_IO_ADDRESS(pa)	IOMEM((pa) - OMAP1_IO_OFFSET)
-
-#define OMAP2_L3_IO_OFFSET	0x90000000
-#define OMAP2_L3_IO_ADDRESS(pa)	IOMEM((pa) + OMAP2_L3_IO_OFFSET) /* L3 */
-
-
-#define OMAP2_L4_IO_OFFSET	0xb2000000
-#define OMAP2_L4_IO_ADDRESS(pa)	IOMEM((pa) + OMAP2_L4_IO_OFFSET) /* L4 */
-
-#define OMAP4_L3_IO_OFFSET	0xb4000000
-#define OMAP4_L3_IO_ADDRESS(pa)	IOMEM((pa) + OMAP4_L3_IO_OFFSET) /* L3 */
-
-#define AM33XX_L4_WK_IO_OFFSET	0xb5000000
-#define AM33XX_L4_WK_IO_ADDRESS(pa)	IOMEM((pa) + AM33XX_L4_WK_IO_OFFSET)
-
-#define OMAP4_L3_PER_IO_OFFSET	0xb1100000
-#define OMAP4_L3_PER_IO_ADDRESS(pa)	IOMEM((pa) + OMAP4_L3_PER_IO_OFFSET)
-
-#define OMAP4_GPMC_IO_OFFSET		0xa9000000
-#define OMAP4_GPMC_IO_ADDRESS(pa)	IOMEM((pa) + OMAP4_GPMC_IO_OFFSET)
-
-#define OMAP2_EMU_IO_OFFSET		0xaa800000	/* Emulation */
-#define OMAP2_EMU_IO_ADDRESS(pa)	IOMEM((pa) + OMAP2_EMU_IO_OFFSET)
-
-/*
- * ----------------------------------------------------------------------------
- * Omap1 specific IO mapping
- * ----------------------------------------------------------------------------
- */
-
-#define OMAP1_IO_PHYS		0xFFFB0000
-#define OMAP1_IO_SIZE		0x40000
-#define OMAP1_IO_VIRT		(OMAP1_IO_PHYS - OMAP1_IO_OFFSET)
-
-/*
- * ----------------------------------------------------------------------------
- * Omap2 specific IO mapping
- * ----------------------------------------------------------------------------
- */
-
-/* We map both L3 and L4 on OMAP2 */
-#define L3_24XX_PHYS	L3_24XX_BASE	/* 0x68000000 --> 0xf8000000*/
-#define L3_24XX_VIRT	(L3_24XX_PHYS + OMAP2_L3_IO_OFFSET)
-#define L3_24XX_SIZE	SZ_1M		/* 44kB of 128MB used, want 1MB sect */
-#define L4_24XX_PHYS	L4_24XX_BASE	/* 0x48000000 --> 0xfa000000 */
-#define L4_24XX_VIRT	(L4_24XX_PHYS + OMAP2_L4_IO_OFFSET)
-#define L4_24XX_SIZE	SZ_1M		/* 1MB of 128MB used, want 1MB sect */
-
-#define L4_WK_243X_PHYS		L4_WK_243X_BASE	/* 0x49000000 --> 0xfb000000 */
-#define L4_WK_243X_VIRT		(L4_WK_243X_PHYS + OMAP2_L4_IO_OFFSET)
-#define L4_WK_243X_SIZE		SZ_1M
-#define OMAP243X_GPMC_PHYS	OMAP243X_GPMC_BASE
-#define OMAP243X_GPMC_VIRT	(OMAP243X_GPMC_PHYS + OMAP2_L3_IO_OFFSET)
-						/* 0x6e000000 --> 0xfe000000 */
-#define OMAP243X_GPMC_SIZE	SZ_1M
-#define OMAP243X_SDRC_PHYS	OMAP243X_SDRC_BASE
-						/* 0x6D000000 --> 0xfd000000 */
-#define OMAP243X_SDRC_VIRT	(OMAP243X_SDRC_PHYS + OMAP2_L3_IO_OFFSET)
-#define OMAP243X_SDRC_SIZE	SZ_1M
-#define OMAP243X_SMS_PHYS	OMAP243X_SMS_BASE
-						/* 0x6c000000 --> 0xfc000000 */
-#define OMAP243X_SMS_VIRT	(OMAP243X_SMS_PHYS + OMAP2_L3_IO_OFFSET)
-#define OMAP243X_SMS_SIZE	SZ_1M
-
-/* 2420 IVA */
-#define DSP_MEM_2420_PHYS	OMAP2420_DSP_MEM_BASE
-						/* 0x58000000 --> 0xfc100000 */
-#define DSP_MEM_2420_VIRT	0xfc100000
-#define DSP_MEM_2420_SIZE	0x28000
-#define DSP_IPI_2420_PHYS	OMAP2420_DSP_IPI_BASE
-						/* 0x59000000 --> 0xfc128000 */
-#define DSP_IPI_2420_VIRT	0xfc128000
-#define DSP_IPI_2420_SIZE	SZ_4K
-#define DSP_MMU_2420_PHYS	OMAP2420_DSP_MMU_BASE
-						/* 0x5a000000 --> 0xfc129000 */
-#define DSP_MMU_2420_VIRT	0xfc129000
-#define DSP_MMU_2420_SIZE	SZ_4K
-
-/* 2430 IVA2.1 - currently unmapped */
-
-/*
- * ----------------------------------------------------------------------------
- * Omap3 specific IO mapping
- * ----------------------------------------------------------------------------
- */
-
-/* We map both L3 and L4 on OMAP3 */
-#define L3_34XX_PHYS		L3_34XX_BASE	/* 0x68000000 --> 0xf8000000 */
-#define L3_34XX_VIRT		(L3_34XX_PHYS + OMAP2_L3_IO_OFFSET)
-#define L3_34XX_SIZE		SZ_1M   /* 44kB of 128MB used, want 1MB sect */
-
-#define L4_34XX_PHYS		L4_34XX_BASE	/* 0x48000000 --> 0xfa000000 */
-#define L4_34XX_VIRT		(L4_34XX_PHYS + OMAP2_L4_IO_OFFSET)
-#define L4_34XX_SIZE		SZ_4M   /* 1MB of 128MB used, want 1MB sect */
-
-/*
- * ----------------------------------------------------------------------------
- * AM33XX specific IO mapping
- * ----------------------------------------------------------------------------
- */
-#define L4_WK_AM33XX_PHYS	L4_WK_AM33XX_BASE
-#define L4_WK_AM33XX_VIRT	(L4_WK_AM33XX_PHYS + AM33XX_L4_WK_IO_OFFSET)
-#define L4_WK_AM33XX_SIZE	SZ_4M   /* 1MB of 128MB used, want 1MB sect */
-
-/*
- * Need to look at the Size 4M for L4.
- * VPOM3430 was not working for Int controller
- */
-
-#define L4_PER_34XX_PHYS	L4_PER_34XX_BASE
-						/* 0x49000000 --> 0xfb000000 */
-#define L4_PER_34XX_VIRT	(L4_PER_34XX_PHYS + OMAP2_L4_IO_OFFSET)
-#define L4_PER_34XX_SIZE	SZ_1M
-
-#define L4_EMU_34XX_PHYS	L4_EMU_34XX_BASE
-						/* 0x54000000 --> 0xfe800000 */
-#define L4_EMU_34XX_VIRT	(L4_EMU_34XX_PHYS + OMAP2_EMU_IO_OFFSET)
-#define L4_EMU_34XX_SIZE	SZ_8M
-
-#define OMAP34XX_GPMC_PHYS	OMAP34XX_GPMC_BASE
-						/* 0x6e000000 --> 0xfe000000 */
-#define OMAP34XX_GPMC_VIRT	(OMAP34XX_GPMC_PHYS + OMAP2_L3_IO_OFFSET)
-#define OMAP34XX_GPMC_SIZE	SZ_1M
-
-#define OMAP343X_SMS_PHYS	OMAP343X_SMS_BASE
-						/* 0x6c000000 --> 0xfc000000 */
-#define OMAP343X_SMS_VIRT	(OMAP343X_SMS_PHYS + OMAP2_L3_IO_OFFSET)
-#define OMAP343X_SMS_SIZE	SZ_1M
-
-#define OMAP343X_SDRC_PHYS	OMAP343X_SDRC_BASE
-						/* 0x6D000000 --> 0xfd000000 */
-#define OMAP343X_SDRC_VIRT	(OMAP343X_SDRC_PHYS + OMAP2_L3_IO_OFFSET)
-#define OMAP343X_SDRC_SIZE	SZ_1M
-
-/* 3430 IVA - currently unmapped */
-
-/*
- * ----------------------------------------------------------------------------
- * Omap4 specific IO mapping
- * ----------------------------------------------------------------------------
- */
-
-/* We map both L3 and L4 on OMAP4 */
-#define L3_44XX_PHYS		L3_44XX_BASE	/* 0x44000000 --> 0xf8000000 */
-#define L3_44XX_VIRT		(L3_44XX_PHYS + OMAP4_L3_IO_OFFSET)
-#define L3_44XX_SIZE		SZ_1M
-
-#define L4_44XX_PHYS		L4_44XX_BASE	/* 0x4a000000 --> 0xfc000000 */
-#define L4_44XX_VIRT		(L4_44XX_PHYS + OMAP2_L4_IO_OFFSET)
-#define L4_44XX_SIZE		SZ_4M
-
-#define L4_PER_44XX_PHYS	L4_PER_44XX_BASE
-						/* 0x48000000 --> 0xfa000000 */
-#define L4_PER_44XX_VIRT	(L4_PER_44XX_PHYS + OMAP2_L4_IO_OFFSET)
-#define L4_PER_44XX_SIZE	SZ_4M
-
-#define L4_ABE_44XX_PHYS	L4_ABE_44XX_BASE
-						/* 0x49000000 --> 0xfb000000 */
-#define L4_ABE_44XX_VIRT	(L4_ABE_44XX_PHYS + OMAP2_L4_IO_OFFSET)
-#define L4_ABE_44XX_SIZE	SZ_1M
-
-#define L4_EMU_44XX_PHYS	L4_EMU_44XX_BASE
-						/* 0x54000000 --> 0xfe800000 */
-#define L4_EMU_44XX_VIRT	(L4_EMU_44XX_PHYS + OMAP2_EMU_IO_OFFSET)
-#define L4_EMU_44XX_SIZE	SZ_8M
-
-#define OMAP44XX_GPMC_PHYS	OMAP44XX_GPMC_BASE
-						/* 0x50000000 --> 0xf9000000 */
-#define OMAP44XX_GPMC_VIRT	(OMAP44XX_GPMC_PHYS + OMAP4_GPMC_IO_OFFSET)
-#define OMAP44XX_GPMC_SIZE	SZ_1M
-
-
-#define OMAP44XX_EMIF1_PHYS	OMAP44XX_EMIF1_BASE
-						/* 0x4c000000 --> 0xfd100000 */
-#define OMAP44XX_EMIF1_VIRT	(OMAP44XX_EMIF1_PHYS + OMAP4_L3_PER_IO_OFFSET)
-#define OMAP44XX_EMIF1_SIZE	SZ_1M
-
-#define OMAP44XX_EMIF2_PHYS	OMAP44XX_EMIF2_BASE
-						/* 0x4d000000 --> 0xfd200000 */
-#define OMAP44XX_EMIF2_SIZE	SZ_1M
-#define OMAP44XX_EMIF2_VIRT	(OMAP44XX_EMIF1_VIRT + OMAP44XX_EMIF1_SIZE)
-
-#define OMAP44XX_DMM_PHYS	OMAP44XX_DMM_BASE
-						/* 0x4e000000 --> 0xfd300000 */
-#define OMAP44XX_DMM_SIZE	SZ_1M
-#define OMAP44XX_DMM_VIRT	(OMAP44XX_EMIF2_VIRT + OMAP44XX_EMIF2_SIZE)
-/*
- * ----------------------------------------------------------------------------
- * Omap specific register access
- * ----------------------------------------------------------------------------
- */
-
-#ifndef __ASSEMBLER__
-
-/*
- * NOTE: Please use ioremap + __raw_read/write where possible instead of these
- */
-
-extern u8 omap_readb(u32 pa);
-extern u16 omap_readw(u32 pa);
-extern u32 omap_readl(u32 pa);
-extern void omap_writeb(u8 v, u32 pa);
-extern void omap_writew(u16 v, u32 pa);
-extern void omap_writel(u32 v, u32 pa);
-
-struct omap_sdrc_params;
-extern void omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
-				      struct omap_sdrc_params *sdrc_cs1);
-
-extern void __init omap_init_consistent_dma_size(void);
-
-#endif
-
-#endif
diff --git a/arch/arm/plat-omap/include/plat/keypad.h b/arch/arm/plat-omap/include/plat/keypad.h
index 793ce9d..a6b21ed 100644
--- a/arch/arm/plat-omap/include/plat/keypad.h
+++ b/arch/arm/plat-omap/include/plat/keypad.h
@@ -12,6 +12,8 @@
 
 #ifndef CONFIG_ARCH_OMAP1
 #warning Please update the board to use matrix-keypad driver
+#define omap_readw(reg)		0
+#define omap_writew(val, reg)	do {} while (0)
 #endif
 #include <linux/input/matrix_keypad.h>
 
diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h
index 8fa74e2..1881412 100644
--- a/arch/arm/plat-omap/include/plat/mcbsp.h
+++ b/arch/arm/plat-omap/include/plat/mcbsp.h
@@ -27,271 +27,10 @@
 #include <linux/spinlock.h>
 #include <linux/clk.h>
 
-/* macro for building platform_device for McBSP ports */
-#define OMAP_MCBSP_PLATFORM_DEVICE(port_nr)		\
-static struct platform_device omap_mcbsp##port_nr = {	\
-	.name	= "omap-mcbsp-dai",			\
-	.id	= port_nr - 1,			\
-}
-
 #define MCBSP_CONFIG_TYPE2	0x2
 #define MCBSP_CONFIG_TYPE3	0x3
 #define MCBSP_CONFIG_TYPE4	0x4
 
-/* McBSP register numbers. Register address offset = num * reg_step */
-enum {
-	/* Common registers */
-	OMAP_MCBSP_REG_SPCR2 = 4,
-	OMAP_MCBSP_REG_SPCR1,
-	OMAP_MCBSP_REG_RCR2,
-	OMAP_MCBSP_REG_RCR1,
-	OMAP_MCBSP_REG_XCR2,
-	OMAP_MCBSP_REG_XCR1,
-	OMAP_MCBSP_REG_SRGR2,
-	OMAP_MCBSP_REG_SRGR1,
-	OMAP_MCBSP_REG_MCR2,
-	OMAP_MCBSP_REG_MCR1,
-	OMAP_MCBSP_REG_RCERA,
-	OMAP_MCBSP_REG_RCERB,
-	OMAP_MCBSP_REG_XCERA,
-	OMAP_MCBSP_REG_XCERB,
-	OMAP_MCBSP_REG_PCR0,
-	OMAP_MCBSP_REG_RCERC,
-	OMAP_MCBSP_REG_RCERD,
-	OMAP_MCBSP_REG_XCERC,
-	OMAP_MCBSP_REG_XCERD,
-	OMAP_MCBSP_REG_RCERE,
-	OMAP_MCBSP_REG_RCERF,
-	OMAP_MCBSP_REG_XCERE,
-	OMAP_MCBSP_REG_XCERF,
-	OMAP_MCBSP_REG_RCERG,
-	OMAP_MCBSP_REG_RCERH,
-	OMAP_MCBSP_REG_XCERG,
-	OMAP_MCBSP_REG_XCERH,
-
-	/* OMAP1-OMAP2420 registers */
-	OMAP_MCBSP_REG_DRR2 = 0,
-	OMAP_MCBSP_REG_DRR1,
-	OMAP_MCBSP_REG_DXR2,
-	OMAP_MCBSP_REG_DXR1,
-
-	/* OMAP2430 and onwards */
-	OMAP_MCBSP_REG_DRR = 0,
-	OMAP_MCBSP_REG_DXR = 2,
-	OMAP_MCBSP_REG_SYSCON =	35,
-	OMAP_MCBSP_REG_THRSH2,
-	OMAP_MCBSP_REG_THRSH1,
-	OMAP_MCBSP_REG_IRQST = 40,
-	OMAP_MCBSP_REG_IRQEN,
-	OMAP_MCBSP_REG_WAKEUPEN,
-	OMAP_MCBSP_REG_XCCR,
-	OMAP_MCBSP_REG_RCCR,
-	OMAP_MCBSP_REG_XBUFFSTAT,
-	OMAP_MCBSP_REG_RBUFFSTAT,
-	OMAP_MCBSP_REG_SSELCR,
-};
-
-/* OMAP3 sidetone control registers */
-#define OMAP_ST_REG_REV		0x00
-#define OMAP_ST_REG_SYSCONFIG	0x10
-#define OMAP_ST_REG_IRQSTATUS	0x18
-#define OMAP_ST_REG_IRQENABLE	0x1C
-#define OMAP_ST_REG_SGAINCR	0x24
-#define OMAP_ST_REG_SFIRCR	0x28
-#define OMAP_ST_REG_SSELCR	0x2C
-
-/************************** McBSP SPCR1 bit definitions ***********************/
-#define RRST			0x0001
-#define RRDY			0x0002
-#define RFULL			0x0004
-#define RSYNC_ERR		0x0008
-#define RINTM(value)		((value)<<4)	/* bits 4:5 */
-#define ABIS			0x0040
-#define DXENA			0x0080
-#define CLKSTP(value)		((value)<<11)	/* bits 11:12 */
-#define RJUST(value)		((value)<<13)	/* bits 13:14 */
-#define ALB			0x8000
-#define DLB			0x8000
-
-/************************** McBSP SPCR2 bit definitions ***********************/
-#define XRST		0x0001
-#define XRDY		0x0002
-#define XEMPTY		0x0004
-#define XSYNC_ERR	0x0008
-#define XINTM(value)	((value)<<4)		/* bits 4:5 */
-#define GRST		0x0040
-#define FRST		0x0080
-#define SOFT		0x0100
-#define FREE		0x0200
-
-/************************** McBSP PCR bit definitions *************************/
-#define CLKRP		0x0001
-#define CLKXP		0x0002
-#define FSRP		0x0004
-#define FSXP		0x0008
-#define DR_STAT		0x0010
-#define DX_STAT		0x0020
-#define CLKS_STAT	0x0040
-#define SCLKME		0x0080
-#define CLKRM		0x0100
-#define CLKXM		0x0200
-#define FSRM		0x0400
-#define FSXM		0x0800
-#define RIOEN		0x1000
-#define XIOEN		0x2000
-#define IDLE_EN		0x4000
-
-/************************** McBSP RCR1 bit definitions ************************/
-#define RWDLEN1(value)		((value)<<5)	/* Bits 5:7 */
-#define RFRLEN1(value)		((value)<<8)	/* Bits 8:14 */
-
-/************************** McBSP XCR1 bit definitions ************************/
-#define XWDLEN1(value)		((value)<<5)	/* Bits 5:7 */
-#define XFRLEN1(value)		((value)<<8)	/* Bits 8:14 */
-
-/*************************** McBSP RCR2 bit definitions ***********************/
-#define RDATDLY(value)		(value)		/* Bits 0:1 */
-#define RFIG			0x0004
-#define RCOMPAND(value)		((value)<<3)	/* Bits 3:4 */
-#define RWDLEN2(value)		((value)<<5)	/* Bits 5:7 */
-#define RFRLEN2(value)		((value)<<8)	/* Bits 8:14 */
-#define RPHASE			0x8000
-
-/*************************** McBSP XCR2 bit definitions ***********************/
-#define XDATDLY(value)		(value)		/* Bits 0:1 */
-#define XFIG			0x0004
-#define XCOMPAND(value)		((value)<<3)	/* Bits 3:4 */
-#define XWDLEN2(value)		((value)<<5)	/* Bits 5:7 */
-#define XFRLEN2(value)		((value)<<8)	/* Bits 8:14 */
-#define XPHASE			0x8000
-
-/************************* McBSP SRGR1 bit definitions ************************/
-#define CLKGDV(value)		(value)		/* Bits 0:7 */
-#define FWID(value)		((value)<<8)	/* Bits 8:15 */
-
-/************************* McBSP SRGR2 bit definitions ************************/
-#define FPER(value)		(value)		/* Bits 0:11 */
-#define FSGM			0x1000
-#define CLKSM			0x2000
-#define CLKSP			0x4000
-#define GSYNC			0x8000
-
-/************************* McBSP MCR1 bit definitions *************************/
-#define RMCM			0x0001
-#define RCBLK(value)		((value)<<2)	/* Bits 2:4 */
-#define RPABLK(value)		((value)<<5)	/* Bits 5:6 */
-#define RPBBLK(value)		((value)<<7)	/* Bits 7:8 */
-
-/************************* McBSP MCR2 bit definitions *************************/
-#define XMCM(value)		(value)		/* Bits 0:1 */
-#define XCBLK(value)		((value)<<2)	/* Bits 2:4 */
-#define XPABLK(value)		((value)<<5)	/* Bits 5:6 */
-#define XPBBLK(value)		((value)<<7)	/* Bits 7:8 */
-
-/*********************** McBSP XCCR bit definitions *************************/
-#define EXTCLKGATE		0x8000
-#define PPCONNECT		0x4000
-#define DXENDLY(value)		((value)<<12)	/* Bits 12:13 */
-#define XFULL_CYCLE		0x0800
-#define DILB			0x0020
-#define XDMAEN			0x0008
-#define XDISABLE		0x0001
-
-/********************** McBSP RCCR bit definitions *************************/
-#define RFULL_CYCLE		0x0800
-#define RDMAEN			0x0008
-#define RDISABLE		0x0001
-
-/********************** McBSP SYSCONFIG bit definitions ********************/
-#define CLOCKACTIVITY(value)	((value)<<8)
-#define SIDLEMODE(value)	((value)<<3)
-#define ENAWAKEUP		0x0004
-#define SOFTRST			0x0002
-
-/********************** McBSP SSELCR bit definitions ***********************/
-#define SIDETONEEN		0x0400
-
-/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/
-#define ST_AUTOIDLE		0x0001
-
-/********************** McBSP Sidetone SGAINCR bit definitions *************/
-#define ST_CH1GAIN(value)	((value<<16))	/* Bits 16:31 */
-#define ST_CH0GAIN(value)	(value)		/* Bits 0:15 */
-
-/********************** McBSP Sidetone SFIRCR bit definitions **************/
-#define ST_FIRCOEFF(value)	(value)		/* Bits 0:15 */
-
-/********************** McBSP Sidetone SSELCR bit definitions **************/
-#define ST_COEFFWRDONE		0x0004
-#define ST_COEFFWREN		0x0002
-#define ST_SIDETONEEN		0x0001
-
-/********************** McBSP DMA operating modes **************************/
-#define MCBSP_DMA_MODE_ELEMENT		0
-#define MCBSP_DMA_MODE_THRESHOLD	1
-#define MCBSP_DMA_MODE_FRAME		2
-
-/********************** McBSP WAKEUPEN bit definitions *********************/
-#define XEMPTYEOFEN		0x4000
-#define XRDYEN			0x0400
-#define XEOFEN			0x0200
-#define XFSXEN			0x0100
-#define XSYNCERREN		0x0080
-#define RRDYEN			0x0008
-#define REOFEN			0x0004
-#define RFSREN			0x0002
-#define RSYNCERREN		0x0001
-
-/* CLKR signal muxing options */
-#define CLKR_SRC_CLKR		0
-#define CLKR_SRC_CLKX		1
-
-/* FSR signal muxing options */
-#define FSR_SRC_FSR		0
-#define FSR_SRC_FSX		1
-
-/* McBSP functional clock sources */
-#define MCBSP_CLKS_PRCM_SRC	0
-#define MCBSP_CLKS_PAD_SRC	1
-
-/* we don't do multichannel for now */
-struct omap_mcbsp_reg_cfg {
-	u16 spcr2;
-	u16 spcr1;
-	u16 rcr2;
-	u16 rcr1;
-	u16 xcr2;
-	u16 xcr1;
-	u16 srgr2;
-	u16 srgr1;
-	u16 mcr2;
-	u16 mcr1;
-	u16 pcr0;
-	u16 rcerc;
-	u16 rcerd;
-	u16 xcerc;
-	u16 xcerd;
-	u16 rcere;
-	u16 rcerf;
-	u16 xcere;
-	u16 xcerf;
-	u16 rcerg;
-	u16 rcerh;
-	u16 xcerg;
-	u16 xcerh;
-	u16 xccr;
-	u16 rccr;
-};
-
-typedef enum {
-	OMAP_MCBSP_WORD_8 = 0,
-	OMAP_MCBSP_WORD_12,
-	OMAP_MCBSP_WORD_16,
-	OMAP_MCBSP_WORD_20,
-	OMAP_MCBSP_WORD_24,
-	OMAP_MCBSP_WORD_32,
-} omap_mcbsp_word_length;
-
 /* Platform specific configuration */
 struct omap_mcbsp_ops {
 	void (*request)(unsigned int);
@@ -312,43 +51,6 @@
 	int (*mux_signal)(struct device *dev, const char *signal, const char *src);
 };
 
-struct omap_mcbsp_st_data {
-	void __iomem *io_base_st;
-	bool running;
-	bool enabled;
-	s16 taps[128];	/* Sidetone filter coefficients */
-	int nr_taps;	/* Number of filter coefficients in use */
-	s16 ch0gain;
-	s16 ch1gain;
-};
-
-struct omap_mcbsp {
-	struct device *dev;
-	unsigned long phys_base;
-	unsigned long phys_dma_base;
-	void __iomem *io_base;
-	u8 id;
-	u8 free;
-
-	int rx_irq;
-	int tx_irq;
-
-	/* DMA stuff */
-	u8 dma_rx_sync;
-	u8 dma_tx_sync;
-
-	/* Protect the field .free, while checking if the mcbsp is in use */
-	spinlock_t lock;
-	struct omap_mcbsp_platform_data *pdata;
-	struct clk *fclk;
-	struct omap_mcbsp_st_data *st_data;
-	int dma_op_mode;
-	u16 max_tx_thres;
-	u16 max_rx_thres;
-	void *reg_cache;
-	int reg_cache_size;
-};
-
 /**
  * omap_mcbsp_dev_attr - OMAP McBSP device attributes for omap_hwmod
  * @sidetone: name of the sidetone device
@@ -357,39 +59,4 @@
 	const char *sidetone;
 };
 
-extern struct omap_mcbsp **mcbsp_ptr;
-extern int omap_mcbsp_count;
-
-int omap_mcbsp_init(void);
-void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config);
-void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold);
-void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold);
-u16 omap_mcbsp_get_max_tx_threshold(unsigned int id);
-u16 omap_mcbsp_get_max_rx_threshold(unsigned int id);
-u16 omap_mcbsp_get_fifo_size(unsigned int id);
-u16 omap_mcbsp_get_tx_delay(unsigned int id);
-u16 omap_mcbsp_get_rx_delay(unsigned int id);
-int omap_mcbsp_get_dma_op_mode(unsigned int id);
-int omap_mcbsp_request(unsigned int id);
-void omap_mcbsp_free(unsigned int id);
-void omap_mcbsp_start(unsigned int id, int tx, int rx);
-void omap_mcbsp_stop(unsigned int id, int tx, int rx);
-
-/* McBSP functional clock source changing function */
-extern int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id);
-
-/* McBSP signal muxing API */
-void omap2_mcbsp1_mux_clkr_src(u8 mux);
-void omap2_mcbsp1_mux_fsr_src(u8 mux);
-
-int omap_mcbsp_dma_ch_params(unsigned int id, unsigned int stream);
-int omap_mcbsp_dma_reg_params(unsigned int id, unsigned int stream);
-
-/* Sidetone specific API */
-int omap_st_set_chgain(unsigned int id, int channel, s16 chgain);
-int omap_st_get_chgain(unsigned int id, int channel, s16 *chgain);
-int omap_st_enable(unsigned int id);
-int omap_st_disable(unsigned int id);
-int omap_st_is_enabled(unsigned int id);
-
 #endif
diff --git a/arch/arm/plat-omap/include/plat/mcspi.h b/arch/arm/plat-omap/include/plat/mcspi.h
index 3d51b18..a357eb2 100644
--- a/arch/arm/plat-omap/include/plat/mcspi.h
+++ b/arch/arm/plat-omap/include/plat/mcspi.h
@@ -18,9 +18,6 @@
 
 struct omap2_mcspi_device_config {
 	unsigned turbo_mode:1;
-
-	/* Do we want one channel enabled at the same time? */
-	unsigned single_channel:1;
 };
 
 #endif
diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h
index f75946c..7a38750 100644
--- a/arch/arm/plat-omap/include/plat/mmc.h
+++ b/arch/arm/plat-omap/include/plat/mmc.h
@@ -137,8 +137,6 @@
 		int (*set_power)(struct device *dev, int slot,
 				 int power_on, int vdd);
 		int (*get_ro)(struct device *dev, int slot);
-		int (*set_sleep)(struct device *dev, int slot, int sleep,
-				 int vdd, int cardsleep);
 		void (*remux)(struct device *dev, int slot, int power_on);
 		/* Call back before enabling / disabling regulators */
 		void (*before_set_reg)(struct device *dev, int slot,
diff --git a/arch/arm/plat-omap/include/plat/omap4-keypad.h b/arch/arm/plat-omap/include/plat/omap4-keypad.h
index 9fe6c87..8ad0a37 100644
--- a/arch/arm/plat-omap/include/plat/omap4-keypad.h
+++ b/arch/arm/plat-omap/include/plat/omap4-keypad.h
@@ -1,15 +1,6 @@
 #ifndef ARCH_ARM_PLAT_OMAP4_KEYPAD_H
 #define ARCH_ARM_PLAT_OMAP4_KEYPAD_H
 
-#include <linux/input/matrix_keypad.h>
-
-struct omap4_keypad_platform_data {
-	const struct matrix_keymap_data *keymap_data;
-
-	u8 rows;
-	u8 cols;
-};
-
 extern int omap4_keyboard_init(struct omap4_keypad_platform_data *,
 				struct omap_board_data *);
 #endif
diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h
index 51423d2..4327b2c 100644
--- a/arch/arm/plat-omap/include/plat/omap_device.h
+++ b/arch/arm/plat-omap/include/plat/omap_device.h
@@ -36,7 +36,7 @@
 
 #include <plat/omap_hwmod.h>
 
-extern struct device omap_device_parent;
+extern struct dev_pm_domain omap_device_pm_domain;
 
 /* omap_device._state values */
 #define OMAP_DEVICE_STATE_UNKNOWN	0
@@ -100,6 +100,13 @@
 					 struct omap_device_pm_latency *pm_lats,
 					 int pm_lats_cnt, int is_early_device);
 
+struct omap_device *omap_device_alloc(struct platform_device *pdev,
+				      struct omap_hwmod **ohs, int oh_cnt,
+				      struct omap_device_pm_latency *pm_lats,
+				      int pm_lats_cnt);
+void omap_device_delete(struct omap_device *od);
+int omap_device_register(struct platform_device *pdev);
+
 void __iomem *omap_device_get_rt_va(struct omap_device *od);
 struct device *omap_device_get_by_hwmod_name(const char *oh_name);
 
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 6470101..8070145 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -47,17 +47,17 @@
  * with the original PRCM protocol defined for OMAP2420
  */
 #define SYSC_TYPE1_MIDLEMODE_SHIFT	12
-#define SYSC_TYPE1_MIDLEMODE_MASK	(0x3 << SYSC_MIDLEMODE_SHIFT)
+#define SYSC_TYPE1_MIDLEMODE_MASK	(0x3 << SYSC_TYPE1_MIDLEMODE_SHIFT)
 #define SYSC_TYPE1_CLOCKACTIVITY_SHIFT	8
-#define SYSC_TYPE1_CLOCKACTIVITY_MASK	(0x3 << SYSC_CLOCKACTIVITY_SHIFT)
+#define SYSC_TYPE1_CLOCKACTIVITY_MASK	(0x3 << SYSC_TYPE1_CLOCKACTIVITY_SHIFT)
 #define SYSC_TYPE1_SIDLEMODE_SHIFT	3
-#define SYSC_TYPE1_SIDLEMODE_MASK	(0x3 << SYSC_SIDLEMODE_SHIFT)
+#define SYSC_TYPE1_SIDLEMODE_MASK	(0x3 << SYSC_TYPE1_SIDLEMODE_SHIFT)
 #define SYSC_TYPE1_ENAWAKEUP_SHIFT	2
-#define SYSC_TYPE1_ENAWAKEUP_MASK	(1 << SYSC_ENAWAKEUP_SHIFT)
+#define SYSC_TYPE1_ENAWAKEUP_MASK	(1 << SYSC_TYPE1_ENAWAKEUP_SHIFT)
 #define SYSC_TYPE1_SOFTRESET_SHIFT	1
-#define SYSC_TYPE1_SOFTRESET_MASK	(1 << SYSC_SOFTRESET_SHIFT)
+#define SYSC_TYPE1_SOFTRESET_MASK	(1 << SYSC_TYPE1_SOFTRESET_SHIFT)
 #define SYSC_TYPE1_AUTOIDLE_SHIFT	0
-#define SYSC_TYPE1_AUTOIDLE_MASK	(1 << SYSC_AUTOIDLE_SHIFT)
+#define SYSC_TYPE1_AUTOIDLE_MASK	(1 << SYSC_TYPE1_AUTOIDLE_SHIFT)
 
 /*
  * OCP SYSCONFIG bit shifts/masks TYPE2. These are for IPs compliant
@@ -484,7 +484,6 @@
  * @main_clk: main clock: OMAP clock name
  * @_clk: pointer to the main struct clk (filled in at runtime)
  * @opt_clks: other device clocks that drivers can request (0..*)
- * @vdd_name: voltage domain name
  * @voltdm: pointer to voltage domain (filled in at runtime)
  * @masters: ptr to array of OCP ifs that this hwmod can initiate on
  * @slaves: ptr to array of OCP ifs that this hwmod can respond on
@@ -528,7 +527,6 @@
 	struct omap_hwmod_opt_clk	*opt_clks;
 	char				*clkdm_name;
 	struct clockdomain		*clkdm;
-	char				*vdd_name;
 	struct omap_hwmod_ocp_if	**masters; /* connect to *_IA */
 	struct omap_hwmod_ocp_if	**slaves;  /* connect to *_TA */
 	void				*dev_attr;
diff --git a/arch/arm/plat-omap/include/plat/remoteproc.h b/arch/arm/plat-omap/include/plat/remoteproc.h
new file mode 100644
index 0000000..b10eac8
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/remoteproc.h
@@ -0,0 +1,57 @@
+/*
+ * Remote Processor - omap-specific bits
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, 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.
+ */
+
+#ifndef _PLAT_REMOTEPROC_H
+#define _PLAT_REMOTEPROC_H
+
+struct rproc_ops;
+struct platform_device;
+
+/*
+ * struct omap_rproc_pdata - omap remoteproc's platform data
+ * @name: the remoteproc's name
+ * @oh_name: omap hwmod device
+ * @oh_name_opt: optional, secondary omap hwmod device
+ * @firmware: name of firmware file to load
+ * @mbox_name: name of omap mailbox device to use with this rproc
+ * @ops: start/stop rproc handlers
+ * @device_enable: omap-specific handler for enabling a device
+ * @device_shutdown: omap-specific handler for shutting down a device
+ */
+struct omap_rproc_pdata {
+	const char *name;
+	const char *oh_name;
+	const char *oh_name_opt;
+	const char *firmware;
+	const char *mbox_name;
+	const struct rproc_ops *ops;
+	int (*device_enable) (struct platform_device *pdev);
+	int (*device_shutdown) (struct platform_device *pdev);
+};
+
+#if defined(CONFIG_OMAP_REMOTEPROC) || defined(CONFIG_OMAP_REMOTEPROC_MODULE)
+
+void __init omap_rproc_reserve_cma(void);
+
+#else
+
+void __init omap_rproc_reserve_cma(void)
+{
+}
+
+#endif
+
+#endif /* _PLAT_REMOTEPROC_H */
diff --git a/arch/arm/plat-omap/include/plat/sdrc.h b/arch/arm/plat-omap/include/plat/sdrc.h
index 925b12b..9bb978e 100644
--- a/arch/arm/plat-omap/include/plat/sdrc.h
+++ b/arch/arm/plat-omap/include/plat/sdrc.h
@@ -16,7 +16,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <mach/io.h>
 
 /* SDRC register offsets - read/write with sdrc_{read,write}_reg() */
 
diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h
index 198d1e6..b073e5f 100644
--- a/arch/arm/plat-omap/include/plat/serial.h
+++ b/arch/arm/plat-omap/include/plat/serial.h
@@ -110,7 +110,6 @@
 struct omap_uart_port_info;
 
 extern void omap_serial_init(void);
-extern int omap_uart_can_sleep(void);
 extern void omap_serial_board_init(struct omap_uart_port_info *platform_data);
 extern void omap_serial_init_port(struct omap_board_data *bdata,
 		struct omap_uart_port_info *platform_data);
diff --git a/arch/arm/plat-omap/include/plat/sram.h b/arch/arm/plat-omap/include/plat/sram.h
index 75aa1b2..227ae26 100644
--- a/arch/arm/plat-omap/include/plat/sram.h
+++ b/arch/arm/plat-omap/include/plat/sram.h
@@ -101,4 +101,5 @@
 #else
 #define OMAP4_SRAM_PA		0x40300000
 #endif
+#define AM33XX_SRAM_PA		0x40300000
 #endif
diff --git a/arch/arm/plat-omap/include/plat/system.h b/arch/arm/plat-omap/include/plat/system.h
deleted file mode 100644
index 8e5ebd7..0000000
--- a/arch/arm/plat-omap/include/plat/system.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copied from arch/arm/mach-sa1100/include/mach/system.h
- * Copyright (c) 1999 Nicolas Pitre <nico@fluxnic.net>
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-#include <asm/proc-fns.h>
-
-static inline void arch_idle(void)
-{
-	cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/plat-omap/include/plat/tc.h b/arch/arm/plat-omap/include/plat/tc.h
index d2fcd78..1b4b2da 100644
--- a/arch/arm/plat-omap/include/plat/tc.h
+++ b/arch/arm/plat-omap/include/plat/tc.h
@@ -84,23 +84,6 @@
 #define EMIFS_CCS(n)		(EMIFS_CS0_CONFIG + (4 * (n)))
 #define EMIFS_ACS(n)		(EMIFS_ACS0 + (4 * (n)))
 
-/* Almost all documentation for chip and board memory maps assumes
- * BM is clear.  Most devel boards have a switch to control booting
- * from NOR flash (using external chipselect 3) rather than mask ROM,
- * which uses BM to interchange the physical CS0 and CS3 addresses.
- */
-static inline u32 omap_cs0_phys(void)
-{
-	return (omap_readl(EMIFS_CONFIG) & OMAP_EMIFS_CONFIG_BM)
-			?  OMAP_CS3_PHYS : 0;
-}
-
-static inline u32 omap_cs3_phys(void)
-{
-	return (omap_readl(EMIFS_CONFIG) & OMAP_EMIFS_CONFIG_BM)
-			? 0 : OMAP_CS3_PHYS;
-}
-
 #endif	/* __ASSEMBLER__ */
 
 #endif	/* __ASM_ARCH_TC_H */
diff --git a/arch/arm/plat-omap/include/plat/uncompress.h b/arch/arm/plat-omap/include/plat/uncompress.h
index 6ee9049..cc3f11b 100644
--- a/arch/arm/plat-omap/include/plat/uncompress.h
+++ b/arch/arm/plat-omap/include/plat/uncompress.h
@@ -160,6 +160,7 @@
 		DEBUG_LL_OMAP3(3, igep0020);
 		DEBUG_LL_OMAP3(3, igep0030);
 		DEBUG_LL_OMAP3(3, nokia_rm680);
+		DEBUG_LL_OMAP3(3, nokia_rm696);
 		DEBUG_LL_OMAP3(3, nokia_rx51);
 		DEBUG_LL_OMAP3(3, omap3517evm);
 		DEBUG_LL_OMAP3(3, omap3_beagle);
diff --git a/arch/arm/plat-omap/include/plat/usb.h b/arch/arm/plat-omap/include/plat/usb.h
index dc864b5..762eeb0 100644
--- a/arch/arm/plat-omap/include/plat/usb.h
+++ b/arch/arm/plat-omap/include/plat/usb.h
@@ -3,6 +3,7 @@
 #ifndef	__ASM_ARCH_OMAP_USB_H
 #define	__ASM_ARCH_OMAP_USB_H
 
+#include <linux/io.h>
 #include <linux/usb/musb.h>
 #include <plat/board.h>
 
@@ -105,6 +106,45 @@
 extern int omap4430_phy_init(struct device *dev);
 extern int omap4430_phy_exit(struct device *dev);
 extern int omap4430_phy_suspend(struct device *dev, int suspend);
+
+/*
+ * NOTE: Please update omap USB drivers to use ioremap + read/write
+ */
+
+#define OMAP2_L4_IO_OFFSET	0xb2000000
+#define OMAP2_L4_IO_ADDRESS(pa)	IOMEM((pa) + OMAP2_L4_IO_OFFSET)
+
+static inline u8 omap_readb(u32 pa)
+{
+	return __raw_readb(OMAP2_L4_IO_ADDRESS(pa));
+}
+
+static inline u16 omap_readw(u32 pa)
+{
+	return __raw_readw(OMAP2_L4_IO_ADDRESS(pa));
+}
+
+static inline u32 omap_readl(u32 pa)
+{
+	return __raw_readl(OMAP2_L4_IO_ADDRESS(pa));
+}
+
+static inline void omap_writeb(u8 v, u32 pa)
+{
+	__raw_writeb(v, OMAP2_L4_IO_ADDRESS(pa));
+}
+
+
+static inline void omap_writew(u16 v, u32 pa)
+{
+	__raw_writew(v, OMAP2_L4_IO_ADDRESS(pa));
+}
+
+static inline void omap_writel(u32 v, u32 pa)
+{
+	__raw_writel(v, OMAP2_L4_IO_ADDRESS(pa));
+}
+
 #endif
 
 extern void am35x_musb_reset(void);
diff --git a/arch/arm/plat-omap/include/plat/vram.h b/arch/arm/plat-omap/include/plat/vram.h
index 0aa4ecd..4d65b7d 100644
--- a/arch/arm/plat-omap/include/plat/vram.h
+++ b/arch/arm/plat-omap/include/plat/vram.h
@@ -23,40 +23,21 @@
 
 #include <linux/types.h>
 
-#define OMAP_VRAM_MEMTYPE_SDRAM		0
-#define OMAP_VRAM_MEMTYPE_SRAM		1
-#define OMAP_VRAM_MEMTYPE_MAX		1
-
 extern int omap_vram_add_region(unsigned long paddr, size_t size);
 extern int omap_vram_free(unsigned long paddr, size_t size);
-extern int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr);
+extern int omap_vram_alloc(size_t size, unsigned long *paddr);
 extern int omap_vram_reserve(unsigned long paddr, size_t size);
 extern void omap_vram_get_info(unsigned long *vram, unsigned long *free_vram,
 		unsigned long *largest_free_block);
 
 #ifdef CONFIG_OMAP2_VRAM
 extern void omap_vram_set_sdram_vram(u32 size, u32 start);
-extern void omap_vram_set_sram_vram(u32 size, u32 start);
 
 extern void omap_vram_reserve_sdram_memblock(void);
-extern unsigned long omap_vram_reserve_sram(unsigned long sram_pstart,
-					    unsigned long sram_vstart,
-					    unsigned long sram_size,
-					    unsigned long pstart_avail,
-					    unsigned long size_avail);
 #else
 static inline void omap_vram_set_sdram_vram(u32 size, u32 start) { }
-static inline void omap_vram_set_sram_vram(u32 size, u32 start) { }
 
 static inline void omap_vram_reserve_sdram_memblock(void) { }
-static inline unsigned long omap_vram_reserve_sram(unsigned long sram_pstart,
-					    unsigned long sram_vstart,
-					    unsigned long sram_size,
-					    unsigned long pstart_avail,
-					    unsigned long size_avail)
-{
-	return 0;
-}
 #endif
 
 #endif
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
index ad80112..ad32621 100644
--- a/arch/arm/plat-omap/mailbox.c
+++ b/arch/arm/plat-omap/mailbox.c
@@ -307,7 +307,7 @@
 	if (!--mbox->use_count) {
 		free_irq(mbox->irq, mbox);
 		tasklet_kill(&mbox->txq->tasklet);
-	flush_work_sync(&mbox->rxq->work);
+		flush_work_sync(&mbox->rxq->work);
 		mbox_queue_free(mbox->txq);
 		mbox_queue_free(mbox->rxq);
 	}
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
deleted file mode 100644
index 4b15cd7..0000000
--- a/arch/arm/plat-omap/mcbsp.c
+++ /dev/null
@@ -1,1361 +0,0 @@
-/*
- * linux/arch/arm/plat-omap/mcbsp.c
- *
- * Copyright (C) 2004 Nokia Corporation
- * Author: Samuel Ortiz <samuel.ortiz@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.
- *
- * Multichannel mode not supported.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#include <plat/mcbsp.h>
-#include <linux/pm_runtime.h>
-
-struct omap_mcbsp **mcbsp_ptr;
-int omap_mcbsp_count;
-
-#define omap_mcbsp_check_valid_id(id)	(id < omap_mcbsp_count)
-#define id_to_mcbsp_ptr(id)		mcbsp_ptr[id];
-
-static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
-{
-	void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
-
-	if (mcbsp->pdata->reg_size == 2) {
-		((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
-		__raw_writew((u16)val, addr);
-	} else {
-		((u32 *)mcbsp->reg_cache)[reg] = val;
-		__raw_writel(val, addr);
-	}
-}
-
-static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
-{
-	void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
-
-	if (mcbsp->pdata->reg_size == 2) {
-		return !from_cache ? __raw_readw(addr) :
-				     ((u16 *)mcbsp->reg_cache)[reg];
-	} else {
-		return !from_cache ? __raw_readl(addr) :
-				     ((u32 *)mcbsp->reg_cache)[reg];
-	}
-}
-
-static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
-{
-	__raw_writel(val, mcbsp->st_data->io_base_st + reg);
-}
-
-static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
-{
-	return __raw_readl(mcbsp->st_data->io_base_st + reg);
-}
-
-#define MCBSP_READ(mcbsp, reg) \
-		omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0)
-#define MCBSP_WRITE(mcbsp, reg, val) \
-		omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val)
-#define MCBSP_READ_CACHE(mcbsp, reg) \
-		omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
-
-#define MCBSP_ST_READ(mcbsp, reg) \
-			omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
-#define MCBSP_ST_WRITE(mcbsp, reg, val) \
-			omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
-
-static void omap_mcbsp_dump_reg(u8 id)
-{
-	struct omap_mcbsp *mcbsp = id_to_mcbsp_ptr(id);
-
-	dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id);
-	dev_dbg(mcbsp->dev, "DRR2:  0x%04x\n",
-			MCBSP_READ(mcbsp, DRR2));
-	dev_dbg(mcbsp->dev, "DRR1:  0x%04x\n",
-			MCBSP_READ(mcbsp, DRR1));
-	dev_dbg(mcbsp->dev, "DXR2:  0x%04x\n",
-			MCBSP_READ(mcbsp, DXR2));
-	dev_dbg(mcbsp->dev, "DXR1:  0x%04x\n",
-			MCBSP_READ(mcbsp, DXR1));
-	dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n",
-			MCBSP_READ(mcbsp, SPCR2));
-	dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n",
-			MCBSP_READ(mcbsp, SPCR1));
-	dev_dbg(mcbsp->dev, "RCR2:  0x%04x\n",
-			MCBSP_READ(mcbsp, RCR2));
-	dev_dbg(mcbsp->dev, "RCR1:  0x%04x\n",
-			MCBSP_READ(mcbsp, RCR1));
-	dev_dbg(mcbsp->dev, "XCR2:  0x%04x\n",
-			MCBSP_READ(mcbsp, XCR2));
-	dev_dbg(mcbsp->dev, "XCR1:  0x%04x\n",
-			MCBSP_READ(mcbsp, XCR1));
-	dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n",
-			MCBSP_READ(mcbsp, SRGR2));
-	dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n",
-			MCBSP_READ(mcbsp, SRGR1));
-	dev_dbg(mcbsp->dev, "PCR0:  0x%04x\n",
-			MCBSP_READ(mcbsp, PCR0));
-	dev_dbg(mcbsp->dev, "***********************\n");
-}
-
-static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
-{
-	struct omap_mcbsp *mcbsp_tx = dev_id;
-	u16 irqst_spcr2;
-
-	irqst_spcr2 = MCBSP_READ(mcbsp_tx, SPCR2);
-	dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
-
-	if (irqst_spcr2 & XSYNC_ERR) {
-		dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n",
-			irqst_spcr2);
-		/* Writing zero to XSYNC_ERR clears the IRQ */
-		MCBSP_WRITE(mcbsp_tx, SPCR2, MCBSP_READ_CACHE(mcbsp_tx, SPCR2));
-	}
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
-{
-	struct omap_mcbsp *mcbsp_rx = dev_id;
-	u16 irqst_spcr1;
-
-	irqst_spcr1 = MCBSP_READ(mcbsp_rx, SPCR1);
-	dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
-
-	if (irqst_spcr1 & RSYNC_ERR) {
-		dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n",
-			irqst_spcr1);
-		/* Writing zero to RSYNC_ERR clears the IRQ */
-		MCBSP_WRITE(mcbsp_rx, SPCR1, MCBSP_READ_CACHE(mcbsp_rx, SPCR1));
-	}
-
-	return IRQ_HANDLED;
-}
-
-/*
- * omap_mcbsp_config simply write a config to the
- * appropriate McBSP.
- * You either call this function or set the McBSP registers
- * by yourself before calling omap_mcbsp_start().
- */
-void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config)
-{
-	struct omap_mcbsp *mcbsp;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return;
-	}
-	mcbsp = id_to_mcbsp_ptr(id);
-
-	dev_dbg(mcbsp->dev, "Configuring McBSP%d  phys_base: 0x%08lx\n",
-			mcbsp->id, mcbsp->phys_base);
-
-	/* We write the given config */
-	MCBSP_WRITE(mcbsp, SPCR2, config->spcr2);
-	MCBSP_WRITE(mcbsp, SPCR1, config->spcr1);
-	MCBSP_WRITE(mcbsp, RCR2, config->rcr2);
-	MCBSP_WRITE(mcbsp, RCR1, config->rcr1);
-	MCBSP_WRITE(mcbsp, XCR2, config->xcr2);
-	MCBSP_WRITE(mcbsp, XCR1, config->xcr1);
-	MCBSP_WRITE(mcbsp, SRGR2, config->srgr2);
-	MCBSP_WRITE(mcbsp, SRGR1, config->srgr1);
-	MCBSP_WRITE(mcbsp, MCR2, config->mcr2);
-	MCBSP_WRITE(mcbsp, MCR1, config->mcr1);
-	MCBSP_WRITE(mcbsp, PCR0, config->pcr0);
-	if (mcbsp->pdata->has_ccr) {
-		MCBSP_WRITE(mcbsp, XCCR, config->xccr);
-		MCBSP_WRITE(mcbsp, RCCR, config->rccr);
-	}
-}
-EXPORT_SYMBOL(omap_mcbsp_config);
-
-/**
- * omap_mcbsp_dma_params - returns the dma channel number
- * @id - mcbsp id
- * @stream - indicates the direction of data flow (rx or tx)
- *
- * Returns the dma channel number for the rx channel or tx channel
- * based on the value of @stream for the requested mcbsp given by @id
- */
-int omap_mcbsp_dma_ch_params(unsigned int id, unsigned int stream)
-{
-	struct omap_mcbsp *mcbsp;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return -ENODEV;
-	}
-	mcbsp = id_to_mcbsp_ptr(id);
-
-	if (stream)
-		return mcbsp->dma_rx_sync;
-	else
-		return mcbsp->dma_tx_sync;
-}
-EXPORT_SYMBOL(omap_mcbsp_dma_ch_params);
-
-/**
- * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
- * @id - mcbsp id
- * @stream - indicates the direction of data flow (rx or tx)
- *
- * Returns the address of mcbsp data transmit register or data receive register
- * to be used by DMA for transferring/receiving data based on the value of
- * @stream for the requested mcbsp given by @id
- */
-int omap_mcbsp_dma_reg_params(unsigned int id, unsigned int stream)
-{
-	struct omap_mcbsp *mcbsp;
-	int data_reg;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return -ENODEV;
-	}
-	mcbsp = id_to_mcbsp_ptr(id);
-
-	if (mcbsp->pdata->reg_size == 2) {
-		if (stream)
-			data_reg = OMAP_MCBSP_REG_DRR1;
-		else
-			data_reg = OMAP_MCBSP_REG_DXR1;
-	} else {
-		if (stream)
-			data_reg = OMAP_MCBSP_REG_DRR;
-		else
-			data_reg = OMAP_MCBSP_REG_DXR;
-	}
-
-	return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step;
-}
-EXPORT_SYMBOL(omap_mcbsp_dma_reg_params);
-
-static void omap_st_on(struct omap_mcbsp *mcbsp)
-{
-	unsigned int w;
-
-	if (mcbsp->pdata->enable_st_clock)
-		mcbsp->pdata->enable_st_clock(mcbsp->id, 1);
-
-	/* Enable McBSP Sidetone */
-	w = MCBSP_READ(mcbsp, SSELCR);
-	MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
-
-	/* Enable Sidetone from Sidetone Core */
-	w = MCBSP_ST_READ(mcbsp, SSELCR);
-	MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
-}
-
-static void omap_st_off(struct omap_mcbsp *mcbsp)
-{
-	unsigned int w;
-
-	w = MCBSP_ST_READ(mcbsp, SSELCR);
-	MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
-
-	w = MCBSP_READ(mcbsp, SSELCR);
-	MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
-
-	if (mcbsp->pdata->enable_st_clock)
-		mcbsp->pdata->enable_st_clock(mcbsp->id, 0);
-}
-
-static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
-{
-	u16 val, i;
-
-	val = MCBSP_ST_READ(mcbsp, SSELCR);
-
-	if (val & ST_COEFFWREN)
-		MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
-
-	MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
-
-	for (i = 0; i < 128; i++)
-		MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
-
-	i = 0;
-
-	val = MCBSP_ST_READ(mcbsp, SSELCR);
-	while (!(val & ST_COEFFWRDONE) && (++i < 1000))
-		val = MCBSP_ST_READ(mcbsp, SSELCR);
-
-	MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
-
-	if (i == 1000)
-		dev_err(mcbsp->dev, "McBSP FIR load error!\n");
-}
-
-static void omap_st_chgain(struct omap_mcbsp *mcbsp)
-{
-	u16 w;
-	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
-	w = MCBSP_ST_READ(mcbsp, SSELCR);
-
-	MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | \
-		      ST_CH1GAIN(st_data->ch1gain));
-}
-
-int omap_st_set_chgain(unsigned int id, int channel, s16 chgain)
-{
-	struct omap_mcbsp *mcbsp;
-	struct omap_mcbsp_st_data *st_data;
-	int ret = 0;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return -ENODEV;
-	}
-
-	mcbsp = id_to_mcbsp_ptr(id);
-	st_data = mcbsp->st_data;
-
-	if (!st_data)
-		return -ENOENT;
-
-	spin_lock_irq(&mcbsp->lock);
-	if (channel == 0)
-		st_data->ch0gain = chgain;
-	else if (channel == 1)
-		st_data->ch1gain = chgain;
-	else
-		ret = -EINVAL;
-
-	if (st_data->enabled)
-		omap_st_chgain(mcbsp);
-	spin_unlock_irq(&mcbsp->lock);
-
-	return ret;
-}
-EXPORT_SYMBOL(omap_st_set_chgain);
-
-int omap_st_get_chgain(unsigned int id, int channel, s16 *chgain)
-{
-	struct omap_mcbsp *mcbsp;
-	struct omap_mcbsp_st_data *st_data;
-	int ret = 0;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return -ENODEV;
-	}
-
-	mcbsp = id_to_mcbsp_ptr(id);
-	st_data = mcbsp->st_data;
-
-	if (!st_data)
-		return -ENOENT;
-
-	spin_lock_irq(&mcbsp->lock);
-	if (channel == 0)
-		*chgain = st_data->ch0gain;
-	else if (channel == 1)
-		*chgain = st_data->ch1gain;
-	else
-		ret = -EINVAL;
-	spin_unlock_irq(&mcbsp->lock);
-
-	return ret;
-}
-EXPORT_SYMBOL(omap_st_get_chgain);
-
-static int omap_st_start(struct omap_mcbsp *mcbsp)
-{
-	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
-	if (st_data && st_data->enabled && !st_data->running) {
-		omap_st_fir_write(mcbsp, st_data->taps);
-		omap_st_chgain(mcbsp);
-
-		if (!mcbsp->free) {
-			omap_st_on(mcbsp);
-			st_data->running = 1;
-		}
-	}
-
-	return 0;
-}
-
-int omap_st_enable(unsigned int id)
-{
-	struct omap_mcbsp *mcbsp;
-	struct omap_mcbsp_st_data *st_data;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return -ENODEV;
-	}
-
-	mcbsp = id_to_mcbsp_ptr(id);
-	st_data = mcbsp->st_data;
-
-	if (!st_data)
-		return -ENODEV;
-
-	spin_lock_irq(&mcbsp->lock);
-	st_data->enabled = 1;
-	omap_st_start(mcbsp);
-	spin_unlock_irq(&mcbsp->lock);
-
-	return 0;
-}
-EXPORT_SYMBOL(omap_st_enable);
-
-static int omap_st_stop(struct omap_mcbsp *mcbsp)
-{
-	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
-	if (st_data && st_data->running) {
-		if (!mcbsp->free) {
-			omap_st_off(mcbsp);
-			st_data->running = 0;
-		}
-	}
-
-	return 0;
-}
-
-int omap_st_disable(unsigned int id)
-{
-	struct omap_mcbsp *mcbsp;
-	struct omap_mcbsp_st_data *st_data;
-	int ret = 0;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return -ENODEV;
-	}
-
-	mcbsp = id_to_mcbsp_ptr(id);
-	st_data = mcbsp->st_data;
-
-	if (!st_data)
-		return -ENODEV;
-
-	spin_lock_irq(&mcbsp->lock);
-	omap_st_stop(mcbsp);
-	st_data->enabled = 0;
-	spin_unlock_irq(&mcbsp->lock);
-
-	return ret;
-}
-EXPORT_SYMBOL(omap_st_disable);
-
-int omap_st_is_enabled(unsigned int id)
-{
-	struct omap_mcbsp *mcbsp;
-	struct omap_mcbsp_st_data *st_data;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return -ENODEV;
-	}
-
-	mcbsp = id_to_mcbsp_ptr(id);
-	st_data = mcbsp->st_data;
-
-	if (!st_data)
-		return -ENODEV;
-
-
-	return st_data->enabled;
-}
-EXPORT_SYMBOL(omap_st_is_enabled);
-
-/*
- * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
- * The threshold parameter is 1 based, and it is converted (threshold - 1)
- * for the THRSH2 register.
- */
-void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
-{
-	struct omap_mcbsp *mcbsp;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return;
-	}
-	mcbsp = id_to_mcbsp_ptr(id);
-	if (mcbsp->pdata->buffer_size == 0)
-		return;
-
-	if (threshold && threshold <= mcbsp->max_tx_thres)
-		MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
-}
-EXPORT_SYMBOL(omap_mcbsp_set_tx_threshold);
-
-/*
- * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
- * The threshold parameter is 1 based, and it is converted (threshold - 1)
- * for the THRSH1 register.
- */
-void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
-{
-	struct omap_mcbsp *mcbsp;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return;
-	}
-	mcbsp = id_to_mcbsp_ptr(id);
-	if (mcbsp->pdata->buffer_size == 0)
-		return;
-
-	if (threshold && threshold <= mcbsp->max_rx_thres)
-		MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
-}
-EXPORT_SYMBOL(omap_mcbsp_set_rx_threshold);
-
-/*
- * omap_mcbsp_get_max_tx_thres just return the current configured
- * maximum threshold for transmission
- */
-u16 omap_mcbsp_get_max_tx_threshold(unsigned int id)
-{
-	struct omap_mcbsp *mcbsp;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return -ENODEV;
-	}
-	mcbsp = id_to_mcbsp_ptr(id);
-
-	return mcbsp->max_tx_thres;
-}
-EXPORT_SYMBOL(omap_mcbsp_get_max_tx_threshold);
-
-/*
- * omap_mcbsp_get_max_rx_thres just return the current configured
- * maximum threshold for reception
- */
-u16 omap_mcbsp_get_max_rx_threshold(unsigned int id)
-{
-	struct omap_mcbsp *mcbsp;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return -ENODEV;
-	}
-	mcbsp = id_to_mcbsp_ptr(id);
-
-	return mcbsp->max_rx_thres;
-}
-EXPORT_SYMBOL(omap_mcbsp_get_max_rx_threshold);
-
-u16 omap_mcbsp_get_fifo_size(unsigned int id)
-{
-	struct omap_mcbsp *mcbsp;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return -ENODEV;
-	}
-	mcbsp = id_to_mcbsp_ptr(id);
-
-	return mcbsp->pdata->buffer_size;
-}
-EXPORT_SYMBOL(omap_mcbsp_get_fifo_size);
-
-/*
- * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
- */
-u16 omap_mcbsp_get_tx_delay(unsigned int id)
-{
-	struct omap_mcbsp *mcbsp;
-	u16 buffstat;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return -ENODEV;
-	}
-	mcbsp = id_to_mcbsp_ptr(id);
-	if (mcbsp->pdata->buffer_size == 0)
-		return 0;
-
-	/* Returns the number of free locations in the buffer */
-	buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
-
-	/* Number of slots are different in McBSP ports */
-	return mcbsp->pdata->buffer_size - buffstat;
-}
-EXPORT_SYMBOL(omap_mcbsp_get_tx_delay);
-
-/*
- * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO
- * to reach the threshold value (when the DMA will be triggered to read it)
- */
-u16 omap_mcbsp_get_rx_delay(unsigned int id)
-{
-	struct omap_mcbsp *mcbsp;
-	u16 buffstat, threshold;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return -ENODEV;
-	}
-	mcbsp = id_to_mcbsp_ptr(id);
-	if (mcbsp->pdata->buffer_size == 0)
-		return 0;
-
-	/* Returns the number of used locations in the buffer */
-	buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
-	/* RX threshold */
-	threshold = MCBSP_READ(mcbsp, THRSH1);
-
-	/* Return the number of location till we reach the threshold limit */
-	if (threshold <= buffstat)
-		return 0;
-	else
-		return threshold - buffstat;
-}
-EXPORT_SYMBOL(omap_mcbsp_get_rx_delay);
-
-/*
- * omap_mcbsp_get_dma_op_mode just return the current configured
- * operating mode for the mcbsp channel
- */
-int omap_mcbsp_get_dma_op_mode(unsigned int id)
-{
-	struct omap_mcbsp *mcbsp;
-	int dma_op_mode;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%u)\n", __func__, id + 1);
-		return -ENODEV;
-	}
-	mcbsp = id_to_mcbsp_ptr(id);
-
-	dma_op_mode = mcbsp->dma_op_mode;
-
-	return dma_op_mode;
-}
-EXPORT_SYMBOL(omap_mcbsp_get_dma_op_mode);
-
-int omap_mcbsp_request(unsigned int id)
-{
-	struct omap_mcbsp *mcbsp;
-	void *reg_cache;
-	int err;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return -ENODEV;
-	}
-	mcbsp = id_to_mcbsp_ptr(id);
-
-	reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL);
-	if (!reg_cache) {
-		return -ENOMEM;
-	}
-
-	spin_lock(&mcbsp->lock);
-	if (!mcbsp->free) {
-		dev_err(mcbsp->dev, "McBSP%d is currently in use\n",
-			mcbsp->id);
-		err = -EBUSY;
-		goto err_kfree;
-	}
-
-	mcbsp->free = false;
-	mcbsp->reg_cache = reg_cache;
-	spin_unlock(&mcbsp->lock);
-
-	if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request)
-		mcbsp->pdata->ops->request(id);
-
-	pm_runtime_get_sync(mcbsp->dev);
-
-	/* Enable wakeup behavior */
-	if (mcbsp->pdata->has_wakeup)
-		MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
-
-	/*
-	 * Make sure that transmitter, receiver and sample-rate generator are
-	 * not running before activating IRQs.
-	 */
-	MCBSP_WRITE(mcbsp, SPCR1, 0);
-	MCBSP_WRITE(mcbsp, SPCR2, 0);
-
-	err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler,
-				0, "McBSP", (void *)mcbsp);
-	if (err != 0) {
-		dev_err(mcbsp->dev, "Unable to request TX IRQ %d "
-				"for McBSP%d\n", mcbsp->tx_irq,
-				mcbsp->id);
-		goto err_clk_disable;
-	}
-
-	if (mcbsp->rx_irq) {
-		err = request_irq(mcbsp->rx_irq,
-				omap_mcbsp_rx_irq_handler,
-				0, "McBSP", (void *)mcbsp);
-		if (err != 0) {
-			dev_err(mcbsp->dev, "Unable to request RX IRQ %d "
-					"for McBSP%d\n", mcbsp->rx_irq,
-					mcbsp->id);
-			goto err_free_irq;
-		}
-	}
-
-	return 0;
-err_free_irq:
-	free_irq(mcbsp->tx_irq, (void *)mcbsp);
-err_clk_disable:
-	if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
-		mcbsp->pdata->ops->free(id);
-
-	/* Disable wakeup behavior */
-	if (mcbsp->pdata->has_wakeup)
-		MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
-
-	pm_runtime_put_sync(mcbsp->dev);
-
-	spin_lock(&mcbsp->lock);
-	mcbsp->free = true;
-	mcbsp->reg_cache = NULL;
-err_kfree:
-	spin_unlock(&mcbsp->lock);
-	kfree(reg_cache);
-
-	return err;
-}
-EXPORT_SYMBOL(omap_mcbsp_request);
-
-void omap_mcbsp_free(unsigned int id)
-{
-	struct omap_mcbsp *mcbsp;
-	void *reg_cache;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return;
-	}
-	mcbsp = id_to_mcbsp_ptr(id);
-
-	if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
-		mcbsp->pdata->ops->free(id);
-
-	/* Disable wakeup behavior */
-	if (mcbsp->pdata->has_wakeup)
-		MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
-
-	pm_runtime_put_sync(mcbsp->dev);
-
-	if (mcbsp->rx_irq)
-		free_irq(mcbsp->rx_irq, (void *)mcbsp);
-	free_irq(mcbsp->tx_irq, (void *)mcbsp);
-
-	reg_cache = mcbsp->reg_cache;
-
-	spin_lock(&mcbsp->lock);
-	if (mcbsp->free)
-		dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id);
-	else
-		mcbsp->free = true;
-	mcbsp->reg_cache = NULL;
-	spin_unlock(&mcbsp->lock);
-
-	if (reg_cache)
-		kfree(reg_cache);
-}
-EXPORT_SYMBOL(omap_mcbsp_free);
-
-/*
- * Here we start the McBSP, by enabling transmitter, receiver or both.
- * If no transmitter or receiver is active prior calling, then sample-rate
- * generator and frame sync are started.
- */
-void omap_mcbsp_start(unsigned int id, int tx, int rx)
-{
-	struct omap_mcbsp *mcbsp;
-	int enable_srg = 0;
-	u16 w;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return;
-	}
-	mcbsp = id_to_mcbsp_ptr(id);
-
-	if (mcbsp->st_data)
-		omap_st_start(mcbsp);
-
-	/* Only enable SRG, if McBSP is master */
-	w = MCBSP_READ_CACHE(mcbsp, PCR0);
-	if (w & (FSXM | FSRM | CLKXM | CLKRM))
-		enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
-				MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
-
-	if (enable_srg) {
-		/* Start the sample generator */
-		w = MCBSP_READ_CACHE(mcbsp, SPCR2);
-		MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
-	}
-
-	/* Enable transmitter and receiver */
-	tx &= 1;
-	w = MCBSP_READ_CACHE(mcbsp, SPCR2);
-	MCBSP_WRITE(mcbsp, SPCR2, w | tx);
-
-	rx &= 1;
-	w = MCBSP_READ_CACHE(mcbsp, SPCR1);
-	MCBSP_WRITE(mcbsp, SPCR1, w | rx);
-
-	/*
-	 * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec
-	 * REVISIT: 100us may give enough time for two CLKSRG, however
-	 * due to some unknown PM related, clock gating etc. reason it
-	 * is now at 500us.
-	 */
-	udelay(500);
-
-	if (enable_srg) {
-		/* Start frame sync */
-		w = MCBSP_READ_CACHE(mcbsp, SPCR2);
-		MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
-	}
-
-	if (mcbsp->pdata->has_ccr) {
-		/* Release the transmitter and receiver */
-		w = MCBSP_READ_CACHE(mcbsp, XCCR);
-		w &= ~(tx ? XDISABLE : 0);
-		MCBSP_WRITE(mcbsp, XCCR, w);
-		w = MCBSP_READ_CACHE(mcbsp, RCCR);
-		w &= ~(rx ? RDISABLE : 0);
-		MCBSP_WRITE(mcbsp, RCCR, w);
-	}
-
-	/* Dump McBSP Regs */
-	omap_mcbsp_dump_reg(id);
-}
-EXPORT_SYMBOL(omap_mcbsp_start);
-
-void omap_mcbsp_stop(unsigned int id, int tx, int rx)
-{
-	struct omap_mcbsp *mcbsp;
-	int idle;
-	u16 w;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
-		return;
-	}
-
-	mcbsp = id_to_mcbsp_ptr(id);
-
-	/* Reset transmitter */
-	tx &= 1;
-	if (mcbsp->pdata->has_ccr) {
-		w = MCBSP_READ_CACHE(mcbsp, XCCR);
-		w |= (tx ? XDISABLE : 0);
-		MCBSP_WRITE(mcbsp, XCCR, w);
-	}
-	w = MCBSP_READ_CACHE(mcbsp, SPCR2);
-	MCBSP_WRITE(mcbsp, SPCR2, w & ~tx);
-
-	/* Reset receiver */
-	rx &= 1;
-	if (mcbsp->pdata->has_ccr) {
-		w = MCBSP_READ_CACHE(mcbsp, RCCR);
-		w |= (rx ? RDISABLE : 0);
-		MCBSP_WRITE(mcbsp, RCCR, w);
-	}
-	w = MCBSP_READ_CACHE(mcbsp, SPCR1);
-	MCBSP_WRITE(mcbsp, SPCR1, w & ~rx);
-
-	idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
-			MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
-
-	if (idle) {
-		/* Reset the sample rate generator */
-		w = MCBSP_READ_CACHE(mcbsp, SPCR2);
-		MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6));
-	}
-
-	if (mcbsp->st_data)
-		omap_st_stop(mcbsp);
-}
-EXPORT_SYMBOL(omap_mcbsp_stop);
-
-int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id)
-{
-	struct omap_mcbsp *mcbsp;
-	const char *src;
-
-	if (!omap_mcbsp_check_valid_id(id)) {
-		pr_err("%s: Invalid id (%d)\n", __func__, id + 1);
-		return -EINVAL;
-	}
-	mcbsp = id_to_mcbsp_ptr(id);
-
-	if (fck_src_id == MCBSP_CLKS_PAD_SRC)
-		src = "clks_ext";
-	else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
-		src = "clks_fclk";
-	else
-		return -EINVAL;
-
-	if (mcbsp->pdata->set_clk_src)
-		return mcbsp->pdata->set_clk_src(mcbsp->dev, mcbsp->fclk, src);
-	else
-		return -EINVAL;
-}
-EXPORT_SYMBOL(omap2_mcbsp_set_clks_src);
-
-void omap2_mcbsp1_mux_clkr_src(u8 mux)
-{
-	struct omap_mcbsp *mcbsp;
-	const char *src;
-
-	if (mux == CLKR_SRC_CLKR)
-		src = "clkr";
-	else if (mux == CLKR_SRC_CLKX)
-		src = "clkx";
-	else
-		return;
-
-	mcbsp = id_to_mcbsp_ptr(0);
-	if (mcbsp->pdata->mux_signal)
-		mcbsp->pdata->mux_signal(mcbsp->dev, "clkr", src);
-}
-EXPORT_SYMBOL(omap2_mcbsp1_mux_clkr_src);
-
-void omap2_mcbsp1_mux_fsr_src(u8 mux)
-{
-	struct omap_mcbsp *mcbsp;
-	const char *src;
-
-	if (mux == FSR_SRC_FSR)
-		src = "fsr";
-	else if (mux == FSR_SRC_FSX)
-		src = "fsx";
-	else
-		return;
-
-	mcbsp = id_to_mcbsp_ptr(0);
-	if (mcbsp->pdata->mux_signal)
-		mcbsp->pdata->mux_signal(mcbsp->dev, "fsr", src);
-}
-EXPORT_SYMBOL(omap2_mcbsp1_mux_fsr_src);
-
-#define max_thres(m)			(mcbsp->pdata->buffer_size)
-#define valid_threshold(m, val)		((val) <= max_thres(m))
-#define THRESHOLD_PROP_BUILDER(prop)					\
-static ssize_t prop##_show(struct device *dev,				\
-			struct device_attribute *attr, char *buf)	\
-{									\
-	struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);		\
-									\
-	return sprintf(buf, "%u\n", mcbsp->prop);			\
-}									\
-									\
-static ssize_t prop##_store(struct device *dev,				\
-				struct device_attribute *attr,		\
-				const char *buf, size_t size)		\
-{									\
-	struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);		\
-	unsigned long val;						\
-	int status;							\
-									\
-	status = strict_strtoul(buf, 0, &val);				\
-	if (status)							\
-		return status;						\
-									\
-	if (!valid_threshold(mcbsp, val))				\
-		return -EDOM;						\
-									\
-	mcbsp->prop = val;						\
-	return size;							\
-}									\
-									\
-static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store);
-
-THRESHOLD_PROP_BUILDER(max_tx_thres);
-THRESHOLD_PROP_BUILDER(max_rx_thres);
-
-static const char *dma_op_modes[] = {
-	"element", "threshold", "frame",
-};
-
-static ssize_t dma_op_mode_show(struct device *dev,
-			struct device_attribute *attr, char *buf)
-{
-	struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
-	int dma_op_mode, i = 0;
-	ssize_t len = 0;
-	const char * const *s;
-
-	dma_op_mode = mcbsp->dma_op_mode;
-
-	for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) {
-		if (dma_op_mode == i)
-			len += sprintf(buf + len, "[%s] ", *s);
-		else
-			len += sprintf(buf + len, "%s ", *s);
-	}
-	len += sprintf(buf + len, "\n");
-
-	return len;
-}
-
-static ssize_t dma_op_mode_store(struct device *dev,
-				struct device_attribute *attr,
-				const char *buf, size_t size)
-{
-	struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
-	const char * const *s;
-	int i = 0;
-
-	for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++)
-		if (sysfs_streq(buf, *s))
-			break;
-
-	if (i == ARRAY_SIZE(dma_op_modes))
-		return -EINVAL;
-
-	spin_lock_irq(&mcbsp->lock);
-	if (!mcbsp->free) {
-		size = -EBUSY;
-		goto unlock;
-	}
-	mcbsp->dma_op_mode = i;
-
-unlock:
-	spin_unlock_irq(&mcbsp->lock);
-
-	return size;
-}
-
-static DEVICE_ATTR(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store);
-
-static const struct attribute *additional_attrs[] = {
-	&dev_attr_max_tx_thres.attr,
-	&dev_attr_max_rx_thres.attr,
-	&dev_attr_dma_op_mode.attr,
-	NULL,
-};
-
-static const struct attribute_group additional_attr_group = {
-	.attrs = (struct attribute **)additional_attrs,
-};
-
-static ssize_t st_taps_show(struct device *dev,
-			    struct device_attribute *attr, char *buf)
-{
-	struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
-	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-	ssize_t status = 0;
-	int i;
-
-	spin_lock_irq(&mcbsp->lock);
-	for (i = 0; i < st_data->nr_taps; i++)
-		status += sprintf(&buf[status], (i ? ", %d" : "%d"),
-				  st_data->taps[i]);
-	if (i)
-		status += sprintf(&buf[status], "\n");
-	spin_unlock_irq(&mcbsp->lock);
-
-	return status;
-}
-
-static ssize_t st_taps_store(struct device *dev,
-			     struct device_attribute *attr,
-			     const char *buf, size_t size)
-{
-	struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
-	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-	int val, tmp, status, i = 0;
-
-	spin_lock_irq(&mcbsp->lock);
-	memset(st_data->taps, 0, sizeof(st_data->taps));
-	st_data->nr_taps = 0;
-
-	do {
-		status = sscanf(buf, "%d%n", &val, &tmp);
-		if (status < 0 || status == 0) {
-			size = -EINVAL;
-			goto out;
-		}
-		if (val < -32768 || val > 32767) {
-			size = -EINVAL;
-			goto out;
-		}
-		st_data->taps[i++] = val;
-		buf += tmp;
-		if (*buf != ',')
-			break;
-		buf++;
-	} while (1);
-
-	st_data->nr_taps = i;
-
-out:
-	spin_unlock_irq(&mcbsp->lock);
-
-	return size;
-}
-
-static DEVICE_ATTR(st_taps, 0644, st_taps_show, st_taps_store);
-
-static const struct attribute *sidetone_attrs[] = {
-	&dev_attr_st_taps.attr,
-	NULL,
-};
-
-static const struct attribute_group sidetone_attr_group = {
-	.attrs = (struct attribute **)sidetone_attrs,
-};
-
-static int __devinit omap_st_add(struct omap_mcbsp *mcbsp,
-				 struct resource *res)
-{
-	struct omap_mcbsp_st_data *st_data;
-	int err;
-
-	st_data = kzalloc(sizeof(*mcbsp->st_data), GFP_KERNEL);
-	if (!st_data) {
-		err = -ENOMEM;
-		goto err1;
-	}
-
-	st_data->io_base_st = ioremap(res->start, resource_size(res));
-	if (!st_data->io_base_st) {
-		err = -ENOMEM;
-		goto err2;
-	}
-
-	err = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
-	if (err)
-		goto err3;
-
-	mcbsp->st_data = st_data;
-	return 0;
-
-err3:
-	iounmap(st_data->io_base_st);
-err2:
-	kfree(st_data);
-err1:
-	return err;
-
-}
-
-static void __devexit omap_st_remove(struct omap_mcbsp *mcbsp)
-{
-	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
-	sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
-	iounmap(st_data->io_base_st);
-	kfree(st_data);
-}
-
-/*
- * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
- * 730 has only 2 McBSP, and both of them are MPU peripherals.
- */
-static int __devinit omap_mcbsp_probe(struct platform_device *pdev)
-{
-	struct omap_mcbsp_platform_data *pdata = pdev->dev.platform_data;
-	struct omap_mcbsp *mcbsp;
-	int id = pdev->id - 1;
-	struct resource *res;
-	int ret = 0;
-
-	if (!pdata) {
-		dev_err(&pdev->dev, "McBSP device initialized without"
-				"platform data\n");
-		ret = -EINVAL;
-		goto exit;
-	}
-
-	dev_dbg(&pdev->dev, "Initializing OMAP McBSP (%d).\n", pdev->id);
-
-	if (id >= omap_mcbsp_count) {
-		dev_err(&pdev->dev, "Invalid McBSP device id (%d)\n", id);
-		ret = -EINVAL;
-		goto exit;
-	}
-
-	mcbsp = kzalloc(sizeof(struct omap_mcbsp), GFP_KERNEL);
-	if (!mcbsp) {
-		ret = -ENOMEM;
-		goto exit;
-	}
-
-	spin_lock_init(&mcbsp->lock);
-	mcbsp->id = id + 1;
-	mcbsp->free = true;
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
-	if (!res) {
-		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-		if (!res) {
-			dev_err(&pdev->dev, "%s:mcbsp%d has invalid memory"
-					"resource\n", __func__, pdev->id);
-			ret = -ENOMEM;
-			goto exit;
-		}
-	}
-	mcbsp->phys_base = res->start;
-	mcbsp->reg_cache_size = resource_size(res);
-	mcbsp->io_base = ioremap(res->start, resource_size(res));
-	if (!mcbsp->io_base) {
-		ret = -ENOMEM;
-		goto err_ioremap;
-	}
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
-	if (!res)
-		mcbsp->phys_dma_base = mcbsp->phys_base;
-	else
-		mcbsp->phys_dma_base = res->start;
-
-	mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
-	mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
-
-	/* From OMAP4 there will be a single irq line */
-	if (mcbsp->tx_irq == -ENXIO)
-		mcbsp->tx_irq = platform_get_irq(pdev, 0);
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
-	if (!res) {
-		dev_err(&pdev->dev, "%s:mcbsp%d has invalid rx DMA channel\n",
-					__func__, pdev->id);
-		ret = -ENODEV;
-		goto err_res;
-	}
-	mcbsp->dma_rx_sync = res->start;
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
-	if (!res) {
-		dev_err(&pdev->dev, "%s:mcbsp%d has invalid tx DMA channel\n",
-					__func__, pdev->id);
-		ret = -ENODEV;
-		goto err_res;
-	}
-	mcbsp->dma_tx_sync = res->start;
-
-	mcbsp->fclk = clk_get(&pdev->dev, "fck");
-	if (IS_ERR(mcbsp->fclk)) {
-		ret = PTR_ERR(mcbsp->fclk);
-		dev_err(&pdev->dev, "unable to get fck: %d\n", ret);
-		goto err_res;
-	}
-
-	mcbsp->pdata = pdata;
-	mcbsp->dev = &pdev->dev;
-	mcbsp_ptr[id] = mcbsp;
-	platform_set_drvdata(pdev, mcbsp);
-	pm_runtime_enable(mcbsp->dev);
-
-	mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
-	if (mcbsp->pdata->buffer_size) {
-		/*
-		 * Initially configure the maximum thresholds to a safe value.
-		 * The McBSP FIFO usage with these values should not go under
-		 * 16 locations.
-		 * If the whole FIFO without safety buffer is used, than there
-		 * is a possibility that the DMA will be not able to push the
-		 * new data on time, causing channel shifts in runtime.
-		 */
-		mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
-		mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
-
-		ret = sysfs_create_group(&mcbsp->dev->kobj,
-					 &additional_attr_group);
-		if (ret) {
-			dev_err(mcbsp->dev,
-				"Unable to create additional controls\n");
-			goto err_thres;
-		}
-	} else {
-		mcbsp->max_tx_thres = -EINVAL;
-		mcbsp->max_rx_thres = -EINVAL;
-	}
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
-	if (res) {
-		ret = omap_st_add(mcbsp, res);
-		if (ret) {
-			dev_err(mcbsp->dev,
-				"Unable to create sidetone controls\n");
-			goto err_st;
-		}
-	}
-
-	return 0;
-
-err_st:
-	if (mcbsp->pdata->buffer_size)
-		sysfs_remove_group(&mcbsp->dev->kobj,
-				   &additional_attr_group);
-err_thres:
-	clk_put(mcbsp->fclk);
-err_res:
-	iounmap(mcbsp->io_base);
-err_ioremap:
-	kfree(mcbsp);
-exit:
-	return ret;
-}
-
-static int __devexit omap_mcbsp_remove(struct platform_device *pdev)
-{
-	struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
-
-	platform_set_drvdata(pdev, NULL);
-	if (mcbsp) {
-
-		if (mcbsp->pdata && mcbsp->pdata->ops &&
-				mcbsp->pdata->ops->free)
-			mcbsp->pdata->ops->free(mcbsp->id);
-
-		if (mcbsp->pdata->buffer_size)
-			sysfs_remove_group(&mcbsp->dev->kobj,
-					   &additional_attr_group);
-
-		if (mcbsp->st_data)
-			omap_st_remove(mcbsp);
-
-		clk_put(mcbsp->fclk);
-
-		iounmap(mcbsp->io_base);
-		kfree(mcbsp);
-	}
-
-	return 0;
-}
-
-static struct platform_driver omap_mcbsp_driver = {
-	.probe		= omap_mcbsp_probe,
-	.remove		= __devexit_p(omap_mcbsp_remove),
-	.driver		= {
-		.name	= "omap-mcbsp",
-	},
-};
-
-int __init omap_mcbsp_init(void)
-{
-	/* Register the McBSP driver */
-	return platform_driver_register(&omap_mcbsp_driver);
-}
diff --git a/arch/arm/plat-omap/mux.c b/arch/arm/plat-omap/mux.c
index 0d4aa0d..cff8712 100644
--- a/arch/arm/plat-omap/mux.c
+++ b/arch/arm/plat-omap/mux.c
@@ -26,8 +26,11 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/io.h>
-#include <asm/system.h>
 #include <linux/spinlock.h>
+
+#include <asm/system.h>
+
+#include <plat/cpu.h>
 #include <plat/mux.h>
 
 #ifdef CONFIG_OMAP_MUX
diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c
index 3dc3801..5a97b4d 100644
--- a/arch/arm/plat-omap/omap-pm-noop.c
+++ b/arch/arm/plat-omap/omap-pm-noop.c
@@ -319,7 +319,7 @@
 	if (WARN_ON(!dev))
 		return -ENODEV;
 
-	if (dev->parent == &omap_device_parent) {
+	if (dev->pm_domain == &omap_device_pm_domain) {
 		count = omap_device_get_context_loss_count(pdev);
 	} else {
 		WARN_ONCE(off_mode_enabled, "omap_pm: using dummy context loss counter; device %s should be converted to omap_device",
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index e8d9869..d50cbc6 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -1,3 +1,4 @@
+
 /*
  * omap_device implementation
  *
@@ -97,14 +98,7 @@
 #define USE_WAKEUP_LAT			0
 #define IGNORE_WAKEUP_LAT		1
 
-static int omap_device_register(struct platform_device *pdev);
 static int omap_early_device_register(struct platform_device *pdev);
-static struct omap_device *omap_device_alloc(struct platform_device *pdev,
-				      struct omap_hwmod **ohs, int oh_cnt,
-				      struct omap_device_pm_latency *pm_lats,
-				      int pm_lats_cnt);
-static void omap_device_delete(struct omap_device *od);
-
 
 static struct omap_device_pm_latency omap_default_latency[] = {
 	{
@@ -320,8 +314,6 @@
 }
 
 
-static struct dev_pm_domain omap_device_pm_domain;
-
 /**
  * omap_device_build_from_dt - build an omap_device with multiple hwmods
  * @pdev_name: name of the platform_device driver to use
@@ -348,7 +340,7 @@
 
 	oh_cnt = of_property_count_strings(node, "ti,hwmods");
 	if (!oh_cnt || IS_ERR_VALUE(oh_cnt)) {
-		dev_warn(&pdev->dev, "No 'hwmods' to build omap_device\n");
+		dev_dbg(&pdev->dev, "No 'hwmods' to build omap_device\n");
 		return -ENODEV;
 	}
 
@@ -509,7 +501,7 @@
  *
  * Returns an struct omap_device pointer or ERR_PTR() on error;
  */
-static struct omap_device *omap_device_alloc(struct platform_device *pdev,
+struct omap_device *omap_device_alloc(struct platform_device *pdev,
 					struct omap_hwmod **ohs, int oh_cnt,
 					struct omap_device_pm_latency *pm_lats,
 					int pm_lats_cnt)
@@ -591,7 +583,7 @@
 	return ERR_PTR(ret);
 }
 
-static void omap_device_delete(struct omap_device *od)
+void omap_device_delete(struct omap_device *od)
 {
 	if (!od)
 		return;
@@ -619,7 +611,7 @@
  * information.  Returns ERR_PTR(-EINVAL) if @oh is NULL; otherwise,
  * passes along the return value of omap_device_build_ss().
  */
-struct platform_device *omap_device_build(const char *pdev_name, int pdev_id,
+struct platform_device __init *omap_device_build(const char *pdev_name, int pdev_id,
 				      struct omap_hwmod *oh, void *pdata,
 				      int pdata_len,
 				      struct omap_device_pm_latency *pm_lats,
@@ -652,7 +644,7 @@
  * platform_device record.  Returns an ERR_PTR() on error, or passes
  * along the return value of omap_device_register().
  */
-struct platform_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
+struct platform_device __init *omap_device_build_ss(const char *pdev_name, int pdev_id,
 					 struct omap_hwmod **ohs, int oh_cnt,
 					 void *pdata, int pdata_len,
 					 struct omap_device_pm_latency *pm_lats,
@@ -717,7 +709,7 @@
  * platform_early_add_device() on the underlying platform_device.
  * Returns 0 by default.
  */
-static int omap_early_device_register(struct platform_device *pdev)
+static int __init omap_early_device_register(struct platform_device *pdev)
 {
 	struct platform_device *devices[1];
 
@@ -762,14 +754,12 @@
 	struct omap_device *od = to_omap_device(pdev);
 	int ret;
 
-	if (od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND)
-		return pm_generic_suspend_noirq(dev);
-
 	ret = pm_generic_suspend_noirq(dev);
 
 	if (!ret && !pm_runtime_status_suspended(dev)) {
 		if (pm_generic_runtime_suspend(dev) == 0) {
-			omap_device_idle(pdev);
+			if (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND))
+				omap_device_idle(pdev);
 			od->flags |= OMAP_DEVICE_SUSPENDED;
 		}
 	}
@@ -782,13 +772,11 @@
 	struct platform_device *pdev = to_platform_device(dev);
 	struct omap_device *od = to_omap_device(pdev);
 
-	if (od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND)
-		return pm_generic_resume_noirq(dev);
-
 	if ((od->flags & OMAP_DEVICE_SUSPENDED) &&
 	    !pm_runtime_status_suspended(dev)) {
 		od->flags &= ~OMAP_DEVICE_SUSPENDED;
-		omap_device_enable(pdev);
+		if (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND))
+			omap_device_enable(pdev);
 		pm_generic_runtime_resume(dev);
 	}
 
@@ -799,7 +787,7 @@
 #define _od_resume_noirq NULL
 #endif
 
-static struct dev_pm_domain omap_device_pm_domain = {
+struct dev_pm_domain omap_device_pm_domain = {
 	.ops = {
 		SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
 				   _od_runtime_idle)
@@ -817,11 +805,10 @@
  * platform_device_register() on the underlying platform_device.
  * Returns the return value of platform_device_register().
  */
-static int omap_device_register(struct platform_device *pdev)
+int omap_device_register(struct platform_device *pdev)
 {
 	pr_debug("omap_device: %s: registering\n", pdev->name);
 
-	pdev->dev.parent = &omap_device_parent;
 	pdev->dev.pm_domain = &omap_device_pm_domain;
 	return platform_device_add(pdev);
 }
@@ -1130,11 +1117,6 @@
 	return 0;
 }
 
-struct device omap_device_parent = {
-	.init_name	= "omap",
-	.parent         = &platform_bus,
-};
-
 static struct notifier_block platform_nb = {
 	.notifier_call = _omap_device_notifier_call,
 };
@@ -1142,6 +1124,6 @@
 static int __init omap_device_init(void)
 {
 	bus_register_notifier(&platform_bus_type, &platform_nb);
-	return device_register(&omap_device_parent);
+	return 0;
 }
 core_initcall(omap_device_init);
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index 4243bdc..eec98af 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -31,11 +31,10 @@
 
 #include "sram.h"
 
-/* XXX These "sideways" includes are a sign that something is wrong */
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-# include "../mach-omap2/prm2xxx_3xxx.h"
-# include "../mach-omap2/sdrc.h"
-#endif
+/* XXX These "sideways" includes will disappear when sram.c becomes a driver */
+#include "../mach-omap2/iomap.h"
+#include "../mach-omap2/prm2xxx_3xxx.h"
+#include "../mach-omap2/sdrc.h"
 
 #define OMAP1_SRAM_PA		0x20000000
 #define OMAP2_SRAM_PUB_PA	(OMAP2_SRAM_PA + 0xf800)
@@ -86,7 +85,7 @@
 			__raw_writel(0xCFDE, OMAP24XX_VA_READPERM0);  /* all i-read */
 			__raw_writel(0xCFDE, OMAP24XX_VA_WRITEPERM0); /* all i-write */
 		}
-		if (cpu_is_omap34xx()) {
+		if (cpu_is_omap34xx() && !cpu_is_am33xx()) {
 			__raw_writel(0xFFFF, OMAP34XX_VA_REQINFOPERM0); /* all q-vects */
 			__raw_writel(0xFFFF, OMAP34XX_VA_READPERM0);  /* all i-read */
 			__raw_writel(0xFFFF, OMAP34XX_VA_WRITEPERM0); /* all i-write */
@@ -124,7 +123,10 @@
 				omap_sram_size = 0x800; /* 2K */
 			}
 		} else {
-			if (cpu_is_omap34xx()) {
+			if (cpu_is_am33xx()) {
+				omap_sram_start = AM33XX_SRAM_PA;
+				omap_sram_size = 0x10000; /* 64K */
+			} else if (cpu_is_omap34xx()) {
 				omap_sram_start = OMAP3_SRAM_PA;
 				omap_sram_size = 0x10000; /* 64K */
 			} else if (cpu_is_omap44xx()) {
@@ -368,6 +370,11 @@
 	return 0;
 }
 
+static inline int am33xx_sram_init(void)
+{
+	return 0;
+}
+
 int __init omap_sram_init(void)
 {
 	omap_detect_sram();
@@ -379,6 +386,8 @@
 		omap242x_sram_init();
 	else if (cpu_is_omap2430())
 		omap243x_sram_init();
+	else if (cpu_is_am33xx())
+		am33xx_sram_init();
 	else if (cpu_is_omap34xx())
 		omap34xx_sram_init();
 
diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c
index f357088..d2bbfd1 100644
--- a/arch/arm/plat-omap/usb.c
+++ b/arch/arm/plat-omap/usb.c
@@ -29,6 +29,10 @@
 #include <plat/usb.h>
 #include <plat/board.h>
 
+#include <mach/hardware.h>
+
+#include "../mach-omap2/common.h"
+
 #ifdef	CONFIG_ARCH_OMAP_OTG
 
 void __init
diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c
index 089899a..74daf5e 100644
--- a/arch/arm/plat-orion/common.c
+++ b/arch/arm/plat-orion/common.c
@@ -21,6 +21,7 @@
 #include <plat/orion_wdt.h>
 #include <plat/mv_xor.h>
 #include <plat/ehci-orion.h>
+#include <mach/bridge-regs.h>
 
 /* Fill in the resources structure and link it into the platform
    device structure. There is always a memory region, and nearly
@@ -568,13 +569,17 @@
  ****************************************************************************/
 static struct orion_wdt_platform_data orion_wdt_data;
 
+static struct resource orion_wdt_resource =
+		DEFINE_RES_MEM(TIMER_VIRT_BASE, 0x28);
+
 static struct platform_device orion_wdt_device = {
 	.name		= "orion_wdt",
 	.id		= -1,
 	.dev		= {
 		.platform_data	= &orion_wdt_data,
 	},
-	.num_resources	= 0,
+	.resource	= &orion_wdt_resource,
+	.num_resources	= 1,
 };
 
 void __init orion_wdt_init(unsigned long tclk)
diff --git a/arch/arm/plat-orion/include/plat/audio.h b/arch/arm/plat-orion/include/plat/audio.h
index 885f8ab..d6a55bd 100644
--- a/arch/arm/plat-orion/include/plat/audio.h
+++ b/arch/arm/plat-orion/include/plat/audio.h
@@ -2,7 +2,6 @@
 #define __PLAT_AUDIO_H
 
 struct kirkwood_asoc_platform_data {
-	u32 tclk;
 	int burst;
 };
 #endif
diff --git a/arch/arm/plat-pxa/dma.c b/arch/arm/plat-pxa/dma.c
index 2d3c19d..79ef102 100644
--- a/arch/arm/plat-pxa/dma.c
+++ b/arch/arm/plat-pxa/dma.c
@@ -20,7 +20,6 @@
 #include <linux/errno.h>
 #include <linux/dma-mapping.h>
 
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/memory.h>
 #include <mach/hardware.h>
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
index d8973ac..21bf6ad 100644
--- a/arch/arm/plat-s3c24xx/Kconfig
+++ b/arch/arm/plat-s3c24xx/Kconfig
@@ -4,7 +4,7 @@
 
 config PLAT_S3C24XX
 	bool
-	depends on ARCH_S3C2410
+	depends on ARCH_S3C24XX
 	default y
 	select NO_IOPORT
 	select ARCH_REQUIRE_GPIOLIB
@@ -44,12 +44,6 @@
 	  Clock code for the S3C2410, and similar processors which
 	  is currently includes the S3C2410, S3C2440, S3C2442.
 
-config S3C2443_CLOCK
-	bool
-	help
-	  Clock code for the S3C2443 and similar processors, which includes
-	  the S3C2416 and S3C2450.
-
 config S3C24XX_DCLK
 	bool
 	help
@@ -76,15 +70,9 @@
 	  Add an extra 128 gpio numbers to the available GPIO pool. This is
 	  available for boards that need extra gpios for external devices.
 
-config PM_SIMTEC
-	bool
-	help
-	  Common power management code for systems that are
-	  compatible with the Simtec style of power management
-
-config S3C2410_DMA
+config S3C24XX_DMA
 	bool "S3C2410 DMA support"
-	depends on ARCH_S3C2410
+	depends on ARCH_S3C24XX
 	select S3C_DMA
 	help
 	  S3C2410 DMA support. This is needed for drivers like sound which
@@ -93,31 +81,11 @@
 
 config S3C2410_DMA_DEBUG
 	bool "S3C2410 DMA support debug"
-	depends on ARCH_S3C2410 && S3C2410_DMA
+	depends on ARCH_S3C24XX && S3C2410_DMA
 	help
 	  Enable debugging output for the DMA code. This option sends info
 	  to the kernel log, at priority KERN_DEBUG.
 
-# SPI default pin configuration code
-
-config S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13
-	bool
-	help
-	  SPI GPIO configuration code for BUS0 when connected to
-	  GPE11, GPE12 and GPE13.
-
-config S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7
-	bool
-	help
-	  SPI GPIO configuration code for BUS 1 when connected to
-	  GPG5, GPG6 and GPG7.
-
-config S3C24XX_SPI_BUS1_GPD8_GPD9_GPD10
-	bool
-	help
-	  SPI GPIO configuration code for BUS 1 when connected to
-	  GPD8, GPD9 and GPD10.
-
 # common code for s3c24xx based machines, such as the SMDKs.
 
 # cpu frequency items common between s3c2410 and s3c2440/s3c2442
@@ -145,21 +113,4 @@
 	  Intel node to select io timing code that is common to the s3c2412
 	  and the s3c2443.
 
-config MACH_SMDK
-	bool
-	help
-	  Common machine code for SMDK2410 and SMDK2440
-
-config S3C24XX_SIMTEC_AUDIO
-	bool
-	depends on (ARCH_BAST || MACH_VR1000 || MACH_OSIRIS || MACH_ANUBIS)
-	default y
-	help
-	  Add audio devices for common Simtec S3C24XX boards
-
-config S3C2410_SETUP_TS
-	bool
-	help
-	  Compile in platform device definition for Samsung TouchScreen.
-
 endif
diff --git a/arch/arm/plat-s3c24xx/Makefile b/arch/arm/plat-s3c24xx/Makefile
index b2b0112..2467b80 100644
--- a/arch/arm/plat-s3c24xx/Makefile
+++ b/arch/arm/plat-s3c24xx/Makefile
@@ -23,28 +23,11 @@
 
 # Architecture dependent builds
 
-obj-$(CONFIG_PM_SIMTEC)		+= pm-simtec.o
 obj-$(CONFIG_PM)		+= pm.o
 obj-$(CONFIG_PM)		+= irq-pm.o
 obj-$(CONFIG_PM)		+= sleep.o
 obj-$(CONFIG_S3C2410_CLOCK)	+= s3c2410-clock.o
-obj-$(CONFIG_S3C2443_CLOCK)	+= s3c2443-clock.o
-obj-$(CONFIG_S3C2410_DMA)	+= dma.o
+obj-$(CONFIG_S3C24XX_DMA)	+= dma.o
 obj-$(CONFIG_S3C2410_IOTIMING)	+= s3c2410-iotiming.o
 obj-$(CONFIG_S3C2412_IOTIMING)	+= s3c2412-iotiming.o
 obj-$(CONFIG_S3C2410_CPUFREQ_UTILS) += s3c2410-cpufreq-utils.o
-
-# device specific setup and/or initialisation
-obj-$(CONFIG_ARCH_S3C2410)	+= setup-i2c.o
-obj-$(CONFIG_S3C2410_SETUP_TS)	+= setup-ts.o
-
-# SPI gpio central GPIO functions
-
-obj-$(CONFIG_S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13) += spi-bus0-gpe11_12_13.o
-obj-$(CONFIG_S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7)    += spi-bus1-gpg5_6_7.o
-obj-$(CONFIG_S3C24XX_SPI_BUS1_GPD8_GPD9_GPD10)	 += spi-bus1-gpd8_9_10.o
-
-# machine common support
-
-obj-$(CONFIG_MACH_SMDK)		+= common-smdk.o
-obj-$(CONFIG_S3C24XX_SIMTEC_AUDIO)	+= simtec-audio.o
diff --git a/arch/arm/plat-s3c24xx/cpu.c b/arch/arm/plat-s3c24xx/cpu.c
index 21f1fda..290942d 100644
--- a/arch/arm/plat-s3c24xx/cpu.c
+++ b/arch/arm/plat-s3c24xx/cpu.c
@@ -32,8 +32,11 @@
 #include <linux/io.h>
 
 #include <mach/hardware.h>
+#include <mach/regs-clock.h>
 #include <asm/irq.h>
 #include <asm/cacheflush.h>
+#include <asm/system_info.h>
+#include <asm/system_misc.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -190,8 +193,34 @@
 	return __raw_readl(S3C2410_GSTATUS1);
 }
 
+static void s3c24xx_default_idle(void)
+{
+	unsigned long tmp;
+	int i;
+
+	/* idle the system by using the idle mode which will wait for an
+	 * interrupt to happen before restarting the system.
+	 */
+
+	/* Warning: going into idle state upsets jtag scanning */
+
+	__raw_writel(__raw_readl(S3C2410_CLKCON) | S3C2410_CLKCON_IDLE,
+		     S3C2410_CLKCON);
+
+	/* the samsung port seems to do a loop and then unset idle.. */
+	for (i = 0; i < 50; i++)
+		tmp += __raw_readl(S3C2410_CLKCON); /* ensure loop not optimised out */
+
+	/* this bit is not cleared on re-start... */
+
+	__raw_writel(__raw_readl(S3C2410_CLKCON) & ~S3C2410_CLKCON_IDLE,
+		     S3C2410_CLKCON);
+}
+
 void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
 {
+	arm_pm_idle = s3c24xx_default_idle;
+
 	/* initialise the io descriptors we need for initialisation */
 	iotable_init(mach_desc, size);
 	iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index 2bab4c9..28f898f 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -27,7 +27,6 @@
 #include <linux/errno.h>
 #include <linux/io.h>
 
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
 #include <mach/dma.h>
diff --git a/arch/arm/plat-s3c24xx/s3c2443-clock.c b/arch/arm/plat-s3c24xx/s3c2443-clock.c
deleted file mode 100644
index 95e6819..0000000
--- a/arch/arm/plat-s3c24xx/s3c2443-clock.c
+++ /dev/null
@@ -1,636 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/s3c2443-clock.c
- *
- * Copyright (c) 2007, 2010 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2443 Clock control suport - common code
- */
-
-#include <linux/init.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <mach/regs-s3c2443-clock.h>
-
-#include <plat/s3c2443.h>
-#include <plat/clock.h>
-#include <plat/clock-clksrc.h>
-#include <plat/cpu.h>
-
-#include <plat/cpu-freq.h>
-
-
-static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable)
-{
-	u32 ctrlbit = clk->ctrlbit;
-	u32 con = __raw_readl(reg);
-
-	if (enable)
-		con |= ctrlbit;
-	else
-		con &= ~ctrlbit;
-
-	__raw_writel(con, reg);
-	return 0;
-}
-
-int s3c2443_clkcon_enable_h(struct clk *clk, int enable)
-{
-	return s3c2443_gate(S3C2443_HCLKCON, clk, enable);
-}
-
-int s3c2443_clkcon_enable_p(struct clk *clk, int enable)
-{
-	return s3c2443_gate(S3C2443_PCLKCON, clk, enable);
-}
-
-int s3c2443_clkcon_enable_s(struct clk *clk, int enable)
-{
-	return s3c2443_gate(S3C2443_SCLKCON, clk, enable);
-}
-
-/* mpllref is a direct descendant of clk_xtal by default, but it is not
- * elided as the EPLL can be either sourced by the XTAL or EXTCLK and as
- * such directly equating the two source clocks is impossible.
- */
-struct clk clk_mpllref = {
-	.name		= "mpllref",
-	.parent		= &clk_xtal,
-};
-
-static struct clk *clk_epllref_sources[] = {
-	[0] = &clk_mpllref,
-	[1] = &clk_mpllref,
-	[2] = &clk_xtal,
-	[3] = &clk_ext,
-};
-
-struct clksrc_clk clk_epllref = {
-	.clk	= {
-		.name		= "epllref",
-	},
-	.sources = &(struct clksrc_sources) {
-		.sources = clk_epllref_sources,
-		.nr_sources = ARRAY_SIZE(clk_epllref_sources),
-	},
-	.reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 },
-};
-
-/* esysclk
- *
- * this is sourced from either the EPLL or the EPLLref clock
-*/
-
-static struct clk *clk_sysclk_sources[] = {
-	[0] = &clk_epllref.clk,
-	[1] = &clk_epll,
-};
-
-struct clksrc_clk clk_esysclk = {
-	.clk	= {
-		.name		= "esysclk",
-		.parent		= &clk_epll,
-	},
-	.sources = &(struct clksrc_sources) {
-		.sources = clk_sysclk_sources,
-		.nr_sources = ARRAY_SIZE(clk_sysclk_sources),
-	},
-	.reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 },
-};
-
-static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
-{
-	unsigned long parent_rate = clk_get_rate(clk->parent);
-	unsigned long div = __raw_readl(S3C2443_CLKDIV0);
-
-	div  &= S3C2443_CLKDIV0_EXTDIV_MASK;
-	div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1);	/* x2 */
-
-	return parent_rate / (div + 1);
-}
-
-static struct clk clk_mdivclk = {
-	.name		= "mdivclk",
-	.parent		= &clk_mpllref,
-	.ops		= &(struct clk_ops) {
-		.get_rate	= s3c2443_getrate_mdivclk,
-	},
-};
-
-static struct clk *clk_msysclk_sources[] = {
-	[0] = &clk_mpllref,
-	[1] = &clk_mpll,
-	[2] = &clk_mdivclk,
-	[3] = &clk_mpllref,
-};
-
-struct clksrc_clk clk_msysclk = {
-	.clk	= {
-		.name		= "msysclk",
-		.parent		= &clk_xtal,
-	},
-	.sources = &(struct clksrc_sources) {
-		.sources = clk_msysclk_sources,
-		.nr_sources = ARRAY_SIZE(clk_msysclk_sources),
-	},
-	.reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 },
-};
-
-/* prediv
- *
- * this divides the msysclk down to pass to h/p/etc.
- */
-
-static unsigned long s3c2443_prediv_getrate(struct clk *clk)
-{
-	unsigned long rate = clk_get_rate(clk->parent);
-	unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
-
-	clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
-	clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
-
-	return rate / (clkdiv0 + 1);
-}
-
-static struct clk clk_prediv = {
-	.name		= "prediv",
-	.parent		= &clk_msysclk.clk,
-	.ops		= &(struct clk_ops) {
-		.get_rate	= s3c2443_prediv_getrate,
-	},
-};
-
-/* armdiv
- *
- * this clock is sourced from msysclk and can have a number of
- * divider values applied to it to then be fed into armclk.
-*/
-
-static unsigned int *armdiv;
-static int nr_armdiv;
-static int armdivmask;
-
-static unsigned long s3c2443_armclk_roundrate(struct clk *clk,
-					      unsigned long rate)
-{
-	unsigned long parent = clk_get_rate(clk->parent);
-	unsigned long calc;
-	unsigned best = 256; /* bigger than any value */
-	unsigned div;
-	int ptr;
-
-	if (!nr_armdiv)
-		return -EINVAL;
-
-	for (ptr = 0; ptr < nr_armdiv; ptr++) {
-		div = armdiv[ptr];
-		if (div) {
-			/* cpufreq provides 266mhz as 266666000 not 266666666 */
-			calc = (parent / div / 1000) * 1000;
-			if (calc <= rate && div < best)
-				best = div;
-		}
-	}
-
-	return parent / best;
-}
-
-static unsigned long s3c2443_armclk_getrate(struct clk *clk)
-{
-	unsigned long rate = clk_get_rate(clk->parent);
-	unsigned long clkcon0;
-	int val;
-
-	if (!nr_armdiv || !armdivmask)
-		return -EINVAL;
-
-	clkcon0 = __raw_readl(S3C2443_CLKDIV0);
-	clkcon0 &= armdivmask;
-	val = clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT;
-
-	return rate / armdiv[val];
-}
-
-static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate)
-{
-	unsigned long parent = clk_get_rate(clk->parent);
-	unsigned long calc;
-	unsigned div;
-	unsigned best = 256; /* bigger than any value */
-	int ptr;
-	int val = -1;
-
-	if (!nr_armdiv || !armdivmask)
-		return -EINVAL;
-
-	for (ptr = 0; ptr < nr_armdiv; ptr++) {
-		div = armdiv[ptr];
-		if (div) {
-			/* cpufreq provides 266mhz as 266666000 not 266666666 */
-			calc = (parent / div / 1000) * 1000;
-			if (calc <= rate && div < best) {
-				best = div;
-				val = ptr;
-			}
-		}
-	}
-
-	if (val >= 0) {
-		unsigned long clkcon0;
-
-		clkcon0 = __raw_readl(S3C2443_CLKDIV0);
-		clkcon0 &= ~armdivmask;
-		clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT;
-		__raw_writel(clkcon0, S3C2443_CLKDIV0);
-	}
-
-	return (val == -1) ? -EINVAL : 0;
-}
-
-static struct clk clk_armdiv = {
-	.name		= "armdiv",
-	.parent		= &clk_msysclk.clk,
-	.ops		= &(struct clk_ops) {
-		.round_rate = s3c2443_armclk_roundrate,
-		.get_rate = s3c2443_armclk_getrate,
-		.set_rate = s3c2443_armclk_setrate,
-	},
-};
-
-/* armclk
- *
- * this is the clock fed into the ARM core itself, from armdiv or from hclk.
- */
-
-static struct clk *clk_arm_sources[] = {
-	[0] = &clk_armdiv,
-	[1] = &clk_h,
-};
-
-static struct clksrc_clk clk_arm = {
-	.clk	= {
-		.name		= "armclk",
-	},
-	.sources = &(struct clksrc_sources) {
-		.sources = clk_arm_sources,
-		.nr_sources = ARRAY_SIZE(clk_arm_sources),
-	},
-	.reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 },
-};
-
-/* usbhost
- *
- * usb host bus-clock, usually 48MHz to provide USB bus clock timing
-*/
-
-static struct clksrc_clk clk_usb_bus_host = {
-	.clk	= {
-		.name		= "usb-bus-host-parent",
-		.parent		= &clk_esysclk.clk,
-		.ctrlbit	= S3C2443_SCLKCON_USBHOST,
-		.enable		= s3c2443_clkcon_enable_s,
-	},
-	.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
-};
-
-/* common clksrc clocks */
-
-static struct clksrc_clk clksrc_clks[] = {
-	{
-		/* camera interface bus-clock, divided down from esysclk */
-		.clk	= {
-			.name		= "camif-upll",	/* same as 2440 name */
-			.parent		= &clk_esysclk.clk,
-			.ctrlbit	= S3C2443_SCLKCON_CAMCLK,
-			.enable		= s3c2443_clkcon_enable_s,
-		},
-		.reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
-	}, {
-		.clk	= {
-			.name		= "display-if",
-			.parent		= &clk_esysclk.clk,
-			.ctrlbit	= S3C2443_SCLKCON_DISPCLK,
-			.enable		= s3c2443_clkcon_enable_s,
-		},
-		.reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
-	},
-};
-
-static struct clksrc_clk clk_esys_uart = {
-	/* ART baud-rate clock sourced from esysclk via a divisor */
-	.clk	= {
-		.name		= "uartclk",
-		.parent		= &clk_esysclk.clk,
-	},
-	.reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
-};
-
-static struct clk clk_i2s_ext = {
-	.name		= "i2s-ext",
-};
-
-/* i2s_eplldiv
- *
- * This clock is the output from the I2S divisor of ESYSCLK, and is separate
- * from the mux that comes after it (cannot merge into one single clock)
-*/
-
-static struct clksrc_clk clk_i2s_eplldiv = {
-	.clk	= {
-		.name		= "i2s-eplldiv",
-		.parent		= &clk_esysclk.clk,
-	},
-	.reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
-};
-
-/* i2s-ref
- *
- * i2s bus reference clock, selectable from external, esysclk or epllref
- *
- * Note, this used to be two clocks, but was compressed into one.
-*/
-
-static struct clk *clk_i2s_srclist[] = {
-	[0] = &clk_i2s_eplldiv.clk,
-	[1] = &clk_i2s_ext,
-	[2] = &clk_epllref.clk,
-	[3] = &clk_epllref.clk,
-};
-
-static struct clksrc_clk clk_i2s = {
-	.clk	= {
-		.name		= "i2s-if",
-		.ctrlbit	= S3C2443_SCLKCON_I2SCLK,
-		.enable		= s3c2443_clkcon_enable_s,
-
-	},
-	.sources = &(struct clksrc_sources) {
-		.sources = clk_i2s_srclist,
-		.nr_sources = ARRAY_SIZE(clk_i2s_srclist),
-	},
-	.reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
-};
-
-static struct clk init_clocks_off[] = {
-	{
-		.name		= "iis",
-		.parent		= &clk_p,
-		.enable		= s3c2443_clkcon_enable_p,
-		.ctrlbit	= S3C2443_PCLKCON_IIS,
-	}, {
-		.name		= "hsspi",
-		.parent		= &clk_p,
-		.enable		= s3c2443_clkcon_enable_p,
-		.ctrlbit	= S3C2443_PCLKCON_HSSPI,
-	}, {
-		.name		= "adc",
-		.parent		= &clk_p,
-		.enable		= s3c2443_clkcon_enable_p,
-		.ctrlbit	= S3C2443_PCLKCON_ADC,
-	}, {
-		.name		= "i2c",
-		.parent		= &clk_p,
-		.enable		= s3c2443_clkcon_enable_p,
-		.ctrlbit	= S3C2443_PCLKCON_IIC,
-	}
-};
-
-static struct clk init_clocks[] = {
-	{
-		.name		= "dma",
-		.parent		= &clk_h,
-		.enable		= s3c2443_clkcon_enable_h,
-		.ctrlbit	= S3C2443_HCLKCON_DMA0,
-	}, {
-		.name		= "dma",
-		.parent		= &clk_h,
-		.enable		= s3c2443_clkcon_enable_h,
-		.ctrlbit	= S3C2443_HCLKCON_DMA1,
-	}, {
-		.name		= "dma",
-		.parent		= &clk_h,
-		.enable		= s3c2443_clkcon_enable_h,
-		.ctrlbit	= S3C2443_HCLKCON_DMA2,
-	}, {
-		.name		= "dma",
-		.parent		= &clk_h,
-		.enable		= s3c2443_clkcon_enable_h,
-		.ctrlbit	= S3C2443_HCLKCON_DMA3,
-	}, {
-		.name		= "dma",
-		.parent		= &clk_h,
-		.enable		= s3c2443_clkcon_enable_h,
-		.ctrlbit	= S3C2443_HCLKCON_DMA4,
-	}, {
-		.name		= "dma",
-		.parent		= &clk_h,
-		.enable		= s3c2443_clkcon_enable_h,
-		.ctrlbit	= S3C2443_HCLKCON_DMA5,
-	}, {
-		.name		= "gpio",
-		.parent		= &clk_p,
-		.enable		= s3c2443_clkcon_enable_p,
-		.ctrlbit	= S3C2443_PCLKCON_GPIO,
-	}, {
-		.name		= "usb-host",
-		.parent		= &clk_h,
-		.enable		= s3c2443_clkcon_enable_h,
-		.ctrlbit	= S3C2443_HCLKCON_USBH,
-	}, {
-		.name		= "usb-device",
-		.parent		= &clk_h,
-		.enable		= s3c2443_clkcon_enable_h,
-		.ctrlbit	= S3C2443_HCLKCON_USBD,
-	}, {
-		.name		= "lcd",
-		.parent		= &clk_h,
-		.enable		= s3c2443_clkcon_enable_h,
-		.ctrlbit	= S3C2443_HCLKCON_LCDC,
-
-	}, {
-		.name		= "timers",
-		.parent		= &clk_p,
-		.enable		= s3c2443_clkcon_enable_p,
-		.ctrlbit	= S3C2443_PCLKCON_PWMT,
-	}, {
-		.name		= "cfc",
-		.parent		= &clk_h,
-		.enable		= s3c2443_clkcon_enable_h,
-		.ctrlbit	= S3C2443_HCLKCON_CFC,
-	}, {
-		.name		= "ssmc",
-		.parent		= &clk_h,
-		.enable		= s3c2443_clkcon_enable_h,
-		.ctrlbit	= S3C2443_HCLKCON_SSMC,
-	}, {
-		.name		= "uart",
-		.devname	= "s3c2440-uart.0",
-		.parent		= &clk_p,
-		.enable		= s3c2443_clkcon_enable_p,
-		.ctrlbit	= S3C2443_PCLKCON_UART0,
-	}, {
-		.name		= "uart",
-		.devname	= "s3c2440-uart.1",
-		.parent		= &clk_p,
-		.enable		= s3c2443_clkcon_enable_p,
-		.ctrlbit	= S3C2443_PCLKCON_UART1,
-	}, {
-		.name		= "uart",
-		.devname	= "s3c2440-uart.2",
-		.parent		= &clk_p,
-		.enable		= s3c2443_clkcon_enable_p,
-		.ctrlbit	= S3C2443_PCLKCON_UART2,
-	}, {
-		.name		= "uart",
-		.devname	= "s3c2440-uart.3",
-		.parent		= &clk_p,
-		.enable		= s3c2443_clkcon_enable_p,
-		.ctrlbit	= S3C2443_PCLKCON_UART3,
-	}, {
-		.name		= "rtc",
-		.parent		= &clk_p,
-		.enable		= s3c2443_clkcon_enable_p,
-		.ctrlbit	= S3C2443_PCLKCON_RTC,
-	}, {
-		.name		= "watchdog",
-		.parent		= &clk_p,
-		.ctrlbit	= S3C2443_PCLKCON_WDT,
-	}, {
-		.name		= "ac97",
-		.parent		= &clk_p,
-		.ctrlbit	= S3C2443_PCLKCON_AC97,
-	}, {
-		.name		= "nand",
-		.parent		= &clk_h,
-	}, {
-		.name		= "usb-bus-host",
-		.parent		= &clk_usb_bus_host.clk,
-	}
-};
-
-static struct clk hsmmc1_clk = {
-	.name		= "hsmmc",
-	.devname	= "s3c-sdhci.1",
-	.parent		= &clk_h,
-	.enable		= s3c2443_clkcon_enable_h,
-	.ctrlbit	= S3C2443_HCLKCON_HSMMC,
-};
-
-static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
-{
-	clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
-
-	return clkcon0 + 1;
-}
-
-/* EPLLCON compatible enough to get on/off information */
-
-void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll)
-{
-	unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
-	unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
-	unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
-	struct clk *xtal_clk;
-	unsigned long xtal;
-	unsigned long pll;
-	unsigned long fclk;
-	unsigned long hclk;
-	unsigned long pclk;
-	int ptr;
-
-	xtal_clk = clk_get(NULL, "xtal");
-	xtal = clk_get_rate(xtal_clk);
-	clk_put(xtal_clk);
-
-	pll = get_mpll(mpllcon, xtal);
-	clk_msysclk.clk.rate = pll;
-
-	fclk = clk_get_rate(&clk_armdiv);
-	hclk = s3c2443_prediv_getrate(&clk_prediv);
-	hclk /= s3c2443_get_hdiv(clkdiv0);
-	pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
-
-	s3c24xx_setup_clocks(fclk, hclk, pclk);
-
-	printk("CPU: MPLL %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
-	       (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
-	       print_mhz(pll), print_mhz(fclk),
-	       print_mhz(hclk), print_mhz(pclk));
-
-	for (ptr = 0; ptr < ARRAY_SIZE(clksrc_clks); ptr++)
-		s3c_set_clksrc(&clksrc_clks[ptr], true);
-
-	/* ensure usb bus clock is within correct rate of 48MHz */
-
-	if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
-		printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
-		clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
-	}
-
-	printk("CPU: EPLL %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
-	       (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
-	       print_mhz(clk_get_rate(&clk_epll)),
-	       print_mhz(clk_get_rate(&clk_usb_bus)));
-}
-
-static struct clk *clks[] __initdata = {
-	&clk_prediv,
-	&clk_mpllref,
-	&clk_mdivclk,
-	&clk_ext,
-	&clk_epll,
-	&clk_usb_bus,
-	&clk_armdiv,
-	&hsmmc1_clk,
-};
-
-static struct clksrc_clk *clksrcs[] __initdata = {
-	&clk_i2s_eplldiv,
-	&clk_i2s,
-	&clk_usb_bus_host,
-	&clk_epllref,
-	&clk_esysclk,
-	&clk_msysclk,
-	&clk_arm,
-};
-
-static struct clk_lookup s3c2443_clk_lookup[] = {
-	CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
-	CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
-	CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_esys_uart.clk),
-	CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &hsmmc1_clk),
-};
-
-void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
-				       unsigned int *divs, int nr_divs,
-				       int divmask)
-{
-	int ptr;
-
-	armdiv = divs;
-	nr_armdiv = nr_divs;
-	armdivmask = divmask;
-
-	/* s3c2443 parents h and p clocks from prediv */
-	clk_h.parent = &clk_prediv;
-	clk_p.parent = &clk_prediv;
-
-	clk_usb_bus.parent = &clk_usb_bus_host.clk;
-	clk_epll.parent = &clk_epllref.clk;
-
-	s3c24xx_register_baseclocks(xtal);
-	s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
-
-	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
-		s3c_register_clksrc(clksrcs[ptr], 1);
-
-	s3c_register_clksrc(clksrc_clks, ARRAY_SIZE(clksrc_clks));
-	s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
-
-	/* See s3c2443/etc notes on disabling clocks at init time */
-	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-	clkdev_add_table(s3c2443_clk_lookup, ARRAY_SIZE(s3c2443_clk_lookup));
-
-	s3c2443_common_setup_clocks(get_mpll);
-}
diff --git a/arch/arm/plat-s3c24xx/simtec-audio.c b/arch/arm/plat-s3c24xx/simtec-audio.c
deleted file mode 100644
index 6bc832e..0000000
--- a/arch/arm/plat-s3c24xx/simtec-audio.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/simtec-audio.c
- *
- * Copyright (c) 2009 Simtec Electronics
- *	http://armlinux.simtec.co.uk/
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * Audio setup for various Simtec S3C24XX implementations
- *
- * 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/interrupt.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/io.h>
-
-#include <mach/bast-map.h>
-#include <mach/bast-irq.h>
-#include <mach/bast-cpld.h>
-
-#include <mach/hardware.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/audio-simtec.h>
-#include <plat/devs.h>
-
-/* platform ops for audio */
-
-static void simtec_audio_startup_lrroute(void)
-{
-	unsigned int tmp;
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	tmp = __raw_readb(BAST_VA_CTRL1);
-	tmp &= ~BAST_CPLD_CTRL1_LRMASK;
-	tmp |= BAST_CPLD_CTRL1_LRCDAC;
-	__raw_writeb(tmp, BAST_VA_CTRL1);
-
-	local_irq_restore(flags);
-}
-
-static struct s3c24xx_audio_simtec_pdata simtec_audio_platdata;
-static char our_name[32];
-
-static struct platform_device simtec_audio_dev = {
-	.name	= our_name,
-	.id	= -1,
-	.dev	= {
-		.parent		= &s3c_device_iis.dev,
-		.platform_data	= &simtec_audio_platdata,
-	},
-};
-
-int __init simtec_audio_add(const char *name, bool has_lr_routing,
-			    struct s3c24xx_audio_simtec_pdata *spd)
-{
-	if (!name)
-		name = "tlv320aic23";
-
-	snprintf(our_name, sizeof(our_name)-1, "s3c24xx-simtec-%s", name);
-
-	/* copy platform data so the source can be __initdata */
-	if (spd)
-		simtec_audio_platdata = *spd;
-
-	if (has_lr_routing)
-		simtec_audio_platdata.startup = simtec_audio_startup_lrroute;
-
-	platform_device_register(&s3c_device_iis);
-	platform_device_register(&simtec_audio_dev);
-	return 0;
-}
diff --git a/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c b/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
deleted file mode 100644
index 704175b..0000000
--- a/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
- *
- * Copyright (c) 2008 Simtec Electronics
- *	http://armlinux.simtec.co.uk/
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * S3C24XX SPI - gpio configuration for bus 0 on gpe11,12,13
- *
- * 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.
-*/
-
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-
-#include <mach/spi.h>
-#include <mach/regs-gpio.h>
-
-void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi,
-					  int enable)
-{
-	if (enable) {
-		s3c_gpio_cfgpin(S3C2410_GPE(13), S3C2410_GPE13_SPICLK0);
-		s3c_gpio_cfgpin(S3C2410_GPE(12), S3C2410_GPE12_SPIMOSI0);
-		s3c_gpio_cfgpin(S3C2410_GPE(11), S3C2410_GPE11_SPIMISO0);
-		s3c2410_gpio_pullup(S3C2410_GPE(11), 0);
-		s3c2410_gpio_pullup(S3C2410_GPE(13), 0);
-	} else {
-		s3c_gpio_cfgpin(S3C2410_GPE(13), S3C2410_GPIO_INPUT);
-		s3c_gpio_cfgpin(S3C2410_GPE(11), S3C2410_GPIO_INPUT);
-		s3c_gpio_setpull(S3C2410_GPE(11), S3C_GPIO_PULL_NONE);
-		s3c_gpio_setpull(S3C2410_GPE(12), S3C_GPIO_PULL_NONE);
-		s3c_gpio_setpull(S3C2410_GPE(13), S3C_GPIO_PULL_NONE);
-	}
-}
diff --git a/arch/arm/plat-s3c24xx/spi-bus1-gpd8_9_10.c b/arch/arm/plat-s3c24xx/spi-bus1-gpd8_9_10.c
deleted file mode 100644
index 72457af..0000000
--- a/arch/arm/plat-s3c24xx/spi-bus1-gpd8_9_10.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpd8_9_10.c
- *
- * Copyright (c) 2008 Simtec Electronics
- *	http://armlinux.simtec.co.uk/
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * S3C24XX SPI - gpio configuration for bus 1 on gpd8,9,10
- *
- * 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.
-*/
-
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-
-#include <mach/spi.h>
-#include <mach/regs-gpio.h>
-
-void s3c24xx_spi_gpiocfg_bus1_gpd8_9_10(struct s3c2410_spi_info *spi,
-					int enable)
-{
-
-	printk(KERN_INFO "%s(%d)\n", __func__, enable);
-	if (enable) {
-		s3c_gpio_cfgpin(S3C2410_GPD(10), S3C2440_GPD10_SPICLK1);
-		s3c_gpio_cfgpin(S3C2410_GPD(9), S3C2440_GPD9_SPIMOSI1);
-		s3c_gpio_cfgpin(S3C2410_GPD(8), S3C2440_GPD8_SPIMISO1);
-		s3c2410_gpio_pullup(S3C2410_GPD(10), 0);
-		s3c2410_gpio_pullup(S3C2410_GPD(9), 0);
-	} else {
-		s3c_gpio_cfgpin(S3C2410_GPD(8), S3C2410_GPIO_INPUT);
-		s3c_gpio_cfgpin(S3C2410_GPD(9), S3C2410_GPIO_INPUT);
-		s3c_gpio_setpull(S3C2410_GPD(10), S3C_GPIO_PULL_NONE);
-		s3c_gpio_setpull(S3C2410_GPD(9), S3C_GPIO_PULL_NONE);
-		s3c_gpio_setpull(S3C2410_GPD(8), S3C_GPIO_PULL_NONE);
-	}
-}
diff --git a/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c b/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
deleted file mode 100644
index c3972b6..0000000
--- a/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpg5_6_7.c
- *
- * Copyright (c) 2008 Simtec Electronics
- *	http://armlinux.simtec.co.uk/
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * S3C24XX SPI - gpio configuration for bus 1 on gpg5,6,7
- *
- * 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.
-*/
-
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-
-#include <mach/spi.h>
-#include <mach/regs-gpio.h>
-
-void s3c24xx_spi_gpiocfg_bus1_gpg5_6_7(struct s3c2410_spi_info *spi,
-				       int enable)
-{
-	if (enable) {
-		s3c_gpio_cfgpin(S3C2410_GPG(7), S3C2410_GPG7_SPICLK1);
-		s3c_gpio_cfgpin(S3C2410_GPG(6), S3C2410_GPG6_SPIMOSI1);
-		s3c_gpio_cfgpin(S3C2410_GPG(5), S3C2410_GPG5_SPIMISO1);
-		s3c2410_gpio_pullup(S3C2410_GPG(5), 0);
-		s3c2410_gpio_pullup(S3C2410_GPG(6), 0);
-	} else {
-		s3c_gpio_cfgpin(S3C2410_GPG(7), S3C2410_GPIO_INPUT);
-		s3c_gpio_cfgpin(S3C2410_GPG(5), S3C2410_GPIO_INPUT);
-		s3c_gpio_setpull(S3C2410_GPG(5), S3C_GPIO_PULL_NONE);
-		s3c_gpio_setpull(S3C2410_GPG(6), S3C_GPIO_PULL_NONE);
-		s3c_gpio_setpull(S3C2410_GPG(7), S3C_GPIO_PULL_NONE);
-	}
-}
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 8167ce6..96bea32 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -9,8 +9,8 @@
 	bool
 	depends on (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS)
 	default y
-	select ARM_VIC if !ARCH_EXYNOS4
-	select ARM_GIC if ARCH_EXYNOS4
+	select ARM_VIC if !ARCH_EXYNOS
+	select ARM_GIC if ARCH_EXYNOS
 	select GIC_NON_BANKED if ARCH_EXYNOS4
 	select NO_IOPORT
 	select ARCH_REQUIRE_GPIOLIB
@@ -40,6 +40,10 @@
 	help
 	  Use the High Resolution timer support
 
+config S5P_DEV_UART
+	def_bool y
+	depends on (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210)
+
 config S5P_PM
 	bool
 	help
@@ -80,6 +84,16 @@
 	help
 	  Compile in platform device definitions for FIMC controller 3
 
+config S5P_DEV_JPEG
+	bool
+	help
+	  Compile in platform device definitions for JPEG codec
+
+config S5P_DEV_G2D
+	bool
+	help
+	  Compile in platform device definitions for G2D device
+
 config S5P_DEV_FIMD0
 	bool
 	help
diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile
index 30d8c30..4bd8241 100644
--- a/arch/arm/plat-s5p/Makefile
+++ b/arch/arm/plat-s5p/Makefile
@@ -12,7 +12,6 @@
 
 # Core files
 
-obj-y				+= dev-uart.o
 obj-y				+= clock.o
 obj-y				+= irq.o
 obj-$(CONFIG_S5P_EXT_INT)	+= irq-eint.o
@@ -23,5 +22,7 @@
 obj-$(CONFIG_S5P_HRT) 		+= s5p-time.o
 
 # devices
+
+obj-$(CONFIG_S5P_DEV_UART)	+= dev-uart.o
 obj-$(CONFIG_S5P_DEV_MFC)	+= dev-mfc.o
 obj-$(CONFIG_S5P_SETUP_MIPIPHY)	+= setup-mipiphy.o
diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c
index 963edea..f68a9bb 100644
--- a/arch/arm/plat-s5p/clock.c
+++ b/arch/arm/plat-s5p/clock.c
@@ -61,6 +61,20 @@
 	.id		= -1,
 };
 
+/* BPLL clock output */
+
+struct clk clk_fout_bpll = {
+	.name		= "fout_bpll",
+	.id		= -1,
+};
+
+/* CPLL clock output */
+
+struct clk clk_fout_cpll = {
+	.name		= "fout_cpll",
+	.id		= -1,
+};
+
 /* MPLL clock output
  * No need .ctrlbit, this is always on
 */
@@ -101,6 +115,28 @@
 	.nr_sources	= ARRAY_SIZE(clk_src_apll_list),
 };
 
+/* Possible clock sources for BPLL Mux */
+static struct clk *clk_src_bpll_list[] = {
+	[0] = &clk_fin_bpll,
+	[1] = &clk_fout_bpll,
+};
+
+struct clksrc_sources clk_src_bpll = {
+	.sources	= clk_src_bpll_list,
+	.nr_sources	= ARRAY_SIZE(clk_src_bpll_list),
+};
+
+/* Possible clock sources for CPLL Mux */
+static struct clk *clk_src_cpll_list[] = {
+	[0] = &clk_fin_cpll,
+	[1] = &clk_fout_cpll,
+};
+
+struct clksrc_sources clk_src_cpll = {
+	.sources	= clk_src_cpll_list,
+	.nr_sources	= ARRAY_SIZE(clk_src_cpll_list),
+};
+
 /* Possible clock sources for MPLL Mux */
 static struct clk *clk_src_mpll_list[] = {
 	[0] = &clk_fin_mpll,
diff --git a/arch/arm/plat-s5p/irq-eint.c b/arch/arm/plat-s5p/irq-eint.c
index c496b35..139c050 100644
--- a/arch/arm/plat-s5p/irq-eint.c
+++ b/arch/arm/plat-s5p/irq-eint.c
@@ -200,7 +200,7 @@
 #endif
 };
 
-int __init s5p_init_irq_eint(void)
+static int __init s5p_init_irq_eint(void)
 {
 	int irq;
 
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c
index 1fdfaa4..82c7311 100644
--- a/arch/arm/plat-s5p/irq-gpioint.c
+++ b/arch/arm/plat-s5p/irq-gpioint.c
@@ -41,7 +41,7 @@
 	void			(*handler)(unsigned int, struct irq_desc *);
 };
 
-LIST_HEAD(banks);
+static LIST_HEAD(banks);
 
 static int s5p_gpioint_set_type(struct irq_data *d, unsigned int type)
 {
diff --git a/arch/arm/plat-s5p/irq-pm.c b/arch/arm/plat-s5p/irq-pm.c
index 327acb3..d1bfeca 100644
--- a/arch/arm/plat-s5p/irq-pm.c
+++ b/arch/arm/plat-s5p/irq-pm.c
@@ -39,19 +39,32 @@
 int s3c_irq_wake(struct irq_data *data, unsigned int state)
 {
 	unsigned long irqbit;
+	unsigned int irq_rtc_tic, irq_rtc_alarm;
 
-	switch (data->irq) {
-	case IRQ_RTC_TIC:
-	case IRQ_RTC_ALARM:
-		irqbit = 1 << (data->irq + 1 - IRQ_RTC_ALARM);
+#ifdef CONFIG_ARCH_EXYNOS
+	if (soc_is_exynos5250()) {
+		irq_rtc_tic = EXYNOS5_IRQ_RTC_TIC;
+		irq_rtc_alarm = EXYNOS5_IRQ_RTC_ALARM;
+	} else {
+		irq_rtc_tic = EXYNOS4_IRQ_RTC_TIC;
+		irq_rtc_alarm = EXYNOS4_IRQ_RTC_ALARM;
+	}
+#else
+	irq_rtc_tic = IRQ_RTC_TIC;
+	irq_rtc_alarm = IRQ_RTC_ALARM;
+#endif
+
+	if (data->irq == irq_rtc_tic || data->irq == irq_rtc_alarm) {
+		irqbit = 1 << (data->irq + 1 - irq_rtc_alarm);
+
 		if (!state)
 			s3c_irqwake_intmask |= irqbit;
 		else
 			s3c_irqwake_intmask &= ~irqbit;
-		break;
-	default:
+	} else {
 		return -ENOENT;
 	}
+
 	return 0;
 }
 
diff --git a/arch/arm/plat-s5p/sleep.S b/arch/arm/plat-s5p/sleep.S
index 0fd591b..006bd01 100644
--- a/arch/arm/plat-s5p/sleep.S
+++ b/arch/arm/plat-s5p/sleep.S
@@ -23,9 +23,18 @@
 */
 
 #include <linux/linkage.h>
-#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/hardware/cache-l2x0.h>
 
-	.text
+/*
+ *	 The following code is located into the .data section. This is to
+ *	 allow l2x0_regs_phys to be accessed with a relative load while we
+ *	 can't rely on any MMU translation. We could have put l2x0_regs_phys
+ *	 in the .text section as well, but some setups might insist on it to
+ *	 be truly read-only. (Reference from: arch/arm/kernel/sleep.S)
+ */
+	.data
+	.align
 
 	/*
 	 * sleep magic, to allow the bootloader to check for an valid
@@ -39,11 +48,34 @@
 	 * s3c_cpu_resume
 	 *
 	 * resume code entry for bootloader to call
-	 *
-	 * we must put this code here in the data segment as we have no
-	 * other way of restoring the stack pointer after sleep, and we
-	 * must not write to the code segment (code is read-only)
 	 */
 
 ENTRY(s3c_cpu_resume)
+#ifdef CONFIG_CACHE_L2X0
+	adr	r0, l2x0_regs_phys
+	ldr	r0, [r0]
+	ldr	r1, [r0, #L2X0_R_PHY_BASE]
+	ldr	r2, [r1, #L2X0_CTRL]
+	tst	r2, #0x1
+	bne	resume_l2on
+	ldr	r2, [r0, #L2X0_R_AUX_CTRL]
+	str	r2, [r1, #L2X0_AUX_CTRL]
+	ldr	r2, [r0, #L2X0_R_TAG_LATENCY]
+	str	r2, [r1, #L2X0_TAG_LATENCY_CTRL]
+	ldr	r2, [r0, #L2X0_R_DATA_LATENCY]
+	str	r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+	ldr	r2, [r0, #L2X0_R_PREFETCH_CTRL]
+	str	r2, [r1, #L2X0_PREFETCH_CTRL]
+	ldr	r2, [r0, #L2X0_R_PWR_CTRL]
+	str	r2, [r1, #L2X0_POWER_CTRL]
+	mov	r2, #1
+	str	r2, [r1, #L2X0_CTRL]
+resume_l2on:
+#endif
 	b	cpu_resume
+ENDPROC(s3c_cpu_resume)
+#ifdef CONFIG_CACHE_L2X0
+	.globl l2x0_regs_phys
+l2x0_regs_phys:
+	.long	0
+#endif
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index 6a2abe6..71553f4 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -205,7 +205,7 @@
 
 config S3C_DEV_WDT
 	bool
-	default y if ARCH_S3C2410
+	default y if ARCH_S3C24XX
 	help
 	  Complie in platform device definition for Watchdog Timer
 
@@ -264,7 +264,7 @@
 
 config SAMSUNG_DEV_PWM
 	bool
-	default y if ARCH_S3C2410
+	default y if ARCH_S3C24XX
 	help
 	  Compile in platform device definition for PWM Timer
 
diff --git a/arch/arm/plat-samsung/clock.c b/arch/arm/plat-samsung/clock.c
index 10f7117..65c5eca 100644
--- a/arch/arm/plat-samsung/clock.c
+++ b/arch/arm/plat-samsung/clock.c
@@ -84,31 +84,35 @@
 
 int clk_enable(struct clk *clk)
 {
+	unsigned long flags;
+
 	if (IS_ERR(clk) || clk == NULL)
 		return -EINVAL;
 
 	clk_enable(clk->parent);
 
-	spin_lock(&clocks_lock);
+	spin_lock_irqsave(&clocks_lock, flags);
 
 	if ((clk->usage++) == 0)
 		(clk->enable)(clk, 1);
 
-	spin_unlock(&clocks_lock);
+	spin_unlock_irqrestore(&clocks_lock, flags);
 	return 0;
 }
 
 void clk_disable(struct clk *clk)
 {
+	unsigned long flags;
+
 	if (IS_ERR(clk) || clk == NULL)
 		return;
 
-	spin_lock(&clocks_lock);
+	spin_lock_irqsave(&clocks_lock, flags);
 
 	if ((--clk->usage) == 0)
 		(clk->enable)(clk, 0);
 
-	spin_unlock(&clocks_lock);
+	spin_unlock_irqrestore(&clocks_lock, flags);
 	clk_disable(clk->parent);
 }
 
diff --git a/arch/arm/plat-samsung/cpu.c b/arch/arm/plat-samsung/cpu.c
index 81c06d4..46b426e 100644
--- a/arch/arm/plat-samsung/cpu.c
+++ b/arch/arm/plat-samsung/cpu.c
@@ -15,7 +15,6 @@
 #include <linux/init.h>
 #include <linux/io.h>
 
-#include <asm/system.h>
 
 #include <mach/map.h>
 #include <plat/cpu.h>
diff --git a/arch/arm/plat-samsung/dev-backlight.c b/arch/arm/plat-samsung/dev-backlight.c
index a976c02..5f197dc 100644
--- a/arch/arm/plat-samsung/dev-backlight.c
+++ b/arch/arm/plat-samsung/dev-backlight.c
@@ -77,7 +77,7 @@
  * @gpio_info:	structure containing GPIO info for PWM timer
  * @bl_data:	structure containing Backlight control data
  */
-void samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
+void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
 	struct platform_pwm_backlight_data *bl_data)
 {
 	int ret = 0;
@@ -115,6 +115,8 @@
 		samsung_bl_data->init = bl_data->init;
 	if (bl_data->notify)
 		samsung_bl_data->notify = bl_data->notify;
+	if (bl_data->notify_after)
+		samsung_bl_data->notify_after = bl_data->notify_after;
 	if (bl_data->exit)
 		samsung_bl_data->exit = bl_data->exit;
 	if (bl_data->check_fb)
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index d21d744..8b928f9 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -57,6 +57,7 @@
 #include <plat/sdhci.h>
 #include <plat/ts.h>
 #include <plat/udc.h>
+#include <plat/udc-hs.h>
 #include <plat/usb-control.h>
 #include <plat/usb-phy.h>
 #include <plat/regs-iic.h>
@@ -267,6 +268,52 @@
 };
 #endif /* CONFIG_S5P_DEV_FIMC3 */
 
+/* G2D */
+
+#ifdef CONFIG_S5P_DEV_G2D
+static struct resource s5p_g2d_resource[] = {
+	[0] = {
+		.start	= S5P_PA_G2D,
+		.end	= S5P_PA_G2D + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_2D,
+		.end	= IRQ_2D,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device s5p_device_g2d = {
+	.name		= "s5p-g2d",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(s5p_g2d_resource),
+	.resource	= s5p_g2d_resource,
+	.dev		= {
+		.dma_mask		= &samsung_device_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+#endif /* CONFIG_S5P_DEV_G2D */
+
+#ifdef CONFIG_S5P_DEV_JPEG
+static struct resource s5p_jpeg_resource[] = {
+	[0] = DEFINE_RES_MEM(S5P_PA_JPEG, SZ_4K),
+	[1] = DEFINE_RES_IRQ(IRQ_JPEG),
+};
+
+struct platform_device s5p_device_jpeg = {
+	.name		= "s5p-jpeg",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(s5p_jpeg_resource),
+	.resource	= s5p_jpeg_resource,
+	.dev		= {
+		.dma_mask		= &samsung_device_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+#endif /*  CONFIG_S5P_DEV_JPEG */
+
 /* FIMD0 */
 
 #ifdef CONFIG_S5P_DEV_FIMD0
@@ -744,17 +791,6 @@
 };
 #endif /* CONFIG_PLAT_S3C24XX */
 
-#ifdef CONFIG_CPU_S3C2440
-struct platform_device s3c2412_device_iis = {
-	.name		= "s3c2412-iis",
-	.id		= -1,
-	.dev		= {
-		.dma_mask		= &samsung_device_dma_mask,
-		.coherent_dma_mask	= DMA_BIT_MASK(32),
-	}
-};
-#endif /* CONFIG_CPU_S3C2440 */
-
 /* IDE CFCON */
 
 #ifdef CONFIG_SAMSUNG_DEV_IDE
@@ -769,7 +805,7 @@
 	.resource	= s3c_cfcon_resource,
 };
 
-void s3c_ide_set_platdata(struct s3c_ide_platdata *pdata)
+void __init s3c_ide_set_platdata(struct s3c_ide_platdata *pdata)
 {
 	s3c_set_platdata(pdata, sizeof(struct s3c_ide_platdata),
 			 &s3c_device_cfcon);
@@ -887,7 +923,7 @@
 
 #ifdef CONFIG_S5P_DEV_CSIS0
 static struct resource s5p_mipi_csis0_resource[] = {
-	[0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS0, SZ_4K),
+	[0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS0, SZ_16K),
 	[1] = DEFINE_RES_IRQ(IRQ_MIPI_CSIS0),
 };
 
@@ -901,7 +937,7 @@
 
 #ifdef CONFIG_S5P_DEV_CSIS1
 static struct resource s5p_mipi_csis1_resource[] = {
-	[0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS1, SZ_4K),
+	[0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS1, SZ_16K),
 	[1] = DEFINE_RES_IRQ(IRQ_MIPI_CSIS1),
 };
 
@@ -1049,7 +1085,7 @@
 	.resource	= s3c64xx_onenand1_resources,
 };
 
-void s3c64xx_onenand1_set_platdata(struct onenand_platform_data *pdata)
+void __init s3c64xx_onenand1_set_platdata(struct onenand_platform_data *pdata)
 {
 	s3c_set_platdata(pdata, sizeof(struct onenand_platform_data),
 			 &s3c64xx_device_onenand1);
@@ -1078,7 +1114,7 @@
 	DEFINE_RES_IRQ(IRQ_PMU)
 };
 
-struct platform_device s5p_device_pmu = {
+static struct platform_device s5p_device_pmu = {
 	.name		= "arm-pmu",
 	.id		= ARM_PMU_DEVICE_CPU,
 	.num_resources	= ARRAY_SIZE(s5p_pmu_resource),
@@ -1423,6 +1459,19 @@
 		.coherent_dma_mask	= DMA_BIT_MASK(32),
 	},
 };
+
+void __init s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd)
+{
+	struct s3c_hsotg_plat *npd;
+
+	npd = s3c_set_platdata(pd, sizeof(struct s3c_hsotg_plat),
+			&s3c_device_usb_hsotg);
+
+	if (!npd->phy_init)
+		npd->phy_init = s5p_usb_phy_init;
+	if (!npd->phy_exit)
+		npd->phy_exit = s5p_usb_phy_exit;
+}
 #endif /* CONFIG_S3C_DEV_USB_HSOTG */
 
 /* USB High Spped 2.0 Device (Gadget) */
diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c
index 0747c77..eb9f4f5 100644
--- a/arch/arm/plat-samsung/dma-ops.c
+++ b/arch/arm/plat-samsung/dma-ops.c
@@ -79,11 +79,11 @@
 			    info->len, offset_in_page(info->buf));
 		sg_dma_address(&sg) = info->buf;
 
-		desc = chan->device->device_prep_slave_sg(chan,
+		desc = dmaengine_prep_slave_sg(chan,
 			&sg, 1, info->direction, DMA_PREP_INTERRUPT);
 		break;
 	case DMA_CYCLIC:
-		desc = chan->device->device_prep_dma_cyclic(chan,
+		desc = dmaengine_prep_dma_cyclic(chan,
 			info->buf, info->len, info->period, info->direction);
 		break;
 	default:
@@ -116,7 +116,7 @@
 	return dmaengine_terminate_all((struct dma_chan *)ch);
 }
 
-struct samsung_dma_ops dmadev_ops = {
+static struct samsung_dma_ops dmadev_ops = {
 	.request	= samsung_dmadev_request,
 	.release	= samsung_dmadev_release,
 	.prepare	= samsung_dmadev_prepare,
diff --git a/arch/arm/plat-samsung/include/plat/audio-simtec.h b/arch/arm/plat-samsung/include/plat/audio-simtec.h
index 5345364..376af52 100644
--- a/arch/arm/plat-samsung/include/plat/audio-simtec.h
+++ b/arch/arm/plat-samsung/include/plat/audio-simtec.h
@@ -32,6 +32,3 @@
 
 	void	(*startup)(void);
 };
-
-extern int simtec_audio_add(const char *codec_name, bool has_lr_routing,
-			    struct s3c24xx_audio_simtec_pdata *pdata);
diff --git a/arch/arm/plat-samsung/include/plat/clock.h b/arch/arm/plat-samsung/include/plat/clock.h
index 73c66d4..a62753d 100644
--- a/arch/arm/plat-samsung/include/plat/clock.h
+++ b/arch/arm/plat-samsung/include/plat/clock.h
@@ -79,6 +79,10 @@
 extern struct clk clk_xtal;
 extern struct clk clk_ext;
 
+/* S3C2443/S3C2416 specific clocks */
+extern struct clksrc_clk clk_epllref;
+extern struct clksrc_clk clk_esysclk;
+
 /* S3C64XX specific clocks */
 extern struct clk clk_h2;
 extern struct clk clk_27m;
@@ -114,7 +118,23 @@
 extern void s3c2410_setup_clocks(void);
 extern void s3c2412_setup_clocks(void);
 extern void s3c244x_setup_clocks(void);
-extern void s3c2443_setup_clocks(void);
+
+/* S3C2410 specific clock functions */
+
+extern int s3c2410_baseclk_add(void);
+
+/* S3C2443/S3C2416 specific clock functions */
+
+typedef unsigned int (*pll_fn)(unsigned int reg, unsigned int base);
+
+extern void s3c2443_common_setup_clocks(pll_fn get_mpll);
+extern void s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
+				       unsigned int *divs, int nr_divs,
+				       int divmask);
+
+extern int s3c2443_clkcon_enable_h(struct clk *clk, int enable);
+extern int s3c2443_clkcon_enable_p(struct clk *clk, int enable);
+extern int s3c2443_clkcon_enable_s(struct clk *clk, int enable);
 
 /* S3C64XX specific functions and clocks */
 
diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h
index 73cb3cf..787ceac 100644
--- a/arch/arm/plat-samsung/include/plat/cpu.h
+++ b/arch/arm/plat-samsung/include/plat/cpu.h
@@ -42,6 +42,9 @@
 #define EXYNOS4412_CPU_ID	0xE4412200
 #define EXYNOS4_CPU_MASK	0xFFFE0000
 
+#define EXYNOS5250_SOC_ID	0x43520000
+#define EXYNOS5_SOC_MASK	0xFFFFF000
+
 #define IS_SAMSUNG_CPU(name, id, mask)		\
 static inline int is_samsung_##name(void)	\
 {						\
@@ -58,6 +61,7 @@
 IS_SAMSUNG_CPU(exynos4210, EXYNOS4210_CPU_ID, EXYNOS4_CPU_MASK)
 IS_SAMSUNG_CPU(exynos4212, EXYNOS4212_CPU_ID, EXYNOS4_CPU_MASK)
 IS_SAMSUNG_CPU(exynos4412, EXYNOS4412_CPU_ID, EXYNOS4_CPU_MASK)
+IS_SAMSUNG_CPU(exynos5250, EXYNOS5250_SOC_ID, EXYNOS5_SOC_MASK)
 
 #if defined(CONFIG_CPU_S3C2410) || defined(CONFIG_CPU_S3C2412) || \
     defined(CONFIG_CPU_S3C2416) || defined(CONFIG_CPU_S3C2440) || \
@@ -120,6 +124,12 @@
 #define EXYNOS4210_REV_1_0	(0x10)
 #define EXYNOS4210_REV_1_1	(0x11)
 
+#if defined(CONFIG_SOC_EXYNOS5250)
+# define soc_is_exynos5250()	is_samsung_exynos5250()
+#else
+# define soc_is_exynos5250()	0
+#endif
+
 #define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C24XX_PA_##x), S3C24XX_SZ_##x, MT_DEVICE }
 
 #ifndef MHZ
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 4214ea0..2155d4a 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -26,6 +26,8 @@
 extern struct s3c24xx_uart_resources s3c2410_uart_resources[];
 extern struct s3c24xx_uart_resources s3c64xx_uart_resources[];
 extern struct s3c24xx_uart_resources s5p_uart_resources[];
+extern struct s3c24xx_uart_resources exynos4_uart_resources[];
+extern struct s3c24xx_uart_resources exynos5_uart_resources[];
 
 extern struct platform_device *s3c24xx_uart_devs[];
 extern struct platform_device *s3c24xx_uart_src[];
@@ -79,6 +81,8 @@
 extern struct platform_device s5p_device_fimc2;
 extern struct platform_device s5p_device_fimc3;
 extern struct platform_device s5p_device_fimc_md;
+extern struct platform_device s5p_device_jpeg;
+extern struct platform_device s5p_device_g2d;
 extern struct platform_device s5p_device_fimd0;
 extern struct platform_device s5p_device_hdmi;
 extern struct platform_device s5p_device_i2c_hdmiphy;
diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h
index c5eaad5..0670f37 100644
--- a/arch/arm/plat-samsung/include/plat/dma-pl330.h
+++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h
@@ -82,6 +82,22 @@
 	DMACH_SLIMBUS4_TX,
 	DMACH_SLIMBUS5_RX,
 	DMACH_SLIMBUS5_TX,
+	DMACH_MIPI_HSI0,
+	DMACH_MIPI_HSI1,
+	DMACH_MIPI_HSI2,
+	DMACH_MIPI_HSI3,
+	DMACH_MIPI_HSI4,
+	DMACH_MIPI_HSI5,
+	DMACH_MIPI_HSI6,
+	DMACH_MIPI_HSI7,
+	DMACH_MTOM_0,
+	DMACH_MTOM_1,
+	DMACH_MTOM_2,
+	DMACH_MTOM_3,
+	DMACH_MTOM_4,
+	DMACH_MTOM_5,
+	DMACH_MTOM_6,
+	DMACH_MTOM_7,
 	/* END Marker, also used to denote a reserved channel */
 	DMACH_MAX,
 };
diff --git a/arch/arm/plat-samsung/include/plat/regs-dma.h b/arch/arm/plat-samsung/include/plat/regs-dma.h
index 178bccb..a7d622e 100644
--- a/arch/arm/plat-samsung/include/plat/regs-dma.h
+++ b/arch/arm/plat-samsung/include/plat/regs-dma.h
@@ -119,7 +119,7 @@
 #define S3C2412_DMAREQSEL_UART2_1	S3C2412_DMAREQSEL_SRC(24)
 #endif /* CONFIG_CPU_S3C2412 */
 
-#ifdef CONFIG_CPU_S3C2443
+#if defined(CONFIG_CPU_S3C2416) || defined(CONFIG_CPU_S3C2443)
 
 #define S3C2443_DMAREQSEL_SRC(x)	((x) << 1)
 
diff --git a/arch/arm/plat-samsung/include/plat/regs-fb.h b/arch/arm/plat-samsung/include/plat/regs-fb.h
index 8f39aa5..9a78012 100644
--- a/arch/arm/plat-samsung/include/plat/regs-fb.h
+++ b/arch/arm/plat-samsung/include/plat/regs-fb.h
@@ -91,6 +91,9 @@
 #define VIDCON1_VSTATUS_BACKPORCH		(0x1 << 13)
 #define VIDCON1_VSTATUS_ACTIVE			(0x2 << 13)
 #define VIDCON1_VSTATUS_FRONTPORCH		(0x0 << 13)
+#define VIDCON1_VCLK_MASK			(0x3 << 9)
+#define VIDCON1_VCLK_HOLD			(0x0 << 9)
+#define VIDCON1_VCLK_RUN			(0x1 << 9)
 
 #define VIDCON1_INV_VCLK			(1 << 7)
 #define VIDCON1_INV_HSYNC			(1 << 6)
@@ -164,15 +167,17 @@
 #define VIDTCON1_HSPW(_x)			((_x) << 0)
 
 #define VIDTCON2				(0x18)
+#define VIDTCON2_LINEVAL_E(_x)			((((_x) & 0x800) >> 11) << 23)
 #define VIDTCON2_LINEVAL_MASK			(0x7ff << 11)
 #define VIDTCON2_LINEVAL_SHIFT			(11)
 #define VIDTCON2_LINEVAL_LIMIT			(0x7ff)
-#define VIDTCON2_LINEVAL(_x)			((_x) << 11)
+#define VIDTCON2_LINEVAL(_x)			(((_x) & 0x7ff) << 11)
 
+#define VIDTCON2_HOZVAL_E(_x)			((((_x) & 0x800) >> 11) << 22)
 #define VIDTCON2_HOZVAL_MASK			(0x7ff << 0)
 #define VIDTCON2_HOZVAL_SHIFT			(0)
 #define VIDTCON2_HOZVAL_LIMIT			(0x7ff)
-#define VIDTCON2_HOZVAL(_x)			((_x) << 0)
+#define VIDTCON2_HOZVAL(_x)			(((_x) & 0x7ff) << 0)
 
 /* WINCONx */
 
@@ -228,25 +233,29 @@
 /* Local input channels (windows 0-2) */
 #define SHADOWCON_CHx_LOCAL_ENABLE(_win)	(1 << (5 + (_win)))
 
+#define VIDOSDxA_TOPLEFT_X_E(_x)		((((_x) & 0x800) >> 11) << 23)
 #define VIDOSDxA_TOPLEFT_X_MASK			(0x7ff << 11)
 #define VIDOSDxA_TOPLEFT_X_SHIFT		(11)
 #define VIDOSDxA_TOPLEFT_X_LIMIT		(0x7ff)
-#define VIDOSDxA_TOPLEFT_X(_x)			((_x) << 11)
+#define VIDOSDxA_TOPLEFT_X(_x)			(((_x) & 0x7ff) << 11)
 
+#define VIDOSDxA_TOPLEFT_Y_E(_x)		((((_x) & 0x800) >> 11) << 22)
 #define VIDOSDxA_TOPLEFT_Y_MASK			(0x7ff << 0)
 #define VIDOSDxA_TOPLEFT_Y_SHIFT		(0)
 #define VIDOSDxA_TOPLEFT_Y_LIMIT		(0x7ff)
-#define VIDOSDxA_TOPLEFT_Y(_x)			((_x) << 0)
+#define VIDOSDxA_TOPLEFT_Y(_x)			(((_x) & 0x7ff) << 0)
 
+#define VIDOSDxB_BOTRIGHT_X_E(_x)		((((_x) & 0x800) >> 11) << 23)
 #define VIDOSDxB_BOTRIGHT_X_MASK		(0x7ff << 11)
 #define VIDOSDxB_BOTRIGHT_X_SHIFT		(11)
 #define VIDOSDxB_BOTRIGHT_X_LIMIT		(0x7ff)
-#define VIDOSDxB_BOTRIGHT_X(_x)			((_x) << 11)
+#define VIDOSDxB_BOTRIGHT_X(_x)			(((_x) & 0x7ff) << 11)
 
+#define VIDOSDxB_BOTRIGHT_Y_E(_x)		((((_x) & 0x800) >> 11) << 22)
 #define VIDOSDxB_BOTRIGHT_Y_MASK		(0x7ff << 0)
 #define VIDOSDxB_BOTRIGHT_Y_SHIFT		(0)
 #define VIDOSDxB_BOTRIGHT_Y_LIMIT		(0x7ff)
-#define VIDOSDxB_BOTRIGHT_Y(_x)			((_x) << 0)
+#define VIDOSDxB_BOTRIGHT_Y(_x)			(((_x) & 0x7ff) << 0)
 
 /* For VIDOSD[1..4]C */
 #define VIDISD14C_ALPHA0_R(_x)			((_x) << 20)
@@ -278,15 +287,17 @@
 #define VIDW_BUF_END1(_buff)			(0xD4 + ((_buff) * 8))
 #define VIDW_BUF_SIZE(_buff)			(0x100 + ((_buff) * 4))
 
+#define VIDW_BUF_SIZE_OFFSET_E(_x)		((((_x) & 0x2000) >> 13) << 27)
 #define VIDW_BUF_SIZE_OFFSET_MASK		(0x1fff << 13)
 #define VIDW_BUF_SIZE_OFFSET_SHIFT		(13)
 #define VIDW_BUF_SIZE_OFFSET_LIMIT		(0x1fff)
-#define VIDW_BUF_SIZE_OFFSET(_x)		((_x) << 13)
+#define VIDW_BUF_SIZE_OFFSET(_x)		(((_x) & 0x1fff) << 13)
 
+#define VIDW_BUF_SIZE_PAGEWIDTH_E(_x)		((((_x) & 0x2000) >> 13) << 26)
 #define VIDW_BUF_SIZE_PAGEWIDTH_MASK		(0x1fff << 0)
 #define VIDW_BUF_SIZE_PAGEWIDTH_SHIFT		(0)
 #define VIDW_BUF_SIZE_PAGEWIDTH_LIMIT		(0x1fff)
-#define VIDW_BUF_SIZE_PAGEWIDTH(_x)		((_x) << 0)
+#define VIDW_BUF_SIZE_PAGEWIDTH(_x)		(((_x) & 0x1fff) << 0)
 
 /* Interrupt controls and status */
 
@@ -384,3 +395,9 @@
 #define WPALCON_W0PAL_16BPP_A555		(0x5 << 0)
 #define WPALCON_W0PAL_16BPP_565			(0x6 << 0)
 
+/* Blending equation control */
+#define BLENDCON				(0x260)
+#define BLENDCON_NEW_MASK			(1 << 0)
+#define BLENDCON_NEW_8BIT_ALPHA_VALUE		(1 << 0)
+#define BLENDCON_NEW_4BIT_ALPHA_VALUE		(0 << 0)
+
diff --git a/arch/arm/plat-samsung/include/plat/regs-rtc.h b/arch/arm/plat-samsung/include/plat/regs-rtc.h
index 30b7cc1..0f8263e 100644
--- a/arch/arm/plat-samsung/include/plat/regs-rtc.h
+++ b/arch/arm/plat-samsung/include/plat/regs-rtc.h
@@ -18,51 +18,54 @@
 #define S3C2410_INTP_ALM	(1 << 1)
 #define S3C2410_INTP_TIC	(1 << 0)
 
-#define S3C2410_RTCCON	      S3C2410_RTCREG(0x40)
-#define S3C2410_RTCCON_RTCEN  (1<<0)
-#define S3C2410_RTCCON_CLKSEL (1<<1)
-#define S3C2410_RTCCON_CNTSEL (1<<2)
-#define S3C2410_RTCCON_CLKRST (1<<3)
-#define S3C64XX_RTCCON_TICEN  (1<<8)
+#define S3C2410_RTCCON		S3C2410_RTCREG(0x40)
+#define S3C2410_RTCCON_RTCEN	(1 << 0)
+#define S3C2410_RTCCON_CNTSEL	(1 << 2)
+#define S3C2410_RTCCON_CLKRST	(1 << 3)
+#define S3C2443_RTCCON_TICSEL	(1 << 4)
+#define S3C64XX_RTCCON_TICEN	(1 << 8)
 
-#define S3C64XX_RTCCON_TICMSK (0xF<<7)
-#define S3C64XX_RTCCON_TICSHT (7)
+#define S3C2410_TICNT		S3C2410_RTCREG(0x44)
+#define S3C2410_TICNT_ENABLE	(1 << 7)
 
-#define S3C2410_TICNT	      S3C2410_RTCREG(0x44)
-#define S3C2410_TICNT_ENABLE  (1<<7)
+/* S3C2443: tick count is 15 bit wide
+ * TICNT[6:0] contains upper 7 bits
+ * TICNT1[7:0] contains lower 8 bits
+ */
+#define S3C2443_TICNT_PART(x)	((x & 0x7f00) >> 8)
+#define S3C2443_TICNT1		S3C2410_RTCREG(0x4C)
+#define S3C2443_TICNT1_PART(x)	(x & 0xff)
 
-#define S3C2410_RTCALM	      S3C2410_RTCREG(0x50)
-#define S3C2410_RTCALM_ALMEN  (1<<6)
-#define S3C2410_RTCALM_YEAREN (1<<5)
-#define S3C2410_RTCALM_MONEN  (1<<4)
-#define S3C2410_RTCALM_DAYEN  (1<<3)
-#define S3C2410_RTCALM_HOUREN (1<<2)
-#define S3C2410_RTCALM_MINEN  (1<<1)
-#define S3C2410_RTCALM_SECEN  (1<<0)
+/* S3C2416: tick count is 32 bit wide
+ * TICNT[6:0] contains bits [14:8]
+ * TICNT1[7:0] contains lower 8 bits
+ * TICNT2[16:0] contains upper 17 bits
+ */
+#define S3C2416_TICNT2		S3C2410_RTCREG(0x48)
+#define S3C2416_TICNT2_PART(x)	((x & 0xffff8000) >> 15)
 
-#define S3C2410_RTCALM_ALL \
-  S3C2410_RTCALM_ALMEN | S3C2410_RTCALM_YEAREN | S3C2410_RTCALM_MONEN |\
-  S3C2410_RTCALM_DAYEN | S3C2410_RTCALM_HOUREN | S3C2410_RTCALM_MINEN |\
-  S3C2410_RTCALM_SECEN
+#define S3C2410_RTCALM		S3C2410_RTCREG(0x50)
+#define S3C2410_RTCALM_ALMEN	(1 << 6)
+#define S3C2410_RTCALM_YEAREN	(1 << 5)
+#define S3C2410_RTCALM_MONEN	(1 << 4)
+#define S3C2410_RTCALM_DAYEN	(1 << 3)
+#define S3C2410_RTCALM_HOUREN	(1 << 2)
+#define S3C2410_RTCALM_MINEN	(1 << 1)
+#define S3C2410_RTCALM_SECEN	(1 << 0)
 
+#define S3C2410_ALMSEC		S3C2410_RTCREG(0x54)
+#define S3C2410_ALMMIN		S3C2410_RTCREG(0x58)
+#define S3C2410_ALMHOUR		S3C2410_RTCREG(0x5c)
 
-#define S3C2410_ALMSEC	      S3C2410_RTCREG(0x54)
-#define S3C2410_ALMMIN	      S3C2410_RTCREG(0x58)
-#define S3C2410_ALMHOUR	      S3C2410_RTCREG(0x5c)
+#define S3C2410_ALMDATE		S3C2410_RTCREG(0x60)
+#define S3C2410_ALMMON		S3C2410_RTCREG(0x64)
+#define S3C2410_ALMYEAR		S3C2410_RTCREG(0x68)
 
-#define S3C2410_ALMDATE	      S3C2410_RTCREG(0x60)
-#define S3C2410_ALMMON	      S3C2410_RTCREG(0x64)
-#define S3C2410_ALMYEAR	      S3C2410_RTCREG(0x68)
-
-#define S3C2410_RTCRST	      S3C2410_RTCREG(0x6c)
-
-#define S3C2410_RTCSEC	      S3C2410_RTCREG(0x70)
-#define S3C2410_RTCMIN	      S3C2410_RTCREG(0x74)
-#define S3C2410_RTCHOUR	      S3C2410_RTCREG(0x78)
-#define S3C2410_RTCDATE	      S3C2410_RTCREG(0x7c)
-#define S3C2410_RTCDAY	      S3C2410_RTCREG(0x80)
-#define S3C2410_RTCMON	      S3C2410_RTCREG(0x84)
-#define S3C2410_RTCYEAR	      S3C2410_RTCREG(0x88)
-
+#define S3C2410_RTCSEC		S3C2410_RTCREG(0x70)
+#define S3C2410_RTCMIN		S3C2410_RTCREG(0x74)
+#define S3C2410_RTCHOUR		S3C2410_RTCREG(0x78)
+#define S3C2410_RTCDATE		S3C2410_RTCREG(0x7c)
+#define S3C2410_RTCMON		S3C2410_RTCREG(0x84)
+#define S3C2410_RTCYEAR		S3C2410_RTCREG(0x88)
 
 #endif /* __ASM_ARCH_REGS_RTC_H */
diff --git a/arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h b/arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h
index a111ad8..fcf2796 100644
--- a/arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h
+++ b/arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h
@@ -25,8 +25,9 @@
 #define S3C_HSOTG_PHYREG(x)	((x) + S3C_VA_USB_HSPHY)
 
 #define S3C_PHYPWR				S3C_HSOTG_PHYREG(0x00)
-#define SRC_PHYPWR_OTG_DISABLE			(1 << 4)
-#define SRC_PHYPWR_ANALOG_POWERDOWN		(1 << 3)
+#define S3C_PHYPWR_NORMAL_MASK			(0x19 << 0)
+#define S3C_PHYPWR_OTG_DISABLE			(1 << 4)
+#define S3C_PHYPWR_ANALOG_POWERDOWN		(1 << 3)
 #define SRC_PHYPWR_FORCE_SUSPEND		(1 << 1)
 
 #define S3C_PHYCLK				S3C_HSOTG_PHYREG(0x04)
@@ -42,7 +43,7 @@
 
 #define S3C_RSTCON				S3C_HSOTG_PHYREG(0x08)
 #define S3C_RSTCON_PHYCLK			(1 << 2)
-#define S3C_RSTCON_HCLK				(1 << 2)
+#define S3C_RSTCON_HCLK				(1 << 1)
 #define S3C_RSTCON_PHY				(1 << 0)
 
 #define S3C_PHYTUNE				S3C_HSOTG_PHYREG(0x20)
diff --git a/arch/arm/plat-samsung/include/plat/rtc-core.h b/arch/arm/plat-samsung/include/plat/rtc-core.h
new file mode 100644
index 0000000..21d8594
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/rtc-core.h
@@ -0,0 +1,27 @@
+/* linux/arch/arm/plat-samsung/include/plat/rtc-core.h
+ *
+ * Copyright (c) 2011 Heiko Stuebner <heiko@sntech.de>
+ *
+ * Samsung RTC Controller core functions
+ *
+ * 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 __ASM_PLAT_RTC_CORE_H
+#define __ASM_PLAT_RTC_CORE_H __FILE__
+
+/* These functions are only for use with the core support code, such as
+ * the cpu specific initialisation code
+ */
+
+/* re-define device name depending on support. */
+static inline void s3c_rtc_setname(char *name)
+{
+#if defined(CONFIG_SAMSUNG_DEV_RTC) || defined(CONFIG_PLAT_S3C24XX)
+	s3c_device_rtc.name = name;
+#endif
+}
+
+#endif /* __ASM_PLAT_RTC_CORE_H */
diff --git a/arch/arm/plat-samsung/include/plat/s3c2410.h b/arch/arm/plat-samsung/include/plat/s3c2410.h
index 3986497..55b0e5f 100644
--- a/arch/arm/plat-samsung/include/plat/s3c2410.h
+++ b/arch/arm/plat-samsung/include/plat/s3c2410.h
@@ -29,5 +29,3 @@
 #define s3c2410_init NULL
 #define s3c2410a_init NULL
 #endif
-
-extern int s3c2410_baseclk_add(void);
diff --git a/arch/arm/plat-samsung/include/plat/s3c2443.h b/arch/arm/plat-samsung/include/plat/s3c2443.h
index dce05b4..a5b794f 100644
--- a/arch/arm/plat-samsung/include/plat/s3c2443.h
+++ b/arch/arm/plat-samsung/include/plat/s3c2443.h
@@ -32,23 +32,3 @@
 #define s3c2443_init NULL
 #define s3c2443_restart NULL
 #endif
-
-/* common code used by s3c2443 and others.
- * note, not to be used outside of arch/arm/mach-s3c* */
-
-struct clk;	/* some files don't need clk.h otherwise */
-
-typedef unsigned int (*pll_fn)(unsigned int reg, unsigned int base);
-
-extern void s3c2443_common_setup_clocks(pll_fn get_mpll);
-extern void s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
-				       unsigned int *divs, int nr_divs,
-				       int divmask);
-
-extern int s3c2443_clkcon_enable_h(struct clk *clk, int enable);
-extern int s3c2443_clkcon_enable_p(struct clk *clk, int enable);
-extern int s3c2443_clkcon_enable_s(struct clk *clk, int enable);
-
-extern struct clksrc_clk clk_epllref;
-extern struct clksrc_clk clk_esysclk;
-extern struct clksrc_clk clk_msysclk;
diff --git a/arch/arm/plat-samsung/include/plat/s5p-clock.h b/arch/arm/plat-samsung/include/plat/s5p-clock.h
index 984bf9e..1de4b32 100644
--- a/arch/arm/plat-samsung/include/plat/s5p-clock.h
+++ b/arch/arm/plat-samsung/include/plat/s5p-clock.h
@@ -18,6 +18,8 @@
 #define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
 
 #define clk_fin_apll clk_ext_xtal_mux
+#define clk_fin_bpll clk_ext_xtal_mux
+#define clk_fin_cpll clk_ext_xtal_mux
 #define clk_fin_mpll clk_ext_xtal_mux
 #define clk_fin_epll clk_ext_xtal_mux
 #define clk_fin_dpll clk_ext_xtal_mux
@@ -29,6 +31,8 @@
 extern struct clk clk_48m;
 extern struct clk s5p_clk_27m;
 extern struct clk clk_fout_apll;
+extern struct clk clk_fout_bpll;
+extern struct clk clk_fout_cpll;
 extern struct clk clk_fout_mpll;
 extern struct clk clk_fout_epll;
 extern struct clk clk_fout_dpll;
@@ -37,6 +41,8 @@
 extern struct clk clk_vpll;
 
 extern struct clksrc_sources clk_src_apll;
+extern struct clksrc_sources clk_src_bpll;
+extern struct clksrc_sources clk_src_cpll;
 extern struct clksrc_sources clk_src_mpll;
 extern struct clksrc_sources clk_src_epll;
 extern struct clksrc_sources clk_src_dpll;
diff --git a/arch/arm/plat-samsung/include/plat/sdhci.h b/arch/arm/plat-samsung/include/plat/sdhci.h
index f82f888..317e246 100644
--- a/arch/arm/plat-samsung/include/plat/sdhci.h
+++ b/arch/arm/plat-samsung/include/plat/sdhci.h
@@ -40,6 +40,7 @@
  * struct s3c_sdhci_platdata() - Platform device data for Samsung SDHCI
  * @max_width: The maximum number of data bits supported.
  * @host_caps: Standard MMC host capabilities bit field.
+ * @host_caps2: The second standard MMC host capabilities bit field.
  * @cd_type: Type of Card Detection method (see cd_types enum above)
  * @clk_type: Type of clock divider method (see clk_types enum above)
  * @ext_cd_init: Initialize external card detect subsystem. Called on
@@ -63,6 +64,7 @@
 struct s3c_sdhci_platdata {
 	unsigned int	max_width;
 	unsigned int	host_caps;
+	unsigned int	host_caps2;
 	unsigned int	pm_caps;
 	enum cd_types	cd_type;
 	enum clk_types	clk_type;
diff --git a/arch/arm/plat-samsung/include/plat/udc-hs.h b/arch/arm/plat-samsung/include/plat/udc-hs.h
index a22a4f2..c9e3667 100644
--- a/arch/arm/plat-samsung/include/plat/udc-hs.h
+++ b/arch/arm/plat-samsung/include/plat/udc-hs.h
@@ -26,4 +26,9 @@
 struct s3c_hsotg_plat {
 	enum s3c_hsotg_dmamode	dma;
 	unsigned int		is_osc : 1;
+
+	int (*phy_init)(struct platform_device *pdev, int type);
+	int (*phy_exit)(struct platform_device *pdev, int type);
 };
+
+extern void s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd);
diff --git a/arch/arm/plat-samsung/include/plat/uncompress.h b/arch/arm/plat-samsung/include/plat/uncompress.h
index ee48e12..7e068d1 100644
--- a/arch/arm/plat-samsung/include/plat/uncompress.h
+++ b/arch/arm/plat-samsung/include/plat/uncompress.h
@@ -37,7 +37,9 @@
 /* how many bytes we allow into the FIFO at a time in FIFO mode */
 #define FIFO_MAX	 (14)
 
+#ifdef S3C_PA_UART
 #define uart_base S3C_PA_UART + (S3C_UART_OFFSET * CONFIG_S3C_LOWLEVEL_UART_PORT)
+#endif
 
 static __inline__ void
 uart_wr(unsigned int reg, unsigned int val)
diff --git a/arch/arm/plat-samsung/irq-vic-timer.c b/arch/arm/plat-samsung/irq-vic-timer.c
index 51583cd..f980cf3 100644
--- a/arch/arm/plat-samsung/irq-vic-timer.c
+++ b/arch/arm/plat-samsung/irq-vic-timer.c
@@ -19,6 +19,7 @@
 #include <linux/io.h>
 
 #include <mach/map.h>
+#include <plat/cpu.h>
 #include <plat/irq-vic-timer.h>
 #include <plat/regs-timer.h>
 
@@ -57,6 +58,21 @@
 	struct irq_chip_type *ct;
 	unsigned int i;
 
+#ifdef CONFIG_ARCH_EXYNOS
+	if (soc_is_exynos5250()) {
+		pirq[0] = EXYNOS5_IRQ_TIMER0_VIC;
+		pirq[1] = EXYNOS5_IRQ_TIMER1_VIC;
+		pirq[2] = EXYNOS5_IRQ_TIMER2_VIC;
+		pirq[3] = EXYNOS5_IRQ_TIMER3_VIC;
+		pirq[4] = EXYNOS5_IRQ_TIMER4_VIC;
+	} else {
+		pirq[0] = EXYNOS4_IRQ_TIMER0_VIC;
+		pirq[1] = EXYNOS4_IRQ_TIMER1_VIC;
+		pirq[2] = EXYNOS4_IRQ_TIMER2_VIC;
+		pirq[3] = EXYNOS4_IRQ_TIMER3_VIC;
+		pirq[4] = EXYNOS4_IRQ_TIMER4_VIC;
+	}
+#endif
 	s3c_tgc = irq_alloc_generic_chip("s3c-timer", 1, timer_irq,
 					 S3C64XX_TINT_CSTAT, handle_level_irq);
 
diff --git a/arch/arm/plat-samsung/platformdata.c b/arch/arm/plat-samsung/platformdata.c
index 0f70718..fa78aa7 100644
--- a/arch/arm/plat-samsung/platformdata.c
+++ b/arch/arm/plat-samsung/platformdata.c
@@ -53,6 +53,8 @@
 		set->cfg_gpio = pd->cfg_gpio;
 	if (pd->host_caps)
 		set->host_caps |= pd->host_caps;
+	if (pd->host_caps2)
+		set->host_caps2 |= pd->host_caps2;
 	if (pd->pm_caps)
 		set->pm_caps |= pd->pm_caps;
 	if (pd->clk_type)
diff --git a/arch/arm/plat-samsung/time.c b/arch/arm/plat-samsung/time.c
index e3bb806..4dcb11c 100644
--- a/arch/arm/plat-samsung/time.c
+++ b/arch/arm/plat-samsung/time.c
@@ -28,7 +28,6 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 
-#include <asm/system.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/plat-spear/include/plat/hardware.h b/arch/arm/plat-spear/include/plat/hardware.h
index 66d6772..70187d7 100644
--- a/arch/arm/plat-spear/include/plat/hardware.h
+++ b/arch/arm/plat-spear/include/plat/hardware.h
@@ -14,10 +14,4 @@
 #ifndef __PLAT_HARDWARE_H
 #define __PLAT_HARDWARE_H
 
-#ifndef __ASSEMBLY__
-#define IOMEM(x)	((void __iomem __force *)(x))
-#else
-#define IOMEM(x)	(x)
-#endif
-
 #endif /* __PLAT_HARDWARE_H */
diff --git a/arch/arm/plat-spear/include/plat/io.h b/arch/arm/plat-spear/include/plat/io.h
deleted file mode 100644
index 4d4ba82..0000000
--- a/arch/arm/plat-spear/include/plat/io.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * arch/arm/plat-spear/include/plat/io.h
- *
- * IO definitions for SPEAr platform
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.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.
- */
-
-#ifndef __PLAT_IO_H
-#define __PLAT_IO_H
-
-#define IO_SPACE_LIMIT		0xFFFFFFFF
-
-#define __io(a)			__typesafe_io(a)
-#define __mem_pci(a)		(a)
-
-#endif /* __PLAT_IO_H */
diff --git a/arch/arm/plat-spear/include/plat/keyboard.h b/arch/arm/plat-spear/include/plat/keyboard.h
index 68b5394..0562f13 100644
--- a/arch/arm/plat-spear/include/plat/keyboard.h
+++ b/arch/arm/plat-spear/include/plat/keyboard.h
@@ -15,7 +15,7 @@
 #include <linux/input/matrix_keypad.h>
 #include <linux/types.h>
 
-#define DECLARE_KEYMAP(_name) \
+#define DECLARE_9x9_KEYMAP(_name) \
 int _name[] = { \
 	KEY(0, 0, KEY_ESC), \
 	KEY(0, 1, KEY_1), \
@@ -62,24 +62,6 @@
 	KEY(4, 6, KEY_Z), \
 	KEY(4, 7, KEY_X), \
 	KEY(4, 8, KEY_C), \
-	KEY(4, 0, KEY_L), \
-	KEY(4, 1, KEY_SEMICOLON), \
-	KEY(4, 2, KEY_APOSTROPHE), \
-	KEY(4, 3, KEY_GRAVE), \
-	KEY(4, 4, KEY_LEFTSHIFT), \
-	KEY(4, 5, KEY_BACKSLASH), \
-	KEY(4, 6, KEY_Z), \
-	KEY(4, 7, KEY_X), \
-	KEY(4, 8, KEY_C), \
-	KEY(4, 0, KEY_L), \
-	KEY(4, 1, KEY_SEMICOLON), \
-	KEY(4, 2, KEY_APOSTROPHE), \
-	KEY(4, 3, KEY_GRAVE), \
-	KEY(4, 4, KEY_LEFTSHIFT), \
-	KEY(4, 5, KEY_BACKSLASH), \
-	KEY(4, 6, KEY_Z), \
-	KEY(4, 7, KEY_X), \
-	KEY(4, 8, KEY_C), \
 	KEY(5, 0, KEY_V), \
 	KEY(5, 1, KEY_B), \
 	KEY(5, 2, KEY_N), \
@@ -118,10 +100,55 @@
 	KEY(8, 8, KEY_KP0), \
 }
 
+#define DECLARE_6x6_KEYMAP(_name) \
+int _name[] = { \
+	KEY(0, 0, KEY_RESERVED), \
+	KEY(0, 1, KEY_1), \
+	KEY(0, 2, KEY_2), \
+	KEY(0, 3, KEY_3), \
+	KEY(0, 4, KEY_4), \
+	KEY(0, 5, KEY_5), \
+	KEY(1, 0, KEY_Q), \
+	KEY(1, 1, KEY_W), \
+	KEY(1, 2, KEY_E), \
+	KEY(1, 3, KEY_R), \
+	KEY(1, 4, KEY_T), \
+	KEY(1, 5, KEY_Y), \
+	KEY(2, 0, KEY_D), \
+	KEY(2, 1, KEY_F), \
+	KEY(2, 2, KEY_G), \
+	KEY(2, 3, KEY_H), \
+	KEY(2, 4, KEY_J), \
+	KEY(2, 5, KEY_K), \
+	KEY(3, 0, KEY_B), \
+	KEY(3, 1, KEY_N), \
+	KEY(3, 2, KEY_M), \
+	KEY(3, 3, KEY_COMMA), \
+	KEY(3, 4, KEY_DOT), \
+	KEY(3, 5, KEY_SLASH), \
+	KEY(4, 0, KEY_F6), \
+	KEY(4, 1, KEY_F7), \
+	KEY(4, 2, KEY_F8), \
+	KEY(4, 3, KEY_F9), \
+	KEY(4, 4, KEY_F10), \
+	KEY(4, 5, KEY_NUMLOCK), \
+	KEY(5, 0, KEY_KP2), \
+	KEY(5, 1, KEY_KP3), \
+	KEY(5, 2, KEY_KP0), \
+	KEY(5, 3, KEY_KPDOT), \
+	KEY(5, 4, KEY_RO), \
+	KEY(5, 5, KEY_ZENKAKUHANKAKU), \
+}
+
+#define KEYPAD_9x9     0
+#define KEYPAD_6x6     1
+#define KEYPAD_2x2     2
+
 /**
  * struct kbd_platform_data - spear keyboard platform data
  * keymap: pointer to keymap data (table and size)
  * rep: enables key autorepeat
+ * mode: choose keyboard support(9x9, 6x6, 2x2)
  *
  * This structure is supposed to be used by platform code to supply
  * keymaps to drivers that implement keyboards.
@@ -129,13 +156,7 @@
 struct kbd_platform_data {
 	const struct matrix_keymap_data *keymap;
 	bool rep;
+	unsigned int mode;
 };
 
-/* This function is used to set platform data field of pdev->dev */
-static inline void
-kbd_set_plat_data(struct platform_device *pdev, struct kbd_platform_data *data)
-{
-	pdev->dev.platform_data = data;
-}
-
 #endif /* __PLAT_KEYBOARD_H */
diff --git a/arch/arm/plat-spear/include/plat/system.h b/arch/arm/plat-spear/include/plat/system.h
deleted file mode 100644
index 86c6f83..0000000
--- a/arch/arm/plat-spear/include/plat/system.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * arch/arm/plat-spear/include/plat/system.h
- *
- * SPEAr platform specific architecture functions
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.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.
- */
-
-#ifndef __PLAT_SYSTEM_H
-#define __PLAT_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-	/*
-	 * This should do all the clock switching
-	 * and wait for interrupt tricks
-	 */
-	cpu_do_idle();
-}
-
-#endif /* __PLAT_SYSTEM_H */
diff --git a/arch/arm/plat-spear/restart.c b/arch/arm/plat-spear/restart.c
index 2b4e3d8..16f203e 100644
--- a/arch/arm/plat-spear/restart.c
+++ b/arch/arm/plat-spear/restart.c
@@ -11,6 +11,7 @@
  * warranty of any kind, whether express or implied.
  */
 #include <linux/io.h>
+#include <asm/system_misc.h>
 #include <asm/hardware/sp810.h>
 #include <mach/hardware.h>
 #include <mach/generic.h>
diff --git a/arch/arm/plat-versatile/Kconfig b/arch/arm/plat-versatile/Kconfig
index 52353be..043f7b0 100644
--- a/arch/arm/plat-versatile/Kconfig
+++ b/arch/arm/plat-versatile/Kconfig
@@ -11,7 +11,6 @@
 	depends on ARCH_REALVIEW || ARCH_VERSATILE
 
 config PLAT_VERSATILE_SCHED_CLOCK
-	def_bool y if !ARCH_INTEGRATOR_AP
-	select HAVE_SCHED_CLOCK
+	def_bool y
 
 endif
diff --git a/arch/arm/plat-versatile/Makefile b/arch/arm/plat-versatile/Makefile
index 69714db..a5cb194 100644
--- a/arch/arm/plat-versatile/Makefile
+++ b/arch/arm/plat-versatile/Makefile
@@ -1,5 +1,4 @@
 obj-y	:= clock.o
-obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
 obj-$(CONFIG_PLAT_VERSATILE_CLCD) += clcd.o
 obj-$(CONFIG_PLAT_VERSATILE_FPGA_IRQ) += fpga-irq.o
 obj-$(CONFIG_PLAT_VERSATILE_LEDS) += leds.o
diff --git a/arch/arm/plat-versatile/localtimer.c b/arch/arm/plat-versatile/localtimer.c
deleted file mode 100644
index 0fb3961..0000000
--- a/arch/arm/plat-versatile/localtimer.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *  linux/arch/arm/plat-versatile/localtimer.c
- *
- *  Copyright (C) 2002 ARM Ltd.
- *  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/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-#include <mach/irqs.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	evt->irq = IRQ_LOCALTIMER;
-	twd_timer_setup(evt);
-	return 0;
-}
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 8f3ccdd..858748e 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -18,7 +18,9 @@
 #include <linux/smp.h>
 #include <linux/init.h>
 
+#include <asm/cp15.h>
 #include <asm/cputype.h>
+#include <asm/system_info.h>
 #include <asm/thread_notify.h>
 #include <asm/vfp.h>
 
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
index 7c756fb..afeae89 100644
--- a/arch/avr32/boards/atngw100/setup.c
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -97,6 +97,7 @@
 	.rdy_pin	= GPIO_PIN_PB(28),
 	.enable_pin	= GPIO_PIN_PE(23),
 	.bus_width_16	= true,
+	.ecc_mode	= NAND_ECC_SOFT,
 	.parts		= nand_partitions,
 	.num_parts	= ARRAY_SIZE(nand_partitions),
 };
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index c56ddac..dc52633 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -95,6 +95,7 @@
 	.ale		= 22,
 	.rdy_pin	= GPIO_PIN_PB(30),
 	.enable_pin	= GPIO_PIN_PB(29),
+	.ecc_mode	= NAND_ECC_SOFT,
 	.parts		= nand_partitions,
 	.num_parts	= ARRAY_SIZE(num_partitions),
 };
diff --git a/arch/avr32/boot/images/Makefile b/arch/avr32/boot/images/Makefile
index 1848bf0..2a3b539 100644
--- a/arch/avr32/boot/images/Makefile
+++ b/arch/avr32/boot/images/Makefile
@@ -6,8 +6,6 @@
 # for more details.
 #
 
-MKIMAGE		:= $(srctree)/scripts/mkuboot.sh
-
 extra-y		:= vmlinux.bin vmlinux.gz
 
 OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note.gnu.build-id
@@ -17,10 +15,9 @@
 $(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
 	$(call if_changed,gzip)
 
-quiet_cmd_uimage = UIMAGE $@
-      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A avr32 -O linux -T kernel	\
-		-C gzip -a $(CONFIG_LOAD_ADDRESS) -e $(CONFIG_ENTRY_ADDRESS)	\
-		-n 'Linux-$(KERNELRELEASE)' -d $< $@
+UIMAGE_LOADADDR = $(CONFIG_LOAD_ADDRESS)
+UIMAGE_ENTRYADDR = $(CONFIG_ENTRY_ADDRESS)
+UIMAGE_COMPRESSION = gzip
 
 targets += uImage uImage.srec
 $(obj)/uImage: $(obj)/vmlinux.gz
diff --git a/arch/avr32/include/asm/atomic.h b/arch/avr32/include/asm/atomic.h
index e0ac263..6140727 100644
--- a/arch/avr32/include/asm/atomic.h
+++ b/arch/avr32/include/asm/atomic.h
@@ -15,7 +15,7 @@
 #define __ASM_AVR32_ATOMIC_H
 
 #include <linux/types.h>
-#include <asm/system.h>
+#include <asm/cmpxchg.h>
 
 #define ATOMIC_INIT(i)  { (i) }
 
diff --git a/arch/avr32/include/asm/barrier.h b/arch/avr32/include/asm/barrier.h
new file mode 100644
index 0000000..0961275
--- /dev/null
+++ b/arch/avr32/include/asm/barrier.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * 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 __ASM_AVR32_BARRIER_H
+#define __ASM_AVR32_BARRIER_H
+
+#define nop()			asm volatile("nop")
+
+#define mb()			asm volatile("" : : : "memory")
+#define rmb()			mb()
+#define wmb()			asm volatile("sync 0" : : : "memory")
+#define read_barrier_depends()  do { } while(0)
+#define set_mb(var, value)      do { var = value; mb(); } while(0)
+
+#ifdef CONFIG_SMP
+# error "The AVR32 port does not support SMP"
+#else
+# define smp_mb()		barrier()
+# define smp_rmb()		barrier()
+# define smp_wmb()		barrier()
+# define smp_read_barrier_depends() do { } while(0)
+#endif
+
+
+#endif /* __ASM_AVR32_BARRIER_H */
diff --git a/arch/avr32/include/asm/bitops.h b/arch/avr32/include/asm/bitops.h
index b70c19b..ebe7ad3 100644
--- a/arch/avr32/include/asm/bitops.h
+++ b/arch/avr32/include/asm/bitops.h
@@ -13,7 +13,6 @@
 #endif
 
 #include <asm/byteorder.h>
-#include <asm/system.h>
 
 /*
  * clear_bit() doesn't provide any barrier for the compiler
diff --git a/arch/avr32/include/asm/bug.h b/arch/avr32/include/asm/bug.h
index 2aa373cc..85a92d09 100644
--- a/arch/avr32/include/asm/bug.h
+++ b/arch/avr32/include/asm/bug.h
@@ -70,4 +70,9 @@
 
 #include <asm-generic/bug.h>
 
+struct pt_regs;
+void die(const char *str, struct pt_regs *regs, long err);
+void _exception(long signr, struct pt_regs *regs, int code,
+		unsigned long addr);
+
 #endif /* __ASM_AVR32_BUG_H */
diff --git a/arch/avr32/include/asm/cmpxchg.h b/arch/avr32/include/asm/cmpxchg.h
new file mode 100644
index 0000000..962a6ae
--- /dev/null
+++ b/arch/avr32/include/asm/cmpxchg.h
@@ -0,0 +1,117 @@
+/*
+ * Atomic operations that C can't guarantee us.  Useful for
+ * resource counting etc.
+ *
+ * But use these as seldom as possible since they are slower than
+ * regular operations.
+ *
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * 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 __ASM_AVR32_CMPXCHG_H
+#define __ASM_AVR32_CMPXCHG_H
+
+#define xchg(ptr,x) \
+	((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+extern void __xchg_called_with_bad_pointer(void);
+
+static inline unsigned long xchg_u32(u32 val, volatile u32 *m)
+{
+	u32 ret;
+
+	asm volatile("xchg %[ret], %[m], %[val]"
+			: [ret] "=&r"(ret), "=m"(*m)
+			: "m"(*m), [m] "r"(m), [val] "r"(val)
+			: "memory");
+	return ret;
+}
+
+static inline unsigned long __xchg(unsigned long x,
+				       volatile void *ptr,
+				       int size)
+{
+	switch(size) {
+	case 4:
+		return xchg_u32(x, ptr);
+	default:
+		__xchg_called_with_bad_pointer();
+		return x;
+	}
+}
+
+static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old,
+					  unsigned long new)
+{
+	__u32 ret;
+
+	asm volatile(
+		"1:	ssrf	5\n"
+		"	ld.w	%[ret], %[m]\n"
+		"	cp.w	%[ret], %[old]\n"
+		"	brne	2f\n"
+		"	stcond	%[m], %[new]\n"
+		"	brne	1b\n"
+		"2:\n"
+		: [ret] "=&r"(ret), [m] "=m"(*m)
+		: "m"(m), [old] "ir"(old), [new] "r"(new)
+		: "memory", "cc");
+	return ret;
+}
+
+extern unsigned long __cmpxchg_u64_unsupported_on_32bit_kernels(
+        volatile int * m, unsigned long old, unsigned long new);
+#define __cmpxchg_u64 __cmpxchg_u64_unsupported_on_32bit_kernels
+
+/* This function doesn't exist, so you'll get a linker error
+   if something tries to do an invalid cmpxchg().  */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+#define __HAVE_ARCH_CMPXCHG 1
+
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+				      unsigned long new, int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32(ptr, old, new);
+	case 8:
+		return __cmpxchg_u64(ptr, old, new);
+	}
+
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg(ptr, old, new)					\
+	((typeof(*(ptr)))__cmpxchg((ptr), (unsigned long)(old),	\
+				   (unsigned long)(new),	\
+				   sizeof(*(ptr))))
+
+#include <asm-generic/cmpxchg-local.h>
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+				      unsigned long old,
+				      unsigned long new, int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32(ptr, old, new);
+	default:
+		return __cmpxchg_local_generic(ptr, old, new, size);
+	}
+
+	return old;
+}
+
+#define cmpxchg_local(ptr, old, new)					\
+	((typeof(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(old),	\
+				   (unsigned long)(new),		\
+				   sizeof(*(ptr))))
+
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#endif /* __ASM_AVR32_CMPXCHG_H */
diff --git a/arch/avr32/include/asm/exec.h b/arch/avr32/include/asm/exec.h
new file mode 100644
index 0000000..f467be8
--- /dev/null
+++ b/arch/avr32/include/asm/exec.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * 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 __ASM_AVR32_EXEC_H
+#define __ASM_AVR32_EXEC_H
+
+#define arch_align_stack(x)	(x)
+
+#endif /* __ASM_AVR32_EXEC_H */
diff --git a/arch/avr32/include/asm/io.h b/arch/avr32/include/asm/io.h
index 22c97ef..cf60d0a 100644
--- a/arch/avr32/include/asm/io.h
+++ b/arch/avr32/include/asm/io.h
@@ -1,6 +1,7 @@
 #ifndef __ASM_AVR32_IO_H
 #define __ASM_AVR32_IO_H
 
+#include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/types.h>
diff --git a/arch/avr32/include/asm/posix_types.h b/arch/avr32/include/asm/posix_types.h
index fe0c0c0..74667bf 100644
--- a/arch/avr32/include/asm/posix_types.h
+++ b/arch/avr32/include/asm/posix_types.h
@@ -14,112 +14,27 @@
  * assume GCC is being used.
  */
 
-typedef unsigned long   __kernel_ino_t;
 typedef unsigned short  __kernel_mode_t;
+#define __kernel_mode_t __kernel_mode_t
+
 typedef unsigned short  __kernel_nlink_t;
-typedef long            __kernel_off_t;
-typedef int             __kernel_pid_t;
+#define __kernel_nlink_t __kernel_nlink_t
+
 typedef unsigned short  __kernel_ipc_pid_t;
-typedef unsigned int	__kernel_uid_t;
-typedef unsigned int	__kernel_gid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
+
 typedef unsigned long	__kernel_size_t;
 typedef long		__kernel_ssize_t;
 typedef int             __kernel_ptrdiff_t;
-typedef long            __kernel_time_t;
-typedef long            __kernel_suseconds_t;
-typedef long            __kernel_clock_t;
-typedef int             __kernel_timer_t;
-typedef int             __kernel_clockid_t;
-typedef int             __kernel_daddr_t;
-typedef char *          __kernel_caddr_t;
-typedef unsigned short  __kernel_uid16_t;
-typedef unsigned short  __kernel_gid16_t;
-typedef unsigned int    __kernel_uid32_t;
-typedef unsigned int    __kernel_gid32_t;
+#define __kernel_size_t __kernel_size_t
 
 typedef unsigned short  __kernel_old_uid_t;
 typedef unsigned short  __kernel_old_gid_t;
+#define __kernel_old_uid_t __kernel_old_uid_t
+
 typedef unsigned short  __kernel_old_dev_t;
+#define __kernel_old_dev_t __kernel_old_dev_t
 
-#ifdef __GNUC__
-typedef long long       __kernel_loff_t;
-#endif
-
-typedef struct {
-    int     val[2];
-} __kernel_fsid_t;
-
-#if defined(__KERNEL__)
-
-#undef  __FD_SET
-static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-    unsigned long __tmp = __fd / __NFDBITS;
-    unsigned long __rem = __fd % __NFDBITS;
-    __fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
-}
-
-#undef  __FD_CLR
-static __inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-    unsigned long __tmp = __fd / __NFDBITS;
-    unsigned long __rem = __fd % __NFDBITS;
-    __fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
-}
-
-
-#undef  __FD_ISSET
-static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
-{
-    unsigned long __tmp = __fd / __NFDBITS;
-    unsigned long __rem = __fd % __NFDBITS;
-    return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
-}
-
-/*
- * This will unroll the loop for the normal constant case (8 ints,
- * for a 256-bit fd_set)
- */
-#undef  __FD_ZERO
-static __inline__ void __FD_ZERO(__kernel_fd_set *__p)
-{
-    unsigned long *__tmp = __p->fds_bits;
-    int __i;
-
-    if (__builtin_constant_p(__FDSET_LONGS)) {
-        switch (__FDSET_LONGS) {
-            case 16:
-                __tmp[ 0] = 0; __tmp[ 1] = 0;
-                __tmp[ 2] = 0; __tmp[ 3] = 0;
-                __tmp[ 4] = 0; __tmp[ 5] = 0;
-                __tmp[ 6] = 0; __tmp[ 7] = 0;
-                __tmp[ 8] = 0; __tmp[ 9] = 0;
-                __tmp[10] = 0; __tmp[11] = 0;
-                __tmp[12] = 0; __tmp[13] = 0;
-                __tmp[14] = 0; __tmp[15] = 0;
-                return;
-
-            case 8:
-                __tmp[ 0] = 0; __tmp[ 1] = 0;
-                __tmp[ 2] = 0; __tmp[ 3] = 0;
-                __tmp[ 4] = 0; __tmp[ 5] = 0;
-                __tmp[ 6] = 0; __tmp[ 7] = 0;
-                return;
-
-            case 4:
-                __tmp[ 0] = 0; __tmp[ 1] = 0;
-                __tmp[ 2] = 0; __tmp[ 3] = 0;
-                return;
-        }
-    }
-    __i = __FDSET_LONGS;
-    while (__i) {
-        __i--;
-        *__tmp = 0;
-        __tmp++;
-    }
-}
-
-#endif /* defined(__KERNEL__) */
+#include <asm-generic/posix_types.h>
 
 #endif /* __ASM_AVR32_POSIX_TYPES_H */
diff --git a/arch/avr32/include/asm/switch_to.h b/arch/avr32/include/asm/switch_to.h
new file mode 100644
index 0000000..9a8e9d5
--- /dev/null
+++ b/arch/avr32/include/asm/switch_to.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * 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 __ASM_AVR32_SWITCH_TO_H
+#define __ASM_AVR32_SWITCH_TO_H
+
+/*
+ * Help PathFinder and other Nexus-compliant debuggers keep track of
+ * the current PID by emitting an Ownership Trace Message each time we
+ * switch task.
+ */
+#ifdef CONFIG_OWNERSHIP_TRACE
+#include <asm/ocd.h>
+#define finish_arch_switch(prev)			\
+	do {						\
+		ocd_write(PID, prev->pid);		\
+		ocd_write(PID, current->pid);		\
+	} while(0)
+#endif
+
+/*
+ * switch_to(prev, next, last) should switch from task `prev' to task
+ * `next'. `prev' will never be the same as `next'.
+ *
+ * We just delegate everything to the __switch_to assembly function,
+ * which is implemented in arch/avr32/kernel/switch_to.S
+ *
+ * mb() tells GCC not to cache `current' across this call.
+ */
+struct cpu_context;
+struct task_struct;
+extern struct task_struct *__switch_to(struct task_struct *,
+				       struct cpu_context *,
+				       struct cpu_context *);
+#define switch_to(prev, next, last)					\
+	do {								\
+		last = __switch_to(prev, &prev->thread.cpu_context + 1,	\
+				   &next->thread.cpu_context);		\
+	} while (0)
+
+
+#endif /* __ASM_AVR32_SWITCH_TO_H */
diff --git a/arch/avr32/include/asm/system.h b/arch/avr32/include/asm/system.h
deleted file mode 100644
index 62d9ded..0000000
--- a/arch/avr32/include/asm/system.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2004-2006 Atmel Corporation
- *
- * 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 __ASM_AVR32_SYSTEM_H
-#define __ASM_AVR32_SYSTEM_H
-
-#include <linux/compiler.h>
-#include <linux/linkage.h>
-#include <linux/types.h>
-
-#include <asm/ptrace.h>
-#include <asm/sysreg.h>
-
-#define xchg(ptr,x) \
-	((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-
-#define nop() asm volatile("nop")
-
-#define mb()			asm volatile("" : : : "memory")
-#define rmb()			mb()
-#define wmb()			asm volatile("sync 0" : : : "memory")
-#define read_barrier_depends()  do { } while(0)
-#define set_mb(var, value)      do { var = value; mb(); } while(0)
-
-/*
- * Help PathFinder and other Nexus-compliant debuggers keep track of
- * the current PID by emitting an Ownership Trace Message each time we
- * switch task.
- */
-#ifdef CONFIG_OWNERSHIP_TRACE
-#include <asm/ocd.h>
-#define finish_arch_switch(prev)			\
-	do {						\
-		ocd_write(PID, prev->pid);		\
-		ocd_write(PID, current->pid);		\
-	} while(0)
-#endif
-
-/*
- * switch_to(prev, next, last) should switch from task `prev' to task
- * `next'. `prev' will never be the same as `next'.
- *
- * We just delegate everything to the __switch_to assembly function,
- * which is implemented in arch/avr32/kernel/switch_to.S
- *
- * mb() tells GCC not to cache `current' across this call.
- */
-struct cpu_context;
-struct task_struct;
-extern struct task_struct *__switch_to(struct task_struct *,
-				       struct cpu_context *,
-				       struct cpu_context *);
-#define switch_to(prev, next, last)					\
-	do {								\
-		last = __switch_to(prev, &prev->thread.cpu_context + 1,	\
-				   &next->thread.cpu_context);		\
-	} while (0)
-
-#ifdef CONFIG_SMP
-# error "The AVR32 port does not support SMP"
-#else
-# define smp_mb()		barrier()
-# define smp_rmb()		barrier()
-# define smp_wmb()		barrier()
-# define smp_read_barrier_depends() do { } while(0)
-#endif
-
-#include <linux/irqflags.h>
-
-extern void __xchg_called_with_bad_pointer(void);
-
-static inline unsigned long xchg_u32(u32 val, volatile u32 *m)
-{
-	u32 ret;
-
-	asm volatile("xchg %[ret], %[m], %[val]"
-			: [ret] "=&r"(ret), "=m"(*m)
-			: "m"(*m), [m] "r"(m), [val] "r"(val)
-			: "memory");
-	return ret;
-}
-
-static inline unsigned long __xchg(unsigned long x,
-				       volatile void *ptr,
-				       int size)
-{
-	switch(size) {
-	case 4:
-		return xchg_u32(x, ptr);
-	default:
-		__xchg_called_with_bad_pointer();
-		return x;
-	}
-}
-
-static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old,
-					  unsigned long new)
-{
-	__u32 ret;
-
-	asm volatile(
-		"1:	ssrf	5\n"
-		"	ld.w	%[ret], %[m]\n"
-		"	cp.w	%[ret], %[old]\n"
-		"	brne	2f\n"
-		"	stcond	%[m], %[new]\n"
-		"	brne	1b\n"
-		"2:\n"
-		: [ret] "=&r"(ret), [m] "=m"(*m)
-		: "m"(m), [old] "ir"(old), [new] "r"(new)
-		: "memory", "cc");
-	return ret;
-}
-
-extern unsigned long __cmpxchg_u64_unsupported_on_32bit_kernels(
-        volatile int * m, unsigned long old, unsigned long new);
-#define __cmpxchg_u64 __cmpxchg_u64_unsupported_on_32bit_kernels
-
-/* This function doesn't exist, so you'll get a linker error
-   if something tries to do an invalid cmpxchg().  */
-extern void __cmpxchg_called_with_bad_pointer(void);
-
-#define __HAVE_ARCH_CMPXCHG 1
-
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-				      unsigned long new, int size)
-{
-	switch (size) {
-	case 4:
-		return __cmpxchg_u32(ptr, old, new);
-	case 8:
-		return __cmpxchg_u64(ptr, old, new);
-	}
-
-	__cmpxchg_called_with_bad_pointer();
-	return old;
-}
-
-#define cmpxchg(ptr, old, new)					\
-	((typeof(*(ptr)))__cmpxchg((ptr), (unsigned long)(old),	\
-				   (unsigned long)(new),	\
-				   sizeof(*(ptr))))
-
-#include <asm-generic/cmpxchg-local.h>
-
-static inline unsigned long __cmpxchg_local(volatile void *ptr,
-				      unsigned long old,
-				      unsigned long new, int size)
-{
-	switch (size) {
-	case 4:
-		return __cmpxchg_u32(ptr, old, new);
-	default:
-		return __cmpxchg_local_generic(ptr, old, new, size);
-	}
-
-	return old;
-}
-
-#define cmpxchg_local(ptr, old, new)					\
-	((typeof(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(old),	\
-				   (unsigned long)(new),		\
-				   sizeof(*(ptr))))
-
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-
-struct pt_regs;
-void die(const char *str, struct pt_regs *regs, long err);
-void _exception(long signr, struct pt_regs *regs, int code,
-		unsigned long addr);
-
-#define arch_align_stack(x)	(x)
-
-#endif /* __ASM_AVR32_SYSTEM_H */
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index 402a7bb..0445c4f 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -1055,8 +1055,6 @@
 	return at32_usarts[id];
 }
 
-struct platform_device *atmel_default_console_device;
-
 void __init at32_setup_serial_console(unsigned int usart_id)
 {
 	atmel_default_console_device = at32_usarts[usart_id];
@@ -1353,7 +1351,6 @@
 		goto fail;
 
 	slave->sdata.dma_dev = &dw_dmac0_device.dev;
-	slave->sdata.reg_width = DW_DMA_SLAVE_WIDTH_32BIT;
 	slave->sdata.cfg_hi = (DWC_CFGH_SRC_PER(0)
 				| DWC_CFGH_DST_PER(1));
 	slave->sdata.cfg_lo &= ~(DWC_CFGL_HS_DST_POL
@@ -2048,27 +2045,19 @@
 	/* Check if DMA slave interface for capture should be configured. */
 	if (flags & AC97C_CAPTURE) {
 		rx_dws->dma_dev = &dw_dmac0_device.dev;
-		rx_dws->reg_width = DW_DMA_SLAVE_WIDTH_16BIT;
 		rx_dws->cfg_hi = DWC_CFGH_SRC_PER(3);
 		rx_dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL);
 		rx_dws->src_master = 0;
 		rx_dws->dst_master = 1;
-		rx_dws->src_msize = DW_DMA_MSIZE_1;
-		rx_dws->dst_msize = DW_DMA_MSIZE_1;
-		rx_dws->fc = DW_DMA_FC_D_P2M;
 	}
 
 	/* Check if DMA slave interface for playback should be configured. */
 	if (flags & AC97C_PLAYBACK) {
 		tx_dws->dma_dev = &dw_dmac0_device.dev;
-		tx_dws->reg_width = DW_DMA_SLAVE_WIDTH_16BIT;
 		tx_dws->cfg_hi = DWC_CFGH_DST_PER(4);
 		tx_dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL);
 		tx_dws->src_master = 0;
 		tx_dws->dst_master = 1;
-		tx_dws->src_msize = DW_DMA_MSIZE_1;
-		tx_dws->dst_msize = DW_DMA_MSIZE_1;
-		tx_dws->fc = DW_DMA_FC_D_M2P;
 	}
 
 	if (platform_device_add_data(pdev, data,
@@ -2138,14 +2127,10 @@
 	dws = &data->dws;
 
 	dws->dma_dev = &dw_dmac0_device.dev;
-	dws->reg_width = DW_DMA_SLAVE_WIDTH_32BIT;
 	dws->cfg_hi = DWC_CFGH_DST_PER(2);
 	dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL);
 	dws->src_master = 0;
 	dws->dst_master = 1;
-	dws->src_msize = DW_DMA_MSIZE_1;
-	dws->dst_msize = DW_DMA_MSIZE_1;
-	dws->fc = DW_DMA_FC_D_M2P;
 
 	if (platform_device_add_data(pdev, data,
 				sizeof(struct atmel_abdac_pdata)))
diff --git a/arch/avr32/mach-at32ap/cpufreq.c b/arch/avr32/mach-at32ap/cpufreq.c
index 6277433..18b7656 100644
--- a/arch/avr32/mach-at32ap/cpufreq.c
+++ b/arch/avr32/mach-at32ap/cpufreq.c
@@ -19,7 +19,6 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/export.h>
-#include <asm/system.h>
 
 static struct clk *cpuclk;
 
diff --git a/arch/avr32/mach-at32ap/include/mach/atmel-mci.h b/arch/avr32/mach-at32ap/include/mach/atmel-mci.h
index a9b3896..4bba585 100644
--- a/arch/avr32/mach-at32ap/include/mach/atmel-mci.h
+++ b/arch/avr32/mach-at32ap/include/mach/atmel-mci.h
@@ -14,11 +14,4 @@
 #define	slave_data_ptr(s)	(&(s)->sdata)
 #define find_slave_dev(s)	((s)->sdata.dma_dev)
 
-#define	setup_dma_addr(s, t, r)	do {		\
-	if (s) {				\
-		(s)->sdata.tx_reg = (t);	\
-		(s)->sdata.rx_reg = (r);	\
-	}					\
-} while (0)
-
 #endif /* __MACH_ATMEL_MCI_H */
diff --git a/arch/avr32/mach-at32ap/include/mach/board.h b/arch/avr32/mach-at32ap/include/mach/board.h
index 67b111c..70742ec 100644
--- a/arch/avr32/mach-at32ap/include/mach/board.h
+++ b/arch/avr32/mach-at32ap/include/mach/board.h
@@ -7,6 +7,7 @@
 #include <linux/types.h>
 #include <linux/serial.h>
 #include <linux/platform_data/macb.h>
+#include <linux/platform_data/atmel.h>
 
 #define GPIO_PIN_NONE	(-1)
 
@@ -116,18 +117,6 @@
 at32_add_device_cf(unsigned int id, unsigned int extint,
 		struct cf_platform_data *data);
 
-/* NAND / SmartMedia */
-struct atmel_nand_data {
-	int	enable_pin;	/* chip enable */
-	int	det_pin;	/* card detect */
-	int	rdy_pin;	/* ready/busy */
-	u8	rdy_pin_active_low;	/* rdy_pin value is inverted */
-	u8	ale;		/* address line number connected to ALE */
-	u8	cle;		/* address line number connected to CLE */
-	u8	bus_width_16;	/* buswidth is 16 bit */
-	struct mtd_partition *parts;
-	unsigned int	num_parts;
-};
 struct platform_device *
 at32_add_device_nand(unsigned int id, struct atmel_nand_data *data);
 
diff --git a/arch/avr32/mach-at32ap/include/mach/cpu.h b/arch/avr32/mach-at32ap/include/mach/cpu.h
index 8181293..16a24b1 100644
--- a/arch/avr32/mach-at32ap/include/mach/cpu.h
+++ b/arch/avr32/mach-at32ap/include/mach/cpu.h
@@ -30,9 +30,6 @@
 #define cpu_is_at91sam9261()	(0)
 #define cpu_is_at91sam9263()	(0)
 #define cpu_is_at91sam9rl()	(0)
-#define cpu_is_at91cap9()	(0)
-#define cpu_is_at91cap9_revB()	(0)
-#define cpu_is_at91cap9_revC()	(0)
 #define cpu_is_at91sam9g10()	(0)
 #define cpu_is_at91sam9g20()	(0)
 #define cpu_is_at91sam9g45()	(0)
diff --git a/arch/avr32/oprofile/op_model_avr32.c b/arch/avr32/oprofile/op_model_avr32.c
index a3e9b3c..f74b780 100644
--- a/arch/avr32/oprofile/op_model_avr32.c
+++ b/arch/avr32/oprofile/op_model_avr32.c
@@ -17,7 +17,6 @@
 #include <linux/types.h>
 
 #include <asm/sysreg.h>
-#include <asm/system.h>
 
 #define AVR32_PERFCTR_IRQ_GROUP	0
 #define AVR32_PERFCTR_IRQ_LINE	1
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index abe5a9e..373a690 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -36,6 +36,7 @@
 	select GENERIC_ATOMIC64
 	select GENERIC_IRQ_PROBE
 	select IRQ_PER_CPU if SMP
+	select HAVE_NMI_WATCHDOG if NMI_WATCHDOG
 
 config GENERIC_CSUM
 	def_bool y
@@ -822,7 +823,7 @@
 	bool "Locate cacheline_aligned data to L1 Data Memory"
 	default y if !BF54x
 	default n if BF54x
-	depends on !SMP && !BF531
+	depends on !SMP && !BF531 && !CRC32
 	help
 	  If enabled, cacheline_aligned data is linked
 	  into L1 data memory. (less latency)
diff --git a/arch/blackfin/boot/Makefile b/arch/blackfin/boot/Makefile
index 0a49279..f7d27d5 100644
--- a/arch/blackfin/boot/Makefile
+++ b/arch/blackfin/boot/Makefile
@@ -6,20 +6,17 @@
 # for more details.
 #
 
-MKIMAGE := $(srctree)/scripts/mkuboot.sh
-
 targets := vmImage vmImage.bin vmImage.bz2 vmImage.gz vmImage.lzma vmImage.lzo vmImage.xip
 extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma vmlinux.bin.lzo vmlinux.bin.xip
 
-UIMAGE_OPTS-y :=
-UIMAGE_OPTS-$(CONFIG_RAMKERNEL) += -a $(CONFIG_BOOT_LOAD)
-UIMAGE_OPTS-$(CONFIG_ROMKERNEL) += -a $(CONFIG_ROM_BASE) -x
-
-quiet_cmd_uimage = UIMAGE  $@
-      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(ARCH) -O linux -T kernel \
-                   -C $(2) -n '$(CPU_REV)-$(KERNELRELEASE)' \
-                   -e $(shell $(NM) vmlinux | awk '$$NF == "__start" {print $$1}') \
-                   $(UIMAGE_OPTS-y) -d $< $@
+ifeq ($(CONFIG_RAMKERNEL),y)
+UIMAGE_LOADADDR = $(CONFIG_BOOT_LOAD)
+else # CONFIG_ROMKERNEL must be set
+UIMAGE_LOADADDR = $(CONFIG_ROM_BASE)
+endif
+UIMAGE_ENTRYADDR = $(shell $(NM) vmlinux | awk '$$NF == "__start" {print $$1}')
+UIMAGE_NAME = '$(CPU_REV)-$(KERNELRELEASE)'
+UIMAGE_OPTS-$(CONFIG_ROMKERNEL) += -x
 
 $(obj)/vmlinux.bin: vmlinux FORCE
 	$(call if_changed,objcopy)
diff --git a/arch/blackfin/configs/BF518F-EZBRD_defconfig b/arch/blackfin/configs/BF518F-EZBRD_defconfig
index 0b7039c..3830078 100644
--- a/arch/blackfin/configs/BF518F-EZBRD_defconfig
+++ b/arch/blackfin/configs/BF518F-EZBRD_defconfig
@@ -4,9 +4,7 @@
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
-# CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
 # CONFIG_SIGNALFD is not set
@@ -35,7 +33,6 @@
 CONFIG_BANK_3=0x99B2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
-CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -51,7 +48,6 @@
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_JEDECPROBE=m
@@ -60,20 +56,28 @@
 CONFIG_MTD_COMPLEX_MAPPINGS=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
+CONFIG_NET_BFIN=y
 CONFIG_BFIN_MAC=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
 # CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
-# CONFIG_DEVKMEM is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_BFIN_JTAG_COMM=m
+# CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
 CONFIG_SERIAL_BFIN_UART0=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
@@ -97,16 +101,13 @@
 CONFIG_VFAT_FS=m
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
-CONFIG_SMB_FS=m
 CONFIG_NLS_CODEPAGE_437=m
 CONFIG_NLS_CODEPAGE_936=m
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_UTF8=m
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_MMRS=y
 CONFIG_DEBUG_HWERR=y
diff --git a/arch/blackfin/configs/BF526-EZBRD_defconfig b/arch/blackfin/configs/BF526-EZBRD_defconfig
index 5553205..2f2c6ac 100644
--- a/arch/blackfin/configs/BF526-EZBRD_defconfig
+++ b/arch/blackfin/configs/BF526-EZBRD_defconfig
@@ -4,9 +4,7 @@
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
-# CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
 # CONFIG_SIGNALFD is not set
@@ -40,7 +38,6 @@
 CONFIG_BANK_3=0x99B2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
-CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -56,7 +53,6 @@
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
@@ -74,10 +70,18 @@
 CONFIG_BLK_DEV_SR=m
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
+CONFIG_NET_BFIN=y
 CONFIG_BFIN_MAC=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
 # CONFIG_WLAN is not set
 CONFIG_INPUT_FF_MEMLESS=m
 # CONFIG_INPUT_MOUSEDEV is not set
@@ -85,12 +89,12 @@
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_MISC=y
 # CONFIG_SERIO is not set
-# CONFIG_DEVKMEM is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_BFIN_JTAG_COMM=m
+# CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
 CONFIG_SERIAL_BFIN_UART1=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=m
@@ -123,7 +127,6 @@
 # CONFIG_USB_DEVICE_CLASS is not set
 CONFIG_USB_OTG_BLACKLIST_HUB=y
 CONFIG_USB_MON=y
-CONFIG_USB_MUSB_HDRC=y
 CONFIG_USB_STORAGE=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_BFIN=y
@@ -135,16 +138,13 @@
 CONFIG_JFFS2_FS=m
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
-CONFIG_SMB_FS=m
 CONFIG_NLS_CODEPAGE_437=m
 CONFIG_NLS_CODEPAGE_936=m
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_UTF8=m
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_MMRS=y
 CONFIG_DEBUG_HWERR=y
diff --git a/arch/blackfin/configs/BF527-EZKIT-V2_defconfig b/arch/blackfin/configs/BF527-EZKIT-V2_defconfig
index 498f64a..91535c3 100644
--- a/arch/blackfin/configs/BF527-EZKIT-V2_defconfig
+++ b/arch/blackfin/configs/BF527-EZKIT-V2_defconfig
@@ -4,9 +4,7 @@
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
-# CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
 # CONFIG_SIGNALFD is not set
@@ -39,7 +37,6 @@
 CONFIG_BANK_3=0x99B2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
-CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -61,7 +58,6 @@
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=m
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_JEDECPROBE=m
@@ -77,10 +73,18 @@
 CONFIG_BLK_DEV_SR=m
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
+CONFIG_NET_BFIN=y
 CONFIG_BFIN_MAC=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
 # CONFIG_WLAN is not set
 CONFIG_INPUT_FF_MEMLESS=m
 # CONFIG_INPUT_MOUSEDEV is not set
@@ -93,12 +97,12 @@
 CONFIG_TOUCHSCREEN_AD7879_I2C=y
 CONFIG_INPUT_MISC=y
 # CONFIG_SERIO is not set
-# CONFIG_DEVKMEM is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_BFIN_JTAG_COMM=m
+# CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
 CONFIG_SERIAL_BFIN_UART1=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=m
@@ -148,7 +152,9 @@
 CONFIG_USB_OTG_BLACKLIST_HUB=y
 CONFIG_USB_MON=y
 CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_BLACKFIN=y
 CONFIG_USB_STORAGE=y
+CONFIG_USB_GADGET=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_ADP5520=y
@@ -163,16 +169,13 @@
 CONFIG_JFFS2_FS=m
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
-CONFIG_SMB_FS=m
 CONFIG_NLS_CODEPAGE_437=m
 CONFIG_NLS_CODEPAGE_936=m
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_UTF8=m
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_MMRS=y
 CONFIG_DEBUG_HWERR=y
diff --git a/arch/blackfin/configs/BF527-EZKIT_defconfig b/arch/blackfin/configs/BF527-EZKIT_defconfig
index 72e0317..90b1753 100644
--- a/arch/blackfin/configs/BF527-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF527-EZKIT_defconfig
@@ -4,9 +4,7 @@
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
-# CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
 # CONFIG_SIGNALFD is not set
@@ -38,7 +36,6 @@
 CONFIG_BANK_3=0x99B2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
-CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -60,7 +57,6 @@
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=m
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_JEDECPROBE=m
@@ -76,10 +72,18 @@
 CONFIG_BLK_DEV_SR=m
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
+CONFIG_NET_BFIN=y
 CONFIG_BFIN_MAC=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
 # CONFIG_WLAN is not set
 CONFIG_INPUT_FF_MEMLESS=m
 # CONFIG_INPUT_MOUSEDEV is not set
@@ -87,12 +91,12 @@
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_MISC=y
 # CONFIG_SERIO is not set
-# CONFIG_DEVKMEM is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_BFIN_JTAG_COMM=m
+# CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
 CONFIG_SERIAL_BFIN_UART1=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=m
@@ -142,8 +146,10 @@
 CONFIG_USB_OTG_BLACKLIST_HUB=y
 CONFIG_USB_MON=y
 CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_BLACKFIN=y
 CONFIG_MUSB_PIO_ONLY=y
 CONFIG_USB_STORAGE=y
+CONFIG_USB_GADGET=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_BFIN=y
 CONFIG_EXT2_FS=m
@@ -155,16 +161,13 @@
 CONFIG_JFFS2_FS=m
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
-CONFIG_SMB_FS=m
 CONFIG_NLS_CODEPAGE_437=m
 CONFIG_NLS_CODEPAGE_936=m
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_UTF8=m
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_MMRS=y
 CONFIG_DEBUG_HWERR=y
diff --git a/arch/blackfin/configs/BF533-EZKIT_defconfig b/arch/blackfin/configs/BF533-EZKIT_defconfig
index 2f075e0..127f20d 100644
--- a/arch/blackfin/configs/BF533-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF533-EZKIT_defconfig
@@ -4,9 +4,7 @@
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
-# CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
 # CONFIG_SIGNALFD is not set
@@ -32,7 +30,6 @@
 CONFIG_BANK_3=0xAAC2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
-CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -53,7 +50,6 @@
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=m
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_JEDECPROBE=m
@@ -62,10 +58,16 @@
 CONFIG_MTD_COMPLEX_MAPPINGS=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
 CONFIG_SMC91X=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
 # CONFIG_WLAN is not set
 CONFIG_INPUT=m
 # CONFIG_INPUT_MOUSEDEV is not set
@@ -74,11 +76,11 @@
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
-# CONFIG_DEVKMEM is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_BFIN_JTAG_COMM=m
+# CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_SPI=y
 CONFIG_SPI_BFIN5XX=y
@@ -94,12 +96,9 @@
 CONFIG_JFFS2_FS=m
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
-CONFIG_SMB_FS=m
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_MMRS=y
 CONFIG_DEBUG_HWERR=y
diff --git a/arch/blackfin/configs/BF533-STAMP_defconfig b/arch/blackfin/configs/BF533-STAMP_defconfig
index ab38a82..0df2f92 100644
--- a/arch/blackfin/configs/BF533-STAMP_defconfig
+++ b/arch/blackfin/configs/BF533-STAMP_defconfig
@@ -4,9 +4,7 @@
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
-# CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
 # CONFIG_SIGNALFD is not set
@@ -30,7 +28,6 @@
 CONFIG_BANK_3=0xAAC2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
-CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -62,10 +59,16 @@
 CONFIG_MTD_COMPLEX_MAPPINGS=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
 CONFIG_SMC91X=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
 # CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=m
@@ -74,11 +77,11 @@
 CONFIG_INPUT_MISC=y
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
-# CONFIG_DEVKMEM is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_BFIN_JTAG_COMM=m
+# CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=m
 CONFIG_I2C_CHARDEV=m
@@ -106,12 +109,9 @@
 CONFIG_JFFS2_FS=m
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
-CONFIG_SMB_FS=m
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_MMRS=y
 CONFIG_DEBUG_HWERR=y
diff --git a/arch/blackfin/configs/BF537-STAMP_defconfig b/arch/blackfin/configs/BF537-STAMP_defconfig
index 5c802d6..91d3eda 100644
--- a/arch/blackfin/configs/BF537-STAMP_defconfig
+++ b/arch/blackfin/configs/BF537-STAMP_defconfig
@@ -4,9 +4,7 @@
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
-# CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
 # CONFIG_SIGNALFD is not set
@@ -30,7 +28,6 @@
 CONFIG_BANK_3=0x99B2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
-CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -45,7 +42,6 @@
 CONFIG_CAN=m
 CONFIG_CAN_RAW=m
 CONFIG_CAN_BCM=m
-CONFIG_CAN_DEV=m
 CONFIG_CAN_BFIN=m
 CONFIG_IRDA=m
 CONFIG_IRLAN=m
@@ -58,7 +54,6 @@
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=m
 CONFIG_MTD_BLOCK=y
@@ -69,11 +64,18 @@
 CONFIG_MTD_PHYSMAP=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_NETDEVICES=y
-CONFIG_SMSC_PHY=y
-CONFIG_NET_ETHERNET=y
+CONFIG_NET_BFIN=y
 CONFIG_BFIN_MAC=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
 # CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=m
@@ -82,12 +84,12 @@
 CONFIG_INPUT_MISC=y
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
-# CONFIG_DEVKMEM is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_BFIN_JTAG_COMM=m
+# CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
 CONFIG_SERIAL_BFIN_UART0=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=m
 CONFIG_I2C_CHARDEV=m
@@ -117,12 +119,9 @@
 CONFIG_JFFS2_FS=m
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
-CONFIG_SMB_FS=m
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_MMRS=y
 CONFIG_DEBUG_HWERR=y
diff --git a/arch/blackfin/configs/BF548-EZKIT_defconfig b/arch/blackfin/configs/BF548-EZKIT_defconfig
index 7a1e3bf..e716fdf 100644
--- a/arch/blackfin/configs/BF548-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF548-EZKIT_defconfig
@@ -5,7 +5,6 @@
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
-# CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
 # CONFIG_SIGNALFD is not set
@@ -85,10 +84,16 @@
 # CONFIG_SATA_PMP is not set
 CONFIG_PATA_BF54X=y
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
 CONFIG_SMSC911X=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
 # CONFIG_WLAN is not set
 CONFIG_INPUT_FF_MEMLESS=m
 # CONFIG_INPUT_MOUSEDEV is not set
@@ -161,6 +166,7 @@
 CONFIG_USB_MUSB_HDRC=y
 CONFIG_USB_MUSB_BLACKFIN=y
 CONFIG_USB_STORAGE=y
+CONFIG_USB_GADGET=y
 CONFIG_MMC=y
 CONFIG_MMC_BLOCK=m
 CONFIG_SDH_BFIN=y
@@ -187,7 +193,6 @@
 CONFIG_NLS_CODEPAGE_936=m
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_UTF8=m
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
diff --git a/arch/blackfin/configs/BF561-EZKIT-SMP_defconfig b/arch/blackfin/configs/BF561-EZKIT-SMP_defconfig
index 78adbbf..680730e 100644
--- a/arch/blackfin/configs/BF561-EZKIT-SMP_defconfig
+++ b/arch/blackfin/configs/BF561-EZKIT-SMP_defconfig
@@ -4,9 +4,7 @@
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
-# CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
 # CONFIG_SIGNALFD is not set
@@ -23,17 +21,18 @@
 # CONFIG_IOSCHED_CFQ is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BF561=y
-CONFIG_SMP=y
 CONFIG_IRQ_TIMER0=10
 CONFIG_CLKIN_HZ=30000000
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_NOMMU_INITIAL_TRIM_EXCESS=0
 CONFIG_BFIN_GPTIMERS=m
+CONFIG_BFIN_EXTMEM_WRITETHROUGH=y
+CONFIG_BFIN_L2_DCACHEABLE=y
+CONFIG_BFIN_L2_WRITETHROUGH=y
 CONFIG_C_CDPRIO=y
 CONFIG_BANK_3=0xAAC2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
-CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -54,21 +53,26 @@
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=m
+CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=m
-CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_RAM=y
 CONFIG_MTD_ROM=m
-CONFIG_MTD_PHYSMAP=m
+CONFIG_MTD_PHYSMAP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
 CONFIG_SMC91X=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
 # CONFIG_WLAN is not set
 CONFIG_INPUT=m
 # CONFIG_INPUT_MOUSEDEV is not set
@@ -77,11 +81,11 @@
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
-# CONFIG_DEVKMEM is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_BFIN_JTAG_COMM=m
+# CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_SPI=y
 CONFIG_SPI_BFIN5XX=y
@@ -95,12 +99,9 @@
 CONFIG_JFFS2_FS=m
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
-CONFIG_SMB_FS=m
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_MMRS=y
 CONFIG_DEBUG_HWERR=y
diff --git a/arch/blackfin/configs/BF561-EZKIT_defconfig b/arch/blackfin/configs/BF561-EZKIT_defconfig
index d3cd0f5..680730e 100644
--- a/arch/blackfin/configs/BF561-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF561-EZKIT_defconfig
@@ -4,9 +4,7 @@
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
-# CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_FUTEX is not set
 # CONFIG_SIGNALFD is not set
@@ -35,7 +33,6 @@
 CONFIG_BANK_3=0xAAC2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
-CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -56,7 +53,6 @@
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
@@ -67,10 +63,16 @@
 CONFIG_MTD_PHYSMAP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
 CONFIG_SMC91X=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
 # CONFIG_WLAN is not set
 CONFIG_INPUT=m
 # CONFIG_INPUT_MOUSEDEV is not set
@@ -79,11 +81,11 @@
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
-# CONFIG_DEVKMEM is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_BFIN_JTAG_COMM=m
+# CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_SPI=y
 CONFIG_SPI_BFIN5XX=y
@@ -97,12 +99,9 @@
 CONFIG_JFFS2_FS=m
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
-CONFIG_SMB_FS=m
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_MMRS=y
 CONFIG_DEBUG_HWERR=y
diff --git a/arch/blackfin/include/asm/atomic.h b/arch/blackfin/include/asm/atomic.h
index 54c6e28..c8db653 100644
--- a/arch/blackfin/include/asm/atomic.h
+++ b/arch/blackfin/include/asm/atomic.h
@@ -7,6 +7,8 @@
 #ifndef __ARCH_BLACKFIN_ATOMIC__
 #define __ARCH_BLACKFIN_ATOMIC__
 
+#include <asm/cmpxchg.h>
+
 #ifdef CONFIG_SMP
 
 #include <linux/linkage.h>
diff --git a/arch/blackfin/include/asm/barrier.h b/arch/blackfin/include/asm/barrier.h
new file mode 100644
index 0000000..ebb1895
--- /dev/null
+++ b/arch/blackfin/include/asm/barrier.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *               Tony Kou (tonyko@lineo.ca)
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#ifndef _BLACKFIN_BARRIER_H
+#define _BLACKFIN_BARRIER_H
+
+#include <asm/cache.h>
+
+#define nop()  __asm__ __volatile__ ("nop;\n\t" : : )
+
+/*
+ * Force strict CPU ordering.
+ */
+#ifdef CONFIG_SMP
+
+#ifdef __ARCH_SYNC_CORE_DCACHE
+/* Force Core data cache coherence */
+# define mb()	do { barrier(); smp_check_barrier(); smp_mark_barrier(); } while (0)
+# define rmb()	do { barrier(); smp_check_barrier(); } while (0)
+# define wmb()	do { barrier(); smp_mark_barrier(); } while (0)
+# define read_barrier_depends()	do { barrier(); smp_check_barrier(); } while (0)
+#else
+# define mb()	barrier()
+# define rmb()	barrier()
+# define wmb()	barrier()
+# define read_barrier_depends()	do { } while (0)
+#endif
+
+#else /* !CONFIG_SMP */
+
+#define mb()	barrier()
+#define rmb()	barrier()
+#define wmb()	barrier()
+#define read_barrier_depends()	do { } while (0)
+
+#endif /* !CONFIG_SMP */
+
+#define smp_mb()  mb()
+#define smp_rmb() rmb()
+#define smp_wmb() wmb()
+#define set_mb(var, value) do { var = value; mb(); } while (0)
+#define smp_read_barrier_depends()	read_barrier_depends()
+
+#endif /* _BLACKFIN_BARRIER_H */
diff --git a/arch/blackfin/include/asm/bfin5xx_spi.h b/arch/blackfin/include/asm/bfin5xx_spi.h
index 5392583..fb95c85 100644
--- a/arch/blackfin/include/asm/bfin5xx_spi.h
+++ b/arch/blackfin/include/asm/bfin5xx_spi.h
@@ -77,7 +77,6 @@
 struct bfin5xx_spi_chip {
 	u16 ctl_reg;
 	u8 enable_dma;
-	u8 bits_per_word;
 	u16 cs_chg_udelay; /* Some devices require 16-bit delays */
 	/* Value to send if no TX value is supplied, usually 0x0 or 0xFFFF */
 	u16 idle_tx_val;
diff --git a/arch/blackfin/include/asm/bfin_simple_timer.h b/arch/blackfin/include/asm/bfin_simple_timer.h
index 5248c13..aadfb1a 100644
--- a/arch/blackfin/include/asm/bfin_simple_timer.h
+++ b/arch/blackfin/include/asm/bfin_simple_timer.h
@@ -11,9 +11,11 @@
 
 #define BFIN_SIMPLE_TIMER_IOCTL_MAGIC 't'
 
-#define BFIN_SIMPLE_TIMER_SET_PERIOD _IO (BFIN_SIMPLE_TIMER_IOCTL_MAGIC,  2)
-#define BFIN_SIMPLE_TIMER_START      _IO (BFIN_SIMPLE_TIMER_IOCTL_MAGIC,  6)
-#define BFIN_SIMPLE_TIMER_STOP       _IO (BFIN_SIMPLE_TIMER_IOCTL_MAGIC,  8)
-#define BFIN_SIMPLE_TIMER_READ       _IO (BFIN_SIMPLE_TIMER_IOCTL_MAGIC, 10)
+#define BFIN_SIMPLE_TIMER_SET_PERIOD _IO(BFIN_SIMPLE_TIMER_IOCTL_MAGIC,  2)
+#define BFIN_SIMPLE_TIMER_SET_WIDTH _IO(BFIN_SIMPLE_TIMER_IOCTL_MAGIC,  3)
+#define BFIN_SIMPLE_TIMER_SET_MODE _IO(BFIN_SIMPLE_TIMER_IOCTL_MAGIC,  4)
+#define BFIN_SIMPLE_TIMER_START      _IO(BFIN_SIMPLE_TIMER_IOCTL_MAGIC,  6)
+#define BFIN_SIMPLE_TIMER_STOP       _IO(BFIN_SIMPLE_TIMER_IOCTL_MAGIC,  8)
+#define BFIN_SIMPLE_TIMER_READ       _IO(BFIN_SIMPLE_TIMER_IOCTL_MAGIC, 10)
 
 #endif
diff --git a/arch/blackfin/include/asm/bfin_sport.h b/arch/blackfin/include/asm/bfin_sport.h
index f8568a3..0afcfbd 100644
--- a/arch/blackfin/include/asm/bfin_sport.h
+++ b/arch/blackfin/include/asm/bfin_sport.h
@@ -13,6 +13,7 @@
 #define NORM_MODE	0x0
 #define TDM_MODE	0x1
 #define I2S_MODE	0x2
+#define NDSO_MODE	0x3
 
 /* Data format, normal, a-law or u-law */
 #define NORM_FORMAT	0x0
@@ -56,6 +57,8 @@
 /* Userspace interface */
 #define SPORT_IOC_MAGIC		'P'
 #define SPORT_IOC_CONFIG	_IOWR('P', 0x01, struct sport_config)
+#define SPORT_IOC_GET_SYSTEMCLOCK         _IOR('P', 0x02, unsigned long)
+#define SPORT_IOC_SET_BAUDRATE            _IOW('P', 0x03, unsigned long)
 
 #ifdef __KERNEL__
 
diff --git a/arch/blackfin/include/asm/blackfin.h b/arch/blackfin/include/asm/blackfin.h
index 0928700..7be5368 100644
--- a/arch/blackfin/include/asm/blackfin.h
+++ b/arch/blackfin/include/asm/blackfin.h
@@ -17,22 +17,16 @@
 static inline void SSYNC(void)
 {
 	int _tmp;
-	if (ANOMALY_05000312)
+	if (ANOMALY_05000312 || ANOMALY_05000244)
 		__asm__ __volatile__(
 			"cli %0;"
 			"nop;"
 			"nop;"
+			"nop;"
 			"ssync;"
 			"sti %0;"
 			: "=d" (_tmp)
 		);
-	else if (ANOMALY_05000244)
-		__asm__ __volatile__(
-			"nop;"
-			"nop;"
-			"nop;"
-			"ssync;"
-		);
 	else
 		__asm__ __volatile__("ssync;");
 }
@@ -41,22 +35,16 @@
 static inline void CSYNC(void)
 {
 	int _tmp;
-	if (ANOMALY_05000312)
+	if (ANOMALY_05000312 || ANOMALY_05000244)
 		__asm__ __volatile__(
 			"cli %0;"
 			"nop;"
 			"nop;"
+			"nop;"
 			"csync;"
 			"sti %0;"
 			: "=d" (_tmp)
 		);
-	else if (ANOMALY_05000244)
-		__asm__ __volatile__(
-			"nop;"
-			"nop;"
-			"nop;"
-			"csync;"
-		);
 	else
 		__asm__ __volatile__("csync;");
 }
@@ -73,18 +61,26 @@
 #define ssync(x) SSYNC(x)
 #define csync(x) CSYNC(x)
 
-#if ANOMALY_05000312
-#define SSYNC(scratch) cli scratch; nop; nop; SSYNC; sti scratch;
-#define CSYNC(scratch) cli scratch; nop; nop; CSYNC; sti scratch;
+#if ANOMALY_05000312 || ANOMALY_05000244
+#define SSYNC(scratch)	\
+do {			\
+	cli scratch;	\
+	nop; nop; nop;	\
+	SSYNC;		\
+	sti scratch;	\
+} while (0)
 
-#elif ANOMALY_05000244
-#define SSYNC(scratch) nop; nop; nop; SSYNC;
-#define CSYNC(scratch) nop; nop; nop; CSYNC;
+#define CSYNC(scratch)	\
+do {			\
+	cli scratch;	\
+	nop; nop; nop;	\
+	CSYNC;		\
+	sti scratch;	\
+} while (0)
 
 #else
 #define SSYNC(scratch) SSYNC;
 #define CSYNC(scratch) CSYNC;
-
 #endif /* ANOMALY_05000312 & ANOMALY_05000244 handling */
 
 #endif /* __ASSEMBLY__ */
diff --git a/arch/blackfin/include/asm/cmpxchg.h b/arch/blackfin/include/asm/cmpxchg.h
new file mode 100644
index 0000000..c05868c
--- /dev/null
+++ b/arch/blackfin/include/asm/cmpxchg.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2004-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __ARCH_BLACKFIN_CMPXCHG__
+#define __ARCH_BLACKFIN_CMPXCHG__
+
+#ifdef CONFIG_SMP
+
+#include <linux/linkage.h>
+
+asmlinkage unsigned long __raw_xchg_1_asm(volatile void *ptr, unsigned long value);
+asmlinkage unsigned long __raw_xchg_2_asm(volatile void *ptr, unsigned long value);
+asmlinkage unsigned long __raw_xchg_4_asm(volatile void *ptr, unsigned long value);
+asmlinkage unsigned long __raw_cmpxchg_1_asm(volatile void *ptr,
+					unsigned long new, unsigned long old);
+asmlinkage unsigned long __raw_cmpxchg_2_asm(volatile void *ptr,
+					unsigned long new, unsigned long old);
+asmlinkage unsigned long __raw_cmpxchg_4_asm(volatile void *ptr,
+					unsigned long new, unsigned long old);
+
+static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
+				   int size)
+{
+	unsigned long tmp;
+
+	switch (size) {
+	case 1:
+		tmp = __raw_xchg_1_asm(ptr, x);
+		break;
+	case 2:
+		tmp = __raw_xchg_2_asm(ptr, x);
+		break;
+	case 4:
+		tmp = __raw_xchg_4_asm(ptr, x);
+		break;
+	}
+
+	return tmp;
+}
+
+/*
+ * Atomic compare and exchange.  Compare OLD with MEM, if identical,
+ * store NEW in MEM.  Return the initial value in MEM.  Success is
+ * indicated by comparing RETURN with OLD.
+ */
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+				      unsigned long new, int size)
+{
+	unsigned long tmp;
+
+	switch (size) {
+	case 1:
+		tmp = __raw_cmpxchg_1_asm(ptr, new, old);
+		break;
+	case 2:
+		tmp = __raw_cmpxchg_2_asm(ptr, new, old);
+		break;
+	case 4:
+		tmp = __raw_cmpxchg_4_asm(ptr, new, old);
+		break;
+	}
+
+	return tmp;
+}
+#define cmpxchg(ptr, o, n) \
+	((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \
+		(unsigned long)(n), sizeof(*(ptr))))
+
+#else /* !CONFIG_SMP */
+
+#include <mach/blackfin.h>
+#include <asm/irqflags.h>
+
+struct __xchg_dummy {
+	unsigned long a[100];
+};
+#define __xg(x) ((volatile struct __xchg_dummy *)(x))
+
+static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
+				   int size)
+{
+	unsigned long tmp = 0;
+	unsigned long flags;
+
+	flags = hard_local_irq_save();
+
+	switch (size) {
+	case 1:
+		__asm__ __volatile__
+			("%0 = b%2 (z);\n\t"
+			 "b%2 = %1;\n\t"
+			 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
+		break;
+	case 2:
+		__asm__ __volatile__
+			("%0 = w%2 (z);\n\t"
+			 "w%2 = %1;\n\t"
+			 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
+		break;
+	case 4:
+		__asm__ __volatile__
+			("%0 = %2;\n\t"
+			 "%2 = %1;\n\t"
+			 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
+		break;
+	}
+	hard_local_irq_restore(flags);
+	return tmp;
+}
+
+#include <asm-generic/cmpxchg-local.h>
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)				  	       \
+	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+			(unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#define cmpxchg(ptr, o, n)	cmpxchg_local((ptr), (o), (n))
+#define cmpxchg64(ptr, o, n)	cmpxchg64_local((ptr), (o), (n))
+
+#endif /* !CONFIG_SMP */
+
+#define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
+#define tas(ptr) ((void)xchg((ptr), 1))
+
+#endif /* __ARCH_BLACKFIN_CMPXCHG__ */
diff --git a/arch/blackfin/include/asm/exec.h b/arch/blackfin/include/asm/exec.h
new file mode 100644
index 0000000..54c2e1d
--- /dev/null
+++ b/arch/blackfin/include/asm/exec.h
@@ -0,0 +1 @@
+/* define arch_align_stack() here */
diff --git a/arch/blackfin/include/asm/gpio.h b/arch/blackfin/include/asm/gpio.h
index 5a25856..12d3571 100644
--- a/arch/blackfin/include/asm/gpio.h
+++ b/arch/blackfin/include/asm/gpio.h
@@ -244,16 +244,26 @@
 	return -EINVAL;
 }
 
-static inline int gpio_get_value(unsigned gpio)
+static inline int __gpio_get_value(unsigned gpio)
 {
 	return bfin_gpio_get_value(gpio);
 }
 
-static inline void gpio_set_value(unsigned gpio, int value)
+static inline void __gpio_set_value(unsigned gpio, int value)
 {
 	return bfin_gpio_set_value(gpio, value);
 }
 
+static inline int gpio_get_value(unsigned gpio)
+{
+	return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+	return __gpio_set_value(gpio, value);
+}
+
 static inline int gpio_to_irq(unsigned gpio)
 {
 	if (likely(gpio < MAX_BLACKFIN_GPIOS))
diff --git a/arch/blackfin/include/asm/irq.h b/arch/blackfin/include/asm/irq.h
index 12f4060..89de539 100644
--- a/arch/blackfin/include/asm/irq.h
+++ b/arch/blackfin/include/asm/irq.h
@@ -38,8 +38,4 @@
 
 #include <asm-generic/irq.h>
 
-#ifdef CONFIG_NMI_WATCHDOG
-# define ARCH_HAS_NMI_WATCHDOG
-#endif
-
 #endif				/* _BFIN_IRQ_H_ */
diff --git a/arch/blackfin/include/asm/irq_handler.h b/arch/blackfin/include/asm/irq_handler.h
index ee73f79..4fbf835 100644
--- a/arch/blackfin/include/asm/irq_handler.h
+++ b/arch/blackfin/include/asm/irq_handler.h
@@ -9,6 +9,7 @@
 
 #include <linux/types.h>
 #include <linux/linkage.h>
+#include <mach/irq.h>
 
 /* init functions only */
 extern int __init init_arch_irq(void);
diff --git a/arch/blackfin/include/asm/kgdb.h b/arch/blackfin/include/asm/kgdb.h
index aaf8845..2703dde 100644
--- a/arch/blackfin/include/asm/kgdb.h
+++ b/arch/blackfin/include/asm/kgdb.h
@@ -109,6 +109,7 @@
 # define CACHE_FLUSH_IS_SAFE	1
 #endif
 #define GDB_ADJUSTS_BREAK_OFFSET
+#define GDB_SKIP_HW_WATCH_TEST
 #define HW_INST_WATCHPOINT_NUM	6
 #define HW_WATCHPOINT_NUM	8
 #define TYPE_INST_WATCHPOINT	0
diff --git a/arch/blackfin/include/asm/mmu_context.h b/arch/blackfin/include/asm/mmu_context.h
index 3828c70..15b16d3 100644
--- a/arch/blackfin/include/asm/mmu_context.h
+++ b/arch/blackfin/include/asm/mmu_context.h
@@ -30,8 +30,11 @@
 static inline void free_l1stack(void)
 {
 	nr_l1stack_tasks--;
-	if (nr_l1stack_tasks == 0)
+	if (nr_l1stack_tasks == 0) {
 		l1sram_free(l1_stack_base);
+		l1_stack_base = NULL;
+		l1_stack_len = 0;
+	}
 }
 
 static inline unsigned long
diff --git a/arch/blackfin/include/asm/switch_to.h b/arch/blackfin/include/asm/switch_to.h
new file mode 100644
index 0000000..aaf671b
--- /dev/null
+++ b/arch/blackfin/include/asm/switch_to.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *               Tony Kou (tonyko@lineo.ca)
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#ifndef _BLACKFIN_SWITCH_TO_H
+#define _BLACKFIN_SWITCH_TO_H
+
+#define prepare_to_switch()     do { } while(0)
+
+/*
+ * switch_to(n) should switch tasks to task ptr, first checking that
+ * ptr isn't the current task, in which case it does nothing.
+ */
+
+#include <asm/l1layout.h>
+#include <asm/mem_map.h>
+
+asmlinkage struct task_struct *resume(struct task_struct *prev, struct task_struct *next);
+
+#ifndef CONFIG_SMP
+#define switch_to(prev,next,last) \
+do {    \
+	memcpy (&task_thread_info(prev)->l1_task_info, L1_SCRATCH_TASK_INFO, \
+		sizeof *L1_SCRATCH_TASK_INFO); \
+	memcpy (L1_SCRATCH_TASK_INFO, &task_thread_info(next)->l1_task_info, \
+		sizeof *L1_SCRATCH_TASK_INFO); \
+	(last) = resume (prev, next);   \
+} while (0)
+#else
+#define switch_to(prev, next, last) \
+do {    \
+	(last) = resume(prev, next);   \
+} while (0)
+#endif
+
+#endif /* _BLACKFIN_SWITCH_TO_H */
diff --git a/arch/blackfin/include/asm/system.h b/arch/blackfin/include/asm/system.h
deleted file mode 100644
index 44bd0cc..0000000
--- a/arch/blackfin/include/asm/system.h
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright 2004-2009 Analog Devices Inc.
- *               Tony Kou (tonyko@lineo.ca)
- *
- * Licensed under the GPL-2 or later
- */
-
-#ifndef _BLACKFIN_SYSTEM_H
-#define _BLACKFIN_SYSTEM_H
-
-#include <linux/linkage.h>
-#include <linux/irqflags.h>
-#include <mach/anomaly.h>
-#include <asm/cache.h>
-#include <asm/pda.h>
-#include <asm/irq.h>
-
-/*
- * Force strict CPU ordering.
- */
-#define nop()  __asm__ __volatile__ ("nop;\n\t" : : )
-#define smp_mb()  mb()
-#define smp_rmb() rmb()
-#define smp_wmb() wmb()
-#define set_mb(var, value) do { var = value; mb(); } while (0)
-#define smp_read_barrier_depends()	read_barrier_depends()
-
-#ifdef CONFIG_SMP
-asmlinkage unsigned long __raw_xchg_1_asm(volatile void *ptr, unsigned long value);
-asmlinkage unsigned long __raw_xchg_2_asm(volatile void *ptr, unsigned long value);
-asmlinkage unsigned long __raw_xchg_4_asm(volatile void *ptr, unsigned long value);
-asmlinkage unsigned long __raw_cmpxchg_1_asm(volatile void *ptr,
-					unsigned long new, unsigned long old);
-asmlinkage unsigned long __raw_cmpxchg_2_asm(volatile void *ptr,
-					unsigned long new, unsigned long old);
-asmlinkage unsigned long __raw_cmpxchg_4_asm(volatile void *ptr,
-					unsigned long new, unsigned long old);
-
-#ifdef __ARCH_SYNC_CORE_DCACHE
-/* Force Core data cache coherence */
-# define mb()	do { barrier(); smp_check_barrier(); smp_mark_barrier(); } while (0)
-# define rmb()	do { barrier(); smp_check_barrier(); } while (0)
-# define wmb()	do { barrier(); smp_mark_barrier(); } while (0)
-# define read_barrier_depends()	do { barrier(); smp_check_barrier(); } while (0)
-#else
-# define mb()	barrier()
-# define rmb()	barrier()
-# define wmb()	barrier()
-# define read_barrier_depends()	do { } while (0)
-#endif
-
-static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
-				   int size)
-{
-	unsigned long tmp;
-
-	switch (size) {
-	case 1:
-		tmp = __raw_xchg_1_asm(ptr, x);
-		break;
-	case 2:
-		tmp = __raw_xchg_2_asm(ptr, x);
-		break;
-	case 4:
-		tmp = __raw_xchg_4_asm(ptr, x);
-		break;
-	}
-
-	return tmp;
-}
-
-/*
- * Atomic compare and exchange.  Compare OLD with MEM, if identical,
- * store NEW in MEM.  Return the initial value in MEM.  Success is
- * indicated by comparing RETURN with OLD.
- */
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-				      unsigned long new, int size)
-{
-	unsigned long tmp;
-
-	switch (size) {
-	case 1:
-		tmp = __raw_cmpxchg_1_asm(ptr, new, old);
-		break;
-	case 2:
-		tmp = __raw_cmpxchg_2_asm(ptr, new, old);
-		break;
-	case 4:
-		tmp = __raw_cmpxchg_4_asm(ptr, new, old);
-		break;
-	}
-
-	return tmp;
-}
-#define cmpxchg(ptr, o, n) \
-	((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \
-		(unsigned long)(n), sizeof(*(ptr))))
-
-#else /* !CONFIG_SMP */
-
-#define mb()	barrier()
-#define rmb()	barrier()
-#define wmb()	barrier()
-#define read_barrier_depends()	do { } while (0)
-
-struct __xchg_dummy {
-	unsigned long a[100];
-};
-#define __xg(x) ((volatile struct __xchg_dummy *)(x))
-
-#include <mach/blackfin.h>
-
-static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
-				   int size)
-{
-	unsigned long tmp = 0;
-	unsigned long flags;
-
-	flags = hard_local_irq_save();
-
-	switch (size) {
-	case 1:
-		__asm__ __volatile__
-			("%0 = b%2 (z);\n\t"
-			 "b%2 = %1;\n\t"
-			 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
-		break;
-	case 2:
-		__asm__ __volatile__
-			("%0 = w%2 (z);\n\t"
-			 "w%2 = %1;\n\t"
-			 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
-		break;
-	case 4:
-		__asm__ __volatile__
-			("%0 = %2;\n\t"
-			 "%2 = %1;\n\t"
-			 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
-		break;
-	}
-	hard_local_irq_restore(flags);
-	return tmp;
-}
-
-#include <asm-generic/cmpxchg-local.h>
-
-/*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
- */
-#define cmpxchg_local(ptr, o, n)				  	       \
-	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
-			(unsigned long)(n), sizeof(*(ptr))))
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-
-#include <asm-generic/cmpxchg.h>
-
-#endif /* !CONFIG_SMP */
-
-#define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
-#define tas(ptr) ((void)xchg((ptr), 1))
-
-#define prepare_to_switch()     do { } while(0)
-
-/*
- * switch_to(n) should switch tasks to task ptr, first checking that
- * ptr isn't the current task, in which case it does nothing.
- */
-
-#include <asm/l1layout.h>
-#include <asm/mem_map.h>
-
-asmlinkage struct task_struct *resume(struct task_struct *prev, struct task_struct *next);
-
-#ifndef CONFIG_SMP
-#define switch_to(prev,next,last) \
-do {    \
-	memcpy (&task_thread_info(prev)->l1_task_info, L1_SCRATCH_TASK_INFO, \
-		sizeof *L1_SCRATCH_TASK_INFO); \
-	memcpy (L1_SCRATCH_TASK_INFO, &task_thread_info(next)->l1_task_info, \
-		sizeof *L1_SCRATCH_TASK_INFO); \
-	(last) = resume (prev, next);   \
-} while (0)
-#else
-#define switch_to(prev, next, last) \
-do {    \
-	(last) = resume(prev, next);   \
-} while (0)
-#endif
-
-#endif	/* _BLACKFIN_SYSTEM_H */
diff --git a/arch/blackfin/include/asm/thread_info.h b/arch/blackfin/include/asm/thread_info.h
index 53ad100..02560fd8 100644
--- a/arch/blackfin/include/asm/thread_info.h
+++ b/arch/blackfin/include/asm/thread_info.h
@@ -100,6 +100,7 @@
 					   TIF_NEED_RESCHED */
 #define TIF_MEMDIE		4	/* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK	5	/* restore signal mask in do_signal() */
+#define TIF_FREEZE		6	/* is freezing for suspend */
 #define TIF_IRQ_SYNC		7	/* sync pipeline stage */
 #define TIF_NOTIFY_RESUME	8	/* callback before returning to user */
 #define TIF_SINGLESTEP		9
@@ -110,6 +111,7 @@
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
+#define _TIF_FREEZE		(1<<TIF_FREEZE)
 #define _TIF_IRQ_SYNC		(1<<TIF_IRQ_SYNC)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
diff --git a/arch/blackfin/include/asm/unistd.h b/arch/blackfin/include/asm/unistd.h
index 0ccba60..75ec9df 100644
--- a/arch/blackfin/include/asm/unistd.h
+++ b/arch/blackfin/include/asm/unistd.h
@@ -399,8 +399,10 @@
 #define __NR_syncfs		378
 #define __NR_setns		379
 #define __NR_sendmmsg		380
+#define __NR_process_vm_readv	381
+#define __NR_process_vm_writev	382
 
-#define __NR_syscall		381
+#define __NR_syscall		383
 #define NR_syscalls		__NR_syscall
 
 /* Old optional stuff no one actually uses */
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
index 1f88edd..9a0d6d7 100644
--- a/arch/blackfin/kernel/Makefile
+++ b/arch/blackfin/kernel/Makefile
@@ -7,7 +7,7 @@
 obj-y := \
 	entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \
 	sys_bfin.o traps.o irqchip.o dma-mapping.o flat.o \
-	fixed_code.o reboot.o bfin_gpio.o bfin_dma_5xx.o \
+	fixed_code.o reboot.o bfin_gpio.o bfin_dma.o \
 	exception.o dumpstack.o
 
 ifeq ($(CONFIG_GENERIC_CLOCKEVENTS),y)
diff --git a/arch/blackfin/kernel/asm-offsets.c b/arch/blackfin/kernel/asm-offsets.c
index 17e3546..37fcae9 100644
--- a/arch/blackfin/kernel/asm-offsets.c
+++ b/arch/blackfin/kernel/asm-offsets.c
@@ -14,6 +14,7 @@
 #include <linux/irq.h>
 #include <linux/thread_info.h>
 #include <linux/kbuild.h>
+#include <asm/pda.h>
 
 int main(void)
 {
diff --git a/arch/blackfin/kernel/bfin_dma.c b/arch/blackfin/kernel/bfin_dma.c
new file mode 100644
index 0000000..40c2ed6
--- /dev/null
+++ b/arch/blackfin/kernel/bfin_dma.c
@@ -0,0 +1,542 @@
+/*
+ * bfin_dma.c - Blackfin DMA implementation
+ *
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/spinlock.h>
+
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+#include <asm/early_printk.h>
+
+/*
+ * To make sure we work around 05000119 - we always check DMA_DONE bit,
+ * never the DMA_RUN bit
+ */
+
+struct dma_channel dma_ch[MAX_DMA_CHANNELS];
+EXPORT_SYMBOL(dma_ch);
+
+static int __init blackfin_dma_init(void)
+{
+	int i;
+
+	printk(KERN_INFO "Blackfin DMA Controller\n");
+
+
+#if ANOMALY_05000480
+	bfin_write_DMAC_TC_PER(0x0111);
+#endif
+
+	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+		atomic_set(&dma_ch[i].chan_status, 0);
+		dma_ch[i].regs = dma_io_base_addr[i];
+	}
+	/* Mark MEMDMA Channel 0 as requested since we're using it internally */
+	request_dma(CH_MEM_STREAM0_DEST, "Blackfin dma_memcpy");
+	request_dma(CH_MEM_STREAM0_SRC, "Blackfin dma_memcpy");
+
+#if defined(CONFIG_DEB_DMA_URGENT)
+	bfin_write_EBIU_DDRQUE(bfin_read_EBIU_DDRQUE()
+			 | DEB1_URGENT | DEB2_URGENT | DEB3_URGENT);
+#endif
+
+	return 0;
+}
+arch_initcall(blackfin_dma_init);
+
+#ifdef CONFIG_PROC_FS
+static int proc_dma_show(struct seq_file *m, void *v)
+{
+	int i;
+
+	for (i = 0; i < MAX_DMA_CHANNELS; ++i)
+		if (dma_channel_active(i))
+			seq_printf(m, "%2d: %s\n", i, dma_ch[i].device_id);
+
+	return 0;
+}
+
+static int proc_dma_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, proc_dma_show, NULL);
+}
+
+static const struct file_operations proc_dma_operations = {
+	.open		= proc_dma_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int __init proc_dma_init(void)
+{
+	return proc_create("dma", 0, NULL, &proc_dma_operations) != NULL;
+}
+late_initcall(proc_dma_init);
+#endif
+
+static void set_dma_peripheral_map(unsigned int channel, const char *device_id)
+{
+#ifdef CONFIG_BF54x
+	unsigned int per_map;
+
+	switch (channel) {
+		case CH_UART2_RX: per_map = 0xC << 12; break;
+		case CH_UART2_TX: per_map = 0xD << 12; break;
+		case CH_UART3_RX: per_map = 0xE << 12; break;
+		case CH_UART3_TX: per_map = 0xF << 12; break;
+		default:          return;
+	}
+
+	if (strncmp(device_id, "BFIN_UART", 9) == 0)
+		dma_ch[channel].regs->peripheral_map = per_map;
+#endif
+}
+
+/**
+ *	request_dma - request a DMA channel
+ *
+ * Request the specific DMA channel from the system if it's available.
+ */
+int request_dma(unsigned int channel, const char *device_id)
+{
+	pr_debug("request_dma() : BEGIN\n");
+
+	if (device_id == NULL)
+		printk(KERN_WARNING "request_dma(%u): no device_id given\n", channel);
+
+#if defined(CONFIG_BF561) && ANOMALY_05000182
+	if (channel >= CH_IMEM_STREAM0_DEST && channel <= CH_IMEM_STREAM1_DEST) {
+		if (get_cclk() > 500000000) {
+			printk(KERN_WARNING
+			       "Request IMDMA failed due to ANOMALY 05000182\n");
+			return -EFAULT;
+		}
+	}
+#endif
+
+	if (atomic_cmpxchg(&dma_ch[channel].chan_status, 0, 1)) {
+		pr_debug("DMA CHANNEL IN USE\n");
+		return -EBUSY;
+	}
+
+	set_dma_peripheral_map(channel, device_id);
+	dma_ch[channel].device_id = device_id;
+	dma_ch[channel].irq = 0;
+
+	/* This is to be enabled by putting a restriction -
+	 * you have to request DMA, before doing any operations on
+	 * descriptor/channel
+	 */
+	pr_debug("request_dma() : END\n");
+	return 0;
+}
+EXPORT_SYMBOL(request_dma);
+
+int set_dma_callback(unsigned int channel, irq_handler_t callback, void *data)
+{
+	int ret;
+	unsigned int irq;
+
+	BUG_ON(channel >= MAX_DMA_CHANNELS || !callback ||
+			!atomic_read(&dma_ch[channel].chan_status));
+
+	irq = channel2irq(channel);
+	ret = request_irq(irq, callback, 0, dma_ch[channel].device_id, data);
+	if (ret)
+		return ret;
+
+	dma_ch[channel].irq = irq;
+	dma_ch[channel].data = data;
+
+	return 0;
+}
+EXPORT_SYMBOL(set_dma_callback);
+
+/**
+ *	clear_dma_buffer - clear DMA fifos for specified channel
+ *
+ * Set the Buffer Clear bit in the Configuration register of specific DMA
+ * channel. This will stop the descriptor based DMA operation.
+ */
+static void clear_dma_buffer(unsigned int channel)
+{
+	dma_ch[channel].regs->cfg |= RESTART;
+	SSYNC();
+	dma_ch[channel].regs->cfg &= ~RESTART;
+}
+
+void free_dma(unsigned int channel)
+{
+	pr_debug("freedma() : BEGIN\n");
+	BUG_ON(channel >= MAX_DMA_CHANNELS ||
+			!atomic_read(&dma_ch[channel].chan_status));
+
+	/* Halt the DMA */
+	disable_dma(channel);
+	clear_dma_buffer(channel);
+
+	if (dma_ch[channel].irq)
+		free_irq(dma_ch[channel].irq, dma_ch[channel].data);
+
+	/* Clear the DMA Variable in the Channel */
+	atomic_set(&dma_ch[channel].chan_status, 0);
+
+	pr_debug("freedma() : END\n");
+}
+EXPORT_SYMBOL(free_dma);
+
+#ifdef CONFIG_PM
+# ifndef MAX_DMA_SUSPEND_CHANNELS
+#  define MAX_DMA_SUSPEND_CHANNELS MAX_DMA_CHANNELS
+# endif
+int blackfin_dma_suspend(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_DMA_CHANNELS; ++i) {
+		if (dma_ch[i].regs->cfg & DMAEN) {
+			printk(KERN_ERR "DMA Channel %d failed to suspend\n", i);
+			return -EBUSY;
+		}
+
+		if (i < MAX_DMA_SUSPEND_CHANNELS)
+			dma_ch[i].saved_peripheral_map = dma_ch[i].regs->peripheral_map;
+	}
+
+#if ANOMALY_05000480
+	bfin_write_DMAC_TC_PER(0x0);
+#endif
+	return 0;
+}
+
+void blackfin_dma_resume(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_DMA_CHANNELS; ++i) {
+		dma_ch[i].regs->cfg = 0;
+
+		if (i < MAX_DMA_SUSPEND_CHANNELS)
+			dma_ch[i].regs->peripheral_map = dma_ch[i].saved_peripheral_map;
+	}
+#if ANOMALY_05000480
+	bfin_write_DMAC_TC_PER(0x0111);
+#endif
+}
+#endif
+
+/**
+ *	blackfin_dma_early_init - minimal DMA init
+ *
+ * Setup a few DMA registers so we can safely do DMA transfers early on in
+ * the kernel booting process.  Really this just means using dma_memcpy().
+ */
+void __init blackfin_dma_early_init(void)
+{
+	early_shadow_stamp();
+	bfin_write_MDMA_S0_CONFIG(0);
+	bfin_write_MDMA_S1_CONFIG(0);
+}
+
+void __init early_dma_memcpy(void *pdst, const void *psrc, size_t size)
+{
+	unsigned long dst = (unsigned long)pdst;
+	unsigned long src = (unsigned long)psrc;
+	struct dma_register *dst_ch, *src_ch;
+
+	early_shadow_stamp();
+
+	/* We assume that everything is 4 byte aligned, so include
+	 * a basic sanity check
+	 */
+	BUG_ON(dst % 4);
+	BUG_ON(src % 4);
+	BUG_ON(size % 4);
+
+	src_ch = 0;
+	/* Find an avalible memDMA channel */
+	while (1) {
+		if (src_ch == (struct dma_register *)MDMA_S0_NEXT_DESC_PTR) {
+			dst_ch = (struct dma_register *)MDMA_D1_NEXT_DESC_PTR;
+			src_ch = (struct dma_register *)MDMA_S1_NEXT_DESC_PTR;
+		} else {
+			dst_ch = (struct dma_register *)MDMA_D0_NEXT_DESC_PTR;
+			src_ch = (struct dma_register *)MDMA_S0_NEXT_DESC_PTR;
+		}
+
+		if (!bfin_read16(&src_ch->cfg))
+			break;
+		else if (bfin_read16(&dst_ch->irq_status) & DMA_DONE) {
+			bfin_write16(&src_ch->cfg, 0);
+			break;
+		}
+	}
+
+	/* Force a sync in case a previous config reset on this channel
+	 * occurred.  This is needed so subsequent writes to DMA registers
+	 * are not spuriously lost/corrupted.
+	 */
+	__builtin_bfin_ssync();
+
+	/* Destination */
+	bfin_write32(&dst_ch->start_addr, dst);
+	bfin_write16(&dst_ch->x_count, size >> 2);
+	bfin_write16(&dst_ch->x_modify, 1 << 2);
+	bfin_write16(&dst_ch->irq_status, DMA_DONE | DMA_ERR);
+
+	/* Source */
+	bfin_write32(&src_ch->start_addr, src);
+	bfin_write16(&src_ch->x_count, size >> 2);
+	bfin_write16(&src_ch->x_modify, 1 << 2);
+	bfin_write16(&src_ch->irq_status, DMA_DONE | DMA_ERR);
+
+	/* Enable */
+	bfin_write16(&src_ch->cfg, DMAEN | WDSIZE_32);
+	bfin_write16(&dst_ch->cfg, WNR | DI_EN | DMAEN | WDSIZE_32);
+
+	/* Since we are atomic now, don't use the workaround ssync */
+	__builtin_bfin_ssync();
+}
+
+void __init early_dma_memcpy_done(void)
+{
+	early_shadow_stamp();
+
+	while ((bfin_read_MDMA_S0_CONFIG() && !(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)) ||
+	       (bfin_read_MDMA_S1_CONFIG() && !(bfin_read_MDMA_D1_IRQ_STATUS() & DMA_DONE)))
+		continue;
+
+	bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+	bfin_write_MDMA_D1_IRQ_STATUS(DMA_DONE | DMA_ERR);
+	/*
+	 * Now that DMA is done, we would normally flush cache, but
+	 * i/d cache isn't running this early, so we don't bother,
+	 * and just clear out the DMA channel for next time
+	 */
+	bfin_write_MDMA_S0_CONFIG(0);
+	bfin_write_MDMA_S1_CONFIG(0);
+	bfin_write_MDMA_D0_CONFIG(0);
+	bfin_write_MDMA_D1_CONFIG(0);
+
+	__builtin_bfin_ssync();
+}
+
+/**
+ *	__dma_memcpy - program the MDMA registers
+ *
+ * Actually program MDMA0 and wait for the transfer to finish.  Disable IRQs
+ * while programming registers so that everything is fully configured.  Wait
+ * for DMA to finish with IRQs enabled.  If interrupted, the initial DMA_DONE
+ * check will make sure we don't clobber any existing transfer.
+ */
+static void __dma_memcpy(u32 daddr, s16 dmod, u32 saddr, s16 smod, size_t cnt, u32 conf)
+{
+	static DEFINE_SPINLOCK(mdma_lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdma_lock, flags);
+
+	/* Force a sync in case a previous config reset on this channel
+	 * occurred.  This is needed so subsequent writes to DMA registers
+	 * are not spuriously lost/corrupted.  Do it under irq lock and
+	 * without the anomaly version (because we are atomic already).
+	 */
+	__builtin_bfin_ssync();
+
+	if (bfin_read_MDMA_S0_CONFIG())
+		while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE))
+			continue;
+
+	if (conf & DMA2D) {
+		/* For larger bit sizes, we've already divided down cnt so it
+		 * is no longer a multiple of 64k.  So we have to break down
+		 * the limit here so it is a multiple of the incoming size.
+		 * There is no limitation here in terms of total size other
+		 * than the hardware though as the bits lost in the shift are
+		 * made up by MODIFY (== we can hit the whole address space).
+		 * X: (2^(16 - 0)) * 1 == (2^(16 - 1)) * 2 == (2^(16 - 2)) * 4
+		 */
+		u32 shift = abs(dmod) >> 1;
+		size_t ycnt = cnt >> (16 - shift);
+		cnt = 1 << (16 - shift);
+		bfin_write_MDMA_D0_Y_COUNT(ycnt);
+		bfin_write_MDMA_S0_Y_COUNT(ycnt);
+		bfin_write_MDMA_D0_Y_MODIFY(dmod);
+		bfin_write_MDMA_S0_Y_MODIFY(smod);
+	}
+
+	bfin_write_MDMA_D0_START_ADDR(daddr);
+	bfin_write_MDMA_D0_X_COUNT(cnt);
+	bfin_write_MDMA_D0_X_MODIFY(dmod);
+	bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+	bfin_write_MDMA_S0_START_ADDR(saddr);
+	bfin_write_MDMA_S0_X_COUNT(cnt);
+	bfin_write_MDMA_S0_X_MODIFY(smod);
+	bfin_write_MDMA_S0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+	bfin_write_MDMA_S0_CONFIG(DMAEN | conf);
+	bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | conf);
+
+	spin_unlock_irqrestore(&mdma_lock, flags);
+
+	SSYNC();
+
+	while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE))
+		if (bfin_read_MDMA_S0_CONFIG())
+			continue;
+		else
+			return;
+
+	bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+	bfin_write_MDMA_S0_CONFIG(0);
+	bfin_write_MDMA_D0_CONFIG(0);
+}
+
+/**
+ *	_dma_memcpy - translate C memcpy settings into MDMA settings
+ *
+ * Handle all the high level steps before we touch the MDMA registers.  So
+ * handle direction, tweaking of sizes, and formatting of addresses.
+ */
+static void *_dma_memcpy(void *pdst, const void *psrc, size_t size)
+{
+	u32 conf, shift;
+	s16 mod;
+	unsigned long dst = (unsigned long)pdst;
+	unsigned long src = (unsigned long)psrc;
+
+	if (size == 0)
+		return NULL;
+
+	if (dst % 4 == 0 && src % 4 == 0 && size % 4 == 0) {
+		conf = WDSIZE_32;
+		shift = 2;
+	} else if (dst % 2 == 0 && src % 2 == 0 && size % 2 == 0) {
+		conf = WDSIZE_16;
+		shift = 1;
+	} else {
+		conf = WDSIZE_8;
+		shift = 0;
+	}
+
+	/* If the two memory regions have a chance of overlapping, make
+	 * sure the memcpy still works as expected.  Do this by having the
+	 * copy run backwards instead.
+	 */
+	mod = 1 << shift;
+	if (src < dst) {
+		mod *= -1;
+		dst += size + mod;
+		src += size + mod;
+	}
+	size >>= shift;
+
+	if (size > 0x10000)
+		conf |= DMA2D;
+
+	__dma_memcpy(dst, mod, src, mod, size, conf);
+
+	return pdst;
+}
+
+/**
+ *	dma_memcpy - DMA memcpy under mutex lock
+ *
+ * Do not check arguments before starting the DMA memcpy.  Break the transfer
+ * up into two pieces.  The first transfer is in multiples of 64k and the
+ * second transfer is the piece smaller than 64k.
+ */
+void *dma_memcpy(void *pdst, const void *psrc, size_t size)
+{
+	unsigned long dst = (unsigned long)pdst;
+	unsigned long src = (unsigned long)psrc;
+
+	if (bfin_addr_dcacheable(src))
+		blackfin_dcache_flush_range(src, src + size);
+
+	if (bfin_addr_dcacheable(dst))
+		blackfin_dcache_invalidate_range(dst, dst + size);
+
+	return dma_memcpy_nocache(pdst, psrc, size);
+}
+EXPORT_SYMBOL(dma_memcpy);
+
+/**
+ *	dma_memcpy_nocache - DMA memcpy under mutex lock
+ *	- No cache flush/invalidate
+ *
+ * Do not check arguments before starting the DMA memcpy.  Break the transfer
+ * up into two pieces.  The first transfer is in multiples of 64k and the
+ * second transfer is the piece smaller than 64k.
+ */
+void *dma_memcpy_nocache(void *pdst, const void *psrc, size_t size)
+{
+	size_t bulk, rest;
+
+	bulk = size & ~0xffff;
+	rest = size - bulk;
+	if (bulk)
+		_dma_memcpy(pdst, psrc, bulk);
+	_dma_memcpy(pdst + bulk, psrc + bulk, rest);
+	return pdst;
+}
+EXPORT_SYMBOL(dma_memcpy_nocache);
+
+/**
+ *	safe_dma_memcpy - DMA memcpy w/argument checking
+ *
+ * Verify arguments are safe before heading to dma_memcpy().
+ */
+void *safe_dma_memcpy(void *dst, const void *src, size_t size)
+{
+	if (!access_ok(VERIFY_WRITE, dst, size))
+		return NULL;
+	if (!access_ok(VERIFY_READ, src, size))
+		return NULL;
+	return dma_memcpy(dst, src, size);
+}
+EXPORT_SYMBOL(safe_dma_memcpy);
+
+static void _dma_out(unsigned long addr, unsigned long buf, unsigned short len,
+                     u16 size, u16 dma_size)
+{
+	blackfin_dcache_flush_range(buf, buf + len * size);
+	__dma_memcpy(addr, 0, buf, size, len, dma_size);
+}
+
+static void _dma_in(unsigned long addr, unsigned long buf, unsigned short len,
+                    u16 size, u16 dma_size)
+{
+	blackfin_dcache_invalidate_range(buf, buf + len * size);
+	__dma_memcpy(buf, size, addr, 0, len, dma_size);
+}
+
+#define MAKE_DMA_IO(io, bwl, isize, dmasize, cnst) \
+void dma_##io##s##bwl(unsigned long addr, cnst void *buf, unsigned short len) \
+{ \
+	_dma_##io(addr, (unsigned long)buf, len, isize, WDSIZE_##dmasize); \
+} \
+EXPORT_SYMBOL(dma_##io##s##bwl)
+MAKE_DMA_IO(out, b, 1,  8, const);
+MAKE_DMA_IO(in,  b, 1,  8, );
+MAKE_DMA_IO(out, w, 2, 16, const);
+MAKE_DMA_IO(in,  w, 2, 16, );
+MAKE_DMA_IO(out, l, 4, 32, const);
+MAKE_DMA_IO(in,  l, 4, 32, );
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
deleted file mode 100644
index 71dbaa4..0000000
--- a/arch/blackfin/kernel/bfin_dma_5xx.c
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * bfin_dma_5xx.c - Blackfin DMA implementation
- *
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/param.h>
-#include <linux/proc_fs.h>
-#include <linux/sched.h>
-#include <linux/seq_file.h>
-#include <linux/spinlock.h>
-
-#include <asm/blackfin.h>
-#include <asm/cacheflush.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-#include <asm/early_printk.h>
-
-/*
- * To make sure we work around 05000119 - we always check DMA_DONE bit,
- * never the DMA_RUN bit
- */
-
-struct dma_channel dma_ch[MAX_DMA_CHANNELS];
-EXPORT_SYMBOL(dma_ch);
-
-static int __init blackfin_dma_init(void)
-{
-	int i;
-
-	printk(KERN_INFO "Blackfin DMA Controller\n");
-
-
-#if ANOMALY_05000480
-	bfin_write_DMAC_TC_PER(0x0111);
-#endif
-
-	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
-		atomic_set(&dma_ch[i].chan_status, 0);
-		dma_ch[i].regs = dma_io_base_addr[i];
-	}
-	/* Mark MEMDMA Channel 0 as requested since we're using it internally */
-	request_dma(CH_MEM_STREAM0_DEST, "Blackfin dma_memcpy");
-	request_dma(CH_MEM_STREAM0_SRC, "Blackfin dma_memcpy");
-
-#if defined(CONFIG_DEB_DMA_URGENT)
-	bfin_write_EBIU_DDRQUE(bfin_read_EBIU_DDRQUE()
-			 | DEB1_URGENT | DEB2_URGENT | DEB3_URGENT);
-#endif
-
-	return 0;
-}
-arch_initcall(blackfin_dma_init);
-
-#ifdef CONFIG_PROC_FS
-static int proc_dma_show(struct seq_file *m, void *v)
-{
-	int i;
-
-	for (i = 0; i < MAX_DMA_CHANNELS; ++i)
-		if (dma_channel_active(i))
-			seq_printf(m, "%2d: %s\n", i, dma_ch[i].device_id);
-
-	return 0;
-}
-
-static int proc_dma_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, proc_dma_show, NULL);
-}
-
-static const struct file_operations proc_dma_operations = {
-	.open		= proc_dma_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int __init proc_dma_init(void)
-{
-	return proc_create("dma", 0, NULL, &proc_dma_operations) != NULL;
-}
-late_initcall(proc_dma_init);
-#endif
-
-static void set_dma_peripheral_map(unsigned int channel, const char *device_id)
-{
-#ifdef CONFIG_BF54x
-	unsigned int per_map;
-
-	switch (channel) {
-		case CH_UART2_RX: per_map = 0xC << 12; break;
-		case CH_UART2_TX: per_map = 0xD << 12; break;
-		case CH_UART3_RX: per_map = 0xE << 12; break;
-		case CH_UART3_TX: per_map = 0xF << 12; break;
-		default:          return;
-	}
-
-	if (strncmp(device_id, "BFIN_UART", 9) == 0)
-		dma_ch[channel].regs->peripheral_map = per_map;
-#endif
-}
-
-/**
- *	request_dma - request a DMA channel
- *
- * Request the specific DMA channel from the system if it's available.
- */
-int request_dma(unsigned int channel, const char *device_id)
-{
-	pr_debug("request_dma() : BEGIN\n");
-
-	if (device_id == NULL)
-		printk(KERN_WARNING "request_dma(%u): no device_id given\n", channel);
-
-#if defined(CONFIG_BF561) && ANOMALY_05000182
-	if (channel >= CH_IMEM_STREAM0_DEST && channel <= CH_IMEM_STREAM1_DEST) {
-		if (get_cclk() > 500000000) {
-			printk(KERN_WARNING
-			       "Request IMDMA failed due to ANOMALY 05000182\n");
-			return -EFAULT;
-		}
-	}
-#endif
-
-	if (atomic_cmpxchg(&dma_ch[channel].chan_status, 0, 1)) {
-		pr_debug("DMA CHANNEL IN USE\n");
-		return -EBUSY;
-	}
-
-	set_dma_peripheral_map(channel, device_id);
-	dma_ch[channel].device_id = device_id;
-	dma_ch[channel].irq = 0;
-
-	/* This is to be enabled by putting a restriction -
-	 * you have to request DMA, before doing any operations on
-	 * descriptor/channel
-	 */
-	pr_debug("request_dma() : END\n");
-	return 0;
-}
-EXPORT_SYMBOL(request_dma);
-
-int set_dma_callback(unsigned int channel, irq_handler_t callback, void *data)
-{
-	int ret;
-	unsigned int irq;
-
-	BUG_ON(channel >= MAX_DMA_CHANNELS || !callback ||
-			!atomic_read(&dma_ch[channel].chan_status));
-
-	irq = channel2irq(channel);
-	ret = request_irq(irq, callback, 0, dma_ch[channel].device_id, data);
-	if (ret)
-		return ret;
-
-	dma_ch[channel].irq = irq;
-	dma_ch[channel].data = data;
-
-	return 0;
-}
-EXPORT_SYMBOL(set_dma_callback);
-
-/**
- *	clear_dma_buffer - clear DMA fifos for specified channel
- *
- * Set the Buffer Clear bit in the Configuration register of specific DMA
- * channel. This will stop the descriptor based DMA operation.
- */
-static void clear_dma_buffer(unsigned int channel)
-{
-	dma_ch[channel].regs->cfg |= RESTART;
-	SSYNC();
-	dma_ch[channel].regs->cfg &= ~RESTART;
-}
-
-void free_dma(unsigned int channel)
-{
-	pr_debug("freedma() : BEGIN\n");
-	BUG_ON(channel >= MAX_DMA_CHANNELS ||
-			!atomic_read(&dma_ch[channel].chan_status));
-
-	/* Halt the DMA */
-	disable_dma(channel);
-	clear_dma_buffer(channel);
-
-	if (dma_ch[channel].irq)
-		free_irq(dma_ch[channel].irq, dma_ch[channel].data);
-
-	/* Clear the DMA Variable in the Channel */
-	atomic_set(&dma_ch[channel].chan_status, 0);
-
-	pr_debug("freedma() : END\n");
-}
-EXPORT_SYMBOL(free_dma);
-
-#ifdef CONFIG_PM
-# ifndef MAX_DMA_SUSPEND_CHANNELS
-#  define MAX_DMA_SUSPEND_CHANNELS MAX_DMA_CHANNELS
-# endif
-int blackfin_dma_suspend(void)
-{
-	int i;
-
-	for (i = 0; i < MAX_DMA_CHANNELS; ++i) {
-		if (dma_ch[i].regs->cfg & DMAEN) {
-			printk(KERN_ERR "DMA Channel %d failed to suspend\n", i);
-			return -EBUSY;
-		}
-
-		if (i < MAX_DMA_SUSPEND_CHANNELS)
-			dma_ch[i].saved_peripheral_map = dma_ch[i].regs->peripheral_map;
-	}
-
-	return 0;
-}
-
-void blackfin_dma_resume(void)
-{
-	int i;
-
-	for (i = 0; i < MAX_DMA_CHANNELS; ++i) {
-		dma_ch[i].regs->cfg = 0;
-
-		if (i < MAX_DMA_SUSPEND_CHANNELS)
-			dma_ch[i].regs->peripheral_map = dma_ch[i].saved_peripheral_map;
-	}
-}
-#endif
-
-/**
- *	blackfin_dma_early_init - minimal DMA init
- *
- * Setup a few DMA registers so we can safely do DMA transfers early on in
- * the kernel booting process.  Really this just means using dma_memcpy().
- */
-void __init blackfin_dma_early_init(void)
-{
-	early_shadow_stamp();
-	bfin_write_MDMA_S0_CONFIG(0);
-	bfin_write_MDMA_S1_CONFIG(0);
-}
-
-void __init early_dma_memcpy(void *pdst, const void *psrc, size_t size)
-{
-	unsigned long dst = (unsigned long)pdst;
-	unsigned long src = (unsigned long)psrc;
-	struct dma_register *dst_ch, *src_ch;
-
-	early_shadow_stamp();
-
-	/* We assume that everything is 4 byte aligned, so include
-	 * a basic sanity check
-	 */
-	BUG_ON(dst % 4);
-	BUG_ON(src % 4);
-	BUG_ON(size % 4);
-
-	src_ch = 0;
-	/* Find an avalible memDMA channel */
-	while (1) {
-		if (src_ch == (struct dma_register *)MDMA_S0_NEXT_DESC_PTR) {
-			dst_ch = (struct dma_register *)MDMA_D1_NEXT_DESC_PTR;
-			src_ch = (struct dma_register *)MDMA_S1_NEXT_DESC_PTR;
-		} else {
-			dst_ch = (struct dma_register *)MDMA_D0_NEXT_DESC_PTR;
-			src_ch = (struct dma_register *)MDMA_S0_NEXT_DESC_PTR;
-		}
-
-		if (!bfin_read16(&src_ch->cfg))
-			break;
-		else if (bfin_read16(&dst_ch->irq_status) & DMA_DONE) {
-			bfin_write16(&src_ch->cfg, 0);
-			break;
-		}
-	}
-
-	/* Force a sync in case a previous config reset on this channel
-	 * occurred.  This is needed so subsequent writes to DMA registers
-	 * are not spuriously lost/corrupted.
-	 */
-	__builtin_bfin_ssync();
-
-	/* Destination */
-	bfin_write32(&dst_ch->start_addr, dst);
-	bfin_write16(&dst_ch->x_count, size >> 2);
-	bfin_write16(&dst_ch->x_modify, 1 << 2);
-	bfin_write16(&dst_ch->irq_status, DMA_DONE | DMA_ERR);
-
-	/* Source */
-	bfin_write32(&src_ch->start_addr, src);
-	bfin_write16(&src_ch->x_count, size >> 2);
-	bfin_write16(&src_ch->x_modify, 1 << 2);
-	bfin_write16(&src_ch->irq_status, DMA_DONE | DMA_ERR);
-
-	/* Enable */
-	bfin_write16(&src_ch->cfg, DMAEN | WDSIZE_32);
-	bfin_write16(&dst_ch->cfg, WNR | DI_EN | DMAEN | WDSIZE_32);
-
-	/* Since we are atomic now, don't use the workaround ssync */
-	__builtin_bfin_ssync();
-}
-
-void __init early_dma_memcpy_done(void)
-{
-	early_shadow_stamp();
-
-	while ((bfin_read_MDMA_S0_CONFIG() && !(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)) ||
-	       (bfin_read_MDMA_S1_CONFIG() && !(bfin_read_MDMA_D1_IRQ_STATUS() & DMA_DONE)))
-		continue;
-
-	bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
-	bfin_write_MDMA_D1_IRQ_STATUS(DMA_DONE | DMA_ERR);
-	/*
-	 * Now that DMA is done, we would normally flush cache, but
-	 * i/d cache isn't running this early, so we don't bother,
-	 * and just clear out the DMA channel for next time
-	 */
-	bfin_write_MDMA_S0_CONFIG(0);
-	bfin_write_MDMA_S1_CONFIG(0);
-	bfin_write_MDMA_D0_CONFIG(0);
-	bfin_write_MDMA_D1_CONFIG(0);
-
-	__builtin_bfin_ssync();
-}
-
-/**
- *	__dma_memcpy - program the MDMA registers
- *
- * Actually program MDMA0 and wait for the transfer to finish.  Disable IRQs
- * while programming registers so that everything is fully configured.  Wait
- * for DMA to finish with IRQs enabled.  If interrupted, the initial DMA_DONE
- * check will make sure we don't clobber any existing transfer.
- */
-static void __dma_memcpy(u32 daddr, s16 dmod, u32 saddr, s16 smod, size_t cnt, u32 conf)
-{
-	static DEFINE_SPINLOCK(mdma_lock);
-	unsigned long flags;
-
-	spin_lock_irqsave(&mdma_lock, flags);
-
-	/* Force a sync in case a previous config reset on this channel
-	 * occurred.  This is needed so subsequent writes to DMA registers
-	 * are not spuriously lost/corrupted.  Do it under irq lock and
-	 * without the anomaly version (because we are atomic already).
-	 */
-	__builtin_bfin_ssync();
-
-	if (bfin_read_MDMA_S0_CONFIG())
-		while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE))
-			continue;
-
-	if (conf & DMA2D) {
-		/* For larger bit sizes, we've already divided down cnt so it
-		 * is no longer a multiple of 64k.  So we have to break down
-		 * the limit here so it is a multiple of the incoming size.
-		 * There is no limitation here in terms of total size other
-		 * than the hardware though as the bits lost in the shift are
-		 * made up by MODIFY (== we can hit the whole address space).
-		 * X: (2^(16 - 0)) * 1 == (2^(16 - 1)) * 2 == (2^(16 - 2)) * 4
-		 */
-		u32 shift = abs(dmod) >> 1;
-		size_t ycnt = cnt >> (16 - shift);
-		cnt = 1 << (16 - shift);
-		bfin_write_MDMA_D0_Y_COUNT(ycnt);
-		bfin_write_MDMA_S0_Y_COUNT(ycnt);
-		bfin_write_MDMA_D0_Y_MODIFY(dmod);
-		bfin_write_MDMA_S0_Y_MODIFY(smod);
-	}
-
-	bfin_write_MDMA_D0_START_ADDR(daddr);
-	bfin_write_MDMA_D0_X_COUNT(cnt);
-	bfin_write_MDMA_D0_X_MODIFY(dmod);
-	bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
-
-	bfin_write_MDMA_S0_START_ADDR(saddr);
-	bfin_write_MDMA_S0_X_COUNT(cnt);
-	bfin_write_MDMA_S0_X_MODIFY(smod);
-	bfin_write_MDMA_S0_IRQ_STATUS(DMA_DONE | DMA_ERR);
-
-	bfin_write_MDMA_S0_CONFIG(DMAEN | conf);
-	bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | conf);
-
-	spin_unlock_irqrestore(&mdma_lock, flags);
-
-	SSYNC();
-
-	while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE))
-		if (bfin_read_MDMA_S0_CONFIG())
-			continue;
-		else
-			return;
-
-	bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
-
-	bfin_write_MDMA_S0_CONFIG(0);
-	bfin_write_MDMA_D0_CONFIG(0);
-}
-
-/**
- *	_dma_memcpy - translate C memcpy settings into MDMA settings
- *
- * Handle all the high level steps before we touch the MDMA registers.  So
- * handle direction, tweaking of sizes, and formatting of addresses.
- */
-static void *_dma_memcpy(void *pdst, const void *psrc, size_t size)
-{
-	u32 conf, shift;
-	s16 mod;
-	unsigned long dst = (unsigned long)pdst;
-	unsigned long src = (unsigned long)psrc;
-
-	if (size == 0)
-		return NULL;
-
-	if (dst % 4 == 0 && src % 4 == 0 && size % 4 == 0) {
-		conf = WDSIZE_32;
-		shift = 2;
-	} else if (dst % 2 == 0 && src % 2 == 0 && size % 2 == 0) {
-		conf = WDSIZE_16;
-		shift = 1;
-	} else {
-		conf = WDSIZE_8;
-		shift = 0;
-	}
-
-	/* If the two memory regions have a chance of overlapping, make
-	 * sure the memcpy still works as expected.  Do this by having the
-	 * copy run backwards instead.
-	 */
-	mod = 1 << shift;
-	if (src < dst) {
-		mod *= -1;
-		dst += size + mod;
-		src += size + mod;
-	}
-	size >>= shift;
-
-	if (size > 0x10000)
-		conf |= DMA2D;
-
-	__dma_memcpy(dst, mod, src, mod, size, conf);
-
-	return pdst;
-}
-
-/**
- *	dma_memcpy - DMA memcpy under mutex lock
- *
- * Do not check arguments before starting the DMA memcpy.  Break the transfer
- * up into two pieces.  The first transfer is in multiples of 64k and the
- * second transfer is the piece smaller than 64k.
- */
-void *dma_memcpy(void *pdst, const void *psrc, size_t size)
-{
-	unsigned long dst = (unsigned long)pdst;
-	unsigned long src = (unsigned long)psrc;
-
-	if (bfin_addr_dcacheable(src))
-		blackfin_dcache_flush_range(src, src + size);
-
-	if (bfin_addr_dcacheable(dst))
-		blackfin_dcache_invalidate_range(dst, dst + size);
-
-	return dma_memcpy_nocache(pdst, psrc, size);
-}
-EXPORT_SYMBOL(dma_memcpy);
-
-/**
- *	dma_memcpy_nocache - DMA memcpy under mutex lock
- *	- No cache flush/invalidate
- *
- * Do not check arguments before starting the DMA memcpy.  Break the transfer
- * up into two pieces.  The first transfer is in multiples of 64k and the
- * second transfer is the piece smaller than 64k.
- */
-void *dma_memcpy_nocache(void *pdst, const void *psrc, size_t size)
-{
-	size_t bulk, rest;
-
-	bulk = size & ~0xffff;
-	rest = size - bulk;
-	if (bulk)
-		_dma_memcpy(pdst, psrc, bulk);
-	_dma_memcpy(pdst + bulk, psrc + bulk, rest);
-	return pdst;
-}
-EXPORT_SYMBOL(dma_memcpy_nocache);
-
-/**
- *	safe_dma_memcpy - DMA memcpy w/argument checking
- *
- * Verify arguments are safe before heading to dma_memcpy().
- */
-void *safe_dma_memcpy(void *dst, const void *src, size_t size)
-{
-	if (!access_ok(VERIFY_WRITE, dst, size))
-		return NULL;
-	if (!access_ok(VERIFY_READ, src, size))
-		return NULL;
-	return dma_memcpy(dst, src, size);
-}
-EXPORT_SYMBOL(safe_dma_memcpy);
-
-static void _dma_out(unsigned long addr, unsigned long buf, unsigned short len,
-                     u16 size, u16 dma_size)
-{
-	blackfin_dcache_flush_range(buf, buf + len * size);
-	__dma_memcpy(addr, 0, buf, size, len, dma_size);
-}
-
-static void _dma_in(unsigned long addr, unsigned long buf, unsigned short len,
-                    u16 size, u16 dma_size)
-{
-	blackfin_dcache_invalidate_range(buf, buf + len * size);
-	__dma_memcpy(buf, size, addr, 0, len, dma_size);
-}
-
-#define MAKE_DMA_IO(io, bwl, isize, dmasize, cnst) \
-void dma_##io##s##bwl(unsigned long addr, cnst void *buf, unsigned short len) \
-{ \
-	_dma_##io(addr, (unsigned long)buf, len, isize, WDSIZE_##dmasize); \
-} \
-EXPORT_SYMBOL(dma_##io##s##bwl)
-MAKE_DMA_IO(out, b, 1,  8, const);
-MAKE_DMA_IO(in,  b, 1,  8, );
-MAKE_DMA_IO(out, w, 2, 16, const);
-MAKE_DMA_IO(in,  w, 2, 16, );
-MAKE_DMA_IO(out, l, 4, 32, const);
-MAKE_DMA_IO(in,  l, 4, 32, );
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
index 8de9229..b56bd85 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
@@ -120,6 +120,7 @@
 		d_data = L2_DMEMORY;
 	} else if (addr >= physical_mem_end) {
 		if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) {
+#if defined(CONFIG_ROMFS_ON_MTD) && defined(CONFIG_MTD_ROM)
 			mask = current_rwx_mask[cpu];
 			if (mask) {
 				int page = (addr - (ASYNC_BANK0_BASE - _ramend)) >> PAGE_SHIFT;
@@ -129,6 +130,7 @@
 				if (mask[idx] & bit)
 					d_data |= CPLB_USER_RD;
 			}
+#endif
 		} else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH
 		    && (status & (FAULT_RW | FAULT_USERSUPV)) == FAULT_USERSUPV) {
 			addr &= ~(1 * 1024 * 1024 - 1);
diff --git a/arch/blackfin/kernel/ipipe.c b/arch/blackfin/kernel/ipipe.c
index dbe1122..f657b38 100644
--- a/arch/blackfin/kernel/ipipe.c
+++ b/arch/blackfin/kernel/ipipe.c
@@ -31,7 +31,6 @@
 #include <linux/kthread.h>
 #include <linux/unistd.h>
 #include <linux/io.h>
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/irq_handler.h>
 
diff --git a/arch/blackfin/kernel/kgdb_test.c b/arch/blackfin/kernel/kgdb_test.c
index 4a7dcfe..18ab004 100644
--- a/arch/blackfin/kernel/kgdb_test.c
+++ b/arch/blackfin/kernel/kgdb_test.c
@@ -13,7 +13,6 @@
 
 #include <asm/current.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #include <asm/blackfin.h>
 
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index a80a643..c0f4fe2 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -19,6 +19,7 @@
 #include <asm/blackfin.h>
 #include <asm/fixed_code.h>
 #include <asm/mem_map.h>
+#include <asm/irq.h>
 
 asmlinkage void ret_from_fork(void);
 
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
index 75089f8..e1f88e0 100644
--- a/arch/blackfin/kernel/ptrace.c
+++ b/arch/blackfin/kernel/ptrace.c
@@ -20,7 +20,6 @@
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/asm-offsets.h>
 #include <asm/dma.h>
diff --git a/arch/blackfin/kernel/reboot.c b/arch/blackfin/kernel/reboot.c
index c4c0081..b0434f8 100644
--- a/arch/blackfin/kernel/reboot.c
+++ b/arch/blackfin/kernel/reboot.c
@@ -9,7 +9,6 @@
 #include <linux/interrupt.h>
 #include <asm/bfin-global.h>
 #include <asm/reboot.h>
-#include <asm/system.h>
 #include <asm/bfrom.h>
 
 /* A system soft reset makes external memory unusable so force
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
index d6102c8..2ad747e 100644
--- a/arch/blackfin/kernel/setup.c
+++ b/arch/blackfin/kernel/setup.c
@@ -30,6 +30,7 @@
 #include <asm/fixed_code.h>
 #include <asm/early_printk.h>
 #include <asm/irq_handler.h>
+#include <asm/pda.h>
 
 u16 _bfin_swrst;
 EXPORT_SYMBOL(_bfin_swrst);
@@ -549,6 +550,7 @@
 {
 #ifdef CONFIG_MTD_UCLINUX
 	unsigned long mtd_phys = 0;
+	unsigned long n;
 #endif
 	unsigned long max_mem;
 
@@ -592,9 +594,9 @@
 	mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 8)));
 
 # if defined(CONFIG_EXT2_FS) || defined(CONFIG_EXT3_FS)
-	if (*((unsigned short *)(mtd_phys + 0x438)) == EXT2_SUPER_MAGIC)
-		mtd_size =
-		    PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x404)) << 10);
+	n = ext2_image_size((void *)(mtd_phys + 0x400));
+	if (n)
+		mtd_size = PAGE_ALIGN(n * 1024);
 # endif
 
 # if defined(CONFIG_CRAMFS)
diff --git a/arch/blackfin/kernel/trace.c b/arch/blackfin/kernel/trace.c
index 050db44..44bbf2f 100644
--- a/arch/blackfin/kernel/trace.c
+++ b/arch/blackfin/kernel/trace.c
@@ -21,6 +21,7 @@
 #include <asm/fixed_code.h>
 #include <asm/traps.h>
 #include <asm/irq_handler.h>
+#include <asm/pda.h>
 
 void decode_address(char *buf, unsigned long address)
 {
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 655f25d..de5c2c3 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -17,6 +17,7 @@
 #include <asm/trace.h>
 #include <asm/fixed_code.h>
 #include <asm/pseudo_instructions.h>
+#include <asm/pda.h>
 
 #ifdef CONFIG_KGDB
 # include <linux/kgdb.h>
diff --git a/arch/blackfin/lib/ins.S b/arch/blackfin/lib/ins.S
index 79cacce..d59608d 100644
--- a/arch/blackfin/lib/ins.S
+++ b/arch/blackfin/lib/ins.S
@@ -66,7 +66,7 @@
  *  - turns interrupts off every loop (low overhead, but longer latency)
  *  - DMA version, which do not suffer from this issue. DMA versions have
  *      different name (prefixed by dma_ ), and are located in
- *      ../kernel/bfin_dma_5xx.c
+ *      ../kernel/bfin_dma.c
  * Using the dma related functions are recommended for transferring large
  * buffers in/out of FIFOs.
  */
diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c
index e9507fe..6b39551 100644
--- a/arch/blackfin/mach-bf537/boards/pnav10.c
+++ b/arch/blackfin/mach-bf537/boards/pnav10.c
@@ -101,7 +101,6 @@
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
 #include <linux/bfin_mac.h>
-#include <linux/export.h>
 static const unsigned short bfin_mac_peripherals[] = P_RMII0;
 
 static struct bfin_phydev_platform_data bfin_phydev_data[] = {
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index 0b80725..f3562b0 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -975,7 +975,7 @@
 	},
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_AD193X) || defined(CONFIG_SND_BF5XX_SOC_AD193X_MODULE)
+#ifdef CONFIG_SND_SOC_AD193X_SPI
 	{
 		.modalias = "ad193x",
 		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
@@ -2171,7 +2171,7 @@
 #endif
 
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
-#if defined(CONFIG_SND_BF5XX_SOC_AD193X) || defined(CONFIG_SND_BF5XX_SOC_AD193X_MODULE)
+#ifdef CONFIG_SND_SOC_AD193X_I2C
 	{
 		I2C_BOARD_INFO("ad1937", 0x04),
 	},
@@ -2593,6 +2593,21 @@
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \
+				defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
+static const unsigned ad73311_gpio[] = {
+	GPIO_PF4,
+};
+
+static struct platform_device bfin_ad73311_machine = {
+	.name = "bfin-snd-ad73311",
+	.id = 1,
+	.dev = {
+		.platform_data = (void *)ad73311_gpio,
+	},
+};
+#endif
+
 #if defined(CONFIG_SND_SOC_AD73311) || defined(CONFIG_SND_SOC_AD73311_MODULE)
 static struct platform_device bfin_ad73311_codec_device = {
 	.name = "ad73311",
@@ -2862,6 +2877,11 @@
 	&bfin_ac97_pcm,
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \
+		defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
+	&bfin_ad73311_machine,
+#endif
+
 #if defined(CONFIG_SND_SOC_AD73311) || defined(CONFIG_SND_SOC_AD73311_MODULE)
 	&bfin_ad73311_codec_device,
 #endif
diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c
index 3ea45f8..4cadaf8 100644
--- a/arch/blackfin/mach-bf548/boards/ezkit.c
+++ b/arch/blackfin/mach-bf548/boards/ezkit.c
@@ -1237,6 +1237,8 @@
 	},
 	.ppi_info = &ppi_info,
 	.ppi_control = (POLC | PACKEN | DLEN_8 | XFR_TYPE | 0x20),
+	.int_mask = 0xFFFFFFFF, /* disable error interrupt on eppi */
+	.blank_clocks = 8, /* 8 clocks as SAV and EAV */
 };
 #endif
 
@@ -1293,6 +1295,11 @@
 #endif
 
 static struct i2c_board_info __initdata bfin_i2c_board_info0[] = {
+#if defined(CONFIG_SND_SOC_SSM2602) || defined(CONFIG_SND_SOC_SSM2602_MODULE)
+	{
+		I2C_BOARD_INFO("ssm2602", 0x1b),
+	},
+#endif
 };
 
 #if !defined(CONFIG_BF542)	/* The BF542 only has 1 TWI */
@@ -1385,6 +1392,8 @@
 static const u16 bfin_snd_pin[][7] = {
 	SPORT_REQ(0),
 	SPORT_REQ(1),
+	SPORT_REQ(2),
+	SPORT_REQ(3),
 };
 
 static struct bfin_snd_platform_data bfin_snd_data[] = {
@@ -1394,6 +1403,12 @@
 	{
 		.pin_req = &bfin_snd_pin[1][0],
 	},
+	{
+		.pin_req = &bfin_snd_pin[2][0],
+	},
+	{
+		.pin_req = &bfin_snd_pin[3][0],
+	},
 };
 
 #define BFIN_SND_RES(x) \
@@ -1423,10 +1438,28 @@
 static struct resource bfin_snd_resources[][4] = {
 	BFIN_SND_RES(0),
 	BFIN_SND_RES(1),
+	BFIN_SND_RES(2),
+	BFIN_SND_RES(3),
 };
+#endif
 
-static struct platform_device bfin_pcm = {
-	.name = "bfin-pcm-audio",
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+static struct platform_device bfin_i2s_pcm = {
+	.name = "bfin-i2s-pcm-audio",
+	.id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+static struct platform_device bfin_tdm_pcm = {
+	.name = "bfin-tdm-pcm-audio",
+	.id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+static struct platform_device bfin_ac97_pcm = {
+	.name = "bfin-ac97-pcm-audio",
 	.id = -1,
 };
 #endif
@@ -1599,10 +1632,14 @@
 	&ezkit_flash_device,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
-	defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
-	defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
-	&bfin_pcm,
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+	&bfin_i2s_pcm,
+#endif
+#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+	&bfin_tdm_pcm,
+#endif
+#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+	&bfin_ac97_pcm,
 #endif
 
 #if defined(CONFIG_SND_BF5XX_SOC_AD1980) || defined(CONFIG_SND_BF5XX_SOC_AD1980_MODULE)
diff --git a/arch/blackfin/mach-bf561/atomic.S b/arch/blackfin/mach-bf561/atomic.S
index 52d6f73..2a08df8 100644
--- a/arch/blackfin/mach-bf561/atomic.S
+++ b/arch/blackfin/mach-bf561/atomic.S
@@ -72,6 +72,13 @@
 	SSYNC(r2);
 	jump .Lretry_corelock_noflush
 .Ldone_corelock_noflush:
+	/*
+	 * SMP kgdb runs into dead loop without NOP here, when one core
+	 * single steps over get_core_lock_noflush and the other executes
+	 * get_core_lock as a slave node.
+	 */
+	nop;
+	CSYNC(r2);
 	rts;
 ENDPROC(_get_core_lock_noflush)
 
diff --git a/arch/blackfin/mach-bf561/include/mach/defBF561.h b/arch/blackfin/mach-bf561/include/mach/defBF561.h
index 71e805e..5f0ac5a 100644
--- a/arch/blackfin/mach-bf561/include/mach/defBF561.h
+++ b/arch/blackfin/mach-bf561/include/mach/defBF561.h
@@ -479,61 +479,61 @@
 #define DMA1_11_PERIPHERAL_MAP 0xFFC01EEC	/* DMA1 Channel 11 Peripheral Map Register */
 
 /* Memory DMA1 Controller registers (0xFFC0 1E80-0xFFC0 1FFF) */
-#define MDMA_D2_CONFIG 0xFFC01F08	/*MemDMA1 Stream 0 Destination Configuration */
-#define MDMA_D2_NEXT_DESC_PTR 0xFFC01F00	/*MemDMA1 Stream 0 Destination Next Descriptor Ptr Reg */
-#define MDMA_D2_START_ADDR 0xFFC01F04	/*MemDMA1 Stream 0 Destination Start Address */
-#define MDMA_D2_X_COUNT 0xFFC01F10	/*MemDMA1 Stream 0 Destination Inner-Loop Count */
-#define MDMA_D2_Y_COUNT 0xFFC01F18	/*MemDMA1 Stream 0 Destination Outer-Loop Count */
-#define MDMA_D2_X_MODIFY 0xFFC01F14	/*MemDMA1 Stream 0 Dest Inner-Loop Address-Increment */
-#define MDMA_D2_Y_MODIFY 0xFFC01F1C	/*MemDMA1 Stream 0 Dest Outer-Loop Address-Increment */
-#define MDMA_D2_CURR_DESC_PTR 0xFFC01F20	/*MemDMA1 Stream 0 Dest Current Descriptor Ptr reg */
-#define MDMA_D2_CURR_ADDR 0xFFC01F24	/*MemDMA1 Stream 0 Destination Current Address */
-#define MDMA_D2_CURR_X_COUNT 0xFFC01F30	/*MemDMA1 Stream 0 Dest Current Inner-Loop Count */
-#define MDMA_D2_CURR_Y_COUNT 0xFFC01F38	/*MemDMA1 Stream 0 Dest Current Outer-Loop Count */
-#define MDMA_D2_IRQ_STATUS 0xFFC01F28	/*MemDMA1 Stream 0 Destination Interrupt/Status */
-#define MDMA_D2_PERIPHERAL_MAP 0xFFC01F2C	/*MemDMA1 Stream 0 Destination Peripheral Map */
+#define MDMA_D0_CONFIG 0xFFC01F08	/*MemDMA1 Stream 0 Destination Configuration */
+#define MDMA_D0_NEXT_DESC_PTR 0xFFC01F00	/*MemDMA1 Stream 0 Destination Next Descriptor Ptr Reg */
+#define MDMA_D0_START_ADDR 0xFFC01F04	/*MemDMA1 Stream 0 Destination Start Address */
+#define MDMA_D0_X_COUNT 0xFFC01F10	/*MemDMA1 Stream 0 Destination Inner-Loop Count */
+#define MDMA_D0_Y_COUNT 0xFFC01F18	/*MemDMA1 Stream 0 Destination Outer-Loop Count */
+#define MDMA_D0_X_MODIFY 0xFFC01F14	/*MemDMA1 Stream 0 Dest Inner-Loop Address-Increment */
+#define MDMA_D0_Y_MODIFY 0xFFC01F1C	/*MemDMA1 Stream 0 Dest Outer-Loop Address-Increment */
+#define MDMA_D0_CURR_DESC_PTR 0xFFC01F20	/*MemDMA1 Stream 0 Dest Current Descriptor Ptr reg */
+#define MDMA_D0_CURR_ADDR 0xFFC01F24	/*MemDMA1 Stream 0 Destination Current Address */
+#define MDMA_D0_CURR_X_COUNT 0xFFC01F30	/*MemDMA1 Stream 0 Dest Current Inner-Loop Count */
+#define MDMA_D0_CURR_Y_COUNT 0xFFC01F38	/*MemDMA1 Stream 0 Dest Current Outer-Loop Count */
+#define MDMA_D0_IRQ_STATUS 0xFFC01F28	/*MemDMA1 Stream 0 Destination Interrupt/Status */
+#define MDMA_D0_PERIPHERAL_MAP 0xFFC01F2C	/*MemDMA1 Stream 0 Destination Peripheral Map */
 
-#define MDMA_S2_CONFIG 0xFFC01F48	/*MemDMA1 Stream 0 Source Configuration */
-#define MDMA_S2_NEXT_DESC_PTR 0xFFC01F40	/*MemDMA1 Stream 0 Source Next Descriptor Ptr Reg */
-#define MDMA_S2_START_ADDR 0xFFC01F44	/*MemDMA1 Stream 0 Source Start Address */
-#define MDMA_S2_X_COUNT 0xFFC01F50	/*MemDMA1 Stream 0 Source Inner-Loop Count */
-#define MDMA_S2_Y_COUNT 0xFFC01F58	/*MemDMA1 Stream 0 Source Outer-Loop Count */
-#define MDMA_S2_X_MODIFY 0xFFC01F54	/*MemDMA1 Stream 0 Source Inner-Loop Address-Increment */
-#define MDMA_S2_Y_MODIFY 0xFFC01F5C	/*MemDMA1 Stream 0 Source Outer-Loop Address-Increment */
-#define MDMA_S2_CURR_DESC_PTR 0xFFC01F60	/*MemDMA1 Stream 0 Source Current Descriptor Ptr reg */
-#define MDMA_S2_CURR_ADDR 0xFFC01F64	/*MemDMA1 Stream 0 Source Current Address */
-#define MDMA_S2_CURR_X_COUNT 0xFFC01F70	/*MemDMA1 Stream 0 Source Current Inner-Loop Count */
-#define MDMA_S2_CURR_Y_COUNT 0xFFC01F78	/*MemDMA1 Stream 0 Source Current Outer-Loop Count */
-#define MDMA_S2_IRQ_STATUS 0xFFC01F68	/*MemDMA1 Stream 0 Source Interrupt/Status */
-#define MDMA_S2_PERIPHERAL_MAP 0xFFC01F6C	/*MemDMA1 Stream 0 Source Peripheral Map */
+#define MDMA_S0_CONFIG 0xFFC01F48	/*MemDMA1 Stream 0 Source Configuration */
+#define MDMA_S0_NEXT_DESC_PTR 0xFFC01F40	/*MemDMA1 Stream 0 Source Next Descriptor Ptr Reg */
+#define MDMA_S0_START_ADDR 0xFFC01F44	/*MemDMA1 Stream 0 Source Start Address */
+#define MDMA_S0_X_COUNT 0xFFC01F50	/*MemDMA1 Stream 0 Source Inner-Loop Count */
+#define MDMA_S0_Y_COUNT 0xFFC01F58	/*MemDMA1 Stream 0 Source Outer-Loop Count */
+#define MDMA_S0_X_MODIFY 0xFFC01F54	/*MemDMA1 Stream 0 Source Inner-Loop Address-Increment */
+#define MDMA_S0_Y_MODIFY 0xFFC01F5C	/*MemDMA1 Stream 0 Source Outer-Loop Address-Increment */
+#define MDMA_S0_CURR_DESC_PTR 0xFFC01F60	/*MemDMA1 Stream 0 Source Current Descriptor Ptr reg */
+#define MDMA_S0_CURR_ADDR 0xFFC01F64	/*MemDMA1 Stream 0 Source Current Address */
+#define MDMA_S0_CURR_X_COUNT 0xFFC01F70	/*MemDMA1 Stream 0 Source Current Inner-Loop Count */
+#define MDMA_S0_CURR_Y_COUNT 0xFFC01F78	/*MemDMA1 Stream 0 Source Current Outer-Loop Count */
+#define MDMA_S0_IRQ_STATUS 0xFFC01F68	/*MemDMA1 Stream 0 Source Interrupt/Status */
+#define MDMA_S0_PERIPHERAL_MAP 0xFFC01F6C	/*MemDMA1 Stream 0 Source Peripheral Map */
 
-#define MDMA_D3_CONFIG 0xFFC01F88	/*MemDMA1 Stream 1 Destination Configuration */
-#define MDMA_D3_NEXT_DESC_PTR 0xFFC01F80	/*MemDMA1 Stream 1 Destination Next Descriptor Ptr Reg */
-#define MDMA_D3_START_ADDR 0xFFC01F84	/*MemDMA1 Stream 1 Destination Start Address */
-#define MDMA_D3_X_COUNT 0xFFC01F90	/*MemDMA1 Stream 1 Destination Inner-Loop Count */
-#define MDMA_D3_Y_COUNT 0xFFC01F98	/*MemDMA1 Stream 1 Destination Outer-Loop Count */
-#define MDMA_D3_X_MODIFY 0xFFC01F94	/*MemDMA1 Stream 1 Dest Inner-Loop Address-Increment */
-#define MDMA_D3_Y_MODIFY 0xFFC01F9C	/*MemDMA1 Stream 1 Dest Outer-Loop Address-Increment */
-#define MDMA_D3_CURR_DESC_PTR 0xFFC01FA0	/*MemDMA1 Stream 1 Dest Current Descriptor Ptr reg */
-#define MDMA_D3_CURR_ADDR 0xFFC01FA4	/*MemDMA1 Stream 1 Dest Current Address */
-#define MDMA_D3_CURR_X_COUNT 0xFFC01FB0	/*MemDMA1 Stream 1 Dest Current Inner-Loop Count */
-#define MDMA_D3_CURR_Y_COUNT 0xFFC01FB8	/*MemDMA1 Stream 1 Dest Current Outer-Loop Count */
-#define MDMA_D3_IRQ_STATUS 0xFFC01FA8	/*MemDMA1 Stream 1 Dest Interrupt/Status */
-#define MDMA_D3_PERIPHERAL_MAP 0xFFC01FAC	/*MemDMA1 Stream 1 Dest Peripheral Map */
+#define MDMA_D1_CONFIG 0xFFC01F88	/*MemDMA1 Stream 1 Destination Configuration */
+#define MDMA_D1_NEXT_DESC_PTR 0xFFC01F80	/*MemDMA1 Stream 1 Destination Next Descriptor Ptr Reg */
+#define MDMA_D1_START_ADDR 0xFFC01F84	/*MemDMA1 Stream 1 Destination Start Address */
+#define MDMA_D1_X_COUNT 0xFFC01F90	/*MemDMA1 Stream 1 Destination Inner-Loop Count */
+#define MDMA_D1_Y_COUNT 0xFFC01F98	/*MemDMA1 Stream 1 Destination Outer-Loop Count */
+#define MDMA_D1_X_MODIFY 0xFFC01F94	/*MemDMA1 Stream 1 Dest Inner-Loop Address-Increment */
+#define MDMA_D1_Y_MODIFY 0xFFC01F9C	/*MemDMA1 Stream 1 Dest Outer-Loop Address-Increment */
+#define MDMA_D1_CURR_DESC_PTR 0xFFC01FA0	/*MemDMA1 Stream 1 Dest Current Descriptor Ptr reg */
+#define MDMA_D1_CURR_ADDR 0xFFC01FA4	/*MemDMA1 Stream 1 Dest Current Address */
+#define MDMA_D1_CURR_X_COUNT 0xFFC01FB0	/*MemDMA1 Stream 1 Dest Current Inner-Loop Count */
+#define MDMA_D1_CURR_Y_COUNT 0xFFC01FB8	/*MemDMA1 Stream 1 Dest Current Outer-Loop Count */
+#define MDMA_D1_IRQ_STATUS 0xFFC01FA8	/*MemDMA1 Stream 1 Dest Interrupt/Status */
+#define MDMA_D1_PERIPHERAL_MAP 0xFFC01FAC	/*MemDMA1 Stream 1 Dest Peripheral Map */
 
-#define MDMA_S3_CONFIG 0xFFC01FC8	/*MemDMA1 Stream 1 Source Configuration */
-#define MDMA_S3_NEXT_DESC_PTR 0xFFC01FC0	/*MemDMA1 Stream 1 Source Next Descriptor Ptr Reg */
-#define MDMA_S3_START_ADDR 0xFFC01FC4	/*MemDMA1 Stream 1 Source Start Address */
-#define MDMA_S3_X_COUNT 0xFFC01FD0	/*MemDMA1 Stream 1 Source Inner-Loop Count */
-#define MDMA_S3_Y_COUNT 0xFFC01FD8	/*MemDMA1 Stream 1 Source Outer-Loop Count */
-#define MDMA_S3_X_MODIFY 0xFFC01FD4	/*MemDMA1 Stream 1 Source Inner-Loop Address-Increment */
-#define MDMA_S3_Y_MODIFY 0xFFC01FDC	/*MemDMA1 Stream 1 Source Outer-Loop Address-Increment */
-#define MDMA_S3_CURR_DESC_PTR 0xFFC01FE0	/*MemDMA1 Stream 1 Source Current Descriptor Ptr reg */
-#define MDMA_S3_CURR_ADDR 0xFFC01FE4	/*MemDMA1 Stream 1 Source Current Address */
-#define MDMA_S3_CURR_X_COUNT 0xFFC01FF0	/*MemDMA1 Stream 1 Source Current Inner-Loop Count */
-#define MDMA_S3_CURR_Y_COUNT 0xFFC01FF8	/*MemDMA1 Stream 1 Source Current Outer-Loop Count */
-#define MDMA_S3_IRQ_STATUS 0xFFC01FE8	/*MemDMA1 Stream 1 Source Interrupt/Status */
-#define MDMA_S3_PERIPHERAL_MAP 0xFFC01FEC	/*MemDMA1 Stream 1 Source Peripheral Map */
+#define MDMA_S1_CONFIG 0xFFC01FC8	/*MemDMA1 Stream 1 Source Configuration */
+#define MDMA_S1_NEXT_DESC_PTR 0xFFC01FC0	/*MemDMA1 Stream 1 Source Next Descriptor Ptr Reg */
+#define MDMA_S1_START_ADDR 0xFFC01FC4	/*MemDMA1 Stream 1 Source Start Address */
+#define MDMA_S1_X_COUNT 0xFFC01FD0	/*MemDMA1 Stream 1 Source Inner-Loop Count */
+#define MDMA_S1_Y_COUNT 0xFFC01FD8	/*MemDMA1 Stream 1 Source Outer-Loop Count */
+#define MDMA_S1_X_MODIFY 0xFFC01FD4	/*MemDMA1 Stream 1 Source Inner-Loop Address-Increment */
+#define MDMA_S1_Y_MODIFY 0xFFC01FDC	/*MemDMA1 Stream 1 Source Outer-Loop Address-Increment */
+#define MDMA_S1_CURR_DESC_PTR 0xFFC01FE0	/*MemDMA1 Stream 1 Source Current Descriptor Ptr reg */
+#define MDMA_S1_CURR_ADDR 0xFFC01FE4	/*MemDMA1 Stream 1 Source Current Address */
+#define MDMA_S1_CURR_X_COUNT 0xFFC01FF0	/*MemDMA1 Stream 1 Source Current Inner-Loop Count */
+#define MDMA_S1_CURR_Y_COUNT 0xFFC01FF8	/*MemDMA1 Stream 1 Source Current Outer-Loop Count */
+#define MDMA_S1_IRQ_STATUS 0xFFC01FE8	/*MemDMA1 Stream 1 Source Interrupt/Status */
+#define MDMA_S1_PERIPHERAL_MAP 0xFFC01FEC	/*MemDMA1 Stream 1 Source Peripheral Map */
 
 /* DMA2 Controller registers (0xFFC0 0C00-0xFFC0 0DFF) */
 #define DMA2_0_CONFIG 0xFFC00C08	/* DMA2 Channel 0 Configuration register */
@@ -705,61 +705,61 @@
 #define DMA2_11_PERIPHERAL_MAP 0xFFC00EEC	/* DMA2 Channel 11 Peripheral Map Register */
 
 /* Memory DMA2 Controller registers (0xFFC0 0E80-0xFFC0 0FFF) */
-#define MDMA_D0_CONFIG 0xFFC00F08	/*MemDMA2 Stream 0 Destination Configuration register */
-#define MDMA_D0_NEXT_DESC_PTR 0xFFC00F00	/*MemDMA2 Stream 0 Destination Next Descriptor Ptr Reg */
-#define MDMA_D0_START_ADDR 0xFFC00F04	/*MemDMA2 Stream 0 Destination Start Address */
-#define MDMA_D0_X_COUNT 0xFFC00F10	/*MemDMA2 Stream 0 Dest Inner-Loop Count register */
-#define MDMA_D0_Y_COUNT 0xFFC00F18	/*MemDMA2 Stream 0 Dest Outer-Loop Count register */
-#define MDMA_D0_X_MODIFY 0xFFC00F14	/*MemDMA2 Stream 0 Dest Inner-Loop Address-Increment */
-#define MDMA_D0_Y_MODIFY 0xFFC00F1C	/*MemDMA2 Stream 0 Dest Outer-Loop Address-Increment */
-#define MDMA_D0_CURR_DESC_PTR 0xFFC00F20	/*MemDMA2 Stream 0 Dest Current Descriptor Ptr reg */
-#define MDMA_D0_CURR_ADDR 0xFFC00F24	/*MemDMA2 Stream 0 Destination Current Address */
-#define MDMA_D0_CURR_X_COUNT 0xFFC00F30	/*MemDMA2 Stream 0 Dest Current Inner-Loop Count reg */
-#define MDMA_D0_CURR_Y_COUNT 0xFFC00F38	/*MemDMA2 Stream 0 Dest Current Outer-Loop Count reg */
-#define MDMA_D0_IRQ_STATUS 0xFFC00F28	/*MemDMA2 Stream 0 Dest Interrupt/Status Register */
-#define MDMA_D0_PERIPHERAL_MAP 0xFFC00F2C	/*MemDMA2 Stream 0 Destination Peripheral Map register */
+#define MDMA_D2_CONFIG 0xFFC00F08	/*MemDMA2 Stream 0 Destination Configuration register */
+#define MDMA_D2_NEXT_DESC_PTR 0xFFC00F00	/*MemDMA2 Stream 0 Destination Next Descriptor Ptr Reg */
+#define MDMA_D2_START_ADDR 0xFFC00F04	/*MemDMA2 Stream 0 Destination Start Address */
+#define MDMA_D2_X_COUNT 0xFFC00F10	/*MemDMA2 Stream 0 Dest Inner-Loop Count register */
+#define MDMA_D2_Y_COUNT 0xFFC00F18	/*MemDMA2 Stream 0 Dest Outer-Loop Count register */
+#define MDMA_D2_X_MODIFY 0xFFC00F14	/*MemDMA2 Stream 0 Dest Inner-Loop Address-Increment */
+#define MDMA_D2_Y_MODIFY 0xFFC00F1C	/*MemDMA2 Stream 0 Dest Outer-Loop Address-Increment */
+#define MDMA_D2_CURR_DESC_PTR 0xFFC00F20	/*MemDMA2 Stream 0 Dest Current Descriptor Ptr reg */
+#define MDMA_D2_CURR_ADDR 0xFFC00F24	/*MemDMA2 Stream 0 Destination Current Address */
+#define MDMA_D2_CURR_X_COUNT 0xFFC00F30	/*MemDMA2 Stream 0 Dest Current Inner-Loop Count reg */
+#define MDMA_D2_CURR_Y_COUNT 0xFFC00F38	/*MemDMA2 Stream 0 Dest Current Outer-Loop Count reg */
+#define MDMA_D2_IRQ_STATUS 0xFFC00F28	/*MemDMA2 Stream 0 Dest Interrupt/Status Register */
+#define MDMA_D2_PERIPHERAL_MAP 0xFFC00F2C	/*MemDMA2 Stream 0 Destination Peripheral Map register */
 
-#define MDMA_S0_CONFIG 0xFFC00F48	/*MemDMA2 Stream 0 Source Configuration register */
-#define MDMA_S0_NEXT_DESC_PTR 0xFFC00F40	/*MemDMA2 Stream 0 Source Next Descriptor Ptr Reg */
-#define MDMA_S0_START_ADDR 0xFFC00F44	/*MemDMA2 Stream 0 Source Start Address */
-#define MDMA_S0_X_COUNT 0xFFC00F50	/*MemDMA2 Stream 0 Source Inner-Loop Count register */
-#define MDMA_S0_Y_COUNT 0xFFC00F58	/*MemDMA2 Stream 0 Source Outer-Loop Count register */
-#define MDMA_S0_X_MODIFY 0xFFC00F54	/*MemDMA2 Stream 0 Src Inner-Loop Addr-Increment reg */
-#define MDMA_S0_Y_MODIFY 0xFFC00F5C	/*MemDMA2 Stream 0 Src Outer-Loop Addr-Increment reg */
-#define MDMA_S0_CURR_DESC_PTR 0xFFC00F60	/*MemDMA2 Stream 0 Source Current Descriptor Ptr reg */
-#define MDMA_S0_CURR_ADDR 0xFFC00F64	/*MemDMA2 Stream 0 Source Current Address */
-#define MDMA_S0_CURR_X_COUNT 0xFFC00F70	/*MemDMA2 Stream 0 Src Current Inner-Loop Count reg */
-#define MDMA_S0_CURR_Y_COUNT 0xFFC00F78	/*MemDMA2 Stream 0 Src Current Outer-Loop Count reg */
-#define MDMA_S0_IRQ_STATUS 0xFFC00F68	/*MemDMA2 Stream 0 Source Interrupt/Status Register */
-#define MDMA_S0_PERIPHERAL_MAP 0xFFC00F6C	/*MemDMA2 Stream 0 Source Peripheral Map register */
+#define MDMA_S2_CONFIG 0xFFC00F48	/*MemDMA2 Stream 0 Source Configuration register */
+#define MDMA_S2_NEXT_DESC_PTR 0xFFC00F40	/*MemDMA2 Stream 0 Source Next Descriptor Ptr Reg */
+#define MDMA_S2_START_ADDR 0xFFC00F44	/*MemDMA2 Stream 0 Source Start Address */
+#define MDMA_S2_X_COUNT 0xFFC00F50	/*MemDMA2 Stream 0 Source Inner-Loop Count register */
+#define MDMA_S2_Y_COUNT 0xFFC00F58	/*MemDMA2 Stream 0 Source Outer-Loop Count register */
+#define MDMA_S2_X_MODIFY 0xFFC00F54	/*MemDMA2 Stream 0 Src Inner-Loop Addr-Increment reg */
+#define MDMA_S2_Y_MODIFY 0xFFC00F5C	/*MemDMA2 Stream 0 Src Outer-Loop Addr-Increment reg */
+#define MDMA_S2_CURR_DESC_PTR 0xFFC00F60	/*MemDMA2 Stream 0 Source Current Descriptor Ptr reg */
+#define MDMA_S2_CURR_ADDR 0xFFC00F64	/*MemDMA2 Stream 0 Source Current Address */
+#define MDMA_S2_CURR_X_COUNT 0xFFC00F70	/*MemDMA2 Stream 0 Src Current Inner-Loop Count reg */
+#define MDMA_S2_CURR_Y_COUNT 0xFFC00F78	/*MemDMA2 Stream 0 Src Current Outer-Loop Count reg */
+#define MDMA_S2_IRQ_STATUS 0xFFC00F68	/*MemDMA2 Stream 0 Source Interrupt/Status Register */
+#define MDMA_S2_PERIPHERAL_MAP 0xFFC00F6C	/*MemDMA2 Stream 0 Source Peripheral Map register */
 
-#define MDMA_D1_CONFIG 0xFFC00F88	/*MemDMA2 Stream 1 Destination Configuration register */
-#define MDMA_D1_NEXT_DESC_PTR 0xFFC00F80	/*MemDMA2 Stream 1 Destination Next Descriptor Ptr Reg */
-#define MDMA_D1_START_ADDR 0xFFC00F84	/*MemDMA2 Stream 1 Destination Start Address */
-#define MDMA_D1_X_COUNT 0xFFC00F90	/*MemDMA2 Stream 1 Dest Inner-Loop Count register */
-#define MDMA_D1_Y_COUNT 0xFFC00F98	/*MemDMA2 Stream 1 Dest Outer-Loop Count register */
-#define MDMA_D1_X_MODIFY 0xFFC00F94	/*MemDMA2 Stream 1 Dest Inner-Loop Address-Increment */
-#define MDMA_D1_Y_MODIFY 0xFFC00F9C	/*MemDMA2 Stream 1 Dest Outer-Loop Address-Increment */
-#define MDMA_D1_CURR_DESC_PTR 0xFFC00FA0	/*MemDMA2 Stream 1 Destination Current Descriptor Ptr */
-#define MDMA_D1_CURR_ADDR 0xFFC00FA4	/*MemDMA2 Stream 1 Destination Current Address reg */
-#define MDMA_D1_CURR_X_COUNT 0xFFC00FB0	/*MemDMA2 Stream 1 Dest Current Inner-Loop Count reg */
-#define MDMA_D1_CURR_Y_COUNT 0xFFC00FB8	/*MemDMA2 Stream 1 Dest Current Outer-Loop Count reg */
-#define MDMA_D1_IRQ_STATUS 0xFFC00FA8	/*MemDMA2 Stream 1 Destination Interrupt/Status Reg */
-#define MDMA_D1_PERIPHERAL_MAP 0xFFC00FAC	/*MemDMA2 Stream 1 Destination Peripheral Map register */
+#define MDMA_D3_CONFIG 0xFFC00F88	/*MemDMA2 Stream 1 Destination Configuration register */
+#define MDMA_D3_NEXT_DESC_PTR 0xFFC00F80	/*MemDMA2 Stream 1 Destination Next Descriptor Ptr Reg */
+#define MDMA_D3_START_ADDR 0xFFC00F84	/*MemDMA2 Stream 1 Destination Start Address */
+#define MDMA_D3_X_COUNT 0xFFC00F90	/*MemDMA2 Stream 1 Dest Inner-Loop Count register */
+#define MDMA_D3_Y_COUNT 0xFFC00F98	/*MemDMA2 Stream 1 Dest Outer-Loop Count register */
+#define MDMA_D3_X_MODIFY 0xFFC00F94	/*MemDMA2 Stream 1 Dest Inner-Loop Address-Increment */
+#define MDMA_D3_Y_MODIFY 0xFFC00F9C	/*MemDMA2 Stream 1 Dest Outer-Loop Address-Increment */
+#define MDMA_D3_CURR_DESC_PTR 0xFFC00FA0	/*MemDMA2 Stream 1 Destination Current Descriptor Ptr */
+#define MDMA_D3_CURR_ADDR 0xFFC00FA4	/*MemDMA2 Stream 1 Destination Current Address reg */
+#define MDMA_D3_CURR_X_COUNT 0xFFC00FB0	/*MemDMA2 Stream 1 Dest Current Inner-Loop Count reg */
+#define MDMA_D3_CURR_Y_COUNT 0xFFC00FB8	/*MemDMA2 Stream 1 Dest Current Outer-Loop Count reg */
+#define MDMA_D3_IRQ_STATUS 0xFFC00FA8	/*MemDMA2 Stream 1 Destination Interrupt/Status Reg */
+#define MDMA_D3_PERIPHERAL_MAP 0xFFC00FAC	/*MemDMA2 Stream 1 Destination Peripheral Map register */
 
-#define MDMA_S1_CONFIG 0xFFC00FC8	/*MemDMA2 Stream 1 Source Configuration register */
-#define MDMA_S1_NEXT_DESC_PTR 0xFFC00FC0	/*MemDMA2 Stream 1 Source Next Descriptor Ptr Reg */
-#define MDMA_S1_START_ADDR 0xFFC00FC4	/*MemDMA2 Stream 1 Source Start Address */
-#define MDMA_S1_X_COUNT 0xFFC00FD0	/*MemDMA2 Stream 1 Source Inner-Loop Count register */
-#define MDMA_S1_Y_COUNT 0xFFC00FD8	/*MemDMA2 Stream 1 Source Outer-Loop Count register */
-#define MDMA_S1_X_MODIFY 0xFFC00FD4	/*MemDMA2 Stream 1 Src Inner-Loop Address-Increment */
-#define MDMA_S1_Y_MODIFY 0xFFC00FDC	/*MemDMA2 Stream 1 Source Outer-Loop Address-Increment */
-#define MDMA_S1_CURR_DESC_PTR 0xFFC00FE0	/*MemDMA2 Stream 1 Source Current Descriptor Ptr reg */
-#define MDMA_S1_CURR_ADDR 0xFFC00FE4	/*MemDMA2 Stream 1 Source Current Address */
-#define MDMA_S1_CURR_X_COUNT 0xFFC00FF0	/*MemDMA2 Stream 1 Source Current Inner-Loop Count */
-#define MDMA_S1_CURR_Y_COUNT 0xFFC00FF8	/*MemDMA2 Stream 1 Source Current Outer-Loop Count */
-#define MDMA_S1_IRQ_STATUS 0xFFC00FE8	/*MemDMA2 Stream 1 Source Interrupt/Status Register */
-#define MDMA_S1_PERIPHERAL_MAP 0xFFC00FEC	/*MemDMA2 Stream 1 Source Peripheral Map register */
+#define MDMA_S3_CONFIG 0xFFC00FC8	/*MemDMA2 Stream 1 Source Configuration register */
+#define MDMA_S3_NEXT_DESC_PTR 0xFFC00FC0	/*MemDMA2 Stream 1 Source Next Descriptor Ptr Reg */
+#define MDMA_S3_START_ADDR 0xFFC00FC4	/*MemDMA2 Stream 1 Source Start Address */
+#define MDMA_S3_X_COUNT 0xFFC00FD0	/*MemDMA2 Stream 1 Source Inner-Loop Count register */
+#define MDMA_S3_Y_COUNT 0xFFC00FD8	/*MemDMA2 Stream 1 Source Outer-Loop Count register */
+#define MDMA_S3_X_MODIFY 0xFFC00FD4	/*MemDMA2 Stream 1 Src Inner-Loop Address-Increment */
+#define MDMA_S3_Y_MODIFY 0xFFC00FDC	/*MemDMA2 Stream 1 Source Outer-Loop Address-Increment */
+#define MDMA_S3_CURR_DESC_PTR 0xFFC00FE0	/*MemDMA2 Stream 1 Source Current Descriptor Ptr reg */
+#define MDMA_S3_CURR_ADDR 0xFFC00FE4	/*MemDMA2 Stream 1 Source Current Address */
+#define MDMA_S3_CURR_X_COUNT 0xFFC00FF0	/*MemDMA2 Stream 1 Source Current Inner-Loop Count */
+#define MDMA_S3_CURR_Y_COUNT 0xFFC00FF8	/*MemDMA2 Stream 1 Source Current Outer-Loop Count */
+#define MDMA_S3_IRQ_STATUS 0xFFC00FE8	/*MemDMA2 Stream 1 Source Interrupt/Status Register */
+#define MDMA_S3_PERIPHERAL_MAP 0xFFC00FEC	/*MemDMA2 Stream 1 Source Peripheral Map register */
 
 /* Internal Memory DMA Registers (0xFFC0_1800 - 0xFFC0_19FF) */
 #define IMDMA_D0_CONFIG 0xFFC01808	/*IMDMA Stream 0 Destination Configuration */
@@ -879,6 +879,13 @@
 #define DLENGTH              0x00003800	/* PPI Data Length  */
 #define DLEN_8		     0x0	/* PPI Data Length mask for DLEN=8 */
 #define DLEN(x)	(((x-9) & 0x07) << 11)	/* PPI Data Length (only works for x=10-->x=16) */
+#define DLEN_10              0x00000800 /* Data Length = 10 Bits */
+#define DLEN_11              0x00001000 /* Data Length = 11 Bits */
+#define DLEN_12              0x00001800 /* Data Length = 12 Bits */
+#define DLEN_13              0x00002000 /* Data Length = 13 Bits */
+#define DLEN_14              0x00002800 /* Data Length = 14 Bits */
+#define DLEN_15              0x00003000 /* Data Length = 15 Bits */
+#define DLEN_16              0x00003800 /* Data Length = 16 Bits */
 #define POL                  0x0000C000	/* PPI Signal Polarities       */
 #define	POLC		0x4000		/* PPI Clock Polarity */
 #define	POLS		0x8000		/* PPI Frame Sync Polarity */
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index e413729..4698a98 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -1244,7 +1244,7 @@
 	.endr
 #endif /* CONFIG_DEBUG_BFIN_HWTRACE_EXPAND */
 
-#if CONFIG_EARLY_PRINTK
+#ifdef CONFIG_EARLY_PRINTK
 __INIT
 ENTRY(_early_trap)
 	SAVE_ALL_SYS
@@ -1755,6 +1755,8 @@
 	.long _sys_syncfs
 	.long _sys_setns
 	.long _sys_sendmmsg		/* 380 */
+	.long _sys_process_vm_readv
+	.long _sys_process_vm_writev
 
 	.rept NR_syscalls-(.-_sys_call_table)/4
 	.long _sys_ni_syscall
diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig
index 3c64b28..1c3ccd4 100644
--- a/arch/c6x/Kconfig
+++ b/arch/c6x/Kconfig
@@ -11,7 +11,7 @@
 	select HAVE_DMA_API_DEBUG
 	select HAVE_GENERIC_HARDIRQS
 	select HAVE_MEMBLOCK
-	select HAVE_SPARSE_IRQ
+	select SPARSE_IRQ
 	select IRQ_DOMAIN
 	select OF
 	select OF_EARLY_FLATTREE
diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild
index 13dcf78a..3af601e 100644
--- a/arch/c6x/include/asm/Kbuild
+++ b/arch/c6x/include/asm/Kbuild
@@ -3,7 +3,6 @@
 generic-y += atomic.h
 generic-y += auxvec.h
 generic-y += bitsperlong.h
-generic-y += bug.h
 generic-y += bugs.h
 generic-y += cputime.h
 generic-y += current.h
diff --git a/arch/c6x/include/asm/barrier.h b/arch/c6x/include/asm/barrier.h
new file mode 100644
index 0000000..538240e
--- /dev/null
+++ b/arch/c6x/include/asm/barrier.h
@@ -0,0 +1,27 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_BARRIER_H
+#define _ASM_C6X_BARRIER_H
+
+#define nop()                    asm("NOP\n");
+
+#define mb()                     barrier()
+#define rmb()                    barrier()
+#define wmb()                    barrier()
+#define set_mb(var, value)       do { var = value;  mb(); } while (0)
+#define set_wmb(var, value)      do { var = value; wmb(); } while (0)
+
+#define smp_mb()	         barrier()
+#define smp_rmb()	         barrier()
+#define smp_wmb()	         barrier()
+#define smp_read_barrier_depends()	do { } while (0)
+
+#endif /* _ASM_C6X_BARRIER_H */
diff --git a/arch/c6x/include/asm/bitops.h b/arch/c6x/include/asm/bitops.h
index 39ab7e8..0bec7e5 100644
--- a/arch/c6x/include/asm/bitops.h
+++ b/arch/c6x/include/asm/bitops.h
@@ -15,7 +15,6 @@
 
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 #include <asm/byteorder.h>
 
 /*
diff --git a/arch/c6x/include/asm/bug.h b/arch/c6x/include/asm/bug.h
new file mode 100644
index 0000000..8d59933
--- /dev/null
+++ b/arch/c6x/include/asm/bug.h
@@ -0,0 +1,23 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_BUG_H
+#define _ASM_C6X_BUG_H
+
+#include <linux/linkage.h>
+#include <asm-generic/bug.h>
+
+struct pt_regs;
+
+extern void die(char *str, struct pt_regs *fp, int nr);
+extern asmlinkage int process_exception(struct pt_regs *regs);
+extern asmlinkage void enable_exception(void);
+
+#endif /* _ASM_C6X_BUG_H */
diff --git a/arch/c6x/include/asm/cmpxchg.h b/arch/c6x/include/asm/cmpxchg.h
new file mode 100644
index 0000000..b27c8ce
--- /dev/null
+++ b/arch/c6x/include/asm/cmpxchg.h
@@ -0,0 +1,68 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_CMPXCHG_H
+#define _ASM_C6X_CMPXCHG_H
+
+#include <linux/irqflags.h>
+
+/*
+ * Misc. functions
+ */
+static inline unsigned int __xchg(unsigned int x, volatile void *ptr, int size)
+{
+	unsigned int tmp;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	switch (size) {
+	case 1:
+		tmp = 0;
+		tmp = *((unsigned char *) ptr);
+		*((unsigned char *) ptr) = (unsigned char) x;
+		break;
+	case 2:
+		tmp = 0;
+		tmp = *((unsigned short *) ptr);
+		*((unsigned short *) ptr) = x;
+		break;
+	case 4:
+		tmp = 0;
+		tmp = *((unsigned int *) ptr);
+		*((unsigned int *) ptr) = x;
+		break;
+	}
+	local_irq_restore(flags);
+	return tmp;
+}
+
+#define xchg(ptr, x) \
+	((__typeof__(*(ptr)))__xchg((unsigned int)(x), (void *) (ptr), \
+				    sizeof(*(ptr))))
+#define tas(ptr)    xchg((ptr), 1)
+
+
+#include <asm-generic/cmpxchg-local.h>
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)					\
+	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr),		\
+						     (unsigned long)(o), \
+						     (unsigned long)(n), \
+						     sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#include <asm-generic/cmpxchg.h>
+
+#endif /* _ASM_C6X_CMPXCHG_H */
diff --git a/arch/c6x/include/asm/exec.h b/arch/c6x/include/asm/exec.h
new file mode 100644
index 0000000..0fea482
--- /dev/null
+++ b/arch/c6x/include/asm/exec.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_C6X_EXEC_H
+#define _ASM_C6X_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* _ASM_C6X_EXEC_H */
diff --git a/arch/c6x/include/asm/pgtable.h b/arch/c6x/include/asm/pgtable.h
index 68c8af4..38a4312 100644
--- a/arch/c6x/include/asm/pgtable.h
+++ b/arch/c6x/include/asm/pgtable.h
@@ -73,9 +73,6 @@
 #define pgtable_cache_init()   do { } while (0)
 #define io_remap_pfn_range      remap_pfn_range
 
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)		\
-		remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
-
 #include <asm-generic/pgtable.h>
 
 #endif /* _ASM_C6X_PGTABLE_H */
diff --git a/arch/c6x/include/asm/processor.h b/arch/c6x/include/asm/processor.h
index 77ecbde..3ff7fab 100644
--- a/arch/c6x/include/asm/processor.h
+++ b/arch/c6x/include/asm/processor.h
@@ -129,4 +129,13 @@
 
 extern const struct seq_operations cpuinfo_op;
 
+/* Reset the board */
+#define HARD_RESET_NOW()
+
+extern unsigned int c6x_core_freq;
+
+
+extern void (*c6x_restart)(void);
+extern void (*c6x_halt)(void);
+
 #endif /* ASM_C6X_PROCESSOR_H */
diff --git a/arch/c6x/include/asm/setup.h b/arch/c6x/include/asm/setup.h
index 1808f27..a01e318 100644
--- a/arch/c6x/include/asm/setup.h
+++ b/arch/c6x/include/asm/setup.h
@@ -27,6 +27,7 @@
 extern unsigned char c6x_fuse_mac[6];
 
 extern void machine_init(unsigned long dt_ptr);
+extern void time_init(void);
 
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASM_C6X_SETUP_H */
diff --git a/arch/c6x/include/asm/special_insns.h b/arch/c6x/include/asm/special_insns.h
new file mode 100644
index 0000000..59672bc
--- /dev/null
+++ b/arch/c6x/include/asm/special_insns.h
@@ -0,0 +1,63 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_SPECIAL_INSNS_H
+#define _ASM_C6X_SPECIAL_INSNS_H
+
+
+#define get_creg(reg) \
+	({ unsigned int __x; \
+	   asm volatile ("mvc .s2 " #reg ",%0\n" : "=b"(__x)); __x; })
+
+#define set_creg(reg, v) \
+	do { unsigned int __x = (unsigned int)(v); \
+		asm volatile ("mvc .s2 %0," #reg "\n" : : "b"(__x)); \
+	} while (0)
+
+#define or_creg(reg, n) \
+	do { unsigned __x, __n = (unsigned)(n);		  \
+		asm volatile ("mvc .s2 " #reg ",%0\n"	  \
+			      "or  .l2 %1,%0,%0\n"	  \
+			      "mvc .s2 %0," #reg "\n"	  \
+			      "nop\n"			  \
+			      : "=&b"(__x) : "b"(__n));	  \
+	} while (0)
+
+#define and_creg(reg, n) \
+	do { unsigned __x, __n = (unsigned)(n);		  \
+		asm volatile ("mvc .s2 " #reg ",%0\n"	  \
+			      "and .l2 %1,%0,%0\n"	  \
+			      "mvc .s2 %0," #reg "\n"	  \
+			      "nop\n"    \
+			      : "=&b"(__x) : "b"(__n));	  \
+	} while (0)
+
+#define get_coreid() (get_creg(DNUM) & 0xff)
+
+/* Set/get IST */
+#define set_ist(x)	set_creg(ISTP, x)
+#define get_ist()       get_creg(ISTP)
+
+/*
+ * Exception management
+ */
+#define disable_exception()
+#define get_except_type()        get_creg(EFR)
+#define ack_exception(type)      set_creg(ECR, 1 << (type))
+#define get_iexcept()            get_creg(IERR)
+#define set_iexcept(mask)        set_creg(IERR, (mask))
+
+#define _extu(x, s, e)							\
+	({      unsigned int __x;					\
+		asm volatile ("extu .S2 %3,%1,%2,%0\n" :		\
+			      "=b"(__x) : "n"(s), "n"(e), "b"(x));	\
+	       __x; })
+
+#endif /* _ASM_C6X_SPECIAL_INSNS_H */
diff --git a/arch/c6x/include/asm/switch_to.h b/arch/c6x/include/asm/switch_to.h
new file mode 100644
index 0000000..af6c71f
--- /dev/null
+++ b/arch/c6x/include/asm/switch_to.h
@@ -0,0 +1,33 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_SWITCH_TO_H
+#define _ASM_C6X_SWITCH_TO_H
+
+#include <linux/linkage.h>
+
+#define prepare_to_switch()    do { } while (0)
+
+struct task_struct;
+struct thread_struct;
+asmlinkage void *__switch_to(struct thread_struct *prev,
+			     struct thread_struct *next,
+			     struct task_struct *tsk);
+
+#define switch_to(prev, next, last)				\
+	do {							\
+		current->thread.wchan = (u_long) __builtin_return_address(0); \
+		(last) = __switch_to(&(prev)->thread,		\
+				     &(next)->thread, (prev));	\
+		mb();						\
+		current->thread.wchan = 0;			\
+	} while (0)
+
+#endif /* _ASM_C6X_SWITCH_TO_H */
diff --git a/arch/c6x/include/asm/system.h b/arch/c6x/include/asm/system.h
deleted file mode 100644
index e076dc0..0000000
--- a/arch/c6x/include/asm/system.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- *  Port on Texas Instruments TMS320C6x architecture
- *
- *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
- *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_SYSTEM_H
-#define _ASM_C6X_SYSTEM_H
-
-#include <linux/linkage.h>
-#include <linux/irqflags.h>
-
-#define prepare_to_switch()    do { } while (0)
-
-struct task_struct;
-struct thread_struct;
-asmlinkage void *__switch_to(struct thread_struct *prev,
-			     struct thread_struct *next,
-			     struct task_struct *tsk);
-
-#define switch_to(prev, next, last)				\
-	do {							\
-		current->thread.wchan = (u_long) __builtin_return_address(0); \
-		(last) = __switch_to(&(prev)->thread,		\
-				     &(next)->thread, (prev));	\
-		mb();						\
-		current->thread.wchan = 0;			\
-	} while (0)
-
-/* Reset the board */
-#define HARD_RESET_NOW()
-
-#define get_creg(reg) \
-	({ unsigned int __x; \
-	   asm volatile ("mvc .s2 " #reg ",%0\n" : "=b"(__x)); __x; })
-
-#define set_creg(reg, v) \
-	do { unsigned int __x = (unsigned int)(v); \
-		asm volatile ("mvc .s2 %0," #reg "\n" : : "b"(__x)); \
-	} while (0)
-
-#define or_creg(reg, n) \
-	do { unsigned __x, __n = (unsigned)(n);		  \
-		asm volatile ("mvc .s2 " #reg ",%0\n"	  \
-			      "or  .l2 %1,%0,%0\n"	  \
-			      "mvc .s2 %0," #reg "\n"	  \
-			      "nop\n"			  \
-			      : "=&b"(__x) : "b"(__n));	  \
-	} while (0)
-
-#define and_creg(reg, n) \
-	do { unsigned __x, __n = (unsigned)(n);		  \
-		asm volatile ("mvc .s2 " #reg ",%0\n"	  \
-			      "and .l2 %1,%0,%0\n"	  \
-			      "mvc .s2 %0," #reg "\n"	  \
-			      "nop\n"    \
-			      : "=&b"(__x) : "b"(__n));	  \
-	} while (0)
-
-#define get_coreid() (get_creg(DNUM) & 0xff)
-
-/* Set/get IST */
-#define set_ist(x)	set_creg(ISTP, x)
-#define get_ist()       get_creg(ISTP)
-
-/*
- * Exception management
- */
-asmlinkage void enable_exception(void);
-#define disable_exception()
-#define get_except_type()        get_creg(EFR)
-#define ack_exception(type)      set_creg(ECR, 1 << (type))
-#define get_iexcept()            get_creg(IERR)
-#define set_iexcept(mask)        set_creg(IERR, (mask))
-
-/*
- * Misc. functions
- */
-#define nop()                    asm("NOP\n");
-#define mb()                     barrier()
-#define rmb()                    barrier()
-#define wmb()                    barrier()
-#define set_mb(var, value)       do { var = value;  mb(); } while (0)
-#define set_wmb(var, value)      do { var = value; wmb(); } while (0)
-
-#define smp_mb()	         barrier()
-#define smp_rmb()	         barrier()
-#define smp_wmb()	         barrier()
-#define smp_read_barrier_depends()	do { } while (0)
-
-#define xchg(ptr, x) \
-	((__typeof__(*(ptr)))__xchg((unsigned int)(x), (void *) (ptr), \
-				    sizeof(*(ptr))))
-#define tas(ptr)    xchg((ptr), 1)
-
-unsigned int _lmbd(unsigned int, unsigned int);
-unsigned int _bitr(unsigned int);
-
-struct __xchg_dummy { unsigned int a[100]; };
-#define __xg(x) ((volatile struct __xchg_dummy *)(x))
-
-static inline unsigned int __xchg(unsigned int x, volatile void *ptr, int size)
-{
-	unsigned int tmp;
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	switch (size) {
-	case 1:
-		tmp = 0;
-		tmp = *((unsigned char *) ptr);
-		*((unsigned char *) ptr) = (unsigned char) x;
-		break;
-	case 2:
-		tmp = 0;
-		tmp = *((unsigned short *) ptr);
-		*((unsigned short *) ptr) = x;
-		break;
-	case 4:
-		tmp = 0;
-		tmp = *((unsigned int *) ptr);
-		*((unsigned int *) ptr) = x;
-		break;
-	}
-	local_irq_restore(flags);
-	return tmp;
-}
-
-#include <asm-generic/cmpxchg-local.h>
-
-/*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
- */
-#define cmpxchg_local(ptr, o, n)					\
-	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr),		\
-						     (unsigned long)(o), \
-						     (unsigned long)(n), \
-						     sizeof(*(ptr))))
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-
-#include <asm-generic/cmpxchg.h>
-
-#define _extu(x, s, e)							\
-	({      unsigned int __x;					\
-		asm volatile ("extu .S2 %3,%1,%2,%0\n" :		\
-			      "=b"(__x) : "n"(s), "n"(e), "b"(x));	\
-	       __x; })
-
-
-extern unsigned int c6x_core_freq;
-
-struct pt_regs;
-
-extern void die(char *str, struct pt_regs *fp, int nr);
-extern asmlinkage int process_exception(struct pt_regs *regs);
-extern void time_init(void);
-extern void free_initmem(void);
-
-extern void (*c6x_restart)(void);
-extern void (*c6x_halt)(void);
-
-#endif /* _ASM_C6X_SYSTEM_H */
diff --git a/arch/c6x/kernel/irq.c b/arch/c6x/kernel/irq.c
index d77bcfd..65b8ddf 100644
--- a/arch/c6x/kernel/irq.c
+++ b/arch/c6x/kernel/irq.c
@@ -27,6 +27,7 @@
 #include <linux/kernel_stat.h>
 
 #include <asm/megamod-pic.h>
+#include <asm/special_insns.h>
 
 unsigned long irq_err_count;
 
diff --git a/arch/c6x/kernel/setup.c b/arch/c6x/kernel/setup.c
index 0c07921..ce46186 100644
--- a/arch/c6x/kernel/setup.c
+++ b/arch/c6x/kernel/setup.c
@@ -34,6 +34,7 @@
 #include <asm/dscr.h>
 #include <asm/clock.h>
 #include <asm/soc.h>
+#include <asm/special_insns.h>
 
 static const char *c6x_soc_name;
 
diff --git a/arch/c6x/kernel/signal.c b/arch/c6x/kernel/signal.c
index 304f675..3b5a050 100644
--- a/arch/c6x/kernel/signal.c
+++ b/arch/c6x/kernel/signal.c
@@ -85,10 +85,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
@@ -279,15 +276,8 @@
 
 	/* Set up the stack frame */
 	ret = setup_rt_frame(sig, ka, info, oldset, regs);
-	if (ret == 0) {
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked, &current->blocked,
-			  &ka->sa.sa_mask);
-		if (!(ka->sa.sa_flags & SA_NODEFER))
-			sigaddset(&current->blocked, sig);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
-	}
+	if (ret == 0)
+		block_sigmask(ka, sig);
 
 	return ret;
 }
diff --git a/arch/c6x/kernel/soc.c b/arch/c6x/kernel/soc.c
index dd45bc3..0748c94 100644
--- a/arch/c6x/kernel/soc.c
+++ b/arch/c6x/kernel/soc.c
@@ -11,7 +11,6 @@
 #include <linux/module.h>
 #include <linux/ctype.h>
 #include <linux/etherdevice.h>
-#include <asm/system.h>
 #include <asm/setup.h>
 #include <asm/soc.h>
 
diff --git a/arch/c6x/kernel/time.c b/arch/c6x/kernel/time.c
index 4c9f136..356ee84 100644
--- a/arch/c6x/kernel/time.c
+++ b/arch/c6x/kernel/time.c
@@ -20,6 +20,7 @@
 #include <linux/timex.h>
 #include <linux/profile.h>
 
+#include <asm/special_insns.h>
 #include <asm/timer64.h>
 
 static u32 sched_clock_multiplier;
diff --git a/arch/c6x/kernel/traps.c b/arch/c6x/kernel/traps.c
index f50e3ed..1be74e5 100644
--- a/arch/c6x/kernel/traps.c
+++ b/arch/c6x/kernel/traps.c
@@ -14,6 +14,7 @@
 #include <linux/bug.h>
 
 #include <asm/soc.h>
+#include <asm/special_insns.h>
 #include <asm/traps.h>
 
 int (*c6x_nmi_handler)(struct pt_regs *regs);
diff --git a/arch/c6x/platforms/timer64.c b/arch/c6x/platforms/timer64.c
index 03c03c2..3c73d74 100644
--- a/arch/c6x/platforms/timer64.c
+++ b/arch/c6x/platforms/timer64.c
@@ -15,6 +15,7 @@
 #include <linux/of_address.h>
 #include <asm/soc.h>
 #include <asm/dscr.h>
+#include <asm/special_insns.h>
 #include <asm/timer64.h>
 
 struct timer_regs {
diff --git a/arch/cris/arch-v10/drivers/ds1302.c b/arch/cris/arch-v10/drivers/ds1302.c
index 3d655dc..74f99c6 100644
--- a/arch/cris/arch-v10/drivers/ds1302.c
+++ b/arch/cris/arch-v10/drivers/ds1302.c
@@ -24,7 +24,6 @@
 #include <linux/capability.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <arch/svinto.h>
 #include <asm/io.h>
 #include <asm/rtc.h>
diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c
index a276f08..609d551 100644
--- a/arch/cris/arch-v10/drivers/gpio.c
+++ b/arch/cris/arch-v10/drivers/gpio.c
@@ -24,7 +24,6 @@
 #include <asm/etraxgpio.h>
 #include <arch/svinto.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <arch/io_interface_mux.h>
 
diff --git a/arch/cris/arch-v10/drivers/i2c.c b/arch/cris/arch-v10/drivers/i2c.c
index c413539..b3d1f9e 100644
--- a/arch/cris/arch-v10/drivers/i2c.c
+++ b/arch/cris/arch-v10/drivers/i2c.c
@@ -22,7 +22,6 @@
 
 #include <asm/etraxi2c.h>
 
-#include <asm/system.h>
 #include <arch/svinto.h>
 #include <asm/io.h>
 #include <asm/delay.h>
diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c
index 1391b73..9da0568 100644
--- a/arch/cris/arch-v10/drivers/pcf8563.c
+++ b/arch/cris/arch-v10/drivers/pcf8563.c
@@ -29,7 +29,6 @@
 #include <linux/mutex.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/rtc.h>
 
diff --git a/arch/cris/arch-v10/drivers/sync_serial.c b/arch/cris/arch-v10/drivers/sync_serial.c
index 466af40..c4b7171 100644
--- a/arch/cris/arch-v10/drivers/sync_serial.c
+++ b/arch/cris/arch-v10/drivers/sync_serial.c
@@ -27,7 +27,6 @@
 #include <asm/io.h>
 #include <arch/svinto.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/sync_serial.h>
 #include <arch/io_interface_mux.h>
 
diff --git a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c
index 99851ba..f932c85 100644
--- a/arch/cris/arch-v10/kernel/debugport.c
+++ b/arch/cris/arch-v10/kernel/debugport.c
@@ -18,7 +18,6 @@
 #include <linux/major.h>
 #include <linux/delay.h>
 #include <linux/tty.h>
-#include <asm/system.h>
 #include <arch/svinto.h>
 #include <asm/io.h>             /* Get SIMCOUT. */
 
diff --git a/arch/cris/arch-v10/kernel/dma.c b/arch/cris/arch-v10/kernel/dma.c
index d31504b..5795047 100644
--- a/arch/cris/arch-v10/kernel/dma.c
+++ b/arch/cris/arch-v10/kernel/dma.c
@@ -8,6 +8,7 @@
 
 #include <asm/dma.h>
 #include <arch/svinto.h>
+#include <arch/system.h>
 
 /* Macro to access ETRAX 100 registers */
 #define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
diff --git a/arch/cris/arch-v10/kernel/io_interface_mux.c b/arch/cris/arch-v10/kernel/io_interface_mux.c
index 29f97e9..ad64cd1 100644
--- a/arch/cris/arch-v10/kernel/io_interface_mux.c
+++ b/arch/cris/arch-v10/kernel/io_interface_mux.c
@@ -14,6 +14,7 @@
 #include <arch/svinto.h>
 #include <asm/io.h>
 #include <arch/io_interface_mux.h>
+#include <arch/system.h>
 
 
 #define DBG(s)
diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c
index 9a57db6..bee8df4 100644
--- a/arch/cris/arch-v10/kernel/process.c
+++ b/arch/cris/arch-v10/kernel/process.c
@@ -16,6 +16,7 @@
 #include <linux/fs.h>
 #include <arch/svinto.h>
 #include <linux/init.h>
+#include <arch/system.h>
 
 #ifdef CONFIG_ETRAX_GPIO
 void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */
diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c
index 320065f..bfddfb9 100644
--- a/arch/cris/arch-v10/kernel/ptrace.c
+++ b/arch/cris/arch-v10/kernel/ptrace.c
@@ -15,7 +15,6 @@
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 
 /* 
diff --git a/arch/cris/arch-v10/kernel/setup.c b/arch/cris/arch-v10/kernel/setup.c
index de27b50..4f96d71 100644
--- a/arch/cris/arch-v10/kernel/setup.c
+++ b/arch/cris/arch-v10/kernel/setup.c
@@ -14,6 +14,7 @@
 #include <linux/proc_fs.h>
 #include <linux/delay.h>
 #include <linux/param.h>
+#include <arch/system.h>
 
 #ifdef CONFIG_PROC_FS
 #define HAS_FPU		0x0001
diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c
index e78fe49..289c584 100644
--- a/arch/cris/arch-v10/kernel/signal.c
+++ b/arch/cris/arch-v10/kernel/signal.c
@@ -27,6 +27,7 @@
 #include <asm/processor.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
+#include <arch/system.h>
 
 #define DEBUG_SIG 0
 
diff --git a/arch/cris/arch-v10/kernel/traps.c b/arch/cris/arch-v10/kernel/traps.c
index 8bebb96..7001bed 100644
--- a/arch/cris/arch-v10/kernel/traps.c
+++ b/arch/cris/arch-v10/kernel/traps.c
@@ -11,6 +11,7 @@
 #include <linux/ptrace.h>
 #include <asm/uaccess.h>
 #include <arch/sv_addr_ag.h>
+#include <arch/system.h>
 
 void
 show_registers(struct pt_regs *regs)
diff --git a/arch/cris/arch-v32/drivers/i2c.c b/arch/cris/arch-v32/drivers/i2c.c
index ddb2399..3b2c82c 100644
--- a/arch/cris/arch-v32/drivers/i2c.c
+++ b/arch/cris/arch-v32/drivers/i2c.c
@@ -36,7 +36,6 @@
 
 #include <asm/etraxi2c.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/delay.h>
 
diff --git a/arch/cris/arch-v32/drivers/mach-a3/gpio.c b/arch/cris/arch-v32/drivers/mach-a3/gpio.c
index c845831..0b86dee 100644
--- a/arch/cris/arch-v32/drivers/mach-a3/gpio.c
+++ b/arch/cris/arch-v32/drivers/mach-a3/gpio.c
@@ -31,7 +31,6 @@
 #include <hwregs/gio_defs.h>
 #include <hwregs/intr_vect_defs.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <mach/pinmux.h>
 
diff --git a/arch/cris/arch-v32/drivers/mach-fs/gpio.c b/arch/cris/arch-v32/drivers/mach-fs/gpio.c
index ee90d26..a2ac091 100644
--- a/arch/cris/arch-v32/drivers/mach-fs/gpio.c
+++ b/arch/cris/arch-v32/drivers/mach-fs/gpio.c
@@ -30,7 +30,6 @@
 #include <hwregs/gio_defs.h>
 #include <hwregs/intr_vect_defs.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 
 #ifdef CONFIG_ETRAX_VIRTUAL_GPIO
diff --git a/arch/cris/arch-v32/kernel/debugport.c b/arch/cris/arch-v32/kernel/debugport.c
index 794b364..610909b 100644
--- a/arch/cris/arch-v32/kernel/debugport.c
+++ b/arch/cris/arch-v32/kernel/debugport.c
@@ -4,7 +4,6 @@
 
 #include <linux/console.h>
 #include <linux/init.h>
-#include <asm/system.h>
 #include <hwregs/reg_rdwr.h>
 #include <hwregs/reg_map.h>
 #include <hwregs/ser_defs.h>
diff --git a/arch/cris/arch-v32/kernel/fasttimer.c b/arch/cris/arch-v32/kernel/fasttimer.c
index 111caa1..ab1551e 100644
--- a/arch/cris/arch-v32/kernel/fasttimer.c
+++ b/arch/cris/arch-v32/kernel/fasttimer.c
@@ -17,7 +17,6 @@
 #include <linux/delay.h>
 
 #include <asm/irq.h>
-#include <asm/system.h>
 
 #include <hwregs/reg_map.h>
 #include <hwregs/reg_rdwr.h>
diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c
index 511ece9..f7ad9e8 100644
--- a/arch/cris/arch-v32/kernel/ptrace.c
+++ b/arch/cris/arch-v32/kernel/ptrace.c
@@ -15,7 +15,6 @@
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <arch/hwregs/supp_reg.h>
 
diff --git a/arch/cris/arch-v32/mach-a3/dma.c b/arch/cris/arch-v32/mach-a3/dma.c
index f35e4f6..47c64bf 100644
--- a/arch/cris/arch-v32/mach-a3/dma.c
+++ b/arch/cris/arch-v32/mach-a3/dma.c
@@ -9,7 +9,6 @@
 #include <hwregs/clkgen_defs.h>
 #include <hwregs/strmux_defs.h>
 #include <linux/errno.h>
-#include <asm/system.h>
 #include <arbiter.h>
 
 static char used_dma_channels[MAX_DMA_CHANNELS];
diff --git a/arch/cris/arch-v32/mach-fs/dma.c b/arch/cris/arch-v32/mach-fs/dma.c
index 2d970d7..fc6416a 100644
--- a/arch/cris/arch-v32/mach-fs/dma.c
+++ b/arch/cris/arch-v32/mach-fs/dma.c
@@ -9,7 +9,6 @@
 #include <hwregs/config_defs.h>
 #include <hwregs/strmux_defs.h>
 #include <linux/errno.h>
-#include <asm/system.h>
 #include <mach/arbiter.h>
 
 static char used_dma_channels[MAX_DMA_CHANNELS];
diff --git a/arch/cris/include/arch-v10/arch/elf.h b/arch/cris/include/arch-v10/arch/elf.h
index 1c38ee7..1eb638a 100644
--- a/arch/cris/include/arch-v10/arch/elf.h
+++ b/arch/cris/include/arch-v10/arch/elf.h
@@ -1,6 +1,8 @@
 #ifndef __ASMCRIS_ARCH_ELF_H
 #define __ASMCRIS_ARCH_ELF_H
 
+#include <arch/system.h>
+
 #define ELF_MACH EF_CRIS_VARIANT_ANY_V0_V10
 
 /*
diff --git a/arch/cris/include/arch-v32/arch/elf.h b/arch/cris/include/arch-v32/arch/elf.h
index 1324e50..c46d582 100644
--- a/arch/cris/include/arch-v32/arch/elf.h
+++ b/arch/cris/include/arch-v32/arch/elf.h
@@ -1,6 +1,8 @@
 #ifndef _ASM_CRIS_ELF_H
 #define _ASM_CRIS_ELF_H
 
+#include <arch/system.h>
+
 #define ELF_CORE_EFLAGS EF_CRIS_VARIANT_V32
 
 /*
diff --git a/arch/cris/include/arch-v32/arch/system.h b/arch/cris/include/arch-v32/arch/system.h
index 76cea99..db853fb 100644
--- a/arch/cris/include/arch-v32/arch/system.h
+++ b/arch/cris/include/arch-v32/arch/system.h
@@ -34,14 +34,4 @@
 /* Write the user-mode stack pointer. */
 #define wrusp(usp) __asm__ __volatile__ ("move %0, $usp" : : "rm" (usp))
 
-#define nop() __asm__ __volatile__ ("nop");
-
-#define xchg(ptr,x) \
-	((__typeof__(*(ptr)))__xchg((unsigned long) (x),(ptr),sizeof(*(ptr))))
-
-#define tas(ptr) (xchg((ptr),1))
-
-struct __xchg_dummy { unsigned long a[100]; };
-#define __xg(x) ((struct __xchg_dummy *)(x))
-
 #endif /* _ASM_CRIS_ARCH_SYSTEM_H */
diff --git a/arch/cris/include/asm/atomic.h b/arch/cris/include/asm/atomic.h
index bbf09381..1056a5d 100644
--- a/arch/cris/include/asm/atomic.h
+++ b/arch/cris/include/asm/atomic.h
@@ -5,7 +5,7 @@
 
 #include <linux/compiler.h>
 #include <linux/types.h>
-#include <asm/system.h>
+#include <asm/cmpxchg.h>
 #include <arch/atomic.h>
 
 /*
diff --git a/arch/cris/include/asm/barrier.h b/arch/cris/include/asm/barrier.h
new file mode 100644
index 0000000..198ad7f
--- /dev/null
+++ b/arch/cris/include/asm/barrier.h
@@ -0,0 +1,25 @@
+#ifndef __ASM_CRIS_BARRIER_H
+#define __ASM_CRIS_BARRIER_H
+
+#define nop() __asm__ __volatile__ ("nop");
+
+#define barrier() __asm__ __volatile__("": : :"memory")
+#define mb() barrier()
+#define rmb() mb()
+#define wmb() mb()
+#define read_barrier_depends() do { } while(0)
+#define set_mb(var, value)  do { var = value; mb(); } while (0)
+
+#ifdef CONFIG_SMP
+#define smp_mb()        mb()
+#define smp_rmb()       rmb()
+#define smp_wmb()       wmb()
+#define smp_read_barrier_depends()     read_barrier_depends()
+#else
+#define smp_mb()        barrier()
+#define smp_rmb()       barrier()
+#define smp_wmb()       barrier()
+#define smp_read_barrier_depends()     do { } while(0)
+#endif
+
+#endif /* __ASM_CRIS_BARRIER_H */
diff --git a/arch/cris/include/asm/bitops.h b/arch/cris/include/asm/bitops.h
index a78a2d7..184066c 100644
--- a/arch/cris/include/asm/bitops.h
+++ b/arch/cris/include/asm/bitops.h
@@ -19,7 +19,6 @@
 #endif
 
 #include <arch/bitops.h>
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <linux/compiler.h>
 
diff --git a/arch/cris/include/asm/cmpxchg.h b/arch/cris/include/asm/cmpxchg.h
new file mode 100644
index 0000000..b756dac
--- /dev/null
+++ b/arch/cris/include/asm/cmpxchg.h
@@ -0,0 +1,53 @@
+#ifndef __ASM_CRIS_CMPXCHG__
+#define __ASM_CRIS_CMPXCHG__
+
+#include <linux/irqflags.h>
+
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+{
+  /* since Etrax doesn't have any atomic xchg instructions, we need to disable
+     irq's (if enabled) and do it with move.d's */
+  unsigned long flags,temp;
+  local_irq_save(flags); /* save flags, including irq enable bit and shut off irqs */
+  switch (size) {
+  case 1:
+    *((unsigned char *)&temp) = x;
+    x = *(unsigned char *)ptr;
+    *(unsigned char *)ptr = *((unsigned char *)&temp);
+    break;
+  case 2:
+    *((unsigned short *)&temp) = x;
+    x = *(unsigned short *)ptr;
+    *(unsigned short *)ptr = *((unsigned short *)&temp);
+    break;
+  case 4:
+    temp = x;
+    x = *(unsigned long *)ptr;
+    *(unsigned long *)ptr = temp;
+    break;
+  }
+  local_irq_restore(flags); /* restore irq enable bit */
+  return x;
+}
+
+#define xchg(ptr,x) \
+	((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+#define tas(ptr) (xchg((ptr),1))
+
+#include <asm-generic/cmpxchg-local.h>
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)				 	       \
+	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+			(unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#ifndef CONFIG_SMP
+#include <asm-generic/cmpxchg.h>
+#endif
+
+#endif /* __ASM_CRIS_CMPXCHG__ */
diff --git a/arch/cris/include/asm/exec.h b/arch/cris/include/asm/exec.h
new file mode 100644
index 0000000..9665dab
--- /dev/null
+++ b/arch/cris/include/asm/exec.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_CRIS_EXEC_H
+#define __ASM_CRIS_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* __ASM_CRIS_EXEC_H */
diff --git a/arch/cris/include/asm/posix_types.h b/arch/cris/include/asm/posix_types.h
index ce3fb25..72b3cd6 100644
--- a/arch/cris/include/asm/posix_types.h
+++ b/arch/cris/include/asm/posix_types.h
@@ -12,55 +12,25 @@
  * assume GCC is being used.
  */
 
-typedef unsigned long	__kernel_ino_t;
 typedef unsigned short	__kernel_mode_t;
+#define __kernel_mode_t __kernel_mode_t
+
 typedef unsigned short	__kernel_nlink_t;
-typedef long		__kernel_off_t;
-typedef int		__kernel_pid_t;
+#define __kernel_nlink_t __kernel_nlink_t
+
 typedef unsigned short  __kernel_ipc_pid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
+
 typedef unsigned short	__kernel_uid_t;
 typedef unsigned short	__kernel_gid_t;
+#define __kernel_uid_t __kernel_uid_t
+
 typedef __SIZE_TYPE__	__kernel_size_t;
 typedef long		__kernel_ssize_t;
 typedef int		__kernel_ptrdiff_t;
-typedef long		__kernel_time_t;
-typedef long            __kernel_suseconds_t;
-typedef long		__kernel_clock_t;
-typedef int		__kernel_timer_t;
-typedef int		__kernel_clockid_t;
-typedef int		__kernel_daddr_t;
-typedef char *		__kernel_caddr_t;
-typedef unsigned short  __kernel_uid16_t;
-typedef unsigned short  __kernel_gid16_t;
-typedef unsigned int    __kernel_uid32_t;
-typedef unsigned int    __kernel_gid32_t;
+#define __kernel_size_t __kernel_size_t
 
-typedef unsigned short  __kernel_old_uid_t;
-typedef unsigned short  __kernel_old_gid_t;
 typedef unsigned short	__kernel_old_dev_t;
-
-#ifdef __GNUC__
-typedef long long	__kernel_loff_t;
-#endif
-
-typedef struct {
-	int	val[2];
-} __kernel_fsid_t;
-
-#ifdef __KERNEL__
-
-#undef	__FD_SET
-#define __FD_SET(fd,fdsetp) set_bit(fd, (void *)(fdsetp))
-
-#undef	__FD_CLR
-#define __FD_CLR(fd,fdsetp) clear_bit(fd, (void *)(fdsetp))
-
-#undef	__FD_ISSET
-#define __FD_ISSET(fd,fdsetp) test_bit(fd, (void *)(fdsetp))
-
-#undef	__FD_ZERO
-#define __FD_ZERO(fdsetp) memset((void *)(fdsetp), 0, __FDSET_LONGS << 2)
-
-#endif /* __KERNEL__ */
+#define __kernel_old_dev_t __kernel_old_dev_t
 
 #endif /* __ARCH_CRIS_POSIX_TYPES_H */
diff --git a/arch/cris/include/asm/processor.h b/arch/cris/include/asm/processor.h
index 3f7248f..4210d72 100644
--- a/arch/cris/include/asm/processor.h
+++ b/arch/cris/include/asm/processor.h
@@ -10,10 +10,10 @@
 #ifndef __ASM_CRIS_PROCESSOR_H
 #define __ASM_CRIS_PROCESSOR_H
 
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
 #include <arch/processor.h>
+#include <arch/system.h>
 
 struct task_struct;
 
@@ -72,4 +72,13 @@
 
 #define cpu_relax()     barrier()
 
+/*
+ * disable hlt during certain critical i/o operations
+ */
+#define HAVE_DISABLE_HLT
+void disable_hlt(void);
+void enable_hlt(void);
+
+void default_idle(void);
+
 #endif /* __ASM_CRIS_PROCESSOR_H */
diff --git a/arch/cris/include/asm/switch_to.h b/arch/cris/include/asm/switch_to.h
new file mode 100644
index 0000000..d842e11
--- /dev/null
+++ b/arch/cris/include/asm/switch_to.h
@@ -0,0 +1,12 @@
+#ifndef __ASM_CRIS_SWITCH_TO_H
+#define __ASM_CRIS_SWITCH_TO_H
+
+/* the switch_to macro calls resume, an asm function in entry.S which does the actual
+ * task switching.
+ */
+
+extern struct task_struct *resume(struct task_struct *prev, struct task_struct *next, int);
+#define switch_to(prev,next,last) last = resume(prev,next, \
+					 (int)&((struct task_struct *)0)->thread)
+
+#endif /* __ASM_CRIS_SWITCH_TO_H */
diff --git a/arch/cris/include/asm/system.h b/arch/cris/include/asm/system.h
deleted file mode 100644
index ea10592..0000000
--- a/arch/cris/include/asm/system.h
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef __ASM_CRIS_SYSTEM_H
-#define __ASM_CRIS_SYSTEM_H
-
-#include <linux/irqflags.h>
-#include <arch/system.h>
-
-/* the switch_to macro calls resume, an asm function in entry.S which does the actual
- * task switching.
- */
-
-extern struct task_struct *resume(struct task_struct *prev, struct task_struct *next, int);
-#define switch_to(prev,next,last) last = resume(prev,next, \
-					 (int)&((struct task_struct *)0)->thread)
-
-#define barrier() __asm__ __volatile__("": : :"memory")
-#define mb() barrier()
-#define rmb() mb()
-#define wmb() mb()
-#define read_barrier_depends() do { } while(0)
-#define set_mb(var, value)  do { var = value; mb(); } while (0)
-
-#ifdef CONFIG_SMP
-#define smp_mb()        mb()
-#define smp_rmb()       rmb()
-#define smp_wmb()       wmb()
-#define smp_read_barrier_depends()     read_barrier_depends()
-#else
-#define smp_mb()        barrier()
-#define smp_rmb()       barrier()
-#define smp_wmb()       barrier()
-#define smp_read_barrier_depends()     do { } while(0)
-#endif
-
-#define iret()
-
-/*
- * disable hlt during certain critical i/o operations
- */
-#define HAVE_DISABLE_HLT
-void disable_hlt(void);
-void enable_hlt(void);
-
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
-{
-  /* since Etrax doesn't have any atomic xchg instructions, we need to disable
-     irq's (if enabled) and do it with move.d's */
-  unsigned long flags,temp;
-  local_irq_save(flags); /* save flags, including irq enable bit and shut off irqs */
-  switch (size) {
-  case 1:
-    *((unsigned char *)&temp) = x;
-    x = *(unsigned char *)ptr;
-    *(unsigned char *)ptr = *((unsigned char *)&temp);
-    break;
-  case 2:
-    *((unsigned short *)&temp) = x;
-    x = *(unsigned short *)ptr;
-    *(unsigned short *)ptr = *((unsigned short *)&temp);
-    break;
-  case 4:
-    temp = x;
-    x = *(unsigned long *)ptr;
-    *(unsigned long *)ptr = temp;
-    break;
-  }
-  local_irq_restore(flags); /* restore irq enable bit */
-  return x;
-}
-
-#include <asm-generic/cmpxchg-local.h>
-
-/*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
- */
-#define cmpxchg_local(ptr, o, n)				 	       \
-	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
-			(unsigned long)(n), sizeof(*(ptr))))
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-
-#ifndef CONFIG_SMP
-#include <asm-generic/cmpxchg.h>
-#endif
-
-#define arch_align_stack(x) (x)
-
-void default_idle(void);
-
-#endif
diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c
index 788eb22..d36836d 100644
--- a/arch/cris/kernel/irq.c
+++ b/arch/cris/kernel/irq.c
@@ -36,6 +36,7 @@
 #include <linux/spinlock.h>
 
 #include <asm/io.h>
+#include <arch/system.h>
 
 /* called by the assembler IRQ entry functions defined in irq.h
  * to dispatch the interrupts to registered handlers
diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c
index d8f50ff..891dad8 100644
--- a/arch/cris/kernel/process.c
+++ b/arch/cris/kernel/process.c
@@ -16,7 +16,6 @@
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/init_task.h>
diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c
index 48b0f39..d114ad3 100644
--- a/arch/cris/kernel/ptrace.c
+++ b/arch/cris/kernel/ptrace.c
@@ -21,7 +21,6 @@
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 
 
diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c
index b712f49..32c3d24 100644
--- a/arch/cris/kernel/setup.c
+++ b/arch/cris/kernel/setup.c
@@ -20,6 +20,7 @@
 #include <linux/pfn.h>
 #include <linux/cpu.h>
 #include <asm/setup.h>
+#include <arch/system.h>
 
 /*
  * Setup options
diff --git a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c
index 8da53f3..a11ad32 100644
--- a/arch/cris/kernel/traps.c
+++ b/arch/cris/kernel/traps.c
@@ -17,6 +17,7 @@
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
+#include <arch/system.h>
 
 extern void arch_enable_nmi(void);
 extern void stop_watchdog(void);
diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c
index 9dcac8e..b4760d8 100644
--- a/arch/cris/mm/fault.c
+++ b/arch/cris/mm/fault.c
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/wait.h>
 #include <asm/uaccess.h>
+#include <arch/system.h>
 
 extern int find_fixup_code(struct pt_regs *);
 extern void die_if_kernel(const char *, struct pt_regs *, long);
diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h
index 0d8a7d6..b86329d 100644
--- a/arch/frv/include/asm/atomic.h
+++ b/arch/frv/include/asm/atomic.h
@@ -16,7 +16,7 @@
 
 #include <linux/types.h>
 #include <asm/spr-regs.h>
-#include <asm/system.h>
+#include <asm/cmpxchg.h>
 
 #ifdef CONFIG_SMP
 #error not SMP safe
@@ -181,61 +181,6 @@
 #define atomic64_dec_and_test(v)	(atomic64_dec_return((v)) == 0)
 #define atomic64_inc_and_test(v)	(atomic64_inc_return((v)) == 0)
 
-/*****************************************************************************/
-/*
- * exchange value with memory
- */
-extern uint64_t __xchg_64(uint64_t i, volatile void *v);
-
-#ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
-
-#define xchg(ptr, x)								\
-({										\
-	__typeof__(ptr) __xg_ptr = (ptr);					\
-	__typeof__(*(ptr)) __xg_orig;						\
-										\
-	switch (sizeof(__xg_orig)) {						\
-	case 4:									\
-		asm volatile(							\
-			"swap%I0 %M0,%1"					\
-			: "+m"(*__xg_ptr), "=r"(__xg_orig)			\
-			: "1"(x)						\
-			: "memory"						\
-			);							\
-		break;								\
-										\
-	default:								\
-		__xg_orig = (__typeof__(__xg_orig))0;				\
-		asm volatile("break");						\
-		break;								\
-	}									\
-										\
-	__xg_orig;								\
-})
-
-#else
-
-extern uint32_t __xchg_32(uint32_t i, volatile void *v);
-
-#define xchg(ptr, x)										\
-({												\
-	__typeof__(ptr) __xg_ptr = (ptr);							\
-	__typeof__(*(ptr)) __xg_orig;								\
-												\
-	switch (sizeof(__xg_orig)) {								\
-	case 4: __xg_orig = (__typeof__(*(ptr))) __xchg_32((uint32_t) x, __xg_ptr);	break;	\
-	default:										\
-		__xg_orig = (__typeof__(__xg_orig))0;									\
-		asm volatile("break");								\
-		break;										\
-	}											\
-	__xg_orig;										\
-})
-
-#endif
-
-#define tas(ptr) (xchg((ptr), 1))
-
 #define atomic_cmpxchg(v, old, new)	(cmpxchg(&(v)->counter, old, new))
 #define atomic_xchg(v, new)		(xchg(&(v)->counter, new))
 #define atomic64_cmpxchg(v, old, new)	(__cmpxchg_64(old, new, &(v)->counter))
diff --git a/arch/frv/include/asm/barrier.h b/arch/frv/include/asm/barrier.h
new file mode 100644
index 0000000..06776ad
--- /dev/null
+++ b/arch/frv/include/asm/barrier.h
@@ -0,0 +1,29 @@
+/* FR-V CPU memory barrier definitions
+ *
+ * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.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 _ASM_BARRIER_H
+#define _ASM_BARRIER_H
+
+#define nop()			asm volatile ("nop"::)
+
+#define mb()			asm volatile ("membar" : : :"memory")
+#define rmb()			asm volatile ("membar" : : :"memory")
+#define wmb()			asm volatile ("membar" : : :"memory")
+#define read_barrier_depends()	do { } while (0)
+
+#define smp_mb()			barrier()
+#define smp_rmb()			barrier()
+#define smp_wmb()			barrier()
+#define smp_read_barrier_depends()	do {} while(0)
+#define set_mb(var, value) \
+	do { var = (value); barrier(); } while (0)
+
+#endif /* _ASM_BARRIER_H */
diff --git a/arch/frv/include/asm/bug.h b/arch/frv/include/asm/bug.h
index 2e05450..dd01bcf 100644
--- a/arch/frv/include/asm/bug.h
+++ b/arch/frv/include/asm/bug.h
@@ -51,4 +51,6 @@
 
 #include <asm-generic/bug.h>
 
+extern void die_if_kernel(const char *, ...) __attribute__((format(printf, 1, 2)));
+
 #endif
diff --git a/arch/frv/include/asm/cmpxchg.h b/arch/frv/include/asm/cmpxchg.h
new file mode 100644
index 0000000..5b04dd0
--- /dev/null
+++ b/arch/frv/include/asm/cmpxchg.h
@@ -0,0 +1,172 @@
+/* xchg and cmpxchg operation emulation for FR-V
+ *
+ * For an explanation of how atomic ops work in this arch, see:
+ *   Documentation/frv/atomic-ops.txt
+ *
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.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 _ASM_CMPXCHG_H
+#define _ASM_CMPXCHG_H
+
+#include <linux/types.h>
+
+/*****************************************************************************/
+/*
+ * exchange value with memory
+ */
+extern uint64_t __xchg_64(uint64_t i, volatile void *v);
+
+#ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
+
+#define xchg(ptr, x)								\
+({										\
+	__typeof__(ptr) __xg_ptr = (ptr);					\
+	__typeof__(*(ptr)) __xg_orig;						\
+										\
+	switch (sizeof(__xg_orig)) {						\
+	case 4:									\
+		asm volatile(							\
+			"swap%I0 %M0,%1"					\
+			: "+m"(*__xg_ptr), "=r"(__xg_orig)			\
+			: "1"(x)						\
+			: "memory"						\
+			);							\
+		break;								\
+										\
+	default:								\
+		__xg_orig = (__typeof__(__xg_orig))0;				\
+		asm volatile("break");						\
+		break;								\
+	}									\
+										\
+	__xg_orig;								\
+})
+
+#else
+
+extern uint32_t __xchg_32(uint32_t i, volatile void *v);
+
+#define xchg(ptr, x)										\
+({												\
+	__typeof__(ptr) __xg_ptr = (ptr);							\
+	__typeof__(*(ptr)) __xg_orig;								\
+												\
+	switch (sizeof(__xg_orig)) {								\
+	case 4: __xg_orig = (__typeof__(*(ptr))) __xchg_32((uint32_t) x, __xg_ptr);	break;	\
+	default:										\
+		__xg_orig = (__typeof__(__xg_orig))0;									\
+		asm volatile("break");								\
+		break;										\
+	}											\
+	__xg_orig;										\
+})
+
+#endif
+
+#define tas(ptr) (xchg((ptr), 1))
+
+/*****************************************************************************/
+/*
+ * compare and conditionally exchange value with memory
+ * - if (*ptr == test) then orig = *ptr; *ptr = test;
+ * - if (*ptr != test) then orig = *ptr;
+ */
+extern uint64_t __cmpxchg_64(uint64_t test, uint64_t new, volatile uint64_t *v);
+
+#ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
+
+#define cmpxchg(ptr, test, new)							\
+({										\
+	__typeof__(ptr) __xg_ptr = (ptr);					\
+	__typeof__(*(ptr)) __xg_orig, __xg_tmp;					\
+	__typeof__(*(ptr)) __xg_test = (test);					\
+	__typeof__(*(ptr)) __xg_new = (new);					\
+										\
+	switch (sizeof(__xg_orig)) {						\
+	case 4:									\
+		asm volatile(							\
+			"0:						\n"	\
+			"	orcc		gr0,gr0,gr0,icc3	\n"	\
+			"	ckeq		icc3,cc7		\n"	\
+			"	ld.p		%M0,%1			\n"	\
+			"	orcr		cc7,cc7,cc3		\n"	\
+			"	sub%I4cc	%1,%4,%2,icc0		\n"	\
+			"	bne		icc0,#0,1f		\n"	\
+			"	cst.p		%3,%M0		,cc3,#1	\n"	\
+			"	corcc		gr29,gr29,gr0	,cc3,#1	\n"	\
+			"	beq		icc3,#0,0b		\n"	\
+			"1:						\n"	\
+			: "+U"(*__xg_ptr), "=&r"(__xg_orig), "=&r"(__xg_tmp)	\
+			: "r"(__xg_new), "NPr"(__xg_test)			\
+			: "memory", "cc7", "cc3", "icc3", "icc0"		\
+			);							\
+		break;								\
+										\
+	default:								\
+		__xg_orig = (__typeof__(__xg_orig))0;				\
+		asm volatile("break");						\
+		break;								\
+	}									\
+										\
+	__xg_orig;								\
+})
+
+#else
+
+extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new);
+
+#define cmpxchg(ptr, test, new)							\
+({										\
+	__typeof__(ptr) __xg_ptr = (ptr);					\
+	__typeof__(*(ptr)) __xg_orig;						\
+	__typeof__(*(ptr)) __xg_test = (test);					\
+	__typeof__(*(ptr)) __xg_new = (new);					\
+										\
+	switch (sizeof(__xg_orig)) {						\
+	case 4: __xg_orig = (__force __typeof__(*ptr))				\
+			__cmpxchg_32((__force uint32_t *)__xg_ptr,		\
+					 (__force uint32_t)__xg_test,		\
+					 (__force uint32_t)__xg_new); break;	\
+	default:								\
+		__xg_orig = (__typeof__(__xg_orig))0;				\
+		asm volatile("break");						\
+		break;								\
+	}									\
+										\
+	__xg_orig;								\
+})
+
+#endif
+
+#include <asm-generic/cmpxchg-local.h>
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+				      unsigned long old,
+				      unsigned long new, int size)
+{
+	switch (size) {
+	case 4:
+		return cmpxchg((unsigned long *)ptr, old, new);
+	default:
+		return __cmpxchg_local_generic(ptr, old, new, size);
+	}
+
+	return old;
+}
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)				  	\
+	((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o),	\
+			(unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#endif /* _ASM_CMPXCHG_H */
diff --git a/arch/frv/include/asm/exec.h b/arch/frv/include/asm/exec.h
new file mode 100644
index 0000000..65c9130
--- /dev/null
+++ b/arch/frv/include/asm/exec.h
@@ -0,0 +1,17 @@
+/* FR-V CPU executable handling
+ *
+ * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.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 _ASM_EXEC_H
+#define _ASM_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* _ASM_EXEC_H */
diff --git a/arch/frv/include/asm/posix_types.h b/arch/frv/include/asm/posix_types.h
index a9f1f5b..3f34cb4 100644
--- a/arch/frv/include/asm/posix_types.h
+++ b/arch/frv/include/asm/posix_types.h
@@ -7,56 +7,23 @@
  * assume GCC is being used.
  */
 
-typedef unsigned long	__kernel_ino_t;
 typedef unsigned short	__kernel_mode_t;
+#define __kernel_mode_t __kernel_mode_t
+
 typedef unsigned short	__kernel_nlink_t;
-typedef long		__kernel_off_t;
-typedef int		__kernel_pid_t;
+#define __kernel_nlink_t __kernel_nlink_t
+
 typedef unsigned short	__kernel_ipc_pid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
+
 typedef unsigned short	__kernel_uid_t;
 typedef unsigned short	__kernel_gid_t;
-typedef unsigned int	__kernel_size_t;
-typedef int		__kernel_ssize_t;
-typedef int		__kernel_ptrdiff_t;
-typedef long		__kernel_time_t;
-typedef long		__kernel_suseconds_t;
-typedef long		__kernel_clock_t;
-typedef int		__kernel_timer_t;
-typedef int		__kernel_clockid_t;
-typedef int		__kernel_daddr_t;
-typedef char *		__kernel_caddr_t;
-typedef unsigned short	__kernel_uid16_t;
-typedef unsigned short	__kernel_gid16_t;
-typedef unsigned int	__kernel_uid32_t;
-typedef unsigned int	__kernel_gid32_t;
+#define __kernel_uid_t __kernel_uid_t
 
-typedef unsigned short	__kernel_old_uid_t;
-typedef unsigned short	__kernel_old_gid_t;
 typedef unsigned short	__kernel_old_dev_t;
+#define __kernel_old_dev_t __kernel_old_dev_t
 
-#ifdef __GNUC__
-typedef long long	__kernel_loff_t;
-#endif
-
-typedef struct {
-	int	val[2];
-} __kernel_fsid_t;
-
-#if defined(__KERNEL__)
-
-#undef	__FD_SET
-#define	__FD_SET(d, set)	((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
-
-#undef	__FD_CLR
-#define	__FD_CLR(d, set)	((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
-
-#undef	__FD_ISSET
-#define	__FD_ISSET(d, set)	(!!((set)->fds_bits[__FDELT(d)] & __FDMASK(d)))
-
-#undef	__FD_ZERO
-#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
-
-#endif /* defined(__KERNEL__) */
+#include <asm-generic/posix_types.h>
 
 #endif
 
diff --git a/arch/frv/include/asm/switch_to.h b/arch/frv/include/asm/switch_to.h
new file mode 100644
index 0000000..2cf0f6a
--- /dev/null
+++ b/arch/frv/include/asm/switch_to.h
@@ -0,0 +1,35 @@
+/* FR-V CPU basic task switching
+ *
+ * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.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 _ASM_SWITCH_TO_H
+#define _ASM_SWITCH_TO_H
+
+#include <linux/thread_info.h>
+
+/*
+ * switch_to(prev, next) should switch from task `prev' to `next'
+ * `prev' will never be the same as `next'.
+ * The `mb' is to tell GCC not to cache `current' across this call.
+ */
+extern asmlinkage
+struct task_struct *__switch_to(struct thread_struct *prev_thread,
+				struct thread_struct *next_thread,
+				struct task_struct *prev);
+
+#define switch_to(prev, next, last)					\
+do {									\
+	(prev)->thread.sched_lr =					\
+		(unsigned long) __builtin_return_address(0);		\
+	(last) = __switch_to(&(prev)->thread, &(next)->thread, (prev));	\
+	mb();								\
+} while(0)
+
+#endif /* _ASM_SWITCH_TO_H */
diff --git a/arch/frv/include/asm/system.h b/arch/frv/include/asm/system.h
deleted file mode 100644
index 6c10fd2..0000000
--- a/arch/frv/include/asm/system.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/* system.h: FR-V CPU control definitions
- *
- * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.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 _ASM_SYSTEM_H
-#define _ASM_SYSTEM_H
-
-#include <linux/types.h>
-#include <linux/linkage.h>
-#include <linux/kernel.h>
-
-struct thread_struct;
-
-/*
- * switch_to(prev, next) should switch from task `prev' to `next'
- * `prev' will never be the same as `next'.
- * The `mb' is to tell GCC not to cache `current' across this call.
- */
-extern asmlinkage
-struct task_struct *__switch_to(struct thread_struct *prev_thread,
-				struct thread_struct *next_thread,
-				struct task_struct *prev);
-
-#define switch_to(prev, next, last)					\
-do {									\
-	(prev)->thread.sched_lr =					\
-		(unsigned long) __builtin_return_address(0);		\
-	(last) = __switch_to(&(prev)->thread, &(next)->thread, (prev));	\
-	mb();								\
-} while(0)
-
-/*
- * Force strict CPU ordering.
- */
-#define nop()			asm volatile ("nop"::)
-#define mb()			asm volatile ("membar" : : :"memory")
-#define rmb()			asm volatile ("membar" : : :"memory")
-#define wmb()			asm volatile ("membar" : : :"memory")
-#define read_barrier_depends()	do { } while (0)
-
-#define smp_mb()			barrier()
-#define smp_rmb()			barrier()
-#define smp_wmb()			barrier()
-#define smp_read_barrier_depends()	do {} while(0)
-#define set_mb(var, value) \
-	do { var = (value); barrier(); } while (0)
-
-extern void die_if_kernel(const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void free_initmem(void);
-
-#define arch_align_stack(x) (x)
-
-/*****************************************************************************/
-/*
- * compare and conditionally exchange value with memory
- * - if (*ptr == test) then orig = *ptr; *ptr = test;
- * - if (*ptr != test) then orig = *ptr;
- */
-extern uint64_t __cmpxchg_64(uint64_t test, uint64_t new, volatile uint64_t *v);
-
-#ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
-
-#define cmpxchg(ptr, test, new)							\
-({										\
-	__typeof__(ptr) __xg_ptr = (ptr);					\
-	__typeof__(*(ptr)) __xg_orig, __xg_tmp;					\
-	__typeof__(*(ptr)) __xg_test = (test);					\
-	__typeof__(*(ptr)) __xg_new = (new);					\
-										\
-	switch (sizeof(__xg_orig)) {						\
-	case 4:									\
-		asm volatile(							\
-			"0:						\n"	\
-			"	orcc		gr0,gr0,gr0,icc3	\n"	\
-			"	ckeq		icc3,cc7		\n"	\
-			"	ld.p		%M0,%1			\n"	\
-			"	orcr		cc7,cc7,cc3		\n"	\
-			"	sub%I4cc	%1,%4,%2,icc0		\n"	\
-			"	bne		icc0,#0,1f		\n"	\
-			"	cst.p		%3,%M0		,cc3,#1	\n"	\
-			"	corcc		gr29,gr29,gr0	,cc3,#1	\n"	\
-			"	beq		icc3,#0,0b		\n"	\
-			"1:						\n"	\
-			: "+U"(*__xg_ptr), "=&r"(__xg_orig), "=&r"(__xg_tmp)	\
-			: "r"(__xg_new), "NPr"(__xg_test)			\
-			: "memory", "cc7", "cc3", "icc3", "icc0"		\
-			);							\
-		break;								\
-										\
-	default:								\
-		__xg_orig = (__typeof__(__xg_orig))0;				\
-		asm volatile("break");						\
-		break;								\
-	}									\
-										\
-	__xg_orig;								\
-})
-
-#else
-
-extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new);
-
-#define cmpxchg(ptr, test, new)							\
-({										\
-	__typeof__(ptr) __xg_ptr = (ptr);					\
-	__typeof__(*(ptr)) __xg_orig;						\
-	__typeof__(*(ptr)) __xg_test = (test);					\
-	__typeof__(*(ptr)) __xg_new = (new);					\
-										\
-	switch (sizeof(__xg_orig)) {						\
-	case 4: __xg_orig = (__force __typeof__(*ptr))				\
-			__cmpxchg_32((__force uint32_t *)__xg_ptr,		\
-					 (__force uint32_t)__xg_test,		\
-					 (__force uint32_t)__xg_new); break;	\
-	default:								\
-		__xg_orig = (__typeof__(__xg_orig))0;				\
-		asm volatile("break");						\
-		break;								\
-	}									\
-										\
-	__xg_orig;								\
-})
-
-#endif
-
-#include <asm-generic/cmpxchg-local.h>
-
-static inline unsigned long __cmpxchg_local(volatile void *ptr,
-				      unsigned long old,
-				      unsigned long new, int size)
-{
-	switch (size) {
-	case 4:
-		return cmpxchg((unsigned long *)ptr, old, new);
-	default:
-		return __cmpxchg_local_generic(ptr, old, new, size);
-	}
-
-	return old;
-}
-
-/*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
- */
-#define cmpxchg_local(ptr, o, n)				  	\
-	((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o),	\
-			(unsigned long)(n), sizeof(*(ptr))))
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-
-#endif /* _ASM_SYSTEM_H */
diff --git a/arch/frv/kernel/debug-stub.c b/arch/frv/kernel/debug-stub.c
index 2845139..a0228f7 100644
--- a/arch/frv/kernel/debug-stub.c
+++ b/arch/frv/kernel/debug-stub.c
@@ -17,7 +17,6 @@
 #include <linux/serial_reg.h>
 #include <linux/start_kernel.h>
 
-#include <asm/system.h>
 #include <asm/serial-regs.h>
 #include <asm/timer-regs.h>
 #include <asm/irc-regs.h>
diff --git a/arch/frv/kernel/gdb-io.c b/arch/frv/kernel/gdb-io.c
index 2ca641d..0707d35 100644
--- a/arch/frv/kernel/gdb-io.c
+++ b/arch/frv/kernel/gdb-io.c
@@ -19,7 +19,6 @@
 #include <linux/serial_reg.h>
 
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/irc-regs.h>
 #include <asm/timer-regs.h>
 #include <asm/gdb-stub.h>
diff --git a/arch/frv/kernel/gdb-stub.c b/arch/frv/kernel/gdb-stub.c
index a6d5381..bbe78b0 100644
--- a/arch/frv/kernel/gdb-stub.c
+++ b/arch/frv/kernel/gdb-stub.c
@@ -126,7 +126,6 @@
 
 #include <asm/asm-offsets.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/gdb-stub.h>
 
 #define LEDS(x) do { /* *(u32*)0xe1200004 = ~(x); mb(); */ } while(0)
diff --git a/arch/frv/kernel/irq-mb93091.c b/arch/frv/kernel/irq-mb93091.c
index 9afc2ea..2cc327a 100644
--- a/arch/frv/kernel/irq-mb93091.c
+++ b/arch/frv/kernel/irq-mb93091.c
@@ -20,7 +20,6 @@
 #include <linux/bitops.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/delay.h>
 #include <asm/irq.h>
 #include <asm/irc-regs.h>
diff --git a/arch/frv/kernel/irq-mb93093.c b/arch/frv/kernel/irq-mb93093.c
index 4d4ad09..95e4eb4 100644
--- a/arch/frv/kernel/irq-mb93093.c
+++ b/arch/frv/kernel/irq-mb93093.c
@@ -20,7 +20,6 @@
 #include <linux/bitops.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/delay.h>
 #include <asm/irq.h>
 #include <asm/irc-regs.h>
diff --git a/arch/frv/kernel/irq-mb93493.c b/arch/frv/kernel/irq-mb93493.c
index 4d034c7..ba648da 100644
--- a/arch/frv/kernel/irq-mb93493.c
+++ b/arch/frv/kernel/irq-mb93493.c
@@ -20,7 +20,6 @@
 #include <linux/bitops.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/delay.h>
 #include <asm/irq.h>
 #include <asm/irc-regs.h>
diff --git a/arch/frv/kernel/irq.c b/arch/frv/kernel/irq.c
index 3facbc2..2239346 100644
--- a/arch/frv/kernel/irq.c
+++ b/arch/frv/kernel/irq.c
@@ -28,7 +28,6 @@
 #include <linux/atomic.h>
 #include <asm/io.h>
 #include <asm/smp.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 #include <asm/delay.h>
diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c
index 29cc497..d4de48b 100644
--- a/arch/frv/kernel/process.c
+++ b/arch/frv/kernel/process.c
@@ -28,7 +28,6 @@
 
 #include <asm/asm-offsets.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/setup.h>
 #include <asm/pgtable.h>
 #include <asm/tlb.h>
diff --git a/arch/frv/kernel/ptrace.c b/arch/frv/kernel/ptrace.c
index 9d68f7f..3987ff8 100644
--- a/arch/frv/kernel/ptrace.c
+++ b/arch/frv/kernel/ptrace.c
@@ -26,7 +26,6 @@
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/unistd.h>
 
diff --git a/arch/frv/kernel/traps.c b/arch/frv/kernel/traps.c
index 1d2dfe6..5cfd142 100644
--- a/arch/frv/kernel/traps.c
+++ b/arch/frv/kernel/traps.c
@@ -23,7 +23,6 @@
 #include <asm/asm-offsets.h>
 #include <asm/setup.h>
 #include <asm/fpu.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/siginfo.h>
diff --git a/arch/frv/mb93090-mb00/pci-dma.c b/arch/frv/mb93090-mb00/pci-dma.c
index 41098a3..4f8d8bc 100644
--- a/arch/frv/mb93090-mb00/pci-dma.c
+++ b/arch/frv/mb93090-mb00/pci-dma.c
@@ -13,6 +13,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/list.h>
 #include <linux/pci.h>
+#include <linux/export.h>
 #include <linux/highmem.h>
 #include <linux/scatterlist.h>
 #include <asm/io.h>
diff --git a/arch/frv/mm/fault.c b/arch/frv/mm/fault.c
index a325d57..331c1e2 100644
--- a/arch/frv/mm/fault.c
+++ b/arch/frv/mm/fault.c
@@ -20,7 +20,6 @@
 #include <linux/ptrace.h>
 #include <linux/hardirq.h>
 
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/gdb-stub.h>
diff --git a/arch/frv/mm/init.c b/arch/frv/mm/init.c
index fbe5f0d..a19effc 100644
--- a/arch/frv/mm/init.c
+++ b/arch/frv/mm/init.c
@@ -33,7 +33,6 @@
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/virtconvert.h>
 #include <asm/sections.h>
diff --git a/arch/frv/mm/kmap.c b/arch/frv/mm/kmap.c
index fb78be3..e9217e6 100644
--- a/arch/frv/mm/kmap.c
+++ b/arch/frv/mm/kmap.c
@@ -21,7 +21,6 @@
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #undef DEBUG
 
diff --git a/arch/h8300/include/asm/atomic.h b/arch/h8300/include/asm/atomic.h
index f5a38c1..40901e3 100644
--- a/arch/h8300/include/asm/atomic.h
+++ b/arch/h8300/include/asm/atomic.h
@@ -2,6 +2,7 @@
 #define __ARCH_H8300_ATOMIC__
 
 #include <linux/types.h>
+#include <asm/cmpxchg.h>
 
 /*
  * Atomic operations that C can't guarantee us.  Useful for
@@ -13,7 +14,6 @@
 #define atomic_read(v)		(*(volatile int *)&(v)->counter)
 #define atomic_set(v, i)	(((v)->counter) = i)
 
-#include <asm/system.h>
 #include <linux/kernel.h>
 
 static __inline__ int atomic_add_return(int i, atomic_t *v)
@@ -102,8 +102,6 @@
 	return ret;
 }
 
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
-
 static inline int __atomic_add_unless(atomic_t *v, int a, int u)
 {
 	int ret;
diff --git a/arch/h8300/include/asm/barrier.h b/arch/h8300/include/asm/barrier.h
new file mode 100644
index 0000000..c7283c3
--- /dev/null
+++ b/arch/h8300/include/asm/barrier.h
@@ -0,0 +1,27 @@
+#ifndef _H8300_BARRIER_H
+#define _H8300_BARRIER_H
+
+#define nop()  asm volatile ("nop"::)
+
+/*
+ * Force strict CPU ordering.
+ * Not really required on H8...
+ */
+#define mb()   asm volatile (""   : : :"memory")
+#define rmb()  asm volatile (""   : : :"memory")
+#define wmb()  asm volatile (""   : : :"memory")
+#define set_mb(var, value) do { xchg(&var, value); } while (0)
+
+#ifdef CONFIG_SMP
+#define smp_mb()	mb()
+#define smp_rmb()	rmb()
+#define smp_wmb()	wmb()
+#define smp_read_barrier_depends()	read_barrier_depends()
+#else
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+#define smp_read_barrier_depends()	do { } while(0)
+#endif
+
+#endif /* _H8300_BARRIER_H */
diff --git a/arch/h8300/include/asm/bitops.h b/arch/h8300/include/asm/bitops.h
index e856c1b..eb34e0c 100644
--- a/arch/h8300/include/asm/bitops.h
+++ b/arch/h8300/include/asm/bitops.h
@@ -7,7 +7,6 @@
  */
 
 #include <linux/compiler.h>
-#include <asm/system.h>
 
 #ifdef __KERNEL__
 
diff --git a/arch/h8300/include/asm/bug.h b/arch/h8300/include/asm/bug.h
index 887c197..1e1be81 100644
--- a/arch/h8300/include/asm/bug.h
+++ b/arch/h8300/include/asm/bug.h
@@ -5,4 +5,8 @@
 #define is_valid_bugaddr(addr) (1)
 
 #include <asm-generic/bug.h>
+
+struct pt_regs;
+extern void die(const char *str, struct pt_regs *fp, unsigned long err);
+
 #endif
diff --git a/arch/h8300/include/asm/cmpxchg.h b/arch/h8300/include/asm/cmpxchg.h
new file mode 100644
index 0000000..cdb203e
--- /dev/null
+++ b/arch/h8300/include/asm/cmpxchg.h
@@ -0,0 +1,60 @@
+#ifndef __ARCH_H8300_CMPXCHG__
+#define __ARCH_H8300_CMPXCHG__
+
+#include <linux/irqflags.h>
+
+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+struct __xchg_dummy { unsigned long a[100]; };
+#define __xg(x) ((volatile struct __xchg_dummy *)(x))
+
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+{
+  unsigned long tmp, flags;
+
+  local_irq_save(flags);
+
+  switch (size) {
+  case 1:
+    __asm__ __volatile__
+    ("mov.b %2,%0\n\t"
+     "mov.b %1,%2"
+    : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory");
+    break;
+  case 2:
+    __asm__ __volatile__
+    ("mov.w %2,%0\n\t"
+     "mov.w %1,%2"
+    : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory");
+    break;
+  case 4:
+    __asm__ __volatile__
+    ("mov.l %2,%0\n\t"
+     "mov.l %1,%2"
+    : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory");
+    break;
+  default:
+    tmp = 0;	  
+  }
+  local_irq_restore(flags);
+  return tmp;
+}
+
+#include <asm-generic/cmpxchg-local.h>
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)				  	       \
+	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+			(unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#ifndef CONFIG_SMP
+#include <asm-generic/cmpxchg.h>
+#endif
+
+#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+
+#endif /* __ARCH_H8300_CMPXCHG__ */
diff --git a/arch/h8300/include/asm/exec.h b/arch/h8300/include/asm/exec.h
new file mode 100644
index 0000000..c01c45c
--- /dev/null
+++ b/arch/h8300/include/asm/exec.h
@@ -0,0 +1,6 @@
+#ifndef _H8300_EXEC_H
+#define _H8300_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* _H8300_EXEC_H */
diff --git a/arch/h8300/include/asm/posix_types.h b/arch/h8300/include/asm/posix_types.h
index 6f833a1..bc4c34e 100644
--- a/arch/h8300/include/asm/posix_types.h
+++ b/arch/h8300/include/asm/posix_types.h
@@ -7,54 +7,23 @@
  * assume GCC is being used.
  */
 
-typedef unsigned long	__kernel_ino_t;
 typedef unsigned short	__kernel_mode_t;
+#define __kernel_mode_t __kernel_mode_t
+
 typedef unsigned short	__kernel_nlink_t;
-typedef long		__kernel_off_t;
-typedef int		__kernel_pid_t;
+#define __kernel_nlink_t __kernel_nlink_t
+
 typedef unsigned short	__kernel_ipc_pid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
+
 typedef unsigned short	__kernel_uid_t;
 typedef unsigned short	__kernel_gid_t;
-typedef unsigned int	__kernel_size_t;
-typedef int		__kernel_ssize_t;
-typedef int		__kernel_ptrdiff_t;
-typedef long		__kernel_time_t;
-typedef long		__kernel_suseconds_t;
-typedef long		__kernel_clock_t;
-typedef int		__kernel_timer_t;
-typedef int		__kernel_clockid_t;
-typedef int		__kernel_daddr_t;
-typedef char *		__kernel_caddr_t;
-typedef unsigned short	__kernel_uid16_t;
-typedef unsigned short	__kernel_gid16_t;
-typedef unsigned int	__kernel_uid32_t;
-typedef unsigned int	__kernel_gid32_t;
+#define __kernel_uid_t __kernel_uid_t
 
 typedef unsigned short	__kernel_old_uid_t;
 typedef unsigned short	__kernel_old_gid_t;
+#define __kernel_old_uid_t __kernel_old_uid_t
 
-#ifdef __GNUC__
-typedef long long	__kernel_loff_t;
-#endif
-
-typedef struct {
-	int	val[2];
-} __kernel_fsid_t;
-
-#if defined(__KERNEL__)
-
-#undef	__FD_SET
-#define	__FD_SET(d, set)	((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
-
-#undef	__FD_CLR
-#define	__FD_CLR(d, set)	((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
-
-#undef	__FD_ISSET
-#define	__FD_ISSET(d, set)	(!!((set)->fds_bits[__FDELT(d)] & __FDMASK(d)))
-
-#undef	__FD_ZERO
-#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
-
-#endif /* defined(__KERNEL__) */
+#include <asm-generic/posix_types.h>
 
 #endif
diff --git a/arch/h8300/include/asm/processor.h b/arch/h8300/include/asm/processor.h
index e834b60..61fabf1 100644
--- a/arch/h8300/include/asm/processor.h
+++ b/arch/h8300/include/asm/processor.h
@@ -135,4 +135,9 @@
 
 #define cpu_relax()    barrier()
 
+#define HARD_RESET_NOW() ({		\
+        local_irq_disable();		\
+        asm("jmp @@0");			\
+})
+
 #endif
diff --git a/arch/h8300/include/asm/switch_to.h b/arch/h8300/include/asm/switch_to.h
new file mode 100644
index 0000000..cdd8731
--- /dev/null
+++ b/arch/h8300/include/asm/switch_to.h
@@ -0,0 +1,50 @@
+#ifndef _H8300_SWITCH_TO_H
+#define _H8300_SWITCH_TO_H
+
+/*
+ * switch_to(n) should switch tasks to task ptr, first checking that
+ * ptr isn't the current task, in which case it does nothing.  This
+ * also clears the TS-flag if the task we switched to has used the
+ * math co-processor latest.
+ */
+/*
+ * switch_to() saves the extra registers, that are not saved
+ * automatically by SAVE_SWITCH_STACK in resume(), ie. d0-d5 and
+ * a0-a1. Some of these are used by schedule() and its predecessors
+ * and so we might get see unexpected behaviors when a task returns
+ * with unexpected register values.
+ *
+ * syscall stores these registers itself and none of them are used
+ * by syscall after the function in the syscall has been called.
+ *
+ * Beware that resume now expects *next to be in d1 and the offset of
+ * tss to be in a1. This saves a few instructions as we no longer have
+ * to push them onto the stack and read them back right after.
+ *
+ * 02/17/96 - Jes Sorensen (jds@kom.auc.dk)
+ *
+ * Changed 96/09/19 by Andreas Schwab
+ * pass prev in a0, next in a1, offset of tss in d1, and whether
+ * the mm structures are shared in d2 (to avoid atc flushing).
+ *
+ * H8/300 Porting 2002/09/04 Yoshinori Sato
+ */
+
+asmlinkage void resume(void);
+#define switch_to(prev,next,last) {                         \
+  void *_last;						    \
+  __asm__ __volatile__(					    \
+  			"mov.l	%1, er0\n\t"		    \
+			"mov.l	%2, er1\n\t"		    \
+                        "mov.l  %3, er2\n\t"                \
+			"jsr @_resume\n\t"                  \
+                        "mov.l  er2,%0\n\t"                 \
+		       : "=r" (_last)			    \
+		       : "r" (&(prev->thread)),		    \
+			 "r" (&(next->thread)),		    \
+                         "g" (prev)                         \
+		       : "cc", "er0", "er1", "er2", "er3"); \
+  (last) = _last; 					    \
+}
+
+#endif /* _H8300_SWITCH_TO_H */
diff --git a/arch/h8300/include/asm/system.h b/arch/h8300/include/asm/system.h
deleted file mode 100644
index 2c2382e..0000000
--- a/arch/h8300/include/asm/system.h
+++ /dev/null
@@ -1,140 +0,0 @@
-#ifndef _H8300_SYSTEM_H
-#define _H8300_SYSTEM_H
-
-#include <linux/linkage.h>
-#include <linux/irqflags.h>
-
-struct pt_regs;
-
-/*
- * switch_to(n) should switch tasks to task ptr, first checking that
- * ptr isn't the current task, in which case it does nothing.  This
- * also clears the TS-flag if the task we switched to has used the
- * math co-processor latest.
- */
-/*
- * switch_to() saves the extra registers, that are not saved
- * automatically by SAVE_SWITCH_STACK in resume(), ie. d0-d5 and
- * a0-a1. Some of these are used by schedule() and its predecessors
- * and so we might get see unexpected behaviors when a task returns
- * with unexpected register values.
- *
- * syscall stores these registers itself and none of them are used
- * by syscall after the function in the syscall has been called.
- *
- * Beware that resume now expects *next to be in d1 and the offset of
- * tss to be in a1. This saves a few instructions as we no longer have
- * to push them onto the stack and read them back right after.
- *
- * 02/17/96 - Jes Sorensen (jds@kom.auc.dk)
- *
- * Changed 96/09/19 by Andreas Schwab
- * pass prev in a0, next in a1, offset of tss in d1, and whether
- * the mm structures are shared in d2 (to avoid atc flushing).
- *
- * H8/300 Porting 2002/09/04 Yoshinori Sato
- */
-
-asmlinkage void resume(void);
-#define switch_to(prev,next,last) {                         \
-  void *_last;						    \
-  __asm__ __volatile__(					    \
-  			"mov.l	%1, er0\n\t"		    \
-			"mov.l	%2, er1\n\t"		    \
-                        "mov.l  %3, er2\n\t"                \
-			"jsr @_resume\n\t"                  \
-                        "mov.l  er2,%0\n\t"                 \
-		       : "=r" (_last)			    \
-		       : "r" (&(prev->thread)),		    \
-			 "r" (&(next->thread)),		    \
-                         "g" (prev)                         \
-		       : "cc", "er0", "er1", "er2", "er3"); \
-  (last) = _last; 					    \
-}
-
-#define iret() __asm__ __volatile__ ("rte": : :"memory", "sp", "cc")
-
-/*
- * Force strict CPU ordering.
- * Not really required on H8...
- */
-#define nop()  asm volatile ("nop"::)
-#define mb()   asm volatile (""   : : :"memory")
-#define rmb()  asm volatile (""   : : :"memory")
-#define wmb()  asm volatile (""   : : :"memory")
-#define set_mb(var, value) do { xchg(&var, value); } while (0)
-
-#ifdef CONFIG_SMP
-#define smp_mb()	mb()
-#define smp_rmb()	rmb()
-#define smp_wmb()	wmb()
-#define smp_read_barrier_depends()	read_barrier_depends()
-#else
-#define smp_mb()	barrier()
-#define smp_rmb()	barrier()
-#define smp_wmb()	barrier()
-#define smp_read_barrier_depends()	do { } while(0)
-#endif
-
-#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-
-struct __xchg_dummy { unsigned long a[100]; };
-#define __xg(x) ((volatile struct __xchg_dummy *)(x))
-
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
-{
-  unsigned long tmp, flags;
-
-  local_irq_save(flags);
-
-  switch (size) {
-  case 1:
-    __asm__ __volatile__
-    ("mov.b %2,%0\n\t"
-     "mov.b %1,%2"
-    : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory");
-    break;
-  case 2:
-    __asm__ __volatile__
-    ("mov.w %2,%0\n\t"
-     "mov.w %1,%2"
-    : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory");
-    break;
-  case 4:
-    __asm__ __volatile__
-    ("mov.l %2,%0\n\t"
-     "mov.l %1,%2"
-    : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)) : "memory");
-    break;
-  default:
-    tmp = 0;	  
-  }
-  local_irq_restore(flags);
-  return tmp;
-}
-
-#define HARD_RESET_NOW() ({		\
-        local_irq_disable();		\
-        asm("jmp @@0");			\
-})
-
-#include <asm-generic/cmpxchg-local.h>
-
-/*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
- */
-#define cmpxchg_local(ptr, o, n)				  	       \
-	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
-			(unsigned long)(n), sizeof(*(ptr))))
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-
-#ifndef CONFIG_SMP
-#include <asm-generic/cmpxchg.h>
-#endif
-
-#define arch_align_stack(x) (x)
-
-extern void die(const char *str, struct pt_regs *fp, unsigned long err);
-
-#endif /* _H8300_SYSTEM_H */
diff --git a/arch/h8300/kernel/irq.c b/arch/h8300/kernel/irq.c
index 1f67fed..2fa8ac7 100644
--- a/arch/h8300/kernel/irq.c
+++ b/arch/h8300/kernel/irq.c
@@ -16,7 +16,6 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 
-#include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/io.h>
 #include <asm/setup.h>
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c
index 1a173b3..0e9c315 100644
--- a/arch/h8300/kernel/process.c
+++ b/arch/h8300/kernel/process.c
@@ -38,7 +38,6 @@
 #include <linux/slab.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/setup.h>
 #include <asm/pgtable.h>
diff --git a/arch/h8300/kernel/ptrace.c b/arch/h8300/kernel/ptrace.c
index 497fa89..748cf65 100644
--- a/arch/h8300/kernel/ptrace.c
+++ b/arch/h8300/kernel/ptrace.c
@@ -27,7 +27,6 @@
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/signal.h>
 
diff --git a/arch/h8300/kernel/traps.c b/arch/h8300/kernel/traps.c
index dfa05bd..7833aa3 100644
--- a/arch/h8300/kernel/traps.c
+++ b/arch/h8300/kernel/traps.c
@@ -22,7 +22,6 @@
 #include <linux/module.h>
 #include <linux/bug.h>
 
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
 #include <asm/page.h>
diff --git a/arch/h8300/mm/fault.c b/arch/h8300/mm/fault.c
index 1d092ab..4725359 100644
--- a/arch/h8300/mm/fault.c
+++ b/arch/h8300/mm/fault.c
@@ -17,7 +17,6 @@
 #include <linux/kernel.h>
 #include <linux/ptrace.h>
 
-#include <asm/system.h>
 #include <asm/pgtable.h>
 
 /*
diff --git a/arch/h8300/mm/init.c b/arch/h8300/mm/init.c
index 7cc3380..973369c 100644
--- a/arch/h8300/mm/init.c
+++ b/arch/h8300/mm/init.c
@@ -36,7 +36,6 @@
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 
 #undef DEBUG
 
diff --git a/arch/h8300/mm/kmap.c b/arch/h8300/mm/kmap.c
index 944a502..f79edcd 100644
--- a/arch/h8300/mm/kmap.c
+++ b/arch/h8300/mm/kmap.c
@@ -19,7 +19,6 @@
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #undef DEBUG
 
diff --git a/arch/h8300/mm/memory.c b/arch/h8300/mm/memory.c
index 5552ddf..06e3646 100644
--- a/arch/h8300/mm/memory.c
+++ b/arch/h8300/mm/memory.c
@@ -26,7 +26,6 @@
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/io.h>
 
diff --git a/arch/hexagon/include/asm/atomic.h b/arch/hexagon/include/asm/atomic.h
index e220f90..3e25804 100644
--- a/arch/hexagon/include/asm/atomic.h
+++ b/arch/hexagon/include/asm/atomic.h
@@ -23,6 +23,7 @@
 #define _ASM_ATOMIC_H
 
 #include <linux/types.h>
+#include <asm/cmpxchg.h>
 
 #define ATOMIC_INIT(i)		{ (i) }
 #define atomic_set(v, i)	((v)->counter = (i))
diff --git a/arch/hexagon/include/asm/barrier.h b/arch/hexagon/include/asm/barrier.h
new file mode 100644
index 0000000..a4ed6e2
--- /dev/null
+++ b/arch/hexagon/include/asm/barrier.h
@@ -0,0 +1,41 @@
+/*
+ * Memory barrier definitions for the Hexagon architecture
+ *
+ * Copyright (c) 2010-2011, Code Aurora Forum. 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.
+ *
+ * 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 _ASM_BARRIER_H
+#define _ASM_BARRIER_H
+
+#define rmb()				barrier()
+#define read_barrier_depends()		barrier()
+#define wmb()				barrier()
+#define mb()				barrier()
+#define smp_rmb()			barrier()
+#define smp_read_barrier_depends()	barrier()
+#define smp_wmb()			barrier()
+#define smp_mb()			barrier()
+#define smp_mb__before_atomic_dec()	barrier()
+#define smp_mb__after_atomic_dec()	barrier()
+#define smp_mb__before_atomic_inc()	barrier()
+#define smp_mb__after_atomic_inc()	barrier()
+
+/*  Set a value and use a memory barrier.  Used by the scheduler somewhere.  */
+#define set_mb(var, value) \
+	do { var = value; mb(); } while (0)
+
+#endif /* _ASM_BARRIER_H */
diff --git a/arch/hexagon/include/asm/bitops.h b/arch/hexagon/include/asm/bitops.h
index d23461e..4caa649 100644
--- a/arch/hexagon/include/asm/bitops.h
+++ b/arch/hexagon/include/asm/bitops.h
@@ -24,7 +24,6 @@
 
 #include <linux/compiler.h>
 #include <asm/byteorder.h>
-#include <asm/system.h>
 #include <asm/atomic.h>
 
 #ifdef __KERNEL__
diff --git a/arch/hexagon/include/asm/cmpxchg.h b/arch/hexagon/include/asm/cmpxchg.h
new file mode 100644
index 0000000..c5f9527
--- /dev/null
+++ b/arch/hexagon/include/asm/cmpxchg.h
@@ -0,0 +1,90 @@
+/*
+ * xchg/cmpxchg operations for the Hexagon architecture
+ *
+ * Copyright (c) 2010-2011, Code Aurora Forum. 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.
+ *
+ * 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 _ASM_CMPXCHG_H
+#define _ASM_CMPXCHG_H
+
+/*
+ * __xchg - atomically exchange a register and a memory location
+ * @x: value to swap
+ * @ptr: pointer to memory
+ * @size:  size of the value
+ *
+ * Only 4 bytes supported currently.
+ *
+ * Note:  there was an errata for V2 about .new's and memw_locked.
+ *
+ */
+static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
+				   int size)
+{
+	unsigned long retval;
+
+	/*  Can't seem to use printk or panic here, so just stop  */
+	if (size != 4) do { asm volatile("brkpt;\n"); } while (1);
+
+	__asm__ __volatile__ (
+	"1:	%0 = memw_locked(%1);\n"    /*  load into retval */
+	"	memw_locked(%1,P0) = %2;\n" /*  store into memory */
+	"	if !P0 jump 1b;\n"
+	: "=&r" (retval)
+	: "r" (ptr), "r" (x)
+	: "memory", "p0"
+	);
+	return retval;
+}
+
+/*
+ * Atomically swap the contents of a register with memory.  Should be atomic
+ * between multiple CPU's and within interrupts on the same CPU.
+ */
+#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \
+	sizeof(*(ptr))))
+
+/*
+ *  see rt-mutex-design.txt; cmpxchg supposedly checks if *ptr == A and swaps.
+ *  looks just like atomic_cmpxchg on our arch currently with a bunch of
+ *  variable casting.
+ */
+#define __HAVE_ARCH_CMPXCHG 1
+
+#define cmpxchg(ptr, old, new)					\
+({								\
+	__typeof__(ptr) __ptr = (ptr);				\
+	__typeof__(*(ptr)) __old = (old);			\
+	__typeof__(*(ptr)) __new = (new);			\
+	__typeof__(*(ptr)) __oldval = 0;			\
+								\
+	asm volatile(						\
+		"1:	%0 = memw_locked(%1);\n"		\
+		"	{ P0 = cmp.eq(%0,%2);\n"		\
+		"	  if (!P0.new) jump:nt 2f; }\n"		\
+		"	memw_locked(%1,p0) = %3;\n"		\
+		"	if (!P0) jump 1b;\n"			\
+		"2:\n"						\
+		: "=&r" (__oldval)				\
+		: "r" (__ptr), "r" (__old), "r" (__new)		\
+		: "memory", "p0"				\
+	);							\
+	__oldval;						\
+})
+
+#endif /* _ASM_CMPXCHG_H */
diff --git a/arch/hexagon/include/asm/dma-mapping.h b/arch/hexagon/include/asm/dma-mapping.h
index 448b224..233ed3d 100644
--- a/arch/hexagon/include/asm/dma-mapping.h
+++ b/arch/hexagon/include/asm/dma-mapping.h
@@ -71,29 +71,35 @@
 	return (dma_addr == bad_dma_address);
 }
 
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-				       dma_addr_t *dma_handle, gfp_t flag)
+#define dma_alloc_coherent(d,s,h,f)	dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+				    dma_addr_t *dma_handle, gfp_t flag,
+				    struct dma_attrs *attrs)
 {
 	void *ret;
 	struct dma_map_ops *ops = get_dma_ops(dev);
 
 	BUG_ON(!dma_ops);
 
-	ret = ops->alloc_coherent(dev, size, dma_handle, flag);
+	ret = ops->alloc(dev, size, dma_handle, flag, attrs);
 
 	debug_dma_alloc_coherent(dev, size, *dma_handle, ret);
 
 	return ret;
 }
 
-static inline void dma_free_coherent(struct device *dev, size_t size,
-				     void *cpu_addr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+				  void *cpu_addr, dma_addr_t dma_handle,
+				  struct dma_attrs *attrs)
 {
 	struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
 	BUG_ON(!dma_ops);
 
-	dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
+	dma_ops->free(dev, size, cpu_addr, dma_handle, attrs);
 
 	debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
 }
diff --git a/arch/hexagon/include/asm/exec.h b/arch/hexagon/include/asm/exec.h
new file mode 100644
index 0000000..350e6d4
--- /dev/null
+++ b/arch/hexagon/include/asm/exec.h
@@ -0,0 +1,28 @@
+/*
+ * Process execution related definitions for the Hexagon architecture
+ *
+ * Copyright (c) 2010-2011, Code Aurora Forum. 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.
+ *
+ * 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 _ASM_EXEC_H
+#define _ASM_EXEC_H
+
+/*  Should probably shoot for an 8-byte aligned stack pointer  */
+#define STACK_MASK (~7)
+#define arch_align_stack(x) (x & STACK_MASK)
+
+#endif /* _ASM_EXEC_H */
diff --git a/arch/hexagon/include/asm/switch_to.h b/arch/hexagon/include/asm/switch_to.h
new file mode 100644
index 0000000..28ca0df
--- /dev/null
+++ b/arch/hexagon/include/asm/switch_to.h
@@ -0,0 +1,34 @@
+/*
+ * Task switching definitions for the Hexagon architecture
+ *
+ * Copyright (c) 2010-2011, Code Aurora Forum. 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.
+ *
+ * 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 _ASM_SWITCH_TO_H
+#define _ASM_SWITCH_TO_H
+
+struct thread_struct;
+
+extern struct task_struct *__switch_to(struct task_struct *,
+	struct task_struct *,
+	struct task_struct *);
+
+#define switch_to(p, n, r) do {\
+	r = __switch_to((p), (n), (r));\
+} while (0)
+
+#endif /* _ASM_SWITCH_TO_H */
diff --git a/arch/hexagon/include/asm/system.h b/arch/hexagon/include/asm/system.h
deleted file mode 100644
index 323ed1d..0000000
--- a/arch/hexagon/include/asm/system.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * System level definitions for the Hexagon architecture
- *
- * Copyright (c) 2010-2011, Code Aurora Forum. 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.
- *
- * 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 _ASM_SYSTEM_H
-#define _ASM_SYSTEM_H
-
-#include <linux/linkage.h>
-#include <linux/irqflags.h>
-#include <asm/atomic.h>
-#include <asm/hexagon_vm.h>
-
-struct thread_struct;
-
-extern struct task_struct *__switch_to(struct task_struct *,
-	struct task_struct *,
-	struct task_struct *);
-
-#define switch_to(p, n, r) do {\
-	r = __switch_to((p), (n), (r));\
-} while (0)
-
-
-#define rmb()				barrier()
-#define read_barrier_depends()		barrier()
-#define wmb()				barrier()
-#define mb()				barrier()
-#define smp_rmb()			barrier()
-#define smp_read_barrier_depends()	barrier()
-#define smp_wmb()			barrier()
-#define smp_mb()			barrier()
-#define smp_mb__before_atomic_dec()	barrier()
-#define smp_mb__after_atomic_dec()	barrier()
-#define smp_mb__before_atomic_inc()	barrier()
-#define smp_mb__after_atomic_inc()	barrier()
-
-/*
- * __xchg - atomically exchange a register and a memory location
- * @x: value to swap
- * @ptr: pointer to memory
- * @size:  size of the value
- *
- * Only 4 bytes supported currently.
- *
- * Note:  there was an errata for V2 about .new's and memw_locked.
- *
- */
-static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
-				   int size)
-{
-	unsigned long retval;
-
-	/*  Can't seem to use printk or panic here, so just stop  */
-	if (size != 4) do { asm volatile("brkpt;\n"); } while (1);
-
-	__asm__ __volatile__ (
-	"1:	%0 = memw_locked(%1);\n"    /*  load into retval */
-	"	memw_locked(%1,P0) = %2;\n" /*  store into memory */
-	"	if !P0 jump 1b;\n"
-	: "=&r" (retval)
-	: "r" (ptr), "r" (x)
-	: "memory", "p0"
-	);
-	return retval;
-}
-
-/*
- * Atomically swap the contents of a register with memory.  Should be atomic
- * between multiple CPU's and within interrupts on the same CPU.
- */
-#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \
-	sizeof(*(ptr))))
-
-/*  Set a value and use a memory barrier.  Used by the scheduler somewhere.  */
-#define set_mb(var, value) \
-	do { var = value; mb(); } while (0)
-
-/*
- *  see rt-mutex-design.txt; cmpxchg supposedly checks if *ptr == A and swaps.
- *  looks just like atomic_cmpxchg on our arch currently with a bunch of
- *  variable casting.
- */
-#define __HAVE_ARCH_CMPXCHG 1
-
-#define cmpxchg(ptr, old, new)					\
-({								\
-	__typeof__(ptr) __ptr = (ptr);				\
-	__typeof__(*(ptr)) __old = (old);			\
-	__typeof__(*(ptr)) __new = (new);			\
-	__typeof__(*(ptr)) __oldval = 0;			\
-								\
-	asm volatile(						\
-		"1:	%0 = memw_locked(%1);\n"		\
-		"	{ P0 = cmp.eq(%0,%2);\n"		\
-		"	  if (!P0.new) jump:nt 2f; }\n"		\
-		"	memw_locked(%1,p0) = %3;\n"		\
-		"	if (!P0) jump 1b;\n"			\
-		"2:\n"						\
-		: "=&r" (__oldval)				\
-		: "r" (__ptr), "r" (__old), "r" (__new)		\
-		: "memory", "p0"				\
-	);							\
-	__oldval;						\
-})
-
-/*  Should probably shoot for an 8-byte aligned stack pointer  */
-#define STACK_MASK (~7)
-#define arch_align_stack(x) (x & STACK_MASK)
-
-#endif
diff --git a/arch/hexagon/kernel/dma.c b/arch/hexagon/kernel/dma.c
index e711ace..3730221 100644
--- a/arch/hexagon/kernel/dma.c
+++ b/arch/hexagon/kernel/dma.c
@@ -54,7 +54,8 @@
 /* Allocates from a pool of uncached memory that was reserved at boot time */
 
 void *hexagon_dma_alloc_coherent(struct device *dev, size_t size,
-				 dma_addr_t *dma_addr, gfp_t flag)
+				 dma_addr_t *dma_addr, gfp_t flag,
+				 struct dma_attrs *attrs)
 {
 	void *ret;
 
@@ -81,7 +82,7 @@
 }
 
 static void hexagon_free_coherent(struct device *dev, size_t size, void *vaddr,
-				  dma_addr_t dma_addr)
+				  dma_addr_t dma_addr, struct dma_attrs *attrs)
 {
 	gen_pool_free(coherent_pool, (unsigned long) vaddr, size);
 }
@@ -202,8 +203,8 @@
 }
 
 struct dma_map_ops hexagon_dma_ops = {
-	.alloc_coherent	= hexagon_dma_alloc_coherent,
-	.free_coherent	= hexagon_free_coherent,
+	.alloc		= hexagon_dma_alloc_coherent,
+	.free		= hexagon_free_coherent,
 	.map_sg		= hexagon_map_sg,
 	.map_page	= hexagon_map_page,
 	.sync_single_for_cpu = hexagon_sync_single_for_cpu,
diff --git a/arch/hexagon/kernel/ptrace.c b/arch/hexagon/kernel/ptrace.c
index bea3f08..32342de 100644
--- a/arch/hexagon/kernel/ptrace.c
+++ b/arch/hexagon/kernel/ptrace.c
@@ -29,7 +29,6 @@
 #include <linux/regset.h>
 #include <linux/user.h>
 
-#include <asm/system.h>
 #include <asm/user.h>
 
 static int genregs_get(struct task_struct *target,
diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c
index b45be31..ecbab34 100644
--- a/arch/hexagon/kernel/signal.c
+++ b/arch/hexagon/kernel/signal.c
@@ -192,12 +192,7 @@
 	if (rc)
 		return rc;
 
-	spin_lock_irq(&current->sighand->siglock);
-	sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&current->blocked, sig);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	block_sigmask(ka, sig);
 
 	return 0;
 }
@@ -305,10 +300,7 @@
 		goto badframe;
 
 	sigdelsetmask(&blocked, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = blocked;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&blocked);
 
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
diff --git a/arch/hexagon/kernel/smp.c b/arch/hexagon/kernel/smp.c
index 0123c63..9b44a9e 100644
--- a/arch/hexagon/kernel/smp.c
+++ b/arch/hexagon/kernel/smp.c
@@ -29,14 +29,13 @@
 #include <linux/smp.h>
 #include <linux/spinlock.h>
 
-#include <asm/system.h>  /*  xchg  */
 #include <asm/time.h>    /*  timer_interrupt  */
 #include <asm/hexagon_vm.h>
 
 #define BASE_IPI_IRQ 26
 
 /*
- * cpu_possible_map needs to be filled out prior to setup_per_cpu_areas
+ * cpu_possible_mask needs to be filled out prior to setup_per_cpu_areas
  * (which is prior to any of our smp_prepare_cpu crap), in order to set
  * up the...  per_cpu areas.
  */
@@ -209,7 +208,7 @@
 	stack_start =  ((void *) thread) + THREAD_SIZE;
 	__vmstart(start_secondary, stack_start);
 
-	while (!cpu_isset(cpu, cpu_online_map))
+	while (!cpu_online(cpu))
 		barrier();
 
 	return 0;
@@ -230,7 +229,7 @@
 
 	/*  Right now, let's just fake it. */
 	for (i = 0; i < max_cpus; i++)
-		cpu_set(i, cpu_present_map);
+		set_cpu_present(i, true);
 
 	/*  Also need to register the interrupts for IPI  */
 	if (max_cpus > 1)
@@ -270,5 +269,5 @@
 	int i;
 
 	for (i = 0; i < NR_CPUS; i++)
-		cpu_set(i, cpu_possible_map);
+		set_cpu_possible(i, true);
 }
diff --git a/arch/hexagon/kernel/vdso.c b/arch/hexagon/kernel/vdso.c
index 16277c3..f212a45 100644
--- a/arch/hexagon/kernel/vdso.c
+++ b/arch/hexagon/kernel/vdso.c
@@ -78,8 +78,7 @@
 	/* MAYWRITE to allow gdb to COW and set breakpoints. */
 	ret = install_special_mapping(mm, vdso_base, PAGE_SIZE,
 				      VM_READ|VM_EXEC|
-				      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-				      VM_ALWAYSDUMP,
+				      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
 				      &vdso_page);
 
 	if (ret)
diff --git a/arch/hexagon/kernel/vm_events.c b/arch/hexagon/kernel/vm_events.c
index 986a081e..591fc1b 100644
--- a/arch/hexagon/kernel/vm_events.c
+++ b/arch/hexagon/kernel/vm_events.c
@@ -22,7 +22,6 @@
 #include <asm/registers.h>
 #include <linux/irq.h>
 #include <linux/hardirq.h>
-#include <asm/system.h>
 
 /*
  * show_regs - print pt_regs structure
diff --git a/arch/ia64/dig/setup.c b/arch/ia64/dig/setup.c
index 9196b33..98131e1 100644
--- a/arch/ia64/dig/setup.c
+++ b/arch/ia64/dig/setup.c
@@ -22,7 +22,7 @@
 
 #include <asm/io.h>
 #include <asm/machvec.h>
-#include <asm/system.h>
+#include <asm/setup.h>
 
 void __init
 dig_setup (char **cmdline_p)
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index f5f4ef1..bcda5b2 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -43,7 +43,6 @@
 #include <asm/io.h>
 #include <asm/page.h>		/* PAGE_OFFSET */
 #include <asm/dma.h>
-#include <asm/system.h>		/* wmb() */
 
 #include <asm/acpi-ext.h>
 
@@ -1130,7 +1129,8 @@
  * See Documentation/DMA-API-HOWTO.txt
  */
 static void *
-sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags)
+sba_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+		   gfp_t flags, struct dma_attrs *attrs)
 {
 	struct ioc *ioc;
 	void *addr;
@@ -1192,8 +1192,8 @@
  *
  * See Documentation/DMA-API-HOWTO.txt
  */
-static void sba_free_coherent (struct device *dev, size_t size, void *vaddr,
-			       dma_addr_t dma_handle)
+static void sba_free_coherent(struct device *dev, size_t size, void *vaddr,
+			      dma_addr_t dma_handle, struct dma_attrs *attrs)
 {
 	sba_unmap_single_attrs(dev, dma_handle, size, 0, NULL);
 	free_pages((unsigned long) vaddr, get_order(size));
@@ -2213,8 +2213,8 @@
 __setup("sbapagesize=",sba_page_override);
 
 struct dma_map_ops sba_dma_ops = {
-	.alloc_coherent		= sba_alloc_coherent,
-	.free_coherent		= sba_free_coherent,
+	.alloc			= sba_alloc_coherent,
+	.free			= sba_free_coherent,
 	.map_page		= sba_map_page,
 	.unmap_page		= sba_unmap_page,
 	.map_sg			= sba_map_sg_attrs,
diff --git a/arch/ia64/hp/sim/boot/bootloader.c b/arch/ia64/hp/sim/boot/bootloader.c
index c5e9baa..28f4b23 100644
--- a/arch/ia64/hp/sim/boot/bootloader.c
+++ b/arch/ia64/hp/sim/boot/bootloader.c
@@ -20,7 +20,6 @@
 #include <asm/pal.h>
 #include <asm/pgtable.h>
 #include <asm/sal.h>
-#include <asm/system.h>
 
 #include "ssc.h"
 
diff --git a/arch/ia64/hp/sim/boot/fw-emu.c b/arch/ia64/hp/sim/boot/fw-emu.c
index 0216e28..271f412 100644
--- a/arch/ia64/hp/sim/boot/fw-emu.c
+++ b/arch/ia64/hp/sim/boot/fw-emu.c
@@ -13,6 +13,7 @@
 #include <asm/io.h>
 #include <asm/pal.h>
 #include <asm/sal.h>
+#include <asm/setup.h>
 
 #include "ssc.h"
 
diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c
index a63218e..c13064e 100644
--- a/arch/ia64/hp/sim/simeth.c
+++ b/arch/ia64/hp/sim/simeth.c
@@ -20,7 +20,6 @@
 #include <linux/skbuff.h>
 #include <linux/notifier.h>
 #include <linux/bitops.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/hpsim.h>
 
diff --git a/arch/ia64/include/asm/acpi.h b/arch/ia64/include/asm/acpi.h
index a06dfb1..301609c 100644
--- a/arch/ia64/include/asm/acpi.h
+++ b/arch/ia64/include/asm/acpi.h
@@ -32,7 +32,6 @@
 
 #include <linux/init.h>
 #include <linux/numa.h>
-#include <asm/system.h>
 #include <asm/numa.h>
 
 #define COMPILER_DEPENDENT_INT64	long
diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h
index 3fad89e..7d91166 100644
--- a/arch/ia64/include/asm/atomic.h
+++ b/arch/ia64/include/asm/atomic.h
@@ -15,7 +15,6 @@
 #include <linux/types.h>
 
 #include <asm/intrinsics.h>
-#include <asm/system.h>
 
 
 #define ATOMIC_INIT(i)		((atomic_t) { (i) })
diff --git a/arch/ia64/include/asm/auxvec.h b/arch/ia64/include/asm/auxvec.h
index 23cebe5..58277fc 100644
--- a/arch/ia64/include/asm/auxvec.h
+++ b/arch/ia64/include/asm/auxvec.h
@@ -8,4 +8,6 @@
 #define AT_SYSINFO	32
 #define AT_SYSINFO_EHDR	33
 
+#define AT_VECTOR_SIZE_ARCH 2 /* entries in ARCH_DLINFO */
+
 #endif /* _ASM_IA64_AUXVEC_H */
diff --git a/arch/ia64/include/asm/barrier.h b/arch/ia64/include/asm/barrier.h
new file mode 100644
index 0000000..60576e0
--- /dev/null
+++ b/arch/ia64/include/asm/barrier.h
@@ -0,0 +1,68 @@
+/*
+ * Memory barrier definitions.  This is based on information published
+ * in the Processor Abstraction Layer and the System Abstraction Layer
+ * manual.
+ *
+ * Copyright (C) 1998-2003 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
+ * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
+ */
+#ifndef _ASM_IA64_BARRIER_H
+#define _ASM_IA64_BARRIER_H
+
+#include <linux/compiler.h>
+
+/*
+ * Macros to force memory ordering.  In these descriptions, "previous"
+ * and "subsequent" refer to program order; "visible" means that all
+ * architecturally visible effects of a memory access have occurred
+ * (at a minimum, this means the memory has been read or written).
+ *
+ *   wmb():	Guarantees that all preceding stores to memory-
+ *		like regions are visible before any subsequent
+ *		stores and that all following stores will be
+ *		visible only after all previous stores.
+ *   rmb():	Like wmb(), but for reads.
+ *   mb():	wmb()/rmb() combo, i.e., all previous memory
+ *		accesses are visible before all subsequent
+ *		accesses and vice versa.  This is also known as
+ *		a "fence."
+ *
+ * Note: "mb()" and its variants cannot be used as a fence to order
+ * accesses to memory mapped I/O registers.  For that, mf.a needs to
+ * be used.  However, we don't want to always use mf.a because (a)
+ * it's (presumably) much slower than mf and (b) mf.a is supported for
+ * sequential memory pages only.
+ */
+#define mb()	ia64_mf()
+#define rmb()	mb()
+#define wmb()	mb()
+#define read_barrier_depends()	do { } while(0)
+
+#ifdef CONFIG_SMP
+# define smp_mb()	mb()
+# define smp_rmb()	rmb()
+# define smp_wmb()	wmb()
+# define smp_read_barrier_depends()	read_barrier_depends()
+#else
+# define smp_mb()	barrier()
+# define smp_rmb()	barrier()
+# define smp_wmb()	barrier()
+# define smp_read_barrier_depends()	do { } while(0)
+#endif
+
+/*
+ * XXX check on this ---I suspect what Linus really wants here is
+ * acquire vs release semantics but we can't discuss this stuff with
+ * Linus just yet.  Grrr...
+ */
+#define set_mb(var, value)	do { (var) = (value); mb(); } while (0)
+
+/*
+ * The group barrier in front of the rsm & ssm are necessary to ensure
+ * that none of the previous instructions in the same group are
+ * affected by the rsm/ssm.
+ */
+
+#endif /* _ASM_IA64_BARRIER_H */
diff --git a/arch/ia64/include/asm/cmpxchg.h b/arch/ia64/include/asm/cmpxchg.h
new file mode 100644
index 0000000..4c96187
--- /dev/null
+++ b/arch/ia64/include/asm/cmpxchg.h
@@ -0,0 +1 @@
+#include <asm/intrinsics.h>
diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h
index 4336d08..4f5e814 100644
--- a/arch/ia64/include/asm/dma-mapping.h
+++ b/arch/ia64/include/asm/dma-mapping.h
@@ -23,23 +23,29 @@
 extern void machvec_dma_sync_sg(struct device *, struct scatterlist *, int,
 				enum dma_data_direction);
 
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-				       dma_addr_t *daddr, gfp_t gfp)
+#define dma_alloc_coherent(d,s,h,f)	dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+				    dma_addr_t *daddr, gfp_t gfp,
+				    struct dma_attrs *attrs)
 {
 	struct dma_map_ops *ops = platform_dma_get_ops(dev);
 	void *caddr;
 
-	caddr = ops->alloc_coherent(dev, size, daddr, gfp);
+	caddr = ops->alloc(dev, size, daddr, gfp, attrs);
 	debug_dma_alloc_coherent(dev, size, *daddr, caddr);
 	return caddr;
 }
 
-static inline void dma_free_coherent(struct device *dev, size_t size,
-				     void *caddr, dma_addr_t daddr)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+				  void *caddr, dma_addr_t daddr,
+				  struct dma_attrs *attrs)
 {
 	struct dma_map_ops *ops = platform_dma_get_ops(dev);
 	debug_dma_free_coherent(dev, size, caddr, daddr);
-	ops->free_coherent(dev, size, caddr, daddr);
+	ops->free(dev, size, caddr, daddr, attrs);
 }
 
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
diff --git a/arch/ia64/include/asm/exec.h b/arch/ia64/include/asm/exec.h
new file mode 100644
index 0000000..b262424
--- /dev/null
+++ b/arch/ia64/include/asm/exec.h
@@ -0,0 +1,14 @@
+/*
+ * Process execution defines.
+ *
+ * Copyright (C) 1998-2003 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
+ * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
+ */
+#ifndef _ASM_IA64_EXEC_H
+#define _ASM_IA64_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* _ASM_IA64_EXEC_H */
diff --git a/arch/ia64/include/asm/futex.h b/arch/ia64/include/asm/futex.h
index 8428525..0ab82cc 100644
--- a/arch/ia64/include/asm/futex.h
+++ b/arch/ia64/include/asm/futex.h
@@ -4,7 +4,6 @@
 #include <linux/futex.h>
 #include <linux/uaccess.h>
 #include <asm/errno.h>
-#include <asm/system.h>
 
 #define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg) \
 do {									\
diff --git a/arch/ia64/include/asm/io.h b/arch/ia64/include/asm/io.h
index e5a6c35..2c26321 100644
--- a/arch/ia64/include/asm/io.h
+++ b/arch/ia64/include/asm/io.h
@@ -71,7 +71,6 @@
 #include <asm/intrinsics.h>
 #include <asm/machvec.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <asm-generic/iomap.h>
 
 /*
diff --git a/arch/ia64/include/asm/irqflags.h b/arch/ia64/include/asm/irqflags.h
index f82d6be..2b68d85 100644
--- a/arch/ia64/include/asm/irqflags.h
+++ b/arch/ia64/include/asm/irqflags.h
@@ -10,6 +10,8 @@
 #ifndef _ASM_IA64_IRQFLAGS_H
 #define _ASM_IA64_IRQFLAGS_H
 
+#include <asm/pal.h>
+
 #ifdef CONFIG_IA64_DEBUG_IRQ
 extern unsigned long last_cli_ip;
 static inline void arch_maybe_save_ip(unsigned long flags)
diff --git a/arch/ia64/include/asm/kexec.h b/arch/ia64/include/asm/kexec.h
index e1d58f81..aea2b81 100644
--- a/arch/ia64/include/asm/kexec.h
+++ b/arch/ia64/include/asm/kexec.h
@@ -1,6 +1,7 @@
 #ifndef _ASM_IA64_KEXEC_H
 #define _ASM_IA64_KEXEC_H
 
+#include <asm/setup.h>
 
 /* Maximum physical address we can use pages from */
 #define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
diff --git a/arch/ia64/include/asm/kvm.h b/arch/ia64/include/asm/kvm.h
index bc90c75..b9f82c8 100644
--- a/arch/ia64/include/asm/kvm.h
+++ b/arch/ia64/include/asm/kvm.h
@@ -261,4 +261,8 @@
 struct kvm_guest_debug_arch {
 };
 
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+};
+
 #endif
diff --git a/arch/ia64/include/asm/kvm_host.h b/arch/ia64/include/asm/kvm_host.h
index 2689ee5..e35b3a8 100644
--- a/arch/ia64/include/asm/kvm_host.h
+++ b/arch/ia64/include/asm/kvm_host.h
@@ -459,6 +459,9 @@
 	unsigned long boot_gp;
 };
 
+struct kvm_arch_memory_slot {
+};
+
 struct kvm_arch {
 	spinlock_t dirty_log_lock;
 
diff --git a/arch/ia64/include/asm/mca_asm.h b/arch/ia64/include/asm/mca_asm.h
index dd2a5b1..13c1d49 100644
--- a/arch/ia64/include/asm/mca_asm.h
+++ b/arch/ia64/include/asm/mca_asm.h
@@ -15,6 +15,8 @@
 #ifndef _ASM_IA64_MCA_ASM_H
 #define _ASM_IA64_MCA_ASM_H
 
+#include <asm/percpu.h>
+
 #define PSR_IC		13
 #define PSR_I		14
 #define	PSR_DT		17
diff --git a/arch/ia64/include/asm/page.h b/arch/ia64/include/asm/page.h
index 961a16f..f1e1b2e 100644
--- a/arch/ia64/include/asm/page.h
+++ b/arch/ia64/include/asm/page.h
@@ -221,4 +221,14 @@
 					 (((current->personality & READ_IMPLIES_EXEC) != 0)	\
 					  ? VM_EXEC : 0))
 
+#define GATE_ADDR		RGN_BASE(RGN_GATE)
+
+/*
+ * 0xa000000000000000+2*PERCPU_PAGE_SIZE
+ * - 0xa000000000000000+3*PERCPU_PAGE_SIZE remain unmapped (guard page)
+ */
+#define KERNEL_START		 (GATE_ADDR+__IA64_UL_CONST(0x100000000))
+#define PERCPU_ADDR		(-PERCPU_PAGE_SIZE)
+#define LOAD_OFFSET		(KERNEL_START - KERNEL_TR_PAGE_SIZE)
+
 #endif /* _ASM_IA64_PAGE_H */
diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index 279b38a..5e04b59 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -11,6 +11,14 @@
 #include <asm/scatterlist.h>
 #include <asm/hw_irq.h>
 
+struct pci_vector_struct {
+	__u16 segment;	/* PCI Segment number */
+	__u16 bus;	/* PCI Bus number */
+	__u32 pci_id;	/* ACPI split 16 bits device, 16 bits function (see section 6.1.1) */
+	__u8 pin;	/* PCI PIN (0 = A, 1 = B, 2 = C, 3 = D) */
+	__u32 irq;	/* IRQ assigned */
+};
+
 /*
  * Can be used to override the logic in pci_scan_bus for skipping already-configured bus
  * numbers - to be used for buggy BIOSes or architectures with incomplete PCI setup by the
@@ -108,12 +116,6 @@
 	return (pci_domain_nr(bus) != 0);
 }
 
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
-		struct pci_bus_region *region, struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev,
-		struct resource *res, struct pci_bus_region *region);
-
 static inline struct resource *
 pcibios_select_root(struct pci_dev *pdev, struct resource *res)
 {
diff --git a/arch/ia64/include/asm/pgtable.h b/arch/ia64/include/asm/pgtable.h
index 1a97af3..815810c 100644
--- a/arch/ia64/include/asm/pgtable.h
+++ b/arch/ia64/include/asm/pgtable.h
@@ -16,7 +16,6 @@
 #include <asm/mman.h>
 #include <asm/page.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/types.h>
 
 #define IA64_MAX_PHYS_BITS	50	/* max. number of physical address bits (architected) */
diff --git a/arch/ia64/include/asm/posix_types.h b/arch/ia64/include/asm/posix_types.h
index 1788556..7323ab9 100644
--- a/arch/ia64/include/asm/posix_types.h
+++ b/arch/ia64/include/asm/posix_types.h
@@ -1,126 +1,11 @@
 #ifndef _ASM_IA64_POSIX_TYPES_H
 #define _ASM_IA64_POSIX_TYPES_H
 
-/*
- * This file is generally used by user-level software, so you need to
- * be a little careful about namespace pollution etc.  Also, we cannot
- * assume GCC is being used.
- *
- * Based on <asm-alpha/posix_types.h>.
- *
- * Modified 1998-2000, 2003
- *	David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
- */
-
-typedef unsigned long	__kernel_ino_t;
-typedef unsigned int	__kernel_mode_t;
 typedef unsigned int	__kernel_nlink_t;
-typedef long		__kernel_off_t;
-typedef long long	__kernel_loff_t;
-typedef int		__kernel_pid_t;
-typedef int		__kernel_ipc_pid_t;
-typedef unsigned int	__kernel_uid_t;
-typedef unsigned int	__kernel_gid_t;
-typedef unsigned long	__kernel_size_t;
-typedef long		__kernel_ssize_t;
-typedef long		__kernel_ptrdiff_t;
-typedef long		__kernel_time_t;
-typedef long		__kernel_suseconds_t;
-typedef long		__kernel_clock_t;
-typedef int		__kernel_timer_t;
-typedef int		__kernel_clockid_t;
-typedef int		__kernel_daddr_t;
-typedef char *		__kernel_caddr_t;
+#define __kernel_nlink_t __kernel_nlink_t
+
 typedef unsigned long	__kernel_sigset_t;	/* at least 32 bits */
-typedef unsigned short	__kernel_uid16_t;
-typedef unsigned short	__kernel_gid16_t;
 
-typedef struct {
-	int	val[2];
-} __kernel_fsid_t;
+#include <asm-generic/posix_types.h>
 
-typedef __kernel_uid_t __kernel_old_uid_t;
-typedef __kernel_gid_t __kernel_old_gid_t;
-typedef __kernel_uid_t __kernel_uid32_t;
-typedef __kernel_gid_t __kernel_gid32_t;
-
-typedef unsigned int	__kernel_old_dev_t;
-
-# ifdef __KERNEL__
-
-#  ifndef __GNUC__
-
-#define	__FD_SET(d, set)	((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
-#define	__FD_CLR(d, set)	((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
-#define	__FD_ISSET(d, set)	(((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) != 0)
-#define	__FD_ZERO(set)	\
-  ((void) memset ((void *) (set), 0, sizeof (__kernel_fd_set)))
-
-#  else /* !__GNUC__ */
-
-/* With GNU C, use inline functions instead so args are evaluated only once: */
-
-#undef __FD_SET
-static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	fdsetp->fds_bits[_tmp] |= (1UL<<_rem);
-}
-
-#undef __FD_CLR
-static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem);
-}
-
-#undef __FD_ISSET
-static __inline__ int __FD_ISSET(unsigned long fd, const __kernel_fd_set *p)
-{ 
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0;
-}
-
-/*
- * This will unroll the loop for the normal constant case (8 ints,
- * for a 256-bit fd_set)
- */
-#undef __FD_ZERO
-static __inline__ void __FD_ZERO(__kernel_fd_set *p)
-{
-	unsigned long *tmp = p->fds_bits;
-	int i;
-
-	if (__builtin_constant_p(__FDSET_LONGS)) {
-		switch (__FDSET_LONGS) {
-		      case 16:
-			tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
-			tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
-			tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
-			tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
-			return;
-
-		      case 8:
-			tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
-			tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
-			return;
-
-		      case 4:
-			tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
-			return;
-		}
-	}
-	i = __FDSET_LONGS;
-	while (i) {
-		i--;
-		*tmp = 0;
-		tmp++;
-	}
-}
-
-#  endif /* !__GNUC__ */
-# endif /* __KERNEL__ */
 #endif /* _ASM_IA64_POSIX_TYPES_H */
diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h
index 691be0b..483f6c6 100644
--- a/arch/ia64/include/asm/processor.h
+++ b/arch/ia64/include/asm/processor.h
@@ -19,6 +19,9 @@
 #include <asm/ptrace.h>
 #include <asm/ustack.h>
 
+#define __ARCH_WANT_UNLOCKED_CTXSW
+#define ARCH_HAS_PREFETCH_SWITCH_STACK
+
 #define IA64_NUM_PHYS_STACK_REG	96
 #define IA64_NUM_DBG_REGS	8
 
@@ -720,6 +723,11 @@
 enum idle_boot_override {IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_FORCE_MWAIT,
 			 IDLE_NOMWAIT, IDLE_POLL};
 
+void cpu_idle_wait(void);
+void default_idle(void);
+
+#define ia64_platform_is(x) (strcmp(x, platform_name) == 0)
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_IA64_PROCESSOR_H */
diff --git a/arch/ia64/include/asm/sal.h b/arch/ia64/include/asm/sal.h
index d19ddba..e504f38 100644
--- a/arch/ia64/include/asm/sal.h
+++ b/arch/ia64/include/asm/sal.h
@@ -40,7 +40,6 @@
 #include <linux/efi.h>
 
 #include <asm/pal.h>
-#include <asm/system.h>
 #include <asm/fpu.h>
 
 extern spinlock_t sal_lock;
diff --git a/arch/ia64/include/asm/setup.h b/arch/ia64/include/asm/setup.h
index 4399a44..8d56458 100644
--- a/arch/ia64/include/asm/setup.h
+++ b/arch/ia64/include/asm/setup.h
@@ -3,4 +3,22 @@
 
 #define COMMAND_LINE_SIZE	2048
 
+extern struct ia64_boot_param {
+	__u64 command_line;		/* physical address of command line arguments */
+	__u64 efi_systab;		/* physical address of EFI system table */
+	__u64 efi_memmap;		/* physical address of EFI memory map */
+	__u64 efi_memmap_size;		/* size of EFI memory map */
+	__u64 efi_memdesc_size;		/* size of an EFI memory map descriptor */
+	__u32 efi_memdesc_version;	/* memory descriptor version */
+	struct {
+		__u16 num_cols;	/* number of columns on console output device */
+		__u16 num_rows;	/* number of rows on console output device */
+		__u16 orig_x;	/* cursor's x position */
+		__u16 orig_y;	/* cursor's y position */
+	} console_info;
+	__u64 fpswa;		/* physical address of the fpswa interface */
+	__u64 initrd_start;
+	__u64 initrd_size;
+} *ia64_boot_param;
+
 #endif
diff --git a/arch/ia64/include/asm/sn/pda.h b/arch/ia64/include/asm/sn/pda.h
index 1c5108d..22ae358 100644
--- a/arch/ia64/include/asm/sn/pda.h
+++ b/arch/ia64/include/asm/sn/pda.h
@@ -10,7 +10,6 @@
 
 #include <linux/cache.h>
 #include <asm/percpu.h>
-#include <asm/system.h>
 
 
 /*
diff --git a/arch/ia64/include/asm/spinlock.h b/arch/ia64/include/asm/spinlock.h
index b77768d..54ff557 100644
--- a/arch/ia64/include/asm/spinlock.h
+++ b/arch/ia64/include/asm/spinlock.h
@@ -15,7 +15,6 @@
 
 #include <linux/atomic.h>
 #include <asm/intrinsics.h>
-#include <asm/system.h>
 
 #define arch_spin_lock_init(x)			((x)->lock = 0)
 
diff --git a/arch/ia64/include/asm/switch_to.h b/arch/ia64/include/asm/switch_to.h
new file mode 100644
index 0000000..cb2412f
--- /dev/null
+++ b/arch/ia64/include/asm/switch_to.h
@@ -0,0 +1,87 @@
+/*
+ * Low-level task switching. This is based on information published in
+ * the Processor Abstraction Layer and the System Abstraction Layer
+ * manual.
+ *
+ * Copyright (C) 1998-2003 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
+ * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
+ */
+#ifndef _ASM_IA64_SWITCH_TO_H
+#define _ASM_IA64_SWITCH_TO_H
+
+#include <linux/percpu.h>
+
+struct task_struct;
+
+/*
+ * Context switch from one thread to another.  If the two threads have
+ * different address spaces, schedule() has already taken care of
+ * switching to the new address space by calling switch_mm().
+ *
+ * Disabling access to the fph partition and the debug-register
+ * context switch MUST be done before calling ia64_switch_to() since a
+ * newly created thread returns directly to
+ * ia64_ret_from_syscall_clear_r8.
+ */
+extern struct task_struct *ia64_switch_to (void *next_task);
+
+extern void ia64_save_extra (struct task_struct *task);
+extern void ia64_load_extra (struct task_struct *task);
+
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+extern void ia64_account_on_switch (struct task_struct *prev, struct task_struct *next);
+# define IA64_ACCOUNT_ON_SWITCH(p,n) ia64_account_on_switch(p,n)
+#else
+# define IA64_ACCOUNT_ON_SWITCH(p,n)
+#endif
+
+#ifdef CONFIG_PERFMON
+  DECLARE_PER_CPU(unsigned long, pfm_syst_info);
+# define PERFMON_IS_SYSWIDE() (__get_cpu_var(pfm_syst_info) & 0x1)
+#else
+# define PERFMON_IS_SYSWIDE() (0)
+#endif
+
+#define IA64_HAS_EXTRA_STATE(t)							\
+	((t)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID)	\
+	 || PERFMON_IS_SYSWIDE())
+
+#define __switch_to(prev,next,last) do {							 \
+	IA64_ACCOUNT_ON_SWITCH(prev, next);							 \
+	if (IA64_HAS_EXTRA_STATE(prev))								 \
+		ia64_save_extra(prev);								 \
+	if (IA64_HAS_EXTRA_STATE(next))								 \
+		ia64_load_extra(next);								 \
+	ia64_psr(task_pt_regs(next))->dfh = !ia64_is_local_fpu_owner(next);			 \
+	(last) = ia64_switch_to((next));							 \
+} while (0)
+
+#ifdef CONFIG_SMP
+/*
+ * In the SMP case, we save the fph state when context-switching away from a thread that
+ * modified fph.  This way, when the thread gets scheduled on another CPU, the CPU can
+ * pick up the state from task->thread.fph, avoiding the complication of having to fetch
+ * the latest fph state from another CPU.  In other words: eager save, lazy restore.
+ */
+# define switch_to(prev,next,last) do {						\
+	if (ia64_psr(task_pt_regs(prev))->mfh && ia64_is_local_fpu_owner(prev)) {				\
+		ia64_psr(task_pt_regs(prev))->mfh = 0;			\
+		(prev)->thread.flags |= IA64_THREAD_FPH_VALID;			\
+		__ia64_save_fpu((prev)->thread.fph);				\
+	}									\
+	__switch_to(prev, next, last);						\
+	/* "next" in old context is "current" in new context */			\
+	if (unlikely((current->thread.flags & IA64_THREAD_MIGRATION) &&	       \
+		     (task_cpu(current) !=				       \
+		      		      task_thread_info(current)->last_cpu))) { \
+		platform_migrate(current);				       \
+		task_thread_info(current)->last_cpu = task_cpu(current);       \
+	}								       \
+} while (0)
+#else
+# define switch_to(prev,next,last)	__switch_to(prev, next, last)
+#endif
+
+#endif /* _ASM_IA64_SWITCH_TO_H */
diff --git a/arch/ia64/include/asm/system.h b/arch/ia64/include/asm/system.h
deleted file mode 100644
index 6cca307..0000000
--- a/arch/ia64/include/asm/system.h
+++ /dev/null
@@ -1,203 +0,0 @@
-#ifndef _ASM_IA64_SYSTEM_H
-#define _ASM_IA64_SYSTEM_H
-
-/*
- * System defines. Note that this is included both from .c and .S
- * files, so it does only defines, not any C code.  This is based
- * on information published in the Processor Abstraction Layer
- * and the System Abstraction Layer manual.
- *
- * Copyright (C) 1998-2003 Hewlett-Packard Co
- *	David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
- * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
- */
-
-#include <asm/kregs.h>
-#include <asm/page.h>
-#include <asm/pal.h>
-#include <asm/percpu.h>
-
-#define GATE_ADDR		RGN_BASE(RGN_GATE)
-
-/*
- * 0xa000000000000000+2*PERCPU_PAGE_SIZE
- * - 0xa000000000000000+3*PERCPU_PAGE_SIZE remain unmapped (guard page)
- */
-#define KERNEL_START		 (GATE_ADDR+__IA64_UL_CONST(0x100000000))
-#define PERCPU_ADDR		(-PERCPU_PAGE_SIZE)
-#define LOAD_OFFSET		(KERNEL_START - KERNEL_TR_PAGE_SIZE)
-
-#ifndef __ASSEMBLY__
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-
-#define AT_VECTOR_SIZE_ARCH 2 /* entries in ARCH_DLINFO */
-
-struct pci_vector_struct {
-	__u16 segment;	/* PCI Segment number */
-	__u16 bus;	/* PCI Bus number */
-	__u32 pci_id;	/* ACPI split 16 bits device, 16 bits function (see section 6.1.1) */
-	__u8 pin;	/* PCI PIN (0 = A, 1 = B, 2 = C, 3 = D) */
-	__u32 irq;	/* IRQ assigned */
-};
-
-extern struct ia64_boot_param {
-	__u64 command_line;		/* physical address of command line arguments */
-	__u64 efi_systab;		/* physical address of EFI system table */
-	__u64 efi_memmap;		/* physical address of EFI memory map */
-	__u64 efi_memmap_size;		/* size of EFI memory map */
-	__u64 efi_memdesc_size;		/* size of an EFI memory map descriptor */
-	__u32 efi_memdesc_version;	/* memory descriptor version */
-	struct {
-		__u16 num_cols;	/* number of columns on console output device */
-		__u16 num_rows;	/* number of rows on console output device */
-		__u16 orig_x;	/* cursor's x position */
-		__u16 orig_y;	/* cursor's y position */
-	} console_info;
-	__u64 fpswa;		/* physical address of the fpswa interface */
-	__u64 initrd_start;
-	__u64 initrd_size;
-} *ia64_boot_param;
-
-/*
- * Macros to force memory ordering.  In these descriptions, "previous"
- * and "subsequent" refer to program order; "visible" means that all
- * architecturally visible effects of a memory access have occurred
- * (at a minimum, this means the memory has been read or written).
- *
- *   wmb():	Guarantees that all preceding stores to memory-
- *		like regions are visible before any subsequent
- *		stores and that all following stores will be
- *		visible only after all previous stores.
- *   rmb():	Like wmb(), but for reads.
- *   mb():	wmb()/rmb() combo, i.e., all previous memory
- *		accesses are visible before all subsequent
- *		accesses and vice versa.  This is also known as
- *		a "fence."
- *
- * Note: "mb()" and its variants cannot be used as a fence to order
- * accesses to memory mapped I/O registers.  For that, mf.a needs to
- * be used.  However, we don't want to always use mf.a because (a)
- * it's (presumably) much slower than mf and (b) mf.a is supported for
- * sequential memory pages only.
- */
-#define mb()	ia64_mf()
-#define rmb()	mb()
-#define wmb()	mb()
-#define read_barrier_depends()	do { } while(0)
-
-#ifdef CONFIG_SMP
-# define smp_mb()	mb()
-# define smp_rmb()	rmb()
-# define smp_wmb()	wmb()
-# define smp_read_barrier_depends()	read_barrier_depends()
-#else
-# define smp_mb()	barrier()
-# define smp_rmb()	barrier()
-# define smp_wmb()	barrier()
-# define smp_read_barrier_depends()	do { } while(0)
-#endif
-
-/*
- * XXX check on this ---I suspect what Linus really wants here is
- * acquire vs release semantics but we can't discuss this stuff with
- * Linus just yet.  Grrr...
- */
-#define set_mb(var, value)	do { (var) = (value); mb(); } while (0)
-
-/*
- * The group barrier in front of the rsm & ssm are necessary to ensure
- * that none of the previous instructions in the same group are
- * affected by the rsm/ssm.
- */
-
-#ifdef __KERNEL__
-
-/*
- * Context switch from one thread to another.  If the two threads have
- * different address spaces, schedule() has already taken care of
- * switching to the new address space by calling switch_mm().
- *
- * Disabling access to the fph partition and the debug-register
- * context switch MUST be done before calling ia64_switch_to() since a
- * newly created thread returns directly to
- * ia64_ret_from_syscall_clear_r8.
- */
-extern struct task_struct *ia64_switch_to (void *next_task);
-
-struct task_struct;
-
-extern void ia64_save_extra (struct task_struct *task);
-extern void ia64_load_extra (struct task_struct *task);
-
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-extern void ia64_account_on_switch (struct task_struct *prev, struct task_struct *next);
-# define IA64_ACCOUNT_ON_SWITCH(p,n) ia64_account_on_switch(p,n)
-#else
-# define IA64_ACCOUNT_ON_SWITCH(p,n)
-#endif
-
-#ifdef CONFIG_PERFMON
-  DECLARE_PER_CPU(unsigned long, pfm_syst_info);
-# define PERFMON_IS_SYSWIDE() (__get_cpu_var(pfm_syst_info) & 0x1)
-#else
-# define PERFMON_IS_SYSWIDE() (0)
-#endif
-
-#define IA64_HAS_EXTRA_STATE(t)							\
-	((t)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID)	\
-	 || PERFMON_IS_SYSWIDE())
-
-#define __switch_to(prev,next,last) do {							 \
-	IA64_ACCOUNT_ON_SWITCH(prev, next);							 \
-	if (IA64_HAS_EXTRA_STATE(prev))								 \
-		ia64_save_extra(prev);								 \
-	if (IA64_HAS_EXTRA_STATE(next))								 \
-		ia64_load_extra(next);								 \
-	ia64_psr(task_pt_regs(next))->dfh = !ia64_is_local_fpu_owner(next);			 \
-	(last) = ia64_switch_to((next));							 \
-} while (0)
-
-#ifdef CONFIG_SMP
-/*
- * In the SMP case, we save the fph state when context-switching away from a thread that
- * modified fph.  This way, when the thread gets scheduled on another CPU, the CPU can
- * pick up the state from task->thread.fph, avoiding the complication of having to fetch
- * the latest fph state from another CPU.  In other words: eager save, lazy restore.
- */
-# define switch_to(prev,next,last) do {						\
-	if (ia64_psr(task_pt_regs(prev))->mfh && ia64_is_local_fpu_owner(prev)) {				\
-		ia64_psr(task_pt_regs(prev))->mfh = 0;			\
-		(prev)->thread.flags |= IA64_THREAD_FPH_VALID;			\
-		__ia64_save_fpu((prev)->thread.fph);				\
-	}									\
-	__switch_to(prev, next, last);						\
-	/* "next" in old context is "current" in new context */			\
-	if (unlikely((current->thread.flags & IA64_THREAD_MIGRATION) &&	       \
-		     (task_cpu(current) !=				       \
-		      		      task_thread_info(current)->last_cpu))) { \
-		platform_migrate(current);				       \
-		task_thread_info(current)->last_cpu = task_cpu(current);       \
-	}								       \
-} while (0)
-#else
-# define switch_to(prev,next,last)	__switch_to(prev, next, last)
-#endif
-
-#define __ARCH_WANT_UNLOCKED_CTXSW
-#define ARCH_HAS_PREFETCH_SWITCH_STACK
-#define ia64_platform_is(x) (strcmp(x, platform_name) == 0)
-
-void cpu_idle_wait(void);
-
-#define arch_align_stack(x) (x)
-
-void default_idle(void);
-
-#endif /* __KERNEL__ */
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* _ASM_IA64_SYSTEM_H */
diff --git a/arch/ia64/include/asm/uv/uv.h b/arch/ia64/include/asm/uv/uv.h
index 61b5bdf..8f6cbaa 100644
--- a/arch/ia64/include/asm/uv/uv.h
+++ b/arch/ia64/include/asm/uv/uv.h
@@ -1,7 +1,6 @@
 #ifndef _ASM_IA64_UV_UV_H
 #define _ASM_IA64_UV_UV_H
 
-#include <asm/system.h>
 #include <asm/sn/simulator.h>
 
 static inline int is_uv_system(void)
diff --git a/arch/ia64/include/asm/xen/interface.h b/arch/ia64/include/asm/xen/interface.h
index fbb5198..09d5f7f 100644
--- a/arch/ia64/include/asm/xen/interface.h
+++ b/arch/ia64/include/asm/xen/interface.h
@@ -77,6 +77,7 @@
 DEFINE_GUEST_HANDLE(long);
 DEFINE_GUEST_HANDLE(void);
 DEFINE_GUEST_HANDLE(uint64_t);
+DEFINE_GUEST_HANDLE(uint32_t);
 
 typedef unsigned long xen_pfn_t;
 DEFINE_GUEST_HANDLE(xen_pfn_t);
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 5207035..6f38b61 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -50,7 +50,6 @@
 #include <asm/iosapic.h>
 #include <asm/machvec.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <asm/numa.h>
 #include <asm/sal.h>
 #include <asm/cyclone.h>
@@ -349,11 +348,11 @@
 
 	iosapic_override_isa_irq(p->source_irq, p->global_irq,
 				 ((p->inti_flags & ACPI_MADT_POLARITY_MASK) ==
-				  ACPI_MADT_POLARITY_ACTIVE_HIGH) ?
-				 IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
+				  ACPI_MADT_POLARITY_ACTIVE_LOW) ?
+				 IOSAPIC_POL_LOW : IOSAPIC_POL_HIGH,
 				 ((p->inti_flags & ACPI_MADT_TRIGGER_MASK) ==
-				 ACPI_MADT_TRIGGER_EDGE) ?
-				 IOSAPIC_EDGE : IOSAPIC_LEVEL);
+				 ACPI_MADT_TRIGGER_LEVEL) ?
+				 IOSAPIC_LEVEL : IOSAPIC_EDGE);
 	return 0;
 }
 
@@ -840,11 +839,11 @@
 early_param("additional_cpus", setup_additional_cpus);
 
 /*
- * cpu_possible_map should be static, it cannot change as CPUs
+ * cpu_possible_mask should be static, it cannot change as CPUs
  * are onlined, or offlined. The reason is per-cpu data-structures
  * are allocated by some modules at init time, and dont expect to
  * do this dynamically on cpu arrival/departure.
- * cpu_present_map on the other hand can change dynamically.
+ * cpu_present_mask on the other hand can change dynamically.
  * In case when cpu_hotplug is not compiled, then we resort to current
  * behaviour, which is cpu_possible == cpu_present.
  * - Ashok Raj
@@ -922,7 +921,7 @@
 
 	acpi_map_cpu2node(handle, cpu, physid);
 
-	cpu_set(cpu, cpu_present_map);
+	set_cpu_present(cpu, true);
 	ia64_cpu_to_sapicid[cpu] = physid;
 
 	acpi_processor_set_pdc(handle);
@@ -941,7 +940,7 @@
 int acpi_unmap_lsapic(int cpu)
 {
 	ia64_cpu_to_sapicid[cpu] = -1;
-	cpu_clear(cpu, cpu_present_map);
+	set_cpu_present(cpu, false);
 
 #ifdef CONFIG_ACPI_NUMA
 	/* NUMA specific cleanup's */
diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c
index af56501..a48bd9a 100644
--- a/arch/ia64/kernel/asm-offsets.c
+++ b/arch/ia64/kernel/asm-offsets.c
@@ -269,8 +269,8 @@
 	BLANK();
 
 	/* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */
-	DEFINE(IA64_GTOD_LOCK_OFFSET,
-		offsetof (struct fsyscall_gtod_data_t, lock));
+	DEFINE(IA64_GTOD_SEQ_OFFSET,
+	       offsetof (struct fsyscall_gtod_data_t, seq));
 	DEFINE(IA64_GTOD_WALL_TIME_OFFSET,
 		offsetof (struct fsyscall_gtod_data_t, wall_time));
 	DEFINE(IA64_GTOD_MONO_TIME_OFFSET,
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index c38d22e..d37bbd4 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -39,6 +39,7 @@
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/mca.h>
+#include <asm/setup.h>
 #include <asm/tlbflush.h>
 
 #define EFI_DEBUG	0
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S
index 331d42b..cc26eda 100644
--- a/arch/ia64/kernel/fsys.S
+++ b/arch/ia64/kernel/fsys.S
@@ -21,7 +21,6 @@
 #include <asm/thread_info.h>
 #include <asm/sal.h>
 #include <asm/signal.h>
-#include <asm/system.h>
 #include <asm/unistd.h>
 
 #include "entry.h"
@@ -174,7 +173,7 @@
 	FSYS_RETURN
 END(fsys_set_tid_address)
 
-#if IA64_GTOD_LOCK_OFFSET !=0
+#if IA64_GTOD_SEQ_OFFSET !=0
 #error fsys_gettimeofday incompatible with changes to struct fsyscall_gtod_data_t
 #endif
 #if IA64_ITC_JITTER_OFFSET !=0
diff --git a/arch/ia64/kernel/fsyscall_gtod_data.h b/arch/ia64/kernel/fsyscall_gtod_data.h
index 57d2ee6..146b15b 100644
--- a/arch/ia64/kernel/fsyscall_gtod_data.h
+++ b/arch/ia64/kernel/fsyscall_gtod_data.h
@@ -6,7 +6,7 @@
  */
 
 struct fsyscall_gtod_data_t {
-	seqlock_t	lock;
+	seqcount_t	seq;
 	struct timespec	wall_time;
 	struct timespec monotonic_time;
 	cycle_t		clk_mask;
diff --git a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S
index 245d3e1..b5f8bdd 100644
--- a/arch/ia64/kernel/gate.S
+++ b/arch/ia64/kernel/gate.S
@@ -11,8 +11,9 @@
 #include <asm/errno.h>
 #include <asm/asm-offsets.h>
 #include <asm/sigcontext.h>
-#include <asm/system.h>
 #include <asm/unistd.h>
+#include <asm/kregs.h>
+#include <asm/page.h>
 #include "paravirt_inst.h"
 
 /*
diff --git a/arch/ia64/kernel/gate.lds.S b/arch/ia64/kernel/gate.lds.S
index d32b085..e518f79 100644
--- a/arch/ia64/kernel/gate.lds.S
+++ b/arch/ia64/kernel/gate.lds.S
@@ -5,8 +5,7 @@
  * its layout.
  */
 
-
-#include <asm/system.h>
+#include <asm/page.h>
 #include "paravirt_patchlist.h"
 
 SECTIONS
diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S
index 17a9fba..629a250 100644
--- a/arch/ia64/kernel/head.S
+++ b/arch/ia64/kernel/head.S
@@ -30,7 +30,6 @@
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/mca_asm.h>
 #include <linux/init.h>
 #include <linux/linkage.h>
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index b0f9afe..ef4b5d8 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -98,7 +98,6 @@
 #include <asm/machvec.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 
 #undef DEBUG_INTERRUPT_ROUTING
 
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index 782c3a35..5c3e088 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -39,7 +39,6 @@
 #include <asm/hw_irq.h>
 #include <asm/machvec.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/tlbflush.h>
 
 #ifdef CONFIG_PERFMON
@@ -118,7 +117,7 @@
 	cpumask_t mask;
 	int pos, vector;
 
-	cpus_and(mask, domain, cpu_online_map);
+	cpumask_and(&mask, &domain, cpu_online_mask);
 	if (cpus_empty(mask))
 		return -EINVAL;
 
@@ -141,7 +140,7 @@
 	BUG_ON((unsigned)irq >= NR_IRQS);
 	BUG_ON((unsigned)vector >= IA64_NUM_VECTORS);
 
-	cpus_and(mask, domain, cpu_online_map);
+	cpumask_and(&mask, &domain, cpu_online_mask);
 	if (cpus_empty(mask))
 		return -EINVAL;
 	if ((cfg->vector == vector) && cpus_equal(cfg->domain, domain))
@@ -179,7 +178,7 @@
 	BUG_ON(cfg->vector == IRQ_VECTOR_UNASSIGNED);
 	vector = cfg->vector;
 	domain = cfg->domain;
-	cpus_and(mask, cfg->domain, cpu_online_map);
+	cpumask_and(&mask, &cfg->domain, cpu_online_mask);
 	for_each_cpu_mask(cpu, mask)
 		per_cpu(vector_irq, cpu)[vector] = -1;
 	cfg->vector = IRQ_VECTOR_UNASSIGNED;
@@ -322,7 +321,7 @@
 	if (unlikely(cpu_isset(smp_processor_id(), cfg->old_domain)))
 		return;
 
-	cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
+	cpumask_and(&cleanup_mask, &cfg->old_domain, cpu_online_mask);
 	cfg->move_cleanup_count = cpus_weight(cleanup_mask);
 	for_each_cpu_mask(i, cleanup_mask)
 		platform_send_ipi(i, IA64_IRQ_MOVE_VECTOR, IA64_IPI_DM_INT, 0);
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S
index d93e396..fa25689 100644
--- a/arch/ia64/kernel/ivt.S
+++ b/arch/ia64/kernel/ivt.S
@@ -54,7 +54,6 @@
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/thread_info.h>
 #include <asm/unistd.h>
 #include <asm/errno.h>
diff --git a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c
index 4eed358..070e8ef 100644
--- a/arch/ia64/kernel/machine_kexec.c
+++ b/arch/ia64/kernel/machine_kexec.c
@@ -157,7 +157,7 @@
 #endif
 #ifdef CONFIG_PGTABLE_3
 	VMCOREINFO_CONFIG(PGTABLE_3);
-#elif  CONFIG_PGTABLE_4
+#elif defined(CONFIG_PGTABLE_4)
 	VMCOREINFO_CONFIG(PGTABLE_4);
 #endif
 }
diff --git a/arch/ia64/kernel/machvec.c b/arch/ia64/kernel/machvec.c
index d41a40e..f5a1e52 100644
--- a/arch/ia64/kernel/machvec.c
+++ b/arch/ia64/kernel/machvec.c
@@ -1,7 +1,6 @@
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
 #include <asm/machvec.h>
-#include <asm/system.h>
 
 #ifdef CONFIG_IA64_GENERIC
 
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 84fb405..65bf9cd 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -92,7 +92,6 @@
 #include <asm/meminit.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/sal.h>
 #include <asm/mca.h>
 #include <asm/kexec.h>
@@ -1447,6 +1446,8 @@
 	/* Get the CMC error record and log it */
 	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC);
 
+	local_irq_disable();
+
 	return IRQ_HANDLED;
 }
 
@@ -1513,7 +1514,8 @@
 ia64_mca_cmc_poll (unsigned long dummy)
 {
 	/* Trigger a CMC interrupt cascade  */
-	platform_send_ipi(first_cpu(cpu_online_map), IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0);
+	platform_send_ipi(cpumask_first(cpu_online_mask), IA64_CMCP_VECTOR,
+							IA64_IPI_DM_INT, 0);
 }
 
 /*
@@ -1589,7 +1591,8 @@
 ia64_mca_cpe_poll (unsigned long dummy)
 {
 	/* Trigger a CPE interrupt cascade  */
-	platform_send_ipi(first_cpu(cpu_online_map), IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0);
+	platform_send_ipi(cpumask_first(cpu_online_mask), IA64_CPEP_VECTOR,
+							IA64_IPI_DM_INT, 0);
 }
 
 #endif /* CONFIG_ACPI */
diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c
index 09b4d68..1c2e894 100644
--- a/arch/ia64/kernel/mca_drv.c
+++ b/arch/ia64/kernel/mca_drv.c
@@ -28,7 +28,6 @@
 #include <asm/machvec.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/sal.h>
 #include <asm/mca.h>
 
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
index 94e0db7..fb2f1e6 100644
--- a/arch/ia64/kernel/msi_ia64.c
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -57,7 +57,7 @@
 		return irq;
 
 	irq_set_msi_desc(irq, desc);
-	cpus_and(mask, irq_to_domain(irq), cpu_online_map);
+	cpumask_and(&mask, &(irq_to_domain(irq)), cpu_online_mask);
 	dest_phys_id = cpu_physical_id(first_cpu(mask));
 	vector = irq_to_vector(irq);
 
@@ -179,7 +179,7 @@
 	unsigned dest;
 	cpumask_t mask;
 
-	cpus_and(mask, irq_to_domain(irq), cpu_online_map);
+	cpumask_and(&mask, &(irq_to_domain(irq)), cpu_online_mask);
 	dest = cpu_physical_id(first_cpu(mask));
 
 	msg->address_hi = 0;
diff --git a/arch/ia64/kernel/patch.c b/arch/ia64/kernel/patch.c
index 68a1311..1cf0917 100644
--- a/arch/ia64/kernel/patch.c
+++ b/arch/ia64/kernel/patch.c
@@ -11,7 +11,6 @@
 #include <asm/patch.h>
 #include <asm/processor.h>
 #include <asm/sections.h>
-#include <asm/system.h>
 #include <asm/unistd.h>
 
 /*
diff --git a/arch/ia64/kernel/pci-dma.c b/arch/ia64/kernel/pci-dma.c
index eb11757..7cdc89b 100644
--- a/arch/ia64/kernel/pci-dma.c
+++ b/arch/ia64/kernel/pci-dma.c
@@ -12,7 +12,6 @@
 #include <asm/machvec.h>
 #include <linux/dma-mapping.h>
 
-#include <asm/system.h>
 
 #ifdef CONFIG_INTEL_IOMMU
 
diff --git a/arch/ia64/kernel/pci-swiotlb.c b/arch/ia64/kernel/pci-swiotlb.c
index d9485d9..939260a 100644
--- a/arch/ia64/kernel/pci-swiotlb.c
+++ b/arch/ia64/kernel/pci-swiotlb.c
@@ -15,16 +15,24 @@
 EXPORT_SYMBOL(swiotlb);
 
 static void *ia64_swiotlb_alloc_coherent(struct device *dev, size_t size,
-					 dma_addr_t *dma_handle, gfp_t gfp)
+					 dma_addr_t *dma_handle, gfp_t gfp,
+					 struct dma_attrs *attrs)
 {
 	if (dev->coherent_dma_mask != DMA_BIT_MASK(64))
 		gfp |= GFP_DMA;
 	return swiotlb_alloc_coherent(dev, size, dma_handle, gfp);
 }
 
+static void ia64_swiotlb_free_coherent(struct device *dev, size_t size,
+				       void *vaddr, dma_addr_t dma_addr,
+				       struct dma_attrs *attrs)
+{
+	swiotlb_free_coherent(dev, size, vaddr, dma_addr);
+}
+
 struct dma_map_ops swiotlb_dma_ops = {
-	.alloc_coherent = ia64_swiotlb_alloc_coherent,
-	.free_coherent = swiotlb_free_coherent,
+	.alloc = ia64_swiotlb_alloc_coherent,
+	.free = ia64_swiotlb_free_coherent,
 	.map_page = swiotlb_map_page,
 	.unmap_page = swiotlb_unmap_page,
 	.map_sg = swiotlb_map_sg_attrs,
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index b2c65e0..9d0fd7d 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -49,7 +49,6 @@
 #include <asm/perfmon.h>
 #include <asm/processor.h>
 #include <asm/signal.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/delay.h>
 
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 9dc52b6..ce74e14 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -38,6 +38,7 @@
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
 #include <asm/sal.h>
+#include <asm/switch_to.h>
 #include <asm/tlbflush.h>
 #include <asm/uaccess.h>
 #include <asm/unwind.h>
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index dad9166..4265ff6 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -26,7 +26,6 @@
 #include <asm/processor.h>
 #include <asm/ptrace_offsets.h>
 #include <asm/rse.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/unwind.h>
 #ifdef CONFIG_PERFMON
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index cd57d73..aaefd9b 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -59,7 +59,6 @@
 #include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/smp.h>
-#include <asm/system.h>
 #include <asm/tlbflush.h>
 #include <asm/unistd.h>
 #include <asm/hpsim.h>
@@ -486,7 +485,7 @@
 {
 #ifdef CONFIG_SMP
 	/* If we register an early console, allow CPU 0 to printk */
-	cpu_set(smp_processor_id(), cpu_online_map);
+	set_cpu_online(smp_processor_id(), true);
 #endif
 }
 
diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
index 0bd537b..9fcd4e6 100644
--- a/arch/ia64/kernel/smp.c
+++ b/arch/ia64/kernel/smp.c
@@ -44,7 +44,6 @@
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/sal.h>
-#include <asm/system.h>
 #include <asm/tlbflush.h>
 #include <asm/unistd.h>
 #include <asm/mca.h>
@@ -77,7 +76,7 @@
 	/*
 	 * Remove this CPU:
 	 */
-	cpu_clear(smp_processor_id(), cpu_online_map);
+	set_cpu_online(smp_processor_id(), false);
 	max_xtp();
 	local_irq_disable();
 	cpu_halt();
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index 5590979..796f6a5 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -55,7 +55,6 @@
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/sal.h>
-#include <asm/system.h>
 #include <asm/tlbflush.h>
 #include <asm/unistd.h>
 #include <asm/sn/arch.h>
@@ -401,7 +400,7 @@
 	/* Setup the per cpu irq handling data structures */
 	__setup_vector_irq(cpuid);
 	notify_cpu_starting(cpuid);
-	cpu_set(cpuid, cpu_online_map);
+	set_cpu_online(cpuid, true);
 	per_cpu(cpu_state, cpuid) = CPU_ONLINE;
 	spin_unlock(&vector_lock);
 	ipi_call_unlock_irq();
@@ -548,7 +547,7 @@
 	if (!cpu_isset(cpu, cpu_callin_map)) {
 		printk(KERN_ERR "Processor 0x%x/0x%x is stuck.\n", cpu, sapicid);
 		ia64_cpu_to_sapicid[cpu] = -1;
-		cpu_clear(cpu, cpu_online_map);  /* was set in smp_callin() */
+		set_cpu_online(cpu, false);  /* was set in smp_callin() */
 		return -EINVAL;
 	}
 	return 0;
@@ -578,8 +577,7 @@
 	}
 
 	ia64_cpu_to_sapicid[0] = boot_cpu_id;
-	cpus_clear(cpu_present_map);
-	set_cpu_present(0, true);
+	init_cpu_present(cpumask_of(0));
 	set_cpu_possible(0, true);
 	for (cpu = 1, i = 0; i < smp_boot_data.cpu_count; i++) {
 		sapicid = smp_boot_data.cpu_phys_id[i];
@@ -606,10 +604,6 @@
 
 	smp_setup_percpu_timer();
 
-	/*
-	 * We have the boot CPU online for sure.
-	 */
-	cpu_set(0, cpu_online_map);
 	cpu_set(0, cpu_callin_map);
 
 	local_cpu_data->loops_per_jiffy = loops_per_jiffy;
@@ -633,7 +627,7 @@
 
 void __devinit smp_prepare_boot_cpu(void)
 {
-	cpu_set(smp_processor_id(), cpu_online_map);
+	set_cpu_online(smp_processor_id(), true);
 	cpu_set(smp_processor_id(), cpu_callin_map);
 	set_numa_node(cpu_to_node_map[smp_processor_id()]);
 	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
@@ -690,7 +684,7 @@
 			/*
 			 * Now re-target the CPEI to a different processor
 			 */
-			new_cpei_cpu = any_online_cpu(cpu_online_map);
+			new_cpei_cpu = cpumask_any(cpu_online_mask);
 			mask = cpumask_of(new_cpei_cpu);
 			set_cpei_target_cpu(new_cpei_cpu);
 			data = irq_get_irq_data(ia64_cpe_irq);
@@ -732,10 +726,10 @@
 			return -EBUSY;
 	}
 
-	cpu_clear(cpu, cpu_online_map);
+	set_cpu_online(cpu, false);
 
 	if (migrate_platform_irqs(cpu)) {
-		cpu_set(cpu, cpu_online_map);
+		set_cpu_online(cpu, true);
 		return -EBUSY;
 	}
 
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 43920de..ecc904b 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -29,15 +29,12 @@
 #include <asm/ptrace.h>
 #include <asm/sal.h>
 #include <asm/sections.h>
-#include <asm/system.h>
 
 #include "fsyscall_gtod_data.h"
 
 static cycle_t itc_get_cycles(struct clocksource *cs);
 
-struct fsyscall_gtod_data_t fsyscall_gtod_data = {
-	.lock = __SEQLOCK_UNLOCKED(fsyscall_gtod_data.lock),
-};
+struct fsyscall_gtod_data_t fsyscall_gtod_data;
 
 struct itc_jitter_data_t itc_jitter_data;
 
@@ -460,9 +457,7 @@
 void update_vsyscall(struct timespec *wall, struct timespec *wtm,
 			struct clocksource *c, u32 mult)
 {
-        unsigned long flags;
-
-        write_seqlock_irqsave(&fsyscall_gtod_data.lock, flags);
+	write_seqcount_begin(&fsyscall_gtod_data.seq);
 
         /* copy fsyscall clock data */
         fsyscall_gtod_data.clk_mask = c->mask;
@@ -485,6 +480,6 @@
 		fsyscall_gtod_data.monotonic_time.tv_sec++;
 	}
 
-        write_sequnlock_irqrestore(&fsyscall_gtod_data.lock, flags);
+	write_seqcount_end(&fsyscall_gtod_data.seq);
 }
 
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
index 9deb21d..c64460b 100644
--- a/arch/ia64/kernel/topology.c
+++ b/arch/ia64/kernel/topology.c
@@ -220,7 +220,8 @@
 	ssize_t	len;
 	cpumask_t shared_cpu_map;
 
-	cpus_and(shared_cpu_map, this_leaf->shared_cpu_map, cpu_online_map);
+	cpumask_and(&shared_cpu_map,
+				&this_leaf->shared_cpu_map, cpu_online_mask);
 	len = cpumask_scnprintf(buf, NR_CPUS+1, &shared_cpu_map);
 	len += sprintf(buf+len, "\n");
 	return len;
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index fd80e70..bd42b76 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -22,6 +22,7 @@
 #include <asm/intrinsics.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
+#include <asm/setup.h>
 
 fpswa_interface_t *fpswa_interface;
 EXPORT_SYMBOL(fpswa_interface);
diff --git a/arch/ia64/kernel/uncached.c b/arch/ia64/kernel/uncached.c
index 6a867dc..a96bcf8 100644
--- a/arch/ia64/kernel/uncached.c
+++ b/arch/ia64/kernel/uncached.c
@@ -23,7 +23,6 @@
 #include <linux/gfp.h>
 #include <asm/page.h>
 #include <asm/pal.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <linux/atomic.h>
 #include <asm/tlbflush.h>
diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c
index fed6afa..8f66195 100644
--- a/arch/ia64/kernel/unwind.c
+++ b/arch/ia64/kernel/unwind.c
@@ -41,7 +41,6 @@
 #include <asm/ptrace_offsets.h>
 #include <asm/rse.h>
 #include <asm/sections.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 #include "entry.h"
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 53c0ba0..0ccb28f 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -1,7 +1,6 @@
 
 #include <asm/cache.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 
 #include <asm-generic/vmlinux.lds.h>
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 4050520..f5104b7 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -809,10 +809,13 @@
 #define GUEST_PHYSICAL_RR4	0x2739
 #define VMM_INIT_RR		0x1660
 
-int kvm_arch_init_vm(struct kvm *kvm)
+int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
 	BUG_ON(!kvm);
 
+	if (type)
+		return -EINVAL;
+
 	kvm->arch.is_sn2 = ia64_platform_is("sn2");
 
 	kvm->arch.metaphysical_rr0 = GUEST_PHYSICAL_RR0;
@@ -1169,6 +1172,11 @@
 
 #define PALE_RESET_ENTRY    0x80000000ffffffb0UL
 
+bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu)
+{
+	return irqchip_in_kernel(vcpu->kcm) == (vcpu->arch.apic != NULL);
+}
+
 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 {
 	struct kvm_vcpu *v;
@@ -1563,6 +1571,21 @@
 	return r;
 }
 
+int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
+{
+	return VM_FAULT_SIGBUS;
+}
+
+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)
+{
+	return 0;
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
 		struct kvm_memory_slot *memslot,
 		struct kvm_memory_slot old,
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
index 20b3593..02d29c2 100644
--- a/arch/ia64/mm/fault.c
+++ b/arch/ia64/mm/fault.c
@@ -14,7 +14,6 @@
 
 #include <asm/pgtable.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 extern int die(char *, struct pt_regs *, long);
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 13df239d..0eab454 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -30,7 +30,6 @@
 #include <asm/pgalloc.h>
 #include <asm/sal.h>
 #include <asm/sections.h>
-#include <asm/system.h>
 #include <asm/tlb.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
diff --git a/arch/ia64/oprofile/backtrace.c b/arch/ia64/oprofile/backtrace.c
index f7b7989..6a219a9 100644
--- a/arch/ia64/oprofile/backtrace.c
+++ b/arch/ia64/oprofile/backtrace.c
@@ -14,7 +14,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 
 /*
  * For IA64 we need to perform a complex little dance to get both
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index f82f5d4..524df42 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -24,7 +24,6 @@
 
 #include <asm/machvec.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/sal.h>
 #include <asm/smp.h>
@@ -320,7 +319,8 @@
 	 * Ignore these tiny memory ranges */
 	if (!((window->resource.flags & IORESOURCE_MEM) &&
 	      (window->resource.end - window->resource.start < 16)))
-		pci_add_resource(&info->resources, &window->resource);
+		pci_add_resource_offset(&info->resources, &window->resource,
+					window->offset);
 
 	return AE_OK;
 }
@@ -395,54 +395,6 @@
 	return NULL;
 }
 
-void pcibios_resource_to_bus(struct pci_dev *dev,
-		struct pci_bus_region *region, struct resource *res)
-{
-	struct pci_controller *controller = PCI_CONTROLLER(dev);
-	unsigned long offset = 0;
-	int i;
-
-	for (i = 0; i < controller->windows; i++) {
-		struct pci_window *window = &controller->window[i];
-		if (!(window->resource.flags & res->flags))
-			continue;
-		if (window->resource.start > res->start)
-			continue;
-		if (window->resource.end < res->end)
-			continue;
-		offset = window->offset;
-		break;
-	}
-
-	region->start = res->start - offset;
-	region->end = res->end - offset;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void pcibios_bus_to_resource(struct pci_dev *dev,
-		struct resource *res, struct pci_bus_region *region)
-{
-	struct pci_controller *controller = PCI_CONTROLLER(dev);
-	unsigned long offset = 0;
-	int i;
-
-	for (i = 0; i < controller->windows; i++) {
-		struct pci_window *window = &controller->window[i];
-		if (!(window->resource.flags & res->flags))
-			continue;
-		if (window->resource.start - window->offset > region->start)
-			continue;
-		if (window->resource.end - window->offset < region->end)
-			continue;
-		offset = window->offset;
-		break;
-	}
-
-	res->start = region->start + offset;
-	res->end = region->end + offset;
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
 static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
 {
 	unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
@@ -464,15 +416,11 @@
 static void __devinit
 pcibios_fixup_resources(struct pci_dev *dev, int start, int limit)
 {
-	struct pci_bus_region region;
 	int i;
 
 	for (i = start; i < limit; i++) {
 		if (!dev->resource[i].flags)
 			continue;
-		region.start = dev->resource[i].start;
-		region.end = dev->resource[i].end;
-		pcibios_bus_to_resource(dev, &dev->resource[i], &region);
 		if ((is_valid_resource(dev, i)))
 			pci_claim_resource(dev, i);
 	}
diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c
index 08b0d9b..f925dec 100644
--- a/arch/ia64/sn/kernel/huberror.c
+++ b/arch/ia64/sn/kernel/huberror.c
@@ -192,6 +192,7 @@
 		    hubdev_info);
 		return;
 	}
+	irq_set_handler(SGI_II_ERROR, handle_level_irq);
 	sn_set_err_irq_affinity(SGI_II_ERROR);
 }
 
@@ -213,6 +214,7 @@
                        hubdev_info);
 		return;
 	}
+	irq_set_handler(SGI_TIO_ERROR, handle_level_irq);
 	sn_set_err_irq_affinity(SGI_TIO_ERROR);
 }
 
diff --git a/arch/ia64/sn/kernel/io_common.c b/arch/ia64/sn/kernel/io_common.c
index 4433dd0..fbb5f2f 100644
--- a/arch/ia64/sn/kernel/io_common.c
+++ b/arch/ia64/sn/kernel/io_common.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/bootmem.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <asm/sn/types.h>
 #include <asm/sn/addrs.h>
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index 0a36f08..238e2c5 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -297,7 +297,8 @@
 	s64 status = 0;
 	struct pci_controller *controller;
 	struct pcibus_bussoft *prom_bussoft_ptr;
-
+	LIST_HEAD(resources);
+	int i;
 
  	status = sal_get_pcibus_info((u64) segment, (u64) busnum,
  				     (u64) ia64_tpa(&prom_bussoft_ptr));
@@ -315,7 +316,15 @@
 	 */
 	controller->platform_data = prom_bussoft_ptr;
 
-	bus = pci_scan_bus(busnum, &pci_root_ops, controller);
+	sn_legacy_pci_window_fixup(controller,
+				   prom_bussoft_ptr->bs_legacy_io,
+				   prom_bussoft_ptr->bs_legacy_mem);
+	for (i = 0; i < controller->windows; i++)
+		pci_add_resource_offset(&resources,
+					&controller->window[i].resource,
+					controller->window[i].offset);
+	bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, controller,
+				&resources);
  	if (bus == NULL)
  		goto error_return; /* error, or bus already scanned */
 
@@ -348,9 +357,6 @@
 			return;
 		}
 		sn_common_bus_fixup(bus, prom_bussoft_ptr);
-		sn_legacy_pci_window_fixup(PCI_CONTROLLER(bus),
-					   prom_bussoft_ptr->bs_legacy_io,
-					   prom_bussoft_ptr->bs_legacy_mem);
         }
         list_for_each_entry(pci_dev, &bus->devices, bus_list) {
                 sn_io_slot_fixup(pci_dev);
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
index dfac09a..62cf4dd 100644
--- a/arch/ia64/sn/kernel/irq.c
+++ b/arch/ia64/sn/kernel/irq.c
@@ -352,6 +352,8 @@
 	spin_lock(&sn_irq_info_lock);
 	list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]);
 	reserve_irq_vector(sn_irq_info->irq_irq);
+	if (sn_irq_info->irq_int_bit != -1)
+		irq_set_handler(sn_irq_info->irq_irq, handle_level_irq);
 	spin_unlock(&sn_irq_info_lock);
 
 	register_intr_pda(sn_irq_info);
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index 77db0b5..f82e7b4 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -33,9 +33,9 @@
 #include <asm/io.h>
 #include <asm/sal.h>
 #include <asm/machvec.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/vga.h>
+#include <asm/setup.h>
 #include <asm/sn/arch.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/pda.h>
diff --git a/arch/ia64/sn/kernel/sn2/prominfo_proc.c b/arch/ia64/sn/kernel/sn2/prominfo_proc.c
index e633288..20b88cb 100644
--- a/arch/ia64/sn/kernel/sn2/prominfo_proc.c
+++ b/arch/ia64/sn/kernel/sn2/prominfo_proc.c
@@ -12,7 +12,6 @@
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
 #include <linux/nodemask.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/sn_cpuid.h>
diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c
index e884ba4..68c8454 100644
--- a/arch/ia64/sn/kernel/sn2/sn2_smp.c
+++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c
@@ -26,7 +26,6 @@
 #include <asm/processor.h>
 #include <asm/irq.h>
 #include <asm/sal.h>
-#include <asm/system.h>
 #include <asm/delay.h>
 #include <asm/io.h>
 #include <asm/smp.h>
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
index 2de41d4..4554f68 100644
--- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c
+++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
@@ -25,6 +25,7 @@
 
 #include <linux/fs.h>
 #include <linux/slab.h>
+#include <linux/export.h>
 #include <linux/vmalloc.h>
 #include <linux/seq_file.h>
 #include <linux/miscdevice.h>
diff --git a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c
index 0f8844e..abab8f9 100644
--- a/arch/ia64/sn/kernel/sn2/timer.c
+++ b/arch/ia64/sn/kernel/sn2/timer.c
@@ -14,7 +14,6 @@
 #include <linux/clocksource.h>
 
 #include <asm/hw_irq.h>
-#include <asm/system.h>
 #include <asm/timex.h>
 
 #include <asm/sn/leds.h>
diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c
index c1bd1cf..14c1711 100644
--- a/arch/ia64/sn/kernel/tiocx.c
+++ b/arch/ia64/sn/kernel/tiocx.c
@@ -14,7 +14,6 @@
 #include <linux/capability.h>
 #include <linux/device.h>
 #include <linux/delay.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/addrs.h>
@@ -191,6 +190,7 @@
 		   struct hubdev_info *hubdev, int bt)
 {
 	struct cx_dev *cx_dev;
+	int r;
 
 	cx_dev = kzalloc(sizeof(struct cx_dev), GFP_KERNEL);
 	DBG("cx_dev= 0x%p\n", cx_dev);
@@ -207,7 +207,11 @@
 	cx_dev->dev.bus = &tiocx_bus_type;
 	cx_dev->dev.release = tiocx_bus_release;
 	dev_set_name(&cx_dev->dev, "%d", cx_dev->cx_id.nasid);
-	device_register(&cx_dev->dev);
+	r = device_register(&cx_dev->dev);
+	if (r) {
+		kfree(cx_dev);
+		return r;
+	}
 	get_device(&cx_dev->dev);
 
 	device_create_file(&cx_dev->dev, &dev_attr_cxdev_control);
diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c
index a9d310d..3290d6e 100644
--- a/arch/ia64/sn/pci/pci_dma.c
+++ b/arch/ia64/sn/pci/pci_dma.c
@@ -76,7 +76,8 @@
  * more information.
  */
 static void *sn_dma_alloc_coherent(struct device *dev, size_t size,
-				   dma_addr_t * dma_handle, gfp_t flags)
+				   dma_addr_t * dma_handle, gfp_t flags,
+				   struct dma_attrs *attrs)
 {
 	void *cpuaddr;
 	unsigned long phys_addr;
@@ -137,7 +138,7 @@
  * any associated IOMMU mappings.
  */
 static void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-				 dma_addr_t dma_handle)
+				 dma_addr_t dma_handle, struct dma_attrs *attrs)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
@@ -466,8 +467,8 @@
 }
 
 static struct dma_map_ops sn_dma_ops = {
-	.alloc_coherent		= sn_dma_alloc_coherent,
-	.free_coherent		= sn_dma_free_coherent,
+	.alloc			= sn_dma_alloc_coherent,
+	.free			= sn_dma_free_coherent,
 	.map_page		= sn_dma_map_page,
 	.unmap_page		= sn_dma_unmap_page,
 	.map_sg			= sn_dma_map_sg,
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
index 8886a0b..8dbbef4 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -146,6 +146,7 @@
 		printk(KERN_WARNING
 		       "pcibr cannot allocate interrupt for error handler\n");
 	}
+	irq_set_handler(SGI_PCIASIC_ERROR, handle_level_irq);
 	sn_set_err_irq_affinity(SGI_PCIASIC_ERROR);
 
 	/* 
diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c
index e77c477..a70b11f 100644
--- a/arch/ia64/sn/pci/tioca_provider.c
+++ b/arch/ia64/sn/pci/tioca_provider.c
@@ -649,6 +649,7 @@
 		       __func__, SGI_TIOCA_ERROR,
 		       (int)tioca_common->ca_common.bs_persist_busnum);
 
+	irq_set_handler(SGI_TIOCA_ERROR, handle_level_irq);
 	sn_set_err_irq_affinity(SGI_TIOCA_ERROR);
 
 	/* Setup locality information */
diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c
index 27faba0..46d3df4 100644
--- a/arch/ia64/sn/pci/tioce_provider.c
+++ b/arch/ia64/sn/pci/tioce_provider.c
@@ -1037,6 +1037,7 @@
 		       tioce_common->ce_pcibus.bs_persist_segment,
 		       tioce_common->ce_pcibus.bs_persist_busnum);
 
+	irq_set_handler(SGI_PCIASIC_ERROR, handle_level_irq);
 	sn_set_err_irq_affinity(SGI_PCIASIC_ERROR);
 	return tioce_common;
 }
diff --git a/arch/ia64/xen/xensetup.S b/arch/ia64/xen/xensetup.S
index b820ed0..e29519e 100644
--- a/arch/ia64/xen/xensetup.S
+++ b/arch/ia64/xen/xensetup.S
@@ -7,7 +7,6 @@
 #include <asm/processor.h>
 #include <asm/asmmacro.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/paravirt.h>
 #include <asm/xen/privop.h>
 #include <linux/elfnote.h>
diff --git a/arch/m32r/include/asm/atomic.h b/arch/m32r/include/asm/atomic.h
index 1e7f29f..0d81697 100644
--- a/arch/m32r/include/asm/atomic.h
+++ b/arch/m32r/include/asm/atomic.h
@@ -11,7 +11,8 @@
 
 #include <linux/types.h>
 #include <asm/assembler.h>
-#include <asm/system.h>
+#include <asm/cmpxchg.h>
+#include <asm/dcache_clear.h>
 
 /*
  * Atomic operations that C can't guarantee us.  Useful for
diff --git a/arch/m32r/include/asm/barrier.h b/arch/m32r/include/asm/barrier.h
new file mode 100644
index 0000000..6976621
--- /dev/null
+++ b/arch/m32r/include/asm/barrier.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2001  Hiroyuki Kondo, Hirokazu Takata, and Hitoshi Yamamoto
+ * Copyright (C) 2004, 2006  Hirokazu Takata <takata at linux-m32r.org>
+ */
+#ifndef _ASM_M32R_BARRIER_H
+#define _ASM_M32R_BARRIER_H
+
+#define nop()  __asm__ __volatile__ ("nop" : : )
+
+/*
+ * Memory barrier.
+ *
+ * mb() prevents loads and stores being reordered across this point.
+ * rmb() prevents loads being reordered across this point.
+ * wmb() prevents stores being reordered across this point.
+ */
+#define mb()   barrier()
+#define rmb()  mb()
+#define wmb()  mb()
+
+/**
+ * read_barrier_depends - Flush all pending reads that subsequents reads
+ * depend on.
+ *
+ * No data-dependent reads from memory-like regions are ever reordered
+ * over this barrier.  All reads preceding this primitive are guaranteed
+ * to access memory (but not necessarily other CPUs' caches) before any
+ * reads following this primitive that depend on the data return by
+ * any of the preceding reads.  This primitive is much lighter weight than
+ * rmb() on most CPUs, and is never heavier weight than is
+ * rmb().
+ *
+ * These ordering constraints are respected by both the local CPU
+ * and the compiler.
+ *
+ * Ordering is not guaranteed by anything other than these primitives,
+ * not even by data dependencies.  See the documentation for
+ * memory_barrier() for examples and URLs to more information.
+ *
+ * For example, the following code would force ordering (the initial
+ * value of "a" is zero, "b" is one, and "p" is "&a"):
+ *
+ * <programlisting>
+ *      CPU 0                           CPU 1
+ *
+ *      b = 2;
+ *      memory_barrier();
+ *      p = &b;                         q = p;
+ *                                      read_barrier_depends();
+ *                                      d = *q;
+ * </programlisting>
+ *
+ *
+ * because the read of "*q" depends on the read of "p" and these
+ * two reads are separated by a read_barrier_depends().  However,
+ * the following code, with the same initial values for "a" and "b":
+ *
+ * <programlisting>
+ *      CPU 0                           CPU 1
+ *
+ *      a = 2;
+ *      memory_barrier();
+ *      b = 3;                          y = b;
+ *                                      read_barrier_depends();
+ *                                      x = a;
+ * </programlisting>
+ *
+ * does not enforce ordering, since there is no data dependency between
+ * the read of "a" and the read of "b".  Therefore, on some CPUs, such
+ * as Alpha, "y" could be set to 3 and "x" to 0.  Use rmb()
+ * in cases like this where there are no data dependencies.
+ **/
+
+#define read_barrier_depends()	do { } while (0)
+
+#ifdef CONFIG_SMP
+#define smp_mb()	mb()
+#define smp_rmb()	rmb()
+#define smp_wmb()	wmb()
+#define smp_read_barrier_depends()	read_barrier_depends()
+#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
+#else
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+#define smp_read_barrier_depends()	do { } while (0)
+#define set_mb(var, value) do { var = value; barrier(); } while (0)
+#endif
+
+#endif /* _ASM_M32R_BARRIER_H */
diff --git a/arch/m32r/include/asm/bitops.h b/arch/m32r/include/asm/bitops.h
index 6300f22..d3dea9a 100644
--- a/arch/m32r/include/asm/bitops.h
+++ b/arch/m32r/include/asm/bitops.h
@@ -16,9 +16,10 @@
 #endif
 
 #include <linux/compiler.h>
+#include <linux/irqflags.h>
 #include <asm/assembler.h>
-#include <asm/system.h>
 #include <asm/byteorder.h>
+#include <asm/dcache_clear.h>
 #include <asm/types.h>
 
 /*
diff --git a/arch/m32r/include/asm/cmpxchg.h b/arch/m32r/include/asm/cmpxchg.h
new file mode 100644
index 0000000..de651db
--- /dev/null
+++ b/arch/m32r/include/asm/cmpxchg.h
@@ -0,0 +1,221 @@
+#ifndef _ASM_M32R_CMPXCHG_H
+#define _ASM_M32R_CMPXCHG_H
+
+/*
+ *  M32R version:
+ *    Copyright (C) 2001, 2002  Hitoshi Yamamoto
+ *    Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ */
+
+#include <linux/irqflags.h>
+#include <asm/assembler.h>
+#include <asm/dcache_clear.h>
+
+extern void  __xchg_called_with_bad_pointer(void);
+
+static __always_inline unsigned long
+__xchg(unsigned long x, volatile void *ptr, int size)
+{
+	unsigned long flags;
+	unsigned long tmp = 0;
+
+	local_irq_save(flags);
+
+	switch (size) {
+#ifndef CONFIG_SMP
+	case 1:
+		__asm__ __volatile__ (
+			"ldb	%0, @%2 \n\t"
+			"stb	%1, @%2 \n\t"
+			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
+		break;
+	case 2:
+		__asm__ __volatile__ (
+			"ldh	%0, @%2 \n\t"
+			"sth	%1, @%2 \n\t"
+			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
+		break;
+	case 4:
+		__asm__ __volatile__ (
+			"ld	%0, @%2 \n\t"
+			"st	%1, @%2 \n\t"
+			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
+		break;
+#else  /* CONFIG_SMP */
+	case 4:
+		__asm__ __volatile__ (
+			DCACHE_CLEAR("%0", "r4", "%2")
+			"lock	%0, @%2;	\n\t"
+			"unlock	%1, @%2;	\n\t"
+			: "=&r" (tmp) : "r" (x), "r" (ptr)
+			: "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+			, "r4"
+#endif	/* CONFIG_CHIP_M32700_TS1 */
+		);
+		break;
+#endif  /* CONFIG_SMP */
+	default:
+		__xchg_called_with_bad_pointer();
+	}
+
+	local_irq_restore(flags);
+
+	return (tmp);
+}
+
+#define xchg(ptr, x)							\
+	((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
+
+static __always_inline unsigned long
+__xchg_local(unsigned long x, volatile void *ptr, int size)
+{
+	unsigned long flags;
+	unsigned long tmp = 0;
+
+	local_irq_save(flags);
+
+	switch (size) {
+	case 1:
+		__asm__ __volatile__ (
+			"ldb	%0, @%2 \n\t"
+			"stb	%1, @%2 \n\t"
+			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
+		break;
+	case 2:
+		__asm__ __volatile__ (
+			"ldh	%0, @%2 \n\t"
+			"sth	%1, @%2 \n\t"
+			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
+		break;
+	case 4:
+		__asm__ __volatile__ (
+			"ld	%0, @%2 \n\t"
+			"st	%1, @%2 \n\t"
+			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
+		break;
+	default:
+		__xchg_called_with_bad_pointer();
+	}
+
+	local_irq_restore(flags);
+
+	return (tmp);
+}
+
+#define xchg_local(ptr, x)						\
+	((__typeof__(*(ptr)))__xchg_local((unsigned long)(x), (ptr),	\
+			sizeof(*(ptr))))
+
+#define __HAVE_ARCH_CMPXCHG	1
+
+static inline unsigned long
+__cmpxchg_u32(volatile unsigned int *p, unsigned int old, unsigned int new)
+{
+	unsigned long flags;
+	unsigned int retval;
+
+	local_irq_save(flags);
+	__asm__ __volatile__ (
+			DCACHE_CLEAR("%0", "r4", "%1")
+			M32R_LOCK" %0, @%1;	\n"
+		"	bne	%0, %2, 1f;	\n"
+			M32R_UNLOCK" %3, @%1;	\n"
+		"	bra	2f;		\n"
+                "       .fillinsn		\n"
+		"1:"
+			M32R_UNLOCK" %0, @%1;	\n"
+                "       .fillinsn		\n"
+		"2:"
+			: "=&r" (retval)
+			: "r" (p), "r" (old), "r" (new)
+			: "cbit", "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+			, "r4"
+#endif  /* CONFIG_CHIP_M32700_TS1 */
+		);
+	local_irq_restore(flags);
+
+	return retval;
+}
+
+static inline unsigned long
+__cmpxchg_local_u32(volatile unsigned int *p, unsigned int old,
+			unsigned int new)
+{
+	unsigned long flags;
+	unsigned int retval;
+
+	local_irq_save(flags);
+	__asm__ __volatile__ (
+			DCACHE_CLEAR("%0", "r4", "%1")
+			"ld %0, @%1;		\n"
+		"	bne	%0, %2, 1f;	\n"
+			"st %3, @%1;		\n"
+		"	bra	2f;		\n"
+		"       .fillinsn		\n"
+		"1:"
+			"st %0, @%1;		\n"
+		"       .fillinsn		\n"
+		"2:"
+			: "=&r" (retval)
+			: "r" (p), "r" (old), "r" (new)
+			: "cbit", "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+			, "r4"
+#endif  /* CONFIG_CHIP_M32700_TS1 */
+		);
+	local_irq_restore(flags);
+
+	return retval;
+}
+
+/* This function doesn't exist, so you'll get a linker error
+   if something tries to do an invalid cmpxchg().  */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+static inline unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32(ptr, old, new);
+#if 0	/* we don't have __cmpxchg_u64 */
+	case 8:
+		return __cmpxchg_u64(ptr, old, new);
+#endif /* 0 */
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg(ptr, o, n)						 \
+	((__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)(o),	 \
+			(unsigned long)(n), sizeof(*(ptr))))
+
+#include <asm-generic/cmpxchg-local.h>
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+				      unsigned long old,
+				      unsigned long new, int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_local_u32(ptr, old, new);
+	default:
+		return __cmpxchg_local_generic(ptr, old, new, size);
+	}
+
+	return old;
+}
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)				  	    \
+	((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o),	    \
+			(unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#endif /* _ASM_M32R_CMPXCHG_H */
diff --git a/arch/m32r/include/asm/dcache_clear.h b/arch/m32r/include/asm/dcache_clear.h
new file mode 100644
index 0000000..a0ae06c
--- /dev/null
+++ b/arch/m32r/include/asm/dcache_clear.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2001  Hiroyuki Kondo, Hirokazu Takata, and Hitoshi Yamamoto
+ * Copyright (C) 2004, 2006  Hirokazu Takata <takata at linux-m32r.org>
+ */
+#ifndef _ASM_M32R_DCACHE_CLEAR_H
+#define _ASM_M32R_DCACHE_CLEAR_H
+
+#ifdef CONFIG_CHIP_M32700_TS1
+#define DCACHE_CLEAR(reg0, reg1, addr)				\
+	"seth	"reg1", #high(dcache_dummy);		\n\t"	\
+	"or3	"reg1", "reg1", #low(dcache_dummy);	\n\t"	\
+	"lock	"reg0", @"reg1";			\n\t"	\
+	"add3	"reg0", "addr", #0x1000;		\n\t"	\
+	"ld	"reg0", @"reg0";			\n\t"	\
+	"add3	"reg0", "addr", #0x2000;		\n\t"	\
+	"ld	"reg0", @"reg0";			\n\t"	\
+	"unlock	"reg0", @"reg1";			\n\t"
+	/* FIXME: This workaround code cannot handle kernel modules
+	 * correctly under SMP environment.
+	 */
+#else	/* CONFIG_CHIP_M32700_TS1 */
+#define DCACHE_CLEAR(reg0, reg1, addr)
+#endif	/* CONFIG_CHIP_M32700_TS1 */
+
+#endif /* _ASM_M32R_DCACHE_CLEAR_H */
diff --git a/arch/m32r/include/asm/exec.h b/arch/m32r/include/asm/exec.h
new file mode 100644
index 0000000..c805dbd
--- /dev/null
+++ b/arch/m32r/include/asm/exec.h
@@ -0,0 +1,14 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2001  Hiroyuki Kondo, Hirokazu Takata, and Hitoshi Yamamoto
+ * Copyright (C) 2004, 2006  Hirokazu Takata <takata at linux-m32r.org>
+ */
+#ifndef _ASM_M32R_EXEC_H
+#define _ASM_M32R_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* _ASM_M32R_EXEC_H */
diff --git a/arch/m32r/include/asm/local.h b/arch/m32r/include/asm/local.h
index 734bca8..4045db3 100644
--- a/arch/m32r/include/asm/local.h
+++ b/arch/m32r/include/asm/local.h
@@ -12,7 +12,6 @@
 
 #include <linux/percpu.h>
 #include <asm/assembler.h>
-#include <asm/system.h>
 #include <asm/local.h>
 
 /*
diff --git a/arch/m32r/include/asm/posix_types.h b/arch/m32r/include/asm/posix_types.h
index b309c58..0195850 100644
--- a/arch/m32r/include/asm/posix_types.h
+++ b/arch/m32r/include/asm/posix_types.h
@@ -7,112 +7,22 @@
  * assume GCC is being used.
  */
 
-typedef unsigned long	__kernel_ino_t;
 typedef unsigned short	__kernel_mode_t;
+#define __kernel_mode_t __kernel_mode_t
+
 typedef unsigned short	__kernel_nlink_t;
-typedef long		__kernel_off_t;
-typedef int		__kernel_pid_t;
+#define __kernel_nlink_t __kernel_nlink_t
+
 typedef unsigned short	__kernel_ipc_pid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
+
 typedef unsigned short	__kernel_uid_t;
 typedef unsigned short	__kernel_gid_t;
-typedef unsigned int	__kernel_size_t;
-typedef int		__kernel_ssize_t;
-typedef int		__kernel_ptrdiff_t;
-typedef long		__kernel_time_t;
-typedef long		__kernel_suseconds_t;
-typedef long		__kernel_clock_t;
-typedef int		__kernel_timer_t;
-typedef int		__kernel_clockid_t;
-typedef int		__kernel_daddr_t;
-typedef char *		__kernel_caddr_t;
-typedef unsigned short	__kernel_uid16_t;
-typedef unsigned short	__kernel_gid16_t;
-typedef unsigned int	__kernel_uid32_t;
-typedef unsigned int	__kernel_gid32_t;
+#define __kernel_uid_t __kernel_uid_t
 
-typedef unsigned short	__kernel_old_uid_t;
-typedef unsigned short	__kernel_old_gid_t;
 typedef unsigned short	__kernel_old_dev_t;
+#define __kernel_old_dev_t __kernel_old_dev_t
 
-#ifdef __GNUC__
-typedef long long	__kernel_loff_t;
-#endif
-
-typedef struct {
-	int	val[2];
-} __kernel_fsid_t;
-
-#if defined(__KERNEL__)
-
-#undef	__FD_SET
-static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-	unsigned long __tmp = __fd / __NFDBITS;
-	unsigned long __rem = __fd % __NFDBITS;
-	__fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
-}
-
-#undef	__FD_CLR
-static __inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-	unsigned long __tmp = __fd / __NFDBITS;
-	unsigned long __rem = __fd % __NFDBITS;
-	__fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
-}
-
-
-#undef	__FD_ISSET
-static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
-{
-	unsigned long __tmp = __fd / __NFDBITS;
-	unsigned long __rem = __fd % __NFDBITS;
-	return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
-}
-
-/*
- * This will unroll the loop for the normal constant case (8 ints,
- * for a 256-bit fd_set)
- */
-#undef	__FD_ZERO
-static __inline__ void __FD_ZERO(__kernel_fd_set *__p)
-{
-	unsigned long *__tmp = __p->fds_bits;
-	int __i;
-
-	if (__builtin_constant_p(__FDSET_LONGS)) {
-		switch (__FDSET_LONGS) {
-		case 16:
-			__tmp[ 0] = 0; __tmp[ 1] = 0;
-			__tmp[ 2] = 0; __tmp[ 3] = 0;
-			__tmp[ 4] = 0; __tmp[ 5] = 0;
-			__tmp[ 6] = 0; __tmp[ 7] = 0;
-			__tmp[ 8] = 0; __tmp[ 9] = 0;
-			__tmp[10] = 0; __tmp[11] = 0;
-			__tmp[12] = 0; __tmp[13] = 0;
-			__tmp[14] = 0; __tmp[15] = 0;
-			return;
-
-		case 8:
-			__tmp[ 0] = 0; __tmp[ 1] = 0;
-			__tmp[ 2] = 0; __tmp[ 3] = 0;
-			__tmp[ 4] = 0; __tmp[ 5] = 0;
-			__tmp[ 6] = 0; __tmp[ 7] = 0;
-			return;
-
-		case 4:
-			__tmp[ 0] = 0; __tmp[ 1] = 0;
-			__tmp[ 2] = 0; __tmp[ 3] = 0;
-			return;
-		}
-	}
-	__i = __FDSET_LONGS;
-	while (__i) {
-		__i--;
-		*__tmp = 0;
-		__tmp++;
-	}
-}
-
-#endif /* defined(__KERNEL__) */
+#include <asm-generic/posix_types.h>
 
 #endif  /* _ASM_M32R_POSIX_TYPES_H */
diff --git a/arch/m32r/include/asm/spinlock.h b/arch/m32r/include/asm/spinlock.h
index b0ea2f2..fa13694 100644
--- a/arch/m32r/include/asm/spinlock.h
+++ b/arch/m32r/include/asm/spinlock.h
@@ -11,6 +11,7 @@
 
 #include <linux/compiler.h>
 #include <linux/atomic.h>
+#include <asm/dcache_clear.h>
 #include <asm/page.h>
 
 /*
diff --git a/arch/m32r/include/asm/switch_to.h b/arch/m32r/include/asm/switch_to.h
new file mode 100644
index 0000000..4b262f7
--- /dev/null
+++ b/arch/m32r/include/asm/switch_to.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2001  Hiroyuki Kondo, Hirokazu Takata, and Hitoshi Yamamoto
+ * Copyright (C) 2004, 2006  Hirokazu Takata <takata at linux-m32r.org>
+ */
+#ifndef _ASM_M32R_SWITCH_TO_H
+#define _ASM_M32R_SWITCH_TO_H
+
+/*
+ * switch_to(prev, next) should switch from task `prev' to `next'
+ * `prev' will never be the same as `next'.
+ *
+ * `next' and `prev' should be struct task_struct, but it isn't always defined
+ */
+
+#if defined(CONFIG_FRAME_POINTER) || \
+	!defined(CONFIG_SCHED_OMIT_FRAME_POINTER)
+#define M32R_PUSH_FP "	push fp\n"
+#define M32R_POP_FP  "	pop  fp\n"
+#else
+#define M32R_PUSH_FP ""
+#define M32R_POP_FP  ""
+#endif
+
+#define switch_to(prev, next, last)  do { \
+	__asm__ __volatile__ ( \
+		"	seth	lr, #high(1f)				\n" \
+		"	or3	lr, lr, #low(1f)			\n" \
+		"	st	lr, @%4  ; store old LR			\n" \
+		"	ld	lr, @%5  ; load new LR			\n" \
+			M32R_PUSH_FP \
+		"	st	sp, @%2  ; store old SP			\n" \
+		"	ld	sp, @%3  ; load new SP			\n" \
+		"	push	%1  ; store `prev' on new stack		\n" \
+		"	jmp	lr					\n" \
+		"	.fillinsn					\n" \
+		"1:							\n" \
+		"	pop	%0  ; restore `__last' from new stack	\n" \
+			M32R_POP_FP \
+		: "=r" (last) \
+		: "0" (prev), \
+		  "r" (&(prev->thread.sp)), "r" (&(next->thread.sp)), \
+		  "r" (&(prev->thread.lr)), "r" (&(next->thread.lr)) \
+		: "memory", "lr" \
+	); \
+} while(0)
+
+#endif /* _ASM_M32R_SWITCH_TO_H */
diff --git a/arch/m32r/include/asm/system.h b/arch/m32r/include/asm/system.h
deleted file mode 100644
index 13c4679..0000000
--- a/arch/m32r/include/asm/system.h
+++ /dev/null
@@ -1,367 +0,0 @@
-#ifndef _ASM_M32R_SYSTEM_H
-#define _ASM_M32R_SYSTEM_H
-
-/*
- * 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.
- *
- * Copyright (C) 2001  Hiroyuki Kondo, Hirokazu Takata, and Hitoshi Yamamoto
- * Copyright (C) 2004, 2006  Hirokazu Takata <takata at linux-m32r.org>
- */
-
-#include <linux/compiler.h>
-#include <linux/irqflags.h>
-#include <asm/assembler.h>
-
-#ifdef __KERNEL__
-
-/*
- * switch_to(prev, next) should switch from task `prev' to `next'
- * `prev' will never be the same as `next'.
- *
- * `next' and `prev' should be struct task_struct, but it isn't always defined
- */
-
-#if defined(CONFIG_FRAME_POINTER) || \
-	!defined(CONFIG_SCHED_OMIT_FRAME_POINTER)
-#define M32R_PUSH_FP "	push fp\n"
-#define M32R_POP_FP  "	pop  fp\n"
-#else
-#define M32R_PUSH_FP ""
-#define M32R_POP_FP  ""
-#endif
-
-#define switch_to(prev, next, last)  do { \
-	__asm__ __volatile__ ( \
-		"	seth	lr, #high(1f)				\n" \
-		"	or3	lr, lr, #low(1f)			\n" \
-		"	st	lr, @%4  ; store old LR			\n" \
-		"	ld	lr, @%5  ; load new LR			\n" \
-			M32R_PUSH_FP \
-		"	st	sp, @%2  ; store old SP			\n" \
-		"	ld	sp, @%3  ; load new SP			\n" \
-		"	push	%1  ; store `prev' on new stack		\n" \
-		"	jmp	lr					\n" \
-		"	.fillinsn					\n" \
-		"1:							\n" \
-		"	pop	%0  ; restore `__last' from new stack	\n" \
-			M32R_POP_FP \
-		: "=r" (last) \
-		: "0" (prev), \
-		  "r" (&(prev->thread.sp)), "r" (&(next->thread.sp)), \
-		  "r" (&(prev->thread.lr)), "r" (&(next->thread.lr)) \
-		: "memory", "lr" \
-	); \
-} while(0)
-
-#define nop()	__asm__ __volatile__ ("nop" : : )
-
-#define xchg(ptr, x)							\
-	((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
-#define xchg_local(ptr, x)						\
-	((__typeof__(*(ptr)))__xchg_local((unsigned long)(x), (ptr),	\
-			sizeof(*(ptr))))
-
-extern void  __xchg_called_with_bad_pointer(void);
-
-#ifdef CONFIG_CHIP_M32700_TS1
-#define DCACHE_CLEAR(reg0, reg1, addr)				\
-	"seth	"reg1", #high(dcache_dummy);		\n\t"	\
-	"or3	"reg1", "reg1", #low(dcache_dummy);	\n\t"	\
-	"lock	"reg0", @"reg1";			\n\t"	\
-	"add3	"reg0", "addr", #0x1000;		\n\t"	\
-	"ld	"reg0", @"reg0";			\n\t"	\
-	"add3	"reg0", "addr", #0x2000;		\n\t"	\
-	"ld	"reg0", @"reg0";			\n\t"	\
-	"unlock	"reg0", @"reg1";			\n\t"
-	/* FIXME: This workaround code cannot handle kernel modules
-	 * correctly under SMP environment.
-	 */
-#else	/* CONFIG_CHIP_M32700_TS1 */
-#define DCACHE_CLEAR(reg0, reg1, addr)
-#endif	/* CONFIG_CHIP_M32700_TS1 */
-
-static __always_inline unsigned long
-__xchg(unsigned long x, volatile void *ptr, int size)
-{
-	unsigned long flags;
-	unsigned long tmp = 0;
-
-	local_irq_save(flags);
-
-	switch (size) {
-#ifndef CONFIG_SMP
-	case 1:
-		__asm__ __volatile__ (
-			"ldb	%0, @%2 \n\t"
-			"stb	%1, @%2 \n\t"
-			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
-		break;
-	case 2:
-		__asm__ __volatile__ (
-			"ldh	%0, @%2 \n\t"
-			"sth	%1, @%2 \n\t"
-			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
-		break;
-	case 4:
-		__asm__ __volatile__ (
-			"ld	%0, @%2 \n\t"
-			"st	%1, @%2 \n\t"
-			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
-		break;
-#else  /* CONFIG_SMP */
-	case 4:
-		__asm__ __volatile__ (
-			DCACHE_CLEAR("%0", "r4", "%2")
-			"lock	%0, @%2;	\n\t"
-			"unlock	%1, @%2;	\n\t"
-			: "=&r" (tmp) : "r" (x), "r" (ptr)
-			: "memory"
-#ifdef CONFIG_CHIP_M32700_TS1
-			, "r4"
-#endif	/* CONFIG_CHIP_M32700_TS1 */
-		);
-		break;
-#endif  /* CONFIG_SMP */
-	default:
-		__xchg_called_with_bad_pointer();
-	}
-
-	local_irq_restore(flags);
-
-	return (tmp);
-}
-
-static __always_inline unsigned long
-__xchg_local(unsigned long x, volatile void *ptr, int size)
-{
-	unsigned long flags;
-	unsigned long tmp = 0;
-
-	local_irq_save(flags);
-
-	switch (size) {
-	case 1:
-		__asm__ __volatile__ (
-			"ldb	%0, @%2 \n\t"
-			"stb	%1, @%2 \n\t"
-			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
-		break;
-	case 2:
-		__asm__ __volatile__ (
-			"ldh	%0, @%2 \n\t"
-			"sth	%1, @%2 \n\t"
-			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
-		break;
-	case 4:
-		__asm__ __volatile__ (
-			"ld	%0, @%2 \n\t"
-			"st	%1, @%2 \n\t"
-			: "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
-		break;
-	default:
-		__xchg_called_with_bad_pointer();
-	}
-
-	local_irq_restore(flags);
-
-	return (tmp);
-}
-
-#define __HAVE_ARCH_CMPXCHG	1
-
-static inline unsigned long
-__cmpxchg_u32(volatile unsigned int *p, unsigned int old, unsigned int new)
-{
-	unsigned long flags;
-	unsigned int retval;
-
-	local_irq_save(flags);
-	__asm__ __volatile__ (
-			DCACHE_CLEAR("%0", "r4", "%1")
-			M32R_LOCK" %0, @%1;	\n"
-		"	bne	%0, %2, 1f;	\n"
-			M32R_UNLOCK" %3, @%1;	\n"
-		"	bra	2f;		\n"
-                "       .fillinsn		\n"
-		"1:"
-			M32R_UNLOCK" %0, @%1;	\n"
-                "       .fillinsn		\n"
-		"2:"
-			: "=&r" (retval)
-			: "r" (p), "r" (old), "r" (new)
-			: "cbit", "memory"
-#ifdef CONFIG_CHIP_M32700_TS1
-			, "r4"
-#endif  /* CONFIG_CHIP_M32700_TS1 */
-		);
-	local_irq_restore(flags);
-
-	return retval;
-}
-
-static inline unsigned long
-__cmpxchg_local_u32(volatile unsigned int *p, unsigned int old,
-			unsigned int new)
-{
-	unsigned long flags;
-	unsigned int retval;
-
-	local_irq_save(flags);
-	__asm__ __volatile__ (
-			DCACHE_CLEAR("%0", "r4", "%1")
-			"ld %0, @%1;		\n"
-		"	bne	%0, %2, 1f;	\n"
-			"st %3, @%1;		\n"
-		"	bra	2f;		\n"
-		"       .fillinsn		\n"
-		"1:"
-			"st %0, @%1;		\n"
-		"       .fillinsn		\n"
-		"2:"
-			: "=&r" (retval)
-			: "r" (p), "r" (old), "r" (new)
-			: "cbit", "memory"
-#ifdef CONFIG_CHIP_M32700_TS1
-			, "r4"
-#endif  /* CONFIG_CHIP_M32700_TS1 */
-		);
-	local_irq_restore(flags);
-
-	return retval;
-}
-
-/* This function doesn't exist, so you'll get a linker error
-   if something tries to do an invalid cmpxchg().  */
-extern void __cmpxchg_called_with_bad_pointer(void);
-
-static inline unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
-{
-	switch (size) {
-	case 4:
-		return __cmpxchg_u32(ptr, old, new);
-#if 0	/* we don't have __cmpxchg_u64 */
-	case 8:
-		return __cmpxchg_u64(ptr, old, new);
-#endif /* 0 */
-	}
-	__cmpxchg_called_with_bad_pointer();
-	return old;
-}
-
-#define cmpxchg(ptr, o, n)						 \
-	((__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)(o),	 \
-			(unsigned long)(n), sizeof(*(ptr))))
-
-#include <asm-generic/cmpxchg-local.h>
-
-static inline unsigned long __cmpxchg_local(volatile void *ptr,
-				      unsigned long old,
-				      unsigned long new, int size)
-{
-	switch (size) {
-	case 4:
-		return __cmpxchg_local_u32(ptr, old, new);
-	default:
-		return __cmpxchg_local_generic(ptr, old, new, size);
-	}
-
-	return old;
-}
-
-/*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
- */
-#define cmpxchg_local(ptr, o, n)				  	    \
-	((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o),	    \
-			(unsigned long)(n), sizeof(*(ptr))))
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-
-#endif  /* __KERNEL__ */
-
-/*
- * Memory barrier.
- *
- * mb() prevents loads and stores being reordered across this point.
- * rmb() prevents loads being reordered across this point.
- * wmb() prevents stores being reordered across this point.
- */
-#define mb()   barrier()
-#define rmb()  mb()
-#define wmb()  mb()
-
-/**
- * read_barrier_depends - Flush all pending reads that subsequents reads
- * depend on.
- *
- * No data-dependent reads from memory-like regions are ever reordered
- * over this barrier.  All reads preceding this primitive are guaranteed
- * to access memory (but not necessarily other CPUs' caches) before any
- * reads following this primitive that depend on the data return by
- * any of the preceding reads.  This primitive is much lighter weight than
- * rmb() on most CPUs, and is never heavier weight than is
- * rmb().
- *
- * These ordering constraints are respected by both the local CPU
- * and the compiler.
- *
- * Ordering is not guaranteed by anything other than these primitives,
- * not even by data dependencies.  See the documentation for
- * memory_barrier() for examples and URLs to more information.
- *
- * For example, the following code would force ordering (the initial
- * value of "a" is zero, "b" is one, and "p" is "&a"):
- *
- * <programlisting>
- *      CPU 0                           CPU 1
- *
- *      b = 2;
- *      memory_barrier();
- *      p = &b;                         q = p;
- *                                      read_barrier_depends();
- *                                      d = *q;
- * </programlisting>
- *
- *
- * because the read of "*q" depends on the read of "p" and these
- * two reads are separated by a read_barrier_depends().  However,
- * the following code, with the same initial values for "a" and "b":
- *
- * <programlisting>
- *      CPU 0                           CPU 1
- *
- *      a = 2;
- *      memory_barrier();
- *      b = 3;                          y = b;
- *                                      read_barrier_depends();
- *                                      x = a;
- * </programlisting>
- *
- * does not enforce ordering, since there is no data dependency between
- * the read of "a" and the read of "b".  Therefore, on some CPUs, such
- * as Alpha, "y" could be set to 3 and "x" to 0.  Use rmb()
- * in cases like this where there are no data dependencies.
- **/
-
-#define read_barrier_depends()	do { } while (0)
-
-#ifdef CONFIG_SMP
-#define smp_mb()	mb()
-#define smp_rmb()	rmb()
-#define smp_wmb()	wmb()
-#define smp_read_barrier_depends()	read_barrier_depends()
-#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
-#else
-#define smp_mb()	barrier()
-#define smp_rmb()	barrier()
-#define smp_wmb()	barrier()
-#define smp_read_barrier_depends()	do { } while (0)
-#define set_mb(var, value) do { var = value; barrier(); } while (0)
-#endif
-
-#define arch_align_stack(x) (x)
-
-#endif /* _ASM_M32R_SYSTEM_H */
diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c
index 2074375..4c03361 100644
--- a/arch/m32r/kernel/ptrace.c
+++ b/arch/m32r/kernel/ptrace.c
@@ -29,7 +29,6 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/mmu_context.h>
 
diff --git a/arch/m32r/kernel/traps.c b/arch/m32r/kernel/traps.c
index ee6a919..3bcb207 100644
--- a/arch/m32r/kernel/traps.c
+++ b/arch/m32r/kernel/traps.c
@@ -18,7 +18,6 @@
 #include <asm/page.h>
 #include <asm/processor.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/atomic.h>
diff --git a/arch/m32r/mm/fault-nommu.c b/arch/m32r/mm/fault-nommu.c
index 888aab1..80f18cc 100644
--- a/arch/m32r/mm/fault-nommu.c
+++ b/arch/m32r/mm/fault-nommu.c
@@ -22,7 +22,6 @@
 #include <linux/vt_kern.h>              /* For unblank_screen() */
 
 #include <asm/m32r.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c
index 2c9aeb4..3cdfa9c 100644
--- a/arch/m32r/mm/fault.c
+++ b/arch/m32r/mm/fault.c
@@ -26,7 +26,6 @@
 #include <linux/module.h>
 
 #include <asm/m32r.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
 #include <asm/mmu_context.h>
diff --git a/arch/m32r/platforms/m32104ut/setup.c b/arch/m32r/platforms/m32104ut/setup.c
index 34671d3..e2dd778 100644
--- a/arch/m32r/platforms/m32104ut/setup.c
+++ b/arch/m32r/platforms/m32104ut/setup.c
@@ -13,7 +13,6 @@
 #include <linux/init.h>
 #include <linux/device.h>
 
-#include <asm/system.h>
 #include <asm/m32r.h>
 #include <asm/io.h>
 
diff --git a/arch/m32r/platforms/m32700ut/setup.c b/arch/m32r/platforms/m32700ut/setup.c
index 1053e1c..9a4ba8a 100644
--- a/arch/m32r/platforms/m32700ut/setup.c
+++ b/arch/m32r/platforms/m32700ut/setup.c
@@ -16,7 +16,6 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 
-#include <asm/system.h>
 #include <asm/m32r.h>
 #include <asm/io.h>
 
diff --git a/arch/m32r/platforms/mappi/setup.c b/arch/m32r/platforms/mappi/setup.c
index 35130ac..767d2f4 100644
--- a/arch/m32r/platforms/mappi/setup.c
+++ b/arch/m32r/platforms/mappi/setup.c
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 
-#include <asm/system.h>
 #include <asm/m32r.h>
 #include <asm/io.h>
 
diff --git a/arch/m32r/platforms/mappi2/setup.c b/arch/m32r/platforms/mappi2/setup.c
index f3ed6b6..76d665a 100644
--- a/arch/m32r/platforms/mappi2/setup.c
+++ b/arch/m32r/platforms/mappi2/setup.c
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 
-#include <asm/system.h>
 #include <asm/m32r.h>
 #include <asm/io.h>
 
diff --git a/arch/m32r/platforms/mappi3/setup.c b/arch/m32r/platforms/mappi3/setup.c
index 2408e35..a3646d4 100644
--- a/arch/m32r/platforms/mappi3/setup.c
+++ b/arch/m32r/platforms/mappi3/setup.c
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 
-#include <asm/system.h>
 #include <asm/m32r.h>
 #include <asm/io.h>
 
diff --git a/arch/m32r/platforms/oaks32r/setup.c b/arch/m32r/platforms/oaks32r/setup.c
index 83b46b0..f8373c0 100644
--- a/arch/m32r/platforms/oaks32r/setup.c
+++ b/arch/m32r/platforms/oaks32r/setup.c
@@ -11,7 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 
-#include <asm/system.h>
 #include <asm/m32r.h>
 #include <asm/io.h>
 
diff --git a/arch/m32r/platforms/opsput/setup.c b/arch/m32r/platforms/opsput/setup.c
index 3266070..cd01704 100644
--- a/arch/m32r/platforms/opsput/setup.c
+++ b/arch/m32r/platforms/opsput/setup.c
@@ -17,7 +17,6 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 
-#include <asm/system.h>
 #include <asm/m32r.h>
 #include <asm/io.h>
 
diff --git a/arch/m32r/platforms/usrv/setup.c b/arch/m32r/platforms/usrv/setup.c
index 0c7a1e8..dcde0ec 100644
--- a/arch/m32r/platforms/usrv/setup.c
+++ b/arch/m32r/platforms/usrv/setup.c
@@ -11,7 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 
-#include <asm/system.h>
 #include <asm/m32r.h>
 #include <asm/io.h>
 
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index ae413d4..d318c60 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -7,6 +7,7 @@
 	select GENERIC_IRQ_SHOW
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
 	select GENERIC_CPU_DEVICES
+	select FPU if MMU
 
 config RWSEM_GENERIC_SPINLOCK
 	bool
@@ -24,9 +25,6 @@
 config GENERIC_CLOCKEVENTS
 	bool
 
-config GENERIC_CMOS_UPDATE
-	def_bool !MMU
-
 config GENERIC_GPIO
 	bool
 
@@ -67,6 +65,9 @@
 config CPU_HAS_ADDRESS_SPACES
 	bool
 
+config FPU
+	bool
+
 config HZ
 	int
 	default 1000 if CLEOPATRA
diff --git a/arch/m68k/amiga/amisound.c b/arch/m68k/amiga/amisound.c
index 61e5c54..2559eef 100644
--- a/arch/m68k/amiga/amisound.c
+++ b/arch/m68k/amiga/amisound.c
@@ -14,7 +14,6 @@
 #include <linux/string.h>
 #include <linux/module.h>
 
-#include <asm/system.h>
 #include <asm/amigahw.h>
 
 static unsigned short *snd_data;
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index b95a451..ee01b7a 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -29,7 +29,6 @@
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
diff --git a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c
index 8d3eafa..0a30406 100644
--- a/arch/m68k/apollo/config.c
+++ b/arch/m68k/apollo/config.c
@@ -9,7 +9,6 @@
 
 #include <asm/setup.h>
 #include <asm/bootinfo.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/apollohw.h>
 #include <asm/irq.h>
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index 8048e1b..783d8f0 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -42,7 +42,6 @@
 #include <linux/seq_file.h>
 #include <linux/module.h>
 
-#include <asm/system.h>
 #include <asm/traps.h>
 
 #include <asm/atarihw.h>
diff --git a/arch/m68k/atari/atasound.c b/arch/m68k/atari/atasound.c
index d266fe8..1c1181e 100644
--- a/arch/m68k/atari/atasound.c
+++ b/arch/m68k/atari/atasound.c
@@ -25,7 +25,6 @@
 #include <linux/module.h>
 
 #include <asm/atarihw.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/atariints.h>
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index c4ac15c..d8eb327 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -39,7 +39,6 @@
 #include <asm/atarihw.h>
 #include <asm/atariints.h>
 #include <asm/atari_stram.h>
-#include <asm/system.h>
 #include <asm/machdep.h>
 #include <asm/hwtest.h>
 #include <asm/io.h>
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index 8128647..0bf850a 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -28,7 +28,6 @@
 #include <linux/bcd.h>
 
 #include <asm/bootinfo.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/setup.h>
 #include <asm/irq.h>
diff --git a/arch/m68k/bvme6000/rtc.c b/arch/m68k/bvme6000/rtc.c
index 1c4d4c7..cf12a17 100644
--- a/arch/m68k/bvme6000/rtc.c
+++ b/arch/m68k/bvme6000/rtc.c
@@ -21,7 +21,6 @@
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/setup.h>
 
 /*
diff --git a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c
index c87fe69..29a71be 100644
--- a/arch/m68k/hp300/time.c
+++ b/arch/m68k/hp300/time.c
@@ -15,7 +15,6 @@
 #include <asm/machdep.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/blinken.h>
 
diff --git a/arch/m68k/include/asm/atomic.h b/arch/m68k/include/asm/atomic.h
index 4eba796..f4e32de 100644
--- a/arch/m68k/include/asm/atomic.h
+++ b/arch/m68k/include/asm/atomic.h
@@ -2,7 +2,8 @@
 #define __ARCH_M68K_ATOMIC__
 
 #include <linux/types.h>
-#include <asm/system.h>
+#include <linux/irqflags.h>
+#include <asm/cmpxchg.h>
 
 /*
  * Atomic operations that C can't guarantee us.  Useful for
diff --git a/arch/m68k/include/asm/barrier.h b/arch/m68k/include/asm/barrier.h
new file mode 100644
index 0000000..445ce22
--- /dev/null
+++ b/arch/m68k/include/asm/barrier.h
@@ -0,0 +1,20 @@
+#ifndef _M68K_BARRIER_H
+#define _M68K_BARRIER_H
+
+/*
+ * Force strict CPU ordering.
+ * Not really required on m68k...
+ */
+#define nop()		do { asm volatile ("nop"); barrier(); } while (0)
+#define mb()		barrier()
+#define rmb()		barrier()
+#define wmb()		barrier()
+#define read_barrier_depends()	((void)0)
+#define set_mb(var, value)	({ (var) = (value); wmb(); })
+
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+#define smp_read_barrier_depends()	((void)0)
+
+#endif /* _M68K_BARRIER_H */
diff --git a/arch/m68k/include/asm/cmpxchg.h b/arch/m68k/include/asm/cmpxchg.h
new file mode 100644
index 0000000..5c81d0e
--- /dev/null
+++ b/arch/m68k/include/asm/cmpxchg.h
@@ -0,0 +1,141 @@
+#ifndef __ARCH_M68K_CMPXCHG__
+#define __ARCH_M68K_CMPXCHG__
+
+#include <linux/irqflags.h>
+
+struct __xchg_dummy { unsigned long a[100]; };
+#define __xg(x) ((volatile struct __xchg_dummy *)(x))
+
+extern unsigned long __invalid_xchg_size(unsigned long, volatile void *, int);
+
+#ifndef CONFIG_RMW_INSNS
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+{
+	unsigned long flags, tmp;
+
+	local_irq_save(flags);
+
+	switch (size) {
+	case 1:
+		tmp = *(u8 *)ptr;
+		*(u8 *)ptr = x;
+		x = tmp;
+		break;
+	case 2:
+		tmp = *(u16 *)ptr;
+		*(u16 *)ptr = x;
+		x = tmp;
+		break;
+	case 4:
+		tmp = *(u32 *)ptr;
+		*(u32 *)ptr = x;
+		x = tmp;
+		break;
+	default:
+		tmp = __invalid_xchg_size(x, ptr, size);
+		break;
+	}
+
+	local_irq_restore(flags);
+	return x;
+}
+#else
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+{
+	switch (size) {
+	case 1:
+		__asm__ __volatile__
+			("moveb %2,%0\n\t"
+			 "1:\n\t"
+			 "casb %0,%1,%2\n\t"
+			 "jne 1b"
+			 : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory");
+		break;
+	case 2:
+		__asm__ __volatile__
+			("movew %2,%0\n\t"
+			 "1:\n\t"
+			 "casw %0,%1,%2\n\t"
+			 "jne 1b"
+			 : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory");
+		break;
+	case 4:
+		__asm__ __volatile__
+			("movel %2,%0\n\t"
+			 "1:\n\t"
+			 "casl %0,%1,%2\n\t"
+			 "jne 1b"
+			 : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory");
+		break;
+	default:
+		x = __invalid_xchg_size(x, ptr, size);
+		break;
+	}
+	return x;
+}
+#endif
+
+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+#include <asm-generic/cmpxchg-local.h>
+
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+extern unsigned long __invalid_cmpxchg_size(volatile void *,
+					    unsigned long, unsigned long, int);
+
+/*
+ * Atomic compare and exchange.  Compare OLD with MEM, if identical,
+ * store NEW in MEM.  Return the initial value in MEM.  Success is
+ * indicated by comparing RETURN with OLD.
+ */
+#ifdef CONFIG_RMW_INSNS
+#define __HAVE_ARCH_CMPXCHG	1
+
+static inline unsigned long __cmpxchg(volatile void *p, unsigned long old,
+				      unsigned long new, int size)
+{
+	switch (size) {
+	case 1:
+		__asm__ __volatile__ ("casb %0,%2,%1"
+				      : "=d" (old), "=m" (*(char *)p)
+				      : "d" (new), "0" (old), "m" (*(char *)p));
+		break;
+	case 2:
+		__asm__ __volatile__ ("casw %0,%2,%1"
+				      : "=d" (old), "=m" (*(short *)p)
+				      : "d" (new), "0" (old), "m" (*(short *)p));
+		break;
+	case 4:
+		__asm__ __volatile__ ("casl %0,%2,%1"
+				      : "=d" (old), "=m" (*(int *)p)
+				      : "d" (new), "0" (old), "m" (*(int *)p));
+		break;
+	default:
+		old = __invalid_cmpxchg_size(p, old, new, size);
+		break;
+	}
+	return old;
+}
+
+#define cmpxchg(ptr, o, n)						    \
+	((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),	    \
+			(unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg_local(ptr, o, n)					    \
+	((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),	    \
+			(unsigned long)(n), sizeof(*(ptr))))
+#else
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)				  	       \
+	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+			(unsigned long)(n), sizeof(*(ptr))))
+
+#include <asm-generic/cmpxchg.h>
+
+#endif
+
+#endif /* __ARCH_M68K_CMPXCHG__ */
diff --git a/arch/m68k/include/asm/exec.h b/arch/m68k/include/asm/exec.h
new file mode 100644
index 0000000..0499adf
--- /dev/null
+++ b/arch/m68k/include/asm/exec.h
@@ -0,0 +1,6 @@
+#ifndef _M68K_EXEC_H
+#define _M68K_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* _M68K_EXEC_H */
diff --git a/arch/m68k/include/asm/m5206sim.h b/arch/m68k/include/asm/m5206sim.h
index 9015ead..6972236 100644
--- a/arch/m68k/include/asm/m5206sim.h
+++ b/arch/m68k/include/asm/m5206sim.h
@@ -100,11 +100,11 @@
 #define	MCFDMA_BASE1		(MCF_MBAR + 0x240)	/* Base address DMA 1 */
 
 #if defined(CONFIG_NETtel)
-#define	MCFUART_BASE1		0x180		/* Base address of UART1 */
-#define	MCFUART_BASE2		0x140		/* Base address of UART2 */
+#define	MCFUART_BASE0		(MCF_MBAR + 0x180)	/* Base address UART0 */
+#define	MCFUART_BASE1		(MCF_MBAR + 0x140)	/* Base address UART1 */
 #else
-#define	MCFUART_BASE1		0x140		/* Base address of UART1 */
-#define	MCFUART_BASE2		0x180		/* Base address of UART2 */
+#define	MCFUART_BASE0		(MCF_MBAR + 0x140)	/* Base address UART0 */
+#define	MCFUART_BASE1		(MCF_MBAR + 0x180)	/* Base address UART1 */
 #endif
 
 /*
@@ -112,6 +112,8 @@
  */
 #define	MCF_IRQ_TIMER		30		/* Timer0, Level 6 */
 #define	MCF_IRQ_PROFILER	31		/* Timer1, Level 7 */
+#define	MCF_IRQ_UART0		73		/* UART0 */
+#define	MCF_IRQ_UART1		74		/* UART1 */
 
 /*
  *	Generic GPIO
diff --git a/arch/m68k/include/asm/m520xsim.h b/arch/m68k/include/asm/m520xsim.h
index eda62de..17f2aab 100644
--- a/arch/m68k/include/asm/m520xsim.h
+++ b/arch/m68k/include/asm/m520xsim.h
@@ -48,8 +48,21 @@
 #define MCFINT_UART1        27          /* Interrupt number for UART1 */
 #define MCFINT_UART2        28          /* Interrupt number for UART2 */
 #define MCFINT_QSPI         31          /* Interrupt number for QSPI */
+#define MCFINT_FECRX0	    36		/* Interrupt number for FEC RX */
+#define MCFINT_FECTX0	    40		/* Interrupt number for FEC RX */
+#define MCFINT_FECENTC0	    42		/* Interrupt number for FEC RX */
 #define MCFINT_PIT1         4           /* Interrupt number for PIT1 (PIT0 in processor) */
 
+#define MCF_IRQ_UART0	    (MCFINT_VECBASE + MCFINT_UART0)
+#define MCF_IRQ_UART1	    (MCFINT_VECBASE + MCFINT_UART1)
+#define MCF_IRQ_UART2	    (MCFINT_VECBASE + MCFINT_UART2)
+
+#define MCF_IRQ_FECRX0	    (MCFINT_VECBASE + MCFINT_FECRX0)
+#define MCF_IRQ_FECTX0	    (MCFINT_VECBASE + MCFINT_FECTX0)
+#define MCF_IRQ_FECENTC0    (MCFINT_VECBASE + MCFINT_FECENTC0)
+
+#define	MCF_IRQ_QSPI	    (MCFINT_VECBASE + MCFINT_QSPI)
+
 /*
  *  SDRAM configuration registers.
  */
@@ -144,15 +157,25 @@
 /*
  *  UART module.
  */
-#define MCFUART_BASE1		0xFC060000	/* Base address of UART1 */
-#define MCFUART_BASE2		0xFC064000	/* Base address of UART2 */
-#define MCFUART_BASE3		0xFC068000	/* Base address of UART2 */
+#define MCFUART_BASE0		0xFC060000	/* Base address of UART0 */
+#define MCFUART_BASE1		0xFC064000	/* Base address of UART1 */
+#define MCFUART_BASE2		0xFC068000	/* Base address of UART2 */
 
 /*
  *  FEC module.
  */
-#define	MCFFEC_BASE		0xFC030000	/* Base of FEC ethernet */
-#define	MCFFEC_SIZE		0x800		/* Register set size */
+#define	MCFFEC_BASE0		0xFC030000	/* Base of FEC ethernet */
+#define	MCFFEC_SIZE0		0x800		/* Register set size */
+
+/*
+ *  QSPI module.
+ */
+#define	MCFQSPI_BASE		0xFC05C000	/* Base of QSPI module */
+#define	MCFQSPI_SIZE		0x40		/* Register set size */
+
+#define	MCFQSPI_CS0		46
+#define	MCFQSPI_CS1		47
+#define	MCFQSPI_CS2		27
 
 /*
  *  Reset Control Unit.
diff --git a/arch/m68k/include/asm/m523xsim.h b/arch/m68k/include/asm/m523xsim.h
index 6235921..075062d 100644
--- a/arch/m68k/include/asm/m523xsim.h
+++ b/arch/m68k/include/asm/m523xsim.h
@@ -35,8 +35,23 @@
 
 #define	MCFINT_VECBASE		64		/* Vector base number */
 #define	MCFINT_UART0		13		/* Interrupt number for UART0 */
-#define	MCFINT_PIT1		36		/* Interrupt number for PIT1 */
+#define	MCFINT_UART1		14		/* Interrupt number for UART1 */
+#define	MCFINT_UART2		15		/* Interrupt number for UART2 */
 #define MCFINT_QSPI		18		/* Interrupt number for QSPI */
+#define	MCFINT_FECRX0		23		/* Interrupt number for FEC */
+#define	MCFINT_FECTX0		27		/* Interrupt number for FEC */
+#define	MCFINT_FECENTC0		29		/* Interrupt number for FEC */
+#define	MCFINT_PIT1		36		/* Interrupt number for PIT1 */
+
+#define	MCF_IRQ_UART0	        (MCFINT_VECBASE + MCFINT_UART0)
+#define	MCF_IRQ_UART1	        (MCFINT_VECBASE + MCFINT_UART1)
+#define	MCF_IRQ_UART2	        (MCFINT_VECBASE + MCFINT_UART2)
+
+#define	MCF_IRQ_FECRX0		(MCFINT_VECBASE + MCFINT_FECRX0)
+#define	MCF_IRQ_FECTX0		(MCFINT_VECBASE + MCFINT_FECTX0)
+#define	MCF_IRQ_FECENTC0	(MCFINT_VECBASE + MCFINT_FECENTC0)
+
+#define	MCF_IRQ_QSPI		(MCFINT_VECBASE + MCFINT_QSPI)
 
 /*
  *	SDRAM configuration registers.
@@ -50,8 +65,8 @@
 /*
  *  Reset Control Unit (relative to IPSBAR).
  */
-#define	MCF_RCR			0x110000
-#define	MCF_RSR			0x110001
+#define	MCF_RCR			(MCF_IPSBAR + 0x110000)
+#define	MCF_RSR			(MCF_IPSBAR + 0x110001)
 
 #define	MCF_RCR_SWRESET		0x80		/* Software reset bit */
 #define	MCF_RCR_FRCSTOUT	0x40		/* Force external reset */
@@ -59,15 +74,26 @@
 /*
  *  UART module.
  */
-#define MCFUART_BASE1		(MCF_IPSBAR + 0x200)
-#define MCFUART_BASE2		(MCF_IPSBAR + 0x240)
-#define MCFUART_BASE3		(MCF_IPSBAR + 0x280)
+#define MCFUART_BASE0		(MCF_IPSBAR + 0x200)
+#define MCFUART_BASE1		(MCF_IPSBAR + 0x240)
+#define MCFUART_BASE2		(MCF_IPSBAR + 0x280)
 
 /*
  *  FEC ethernet module.
  */
-#define	MCFFEC_BASE		(MCF_IPSBAR + 0x1000)
-#define	MCFFEC_SIZE		0x800
+#define	MCFFEC_BASE0		(MCF_IPSBAR + 0x1000)
+#define	MCFFEC_SIZE0		0x800
+
+/*
+ *  QSPI module.
+ */
+#define	MCFQSPI_BASE		(MCF_IPSBAR + 0x340)
+#define	MCFQSPI_SIZE		0x40
+
+#define	MCFQSPI_CS0		91
+#define	MCFQSPI_CS1		92
+#define	MCFQSPI_CS2		103
+#define	MCFQSPI_CS3		99
 
 /*
  *  GPIO module.
diff --git a/arch/m68k/include/asm/m5249sim.h b/arch/m68k/include/asm/m5249sim.h
index 805714c..7f0c2c3 100644
--- a/arch/m68k/include/asm/m5249sim.h
+++ b/arch/m68k/include/asm/m5249sim.h
@@ -76,8 +76,19 @@
 /*
  *	UART module.
  */
-#define MCFUART_BASE1		0x1c0           /* Base address of UART1 */
-#define MCFUART_BASE2		0x200           /* Base address of UART2 */
+#define MCFUART_BASE0		(MCF_MBAR + 0x1c0)	/* Base address UART0 */
+#define MCFUART_BASE1		(MCF_MBAR + 0x200)	/* Base address UART1 */
+
+/*
+ *	QSPI module.
+ */
+#define	MCFQSPI_BASE		(MCF_MBAR + 0x300)	/* Base address QSPI */
+#define	MCFQSPI_SIZE		0x40			/* Register set size */
+
+#define	MCFQSPI_CS0		29
+#define	MCFQSPI_CS1		24
+#define	MCFQSPI_CS2		21
+#define	MCFQSPI_CS3		22
 
 /*
  *	DMA unit base addresses.
@@ -108,6 +119,9 @@
 #define	MCF_IRQ_TIMER		30		/* Timer0, Level 6 */
 #define	MCF_IRQ_PROFILER	31		/* Timer1, Level 7 */
 
+#define	MCF_IRQ_UART0		73		/* UART0 */
+#define	MCF_IRQ_UART1		74		/* UART1 */
+
 /*
  *	General purpose IO registers (in MBAR2).
  */
diff --git a/arch/m68k/include/asm/m5272sim.h b/arch/m68k/include/asm/m5272sim.h
index 759c2b0..a58f176 100644
--- a/arch/m68k/include/asm/m5272sim.h
+++ b/arch/m68k/include/asm/m5272sim.h
@@ -68,8 +68,8 @@
 #define	MCFSIM_DCMR1		0x5c		/* DRAM 1 Mask reg (r/w) */
 #define	MCFSIM_DCCR1		0x63		/* DRAM 1 Control reg (r/w) */
 
-#define	MCFUART_BASE1		0x100		/* Base address of UART1 */
-#define	MCFUART_BASE2		0x140		/* Base address of UART2 */
+#define	MCFUART_BASE0		(MCF_MBAR + 0x100) /* Base address UART0 */
+#define	MCFUART_BASE1		(MCF_MBAR + 0x140) /* Base address UART1 */
 
 #define	MCFSIM_PACNT		(MCF_MBAR + 0x80) /* Port A Control (r/w) */
 #define	MCFSIM_PADDR		(MCF_MBAR + 0x84) /* Port A Direction (r/w) */
@@ -88,6 +88,9 @@
 #define	MCFTIMER_BASE3		(MCF_MBAR + 0x240) /* Base address TIMER4 */
 #define	MCFTIMER_BASE4		(MCF_MBAR + 0x260) /* Base address TIMER3 */
 
+#define	MCFFEC_BASE0		(MCF_MBAR + 0x840) /* Base FEC ethernet */
+#define	MCFFEC_SIZE0		0x1d0
+
 /*
  *	Define system peripheral IRQ usage.
  */
@@ -101,8 +104,8 @@
 #define	MCF_IRQ_TIMER2		70		/* Timer 2 */
 #define	MCF_IRQ_TIMER3		71		/* Timer 3 */
 #define	MCF_IRQ_TIMER4		72		/* Timer 4 */
-#define	MCF_IRQ_UART1		73		/* UART 1 */
-#define	MCF_IRQ_UART2		74		/* UART 2 */
+#define	MCF_IRQ_UART0		73		/* UART 0 */
+#define	MCF_IRQ_UART1		74		/* UART 1 */
 #define	MCF_IRQ_PLIP		75		/* PLIC 2Khz Periodic */
 #define	MCF_IRQ_PLIA		76		/* PLIC Asynchronous */
 #define	MCF_IRQ_USB0		77		/* USB Endpoint 0 */
@@ -114,9 +117,9 @@
 #define	MCF_IRQ_USB6		83		/* USB Endpoint 6 */
 #define	MCF_IRQ_USB7		84		/* USB Endpoint 7 */
 #define	MCF_IRQ_DMA		85		/* DMA Controller */
-#define	MCF_IRQ_ERX		86		/* Ethernet Receiver */
-#define	MCF_IRQ_ETX		87		/* Ethernet Transmitter */
-#define	MCF_IRQ_ENTC		88		/* Ethernet Non-Time Critical */
+#define	MCF_IRQ_FECRX0		86		/* Ethernet Receiver */
+#define	MCF_IRQ_FECTX0		87		/* Ethernet Transmitter */
+#define	MCF_IRQ_FECENTC0	88		/* Ethernet Non-Time Critical */
 #define	MCF_IRQ_QSPI		89		/* Queued Serial Interface */
 #define	MCF_IRQ_EINT5		90		/* External Interrupt 5 */
 #define	MCF_IRQ_EINT6		91		/* External Interrupt 6 */
diff --git a/arch/m68k/include/asm/m527xsim.h b/arch/m68k/include/asm/m527xsim.h
index 758810e..83db810 100644
--- a/arch/m68k/include/asm/m527xsim.h
+++ b/arch/m68k/include/asm/m527xsim.h
@@ -38,8 +38,29 @@
 #define	MCFINT_UART1		14		/* Interrupt number for UART1 */
 #define	MCFINT_UART2		15		/* Interrupt number for UART2 */
 #define	MCFINT_QSPI		18		/* Interrupt number for QSPI */
+#define	MCFINT_FECRX0		23		/* Interrupt number for FEC0 */
+#define	MCFINT_FECTX0		27		/* Interrupt number for FEC0 */
+#define	MCFINT_FECENTC0		29		/* Interrupt number for FEC0 */
 #define	MCFINT_PIT1		36		/* Interrupt number for PIT1 */
 
+#define	MCFINT2_VECBASE		128		/* Vector base number 2 */
+#define	MCFINT2_FECRX1		23		/* Interrupt number for FEC1 */
+#define	MCFINT2_FECTX1		27		/* Interrupt number for FEC1 */
+#define	MCFINT2_FECENTC1	29		/* Interrupt number for FEC1 */
+
+#define	MCF_IRQ_UART0	        (MCFINT_VECBASE + MCFINT_UART0)
+#define	MCF_IRQ_UART1	        (MCFINT_VECBASE + MCFINT_UART1)
+#define	MCF_IRQ_UART2	        (MCFINT_VECBASE + MCFINT_UART2)
+
+#define	MCF_IRQ_FECRX0		(MCFINT_VECBASE + MCFINT_FECRX0)
+#define	MCF_IRQ_FECTX0		(MCFINT_VECBASE + MCFINT_FECTX0)
+#define	MCF_IRQ_FECENTC0	(MCFINT_VECBASE + MCFINT_FECENTC0)
+#define	MCF_IRQ_FECRX1		(MCFINT2_VECBASE + MCFINT2_FECRX1)
+#define	MCF_IRQ_FECTX1		(MCFINT2_VECBASE + MCFINT2_FECTX1)
+#define	MCF_IRQ_FECENTC1	(MCFINT2_VECBASE + MCFINT2_FECENTC1)
+
+#define	MCF_IRQ_QSPI		(MCFINT_VECBASE + MCFINT_QSPI)
+
 /*
  *	SDRAM configuration registers.
  */
@@ -72,9 +93,9 @@
 /*
  *	UART module.
  */
-#define MCFUART_BASE1		(MCF_IPSBAR + 0x200)
-#define MCFUART_BASE2		(MCF_IPSBAR + 0x240)
-#define MCFUART_BASE3		(MCF_IPSBAR + 0x280)
+#define MCFUART_BASE0		(MCF_IPSBAR + 0x200)
+#define MCFUART_BASE1		(MCF_IPSBAR + 0x240)
+#define MCFUART_BASE2		(MCF_IPSBAR + 0x280)
 
 /*
  *	FEC ethernet module.
@@ -84,6 +105,28 @@
 #define	MCFFEC_BASE1		(MCF_IPSBAR + 0x1800)
 #define	MCFFEC_SIZE1		0x800
 
+/*
+ *	QSPI module.
+ */
+#define	MCFQSPI_BASE		(MCF_IPSBAR + 0x340)
+#define	MCFQSPI_SIZE		0x40
+
+#ifdef CONFIG_M5271
+#define	MCFQSPI_CS0		91
+#define	MCFQSPI_CS1		92
+#define	MCFQSPI_CS2		99
+#define	MCFQSPI_CS3		103
+#endif
+#ifdef CONFIG_M5275
+#define	MCFQSPI_CS0		59
+#define	MCFQSPI_CS1		60
+#define	MCFQSPI_CS2		61
+#define	MCFQSPI_CS3		62
+#endif
+
+/*
+ *	GPIO module.
+ */
 #ifdef CONFIG_M5271
 #define MCFGPIO_PODR_ADDR	(MCF_IPSBAR + 0x100000)
 #define MCFGPIO_PODR_DATAH	(MCF_IPSBAR + 0x100001)
@@ -285,8 +328,8 @@
 /*
  *  Reset Control Unit (relative to IPSBAR).
  */
-#define	MCF_RCR			0x110000
-#define	MCF_RSR			0x110001
+#define	MCF_RCR			(MCF_IPSBAR + 0x110000)
+#define	MCF_RSR			(MCF_IPSBAR + 0x110001)
 
 #define	MCF_RCR_SWRESET		0x80		/* Software reset bit */
 #define	MCF_RCR_FRCSTOUT	0x40		/* Force external reset */
diff --git a/arch/m68k/include/asm/m528xsim.h b/arch/m68k/include/asm/m528xsim.h
index d798bd5..569476f 100644
--- a/arch/m68k/include/asm/m528xsim.h
+++ b/arch/m68k/include/asm/m528xsim.h
@@ -35,9 +35,24 @@
 
 #define	MCFINT_VECBASE		64		/* Vector base number */
 #define	MCFINT_UART0		13		/* Interrupt number for UART0 */
+#define	MCFINT_UART1		14		/* Interrupt number for UART1 */
+#define	MCFINT_UART2		15		/* Interrupt number for UART2 */
 #define	MCFINT_QSPI		18		/* Interrupt number for QSPI */
+#define	MCFINT_FECRX0		23		/* Interrupt number for FEC */
+#define	MCFINT_FECTX0		27		/* Interrupt number for FEC */
+#define	MCFINT_FECENTC0		29		/* Interrupt number for FEC */
 #define	MCFINT_PIT1		55		/* Interrupt number for PIT1 */
 
+#define	MCF_IRQ_UART0	        (MCFINT_VECBASE + MCFINT_UART0)
+#define	MCF_IRQ_UART1	        (MCFINT_VECBASE + MCFINT_UART1)
+#define	MCF_IRQ_UART2	        (MCFINT_VECBASE + MCFINT_UART2)
+
+#define	MCF_IRQ_FECRX0		(MCFINT_VECBASE + MCFINT_FECRX0)
+#define	MCF_IRQ_FECTX0		(MCFINT_VECBASE + MCFINT_FECTX0)
+#define	MCF_IRQ_FECENTC0	(MCFINT_VECBASE + MCFINT_FECENTC0)
+
+#define	MCF_IRQ_QSPI		(MCFINT_VECBASE + MCFINT_QSPI)
+
 /*
  *	SDRAM configuration registers.
  */
@@ -58,15 +73,26 @@
 /*
  *	UART module.
  */
-#define	MCFUART_BASE1		(MCF_IPSBAR + 0x00000200)
-#define	MCFUART_BASE2		(MCF_IPSBAR + 0x00000240)
-#define	MCFUART_BASE3		(MCF_IPSBAR + 0x00000280)
+#define	MCFUART_BASE0		(MCF_IPSBAR + 0x00000200)
+#define	MCFUART_BASE1		(MCF_IPSBAR + 0x00000240)
+#define	MCFUART_BASE2		(MCF_IPSBAR + 0x00000280)
 
 /*
  *	FEC ethernet module.
  */
-#define	MCFFEC_BASE		(MCF_IPSBAR + 0x00001000)
-#define	MCFFEC_SIZE		0x800
+#define	MCFFEC_BASE0		(MCF_IPSBAR + 0x00001000)
+#define	MCFFEC_SIZE0		0x800
+
+/*
+ *	QSPI module.
+ */
+#define	MCFQSPI_IOBASE		(MCF_IPSBAR + 0x340)
+#define	MCFQSPI_SIZE		0x40
+
+#define	MCFQSPI_CS0		147
+#define	MCFQSPI_CS1		148
+#define	MCFQSPI_CS2		149
+#define	MCFQSPI_CS3		150
 
 /*
  * 	GPIO registers
@@ -246,8 +272,8 @@
 /*
  *  Reset Control Unit (relative to IPSBAR).
  */
-#define	MCF_RCR			0x110000
-#define	MCF_RSR			0x110001
+#define	MCF_RCR			(MCF_IPSBAR + 0x110000)
+#define	MCF_RSR			(MCF_IPSBAR + 0x110001)
 
 #define	MCF_RCR_SWRESET		0x80		/* Software reset bit */
 #define	MCF_RCR_FRCSTOUT	0x40		/* Force external reset */
diff --git a/arch/m68k/include/asm/m5307sim.h b/arch/m68k/include/asm/m5307sim.h
index 8f8609f..3bc3ada 100644
--- a/arch/m68k/include/asm/m5307sim.h
+++ b/arch/m68k/include/asm/m5307sim.h
@@ -117,11 +117,11 @@
  *  UART module.
  */
 #if defined(CONFIG_NETtel) || defined(CONFIG_SECUREEDGEMP3)
-#define MCFUART_BASE1		0x200           /* Base address of UART1 */
-#define MCFUART_BASE2		0x1c0           /* Base address of UART2 */
+#define MCFUART_BASE0		(MCF_MBAR + 0x200)	/* Base address UART0 */
+#define MCFUART_BASE1		(MCF_MBAR + 0x1c0)	/* Base address UART1 */
 #else
-#define MCFUART_BASE1		0x1c0           /* Base address of UART1 */
-#define MCFUART_BASE2		0x200           /* Base address of UART2 */
+#define MCFUART_BASE0		(MCF_MBAR + 0x1c0)	/* Base address UART0 */
+#define MCFUART_BASE1		(MCF_MBAR + 0x200)	/* Base address UART1 */
 #endif
 
 /*
@@ -176,6 +176,8 @@
  */
 #define	MCF_IRQ_TIMER		30		/* Timer0, Level 6 */
 #define	MCF_IRQ_PROFILER	31		/* Timer1, Level 7 */
+#define	MCF_IRQ_UART0		73		/* UART0 */
+#define	MCF_IRQ_UART1		74		/* UART1 */
 
 /****************************************************************************/
 #endif	/* m5307sim_h */
diff --git a/arch/m68k/include/asm/m532xsim.h b/arch/m68k/include/asm/m532xsim.h
index ba4cc78..29b66e2 100644
--- a/arch/m68k/include/asm/m532xsim.h
+++ b/arch/m68k/include/asm/m532xsim.h
@@ -24,6 +24,19 @@
 #define MCFINT_UART1        27          /* Interrupt number for UART1 */
 #define MCFINT_UART2        28          /* Interrupt number for UART2 */
 #define MCFINT_QSPI         31          /* Interrupt number for QSPI */
+#define MCFINT_FECRX0	    36		/* Interrupt number for FEC */
+#define MCFINT_FECTX0	    40		/* Interrupt number for FEC */
+#define MCFINT_FECENTC0	    42		/* Interrupt number for FEC */
+
+#define MCF_IRQ_UART0       (MCFINT_VECBASE + MCFINT_UART0)
+#define MCF_IRQ_UART1       (MCFINT_VECBASE + MCFINT_UART1)
+#define MCF_IRQ_UART2       (MCFINT_VECBASE + MCFINT_UART2)
+
+#define MCF_IRQ_FECRX0	    (MCFINT_VECBASE + MCFINT_FECRX0)
+#define MCF_IRQ_FECTX0	    (MCFINT_VECBASE + MCFINT_FECTX0)
+#define MCF_IRQ_FECENTC0    (MCFINT_VECBASE + MCFINT_FECENTC0)
+
+#define	MCF_IRQ_QSPI	    (MCFINT_VECBASE + MCFINT_QSPI)
 
 #define MCF_WTM_WCR	MCF_REG16(0xFC098000)
 
@@ -82,9 +95,25 @@
 /*
  *  UART module.
  */
-#define MCFUART_BASE1		0xFC060000	/* Base address of UART1 */
-#define MCFUART_BASE2		0xFC064000	/* Base address of UART2 */
-#define MCFUART_BASE3		0xFC068000	/* Base address of UART3 */
+#define MCFUART_BASE0		0xFC060000	/* Base address of UART1 */
+#define MCFUART_BASE1		0xFC064000	/* Base address of UART2 */
+#define MCFUART_BASE2		0xFC068000	/* Base address of UART3 */
+
+/*
+ *  FEC module.
+ */
+#define	MCFFEC_BASE0		0xFC030000	/* Base address of FEC0 */
+#define	MCFFEC_SIZE0		0x800		/* Size of FEC0 region */
+
+/*
+ *  QSPI module.
+ */
+#define	MCFQSPI_BASE		0xFC058000	/* Base address of QSPI */
+#define	MCFQSPI_SIZE		0x40		/* Size of QSPI region */
+
+#define	MCFQSPI_CS0		84
+#define	MCFQSPI_CS1		85
+#define	MCFQSPI_CS2		86
 
 /*
  *  Timer module.
diff --git a/arch/m68k/include/asm/m5407sim.h b/arch/m68k/include/asm/m5407sim.h
index 51e00b0..79f58dd 100644
--- a/arch/m68k/include/asm/m5407sim.h
+++ b/arch/m68k/include/asm/m5407sim.h
@@ -85,8 +85,8 @@
 #define MCFTIMER_BASE1		(MCF_MBAR + 0x140)	/* Base of TIMER1 */
 #define MCFTIMER_BASE2		(MCF_MBAR + 0x180)	/* Base of TIMER2 */
 
-#define MCFUART_BASE1		0x1c0           /* Base address of UART1 */
-#define MCFUART_BASE2		0x200           /* Base address of UART2 */
+#define MCFUART_BASE0		(MCF_MBAR + 0x1c0)	/* Base address UART0 */
+#define MCFUART_BASE1		(MCF_MBAR + 0x200)	/* Base address UART1 */
 
 #define	MCFSIM_PADDR		(MCF_MBAR + 0x244)
 #define	MCFSIM_PADAT		(MCF_MBAR + 0x248)
@@ -139,6 +139,8 @@
  */
 #define	MCF_IRQ_TIMER		30		/* Timer0, Level 6 */
 #define	MCF_IRQ_PROFILER	31		/* Timer1, Level 7 */
+#define	MCF_IRQ_UART0		73		/* UART0 */
+#define	MCF_IRQ_UART1		74		/* UART1 */
 
 /****************************************************************************/
 #endif	/* m5407sim_h */
diff --git a/arch/m68k/include/asm/m54xxsim.h b/arch/m68k/include/asm/m54xxsim.h
index 1ed8bfb..ae56b88 100644
--- a/arch/m68k/include/asm/m54xxsim.h
+++ b/arch/m68k/include/asm/m54xxsim.h
@@ -31,16 +31,20 @@
 /*
  *	UART module.
  */
-#define MCFUART_BASE1		0x8600		/* Base address of UART1 */
-#define MCFUART_BASE2		0x8700		/* Base address of UART2 */
-#define MCFUART_BASE3		0x8800		/* Base address of UART3 */
-#define MCFUART_BASE4		0x8900		/* Base address of UART4 */
+#define MCFUART_BASE0		(MCF_MBAR + 0x8600)	/* Base address UART0 */
+#define MCFUART_BASE1		(MCF_MBAR + 0x8700)	/* Base address UART1 */
+#define MCFUART_BASE2		(MCF_MBAR + 0x8800)	/* Base address UART2 */
+#define MCFUART_BASE3		(MCF_MBAR + 0x8900)	/* Base address UART3 */
 
 /*
  *	Define system peripheral IRQ usage.
  */
-#define MCF_IRQ_TIMER		(64 + 54)	/* Slice Timer 0 */
-#define MCF_IRQ_PROFILER	(64 + 53)	/* Slice Timer 1 */
+#define MCF_IRQ_TIMER		(MCFINT_VECBASE + 54)	/* Slice Timer 0 */
+#define MCF_IRQ_PROFILER	(MCFINT_VECBASE + 53)	/* Slice Timer 1 */
+#define MCF_IRQ_UART0		(MCFINT_VECBASE + 35)
+#define MCF_IRQ_UART1		(MCFINT_VECBASE + 34)
+#define MCF_IRQ_UART2		(MCFINT_VECBASE + 33)
+#define MCF_IRQ_UART3		(MCFINT_VECBASE + 32)
 
 /*
  *	Generic GPIO support
diff --git a/arch/m68k/include/asm/machdep.h b/arch/m68k/include/asm/machdep.h
index 789f3b2..825c1c8 100644
--- a/arch/m68k/include/asm/machdep.h
+++ b/arch/m68k/include/asm/machdep.h
@@ -22,8 +22,6 @@
 extern int (*mach_get_rtc_pll)(struct rtc_pll_info *);
 extern int (*mach_set_rtc_pll)(struct rtc_pll_info *);
 extern int (*mach_set_clock_mmss)(unsigned long);
-extern void (*mach_gettod)(int *year, int *mon, int *day, int *hour,
-			    int *min, int *sec);
 extern void (*mach_reset)( void );
 extern void (*mach_halt)( void );
 extern void (*mach_power_off)( void );
@@ -35,9 +33,8 @@
 extern void (*mach_beep) (unsigned int, unsigned int);
 
 /* Hardware clock functions */
-extern void hw_timer_init(void);
+extern void hw_timer_init(irq_handler_t handler);
 extern unsigned long hw_timer_offset(void);
-extern irqreturn_t arch_timer_interrupt(int irq, void *dummy);
 
 extern void config_BSP(char *command, int len);
 
diff --git a/arch/m68k/include/asm/mcfqspi.h b/arch/m68k/include/asm/mcfqspi.h
index 7fe6319..7b51416 100644
--- a/arch/m68k/include/asm/mcfqspi.h
+++ b/arch/m68k/include/asm/mcfqspi.h
@@ -21,17 +21,6 @@
 #ifndef mcfqspi_h
 #define mcfqspi_h
 
-#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
-#define	MCFQSPI_IOBASE		(MCF_IPSBAR + 0x340)
-#elif defined(CONFIG_M5249)
-#define MCFQSPI_IOBASE         (MCF_MBAR + 0x300)
-#elif defined(CONFIG_M520x)
-#define MCFQSPI_IOBASE         0xFC05C000
-#elif defined(CONFIG_M532x)
-#define MCFQSPI_IOBASE         0xFC058000
-#endif
-#define MCFQSPI_IOSIZE		0x40
-
 /**
  * struct mcfqspi_cs_control - chip select control for the coldfire qspi driver
  * @setup: setup the control; allocate gpio's, etc. May be NULL.
diff --git a/arch/m68k/include/asm/mcfuart.h b/arch/m68k/include/asm/mcfuart.h
index 2abedff..2d3bc77 100644
--- a/arch/m68k/include/asm/mcfuart.h
+++ b/arch/m68k/include/asm/mcfuart.h
@@ -41,7 +41,10 @@
 #define	MCFUART_UTF		0x28		/* Transmitter FIFO (r/w) */
 #define	MCFUART_URF		0x2c		/* Receiver FIFO (r/w) */
 #define	MCFUART_UFPD		0x30		/* Frac Prec. Divider (r/w) */
-#else
+#endif
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
+        defined(CONFIG_M5249) || defined(CONFIG_M5307) || \
+        defined(CONFIG_M5407)
 #define	MCFUART_UIVR		0x30		/* Interrupt Vector (r/w) */
 #endif
 #define	MCFUART_UIPR		0x34		/* Input Port (r) */
diff --git a/arch/m68k/include/asm/posix_types.h b/arch/m68k/include/asm/posix_types.h
index 98d0970..6373093 100644
--- a/arch/m68k/include/asm/posix_types.h
+++ b/arch/m68k/include/asm/posix_types.h
@@ -7,55 +7,22 @@
  * assume GCC is being used.
  */
 
-typedef unsigned long	__kernel_ino_t;
 typedef unsigned short	__kernel_mode_t;
+#define __kernel_mode_t __kernel_mode_t
+
 typedef unsigned short	__kernel_nlink_t;
-typedef long		__kernel_off_t;
-typedef int		__kernel_pid_t;
+#define __kernel_nlink_t __kernel_nlink_t
+
 typedef unsigned short	__kernel_ipc_pid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
+
 typedef unsigned short	__kernel_uid_t;
 typedef unsigned short	__kernel_gid_t;
-typedef unsigned int	__kernel_size_t;
-typedef int		__kernel_ssize_t;
-typedef int		__kernel_ptrdiff_t;
-typedef long		__kernel_time_t;
-typedef long		__kernel_suseconds_t;
-typedef long		__kernel_clock_t;
-typedef int		__kernel_timer_t;
-typedef int		__kernel_clockid_t;
-typedef int		__kernel_daddr_t;
-typedef char *		__kernel_caddr_t;
-typedef unsigned short	__kernel_uid16_t;
-typedef unsigned short	__kernel_gid16_t;
-typedef unsigned int	__kernel_uid32_t;
-typedef unsigned int	__kernel_gid32_t;
+#define __kernel_uid_t __kernel_uid_t
 
-typedef unsigned short	__kernel_old_uid_t;
-typedef unsigned short	__kernel_old_gid_t;
 typedef unsigned short	__kernel_old_dev_t;
+#define __kernel_old_dev_t __kernel_old_dev_t
 
-#ifdef __GNUC__
-typedef long long	__kernel_loff_t;
-#endif
-
-typedef struct {
-	int	val[2];
-} __kernel_fsid_t;
-
-#if defined(__KERNEL__)
-
-#undef	__FD_SET
-#define	__FD_SET(d, set)	((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
-
-#undef	__FD_CLR
-#define	__FD_CLR(d, set)	((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
-
-#undef	__FD_ISSET
-#define	__FD_ISSET(d, set)	(!!((set)->fds_bits[__FDELT(d)] & __FDMASK(d)))
-
-#undef	__FD_ZERO
-#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
-
-#endif /* defined(__KERNEL__) */
+#include <asm-generic/posix_types.h>
 
 #endif
diff --git a/arch/m68k/include/asm/sun3xflop.h b/arch/m68k/include/asm/sun3xflop.h
index 32c45f8..95231e2 100644
--- a/arch/m68k/include/asm/sun3xflop.h
+++ b/arch/m68k/include/asm/sun3xflop.h
@@ -11,7 +11,6 @@
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/sun3x.h>
 
diff --git a/arch/m68k/include/asm/switch_to.h b/arch/m68k/include/asm/switch_to.h
new file mode 100644
index 0000000..16fd6b6
--- /dev/null
+++ b/arch/m68k/include/asm/switch_to.h
@@ -0,0 +1,41 @@
+#ifndef _M68K_SWITCH_TO_H
+#define _M68K_SWITCH_TO_H
+
+/*
+ * switch_to(n) should switch tasks to task ptr, first checking that
+ * ptr isn't the current task, in which case it does nothing.  This
+ * also clears the TS-flag if the task we switched to has used the
+ * math co-processor latest.
+ */
+/*
+ * switch_to() saves the extra registers, that are not saved
+ * automatically by SAVE_SWITCH_STACK in resume(), ie. d0-d5 and
+ * a0-a1. Some of these are used by schedule() and its predecessors
+ * and so we might get see unexpected behaviors when a task returns
+ * with unexpected register values.
+ *
+ * syscall stores these registers itself and none of them are used
+ * by syscall after the function in the syscall has been called.
+ *
+ * Beware that resume now expects *next to be in d1 and the offset of
+ * tss to be in a1. This saves a few instructions as we no longer have
+ * to push them onto the stack and read them back right after.
+ *
+ * 02/17/96 - Jes Sorensen (jds@kom.auc.dk)
+ *
+ * Changed 96/09/19 by Andreas Schwab
+ * pass prev in a0, next in a1
+ */
+asmlinkage void resume(void);
+#define switch_to(prev,next,last) do { \
+  register void *_prev __asm__ ("a0") = (prev); \
+  register void *_next __asm__ ("a1") = (next); \
+  register void *_last __asm__ ("d1"); \
+  __asm__ __volatile__("jbsr resume" \
+		       : "=a" (_prev), "=a" (_next), "=d" (_last) \
+		       : "0" (_prev), "1" (_next) \
+		       : "d0", "d2", "d3", "d4", "d5"); \
+  (last) = _last; \
+} while (0)
+
+#endif /* _M68K_SWITCH_TO_H */
diff --git a/arch/m68k/include/asm/system.h b/arch/m68k/include/asm/system.h
deleted file mode 100644
index 47b01f47..0000000
--- a/arch/m68k/include/asm/system.h
+++ /dev/null
@@ -1,193 +0,0 @@
-#ifndef _M68K_SYSTEM_H
-#define _M68K_SYSTEM_H
-
-#include <linux/linkage.h>
-#include <linux/kernel.h>
-#include <linux/irqflags.h>
-#include <asm/segment.h>
-#include <asm/entry.h>
-
-#ifdef __KERNEL__
-
-/*
- * switch_to(n) should switch tasks to task ptr, first checking that
- * ptr isn't the current task, in which case it does nothing.  This
- * also clears the TS-flag if the task we switched to has used the
- * math co-processor latest.
- */
-/*
- * switch_to() saves the extra registers, that are not saved
- * automatically by SAVE_SWITCH_STACK in resume(), ie. d0-d5 and
- * a0-a1. Some of these are used by schedule() and its predecessors
- * and so we might get see unexpected behaviors when a task returns
- * with unexpected register values.
- *
- * syscall stores these registers itself and none of them are used
- * by syscall after the function in the syscall has been called.
- *
- * Beware that resume now expects *next to be in d1 and the offset of
- * tss to be in a1. This saves a few instructions as we no longer have
- * to push them onto the stack and read them back right after.
- *
- * 02/17/96 - Jes Sorensen (jds@kom.auc.dk)
- *
- * Changed 96/09/19 by Andreas Schwab
- * pass prev in a0, next in a1
- */
-asmlinkage void resume(void);
-#define switch_to(prev,next,last) do { \
-  register void *_prev __asm__ ("a0") = (prev); \
-  register void *_next __asm__ ("a1") = (next); \
-  register void *_last __asm__ ("d1"); \
-  __asm__ __volatile__("jbsr resume" \
-		       : "=a" (_prev), "=a" (_next), "=d" (_last) \
-		       : "0" (_prev), "1" (_next) \
-		       : "d0", "d2", "d3", "d4", "d5"); \
-  (last) = _last; \
-} while (0)
-
-
-/*
- * Force strict CPU ordering.
- * Not really required on m68k...
- */
-#define nop()		do { asm volatile ("nop"); barrier(); } while (0)
-#define mb()		barrier()
-#define rmb()		barrier()
-#define wmb()		barrier()
-#define read_barrier_depends()	((void)0)
-#define set_mb(var, value)	({ (var) = (value); wmb(); })
-
-#define smp_mb()	barrier()
-#define smp_rmb()	barrier()
-#define smp_wmb()	barrier()
-#define smp_read_barrier_depends()	((void)0)
-
-#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-
-struct __xchg_dummy { unsigned long a[100]; };
-#define __xg(x) ((volatile struct __xchg_dummy *)(x))
-
-#ifndef CONFIG_RMW_INSNS
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
-{
-	unsigned long flags, tmp;
-
-	local_irq_save(flags);
-
-	switch (size) {
-	case 1:
-		tmp = *(u8 *)ptr;
-		*(u8 *)ptr = x;
-		x = tmp;
-		break;
-	case 2:
-		tmp = *(u16 *)ptr;
-		*(u16 *)ptr = x;
-		x = tmp;
-		break;
-	case 4:
-		tmp = *(u32 *)ptr;
-		*(u32 *)ptr = x;
-		x = tmp;
-		break;
-	default:
-		BUG();
-	}
-
-	local_irq_restore(flags);
-	return x;
-}
-#else
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
-{
-	switch (size) {
-	    case 1:
-		__asm__ __volatile__
-			("moveb %2,%0\n\t"
-			 "1:\n\t"
-			 "casb %0,%1,%2\n\t"
-			 "jne 1b"
-			 : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory");
-		break;
-	    case 2:
-		__asm__ __volatile__
-			("movew %2,%0\n\t"
-			 "1:\n\t"
-			 "casw %0,%1,%2\n\t"
-			 "jne 1b"
-			 : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory");
-		break;
-	    case 4:
-		__asm__ __volatile__
-			("movel %2,%0\n\t"
-			 "1:\n\t"
-			 "casl %0,%1,%2\n\t"
-			 "jne 1b"
-			 : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory");
-		break;
-	}
-	return x;
-}
-#endif
-
-#include <asm-generic/cmpxchg-local.h>
-
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-
-/*
- * Atomic compare and exchange.  Compare OLD with MEM, if identical,
- * store NEW in MEM.  Return the initial value in MEM.  Success is
- * indicated by comparing RETURN with OLD.
- */
-#ifdef CONFIG_RMW_INSNS
-#define __HAVE_ARCH_CMPXCHG	1
-
-static inline unsigned long __cmpxchg(volatile void *p, unsigned long old,
-				      unsigned long new, int size)
-{
-	switch (size) {
-	case 1:
-		__asm__ __volatile__ ("casb %0,%2,%1"
-				      : "=d" (old), "=m" (*(char *)p)
-				      : "d" (new), "0" (old), "m" (*(char *)p));
-		break;
-	case 2:
-		__asm__ __volatile__ ("casw %0,%2,%1"
-				      : "=d" (old), "=m" (*(short *)p)
-				      : "d" (new), "0" (old), "m" (*(short *)p));
-		break;
-	case 4:
-		__asm__ __volatile__ ("casl %0,%2,%1"
-				      : "=d" (old), "=m" (*(int *)p)
-				      : "d" (new), "0" (old), "m" (*(int *)p));
-		break;
-	}
-	return old;
-}
-
-#define cmpxchg(ptr, o, n)						    \
-	((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),	    \
-			(unsigned long)(n), sizeof(*(ptr))))
-#define cmpxchg_local(ptr, o, n)					    \
-	((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),	    \
-			(unsigned long)(n), sizeof(*(ptr))))
-#else
-
-/*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
- */
-#define cmpxchg_local(ptr, o, n)				  	       \
-	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
-			(unsigned long)(n), sizeof(*(ptr))))
-
-#include <asm-generic/cmpxchg.h>
-
-#endif
-
-#define arch_align_stack(x) (x)
-
-#endif /* __KERNEL__ */
-
-#endif /* _M68K_SYSTEM_H */
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index 74fefac..6b32b64 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -15,7 +15,6 @@
 #include <linux/init.h>
 
 #include <asm/setup.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
 #include <asm/page.h>
diff --git a/arch/m68k/kernel/irq.c b/arch/m68k/kernel/irq.c
index c73988c..9ab4f55 100644
--- a/arch/m68k/kernel/irq.c
+++ b/arch/m68k/kernel/irq.c
@@ -15,7 +15,6 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/seq_file.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 
 asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 6cf4bd6..c488e3c 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -1,5 +1,377 @@
-#ifdef CONFIG_MMU
-#include "process_mm.c"
+/*
+ *  linux/arch/m68k/kernel/process.c
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ *
+ *  68060 fixes by Jesper Skov
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/smp.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/reboot.h>
+#include <linux/init_task.h>
+#include <linux/mqueue.h>
+
+#include <asm/uaccess.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/setup.h>
+#include <asm/pgtable.h>
+
+
+asmlinkage void ret_from_fork(void);
+
+
+/*
+ * Return saved PC from a blocked thread
+ */
+unsigned long thread_saved_pc(struct task_struct *tsk)
+{
+	struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
+	/* Check whether the thread is blocked in resume() */
+	if (in_sched_functions(sw->retpc))
+		return ((unsigned long *)sw->a6)[1];
+	else
+		return sw->retpc;
+}
+
+/*
+ * The idle loop on an m68k..
+ */
+static void default_idle(void)
+{
+	if (!need_resched())
+#if defined(MACH_ATARI_ONLY)
+		/* block out HSYNC on the atari (falcon) */
+		__asm__("stop #0x2200" : : : "cc");
 #else
-#include "process_no.c"
+		__asm__("stop #0x2000" : : : "cc");
 #endif
+}
+
+void (*idle)(void) = default_idle;
+
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle(void)
+{
+	/* endless idle loop with no priority at all */
+	while (1) {
+		while (!need_resched())
+			idle();
+		schedule_preempt_disabled();
+	}
+}
+
+void machine_restart(char * __unused)
+{
+	if (mach_reset)
+		mach_reset();
+	for (;;);
+}
+
+void machine_halt(void)
+{
+	if (mach_halt)
+		mach_halt();
+	for (;;);
+}
+
+void machine_power_off(void)
+{
+	if (mach_power_off)
+		mach_power_off();
+	for (;;);
+}
+
+void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL(pm_power_off);
+
+void show_regs(struct pt_regs * regs)
+{
+	printk("\n");
+	printk("Format %02x  Vector: %04x  PC: %08lx  Status: %04x    %s\n",
+	       regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
+	printk("ORIG_D0: %08lx  D0: %08lx  A2: %08lx  A1: %08lx\n",
+	       regs->orig_d0, regs->d0, regs->a2, regs->a1);
+	printk("A0: %08lx  D5: %08lx  D4: %08lx\n",
+	       regs->a0, regs->d5, regs->d4);
+	printk("D3: %08lx  D2: %08lx  D1: %08lx\n",
+	       regs->d3, regs->d2, regs->d1);
+	if (!(regs->sr & PS_S))
+		printk("USP: %08lx\n", rdusp());
+}
+
+/*
+ * Create a kernel thread
+ */
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+	int pid;
+	mm_segment_t fs;
+
+	fs = get_fs();
+	set_fs (KERNEL_DS);
+
+	{
+	register long retval __asm__ ("d0");
+	register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED;
+
+	retval = __NR_clone;
+	__asm__ __volatile__
+	  ("clrl %%d2\n\t"
+	   "trap #0\n\t"		/* Linux/m68k system call */
+	   "tstl %0\n\t"		/* child or parent */
+	   "jne 1f\n\t"			/* parent - jump */
+#ifdef CONFIG_MMU
+	   "lea %%sp@(%c7),%6\n\t"	/* reload current */
+	   "movel %6@,%6\n\t"
+#endif
+	   "movel %3,%%sp@-\n\t"	/* push argument */
+	   "jsr %4@\n\t"		/* call fn */
+	   "movel %0,%%d1\n\t"		/* pass exit value */
+	   "movel %2,%%d0\n\t"		/* exit */
+	   "trap #0\n"
+	   "1:"
+	   : "+d" (retval)
+	   : "i" (__NR_clone), "i" (__NR_exit),
+	     "r" (arg), "a" (fn), "d" (clone_arg), "r" (current),
+	     "i" (-THREAD_SIZE)
+	   : "d2");
+
+	pid = retval;
+	}
+
+	set_fs (fs);
+	return pid;
+}
+EXPORT_SYMBOL(kernel_thread);
+
+void flush_thread(void)
+{
+	current->thread.fs = __USER_DS;
+#ifdef CONFIG_FPU
+	if (!FPU_IS_EMU) {
+		unsigned long zero = 0;
+		asm volatile("frestore %0": :"m" (zero));
+	}
+#endif
+}
+
+/*
+ * "m68k_fork()".. By the time we get here, the
+ * non-volatile registers have also been saved on the
+ * stack. We do some ugly pointer stuff here.. (see
+ * also copy_thread)
+ */
+
+asmlinkage int m68k_fork(struct pt_regs *regs)
+{
+#ifdef CONFIG_MMU
+	return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
+#else
+	return -EINVAL;
+#endif
+}
+
+asmlinkage int m68k_vfork(struct pt_regs *regs)
+{
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0,
+		       NULL, NULL);
+}
+
+asmlinkage int m68k_clone(struct pt_regs *regs)
+{
+	unsigned long clone_flags;
+	unsigned long newsp;
+	int __user *parent_tidptr, *child_tidptr;
+
+	/* syscall2 puts clone_flags in d1 and usp in d2 */
+	clone_flags = regs->d1;
+	newsp = regs->d2;
+	parent_tidptr = (int __user *)regs->d3;
+	child_tidptr = (int __user *)regs->d4;
+	if (!newsp)
+		newsp = rdusp();
+	return do_fork(clone_flags, newsp, regs, 0,
+		       parent_tidptr, child_tidptr);
+}
+
+int copy_thread(unsigned long clone_flags, unsigned long usp,
+		 unsigned long unused,
+		 struct task_struct * p, struct pt_regs * regs)
+{
+	struct pt_regs * childregs;
+	struct switch_stack * childstack, *stack;
+	unsigned long *retp;
+
+	childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
+
+	*childregs = *regs;
+	childregs->d0 = 0;
+
+	retp = ((unsigned long *) regs);
+	stack = ((struct switch_stack *) retp) - 1;
+
+	childstack = ((struct switch_stack *) childregs) - 1;
+	*childstack = *stack;
+	childstack->retpc = (unsigned long)ret_from_fork;
+
+	p->thread.usp = usp;
+	p->thread.ksp = (unsigned long)childstack;
+
+	if (clone_flags & CLONE_SETTLS)
+		task_thread_info(p)->tp_value = regs->d5;
+
+	/*
+	 * Must save the current SFC/DFC value, NOT the value when
+	 * the parent was last descheduled - RGH  10-08-96
+	 */
+	p->thread.fs = get_fs().seg;
+
+#ifdef CONFIG_FPU
+	if (!FPU_IS_EMU) {
+		/* Copy the current fpu state */
+		asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
+
+		if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) {
+			if (CPU_IS_COLDFIRE) {
+				asm volatile ("fmovemd %/fp0-%/fp7,%0\n\t"
+					      "fmovel %/fpiar,%1\n\t"
+					      "fmovel %/fpcr,%2\n\t"
+					      "fmovel %/fpsr,%3"
+					      :
+					      : "m" (p->thread.fp[0]),
+						"m" (p->thread.fpcntl[0]),
+						"m" (p->thread.fpcntl[1]),
+						"m" (p->thread.fpcntl[2])
+					      : "memory");
+			} else {
+				asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
+					      "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
+					      :
+					      : "m" (p->thread.fp[0]),
+						"m" (p->thread.fpcntl[0])
+					      : "memory");
+			}
+		}
+
+		/* Restore the state in case the fpu was busy */
+		asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
+	}
+#endif /* CONFIG_FPU */
+
+	return 0;
+}
+
+/* Fill in the fpu structure for a core dump.  */
+#ifdef CONFIG_FPU
+int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
+{
+	char fpustate[216];
+
+	if (FPU_IS_EMU) {
+		int i;
+
+		memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
+		memcpy(fpu->fpregs, current->thread.fp, 96);
+		/* Convert internal fpu reg representation
+		 * into long double format
+		 */
+		for (i = 0; i < 24; i += 3)
+			fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
+			                 ((fpu->fpregs[i] & 0x0000ffff) << 16);
+		return 1;
+	}
+
+	/* First dump the fpu context to avoid protocol violation.  */
+	asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
+	if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
+		return 0;
+
+	if (CPU_IS_COLDFIRE) {
+		asm volatile ("fmovel %/fpiar,%0\n\t"
+			      "fmovel %/fpcr,%1\n\t"
+			      "fmovel %/fpsr,%2\n\t"
+			      "fmovemd %/fp0-%/fp7,%3"
+			      :
+			      : "m" (fpu->fpcntl[0]),
+				"m" (fpu->fpcntl[1]),
+				"m" (fpu->fpcntl[2]),
+				"m" (fpu->fpregs[0])
+			      : "memory");
+	} else {
+		asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
+			      :
+			      : "m" (fpu->fpcntl[0])
+			      : "memory");
+		asm volatile ("fmovemx %/fp0-%/fp7,%0"
+			      :
+			      : "m" (fpu->fpregs[0])
+			      : "memory");
+	}
+
+	return 1;
+}
+EXPORT_SYMBOL(dump_fpu);
+#endif /* CONFIG_FPU */
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(const char __user *name,
+			  const char __user *const __user *argv,
+			  const char __user *const __user *envp)
+{
+	int error;
+	char * filename;
+	struct pt_regs *regs = (struct pt_regs *) &name;
+
+	filename = getname(name);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		return error;
+	error = do_execve(filename, argv, envp, regs);
+	putname(filename);
+	return error;
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+	unsigned long fp, pc;
+	unsigned long stack_page;
+	int count = 0;
+	if (!p || p == current || p->state == TASK_RUNNING)
+		return 0;
+
+	stack_page = (unsigned long)task_stack_page(p);
+	fp = ((struct switch_stack *)p->thread.ksp)->a6;
+	do {
+		if (fp < stack_page+sizeof(struct thread_info) ||
+		    fp >= 8184+stack_page)
+			return 0;
+		pc = ((unsigned long *)fp)[1];
+		if (!in_sched_functions(pc))
+			return pc;
+		fp = *(unsigned long *) fp;
+	} while (count++ < 16);
+	return 0;
+}
diff --git a/arch/m68k/kernel/process_mm.c b/arch/m68k/kernel/process_mm.c
deleted file mode 100644
index fe4186b..0000000
--- a/arch/m68k/kernel/process_mm.c
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- *  linux/arch/m68k/kernel/process.c
- *
- *  Copyright (C) 1995  Hamish Macdonald
- *
- *  68060 fixes by Jesper Skov
- */
-
-/*
- * This file handles the architecture-dependent parts of process handling..
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/smp.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-#include <linux/reboot.h>
-#include <linux/init_task.h>
-#include <linux/mqueue.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/traps.h>
-#include <asm/machdep.h>
-#include <asm/setup.h>
-#include <asm/pgtable.h>
-
-
-asmlinkage void ret_from_fork(void);
-
-
-/*
- * Return saved PC from a blocked thread
- */
-unsigned long thread_saved_pc(struct task_struct *tsk)
-{
-	struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
-	/* Check whether the thread is blocked in resume() */
-	if (in_sched_functions(sw->retpc))
-		return ((unsigned long *)sw->a6)[1];
-	else
-		return sw->retpc;
-}
-
-/*
- * The idle loop on an m68k..
- */
-static void default_idle(void)
-{
-	if (!need_resched())
-#if defined(MACH_ATARI_ONLY)
-		/* block out HSYNC on the atari (falcon) */
-		__asm__("stop #0x2200" : : : "cc");
-#else
-		__asm__("stop #0x2000" : : : "cc");
-#endif
-}
-
-void (*idle)(void) = default_idle;
-
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle(void)
-{
-	/* endless idle loop with no priority at all */
-	while (1) {
-		while (!need_resched())
-			idle();
-		schedule_preempt_disabled();
-	}
-}
-
-void machine_restart(char * __unused)
-{
-	if (mach_reset)
-		mach_reset();
-	for (;;);
-}
-
-void machine_halt(void)
-{
-	if (mach_halt)
-		mach_halt();
-	for (;;);
-}
-
-void machine_power_off(void)
-{
-	if (mach_power_off)
-		mach_power_off();
-	for (;;);
-}
-
-void (*pm_power_off)(void) = machine_power_off;
-EXPORT_SYMBOL(pm_power_off);
-
-void show_regs(struct pt_regs * regs)
-{
-	printk("\n");
-	printk("Format %02x  Vector: %04x  PC: %08lx  Status: %04x    %s\n",
-	       regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
-	printk("ORIG_D0: %08lx  D0: %08lx  A2: %08lx  A1: %08lx\n",
-	       regs->orig_d0, regs->d0, regs->a2, regs->a1);
-	printk("A0: %08lx  D5: %08lx  D4: %08lx\n",
-	       regs->a0, regs->d5, regs->d4);
-	printk("D3: %08lx  D2: %08lx  D1: %08lx\n",
-	       regs->d3, regs->d2, regs->d1);
-	if (!(regs->sr & PS_S))
-		printk("USP: %08lx\n", rdusp());
-}
-
-/*
- * Create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-	int pid;
-	mm_segment_t fs;
-
-	fs = get_fs();
-	set_fs (KERNEL_DS);
-
-	{
-	register long retval __asm__ ("d0");
-	register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED;
-
-	retval = __NR_clone;
-	__asm__ __volatile__
-	  ("clrl %%d2\n\t"
-	   "trap #0\n\t"		/* Linux/m68k system call */
-	   "tstl %0\n\t"		/* child or parent */
-	   "jne 1f\n\t"			/* parent - jump */
-	   "lea %%sp@(%c7),%6\n\t"	/* reload current */
-	   "movel %6@,%6\n\t"
-	   "movel %3,%%sp@-\n\t"	/* push argument */
-	   "jsr %4@\n\t"		/* call fn */
-	   "movel %0,%%d1\n\t"		/* pass exit value */
-	   "movel %2,%%d0\n\t"		/* exit */
-	   "trap #0\n"
-	   "1:"
-	   : "+d" (retval)
-	   : "i" (__NR_clone), "i" (__NR_exit),
-	     "r" (arg), "a" (fn), "d" (clone_arg), "r" (current),
-	     "i" (-THREAD_SIZE)
-	   : "d2");
-
-	pid = retval;
-	}
-
-	set_fs (fs);
-	return pid;
-}
-EXPORT_SYMBOL(kernel_thread);
-
-void flush_thread(void)
-{
-	unsigned long zero = 0;
-
-	current->thread.fs = __USER_DS;
-	if (!FPU_IS_EMU)
-		asm volatile("frestore %0": :"m" (zero));
-}
-
-/*
- * "m68k_fork()".. By the time we get here, the
- * non-volatile registers have also been saved on the
- * stack. We do some ugly pointer stuff here.. (see
- * also copy_thread)
- */
-
-asmlinkage int m68k_fork(struct pt_regs *regs)
-{
-	return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-}
-
-asmlinkage int m68k_vfork(struct pt_regs *regs)
-{
-	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0,
-		       NULL, NULL);
-}
-
-asmlinkage int m68k_clone(struct pt_regs *regs)
-{
-	unsigned long clone_flags;
-	unsigned long newsp;
-	int __user *parent_tidptr, *child_tidptr;
-
-	/* syscall2 puts clone_flags in d1 and usp in d2 */
-	clone_flags = regs->d1;
-	newsp = regs->d2;
-	parent_tidptr = (int __user *)regs->d3;
-	child_tidptr = (int __user *)regs->d4;
-	if (!newsp)
-		newsp = rdusp();
-	return do_fork(clone_flags, newsp, regs, 0,
-		       parent_tidptr, child_tidptr);
-}
-
-int copy_thread(unsigned long clone_flags, unsigned long usp,
-		 unsigned long unused,
-		 struct task_struct * p, struct pt_regs * regs)
-{
-	struct pt_regs * childregs;
-	struct switch_stack * childstack, *stack;
-	unsigned long *retp;
-
-	childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
-
-	*childregs = *regs;
-	childregs->d0 = 0;
-
-	retp = ((unsigned long *) regs);
-	stack = ((struct switch_stack *) retp) - 1;
-
-	childstack = ((struct switch_stack *) childregs) - 1;
-	*childstack = *stack;
-	childstack->retpc = (unsigned long)ret_from_fork;
-
-	p->thread.usp = usp;
-	p->thread.ksp = (unsigned long)childstack;
-
-	if (clone_flags & CLONE_SETTLS)
-		task_thread_info(p)->tp_value = regs->d5;
-
-	/*
-	 * Must save the current SFC/DFC value, NOT the value when
-	 * the parent was last descheduled - RGH  10-08-96
-	 */
-	p->thread.fs = get_fs().seg;
-
-	if (!FPU_IS_EMU) {
-		/* Copy the current fpu state */
-		asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
-
-		if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) {
-			if (CPU_IS_COLDFIRE) {
-				asm volatile ("fmovemd %/fp0-%/fp7,%0\n\t"
-					      "fmovel %/fpiar,%1\n\t"
-					      "fmovel %/fpcr,%2\n\t"
-					      "fmovel %/fpsr,%3"
-					      :
-					      : "m" (p->thread.fp[0]),
-						"m" (p->thread.fpcntl[0]),
-						"m" (p->thread.fpcntl[1]),
-						"m" (p->thread.fpcntl[2])
-					      : "memory");
-			} else {
-				asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
-					      "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
-					      :
-					      : "m" (p->thread.fp[0]),
-						"m" (p->thread.fpcntl[0])
-					      : "memory");
-			}
-		}
-
-		/* Restore the state in case the fpu was busy */
-		asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
-	}
-
-	return 0;
-}
-
-/* Fill in the fpu structure for a core dump.  */
-
-int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
-{
-	char fpustate[216];
-
-	if (FPU_IS_EMU) {
-		int i;
-
-		memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
-		memcpy(fpu->fpregs, current->thread.fp, 96);
-		/* Convert internal fpu reg representation
-		 * into long double format
-		 */
-		for (i = 0; i < 24; i += 3)
-			fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
-			                 ((fpu->fpregs[i] & 0x0000ffff) << 16);
-		return 1;
-	}
-
-	/* First dump the fpu context to avoid protocol violation.  */
-	asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
-	if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
-		return 0;
-
-	if (CPU_IS_COLDFIRE) {
-		asm volatile ("fmovel %/fpiar,%0\n\t"
-			      "fmovel %/fpcr,%1\n\t"
-			      "fmovel %/fpsr,%2\n\t"
-			      "fmovemd %/fp0-%/fp7,%3"
-			      :
-			      : "m" (fpu->fpcntl[0]),
-				"m" (fpu->fpcntl[1]),
-				"m" (fpu->fpcntl[2]),
-				"m" (fpu->fpregs[0])
-			      : "memory");
-	} else {
-		asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
-			      :
-			      : "m" (fpu->fpcntl[0])
-			      : "memory");
-		asm volatile ("fmovemx %/fp0-%/fp7,%0"
-			      :
-			      : "m" (fpu->fpregs[0])
-			      : "memory");
-	}
-
-	return 1;
-}
-EXPORT_SYMBOL(dump_fpu);
-
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(const char __user *name,
-			  const char __user *const __user *argv,
-			  const char __user *const __user *envp)
-{
-	int error;
-	char * filename;
-	struct pt_regs *regs = (struct pt_regs *) &name;
-
-	filename = getname(name);
-	error = PTR_ERR(filename);
-	if (IS_ERR(filename))
-		return error;
-	error = do_execve(filename, argv, envp, regs);
-	putname(filename);
-	return error;
-}
-
-unsigned long get_wchan(struct task_struct *p)
-{
-	unsigned long fp, pc;
-	unsigned long stack_page;
-	int count = 0;
-	if (!p || p == current || p->state == TASK_RUNNING)
-		return 0;
-
-	stack_page = (unsigned long)task_stack_page(p);
-	fp = ((struct switch_stack *)p->thread.ksp)->a6;
-	do {
-		if (fp < stack_page+sizeof(struct thread_info) ||
-		    fp >= 8184+stack_page)
-			return 0;
-		pc = ((unsigned long *)fp)[1];
-		if (!in_sched_functions(pc))
-			return pc;
-		fp = *(unsigned long *) fp;
-	} while (count++ < 16);
-	return 0;
-}
diff --git a/arch/m68k/kernel/process_no.c b/arch/m68k/kernel/process_no.c
deleted file mode 100644
index f7fe6c3..0000000
--- a/arch/m68k/kernel/process_no.c
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/process.c
- *
- *  Copyright (C) 1995  Hamish Macdonald
- *
- *  68060 fixes by Jesper Skov
- *
- *  uClinux changes
- *  Copyright (C) 2000-2002, David McCullough <davidm@snapgear.com>
- */
-
-/*
- * This file handles the architecture-dependent parts of process handling..
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/traps.h>
-#include <asm/machdep.h>
-#include <asm/setup.h>
-#include <asm/pgtable.h>
-
-asmlinkage void ret_from_fork(void);
-
-/*
- * The following aren't currently used.
- */
-void (*pm_idle)(void);
-EXPORT_SYMBOL(pm_idle);
-
-void (*pm_power_off)(void);
-EXPORT_SYMBOL(pm_power_off);
-
-/*
- * The idle loop on an m68knommu..
- */
-static void default_idle(void)
-{
-	local_irq_disable();
- 	while (!need_resched()) {
-		/* This stop will re-enable interrupts */
- 		__asm__("stop #0x2000" : : : "cc");
-		local_irq_disable();
-	}
-	local_irq_enable();
-}
-
-void (*idle)(void) = default_idle;
-
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle(void)
-{
-	/* endless idle loop with no priority at all */
-	while (1) {
-		idle();
-		schedule_preempt_disabled();
-	}
-}
-
-void machine_restart(char * __unused)
-{
-	if (mach_reset)
-		mach_reset();
-	for (;;);
-}
-
-void machine_halt(void)
-{
-	if (mach_halt)
-		mach_halt();
-	for (;;);
-}
-
-void machine_power_off(void)
-{
-	if (mach_power_off)
-		mach_power_off();
-	for (;;);
-}
-
-void show_regs(struct pt_regs * regs)
-{
-	printk(KERN_NOTICE "\n");
-	printk(KERN_NOTICE "Format %02x  Vector: %04x  PC: %08lx  Status: %04x    %s\n",
-	       regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
-	printk(KERN_NOTICE "ORIG_D0: %08lx  D0: %08lx  A2: %08lx  A1: %08lx\n",
-	       regs->orig_d0, regs->d0, regs->a2, regs->a1);
-	printk(KERN_NOTICE "A0: %08lx  D5: %08lx  D4: %08lx\n",
-	       regs->a0, regs->d5, regs->d4);
-	printk(KERN_NOTICE "D3: %08lx  D2: %08lx  D1: %08lx\n",
-	       regs->d3, regs->d2, regs->d1);
-	if (!(regs->sr & PS_S))
-		printk(KERN_NOTICE "USP: %08lx\n", rdusp());
-}
-
-/*
- * Create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-	int retval;
-	long clone_arg = flags | CLONE_VM;
-	mm_segment_t fs;
-
-	fs = get_fs();
-	set_fs(KERNEL_DS);
-
-	__asm__ __volatile__ (
-			"movel	%%sp, %%d2\n\t"
-			"movel	%5, %%d1\n\t"
-			"movel	%1, %%d0\n\t"
-			"trap	#0\n\t"
-			"cmpl	%%sp, %%d2\n\t"
-			"jeq	1f\n\t"
-			"movel	%3, %%sp@-\n\t"
-			"jsr	%4@\n\t"
-			"movel	%2, %%d0\n\t"
-			"trap	#0\n"
-			"1:\n\t"
-			"movel	%%d0, %0\n"
-		: "=d" (retval)
-		: "i" (__NR_clone),
-		  "i" (__NR_exit),
-		  "a" (arg),
-		  "a" (fn),
-		  "a" (clone_arg)
-		: "cc", "%d0", "%d1", "%d2");
-
-	set_fs(fs);
-	return retval;
-}
-EXPORT_SYMBOL(kernel_thread);
-
-void flush_thread(void)
-{
-#ifdef CONFIG_FPU
-	unsigned long zero = 0;
-#endif
-
-	current->thread.fs = __USER_DS;
-#ifdef CONFIG_FPU
-	if (!FPU_IS_EMU)
-		asm volatile (".chip 68k/68881\n\t"
-			      "frestore %0\n\t"
-			      ".chip 68k" : : "m" (zero));
-#endif
-}
-
-/*
- * "m68k_fork()".. By the time we get here, the
- * non-volatile registers have also been saved on the
- * stack. We do some ugly pointer stuff here.. (see
- * also copy_thread)
- */
-
-asmlinkage int m68k_fork(struct pt_regs *regs)
-{
-	/* fork almost works, enough to trick you into looking elsewhere :-( */
-	return(-EINVAL);
-}
-
-asmlinkage int m68k_vfork(struct pt_regs *regs)
-{
-	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-}
-
-asmlinkage int m68k_clone(struct pt_regs *regs)
-{
-	unsigned long clone_flags;
-	unsigned long newsp;
-
-	/* syscall2 puts clone_flags in d1 and usp in d2 */
-	clone_flags = regs->d1;
-	newsp = regs->d2;
-	if (!newsp)
-		newsp = rdusp();
-        return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
-}
-
-int copy_thread(unsigned long clone_flags,
-		unsigned long usp, unsigned long topstk,
-		struct task_struct * p, struct pt_regs * regs)
-{
-	struct pt_regs * childregs;
-	struct switch_stack * childstack, *stack;
-	unsigned long *retp;
-
-	childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
-
-	*childregs = *regs;
-	childregs->d0 = 0;
-
-	retp = ((unsigned long *) regs);
-	stack = ((struct switch_stack *) retp) - 1;
-
-	childstack = ((struct switch_stack *) childregs) - 1;
-	*childstack = *stack;
-	childstack->retpc = (unsigned long)ret_from_fork;
-
-	p->thread.usp = usp;
-	p->thread.ksp = (unsigned long)childstack;
-
-	if (clone_flags & CLONE_SETTLS)
-		task_thread_info(p)->tp_value = regs->d5;
-
-	/*
-	 * Must save the current SFC/DFC value, NOT the value when
-	 * the parent was last descheduled - RGH  10-08-96
-	 */
-	p->thread.fs = get_fs().seg;
-
-#ifdef CONFIG_FPU
-	if (!FPU_IS_EMU) {
-		/* Copy the current fpu state */
-		asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
-
-		if (p->thread.fpstate[0])
-		  asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
-				"fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
-				: : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
-				: "memory");
-		/* Restore the state in case the fpu was busy */
-		asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
-	}
-#endif
-
-	return 0;
-}
-
-/* Fill in the fpu structure for a core dump.  */
-
-int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu)
-{
-#ifdef CONFIG_FPU
-	char fpustate[216];
-
-	if (FPU_IS_EMU) {
-		int i;
-
-		memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
-		memcpy(fpu->fpregs, current->thread.fp, 96);
-		/* Convert internal fpu reg representation
-		 * into long double format
-		 */
-		for (i = 0; i < 24; i += 3)
-			fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
-			                 ((fpu->fpregs[i] & 0x0000ffff) << 16);
-		return 1;
-	}
-
-	/* First dump the fpu context to avoid protocol violation.  */
-	asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
-	if (!fpustate[0])
-		return 0;
-
-	asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
-		:: "m" (fpu->fpcntl[0])
-		: "memory");
-	asm volatile ("fmovemx %/fp0-%/fp7,%0"
-		:: "m" (fpu->fpregs[0])
-		: "memory");
-#endif
-	return 1;
-}
-EXPORT_SYMBOL(dump_fpu);
-
-/*
- *	Generic dumping code. Used for panic and debug.
- */
-void dump(struct pt_regs *fp)
-{
-	unsigned long	*sp;
-	unsigned char	*tp;
-	int		i;
-
-	printk(KERN_EMERG "\nCURRENT PROCESS:\n\n");
-	printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid);
-
-	if (current->mm) {
-		printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n",
-			(int) current->mm->start_code,
-			(int) current->mm->end_code,
-			(int) current->mm->start_data,
-			(int) current->mm->end_data,
-			(int) current->mm->end_data,
-			(int) current->mm->brk);
-		printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n",
-			(int) current->mm->start_stack,
-			(int)(((unsigned long) current) + THREAD_SIZE));
-	}
-
-	printk(KERN_EMERG "PC: %08lx\n", fp->pc);
-	printk(KERN_EMERG "SR: %08lx    SP: %08lx\n", (long) fp->sr, (long) fp);
-	printk(KERN_EMERG "d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
-		fp->d0, fp->d1, fp->d2, fp->d3);
-	printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
-		fp->d4, fp->d5, fp->a0, fp->a1);
-	printk(KERN_EMERG "\nUSP: %08x   TRAPFRAME: %p\n",
-		(unsigned int) rdusp(), fp);
-
-	printk(KERN_EMERG "\nCODE:");
-	tp = ((unsigned char *) fp->pc) - 0x20;
-	for (sp = (unsigned long *) tp, i = 0; (i < 0x40);  i += 4) {
-		if ((i % 0x10) == 0)
-			printk(KERN_EMERG "%p: ", tp + i);
-		printk("%08x ", (int) *sp++);
-	}
-	printk(KERN_EMERG "\n");
-
-	printk(KERN_EMERG "KERNEL STACK:");
-	tp = ((unsigned char *) fp) - 0x40;
-	for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) {
-		if ((i % 0x10) == 0)
-			printk(KERN_EMERG "%p: ", tp + i);
-		printk("%08x ", (int) *sp++);
-	}
-	printk(KERN_EMERG "\n");
-
-	printk(KERN_EMERG "USER STACK:");
-	tp = (unsigned char *) (rdusp() - 0x10);
-	for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) {
-		if ((i % 0x10) == 0)
-			printk(KERN_EMERG "%p: ", tp + i);
-		printk("%08x ", (int) *sp++);
-	}
-	printk(KERN_EMERG "\n");
-}
-
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(const char *name,
-			  const char *const *argv,
-			  const char *const *envp)
-{
-	int error;
-	char * filename;
-	struct pt_regs *regs = (struct pt_regs *) &name;
-
-	filename = getname(name);
-	error = PTR_ERR(filename);
-	if (IS_ERR(filename))
-		return error;
-	error = do_execve(filename, argv, envp, regs);
-	putname(filename);
-	return error;
-}
-
-unsigned long get_wchan(struct task_struct *p)
-{
-	unsigned long fp, pc;
-	unsigned long stack_page;
-	int count = 0;
-	if (!p || p == current || p->state == TASK_RUNNING)
-		return 0;
-
-	stack_page = (unsigned long)p;
-	fp = ((struct switch_stack *)p->thread.ksp)->a6;
-	do {
-		if (fp < stack_page+sizeof(struct thread_info) ||
-		    fp >= THREAD_SIZE-8+stack_page)
-			return 0;
-		pc = ((unsigned long *)fp)[1];
-		if (!in_sched_functions(pc))
-			return pc;
-		fp = *(unsigned long *) fp;
-	} while (count++ < 16);
-	return 0;
-}
-
-/*
- * Return saved PC of a blocked thread.
- */
-unsigned long thread_saved_pc(struct task_struct *tsk)
-{
-	struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
-
-	/* Check whether the thread is blocked in resume() */
-	if (in_sched_functions(sw->retpc))
-		return ((unsigned long *)sw->a6)[1];
-	else
-		return sw->retpc;
-}
-
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 07a4175..8b4a222 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -1,5 +1,304 @@
+/*
+ *  linux/arch/m68k/kernel/ptrace.c
+ *
+ *  Copyright (C) 1994 by Hamish Macdonald
+ *  Taken from linux/kernel/ptrace.c and modified for M680x0.
+ *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ *
+ * 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/signal.h>
+#include <linux/tracehook.h>
+
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/* determines which bits in the SR the user has access to. */
+/* 1 = access 0 = no access */
+#define SR_MASK 0x001f
+
+/* sets the trace bits. */
+#define TRACE_BITS 0xC000
+#define T1_BIT 0x8000
+#define T0_BIT 0x4000
+
+/* Find the stack offset for a register, relative to thread.esp0. */
+#define PT_REG(reg)	((long)&((struct pt_regs *)0)->reg)
+#define SW_REG(reg)	((long)&((struct switch_stack *)0)->reg \
+			 - sizeof(struct switch_stack))
+/* Mapping from PT_xxx to the stack offset at which the register is
+   saved.  Notice that usp has no stack-slot and needs to be treated
+   specially (see get_reg/put_reg below). */
+static const int regoff[] = {
+	[0]	= PT_REG(d1),
+	[1]	= PT_REG(d2),
+	[2]	= PT_REG(d3),
+	[3]	= PT_REG(d4),
+	[4]	= PT_REG(d5),
+	[5]	= SW_REG(d6),
+	[6]	= SW_REG(d7),
+	[7]	= PT_REG(a0),
+	[8]	= PT_REG(a1),
+	[9]	= PT_REG(a2),
+	[10]	= SW_REG(a3),
+	[11]	= SW_REG(a4),
+	[12]	= SW_REG(a5),
+	[13]	= SW_REG(a6),
+	[14]	= PT_REG(d0),
+	[15]	= -1,
+	[16]	= PT_REG(orig_d0),
+	[17]	= PT_REG(sr),
+	[18]	= PT_REG(pc),
+};
+
+/*
+ * Get contents of register REGNO in task TASK.
+ */
+static inline long get_reg(struct task_struct *task, int regno)
+{
+	unsigned long *addr;
+
+	if (regno == PT_USP)
+		addr = &task->thread.usp;
+	else if (regno < ARRAY_SIZE(regoff))
+		addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
+	else
+		return 0;
+	/* Need to take stkadj into account. */
+	if (regno == PT_SR || regno == PT_PC) {
+		long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
+		addr = (unsigned long *) ((unsigned long)addr + stkadj);
+		/* The sr is actually a 16 bit register.  */
+		if (regno == PT_SR)
+			return *(unsigned short *)addr;
+	}
+	return *addr;
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+static inline int put_reg(struct task_struct *task, int regno,
+			  unsigned long data)
+{
+	unsigned long *addr;
+
+	if (regno == PT_USP)
+		addr = &task->thread.usp;
+	else if (regno < ARRAY_SIZE(regoff))
+		addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
+	else
+		return -1;
+	/* Need to take stkadj into account. */
+	if (regno == PT_SR || regno == PT_PC) {
+		long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
+		addr = (unsigned long *) ((unsigned long)addr + stkadj);
+		/* The sr is actually a 16 bit register.  */
+		if (regno == PT_SR) {
+			*(unsigned short *)addr = data;
+			return 0;
+		}
+	}
+	*addr = data;
+	return 0;
+}
+
+/*
+ * Make sure the single step bit is not set.
+ */
+static inline void singlestep_disable(struct task_struct *child)
+{
+	unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
+	put_reg(child, PT_SR, tmp);
+	clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ */
+void ptrace_disable(struct task_struct *child)
+{
+	singlestep_disable(child);
+}
+
+void user_enable_single_step(struct task_struct *child)
+{
+	unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
+	put_reg(child, PT_SR, tmp | T1_BIT);
+	set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
+}
+
 #ifdef CONFIG_MMU
-#include "ptrace_mm.c"
-#else
-#include "ptrace_no.c"
+void user_enable_block_step(struct task_struct *child)
+{
+	unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
+	put_reg(child, PT_SR, tmp | T0_BIT);
+}
 #endif
+
+void user_disable_single_step(struct task_struct *child)
+{
+	singlestep_disable(child);
+}
+
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
+{
+	unsigned long tmp;
+	int i, ret = 0;
+	int regno = addr >> 2; /* temporary hack. */
+	unsigned long __user *datap = (unsigned long __user *) data;
+
+	switch (request) {
+	/* read the word at location addr in the USER area. */
+	case PTRACE_PEEKUSR:
+		if (addr & 3)
+			goto out_eio;
+
+		if (regno >= 0 && regno < 19) {
+			tmp = get_reg(child, regno);
+		} else if (regno >= 21 && regno < 49) {
+			tmp = child->thread.fp[regno - 21];
+			/* Convert internal fpu reg representation
+			 * into long double format
+			 */
+			if (FPU_IS_EMU && (regno < 45) && !(regno % 3))
+				tmp = ((tmp & 0xffff0000) << 15) |
+				      ((tmp & 0x0000ffff) << 16);
+#ifndef CONFIG_MMU
+		} else if (regno == 49) {
+			tmp = child->mm->start_code;
+		} else if (regno == 50) {
+			tmp = child->mm->start_data;
+		} else if (regno == 51) {
+			tmp = child->mm->end_code;
+#endif
+		} else
+			goto out_eio;
+		ret = put_user(tmp, datap);
+		break;
+
+	case PTRACE_POKEUSR:
+	/* write the word at location addr in the USER area */
+		if (addr & 3)
+			goto out_eio;
+
+		if (regno == PT_SR) {
+			data &= SR_MASK;
+			data |= get_reg(child, PT_SR) & ~SR_MASK;
+		}
+		if (regno >= 0 && regno < 19) {
+			if (put_reg(child, regno, data))
+				goto out_eio;
+		} else if (regno >= 21 && regno < 48) {
+			/* Convert long double format
+			 * into internal fpu reg representation
+			 */
+			if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) {
+				data <<= 15;
+				data = (data & 0xffff0000) |
+				       ((data & 0x0000ffff) >> 1);
+			}
+			child->thread.fp[regno - 21] = data;
+		} else
+			goto out_eio;
+		break;
+
+	case PTRACE_GETREGS:	/* Get all gp regs from the child. */
+		for (i = 0; i < 19; i++) {
+			tmp = get_reg(child, i);
+			ret = put_user(tmp, datap);
+			if (ret)
+				break;
+			datap++;
+		}
+		break;
+
+	case PTRACE_SETREGS:	/* Set all gp regs in the child. */
+		for (i = 0; i < 19; i++) {
+			ret = get_user(tmp, datap);
+			if (ret)
+				break;
+			if (i == PT_SR) {
+				tmp &= SR_MASK;
+				tmp |= get_reg(child, PT_SR) & ~SR_MASK;
+			}
+			put_reg(child, i, tmp);
+			datap++;
+		}
+		break;
+
+	case PTRACE_GETFPREGS:	/* Get the child FPU state. */
+		if (copy_to_user(datap, &child->thread.fp,
+				 sizeof(struct user_m68kfp_struct)))
+			ret = -EFAULT;
+		break;
+
+	case PTRACE_SETFPREGS:	/* Set the child FPU state. */
+		if (copy_from_user(&child->thread.fp, datap,
+				   sizeof(struct user_m68kfp_struct)))
+			ret = -EFAULT;
+		break;
+
+	case PTRACE_GET_THREAD_AREA:
+		ret = put_user(task_thread_info(child)->tp_value, datap);
+		break;
+
+	default:
+		ret = ptrace_request(child, request, addr, data);
+		break;
+	}
+
+	return ret;
+out_eio:
+	return -EIO;
+}
+
+asmlinkage void syscall_trace(void)
+{
+	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+				 ? 0x80 : 0));
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (current->exit_code) {
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
+}
+
+#ifdef CONFIG_COLDFIRE
+asmlinkage int syscall_trace_enter(void)
+{
+	int ret = 0;
+
+	if (test_thread_flag(TIF_SYSCALL_TRACE))
+		ret = tracehook_report_syscall_entry(task_pt_regs(current));
+	return ret;
+}
+
+asmlinkage void syscall_trace_leave(void)
+{
+	if (test_thread_flag(TIF_SYSCALL_TRACE))
+		tracehook_report_syscall_exit(task_pt_regs(current), 0);
+}
+#endif /* CONFIG_COLDFIRE */
diff --git a/arch/m68k/kernel/ptrace_mm.c b/arch/m68k/kernel/ptrace_mm.c
deleted file mode 100644
index 7bc999b..0000000
--- a/arch/m68k/kernel/ptrace_mm.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- *  linux/arch/m68k/kernel/ptrace.c
- *
- *  Copyright (C) 1994 by Hamish Macdonald
- *  Taken from linux/kernel/ptrace.c and modified for M680x0.
- *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
- *
- * 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/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-#include <linux/signal.h>
-#include <linux/tracehook.h>
-
-#include <asm/uaccess.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/processor.h>
-
-/*
- * does not yet catch signals sent when the child dies.
- * in exit.c or in signal.c.
- */
-
-/* determines which bits in the SR the user has access to. */
-/* 1 = access 0 = no access */
-#define SR_MASK 0x001f
-
-/* sets the trace bits. */
-#define TRACE_BITS 0xC000
-#define T1_BIT 0x8000
-#define T0_BIT 0x4000
-
-/* Find the stack offset for a register, relative to thread.esp0. */
-#define PT_REG(reg)	((long)&((struct pt_regs *)0)->reg)
-#define SW_REG(reg)	((long)&((struct switch_stack *)0)->reg \
-			 - sizeof(struct switch_stack))
-/* Mapping from PT_xxx to the stack offset at which the register is
-   saved.  Notice that usp has no stack-slot and needs to be treated
-   specially (see get_reg/put_reg below). */
-static const int regoff[] = {
-	[0]	= PT_REG(d1),
-	[1]	= PT_REG(d2),
-	[2]	= PT_REG(d3),
-	[3]	= PT_REG(d4),
-	[4]	= PT_REG(d5),
-	[5]	= SW_REG(d6),
-	[6]	= SW_REG(d7),
-	[7]	= PT_REG(a0),
-	[8]	= PT_REG(a1),
-	[9]	= PT_REG(a2),
-	[10]	= SW_REG(a3),
-	[11]	= SW_REG(a4),
-	[12]	= SW_REG(a5),
-	[13]	= SW_REG(a6),
-	[14]	= PT_REG(d0),
-	[15]	= -1,
-	[16]	= PT_REG(orig_d0),
-	[17]	= PT_REG(sr),
-	[18]	= PT_REG(pc),
-};
-
-/*
- * Get contents of register REGNO in task TASK.
- */
-static inline long get_reg(struct task_struct *task, int regno)
-{
-	unsigned long *addr;
-
-	if (regno == PT_USP)
-		addr = &task->thread.usp;
-	else if (regno < ARRAY_SIZE(regoff))
-		addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
-	else
-		return 0;
-	/* Need to take stkadj into account. */
-	if (regno == PT_SR || regno == PT_PC) {
-		long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
-		addr = (unsigned long *) ((unsigned long)addr + stkadj);
-		/* The sr is actually a 16 bit register.  */
-		if (regno == PT_SR)
-			return *(unsigned short *)addr;
-	}
-	return *addr;
-}
-
-/*
- * Write contents of register REGNO in task TASK.
- */
-static inline int put_reg(struct task_struct *task, int regno,
-			  unsigned long data)
-{
-	unsigned long *addr;
-
-	if (regno == PT_USP)
-		addr = &task->thread.usp;
-	else if (regno < ARRAY_SIZE(regoff))
-		addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
-	else
-		return -1;
-	/* Need to take stkadj into account. */
-	if (regno == PT_SR || regno == PT_PC) {
-		long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
-		addr = (unsigned long *) ((unsigned long)addr + stkadj);
-		/* The sr is actually a 16 bit register.  */
-		if (regno == PT_SR) {
-			*(unsigned short *)addr = data;
-			return 0;
-		}
-	}
-	*addr = data;
-	return 0;
-}
-
-/*
- * Make sure the single step bit is not set.
- */
-static inline void singlestep_disable(struct task_struct *child)
-{
-	unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
-	put_reg(child, PT_SR, tmp);
-	clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
-}
-
-/*
- * Called by kernel/ptrace.c when detaching..
- */
-void ptrace_disable(struct task_struct *child)
-{
-	singlestep_disable(child);
-}
-
-void user_enable_single_step(struct task_struct *child)
-{
-	unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
-	put_reg(child, PT_SR, tmp | T1_BIT);
-	set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
-}
-
-void user_enable_block_step(struct task_struct *child)
-{
-	unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
-	put_reg(child, PT_SR, tmp | T0_BIT);
-}
-
-void user_disable_single_step(struct task_struct *child)
-{
-	singlestep_disable(child);
-}
-
-long arch_ptrace(struct task_struct *child, long request,
-		 unsigned long addr, unsigned long data)
-{
-	unsigned long tmp;
-	int i, ret = 0;
-	int regno = addr >> 2; /* temporary hack. */
-	unsigned long __user *datap = (unsigned long __user *) data;
-
-	switch (request) {
-	/* read the word at location addr in the USER area. */
-	case PTRACE_PEEKUSR:
-		if (addr & 3)
-			goto out_eio;
-
-		if (regno >= 0 && regno < 19) {
-			tmp = get_reg(child, regno);
-		} else if (regno >= 21 && regno < 49) {
-			tmp = child->thread.fp[regno - 21];
-			/* Convert internal fpu reg representation
-			 * into long double format
-			 */
-			if (FPU_IS_EMU && (regno < 45) && !(regno % 3))
-				tmp = ((tmp & 0xffff0000) << 15) |
-				      ((tmp & 0x0000ffff) << 16);
-		} else
-			goto out_eio;
-		ret = put_user(tmp, datap);
-		break;
-
-	case PTRACE_POKEUSR:
-	/* write the word at location addr in the USER area */
-		if (addr & 3)
-			goto out_eio;
-
-		if (regno == PT_SR) {
-			data &= SR_MASK;
-			data |= get_reg(child, PT_SR) & ~SR_MASK;
-		}
-		if (regno >= 0 && regno < 19) {
-			if (put_reg(child, regno, data))
-				goto out_eio;
-		} else if (regno >= 21 && regno < 48) {
-			/* Convert long double format
-			 * into internal fpu reg representation
-			 */
-			if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) {
-				data <<= 15;
-				data = (data & 0xffff0000) |
-				       ((data & 0x0000ffff) >> 1);
-			}
-			child->thread.fp[regno - 21] = data;
-		} else
-			goto out_eio;
-		break;
-
-	case PTRACE_GETREGS:	/* Get all gp regs from the child. */
-		for (i = 0; i < 19; i++) {
-			tmp = get_reg(child, i);
-			ret = put_user(tmp, datap);
-			if (ret)
-				break;
-			datap++;
-		}
-		break;
-
-	case PTRACE_SETREGS:	/* Set all gp regs in the child. */
-		for (i = 0; i < 19; i++) {
-			ret = get_user(tmp, datap);
-			if (ret)
-				break;
-			if (i == PT_SR) {
-				tmp &= SR_MASK;
-				tmp |= get_reg(child, PT_SR) & ~SR_MASK;
-			}
-			put_reg(child, i, tmp);
-			datap++;
-		}
-		break;
-
-	case PTRACE_GETFPREGS:	/* Get the child FPU state. */
-		if (copy_to_user(datap, &child->thread.fp,
-				 sizeof(struct user_m68kfp_struct)))
-			ret = -EFAULT;
-		break;
-
-	case PTRACE_SETFPREGS:	/* Set the child FPU state. */
-		if (copy_from_user(&child->thread.fp, datap,
-				   sizeof(struct user_m68kfp_struct)))
-			ret = -EFAULT;
-		break;
-
-	case PTRACE_GET_THREAD_AREA:
-		ret = put_user(task_thread_info(child)->tp_value, datap);
-		break;
-
-	default:
-		ret = ptrace_request(child, request, addr, data);
-		break;
-	}
-
-	return ret;
-out_eio:
-	return -EIO;
-}
-
-asmlinkage void syscall_trace(void)
-{
-	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-				 ? 0x80 : 0));
-	/*
-	 * this isn't the same as continuing with a signal, but it will do
-	 * for normal use.  strace only continues with a signal if the
-	 * stopping signal is not SIGTRAP.  -brl
-	 */
-	if (current->exit_code) {
-		send_sig(current->exit_code, current, 1);
-		current->exit_code = 0;
-	}
-}
-
-#ifdef CONFIG_COLDFIRE
-asmlinkage int syscall_trace_enter(void)
-{
-	int ret = 0;
-
-	if (test_thread_flag(TIF_SYSCALL_TRACE))
-		ret = tracehook_report_syscall_entry(task_pt_regs(current));
-	return ret;
-}
-
-asmlinkage void syscall_trace_leave(void)
-{
-	if (test_thread_flag(TIF_SYSCALL_TRACE))
-		tracehook_report_syscall_exit(task_pt_regs(current), 0);
-}
-#endif /* CONFIG_COLDFIRE */
diff --git a/arch/m68k/kernel/ptrace_no.c b/arch/m68k/kernel/ptrace_no.c
deleted file mode 100644
index 6709fb7..0000000
--- a/arch/m68k/kernel/ptrace_no.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/ptrace.c
- *
- *  Copyright (C) 1994 by Hamish Macdonald
- *  Taken from linux/kernel/ptrace.c and modified for M680x0.
- *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
- *
- * 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/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-#include <linux/signal.h>
-#include <linux/tracehook.h>
-
-#include <asm/uaccess.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/processor.h>
-
-/*
- * does not yet catch signals sent when the child dies.
- * in exit.c or in signal.c.
- */
-
-/* determines which bits in the SR the user has access to. */
-/* 1 = access 0 = no access */
-#define SR_MASK 0x001f
-
-/* sets the trace bits. */
-#define TRACE_BITS 0x8000
-
-/* Find the stack offset for a register, relative to thread.esp0. */
-#define PT_REG(reg)	((long)&((struct pt_regs *)0)->reg)
-#define SW_REG(reg)	((long)&((struct switch_stack *)0)->reg \
-			 - sizeof(struct switch_stack))
-/* Mapping from PT_xxx to the stack offset at which the register is
-   saved.  Notice that usp has no stack-slot and needs to be treated
-   specially (see get_reg/put_reg below). */
-static int regoff[] = {
-	PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4),
-	PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
-	PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4),
-	SW_REG(a5), SW_REG(a6), PT_REG(d0), -1,
-	PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
-};
-
-/*
- * Get contents of register REGNO in task TASK.
- */
-static inline long get_reg(struct task_struct *task, int regno)
-{
-	unsigned long *addr;
-
-	if (regno == PT_USP)
-		addr = &task->thread.usp;
-	else if (regno < ARRAY_SIZE(regoff))
-		addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
-	else
-		return 0;
-	return *addr;
-}
-
-/*
- * Write contents of register REGNO in task TASK.
- */
-static inline int put_reg(struct task_struct *task, int regno,
-			  unsigned long data)
-{
-	unsigned long *addr;
-
-	if (regno == PT_USP)
-		addr = &task->thread.usp;
-	else if (regno < ARRAY_SIZE(regoff))
-		addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
-	else
-		return -1;
-	*addr = data;
-	return 0;
-}
-
-void user_enable_single_step(struct task_struct *task)
-{
-	unsigned long srflags;
-	srflags = get_reg(task, PT_SR) | (TRACE_BITS << 16);
-	put_reg(task, PT_SR, srflags);
-}
-
-void user_disable_single_step(struct task_struct *task)
-{
-	unsigned long srflags;
-	srflags = get_reg(task, PT_SR) & ~(TRACE_BITS << 16);
-	put_reg(task, PT_SR, srflags);
-}
-
-/*
- * Called by kernel/ptrace.c when detaching..
- *
- * Make sure the single step bit is not set.
- */
-void ptrace_disable(struct task_struct *child)
-{
-	/* make sure the single step bit is not set. */
-	user_disable_single_step(child);
-}
-
-long arch_ptrace(struct task_struct *child, long request,
-		 unsigned long addr, unsigned long data)
-{
-	int ret;
-	int regno = addr >> 2;
-	unsigned long __user *datap = (unsigned long __user *) data;
-
-	switch (request) {
-		/* read the word at location addr in the USER area. */
-		case PTRACE_PEEKUSR: {
-			unsigned long tmp;
-			
-			ret = -EIO;
-			if ((addr & 3) || addr > sizeof(struct user) - 3)
-				break;
-			
-			tmp = 0;  /* Default return condition */
-			ret = -EIO;
-			if (regno < 19) {
-				tmp = get_reg(child, regno);
-				if (regno == PT_SR)
-					tmp >>= 16;
-			} else if (regno >= 21 && regno < 49) {
-				tmp = child->thread.fp[regno - 21];
-			} else if (regno == 49) {
-				tmp = child->mm->start_code;
-			} else if (regno == 50) {
-				tmp = child->mm->start_data;
-			} else if (regno == 51) {
-				tmp = child->mm->end_code;
-			} else
-				break;
-			ret = put_user(tmp, datap);
-			break;
-		}
-
-		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-			ret = -EIO;
-			if ((addr & 3) || addr > sizeof(struct user) - 3)
-				break;
-
-			if (regno == PT_SR) {
-				data &= SR_MASK;
-				data <<= 16;
-				data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
-			}
-			if (regno < 19) {
-				if (put_reg(child, regno, data))
-					break;
-				ret = 0;
-				break;
-			}
-			if (regno >= 21 && regno < 48)
-			{
-				child->thread.fp[regno - 21] = data;
-				ret = 0;
-			}
-			break;
-
-		case PTRACE_GETREGS: { /* Get all gp regs from the child. */
-		  	int i;
-			unsigned long tmp;
-			for (i = 0; i < 19; i++) {
-			    tmp = get_reg(child, i);
-			    if (i == PT_SR)
-				tmp >>= 16;
-			    if (put_user(tmp, datap)) {
-				ret = -EFAULT;
-				break;
-			    }
-			    datap++;
-			}
-			ret = 0;
-			break;
-		}
-
-		case PTRACE_SETREGS: { /* Set all gp regs in the child. */
-			int i;
-			unsigned long tmp;
-			for (i = 0; i < 19; i++) {
-			    if (get_user(tmp, datap)) {
-				ret = -EFAULT;
-				break;
-			    }
-			    if (i == PT_SR) {
-				tmp &= SR_MASK;
-				tmp <<= 16;
-				tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
-			    }
-			    put_reg(child, i, tmp);
-			    datap++;
-			}
-			ret = 0;
-			break;
-		}
-
-#ifdef PTRACE_GETFPREGS
-		case PTRACE_GETFPREGS: { /* Get the child FPU state. */
-			ret = 0;
-			if (copy_to_user(datap, &child->thread.fp,
-					 sizeof(struct user_m68kfp_struct)))
-				ret = -EFAULT;
-			break;
-		}
-#endif
-
-#ifdef PTRACE_SETFPREGS
-		case PTRACE_SETFPREGS: { /* Set the child FPU state. */
-			ret = 0;
-			if (copy_from_user(&child->thread.fp, datap,
-					   sizeof(struct user_m68kfp_struct)))
-				ret = -EFAULT;
-			break;
-		}
-#endif
-
-	case PTRACE_GET_THREAD_AREA:
-		ret = put_user(task_thread_info(child)->tp_value, datap);
-		break;
-
-		default:
-			ret = ptrace_request(child, request, addr, data);
-			break;
-	}
-	return ret;
-}
-
-asmlinkage int syscall_trace_enter(void)
-{
-	int ret = 0;
-
-	if (test_thread_flag(TIF_SYSCALL_TRACE))
-		ret = tracehook_report_syscall_entry(task_pt_regs(current));
-	return ret;
-}
-
-asmlinkage void syscall_trace_leave(void)
-{
-	if (test_thread_flag(TIF_SYSCALL_TRACE))
-		tracehook_report_syscall_exit(task_pt_regs(current), 0);
-}
diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c
index ca3df0d..7dc186b 100644
--- a/arch/m68k/kernel/setup_no.c
+++ b/arch/m68k/kernel/setup_no.c
@@ -31,6 +31,7 @@
 #include <linux/init.h>
 #include <linux/initrd.h>
 #include <linux/root_dev.h>
+#include <linux/rtc.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
@@ -47,7 +48,9 @@
 char __initdata command_line[COMMAND_LINE_SIZE];
 
 /* machine dependent timer functions */
+void (*mach_sched_init)(irq_handler_t handler) __initdata = NULL;
 int (*mach_set_clock_mmss)(unsigned long);
+int (*mach_hwclk) (int, struct rtc_time*);
 
 /* machine dependent reboot functions */
 void (*mach_reset)(void);
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 75ab79b..d7deb7f 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -1,5 +1,111 @@
-#if defined(CONFIG_MMU) && !defined(CONFIG_COLDFIRE)
-#include "time_mm.c"
-#else
-#include "time_no.c"
-#endif
+/*
+ *  linux/arch/m68k/kernel/time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *
+ * This file contains the m68k-specific time handling details.
+ * Most of the stuff is located in the machine specific files.
+ *
+ * 1997-09-10	Updated NTP code according to technical memorandum Jan '96
+ *		"A Kernel Model for Precision Timekeeping" by Dave Mills
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/irq_regs.h>
+
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/profile.h>
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "xtime_update()" routine every clocktick
+ */
+static irqreturn_t timer_interrupt(int irq, void *dummy)
+{
+	xtime_update(1);
+	update_process_times(user_mode(get_irq_regs()));
+	profile_tick(CPU_PROFILING);
+
+#ifdef CONFIG_HEARTBEAT
+	/* use power LED as a heartbeat instead -- much more useful
+	   for debugging -- based on the version for PReP by Cort */
+	/* acts like an actual heart beat -- ie thump-thump-pause... */
+	if (mach_heartbeat) {
+	    static unsigned cnt = 0, period = 0, dist = 0;
+
+	    if (cnt == 0 || cnt == dist)
+		mach_heartbeat( 1 );
+	    else if (cnt == 7 || cnt == dist+7)
+		mach_heartbeat( 0 );
+
+	    if (++cnt > period) {
+		cnt = 0;
+		/* The hyperbolic function below modifies the heartbeat period
+		 * length in dependency of the current (5min) load. It goes
+		 * through the points f(0)=126, f(1)=86, f(5)=51,
+		 * f(inf)->30. */
+		period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+		dist = period / 4;
+	    }
+	}
+#endif /* CONFIG_HEARTBEAT */
+	return IRQ_HANDLED;
+}
+
+void read_persistent_clock(struct timespec *ts)
+{
+	struct rtc_time time;
+	ts->tv_sec = 0;
+	ts->tv_nsec = 0;
+
+	if (mach_hwclk) {
+		mach_hwclk(0, &time);
+
+		if ((time.tm_year += 1900) < 1970)
+			time.tm_year += 100;
+		ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
+				      time.tm_hour, time.tm_min, time.tm_sec);
+	}
+}
+
+void __init time_init(void)
+{
+	mach_sched_init(timer_interrupt);
+}
+
+#ifdef CONFIG_M68KCLASSIC
+
+u32 arch_gettimeoffset(void)
+{
+	return mach_gettimeoffset() * 1000;
+}
+
+static int __init rtc_init(void)
+{
+	struct platform_device *pdev;
+
+	if (!mach_hwclk)
+		return -ENODEV;
+
+	pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	return 0;
+}
+
+module_init(rtc_init);
+
+#endif /* CONFIG_M68KCLASSIC */
diff --git a/arch/m68k/kernel/time_mm.c b/arch/m68k/kernel/time_mm.c
deleted file mode 100644
index 18b34ee..0000000
--- a/arch/m68k/kernel/time_mm.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- *  linux/arch/m68k/kernel/time.c
- *
- *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *
- * This file contains the m68k-specific time handling details.
- * Most of the stuff is located in the machine specific files.
- *
- * 1997-09-10	Updated NTP code according to technical memorandum Jan '96
- *		"A Kernel Model for Precision Timekeeping" by Dave Mills
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/rtc.h>
-#include <linux/platform_device.h>
-
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/irq_regs.h>
-
-#include <linux/time.h>
-#include <linux/timex.h>
-#include <linux/profile.h>
-
-static inline int set_rtc_mmss(unsigned long nowtime)
-{
-  if (mach_set_clock_mmss)
-    return mach_set_clock_mmss (nowtime);
-  return -1;
-}
-
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "xtime_update()" routine every clocktick
- */
-static irqreturn_t timer_interrupt(int irq, void *dummy)
-{
-	xtime_update(1);
-	update_process_times(user_mode(get_irq_regs()));
-	profile_tick(CPU_PROFILING);
-
-#ifdef CONFIG_HEARTBEAT
-	/* use power LED as a heartbeat instead -- much more useful
-	   for debugging -- based on the version for PReP by Cort */
-	/* acts like an actual heart beat -- ie thump-thump-pause... */
-	if (mach_heartbeat) {
-	    static unsigned cnt = 0, period = 0, dist = 0;
-
-	    if (cnt == 0 || cnt == dist)
-		mach_heartbeat( 1 );
-	    else if (cnt == 7 || cnt == dist+7)
-		mach_heartbeat( 0 );
-
-	    if (++cnt > period) {
-		cnt = 0;
-		/* The hyperbolic function below modifies the heartbeat period
-		 * length in dependency of the current (5min) load. It goes
-		 * through the points f(0)=126, f(1)=86, f(5)=51,
-		 * f(inf)->30. */
-		period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
-		dist = period / 4;
-	    }
-	}
-#endif /* CONFIG_HEARTBEAT */
-	return IRQ_HANDLED;
-}
-
-void read_persistent_clock(struct timespec *ts)
-{
-	struct rtc_time time;
-	ts->tv_sec = 0;
-	ts->tv_nsec = 0;
-
-	if (mach_hwclk) {
-		mach_hwclk(0, &time);
-
-		if ((time.tm_year += 1900) < 1970)
-			time.tm_year += 100;
-		ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
-				      time.tm_hour, time.tm_min, time.tm_sec);
-	}
-}
-
-void __init time_init(void)
-{
-	mach_sched_init(timer_interrupt);
-}
-
-u32 arch_gettimeoffset(void)
-{
-	return mach_gettimeoffset() * 1000;
-}
-
-static int __init rtc_init(void)
-{
-	struct platform_device *pdev;
-
-	if (!mach_hwclk)
-		return -ENODEV;
-
-	pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
-
-	return 0;
-}
-
-module_init(rtc_init);
diff --git a/arch/m68k/kernel/time_no.c b/arch/m68k/kernel/time_no.c
deleted file mode 100644
index 3ef0f77..0000000
--- a/arch/m68k/kernel/time_no.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/time.c
- *
- *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *
- * This file contains the m68k-specific time handling details.
- * Most of the stuff is located in the machine specific files.
- *
- * 1997-09-10	Updated NTP code according to technical memorandum Jan '96
- *		"A Kernel Model for Precision Timekeeping" by Dave Mills
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/profile.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-
-#include <asm/machdep.h>
-#include <asm/irq_regs.h>
-
-#define	TICK_SIZE (tick_nsec / 1000)
-
-/* machine dependent timer functions */
-void (*mach_gettod)(int*, int*, int*, int*, int*, int*);
-
-static inline int set_rtc_mmss(unsigned long nowtime)
-{
-	if (mach_set_clock_mmss)
-		return mach_set_clock_mmss (nowtime);
-	return -1;
-}
-
-#ifndef CONFIG_GENERIC_CLOCKEVENTS
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "xtime_update()" routine every clocktick
- */
-irqreturn_t arch_timer_interrupt(int irq, void *dummy)
-{
-
-	if (current->pid)
-		profile_tick(CPU_PROFILING);
-
-	xtime_update(1);
-
-	update_process_times(user_mode(get_irq_regs()));
-
-	return(IRQ_HANDLED);
-}
-#endif
-
-static unsigned long read_rtc_mmss(void)
-{
-	unsigned int year, mon, day, hour, min, sec;
-
-	if (mach_gettod) {
-		mach_gettod(&year, &mon, &day, &hour, &min, &sec);
-		if ((year += 1900) < 1970)
-			year += 100;
-	} else {
-		year = 1970;
-		mon = day = 1;
-		hour = min = sec = 0;
-	}
-
-
-	return  mktime(year, mon, day, hour, min, sec);
-}
-
-void read_persistent_clock(struct timespec *ts)
-{
-	ts->tv_sec = read_rtc_mmss();
-	ts->tv_nsec = 0;
-}
-
-int update_persistent_clock(struct timespec now)
-{
-	return set_rtc_mmss(now.tv_sec);
-}
-
-void time_init(void)
-{
-	hw_timer_init();
-}
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index daaa918..388e5cc 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -32,7 +32,6 @@
 
 #include <asm/setup.h>
 #include <asm/fpu.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/traps.h>
 #include <asm/pgalloc.h>
diff --git a/arch/m68k/kernel/vectors.c b/arch/m68k/kernel/vectors.c
index 147b03f..322c977 100644
--- a/arch/m68k/kernel/vectors.c
+++ b/arch/m68k/kernel/vectors.c
@@ -25,7 +25,6 @@
 
 #include <asm/setup.h>
 #include <asm/fpu.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 
 /* assembler routines */
diff --git a/arch/m68k/kernel/vmlinux-nommu.lds b/arch/m68k/kernel/vmlinux-nommu.lds
index 8e66ccb..40e02d9 100644
--- a/arch/m68k/kernel/vmlinux-nommu.lds
+++ b/arch/m68k/kernel/vmlinux-nommu.lds
@@ -1,195 +1,93 @@
 /*
  *	vmlinux.lds.S -- master linker script for m68knommu arch
  *
- *	(C) Copyright 2002-2006, Greg Ungerer <gerg@snapgear.com>
+ *	(C) Copyright 2002-2012, Greg Ungerer <gerg@snapgear.com>
  *
  *	This linker script is equipped to build either ROM loaded or RAM
  *	run kernels.
  */
 
-#include <asm-generic/vmlinux.lds.h>
+#if defined(CONFIG_RAMKERNEL)
+#define	KTEXT_ADDR	CONFIG_KERNELBASE
+#endif
+#if defined(CONFIG_ROMKERNEL)
+#define	KTEXT_ADDR	CONFIG_ROMSTART
+#define	KDATA_ADDR	CONFIG_KERNELBASE
+#define	LOAD_OFFSET	KDATA_ADDR + (ADDR(.text) + SIZEOF(.text))
+#endif
+
 #include <asm/page.h>
 #include <asm/thread_info.h>
-
-#if defined(CONFIG_RAMKERNEL)
-#define	RAM_START	CONFIG_KERNELBASE
-#define	RAM_LENGTH	(CONFIG_RAMBASE + CONFIG_RAMSIZE - CONFIG_KERNELBASE)
-#define	TEXT		ram
-#define	DATA		ram
-#define	INIT		ram
-#define	BSSS		ram
-#endif
-#if defined(CONFIG_ROMKERNEL) || defined(CONFIG_HIMEMKERNEL)
-#define	RAM_START	CONFIG_RAMBASE
-#define	RAM_LENGTH	CONFIG_RAMSIZE
-#define	ROMVEC_START	CONFIG_ROMVEC
-#define	ROMVEC_LENGTH	CONFIG_ROMVECSIZE
-#define	ROM_START	CONFIG_ROMSTART
-#define	ROM_LENGTH	CONFIG_ROMSIZE
-#define	TEXT		rom
-#define	DATA		ram
-#define	INIT		ram
-#define	BSSS		ram
-#endif
-
-#ifndef DATA_ADDR
-#define	DATA_ADDR
-#endif
-
+#include <asm-generic/vmlinux.lds.h>
 
 OUTPUT_ARCH(m68k)
 ENTRY(_start)
 
-MEMORY {
-	ram	: ORIGIN = RAM_START, LENGTH = RAM_LENGTH
-#ifdef ROM_START
-	romvec	: ORIGIN = ROMVEC_START, LENGTH = ROMVEC_LENGTH
-	rom	: ORIGIN = ROM_START, LENGTH = ROM_LENGTH
-#endif
-}
-
 jiffies = jiffies_64 + 4;
 
 SECTIONS {
 
-#ifdef ROMVEC_START
-	. = ROMVEC_START ;
+#ifdef CONFIG_ROMVEC
+	. = CONFIG_ROMVEC;
 	.romvec : {
-		__rom_start = . ;
+		__rom_start = .;
 		_romvec = .;
+		*(.romvec)
 		*(.data..initvect)
-	} > romvec
+	}
 #endif
 
+	. = KTEXT_ADDR;
+
+	_text = .;
+	_stext = .;
 	.text : {
-		_text = .;
-		_stext = . ;
 		HEAD_TEXT
 		TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
-		*(.text..lock)
 		*(.fixup)
+		. = ALIGN(16);
+	}
+	_etext = .;
 
-		. = ALIGN(16);          /* Exception table              */
-		__start___ex_table = .;
-		*(__ex_table)
-		__stop___ex_table = .;
+#ifdef KDATA_ADDR
+	. = KDATA_ADDR;
+#endif
 
-		*(.rodata) *(.rodata.*)
-		*(__vermagic)		/* Kernel version magic */
-		*(.rodata1)
-		*(.rodata.str1.1)
+	_sdata = .;
+	RO_DATA_SECTION(PAGE_SIZE)
+	RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE)
+	_edata = .;
 
-		/* Kernel symbol table: Normal symbols */
-		. = ALIGN(4);
-		__start___ksymtab = .;
-		*(SORT(___ksymtab+*))
-		__stop___ksymtab = .;
+	EXCEPTION_TABLE(16)
+	NOTES
 
-		/* Kernel symbol table: GPL-only symbols */
-		__start___ksymtab_gpl = .;
-		*(SORT(___ksymtab_gpl+*))
-		__stop___ksymtab_gpl = .;
-
-		/* Kernel symbol table: Normal unused symbols */
-		__start___ksymtab_unused = .;
-		*(SORT(___ksymtab_unused+*))
-		__stop___ksymtab_unused = .;
-
-		/* Kernel symbol table: GPL-only unused symbols */
-		__start___ksymtab_unused_gpl = .;
-		*(SORT(___ksymtab_unused_gpl+*))
-		__stop___ksymtab_unused_gpl = .;
-
-		/* Kernel symbol table: GPL-future symbols */
-		__start___ksymtab_gpl_future = .;
-		*(SORT(___ksymtab_gpl_future+*))
-		__stop___ksymtab_gpl_future = .;
-
-		/* Kernel symbol table: Normal symbols */
-		__start___kcrctab = .;
-		*(SORT(___kcrctab+*))
-		__stop___kcrctab = .;
-
-		/* Kernel symbol table: GPL-only symbols */
-		__start___kcrctab_gpl = .;
-		*(SORT(___kcrctab_gpl+*))
-		__stop___kcrctab_gpl = .;
-
-		/* Kernel symbol table: Normal unused symbols */
-		__start___kcrctab_unused = .;
-		*(SORT(___kcrctab_unused+*))
-		__stop___kcrctab_unused = .;
-
-		/* Kernel symbol table: GPL-only unused symbols */
-		__start___kcrctab_unused_gpl = .;
-		*(SORT(___kcrctab_unused_gpl+*))
-		__stop___kcrctab_unused_gpl = .;
-
-		/* Kernel symbol table: GPL-future symbols */
-		__start___kcrctab_gpl_future = .;
-		*(SORT(___kcrctab_gpl_future+*))
-		__stop___kcrctab_gpl_future = .;
-
-		/* Kernel symbol table: strings */
-		*(__ksymtab_strings)
-
-		/* Built-in module parameters */
-		. = ALIGN(4) ;
-		__start___param = .;
-		*(__param)
-		__stop___param = .;
-
-		/* Built-in module versions */
-		. = ALIGN(4) ;
-		__start___modver = .;
-		*(__modver)
-		__stop___modver = .;
-
-		. = ALIGN(4) ;
-		_etext = . ;
-	} > TEXT
-
-	.data DATA_ADDR : {
-		. = ALIGN(4);
-		_sdata = . ;
-		DATA_DATA
-		CACHELINE_ALIGNED_DATA(32)
-		PAGE_ALIGNED_DATA(PAGE_SIZE)
-		*(.data..shared_aligned)
-		INIT_TASK_DATA(THREAD_SIZE)
-		_edata = . ;
-	} > DATA
-
+	. = ALIGN(PAGE_SIZE);
+	__init_begin = .;
+	INIT_TEXT_SECTION(PAGE_SIZE)
+	INIT_DATA_SECTION(16)
+	PERCPU_SECTION(16)
 	.m68k_fixup : {
 		__start_fixup = .;
 		*(.m68k_fixup)
 		__stop_fixup = .;
-	} > DATA
-	NOTES > DATA
-
-	.init.text : {
-		. = ALIGN(PAGE_SIZE);
-		__init_begin = .;
-	} > INIT
-	INIT_TEXT_SECTION(PAGE_SIZE) > INIT
-	INIT_DATA_SECTION(16) > INIT
+	}
 	.init.data : {
 		. = ALIGN(PAGE_SIZE);
 		__init_end = .;
-	} > INIT
+	}
 
-	.bss : {
-		. = ALIGN(4);
-		_sbss = . ;
-		*(.bss)
-		*(COMMON)
-		. = ALIGN(4) ;
-		_ebss = . ;
-	 	_end = . ;
-	} > BSSS
+	_sbss = .;
+	BSS_SECTION(0, 0, 0)
+	_ebss = .;
 
+	_end = .;
+
+	STABS_DEBUG
+	.comment 0 : { *(.comment) }
+
+	/* Sections to be discarded */
 	DISCARDS
 }
 
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index f60ff5f..d9f62e0 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -30,7 +30,6 @@
 #include <asm/setup.h>
 #include <asm/bootinfo.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
@@ -981,6 +980,9 @@
 {
 	u8 *swim_base;
 
+	if (!MACH_IS_MAC)
+		return -ENODEV;
+
 	/*
 	 * Serial devices
 	 */
diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index eb91555..5e08555 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -19,7 +19,6 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/rtc.h>
-#include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/setup.h>
 #include <asm/macintosh.h>
diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c
index 2db6099..6b020a8 100644
--- a/arch/m68k/mm/fault.c
+++ b/arch/m68k/mm/fault.c
@@ -13,7 +13,6 @@
 
 #include <asm/setup.h>
 #include <asm/traps.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 
diff --git a/arch/m68k/mm/init_mm.c b/arch/m68k/mm/init_mm.c
index 89f3b20..f77f258 100644
--- a/arch/m68k/mm/init_mm.c
+++ b/arch/m68k/mm/init_mm.c
@@ -23,7 +23,6 @@
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
diff --git a/arch/m68k/mm/init_no.c b/arch/m68k/mm/init_no.c
index 1e33d39..345ec0d 100644
--- a/arch/m68k/mm/init_no.c
+++ b/arch/m68k/mm/init_no.c
@@ -36,7 +36,6 @@
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/machdep.h>
 
 /*
diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c
index 1cc2bed..568cfad 100644
--- a/arch/m68k/mm/kmap.c
+++ b/arch/m68k/mm/kmap.c
@@ -20,7 +20,6 @@
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #undef DEBUG
 
diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c
index a5dbb74..250b8b7 100644
--- a/arch/m68k/mm/memory.c
+++ b/arch/m68k/mm/memory.c
@@ -17,7 +17,6 @@
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/machdep.h>
 
diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c
index 8b3db1c..0dafa69 100644
--- a/arch/m68k/mm/motorola.c
+++ b/arch/m68k/mm/motorola.c
@@ -24,7 +24,6 @@
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
-#include <asm/system.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/dma.h>
diff --git a/arch/m68k/mm/sun3mmu.c b/arch/m68k/mm/sun3mmu.c
index 1b902db..e080406 100644
--- a/arch/m68k/mm/sun3mmu.c
+++ b/arch/m68k/mm/sun3mmu.c
@@ -21,7 +21,6 @@
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
 
diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
index 5de924e..a41c091 100644
--- a/arch/m68k/mvme147/config.c
+++ b/arch/m68k/mvme147/config.c
@@ -26,7 +26,6 @@
 #include <linux/interrupt.h>
 
 #include <asm/bootinfo.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/setup.h>
 #include <asm/irq.h>
diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
index c3fb3bd..b6d7d8a 100644
--- a/arch/m68k/mvme16x/config.c
+++ b/arch/m68k/mvme16x/config.c
@@ -29,7 +29,6 @@
 #include <linux/module.h>
 
 #include <asm/bootinfo.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/setup.h>
 #include <asm/irq.h>
diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c
index 39c79eb..6ef7a81 100644
--- a/arch/m68k/mvme16x/rtc.c
+++ b/arch/m68k/mvme16x/rtc.c
@@ -20,7 +20,6 @@
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/setup.h>
 
 /*
diff --git a/arch/m68k/platform/5206/config.c b/arch/m68k/platform/5206/config.c
index 6fa3f80..6bfbeeb 100644
--- a/arch/m68k/platform/5206/config.c
+++ b/arch/m68k/platform/5206/config.c
@@ -16,83 +16,6 @@
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m5206_uart_platform[] = {
-	{
-		.mapbase	= MCF_MBAR + MCFUART_BASE1,
-		.irq		= 73,
-	},
-	{
-		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
-		.irq		= 74,
-	},
-	{ },
-};
-
-static struct platform_device m5206_uart = {
-	.name			= "mcfuart",
-	.id			= 0,
-	.dev.platform_data	= m5206_uart_platform,
-};
-
-static struct platform_device *m5206_devices[] __initdata = {
-	&m5206_uart,
-};
-
-/***************************************************************************/
-
-static void __init m5206_uart_init_line(int line, int irq)
-{
-	if (line == 0) {
-		writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-		writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
-		mcf_mapirq2imr(irq, MCFINTC_UART0);
-	} else if (line == 1) {
-		writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-		writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
-		mcf_mapirq2imr(irq, MCFINTC_UART1);
-	}
-}
-
-static void __init m5206_uarts_init(void)
-{
-	const int nrlines = ARRAY_SIZE(m5206_uart_platform);
-	int line;
-
-	for (line = 0; (line < nrlines); line++)
-		m5206_uart_init_line(line, m5206_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void __init m5206_timers_init(void)
-{
-	/* Timer1 is always used as system timer */
-	writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
-		MCF_MBAR + MCFSIM_TIMER1ICR);
-	mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
-
-#ifdef CONFIG_HIGHPROFILE
-	/* Timer2 is to be used as a high speed profile timer  */
-	writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
-		MCF_MBAR + MCFSIM_TIMER2ICR);
-	mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
-#endif
-}
-
-/***************************************************************************/
-
-void m5206_cpu_reset(void)
-{
-	local_irq_disable();
-	/* Set watchdog to soft reset, and enabled */
-	__raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
-	for (;;)
-		/* wait for watchdog to timeout */;
-}
 
 /***************************************************************************/
 
@@ -104,9 +27,7 @@
 	commandp[size-1] = 0;
 #endif /* CONFIG_NETtel */
 
-	mach_reset = m5206_cpu_reset;
-	m5206_timers_init();
-	m5206_uarts_init();
+	mach_sched_init = hw_timer_init;
 
 	/* Only support the external interrupts on their primary level */
 	mcf_mapirq2imr(25, MCFINTC_EINT1);
@@ -115,13 +36,3 @@
 }
 
 /***************************************************************************/
-
-static int __init init_BSP(void)
-{
-	platform_add_devices(m5206_devices, ARRAY_SIZE(m5206_devices));
-	return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/520x/config.c b/arch/m68k/platform/520x/config.c
index 8a98683..23594784 100644
--- a/arch/m68k/platform/520x/config.c
+++ b/arch/m68k/platform/520x/config.c
@@ -15,194 +15,14 @@
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m520x_uart_platform[] = {
-	{
-		.mapbase	= MCFUART_BASE1,
-		.irq		= MCFINT_VECBASE + MCFINT_UART0,
-	},
-	{
-		.mapbase 	= MCFUART_BASE2,
-		.irq		= MCFINT_VECBASE + MCFINT_UART1,
-	},
-	{
-		.mapbase 	= MCFUART_BASE3,
-		.irq		= MCFINT_VECBASE + MCFINT_UART2,
-	},
-	{ },
-};
-
-static struct platform_device m520x_uart = {
-	.name			= "mcfuart",
-	.id			= 0,
-	.dev.platform_data	= m520x_uart_platform,
-};
-
-static struct resource m520x_fec_resources[] = {
-	{
-		.start		= MCFFEC_BASE,
-		.end		= MCFFEC_BASE + MCFFEC_SIZE - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= 64 + 36,
-		.end		= 64 + 36,
-		.flags		= IORESOURCE_IRQ,
-	},
-	{
-		.start		= 64 + 40,
-		.end		= 64 + 40,
-		.flags		= IORESOURCE_IRQ,
-	},
-	{
-		.start		= 64 + 42,
-		.end		= 64 + 42,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device m520x_fec = {
-	.name			= "fec",
-	.id			= 0,
-	.num_resources		= ARRAY_SIZE(m520x_fec_resources),
-	.resource		= m520x_fec_resources,
-};
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m520x_qspi_resources[] = {
-	{
-		.start		= MCFQSPI_IOBASE,
-		.end		= MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= MCFINT_VECBASE + MCFINT_QSPI,
-		.end		= MCFINT_VECBASE + MCFINT_QSPI,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-#define MCFQSPI_CS0    46
-#define MCFQSPI_CS1    47
-#define MCFQSPI_CS2    27
-
-static int m520x_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-	int status;
-
-	status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-		goto fail0;
-	}
-	status = gpio_direction_output(MCFQSPI_CS0, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-		goto fail1;
-	}
-
-	status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-		goto fail1;
-	}
-	status = gpio_direction_output(MCFQSPI_CS1, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-		goto fail2;
-	}
-
-	status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-		goto fail2;
-	}
-	status = gpio_direction_output(MCFQSPI_CS2, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-		goto fail3;
-	}
-
-	return 0;
-
-fail3:
-	gpio_free(MCFQSPI_CS2);
-fail2:
-	gpio_free(MCFQSPI_CS1);
-fail1:
-	gpio_free(MCFQSPI_CS0);
-fail0:
-	return status;
-}
-
-static void m520x_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-	gpio_free(MCFQSPI_CS2);
-	gpio_free(MCFQSPI_CS1);
-	gpio_free(MCFQSPI_CS0);
-}
-
-static void m520x_cs_select(struct mcfqspi_cs_control *cs_control,
-			    u8 chip_select, bool cs_high)
-{
-	switch (chip_select) {
-	case 0:
-		gpio_set_value(MCFQSPI_CS0, cs_high);
-		break;
-	case 1:
-		gpio_set_value(MCFQSPI_CS1, cs_high);
-		break;
-	case 2:
-		gpio_set_value(MCFQSPI_CS2, cs_high);
-		break;
-	}
-}
-
-static void m520x_cs_deselect(struct mcfqspi_cs_control *cs_control,
-			      u8 chip_select, bool cs_high)
-{
-	switch (chip_select) {
-	case 0:
-		gpio_set_value(MCFQSPI_CS0, !cs_high);
-		break;
-	case 1:
-		gpio_set_value(MCFQSPI_CS1, !cs_high);
-		break;
-	case 2:
-		gpio_set_value(MCFQSPI_CS2, !cs_high);
-		break;
-	}
-}
-
-static struct mcfqspi_cs_control m520x_cs_control = {
-	.setup                  = m520x_cs_setup,
-	.teardown               = m520x_cs_teardown,
-	.select                 = m520x_cs_select,
-	.deselect               = m520x_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m520x_qspi_data = {
-	.bus_num		= 0,
-	.num_chipselect		= 3,
-	.cs_control		= &m520x_cs_control,
-};
-
-static struct platform_device m520x_qspi = {
-	.name			= "mcfqspi",
-	.id			= 0,
-	.num_resources		= ARRAY_SIZE(m520x_qspi_resources),
-	.resource		= m520x_qspi_resources,
-	.dev.platform_data	= &m520x_qspi_data,
-};
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 
 static void __init m520x_qspi_init(void)
 {
@@ -214,54 +34,28 @@
 	par &= 0x00ff;
 	writew(par, MCF_GPIO_PAR_UART);
 }
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
 
-
-static struct platform_device *m520x_devices[] __initdata = {
-	&m520x_uart,
-	&m520x_fec,
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-	&m520x_qspi,
-#endif
-};
+#endif /* CONFIG_SPI_COLDFIRE_QSPI */
 
 /***************************************************************************/
 
-static void __init m520x_uart_init_line(int line, int irq)
+static void __init m520x_uarts_init(void)
 {
 	u16 par;
 	u8 par2;
 
-	switch (line) {
-	case 0:
-		par = readw(MCF_GPIO_PAR_UART);
-		par |= MCF_GPIO_PAR_UART_PAR_UTXD0 |
-		       MCF_GPIO_PAR_UART_PAR_URXD0;
-		writew(par, MCF_GPIO_PAR_UART);
-		break;
-	case 1:
-		par = readw(MCF_GPIO_PAR_UART);
-		par |= MCF_GPIO_PAR_UART_PAR_UTXD1 |
-		       MCF_GPIO_PAR_UART_PAR_URXD1;
-		writew(par, MCF_GPIO_PAR_UART);
-		break;
-	case 2:
-		par2 = readb(MCF_GPIO_PAR_FECI2C);
-		par2 &= ~0x0F;
-		par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 |
-			MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
-		writeb(par2, MCF_GPIO_PAR_FECI2C);
-		break;
-	}
-}
+	/* UART0 and UART1 GPIO pin setup */
+	par = readw(MCF_GPIO_PAR_UART);
+	par |= MCF_GPIO_PAR_UART_PAR_UTXD0 | MCF_GPIO_PAR_UART_PAR_URXD0;
+	par |= MCF_GPIO_PAR_UART_PAR_UTXD1 | MCF_GPIO_PAR_UART_PAR_URXD1;
+	writew(par, MCF_GPIO_PAR_UART);
 
-static void __init m520x_uarts_init(void)
-{
-	const int nrlines = ARRAY_SIZE(m520x_uart_platform);
-	int line;
-
-	for (line = 0; (line < nrlines); line++)
-		m520x_uart_init_line(line, m520x_uart_platform[line].irq);
+	/* UART1 GPIO pin setup */
+	par2 = readb(MCF_GPIO_PAR_FECI2C);
+	par2 &= ~0x0F;
+	par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 |
+		MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
+	writeb(par2, MCF_GPIO_PAR_FECI2C);
 }
 
 /***************************************************************************/
@@ -280,32 +74,14 @@
 
 /***************************************************************************/
 
-static void m520x_cpu_reset(void)
-{
-	local_irq_disable();
-	__raw_writeb(MCF_RCR_SWRESET, MCF_RCR);
-}
-
-/***************************************************************************/
-
 void __init config_BSP(char *commandp, int size)
 {
-	mach_reset = m520x_cpu_reset;
+	mach_sched_init = hw_timer_init;
 	m520x_uarts_init();
 	m520x_fec_init();
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 	m520x_qspi_init();
 #endif
 }
 
 /***************************************************************************/
-
-static int __init init_BSP(void)
-{
-	platform_add_devices(m520x_devices, ARRAY_SIZE(m520x_devices));
-	return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/523x/config.c b/arch/m68k/platform/523x/config.c
index 71f4436..c8b405d 100644
--- a/arch/m68k/platform/523x/config.c
+++ b/arch/m68k/platform/523x/config.c
@@ -16,215 +16,13 @@
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m523x_uart_platform[] = {
-	{
-		.mapbase	= MCFUART_BASE1,
-		.irq		= MCFINT_VECBASE + MCFINT_UART0,
-	},
-	{
-		.mapbase 	= MCFUART_BASE2,
-		.irq		= MCFINT_VECBASE + MCFINT_UART0 + 1,
-	},
-	{
-		.mapbase 	= MCFUART_BASE3,
-		.irq		= MCFINT_VECBASE + MCFINT_UART0 + 2,
-	},
-	{ },
-};
-
-static struct platform_device m523x_uart = {
-	.name			= "mcfuart",
-	.id			= 0,
-	.dev.platform_data	= m523x_uart_platform,
-};
-
-static struct resource m523x_fec_resources[] = {
-	{
-		.start		= MCFFEC_BASE,
-		.end		= MCFFEC_BASE + MCFFEC_SIZE - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= 64 + 23,
-		.end		= 64 + 23,
-		.flags		= IORESOURCE_IRQ,
-	},
-	{
-		.start		= 64 + 27,
-		.end		= 64 + 27,
-		.flags		= IORESOURCE_IRQ,
-	},
-	{
-		.start		= 64 + 29,
-		.end		= 64 + 29,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device m523x_fec = {
-	.name			= "fec",
-	.id			= 0,
-	.num_resources		= ARRAY_SIZE(m523x_fec_resources),
-	.resource		= m523x_fec_resources,
-};
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m523x_qspi_resources[] = {
-	{
-		.start		= MCFQSPI_IOBASE,
-		.end		= MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= MCFINT_VECBASE + MCFINT_QSPI,
-		.end		= MCFINT_VECBASE + MCFINT_QSPI,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-#define MCFQSPI_CS0    91
-#define MCFQSPI_CS1    92
-#define MCFQSPI_CS2    103
-#define MCFQSPI_CS3    99
-
-static int m523x_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-	int status;
-
-	status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-		goto fail0;
-	}
-	status = gpio_direction_output(MCFQSPI_CS0, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-		goto fail1;
-	}
-
-	status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-		goto fail1;
-	}
-	status = gpio_direction_output(MCFQSPI_CS1, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-		goto fail2;
-	}
-
-	status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-		goto fail2;
-	}
-	status = gpio_direction_output(MCFQSPI_CS2, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-		goto fail3;
-	}
-
-	status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
-		goto fail3;
-	}
-	status = gpio_direction_output(MCFQSPI_CS3, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
-		goto fail4;
-	}
-
-	return 0;
-
-fail4:
-	gpio_free(MCFQSPI_CS3);
-fail3:
-	gpio_free(MCFQSPI_CS2);
-fail2:
-	gpio_free(MCFQSPI_CS1);
-fail1:
-	gpio_free(MCFQSPI_CS0);
-fail0:
-	return status;
-}
-
-static void m523x_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-	gpio_free(MCFQSPI_CS3);
-	gpio_free(MCFQSPI_CS2);
-	gpio_free(MCFQSPI_CS1);
-	gpio_free(MCFQSPI_CS0);
-}
-
-static void m523x_cs_select(struct mcfqspi_cs_control *cs_control,
-			    u8 chip_select, bool cs_high)
-{
-	switch (chip_select) {
-	case 0:
-		gpio_set_value(MCFQSPI_CS0, cs_high);
-		break;
-	case 1:
-		gpio_set_value(MCFQSPI_CS1, cs_high);
-		break;
-	case 2:
-		gpio_set_value(MCFQSPI_CS2, cs_high);
-		break;
-	case 3:
-		gpio_set_value(MCFQSPI_CS3, cs_high);
-		break;
-	}
-}
-
-static void m523x_cs_deselect(struct mcfqspi_cs_control *cs_control,
-			      u8 chip_select, bool cs_high)
-{
-	switch (chip_select) {
-	case 0:
-		gpio_set_value(MCFQSPI_CS0, !cs_high);
-		break;
-	case 1:
-		gpio_set_value(MCFQSPI_CS1, !cs_high);
-		break;
-	case 2:
-		gpio_set_value(MCFQSPI_CS2, !cs_high);
-		break;
-	case 3:
-		gpio_set_value(MCFQSPI_CS3, !cs_high);
-		break;
-	}
-}
-
-static struct mcfqspi_cs_control m523x_cs_control = {
-	.setup                  = m523x_cs_setup,
-	.teardown               = m523x_cs_teardown,
-	.select                 = m523x_cs_select,
-	.deselect               = m523x_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m523x_qspi_data = {
-	.bus_num		= 0,
-	.num_chipselect		= 4,
-	.cs_control		= &m523x_cs_control,
-};
-
-static struct platform_device m523x_qspi = {
-	.name			= "mcfqspi",
-	.id			= 0,
-	.num_resources		= ARRAY_SIZE(m523x_qspi_resources),
-	.resource		= m523x_qspi_resources,
-	.dev.platform_data	= &m523x_qspi_data,
-};
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 
 static void __init m523x_qspi_init(void)
 {
@@ -237,15 +35,8 @@
 	par &= 0x3f3f;
 	writew(par, MCFGPIO_PAR_TIMER);
 }
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
 
-static struct platform_device *m523x_devices[] __initdata = {
-	&m523x_uart,
-	&m523x_fec,
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-	&m523x_qspi,
-#endif
-};
+#endif /* CONFIG_SPI_COLDFIRE_QSPI */
 
 /***************************************************************************/
 
@@ -263,31 +54,13 @@
 
 /***************************************************************************/
 
-static void m523x_cpu_reset(void)
-{
-	local_irq_disable();
-	__raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR);
-}
-
-/***************************************************************************/
-
 void __init config_BSP(char *commandp, int size)
 {
-	mach_reset = m523x_cpu_reset;
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
+	mach_sched_init = hw_timer_init;
 	m523x_fec_init();
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 	m523x_qspi_init();
 #endif
-	platform_add_devices(m523x_devices, ARRAY_SIZE(m523x_devices));
-	return 0;
 }
 
-arch_initcall(init_BSP);
-
 /***************************************************************************/
diff --git a/arch/m68k/platform/5249/config.c b/arch/m68k/platform/5249/config.c
index ceb31e5..bbf0513 100644
--- a/arch/m68k/platform/5249/config.c
+++ b/arch/m68k/platform/5249/config.c
@@ -12,34 +12,13 @@
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
+#include <linux/platform_device.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m5249_uart_platform[] = {
-	{
-		.mapbase	= MCF_MBAR + MCFUART_BASE1,
-		.irq		= 73,
-	},
-	{
-		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
-		.irq		= 74,
-	},
-	{ },
-};
-
-static struct platform_device m5249_uart = {
-	.name			= "mcfuart",
-	.id			= 0,
-	.dev.platform_data	= m5249_uart_platform,
-};
-
 #ifdef CONFIG_M5249C3
 
 static struct resource m5249_smc91x_resources[] = {
@@ -64,153 +43,15 @@
 
 #endif /* CONFIG_M5249C3 */
 
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m5249_qspi_resources[] = {
-	{
-		.start		= MCFQSPI_IOBASE,
-		.end		= MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= MCF_IRQ_QSPI,
-		.end		= MCF_IRQ_QSPI,
-		.flags		= IORESOURCE_IRQ,
-	},
+static struct platform_device *m5249_devices[] __initdata = {
+#ifdef CONFIG_M5249C3
+	&m5249_smc91x,
+#endif
 };
 
-#define MCFQSPI_CS0    29
-#define MCFQSPI_CS1    24
-#define MCFQSPI_CS2    21
-#define MCFQSPI_CS3    22
+/***************************************************************************/
 
-static int m5249_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-	int status;
-
-	status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-		goto fail0;
-	}
-	status = gpio_direction_output(MCFQSPI_CS0, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-		goto fail1;
-	}
-
-	status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-		goto fail1;
-	}
-	status = gpio_direction_output(MCFQSPI_CS1, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-		goto fail2;
-	}
-
-	status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-		goto fail2;
-	}
-	status = gpio_direction_output(MCFQSPI_CS2, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-		goto fail3;
-	}
-
-	status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
-		goto fail3;
-	}
-	status = gpio_direction_output(MCFQSPI_CS3, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
-		goto fail4;
-	}
-
-	return 0;
-
-fail4:
-	gpio_free(MCFQSPI_CS3);
-fail3:
-	gpio_free(MCFQSPI_CS2);
-fail2:
-	gpio_free(MCFQSPI_CS1);
-fail1:
-	gpio_free(MCFQSPI_CS0);
-fail0:
-	return status;
-}
-
-static void m5249_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-	gpio_free(MCFQSPI_CS3);
-	gpio_free(MCFQSPI_CS2);
-	gpio_free(MCFQSPI_CS1);
-	gpio_free(MCFQSPI_CS0);
-}
-
-static void m5249_cs_select(struct mcfqspi_cs_control *cs_control,
-			    u8 chip_select, bool cs_high)
-{
-	switch (chip_select) {
-	case 0:
-		gpio_set_value(MCFQSPI_CS0, cs_high);
-		break;
-	case 1:
-		gpio_set_value(MCFQSPI_CS1, cs_high);
-		break;
-	case 2:
-		gpio_set_value(MCFQSPI_CS2, cs_high);
-		break;
-	case 3:
-		gpio_set_value(MCFQSPI_CS3, cs_high);
-		break;
-	}
-}
-
-static void m5249_cs_deselect(struct mcfqspi_cs_control *cs_control,
-			      u8 chip_select, bool cs_high)
-{
-	switch (chip_select) {
-	case 0:
-		gpio_set_value(MCFQSPI_CS0, !cs_high);
-		break;
-	case 1:
-		gpio_set_value(MCFQSPI_CS1, !cs_high);
-		break;
-	case 2:
-		gpio_set_value(MCFQSPI_CS2, !cs_high);
-		break;
-	case 3:
-		gpio_set_value(MCFQSPI_CS3, !cs_high);
-		break;
-	}
-}
-
-static struct mcfqspi_cs_control m5249_cs_control = {
-	.setup                  = m5249_cs_setup,
-	.teardown               = m5249_cs_teardown,
-	.select                 = m5249_cs_select,
-	.deselect               = m5249_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m5249_qspi_data = {
-	.bus_num		= 0,
-	.num_chipselect		= 4,
-	.cs_control		= &m5249_cs_control,
-};
-
-static struct platform_device m5249_qspi = {
-	.name			= "mcfqspi",
-	.id			= 0,
-	.num_resources		= ARRAY_SIZE(m5249_qspi_resources),
-	.resource		= m5249_qspi_resources,
-	.dev.platform_data	= &m5249_qspi_data,
-};
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 
 static void __init m5249_qspi_init(void)
 {
@@ -219,42 +60,8 @@
 	       MCF_MBAR + MCFSIM_QSPIICR);
 	mcf_mapirq2imr(MCF_IRQ_QSPI, MCFINTC_QSPI);
 }
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
 
-
-static struct platform_device *m5249_devices[] __initdata = {
-	&m5249_uart,
-#ifdef CONFIG_M5249C3
-	&m5249_smc91x,
-#endif
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-	&m5249_qspi,
-#endif
-};
-
-/***************************************************************************/
-
-static void __init m5249_uart_init_line(int line, int irq)
-{
-	if (line == 0) {
-		writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-		writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
-		mcf_mapirq2imr(irq, MCFINTC_UART0);
-	} else if (line == 1) {
-		writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-		writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
-		mcf_mapirq2imr(irq, MCFINTC_UART1);
-	}
-}
-
-static void __init m5249_uarts_init(void)
-{
-	const int nrlines = ARRAY_SIZE(m5249_uart_platform);
-	int line;
-
-	for (line = 0; (line < nrlines); line++)
-		m5249_uart_init_line(line, m5249_uart_platform[line].irq);
-}
+#endif /* CONFIG_SPI_COLDFIRE_QSPI */
 
 /***************************************************************************/
 
@@ -276,43 +83,14 @@
 
 /***************************************************************************/
 
-static void __init m5249_timers_init(void)
-{
-	/* Timer1 is always used as system timer */
-	writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
-		MCF_MBAR + MCFSIM_TIMER1ICR);
-	mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
-
-#ifdef CONFIG_HIGHPROFILE
-	/* Timer2 is to be used as a high speed profile timer  */
-	writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
-		MCF_MBAR + MCFSIM_TIMER2ICR);
-	mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
-#endif
-}
-
-/***************************************************************************/
-
-void m5249_cpu_reset(void)
-{
-	local_irq_disable();
-	/* Set watchdog to soft reset, and enabled */
-	__raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
-	for (;;)
-		/* wait for watchdog to timeout */;
-}
-
-/***************************************************************************/
-
 void __init config_BSP(char *commandp, int size)
 {
-	mach_reset = m5249_cpu_reset;
-	m5249_timers_init();
-	m5249_uarts_init();
+	mach_sched_init = hw_timer_init;
+
 #ifdef CONFIG_M5249C3
 	m5249_smc91x_init();
 #endif
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 	m5249_qspi_init();
 #endif
 }
diff --git a/arch/m68k/platform/5272/config.c b/arch/m68k/platform/5272/config.c
index 65bb582..e68bc7a 100644
--- a/arch/m68k/platform/5272/config.c
+++ b/arch/m68k/platform/5272/config.c
@@ -30,84 +30,18 @@
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m5272_uart_platform[] = {
-	{
-		.mapbase	= MCF_MBAR + MCFUART_BASE1,
-		.irq		= MCF_IRQ_UART1,
-	},
-	{
-		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
-		.irq		= MCF_IRQ_UART2,
-	},
-	{ },
-};
-
-static struct platform_device m5272_uart = {
-	.name			= "mcfuart",
-	.id			= 0,
-	.dev.platform_data	= m5272_uart_platform,
-};
-
-static struct resource m5272_fec_resources[] = {
-	{
-		.start		= MCF_MBAR + 0x840,
-		.end		= MCF_MBAR + 0x840 + 0x1cf,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= MCF_IRQ_ERX,
-		.end		= MCF_IRQ_ERX,
-		.flags		= IORESOURCE_IRQ,
-	},
-	{
-		.start		= MCF_IRQ_ETX,
-		.end		= MCF_IRQ_ETX,
-		.flags		= IORESOURCE_IRQ,
-	},
-	{
-		.start		= MCF_IRQ_ENTC,
-		.end		= MCF_IRQ_ENTC,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device m5272_fec = {
-	.name			= "fec",
-	.id			= 0,
-	.num_resources		= ARRAY_SIZE(m5272_fec_resources),
-	.resource		= m5272_fec_resources,
-};
-
-static struct platform_device *m5272_devices[] __initdata = {
-	&m5272_uart,
-	&m5272_fec,
-};
-
-/***************************************************************************/
-
-static void __init m5272_uart_init_line(int line, int irq)
+static void __init m5272_uarts_init(void)
 {
 	u32 v;
 
-	if ((line >= 0) && (line < 2)) {
-		/* Enable the output lines for the serial ports */
-		v = readl(MCF_MBAR + MCFSIM_PBCNT);
-		v = (v & ~0x000000ff) | 0x00000055;
-		writel(v, MCF_MBAR + MCFSIM_PBCNT);
+	/* Enable the output lines for the serial ports */
+	v = readl(MCF_MBAR + MCFSIM_PBCNT);
+	v = (v & ~0x000000ff) | 0x00000055;
+	writel(v, MCF_MBAR + MCFSIM_PBCNT);
 
-		v = readl(MCF_MBAR + MCFSIM_PDCNT);
-		v = (v & ~0x000003fc) | 0x000002a8;
-		writel(v, MCF_MBAR + MCFSIM_PDCNT);
-	}
-}
-
-static void __init m5272_uarts_init(void)
-{
-	const int nrlines = ARRAY_SIZE(m5272_uart_platform);
-	int line;
-
-	for (line = 0; (line < nrlines); line++)
-		m5272_uart_init_line(line, m5272_uart_platform[line].irq);
+	v = readl(MCF_MBAR + MCFSIM_PDCNT);
+	v = (v & ~0x000003fc) | 0x000002a8;
+	writel(v, MCF_MBAR + MCFSIM_PDCNT);
 }
 
 /***************************************************************************/
@@ -146,6 +80,7 @@
 #endif
 
 	mach_reset = m5272_cpu_reset;
+	mach_sched_init = hw_timer_init;
 }
 
 /***************************************************************************/
@@ -167,7 +102,6 @@
 {
 	m5272_uarts_init();
 	fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status);
-	platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices));
 	return 0;
 }
 
diff --git a/arch/m68k/platform/527x/config.c b/arch/m68k/platform/527x/config.c
index 3ebc769..7ed848c 100644
--- a/arch/m68k/platform/527x/config.c
+++ b/arch/m68k/platform/527x/config.c
@@ -16,253 +16,14 @@
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m527x_uart_platform[] = {
-	{
-		.mapbase	= MCFUART_BASE1,
-		.irq		= MCFINT_VECBASE + MCFINT_UART0,
-	},
-	{
-		.mapbase 	= MCFUART_BASE2,
-		.irq		= MCFINT_VECBASE + MCFINT_UART1,
-	},
-	{
-		.mapbase 	= MCFUART_BASE3,
-		.irq		= MCFINT_VECBASE + MCFINT_UART2,
-	},
-	{ },
-};
-
-static struct platform_device m527x_uart = {
-	.name			= "mcfuart",
-	.id			= 0,
-	.dev.platform_data	= m527x_uart_platform,
-};
-
-static struct resource m527x_fec0_resources[] = {
-	{
-		.start		= MCFFEC_BASE0,
-		.end		= MCFFEC_BASE0 + MCFFEC_SIZE0 - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= 64 + 23,
-		.end		= 64 + 23,
-		.flags		= IORESOURCE_IRQ,
-	},
-	{
-		.start		= 64 + 27,
-		.end		= 64 + 27,
-		.flags		= IORESOURCE_IRQ,
-	},
-	{
-		.start		= 64 + 29,
-		.end		= 64 + 29,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-static struct resource m527x_fec1_resources[] = {
-	{
-		.start		= MCFFEC_BASE1,
-		.end		= MCFFEC_BASE1 + MCFFEC_SIZE1 - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= 128 + 23,
-		.end		= 128 + 23,
-		.flags		= IORESOURCE_IRQ,
-	},
-	{
-		.start		= 128 + 27,
-		.end		= 128 + 27,
-		.flags		= IORESOURCE_IRQ,
-	},
-	{
-		.start		= 128 + 29,
-		.end		= 128 + 29,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device m527x_fec[] = {
-	{
-		.name		= "fec",
-		.id		= 0,
-		.num_resources	= ARRAY_SIZE(m527x_fec0_resources),
-		.resource	= m527x_fec0_resources,
-	},
-	{
-		.name		= "fec",
-		.id		= 1,
-		.num_resources	= ARRAY_SIZE(m527x_fec1_resources),
-		.resource	= m527x_fec1_resources,
-	},
-};
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m527x_qspi_resources[] = {
-	{
-		.start		= MCFQSPI_IOBASE,
-		.end		= MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= MCFINT_VECBASE + MCFINT_QSPI,
-		.end		= MCFINT_VECBASE + MCFINT_QSPI,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-#if defined(CONFIG_M5271)
-#define MCFQSPI_CS0    91
-#define MCFQSPI_CS1    92
-#define MCFQSPI_CS2    99
-#define MCFQSPI_CS3    103
-#elif defined(CONFIG_M5275)
-#define MCFQSPI_CS0    59
-#define MCFQSPI_CS1    60
-#define MCFQSPI_CS2    61
-#define MCFQSPI_CS3    62
-#endif
-
-static int m527x_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-	int status;
-
-	status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-		goto fail0;
-	}
-	status = gpio_direction_output(MCFQSPI_CS0, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-		goto fail1;
-	}
-
-	status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-		goto fail1;
-	}
-	status = gpio_direction_output(MCFQSPI_CS1, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-		goto fail2;
-	}
-
-	status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-		goto fail2;
-	}
-	status = gpio_direction_output(MCFQSPI_CS2, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-		goto fail3;
-	}
-
-	status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
-		goto fail3;
-	}
-	status = gpio_direction_output(MCFQSPI_CS3, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
-		goto fail4;
-	}
-
-	return 0;
-
-fail4:
-	gpio_free(MCFQSPI_CS3);
-fail3:
-	gpio_free(MCFQSPI_CS2);
-fail2:
-	gpio_free(MCFQSPI_CS1);
-fail1:
-	gpio_free(MCFQSPI_CS0);
-fail0:
-	return status;
-}
-
-static void m527x_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-	gpio_free(MCFQSPI_CS3);
-	gpio_free(MCFQSPI_CS2);
-	gpio_free(MCFQSPI_CS1);
-	gpio_free(MCFQSPI_CS0);
-}
-
-static void m527x_cs_select(struct mcfqspi_cs_control *cs_control,
-			    u8 chip_select, bool cs_high)
-{
-	switch (chip_select) {
-	case 0:
-		gpio_set_value(MCFQSPI_CS0, cs_high);
-		break;
-	case 1:
-		gpio_set_value(MCFQSPI_CS1, cs_high);
-		break;
-	case 2:
-		gpio_set_value(MCFQSPI_CS2, cs_high);
-		break;
-	case 3:
-		gpio_set_value(MCFQSPI_CS3, cs_high);
-		break;
-	}
-}
-
-static void m527x_cs_deselect(struct mcfqspi_cs_control *cs_control,
-			      u8 chip_select, bool cs_high)
-{
-	switch (chip_select) {
-	case 0:
-		gpio_set_value(MCFQSPI_CS0, !cs_high);
-		break;
-	case 1:
-		gpio_set_value(MCFQSPI_CS1, !cs_high);
-		break;
-	case 2:
-		gpio_set_value(MCFQSPI_CS2, !cs_high);
-		break;
-	case 3:
-		gpio_set_value(MCFQSPI_CS3, !cs_high);
-		break;
-	}
-}
-
-static struct mcfqspi_cs_control m527x_cs_control = {
-	.setup                  = m527x_cs_setup,
-	.teardown               = m527x_cs_teardown,
-	.select                 = m527x_cs_select,
-	.deselect               = m527x_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m527x_qspi_data = {
-	.bus_num		= 0,
-	.num_chipselect		= 4,
-	.cs_control		= &m527x_cs_control,
-};
-
-static struct platform_device m527x_qspi = {
-	.name			= "mcfqspi",
-	.id			= 0,
-	.num_resources		= ARRAY_SIZE(m527x_qspi_resources),
-	.resource		= m527x_qspi_resources,
-	.dev.platform_data	= &m527x_qspi_data,
-};
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 
 static void __init m527x_qspi_init(void)
 {
@@ -280,50 +41,23 @@
 	writew(0x003e, MCFGPIO_PAR_QSPI);
 #endif
 }
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
 
-static struct platform_device *m527x_devices[] __initdata = {
-	&m527x_uart,
-	&m527x_fec[0],
-#ifdef CONFIG_FEC2
-	&m527x_fec[1],
-#endif
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-	&m527x_qspi,
-#endif
-};
+#endif /* CONFIG_SPI_COLDFIRE_QSPI */
 
 /***************************************************************************/
 
-static void __init m527x_uart_init_line(int line, int irq)
+static void __init m527x_uarts_init(void)
 {
 	u16 sepmask;
 
-	if ((line < 0) || (line > 2))
-		return;
-
 	/*
 	 * External Pin Mask Setting & Enable External Pin for Interface
 	 */
 	sepmask = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART);
-	if (line == 0)
-		sepmask |= UART0_ENABLE_MASK;
-	else if (line == 1)
-		sepmask |= UART1_ENABLE_MASK;
-	else if (line == 2)
-		sepmask |= UART2_ENABLE_MASK;
+	sepmask |= UART0_ENABLE_MASK | UART1_ENABLE_MASK | UART2_ENABLE_MASK;
 	writew(sepmask, MCF_IPSBAR + MCF_GPIO_PAR_UART);
 }
 
-static void __init m527x_uarts_init(void)
-{
-	const int nrlines = ARRAY_SIZE(m527x_uart_platform);
-	int line;
-
-	for (line = 0; (line < nrlines); line++)
-		m527x_uart_init_line(line, m527x_uart_platform[line].irq);
-}
-
 /***************************************************************************/
 
 static void __init m527x_fec_init(void)
@@ -353,32 +87,14 @@
 
 /***************************************************************************/
 
-static void m527x_cpu_reset(void)
-{
-	local_irq_disable();
-	__raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR);
-}
-
-/***************************************************************************/
-
 void __init config_BSP(char *commandp, int size)
 {
-	mach_reset = m527x_cpu_reset;
+	mach_sched_init = hw_timer_init;
 	m527x_uarts_init();
 	m527x_fec_init();
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 	m527x_qspi_init();
 #endif
 }
 
 /***************************************************************************/
-
-static int __init init_BSP(void)
-{
-	platform_add_devices(m527x_devices, ARRAY_SIZE(m527x_devices));
-	return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/528x/config.c b/arch/m68k/platform/528x/config.c
index 7abe77a..d449292 100644
--- a/arch/m68k/platform/528x/config.c
+++ b/arch/m68k/platform/528x/config.c
@@ -17,229 +17,33 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m528x_uart_platform[] = {
-	{
-		.mapbase	= MCFUART_BASE1,
-		.irq		= MCFINT_VECBASE + MCFINT_UART0,
-	},
-	{
-		.mapbase 	= MCFUART_BASE2,
-		.irq		= MCFINT_VECBASE + MCFINT_UART0 + 1,
-	},
-	{
-		.mapbase 	= MCFUART_BASE3,
-		.irq		= MCFINT_VECBASE + MCFINT_UART0 + 2,
-	},
-	{ },
-};
-
-static struct platform_device m528x_uart = {
-	.name			= "mcfuart",
-	.id			= 0,
-	.dev.platform_data	= m528x_uart_platform,
-};
-
-static struct resource m528x_fec_resources[] = {
-	{
-		.start		= MCFFEC_BASE,
-		.end		= MCFFEC_BASE + MCFFEC_SIZE - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= 64 + 23,
-		.end		= 64 + 23,
-		.flags		= IORESOURCE_IRQ,
-	},
-	{
-		.start		= 64 + 27,
-		.end		= 64 + 27,
-		.flags		= IORESOURCE_IRQ,
-	},
-	{
-		.start		= 64 + 29,
-		.end		= 64 + 29,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device m528x_fec = {
-	.name			= "fec",
-	.id			= 0,
-	.num_resources		= ARRAY_SIZE(m528x_fec_resources),
-	.resource		= m528x_fec_resources,
-};
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m528x_qspi_resources[] = {
-	{
-		.start		= MCFQSPI_IOBASE,
-		.end		= MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= MCFINT_VECBASE + MCFINT_QSPI,
-		.end		= MCFINT_VECBASE + MCFINT_QSPI,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-#define MCFQSPI_CS0    147
-#define MCFQSPI_CS1    148
-#define MCFQSPI_CS2    149
-#define MCFQSPI_CS3    150
-
-static int m528x_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-	int status;
-
-	status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-		goto fail0;
-	}
-	status = gpio_direction_output(MCFQSPI_CS0, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-		goto fail1;
-	}
-
-	status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-		goto fail1;
-	}
-	status = gpio_direction_output(MCFQSPI_CS1, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-		goto fail2;
-	}
-
-	status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-		goto fail2;
-	}
-	status = gpio_direction_output(MCFQSPI_CS2, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-		goto fail3;
-	}
-
-	status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
-		goto fail3;
-	}
-	status = gpio_direction_output(MCFQSPI_CS3, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
-		goto fail4;
-	}
-
-	return 0;
-
-fail4:
-	gpio_free(MCFQSPI_CS3);
-fail3:
-	gpio_free(MCFQSPI_CS2);
-fail2:
-	gpio_free(MCFQSPI_CS1);
-fail1:
-	gpio_free(MCFQSPI_CS0);
-fail0:
-	return status;
-}
-
-static void m528x_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-	gpio_free(MCFQSPI_CS3);
-	gpio_free(MCFQSPI_CS2);
-	gpio_free(MCFQSPI_CS1);
-	gpio_free(MCFQSPI_CS0);
-}
-
-static void m528x_cs_select(struct mcfqspi_cs_control *cs_control,
-			    u8 chip_select, bool cs_high)
-{
-	gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high);
-}
-
-static void m528x_cs_deselect(struct mcfqspi_cs_control *cs_control,
-			      u8 chip_select, bool cs_high)
-{
-	gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high);
-}
-
-static struct mcfqspi_cs_control m528x_cs_control = {
-	.setup                  = m528x_cs_setup,
-	.teardown               = m528x_cs_teardown,
-	.select                 = m528x_cs_select,
-	.deselect               = m528x_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m528x_qspi_data = {
-	.bus_num		= 0,
-	.num_chipselect		= 4,
-	.cs_control		= &m528x_cs_control,
-};
-
-static struct platform_device m528x_qspi = {
-	.name			= "mcfqspi",
-	.id			= 0,
-	.num_resources		= ARRAY_SIZE(m528x_qspi_resources),
-	.resource		= m528x_qspi_resources,
-	.dev.platform_data	= &m528x_qspi_data,
-};
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 
 static void __init m528x_qspi_init(void)
 {
 	/* setup Port QS for QSPI with gpio CS control */
 	__raw_writeb(0x07, MCFGPIO_PQSPAR);
 }
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
 
-static struct platform_device *m528x_devices[] __initdata = {
-	&m528x_uart,
-	&m528x_fec,
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-	&m528x_qspi,
-#endif
-};
+#endif /* CONFIG_SPI_COLDFIRE_QSPI */
 
 /***************************************************************************/
 
-static void __init m528x_uart_init_line(int line, int irq)
+static void __init m528x_uarts_init(void)
 {
 	u8 port;
 
-	if ((line < 0) || (line > 2))
-		return;
-
 	/* make sure PUAPAR is set for UART0 and UART1 */
-	if (line < 2) {
-		port = readb(MCF5282_GPIO_PUAPAR);
-		port |= (0x03 << (line * 2));
-		writeb(port, MCF5282_GPIO_PUAPAR);
-	}
-}
-
-static void __init m528x_uarts_init(void)
-{
-	const int nrlines = ARRAY_SIZE(m528x_uart_platform);
-	int line;
-
-	for (line = 0; (line < nrlines); line++)
-		m528x_uart_init_line(line, m528x_uart_platform[line].irq);
+	port = readb(MCF5282_GPIO_PUAPAR);
+	port |= 0x03 | (0x03 << 2);
+	writeb(port, MCF5282_GPIO_PUAPAR);
 }
 
 /***************************************************************************/
@@ -256,14 +60,6 @@
 
 /***************************************************************************/
 
-static void m528x_cpu_reset(void)
-{
-	local_irq_disable();
-	__raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR);
-}
-
-/***************************************************************************/
-
 #ifdef CONFIG_WILDFIRE
 void wildfire_halt(void)
 {
@@ -299,22 +95,12 @@
 #ifdef CONFIG_WILDFIREMOD
 	mach_halt = wildfiremod_halt;
 #endif
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-	mach_reset = m528x_cpu_reset;
+	mach_sched_init = hw_timer_init;
 	m528x_uarts_init();
 	m528x_fec_init();
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 	m528x_qspi_init();
 #endif
-	platform_add_devices(m528x_devices, ARRAY_SIZE(m528x_devices));
-	return 0;
 }
 
-arch_initcall(init_BSP);
-
 /***************************************************************************/
diff --git a/arch/m68k/platform/5307/config.c b/arch/m68k/platform/5307/config.c
index 00900ac..a568d28 100644
--- a/arch/m68k/platform/5307/config.c
+++ b/arch/m68k/platform/5307/config.c
@@ -16,7 +16,6 @@
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
 #include <asm/mcfwdebug.h>
 
 /***************************************************************************/
@@ -29,82 +28,6 @@
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m5307_uart_platform[] = {
-	{
-		.mapbase	= MCF_MBAR + MCFUART_BASE1,
-		.irq		= 73,
-	},
-	{
-		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
-		.irq		= 74,
-	},
-	{ },
-};
-
-static struct platform_device m5307_uart = {
-	.name			= "mcfuart",
-	.id			= 0,
-	.dev.platform_data	= m5307_uart_platform,
-};
-
-static struct platform_device *m5307_devices[] __initdata = {
-	&m5307_uart,
-};
-
-/***************************************************************************/
-
-static void __init m5307_uart_init_line(int line, int irq)
-{
-	if (line == 0) {
-		writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-		writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
-		mcf_mapirq2imr(irq, MCFINTC_UART0);
-	} else if (line == 1) {
-		writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-		writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
-		mcf_mapirq2imr(irq, MCFINTC_UART1);
-	}
-}
-
-static void __init m5307_uarts_init(void)
-{
-	const int nrlines = ARRAY_SIZE(m5307_uart_platform);
-	int line;
-
-	for (line = 0; (line < nrlines); line++)
-		m5307_uart_init_line(line, m5307_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void __init m5307_timers_init(void)
-{
-	/* Timer1 is always used as system timer */
-	writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
-		MCF_MBAR + MCFSIM_TIMER1ICR);
-	mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
-
-#ifdef CONFIG_HIGHPROFILE
-	/* Timer2 is to be used as a high speed profile timer  */
-	writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
-		MCF_MBAR + MCFSIM_TIMER2ICR);
-	mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
-#endif
-}
-
-/***************************************************************************/
-
-void m5307_cpu_reset(void)
-{
-	local_irq_disable();
-	/* Set watchdog to soft reset, and enabled */
-	__raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
-	for (;;)
-		/* wait for watchdog to timeout */;
-}
-
-/***************************************************************************/
-
 void __init config_BSP(char *commandp, int size)
 {
 #if defined(CONFIG_NETtel) || \
@@ -114,9 +37,7 @@
 	commandp[size-1] = 0;
 #endif
 
-	mach_reset = m5307_cpu_reset;
-	m5307_timers_init();
-	m5307_uarts_init();
+	mach_sched_init = hw_timer_init;
 
 	/* Only support the external interrupts on their primary level */
 	mcf_mapirq2imr(25, MCFINTC_EINT1);
@@ -135,13 +56,3 @@
 }
 
 /***************************************************************************/
-
-static int __init init_BSP(void)
-{
-	platform_add_devices(m5307_devices, ARRAY_SIZE(m5307_devices));
-	return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/532x/config.c b/arch/m68k/platform/532x/config.c
index ca51323..2bec347 100644
--- a/arch/m68k/platform/532x/config.c
+++ b/arch/m68k/platform/532x/config.c
@@ -21,214 +21,33 @@
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
 #include <asm/mcfdma.h>
 #include <asm/mcfwdebug.h>
-#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m532x_uart_platform[] = {
-	{
-		.mapbase	= MCFUART_BASE1,
-		.irq		= MCFINT_VECBASE + MCFINT_UART0,
-	},
-	{
-		.mapbase 	= MCFUART_BASE2,
-		.irq		= MCFINT_VECBASE + MCFINT_UART1,
-	},
-	{
-		.mapbase 	= MCFUART_BASE3,
-		.irq		= MCFINT_VECBASE + MCFINT_UART2,
-	},
-	{ },
-};
-
-static struct platform_device m532x_uart = {
-	.name			= "mcfuart",
-	.id			= 0,
-	.dev.platform_data	= m532x_uart_platform,
-};
-
-static struct resource m532x_fec_resources[] = {
-	{
-		.start		= 0xfc030000,
-		.end		= 0xfc0307ff,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= 64 + 36,
-		.end		= 64 + 36,
-		.flags		= IORESOURCE_IRQ,
-	},
-	{
-		.start		= 64 + 40,
-		.end		= 64 + 40,
-		.flags		= IORESOURCE_IRQ,
-	},
-	{
-		.start		= 64 + 42,
-		.end		= 64 + 42,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device m532x_fec = {
-	.name			= "fec",
-	.id			= 0,
-	.num_resources		= ARRAY_SIZE(m532x_fec_resources),
-	.resource		= m532x_fec_resources,
-};
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m532x_qspi_resources[] = {
-	{
-		.start		= MCFQSPI_IOBASE,
-		.end		= MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= MCFINT_VECBASE + MCFINT_QSPI,
-		.end		= MCFINT_VECBASE + MCFINT_QSPI,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-#define MCFQSPI_CS0    84
-#define MCFQSPI_CS1    85
-#define MCFQSPI_CS2    86
-
-static int m532x_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-	int status;
-
-	status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-		goto fail0;
-	}
-	status = gpio_direction_output(MCFQSPI_CS0, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-		goto fail1;
-	}
-
-	status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-		goto fail1;
-	}
-	status = gpio_direction_output(MCFQSPI_CS1, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-		goto fail2;
-	}
-
-	status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-	if (status) {
-		pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-		goto fail2;
-	}
-	status = gpio_direction_output(MCFQSPI_CS2, 1);
-	if (status) {
-		pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-		goto fail3;
-	}
-
-	return 0;
-
-fail3:
-	gpio_free(MCFQSPI_CS2);
-fail2:
-	gpio_free(MCFQSPI_CS1);
-fail1:
-	gpio_free(MCFQSPI_CS0);
-fail0:
-	return status;
-}
-
-static void m532x_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-	gpio_free(MCFQSPI_CS2);
-	gpio_free(MCFQSPI_CS1);
-	gpio_free(MCFQSPI_CS0);
-}
-
-static void m532x_cs_select(struct mcfqspi_cs_control *cs_control,
-			    u8 chip_select, bool cs_high)
-{
-	gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high);
-}
-
-static void m532x_cs_deselect(struct mcfqspi_cs_control *cs_control,
-			      u8 chip_select, bool cs_high)
-{
-	gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high);
-}
-
-static struct mcfqspi_cs_control m532x_cs_control = {
-	.setup                  = m532x_cs_setup,
-	.teardown               = m532x_cs_teardown,
-	.select                 = m532x_cs_select,
-	.deselect               = m532x_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m532x_qspi_data = {
-	.bus_num		= 0,
-	.num_chipselect		= 3,
-	.cs_control		= &m532x_cs_control,
-};
-
-static struct platform_device m532x_qspi = {
-	.name			= "mcfqspi",
-	.id			= 0,
-	.num_resources		= ARRAY_SIZE(m532x_qspi_resources),
-	.resource		= m532x_qspi_resources,
-	.dev.platform_data	= &m532x_qspi_data,
-};
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 
 static void __init m532x_qspi_init(void)
 {
 	/* setup QSPS pins for QSPI with gpio CS control */
 	writew(0x01f0, MCF_GPIO_PAR_QSPI);
 }
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
 
-
-static struct platform_device *m532x_devices[] __initdata = {
-	&m532x_uart,
-	&m532x_fec,
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-	&m532x_qspi,
-#endif
-};
+#endif /* CONFIG_SPI_COLDFIRE_QSPI */
 
 /***************************************************************************/
 
-static void __init m532x_uart_init_line(int line, int irq)
-{
-	if (line == 0) {
-		/* GPIO initialization */
-		MCF_GPIO_PAR_UART |= 0x000F;
-	} else if (line == 1) {
-		/* GPIO initialization */
-		MCF_GPIO_PAR_UART |= 0x0FF0;
-	}
-}
-
 static void __init m532x_uarts_init(void)
 {
-	const int nrlines = ARRAY_SIZE(m532x_uart_platform);
-	int line;
-
-	for (line = 0; (line < nrlines); line++)
-		m532x_uart_init_line(line, m532x_uart_platform[line].irq);
+	/* UART GPIO initialization */
+	MCF_GPIO_PAR_UART |= 0x0FFF;
 }
+
 /***************************************************************************/
 
 static void __init m532x_fec_init(void)
@@ -242,14 +61,6 @@
 
 /***************************************************************************/
 
-static void m532x_cpu_reset(void)
-{
-	local_irq_disable();
-	__raw_writeb(MCF_RCR_SWRESET, MCF_RCR);
-}
-
-/***************************************************************************/
-
 void __init config_BSP(char *commandp, int size)
 {
 #if !defined(CONFIG_BOOTPARAM)
@@ -263,6 +74,13 @@
 	}
 #endif
 
+	mach_sched_init = hw_timer_init;
+	m532x_uarts_init();
+	m532x_fec_init();
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
+	m532x_qspi_init();
+#endif
+
 #ifdef CONFIG_BDM_DISABLE
 	/*
 	 * Disable the BDM clocking.  This also turns off most of the rest of
@@ -274,21 +92,6 @@
 }
 
 /***************************************************************************/
-
-static int __init init_BSP(void)
-{
-	m532x_uarts_init();
-	m532x_fec_init();
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-	m532x_qspi_init();
-#endif
-	platform_add_devices(m532x_devices, ARRAY_SIZE(m532x_devices));
-	return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
 /* Board initialization */
 /***************************************************************************/
 /* 
diff --git a/arch/m68k/platform/5407/config.c b/arch/m68k/platform/5407/config.c
index 70ea789..bb6c746 100644
--- a/arch/m68k/platform/5407/config.c
+++ b/arch/m68k/platform/5407/config.c
@@ -16,91 +16,12 @@
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m5407_uart_platform[] = {
-	{
-		.mapbase	= MCF_MBAR + MCFUART_BASE1,
-		.irq		= 73,
-	},
-	{
-		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
-		.irq		= 74,
-	},
-	{ },
-};
-
-static struct platform_device m5407_uart = {
-	.name			= "mcfuart",
-	.id			= 0,
-	.dev.platform_data	= m5407_uart_platform,
-};
-
-static struct platform_device *m5407_devices[] __initdata = {
-	&m5407_uart,
-};
-
-/***************************************************************************/
-
-static void __init m5407_uart_init_line(int line, int irq)
-{
-	if (line == 0) {
-		writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-		writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
-		mcf_mapirq2imr(irq, MCFINTC_UART0);
-	} else if (line == 1) {
-		writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-		writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
-		mcf_mapirq2imr(irq, MCFINTC_UART1);
-	}
-}
-
-static void __init m5407_uarts_init(void)
-{
-	const int nrlines = ARRAY_SIZE(m5407_uart_platform);
-	int line;
-
-	for (line = 0; (line < nrlines); line++)
-		m5407_uart_init_line(line, m5407_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void __init m5407_timers_init(void)
-{
-	/* Timer1 is always used as system timer */
-	writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
-		MCF_MBAR + MCFSIM_TIMER1ICR);
-	mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
-
-#ifdef CONFIG_HIGHPROFILE
-	/* Timer2 is to be used as a high speed profile timer  */
-	writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
-		MCF_MBAR + MCFSIM_TIMER2ICR);
-	mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
-#endif
-}
-
-/***************************************************************************/
-
-void m5407_cpu_reset(void)
-{
-	local_irq_disable();
-	/* set watchdog to soft reset, and enabled */
-	__raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
-	for (;;)
-		/* wait for watchdog to timeout */;
-}
 
 /***************************************************************************/
 
 void __init config_BSP(char *commandp, int size)
 {
-	mach_reset = m5407_cpu_reset;
-	m5407_timers_init();
-	m5407_uarts_init();
+	mach_sched_init = hw_timer_init;
 
 	/* Only support the external interrupts on their primary level */
 	mcf_mapirq2imr(25, MCFINTC_EINT1);
@@ -110,13 +31,3 @@
 }
 
 /***************************************************************************/
-
-static int __init init_BSP(void)
-{
-	platform_add_devices(m5407_devices, ARRAY_SIZE(m5407_devices));
-	return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/54xx/config.c b/arch/m68k/platform/54xx/config.c
index ee04354..2081c6c 100644
--- a/arch/m68k/platform/54xx/config.c
+++ b/arch/m68k/platform/54xx/config.c
@@ -27,64 +27,17 @@
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m54xx_uart_platform[] = {
-	{
-		.mapbase	= MCF_MBAR + MCFUART_BASE1,
-		.irq		= 64 + 35,
-	},
-	{
-		.mapbase	= MCF_MBAR + MCFUART_BASE2,
-		.irq		= 64 + 34,
-	},
-	{
-		.mapbase	= MCF_MBAR + MCFUART_BASE3,
-		.irq		= 64 + 33,
-	},
-	{
-		.mapbase	= MCF_MBAR + MCFUART_BASE4,
-		.irq		= 64 + 32,
-	},
-};
-
-static struct platform_device m54xx_uart = {
-	.name			= "mcfuart",
-	.id			= 0,
-	.dev.platform_data	= m54xx_uart_platform,
-};
-
-static struct platform_device *m54xx_devices[] __initdata = {
-	&m54xx_uart,
-};
-
-
-/***************************************************************************/
-
-static void __init m54xx_uart_init_line(int line, int irq)
-{
-	int rts_cts;
-
-	/* enable io pins */
-	switch (line) {
-	case 0:
-		rts_cts = 0; break;
-	case 1:
-		rts_cts = MCF_PAR_PSC_RTS_RTS; break;
-	case 2:
-		rts_cts = MCF_PAR_PSC_RTS_RTS | MCF_PAR_PSC_CTS_CTS; break;
-	case 3:
-		rts_cts = 0; break;
-	}
-	__raw_writeb(MCF_PAR_PSC_TXD | rts_cts | MCF_PAR_PSC_RXD,
-						MCF_MBAR + MCF_PAR_PSC(line));
-}
-
 static void __init m54xx_uarts_init(void)
 {
-	const int nrlines = ARRAY_SIZE(m54xx_uart_platform);
-	int line;
-
-	for (line = 0; (line < nrlines); line++)
-		m54xx_uart_init_line(line, m54xx_uart_platform[line].irq);
+	/* enable io pins */
+	__raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD,
+		MCF_MBAR + MCF_PAR_PSC(0));
+	__raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD | MCF_PAR_PSC_RTS_RTS,
+		MCF_MBAR + MCF_PAR_PSC(1));
+	__raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD | MCF_PAR_PSC_RTS_RTS |
+		MCF_PAR_PSC_CTS_CTS, MCF_MBAR + MCF_PAR_PSC(2));
+	__raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD,
+		MCF_MBAR + MCF_PAR_PSC(3));
 }
 
 /***************************************************************************/
@@ -145,18 +98,8 @@
 	mmu_context_init();
 #endif
 	mach_reset = mcf54xx_reset;
+	mach_sched_init = hw_timer_init;
 	m54xx_uarts_init();
 }
 
 /***************************************************************************/
-
-static int __init init_BSP(void)
-{
-
-	platform_add_devices(m54xx_devices, ARRAY_SIZE(m54xx_devices));
-	return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/68328/config.c b/arch/m68k/platform/68328/config.c
index d70bf26..8c20e89 100644
--- a/arch/m68k/platform/68328/config.c
+++ b/arch/m68k/platform/68328/config.c
@@ -17,7 +17,7 @@
 
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <asm/system.h>
+#include <linux/rtc.h>
 #include <asm/machdep.h>
 #include <asm/MC68328.h>
 #if defined(CONFIG_PILOT) || defined(CONFIG_INIT_LCD)
@@ -26,7 +26,7 @@
 
 /***************************************************************************/
 
-void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec);
+int m68328_hwclk(int set, struct rtc_time *t);
 
 /***************************************************************************/
 
@@ -48,7 +48,7 @@
   printk(KERN_INFO "68328 support Kenneth Albanowski <kjahds@kjshds.com>\n");
   printk(KERN_INFO "68328/Pilot support Bernhard Kuhn <kuhn@lpr.e-technik.tu-muenchen.de>\n");
 
-  mach_gettod = m68328_timer_gettod;
+  mach_hwclk = m68328_hwclk;
   mach_reset = m68328_reset;
 }
 
diff --git a/arch/m68k/platform/68328/ints.c b/arch/m68k/platform/68328/ints.c
index 4bd4565..b3810fe 100644
--- a/arch/m68k/platform/68328/ints.c
+++ b/arch/m68k/platform/68328/ints.c
@@ -68,8 +68,6 @@
 asmlinkage irqreturn_t inthandler6(void);
 asmlinkage irqreturn_t inthandler7(void);
 
-extern e_vector *_ramvec;
-
 /* The 68k family did not have a good way to determine the source
  * of interrupts until later in the family.  The EC000 core does
  * not provide the vector number on the stack, we vector everything
diff --git a/arch/m68k/platform/68328/timers.c b/arch/m68k/platform/68328/timers.c
index f267886..c801c17 100644
--- a/arch/m68k/platform/68328/timers.c
+++ b/arch/m68k/platform/68328/timers.c
@@ -20,8 +20,8 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/clocksource.h>
+#include <linux/rtc.h>
 #include <asm/setup.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/machdep.h>
 #include <asm/MC68VZ328.h>
@@ -119,14 +119,17 @@
 
 /***************************************************************************/
 
-void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec)
+int m68328_hwclk(int set, struct rtc_time *t)
 {
-	long now = RTCTIME;
+	if (!set) {
+		long now = RTCTIME;
+		t->tm_year = t->tm_mon = t->tm_mday = 1;
+		t->tm_hour = (now >> 24) % 24;
+		t->tm_min = (now >> 16) % 60;
+		t->tm_sec = now % 60;
+	}
 
-	*year = *mon = *day = 1;
-	*hour = (now >> 24) % 24;
-	*min = (now >> 16) % 60;
-	*sec = now % 60;
+	return 0;
 }
 
 /***************************************************************************/
diff --git a/arch/m68k/platform/68360/config.c b/arch/m68k/platform/68360/config.c
index 9dd5bca..255fc03 100644
--- a/arch/m68k/platform/68360/config.c
+++ b/arch/m68k/platform/68360/config.c
@@ -18,7 +18,6 @@
 #include <linux/irq.h>
 
 #include <asm/setup.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/machdep.h>
 #include <asm/m68360.h>
@@ -103,11 +102,6 @@
   pquicc->timer_tgcr  = tgcr_save;
 }
 
-void BSP_gettod (int *yearp, int *monp, int *dayp,
-		   int *hourp, int *minp, int *secp)
-{
-}
-
 int BSP_set_clock_mmss(unsigned long nowtime)
 {
 #if 0
@@ -181,6 +175,5 @@
   scc1_hwaddr = "\00\01\02\03\04\05";
 #endif
  
-  mach_gettod          = BSP_gettod;
-  mach_reset           = BSP_reset;
+  mach_reset = BSP_reset;
 }
diff --git a/arch/m68k/platform/68360/ints.c b/arch/m68k/platform/68360/ints.c
index 7b40202..8cd4269 100644
--- a/arch/m68k/platform/68360/ints.c
+++ b/arch/m68k/platform/68360/ints.c
@@ -32,8 +32,6 @@
 asmlinkage void bad_interrupt(void);
 asmlinkage void inthandler(void);
 
-extern void *_ramvec[];
-
 static void intc_irq_unmask(struct irq_data *d)
 {
 	pquicc->intr_cimr |= (1 << d->irq);
diff --git a/arch/m68k/platform/68EZ328/config.c b/arch/m68k/platform/68EZ328/config.c
index 1be1a16..4f158d5 100644
--- a/arch/m68k/platform/68EZ328/config.c
+++ b/arch/m68k/platform/68EZ328/config.c
@@ -15,7 +15,7 @@
 
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <asm/system.h>
+#include <linux/rtc.h>
 #include <asm/pgtable.h>
 #include <asm/machdep.h>
 #include <asm/MC68EZ328.h>
@@ -25,7 +25,7 @@
 
 /***************************************************************************/
 
-void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec);
+int m68328_hwclk(int set, struct rtc_time *t);
 
 /***************************************************************************/
 
@@ -69,7 +69,7 @@
   else command[0] = 0;
 #endif
  
-  mach_gettod = m68328_timer_gettod;
+  mach_hwclk = m68328_hwclk;
   mach_reset = m68ez328_reset;
 }
 
diff --git a/arch/m68k/platform/68VZ328/config.c b/arch/m68k/platform/68VZ328/config.c
index eabaabe..2ed8dc3 100644
--- a/arch/m68k/platform/68VZ328/config.c
+++ b/arch/m68k/platform/68VZ328/config.c
@@ -20,8 +20,8 @@
 #include <linux/netdevice.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/rtc.h>
 
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/machdep.h>
 #include <asm/MC68VZ328.h>
@@ -33,7 +33,7 @@
 
 /***************************************************************************/
 
-void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec);
+int m68328_hwclk(int set, struct rtc_time *t);
 
 /***************************************************************************/
 /*                        Init Drangon Engine hardware                     */
@@ -181,7 +181,7 @@
 
 	init_hardware(command, size);
 
-	mach_gettod = m68328_timer_gettod;
+	mach_hwclk = m68328_hwclk;
 	mach_reset = m68vz328_reset;
 }
 
diff --git a/arch/m68k/platform/coldfire/Makefile b/arch/m68k/platform/coldfire/Makefile
index a8967ba..a0815c6 100644
--- a/arch/m68k/platform/coldfire/Makefile
+++ b/arch/m68k/platform/coldfire/Makefile
@@ -14,18 +14,18 @@
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
 
-obj-$(CONFIG_COLDFIRE)	+= cache.o clk.o dma.o entry.o vectors.o
-obj-$(CONFIG_M5206)	+= timers.o intc.o
-obj-$(CONFIG_M5206e)	+= timers.o intc.o
-obj-$(CONFIG_M520x)	+= pit.o intc-simr.o
-obj-$(CONFIG_M523x)	+= pit.o dma_timer.o intc-2.o
-obj-$(CONFIG_M5249)	+= timers.o intc.o
-obj-$(CONFIG_M527x)	+= pit.o intc-2.o
+obj-$(CONFIG_COLDFIRE)	+= cache.o clk.o device.o dma.o entry.o vectors.o
+obj-$(CONFIG_M5206)	+= timers.o intc.o reset.o
+obj-$(CONFIG_M5206e)	+= timers.o intc.o reset.o
+obj-$(CONFIG_M520x)	+= pit.o intc-simr.o reset.o
+obj-$(CONFIG_M523x)	+= pit.o dma_timer.o intc-2.o reset.o
+obj-$(CONFIG_M5249)	+= timers.o intc.o reset.o
+obj-$(CONFIG_M527x)	+= pit.o intc-2.o reset.o
 obj-$(CONFIG_M5272)	+= timers.o
-obj-$(CONFIG_M528x)	+= pit.o intc-2.o
-obj-$(CONFIG_M5307)	+= timers.o intc.o
-obj-$(CONFIG_M532x)	+= timers.o intc-simr.o
-obj-$(CONFIG_M5407)	+= timers.o intc.o
+obj-$(CONFIG_M528x)	+= pit.o intc-2.o reset.o
+obj-$(CONFIG_M5307)	+= timers.o intc.o reset.o
+obj-$(CONFIG_M532x)	+= timers.o intc-simr.o reset.o
+obj-$(CONFIG_M5407)	+= timers.o intc.o reset.o
 obj-$(CONFIG_M54xx)	+= sltimers.o intc-2.o
 
 obj-y			+= pinmux.o gpio.o
diff --git a/arch/m68k/platform/coldfire/device.c b/arch/m68k/platform/coldfire/device.c
new file mode 100644
index 0000000..fa50c48
--- /dev/null
+++ b/arch/m68k/platform/coldfire/device.c
@@ -0,0 +1,318 @@
+/*
+ * device.c  -- common ColdFire SoC device support
+ *
+ * (C) Copyright 2011, Greg Ungerer <gerg@uclinux.org>
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <asm/traps.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfqspi.h>
+
+/*
+ *	All current ColdFire parts contain from 2, 3 or 4 UARTS.
+ */
+static struct mcf_platform_uart mcf_uart_platform_data[] = {
+	{
+		.mapbase	= MCFUART_BASE0,
+		.irq		= MCF_IRQ_UART0,
+	},
+	{
+		.mapbase	= MCFUART_BASE1,
+		.irq		= MCF_IRQ_UART1,
+	},
+#ifdef MCFUART_BASE2
+	{
+		.mapbase	= MCFUART_BASE2,
+		.irq		= MCF_IRQ_UART2,
+	},
+#endif
+#ifdef MCFUART_BASE3
+	{
+		.mapbase	= MCFUART_BASE3,
+		.irq		= MCF_IRQ_UART3,
+	},
+#endif
+	{ },
+};
+
+static struct platform_device mcf_uart = {
+	.name			= "mcfuart",
+	.id			= 0,
+	.dev.platform_data	= mcf_uart_platform_data,
+};
+
+#ifdef CONFIG_FEC
+/*
+ *	Some ColdFire cores contain the Fast Ethernet Controller (FEC)
+ *	block. It is Freescale's own hardware block. Some ColdFires
+ *	have 2 of these.
+ */
+static struct resource mcf_fec0_resources[] = {
+	{
+		.start		= MCFFEC_BASE0,
+		.end		= MCFFEC_BASE0 + MCFFEC_SIZE0 - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= MCF_IRQ_FECRX0,
+		.end		= MCF_IRQ_FECRX0,
+		.flags		= IORESOURCE_IRQ,
+	},
+	{
+		.start		= MCF_IRQ_FECTX0,
+		.end		= MCF_IRQ_FECTX0,
+		.flags		= IORESOURCE_IRQ,
+	},
+	{
+		.start		= MCF_IRQ_FECENTC0,
+		.end		= MCF_IRQ_FECENTC0,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device mcf_fec0 = {
+	.name			= "fec",
+	.id			= 0,
+	.num_resources		= ARRAY_SIZE(mcf_fec0_resources),
+	.resource		= mcf_fec0_resources,
+};
+
+#ifdef MCFFEC_BASE1
+static struct resource mcf_fec1_resources[] = {
+	{
+		.start		= MCFFEC_BASE1,
+		.end		= MCFFEC_BASE1 + MCFFEC_SIZE1 - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= MCF_IRQ_FECRX1,
+		.end		= MCF_IRQ_FECRX1,
+		.flags		= IORESOURCE_IRQ,
+	},
+	{
+		.start		= MCF_IRQ_FECTX1,
+		.end		= MCF_IRQ_FECTX1,
+		.flags		= IORESOURCE_IRQ,
+	},
+	{
+		.start		= MCF_IRQ_FECENTC1,
+		.end		= MCF_IRQ_FECENTC1,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device mcf_fec1 = {
+	.name			= "fec",
+	.id			= 0,
+	.num_resources		= ARRAY_SIZE(mcf_fec1_resources),
+	.resource		= mcf_fec1_resources,
+};
+#endif /* MCFFEC_BASE1 */
+#endif /* CONFIG_FEC */
+
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
+/*
+ *	The ColdFire QSPI module is an SPI protocol hardware block used
+ *	on a number of different ColdFire CPUs.
+ */
+static struct resource mcf_qspi_resources[] = {
+	{
+		.start		= MCFQSPI_BASE,
+		.end		= MCFQSPI_BASE + MCFQSPI_SIZE - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= MCF_IRQ_QSPI,
+		.end		= MCF_IRQ_QSPI,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static int mcf_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+	int status;
+
+	status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+	if (status) {
+		pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+		goto fail0;
+	}
+	status = gpio_direction_output(MCFQSPI_CS0, 1);
+	if (status) {
+		pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+		goto fail1;
+	}
+
+	status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+	if (status) {
+		pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+		goto fail1;
+	}
+	status = gpio_direction_output(MCFQSPI_CS1, 1);
+	if (status) {
+		pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+		goto fail2;
+	}
+
+	status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+	if (status) {
+		pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+		goto fail2;
+	}
+	status = gpio_direction_output(MCFQSPI_CS2, 1);
+	if (status) {
+		pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+		goto fail3;
+	}
+
+#ifdef MCFQSPI_CS3
+	status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
+	if (status) {
+		pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
+		goto fail3;
+	}
+	status = gpio_direction_output(MCFQSPI_CS3, 1);
+	if (status) {
+		pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
+		gpio_free(MCFQSPI_CS3);
+		goto fail3;
+	}
+#endif
+
+	return 0;
+
+fail3:
+	gpio_free(MCFQSPI_CS2);
+fail2:
+	gpio_free(MCFQSPI_CS1);
+fail1:
+	gpio_free(MCFQSPI_CS0);
+fail0:
+	return status;
+}
+
+static void mcf_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+#ifdef MCFQSPI_CS3
+	gpio_free(MCFQSPI_CS3);
+#endif
+	gpio_free(MCFQSPI_CS2);
+	gpio_free(MCFQSPI_CS1);
+	gpio_free(MCFQSPI_CS0);
+}
+
+static void mcf_cs_select(struct mcfqspi_cs_control *cs_control,
+			  u8 chip_select, bool cs_high)
+{
+	switch (chip_select) {
+	case 0:
+		gpio_set_value(MCFQSPI_CS0, cs_high);
+		break;
+	case 1:
+		gpio_set_value(MCFQSPI_CS1, cs_high);
+		break;
+	case 2:
+		gpio_set_value(MCFQSPI_CS2, cs_high);
+		break;
+#ifdef MCFQSPI_CS3
+	case 3:
+		gpio_set_value(MCFQSPI_CS3, cs_high);
+		break;
+#endif
+	}
+}
+
+static void mcf_cs_deselect(struct mcfqspi_cs_control *cs_control,
+			    u8 chip_select, bool cs_high)
+{
+	switch (chip_select) {
+	case 0:
+		gpio_set_value(MCFQSPI_CS0, !cs_high);
+		break;
+	case 1:
+		gpio_set_value(MCFQSPI_CS1, !cs_high);
+		break;
+	case 2:
+		gpio_set_value(MCFQSPI_CS2, !cs_high);
+		break;
+#ifdef MCFQSPI_CS3
+	case 3:
+		gpio_set_value(MCFQSPI_CS3, !cs_high);
+		break;
+#endif
+	}
+}
+
+static struct mcfqspi_cs_control mcf_cs_control = {
+	.setup			= mcf_cs_setup,
+	.teardown		= mcf_cs_teardown,
+	.select			= mcf_cs_select,
+	.deselect		= mcf_cs_deselect,
+};
+
+static struct mcfqspi_platform_data mcf_qspi_data = {
+	.bus_num		= 0,
+	.num_chipselect		= 4,
+	.cs_control		= &mcf_cs_control,
+};
+
+static struct platform_device mcf_qspi = {
+	.name			= "mcfqspi",
+	.id			= 0,
+	.num_resources		= ARRAY_SIZE(mcf_qspi_resources),
+	.resource		= mcf_qspi_resources,
+	.dev.platform_data	= &mcf_qspi_data,
+};
+#endif /* CONFIG_SPI_COLDFIRE_QSPI */
+
+static struct platform_device *mcf_devices[] __initdata = {
+	&mcf_uart,
+#ifdef CONFIG_FEC
+	&mcf_fec0,
+#ifdef MCFFEC_BASE1
+	&mcf_fec1,
+#endif
+#endif
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
+	&mcf_qspi,
+#endif
+};
+
+/*
+ *	Some ColdFire UARTs let you set the IRQ line to use.
+ */
+static void __init mcf_uart_set_irq(void)
+{
+#ifdef MCFUART_UIVR
+	/* UART0 interrupt setup */
+	writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+	writeb(MCF_IRQ_UART0, MCFUART_BASE0 + MCFUART_UIVR);
+	mcf_mapirq2imr(MCF_IRQ_UART0, MCFINTC_UART0);
+
+	/* UART1 interrupt setup */
+	writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+	writeb(MCF_IRQ_UART1, MCFUART_BASE1 + MCFUART_UIVR);
+	mcf_mapirq2imr(MCF_IRQ_UART1, MCFINTC_UART1);
+#endif
+}
+
+static int __init mcf_init_devices(void)
+{
+	mcf_uart_set_irq();
+	platform_add_devices(mcf_devices, ARRAY_SIZE(mcf_devices));
+	return 0;
+}
+
+arch_initcall(mcf_init_devices);
+
diff --git a/arch/m68k/platform/coldfire/head.S b/arch/m68k/platform/coldfire/head.S
index 38f04a3..c3db70e 100644
--- a/arch/m68k/platform/coldfire/head.S
+++ b/arch/m68k/platform/coldfire/head.S
@@ -158,6 +158,10 @@
 #if defined(CONFIG_UBOOT)
 	movel	%sp,_init_sp			/* save initial stack pointer */
 #endif
+#ifdef CONFIG_MBAR
+	movel	#CONFIG_MBAR+1,%d0		/* configured MBAR address */
+	movec	%d0,%MBAR			/* set it */
+#endif
 
 	/*
 	 *	Do any platform or board specific setup now. Most boards
diff --git a/arch/m68k/platform/coldfire/pit.c b/arch/m68k/platform/coldfire/pit.c
index 02663d2..e62dbbc 100644
--- a/arch/m68k/platform/coldfire/pit.c
+++ b/arch/m68k/platform/coldfire/pit.c
@@ -149,7 +149,7 @@
 
 /***************************************************************************/
 
-void hw_timer_init(void)
+void hw_timer_init(irq_handler_t handler)
 {
 	cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id());
 	cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
diff --git a/arch/m68k/platform/coldfire/reset.c b/arch/m68k/platform/coldfire/reset.c
new file mode 100644
index 0000000..933e54e
--- /dev/null
+++ b/arch/m68k/platform/coldfire/reset.c
@@ -0,0 +1,50 @@
+/*
+ * reset.c  -- common ColdFire SoC reset support
+ *
+ * (C) Copyright 2012, Greg Ungerer <gerg@uclinux.org>
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/*
+ *	There are 2 common methods amongst the ColdFure parts for reseting
+ *	the CPU. But there are couple of exceptions, the 5272 and the 547x
+ *	have something completely special to them, and we let their specific
+ *	subarch code handle them.
+ */
+
+#ifdef MCFSIM_SYPCR
+static void mcf_cpu_reset(void)
+{
+	local_irq_disable();
+	/* Set watchdog to soft reset, and enabled */
+	__raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
+	for (;;)
+		/* wait for watchdog to timeout */;
+}
+#endif
+
+#ifdef MCF_RCR
+static void mcf_cpu_reset(void)
+{
+	local_irq_disable();
+	__raw_writeb(MCF_RCR_SWRESET, MCF_RCR);
+}
+#endif
+
+static int __init mcf_setup_reset(void)
+{
+	mach_reset = mcf_cpu_reset;
+	return 0;
+}
+
+arch_initcall(mcf_setup_reset);
diff --git a/arch/m68k/platform/coldfire/sltimers.c b/arch/m68k/platform/coldfire/sltimers.c
index 54e1452..2027fc2 100644
--- a/arch/m68k/platform/coldfire/sltimers.c
+++ b/arch/m68k/platform/coldfire/sltimers.c
@@ -81,12 +81,14 @@
 static u32 mcfslt_cycles_per_jiffy;
 static u32 mcfslt_cnt;
 
+static irq_handler_t timer_interrupt;
+
 static irqreturn_t mcfslt_tick(int irq, void *dummy)
 {
 	/* Reset Slice Timer 0 */
 	__raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR));
 	mcfslt_cnt += mcfslt_cycles_per_jiffy;
-	return arch_timer_interrupt(irq, dummy);
+	return timer_interrupt(irq, dummy);
 }
 
 static struct irqaction mcfslt_timer_irq = {
@@ -121,7 +123,7 @@
 	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-void hw_timer_init(void)
+void hw_timer_init(irq_handler_t handler)
 {
 	mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ;
 	/*
@@ -136,6 +138,7 @@
 	/* initialize mcfslt_cnt knowing that slice timers count down */
 	mcfslt_cnt = mcfslt_cycles_per_jiffy;
 
+	timer_interrupt = handler;
 	setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq);
 
 	clocksource_register_hz(&mcfslt_clk, MCF_BUSCLK);
diff --git a/arch/m68k/platform/coldfire/timers.c b/arch/m68k/platform/coldfire/timers.c
index 0d90da3..ed96ce5 100644
--- a/arch/m68k/platform/coldfire/timers.c
+++ b/arch/m68k/platform/coldfire/timers.c
@@ -47,6 +47,27 @@
 static u32 mcftmr_cycles_per_jiffy;
 static u32 mcftmr_cnt;
 
+static irq_handler_t timer_interrupt;
+
+/***************************************************************************/
+
+static void init_timer_irq(void)
+{
+#ifdef MCFSIM_ICR_AUTOVEC
+	/* Timer1 is always used as system timer */
+	writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
+		MCF_MBAR + MCFSIM_TIMER1ICR);
+	mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
+
+#ifdef CONFIG_HIGHPROFILE
+	/* Timer2 is to be used as a high speed profile timer  */
+	writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
+		MCF_MBAR + MCFSIM_TIMER2ICR);
+	mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
+#endif
+#endif /* MCFSIM_ICR_AUTOVEC */
+}
+
 /***************************************************************************/
 
 static irqreturn_t mcftmr_tick(int irq, void *dummy)
@@ -55,7 +76,7 @@
 	__raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER));
 
 	mcftmr_cnt += mcftmr_cycles_per_jiffy;
-	return arch_timer_interrupt(irq, dummy);
+	return timer_interrupt(irq, dummy);
 }
 
 /***************************************************************************/
@@ -94,7 +115,7 @@
 
 /***************************************************************************/
 
-void hw_timer_init(void)
+void hw_timer_init(irq_handler_t handler)
 {
 	__raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
 	mcftmr_cycles_per_jiffy = FREQ / HZ;
@@ -110,6 +131,8 @@
 
 	clocksource_register_hz(&mcftmr_clk, FREQ);
 
+	timer_interrupt = handler;
+	init_timer_irq();
 	setup_irq(MCF_IRQ_TIMER, &mcftmr_timer_irq);
 
 #ifdef CONFIG_HIGHPROFILE
diff --git a/arch/m68k/platform/coldfire/vectors.c b/arch/m68k/platform/coldfire/vectors.c
index 3a7cc52..a4dbdec 100644
--- a/arch/m68k/platform/coldfire/vectors.c
+++ b/arch/m68k/platform/coldfire/vectors.c
@@ -33,8 +33,6 @@
 
 /***************************************************************************/
 
-extern e_vector	*_ramvec;
-
 /* Assembler routines */
 asmlinkage void buserr(void);
 asmlinkage void trap(void);
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index ad10fec..8a1ce32 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -24,11 +24,11 @@
 #include <linux/rtc.h>
 #include <linux/vt_kern.h>
 #include <linux/bcd.h>
+#include <linux/platform_device.h>
 
 #include <asm/io.h>
 #include <asm/rtc.h>
 #include <asm/bootinfo.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/setup.h>
 #include <asm/irq.h>
@@ -329,3 +329,18 @@
 	} else
 		return -EINVAL;
 }
+
+static __init int q40_add_kbd_device(void)
+{
+	struct platform_device *pdev;
+
+	if (!MACH_IS_Q40)
+		return -ENODEV;
+
+	pdev = platform_device_register_simple("q40kbd", -1, NULL, 0);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	return 0;
+}
+arch_initcall(q40_add_kbd_device);
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
index 2b88849..513f9bb 100644
--- a/arch/m68k/q40/q40ints.c
+++ b/arch/m68k/q40/q40ints.c
@@ -18,7 +18,6 @@
 #include <linux/irq.h>
 
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 
 #include <asm/q40_master.h>
diff --git a/arch/m68k/sun3/intersil.c b/arch/m68k/sun3/intersil.c
index 0116d20..94fe801 100644
--- a/arch/m68k/sun3/intersil.c
+++ b/arch/m68k/sun3/intersil.c
@@ -14,7 +14,6 @@
 #include <linux/rtc.h>
 
 #include <asm/errno.h>
-#include <asm/system.h>
 #include <asm/rtc.h>
 #include <asm/intersil.h>
 
diff --git a/arch/m68k/sun3/mmu_emu.c b/arch/m68k/sun3/mmu_emu.c
index 94f81ec..8edc510 100644
--- a/arch/m68k/sun3/mmu_emu.c
+++ b/arch/m68k/sun3/mmu_emu.c
@@ -17,7 +17,6 @@
 
 #include <asm/setup.h>
 #include <asm/traps.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
diff --git a/arch/m68k/sun3/prom/console.c b/arch/m68k/sun3/prom/console.c
index 2bcb6e4..e9236437 100644
--- a/arch/m68k/sun3/prom/console.c
+++ b/arch/m68k/sun3/prom/console.c
@@ -10,7 +10,6 @@
 #include <linux/sched.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
-#include <asm/system.h>
 #include <linux/string.h>
 
 /* Non blocking get character from console input device, returns -1
diff --git a/arch/m68k/sun3x/config.c b/arch/m68k/sun3x/config.c
index fc599fa..dd306c8 100644
--- a/arch/m68k/sun3x/config.c
+++ b/arch/m68k/sun3x/config.c
@@ -12,7 +12,6 @@
 #include <linux/console.h>
 #include <linux/init.h>
 
-#include <asm/system.h>
 #include <asm/machdep.h>
 #include <asm/irq.h>
 #include <asm/sun3xprom.h>
diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c
index 536a04a..1d0a724 100644
--- a/arch/m68k/sun3x/time.c
+++ b/arch/m68k/sun3x/time.c
@@ -15,7 +15,6 @@
 
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/sun3x.h>
 #include <asm/sun3ints.h>
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index 11060fa..ac22dc7 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -1,6 +1,7 @@
 config MICROBLAZE
 	def_bool y
 	select HAVE_MEMBLOCK
+	select HAVE_MEMBLOCK_NODE_MAP
 	select HAVE_FUNCTION_TRACER
 	select HAVE_FUNCTION_TRACE_MCOUNT_TEST
 	select HAVE_FUNCTION_GRAPH_TRACER
@@ -28,6 +29,12 @@
 config RWSEM_GENERIC_SPINLOCK
 	def_bool y
 
+config ZONE_DMA
+	def_bool y
+
+config ARCH_POPULATES_NODE_MAP
+	def_bool y
+
 config RWSEM_XCHGADD_ALGORITHM
 	bool
 
@@ -153,20 +160,18 @@
 	  The feature requires the design to define the RAM memory controller
 	  window to be twice as large as the actual physical memory.
 
-config HIGHMEM_START_BOOL
-	bool "Set high memory pool address"
-	depends on ADVANCED_OPTIONS && HIGHMEM
-	help
-	  This option allows you to set the base address of the kernel virtual
-	  area used to map high memory pages.  This can be useful in
-	  optimizing the layout of kernel virtual memory.
-
-	  Say N here unless you know what you are doing.
-
-config HIGHMEM_START
-	hex "Virtual start address of high memory pool" if HIGHMEM_START_BOOL
+config HIGHMEM
+	bool "High memory support"
 	depends on MMU
-	default "0xfe000000"
+	help
+	  The address space of Microblaze processors is only 4 Gigabytes large
+	  and it has to accommodate user address space, kernel address
+	  space as well as some memory mapped IO. That means that, if you
+	  have a large amount of physical memory and/or IO, not all of the
+	  memory can be "permanently mapped" by the kernel. The physical
+	  memory that is not permanently mapped is called "high memory".
+
+	  If unsure, say n.
 
 config LOWMEM_SIZE_BOOL
 	bool "Set maximum low memory"
@@ -255,6 +260,10 @@
 
 endchoice
 
+config KERNEL_PAD
+	hex "Kernel PAD for unpacking" if ADVANCED_OPTIONS
+	default "0x80000" if MMU
+
 endmenu
 
 source "mm/Kconfig"
diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile
index 0c796cf..fa83ea4 100644
--- a/arch/microblaze/boot/Makefile
+++ b/arch/microblaze/boot/Makefile
@@ -2,13 +2,11 @@
 # arch/microblaze/boot/Makefile
 #
 
-MKIMAGE := $(srctree)/scripts/mkuboot.sh
-
 obj-y += linked_dtb.o
 
 targets := linux.bin linux.bin.gz simpleImage.%
 
-OBJCOPYFLAGS := -O binary
+OBJCOPYFLAGS := -R .note -R .comment -R .note.gnu.build-id -O binary
 
 # Ensure system.dtb exists
 $(obj)/linked_dtb.o: $(obj)/system.dtb
@@ -35,11 +33,9 @@
 	cmd_strip = $(STRIP) -K microblaze_start -K _end -K __log_buf \
 				-K _fdt_start vmlinux -o $@
 
-quiet_cmd_uimage = UIMAGE  $@.ub
-	cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A microblaze -O linux -T kernel \
-		-C none -n 'Linux-$(KERNELRELEASE)' \
-		-a $(CONFIG_KERNEL_BASE_ADDR) -e $(CONFIG_KERNEL_BASE_ADDR) \
-		-d $@ $@.ub
+UIMAGE_IN = $@
+UIMAGE_OUT = $@.ub
+UIMAGE_LOADADDR = $(CONFIG_KERNEL_BASE_ADDR)
 
 $(obj)/simpleImage.%: vmlinux FORCE
 	$(call if_changed,cp,.unstrip)
diff --git a/arch/microblaze/include/asm/atomic.h b/arch/microblaze/include/asm/atomic.h
index 615f539..472d8bf 100644
--- a/arch/microblaze/include/asm/atomic.h
+++ b/arch/microblaze/include/asm/atomic.h
@@ -1,6 +1,7 @@
 #ifndef _ASM_MICROBLAZE_ATOMIC_H
 #define _ASM_MICROBLAZE_ATOMIC_H
 
+#include <asm/cmpxchg.h>
 #include <asm-generic/atomic.h>
 #include <asm-generic/atomic64.h>
 
diff --git a/arch/microblaze/include/asm/barrier.h b/arch/microblaze/include/asm/barrier.h
new file mode 100644
index 0000000..df5be3e8
--- /dev/null
+++ b/arch/microblaze/include/asm/barrier.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2006 Atmark Techno, Inc.
+ *
+ * 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.
+ */
+
+#ifndef _ASM_MICROBLAZE_BARRIER_H
+#define _ASM_MICROBLAZE_BARRIER_H
+
+#define nop()                  asm volatile ("nop")
+
+#define smp_read_barrier_depends()	do {} while (0)
+#define read_barrier_depends()		do {} while (0)
+
+#define mb()			barrier()
+#define rmb()			mb()
+#define wmb()			mb()
+#define set_mb(var, value)	do { var = value; mb(); } while (0)
+#define set_wmb(var, value)	do { var = value; wmb(); } while (0)
+
+#define smp_mb()		mb()
+#define smp_rmb()		rmb()
+#define smp_wmb()		wmb()
+
+#endif /* _ASM_MICROBLAZE_BARRIER_H */
diff --git a/arch/microblaze/include/asm/cmpxchg.h b/arch/microblaze/include/asm/cmpxchg.h
new file mode 100644
index 0000000..538afc0
--- /dev/null
+++ b/arch/microblaze/include/asm/cmpxchg.h
@@ -0,0 +1,42 @@
+#ifndef _ASM_MICROBLAZE_CMPXCHG_H
+#define _ASM_MICROBLAZE_CMPXCHG_H
+
+#include <linux/irqflags.h>
+
+void __bad_xchg(volatile void *ptr, int size);
+
+static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
+								int size)
+{
+	unsigned long ret;
+	unsigned long flags;
+
+	switch (size) {
+	case 1:
+		local_irq_save(flags);
+		ret = *(volatile unsigned char *)ptr;
+		*(volatile unsigned char *)ptr = x;
+		local_irq_restore(flags);
+		break;
+
+	case 4:
+		local_irq_save(flags);
+		ret = *(volatile unsigned long *)ptr;
+		*(volatile unsigned long *)ptr = x;
+		local_irq_restore(flags);
+		break;
+	default:
+		__bad_xchg(ptr, size), ret = 0;
+		break;
+	}
+
+	return ret;
+}
+
+#define xchg(ptr, x) \
+	((__typeof__(*(ptr))) __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
+
+#include <asm-generic/cmpxchg.h>
+#include <asm-generic/cmpxchg-local.h>
+
+#endif /* _ASM_MICROBLAZE_CMPXCHG_H */
diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h
index 3a3e5b8..01d2282 100644
--- a/arch/microblaze/include/asm/dma-mapping.h
+++ b/arch/microblaze/include/asm/dma-mapping.h
@@ -123,28 +123,34 @@
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
 
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-					dma_addr_t *dma_handle, gfp_t flag)
+#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+				    dma_addr_t *dma_handle, gfp_t flag,
+				    struct dma_attrs *attrs)
 {
 	struct dma_map_ops *ops = get_dma_ops(dev);
 	void *memory;
 
 	BUG_ON(!ops);
 
-	memory = ops->alloc_coherent(dev, size, dma_handle, flag);
+	memory = ops->alloc(dev, size, dma_handle, flag, attrs);
 
 	debug_dma_alloc_coherent(dev, size, *dma_handle, memory);
 	return memory;
 }
 
-static inline void dma_free_coherent(struct device *dev, size_t size,
-				     void *cpu_addr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d, s, c, h, NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+				  void *cpu_addr, dma_addr_t dma_handle,
+				  struct dma_attrs *attrs)
 {
 	struct dma_map_ops *ops = get_dma_ops(dev);
 
 	BUG_ON(!ops);
 	debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
-	ops->free_coherent(dev, size, cpu_addr, dma_handle);
+	ops->free(dev, size, cpu_addr, dma_handle, attrs);
 }
 
 static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
diff --git a/arch/microblaze/include/asm/exec.h b/arch/microblaze/include/asm/exec.h
new file mode 100644
index 0000000..e750de1
--- /dev/null
+++ b/arch/microblaze/include/asm/exec.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2006 Atmark Techno, Inc.
+ *
+ * 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.
+ */
+
+#ifndef _ASM_MICROBLAZE_EXEC_H
+#define _ASM_MICROBLAZE_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* _ASM_MICROBLAZE_EXEC_H */
diff --git a/arch/microblaze/include/asm/fixmap.h b/arch/microblaze/include/asm/fixmap.h
new file mode 100644
index 0000000..f2b312e
--- /dev/null
+++ b/arch/microblaze/include/asm/fixmap.h
@@ -0,0 +1,109 @@
+/*
+ * fixmap.h: compile-time virtual memory allocation
+ *
+ * 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.
+ *
+ * Copyright (C) 1998 Ingo Molnar
+ *
+ * Copyright 2008 Freescale Semiconductor Inc.
+ *   Port to powerpc added by Kumar Gala
+ *
+ * Copyright 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright 2011 PetaLogix Qld Pty Ltd
+ *   Port to Microblaze
+ */
+
+#ifndef _ASM_FIXMAP_H
+#define _ASM_FIXMAP_H
+
+#ifndef __ASSEMBLY__
+#include <linux/kernel.h>
+#include <asm/page.h>
+#ifdef CONFIG_HIGHMEM
+#include <linux/threads.h>
+#include <asm/kmap_types.h>
+#endif
+
+#define FIXADDR_TOP	((unsigned long)(-PAGE_SIZE))
+
+/*
+ * Here we define all the compile-time 'special' virtual
+ * addresses. The point is to have a constant address at
+ * compile time, but to set the physical address only
+ * in the boot process. We allocate these special addresses
+ * from the end of virtual memory (0xfffff000) backwards.
+ * Also this lets us do fail-safe vmalloc(), we
+ * can guarantee that these special addresses and
+ * vmalloc()-ed addresses never overlap.
+ *
+ * these 'compile-time allocated' memory buffers are
+ * fixed-size 4k pages. (or larger if used with an increment
+ * highger than 1) use fixmap_set(idx,phys) to associate
+ * physical memory with fixmap indices.
+ *
+ * TLB entries of such buffers will not be flushed across
+ * task switches.
+ */
+enum fixed_addresses {
+	FIX_HOLE,
+#ifdef CONFIG_HIGHMEM
+	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings */
+	FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * num_possible_cpus()) - 1,
+#endif
+	__end_of_fixed_addresses
+};
+
+extern void __set_fixmap(enum fixed_addresses idx,
+					phys_addr_t phys, pgprot_t flags);
+
+#define set_fixmap(idx, phys) \
+		__set_fixmap(idx, phys, PAGE_KERNEL)
+/*
+ * Some hardware wants to get fixmapped without caching.
+ */
+#define set_fixmap_nocache(idx, phys) \
+		__set_fixmap(idx, phys, PAGE_KERNEL_CI)
+
+#define clear_fixmap(idx) \
+		__set_fixmap(idx, 0, __pgprot(0))
+
+#define __FIXADDR_SIZE	(__end_of_fixed_addresses << PAGE_SHIFT)
+#define FIXADDR_START		(FIXADDR_TOP - __FIXADDR_SIZE)
+
+#define __fix_to_virt(x)	(FIXADDR_TOP - ((x) << PAGE_SHIFT))
+#define __virt_to_fix(x)	((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
+
+extern void __this_fixmap_does_not_exist(void);
+
+/*
+ * 'index to address' translation. If anyone tries to use the idx
+ * directly without tranlation, we catch the bug with a NULL-deference
+ * kernel oops. Illegal ranges of incoming indices are caught too.
+ */
+static __always_inline unsigned long fix_to_virt(const unsigned int idx)
+{
+	/*
+	 * this branch gets completely eliminated after inlining,
+	 * except when someone tries to use fixaddr indices in an
+	 * illegal way. (such as mixing up address types or using
+	 * out-of-range indices).
+	 *
+	 * If it doesn't get removed, the linker will complain
+	 * loudly with a reasonably clear error message..
+	 */
+	if (idx >= __end_of_fixed_addresses)
+		__this_fixmap_does_not_exist();
+
+	return __fix_to_virt(idx);
+}
+
+static inline unsigned long virt_to_fix(const unsigned long vaddr)
+{
+	BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
+	return __virt_to_fix(vaddr);
+}
+
+#endif /* !__ASSEMBLY__ */
+#endif
diff --git a/arch/microblaze/include/asm/futex.h b/arch/microblaze/include/asm/futex.h
index b0526d2..ff8cde1 100644
--- a/arch/microblaze/include/asm/futex.h
+++ b/arch/microblaze/include/asm/futex.h
@@ -24,7 +24,7 @@
 			.word	1b,4b,2b,4b;				\
 			.previous;"					\
 	: "=&r" (oldval), "=&r" (ret)					\
-	: "b" (uaddr), "i" (-EFAULT), "r" (oparg)			\
+	: "r" (uaddr), "i" (-EFAULT), "r" (oparg)			\
 	);								\
 })
 
diff --git a/arch/microblaze/include/asm/highmem.h b/arch/microblaze/include/asm/highmem.h
new file mode 100644
index 0000000..2446a73
--- /dev/null
+++ b/arch/microblaze/include/asm/highmem.h
@@ -0,0 +1,96 @@
+/*
+ * highmem.h: virtual kernel memory mappings for high memory
+ *
+ * Used in CONFIG_HIGHMEM systems for memory pages which
+ * are not addressable by direct kernel virtual addresses.
+ *
+ * Copyright (C) 1999 Gerhard Wichert, Siemens AG
+ *		      Gerhard.Wichert@pdb.siemens.de
+ *
+ *
+ * Redesigned the x86 32-bit VM architecture to deal with
+ * up to 16 Terabyte physical memory. With current x86 CPUs
+ * we now support up to 64 Gigabytes physical RAM.
+ *
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ */
+#ifndef _ASM_HIGHMEM_H
+#define _ASM_HIGHMEM_H
+
+#ifdef __KERNEL__
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <asm/fixmap.h>
+
+extern pte_t *kmap_pte;
+extern pgprot_t kmap_prot;
+extern pte_t *pkmap_page_table;
+
+/*
+ * Right now we initialize only a single pte table. It can be extended
+ * easily, subsequent pte tables have to be allocated in one physical
+ * chunk of RAM.
+ */
+/*
+ * We use one full pte table with 4K pages. And with 16K/64K/256K pages pte
+ * table covers enough memory (32MB/512MB/2GB resp.), so that both FIXMAP
+ * and PKMAP can be placed in a single pte table. We use 512 pages for PKMAP
+ * in case of 16K/64K/256K page sizes.
+ */
+
+#define PKMAP_ORDER	PTE_SHIFT
+#define LAST_PKMAP	(1 << PKMAP_ORDER)
+
+#define PKMAP_BASE	((FIXADDR_START - PAGE_SIZE * (LAST_PKMAP + 1)) \
+								& PMD_MASK)
+
+#define LAST_PKMAP_MASK	(LAST_PKMAP - 1)
+#define PKMAP_NR(virt)  ((virt - PKMAP_BASE) >> PAGE_SHIFT)
+#define PKMAP_ADDR(nr)  (PKMAP_BASE + ((nr) << PAGE_SHIFT))
+
+extern void *kmap_high(struct page *page);
+extern void kunmap_high(struct page *page);
+extern void *kmap_atomic_prot(struct page *page, pgprot_t prot);
+extern void __kunmap_atomic(void *kvaddr);
+
+static inline void *kmap(struct page *page)
+{
+	might_sleep();
+	if (!PageHighMem(page))
+		return page_address(page);
+	return kmap_high(page);
+}
+
+static inline void kunmap(struct page *page)
+{
+	BUG_ON(in_interrupt());
+	if (!PageHighMem(page))
+		return;
+	kunmap_high(page);
+}
+
+static inline void *__kmap_atomic(struct page *page)
+{
+	return kmap_atomic_prot(page, kmap_prot);
+}
+
+static inline struct page *kmap_atomic_to_page(void *ptr)
+{
+	unsigned long idx, vaddr = (unsigned long) ptr;
+	pte_t *pte;
+
+	if (vaddr < FIXADDR_START)
+		return virt_to_page(ptr);
+
+	idx = virt_to_fix(vaddr);
+	pte = kmap_pte - (idx - FIX_KMAP_BEGIN);
+	return pte_page(*pte);
+}
+
+#define flush_cache_kmaps()	{ flush_icache(); flush_dcache(); }
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_HIGHMEM_H */
diff --git a/arch/microblaze/include/asm/mmu.h b/arch/microblaze/include/asm/mmu.h
index 8d6a654..1f9eddd 100644
--- a/arch/microblaze/include/asm/mmu.h
+++ b/arch/microblaze/include/asm/mmu.h
@@ -56,6 +56,12 @@
 
 extern void _tlbie(unsigned long va);	/* invalidate a TLB entry */
 extern void _tlbia(void);		/* invalidate all TLB entries */
+
+/*
+ * tlb_skip size stores actual number skipped TLBs from TLB0 - every directy TLB
+ * mapping has to increase tlb_skip size.
+ */
+extern u32 tlb_skip;
 #   endif /* __ASSEMBLY__ */
 
 /*
@@ -69,6 +75,12 @@
 
 #  define MICROBLAZE_TLB_SIZE 64
 
+/* For cases when you want to skip some TLB entries */
+#  define MICROBLAZE_TLB_SKIP 0
+
+/* Use the last TLB for temporary access to LMB */
+#  define MICROBLAZE_LMB_TLB_ID 63
+
 /*
  * TLB entries are defined by a "high" tag portion and a "low" data
  * portion. The data portion is 32-bits.
diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h
index a25e6b5..287c548 100644
--- a/arch/microblaze/include/asm/page.h
+++ b/arch/microblaze/include/asm/page.h
@@ -135,8 +135,10 @@
 extern unsigned long max_pfn;
 
 extern unsigned long memory_start;
-extern unsigned long memory_end;
 extern unsigned long memory_size;
+extern unsigned long lowmem_size;
+
+extern unsigned long kernel_tlb;
 
 extern int page_is_ram(unsigned long pfn);
 
diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
index e9834b2..cb5d397 100644
--- a/arch/microblaze/include/asm/pci-bridge.h
+++ b/arch/microblaze/include/asm/pci-bridge.h
@@ -10,7 +10,6 @@
 #include <linux/pci.h>
 #include <linux/list.h>
 #include <linux/ioport.h>
-#include <asm-generic/pci-bridge.h>
 
 struct device_node;
 
diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h
index 0331376..a0da88b 100644
--- a/arch/microblaze/include/asm/pci.h
+++ b/arch/microblaze/include/asm/pci.h
@@ -94,14 +94,6 @@
  */
 #define PCI_DMA_BUS_IS_PHYS     (1)
 
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
-			struct pci_bus_region *region,
-			struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev,
-			struct resource *res,
-			struct pci_bus_region *region);
-
 static inline struct resource *pcibios_select_root(struct pci_dev *pdev,
 			struct resource *res)
 {
diff --git a/arch/microblaze/include/asm/pgtable.h b/arch/microblaze/include/asm/pgtable.h
index b2af423..3ef7b9c 100644
--- a/arch/microblaze/include/asm/pgtable.h
+++ b/arch/microblaze/include/asm/pgtable.h
@@ -94,8 +94,7 @@
 /* Start and end of the vmalloc area. */
 /* Make sure to map the vmalloc area above the pinned kernel memory area
    of 32Mb.  */
-#define VMALLOC_START	(CONFIG_KERNEL_START + \
-				max(32 * 1024 * 1024UL, memory_size))
+#define VMALLOC_START	(CONFIG_KERNEL_START + CONFIG_LOWMEM_SIZE)
 #define VMALLOC_END	ioremap_bot
 
 #endif /* __ASSEMBLY__ */
@@ -543,8 +542,6 @@
 /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
 #define kern_addr_valid(addr)	(1)
 
-#define io_remap_page_range remap_page_range
-
 /*
  * No page table caches to initialise
  */
diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h
index 7283bfb..bffb545 100644
--- a/arch/microblaze/include/asm/processor.h
+++ b/arch/microblaze/include/asm/processor.h
@@ -31,6 +31,8 @@
 /* Do necessary setup to start up a newly executed thread. */
 void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp);
 
+extern void ret_from_fork(void);
+
 # endif /* __ASSEMBLY__ */
 
 # ifndef CONFIG_MMU
@@ -125,7 +127,6 @@
 	.pgdir = swapper_pg_dir, \
 }
 
-
 /* Free all resources held by a thread. */
 extern inline void release_thread(struct task_struct *dead_task)
 {
@@ -166,6 +167,14 @@
 #  define STACK_TOP	TASK_SIZE
 #  define STACK_TOP_MAX	STACK_TOP
 
+void disable_hlt(void);
+void enable_hlt(void);
+void default_idle(void);
+
+#ifdef CONFIG_DEBUG_FS
+extern struct dentry *of_debugfs_root;
+#endif
+
 #  endif /* __ASSEMBLY__ */
 # endif /* CONFIG_MMU */
 #endif /* _ASM_MICROBLAZE_PROCESSOR_H */
diff --git a/arch/microblaze/include/asm/setup.h b/arch/microblaze/include/asm/setup.h
index 6c72ed7..0061aa1 100644
--- a/arch/microblaze/include/asm/setup.h
+++ b/arch/microblaze/include/asm/setup.h
@@ -20,6 +20,8 @@
 
 extern char cmd_line[COMMAND_LINE_SIZE];
 
+extern char *klimit;
+
 void early_printk(const char *fmt, ...);
 
 int setup_early_printk(char *opt);
@@ -39,13 +41,18 @@
 void time_init(void);
 void init_IRQ(void);
 void machine_early_init(const char *cmdline, unsigned int ram,
-			unsigned int fdt, unsigned int msr);
+		unsigned int fdt, unsigned int msr, unsigned int tlb0,
+		unsigned int tlb1);
 
 void machine_restart(char *cmd);
 void machine_shutdown(void);
 void machine_halt(void);
 void machine_power_off(void);
 
+void free_init_pages(char *what, unsigned long begin, unsigned long end);
+extern void *alloc_maybe_bootmem(size_t size, gfp_t mask);
+extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
+
 #  endif/* __KERNEL__ */
 # endif /* __ASSEMBLY__ */
 #endif /* _ASM_MICROBLAZE_SETUP_H */
diff --git a/arch/microblaze/include/asm/switch_to.h b/arch/microblaze/include/asm/switch_to.h
new file mode 100644
index 0000000..f45baa2
--- /dev/null
+++ b/arch/microblaze/include/asm/switch_to.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2006 Atmark Techno, Inc.
+ *
+ * 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.
+ */
+
+#ifndef _ASM_MICROBLAZE_SWITCH_TO_H
+#define _ASM_MICROBLAZE_SWITCH_TO_H
+
+struct task_struct;
+struct thread_info;
+
+extern struct task_struct *_switch_to(struct thread_info *prev,
+					struct thread_info *next);
+
+#define switch_to(prev, next, last)					\
+	do {								\
+		(last) = _switch_to(task_thread_info(prev),		\
+					task_thread_info(next));	\
+	} while (0)
+
+#endif /* _ASM_MICROBLAZE_SWITCH_TO_H */
diff --git a/arch/microblaze/include/asm/system.h b/arch/microblaze/include/asm/system.h
deleted file mode 100644
index 5a433cb..0000000
--- a/arch/microblaze/include/asm/system.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * 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.
- */
-
-#ifndef _ASM_MICROBLAZE_SYSTEM_H
-#define _ASM_MICROBLAZE_SYSTEM_H
-
-#include <asm/registers.h>
-#include <asm/setup.h>
-#include <asm/irqflags.h>
-#include <asm/cache.h>
-
-#include <asm-generic/cmpxchg.h>
-#include <asm-generic/cmpxchg-local.h>
-
-struct task_struct;
-struct thread_info;
-
-extern struct task_struct *_switch_to(struct thread_info *prev,
-					struct thread_info *next);
-
-#define switch_to(prev, next, last)					\
-	do {								\
-		(last) = _switch_to(task_thread_info(prev),		\
-					task_thread_info(next));	\
-	} while (0)
-
-#define smp_read_barrier_depends()	do {} while (0)
-#define read_barrier_depends()		do {} while (0)
-
-#define nop()			asm volatile ("nop")
-#define mb()			barrier()
-#define rmb()			mb()
-#define wmb()			mb()
-#define set_mb(var, value)	do { var = value; mb(); } while (0)
-#define set_wmb(var, value)	do { var = value; wmb(); } while (0)
-
-#define smp_mb()		mb()
-#define smp_rmb()		rmb()
-#define smp_wmb()		wmb()
-
-void __bad_xchg(volatile void *ptr, int size);
-
-static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
-								int size)
-{
-	unsigned long ret;
-	unsigned long flags;
-
-	switch (size) {
-	case 1:
-		local_irq_save(flags);
-		ret = *(volatile unsigned char *)ptr;
-		*(volatile unsigned char *)ptr = x;
-		local_irq_restore(flags);
-		break;
-
-	case 4:
-		local_irq_save(flags);
-		ret = *(volatile unsigned long *)ptr;
-		*(volatile unsigned long *)ptr = x;
-		local_irq_restore(flags);
-		break;
-	default:
-		__bad_xchg(ptr, size), ret = 0;
-		break;
-	}
-
-	return ret;
-}
-
-void disable_hlt(void);
-void enable_hlt(void);
-void default_idle(void);
-
-#define xchg(ptr, x) \
-	((__typeof__(*(ptr))) __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
-
-void free_init_pages(char *what, unsigned long begin, unsigned long end);
-void free_initmem(void);
-extern char *klimit;
-extern void ret_from_fork(void);
-
-extern void *alloc_maybe_bootmem(size_t size, gfp_t mask);
-extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
-
-#ifdef CONFIG_DEBUG_FS
-extern struct dentry *of_debugfs_root;
-#endif
-
-#define arch_align_stack(x) (x)
-
-#endif /* _ASM_MICROBLAZE_SYSTEM_H */
diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h
index 072b007..ef25f75 100644
--- a/arch/microblaze/include/asm/uaccess.h
+++ b/arch/microblaze/include/asm/uaccess.h
@@ -80,7 +80,7 @@
 static inline int ___range_ok(unsigned long addr, unsigned long size)
 {
 	return ((addr < memory_start) ||
-		((addr + size) > memory_end));
+		((addr + size - 1) > (memory_start + memory_size - 1)));
 }
 
 #define __range_ok(addr, size) \
diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c
index 54194b2..eab6abf 100644
--- a/arch/microblaze/kernel/cpu/cpuinfo.c
+++ b/arch/microblaze/kernel/cpu/cpuinfo.c
@@ -35,6 +35,8 @@
 	{"8.00.b", 0x13},
 	{"8.10.a", 0x14},
 	{"8.20.a", 0x15},
+	{"8.20.b", 0x16},
+	{"8.30.a", 0x17},
 	{NULL, 0},
 };
 
diff --git a/arch/microblaze/kernel/cpu/pvr.c b/arch/microblaze/kernel/cpu/pvr.c
index 488c1ed..3a749d5 100644
--- a/arch/microblaze/kernel/cpu/pvr.c
+++ b/arch/microblaze/kernel/cpu/pvr.c
@@ -12,7 +12,6 @@
 
 #include <linux/kernel.h>
 #include <linux/compiler.h>
-#include <asm/system.h>
 #include <asm/exceptions.h>
 #include <asm/pvr.h>
 
diff --git a/arch/microblaze/kernel/dma.c b/arch/microblaze/kernel/dma.c
index 65a4af4..a2bfa2c 100644
--- a/arch/microblaze/kernel/dma.c
+++ b/arch/microblaze/kernel/dma.c
@@ -33,7 +33,8 @@
 #define NOT_COHERENT_CACHE
 
 static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
-				dma_addr_t *dma_handle, gfp_t flag)
+				       dma_addr_t *dma_handle, gfp_t flag,
+				       struct dma_attrs *attrs)
 {
 #ifdef NOT_COHERENT_CACHE
 	return consistent_alloc(flag, size, dma_handle);
@@ -57,7 +58,8 @@
 }
 
 static void dma_direct_free_coherent(struct device *dev, size_t size,
-			      void *vaddr, dma_addr_t dma_handle)
+				     void *vaddr, dma_addr_t dma_handle,
+				     struct dma_attrs *attrs)
 {
 #ifdef NOT_COHERENT_CACHE
 	consistent_free(size, vaddr);
@@ -176,8 +178,8 @@
 }
 
 struct dma_map_ops dma_direct_ops = {
-	.alloc_coherent	= dma_direct_alloc_coherent,
-	.free_coherent	= dma_direct_free_coherent,
+	.alloc		= dma_direct_alloc_coherent,
+	.free		= dma_direct_free_coherent,
 	.map_sg		= dma_direct_map_sg,
 	.unmap_sg	= dma_direct_unmap_sg,
 	.dma_supported	= dma_direct_dma_supported,
diff --git a/arch/microblaze/kernel/early_printk.c b/arch/microblaze/kernel/early_printk.c
index 8356e47..aba1f9a9 100644
--- a/arch/microblaze/kernel/early_printk.c
+++ b/arch/microblaze/kernel/early_printk.c
@@ -171,10 +171,26 @@
 {
 	if (!early_console_initialized || !early_console)
 		return;
-	printk(KERN_INFO "early_printk_console remaping from 0x%x to ",
+	printk(KERN_INFO "early_printk_console remapping from 0x%x to ",
 								base_addr);
 	base_addr = (u32) ioremap(base_addr, PAGE_SIZE);
 	printk(KERN_CONT "0x%x\n", base_addr);
+
+#ifdef CONFIG_MMU
+	/*
+	 * Early console is on the top of skipped TLB entries
+	 * decrease tlb_skip size ensure that hardcoded TLB entry will be
+	 * used by generic algorithm
+	 * FIXME check if early console mapping is on the top by rereading
+	 * TLB entry and compare baseaddr
+	 *  mts  rtlbx, (tlb_skip - 1)
+	 *  nop
+	 *  mfs  rX, rtlblo
+	 *  nop
+	 *  cmp rX, orig_base_addr
+	 */
+	tlb_skip -= 1;
+#endif
 }
 
 void __init disable_early_printk(void)
diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S
index 77320b8..98b17f9 100644
--- a/arch/microblaze/kernel/head.S
+++ b/arch/microblaze/kernel/head.S
@@ -63,9 +63,7 @@
 real_start:
 #endif
 
-	mfs	r1, rmsr
-	andi	r1, r1, ~2
-	mts	rmsr, r1
+	mts	rmsr, r0
 /*
  * According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc'
  * if the msrclr instruction is not enabled. We use this to detect
@@ -73,6 +71,7 @@
  * r8 == 0 - msr instructions are implemented
  * r8 != 0 - msr instructions are not implemented
  */
+	mfs	r1, rmsr
 	msrclr	r8, 0 /* clear nothing - just read msr for test */
 	cmpu	r8, r8, r1 /* r1 must contain msr reg content */
 
@@ -96,7 +95,7 @@
 _prepare_copy_fdt:
 	or	r11, r0, r0 /* incremment */
 	ori	r4, r0, TOPHYS(_fdt_start)
-	ori	r3, r0, (0x4000 - 4)
+	ori	r3, r0, (0x8000 - 4)
 _copy_fdt:
 	lw	r12, r7, r11 /* r12 = r7 + r11 */
 	sw	r12, r4, r11 /* addr[r4 + r11] = r12 */
@@ -150,6 +149,7 @@
 _invalidate:
 	mts	rtlbx, r3
 	mts	rtlbhi, r0			/* flush: ensure V is clear   */
+	mts	rtlblo, r0
 	bgtid	r3, _invalidate		/* loop for all entries       */
 	addik	r3, r3, -1
 	/* sync */
@@ -169,6 +169,53 @@
 	addik	r3,r0, CONFIG_KERNEL_START /* Load the kernel virtual address */
 	tophys(r4,r3)			/* Load the kernel physical address */
 
+	/* start to do TLB calculation */
+	addik	r12, r0, _end
+	rsub	r12, r3, r12
+	addik	r12, r12, CONFIG_KERNEL_PAD /* that's the pad */
+
+	or r9, r0, r0 /* TLB0 = 0 */
+	or r10, r0, r0 /* TLB1 = 0 */
+
+	addik	r11, r12, -0x1000000
+	bgei	r11, GT16 /* size is greater than 16MB */
+	addik	r11, r12, -0x0800000
+	bgei	r11, GT8 /* size is greater than 8MB */
+	addik	r11, r12, -0x0400000
+	bgei	r11, GT4 /* size is greater than 4MB */
+	/* size is less than 4MB */
+	addik	r11, r12, -0x0200000
+	bgei	r11, GT2 /* size is greater than 2MB */
+	addik	r9, r0, 0x0100000 /* TLB0 must be 1MB */
+	addik	r11, r12, -0x0100000
+	bgei	r11, GT1 /* size is greater than 1MB */
+	/* TLB1 is 0 which is setup above */
+	bri tlb_end
+GT4: /* r11 contains the rest - will be either 1 or 4 */
+	ori r9, r0, 0x400000 /* TLB0 is 4MB */
+	bri TLB1
+GT16: /* TLB0 is 16MB */
+	addik	r9, r0, 0x1000000 /* means TLB0 is 16MB */
+TLB1:
+	/* must be used r2 because of substract if failed */
+	addik	r2, r11, -0x0400000
+	bgei	r2, GT20 /* size is greater than 16MB */
+	/* size is >16MB and <20MB */
+	addik	r11, r11, -0x0100000
+	bgei	r11, GT17 /* size is greater than 17MB */
+	/* kernel is >16MB and < 17MB */
+GT1:
+	addik	r10, r0, 0x0100000 /* means TLB1 is 1MB */
+	bri tlb_end
+GT2: /* TLB0 is 0 and TLB1 will be 4MB */
+GT17: /* TLB1 is 4MB - kernel size <20MB */
+	addik	r10, r0, 0x0400000 /* means TLB1 is 4MB */
+	bri tlb_end
+GT8: /* TLB0 is still zero that's why I can use only TLB1 */
+GT20: /* TLB1 is 16MB - kernel size >20MB */
+	addik	r10, r0, 0x1000000 /* means TLB1 is 16MB */
+tlb_end:
+
 	/*
 	 * Configure and load two entries into TLB slots 0 and 1.
 	 * In case we are pinning TLBs, these are reserved in by the
@@ -178,28 +225,81 @@
 	andi	r4,r4,0xfffffc00	/* Mask off the real page number */
 	ori	r4,r4,(TLB_WR | TLB_EX)	/* Set the write and execute bits */
 
+	/*
+	 * TLB0 is always used - check if is not zero (r9 stores TLB0 value)
+	 * if is use TLB1 value and clear it (r10 stores TLB1 value)
+	 */
+	bnei	r9, tlb0_not_zero
+	add	r9, r10, r0
+	add	r10, r0, r0
+tlb0_not_zero:
+
+	/* look at the code below */
+	ori	r30, r0, 0x200
+	andi	r29, r9, 0x100000
+	bneid	r29, 1f
+	addik	r30, r30, 0x80
+	andi	r29, r9, 0x400000
+	bneid	r29, 1f
+	addik	r30, r30, 0x80
+	andi	r29, r9, 0x1000000
+	bneid	r29, 1f
+	addik	r30, r30, 0x80
+1:
 	andi	r3,r3,0xfffffc00	/* Mask off the effective page number */
-	ori	r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M))
+	ori	r3,r3,(TLB_VALID)
+	or	r3, r3, r30
 
-	mts     rtlbx,r0		/* TLB slow 0 */
+	/* Load tlb_skip size value which is index to first unused TLB entry */
+	lwi	r11, r0, TOPHYS(tlb_skip)
+	mts     rtlbx,r11		/* TLB slow 0 */
 
 	mts	rtlblo,r4		/* Load the data portion of the entry */
 	mts	rtlbhi,r3		/* Load the tag portion of the entry */
 
-	addik	r4, r4, 0x01000000	/* Map next 16 M entries */
-	addik	r3, r3, 0x01000000
+	/* Increase tlb_skip size */
+	addik	r11, r11, 1
+	swi	r11, r0, TOPHYS(tlb_skip)
 
-	ori	r6,r0,1			/* TLB slot 1 */
-	mts     rtlbx,r6
+	/* TLB1 can be zeroes that's why we not setup it */
+	beqi	r10, jump_over2
+
+	/* look at the code below */
+	ori	r30, r0, 0x200
+	andi	r29, r10, 0x100000
+	bneid	r29, 1f
+	addik	r30, r30, 0x80
+	andi	r29, r10, 0x400000
+	bneid	r29, 1f
+	addik	r30, r30, 0x80
+	andi	r29, r10, 0x1000000
+	bneid	r29, 1f
+	addik	r30, r30, 0x80
+1:
+	addk	r4, r4, r9	/* previous addr + TLB0 size */
+	addk	r3, r3, r9
+
+	andi	r3,r3,0xfffffc00	/* Mask off the effective page number */
+	ori	r3,r3,(TLB_VALID)
+	or	r3, r3, r30
+
+	lwi	r11, r0, TOPHYS(tlb_skip)
+	mts     rtlbx, r11		/* r11 is used from TLB0 */
 
 	mts	rtlblo,r4		/* Load the data portion of the entry */
 	mts	rtlbhi,r3		/* Load the tag portion of the entry */
 
+	/* Increase tlb_skip size */
+	addik	r11, r11, 1
+	swi	r11, r0, TOPHYS(tlb_skip)
+
+jump_over2:
 	/*
 	 * Load a TLB entry for LMB, since we need access to
 	 * the exception vectors, using a 4k real==virtual mapping.
 	 */
-	ori	r6,r0,3			/* TLB slot 3 */
+	/* Use temporary TLB_ID for LMB - clear this temporary mapping later */
+	ori	r6, r0, MICROBLAZE_LMB_TLB_ID
 	mts     rtlbx,r6
 
 	ori	r4,r0,(TLB_WR | TLB_EX)
@@ -238,8 +338,8 @@
 	 * Please see $(ARCH)/mach-$(SUBARCH)/setup.c for
 	 * the function.
 	 */
-	addik	r9, r0, machine_early_init
-	brald	r15, r9
+	addik	r11, r0, machine_early_init
+	brald	r15, r11
 	nop
 
 #ifndef CONFIG_MMU
@@ -268,8 +368,7 @@
 
 	/* Load up the kernel context */
 kernel_load_context:
-	# Keep entry 0 and 1 valid. Entry 3 mapped to LMB can go away.
-	ori	r5,r0,3
+	ori	r5, r0, MICROBLAZE_LMB_TLB_ID
 	mts     rtlbx,r5
 	nop
 	mts	rtlbhi,r0
diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S
index e62be83..aa510f4 100644
--- a/arch/microblaze/kernel/hw_exception_handler.S
+++ b/arch/microblaze/kernel/hw_exception_handler.S
@@ -820,19 +820,26 @@
  *	Upon exit, we reload everything and RFI.
  * A common place to load the TLB.
  */
+.section .data
+.align 4
+.global tlb_skip
+	tlb_skip:
+		.long	MICROBLAZE_TLB_SKIP
 	tlb_index:
-		.long	1 /* MS: storing last used tlb index */
+		/* MS: storing last used tlb index */
+		.long	MICROBLAZE_TLB_SIZE/2
+.previous
 	finish_tlb_load:
 		/* MS: load the last used TLB index. */
 		lwi	r5, r0, TOPHYS(tlb_index)
 		addik	r5, r5, 1 /* MS: inc tlb_index -> use next one */
 
 /* MS: FIXME this is potential fault, because this is mask not count */
-		andi	r5, r5, (MICROBLAZE_TLB_SIZE-1)
+		andi	r5, r5, MICROBLAZE_TLB_SIZE - 1
 		ori	r6, r0, 1
 		cmp	r31, r5, r6
 		blti	r31, ex12
-		addik	r5, r6, 1
+		lwi	r5, r0, TOPHYS(tlb_skip)
 	ex12:
 		/* MS: save back current TLB index */
 		swi	r5, r0, TOPHYS(tlb_index)
diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c
index ad12067..6c54d4d 100644
--- a/arch/microblaze/kernel/intc.c
+++ b/arch/microblaze/kernel/intc.c
@@ -151,8 +151,8 @@
 #ifdef CONFIG_SELFMOD_INTC
 	selfmod_function((int *) arr_func, intc_baseaddr);
 #endif
-	printk(KERN_INFO "XPS intc #0 at 0x%08x, num_irq=%d, edge=0x%x\n",
-		intc_baseaddr, nr_irq, intr_mask);
+	printk(KERN_INFO "%s #0 at 0x%08x, num_irq=%d, edge=0x%x\n",
+		intc->name, intc_baseaddr, nr_irq, intr_mask);
 
 	/*
 	 * Disable all external interrupts until they are
diff --git a/arch/microblaze/kernel/microblaze_ksyms.c b/arch/microblaze/kernel/microblaze_ksyms.c
index 49faeb4..bb4907c 100644
--- a/arch/microblaze/kernel/microblaze_ksyms.c
+++ b/arch/microblaze/kernel/microblaze_ksyms.c
@@ -18,7 +18,6 @@
 #include <asm/cacheflush.h>
 #include <linux/io.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <linux/ftrace.h>
 #include <linux/uaccess.h>
 
diff --git a/arch/microblaze/kernel/misc.S b/arch/microblaze/kernel/misc.S
index 206da3d..1dafdde 100644
--- a/arch/microblaze/kernel/misc.S
+++ b/arch/microblaze/kernel/misc.S
@@ -29,16 +29,16 @@
 .type  _tlbia, @function
 .align 4;
 _tlbia:
-	addik	r12, r0, MICROBLAZE_TLB_SIZE - 1 /* flush all entries (63 - 3) */
+	lwi	r12, r0, tlb_skip;
 	/* isync */
 _tlbia_1:
 	mts	rtlbx, r12
 	nop
 	mts	rtlbhi, r0 /* flush: ensure V is clear */
 	nop
-	addik	r11, r12, -2
+	rsubi	r11, r12, MICROBLAZE_TLB_SIZE - 1
 	bneid	r11, _tlbia_1 /* loop for all entries */
-	addik	r12, r12, -1
+	addik	r12, r12, 1
 	/* sync */
 	rtsd	r15, 8
 	nop
@@ -75,7 +75,7 @@
 	 * Load a TLB entry for the UART, so that microblaze_progress() can use
 	 * the UARTs nice and early.  We use a 4k real==virtual mapping.
 	 */
-	ori	r4, r0, MICROBLAZE_TLB_SIZE - 1
+	lwi	r4, r0, tlb_skip
 	mts	rtlbx, r4 /* TLB slot 63 */
 
 	or	r4,r5,r0
@@ -89,6 +89,11 @@
 	nop
 	mts	rtlbhi,r5 /* Load the tag portion of the entry */
 	nop
+
+	lwi	r5, r0, tlb_skip
+	addik	r5, r5, 1
+	swi	r5, r0, tlb_skip
+
 	rtsd	r15, 8
 	nop
 
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
index 9155f7d..883b927 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -13,7 +13,6 @@
 #include <linux/pm.h>
 #include <linux/tick.h>
 #include <linux/bitops.h>
-#include <asm/system.h>
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h> /* for USER_DS macros */
 #include <asm/cacheflush.h>
diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c
index 80d314e..4a764cc 100644
--- a/arch/microblaze/kernel/prom.c
+++ b/arch/microblaze/kernel/prom.c
@@ -36,7 +36,6 @@
 #include <asm/processor.h>
 #include <asm/irq.h>
 #include <linux/io.h>
-#include <asm/system.h>
 #include <asm/mmu.h>
 #include <asm/pgtable.h>
 #include <asm/sections.h>
diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c
index 70e6d0b..16d8dfd 100644
--- a/arch/microblaze/kernel/setup.c
+++ b/arch/microblaze/kernel/setup.c
@@ -30,7 +30,6 @@
 #include <asm/entry.h>
 #include <asm/cpuinfo.h>
 
-#include <asm/system.h>
 #include <asm/prom.h>
 #include <asm/pgtable.h>
 
@@ -95,8 +94,11 @@
 }
 #endif	/* CONFIG_MTD_UCLINUX_EBSS */
 
+unsigned long kernel_tlb;
+
 void __init machine_early_init(const char *cmdline, unsigned int ram,
-		unsigned int fdt, unsigned int msr)
+		unsigned int fdt, unsigned int msr, unsigned int tlb0,
+		unsigned int tlb1)
 {
 	unsigned long *src, *dst;
 	unsigned int offset = 0;
@@ -143,6 +145,12 @@
 	setup_early_printk(NULL);
 #endif
 
+	/* setup kernel_tlb after BSS cleaning
+	 * Maybe worth to move to asm code */
+	kernel_tlb = tlb0 + tlb1;
+	/* printk("TLB1 0x%08x, TLB0 0x%08x, tlb 0x%x\n", tlb0,
+							tlb1, kernel_tlb); */
+
 	printk("Ramdisk addr 0x%08x, ", ram);
 	if (fdt)
 		printk("FDT at 0x%08x\n", fdt);
@@ -197,6 +205,21 @@
 	return of_debugfs_root == NULL;
 }
 arch_initcall(microblaze_debugfs_init);
+
+# ifdef CONFIG_MMU
+static int __init debugfs_tlb(void)
+{
+	struct dentry *d;
+
+	if (!of_debugfs_root)
+		return -ENODEV;
+
+	d = debugfs_create_u32("tlb_skip", S_IRUGO, of_debugfs_root, &tlb_skip);
+	if (!d)
+		return -ENOMEM;
+}
+device_initcall(debugfs_tlb);
+# endif
 #endif
 
 static int dflt_bus_notify(struct notifier_block *nb,
diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c
index 3cb0bf6..522defa 100644
--- a/arch/microblaze/kernel/timer.c
+++ b/arch/microblaze/kernel/timer.c
@@ -27,7 +27,6 @@
 #include <asm/setup.h>
 #include <asm/prom.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <linux/cnt32_to_63.h>
 
 #ifdef CONFIG_SELFMOD_TIMER
@@ -79,7 +78,7 @@
 	 * !PWMA - disable pwm
 	 * TINT - clear interrupt status
 	 * ENT- enable timer itself
-	 * EINT - enable interrupt
+	 * ENIT - enable interrupt
 	 * !LOAD - clear the bit to let go
 	 * ARHT - auto reload
 	 * !CAPT - no external trigger
@@ -274,8 +273,8 @@
 #ifdef CONFIG_SELFMOD_TIMER
 	selfmod_function((int *) arr_func, timer_baseaddr);
 #endif
-	printk(KERN_INFO "XPS timer #0 at 0x%08x, irq=%d\n",
-		timer_baseaddr, irq);
+	printk(KERN_INFO "%s #0 at 0x%08x, irq=%d\n",
+		timer->name, timer_baseaddr, irq);
 
 	/* If there is clock-frequency property than use it */
 	prop = of_get_property(timer, "clock-frequency", NULL);
diff --git a/arch/microblaze/kernel/traps.c b/arch/microblaze/kernel/traps.c
index ba034d4..5541ac5 100644
--- a/arch/microblaze/kernel/traps.c
+++ b/arch/microblaze/kernel/traps.c
@@ -15,7 +15,6 @@
 #include <linux/debug_locks.h>
 
 #include <asm/exceptions.h>
-#include <asm/system.h>
 #include <asm/unwind.h>
 
 void trap_init(void)
diff --git a/arch/microblaze/kernel/unwind.c b/arch/microblaze/kernel/unwind.c
index 9781a52..6be4ae3 100644
--- a/arch/microblaze/kernel/unwind.c
+++ b/arch/microblaze/kernel/unwind.c
@@ -24,6 +24,7 @@
 #include <asm/sections.h>
 #include <asm/exceptions.h>
 #include <asm/unwind.h>
+#include <asm/switch_to.h>
 
 struct stack_trace;
 
diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S
index ac0e1a5..109e9d8 100644
--- a/arch/microblaze/kernel/vmlinux.lds.S
+++ b/arch/microblaze/kernel/vmlinux.lds.S
@@ -44,7 +44,7 @@
 	__fdt_blob : AT(ADDR(__fdt_blob) - LOAD_OFFSET) {
 		_fdt_start = . ;		/* place for fdt blob */
 		*(__fdt_blob) ;			/* Any link-placed DTB */
-	        . = _fdt_start + 0x4000;	/* Pad up to 16kbyte */
+	        . = _fdt_start + 0x8000;	/* Pad up to 32kbyte */
 		_fdt_end = . ;
 	}
 
diff --git a/arch/microblaze/lib/memcpy.c b/arch/microblaze/lib/memcpy.c
index 52746e7..fe9c53f 100644
--- a/arch/microblaze/lib/memcpy.c
+++ b/arch/microblaze/lib/memcpy.c
@@ -30,7 +30,6 @@
 #include <linux/module.h>
 
 #include <linux/string.h>
-#include <asm/system.h>
 
 #ifdef __HAVE_ARCH_MEMCPY
 #ifndef CONFIG_OPT_LIB_FUNCTION
diff --git a/arch/microblaze/lib/uaccess_old.S b/arch/microblaze/lib/uaccess_old.S
index f037266..f085995 100644
--- a/arch/microblaze/lib/uaccess_old.S
+++ b/arch/microblaze/lib/uaccess_old.S
@@ -122,22 +122,22 @@
 15:	swi	r24, r5, 0x0018 + offset;	\
 16:	swi	r25, r5, 0x001C + offset;	\
 	.section __ex_table,"a";		\
-	.word	1b, 0f;				\
-	.word	2b, 0f;				\
-	.word	3b, 0f;				\
-	.word	4b, 0f;				\
-	.word	5b, 0f;				\
-	.word	6b, 0f;				\
-	.word	7b, 0f;				\
-	.word	8b, 0f;				\
-	.word	9b, 0f;				\
-	.word	10b, 0f;			\
-	.word	11b, 0f;			\
-	.word	12b, 0f;			\
-	.word	13b, 0f;			\
-	.word	14b, 0f;			\
-	.word	15b, 0f;			\
-	.word	16b, 0f;			\
+	.word	1b, 33f;			\
+	.word	2b, 33f;			\
+	.word	3b, 33f;			\
+	.word	4b, 33f;			\
+	.word	5b, 33f;			\
+	.word	6b, 33f;			\
+	.word	7b, 33f;			\
+	.word	8b, 33f;			\
+	.word	9b, 33f;			\
+	.word	10b, 33f;			\
+	.word	11b, 33f;			\
+	.word	12b, 33f;			\
+	.word	13b, 33f;			\
+	.word	14b, 33f;			\
+	.word	15b, 33f;			\
+	.word	16b, 33f;			\
 	.text
 
 #define COPY_80(offset)	\
@@ -190,14 +190,17 @@
 
 .align 4 /* Alignment is important to keep icache happy */
 page:	/* Create room on stack and save registers for storign values */
-	addik   r1, r1, -32
-	swi	r19, r1, 4
-	swi	r20, r1, 8
-	swi	r21, r1, 12
-	swi	r22, r1, 16
-	swi	r23, r1, 20
-	swi	r24, r1, 24
-	swi	r25, r1, 28
+	addik   r1, r1, -40
+	swi	r5, r1, 0
+	swi	r6, r1, 4
+	swi	r7, r1, 8
+	swi	r19, r1, 12
+	swi	r20, r1, 16
+	swi	r21, r1, 20
+	swi	r22, r1, 24
+	swi	r23, r1, 28
+	swi	r24, r1, 32
+	swi	r25, r1, 36
 loop:	/* r4, r19, r20, r21, r22, r23, r24, r25 are used for storing values */
 	/* Loop unrolling to get performance boost */
 	COPY_80(0x000);
@@ -205,21 +208,44 @@
 	COPY_80(0x100);
 	COPY_80(0x180);
 	/* copy loop */
-	addik	r6, r6, 0x200
-	addik	r7, r7, -0x200
-	bneid	r7, loop
-	addik	r5, r5, 0x200
+	addik   r6, r6, 0x200
+	addik   r7, r7, -0x200
+	bneid   r7, loop
+	addik   r5, r5, 0x200
+
 	/* Restore register content */
-	lwi	r19, r1, 4
-	lwi	r20, r1, 8
-	lwi	r21, r1, 12
-	lwi	r22, r1, 16
-	lwi	r23, r1, 20
-	lwi	r24, r1, 24
-	lwi	r25, r1, 28
-	addik   r1, r1, 32
+	lwi	r5, r1, 0
+	lwi	r6, r1, 4
+	lwi	r7, r1, 8
+	lwi	r19, r1, 12
+	lwi	r20, r1, 16
+	lwi	r21, r1, 20
+	lwi	r22, r1, 24
+	lwi	r23, r1, 28
+	lwi	r24, r1, 32
+	lwi	r25, r1, 36
+	addik   r1, r1, 40
 	/* return back */
+	addik	r3, r0, 0
+	rtsd	r15, 8
+	nop
+
+/* Fault case - return temp count */
+33:
 	addik	r3, r7, 0
+	/* Restore register content */
+	lwi	r5, r1, 0
+	lwi	r6, r1, 4
+	lwi	r7, r1, 8
+	lwi	r19, r1, 12
+	lwi	r20, r1, 16
+	lwi	r21, r1, 20
+	lwi	r22, r1, 24
+	lwi	r23, r1, 28
+	lwi	r24, r1, 32
+	lwi	r25, r1, 36
+	addik   r1, r1, 40
+	/* return back */
 	rtsd	r15, 8
 	nop
 
diff --git a/arch/microblaze/mm/Makefile b/arch/microblaze/mm/Makefile
index 09c49ed..7313bd8 100644
--- a/arch/microblaze/mm/Makefile
+++ b/arch/microblaze/mm/Makefile
@@ -5,3 +5,4 @@
 obj-y := consistent.o init.o
 
 obj-$(CONFIG_MMU) += pgtable.o mmu_context.o fault.o
+obj-$(CONFIG_HIGHMEM) += highmem.o
diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c
index ae97d2c..c38a265 100644
--- a/arch/microblaze/mm/fault.c
+++ b/arch/microblaze/mm/fault.c
@@ -33,7 +33,6 @@
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
 #include <asm/mmu_context.h>
-#include <asm/system.h>
 #include <linux/uaccess.h>
 #include <asm/exceptions.h>
 
diff --git a/arch/microblaze/mm/highmem.c b/arch/microblaze/mm/highmem.c
new file mode 100644
index 0000000..7d78838
--- /dev/null
+++ b/arch/microblaze/mm/highmem.c
@@ -0,0 +1,88 @@
+/*
+ * highmem.c: virtual kernel memory mappings for high memory
+ *
+ * PowerPC version, stolen from the i386 version.
+ *
+ * Used in CONFIG_HIGHMEM systems for memory pages which
+ * are not addressable by direct kernel virtual addresses.
+ *
+ * Copyright (C) 1999 Gerhard Wichert, Siemens AG
+ *		      Gerhard.Wichert@pdb.siemens.de
+ *
+ *
+ * Redesigned the x86 32-bit VM architecture to deal with
+ * up to 16 Terrabyte physical memory. With current x86 CPUs
+ * we now support up to 64 Gigabytes physical RAM.
+ *
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ *
+ * Reworked for PowerPC by various contributors. Moved from
+ * highmem.h by Benjamin Herrenschmidt (c) 2009 IBM Corp.
+ */
+
+#include <linux/highmem.h>
+#include <linux/module.h>
+
+/*
+ * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap
+ * gives a more generic (and caching) interface. But kmap_atomic can
+ * be used in IRQ contexts, so in some (very limited) cases we need
+ * it.
+ */
+#include <asm/tlbflush.h>
+
+void *kmap_atomic_prot(struct page *page, pgprot_t prot)
+{
+
+	unsigned long vaddr;
+	int idx, type;
+
+	/* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
+	pagefault_disable();
+	if (!PageHighMem(page))
+		return page_address(page);
+
+
+	type = kmap_atomic_idx_push();
+	idx = type + KM_TYPE_NR*smp_processor_id();
+	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+#ifdef CONFIG_DEBUG_HIGHMEM
+	BUG_ON(!pte_none(*(kmap_pte-idx)));
+#endif
+	set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot));
+	local_flush_tlb_page(NULL, vaddr);
+
+	return (void *) vaddr;
+}
+EXPORT_SYMBOL(kmap_atomic_prot);
+
+void __kunmap_atomic(void *kvaddr)
+{
+	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
+	int type;
+
+	if (vaddr < __fix_to_virt(FIX_KMAP_END)) {
+		pagefault_enable();
+		return;
+	}
+
+	type = kmap_atomic_idx();
+#ifdef CONFIG_DEBUG_HIGHMEM
+	{
+		unsigned int idx;
+
+		idx = type + KM_TYPE_NR * smp_processor_id();
+		BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+
+		/*
+		 * force other mappings to Oops if they'll try to access
+		 * this pte without first remap it
+		 */
+		pte_clear(&init_mm, vaddr, kmap_pte-idx);
+		local_flush_tlb_page(NULL, vaddr);
+	}
+#endif
+	kmap_atomic_idx_pop();
+	pagefault_enable();
+}
+EXPORT_SYMBOL(__kunmap_atomic);
diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c
index 565d193..ce80823 100644
--- a/arch/microblaze/mm/init.c
+++ b/arch/microblaze/mm/init.c
@@ -24,6 +24,7 @@
 #include <asm/pgalloc.h>
 #include <asm/sections.h>
 #include <asm/tlb.h>
+#include <asm/fixmap.h>
 
 /* Use for MMU and noMMU because of PCI generic code */
 int mem_init_done;
@@ -44,9 +45,56 @@
  */
 unsigned long memory_start;
 EXPORT_SYMBOL(memory_start);
-unsigned long memory_end; /* due to mm/nommu.c */
 unsigned long memory_size;
 EXPORT_SYMBOL(memory_size);
+unsigned long lowmem_size;
+
+#ifdef CONFIG_HIGHMEM
+pte_t *kmap_pte;
+EXPORT_SYMBOL(kmap_pte);
+pgprot_t kmap_prot;
+EXPORT_SYMBOL(kmap_prot);
+
+static inline pte_t *virt_to_kpte(unsigned long vaddr)
+{
+	return pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr),
+			vaddr), vaddr);
+}
+
+static void __init highmem_init(void)
+{
+	pr_debug("%x\n", (u32)PKMAP_BASE);
+	map_page(PKMAP_BASE, 0, 0);	/* XXX gross */
+	pkmap_page_table = virt_to_kpte(PKMAP_BASE);
+
+	kmap_pte = virt_to_kpte(__fix_to_virt(FIX_KMAP_BEGIN));
+	kmap_prot = PAGE_KERNEL;
+}
+
+static unsigned long highmem_setup(void)
+{
+	unsigned long pfn;
+	unsigned long reservedpages = 0;
+
+	for (pfn = max_low_pfn; pfn < max_pfn; ++pfn) {
+		struct page *page = pfn_to_page(pfn);
+
+		/* FIXME not sure about */
+		if (memblock_is_reserved(pfn << PAGE_SHIFT))
+			continue;
+		ClearPageReserved(page);
+		init_page_count(page);
+		__free_page(page);
+		totalhigh_pages++;
+		reservedpages++;
+	}
+	totalram_pages += totalhigh_pages;
+	printk(KERN_INFO "High memory: %luk\n",
+					totalhigh_pages << (PAGE_SHIFT-10));
+
+	return reservedpages;
+}
+#endif /* CONFIG_HIGHMEM */
 
 /*
  * paging_init() sets up the page tables - in fact we've already done this.
@@ -54,17 +102,28 @@
 static void __init paging_init(void)
 {
 	unsigned long zones_size[MAX_NR_ZONES];
+#ifdef CONFIG_MMU
+	int idx;
+
+	/* Setup fixmaps */
+	for (idx = 0; idx < __end_of_fixed_addresses; idx++)
+		clear_fixmap(idx);
+#endif
 
 	/* Clean every zones */
 	memset(zones_size, 0, sizeof(zones_size));
 
-	/*
-	 * old: we can DMA to/from any address.put all page into ZONE_DMA
-	 * We use only ZONE_NORMAL
-	 */
-	zones_size[ZONE_NORMAL] = max_mapnr;
+#ifdef CONFIG_HIGHMEM
+	highmem_init();
 
-	free_area_init(zones_size);
+	zones_size[ZONE_DMA] = max_low_pfn;
+	zones_size[ZONE_HIGHMEM] = max_pfn;
+#else
+	zones_size[ZONE_DMA] = max_pfn;
+#endif
+
+	/* We don't have holes in memory map */
+	free_area_init_nodes(zones_size);
 }
 
 void __init setup_memory(void)
@@ -78,32 +137,31 @@
 	/* Find main memory where is the kernel */
 	for_each_memblock(memory, reg) {
 		memory_start = (u32)reg->base;
-		memory_end = (u32) reg->base + reg->size;
+		lowmem_size = reg->size;
 		if ((memory_start <= (u32)_text) &&
-					((u32)_text <= memory_end)) {
-			memory_size = memory_end - memory_start;
+			((u32)_text <= (memory_start + lowmem_size - 1))) {
+			memory_size = lowmem_size;
 			PAGE_OFFSET = memory_start;
-			printk(KERN_INFO "%s: Main mem: 0x%x-0x%x, "
+			printk(KERN_INFO "%s: Main mem: 0x%x, "
 				"size 0x%08x\n", __func__, (u32) memory_start,
-					(u32) memory_end, (u32) memory_size);
+					(u32) memory_size);
 			break;
 		}
 	}
 
-	if (!memory_start || !memory_end) {
-		panic("%s: Missing memory setting 0x%08x-0x%08x\n",
-			__func__, (u32) memory_start, (u32) memory_end);
+	if (!memory_start || !memory_size) {
+		panic("%s: Missing memory setting 0x%08x, size=0x%08x\n",
+			__func__, (u32) memory_start, (u32) memory_size);
 	}
 
 	/* reservation of region where is the kernel */
 	kernel_align_start = PAGE_DOWN((u32)_text);
 	/* ALIGN can be remove because _end in vmlinux.lds.S is align */
 	kernel_align_size = PAGE_UP((u32)klimit) - kernel_align_start;
-	memblock_reserve(kernel_align_start, kernel_align_size);
-	printk(KERN_INFO "%s: kernel addr=0x%08x-0x%08x size=0x%08x\n",
+	printk(KERN_INFO "%s: kernel addr:0x%08x-0x%08x size=0x%08x\n",
 		__func__, kernel_align_start, kernel_align_start
 			+ kernel_align_size, kernel_align_size);
-
+	memblock_reserve(kernel_align_start, kernel_align_size);
 #endif
 	/*
 	 * Kernel:
@@ -120,11 +178,13 @@
 	min_low_pfn = memory_start >> PAGE_SHIFT; /* minimum for allocation */
 	/* RAM is assumed contiguous */
 	num_physpages = max_mapnr = memory_size >> PAGE_SHIFT;
-	max_pfn = max_low_pfn = memory_end >> PAGE_SHIFT;
+	max_low_pfn = ((u64)memory_start + (u64)lowmem_size) >> PAGE_SHIFT;
+	max_pfn = ((u64)memory_start + (u64)memory_size) >> PAGE_SHIFT;
 
 	printk(KERN_INFO "%s: max_mapnr: %#lx\n", __func__, max_mapnr);
 	printk(KERN_INFO "%s: min_low_pfn: %#lx\n", __func__, min_low_pfn);
 	printk(KERN_INFO "%s: max_low_pfn: %#lx\n", __func__, max_low_pfn);
+	printk(KERN_INFO "%s: max_pfn: %#lx\n", __func__, max_pfn);
 
 	/*
 	 * Find an area to use for the bootmem bitmap.
@@ -137,15 +197,39 @@
 		PFN_UP(TOPHYS((u32)klimit)), min_low_pfn, max_low_pfn);
 	memblock_reserve(PFN_UP(TOPHYS((u32)klimit)) << PAGE_SHIFT, map_size);
 
+	/* Add active regions with valid PFNs */
+	for_each_memblock(memory, reg) {
+		unsigned long start_pfn, end_pfn;
+
+		start_pfn = memblock_region_memory_base_pfn(reg);
+		end_pfn = memblock_region_memory_end_pfn(reg);
+		memblock_set_node(start_pfn << PAGE_SHIFT,
+					(end_pfn - start_pfn) << PAGE_SHIFT, 0);
+	}
+
 	/* free bootmem is whole main memory */
-	free_bootmem(memory_start, memory_size);
+	free_bootmem_with_active_regions(0, max_low_pfn);
 
 	/* reserve allocate blocks */
 	for_each_memblock(reserved, reg) {
-		pr_debug("reserved - 0x%08x-0x%08x\n",
-			 (u32) reg->base, (u32) reg->size);
-		reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
+		unsigned long top = reg->base + reg->size - 1;
+
+		pr_debug("reserved - 0x%08x-0x%08x, %lx, %lx\n",
+			 (u32) reg->base, (u32) reg->size, top,
+						memory_start + lowmem_size - 1);
+
+		if (top <= (memory_start + lowmem_size - 1)) {
+			reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
+		} else if (reg->base < (memory_start + lowmem_size - 1)) {
+			unsigned long trunc_size = memory_start + lowmem_size -
+								reg->base;
+			reserve_bootmem(reg->base, trunc_size, BOOTMEM_DEFAULT);
+		}
 	}
+
+	/* XXX need to clip this if using highmem? */
+	sparse_memory_present_with_active_regions(0);
+
 #ifdef CONFIG_MMU
 	init_bootmem_done = 1;
 #endif
@@ -190,13 +274,58 @@
 
 void __init mem_init(void)
 {
-	high_memory = (void *)__va(memory_end);
+	pg_data_t *pgdat;
+	unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;
+
+	high_memory = (void *)__va(memory_start + lowmem_size - 1);
+
 	/* this will put all memory onto the freelists */
 	totalram_pages += free_all_bootmem();
 
-	printk(KERN_INFO "Memory: %luk/%luk available\n",
-	       nr_free_pages() << (PAGE_SHIFT-10),
-	       num_physpages << (PAGE_SHIFT-10));
+	for_each_online_pgdat(pgdat) {
+		unsigned long i;
+		struct page *page;
+
+		for (i = 0; i < pgdat->node_spanned_pages; i++) {
+			if (!pfn_valid(pgdat->node_start_pfn + i))
+				continue;
+			page = pgdat_page_nr(pgdat, i);
+			if (PageReserved(page))
+				reservedpages++;
+		}
+	}
+
+#ifdef CONFIG_HIGHMEM
+	reservedpages -= highmem_setup();
+#endif
+
+	codesize = (unsigned long)&_sdata - (unsigned long)&_stext;
+	datasize = (unsigned long)&_edata - (unsigned long)&_sdata;
+	initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin;
+	bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start;
+
+	pr_info("Memory: %luk/%luk available (%luk kernel code, "
+		"%luk reserved, %luk data, %luk bss, %luk init)\n",
+		nr_free_pages() << (PAGE_SHIFT-10),
+		num_physpages << (PAGE_SHIFT-10),
+		codesize >> 10,
+		reservedpages << (PAGE_SHIFT-10),
+		datasize >> 10,
+		bsssize >> 10,
+		initsize >> 10);
+
+#ifdef CONFIG_MMU
+	pr_info("Kernel virtual memory layout:\n");
+	pr_info("  * 0x%08lx..0x%08lx  : fixmap\n", FIXADDR_START, FIXADDR_TOP);
+#ifdef CONFIG_HIGHMEM
+	pr_info("  * 0x%08lx..0x%08lx  : highmem PTEs\n",
+		PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP));
+#endif /* CONFIG_HIGHMEM */
+	pr_info("  * 0x%08lx..0x%08lx  : early ioremap\n",
+		ioremap_bot, ioremap_base);
+	pr_info("  * 0x%08lx..0x%08lx  : vmalloc & ioremap\n",
+		(unsigned long)VMALLOC_START, VMALLOC_END);
+#endif
 	mem_init_done = 1;
 }
 
@@ -226,7 +355,6 @@
 		maxmem = memparse(p, &p);
 		if (maxmem && memory_size > maxmem) {
 			memory_size = maxmem;
-			memory_end = memory_start + memory_size;
 			memblock.memory.regions[0].size = memory_size;
 		}
 	}
@@ -270,15 +398,26 @@
 		machine_restart(NULL);
 	}
 
-	if ((u32) memblock.memory.regions[0].size < 0x1000000) {
-		printk(KERN_EMERG "Memory must be greater than 16MB\n");
+	if ((u32) memblock.memory.regions[0].size < 0x400000) {
+		printk(KERN_EMERG "Memory must be greater than 4MB\n");
 		machine_restart(NULL);
 	}
+
+	if ((u32) memblock.memory.regions[0].size < kernel_tlb) {
+		printk(KERN_EMERG "Kernel size is greater than memory node\n");
+		machine_restart(NULL);
+	}
+
 	/* Find main memory where the kernel is */
 	memory_start = (u32) memblock.memory.regions[0].base;
-	memory_end = (u32) memblock.memory.regions[0].base +
-				(u32) memblock.memory.regions[0].size;
-	memory_size = memory_end - memory_start;
+	lowmem_size = memory_size = (u32) memblock.memory.regions[0].size;
+
+	if (lowmem_size > CONFIG_LOWMEM_SIZE) {
+		lowmem_size = CONFIG_LOWMEM_SIZE;
+#ifndef CONFIG_HIGHMEM
+		memory_size = lowmem_size;
+#endif
+	}
 
 	mm_cmdline_setup(); /* FIXME parse args from command line - not used */
 
@@ -305,15 +444,20 @@
 	/* Map in all of RAM starting at CONFIG_KERNEL_START */
 	mapin_ram();
 
-#ifdef CONFIG_HIGHMEM_START_BOOL
-	ioremap_base = CONFIG_HIGHMEM_START;
+	/* Extend vmalloc and ioremap area as big as possible */
+#ifdef CONFIG_HIGHMEM
+	ioremap_base = ioremap_bot = PKMAP_BASE;
 #else
-	ioremap_base = 0xfe000000UL;	/* for now, could be 0xfffff000 */
-#endif /* CONFIG_HIGHMEM_START_BOOL */
-	ioremap_bot = ioremap_base;
+	ioremap_base = ioremap_bot = FIXADDR_START;
+#endif
 
 	/* Initialize the context management stuff */
 	mmu_context_init();
+
+	/* Shortly after that, the entire linear mapping will be available */
+	/* This will also cause that unflatten device tree will be allocated
+	 * inside 768MB limit */
+	memblock_set_current_limit(memory_start + lowmem_size - 1);
 }
 
 /* This is only called until mem_init is done. */
@@ -324,11 +468,11 @@
 		p = alloc_bootmem_pages(PAGE_SIZE);
 	} else {
 		/*
-		 * Mem start + 32MB -> here is limit
+		 * Mem start + kernel_tlb -> here is limit
 		 * because of mem mapping from head.S
 		 */
 		p = __va(memblock_alloc_base(PAGE_SIZE, PAGE_SIZE,
-					memory_start + 0x2000000));
+					memory_start + kernel_tlb));
 	}
 	return p;
 }
diff --git a/arch/microblaze/mm/pgtable.c b/arch/microblaze/mm/pgtable.c
index 59bf233..d1c06d0 100644
--- a/arch/microblaze/mm/pgtable.c
+++ b/arch/microblaze/mm/pgtable.c
@@ -37,6 +37,7 @@
 #include <linux/io.h>
 #include <asm/mmu.h>
 #include <asm/sections.h>
+#include <asm/fixmap.h>
 
 #define flush_HPTE(X, va, pg)	_tlbie(va)
 
@@ -44,11 +45,6 @@
 unsigned long ioremap_bot;
 EXPORT_SYMBOL(ioremap_bot);
 
-/* The maximum lowmem defaults to 768Mb, but this can be configured to
- * another value.
- */
-#define MAX_LOW_MEM	CONFIG_LOWMEM_SIZE
-
 #ifndef CONFIG_SMP
 struct pgtable_cache_struct quicklists;
 #endif
@@ -80,7 +76,7 @@
 		!(p >= virt_to_phys((unsigned long)&__bss_stop) &&
 		p < virt_to_phys((unsigned long)__bss_stop))) {
 		printk(KERN_WARNING "__ioremap(): phys addr "PTE_FMT
-			" is RAM lr %p\n", (unsigned long)p,
+			" is RAM lr %pf\n", (unsigned long)p,
 			__builtin_return_address(0));
 		return NULL;
 	}
@@ -171,7 +167,7 @@
 
 	v = CONFIG_KERNEL_START;
 	p = memory_start;
-	for (s = 0; s < memory_size; s += PAGE_SIZE) {
+	for (s = 0; s < lowmem_size; s += PAGE_SIZE) {
 		f = _PAGE_PRESENT | _PAGE_ACCESSED |
 				_PAGE_SHARED | _PAGE_HWEXEC;
 		if ((char *) v < _stext || (char *) v >= _etext)
@@ -254,3 +250,13 @@
 	}
 	return pte;
 }
+
+void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags)
+{
+	unsigned long address = __fix_to_virt(idx);
+
+	if (idx >= __end_of_fixed_addresses)
+		BUG();
+
+	map_page(address, phys, pgprot_val(flags));
+}
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 85f2ac1..d10403d 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -46,9 +46,6 @@
 /* ISA Memory physical address */
 resource_size_t isa_mem_base;
 
-/* Default PCI flags is 0 on ppc32, modified at boot on ppc64 */
-unsigned int pci_flags;
-
 static struct dma_map_ops *pci_dma_ops = &dma_direct_ops;
 
 unsigned long isa_io_base;
@@ -833,64 +830,7 @@
 {
 	struct pci_controller *hose = pci_bus_to_host(bus);
 
-	if (!(pci_flags & PCI_ENABLE_PROC_DOMAINS))
-		return 0;
-	if (pci_flags & PCI_COMPAT_DOMAIN_0)
-		return hose->global_number != 0;
-	return 1;
-}
-
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-			     struct resource *res)
-{
-	resource_size_t offset = 0, mask = (resource_size_t)-1;
-	struct pci_controller *hose = pci_bus_to_host(dev->bus);
-
-	if (!hose)
-		return;
-	if (res->flags & IORESOURCE_IO) {
-		offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-		mask = 0xffffffffu;
-	} else if (res->flags & IORESOURCE_MEM)
-		offset = hose->pci_mem_offset;
-
-	region->start = (res->start - offset) & mask;
-	region->end = (res->end - offset) & mask;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-			     struct pci_bus_region *region)
-{
-	resource_size_t offset = 0, mask = (resource_size_t)-1;
-	struct pci_controller *hose = pci_bus_to_host(dev->bus);
-
-	if (!hose)
-		return;
-	if (res->flags & IORESOURCE_IO) {
-		offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-		mask = 0xffffffffu;
-	} else if (res->flags & IORESOURCE_MEM)
-		offset = hose->pci_mem_offset;
-	res->start = (region->start + offset) & mask;
-	res->end = (region->end + offset) & mask;
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
-/* Fixup a bus resource into a linux resource */
-static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
-{
-	struct pci_controller *hose = pci_bus_to_host(dev->bus);
-	resource_size_t offset = 0, mask = (resource_size_t)-1;
-
-	if (res->flags & IORESOURCE_IO) {
-		offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-		mask = 0xffffffffu;
-	} else if (res->flags & IORESOURCE_MEM)
-		offset = hose->pci_mem_offset;
-
-	res->start = (res->start + offset) & mask;
-	res->end = (res->end + offset) & mask;
+	return 0;
 }
 
 /* This header fixup will do the resource fixup for all devices as they are
@@ -910,13 +850,7 @@
 		struct resource *res = dev->resource + i;
 		if (!res->flags)
 			continue;
-		/* On platforms that have PCI_PROBE_ONLY set, we don't
-		 * consider 0 as an unassigned BAR value. It's technically
-		 * a valid value, but linux doesn't like it... so when we can
-		 * re-assign things, we do so, but if we can't, we keep it
-		 * around and hope for the best...
-		 */
-		if (res->start == 0 && !(pci_flags & PCI_PROBE_ONLY)) {
+		if (res->start == 0) {
 			pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]" \
 							"is unassigned\n",
 				 pci_name(dev), i,
@@ -929,18 +863,11 @@
 			continue;
 		}
 
-		pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] fixup...\n",
+		pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]\n",
 			 pci_name(dev), i,
 			 (unsigned long long)res->start,\
 			 (unsigned long long)res->end,
 			 (unsigned int)res->flags);
-
-		fixup_resource(res, dev);
-
-		pr_debug("PCI:%s            %016llx-%016llx\n",
-			 pci_name(dev),
-			 (unsigned long long)res->start,
-			 (unsigned long long)res->end);
 	}
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
@@ -959,10 +886,6 @@
 	u16 command;
 	int i;
 
-	/* We don't do anything if PCI_PROBE_ONLY is set */
-	if (pci_flags & PCI_PROBE_ONLY)
-		return 0;
-
 	/* Job is a bit different between memory and IO */
 	if (res->flags & IORESOURCE_MEM) {
 		/* If the BAR is non-0 (res != pci_mem_offset) then it's
@@ -1037,9 +960,6 @@
 			 (unsigned long long)res->end,
 			 (unsigned int)res->flags);
 
-		/* Perform fixup */
-		fixup_resource(res, dev);
-
 		/* Try to detect uninitialized P2P bridge resources,
 		 * and clear them out so they get re-assigned later
 		 */
@@ -1107,9 +1027,6 @@
 
 static int skip_isa_ioresource_align(struct pci_dev *dev)
 {
-	if ((pci_flags & PCI_CAN_SKIP_ISA_ALIGN) &&
-	    !(dev->bus->bridge_ctl & PCI_BRIDGE_CTL_ISA))
-		return 1;
 	return 0;
 }
 
@@ -1236,8 +1153,6 @@
 			 * and as such ensure proper re-allocation
 			 * later.
 			 */
-			if (pci_flags & PCI_REASSIGN_ALL_RSRC)
-				goto clear_resource;
 			pr = pci_find_parent_resource(bus->self, res);
 			if (pr == res) {
 				/* this happens when the generic PCI
@@ -1422,27 +1337,19 @@
 	list_for_each_entry(b, &pci_root_buses, node)
 		pcibios_allocate_bus_resources(b);
 
-	if (!(pci_flags & PCI_REASSIGN_ALL_RSRC)) {
-		pcibios_allocate_resources(0);
-		pcibios_allocate_resources(1);
-	}
+	pcibios_allocate_resources(0);
+	pcibios_allocate_resources(1);
 
 	/* Before we start assigning unassigned resource, we try to reserve
 	 * the low IO area and the VGA memory area if they intersect the
 	 * bus available resources to avoid allocating things on top of them
 	 */
-	if (!(pci_flags & PCI_PROBE_ONLY)) {
-		list_for_each_entry(b, &pci_root_buses, node)
-			pcibios_reserve_legacy_regions(b);
-	}
+	list_for_each_entry(b, &pci_root_buses, node)
+		pcibios_reserve_legacy_regions(b);
 
-	/* Now, if the platform didn't decide to blindly trust the firmware,
-	 * we proceed to assigning things that were left unassigned
-	 */
-	if (!(pci_flags & PCI_PROBE_ONLY)) {
-		pr_debug("PCI: Assigning unassigned resources...\n");
-		pci_assign_unassigned_resources();
-	}
+	/* Now proceed to assigning things that were left unassigned */
+	pr_debug("PCI: Assigning unassigned resources...\n");
+	pci_assign_unassigned_resources();
 }
 
 #ifdef CONFIG_HOTPLUG
@@ -1535,7 +1442,7 @@
 		res->end = res->start + IO_SPACE_LIMIT;
 		res->flags = IORESOURCE_IO;
 	}
-	pci_add_resource(resources, res);
+	pci_add_resource_offset(resources, res, hose->io_base_virt - _IO_BASE);
 
 	pr_debug("PCI: PHB IO resource    = %016llx-%016llx [%lx]\n",
 		 (unsigned long long)res->start,
@@ -1558,7 +1465,7 @@
 			res->flags = IORESOURCE_MEM;
 
 		}
-		pci_add_resource(resources, res);
+		pci_add_resource_offset(resources, res, hose->pci_mem_offset);
 
 		pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n",
 			i, (unsigned long long)res->start,
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index edbbae1..ce30e2f 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2457,6 +2457,7 @@
 config COMPAT
 	bool
 	depends on MIPS32_COMPAT
+	select ARCH_WANT_OLD_COMPAT_IPC
 	default y
 
 config SYSVIPC_COMPAT
diff --git a/arch/mips/cavium-octeon/dma-octeon.c b/arch/mips/cavium-octeon/dma-octeon.c
index b6bb92c..41dd0088 100644
--- a/arch/mips/cavium-octeon/dma-octeon.c
+++ b/arch/mips/cavium-octeon/dma-octeon.c
@@ -157,7 +157,7 @@
 }
 
 static void *octeon_dma_alloc_coherent(struct device *dev, size_t size,
-	dma_addr_t *dma_handle, gfp_t gfp)
+	dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs)
 {
 	void *ret;
 
@@ -192,7 +192,7 @@
 }
 
 static void octeon_dma_free_coherent(struct device *dev, size_t size,
-	void *vaddr, dma_addr_t dma_handle)
+	void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs)
 {
 	int order = get_order(size);
 
@@ -240,8 +240,8 @@
 
 static struct octeon_dma_map_ops octeon_linear_dma_map_ops = {
 	.dma_map_ops = {
-		.alloc_coherent = octeon_dma_alloc_coherent,
-		.free_coherent = octeon_dma_free_coherent,
+		.alloc = octeon_dma_alloc_coherent,
+		.free = octeon_dma_free_coherent,
 		.map_page = octeon_dma_map_page,
 		.unmap_page = swiotlb_unmap_page,
 		.map_sg = octeon_dma_map_sg,
@@ -325,8 +325,8 @@
 #ifdef CONFIG_PCI
 static struct octeon_dma_map_ops _octeon_pci_dma_map_ops = {
 	.dma_map_ops = {
-		.alloc_coherent = octeon_dma_alloc_coherent,
-		.free_coherent = octeon_dma_free_coherent,
+		.alloc = octeon_dma_alloc_coherent,
+		.free = octeon_dma_free_coherent,
 		.map_page = octeon_dma_map_page,
 		.unmap_page = swiotlb_unmap_page,
 		.map_sg = octeon_dma_map_sg,
diff --git a/arch/mips/cavium-octeon/flash_setup.c b/arch/mips/cavium-octeon/flash_setup.c
index 0a430e0..e44a55b 100644
--- a/arch/mips/cavium-octeon/flash_setup.c
+++ b/arch/mips/cavium-octeon/flash_setup.c
@@ -60,7 +60,7 @@
 		if (mymtd) {
 			mymtd->owner = THIS_MODULE;
 			mtd_device_parse_register(mymtd, part_probe_types,
-						  0, NULL, 0);
+						  NULL, NULL, 0);
 		} else {
 			pr_err("Failed to register MTD device for flash\n");
 		}
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
index 260b273..d3a9f012 100644
--- a/arch/mips/cavium-octeon/setup.c
+++ b/arch/mips/cavium-octeon/setup.c
@@ -24,7 +24,6 @@
 #include <asm/processor.h>
 #include <asm/reboot.h>
 #include <asm/smp-ops.h>
-#include <asm/system.h>
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
 #include <asm/bootinfo.h>
diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c
index b1535fe..97e7ce9 100644
--- a/arch/mips/cavium-octeon/smp.c
+++ b/arch/mips/cavium-octeon/smp.c
@@ -15,8 +15,8 @@
 #include <linux/module.h>
 
 #include <asm/mmu_context.h>
-#include <asm/system.h>
 #include <asm/time.h>
+#include <asm/setup.h>
 
 #include <asm/octeon/octeon.h>
 
@@ -78,7 +78,7 @@
 }
 
 /**
- * Detect available CPUs, populate cpu_possible_map
+ * Detect available CPUs, populate cpu_possible_mask
  */
 static void octeon_smp_hotplug_setup(void)
 {
@@ -268,7 +268,7 @@
 
 	spin_lock(&smp_reserve_lock);
 
-	cpu_clear(cpu, cpu_online_map);
+	set_cpu_online(cpu, false);
 	cpu_clear(cpu, cpu_callin_map);
 	local_irq_disable();
 	fixup_irqs();
diff --git a/arch/mips/configs/db1300_defconfig b/arch/mips/configs/db1300_defconfig
index c38b190..3590ab5 100644
--- a/arch/mips/configs/db1300_defconfig
+++ b/arch/mips/configs/db1300_defconfig
@@ -133,7 +133,7 @@
 CONFIG_IOSCHED_NOOP=y
 CONFIG_DEFAULT_NOOP=y
 CONFIG_DEFAULT_IOSCHED="noop"
-CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_UNINLINE_SPIN_UNLOCK is not set
 CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
 CONFIG_INLINE_READ_UNLOCK=y
 CONFIG_INLINE_READ_UNLOCK_IRQ=y
diff --git a/arch/mips/dec/ecc-berr.c b/arch/mips/dec/ecc-berr.c
index 7abce66..5abf4e8 100644
--- a/arch/mips/dec/ecc-berr.c
+++ b/arch/mips/dec/ecc-berr.c
@@ -24,7 +24,6 @@
 #include <asm/irq_regs.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 
 #include <asm/dec/ecc.h>
diff --git a/arch/mips/dec/kn01-berr.c b/arch/mips/dec/kn01-berr.c
index 94d23b4..44d8a87 100644
--- a/arch/mips/dec/kn01-berr.c
+++ b/arch/mips/dec/kn01-berr.c
@@ -22,7 +22,6 @@
 #include <asm/mipsregs.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/uaccess.h>
 
diff --git a/arch/mips/dec/kn02xa-berr.c b/arch/mips/dec/kn02xa-berr.c
index 07ca540..ebb73c5 100644
--- a/arch/mips/dec/kn02xa-berr.c
+++ b/arch/mips/dec/kn02xa-berr.c
@@ -21,7 +21,6 @@
 #include <asm/addrspace.h>
 #include <asm/irq_regs.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 
 #include <asm/dec/kn02ca.h>
diff --git a/arch/mips/dec/wbflush.c b/arch/mips/dec/wbflush.c
index 925c052..43feddd 100644
--- a/arch/mips/dec/wbflush.c
+++ b/arch/mips/dec/wbflush.c
@@ -17,8 +17,8 @@
 #include <linux/init.h>
 
 #include <asm/bootinfo.h>
-#include <asm/system.h>
 #include <asm/wbflush.h>
+#include <asm/barrier.h>
 
 static void wbflush_kn01(void);
 static void wbflush_kn210(void);
diff --git a/arch/mips/emma/markeins/irq.c b/arch/mips/emma/markeins/irq.c
index 7798887..b5f0825 100644
--- a/arch/mips/emma/markeins/irq.c
+++ b/arch/mips/emma/markeins/irq.c
@@ -27,7 +27,6 @@
 #include <linux/delay.h>
 
 #include <asm/irq_cpu.h>
-#include <asm/system.h>
 #include <asm/mipsregs.h>
 #include <asm/addrspace.h>
 #include <asm/bootinfo.h>
diff --git a/arch/mips/fw/arc/cmdline.c b/arch/mips/fw/arc/cmdline.c
index 9fdf07e..c0122a1 100644
--- a/arch/mips/fw/arc/cmdline.c
+++ b/arch/mips/fw/arc/cmdline.c
@@ -7,6 +7,7 @@
  *
  * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
  */
+#include <linux/bug.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
diff --git a/arch/mips/fw/arc/identify.c b/arch/mips/fw/arc/identify.c
index 788060a..54a33c7 100644
--- a/arch/mips/fw/arc/identify.c
+++ b/arch/mips/fw/arc/identify.c
@@ -11,6 +11,7 @@
  *
  * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
  */
+#include <linux/bug.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
diff --git a/arch/mips/fw/arc/misc.c b/arch/mips/fw/arc/misc.c
index 29627fb..7cf80ca 100644
--- a/arch/mips/fw/arc/misc.c
+++ b/arch/mips/fw/arc/misc.c
@@ -17,7 +17,6 @@
 #include <asm/fw/arc/types.h>
 #include <asm/sgialib.h>
 #include <asm/bootinfo.h>
-#include <asm/system.h>
 
 VOID
 ArcHalt(VOID)
diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h
index 1d93f81..3f4c5cb 100644
--- a/arch/mips/include/asm/atomic.h
+++ b/arch/mips/include/asm/atomic.h
@@ -18,8 +18,8 @@
 #include <linux/types.h>
 #include <asm/barrier.h>
 #include <asm/cpu-features.h>
+#include <asm/cmpxchg.h>
 #include <asm/war.h>
-#include <asm/system.h>
 
 #define ATOMIC_INIT(i)    { (i) }
 
diff --git a/arch/mips/include/asm/barrier.h b/arch/mips/include/asm/barrier.h
index c0884f0..f7fdc24 100644
--- a/arch/mips/include/asm/barrier.h
+++ b/arch/mips/include/asm/barrier.h
@@ -8,6 +8,8 @@
 #ifndef __ASM_BARRIER_H
 #define __ASM_BARRIER_H
 
+#include <asm/addrspace.h>
+
 /*
  * read_barrier_depends - Flush all pending reads that subsequents reads
  * depend on.
diff --git a/arch/mips/include/asm/cmpxchg.h b/arch/mips/include/asm/cmpxchg.h
index d8d1c28..285a41f 100644
--- a/arch/mips/include/asm/cmpxchg.h
+++ b/arch/mips/include/asm/cmpxchg.h
@@ -9,6 +9,130 @@
 #define __ASM_CMPXCHG_H
 
 #include <linux/irqflags.h>
+#include <asm/war.h>
+
+static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
+{
+	__u32 retval;
+
+	smp_mb__before_llsc();
+
+	if (kernel_uses_llsc && R10000_LLSC_WAR) {
+		unsigned long dummy;
+
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:	ll	%0, %3			# xchg_u32	\n"
+		"	.set	mips0					\n"
+		"	move	%2, %z4					\n"
+		"	.set	mips3					\n"
+		"	sc	%2, %1					\n"
+		"	beqzl	%2, 1b					\n"
+		"	.set	mips0					\n"
+		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
+		: "R" (*m), "Jr" (val)
+		: "memory");
+	} else if (kernel_uses_llsc) {
+		unsigned long dummy;
+
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	ll	%0, %3		# xchg_u32	\n"
+			"	.set	mips0				\n"
+			"	move	%2, %z4				\n"
+			"	.set	mips3				\n"
+			"	sc	%2, %1				\n"
+			"	.set	mips0				\n"
+			: "=&r" (retval), "=m" (*m), "=&r" (dummy)
+			: "R" (*m), "Jr" (val)
+			: "memory");
+		} while (unlikely(!dummy));
+	} else {
+		unsigned long flags;
+
+		raw_local_irq_save(flags);
+		retval = *m;
+		*m = val;
+		raw_local_irq_restore(flags);	/* implies memory barrier  */
+	}
+
+	smp_llsc_mb();
+
+	return retval;
+}
+
+#ifdef CONFIG_64BIT
+static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
+{
+	__u64 retval;
+
+	smp_mb__before_llsc();
+
+	if (kernel_uses_llsc && R10000_LLSC_WAR) {
+		unsigned long dummy;
+
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:	lld	%0, %3			# xchg_u64	\n"
+		"	move	%2, %z4					\n"
+		"	scd	%2, %1					\n"
+		"	beqzl	%2, 1b					\n"
+		"	.set	mips0					\n"
+		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
+		: "R" (*m), "Jr" (val)
+		: "memory");
+	} else if (kernel_uses_llsc) {
+		unsigned long dummy;
+
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	lld	%0, %3		# xchg_u64	\n"
+			"	move	%2, %z4				\n"
+			"	scd	%2, %1				\n"
+			"	.set	mips0				\n"
+			: "=&r" (retval), "=m" (*m), "=&r" (dummy)
+			: "R" (*m), "Jr" (val)
+			: "memory");
+		} while (unlikely(!dummy));
+	} else {
+		unsigned long flags;
+
+		raw_local_irq_save(flags);
+		retval = *m;
+		*m = val;
+		raw_local_irq_restore(flags);	/* implies memory barrier  */
+	}
+
+	smp_llsc_mb();
+
+	return retval;
+}
+#else
+extern __u64 __xchg_u64_unsupported_on_32bit_kernels(volatile __u64 * m, __u64 val);
+#define __xchg_u64 __xchg_u64_unsupported_on_32bit_kernels
+#endif
+
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+{
+	switch (size) {
+	case 4:
+		return __xchg_u32(ptr, x);
+	case 8:
+		return __xchg_u64(ptr, x);
+	}
+
+	return x;
+}
+
+#define xchg(ptr, x)							\
+({									\
+	BUILD_BUG_ON(sizeof(*(ptr)) & ~0xc);				\
+									\
+	((__typeof__(*(ptr)))						\
+		__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))));	\
+})
 
 #define __HAVE_ARCH_CMPXCHG 1
 
diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h
index 7aa37dd..be39a12 100644
--- a/arch/mips/include/asm/dma-mapping.h
+++ b/arch/mips/include/asm/dma-mapping.h
@@ -57,25 +57,31 @@
 extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
 	       enum dma_data_direction direction);
 
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-				       dma_addr_t *dma_handle, gfp_t gfp)
+#define dma_alloc_coherent(d,s,h,f)	dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+				    dma_addr_t *dma_handle, gfp_t gfp,
+				    struct dma_attrs *attrs)
 {
 	void *ret;
 	struct dma_map_ops *ops = get_dma_ops(dev);
 
-	ret = ops->alloc_coherent(dev, size, dma_handle, gfp);
+	ret = ops->alloc(dev, size, dma_handle, gfp, attrs);
 
 	debug_dma_alloc_coherent(dev, size, *dma_handle, ret);
 
 	return ret;
 }
 
-static inline void dma_free_coherent(struct device *dev, size_t size,
-				     void *vaddr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+				  void *vaddr, dma_addr_t dma_handle,
+				  struct dma_attrs *attrs)
 {
 	struct dma_map_ops *ops = get_dma_ops(dev);
 
-	ops->free_coherent(dev, size, vaddr, dma_handle);
+	ops->free(dev, size, vaddr, dma_handle, attrs);
 
 	debug_dma_free_coherent(dev, size, vaddr, dma_handle);
 }
diff --git a/arch/mips/include/asm/dma.h b/arch/mips/include/asm/dma.h
index 2d47da6..f5097f6 100644
--- a/arch/mips/include/asm/dma.h
+++ b/arch/mips/include/asm/dma.h
@@ -15,7 +15,6 @@
 #include <asm/io.h>			/* need byte IO */
 #include <linux/spinlock.h>		/* And spinlocks */
 #include <linux/delay.h>
-#include <asm/system.h>
 
 
 #ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
diff --git a/arch/mips/include/asm/exec.h b/arch/mips/include/asm/exec.h
new file mode 100644
index 0000000..c1f6afa
--- /dev/null
+++ b/arch/mips/include/asm/exec.h
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 1994, 95, 96, 97, 98, 99, 2003, 06 by Ralf Baechle
+ * Copyright (C) 1996 by Paul M. Antoine
+ * Copyright (C) 1999 Silicon Graphics
+ * Kevin D. Kissell, kevink@mips.org and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.
+ */
+#ifndef _ASM_EXEC_H
+#define _ASM_EXEC_H
+
+extern unsigned long arch_align_stack(unsigned long sp);
+
+#endif /* _ASM_EXEC_H */
diff --git a/arch/mips/include/asm/mach-au1x00/au1000_dma.h b/arch/mips/include/asm/mach-au1x00/au1000_dma.h
index 59f5b55..ba4cf0e 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000_dma.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000_dma.h
@@ -33,7 +33,6 @@
 #include <linux/io.h>		/* need byte IO */
 #include <linux/spinlock.h>	/* And spinlocks */
 #include <linux/delay.h>
-#include <asm/system.h>
 
 #define NUM_AU1000_DMA_CHANNELS	8
 
diff --git a/arch/mips/include/asm/mman.h b/arch/mips/include/asm/mman.h
index 785b4ea..46d3da0 100644
--- a/arch/mips/include/asm/mman.h
+++ b/arch/mips/include/asm/mman.h
@@ -80,6 +80,10 @@
 #define MADV_HUGEPAGE	14		/* Worth backing with hugepages */
 #define MADV_NOHUGEPAGE	15		/* Not worth backing with hugepages */
 
+#define MADV_DONTDUMP   16		/* Explicity exclude from the core dump,
+					   overrides the coredump filter bits */
+#define MADV_DODUMP	17		/* Clear the MADV_NODUMP flag */
+
 /* compatibility flags */
 #define MAP_FILE	0
 
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
index 576397c..fcd4060 100644
--- a/arch/mips/include/asm/pci.h
+++ b/arch/mips/include/asm/pci.h
@@ -92,6 +92,7 @@
 #include <asm/scatterlist.h>
 #include <linux/string.h>
 #include <asm/io.h>
+#include <asm-generic/pci-bridge.h>
 
 struct pci_dev;
 
@@ -112,12 +113,6 @@
 }
 #endif
 
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
-	struct pci_bus_region *region, struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-				    struct pci_bus_region *region);
-
 #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
 
 static inline int pci_proc_domain(struct pci_bus *bus)
@@ -145,8 +140,6 @@
 #define arch_setup_msi_irqs arch_setup_msi_irqs
 #endif
 
-extern int pci_probe_only;
-
 extern char * (*pcibios_plat_setup)(char *str);
 
 #endif /* _ASM_PCI_H */
diff --git a/arch/mips/include/asm/posix_types.h b/arch/mips/include/asm/posix_types.h
index c200102..e0308dc 100644
--- a/arch/mips/include/asm/posix_types.h
+++ b/arch/mips/include/asm/posix_types.h
@@ -17,128 +17,21 @@
  * assume GCC is being used.
  */
 
-typedef unsigned long	__kernel_ino_t;
-typedef unsigned int	__kernel_mode_t;
-#if (_MIPS_SZLONG == 32)
-typedef unsigned long	__kernel_nlink_t;
-#endif
 #if (_MIPS_SZLONG == 64)
 typedef unsigned int	__kernel_nlink_t;
+#define __kernel_nlink_t __kernel_nlink_t
 #endif
-typedef long		__kernel_off_t;
-typedef int		__kernel_pid_t;
-typedef int		__kernel_ipc_pid_t;
-typedef unsigned int	__kernel_uid_t;
-typedef unsigned int	__kernel_gid_t;
-#if (_MIPS_SZLONG == 32)
-typedef unsigned int	__kernel_size_t;
-typedef int		__kernel_ssize_t;
-typedef int		__kernel_ptrdiff_t;
-#endif
-#if (_MIPS_SZLONG == 64)
-typedef unsigned long	__kernel_size_t;
-typedef long		__kernel_ssize_t;
-typedef long		__kernel_ptrdiff_t;
-#endif
-typedef long		__kernel_time_t;
-typedef long		__kernel_suseconds_t;
-typedef long		__kernel_clock_t;
-typedef int		__kernel_timer_t;
-typedef int		__kernel_clockid_t;
+
 typedef long		__kernel_daddr_t;
-typedef char *		__kernel_caddr_t;
+#define __kernel_daddr_t __kernel_daddr_t
 
-typedef unsigned short	__kernel_uid16_t;
-typedef unsigned short	__kernel_gid16_t;
-typedef unsigned int	__kernel_uid32_t;
-typedef unsigned int	__kernel_gid32_t;
-typedef __kernel_uid_t	__kernel_old_uid_t;
-typedef __kernel_gid_t	__kernel_old_gid_t;
-typedef unsigned int	__kernel_old_dev_t;
-
-#ifdef __GNUC__
-typedef long long      __kernel_loff_t;
-#endif
-
-typedef struct {
 #if (_MIPS_SZLONG == 32)
+typedef struct {
 	long	val[2];
-#endif
-#if (_MIPS_SZLONG == 64)
-	int	val[2];
-#endif
 } __kernel_fsid_t;
+#define __kernel_fsid_t __kernel_fsid_t
+#endif
 
-#if defined(__KERNEL__)
-
-#undef __FD_SET
-static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-	unsigned long __tmp = __fd / __NFDBITS;
-	unsigned long __rem = __fd % __NFDBITS;
-	__fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
-}
-
-#undef __FD_CLR
-static __inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-	unsigned long __tmp = __fd / __NFDBITS;
-	unsigned long __rem = __fd % __NFDBITS;
-	__fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
-}
-
-#undef __FD_ISSET
-static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
-{
-	unsigned long __tmp = __fd / __NFDBITS;
-	unsigned long __rem = __fd % __NFDBITS;
-	return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
-}
-
-/*
- * This will unroll the loop for the normal constant case (8 ints,
- * for a 256-bit fd_set)
- */
-#undef __FD_ZERO
-static __inline__ void __FD_ZERO(__kernel_fd_set *__p)
-{
-	unsigned long *__tmp = __p->fds_bits;
-	int __i;
-
-	if (__builtin_constant_p(__FDSET_LONGS)) {
-		switch (__FDSET_LONGS) {
-		case 16:
-			__tmp[ 0] = 0; __tmp[ 1] = 0;
-			__tmp[ 2] = 0; __tmp[ 3] = 0;
-			__tmp[ 4] = 0; __tmp[ 5] = 0;
-			__tmp[ 6] = 0; __tmp[ 7] = 0;
-			__tmp[ 8] = 0; __tmp[ 9] = 0;
-			__tmp[10] = 0; __tmp[11] = 0;
-			__tmp[12] = 0; __tmp[13] = 0;
-			__tmp[14] = 0; __tmp[15] = 0;
-			return;
-
-		case 8:
-			__tmp[ 0] = 0; __tmp[ 1] = 0;
-			__tmp[ 2] = 0; __tmp[ 3] = 0;
-			__tmp[ 4] = 0; __tmp[ 5] = 0;
-			__tmp[ 6] = 0; __tmp[ 7] = 0;
-			return;
-
-		case 4:
-			__tmp[ 0] = 0; __tmp[ 1] = 0;
-			__tmp[ 2] = 0; __tmp[ 3] = 0;
-			return;
-		}
-	}
-	__i = __FDSET_LONGS;
-	while (__i) {
-		__i--;
-		*__tmp = 0;
-		__tmp++;
-	}
-}
-
-#endif /* defined(__KERNEL__) */
+#include <asm-generic/posix_types.h>
 
 #endif /* _ASM_POSIX_TYPES_H */
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
index c104f10..20e9dcf 100644
--- a/arch/mips/include/asm/processor.h
+++ b/arch/mips/include/asm/processor.h
@@ -19,7 +19,6 @@
 #include <asm/cpu-info.h>
 #include <asm/mipsregs.h>
 #include <asm/prefetch.h>
-#include <asm/system.h>
 
 /*
  * Return current * instruction pointer ("program counter").
@@ -356,6 +355,12 @@
 #define ARCH_HAS_PREFETCHW
 #define prefetchw(x) __builtin_prefetch((x), 1, 1)
 
+/*
+ * See Documentation/scheduler/sched-arch.txt; prevents deadlock on SMP
+ * systems.
+ */
+#define __ARCH_WANT_UNLOCKED_CTXSW
+
 #endif
 
 #endif /* _ASM_PROCESSOR_H */
diff --git a/arch/mips/include/asm/setup.h b/arch/mips/include/asm/setup.h
index 50511aa..6dce6d8 100644
--- a/arch/mips/include/asm/setup.h
+++ b/arch/mips/include/asm/setup.h
@@ -5,6 +5,17 @@
 
 #ifdef  __KERNEL__
 extern void setup_early_printk(void);
+
+extern void set_handler(unsigned long offset, void *addr, unsigned long len);
+extern void set_uncached_handler(unsigned long offset, void *addr, unsigned long len);
+
+typedef void (*vi_handler_t)(void);
+extern void *set_vi_handler(int n, vi_handler_t addr);
+
+extern void *set_except_vector(int n, void *addr);
+extern unsigned long ebase;
+extern void per_cpu_trap_init(void);
+
 #endif /* __KERNEL__ */
 
 #endif /* __SETUP_H */
diff --git a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h
new file mode 100644
index 0000000..5d33621
--- /dev/null
+++ b/arch/mips/include/asm/switch_to.h
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 1994, 95, 96, 97, 98, 99, 2003, 06 by Ralf Baechle
+ * Copyright (C) 1996 by Paul M. Antoine
+ * Copyright (C) 1999 Silicon Graphics
+ * Kevin D. Kissell, kevink@mips.org and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.
+ */
+#ifndef _ASM_SWITCH_TO_H
+#define _ASM_SWITCH_TO_H
+
+#include <asm/cpu-features.h>
+#include <asm/watch.h>
+#include <asm/dsp.h>
+
+struct task_struct;
+
+/*
+ * switch_to(n) should switch tasks to task nr n, first
+ * checking that n isn't the current task, in which case it does nothing.
+ */
+extern asmlinkage void *resume(void *last, void *next, void *next_ti);
+
+extern unsigned int ll_bit;
+extern struct task_struct *ll_task;
+
+#ifdef CONFIG_MIPS_MT_FPAFF
+
+/*
+ * Handle the scheduler resume end of FPU affinity management.  We do this
+ * inline to try to keep the overhead down. If we have been forced to run on
+ * a "CPU" with an FPU because of a previous high level of FP computation,
+ * but did not actually use the FPU during the most recent time-slice (CU1
+ * isn't set), we undo the restriction on cpus_allowed.
+ *
+ * We're not calling set_cpus_allowed() here, because we have no need to
+ * force prompt migration - we're already switching the current CPU to a
+ * different thread.
+ */
+
+#define __mips_mt_fpaff_switch_to(prev)					\
+do {									\
+	struct thread_info *__prev_ti = task_thread_info(prev);		\
+									\
+	if (cpu_has_fpu &&						\
+	    test_ti_thread_flag(__prev_ti, TIF_FPUBOUND) &&		\
+	    (!(KSTK_STATUS(prev) & ST0_CU1))) {				\
+		clear_ti_thread_flag(__prev_ti, TIF_FPUBOUND);		\
+		prev->cpus_allowed = prev->thread.user_cpus_allowed;	\
+	}								\
+	next->thread.emulated_fp = 0;					\
+} while(0)
+
+#else
+#define __mips_mt_fpaff_switch_to(prev) do { (void) (prev); } while (0)
+#endif
+
+#define __clear_software_ll_bit()					\
+do {									\
+	if (!__builtin_constant_p(cpu_has_llsc) || !cpu_has_llsc)	\
+		ll_bit = 0;						\
+} while (0)
+
+#define switch_to(prev, next, last)					\
+do {									\
+	__mips_mt_fpaff_switch_to(prev);				\
+	if (cpu_has_dsp)						\
+		__save_dsp(prev);					\
+	__clear_software_ll_bit();					\
+	(last) = resume(prev, next, task_thread_info(next));		\
+} while (0)
+
+#define finish_arch_switch(prev)					\
+do {									\
+	if (cpu_has_dsp)						\
+		__restore_dsp(current);					\
+	if (cpu_has_userlocal)						\
+		write_c0_userlocal(current_thread_info()->tp_value);	\
+	__restore_watch();						\
+} while (0)
+
+#endif /* _ASM_SWITCH_TO_H */
diff --git a/arch/mips/include/asm/system.h b/arch/mips/include/asm/system.h
deleted file mode 100644
index 6018c80..0000000
--- a/arch/mips/include/asm/system.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * 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.
- *
- * Copyright (C) 1994, 95, 96, 97, 98, 99, 2003, 06 by Ralf Baechle
- * Copyright (C) 1996 by Paul M. Antoine
- * Copyright (C) 1999 Silicon Graphics
- * Kevin D. Kissell, kevink@mips.org and Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 2000 MIPS Technologies, Inc.
- */
-#ifndef _ASM_SYSTEM_H
-#define _ASM_SYSTEM_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/irqflags.h>
-
-#include <asm/addrspace.h>
-#include <asm/barrier.h>
-#include <asm/cmpxchg.h>
-#include <asm/cpu-features.h>
-#include <asm/dsp.h>
-#include <asm/watch.h>
-#include <asm/war.h>
-
-
-/*
- * switch_to(n) should switch tasks to task nr n, first
- * checking that n isn't the current task, in which case it does nothing.
- */
-extern asmlinkage void *resume(void *last, void *next, void *next_ti);
-
-struct task_struct;
-
-extern unsigned int ll_bit;
-extern struct task_struct *ll_task;
-
-#ifdef CONFIG_MIPS_MT_FPAFF
-
-/*
- * Handle the scheduler resume end of FPU affinity management.  We do this
- * inline to try to keep the overhead down. If we have been forced to run on
- * a "CPU" with an FPU because of a previous high level of FP computation,
- * but did not actually use the FPU during the most recent time-slice (CU1
- * isn't set), we undo the restriction on cpus_allowed.
- *
- * We're not calling set_cpus_allowed() here, because we have no need to
- * force prompt migration - we're already switching the current CPU to a
- * different thread.
- */
-
-#define __mips_mt_fpaff_switch_to(prev)					\
-do {									\
-	struct thread_info *__prev_ti = task_thread_info(prev);		\
-									\
-	if (cpu_has_fpu &&						\
-	    test_ti_thread_flag(__prev_ti, TIF_FPUBOUND) &&		\
-	    (!(KSTK_STATUS(prev) & ST0_CU1))) {				\
-		clear_ti_thread_flag(__prev_ti, TIF_FPUBOUND);		\
-		prev->cpus_allowed = prev->thread.user_cpus_allowed;	\
-	}								\
-	next->thread.emulated_fp = 0;					\
-} while(0)
-
-#else
-#define __mips_mt_fpaff_switch_to(prev) do { (void) (prev); } while (0)
-#endif
-
-#define __clear_software_ll_bit()					\
-do {									\
-	if (!__builtin_constant_p(cpu_has_llsc) || !cpu_has_llsc)	\
-		ll_bit = 0;						\
-} while (0)
-
-#define switch_to(prev, next, last)					\
-do {									\
-	__mips_mt_fpaff_switch_to(prev);				\
-	if (cpu_has_dsp)						\
-		__save_dsp(prev);					\
-	__clear_software_ll_bit();					\
-	(last) = resume(prev, next, task_thread_info(next));		\
-} while (0)
-
-#define finish_arch_switch(prev)					\
-do {									\
-	if (cpu_has_dsp)						\
-		__restore_dsp(current);					\
-	if (cpu_has_userlocal)						\
-		write_c0_userlocal(current_thread_info()->tp_value);	\
-	__restore_watch();						\
-} while (0)
-
-static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
-{
-	__u32 retval;
-
-	smp_mb__before_llsc();
-
-	if (kernel_uses_llsc && R10000_LLSC_WAR) {
-		unsigned long dummy;
-
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	ll	%0, %3			# xchg_u32	\n"
-		"	.set	mips0					\n"
-		"	move	%2, %z4					\n"
-		"	.set	mips3					\n"
-		"	sc	%2, %1					\n"
-		"	beqzl	%2, 1b					\n"
-		"	.set	mips0					\n"
-		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
-		: "R" (*m), "Jr" (val)
-		: "memory");
-	} else if (kernel_uses_llsc) {
-		unsigned long dummy;
-
-		do {
-			__asm__ __volatile__(
-			"	.set	mips3				\n"
-			"	ll	%0, %3		# xchg_u32	\n"
-			"	.set	mips0				\n"
-			"	move	%2, %z4				\n"
-			"	.set	mips3				\n"
-			"	sc	%2, %1				\n"
-			"	.set	mips0				\n"
-			: "=&r" (retval), "=m" (*m), "=&r" (dummy)
-			: "R" (*m), "Jr" (val)
-			: "memory");
-		} while (unlikely(!dummy));
-	} else {
-		unsigned long flags;
-
-		raw_local_irq_save(flags);
-		retval = *m;
-		*m = val;
-		raw_local_irq_restore(flags);	/* implies memory barrier  */
-	}
-
-	smp_llsc_mb();
-
-	return retval;
-}
-
-#ifdef CONFIG_64BIT
-static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
-{
-	__u64 retval;
-
-	smp_mb__before_llsc();
-
-	if (kernel_uses_llsc && R10000_LLSC_WAR) {
-		unsigned long dummy;
-
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	lld	%0, %3			# xchg_u64	\n"
-		"	move	%2, %z4					\n"
-		"	scd	%2, %1					\n"
-		"	beqzl	%2, 1b					\n"
-		"	.set	mips0					\n"
-		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
-		: "R" (*m), "Jr" (val)
-		: "memory");
-	} else if (kernel_uses_llsc) {
-		unsigned long dummy;
-
-		do {
-			__asm__ __volatile__(
-			"	.set	mips3				\n"
-			"	lld	%0, %3		# xchg_u64	\n"
-			"	move	%2, %z4				\n"
-			"	scd	%2, %1				\n"
-			"	.set	mips0				\n"
-			: "=&r" (retval), "=m" (*m), "=&r" (dummy)
-			: "R" (*m), "Jr" (val)
-			: "memory");
-		} while (unlikely(!dummy));
-	} else {
-		unsigned long flags;
-
-		raw_local_irq_save(flags);
-		retval = *m;
-		*m = val;
-		raw_local_irq_restore(flags);	/* implies memory barrier  */
-	}
-
-	smp_llsc_mb();
-
-	return retval;
-}
-#else
-extern __u64 __xchg_u64_unsupported_on_32bit_kernels(volatile __u64 * m, __u64 val);
-#define __xchg_u64 __xchg_u64_unsupported_on_32bit_kernels
-#endif
-
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
-{
-	switch (size) {
-	case 4:
-		return __xchg_u32(ptr, x);
-	case 8:
-		return __xchg_u64(ptr, x);
-	}
-
-	return x;
-}
-
-#define xchg(ptr, x)							\
-({									\
-	BUILD_BUG_ON(sizeof(*(ptr)) & ~0xc);				\
-									\
-	((__typeof__(*(ptr)))						\
-		__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))));	\
-})
-
-extern void set_handler(unsigned long offset, void *addr, unsigned long len);
-extern void set_uncached_handler(unsigned long offset, void *addr, unsigned long len);
-
-typedef void (*vi_handler_t)(void);
-extern void *set_vi_handler(int n, vi_handler_t addr);
-
-extern void *set_except_vector(int n, void *addr);
-extern unsigned long ebase;
-extern void per_cpu_trap_init(void);
-
-/*
- * See include/asm-ia64/system.h; prevents deadlock on SMP
- * systems.
- */
-#define __ARCH_WANT_UNLOCKED_CTXSW
-
-extern unsigned long arch_align_stack(unsigned long sp);
-
-#endif /* _ASM_SYSTEM_H */
diff --git a/arch/mips/include/asm/txx9/jmr3927.h b/arch/mips/include/asm/txx9/jmr3927.h
index a409c44..8808d7f 100644
--- a/arch/mips/include/asm/txx9/jmr3927.h
+++ b/arch/mips/include/asm/txx9/jmr3927.h
@@ -12,7 +12,6 @@
 
 #include <asm/txx9/tx3927.h>
 #include <asm/addrspace.h>
-#include <asm/system.h>
 #include <asm/txx9irq.h>
 
 /* CS */
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index 639e3ce..9a91fe9 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -418,6 +418,11 @@
 	},
 };
 
+/* audio */
+static struct platform_device qi_lb60_audio_device = {
+	.name = "qi-lb60-audio",
+	.id = -1,
+};
 
 static struct platform_device *jz_platform_devices[] __initdata = {
 	&jz4740_udc_device,
@@ -434,6 +439,7 @@
 	&qi_lb60_gpio_keys,
 	&qi_lb60_pwm_beeper,
 	&qi_lb60_charger_device,
+	&qi_lb60_audio_device,
 };
 
 static void __init board_gpio_setup(void)
diff --git a/arch/mips/kernel/cpu-bugs64.c b/arch/mips/kernel/cpu-bugs64.c
index f305ca1..d6a1864 100644
--- a/arch/mips/kernel/cpu-bugs64.c
+++ b/arch/mips/kernel/cpu-bugs64.c
@@ -16,7 +16,7 @@
 #include <asm/cpu.h>
 #include <asm/fpu.h>
 #include <asm/mipsregs.h>
-#include <asm/system.h>
+#include <asm/setup.h>
 
 static char bug64hit[] __initdata =
 	"reliable operation impossible!\n%s";
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 0bab464..5099201 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -22,7 +22,6 @@
 #include <asm/cpu.h>
 #include <asm/fpu.h>
 #include <asm/mipsregs.h>
-#include <asm/system.h>
 #include <asm/watch.h>
 #include <asm/elf.h>
 #include <asm/spram.h>
diff --git a/arch/mips/kernel/irq-rm7000.c b/arch/mips/kernel/irq-rm7000.c
index a8a8977..b0662cf 100644
--- a/arch/mips/kernel/irq-rm7000.c
+++ b/arch/mips/kernel/irq-rm7000.c
@@ -16,7 +16,6 @@
 
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
-#include <asm/system.h>
 
 static inline void unmask_rm7k_irq(struct irq_data *d)
 {
diff --git a/arch/mips/kernel/irq-rm9000.c b/arch/mips/kernel/irq-rm9000.c
index 38874a4..1282b9a 100644
--- a/arch/mips/kernel/irq-rm9000.c
+++ b/arch/mips/kernel/irq-rm9000.c
@@ -17,7 +17,6 @@
 
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
-#include <asm/system.h>
 
 static inline void unmask_rm9k_irq(struct irq_data *d)
 {
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
index 7f50318..a5aa43d 100644
--- a/arch/mips/kernel/irq.c
+++ b/arch/mips/kernel/irq.c
@@ -23,7 +23,6 @@
 #include <linux/ftrace.h>
 
 #include <linux/atomic.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 #ifdef CONFIG_KGDB
diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c
index 191eb52..972263b 100644
--- a/arch/mips/kernel/irq_cpu.c
+++ b/arch/mips/kernel/irq_cpu.c
@@ -35,7 +35,6 @@
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
 #include <asm/mipsmtregs.h>
-#include <asm/system.h>
 
 static inline void unmask_mips_irq(struct irq_data *d)
 {
diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c
index 29811f0..84d0639 100644
--- a/arch/mips/kernel/kspd.c
+++ b/arch/mips/kernel/kspd.c
@@ -326,7 +326,7 @@
 		i = j * __NFDBITS;
 		if (i >= fdt->max_fds)
 			break;
-		set = fdt->open_fds->fds_bits[j++];
+		set = fdt->open_fds[j++];
 		while (set) {
 			if (set & 1) {
 				struct file * file = xchg(&fdt->fd[i], NULL);
diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
index 802e616..33f63ba 100644
--- a/arch/mips/kernel/mips-mt-fpaff.c
+++ b/arch/mips/kernel/mips-mt-fpaff.c
@@ -173,7 +173,7 @@
 	if (retval)
 		goto out_unlock;
 
-	cpus_and(mask, p->thread.user_cpus_allowed, cpu_possible_map);
+	cpumask_and(&mask, &p->thread.user_cpus_allowed, cpu_possible_mask);
 
 out_unlock:
 	read_unlock(&tasklist_lock);
diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c
index c23d11f..7f3376b 100644
--- a/arch/mips/kernel/mips-mt.c
+++ b/arch/mips/kernel/mips-mt.c
@@ -13,7 +13,6 @@
 #include <asm/cpu.h>
 #include <asm/processor.h>
 #include <linux/atomic.h>
-#include <asm/system.h>
 #include <asm/hardirq.h>
 #include <asm/mmu_context.h>
 #include <asm/mipsmtregs.h>
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index e309665..f8b2c59 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -25,7 +25,7 @@
 	int i;
 
 #ifdef CONFIG_SMP
-	if (!cpu_isset(n, cpu_online_map))
+	if (!cpu_online(n))
 		return 0;
 #endif
 
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 61f1cb4..e9a5fd7 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -32,7 +32,6 @@
 #include <asm/dsp.h>
 #include <asm/fpu.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/mipsregs.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 7786b60..7c24c29 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -34,7 +34,6 @@
 #include <asm/mipsmtregs.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/bootinfo.h>
 #include <asm/reg.h>
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
index 32644b4..a3b0178 100644
--- a/arch/mips/kernel/ptrace32.c
+++ b/arch/mips/kernel/ptrace32.c
@@ -32,7 +32,6 @@
 #include <asm/mipsmtregs.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/bootinfo.h>
 
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index a9d801d..b8c18dc 100644
--- a/arch/mips/kernel/rtlx.c
+++ b/arch/mips/kernel/rtlx.c
@@ -38,7 +38,6 @@
 #include <linux/atomic.h>
 #include <asm/cpu.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/vpe.h>
 #include <asm/rtlx.h>
 
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 058e964..c504b21 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -31,7 +31,6 @@
 #include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/smp-ops.h>
-#include <asm/system.h>
 #include <asm/prom.h>
 
 struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly;
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index f852400..185ca00 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -34,6 +34,7 @@
 #include <asm/cpu-features.h>
 #include <asm/war.h>
 #include <asm/vdso.h>
+#include <asm/dsp.h>
 
 #include "signal-common.h"
 
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index aae9866..06b5da3 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -29,10 +29,10 @@
 #include <asm/cacheflush.h>
 #include <asm/sim.h>
 #include <asm/ucontext.h>
-#include <asm/system.h>
 #include <asm/fpu.h>
 #include <asm/war.h>
 #include <asm/vdso.h>
+#include <asm/dsp.h>
 
 #include "signal-common.h"
 
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index ee24d81..ae29e89 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -35,7 +35,6 @@
 #include <asm/sim.h>
 #include <asm/uaccess.h>
 #include <asm/ucontext.h>
-#include <asm/system.h>
 #include <asm/fpu.h>
 #include <asm/cpu-features.h>
 #include <asm/war.h>
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c
index d5e950a..3046e29 100644
--- a/arch/mips/kernel/smp-bmips.c
+++ b/arch/mips/kernel/smp-bmips.c
@@ -28,7 +28,6 @@
 #include <asm/time.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/bootinfo.h>
 #include <asm/pmon.h>
 #include <asm/cacheflush.h>
@@ -318,7 +317,7 @@
 
 	pr_info("SMP: CPU%d is offline\n", cpu);
 
-	cpu_clear(cpu, cpu_online_map);
+	set_cpu_online(cpu, false);
 	cpu_clear(cpu, cpu_callin_map);
 
 	local_flush_tlb_all();
diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c
index fe30951..e7e03ec 100644
--- a/arch/mips/kernel/smp-cmp.c
+++ b/arch/mips/kernel/smp-cmp.c
@@ -29,7 +29,6 @@
 #include <asm/cacheflush.h>
 #include <asm/cpu.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/hardirq.h>
 #include <asm/mmu_context.h>
 #include <asm/smp.h>
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c
index ce9e286..ff17868 100644
--- a/arch/mips/kernel/smp-mt.c
+++ b/arch/mips/kernel/smp-mt.c
@@ -28,7 +28,6 @@
 #include <asm/cacheflush.h>
 #include <asm/cpu.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/hardirq.h>
 #include <asm/mmu_context.h>
 #include <asm/time.h>
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 32c1e95..ba9376bf 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -38,9 +38,9 @@
 #include <asm/cpu.h>
 #include <asm/processor.h>
 #include <asm/r4k-timer.h>
-#include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/time.h>
+#include <asm/setup.h>
 
 #ifdef CONFIG_MIPS_MT_SMTC
 #include <asm/mipsmtregs.h>
@@ -148,7 +148,7 @@
 	/*
 	 * Remove this CPU:
 	 */
-	cpu_clear(smp_processor_id(), cpu_online_map);
+	set_cpu_online(smp_processor_id(), false);
 	for (;;) {
 		if (cpu_wait)
 			(*cpu_wait)();		/* Wait if available. */
@@ -174,7 +174,7 @@
 	mp_ops->prepare_cpus(max_cpus);
 	set_cpu_sibling_map(0);
 #ifndef CONFIG_HOTPLUG_CPU
-	init_cpu_present(&cpu_possible_map);
+	init_cpu_present(cpu_possible_mask);
 #endif
 }
 
@@ -248,7 +248,7 @@
 	while (!cpu_isset(cpu, cpu_callin_map))
 		udelay(100);
 
-	cpu_set(cpu, cpu_online_map);
+	set_cpu_online(cpu, true);
 
 	return 0;
 }
@@ -320,13 +320,12 @@
 	if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
 		smp_on_other_tlbs(flush_tlb_mm_ipi, mm);
 	} else {
-		cpumask_t mask = cpu_online_map;
 		unsigned int cpu;
 
-		cpu_clear(smp_processor_id(), mask);
-		for_each_cpu_mask(cpu, mask)
-			if (cpu_context(cpu, mm))
+		for_each_online_cpu(cpu) {
+			if (cpu != smp_processor_id() && cpu_context(cpu, mm))
 				cpu_context(cpu, mm) = 0;
+		}
 	}
 	local_flush_tlb_mm(mm);
 
@@ -360,13 +359,12 @@
 
 		smp_on_other_tlbs(flush_tlb_range_ipi, &fd);
 	} else {
-		cpumask_t mask = cpu_online_map;
 		unsigned int cpu;
 
-		cpu_clear(smp_processor_id(), mask);
-		for_each_cpu_mask(cpu, mask)
-			if (cpu_context(cpu, mm))
+		for_each_online_cpu(cpu) {
+			if (cpu != smp_processor_id() && cpu_context(cpu, mm))
 				cpu_context(cpu, mm) = 0;
+		}
 	}
 	local_flush_tlb_range(vma, start, end);
 	preempt_enable();
@@ -407,13 +405,12 @@
 
 		smp_on_other_tlbs(flush_tlb_page_ipi, &fd);
 	} else {
-		cpumask_t mask = cpu_online_map;
 		unsigned int cpu;
 
-		cpu_clear(smp_processor_id(), mask);
-		for_each_cpu_mask(cpu, mask)
-			if (cpu_context(cpu, vma->vm_mm))
+		for_each_online_cpu(cpu) {
+			if (cpu != smp_processor_id() && cpu_context(cpu, vma->vm_mm))
 				cpu_context(cpu, vma->vm_mm) = 0;
+		}
 	}
 	local_flush_tlb_page(vma, page);
 	preempt_enable();
diff --git a/arch/mips/kernel/smtc-proc.c b/arch/mips/kernel/smtc-proc.c
index 928a5a6..145771c 100644
--- a/arch/mips/kernel/smtc-proc.c
+++ b/arch/mips/kernel/smtc-proc.c
@@ -11,7 +11,6 @@
 #include <asm/cpu.h>
 #include <asm/processor.h>
 #include <linux/atomic.h>
-#include <asm/system.h>
 #include <asm/hardirq.h>
 #include <asm/mmu_context.h>
 #include <asm/mipsregs.h>
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index 0a42ff3..f5dd38f 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -31,7 +31,6 @@
 #include <asm/cpu.h>
 #include <asm/processor.h>
 #include <linux/atomic.h>
-#include <asm/system.h>
 #include <asm/hardirq.h>
 #include <asm/hazards.h>
 #include <asm/irq.h>
@@ -292,7 +291,7 @@
  * possibly leave some TCs/VPEs as "slave" processors.
  *
  * Use c0_MVPConf0 to find out how many TCs are available, setting up
- * cpu_possible_map and the logical/physical mappings.
+ * cpu_possible_mask and the logical/physical mappings.
  */
 
 int __init smtc_build_cpu_map(int start_cpu_slot)
diff --git a/arch/mips/kernel/spram.c b/arch/mips/kernel/spram.c
index 1821d12..6af08d8 100644
--- a/arch/mips/kernel/spram.c
+++ b/arch/mips/kernel/spram.c
@@ -15,7 +15,6 @@
 
 #include <asm/fpu.h>
 #include <asm/mipsregs.h>
-#include <asm/system.h>
 #include <asm/r4kcache.h>
 #include <asm/hazards.h>
 
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index d027657..b08220c 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -37,6 +37,7 @@
 #include <asm/shmparam.h>
 #include <asm/sysmips.h>
 #include <asm/uaccess.h>
+#include <asm/switch_to.h>
 
 /*
  * For historic reasons the pipe(2) syscall on MIPS has an unusual calling
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index d79ae54..cfdaaa4 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -45,7 +45,6 @@
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
 #include <asm/sections.h>
-#include <asm/system.h>
 #include <asm/tlbdebug.h>
 #include <asm/traps.h>
 #include <asm/uaccess.h>
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index aedb894..9c58bdf 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -85,7 +85,6 @@
 #include <asm/cop2.h>
 #include <asm/inst.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #define STR(x)  __STR(x)
 #define __STR(x)  #x
diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c
index e5cdfd6..0f1af58 100644
--- a/arch/mips/kernel/vdso.c
+++ b/arch/mips/kernel/vdso.c
@@ -88,8 +88,7 @@
 
 	ret = install_special_mapping(mm, addr, PAGE_SIZE,
 				      VM_READ|VM_EXEC|
-				      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-				      VM_ALWAYSDUMP,
+				      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
 				      &vdso_page);
 
 	if (ret)
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index bfa12a4..f6f9152 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -49,7 +49,6 @@
 #include <asm/cpu.h>
 #include <asm/mips_mt.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/vpe.h>
 #include <asm/kspd.h>
 
diff --git a/arch/mips/lasat/reset.c b/arch/mips/lasat/reset.c
index b1e7a89..e21f0b9 100644
--- a/arch/mips/lasat/reset.c
+++ b/arch/mips/lasat/reset.c
@@ -21,7 +21,6 @@
 #include <linux/pm.h>
 
 #include <asm/reboot.h>
-#include <asm/system.h>
 #include <asm/lasat/lasat.h>
 
 #include "picvue.h"
diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c
index 3c4a8c5..384a3b0 100644
--- a/arch/mips/math-emu/dsemul.c
+++ b/arch/mips/math-emu/dsemul.c
@@ -12,7 +12,6 @@
 #include <asm/uaccess.h>
 #include <asm/branch.h>
 #include <asm/mipsregs.h>
-#include <asm/system.h>
 #include <asm/cacheflush.h>
 
 #include <asm/fpu_emulator.h>
diff --git a/arch/mips/mipssim/sim_smtc.c b/arch/mips/mipssim/sim_smtc.c
index 9150639..3c104ab 100644
--- a/arch/mips/mipssim/sim_smtc.c
+++ b/arch/mips/mipssim/sim_smtc.c
@@ -28,7 +28,6 @@
 #include <asm/cpu.h>
 #include <asm/processor.h>
 #include <asm/smtc.h>
-#include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/smtc_ipi.h>
 
diff --git a/arch/mips/mipssim/sim_time.c b/arch/mips/mipssim/sim_time.c
index 5492c42..77bad3c 100644
--- a/arch/mips/mipssim/sim_time.c
+++ b/arch/mips/mipssim/sim_time.c
@@ -11,6 +11,7 @@
 #include <asm/hardirq.h>
 #include <asm/div64.h>
 #include <asm/cpu.h>
+#include <asm/setup.h>
 #include <asm/time.h>
 #include <asm/irq.h>
 #include <asm/mc146818-time.h>
diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c
index cf7895d..47037ec 100644
--- a/arch/mips/mm/c-octeon.c
+++ b/arch/mips/mm/c-octeon.c
@@ -21,7 +21,6 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/r4kcache.h>
-#include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/war.h>
 
@@ -81,9 +80,9 @@
 	if (vma)
 		mask = *mm_cpumask(vma->vm_mm);
 	else
-		mask = cpu_online_map;
-	cpu_clear(cpu, mask);
-	for_each_cpu_mask(cpu, mask)
+		mask = *cpu_online_mask;
+	cpumask_clear_cpu(cpu, &mask);
+	for_each_cpu(cpu, &mask)
 		octeon_send_ipi_single(cpu, SMP_ICACHE_FLUSH);
 
 	preempt_enable();
diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c
index 0765583..031c4c2 100644
--- a/arch/mips/mm/c-r3k.c
+++ b/arch/mips/mm/c-r3k.c
@@ -18,7 +18,6 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
-#include <asm/system.h>
 #include <asm/isadep.h>
 #include <asm/io.h>
 #include <asm/bootinfo.h>
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index c97087d..bda8eb2 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -29,7 +29,6 @@
 #include <asm/pgtable.h>
 #include <asm/r4kcache.h>
 #include <asm/sections.h>
-#include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/war.h>
 #include <asm/cacheflush.h> /* for run_uncached() */
diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c
index a43c197c..87d23ca 100644
--- a/arch/mips/mm/c-tx39.c
+++ b/arch/mips/mm/c-tx39.c
@@ -18,7 +18,6 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
-#include <asm/system.h>
 #include <asm/isadep.h>
 #include <asm/io.h>
 #include <asm/bootinfo.h>
diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c
index 4608491..3fab204 100644
--- a/arch/mips/mm/dma-default.c
+++ b/arch/mips/mm/dma-default.c
@@ -98,7 +98,7 @@
 EXPORT_SYMBOL(dma_alloc_noncoherent);
 
 static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
-	dma_addr_t * dma_handle, gfp_t gfp)
+	dma_addr_t * dma_handle, gfp_t gfp, struct dma_attrs *attrs)
 {
 	void *ret;
 
@@ -132,7 +132,7 @@
 EXPORT_SYMBOL(dma_free_noncoherent);
 
 static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
-	dma_addr_t dma_handle)
+	dma_addr_t dma_handle, struct dma_attrs *attrs)
 {
 	unsigned long addr = (unsigned long) vaddr;
 	int order = get_order(size);
@@ -323,8 +323,8 @@
 EXPORT_SYMBOL(dma_cache_sync);
 
 static struct dma_map_ops mips_default_dma_map_ops = {
-	.alloc_coherent = mips_dma_alloc_coherent,
-	.free_coherent = mips_dma_free_coherent,
+	.alloc = mips_dma_alloc_coherent,
+	.free = mips_dma_free_coherent,
 	.map_page = mips_dma_map_page,
 	.unmap_page = mips_dma_unmap_page,
 	.map_sg = mips_dma_map_sg,
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index 69ebd58..c14f6df 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -22,7 +22,6 @@
 
 #include <asm/branch.h>
 #include <asm/mmu_context.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/ptrace.h>
 #include <asm/highmem.h>		/* For VMALLOC_END */
diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c
index 36272f7..cc0b6268 100644
--- a/arch/mips/mm/page.c
+++ b/arch/mips/mm/page.c
@@ -22,7 +22,6 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/prefetch.h>
-#include <asm/system.h>
 #include <asm/bootinfo.h>
 #include <asm/mipsregs.h>
 #include <asm/mmu_context.h>
diff --git a/arch/mips/mm/sc-ip22.c b/arch/mips/mm/sc-ip22.c
index a6bd11f..1eb708e 100644
--- a/arch/mips/mm/sc-ip22.c
+++ b/arch/mips/mm/sc-ip22.c
@@ -12,7 +12,6 @@
 #include <asm/bcache.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/bootinfo.h>
 #include <asm/sgi/ip22.h>
 #include <asm/sgi/mc.h>
diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c
index 9cca8de..93d937b 100644
--- a/arch/mips/mm/sc-mips.c
+++ b/arch/mips/mm/sc-mips.c
@@ -11,7 +11,6 @@
 #include <asm/cacheops.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/r4kcache.h>
 
diff --git a/arch/mips/mm/sc-r5k.c b/arch/mips/mm/sc-r5k.c
index ae1e533..8d90ff2 100644
--- a/arch/mips/mm/sc-r5k.c
+++ b/arch/mips/mm/sc-r5k.c
@@ -12,7 +12,6 @@
 #include <asm/cacheops.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/r4kcache.h>
 
diff --git a/arch/mips/mm/tlb-r3k.c b/arch/mips/mm/tlb-r3k.c
index ed1fa46..a63d1ed 100644
--- a/arch/mips/mm/tlb-r3k.c
+++ b/arch/mips/mm/tlb-r3k.c
@@ -19,7 +19,6 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
-#include <asm/system.h>
 #include <asm/tlbmisc.h>
 #include <asm/isadep.h>
 #include <asm/io.h>
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index 2dc6253..d2572cb 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -18,7 +18,6 @@
 #include <asm/bootinfo.h>
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/tlbmisc.h>
 
 extern void build_tlb_refill_handler(void);
diff --git a/arch/mips/mm/tlb-r8k.c b/arch/mips/mm/tlb-r8k.c
index 3d95f76c..91c2499 100644
--- a/arch/mips/mm/tlb-r8k.c
+++ b/arch/mips/mm/tlb-r8k.c
@@ -17,7 +17,6 @@
 #include <asm/bootinfo.h>
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 
 extern void build_tlb_refill_handler(void);
 
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index e06370f..0bc485b 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -32,6 +32,7 @@
 #include <asm/pgtable.h>
 #include <asm/war.h>
 #include <asm/uasm.h>
+#include <asm/setup.h>
 
 /*
  * TLB load/store/modify handlers.
diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c
index 4b988b9..27a6cdb 100644
--- a/arch/mips/mti-malta/malta-init.c
+++ b/arch/mips/mti-malta/malta-init.c
@@ -26,7 +26,6 @@
 #include <asm/bootinfo.h>
 #include <asm/gt64120.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/cacheflush.h>
 #include <asm/smp-ops.h>
 #include <asm/traps.h>
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index a588b5c..7b13a4c 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -44,6 +44,7 @@
 #include <asm/msc01_ic.h>
 #include <asm/gic.h>
 #include <asm/gcmpregs.h>
+#include <asm/setup.h>
 
 int gcmp_present = -1;
 int gic_present;
diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c
index f8ee945..115f5bc 100644
--- a/arch/mips/mti-malta/malta-time.c
+++ b/arch/mips/mti-malta/malta-time.c
@@ -35,6 +35,7 @@
 #include <asm/irq.h>
 #include <asm/div64.h>
 #include <asm/cpu.h>
+#include <asm/setup.h>
 #include <asm/time.h>
 #include <asm/mc146818-time.h>
 #include <asm/msc01_ic.h>
diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c
index 49a4f6c..e52bfcb 100644
--- a/arch/mips/netlogic/common/irq.c
+++ b/arch/mips/netlogic/common/irq.c
@@ -43,7 +43,6 @@
 
 #include <asm/errno.h>
 #include <asm/signal.h>
-#include <asm/system.h>
 #include <asm/ptrace.h>
 #include <asm/mipsregs.h>
 #include <asm/thread_info.h>
diff --git a/arch/mips/netlogic/common/smp.c b/arch/mips/netlogic/common/smp.c
index db17f49..fab316d 100644
--- a/arch/mips/netlogic/common/smp.c
+++ b/arch/mips/netlogic/common/smp.c
@@ -165,7 +165,7 @@
 	cpu_set(boot_cpu, phys_cpu_present_map);
 	__cpu_number_map[boot_cpu] = 0;
 	__cpu_logical_map[0] = boot_cpu;
-	cpu_set(0, cpu_possible_map);
+	set_cpu_possible(0, true);
 
 	num_cpus = 1;
 	for (i = 0; i < NR_CPUS; i++) {
@@ -177,14 +177,14 @@
 			cpu_set(i, phys_cpu_present_map);
 			__cpu_number_map[i] = num_cpus;
 			__cpu_logical_map[num_cpus] = i;
-			cpu_set(num_cpus, cpu_possible_map);
+			set_cpu_possible(num_cpus, true);
 			++num_cpus;
 		}
 	}
 
 	pr_info("Phys CPU present map: %lx, possible map %lx\n",
 		(unsigned long)phys_cpu_present_map.bits[0],
-		(unsigned long)cpu_possible_map.bits[0]);
+		(unsigned long)cpumask_bits(cpu_possible_mask)[0]);
 
 	pr_info("Detected %i Slave CPU(s)\n", num_cpus);
 	nlm_set_nmi_handler(nlm_boot_secondary_cpus);
diff --git a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c
index acacd14..9553b14 100644
--- a/arch/mips/pci/fixup-cobalt.c
+++ b/arch/mips/pci/fixup-cobalt.c
@@ -51,67 +51,6 @@
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111,
 	 qube_raq_galileo_early_fixup);
 
-static void __devinit cobalt_legacy_ide_resource_fixup(struct pci_dev *dev,
-						       struct resource *res)
-{
-	struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
-	unsigned long offset = hose->io_offset;
-	struct resource orig = *res;
-
-	if (!(res->flags & IORESOURCE_IO) ||
-	    !(res->flags & IORESOURCE_PCI_FIXED))
-		return;
-
-	res->start -= offset;
-	res->end -= offset;
-	dev_printk(KERN_DEBUG, &dev->dev, "converted legacy %pR to bus %pR\n",
-		   &orig, res);
-}
-
-static void __devinit cobalt_legacy_ide_fixup(struct pci_dev *dev)
-{
-	u32 class;
-	u8 progif;
-
-	/*
-	 * If the IDE controller is in legacy mode, pci_setup_device() fills in
-	 * the resources with the legacy addresses that normally appear on the
-	 * PCI bus, just as if we had read them from a BAR.
-	 *
-	 * However, with the GT-64111, those legacy addresses, e.g., 0x1f0,
-	 * will never appear on the PCI bus because it converts memory accesses
-	 * in the PCI I/O region (which is never at address zero) into I/O port
-	 * accesses with no address translation.
-	 *
-	 * For example, if GT_DEF_PCI0_IO_BASE is 0x10000000, a load or store
-	 * to physical address 0x100001f0 will become a PCI access to I/O port
-	 * 0x100001f0.  There's no way to generate an access to I/O port 0x1f0,
-	 * but the VT82C586 IDE controller does respond at 0x100001f0 because
-	 * it only decodes the low 24 bits of the address.
-	 *
-	 * When this quirk runs, the pci_dev resources should contain bus
-	 * addresses, not Linux I/O port numbers, so convert legacy addresses
-	 * like 0x1f0 to bus addresses like 0x100001f0.  Later, we'll convert
-	 * them back with pcibios_fixup_bus() or pcibios_bus_to_resource().
-	 */
-	class = dev->class >> 8;
-	if (class != PCI_CLASS_STORAGE_IDE)
-		return;
-
-	pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
-	if ((progif & 1) == 0) {
-		cobalt_legacy_ide_resource_fixup(dev, &dev->resource[0]);
-		cobalt_legacy_ide_resource_fixup(dev, &dev->resource[1]);
-	}
-	if ((progif & 4) == 0) {
-		cobalt_legacy_ide_resource_fixup(dev, &dev->resource[2]);
-		cobalt_legacy_ide_resource_fixup(dev, &dev->resource[3]);
-	}
-}
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1,
-	  cobalt_legacy_ide_fixup);
-
 static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev)
 {
 	unsigned short cfgword;
diff --git a/arch/mips/pci/pci-bcm1480.c b/arch/mips/pci/pci-bcm1480.c
index af8c319..37b52dc 100644
--- a/arch/mips/pci/pci-bcm1480.c
+++ b/arch/mips/pci/pci-bcm1480.c
@@ -204,7 +204,7 @@
 	uint64_t reg;
 
 	/* CFE will assign PCI resources */
-	pci_probe_only = 1;
+	pci_set_flags(PCI_PROBE_ONLY);
 
 	/* Avoid ISA compat ranges.  */
 	PCIBIOS_MIN_IO = 0x00008000UL;
diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c
index 193e949..0fbe4c0 100644
--- a/arch/mips/pci/pci-ip27.c
+++ b/arch/mips/pci/pci-ip27.c
@@ -50,7 +50,7 @@
 	bridge_t *bridge;
 	int slot;
 
-	pci_probe_only = 1;
+	pci_set_flags(PCI_PROBE_ONLY);
 
 	printk("a bridge\n");
 
diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c
index be1e1af..030c77e 100644
--- a/arch/mips/pci/pci-lantiq.c
+++ b/arch/mips/pci/pci-lantiq.c
@@ -270,7 +270,8 @@
 {
 	struct ltq_pci_data *ltq_pci_data =
 		(struct ltq_pci_data *) pdev->dev.platform_data;
-	pci_probe_only = 0;
+
+	pci_clear_flags(PCI_PROBE_ONLY);
 	ltq_pci_irq_map = ltq_pci_data->irq;
 	ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE);
 	ltq_pci_mapped_cfg =
diff --git a/arch/mips/pci/pci-sb1250.c b/arch/mips/pci/pci-sb1250.c
index 1711e8e..dd97f3a 100644
--- a/arch/mips/pci/pci-sb1250.c
+++ b/arch/mips/pci/pci-sb1250.c
@@ -213,7 +213,7 @@
 	uint64_t reg;
 
 	/* CFE will assign PCI resources */
-	pci_probe_only = 1;
+	pci_set_flags(PCI_PROBE_ONLY);
 
 	/* Avoid ISA compat ranges.  */
 	PCIBIOS_MIN_IO = 0x00008000UL;
diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c
index 3d701a9..1644805 100644
--- a/arch/mips/pci/pci-xlr.c
+++ b/arch/mips/pci/pci-xlr.c
@@ -292,7 +292,7 @@
 static int __init pcibios_init(void)
 {
 	/* PSB assigns PCI resources */
-	pci_probe_only = 1;
+	pci_set_flags(PCI_PROBE_ONLY);
 	pci_config_base = ioremap(DEFAULT_PCI_CONFIG_BASE, 16 << 20);
 
 	/* Extend IO port for memory mapped io */
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 1552150..0514866 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -20,16 +20,9 @@
 #include <asm/cpu-info.h>
 
 /*
- * Indicate whether we respect the PCI setup left by the firmware.
- *
- * Make this long-lived  so that we know when shutting down
- * whether we probed only or not.
+ * If PCI_PROBE_ONLY in pci_flags is set, we don't change any PCI resource
+ * assignments.
  */
-int pci_probe_only;
-
-#define PCI_ASSIGN_ALL_BUSSES	1
-
-unsigned int pci_probe = PCI_ASSIGN_ALL_BUSSES;
 
 /*
  * The PCI controller list.
@@ -92,11 +85,12 @@
 	if (!hose->iommu)
 		PCI_DMA_BUS_IS_PHYS = 1;
 
-	if (hose->get_busno && pci_probe_only)
+	if (hose->get_busno && pci_has_flag(PCI_PROBE_ONLY))
 		next_busno = (*hose->get_busno)();
 
-	pci_add_resource(&resources, hose->mem_resource);
-	pci_add_resource(&resources, hose->io_resource);
+	pci_add_resource_offset(&resources,
+				hose->mem_resource, hose->mem_offset);
+	pci_add_resource_offset(&resources, hose->io_resource, hose->io_offset);
 	bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
 				&resources);
 	if (!bus)
@@ -115,7 +109,7 @@
 			need_domain_info = 1;
 		}
 
-		if (!pci_probe_only) {
+		if (!pci_has_flag(PCI_PROBE_ONLY)) {
 			pci_bus_size_bridges(bus);
 			pci_bus_assign_resources(bus);
 			pci_enable_bridges(bus);
@@ -241,7 +235,7 @@
 
 unsigned int pcibios_assign_all_busses(void)
 {
-	return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
+	return 1;
 }
 
 int pcibios_enable_device(struct pci_dev *dev, int mask)
@@ -254,42 +248,13 @@
 	return pcibios_plat_dev_init(dev);
 }
 
-static void pcibios_fixup_device_resources(struct pci_dev *dev,
-	struct pci_bus *bus)
-{
-	/* Update device resources.  */
-	struct pci_controller *hose = (struct pci_controller *)bus->sysdata;
-	unsigned long offset = 0;
-	int i;
-
-	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-		if (!dev->resource[i].start)
-			continue;
-		if (dev->resource[i].flags & IORESOURCE_IO)
-			offset = hose->io_offset;
-		else if (dev->resource[i].flags & IORESOURCE_MEM)
-			offset = hose->mem_offset;
-
-		dev->resource[i].start += offset;
-		dev->resource[i].end += offset;
-	}
-}
-
 void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
-	/* Propagate hose info into the subordinate devices.  */
-
 	struct pci_dev *dev = bus->self;
 
-	if (pci_probe_only && dev &&
+	if (pci_has_flag(PCI_PROBE_ONLY) && dev &&
 	    (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
 		pci_read_bridge_bases(bus);
-		pcibios_fixup_device_resources(dev, bus);
-	}
-
-	list_for_each_entry(dev, &bus->devices, bus_list) {
-		if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
-			pcibios_fixup_device_resources(dev, bus);
 	}
 }
 
@@ -299,40 +264,7 @@
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
 
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-			 struct resource *res)
-{
-	struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
-	unsigned long offset = 0;
-
-	if (res->flags & IORESOURCE_IO)
-		offset = hose->io_offset;
-	else if (res->flags & IORESOURCE_MEM)
-		offset = hose->mem_offset;
-
-	region->start = res->start - offset;
-	region->end = res->end - offset;
-}
-
-void __devinit
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-			struct pci_bus_region *region)
-{
-	struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
-	unsigned long offset = 0;
-
-	if (res->flags & IORESOURCE_IO)
-		offset = hose->io_offset;
-	else if (res->flags & IORESOURCE_MEM)
-		offset = hose->mem_offset;
-
-	res->start = region->start + offset;
-	res->end = region->end + offset;
-}
-
 #ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-EXPORT_SYMBOL(pcibios_bus_to_resource);
 EXPORT_SYMBOL(PCIBIOS_MIN_IO);
 EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
 #endif
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c b/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c
index c4fa2d7..2e6f7ca 100644
--- a/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c
+++ b/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c
@@ -16,7 +16,6 @@
 #include <linux/irq.h>
 
 #include <asm/mipsregs.h>
-#include <asm/system.h>
 
 #include <msp_cic_int.h>
 #include <msp_regs.h>
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c b/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c
index 98fd009..598b6a6 100644
--- a/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c
+++ b/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c
@@ -16,7 +16,6 @@
 #include <linux/bitops.h>
 
 #include <asm/mipsregs.h>
-#include <asm/system.h>
 
 #include <msp_cic_int.h>
 #include <msp_regs.h>
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c b/arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c
index 5bbcc47..83a1c5e 100644
--- a/arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c
+++ b/arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c
@@ -16,7 +16,6 @@
 #include <linux/bitops.h>
 
 #include <asm/mipsregs.h>
-#include <asm/system.h>
 
 #include <msp_slp_int.h>
 #include <msp_regs.h>
diff --git a/arch/mips/pmc-sierra/yosemite/irq.c b/arch/mips/pmc-sierra/yosemite/irq.c
index 25bbbf4..6590812 100644
--- a/arch/mips/pmc-sierra/yosemite/irq.c
+++ b/arch/mips/pmc-sierra/yosemite/irq.c
@@ -44,7 +44,6 @@
 #include <asm/irq.h>
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
-#include <asm/system.h>
 #include <asm/titan_dep.h>
 
 /* Hypertransport specific */
diff --git a/arch/mips/pmc-sierra/yosemite/prom.c b/arch/mips/pmc-sierra/yosemite/prom.c
index dcc926e..6a2754c 100644
--- a/arch/mips/pmc-sierra/yosemite/prom.c
+++ b/arch/mips/pmc-sierra/yosemite/prom.c
@@ -20,7 +20,6 @@
 #include <asm/processor.h>
 #include <asm/reboot.h>
 #include <asm/smp-ops.h>
-#include <asm/system.h>
 #include <asm/bootinfo.h>
 #include <asm/pmon.h>
 
diff --git a/arch/mips/pmc-sierra/yosemite/smp.c b/arch/mips/pmc-sierra/yosemite/smp.c
index 2608752..b71fae2 100644
--- a/arch/mips/pmc-sierra/yosemite/smp.c
+++ b/arch/mips/pmc-sierra/yosemite/smp.c
@@ -146,7 +146,7 @@
 }
 
 /*
- * Detect available CPUs, populate cpu_possible_map before smp_init
+ * Detect available CPUs, populate cpu_possible_mask before smp_init
  *
  * We don't want to start the secondary CPU yet nor do we have a nice probing
  * feature in PMON so we just assume presence of the secondary core.
@@ -155,10 +155,10 @@
 {
 	int i;
 
-	cpus_clear(cpu_possible_map);
+	init_cpu_possible(cpu_none_mask);
 
 	for (i = 0; i < 2; i++) {
-		cpu_set(i, cpu_possible_map);
+		set_cpu_possible(i, true);
 		__cpu_number_map[i]	= i;
 		__cpu_logical_map[i]	= i;
 	}
@@ -169,7 +169,7 @@
 	/*
 	 * Be paranoid.  Enable the IPI only if we're really about to go SMP.
 	 */
-	if (cpus_weight(cpu_possible_map))
+	if (num_possible_cpus())
 		set_c0_status(STATUSF_IP5);
 }
 
diff --git a/arch/mips/pnx833x/common/interrupts.c b/arch/mips/pnx833x/common/interrupts.c
index adc171c..a86d5d5 100644
--- a/arch/mips/pnx833x/common/interrupts.c
+++ b/arch/mips/pnx833x/common/interrupts.c
@@ -25,6 +25,7 @@
 #include <linux/interrupt.h>
 #include <asm/mipsregs.h>
 #include <asm/irq_cpu.h>
+#include <asm/setup.h>
 #include <irq.h>
 #include <irq-mapping.h>
 #include <gpio.h>
diff --git a/arch/mips/powertv/asic/asic_int.c b/arch/mips/powertv/asic/asic_int.c
index 529c44a..99d82e1 100644
--- a/arch/mips/powertv/asic/asic_int.c
+++ b/arch/mips/powertv/asic/asic_int.c
@@ -34,6 +34,7 @@
 #include <asm/irq_cpu.h>
 #include <linux/io.h>
 #include <asm/irq_regs.h>
+#include <asm/setup.h>
 #include <asm/mips-boards/generic.h>
 
 #include <asm/mach-powertv/asic_regs.h>
diff --git a/arch/mips/powertv/asic/irq_asic.c b/arch/mips/powertv/asic/irq_asic.c
index 7fb97fb..fa9ae95 100644
--- a/arch/mips/powertv/asic/irq_asic.c
+++ b/arch/mips/powertv/asic/irq_asic.c
@@ -17,7 +17,6 @@
 
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
-#include <asm/system.h>
 
 #include <asm/mach-powertv/asic_regs.h>
 
diff --git a/arch/mips/powertv/init.c b/arch/mips/powertv/init.c
index 8355228..1cf5abb 100644
--- a/arch/mips/powertv/init.c
+++ b/arch/mips/powertv/init.c
@@ -26,7 +26,6 @@
 
 #include <asm/bootinfo.h>
 #include <linux/io.h>
-#include <asm/system.h>
 #include <asm/cacheflush.h>
 #include <asm/traps.h>
 
diff --git a/arch/mips/rb532/irq.c b/arch/mips/rb532/irq.c
index 7c6db74..f298430 100644
--- a/arch/mips/rb532/irq.c
+++ b/arch/mips/rb532/irq.c
@@ -42,7 +42,6 @@
 #include <asm/bootinfo.h>
 #include <asm/time.h>
 #include <asm/mipsregs.h>
-#include <asm/system.h>
 
 #include <asm/mach-rc32434/irq.h>
 #include <asm/mach-rc32434/gpio.h>
diff --git a/arch/mips/sgi-ip22/ip22-berr.c b/arch/mips/sgi-ip22/ip22-berr.c
index 911d399..3f6ccd5 100644
--- a/arch/mips/sgi-ip22/ip22-berr.c
+++ b/arch/mips/sgi-ip22/ip22-berr.c
@@ -9,7 +9,6 @@
 #include <linux/sched.h>
 
 #include <asm/addrspace.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/branch.h>
 #include <asm/irq_regs.h>
diff --git a/arch/mips/sgi-ip22/ip22-reset.c b/arch/mips/sgi-ip22/ip22-reset.c
index 45b6694..20363d2 100644
--- a/arch/mips/sgi-ip22/ip22-reset.c
+++ b/arch/mips/sgi-ip22/ip22-reset.c
@@ -18,7 +18,6 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/reboot.h>
 #include <asm/sgialib.h>
 #include <asm/sgi/ioc.h>
diff --git a/arch/mips/sgi-ip22/ip28-berr.c b/arch/mips/sgi-ip22/ip28-berr.c
index 88c684e..0626555 100644
--- a/arch/mips/sgi-ip22/ip28-berr.c
+++ b/arch/mips/sgi-ip22/ip28-berr.c
@@ -11,7 +11,6 @@
 #include <linux/seq_file.h>
 
 #include <asm/addrspace.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/branch.h>
 #include <asm/irq_regs.h>
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c
index 2364223..69a939ae 100644
--- a/arch/mips/sgi-ip27/ip27-irq.c
+++ b/arch/mips/sgi-ip27/ip27-irq.c
@@ -27,7 +27,6 @@
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
-#include <asm/system.h>
 
 #include <asm/processor.h>
 #include <asm/pci/bridge.h>
diff --git a/arch/mips/sgi-ip27/ip27-reset.c b/arch/mips/sgi-ip27/ip27-reset.c
index c170761..f347bc6 100644
--- a/arch/mips/sgi-ip27/ip27-reset.c
+++ b/arch/mips/sgi-ip27/ip27-reset.c
@@ -19,7 +19,6 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/reboot.h>
-#include <asm/system.h>
 #include <asm/sgialib.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/arch.h>
diff --git a/arch/mips/sgi-ip27/ip27-smp.c b/arch/mips/sgi-ip27/ip27-smp.c
index c6851df..735b43b 100644
--- a/arch/mips/sgi-ip27/ip27-smp.c
+++ b/arch/mips/sgi-ip27/ip27-smp.c
@@ -76,7 +76,7 @@
 			/* Only let it join in if it's marked enabled */
 			if ((acpu->cpu_info.flags & KLINFO_ENABLE) &&
 			    (tot_cpus_found != NR_CPUS)) {
-				cpu_set(cpuid, cpu_possible_map);
+				set_cpu_possible(cpuid, true);
 				alloc_cpupda(cpuid, tot_cpus_found);
 				cpus_found++;
 				tot_cpus_found++;
diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c
index a092860..e7d5054 100644
--- a/arch/mips/sgi-ip32/ip32-irq.c
+++ b/arch/mips/sgi-ip32/ip32-irq.c
@@ -22,7 +22,6 @@
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
 #include <asm/signal.h>
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/ip32/crime.h>
 #include <asm/ip32/mace.h>
diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c
index 9b95d80..1f823da 100644
--- a/arch/mips/sgi-ip32/ip32-reset.c
+++ b/arch/mips/sgi-ip32/ip32-reset.c
@@ -20,7 +20,6 @@
 #include <asm/addrspace.h>
 #include <asm/irq.h>
 #include <asm/reboot.h>
-#include <asm/system.h>
 #include <asm/wbflush.h>
 #include <asm/ip32/mace.h>
 #include <asm/ip32/crime.h>
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c
index 09740d6..215713e 100644
--- a/arch/mips/sibyte/bcm1480/irq.c
+++ b/arch/mips/sibyte/bcm1480/irq.c
@@ -27,7 +27,6 @@
 #include <asm/errno.h>
 #include <asm/irq_regs.h>
 #include <asm/signal.h>
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include <asm/sibyte/bcm1480_regs.h>
diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c
index d667875..de88e22 100644
--- a/arch/mips/sibyte/bcm1480/smp.c
+++ b/arch/mips/sibyte/bcm1480/smp.c
@@ -138,7 +138,7 @@
 
 /*
  * Use CFE to find out how many CPUs are available, setting up
- * cpu_possible_map and the logical/physical mappings.
+ * cpu_possible_mask and the logical/physical mappings.
  * XXXKW will the boot CPU ever not be physical 0?
  *
  * Common setup before any secondaries are started
@@ -147,14 +147,13 @@
 {
 	int i, num;
 
-	cpus_clear(cpu_possible_map);
-	cpu_set(0, cpu_possible_map);
+	init_cpu_possible(cpumask_of(0));
 	__cpu_number_map[0] = 0;
 	__cpu_logical_map[0] = 0;
 
 	for (i = 1, num = 0; i < NR_CPUS; i++) {
 		if (cfe_cpu_stop(i) == 0) {
-			cpu_set(i, cpu_possible_map);
+			set_cpu_possible(i, true);
 			__cpu_number_map[i] = ++num;
 			__cpu_logical_map[num] = i;
 		}
diff --git a/arch/mips/sibyte/common/sb_tbprof.c b/arch/mips/sibyte/common/sb_tbprof.c
index 48853ab..e8c4538 100644
--- a/arch/mips/sibyte/common/sb_tbprof.c
+++ b/arch/mips/sibyte/common/sb_tbprof.c
@@ -53,7 +53,6 @@
 #define K_INT_PERF_CNT K_BCM1480_INT_PERF_CNT
 #endif
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 #define SBPROF_TB_MAJOR 240
diff --git a/arch/mips/sibyte/sb1250/bus_watcher.c b/arch/mips/sibyte/sb1250/bus_watcher.c
index 45274bd..86e6e54 100644
--- a/arch/mips/sibyte/sb1250/bus_watcher.c
+++ b/arch/mips/sibyte/sb1250/bus_watcher.c
@@ -30,7 +30,6 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include <asm/sibyte/sb1250.h>
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c
index 76ee045..340aaf6 100644
--- a/arch/mips/sibyte/sb1250/irq.c
+++ b/arch/mips/sibyte/sb1250/irq.c
@@ -26,7 +26,6 @@
 
 #include <asm/errno.h>
 #include <asm/signal.h>
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/io.h>
 
diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c
index 38e7f6b..285cfef 100644
--- a/arch/mips/sibyte/sb1250/smp.c
+++ b/arch/mips/sibyte/sb1250/smp.c
@@ -126,7 +126,7 @@
 
 /*
  * Use CFE to find out how many CPUs are available, setting up
- * cpu_possible_map and the logical/physical mappings.
+ * cpu_possible_mask and the logical/physical mappings.
  * XXXKW will the boot CPU ever not be physical 0?
  *
  * Common setup before any secondaries are started
@@ -135,14 +135,13 @@
 {
 	int i, num;
 
-	cpus_clear(cpu_possible_map);
-	cpu_set(0, cpu_possible_map);
+	init_cpu_possible(cpumask_of(0));
 	__cpu_number_map[0] = 0;
 	__cpu_logical_map[0] = 0;
 
 	for (i = 1, num = 0; i < NR_CPUS; i++) {
 		if (cfe_cpu_stop(i) == 0) {
-			cpu_set(i, cpu_possible_map);
+			set_cpu_possible(i, true);
 			__cpu_number_map[i] = ++num;
 			__cpu_logical_map[num] = i;
 		}
diff --git a/arch/mips/sni/reset.c b/arch/mips/sni/reset.c
index 79f8d70..244f942 100644
--- a/arch/mips/sni/reset.c
+++ b/arch/mips/sni/reset.c
@@ -5,7 +5,6 @@
  */
 #include <asm/io.h>
 #include <asm/reboot.h>
-#include <asm/system.h>
 #include <asm/sni.h>
 
 /*
diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c
index fad2bef..ae0e4ee 100644
--- a/arch/mips/vr41xx/common/irq.c
+++ b/arch/mips/vr41xx/common/irq.c
@@ -22,7 +22,6 @@
 #include <linux/irq.h>
 
 #include <asm/irq_cpu.h>
-#include <asm/system.h>
 #include <asm/vr41xx/irq.h>
 
 typedef struct irq_cascade {
diff --git a/arch/mips/vr41xx/common/pmu.c b/arch/mips/vr41xx/common/pmu.c
index 692b4e8..9fbf5f0 100644
--- a/arch/mips/vr41xx/common/pmu.c
+++ b/arch/mips/vr41xx/common/pmu.c
@@ -30,7 +30,6 @@
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/reboot.h>
-#include <asm/system.h>
 
 #define PMU_TYPE1_BASE	0x0b0000a0UL
 #define PMU_TYPE1_SIZE	0x0eUL
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index 8f1c40d..3aa3de0 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -5,6 +5,7 @@
 	select GENERIC_IRQ_SHOW
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_ARCH_KGDB
+	select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER
 
 config AM33_2
 	def_bool n
diff --git a/arch/mn10300/include/asm/atomic.h b/arch/mn10300/include/asm/atomic.h
index b9a8f84..975e184 100644
--- a/arch/mn10300/include/asm/atomic.h
+++ b/arch/mn10300/include/asm/atomic.h
@@ -12,112 +12,7 @@
 #define _ASM_ATOMIC_H
 
 #include <asm/irqflags.h>
-
-#ifndef __ASSEMBLY__
-
-#ifdef CONFIG_SMP
-#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
-static inline
-unsigned long __xchg(volatile unsigned long *m, unsigned long val)
-{
-	unsigned long status;
-	unsigned long oldval;
-
-	asm volatile(
-		"1:	mov	%4,(_AAR,%3)	\n"
-		"	mov	(_ADR,%3),%1	\n"
-		"	mov	%5,(_ADR,%3)	\n"
-		"	mov	(_ADR,%3),%0	\n"	/* flush */
-		"	mov	(_ASR,%3),%0	\n"
-		"	or	%0,%0		\n"
-		"	bne	1b		\n"
-		: "=&r"(status), "=&r"(oldval), "=m"(*m)
-		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(m), "r"(val)
-		: "memory", "cc");
-
-	return oldval;
-}
-
-static inline unsigned long __cmpxchg(volatile unsigned long *m,
-				      unsigned long old, unsigned long new)
-{
-	unsigned long status;
-	unsigned long oldval;
-
-	asm volatile(
-		"1:	mov	%4,(_AAR,%3)	\n"
-		"	mov	(_ADR,%3),%1	\n"
-		"	cmp	%5,%1		\n"
-		"	bne	2f		\n"
-		"	mov	%6,(_ADR,%3)	\n"
-		"2:	mov	(_ADR,%3),%0	\n"	/* flush */
-		"	mov	(_ASR,%3),%0	\n"
-		"	or	%0,%0		\n"
-		"	bne	1b		\n"
-		: "=&r"(status), "=&r"(oldval), "=m"(*m)
-		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(m),
-		  "r"(old), "r"(new)
-		: "memory", "cc");
-
-	return oldval;
-}
-#else  /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
-#error "No SMP atomic operation support!"
-#endif /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
-
-#else  /* CONFIG_SMP */
-
-/*
- * Emulate xchg for non-SMP MN10300
- */
-struct __xchg_dummy { unsigned long a[100]; };
-#define __xg(x) ((struct __xchg_dummy *)(x))
-
-static inline
-unsigned long __xchg(volatile unsigned long *m, unsigned long val)
-{
-	unsigned long oldval;
-	unsigned long flags;
-
-	flags = arch_local_cli_save();
-	oldval = *m;
-	*m = val;
-	arch_local_irq_restore(flags);
-	return oldval;
-}
-
-/*
- * Emulate cmpxchg for non-SMP MN10300
- */
-static inline unsigned long __cmpxchg(volatile unsigned long *m,
-				      unsigned long old, unsigned long new)
-{
-	unsigned long oldval;
-	unsigned long flags;
-
-	flags = arch_local_cli_save();
-	oldval = *m;
-	if (oldval == old)
-		*m = new;
-	arch_local_irq_restore(flags);
-	return oldval;
-}
-
-#endif /* CONFIG_SMP */
-
-#define xchg(ptr, v)						\
-	((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr),	\
-				     (unsigned long)(v)))
-
-#define cmpxchg(ptr, o, n)					\
-	((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \
-					(unsigned long)(o),	\
-					(unsigned long)(n)))
-
-#define atomic_xchg(ptr, v)		(xchg(&(ptr)->counter, (v)))
-#define atomic_cmpxchg(v, old, new)	(cmpxchg(&((v)->counter), (old), (new)))
-
-#endif /* !__ASSEMBLY__ */
+#include <asm/cmpxchg.h>
 
 #ifndef CONFIG_SMP
 #include <asm-generic/atomic.h>
@@ -269,6 +164,8 @@
 	c;							\
 })
 
+#define atomic_xchg(ptr, v)		(xchg(&(ptr)->counter, (v)))
+#define atomic_cmpxchg(v, old, new)	(cmpxchg(&((v)->counter), (old), (new)))
 
 /**
  * atomic_clear_mask - Atomically clear bits in memory
diff --git a/arch/mn10300/include/asm/barrier.h b/arch/mn10300/include/asm/barrier.h
new file mode 100644
index 0000000..2bd97a5
--- /dev/null
+++ b/arch/mn10300/include/asm/barrier.h
@@ -0,0 +1,37 @@
+/* MN10300 memory barrier definitions
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef _ASM_BARRIER_H
+#define _ASM_BARRIER_H
+
+#define nop()	asm volatile ("nop")
+
+#define mb()	asm volatile ("": : :"memory")
+#define rmb()	mb()
+#define wmb()	asm volatile ("": : :"memory")
+
+#ifdef CONFIG_SMP
+#define smp_mb()	mb()
+#define smp_rmb()	rmb()
+#define smp_wmb()	wmb()
+#define set_mb(var, value)  do { xchg(&var, value); } while (0)
+#else  /* CONFIG_SMP */
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+#define set_mb(var, value)  do { var = value;  mb(); } while (0)
+#endif /* CONFIG_SMP */
+
+#define set_wmb(var, value) do { var = value; wmb(); } while (0)
+
+#define read_barrier_depends()		do {} while (0)
+#define smp_read_barrier_depends()	do {} while (0)
+
+#endif /* _ASM_BARRIER_H */
diff --git a/arch/mn10300/include/asm/cmpxchg.h b/arch/mn10300/include/asm/cmpxchg.h
new file mode 100644
index 0000000..97a4aaf
--- /dev/null
+++ b/arch/mn10300/include/asm/cmpxchg.h
@@ -0,0 +1,115 @@
+/* MN10300 Atomic xchg/cmpxchg operations
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef _ASM_CMPXCHG_H
+#define _ASM_CMPXCHG_H
+
+#include <asm/irqflags.h>
+
+#ifdef CONFIG_SMP
+#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+static inline
+unsigned long __xchg(volatile unsigned long *m, unsigned long val)
+{
+	unsigned long status;
+	unsigned long oldval;
+
+	asm volatile(
+		"1:	mov	%4,(_AAR,%3)	\n"
+		"	mov	(_ADR,%3),%1	\n"
+		"	mov	%5,(_ADR,%3)	\n"
+		"	mov	(_ADR,%3),%0	\n"	/* flush */
+		"	mov	(_ASR,%3),%0	\n"
+		"	or	%0,%0		\n"
+		"	bne	1b		\n"
+		: "=&r"(status), "=&r"(oldval), "=m"(*m)
+		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(m), "r"(val)
+		: "memory", "cc");
+
+	return oldval;
+}
+
+static inline unsigned long __cmpxchg(volatile unsigned long *m,
+				      unsigned long old, unsigned long new)
+{
+	unsigned long status;
+	unsigned long oldval;
+
+	asm volatile(
+		"1:	mov	%4,(_AAR,%3)	\n"
+		"	mov	(_ADR,%3),%1	\n"
+		"	cmp	%5,%1		\n"
+		"	bne	2f		\n"
+		"	mov	%6,(_ADR,%3)	\n"
+		"2:	mov	(_ADR,%3),%0	\n"	/* flush */
+		"	mov	(_ASR,%3),%0	\n"
+		"	or	%0,%0		\n"
+		"	bne	1b		\n"
+		: "=&r"(status), "=&r"(oldval), "=m"(*m)
+		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(m),
+		  "r"(old), "r"(new)
+		: "memory", "cc");
+
+	return oldval;
+}
+#else  /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
+#error "No SMP atomic operation support!"
+#endif /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
+
+#else  /* CONFIG_SMP */
+
+/*
+ * Emulate xchg for non-SMP MN10300
+ */
+struct __xchg_dummy { unsigned long a[100]; };
+#define __xg(x) ((struct __xchg_dummy *)(x))
+
+static inline
+unsigned long __xchg(volatile unsigned long *m, unsigned long val)
+{
+	unsigned long oldval;
+	unsigned long flags;
+
+	flags = arch_local_cli_save();
+	oldval = *m;
+	*m = val;
+	arch_local_irq_restore(flags);
+	return oldval;
+}
+
+/*
+ * Emulate cmpxchg for non-SMP MN10300
+ */
+static inline unsigned long __cmpxchg(volatile unsigned long *m,
+				      unsigned long old, unsigned long new)
+{
+	unsigned long oldval;
+	unsigned long flags;
+
+	flags = arch_local_cli_save();
+	oldval = *m;
+	if (oldval == old)
+		*m = new;
+	arch_local_irq_restore(flags);
+	return oldval;
+}
+
+#endif /* CONFIG_SMP */
+
+#define xchg(ptr, v)						\
+	((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr),	\
+				     (unsigned long)(v)))
+
+#define cmpxchg(ptr, o, n)					\
+	((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \
+					(unsigned long)(o),	\
+					(unsigned long)(n)))
+
+#endif /* _ASM_CMPXCHG_H */
diff --git a/arch/mn10300/include/asm/dma.h b/arch/mn10300/include/asm/dma.h
index 098df2e..10b77d4 100644
--- a/arch/mn10300/include/asm/dma.h
+++ b/arch/mn10300/include/asm/dma.h
@@ -11,7 +11,6 @@
 #ifndef _ASM_DMA_H
 #define _ASM_DMA_H
 
-#include <asm/system.h>
 #include <linux/spinlock.h>
 #include <asm/io.h>
 #include <linux/delay.h>
diff --git a/arch/mn10300/include/asm/exec.h b/arch/mn10300/include/asm/exec.h
new file mode 100644
index 0000000..c74e367
--- /dev/null
+++ b/arch/mn10300/include/asm/exec.h
@@ -0,0 +1,16 @@
+/* MN10300 process execution definitions
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef _ASM_EXEC_H
+#define _ASM_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* _ASM_EXEC_H */
diff --git a/arch/mn10300/include/asm/pci.h b/arch/mn10300/include/asm/pci.h
index 6095a28..8137c25 100644
--- a/arch/mn10300/include/asm/pci.h
+++ b/arch/mn10300/include/asm/pci.h
@@ -85,22 +85,6 @@
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
 #include <asm-generic/pci-dma-compat.h>
 
-/**
- * pcibios_resource_to_bus - convert resource to PCI bus address
- * @dev: device which owns this resource
- * @region: converted bus-centric region (start,end)
- * @res: resource to convert
- *
- * Convert a resource to a PCI device bus address or bus window.
- */
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
-				    struct pci_bus_region *region,
-				    struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev,
-				    struct resource *res,
-				    struct pci_bus_region *region);
-
 static inline struct resource *
 pcibios_select_root(struct pci_dev *pdev, struct resource *res)
 {
diff --git a/arch/mn10300/include/asm/posix_types.h b/arch/mn10300/include/asm/posix_types.h
index 56ffbc1..ab50618 100644
--- a/arch/mn10300/include/asm/posix_types.h
+++ b/arch/mn10300/include/asm/posix_types.h
@@ -17,14 +17,19 @@
  * assume GCC is being used.
  */
 
-typedef unsigned long	__kernel_ino_t;
 typedef unsigned short	__kernel_mode_t;
+#define __kernel_mode_t __kernel_mode_t
+
 typedef unsigned short	__kernel_nlink_t;
-typedef long		__kernel_off_t;
-typedef int		__kernel_pid_t;
+#define __kernel_nlink_t __kernel_nlink_t
+
 typedef unsigned short	__kernel_ipc_pid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
+
 typedef unsigned short	__kernel_uid_t;
 typedef unsigned short	__kernel_gid_t;
+#define __kernel_uid_t __kernel_uid_t
+
 #if __GNUC__ == 4
 typedef unsigned int	__kernel_size_t;
 typedef signed int	__kernel_ssize_t;
@@ -33,105 +38,11 @@
 typedef signed long	__kernel_ssize_t;
 #endif
 typedef int		__kernel_ptrdiff_t;
-typedef long		__kernel_time_t;
-typedef long		__kernel_suseconds_t;
-typedef long		__kernel_clock_t;
-typedef int		__kernel_timer_t;
-typedef int		__kernel_clockid_t;
-typedef int		__kernel_daddr_t;
-typedef char *		__kernel_caddr_t;
-typedef unsigned short	__kernel_uid16_t;
-typedef unsigned short	__kernel_gid16_t;
-typedef unsigned int	__kernel_uid32_t;
-typedef unsigned int	__kernel_gid32_t;
+#define __kernel_size_t __kernel_size_t
 
-typedef unsigned short	__kernel_old_uid_t;
-typedef unsigned short	__kernel_old_gid_t;
 typedef unsigned short	__kernel_old_dev_t;
+#define __kernel_old_dev_t __kernel_old_dev_t
 
-#ifdef __GNUC__
-typedef long long	__kernel_loff_t;
-#endif
-
-typedef struct {
-#if defined(__KERNEL__) || defined(__USE_ALL)
-	int	val[2];
-#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
-	int	__val[2];
-#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
-} __kernel_fsid_t;
-
-#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
-
-#undef	__FD_SET
-static inline void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-	unsigned long __tmp = __fd / __NFDBITS;
-	unsigned long __rem = __fd % __NFDBITS;
-	__fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
-}
-
-#undef	__FD_CLR
-static inline void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-	unsigned long __tmp = __fd / __NFDBITS;
-	unsigned long __rem = __fd % __NFDBITS;
-	__fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
-}
-
-
-#undef	__FD_ISSET
-static inline int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
-{
-	unsigned long __tmp = __fd / __NFDBITS;
-	unsigned long __rem = __fd % __NFDBITS;
-	return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
-}
-
-/*
- * This will unroll the loop for the normal constant case (8 ints,
- * for a 256-bit fd_set)
- */
-#undef	__FD_ZERO
-static inline void __FD_ZERO(__kernel_fd_set *__p)
-{
-	unsigned long *__tmp = __p->fds_bits;
-	int __i;
-
-	if (__builtin_constant_p(__FDSET_LONGS)) {
-		switch (__FDSET_LONGS) {
-		case 16:
-			__tmp[ 0] = 0; __tmp[ 1] = 0;
-			__tmp[ 2] = 0; __tmp[ 3] = 0;
-			__tmp[ 4] = 0; __tmp[ 5] = 0;
-			__tmp[ 6] = 0; __tmp[ 7] = 0;
-			__tmp[ 8] = 0; __tmp[ 9] = 0;
-			__tmp[10] = 0; __tmp[11] = 0;
-			__tmp[12] = 0; __tmp[13] = 0;
-			__tmp[14] = 0; __tmp[15] = 0;
-			return;
-
-		case 8:
-			__tmp[ 0] = 0; __tmp[ 1] = 0;
-			__tmp[ 2] = 0; __tmp[ 3] = 0;
-			__tmp[ 4] = 0; __tmp[ 5] = 0;
-			__tmp[ 6] = 0; __tmp[ 7] = 0;
-			return;
-
-		case 4:
-			__tmp[ 0] = 0; __tmp[ 1] = 0;
-			__tmp[ 2] = 0; __tmp[ 3] = 0;
-			return;
-		}
-	}
-	__i = __FDSET_LONGS;
-	while (__i) {
-		__i--;
-		*__tmp = 0;
-		__tmp++;
-	}
-}
-
-#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
+#include <asm-generic/posix_types.h>
 
 #endif /* _ASM_POSIX_TYPES_H */
diff --git a/arch/mn10300/include/asm/reset-regs.h b/arch/mn10300/include/asm/reset-regs.h
index 10c7502..8ca2a42 100644
--- a/arch/mn10300/include/asm/reset-regs.h
+++ b/arch/mn10300/include/asm/reset-regs.h
@@ -17,10 +17,6 @@
 
 #ifdef __KERNEL__
 
-#ifdef CONFIG_MN10300_WD_TIMER
-#define ARCH_HAS_NMI_WATCHDOG		/* See include/linux/nmi.h */
-#endif
-
 /*
  * watchdog timer registers
  */
diff --git a/arch/mn10300/include/asm/switch_to.h b/arch/mn10300/include/asm/switch_to.h
new file mode 100644
index 0000000..393d311
--- /dev/null
+++ b/arch/mn10300/include/asm/switch_to.h
@@ -0,0 +1,49 @@
+/* MN10300 task switching definitions
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef _ASM_SWITCH_TO_H
+#define _ASM_SWITCH_TO_H
+
+#include <asm/barrier.h>
+
+struct task_struct;
+struct thread_struct;
+
+#if !defined(CONFIG_LAZY_SAVE_FPU)
+struct fpu_state_struct;
+extern asmlinkage void fpu_save(struct fpu_state_struct *);
+#define switch_fpu(prev, next)						\
+	do {								\
+		if ((prev)->thread.fpu_flags & THREAD_HAS_FPU) {	\
+			(prev)->thread.fpu_flags &= ~THREAD_HAS_FPU;	\
+			(prev)->thread.uregs->epsw &= ~EPSW_FE;		\
+			fpu_save(&(prev)->thread.fpu_state);		\
+		}							\
+	} while (0)
+#else
+#define switch_fpu(prev, next) do {} while (0)
+#endif
+
+/* context switching is now performed out-of-line in switch_to.S */
+extern asmlinkage
+struct task_struct *__switch_to(struct thread_struct *prev,
+				struct thread_struct *next,
+				struct task_struct *prev_task);
+
+#define switch_to(prev, next, last)					\
+do {									\
+	switch_fpu(prev, next);						\
+	current->thread.wchan = (u_long) __builtin_return_address(0);	\
+	(last) = __switch_to(&(prev)->thread, &(next)->thread, (prev));	\
+	mb();								\
+	current->thread.wchan = 0;					\
+} while (0)
+
+#endif /* _ASM_SWITCH_TO_H */
diff --git a/arch/mn10300/include/asm/system.h b/arch/mn10300/include/asm/system.h
deleted file mode 100644
index 94b4c5e..0000000
--- a/arch/mn10300/include/asm/system.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/* MN10300 System definitions
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-#ifndef _ASM_SYSTEM_H
-#define _ASM_SYSTEM_H
-
-#include <asm/cpu-regs.h>
-#include <asm/intctl-regs.h>
-
-#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
-
-#include <linux/kernel.h>
-#include <linux/irqflags.h>
-#include <linux/atomic.h>
-
-#if !defined(CONFIG_LAZY_SAVE_FPU)
-struct fpu_state_struct;
-extern asmlinkage void fpu_save(struct fpu_state_struct *);
-#define switch_fpu(prev, next)						\
-	do {								\
-		if ((prev)->thread.fpu_flags & THREAD_HAS_FPU) {	\
-			(prev)->thread.fpu_flags &= ~THREAD_HAS_FPU;	\
-			(prev)->thread.uregs->epsw &= ~EPSW_FE;		\
-			fpu_save(&(prev)->thread.fpu_state);		\
-		}							\
-	} while (0)
-#else
-#define switch_fpu(prev, next) do {} while (0)
-#endif
-
-struct task_struct;
-struct thread_struct;
-
-extern asmlinkage
-struct task_struct *__switch_to(struct thread_struct *prev,
-				struct thread_struct *next,
-				struct task_struct *prev_task);
-
-/* context switching is now performed out-of-line in switch_to.S */
-#define switch_to(prev, next, last)					\
-do {									\
-	switch_fpu(prev, next);						\
-	current->thread.wchan = (u_long) __builtin_return_address(0);	\
-	(last) = __switch_to(&(prev)->thread, &(next)->thread, (prev));	\
-	mb();								\
-	current->thread.wchan = 0;					\
-} while (0)
-
-#define arch_align_stack(x) (x)
-
-#define nop() asm volatile ("nop")
-
-/*
- * Force strict CPU ordering.
- * And yes, this is required on UP too when we're talking
- * to devices.
- *
- * For now, "wmb()" doesn't actually do anything, as all
- * Intel CPU's follow what Intel calls a *Processor Order*,
- * in which all writes are seen in the program order even
- * outside the CPU.
- *
- * I expect future Intel CPU's to have a weaker ordering,
- * but I'd also expect them to finally get their act together
- * and add some real memory barriers if so.
- *
- * Some non intel clones support out of order store. wmb() ceases to be a
- * nop for these.
- */
-
-#define mb()	asm volatile ("": : :"memory")
-#define rmb()	mb()
-#define wmb()	asm volatile ("": : :"memory")
-
-#ifdef CONFIG_SMP
-#define smp_mb()	mb()
-#define smp_rmb()	rmb()
-#define smp_wmb()	wmb()
-#define set_mb(var, value)  do { xchg(&var, value); } while (0)
-#else  /* CONFIG_SMP */
-#define smp_mb()	barrier()
-#define smp_rmb()	barrier()
-#define smp_wmb()	barrier()
-#define set_mb(var, value)  do { var = value;  mb(); } while (0)
-#endif /* CONFIG_SMP */
-
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
-
-#define read_barrier_depends()		do {} while (0)
-#define smp_read_barrier_depends()	do {} while (0)
-
-#endif /* !__ASSEMBLY__ */
-#endif /* __KERNEL__ */
-#endif /* _ASM_SYSTEM_H */
diff --git a/arch/mn10300/kernel/entry.S b/arch/mn10300/kernel/entry.S
index 3e3620d..8e11f9f 100644
--- a/arch/mn10300/kernel/entry.S
+++ b/arch/mn10300/kernel/entry.S
@@ -15,7 +15,6 @@
 #include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/smp.h>
-#include <asm/system.h>
 #include <asm/irqflags.h>
 #include <asm/thread_info.h>
 #include <asm/intctl-regs.h>
diff --git a/arch/mn10300/kernel/fpu.c b/arch/mn10300/kernel/fpu.c
index bb5fa7d..064fa19 100644
--- a/arch/mn10300/kernel/fpu.c
+++ b/arch/mn10300/kernel/fpu.c
@@ -12,7 +12,6 @@
 #include <asm/fpu.h>
 #include <asm/elf.h>
 #include <asm/exceptions.h>
-#include <asm/system.h>
 
 #ifdef CONFIG_LAZY_SAVE_FPU
 struct task_struct *fpu_state_owner;
diff --git a/arch/mn10300/kernel/gdb-io-serial.c b/arch/mn10300/kernel/gdb-io-serial.c
index f28dc99..df51242 100644
--- a/arch/mn10300/kernel/gdb-io-serial.c
+++ b/arch/mn10300/kernel/gdb-io-serial.c
@@ -18,7 +18,6 @@
 #include <linux/nmi.h>
 
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/gdb-stub.h>
 #include <asm/exceptions.h>
 #include <asm/serial-regs.h>
diff --git a/arch/mn10300/kernel/gdb-io-ttysm.c b/arch/mn10300/kernel/gdb-io-ttysm.c
index c859cac..caae8ca 100644
--- a/arch/mn10300/kernel/gdb-io-ttysm.c
+++ b/arch/mn10300/kernel/gdb-io-ttysm.c
@@ -17,7 +17,6 @@
 #include <linux/init.h>
 #include <linux/tty.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/gdb-stub.h>
 #include <asm/exceptions.h>
 #include <unit/clock.h>
diff --git a/arch/mn10300/kernel/gdb-stub.c b/arch/mn10300/kernel/gdb-stub.c
index 522eb8a..a128c57 100644
--- a/arch/mn10300/kernel/gdb-stub.c
+++ b/arch/mn10300/kernel/gdb-stub.c
@@ -130,7 +130,6 @@
 #include <linux/bug.h>
 
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/gdb-stub.h>
 #include <asm/exceptions.h>
 #include <asm/debugger.h>
diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c
index 94901c5..339cef4 100644
--- a/arch/mn10300/kernel/mn10300-serial.c
+++ b/arch/mn10300/kernel/mn10300-serial.c
@@ -36,7 +36,6 @@
 #include <linux/console.h>
 #include <linux/sysrq.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
diff --git a/arch/mn10300/kernel/mn10300-watchdog.c b/arch/mn10300/kernel/mn10300-watchdog.c
index a45f0c7..db64a71 100644
--- a/arch/mn10300/kernel/mn10300-watchdog.c
+++ b/arch/mn10300/kernel/mn10300-watchdog.c
@@ -18,7 +18,6 @@
 #include <linux/kernel_stat.h>
 #include <linux/nmi.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/intctl-regs.h>
 #include <asm/rtc-regs.h>
diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c
index cac401d..14707f2 100644
--- a/arch/mn10300/kernel/process.c
+++ b/arch/mn10300/kernel/process.c
@@ -27,7 +27,6 @@
 #include <linux/slab.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/mmu_context.h>
diff --git a/arch/mn10300/kernel/ptrace.c b/arch/mn10300/kernel/ptrace.c
index 5c0b07e..5bd5851 100644
--- a/arch/mn10300/kernel/ptrace.c
+++ b/arch/mn10300/kernel/ptrace.c
@@ -21,7 +21,6 @@
 #include <linux/tracehook.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/cacheflush.h>
 #include <asm/fpu.h>
diff --git a/arch/mn10300/kernel/setup.c b/arch/mn10300/kernel/setup.c
index 9e7a320..33c3bd1 100644
--- a/arch/mn10300/kernel/setup.c
+++ b/arch/mn10300/kernel/setup.c
@@ -26,7 +26,6 @@
 #include <asm/processor.h>
 #include <linux/console.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/setup.h>
 #include <asm/io.h>
 #include <asm/smp.h>
diff --git a/arch/mn10300/kernel/smp-low.S b/arch/mn10300/kernel/smp-low.S
index 72938ce..71f1b2f 100644
--- a/arch/mn10300/kernel/smp-low.S
+++ b/arch/mn10300/kernel/smp-low.S
@@ -13,9 +13,9 @@
 #include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/smp.h>
-#include <asm/system.h>
 #include <asm/thread_info.h>
 #include <asm/cpu-regs.h>
+#include <asm/intctl-regs.h>
 #include <proc/smp-regs.h>
 #include <asm/asm-offsets.h>
 #include <asm/frame.inc>
diff --git a/arch/mn10300/kernel/smp.c b/arch/mn10300/kernel/smp.c
index 9242e9f..910dddf 100644
--- a/arch/mn10300/kernel/smp.c
+++ b/arch/mn10300/kernel/smp.c
@@ -25,7 +25,6 @@
 #include <linux/profile.h>
 #include <linux/smp.h>
 #include <asm/tlbflush.h>
-#include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/processor.h>
 #include <asm/bug.h>
diff --git a/arch/mn10300/kernel/traps.c b/arch/mn10300/kernel/traps.c
index 9220a75a..94a9c6d 100644
--- a/arch/mn10300/kernel/traps.c
+++ b/arch/mn10300/kernel/traps.c
@@ -27,7 +27,6 @@
 #include <linux/bug.h>
 #include <linux/irq.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <linux/uaccess.h>
 #include <asm/io.h>
 #include <linux/atomic.h>
diff --git a/arch/mn10300/lib/bitops.c b/arch/mn10300/lib/bitops.c
index a66c6cd..37309cd 100644
--- a/arch/mn10300/lib/bitops.c
+++ b/arch/mn10300/lib/bitops.c
@@ -10,7 +10,6 @@
  */
 #include <linux/module.h>
 #include <asm/bitops.h>
-#include <asm/system.h>
 
 /*
  * try flipping a bit using BSET and BCLR
diff --git a/arch/mn10300/mm/fault.c b/arch/mn10300/mm/fault.c
index 0945409..90f346f 100644
--- a/arch/mn10300/mm/fault.c
+++ b/arch/mn10300/mm/fault.c
@@ -24,7 +24,6 @@
 #include <linux/init.h>
 #include <linux/vt_kern.h>		/* For unblank_screen() */
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 #include <asm/hardirq.h>
diff --git a/arch/mn10300/mm/init.c b/arch/mn10300/mm/init.c
index 1380182..e57e5bc 100644
--- a/arch/mn10300/mm/init.c
+++ b/arch/mn10300/mm/init.c
@@ -29,7 +29,6 @@
 #include <linux/gfp.h>
 
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
diff --git a/arch/mn10300/mm/misalignment.c b/arch/mn10300/mm/misalignment.c
index f9bb8cb..b9920b1 100644
--- a/arch/mn10300/mm/misalignment.c
+++ b/arch/mn10300/mm/misalignment.c
@@ -23,7 +23,6 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/atomic.h>
diff --git a/arch/mn10300/mm/pgtable.c b/arch/mn10300/mm/pgtable.c
index 450f7ba..4ebf117 100644
--- a/arch/mn10300/mm/pgtable.c
+++ b/arch/mn10300/mm/pgtable.c
@@ -21,7 +21,6 @@
 #include <linux/spinlock.h>
 #include <linux/quicklist.h>
 
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/tlb.h>
diff --git a/arch/mn10300/mm/tlb-smp.c b/arch/mn10300/mm/tlb-smp.c
index 9a77749..3e57faf 100644
--- a/arch/mn10300/mm/tlb-smp.c
+++ b/arch/mn10300/mm/tlb-smp.c
@@ -24,7 +24,6 @@
 #include <linux/profile.h>
 #include <linux/smp.h>
 #include <asm/tlbflush.h>
-#include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/processor.h>
 #include <asm/bug.h>
diff --git a/arch/mn10300/proc-mn2ws0050/proc-init.c b/arch/mn10300/proc-mn2ws0050/proc-init.c
index fe6e249..ee6d03d 100644
--- a/arch/mn10300/proc-mn2ws0050/proc-init.c
+++ b/arch/mn10300/proc-mn2ws0050/proc-init.c
@@ -15,7 +15,6 @@
 #include <linux/interrupt.h>
 
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/atomic.h>
diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c
index a7c5f08..6dce9fc 100644
--- a/arch/mn10300/unit-asb2305/pci.c
+++ b/arch/mn10300/unit-asb2305/pci.c
@@ -32,8 +32,7 @@
  * insert specific PCI bus resources instead of using the platform-level bus
  * resources directly for the PCI root bus.
  *
- * These are configured and inserted by pcibios_init() and are attached to the
- * root bus by pcibios_fixup_bus().
+ * These are configured and inserted by pcibios_init().
  */
 static struct resource pci_ioport_resource = {
 	.name	= "PCI IO",
@@ -78,52 +77,6 @@
 }
 
 /*
- * translate Linuxcentric addresses to PCI bus addresses
- */
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-			     struct resource *res)
-{
-	if (res->flags & IORESOURCE_IO) {
-		region->start = (res->start & 0x00ffffff);
-		region->end   = (res->end   & 0x00ffffff);
-	}
-
-	if (res->flags & IORESOURCE_MEM) {
-		region->start = (res->start & 0x03ffffff) | MEM_PAGING_REG;
-		region->end   = (res->end   & 0x03ffffff) | MEM_PAGING_REG;
-	}
-
-#if 0
-	printk(KERN_DEBUG "RES->BUS: %lx-%lx => %lx-%lx\n",
-	       res->start, res->end, region->start, region->end);
-#endif
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-/*
- * translate PCI bus addresses to Linuxcentric addresses
- */
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-			     struct pci_bus_region *region)
-{
-	if (res->flags & IORESOURCE_IO) {
-		res->start = (region->start & 0x00ffffff) | 0xbe000000;
-		res->end   = (region->end   & 0x00ffffff) | 0xbe000000;
-	}
-
-	if (res->flags & IORESOURCE_MEM) {
-		res->start = (region->start & 0x03ffffff) | 0xb8000000;
-		res->end   = (region->end   & 0x03ffffff) | 0xb8000000;
-	}
-
-#if 0
-	printk(KERN_INFO "BUS->RES: %lx-%lx => %lx-%lx\n",
-	       region->start, region->end, res->start, res->end);
-#endif
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
-/*
  *
  */
 static int pci_ampci_read_config_byte(struct pci_bus *bus, unsigned int devfn,
@@ -364,9 +317,6 @@
 		if (!dev->resource[i].flags)
 			continue;
 
-		region.start = dev->resource[i].start;
-		region.end = dev->resource[i].end;
-		pcibios_bus_to_resource(dev, &dev->resource[i], &region);
 		if (is_valid_resource(dev, i))
 			pci_claim_resource(dev, i);
 	}
@@ -397,6 +347,7 @@
  */
 static int __init pcibios_init(void)
 {
+	resource_size_t io_offset, mem_offset;
 	LIST_HEAD(resources);
 
 	ioport_resource.start	= 0xA0000000;
@@ -420,8 +371,13 @@
 	printk(KERN_INFO "PCI: Probing PCI hardware [mempage %08x]\n",
 	       MEM_PAGING_REG);
 
-	pci_add_resource(&resources, &pci_ioport_resource);
-	pci_add_resource(&resources, &pci_iomem_resource);
+	io_offset = pci_ioport_resource.start -
+	    (pci_ioport_resource.start & 0x00ffffff);
+	mem_offset = pci_iomem_resource.start -
+	    ((pci_iomem_resource.start & 0x03ffffff) | MEM_PAGING_REG);
+
+	pci_add_resource_offset(&resources, &pci_ioport_resource, io_offset);
+	pci_add_resource_offset(&resources, &pci_iomem_resource, mem_offset);
 	pci_root_bus = pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL,
 					 &resources);
 
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index bc428b5..a478719 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -16,6 +16,7 @@
 	select GENERIC_IRQ_SHOW
 	select GENERIC_IOMAP
 	select GENERIC_CPU_DEVICES
+	select GENERIC_ATOMIC64
 
 config MMU
 	def_bool y
diff --git a/arch/openrisc/include/asm/Kbuild b/arch/openrisc/include/asm/Kbuild
index 11162e6..dcea5a0 100644
--- a/arch/openrisc/include/asm/Kbuild
+++ b/arch/openrisc/include/asm/Kbuild
@@ -4,6 +4,7 @@
 
 generic-y += atomic.h
 generic-y += auxvec.h
+generic-y += barrier.h
 generic-y += bitsperlong.h
 generic-y += bug.h
 generic-y += bugs.h
@@ -19,6 +20,7 @@
 generic-y += dma.h
 generic-y += emergency-restart.h
 generic-y += errno.h
+generic-y += exec.h
 generic-y += fb.h
 generic-y += fcntl.h
 generic-y += ftrace.h
@@ -55,6 +57,7 @@
 generic-y += statfs.h
 generic-y += stat.h
 generic-y += string.h
+generic-y += switch_to.h
 generic-y += swab.h
 generic-y += termbits.h
 generic-y += termios.h
diff --git a/arch/openrisc/include/asm/page.h b/arch/openrisc/include/asm/page.h
index b041b34..108906f 100644
--- a/arch/openrisc/include/asm/page.h
+++ b/arch/openrisc/include/asm/page.h
@@ -71,9 +71,6 @@
 #define __pgd(x)	((pgd_t) { (x) })
 #define __pgprot(x)	((pgprot_t) { (x) })
 
-extern unsigned long memory_start;
-extern unsigned long memory_end;
-
 #endif /* !__ASSEMBLY__ */
 
 
@@ -94,8 +91,7 @@
 
 #define pfn_valid(pfn)          ((pfn) < max_mapnr)
 
-#define virt_addr_valid(kaddr)  (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
-				((void *)(kaddr) < (void *)memory_end))
+#define virt_addr_valid(kaddr)	(pfn_valid(virt_to_pfn(kaddr)))
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/arch/openrisc/include/asm/pgtable.h b/arch/openrisc/include/asm/pgtable.h
index 043505d..14c900c 100644
--- a/arch/openrisc/include/asm/pgtable.h
+++ b/arch/openrisc/include/asm/pgtable.h
@@ -455,7 +455,6 @@
  * No page table caches to initialise
  */
 #define pgtable_cache_init()		do { } while (0)
-#define io_remap_page_range		remap_page_range
 
 typedef pte_t *pte_addr_t;
 
diff --git a/arch/openrisc/include/asm/processor.h b/arch/openrisc/include/asm/processor.h
index bb54c97..f7516fa 100644
--- a/arch/openrisc/include/asm/processor.h
+++ b/arch/openrisc/include/asm/processor.h
@@ -81,8 +81,8 @@
 #define INIT_THREAD  { }
 
 
-#define KSTK_EIP(tsk)   (task_pt_regs(tsk)->pc);
-#define KSTK_ESP(tsk)   (task_pt_regs(tsk)->sp);
+#define KSTK_EIP(tsk)   (task_pt_regs(tsk)->pc)
+#define KSTK_ESP(tsk)   (task_pt_regs(tsk)->sp)
 
 
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
diff --git a/arch/openrisc/include/asm/ptrace.h b/arch/openrisc/include/asm/ptrace.h
index e612ce4..4651a73 100644
--- a/arch/openrisc/include/asm/ptrace.h
+++ b/arch/openrisc/include/asm/ptrace.h
@@ -73,9 +73,13 @@
 		};
 	};
 	long  pc;
+	/* For restarting system calls:
+	 * Set to syscall number for syscall exceptions,
+	 * -1 for all other exceptions.
+	 */
 	long  orig_gpr11;	/* For restarting system calls */
-	long  syscallno;	/* Syscall number (used by strace) */
 	long dummy;		/* Cheap alignment fix */
+	long dummy2;		/* Cheap alignment fix */
 };
 
 /* TODO: Rename this to REDZONE because that's what it is */
diff --git a/arch/openrisc/include/asm/syscall.h b/arch/openrisc/include/asm/syscall.h
index 9f03370..b752bb6 100644
--- a/arch/openrisc/include/asm/syscall.h
+++ b/arch/openrisc/include/asm/syscall.h
@@ -25,7 +25,7 @@
 static inline int
 syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
 {
-	return regs->syscallno ? regs->syscallno : -1;
+	return regs->orig_gpr11;
 }
 
 static inline void
@@ -50,10 +50,7 @@
 syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
 			 int error, long val)
 {
-	if (error)
-		regs->gpr[11] = -error;
-	else
-		regs->gpr[11] = val;
+	regs->gpr[11] = (long) error ?: val;
 }
 
 static inline void
diff --git a/arch/openrisc/include/asm/system.h b/arch/openrisc/include/asm/system.h
deleted file mode 100644
index cf65888..0000000
--- a/arch/openrisc/include/asm/system.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * OpenRISC Linux
- *
- * Linux architectural port borrowing liberally from similar works of
- * others.  All original copyrights apply as per the original source
- * declaration.
- *
- * OpenRISC implementation:
- * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
- * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
- * et al.
- *
- * 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 __ASM_OPENRISC_SYSTEM_H
-#define __ASM_OPENRISC_SYSTEM_H
-
-#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
-
-#include <asm/spr.h>
-#include <asm-generic/system.h>
-
-/* We probably need this definition, but the generic system.h provides it
- * and it's not used on our arch anyway...
- */
-/*#define nop() __asm__ __volatile__ ("l.nop"::)*/
-
-#endif /* __ASSEMBLY__ */
-#endif /* __KERNEL__ */
-#endif /* __ASM_OPENRISC_SYSTEM_H */
diff --git a/arch/openrisc/include/asm/uaccess.h b/arch/openrisc/include/asm/uaccess.h
index c310e45..f5abaa0 100644
--- a/arch/openrisc/include/asm/uaccess.h
+++ b/arch/openrisc/include/asm/uaccess.h
@@ -26,7 +26,6 @@
 #include <linux/thread_info.h>
 #include <linux/prefetch.h>
 #include <linux/string.h>
-#include <linux/thread_info.h>
 #include <asm/page.h>
 
 #define VERIFY_READ	0
diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S
index d5f9c35..6e61af8 100644
--- a/arch/openrisc/kernel/entry.S
+++ b/arch/openrisc/kernel/entry.S
@@ -95,7 +95,6 @@
 	/* r1, EPCR, ESR a already saved */			;\
 	l.sw	PT_GPR2(r1),r2					;\
 	l.sw    PT_GPR3(r1),r3					;\
-	l.sw    PT_ORIG_GPR11(r1),r11				;\
 	/* r4 already save */					;\
 	l.sw    PT_GPR5(r1),r5					;\
 	l.sw    PT_GPR6(r1),r6					;\
@@ -125,7 +124,9 @@
 	/* r30 already save */					;\
 /*        l.sw    PT_GPR30(r1),r30*/					;\
 	l.sw    PT_GPR31(r1),r31					;\
-	l.sw    PT_SYSCALLNO(r1),r0
+	/* Store -1 in orig_gpr11 for non-syscall exceptions */	;\
+	l.addi	r30,r0,-1					;\
+	l.sw	PT_ORIG_GPR11(r1),r30
 
 #define UNHANDLED_EXCEPTION(handler,vector)			\
 	.global	handler						;\
@@ -133,7 +134,6 @@
 	/* r1, EPCR, ESR already saved */			;\
 	l.sw    PT_GPR2(r1),r2					;\
 	l.sw    PT_GPR3(r1),r3					;\
-	l.sw    PT_ORIG_GPR11(r1),r11				;\
 	l.sw    PT_GPR5(r1),r5					;\
 	l.sw    PT_GPR6(r1),r6					;\
 	l.sw    PT_GPR7(r1),r7					;\
@@ -162,7 +162,9 @@
 	/* r31 already saved */					;\
 	l.sw    PT_GPR30(r1),r30					;\
 /*        l.sw    PT_GPR31(r1),r31	*/				;\
-	l.sw    PT_SYSCALLNO(r1),r0				;\
+	/* Store -1 in orig_gpr11 for non-syscall exceptions */	;\
+	l.addi	r30,r0,-1					;\
+	l.sw	PT_ORIG_GPR11(r1),r30				;\
 	l.addi	r3,r1,0						;\
 	/* r4 is exception EA */				;\
 	l.addi	r5,r0,vector					;\
@@ -554,6 +556,7 @@
 	l.sw    PT_GPR9(r1),r9
 	/* r10 already saved */
 	l.sw    PT_GPR11(r1),r11
+	/* orig_gpr11 must be set for syscalls */
 	l.sw    PT_ORIG_GPR11(r1),r11
 	/* r12,r13 already saved */
 
@@ -567,9 +570,6 @@
 	/* r30 is the only register we clobber in the fast path */
 	/* r30 already saved */
 /*	l.sw    PT_GPR30(r1),r30 */
-	/* This is used by do_signal to determine whether to check for
-	 * syscall restart or not */
-	l.sw    PT_SYSCALLNO(r1),r11
 
 _syscall_check_trace_enter:
 	/* If TIF_SYSCALL_TRACE is set, then we want to do syscall tracing */
@@ -731,7 +731,7 @@
 	 * so that we can do the syscall for real and return to the syscall
 	 * hot path.
 	 */
-	l.lwz	r11,PT_SYSCALLNO(r1)
+	l.lwz	r11,PT_GPR11(r1)
 	l.lwz	r3,PT_GPR3(r1)
 	l.lwz	r4,PT_GPR4(r1)
 	l.lwz	r5,PT_GPR5(r1)
diff --git a/arch/openrisc/kernel/head.S b/arch/openrisc/kernel/head.S
index c75018d..1088b5f 100644
--- a/arch/openrisc/kernel/head.S
+++ b/arch/openrisc/kernel/head.S
@@ -26,6 +26,7 @@
 #include <asm/cache.h>
 #include <asm/spr_defs.h>
 #include <asm/asm-offsets.h>
+#include <linux/of_fdt.h>
 
 #define tophys(rd,rs)				\
 	l.movhi	rd,hi(-KERNELBASE)		;\
@@ -440,6 +441,9 @@
 	__HEAD
 	.global _start
 _start:
+	/* save kernel parameters */
+	l.or	r25,r0,r3	/* pointer to fdt */
+
 	/*
 	 * ensure a deterministic start
 	 */
@@ -471,7 +475,6 @@
 	CLEAR_GPR(r22)
 	CLEAR_GPR(r23)
 	CLEAR_GPR(r24)
-	CLEAR_GPR(r25)
 	CLEAR_GPR(r26)
 	CLEAR_GPR(r27)
 	CLEAR_GPR(r28)
@@ -565,6 +568,18 @@
 	// reset the simulation counters
 	l.nop 5
 
+	/* check fdt header magic word */
+	l.lwz	r3,0(r25)	/* load magic from fdt into r3 */
+	l.movhi	r4,hi(OF_DT_HEADER)
+	l.ori	r4,r4,lo(OF_DT_HEADER)
+	l.sfeq	r3,r4
+	l.bf	_fdt_found
+	 l.nop
+	/* magic number mismatch, set fdt pointer to null */
+	l.or	r25,r0,r0
+_fdt_found:
+	/* pass fdt pointer to or32_early_setup in r3 */
+	l.or	r3,r0,r25
 	LOAD_SYMBOL_2_GPR(r24, or32_early_setup)
 	l.jalr r24
 	 l.nop
diff --git a/arch/openrisc/kernel/idle.c b/arch/openrisc/kernel/idle.c
index e5fc7887..7d618fe 100644
--- a/arch/openrisc/kernel/idle.c
+++ b/arch/openrisc/kernel/idle.c
@@ -31,7 +31,6 @@
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/mmu.h>
diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c
index e4209af..55210f3 100644
--- a/arch/openrisc/kernel/process.c
+++ b/arch/openrisc/kernel/process.c
@@ -38,7 +38,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/spr_defs.h>
diff --git a/arch/openrisc/kernel/prom.c b/arch/openrisc/kernel/prom.c
index 3d4478f..5869e3f 100644
--- a/arch/openrisc/kernel/prom.c
+++ b/arch/openrisc/kernel/prom.c
@@ -42,7 +42,6 @@
 #include <asm/processor.h>
 #include <asm/irq.h>
 #include <linux/io.h>
-#include <asm/system.h>
 #include <asm/mmu.h>
 #include <asm/pgtable.h>
 #include <asm/sections.h>
diff --git a/arch/openrisc/kernel/ptrace.c b/arch/openrisc/kernel/ptrace.c
index 7259047..e71781d 100644
--- a/arch/openrisc/kernel/ptrace.c
+++ b/arch/openrisc/kernel/ptrace.c
@@ -33,7 +33,6 @@
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 
 /*
  * Copy the thread state to a regset that can be interpreted by userspace.
@@ -188,11 +187,11 @@
 		 */
 		ret = -1L;
 
-	audit_syscall_entry(audit_arch(), regs->syscallno,
+	audit_syscall_entry(audit_arch(), regs->gpr[11],
 			    regs->gpr[3], regs->gpr[4],
 			    regs->gpr[5], regs->gpr[6]);
 
-	return ret ? : regs->syscallno;
+	return ret ? : regs->gpr[11];
 }
 
 asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
diff --git a/arch/openrisc/kernel/setup.c b/arch/openrisc/kernel/setup.c
index 1422f74..f4d5bed 100644
--- a/arch/openrisc/kernel/setup.c
+++ b/arch/openrisc/kernel/setup.c
@@ -41,7 +41,6 @@
 #include <linux/of_platform.h>
 
 #include <asm/segment.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -207,18 +206,18 @@
  * Handles the pointer to the device tree that this kernel is to use
  * for establishing the available platform devices.
  *
- * For now, this is limited to using the built-in device tree.  In the future,
- * it is intended that this function will take a pointer to the device tree
- * that is potentially built-in, but potentially also passed in by the
- * bootloader, or discovered by some equally clever means...
+ * Falls back on built-in device tree in case null pointer is passed.
  */
 
-void __init or32_early_setup(void)
+void __init or32_early_setup(unsigned int fdt)
 {
-
-	early_init_devtree(__dtb_start);
-
-	printk(KERN_INFO "Compiled-in FDT at 0x%p\n", __dtb_start);
+	if (fdt) {
+		early_init_devtree((void*) fdt);
+		printk(KERN_INFO "FDT at 0x%08x\n", fdt);
+	} else {
+		early_init_devtree(__dtb_start);
+		printk(KERN_INFO "Compiled-in FDT at %p\n", __dtb_start);
+	}
 }
 
 static int __init openrisc_device_probe(void)
diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c
index 95207ab..e970743 100644
--- a/arch/openrisc/kernel/signal.c
+++ b/arch/openrisc/kernel/signal.c
@@ -102,10 +102,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
@@ -189,8 +186,8 @@
  * trampoline which performs the syscall sigreturn, or a provided
  * user-mode trampoline.
  */
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-			   sigset_t *set, struct pt_regs *regs)
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+			  sigset_t *set, struct pt_regs *regs)
 {
 	struct rt_sigframe *frame;
 	unsigned long return_ip;
@@ -247,31 +244,27 @@
 	/* actually move the usp to reflect the stacked frame */
 	regs->sp = (unsigned long)frame;
 
-	return;
+	return 0;
 
 give_sigsegv:
-	if (sig == SIGSEGV)
-		ka->sa.sa_handler = SIG_DFL;
-	force_sig(SIGSEGV, current);
+	force_sigsegv(sig, current);
+	return -EFAULT;
 }
 
-static inline void
+static inline int
 handle_signal(unsigned long sig,
 	      siginfo_t *info, struct k_sigaction *ka,
 	      sigset_t *oldset, struct pt_regs *regs)
 {
-	setup_rt_frame(sig, ka, info, oldset, regs);
+	int ret;
 
-	if (ka->sa.sa_flags & SA_ONESHOT)
-		ka->sa.sa_handler = SIG_DFL;
+	ret = setup_rt_frame(sig, ka, info, oldset, regs);
+	if (ret)
+		return ret;
 
-	spin_lock_irq(&current->sighand->siglock);
-	sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&current->blocked, sig);
-	recalc_sigpending();
+	block_sigmask(ka, sig);
 
-	spin_unlock_irq(&current->sighand->siglock);
+	return 0;
 }
 
 /*
@@ -312,7 +305,7 @@
 	 * below mean that the syscall executed to completion and no
 	 * restart is necessary.
 	 */
-	if (regs->syscallno) {
+	if (regs->orig_gpr11) {
 		int restart = 0;
 
 		switch (regs->gpr[11]) {
@@ -360,13 +353,13 @@
 			oldset = &current->blocked;
 
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, &info, &ka, oldset, regs);
-		/* a signal was successfully delivered; the saved
-		 * sigmask will have been stored in the signal frame,
-		 * and will be restored by sigreturn, so we can simply
-		 * clear the TIF_RESTORE_SIGMASK flag */
-		if (test_thread_flag(TIF_RESTORE_SIGMASK))
+		if (!handle_signal(signr, &info, &ka, oldset, regs)) {
+			/* a signal was successfully delivered; the saved
+			 * sigmask will have been stored in the signal frame,
+			 * and will be restored by sigreturn, so we can simply
+			 * clear the TIF_RESTORE_SIGMASK flag */
 			clear_thread_flag(TIF_RESTORE_SIGMASK);
+		}
 
 		tracehook_signal_handler(signr, &info, &ka, regs,
 					 test_thread_flag(TIF_SINGLESTEP));
diff --git a/arch/openrisc/kernel/time.c b/arch/openrisc/kernel/time.c
index bd946ef..7c52e94 100644
--- a/arch/openrisc/kernel/time.c
+++ b/arch/openrisc/kernel/time.c
@@ -125,16 +125,13 @@
 
 static __init void openrisc_clockevent_init(void)
 {
-	clockevents_calc_mult_shift(&clockevent_openrisc_timer,
-				    cpuinfo.clock_frequency, 4);
+	clockevent_openrisc_timer.cpumask = cpumask_of(0);
 
 	/* We only have 28 bits */
-	clockevent_openrisc_timer.max_delta_ns =
-	    clockevent_delta2ns((u32) 0x0fffffff, &clockevent_openrisc_timer);
-	clockevent_openrisc_timer.min_delta_ns =
-	    clockevent_delta2ns(1, &clockevent_openrisc_timer);
-	clockevent_openrisc_timer.cpumask = cpumask_of(0);
-	clockevents_register_device(&clockevent_openrisc_timer);
+	clockevents_config_and_register(&clockevent_openrisc_timer,
+					cpuinfo.clock_frequency,
+					100, 0x0fffffff);
+
 }
 
 /**
diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c
index a4ec44a..5cce396 100644
--- a/arch/openrisc/kernel/traps.c
+++ b/arch/openrisc/kernel/traps.c
@@ -33,7 +33,6 @@
 #include <linux/kallsyms.h>
 #include <asm/uaccess.h>
 
-#include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
@@ -115,6 +114,7 @@
 
 	show_stack(current, &stack);
 }
+EXPORT_SYMBOL(dump_stack);
 
 void show_registers(struct pt_regs *regs)
 {
@@ -145,8 +145,8 @@
 	       regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]);
 	printk("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n",
 	       regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]);
-	printk("  RES: %08lx oGPR11: %08lx syscallno: %08lx\n",
-	       regs->gpr[11], regs->orig_gpr11, regs->syscallno);
+	printk("  RES: %08lx oGPR11: %08lx\n",
+	       regs->gpr[11], regs->orig_gpr11);
 
 	printk("Process %s (pid: %d, stackpage=%08lx)\n",
 	       current->comm, current->pid, (unsigned long)current);
@@ -207,8 +207,8 @@
 	       regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]);
 	printk("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n",
 	       regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]);
-	printk("  RES: %08lx oGPR11: %08lx syscallno: %08lx\n",
-	       regs->gpr[11], regs->orig_gpr11, regs->syscallno);
+	printk("  RES: %08lx oGPR11: %08lx\n",
+	       regs->gpr[11], regs->orig_gpr11);
 
 	printk("Process %s (pid: %d, stackpage=%08lx)\n",
 	       ((struct task_struct *)(__pa(current)))->comm,
diff --git a/arch/openrisc/mm/init.c b/arch/openrisc/mm/init.c
index 359dcb2..79dea97 100644
--- a/arch/openrisc/mm/init.c
+++ b/arch/openrisc/mm/init.c
@@ -33,7 +33,6 @@
 #include <linux/pagemap.h>
 #include <linux/memblock.h>
 
-#include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
@@ -222,8 +221,7 @@
 {
 	int codesize, reservedpages, datasize, initsize;
 
-	if (!mem_map)
-		BUG();
+	BUG_ON(!mem_map);
 
 	set_max_mapnr_init();
 
diff --git a/arch/openrisc/mm/tlb.c b/arch/openrisc/mm/tlb.c
index 56b0b89..683bd4d 100644
--- a/arch/openrisc/mm/tlb.c
+++ b/arch/openrisc/mm/tlb.c
@@ -26,7 +26,6 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 
-#include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/tlbflush.h>
 #include <asm/pgtable.h>
diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h
index 4054b31..6c6defc 100644
--- a/arch/parisc/include/asm/atomic.h
+++ b/arch/parisc/include/asm/atomic.h
@@ -6,7 +6,7 @@
 #define _ASM_PARISC_ATOMIC_H_
 
 #include <linux/types.h>
-#include <asm/system.h>
+#include <asm/cmpxchg.h>
 
 /*
  * Atomic operations that C can't guarantee us.  Useful for
@@ -49,112 +49,6 @@
 #  define _atomic_spin_unlock_irqrestore(l,f) do { local_irq_restore(f); } while (0)
 #endif
 
-/* This should get optimized out since it's never called.
-** Or get a link error if xchg is used "wrong".
-*/
-extern void __xchg_called_with_bad_pointer(void);
-
-
-/* __xchg32/64 defined in arch/parisc/lib/bitops.c */
-extern unsigned long __xchg8(char, char *);
-extern unsigned long __xchg32(int, int *);
-#ifdef CONFIG_64BIT
-extern unsigned long __xchg64(unsigned long, unsigned long *);
-#endif
-
-/* optimizer better get rid of switch since size is a constant */
-static __inline__ unsigned long
-__xchg(unsigned long x, __volatile__ void * ptr, int size)
-{
-	switch(size) {
-#ifdef CONFIG_64BIT
-	case 8: return __xchg64(x,(unsigned long *) ptr);
-#endif
-	case 4: return __xchg32((int) x, (int *) ptr);
-	case 1: return __xchg8((char) x, (char *) ptr);
-	}
-	__xchg_called_with_bad_pointer();
-	return x;
-}
-
-
-/*
-** REVISIT - Abandoned use of LDCW in xchg() for now:
-** o need to test sizeof(*ptr) to avoid clearing adjacent bytes
-** o and while we are at it, could CONFIG_64BIT code use LDCD too?
-**
-**	if (__builtin_constant_p(x) && (x == NULL))
-**		if (((unsigned long)p & 0xf) == 0)
-**			return __ldcw(p);
-*/
-#define xchg(ptr,x) \
-	((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-
-
-#define __HAVE_ARCH_CMPXCHG	1
-
-/* bug catcher for when unsupported size is used - won't link */
-extern void __cmpxchg_called_with_bad_pointer(void);
-
-/* __cmpxchg_u32/u64 defined in arch/parisc/lib/bitops.c */
-extern unsigned long __cmpxchg_u32(volatile unsigned int *m, unsigned int old, unsigned int new_);
-extern unsigned long __cmpxchg_u64(volatile unsigned long *ptr, unsigned long old, unsigned long new_);
-
-/* don't worry...optimizer will get rid of most of this */
-static __inline__ unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
-{
-	switch(size) {
-#ifdef CONFIG_64BIT
-	case 8: return __cmpxchg_u64((unsigned long *)ptr, old, new_);
-#endif
-	case 4: return __cmpxchg_u32((unsigned int *)ptr, (unsigned int) old, (unsigned int) new_);
-	}
-	__cmpxchg_called_with_bad_pointer();
-	return old;
-}
-
-#define cmpxchg(ptr,o,n)						 \
-  ({									 \
-     __typeof__(*(ptr)) _o_ = (o);					 \
-     __typeof__(*(ptr)) _n_ = (n);					 \
-     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
-				    (unsigned long)_n_, sizeof(*(ptr))); \
-  })
-
-#include <asm-generic/cmpxchg-local.h>
-
-static inline unsigned long __cmpxchg_local(volatile void *ptr,
-				      unsigned long old,
-				      unsigned long new_, int size)
-{
-	switch (size) {
-#ifdef CONFIG_64BIT
-	case 8:	return __cmpxchg_u64((unsigned long *)ptr, old, new_);
-#endif
-	case 4:	return __cmpxchg_u32(ptr, old, new_);
-	default:
-		return __cmpxchg_local_generic(ptr, old, new_, size);
-	}
-}
-
-/*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
- */
-#define cmpxchg_local(ptr, o, n)				  	\
-	((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o),	\
-			(unsigned long)(n), sizeof(*(ptr))))
-#ifdef CONFIG_64BIT
-#define cmpxchg64_local(ptr, o, n)					\
-  ({									\
-	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
-	cmpxchg_local((ptr), (o), (n));					\
-  })
-#else
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-#endif
-
 /*
  * Note that we need not lock read accesses - aligned word writes/reads
  * are atomic, so a reader never sees inconsistent values.
diff --git a/arch/parisc/include/asm/barrier.h b/arch/parisc/include/asm/barrier.h
new file mode 100644
index 0000000..e77d834
--- /dev/null
+++ b/arch/parisc/include/asm/barrier.h
@@ -0,0 +1,35 @@
+#ifndef __PARISC_BARRIER_H
+#define __PARISC_BARRIER_H
+
+/*
+** This is simply the barrier() macro from linux/kernel.h but when serial.c
+** uses tqueue.h uses smp_mb() defined using barrier(), linux/kernel.h
+** hasn't yet been included yet so it fails, thus repeating the macro here.
+**
+** PA-RISC architecture allows for weakly ordered memory accesses although
+** none of the processors use it. There is a strong ordered bit that is
+** set in the O-bit of the page directory entry. Operating systems that
+** can not tolerate out of order accesses should set this bit when mapping
+** pages. The O-bit of the PSW should also be set to 1 (I don't believe any
+** of the processor implemented the PSW O-bit). The PCX-W ERS states that
+** the TLB O-bit is not implemented so the page directory does not need to
+** have the O-bit set when mapping pages (section 3.1). This section also
+** states that the PSW Y, Z, G, and O bits are not implemented.
+** So it looks like nothing needs to be done for parisc-linux (yet).
+** (thanks to chada for the above comment -ggg)
+**
+** The __asm__ op below simple prevents gcc/ld from reordering
+** instructions across the mb() "call".
+*/
+#define mb()		__asm__ __volatile__("":::"memory")	/* barrier() */
+#define rmb()		mb()
+#define wmb()		mb()
+#define smp_mb()	mb()
+#define smp_rmb()	mb()
+#define smp_wmb()	mb()
+#define smp_read_barrier_depends()	do { } while(0)
+#define read_barrier_depends()		do { } while(0)
+
+#define set_mb(var, value)		do { var = value; mb(); } while (0)
+
+#endif /* __PARISC_BARRIER_H */
diff --git a/arch/parisc/include/asm/cmpxchg.h b/arch/parisc/include/asm/cmpxchg.h
new file mode 100644
index 0000000..dbd1335
--- /dev/null
+++ b/arch/parisc/include/asm/cmpxchg.h
@@ -0,0 +1,116 @@
+/*
+ * forked from parisc asm/atomic.h which was:
+ *	Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *	Copyright (C) 2006 Kyle McMartin <kyle@parisc-linux.org>
+ */
+
+#ifndef _ASM_PARISC_CMPXCHG_H_
+#define _ASM_PARISC_CMPXCHG_H_
+
+/* This should get optimized out since it's never called.
+** Or get a link error if xchg is used "wrong".
+*/
+extern void __xchg_called_with_bad_pointer(void);
+
+/* __xchg32/64 defined in arch/parisc/lib/bitops.c */
+extern unsigned long __xchg8(char, char *);
+extern unsigned long __xchg32(int, int *);
+#ifdef CONFIG_64BIT
+extern unsigned long __xchg64(unsigned long, unsigned long *);
+#endif
+
+/* optimizer better get rid of switch since size is a constant */
+static inline unsigned long
+__xchg(unsigned long x, __volatile__ void *ptr, int size)
+{
+	switch (size) {
+#ifdef CONFIG_64BIT
+	case 8: return __xchg64(x, (unsigned long *) ptr);
+#endif
+	case 4: return __xchg32((int) x, (int *) ptr);
+	case 1: return __xchg8((char) x, (char *) ptr);
+	}
+	__xchg_called_with_bad_pointer();
+	return x;
+}
+
+/*
+** REVISIT - Abandoned use of LDCW in xchg() for now:
+** o need to test sizeof(*ptr) to avoid clearing adjacent bytes
+** o and while we are at it, could CONFIG_64BIT code use LDCD too?
+**
+**	if (__builtin_constant_p(x) && (x == NULL))
+**		if (((unsigned long)p & 0xf) == 0)
+**			return __ldcw(p);
+*/
+#define xchg(ptr, x) \
+	((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
+
+#define __HAVE_ARCH_CMPXCHG	1
+
+/* bug catcher for when unsupported size is used - won't link */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+/* __cmpxchg_u32/u64 defined in arch/parisc/lib/bitops.c */
+extern unsigned long __cmpxchg_u32(volatile unsigned int *m, unsigned int old,
+				   unsigned int new_);
+extern unsigned long __cmpxchg_u64(volatile unsigned long *ptr,
+				   unsigned long old, unsigned long new_);
+
+/* don't worry...optimizer will get rid of most of this */
+static inline unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
+{
+	switch (size) {
+#ifdef CONFIG_64BIT
+	case 8: return __cmpxchg_u64((unsigned long *)ptr, old, new_);
+#endif
+	case 4: return __cmpxchg_u32((unsigned int *)ptr,
+				     (unsigned int)old, (unsigned int)new_);
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg(ptr, o, n)						 \
+({									 \
+	__typeof__(*(ptr)) _o_ = (o);					 \
+	__typeof__(*(ptr)) _n_ = (n);					 \
+	(__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,	 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+})
+
+#include <asm-generic/cmpxchg-local.h>
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+				      unsigned long old,
+				      unsigned long new_, int size)
+{
+	switch (size) {
+#ifdef CONFIG_64BIT
+	case 8:	return __cmpxchg_u64((unsigned long *)ptr, old, new_);
+#endif
+	case 4:	return __cmpxchg_u32(ptr, old, new_);
+	default:
+		return __cmpxchg_local_generic(ptr, old, new_, size);
+	}
+}
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)					\
+	((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o),	\
+			(unsigned long)(n), sizeof(*(ptr))))
+#ifdef CONFIG_64BIT
+#define cmpxchg64_local(ptr, o, n)					\
+({									\
+	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
+	cmpxchg_local((ptr), (o), (n));					\
+})
+#else
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+#endif
+
+#endif /* _ASM_PARISC_CMPXCHG_H_ */
diff --git a/arch/parisc/include/asm/delay.h b/arch/parisc/include/asm/delay.h
index 7a75e98..912ee7e 100644
--- a/arch/parisc/include/asm/delay.h
+++ b/arch/parisc/include/asm/delay.h
@@ -1,7 +1,7 @@
 #ifndef _PARISC_DELAY_H
 #define _PARISC_DELAY_H
 
-#include <asm/system.h>    /* for mfctl() */
+#include <asm/special_insns.h>    /* for mfctl() */
 #include <asm/processor.h> /* for boot_cpu_data */
 
 
diff --git a/arch/parisc/include/asm/dma.h b/arch/parisc/include/asm/dma.h
index f7a18f9..fd48ae2 100644
--- a/arch/parisc/include/asm/dma.h
+++ b/arch/parisc/include/asm/dma.h
@@ -9,7 +9,6 @@
 #define _ASM_DMA_H
 
 #include <asm/io.h>		/* need byte IO */
-#include <asm/system.h>	
 
 #define dma_outb	outb
 #define dma_inb		inb
diff --git a/arch/parisc/include/asm/exec.h b/arch/parisc/include/asm/exec.h
new file mode 100644
index 0000000..6bb5af7
--- /dev/null
+++ b/arch/parisc/include/asm/exec.h
@@ -0,0 +1,6 @@
+#ifndef __PARISC_EXEC_H
+#define __PARISC_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* __PARISC_EXEC_H */
diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
index 2388bdb..49df148 100644
--- a/arch/parisc/include/asm/futex.h
+++ b/arch/parisc/include/asm/futex.h
@@ -8,6 +8,29 @@
 #include <asm/atomic.h>
 #include <asm/errno.h>
 
+/* The following has to match the LWS code in syscall.S.  We have
+   sixteen four-word locks. */
+
+static inline void
+_futex_spin_lock_irqsave(u32 __user *uaddr, unsigned long int *flags)
+{
+	extern u32 lws_lock_start[];
+	long index = ((long)uaddr & 0xf0) >> 2;
+	arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
+	local_irq_save(*flags);
+	arch_spin_lock(s);
+}
+
+static inline void
+_futex_spin_unlock_irqrestore(u32 __user *uaddr, unsigned long int *flags)
+{
+	extern u32 lws_lock_start[];
+	long index = ((long)uaddr & 0xf0) >> 2;
+	arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
+	arch_spin_unlock(s);
+	local_irq_restore(*flags);
+}
+
 static inline int
 futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
 {
@@ -26,7 +49,7 @@
 
 	pagefault_disable();
 
-	_atomic_spin_lock_irqsave(uaddr, flags);
+	_futex_spin_lock_irqsave(uaddr, &flags);
 
 	switch (op) {
 	case FUTEX_OP_SET:
@@ -71,7 +94,7 @@
 		ret = -ENOSYS;
 	}
 
-	_atomic_spin_unlock_irqrestore(uaddr, flags);
+	_futex_spin_unlock_irqrestore(uaddr, &flags);
 
 	pagefault_enable();
 
@@ -113,7 +136,7 @@
 	 * address. This should scale to a couple of CPUs.
 	 */
 
-	_atomic_spin_lock_irqsave(uaddr, flags);
+	_futex_spin_lock_irqsave(uaddr, &flags);
 
 	ret = get_user(val, uaddr);
 
@@ -122,7 +145,7 @@
 
 	*uval = val;
 
-	_atomic_spin_unlock_irqrestore(uaddr, flags);
+	_futex_spin_unlock_irqrestore(uaddr, &flags);
 
 	return ret;
 }
diff --git a/arch/parisc/include/asm/ldcw.h b/arch/parisc/include/asm/ldcw.h
new file mode 100644
index 0000000..d2d11b7
--- /dev/null
+++ b/arch/parisc/include/asm/ldcw.h
@@ -0,0 +1,48 @@
+#ifndef __PARISC_LDCW_H
+#define __PARISC_LDCW_H
+
+#ifndef CONFIG_PA20
+/* Because kmalloc only guarantees 8-byte alignment for kmalloc'd data,
+   and GCC only guarantees 8-byte alignment for stack locals, we can't
+   be assured of 16-byte alignment for atomic lock data even if we
+   specify "__attribute ((aligned(16)))" in the type declaration.  So,
+   we use a struct containing an array of four ints for the atomic lock
+   type and dynamically select the 16-byte aligned int from the array
+   for the semaphore.  */
+
+#define __PA_LDCW_ALIGNMENT	16
+#define __ldcw_align(a) ({					\
+	unsigned long __ret = (unsigned long) &(a)->lock[0];	\
+	__ret = (__ret + __PA_LDCW_ALIGNMENT - 1)		\
+		& ~(__PA_LDCW_ALIGNMENT - 1);			\
+	(volatile unsigned int *) __ret;			\
+})
+#define __LDCW	"ldcw"
+
+#else /*CONFIG_PA20*/
+/* From: "Jim Hull" <jim.hull of hp.com>
+   I've attached a summary of the change, but basically, for PA 2.0, as
+   long as the ",CO" (coherent operation) completer is specified, then the
+   16-byte alignment requirement for ldcw and ldcd is relaxed, and instead
+   they only require "natural" alignment (4-byte for ldcw, 8-byte for
+   ldcd). */
+
+#define __PA_LDCW_ALIGNMENT	4
+#define __ldcw_align(a) (&(a)->slock)
+#define __LDCW	"ldcw,co"
+
+#endif /*!CONFIG_PA20*/
+
+/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.  */
+#define __ldcw(a) ({						\
+	unsigned __ret;						\
+	__asm__ __volatile__(__LDCW " 0(%2),%0"			\
+		: "=r" (__ret), "+m" (*(a)) : "r" (a));		\
+	__ret;							\
+})
+
+#ifdef CONFIG_SMP
+# define __lock_aligned __attribute__((__section__(".data..lock_aligned")))
+#endif
+
+#endif /* __PARISC_LDCW_H */
diff --git a/arch/parisc/include/asm/mman.h b/arch/parisc/include/asm/mman.h
index f5b7bf5..12219eb 100644
--- a/arch/parisc/include/asm/mman.h
+++ b/arch/parisc/include/asm/mman.h
@@ -62,6 +62,10 @@
 #define MADV_HUGEPAGE	67		/* Worth backing with hugepages */
 #define MADV_NOHUGEPAGE	68		/* Not worth backing with hugepages */
 
+#define MADV_DONTDUMP   69		/* Explicity exclude from the core dump,
+					   overrides the coredump filter bits */
+#define MADV_DODUMP	70		/* Clear the MADV_NODUMP flag */
+
 /* compatibility flags */
 #define MAP_FILE	0
 #define MAP_VARIABLE	0
diff --git a/arch/parisc/include/asm/pci.h b/arch/parisc/include/asm/pci.h
index 2242a5c..3234f49 100644
--- a/arch/parisc/include/asm/pci.h
+++ b/arch/parisc/include/asm/pci.h
@@ -82,38 +82,8 @@
 
 #ifdef CONFIG_64BIT
 #define PCI_F_EXTEND		0xffffffff00000000UL
-#define PCI_IS_LMMIO(hba,a)	pci_is_lmmio(hba,a)
-
-/* We need to know if an address is LMMMIO or GMMIO.
- * LMMIO requires mangling and GMMIO we must use as-is.
- */
-static __inline__  int pci_is_lmmio(struct pci_hba_data *hba, unsigned long a)
-{
-	return(((a) & PCI_F_EXTEND) == PCI_F_EXTEND);
-}
-
-/*
-** Convert between PCI (IO_VIEW) addresses and processor (PA_VIEW) addresses.
-** See pci.c for more conversions used by Generic PCI code.
-**
-** Platform characteristics/firmware guarantee that
-**	(1) PA_VIEW - IO_VIEW = lmmio_offset for both LMMIO and ELMMIO
-**	(2) PA_VIEW == IO_VIEW for GMMIO
-*/
-#define PCI_BUS_ADDR(hba,a)	(PCI_IS_LMMIO(hba,a)	\
-		?  ((a) - hba->lmmio_space_offset)	/* mangle LMMIO */ \
-		: (a))					/* GMMIO */
-#define PCI_HOST_ADDR(hba,a)	(((a) & PCI_F_EXTEND) == 0 \
-		? (a) + hba->lmmio_space_offset \
-		: (a))
-
 #else	/* !CONFIG_64BIT */
-
-#define PCI_BUS_ADDR(hba,a)	(a)
-#define PCI_HOST_ADDR(hba,a)	(a)
 #define PCI_F_EXTEND		0UL
-#define PCI_IS_LMMIO(hba,a)	(1)	/* 32-bit doesn't support GMMIO */
-
 #endif /* !CONFIG_64BIT */
 
 /*
@@ -245,14 +215,6 @@
 }
 #endif
 
-extern void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-			 struct resource *res);
-
-extern void
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-			struct pci_bus_region *region);
-
 static inline void pcibios_penalize_isa_irq(int irq, int active)
 {
 	/* We don't need to penalize isa irq's */
diff --git a/arch/parisc/include/asm/posix_types.h b/arch/parisc/include/asm/posix_types.h
index 00da29a..5212b03 100644
--- a/arch/parisc/include/asm/posix_types.h
+++ b/arch/parisc/include/asm/posix_types.h
@@ -6,123 +6,22 @@
  * be a little careful about namespace pollution etc.  Also, we cannot
  * assume GCC is being used.
  */
-typedef unsigned long		__kernel_ino_t;
+
 typedef unsigned short		__kernel_mode_t;
+#define __kernel_mode_t __kernel_mode_t
+
 typedef unsigned short		__kernel_nlink_t;
-typedef long			__kernel_off_t;
-typedef int			__kernel_pid_t;
+#define __kernel_nlink_t __kernel_nlink_t
+
 typedef unsigned short		__kernel_ipc_pid_t;
-typedef unsigned int		__kernel_uid_t;
-typedef unsigned int		__kernel_gid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
+
 typedef int			__kernel_suseconds_t;
-typedef long			__kernel_clock_t;
-typedef int			__kernel_timer_t;
-typedef int			__kernel_clockid_t;
-typedef int			__kernel_daddr_t;
-/* Note these change from narrow to wide kernels */
-#ifdef CONFIG_64BIT
-typedef unsigned long		__kernel_size_t;
-typedef long			__kernel_ssize_t;
-typedef long			__kernel_ptrdiff_t;
-#else
-typedef unsigned int		__kernel_size_t;
-typedef int			__kernel_ssize_t;
-typedef int			__kernel_ptrdiff_t;
-#endif
-typedef long			__kernel_time_t;
-typedef char *			__kernel_caddr_t;
+#define __kernel_suseconds_t __kernel_suseconds_t
 
-typedef unsigned short		__kernel_uid16_t;
-typedef unsigned short		__kernel_gid16_t;
-typedef unsigned int		__kernel_uid32_t;
-typedef unsigned int		__kernel_gid32_t;
-
-#ifdef __GNUC__
-typedef long long		__kernel_loff_t;
 typedef long long		__kernel_off64_t;
 typedef unsigned long long	__kernel_ino64_t;
-#endif
 
-typedef unsigned int		__kernel_old_dev_t;
-
-typedef struct {
-	int	val[2];
-} __kernel_fsid_t;
-
-/* compatibility stuff */
-typedef __kernel_uid_t __kernel_old_uid_t;
-typedef __kernel_gid_t __kernel_old_gid_t;
-
-#if defined(__KERNEL__)
-
-#undef __FD_SET
-static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-	unsigned long __tmp = __fd / __NFDBITS;
-	unsigned long __rem = __fd % __NFDBITS;
-	__fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
-}
-
-#undef __FD_CLR
-static __inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-	unsigned long __tmp = __fd / __NFDBITS;
-	unsigned long __rem = __fd % __NFDBITS;
-	__fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
-}
-
-#undef __FD_ISSET
-static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
-{ 
-	unsigned long __tmp = __fd / __NFDBITS;
-	unsigned long __rem = __fd % __NFDBITS;
-	return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
-}
-
-/*
- * This will unroll the loop for the normal constant case (8 ints,
- * for a 256-bit fd_set)
- */
-#undef __FD_ZERO
-static __inline__ void __FD_ZERO(__kernel_fd_set *__p)
-{
-	unsigned long *__tmp = __p->fds_bits;
-	int __i;
-
-	if (__builtin_constant_p(__FDSET_LONGS)) {
-		switch (__FDSET_LONGS) {
-		case 16:
-			__tmp[ 0] = 0; __tmp[ 1] = 0;
-			__tmp[ 2] = 0; __tmp[ 3] = 0;
-			__tmp[ 4] = 0; __tmp[ 5] = 0;
-			__tmp[ 6] = 0; __tmp[ 7] = 0;
-			__tmp[ 8] = 0; __tmp[ 9] = 0;
-			__tmp[10] = 0; __tmp[11] = 0;
-			__tmp[12] = 0; __tmp[13] = 0;
-			__tmp[14] = 0; __tmp[15] = 0;
-			return;
-
-		case 8:
-			__tmp[ 0] = 0; __tmp[ 1] = 0;
-			__tmp[ 2] = 0; __tmp[ 3] = 0;
-			__tmp[ 4] = 0; __tmp[ 5] = 0;
-			__tmp[ 6] = 0; __tmp[ 7] = 0;
-			return;
-
-		case 4:
-			__tmp[ 0] = 0; __tmp[ 1] = 0;
-			__tmp[ 2] = 0; __tmp[ 3] = 0;
-			return;
-		}
-	}
-	__i = __FDSET_LONGS;
-	while (__i) {
-		__i--;
-		*__tmp = 0;
-		__tmp++;
-	}
-}
-
-#endif /* defined(__KERNEL__) */
+#include <asm-generic/posix_types.h>
 
 #endif
diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h
index 7213ec9..acdf4ca 100644
--- a/arch/parisc/include/asm/processor.h
+++ b/arch/parisc/include/asm/processor.h
@@ -16,7 +16,6 @@
 #include <asm/pdc.h>
 #include <asm/ptrace.h>
 #include <asm/types.h>
-#include <asm/system.h>
 #include <asm/percpu.h>
 
 #endif /* __ASSEMBLY__ */
@@ -169,6 +168,7 @@
  * Return saved PC of a blocked thread.  This is used by ps mostly.
  */
 
+struct task_struct;
 unsigned long thread_saved_pc(struct task_struct *t);
 void show_trace(struct task_struct *task, unsigned long *stack);
 
diff --git a/arch/parisc/include/asm/psw.h b/arch/parisc/include/asm/psw.h
index 5a3e23c..ad69a35 100644
--- a/arch/parisc/include/asm/psw.h
+++ b/arch/parisc/include/asm/psw.h
@@ -59,4 +59,45 @@
 #define USER_PSW_MASK (WIDE_PSW | PSW_T | PSW_N | PSW_X | PSW_B | PSW_V | PSW_CB)
 #define USER_PSW      (PSW_C | PSW_Q | PSW_P | PSW_D | PSW_I)
 
+#ifndef __ASSEMBLY__
+
+/* The program status word as bitfields.  */
+struct pa_psw {
+	unsigned int y:1;
+	unsigned int z:1;
+	unsigned int rv:2;
+	unsigned int w:1;
+	unsigned int e:1;
+	unsigned int s:1;
+	unsigned int t:1;
+
+	unsigned int h:1;
+	unsigned int l:1;
+	unsigned int n:1;
+	unsigned int x:1;
+	unsigned int b:1;
+	unsigned int c:1;
+	unsigned int v:1;
+	unsigned int m:1;
+
+	unsigned int cb:8;
+
+	unsigned int o:1;
+	unsigned int g:1;
+	unsigned int f:1;
+	unsigned int r:1;
+	unsigned int q:1;
+	unsigned int p:1;
+	unsigned int d:1;
+	unsigned int i:1;
+};
+
+#ifdef CONFIG_64BIT
+#define pa_psw(task) ((struct pa_psw *) ((char *) (task) + TASK_PT_PSW + 4))
+#else
+#define pa_psw(task) ((struct pa_psw *) ((char *) (task) + TASK_PT_PSW))
+#endif
+
+#endif /* !__ASSEMBLY__ */
+
 #endif
diff --git a/arch/parisc/include/asm/special_insns.h b/arch/parisc/include/asm/special_insns.h
new file mode 100644
index 0000000..d306b75
--- /dev/null
+++ b/arch/parisc/include/asm/special_insns.h
@@ -0,0 +1,40 @@
+#ifndef __PARISC_SPECIAL_INSNS_H
+#define __PARISC_SPECIAL_INSNS_H
+
+#define mfctl(reg)	({		\
+	unsigned long cr;		\
+	__asm__ __volatile__(		\
+		"mfctl " #reg ",%0" :	\
+		 "=r" (cr)		\
+	);				\
+	cr;				\
+})
+
+#define mtctl(gr, cr) \
+	__asm__ __volatile__("mtctl %0,%1" \
+		: /* no outputs */ \
+		: "r" (gr), "i" (cr) : "memory")
+
+/* these are here to de-mystefy the calling code, and to provide hooks */
+/* which I needed for debugging EIEM problems -PB */
+#define get_eiem() mfctl(15)
+static inline void set_eiem(unsigned long val)
+{
+	mtctl(val, 15);
+}
+
+#define mfsp(reg)	({		\
+	unsigned long cr;		\
+	__asm__ __volatile__(		\
+		"mfsp " #reg ",%0" :	\
+		 "=r" (cr)		\
+	);				\
+	cr;				\
+})
+
+#define mtsp(gr, cr) \
+	__asm__ __volatile__("mtsp %0,%1" \
+		: /* no outputs */ \
+		: "r" (gr), "i" (cr) : "memory")
+
+#endif /* __PARISC_SPECIAL_INSNS_H */
diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h
index 74036f4..804aa28 100644
--- a/arch/parisc/include/asm/spinlock.h
+++ b/arch/parisc/include/asm/spinlock.h
@@ -1,7 +1,6 @@
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
 
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/spinlock_types.h>
 
diff --git a/arch/parisc/include/asm/switch_to.h b/arch/parisc/include/asm/switch_to.h
new file mode 100644
index 0000000..8ed8fea
--- /dev/null
+++ b/arch/parisc/include/asm/switch_to.h
@@ -0,0 +1,12 @@
+#ifndef __PARISC_SWITCH_TO_H
+#define __PARISC_SWITCH_TO_H
+
+struct task_struct;
+
+extern struct task_struct *_switch_to(struct task_struct *, struct task_struct *);
+
+#define switch_to(prev, next, last) do {			\
+	(last) = _switch_to(prev, next);			\
+} while(0)
+
+#endif /* __PARISC_SWITCH_TO_H */
diff --git a/arch/parisc/include/asm/system.h b/arch/parisc/include/asm/system.h
deleted file mode 100644
index b19e63a..0000000
--- a/arch/parisc/include/asm/system.h
+++ /dev/null
@@ -1,165 +0,0 @@
-#ifndef __PARISC_SYSTEM_H
-#define __PARISC_SYSTEM_H
-
-#include <linux/irqflags.h>
-
-/* The program status word as bitfields.  */
-struct pa_psw {
-	unsigned int y:1;
-	unsigned int z:1;
-	unsigned int rv:2;
-	unsigned int w:1;
-	unsigned int e:1;
-	unsigned int s:1;
-	unsigned int t:1;
-
-	unsigned int h:1;
-	unsigned int l:1;
-	unsigned int n:1;
-	unsigned int x:1;
-	unsigned int b:1;
-	unsigned int c:1;
-	unsigned int v:1;
-	unsigned int m:1;
-
-	unsigned int cb:8;
-
-	unsigned int o:1;
-	unsigned int g:1;
-	unsigned int f:1;
-	unsigned int r:1;
-	unsigned int q:1;
-	unsigned int p:1;
-	unsigned int d:1;
-	unsigned int i:1;
-};
-
-#ifdef CONFIG_64BIT
-#define pa_psw(task) ((struct pa_psw *) ((char *) (task) + TASK_PT_PSW + 4))
-#else
-#define pa_psw(task) ((struct pa_psw *) ((char *) (task) + TASK_PT_PSW))
-#endif
-
-struct task_struct;
-
-extern struct task_struct *_switch_to(struct task_struct *, struct task_struct *);
-
-#define switch_to(prev, next, last) do {			\
-	(last) = _switch_to(prev, next);			\
-} while(0)
-
-#define mfctl(reg)	({		\
-	unsigned long cr;		\
-	__asm__ __volatile__(		\
-		"mfctl " #reg ",%0" :	\
-		 "=r" (cr)		\
-	);				\
-	cr;				\
-})
-
-#define mtctl(gr, cr) \
-	__asm__ __volatile__("mtctl %0,%1" \
-		: /* no outputs */ \
-		: "r" (gr), "i" (cr) : "memory")
-
-/* these are here to de-mystefy the calling code, and to provide hooks */
-/* which I needed for debugging EIEM problems -PB */
-#define get_eiem() mfctl(15)
-static inline void set_eiem(unsigned long val)
-{
-	mtctl(val, 15);
-}
-
-#define mfsp(reg)	({		\
-	unsigned long cr;		\
-	__asm__ __volatile__(		\
-		"mfsp " #reg ",%0" :	\
-		 "=r" (cr)		\
-	);				\
-	cr;				\
-})
-
-#define mtsp(gr, cr) \
-	__asm__ __volatile__("mtsp %0,%1" \
-		: /* no outputs */ \
-		: "r" (gr), "i" (cr) : "memory")
-
-
-/*
-** This is simply the barrier() macro from linux/kernel.h but when serial.c
-** uses tqueue.h uses smp_mb() defined using barrier(), linux/kernel.h
-** hasn't yet been included yet so it fails, thus repeating the macro here.
-**
-** PA-RISC architecture allows for weakly ordered memory accesses although
-** none of the processors use it. There is a strong ordered bit that is
-** set in the O-bit of the page directory entry. Operating systems that
-** can not tolerate out of order accesses should set this bit when mapping
-** pages. The O-bit of the PSW should also be set to 1 (I don't believe any
-** of the processor implemented the PSW O-bit). The PCX-W ERS states that
-** the TLB O-bit is not implemented so the page directory does not need to
-** have the O-bit set when mapping pages (section 3.1). This section also
-** states that the PSW Y, Z, G, and O bits are not implemented.
-** So it looks like nothing needs to be done for parisc-linux (yet).
-** (thanks to chada for the above comment -ggg)
-**
-** The __asm__ op below simple prevents gcc/ld from reordering
-** instructions across the mb() "call".
-*/
-#define mb()		__asm__ __volatile__("":::"memory")	/* barrier() */
-#define rmb()		mb()
-#define wmb()		mb()
-#define smp_mb()	mb()
-#define smp_rmb()	mb()
-#define smp_wmb()	mb()
-#define smp_read_barrier_depends()	do { } while(0)
-#define read_barrier_depends()		do { } while(0)
-
-#define set_mb(var, value)		do { var = value; mb(); } while (0)
-
-#ifndef CONFIG_PA20
-/* Because kmalloc only guarantees 8-byte alignment for kmalloc'd data,
-   and GCC only guarantees 8-byte alignment for stack locals, we can't
-   be assured of 16-byte alignment for atomic lock data even if we
-   specify "__attribute ((aligned(16)))" in the type declaration.  So,
-   we use a struct containing an array of four ints for the atomic lock
-   type and dynamically select the 16-byte aligned int from the array
-   for the semaphore.  */
-
-#define __PA_LDCW_ALIGNMENT	16
-#define __ldcw_align(a) ({					\
-	unsigned long __ret = (unsigned long) &(a)->lock[0];	\
-	__ret = (__ret + __PA_LDCW_ALIGNMENT - 1)		\
-		& ~(__PA_LDCW_ALIGNMENT - 1);			\
-	(volatile unsigned int *) __ret;			\
-})
-#define __LDCW	"ldcw"
-
-#else /*CONFIG_PA20*/
-/* From: "Jim Hull" <jim.hull of hp.com>
-   I've attached a summary of the change, but basically, for PA 2.0, as
-   long as the ",CO" (coherent operation) completer is specified, then the
-   16-byte alignment requirement for ldcw and ldcd is relaxed, and instead
-   they only require "natural" alignment (4-byte for ldcw, 8-byte for
-   ldcd). */
-
-#define __PA_LDCW_ALIGNMENT	4
-#define __ldcw_align(a) (&(a)->slock)
-#define __LDCW	"ldcw,co"
-
-#endif /*!CONFIG_PA20*/
-
-/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.  */
-#define __ldcw(a) ({						\
-	unsigned __ret;						\
-	__asm__ __volatile__(__LDCW " 0(%2),%0"			\
-		: "=r" (__ret), "+m" (*(a)) : "r" (a));		\
-	__ret;							\
-})
-
-#ifdef CONFIG_SMP
-# define __lock_aligned __attribute__((__section__(".data..lock_aligned")))
-#endif
-
-#define arch_align_stack(x) (x)
-
-#endif
diff --git a/arch/parisc/include/asm/thread_info.h b/arch/parisc/include/asm/thread_info.h
index 6d9c7c7..83ae7dd 100644
--- a/arch/parisc/include/asm/thread_info.h
+++ b/arch/parisc/include/asm/thread_info.h
@@ -5,6 +5,7 @@
 
 #ifndef __ASSEMBLY__
 #include <asm/processor.h>
+#include <asm/special_insns.h>
 
 struct thread_info {
 	struct task_struct *task;	/* main task structure */
diff --git a/arch/parisc/include/asm/timex.h b/arch/parisc/include/asm/timex.h
index 3b68d77..2bd51f6 100644
--- a/arch/parisc/include/asm/timex.h
+++ b/arch/parisc/include/asm/timex.h
@@ -6,7 +6,6 @@
 #ifndef _ASMPARISC_TIMEX_H
 #define _ASMPARISC_TIMEX_H
 
-#include <asm/system.h>
 
 #define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
 
diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h
index ff4cf9d..9ac0660 100644
--- a/arch/parisc/include/asm/uaccess.h
+++ b/arch/parisc/include/asm/uaccess.h
@@ -5,7 +5,6 @@
  * User space memory access functions
  */
 #include <asm/page.h>
-#include <asm/system.h>
 #include <asm/cache.h>
 #include <asm/errno.h>
 #include <asm-generic/uaccess-unaligned.h>
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index 83335f3..9d18189 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -22,7 +22,6 @@
 #include <asm/cache.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c
index 4896ed0..f65fa48 100644
--- a/arch/parisc/kernel/firmware.c
+++ b/arch/parisc/kernel/firmware.c
@@ -67,7 +67,6 @@
 #include <asm/page.h>
 #include <asm/pdc.h>
 #include <asm/pdcpat.h>
-#include <asm/system.h>
 #include <asm/processor.h>	/* for boot_cpu_data */
 
 static DEFINE_SPINLOCK(pdc_lock);
diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
index 9efd974..24644ac 100644
--- a/arch/parisc/kernel/pci.c
+++ b/arch/parisc/kernel/pci.c
@@ -16,7 +16,6 @@
 #include <linux/types.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/superio.h>
 
 #define DEBUG_RESOURCES 0
@@ -195,58 +194,6 @@
 	pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bridge_ctl);
 }
 
-/* called by drivers/pci/setup-bus.c:pci_setup_bridge().  */
-void __devinit pcibios_resource_to_bus(struct pci_dev *dev,
-		struct pci_bus_region *region, struct resource *res)
-{
-#ifdef CONFIG_64BIT
-	struct pci_hba_data *hba = HBA_DATA(dev->bus->bridge->platform_data);
-#endif
-
-	if (res->flags & IORESOURCE_IO) {
-		/*
-		** I/O space may see busnumbers here. Something
-		** in the form of 0xbbxxxx where bb is the bus num
-		** and xxxx is the I/O port space address.
-		** Remaining address translation are done in the
-		** PCI Host adapter specific code - ie dino_out8.
-		*/
-		region->start = PCI_PORT_ADDR(res->start);
-		region->end   = PCI_PORT_ADDR(res->end);
-	} else if (res->flags & IORESOURCE_MEM) {
-		/* Convert MMIO addr to PCI addr (undo global virtualization) */
-		region->start = PCI_BUS_ADDR(hba, res->start);
-		region->end   = PCI_BUS_ADDR(hba, res->end);
-	}
-
-	DBG_RES("pcibios_resource_to_bus(%02x %s [%lx,%lx])\n",
-		dev->bus->number, res->flags & IORESOURCE_IO ? "IO" : "MEM",
-		region->start, region->end);
-}
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-			      struct pci_bus_region *region)
-{
-#ifdef CONFIG_64BIT
-	struct pci_hba_data *hba = HBA_DATA(dev->bus->bridge->platform_data);
-#endif
-
-	if (res->flags & IORESOURCE_MEM) {
-		res->start = PCI_HOST_ADDR(hba, region->start);
-		res->end = PCI_HOST_ADDR(hba, region->end);
-	}
-
-	if (res->flags & IORESOURCE_IO) {
-		res->start = region->start;
-		res->end = region->end;
-	}
-}
-
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-#endif
-
 /*
  * pcibios align resources() is called every time generic PCI code
  * wants to generate a new address. The process of looking for
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
index 2905b1f..857c2f5 100644
--- a/arch/parisc/kernel/ptrace.c
+++ b/arch/parisc/kernel/ptrace.c
@@ -22,7 +22,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/asm-offsets.h>
 
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
index 32d5884..0bb1d63 100644
--- a/arch/parisc/kernel/smp.c
+++ b/arch/parisc/kernel/smp.c
@@ -32,7 +32,6 @@
 #include <linux/bitops.h>
 #include <linux/ftrace.h>
 
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/current.h>
 #include <asm/delay.h>
@@ -291,8 +290,7 @@
 	mb();
 
 	/* Well, support 2.4 linux scheme as well. */
-	if (cpu_isset(cpunum, cpu_online_map))
-	{
+	if (cpu_online(cpunum))	{
 		extern void machine_halt(void); /* arch/parisc.../process.c */
 
 		printk(KERN_CRIT "CPU#%d already initialized!\n", cpunum);
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index f19e660..45ba99f 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -27,7 +27,6 @@
 #include <linux/bug.h>
 
 #include <asm/assembly.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
diff --git a/arch/parisc/lib/bitops.c b/arch/parisc/lib/bitops.c
index a8bffd8..1871188 100644
--- a/arch/parisc/lib/bitops.c
+++ b/arch/parisc/lib/bitops.c
@@ -8,7 +8,6 @@
 
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
-#include <asm/system.h>
 #include <linux/atomic.h>
 
 #ifdef CONFIG_SMP
diff --git a/arch/parisc/math-emu/fpudispatch.c b/arch/parisc/math-emu/fpudispatch.c
index 6e28f9f..673b73e 100644
--- a/arch/parisc/math-emu/fpudispatch.c
+++ b/arch/parisc/math-emu/fpudispatch.c
@@ -50,6 +50,7 @@
 #define FPUDEBUG 0
 
 #include "float.h"
+#include <linux/bug.h>
 #include <linux/kernel.h>
 #include <asm/processor.h>
 /* #include <sys/debug.h> */
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 303703d..feab3ba 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -133,7 +133,7 @@
 	select HAVE_REGS_AND_STACK_ACCESS_API
 	select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64
 	select HAVE_GENERIC_HARDIRQS
-	select HAVE_SPARSE_IRQ
+	select SPARSE_IRQ
 	select IRQ_PER_CPU
 	select IRQ_DOMAIN
 	select GENERIC_IRQ_SHOW
@@ -153,6 +153,7 @@
 	bool
 	default y if PPC64
 	select COMPAT_BINFMT_ELF
+	select ARCH_WANT_OLD_COMPAT_IPC
 
 config SYSVIPC_COMPAT
 	bool
@@ -377,13 +378,16 @@
 	  The same kernel binary can be used as production kernel and dump
 	  capture kernel.
 
-config PHYP_DUMP
-	bool "Hypervisor-assisted dump (EXPERIMENTAL)"
-	depends on PPC_PSERIES && EXPERIMENTAL
+config FA_DUMP
+	bool "Firmware-assisted dump"
+	depends on PPC64 && PPC_RTAS && CRASH_DUMP
 	help
-	  Hypervisor-assisted dump is meant to be a kdump replacement
-	  offering robustness and speed not possible without system
-	  hypervisor assistance.
+	  A robust mechanism to get reliable kernel crash dump with
+	  assistance from firmware. This approach does not use kexec,
+	  instead firmware assists in booting the kdump kernel
+	  while preserving memory contents. Firmware-assisted dump
+	  is meant to be a kdump replacement offering robustness and
+	  speed not possible without system firmware assistance.
 
 	  If unsure, say "N"
 
@@ -612,7 +616,7 @@
 
 config ISA_DMA_API
 	bool
-	default !PPC_ISERIES || PCI
+	default PCI
 
 menu "Bus options"
 
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index 4ccb2a0..e5f2689 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -114,16 +114,6 @@
 	depends on KGDB || XMON
 	default y
 
-config VIRQ_DEBUG
-	bool "Expose hardware/virtual IRQ mapping via debugfs"
-	depends on DEBUG_FS
-	help
-	  This option will show the mapping relationship between hardware irq
-	  numbers and virtual irq numbers. The mapping is exposed via debugfs
-	  in the file powerpc/virq_mapping.
-
-	  If you don't know what this means you don't need it.
-
 config BDI_SWITCH
 	bool "Include BDI-2000 user context switcher"
 	depends on DEBUG_KERNEL && PPC32
@@ -196,13 +186,6 @@
 	help
 	  Select this to enable early debugging for Maple.
 
-config PPC_EARLY_DEBUG_ISERIES
-	bool "iSeries HV Console"
-	depends on PPC_ISERIES
-	help
-	  Select this to enable early debugging for legacy iSeries. You need
-	  to hit "Ctrl-x Ctrl-x" to see the messages on the console.
-
 config PPC_EARLY_DEBUG_PAS_REALMODE
 	bool "PA Semi real mode"
 	depends on PPC_PASEMI
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index b8b105c..6524c6e 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -157,6 +157,7 @@
 				   arch/powerpc/net/
 core-$(CONFIG_XMON)		+= arch/powerpc/xmon/
 core-$(CONFIG_KVM) 		+= arch/powerpc/kvm/
+core-$(CONFIG_PERF_EVENTS)	+= arch/powerpc/perf/
 
 drivers-$(CONFIG_OPROFILE)	+= arch/powerpc/oprofile/
 
diff --git a/arch/powerpc/boot/.gitignore b/arch/powerpc/boot/.gitignore
index 12da77e..1c1aadc 100644
--- a/arch/powerpc/boot/.gitignore
+++ b/arch/powerpc/boot/.gitignore
@@ -27,7 +27,6 @@
 zImage.chrp
 zImage.coff
 zImage.holly
-zImage.iseries
 zImage.*lds
 zImage.miboot
 zImage.pmac
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 8844a17..e8461cb 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -184,7 +184,6 @@
 image-$(CONFIG_PPC_PMAC)		+= zImage.pmac
 image-$(CONFIG_PPC_HOLLY)		+= dtbImage.holly
 image-$(CONFIG_PPC_PRPMC2800)		+= dtbImage.prpmc2800
-image-$(CONFIG_PPC_ISERIES)		+= zImage.iseries
 image-$(CONFIG_DEFAULT_UIMAGE)		+= uImage
 image-$(CONFIG_EPAPR_BOOT)		+= zImage.epapr
 
@@ -247,7 +246,7 @@
 image-$(CONFIG_MPC8540_ADS)		+= cuImage.mpc8540ads
 image-$(CONFIG_MPC8560_ADS)		+= cuImage.mpc8560ads
 image-$(CONFIG_MPC85xx_CDS)		+= cuImage.mpc8541cds \
-					   cuImage.mpc8548cds \
+					   cuImage.mpc8548cds_32b \
 					   cuImage.mpc8555cds
 image-$(CONFIG_MPC85xx_MDS)		+= cuImage.mpc8568mds
 image-$(CONFIG_MPC85xx_DS)		+= cuImage.mpc8544ds \
@@ -311,12 +310,6 @@
 $(obj)/vmlinux.strip: vmlinux
 	$(STRIP) -s -R .comment $< -o $@
 
-# The iseries hypervisor won't take an ET_DYN executable, so this
-# changes the type (byte 17) in the file to ET_EXEC (2).
-$(obj)/zImage.iseries: vmlinux
-	$(STRIP) -s -R .comment $< -o $@
-	printf "\x02" | dd of=$@ conv=notrunc bs=1 seek=17
-
 $(obj)/uImage: vmlinux $(wrapperbits)
 	$(call if_changed,wrap,uboot)
 
@@ -364,7 +357,7 @@
 # anything not in $(targets)
 clean-files += $(image-) $(initrd-) cuImage.* dtbImage.* treeImage.* \
 	zImage zImage.initrd zImage.chrp zImage.coff zImage.holly \
-	zImage.iseries zImage.miboot zImage.pmac zImage.pseries \
+	zImage.miboot zImage.pmac zImage.pseries \
 	zImage.maple simpleImage.* otheros.bld *.dtb
 
 # clean up files cached by wrapper
diff --git a/arch/powerpc/boot/dts/a4m072.dts b/arch/powerpc/boot/dts/a4m072.dts
new file mode 100644
index 0000000..fabe7b7
--- /dev/null
+++ b/arch/powerpc/boot/dts/a4m072.dts
@@ -0,0 +1,168 @@
+/*
+ * a4m072 board Device Tree Source
+ *
+ * Copyright (C) 2011 DENX Software Engineering GmbH
+ * Heiko Schocher <hs@denx.de>
+ *
+ * Copyright (C) 2007 Semihalf
+ * Marian Balakowicz <m8@semihalf.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/ "mpc5200b.dtsi"
+
+/ {
+	model = "anonymous,a4m072";
+	compatible = "anonymous,a4m072";
+
+	soc5200@f0000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "fsl,mpc5200b-immr";
+		ranges = <0 0xf0000000 0x0000c000>;
+		reg = <0xf0000000 0x00000100>;
+		bus-frequency = <0>; /* From boot loader */
+		system-frequency = <0>; /* From boot loader */
+
+		cdm@200 {
+			fsl,init-ext-48mhz-en = <0x0>;
+			fsl,init-fd-enable = <0x01>;
+			fsl,init-fd-counters = <0x3333>;
+		};
+
+		timer@600 {
+			fsl,has-wdt;
+		};
+
+		gpt3: timer@630 { /* General Purpose Timer in GPIO mode */
+			compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+
+		gpt4: timer@640 { /* General Purpose Timer in GPIO mode */
+			compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+
+		gpt5: timer@650 { /* General Purpose Timer in GPIO mode */
+			compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+
+		spi@f00 {
+			status = "disabled";
+		};
+
+		psc@2000 {
+			compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+			reg = <0x2000 0x100>;
+			interrupts = <2 1 0>;
+		};
+
+		psc@2200 {
+			compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+			reg = <0x2200 0x100>;
+			interrupts = <2 2 0>;
+		};
+
+		psc@2400 {
+			compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+			reg = <0x2400 0x100>;
+			interrupts = <2 3 0>;
+		};
+
+		psc@2600 {
+			status = "disabled";
+		};
+
+		psc@2800 {
+			status = "disabled";
+		};
+
+		psc@2c00 {
+			compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+			reg = <0x2c00 0x100>;
+			interrupts = <2 4 0>;
+		};
+
+		ethernet@3000 {
+			phy-handle = <&phy0>;
+		};
+
+		mdio@3000 {
+			phy0: ethernet-phy@1f {
+				reg = <0x1f>;
+				interrupts = <1 2 0>; /* IRQ 2 active low */
+			};
+		};
+
+		i2c@3d00 {
+			status = "disabled";
+		};
+
+		i2c@3d40 {
+			hwmon@2e {
+				compatible = "nsc,lm87";
+				reg = <0x2e>;
+			};
+			rtc@51 {
+				compatible = "nxp,rtc8564";
+				reg = <0x51>;
+			};
+		};
+	};
+
+	localbus {
+		compatible = "fsl,mpc5200b-lpb","simple-bus";
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges = <0 0 0xfe000000 0x02000000
+			  1 0 0x62000000 0x00400000
+			  2 0 0x64000000 0x00200000
+			  3 0 0x66000000 0x01000000
+			  6 0 0x68000000 0x01000000
+			  7 0 0x6a000000 0x00000004>;
+
+		flash@0,0 {
+			compatible = "cfi-flash";
+			reg = <0 0 0x02000000>;
+			bank-width = <2>;
+			#size-cells = <1>;
+			#address-cells = <1>;
+		};
+		sram0@1,0 {
+			compatible = "mtd-ram";
+			reg = <1 0x00000 0x00400000>;
+			bank-width = <2>;
+		};
+	};
+
+	pci@f0000d00 {
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		device_type = "pci";
+		compatible = "fsl,mpc5200-pci";
+		reg = <0xf0000d00 0x100>;
+		interrupt-map-mask = <0xf800 0 0 7>;
+		interrupt-map = <
+				 /* IDSEL 0x16 */
+				 0xc000 0 0 1 &mpc5200_pic 1 3 3
+				 0xc000 0 0 2 &mpc5200_pic 1 3 3
+				 0xc000 0 0 3 &mpc5200_pic 1 3 3
+				 0xc000 0 0 4 &mpc5200_pic 1 3 3>;
+		clock-frequency = <0>; /* From boot loader */
+		interrupts = <2 8 0 2 9 0 2 10 0>;
+		bus-range = <0 0>;
+		ranges = <0x42000000 0 0x80000000 0x80000000 0 0x10000000
+			  0x02000000 0 0x90000000 0x90000000 0 0x10000000
+			  0x01000000 0 0x00000000 0xa0000000 0 0x01000000>;
+	};
+};
diff --git a/arch/powerpc/boot/dts/bluestone.dts b/arch/powerpc/boot/dts/bluestone.dts
index 74876f7..7bda373 100644
--- a/arch/powerpc/boot/dts/bluestone.dts
+++ b/arch/powerpc/boot/dts/bluestone.dts
@@ -33,7 +33,7 @@
 	aliases {
 		ethernet0 = &EMAC0;
 		serial0 = &UART0;
-		//serial1 = &UART1; --gcl missing UART1 label
+		serial1 = &UART1;
 	};
 
 	cpus {
@@ -52,7 +52,7 @@
 			d-cache-size = <32768>;
 			dcr-controller;
 			dcr-access-method = "native";
-			//next-level-cache = <&L2C0>; --gcl missing L2C0 label
+			next-level-cache = <&L2C0>;
 		};
 	};
 
@@ -117,6 +117,16 @@
 		dcr-reg = <0x00c 0x002>;
 	};
 
+	L2C0: l2c {
+		compatible = "ibm,l2-cache-apm82181", "ibm,l2-cache";
+		dcr-reg = <0x020 0x008
+			   0x030 0x008>;
+		cache-line-size = <32>;
+		cache-size = <262144>;
+		interrupt-parent = <&UIC1>;
+		interrupts = <11 1>;
+	};
+
 	plb {
 		compatible = "ibm,plb4";
 		#address-cells = <2>;
@@ -182,6 +192,53 @@
 						reg = <0x001a0000 0x00060000>;
 					};
 				};
+
+				ndfc@1,0 {
+					compatible = "ibm,ndfc";
+					reg = <0x00000003 0x00000000 0x00002000>;
+					ccr = <0x00001000>;
+					bank-settings = <0x80002222>;
+					#address-cells = <1>;
+					#size-cells = <1>;
+					/* 2Gb Nand Flash */
+					nand {
+						#address-cells = <1>;
+						#size-cells = <1>;
+
+						partition@0 {
+							label = "firmware";
+							reg   = <0x00000000 0x00C00000>;
+						};
+						partition@c00000 {
+							label = "environment";
+							reg   = <0x00C00000 0x00B00000>;
+						};
+						partition@1700000 {
+							label = "kernel";
+							reg   = <0x01700000 0x00E00000>;
+						};
+						partition@2500000 {
+							label = "root";
+							reg   = <0x02500000 0x08200000>;
+						};
+						partition@a700000 {
+							label = "device-tree";
+							reg   = <0x0A700000 0x00B00000>;
+						};
+						partition@b200000 {
+							label = "config";
+							reg   = <0x0B200000 0x00D00000>;
+						};
+						partition@bf00000 {
+							label = "diag";
+							reg   = <0x0BF00000 0x00C00000>;
+						};
+						partition@cb00000 {
+							label = "vendor";
+							reg   = <0x0CB00000 0x3500000>;
+						};
+					};
+				};
 			};
 
 			UART0: serial@ef600300 {
@@ -195,11 +252,36 @@
 				interrupts = <0x1 0x4>;
 			};
 
+			UART1: serial@ef600400 {
+				device_type = "serial";
+				compatible = "ns16550";
+				reg = <0xef600400 0x00000008>;
+				virtual-reg = <0xef600400>;
+				clock-frequency = <0>; /* Filled in by U-Boot */
+				current-speed = <0>; /* Filled in by U-Boot */
+				interrupt-parent = <&UIC0>;
+				interrupts = <0x1 0x4>;
+			};
+
 			IIC0: i2c@ef600700 {
 				compatible = "ibm,iic";
 				reg = <0xef600700 0x00000014>;
 				interrupt-parent = <&UIC0>;
 				interrupts = <0x2 0x4>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				rtc@68 {
+					compatible = "stm,m41t80";
+					reg = <0x68>;
+					interrupt-parent = <&UIC0>;
+					interrupts = <0x9 0x8>;
+				};
+				sttm@4C {
+					compatible = "adm,adm1032";
+					reg = <0x4C>;
+					interrupt-parent = <&UIC1>;
+					interrupts = <0x1E 0x8>; /* CPU_THERNAL_L */
+				};
 			};
 
 			IIC1: i2c@ef600800 {
@@ -250,5 +332,46 @@
 			};
 		};
 
+		PCIE0: pciex@d00000000 {
+			device_type = "pci";
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			compatible = "ibm,plb-pciex-apm821xx", "ibm,plb-pciex";
+			primary;
+			port = <0x0>; /* port number */
+			reg = <0x0000000d 0x00000000 0x20000000	/* Config space access */
+			       0x0000000c 0x08010000 0x00001000>;	/* Registers */
+			dcr-reg = <0x100 0x020>;
+			sdr-base = <0x300>;
+
+			/* Outbound ranges, one memory and one IO,
+			 * later cannot be changed
+			 */
+			ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000
+				  0x02000000 0x00000000 0x00000000 0x0000000f 0x00000000 0x00000000 0x00100000
+				  0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>;
+
+			/* Inbound 2GB range starting at 0 */
+			dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
+
+			/* This drives busses 40 to 0x7f */
+			bus-range = <0x40 0x7f>;
+
+			/* Legacy interrupts (note the weird polarity, the bridge seems
+			 * to invert PCIe legacy interrupts).
+			 * We are de-swizzling here because the numbers are actually for
+			 * port of the root complex virtual P2P bridge. But I want
+			 * to avoid putting a node for it in the tree, so the numbers
+			 * below are basically de-swizzled numbers.
+			 * The real slot is on idsel 0, so the swizzling is 1:1
+			 */
+			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+			interrupt-map = <
+				0x0 0x0 0x0 0x1 &UIC3 0xc 0x4 /* swizzled int A */
+				0x0 0x0 0x0 0x2 &UIC3 0xd 0x4 /* swizzled int B */
+				0x0 0x0 0x0 0x3 &UIC3 0xe 0x4 /* swizzled int C */
+				0x0 0x0 0x0 0x4 &UIC3 0xf 0x4 /* swizzled int D */>;
+		};
 	};
 };
diff --git a/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi
index b37da56..c8b2daa 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi
@@ -202,7 +202,7 @@
 /include/ "pq3-etsec1-timer-0.dtsi"
 
 	usb@22000 {
-		compatible = "fsl,mpc8536-usb2-mph", "fsl-usb2-mph";
+		compatible = "fsl-usb2-mph-v1.2", "fsl,mpc8536-usb2-mph", "fsl-usb2-mph";
 		reg = <0x22000 0x1000>;
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -210,7 +210,7 @@
 	};
 
 	usb@23000 {
-		compatible = "fsl,mpc8536-usb2-mph", "fsl-usb2-mph";
+		compatible = "fsl-usb2-mph-v1.2", "fsl,mpc8536-usb2-mph", "fsl-usb2-mph";
 		reg = <0x23000 0x1000>;
 		#address-cells = <1>;
 		#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi
index 9d8023a..579d76c 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi
@@ -89,6 +89,21 @@
 	};
 };
 
+&rio {
+	compatible = "fsl,srio";
+	interrupts = <48 2 0 0>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+	fsl,srio-rmu-handle = <&rmu>;
+	ranges;
+
+	port1 {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		cell-index = <1>;
+	};
+};
+
 &soc {
 	#address-cells = <1>;
 	#size-cells = <1>;
@@ -134,6 +149,7 @@
 
 /include/ "pq3-sec2.1-0.dtsi"
 /include/ "pq3-mpic.dtsi"
+/include/ "pq3-rmu-0.dtsi"
 
 	global-utilities@e0000 {
 		compatible = "fsl,mpc8548-guts";
diff --git a/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi
index 289f121..720422d 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi
@@ -43,7 +43,9 @@
 		serial0 = &serial0;
 		serial1 = &serial1;
 		ethernet0 = &enet0;
-		ethernet1 = &enet2;
+		ethernet1 = &enet1;
+		ethernet2 = &enet2;
+		ethernet3 = &enet3;
 		pci0 = &pci0;
 		pci1 = &pci1;
 		pci2 = &pci2;
diff --git a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
index a97d126..0bde9ee 100644
--- a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
@@ -156,6 +156,9 @@
 
 /include/ "pq3-dma-0.dtsi"
 /include/ "pq3-usb2-dr-0.dtsi"
+	usb@22000 {
+		compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+	};
 /include/ "pq3-esdhc-0.dtsi"
 	sdhc@2e000 {
 		compatible = "fsl,p1010-esdhc", "fsl,esdhc";
diff --git a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi
index 5de5fc3..68cc5e7 100644
--- a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi
@@ -142,7 +142,13 @@
 
 /include/ "pq3-dma-0.dtsi"
 /include/ "pq3-usb2-dr-0.dtsi"
+	usb@22000 {
+		compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+	};
 /include/ "pq3-usb2-dr-1.dtsi"
+	usb@23000 {
+		compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+	};
 
 /include/ "pq3-esdhc-0.dtsi"
 	sdhc@2e000 {
diff --git a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi
index 38ba54d..4252ef8 100644
--- a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi
@@ -142,8 +142,15 @@
 
 /include/ "pq3-dma-0.dtsi"
 /include/ "pq3-usb2-dr-0.dtsi"
+	usb@22000 {
+		compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+	};
 
 /include/ "pq3-esdhc-0.dtsi"
+	sdhc@2e000 {
+		sdhci,auto-cmd12;
+	};
+
 /include/ "pq3-sec3.3-0.dtsi"
 
 /include/ "pq3-mpic.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
index ff9ed1d8..06216b8 100644
--- a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
@@ -35,7 +35,11 @@
 &lbc {
 	#address-cells = <2>;
 	#size-cells = <1>;
-	compatible = "fsl,p1022-elbc", "fsl,elbc", "simple-bus";
+	/*
+	 * The localbus on the P1022 is not a simple-bus because of the eLBC
+	 * pin muxing when the DIU is enabled.
+	 */
+	compatible = "fsl,p1022-elbc", "fsl,elbc";
 	interrupts = <19 2 0 0>;
 };
 
@@ -199,7 +203,13 @@
 
 /include/ "pq3-dma-0.dtsi"
 /include/ "pq3-usb2-dr-0.dtsi"
+	usb@22000 {
+		compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+	};
 /include/ "pq3-usb2-dr-1.dtsi"
+	usb@23000 {
+		compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+	};
 
 /include/ "pq3-esdhc-0.dtsi"
 	sdhc@2e000 {
diff --git a/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi
index b06bb4c..941fa15 100644
--- a/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi
@@ -142,6 +142,9 @@
 
 /include/ "pq3-dma-0.dtsi"
 /include/ "pq3-usb2-dr-0.dtsi"
+	usb@22000 {
+		compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+	};
 
 	crypto: crypto@300000 {
 		compatible = "fsl,sec-v4.2", "fsl,sec-v4.0";
diff --git a/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi
index 332e9e7..884e01b 100644
--- a/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi
@@ -171,6 +171,9 @@
 
 /include/ "pq3-dma-0.dtsi"
 /include/ "pq3-usb2-dr-0.dtsi"
+	usb@22000 {
+		compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+	};
 /include/ "pq3-etsec1-0.dtsi"
 /include/ "pq3-etsec1-timer-0.dtsi"
 
diff --git a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
index 234a399..531eab8 100644
--- a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
@@ -309,12 +309,14 @@
 /include/ "qoriq-gpio-0.dtsi"
 /include/ "qoriq-usb2-mph-0.dtsi"
 		usb0: usb@210000 {
+			compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
 			phy_type = "utmi";
 			port0;
 		};
 
 /include/ "qoriq-usb2-dr-0.dtsi"
 		usb1: usb@211000 {
+			compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
 			dr_mode = "host";
 			phy_type = "utmi";
 		};
diff --git a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
index d41d08d..af4ebc8 100644
--- a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
@@ -336,12 +336,14 @@
 /include/ "qoriq-gpio-0.dtsi"
 /include/ "qoriq-usb2-mph-0.dtsi"
 		usb0: usb@210000 {
+			compatible = "fsl-usb2-mph-v1.6", "fsl-usb2-mph";
 			phy_type = "utmi";
 			port0;
 		};
 
 /include/ "qoriq-usb2-dr-0.dtsi"
 		usb1: usb@211000 {
+			compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
 			dr_mode = "host";
 			phy_type = "utmi";
 		};
diff --git a/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi b/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi
index a63edd1..b3e5692 100644
--- a/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi
@@ -291,6 +291,12 @@
 /include/ "qoriq-duart-1.dtsi"
 /include/ "qoriq-gpio-0.dtsi"
 /include/ "qoriq-usb2-mph-0.dtsi"
+	usb@210000 {
+		compatible = "fsl-usb2-mph-v2.2", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
+	};
 /include/ "qoriq-usb2-dr-0.dtsi"
+	usb@211000 {
+		compatible = "fsl-usb2-dr-v2.2", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
+	};
 /include/ "qoriq-sec4.1-0.dtsi"
 };
diff --git a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
index 914074b..64b6abe 100644
--- a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
@@ -339,12 +339,14 @@
 /include/ "qoriq-gpio-0.dtsi"
 /include/ "qoriq-usb2-mph-0.dtsi"
 		usb0: usb@210000 {
+			compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
 			phy_type = "utmi";
 			port0;
 		};
 
 /include/ "qoriq-usb2-dr-0.dtsi"
 		usb1: usb@211000 {
+			compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
 			dr_mode = "host";
 			phy_type = "utmi";
 		};
diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi
index a1979ae..3b0650a 100644
--- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi
+++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi
@@ -1,7 +1,7 @@
 /*
  * PQ3 eTSEC device tree stub [ @ offsets 0x24000 ]
  *
- * Copyright 2011 Freescale Semiconductor Inc.
+ * Copyright 2011-2012 Freescale Semiconductor Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -41,6 +41,7 @@
 	compatible = "gianfar";
 	reg = <0x24000 0x1000>;
 	ranges = <0x0 0x24000 0x1000>;
+	fsl,magic-packet;
 	local-mac-address = [ 00 00 00 00 00 00 ];
 	interrupts = <29 2 0 0 30 2 0 0 34 2 0 0>;
 };
diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi
index 4c4fdde..96693b4 100644
--- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi
+++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi
@@ -1,7 +1,7 @@
 /*
  * PQ3 eTSEC device tree stub [ @ offsets 0x25000 ]
  *
- * Copyright 2011 Freescale Semiconductor Inc.
+ * Copyright 2011-2012 Freescale Semiconductor Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -41,6 +41,7 @@
 	compatible = "gianfar";
 	reg = <0x25000 0x1000>;
 	ranges = <0x0 0x25000 0x1000>;
+	fsl,magic-packet;
 	local-mac-address = [ 00 00 00 00 00 00 ];
 	interrupts = <35 2 0 0 36 2 0 0 40 2 0 0>;
 };
diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi
index 4b8ab43..6b3fab1 100644
--- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi
+++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi
@@ -1,7 +1,7 @@
 /*
  * PQ3 eTSEC device tree stub [ @ offsets 0x26000 ]
  *
- * Copyright 2011 Freescale Semiconductor Inc.
+ * Copyright 2011-2012 Freescale Semiconductor Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -41,6 +41,7 @@
 	compatible = "gianfar";
 	reg = <0x26000 0x1000>;
 	ranges = <0x0 0x26000 0x1000>;
+	fsl,magic-packet;
 	local-mac-address = [ 00 00 00 00 00 00 ];
 	interrupts = <31 2 0 0 32 2 0 0 33 2 0 0>;
 };
diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi
index 40c9137..0da592d 100644
--- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi
+++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi
@@ -1,7 +1,7 @@
 /*
  * PQ3 eTSEC device tree stub [ @ offsets 0x27000 ]
  *
- * Copyright 2011 Freescale Semiconductor Inc.
+ * Copyright 2011-2012 Freescale Semiconductor Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -41,6 +41,7 @@
 	compatible = "gianfar";
 	reg = <0x27000 0x1000>;
 	ranges = <0x0 0x27000 0x1000>;
+	fsl,magic-packet;
 	local-mac-address = [ 00 00 00 00 00 00 ];
 	interrupts = <37 2 0 0 38 2 0 0 39 2 0 0>;
 };
diff --git a/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi b/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi
index 5c80460..fdedf7b 100644
--- a/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi
+++ b/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi
@@ -39,6 +39,9 @@
 	reg = <0x40000 0x40000>;
 	compatible = "fsl,mpic";
 	device_type = "open-pic";
+	big-endian;
+	single-cpu-affinity;
+	last-interrupt-source = <255>;
 };
 
 timer@41100 {
diff --git a/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi
index bf957a7..d4c9d5d 100644
--- a/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi
+++ b/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi
@@ -33,32 +33,32 @@
  */
 
 crypto@30000 {
-	compatible = "fsl,sec4.4", "fsl,sec4.0";
+	compatible = "fsl,sec-v4.4", "fsl,sec-v4.0";
 	#address-cells = <1>;
 	#size-cells = <1>;
 	reg		 = <0x30000 0x10000>;
 	interrupts	 = <58 2 0 0>;
 
 	sec_jr0: jr@1000 {
-		compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring";
+		compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring";
 		reg	   = <0x1000 0x1000>;
 		interrupts	 = <45 2 0 0>;
 	};
 
 	sec_jr1: jr@2000 {
-		compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring";
+		compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring";
 		reg	   = <0x2000 0x1000>;
 		interrupts	 = <45 2 0 0>;
 	};
 
 	sec_jr2: jr@3000 {
-		compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring";
+		compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring";
 		reg	   = <0x3000 0x1000>;
 		interrupts	 = <45 2 0 0>;
 	};
 
 	sec_jr3: jr@4000 {
-		compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring";
+		compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring";
 		reg	   = <0x4000 0x1000>;
 		interrupts	 = <45 2 0 0>;
 	};
diff --git a/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi
index b9bada6..08f4227 100644
--- a/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi
+++ b/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi
@@ -53,7 +53,7 @@
 
 msi0: msi@41600 {
 	compatible = "fsl,mpic-msi";
-	reg = <0x41600 0x200>;
+	reg = <0x41600 0x200 0x44140 4>;
 	msi-available-ranges = <0 0x100>;
 	interrupts = <
 		0xe0 0 0 0
@@ -68,7 +68,7 @@
 
 msi1: msi@41800 {
 	compatible = "fsl,mpic-msi";
-	reg = <0x41800 0x200>;
+	reg = <0x41800 0x200 0x45140 4>;
 	msi-available-ranges = <0 0x100>;
 	interrupts = <
 		0xe8 0 0 0
@@ -83,7 +83,7 @@
 
 msi2: msi@41a00 {
 	compatible = "fsl,mpic-msi";
-	reg = <0x41a00 0x200>;
+	reg = <0x41a00 0x200 0x46140 4>;
 	msi-available-ranges = <0 0x100>;
 	interrupts = <
 		0xf0 0 0 0
diff --git a/arch/powerpc/boot/dts/ge_imp3a.dts b/arch/powerpc/boot/dts/ge_imp3a.dts
new file mode 100644
index 0000000..fefae41
--- /dev/null
+++ b/arch/powerpc/boot/dts/ge_imp3a.dts
@@ -0,0 +1,255 @@
+/*
+ * GE IMP3A Device Tree Source
+ *
+ * Copyright 2010-2011 GE Intelligent Platforms Embedded Systems, Inc.
+ *
+ * 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.
+ *
+ * Based on: P2020 DS Device Tree Source
+ * Copyright 2009 Freescale Semiconductor Inc.
+ */
+
+/include/ "fsl/p2020si-pre.dtsi"
+
+/ {
+	model = "GE_IMP3A";
+	compatible = "ge,imp3a";
+
+	memory {
+		device_type = "memory";
+	};
+
+	lbc: localbus@fef05000 {
+		reg = <0 0xfef05000 0 0x1000>;
+
+		ranges = <0x0 0x0 0x0 0xff000000 0x01000000
+			  0x1 0x0 0x0 0xe0000000 0x08000000
+			  0x2 0x0 0x0 0xe8000000 0x08000000
+			  0x3 0x0 0x0 0xfc100000 0x00020000
+			  0x4 0x0 0x0 0xfc000000 0x00008000
+			  0x5 0x0 0x0 0xfc008000 0x00008000
+			  0x6 0x0 0x0 0xfee00000 0x00040000
+			  0x7 0x0 0x0 0xfee80000 0x00040000>;
+
+		/* nor@0,0 is a mirror of part of the memory in nor@1,0
+		nor@0,0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "ge,imp3a-firmware-mirror", "cfi-flash";
+			reg = <0x0 0x0 0x1000000>;
+			bank-width = <2>;
+			device-width = <1>;
+
+			partition@0 {
+				label = "firmware";
+				reg = <0x0 0x1000000>;
+				read-only;
+			};
+		};
+		*/
+
+		nor@1,0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "ge,imp3a-paged-flash", "cfi-flash";
+			reg = <0x1 0x0 0x8000000>;
+			bank-width = <2>;
+			device-width = <1>;
+
+			partition@0 {
+				label = "user";
+				reg = <0x0 0x7800000>;
+			};
+
+			partition@7800000 {
+				label = "firmware";
+				reg = <0x7800000 0x800000>;
+				read-only;
+			};
+		};
+
+		nvram@3,0 {
+			device_type = "nvram";
+			compatible = "simtek,stk14ca8";
+			reg = <0x3 0x0 0x20000>;
+		};
+
+		fpga@4,0 {
+			compatible = "ge,imp3a-fpga-regs";
+			reg = <0x4 0x0 0x20>;
+		};
+
+		gef_pic: pic@4,20 {
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			device_type = "interrupt-controller";
+			compatible = "ge,imp3a-fpga-pic", "gef,fpga-pic-1.00";
+			reg = <0x4 0x20 0x20>;
+			interrupts = <6 7 0 0>;
+		};
+
+		gef_gpio: gpio@4,400 {
+			#gpio-cells = <2>;
+			compatible = "ge,imp3a-gpio";
+			reg = <0x4 0x400 0x24>;
+			gpio-controller;
+		};
+
+		wdt@4,800 {
+			compatible = "ge,imp3a-fpga-wdt", "gef,fpga-wdt-1.00",
+				"gef,fpga-wdt";
+			reg = <0x4 0x800 0x8>;
+			interrupts = <10 4>;
+			interrupt-parent = <&gef_pic>;
+		};
+
+		/* Second watchdog available, driver currently supports one.
+		wdt@4,808 {
+			compatible = "gef,imp3a-fpga-wdt", "gef,fpga-wdt-1.00",
+				"gef,fpga-wdt";
+			reg = <0x4 0x808 0x8>;
+			interrupts = <9 4>;
+			interrupt-parent = <&gef_pic>;
+		};
+		*/
+
+		nand@6,0 {
+			compatible = "fsl,elbc-fcm-nand";
+			reg = <0x6 0x0 0x40000>;
+		};
+
+		nand@7,0 {
+			compatible = "fsl,elbc-fcm-nand";
+			reg = <0x7 0x0 0x40000>;
+		};
+	};
+
+	soc: soc@fef00000 {
+		ranges = <0x0 0 0xfef00000 0x100000>;
+
+		i2c@3000 {
+			hwmon@48 {
+				compatible = "national,lm92";
+				reg = <0x48>;
+			};
+
+			hwmon@4c {
+				compatible = "adi,adt7461";
+				reg = <0x4c>;
+			};
+
+			rtc@51 {
+				compatible = "epson,rx8581";
+				reg = <0x51>;
+			};
+
+			eti@6b {
+				compatible = "dallas,ds1682";
+				reg = <0x6b>;
+			};
+		};
+
+		usb@22000 {
+			phy_type = "ulpi";
+			dr_mode = "host";
+		};
+
+		mdio@24520 {
+			phy0: ethernet-phy@0 {
+				interrupt-parent = <&gef_pic>;
+				interrupts = <0xc 0x4>;
+				reg = <0x1>;
+			};
+			phy1: ethernet-phy@1 {
+				interrupt-parent = <&gef_pic>;
+				interrupts = <0xb 0x4>;
+				reg = <0x2>;
+			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@26520 {
+			status = "disabled";
+		};
+
+		enet0: ethernet@24000 {
+			tbi-handle = <&tbi0>;
+			phy-handle = <&phy0>;
+			phy-connection-type = "gmii";
+		};
+
+		enet1: ethernet@25000 {
+			tbi-handle = <&tbi1>;
+			phy-handle = <&phy1>;
+			phy-connection-type = "gmii";
+		};
+
+		enet2: ethernet@26000 {
+			status = "disabled";
+		};
+	};
+
+	pci0: pcie@fef08000 {
+		ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xfe020000 0x0 0x10000>;
+		reg = <0 0xfef08000 0 0x1000>;
+
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xc0000000
+				  0x2000000 0x0 0xc0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x10000>;
+		};
+	};
+
+	pci1: pcie@fef09000 {
+		reg = <0 0xfef09000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xfe010000 0x0 0x10000>;
+
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xa0000000
+				  0x2000000 0x0 0xa0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x10000>;
+		};
+
+	};
+
+	pci2: pcie@fef0a000 {
+		reg = <0 0xfef0a000 0 0x1000>;
+		ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xfe000000 0x0 0x10000>;
+
+		pcie@0 {
+			ranges = <0x2000000 0x0 0x80000000
+				  0x2000000 0x0 0x80000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x10000>;
+		};
+	};
+};
+
+/include/ "fsl/p2020si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts
index c0e450a..81dd513 100644
--- a/arch/powerpc/boot/dts/mpc836x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc836x_mds.dts
@@ -405,6 +405,10 @@
 				reg = <0x1>;
 				device_type = "ethernet-phy";
 			};
+			tbi-phy@2 {
+				device_type = "tbi-phy";
+				reg = <0x2>;
+			};
 		};
 
 		qeic: interrupt-controller@80 {
diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts
index c158815..1973622 100644
--- a/arch/powerpc/boot/dts/mpc8536ds.dts
+++ b/arch/powerpc/boot/dts/mpc8536ds.dts
@@ -1,7 +1,7 @@
 /*
  * MPC8536 DS Device Tree Source
  *
- * Copyright 2008 Freescale Semiconductor, Inc.
+ * Copyright 2008, 2011 Freescale Semiconductor, Inc.
  *
  * 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
@@ -34,6 +34,10 @@
 
 	lbc: localbus@ffe05000 {
 		reg = <0 0xffe05000 0 0x1000>;
+
+		ranges = <0x0 0x0 0x0 0xe8000000 0x08000000
+			  0x2 0x0 0x0 0xffa00000 0x00040000
+			  0x3 0x0 0x0 0xffdf0000 0x00008000>;
 	};
 
 	board_soc: soc: soc@ffe00000 {
diff --git a/arch/powerpc/boot/dts/mpc8536ds.dtsi b/arch/powerpc/boot/dts/mpc8536ds.dtsi
index 1462e4c..cc46dbd 100644
--- a/arch/powerpc/boot/dts/mpc8536ds.dtsi
+++ b/arch/powerpc/boot/dts/mpc8536ds.dtsi
@@ -32,6 +32,99 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+&lbc {
+	nor@0,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "cfi-flash";
+		reg = <0x0 0x0 0x8000000>;
+		bank-width = <2>;
+		device-width = <1>;
+
+		partition@0 {
+			reg = <0x0 0x03000000>;
+			label = "ramdisk-nor";
+		};
+
+		partition@3000000 {
+			reg = <0x03000000 0x00e00000>;
+			label = "diagnostic-nor";
+			read-only;
+		};
+
+		partition@3e00000 {
+			reg = <0x03e00000 0x00200000>;
+			label = "dink-nor";
+			read-only;
+		};
+
+		partition@4000000 {
+			reg = <0x04000000 0x00400000>;
+			label = "kernel-nor";
+		};
+
+		partition@4400000 {
+			reg = <0x04400000 0x03b00000>;
+			label = "fs-nor";
+		};
+
+		partition@7f00000 {
+			reg = <0x07f00000 0x00080000>;
+			label = "dtb-nor";
+		};
+
+		partition@7f80000 {
+			reg = <0x07f80000 0x00080000>;
+			label = "u-boot-nor";
+			read-only;
+		};
+	};
+
+	nand@2,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "fsl,mpc8536-fcm-nand",
+			     "fsl,elbc-fcm-nand";
+		reg = <0x2 0x0 0x40000>;
+
+		partition@0 {
+			reg = <0x0 0x02000000>;
+			label = "u-boot-nand";
+			read-only;
+		};
+
+		partition@2000000 {
+			reg = <0x02000000 0x10000000>;
+			label = "fs-nand";
+		};
+
+		partition@12000000 {
+			reg = <0x12000000 0x08000000>;
+			label = "ramdisk-nand";
+		};
+
+		partition@1a000000 {
+			reg = <0x1a000000 0x04000000>;
+			label = "kernel-nand";
+		};
+
+		partition@1e000000 {
+			reg = <0x1e000000 0x01000000>;
+			label = "dtb-nand";
+		};
+
+		partition@1f000000 {
+			reg = <0x1f000000 0x21000000>;
+			label = "empty-nand";
+		};
+	};
+
+	board-control@3,0 {
+		compatible = "fsl,mpc8536ds-fpga-pixis";
+		reg = <0x3 0x0 0x8000>;
+	};
+};
+
 &board_soc {
 	i2c@3100 {
 		rtc@68 {
diff --git a/arch/powerpc/boot/dts/mpc8536ds_36b.dts b/arch/powerpc/boot/dts/mpc8536ds_36b.dts
index 8f4b929..f8a3b34 100644
--- a/arch/powerpc/boot/dts/mpc8536ds_36b.dts
+++ b/arch/powerpc/boot/dts/mpc8536ds_36b.dts
@@ -1,7 +1,7 @@
 /*
  * MPC8536DS Device Tree Source (36-bit address map)
  *
- * Copyright 2008-2009 Freescale Semiconductor, Inc.
+ * Copyright 2008-2009, 2011 Freescale Semiconductor, Inc.
  *
  * 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
@@ -33,7 +33,11 @@
 	};
 
 	lbc: localbus@ffe05000 {
-		reg = <0 0xffe05000 0 0x1000>;
+		reg = <0xf 0xffe05000 0 0x1000>;
+
+		ranges = <0x0 0x0 0xf 0xe8000000 0x08000000
+			  0x2 0x0 0xf 0xffa00000 0x00040000
+			  0x3 0x0 0xf 0xffdf0000 0x00008000>;
 	};
 
 	board_soc: soc: soc@fffe00000 {
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts
deleted file mode 100644
index 07b8dae0..0000000
--- a/arch/powerpc/boot/dts/mpc8548cds.dts
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * MPC8548 CDS Device Tree Source
- *
- * Copyright 2006, 2008 Freescale Semiconductor Inc.
- *
- * 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/ "fsl/mpc8548si-pre.dtsi"
-
-/ {
-	model = "MPC8548CDS";
-	compatible = "MPC8548CDS", "MPC85xxCDS";
-
-	aliases {
-		ethernet0 = &enet0;
-		ethernet1 = &enet1;
-		ethernet2 = &enet2;
-		ethernet3 = &enet3;
-		serial0 = &serial0;
-		serial1 = &serial1;
-		pci0 = &pci0;
-		pci1 = &pci1;
-		pci2 = &pci2;
-	};
-
-	memory {
-		device_type = "memory";
-		reg = <0 0 0x0 0x8000000>;	// 128M at 0x0
-	};
-
-	lbc: localbus@e0005000 {
-		reg = <0 0xe0005000 0 0x1000>;
-	};
-
-	soc: soc8548@e0000000 {
-		ranges = <0 0x0 0xe0000000 0x100000>;
-
-		i2c@3000 {
-			eeprom@50 {
-				compatible = "atmel,24c64";
-				reg = <0x50>;
-			};
-
-			eeprom@56 {
-				compatible = "atmel,24c64";
-				reg = <0x56>;
-			};
-
-			eeprom@57 {
-				compatible = "atmel,24c64";
-				reg = <0x57>;
-			};
-		};
-
-		i2c@3100 {
-			eeprom@50 {
-				compatible = "atmel,24c64";
-				reg = <0x50>;
-			};
-		};
-
-		enet0: ethernet@24000 {
-			tbi-handle = <&tbi0>;
-			phy-handle = <&phy0>;
-		};
-
-		mdio@24520 {
-			phy0: ethernet-phy@0 {
-				interrupts = <5 1 0 0>;
-				reg = <0x0>;
-				device_type = "ethernet-phy";
-			};
-			phy1: ethernet-phy@1 {
-				interrupts = <5 1 0 0>;
-				reg = <0x1>;
-				device_type = "ethernet-phy";
-			};
-			phy2: ethernet-phy@2 {
-				interrupts = <5 1 0 0>;
-				reg = <0x2>;
-				device_type = "ethernet-phy";
-			};
-			phy3: ethernet-phy@3 {
-				interrupts = <5 1 0 0>;
-				reg = <0x3>;
-				device_type = "ethernet-phy";
-			};
-			tbi0: tbi-phy@11 {
-				reg = <0x11>;
-				device_type = "tbi-phy";
-			};
-		};
-
-		enet1: ethernet@25000 {
-			tbi-handle = <&tbi1>;
-			phy-handle = <&phy1>;
-		};
-
-		mdio@25520 {
-			tbi1: tbi-phy@11 {
-				reg = <0x11>;
-				device_type = "tbi-phy";
-			};
-		};
-
-		enet2: ethernet@26000 {
-			tbi-handle = <&tbi2>;
-			phy-handle = <&phy2>;
-		};
-
-		mdio@26520 {
-			tbi2: tbi-phy@11 {
-				reg = <0x11>;
-				device_type = "tbi-phy";
-			};
-		};
-
-		enet3: ethernet@27000 {
-			tbi-handle = <&tbi3>;
-			phy-handle = <&phy3>;
-		};
-
-		mdio@27520 {
-			tbi3: tbi-phy@11 {
-				reg = <0x11>;
-				device_type = "tbi-phy";
-			};
-		};
-	};
-
-	pci0: pci@e0008000 {
-		reg = <0 0xe0008000 0 0x1000>;
-		ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x10000000
-			  0x1000000 0x0 0x00000000 0 0xe2000000 0x0 0x800000>;
-		clock-frequency = <66666666>;
-		interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
-		interrupt-map = <
-			/* IDSEL 0x4 (PCIX Slot 2) */
-			0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-			0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-			0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-			0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
-
-			/* IDSEL 0x5 (PCIX Slot 3) */
-			0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0
-			0x2800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0
-			0x2800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0
-			0x2800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0
-
-			/* IDSEL 0x6 (PCIX Slot 4) */
-			0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0
-			0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0
-			0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0
-			0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0
-
-			/* IDSEL 0x8 (PCIX Slot 5) */
-			0x4000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-			0x4000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-			0x4000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-			0x4000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
-
-			/* IDSEL 0xC (Tsi310 bridge) */
-			0x6000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-			0x6000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-			0x6000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-			0x6000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
-
-			/* IDSEL 0x14 (Slot 2) */
-			0xa000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-			0xa000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-			0xa000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-			0xa000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
-
-			/* IDSEL 0x15 (Slot 3) */
-			0xa800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0
-			0xa800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0
-			0xa800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0
-			0xa800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0
-
-			/* IDSEL 0x16 (Slot 4) */
-			0xb000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0
-			0xb000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0
-			0xb000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0
-			0xb000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0
-
-			/* IDSEL 0x18 (Slot 5) */
-			0xc000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-			0xc000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-			0xc000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-			0xc000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
-
-			/* IDSEL 0x1C (Tsi310 bridge PCI primary) */
-			0xe000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-			0xe000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-			0xe000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-			0xe000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>;
-
-		pci_bridge@1c {
-			interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
-			interrupt-map = <
-
-				/* IDSEL 0x00 (PrPMC Site) */
-				0000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-				0000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-				0000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-				0000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
-
-				/* IDSEL 0x04 (VIA chip) */
-				0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-				0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-				0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-				0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
-
-				/* IDSEL 0x05 (8139) */
-				0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0
-
-				/* IDSEL 0x06 (Slot 6) */
-				0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0
-				0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0
-				0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0
-				0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0
-
-				/* IDESL 0x07 (Slot 7) */
-				0x3800 0x0 0x0 0x1 &mpic 0x3 0x1 0 0
-				0x3800 0x0 0x0 0x2 &mpic 0x0 0x1 0 0
-				0x3800 0x0 0x0 0x3 &mpic 0x1 0x1 0 0
-				0x3800 0x0 0x0 0x4 &mpic 0x2 0x1 0 0>;
-
-			reg = <0xe000 0x0 0x0 0x0 0x0>;
-			#interrupt-cells = <1>;
-			#size-cells = <2>;
-			#address-cells = <3>;
-			ranges = <0x2000000 0x0 0x80000000
-				  0x2000000 0x0 0x80000000
-				  0x0 0x20000000
-				  0x1000000 0x0 0x0
-				  0x1000000 0x0 0x0
-				  0x0 0x80000>;
-			clock-frequency = <33333333>;
-
-			isa@4 {
-				device_type = "isa";
-				#interrupt-cells = <2>;
-				#size-cells = <1>;
-				#address-cells = <2>;
-				reg = <0x2000 0x0 0x0 0x0 0x0>;
-				ranges = <0x1 0x0 0x1000000 0x0 0x0 0x1000>;
-				interrupt-parent = <&i8259>;
-
-				i8259: interrupt-controller@20 {
-					interrupt-controller;
-					device_type = "interrupt-controller";
-					reg = <0x1 0x20 0x2
-					       0x1 0xa0 0x2
-					       0x1 0x4d0 0x2>;
-					#address-cells = <0>;
-					#interrupt-cells = <2>;
-					compatible = "chrp,iic";
-					interrupts = <0 1 0 0>;
-					interrupt-parent = <&mpic>;
-				};
-
-				rtc@70 {
-					compatible = "pnpPNP,b00";
-					reg = <0x1 0x70 0x2>;
-				};
-			};
-		};
-	};
-
-	pci1: pci@e0009000 {
-		reg = <0 0xe0009000 0 0x1000>;
-		ranges = <0x2000000 0x0 0x90000000 0 0x90000000 0x0 0x10000000
-			  0x1000000 0x0 0x00000000 0 0xe2800000 0x0 0x800000>;
-		clock-frequency = <66666666>;
-		interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
-		interrupt-map = <
-
-			/* IDSEL 0x15 */
-			0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 0 0
-			0xa800 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-			0xa800 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-			0xa800 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>;
-	};
-
-	pci2: pcie@e000a000 {
-		reg = <0 0xe000a000 0 0x1000>;
-		ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
-			  0x1000000 0x0 0x00000000 0 0xe3000000 0x0 0x100000>;
-		pcie@0 {
-			ranges = <0x2000000 0x0 0xa0000000
-				  0x2000000 0x0 0xa0000000
-				  0x0 0x20000000
-
-				  0x1000000 0x0 0x0
-				  0x1000000 0x0 0x0
-				  0x0 0x100000>;
-		};
-	};
-};
-
-/include/ "fsl/mpc8548si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dtsi b/arch/powerpc/boot/dts/mpc8548cds.dtsi
new file mode 100644
index 0000000..c61f525
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8548cds.dtsi
@@ -0,0 +1,306 @@
+/*
+ * MPC8548CDS Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+&board_lbc {
+	nor@0,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "cfi-flash";
+		reg = <0x0 0x0 0x01000000>;
+		bank-width = <2>;
+		device-width = <2>;
+
+		partition@0 {
+			reg = <0x0 0x0b00000>;
+			label = "ramdisk-nor";
+		};
+
+		partition@300000 {
+			reg = <0x0b00000 0x0400000>;
+			label = "kernel-nor";
+		};
+
+		partition@700000 {
+			reg = <0x0f00000 0x060000>;
+			label = "dtb-nor";
+		};
+
+		partition@760000 {
+			reg = <0x0f60000 0x020000>;
+			label = "env-nor";
+			read-only;
+		};
+
+		partition@780000 {
+			reg = <0x0f80000 0x080000>;
+			label = "u-boot-nor";
+			read-only;
+		};
+	};
+
+	board-control@1,0 {
+		compatible = "fsl,mpc8548cds-fpga";
+		reg = <0x1 0x0 0x1000>;
+	};
+};
+
+&board_soc {
+	i2c@3000 {
+		eeprom@50 {
+			compatible = "atmel,24c64";
+			reg = <0x50>;
+		};
+
+		eeprom@56 {
+			compatible = "atmel,24c64";
+			reg = <0x56>;
+		};
+
+		eeprom@57 {
+			compatible = "atmel,24c64";
+			reg = <0x57>;
+		};
+	};
+
+	i2c@3100 {
+		eeprom@50 {
+			compatible = "atmel,24c64";
+			reg = <0x50>;
+		};
+	};
+
+	enet0: ethernet@24000 {
+		tbi-handle = <&tbi0>;
+		phy-handle = <&phy0>;
+	};
+
+	mdio@24520 {
+		phy0: ethernet-phy@0 {
+			interrupts = <5 1 0 0>;
+			reg = <0x0>;
+			device_type = "ethernet-phy";
+		};
+		phy1: ethernet-phy@1 {
+			interrupts = <5 1 0 0>;
+			reg = <0x1>;
+			device_type = "ethernet-phy";
+		};
+		phy2: ethernet-phy@2 {
+			interrupts = <5 1 0 0>;
+			reg = <0x2>;
+			device_type = "ethernet-phy";
+		};
+		phy3: ethernet-phy@3 {
+			interrupts = <5 1 0 0>;
+			reg = <0x3>;
+			device_type = "ethernet-phy";
+		};
+		tbi0: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+
+	enet1: ethernet@25000 {
+		tbi-handle = <&tbi1>;
+		phy-handle = <&phy1>;
+	};
+
+	mdio@25520 {
+		tbi1: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+
+	enet2: ethernet@26000 {
+		tbi-handle = <&tbi2>;
+		phy-handle = <&phy2>;
+	};
+
+	mdio@26520 {
+		tbi2: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+
+	enet3: ethernet@27000 {
+		tbi-handle = <&tbi3>;
+		phy-handle = <&phy3>;
+	};
+
+	mdio@27520 {
+		tbi3: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+};
+
+&board_pci0 {
+	interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+	interrupt-map = <
+		/* IDSEL 0x4 (PCIX Slot 2) */
+		0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+		0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+		0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+		0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
+
+		/* IDSEL 0x5 (PCIX Slot 3) */
+		0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0
+		0x2800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0
+		0x2800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0
+		0x2800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0
+
+		/* IDSEL 0x6 (PCIX Slot 4) */
+		0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0
+		0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0
+		0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0
+		0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0
+
+		/* IDSEL 0x8 (PCIX Slot 5) */
+		0x4000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+		0x4000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+		0x4000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+		0x4000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
+
+		/* IDSEL 0xC (Tsi310 bridge) */
+		0x6000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+		0x6000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+		0x6000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+		0x6000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
+
+		/* IDSEL 0x14 (Slot 2) */
+		0xa000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+		0xa000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+		0xa000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+		0xa000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
+
+		/* IDSEL 0x15 (Slot 3) */
+		0xa800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0
+		0xa800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0
+		0xa800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0
+		0xa800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0
+
+		/* IDSEL 0x16 (Slot 4) */
+		0xb000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0
+		0xb000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0
+		0xb000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0
+		0xb000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0
+
+		/* IDSEL 0x18 (Slot 5) */
+		0xc000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+		0xc000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+		0xc000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+		0xc000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
+
+		/* IDSEL 0x1C (Tsi310 bridge PCI primary) */
+		0xe000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+		0xe000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+		0xe000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+		0xe000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>;
+
+	pci_bridge@1c {
+		interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+		interrupt-map = <
+
+			/* IDSEL 0x00 (PrPMC Site) */
+			0000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+			0000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+			0000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+			0000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
+
+			/* IDSEL 0x04 (VIA chip) */
+			0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+			0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+			0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+			0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
+
+			/* IDSEL 0x05 (8139) */
+			0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0
+
+			/* IDSEL 0x06 (Slot 6) */
+			0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0
+			0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0
+			0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0
+			0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0
+
+			/* IDESL 0x07 (Slot 7) */
+			0x3800 0x0 0x0 0x1 &mpic 0x3 0x1 0 0
+			0x3800 0x0 0x0 0x2 &mpic 0x0 0x1 0 0
+			0x3800 0x0 0x0 0x3 &mpic 0x1 0x1 0 0
+			0x3800 0x0 0x0 0x4 &mpic 0x2 0x1 0 0>;
+
+		reg = <0xe000 0x0 0x0 0x0 0x0>;
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		ranges = <0x2000000 0x0 0x80000000
+			  0x2000000 0x0 0x80000000
+			  0x0 0x20000000
+			  0x1000000 0x0 0x0
+			  0x1000000 0x0 0x0
+			  0x0 0x80000>;
+		clock-frequency = <33333333>;
+
+		isa@4 {
+			device_type = "isa";
+			#interrupt-cells = <2>;
+			#size-cells = <1>;
+			#address-cells = <2>;
+			reg = <0x2000 0x0 0x0 0x0 0x0>;
+			ranges = <0x1 0x0 0x1000000 0x0 0x0 0x1000>;
+			interrupt-parent = <&i8259>;
+
+			i8259: interrupt-controller@20 {
+				interrupt-controller;
+				device_type = "interrupt-controller";
+				reg = <0x1 0x20 0x2
+				       0x1 0xa0 0x2
+				       0x1 0x4d0 0x2>;
+				#address-cells = <0>;
+				#interrupt-cells = <2>;
+				compatible = "chrp,iic";
+				interrupts = <0 1 0 0>;
+				interrupt-parent = <&mpic>;
+			};
+
+			rtc@70 {
+				compatible = "pnpPNP,b00";
+				reg = <0x1 0x70 0x2>;
+			};
+		};
+	};
+};
diff --git a/arch/powerpc/boot/dts/mpc8548cds_32b.dts b/arch/powerpc/boot/dts/mpc8548cds_32b.dts
new file mode 100644
index 0000000..6fd6316
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8548cds_32b.dts
@@ -0,0 +1,86 @@
+/*
+ * MPC8548 CDS Device Tree Source (32-bit address map)
+ *
+ * Copyright 2006, 2008, 2011-2012 Freescale Semiconductor Inc.
+ *
+ * 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/ "fsl/mpc8548si-pre.dtsi"
+
+/ {
+	model = "MPC8548CDS";
+	compatible = "MPC8548CDS", "MPC85xxCDS";
+
+	memory {
+		device_type = "memory";
+		reg = <0 0 0x0 0x8000000>;	// 128M at 0x0
+	};
+
+	board_lbc: lbc: localbus@e0005000 {
+		reg = <0 0xe0005000 0 0x1000>;
+
+		ranges = <0x0 0x0 0x0 0xff000000 0x01000000
+			  0x1 0x0 0x0 0xf8004000 0x00001000>;
+
+	};
+
+	board_soc: soc: soc8548@e0000000 {
+		ranges = <0 0x0 0xe0000000 0x100000>;
+	};
+
+	board_pci0: pci0: pci@e0008000 {
+		reg = <0 0xe0008000 0 0x1000>;
+		ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x10000000
+			  0x1000000 0x0 0x00000000 0 0xe2000000 0x0 0x800000>;
+		clock-frequency = <66666666>;
+	};
+
+	pci1: pci@e0009000 {
+		reg = <0 0xe0009000 0 0x1000>;
+		ranges = <0x2000000 0x0 0x90000000 0 0x90000000 0x0 0x10000000
+			  0x1000000 0x0 0x00000000 0 0xe2800000 0x0 0x800000>;
+		clock-frequency = <66666666>;
+		interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+		interrupt-map = <
+
+			/* IDSEL 0x15 */
+			0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 0 0
+			0xa800 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+			0xa800 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+			0xa800 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>;
+	};
+
+	pci2: pcie@e000a000 {
+		reg = <0 0xe000a000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xe3000000 0x0 0x100000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xa0000000
+				  0x2000000 0x0 0xa0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	rio: rapidio@e00c0000 {
+		reg = <0x0 0xe00c0000 0x0 0x20000>;
+		port1 {
+			ranges = <0x0 0x0 0x0 0xc0000000 0x0 0x20000000>;
+		};
+	};
+};
+
+/*
+ * mpc8548cds.dtsi must be last to ensure board_pci0 overrides pci0 settings
+ * for interrupt-map & interrupt-map-mask.
+ */
+
+/include/ "fsl/mpc8548si-post.dtsi"
+/include/ "mpc8548cds.dtsi"
diff --git a/arch/powerpc/boot/dts/mpc8548cds_36b.dts b/arch/powerpc/boot/dts/mpc8548cds_36b.dts
new file mode 100644
index 0000000..10e551b
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8548cds_36b.dts
@@ -0,0 +1,86 @@
+/*
+ * MPC8548 CDS Device Tree Source (36-bit address map)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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/ "fsl/mpc8548si-pre.dtsi"
+
+/ {
+	model = "MPC8548CDS";
+	compatible = "MPC8548CDS", "MPC85xxCDS";
+
+	memory {
+		device_type = "memory";
+		reg = <0 0 0x0 0x8000000>;	// 128M at 0x0
+	};
+
+	board_lbc: lbc: localbus@fe0005000 {
+		reg = <0xf 0xe0005000 0 0x1000>;
+
+		ranges = <0x0 0x0 0xf 0xff000000 0x01000000
+			  0x1 0x0 0xf 0xf8004000 0x00001000>;
+
+	};
+
+	board_soc: soc: soc8548@fe0000000 {
+		ranges = <0 0xf 0xe0000000 0x100000>;
+	};
+
+	board_pci0: pci0: pci@fe0008000 {
+		reg = <0xf 0xe0008000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x10000000
+			  0x1000000 0x0 0x00000000 0xf 0xe2000000 0x0 0x800000>;
+		clock-frequency = <66666666>;
+	};
+
+	pci1: pci@fe0009000 {
+		reg = <0xf 0xe0009000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0xc 0x10000000 0x0 0x10000000
+			  0x1000000 0x0 0x00000000 0xf 0xe2800000 0x0 0x800000>;
+		clock-frequency = <66666666>;
+		interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+		interrupt-map = <
+
+			/* IDSEL 0x15 */
+			0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 0 0
+			0xa800 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+			0xa800 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+			0xa800 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>;
+	};
+
+	pci2: pcie@fe000a000 {
+		reg = <0xf 0xe000a000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xe3000000 0x0 0x100000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xa0000000
+				  0x2000000 0x0 0xa0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	rio: rapidio@fe00c0000 {
+		reg = <0xf 0xe00c0000 0x0 0x20000>;
+		port1 {
+			ranges = <0x0 0x0 0xc 0x40000000 0x0 0x20000000>;
+		};
+	};
+};
+
+/*
+ * mpc8548cds.dtsi must be last to ensure board_pci0 overrides pci0 settings
+ * for interrupt-map & interrupt-map-mask.
+ */
+
+/include/ "fsl/mpc8548si-post.dtsi"
+/include/ "mpc8548cds.dtsi"
diff --git a/arch/powerpc/boot/dts/mpc8572ds.dtsi b/arch/powerpc/boot/dts/mpc8572ds.dtsi
index c3d4fac..1417894 100644
--- a/arch/powerpc/boot/dts/mpc8572ds.dtsi
+++ b/arch/powerpc/boot/dts/mpc8572ds.dtsi
@@ -41,37 +41,47 @@
 		bank-width = <2>;
 		device-width = <1>;
 
-		ramdisk@0 {
+		partition@0 {
 			reg = <0x0 0x03000000>;
-			read-only;
+			label = "ramdisk-nor";
 		};
 
-		diagnostic@3000000 {
+		partition@3000000 {
 			reg = <0x03000000 0x00e00000>;
+			label = "diagnostic-nor";
 			read-only;
 		};
 
-		dink@3e00000 {
+		partition@3e00000 {
 			reg = <0x03e00000 0x00200000>;
+			label = "dink-nor";
 			read-only;
 		};
 
-		kernel@4000000 {
+		partition@4000000 {
 			reg = <0x04000000 0x00400000>;
-			read-only;
+			label = "kernel-nor";
 		};
 
-		jffs2@4400000 {
+		partition@4400000 {
 			reg = <0x04400000 0x03b00000>;
+			label = "fs-nor";
 		};
 
-		dtb@7f00000 {
-			reg = <0x07f00000 0x00080000>;
+		partition@7f00000 {
+			reg = <0x07f00000 0x00060000>;
+			label = "dtb-nor";
+		};
+
+		partition@7f60000 {
+			reg = <0x07f60000 0x00020000>;
+			label = "env-nor";
 			read-only;
 		};
 
-		u-boot@7f80000 {
+		partition@7f80000 {
 			reg = <0x07f80000 0x00080000>;
+			label = "u-boot-nor";
 			read-only;
 		};
 	};
@@ -83,31 +93,35 @@
 			     "fsl,elbc-fcm-nand";
 		reg = <0x2 0x0 0x40000>;
 
-		u-boot@0 {
+		partition@0 {
 			reg = <0x0 0x02000000>;
+			label = "u-boot-nand";
 			read-only;
 		};
 
-		jffs2@2000000 {
+		partition@2000000 {
 			reg = <0x02000000 0x10000000>;
+			label = "fs-nand";
 		};
 
-		ramdisk@12000000 {
+		partition@12000000 {
 			reg = <0x12000000 0x08000000>;
-			read-only;
+			label = "ramdisk-nand";
 		};
 
-		kernel@1a000000 {
+		partition@1a000000 {
 			reg = <0x1a000000 0x04000000>;
+			label = "kernel-nand";
 		};
 
-		dtb@1e000000 {
+		partition@1e000000 {
 			reg = <0x1e000000 0x01000000>;
-			read-only;
+			label = "dtb-nand";
 		};
 
-		empty@1f000000 {
+		partition@1f000000 {
 			reg = <0x1f000000 0x21000000>;
+			label = "empty-nand";
 		};
 	};
 
diff --git a/arch/powerpc/boot/dts/p1010rdb.dtsi b/arch/powerpc/boot/dts/p1010rdb.dtsi
index d4c4a77..4977614 100644
--- a/arch/powerpc/boot/dts/p1010rdb.dtsi
+++ b/arch/powerpc/boot/dts/p1010rdb.dtsi
@@ -138,7 +138,7 @@
 			#size-cells = <1>;
 			compatible = "spansion,s25sl12801";
 			reg = <0>;
-			spi-max-frequency = <50000000>;
+			spi-max-frequency = <40000000>;
 
 			partition@0 {
 				/* 1MB for u-boot Bootloader Image */
@@ -196,7 +196,7 @@
 		};
 
 		tbi-phy@3 {
-			device-type = "tbi-phy";
+			device_type = "tbi-phy";
 			reg = <0x3>;
 		};
 	};
diff --git a/arch/powerpc/boot/dts/p1020mbg-pc.dtsi b/arch/powerpc/boot/dts/p1020mbg-pc.dtsi
new file mode 100644
index 0000000..a24699c
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020mbg-pc.dtsi
@@ -0,0 +1,151 @@
+/*
+ * P1020 MBG-PC Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+&lbc {
+	nor@0,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "cfi-flash";
+		reg = <0x0 0x0 0x4000000>;
+		bank-width = <2>;
+		device-width = <1>;
+
+		partition@0 {
+			/* 128KB for DTB Image */
+			reg = <0x0 0x00020000>;
+			label = "NOR DTB Image";
+		};
+
+		partition@20000 {
+			/* 3.875 MB for Linux Kernel Image */
+			reg = <0x00020000 0x003e0000>;
+			label = "NOR Linux Kernel Image";
+		};
+
+		partition@400000 {
+			/* 58MB for Root file System */
+			reg = <0x00400000 0x03a00000>;
+			label = "NOR Root File System";
+		};
+
+		partition@3e00000 {
+			/* This location must not be altered  */
+			/* 1M for Vitesse 7385 Switch firmware */
+			reg = <0x3e00000 0x00100000>;
+			label = "NOR Vitesse-7385 Firmware";
+			read-only;
+		};
+
+		partition@3f00000 {
+			/* This location must not be altered  */
+			/* 512KB for u-boot Bootloader Image */
+			/* 512KB for u-boot Environment Variables */
+			reg = <0x03f00000 0x00100000>;
+			label = "NOR U-Boot Image";
+			read-only;
+		};
+	};
+
+	L2switch@2,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "vitesse-7385";
+		reg = <0x2 0x0 0x20000>;
+	};
+};
+
+&soc {
+	i2c@3000 {
+		rtc@68 {
+			compatible = "dallas,ds1339";
+			reg = <0x68>;
+		};
+	};
+
+	mdio@24000 {
+		phy0: ethernet-phy@0 {
+			interrupts = <3 1 0 0>;
+			reg = <0x0>;
+		};
+		phy1: ethernet-phy@1 {
+			interrupts = <2 1 0 0>;
+			reg = <0x1>;
+		};
+	};
+
+	mdio@25000 {
+		tbi1: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+
+	mdio@26000 {
+		tbi2: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+
+	enet0: ethernet@b0000 {
+		fixed-link = <1 1 1000 0 0>;
+		phy-connection-type = "rgmii-id";
+	};
+
+	enet1: ethernet@b1000 {
+		phy-handle = <&phy0>;
+		tbi-handle = <&tbi1>;
+		phy-connection-type = "sgmii";
+	};
+
+	enet2: ethernet@b2000 {
+		phy-handle = <&phy1>;
+		phy-connection-type = "rgmii-id";
+	};
+
+	usb@22000 {
+		phy_type = "ulpi";
+	};
+
+	/* USB2 is shared with localbus, so it must be disabled
+	   by default. We can't put 'status = "disabled";' here
+	   since U-Boot doesn't clear the status property when
+	   it enables USB2. OTOH, U-Boot does create a new node
+	   when there isn't any. So, just comment it out.
+	*/
+	usb@23000 {
+		status = "disabled";
+		phy_type = "ulpi";
+	};
+};
diff --git a/arch/powerpc/boot/dts/p1020mbg-pc_32b.dts b/arch/powerpc/boot/dts/p1020mbg-pc_32b.dts
new file mode 100644
index 0000000..ab8f076
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020mbg-pc_32b.dts
@@ -0,0 +1,89 @@
+/*
+ * P1020 MBG-PC Device Tree Source (32-bit address map)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1020si-pre.dtsi"
+/ {
+	model = "fsl,P1020MBG-PC";
+	compatible = "fsl,P1020MBG-PC";
+
+	memory {
+		device_type = "memory";
+	};
+
+	lbc: localbus@ffe05000 {
+		reg = <0x0 0xffe05000 0x0 0x1000>;
+
+		/* NOR and L2 switch */
+		ranges = <0x0 0x0 0x0 0xec000000 0x04000000
+			  0x1 0x0 0x0 0xffa00000 0x00040000
+			  0x2 0x0 0x0 0xffb00000 0x00020000>;
+	};
+
+	soc: soc@ffe00000 {
+		ranges = <0x0 0x0 0xffe00000 0x100000>;
+	};
+
+	pci0: pcie@ffe09000 {
+		reg = <0x0 0xffe09000 0x0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0x0 0xa0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0x0 0xffc10000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci1: pcie@ffe0a000 {
+		reg = <0x0 0xffe0a000 0x0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0x0 0x80000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0x0 0xffc00000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+};
+
+/include/ "p1020mbg-pc.dtsi"
+/include/ "fsl/p1020si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1020mbg-pc_36b.dts b/arch/powerpc/boot/dts/p1020mbg-pc_36b.dts
new file mode 100644
index 0000000..9e9f401
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020mbg-pc_36b.dts
@@ -0,0 +1,89 @@
+/*
+ * P1020 MBG-PC Device Tree Source (36-bit address map)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1020si-pre.dtsi"
+/ {
+	model = "fsl,P1020MBG-PC";
+	compatible = "fsl,P1020MBG-PC";
+
+	memory {
+		device_type = "memory";
+	};
+
+	lbc: localbus@fffe05000 {
+		reg = <0xf 0xffe05000 0x0 0x1000>;
+
+		/* NOR and L2 switch */
+		ranges = <0x0 0x0 0xf 0xec000000 0x04000000
+			  0x1 0x0 0xf 0xffa00000 0x00040000
+			  0x2 0x0 0xf 0xffb00000 0x00020000>;
+	};
+
+	soc: soc@fffe00000 {
+		ranges = <0x0 0xf 0xffe00000 0x100000>;
+	};
+
+	pci0: pcie@fffe09000 {
+		reg = <0xf 0xffe09000 0x0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci1: pcie@fffe0a000 {
+		reg = <0xf 0xffe0a000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+};
+
+/include/ "p1020mbg-pc.dtsi"
+/include/ "fsl/p1020si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1020rdb-pc.dtsi b/arch/powerpc/boot/dts/p1020rdb-pc.dtsi
new file mode 100644
index 0000000..c952cd3
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020rdb-pc.dtsi
@@ -0,0 +1,247 @@
+/*
+ * P1020 RDB-PC Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+&lbc {
+	nor@0,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "cfi-flash";
+		reg = <0x0 0x0 0x1000000>;
+		bank-width = <2>;
+		device-width = <1>;
+
+		partition@0 {
+			/* This location must not be altered  */
+			/* 256KB for Vitesse 7385 Switch firmware */
+			reg = <0x0 0x00040000>;
+			label = "NOR Vitesse-7385 Firmware";
+			read-only;
+		};
+
+		partition@40000 {
+			/* 256KB for DTB Image */
+			reg = <0x00040000 0x00040000>;
+			label = "NOR DTB Image";
+		};
+
+		partition@80000 {
+			/* 3.5 MB for Linux Kernel Image */
+			reg = <0x00080000 0x00380000>;
+			label = "NOR Linux Kernel Image";
+		};
+
+		partition@400000 {
+			/* 11MB for JFFS2 based Root file System */
+			reg = <0x00400000 0x00b00000>;
+			label = "NOR JFFS2 Root File System";
+		};
+
+		partition@f00000 {
+			/* This location must not be altered  */
+			/* 512KB for u-boot Bootloader Image */
+			/* 512KB for u-boot Environment Variables */
+			reg = <0x00f00000 0x00100000>;
+			label = "NOR U-Boot Image";
+			read-only;
+		};
+	};
+
+	nand@1,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "fsl,p1020-fcm-nand",
+			     "fsl,elbc-fcm-nand";
+		reg = <0x1 0x0 0x40000>;
+
+		partition@0 {
+			/* This location must not be altered  */
+			/* 1MB for u-boot Bootloader Image */
+			reg = <0x0 0x00100000>;
+			label = "NAND U-Boot Image";
+			read-only;
+		};
+
+		partition@100000 {
+			/* 1MB for DTB Image */
+			reg = <0x00100000 0x00100000>;
+			label = "NAND DTB Image";
+		};
+
+		partition@200000 {
+			/* 4MB for Linux Kernel Image */
+			reg = <0x00200000 0x00400000>;
+			label = "NAND Linux Kernel Image";
+		};
+
+		partition@600000 {
+			/* 4MB for Compressed Root file System Image */
+			reg = <0x00600000 0x00400000>;
+			label = "NAND Compressed RFS Image";
+		};
+
+		partition@a00000 {
+			/* 7MB for JFFS2 based Root file System */
+			reg = <0x00a00000 0x00700000>;
+			label = "NAND JFFS2 Root File System";
+		};
+
+		partition@1100000 {
+			/* 15MB for JFFS2 based Root file System */
+			reg = <0x01100000 0x00f00000>;
+			label = "NAND Writable User area";
+		};
+	};
+
+	L2switch@2,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "vitesse-7385";
+		reg = <0x2 0x0 0x20000>;
+	};
+
+	cpld@3,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "cpld";
+		reg = <0x3 0x0 0x20000>;
+		read-only;
+	};
+};
+
+&soc {
+	i2c@3000 {
+		rtc@68 {
+			compatible = "pericom,pt7c4338";
+			reg = <0x68>;
+		};
+	};
+
+	spi@7000 {
+		flash@0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "spansion,s25sl12801";
+			reg = <0>;
+			spi-max-frequency = <40000000>; /* input clock */
+
+			partition@u-boot {
+				/* 512KB for u-boot Bootloader Image */
+				reg = <0x0 0x00080000>;
+				label = "u-boot";
+				read-only;
+			};
+
+			partition@dtb {
+				/* 512KB for DTB Image*/
+				reg = <0x00080000 0x00080000>;
+				label = "dtb";
+			};
+
+			partition@kernel {
+				/* 4MB for Linux Kernel Image */
+				reg = <0x00100000 0x00400000>;
+				label = "kernel";
+			};
+
+			partition@fs {
+				/* 4MB for Compressed RFS Image */
+				reg = <0x00500000 0x00400000>;
+				label = "file system";
+			};
+
+			partition@jffs-fs {
+				/* 7MB for JFFS2 based RFS */
+				reg = <0x00900000 0x00700000>;
+				label = "file system jffs2";
+			};
+		};
+	};
+
+	usb@22000 {
+		phy_type = "ulpi";
+	};
+
+	/* USB2 is shared with localbus, so it must be disabled
+	   by default. We can't put 'status = "disabled";' here
+	   since U-Boot doesn't clear the status property when
+	   it enables USB2. OTOH, U-Boot does create a new node
+	   when there isn't any. So, just comment it out.
+	usb@23000 {
+		phy_type = "ulpi";
+	};
+	*/
+
+	mdio@24000 {
+		phy0: ethernet-phy@0 {
+			interrupt-parent = <&mpic>;
+			interrupts = <3 1>;
+			reg = <0x0>;
+		};
+
+		phy1: ethernet-phy@1 {
+			interrupt-parent = <&mpic>;
+			interrupts = <2 1>;
+			reg = <0x1>;
+		};
+
+		tbi0: tbi-phy@11 {
+			device_type = "tbi-phy";
+			reg = <0x11>;
+		};
+	};
+
+	mdio@25000 {
+		tbi1: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+
+	enet0: ethernet@b0000 {
+		fixed-link = <1 1 1000 0 0>;
+		phy-connection-type = "rgmii-id";
+
+	};
+
+	enet1: ethernet@b1000 {
+		phy-handle = <&phy0>;
+		tbi-handle = <&tbi1>;
+		phy-connection-type = "sgmii";
+	};
+
+	enet2: ethernet@b2000 {
+		phy-handle = <&phy1>;
+		phy-connection-type = "rgmii-id";
+	};
+};
diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts b/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts
new file mode 100644
index 0000000..4de69b7
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts
@@ -0,0 +1,90 @@
+/*
+ * P1020 RDB-PC Device Tree Source (32-bit address map)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1020si-pre.dtsi"
+/ {
+	model = "fsl,P1020RDB-PC";
+	compatible = "fsl,P1020RDB-PC";
+
+	memory {
+		device_type = "memory";
+	};
+
+	lbc: localbus@ffe05000 {
+		reg = <0 0xffe05000 0 0x1000>;
+
+		/* NOR, NAND Flashes and Vitesse 5 port L2 switch */
+		ranges = <0x0 0x0 0x0 0xef000000 0x01000000
+			  0x1 0x0 0x0 0xff800000 0x00040000
+			  0x2 0x0 0x0 0xffb00000 0x00020000
+			  0x3 0x0 0x0 0xffa00000 0x00020000>;
+	};
+
+	soc: soc@ffe00000 {
+		ranges = <0x0 0x0 0xffe00000 0x100000>;
+	};
+
+	pci0: pcie@ffe09000 {
+		ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+		reg = <0 0xffe09000 0 0x1000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xa0000000
+				  0x2000000 0x0 0xa0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci1: pcie@ffe0a000 {
+		reg = <0 0xffe0a000 0 0x1000>;
+		ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0x80000000
+				  0x2000000 0x0 0x80000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+};
+
+/include/ "p1020rdb-pc.dtsi"
+/include/ "fsl/p1020si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts b/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts
new file mode 100644
index 0000000..5237da7
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts
@@ -0,0 +1,90 @@
+/*
+ * P1020 RDB-PC Device Tree Source (36-bit address map)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1020si-pre.dtsi"
+/ {
+	model = "fsl,P1020RDB-PC";
+	compatible = "fsl,P1020RDB-PC";
+
+	memory {
+		device_type = "memory";
+	};
+
+	lbc: localbus@fffe05000 {
+		reg = <0xf 0xffe05000 0 0x1000>;
+
+		/* NOR, NAND Flashes and Vitesse 5 port L2 switch */
+		ranges = <0x0 0x0 0xf 0xef000000 0x01000000
+			  0x1 0x0 0xf 0xff800000 0x00040000
+			  0x2 0x0 0xf 0xffb00000 0x00040000
+			  0x3 0x0 0xf 0xffa00000 0x00020000>;
+	};
+
+	soc: soc@fffe00000 {
+		ranges = <0x0 0xf 0xffe00000 0x100000>;
+	};
+
+	pci0: pcie@fffe09000 {
+		reg = <0xf 0xffe09000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xc0000000
+				  0x2000000 0x0 0xc0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci1: pcie@fffe0a000 {
+		reg = <0xf 0xffe0a000 0 0x1000>;
+		ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0x80000000
+				  0x2000000 0x0 0x80000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+};
+
+/include/ "p1020rdb-pc.dtsi"
+/include/ "fsl/p1020si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts
new file mode 100644
index 0000000..f411515
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts
@@ -0,0 +1,64 @@
+/*
+ * P1020 RDB-PC  Core0 Device Tree Source in CAMP mode.
+ *
+ * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
+ * can be shared, all the other devices must be assigned to one core only.
+ * This dts file allows core0 to have memory, l2, i2c, spi, gpio, tdm, dma, usb,
+ * eth1, eth2, sdhc, crypto, global-util, message, pci0, pci1, msi.
+ *
+ * Please note to add "-b 0" for core0's dts compiling.
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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/ "p1020rdb-pc_32b.dts"
+
+/ {
+	model = "fsl,P1020RDB-PC";
+	compatible = "fsl,P1020RDB-PC";
+
+	aliases {
+		ethernet1 = &enet1;
+		ethernet2 = &enet2;
+		serial0 = &serial0;
+		pci0 = &pci0;
+		pci1 = &pci1;
+	};
+
+	cpus {
+		PowerPC,P1020@1 {
+			status = "disabled";
+		};
+	};
+
+	memory {
+		device_type = "memory";
+	};
+
+	localbus@ffe05000 {
+		status = "disabled";
+	};
+
+	soc@ffe00000 {
+		serial1: serial@4600 {
+			status = "disabled";
+		};
+
+		enet0: ethernet@b0000 {
+			status = "disabled";
+		};
+
+		mpic: pic@40000 {
+			protected-sources = <
+			42 29 30 34	/* serial1, enet0-queue-group0 */
+			17 18 24 45	/* enet0-queue-group1, crypto */
+			>;
+			pic-no-reset;
+		};
+	};
+};
diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts
new file mode 100644
index 0000000..a91335a
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts
@@ -0,0 +1,142 @@
+/*
+ * P1020 RDB-PC Core1 Device Tree Source in CAMP mode.
+ *
+ * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
+ * can be shared, all the other devices must be assigned to one core only.
+ * This dts allows core1 to have l2, eth0, crypto.
+ *
+ * Please note to add "-b 1" for core1's dts compiling.
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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/ "p1020rdb-pc_32b.dts"
+
+/ {
+	model = "fsl,P1020RDB-PC";
+	compatible = "fsl,P1020RDB-PC";
+
+	aliases {
+		ethernet0 = &enet0;
+		serial0 = &serial1;
+		};
+
+	cpus {
+		PowerPC,P1020@0 {
+			status = "disabled";
+		};
+	};
+
+	memory {
+		device_type = "memory";
+	};
+
+	localbus@ffe05000 {
+		status = "disabled";
+	};
+
+	soc@ffe00000 {
+		ecm-law@0 {
+			status = "disabled";
+		};
+
+		ecm@1000 {
+			status = "disabled";
+		};
+
+		memory-controller@2000 {
+			status = "disabled";
+		};
+
+		i2c@3000 {
+			status = "disabled";
+		};
+
+		i2c@3100 {
+			status = "disabled";
+		};
+
+		serial0: serial@4500 {
+			status = "disabled";
+		};
+
+		spi@7000 {
+			status = "disabled";
+		};
+
+		gpio: gpio-controller@f000 {
+			status = "disabled";
+		};
+
+		dma@21300 {
+			status = "disabled";
+		};
+
+		mdio@24000 {
+			status = "disabled";
+		};
+
+		mdio@25000 {
+			status = "disabled";
+		};
+
+		enet1: ethernet@b1000 {
+			status = "disabled";
+		};
+
+		enet2: ethernet@b2000 {
+			status = "disabled";
+		};
+
+		usb@22000 {
+			status = "disabled";
+		};
+
+		sdhci@2e000 {
+			status = "disabled";
+		};
+
+		mpic: pic@40000 {
+			protected-sources = <
+			16 		/* ecm, mem, L2, pci0, pci1 */
+			43 42 59	/* i2c, serial0, spi */
+			47 63 62 	/* gpio, tdm */
+			20 21 22 23	/* dma */
+			03 02 		/* mdio */
+			35 36 40	/* enet1-queue-group0 */
+			51 52 67	/* enet1-queue-group1 */
+			31 32 33	/* enet2-queue-group0 */
+			25 26 27	/* enet2-queue-group1 */
+			28 72 58 	/* usb, sdhci, crypto */
+			0xb0 0xb1 0xb2	/* message */
+			0xb3 0xb4 0xb5
+			0xb6 0xb7
+			0xe0 0xe1 0xe2	/* msi */
+			0xe3 0xe4 0xe5
+			0xe6 0xe7		/* sdhci, crypto , pci */
+			>;
+			pic-no-reset;
+		};
+
+		msi@41600 {
+			status = "disabled";
+		};
+
+		global-utilities@e0000 {	//global utilities block
+			status = "disabled";
+		};
+	};
+
+	pci0: pcie@ffe09000 {
+		status = "disabled";
+	};
+
+	pci1: pcie@ffe0a000 {
+		status = "disabled";
+	};
+};
diff --git a/arch/powerpc/boot/dts/p1020utm-pc.dtsi b/arch/powerpc/boot/dts/p1020utm-pc.dtsi
new file mode 100644
index 0000000..7ea85ea
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020utm-pc.dtsi
@@ -0,0 +1,140 @@
+/*
+ * P1020 UTM-PC Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+&lbc {
+	nor@0,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "cfi-flash";
+		reg = <0x0 0x0 0x2000000>;
+		bank-width = <2>;
+		device-width = <1>;
+
+		partition@0 {
+			/* 256KB for DTB Image */
+			reg = <0x0 0x00040000>;
+			label = "NOR DTB Image";
+		};
+
+		partition@40000 {
+			/* 3.75 MB for Linux Kernel Image */
+			reg = <0x00040000 0x003c0000>;
+			label = "NOR Linux Kernel Image";
+		};
+
+		partition@400000 {
+			/* 27MB for Root file System */
+			reg = <0x00400000 0x01b00000>;
+			label = "NOR Root File System";
+		};
+
+		partition@1f00000 {
+			/* This location must not be altered  */
+			/* 512KB for u-boot Bootloader Image */
+			/* 512KB for u-boot Environment Variables */
+			reg = <0x01f00000 0x00100000>;
+			label = "NOR U-Boot Image";
+			read-only;
+		};
+	};
+};
+
+&soc {
+	i2c@3000 {
+		rtc@68 {
+			compatible = "dallas,ds1339";
+			reg = <0x68>;
+		};
+	};
+
+	mdio@24000 {
+		phy0: ethernet-phy@0 {
+			interrupts = <3 1 0 0>;
+			reg = <0x0>;
+		};
+		phy1: ethernet-phy@1 {
+			interrupts = <2 1 0 0>;
+			reg = <0x1>;
+		};
+		phy2: ethernet-phy@2 {
+			interrupts = <1 1 0 0>;
+			reg = <0x2>;
+		};
+	};
+
+	mdio@25000 {
+		tbi1: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+
+	mdio@26000 {
+		tbi2: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+
+	enet0: ethernet@b0000 {
+		phy-handle = <&phy2>;
+		phy-connection-type = "rgmii-id";
+	};
+
+	enet1: ethernet@b1000 {
+		phy-handle = <&phy0>;
+		tbi-handle = <&tbi1>;
+		phy-connection-type = "sgmii";
+	};
+
+	enet2: ethernet@b2000 {
+		phy-handle = <&phy1>;
+		phy-connection-type = "rgmii-id";
+	};
+
+	usb@22000 {
+		phy_type = "ulpi";
+	};
+
+	/* USB2 is shared with localbus, so it must be disabled
+	   by default. We can't put 'status = "disabled";' here
+	   since U-Boot doesn't clear the status property when
+	   it enables USB2. OTOH, U-Boot does create a new node
+	   when there isn't any. So, just comment it out.
+	*/
+	usb@23000 {
+		status = "disabled";
+		phy_type = "ulpi";
+	};
+};
diff --git a/arch/powerpc/boot/dts/p1020utm-pc_32b.dts b/arch/powerpc/boot/dts/p1020utm-pc_32b.dts
new file mode 100644
index 0000000..4bfdd89
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020utm-pc_32b.dts
@@ -0,0 +1,89 @@
+/*
+ * P1020 UTM-PC Device Tree Source (32-bit address map)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1020si-pre.dtsi"
+/ {
+	model = "fsl,P1020UTM-PC";
+	compatible = "fsl,P1020UTM-PC";
+
+	memory {
+		device_type = "memory";
+	};
+
+	lbc: localbus@ffe05000 {
+		reg = <0x0 0xffe05000 0x0 0x1000>;
+
+		/* NOR */
+		ranges = <0x0 0x0 0x0 0xec000000 0x02000000
+			  0x1 0x0 0x0 0xffa00000 0x00040000
+			  0x2 0x0 0x0 0xffb00000 0x00020000>;
+	};
+
+	soc: soc@ffe00000 {
+		ranges = <0x0 0x0 0xffe00000 0x100000>;
+	};
+
+	pci0: pcie@ffe09000 {
+		reg = <0x0 0xffe09000 0x0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0x0 0xa0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0x0 0xffc10000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci1: pcie@ffe0a000 {
+		reg = <0x0 0xffe0a000 0x0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0x0 0x80000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0x0 0xffc00000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+};
+
+/include/ "p1020utm-pc.dtsi"
+/include/ "fsl/p1020si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1020utm-pc_36b.dts b/arch/powerpc/boot/dts/p1020utm-pc_36b.dts
new file mode 100644
index 0000000..abec535
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020utm-pc_36b.dts
@@ -0,0 +1,89 @@
+/*
+ * P1020 UTM-PC Device Tree Source (36-bit address map)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1020si-pre.dtsi"
+/ {
+	model = "fsl,P1020UTM-PC";
+	compatible = "fsl,P1020UTM-PC";
+
+	memory {
+		device_type = "memory";
+	};
+
+	lbc: localbus@fffe05000 {
+		reg = <0xf 0xffe05000 0x0 0x1000>;
+
+		/* NOR */
+		ranges = <0x0 0x0 0xf 0xec000000 0x02000000
+			  0x1 0x0 0xf 0xffa00000 0x00040000
+			  0x2 0x0 0xf 0xffb00000 0x00020000>;
+	};
+
+	soc: soc@fffe00000 {
+		ranges = <0x0 0xf 0xffe00000 0x100000>;
+	};
+
+	pci0: pcie@fffe09000 {
+		reg = <0xf 0xffe09000 0x0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci1: pcie@fffe0a000 {
+		reg = <0xf 0xffe0a000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+};
+
+/include/ "p1020utm-pc.dtsi"
+/include/ "fsl/p1020si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1021rdb.dts b/arch/powerpc/boot/dts/p1021rdb.dts
new file mode 100644
index 0000000..90b6b4c
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1021rdb.dts
@@ -0,0 +1,96 @@
+/*
+ * P1021 RDB Device Tree Source
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1021si-pre.dtsi"
+/ {
+	model = "fsl,P1021RDB";
+	compatible = "fsl,P1021RDB-PC";
+
+	memory {
+		device_type = "memory";
+	};
+
+	lbc: localbus@ffe05000 {
+		reg = <0 0xffe05000 0 0x1000>;
+
+		/* NOR, NAND Flashes and Vitesse 5 port L2 switch */
+		ranges = <0x0 0x0 0x0 0xef000000 0x01000000
+			  0x1 0x0 0x0 0xff800000 0x00040000
+			  0x2 0x0 0x0 0xffb00000 0x00020000>;
+	};
+
+	soc: soc@ffe00000 {
+		ranges = <0x0 0x0 0xffe00000 0x100000>;
+	};
+
+	pci0: pcie@ffe09000 {
+		ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+		reg = <0 0xffe09000 0 0x1000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xa0000000
+				  0x2000000 0x0 0xa0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci1: pcie@ffe0a000 {
+		reg = <0 0xffe0a000 0 0x1000>;
+		ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0x80000000
+				  0x2000000 0x0 0x80000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	qe: qe@ffe80000 {
+                ranges = <0x0 0x0 0xffe80000 0x40000>;
+                reg = <0 0xffe80000 0 0x480>;
+                brg-frequency = <0>;
+                bus-frequency = <0>;
+        };
+};
+
+/include/ "p1021rdb.dtsi"
+/include/ "fsl/p1021si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1021rdb.dtsi b/arch/powerpc/boot/dts/p1021rdb.dtsi
new file mode 100644
index 0000000..b973461
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1021rdb.dtsi
@@ -0,0 +1,236 @@
+/*
+ * P1021 RDB Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+&lbc {
+	nor@0,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "cfi-flash";
+		reg = <0x0 0x0 0x1000000>;
+		bank-width = <2>;
+		device-width = <1>;
+
+		partition@0 {
+			/* This location must not be altered  */
+			/* 256KB for Vitesse 7385 Switch firmware */
+			reg = <0x0 0x00040000>;
+			label = "NOR Vitesse-7385 Firmware";
+			read-only;
+		};
+
+		partition@40000 {
+			/* 256KB for DTB Image */
+			reg = <0x00040000 0x00040000>;
+			label = "NOR DTB Image";
+		};
+
+		partition@80000 {
+			/* 3.5 MB for Linux Kernel Image */
+			reg = <0x00080000 0x00380000>;
+			label = "NOR Linux Kernel Image";
+		};
+
+		partition@400000 {
+			/* 11MB for JFFS2 based Root file System */
+			reg = <0x00400000 0x00b00000>;
+			label = "NOR JFFS2 Root File System";
+		};
+
+		partition@f00000 {
+			/* This location must not be altered  */
+			/* 512KB for u-boot Bootloader Image */
+			/* 512KB for u-boot Environment Variables */
+			reg = <0x00f00000 0x00100000>;
+			label = "NOR U-Boot Image";
+		};
+	};
+
+	nand@1,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "fsl,p1021-fcm-nand",
+			     "fsl,elbc-fcm-nand";
+		reg = <0x1 0x0 0x40000>;
+
+		partition@0 {
+			/* This location must not be altered  */
+			/* 1MB for u-boot Bootloader Image */
+			reg = <0x0 0x00100000>;
+			label = "NAND U-Boot Image";
+			read-only;
+		};
+
+		partition@100000 {
+			/* 1MB for DTB Image */
+			reg = <0x00100000 0x00100000>;
+			label = "NAND DTB Image";
+		};
+
+		partition@200000 {
+			/* 4MB for Linux Kernel Image */
+			reg = <0x00200000 0x00400000>;
+			label = "NAND Linux Kernel Image";
+		};
+
+		partition@600000 {
+			/* 4MB for Compressed Root file System Image */
+			reg = <0x00600000 0x00400000>;
+			label = "NAND Compressed RFS Image";
+		};
+
+		partition@a00000 {
+			/* 7MB for JFFS2 based Root file System */
+			reg = <0x00a00000 0x00700000>;
+			label = "NAND JFFS2 Root File System";
+		};
+
+		partition@1100000 {
+			/* 15MB for User Writable Area  */
+			reg = <0x01100000 0x00f00000>;
+			label = "NAND Writable User area";
+		};
+	};
+
+	L2switch@2,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "vitesse-7385";
+		reg = <0x2 0x0 0x20000>;
+	};
+};
+
+&soc {
+	i2c@3000 {
+		rtc@68 {
+			compatible = "pericom,pt7c4338";
+			reg = <0x68>;
+		};
+	};
+
+	spi@7000 {
+		flash@0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "spansion,s25sl12801";
+			reg = <0>;
+			spi-max-frequency = <40000000>; /* input clock */
+
+			partition@u-boot {
+				/* 512KB for u-boot Bootloader Image */
+				reg = <0x0 0x00080000>;
+				label = "SPI Flash U-Boot Image";
+				read-only;
+			};
+
+			partition@dtb {
+				/* 512KB for DTB Image */
+				reg = <0x00080000 0x00080000>;
+				label = "SPI Flash DTB Image";
+			};
+
+			partition@kernel {
+				/* 4MB for Linux Kernel Image */
+				reg = <0x00100000 0x00400000>;
+				label = "SPI Flash Linux Kernel Image";
+			};
+
+			partition@fs {
+				/* 4MB for Compressed RFS Image */
+				reg = <0x00500000 0x00400000>;
+				label = "SPI Flash Compressed RFSImage";
+			};
+
+			partition@jffs-fs {
+				/* 7MB for JFFS2 based RFS */
+				reg = <0x00900000 0x00700000>;
+				label = "SPI Flash JFFS2 RFS";
+			};
+		};
+	};
+
+	usb@22000 {
+		phy_type = "ulpi";
+	};
+
+	mdio@24000 {
+		phy0: ethernet-phy@0 {
+			interrupt-parent = <&mpic>;
+			interrupts = <3 1 0 0>;
+			reg = <0x0>;
+		};
+
+		phy1: ethernet-phy@1 {
+			interrupt-parent = <&mpic>;
+			interrupts = <2 1 0 0>;
+			reg = <0x1>;
+		};
+
+		tbi0: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+
+	mdio@25000 {
+		tbi1: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+
+	mdio@26000 {
+		tbi2: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+
+	enet0: ethernet@b0000 {
+		fixed-link = <1 1 1000 0 0>;
+		phy-connection-type = "rgmii-id";
+
+	};
+
+	enet1: ethernet@b1000 {
+		phy-handle = <&phy0>;
+		tbi-handle = <&tbi1>;
+		phy-connection-type = "sgmii";
+	};
+
+	enet2: ethernet@b2000 {
+		phy-handle = <&phy1>;
+		tbi-handle = <&tbi2>;
+		phy-connection-type = "rgmii-id";
+	};
+};
diff --git a/arch/powerpc/boot/dts/p1021rdb_36b.dts b/arch/powerpc/boot/dts/p1021rdb_36b.dts
new file mode 100644
index 0000000..ea6d8b5
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1021rdb_36b.dts
@@ -0,0 +1,96 @@
+/*
+ * P1021 RDB Device Tree Source (36-bit address map)
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1021si-pre.dtsi"
+/ {
+	model = "fsl,P1021RDB";
+	compatible = "fsl,P1021RDB-PC";
+
+	memory {
+		device_type = "memory";
+	};
+
+	lbc: localbus@fffe05000 {
+		reg = <0xf 0xffe05000 0 0x1000>;
+
+		/* NOR, NAND Flashes and Vitesse 5 port L2 switch */
+		ranges = <0x0 0x0 0xf 0xef000000 0x01000000
+			  0x1 0x0 0xf 0xff800000 0x00040000
+			  0x2 0x0 0xf 0xffb00000 0x00020000>;
+	};
+
+	soc: soc@fffe00000 {
+		ranges = <0x0 0xf 0xffe00000 0x100000>;
+	};
+
+	pci0: pcie@fffe09000 {
+		ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
+		reg = <0xf 0xffe09000 0 0x1000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xa0000000
+				  0x2000000 0x0 0xa0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci1: pcie@fffe0a000 {
+		reg = <0xf 0xffe0a000 0 0x1000>;
+		ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xc0000000
+				  0x2000000 0x0 0xc0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	qe: qe@fffe80000 {
+                ranges = <0x0 0xf 0xffe80000 0x40000>;
+                reg = <0xf 0xffe80000 0 0x480>;
+                brg-frequency = <0>;
+                bus-frequency = <0>;
+        };
+};
+
+/include/ "p1021rdb.dtsi"
+/include/ "fsl/p1021si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1022ds.dts b/arch/powerpc/boot/dts/p1022ds.dts
deleted file mode 100644
index ef95717..0000000
--- a/arch/powerpc/boot/dts/p1022ds.dts
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * P1022 DS 36Bit Physical Address Map Device Tree Source
- *
- * Copyright 2010 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.
- */
-
-/include/ "fsl/p1022si-pre.dtsi"
-/ {
-	model = "fsl,P1022DS";
-	compatible = "fsl,P1022DS";
-
-	memory {
-		device_type = "memory";
-	};
-
-	lbc: localbus@fffe05000 {
-		reg = <0xf 0xffe05000 0 0x1000>;
-		ranges = <0x0 0x0 0xf 0xe8000000 0x08000000
-			  0x1 0x0 0xf 0xe0000000 0x08000000
-			  0x2 0x0 0xf 0xff800000 0x00040000
-			  0x3 0x0 0xf 0xffdf0000 0x00008000>;
-
-		/*
-		 * This node is used to access the pixis via "indirect" mode,
-		 * which is done by writing the pixis register index to chip
-		 * select 0 and the value to/from chip select 1.  Indirect
-		 * mode is the only way to access the pixis when DIU video
-		 * is enabled.  Note that this assumes that the first column
-		 * of the 'ranges' property above is the chip select number.
-		 */
-		board-control@0,0 {
-			compatible = "fsl,p1022ds-indirect-pixis";
-			reg = <0x0 0x0 1	/* CS0 */
-			       0x1 0x0 1>;	/* CS1 */
-		};
-
-		nor@0,0 {
-			#address-cells = <1>;
-			#size-cells = <1>;
-			compatible = "cfi-flash";
-			reg = <0x0 0x0 0x8000000>;
-			bank-width = <2>;
-			device-width = <1>;
-
-			partition@0 {
-				reg = <0x0 0x03000000>;
-				label = "ramdisk-nor";
-				read-only;
-			};
-
-			partition@3000000 {
-				reg = <0x03000000 0x00e00000>;
-				label = "diagnostic-nor";
-				read-only;
-			};
-
-			partition@3e00000 {
-				reg = <0x03e00000 0x00200000>;
-				label = "dink-nor";
-				read-only;
-			};
-
-			partition@4000000 {
-				reg = <0x04000000 0x00400000>;
-				label = "kernel-nor";
-				read-only;
-			};
-
-			partition@4400000 {
-				reg = <0x04400000 0x03b00000>;
-				label = "jffs2-nor";
-			};
-
-			partition@7f00000 {
-				reg = <0x07f00000 0x00080000>;
-				label = "dtb-nor";
-				read-only;
-			};
-
-			partition@7f80000 {
-				reg = <0x07f80000 0x00080000>;
-				label = "u-boot-nor";
-				read-only;
-			};
-		};
-
-		nand@2,0 {
-			#address-cells = <1>;
-			#size-cells = <1>;
-			compatible = "fsl,elbc-fcm-nand";
-			reg = <0x2 0x0 0x40000>;
-
-			partition@0 {
-				reg = <0x0 0x02000000>;
-				label = "u-boot-nand";
-				read-only;
-			};
-
-			partition@2000000 {
-				reg = <0x02000000 0x10000000>;
-				label = "jffs2-nand";
-			};
-
-			partition@12000000 {
-				reg = <0x12000000 0x10000000>;
-				label = "ramdisk-nand";
-				read-only;
-			};
-
-			partition@22000000 {
-				reg = <0x22000000 0x04000000>;
-				label = "kernel-nand";
-			};
-
-			partition@26000000 {
-				reg = <0x26000000 0x01000000>;
-				label = "dtb-nand";
-				read-only;
-			};
-
-			partition@27000000 {
-				reg = <0x27000000 0x19000000>;
-				label = "reserved-nand";
-			};
-		};
-
-		board-control@3,0 {
-			compatible = "fsl,p1022ds-fpga", "fsl,fpga-ngpixis";
-			reg = <3 0 0x30>;
-			interrupt-parent = <&mpic>;
-			/*
-			 * IRQ8 is generated if the "EVENT" switch is pressed
-			 * and PX_CTL[EVESEL] is set to 00.
-			 */
-			interrupts = <8 8 0 0>;
-		};
-	};
-
-	soc: soc@fffe00000 {
-		ranges = <0x0 0xf 0xffe00000 0x100000>;
-
-		i2c@3100 {
-			wm8776:codec@1a {
-				compatible = "wlf,wm8776";
-				reg = <0x1a>;
-				/*
-				 * clock-frequency will be set by U-Boot if
-				 * the clock is enabled.
-				 */
-			};
-		};
-
-		spi@7000 {
-			flash@0 {
-				#address-cells = <1>;
-				#size-cells = <1>;
-				compatible = "spansion,s25sl12801";
-				reg = <0>;
-				spi-max-frequency = <40000000>; /* input clock */
-
-				partition@0 {
-					label = "u-boot-spi";
-					reg = <0x00000000 0x00100000>;
-					read-only;
-				};
-				partition@100000 {
-					label = "kernel-spi";
-					reg = <0x00100000 0x00500000>;
-					read-only;
-				};
-				partition@600000 {
-					label = "dtb-spi";
-					reg = <0x00600000 0x00100000>;
-					read-only;
-				};
-				partition@700000 {
-					label = "file system-spi";
-					reg = <0x00700000 0x00900000>;
-				};
-			};
-		};
-
-		ssi@15000 {
-			fsl,mode = "i2s-slave";
-			codec-handle = <&wm8776>;
-			fsl,ssi-asynchronous;
-		};
-
-		usb@22000 {
-			phy_type = "ulpi";
-		};
-
-		usb@23000 {
-			status = "disabled";
-		};
-
-		mdio@24000 {
-			phy0: ethernet-phy@0 {
-				interrupts = <3 1 0 0>;
-				reg = <0x1>;
-			};
-			phy1: ethernet-phy@1 {
-				interrupts = <9 1 0 0>;
-				reg = <0x2>;
-			};
-			tbi-phy@2 {
-				device_type = "tbi-phy";
-				reg = <0x2>;
-			};
-		};
-
-		ethernet@b0000 {
-			phy-handle = <&phy0>;
-			phy-connection-type = "rgmii-id";
-		};
-
-		ethernet@b1000 {
-			phy-handle = <&phy1>;
-			phy-connection-type = "rgmii-id";
-		};
-	};
-
-	pci0: pcie@fffe09000 {
-		reg = <0xf 0xffe09000 0 0x1000>;
-		ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
-			  0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
-		pcie@0 {
-			ranges = <0x2000000 0x0 0xe0000000
-				  0x2000000 0x0 0xe0000000
-				  0x0 0x20000000
-
-				  0x1000000 0x0 0x0
-				  0x1000000 0x0 0x0
-				  0x0 0x100000>;
-		};
-	};
-
-	pci1: pcie@fffe0a000 {
-		reg = <0xf 0xffe0a000 0 0x1000>;
-		ranges = <0x2000000 0x0 0xe0000000 0xc 0x40000000 0x0 0x20000000
-			  0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>;
-		pcie@0 {
-			reg = <0x0 0x0 0x0 0x0 0x0>;
-			ranges = <0x2000000 0x0 0xe0000000
-				  0x2000000 0x0 0xe0000000
-				  0x0 0x20000000
-
-				  0x1000000 0x0 0x0
-				  0x1000000 0x0 0x0
-				  0x0 0x100000>;
-		};
-	};
-
-	pci2: pcie@fffe0b000 {
-		reg = <0xf 0xffe0b000 0 0x1000>;
-		ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000
-			  0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
-		pcie@0 {
-			ranges = <0x2000000 0x0 0xe0000000
-				  0x2000000 0x0 0xe0000000
-				  0x0 0x20000000
-
-				  0x1000000 0x0 0x0
-				  0x1000000 0x0 0x0
-				  0x0 0x100000>;
-		};
-	};
-};
-
-/include/ "fsl/p1022si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1022ds.dtsi b/arch/powerpc/boot/dts/p1022ds.dtsi
new file mode 100644
index 0000000..7cdb505
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1022ds.dtsi
@@ -0,0 +1,234 @@
+/*
+ * P1022 DS Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor 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.
+ */
+
+&board_lbc {
+	/*
+	 * This node is used to access the pixis via "indirect" mode,
+	 * which is done by writing the pixis register index to chip
+	 * select 0 and the value to/from chip select 1.  Indirect
+	 * mode is the only way to access the pixis when DIU video
+	 * is enabled.  Note that this assumes that the first column
+	 * of the 'ranges' property above is the chip select number.
+	 */
+	board-control@0,0 {
+		compatible = "fsl,p1022ds-indirect-pixis";
+		reg = <0x0 0x0 1	/* CS0 */
+		       0x1 0x0 1>;	/* CS1 */
+		interrupt-parent = <&mpic>;
+		interrupts = <8 0 0 0>;
+	};
+
+	nor@0,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "cfi-flash";
+		reg = <0x0 0x0 0x8000000>;
+		bank-width = <2>;
+		device-width = <1>;
+
+		partition@0 {
+			reg = <0x0 0x03000000>;
+			label = "ramdisk-nor";
+			read-only;
+		};
+
+		partition@3000000 {
+			reg = <0x03000000 0x00e00000>;
+			label = "diagnostic-nor";
+			read-only;
+		};
+
+		partition@3e00000 {
+			reg = <0x03e00000 0x00200000>;
+			label = "dink-nor";
+			read-only;
+		};
+
+		partition@4000000 {
+			reg = <0x04000000 0x00400000>;
+			label = "kernel-nor";
+			read-only;
+		};
+
+		partition@4400000 {
+			reg = <0x04400000 0x03b00000>;
+			label = "jffs2-nor";
+		};
+
+		partition@7f00000 {
+			reg = <0x07f00000 0x00080000>;
+			label = "dtb-nor";
+			read-only;
+		};
+
+		partition@7f80000 {
+			reg = <0x07f80000 0x00080000>;
+			label = "u-boot-nor";
+			read-only;
+		};
+	};
+
+	nand@2,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "fsl,elbc-fcm-nand";
+		reg = <0x2 0x0 0x40000>;
+
+		partition@0 {
+			reg = <0x0 0x02000000>;
+			label = "u-boot-nand";
+			read-only;
+		};
+
+		partition@2000000 {
+			reg = <0x02000000 0x10000000>;
+			label = "jffs2-nand";
+		};
+
+		partition@12000000 {
+			reg = <0x12000000 0x10000000>;
+			label = "ramdisk-nand";
+			read-only;
+		};
+
+		partition@22000000 {
+			reg = <0x22000000 0x04000000>;
+			label = "kernel-nand";
+		};
+
+		partition@26000000 {
+			reg = <0x26000000 0x01000000>;
+			label = "dtb-nand";
+			read-only;
+		};
+
+		partition@27000000 {
+			reg = <0x27000000 0x19000000>;
+			label = "reserved-nand";
+		};
+	};
+
+	board-control@3,0 {
+		compatible = "fsl,p1022ds-fpga", "fsl,fpga-ngpixis";
+		reg = <3 0 0x30>;
+		interrupt-parent = <&mpic>;
+		/*
+		 * IRQ8 is generated if the "EVENT" switch is pressed
+		 * and PX_CTL[EVESEL] is set to 00.
+		 */
+		interrupts = <8 0 0 0>;
+	};
+};
+
+&board_soc {
+	i2c@3100 {
+		wm8776:codec@1a {
+			compatible = "wlf,wm8776";
+			reg = <0x1a>;
+			/*
+			 * clock-frequency will be set by U-Boot if
+			 * the clock is enabled.
+			 */
+		};
+	};
+
+	spi@7000 {
+		flash@0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "spansion,s25sl12801";
+			reg = <0>;
+			spi-max-frequency = <40000000>; /* input clock */
+
+			partition@0 {
+				label = "u-boot-spi";
+				reg = <0x00000000 0x00100000>;
+				read-only;
+			};
+			partition@100000 {
+				label = "kernel-spi";
+				reg = <0x00100000 0x00500000>;
+				read-only;
+			};
+			partition@600000 {
+				label = "dtb-spi";
+				reg = <0x00600000 0x00100000>;
+				read-only;
+			};
+			partition@700000 {
+				label = "file system-spi";
+				reg = <0x00700000 0x00900000>;
+			};
+		};
+	};
+
+	ssi@15000 {
+		fsl,mode = "i2s-slave";
+		codec-handle = <&wm8776>;
+		fsl,ssi-asynchronous;
+	};
+
+	usb@22000 {
+		phy_type = "ulpi";
+	};
+
+	usb@23000 {
+		status = "disabled";
+	};
+
+	mdio@24000 {
+		phy0: ethernet-phy@0 {
+			interrupts = <3 1 0 0>;
+			reg = <0x1>;
+		};
+		phy1: ethernet-phy@1 {
+			interrupts = <9 1 0 0>;
+			reg = <0x2>;
+		};
+		tbi-phy@2 {
+			device_type = "tbi-phy";
+			reg = <0x2>;
+		};
+	};
+
+	ethernet@b0000 {
+		phy-handle = <&phy0>;
+		phy-connection-type = "rgmii-id";
+	};
+
+	ethernet@b1000 {
+		phy-handle = <&phy1>;
+		phy-connection-type = "rgmii-id";
+	};
+};
diff --git a/arch/powerpc/boot/dts/p1022ds_32b.dts b/arch/powerpc/boot/dts/p1022ds_32b.dts
new file mode 100644
index 0000000..d96cae0
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1022ds_32b.dts
@@ -0,0 +1,103 @@
+/*
+ * P1022 DS 32-bit Physical Address Map Device Tree Source
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1022si-pre.dtsi"
+/ {
+	model = "fsl,P1022DS";
+	compatible = "fsl,P1022DS";
+
+	memory {
+		device_type = "memory";
+	};
+
+	board_lbc: lbc: localbus@ffe05000 {
+		ranges = <0x0 0x0 0x0 0xe8000000 0x08000000
+			  0x1 0x0 0x0 0xe0000000 0x08000000
+			  0x2 0x0 0x0 0xff800000 0x00040000
+			  0x3 0x0 0x0 0xffdf0000 0x00008000>;
+		reg = <0x0 0xffe05000 0 0x1000>;
+	};
+
+	board_soc: soc: soc@ffe00000 {
+		ranges = <0x0 0x0 0xffe00000 0x100000>;
+	};
+
+	pci0: pcie@ffe09000 {
+		ranges = <0x2000000 0x0 0xe0000000 0 0xa0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+		reg = <0x0 0xffe09000 0 0x1000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci1: pcie@ffe0a000 {
+		ranges = <0x2000000 0x0 0xe0000000 0 0xc0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>;
+		reg = <0 0xffe0a000 0 0x1000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci2: pcie@ffe0b000 {
+		ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+		reg = <0 0xffe0b000 0 0x1000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+};
+
+/include/ "fsl/p1022si-post.dtsi"
+/include/ "p1022ds.dtsi"
diff --git a/arch/powerpc/boot/dts/p1022ds_36b.dts b/arch/powerpc/boot/dts/p1022ds_36b.dts
new file mode 100644
index 0000000..f7aacce
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1022ds_36b.dts
@@ -0,0 +1,103 @@
+/*
+ * P1022 DS 36-bit Physical Address Map Device Tree Source
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1022si-pre.dtsi"
+/ {
+	model = "fsl,P1022DS";
+	compatible = "fsl,P1022DS";
+
+	memory {
+		device_type = "memory";
+	};
+
+	board_lbc: lbc: localbus@fffe05000 {
+		ranges = <0x0 0x0 0xf 0xe8000000 0x08000000
+			  0x1 0x0 0xf 0xe0000000 0x08000000
+			  0x2 0x0 0xf 0xff800000 0x00040000
+			  0x3 0x0 0xf 0xffdf0000 0x00008000>;
+		reg = <0xf 0xffe05000 0 0x1000>;
+	};
+
+	board_soc: soc: soc@fffe00000 {
+		ranges = <0x0 0xf 0xffe00000 0x100000>;
+	};
+
+	pci0: pcie@fffe09000 {
+		ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
+		reg = <0xf 0xffe09000 0 0x1000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci1: pcie@fffe0a000 {
+		ranges = <0x2000000 0x0 0xe0000000 0xc 0x40000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>;
+		reg = <0xf 0xffe0a000 0 0x1000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci2: pcie@fffe0b000 {
+		ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
+		reg = <0xf 0xffe0b000 0 0x1000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+};
+
+/include/ "fsl/p1022si-post.dtsi"
+/include/ "p1022ds.dtsi"
diff --git a/arch/powerpc/boot/dts/p1025rdb.dtsi b/arch/powerpc/boot/dts/p1025rdb.dtsi
new file mode 100644
index 0000000..cf3676f
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1025rdb.dtsi
@@ -0,0 +1,286 @@
+/*
+ * P1025 RDB Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+&lbc {
+	nor@0,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "cfi-flash";
+		reg = <0x0 0x0 0x1000000>;
+		bank-width = <2>;
+		device-width = <1>;
+
+		partition@0 {
+			/* This location must not be altered  */
+			/* 256KB for Vitesse 7385 Switch firmware */
+			reg = <0x0 0x00040000>;
+			label = "NOR Vitesse-7385 Firmware";
+			read-only;
+		};
+
+		partition@40000 {
+			/* 256KB for DTB Image */
+			reg = <0x00040000 0x00040000>;
+			label = "NOR DTB Image";
+		};
+
+		partition@80000 {
+			/* 3.5 MB for Linux Kernel Image */
+			reg = <0x00080000 0x00380000>;
+			label = "NOR Linux Kernel Image";
+		};
+
+		partition@400000 {
+			/* 11MB for JFFS2 based Root file System */
+			reg = <0x00400000 0x00b00000>;
+			label = "NOR JFFS2 Root File System";
+		};
+
+		partition@f00000 {
+			/* This location must not be altered  */
+			/* 512KB for u-boot Bootloader Image */
+			/* 512KB for u-boot Environment Variables */
+			reg = <0x00f00000 0x00100000>;
+			label = "NOR U-Boot Image";
+			read-only;
+		};
+	};
+
+	nand@1,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "fsl,p1025-fcm-nand",
+			     "fsl,elbc-fcm-nand";
+		reg = <0x1 0x0 0x40000>;
+
+		partition@0 {
+			/* This location must not be altered  */
+			/* 1MB for u-boot Bootloader Image */
+			reg = <0x0 0x00100000>;
+			label = "NAND U-Boot Image";
+			read-only;
+		};
+
+		partition@100000 {
+			/* 1MB for DTB Image */
+			reg = <0x00100000 0x00100000>;
+			label = "NAND DTB Image";
+		};
+
+		partition@200000 {
+			/* 4MB for Linux Kernel Image */
+			reg = <0x00200000 0x00400000>;
+			label = "NAND Linux Kernel Image";
+		};
+
+		partition@600000 {
+			/* 4MB for Compressed Root file System Image */
+			reg = <0x00600000 0x00400000>;
+			label = "NAND Compressed RFS Image";
+		};
+
+		partition@a00000 {
+			/* 7MB for JFFS2 based Root file System */
+			reg = <0x00a00000 0x00700000>;
+			label = "NAND JFFS2 Root File System";
+		};
+
+		partition@1100000 {
+			/* 15MB for JFFS2 based Root file System */
+			reg = <0x01100000 0x00f00000>;
+			label = "NAND Writable User area";
+		};
+	};
+
+};
+
+&soc {
+	i2c@3000 {
+		rtc@68 {
+			compatible = "dallas,ds1339";
+			reg = <0x68>;
+		};
+	};
+
+	spi@7000 {
+		flash@0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "spansion,s25sl12801";
+			reg = <0>;
+			spi-max-frequency = <40000000>; /* input clock */
+
+			partition@u-boot {
+				/* 512KB for u-boot Bootloader Image */
+				reg = <0x0 0x00080000>;
+				label = "u-boot";
+				read-only;
+			};
+
+			partition@dtb {
+				/* 512KB for DTB Image */
+				reg = <0x00080000 0x00080000>;
+				label = "dtb";
+			};
+
+			partition@kernel {
+				/* 4MB for Linux Kernel Image */
+				reg = <0x00100000 0x00400000>;
+				label = "kernel";
+			};
+
+			partition@fs {
+				/* 4MB for Compressed RFS Image */
+				reg = <0x00500000 0x00400000>;
+				label = "file system";
+			};
+
+			partition@jffs-fs {
+				/* 7MB for JFFS2 based RFS */
+				reg = <0x00900000 0x00700000>;
+				label = "file system jffs2";
+			};
+		};
+	};
+
+	usb@22000 {
+		phy_type = "ulpi";
+	};
+
+	/* USB2 is shared with localbus, so it must be disabled
+	   by default. We can't put 'status = "disabled";' here
+	   since U-Boot doesn't clear the status property when
+	   it enables USB2. OTOH, U-Boot does create a new node
+	   when there isn't any. So, just comment it out.
+	usb@23000 {
+		phy_type = "ulpi";
+	};
+	*/
+
+	mdio@24000 {
+		phy0: ethernet-phy@0 {
+			interrupt-parent = <&mpic>;
+			interrupts = <3 1>;
+			reg = <0x0>;
+		};
+
+		phy1: ethernet-phy@1 {
+			interrupt-parent = <&mpic>;
+			interrupts = <2 1>;
+			reg = <0x1>;
+		};
+
+		tbi0: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+
+	mdio@25000 {
+		tbi1: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+
+	mdio@26000 {
+		tbi2: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+
+	enet0: ethernet@b0000 {
+		fixed-link = <1 1 1000 0 0>;
+		phy-connection-type = "rgmii-id";
+
+	};
+
+	enet1: ethernet@b1000 {
+		phy-handle = <&phy0>;
+		tbi-handle = <&tbi1>;
+		phy-connection-type = "sgmii";
+	};
+
+	enet2: ethernet@b2000 {
+		phy-handle = <&phy1>;
+		phy-connection-type = "rgmii-id";
+	};
+
+	par_io@e0100 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xe0100 0x60>;
+		ranges = <0x0 0xe0100 0x60>;
+		device_type = "par_io";
+		num-ports = <3>;
+		pio1: ucc_pin@01 {
+			pio-map = <
+		/* port  pin  dir  open_drain  assignment  has_irq */
+				0x1  0x13 0x1  0x0  0x1  0x0    /* QE_MUX_MDC */
+				0x1  0x14 0x3  0x0  0x1  0x0    /* QE_MUX_MDIO */
+				0x0  0x17 0x2  0x0  0x2  0x0    /* CLK12 */
+				0x0  0x18 0x2  0x0  0x1  0x0    /* CLK9 */
+				0x0  0x7  0x1  0x0  0x2  0x0    /* ENET1_TXD0_SER1_TXD0 */
+				0x0  0x9  0x1  0x0  0x2  0x0    /* ENET1_TXD1_SER1_TXD1 */
+				0x0  0xb  0x1  0x0  0x2  0x0    /* ENET1_TXD2_SER1_TXD2 */
+				0x0  0xc  0x1  0x0  0x2  0x0    /* ENET1_TXD3_SER1_TXD3 */
+				0x0  0x6  0x2  0x0  0x2  0x0    /* ENET1_RXD0_SER1_RXD0 */
+				0x0  0xa  0x2  0x0  0x2  0x0    /* ENET1_RXD1_SER1_RXD1 */
+				0x0  0xe  0x2  0x0  0x2  0x0    /* ENET1_RXD2_SER1_RXD2 */
+				0x0  0xf  0x2  0x0  0x2  0x0    /* ENET1_RXD3_SER1_RXD3 */
+				0x0  0x5  0x1  0x0  0x2  0x0    /* ENET1_TX_EN_SER1_RTS_B */
+				0x0  0xd  0x1  0x0  0x2  0x0    /* ENET1_TX_ER */
+				0x0  0x4  0x2  0x0  0x2  0x0    /* ENET1_RX_DV_SER1_CTS_B */
+				0x0  0x8  0x2  0x0  0x2  0x0    /* ENET1_RX_ER_SER1_CD_B */
+				0x0  0x11 0x2  0x0  0x2  0x0    /* ENET1_CRS */
+				0x0  0x10 0x2  0x0  0x2  0x0>;    /* ENET1_COL */
+		};
+
+		pio2: ucc_pin@02 {
+			pio-map = <
+		/* port  pin  dir  open_drain  assignment  has_irq */
+				0x1  0x13 0x1  0x0  0x1  0x0    /* QE_MUX_MDC */
+				0x1  0x14 0x3  0x0  0x1  0x0    /* QE_MUX_MDIO */
+				0x1  0xb  0x2  0x0  0x1  0x0    /* CLK13 */
+				0x1  0x7  0x1  0x0  0x2  0x0    /* ENET5_TXD0_SER5_TXD0 */
+				0x1  0xa  0x1  0x0  0x2  0x0    /* ENET5_TXD1_SER5_TXD1 */
+				0x1  0x6  0x2  0x0  0x2  0x0    /* ENET5_RXD0_SER5_RXD0 */
+				0x1  0x9  0x2  0x0  0x2  0x0    /* ENET5_RXD1_SER5_RXD1 */
+				0x1  0x5  0x1  0x0  0x2  0x0    /* ENET5_TX_EN_SER5_RTS_B */
+				0x1  0x4  0x2  0x0  0x2  0x0    /* ENET5_RX_DV_SER5_CTS_B */
+				0x1  0x8  0x2  0x0  0x2  0x0>;    /* ENET5_RX_ER_SER5_CD_B */
+		};
+	};
+};
diff --git a/arch/powerpc/boot/dts/p1025rdb_32b.dts b/arch/powerpc/boot/dts/p1025rdb_32b.dts
new file mode 100644
index 0000000..ac5729c
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1025rdb_32b.dts
@@ -0,0 +1,135 @@
+/*
+ * P1025 RDB Device Tree Source (32-bit address map)
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1021si-pre.dtsi"
+/ {
+	model = "fsl,P1025RDB";
+	compatible = "fsl,P1025RDB";
+
+	memory {
+		device_type = "memory";
+	};
+
+	lbc: localbus@ffe05000 {
+		reg = <0 0xffe05000 0 0x1000>;
+
+		/* NOR, NAND Flashes */
+		ranges = <0x0 0x0 0x0 0xef000000 0x01000000
+			  0x1 0x0 0x0 0xff800000 0x00040000>;
+	};
+
+	soc: soc@ffe00000 {
+		ranges = <0x0 0x0 0xffe00000 0x100000>;
+	};
+
+	pci0: pcie@ffe09000 {
+		ranges = <0x2000000 0x0 0xe0000000 0 0xe0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+		reg = <0 0xffe09000 0 0x1000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci1: pcie@ffe0a000 {
+		reg = <0 0xffe0a000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0 0xe0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	qe: qe@ffe80000 {
+		ranges = <0x0 0x0 0xffe80000 0x40000>;
+		reg = <0 0xffe80000 0 0x480>;
+		brg-frequency = <0>;
+		bus-frequency = <0>;
+		status = "disabled"; /* no firmware loaded */
+
+		enet3: ucc@2000 {
+			device_type = "network";
+			compatible = "ucc_geth";
+			rx-clock-name = "clk12";
+			tx-clock-name = "clk9";
+			pio-handle = <&pio1>;
+			phy-handle = <&qe_phy0>;
+			phy-connection-type = "mii";
+		};
+
+		mdio@2120 {
+			qe_phy0: ethernet-phy@0 {
+				interrupt-parent = <&mpic>;
+				interrupts = <4 1 0 0>;
+				reg = <0x6>;
+				device_type = "ethernet-phy";
+			};
+			qe_phy1: ethernet-phy@03 {
+				interrupt-parent = <&mpic>;
+				interrupts = <5 1 0 0>;
+				reg = <0x3>;
+				device_type = "ethernet-phy";
+			};
+			tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		enet4: ucc@2400 {
+			device_type = "network";
+			compatible = "ucc_geth";
+			rx-clock-name = "none";
+			tx-clock-name = "clk13";
+			pio-handle = <&pio2>;
+			phy-handle = <&qe_phy1>;
+			phy-connection-type = "rmii";
+		};
+	};
+};
+
+/include/ "p1025rdb.dtsi"
+/include/ "fsl/p1021si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1025rdb_36b.dts b/arch/powerpc/boot/dts/p1025rdb_36b.dts
new file mode 100644
index 0000000..4ce4bfa
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1025rdb_36b.dts
@@ -0,0 +1,88 @@
+/*
+ * P1025 RDB Device Tree Source (36-bit address map)
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1021si-pre.dtsi"
+/ {
+	model = "fsl,P1025RDB";
+	compatible = "fsl,P1025RDB";
+
+	memory {
+		device_type = "memory";
+	};
+
+	lbc: localbus@fffe05000 {
+		reg = <0xf 0xffe05000 0 0x1000>;
+
+		/* NOR, NAND Flashes */
+		ranges = <0x0 0x0 0xf 0xef000000 0x01000000
+			  0x1 0x0 0xf 0xff800000 0x00040000>;
+	};
+
+	soc: soc@fffe00000 {
+		ranges = <0x0 0xf 0xffe00000 0x100000>;
+	};
+
+	pci0: pcie@fffe09000 {
+		reg = <0xf 0xffe09000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0xe 0x20000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci1: pcie@fffe0a000 {
+		reg = <0xf 0xffe0a000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+};
+
+/include/ "p1025rdb.dtsi"
+/include/ "fsl/p1021si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p2020rdb-pc.dtsi b/arch/powerpc/boot/dts/p2020rdb-pc.dtsi
new file mode 100644
index 0000000..c21d1c7
--- /dev/null
+++ b/arch/powerpc/boot/dts/p2020rdb-pc.dtsi
@@ -0,0 +1,241 @@
+/*
+ * P2020 RDB-PC Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+&lbc {
+	nor@0,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "cfi-flash";
+		reg = <0x0 0x0 0x1000000>;
+		bank-width = <2>;
+		device-width = <1>;
+
+		partition@0 {
+			/* This location must not be altered  */
+			/* 256KB for Vitesse 7385 Switch firmware */
+			reg = <0x0 0x00040000>;
+			label = "NOR Vitesse-7385 Firmware";
+			read-only;
+		};
+
+		partition@40000 {
+			/* 256KB for DTB Image */
+			reg = <0x00040000 0x00040000>;
+			label = "NOR DTB Image";
+		};
+
+		partition@80000 {
+			/* 3.5 MB for Linux Kernel Image */
+			reg = <0x00080000 0x00380000>;
+			label = "NOR Linux Kernel Image";
+		};
+
+		partition@400000 {
+			/* 11MB for JFFS2 based Root file System */
+			reg = <0x00400000 0x00b00000>;
+			label = "NOR JFFS2 Root File System";
+		};
+
+		partition@f00000 {
+			/* This location must not be altered  */
+			/* 512KB for u-boot Bootloader Image */
+			/* 512KB for u-boot Environment Variables */
+			reg = <0x00f00000 0x00100000>;
+			label = "NOR U-Boot Image";
+			read-only;
+		};
+	};
+
+	nand@1,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "fsl,p2020-fcm-nand",
+				 "fsl,elbc-fcm-nand";
+		reg = <0x1 0x0 0x40000>;
+
+		partition@0 {
+			/* This location must not be altered  */
+			/* 1MB for u-boot Bootloader Image */
+			reg = <0x0 0x00100000>;
+			label = "NAND U-Boot Image";
+			read-only;
+		};
+
+		partition@100000 {
+			/* 1MB for DTB Image */
+			reg = <0x00100000 0x00100000>;
+			label = "NAND DTB Image";
+		};
+
+		partition@200000 {
+			/* 4MB for Linux Kernel Image */
+			reg = <0x00200000 0x00400000>;
+			label = "NAND Linux Kernel Image";
+		};
+
+		partition@600000 {
+			/* 4MB for Compressed Root file System Image */
+			reg = <0x00600000 0x00400000>;
+			label = "NAND Compressed RFS Image";
+		};
+
+		partition@a00000 {
+			/* 7MB for JFFS2 based Root file System */
+			reg = <0x00a00000 0x00700000>;
+			label = "NAND JFFS2 Root File System";
+		};
+
+		partition@1100000 {
+			/* 15MB for JFFS2 based Root file System */
+			reg = <0x01100000 0x00f00000>;
+			label = "NAND Writable User area";
+		};
+	};
+
+	L2switch@2,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "vitesse-7385";
+		reg = <0x2 0x0 0x20000>;
+	};
+
+	cpld@3,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "cpld";
+		reg = <0x3 0x0 0x20000>;
+		read-only;
+	};
+};
+
+&soc {
+	i2c@3000 {
+		rtc@68 {
+			compatible = "pericom,pt7c4338";
+			reg = <0x68>;
+		};
+	};
+
+	spi@7000 {
+		flash@0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "spansion,m25p80";
+			reg = <0>;
+			spi-max-frequency = <40000000>;
+
+			partition@0 {
+				/* 512KB for u-boot Bootloader Image */
+				reg = <0x0 0x00080000>;
+				label = "SPI U-Boot Image";
+				read-only;
+			};
+
+			partition@80000 {
+				/* 512KB for DTB Image */
+				reg = <0x00080000 0x00080000>;
+				label = "SPI DTB Image";
+			};
+
+			partition@100000 {
+				/* 4MB for Linux Kernel Image */
+				reg = <0x00100000 0x00400000>;
+				label = "SPI Linux Kernel Image";
+			};
+
+			partition@500000 {
+				/* 4MB for Compressed RFS Image */
+				reg = <0x00500000 0x00400000>;
+				label = "SPI Compressed RFS Image";
+			};
+
+			partition@900000 {
+				/* 7MB for JFFS2 based RFS */
+				reg = <0x00900000 0x00700000>;
+				label = "SPI JFFS2 RFS";
+			};
+		};
+	};
+
+	usb@22000 {
+		phy_type = "ulpi";
+	};
+
+	mdio@24520 {
+		phy0: ethernet-phy@0 {
+			interrupts = <3 1 0 0>;
+			reg = <0x0>;
+			};
+		phy1: ethernet-phy@1 {
+			interrupts = <2 1 0 0>;
+			reg = <0x1>;
+			};
+	};
+
+	mdio@25520 {
+		tbi0: tbi-phy@11 {
+			reg = <0x11>;
+			device_type = "tbi-phy";
+		};
+	};
+
+	mdio@26520 {
+		status = "disabled";
+	};
+
+	ptp_clock@24e00 {
+		fsl,tclk-period = <5>;
+		fsl,tmr-prsc = <200>;
+		fsl,tmr-add = <0xCCCCCCCD>;
+		fsl,tmr-fiper1 = <0x3B9AC9FB>;
+		fsl,tmr-fiper2 = <0x0001869B>;
+		fsl,max-adj = <249999999>;
+	};
+
+	enet0: ethernet@24000 {
+		fixed-link = <1 1 1000 0 0>;
+		phy-connection-type = "rgmii-id";
+	};
+
+	enet1: ethernet@25000 {
+		tbi-handle = <&tbi0>;
+		phy-handle = <&phy0>;
+		phy-connection-type = "sgmii";
+	};
+
+	enet2: ethernet@26000 {
+		phy-handle = <&phy1>;
+		phy-connection-type = "rgmii-id";
+	};
+};
diff --git a/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts b/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts
new file mode 100644
index 0000000..852e5b2
--- /dev/null
+++ b/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts
@@ -0,0 +1,96 @@
+/*
+ * P2020 RDB-PC 32Bit Physical Address Map Device Tree Source
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p2020si-pre.dtsi"
+
+/ {
+	model = "fsl,P2020RDB";
+	compatible = "fsl,P2020RDB-PC";
+
+	memory {
+		device_type = "memory";
+	};
+
+	lbc: localbus@ffe05000 {
+		reg = <0 0xffe05000 0 0x1000>;
+
+		/* NOR and NAND Flashes */
+		ranges = <0x0 0x0 0x0 0xef000000 0x01000000
+			  0x1 0x0 0x0 0xff800000 0x00040000
+			  0x2 0x0 0x0 0xffb00000 0x00020000
+			  0x3 0x0 0x0 0xffa00000 0x00020000>;
+	};
+
+	soc: soc@ffe00000 {
+		ranges = <0x0 0x0 0xffe00000 0x100000>;
+	};
+
+	pci0: pcie@ffe08000 {
+		reg = <0 0xffe08000 0 0x1000>;
+		status = "disabled";
+	};
+
+	pci1: pcie@ffe09000 {
+		reg = <0 0xffe09000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0 0xa0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci2: pcie@ffe0a000 {
+		reg = <0 0xffe0a000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+};
+
+/include/ "p2020rdb-pc.dtsi"
+/include/ "fsl/p2020si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts b/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts
new file mode 100644
index 0000000..b5a56ca
--- /dev/null
+++ b/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts
@@ -0,0 +1,96 @@
+/*
+ * P2020 RDB-PC 36Bit Physical Address Map Device Tree Source
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p2020si-pre.dtsi"
+
+/ {
+	model = "fsl,P2020RDB";
+	compatible = "fsl,P2020RDB-PC";
+
+	memory {
+		device_type = "memory";
+	};
+
+	lbc: localbus@fffe05000 {
+		reg = <0xf 0xffe05000 0 0x1000>;
+
+		/* NOR and NAND Flashes */
+		ranges = <0x0 0x0 0xf 0xef000000 0x01000000
+			  0x1 0x0 0xf 0xff800000 0x00040000
+			  0x2 0x0 0xf 0xffb00000 0x00020000
+			  0x3 0x0 0xf 0xffa00000 0x00020000>;
+	};
+
+	soc: soc@fffe00000 {
+		ranges = <0x0 0xf 0xffe00000 0x100000>;
+	};
+
+	pci0: pcie@fffe08000 {
+		reg = <0xf 0xffe08000 0 0x1000>;
+		status = "disabled";
+	};
+
+	pci1: pcie@fffe09000 {
+		reg = <0xf 0xffe09000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci2: pcie@fffe0a000 {
+		reg = <0xf 0xffe0a000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
+		pcie@0 {
+			ranges = <0x2000000 0x0 0xe0000000
+				  0x2000000 0x0 0xe0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+};
+
+/include/ "p2020rdb-pc.dtsi"
+/include/ "fsl/p2020si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p2020rdb.dts b/arch/powerpc/boot/dts/p2020rdb.dts
index eb8a6aa..153bc76 100644
--- a/arch/powerpc/boot/dts/p2020rdb.dts
+++ b/arch/powerpc/boot/dts/p2020rdb.dts
@@ -34,7 +34,7 @@
 
 		/* NOR and NAND Flashes */
 		ranges = <0x0 0x0 0x0 0xef000000 0x01000000
-			  0x1 0x0 0x0 0xffa00000 0x00040000
+			  0x1 0x0 0x0 0xff800000 0x00040000
 			  0x2 0x0 0x0 0xffb00000 0x00020000>;
 
 		nor@0,0 {
@@ -157,7 +157,7 @@
 				#size-cells = <1>;
 				compatible = "spansion,s25sl12801";
 				reg = <0>;
-				spi-max-frequency = <50000000>;
+				spi-max-frequency = <40000000>;
 
 				partition@0 {
 					/* 512KB for u-boot Bootloader Image */
diff --git a/arch/powerpc/boot/dts/p2041rdb.dts b/arch/powerpc/boot/dts/p2041rdb.dts
index 4f957db..2852139 100644
--- a/arch/powerpc/boot/dts/p2041rdb.dts
+++ b/arch/powerpc/boot/dts/p2041rdb.dts
@@ -135,7 +135,6 @@
 		reg = <0xf 0xfe200000 0 0x1000>;
 		ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0x0 0x20000000
 			  0x01000000 0 0x00000000 0xf 0xf8000000 0x0 0x00010000>;
-		fsl,msi = <&msi0>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
@@ -151,7 +150,6 @@
 		reg = <0xf 0xfe201000 0 0x1000>;
 		ranges = <0x02000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
 			  0x01000000 0x0 0x00000000 0xf 0xf8010000 0x0 0x00010000>;
-		fsl,msi = <&msi1>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
@@ -167,7 +165,6 @@
 		reg = <0xf 0xfe202000 0 0x1000>;
 		ranges = <0x02000000 0 0xe0000000 0xc 0x40000000 0 0x20000000
 			  0x01000000 0 0x00000000 0xf 0xf8020000 0 0x00010000>;
-		fsl,msi = <&msi2>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
diff --git a/arch/powerpc/boot/dts/p3041ds.dts b/arch/powerpc/boot/dts/p3041ds.dts
index f469145..22a215e 100644
--- a/arch/powerpc/boot/dts/p3041ds.dts
+++ b/arch/powerpc/boot/dts/p3041ds.dts
@@ -173,7 +173,6 @@
 		reg = <0xf 0xfe200000 0 0x1000>;
 		ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0x0 0x20000000
 			  0x01000000 0 0x00000000 0xf 0xf8000000 0x0 0x00010000>;
-		fsl,msi = <&msi0>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
@@ -189,7 +188,6 @@
 		reg = <0xf 0xfe201000 0 0x1000>;
 		ranges = <0x02000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
 			  0x01000000 0x0 0x00000000 0xf 0xf8010000 0x0 0x00010000>;
-		fsl,msi = <&msi1>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
@@ -205,7 +203,6 @@
 		reg = <0xf 0xfe202000 0 0x1000>;
 		ranges = <0x02000000 0 0xe0000000 0xc 0x40000000 0 0x20000000
 			  0x01000000 0 0x00000000 0xf 0xf8020000 0 0x00010000>;
-		fsl,msi = <&msi2>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
@@ -221,7 +218,6 @@
 		reg = <0xf 0xfe203000 0 0x1000>;
 		ranges = <0x02000000 0 0xe0000000 0xc 0x60000000 0 0x20000000
 			  0x01000000 0 0x00000000 0xf 0xf8030000 0 0x00010000>;
-		fsl,msi = <&msi2>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
diff --git a/arch/powerpc/boot/dts/p3060qds.dts b/arch/powerpc/boot/dts/p3060qds.dts
index 529042e..9ae875c 100644
--- a/arch/powerpc/boot/dts/p3060qds.dts
+++ b/arch/powerpc/boot/dts/p3060qds.dts
@@ -212,7 +212,6 @@
 		reg = <0xf 0xfe200000 0 0x1000>;
 		ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0x0 0x20000000
 			  0x01000000 0 0x00000000 0xf 0xf8000000 0x0 0x00010000>;
-		fsl,msi = <&msi0>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
@@ -228,7 +227,6 @@
 		reg = <0xf 0xfe201000 0 0x1000>;
 		ranges = <0x02000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
 			  0x01000000 0x0 0x00000000 0xf 0xf8010000 0x0 0x00010000>;
-		fsl,msi = <&msi1>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts
index 6d60e54..3e20460 100644
--- a/arch/powerpc/boot/dts/p4080ds.dts
+++ b/arch/powerpc/boot/dts/p4080ds.dts
@@ -141,7 +141,6 @@
 		reg = <0xf 0xfe200000 0 0x1000>;
 		ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0x0 0x20000000
 			  0x01000000 0 0x00000000 0xf 0xf8000000 0x0 0x00010000>;
-		fsl,msi = <&msi0>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
@@ -157,7 +156,6 @@
 		reg = <0xf 0xfe201000 0 0x1000>;
 		ranges = <0x02000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
 			  0x01000000 0x0 0x00000000 0xf 0xf8010000 0x0 0x00010000>;
-		fsl,msi = <&msi1>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
@@ -173,7 +171,6 @@
 		reg = <0xf 0xfe202000 0 0x1000>;
 		ranges = <0x02000000 0 0xe0000000 0xc 0x40000000 0 0x20000000
 			  0x01000000 0 0x00000000 0xf 0xf8020000 0 0x00010000>;
-		fsl,msi = <&msi2>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
diff --git a/arch/powerpc/boot/dts/p5020ds.dts b/arch/powerpc/boot/dts/p5020ds.dts
index 1c25068..27c07ed 100644
--- a/arch/powerpc/boot/dts/p5020ds.dts
+++ b/arch/powerpc/boot/dts/p5020ds.dts
@@ -173,7 +173,6 @@
 		reg = <0xf 0xfe200000 0 0x1000>;
 		ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0x0 0x20000000
 			  0x01000000 0 0x00000000 0xf 0xf8000000 0x0 0x00010000>;
-		fsl,msi = <&msi0>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
@@ -189,7 +188,6 @@
 		reg = <0xf 0xfe201000 0 0x1000>;
 		ranges = <0x02000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
 			  0x01000000 0x0 0x00000000 0xf 0xf8010000 0x0 0x00010000>;
-		fsl,msi = <&msi1>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
@@ -205,7 +203,6 @@
 		reg = <0xf 0xfe202000 0 0x1000>;
 		ranges = <0x02000000 0 0xe0000000 0xc 0x40000000 0 0x20000000
 			  0x01000000 0 0x00000000 0xf 0xf8020000 0 0x00010000>;
-		fsl,msi = <&msi2>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
@@ -221,7 +218,6 @@
 		reg = <0xf 0xfe203000 0 0x1000>;
 		ranges = <0x02000000 0 0xe0000000 0xc 0x60000000 0 0x20000000
 			  0x01000000 0 0x00000000 0xf 0xf8030000 0 0x00010000>;
-		fsl,msi = <&msi2>;
 		pcie@0 {
 			ranges = <0x02000000 0 0xe0000000
 				  0x02000000 0 0xe0000000
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index f090e6d..6761c74 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -144,6 +144,7 @@
 ksection=.kernel:vmlinux.strip
 isection=.kernel:initrd
 link_address='0x400000'
+make_space=y
 
 case "$platform" in
 pseries)
@@ -210,6 +211,7 @@
     ksection=.kernel:vmlinux.bin
     isection=.kernel:initrd
     link_address=''
+    make_space=n
     pie=
     ;;
 ep88xc|ep405|ep8248e)
@@ -278,17 +280,19 @@
     rm -f $vmz.$$
 fi
 
-# Round the size to next higher MB limit
-round_size=$(((strip_size + 0xfffff) & 0xfff00000))
+if [ "$make_space" = "y" ]; then
+	# Round the size to next higher MB limit
+	round_size=$(((strip_size + 0xfffff) & 0xfff00000))
 
-round_size=0x$(printf "%x" $round_size)
-link_addr=$(printf "%d" $link_address)
+	round_size=0x$(printf "%x" $round_size)
+	link_addr=$(printf "%d" $link_address)
 
-if [ $link_addr -lt $strip_size ]; then
-    echo "INFO: Uncompressed kernel (size 0x$(printf "%x\n" $strip_size))" \
-		"overlaps the address of the wrapper($link_address)"
-    echo "INFO: Fixing the link_address of wrapper to ($round_size)"
-    link_address=$round_size
+	if [ $link_addr -lt $strip_size ]; then
+	    echo "INFO: Uncompressed kernel (size 0x$(printf "%x\n" $strip_size))" \
+			"overlaps the address of the wrapper($link_address)"
+	    echo "INFO: Fixing the link_address of wrapper to ($round_size)"
+	    link_address=$round_size
+	fi
 fi
 
 vmz="$vmz$gzip"
diff --git a/arch/powerpc/configs/85xx/ge_imp3a_defconfig b/arch/powerpc/configs/85xx/ge_imp3a_defconfig
new file mode 100644
index 0000000..f8c51a4
--- /dev/null
+++ b/arch/powerpc/configs/85xx/ge_imp3a_defconfig
@@ -0,0 +1,257 @@
+CONFIG_PPC_85xx=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_PERF_EVENTS=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_GE_IMP3A=y
+CONFIG_QUICC_ENGINE=y
+CONFIG_QE_GPIO=y
+CONFIG_CPM2=y
+CONFIG_HIGHMEM=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_HZ_1000=y
+CONFIG_PREEMPT=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_MISC=m
+CONFIG_MATH_EMULATION=y
+CONFIG_IRQ_ALL_CPUS=y
+CONFIG_FORCE_MAX_ZONEORDER=17
+CONFIG_PCI=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCI_MSI=y
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_LOAD_CIS is not set
+CONFIG_YENTA=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NET_PKTGEN=m
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_MTD=y
+CONFIG_MTD_OF_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_FSL_ELBC=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=131072
+CONFIG_MISC_DEVICES=y
+CONFIG_DS1682=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI=y
+CONFIG_SATA_SIL24=y
+# CONFIG_ATA_SFF is not set
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_NETCONSOLE=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_TUN=m
+# CONFIG_NET_VENDOR_3COM is not set
+CONFIG_FS_ENET=y
+CONFIG_UCC_GETH=y
+CONFIG_GIANFAR=y
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_QE=m
+CONFIG_NVRAM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_CPM=m
+CONFIG_I2C_MPC=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_GE_FPGA=y
+CONFIG_SENSORS_LM90=y
+CONFIG_SENSORS_LM92=y
+CONFIG_WATCHDOG=y
+CONFIG_GEF_WDT=y
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_HID_DRAGONRISE=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_ORTEK=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_USB=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_FSL=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
+CONFIG_USB_OHCI_HCD_PPC_OF_LE=y
+CONFIG_USB_STORAGE=y
+CONFIG_EDAC=y
+CONFIG_EDAC_MM_EDAC=y
+CONFIG_EDAC_MPC85XX=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_INTF_PROC is not set
+CONFIG_RTC_DRV_RX8581=y
+CONFIG_DMADEVICES=y
+CONFIG_FSL_DMA=y
+# CONFIG_NET_DMA is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=850
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_NTFS_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V4=y
+CONFIG_CIFS=m
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC_T10DIF=y
+CONFIG_LIBCRC32C=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_TALITOS=y
diff --git a/arch/powerpc/configs/85xx/p1023rds_defconfig b/arch/powerpc/configs/85xx/p1023rds_defconfig
index c091aaf..f4337ba 100644
--- a/arch/powerpc/configs/85xx/p1023rds_defconfig
+++ b/arch/powerpc/configs/85xx/p1023rds_defconfig
@@ -165,7 +165,7 @@
 CONFIG_DEBUG_INFO=y
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_VIRQ_DEBUG=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_SHA256=y
 CONFIG_CRYPTO_SHA512=y
diff --git a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
index d41857a..da731c2 100644
--- a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
+++ b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
@@ -131,6 +131,7 @@
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MPC=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_GE_FPGA=y
 CONFIG_SENSORS_LM90=y
 CONFIG_SENSORS_LM92=y
 CONFIG_WATCHDOG=y
diff --git a/arch/powerpc/configs/86xx/gef_sbc310_defconfig b/arch/powerpc/configs/86xx/gef_sbc310_defconfig
index 38303ec..2149360 100644
--- a/arch/powerpc/configs/86xx/gef_sbc310_defconfig
+++ b/arch/powerpc/configs/86xx/gef_sbc310_defconfig
@@ -132,6 +132,7 @@
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MPC=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_GE_FPGA=y
 CONFIG_SENSORS_LM90=y
 CONFIG_SENSORS_LM92=y
 CONFIG_WATCHDOG=y
diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
index 9853397..af2e8e1 100644
--- a/arch/powerpc/configs/86xx/gef_sbc610_defconfig
+++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
@@ -183,6 +183,8 @@
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MPC=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_GE_FPGA=y
 CONFIG_SENSORS_LM90=y
 CONFIG_SENSORS_LM92=y
 CONFIG_WATCHDOG=y
diff --git a/arch/powerpc/configs/chroma_defconfig b/arch/powerpc/configs/chroma_defconfig
index acf7fb2..f104ccd 100644
--- a/arch/powerpc/configs/chroma_defconfig
+++ b/arch/powerpc/configs/chroma_defconfig
@@ -279,7 +279,7 @@
 CONFIG_PPC_EMULATED_STATS=y
 CONFIG_XMON=y
 CONFIG_XMON_DEFAULT=y
-CONFIG_VIRQ_DEBUG=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
 CONFIG_PPC_EARLY_DEBUG=y
 CONFIG_KEYS_DEBUG_PROC_KEYS=y
 CONFIG_CRYPTO_NULL=m
diff --git a/arch/powerpc/configs/corenet32_smp_defconfig b/arch/powerpc/configs/corenet32_smp_defconfig
index f8aef20..91db656 100644
--- a/arch/powerpc/configs/corenet32_smp_defconfig
+++ b/arch/powerpc/configs/corenet32_smp_defconfig
@@ -116,6 +116,7 @@
 CONFIG_HW_RANDOM=y
 CONFIG_NVRAM=y
 CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MPC=y
 CONFIG_SPI=y
 CONFIG_SPI_GPIO=y
diff --git a/arch/powerpc/configs/corenet64_smp_defconfig b/arch/powerpc/configs/corenet64_smp_defconfig
index 7ed8d4c..6798343 100644
--- a/arch/powerpc/configs/corenet64_smp_defconfig
+++ b/arch/powerpc/configs/corenet64_smp_defconfig
@@ -71,6 +71,8 @@
 CONFIG_SERIAL_8250_DETECT_IRQ=y
 CONFIG_SERIAL_8250_RSA=y
 CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MPC=y
 # CONFIG_HWMON is not set
 CONFIG_VIDEO_OUTPUT_CONTROL=y
 # CONFIG_HID_SUPPORT is not set
@@ -95,7 +97,7 @@
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
 CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_VIRQ_DEBUG=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_SHA256=y
 CONFIG_CRYPTO_SHA512=y
diff --git a/arch/powerpc/configs/iseries_defconfig b/arch/powerpc/configs/iseries_defconfig
deleted file mode 100644
index 27c46d6..0000000
--- a/arch/powerpc/configs/iseries_defconfig
+++ /dev/null
@@ -1,236 +0,0 @@
-CONFIG_PPC64=y
-CONFIG_SMP=y
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_AUDIT=y
-CONFIG_AUDITSYSCALL=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_COMPAT_BRK is not set
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_PPC_PSERIES is not set
-CONFIG_LPARCFG=y
-CONFIG_PPC_ISERIES=y
-CONFIG_VIODASD=y
-CONFIG_VIOCD=m
-CONFIG_VIOTAPE=m
-# CONFIG_PPC_PMAC is not set
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_IRQ_ALL_CPUS=y
-# CONFIG_MIGRATION is not set
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_XFRM_USER=m
-CONFIG_XFRM_SUB_POLICY=y
-CONFIG_NET_KEY=m
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_NET_IPIP=y
-CONFIG_SYN_COOKIES=y
-CONFIG_INET_AH=m
-CONFIG_INET_ESP=m
-CONFIG_INET_IPCOMP=m
-CONFIG_INET_XFRM_MODE_BEET=m
-# CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_NETLINK_QUEUE=m
-CONFIG_NETFILTER_NETLINK_LOG=m
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_EVENTS=y
-# CONFIG_NF_CT_PROTO_SCTP is not set
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_TPROXY=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_DSCP=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_TPROXY=m
-CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DSCP=m
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_OWNER=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_TIME=m
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_NF_NAT=m
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_NETMAP=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_PROC_DEVICETREE=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=65536
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_SPI_ATTRS=y
-CONFIG_SCSI_FC_ATTRS=y
-CONFIG_SCSI_SAS_LIBSAS=m
-CONFIG_SCSI_IBMVSCSI=m
-CONFIG_MD=y
-CONFIG_BLK_DEV_MD=y
-CONFIG_MD_LINEAR=y
-CONFIG_MD_RAID0=y
-CONFIG_MD_RAID1=y
-CONFIG_MD_RAID10=m
-CONFIG_MD_MULTIPATH=m
-CONFIG_MD_FAULTY=m
-CONFIG_BLK_DEV_DM=y
-CONFIG_DM_CRYPT=m
-CONFIG_DM_SNAPSHOT=m
-CONFIG_DM_MIRROR=m
-CONFIG_DM_ZERO=m
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
-CONFIG_BONDING=m
-CONFIG_TUN=m
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_PCI=y
-CONFIG_PCNET32=y
-CONFIG_E100=y
-CONFIG_ACENIC=m
-CONFIG_E1000=m
-CONFIG_ISERIES_VETH=y
-CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPPOE=m
-CONFIG_NETCONSOLE=y
-CONFIG_NETPOLL_TRAP=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ICOM=m
-# CONFIG_HW_RANDOM is not set
-CONFIG_GEN_RTC=y
-CONFIG_RAW_DRIVER=y
-# CONFIG_HWMON is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT2_FS_SECURITY=y
-CONFIG_EXT2_FS_XIP=y
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
-CONFIG_EXT4_FS=y
-CONFIG_REISERFS_FS=y
-CONFIG_REISERFS_FS_XATTR=y
-CONFIG_REISERFS_FS_POSIX_ACL=y
-CONFIG_REISERFS_FS_SECURITY=y
-CONFIG_JFS_FS=m
-CONFIG_JFS_POSIX_ACL=y
-CONFIG_JFS_SECURITY=y
-CONFIG_XFS_FS=m
-CONFIG_XFS_POSIX_ACL=y
-CONFIG_GFS2_FS=m
-CONFIG_AUTOFS_FS=m
-CONFIG_ISO9660_FS=y
-CONFIG_JOLIET=y
-CONFIG_ZISOFS=y
-CONFIG_UDF_FS=m
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V3_ACL=y
-CONFIG_NFSD_V4=y
-CONFIG_RPCSEC_GSS_SPKM3=m
-CONFIG_CIFS=m
-CONFIG_CIFS_XATTR=y
-CONFIG_CIFS_POSIX=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_DLM=m
-CONFIG_CRC_T10DIF=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_LATENCYTOP=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_DEBUG_STACKOVERFLOW=y
-CONFIG_DEBUG_STACK_USAGE=y
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_TGR192=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_AES=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_TWOFISH=m
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_HW is not set
diff --git a/arch/powerpc/configs/mpc5200_defconfig b/arch/powerpc/configs/mpc5200_defconfig
index 2a1320f..6640a35 100644
--- a/arch/powerpc/configs/mpc5200_defconfig
+++ b/arch/powerpc/configs/mpc5200_defconfig
@@ -1,8 +1,8 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
+CONFIG_SPARSE_IRQ=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
@@ -13,15 +13,12 @@
 CONFIG_PPC_LITE5200=y
 CONFIG_PPC_MEDIA5200=y
 CONFIG_PPC_MPC5200_BUGFIX=y
-CONFIG_PPC_MPC5200_GPIO=y
 CONFIG_PPC_MPC5200_LPBFIFO=m
 # CONFIG_PPC_PMAC is not set
 CONFIG_PPC_BESTCOMM=y
 CONFIG_SIMPLE_GPIO=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
-CONFIG_SPARSE_IRQ=y
-CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -36,23 +33,20 @@
 # CONFIG_IPV6 is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_OF_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_RAM=y
 CONFIG_MTD_ROM=y
 CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_PLATRAM=y
 CONFIG_MTD_UBI=m
 CONFIG_PROC_DEVICETREE=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=32768
-CONFIG_MISC_DEVICES=y
 CONFIG_EEPROM_AT24=y
 CONFIG_SCSI_TGT=y
 CONFIG_BLK_DEV_SD=y
@@ -61,11 +55,10 @@
 CONFIG_PATA_MPC52xx=y
 CONFIG_PATA_PLATFORM=y
 CONFIG_NETDEVICES=y
-CONFIG_LXT_PHY=y
-CONFIG_NET_ETHERNET=y
 CONFIG_FEC_MPC52xx=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+CONFIG_AMD_PHY=y
+CONFIG_LXT_PHY=y
+CONFIG_FIXED_PHY=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
@@ -80,11 +73,17 @@
 CONFIG_SPI_MPC52xx=m
 CONFIG_SPI_MPC52xx_PSC=m
 CONFIG_SPI_SPIDEV=m
+CONFIG_GPIO_SYSFS=y
+CONFIG_SENSORS_LM80=y
+CONFIG_SENSORS_LM87=m
 CONFIG_WATCHDOG=y
+CONFIG_MFD_SM501=m
 CONFIG_DRM=y
 CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_FB=y
+CONFIG_FB_FOREIGN_ENDIAN=y
 CONFIG_FB_RADEON=y
+CONFIG_FB_SM501=m
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
@@ -124,10 +123,11 @@
 CONFIG_NEW_LEDS=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_DS1374=y
+CONFIG_RTC_DRV_PCF8563=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_INOTIFY=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_PROC_KCORE=y
@@ -145,5 +145,4 @@
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index f37a2ab..d6b6df5 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -1,4 +1,5 @@
 CONFIG_PPC_85xx=y
+CONFIG_PHYS_64BIT=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
@@ -116,6 +117,7 @@
 CONFIG_SERIAL_QE=m
 CONFIG_NVRAM=y
 CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_CPM=m
 CONFIG_I2C_MPC=y
 CONFIG_SPI=y
@@ -213,7 +215,7 @@
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
 CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_VIRQ_DEBUG=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_SHA256=y
 CONFIG_CRYPTO_SHA512=y
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index abdcd31..5b0e292 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -1,4 +1,5 @@
 CONFIG_PPC_85xx=y
+CONFIG_PHYS_64BIT=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=8
 CONFIG_EXPERIMENTAL=y
@@ -118,6 +119,7 @@
 CONFIG_SERIAL_QE=m
 CONFIG_NVRAM=y
 CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_CPM=m
 CONFIG_I2C_MPC=y
 CONFIG_SPI=y
@@ -215,7 +217,7 @@
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
 CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_VIRQ_DEBUG=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_SHA256=y
 CONFIG_CRYPTO_SHA512=y
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index 1acf650..c1442a3 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -457,7 +457,7 @@
 CONFIG_FTR_FIXUP_SELFTEST=y
 CONFIG_MSI_BITMAP_SELFTEST=y
 CONFIG_XMON=y
-CONFIG_VIRQ_DEBUG=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
 CONFIG_BOOTX_TEXT=y
 CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_TEST=m
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index 30e7d0d..6608232 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -340,7 +340,7 @@
 CONFIG_MSI_BITMAP_SELFTEST=y
 CONFIG_XMON=y
 CONFIG_XMON_DEFAULT=y
-CONFIG_VIRQ_DEBUG=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
 CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_CCM=m
diff --git a/arch/powerpc/include/asm/abs_addr.h b/arch/powerpc/include/asm/abs_addr.h
index 5ab0b71..9d92ba0 100644
--- a/arch/powerpc/include/asm/abs_addr.h
+++ b/arch/powerpc/include/asm/abs_addr.h
@@ -17,7 +17,6 @@
 #include <asm/types.h>
 #include <asm/page.h>
 #include <asm/prom.h>
-#include <asm/firmware.h>
 
 struct mschunks_map {
         unsigned long num_chunks;
@@ -46,30 +45,12 @@
 
 static inline unsigned long phys_to_abs(unsigned long pa)
 {
-	unsigned long chunk;
-
-	/* This is a no-op on non-iSeries */
-	if (!firmware_has_feature(FW_FEATURE_ISERIES))
-		return pa;
-
-	chunk = addr_to_chunk(pa);
-
-	if (chunk < mschunks_map.num_chunks)
-		chunk = mschunks_map.mapping[chunk];
-
-	return chunk_to_addr(chunk) + (pa & MSCHUNKS_OFFSET_MASK);
+	return pa;
 }
 
 /* Convenience macros */
 #define virt_to_abs(va) phys_to_abs(__pa(va))
 #define abs_to_virt(aa) __va(aa)
 
-/*
- * Converts Virtual Address to Real Address for
- * Legacy iSeries Hypervisor calls
- */
-#define iseries_hv_addr(virtaddr)	\
-	(0x8000000000000000UL | virt_to_abs(virtaddr))
-
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_ABS_ADDR_H */
diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h
index 02e41b5..da29032 100644
--- a/arch/powerpc/include/asm/atomic.h
+++ b/arch/powerpc/include/asm/atomic.h
@@ -5,13 +5,9 @@
  * PowerPC atomic operations
  */
 
-#include <linux/types.h>
-
 #ifdef __KERNEL__
-#include <linux/compiler.h>
-#include <asm/synch.h>
-#include <asm/asm-compat.h>
-#include <asm/system.h>
+#include <linux/types.h>
+#include <asm/cmpxchg.h>
 
 #define ATOMIC_INIT(i)		{ (i) }
 
@@ -212,6 +208,36 @@
 	return t;
 }
 
+/**
+ * atomic_inc_not_zero - increment unless the number is zero
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1, so long as @v is non-zero.
+ * Returns non-zero if @v was non-zero, and zero otherwise.
+ */
+static __inline__ int atomic_inc_not_zero(atomic_t *v)
+{
+	int t1, t2;
+
+	__asm__ __volatile__ (
+	PPC_ATOMIC_ENTRY_BARRIER
+"1:	lwarx	%0,0,%2		# atomic_inc_not_zero\n\
+	cmpwi	0,%0,0\n\
+	beq-	2f\n\
+	addic	%1,%0,1\n"
+	PPC405_ERR77(0,%2)
+"	stwcx.	%1,0,%2\n\
+	bne-	1b\n"
+	PPC_ATOMIC_EXIT_BARRIER
+	"\n\
+2:"
+	: "=&r" (t1), "=&r" (t2)
+	: "r" (&v->counter)
+	: "cc", "xer", "memory");
+
+	return t1;
+}
+#define atomic_inc_not_zero(v) atomic_inc_not_zero((v))
 
 #define atomic_sub_and_test(a, v)	(atomic_sub_return((a), (v)) == 0)
 #define atomic_dec_and_test(v)		(atomic_dec_return((v)) == 0)
@@ -467,7 +493,34 @@
 	return t != u;
 }
 
-#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+/**
+ * atomic_inc64_not_zero - increment unless the number is zero
+ * @v: pointer of type atomic64_t
+ *
+ * Atomically increments @v by 1, so long as @v is non-zero.
+ * Returns non-zero if @v was non-zero, and zero otherwise.
+ */
+static __inline__ long atomic64_inc_not_zero(atomic64_t *v)
+{
+	long t1, t2;
+
+	__asm__ __volatile__ (
+	PPC_ATOMIC_ENTRY_BARRIER
+"1:	ldarx	%0,0,%2		# atomic64_inc_not_zero\n\
+	cmpdi	0,%0,0\n\
+	beq-	2f\n\
+	addic	%1,%0,1\n\
+	stdcx.	%1,0,%2\n\
+	bne-	1b\n"
+	PPC_ATOMIC_EXIT_BARRIER
+	"\n\
+2:"
+	: "=&r" (t1), "=&r" (t2)
+	: "r" (&v->counter)
+	: "cc", "xer", "memory");
+
+	return t1;
+}
 
 #endif /* __powerpc64__ */
 
diff --git a/arch/powerpc/include/asm/auxvec.h b/arch/powerpc/include/asm/auxvec.h
index 19a099b..ce17d2c 100644
--- a/arch/powerpc/include/asm/auxvec.h
+++ b/arch/powerpc/include/asm/auxvec.h
@@ -16,4 +16,6 @@
  */
 #define AT_SYSINFO_EHDR		33
 
+#define AT_VECTOR_SIZE_ARCH 6 /* entries in ARCH_DLINFO */
+
 #endif
diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h
new file mode 100644
index 0000000..ae78225
--- /dev/null
+++ b/arch/powerpc/include/asm/barrier.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
+ */
+#ifndef _ASM_POWERPC_BARRIER_H
+#define _ASM_POWERPC_BARRIER_H
+
+/*
+ * Memory barrier.
+ * The sync instruction guarantees that all memory accesses initiated
+ * by this processor have been performed (with respect to all other
+ * mechanisms that access memory).  The eieio instruction is a barrier
+ * providing an ordering (separately) for (a) cacheable stores and (b)
+ * loads and stores to non-cacheable memory (e.g. I/O devices).
+ *
+ * mb() prevents loads and stores being reordered across this point.
+ * rmb() prevents loads being reordered across this point.
+ * wmb() prevents stores being reordered across this point.
+ * read_barrier_depends() prevents data-dependent loads being reordered
+ *	across this point (nop on PPC).
+ *
+ * *mb() variants without smp_ prefix must order all types of memory
+ * operations with one another. sync is the only instruction sufficient
+ * to do this.
+ *
+ * For the smp_ barriers, ordering is for cacheable memory operations
+ * only. We have to use the sync instruction for smp_mb(), since lwsync
+ * doesn't order loads with respect to previous stores.  Lwsync can be
+ * used for smp_rmb() and smp_wmb().
+ *
+ * However, on CPUs that don't support lwsync, lwsync actually maps to a
+ * heavy-weight sync, so smp_wmb() can be a lighter-weight eieio.
+ */
+#define mb()   __asm__ __volatile__ ("sync" : : : "memory")
+#define rmb()  __asm__ __volatile__ ("sync" : : : "memory")
+#define wmb()  __asm__ __volatile__ ("sync" : : : "memory")
+#define read_barrier_depends()  do { } while(0)
+
+#define set_mb(var, value)	do { var = value; mb(); } while (0)
+
+#ifdef CONFIG_SMP
+
+#ifdef __SUBARCH_HAS_LWSYNC
+#    define SMPWMB      LWSYNC
+#else
+#    define SMPWMB      eieio
+#endif
+
+#define smp_mb()	mb()
+#define smp_rmb()	__asm__ __volatile__ (stringify_in_c(LWSYNC) : : :"memory")
+#define smp_wmb()	__asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory")
+#define smp_read_barrier_depends()	read_barrier_depends()
+#else
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+#define smp_read_barrier_depends()	do { } while(0)
+#endif /* CONFIG_SMP */
+
+/*
+ * This is a barrier which prevents following instructions from being
+ * started until the value of the argument x is known.  For example, if
+ * x is a variable loaded from memory, this prevents following
+ * instructions from being executed until the load has been performed.
+ */
+#define data_barrier(x)	\
+	asm volatile("twi 0,%0,0; isync" : : "r" (x) : "memory");
+
+#endif /* _ASM_POWERPC_BARRIER_H */
diff --git a/arch/powerpc/include/asm/bug.h b/arch/powerpc/include/asm/bug.h
index 065c590..3eb53d7 100644
--- a/arch/powerpc/include/asm/bug.h
+++ b/arch/powerpc/include/asm/bug.h
@@ -126,5 +126,16 @@
 
 #include <asm-generic/bug.h>
 
+#ifndef __ASSEMBLY__
+
+struct pt_regs;
+extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long);
+extern void bad_page_fault(struct pt_regs *, unsigned long, int);
+extern void _exception(int, struct pt_regs *, int, unsigned long);
+extern void die(const char *, struct pt_regs *, long);
+extern void print_backtrace(unsigned long *);
+
+#endif /* !__ASSEMBLY__ */
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_BUG_H */
diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h
index 4b50941..9e495c9 100644
--- a/arch/powerpc/include/asm/cache.h
+++ b/arch/powerpc/include/asm/cache.h
@@ -42,8 +42,24 @@
 #endif /* __powerpc64__ && ! __ASSEMBLY__ */
 
 #if !defined(__ASSEMBLY__)
+
 #define __read_mostly __attribute__((__section__(".data..read_mostly")))
+
+#ifdef CONFIG_6xx
+extern long _get_L2CR(void);
+extern long _get_L3CR(void);
+extern void _set_L2CR(unsigned long);
+extern void _set_L3CR(unsigned long);
+#else
+#define _get_L2CR()	0L
+#define _get_L3CR()	0L
+#define _set_L2CR(val)	do { } while(0)
+#define _set_L3CR(val)	do { } while(0)
 #endif
 
+extern void cacheable_memzero(void *p, unsigned int nb);
+extern void *cacheable_memcpy(void *, const void *, unsigned int);
+
+#endif /* !__ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_CACHE_H */
diff --git a/arch/powerpc/include/asm/cmpxchg.h b/arch/powerpc/include/asm/cmpxchg.h
new file mode 100644
index 0000000..e245aab
--- /dev/null
+++ b/arch/powerpc/include/asm/cmpxchg.h
@@ -0,0 +1,309 @@
+#ifndef _ASM_POWERPC_CMPXCHG_H_
+#define _ASM_POWERPC_CMPXCHG_H_
+
+#ifdef __KERNEL__
+#include <linux/compiler.h>
+#include <asm/synch.h>
+#include <asm/asm-compat.h>
+
+/*
+ * Atomic exchange
+ *
+ * Changes the memory location '*ptr' to be val and returns
+ * the previous value stored there.
+ */
+static __always_inline unsigned long
+__xchg_u32(volatile void *p, unsigned long val)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__(
+	PPC_RELEASE_BARRIER
+"1:	lwarx	%0,0,%2 \n"
+	PPC405_ERR77(0,%2)
+"	stwcx.	%3,0,%2 \n\
+	bne-	1b"
+	PPC_ACQUIRE_BARRIER
+	: "=&r" (prev), "+m" (*(volatile unsigned int *)p)
+	: "r" (p), "r" (val)
+	: "cc", "memory");
+
+	return prev;
+}
+
+/*
+ * Atomic exchange
+ *
+ * Changes the memory location '*ptr' to be val and returns
+ * the previous value stored there.
+ */
+static __always_inline unsigned long
+__xchg_u32_local(volatile void *p, unsigned long val)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%2 \n"
+	PPC405_ERR77(0,%2)
+"	stwcx.	%3,0,%2 \n\
+	bne-	1b"
+	: "=&r" (prev), "+m" (*(volatile unsigned int *)p)
+	: "r" (p), "r" (val)
+	: "cc", "memory");
+
+	return prev;
+}
+
+#ifdef CONFIG_PPC64
+static __always_inline unsigned long
+__xchg_u64(volatile void *p, unsigned long val)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__(
+	PPC_RELEASE_BARRIER
+"1:	ldarx	%0,0,%2 \n"
+	PPC405_ERR77(0,%2)
+"	stdcx.	%3,0,%2 \n\
+	bne-	1b"
+	PPC_ACQUIRE_BARRIER
+	: "=&r" (prev), "+m" (*(volatile unsigned long *)p)
+	: "r" (p), "r" (val)
+	: "cc", "memory");
+
+	return prev;
+}
+
+static __always_inline unsigned long
+__xchg_u64_local(volatile void *p, unsigned long val)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__(
+"1:	ldarx	%0,0,%2 \n"
+	PPC405_ERR77(0,%2)
+"	stdcx.	%3,0,%2 \n\
+	bne-	1b"
+	: "=&r" (prev), "+m" (*(volatile unsigned long *)p)
+	: "r" (p), "r" (val)
+	: "cc", "memory");
+
+	return prev;
+}
+#endif
+
+/*
+ * This function doesn't exist, so you'll get a linker error
+ * if something tries to do an invalid xchg().
+ */
+extern void __xchg_called_with_bad_pointer(void);
+
+static __always_inline unsigned long
+__xchg(volatile void *ptr, unsigned long x, unsigned int size)
+{
+	switch (size) {
+	case 4:
+		return __xchg_u32(ptr, x);
+#ifdef CONFIG_PPC64
+	case 8:
+		return __xchg_u64(ptr, x);
+#endif
+	}
+	__xchg_called_with_bad_pointer();
+	return x;
+}
+
+static __always_inline unsigned long
+__xchg_local(volatile void *ptr, unsigned long x, unsigned int size)
+{
+	switch (size) {
+	case 4:
+		return __xchg_u32_local(ptr, x);
+#ifdef CONFIG_PPC64
+	case 8:
+		return __xchg_u64_local(ptr, x);
+#endif
+	}
+	__xchg_called_with_bad_pointer();
+	return x;
+}
+#define xchg(ptr,x)							     \
+  ({									     \
+     __typeof__(*(ptr)) _x_ = (x);					     \
+     (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
+  })
+
+#define xchg_local(ptr,x)						     \
+  ({									     \
+     __typeof__(*(ptr)) _x_ = (x);					     \
+     (__typeof__(*(ptr))) __xchg_local((ptr),				     \
+     		(unsigned long)_x_, sizeof(*(ptr))); 			     \
+  })
+
+/*
+ * Compare and exchange - if *p == old, set it to new,
+ * and return the old value of *p.
+ */
+#define __HAVE_ARCH_CMPXCHG	1
+
+static __always_inline unsigned long
+__cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
+{
+	unsigned int prev;
+
+	__asm__ __volatile__ (
+	PPC_RELEASE_BARRIER
+"1:	lwarx	%0,0,%2		# __cmpxchg_u32\n\
+	cmpw	0,%0,%3\n\
+	bne-	2f\n"
+	PPC405_ERR77(0,%2)
+"	stwcx.	%4,0,%2\n\
+	bne-	1b"
+	PPC_ACQUIRE_BARRIER
+	"\n\
+2:"
+	: "=&r" (prev), "+m" (*p)
+	: "r" (p), "r" (old), "r" (new)
+	: "cc", "memory");
+
+	return prev;
+}
+
+static __always_inline unsigned long
+__cmpxchg_u32_local(volatile unsigned int *p, unsigned long old,
+			unsigned long new)
+{
+	unsigned int prev;
+
+	__asm__ __volatile__ (
+"1:	lwarx	%0,0,%2		# __cmpxchg_u32\n\
+	cmpw	0,%0,%3\n\
+	bne-	2f\n"
+	PPC405_ERR77(0,%2)
+"	stwcx.	%4,0,%2\n\
+	bne-	1b"
+	"\n\
+2:"
+	: "=&r" (prev), "+m" (*p)
+	: "r" (p), "r" (old), "r" (new)
+	: "cc", "memory");
+
+	return prev;
+}
+
+#ifdef CONFIG_PPC64
+static __always_inline unsigned long
+__cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__ (
+	PPC_RELEASE_BARRIER
+"1:	ldarx	%0,0,%2		# __cmpxchg_u64\n\
+	cmpd	0,%0,%3\n\
+	bne-	2f\n\
+	stdcx.	%4,0,%2\n\
+	bne-	1b"
+	PPC_ACQUIRE_BARRIER
+	"\n\
+2:"
+	: "=&r" (prev), "+m" (*p)
+	: "r" (p), "r" (old), "r" (new)
+	: "cc", "memory");
+
+	return prev;
+}
+
+static __always_inline unsigned long
+__cmpxchg_u64_local(volatile unsigned long *p, unsigned long old,
+			unsigned long new)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__ (
+"1:	ldarx	%0,0,%2		# __cmpxchg_u64\n\
+	cmpd	0,%0,%3\n\
+	bne-	2f\n\
+	stdcx.	%4,0,%2\n\
+	bne-	1b"
+	"\n\
+2:"
+	: "=&r" (prev), "+m" (*p)
+	: "r" (p), "r" (old), "r" (new)
+	: "cc", "memory");
+
+	return prev;
+}
+#endif
+
+/* This function doesn't exist, so you'll get a linker error
+   if something tries to do an invalid cmpxchg().  */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+static __always_inline unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
+	  unsigned int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32(ptr, old, new);
+#ifdef CONFIG_PPC64
+	case 8:
+		return __cmpxchg_u64(ptr, old, new);
+#endif
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+static __always_inline unsigned long
+__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
+	  unsigned int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32_local(ptr, old, new);
+#ifdef CONFIG_PPC64
+	case 8:
+		return __cmpxchg_u64_local(ptr, old, new);
+#endif
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg(ptr, o, n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
+
+
+#define cmpxchg_local(ptr, o, n)					 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,	 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
+
+#ifdef CONFIG_PPC64
+#define cmpxchg64(ptr, o, n)						\
+  ({									\
+	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
+	cmpxchg((ptr), (o), (n));					\
+  })
+#define cmpxchg64_local(ptr, o, n)					\
+  ({									\
+	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
+	cmpxchg_local((ptr), (o), (n));					\
+  })
+#else
+#include <asm-generic/cmpxchg-local.h>
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+#endif
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_CMPXCHG_H_ */
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index ad55a1c..b9219e9 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -390,6 +390,10 @@
 	    CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \
 	    CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
 	    CPU_FTR_DEBUG_LVL_EXC)
+#define CPU_FTRS_E6500	(CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \
+	    CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \
+	    CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
+	    CPU_FTR_DEBUG_LVL_EXC)
 #define CPU_FTRS_GENERIC_32	(CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
 
 /* 64-bit CPUs */
@@ -442,7 +446,7 @@
 
 #ifdef __powerpc64__
 #ifdef CONFIG_PPC_BOOK3E
-#define CPU_FTRS_POSSIBLE	(CPU_FTRS_E5500 | CPU_FTRS_A2)
+#define CPU_FTRS_POSSIBLE	(CPU_FTRS_E6500 | CPU_FTRS_E5500 | CPU_FTRS_A2)
 #else
 #define CPU_FTRS_POSSIBLE	\
 	    (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 |	\
@@ -483,7 +487,7 @@
 #endif
 #ifdef CONFIG_E500
 	    CPU_FTRS_E500 | CPU_FTRS_E500_2 | CPU_FTRS_E500MC |
-	    CPU_FTRS_E5500 |
+	    CPU_FTRS_E5500 | CPU_FTRS_E6500 |
 #endif
 	    0,
 };
@@ -491,7 +495,7 @@
 
 #ifdef __powerpc64__
 #ifdef CONFIG_PPC_BOOK3E
-#define CPU_FTRS_ALWAYS		(CPU_FTRS_E5500 & CPU_FTRS_A2)
+#define CPU_FTRS_ALWAYS		(CPU_FTRS_E6500 & CPU_FTRS_E5500 & CPU_FTRS_A2)
 #else
 #define CPU_FTRS_ALWAYS		\
 	    (CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 &	\
@@ -528,7 +532,7 @@
 #endif
 #ifdef CONFIG_E500
 	    CPU_FTRS_E500 & CPU_FTRS_E500_2 & CPU_FTRS_E500MC &
-	    CPU_FTRS_E5500 &
+	    CPU_FTRS_E5500 & CPU_FTRS_E6500 &
 #endif
 	    CPU_FTRS_POSSIBLE,
 };
diff --git a/arch/powerpc/include/asm/debug.h b/arch/powerpc/include/asm/debug.h
new file mode 100644
index 0000000..716d2f0
--- /dev/null
+++ b/arch/powerpc/include/asm/debug.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
+ */
+#ifndef _ASM_POWERPC_DEBUG_H
+#define _ASM_POWERPC_DEBUG_H
+
+struct pt_regs;
+
+extern struct dentry *powerpc_debugfs_root;
+
+#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
+
+extern int (*__debugger)(struct pt_regs *regs);
+extern int (*__debugger_ipi)(struct pt_regs *regs);
+extern int (*__debugger_bpt)(struct pt_regs *regs);
+extern int (*__debugger_sstep)(struct pt_regs *regs);
+extern int (*__debugger_iabr_match)(struct pt_regs *regs);
+extern int (*__debugger_dabr_match)(struct pt_regs *regs);
+extern int (*__debugger_fault_handler)(struct pt_regs *regs);
+
+#define DEBUGGER_BOILERPLATE(__NAME) \
+static inline int __NAME(struct pt_regs *regs) \
+{ \
+	if (unlikely(__ ## __NAME)) \
+		return __ ## __NAME(regs); \
+	return 0; \
+}
+
+DEBUGGER_BOILERPLATE(debugger)
+DEBUGGER_BOILERPLATE(debugger_ipi)
+DEBUGGER_BOILERPLATE(debugger_bpt)
+DEBUGGER_BOILERPLATE(debugger_sstep)
+DEBUGGER_BOILERPLATE(debugger_iabr_match)
+DEBUGGER_BOILERPLATE(debugger_dabr_match)
+DEBUGGER_BOILERPLATE(debugger_fault_handler)
+
+#else
+static inline int debugger(struct pt_regs *regs) { return 0; }
+static inline int debugger_ipi(struct pt_regs *regs) { return 0; }
+static inline int debugger_bpt(struct pt_regs *regs) { return 0; }
+static inline int debugger_sstep(struct pt_regs *regs) { return 0; }
+static inline int debugger_iabr_match(struct pt_regs *regs) { return 0; }
+static inline int debugger_dabr_match(struct pt_regs *regs) { return 0; }
+static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; }
+#endif
+
+extern int set_dabr(unsigned long dabr);
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+extern void do_send_trap(struct pt_regs *regs, unsigned long address,
+			 unsigned long error_code, int signal_code, int brkpt);
+#else
+extern void do_dabr(struct pt_regs *regs, unsigned long address,
+		    unsigned long error_code);
+#endif
+
+#endif /* _ASM_POWERPC_DEBUG_H */
diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h
index d57c08a..63d5ca4 100644
--- a/arch/powerpc/include/asm/device.h
+++ b/arch/powerpc/include/asm/device.h
@@ -31,6 +31,9 @@
 #ifdef CONFIG_SWIOTLB
 	dma_addr_t		max_direct_dma_addr;
 #endif
+#ifdef CONFIG_EEH
+	struct eeh_dev		*edev;
+#endif
 };
 
 struct pdev_archdata {
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h
index dd70fac..62678e3 100644
--- a/arch/powerpc/include/asm/dma-mapping.h
+++ b/arch/powerpc/include/asm/dma-mapping.h
@@ -22,9 +22,11 @@
 
 /* Some dma direct funcs must be visible for use in other dma_ops */
 extern void *dma_direct_alloc_coherent(struct device *dev, size_t size,
-				       dma_addr_t *dma_handle, gfp_t flag);
+				       dma_addr_t *dma_handle, gfp_t flag,
+				       struct dma_attrs *attrs);
 extern void dma_direct_free_coherent(struct device *dev, size_t size,
-				     void *vaddr, dma_addr_t dma_handle);
+				     void *vaddr, dma_addr_t dma_handle,
+				     struct dma_attrs *attrs);
 
 
 #ifdef CONFIG_NOT_COHERENT_CACHE
@@ -130,23 +132,29 @@
 
 extern int dma_set_mask(struct device *dev, u64 dma_mask);
 
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-				       dma_addr_t *dma_handle, gfp_t flag)
+#define dma_alloc_coherent(d,s,h,f)	dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+				    dma_addr_t *dma_handle, gfp_t flag,
+				    struct dma_attrs *attrs)
 {
 	struct dma_map_ops *dma_ops = get_dma_ops(dev);
 	void *cpu_addr;
 
 	BUG_ON(!dma_ops);
 
-	cpu_addr = dma_ops->alloc_coherent(dev, size, dma_handle, flag);
+	cpu_addr = dma_ops->alloc(dev, size, dma_handle, flag, attrs);
 
 	debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr);
 
 	return cpu_addr;
 }
 
-static inline void dma_free_coherent(struct device *dev, size_t size,
-				     void *cpu_addr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+				  void *cpu_addr, dma_addr_t dma_handle,
+				  struct dma_attrs *attrs)
 {
 	struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
@@ -154,7 +162,7 @@
 
 	debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
 
-	dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
+	dma_ops->free(dev, size, cpu_addr, dma_handle, attrs);
 }
 
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
diff --git a/arch/powerpc/include/asm/dma.h b/arch/powerpc/include/asm/dma.h
index a7e06e2..f6813e9 100644
--- a/arch/powerpc/include/asm/dma.h
+++ b/arch/powerpc/include/asm/dma.h
@@ -24,7 +24,6 @@
 
 #include <asm/io.h>
 #include <linux/spinlock.h>
-#include <asm/system.h>
 
 #ifndef MAX_DMA_CHANNELS
 #define MAX_DMA_CHANNELS	8
@@ -34,8 +33,6 @@
 /* Doesn't really apply... */
 #define MAX_DMA_ADDRESS		(~0UL)
 
-#if !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI)
-
 #ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
 #define dma_outb	outb_p
 #else
@@ -354,7 +351,5 @@
 #define isa_dma_bridge_buggy	(0)
 #endif
 
-#endif	/* !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) */
-
 #endif /* __KERNEL__ */
 #endif	/* _ASM_POWERPC_DMA_H */
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 66ea9b8..d60f998 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -1,6 +1,6 @@
 /*
- * eeh.h
  * Copyright (C) 2001  Dave Engebretsen & Todd Inglett IBM Corporation.
+ * Copyright 2001-2012 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
@@ -31,44 +31,105 @@
 
 #ifdef CONFIG_EEH
 
+/*
+ * The struct is used to trace EEH state for the associated
+ * PCI device node or PCI device. In future, it might
+ * represent PE as well so that the EEH device to form
+ * another tree except the currently existing tree of PCI
+ * buses and PCI devices
+ */
+#define EEH_MODE_SUPPORTED	(1<<0)	/* EEH supported on the device	*/
+#define EEH_MODE_NOCHECK	(1<<1)	/* EEH check should be skipped	*/
+#define EEH_MODE_ISOLATED	(1<<2)	/* The device has been isolated	*/
+#define EEH_MODE_RECOVERING	(1<<3)	/* Recovering the device	*/
+#define EEH_MODE_IRQ_DISABLED	(1<<4)	/* Interrupt disabled		*/
+
+struct eeh_dev {
+	int mode;			/* EEH mode			*/
+	int class_code;			/* Class code of the device	*/
+	int config_addr;		/* Config address		*/
+	int pe_config_addr;		/* PE config address		*/
+	int check_count;		/* Times of ignored error	*/
+	int freeze_count;		/* Times of froze up		*/
+	int false_positives;		/* Times of reported #ff's	*/
+	u32 config_space[16];		/* Saved PCI config space	*/
+	struct pci_controller *phb;	/* Associated PHB		*/
+	struct device_node *dn;		/* Associated device node	*/
+	struct pci_dev *pdev;		/* Associated PCI device	*/
+};
+
+static inline struct device_node *eeh_dev_to_of_node(struct eeh_dev *edev)
+{
+	return edev->dn;
+}
+
+static inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev)
+{
+	return edev->pdev;
+}
+
+/*
+ * The struct is used to trace the registered EEH operation
+ * callback functions. Actually, those operation callback
+ * functions are heavily platform dependent. That means the
+ * platform should register its own EEH operation callback
+ * functions before any EEH further operations.
+ */
+#define EEH_OPT_DISABLE		0	/* EEH disable	*/
+#define EEH_OPT_ENABLE		1	/* EEH enable	*/
+#define EEH_OPT_THAW_MMIO	2	/* MMIO enable	*/
+#define EEH_OPT_THAW_DMA	3	/* DMA enable	*/
+#define EEH_STATE_UNAVAILABLE	(1 << 0)	/* State unavailable	*/
+#define EEH_STATE_NOT_SUPPORT	(1 << 1)	/* EEH not supported	*/
+#define EEH_STATE_RESET_ACTIVE	(1 << 2)	/* Active reset		*/
+#define EEH_STATE_MMIO_ACTIVE	(1 << 3)	/* Active MMIO		*/
+#define EEH_STATE_DMA_ACTIVE	(1 << 4)	/* Active DMA		*/
+#define EEH_STATE_MMIO_ENABLED	(1 << 5)	/* MMIO enabled		*/
+#define EEH_STATE_DMA_ENABLED	(1 << 6)	/* DMA enabled		*/
+#define EEH_RESET_DEACTIVATE	0	/* Deactivate the PE reset	*/
+#define EEH_RESET_HOT		1	/* Hot reset			*/
+#define EEH_RESET_FUNDAMENTAL	3	/* Fundamental reset		*/
+#define EEH_LOG_TEMP		1	/* EEH temporary error log	*/
+#define EEH_LOG_PERM		2	/* EEH permanent error log	*/
+
+struct eeh_ops {
+	char *name;
+	int (*init)(void);
+	int (*set_option)(struct device_node *dn, int option);
+	int (*get_pe_addr)(struct device_node *dn);
+	int (*get_state)(struct device_node *dn, int *state);
+	int (*reset)(struct device_node *dn, int option);
+	int (*wait_state)(struct device_node *dn, int max_wait);
+	int (*get_log)(struct device_node *dn, int severity, char *drv_log, unsigned long len);
+	int (*configure_bridge)(struct device_node *dn);
+	int (*read_config)(struct device_node *dn, int where, int size, u32 *val);
+	int (*write_config)(struct device_node *dn, int where, int size, u32 val);
+};
+
+extern struct eeh_ops *eeh_ops;
 extern int eeh_subsystem_enabled;
 
-/* Values for eeh_mode bits in device_node */
-#define EEH_MODE_SUPPORTED     (1<<0)
-#define EEH_MODE_NOCHECK       (1<<1)
-#define EEH_MODE_ISOLATED      (1<<2)
-#define EEH_MODE_RECOVERING    (1<<3)
-#define EEH_MODE_IRQ_DISABLED  (1<<4)
-
-/* Max number of EEH freezes allowed before we consider the device
- * to be permanently disabled. */
+/*
+ * Max number of EEH freezes allowed before we consider the device
+ * to be permanently disabled.
+ */
 #define EEH_MAX_ALLOWED_FREEZES 5
 
+void * __devinit eeh_dev_init(struct device_node *dn, void *data);
+void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb);
+void __init eeh_dev_phb_init(void);
 void __init eeh_init(void);
+#ifdef CONFIG_PPC_PSERIES
+int __init eeh_pseries_init(void);
+#endif
+int __init eeh_ops_register(struct eeh_ops *ops);
+int __exit eeh_ops_unregister(const char *name);
 unsigned long eeh_check_failure(const volatile void __iomem *token,
 				unsigned long val);
 int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev);
 void __init pci_addr_cache_build(void);
-
-/**
- * eeh_add_device_early
- * eeh_add_device_late
- *
- * Perform eeh initialization for devices added after boot.
- * Call eeh_add_device_early before doing any i/o to the
- * device (including config space i/o).  Call eeh_add_device_late
- * to finish the eeh setup for this device.
- */
 void eeh_add_device_tree_early(struct device_node *);
 void eeh_add_device_tree_late(struct pci_bus *);
-
-/**
- * eeh_remove_device_recursive - undo EEH for device & children.
- * @dev: pci device to be removed
- *
- * As above, this removes the device; it also removes child
- * pci devices as well.
- */
 void eeh_remove_bus_device(struct pci_dev *);
 
 /**
@@ -87,8 +148,25 @@
 #define EEH_IO_ERROR_VALUE(size)	(~0U >> ((4 - (size)) * 8))
 
 #else /* !CONFIG_EEH */
+
+static inline void *eeh_dev_init(struct device_node *dn, void *data)
+{
+	return NULL;
+}
+
+static inline void eeh_dev_phb_init_dynamic(struct pci_controller *phb) { }
+
+static inline void eeh_dev_phb_init(void) { }
+
 static inline void eeh_init(void) { }
 
+#ifdef CONFIG_PPC_PSERIES
+static inline int eeh_pseries_init(void)
+{
+	return 0;
+}
+#endif /* CONFIG_PPC_PSERIES */
+
 static inline unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val)
 {
 	return val;
diff --git a/arch/powerpc/include/asm/eeh_event.h b/arch/powerpc/include/asm/eeh_event.h
index cc3cb04..c68b012 100644
--- a/arch/powerpc/include/asm/eeh_event.h
+++ b/arch/powerpc/include/asm/eeh_event.h
@@ -1,6 +1,4 @@
 /*
- *	eeh_event.h
- *
  * 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
@@ -22,32 +20,19 @@
 #define ASM_POWERPC_EEH_EVENT_H
 #ifdef __KERNEL__
 
-/** EEH event -- structure holding pci controller data that describes
- *  a change in the isolation status of a PCI slot.  A pointer
- *  to this struct is passed as the data pointer in a notify callback.
+/*
+ * structure holding pci controller data that describes a
+ * change in the isolation status of a PCI slot.  A pointer
+ * to this struct is passed as the data pointer in a notify
+ * callback.
  */
 struct eeh_event {
-	struct list_head     list;
-	struct device_node 	*dn;   /* struct device node */
-	struct pci_dev       *dev;  /* affected device */
+	struct list_head	list;	/* to form event queue	*/
+	struct eeh_dev		*edev;	/* EEH device		*/
 };
 
-/**
- * eeh_send_failure_event - generate a PCI error event
- * @dev pci device
- *
- * This routine builds a PCI error event which will be delivered
- * to all listeners on the eeh_notifier_chain.
- *
- * This routine can be called within an interrupt context;
- * the actual event will be delivered in a normal context
- * (from a workqueue).
- */
-int eeh_send_failure_event (struct device_node *dn,
-                            struct pci_dev *dev);
-
-/* Main recovery function */
-struct pci_dn * handle_eeh_events (struct eeh_event *);
+int eeh_send_failure_event(struct eeh_dev *edev);
+struct eeh_dev *handle_eeh_events(struct eeh_event *);
 
 #endif /* __KERNEL__ */
 #endif /* ASM_POWERPC_EEH_EVENT_H */
diff --git a/arch/powerpc/include/asm/epapr_hcalls.h b/arch/powerpc/include/asm/epapr_hcalls.h
index f3b0c2c..976835d 100644
--- a/arch/powerpc/include/asm/epapr_hcalls.h
+++ b/arch/powerpc/include/asm/epapr_hcalls.h
@@ -134,10 +134,15 @@
  * whether they will be clobbered.
  *
  * Note that r11 can be used as an output parameter.
+ *
+ * The "memory" clobber is only necessary for hcalls where the Hypervisor
+ * will read or write guest memory. However, we add it to all hcalls because
+ * the impact is minimal, and we want to ensure that it's present for the
+ * hcalls that need it.
 */
 
 /* List of common clobbered registers.  Do not use this macro. */
-#define EV_HCALL_CLOBBERS "r0", "r12", "xer", "ctr", "lr", "cc"
+#define EV_HCALL_CLOBBERS "r0", "r12", "xer", "ctr", "lr", "cc", "memory"
 
 #define EV_HCALL_CLOBBERS8 EV_HCALL_CLOBBERS
 #define EV_HCALL_CLOBBERS7 EV_HCALL_CLOBBERS8, "r10"
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 8057f4f..548da3a 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -232,23 +232,30 @@
 	EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common,	\
 				 EXC_HV, KVMTEST, vec)
 
-#define __SOFTEN_TEST(h)						\
+/* This associate vector numbers with bits in paca->irq_happened */
+#define SOFTEN_VALUE_0x500	PACA_IRQ_EE
+#define SOFTEN_VALUE_0x502	PACA_IRQ_EE
+#define SOFTEN_VALUE_0x900	PACA_IRQ_DEC
+#define SOFTEN_VALUE_0x982	PACA_IRQ_DEC
+
+#define __SOFTEN_TEST(h, vec)						\
 	lbz	r10,PACASOFTIRQEN(r13);					\
 	cmpwi	r10,0;							\
+	li	r10,SOFTEN_VALUE_##vec;					\
 	beq	masked_##h##interrupt
-#define _SOFTEN_TEST(h)	__SOFTEN_TEST(h)
+#define _SOFTEN_TEST(h, vec)	__SOFTEN_TEST(h, vec)
 
 #define SOFTEN_TEST_PR(vec)						\
 	KVMTEST_PR(vec);						\
-	_SOFTEN_TEST(EXC_STD)
+	_SOFTEN_TEST(EXC_STD, vec)
 
 #define SOFTEN_TEST_HV(vec)						\
 	KVMTEST(vec);							\
-	_SOFTEN_TEST(EXC_HV)
+	_SOFTEN_TEST(EXC_HV, vec)
 
 #define SOFTEN_TEST_HV_201(vec)						\
 	KVMTEST(vec);							\
-	_SOFTEN_TEST(EXC_STD)
+	_SOFTEN_TEST(EXC_STD, vec)
 
 #define __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra)		\
 	HMT_MEDIUM;							\
@@ -272,73 +279,55 @@
 	_MASKABLE_EXCEPTION_PSERIES(vec, label,				\
 				    EXC_HV, SOFTEN_TEST_HV)
 
-#ifdef CONFIG_PPC_ISERIES
-#define DISABLE_INTS				\
-	li	r11,0;				\
-	stb	r11,PACASOFTIRQEN(r13);		\
-BEGIN_FW_FTR_SECTION;				\
-	stb	r11,PACAHARDIRQEN(r13);		\
-END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES);	\
-	TRACE_DISABLE_INTS;			\
-BEGIN_FW_FTR_SECTION;				\
-	mfmsr	r10;				\
-	ori	r10,r10,MSR_EE;			\
-	mtmsrd	r10,1;				\
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#else
-#define DISABLE_INTS				\
-	li	r11,0;				\
-	stb	r11,PACASOFTIRQEN(r13);		\
-	stb	r11,PACAHARDIRQEN(r13);		\
-	TRACE_DISABLE_INTS
-#endif /* CONFIG_PPC_ISERIES */
+/*
+ * Our exception common code can be passed various "additions"
+ * to specify the behaviour of interrupts, whether to kick the
+ * runlatch, etc...
+ */
 
+/* Exception addition: Hard disable interrupts */
+#define DISABLE_INTS	SOFT_DISABLE_INTS(r10,r11)
+
+/* Exception addition: Keep interrupt state */
 #define ENABLE_INTS				\
+	ld	r11,PACAKMSR(r13);		\
 	ld	r12,_MSR(r1);			\
-	mfmsr	r11;				\
 	rlwimi	r11,r12,0,MSR_EE;		\
 	mtmsrd	r11,1
 
-#define STD_EXCEPTION_COMMON(trap, label, hdlr)		\
-	.align	7;					\
-	.globl label##_common;				\
-label##_common:						\
-	EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN);	\
-	DISABLE_INTS;					\
-	bl	.save_nvgprs;				\
-	addi	r3,r1,STACK_FRAME_OVERHEAD;		\
-	bl	hdlr;					\
-	b	.ret_from_except
+#define ADD_NVGPRS				\
+	bl	.save_nvgprs
+
+#define RUNLATCH_ON				\
+BEGIN_FTR_SECTION				\
+	clrrdi	r3,r1,THREAD_SHIFT;		\
+	ld	r4,TI_LOCAL_FLAGS(r3);		\
+	andi.	r0,r4,_TLF_RUNLATCH;		\
+	beql	ppc64_runlatch_on_trampoline;	\
+END_FTR_SECTION_IFSET(CPU_FTR_CTRL)
+
+#define EXCEPTION_COMMON(trap, label, hdlr, ret, additions)	\
+	.align	7;						\
+	.globl label##_common;					\
+label##_common:							\
+	EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN);		\
+	additions;						\
+	addi	r3,r1,STACK_FRAME_OVERHEAD;			\
+	bl	hdlr;						\
+	b	ret
+
+#define STD_EXCEPTION_COMMON(trap, label, hdlr)			\
+	EXCEPTION_COMMON(trap, label, hdlr, ret_from_except,	\
+			 ADD_NVGPRS;DISABLE_INTS)
 
 /*
  * Like STD_EXCEPTION_COMMON, but for exceptions that can occur
- * in the idle task and therefore need the special idle handling.
+ * in the idle task and therefore need the special idle handling
+ * (finish nap and runlatch)
  */
-#define STD_EXCEPTION_COMMON_IDLE(trap, label, hdlr)	\
-	.align	7;					\
-	.globl label##_common;				\
-label##_common:						\
-	EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN);	\
-	FINISH_NAP;					\
-	DISABLE_INTS;					\
-	bl	.save_nvgprs;				\
-	addi	r3,r1,STACK_FRAME_OVERHEAD;		\
-	bl	hdlr;					\
-	b	.ret_from_except
-
-#define STD_EXCEPTION_COMMON_LITE(trap, label, hdlr)	\
-	.align	7;					\
-	.globl label##_common;				\
-label##_common:						\
-	EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN);	\
-	FINISH_NAP;					\
-	DISABLE_INTS;					\
-BEGIN_FTR_SECTION					\
-	bl	.ppc64_runlatch_on;			\
-END_FTR_SECTION_IFSET(CPU_FTR_CTRL)			\
-	addi	r3,r1,STACK_FRAME_OVERHEAD;		\
-	bl	hdlr;					\
-	b	.ret_from_except_lite
+#define STD_EXCEPTION_COMMON_ASYNC(trap, label, hdlr)		  \
+	EXCEPTION_COMMON(trap, label, hdlr, ret_from_except_lite, \
+			 FINISH_NAP;RUNLATCH_ON;DISABLE_INTS)
 
 /*
  * When the idle code in power4_idle puts the CPU into NAP mode,
diff --git a/arch/powerpc/include/asm/exec.h b/arch/powerpc/include/asm/exec.h
new file mode 100644
index 0000000..8196e9c
--- /dev/null
+++ b/arch/powerpc/include/asm/exec.h
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
+ */
+#ifndef _ASM_POWERPC_EXEC_H
+#define _ASM_POWERPC_EXEC_H
+
+extern unsigned long arch_align_stack(unsigned long sp);
+
+#endif /* _ASM_POWERPC_EXEC_H */
diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h
new file mode 100644
index 0000000..88dbf96
--- /dev/null
+++ b/arch/powerpc/include/asm/fadump.h
@@ -0,0 +1,218 @@
+/*
+ * Firmware Assisted dump header file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright 2011 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#ifndef __PPC64_FA_DUMP_H__
+#define __PPC64_FA_DUMP_H__
+
+#ifdef CONFIG_FA_DUMP
+
+/*
+ * The RMA region will be saved for later dumping when kernel crashes.
+ * RMA is Real Mode Area, the first block of logical memory address owned
+ * by logical partition, containing the storage that may be accessed with
+ * translate off.
+ */
+#define RMA_START	0x0
+#define RMA_END		(ppc64_rma_size)
+
+/*
+ * On some Power systems where RMO is 128MB, it still requires minimum of
+ * 256MB for kernel to boot successfully. When kdump infrastructure is
+ * configured to save vmcore over network, we run into OOM issue while
+ * loading modules related to network setup. Hence we need aditional 64M
+ * of memory to avoid OOM issue.
+ */
+#define MIN_BOOT_MEM	(((RMA_END < (0x1UL << 28)) ? (0x1UL << 28) : RMA_END) \
+			+ (0x1UL << 26))
+
+#define memblock_num_regions(memblock_type)	(memblock.memblock_type.cnt)
+
+#ifndef ELF_CORE_EFLAGS
+#define ELF_CORE_EFLAGS 0
+#endif
+
+/* Firmware provided dump sections */
+#define FADUMP_CPU_STATE_DATA	0x0001
+#define FADUMP_HPTE_REGION	0x0002
+#define FADUMP_REAL_MODE_REGION	0x0011
+
+/* Dump request flag */
+#define FADUMP_REQUEST_FLAG	0x00000001
+
+/* FAD commands */
+#define FADUMP_REGISTER		1
+#define FADUMP_UNREGISTER	2
+#define FADUMP_INVALIDATE	3
+
+/* Dump status flag */
+#define FADUMP_ERROR_FLAG	0x2000
+
+#define FADUMP_CPU_ID_MASK	((1UL << 32) - 1)
+
+#define CPU_UNKNOWN		(~((u32)0))
+
+/* Utility macros */
+#define SKIP_TO_NEXT_CPU(reg_entry)			\
+({							\
+	while (reg_entry->reg_id != REG_ID("CPUEND"))	\
+		reg_entry++;				\
+	reg_entry++;					\
+})
+
+/* Kernel Dump section info */
+struct fadump_section {
+	u32	request_flag;
+	u16	source_data_type;
+	u16	error_flags;
+	u64	source_address;
+	u64	source_len;
+	u64	bytes_dumped;
+	u64	destination_address;
+};
+
+/* ibm,configure-kernel-dump header. */
+struct fadump_section_header {
+	u32	dump_format_version;
+	u16	dump_num_sections;
+	u16	dump_status_flag;
+	u32	offset_first_dump_section;
+
+	/* Fields for disk dump option. */
+	u32	dd_block_size;
+	u64	dd_block_offset;
+	u64	dd_num_blocks;
+	u32	dd_offset_disk_path;
+
+	/* Maximum time allowed to prevent an automatic dump-reboot. */
+	u32	max_time_auto;
+};
+
+/*
+ * Firmware Assisted dump memory structure. This structure is required for
+ * registering future kernel dump with power firmware through rtas call.
+ *
+ * No disk dump option. Hence disk dump path string section is not included.
+ */
+struct fadump_mem_struct {
+	struct fadump_section_header	header;
+
+	/* Kernel dump sections */
+	struct fadump_section		cpu_state_data;
+	struct fadump_section		hpte_region;
+	struct fadump_section		rmr_region;
+};
+
+/* Firmware-assisted dump configuration details. */
+struct fw_dump {
+	unsigned long	cpu_state_data_size;
+	unsigned long	hpte_region_size;
+	unsigned long	boot_memory_size;
+	unsigned long	reserve_dump_area_start;
+	unsigned long	reserve_dump_area_size;
+	/* cmd line option during boot */
+	unsigned long	reserve_bootvar;
+
+	unsigned long	fadumphdr_addr;
+	unsigned long	cpu_notes_buf;
+	unsigned long	cpu_notes_buf_size;
+
+	int		ibm_configure_kernel_dump;
+
+	unsigned long	fadump_enabled:1;
+	unsigned long	fadump_supported:1;
+	unsigned long	dump_active:1;
+	unsigned long	dump_registered:1;
+};
+
+/*
+ * Copy the ascii values for first 8 characters from a string into u64
+ * variable at their respective indexes.
+ * e.g.
+ *  The string "FADMPINF" will be converted into 0x4641444d50494e46
+ */
+static inline u64 str_to_u64(const char *str)
+{
+	u64 val = 0;
+	int i;
+
+	for (i = 0; i < sizeof(val); i++)
+		val = (*str) ? (val << 8) | *str++ : val << 8;
+	return val;
+}
+#define STR_TO_HEX(x)	str_to_u64(x)
+#define REG_ID(x)	str_to_u64(x)
+
+#define FADUMP_CRASH_INFO_MAGIC		STR_TO_HEX("FADMPINF")
+#define REGSAVE_AREA_MAGIC		STR_TO_HEX("REGSAVE")
+
+/* The firmware-assisted dump format.
+ *
+ * The register save area is an area in the partition's memory used to preserve
+ * the register contents (CPU state data) for the active CPUs during a firmware
+ * assisted dump. The dump format contains register save area header followed
+ * by register entries. Each list of registers for a CPU starts with
+ * "CPUSTRT" and ends with "CPUEND".
+ */
+
+/* Register save area header. */
+struct fadump_reg_save_area_header {
+	u64		magic_number;
+	u32		version;
+	u32		num_cpu_offset;
+};
+
+/* Register entry. */
+struct fadump_reg_entry {
+	u64		reg_id;
+	u64		reg_value;
+};
+
+/* fadump crash info structure */
+struct fadump_crash_info_header {
+	u64		magic_number;
+	u64		elfcorehdr_addr;
+	u32		crashing_cpu;
+	struct pt_regs	regs;
+	struct cpumask	cpu_online_mask;
+};
+
+/* Crash memory ranges */
+#define INIT_CRASHMEM_RANGES	(INIT_MEMBLOCK_REGIONS + 2)
+
+struct fad_crash_memory_ranges {
+	unsigned long long	base;
+	unsigned long long	size;
+};
+
+extern int early_init_dt_scan_fw_dump(unsigned long node,
+		const char *uname, int depth, void *data);
+extern int fadump_reserve_mem(void);
+extern int setup_fadump(void);
+extern int is_fadump_active(void);
+extern void crash_fadump(struct pt_regs *, const char *);
+extern void fadump_cleanup(void);
+
+extern void vmcore_cleanup(void);
+#else	/* CONFIG_FA_DUMP */
+static inline int is_fadump_active(void) { return 0; }
+static inline void crash_fadump(struct pt_regs *regs, const char *str) { }
+#endif
+#endif
diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h
index 14db29b..ad0b751 100644
--- a/arch/powerpc/include/asm/firmware.h
+++ b/arch/powerpc/include/asm/firmware.h
@@ -41,7 +41,6 @@
 #define FW_FEATURE_XDABR	ASM_CONST(0x0000000000040000)
 #define FW_FEATURE_MULTITCE	ASM_CONST(0x0000000000080000)
 #define FW_FEATURE_SPLPAR	ASM_CONST(0x0000000000100000)
-#define FW_FEATURE_ISERIES	ASM_CONST(0x0000000000200000)
 #define FW_FEATURE_LPAR		ASM_CONST(0x0000000000400000)
 #define FW_FEATURE_PS3_LV1	ASM_CONST(0x0000000000800000)
 #define FW_FEATURE_BEAT		ASM_CONST(0x0000000001000000)
@@ -65,8 +64,6 @@
 		FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR |
 		FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO,
 	FW_FEATURE_PSERIES_ALWAYS = 0,
-	FW_FEATURE_ISERIES_POSSIBLE = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
-	FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
 	FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL | FW_FEATURE_OPALv2,
 	FW_FEATURE_POWERNV_ALWAYS = 0,
 	FW_FEATURE_PS3_POSSIBLE = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1,
@@ -79,9 +76,6 @@
 #ifdef CONFIG_PPC_PSERIES
 		FW_FEATURE_PSERIES_POSSIBLE |
 #endif
-#ifdef CONFIG_PPC_ISERIES
-		FW_FEATURE_ISERIES_POSSIBLE |
-#endif
 #ifdef CONFIG_PPC_POWERNV
 		FW_FEATURE_POWERNV_POSSIBLE |
 #endif
@@ -99,9 +93,6 @@
 #ifdef CONFIG_PPC_PSERIES
 		FW_FEATURE_PSERIES_ALWAYS &
 #endif
-#ifdef CONFIG_PPC_ISERIES
-		FW_FEATURE_ISERIES_ALWAYS &
-#endif
 #ifdef CONFIG_PPC_POWERNV
 		FW_FEATURE_POWERNV_ALWAYS &
 #endif
diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h
index bebd124..aa4c488 100644
--- a/arch/powerpc/include/asm/fsl_guts.h
+++ b/arch/powerpc/include/asm/fsl_guts.h
@@ -4,7 +4,7 @@
  * Authors: Jeff Brown
  *          Timur Tabi <timur@freescale.com>
  *
- * Copyright 2004,2007 Freescale Semiconductor, Inc
+ * Copyright 2004,2007,2012 Freescale Semiconductor, Inc
  *
  * 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
@@ -16,15 +16,6 @@
 #define __ASM_POWERPC_FSL_GUTS_H__
 #ifdef __KERNEL__
 
-/*
- * These #ifdefs are safe because it's not possible to build a kernel that
- * runs on e500 and e600 cores.
- */
-
-#if !defined(CONFIG_PPC_85xx) && !defined(CONFIG_PPC_86xx)
-#error Only 85xx and 86xx SOCs are supported
-#endif
-
 /**
  * Global Utility Registers.
  *
@@ -36,11 +27,7 @@
  * different names.  In these cases, one name is chosen to avoid extraneous
  * #ifdefs.
  */
-#ifdef CONFIG_PPC_85xx
-struct ccsr_guts_85xx {
-#else
-struct ccsr_guts_86xx {
-#endif
+struct ccsr_guts {
 	__be32	porpllsr;	/* 0x.0000 - POR PLL Ratio Status Register */
 	__be32	porbmsr;	/* 0x.0004 - POR Boot Mode Status Register */
 	__be32	porimpscr;	/* 0x.0008 - POR I/O Impedance Status and Control Register */
@@ -77,11 +64,8 @@
 	u8	res0a8[0xb0 - 0xa8];
 	__be32	rstcr;		/* 0x.00b0 - Reset Control Register */
 	u8	res0b4[0xc0 - 0xb4];
-#ifdef CONFIG_PPC_85xx
-	__be32  iovselsr;	/* 0x.00c0 - I/O voltage select status register */
-#else
-	__be32	elbcvselcr;	/* 0x.00c0 - eLBC Voltage Select Ctrl Reg */
-#endif
+	__be32  iovselsr;	/* 0x.00c0 - I/O voltage select status register
+					     Called 'elbcvselcr' on 86xx SOCs */
 	u8	res0c4[0x224 - 0xc4];
 	__be32  iodelay1;	/* 0x.0224 - IO delay control register 1 */
 	__be32  iodelay2;	/* 0x.0228 - IO delay control register 2 */
@@ -114,6 +98,10 @@
 	__be32	srds2cr1;	/* 0x.0f44 - SerDes2 Control Register 0 */
 } __attribute__ ((packed));
 
+
+/* Alternate function signal multiplex control */
+#define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x))
+
 #ifdef CONFIG_PPC_86xx
 
 #define CCSR_GUTS_DMACR_DEV_SSI	0	/* DMA controller/channel set to SSI */
@@ -132,7 +120,7 @@
  * ch: The channel on the DMA controller (0, 1, 2, or 3)
  * device: The device to set as the source (CCSR_GUTS_DMACR_DEV_xx)
  */
-static inline void guts_set_dmacr(struct ccsr_guts_86xx __iomem *guts,
+static inline void guts_set_dmacr(struct ccsr_guts __iomem *guts,
 	unsigned int co, unsigned int ch, unsigned int device)
 {
 	unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
@@ -168,7 +156,7 @@
  * ch: The channel on the DMA controller (0, 1, 2, or 3)
  * value: the new value for the bit (0 or 1)
  */
-static inline void guts_set_pmuxcr_dma(struct ccsr_guts_86xx __iomem *guts,
+static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
 	unsigned int co, unsigned int ch, unsigned int value)
 {
 	if ((ch == 0) || (ch == 3)) {
diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h
index 80fd4d2..be04330 100644
--- a/arch/powerpc/include/asm/hw_breakpoint.h
+++ b/arch/powerpc/include/asm/hw_breakpoint.h
@@ -35,7 +35,7 @@
 
 #include <linux/kdebug.h>
 #include <asm/reg.h>
-#include <asm/system.h>
+#include <asm/debug.h>
 
 struct perf_event;
 struct pmu;
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h
index bb712c9..51010bf 100644
--- a/arch/powerpc/include/asm/hw_irq.h
+++ b/arch/powerpc/include/asm/hw_irq.h
@@ -11,6 +11,27 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 
+#ifdef CONFIG_PPC64
+
+/*
+ * PACA flags in paca->irq_happened.
+ *
+ * This bits are set when interrupts occur while soft-disabled
+ * and allow a proper replay. Additionally, PACA_IRQ_HARD_DIS
+ * is set whenever we manually hard disable.
+ */
+#define PACA_IRQ_HARD_DIS	0x01
+#define PACA_IRQ_DBELL		0x02
+#define PACA_IRQ_EE		0x04
+#define PACA_IRQ_DEC		0x08 /* Or FIT */
+#define PACA_IRQ_EE_EDGE	0x10 /* BookE only */
+
+#endif /* CONFIG_PPC64 */
+
+#ifndef __ASSEMBLY__
+
+extern void __replay_interrupt(unsigned int vector);
+
 extern void timer_interrupt(struct pt_regs *);
 
 #ifdef CONFIG_PPC64
@@ -42,7 +63,6 @@
 }
 
 extern void arch_local_irq_restore(unsigned long);
-extern void iseries_handle_interrupts(void);
 
 static inline void arch_local_irq_enable(void)
 {
@@ -68,16 +88,33 @@
 #define __hard_irq_enable()	asm volatile("wrteei 1" : : : "memory");
 #define __hard_irq_disable()	asm volatile("wrteei 0" : : : "memory");
 #else
-#define __hard_irq_enable()	__mtmsrd(mfmsr() | MSR_EE, 1)
-#define __hard_irq_disable()	__mtmsrd(mfmsr() & ~MSR_EE, 1)
+#define __hard_irq_enable()	__mtmsrd(local_paca->kernel_msr | MSR_EE, 1)
+#define __hard_irq_disable()	__mtmsrd(local_paca->kernel_msr, 1)
 #endif
 
-#define  hard_irq_disable()			\
-	do {					\
-		__hard_irq_disable();		\
-		get_paca()->soft_enabled = 0;	\
-		get_paca()->hard_enabled = 0;	\
-	} while(0)
+static inline void hard_irq_disable(void)
+{
+	__hard_irq_disable();
+	get_paca()->soft_enabled = 0;
+	get_paca()->irq_happened |= PACA_IRQ_HARD_DIS;
+}
+
+/*
+ * This is called by asynchronous interrupts to conditionally
+ * re-enable hard interrupts when soft-disabled after having
+ * cleared the source of the interrupt
+ */
+static inline void may_hard_irq_enable(void)
+{
+	get_paca()->irq_happened &= ~PACA_IRQ_HARD_DIS;
+	if (!(get_paca()->irq_happened & PACA_IRQ_EE))
+		__hard_irq_enable();
+}
+
+static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
+{
+	return !regs->softe;
+}
 
 #else /* CONFIG_PPC64 */
 
@@ -139,6 +176,13 @@
 
 #define hard_irq_disable()		arch_local_irq_disable()
 
+static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
+{
+	return !(regs->msr & MSR_EE);
+}
+
+static inline void may_hard_irq_enable(void) { }
+
 #endif /* CONFIG_PPC64 */
 
 #define ARCH_IRQ_INIT_FLAGS	IRQ_NOREQUEST
@@ -149,5 +193,6 @@
  */
 struct irq_chip;
 
+#endif  /* __ASSEMBLY__ */
 #endif	/* __KERNEL__ */
 #endif	/* _ASM_POWERPC_HW_IRQ_H */
diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index edfc980..957a83f 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -112,7 +112,6 @@
 			     struct dma_attrs *attrs);
 
 extern void iommu_init_early_pSeries(void);
-extern void iommu_init_early_iSeries(void);
 extern void iommu_init_early_dart(void);
 extern void iommu_init_early_pasemi(void);
 
diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
index fe0b09d..cf417e51 100644
--- a/arch/powerpc/include/asm/irq.h
+++ b/arch/powerpc/include/asm/irq.h
@@ -27,12 +27,6 @@
 /* This number is used when no interrupt has been assigned */
 #define NO_IRQ			(0)
 
-/* This is a special irq number to return from get_irq() to tell that
- * no interrupt happened _and_ ignore it (don't count it as bad). Some
- * platforms like iSeries rely on that.
- */
-#define NO_IRQ_IGNORE		((unsigned int)-1)
-
 /* Total number of virq in the platform */
 #define NR_IRQS		CONFIG_NR_IRQS
 
diff --git a/arch/powerpc/include/asm/irqflags.h b/arch/powerpc/include/asm/irqflags.h
index b0b06d8..6f9b6e2 100644
--- a/arch/powerpc/include/asm/irqflags.h
+++ b/arch/powerpc/include/asm/irqflags.h
@@ -39,24 +39,31 @@
 #define TRACE_ENABLE_INTS	TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on)
 #define TRACE_DISABLE_INTS	TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off)
 
-#define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip)		\
-	cmpdi	en,0;					\
-	bne	95f;					\
-	stb	en,PACASOFTIRQEN(r13);			\
-	TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off)	\
-	b	skip;					\
-95:	TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on)	\
-	li	en,1;
-#define TRACE_AND_RESTORE_IRQ(en)		\
-	TRACE_AND_RESTORE_IRQ_PARTIAL(en,96f);	\
-	stb	en,PACASOFTIRQEN(r13);		\
-96:
+/*
+ * This is used by assembly code to soft-disable interrupts
+ */
+#define SOFT_DISABLE_INTS(__rA, __rB)		\
+	lbz	__rA,PACASOFTIRQEN(r13);	\
+	lbz	__rB,PACAIRQHAPPENED(r13);	\
+	cmpwi	cr0,__rA,0;			\
+	li	__rA,0;				\
+	ori	__rB,__rB,PACA_IRQ_HARD_DIS;	\
+	stb	__rB,PACAIRQHAPPENED(r13);	\
+	beq	44f;				\
+	stb	__rA,PACASOFTIRQEN(r13);	\
+	TRACE_DISABLE_INTS;			\
+44:
+
 #else
 #define TRACE_ENABLE_INTS
 #define TRACE_DISABLE_INTS
-#define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip)
-#define TRACE_AND_RESTORE_IRQ(en)		\
-	stb	en,PACASOFTIRQEN(r13)
+
+#define SOFT_DISABLE_INTS(__rA, __rB)		\
+	lbz	__rA,PACAIRQHAPPENED(r13);	\
+	li	__rB,0;				\
+	ori	__rA,__rA,PACA_IRQ_HARD_DIS;	\
+	stb	__rB,PACASOFTIRQEN(r13);	\
+	stb	__rA,PACAIRQHAPPENED(r13)
 #endif
 #endif
 
diff --git a/arch/powerpc/include/asm/iseries/alpaca.h b/arch/powerpc/include/asm/iseries/alpaca.h
deleted file mode 100644
index c0cce67..0000000
--- a/arch/powerpc/include/asm/iseries/alpaca.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright © 2008  Stephen Rothwell 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef _ASM_POWERPC_ISERIES_ALPACA_H
-#define _ASM_POWERPC_ISERIES_ALPACA_H
-
-/*
- * This is the part of the paca that the iSeries hypervisor
- * needs to be statically initialised. Immediately after boot
- * we switch to the normal Linux paca.
- */
-struct alpaca {
-	struct lppaca *lppaca_ptr;	/* Pointer to LpPaca for PLIC */
-	const void *reg_save_ptr;	/* Pointer to LpRegSave for PLIC */
-};
-
-#endif /* _ASM_POWERPC_ISERIES_ALPACA_H */
diff --git a/arch/powerpc/include/asm/iseries/hv_call.h b/arch/powerpc/include/asm/iseries/hv_call.h
deleted file mode 100644
index 162d653..0000000
--- a/arch/powerpc/include/asm/iseries/hv_call.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- *
- * This file contains the "hypervisor call" interface which is used to
- * drive the hypervisor from the OS.
- */
-#ifndef _ASM_POWERPC_ISERIES_HV_CALL_H
-#define _ASM_POWERPC_ISERIES_HV_CALL_H
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/paca.h>
-
-/* Type of yield for HvCallBaseYieldProcessor */
-#define HvCall_YieldTimed	0	/* Yield until specified time (tb) */
-#define HvCall_YieldToActive	1	/* Yield until all active procs have run */
-#define HvCall_YieldToProc	2	/* Yield until the specified processor has run */
-
-/* interrupt masks for setEnabledInterrupts */
-#define HvCall_MaskIPI		0x00000001
-#define HvCall_MaskLpEvent	0x00000002
-#define HvCall_MaskLpProd	0x00000004
-#define HvCall_MaskTimeout	0x00000008
-
-/* Log buffer formats */
-#define HvCall_LogBuffer_ASCII          0
-#define HvCall_LogBuffer_EBCDIC         1
-
-#define HvCallBaseAckDeferredInts			HvCallBase +  0
-#define HvCallBaseCpmPowerOff				HvCallBase +  1
-#define HvCallBaseGetHwPatch				HvCallBase +  2
-#define HvCallBaseReIplSpAttn				HvCallBase +  3
-#define HvCallBaseSetASR				HvCallBase +  4
-#define HvCallBaseSetASRAndRfi				HvCallBase +  5
-#define HvCallBaseSetIMR				HvCallBase +  6
-#define HvCallBaseSendIPI				HvCallBase +  7
-#define HvCallBaseTerminateMachine			HvCallBase +  8
-#define HvCallBaseTerminateMachineSrc			HvCallBase +  9
-#define HvCallBaseProcessPlicInterrupts			HvCallBase + 10
-#define HvCallBaseIsPrimaryCpmOrMsdIpl			HvCallBase + 11
-#define HvCallBaseSetVirtualSIT				HvCallBase + 12
-#define HvCallBaseVaryOffThisProcessor			HvCallBase + 13
-#define HvCallBaseVaryOffMemoryChunk			HvCallBase + 14
-#define HvCallBaseVaryOffInteractivePercentage		HvCallBase + 15
-#define HvCallBaseSendLpProd				HvCallBase + 16
-#define HvCallBaseSetEnabledInterrupts			HvCallBase + 17
-#define HvCallBaseYieldProcessor			HvCallBase + 18
-#define HvCallBaseVaryOffSharedProcUnits		HvCallBase + 19
-#define HvCallBaseSetVirtualDecr			HvCallBase + 20
-#define HvCallBaseClearLogBuffer			HvCallBase + 21
-#define HvCallBaseGetLogBufferCodePage			HvCallBase + 22
-#define HvCallBaseGetLogBufferFormat			HvCallBase + 23
-#define HvCallBaseGetLogBufferLength			HvCallBase + 24
-#define HvCallBaseReadLogBuffer				HvCallBase + 25
-#define HvCallBaseSetLogBufferFormatAndCodePage		HvCallBase + 26
-#define HvCallBaseWriteLogBuffer			HvCallBase + 27
-#define HvCallBaseRouter28				HvCallBase + 28
-#define HvCallBaseRouter29				HvCallBase + 29
-#define HvCallBaseRouter30				HvCallBase + 30
-#define HvCallBaseSetDebugBus				HvCallBase + 31
-
-#define HvCallCcSetDABR					HvCallCc + 7
-
-static inline void HvCall_setVirtualDecr(void)
-{
-	/*
-	 * Ignore any error return codes - most likely means that the
-	 * target value for the LP has been increased and this vary off
-	 * would bring us below the new target.
-	 */
-	HvCall0(HvCallBaseSetVirtualDecr);
-}
-
-static inline void HvCall_yieldProcessor(unsigned typeOfYield, u64 yieldParm)
-{
-	HvCall2(HvCallBaseYieldProcessor, typeOfYield, yieldParm);
-}
-
-static inline void HvCall_setEnabledInterrupts(u64 enabledInterrupts)
-{
-	HvCall1(HvCallBaseSetEnabledInterrupts, enabledInterrupts);
-}
-
-static inline void HvCall_setLogBufferFormatAndCodepage(int format,
-		u32 codePage)
-{
-	HvCall2(HvCallBaseSetLogBufferFormatAndCodePage, format, codePage);
-}
-
-extern void HvCall_writeLogBuffer(const void *buffer, u64 bufLen);
-
-static inline void HvCall_sendIPI(struct paca_struct *targetPaca)
-{
-	HvCall1(HvCallBaseSendIPI, targetPaca->paca_index);
-}
-
-#endif /* _ASM_POWERPC_ISERIES_HV_CALL_H */
diff --git a/arch/powerpc/include/asm/iseries/hv_call_event.h b/arch/powerpc/include/asm/iseries/hv_call_event.h
deleted file mode 100644
index cc029d3..0000000
--- a/arch/powerpc/include/asm/iseries/hv_call_event.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- *
- * This file contains the "hypervisor call" interface which is used to
- * drive the hypervisor from the OS.
- */
-#ifndef _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H
-#define _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H
-
-#include <linux/types.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/abs_addr.h>
-
-struct HvLpEvent;
-
-typedef u8 HvLpEvent_Type;
-typedef u8 HvLpEvent_AckInd;
-typedef u8 HvLpEvent_AckType;
-
-typedef u8 HvLpDma_Direction;
-typedef u8 HvLpDma_AddressType;
-
-typedef u64 HvLpEvent_Rc;
-typedef u64 HvLpDma_Rc;
-
-#define HvCallEventAckLpEvent				HvCallEvent +  0
-#define HvCallEventCancelLpEvent			HvCallEvent +  1
-#define HvCallEventCloseLpEventPath			HvCallEvent +  2
-#define HvCallEventDmaBufList				HvCallEvent +  3
-#define HvCallEventDmaSingle				HvCallEvent +  4
-#define HvCallEventDmaToSp				HvCallEvent +  5
-#define HvCallEventGetOverflowLpEvents			HvCallEvent +  6
-#define HvCallEventGetSourceLpInstanceId		HvCallEvent +  7
-#define HvCallEventGetTargetLpInstanceId		HvCallEvent +  8
-#define HvCallEventOpenLpEventPath			HvCallEvent +  9
-#define HvCallEventSetLpEventStack			HvCallEvent + 10
-#define HvCallEventSignalLpEvent			HvCallEvent + 11
-#define HvCallEventSignalLpEventParms			HvCallEvent + 12
-#define HvCallEventSetInterLpQueueIndex			HvCallEvent + 13
-#define HvCallEventSetLpEventQueueInterruptProc		HvCallEvent + 14
-#define HvCallEventRouter15				HvCallEvent + 15
-
-static inline void HvCallEvent_getOverflowLpEvents(u8 queueIndex)
-{
-	HvCall1(HvCallEventGetOverflowLpEvents, queueIndex);
-}
-
-static inline void HvCallEvent_setInterLpQueueIndex(u8 queueIndex)
-{
-	HvCall1(HvCallEventSetInterLpQueueIndex, queueIndex);
-}
-
-static inline void HvCallEvent_setLpEventStack(u8 queueIndex,
-		char *eventStackAddr, u32 eventStackSize)
-{
-	HvCall3(HvCallEventSetLpEventStack, queueIndex,
-			virt_to_abs(eventStackAddr), eventStackSize);
-}
-
-static inline void HvCallEvent_setLpEventQueueInterruptProc(u8 queueIndex,
-		u16 lpLogicalProcIndex)
-{
-	HvCall2(HvCallEventSetLpEventQueueInterruptProc, queueIndex,
-			lpLogicalProcIndex);
-}
-
-static inline HvLpEvent_Rc HvCallEvent_signalLpEvent(struct HvLpEvent *event)
-{
-	return HvCall1(HvCallEventSignalLpEvent, virt_to_abs(event));
-}
-
-static inline HvLpEvent_Rc HvCallEvent_signalLpEventFast(HvLpIndex targetLp,
-		HvLpEvent_Type type, u16 subtype, HvLpEvent_AckInd ackInd,
-		HvLpEvent_AckType ackType, HvLpInstanceId sourceInstanceId,
-		HvLpInstanceId targetInstanceId, u64 correlationToken,
-		u64 eventData1, u64 eventData2, u64 eventData3,
-		u64 eventData4, u64 eventData5)
-{
-	/* Pack the misc bits into a single Dword to pass to PLIC */
-	union {
-		struct {
-			u8		ack_and_target;
-			u8		type;
-			u16		subtype;
-			HvLpInstanceId	src_inst;
-			HvLpInstanceId	target_inst;
-		} parms;
-		u64		dword;
-	} packed;
-
-	packed.parms.ack_and_target = (ackType << 7) | (ackInd << 6) | targetLp;
-	packed.parms.type = type;
-	packed.parms.subtype = subtype;
-	packed.parms.src_inst = sourceInstanceId;
-	packed.parms.target_inst = targetInstanceId;
-
-	return HvCall7(HvCallEventSignalLpEventParms, packed.dword,
-			correlationToken, eventData1, eventData2,
-			eventData3, eventData4, eventData5);
-}
-
-extern void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag);
-extern void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle);
-extern dma_addr_t iseries_hv_map(void *vaddr, size_t size,
-			enum dma_data_direction direction);
-extern void iseries_hv_unmap(dma_addr_t dma_handle, size_t size,
-			enum dma_data_direction direction);
-
-static inline HvLpEvent_Rc HvCallEvent_ackLpEvent(struct HvLpEvent *event)
-{
-	return HvCall1(HvCallEventAckLpEvent, virt_to_abs(event));
-}
-
-static inline HvLpEvent_Rc HvCallEvent_cancelLpEvent(struct HvLpEvent *event)
-{
-	return HvCall1(HvCallEventCancelLpEvent, virt_to_abs(event));
-}
-
-static inline HvLpInstanceId HvCallEvent_getSourceLpInstanceId(
-		HvLpIndex targetLp, HvLpEvent_Type type)
-{
-	return HvCall2(HvCallEventGetSourceLpInstanceId, targetLp, type);
-}
-
-static inline HvLpInstanceId HvCallEvent_getTargetLpInstanceId(
-		HvLpIndex targetLp, HvLpEvent_Type type)
-{
-	return HvCall2(HvCallEventGetTargetLpInstanceId, targetLp, type);
-}
-
-static inline void HvCallEvent_openLpEventPath(HvLpIndex targetLp,
-		HvLpEvent_Type type)
-{
-	HvCall2(HvCallEventOpenLpEventPath, targetLp, type);
-}
-
-static inline void HvCallEvent_closeLpEventPath(HvLpIndex targetLp,
-		HvLpEvent_Type type)
-{
-	HvCall2(HvCallEventCloseLpEventPath, targetLp, type);
-}
-
-static inline HvLpDma_Rc HvCallEvent_dmaBufList(HvLpEvent_Type type,
-		HvLpIndex remoteLp, HvLpDma_Direction direction,
-		HvLpInstanceId localInstanceId,
-		HvLpInstanceId remoteInstanceId,
-		HvLpDma_AddressType localAddressType,
-		HvLpDma_AddressType remoteAddressType,
-		/* Do these need to be converted to absolute addresses? */
-		u64 localBufList, u64 remoteBufList, u32 transferLength)
-{
-	/* Pack the misc bits into a single Dword to pass to PLIC */
-	union {
-		struct {
-			u8		flags;
-			HvLpIndex	remote;
-			u8		type;
-			u8		reserved;
-			HvLpInstanceId	local_inst;
-			HvLpInstanceId	remote_inst;
-		} parms;
-		u64		dword;
-	} packed;
-
-	packed.parms.flags = (direction << 7) |
-		(localAddressType << 6) | (remoteAddressType << 5);
-	packed.parms.remote = remoteLp;
-	packed.parms.type = type;
-	packed.parms.reserved = 0;
-	packed.parms.local_inst = localInstanceId;
-	packed.parms.remote_inst = remoteInstanceId;
-
-	return HvCall4(HvCallEventDmaBufList, packed.dword, localBufList,
-			remoteBufList, transferLength);
-}
-
-static inline HvLpDma_Rc HvCallEvent_dmaToSp(void *local, u32 remote,
-		u32 length, HvLpDma_Direction dir)
-{
-	return HvCall4(HvCallEventDmaToSp, virt_to_abs(local), remote,
-			length, dir);
-}
-
-#endif /* _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H */
diff --git a/arch/powerpc/include/asm/iseries/hv_call_sc.h b/arch/powerpc/include/asm/iseries/hv_call_sc.h
deleted file mode 100644
index f5d2109..0000000
--- a/arch/powerpc/include/asm/iseries/hv_call_sc.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef _ASM_POWERPC_ISERIES_HV_CALL_SC_H
-#define _ASM_POWERPC_ISERIES_HV_CALL_SC_H
-
-#include <linux/types.h>
-
-#define HvCallBase		0x8000000000000000ul
-#define HvCallCc		0x8001000000000000ul
-#define HvCallCfg		0x8002000000000000ul
-#define HvCallEvent		0x8003000000000000ul
-#define HvCallHpt		0x8004000000000000ul
-#define HvCallPci		0x8005000000000000ul
-#define HvCallSm		0x8007000000000000ul
-#define HvCallXm		0x8009000000000000ul
-
-extern u64 HvCall0(u64);
-extern u64 HvCall1(u64, u64);
-extern u64 HvCall2(u64, u64, u64);
-extern u64 HvCall3(u64, u64, u64, u64);
-extern u64 HvCall4(u64, u64, u64, u64, u64);
-extern u64 HvCall5(u64, u64, u64, u64, u64, u64);
-extern u64 HvCall6(u64, u64, u64, u64, u64, u64, u64);
-extern u64 HvCall7(u64, u64, u64, u64, u64, u64, u64, u64);
-
-extern u64 HvCall0Ret16(u64, void *);
-extern u64 HvCall1Ret16(u64, void *, u64);
-extern u64 HvCall2Ret16(u64, void *, u64, u64);
-extern u64 HvCall3Ret16(u64, void *, u64, u64, u64);
-extern u64 HvCall4Ret16(u64, void *, u64, u64, u64, u64);
-extern u64 HvCall5Ret16(u64, void *, u64, u64, u64, u64, u64);
-extern u64 HvCall6Ret16(u64, void *, u64, u64, u64, u64, u64, u64);
-extern u64 HvCall7Ret16(u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64);
-
-#endif /* _ASM_POWERPC_ISERIES_HV_CALL_SC_H */
diff --git a/arch/powerpc/include/asm/iseries/hv_call_xm.h b/arch/powerpc/include/asm/iseries/hv_call_xm.h
deleted file mode 100644
index 392ac3f..0000000
--- a/arch/powerpc/include/asm/iseries/hv_call_xm.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * This file contains the "hypervisor call" interface which is used to
- * drive the hypervisor from SLIC.
- */
-#ifndef _ASM_POWERPC_ISERIES_HV_CALL_XM_H
-#define _ASM_POWERPC_ISERIES_HV_CALL_XM_H
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-
-#define HvCallXmGetTceTableParms	HvCallXm +  0
-#define HvCallXmTestBus			HvCallXm +  1
-#define HvCallXmConnectBusUnit		HvCallXm +  2
-#define HvCallXmLoadTod			HvCallXm +  8
-#define HvCallXmTestBusUnit		HvCallXm +  9
-#define HvCallXmSetTce			HvCallXm + 11
-#define HvCallXmSetTces			HvCallXm + 13
-
-static inline void HvCallXm_getTceTableParms(u64 cb)
-{
-	HvCall1(HvCallXmGetTceTableParms, cb);
-}
-
-static inline u64 HvCallXm_setTce(u64 tceTableToken, u64 tceOffset, u64 tce)
-{
-	return HvCall3(HvCallXmSetTce, tceTableToken, tceOffset, tce);
-}
-
-static inline u64 HvCallXm_setTces(u64 tceTableToken, u64 tceOffset,
-		u64 numTces, u64 tce1, u64 tce2, u64 tce3, u64 tce4)
-{
-	return HvCall7(HvCallXmSetTces, tceTableToken, tceOffset, numTces,
-			     tce1, tce2, tce3, tce4);
-}
-
-static inline u64 HvCallXm_testBus(u16 busNumber)
-{
-	return HvCall1(HvCallXmTestBus, busNumber);
-}
-
-static inline u64 HvCallXm_testBusUnit(u16 busNumber, u8 subBusNumber,
-		u8 deviceId)
-{
-	return HvCall2(HvCallXmTestBusUnit, busNumber,
-			(subBusNumber << 8) | deviceId);
-}
-
-static inline u64 HvCallXm_connectBusUnit(u16 busNumber, u8 subBusNumber,
-		u8 deviceId, u64 interruptToken)
-{
-	return HvCall5(HvCallXmConnectBusUnit, busNumber,
-			(subBusNumber << 8) | deviceId, interruptToken, 0,
-			0 /* HvLpConfig::mapDsaToQueueIndex(HvLpDSA(busNumber, xBoard, xCard)) */);
-}
-
-static inline u64 HvCallXm_loadTod(void)
-{
-	return HvCall0(HvCallXmLoadTod);
-}
-
-#endif /* _ASM_POWERPC_ISERIES_HV_CALL_XM_H */
diff --git a/arch/powerpc/include/asm/iseries/hv_lp_config.h b/arch/powerpc/include/asm/iseries/hv_lp_config.h
deleted file mode 100644
index a006fd1..0000000
--- a/arch/powerpc/include/asm/iseries/hv_lp_config.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef _ASM_POWERPC_ISERIES_HV_LP_CONFIG_H
-#define _ASM_POWERPC_ISERIES_HV_LP_CONFIG_H
-
-/*
- * This file contains the interface to the LPAR configuration data
- * to determine which resources should be allocated to each partition.
- */
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-
-enum {
-	HvCallCfg_Cur	= 0,
-	HvCallCfg_Init	= 1,
-	HvCallCfg_Max	= 2,
-	HvCallCfg_Min	= 3
-};
-
-#define HvCallCfgGetSystemPhysicalProcessors		HvCallCfg +  6
-#define HvCallCfgGetPhysicalProcessors			HvCallCfg +  7
-#define HvCallCfgGetMsChunks				HvCallCfg +  9
-#define HvCallCfgGetSharedPoolIndex			HvCallCfg + 20
-#define HvCallCfgGetSharedProcUnits			HvCallCfg + 21
-#define HvCallCfgGetNumProcsInSharedPool		HvCallCfg + 22
-#define HvCallCfgGetVirtualLanIndexMap			HvCallCfg + 30
-#define HvCallCfgGetHostingLpIndex			HvCallCfg + 32
-
-extern HvLpIndex HvLpConfig_getLpIndex_outline(void);
-extern HvLpIndex HvLpConfig_getLpIndex(void);
-extern HvLpIndex HvLpConfig_getPrimaryLpIndex(void);
-
-static inline u64 HvLpConfig_getMsChunks(void)
-{
-	return HvCall2(HvCallCfgGetMsChunks, HvLpConfig_getLpIndex(),
-			HvCallCfg_Cur);
-}
-
-static inline u64 HvLpConfig_getSystemPhysicalProcessors(void)
-{
-	return HvCall0(HvCallCfgGetSystemPhysicalProcessors);
-}
-
-static inline u64 HvLpConfig_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI)
-{
-	return (u16)HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI);
-}
-
-static inline u64 HvLpConfig_getPhysicalProcessors(void)
-{
-	return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(),
-			HvCallCfg_Cur);
-}
-
-static inline HvLpSharedPoolIndex HvLpConfig_getSharedPoolIndex(void)
-{
-	return HvCall1(HvCallCfgGetSharedPoolIndex, HvLpConfig_getLpIndex());
-}
-
-static inline u64 HvLpConfig_getSharedProcUnits(void)
-{
-	return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(),
-			HvCallCfg_Cur);
-}
-
-static inline u64 HvLpConfig_getMaxSharedProcUnits(void)
-{
-	return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(),
-			HvCallCfg_Max);
-}
-
-static inline u64 HvLpConfig_getMaxPhysicalProcessors(void)
-{
-	return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(),
-			HvCallCfg_Max);
-}
-
-static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMapForLp(
-		HvLpIndex lp)
-{
-	/*
-	 * This is a new function in V5R1 so calls to this on older
-	 * hypervisors will return -1
-	 */
-	u64 retVal = HvCall1(HvCallCfgGetVirtualLanIndexMap, lp);
-	if (retVal == -1)
-		retVal = 0;
-	return retVal;
-}
-
-static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void)
-{
-	return HvLpConfig_getVirtualLanIndexMapForLp(
-			HvLpConfig_getLpIndex_outline());
-}
-
-static inline int HvLpConfig_doLpsCommunicateOnVirtualLan(HvLpIndex lp1,
-		HvLpIndex lp2)
-{
-	HvLpVirtualLanIndexMap virtualLanIndexMap1 =
-		HvLpConfig_getVirtualLanIndexMapForLp(lp1);
-	HvLpVirtualLanIndexMap virtualLanIndexMap2 =
-		HvLpConfig_getVirtualLanIndexMapForLp(lp2);
-	return ((virtualLanIndexMap1 & virtualLanIndexMap2) != 0);
-}
-
-static inline HvLpIndex HvLpConfig_getHostingLpIndex(HvLpIndex lp)
-{
-	return HvCall1(HvCallCfgGetHostingLpIndex, lp);
-}
-
-#endif /* _ASM_POWERPC_ISERIES_HV_LP_CONFIG_H */
diff --git a/arch/powerpc/include/asm/iseries/hv_lp_event.h b/arch/powerpc/include/asm/iseries/hv_lp_event.h
deleted file mode 100644
index 8f5da7d..0000000
--- a/arch/powerpc/include/asm/iseries/hv_lp_event.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-
-/* This file contains the class for HV events in the system. */
-
-#ifndef _ASM_POWERPC_ISERIES_HV_LP_EVENT_H
-#define _ASM_POWERPC_ISERIES_HV_LP_EVENT_H
-
-#include <asm/types.h>
-#include <asm/ptrace.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_call_event.h>
-
-/*
- * HvLpEvent is the structure for Lp Event messages passed between
- * partitions through PLIC.
- */
-
-struct HvLpEvent {
-	u8	flags;			/* Event flags		      x00-x00 */
-	u8	xType;			/* Type of message	      x01-x01 */
-	u16	xSubtype;		/* Subtype for event	      x02-x03 */
-	u8	xSourceLp;		/* Source LP		      x04-x04 */
-	u8	xTargetLp;		/* Target LP		      x05-x05 */
-	u8	xSizeMinus1;		/* Size of Derived class - 1  x06-x06 */
-	u8	xRc;			/* RC for Ack flows	      x07-x07 */
-	u16	xSourceInstanceId;	/* Source sides instance id   x08-x09 */
-	u16	xTargetInstanceId;	/* Target sides instance id   x0A-x0B */
-	union {
-		u32	xSubtypeData;	/* Data usable by the subtype x0C-x0F */
-		u16	xSubtypeDataShort[2];	/* Data as 2 shorts */
-		u8	xSubtypeDataChar[4];	/* Data as 4 chars */
-	} x;
-
-	u64	xCorrelationToken;	/* Unique value for source/type x10-x17 */
-};
-
-typedef void (*LpEventHandler)(struct HvLpEvent *);
-
-/* Register a handler for an event type - returns 0 on success */
-extern int HvLpEvent_registerHandler(HvLpEvent_Type eventType,
-		LpEventHandler hdlr);
-
-/*
- * Unregister a handler for an event type
- *
- * This call will sleep until the handler being removed is guaranteed to
- * be no longer executing on any CPU. Do not call with locks held.
- *
- *  returns 0 on success
- *  Unregister will fail if there are any paths open for the type
- */
-extern int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType);
-
-/*
- * Open an Lp Event Path for an event type
- * returns 0 on success
- * openPath will fail if there is no handler registered for the event type.
- * The lpIndex specified is the partition index for the target partition
- * (for VirtualIo, VirtualLan and SessionMgr) other types specify zero)
- */
-extern int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex);
-
-/*
- * Close an Lp Event Path for a type and partition
- * returns 0 on success
- */
-extern int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex);
-
-#define HvLpEvent_Type_Hypervisor 0
-#define HvLpEvent_Type_MachineFac 1
-#define HvLpEvent_Type_SessionMgr 2
-#define HvLpEvent_Type_SpdIo      3
-#define HvLpEvent_Type_VirtualBus 4
-#define HvLpEvent_Type_PciIo      5
-#define HvLpEvent_Type_RioIo      6
-#define HvLpEvent_Type_VirtualLan 7
-#define HvLpEvent_Type_VirtualIo  8
-#define HvLpEvent_Type_NumTypes   9
-
-#define HvLpEvent_Rc_Good 0
-#define HvLpEvent_Rc_BufferNotAvailable 1
-#define HvLpEvent_Rc_Cancelled 2
-#define HvLpEvent_Rc_GenericError 3
-#define HvLpEvent_Rc_InvalidAddress 4
-#define HvLpEvent_Rc_InvalidPartition 5
-#define HvLpEvent_Rc_InvalidSize 6
-#define HvLpEvent_Rc_InvalidSubtype 7
-#define HvLpEvent_Rc_InvalidSubtypeData 8
-#define HvLpEvent_Rc_InvalidType 9
-#define HvLpEvent_Rc_PartitionDead 10
-#define HvLpEvent_Rc_PathClosed 11
-#define HvLpEvent_Rc_SubtypeError 12
-
-#define HvLpEvent_Function_Ack 0
-#define HvLpEvent_Function_Int 1
-
-#define HvLpEvent_AckInd_NoAck 0
-#define HvLpEvent_AckInd_DoAck 1
-
-#define HvLpEvent_AckType_ImmediateAck 0
-#define HvLpEvent_AckType_DeferredAck 1
-
-#define HV_LP_EVENT_INT			0x01
-#define HV_LP_EVENT_DO_ACK		0x02
-#define HV_LP_EVENT_DEFERRED_ACK	0x04
-#define HV_LP_EVENT_VALID		0x80
-
-#define HvLpDma_Direction_LocalToRemote 0
-#define HvLpDma_Direction_RemoteToLocal 1
-
-#define HvLpDma_AddressType_TceIndex 0
-#define HvLpDma_AddressType_RealAddress 1
-
-#define HvLpDma_Rc_Good 0
-#define HvLpDma_Rc_Error 1
-#define HvLpDma_Rc_PartitionDead 2
-#define HvLpDma_Rc_PathClosed 3
-#define HvLpDma_Rc_InvalidAddress 4
-#define HvLpDma_Rc_InvalidLength 5
-
-static inline int hvlpevent_is_valid(struct HvLpEvent *h)
-{
-	return h->flags & HV_LP_EVENT_VALID;
-}
-
-static inline void hvlpevent_invalidate(struct HvLpEvent *h)
-{
-	h->flags &= ~ HV_LP_EVENT_VALID;
-}
-
-static inline int hvlpevent_is_int(struct HvLpEvent *h)
-{
-	return h->flags & HV_LP_EVENT_INT;
-}
-
-static inline int hvlpevent_is_ack(struct HvLpEvent *h)
-{
-	return !hvlpevent_is_int(h);
-}
-
-static inline int hvlpevent_need_ack(struct HvLpEvent *h)
-{
-	return h->flags & HV_LP_EVENT_DO_ACK;
-}
-
-#endif /* _ASM_POWERPC_ISERIES_HV_LP_EVENT_H */
diff --git a/arch/powerpc/include/asm/iseries/hv_types.h b/arch/powerpc/include/asm/iseries/hv_types.h
deleted file mode 100644
index c3e6d2a..0000000
--- a/arch/powerpc/include/asm/iseries/hv_types.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef _ASM_POWERPC_ISERIES_HV_TYPES_H
-#define _ASM_POWERPC_ISERIES_HV_TYPES_H
-
-/*
- * General typedefs for the hypervisor.
- */
-
-#include <asm/types.h>
-
-typedef u8	HvLpIndex;
-typedef u16	HvLpInstanceId;
-typedef u64	HvLpTOD;
-typedef u64	HvLpSystemSerialNum;
-typedef u8	HvLpDeviceSerialNum[12];
-typedef u16	HvLpSanHwSet;
-typedef u16	HvLpBus;
-typedef u16	HvLpBoard;
-typedef u16	HvLpCard;
-typedef u8	HvLpDeviceType[4];
-typedef u8	HvLpDeviceModel[3];
-typedef u64	HvIoToken;
-typedef u8	HvLpName[8];
-typedef u32	HvIoId;
-typedef u64	HvRealMemoryIndex;
-typedef u32	HvLpIndexMap;	/* Must hold HVMAXARCHITECTEDLPS bits!!! */
-typedef u16	HvLpVrmIndex;
-typedef u32	HvXmGenerationId;
-typedef u8	HvLpBusPool;
-typedef u8	HvLpSharedPoolIndex;
-typedef u16	HvLpSharedProcUnitsX100;
-typedef u8	HvLpVirtualLanIndex;
-typedef u16	HvLpVirtualLanIndexMap;	/* Must hold HVMAXARCHITECTEDVIRTUALLANS bits!!! */
-typedef u16	HvBusNumber;	/* Hypervisor Bus Number */
-typedef u8	HvSubBusNumber;	/* Hypervisor SubBus Number */
-typedef u8	HvAgentId;	/* Hypervisor DevFn */
-
-
-#define HVMAXARCHITECTEDLPS		32
-#define HVMAXARCHITECTEDVIRTUALLANS	16
-#define HVMAXARCHITECTEDVIRTUALDISKS	32
-#define HVMAXARCHITECTEDVIRTUALCDROMS	8
-#define HVMAXARCHITECTEDVIRTUALTAPES	8
-#define HVCHUNKSIZE			(256 * 1024)
-#define HVPAGESIZE			(4 * 1024)
-#define HVLPMINMEGSPRIMARY		256
-#define HVLPMINMEGSSECONDARY		64
-#define HVCHUNKSPERMEG			4
-#define HVPAGESPERMEG			256
-#define HVPAGESPERCHUNK			64
-
-#define HvLpIndexInvalid		((HvLpIndex)0xff)
-
-/*
- * Enums for the sub-components under PLIC
- * Used in HvCall  and HvPrimaryCall
- */
-enum {
-	HvCallCompId = 0,
-	HvCallCpuCtlsCompId = 1,
-	HvCallCfgCompId = 2,
-	HvCallEventCompId = 3,
-	HvCallHptCompId = 4,
-	HvCallPciCompId = 5,
-	HvCallSlmCompId = 6,
-	HvCallSmCompId = 7,
-	HvCallSpdCompId = 8,
-	HvCallXmCompId = 9,
-	HvCallRioCompId = 10,
-	HvCallRsvd3CompId = 11,
-	HvCallRsvd2CompId = 12,
-	HvCallRsvd1CompId = 13,
-	HvCallMaxCompId = 14,
-	HvPrimaryCallCompId = 0,
-	HvPrimaryCallCfgCompId = 1,
-	HvPrimaryCallPciCompId = 2,
-	HvPrimaryCallSmCompId = 3,
-	HvPrimaryCallSpdCompId = 4,
-	HvPrimaryCallXmCompId = 5,
-	HvPrimaryCallRioCompId = 6,
-	HvPrimaryCallRsvd7CompId = 7,
-	HvPrimaryCallRsvd6CompId = 8,
-	HvPrimaryCallRsvd5CompId = 9,
-	HvPrimaryCallRsvd4CompId = 10,
-	HvPrimaryCallRsvd3CompId = 11,
-	HvPrimaryCallRsvd2CompId = 12,
-	HvPrimaryCallRsvd1CompId = 13,
-	HvPrimaryCallMaxCompId = HvCallMaxCompId
-};
-
-struct HvLpBufferList {
-	u64 addr;
-	u64 len;
-};
-
-#endif /* _ASM_POWERPC_ISERIES_HV_TYPES_H */
diff --git a/arch/powerpc/include/asm/iseries/iommu.h b/arch/powerpc/include/asm/iseries/iommu.h
deleted file mode 100644
index 1b9692c..0000000
--- a/arch/powerpc/include/asm/iseries/iommu.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef _ASM_POWERPC_ISERIES_IOMMU_H
-#define _ASM_POWERPC_ISERIES_IOMMU_H
-
-/*
- * Copyright (C) 2005  Stephen Rothwell, 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-
-struct pci_dev;
-struct vio_dev;
-struct device_node;
-struct iommu_table;
-
-/* Get table parameters from HV */
-extern void iommu_table_getparms_iSeries(unsigned long busno,
-		unsigned char slotno, unsigned char virtbus,
-		struct iommu_table *tbl);
-
-extern struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev);
-extern void iommu_vio_init(void);
-
-#endif /* _ASM_POWERPC_ISERIES_IOMMU_H */
diff --git a/arch/powerpc/include/asm/iseries/it_lp_queue.h b/arch/powerpc/include/asm/iseries/it_lp_queue.h
deleted file mode 100644
index 4282788..0000000
--- a/arch/powerpc/include/asm/iseries/it_lp_queue.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H
-#define _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H
-
-/*
- *	This control block defines the simple LP queue structure that is
- *	shared between the hypervisor (PLIC) and the OS in order to send
- *	events to an LP.
- */
-
-#include <asm/types.h>
-#include <asm/ptrace.h>
-
-#define IT_LP_MAX_QUEUES	8
-
-#define IT_LP_NOT_USED		0	/* Queue will not be used by PLIC */
-#define IT_LP_DEDICATED_IO	1	/* Queue dedicated to IO processor specified */
-#define IT_LP_DEDICATED_LP	2	/* Queue dedicated to LP specified */
-#define IT_LP_SHARED		3	/* Queue shared for both IO and LP */
-
-#define IT_LP_EVENT_STACK_SIZE	4096
-#define IT_LP_EVENT_MAX_SIZE	256
-#define IT_LP_EVENT_ALIGN	64
-
-struct hvlpevent_queue {
-/*
- * The hq_current_event is the pointer to the next event stack entry
- * that will become valid.  The OS must peek at this entry to determine
- * if it is valid.  PLIC will set the valid indicator as the very last
- * store into that entry.
- *
- * When the OS has completed processing of the event then it will mark
- * the event as invalid so that PLIC knows it can store into that event
- * location again.
- *
- * If the event stack fills and there are overflow events, then PLIC
- * will set the hq_overflow_pending flag in which case the OS will
- * have to fetch the additional LP events once they have drained the
- * event stack.
- *
- * The first 16-bytes are known by both the OS and PLIC.  The remainder
- * of the cache line is for use by the OS.
- */
-	u8		hq_overflow_pending;	/* 0x00 Overflow events are pending */
-	u8		hq_status;		/* 0x01 DedicatedIo or DedicatedLp or NotUsed */
-	u16		hq_proc_index;		/* 0x02 Logical Proc Index for correlation */
-	u8		hq_reserved1[12];	/* 0x04 */
-	char		*hq_current_event;	/* 0x10 */
-	char		*hq_last_event;		/* 0x18 */
-	char		*hq_event_stack;	/* 0x20 */
-	u8		hq_index;		/* 0x28 unique sequential index. */
-	u8		hq_reserved2[3];	/* 0x29-2b */
-	spinlock_t	hq_lock;
-};
-
-extern struct hvlpevent_queue hvlpevent_queue;
-
-extern int hvlpevent_is_pending(void);
-extern void process_hvlpevents(void);
-extern void setup_hvlpevent_queue(void);
-
-#endif /* _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H */
diff --git a/arch/powerpc/include/asm/iseries/lpar_map.h b/arch/powerpc/include/asm/iseries/lpar_map.h
deleted file mode 100644
index 5e9f3e1..0000000
--- a/arch/powerpc/include/asm/iseries/lpar_map.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef _ASM_POWERPC_ISERIES_LPAR_MAP_H
-#define _ASM_POWERPC_ISERIES_LPAR_MAP_H
-
-#ifndef __ASSEMBLY__
-
-#include <asm/types.h>
-
-#endif
-
-/*
- * The iSeries hypervisor will set up mapping for one or more
- * ESID/VSID pairs (in SLB/segment registers) and will set up
- * mappings of one or more ranges of pages to VAs.
- * We will have the hypervisor set up the ESID->VSID mapping
- * for the four kernel segments (C-F).  With shared processors,
- * the hypervisor will clear all segment registers and reload
- * these four whenever the processor is switched from one
- * partition to another.
- */
-
-/* The Vsid and Esid identified below will be used by the hypervisor
- * to set up a memory mapping for part of the load area before giving
- * control to the Linux kernel.  The load area is 64 MB, but this must
- * not attempt to map the whole load area.  The Hashed Page Table may
- * need to be located within the load area (if the total partition size
- * is 64 MB), but cannot be mapped.  Typically, this should specify
- * to map half (32 MB) of the load area.
- *
- * The hypervisor will set up page table entries for the number of
- * pages specified.
- *
- * In 32-bit mode, the hypervisor will load all four of the
- * segment registers (identified by the low-order four bits of the
- * Esid field.  In 64-bit mode, the hypervisor will load one SLB
- * entry to map the Esid to the Vsid.
-*/
-
-#define HvEsidsToMap	2
-#define HvRangesToMap	1
-
-/* Hypervisor initially maps 32MB of the load area */
-#define HvPagesToMap	8192
-
-#ifndef __ASSEMBLY__
-struct LparMap {
-	u64	xNumberEsids;	// Number of ESID/VSID pairs
-	u64	xNumberRanges;	// Number of VA ranges to map
-	u64	xSegmentTableOffs; // Page number within load area of seg table
-	u64	xRsvd[5];
-	struct {
-		u64	xKernelEsid;	// Esid used to map kernel load
-		u64	xKernelVsid;	// Vsid used to map kernel load
-	} xEsids[HvEsidsToMap];
-	struct {
-		u64	xPages;		// Number of pages to be mapped
-		u64	xOffset;	// Offset from start of load area
-		u64	xVPN;		// Virtual Page Number
-	} xRanges[HvRangesToMap];
-};
-
-extern const struct LparMap	xLparMap;
-
-#endif /* __ASSEMBLY__ */
-
-/* the fixed address where the LparMap exists */
-#define LPARMAP_PHYS		0x7000
-
-#endif /* _ASM_POWERPC_ISERIES_LPAR_MAP_H */
diff --git a/arch/powerpc/include/asm/iseries/mf.h b/arch/powerpc/include/asm/iseries/mf.h
deleted file mode 100644
index eb851a9..0000000
--- a/arch/powerpc/include/asm/iseries/mf.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2001  Troy D. Armstrong IBM Corporation
- * Copyright (C) 2004  Stephen Rothwell IBM Corporation
- *
- * This modules exists as an interface between a Linux secondary partition
- * running on an iSeries and the primary partition's Virtual Service
- * Processor (VSP) object.  The VSP has final authority over powering on/off
- * all partitions in the iSeries.  It also provides miscellaneous low-level
- * machine facility type operations.
- *
- * 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
- */
-#ifndef _ASM_POWERPC_ISERIES_MF_H
-#define _ASM_POWERPC_ISERIES_MF_H
-
-#include <linux/types.h>
-
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_call_event.h>
-
-struct rtc_time;
-
-typedef void (*MFCompleteHandler)(void *clientToken, int returnCode);
-
-extern void mf_allocate_lp_events(HvLpIndex targetLp, HvLpEvent_Type type,
-		unsigned size, unsigned amount, MFCompleteHandler hdlr,
-		void *userToken);
-extern void mf_deallocate_lp_events(HvLpIndex targetLp, HvLpEvent_Type type,
-		unsigned count, MFCompleteHandler hdlr, void *userToken);
-
-extern void mf_power_off(void);
-extern void mf_reboot(char *cmd);
-
-extern void mf_display_src(u32 word);
-extern void mf_display_progress(u16 value);
-
-extern void mf_init(void);
-
-#endif /* _ASM_POWERPC_ISERIES_MF_H */
diff --git a/arch/powerpc/include/asm/iseries/vio.h b/arch/powerpc/include/asm/iseries/vio.h
deleted file mode 100644
index f9ac0d0..0000000
--- a/arch/powerpc/include/asm/iseries/vio.h
+++ /dev/null
@@ -1,265 +0,0 @@
-/* -*- linux-c -*-
- *
- *  iSeries Virtual I/O Message Path header
- *
- *  Authors: Dave Boutcher <boutcher@us.ibm.com>
- *           Ryan Arnold <ryanarn@us.ibm.com>
- *           Colin Devilbiss <devilbis@us.ibm.com>
- *
- * (C) Copyright 2000 IBM Corporation
- *
- * This header file is used by the iSeries virtual I/O device
- * drivers.  It defines the interfaces to the common functions
- * (implemented in drivers/char/viopath.h) as well as defining
- * common functions and structures.  Currently (at the time I
- * wrote this comment) the iSeries virtual I/O device drivers
- * that use this are
- *   drivers/block/viodasd.c
- *   drivers/char/viocons.c
- *   drivers/char/viotape.c
- *   drivers/cdrom/viocd.c
- *
- * The iSeries virtual ethernet support (veth.c) uses a whole
- * different set of functions.
- *
- * 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) anyu 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
- *
- */
-#ifndef _ASM_POWERPC_ISERIES_VIO_H
-#define _ASM_POWERPC_ISERIES_VIO_H
-
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-
-/*
- * iSeries virtual I/O events use the subtype field in
- * HvLpEvent to figure out what kind of vio event is coming
- * in.  We use a table to route these, and this defines
- * the maximum number of distinct subtypes
- */
-#define VIO_MAX_SUBTYPES 8
-
-#define VIOMAXBLOCKDMA	12
-
-struct open_data {
-	u64	disk_size;
-	u16	max_disk;
-	u16	cylinders;
-	u16	tracks;
-	u16	sectors;
-	u16	bytes_per_sector;
-};
-
-struct rw_data {
-	u64	offset;
-	struct {
-		u32	token;
-		u32	reserved;
-		u64	len;
-	} dma_info[VIOMAXBLOCKDMA];
-};
-
-struct vioblocklpevent {
-	struct HvLpEvent	event;
-	u32			reserved;
-	u16			version;
-	u16			sub_result;
-	u16			disk;
-	u16			flags;
-	union {
-		struct open_data	open_data;
-		struct rw_data		rw_data;
-		u64			changed;
-	} u;
-};
-
-#define vioblockflags_ro   0x0001
-
-enum vioblocksubtype {
-	vioblockopen = 0x0001,
-	vioblockclose = 0x0002,
-	vioblockread = 0x0003,
-	vioblockwrite = 0x0004,
-	vioblockflush = 0x0005,
-	vioblockcheck = 0x0007
-};
-
-struct viocdlpevent {
-	struct HvLpEvent	event;
-	u32			reserved;
-	u16			version;
-	u16			sub_result;
-	u16			disk;
-	u16			flags;
-	u32			token;
-	u64			offset;		/* On open, max number of disks */
-	u64			len;		/* On open, size of the disk */
-	u32			block_size;	/* Only set on open */
-	u32			media_size;	/* Only set on open */
-};
-
-enum viocdsubtype {
-	viocdopen = 0x0001,
-	viocdclose = 0x0002,
-	viocdread = 0x0003,
-	viocdwrite = 0x0004,
-	viocdlockdoor = 0x0005,
-	viocdgetinfo = 0x0006,
-	viocdcheck = 0x0007
-};
-
-struct viotapelpevent {
-	struct HvLpEvent event;
-	u32 reserved;
-	u16 version;
-	u16 sub_type_result;
-	u16 tape;
-	u16 flags;
-	u32 token;
-	u64 len;
-	union {
-		struct {
-			u32 tape_op;
-			u32 count;
-		} op;
-		struct {
-			u32 type;
-			u32 resid;
-			u32 dsreg;
-			u32 gstat;
-			u32 erreg;
-			u32 file_no;
-			u32 block_no;
-		} get_status;
-		struct {
-			u32 block_no;
-		} get_pos;
-	} u;
-};
-
-enum viotapesubtype {
-	viotapeopen = 0x0001,
-	viotapeclose = 0x0002,
-	viotaperead = 0x0003,
-	viotapewrite = 0x0004,
-	viotapegetinfo = 0x0005,
-	viotapeop = 0x0006,
-	viotapegetpos = 0x0007,
-	viotapesetpos = 0x0008,
-	viotapegetstatus = 0x0009
-};
-
-/*
- * Each subtype can register a handler to process their events.
- * The handler must have this interface.
- */
-typedef void (vio_event_handler_t) (struct HvLpEvent * event);
-
-extern int viopath_open(HvLpIndex remoteLp, int subtype, int numReq);
-extern int viopath_close(HvLpIndex remoteLp, int subtype, int numReq);
-extern int vio_setHandler(int subtype, vio_event_handler_t * beh);
-extern int vio_clearHandler(int subtype);
-extern int viopath_isactive(HvLpIndex lp);
-extern HvLpInstanceId viopath_sourceinst(HvLpIndex lp);
-extern HvLpInstanceId viopath_targetinst(HvLpIndex lp);
-extern void vio_set_hostlp(void);
-extern void *vio_get_event_buffer(int subtype);
-extern void vio_free_event_buffer(int subtype, void *buffer);
-
-extern struct vio_dev *vio_create_viodasd(u32 unit);
-
-extern HvLpIndex viopath_hostLp;
-extern HvLpIndex viopath_ourLp;
-
-#define VIOCHAR_MAX_DATA	200
-
-#define VIOMAJOR_SUBTYPE_MASK	0xff00
-#define VIOMINOR_SUBTYPE_MASK	0x00ff
-#define VIOMAJOR_SUBTYPE_SHIFT	8
-
-#define VIOVERSION		0x0101
-
-/*
- * This is the general structure for VIO errors; each module should have
- * a table of them, and each table should be terminated by an entry of
- * { 0, 0, NULL }.  Then, to find a specific error message, a module
- * should pass its local table and the return code.
- */
-struct vio_error_entry {
-	u16 rc;
-	int errno;
-	const char *msg;
-};
-extern const struct vio_error_entry *vio_lookup_rc(
-		const struct vio_error_entry *local_table, u16 rc);
-
-enum viosubtypes {
-	viomajorsubtype_monitor = 0x0100,
-	viomajorsubtype_blockio = 0x0200,
-	viomajorsubtype_chario = 0x0300,
-	viomajorsubtype_config = 0x0400,
-	viomajorsubtype_cdio = 0x0500,
-	viomajorsubtype_tape = 0x0600,
-	viomajorsubtype_scsi = 0x0700
-};
-
-enum vioconfigsubtype {
-	vioconfigget = 0x0001,
-};
-
-enum viorc {
-	viorc_good = 0x0000,
-	viorc_noConnection = 0x0001,
-	viorc_noReceiver = 0x0002,
-	viorc_noBufferAvailable = 0x0003,
-	viorc_invalidMessageType = 0x0004,
-	viorc_invalidRange = 0x0201,
-	viorc_invalidToken = 0x0202,
-	viorc_DMAError = 0x0203,
-	viorc_useError = 0x0204,
-	viorc_releaseError = 0x0205,
-	viorc_invalidDisk = 0x0206,
-	viorc_openRejected = 0x0301
-};
-
-/*
- * The structure of the events that flow between us and OS/400 for chario
- * events.  You can't mess with this unless the OS/400 side changes too.
- */
-struct viocharlpevent {
-	struct HvLpEvent event;
-	u32 reserved;
-	u16 version;
-	u16 subtype_result_code;
-	u8 virtual_device;
-	u8 len;
-	u8 data[VIOCHAR_MAX_DATA];
-};
-
-#define VIOCHAR_WINDOW		10
-
-enum viocharsubtype {
-	viocharopen = 0x0001,
-	viocharclose = 0x0002,
-	viochardata = 0x0003,
-	viocharack = 0x0004,
-	viocharconfig = 0x0005
-};
-
-enum viochar_rc {
-	viochar_rc_ebusy = 1
-};
-
-#endif /* _ASM_POWERPC_ISERIES_VIO_H */
diff --git a/arch/powerpc/include/asm/kvm.h b/arch/powerpc/include/asm/kvm.h
index f7727d9..b921c3f 100644
--- a/arch/powerpc/include/asm/kvm.h
+++ b/arch/powerpc/include/asm/kvm.h
@@ -265,12 +265,9 @@
 struct kvm_guest_debug_arch {
 };
 
-#define KVM_REG_MASK		0x001f
-#define KVM_REG_EXT_MASK	0xffe0
-#define KVM_REG_GPR		0x0000
-#define KVM_REG_FPR		0x0020
-#define KVM_REG_QPR		0x0040
-#define KVM_REG_FQPR		0x0060
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+};
 
 #define KVM_INTERRUPT_SET	-1U
 #define KVM_INTERRUPT_UNSET	-2U
@@ -292,4 +289,41 @@
 	__u64 rma_size;
 };
 
+struct kvm_book3e_206_tlb_entry {
+	__u32 mas8;
+	__u32 mas1;
+	__u64 mas2;
+	__u64 mas7_3;
+};
+
+struct kvm_book3e_206_tlb_params {
+	/*
+	 * For mmu types KVM_MMU_FSL_BOOKE_NOHV and KVM_MMU_FSL_BOOKE_HV:
+	 *
+	 * - The number of ways of TLB0 must be a power of two between 2 and
+	 *   16.
+	 * - TLB1 must be fully associative.
+	 * - The size of TLB0 must be a multiple of the number of ways, and
+	 *   the number of sets must be a power of two.
+	 * - The size of TLB1 may not exceed 64 entries.
+	 * - TLB0 supports 4 KiB pages.
+	 * - The page sizes supported by TLB1 are as indicated by
+	 *   TLB1CFG (if MMUCFG[MAVN] = 0) or TLB1PS (if MMUCFG[MAVN] = 1)
+	 *   as returned by KVM_GET_SREGS.
+	 * - TLB2 and TLB3 are reserved, and their entries in tlb_sizes[]
+	 *   and tlb_ways[] must be zero.
+	 *
+	 * tlb_ways[n] = tlb_sizes[n] means the array is fully associative.
+	 *
+	 * KVM will adjust TLBnCFG based on the sizes configured here,
+	 * though arrays greater than 2048 entries will have TLBnCFG[NENTRY]
+	 * set to zero.
+	 */
+	__u32 tlb_sizes[4];
+	__u32 tlb_ways[4];
+	__u32 reserved[8];
+};
+
+#define KVM_REG_PPC_HIOR	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1)
+
 #endif /* __LINUX_KVM_POWERPC_H */
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index 69c7377..aa795cc 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -90,6 +90,8 @@
 #endif
 	int context_id[SID_CONTEXTS];
 
+	bool hior_explicit;		/* HIOR is set by ioctl, not PVR */
+
 	struct hlist_head hpte_hash_pte[HPTEG_HASH_NUM_PTE];
 	struct hlist_head hpte_hash_pte_long[HPTEG_HASH_NUM_PTE_LONG];
 	struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE];
@@ -119,6 +121,11 @@
 extern int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte);
 extern int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr);
 extern void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu);
+extern int kvmppc_book3s_hv_page_fault(struct kvm_run *run,
+			struct kvm_vcpu *vcpu, unsigned long addr,
+			unsigned long status);
+extern long kvmppc_hv_find_lock_hpte(struct kvm *kvm, gva_t eaddr,
+			unsigned long slb_v, unsigned long valid);
 
 extern void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte);
 extern struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu);
@@ -138,6 +145,21 @@
 extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
 extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu);
 extern pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn);
+extern void kvmppc_add_revmap_chain(struct kvm *kvm, struct revmap_entry *rev,
+			unsigned long *rmap, long pte_index, int realmode);
+extern void kvmppc_invalidate_hpte(struct kvm *kvm, unsigned long *hptep,
+			unsigned long pte_index);
+void kvmppc_clear_ref_hpte(struct kvm *kvm, unsigned long *hptep,
+			unsigned long pte_index);
+extern void *kvmppc_pin_guest_page(struct kvm *kvm, unsigned long addr,
+			unsigned long *nb_ret);
+extern void kvmppc_unpin_guest_page(struct kvm *kvm, void *addr);
+extern long kvmppc_virtmode_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
+			long pte_index, unsigned long pteh, unsigned long ptel);
+extern long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
+			long pte_index, unsigned long pteh, unsigned long ptel);
+extern long kvmppc_hv_get_dirty_log(struct kvm *kvm,
+			struct kvm_memory_slot *memslot);
 
 extern void kvmppc_entry_trampoline(void);
 extern void kvmppc_hv_entry_trampoline(void);
@@ -183,7 +205,9 @@
 static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
 {
 	if ( num < 14 ) {
-		to_svcpu(vcpu)->gpr[num] = val;
+		struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+		svcpu->gpr[num] = val;
+		svcpu_put(svcpu);
 		to_book3s(vcpu)->shadow_vcpu->gpr[num] = val;
 	} else
 		vcpu->arch.gpr[num] = val;
@@ -191,80 +215,120 @@
 
 static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num)
 {
-	if ( num < 14 )
-		return to_svcpu(vcpu)->gpr[num];
-	else
+	if ( num < 14 ) {
+		struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+		ulong r = svcpu->gpr[num];
+		svcpu_put(svcpu);
+		return r;
+	} else
 		return vcpu->arch.gpr[num];
 }
 
 static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val)
 {
-	to_svcpu(vcpu)->cr = val;
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	svcpu->cr = val;
+	svcpu_put(svcpu);
 	to_book3s(vcpu)->shadow_vcpu->cr = val;
 }
 
 static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu)
 {
-	return to_svcpu(vcpu)->cr;
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	u32 r;
+	r = svcpu->cr;
+	svcpu_put(svcpu);
+	return r;
 }
 
 static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val)
 {
-	to_svcpu(vcpu)->xer = val;
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	svcpu->xer = val;
 	to_book3s(vcpu)->shadow_vcpu->xer = val;
+	svcpu_put(svcpu);
 }
 
 static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu)
 {
-	return to_svcpu(vcpu)->xer;
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	u32 r;
+	r = svcpu->xer;
+	svcpu_put(svcpu);
+	return r;
 }
 
 static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val)
 {
-	to_svcpu(vcpu)->ctr = val;
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	svcpu->ctr = val;
+	svcpu_put(svcpu);
 }
 
 static inline ulong kvmppc_get_ctr(struct kvm_vcpu *vcpu)
 {
-	return to_svcpu(vcpu)->ctr;
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	ulong r;
+	r = svcpu->ctr;
+	svcpu_put(svcpu);
+	return r;
 }
 
 static inline void kvmppc_set_lr(struct kvm_vcpu *vcpu, ulong val)
 {
-	to_svcpu(vcpu)->lr = val;
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	svcpu->lr = val;
+	svcpu_put(svcpu);
 }
 
 static inline ulong kvmppc_get_lr(struct kvm_vcpu *vcpu)
 {
-	return to_svcpu(vcpu)->lr;
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	ulong r;
+	r = svcpu->lr;
+	svcpu_put(svcpu);
+	return r;
 }
 
 static inline void kvmppc_set_pc(struct kvm_vcpu *vcpu, ulong val)
 {
-	to_svcpu(vcpu)->pc = val;
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	svcpu->pc = val;
+	svcpu_put(svcpu);
 }
 
 static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu)
 {
-	return to_svcpu(vcpu)->pc;
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	ulong r;
+	r = svcpu->pc;
+	svcpu_put(svcpu);
+	return r;
 }
 
 static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
 {
 	ulong pc = kvmppc_get_pc(vcpu);
-	struct kvmppc_book3s_shadow_vcpu *svcpu = to_svcpu(vcpu);
+	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);
 
-	return svcpu->last_inst;
+	r = svcpu->last_inst;
+	svcpu_put(svcpu);
+	return r;
 }
 
 static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
 {
-	return to_svcpu(vcpu)->fault_dar;
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	ulong r;
+	r = svcpu->fault_dar;
+	svcpu_put(svcpu);
+	return r;
 }
 
 static inline bool kvmppc_critical_section(struct kvm_vcpu *vcpu)
diff --git a/arch/powerpc/include/asm/kvm_book3s_32.h b/arch/powerpc/include/asm/kvm_book3s_32.h
index de604db..38040ff 100644
--- a/arch/powerpc/include/asm/kvm_book3s_32.h
+++ b/arch/powerpc/include/asm/kvm_book3s_32.h
@@ -20,11 +20,15 @@
 #ifndef __ASM_KVM_BOOK3S_32_H__
 #define __ASM_KVM_BOOK3S_32_H__
 
-static inline struct kvmppc_book3s_shadow_vcpu *to_svcpu(struct kvm_vcpu *vcpu)
+static inline struct kvmppc_book3s_shadow_vcpu *svcpu_get(struct kvm_vcpu *vcpu)
 {
 	return to_book3s(vcpu)->shadow_vcpu;
 }
 
+static inline void svcpu_put(struct kvmppc_book3s_shadow_vcpu *svcpu)
+{
+}
+
 #define PTE_SIZE	12
 #define VSID_ALL	0
 #define SR_INVALID	0x00000001	/* VSID 1 should always be unused */
diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
index d0ac94f..b0c08b1 100644
--- a/arch/powerpc/include/asm/kvm_book3s_64.h
+++ b/arch/powerpc/include/asm/kvm_book3s_64.h
@@ -21,14 +21,56 @@
 #define __ASM_KVM_BOOK3S_64_H__
 
 #ifdef CONFIG_KVM_BOOK3S_PR
-static inline struct kvmppc_book3s_shadow_vcpu *to_svcpu(struct kvm_vcpu *vcpu)
+static inline struct kvmppc_book3s_shadow_vcpu *svcpu_get(struct kvm_vcpu *vcpu)
 {
+	preempt_disable();
 	return &get_paca()->shadow_vcpu;
 }
+
+static inline void svcpu_put(struct kvmppc_book3s_shadow_vcpu *svcpu)
+{
+	preempt_enable();
+}
 #endif
 
 #define SPAPR_TCE_SHIFT		12
 
+#ifdef CONFIG_KVM_BOOK3S_64_HV
+/* For now use fixed-size 16MB page table */
+#define HPT_ORDER	24
+#define HPT_NPTEG	(1ul << (HPT_ORDER - 7))	/* 128B per pteg */
+#define HPT_NPTE	(HPT_NPTEG << 3)		/* 8 PTEs per PTEG */
+#define HPT_HASH_MASK	(HPT_NPTEG - 1)
+#endif
+
+#define VRMA_VSID	0x1ffffffUL	/* 1TB VSID reserved for VRMA */
+
+/*
+ * We use a lock bit in HPTE dword 0 to synchronize updates and
+ * accesses to each HPTE, and another bit to indicate non-present
+ * HPTEs.
+ */
+#define HPTE_V_HVLOCK	0x40UL
+#define HPTE_V_ABSENT	0x20UL
+
+static inline long try_lock_hpte(unsigned long *hpte, unsigned long bits)
+{
+	unsigned long tmp, old;
+
+	asm volatile("	ldarx	%0,0,%2\n"
+		     "	and.	%1,%0,%3\n"
+		     "	bne	2f\n"
+		     "	ori	%0,%0,%4\n"
+		     "  stdcx.	%0,0,%2\n"
+		     "	beq+	2f\n"
+		     "	li	%1,%3\n"
+		     "2:	isync"
+		     : "=&r" (tmp), "=&r" (old)
+		     : "r" (hpte), "r" (bits), "i" (HPTE_V_HVLOCK)
+		     : "cc", "memory");
+	return old == 0;
+}
+
 static inline unsigned long compute_tlbie_rb(unsigned long v, unsigned long r,
 					     unsigned long pte_index)
 {
@@ -62,4 +104,140 @@
 	return rb;
 }
 
+static inline unsigned long hpte_page_size(unsigned long h, unsigned long l)
+{
+	/* only handle 4k, 64k and 16M pages for now */
+	if (!(h & HPTE_V_LARGE))
+		return 1ul << 12;		/* 4k page */
+	if ((l & 0xf000) == 0x1000 && cpu_has_feature(CPU_FTR_ARCH_206))
+		return 1ul << 16;		/* 64k page */
+	if ((l & 0xff000) == 0)
+		return 1ul << 24;		/* 16M page */
+	return 0;				/* error */
+}
+
+static inline unsigned long hpte_rpn(unsigned long ptel, unsigned long psize)
+{
+	return ((ptel & HPTE_R_RPN) & ~(psize - 1)) >> PAGE_SHIFT;
+}
+
+static inline int hpte_is_writable(unsigned long ptel)
+{
+	unsigned long pp = ptel & (HPTE_R_PP0 | HPTE_R_PP);
+
+	return pp != PP_RXRX && pp != PP_RXXX;
+}
+
+static inline unsigned long hpte_make_readonly(unsigned long ptel)
+{
+	if ((ptel & HPTE_R_PP0) || (ptel & HPTE_R_PP) == PP_RWXX)
+		ptel = (ptel & ~HPTE_R_PP) | PP_RXXX;
+	else
+		ptel |= PP_RXRX;
+	return ptel;
+}
+
+static inline int hpte_cache_flags_ok(unsigned long ptel, unsigned long io_type)
+{
+	unsigned int wimg = ptel & HPTE_R_WIMG;
+
+	/* Handle SAO */
+	if (wimg == (HPTE_R_W | HPTE_R_I | HPTE_R_M) &&
+	    cpu_has_feature(CPU_FTR_ARCH_206))
+		wimg = HPTE_R_M;
+
+	if (!io_type)
+		return wimg == HPTE_R_M;
+
+	return (wimg & (HPTE_R_W | HPTE_R_I)) == io_type;
+}
+
+/*
+ * Lock and read a linux PTE.  If it's present and writable, atomically
+ * set dirty and referenced bits and return the PTE, otherwise return 0.
+ */
+static inline pte_t kvmppc_read_update_linux_pte(pte_t *p, int writing)
+{
+	pte_t pte, tmp;
+
+	/* wait until _PAGE_BUSY is clear then set it atomically */
+	__asm__ __volatile__ (
+		"1:	ldarx	%0,0,%3\n"
+		"	andi.	%1,%0,%4\n"
+		"	bne-	1b\n"
+		"	ori	%1,%0,%4\n"
+		"	stdcx.	%1,0,%3\n"
+		"	bne-	1b"
+		: "=&r" (pte), "=&r" (tmp), "=m" (*p)
+		: "r" (p), "i" (_PAGE_BUSY)
+		: "cc");
+
+	if (pte_present(pte)) {
+		pte = pte_mkyoung(pte);
+		if (writing && pte_write(pte))
+			pte = pte_mkdirty(pte);
+	}
+
+	*p = pte;	/* clears _PAGE_BUSY */
+
+	return pte;
+}
+
+/* Return HPTE cache control bits corresponding to Linux pte bits */
+static inline unsigned long hpte_cache_bits(unsigned long pte_val)
+{
+#if _PAGE_NO_CACHE == HPTE_R_I && _PAGE_WRITETHRU == HPTE_R_W
+	return pte_val & (HPTE_R_W | HPTE_R_I);
+#else
+	return ((pte_val & _PAGE_NO_CACHE) ? HPTE_R_I : 0) +
+		((pte_val & _PAGE_WRITETHRU) ? HPTE_R_W : 0);
+#endif
+}
+
+static inline bool hpte_read_permission(unsigned long pp, unsigned long key)
+{
+	if (key)
+		return PP_RWRX <= pp && pp <= PP_RXRX;
+	return 1;
+}
+
+static inline bool hpte_write_permission(unsigned long pp, unsigned long key)
+{
+	if (key)
+		return pp == PP_RWRW;
+	return pp <= PP_RWRW;
+}
+
+static inline int hpte_get_skey_perm(unsigned long hpte_r, unsigned long amr)
+{
+	unsigned long skey;
+
+	skey = ((hpte_r & HPTE_R_KEY_HI) >> 57) |
+		((hpte_r & HPTE_R_KEY_LO) >> 9);
+	return (amr >> (62 - 2 * skey)) & 3;
+}
+
+static inline void lock_rmap(unsigned long *rmap)
+{
+	do {
+		while (test_bit(KVMPPC_RMAP_LOCK_BIT, rmap))
+			cpu_relax();
+	} while (test_and_set_bit_lock(KVMPPC_RMAP_LOCK_BIT, rmap));
+}
+
+static inline void unlock_rmap(unsigned long *rmap)
+{
+	__clear_bit_unlock(KVMPPC_RMAP_LOCK_BIT, rmap);
+}
+
+static inline bool slot_is_aligned(struct kvm_memory_slot *memslot,
+				   unsigned long pagesize)
+{
+	unsigned long mask = (pagesize >> PAGE_SHIFT) - 1;
+
+	if (pagesize <= PAGE_SIZE)
+		return 1;
+	return !(memslot->base_gfn & mask) && !(memslot->npages & mask);
+}
+
 #endif /* __ASM_KVM_BOOK3S_64_H__ */
diff --git a/arch/powerpc/include/asm/kvm_e500.h b/arch/powerpc/include/asm/kvm_e500.h
index adbfca9..8cd50a5 100644
--- a/arch/powerpc/include/asm/kvm_e500.h
+++ b/arch/powerpc/include/asm/kvm_e500.h
@@ -22,46 +22,55 @@
 #define E500_PID_NUM   3
 #define E500_TLB_NUM   2
 
-struct tlbe{
-	u32 mas1;
-	u32 mas2;
-	u32 mas3;
-	u32 mas7;
-};
-
 #define E500_TLB_VALID 1
 #define E500_TLB_DIRTY 2
 
-struct tlbe_priv {
+struct tlbe_ref {
 	pfn_t pfn;
 	unsigned int flags; /* E500_TLB_* */
 };
 
+struct tlbe_priv {
+	struct tlbe_ref ref; /* TLB0 only -- TLB1 uses tlb_refs */
+};
+
 struct vcpu_id_table;
 
+struct kvmppc_e500_tlb_params {
+	int entries, ways, sets;
+};
+
 struct kvmppc_vcpu_e500 {
-	/* Unmodified copy of the guest's TLB. */
-	struct tlbe *gtlb_arch[E500_TLB_NUM];
+	/* Unmodified copy of the guest's TLB -- shared with host userspace. */
+	struct kvm_book3e_206_tlb_entry *gtlb_arch;
+
+	/* Starting entry number in gtlb_arch[] */
+	int gtlb_offset[E500_TLB_NUM];
 
 	/* KVM internal information associated with each guest TLB entry */
 	struct tlbe_priv *gtlb_priv[E500_TLB_NUM];
 
-	unsigned int gtlb_size[E500_TLB_NUM];
+	struct kvmppc_e500_tlb_params gtlb_params[E500_TLB_NUM];
+
 	unsigned int gtlb_nv[E500_TLB_NUM];
 
+	/*
+	 * information associated with each host TLB entry --
+	 * TLB1 only for now.  If/when guest TLB1 entries can be
+	 * mapped with host TLB0, this will be used for that too.
+	 *
+	 * We don't want to use this for guest TLB0 because then we'd
+	 * have the overhead of doing the translation again even if
+	 * the entry is still in the guest TLB (e.g. we swapped out
+	 * and back, and our host TLB entries got evicted).
+	 */
+	struct tlbe_ref *tlb_refs[E500_TLB_NUM];
+	unsigned int host_tlb1_nv;
+
 	u32 host_pid[E500_PID_NUM];
 	u32 pid[E500_PID_NUM];
 	u32 svr;
 
-	u32 mas0;
-	u32 mas1;
-	u32 mas2;
-	u32 mas3;
-	u32 mas4;
-	u32 mas5;
-	u32 mas6;
-	u32 mas7;
-
 	/* vcpu id table */
 	struct vcpu_id_table *idt;
 
@@ -73,6 +82,9 @@
 	u32 tlb1cfg;
 	u64 mcar;
 
+	struct page **shared_tlb_pages;
+	int num_shared_tlb_pages;
+
 	struct kvm_vcpu vcpu;
 };
 
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index bf8af5d..52eb9c1 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -32,17 +32,32 @@
 #include <linux/atomic.h>
 #include <asm/kvm_asm.h>
 #include <asm/processor.h>
+#include <asm/page.h>
 
 #define KVM_MAX_VCPUS		NR_CPUS
 #define KVM_MAX_VCORES		NR_CPUS
 #define KVM_MEMORY_SLOTS 32
 /* memory slots that does not exposed to userspace */
 #define KVM_PRIVATE_MEM_SLOTS 4
+#define KVM_MEM_SLOTS_NUM (KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS)
 
 #ifdef CONFIG_KVM_MMIO
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
 #endif
 
+#ifdef CONFIG_KVM_BOOK3S_64_HV
+#include <linux/mmu_notifier.h>
+
+#define KVM_ARCH_WANT_MMU_NOTIFIER
+
+struct kvm;
+extern int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
+extern int kvm_age_hva(struct kvm *kvm, unsigned long hva);
+extern int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
+extern void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
+
+#endif
+
 /* We don't currently support large pages. */
 #define KVM_HPAGE_GFN_SHIFT(x)	0
 #define KVM_NR_PAGE_SIZES	1
@@ -158,34 +173,72 @@
 	struct page *pages[0];
 };
 
-struct kvmppc_rma_info {
+struct kvmppc_linear_info {
 	void		*base_virt;
 	unsigned long	 base_pfn;
 	unsigned long	 npages;
 	struct list_head list;
-	atomic_t 	 use_count;
+	atomic_t	 use_count;
+	int		 type;
+};
+
+/*
+ * The reverse mapping array has one entry for each HPTE,
+ * which stores the guest's view of the second word of the HPTE
+ * (including the guest physical address of the mapping),
+ * plus forward and backward pointers in a doubly-linked ring
+ * of HPTEs that map the same host page.  The pointers in this
+ * ring are 32-bit HPTE indexes, to save space.
+ */
+struct revmap_entry {
+	unsigned long guest_rpte;
+	unsigned int forw, back;
+};
+
+/*
+ * We use the top bit of each memslot->rmap entry as a lock bit,
+ * and bit 32 as a present flag.  The bottom 32 bits are the
+ * index in the guest HPT of a HPTE that points to the page.
+ */
+#define KVMPPC_RMAP_LOCK_BIT	63
+#define KVMPPC_RMAP_RC_SHIFT	32
+#define KVMPPC_RMAP_REFERENCED	(HPTE_R_R << KVMPPC_RMAP_RC_SHIFT)
+#define KVMPPC_RMAP_CHANGED	(HPTE_R_C << KVMPPC_RMAP_RC_SHIFT)
+#define KVMPPC_RMAP_PRESENT	0x100000000ul
+#define KVMPPC_RMAP_INDEX	0xfffffffful
+
+/* Low-order bits in kvm->arch.slot_phys[][] */
+#define KVMPPC_PAGE_ORDER_MASK	0x1f
+#define KVMPPC_PAGE_NO_CACHE	HPTE_R_I	/* 0x20 */
+#define KVMPPC_PAGE_WRITETHRU	HPTE_R_W	/* 0x40 */
+#define KVMPPC_GOT_PAGE		0x80
+
+struct kvm_arch_memory_slot {
 };
 
 struct kvm_arch {
 #ifdef CONFIG_KVM_BOOK3S_64_HV
 	unsigned long hpt_virt;
-	unsigned long ram_npages;
-	unsigned long ram_psize;
-	unsigned long ram_porder;
-	struct kvmppc_pginfo *ram_pginfo;
+	struct revmap_entry *revmap;
 	unsigned int lpid;
 	unsigned int host_lpid;
 	unsigned long host_lpcr;
 	unsigned long sdr1;
 	unsigned long host_sdr1;
 	int tlbie_lock;
-	int n_rma_pages;
 	unsigned long lpcr;
 	unsigned long rmor;
-	struct kvmppc_rma_info *rma;
+	struct kvmppc_linear_info *rma;
+	unsigned long vrma_slb_v;
+	int rma_setup_done;
+	int using_mmu_notifiers;
 	struct list_head spapr_tce_tables;
+	spinlock_t slot_phys_lock;
+	unsigned long *slot_phys[KVM_MEM_SLOTS_NUM];
+	int slot_npages[KVM_MEM_SLOTS_NUM];
 	unsigned short last_vcpu[NR_CPUS];
 	struct kvmppc_vcore *vcores[KVM_MAX_VCORES];
+	struct kvmppc_linear_info *hpt_li;
 #endif /* CONFIG_KVM_BOOK3S_64_HV */
 };
 
@@ -318,10 +371,6 @@
 	u32 vrsave; /* also USPRG0 */
 	u32 mmucr;
 	ulong shadow_msr;
-	ulong sprg4;
-	ulong sprg5;
-	ulong sprg6;
-	ulong sprg7;
 	ulong csrr0;
 	ulong csrr1;
 	ulong dsrr0;
@@ -329,16 +378,14 @@
 	ulong mcsrr0;
 	ulong mcsrr1;
 	ulong mcsr;
-	ulong esr;
 	u32 dec;
 	u32 decar;
 	u32 tbl;
 	u32 tbu;
 	u32 tcr;
-	u32 tsr;
+	ulong tsr; /* we need to perform set/clr_bits() which requires ulong */
 	u32 ivor[64];
 	ulong ivpr;
-	u32 pir;
 	u32 pvr;
 
 	u32 shadow_pid;
@@ -427,9 +474,14 @@
 #ifdef CONFIG_KVM_BOOK3S_64_HV
 	struct kvm_vcpu_arch_shared shregs;
 
+	unsigned long pgfault_addr;
+	long pgfault_index;
+	unsigned long pgfault_hpte[2];
+
 	struct list_head run_list;
 	struct task_struct *run_task;
 	struct kvm_run *kvm_run;
+	pgd_t *pgdir;
 #endif
 };
 
@@ -438,4 +490,12 @@
 #define KVMPPC_VCPU_BUSY_IN_HOST	1
 #define KVMPPC_VCPU_RUNNABLE		2
 
+/* Values for vcpu->arch.io_gpr */
+#define KVM_MMIO_REG_MASK	0x001f
+#define KVM_MMIO_REG_EXT_MASK	0xffe0
+#define KVM_MMIO_REG_GPR	0x0000
+#define KVM_MMIO_REG_FPR	0x0020
+#define KVM_MMIO_REG_QPR	0x0040
+#define KVM_MMIO_REG_FQPR	0x0060
+
 #endif /* __POWERPC_KVM_HOST_H__ */
diff --git a/arch/powerpc/include/asm/kvm_para.h b/arch/powerpc/include/asm/kvm_para.h
index 50533f9..7b754e7 100644
--- a/arch/powerpc/include/asm/kvm_para.h
+++ b/arch/powerpc/include/asm/kvm_para.h
@@ -22,6 +22,16 @@
 
 #include <linux/types.h>
 
+/*
+ * Additions to this struct must only occur at the end, and should be
+ * accompanied by a KVM_MAGIC_FEAT flag to advertise that they are present
+ * (albeit not necessarily relevant to the current target hardware platform).
+ *
+ * Struct fields are always 32 or 64 bit aligned, depending on them being 32
+ * or 64 bit wide respectively.
+ *
+ * See Documentation/virtual/kvm/ppc-pv.txt
+ */
 struct kvm_vcpu_arch_shared {
 	__u64 scratch1;
 	__u64 scratch2;
@@ -33,11 +43,35 @@
 	__u64 sprg3;
 	__u64 srr0;
 	__u64 srr1;
-	__u64 dar;
+	__u64 dar;		/* dear on BookE */
 	__u64 msr;
 	__u32 dsisr;
 	__u32 int_pending;	/* Tells the guest if we have an interrupt */
 	__u32 sr[16];
+	__u32 mas0;
+	__u32 mas1;
+	__u64 mas7_3;
+	__u64 mas2;
+	__u32 mas4;
+	__u32 mas6;
+	__u32 esr;
+	__u32 pir;
+
+	/*
+	 * SPRG4-7 are user-readable, so we can only keep these consistent
+	 * between the shared area and the real registers when there's an
+	 * intervening exit to KVM.  This also applies to SPRG3 on some
+	 * chips.
+	 *
+	 * This suffices for access by guest userspace, since in PR-mode
+	 * KVM, an exit must occur when changing the guest's MSR[PR].
+	 * If the guest kernel writes to SPRG3-7 via the shared area, it
+	 * must also use the shared area for reading while in kernel space.
+	 */
+	__u64 sprg4;
+	__u64 sprg5;
+	__u64 sprg6;
+	__u64 sprg7;
 };
 
 #define KVM_SC_MAGIC_R0		0x4b564d21 /* "KVM!" */
@@ -47,7 +81,10 @@
 
 #define KVM_FEATURE_MAGIC_PAGE	1
 
-#define KVM_MAGIC_FEAT_SR	(1 << 0)
+#define KVM_MAGIC_FEAT_SR		(1 << 0)
+
+/* MASn, ESR, PIR, and high SPRGs */
+#define KVM_MAGIC_FEAT_MAS0_TO_SPRG7	(1 << 1)
 
 #ifdef __KERNEL__
 
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 46efd1a..9d6dee0 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -66,6 +66,7 @@
 extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu);
 extern void kvmppc_emulate_dec(struct kvm_vcpu *vcpu);
 extern u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb);
+extern void kvmppc_decrementer_func(unsigned long data);
 extern int kvmppc_sanity_check(struct kvm_vcpu *vcpu);
 
 /* Core-specific hooks */
@@ -94,7 +95,7 @@
 extern void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
 extern void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu);
 
-extern void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu);
+extern void kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu);
 extern int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu);
 extern void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong flags);
 extern void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu);
@@ -120,15 +121,17 @@
 extern void kvmppc_free_hpt(struct kvm *kvm);
 extern long kvmppc_prepare_vrma(struct kvm *kvm,
 				struct kvm_userspace_memory_region *mem);
-extern void kvmppc_map_vrma(struct kvm *kvm,
-			    struct kvm_userspace_memory_region *mem);
+extern void kvmppc_map_vrma(struct kvm_vcpu *vcpu,
+			struct kvm_memory_slot *memslot, unsigned long porder);
 extern int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu);
 extern long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
 				struct kvm_create_spapr_tce *args);
 extern long kvm_vm_ioctl_allocate_rma(struct kvm *kvm,
 				struct kvm_allocate_rma *rma);
-extern struct kvmppc_rma_info *kvm_alloc_rma(void);
-extern void kvm_release_rma(struct kvmppc_rma_info *ri);
+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 int kvmppc_core_init_vm(struct kvm *kvm);
 extern void kvmppc_core_destroy_vm(struct kvm *kvm);
 extern int kvmppc_core_prepare_memory_region(struct kvm *kvm,
@@ -175,6 +178,9 @@
 void kvmppc_get_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
 int kvmppc_set_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
 
+int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg);
+int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg);
+
 void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 pid);
 
 #ifdef CONFIG_KVM_BOOK3S_64_HV
@@ -183,14 +189,19 @@
 	paca[cpu].kvm_hstate.xics_phys = addr;
 }
 
-extern void kvm_rma_init(void);
+extern void kvm_linear_init(void);
 
 #else
 static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr)
 {}
 
-static inline void kvm_rma_init(void)
+static inline void kvm_linear_init(void)
 {}
 #endif
 
+int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu,
+			      struct kvm_config_tlb *cfg);
+int kvm_vcpu_ioctl_dirty_tlb(struct kvm_vcpu *vcpu,
+			     struct kvm_dirty_tlb *cfg);
+
 #endif /* __POWERPC_KVM_PPC_H__ */
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h
index e0298d2..a76254a 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -41,15 +41,7 @@
  * We only have to have statically allocated lppaca structs on
  * legacy iSeries, which supports at most 64 cpus.
  */
-#ifdef CONFIG_PPC_ISERIES
-#if NR_CPUS < 64
-#define NR_LPPACAS	NR_CPUS
-#else
-#define NR_LPPACAS	64
-#endif
-#else /* not iSeries */
 #define NR_LPPACAS	1
-#endif
 
 
 /* The Hypervisor barfs if the lppaca crosses a page boundary.  A 1k
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index bf37931d..42ce570 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -99,9 +99,7 @@
 
 	void		(*init_IRQ)(void);
 
-	/* Return an irq, or NO_IRQ to indicate there are none pending.
-	 * If for some reason there is no irq, but the interrupt
-	 * shouldn't be counted as spurious, return NO_IRQ_IGNORE. */
+	/* Return an irq, or NO_IRQ to indicate there are none pending. */
 	unsigned int	(*get_irq)(void);
 
 	/* PCI stuff */
diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h
index f5f89ca..cdb54218 100644
--- a/arch/powerpc/include/asm/mmu-book3e.h
+++ b/arch/powerpc/include/asm/mmu-book3e.h
@@ -41,9 +41,10 @@
 /* MAS registers bit definitions */
 
 #define MAS0_TLBSEL(x)		(((x) << 28) & 0x30000000)
-#define MAS0_ESEL(x)		(((x) << 16) & 0x0FFF0000)
-#define MAS0_NV(x)		((x) & 0x00000FFF)
 #define MAS0_ESEL_MASK		0x0FFF0000
+#define MAS0_ESEL_SHIFT		16
+#define MAS0_ESEL(x)		(((x) << MAS0_ESEL_SHIFT) & MAS0_ESEL_MASK)
+#define MAS0_NV(x)		((x) & 0x00000FFF)
 #define MAS0_HES		0x00004000
 #define MAS0_WQ_ALLWAYS		0x00000000
 #define MAS0_WQ_COND		0x00001000
@@ -167,6 +168,7 @@
 #define TLBnCFG_MAXSIZE		0x000f0000	/* Maximum Page Size (v1.0) */
 #define TLBnCFG_MAXSIZE_SHIFT	16
 #define TLBnCFG_ASSOC		0xff000000	/* Associativity */
+#define TLBnCFG_ASSOC_SHIFT	24
 
 /* TLBnPS encoding */
 #define TLBnPS_4K		0x00000004
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h
index 412ba49..1c65a59 100644
--- a/arch/powerpc/include/asm/mmu-hash64.h
+++ b/arch/powerpc/include/asm/mmu-hash64.h
@@ -108,11 +108,11 @@
 #define HPTE_V_VRMA_MASK	ASM_CONST(0x4001ffffff000000)
 
 /* Values for PP (assumes Ks=0, Kp=1) */
-/* pp0 will always be 0 for linux     */
 #define PP_RWXX	0	/* Supervisor read/write, User none */
 #define PP_RWRX 1	/* Supervisor read/write, User read */
 #define PP_RWRW 2	/* Supervisor read/write, User read/write */
 #define PP_RXRX 3	/* Supervisor read,       User read */
+#define PP_RXXX	(HPTE_R_PP0 | 2)	/* Supervisor read, user none */
 
 #ifndef __ASSEMBLY__
 
@@ -267,7 +267,6 @@
 
 extern void hpte_init_native(void);
 extern void hpte_init_lpar(void);
-extern void hpte_init_iSeries(void);
 extern void hpte_init_beat(void);
 extern void hpte_init_beat_v3(void);
 
@@ -325,9 +324,6 @@
  * WARNING - If you change these you must make sure the asm
  * implementations in slb_allocate (slb_low.S), do_stab_bolted
  * (head.S) and ASM_VSID_SCRAMBLE (below) are changed accordingly.
- *
- * You'll also need to change the precomputed VSID values in head.S
- * which are used by the iSeries firmware.
  */
 
 #define VSID_MULTIPLIER_256M	ASM_CONST(200730139)	/* 28-bit prime */
@@ -484,14 +480,6 @@
 			     | (ea >> SID_SHIFT_1T), 1T);
 }
 
-/*
- * This is only used on legacy iSeries in lparmap.c,
- * hence the 256MB segment assumption.
- */
-#define VSID_SCRAMBLE(pvsid)	(((pvsid) * VSID_MULTIPLIER_256M) %	\
-				 VSID_MODULUS_256M)
-#define KERNEL_VSID(ea)		VSID_SCRAMBLE(GET_ESID(ea))
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_MMU_HASH64_H_ */
diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
index a5b7c56..c65b929 100644
--- a/arch/powerpc/include/asm/mpic.h
+++ b/arch/powerpc/include/asm/mpic.h
@@ -273,7 +273,6 @@
 	unsigned int		isu_size;
 	unsigned int		isu_shift;
 	unsigned int		isu_mask;
-	unsigned int		irq_count;
 	/* Number of sources */
 	unsigned int		num_sources;
 	/* default senses array */
@@ -349,8 +348,6 @@
 #define MPIC_U3_HT_IRQS			0x00000004
 /* Broken IPI registers (autodetected) */
 #define MPIC_BROKEN_IPI			0x00000008
-/* MPIC wants a reset */
-#define MPIC_WANTS_RESET		0x00000010
 /* Spurious vector requires EOI */
 #define MPIC_SPV_EOI			0x00000020
 /* No passthrough disable */
@@ -363,15 +360,11 @@
 #define MPIC_ENABLE_MCK			0x00000200
 /* Disable bias among target selection, spread interrupts evenly */
 #define MPIC_NO_BIAS			0x00000400
-/* Ignore NIRQS as reported by FRR */
-#define MPIC_BROKEN_FRR_NIRQS		0x00000800
 /* Destination only supports a single CPU at a time */
 #define MPIC_SINGLE_DEST_CPU		0x00001000
 /* Enable CoreInt delivery of interrupts */
 #define MPIC_ENABLE_COREINT		0x00002000
-/* Disable resetting of the MPIC.
- * NOTE: This flag trumps MPIC_WANTS_RESET.
- */
+/* Do not reset the MPIC during initialization */
 #define MPIC_NO_RESET			0x00004000
 /* Freescale MPIC (compatible includes "fsl,mpic") */
 #define MPIC_FSL			0x00008000
diff --git a/arch/powerpc/include/asm/mpic_msgr.h b/arch/powerpc/include/asm/mpic_msgr.h
new file mode 100644
index 0000000..3ec37dc
--- /dev/null
+++ b/arch/powerpc/include/asm/mpic_msgr.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2011-2012, Meador Inge, Mentor Graphics 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; version 2 of the
+ * License.
+ *
+ */
+
+#ifndef _ASM_MPIC_MSGR_H
+#define _ASM_MPIC_MSGR_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+struct mpic_msgr {
+	u32 __iomem *base;
+	u32 __iomem *mer;
+	int irq;
+	unsigned char in_use;
+	raw_spinlock_t lock;
+	int num;
+};
+
+/* Get a message register
+ *
+ * @reg_num:	the MPIC message register to get
+ *
+ * A pointer to the message register is returned.  If
+ * the message register asked for is already in use, then
+ * EBUSY is returned.  If the number given is not associated
+ * with an actual message register, then ENODEV is returned.
+ * Successfully getting the register marks it as in use.
+ */
+extern struct mpic_msgr *mpic_msgr_get(unsigned int reg_num);
+
+/* Relinquish a message register
+ *
+ * @msgr:	the message register to return
+ *
+ * Disables the given message register and marks it as free.
+ * After this call has completed successully the message
+ * register is available to be acquired by a call to
+ * mpic_msgr_get.
+ */
+extern void mpic_msgr_put(struct mpic_msgr *msgr);
+
+/* Enable a message register
+ *
+ * @msgr:	the message register to enable
+ *
+ * The given message register is enabled for sending
+ * messages.
+ */
+extern void mpic_msgr_enable(struct mpic_msgr *msgr);
+
+/* Disable a message register
+ *
+ * @msgr:	the message register to disable
+ *
+ * The given message register is disabled for sending
+ * messages.
+ */
+extern void mpic_msgr_disable(struct mpic_msgr *msgr);
+
+/* Write a message to a message register
+ *
+ * @msgr:	the message register to write to
+ * @message:	the message to write
+ *
+ * The given 32-bit message is written to the given message
+ * register.  Writing to an enabled message registers fires
+ * an interrupt.
+ */
+static inline void mpic_msgr_write(struct mpic_msgr *msgr, u32 message)
+{
+	out_be32(msgr->base, message);
+}
+
+/* Read a message from a message register
+ *
+ * @msgr:	the message register to read from
+ *
+ * Returns the 32-bit value currently in the given message register.
+ * Upon reading the register any interrupts for that register are
+ * cleared.
+ */
+static inline u32 mpic_msgr_read(struct mpic_msgr *msgr)
+{
+	return in_be32(msgr->base);
+}
+
+/* Clear a message register
+ *
+ * @msgr:	the message register to clear
+ *
+ * Clears any interrupts associated with the given message register.
+ */
+static inline void mpic_msgr_clear(struct mpic_msgr *msgr)
+{
+	(void) mpic_msgr_read(msgr);
+}
+
+/* Set the destination CPU for the message register
+ *
+ * @msgr:	the message register whose destination is to be set
+ * @cpu_num:	the Linux CPU number to bind the message register to
+ *
+ * Note that the CPU number given is the CPU number used by the kernel
+ * and *not* the actual hardware CPU number.
+ */
+static inline void mpic_msgr_set_destination(struct mpic_msgr *msgr,
+					     u32 cpu_num)
+{
+	out_be32(msgr->base, 1 << get_hard_smp_processor_id(cpu_num));
+}
+
+/* Get the IRQ number for the message register
+ * @msgr:	the message register whose IRQ is to be returned
+ *
+ * Returns the IRQ number associated with the given message register.
+ * NO_IRQ is returned if this message register is not capable of
+ * receiving interrupts.  What message register can and cannot receive
+ * interrupts is specified in the device tree for the system.
+ */
+static inline int mpic_msgr_get_irq(struct mpic_msgr *msgr)
+{
+	return msgr->irq;
+}
+
+#endif
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index 269c05a3..daf813f 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -132,7 +132,7 @@
 	u64 saved_msr;			/* MSR saved here by enter_rtas */
 	u16 trap_save;			/* Used when bad stack is encountered */
 	u8 soft_enabled;		/* irq soft-enable flag */
-	u8 hard_enabled;		/* set if irqs are enabled in MSR */
+	u8 irq_happened;		/* irq happened while soft-disabled */
 	u8 io_sync;			/* writel() needs spin_unlock sync */
 	u8 irq_work_pending;		/* IRQ_WORK interrupt while soft-disable */
 	u8 nap_state_lost;		/* NV GPR values lost in power7_idle */
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 5d48765..ac39e6a 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -155,14 +155,7 @@
 
 	struct	pci_dev *pcidev;	/* back-pointer to the pci device */
 #ifdef CONFIG_EEH
-	int	class_code;		/* pci device class */
-	int	eeh_mode;		/* See eeh.h for possible EEH_MODEs */
-	int	eeh_config_addr;
-	int	eeh_pe_config_addr; /* new-style partition endpoint address */
-	int	eeh_check_count;	/* # times driver ignored error */
-	int	eeh_freeze_count;	/* # times this device froze up. */
-	int	eeh_false_positives;	/* # times this device reported #ff's */
-	u32	config_space[16];	/* saved PCI config space */
+	struct eeh_dev *edev;		/* eeh device */
 #endif
 #define IODA_INVALID_PE		(-1)
 #ifdef CONFIG_PPC_POWERNV
@@ -185,6 +178,13 @@
 	return 0;
 }
 
+#if defined(CONFIG_EEH)
+static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn)
+{
+	return PCI_DN(dn)->edev;
+}
+#endif
+
 /** Find the bus corresponding to the indicated device node */
 extern struct pci_bus *pcibios_find_pci_bus(struct device_node *dn);
 
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index f54b3d2..6653f27 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -154,14 +154,6 @@
 
 #endif /* CONFIG_PPC64 */
 
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
-			struct pci_bus_region *region,
-			struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev,
-			struct resource *res,
-			struct pci_bus_region *region);
-
 extern void pcibios_claim_one_bus(struct pci_bus *b);
 
 extern void pcibios_finish_adding_to_bus(struct pci_bus *bus);
@@ -190,6 +182,7 @@
 				 const struct resource *rsrc,
 				 resource_size_t *start, resource_size_t *end);
 
+extern resource_size_t pcibios_io_space_offset(struct pci_controller *hose);
 extern void pcibios_setup_bus_devices(struct pci_bus *bus);
 extern void pcibios_setup_bus_self(struct pci_bus *bus);
 extern void pcibios_setup_phb_io_space(struct pci_controller *hose);
diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h
index 1a8093f..078019b 100644
--- a/arch/powerpc/include/asm/perf_event_server.h
+++ b/arch/powerpc/include/asm/perf_event_server.h
@@ -47,6 +47,8 @@
  */
 #define PPMU_LIMITED_PMC5_6	1	/* PMC5/6 have limited function */
 #define PPMU_ALT_SIPR		2	/* uses alternate posn for SIPR/HV */
+#define PPMU_NO_SIPR		4	/* no SIPR/HV in MMCRA at all */
+#define PPMU_NO_CONT_SAMPLING	8	/* no continuous sampling */
 
 /*
  * Values for flags to get_alternatives()
diff --git a/arch/powerpc/include/asm/phyp_dump.h b/arch/powerpc/include/asm/phyp_dump.h
deleted file mode 100644
index fa74c6c..0000000
--- a/arch/powerpc/include/asm/phyp_dump.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Hypervisor-assisted dump
- *
- * Linas Vepstas, Manish Ahuja 2008
- * Copyright 2008 IBM Corp.
- *
- *      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 _PPC64_PHYP_DUMP_H
-#define _PPC64_PHYP_DUMP_H
-
-#ifdef CONFIG_PHYP_DUMP
-
-/* The RMR region will be saved for later dumping
- * whenever the kernel crashes. Set this to 256MB. */
-#define PHYP_DUMP_RMR_START 0x0
-#define PHYP_DUMP_RMR_END   (1UL<<28)
-
-struct phyp_dump {
-	/* Memory that is reserved during very early boot. */
-	unsigned long init_reserve_start;
-	unsigned long init_reserve_size;
-	/* cmd line options during boot */
-	unsigned long reserve_bootvar;
-	unsigned long phyp_dump_at_boot;
-	/* Check status during boot if dump supported, active & present*/
-	unsigned long phyp_dump_configured;
-	unsigned long phyp_dump_is_active;
-	/* store cpu & hpte size */
-	unsigned long cpu_state_size;
-	unsigned long hpte_region_size;
-	/* previous scratch area values */
-	unsigned long reserved_scratch_addr;
-	unsigned long reserved_scratch_size;
-};
-
-extern struct phyp_dump *phyp_dump_info;
-
-int early_init_dt_scan_phyp_dump(unsigned long node,
-		const char *uname, int depth, void *data);
-
-#endif /* CONFIG_PHYP_DUMP */
-#endif /* _PPC64_PHYP_DUMP_H */
diff --git a/arch/powerpc/include/asm/posix_types.h b/arch/powerpc/include/asm/posix_types.h
index c4e396b..f139325 100644
--- a/arch/powerpc/include/asm/posix_types.h
+++ b/arch/powerpc/include/asm/posix_types.h
@@ -7,122 +7,22 @@
  * assume GCC is being used.
  */
 
-typedef unsigned long	__kernel_ino_t;
-typedef unsigned int	__kernel_mode_t;
-typedef long		__kernel_off_t;
-typedef int		__kernel_pid_t;
-typedef unsigned int	__kernel_uid_t;
-typedef unsigned int	__kernel_gid_t;
-typedef long		__kernel_ptrdiff_t;
-typedef long		__kernel_time_t;
-typedef long		__kernel_clock_t;
-typedef int		__kernel_timer_t;
-typedef int		__kernel_clockid_t;
-typedef long		__kernel_suseconds_t;
-typedef int		__kernel_daddr_t;
-typedef char *		__kernel_caddr_t;
-typedef unsigned short	__kernel_uid16_t;
-typedef unsigned short	__kernel_gid16_t;
-typedef unsigned int	__kernel_uid32_t;
-typedef unsigned int	__kernel_gid32_t;
-typedef unsigned int	__kernel_old_uid_t;
-typedef unsigned int	__kernel_old_gid_t;
-
 #ifdef __powerpc64__
-typedef unsigned long  	__kernel_nlink_t;
-typedef int             __kernel_ipc_pid_t;
-typedef unsigned long	__kernel_size_t;
-typedef long		__kernel_ssize_t;
 typedef unsigned long	__kernel_old_dev_t;
+#define __kernel_old_dev_t __kernel_old_dev_t
 #else
-typedef unsigned short	__kernel_nlink_t;
-typedef short		__kernel_ipc_pid_t;
 typedef unsigned int	__kernel_size_t;
 typedef int		__kernel_ssize_t;
-typedef unsigned int	__kernel_old_dev_t;
+typedef long		__kernel_ptrdiff_t;
+#define __kernel_size_t __kernel_size_t
+
+typedef unsigned short	__kernel_nlink_t;
+#define __kernel_nlink_t __kernel_nlink_t
+
+typedef short		__kernel_ipc_pid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
 #endif
 
-#ifdef __powerpc64__
-typedef long long	__kernel_loff_t;
-#else
-#ifdef __GNUC__
-typedef long long	__kernel_loff_t;
-#endif
-#endif
+#include <asm-generic/posix_types.h>
 
-typedef struct {
-	int	val[2];
-} __kernel_fsid_t;
-
-#ifndef __GNUC__
-
-#define	__FD_SET(d, set)	((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
-#define	__FD_CLR(d, set)	((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
-#define	__FD_ISSET(d, set)	(((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) != 0)
-#define	__FD_ZERO(set)	\
-  ((void) memset ((void *) (set), 0, sizeof (__kernel_fd_set)))
-
-#else /* __GNUC__ */
-
-#if defined(__KERNEL__)
-/* With GNU C, use inline functions instead so args are evaluated only once: */
-
-#undef __FD_SET
-static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	fdsetp->fds_bits[_tmp] |= (1UL<<_rem);
-}
-
-#undef __FD_CLR
-static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem);
-}
-
-#undef __FD_ISSET
-static __inline__ int __FD_ISSET(unsigned long fd, __kernel_fd_set *p)
-{ 
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0;
-}
-
-/*
- * This will unroll the loop for the normal constant case (8 ints,
- * for a 256-bit fd_set)
- */
-#undef __FD_ZERO
-static __inline__ void __FD_ZERO(__kernel_fd_set *p)
-{
-	unsigned long *tmp = (unsigned long *)p->fds_bits;
-	int i;
-
-	if (__builtin_constant_p(__FDSET_LONGS)) {
-		switch (__FDSET_LONGS) {
-		      case 16:
-			tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
-			tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
-
-		      case 8:
-			tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
-
-		      case 4:
-			tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
-			return;
-		}
-	}
-	i = __FDSET_LONGS;
-	while (i) {
-		i--;
-		*tmp = 0;
-		tmp++;
-	}
-}
-
-#endif /* defined(__KERNEL__) */
-#endif /* __GNUC__ */
 #endif /* _ASM_POWERPC_POSIX_TYPES_H */
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index e980faa..d81f994 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -45,6 +45,7 @@
 #define PPC_INST_MFSPR_DSCR_MASK	0xfc1fffff
 #define PPC_INST_MTSPR_DSCR		0x7c1103a6
 #define PPC_INST_MTSPR_DSCR_MASK	0xfc1fffff
+#define PPC_INST_SLBFEE			0x7c0007a7
 
 #define PPC_INST_STRING			0x7c00042a
 #define PPC_INST_STRING_MASK		0xfc0007fe
@@ -183,7 +184,8 @@
 					__PPC_RS(t) | __PPC_RA(a) | __PPC_RB(b))
 #define PPC_ERATSX_DOT(t, a, w)	stringify_in_c(.long PPC_INST_ERATSX_DOT | \
 					__PPC_RS(t) | __PPC_RA(a) | __PPC_RB(b))
-
+#define PPC_SLBFEE_DOT(t, b)	stringify_in_c(.long PPC_INST_SLBFEE | \
+					__PPC_RT(t) | __PPC_RB(b))
 
 /*
  * Define what the VSX XX1 form instructions will look like, then add
diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h
index 6d42297..80fa704 100644
--- a/arch/powerpc/include/asm/ppc-pci.h
+++ b/arch/powerpc/include/asm/ppc-pci.h
@@ -45,94 +45,21 @@
 extern unsigned long get_phb_buid (struct device_node *);
 extern int rtas_setup_phb(struct pci_controller *phb);
 
-extern unsigned long pci_probe_only;
-
-/* ---- EEH internal-use-only related routines ---- */
 #ifdef CONFIG_EEH
 
+void pci_addr_cache_build(void);
 void pci_addr_cache_insert_device(struct pci_dev *dev);
 void pci_addr_cache_remove_device(struct pci_dev *dev);
-void pci_addr_cache_build(void);
-struct pci_dev *pci_get_device_by_addr(unsigned long addr);
-
-/**
- * eeh_slot_error_detail -- record and EEH error condition to the log
- * @pdn:      pci device node
- * @severity: EEH_LOG_TEMP_FAILURE or EEH_LOG_PERM_FAILURE
- *
- * Obtains the EEH error details from the RTAS subsystem,
- * and then logs these details with the RTAS error log system.
- */
-#define EEH_LOG_TEMP_FAILURE 1
-#define EEH_LOG_PERM_FAILURE 2
-void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
-
-/**
- * rtas_pci_enable - enable IO transfers for this slot
- * @pdn:       pci device node
- * @function:  either EEH_THAW_MMIO or EEH_THAW_DMA 
- *
- * Enable I/O transfers to this slot 
- */
-#define EEH_THAW_MMIO 2
-#define EEH_THAW_DMA  3
-int rtas_pci_enable(struct pci_dn *pdn, int function);
-
-/**
- * rtas_set_slot_reset -- unfreeze a frozen slot
- * @pdn:       pci device node
- *
- * Clear the EEH-frozen condition on a slot.  This routine
- * does this by asserting the PCI #RST line for 1/8th of
- * a second; this routine will sleep while the adapter is
- * being reset.
- *
- * Returns a non-zero value if the reset failed.
- */
-int rtas_set_slot_reset (struct pci_dn *);
-int eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs);
-
-/** 
- * eeh_restore_bars - Restore device configuration info.
- * @pdn:       pci device node
- *
- * A reset of a PCI device will clear out its config space.
- * This routines will restore the config space for this
- * device, and is children, to values previously obtained
- * from the firmware.
- */
-void eeh_restore_bars(struct pci_dn *);
-
-/**
- * rtas_configure_bridge -- firmware initialization of pci bridge
- * @pdn:       pci device node
- *
- * Ask the firmware to configure all PCI bridges devices
- * located behind the indicated node. Required after a
- * pci device reset. Does essentially the same hing as
- * eeh_restore_bars, but for brdges, and lets firmware 
- * do the work.
- */
-void rtas_configure_bridge(struct pci_dn *);
-
+struct pci_dev *pci_addr_cache_get_device(unsigned long addr);
+void eeh_slot_error_detail(struct eeh_dev *edev, int severity);
+int eeh_pci_enable(struct eeh_dev *edev, int function);
+int eeh_reset_pe(struct eeh_dev *);
+void eeh_restore_bars(struct eeh_dev *);
 int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
 int rtas_read_config(struct pci_dn *, int where, int size, u32 *val);
-
-/**
- * eeh_mark_slot -- set mode flags for pertition endpoint
- * @pdn:       pci device node
- *
- * mark and clear slots: find "partition endpoint" PE and set or 
- * clear the flags for each subnode of the PE.
- */
-void eeh_mark_slot (struct device_node *dn, int mode_flag);
-void eeh_clear_slot (struct device_node *dn, int mode_flag);
-
-/**
- * find_device_pe -- Find the associated "Partiationable Endpoint" PE
- * @pdn:       pci device node
- */
-struct device_node * find_device_pe(struct device_node *dn);
+void eeh_mark_slot(struct device_node *dn, int mode_flag);
+void eeh_clear_slot(struct device_node *dn, int mode_flag);
+struct device_node *eeh_find_device_pe(struct device_node *dn);
 
 void eeh_sysfs_add_device(struct pci_dev *pdev);
 void eeh_sysfs_remove_device(struct pci_dev *pdev);
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index 368f72f..50f73aa 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -60,6 +60,8 @@
 	cmpd	cr1,r11,r10;						\
 	beq+	cr1,33f;						\
 	bl	.accumulate_stolen_time;				\
+	ld	r12,_MSR(r1);						\
+	andi.	r10,r12,MSR_PR;		/* Restore cr0 (coming from user) */ \
 33:									\
 END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
 
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index b585bff..8e2d037 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -385,6 +385,36 @@
 extern unsigned long cpuidle_disable;
 enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};
 
+extern int powersave_nap;	/* set if nap mode can be used in idle loop */
+void cpu_idle_wait(void);
+
+#ifdef CONFIG_PSERIES_IDLE
+extern void update_smt_snooze_delay(int snooze);
+extern int pseries_notify_cpuidle_add_cpu(int cpu);
+#else
+static inline void update_smt_snooze_delay(int snooze) {}
+static inline int pseries_notify_cpuidle_add_cpu(int cpu) { return 0; }
+#endif
+
+extern void flush_instruction_cache(void);
+extern void hard_reset_now(void);
+extern void poweroff_now(void);
+extern int fix_alignment(struct pt_regs *);
+extern void cvt_fd(float *from, double *to);
+extern void cvt_df(double *from, float *to);
+extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
+
+#ifdef CONFIG_PPC64
+/*
+ * We handle most unaligned accesses in hardware. On the other hand 
+ * unaligned DMA can be very expensive on some ppc64 IO chips (it does
+ * powers of 2 writes until it reaches sufficient alignment).
+ *
+ * Based on this we disable the IP header alignment in network drivers.
+ */
+#define NET_IP_ALIGN	0
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_POWERPC_PROCESSOR_H */
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 7fdc2c0..9d7f0fb 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -216,6 +216,7 @@
 #define   DSISR_ISSTORE		0x02000000	/* access was a store */
 #define   DSISR_DABRMATCH	0x00400000	/* hit data breakpoint */
 #define   DSISR_NOSEGMENT	0x00200000	/* STAB/SLB miss */
+#define   DSISR_KEYFAULT	0x00200000	/* Key fault */
 #define SPRN_TBRL	0x10C	/* Time Base Read Lower Register (user, R/O) */
 #define SPRN_TBRU	0x10D	/* Time Base Read Upper Register (user, R/O) */
 #define SPRN_TBWL	0x11C	/* Time Base Lower Register (super, R/W) */
@@ -237,6 +238,7 @@
 #define   LPCR_ISL	(1ul << (63-2))
 #define   LPCR_VC_SH	(63-2)
 #define   LPCR_DPFD_SH	(63-11)
+#define   LPCR_VRMASD	(0x1ful << (63-16))
 #define   LPCR_VRMA_L	(1ul << (63-12))
 #define   LPCR_VRMA_LP0	(1ul << (63-15))
 #define   LPCR_VRMA_LP1	(1ul << (63-16))
@@ -493,6 +495,9 @@
 #define SPRN_SPRG7	0x117	/* Special Purpose Register General 7 */
 #define SPRN_SRR0	0x01A	/* Save/Restore Register 0 */
 #define SPRN_SRR1	0x01B	/* Save/Restore Register 1 */
+#define   SRR1_ISI_NOPT		0x40000000 /* ISI: Not found in hash */
+#define   SRR1_ISI_N_OR_G	0x10000000 /* ISI: Access is no-exec or G */
+#define   SRR1_ISI_PROT		0x08000000 /* ISI: Other protection fault */
 #define   SRR1_WAKEMASK		0x00380000 /* reason for wakeup */
 #define   SRR1_WAKESYSERR	0x00300000 /* System error */
 #define   SRR1_WAKEEE		0x00200000 /* External interrupt */
@@ -1079,30 +1084,12 @@
 
 #define proc_trap()	asm volatile("trap")
 
-#ifdef CONFIG_PPC64
-
-extern void ppc64_runlatch_on(void);
-extern void __ppc64_runlatch_off(void);
-
-#define ppc64_runlatch_off()					\
-	do {							\
-		if (cpu_has_feature(CPU_FTR_CTRL) &&		\
-		    test_thread_flag(TIF_RUNLATCH))		\
-			__ppc64_runlatch_off();			\
-	} while (0)
+#define __get_SP()	({unsigned long sp; \
+			asm volatile("mr %0,1": "=r" (sp)); sp;})
 
 extern unsigned long scom970_read(unsigned int address);
 extern void scom970_write(unsigned int address, unsigned long value);
 
-#else
-#define ppc64_runlatch_on()
-#define ppc64_runlatch_off()
-
-#endif /* CONFIG_PPC64 */
-
-#define __get_SP()	({unsigned long sp; \
-			asm volatile("mr %0,1": "=r" (sp)); sp;})
-
 struct pt_regs;
 
 extern void ppc_save_regs(struct pt_regs *regs);
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index 500fe1d..b86faa9 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -15,6 +15,11 @@
 #ifndef __ASM_POWERPC_REG_BOOKE_H__
 #define __ASM_POWERPC_REG_BOOKE_H__
 
+#ifdef CONFIG_BOOKE_WDT
+extern u32 booke_wdt_enabled;
+extern u32 booke_wdt_period;
+#endif /* CONFIG_BOOKE_WDT */
+
 /* Machine State Register (MSR) Fields */
 #define MSR_GS		(1<<28) /* Guest state */
 #define MSR_UCLE	(1<<26)	/* User-mode cache lock enable */
@@ -62,6 +67,7 @@
 #define SPRN_DVC2	0x13F	/* Data Value Compare Register 2 */
 #define SPRN_MAS8	0x155	/* MMU Assist Register 8 */
 #define SPRN_TLB0PS	0x158	/* TLB 0 Page Size Register */
+#define SPRN_TLB1PS	0x159	/* TLB 1 Page Size Register */
 #define SPRN_MAS5_MAS6	0x15c	/* MMU Assist Register 5 || 6 */
 #define SPRN_MAS8_MAS1	0x15d	/* MMU Assist Register 8 || 1 */
 #define SPRN_EPTCFG	0x15e	/* Embedded Page Table Config */
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index 01c143b..557cff8 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -74,7 +74,6 @@
 /* RTAS event classes */
 #define RTAS_INTERNAL_ERROR		0x80000000 /* set bit 0 */
 #define RTAS_EPOW_WARNING		0x40000000 /* set bit 1 */
-#define RTAS_POWERMGM_EVENTS		0x20000000 /* set bit 2 */
 #define RTAS_HOTPLUG_EVENTS		0x10000000 /* set bit 3 */
 #define RTAS_IO_EVENTS			0x08000000 /* set bit 4 */
 #define RTAS_EVENT_SCAN_ALL_EVENTS	0xffffffff
@@ -204,6 +203,39 @@
 					/* Variable length.		*/
 };
 
+/* pSeries event log format */
+
+/* Two bytes ASCII section IDs */
+#define PSERIES_ELOG_SECT_ID_PRIV_HDR		(('P' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_USER_HDR		(('U' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_PRIMARY_SRC	(('P' << 8) | 'S')
+#define PSERIES_ELOG_SECT_ID_EXTENDED_UH	(('E' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_FAILING_MTMS	(('M' << 8) | 'T')
+#define PSERIES_ELOG_SECT_ID_SECONDARY_SRC	(('S' << 8) | 'S')
+#define PSERIES_ELOG_SECT_ID_DUMP_LOCATOR	(('D' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_FW_ERROR		(('S' << 8) | 'W')
+#define PSERIES_ELOG_SECT_ID_IMPACT_PART_ID	(('L' << 8) | 'P')
+#define PSERIES_ELOG_SECT_ID_LOGIC_RESOURCE_ID	(('L' << 8) | 'R')
+#define PSERIES_ELOG_SECT_ID_HMC_ID		(('H' << 8) | 'M')
+#define PSERIES_ELOG_SECT_ID_EPOW		(('E' << 8) | 'P')
+#define PSERIES_ELOG_SECT_ID_IO_EVENT		(('I' << 8) | 'E')
+#define PSERIES_ELOG_SECT_ID_MANUFACT_INFO	(('M' << 8) | 'I')
+#define PSERIES_ELOG_SECT_ID_CALL_HOME		(('C' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_USER_DEF		(('U' << 8) | 'D')
+
+/* Vendor specific Platform Event Log Format, Version 6, section header */
+struct pseries_errorlog {
+	uint16_t id;			/* 0x00 2-byte ASCII section ID	*/
+	uint16_t length;		/* 0x02 Section length in bytes	*/
+	uint8_t version;		/* 0x04 Section version		*/
+	uint8_t subtype;		/* 0x05 Section subtype		*/
+	uint16_t creator_component;	/* 0x06 Creator component ID	*/
+	uint8_t data[];			/* 0x08 Start of section data	*/
+};
+
+struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
+					      uint16_t section_id);
+
 /*
  * This can be set by the rtas_flash module so that it can get called
  * as the absolutely last thing before the kernel terminates.
@@ -325,5 +357,7 @@
 static inline int page_is_rtas_user_buf(unsigned long pfn) { return 0;}
 #endif
 
+extern int call_rtas(const char *, int, int, unsigned long *, ...);
+
 #endif /* __KERNEL__ */
 #endif /* _POWERPC_RTAS_H */
diff --git a/arch/powerpc/include/asm/runlatch.h b/arch/powerpc/include/asm/runlatch.h
new file mode 100644
index 0000000..54e9b96
--- /dev/null
+++ b/arch/powerpc/include/asm/runlatch.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
+ */
+#ifndef _ASM_POWERPC_RUNLATCH_H
+#define _ASM_POWERPC_RUNLATCH_H
+
+#ifdef CONFIG_PPC64
+
+extern void __ppc64_runlatch_on(void);
+extern void __ppc64_runlatch_off(void);
+
+/*
+ * We manually hard enable-disable, this is called
+ * in the idle loop and we don't want to mess up
+ * with soft-disable/enable & interrupt replay.
+ */
+#define ppc64_runlatch_off()					\
+	do {							\
+		if (cpu_has_feature(CPU_FTR_CTRL) &&		\
+		    test_thread_local_flags(_TLF_RUNLATCH)) {	\
+			unsigned long msr = mfmsr();		\
+			__hard_irq_disable();			\
+			__ppc64_runlatch_off();			\
+			if (msr & MSR_EE)			\
+				__hard_irq_enable();		\
+		}      						\
+	} while (0)
+
+#define ppc64_runlatch_on()					\
+	do {							\
+		if (cpu_has_feature(CPU_FTR_CTRL) &&		\
+		    !test_thread_local_flags(_TLF_RUNLATCH)) {	\
+			unsigned long msr = mfmsr();		\
+			__hard_irq_disable();			\
+			__ppc64_runlatch_on();			\
+			if (msr & MSR_EE)			\
+				__hard_irq_enable();		\
+		}      						\
+	} while (0)
+#else
+#define ppc64_runlatch_on()
+#define ppc64_runlatch_off()
+#endif /* CONFIG_PPC64 */
+
+#endif /* _ASM_POWERPC_RUNLATCH_H */
diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h
index 186e0fb..d084ce1 100644
--- a/arch/powerpc/include/asm/setup.h
+++ b/arch/powerpc/include/asm/setup.h
@@ -5,6 +5,28 @@
 
 #ifndef __ASSEMBLY__
 extern void ppc_printk_progress(char *s, unsigned short hex);
-#endif
+
+extern unsigned int rtas_data;
+extern int mem_init_done;	/* set on boot once kmalloc can be called */
+extern int init_bootmem_done;	/* set once bootmem is available */
+extern phys_addr_t memory_limit;
+extern unsigned long klimit;
+extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
+
+extern void via_cuda_init(void);
+extern void read_rtc_time(void);
+extern void pmac_find_display(void);
+
+struct device_node;
+extern void note_scsi_host(struct device_node *, void *);
+
+/* Used in very early kernel initialization. */
+extern unsigned long reloc_offset(void);
+extern unsigned long add_reloc_offset(unsigned long);
+extern void reloc_got2(unsigned long);
+
+#define PTRRELOC(x)	((typeof(x)) add_reloc_offset((unsigned long)(x)))
+
+#endif /* !__ASSEMBLY__ */
 
 #endif	/* _ASM_POWERPC_SETUP_H */
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index adba970..ebc24dc 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -122,7 +122,6 @@
 extern void smp_muxed_ipi_message_pass(int cpu, int msg);
 extern irqreturn_t smp_ipi_demux(void);
 
-void smp_init_iSeries(void);
 void smp_init_pSeries(void);
 void smp_init_cell(void);
 void smp_init_celleb(void);
diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h
index f9611bd..7124fc0 100644
--- a/arch/powerpc/include/asm/spinlock.h
+++ b/arch/powerpc/include/asm/spinlock.h
@@ -23,7 +23,6 @@
 #ifdef CONFIG_PPC64
 #include <asm/paca.h>
 #include <asm/hvcall.h>
-#include <asm/iseries/hv_call.h>
 #endif
 #include <asm/asm-compat.h>
 #include <asm/synch.h>
@@ -95,12 +94,12 @@
  * value.
  */
 
-#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES)
+#if defined(CONFIG_PPC_SPLPAR)
 /* We only yield to the hypervisor if we are in shared processor mode */
 #define SHARED_PROCESSOR (get_lppaca()->shared_proc)
 extern void __spin_yield(arch_spinlock_t *lock);
 extern void __rw_yield(arch_rwlock_t *lock);
-#else /* SPLPAR || ISERIES */
+#else /* SPLPAR */
 #define __spin_yield(x)	barrier()
 #define __rw_yield(x)	barrier()
 #define SHARED_PROCESSOR	0
diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
new file mode 100644
index 0000000..caf82d0
--- /dev/null
+++ b/arch/powerpc/include/asm/switch_to.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
+ */
+#ifndef _ASM_POWERPC_SWITCH_TO_H
+#define _ASM_POWERPC_SWITCH_TO_H
+
+struct thread_struct;
+struct task_struct;
+struct pt_regs;
+
+extern struct task_struct *__switch_to(struct task_struct *,
+	struct task_struct *);
+#define switch_to(prev, next, last)	((last) = __switch_to((prev), (next)))
+
+struct thread_struct;
+extern struct task_struct *_switch(struct thread_struct *prev,
+				   struct thread_struct *next);
+
+extern void giveup_fpu(struct task_struct *);
+extern void disable_kernel_fp(void);
+extern void enable_kernel_fp(void);
+extern void flush_fp_to_thread(struct task_struct *);
+extern void enable_kernel_altivec(void);
+extern void giveup_altivec(struct task_struct *);
+extern void load_up_altivec(struct task_struct *);
+extern int emulate_altivec(struct pt_regs *);
+extern void __giveup_vsx(struct task_struct *);
+extern void giveup_vsx(struct task_struct *);
+extern void enable_kernel_spe(void);
+extern void giveup_spe(struct task_struct *);
+extern void load_up_spe(struct task_struct *);
+
+#ifndef CONFIG_SMP
+extern void discard_lazy_cpu_state(void);
+#else
+static inline void discard_lazy_cpu_state(void)
+{
+}
+#endif
+
+#ifdef CONFIG_ALTIVEC
+extern void flush_altivec_to_thread(struct task_struct *);
+#else
+static inline void flush_altivec_to_thread(struct task_struct *t)
+{
+}
+#endif
+
+#ifdef CONFIG_VSX
+extern void flush_vsx_to_thread(struct task_struct *);
+#else
+static inline void flush_vsx_to_thread(struct task_struct *t)
+{
+}
+#endif
+
+#ifdef CONFIG_SPE
+extern void flush_spe_to_thread(struct task_struct *);
+#else
+static inline void flush_spe_to_thread(struct task_struct *t)
+{
+}
+#endif
+
+#endif /* _ASM_POWERPC_SWITCH_TO_H */
diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h
deleted file mode 100644
index c377457..0000000
--- a/arch/powerpc/include/asm/system.h
+++ /dev/null
@@ -1,554 +0,0 @@
-/*
- * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
- */
-#ifndef _ASM_POWERPC_SYSTEM_H
-#define _ASM_POWERPC_SYSTEM_H
-
-#include <linux/kernel.h>
-#include <linux/irqflags.h>
-
-#include <asm/hw_irq.h>
-
-/*
- * Memory barrier.
- * The sync instruction guarantees that all memory accesses initiated
- * by this processor have been performed (with respect to all other
- * mechanisms that access memory).  The eieio instruction is a barrier
- * providing an ordering (separately) for (a) cacheable stores and (b)
- * loads and stores to non-cacheable memory (e.g. I/O devices).
- *
- * mb() prevents loads and stores being reordered across this point.
- * rmb() prevents loads being reordered across this point.
- * wmb() prevents stores being reordered across this point.
- * read_barrier_depends() prevents data-dependent loads being reordered
- *	across this point (nop on PPC).
- *
- * *mb() variants without smp_ prefix must order all types of memory
- * operations with one another. sync is the only instruction sufficient
- * to do this.
- *
- * For the smp_ barriers, ordering is for cacheable memory operations
- * only. We have to use the sync instruction for smp_mb(), since lwsync
- * doesn't order loads with respect to previous stores.  Lwsync can be
- * used for smp_rmb() and smp_wmb().
- *
- * However, on CPUs that don't support lwsync, lwsync actually maps to a
- * heavy-weight sync, so smp_wmb() can be a lighter-weight eieio.
- */
-#define mb()   __asm__ __volatile__ ("sync" : : : "memory")
-#define rmb()  __asm__ __volatile__ ("sync" : : : "memory")
-#define wmb()  __asm__ __volatile__ ("sync" : : : "memory")
-#define read_barrier_depends()  do { } while(0)
-
-#define set_mb(var, value)	do { var = value; mb(); } while (0)
-
-#ifdef __KERNEL__
-#define AT_VECTOR_SIZE_ARCH 6 /* entries in ARCH_DLINFO */
-#ifdef CONFIG_SMP
-
-#ifdef __SUBARCH_HAS_LWSYNC
-#    define SMPWMB      LWSYNC
-#else
-#    define SMPWMB      eieio
-#endif
-
-#define smp_mb()	mb()
-#define smp_rmb()	__asm__ __volatile__ (stringify_in_c(LWSYNC) : : :"memory")
-#define smp_wmb()	__asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory")
-#define smp_read_barrier_depends()	read_barrier_depends()
-#else
-#define smp_mb()	barrier()
-#define smp_rmb()	barrier()
-#define smp_wmb()	barrier()
-#define smp_read_barrier_depends()	do { } while(0)
-#endif /* CONFIG_SMP */
-
-/*
- * This is a barrier which prevents following instructions from being
- * started until the value of the argument x is known.  For example, if
- * x is a variable loaded from memory, this prevents following
- * instructions from being executed until the load has been performed.
- */
-#define data_barrier(x)	\
-	asm volatile("twi 0,%0,0; isync" : : "r" (x) : "memory");
-
-struct task_struct;
-struct pt_regs;
-
-#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
-
-extern int (*__debugger)(struct pt_regs *regs);
-extern int (*__debugger_ipi)(struct pt_regs *regs);
-extern int (*__debugger_bpt)(struct pt_regs *regs);
-extern int (*__debugger_sstep)(struct pt_regs *regs);
-extern int (*__debugger_iabr_match)(struct pt_regs *regs);
-extern int (*__debugger_dabr_match)(struct pt_regs *regs);
-extern int (*__debugger_fault_handler)(struct pt_regs *regs);
-
-#define DEBUGGER_BOILERPLATE(__NAME) \
-static inline int __NAME(struct pt_regs *regs) \
-{ \
-	if (unlikely(__ ## __NAME)) \
-		return __ ## __NAME(regs); \
-	return 0; \
-}
-
-DEBUGGER_BOILERPLATE(debugger)
-DEBUGGER_BOILERPLATE(debugger_ipi)
-DEBUGGER_BOILERPLATE(debugger_bpt)
-DEBUGGER_BOILERPLATE(debugger_sstep)
-DEBUGGER_BOILERPLATE(debugger_iabr_match)
-DEBUGGER_BOILERPLATE(debugger_dabr_match)
-DEBUGGER_BOILERPLATE(debugger_fault_handler)
-
-#else
-static inline int debugger(struct pt_regs *regs) { return 0; }
-static inline int debugger_ipi(struct pt_regs *regs) { return 0; }
-static inline int debugger_bpt(struct pt_regs *regs) { return 0; }
-static inline int debugger_sstep(struct pt_regs *regs) { return 0; }
-static inline int debugger_iabr_match(struct pt_regs *regs) { return 0; }
-static inline int debugger_dabr_match(struct pt_regs *regs) { return 0; }
-static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; }
-#endif
-
-extern int set_dabr(unsigned long dabr);
-#ifdef CONFIG_PPC_ADV_DEBUG_REGS
-extern void do_send_trap(struct pt_regs *regs, unsigned long address,
-			 unsigned long error_code, int signal_code, int brkpt);
-#else
-extern void do_dabr(struct pt_regs *regs, unsigned long address,
-		    unsigned long error_code);
-#endif
-extern void print_backtrace(unsigned long *);
-extern void flush_instruction_cache(void);
-extern void hard_reset_now(void);
-extern void poweroff_now(void);
-
-#ifdef CONFIG_6xx
-extern long _get_L2CR(void);
-extern long _get_L3CR(void);
-extern void _set_L2CR(unsigned long);
-extern void _set_L3CR(unsigned long);
-#else
-#define _get_L2CR()	0L
-#define _get_L3CR()	0L
-#define _set_L2CR(val)	do { } while(0)
-#define _set_L3CR(val)	do { } while(0)
-#endif
-
-extern void via_cuda_init(void);
-extern void read_rtc_time(void);
-extern void pmac_find_display(void);
-extern void giveup_fpu(struct task_struct *);
-extern void disable_kernel_fp(void);
-extern void enable_kernel_fp(void);
-extern void flush_fp_to_thread(struct task_struct *);
-extern void enable_kernel_altivec(void);
-extern void giveup_altivec(struct task_struct *);
-extern void load_up_altivec(struct task_struct *);
-extern int emulate_altivec(struct pt_regs *);
-extern void __giveup_vsx(struct task_struct *);
-extern void giveup_vsx(struct task_struct *);
-extern void enable_kernel_spe(void);
-extern void giveup_spe(struct task_struct *);
-extern void load_up_spe(struct task_struct *);
-extern int fix_alignment(struct pt_regs *);
-extern void cvt_fd(float *from, double *to);
-extern void cvt_df(double *from, float *to);
-
-#ifndef CONFIG_SMP
-extern void discard_lazy_cpu_state(void);
-#else
-static inline void discard_lazy_cpu_state(void)
-{
-}
-#endif
-
-#ifdef CONFIG_ALTIVEC
-extern void flush_altivec_to_thread(struct task_struct *);
-#else
-static inline void flush_altivec_to_thread(struct task_struct *t)
-{
-}
-#endif
-
-#ifdef CONFIG_VSX
-extern void flush_vsx_to_thread(struct task_struct *);
-#else
-static inline void flush_vsx_to_thread(struct task_struct *t)
-{
-}
-#endif
-
-#ifdef CONFIG_SPE
-extern void flush_spe_to_thread(struct task_struct *);
-#else
-static inline void flush_spe_to_thread(struct task_struct *t)
-{
-}
-#endif
-
-extern int call_rtas(const char *, int, int, unsigned long *, ...);
-extern void cacheable_memzero(void *p, unsigned int nb);
-extern void *cacheable_memcpy(void *, const void *, unsigned int);
-extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long);
-extern void bad_page_fault(struct pt_regs *, unsigned long, int);
-extern void _exception(int, struct pt_regs *, int, unsigned long);
-extern void die(const char *, struct pt_regs *, long);
-extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
-
-#ifdef CONFIG_BOOKE_WDT
-extern u32 booke_wdt_enabled;
-extern u32 booke_wdt_period;
-#endif /* CONFIG_BOOKE_WDT */
-
-struct device_node;
-extern void note_scsi_host(struct device_node *, void *);
-
-extern struct task_struct *__switch_to(struct task_struct *,
-	struct task_struct *);
-#define switch_to(prev, next, last)	((last) = __switch_to((prev), (next)))
-
-struct thread_struct;
-extern struct task_struct *_switch(struct thread_struct *prev,
-				   struct thread_struct *next);
-
-extern unsigned int rtas_data;
-extern int mem_init_done;	/* set on boot once kmalloc can be called */
-extern int init_bootmem_done;	/* set once bootmem is available */
-extern phys_addr_t memory_limit;
-extern unsigned long klimit;
-extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
-
-extern int powersave_nap;	/* set if nap mode can be used in idle loop */
-void cpu_idle_wait(void);
-
-#ifdef CONFIG_PSERIES_IDLE
-extern void update_smt_snooze_delay(int snooze);
-extern int pseries_notify_cpuidle_add_cpu(int cpu);
-#else
-static inline void update_smt_snooze_delay(int snooze) {}
-static inline int pseries_notify_cpuidle_add_cpu(int cpu) { return 0; }
-#endif
-
-/*
- * Atomic exchange
- *
- * Changes the memory location '*ptr' to be val and returns
- * the previous value stored there.
- */
-static __always_inline unsigned long
-__xchg_u32(volatile void *p, unsigned long val)
-{
-	unsigned long prev;
-
-	__asm__ __volatile__(
-	PPC_RELEASE_BARRIER
-"1:	lwarx	%0,0,%2 \n"
-	PPC405_ERR77(0,%2)
-"	stwcx.	%3,0,%2 \n\
-	bne-	1b"
-	PPC_ACQUIRE_BARRIER
-	: "=&r" (prev), "+m" (*(volatile unsigned int *)p)
-	: "r" (p), "r" (val)
-	: "cc", "memory");
-
-	return prev;
-}
-
-/*
- * Atomic exchange
- *
- * Changes the memory location '*ptr' to be val and returns
- * the previous value stored there.
- */
-static __always_inline unsigned long
-__xchg_u32_local(volatile void *p, unsigned long val)
-{
-	unsigned long prev;
-
-	__asm__ __volatile__(
-"1:	lwarx	%0,0,%2 \n"
-	PPC405_ERR77(0,%2)
-"	stwcx.	%3,0,%2 \n\
-	bne-	1b"
-	: "=&r" (prev), "+m" (*(volatile unsigned int *)p)
-	: "r" (p), "r" (val)
-	: "cc", "memory");
-
-	return prev;
-}
-
-#ifdef CONFIG_PPC64
-static __always_inline unsigned long
-__xchg_u64(volatile void *p, unsigned long val)
-{
-	unsigned long prev;
-
-	__asm__ __volatile__(
-	PPC_RELEASE_BARRIER
-"1:	ldarx	%0,0,%2 \n"
-	PPC405_ERR77(0,%2)
-"	stdcx.	%3,0,%2 \n\
-	bne-	1b"
-	PPC_ACQUIRE_BARRIER
-	: "=&r" (prev), "+m" (*(volatile unsigned long *)p)
-	: "r" (p), "r" (val)
-	: "cc", "memory");
-
-	return prev;
-}
-
-static __always_inline unsigned long
-__xchg_u64_local(volatile void *p, unsigned long val)
-{
-	unsigned long prev;
-
-	__asm__ __volatile__(
-"1:	ldarx	%0,0,%2 \n"
-	PPC405_ERR77(0,%2)
-"	stdcx.	%3,0,%2 \n\
-	bne-	1b"
-	: "=&r" (prev), "+m" (*(volatile unsigned long *)p)
-	: "r" (p), "r" (val)
-	: "cc", "memory");
-
-	return prev;
-}
-#endif
-
-/*
- * This function doesn't exist, so you'll get a linker error
- * if something tries to do an invalid xchg().
- */
-extern void __xchg_called_with_bad_pointer(void);
-
-static __always_inline unsigned long
-__xchg(volatile void *ptr, unsigned long x, unsigned int size)
-{
-	switch (size) {
-	case 4:
-		return __xchg_u32(ptr, x);
-#ifdef CONFIG_PPC64
-	case 8:
-		return __xchg_u64(ptr, x);
-#endif
-	}
-	__xchg_called_with_bad_pointer();
-	return x;
-}
-
-static __always_inline unsigned long
-__xchg_local(volatile void *ptr, unsigned long x, unsigned int size)
-{
-	switch (size) {
-	case 4:
-		return __xchg_u32_local(ptr, x);
-#ifdef CONFIG_PPC64
-	case 8:
-		return __xchg_u64_local(ptr, x);
-#endif
-	}
-	__xchg_called_with_bad_pointer();
-	return x;
-}
-#define xchg(ptr,x)							     \
-  ({									     \
-     __typeof__(*(ptr)) _x_ = (x);					     \
-     (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
-  })
-
-#define xchg_local(ptr,x)						     \
-  ({									     \
-     __typeof__(*(ptr)) _x_ = (x);					     \
-     (__typeof__(*(ptr))) __xchg_local((ptr),				     \
-     		(unsigned long)_x_, sizeof(*(ptr))); 			     \
-  })
-
-/*
- * Compare and exchange - if *p == old, set it to new,
- * and return the old value of *p.
- */
-#define __HAVE_ARCH_CMPXCHG	1
-
-static __always_inline unsigned long
-__cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
-{
-	unsigned int prev;
-
-	__asm__ __volatile__ (
-	PPC_RELEASE_BARRIER
-"1:	lwarx	%0,0,%2		# __cmpxchg_u32\n\
-	cmpw	0,%0,%3\n\
-	bne-	2f\n"
-	PPC405_ERR77(0,%2)
-"	stwcx.	%4,0,%2\n\
-	bne-	1b"
-	PPC_ACQUIRE_BARRIER
-	"\n\
-2:"
-	: "=&r" (prev), "+m" (*p)
-	: "r" (p), "r" (old), "r" (new)
-	: "cc", "memory");
-
-	return prev;
-}
-
-static __always_inline unsigned long
-__cmpxchg_u32_local(volatile unsigned int *p, unsigned long old,
-			unsigned long new)
-{
-	unsigned int prev;
-
-	__asm__ __volatile__ (
-"1:	lwarx	%0,0,%2		# __cmpxchg_u32\n\
-	cmpw	0,%0,%3\n\
-	bne-	2f\n"
-	PPC405_ERR77(0,%2)
-"	stwcx.	%4,0,%2\n\
-	bne-	1b"
-	"\n\
-2:"
-	: "=&r" (prev), "+m" (*p)
-	: "r" (p), "r" (old), "r" (new)
-	: "cc", "memory");
-
-	return prev;
-}
-
-#ifdef CONFIG_PPC64
-static __always_inline unsigned long
-__cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
-{
-	unsigned long prev;
-
-	__asm__ __volatile__ (
-	PPC_RELEASE_BARRIER
-"1:	ldarx	%0,0,%2		# __cmpxchg_u64\n\
-	cmpd	0,%0,%3\n\
-	bne-	2f\n\
-	stdcx.	%4,0,%2\n\
-	bne-	1b"
-	PPC_ACQUIRE_BARRIER
-	"\n\
-2:"
-	: "=&r" (prev), "+m" (*p)
-	: "r" (p), "r" (old), "r" (new)
-	: "cc", "memory");
-
-	return prev;
-}
-
-static __always_inline unsigned long
-__cmpxchg_u64_local(volatile unsigned long *p, unsigned long old,
-			unsigned long new)
-{
-	unsigned long prev;
-
-	__asm__ __volatile__ (
-"1:	ldarx	%0,0,%2		# __cmpxchg_u64\n\
-	cmpd	0,%0,%3\n\
-	bne-	2f\n\
-	stdcx.	%4,0,%2\n\
-	bne-	1b"
-	"\n\
-2:"
-	: "=&r" (prev), "+m" (*p)
-	: "r" (p), "r" (old), "r" (new)
-	: "cc", "memory");
-
-	return prev;
-}
-#endif
-
-/* This function doesn't exist, so you'll get a linker error
-   if something tries to do an invalid cmpxchg().  */
-extern void __cmpxchg_called_with_bad_pointer(void);
-
-static __always_inline unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
-	  unsigned int size)
-{
-	switch (size) {
-	case 4:
-		return __cmpxchg_u32(ptr, old, new);
-#ifdef CONFIG_PPC64
-	case 8:
-		return __cmpxchg_u64(ptr, old, new);
-#endif
-	}
-	__cmpxchg_called_with_bad_pointer();
-	return old;
-}
-
-static __always_inline unsigned long
-__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
-	  unsigned int size)
-{
-	switch (size) {
-	case 4:
-		return __cmpxchg_u32_local(ptr, old, new);
-#ifdef CONFIG_PPC64
-	case 8:
-		return __cmpxchg_u64_local(ptr, old, new);
-#endif
-	}
-	__cmpxchg_called_with_bad_pointer();
-	return old;
-}
-
-#define cmpxchg(ptr, o, n)						 \
-  ({									 \
-     __typeof__(*(ptr)) _o_ = (o);					 \
-     __typeof__(*(ptr)) _n_ = (n);					 \
-     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
-				    (unsigned long)_n_, sizeof(*(ptr))); \
-  })
-
-
-#define cmpxchg_local(ptr, o, n)					 \
-  ({									 \
-     __typeof__(*(ptr)) _o_ = (o);					 \
-     __typeof__(*(ptr)) _n_ = (n);					 \
-     (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,	 \
-				    (unsigned long)_n_, sizeof(*(ptr))); \
-  })
-
-#ifdef CONFIG_PPC64
-/*
- * We handle most unaligned accesses in hardware. On the other hand 
- * unaligned DMA can be very expensive on some ppc64 IO chips (it does
- * powers of 2 writes until it reaches sufficient alignment).
- *
- * Based on this we disable the IP header alignment in network drivers.
- */
-#define NET_IP_ALIGN	0
-
-#define cmpxchg64(ptr, o, n)						\
-  ({									\
-	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
-	cmpxchg((ptr), (o), (n));					\
-  })
-#define cmpxchg64_local(ptr, o, n)					\
-  ({									\
-	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
-	cmpxchg_local((ptr), (o), (n));					\
-  })
-#else
-#include <asm-generic/cmpxchg-local.h>
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-#endif
-
-extern unsigned long arch_align_stack(unsigned long sp);
-
-/* Used in very early kernel initialization. */
-extern unsigned long reloc_offset(void);
-extern unsigned long add_reloc_offset(unsigned long);
-extern void reloc_got2(unsigned long);
-
-#define PTRRELOC(x)	((typeof(x)) add_reloc_offset((unsigned long)(x)))
-
-extern struct dentry *powerpc_debugfs_root;
-
-#endif /* __KERNEL__ */
-#endif /* _ASM_POWERPC_SYSTEM_H */
diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h
index 96471494..4a741c7 100644
--- a/arch/powerpc/include/asm/thread_info.h
+++ b/arch/powerpc/include/asm/thread_info.h
@@ -110,7 +110,6 @@
 #define TIF_NOERROR		12	/* Force successful syscall return */
 #define TIF_NOTIFY_RESUME	13	/* callback before returning to user */
 #define TIF_SYSCALL_TRACEPOINT	15	/* syscall tracepoint instrumentation */
-#define TIF_RUNLATCH		16	/* Is the runlatch enabled? */
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -141,11 +140,13 @@
 #define TLF_SLEEPING		1	/* suspend code enabled SLEEP mode */
 #define TLF_RESTORE_SIGMASK	2	/* Restore signal mask in do_signal */
 #define TLF_LAZY_MMU		3	/* tlb_batch is active */
+#define TLF_RUNLATCH		4	/* Is the runlatch enabled? */
 
 #define _TLF_NAPPING		(1 << TLF_NAPPING)
 #define _TLF_SLEEPING		(1 << TLF_SLEEPING)
 #define _TLF_RESTORE_SIGMASK	(1 << TLF_RESTORE_SIGMASK)
 #define _TLF_LAZY_MMU		(1 << TLF_LAZY_MMU)
+#define _TLF_RUNLATCH		(1 << TLF_RUNLATCH)
 
 #ifndef __ASSEMBLY__
 #define HAVE_SET_RESTORE_SIGMASK	1
@@ -156,6 +157,12 @@
 	set_bit(TIF_SIGPENDING, &ti->flags);
 }
 
+static inline bool test_thread_local_flags(unsigned int flags)
+{
+	struct thread_info *ti = current_thread_info();
+	return (ti->local_flags & flags) != 0;
+}
+
 #ifdef CONFIG_PPC64
 #define is_32bit_task()	(test_thread_flag(TIF_32BIT))
 #else
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index 7eb10fb..2136f58 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -18,11 +18,6 @@
 #include <linux/percpu.h>
 
 #include <asm/processor.h>
-#ifdef CONFIG_PPC_ISERIES
-#include <asm/paca.h>
-#include <asm/firmware.h>
-#include <asm/iseries/hv_call.h>
-#endif
 
 /* time.c */
 extern unsigned long tb_ticks_per_jiffy;
@@ -167,15 +162,6 @@
 #ifndef CONFIG_BOOKE
 	--val;
 #endif
-#ifdef CONFIG_PPC_ISERIES
-	if (firmware_has_feature(FW_FEATURE_ISERIES) &&
-			get_lppaca()->shared_proc) {
-		get_lppaca()->virtual_decr = val;
-		if (get_dec() > val)
-			HvCall_setVirtualDecr();
-		return;
-	}
-#endif
 	mtspr(SPRN_DEC, val);
 #endif /* not 40x or 8xx_CPU6 */
 }
@@ -217,7 +203,6 @@
 #endif
 
 extern void secondary_cpu_time_init(void);
-extern void iSeries_time_init_early(void);
 
 DECLARE_PER_CPU(u64, decrementers_next_tb);
 
diff --git a/arch/powerpc/include/asm/udbg.h b/arch/powerpc/include/asm/udbg.h
index 8338aef..b303881 100644
--- a/arch/powerpc/include/asm/udbg.h
+++ b/arch/powerpc/include/asm/udbg.h
@@ -44,7 +44,6 @@
 extern void __init udbg_init_pmac_realmode(void);
 extern void __init udbg_init_maple_realmode(void);
 extern void __init udbg_init_pas_realmode(void);
-extern void __init udbg_init_iseries(void);
 extern void __init udbg_init_rtas_panel(void);
 extern void __init udbg_init_rtas_console(void);
 extern void __init udbg_init_debug_beat(void);
diff --git a/arch/powerpc/include/asm/vio.h b/arch/powerpc/include/asm/vio.h
index 0a290a1..6bfd5ff 100644
--- a/arch/powerpc/include/asm/vio.h
+++ b/arch/powerpc/include/asm/vio.h
@@ -69,6 +69,7 @@
 };
 
 struct vio_driver {
+	const char *name;
 	const struct vio_device_id *id_table;
 	int (*probe)(struct vio_dev *dev, const struct vio_device_id *id);
 	int (*remove)(struct vio_dev *dev);
@@ -76,10 +77,17 @@
 	 * be loaded in a CMO environment if it uses DMA.
 	 */
 	unsigned long (*get_desired_dma)(struct vio_dev *dev);
+	const struct dev_pm_ops *pm;
 	struct device_driver driver;
 };
 
-extern int vio_register_driver(struct vio_driver *drv);
+extern int __vio_register_driver(struct vio_driver *drv, struct module *owner,
+				 const char *mod_name);
+/*
+ * vio_register_driver must be a macro so that KBUILD_MODNAME can be expanded
+ */
+#define vio_register_driver(driver)		\
+	__vio_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
 extern void vio_unregister_driver(struct vio_driver *drv);
 
 extern int vio_cmo_entitlement_update(size_t);
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index ee728e4..f5808a3 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -60,6 +60,7 @@
 obj-$(CONFIG_IBMEBUS)           += ibmebus.o
 obj-$(CONFIG_GENERIC_TBSYNC)	+= smp-tbsync.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
+obj-$(CONFIG_FA_DUMP)		+= fadump.o
 ifeq ($(CONFIG_PPC32),y)
 obj-$(CONFIG_E500)		+= idle_e500.o
 endif
@@ -113,15 +114,6 @@
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o
 obj-$(CONFIG_FTRACE_SYSCALLS)	+= ftrace.o
-obj-$(CONFIG_PERF_EVENTS)	+= perf_callchain.o
-
-obj-$(CONFIG_PPC_PERF_CTRS)	+= perf_event.o
-obj64-$(CONFIG_PPC_PERF_CTRS)	+= power4-pmu.o ppc970-pmu.o power5-pmu.o \
-				   power5+-pmu.o power6-pmu.o power7-pmu.o
-obj32-$(CONFIG_PPC_PERF_CTRS)	+= mpc7450-pmu.o
-
-obj-$(CONFIG_FSL_EMB_PERF_EVENT) += perf_event_fsl_emb.o
-obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o
 
 obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o
 
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
index 8184ee9..ee5b690 100644
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -21,10 +21,10 @@
 #include <linux/mm.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/cache.h>
 #include <asm/cputable.h>
 #include <asm/emulated_ops.h>
+#include <asm/switch_to.h>
 
 struct aligninfo {
 	unsigned char len;
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 04caee7..34b8afe9 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -46,9 +46,6 @@
 #include <asm/hvcall.h>
 #include <asm/xics.h>
 #endif
-#ifdef CONFIG_PPC_ISERIES
-#include <asm/iseries/alpaca.h>
-#endif
 #ifdef CONFIG_PPC_POWERNV
 #include <asm/opal.h>
 #endif
@@ -147,7 +144,7 @@
 	DEFINE(PACAKBASE, offsetof(struct paca_struct, kernelbase));
 	DEFINE(PACAKMSR, offsetof(struct paca_struct, kernel_msr));
 	DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled));
-	DEFINE(PACAHARDIRQEN, offsetof(struct paca_struct, hard_enabled));
+	DEFINE(PACAIRQHAPPENED, offsetof(struct paca_struct, irq_happened));
 	DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
 #ifdef CONFIG_PPC_MM_SLICES
 	DEFINE(PACALOWSLICESPSIZE, offsetof(struct paca_struct,
@@ -384,17 +381,6 @@
 	DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry));
 #endif
 
-#ifdef CONFIG_PPC_ISERIES
-	/* the assembler miscalculates the VSID values */
-	DEFINE(PAGE_OFFSET_ESID, GET_ESID(PAGE_OFFSET));
-	DEFINE(PAGE_OFFSET_VSID, KERNEL_VSID(PAGE_OFFSET));
-	DEFINE(VMALLOC_START_ESID, GET_ESID(VMALLOC_START));
-	DEFINE(VMALLOC_START_VSID, KERNEL_VSID(VMALLOC_START));
-
-	/* alpaca */
-	DEFINE(ALPACA_SIZE, sizeof(struct alpaca));
-#endif
-
 	DEFINE(PGD_TABLE_SIZE, PGD_TABLE_SIZE);
 	DEFINE(PTE_SIZE, sizeof(pte_t));
 
@@ -426,16 +412,23 @@
 	DEFINE(VCPU_SPRG2, offsetof(struct kvm_vcpu, arch.shregs.sprg2));
 	DEFINE(VCPU_SPRG3, offsetof(struct kvm_vcpu, arch.shregs.sprg3));
 #endif
-	DEFINE(VCPU_SPRG4, offsetof(struct kvm_vcpu, arch.sprg4));
-	DEFINE(VCPU_SPRG5, offsetof(struct kvm_vcpu, arch.sprg5));
-	DEFINE(VCPU_SPRG6, offsetof(struct kvm_vcpu, arch.sprg6));
-	DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7));
+	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));
+	DEFINE(VCPU_SHARED_SPRG7, offsetof(struct kvm_vcpu_arch_shared, sprg7));
 	DEFINE(VCPU_SHADOW_PID, offsetof(struct kvm_vcpu, arch.shadow_pid));
 	DEFINE(VCPU_SHADOW_PID1, offsetof(struct kvm_vcpu, arch.shadow_pid1));
 	DEFINE(VCPU_SHARED, offsetof(struct kvm_vcpu, arch.shared));
 	DEFINE(VCPU_SHARED_MSR, offsetof(struct kvm_vcpu_arch_shared, msr));
 	DEFINE(VCPU_SHADOW_MSR, offsetof(struct kvm_vcpu, arch.shadow_msr));
 
+	DEFINE(VCPU_SHARED_MAS0, offsetof(struct kvm_vcpu_arch_shared, mas0));
+	DEFINE(VCPU_SHARED_MAS1, offsetof(struct kvm_vcpu_arch_shared, mas1));
+	DEFINE(VCPU_SHARED_MAS2, offsetof(struct kvm_vcpu_arch_shared, mas2));
+	DEFINE(VCPU_SHARED_MAS7_3, offsetof(struct kvm_vcpu_arch_shared, mas7_3));
+	DEFINE(VCPU_SHARED_MAS4, offsetof(struct kvm_vcpu_arch_shared, mas4));
+	DEFINE(VCPU_SHARED_MAS6, offsetof(struct kvm_vcpu_arch_shared, mas6));
+
 	/* book3s */
 #ifdef CONFIG_KVM_BOOK3S_64_HV
 	DEFINE(KVM_LPID, offsetof(struct kvm, arch.lpid));
@@ -448,6 +441,7 @@
 	DEFINE(KVM_LAST_VCPU, offsetof(struct kvm, arch.last_vcpu));
 	DEFINE(KVM_LPCR, offsetof(struct kvm, arch.lpcr));
 	DEFINE(KVM_RMOR, offsetof(struct kvm, arch.rmor));
+	DEFINE(KVM_VRMA_SLB_V, offsetof(struct kvm, arch.vrma_slb_v));
 	DEFINE(VCPU_DSISR, offsetof(struct kvm_vcpu, arch.shregs.dsisr));
 	DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar));
 #endif
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 81db9e2..455faa3 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -20,6 +20,7 @@
 #include <asm/cputable.h>
 #include <asm/prom.h>		/* for PTRRELOC on ARCH=ppc */
 #include <asm/mmu.h>
+#include <asm/setup.h>
 
 struct cpu_spec* cur_cpu_spec = NULL;
 EXPORT_SYMBOL(cur_cpu_spec);
@@ -1816,7 +1817,7 @@
 		.platform		= "ppc440",
 	},
 	{ /* 464 in APM821xx */
-		.pvr_mask		= 0xffffff00,
+		.pvr_mask		= 0xfffffff0,
 		.pvr_value		= 0x12C41C80,
 		.cpu_name		= "APM821XX",
 		.cpu_features		= CPU_FTRS_44X,
@@ -2019,6 +2020,24 @@
 		.machine_check		= machine_check_e500mc,
 		.platform		= "ppce5500",
 	},
+	{	/* e6500 */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x80400000,
+		.cpu_name		= "e6500",
+		.cpu_features		= CPU_FTRS_E6500,
+		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.mmu_features		= MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS |
+			MMU_FTR_USE_TLBILX,
+		.icache_bsize		= 64,
+		.dcache_bsize		= 64,
+		.num_pmcs		= 4,
+		.oprofile_cpu_type	= "ppc/e6500",
+		.oprofile_type		= PPC_OPROFILE_FSL_EMB,
+		.cpu_setup		= __setup_cpu_e5500,
+		.cpu_restore		= __restore_cpu_e5500,
+		.machine_check		= machine_check_e500mc,
+		.platform		= "ppce6500",
+	},
 #ifdef CONFIG_PPC32
 	{	/* default match */
 		.pvr_mask		= 0x00000000,
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index abef751..fdcd8f5 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -27,8 +27,8 @@
 #include <asm/kdump.h>
 #include <asm/prom.h>
 #include <asm/smp.h>
-#include <asm/system.h>
 #include <asm/setjmp.h>
+#include <asm/debug.h>
 
 /*
  * The primary CPU waits a while for all secondary CPUs to enter. This is to
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c
index 2cc451a..5b25c80 100644
--- a/arch/powerpc/kernel/dbell.c
+++ b/arch/powerpc/kernel/dbell.c
@@ -37,6 +37,8 @@
 
 	irq_enter();
 
+	may_hard_irq_enable();
+
 	smp_ipi_demux();
 
 	irq_exit();
diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c
index 3f6464b..bcfdcd2 100644
--- a/arch/powerpc/kernel/dma-iommu.c
+++ b/arch/powerpc/kernel/dma-iommu.c
@@ -17,7 +17,8 @@
  * to the dma address (mapping) of the first page.
  */
 static void *dma_iommu_alloc_coherent(struct device *dev, size_t size,
-				      dma_addr_t *dma_handle, gfp_t flag)
+				      dma_addr_t *dma_handle, gfp_t flag,
+				      struct dma_attrs *attrs)
 {
 	return iommu_alloc_coherent(dev, get_iommu_table_base(dev), size,
 				    dma_handle, dev->coherent_dma_mask, flag,
@@ -25,7 +26,8 @@
 }
 
 static void dma_iommu_free_coherent(struct device *dev, size_t size,
-				    void *vaddr, dma_addr_t dma_handle)
+				    void *vaddr, dma_addr_t dma_handle,
+				    struct dma_attrs *attrs)
 {
 	iommu_free_coherent(get_iommu_table_base(dev), size, vaddr, dma_handle);
 }
@@ -105,8 +107,8 @@
 }
 
 struct dma_map_ops dma_iommu_ops = {
-	.alloc_coherent		= dma_iommu_alloc_coherent,
-	.free_coherent		= dma_iommu_free_coherent,
+	.alloc			= dma_iommu_alloc_coherent,
+	.free			= dma_iommu_free_coherent,
 	.map_sg			= dma_iommu_map_sg,
 	.unmap_sg		= dma_iommu_unmap_sg,
 	.dma_supported		= dma_iommu_dma_supported,
diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c
index 1ebc918..4ab88da 100644
--- a/arch/powerpc/kernel/dma-swiotlb.c
+++ b/arch/powerpc/kernel/dma-swiotlb.c
@@ -47,8 +47,8 @@
  * for everything else.
  */
 struct dma_map_ops swiotlb_dma_ops = {
-	.alloc_coherent = dma_direct_alloc_coherent,
-	.free_coherent = dma_direct_free_coherent,
+	.alloc = dma_direct_alloc_coherent,
+	.free = dma_direct_free_coherent,
 	.map_sg = swiotlb_map_sg_attrs,
 	.unmap_sg = swiotlb_unmap_sg_attrs,
 	.dma_supported = swiotlb_dma_supported,
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c
index 7d0233c..b1ec983 100644
--- a/arch/powerpc/kernel/dma.c
+++ b/arch/powerpc/kernel/dma.c
@@ -26,7 +26,8 @@
 
 
 void *dma_direct_alloc_coherent(struct device *dev, size_t size,
-				dma_addr_t *dma_handle, gfp_t flag)
+				dma_addr_t *dma_handle, gfp_t flag,
+				struct dma_attrs *attrs)
 {
 	void *ret;
 #ifdef CONFIG_NOT_COHERENT_CACHE
@@ -54,7 +55,8 @@
 }
 
 void dma_direct_free_coherent(struct device *dev, size_t size,
-			      void *vaddr, dma_addr_t dma_handle)
+			      void *vaddr, dma_addr_t dma_handle,
+			      struct dma_attrs *attrs)
 {
 #ifdef CONFIG_NOT_COHERENT_CACHE
 	__dma_free_coherent(size, vaddr);
@@ -150,8 +152,8 @@
 #endif
 
 struct dma_map_ops dma_direct_ops = {
-	.alloc_coherent			= dma_direct_alloc_coherent,
-	.free_coherent			= dma_direct_free_coherent,
+	.alloc				= dma_direct_alloc_coherent,
+	.free				= dma_direct_free_coherent,
 	.map_sg				= dma_direct_map_sg,
 	.unmap_sg			= dma_direct_unmap_sg,
 	.dma_supported			= dma_direct_dma_supported,
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 866462c..f8a7a1a 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -32,6 +32,7 @@
 #include <asm/ptrace.h>
 #include <asm/irqflags.h>
 #include <asm/ftrace.h>
+#include <asm/hw_irq.h>
 
 /*
  * System calls.
@@ -115,39 +116,33 @@
 END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
 #endif /* CONFIG_VIRT_CPU_ACCOUNTING && CONFIG_PPC_SPLPAR */
 
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	.trace_hardirqs_on
-	REST_GPR(0,r1)
-	REST_4GPRS(3,r1)
-	REST_2GPRS(7,r1)
-	addi	r9,r1,STACK_FRAME_OVERHEAD
-	ld	r12,_MSR(r1)
-#endif /* CONFIG_TRACE_IRQFLAGS */
-	li	r10,1
-	stb	r10,PACASOFTIRQEN(r13)
-	stb	r10,PACAHARDIRQEN(r13)
-	std	r10,SOFTE(r1)
-#ifdef CONFIG_PPC_ISERIES
-BEGIN_FW_FTR_SECTION
-	/* Hack for handling interrupts when soft-enabling on iSeries */
-	cmpdi	cr1,r0,0x5555		/* syscall 0x5555 */
-	andi.	r10,r12,MSR_PR		/* from kernel */
-	crand	4*cr0+eq,4*cr1+eq,4*cr0+eq
-	bne	2f
-	b	hardware_interrupt_entry
-2:
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif /* CONFIG_PPC_ISERIES */
+	/*
+	 * A syscall should always be called with interrupts enabled
+	 * so we just unconditionally hard-enable here. When some kind
+	 * of irq tracing is used, we additionally check that condition
+	 * is correct
+	 */
+#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_BUG)
+	lbz	r10,PACASOFTIRQEN(r13)
+	xori	r10,r10,1
+1:	tdnei	r10,0
+	EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING
+#endif
 
-	/* Hard enable interrupts */
 #ifdef CONFIG_PPC_BOOK3E
 	wrteei	1
 #else
-	mfmsr	r11
+	ld	r11,PACAKMSR(r13)
 	ori	r11,r11,MSR_EE
 	mtmsrd	r11,1
 #endif /* CONFIG_PPC_BOOK3E */
 
+	/* We do need to set SOFTE in the stack frame or the return
+	 * from interrupt will be painful
+	 */
+	li	r10,1
+	std	r10,SOFTE(r1)
+
 #ifdef SHOW_SYSCALLS
 	bl	.do_show_syscall
 	REST_GPR(0,r1)
@@ -198,16 +193,14 @@
 	andi.	r10,r8,MSR_RI
 	beq-	unrecov_restore
 #endif
-
-	/* Disable interrupts so current_thread_info()->flags can't change,
+	/*
+	 * Disable interrupts so current_thread_info()->flags can't change,
 	 * and so that we don't get interrupted after loading SRR0/1.
 	 */
 #ifdef CONFIG_PPC_BOOK3E
 	wrteei	0
 #else
-	mfmsr	r10
-	rldicl	r10,r10,48,1
-	rotldi	r10,r10,16
+	ld	r10,PACAKMSR(r13)
 	mtmsrd	r10,1
 #endif /* CONFIG_PPC_BOOK3E */
 
@@ -319,7 +312,7 @@
 #ifdef CONFIG_PPC_BOOK3E
 	wrteei	1
 #else
-	mfmsr	r10
+	ld	r10,PACAKMSR(r13)
 	ori	r10,r10,MSR_EE
 	mtmsrd	r10,1
 #endif /* CONFIG_PPC_BOOK3E */
@@ -565,10 +558,8 @@
 #ifdef CONFIG_PPC_BOOK3E
 	wrteei	0
 #else
-	mfmsr	r10		/* Get current interrupt state */
-	rldicl	r9,r10,48,1	/* clear MSR_EE */
-	rotldi	r9,r9,16
-	mtmsrd	r9,1		/* Update machine state */
+	ld	r10,PACAKMSR(r13) /* Get kernel MSR without EE */
+	mtmsrd	r10,1		  /* Update machine state */
 #endif /* CONFIG_PPC_BOOK3E */
 
 #ifdef CONFIG_PREEMPT
@@ -591,25 +582,74 @@
 	ld	r4,TI_FLAGS(r9)
 	andi.	r0,r4,_TIF_USER_WORK_MASK
 	bne	do_work
-#endif
+#endif /* !CONFIG_PREEMPT */
 
+	.globl	fast_exc_return_irq
+fast_exc_return_irq:
 restore:
-BEGIN_FW_FTR_SECTION
+	/*
+	 * This is the main kernel exit path, we first check if we
+	 * have to change our interrupt state.
+	 */
 	ld	r5,SOFTE(r1)
-FW_FTR_SECTION_ELSE
-	b	.Liseries_check_pending_irqs
-ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES)
-2:
-	TRACE_AND_RESTORE_IRQ(r5);
+	lbz	r6,PACASOFTIRQEN(r13)
+	cmpwi	cr1,r5,0
+	cmpw	cr0,r5,r6
+	beq	cr0,4f
 
-	/* extract EE bit and use it to restore paca->hard_enabled */
-	ld	r3,_MSR(r1)
-	rldicl	r4,r3,49,63		/* r0 = (r3 >> 15) & 1 */
-	stb	r4,PACAHARDIRQEN(r13)
+	/* We do, handle disable first, which is easy */
+	bne	cr1,3f;
+ 	li	r0,0
+	stb	r0,PACASOFTIRQEN(r13);
+	TRACE_DISABLE_INTS
+	b	4f
 
+3:	/*
+	 * We are about to soft-enable interrupts (we are hard disabled
+	 * at this point). We check if there's anything that needs to
+	 * be replayed first.
+	 */
+	lbz	r0,PACAIRQHAPPENED(r13)
+	cmpwi	cr0,r0,0
+	bne-	restore_check_irq_replay
+
+	/*
+	 * Get here when nothing happened while soft-disabled, just
+	 * soft-enable and move-on. We will hard-enable as a side
+	 * effect of rfi
+	 */
+restore_no_replay:
+	TRACE_ENABLE_INTS
+	li	r0,1
+	stb	r0,PACASOFTIRQEN(r13);
+
+	/*
+	 * Final return path. BookE is handled in a different file
+	 */
+4:
 #ifdef CONFIG_PPC_BOOK3E
 	b	.exception_return_book3e
 #else
+	/*
+	 * Clear the reservation. If we know the CPU tracks the address of
+	 * the reservation then we can potentially save some cycles and use
+	 * a larx. On POWER6 and POWER7 this is significantly faster.
+	 */
+BEGIN_FTR_SECTION
+	stdcx.	r0,0,r1		/* to clear the reservation */
+FTR_SECTION_ELSE
+	ldarx	r4,0,r1
+ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
+
+	/*
+	 * Some code path such as load_up_fpu or altivec return directly
+	 * here. They run entirely hard disabled and do not alter the
+	 * interrupt state. They also don't use lwarx/stwcx. and thus
+	 * are known not to leave dangling reservations.
+	 */
+	.globl	fast_exception_return
+fast_exception_return:
+	ld	r3,_MSR(r1)
 	ld	r4,_CTR(r1)
 	ld	r0,_LINK(r1)
 	mtctr	r4
@@ -623,28 +663,18 @@
 	beq-	unrecov_restore
 
 	/*
-	 * Clear the reservation. If we know the CPU tracks the address of
-	 * the reservation then we can potentially save some cycles and use
-	 * a larx. On POWER6 and POWER7 this is significantly faster.
-	 */
-BEGIN_FTR_SECTION
-	stdcx.	r0,0,r1		/* to clear the reservation */
-FTR_SECTION_ELSE
-	ldarx	r4,0,r1
-ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
-
-	/*
 	 * Clear RI before restoring r13.  If we are returning to
 	 * userspace and we take an exception after restoring r13,
 	 * we end up corrupting the userspace r13 value.
 	 */
-	mfmsr	r4
-	andc	r4,r4,r0	/* r0 contains MSR_RI here */
+	ld	r4,PACAKMSR(r13) /* Get kernel MSR without EE */
+	andc	r4,r4,r0	 /* r0 contains MSR_RI here */
 	mtmsrd	r4,1
 
 	/*
 	 * r13 is our per cpu area, only restore it if we are returning to
-	 * userspace
+	 * userspace the value stored in the stack frame may belong to
+	 * another CPU.
 	 */
 	andi.	r0,r3,MSR_PR
 	beq	1f
@@ -669,30 +699,55 @@
 
 #endif /* CONFIG_PPC_BOOK3E */
 
-.Liseries_check_pending_irqs:
-#ifdef CONFIG_PPC_ISERIES
-	ld	r5,SOFTE(r1)
-	cmpdi	0,r5,0
-	beq	2b
-	/* Check for pending interrupts (iSeries) */
-	ld	r3,PACALPPACAPTR(r13)
-	ld	r3,LPPACAANYINT(r3)
-	cmpdi	r3,0
-	beq+	2b			/* skip do_IRQ if no interrupts */
+	/*
+	 * Something did happen, check if a re-emit is needed
+	 * (this also clears paca->irq_happened)
+	 */
+restore_check_irq_replay:
+	/* XXX: We could implement a fast path here where we check
+	 * for irq_happened being just 0x01, in which case we can
+	 * clear it and return. That means that we would potentially
+	 * miss a decrementer having wrapped all the way around.
+	 *
+	 * Still, this might be useful for things like hash_page
+	 */
+	bl	.__check_irq_replay
+	cmpwi	cr0,r3,0
+ 	beq	restore_no_replay
+ 
+	/*
+	 * We need to re-emit an interrupt. We do so by re-using our
+	 * existing exception frame. We first change the trap value,
+	 * but we need to ensure we preserve the low nibble of it
+	 */
+	ld	r4,_TRAP(r1)
+	clrldi	r4,r4,60
+	or	r4,r4,r3
+	std	r4,_TRAP(r1)
 
-	li	r3,0
-	stb	r3,PACASOFTIRQEN(r13)	/* ensure we are soft-disabled */
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	.trace_hardirqs_off
-	mfmsr	r10
-#endif
-	ori	r10,r10,MSR_EE
-	mtmsrd	r10			/* hard-enable again */
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	bl	.do_IRQ
-	b	.ret_from_except_lite		/* loop back and handle more */
-#endif
-
+	/*
+	 * Then find the right handler and call it. Interrupts are
+	 * still soft-disabled and we keep them that way.
+	*/
+	cmpwi	cr0,r3,0x500
+	bne	1f
+	addi	r3,r1,STACK_FRAME_OVERHEAD;
+ 	bl	.do_IRQ
+	b	.ret_from_except
+1:	cmpwi	cr0,r3,0x900
+	bne	1f
+	addi	r3,r1,STACK_FRAME_OVERHEAD;
+	bl	.timer_interrupt
+	b	.ret_from_except
+#ifdef CONFIG_PPC_BOOK3E
+1:	cmpwi	cr0,r3,0x280
+	bne	1f
+	addi	r3,r1,STACK_FRAME_OVERHEAD;
+	bl	.doorbell_exception
+	b	.ret_from_except
+#endif /* CONFIG_PPC_BOOK3E */
+1:	b	.ret_from_except /* What else to do here ? */
+ 
 do_work:
 #ifdef CONFIG_PREEMPT
 	andi.	r0,r3,MSR_PR	/* Returning to user mode? */
@@ -705,31 +760,22 @@
 	crandc	eq,cr1*4+eq,eq
 	bne	restore
 
-	/* Here we are preempting the current task.
-	 *
-	 * Ensure interrupts are soft-disabled. We also properly mark
-	 * the PACA to reflect the fact that they are hard-disabled
-	 * and trace the change
+	/*
+	 * Here we are preempting the current task. We want to make
+	 * sure we are soft-disabled first
 	 */
-	li	r0,0
-	stb	r0,PACASOFTIRQEN(r13)
-	stb	r0,PACAHARDIRQEN(r13)
-	TRACE_DISABLE_INTS
-
-	/* Call the scheduler with soft IRQs off */
+	SOFT_DISABLE_INTS(r3,r4)
 1:	bl	.preempt_schedule_irq
 
 	/* Hard-disable interrupts again (and update PACA) */
 #ifdef CONFIG_PPC_BOOK3E
 	wrteei	0
 #else
-	mfmsr	r10
-	rldicl	r10,r10,48,1
-	rotldi	r10,r10,16
+	ld	r10,PACAKMSR(r13) /* Get kernel MSR without EE */
 	mtmsrd	r10,1
 #endif /* CONFIG_PPC_BOOK3E */
-	li	r0,0
-	stb	r0,PACAHARDIRQEN(r13)
+	li	r0,PACA_IRQ_HARD_DIS
+	stb	r0,PACAIRQHAPPENED(r13)
 
 	/* Re-test flags and eventually loop */
 	clrrdi	r9,r1,THREAD_SHIFT
@@ -751,14 +797,12 @@
 
 	andi.	r0,r4,_TIF_NEED_RESCHED
 	beq	1f
-	li	r5,1
-	TRACE_AND_RESTORE_IRQ(r5);
+	bl	.restore_interrupts
 	bl	.schedule
 	b	.ret_from_except_lite
 
 1:	bl	.save_nvgprs
-	li	r5,1
-	TRACE_AND_RESTORE_IRQ(r5);
+	bl	.restore_interrupts
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	bl	.do_notify_resume
 	b	.ret_from_except
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
index 429983c..7215cc2 100644
--- a/arch/powerpc/kernel/exceptions-64e.S
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -24,6 +24,7 @@
 #include <asm/ptrace.h>
 #include <asm/ppc-opcode.h>
 #include <asm/mmu.h>
+#include <asm/hw_irq.h>
 
 /* XXX This will ultimately add space for a special exception save
  *     structure used to save things like SRR0/SRR1, SPRGs, MAS, etc...
@@ -77,59 +78,55 @@
 #define SPRN_MC_SRR1	SPRN_MCSRR1
 
 #define NORMAL_EXCEPTION_PROLOG(n, addition)				    \
-	EXCEPTION_PROLOG(n, GEN, addition##_GEN)
+	EXCEPTION_PROLOG(n, GEN, addition##_GEN(n))
 
 #define CRIT_EXCEPTION_PROLOG(n, addition)				    \
-	EXCEPTION_PROLOG(n, CRIT, addition##_CRIT)
+	EXCEPTION_PROLOG(n, CRIT, addition##_CRIT(n))
 
 #define DBG_EXCEPTION_PROLOG(n, addition)				    \
-	EXCEPTION_PROLOG(n, DBG, addition##_DBG)
+	EXCEPTION_PROLOG(n, DBG, addition##_DBG(n))
 
 #define MC_EXCEPTION_PROLOG(n, addition)				    \
-	EXCEPTION_PROLOG(n, MC, addition##_MC)
+	EXCEPTION_PROLOG(n, MC, addition##_MC(n))
 
 
 /* Variants of the "addition" argument for the prolog
  */
-#define PROLOG_ADDITION_NONE_GEN
-#define PROLOG_ADDITION_NONE_CRIT
-#define PROLOG_ADDITION_NONE_DBG
-#define PROLOG_ADDITION_NONE_MC
+#define PROLOG_ADDITION_NONE_GEN(n)
+#define PROLOG_ADDITION_NONE_CRIT(n)
+#define PROLOG_ADDITION_NONE_DBG(n)
+#define PROLOG_ADDITION_NONE_MC(n)
 
-#define PROLOG_ADDITION_MASKABLE_GEN					    \
+#define PROLOG_ADDITION_MASKABLE_GEN(n)					    \
 	lbz	r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */	    \
 	cmpwi	cr0,r11,0;		/* yes -> go out of line */	    \
-	beq	masked_interrupt_book3e;
+	beq	masked_interrupt_book3e_##n
 
-#define PROLOG_ADDITION_2REGS_GEN					    \
+#define PROLOG_ADDITION_2REGS_GEN(n)					    \
 	std	r14,PACA_EXGEN+EX_R14(r13);				    \
 	std	r15,PACA_EXGEN+EX_R15(r13)
 
-#define PROLOG_ADDITION_1REG_GEN					    \
+#define PROLOG_ADDITION_1REG_GEN(n)					    \
 	std	r14,PACA_EXGEN+EX_R14(r13);
 
-#define PROLOG_ADDITION_2REGS_CRIT					    \
+#define PROLOG_ADDITION_2REGS_CRIT(n)					    \
 	std	r14,PACA_EXCRIT+EX_R14(r13);				    \
 	std	r15,PACA_EXCRIT+EX_R15(r13)
 
-#define PROLOG_ADDITION_2REGS_DBG					    \
+#define PROLOG_ADDITION_2REGS_DBG(n)					    \
 	std	r14,PACA_EXDBG+EX_R14(r13);				    \
 	std	r15,PACA_EXDBG+EX_R15(r13)
 
-#define PROLOG_ADDITION_2REGS_MC					    \
+#define PROLOG_ADDITION_2REGS_MC(n)					    \
 	std	r14,PACA_EXMC+EX_R14(r13);				    \
 	std	r15,PACA_EXMC+EX_R15(r13)
 
-#define PROLOG_ADDITION_DOORBELL_GEN					    \
-	lbz	r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */	    \
-	cmpwi	cr0,r11,0;		/* yes -> go out of line */	    \
-	beq	masked_doorbell_book3e
-
 
 /* Core exception code for all exceptions except TLB misses.
  * XXX: Needs to make SPRN_SPRG_GEN depend on exception type
  */
 #define EXCEPTION_COMMON(n, excf, ints)					    \
+exc_##n##_common:							    \
 	std	r0,GPR0(r1);		/* save r0 in stackframe */	    \
 	std	r2,GPR2(r1);		/* save r2 in stackframe */	    \
 	SAVE_4GPRS(3, r1);		/* save r3 - r6 in stackframe */    \
@@ -167,20 +164,21 @@
 	std	r0,RESULT(r1);		/* clear regs->result */	    \
 	ints;
 
-/* Variants for the "ints" argument */
+/* Variants for the "ints" argument. This one does nothing when we want
+ * to keep interrupts in their original state
+ */
 #define INTS_KEEP
-#define INTS_DISABLE_SOFT						    \
-	stb	r0,PACASOFTIRQEN(r13);	/* mark interrupts soft-disabled */ \
-	TRACE_DISABLE_INTS;
-#define INTS_DISABLE_HARD						    \
-	stb	r0,PACAHARDIRQEN(r13); /* and hard disabled */
-#define INTS_DISABLE_ALL						    \
-	INTS_DISABLE_SOFT						    \
-	INTS_DISABLE_HARD
 
-/* This is called by exceptions that used INTS_KEEP (that is did not clear
- * neither soft nor hard IRQ indicators in the PACA. This will restore MSR:EE
- * to it's previous value
+/* This second version is meant for exceptions that don't immediately
+ * hard-enable. We set a bit in paca->irq_happened to ensure that
+ * a subsequent call to arch_local_irq_restore() will properly
+ * hard-enable and avoid the fast-path
+ */
+#define INTS_DISABLE	SOFT_DISABLE_INTS(r3,r4)
+
+/* This is called by exceptions that used INTS_KEEP (that did not touch
+ * irq indicators in the PACA). This will restore MSR:EE to it's previous
+ * value
  *
  * XXX In the long run, we may want to open-code it in order to separate the
  *     load from the wrtee, thus limiting the latency caused by the dependency
@@ -238,7 +236,7 @@
 #define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack)			\
 	START_EXCEPTION(label);						\
 	NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE)	\
-	EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE_ALL)		\
+	EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE)		\
 	ack(r8);							\
 	CHECK_NAPPING();						\
 	addi	r3,r1,STACK_FRAME_OVERHEAD;				\
@@ -289,7 +287,7 @@
 /* Critical Input Interrupt */
 	START_EXCEPTION(critical_input);
 	CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE)
-//	EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE_ALL)
+//	EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE)
 //	bl	special_reg_save_crit
 //	CHECK_NAPPING();
 //	addi	r3,r1,STACK_FRAME_OVERHEAD
@@ -300,7 +298,7 @@
 /* Machine Check Interrupt */
 	START_EXCEPTION(machine_check);
 	CRIT_EXCEPTION_PROLOG(0x200, PROLOG_ADDITION_NONE)
-//	EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE_ALL)
+//	EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE)
 //	bl	special_reg_save_mc
 //	addi	r3,r1,STACK_FRAME_OVERHEAD
 //	CHECK_NAPPING();
@@ -313,7 +311,7 @@
 	NORMAL_EXCEPTION_PROLOG(0x300, PROLOG_ADDITION_2REGS)
 	mfspr	r14,SPRN_DEAR
 	mfspr	r15,SPRN_ESR
-	EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_KEEP)
+	EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_DISABLE)
 	b	storage_fault_common
 
 /* Instruction Storage Interrupt */
@@ -321,7 +319,7 @@
 	NORMAL_EXCEPTION_PROLOG(0x400, PROLOG_ADDITION_2REGS)
 	li	r15,0
 	mr	r14,r10
-	EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_KEEP)
+	EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_DISABLE)
 	b	storage_fault_common
 
 /* External Input Interrupt */
@@ -339,12 +337,11 @@
 	START_EXCEPTION(program);
 	NORMAL_EXCEPTION_PROLOG(0x700, PROLOG_ADDITION_1REG)
 	mfspr	r14,SPRN_ESR
-	EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE_SOFT)
+	EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE)
 	std	r14,_DSISR(r1)
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	ld	r14,PACA_EXGEN+EX_R14(r13)
 	bl	.save_nvgprs
-	INTS_RESTORE_HARD
 	bl	.program_check_exception
 	b	.ret_from_except
 
@@ -353,15 +350,16 @@
 	NORMAL_EXCEPTION_PROLOG(0x800, PROLOG_ADDITION_NONE)
 	/* we can probably do a shorter exception entry for that one... */
 	EXCEPTION_COMMON(0x800, PACA_EXGEN, INTS_KEEP)
-	bne	1f			/* if from user, just load it up */
-	bl	.save_nvgprs
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	INTS_RESTORE_HARD
-	bl	.kernel_fp_unavailable_exception
-	BUG_OPCODE
-1:	ld	r12,_MSR(r1)
+	ld	r12,_MSR(r1)
+	andi.	r0,r12,MSR_PR;
+	beq-	1f
 	bl	.load_up_fpu
 	b	fast_exception_return
+1:	INTS_DISABLE
+	bl	.save_nvgprs
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	.kernel_fp_unavailable_exception
+	b	.ret_from_except
 
 /* Decrementer Interrupt */
 	MASKABLE_EXCEPTION(0x900, decrementer, .timer_interrupt, ACK_DEC)
@@ -372,7 +370,7 @@
 /* Watchdog Timer Interrupt */
 	START_EXCEPTION(watchdog);
 	CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE)
-//	EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE_ALL)
+//	EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE)
 //	bl	special_reg_save_crit
 //	CHECK_NAPPING();
 //	addi	r3,r1,STACK_FRAME_OVERHEAD
@@ -391,10 +389,9 @@
 /* Auxiliary Processor Unavailable Interrupt */
 	START_EXCEPTION(ap_unavailable);
 	NORMAL_EXCEPTION_PROLOG(0xf20, PROLOG_ADDITION_NONE)
-	EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_KEEP)
-	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_DISABLE)
 	bl	.save_nvgprs
-	INTS_RESTORE_HARD
+	addi	r3,r1,STACK_FRAME_OVERHEAD
 	bl	.unknown_exception
 	b	.ret_from_except
 
@@ -450,7 +447,7 @@
 	mfspr	r15,SPRN_SPRG_CRIT_SCRATCH
 	mtspr	SPRN_SPRG_GEN_SCRATCH,r15
 	mfspr	r14,SPRN_DBSR
-	EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE_ALL)
+	EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE)
 	std	r14,_DSISR(r1)
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	mr	r4,r14
@@ -465,7 +462,7 @@
 
 /* Debug exception as a debug interrupt*/
 	START_EXCEPTION(debug_debug);
-	DBG_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS)
+	DBG_EXCEPTION_PROLOG(0xd08, PROLOG_ADDITION_2REGS)
 
 	/*
 	 * If there is a single step or branch-taken exception in an
@@ -515,7 +512,7 @@
 	mfspr	r15,SPRN_SPRG_DBG_SCRATCH
 	mtspr	SPRN_SPRG_GEN_SCRATCH,r15
 	mfspr	r14,SPRN_DBSR
-	EXCEPTION_COMMON(0xd00, PACA_EXDBG, INTS_DISABLE_ALL)
+	EXCEPTION_COMMON(0xd08, PACA_EXDBG, INTS_DISABLE)
 	std	r14,_DSISR(r1)
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	mr	r4,r14
@@ -525,21 +522,20 @@
 	bl	.DebugException
 	b	.ret_from_except
 
-	MASKABLE_EXCEPTION(0x260, perfmon, .performance_monitor_exception, ACK_NONE)
+	START_EXCEPTION(perfmon);
+	NORMAL_EXCEPTION_PROLOG(0x260, PROLOG_ADDITION_NONE)
+	EXCEPTION_COMMON(0x260, PACA_EXGEN, INTS_DISABLE)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	.performance_monitor_exception
+	b	.ret_from_except_lite
 
 /* Doorbell interrupt */
-	START_EXCEPTION(doorbell)
-	NORMAL_EXCEPTION_PROLOG(0x2070, PROLOG_ADDITION_DOORBELL)
-	EXCEPTION_COMMON(0x2070, PACA_EXGEN, INTS_DISABLE_ALL)
-	CHECK_NAPPING()
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	bl	.doorbell_exception
-	b	.ret_from_except_lite
+	MASKABLE_EXCEPTION(0x280, doorbell, .doorbell_exception, ACK_NONE)
 
 /* Doorbell critical Interrupt */
 	START_EXCEPTION(doorbell_crit);
-	CRIT_EXCEPTION_PROLOG(0x2080, PROLOG_ADDITION_NONE)
-//	EXCEPTION_COMMON(0x2080, PACA_EXCRIT, INTS_DISABLE_ALL)
+	CRIT_EXCEPTION_PROLOG(0x2a0, PROLOG_ADDITION_NONE)
+//	EXCEPTION_COMMON(0x2a0, PACA_EXCRIT, INTS_DISABLE)
 //	bl	special_reg_save_crit
 //	CHECK_NAPPING();
 //	addi	r3,r1,STACK_FRAME_OVERHEAD
@@ -547,36 +543,114 @@
 //	b	ret_from_crit_except
 	b	.
 
+/* Guest Doorbell */
 	MASKABLE_EXCEPTION(0x2c0, guest_doorbell, .unknown_exception, ACK_NONE)
-	MASKABLE_EXCEPTION(0x2e0, guest_doorbell_crit, .unknown_exception, ACK_NONE)
-	MASKABLE_EXCEPTION(0x310, hypercall, .unknown_exception, ACK_NONE)
-	MASKABLE_EXCEPTION(0x320, ehpriv, .unknown_exception, ACK_NONE)
 
+/* Guest Doorbell critical Interrupt */
+	START_EXCEPTION(guest_doorbell_crit);
+	CRIT_EXCEPTION_PROLOG(0x2e0, PROLOG_ADDITION_NONE)
+//	EXCEPTION_COMMON(0x2e0, PACA_EXCRIT, INTS_DISABLE)
+//	bl	special_reg_save_crit
+//	CHECK_NAPPING();
+//	addi	r3,r1,STACK_FRAME_OVERHEAD
+//	bl	.guest_doorbell_critical_exception
+//	b	ret_from_crit_except
+	b	.
+
+/* Hypervisor call */
+	START_EXCEPTION(hypercall);
+	NORMAL_EXCEPTION_PROLOG(0x310, PROLOG_ADDITION_NONE)
+	EXCEPTION_COMMON(0x310, PACA_EXGEN, INTS_KEEP)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	.save_nvgprs
+	INTS_RESTORE_HARD
+	bl	.unknown_exception
+	b	.ret_from_except
+
+/* Embedded Hypervisor priviledged  */
+	START_EXCEPTION(ehpriv);
+	NORMAL_EXCEPTION_PROLOG(0x320, PROLOG_ADDITION_NONE)
+	EXCEPTION_COMMON(0x320, PACA_EXGEN, INTS_KEEP)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	.save_nvgprs
+	INTS_RESTORE_HARD
+	bl	.unknown_exception
+	b	.ret_from_except
 
 /*
- * An interrupt came in while soft-disabled; clear EE in SRR1,
- * clear paca->hard_enabled and return.
+ * An interrupt came in while soft-disabled; We mark paca->irq_happened
+ * accordingly and if the interrupt is level sensitive, we hard disable
  */
-masked_doorbell_book3e:
-	mtcr	r10
-	/* Resend the doorbell to fire again when ints enabled */
-	mfspr	r10,SPRN_PIR
-	PPC_MSGSND(r10)
-	b	masked_interrupt_book3e_common
 
-masked_interrupt_book3e:
+masked_interrupt_book3e_0x500:
+	/* XXX When adding support for EPR, use PACA_IRQ_EE_EDGE */
+	li	r11,PACA_IRQ_EE
+	b	masked_interrupt_book3e_full_mask
+
+masked_interrupt_book3e_0x900:
+	ACK_DEC(r11);
+	li	r11,PACA_IRQ_DEC
+	b	masked_interrupt_book3e_no_mask
+masked_interrupt_book3e_0x980:
+	ACK_FIT(r11);
+	li	r11,PACA_IRQ_DEC
+	b	masked_interrupt_book3e_no_mask
+masked_interrupt_book3e_0x280:
+masked_interrupt_book3e_0x2c0:
+	li	r11,PACA_IRQ_DBELL
+	b	masked_interrupt_book3e_no_mask
+
+masked_interrupt_book3e_no_mask:
 	mtcr	r10
-masked_interrupt_book3e_common:
-	stb	r11,PACAHARDIRQEN(r13)
+	lbz	r10,PACAIRQHAPPENED(r13)
+	or	r10,r10,r11
+	stb	r10,PACAIRQHAPPENED(r13)
+	b	1f
+masked_interrupt_book3e_full_mask:
+	mtcr	r10
+	lbz	r10,PACAIRQHAPPENED(r13)
+	or	r10,r10,r11
+	stb	r10,PACAIRQHAPPENED(r13)
 	mfspr	r10,SPRN_SRR1
 	rldicl	r11,r10,48,1		/* clear MSR_EE */
 	rotldi	r10,r11,16
 	mtspr	SPRN_SRR1,r10
-	ld	r10,PACA_EXGEN+EX_R10(r13);	/* restore registers */
+1:	ld	r10,PACA_EXGEN+EX_R10(r13);
 	ld	r11,PACA_EXGEN+EX_R11(r13);
 	mfspr	r13,SPRN_SPRG_GEN_SCRATCH;
 	rfi
 	b	.
+/*
+ * Called from arch_local_irq_enable when an interrupt needs
+ * to be resent. r3 contains either 0x500,0x900,0x260 or 0x280
+ * to indicate the kind of interrupt. MSR:EE is already off.
+ * We generate a stackframe like if a real interrupt had happened.
+ *
+ * Note: While MSR:EE is off, we need to make sure that _MSR
+ * in the generated frame has EE set to 1 or the exception
+ * handler will not properly re-enable them.
+ */
+_GLOBAL(__replay_interrupt)
+	/* We are going to jump to the exception common code which
+	 * will retrieve various register values from the PACA which
+	 * we don't give a damn about.
+	 */
+	mflr	r10
+	mfmsr	r11
+	mfcr	r4
+	mtspr	SPRN_SPRG_GEN_SCRATCH,r13;
+	std	r1,PACA_EXGEN+EX_R1(r13);
+	stw	r4,PACA_EXGEN+EX_CR(r13);
+	ori	r11,r11,MSR_EE
+	subi	r1,r1,INT_FRAME_SIZE;
+	cmpwi	cr0,r3,0x500
+	beq	exc_0x500_common
+	cmpwi	cr0,r3,0x900
+	beq	exc_0x900_common
+	cmpwi	cr0,r3,0x280
+	beq	exc_0x280_common
+	blr
+
 
 /*
  * This is called from 0x300 and 0x400 handlers after the prologs with
@@ -591,7 +665,6 @@
 	mr	r5,r15
 	ld	r14,PACA_EXGEN+EX_R14(r13)
 	ld	r15,PACA_EXGEN+EX_R15(r13)
-	INTS_RESTORE_HARD
 	bl	.do_page_fault
 	cmpdi	r3,0
 	bne-	1f
@@ -680,6 +753,8 @@
 BAD_STACK_TRAMPOLINE(0x100)
 BAD_STACK_TRAMPOLINE(0x200)
 BAD_STACK_TRAMPOLINE(0x260)
+BAD_STACK_TRAMPOLINE(0x280)
+BAD_STACK_TRAMPOLINE(0x2a0)
 BAD_STACK_TRAMPOLINE(0x2c0)
 BAD_STACK_TRAMPOLINE(0x2e0)
 BAD_STACK_TRAMPOLINE(0x300)
@@ -697,11 +772,10 @@
 BAD_STACK_TRAMPOLINE(0xb00)
 BAD_STACK_TRAMPOLINE(0xc00)
 BAD_STACK_TRAMPOLINE(0xd00)
+BAD_STACK_TRAMPOLINE(0xd08)
 BAD_STACK_TRAMPOLINE(0xe00)
 BAD_STACK_TRAMPOLINE(0xf00)
 BAD_STACK_TRAMPOLINE(0xf20)
-BAD_STACK_TRAMPOLINE(0x2070)
-BAD_STACK_TRAMPOLINE(0x2080)
 
 	.globl	bad_stack_book3e
 bad_stack_book3e:
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 15c5a4f..cb705fd 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -12,6 +12,7 @@
  *
  */
 
+#include <asm/hw_irq.h>
 #include <asm/exception-64s.h>
 #include <asm/ptrace.h>
 
@@ -19,7 +20,7 @@
  * We layout physical memory as follows:
  * 0x0000 - 0x00ff : Secondary processor spin code
  * 0x0100 - 0x2fff : pSeries Interrupt prologs
- * 0x3000 - 0x5fff : interrupt support, iSeries and common interrupt prologs
+ * 0x3000 - 0x5fff : interrupt support common interrupt prologs
  * 0x6000 - 0x6fff : Initial (CPU0) segment table
  * 0x7000 - 0x7fff : FWNMI data area
  * 0x8000 -        : Early init and support code
@@ -100,14 +101,14 @@
 END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB)
 #endif
 	EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD,
-				 KVMTEST_PR, 0x300)
+				 KVMTEST, 0x300)
 
 	. = 0x380
 	.globl data_access_slb_pSeries
 data_access_slb_pSeries:
 	HMT_MEDIUM
 	SET_SCRATCH0(r13)
-	EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x380)
+	EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST, 0x380)
 	std	r3,PACA_EXSLB+EX_R3(r13)
 	mfspr	r3,SPRN_DAR
 #ifdef __DISABLED__
@@ -329,8 +330,8 @@
 	EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted, EXC_STD)
 #endif /* CONFIG_POWER4_ONLY */
 
-	KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_STD, 0x300)
-	KVM_HANDLER_PR_SKIP(PACA_EXSLB, EXC_STD, 0x380)
+	KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x300)
+	KVM_HANDLER_SKIP(PACA_EXSLB, EXC_STD, 0x380)
 	KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x400)
 	KVM_HANDLER_PR(PACA_EXSLB, EXC_STD, 0x480)
 	KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x900)
@@ -356,34 +357,60 @@
 	KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40)
 
 /*
- * An interrupt came in while soft-disabled; clear EE in SRR1,
- * clear paca->hard_enabled and return.
+ * An interrupt came in while soft-disabled. We set paca->irq_happened,
+ * then, if it was a decrementer interrupt, we bump the dec to max and
+ * and return, else we hard disable and return. This is called with
+ * r10 containing the value to OR to the paca field.
  */
-masked_interrupt:
-	stb	r10,PACAHARDIRQEN(r13)
-	mtcrf	0x80,r9
-	ld	r9,PACA_EXGEN+EX_R9(r13)
-	mfspr	r10,SPRN_SRR1
-	rldicl	r10,r10,48,1		/* clear MSR_EE */
-	rotldi	r10,r10,16
-	mtspr	SPRN_SRR1,r10
-	ld	r10,PACA_EXGEN+EX_R10(r13)
-	GET_SCRATCH0(r13)
-	rfid
+#define MASKED_INTERRUPT(_H)				\
+masked_##_H##interrupt:					\
+	std	r11,PACA_EXGEN+EX_R11(r13);		\
+	lbz	r11,PACAIRQHAPPENED(r13);		\
+	or	r11,r11,r10;				\
+	stb	r11,PACAIRQHAPPENED(r13);		\
+	andi.	r10,r10,PACA_IRQ_DEC;			\
+	beq	1f;					\
+	lis	r10,0x7fff;				\
+	ori	r10,r10,0xffff;				\
+	mtspr	SPRN_DEC,r10;				\
+	b	2f;					\
+1:	mfspr	r10,SPRN_##_H##SRR1;			\
+	rldicl	r10,r10,48,1; /* clear MSR_EE */	\
+	rotldi	r10,r10,16;				\
+	mtspr	SPRN_##_H##SRR1,r10;			\
+2:	mtcrf	0x80,r9;				\
+	ld	r9,PACA_EXGEN+EX_R9(r13);		\
+	ld	r10,PACA_EXGEN+EX_R10(r13);		\
+	ld	r11,PACA_EXGEN+EX_R11(r13);		\
+	GET_SCRATCH0(r13);				\
+	##_H##rfid;					\
 	b	.
+	
+	MASKED_INTERRUPT()
+	MASKED_INTERRUPT(H)
 
-masked_Hinterrupt:
-	stb	r10,PACAHARDIRQEN(r13)
-	mtcrf	0x80,r9
-	ld	r9,PACA_EXGEN+EX_R9(r13)
-	mfspr	r10,SPRN_HSRR1
-	rldicl	r10,r10,48,1		/* clear MSR_EE */
-	rotldi	r10,r10,16
-	mtspr	SPRN_HSRR1,r10
-	ld	r10,PACA_EXGEN+EX_R10(r13)
-	GET_SCRATCH0(r13)
-	hrfid
-	b	.
+/*
+ * Called from arch_local_irq_enable when an interrupt needs
+ * to be resent. r3 contains 0x500 or 0x900 to indicate which
+ * kind of interrupt. MSR:EE is already off. We generate a
+ * stackframe like if a real interrupt had happened.
+ *
+ * Note: While MSR:EE is off, we need to make sure that _MSR
+ * in the generated frame has EE set to 1 or the exception
+ * handler will not properly re-enable them.
+ */
+_GLOBAL(__replay_interrupt)
+	/* We are going to jump to the exception common code which
+	 * will retrieve various register values from the PACA which
+	 * we don't give a damn about, so we don't bother storing them.
+	 */
+	mfmsr	r12
+	mflr	r11
+	mfcr	r9
+	ori	r12,r12,MSR_EE
+	andi.	r3,r3,0x0800
+	bne	decrementer_common
+	b	hardware_interrupt_common
 
 #ifdef CONFIG_PPC_PSERIES
 /*
@@ -458,14 +485,15 @@
 	bl	.machine_check_exception
 	b	.ret_from_except
 
-	STD_EXCEPTION_COMMON_LITE(0x900, decrementer, .timer_interrupt)
+	STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ)
+	STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt)
 	STD_EXCEPTION_COMMON(0xa00, trap_0a, .unknown_exception)
 	STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception)
 	STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception)
 	STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception)
         STD_EXCEPTION_COMMON(0xe40, emulation_assist, .program_check_exception)
         STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception)
-	STD_EXCEPTION_COMMON_IDLE(0xf00, performance_monitor, .performance_monitor_exception)
+	STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, .performance_monitor_exception)
 	STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception)
 #ifdef CONFIG_ALTIVEC
 	STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception)
@@ -482,6 +510,9 @@
 system_call_entry:
 	b	system_call_common
 
+ppc64_runlatch_on_trampoline:
+	b	.__ppc64_runlatch_on
+
 /*
  * Here we have detected that the kernel stack pointer is bad.
  * R9 contains the saved CR, r13 points to the paca,
@@ -555,6 +586,8 @@
 	mfspr	r10,SPRN_DSISR
 	stw	r10,PACA_EXGEN+EX_DSISR(r13)
 	EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN)
+	DISABLE_INTS
+	ld	r12,_MSR(r1)
 	ld	r3,PACA_EXGEN+EX_DAR(r13)
 	lwz	r4,PACA_EXGEN+EX_DSISR(r13)
 	li	r5,0x300
@@ -569,6 +602,7 @@
         stw     r10,PACA_EXGEN+EX_DSISR(r13)
         EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN)
         bl      .save_nvgprs
+	DISABLE_INTS
         addi    r3,r1,STACK_FRAME_OVERHEAD
         bl      .unknown_exception
         b       .ret_from_except
@@ -577,6 +611,8 @@
 	.globl instruction_access_common
 instruction_access_common:
 	EXCEPTION_PROLOG_COMMON(0x400, PACA_EXGEN)
+	DISABLE_INTS
+	ld	r12,_MSR(r1)
 	ld	r3,_NIP(r1)
 	andis.	r4,r12,0x5820
 	li	r5,0x400
@@ -672,12 +708,6 @@
 	ld	r10,PACA_EXSLB+EX_LR(r13)
 	ld	r3,PACA_EXSLB+EX_R3(r13)
 	lwz	r9,PACA_EXSLB+EX_CCR(r13)	/* get saved CR */
-#ifdef CONFIG_PPC_ISERIES
-BEGIN_FW_FTR_SECTION
-	ld	r11,PACALPPACAPTR(r13)
-	ld	r11,LPPACASRR0(r11)		/* get SRR0 value */
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif /* CONFIG_PPC_ISERIES */
 
 	mtlr	r10
 
@@ -690,12 +720,6 @@
 	mtcrf	0x01,r9		/* slb_allocate uses cr0 and cr7 */
 .machine	pop
 
-#ifdef CONFIG_PPC_ISERIES
-BEGIN_FW_FTR_SECTION
-	mtspr	SPRN_SRR0,r11
-	mtspr	SPRN_SRR1,r12
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif /* CONFIG_PPC_ISERIES */
 	ld	r9,PACA_EXSLB+EX_R9(r13)
 	ld	r10,PACA_EXSLB+EX_R10(r13)
 	ld	r11,PACA_EXSLB+EX_R11(r13)
@@ -704,13 +728,7 @@
 	rfid
 	b	.	/* prevent speculative execution */
 
-2:
-#ifdef CONFIG_PPC_ISERIES
-BEGIN_FW_FTR_SECTION
-	b	unrecov_slb
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif /* CONFIG_PPC_ISERIES */
-	mfspr	r11,SPRN_SRR0
+2:	mfspr	r11,SPRN_SRR0
 	ld	r10,PACAKBASE(r13)
 	LOAD_HANDLER(r10,unrecov_slb)
 	mtspr	SPRN_SRR0,r10
@@ -727,20 +745,6 @@
 	bl	.unrecoverable_exception
 	b	1b
 
-	.align	7
-	.globl hardware_interrupt_common
-	.globl hardware_interrupt_entry
-hardware_interrupt_common:
-	EXCEPTION_PROLOG_COMMON(0x500, PACA_EXGEN)
-	FINISH_NAP
-hardware_interrupt_entry:
-	DISABLE_INTS
-BEGIN_FTR_SECTION
-	bl	.ppc64_runlatch_on
-END_FTR_SECTION_IFSET(CPU_FTR_CTRL)
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	bl	.do_IRQ
-	b	.ret_from_except_lite
 
 #ifdef CONFIG_PPC_970_NAP
 power4_fixup_nap:
@@ -785,8 +789,8 @@
 	EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN)
 	bne	1f			/* if from user, just load it up */
 	bl	.save_nvgprs
+	DISABLE_INTS
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	ENABLE_INTS
 	bl	.kernel_fp_unavailable_exception
 	BUG_OPCODE
 1:	bl	.load_up_fpu
@@ -805,8 +809,8 @@
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif
 	bl	.save_nvgprs
+	DISABLE_INTS
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	ENABLE_INTS
 	bl	.altivec_unavailable_exception
 	b	.ret_from_except
 
@@ -816,13 +820,14 @@
 	EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN)
 #ifdef CONFIG_VSX
 BEGIN_FTR_SECTION
-	bne	.load_up_vsx
+	beq	1f
+	b	.load_up_vsx
 1:
 END_FTR_SECTION_IFSET(CPU_FTR_VSX)
 #endif
 	bl	.save_nvgprs
+	DISABLE_INTS
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	ENABLE_INTS
 	bl	.vsx_unavailable_exception
 	b	.ret_from_except
 
@@ -831,66 +836,6 @@
 __end_handlers:
 
 /*
- * Return from an exception with minimal checks.
- * The caller is assumed to have done EXCEPTION_PROLOG_COMMON.
- * If interrupts have been enabled, or anything has been
- * done that might have changed the scheduling status of
- * any task or sent any task a signal, you should use
- * ret_from_except or ret_from_except_lite instead of this.
- */
-fast_exc_return_irq:			/* restores irq state too */
-	ld	r3,SOFTE(r1)
-	TRACE_AND_RESTORE_IRQ(r3);
-	ld	r12,_MSR(r1)
-	rldicl	r4,r12,49,63		/* get MSR_EE to LSB */
-	stb	r4,PACAHARDIRQEN(r13)	/* restore paca->hard_enabled */
-	b	1f
-
-	.globl	fast_exception_return
-fast_exception_return:
-	ld	r12,_MSR(r1)
-1:	ld	r11,_NIP(r1)
-	andi.	r3,r12,MSR_RI		/* check if RI is set */
-	beq-	unrecov_fer
-
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-	andi.	r3,r12,MSR_PR
-	beq	2f
-	ACCOUNT_CPU_USER_EXIT(r3, r4)
-2:
-#endif
-
-	ld	r3,_CCR(r1)
-	ld	r4,_LINK(r1)
-	ld	r5,_CTR(r1)
-	ld	r6,_XER(r1)
-	mtcr	r3
-	mtlr	r4
-	mtctr	r5
-	mtxer	r6
-	REST_GPR(0, r1)
-	REST_8GPRS(2, r1)
-
-	mfmsr	r10
-	rldicl	r10,r10,48,1		/* clear EE */
-	rldicr	r10,r10,16,61		/* clear RI (LE is 0 already) */
-	mtmsrd	r10,1
-
-	mtspr	SPRN_SRR1,r12
-	mtspr	SPRN_SRR0,r11
-	REST_4GPRS(10, r1)
-	ld	r1,GPR1(r1)
-	rfid
-	b	.	/* prevent speculative execution */
-
-unrecov_fer:
-	bl	.save_nvgprs
-1:	addi	r3,r1,STACK_FRAME_OVERHEAD
-	bl	.unrecoverable_exception
-	b	1b
-
-
-/*
  * Hash table stuff
  */
 	.align	7
@@ -912,28 +857,6 @@
 	lwz	r0,TI_PREEMPT(r11)	/* If we're in an "NMI" */
 	andis.	r0,r0,NMI_MASK@h	/* (i.e. an irq when soft-disabled) */
 	bne	77f			/* then don't call hash_page now */
-
-	/*
-	 * On iSeries, we soft-disable interrupts here, then
-	 * hard-enable interrupts so that the hash_page code can spin on
-	 * the hash_table_lock without problems on a shared processor.
-	 */
-	DISABLE_INTS
-
-	/*
-	 * Currently, trace_hardirqs_off() will be called by DISABLE_INTS
-	 * and will clobber volatile registers when irq tracing is enabled
-	 * so we need to reload them. It may be possible to be smarter here
-	 * and move the irq tracing elsewhere but let's keep it simple for
-	 * now
-	 */
-#ifdef CONFIG_TRACE_IRQFLAGS
-	ld	r3,_DAR(r1)
-	ld	r4,_DSISR(r1)
-	ld	r5,_TRAP(r1)
-	ld	r12,_MSR(r1)
-	clrrdi	r5,r5,4
-#endif /* CONFIG_TRACE_IRQFLAGS */
 	/*
 	 * We need to set the _PAGE_USER bit if MSR_PR is set or if we are
 	 * accessing a userspace segment (even from the kernel). We assume
@@ -951,43 +874,31 @@
 	 * r4 contains the required access permissions
 	 * r5 contains the trap number
 	 *
-	 * at return r3 = 0 for success
+	 * at return r3 = 0 for success, 1 for page fault, negative for error
 	 */
 	bl	.hash_page		/* build HPTE if possible */
 	cmpdi	r3,0			/* see if hash_page succeeded */
 
-BEGIN_FW_FTR_SECTION
-	/*
-	 * If we had interrupts soft-enabled at the point where the
-	 * DSI/ISI occurred, and an interrupt came in during hash_page,
-	 * handle it now.
-	 * We jump to ret_from_except_lite rather than fast_exception_return
-	 * because ret_from_except_lite will check for and handle pending
-	 * interrupts if necessary.
-	 */
-	beq	13f
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-
-BEGIN_FW_FTR_SECTION
-	/*
-	 * Here we have interrupts hard-disabled, so it is sufficient
-	 * to restore paca->{soft,hard}_enable and get out.
-	 */
+	/* Success */
 	beq	fast_exc_return_irq	/* Return from exception on success */
-END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
 
-	/* For a hash failure, we don't bother re-enabling interrupts */
-	ble-	12f
+	/* Error */
+	blt-	13f
 
-	/*
-	 * hash_page couldn't handle it, set soft interrupt enable back
-	 * to what it was before the trap.  Note that .arch_local_irq_restore
-	 * handles any interrupts pending at this point.
-	 */
-	ld	r3,SOFTE(r1)
-	TRACE_AND_RESTORE_IRQ_PARTIAL(r3, 11f)
-	bl	.arch_local_irq_restore
-	b	11f
+/* Here we have a page fault that hash_page can't handle. */
+handle_page_fault:
+11:	ld	r4,_DAR(r1)
+	ld	r5,_DSISR(r1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	.do_page_fault
+	cmpdi	r3,0
+	beq+	12f
+	bl	.save_nvgprs
+	mr	r5,r3
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	lwz	r4,_DAR(r1)
+	bl	.bad_page_fault
+	b	.ret_from_except
 
 /* We have a data breakpoint exception - handle it */
 handle_dabr_fault:
@@ -996,30 +907,13 @@
 	ld      r5,_DSISR(r1)
 	addi    r3,r1,STACK_FRAME_OVERHEAD
 	bl      .do_dabr
-	b       .ret_from_except_lite
+12:	b       .ret_from_except_lite
 
-/* Here we have a page fault that hash_page can't handle. */
-handle_page_fault:
-	ENABLE_INTS
-11:	ld	r4,_DAR(r1)
-	ld	r5,_DSISR(r1)
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	bl	.do_page_fault
-	cmpdi	r3,0
-	beq+	13f
-	bl	.save_nvgprs
-	mr	r5,r3
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	lwz	r4,_DAR(r1)
-	bl	.bad_page_fault
-	b	.ret_from_except
-
-13:	b	.ret_from_except_lite
 
 /* We have a page fault that hash_page could handle but HV refused
  * the PTE insertion
  */
-12:	bl	.save_nvgprs
+13:	bl	.save_nvgprs
 	mr	r5,r3
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	ld	r4,_DAR(r1)
@@ -1141,51 +1035,19 @@
 	.= 0x7000
 	.globl fwnmi_data_area
 fwnmi_data_area:
-#endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */
 
-	/* iSeries does not use the FWNMI stuff, so it is safe to put
-	 * this here, even if we later allow kernels that will boot on
-	 * both pSeries and iSeries */
-#ifdef CONFIG_PPC_ISERIES
-        . = LPARMAP_PHYS
-	.globl xLparMap
-xLparMap:
-	.quad	HvEsidsToMap		/* xNumberEsids */
-	.quad	HvRangesToMap		/* xNumberRanges */
-	.quad	STAB0_PAGE		/* xSegmentTableOffs */
-	.zero	40			/* xRsvd */
-	/* xEsids (HvEsidsToMap entries of 2 quads) */
-	.quad	PAGE_OFFSET_ESID	/* xKernelEsid */
-	.quad	PAGE_OFFSET_VSID	/* xKernelVsid */
-	.quad	VMALLOC_START_ESID	/* xKernelEsid */
-	.quad	VMALLOC_START_VSID	/* xKernelVsid */
-	/* xRanges (HvRangesToMap entries of 3 quads) */
-	.quad	HvPagesToMap		/* xPages */
-	.quad	0			/* xOffset */
-	.quad	PAGE_OFFSET_VSID << (SID_SHIFT - HW_PAGE_SHIFT)	/* xVPN */
-
-#endif /* CONFIG_PPC_ISERIES */
-
-#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
 	/* pseries and powernv need to keep the whole page from
 	 * 0x7000 to 0x8000 free for use by the firmware
 	 */
         . = 0x8000
 #endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */
 
-/*
- * Space for CPU0's segment table.
- *
- * On iSeries, the hypervisor must fill in at least one entry before
- * we get control (with relocate on).  The address is given to the hv
- * as a page number (see xLparMap above), so this must be at a
- * fixed address (the linker can't compute (u64)&initial_stab >>
- * PAGE_SHIFT).
- */
-	. = STAB0_OFFSET	/* 0x8000 */
+/* Space for CPU0's segment table */
+	.balign 4096
 	.globl initial_stab
 initial_stab:
 	.space	4096
+
 #ifdef CONFIG_PPC_POWERNV
 _GLOBAL(opal_mc_secondary_handler)
 	HMT_MEDIUM
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
new file mode 100644
index 0000000..18bdf74
--- /dev/null
+++ b/arch/powerpc/kernel/fadump.c
@@ -0,0 +1,1317 @@
+/*
+ * Firmware Assisted dump: A robust mechanism to get reliable kernel crash
+ * dump with assistance from firmware. This approach does not use kexec,
+ * instead firmware assists in booting the kdump kernel while preserving
+ * memory contents. The most of the code implementation has been adapted
+ * from phyp assisted dump implementation written by Linas Vepstas and
+ * Manish Ahuja
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright 2011 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#undef DEBUG
+#define pr_fmt(fmt) "fadump: " fmt
+
+#include <linux/string.h>
+#include <linux/memblock.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/crash_dump.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+
+#include <asm/page.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/fadump.h>
+#include <asm/debug.h>
+#include <asm/setup.h>
+
+static struct fw_dump fw_dump;
+static struct fadump_mem_struct fdm;
+static const struct fadump_mem_struct *fdm_active;
+
+static DEFINE_MUTEX(fadump_mutex);
+struct fad_crash_memory_ranges crash_memory_ranges[INIT_CRASHMEM_RANGES];
+int crash_mem_ranges;
+
+/* Scan the Firmware Assisted dump configuration details. */
+int __init early_init_dt_scan_fw_dump(unsigned long node,
+			const char *uname, int depth, void *data)
+{
+	__be32 *sections;
+	int i, num_sections;
+	unsigned long size;
+	const int *token;
+
+	if (depth != 1 || strcmp(uname, "rtas") != 0)
+		return 0;
+
+	/*
+	 * Check if Firmware Assisted dump is supported. if yes, check
+	 * if dump has been initiated on last reboot.
+	 */
+	token = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL);
+	if (!token)
+		return 0;
+
+	fw_dump.fadump_supported = 1;
+	fw_dump.ibm_configure_kernel_dump = *token;
+
+	/*
+	 * The 'ibm,kernel-dump' rtas node is present only if there is
+	 * dump data waiting for us.
+	 */
+	fdm_active = of_get_flat_dt_prop(node, "ibm,kernel-dump", NULL);
+	if (fdm_active)
+		fw_dump.dump_active = 1;
+
+	/* Get the sizes required to store dump data for the firmware provided
+	 * dump sections.
+	 * For each dump section type supported, a 32bit cell which defines
+	 * the ID of a supported section followed by two 32 bit cells which
+	 * gives teh size of the section in bytes.
+	 */
+	sections = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes",
+					&size);
+
+	if (!sections)
+		return 0;
+
+	num_sections = size / (3 * sizeof(u32));
+
+	for (i = 0; i < num_sections; i++, sections += 3) {
+		u32 type = (u32)of_read_number(sections, 1);
+
+		switch (type) {
+		case FADUMP_CPU_STATE_DATA:
+			fw_dump.cpu_state_data_size =
+					of_read_ulong(&sections[1], 2);
+			break;
+		case FADUMP_HPTE_REGION:
+			fw_dump.hpte_region_size =
+					of_read_ulong(&sections[1], 2);
+			break;
+		}
+	}
+	return 1;
+}
+
+int is_fadump_active(void)
+{
+	return fw_dump.dump_active;
+}
+
+/* Print firmware assisted dump configurations for debugging purpose. */
+static void fadump_show_config(void)
+{
+	pr_debug("Support for firmware-assisted dump (fadump): %s\n",
+			(fw_dump.fadump_supported ? "present" : "no support"));
+
+	if (!fw_dump.fadump_supported)
+		return;
+
+	pr_debug("Fadump enabled    : %s\n",
+				(fw_dump.fadump_enabled ? "yes" : "no"));
+	pr_debug("Dump Active       : %s\n",
+				(fw_dump.dump_active ? "yes" : "no"));
+	pr_debug("Dump section sizes:\n");
+	pr_debug("    CPU state data size: %lx\n", fw_dump.cpu_state_data_size);
+	pr_debug("    HPTE region size   : %lx\n", fw_dump.hpte_region_size);
+	pr_debug("Boot memory size  : %lx\n", fw_dump.boot_memory_size);
+}
+
+static unsigned long init_fadump_mem_struct(struct fadump_mem_struct *fdm,
+				unsigned long addr)
+{
+	if (!fdm)
+		return 0;
+
+	memset(fdm, 0, sizeof(struct fadump_mem_struct));
+	addr = addr & PAGE_MASK;
+
+	fdm->header.dump_format_version = 0x00000001;
+	fdm->header.dump_num_sections = 3;
+	fdm->header.dump_status_flag = 0;
+	fdm->header.offset_first_dump_section =
+		(u32)offsetof(struct fadump_mem_struct, cpu_state_data);
+
+	/*
+	 * Fields for disk dump option.
+	 * We are not using disk dump option, hence set these fields to 0.
+	 */
+	fdm->header.dd_block_size = 0;
+	fdm->header.dd_block_offset = 0;
+	fdm->header.dd_num_blocks = 0;
+	fdm->header.dd_offset_disk_path = 0;
+
+	/* set 0 to disable an automatic dump-reboot. */
+	fdm->header.max_time_auto = 0;
+
+	/* Kernel dump sections */
+	/* cpu state data section. */
+	fdm->cpu_state_data.request_flag = FADUMP_REQUEST_FLAG;
+	fdm->cpu_state_data.source_data_type = FADUMP_CPU_STATE_DATA;
+	fdm->cpu_state_data.source_address = 0;
+	fdm->cpu_state_data.source_len = fw_dump.cpu_state_data_size;
+	fdm->cpu_state_data.destination_address = addr;
+	addr += fw_dump.cpu_state_data_size;
+
+	/* hpte region section */
+	fdm->hpte_region.request_flag = FADUMP_REQUEST_FLAG;
+	fdm->hpte_region.source_data_type = FADUMP_HPTE_REGION;
+	fdm->hpte_region.source_address = 0;
+	fdm->hpte_region.source_len = fw_dump.hpte_region_size;
+	fdm->hpte_region.destination_address = addr;
+	addr += fw_dump.hpte_region_size;
+
+	/* RMA region section */
+	fdm->rmr_region.request_flag = FADUMP_REQUEST_FLAG;
+	fdm->rmr_region.source_data_type = FADUMP_REAL_MODE_REGION;
+	fdm->rmr_region.source_address = RMA_START;
+	fdm->rmr_region.source_len = fw_dump.boot_memory_size;
+	fdm->rmr_region.destination_address = addr;
+	addr += fw_dump.boot_memory_size;
+
+	return addr;
+}
+
+/**
+ * fadump_calculate_reserve_size(): reserve variable boot area 5% of System RAM
+ *
+ * Function to find the largest memory size we need to reserve during early
+ * boot process. This will be the size of the memory that is required for a
+ * kernel to boot successfully.
+ *
+ * This function has been taken from phyp-assisted dump feature implementation.
+ *
+ * returns larger of 256MB or 5% rounded down to multiples of 256MB.
+ *
+ * TODO: Come up with better approach to find out more accurate memory size
+ * that is required for a kernel to boot successfully.
+ *
+ */
+static inline unsigned long fadump_calculate_reserve_size(void)
+{
+	unsigned long size;
+
+	/*
+	 * Check if the size is specified through fadump_reserve_mem= cmdline
+	 * option. If yes, then use that.
+	 */
+	if (fw_dump.reserve_bootvar)
+		return fw_dump.reserve_bootvar;
+
+	/* divide by 20 to get 5% of value */
+	size = memblock_end_of_DRAM() / 20;
+
+	/* round it down in multiples of 256 */
+	size = size & ~0x0FFFFFFFUL;
+
+	/* Truncate to memory_limit. We don't want to over reserve the memory.*/
+	if (memory_limit && size > memory_limit)
+		size = memory_limit;
+
+	return (size > MIN_BOOT_MEM ? size : MIN_BOOT_MEM);
+}
+
+/*
+ * Calculate the total memory size required to be reserved for
+ * firmware-assisted dump registration.
+ */
+static unsigned long get_fadump_area_size(void)
+{
+	unsigned long size = 0;
+
+	size += fw_dump.cpu_state_data_size;
+	size += fw_dump.hpte_region_size;
+	size += fw_dump.boot_memory_size;
+	size += sizeof(struct fadump_crash_info_header);
+	size += sizeof(struct elfhdr); /* ELF core header.*/
+	size += sizeof(struct elf_phdr); /* place holder for cpu notes */
+	/* Program headers for crash memory regions. */
+	size += sizeof(struct elf_phdr) * (memblock_num_regions(memory) + 2);
+
+	size = PAGE_ALIGN(size);
+	return size;
+}
+
+int __init fadump_reserve_mem(void)
+{
+	unsigned long base, size, memory_boundary;
+
+	if (!fw_dump.fadump_enabled)
+		return 0;
+
+	if (!fw_dump.fadump_supported) {
+		printk(KERN_INFO "Firmware-assisted dump is not supported on"
+				" this hardware\n");
+		fw_dump.fadump_enabled = 0;
+		return 0;
+	}
+	/*
+	 * Initialize boot memory size
+	 * If dump is active then we have already calculated the size during
+	 * first kernel.
+	 */
+	if (fdm_active)
+		fw_dump.boot_memory_size = fdm_active->rmr_region.source_len;
+	else
+		fw_dump.boot_memory_size = fadump_calculate_reserve_size();
+
+	/*
+	 * Calculate the memory boundary.
+	 * If memory_limit is less than actual memory boundary then reserve
+	 * the memory for fadump beyond the memory_limit and adjust the
+	 * memory_limit accordingly, so that the running kernel can run with
+	 * specified memory_limit.
+	 */
+	if (memory_limit && memory_limit < memblock_end_of_DRAM()) {
+		size = get_fadump_area_size();
+		if ((memory_limit + size) < memblock_end_of_DRAM())
+			memory_limit += size;
+		else
+			memory_limit = memblock_end_of_DRAM();
+		printk(KERN_INFO "Adjusted memory_limit for firmware-assisted"
+				" dump, now %#016llx\n",
+				(unsigned long long)memory_limit);
+	}
+	if (memory_limit)
+		memory_boundary = memory_limit;
+	else
+		memory_boundary = memblock_end_of_DRAM();
+
+	if (fw_dump.dump_active) {
+		printk(KERN_INFO "Firmware-assisted dump is active.\n");
+		/*
+		 * If last boot has crashed then reserve all the memory
+		 * above boot_memory_size so that we don't touch it until
+		 * dump is written to disk by userspace tool. This memory
+		 * will be released for general use once the dump is saved.
+		 */
+		base = fw_dump.boot_memory_size;
+		size = memory_boundary - base;
+		memblock_reserve(base, size);
+		printk(KERN_INFO "Reserved %ldMB of memory at %ldMB "
+				"for saving crash dump\n",
+				(unsigned long)(size >> 20),
+				(unsigned long)(base >> 20));
+
+		fw_dump.fadumphdr_addr =
+				fdm_active->rmr_region.destination_address +
+				fdm_active->rmr_region.source_len;
+		pr_debug("fadumphdr_addr = %p\n",
+				(void *) fw_dump.fadumphdr_addr);
+	} else {
+		/* Reserve the memory at the top of memory. */
+		size = get_fadump_area_size();
+		base = memory_boundary - size;
+		memblock_reserve(base, size);
+		printk(KERN_INFO "Reserved %ldMB of memory at %ldMB "
+				"for firmware-assisted dump\n",
+				(unsigned long)(size >> 20),
+				(unsigned long)(base >> 20));
+	}
+	fw_dump.reserve_dump_area_start = base;
+	fw_dump.reserve_dump_area_size = size;
+	return 1;
+}
+
+/* Look for fadump= cmdline option. */
+static int __init early_fadump_param(char *p)
+{
+	if (!p)
+		return 1;
+
+	if (strncmp(p, "on", 2) == 0)
+		fw_dump.fadump_enabled = 1;
+	else if (strncmp(p, "off", 3) == 0)
+		fw_dump.fadump_enabled = 0;
+
+	return 0;
+}
+early_param("fadump", early_fadump_param);
+
+/* Look for fadump_reserve_mem= cmdline option */
+static int __init early_fadump_reserve_mem(char *p)
+{
+	if (p)
+		fw_dump.reserve_bootvar = memparse(p, &p);
+	return 0;
+}
+early_param("fadump_reserve_mem", early_fadump_reserve_mem);
+
+static void register_fw_dump(struct fadump_mem_struct *fdm)
+{
+	int rc;
+	unsigned int wait_time;
+
+	pr_debug("Registering for firmware-assisted kernel dump...\n");
+
+	/* TODO: Add upper time limit for the delay */
+	do {
+		rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
+			FADUMP_REGISTER, fdm,
+			sizeof(struct fadump_mem_struct));
+
+		wait_time = rtas_busy_delay_time(rc);
+		if (wait_time)
+			mdelay(wait_time);
+
+	} while (wait_time);
+
+	switch (rc) {
+	case -1:
+		printk(KERN_ERR "Failed to register firmware-assisted kernel"
+			" dump. Hardware Error(%d).\n", rc);
+		break;
+	case -3:
+		printk(KERN_ERR "Failed to register firmware-assisted kernel"
+			" dump. Parameter Error(%d).\n", rc);
+		break;
+	case -9:
+		printk(KERN_ERR "firmware-assisted kernel dump is already "
+			" registered.");
+		fw_dump.dump_registered = 1;
+		break;
+	case 0:
+		printk(KERN_INFO "firmware-assisted kernel dump registration"
+			" is successful\n");
+		fw_dump.dump_registered = 1;
+		break;
+	}
+}
+
+void crash_fadump(struct pt_regs *regs, const char *str)
+{
+	struct fadump_crash_info_header *fdh = NULL;
+
+	if (!fw_dump.dump_registered || !fw_dump.fadumphdr_addr)
+		return;
+
+	fdh = __va(fw_dump.fadumphdr_addr);
+	crashing_cpu = smp_processor_id();
+	fdh->crashing_cpu = crashing_cpu;
+	crash_save_vmcoreinfo();
+
+	if (regs)
+		fdh->regs = *regs;
+	else
+		ppc_save_regs(&fdh->regs);
+
+	fdh->cpu_online_mask = *cpu_online_mask;
+
+	/* Call ibm,os-term rtas call to trigger firmware assisted dump */
+	rtas_os_term((char *)str);
+}
+
+#define GPR_MASK	0xffffff0000000000
+static inline int fadump_gpr_index(u64 id)
+{
+	int i = -1;
+	char str[3];
+
+	if ((id & GPR_MASK) == REG_ID("GPR")) {
+		/* get the digits at the end */
+		id &= ~GPR_MASK;
+		id >>= 24;
+		str[2] = '\0';
+		str[1] = id & 0xff;
+		str[0] = (id >> 8) & 0xff;
+		sscanf(str, "%d", &i);
+		if (i > 31)
+			i = -1;
+	}
+	return i;
+}
+
+static inline void fadump_set_regval(struct pt_regs *regs, u64 reg_id,
+								u64 reg_val)
+{
+	int i;
+
+	i = fadump_gpr_index(reg_id);
+	if (i >= 0)
+		regs->gpr[i] = (unsigned long)reg_val;
+	else if (reg_id == REG_ID("NIA"))
+		regs->nip = (unsigned long)reg_val;
+	else if (reg_id == REG_ID("MSR"))
+		regs->msr = (unsigned long)reg_val;
+	else if (reg_id == REG_ID("CTR"))
+		regs->ctr = (unsigned long)reg_val;
+	else if (reg_id == REG_ID("LR"))
+		regs->link = (unsigned long)reg_val;
+	else if (reg_id == REG_ID("XER"))
+		regs->xer = (unsigned long)reg_val;
+	else if (reg_id == REG_ID("CR"))
+		regs->ccr = (unsigned long)reg_val;
+	else if (reg_id == REG_ID("DAR"))
+		regs->dar = (unsigned long)reg_val;
+	else if (reg_id == REG_ID("DSISR"))
+		regs->dsisr = (unsigned long)reg_val;
+}
+
+static struct fadump_reg_entry*
+fadump_read_registers(struct fadump_reg_entry *reg_entry, struct pt_regs *regs)
+{
+	memset(regs, 0, sizeof(struct pt_regs));
+
+	while (reg_entry->reg_id != REG_ID("CPUEND")) {
+		fadump_set_regval(regs, reg_entry->reg_id,
+					reg_entry->reg_value);
+		reg_entry++;
+	}
+	reg_entry++;
+	return reg_entry;
+}
+
+static u32 *fadump_append_elf_note(u32 *buf, char *name, unsigned type,
+						void *data, size_t data_len)
+{
+	struct elf_note note;
+
+	note.n_namesz = strlen(name) + 1;
+	note.n_descsz = data_len;
+	note.n_type   = type;
+	memcpy(buf, &note, sizeof(note));
+	buf += (sizeof(note) + 3)/4;
+	memcpy(buf, name, note.n_namesz);
+	buf += (note.n_namesz + 3)/4;
+	memcpy(buf, data, note.n_descsz);
+	buf += (note.n_descsz + 3)/4;
+
+	return buf;
+}
+
+static void fadump_final_note(u32 *buf)
+{
+	struct elf_note note;
+
+	note.n_namesz = 0;
+	note.n_descsz = 0;
+	note.n_type   = 0;
+	memcpy(buf, &note, sizeof(note));
+}
+
+static u32 *fadump_regs_to_elf_notes(u32 *buf, struct pt_regs *regs)
+{
+	struct elf_prstatus prstatus;
+
+	memset(&prstatus, 0, sizeof(prstatus));
+	/*
+	 * FIXME: How do i get PID? Do I really need it?
+	 * prstatus.pr_pid = ????
+	 */
+	elf_core_copy_kernel_regs(&prstatus.pr_reg, regs);
+	buf = fadump_append_elf_note(buf, KEXEC_CORE_NOTE_NAME, NT_PRSTATUS,
+				&prstatus, sizeof(prstatus));
+	return buf;
+}
+
+static void fadump_update_elfcore_header(char *bufp)
+{
+	struct elfhdr *elf;
+	struct elf_phdr *phdr;
+
+	elf = (struct elfhdr *)bufp;
+	bufp += sizeof(struct elfhdr);
+
+	/* First note is a place holder for cpu notes info. */
+	phdr = (struct elf_phdr *)bufp;
+
+	if (phdr->p_type == PT_NOTE) {
+		phdr->p_paddr = fw_dump.cpu_notes_buf;
+		phdr->p_offset	= phdr->p_paddr;
+		phdr->p_filesz	= fw_dump.cpu_notes_buf_size;
+		phdr->p_memsz = fw_dump.cpu_notes_buf_size;
+	}
+	return;
+}
+
+static void *fadump_cpu_notes_buf_alloc(unsigned long size)
+{
+	void *vaddr;
+	struct page *page;
+	unsigned long order, count, i;
+
+	order = get_order(size);
+	vaddr = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, order);
+	if (!vaddr)
+		return NULL;
+
+	count = 1 << order;
+	page = virt_to_page(vaddr);
+	for (i = 0; i < count; i++)
+		SetPageReserved(page + i);
+	return vaddr;
+}
+
+static void fadump_cpu_notes_buf_free(unsigned long vaddr, unsigned long size)
+{
+	struct page *page;
+	unsigned long order, count, i;
+
+	order = get_order(size);
+	count = 1 << order;
+	page = virt_to_page(vaddr);
+	for (i = 0; i < count; i++)
+		ClearPageReserved(page + i);
+	__free_pages(page, order);
+}
+
+/*
+ * Read CPU state dump data and convert it into ELF notes.
+ * The CPU dump starts with magic number "REGSAVE". NumCpusOffset should be
+ * used to access the data to allow for additional fields to be added without
+ * affecting compatibility. Each list of registers for a CPU starts with
+ * "CPUSTRT" and ends with "CPUEND". Each register entry is of 16 bytes,
+ * 8 Byte ASCII identifier and 8 Byte register value. The register entry
+ * with identifier "CPUSTRT" and "CPUEND" contains 4 byte cpu id as part
+ * of register value. For more details refer to PAPR document.
+ *
+ * Only for the crashing cpu we ignore the CPU dump data and get exact
+ * state from fadump crash info structure populated by first kernel at the
+ * time of crash.
+ */
+static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm)
+{
+	struct fadump_reg_save_area_header *reg_header;
+	struct fadump_reg_entry *reg_entry;
+	struct fadump_crash_info_header *fdh = NULL;
+	void *vaddr;
+	unsigned long addr;
+	u32 num_cpus, *note_buf;
+	struct pt_regs regs;
+	int i, rc = 0, cpu = 0;
+
+	if (!fdm->cpu_state_data.bytes_dumped)
+		return -EINVAL;
+
+	addr = fdm->cpu_state_data.destination_address;
+	vaddr = __va(addr);
+
+	reg_header = vaddr;
+	if (reg_header->magic_number != REGSAVE_AREA_MAGIC) {
+		printk(KERN_ERR "Unable to read register save area.\n");
+		return -ENOENT;
+	}
+	pr_debug("--------CPU State Data------------\n");
+	pr_debug("Magic Number: %llx\n", reg_header->magic_number);
+	pr_debug("NumCpuOffset: %x\n", reg_header->num_cpu_offset);
+
+	vaddr += reg_header->num_cpu_offset;
+	num_cpus = *((u32 *)(vaddr));
+	pr_debug("NumCpus     : %u\n", num_cpus);
+	vaddr += sizeof(u32);
+	reg_entry = (struct fadump_reg_entry *)vaddr;
+
+	/* Allocate buffer to hold cpu crash notes. */
+	fw_dump.cpu_notes_buf_size = num_cpus * sizeof(note_buf_t);
+	fw_dump.cpu_notes_buf_size = PAGE_ALIGN(fw_dump.cpu_notes_buf_size);
+	note_buf = fadump_cpu_notes_buf_alloc(fw_dump.cpu_notes_buf_size);
+	if (!note_buf) {
+		printk(KERN_ERR "Failed to allocate 0x%lx bytes for "
+			"cpu notes buffer\n", fw_dump.cpu_notes_buf_size);
+		return -ENOMEM;
+	}
+	fw_dump.cpu_notes_buf = __pa(note_buf);
+
+	pr_debug("Allocated buffer for cpu notes of size %ld at %p\n",
+			(num_cpus * sizeof(note_buf_t)), note_buf);
+
+	if (fw_dump.fadumphdr_addr)
+		fdh = __va(fw_dump.fadumphdr_addr);
+
+	for (i = 0; i < num_cpus; i++) {
+		if (reg_entry->reg_id != REG_ID("CPUSTRT")) {
+			printk(KERN_ERR "Unable to read CPU state data\n");
+			rc = -ENOENT;
+			goto error_out;
+		}
+		/* Lower 4 bytes of reg_value contains logical cpu id */
+		cpu = reg_entry->reg_value & FADUMP_CPU_ID_MASK;
+		if (!cpumask_test_cpu(cpu, &fdh->cpu_online_mask)) {
+			SKIP_TO_NEXT_CPU(reg_entry);
+			continue;
+		}
+		pr_debug("Reading register data for cpu %d...\n", cpu);
+		if (fdh && fdh->crashing_cpu == cpu) {
+			regs = fdh->regs;
+			note_buf = fadump_regs_to_elf_notes(note_buf, &regs);
+			SKIP_TO_NEXT_CPU(reg_entry);
+		} else {
+			reg_entry++;
+			reg_entry = fadump_read_registers(reg_entry, &regs);
+			note_buf = fadump_regs_to_elf_notes(note_buf, &regs);
+		}
+	}
+	fadump_final_note(note_buf);
+
+	pr_debug("Updating elfcore header (%llx) with cpu notes\n",
+							fdh->elfcorehdr_addr);
+	fadump_update_elfcore_header((char *)__va(fdh->elfcorehdr_addr));
+	return 0;
+
+error_out:
+	fadump_cpu_notes_buf_free((unsigned long)__va(fw_dump.cpu_notes_buf),
+					fw_dump.cpu_notes_buf_size);
+	fw_dump.cpu_notes_buf = 0;
+	fw_dump.cpu_notes_buf_size = 0;
+	return rc;
+
+}
+
+/*
+ * Validate and process the dump data stored by firmware before exporting
+ * it through '/proc/vmcore'.
+ */
+static int __init process_fadump(const struct fadump_mem_struct *fdm_active)
+{
+	struct fadump_crash_info_header *fdh;
+	int rc = 0;
+
+	if (!fdm_active || !fw_dump.fadumphdr_addr)
+		return -EINVAL;
+
+	/* Check if the dump data is valid. */
+	if ((fdm_active->header.dump_status_flag == FADUMP_ERROR_FLAG) ||
+			(fdm_active->cpu_state_data.error_flags != 0) ||
+			(fdm_active->rmr_region.error_flags != 0)) {
+		printk(KERN_ERR "Dump taken by platform is not valid\n");
+		return -EINVAL;
+	}
+	if ((fdm_active->rmr_region.bytes_dumped !=
+			fdm_active->rmr_region.source_len) ||
+			!fdm_active->cpu_state_data.bytes_dumped) {
+		printk(KERN_ERR "Dump taken by platform is incomplete\n");
+		return -EINVAL;
+	}
+
+	/* Validate the fadump crash info header */
+	fdh = __va(fw_dump.fadumphdr_addr);
+	if (fdh->magic_number != FADUMP_CRASH_INFO_MAGIC) {
+		printk(KERN_ERR "Crash info header is not valid.\n");
+		return -EINVAL;
+	}
+
+	rc = fadump_build_cpu_notes(fdm_active);
+	if (rc)
+		return rc;
+
+	/*
+	 * We are done validating dump info and elfcore header is now ready
+	 * to be exported. set elfcorehdr_addr so that vmcore module will
+	 * export the elfcore header through '/proc/vmcore'.
+	 */
+	elfcorehdr_addr = fdh->elfcorehdr_addr;
+
+	return 0;
+}
+
+static inline void fadump_add_crash_memory(unsigned long long base,
+					unsigned long long end)
+{
+	if (base == end)
+		return;
+
+	pr_debug("crash_memory_range[%d] [%#016llx-%#016llx], %#llx bytes\n",
+		crash_mem_ranges, base, end - 1, (end - base));
+	crash_memory_ranges[crash_mem_ranges].base = base;
+	crash_memory_ranges[crash_mem_ranges].size = end - base;
+	crash_mem_ranges++;
+}
+
+static void fadump_exclude_reserved_area(unsigned long long start,
+					unsigned long long end)
+{
+	unsigned long long ra_start, ra_end;
+
+	ra_start = fw_dump.reserve_dump_area_start;
+	ra_end = ra_start + fw_dump.reserve_dump_area_size;
+
+	if ((ra_start < end) && (ra_end > start)) {
+		if ((start < ra_start) && (end > ra_end)) {
+			fadump_add_crash_memory(start, ra_start);
+			fadump_add_crash_memory(ra_end, end);
+		} else if (start < ra_start) {
+			fadump_add_crash_memory(start, ra_start);
+		} else if (ra_end < end) {
+			fadump_add_crash_memory(ra_end, end);
+		}
+	} else
+		fadump_add_crash_memory(start, end);
+}
+
+static int fadump_init_elfcore_header(char *bufp)
+{
+	struct elfhdr *elf;
+
+	elf = (struct elfhdr *) bufp;
+	bufp += sizeof(struct elfhdr);
+	memcpy(elf->e_ident, ELFMAG, SELFMAG);
+	elf->e_ident[EI_CLASS] = ELF_CLASS;
+	elf->e_ident[EI_DATA] = ELF_DATA;
+	elf->e_ident[EI_VERSION] = EV_CURRENT;
+	elf->e_ident[EI_OSABI] = ELF_OSABI;
+	memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+	elf->e_type = ET_CORE;
+	elf->e_machine = ELF_ARCH;
+	elf->e_version = EV_CURRENT;
+	elf->e_entry = 0;
+	elf->e_phoff = sizeof(struct elfhdr);
+	elf->e_shoff = 0;
+	elf->e_flags = ELF_CORE_EFLAGS;
+	elf->e_ehsize = sizeof(struct elfhdr);
+	elf->e_phentsize = sizeof(struct elf_phdr);
+	elf->e_phnum = 0;
+	elf->e_shentsize = 0;
+	elf->e_shnum = 0;
+	elf->e_shstrndx = 0;
+
+	return 0;
+}
+
+/*
+ * Traverse through memblock structure and setup crash memory ranges. These
+ * ranges will be used create PT_LOAD program headers in elfcore header.
+ */
+static void fadump_setup_crash_memory_ranges(void)
+{
+	struct memblock_region *reg;
+	unsigned long long start, end;
+
+	pr_debug("Setup crash memory ranges.\n");
+	crash_mem_ranges = 0;
+	/*
+	 * add the first memory chunk (RMA_START through boot_memory_size) as
+	 * a separate memory chunk. The reason is, at the time crash firmware
+	 * will move the content of this memory chunk to different location
+	 * specified during fadump registration. We need to create a separate
+	 * program header for this chunk with the correct offset.
+	 */
+	fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size);
+
+	for_each_memblock(memory, reg) {
+		start = (unsigned long long)reg->base;
+		end = start + (unsigned long long)reg->size;
+		if (start == RMA_START && end >= fw_dump.boot_memory_size)
+			start = fw_dump.boot_memory_size;
+
+		/* add this range excluding the reserved dump area. */
+		fadump_exclude_reserved_area(start, end);
+	}
+}
+
+/*
+ * If the given physical address falls within the boot memory region then
+ * return the relocated address that points to the dump region reserved
+ * for saving initial boot memory contents.
+ */
+static inline unsigned long fadump_relocate(unsigned long paddr)
+{
+	if (paddr > RMA_START && paddr < fw_dump.boot_memory_size)
+		return fdm.rmr_region.destination_address + paddr;
+	else
+		return paddr;
+}
+
+static int fadump_create_elfcore_headers(char *bufp)
+{
+	struct elfhdr *elf;
+	struct elf_phdr *phdr;
+	int i;
+
+	fadump_init_elfcore_header(bufp);
+	elf = (struct elfhdr *)bufp;
+	bufp += sizeof(struct elfhdr);
+
+	/*
+	 * setup ELF PT_NOTE, place holder for cpu notes info. The notes info
+	 * will be populated during second kernel boot after crash. Hence
+	 * this PT_NOTE will always be the first elf note.
+	 *
+	 * NOTE: Any new ELF note addition should be placed after this note.
+	 */
+	phdr = (struct elf_phdr *)bufp;
+	bufp += sizeof(struct elf_phdr);
+	phdr->p_type = PT_NOTE;
+	phdr->p_flags = 0;
+	phdr->p_vaddr = 0;
+	phdr->p_align = 0;
+
+	phdr->p_offset = 0;
+	phdr->p_paddr = 0;
+	phdr->p_filesz = 0;
+	phdr->p_memsz = 0;
+
+	(elf->e_phnum)++;
+
+	/* setup ELF PT_NOTE for vmcoreinfo */
+	phdr = (struct elf_phdr *)bufp;
+	bufp += sizeof(struct elf_phdr);
+	phdr->p_type	= PT_NOTE;
+	phdr->p_flags	= 0;
+	phdr->p_vaddr	= 0;
+	phdr->p_align	= 0;
+
+	phdr->p_paddr	= fadump_relocate(paddr_vmcoreinfo_note());
+	phdr->p_offset	= phdr->p_paddr;
+	phdr->p_memsz	= vmcoreinfo_max_size;
+	phdr->p_filesz	= vmcoreinfo_max_size;
+
+	/* Increment number of program headers. */
+	(elf->e_phnum)++;
+
+	/* setup PT_LOAD sections. */
+
+	for (i = 0; i < crash_mem_ranges; i++) {
+		unsigned long long mbase, msize;
+		mbase = crash_memory_ranges[i].base;
+		msize = crash_memory_ranges[i].size;
+
+		if (!msize)
+			continue;
+
+		phdr = (struct elf_phdr *)bufp;
+		bufp += sizeof(struct elf_phdr);
+		phdr->p_type	= PT_LOAD;
+		phdr->p_flags	= PF_R|PF_W|PF_X;
+		phdr->p_offset	= mbase;
+
+		if (mbase == RMA_START) {
+			/*
+			 * The entire RMA region will be moved by firmware
+			 * to the specified destination_address. Hence set
+			 * the correct offset.
+			 */
+			phdr->p_offset = fdm.rmr_region.destination_address;
+		}
+
+		phdr->p_paddr = mbase;
+		phdr->p_vaddr = (unsigned long)__va(mbase);
+		phdr->p_filesz = msize;
+		phdr->p_memsz = msize;
+		phdr->p_align = 0;
+
+		/* Increment number of program headers. */
+		(elf->e_phnum)++;
+	}
+	return 0;
+}
+
+static unsigned long init_fadump_header(unsigned long addr)
+{
+	struct fadump_crash_info_header *fdh;
+
+	if (!addr)
+		return 0;
+
+	fw_dump.fadumphdr_addr = addr;
+	fdh = __va(addr);
+	addr += sizeof(struct fadump_crash_info_header);
+
+	memset(fdh, 0, sizeof(struct fadump_crash_info_header));
+	fdh->magic_number = FADUMP_CRASH_INFO_MAGIC;
+	fdh->elfcorehdr_addr = addr;
+	/* We will set the crashing cpu id in crash_fadump() during crash. */
+	fdh->crashing_cpu = CPU_UNKNOWN;
+
+	return addr;
+}
+
+static void register_fadump(void)
+{
+	unsigned long addr;
+	void *vaddr;
+
+	/*
+	 * If no memory is reserved then we can not register for firmware-
+	 * assisted dump.
+	 */
+	if (!fw_dump.reserve_dump_area_size)
+		return;
+
+	fadump_setup_crash_memory_ranges();
+
+	addr = fdm.rmr_region.destination_address + fdm.rmr_region.source_len;
+	/* Initialize fadump crash info header. */
+	addr = init_fadump_header(addr);
+	vaddr = __va(addr);
+
+	pr_debug("Creating ELF core headers at %#016lx\n", addr);
+	fadump_create_elfcore_headers(vaddr);
+
+	/* register the future kernel dump with firmware. */
+	register_fw_dump(&fdm);
+}
+
+static int fadump_unregister_dump(struct fadump_mem_struct *fdm)
+{
+	int rc = 0;
+	unsigned int wait_time;
+
+	pr_debug("Un-register firmware-assisted dump\n");
+
+	/* TODO: Add upper time limit for the delay */
+	do {
+		rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
+			FADUMP_UNREGISTER, fdm,
+			sizeof(struct fadump_mem_struct));
+
+		wait_time = rtas_busy_delay_time(rc);
+		if (wait_time)
+			mdelay(wait_time);
+	} while (wait_time);
+
+	if (rc) {
+		printk(KERN_ERR "Failed to un-register firmware-assisted dump."
+			" unexpected error(%d).\n", rc);
+		return rc;
+	}
+	fw_dump.dump_registered = 0;
+	return 0;
+}
+
+static int fadump_invalidate_dump(struct fadump_mem_struct *fdm)
+{
+	int rc = 0;
+	unsigned int wait_time;
+
+	pr_debug("Invalidating firmware-assisted dump registration\n");
+
+	/* TODO: Add upper time limit for the delay */
+	do {
+		rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
+			FADUMP_INVALIDATE, fdm,
+			sizeof(struct fadump_mem_struct));
+
+		wait_time = rtas_busy_delay_time(rc);
+		if (wait_time)
+			mdelay(wait_time);
+	} while (wait_time);
+
+	if (rc) {
+		printk(KERN_ERR "Failed to invalidate firmware-assisted dump "
+			"rgistration. unexpected error(%d).\n", rc);
+		return rc;
+	}
+	fw_dump.dump_active = 0;
+	fdm_active = NULL;
+	return 0;
+}
+
+void fadump_cleanup(void)
+{
+	/* Invalidate the registration only if dump is active. */
+	if (fw_dump.dump_active) {
+		init_fadump_mem_struct(&fdm,
+			fdm_active->cpu_state_data.destination_address);
+		fadump_invalidate_dump(&fdm);
+	}
+}
+
+/*
+ * Release the memory that was reserved in early boot to preserve the memory
+ * contents. The released memory will be available for general use.
+ */
+static void fadump_release_memory(unsigned long begin, unsigned long end)
+{
+	unsigned long addr;
+	unsigned long ra_start, ra_end;
+
+	ra_start = fw_dump.reserve_dump_area_start;
+	ra_end = ra_start + fw_dump.reserve_dump_area_size;
+
+	for (addr = begin; addr < end; addr += PAGE_SIZE) {
+		/*
+		 * exclude the dump reserve area. Will reuse it for next
+		 * fadump registration.
+		 */
+		if (addr <= ra_end && ((addr + PAGE_SIZE) > ra_start))
+			continue;
+
+		ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT));
+		init_page_count(pfn_to_page(addr >> PAGE_SHIFT));
+		free_page((unsigned long)__va(addr));
+		totalram_pages++;
+	}
+}
+
+static void fadump_invalidate_release_mem(void)
+{
+	unsigned long reserved_area_start, reserved_area_end;
+	unsigned long destination_address;
+
+	mutex_lock(&fadump_mutex);
+	if (!fw_dump.dump_active) {
+		mutex_unlock(&fadump_mutex);
+		return;
+	}
+
+	destination_address = fdm_active->cpu_state_data.destination_address;
+	fadump_cleanup();
+	mutex_unlock(&fadump_mutex);
+
+	/*
+	 * Save the current reserved memory bounds we will require them
+	 * later for releasing the memory for general use.
+	 */
+	reserved_area_start = fw_dump.reserve_dump_area_start;
+	reserved_area_end = reserved_area_start +
+			fw_dump.reserve_dump_area_size;
+	/*
+	 * Setup reserve_dump_area_start and its size so that we can
+	 * reuse this reserved memory for Re-registration.
+	 */
+	fw_dump.reserve_dump_area_start = destination_address;
+	fw_dump.reserve_dump_area_size = get_fadump_area_size();
+
+	fadump_release_memory(reserved_area_start, reserved_area_end);
+	if (fw_dump.cpu_notes_buf) {
+		fadump_cpu_notes_buf_free(
+				(unsigned long)__va(fw_dump.cpu_notes_buf),
+				fw_dump.cpu_notes_buf_size);
+		fw_dump.cpu_notes_buf = 0;
+		fw_dump.cpu_notes_buf_size = 0;
+	}
+	/* Initialize the kernel dump memory structure for FAD registration. */
+	init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
+}
+
+static ssize_t fadump_release_memory_store(struct kobject *kobj,
+					struct kobj_attribute *attr,
+					const char *buf, size_t count)
+{
+	if (!fw_dump.dump_active)
+		return -EPERM;
+
+	if (buf[0] == '1') {
+		/*
+		 * Take away the '/proc/vmcore'. We are releasing the dump
+		 * memory, hence it will not be valid anymore.
+		 */
+		vmcore_cleanup();
+		fadump_invalidate_release_mem();
+
+	} else
+		return -EINVAL;
+	return count;
+}
+
+static ssize_t fadump_enabled_show(struct kobject *kobj,
+					struct kobj_attribute *attr,
+					char *buf)
+{
+	return sprintf(buf, "%d\n", fw_dump.fadump_enabled);
+}
+
+static ssize_t fadump_register_show(struct kobject *kobj,
+					struct kobj_attribute *attr,
+					char *buf)
+{
+	return sprintf(buf, "%d\n", fw_dump.dump_registered);
+}
+
+static ssize_t fadump_register_store(struct kobject *kobj,
+					struct kobj_attribute *attr,
+					const char *buf, size_t count)
+{
+	int ret = 0;
+
+	if (!fw_dump.fadump_enabled || fdm_active)
+		return -EPERM;
+
+	mutex_lock(&fadump_mutex);
+
+	switch (buf[0]) {
+	case '0':
+		if (fw_dump.dump_registered == 0) {
+			ret = -EINVAL;
+			goto unlock_out;
+		}
+		/* Un-register Firmware-assisted dump */
+		fadump_unregister_dump(&fdm);
+		break;
+	case '1':
+		if (fw_dump.dump_registered == 1) {
+			ret = -EINVAL;
+			goto unlock_out;
+		}
+		/* Register Firmware-assisted dump */
+		register_fadump();
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+unlock_out:
+	mutex_unlock(&fadump_mutex);
+	return ret < 0 ? ret : count;
+}
+
+static int fadump_region_show(struct seq_file *m, void *private)
+{
+	const struct fadump_mem_struct *fdm_ptr;
+
+	if (!fw_dump.fadump_enabled)
+		return 0;
+
+	mutex_lock(&fadump_mutex);
+	if (fdm_active)
+		fdm_ptr = fdm_active;
+	else {
+		mutex_unlock(&fadump_mutex);
+		fdm_ptr = &fdm;
+	}
+
+	seq_printf(m,
+			"CPU : [%#016llx-%#016llx] %#llx bytes, "
+			"Dumped: %#llx\n",
+			fdm_ptr->cpu_state_data.destination_address,
+			fdm_ptr->cpu_state_data.destination_address +
+			fdm_ptr->cpu_state_data.source_len - 1,
+			fdm_ptr->cpu_state_data.source_len,
+			fdm_ptr->cpu_state_data.bytes_dumped);
+	seq_printf(m,
+			"HPTE: [%#016llx-%#016llx] %#llx bytes, "
+			"Dumped: %#llx\n",
+			fdm_ptr->hpte_region.destination_address,
+			fdm_ptr->hpte_region.destination_address +
+			fdm_ptr->hpte_region.source_len - 1,
+			fdm_ptr->hpte_region.source_len,
+			fdm_ptr->hpte_region.bytes_dumped);
+	seq_printf(m,
+			"DUMP: [%#016llx-%#016llx] %#llx bytes, "
+			"Dumped: %#llx\n",
+			fdm_ptr->rmr_region.destination_address,
+			fdm_ptr->rmr_region.destination_address +
+			fdm_ptr->rmr_region.source_len - 1,
+			fdm_ptr->rmr_region.source_len,
+			fdm_ptr->rmr_region.bytes_dumped);
+
+	if (!fdm_active ||
+		(fw_dump.reserve_dump_area_start ==
+		fdm_ptr->cpu_state_data.destination_address))
+		goto out;
+
+	/* Dump is active. Show reserved memory region. */
+	seq_printf(m,
+			"    : [%#016llx-%#016llx] %#llx bytes, "
+			"Dumped: %#llx\n",
+			(unsigned long long)fw_dump.reserve_dump_area_start,
+			fdm_ptr->cpu_state_data.destination_address - 1,
+			fdm_ptr->cpu_state_data.destination_address -
+			fw_dump.reserve_dump_area_start,
+			fdm_ptr->cpu_state_data.destination_address -
+			fw_dump.reserve_dump_area_start);
+out:
+	if (fdm_active)
+		mutex_unlock(&fadump_mutex);
+	return 0;
+}
+
+static struct kobj_attribute fadump_release_attr = __ATTR(fadump_release_mem,
+						0200, NULL,
+						fadump_release_memory_store);
+static struct kobj_attribute fadump_attr = __ATTR(fadump_enabled,
+						0444, fadump_enabled_show,
+						NULL);
+static struct kobj_attribute fadump_register_attr = __ATTR(fadump_registered,
+						0644, fadump_register_show,
+						fadump_register_store);
+
+static int fadump_region_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, fadump_region_show, inode->i_private);
+}
+
+static const struct file_operations fadump_region_fops = {
+	.open    = fadump_region_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = single_release,
+};
+
+static void fadump_init_files(void)
+{
+	struct dentry *debugfs_file;
+	int rc = 0;
+
+	rc = sysfs_create_file(kernel_kobj, &fadump_attr.attr);
+	if (rc)
+		printk(KERN_ERR "fadump: unable to create sysfs file"
+			" fadump_enabled (%d)\n", rc);
+
+	rc = sysfs_create_file(kernel_kobj, &fadump_register_attr.attr);
+	if (rc)
+		printk(KERN_ERR "fadump: unable to create sysfs file"
+			" fadump_registered (%d)\n", rc);
+
+	debugfs_file = debugfs_create_file("fadump_region", 0444,
+					powerpc_debugfs_root, NULL,
+					&fadump_region_fops);
+	if (!debugfs_file)
+		printk(KERN_ERR "fadump: unable to create debugfs file"
+				" fadump_region\n");
+
+	if (fw_dump.dump_active) {
+		rc = sysfs_create_file(kernel_kobj, &fadump_release_attr.attr);
+		if (rc)
+			printk(KERN_ERR "fadump: unable to create sysfs file"
+				" fadump_release_mem (%d)\n", rc);
+	}
+	return;
+}
+
+/*
+ * Prepare for firmware-assisted dump.
+ */
+int __init setup_fadump(void)
+{
+	if (!fw_dump.fadump_enabled)
+		return 0;
+
+	if (!fw_dump.fadump_supported) {
+		printk(KERN_ERR "Firmware-assisted dump is not supported on"
+			" this hardware\n");
+		return 0;
+	}
+
+	fadump_show_config();
+	/*
+	 * If dump data is available then see if it is valid and prepare for
+	 * saving it to the disk.
+	 */
+	if (fw_dump.dump_active) {
+		/*
+		 * if dump process fails then invalidate the registration
+		 * and release memory before proceeding for re-registration.
+		 */
+		if (process_fadump(fdm_active) < 0)
+			fadump_invalidate_release_mem();
+	}
+	/* Initialize the kernel dump memory structure for FAD registration. */
+	else if (fw_dump.reserve_dump_area_size)
+		init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
+	fadump_init_files();
+
+	return 1;
+}
+subsys_initcall(setup_fadump);
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index 0654dba..dc0488b 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -395,7 +395,7 @@
 	bl	hash_page
 1:	lwz	r5,_DSISR(r11)		/* get DSISR value */
 	mfspr	r4,SPRN_DAR
-	EXC_XFER_EE_LITE(0x300, handle_page_fault)
+	EXC_XFER_LITE(0x300, handle_page_fault)
 
 
 /* Instruction access exception. */
@@ -410,7 +410,7 @@
 	bl	hash_page
 1:	mr	r4,r12
 	mr	r5,r9
-	EXC_XFER_EE_LITE(0x400, handle_page_fault)
+	EXC_XFER_LITE(0x400, handle_page_fault)
 
 /* External interrupt */
 	EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S
index 872a6af..4989661 100644
--- a/arch/powerpc/kernel/head_40x.S
+++ b/arch/powerpc/kernel/head_40x.S
@@ -394,7 +394,7 @@
 	NORMAL_EXCEPTION_PROLOG
 	mr	r4,r12			/* Pass SRR0 as arg2 */
 	li	r5,0			/* Pass zero as arg3 */
-	EXC_XFER_EE_LITE(0x400, handle_page_fault)
+	EXC_XFER_LITE(0x400, handle_page_fault)
 
 /* 0x0500 - External Interrupt Exception */
 	EXCEPTION(0x0500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
@@ -747,7 +747,7 @@
 	mfspr	r5,SPRN_ESR		/* Grab the ESR, save it, pass arg3 */
 	stw	r5,_ESR(r11)
 	mfspr	r4,SPRN_DEAR		/* Grab the DEAR, save it, pass arg2 */
-	EXC_XFER_EE_LITE(0x300, handle_page_fault)
+	EXC_XFER_LITE(0x300, handle_page_fault)
 
 /* Other PowerPC processors, namely those derived from the 6xx-series
  * have vectors from 0x2100 through 0x2F00 defined, but marked as reserved.
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 06c7251..58bddee 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -32,13 +32,13 @@
 #include <asm/cputable.h>
 #include <asm/setup.h>
 #include <asm/hvcall.h>
-#include <asm/iseries/lpar_map.h>
 #include <asm/thread_info.h>
 #include <asm/firmware.h>
 #include <asm/page_64.h>
 #include <asm/irqflags.h>
 #include <asm/kvm_book3s_asm.h>
 #include <asm/ptrace.h>
+#include <asm/hw_irq.h>
 
 /* The physical memory is laid out such that the secondary processor
  * spin code sits at 0x0000...0x00ff. On server, the vectors follow
@@ -57,10 +57,6 @@
  *	entry in r9 for debugging purposes
  *   2. Secondary processors enter at 0x60 with PIR in gpr3
  *
- *  For iSeries:
- *   1. The MMU is on (as it always is for iSeries)
- *   2. The kernel is entered at system_reset_iSeries
- *
  *  For Book3E processors:
  *   1. The MMU is on running in AS0 in a state defined in ePAPR
  *   2. The kernel is entered at __start
@@ -93,15 +89,6 @@
 __secondary_hold_acknowledge:
 	.llong	0x0
 
-#ifdef CONFIG_PPC_ISERIES
-	/*
-	 * At offset 0x20, there is a pointer to iSeries LPAR data.
-	 * This is required by the hypervisor
-	 */
-	. = 0x20
-	.llong hvReleaseData-KERNELBASE
-#endif /* CONFIG_PPC_ISERIES */
-
 #ifdef CONFIG_RELOCATABLE
 	/* This flag is set to 1 by a loader if the kernel should run
 	 * at the loaded address instead of the linked address.  This
@@ -564,7 +551,8 @@
 	 */
 	li	r0,0
 	stb	r0,PACASOFTIRQEN(r13)
-	stb	r0,PACAHARDIRQEN(r13)
+	li	r0,PACA_IRQ_HARD_DIS
+	stb	r0,PACAIRQHAPPENED(r13)
 
 	/* Create a temp kernel stack for use before relocation is on.	*/
 	ld	r1,PACAEMERGSP(r13)
@@ -582,7 +570,7 @@
  *   1. Processor number
  *   2. Segment table pointer (virtual address)
  * On entry the following are set:
- *   r1	       = stack pointer.  vaddr for iSeries, raddr (temp stack) for pSeries
+ *   r1	       = stack pointer (real addr of temp stack)
  *   r24       = cpu# (in Linux terms)
  *   r13       = paca virtual address
  *   SPRG_PACA = paca virtual address
@@ -595,7 +583,7 @@
 	/* Set thread priority to MEDIUM */
 	HMT_MEDIUM
 
-	/* Initialize the kernel stack.  Just a repeat for iSeries.	 */
+	/* Initialize the kernel stack */
 	LOAD_REG_ADDR(r3, current_set)
 	sldi	r28,r24,3		/* get current_set[cpu#]	 */
 	ldx	r14,r3,r28
@@ -615,20 +603,16 @@
 	li	r7,0
 	mtlr	r7
 
+	/* Mark interrupts soft and hard disabled (they might be enabled
+	 * in the PACA when doing hotplug)
+	 */
+	stb	r7,PACASOFTIRQEN(r13)
+	li	r0,PACA_IRQ_HARD_DIS
+	stb	r0,PACAIRQHAPPENED(r13)
+
 	/* enable MMU and jump to start_secondary */
 	LOAD_REG_ADDR(r3, .start_secondary_prolog)
 	LOAD_REG_IMMEDIATE(r4, MSR_KERNEL)
-#ifdef CONFIG_PPC_ISERIES
-BEGIN_FW_FTR_SECTION
-	ori	r4,r4,MSR_EE
-	li	r8,1
-	stb	r8,PACAHARDIRQEN(r13)
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif
-BEGIN_FW_FTR_SECTION
-	stb	r7,PACAHARDIRQEN(r13)
-END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
-	stb	r7,PACASOFTIRQEN(r13)
 
 	mtspr	SPRN_SRR0,r3
 	mtspr	SPRN_SRR1,r4
@@ -771,22 +755,18 @@
 	/* Load the TOC (virtual address) */
 	ld	r2,PACATOC(r13)
 
+	/* Do more system initializations in virtual mode */
 	bl	.setup_system
 
-	/* Load up the kernel context */
-5:
-	li	r5,0
-	stb	r5,PACASOFTIRQEN(r13)	/* Soft Disabled */
-#ifdef CONFIG_PPC_ISERIES
-BEGIN_FW_FTR_SECTION
-	mfmsr	r5
-	ori	r5,r5,MSR_EE		/* Hard Enabled on iSeries*/
-	mtmsrd	r5
-	li	r5,1
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif
-	stb	r5,PACAHARDIRQEN(r13)	/* Hard Disabled on others */
+	/* Mark interrupts soft and hard disabled (they might be enabled
+	 * in the PACA when doing hotplug)
+	 */
+	li	r0,0
+	stb	r0,PACASOFTIRQEN(r13)
+	li	r0,PACA_IRQ_HARD_DIS
+	stb	r0,PACAIRQHAPPENED(r13)
 
+	/* Generic kernel entry */
 	bl	.start_kernel
 
 	/* Not reached */
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index b68cb17..b2a5860 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -220,7 +220,7 @@
 	mfspr	r4,SPRN_DAR
 	li	r10,0x00f0
 	mtspr	SPRN_DAR,r10	/* Tag DAR, to be used in DTLB Error */
-	EXC_XFER_EE_LITE(0x300, handle_page_fault)
+	EXC_XFER_LITE(0x300, handle_page_fault)
 
 /* Instruction access exception.
  * This is "never generated" by the MPC8xx.  We jump to it for other
@@ -231,7 +231,7 @@
 	EXCEPTION_PROLOG
 	mr	r4,r12
 	mr	r5,r9
-	EXC_XFER_EE_LITE(0x400, handle_page_fault)
+	EXC_XFER_LITE(0x400, handle_page_fault)
 
 /* External interrupt */
 	EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h
index fc921bf..0e41753 100644
--- a/arch/powerpc/kernel/head_booke.h
+++ b/arch/powerpc/kernel/head_booke.h
@@ -359,7 +359,7 @@
 	mfspr	r5,SPRN_ESR;		/* Grab the ESR and save it */	      \
 	stw	r5,_ESR(r11);						      \
 	mfspr	r4,SPRN_DEAR;		/* Grab the DEAR */		      \
-	EXC_XFER_EE_LITE(0x0300, handle_page_fault)
+	EXC_XFER_LITE(0x0300, handle_page_fault)
 
 #define INSTRUCTION_STORAGE_EXCEPTION					      \
 	START_EXCEPTION(InstructionStorage)				      \
@@ -368,7 +368,7 @@
 	stw	r5,_ESR(r11);						      \
 	mr      r4,r12;                 /* Pass SRR0 as arg2 */		      \
 	li      r5,0;                   /* Pass zero as arg3 */		      \
-	EXC_XFER_EE_LITE(0x0400, handle_page_fault)
+	EXC_XFER_LITE(0x0400, handle_page_fault)
 
 #define ALIGNMENT_EXCEPTION						      \
 	START_EXCEPTION(Alignment)					      \
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index d5d78c4..28e6259 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -319,7 +319,7 @@
 	mfspr	r4,SPRN_DEAR		/* Grab the DEAR, save it, pass arg2 */
 	andis.	r10,r5,(ESR_ILK|ESR_DLK)@h
 	bne	1f
-	EXC_XFER_EE_LITE(0x0300, handle_page_fault)
+	EXC_XFER_LITE(0x0300, handle_page_fault)
 1:
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	EXC_XFER_EE_LITE(0x0300, CacheLockingException)
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index 79bb282..b01d14e 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -65,7 +65,8 @@
 static void *ibmebus_alloc_coherent(struct device *dev,
 				    size_t size,
 				    dma_addr_t *dma_handle,
-				    gfp_t flag)
+				    gfp_t flag,
+				    struct dma_attrs *attrs)
 {
 	void *mem;
 
@@ -77,7 +78,8 @@
 
 static void ibmebus_free_coherent(struct device *dev,
 				  size_t size, void *vaddr,
-				  dma_addr_t dma_handle)
+				  dma_addr_t dma_handle,
+				  struct dma_attrs *attrs)
 {
 	kfree(vaddr);
 }
@@ -136,8 +138,8 @@
 }
 
 static struct dma_map_ops ibmebus_dma_ops = {
-	.alloc_coherent     = ibmebus_alloc_coherent,
-	.free_coherent      = ibmebus_free_coherent,
+	.alloc              = ibmebus_alloc_coherent,
+	.free               = ibmebus_free_coherent,
 	.map_sg             = ibmebus_map_sg,
 	.unmap_sg           = ibmebus_unmap_sg,
 	.dma_supported      = ibmebus_dma_supported,
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c
index c97fc60..6d2209a 100644
--- a/arch/powerpc/kernel/idle.c
+++ b/arch/powerpc/kernel/idle.c
@@ -26,11 +26,11 @@
 #include <linux/sysctl.h>
 #include <linux/tick.h>
 
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
+#include <asm/runlatch.h>
 #include <asm/smp.h>
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -84,7 +84,11 @@
 
 				start_critical_timings();
 
-				local_irq_enable();
+				/* Some power_save functions return with
+				 * interrupts enabled, some don't.
+				 */
+				if (irqs_disabled())
+					local_irq_enable();
 				set_thread_flag(TIF_POLLING_NRFLAG);
 
 			} else {
diff --git a/arch/powerpc/kernel/idle_book3e.S b/arch/powerpc/kernel/idle_book3e.S
index 16c002d..ff007b5 100644
--- a/arch/powerpc/kernel/idle_book3e.S
+++ b/arch/powerpc/kernel/idle_book3e.S
@@ -29,43 +29,30 @@
 	wrteei	0
 
 	/* Now check if an interrupt came in while we were soft disabled
-	 * since we may otherwise lose it (doorbells etc...). We know
-	 * that since PACAHARDIRQEN will have been cleared in that case.
+	 * since we may otherwise lose it (doorbells etc...).
 	 */
-	lbz	r3,PACAHARDIRQEN(r13)
+	lbz	r3,PACAIRQHAPPENED(r13)
 	cmpwi	cr0,r3,0
-	beqlr
+	bnelr
 
-	/* Now we are going to mark ourselves as soft and hard enables in
+	/* Now we are going to mark ourselves as soft and hard enabled in
 	 * order to be able to take interrupts while asleep. We inform lockdep
 	 * of that. We don't actually turn interrupts on just yet tho.
 	 */
 #ifdef CONFIG_TRACE_IRQFLAGS
 	stdu    r1,-128(r1)
 	bl	.trace_hardirqs_on
+	addi    r1,r1,128
 #endif
 	li	r0,1
 	stb	r0,PACASOFTIRQEN(r13)
-	stb	r0,PACAHARDIRQEN(r13)
 	
 	/* Interrupts will make use return to LR, so get something we want
 	 * in there
 	 */
 	bl	1f
 
-	/* Hard disable interrupts again */
-	wrteei	0
-
-	/* Mark them off again in the PACA as well */
-	li	r0,0
-	stb	r0,PACASOFTIRQEN(r13)
-	stb	r0,PACAHARDIRQEN(r13)
-
-	/* Tell lockdep about it */
-#ifdef CONFIG_TRACE_IRQFLAGS
-	bl	.trace_hardirqs_off
-	addi    r1,r1,128
-#endif
+	/* And return (interrupts are on) */
 	ld	r0,16(r1)
 	mtlr	r0
 	blr
diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S
index ba31954..2c71b0f 100644
--- a/arch/powerpc/kernel/idle_power4.S
+++ b/arch/powerpc/kernel/idle_power4.S
@@ -14,6 +14,7 @@
 #include <asm/thread_info.h>
 #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
+#include <asm/irqflags.h>
 
 #undef DEBUG
 
@@ -29,14 +30,31 @@
 	cmpwi	0,r4,0
 	beqlr
 
-	/* Go to NAP now */
+	/* Hard disable interrupts */
 	mfmsr	r7
 	rldicl	r0,r7,48,1
 	rotldi	r0,r0,16
-	mtmsrd	r0,1			/* hard-disable interrupts */
+	mtmsrd	r0,1
+
+	/* Check if something happened while soft-disabled */
+	lbz	r0,PACAIRQHAPPENED(r13)
+	cmpwi	cr0,r0,0
+	bnelr
+
+	/* Soft-enable interrupts */
+#ifdef CONFIG_TRACE_IRQFLAGS
+	mflr	r0
+	std	r0,16(r1)
+	stdu    r1,-128(r1)
+	bl	.trace_hardirqs_on
+	addi    r1,r1,128
+	ld	r0,16(r1)
+	mtlr	r0
+	mfmsr	r7
+#endif /* CONFIG_TRACE_IRQFLAGS */
+
 	li	r0,1
 	stb	r0,PACASOFTIRQEN(r13)	/* we'll hard-enable shortly */
-	stb	r0,PACAHARDIRQEN(r13)
 BEGIN_FTR_SECTION
 	DSSALL
 	sync
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S
index fcdff19..0cdc9a3 100644
--- a/arch/powerpc/kernel/idle_power7.S
+++ b/arch/powerpc/kernel/idle_power7.S
@@ -1,5 +1,5 @@
 /*
- *  This file contains the power_save function for 970-family CPUs.
+ *  This file contains the power_save function for Power7 CPUs.
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
@@ -15,6 +15,7 @@
 #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
 #include <asm/ppc-opcode.h>
+#include <asm/hw_irq.h>
 
 #undef DEBUG
 
@@ -51,9 +52,25 @@
 	rldicl	r9,r9,48,1
 	rotldi	r9,r9,16
 	mtmsrd	r9,1			/* hard-disable interrupts */
+
+	/* Check if something happened while soft-disabled */
+	lbz	r0,PACAIRQHAPPENED(r13)
+	cmpwi	cr0,r0,0
+	beq	1f
+	addi	r1,r1,INT_FRAME_SIZE
+	ld	r0,16(r1)
+	mtlr	r0
+	blr
+
+1:	/* We mark irqs hard disabled as this is the state we'll
+	 * be in when returning and we need to tell arch_local_irq_restore()
+	 * about it
+	 */
+	li	r0,PACA_IRQ_HARD_DIS
+	stb	r0,PACAIRQHAPPENED(r13)
+
+	/* We haven't lost state ... yet */
 	li	r0,0
-	stb	r0,PACASOFTIRQEN(r13)	/* we'll hard-enable shortly */
-	stb	r0,PACAHARDIRQEN(r13)
 	stb	r0,PACA_NAPSTATELOST(r13)
 
 	/* Continue saving state */
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 0cfcf98..359f078 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -39,6 +39,7 @@
 #include <asm/pci-bridge.h>
 #include <asm/machdep.h>
 #include <asm/kdump.h>
+#include <asm/fadump.h>
 
 #define DBG(...)
 
@@ -445,7 +446,12 @@
 
 static void iommu_table_clear(struct iommu_table *tbl)
 {
-	if (!is_kdump_kernel()) {
+	/*
+	 * In case of firmware assisted dump system goes through clean
+	 * reboot process at the time of system crash. Hence it's safe to
+	 * clear the TCE entries if firmware assisted dump is active.
+	 */
+	if (!is_kdump_kernel() || is_fadump_active()) {
 		/* Clear the table in case firmware left allocations in it */
 		ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size);
 		return;
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index bdfb3eee..243dbab 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -57,7 +57,6 @@
 #include <linux/of_irq.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
@@ -67,6 +66,7 @@
 #include <asm/machdep.h>
 #include <asm/udbg.h>
 #include <asm/smp.h>
+#include <asm/debug.h>
 
 #ifdef CONFIG_PPC64
 #include <asm/paca.h>
@@ -93,20 +93,16 @@
 
 #ifdef CONFIG_PPC64
 
-#ifndef CONFIG_SPARSE_IRQ
-EXPORT_SYMBOL(irq_desc);
-#endif
-
 int distribute_irqs = 1;
 
-static inline notrace unsigned long get_hard_enabled(void)
+static inline notrace unsigned long get_irq_happened(void)
 {
-	unsigned long enabled;
+	unsigned long happened;
 
 	__asm__ __volatile__("lbz %0,%1(13)"
-	: "=r" (enabled) : "i" (offsetof(struct paca_struct, hard_enabled)));
+	: "=r" (happened) : "i" (offsetof(struct paca_struct, irq_happened)));
 
-	return enabled;
+	return happened;
 }
 
 static inline notrace void set_soft_enabled(unsigned long enable)
@@ -115,75 +111,41 @@
 	: : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled)));
 }
 
-static inline notrace void decrementer_check_overflow(void)
+static inline notrace int decrementer_check_overflow(void)
 {
-	u64 now = get_tb_or_rtc();
-	u64 *next_tb;
-
-	preempt_disable();
-	next_tb = &__get_cpu_var(decrementers_next_tb);
-
+ 	u64 now = get_tb_or_rtc();
+ 	u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
+ 
 	if (now >= *next_tb)
 		set_dec(1);
-	preempt_enable();
+	return now >= *next_tb;
 }
 
-notrace void arch_local_irq_restore(unsigned long en)
+/* This is called whenever we are re-enabling interrupts
+ * and returns either 0 (nothing to do) or 500/900 if there's
+ * either an EE or a DEC to generate.
+ *
+ * This is called in two contexts: From arch_local_irq_restore()
+ * before soft-enabling interrupts, and from the exception exit
+ * path when returning from an interrupt from a soft-disabled to
+ * a soft enabled context. In both case we have interrupts hard
+ * disabled.
+ *
+ * We take care of only clearing the bits we handled in the
+ * PACA irq_happened field since we can only re-emit one at a
+ * time and we don't want to "lose" one.
+ */
+notrace unsigned int __check_irq_replay(void)
 {
 	/*
-	 * get_paca()->soft_enabled = en;
-	 * Is it ever valid to use local_irq_restore(0) when soft_enabled is 1?
-	 * That was allowed before, and in such a case we do need to take care
-	 * that gcc will set soft_enabled directly via r13, not choose to use
-	 * an intermediate register, lest we're preempted to a different cpu.
+	 * We use local_paca rather than get_paca() to avoid all
+	 * the debug_smp_processor_id() business in this low level
+	 * function
 	 */
-	set_soft_enabled(en);
-	if (!en)
-		return;
+	unsigned char happened = local_paca->irq_happened;
 
-#ifdef CONFIG_PPC_STD_MMU_64
-	if (firmware_has_feature(FW_FEATURE_ISERIES)) {
-		/*
-		 * Do we need to disable preemption here?  Not really: in the
-		 * unlikely event that we're preempted to a different cpu in
-		 * between getting r13, loading its lppaca_ptr, and loading
-		 * its any_int, we might call iseries_handle_interrupts without
-		 * an interrupt pending on the new cpu, but that's no disaster,
-		 * is it?  And the business of preempting us off the old cpu
-		 * would itself involve a local_irq_restore which handles the
-		 * interrupt to that cpu.
-		 *
-		 * But use "local_paca->lppaca_ptr" instead of "get_lppaca()"
-		 * to avoid any preemption checking added into get_paca().
-		 */
-		if (local_paca->lppaca_ptr->int_dword.any_int)
-			iseries_handle_interrupts();
-	}
-#endif /* CONFIG_PPC_STD_MMU_64 */
-
-	/*
-	 * if (get_paca()->hard_enabled) return;
-	 * But again we need to take care that gcc gets hard_enabled directly
-	 * via r13, not choose to use an intermediate register, lest we're
-	 * preempted to a different cpu in between the two instructions.
-	 */
-	if (get_hard_enabled())
-		return;
-
-	/*
-	 * Need to hard-enable interrupts here.  Since currently disabled,
-	 * no need to take further asm precautions against preemption; but
-	 * use local_paca instead of get_paca() to avoid preemption checking.
-	 */
-	local_paca->hard_enabled = en;
-
-	/*
-	 * Trigger the decrementer if we have a pending event. Some processors
-	 * only trigger on edge transitions of the sign bit. We might also
-	 * have disabled interrupts long enough that the decrementer wrapped
-	 * to positive.
-	 */
-	decrementer_check_overflow();
+	/* Clear bit 0 which we wouldn't clear otherwise */
+	local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS;
 
 	/*
 	 * Force the delivery of pending soft-disabled interrupts on PS3.
@@ -194,9 +156,117 @@
 		lv1_get_version_info(&tmp, &tmp2);
 	}
 
+	/*
+	 * We may have missed a decrementer interrupt. We check the
+	 * decrementer itself rather than the paca irq_happened field
+	 * in case we also had a rollover while hard disabled
+	 */
+	local_paca->irq_happened &= ~PACA_IRQ_DEC;
+	if (decrementer_check_overflow())
+		return 0x900;
+
+	/* Finally check if an external interrupt happened */
+	local_paca->irq_happened &= ~PACA_IRQ_EE;
+	if (happened & PACA_IRQ_EE)
+		return 0x500;
+
+#ifdef CONFIG_PPC_BOOK3E
+	/* Finally check if an EPR external interrupt happened
+	 * this bit is typically set if we need to handle another
+	 * "edge" interrupt from within the MPIC "EPR" handler
+	 */
+	local_paca->irq_happened &= ~PACA_IRQ_EE_EDGE;
+	if (happened & PACA_IRQ_EE_EDGE)
+		return 0x500;
+
+	local_paca->irq_happened &= ~PACA_IRQ_DBELL;
+	if (happened & PACA_IRQ_DBELL)
+		return 0x280;
+#endif /* CONFIG_PPC_BOOK3E */
+
+	/* There should be nothing left ! */
+	BUG_ON(local_paca->irq_happened != 0);
+
+	return 0;
+}
+
+notrace void arch_local_irq_restore(unsigned long en)
+{
+	unsigned char irq_happened;
+	unsigned int replay;
+
+	/* Write the new soft-enabled value */
+	set_soft_enabled(en);
+	if (!en)
+		return;
+	/*
+	 * From this point onward, we can take interrupts, preempt,
+	 * etc... unless we got hard-disabled. We check if an event
+	 * happened. If none happened, we know we can just return.
+	 *
+	 * We may have preempted before the check below, in which case
+	 * we are checking the "new" CPU instead of the old one. This
+	 * is only a problem if an event happened on the "old" CPU.
+	 *
+	 * External interrupt events will have caused interrupts to
+	 * be hard-disabled, so there is no problem, we
+	 * cannot have preempted.
+	 */
+	irq_happened = get_irq_happened();
+	if (!irq_happened)
+		return;
+
+	/*
+	 * We need to hard disable to get a trusted value from
+	 * __check_irq_replay(). We also need to soft-disable
+	 * again to avoid warnings in there due to the use of
+	 * per-cpu variables.
+	 *
+	 * We know that if the value in irq_happened is exactly 0x01
+	 * then we are already hard disabled (there are other less
+	 * common cases that we'll ignore for now), so we skip the
+	 * (expensive) mtmsrd.
+	 */
+	if (unlikely(irq_happened != PACA_IRQ_HARD_DIS))
+		__hard_irq_disable();
+	set_soft_enabled(0);
+
+	/*
+	 * Check if anything needs to be re-emitted. We haven't
+	 * soft-enabled yet to avoid warnings in decrementer_check_overflow
+	 * accessing per-cpu variables
+	 */
+	replay = __check_irq_replay();
+
+	/* We can soft-enable now */
+	set_soft_enabled(1);
+
+	/*
+	 * And replay if we have to. This will return with interrupts
+	 * hard-enabled.
+	 */
+	if (replay) {
+		__replay_interrupt(replay);
+		return;
+	}
+
+	/* Finally, let's ensure we are hard enabled */
 	__hard_irq_enable();
 }
 EXPORT_SYMBOL(arch_local_irq_restore);
+
+/*
+ * This is specifically called by assembly code to re-enable interrupts
+ * if they are currently disabled. This is typically called before
+ * schedule() or do_signal() when returning to userspace. We do it
+ * in C to avoid the burden of dealing with lockdep etc...
+ */
+void restore_interrupts(void)
+{
+	if (irqs_disabled())
+		local_irq_enable();
+}
+
 #endif /* CONFIG_PPC64 */
 
 int arch_show_interrupts(struct seq_file *p, int prec)
@@ -364,25 +434,25 @@
 
 	check_stack_overflow();
 
+	/*
+	 * Query the platform PIC for the interrupt & ack it.
+	 *
+	 * This will typically lower the interrupt line to the CPU
+	 */
 	irq = ppc_md.get_irq();
 
-	if (irq != NO_IRQ && irq != NO_IRQ_IGNORE)
+	/* We can hard enable interrupts now */
+	may_hard_irq_enable();
+
+	/* And finally process it */
+	if (irq != NO_IRQ)
 		handle_one_irq(irq);
-	else if (irq != NO_IRQ_IGNORE)
+	else
 		__get_cpu_var(irq_stat).spurious_irqs++;
 
 	irq_exit();
 	set_irq_regs(old_regs);
 
-#ifdef CONFIG_PPC_ISERIES
-	if (firmware_has_feature(FW_FEATURE_ISERIES) &&
-			get_lppaca()->int_dword.fields.decr_int) {
-		get_lppaca()->int_dword.fields.decr_int = 0;
-		/* Signal a fake decrementer interrupt */
-		timer_interrupt(regs);
-	}
-#endif
-
 	trace_irq_exit(regs);
 }
 
diff --git a/arch/powerpc/kernel/isa-bridge.c b/arch/powerpc/kernel/isa-bridge.c
index 4797529..d45ec58 100644
--- a/arch/powerpc/kernel/isa-bridge.c
+++ b/arch/powerpc/kernel/isa-bridge.c
@@ -29,7 +29,6 @@
 #include <asm/pci-bridge.h>
 #include <asm/machdep.h>
 #include <asm/ppc-pci.h>
-#include <asm/firmware.h>
 
 unsigned long isa_io_base;	/* NULL if no ISA bus */
 EXPORT_SYMBOL(isa_io_base);
@@ -261,8 +260,6 @@
  */
 static int __init isa_bridge_init(void)
 {
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		return 0;
 	bus_register_notifier(&pci_bus_type, &isa_bridge_notifier);
 	return 0;
 }
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
index 76a6e40..782bd0a 100644
--- a/arch/powerpc/kernel/kgdb.c
+++ b/arch/powerpc/kernel/kgdb.c
@@ -24,6 +24,7 @@
 #include <asm/current.h>
 #include <asm/processor.h>
 #include <asm/machdep.h>
+#include <asm/debug.h>
 
 /*
  * This table contains the mapping between PowerPC hardware trap types, and
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index bc47352..e88c643 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -35,7 +35,6 @@
 #include <asm/cacheflush.h>
 #include <asm/sstep.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
 #define MSR_SINGLESTEP	(MSR_DE)
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c
index 2985338..62bdf23 100644
--- a/arch/powerpc/kernel/kvm.c
+++ b/arch/powerpc/kernel/kvm.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved.
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
  *
  * Authors:
  *     Alexander Graf <agraf@suse.de>
@@ -29,6 +30,7 @@
 #include <asm/sections.h>
 #include <asm/cacheflush.h>
 #include <asm/disassemble.h>
+#include <asm/ppc-opcode.h>
 
 #define KVM_MAGIC_PAGE		(-4096L)
 #define magic_var(x) KVM_MAGIC_PAGE + offsetof(struct kvm_vcpu_arch_shared, x)
@@ -41,34 +43,30 @@
 #define KVM_INST_B		0x48000000
 #define KVM_INST_B_MASK		0x03ffffff
 #define KVM_INST_B_MAX		0x01ffffff
+#define KVM_INST_LI		0x38000000
 
 #define KVM_MASK_RT		0x03e00000
 #define KVM_RT_30		0x03c00000
 #define KVM_MASK_RB		0x0000f800
 #define KVM_INST_MFMSR		0x7c0000a6
-#define KVM_INST_MFSPR_SPRG0	0x7c1042a6
-#define KVM_INST_MFSPR_SPRG1	0x7c1142a6
-#define KVM_INST_MFSPR_SPRG2	0x7c1242a6
-#define KVM_INST_MFSPR_SPRG3	0x7c1342a6
-#define KVM_INST_MFSPR_SRR0	0x7c1a02a6
-#define KVM_INST_MFSPR_SRR1	0x7c1b02a6
-#define KVM_INST_MFSPR_DAR	0x7c1302a6
-#define KVM_INST_MFSPR_DSISR	0x7c1202a6
 
-#define KVM_INST_MTSPR_SPRG0	0x7c1043a6
-#define KVM_INST_MTSPR_SPRG1	0x7c1143a6
-#define KVM_INST_MTSPR_SPRG2	0x7c1243a6
-#define KVM_INST_MTSPR_SPRG3	0x7c1343a6
-#define KVM_INST_MTSPR_SRR0	0x7c1a03a6
-#define KVM_INST_MTSPR_SRR1	0x7c1b03a6
-#define KVM_INST_MTSPR_DAR	0x7c1303a6
-#define KVM_INST_MTSPR_DSISR	0x7c1203a6
+#define SPR_FROM		0
+#define SPR_TO			0x100
+
+#define KVM_INST_SPR(sprn, moveto) (0x7c0002a6 | \
+				    (((sprn) & 0x1f) << 16) | \
+				    (((sprn) & 0x3e0) << 6) | \
+				    (moveto))
+
+#define KVM_INST_MFSPR(sprn)	KVM_INST_SPR(sprn, SPR_FROM)
+#define KVM_INST_MTSPR(sprn)	KVM_INST_SPR(sprn, SPR_TO)
 
 #define KVM_INST_TLBSYNC	0x7c00046c
 #define KVM_INST_MTMSRD_L0	0x7c000164
 #define KVM_INST_MTMSRD_L1	0x7c010164
 #define KVM_INST_MTMSR		0x7c000124
 
+#define KVM_INST_WRTEE		0x7c000106
 #define KVM_INST_WRTEEI_0	0x7c000146
 #define KVM_INST_WRTEEI_1	0x7c008146
 
@@ -270,26 +268,27 @@
 
 #ifdef CONFIG_BOOKE
 
-extern u32 kvm_emulate_wrteei_branch_offs;
-extern u32 kvm_emulate_wrteei_ee_offs;
-extern u32 kvm_emulate_wrteei_len;
-extern u32 kvm_emulate_wrteei[];
+extern u32 kvm_emulate_wrtee_branch_offs;
+extern u32 kvm_emulate_wrtee_reg_offs;
+extern u32 kvm_emulate_wrtee_orig_ins_offs;
+extern u32 kvm_emulate_wrtee_len;
+extern u32 kvm_emulate_wrtee[];
 
-static void kvm_patch_ins_wrteei(u32 *inst)
+static void kvm_patch_ins_wrtee(u32 *inst, u32 rt, int imm_one)
 {
 	u32 *p;
 	int distance_start;
 	int distance_end;
 	ulong next_inst;
 
-	p = kvm_alloc(kvm_emulate_wrteei_len * 4);
+	p = kvm_alloc(kvm_emulate_wrtee_len * 4);
 	if (!p)
 		return;
 
 	/* Find out where we are and put everything there */
 	distance_start = (ulong)p - (ulong)inst;
 	next_inst = ((ulong)inst + 4);
-	distance_end = next_inst - (ulong)&p[kvm_emulate_wrteei_branch_offs];
+	distance_end = next_inst - (ulong)&p[kvm_emulate_wrtee_branch_offs];
 
 	/* Make sure we only write valid b instructions */
 	if (distance_start > KVM_INST_B_MAX) {
@@ -298,10 +297,65 @@
 	}
 
 	/* Modify the chunk to fit the invocation */
-	memcpy(p, kvm_emulate_wrteei, kvm_emulate_wrteei_len * 4);
-	p[kvm_emulate_wrteei_branch_offs] |= distance_end & KVM_INST_B_MASK;
-	p[kvm_emulate_wrteei_ee_offs] |= (*inst & MSR_EE);
-	flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrteei_len * 4);
+	memcpy(p, kvm_emulate_wrtee, kvm_emulate_wrtee_len * 4);
+	p[kvm_emulate_wrtee_branch_offs] |= distance_end & KVM_INST_B_MASK;
+
+	if (imm_one) {
+		p[kvm_emulate_wrtee_reg_offs] =
+			KVM_INST_LI | __PPC_RT(30) | MSR_EE;
+	} else {
+		/* Make clobbered registers work too */
+		switch (get_rt(rt)) {
+		case 30:
+			kvm_patch_ins_ll(&p[kvm_emulate_wrtee_reg_offs],
+					 magic_var(scratch2), KVM_RT_30);
+			break;
+		case 31:
+			kvm_patch_ins_ll(&p[kvm_emulate_wrtee_reg_offs],
+					 magic_var(scratch1), KVM_RT_30);
+			break;
+		default:
+			p[kvm_emulate_wrtee_reg_offs] |= rt;
+			break;
+		}
+	}
+
+	p[kvm_emulate_wrtee_orig_ins_offs] = *inst;
+	flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrtee_len * 4);
+
+	/* Patch the invocation */
+	kvm_patch_ins_b(inst, distance_start);
+}
+
+extern u32 kvm_emulate_wrteei_0_branch_offs;
+extern u32 kvm_emulate_wrteei_0_len;
+extern u32 kvm_emulate_wrteei_0[];
+
+static void kvm_patch_ins_wrteei_0(u32 *inst)
+{
+	u32 *p;
+	int distance_start;
+	int distance_end;
+	ulong next_inst;
+
+	p = kvm_alloc(kvm_emulate_wrteei_0_len * 4);
+	if (!p)
+		return;
+
+	/* Find out where we are and put everything there */
+	distance_start = (ulong)p - (ulong)inst;
+	next_inst = ((ulong)inst + 4);
+	distance_end = next_inst - (ulong)&p[kvm_emulate_wrteei_0_branch_offs];
+
+	/* Make sure we only write valid b instructions */
+	if (distance_start > KVM_INST_B_MAX) {
+		kvm_patching_worked = false;
+		return;
+	}
+
+	memcpy(p, kvm_emulate_wrteei_0, kvm_emulate_wrteei_0_len * 4);
+	p[kvm_emulate_wrteei_0_branch_offs] |= distance_end & KVM_INST_B_MASK;
+	flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrteei_0_len * 4);
 
 	/* Patch the invocation */
 	kvm_patch_ins_b(inst, distance_start);
@@ -380,56 +434,191 @@
 	case KVM_INST_MFMSR:
 		kvm_patch_ins_ld(inst, magic_var(msr), inst_rt);
 		break;
-	case KVM_INST_MFSPR_SPRG0:
+	case KVM_INST_MFSPR(SPRN_SPRG0):
 		kvm_patch_ins_ld(inst, magic_var(sprg0), inst_rt);
 		break;
-	case KVM_INST_MFSPR_SPRG1:
+	case KVM_INST_MFSPR(SPRN_SPRG1):
 		kvm_patch_ins_ld(inst, magic_var(sprg1), inst_rt);
 		break;
-	case KVM_INST_MFSPR_SPRG2:
+	case KVM_INST_MFSPR(SPRN_SPRG2):
 		kvm_patch_ins_ld(inst, magic_var(sprg2), inst_rt);
 		break;
-	case KVM_INST_MFSPR_SPRG3:
+	case KVM_INST_MFSPR(SPRN_SPRG3):
 		kvm_patch_ins_ld(inst, magic_var(sprg3), inst_rt);
 		break;
-	case KVM_INST_MFSPR_SRR0:
+	case KVM_INST_MFSPR(SPRN_SRR0):
 		kvm_patch_ins_ld(inst, magic_var(srr0), inst_rt);
 		break;
-	case KVM_INST_MFSPR_SRR1:
+	case KVM_INST_MFSPR(SPRN_SRR1):
 		kvm_patch_ins_ld(inst, magic_var(srr1), inst_rt);
 		break;
-	case KVM_INST_MFSPR_DAR:
+#ifdef CONFIG_BOOKE
+	case KVM_INST_MFSPR(SPRN_DEAR):
+#else
+	case KVM_INST_MFSPR(SPRN_DAR):
+#endif
 		kvm_patch_ins_ld(inst, magic_var(dar), inst_rt);
 		break;
-	case KVM_INST_MFSPR_DSISR:
+	case KVM_INST_MFSPR(SPRN_DSISR):
 		kvm_patch_ins_lwz(inst, magic_var(dsisr), inst_rt);
 		break;
 
+#ifdef CONFIG_PPC_BOOK3E_MMU
+	case KVM_INST_MFSPR(SPRN_MAS0):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_lwz(inst, magic_var(mas0), inst_rt);
+		break;
+	case KVM_INST_MFSPR(SPRN_MAS1):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_lwz(inst, magic_var(mas1), inst_rt);
+		break;
+	case KVM_INST_MFSPR(SPRN_MAS2):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_ld(inst, magic_var(mas2), inst_rt);
+		break;
+	case KVM_INST_MFSPR(SPRN_MAS3):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_lwz(inst, magic_var(mas7_3) + 4, inst_rt);
+		break;
+	case KVM_INST_MFSPR(SPRN_MAS4):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_lwz(inst, magic_var(mas4), inst_rt);
+		break;
+	case KVM_INST_MFSPR(SPRN_MAS6):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_lwz(inst, magic_var(mas6), inst_rt);
+		break;
+	case KVM_INST_MFSPR(SPRN_MAS7):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_lwz(inst, magic_var(mas7_3), inst_rt);
+		break;
+#endif /* CONFIG_PPC_BOOK3E_MMU */
+
+	case KVM_INST_MFSPR(SPRN_SPRG4):
+#ifdef CONFIG_BOOKE
+	case KVM_INST_MFSPR(SPRN_SPRG4R):
+#endif
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_ld(inst, magic_var(sprg4), inst_rt);
+		break;
+	case KVM_INST_MFSPR(SPRN_SPRG5):
+#ifdef CONFIG_BOOKE
+	case KVM_INST_MFSPR(SPRN_SPRG5R):
+#endif
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_ld(inst, magic_var(sprg5), inst_rt);
+		break;
+	case KVM_INST_MFSPR(SPRN_SPRG6):
+#ifdef CONFIG_BOOKE
+	case KVM_INST_MFSPR(SPRN_SPRG6R):
+#endif
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_ld(inst, magic_var(sprg6), inst_rt);
+		break;
+	case KVM_INST_MFSPR(SPRN_SPRG7):
+#ifdef CONFIG_BOOKE
+	case KVM_INST_MFSPR(SPRN_SPRG7R):
+#endif
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_ld(inst, magic_var(sprg7), inst_rt);
+		break;
+
+#ifdef CONFIG_BOOKE
+	case KVM_INST_MFSPR(SPRN_ESR):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_lwz(inst, magic_var(esr), inst_rt);
+		break;
+#endif
+
+	case KVM_INST_MFSPR(SPRN_PIR):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_lwz(inst, magic_var(pir), inst_rt);
+		break;
+
+
 	/* Stores */
-	case KVM_INST_MTSPR_SPRG0:
+	case KVM_INST_MTSPR(SPRN_SPRG0):
 		kvm_patch_ins_std(inst, magic_var(sprg0), inst_rt);
 		break;
-	case KVM_INST_MTSPR_SPRG1:
+	case KVM_INST_MTSPR(SPRN_SPRG1):
 		kvm_patch_ins_std(inst, magic_var(sprg1), inst_rt);
 		break;
-	case KVM_INST_MTSPR_SPRG2:
+	case KVM_INST_MTSPR(SPRN_SPRG2):
 		kvm_patch_ins_std(inst, magic_var(sprg2), inst_rt);
 		break;
-	case KVM_INST_MTSPR_SPRG3:
+	case KVM_INST_MTSPR(SPRN_SPRG3):
 		kvm_patch_ins_std(inst, magic_var(sprg3), inst_rt);
 		break;
-	case KVM_INST_MTSPR_SRR0:
+	case KVM_INST_MTSPR(SPRN_SRR0):
 		kvm_patch_ins_std(inst, magic_var(srr0), inst_rt);
 		break;
-	case KVM_INST_MTSPR_SRR1:
+	case KVM_INST_MTSPR(SPRN_SRR1):
 		kvm_patch_ins_std(inst, magic_var(srr1), inst_rt);
 		break;
-	case KVM_INST_MTSPR_DAR:
+#ifdef CONFIG_BOOKE
+	case KVM_INST_MTSPR(SPRN_DEAR):
+#else
+	case KVM_INST_MTSPR(SPRN_DAR):
+#endif
 		kvm_patch_ins_std(inst, magic_var(dar), inst_rt);
 		break;
-	case KVM_INST_MTSPR_DSISR:
+	case KVM_INST_MTSPR(SPRN_DSISR):
 		kvm_patch_ins_stw(inst, magic_var(dsisr), inst_rt);
 		break;
+#ifdef CONFIG_PPC_BOOK3E_MMU
+	case KVM_INST_MTSPR(SPRN_MAS0):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_stw(inst, magic_var(mas0), inst_rt);
+		break;
+	case KVM_INST_MTSPR(SPRN_MAS1):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_stw(inst, magic_var(mas1), inst_rt);
+		break;
+	case KVM_INST_MTSPR(SPRN_MAS2):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_std(inst, magic_var(mas2), inst_rt);
+		break;
+	case KVM_INST_MTSPR(SPRN_MAS3):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_stw(inst, magic_var(mas7_3) + 4, inst_rt);
+		break;
+	case KVM_INST_MTSPR(SPRN_MAS4):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_stw(inst, magic_var(mas4), inst_rt);
+		break;
+	case KVM_INST_MTSPR(SPRN_MAS6):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_stw(inst, magic_var(mas6), inst_rt);
+		break;
+	case KVM_INST_MTSPR(SPRN_MAS7):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_stw(inst, magic_var(mas7_3), inst_rt);
+		break;
+#endif /* CONFIG_PPC_BOOK3E_MMU */
+
+	case KVM_INST_MTSPR(SPRN_SPRG4):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_std(inst, magic_var(sprg4), inst_rt);
+		break;
+	case KVM_INST_MTSPR(SPRN_SPRG5):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_std(inst, magic_var(sprg5), inst_rt);
+		break;
+	case KVM_INST_MTSPR(SPRN_SPRG6):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_std(inst, magic_var(sprg6), inst_rt);
+		break;
+	case KVM_INST_MTSPR(SPRN_SPRG7):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_std(inst, magic_var(sprg7), inst_rt);
+		break;
+
+#ifdef CONFIG_BOOKE
+	case KVM_INST_MTSPR(SPRN_ESR):
+		if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+			kvm_patch_ins_stw(inst, magic_var(esr), inst_rt);
+		break;
+#endif
 
 	/* Nops */
 	case KVM_INST_TLBSYNC:
@@ -444,6 +633,11 @@
 	case KVM_INST_MTMSRD_L0:
 		kvm_patch_ins_mtmsr(inst, inst_rt);
 		break;
+#ifdef CONFIG_BOOKE
+	case KVM_INST_WRTEE:
+		kvm_patch_ins_wrtee(inst, inst_rt, 0);
+		break;
+#endif
 	}
 
 	switch (inst_no_rt & ~KVM_MASK_RB) {
@@ -461,13 +655,19 @@
 	switch (_inst) {
 #ifdef CONFIG_BOOKE
 	case KVM_INST_WRTEEI_0:
+		kvm_patch_ins_wrteei_0(inst);
+		break;
+
 	case KVM_INST_WRTEEI_1:
-		kvm_patch_ins_wrteei(inst);
+		kvm_patch_ins_wrtee(inst, 0, 1);
 		break;
 #endif
 	}
 }
 
+extern u32 kvm_template_start[];
+extern u32 kvm_template_end[];
+
 static void kvm_use_magic_page(void)
 {
 	u32 *p;
@@ -488,8 +688,23 @@
 	start = (void*)_stext;
 	end = (void*)_etext;
 
-	for (p = start; p < end; p++)
+	/*
+	 * Being interrupted in the middle of patching would
+	 * be bad for SPRG4-7, which KVM can't keep in sync
+	 * with emulated accesses because reads don't trap.
+	 */
+	local_irq_disable();
+
+	for (p = start; p < end; p++) {
+		/* Avoid patching the template code */
+		if (p >= kvm_template_start && p < kvm_template_end) {
+			p = kvm_template_end - 1;
+			continue;
+		}
 		kvm_check_ins(p, features);
+	}
+
+	local_irq_enable();
 
 	printk(KERN_INFO "KVM: Live patching for a fast VM %s\n",
 			 kvm_patching_worked ? "worked" : "failed");
diff --git a/arch/powerpc/kernel/kvm_emul.S b/arch/powerpc/kernel/kvm_emul.S
index f2b1b25..e291cf3 100644
--- a/arch/powerpc/kernel/kvm_emul.S
+++ b/arch/powerpc/kernel/kvm_emul.S
@@ -13,6 +13,7 @@
  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  *
  * Copyright SUSE Linux Products GmbH 2010
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
  *
  * Authors: Alexander Graf <agraf@suse.de>
  */
@@ -65,6 +66,9 @@
 	   shared->critical == r1 and r2 is always != r1 */		\
 	STL64(r2, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0);
 
+.global kvm_template_start
+kvm_template_start:
+
 .global kvm_emulate_mtmsrd
 kvm_emulate_mtmsrd:
 
@@ -167,6 +171,9 @@
 kvm_emulate_mtmsr_reg2:
 	ori	r30, r0, 0
 
+	/* Put MSR into magic page because we don't call mtmsr */
+	STL64(r30, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
 	/* Check if we have to fetch an interrupt */
 	lwz	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
 	cmpwi	r31, 0
@@ -174,15 +181,10 @@
 
 	/* Check if we may trigger an interrupt */
 	andi.	r31, r30, MSR_EE
-	beq	no_mtmsr
-
-	b	do_mtmsr
+	bne	do_mtmsr
 
 no_mtmsr:
 
-	/* Put MSR into magic page because we don't call mtmsr */
-	STL64(r30, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
-
 	SCRATCH_RESTORE
 
 	/* Go back to caller */
@@ -210,24 +212,80 @@
 kvm_emulate_mtmsr_len:
 	.long (kvm_emulate_mtmsr_end - kvm_emulate_mtmsr) / 4
 
-
-
-.global kvm_emulate_wrteei
-kvm_emulate_wrteei:
+/* also used for wrteei 1 */
+.global kvm_emulate_wrtee
+kvm_emulate_wrtee:
 
 	SCRATCH_SAVE
 
 	/* Fetch old MSR in r31 */
 	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
 
-	/* Remove MSR_EE from old MSR */
-	li	r30, 0
-	ori	r30, r30, MSR_EE
-	andc	r31, r31, r30
+	/* Insert new MSR[EE] */
+kvm_emulate_wrtee_reg:
+	ori	r30, r0, 0
+	rlwimi	r31, r30, 0, MSR_EE
 
-	/* OR new MSR_EE onto the old MSR */
-kvm_emulate_wrteei_ee:
-	ori	r31, r31, 0
+	/*
+	 * If MSR[EE] is now set, check for a pending interrupt.
+	 * We could skip this if MSR[EE] was already on, but that
+	 * should be rare, so don't bother.
+	 */
+	andi.	r30, r30, MSR_EE
+
+	/* Put MSR into magic page because we don't call wrtee */
+	STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
+	beq	no_wrtee
+
+	/* Check if we have to fetch an interrupt */
+	lwz	r30, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
+	cmpwi	r30, 0
+	bne	do_wrtee
+
+no_wrtee:
+	SCRATCH_RESTORE
+
+	/* Go back to caller */
+kvm_emulate_wrtee_branch:
+	b	.
+
+do_wrtee:
+	SCRATCH_RESTORE
+
+	/* Just fire off the wrtee if it's critical */
+kvm_emulate_wrtee_orig_ins:
+	wrtee	r0
+
+	b	kvm_emulate_wrtee_branch
+
+kvm_emulate_wrtee_end:
+
+.global kvm_emulate_wrtee_branch_offs
+kvm_emulate_wrtee_branch_offs:
+	.long (kvm_emulate_wrtee_branch - kvm_emulate_wrtee) / 4
+
+.global kvm_emulate_wrtee_reg_offs
+kvm_emulate_wrtee_reg_offs:
+	.long (kvm_emulate_wrtee_reg - kvm_emulate_wrtee) / 4
+
+.global kvm_emulate_wrtee_orig_ins_offs
+kvm_emulate_wrtee_orig_ins_offs:
+	.long (kvm_emulate_wrtee_orig_ins - kvm_emulate_wrtee) / 4
+
+.global kvm_emulate_wrtee_len
+kvm_emulate_wrtee_len:
+	.long (kvm_emulate_wrtee_end - kvm_emulate_wrtee) / 4
+
+.global kvm_emulate_wrteei_0
+kvm_emulate_wrteei_0:
+	SCRATCH_SAVE
+
+	/* Fetch old MSR in r31 */
+	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
+	/* Remove MSR_EE from old MSR */
+	rlwinm	r31, r31, 0, ~MSR_EE
 
 	/* Write new MSR value back */
 	STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
@@ -235,22 +293,17 @@
 	SCRATCH_RESTORE
 
 	/* Go back to caller */
-kvm_emulate_wrteei_branch:
+kvm_emulate_wrteei_0_branch:
 	b	.
-kvm_emulate_wrteei_end:
+kvm_emulate_wrteei_0_end:
 
-.global kvm_emulate_wrteei_branch_offs
-kvm_emulate_wrteei_branch_offs:
-	.long (kvm_emulate_wrteei_branch - kvm_emulate_wrteei) / 4
+.global kvm_emulate_wrteei_0_branch_offs
+kvm_emulate_wrteei_0_branch_offs:
+	.long (kvm_emulate_wrteei_0_branch - kvm_emulate_wrteei_0) / 4
 
-.global kvm_emulate_wrteei_ee_offs
-kvm_emulate_wrteei_ee_offs:
-	.long (kvm_emulate_wrteei_ee - kvm_emulate_wrteei) / 4
-
-.global kvm_emulate_wrteei_len
-kvm_emulate_wrteei_len:
-	.long (kvm_emulate_wrteei_end - kvm_emulate_wrteei) / 4
-
+.global kvm_emulate_wrteei_0_len
+kvm_emulate_wrteei_0_len:
+	.long (kvm_emulate_wrteei_0_end - kvm_emulate_wrteei_0) / 4
 
 .global kvm_emulate_mtsrin
 kvm_emulate_mtsrin:
@@ -300,3 +353,6 @@
 .global kvm_emulate_mtsrin_len
 kvm_emulate_mtsrin_len:
 	.long (kvm_emulate_mtsrin_end - kvm_emulate_mtsrin) / 4
+
+.global kvm_template_end
+kvm_template_end:
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index 578f35f..f5725bc 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -26,12 +26,10 @@
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <asm/uaccess.h>
-#include <asm/iseries/hv_lp_config.h>
 #include <asm/lppaca.h>
 #include <asm/hvcall.h>
 #include <asm/firmware.h>
 #include <asm/rtas.h>
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/prom.h>
 #include <asm/vdso_datapage.h>
@@ -55,80 +53,14 @@
 	int cpu;
 
 	for_each_possible_cpu(cpu) {
-		if (firmware_has_feature(FW_FEATURE_ISERIES))
-			sum_purr += lppaca_of(cpu).emulated_time_base;
-		else {
-			struct cpu_usage *cu;
+		struct cpu_usage *cu;
 
-			cu = &per_cpu(cpu_usage_array, cpu);
-			sum_purr += cu->current_tb;
-		}
+		cu = &per_cpu(cpu_usage_array, cpu);
+		sum_purr += cu->current_tb;
 	}
 	return sum_purr;
 }
 
-#ifdef CONFIG_PPC_ISERIES
-
-/*
- * Methods used to fetch LPAR data when running on an iSeries platform.
- */
-static int iseries_lparcfg_data(struct seq_file *m, void *v)
-{
-	unsigned long pool_id;
-	int shared, entitled_capacity, max_entitled_capacity;
-	int processors, max_processors;
-	unsigned long purr = get_purr();
-
-	shared = (int)(local_paca->lppaca_ptr->shared_proc);
-
-	seq_printf(m, "system_active_processors=%d\n",
-		   (int)HvLpConfig_getSystemPhysicalProcessors());
-
-	seq_printf(m, "system_potential_processors=%d\n",
-		   (int)HvLpConfig_getSystemPhysicalProcessors());
-
-	processors = (int)HvLpConfig_getPhysicalProcessors();
-	seq_printf(m, "partition_active_processors=%d\n", processors);
-
-	max_processors = (int)HvLpConfig_getMaxPhysicalProcessors();
-	seq_printf(m, "partition_potential_processors=%d\n", max_processors);
-
-	if (shared) {
-		entitled_capacity = HvLpConfig_getSharedProcUnits();
-		max_entitled_capacity = HvLpConfig_getMaxSharedProcUnits();
-	} else {
-		entitled_capacity = processors * 100;
-		max_entitled_capacity = max_processors * 100;
-	}
-	seq_printf(m, "partition_entitled_capacity=%d\n", entitled_capacity);
-
-	seq_printf(m, "partition_max_entitled_capacity=%d\n",
-		   max_entitled_capacity);
-
-	if (shared) {
-		pool_id = HvLpConfig_getSharedPoolIndex();
-		seq_printf(m, "pool=%d\n", (int)pool_id);
-		seq_printf(m, "pool_capacity=%d\n",
-			   (int)(HvLpConfig_getNumProcsInSharedPool(pool_id) *
-				 100));
-		seq_printf(m, "purr=%ld\n", purr);
-	}
-
-	seq_printf(m, "shared_processor_mode=%d\n", shared);
-
-	return 0;
-}
-
-#else				/* CONFIG_PPC_ISERIES */
-
-static int iseries_lparcfg_data(struct seq_file *m, void *v)
-{
-	return 0;
-}
-
-#endif				/* CONFIG_PPC_ISERIES */
-
-#ifdef CONFIG_PPC_PSERIES
 /*
  * Methods used to fetch LPAR data when running on a pSeries platform.
  */
@@ -648,8 +580,7 @@
 	u8 new_weight, *new_weight_ptr = &new_weight;
 	ssize_t retval;
 
-	if (!firmware_has_feature(FW_FEATURE_SPLPAR) ||
-			firmware_has_feature(FW_FEATURE_ISERIES))
+	if (!firmware_has_feature(FW_FEATURE_SPLPAR))
 		return -EINVAL;
 
 	if (count > kbuf_sz)
@@ -709,21 +640,6 @@
 	return retval;
 }
 
-#else				/* CONFIG_PPC_PSERIES */
-
-static int pseries_lparcfg_data(struct seq_file *m, void *v)
-{
-	return 0;
-}
-
-static ssize_t lparcfg_write(struct file *file, const char __user * buf,
-			     size_t count, loff_t * off)
-{
-	return -EINVAL;
-}
-
-#endif				/* CONFIG_PPC_PSERIES */
-
 static int lparcfg_data(struct seq_file *m, void *v)
 {
 	struct device_node *rootdn;
@@ -738,19 +654,11 @@
 	rootdn = of_find_node_by_path("/");
 	if (rootdn) {
 		tmp = of_get_property(rootdn, "model", NULL);
-		if (tmp) {
+		if (tmp)
 			model = tmp;
-			/* Skip "IBM," - see platforms/iseries/dt.c */
-			if (firmware_has_feature(FW_FEATURE_ISERIES))
-				model += 4;
-		}
 		tmp = of_get_property(rootdn, "system-id", NULL);
-		if (tmp) {
+		if (tmp)
 			system_id = tmp;
-			/* Skip "IBM," - see platforms/iseries/dt.c */
-			if (firmware_has_feature(FW_FEATURE_ISERIES))
-				system_id += 4;
-		}
 		lp_index_ptr = of_get_property(rootdn, "ibm,partition-no",
 					NULL);
 		if (lp_index_ptr)
@@ -761,8 +669,6 @@
 	seq_printf(m, "system_type=%s\n", model);
 	seq_printf(m, "partition_id=%d\n", (int)lp_index);
 
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		return iseries_lparcfg_data(m, v);
 	return pseries_lparcfg_data(m, v);
 }
 
@@ -786,8 +692,7 @@
 	umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
 
 	/* Allow writing if we have FW_FEATURE_SPLPAR */
-	if (firmware_has_feature(FW_FEATURE_SPLPAR) &&
-			!firmware_has_feature(FW_FEATURE_ISERIES))
+	if (firmware_has_feature(FW_FEATURE_SPLPAR))
 		mode |= S_IWUSR;
 
 	ent = proc_create("powerpc/lparcfg", mode, NULL, &lparcfg_fops);
diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S
index b69463e..ba16874 100644
--- a/arch/powerpc/kernel/misc.S
+++ b/arch/powerpc/kernel/misc.S
@@ -5,7 +5,6 @@
  * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
  * and Paul Mackerras.
  *
- * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
  * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com)
  *
  * setjmp/longjmp code by Paul Mackerras.
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
index e1612df..2049f2d0 100644
--- a/arch/powerpc/kernel/of_platform.c
+++ b/arch/powerpc/kernel/of_platform.c
@@ -21,12 +21,13 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
+#include <linux/atomic.h>
 
 #include <asm/errno.h>
 #include <asm/topology.h>
 #include <asm/pci-bridge.h>
 #include <asm/ppc-pci.h>
-#include <linux/atomic.h>
+#include <asm/eeh.h>
 
 #ifdef CONFIG_PPC_OF_PLATFORM_PCI
 
@@ -66,6 +67,9 @@
 	/* Init pci_dn data structures */
 	pci_devs_phb_init_dynamic(phb);
 
+	/* Create EEH devices for the PHB */
+	eeh_dev_phb_init_dynamic(phb);
+
 	/* Register devices with EEH */
 #ifdef CONFIG_EEH
 	if (dev->dev.of_node->child)
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index 41456ff..0bb1f98 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -11,13 +11,10 @@
 #include <linux/export.h>
 #include <linux/memblock.h>
 
-#include <asm/firmware.h>
 #include <asm/lppaca.h>
 #include <asm/paca.h>
 #include <asm/sections.h>
 #include <asm/pgtable.h>
-#include <asm/iseries/lpar_map.h>
-#include <asm/iseries/hv_types.h>
 #include <asm/kexec.h>
 
 /* This symbol is provided by the linker - let it fill in the paca
@@ -30,8 +27,8 @@
  * The structure which the hypervisor knows about - this structure
  * should not cross a page boundary.  The vpa_init/register_vpa call
  * is now known to fail if the lppaca structure crosses a page
- * boundary.  The lppaca is also used on legacy iSeries and POWER5
- * pSeries boxes.  The lppaca is 640 bytes long, and cannot readily
+ * boundary.  The lppaca is also used on POWER5 pSeries boxes.
+ * The lppaca is 640 bytes long, and cannot readily
  * change since the hypervisor knows its layout, so a 1kB alignment
  * will suffice to ensure that it doesn't cross a page boundary.
  */
@@ -183,12 +180,9 @@
 	/*
 	 * We can't take SLB misses on the paca, and we want to access them
 	 * in real mode, so allocate them within the RMA and also within
-	 * the first segment. On iSeries they must be within the area mapped
-	 * by the HV, which is HvPagesToMap * HVPAGESIZE bytes.
+	 * the first segment.
 	 */
 	limit = min(0x10000000ULL, ppc64_rma_size);
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		limit = min(limit, HvPagesToMap * HVPAGESIZE);
 
 	paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpu_ids);
 
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index cce98d7..8e78e93 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -38,7 +38,6 @@
 #include <asm/byteorder.h>
 #include <asm/machdep.h>
 #include <asm/ppc-pci.h>
-#include <asm/firmware.h>
 #include <asm/eeh.h>
 
 static DEFINE_SPINLOCK(hose_spinlock);
@@ -50,9 +49,6 @@
 /* ISA Memory physical address */
 resource_size_t isa_mem_base;
 
-/* Default PCI flags is 0 on ppc32, modified at boot on ppc64 */
-unsigned int pci_flags = 0;
-
 
 static struct dma_map_ops *pci_dma_ops = &dma_direct_ops;
 
@@ -219,20 +215,6 @@
 	struct of_irq oirq;
 	unsigned int virq;
 
-	/* The current device-tree that iSeries generates from the HV
-	 * PCI informations doesn't contain proper interrupt routing,
-	 * and all the fallback would do is print out crap, so we
-	 * don't attempt to resolve the interrupts here at all, some
-	 * iSeries specific fixup does it.
-	 *
-	 * In the long run, we will hopefully fix the generated device-tree
-	 * instead.
-	 */
-#ifdef CONFIG_PPC_ISERIES
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		return -1;
-#endif
-
 	pr_debug("PCI: Try to map irq for %s...\n", pci_name(pci_dev));
 
 #ifdef DEBUG
@@ -849,60 +831,6 @@
 	return 1;
 }
 
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-			     struct resource *res)
-{
-	resource_size_t offset = 0, mask = (resource_size_t)-1;
-	struct pci_controller *hose = pci_bus_to_host(dev->bus);
-
-	if (!hose)
-		return;
-	if (res->flags & IORESOURCE_IO) {
-		offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-		mask = 0xffffffffu;
-	} else if (res->flags & IORESOURCE_MEM)
-		offset = hose->pci_mem_offset;
-
-	region->start = (res->start - offset) & mask;
-	region->end = (res->end - offset) & mask;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-			     struct pci_bus_region *region)
-{
-	resource_size_t offset = 0, mask = (resource_size_t)-1;
-	struct pci_controller *hose = pci_bus_to_host(dev->bus);
-
-	if (!hose)
-		return;
-	if (res->flags & IORESOURCE_IO) {
-		offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-		mask = 0xffffffffu;
-	} else if (res->flags & IORESOURCE_MEM)
-		offset = hose->pci_mem_offset;
-	res->start = (region->start + offset) & mask;
-	res->end = (region->end + offset) & mask;
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
-/* Fixup a bus resource into a linux resource */
-static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
-{
-	struct pci_controller *hose = pci_bus_to_host(dev->bus);
-	resource_size_t offset = 0, mask = (resource_size_t)-1;
-
-	if (res->flags & IORESOURCE_IO) {
-		offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-		mask = 0xffffffffu;
-	} else if (res->flags & IORESOURCE_MEM)
-		offset = hose->pci_mem_offset;
-
-	res->start = (res->start + offset) & mask;
-	res->end = (res->end + offset) & mask;
-}
-
-
 /* This header fixup will do the resource fixup for all devices as they are
  * probed, but not for bridge ranges
  */
@@ -942,18 +870,11 @@
 			continue;
 		}
 
-		pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] fixup...\n",
+		pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]\n",
 			 pci_name(dev), i,
 			 (unsigned long long)res->start,\
 			 (unsigned long long)res->end,
 			 (unsigned int)res->flags);
-
-		fixup_resource(res, dev);
-
-		pr_debug("PCI:%s            %016llx-%016llx\n",
-			 pci_name(dev),
-			 (unsigned long long)res->start,
-			 (unsigned long long)res->end);
 	}
 
 	/* Call machine specific resource fixup */
@@ -1055,27 +976,18 @@
 			continue;
 		}
 
-		pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
+		pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x]\n",
 			 pci_name(dev), i,
 			 (unsigned long long)res->start,\
 			 (unsigned long long)res->end,
 			 (unsigned int)res->flags);
 
-		/* Perform fixup */
-		fixup_resource(res, dev);
-
 		/* Try to detect uninitialized P2P bridge resources,
 		 * and clear them out so they get re-assigned later
 		 */
 		if (pcibios_uninitialized_bridge_resource(bus, res)) {
 			res->flags = 0;
 			pr_debug("PCI:%s            (unassigned)\n", pci_name(dev));
-		} else {
-
-			pr_debug("PCI:%s            %016llx-%016llx\n",
-				 pci_name(dev),
-				 (unsigned long long)res->start,
-				 (unsigned long long)res->end);
 		}
 	}
 }
@@ -1565,6 +1477,11 @@
 	return pci_enable_resources(dev, mask);
 }
 
+resource_size_t pcibios_io_space_offset(struct pci_controller *hose)
+{
+	return (unsigned long) hose->io_base_virt - _IO_BASE;
+}
+
 static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, struct list_head *resources)
 {
 	struct resource *res;
@@ -1589,7 +1506,7 @@
 		 (unsigned long long)res->start,
 		 (unsigned long long)res->end,
 		 (unsigned long)res->flags);
-	pci_add_resource(resources, res);
+	pci_add_resource_offset(resources, res, pcibios_io_space_offset(hose));
 
 	/* Hookup PHB Memory resources */
 	for (i = 0; i < 3; ++i) {
@@ -1612,7 +1529,7 @@
 			 (unsigned long long)res->start,
 			 (unsigned long long)res->end,
 			 (unsigned long)res->flags);
-		pci_add_resource(resources, res);
+		pci_add_resource_offset(resources, res, hose->pci_mem_offset);
 	}
 
 	pr_debug("PCI: PHB MEM offset     = %016llx\n",
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index fdd1a3d..4b06ec5 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -219,9 +219,9 @@
 	struct resource *res = &hose->io_resource;
 
 	/* Fixup IO space offset */
-	io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
-	res->start = (res->start + io_offset) & 0xffffffffu;
-	res->end = (res->end + io_offset) & 0xffffffffu;
+	io_offset = pcibios_io_space_offset(hose);
+	res->start += io_offset;
+	res->end += io_offset;
 }
 
 static int __init pcibios_init(void)
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 3318d39..94a54f6 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -33,8 +33,6 @@
 #include <asm/machdep.h>
 #include <asm/ppc-pci.h>
 
-unsigned long pci_probe_only = 1;
-
 /* pci_io_base -- the base address from which io bars are offsets.
  * This is the lowest I/O base address (so bar values are always positive),
  * and it *must* be the start of ISA space if an ISA bus exists because
@@ -55,9 +53,6 @@
 	 */
 	ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
 
-	if (pci_probe_only)
-		pci_add_flags(PCI_PROBE_ONLY);
-
 	/* On ppc64, we always enable PCI domains and we keep domain 0
 	 * backward compatible in /proc for video cards
 	 */
@@ -173,7 +168,7 @@
 		return -ENOMEM;
 
 	/* Fixup hose IO resource */
-	io_virt_offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+	io_virt_offset = pcibios_io_space_offset(hose);
 	hose->io_resource.start += io_virt_offset;
 	hose->io_resource.end += io_virt_offset;
 
diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c
index b37d0b5..89dde17 100644
--- a/arch/powerpc/kernel/pci_of_scan.c
+++ b/arch/powerpc/kernel/pci_of_scan.c
@@ -75,6 +75,7 @@
 {
 	u64 base, size;
 	unsigned int flags;
+	struct pci_bus_region region;
 	struct resource *res;
 	const u32 *addrs;
 	u32 i;
@@ -106,10 +107,11 @@
 			printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i);
 			continue;
 		}
-		res->start = base;
-		res->end = base + size - 1;
 		res->flags = flags;
 		res->name = pci_name(dev);
+		region.start = base;
+		region.end = base + size - 1;
+		pcibios_bus_to_resource(dev, res, &region);
 	}
 }
 
@@ -209,6 +211,7 @@
 	struct pci_bus *bus;
 	const u32 *busrange, *ranges;
 	int len, i, mode;
+	struct pci_bus_region region;
 	struct resource *res;
 	unsigned int flags;
 	u64 size;
@@ -270,9 +273,10 @@
 			res = bus->resource[i];
 			++i;
 		}
-		res->start = of_read_number(&ranges[1], 2);
-		res->end = res->start + size - 1;
 		res->flags = flags;
+		region.start = of_read_number(&ranges[1], 2);
+		region.end = region.start + size - 1;
+		pcibios_bus_to_resource(dev, res, &region);
 	}
 	sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
 		bus->number);
diff --git a/arch/powerpc/kernel/perf_callchain.c b/arch/powerpc/kernel/perf_callchain.c
deleted file mode 100644
index 564c1d8..0000000
--- a/arch/powerpc/kernel/perf_callchain.c
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * Performance counter callchain support - powerpc architecture code
- *
- * Copyright © 2009 Paul Mackerras, 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.
- */
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/perf_event.h>
-#include <linux/percpu.h>
-#include <linux/uaccess.h>
-#include <linux/mm.h>
-#include <asm/ptrace.h>
-#include <asm/pgtable.h>
-#include <asm/sigcontext.h>
-#include <asm/ucontext.h>
-#include <asm/vdso.h>
-#ifdef CONFIG_PPC64
-#include "ppc32.h"
-#endif
-
-
-/*
- * Is sp valid as the address of the next kernel stack frame after prev_sp?
- * The next frame may be in a different stack area but should not go
- * back down in the same stack area.
- */
-static int valid_next_sp(unsigned long sp, unsigned long prev_sp)
-{
-	if (sp & 0xf)
-		return 0;		/* must be 16-byte aligned */
-	if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
-		return 0;
-	if (sp >= prev_sp + STACK_FRAME_OVERHEAD)
-		return 1;
-	/*
-	 * sp could decrease when we jump off an interrupt stack
-	 * back to the regular process stack.
-	 */
-	if ((sp & ~(THREAD_SIZE - 1)) != (prev_sp & ~(THREAD_SIZE - 1)))
-		return 1;
-	return 0;
-}
-
-void
-perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
-{
-	unsigned long sp, next_sp;
-	unsigned long next_ip;
-	unsigned long lr;
-	long level = 0;
-	unsigned long *fp;
-
-	lr = regs->link;
-	sp = regs->gpr[1];
-	perf_callchain_store(entry, regs->nip);
-
-	if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
-		return;
-
-	for (;;) {
-		fp = (unsigned long *) sp;
-		next_sp = fp[0];
-
-		if (next_sp == sp + STACK_INT_FRAME_SIZE &&
-		    fp[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) {
-			/*
-			 * This looks like an interrupt frame for an
-			 * interrupt that occurred in the kernel
-			 */
-			regs = (struct pt_regs *)(sp + STACK_FRAME_OVERHEAD);
-			next_ip = regs->nip;
-			lr = regs->link;
-			level = 0;
-			perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
-
-		} else {
-			if (level == 0)
-				next_ip = lr;
-			else
-				next_ip = fp[STACK_FRAME_LR_SAVE];
-
-			/*
-			 * We can't tell which of the first two addresses
-			 * we get are valid, but we can filter out the
-			 * obviously bogus ones here.  We replace them
-			 * with 0 rather than removing them entirely so
-			 * that userspace can tell which is which.
-			 */
-			if ((level == 1 && next_ip == lr) ||
-			    (level <= 1 && !kernel_text_address(next_ip)))
-				next_ip = 0;
-
-			++level;
-		}
-
-		perf_callchain_store(entry, next_ip);
-		if (!valid_next_sp(next_sp, sp))
-			return;
-		sp = next_sp;
-	}
-}
-
-#ifdef CONFIG_PPC64
-/*
- * On 64-bit we don't want to invoke hash_page on user addresses from
- * interrupt context, so if the access faults, we read the page tables
- * to find which page (if any) is mapped and access it directly.
- */
-static int read_user_stack_slow(void __user *ptr, void *ret, int nb)
-{
-	pgd_t *pgdir;
-	pte_t *ptep, pte;
-	unsigned shift;
-	unsigned long addr = (unsigned long) ptr;
-	unsigned long offset;
-	unsigned long pfn;
-	void *kaddr;
-
-	pgdir = current->mm->pgd;
-	if (!pgdir)
-		return -EFAULT;
-
-	ptep = find_linux_pte_or_hugepte(pgdir, addr, &shift);
-	if (!shift)
-		shift = PAGE_SHIFT;
-
-	/* align address to page boundary */
-	offset = addr & ((1UL << shift) - 1);
-	addr -= offset;
-
-	if (ptep == NULL)
-		return -EFAULT;
-	pte = *ptep;
-	if (!pte_present(pte) || !(pte_val(pte) & _PAGE_USER))
-		return -EFAULT;
-	pfn = pte_pfn(pte);
-	if (!page_is_ram(pfn))
-		return -EFAULT;
-
-	/* no highmem to worry about here */
-	kaddr = pfn_to_kaddr(pfn);
-	memcpy(ret, kaddr + offset, nb);
-	return 0;
-}
-
-static int read_user_stack_64(unsigned long __user *ptr, unsigned long *ret)
-{
-	if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned long) ||
-	    ((unsigned long)ptr & 7))
-		return -EFAULT;
-
-	pagefault_disable();
-	if (!__get_user_inatomic(*ret, ptr)) {
-		pagefault_enable();
-		return 0;
-	}
-	pagefault_enable();
-
-	return read_user_stack_slow(ptr, ret, 8);
-}
-
-static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
-{
-	if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
-	    ((unsigned long)ptr & 3))
-		return -EFAULT;
-
-	pagefault_disable();
-	if (!__get_user_inatomic(*ret, ptr)) {
-		pagefault_enable();
-		return 0;
-	}
-	pagefault_enable();
-
-	return read_user_stack_slow(ptr, ret, 4);
-}
-
-static inline int valid_user_sp(unsigned long sp, int is_64)
-{
-	if (!sp || (sp & 7) || sp > (is_64 ? TASK_SIZE : 0x100000000UL) - 32)
-		return 0;
-	return 1;
-}
-
-/*
- * 64-bit user processes use the same stack frame for RT and non-RT signals.
- */
-struct signal_frame_64 {
-	char		dummy[__SIGNAL_FRAMESIZE];
-	struct ucontext	uc;
-	unsigned long	unused[2];
-	unsigned int	tramp[6];
-	struct siginfo	*pinfo;
-	void		*puc;
-	struct siginfo	info;
-	char		abigap[288];
-};
-
-static int is_sigreturn_64_address(unsigned long nip, unsigned long fp)
-{
-	if (nip == fp + offsetof(struct signal_frame_64, tramp))
-		return 1;
-	if (vdso64_rt_sigtramp && current->mm->context.vdso_base &&
-	    nip == current->mm->context.vdso_base + vdso64_rt_sigtramp)
-		return 1;
-	return 0;
-}
-
-/*
- * Do some sanity checking on the signal frame pointed to by sp.
- * We check the pinfo and puc pointers in the frame.
- */
-static int sane_signal_64_frame(unsigned long sp)
-{
-	struct signal_frame_64 __user *sf;
-	unsigned long pinfo, puc;
-
-	sf = (struct signal_frame_64 __user *) sp;
-	if (read_user_stack_64((unsigned long __user *) &sf->pinfo, &pinfo) ||
-	    read_user_stack_64((unsigned long __user *) &sf->puc, &puc))
-		return 0;
-	return pinfo == (unsigned long) &sf->info &&
-		puc == (unsigned long) &sf->uc;
-}
-
-static void perf_callchain_user_64(struct perf_callchain_entry *entry,
-				   struct pt_regs *regs)
-{
-	unsigned long sp, next_sp;
-	unsigned long next_ip;
-	unsigned long lr;
-	long level = 0;
-	struct signal_frame_64 __user *sigframe;
-	unsigned long __user *fp, *uregs;
-
-	next_ip = regs->nip;
-	lr = regs->link;
-	sp = regs->gpr[1];
-	perf_callchain_store(entry, next_ip);
-
-	for (;;) {
-		fp = (unsigned long __user *) sp;
-		if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp))
-			return;
-		if (level > 0 && read_user_stack_64(&fp[2], &next_ip))
-			return;
-
-		/*
-		 * Note: the next_sp - sp >= signal frame size check
-		 * is true when next_sp < sp, which can happen when
-		 * transitioning from an alternate signal stack to the
-		 * normal stack.
-		 */
-		if (next_sp - sp >= sizeof(struct signal_frame_64) &&
-		    (is_sigreturn_64_address(next_ip, sp) ||
-		     (level <= 1 && is_sigreturn_64_address(lr, sp))) &&
-		    sane_signal_64_frame(sp)) {
-			/*
-			 * This looks like an signal frame
-			 */
-			sigframe = (struct signal_frame_64 __user *) sp;
-			uregs = sigframe->uc.uc_mcontext.gp_regs;
-			if (read_user_stack_64(&uregs[PT_NIP], &next_ip) ||
-			    read_user_stack_64(&uregs[PT_LNK], &lr) ||
-			    read_user_stack_64(&uregs[PT_R1], &sp))
-				return;
-			level = 0;
-			perf_callchain_store(entry, PERF_CONTEXT_USER);
-			perf_callchain_store(entry, next_ip);
-			continue;
-		}
-
-		if (level == 0)
-			next_ip = lr;
-		perf_callchain_store(entry, next_ip);
-		++level;
-		sp = next_sp;
-	}
-}
-
-static inline int current_is_64bit(void)
-{
-	/*
-	 * We can't use test_thread_flag() here because we may be on an
-	 * interrupt stack, and the thread flags don't get copied over
-	 * from the thread_info on the main stack to the interrupt stack.
-	 */
-	return !test_ti_thread_flag(task_thread_info(current), TIF_32BIT);
-}
-
-#else  /* CONFIG_PPC64 */
-/*
- * On 32-bit we just access the address and let hash_page create a
- * HPTE if necessary, so there is no need to fall back to reading
- * the page tables.  Since this is called at interrupt level,
- * do_page_fault() won't treat a DSI as a page fault.
- */
-static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
-{
-	int rc;
-
-	if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
-	    ((unsigned long)ptr & 3))
-		return -EFAULT;
-
-	pagefault_disable();
-	rc = __get_user_inatomic(*ret, ptr);
-	pagefault_enable();
-
-	return rc;
-}
-
-static inline void perf_callchain_user_64(struct perf_callchain_entry *entry,
-					  struct pt_regs *regs)
-{
-}
-
-static inline int current_is_64bit(void)
-{
-	return 0;
-}
-
-static inline int valid_user_sp(unsigned long sp, int is_64)
-{
-	if (!sp || (sp & 7) || sp > TASK_SIZE - 32)
-		return 0;
-	return 1;
-}
-
-#define __SIGNAL_FRAMESIZE32	__SIGNAL_FRAMESIZE
-#define sigcontext32		sigcontext
-#define mcontext32		mcontext
-#define ucontext32		ucontext
-#define compat_siginfo_t	struct siginfo
-
-#endif /* CONFIG_PPC64 */
-
-/*
- * Layout for non-RT signal frames
- */
-struct signal_frame_32 {
-	char			dummy[__SIGNAL_FRAMESIZE32];
-	struct sigcontext32	sctx;
-	struct mcontext32	mctx;
-	int			abigap[56];
-};
-
-/*
- * Layout for RT signal frames
- */
-struct rt_signal_frame_32 {
-	char			dummy[__SIGNAL_FRAMESIZE32 + 16];
-	compat_siginfo_t	info;
-	struct ucontext32	uc;
-	int			abigap[56];
-};
-
-static int is_sigreturn_32_address(unsigned int nip, unsigned int fp)
-{
-	if (nip == fp + offsetof(struct signal_frame_32, mctx.mc_pad))
-		return 1;
-	if (vdso32_sigtramp && current->mm->context.vdso_base &&
-	    nip == current->mm->context.vdso_base + vdso32_sigtramp)
-		return 1;
-	return 0;
-}
-
-static int is_rt_sigreturn_32_address(unsigned int nip, unsigned int fp)
-{
-	if (nip == fp + offsetof(struct rt_signal_frame_32,
-				 uc.uc_mcontext.mc_pad))
-		return 1;
-	if (vdso32_rt_sigtramp && current->mm->context.vdso_base &&
-	    nip == current->mm->context.vdso_base + vdso32_rt_sigtramp)
-		return 1;
-	return 0;
-}
-
-static int sane_signal_32_frame(unsigned int sp)
-{
-	struct signal_frame_32 __user *sf;
-	unsigned int regs;
-
-	sf = (struct signal_frame_32 __user *) (unsigned long) sp;
-	if (read_user_stack_32((unsigned int __user *) &sf->sctx.regs, &regs))
-		return 0;
-	return regs == (unsigned long) &sf->mctx;
-}
-
-static int sane_rt_signal_32_frame(unsigned int sp)
-{
-	struct rt_signal_frame_32 __user *sf;
-	unsigned int regs;
-
-	sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
-	if (read_user_stack_32((unsigned int __user *) &sf->uc.uc_regs, &regs))
-		return 0;
-	return regs == (unsigned long) &sf->uc.uc_mcontext;
-}
-
-static unsigned int __user *signal_frame_32_regs(unsigned int sp,
-				unsigned int next_sp, unsigned int next_ip)
-{
-	struct mcontext32 __user *mctx = NULL;
-	struct signal_frame_32 __user *sf;
-	struct rt_signal_frame_32 __user *rt_sf;
-
-	/*
-	 * Note: the next_sp - sp >= signal frame size check
-	 * is true when next_sp < sp, for example, when
-	 * transitioning from an alternate signal stack to the
-	 * normal stack.
-	 */
-	if (next_sp - sp >= sizeof(struct signal_frame_32) &&
-	    is_sigreturn_32_address(next_ip, sp) &&
-	    sane_signal_32_frame(sp)) {
-		sf = (struct signal_frame_32 __user *) (unsigned long) sp;
-		mctx = &sf->mctx;
-	}
-
-	if (!mctx && next_sp - sp >= sizeof(struct rt_signal_frame_32) &&
-	    is_rt_sigreturn_32_address(next_ip, sp) &&
-	    sane_rt_signal_32_frame(sp)) {
-		rt_sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
-		mctx = &rt_sf->uc.uc_mcontext;
-	}
-
-	if (!mctx)
-		return NULL;
-	return mctx->mc_gregs;
-}
-
-static void perf_callchain_user_32(struct perf_callchain_entry *entry,
-				   struct pt_regs *regs)
-{
-	unsigned int sp, next_sp;
-	unsigned int next_ip;
-	unsigned int lr;
-	long level = 0;
-	unsigned int __user *fp, *uregs;
-
-	next_ip = regs->nip;
-	lr = regs->link;
-	sp = regs->gpr[1];
-	perf_callchain_store(entry, next_ip);
-
-	while (entry->nr < PERF_MAX_STACK_DEPTH) {
-		fp = (unsigned int __user *) (unsigned long) sp;
-		if (!valid_user_sp(sp, 0) || read_user_stack_32(fp, &next_sp))
-			return;
-		if (level > 0 && read_user_stack_32(&fp[1], &next_ip))
-			return;
-
-		uregs = signal_frame_32_regs(sp, next_sp, next_ip);
-		if (!uregs && level <= 1)
-			uregs = signal_frame_32_regs(sp, next_sp, lr);
-		if (uregs) {
-			/*
-			 * This looks like an signal frame, so restart
-			 * the stack trace with the values in it.
-			 */
-			if (read_user_stack_32(&uregs[PT_NIP], &next_ip) ||
-			    read_user_stack_32(&uregs[PT_LNK], &lr) ||
-			    read_user_stack_32(&uregs[PT_R1], &sp))
-				return;
-			level = 0;
-			perf_callchain_store(entry, PERF_CONTEXT_USER);
-			perf_callchain_store(entry, next_ip);
-			continue;
-		}
-
-		if (level == 0)
-			next_ip = lr;
-		perf_callchain_store(entry, next_ip);
-		++level;
-		sp = next_sp;
-	}
-}
-
-void
-perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
-{
-	if (current_is_64bit())
-		perf_callchain_user_64(entry, regs);
-	else
-		perf_callchain_user_32(entry, regs);
-}
diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c
deleted file mode 100644
index c2e27ed..0000000
--- a/arch/powerpc/kernel/perf_event.c
+++ /dev/null
@@ -1,1448 +0,0 @@
-/*
- * Performance event support - powerpc architecture code
- *
- * Copyright 2008-2009 Paul Mackerras, 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.
- */
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/perf_event.h>
-#include <linux/percpu.h>
-#include <linux/hardirq.h>
-#include <asm/reg.h>
-#include <asm/pmc.h>
-#include <asm/machdep.h>
-#include <asm/firmware.h>
-#include <asm/ptrace.h>
-
-struct cpu_hw_events {
-	int n_events;
-	int n_percpu;
-	int disabled;
-	int n_added;
-	int n_limited;
-	u8  pmcs_enabled;
-	struct perf_event *event[MAX_HWEVENTS];
-	u64 events[MAX_HWEVENTS];
-	unsigned int flags[MAX_HWEVENTS];
-	unsigned long mmcr[3];
-	struct perf_event *limited_counter[MAX_LIMITED_HWCOUNTERS];
-	u8  limited_hwidx[MAX_LIMITED_HWCOUNTERS];
-	u64 alternatives[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
-	unsigned long amasks[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
-	unsigned long avalues[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
-
-	unsigned int group_flag;
-	int n_txn_start;
-};
-DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
-
-struct power_pmu *ppmu;
-
-/*
- * Normally, to ignore kernel events we set the FCS (freeze counters
- * in supervisor mode) bit in MMCR0, but if the kernel runs with the
- * hypervisor bit set in the MSR, or if we are running on a processor
- * where the hypervisor bit is forced to 1 (as on Apple G5 processors),
- * then we need to use the FCHV bit to ignore kernel events.
- */
-static unsigned int freeze_events_kernel = MMCR0_FCS;
-
-/*
- * 32-bit doesn't have MMCRA but does have an MMCR2,
- * and a few other names are different.
- */
-#ifdef CONFIG_PPC32
-
-#define MMCR0_FCHV		0
-#define MMCR0_PMCjCE		MMCR0_PMCnCE
-
-#define SPRN_MMCRA		SPRN_MMCR2
-#define MMCRA_SAMPLE_ENABLE	0
-
-static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
-{
-	return 0;
-}
-static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) { }
-static inline u32 perf_get_misc_flags(struct pt_regs *regs)
-{
-	return 0;
-}
-static inline void perf_read_regs(struct pt_regs *regs) { }
-static inline int perf_intr_is_nmi(struct pt_regs *regs)
-{
-	return 0;
-}
-
-#endif /* CONFIG_PPC32 */
-
-/*
- * Things that are specific to 64-bit implementations.
- */
-#ifdef CONFIG_PPC64
-
-static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
-{
-	unsigned long mmcra = regs->dsisr;
-
-	if ((mmcra & MMCRA_SAMPLE_ENABLE) && !(ppmu->flags & PPMU_ALT_SIPR)) {
-		unsigned long slot = (mmcra & MMCRA_SLOT) >> MMCRA_SLOT_SHIFT;
-		if (slot > 1)
-			return 4 * (slot - 1);
-	}
-	return 0;
-}
-
-/*
- * The user wants a data address recorded.
- * If we're not doing instruction sampling, give them the SDAR
- * (sampled data address).  If we are doing instruction sampling, then
- * only give them the SDAR if it corresponds to the instruction
- * pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC
- * bit in MMCRA.
- */
-static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
-{
-	unsigned long mmcra = regs->dsisr;
-	unsigned long sdsync = (ppmu->flags & PPMU_ALT_SIPR) ?
-		POWER6_MMCRA_SDSYNC : MMCRA_SDSYNC;
-
-	if (!(mmcra & MMCRA_SAMPLE_ENABLE) || (mmcra & sdsync))
-		*addrp = mfspr(SPRN_SDAR);
-}
-
-static inline u32 perf_get_misc_flags(struct pt_regs *regs)
-{
-	unsigned long mmcra = regs->dsisr;
-	unsigned long sihv = MMCRA_SIHV;
-	unsigned long sipr = MMCRA_SIPR;
-
-	if (TRAP(regs) != 0xf00)
-		return 0;	/* not a PMU interrupt */
-
-	if (ppmu->flags & PPMU_ALT_SIPR) {
-		sihv = POWER6_MMCRA_SIHV;
-		sipr = POWER6_MMCRA_SIPR;
-	}
-
-	/* PR has priority over HV, so order below is important */
-	if (mmcra & sipr)
-		return PERF_RECORD_MISC_USER;
-	if ((mmcra & sihv) && (freeze_events_kernel != MMCR0_FCHV))
-		return PERF_RECORD_MISC_HYPERVISOR;
-	return PERF_RECORD_MISC_KERNEL;
-}
-
-/*
- * Overload regs->dsisr to store MMCRA so we only need to read it once
- * on each interrupt.
- */
-static inline void perf_read_regs(struct pt_regs *regs)
-{
-	regs->dsisr = mfspr(SPRN_MMCRA);
-}
-
-/*
- * If interrupts were soft-disabled when a PMU interrupt occurs, treat
- * it as an NMI.
- */
-static inline int perf_intr_is_nmi(struct pt_regs *regs)
-{
-	return !regs->softe;
-}
-
-#endif /* CONFIG_PPC64 */
-
-static void perf_event_interrupt(struct pt_regs *regs);
-
-void perf_event_print_debug(void)
-{
-}
-
-/*
- * Read one performance monitor counter (PMC).
- */
-static unsigned long read_pmc(int idx)
-{
-	unsigned long val;
-
-	switch (idx) {
-	case 1:
-		val = mfspr(SPRN_PMC1);
-		break;
-	case 2:
-		val = mfspr(SPRN_PMC2);
-		break;
-	case 3:
-		val = mfspr(SPRN_PMC3);
-		break;
-	case 4:
-		val = mfspr(SPRN_PMC4);
-		break;
-	case 5:
-		val = mfspr(SPRN_PMC5);
-		break;
-	case 6:
-		val = mfspr(SPRN_PMC6);
-		break;
-#ifdef CONFIG_PPC64
-	case 7:
-		val = mfspr(SPRN_PMC7);
-		break;
-	case 8:
-		val = mfspr(SPRN_PMC8);
-		break;
-#endif /* CONFIG_PPC64 */
-	default:
-		printk(KERN_ERR "oops trying to read PMC%d\n", idx);
-		val = 0;
-	}
-	return val;
-}
-
-/*
- * Write one PMC.
- */
-static void write_pmc(int idx, unsigned long val)
-{
-	switch (idx) {
-	case 1:
-		mtspr(SPRN_PMC1, val);
-		break;
-	case 2:
-		mtspr(SPRN_PMC2, val);
-		break;
-	case 3:
-		mtspr(SPRN_PMC3, val);
-		break;
-	case 4:
-		mtspr(SPRN_PMC4, val);
-		break;
-	case 5:
-		mtspr(SPRN_PMC5, val);
-		break;
-	case 6:
-		mtspr(SPRN_PMC6, val);
-		break;
-#ifdef CONFIG_PPC64
-	case 7:
-		mtspr(SPRN_PMC7, val);
-		break;
-	case 8:
-		mtspr(SPRN_PMC8, val);
-		break;
-#endif /* CONFIG_PPC64 */
-	default:
-		printk(KERN_ERR "oops trying to write PMC%d\n", idx);
-	}
-}
-
-/*
- * Check if a set of events can all go on the PMU at once.
- * If they can't, this will look at alternative codes for the events
- * and see if any combination of alternative codes is feasible.
- * The feasible set is returned in event_id[].
- */
-static int power_check_constraints(struct cpu_hw_events *cpuhw,
-				   u64 event_id[], unsigned int cflags[],
-				   int n_ev)
-{
-	unsigned long mask, value, nv;
-	unsigned long smasks[MAX_HWEVENTS], svalues[MAX_HWEVENTS];
-	int n_alt[MAX_HWEVENTS], choice[MAX_HWEVENTS];
-	int i, j;
-	unsigned long addf = ppmu->add_fields;
-	unsigned long tadd = ppmu->test_adder;
-
-	if (n_ev > ppmu->n_counter)
-		return -1;
-
-	/* First see if the events will go on as-is */
-	for (i = 0; i < n_ev; ++i) {
-		if ((cflags[i] & PPMU_LIMITED_PMC_REQD)
-		    && !ppmu->limited_pmc_event(event_id[i])) {
-			ppmu->get_alternatives(event_id[i], cflags[i],
-					       cpuhw->alternatives[i]);
-			event_id[i] = cpuhw->alternatives[i][0];
-		}
-		if (ppmu->get_constraint(event_id[i], &cpuhw->amasks[i][0],
-					 &cpuhw->avalues[i][0]))
-			return -1;
-	}
-	value = mask = 0;
-	for (i = 0; i < n_ev; ++i) {
-		nv = (value | cpuhw->avalues[i][0]) +
-			(value & cpuhw->avalues[i][0] & addf);
-		if ((((nv + tadd) ^ value) & mask) != 0 ||
-		    (((nv + tadd) ^ cpuhw->avalues[i][0]) &
-		     cpuhw->amasks[i][0]) != 0)
-			break;
-		value = nv;
-		mask |= cpuhw->amasks[i][0];
-	}
-	if (i == n_ev)
-		return 0;	/* all OK */
-
-	/* doesn't work, gather alternatives... */
-	if (!ppmu->get_alternatives)
-		return -1;
-	for (i = 0; i < n_ev; ++i) {
-		choice[i] = 0;
-		n_alt[i] = ppmu->get_alternatives(event_id[i], cflags[i],
-						  cpuhw->alternatives[i]);
-		for (j = 1; j < n_alt[i]; ++j)
-			ppmu->get_constraint(cpuhw->alternatives[i][j],
-					     &cpuhw->amasks[i][j],
-					     &cpuhw->avalues[i][j]);
-	}
-
-	/* enumerate all possibilities and see if any will work */
-	i = 0;
-	j = -1;
-	value = mask = nv = 0;
-	while (i < n_ev) {
-		if (j >= 0) {
-			/* we're backtracking, restore context */
-			value = svalues[i];
-			mask = smasks[i];
-			j = choice[i];
-		}
-		/*
-		 * See if any alternative k for event_id i,
-		 * where k > j, will satisfy the constraints.
-		 */
-		while (++j < n_alt[i]) {
-			nv = (value | cpuhw->avalues[i][j]) +
-				(value & cpuhw->avalues[i][j] & addf);
-			if ((((nv + tadd) ^ value) & mask) == 0 &&
-			    (((nv + tadd) ^ cpuhw->avalues[i][j])
-			     & cpuhw->amasks[i][j]) == 0)
-				break;
-		}
-		if (j >= n_alt[i]) {
-			/*
-			 * No feasible alternative, backtrack
-			 * to event_id i-1 and continue enumerating its
-			 * alternatives from where we got up to.
-			 */
-			if (--i < 0)
-				return -1;
-		} else {
-			/*
-			 * Found a feasible alternative for event_id i,
-			 * remember where we got up to with this event_id,
-			 * go on to the next event_id, and start with
-			 * the first alternative for it.
-			 */
-			choice[i] = j;
-			svalues[i] = value;
-			smasks[i] = mask;
-			value = nv;
-			mask |= cpuhw->amasks[i][j];
-			++i;
-			j = -1;
-		}
-	}
-
-	/* OK, we have a feasible combination, tell the caller the solution */
-	for (i = 0; i < n_ev; ++i)
-		event_id[i] = cpuhw->alternatives[i][choice[i]];
-	return 0;
-}
-
-/*
- * Check if newly-added events have consistent settings for
- * exclude_{user,kernel,hv} with each other and any previously
- * added events.
- */
-static int check_excludes(struct perf_event **ctrs, unsigned int cflags[],
-			  int n_prev, int n_new)
-{
-	int eu = 0, ek = 0, eh = 0;
-	int i, n, first;
-	struct perf_event *event;
-
-	n = n_prev + n_new;
-	if (n <= 1)
-		return 0;
-
-	first = 1;
-	for (i = 0; i < n; ++i) {
-		if (cflags[i] & PPMU_LIMITED_PMC_OK) {
-			cflags[i] &= ~PPMU_LIMITED_PMC_REQD;
-			continue;
-		}
-		event = ctrs[i];
-		if (first) {
-			eu = event->attr.exclude_user;
-			ek = event->attr.exclude_kernel;
-			eh = event->attr.exclude_hv;
-			first = 0;
-		} else if (event->attr.exclude_user != eu ||
-			   event->attr.exclude_kernel != ek ||
-			   event->attr.exclude_hv != eh) {
-			return -EAGAIN;
-		}
-	}
-
-	if (eu || ek || eh)
-		for (i = 0; i < n; ++i)
-			if (cflags[i] & PPMU_LIMITED_PMC_OK)
-				cflags[i] |= PPMU_LIMITED_PMC_REQD;
-
-	return 0;
-}
-
-static u64 check_and_compute_delta(u64 prev, u64 val)
-{
-	u64 delta = (val - prev) & 0xfffffffful;
-
-	/*
-	 * POWER7 can roll back counter values, if the new value is smaller
-	 * than the previous value it will cause the delta and the counter to
-	 * have bogus values unless we rolled a counter over.  If a coutner is
-	 * rolled back, it will be smaller, but within 256, which is the maximum
-	 * number of events to rollback at once.  If we dectect a rollback
-	 * return 0.  This can lead to a small lack of precision in the
-	 * counters.
-	 */
-	if (prev > val && (prev - val) < 256)
-		delta = 0;
-
-	return delta;
-}
-
-static void power_pmu_read(struct perf_event *event)
-{
-	s64 val, delta, prev;
-
-	if (event->hw.state & PERF_HES_STOPPED)
-		return;
-
-	if (!event->hw.idx)
-		return;
-	/*
-	 * Performance monitor interrupts come even when interrupts
-	 * are soft-disabled, as long as interrupts are hard-enabled.
-	 * Therefore we treat them like NMIs.
-	 */
-	do {
-		prev = local64_read(&event->hw.prev_count);
-		barrier();
-		val = read_pmc(event->hw.idx);
-		delta = check_and_compute_delta(prev, val);
-		if (!delta)
-			return;
-	} while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
-
-	local64_add(delta, &event->count);
-	local64_sub(delta, &event->hw.period_left);
-}
-
-/*
- * On some machines, PMC5 and PMC6 can't be written, don't respect
- * the freeze conditions, and don't generate interrupts.  This tells
- * us if `event' is using such a PMC.
- */
-static int is_limited_pmc(int pmcnum)
-{
-	return (ppmu->flags & PPMU_LIMITED_PMC5_6)
-		&& (pmcnum == 5 || pmcnum == 6);
-}
-
-static void freeze_limited_counters(struct cpu_hw_events *cpuhw,
-				    unsigned long pmc5, unsigned long pmc6)
-{
-	struct perf_event *event;
-	u64 val, prev, delta;
-	int i;
-
-	for (i = 0; i < cpuhw->n_limited; ++i) {
-		event = cpuhw->limited_counter[i];
-		if (!event->hw.idx)
-			continue;
-		val = (event->hw.idx == 5) ? pmc5 : pmc6;
-		prev = local64_read(&event->hw.prev_count);
-		event->hw.idx = 0;
-		delta = check_and_compute_delta(prev, val);
-		if (delta)
-			local64_add(delta, &event->count);
-	}
-}
-
-static void thaw_limited_counters(struct cpu_hw_events *cpuhw,
-				  unsigned long pmc5, unsigned long pmc6)
-{
-	struct perf_event *event;
-	u64 val, prev;
-	int i;
-
-	for (i = 0; i < cpuhw->n_limited; ++i) {
-		event = cpuhw->limited_counter[i];
-		event->hw.idx = cpuhw->limited_hwidx[i];
-		val = (event->hw.idx == 5) ? pmc5 : pmc6;
-		prev = local64_read(&event->hw.prev_count);
-		if (check_and_compute_delta(prev, val))
-			local64_set(&event->hw.prev_count, val);
-		perf_event_update_userpage(event);
-	}
-}
-
-/*
- * Since limited events don't respect the freeze conditions, we
- * have to read them immediately after freezing or unfreezing the
- * other events.  We try to keep the values from the limited
- * events as consistent as possible by keeping the delay (in
- * cycles and instructions) between freezing/unfreezing and reading
- * the limited events as small and consistent as possible.
- * Therefore, if any limited events are in use, we read them
- * both, and always in the same order, to minimize variability,
- * and do it inside the same asm that writes MMCR0.
- */
-static void write_mmcr0(struct cpu_hw_events *cpuhw, unsigned long mmcr0)
-{
-	unsigned long pmc5, pmc6;
-
-	if (!cpuhw->n_limited) {
-		mtspr(SPRN_MMCR0, mmcr0);
-		return;
-	}
-
-	/*
-	 * Write MMCR0, then read PMC5 and PMC6 immediately.
-	 * To ensure we don't get a performance monitor interrupt
-	 * between writing MMCR0 and freezing/thawing the limited
-	 * events, we first write MMCR0 with the event overflow
-	 * interrupt enable bits turned off.
-	 */
-	asm volatile("mtspr %3,%2; mfspr %0,%4; mfspr %1,%5"
-		     : "=&r" (pmc5), "=&r" (pmc6)
-		     : "r" (mmcr0 & ~(MMCR0_PMC1CE | MMCR0_PMCjCE)),
-		       "i" (SPRN_MMCR0),
-		       "i" (SPRN_PMC5), "i" (SPRN_PMC6));
-
-	if (mmcr0 & MMCR0_FC)
-		freeze_limited_counters(cpuhw, pmc5, pmc6);
-	else
-		thaw_limited_counters(cpuhw, pmc5, pmc6);
-
-	/*
-	 * Write the full MMCR0 including the event overflow interrupt
-	 * enable bits, if necessary.
-	 */
-	if (mmcr0 & (MMCR0_PMC1CE | MMCR0_PMCjCE))
-		mtspr(SPRN_MMCR0, mmcr0);
-}
-
-/*
- * Disable all events to prevent PMU interrupts and to allow
- * events to be added or removed.
- */
-static void power_pmu_disable(struct pmu *pmu)
-{
-	struct cpu_hw_events *cpuhw;
-	unsigned long flags;
-
-	if (!ppmu)
-		return;
-	local_irq_save(flags);
-	cpuhw = &__get_cpu_var(cpu_hw_events);
-
-	if (!cpuhw->disabled) {
-		cpuhw->disabled = 1;
-		cpuhw->n_added = 0;
-
-		/*
-		 * Check if we ever enabled the PMU on this cpu.
-		 */
-		if (!cpuhw->pmcs_enabled) {
-			ppc_enable_pmcs();
-			cpuhw->pmcs_enabled = 1;
-		}
-
-		/*
-		 * Disable instruction sampling if it was enabled
-		 */
-		if (cpuhw->mmcr[2] & MMCRA_SAMPLE_ENABLE) {
-			mtspr(SPRN_MMCRA,
-			      cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
-			mb();
-		}
-
-		/*
-		 * Set the 'freeze counters' bit.
-		 * The barrier is to make sure the mtspr has been
-		 * executed and the PMU has frozen the events
-		 * before we return.
-		 */
-		write_mmcr0(cpuhw, mfspr(SPRN_MMCR0) | MMCR0_FC);
-		mb();
-	}
-	local_irq_restore(flags);
-}
-
-/*
- * Re-enable all events if disable == 0.
- * If we were previously disabled and events were added, then
- * put the new config on the PMU.
- */
-static void power_pmu_enable(struct pmu *pmu)
-{
-	struct perf_event *event;
-	struct cpu_hw_events *cpuhw;
-	unsigned long flags;
-	long i;
-	unsigned long val;
-	s64 left;
-	unsigned int hwc_index[MAX_HWEVENTS];
-	int n_lim;
-	int idx;
-
-	if (!ppmu)
-		return;
-	local_irq_save(flags);
-	cpuhw = &__get_cpu_var(cpu_hw_events);
-	if (!cpuhw->disabled) {
-		local_irq_restore(flags);
-		return;
-	}
-	cpuhw->disabled = 0;
-
-	/*
-	 * If we didn't change anything, or only removed events,
-	 * no need to recalculate MMCR* settings and reset the PMCs.
-	 * Just reenable the PMU with the current MMCR* settings
-	 * (possibly updated for removal of events).
-	 */
-	if (!cpuhw->n_added) {
-		mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
-		mtspr(SPRN_MMCR1, cpuhw->mmcr[1]);
-		if (cpuhw->n_events == 0)
-			ppc_set_pmu_inuse(0);
-		goto out_enable;
-	}
-
-	/*
-	 * Compute MMCR* values for the new set of events
-	 */
-	if (ppmu->compute_mmcr(cpuhw->events, cpuhw->n_events, hwc_index,
-			       cpuhw->mmcr)) {
-		/* shouldn't ever get here */
-		printk(KERN_ERR "oops compute_mmcr failed\n");
-		goto out;
-	}
-
-	/*
-	 * Add in MMCR0 freeze bits corresponding to the
-	 * attr.exclude_* bits for the first event.
-	 * We have already checked that all events have the
-	 * same values for these bits as the first event.
-	 */
-	event = cpuhw->event[0];
-	if (event->attr.exclude_user)
-		cpuhw->mmcr[0] |= MMCR0_FCP;
-	if (event->attr.exclude_kernel)
-		cpuhw->mmcr[0] |= freeze_events_kernel;
-	if (event->attr.exclude_hv)
-		cpuhw->mmcr[0] |= MMCR0_FCHV;
-
-	/*
-	 * Write the new configuration to MMCR* with the freeze
-	 * bit set and set the hardware events to their initial values.
-	 * Then unfreeze the events.
-	 */
-	ppc_set_pmu_inuse(1);
-	mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
-	mtspr(SPRN_MMCR1, cpuhw->mmcr[1]);
-	mtspr(SPRN_MMCR0, (cpuhw->mmcr[0] & ~(MMCR0_PMC1CE | MMCR0_PMCjCE))
-				| MMCR0_FC);
-
-	/*
-	 * Read off any pre-existing events that need to move
-	 * to another PMC.
-	 */
-	for (i = 0; i < cpuhw->n_events; ++i) {
-		event = cpuhw->event[i];
-		if (event->hw.idx && event->hw.idx != hwc_index[i] + 1) {
-			power_pmu_read(event);
-			write_pmc(event->hw.idx, 0);
-			event->hw.idx = 0;
-		}
-	}
-
-	/*
-	 * Initialize the PMCs for all the new and moved events.
-	 */
-	cpuhw->n_limited = n_lim = 0;
-	for (i = 0; i < cpuhw->n_events; ++i) {
-		event = cpuhw->event[i];
-		if (event->hw.idx)
-			continue;
-		idx = hwc_index[i] + 1;
-		if (is_limited_pmc(idx)) {
-			cpuhw->limited_counter[n_lim] = event;
-			cpuhw->limited_hwidx[n_lim] = idx;
-			++n_lim;
-			continue;
-		}
-		val = 0;
-		if (event->hw.sample_period) {
-			left = local64_read(&event->hw.period_left);
-			if (left < 0x80000000L)
-				val = 0x80000000L - left;
-		}
-		local64_set(&event->hw.prev_count, val);
-		event->hw.idx = idx;
-		if (event->hw.state & PERF_HES_STOPPED)
-			val = 0;
-		write_pmc(idx, val);
-		perf_event_update_userpage(event);
-	}
-	cpuhw->n_limited = n_lim;
-	cpuhw->mmcr[0] |= MMCR0_PMXE | MMCR0_FCECE;
-
- out_enable:
-	mb();
-	write_mmcr0(cpuhw, cpuhw->mmcr[0]);
-
-	/*
-	 * Enable instruction sampling if necessary
-	 */
-	if (cpuhw->mmcr[2] & MMCRA_SAMPLE_ENABLE) {
-		mb();
-		mtspr(SPRN_MMCRA, cpuhw->mmcr[2]);
-	}
-
- out:
-	local_irq_restore(flags);
-}
-
-static int collect_events(struct perf_event *group, int max_count,
-			  struct perf_event *ctrs[], u64 *events,
-			  unsigned int *flags)
-{
-	int n = 0;
-	struct perf_event *event;
-
-	if (!is_software_event(group)) {
-		if (n >= max_count)
-			return -1;
-		ctrs[n] = group;
-		flags[n] = group->hw.event_base;
-		events[n++] = group->hw.config;
-	}
-	list_for_each_entry(event, &group->sibling_list, group_entry) {
-		if (!is_software_event(event) &&
-		    event->state != PERF_EVENT_STATE_OFF) {
-			if (n >= max_count)
-				return -1;
-			ctrs[n] = event;
-			flags[n] = event->hw.event_base;
-			events[n++] = event->hw.config;
-		}
-	}
-	return n;
-}
-
-/*
- * Add a event to the PMU.
- * If all events are not already frozen, then we disable and
- * re-enable the PMU in order to get hw_perf_enable to do the
- * actual work of reconfiguring the PMU.
- */
-static int power_pmu_add(struct perf_event *event, int ef_flags)
-{
-	struct cpu_hw_events *cpuhw;
-	unsigned long flags;
-	int n0;
-	int ret = -EAGAIN;
-
-	local_irq_save(flags);
-	perf_pmu_disable(event->pmu);
-
-	/*
-	 * Add the event to the list (if there is room)
-	 * and check whether the total set is still feasible.
-	 */
-	cpuhw = &__get_cpu_var(cpu_hw_events);
-	n0 = cpuhw->n_events;
-	if (n0 >= ppmu->n_counter)
-		goto out;
-	cpuhw->event[n0] = event;
-	cpuhw->events[n0] = event->hw.config;
-	cpuhw->flags[n0] = event->hw.event_base;
-
-	if (!(ef_flags & PERF_EF_START))
-		event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
-
-	/*
-	 * If group events scheduling transaction was started,
-	 * skip the schedulability test here, it will be performed
-	 * at commit time(->commit_txn) as a whole
-	 */
-	if (cpuhw->group_flag & PERF_EVENT_TXN)
-		goto nocheck;
-
-	if (check_excludes(cpuhw->event, cpuhw->flags, n0, 1))
-		goto out;
-	if (power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n0 + 1))
-		goto out;
-	event->hw.config = cpuhw->events[n0];
-
-nocheck:
-	++cpuhw->n_events;
-	++cpuhw->n_added;
-
-	ret = 0;
- out:
-	perf_pmu_enable(event->pmu);
-	local_irq_restore(flags);
-	return ret;
-}
-
-/*
- * Remove a event from the PMU.
- */
-static void power_pmu_del(struct perf_event *event, int ef_flags)
-{
-	struct cpu_hw_events *cpuhw;
-	long i;
-	unsigned long flags;
-
-	local_irq_save(flags);
-	perf_pmu_disable(event->pmu);
-
-	power_pmu_read(event);
-
-	cpuhw = &__get_cpu_var(cpu_hw_events);
-	for (i = 0; i < cpuhw->n_events; ++i) {
-		if (event == cpuhw->event[i]) {
-			while (++i < cpuhw->n_events) {
-				cpuhw->event[i-1] = cpuhw->event[i];
-				cpuhw->events[i-1] = cpuhw->events[i];
-				cpuhw->flags[i-1] = cpuhw->flags[i];
-			}
-			--cpuhw->n_events;
-			ppmu->disable_pmc(event->hw.idx - 1, cpuhw->mmcr);
-			if (event->hw.idx) {
-				write_pmc(event->hw.idx, 0);
-				event->hw.idx = 0;
-			}
-			perf_event_update_userpage(event);
-			break;
-		}
-	}
-	for (i = 0; i < cpuhw->n_limited; ++i)
-		if (event == cpuhw->limited_counter[i])
-			break;
-	if (i < cpuhw->n_limited) {
-		while (++i < cpuhw->n_limited) {
-			cpuhw->limited_counter[i-1] = cpuhw->limited_counter[i];
-			cpuhw->limited_hwidx[i-1] = cpuhw->limited_hwidx[i];
-		}
-		--cpuhw->n_limited;
-	}
-	if (cpuhw->n_events == 0) {
-		/* disable exceptions if no events are running */
-		cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE);
-	}
-
-	perf_pmu_enable(event->pmu);
-	local_irq_restore(flags);
-}
-
-/*
- * POWER-PMU does not support disabling individual counters, hence
- * program their cycle counter to their max value and ignore the interrupts.
- */
-
-static void power_pmu_start(struct perf_event *event, int ef_flags)
-{
-	unsigned long flags;
-	s64 left;
-	unsigned long val;
-
-	if (!event->hw.idx || !event->hw.sample_period)
-		return;
-
-	if (!(event->hw.state & PERF_HES_STOPPED))
-		return;
-
-	if (ef_flags & PERF_EF_RELOAD)
-		WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
-
-	local_irq_save(flags);
-	perf_pmu_disable(event->pmu);
-
-	event->hw.state = 0;
-	left = local64_read(&event->hw.period_left);
-
-	val = 0;
-	if (left < 0x80000000L)
-		val = 0x80000000L - left;
-
-	write_pmc(event->hw.idx, val);
-
-	perf_event_update_userpage(event);
-	perf_pmu_enable(event->pmu);
-	local_irq_restore(flags);
-}
-
-static void power_pmu_stop(struct perf_event *event, int ef_flags)
-{
-	unsigned long flags;
-
-	if (!event->hw.idx || !event->hw.sample_period)
-		return;
-
-	if (event->hw.state & PERF_HES_STOPPED)
-		return;
-
-	local_irq_save(flags);
-	perf_pmu_disable(event->pmu);
-
-	power_pmu_read(event);
-	event->hw.state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
-	write_pmc(event->hw.idx, 0);
-
-	perf_event_update_userpage(event);
-	perf_pmu_enable(event->pmu);
-	local_irq_restore(flags);
-}
-
-/*
- * Start group events scheduling transaction
- * Set the flag to make pmu::enable() not perform the
- * schedulability test, it will be performed at commit time
- */
-void power_pmu_start_txn(struct pmu *pmu)
-{
-	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
-
-	perf_pmu_disable(pmu);
-	cpuhw->group_flag |= PERF_EVENT_TXN;
-	cpuhw->n_txn_start = cpuhw->n_events;
-}
-
-/*
- * Stop group events scheduling transaction
- * Clear the flag and pmu::enable() will perform the
- * schedulability test.
- */
-void power_pmu_cancel_txn(struct pmu *pmu)
-{
-	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
-
-	cpuhw->group_flag &= ~PERF_EVENT_TXN;
-	perf_pmu_enable(pmu);
-}
-
-/*
- * Commit group events scheduling transaction
- * Perform the group schedulability test as a whole
- * Return 0 if success
- */
-int power_pmu_commit_txn(struct pmu *pmu)
-{
-	struct cpu_hw_events *cpuhw;
-	long i, n;
-
-	if (!ppmu)
-		return -EAGAIN;
-	cpuhw = &__get_cpu_var(cpu_hw_events);
-	n = cpuhw->n_events;
-	if (check_excludes(cpuhw->event, cpuhw->flags, 0, n))
-		return -EAGAIN;
-	i = power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n);
-	if (i < 0)
-		return -EAGAIN;
-
-	for (i = cpuhw->n_txn_start; i < n; ++i)
-		cpuhw->event[i]->hw.config = cpuhw->events[i];
-
-	cpuhw->group_flag &= ~PERF_EVENT_TXN;
-	perf_pmu_enable(pmu);
-	return 0;
-}
-
-/*
- * Return 1 if we might be able to put event on a limited PMC,
- * or 0 if not.
- * A event can only go on a limited PMC if it counts something
- * that a limited PMC can count, doesn't require interrupts, and
- * doesn't exclude any processor mode.
- */
-static int can_go_on_limited_pmc(struct perf_event *event, u64 ev,
-				 unsigned int flags)
-{
-	int n;
-	u64 alt[MAX_EVENT_ALTERNATIVES];
-
-	if (event->attr.exclude_user
-	    || event->attr.exclude_kernel
-	    || event->attr.exclude_hv
-	    || event->attr.sample_period)
-		return 0;
-
-	if (ppmu->limited_pmc_event(ev))
-		return 1;
-
-	/*
-	 * The requested event_id isn't on a limited PMC already;
-	 * see if any alternative code goes on a limited PMC.
-	 */
-	if (!ppmu->get_alternatives)
-		return 0;
-
-	flags |= PPMU_LIMITED_PMC_OK | PPMU_LIMITED_PMC_REQD;
-	n = ppmu->get_alternatives(ev, flags, alt);
-
-	return n > 0;
-}
-
-/*
- * Find an alternative event_id that goes on a normal PMC, if possible,
- * and return the event_id code, or 0 if there is no such alternative.
- * (Note: event_id code 0 is "don't count" on all machines.)
- */
-static u64 normal_pmc_alternative(u64 ev, unsigned long flags)
-{
-	u64 alt[MAX_EVENT_ALTERNATIVES];
-	int n;
-
-	flags &= ~(PPMU_LIMITED_PMC_OK | PPMU_LIMITED_PMC_REQD);
-	n = ppmu->get_alternatives(ev, flags, alt);
-	if (!n)
-		return 0;
-	return alt[0];
-}
-
-/* Number of perf_events counting hardware events */
-static atomic_t num_events;
-/* Used to avoid races in calling reserve/release_pmc_hardware */
-static DEFINE_MUTEX(pmc_reserve_mutex);
-
-/*
- * Release the PMU if this is the last perf_event.
- */
-static void hw_perf_event_destroy(struct perf_event *event)
-{
-	if (!atomic_add_unless(&num_events, -1, 1)) {
-		mutex_lock(&pmc_reserve_mutex);
-		if (atomic_dec_return(&num_events) == 0)
-			release_pmc_hardware();
-		mutex_unlock(&pmc_reserve_mutex);
-	}
-}
-
-/*
- * Translate a generic cache event_id config to a raw event_id code.
- */
-static int hw_perf_cache_event(u64 config, u64 *eventp)
-{
-	unsigned long type, op, result;
-	int ev;
-
-	if (!ppmu->cache_events)
-		return -EINVAL;
-
-	/* unpack config */
-	type = config & 0xff;
-	op = (config >> 8) & 0xff;
-	result = (config >> 16) & 0xff;
-
-	if (type >= PERF_COUNT_HW_CACHE_MAX ||
-	    op >= PERF_COUNT_HW_CACHE_OP_MAX ||
-	    result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
-		return -EINVAL;
-
-	ev = (*ppmu->cache_events)[type][op][result];
-	if (ev == 0)
-		return -EOPNOTSUPP;
-	if (ev == -1)
-		return -EINVAL;
-	*eventp = ev;
-	return 0;
-}
-
-static int power_pmu_event_init(struct perf_event *event)
-{
-	u64 ev;
-	unsigned long flags;
-	struct perf_event *ctrs[MAX_HWEVENTS];
-	u64 events[MAX_HWEVENTS];
-	unsigned int cflags[MAX_HWEVENTS];
-	int n;
-	int err;
-	struct cpu_hw_events *cpuhw;
-
-	if (!ppmu)
-		return -ENOENT;
-
-	/* does not support taken branch sampling */
-	if (has_branch_stack(event))
-		return -EOPNOTSUPP;
-
-	switch (event->attr.type) {
-	case PERF_TYPE_HARDWARE:
-		ev = event->attr.config;
-		if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
-			return -EOPNOTSUPP;
-		ev = ppmu->generic_events[ev];
-		break;
-	case PERF_TYPE_HW_CACHE:
-		err = hw_perf_cache_event(event->attr.config, &ev);
-		if (err)
-			return err;
-		break;
-	case PERF_TYPE_RAW:
-		ev = event->attr.config;
-		break;
-	default:
-		return -ENOENT;
-	}
-
-	event->hw.config_base = ev;
-	event->hw.idx = 0;
-
-	/*
-	 * If we are not running on a hypervisor, force the
-	 * exclude_hv bit to 0 so that we don't care what
-	 * the user set it to.
-	 */
-	if (!firmware_has_feature(FW_FEATURE_LPAR))
-		event->attr.exclude_hv = 0;
-
-	/*
-	 * If this is a per-task event, then we can use
-	 * PM_RUN_* events interchangeably with their non RUN_*
-	 * equivalents, e.g. PM_RUN_CYC instead of PM_CYC.
-	 * XXX we should check if the task is an idle task.
-	 */
-	flags = 0;
-	if (event->attach_state & PERF_ATTACH_TASK)
-		flags |= PPMU_ONLY_COUNT_RUN;
-
-	/*
-	 * If this machine has limited events, check whether this
-	 * event_id could go on a limited event.
-	 */
-	if (ppmu->flags & PPMU_LIMITED_PMC5_6) {
-		if (can_go_on_limited_pmc(event, ev, flags)) {
-			flags |= PPMU_LIMITED_PMC_OK;
-		} else if (ppmu->limited_pmc_event(ev)) {
-			/*
-			 * The requested event_id is on a limited PMC,
-			 * but we can't use a limited PMC; see if any
-			 * alternative goes on a normal PMC.
-			 */
-			ev = normal_pmc_alternative(ev, flags);
-			if (!ev)
-				return -EINVAL;
-		}
-	}
-
-	/*
-	 * If this is in a group, check if it can go on with all the
-	 * other hardware events in the group.  We assume the event
-	 * hasn't been linked into its leader's sibling list at this point.
-	 */
-	n = 0;
-	if (event->group_leader != event) {
-		n = collect_events(event->group_leader, ppmu->n_counter - 1,
-				   ctrs, events, cflags);
-		if (n < 0)
-			return -EINVAL;
-	}
-	events[n] = ev;
-	ctrs[n] = event;
-	cflags[n] = flags;
-	if (check_excludes(ctrs, cflags, n, 1))
-		return -EINVAL;
-
-	cpuhw = &get_cpu_var(cpu_hw_events);
-	err = power_check_constraints(cpuhw, events, cflags, n + 1);
-	put_cpu_var(cpu_hw_events);
-	if (err)
-		return -EINVAL;
-
-	event->hw.config = events[n];
-	event->hw.event_base = cflags[n];
-	event->hw.last_period = event->hw.sample_period;
-	local64_set(&event->hw.period_left, event->hw.last_period);
-
-	/*
-	 * See if we need to reserve the PMU.
-	 * If no events are currently in use, then we have to take a
-	 * mutex to ensure that we don't race with another task doing
-	 * reserve_pmc_hardware or release_pmc_hardware.
-	 */
-	err = 0;
-	if (!atomic_inc_not_zero(&num_events)) {
-		mutex_lock(&pmc_reserve_mutex);
-		if (atomic_read(&num_events) == 0 &&
-		    reserve_pmc_hardware(perf_event_interrupt))
-			err = -EBUSY;
-		else
-			atomic_inc(&num_events);
-		mutex_unlock(&pmc_reserve_mutex);
-	}
-	event->destroy = hw_perf_event_destroy;
-
-	return err;
-}
-
-static int power_pmu_event_idx(struct perf_event *event)
-{
-	return event->hw.idx;
-}
-
-struct pmu power_pmu = {
-	.pmu_enable	= power_pmu_enable,
-	.pmu_disable	= power_pmu_disable,
-	.event_init	= power_pmu_event_init,
-	.add		= power_pmu_add,
-	.del		= power_pmu_del,
-	.start		= power_pmu_start,
-	.stop		= power_pmu_stop,
-	.read		= power_pmu_read,
-	.start_txn	= power_pmu_start_txn,
-	.cancel_txn	= power_pmu_cancel_txn,
-	.commit_txn	= power_pmu_commit_txn,
-	.event_idx	= power_pmu_event_idx,
-};
-
-/*
- * A counter has overflowed; update its count and record
- * things if requested.  Note that interrupts are hard-disabled
- * here so there is no possibility of being interrupted.
- */
-static void record_and_restart(struct perf_event *event, unsigned long val,
-			       struct pt_regs *regs)
-{
-	u64 period = event->hw.sample_period;
-	s64 prev, delta, left;
-	int record = 0;
-
-	if (event->hw.state & PERF_HES_STOPPED) {
-		write_pmc(event->hw.idx, 0);
-		return;
-	}
-
-	/* we don't have to worry about interrupts here */
-	prev = local64_read(&event->hw.prev_count);
-	delta = check_and_compute_delta(prev, val);
-	local64_add(delta, &event->count);
-
-	/*
-	 * See if the total period for this event has expired,
-	 * and update for the next period.
-	 */
-	val = 0;
-	left = local64_read(&event->hw.period_left) - delta;
-	if (period) {
-		if (left <= 0) {
-			left += period;
-			if (left <= 0)
-				left = period;
-			record = 1;
-			event->hw.last_period = event->hw.sample_period;
-		}
-		if (left < 0x80000000LL)
-			val = 0x80000000LL - left;
-	}
-
-	write_pmc(event->hw.idx, val);
-	local64_set(&event->hw.prev_count, val);
-	local64_set(&event->hw.period_left, left);
-	perf_event_update_userpage(event);
-
-	/*
-	 * Finally record data if requested.
-	 */
-	if (record) {
-		struct perf_sample_data data;
-
-		perf_sample_data_init(&data, ~0ULL);
-		data.period = event->hw.last_period;
-
-		if (event->attr.sample_type & PERF_SAMPLE_ADDR)
-			perf_get_data_addr(regs, &data.addr);
-
-		if (perf_event_overflow(event, &data, regs))
-			power_pmu_stop(event, 0);
-	}
-}
-
-/*
- * Called from generic code to get the misc flags (i.e. processor mode)
- * for an event_id.
- */
-unsigned long perf_misc_flags(struct pt_regs *regs)
-{
-	u32 flags = perf_get_misc_flags(regs);
-
-	if (flags)
-		return flags;
-	return user_mode(regs) ? PERF_RECORD_MISC_USER :
-		PERF_RECORD_MISC_KERNEL;
-}
-
-/*
- * Called from generic code to get the instruction pointer
- * for an event_id.
- */
-unsigned long perf_instruction_pointer(struct pt_regs *regs)
-{
-	unsigned long ip;
-
-	if (TRAP(regs) != 0xf00)
-		return regs->nip;	/* not a PMU interrupt */
-
-	ip = mfspr(SPRN_SIAR) + perf_ip_adjust(regs);
-	return ip;
-}
-
-static bool pmc_overflow(unsigned long val)
-{
-	if ((int)val < 0)
-		return true;
-
-	/*
-	 * Events on POWER7 can roll back if a speculative event doesn't
-	 * eventually complete. Unfortunately in some rare cases they will
-	 * raise a performance monitor exception. We need to catch this to
-	 * ensure we reset the PMC. In all cases the PMC will be 256 or less
-	 * cycles from overflow.
-	 *
-	 * We only do this if the first pass fails to find any overflowing
-	 * PMCs because a user might set a period of less than 256 and we
-	 * don't want to mistakenly reset them.
-	 */
-	if (__is_processor(PV_POWER7) && ((0x80000000 - val) <= 256))
-		return true;
-
-	return false;
-}
-
-/*
- * Performance monitor interrupt stuff
- */
-static void perf_event_interrupt(struct pt_regs *regs)
-{
-	int i;
-	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
-	struct perf_event *event;
-	unsigned long val;
-	int found = 0;
-	int nmi;
-
-	if (cpuhw->n_limited)
-		freeze_limited_counters(cpuhw, mfspr(SPRN_PMC5),
-					mfspr(SPRN_PMC6));
-
-	perf_read_regs(regs);
-
-	nmi = perf_intr_is_nmi(regs);
-	if (nmi)
-		nmi_enter();
-	else
-		irq_enter();
-
-	for (i = 0; i < cpuhw->n_events; ++i) {
-		event = cpuhw->event[i];
-		if (!event->hw.idx || is_limited_pmc(event->hw.idx))
-			continue;
-		val = read_pmc(event->hw.idx);
-		if ((int)val < 0) {
-			/* event has overflowed */
-			found = 1;
-			record_and_restart(event, val, regs);
-		}
-	}
-
-	/*
-	 * In case we didn't find and reset the event that caused
-	 * the interrupt, scan all events and reset any that are
-	 * negative, to avoid getting continual interrupts.
-	 * Any that we processed in the previous loop will not be negative.
-	 */
-	if (!found) {
-		for (i = 0; i < ppmu->n_counter; ++i) {
-			if (is_limited_pmc(i + 1))
-				continue;
-			val = read_pmc(i + 1);
-			if (pmc_overflow(val))
-				write_pmc(i + 1, 0);
-		}
-	}
-
-	/*
-	 * Reset MMCR0 to its normal value.  This will set PMXE and
-	 * clear FC (freeze counters) and PMAO (perf mon alert occurred)
-	 * and thus allow interrupts to occur again.
-	 * XXX might want to use MSR.PM to keep the events frozen until
-	 * we get back out of this interrupt.
-	 */
-	write_mmcr0(cpuhw, cpuhw->mmcr[0]);
-
-	if (nmi)
-		nmi_exit();
-	else
-		irq_exit();
-}
-
-static void power_pmu_setup(int cpu)
-{
-	struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
-
-	if (!ppmu)
-		return;
-	memset(cpuhw, 0, sizeof(*cpuhw));
-	cpuhw->mmcr[0] = MMCR0_FC;
-}
-
-static int __cpuinit
-power_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
-{
-	unsigned int cpu = (long)hcpu;
-
-	switch (action & ~CPU_TASKS_FROZEN) {
-	case CPU_UP_PREPARE:
-		power_pmu_setup(cpu);
-		break;
-
-	default:
-		break;
-	}
-
-	return NOTIFY_OK;
-}
-
-int __cpuinit register_power_pmu(struct power_pmu *pmu)
-{
-	if (ppmu)
-		return -EBUSY;		/* something's already registered */
-
-	ppmu = pmu;
-	pr_info("%s performance monitor hardware support registered\n",
-		pmu->name);
-
-#ifdef MSR_HV
-	/*
-	 * Use FCHV to ignore kernel events if MSR.HV is set.
-	 */
-	if (mfmsr() & MSR_HV)
-		freeze_events_kernel = MMCR0_FCHV;
-#endif /* CONFIG_PPC64 */
-
-	perf_pmu_register(&power_pmu, "cpu", PERF_TYPE_RAW);
-	perf_cpu_notifier(power_pmu_notifier);
-
-	return 0;
-}
diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c
index a841a9d..58eaa3d 100644
--- a/arch/powerpc/kernel/pmc.c
+++ b/arch/powerpc/kernel/pmc.c
@@ -13,6 +13,7 @@
  */
 
 #include <linux/errno.h>
+#include <linux/bug.h>
 #include <linux/spinlock.h>
 #include <linux/export.h>
 
diff --git a/arch/powerpc/kernel/power4-pmu.c b/arch/powerpc/kernel/power4-pmu.c
deleted file mode 100644
index b4f1dda..0000000
--- a/arch/powerpc/kernel/power4-pmu.c
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * Performance counter support for POWER4 (GP) and POWER4+ (GQ) processors.
- *
- * Copyright 2009 Paul Mackerras, 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.
- */
-#include <linux/kernel.h>
-#include <linux/perf_event.h>
-#include <linux/string.h>
-#include <asm/reg.h>
-#include <asm/cputable.h>
-
-/*
- * Bits in event code for POWER4
- */
-#define PM_PMC_SH	12	/* PMC number (1-based) for direct events */
-#define PM_PMC_MSK	0xf
-#define PM_UNIT_SH	8	/* TTMMUX number and setting - unit select */
-#define PM_UNIT_MSK	0xf
-#define PM_LOWER_SH	6
-#define PM_LOWER_MSK	1
-#define PM_LOWER_MSKS	0x40
-#define PM_BYTE_SH	4	/* Byte number of event bus to use */
-#define PM_BYTE_MSK	3
-#define PM_PMCSEL_MSK	7
-
-/*
- * Unit code values
- */
-#define PM_FPU		1
-#define PM_ISU1		2
-#define PM_IFU		3
-#define PM_IDU0		4
-#define PM_ISU1_ALT	6
-#define PM_ISU2		7
-#define PM_IFU_ALT	8
-#define PM_LSU0		9
-#define PM_LSU1		0xc
-#define PM_GPS		0xf
-
-/*
- * Bits in MMCR0 for POWER4
- */
-#define MMCR0_PMC1SEL_SH	8
-#define MMCR0_PMC2SEL_SH	1
-#define MMCR_PMCSEL_MSK		0x1f
-
-/*
- * Bits in MMCR1 for POWER4
- */
-#define MMCR1_TTM0SEL_SH	62
-#define MMCR1_TTC0SEL_SH	61
-#define MMCR1_TTM1SEL_SH	59
-#define MMCR1_TTC1SEL_SH	58
-#define MMCR1_TTM2SEL_SH	56
-#define MMCR1_TTC2SEL_SH	55
-#define MMCR1_TTM3SEL_SH	53
-#define MMCR1_TTC3SEL_SH	52
-#define MMCR1_TTMSEL_MSK	3
-#define MMCR1_TD_CP_DBG0SEL_SH	50
-#define MMCR1_TD_CP_DBG1SEL_SH	48
-#define MMCR1_TD_CP_DBG2SEL_SH	46
-#define MMCR1_TD_CP_DBG3SEL_SH	44
-#define MMCR1_DEBUG0SEL_SH	43
-#define MMCR1_DEBUG1SEL_SH	42
-#define MMCR1_DEBUG2SEL_SH	41
-#define MMCR1_DEBUG3SEL_SH	40
-#define MMCR1_PMC1_ADDER_SEL_SH	39
-#define MMCR1_PMC2_ADDER_SEL_SH	38
-#define MMCR1_PMC6_ADDER_SEL_SH	37
-#define MMCR1_PMC5_ADDER_SEL_SH	36
-#define MMCR1_PMC8_ADDER_SEL_SH	35
-#define MMCR1_PMC7_ADDER_SEL_SH	34
-#define MMCR1_PMC3_ADDER_SEL_SH	33
-#define MMCR1_PMC4_ADDER_SEL_SH	32
-#define MMCR1_PMC3SEL_SH	27
-#define MMCR1_PMC4SEL_SH	22
-#define MMCR1_PMC5SEL_SH	17
-#define MMCR1_PMC6SEL_SH	12
-#define MMCR1_PMC7SEL_SH	7
-#define MMCR1_PMC8SEL_SH	2	/* note bit 0 is in MMCRA for GP */
-
-static short mmcr1_adder_bits[8] = {
-	MMCR1_PMC1_ADDER_SEL_SH,
-	MMCR1_PMC2_ADDER_SEL_SH,
-	MMCR1_PMC3_ADDER_SEL_SH,
-	MMCR1_PMC4_ADDER_SEL_SH,
-	MMCR1_PMC5_ADDER_SEL_SH,
-	MMCR1_PMC6_ADDER_SEL_SH,
-	MMCR1_PMC7_ADDER_SEL_SH,
-	MMCR1_PMC8_ADDER_SEL_SH
-};
-
-/*
- * Bits in MMCRA
- */
-#define MMCRA_PMC8SEL0_SH	17	/* PMC8SEL bit 0 for GP */
-
-/*
- * Layout of constraint bits:
- * 6666555555555544444444443333333333222222222211111111110000000000
- * 3210987654321098765432109876543210987654321098765432109876543210
- *        |[  >[  >[   >|||[  >[  ><  ><  ><  ><  ><><><><><><><><>
- *        | UC1 UC2 UC3 ||| PS1 PS2 B0  B1  B2  B3 P1P2P3P4P5P6P7P8
- * 	  \SMPL	        ||\TTC3SEL
- * 		        |\TTC_IFU_SEL
- * 		        \TTM2SEL0
- *
- * SMPL - SAMPLE_ENABLE constraint
- *     56: SAMPLE_ENABLE value 0x0100_0000_0000_0000
- *
- * UC1 - unit constraint 1: can't have all three of FPU/ISU1/IDU0|ISU2
- *     55: UC1 error 0x0080_0000_0000_0000
- *     54: FPU events needed 0x0040_0000_0000_0000
- *     53: ISU1 events needed 0x0020_0000_0000_0000
- *     52: IDU0|ISU2 events needed 0x0010_0000_0000_0000
- *
- * UC2 - unit constraint 2: can't have all three of FPU/IFU/LSU0
- *     51: UC2 error 0x0008_0000_0000_0000
- *     50: FPU events needed 0x0004_0000_0000_0000
- *     49: IFU events needed 0x0002_0000_0000_0000
- *     48: LSU0 events needed 0x0001_0000_0000_0000
- *
- * UC3 - unit constraint 3: can't have all four of LSU0/IFU/IDU0|ISU2/ISU1
- *     47: UC3 error 0x8000_0000_0000
- *     46: LSU0 events needed 0x4000_0000_0000
- *     45: IFU events needed 0x2000_0000_0000
- *     44: IDU0|ISU2 events needed 0x1000_0000_0000
- *     43: ISU1 events needed 0x0800_0000_0000
- *
- * TTM2SEL0
- *     42: 0 = IDU0 events needed
- *     	   1 = ISU2 events needed 0x0400_0000_0000
- *
- * TTC_IFU_SEL
- *     41: 0 = IFU.U events needed
- *     	   1 = IFU.L events needed 0x0200_0000_0000
- *
- * TTC3SEL
- *     40: 0 = LSU1.U events needed
- *     	   1 = LSU1.L events needed 0x0100_0000_0000
- *
- * PS1
- *     39: PS1 error 0x0080_0000_0000
- *     36-38: count of events needing PMC1/2/5/6 0x0070_0000_0000
- *
- * PS2
- *     35: PS2 error 0x0008_0000_0000
- *     32-34: count of events needing PMC3/4/7/8 0x0007_0000_0000
- *
- * B0
- *     28-31: Byte 0 event source 0xf000_0000
- *     	   1 = FPU
- * 	   2 = ISU1
- * 	   3 = IFU
- * 	   4 = IDU0
- * 	   7 = ISU2
- * 	   9 = LSU0
- * 	   c = LSU1
- * 	   f = GPS
- *
- * B1, B2, B3
- *     24-27, 20-23, 16-19: Byte 1, 2, 3 event sources
- *
- * P8
- *     15: P8 error 0x8000
- *     14-15: Count of events needing PMC8
- *
- * P1..P7
- *     0-13: Count of events needing PMC1..PMC7
- *
- * Note: this doesn't allow events using IFU.U to be combined with events
- * using IFU.L, though that is feasible (using TTM0 and TTM2).  However
- * there are no listed events for IFU.L (they are debug events not
- * verified for performance monitoring) so this shouldn't cause a
- * problem.
- */
-
-static struct unitinfo {
-	unsigned long	value, mask;
-	int		unit;
-	int		lowerbit;
-} p4_unitinfo[16] = {
-	[PM_FPU]  = { 0x44000000000000ul, 0x88000000000000ul, PM_FPU, 0 },
-	[PM_ISU1] = { 0x20080000000000ul, 0x88000000000000ul, PM_ISU1, 0 },
-	[PM_ISU1_ALT] =
-		    { 0x20080000000000ul, 0x88000000000000ul, PM_ISU1, 0 },
-	[PM_IFU]  = { 0x02200000000000ul, 0x08820000000000ul, PM_IFU, 41 },
-	[PM_IFU_ALT] =
-		    { 0x02200000000000ul, 0x08820000000000ul, PM_IFU, 41 },
-	[PM_IDU0] = { 0x10100000000000ul, 0x80840000000000ul, PM_IDU0, 1 },
-	[PM_ISU2] = { 0x10140000000000ul, 0x80840000000000ul, PM_ISU2, 0 },
-	[PM_LSU0] = { 0x01400000000000ul, 0x08800000000000ul, PM_LSU0, 0 },
-	[PM_LSU1] = { 0x00000000000000ul, 0x00010000000000ul, PM_LSU1, 40 },
-	[PM_GPS]  = { 0x00000000000000ul, 0x00000000000000ul, PM_GPS, 0 }
-};
-
-static unsigned char direct_marked_event[8] = {
-	(1<<2) | (1<<3),	/* PMC1: PM_MRK_GRP_DISP, PM_MRK_ST_CMPL */
-	(1<<3) | (1<<5),	/* PMC2: PM_THRESH_TIMEO, PM_MRK_BRU_FIN */
-	(1<<3),			/* PMC3: PM_MRK_ST_CMPL_INT */
-	(1<<4) | (1<<5),	/* PMC4: PM_MRK_GRP_CMPL, PM_MRK_CRU_FIN */
-	(1<<4) | (1<<5),	/* PMC5: PM_MRK_GRP_TIMEO */
-	(1<<3) | (1<<4) | (1<<5),
-		/* PMC6: PM_MRK_ST_GPS, PM_MRK_FXU_FIN, PM_MRK_GRP_ISSUED */
-	(1<<4) | (1<<5),	/* PMC7: PM_MRK_FPU_FIN, PM_MRK_INST_FIN */
-	(1<<4),			/* PMC8: PM_MRK_LSU_FIN */
-};
-
-/*
- * Returns 1 if event counts things relating to marked instructions
- * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
- */
-static int p4_marked_instr_event(u64 event)
-{
-	int pmc, psel, unit, byte, bit;
-	unsigned int mask;
-
-	pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-	psel = event & PM_PMCSEL_MSK;
-	if (pmc) {
-		if (direct_marked_event[pmc - 1] & (1 << psel))
-			return 1;
-		if (psel == 0)		/* add events */
-			bit = (pmc <= 4)? pmc - 1: 8 - pmc;
-		else if (psel == 6)	/* decode events */
-			bit = 4;
-		else
-			return 0;
-	} else
-		bit = psel;
-
-	byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-	unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
-	mask = 0;
-	switch (unit) {
-	case PM_LSU1:
-		if (event & PM_LOWER_MSKS)
-			mask = 1 << 28;		/* byte 7 bit 4 */
-		else
-			mask = 6 << 24;		/* byte 3 bits 1 and 2 */
-		break;
-	case PM_LSU0:
-		/* byte 3, bit 3; byte 2 bits 0,2,3,4,5; byte 1 */
-		mask = 0x083dff00;
-	}
-	return (mask >> (byte * 8 + bit)) & 1;
-}
-
-static int p4_get_constraint(u64 event, unsigned long *maskp,
-			     unsigned long *valp)
-{
-	int pmc, byte, unit, lower, sh;
-	unsigned long mask = 0, value = 0;
-	int grp = -1;
-
-	pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-	if (pmc) {
-		if (pmc > 8)
-			return -1;
-		sh = (pmc - 1) * 2;
-		mask |= 2 << sh;
-		value |= 1 << sh;
-		grp = ((pmc - 1) >> 1) & 1;
-	}
-	unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
-	byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-	if (unit) {
-		lower = (event >> PM_LOWER_SH) & PM_LOWER_MSK;
-
-		/*
-		 * Bus events on bytes 0 and 2 can be counted
-		 * on PMC1/2/5/6; bytes 1 and 3 on PMC3/4/7/8.
-		 */
-		if (!pmc)
-			grp = byte & 1;
-
-		if (!p4_unitinfo[unit].unit)
-			return -1;
-		mask  |= p4_unitinfo[unit].mask;
-		value |= p4_unitinfo[unit].value;
-		sh = p4_unitinfo[unit].lowerbit;
-		if (sh > 1)
-			value |= (unsigned long)lower << sh;
-		else if (lower != sh)
-			return -1;
-		unit = p4_unitinfo[unit].unit;
-
-		/* Set byte lane select field */
-		mask  |= 0xfULL << (28 - 4 * byte);
-		value |= (unsigned long)unit << (28 - 4 * byte);
-	}
-	if (grp == 0) {
-		/* increment PMC1/2/5/6 field */
-		mask  |= 0x8000000000ull;
-		value |= 0x1000000000ull;
-	} else {
-		/* increment PMC3/4/7/8 field */
-		mask  |= 0x800000000ull;
-		value |= 0x100000000ull;
-	}
-
-	/* Marked instruction events need sample_enable set */
-	if (p4_marked_instr_event(event)) {
-		mask  |= 1ull << 56;
-		value |= 1ull << 56;
-	}
-
-	/* PMCSEL=6 decode events on byte 2 need sample_enable clear */
-	if (pmc && (event & PM_PMCSEL_MSK) == 6 && byte == 2)
-		mask  |= 1ull << 56;
-
-	*maskp = mask;
-	*valp = value;
-	return 0;
-}
-
-static unsigned int ppc_inst_cmpl[] = {
-	0x1001, 0x4001, 0x6001, 0x7001, 0x8001
-};
-
-static int p4_get_alternatives(u64 event, unsigned int flags, u64 alt[])
-{
-	int i, j, na;
-
-	alt[0] = event;
-	na = 1;
-
-	/* 2 possibilities for PM_GRP_DISP_REJECT */
-	if (event == 0x8003 || event == 0x0224) {
-		alt[1] = event ^ (0x8003 ^ 0x0224);
-		return 2;
-	}
-
-	/* 2 possibilities for PM_ST_MISS_L1 */
-	if (event == 0x0c13 || event == 0x0c23) {
-		alt[1] = event ^ (0x0c13 ^ 0x0c23);
-		return 2;
-	}
-
-	/* several possibilities for PM_INST_CMPL */
-	for (i = 0; i < ARRAY_SIZE(ppc_inst_cmpl); ++i) {
-		if (event == ppc_inst_cmpl[i]) {
-			for (j = 0; j < ARRAY_SIZE(ppc_inst_cmpl); ++j)
-				if (j != i)
-					alt[na++] = ppc_inst_cmpl[j];
-			break;
-		}
-	}
-
-	return na;
-}
-
-static int p4_compute_mmcr(u64 event[], int n_ev,
-			   unsigned int hwc[], unsigned long mmcr[])
-{
-	unsigned long mmcr0 = 0, mmcr1 = 0, mmcra = 0;
-	unsigned int pmc, unit, byte, psel, lower;
-	unsigned int ttm, grp;
-	unsigned int pmc_inuse = 0;
-	unsigned int pmc_grp_use[2];
-	unsigned char busbyte[4];
-	unsigned char unituse[16];
-	unsigned int unitlower = 0;
-	int i;
-
-	if (n_ev > 8)
-		return -1;
-
-	/* First pass to count resource use */
-	pmc_grp_use[0] = pmc_grp_use[1] = 0;
-	memset(busbyte, 0, sizeof(busbyte));
-	memset(unituse, 0, sizeof(unituse));
-	for (i = 0; i < n_ev; ++i) {
-		pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-		if (pmc) {
-			if (pmc_inuse & (1 << (pmc - 1)))
-				return -1;
-			pmc_inuse |= 1 << (pmc - 1);
-			/* count 1/2/5/6 vs 3/4/7/8 use */
-			++pmc_grp_use[((pmc - 1) >> 1) & 1];
-		}
-		unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
-		byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
-		lower = (event[i] >> PM_LOWER_SH) & PM_LOWER_MSK;
-		if (unit) {
-			if (!pmc)
-				++pmc_grp_use[byte & 1];
-			if (unit == 6 || unit == 8)
-				/* map alt ISU1/IFU codes: 6->2, 8->3 */
-				unit = (unit >> 1) - 1;
-			if (busbyte[byte] && busbyte[byte] != unit)
-				return -1;
-			busbyte[byte] = unit;
-			lower <<= unit;
-			if (unituse[unit] && lower != (unitlower & lower))
-				return -1;
-			unituse[unit] = 1;
-			unitlower |= lower;
-		}
-	}
-	if (pmc_grp_use[0] > 4 || pmc_grp_use[1] > 4)
-		return -1;
-
-	/*
-	 * Assign resources and set multiplexer selects.
-	 *
-	 * Units 1,2,3 are on TTM0, 4,6,7 on TTM1, 8,10 on TTM2.
-	 * Each TTMx can only select one unit, but since
-	 * units 2 and 6 are both ISU1, and 3 and 8 are both IFU,
-	 * we have some choices.
-	 */
-	if (unituse[2] & (unituse[1] | (unituse[3] & unituse[9]))) {
-		unituse[6] = 1;		/* Move 2 to 6 */
-		unituse[2] = 0;
-	}
-	if (unituse[3] & (unituse[1] | unituse[2])) {
-		unituse[8] = 1;		/* Move 3 to 8 */
-		unituse[3] = 0;
-		unitlower = (unitlower & ~8) | ((unitlower & 8) << 5);
-	}
-	/* Check only one unit per TTMx */
-	if (unituse[1] + unituse[2] + unituse[3] > 1 ||
-	    unituse[4] + unituse[6] + unituse[7] > 1 ||
-	    unituse[8] + unituse[9] > 1 ||
-	    (unituse[5] | unituse[10] | unituse[11] |
-	     unituse[13] | unituse[14]))
-		return -1;
-
-	/* Set TTMxSEL fields.  Note, units 1-3 => TTM0SEL codes 0-2 */
-	mmcr1 |= (unsigned long)(unituse[3] * 2 + unituse[2])
-		<< MMCR1_TTM0SEL_SH;
-	mmcr1 |= (unsigned long)(unituse[7] * 3 + unituse[6] * 2)
-		<< MMCR1_TTM1SEL_SH;
-	mmcr1 |= (unsigned long)unituse[9] << MMCR1_TTM2SEL_SH;
-
-	/* Set TTCxSEL fields. */
-	if (unitlower & 0xe)
-		mmcr1 |= 1ull << MMCR1_TTC0SEL_SH;
-	if (unitlower & 0xf0)
-		mmcr1 |= 1ull << MMCR1_TTC1SEL_SH;
-	if (unitlower & 0xf00)
-		mmcr1 |= 1ull << MMCR1_TTC2SEL_SH;
-	if (unitlower & 0x7000)
-		mmcr1 |= 1ull << MMCR1_TTC3SEL_SH;
-
-	/* Set byte lane select fields. */
-	for (byte = 0; byte < 4; ++byte) {
-		unit = busbyte[byte];
-		if (!unit)
-			continue;
-		if (unit == 0xf) {
-			/* special case for GPS */
-			mmcr1 |= 1ull << (MMCR1_DEBUG0SEL_SH - byte);
-		} else {
-			if (!unituse[unit])
-				ttm = unit - 1;		/* 2->1, 3->2 */
-			else
-				ttm = unit >> 2;
-			mmcr1 |= (unsigned long)ttm
-				<< (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
-		}
-	}
-
-	/* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
-	for (i = 0; i < n_ev; ++i) {
-		pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-		unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
-		byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
-		psel = event[i] & PM_PMCSEL_MSK;
-		if (!pmc) {
-			/* Bus event or 00xxx direct event (off or cycles) */
-			if (unit)
-				psel |= 0x10 | ((byte & 2) << 2);
-			for (pmc = 0; pmc < 8; ++pmc) {
-				if (pmc_inuse & (1 << pmc))
-					continue;
-				grp = (pmc >> 1) & 1;
-				if (unit) {
-					if (grp == (byte & 1))
-						break;
-				} else if (pmc_grp_use[grp] < 4) {
-					++pmc_grp_use[grp];
-					break;
-				}
-			}
-			pmc_inuse |= 1 << pmc;
-		} else {
-			/* Direct event */
-			--pmc;
-			if (psel == 0 && (byte & 2))
-				/* add events on higher-numbered bus */
-				mmcr1 |= 1ull << mmcr1_adder_bits[pmc];
-			else if (psel == 6 && byte == 3)
-				/* seem to need to set sample_enable here */
-				mmcra |= MMCRA_SAMPLE_ENABLE;
-			psel |= 8;
-		}
-		if (pmc <= 1)
-			mmcr0 |= psel << (MMCR0_PMC1SEL_SH - 7 * pmc);
-		else
-			mmcr1 |= psel << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2));
-		if (pmc == 7)	/* PMC8 */
-			mmcra |= (psel & 1) << MMCRA_PMC8SEL0_SH;
-		hwc[i] = pmc;
-		if (p4_marked_instr_event(event[i]))
-			mmcra |= MMCRA_SAMPLE_ENABLE;
-	}
-
-	if (pmc_inuse & 1)
-		mmcr0 |= MMCR0_PMC1CE;
-	if (pmc_inuse & 0xfe)
-		mmcr0 |= MMCR0_PMCjCE;
-
-	mmcra |= 0x2000;	/* mark only one IOP per PPC instruction */
-
-	/* Return MMCRx values */
-	mmcr[0] = mmcr0;
-	mmcr[1] = mmcr1;
-	mmcr[2] = mmcra;
-	return 0;
-}
-
-static void p4_disable_pmc(unsigned int pmc, unsigned long mmcr[])
-{
-	/*
-	 * Setting the PMCxSEL field to 0 disables PMC x.
-	 * (Note that pmc is 0-based here, not 1-based.)
-	 */
-	if (pmc <= 1) {
-		mmcr[0] &= ~(0x1fUL << (MMCR0_PMC1SEL_SH - 7 * pmc));
-	} else {
-		mmcr[1] &= ~(0x1fUL << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2)));
-		if (pmc == 7)
-			mmcr[2] &= ~(1UL << MMCRA_PMC8SEL0_SH);
-	}
-}
-
-static int p4_generic_events[] = {
-	[PERF_COUNT_HW_CPU_CYCLES]		= 7,
-	[PERF_COUNT_HW_INSTRUCTIONS]		= 0x1001,
-	[PERF_COUNT_HW_CACHE_REFERENCES]	= 0x8c10, /* PM_LD_REF_L1 */
-	[PERF_COUNT_HW_CACHE_MISSES]		= 0x3c10, /* PM_LD_MISS_L1 */
-	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= 0x330,  /* PM_BR_ISSUED */
-	[PERF_COUNT_HW_BRANCH_MISSES]		= 0x331,  /* PM_BR_MPRED_CR */
-};
-
-#define C(x)	PERF_COUNT_HW_CACHE_##x
-
-/*
- * Table of generalized cache-related events.
- * 0 means not supported, -1 means nonsensical, other values
- * are event codes.
- */
-static int power4_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
-	[C(L1D)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0x8c10,		0x3c10	},
-		[C(OP_WRITE)] = {	0x7c10,		0xc13	},
-		[C(OP_PREFETCH)] = {	0xc35,		0	},
-	},
-	[C(L1I)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0,		0	},
-		[C(OP_WRITE)] = {	-1,		-1	},
-		[C(OP_PREFETCH)] = {	0,		0	},
-	},
-	[C(LL)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0,		0	},
-		[C(OP_WRITE)] = {	0,		0	},
-		[C(OP_PREFETCH)] = {	0xc34,		0	},
-	},
-	[C(DTLB)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0,		0x904	},
-		[C(OP_WRITE)] = {	-1,		-1	},
-		[C(OP_PREFETCH)] = {	-1,		-1	},
-	},
-	[C(ITLB)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0,		0x900	},
-		[C(OP_WRITE)] = {	-1,		-1	},
-		[C(OP_PREFETCH)] = {	-1,		-1	},
-	},
-	[C(BPU)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0x330,		0x331	},
-		[C(OP_WRITE)] = {	-1,		-1	},
-		[C(OP_PREFETCH)] = {	-1,		-1	},
-	},
-	[C(NODE)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	-1,		-1	},
-		[C(OP_WRITE)] = {	-1,		-1	},
-		[C(OP_PREFETCH)] = {	-1,		-1	},
-	},
-};
-
-static struct power_pmu power4_pmu = {
-	.name			= "POWER4/4+",
-	.n_counter		= 8,
-	.max_alternatives	= 5,
-	.add_fields		= 0x0000001100005555ul,
-	.test_adder		= 0x0011083300000000ul,
-	.compute_mmcr		= p4_compute_mmcr,
-	.get_constraint		= p4_get_constraint,
-	.get_alternatives	= p4_get_alternatives,
-	.disable_pmc		= p4_disable_pmc,
-	.n_generic		= ARRAY_SIZE(p4_generic_events),
-	.generic_events		= p4_generic_events,
-	.cache_events		= &power4_cache_events,
-};
-
-static int __init init_power4_pmu(void)
-{
-	if (!cur_cpu_spec->oprofile_cpu_type ||
-	    strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power4"))
-		return -ENODEV;
-
-	return register_power_pmu(&power4_pmu);
-}
-
-early_initcall(init_power4_pmu);
diff --git a/arch/powerpc/kernel/power6-pmu.c b/arch/powerpc/kernel/power6-pmu.c
deleted file mode 100644
index 0bbc901..0000000
--- a/arch/powerpc/kernel/power6-pmu.c
+++ /dev/null
@@ -1,552 +0,0 @@
-/*
- * Performance counter support for POWER6 processors.
- *
- * Copyright 2008-2009 Paul Mackerras, 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.
- */
-#include <linux/kernel.h>
-#include <linux/perf_event.h>
-#include <linux/string.h>
-#include <asm/reg.h>
-#include <asm/cputable.h>
-
-/*
- * Bits in event code for POWER6
- */
-#define PM_PMC_SH	20	/* PMC number (1-based) for direct events */
-#define PM_PMC_MSK	0x7
-#define PM_PMC_MSKS	(PM_PMC_MSK << PM_PMC_SH)
-#define PM_UNIT_SH	16	/* Unit event comes (TTMxSEL encoding) */
-#define PM_UNIT_MSK	0xf
-#define PM_UNIT_MSKS	(PM_UNIT_MSK << PM_UNIT_SH)
-#define PM_LLAV		0x8000	/* Load lookahead match value */
-#define PM_LLA		0x4000	/* Load lookahead match enable */
-#define PM_BYTE_SH	12	/* Byte of event bus to use */
-#define PM_BYTE_MSK	3
-#define PM_SUBUNIT_SH	8	/* Subunit event comes from (NEST_SEL enc.) */
-#define PM_SUBUNIT_MSK	7
-#define PM_SUBUNIT_MSKS	(PM_SUBUNIT_MSK << PM_SUBUNIT_SH)
-#define PM_PMCSEL_MSK	0xff	/* PMCxSEL value */
-#define PM_BUSEVENT_MSK	0xf3700
-
-/*
- * Bits in MMCR1 for POWER6
- */
-#define MMCR1_TTM0SEL_SH	60
-#define MMCR1_TTMSEL_SH(n)	(MMCR1_TTM0SEL_SH - (n) * 4)
-#define MMCR1_TTMSEL_MSK	0xf
-#define MMCR1_TTMSEL(m, n)	(((m) >> MMCR1_TTMSEL_SH(n)) & MMCR1_TTMSEL_MSK)
-#define MMCR1_NESTSEL_SH	45
-#define MMCR1_NESTSEL_MSK	0x7
-#define MMCR1_NESTSEL(m)	(((m) >> MMCR1_NESTSEL_SH) & MMCR1_NESTSEL_MSK)
-#define MMCR1_PMC1_LLA		(1ul << 44)
-#define MMCR1_PMC1_LLA_VALUE	(1ul << 39)
-#define MMCR1_PMC1_ADDR_SEL	(1ul << 35)
-#define MMCR1_PMC1SEL_SH	24
-#define MMCR1_PMCSEL_SH(n)	(MMCR1_PMC1SEL_SH - (n) * 8)
-#define MMCR1_PMCSEL_MSK	0xff
-
-/*
- * Map of which direct events on which PMCs are marked instruction events.
- * Indexed by PMCSEL value >> 1.
- * Bottom 4 bits are a map of which PMCs are interesting,
- * top 4 bits say what sort of event:
- *   0 = direct marked event,
- *   1 = byte decode event,
- *   4 = add/and event (PMC1 -> bits 0 & 4),
- *   5 = add/and event (PMC1 -> bits 1 & 5),
- *   6 = add/and event (PMC1 -> bits 2 & 6),
- *   7 = add/and event (PMC1 -> bits 3 & 7).
- */
-static unsigned char direct_event_is_marked[0x60 >> 1] = {
-	0,	/* 00 */
-	0,	/* 02 */
-	0,	/* 04 */
-	0x07,	/* 06 PM_MRK_ST_CMPL, PM_MRK_ST_GPS, PM_MRK_ST_CMPL_INT */
-	0x04,	/* 08 PM_MRK_DFU_FIN */
-	0x06,	/* 0a PM_MRK_IFU_FIN, PM_MRK_INST_FIN */
-	0,	/* 0c */
-	0,	/* 0e */
-	0x02,	/* 10 PM_MRK_INST_DISP */
-	0x08,	/* 12 PM_MRK_LSU_DERAT_MISS */
-	0,	/* 14 */
-	0,	/* 16 */
-	0x0c,	/* 18 PM_THRESH_TIMEO, PM_MRK_INST_FIN */
-	0x0f,	/* 1a PM_MRK_INST_DISP, PM_MRK_{FXU,FPU,LSU}_FIN */
-	0x01,	/* 1c PM_MRK_INST_ISSUED */
-	0,	/* 1e */
-	0,	/* 20 */
-	0,	/* 22 */
-	0,	/* 24 */
-	0,	/* 26 */
-	0x15,	/* 28 PM_MRK_DATA_FROM_L2MISS, PM_MRK_DATA_FROM_L3MISS */
-	0,	/* 2a */
-	0,	/* 2c */
-	0,	/* 2e */
-	0x4f,	/* 30 */
-	0x7f,	/* 32 */
-	0x4f,	/* 34 */
-	0x5f,	/* 36 */
-	0x6f,	/* 38 */
-	0x4f,	/* 3a */
-	0,	/* 3c */
-	0x08,	/* 3e PM_MRK_INST_TIMEO */
-	0x1f,	/* 40 */
-	0x1f,	/* 42 */
-	0x1f,	/* 44 */
-	0x1f,	/* 46 */
-	0x1f,	/* 48 */
-	0x1f,	/* 4a */
-	0x1f,	/* 4c */
-	0x1f,	/* 4e */
-	0,	/* 50 */
-	0x05,	/* 52 PM_MRK_BR_TAKEN, PM_MRK_BR_MPRED */
-	0x1c,	/* 54 PM_MRK_PTEG_FROM_L3MISS, PM_MRK_PTEG_FROM_L2MISS */
-	0x02,	/* 56 PM_MRK_LD_MISS_L1 */
-	0,	/* 58 */
-	0,	/* 5a */
-	0,	/* 5c */
-	0,	/* 5e */
-};
-
-/*
- * Masks showing for each unit which bits are marked events.
- * These masks are in LE order, i.e. 0x00000001 is byte 0, bit 0.
- */
-static u32 marked_bus_events[16] = {
-	0x01000000,	/* direct events set 1: byte 3 bit 0 */
-	0x00010000,	/* direct events set 2: byte 2 bit 0 */
-	0, 0, 0, 0,	/* IDU, IFU, nest: nothing */
-	0x00000088,	/* VMX set 1: byte 0 bits 3, 7 */
-	0x000000c0,	/* VMX set 2: byte 0 bits 4-7 */
-	0x04010000,	/* LSU set 1: byte 2 bit 0, byte 3 bit 2 */
-	0xff010000u,	/* LSU set 2: byte 2 bit 0, all of byte 3 */
-	0,		/* LSU set 3 */
-	0x00000010,	/* VMX set 3: byte 0 bit 4 */
-	0,		/* BFP set 1 */
-	0x00000022,	/* BFP set 2: byte 0 bits 1, 5 */
-	0, 0
-};
-	
-/*
- * Returns 1 if event counts things relating to marked instructions
- * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
- */
-static int power6_marked_instr_event(u64 event)
-{
-	int pmc, psel, ptype;
-	int bit, byte, unit;
-	u32 mask;
-
-	pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-	psel = (event & PM_PMCSEL_MSK) >> 1;	/* drop edge/level bit */
-	if (pmc >= 5)
-		return 0;
-
-	bit = -1;
-	if (psel < sizeof(direct_event_is_marked)) {
-		ptype = direct_event_is_marked[psel];
-		if (pmc == 0 || !(ptype & (1 << (pmc - 1))))
-			return 0;
-		ptype >>= 4;
-		if (ptype == 0)
-			return 1;
-		if (ptype == 1)
-			bit = 0;
-		else
-			bit = ptype ^ (pmc - 1);
-	} else if ((psel & 0x48) == 0x40)
-		bit = psel & 7;
-
-	if (!(event & PM_BUSEVENT_MSK) || bit == -1)
-		return 0;
-
-	byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-	unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
-	mask = marked_bus_events[unit];
-	return (mask >> (byte * 8 + bit)) & 1;
-}
-
-/*
- * Assign PMC numbers and compute MMCR1 value for a set of events
- */
-static int p6_compute_mmcr(u64 event[], int n_ev,
-			   unsigned int hwc[], unsigned long mmcr[])
-{
-	unsigned long mmcr1 = 0;
-	unsigned long mmcra = MMCRA_SDAR_DCACHE_MISS | MMCRA_SDAR_ERAT_MISS;
-	int i;
-	unsigned int pmc, ev, b, u, s, psel;
-	unsigned int ttmset = 0;
-	unsigned int pmc_inuse = 0;
-
-	if (n_ev > 6)
-		return -1;
-	for (i = 0; i < n_ev; ++i) {
-		pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-		if (pmc) {
-			if (pmc_inuse & (1 << (pmc - 1)))
-				return -1;	/* collision! */
-			pmc_inuse |= 1 << (pmc - 1);
-		}
-	}
-	for (i = 0; i < n_ev; ++i) {
-		ev = event[i];
-		pmc = (ev >> PM_PMC_SH) & PM_PMC_MSK;
-		if (pmc) {
-			--pmc;
-		} else {
-			/* can go on any PMC; find a free one */
-			for (pmc = 0; pmc < 4; ++pmc)
-				if (!(pmc_inuse & (1 << pmc)))
-					break;
-			if (pmc >= 4)
-				return -1;
-			pmc_inuse |= 1 << pmc;
-		}
-		hwc[i] = pmc;
-		psel = ev & PM_PMCSEL_MSK;
-		if (ev & PM_BUSEVENT_MSK) {
-			/* this event uses the event bus */
-			b = (ev >> PM_BYTE_SH) & PM_BYTE_MSK;
-			u = (ev >> PM_UNIT_SH) & PM_UNIT_MSK;
-			/* check for conflict on this byte of event bus */
-			if ((ttmset & (1 << b)) && MMCR1_TTMSEL(mmcr1, b) != u)
-				return -1;
-			mmcr1 |= (unsigned long)u << MMCR1_TTMSEL_SH(b);
-			ttmset |= 1 << b;
-			if (u == 5) {
-				/* Nest events have a further mux */
-				s = (ev >> PM_SUBUNIT_SH) & PM_SUBUNIT_MSK;
-				if ((ttmset & 0x10) &&
-				    MMCR1_NESTSEL(mmcr1) != s)
-					return -1;
-				ttmset |= 0x10;
-				mmcr1 |= (unsigned long)s << MMCR1_NESTSEL_SH;
-			}
-			if (0x30 <= psel && psel <= 0x3d) {
-				/* these need the PMCx_ADDR_SEL bits */
-				if (b >= 2)
-					mmcr1 |= MMCR1_PMC1_ADDR_SEL >> pmc;
-			}
-			/* bus select values are different for PMC3/4 */
-			if (pmc >= 2 && (psel & 0x90) == 0x80)
-				psel ^= 0x20;
-		}
-		if (ev & PM_LLA) {
-			mmcr1 |= MMCR1_PMC1_LLA >> pmc;
-			if (ev & PM_LLAV)
-				mmcr1 |= MMCR1_PMC1_LLA_VALUE >> pmc;
-		}
-		if (power6_marked_instr_event(event[i]))
-			mmcra |= MMCRA_SAMPLE_ENABLE;
-		if (pmc < 4)
-			mmcr1 |= (unsigned long)psel << MMCR1_PMCSEL_SH(pmc);
-	}
-	mmcr[0] = 0;
-	if (pmc_inuse & 1)
-		mmcr[0] = MMCR0_PMC1CE;
-	if (pmc_inuse & 0xe)
-		mmcr[0] |= MMCR0_PMCjCE;
-	mmcr[1] = mmcr1;
-	mmcr[2] = mmcra;
-	return 0;
-}
-
-/*
- * Layout of constraint bits:
- *
- *	0-1	add field: number of uses of PMC1 (max 1)
- *	2-3, 4-5, 6-7, 8-9, 10-11: ditto for PMC2, 3, 4, 5, 6
- *	12-15	add field: number of uses of PMC1-4 (max 4)
- *	16-19	select field: unit on byte 0 of event bus
- *	20-23, 24-27, 28-31 ditto for bytes 1, 2, 3
- *	32-34	select field: nest (subunit) event selector
- */
-static int p6_get_constraint(u64 event, unsigned long *maskp,
-			     unsigned long *valp)
-{
-	int pmc, byte, sh, subunit;
-	unsigned long mask = 0, value = 0;
-
-	pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-	if (pmc) {
-		if (pmc > 4 && !(event == 0x500009 || event == 0x600005))
-			return -1;
-		sh = (pmc - 1) * 2;
-		mask |= 2 << sh;
-		value |= 1 << sh;
-	}
-	if (event & PM_BUSEVENT_MSK) {
-		byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-		sh = byte * 4 + (16 - PM_UNIT_SH);
-		mask |= PM_UNIT_MSKS << sh;
-		value |= (unsigned long)(event & PM_UNIT_MSKS) << sh;
-		if ((event & PM_UNIT_MSKS) == (5 << PM_UNIT_SH)) {
-			subunit = (event >> PM_SUBUNIT_SH) & PM_SUBUNIT_MSK;
-			mask  |= (unsigned long)PM_SUBUNIT_MSK << 32;
-			value |= (unsigned long)subunit << 32;
-		}
-	}
-	if (pmc <= 4) {
-		mask  |= 0x8000;	/* add field for count of PMC1-4 uses */
-		value |= 0x1000;
-	}
-	*maskp = mask;
-	*valp = value;
-	return 0;
-}
-
-static int p6_limited_pmc_event(u64 event)
-{
-	int pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-
-	return pmc == 5 || pmc == 6;
-}
-
-#define MAX_ALT	4	/* at most 4 alternatives for any event */
-
-static const unsigned int event_alternatives[][MAX_ALT] = {
-	{ 0x0130e8, 0x2000f6, 0x3000fc },	/* PM_PTEG_RELOAD_VALID */
-	{ 0x080080, 0x10000d, 0x30000c, 0x4000f0 }, /* PM_LD_MISS_L1 */
-	{ 0x080088, 0x200054, 0x3000f0 },	/* PM_ST_MISS_L1 */
-	{ 0x10000a, 0x2000f4, 0x600005 },	/* PM_RUN_CYC */
-	{ 0x10000b, 0x2000f5 },			/* PM_RUN_COUNT */
-	{ 0x10000e, 0x400010 },			/* PM_PURR */
-	{ 0x100010, 0x4000f8 },			/* PM_FLUSH */
-	{ 0x10001a, 0x200010 },			/* PM_MRK_INST_DISP */
-	{ 0x100026, 0x3000f8 },			/* PM_TB_BIT_TRANS */
-	{ 0x100054, 0x2000f0 },			/* PM_ST_FIN */
-	{ 0x100056, 0x2000fc },			/* PM_L1_ICACHE_MISS */
-	{ 0x1000f0, 0x40000a },			/* PM_INST_IMC_MATCH_CMPL */
-	{ 0x1000f8, 0x200008 },			/* PM_GCT_EMPTY_CYC */
-	{ 0x1000fc, 0x400006 },			/* PM_LSU_DERAT_MISS_CYC */
-	{ 0x20000e, 0x400007 },			/* PM_LSU_DERAT_MISS */
-	{ 0x200012, 0x300012 },			/* PM_INST_DISP */
-	{ 0x2000f2, 0x3000f2 },			/* PM_INST_DISP */
-	{ 0x2000f8, 0x300010 },			/* PM_EXT_INT */
-	{ 0x2000fe, 0x300056 },			/* PM_DATA_FROM_L2MISS */
-	{ 0x2d0030, 0x30001a },			/* PM_MRK_FPU_FIN */
-	{ 0x30000a, 0x400018 },			/* PM_MRK_INST_FIN */
-	{ 0x3000f6, 0x40000e },			/* PM_L1_DCACHE_RELOAD_VALID */
-	{ 0x3000fe, 0x400056 },			/* PM_DATA_FROM_L3MISS */
-};
-
-/*
- * This could be made more efficient with a binary search on
- * a presorted list, if necessary
- */
-static int find_alternatives_list(u64 event)
-{
-	int i, j;
-	unsigned int alt;
-
-	for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
-		if (event < event_alternatives[i][0])
-			return -1;
-		for (j = 0; j < MAX_ALT; ++j) {
-			alt = event_alternatives[i][j];
-			if (!alt || event < alt)
-				break;
-			if (event == alt)
-				return i;
-		}
-	}
-	return -1;
-}
-
-static int p6_get_alternatives(u64 event, unsigned int flags, u64 alt[])
-{
-	int i, j, nlim;
-	unsigned int psel, pmc;
-	unsigned int nalt = 1;
-	u64 aevent;
-
-	alt[0] = event;
-	nlim = p6_limited_pmc_event(event);
-
-	/* check the alternatives table */
-	i = find_alternatives_list(event);
-	if (i >= 0) {
-		/* copy out alternatives from list */
-		for (j = 0; j < MAX_ALT; ++j) {
-			aevent = event_alternatives[i][j];
-			if (!aevent)
-				break;
-			if (aevent != event)
-				alt[nalt++] = aevent;
-			nlim += p6_limited_pmc_event(aevent);
-		}
-
-	} else {
-		/* Check for alternative ways of computing sum events */
-		/* PMCSEL 0x32 counter N == PMCSEL 0x34 counter 5-N */
-		psel = event & (PM_PMCSEL_MSK & ~1);	/* ignore edge bit */
-		pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-		if (pmc && (psel == 0x32 || psel == 0x34))
-			alt[nalt++] = ((event ^ 0x6) & ~PM_PMC_MSKS) |
-				((5 - pmc) << PM_PMC_SH);
-
-		/* PMCSEL 0x38 counter N == PMCSEL 0x3a counter N+/-2 */
-		if (pmc && (psel == 0x38 || psel == 0x3a))
-			alt[nalt++] = ((event ^ 0x2) & ~PM_PMC_MSKS) |
-				((pmc > 2? pmc - 2: pmc + 2) << PM_PMC_SH);
-	}
-
-	if (flags & PPMU_ONLY_COUNT_RUN) {
-		/*
-		 * We're only counting in RUN state,
-		 * so PM_CYC is equivalent to PM_RUN_CYC,
-		 * PM_INST_CMPL === PM_RUN_INST_CMPL, PM_PURR === PM_RUN_PURR.
-		 * This doesn't include alternatives that don't provide
-		 * any extra flexibility in assigning PMCs (e.g.
-		 * 0x10000a for PM_RUN_CYC vs. 0x1e for PM_CYC).
-		 * Note that even with these additional alternatives
-		 * we never end up with more than 4 alternatives for any event.
-		 */
-		j = nalt;
-		for (i = 0; i < nalt; ++i) {
-			switch (alt[i]) {
-			case 0x1e:	/* PM_CYC */
-				alt[j++] = 0x600005;	/* PM_RUN_CYC */
-				++nlim;
-				break;
-			case 0x10000a:	/* PM_RUN_CYC */
-				alt[j++] = 0x1e;	/* PM_CYC */
-				break;
-			case 2:		/* PM_INST_CMPL */
-				alt[j++] = 0x500009;	/* PM_RUN_INST_CMPL */
-				++nlim;
-				break;
-			case 0x500009:	/* PM_RUN_INST_CMPL */
-				alt[j++] = 2;		/* PM_INST_CMPL */
-				break;
-			case 0x10000e:	/* PM_PURR */
-				alt[j++] = 0x4000f4;	/* PM_RUN_PURR */
-				break;
-			case 0x4000f4:	/* PM_RUN_PURR */
-				alt[j++] = 0x10000e;	/* PM_PURR */
-				break;
-			}
-		}
-		nalt = j;
-	}
-
-	if (!(flags & PPMU_LIMITED_PMC_OK) && nlim) {
-		/* remove the limited PMC events */
-		j = 0;
-		for (i = 0; i < nalt; ++i) {
-			if (!p6_limited_pmc_event(alt[i])) {
-				alt[j] = alt[i];
-				++j;
-			}
-		}
-		nalt = j;
-	} else if ((flags & PPMU_LIMITED_PMC_REQD) && nlim < nalt) {
-		/* remove all but the limited PMC events */
-		j = 0;
-		for (i = 0; i < nalt; ++i) {
-			if (p6_limited_pmc_event(alt[i])) {
-				alt[j] = alt[i];
-				++j;
-			}
-		}
-		nalt = j;
-	}
-
-	return nalt;
-}
-
-static void p6_disable_pmc(unsigned int pmc, unsigned long mmcr[])
-{
-	/* Set PMCxSEL to 0 to disable PMCx */
-	if (pmc <= 3)
-		mmcr[1] &= ~(0xffUL << MMCR1_PMCSEL_SH(pmc));
-}
-
-static int power6_generic_events[] = {
-	[PERF_COUNT_HW_CPU_CYCLES]		= 0x1e,
-	[PERF_COUNT_HW_INSTRUCTIONS]		= 2,
-	[PERF_COUNT_HW_CACHE_REFERENCES]	= 0x280030, /* LD_REF_L1 */
-	[PERF_COUNT_HW_CACHE_MISSES]		= 0x30000c, /* LD_MISS_L1 */
-	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= 0x410a0,  /* BR_PRED */
-	[PERF_COUNT_HW_BRANCH_MISSES]		= 0x400052, /* BR_MPRED */
-};
-
-#define C(x)	PERF_COUNT_HW_CACHE_##x
-
-/*
- * Table of generalized cache-related events.
- * 0 means not supported, -1 means nonsensical, other values
- * are event codes.
- * The "DTLB" and "ITLB" events relate to the DERAT and IERAT.
- */
-static int power6_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
-	[C(L1D)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0x280030,	0x80080		},
-		[C(OP_WRITE)] = {	0x180032,	0x80088		},
-		[C(OP_PREFETCH)] = {	0x810a4,	0		},
-	},
-	[C(L1I)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0,		0x100056 	},
-		[C(OP_WRITE)] = {	-1,		-1		},
-		[C(OP_PREFETCH)] = {	0x4008c,	0		},
-	},
-	[C(LL)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0x150730,	0x250532	},
-		[C(OP_WRITE)] = {	0x250432,	0x150432	},
-		[C(OP_PREFETCH)] = {	0x810a6,	0		},
-	},
-	[C(DTLB)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0,		0x20000e	},
-		[C(OP_WRITE)] = {	-1,		-1		},
-		[C(OP_PREFETCH)] = {	-1,		-1		},
-	},
-	[C(ITLB)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0,		0x420ce		},
-		[C(OP_WRITE)] = {	-1,		-1		},
-		[C(OP_PREFETCH)] = {	-1,		-1		},
-	},
-	[C(BPU)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0x430e6,	0x400052	},
-		[C(OP_WRITE)] = {	-1,		-1		},
-		[C(OP_PREFETCH)] = {	-1,		-1		},
-	},
-	[C(NODE)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	-1,		-1		},
-		[C(OP_WRITE)] = {	-1,		-1		},
-		[C(OP_PREFETCH)] = {	-1,		-1		},
-	},
-};
-
-static struct power_pmu power6_pmu = {
-	.name			= "POWER6",
-	.n_counter		= 6,
-	.max_alternatives	= MAX_ALT,
-	.add_fields		= 0x1555,
-	.test_adder		= 0x3000,
-	.compute_mmcr		= p6_compute_mmcr,
-	.get_constraint		= p6_get_constraint,
-	.get_alternatives	= p6_get_alternatives,
-	.disable_pmc		= p6_disable_pmc,
-	.limited_pmc_event	= p6_limited_pmc_event,
-	.flags			= PPMU_LIMITED_PMC5_6 | PPMU_ALT_SIPR,
-	.n_generic		= ARRAY_SIZE(power6_generic_events),
-	.generic_events		= power6_generic_events,
-	.cache_events		= &power6_cache_events,
-};
-
-static int __init init_power6_pmu(void)
-{
-	if (!cur_cpu_spec->oprofile_cpu_type ||
-	    strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power6"))
-		return -ENODEV;
-
-	return register_power_pmu(&power6_pmu);
-}
-
-early_initcall(init_power6_pmu);
diff --git a/arch/powerpc/kernel/ppc970-pmu.c b/arch/powerpc/kernel/ppc970-pmu.c
deleted file mode 100644
index 8c21902..0000000
--- a/arch/powerpc/kernel/ppc970-pmu.c
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * Performance counter support for PPC970-family processors.
- *
- * Copyright 2008-2009 Paul Mackerras, 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.
- */
-#include <linux/string.h>
-#include <linux/perf_event.h>
-#include <asm/reg.h>
-#include <asm/cputable.h>
-
-/*
- * Bits in event code for PPC970
- */
-#define PM_PMC_SH	12	/* PMC number (1-based) for direct events */
-#define PM_PMC_MSK	0xf
-#define PM_UNIT_SH	8	/* TTMMUX number and setting - unit select */
-#define PM_UNIT_MSK	0xf
-#define PM_SPCSEL_SH	6
-#define PM_SPCSEL_MSK	3
-#define PM_BYTE_SH	4	/* Byte number of event bus to use */
-#define PM_BYTE_MSK	3
-#define PM_PMCSEL_MSK	0xf
-
-/* Values in PM_UNIT field */
-#define PM_NONE		0
-#define PM_FPU		1
-#define PM_VPU		2
-#define PM_ISU		3
-#define PM_IFU		4
-#define PM_IDU		5
-#define PM_STS		6
-#define PM_LSU0		7
-#define PM_LSU1U	8
-#define PM_LSU1L	9
-#define PM_LASTUNIT	9
-
-/*
- * Bits in MMCR0 for PPC970
- */
-#define MMCR0_PMC1SEL_SH	8
-#define MMCR0_PMC2SEL_SH	1
-#define MMCR_PMCSEL_MSK		0x1f
-
-/*
- * Bits in MMCR1 for PPC970
- */
-#define MMCR1_TTM0SEL_SH	62
-#define MMCR1_TTM1SEL_SH	59
-#define MMCR1_TTM3SEL_SH	53
-#define MMCR1_TTMSEL_MSK	3
-#define MMCR1_TD_CP_DBG0SEL_SH	50
-#define MMCR1_TD_CP_DBG1SEL_SH	48
-#define MMCR1_TD_CP_DBG2SEL_SH	46
-#define MMCR1_TD_CP_DBG3SEL_SH	44
-#define MMCR1_PMC1_ADDER_SEL_SH	39
-#define MMCR1_PMC2_ADDER_SEL_SH	38
-#define MMCR1_PMC6_ADDER_SEL_SH	37
-#define MMCR1_PMC5_ADDER_SEL_SH	36
-#define MMCR1_PMC8_ADDER_SEL_SH	35
-#define MMCR1_PMC7_ADDER_SEL_SH	34
-#define MMCR1_PMC3_ADDER_SEL_SH	33
-#define MMCR1_PMC4_ADDER_SEL_SH	32
-#define MMCR1_PMC3SEL_SH	27
-#define MMCR1_PMC4SEL_SH	22
-#define MMCR1_PMC5SEL_SH	17
-#define MMCR1_PMC6SEL_SH	12
-#define MMCR1_PMC7SEL_SH	7
-#define MMCR1_PMC8SEL_SH	2
-
-static short mmcr1_adder_bits[8] = {
-	MMCR1_PMC1_ADDER_SEL_SH,
-	MMCR1_PMC2_ADDER_SEL_SH,
-	MMCR1_PMC3_ADDER_SEL_SH,
-	MMCR1_PMC4_ADDER_SEL_SH,
-	MMCR1_PMC5_ADDER_SEL_SH,
-	MMCR1_PMC6_ADDER_SEL_SH,
-	MMCR1_PMC7_ADDER_SEL_SH,
-	MMCR1_PMC8_ADDER_SEL_SH
-};
-
-/*
- * Layout of constraint bits:
- * 6666555555555544444444443333333333222222222211111111110000000000
- * 3210987654321098765432109876543210987654321098765432109876543210
- *               <><><>[  >[  >[  ><  ><  ><  ><  ><><><><><><><><>
- *               SPT0T1 UC  PS1 PS2 B0  B1  B2  B3 P1P2P3P4P5P6P7P8
- *
- * SP - SPCSEL constraint
- *     48-49: SPCSEL value 0x3_0000_0000_0000
- *
- * T0 - TTM0 constraint
- *     46-47: TTM0SEL value (0=FPU, 2=IFU, 3=VPU) 0xC000_0000_0000
- *
- * T1 - TTM1 constraint
- *     44-45: TTM1SEL value (0=IDU, 3=STS) 0x3000_0000_0000
- *
- * UC - unit constraint: can't have all three of FPU|IFU|VPU, ISU, IDU|STS
- *     43: UC3 error 0x0800_0000_0000
- *     42: FPU|IFU|VPU events needed 0x0400_0000_0000
- *     41: ISU events needed 0x0200_0000_0000
- *     40: IDU|STS events needed 0x0100_0000_0000
- *
- * PS1
- *     39: PS1 error 0x0080_0000_0000
- *     36-38: count of events needing PMC1/2/5/6 0x0070_0000_0000
- *
- * PS2
- *     35: PS2 error 0x0008_0000_0000
- *     32-34: count of events needing PMC3/4/7/8 0x0007_0000_0000
- *
- * B0
- *     28-31: Byte 0 event source 0xf000_0000
- *	      Encoding as for the event code
- *
- * B1, B2, B3
- *     24-27, 20-23, 16-19: Byte 1, 2, 3 event sources
- *
- * P1
- *     15: P1 error 0x8000
- *     14-15: Count of events needing PMC1
- *
- * P2..P8
- *     0-13: Count of events needing PMC2..PMC8
- */
-
-static unsigned char direct_marked_event[8] = {
-	(1<<2) | (1<<3),	/* PMC1: PM_MRK_GRP_DISP, PM_MRK_ST_CMPL */
-	(1<<3) | (1<<5),	/* PMC2: PM_THRESH_TIMEO, PM_MRK_BRU_FIN */
-	(1<<3) | (1<<5),	/* PMC3: PM_MRK_ST_CMPL_INT, PM_MRK_VMX_FIN */
-	(1<<4) | (1<<5),	/* PMC4: PM_MRK_GRP_CMPL, PM_MRK_CRU_FIN */
-	(1<<4) | (1<<5),	/* PMC5: PM_GRP_MRK, PM_MRK_GRP_TIMEO */
-	(1<<3) | (1<<4) | (1<<5),
-		/* PMC6: PM_MRK_ST_STS, PM_MRK_FXU_FIN, PM_MRK_GRP_ISSUED */
-	(1<<4) | (1<<5),	/* PMC7: PM_MRK_FPU_FIN, PM_MRK_INST_FIN */
-	(1<<4)			/* PMC8: PM_MRK_LSU_FIN */
-};
-
-/*
- * Returns 1 if event counts things relating to marked instructions
- * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
- */
-static int p970_marked_instr_event(u64 event)
-{
-	int pmc, psel, unit, byte, bit;
-	unsigned int mask;
-
-	pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-	psel = event & PM_PMCSEL_MSK;
-	if (pmc) {
-		if (direct_marked_event[pmc - 1] & (1 << psel))
-			return 1;
-		if (psel == 0)		/* add events */
-			bit = (pmc <= 4)? pmc - 1: 8 - pmc;
-		else if (psel == 7 || psel == 13)	/* decode events */
-			bit = 4;
-		else
-			return 0;
-	} else
-		bit = psel;
-
-	byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-	unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
-	mask = 0;
-	switch (unit) {
-	case PM_VPU:
-		mask = 0x4c;		/* byte 0 bits 2,3,6 */
-		break;
-	case PM_LSU0:
-		/* byte 2 bits 0,2,3,4,6; all of byte 1 */
-		mask = 0x085dff00;
-		break;
-	case PM_LSU1L:
-		mask = 0x50 << 24;	/* byte 3 bits 4,6 */
-		break;
-	}
-	return (mask >> (byte * 8 + bit)) & 1;
-}
-
-/* Masks and values for using events from the various units */
-static unsigned long unit_cons[PM_LASTUNIT+1][2] = {
-	[PM_FPU] =   { 0xc80000000000ull, 0x040000000000ull },
-	[PM_VPU] =   { 0xc80000000000ull, 0xc40000000000ull },
-	[PM_ISU] =   { 0x080000000000ull, 0x020000000000ull },
-	[PM_IFU] =   { 0xc80000000000ull, 0x840000000000ull },
-	[PM_IDU] =   { 0x380000000000ull, 0x010000000000ull },
-	[PM_STS] =   { 0x380000000000ull, 0x310000000000ull },
-};
-
-static int p970_get_constraint(u64 event, unsigned long *maskp,
-			       unsigned long *valp)
-{
-	int pmc, byte, unit, sh, spcsel;
-	unsigned long mask = 0, value = 0;
-	int grp = -1;
-
-	pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-	if (pmc) {
-		if (pmc > 8)
-			return -1;
-		sh = (pmc - 1) * 2;
-		mask |= 2 << sh;
-		value |= 1 << sh;
-		grp = ((pmc - 1) >> 1) & 1;
-	}
-	unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
-	if (unit) {
-		if (unit > PM_LASTUNIT)
-			return -1;
-		mask |= unit_cons[unit][0];
-		value |= unit_cons[unit][1];
-		byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-		/*
-		 * Bus events on bytes 0 and 2 can be counted
-		 * on PMC1/2/5/6; bytes 1 and 3 on PMC3/4/7/8.
-		 */
-		if (!pmc)
-			grp = byte & 1;
-		/* Set byte lane select field */
-		mask  |= 0xfULL << (28 - 4 * byte);
-		value |= (unsigned long)unit << (28 - 4 * byte);
-	}
-	if (grp == 0) {
-		/* increment PMC1/2/5/6 field */
-		mask  |= 0x8000000000ull;
-		value |= 0x1000000000ull;
-	} else if (grp == 1) {
-		/* increment PMC3/4/7/8 field */
-		mask  |= 0x800000000ull;
-		value |= 0x100000000ull;
-	}
-	spcsel = (event >> PM_SPCSEL_SH) & PM_SPCSEL_MSK;
-	if (spcsel) {
-		mask  |= 3ull << 48;
-		value |= (unsigned long)spcsel << 48;
-	}
-	*maskp = mask;
-	*valp = value;
-	return 0;
-}
-
-static int p970_get_alternatives(u64 event, unsigned int flags, u64 alt[])
-{
-	alt[0] = event;
-
-	/* 2 alternatives for LSU empty */
-	if (event == 0x2002 || event == 0x3002) {
-		alt[1] = event ^ 0x1000;
-		return 2;
-	}
-		
-	return 1;
-}
-
-static int p970_compute_mmcr(u64 event[], int n_ev,
-			     unsigned int hwc[], unsigned long mmcr[])
-{
-	unsigned long mmcr0 = 0, mmcr1 = 0, mmcra = 0;
-	unsigned int pmc, unit, byte, psel;
-	unsigned int ttm, grp;
-	unsigned int pmc_inuse = 0;
-	unsigned int pmc_grp_use[2];
-	unsigned char busbyte[4];
-	unsigned char unituse[16];
-	unsigned char unitmap[] = { 0, 0<<3, 3<<3, 1<<3, 2<<3, 0|4, 3|4 };
-	unsigned char ttmuse[2];
-	unsigned char pmcsel[8];
-	int i;
-	int spcsel;
-
-	if (n_ev > 8)
-		return -1;
-
-	/* First pass to count resource use */
-	pmc_grp_use[0] = pmc_grp_use[1] = 0;
-	memset(busbyte, 0, sizeof(busbyte));
-	memset(unituse, 0, sizeof(unituse));
-	for (i = 0; i < n_ev; ++i) {
-		pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-		if (pmc) {
-			if (pmc_inuse & (1 << (pmc - 1)))
-				return -1;
-			pmc_inuse |= 1 << (pmc - 1);
-			/* count 1/2/5/6 vs 3/4/7/8 use */
-			++pmc_grp_use[((pmc - 1) >> 1) & 1];
-		}
-		unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
-		byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
-		if (unit) {
-			if (unit > PM_LASTUNIT)
-				return -1;
-			if (!pmc)
-				++pmc_grp_use[byte & 1];
-			if (busbyte[byte] && busbyte[byte] != unit)
-				return -1;
-			busbyte[byte] = unit;
-			unituse[unit] = 1;
-		}
-	}
-	if (pmc_grp_use[0] > 4 || pmc_grp_use[1] > 4)
-		return -1;
-
-	/*
-	 * Assign resources and set multiplexer selects.
-	 *
-	 * PM_ISU can go either on TTM0 or TTM1, but that's the only
-	 * choice we have to deal with.
-	 */
-	if (unituse[PM_ISU] &
-	    (unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_VPU]))
-		unitmap[PM_ISU] = 2 | 4;	/* move ISU to TTM1 */
-	/* Set TTM[01]SEL fields. */
-	ttmuse[0] = ttmuse[1] = 0;
-	for (i = PM_FPU; i <= PM_STS; ++i) {
-		if (!unituse[i])
-			continue;
-		ttm = unitmap[i];
-		++ttmuse[(ttm >> 2) & 1];
-		mmcr1 |= (unsigned long)(ttm & ~4) << MMCR1_TTM1SEL_SH;
-	}
-	/* Check only one unit per TTMx */
-	if (ttmuse[0] > 1 || ttmuse[1] > 1)
-		return -1;
-
-	/* Set byte lane select fields and TTM3SEL. */
-	for (byte = 0; byte < 4; ++byte) {
-		unit = busbyte[byte];
-		if (!unit)
-			continue;
-		if (unit <= PM_STS)
-			ttm = (unitmap[unit] >> 2) & 1;
-		else if (unit == PM_LSU0)
-			ttm = 2;
-		else {
-			ttm = 3;
-			if (unit == PM_LSU1L && byte >= 2)
-				mmcr1 |= 1ull << (MMCR1_TTM3SEL_SH + 3 - byte);
-		}
-		mmcr1 |= (unsigned long)ttm
-			<< (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
-	}
-
-	/* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
-	memset(pmcsel, 0x8, sizeof(pmcsel));	/* 8 means don't count */
-	for (i = 0; i < n_ev; ++i) {
-		pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-		unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
-		byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
-		psel = event[i] & PM_PMCSEL_MSK;
-		if (!pmc) {
-			/* Bus event or any-PMC direct event */
-			if (unit)
-				psel |= 0x10 | ((byte & 2) << 2);
-			else
-				psel |= 8;
-			for (pmc = 0; pmc < 8; ++pmc) {
-				if (pmc_inuse & (1 << pmc))
-					continue;
-				grp = (pmc >> 1) & 1;
-				if (unit) {
-					if (grp == (byte & 1))
-						break;
-				} else if (pmc_grp_use[grp] < 4) {
-					++pmc_grp_use[grp];
-					break;
-				}
-			}
-			pmc_inuse |= 1 << pmc;
-		} else {
-			/* Direct event */
-			--pmc;
-			if (psel == 0 && (byte & 2))
-				/* add events on higher-numbered bus */
-				mmcr1 |= 1ull << mmcr1_adder_bits[pmc];
-		}
-		pmcsel[pmc] = psel;
-		hwc[i] = pmc;
-		spcsel = (event[i] >> PM_SPCSEL_SH) & PM_SPCSEL_MSK;
-		mmcr1 |= spcsel;
-		if (p970_marked_instr_event(event[i]))
-			mmcra |= MMCRA_SAMPLE_ENABLE;
-	}
-	for (pmc = 0; pmc < 2; ++pmc)
-		mmcr0 |= pmcsel[pmc] << (MMCR0_PMC1SEL_SH - 7 * pmc);
-	for (; pmc < 8; ++pmc)
-		mmcr1 |= (unsigned long)pmcsel[pmc]
-			<< (MMCR1_PMC3SEL_SH - 5 * (pmc - 2));
-	if (pmc_inuse & 1)
-		mmcr0 |= MMCR0_PMC1CE;
-	if (pmc_inuse & 0xfe)
-		mmcr0 |= MMCR0_PMCjCE;
-
-	mmcra |= 0x2000;	/* mark only one IOP per PPC instruction */
-
-	/* Return MMCRx values */
-	mmcr[0] = mmcr0;
-	mmcr[1] = mmcr1;
-	mmcr[2] = mmcra;
-	return 0;
-}
-
-static void p970_disable_pmc(unsigned int pmc, unsigned long mmcr[])
-{
-	int shift, i;
-
-	if (pmc <= 1) {
-		shift = MMCR0_PMC1SEL_SH - 7 * pmc;
-		i = 0;
-	} else {
-		shift = MMCR1_PMC3SEL_SH - 5 * (pmc - 2);
-		i = 1;
-	}
-	/*
-	 * Setting the PMCxSEL field to 0x08 disables PMC x.
-	 */
-	mmcr[i] = (mmcr[i] & ~(0x1fUL << shift)) | (0x08UL << shift);
-}
-
-static int ppc970_generic_events[] = {
-	[PERF_COUNT_HW_CPU_CYCLES]		= 7,
-	[PERF_COUNT_HW_INSTRUCTIONS]		= 1,
-	[PERF_COUNT_HW_CACHE_REFERENCES]	= 0x8810, /* PM_LD_REF_L1 */
-	[PERF_COUNT_HW_CACHE_MISSES]		= 0x3810, /* PM_LD_MISS_L1 */
-	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= 0x431,  /* PM_BR_ISSUED */
-	[PERF_COUNT_HW_BRANCH_MISSES] 		= 0x327,  /* PM_GRP_BR_MPRED */
-};
-
-#define C(x)	PERF_COUNT_HW_CACHE_##x
-
-/*
- * Table of generalized cache-related events.
- * 0 means not supported, -1 means nonsensical, other values
- * are event codes.
- */
-static int ppc970_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
-	[C(L1D)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0x8810,		0x3810	},
-		[C(OP_WRITE)] = {	0x7810,		0x813	},
-		[C(OP_PREFETCH)] = {	0x731,		0	},
-	},
-	[C(L1I)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0,		0	},
-		[C(OP_WRITE)] = {	-1,		-1	},
-		[C(OP_PREFETCH)] = {	0,		0	},
-	},
-	[C(LL)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0,		0	},
-		[C(OP_WRITE)] = {	0,		0	},
-		[C(OP_PREFETCH)] = {	0x733,		0	},
-	},
-	[C(DTLB)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0,		0x704	},
-		[C(OP_WRITE)] = {	-1,		-1	},
-		[C(OP_PREFETCH)] = {	-1,		-1	},
-	},
-	[C(ITLB)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0,		0x700	},
-		[C(OP_WRITE)] = {	-1,		-1	},
-		[C(OP_PREFETCH)] = {	-1,		-1	},
-	},
-	[C(BPU)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	0x431,		0x327	},
-		[C(OP_WRITE)] = {	-1,		-1	},
-		[C(OP_PREFETCH)] = {	-1,		-1	},
-	},
-	[C(NODE)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
-		[C(OP_READ)] = {	-1,		-1	},
-		[C(OP_WRITE)] = {	-1,		-1	},
-		[C(OP_PREFETCH)] = {	-1,		-1	},
-	},
-};
-
-static struct power_pmu ppc970_pmu = {
-	.name			= "PPC970/FX/MP",
-	.n_counter		= 8,
-	.max_alternatives	= 2,
-	.add_fields		= 0x001100005555ull,
-	.test_adder		= 0x013300000000ull,
-	.compute_mmcr		= p970_compute_mmcr,
-	.get_constraint		= p970_get_constraint,
-	.get_alternatives	= p970_get_alternatives,
-	.disable_pmc		= p970_disable_pmc,
-	.n_generic		= ARRAY_SIZE(ppc970_generic_events),
-	.generic_events		= ppc970_generic_events,
-	.cache_events		= &ppc970_cache_events,
-};
-
-static int __init init_ppc970_pmu(void)
-{
-	if (!cur_cpu_spec->oprofile_cpu_type ||
-	    (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970")
-	     && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970MP")))
-		return -ENODEV;
-
-	return register_power_pmu(&ppc970_pmu);
-}
-
-early_initcall(init_ppc970_pmu);
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index d3114a7..786a270 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -26,7 +26,6 @@
 #include <linux/cuda.h>
 #include <linux/pmu.h>
 #include <asm/prom.h>
-#include <asm/system.h>
 #include <asm/pci-bridge.h>
 #include <asm/irq.h>
 #include <asm/pmac_feature.h>
@@ -43,6 +42,7 @@
 #include <asm/signal.h>
 #include <asm/dcr.h>
 #include <asm/ftrace.h>
+#include <asm/switch_to.h>
 
 #ifdef CONFIG_PPC32
 extern void transfer_to_handler(void);
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index d817ab0..f88698c 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -41,14 +41,16 @@
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/mmu.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/time.h>
+#include <asm/runlatch.h>
 #include <asm/syscalls.h>
+#include <asm/switch_to.h>
+#include <asm/debug.h>
 #ifdef CONFIG_PPC64
 #include <asm/firmware.h>
 #endif
@@ -647,6 +649,9 @@
 	printk("MSR: "REG" ", regs->msr);
 	printbits(regs->msr, msr_bits);
 	printk("  CR: %08lx  XER: %08lx\n", regs->ccr, regs->xer);
+#ifdef CONFIG_PPC64
+	printk("SOFTE: %ld\n", regs->softe);
+#endif
 	trap = TRAP(regs);
 	if ((regs->trap != 0xc00) && cpu_has_feature(CPU_FTR_CFAR))
 		printk("CFAR: "REG"\n", regs->orig_gpr3);
@@ -1220,34 +1225,32 @@
 EXPORT_SYMBOL(dump_stack);
 
 #ifdef CONFIG_PPC64
-void ppc64_runlatch_on(void)
+/* Called with hard IRQs off */
+void __ppc64_runlatch_on(void)
 {
+	struct thread_info *ti = current_thread_info();
 	unsigned long ctrl;
 
-	if (cpu_has_feature(CPU_FTR_CTRL) && !test_thread_flag(TIF_RUNLATCH)) {
-		HMT_medium();
+	ctrl = mfspr(SPRN_CTRLF);
+	ctrl |= CTRL_RUNLATCH;
+	mtspr(SPRN_CTRLT, ctrl);
 
-		ctrl = mfspr(SPRN_CTRLF);
-		ctrl |= CTRL_RUNLATCH;
-		mtspr(SPRN_CTRLT, ctrl);
-
-		set_thread_flag(TIF_RUNLATCH);
-	}
+	ti->local_flags |= TLF_RUNLATCH;
 }
 
+/* Called with hard IRQs off */
 void __ppc64_runlatch_off(void)
 {
+	struct thread_info *ti = current_thread_info();
 	unsigned long ctrl;
 
-	HMT_medium();
-
-	clear_thread_flag(TIF_RUNLATCH);
+	ti->local_flags &= ~TLF_RUNLATCH;
 
 	ctrl = mfspr(SPRN_CTRLF);
 	ctrl &= ~CTRL_RUNLATCH;
 	mtspr(SPRN_CTRLT, ctrl);
 }
-#endif
+#endif /* CONFIG_PPC64 */
 
 #if THREAD_SHIFT < PAGE_SHIFT
 
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index abe405d..f191bf0 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -41,7 +41,6 @@
 #include <asm/io.h>
 #include <asm/kdump.h>
 #include <asm/smp.h>
-#include <asm/system.h>
 #include <asm/mmu.h>
 #include <asm/paca.h>
 #include <asm/pgtable.h>
@@ -52,9 +51,9 @@
 #include <asm/machdep.h>
 #include <asm/pSeries_reconfig.h>
 #include <asm/pci-bridge.h>
-#include <asm/phyp_dump.h>
 #include <asm/kexec.h>
 #include <asm/opal.h>
+#include <asm/fadump.h>
 
 #include <mm/mmu_decl.h>
 
@@ -615,86 +614,6 @@
 	}
 }
 
-#ifdef CONFIG_PHYP_DUMP
-/**
- * phyp_dump_calculate_reserve_size() - reserve variable boot area 5% or arg
- *
- * Function to find the largest size we need to reserve
- * during early boot process.
- *
- * It either looks for boot param and returns that OR
- * returns larger of 256 or 5% rounded down to multiples of 256MB.
- *
- */
-static inline unsigned long phyp_dump_calculate_reserve_size(void)
-{
-	unsigned long tmp;
-
-	if (phyp_dump_info->reserve_bootvar)
-		return phyp_dump_info->reserve_bootvar;
-
-	/* divide by 20 to get 5% of value */
-	tmp = memblock_end_of_DRAM();
-	do_div(tmp, 20);
-
-	/* round it down in multiples of 256 */
-	tmp = tmp & ~0x0FFFFFFFUL;
-
-	return (tmp > PHYP_DUMP_RMR_END ? tmp : PHYP_DUMP_RMR_END);
-}
-
-/**
- * phyp_dump_reserve_mem() - reserve all not-yet-dumped mmemory
- *
- * This routine may reserve memory regions in the kernel only
- * if the system is supported and a dump was taken in last
- * boot instance or if the hardware is supported and the
- * scratch area needs to be setup. In other instances it returns
- * without reserving anything. The memory in case of dump being
- * active is freed when the dump is collected (by userland tools).
- */
-static void __init phyp_dump_reserve_mem(void)
-{
-	unsigned long base, size;
-	unsigned long variable_reserve_size;
-
-	if (!phyp_dump_info->phyp_dump_configured) {
-		printk(KERN_ERR "Phyp-dump not supported on this hardware\n");
-		return;
-	}
-
-	if (!phyp_dump_info->phyp_dump_at_boot) {
-		printk(KERN_INFO "Phyp-dump disabled at boot time\n");
-		return;
-	}
-
-	variable_reserve_size = phyp_dump_calculate_reserve_size();
-
-	if (phyp_dump_info->phyp_dump_is_active) {
-		/* Reserve *everything* above RMR.Area freed by userland tools*/
-		base = variable_reserve_size;
-		size = memblock_end_of_DRAM() - base;
-
-		/* XXX crashed_ram_end is wrong, since it may be beyond
-		 * the memory_limit, it will need to be adjusted. */
-		memblock_reserve(base, size);
-
-		phyp_dump_info->init_reserve_start = base;
-		phyp_dump_info->init_reserve_size = size;
-	} else {
-		size = phyp_dump_info->cpu_state_size +
-			phyp_dump_info->hpte_region_size +
-			variable_reserve_size;
-		base = memblock_end_of_DRAM() - size;
-		memblock_reserve(base, size);
-		phyp_dump_info->init_reserve_start = base;
-		phyp_dump_info->init_reserve_size = size;
-	}
-}
-#else
-static inline void __init phyp_dump_reserve_mem(void) {}
-#endif /* CONFIG_PHYP_DUMP  && CONFIG_PPC_RTAS */
-
 void __init early_init_devtree(void *params)
 {
 	phys_addr_t limit;
@@ -714,9 +633,9 @@
 	of_scan_flat_dt(early_init_dt_scan_opal, NULL);
 #endif
 
-#ifdef CONFIG_PHYP_DUMP
-	/* scan tree to see if dump occurred during last boot */
-	of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL);
+#ifdef CONFIG_FA_DUMP
+	/* scan tree to see if dump is active during last boot */
+	of_scan_flat_dt(early_init_dt_scan_fw_dump, NULL);
 #endif
 
 	/* Pre-initialize the cmd_line with the content of boot_commmand_line,
@@ -750,9 +669,15 @@
 	if (PHYSICAL_START > MEMORY_START)
 		memblock_reserve(MEMORY_START, 0x8000);
 	reserve_kdump_trampoline();
-	reserve_crashkernel();
+#ifdef CONFIG_FA_DUMP
+	/*
+	 * If we fail to reserve memory for firmware-assisted dump then
+	 * fallback to kexec based kdump.
+	 */
+	if (fadump_reserve_mem() == 0)
+#endif
+		reserve_crashkernel();
 	early_reserve_mem();
-	phyp_dump_reserve_mem();
 
 	/*
 	 * Ensure that total memory size is page-aligned, because otherwise
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index eca626e..9986027 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -35,7 +35,6 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/smp.h>
-#include <asm/system.h>
 #include <asm/mmu.h>
 #include <asm/pgtable.h>
 #include <asm/pci.h>
@@ -48,14 +47,6 @@
 #include <linux/linux_logo.h>
 
 /*
- * Properties whose value is longer than this get excluded from our
- * copy of the device tree. This value does need to be big enough to
- * ensure that we don't lose things like the interrupt-map property
- * on a PCI-PCI bridge.
- */
-#define MAX_PROPERTY_LENGTH	(1UL * 1024 * 1024)
-
-/*
  * Eventually bump that one up
  */
 #define DEVTREE_CHUNK_SIZE	0x100000
@@ -455,7 +446,7 @@
 	if (RELOC(of_platform) == PLATFORM_POWERMAC)
 		asm("trap\n");
 
-	/* ToDo: should put up an SRC here on p/iSeries */
+	/* ToDo: should put up an SRC here on pSeries */
 	call_prom("exit", 0, 0);
 
 	for (;;)			/* should never get here */
@@ -2273,13 +2264,6 @@
 		/* sanity checks */
 		if (l == PROM_ERROR)
 			continue;
-		if (l > MAX_PROPERTY_LENGTH) {
-			prom_printf("WARNING: ignoring large property ");
-			/* It seems OF doesn't null-terminate the path :-( */
-			prom_printf("[%s] ", path);
-			prom_printf("%s length 0x%x\n", RELOC(pname), l);
-			continue;
-		}
 
 		/* push property head */
 		dt_push_token(OF_DT_PROP, mem_start, mem_end);
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 5b43325..8d8e028 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -36,7 +36,7 @@
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
+#include <asm/switch_to.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/syscalls.h>
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 69c4be9..469349d 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -32,7 +32,7 @@
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
+#include <asm/switch_to.h>
 
 /*
  * does not yet catch signals sent when the child dies.
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 9f843cd..fcec382 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -33,7 +33,6 @@
 #include <asm/firmware.h>
 #include <asm/page.h>
 #include <asm/param.h>
-#include <asm/system.h>
 #include <asm/delay.h>
 #include <asm/uaccess.h>
 #include <asm/udbg.h>
@@ -868,6 +867,40 @@
 }
 #endif
 
+/**
+ * Find a specific pseries error log in an RTAS extended event log.
+ * @log: RTAS error/event log
+ * @section_id: two character section identifier
+ *
+ * Returns a pointer to the specified errorlog or NULL if not found.
+ */
+struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
+					      uint16_t section_id)
+{
+	struct rtas_ext_event_log_v6 *ext_log =
+		(struct rtas_ext_event_log_v6 *)log->buffer;
+	struct pseries_errorlog *sect;
+	unsigned char *p, *log_end;
+
+	/* Check that we understand the format */
+	if (log->extended_log_length < sizeof(struct rtas_ext_event_log_v6) ||
+	    ext_log->log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG ||
+	    ext_log->company_id != RTAS_V6EXT_COMPANY_ID_IBM)
+		return NULL;
+
+	log_end = log->buffer + log->extended_log_length;
+	p = ext_log->vendor_log;
+
+	while (p < log_end) {
+		sect = (struct pseries_errorlog *)p;
+		if (sect->id == section_id)
+			return sect;
+		p += sect->length;
+	}
+
+	return NULL;
+}
+
 asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
 {
 	struct rtas_args args;
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
index 6cd8f01..179af90 100644
--- a/arch/powerpc/kernel/rtas_pci.c
+++ b/arch/powerpc/kernel/rtas_pci.c
@@ -275,8 +275,11 @@
 	of_node_put(root);
 	pci_devs_phb_init();
 
+	/* Create EEH devices for all PHBs */
+	eeh_dev_phb_init();
+
 	/*
-	 * pci_probe_only and pci_assign_all_buses can be set via properties
+	 * PCI_PROBE_ONLY and PCI_REASSIGN_ALL_BUS can be set via properties
 	 * in chosen.
 	 */
 	if (of_chosen) {
@@ -284,8 +287,12 @@
 
 		prop = of_get_property(of_chosen,
 				"linux,pci-probe-only", NULL);
-		if (prop)
-			pci_probe_only = *prop;
+		if (prop) {
+			if (*prop)
+				pci_add_flags(PCI_PROBE_ONLY);
+			else
+				pci_clear_flags(PCI_PROBE_ONLY);
+		}
 
 #ifdef CONFIG_PPC32 /* Will be made generic soon */
 		prop = of_get_property(of_chosen,
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 77bb77d..afd4f05 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -51,7 +51,6 @@
 #include <asm/btext.h>
 #include <asm/nvram.h>
 #include <asm/setup.h>
-#include <asm/system.h>
 #include <asm/rtas.h>
 #include <asm/iommu.h>
 #include <asm/serial.h>
@@ -61,6 +60,7 @@
 #include <asm/xmon.h>
 #include <asm/cputhreads.h>
 #include <mm/mmu_decl.h>
+#include <asm/fadump.h>
 
 #include "setup.h"
 
@@ -109,6 +109,14 @@
 /* also used by kexec */
 void machine_shutdown(void)
 {
+#ifdef CONFIG_FA_DUMP
+	/*
+	 * if fadump is active, cleanup the fadump registration before we
+	 * shutdown.
+	 */
+	fadump_cleanup();
+#endif
+
 	if (ppc_md.machine_shutdown)
 		ppc_md.machine_shutdown();
 }
@@ -639,6 +647,11 @@
 static int ppc_panic_event(struct notifier_block *this,
                              unsigned long event, void *ptr)
 {
+	/*
+	 * If firmware-assisted dump has been registered then trigger
+	 * firmware-assisted dump and let firmware handle everything else.
+	 */
+	crash_fadump(NULL, ptr);
 	ppc_md.panic(ptr);  /* May not return */
 	return NOTIFY_DONE;
 }
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index ac76108..9825f29 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -30,7 +30,6 @@
 #include <asm/btext.h>
 #include <asm/machdep.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/pmac_feature.h>
 #include <asm/sections.h>
 #include <asm/nvram.h>
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 4cb8f1e..389bd4f 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -52,7 +52,6 @@
 #include <asm/btext.h>
 #include <asm/nvram.h>
 #include <asm/setup.h>
-#include <asm/system.h>
 #include <asm/rtas.h>
 #include <asm/iommu.h>
 #include <asm/serial.h>
@@ -598,7 +597,7 @@
 	/* Initialize the MMU context management stuff */
 	mmu_context_init();
 
-	kvm_rma_init();
+	kvm_linear_init();
 
 	ppc64_boot_msg(0x15, "Setup Done");
 }
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index ac6e437..651c596 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -15,6 +15,7 @@
 #include <asm/hw_breakpoint.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
+#include <asm/debug.h>
 
 #include "signal.h"
 
@@ -57,10 +58,7 @@
 void restore_sigmask(sigset_t *set)
 {
 	sigdelsetmask(set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = *set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(set);
 }
 
 static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka,
@@ -169,13 +167,7 @@
 
 	regs->trap = 0;
 	if (ret) {
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked, &current->blocked,
-			  &ka.sa.sa_mask);
-		if (!(ka.sa.sa_flags & SA_NODEFER))
-			sigaddset(&current->blocked, signr);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
+		block_sigmask(&ka, signr);
 
 		/*
 		 * A signal was successfully delivered; the saved sigmask is in
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 836a5a1..45eb998 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -43,6 +43,7 @@
 #include <asm/syscalls.h>
 #include <asm/sigcontext.h>
 #include <asm/vdso.h>
+#include <asm/switch_to.h>
 #ifdef CONFIG_PPC64
 #include "ppc32.h"
 #include <asm/unistd.h>
@@ -242,12 +243,13 @@
  */
 long sys_sigsuspend(old_sigset_t mask)
 {
-	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sighand->siglock);
+	sigset_t blocked;
+
 	current->saved_sigmask = current->blocked;
-	siginitset(&current->blocked, mask);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+
+	mask &= _BLOCKABLE;
+	siginitset(&blocked, mask);
+	set_current_blocked(&blocked);
 
  	current->state = TASK_INTERRUPTIBLE;
  	schedule();
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index a50b5ec..2692efd 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -33,6 +33,7 @@
 #include <asm/cacheflush.h>
 #include <asm/syscalls.h>
 #include <asm/vdso.h>
+#include <asm/switch_to.h>
 
 #include "signal.h"
 
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 46695fe..d9f9441 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -43,12 +43,12 @@
 #include <asm/machdep.h>
 #include <asm/cputhreads.h>
 #include <asm/cputable.h>
-#include <asm/system.h>
 #include <asm/mpic.h>
 #include <asm/vdso_datapage.h>
 #ifdef CONFIG_PPC64
 #include <asm/paca.h>
 #endif
+#include <asm/debug.h>
 
 #ifdef DEBUG
 #include <asm/udbg.h>
diff --git a/arch/powerpc/kernel/softemu8xx.c b/arch/powerpc/kernel/softemu8xx.c
index af0e829..29b2f81 100644
--- a/arch/powerpc/kernel/softemu8xx.c
+++ b/arch/powerpc/kernel/softemu8xx.c
@@ -26,7 +26,6 @@
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/io.h>
 
 /* Eventually we may need a look-up table, but this works for now.
diff --git a/arch/powerpc/kernel/swsusp.c b/arch/powerpc/kernel/swsusp.c
index 641f9ad..eae33e1 100644
--- a/arch/powerpc/kernel/swsusp.c
+++ b/arch/powerpc/kernel/swsusp.c
@@ -10,9 +10,9 @@
  */
 
 #include <linux/sched.h>
-#include <asm/system.h>
 #include <asm/current.h>
 #include <asm/mmu_context.h>
+#include <asm/switch_to.h>
 
 void save_processor_state(void)
 {
diff --git a/arch/powerpc/kernel/swsusp_64.c b/arch/powerpc/kernel/swsusp_64.c
index 168e884..0e899e4 100644
--- a/arch/powerpc/kernel/swsusp_64.c
+++ b/arch/powerpc/kernel/swsusp_64.c
@@ -6,7 +6,6 @@
  * GPLv2
  */
 
-#include <asm/system.h>
 #include <asm/iommu.h>
 #include <linux/irq.h>
 #include <linux/sched.h>
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index 4e5bf1e..81c5706 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -50,6 +50,7 @@
 #include <asm/mmu_context.h>
 #include <asm/ppc-pci.h>
 #include <asm/syscalls.h>
+#include <asm/switch_to.h>
 
 
 asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp,
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index 883e74c..3529446 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -12,13 +12,11 @@
 #include <asm/current.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
-#include <asm/firmware.h>
 #include <asm/hvcall.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/smp.h>
 #include <asm/pmc.h>
-#include <asm/system.h>
 
 #include "cacheinfo.h"
 
@@ -341,8 +339,7 @@
 	int i, nattrs;
 
 #ifdef CONFIG_PPC64
-	if (!firmware_has_feature(FW_FEATURE_ISERIES) &&
-			cpu_has_feature(CPU_FTR_SMT))
+	if (cpu_has_feature(CPU_FTR_SMT))
 		device_create_file(s, &dev_attr_smt_snooze_delay);
 #endif
 
@@ -414,8 +411,7 @@
 	BUG_ON(!c->hotpluggable);
 
 #ifdef CONFIG_PPC64
-	if (!firmware_has_feature(FW_FEATURE_ISERIES) &&
-			cpu_has_feature(CPU_FTR_SMT))
+	if (cpu_has_feature(CPU_FTR_SMT))
 		device_remove_file(s, &dev_attr_smt_snooze_delay);
 #endif
 
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 567dd7c..2c42cd7 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -17,8 +17,7 @@
  *
  * TODO (not necessarily in this file):
  * - improve precision and reproducibility of timebase frequency
- * measurement at boot time. (for iSeries, we calibrate the timebase
- * against the Titan chip's clock.)
+ * measurement at boot time.
  * - for astronomical applications: add a new function to get
  * non ambiguous timestamps even around leap seconds. This needs
  * a new timestamp format and a good name.
@@ -70,10 +69,6 @@
 #include <asm/vdso_datapage.h>
 #include <asm/firmware.h>
 #include <asm/cputime.h>
-#ifdef CONFIG_PPC_ISERIES
-#include <asm/iseries/it_lp_queue.h>
-#include <asm/iseries/hv_call_xm.h>
-#endif
 
 /* powerpc clocksource/clockevent code */
 
@@ -117,14 +112,6 @@
 DEFINE_PER_CPU(u64, decrementers_next_tb);
 static DEFINE_PER_CPU(struct clock_event_device, decrementers);
 
-#ifdef CONFIG_PPC_ISERIES
-static unsigned long __initdata iSeries_recal_titan;
-static signed long __initdata iSeries_recal_tb;
-
-/* Forward declaration is only needed for iSereis compiles */
-static void __init clocksource_init(void);
-#endif
-
 #define XSEC_PER_SEC (1024*1024)
 
 #ifdef CONFIG_PPC64
@@ -259,7 +246,6 @@
 	u64 sst, ust;
 
 	u8 save_soft_enabled = local_paca->soft_enabled;
-	u8 save_hard_enabled = local_paca->hard_enabled;
 
 	/* We are called early in the exception entry, before
 	 * soft/hard_enabled are sync'ed to the expected state
@@ -268,7 +254,6 @@
 	 * complain
 	 */
 	local_paca->soft_enabled = 0;
-	local_paca->hard_enabled = 0;
 
 	sst = scan_dispatch_log(local_paca->starttime_user);
 	ust = scan_dispatch_log(local_paca->starttime);
@@ -277,7 +262,6 @@
 	local_paca->stolen_time += ust + sst;
 
 	local_paca->soft_enabled = save_soft_enabled;
-	local_paca->hard_enabled = save_hard_enabled;
 }
 
 static inline u64 calculate_stolen_time(u64 stop_tb)
@@ -426,74 +410,6 @@
 EXPORT_SYMBOL(profile_pc);
 #endif
 
-#ifdef CONFIG_PPC_ISERIES
-
-/* 
- * This function recalibrates the timebase based on the 49-bit time-of-day
- * value in the Titan chip.  The Titan is much more accurate than the value
- * returned by the service processor for the timebase frequency.
- */
-
-static int __init iSeries_tb_recal(void)
-{
-	unsigned long titan, tb;
-
-	/* Make sure we only run on iSeries */
-	if (!firmware_has_feature(FW_FEATURE_ISERIES))
-		return -ENODEV;
-
-	tb = get_tb();
-	titan = HvCallXm_loadTod();
-	if ( iSeries_recal_titan ) {
-		unsigned long tb_ticks = tb - iSeries_recal_tb;
-		unsigned long titan_usec = (titan - iSeries_recal_titan) >> 12;
-		unsigned long new_tb_ticks_per_sec   = (tb_ticks * USEC_PER_SEC)/titan_usec;
-		unsigned long new_tb_ticks_per_jiffy =
-			DIV_ROUND_CLOSEST(new_tb_ticks_per_sec, HZ);
-		long tick_diff = new_tb_ticks_per_jiffy - tb_ticks_per_jiffy;
-		char sign = '+';		
-		/* make sure tb_ticks_per_sec and tb_ticks_per_jiffy are consistent */
-		new_tb_ticks_per_sec = new_tb_ticks_per_jiffy * HZ;
-
-		if ( tick_diff < 0 ) {
-			tick_diff = -tick_diff;
-			sign = '-';
-		}
-		if ( tick_diff ) {
-			if ( tick_diff < tb_ticks_per_jiffy/25 ) {
-				printk( "Titan recalibrate: new tb_ticks_per_jiffy = %lu (%c%ld)\n",
-						new_tb_ticks_per_jiffy, sign, tick_diff );
-				tb_ticks_per_jiffy = new_tb_ticks_per_jiffy;
-				tb_ticks_per_sec   = new_tb_ticks_per_sec;
-				calc_cputime_factors();
-				vdso_data->tb_ticks_per_sec = tb_ticks_per_sec;
-				setup_cputime_one_jiffy();
-			}
-			else {
-				printk( "Titan recalibrate: FAILED (difference > 4 percent)\n"
-					"                   new tb_ticks_per_jiffy = %lu\n"
-					"                   old tb_ticks_per_jiffy = %lu\n",
-					new_tb_ticks_per_jiffy, tb_ticks_per_jiffy );
-			}
-		}
-	}
-	iSeries_recal_titan = titan;
-	iSeries_recal_tb = tb;
-
-	/* Called here as now we know accurate values for the timebase */
-	clocksource_init();
-	return 0;
-}
-late_initcall(iSeries_tb_recal);
-
-/* Called from platform early init */
-void __init iSeries_time_init_early(void)
-{
-	iSeries_recal_tb = get_tb();
-	iSeries_recal_titan = HvCallXm_loadTod();
-}
-#endif /* CONFIG_PPC_ISERIES */
-
 #ifdef CONFIG_IRQ_WORK
 
 /*
@@ -550,16 +466,6 @@
 #endif /* CONFIG_IRQ_WORK */
 
 /*
- * For iSeries shared processors, we have to let the hypervisor
- * set the hardware decrementer.  We set a virtual decrementer
- * in the lppaca and call the hypervisor if the virtual
- * decrementer is less than the current value in the hardware
- * decrementer. (almost always the new decrementer value will
- * be greater than the current hardware decementer so the hypervisor
- * call will not be needed)
- */
-
-/*
  * timer_interrupt - gets called when the decrementer overflows,
  * with interrupts disabled.
  */
@@ -580,6 +486,11 @@
 	if (!cpu_online(smp_processor_id()))
 		return;
 
+	/* Conditionally hard-enable interrupts now that the DEC has been
+	 * bumped to its maximum value
+	 */
+	may_hard_irq_enable();
+
 	trace_timer_interrupt_entry(regs);
 
 	__get_cpu_var(irq_stat).timer_irqs++;
@@ -597,20 +508,10 @@
 		irq_work_run();
 	}
 
-#ifdef CONFIG_PPC_ISERIES
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		get_lppaca()->int_dword.fields.decr_int = 0;
-#endif
-
 	*next_tb = ~(u64)0;
 	if (evt->event_handler)
 		evt->event_handler(evt);
 
-#ifdef CONFIG_PPC_ISERIES
-	if (firmware_has_feature(FW_FEATURE_ISERIES) && hvlpevent_is_pending())
-		process_hvlpevents();
-#endif
-
 #ifdef CONFIG_PPC64
 	/* collect purr register values often, for accurate calculations */
 	if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
@@ -982,9 +883,8 @@
 	 */
 	start_cpu_decrementer();
 
-	/* Register the clocksource, if we're not running on iSeries */
-	if (!firmware_has_feature(FW_FEATURE_ISERIES))
-		clocksource_init();
+	/* Register the clocksource */
+	clocksource_init();
 
 	init_decrementer_clockevent();
 }
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index c091527..6aa0c66 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -39,7 +39,6 @@
 #include <asm/emulated_ops.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
 #include <asm/rtas.h>
@@ -57,6 +56,9 @@
 #include <asm/kexec.h>
 #include <asm/ppc-opcode.h>
 #include <asm/rio.h>
+#include <asm/fadump.h>
+#include <asm/switch_to.h>
+#include <asm/debug.h>
 
 #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
 int (*__debugger)(struct pt_regs *regs) __read_mostly;
@@ -145,6 +147,8 @@
 		arch_spin_unlock(&die_lock);
 	raw_local_irq_restore(flags);
 
+	crash_fadump(regs, "die oops");
+
 	/*
 	 * A system reset (0x100) is a request to dump, so we always send
 	 * it through the crashdump code.
@@ -244,6 +248,9 @@
 				   addr, regs->nip, regs->link, code);
 	}
 
+	if (!arch_irq_disabled_regs(regs))
+		local_irq_enable();
+
 	memset(&info, 0, sizeof(info));
 	info.si_signo = signr;
 	info.si_code = code;
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index 57fa2c0..c39c1ca 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -46,9 +46,6 @@
 #elif defined(CONFIG_PPC_EARLY_DEBUG_MAPLE)
 	/* Maple real mode debug */
 	udbg_init_maple_realmode();
-#elif defined(CONFIG_PPC_EARLY_DEBUG_ISERIES)
-	/* For iSeries - hit Ctrl-x Ctrl-x to see the output */
-	udbg_init_iseries();
 #elif defined(CONFIG_PPC_EARLY_DEBUG_BEAT)
 	udbg_init_debug_beat();
 #elif defined(CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE)
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index 7d14bb69..9eb5b9b 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -24,7 +24,6 @@
 #include <linux/memblock.h>
 
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/mmu.h>
 #include <asm/mmu_context.h>
@@ -263,17 +262,11 @@
 	 * the "data" page of the vDSO or you'll stop getting kernel updates
 	 * and your nice userland gettimeofday will be totally dead.
 	 * It's fine to use that for setting breakpoints in the vDSO code
-	 * pages though
-	 *
-	 * Make sure the vDSO gets into every core dump.
-	 * Dumping its contents makes post-mortem fully interpretable later
-	 * without matching up the same kernel and hardware config to see
-	 * what PC values meant.
+	 * pages though.
 	 */
 	rc = install_special_mapping(mm, vdso_base, vdso_pages << PAGE_SHIFT,
 				     VM_READ|VM_EXEC|
-				     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-				     VM_ALWAYSDUMP,
+				     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
 				     vdso_pagelist);
 	if (rc) {
 		current->mm->context.vdso_base = 0;
@@ -727,10 +720,10 @@
 	vdso_data->version.minor = SYSTEMCFG_MINOR;
 	vdso_data->processor = mfspr(SPRN_PVR);
 	/*
-	 * Fake the old platform number for pSeries and iSeries and add
+	 * Fake the old platform number for pSeries and add
 	 * in LPAR bit if necessary
 	 */
-	vdso_data->platform = machine_is(iseries) ? 0x200 : 0x100;
+	vdso_data->platform = 0x100;
 	if (firmware_has_feature(FW_FEATURE_LPAR))
 		vdso_data->platform |= 1;
 	vdso_data->physicalMemorySize = memblock_phys_mem_size();
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 8b08629..a3a9990 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -34,11 +34,6 @@
 #include <asm/abs_addr.h>
 #include <asm/page.h>
 #include <asm/hvcall.h>
-#include <asm/iseries/vio.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/iseries/iommu.h>
 
 static struct bus_type vio_bus_type;
 
@@ -487,7 +482,8 @@
 }
 
 static void *vio_dma_iommu_alloc_coherent(struct device *dev, size_t size,
-                                          dma_addr_t *dma_handle, gfp_t flag)
+					  dma_addr_t *dma_handle, gfp_t flag,
+					  struct dma_attrs *attrs)
 {
 	struct vio_dev *viodev = to_vio_dev(dev);
 	void *ret;
@@ -497,7 +493,7 @@
 		return NULL;
 	}
 
-	ret = dma_iommu_ops.alloc_coherent(dev, size, dma_handle, flag);
+	ret = dma_iommu_ops.alloc(dev, size, dma_handle, flag, attrs);
 	if (unlikely(ret == NULL)) {
 		vio_cmo_dealloc(viodev, roundup(size, PAGE_SIZE));
 		atomic_inc(&viodev->cmo.allocs_failed);
@@ -507,11 +503,12 @@
 }
 
 static void vio_dma_iommu_free_coherent(struct device *dev, size_t size,
-                                        void *vaddr, dma_addr_t dma_handle)
+					void *vaddr, dma_addr_t dma_handle,
+					struct dma_attrs *attrs)
 {
 	struct vio_dev *viodev = to_vio_dev(dev);
 
-	dma_iommu_ops.free_coherent(dev, size, vaddr, dma_handle);
+	dma_iommu_ops.free(dev, size, vaddr, dma_handle, attrs);
 
 	vio_cmo_dealloc(viodev, roundup(size, PAGE_SIZE));
 }
@@ -612,8 +609,8 @@
 }
 
 struct dma_map_ops vio_dma_mapping_ops = {
-	.alloc_coherent    = vio_dma_iommu_alloc_coherent,
-	.free_coherent     = vio_dma_iommu_free_coherent,
+	.alloc             = vio_dma_iommu_alloc_coherent,
+	.free              = vio_dma_iommu_free_coherent,
 	.map_sg            = vio_dma_iommu_map_sg,
 	.unmap_sg          = vio_dma_iommu_unmap_sg,
 	.map_page          = vio_dma_iommu_map_page,
@@ -1042,7 +1039,6 @@
 	vio_bus_type.bus_attrs = vio_cmo_bus_attrs;
 }
 #else /* CONFIG_PPC_SMLPAR */
-/* Dummy functions for iSeries platform */
 int vio_cmo_entitlement_update(size_t new_entitlement) { return 0; }
 void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired) {}
 static int vio_cmo_bus_probe(struct vio_dev *viodev) { return 0; }
@@ -1060,9 +1056,6 @@
 	struct iommu_table *tbl;
 	unsigned long offset, size;
 
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		return vio_build_iommu_table_iseries(dev);
-
 	dma_window = of_get_property(dev->dev.of_node,
 				  "ibm,my-dma-window", NULL);
 	if (!dma_window)
@@ -1168,17 +1161,21 @@
  * vio_register_driver: - Register a new vio driver
  * @drv:	The vio_driver structure to be registered.
  */
-int vio_register_driver(struct vio_driver *viodrv)
+int __vio_register_driver(struct vio_driver *viodrv, struct module *owner,
+			  const char *mod_name)
 {
-	printk(KERN_DEBUG "%s: driver %s registering\n", __func__,
-		viodrv->driver.name);
+	pr_debug("%s: driver %s registering\n", __func__, viodrv->name);
 
 	/* fill in 'struct driver' fields */
+	viodrv->driver.name = viodrv->name;
+	viodrv->driver.pm = viodrv->pm;
 	viodrv->driver.bus = &vio_bus_type;
+	viodrv->driver.owner = owner;
+	viodrv->driver.mod_name = mod_name;
 
 	return driver_register(&viodrv->driver);
 }
-EXPORT_SYMBOL(vio_register_driver);
+EXPORT_SYMBOL(__vio_register_driver);
 
 /**
  * vio_unregister_driver - Remove registration of vio driver.
@@ -1195,8 +1192,7 @@
 {
 	struct iommu_table *tbl = get_iommu_table_base(dev);
 
-	/* iSeries uses a common table for all vio devices */
-	if (!firmware_has_feature(FW_FEATURE_ISERIES) && tbl)
+	if (tbl)
 		iommu_free_table(tbl, dev->of_node ?
 			dev->of_node->full_name : dev_name(dev));
 	of_node_put(dev->of_node);
@@ -1244,12 +1240,6 @@
 	viodev->name = of_node->name;
 	viodev->type = of_node->type;
 	viodev->unit_address = *unit_address;
-	if (firmware_has_feature(FW_FEATURE_ISERIES)) {
-		unit_address = of_get_property(of_node,
-				"linux,unit_address", NULL);
-		if (unit_address != NULL)
-			viodev->unit_address = *unit_address;
-	}
 	viodev->dev.of_node = of_node_get(of_node);
 
 	if (firmware_has_feature(FW_FEATURE_CMO))
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 710a540..65d1c08 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -109,11 +109,6 @@
 		__ptov_table_begin = .;
 		*(.ptov_fixup);
 		__ptov_table_end = .;
-#ifdef CONFIG_PPC_ISERIES
-		__dt_strings_start = .;
-		*(.dt_strings);
-		__dt_strings_end = .;
-#endif
 	}
 
 	.init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index 78133de..8f64709 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -69,6 +69,7 @@
 config KVM_BOOK3S_64_HV
 	bool "KVM support for POWER7 and PPC970 using hypervisor mode in host"
 	depends on KVM_BOOK3S_64
+	select MMU_NOTIFIER
 	---help---
 	  Support running unmodified book3s_64 guest kernels in
 	  virtual machines on POWER7 and PPC970 processors that have
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index e41ac6f..7d54f4e 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -258,7 +258,7 @@
 	return true;
 }
 
-void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
+void kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
 {
 	unsigned long *pending = &vcpu->arch.pending_exceptions;
 	unsigned long old_pending = vcpu->arch.pending_exceptions;
@@ -423,10 +423,10 @@
 	regs->sprg1 = vcpu->arch.shared->sprg1;
 	regs->sprg2 = vcpu->arch.shared->sprg2;
 	regs->sprg3 = vcpu->arch.shared->sprg3;
-	regs->sprg4 = vcpu->arch.sprg4;
-	regs->sprg5 = vcpu->arch.sprg5;
-	regs->sprg6 = vcpu->arch.sprg6;
-	regs->sprg7 = vcpu->arch.sprg7;
+	regs->sprg4 = vcpu->arch.shared->sprg4;
+	regs->sprg5 = vcpu->arch.shared->sprg5;
+	regs->sprg6 = vcpu->arch.shared->sprg6;
+	regs->sprg7 = vcpu->arch.shared->sprg7;
 
 	for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
 		regs->gpr[i] = kvmppc_get_gpr(vcpu, i);
@@ -450,10 +450,10 @@
 	vcpu->arch.shared->sprg1 = regs->sprg1;
 	vcpu->arch.shared->sprg2 = regs->sprg2;
 	vcpu->arch.shared->sprg3 = regs->sprg3;
-	vcpu->arch.sprg4 = regs->sprg4;
-	vcpu->arch.sprg5 = regs->sprg5;
-	vcpu->arch.sprg6 = regs->sprg6;
-	vcpu->arch.sprg7 = regs->sprg7;
+	vcpu->arch.shared->sprg4 = regs->sprg4;
+	vcpu->arch.shared->sprg5 = regs->sprg5;
+	vcpu->arch.shared->sprg6 = regs->sprg6;
+	vcpu->arch.shared->sprg7 = regs->sprg7;
 
 	for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
 		kvmppc_set_gpr(vcpu, i, regs->gpr[i]);
@@ -477,41 +477,10 @@
 	return 0;
 }
 
-/*
- * Get (and clear) the dirty memory log for a memory slot.
- */
-int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
-				      struct kvm_dirty_log *log)
+void kvmppc_decrementer_func(unsigned long data)
 {
-	struct kvm_memory_slot *memslot;
-	struct kvm_vcpu *vcpu;
-	ulong ga, ga_end;
-	int is_dirty = 0;
-	int r;
-	unsigned long n;
+	struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
 
-	mutex_lock(&kvm->slots_lock);
-
-	r = kvm_get_dirty_log(kvm, log, &is_dirty);
-	if (r)
-		goto out;
-
-	/* If nothing is dirty, don't bother messing with page tables. */
-	if (is_dirty) {
-		memslot = id_to_memslot(kvm->memslots, log->slot);
-
-		ga = memslot->base_gfn << PAGE_SHIFT;
-		ga_end = ga + (memslot->npages << PAGE_SHIFT);
-
-		kvm_for_each_vcpu(n, vcpu, kvm)
-			kvmppc_mmu_pte_pflush(vcpu, ga, ga_end);
-
-		n = kvm_dirty_bitmap_bytes(memslot);
-		memset(memslot->dirty_bitmap, 0, n);
-	}
-
-	r = 0;
-out:
-	mutex_unlock(&kvm->slots_lock);
-	return r;
+	kvmppc_core_queue_dec(vcpu);
+	kvm_vcpu_kick(vcpu);
 }
diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c
index 9fecbfb..f922c29 100644
--- a/arch/powerpc/kvm/book3s_32_mmu_host.c
+++ b/arch/powerpc/kvm/book3s_32_mmu_host.c
@@ -151,13 +151,15 @@
 	bool primary = false;
 	bool evict = false;
 	struct hpte_cache *pte;
+	int r = 0;
 
 	/* Get host physical address for gpa */
 	hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT);
 	if (is_error_pfn(hpaddr)) {
 		printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n",
 				 orig_pte->eaddr);
-		return -EINVAL;
+		r = -EINVAL;
+		goto out;
 	}
 	hpaddr <<= PAGE_SHIFT;
 
@@ -249,7 +251,8 @@
 
 	kvmppc_mmu_hpte_cache_map(vcpu, pte);
 
-	return 0;
+out:
+	return r;
 }
 
 static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
@@ -297,12 +300,14 @@
 	u64 gvsid;
 	u32 sr;
 	struct kvmppc_sid_map *map;
-	struct kvmppc_book3s_shadow_vcpu *svcpu = to_svcpu(vcpu);
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	int r = 0;
 
 	if (vcpu->arch.mmu.esid_to_vsid(vcpu, esid, &gvsid)) {
 		/* Invalidate an entry */
 		svcpu->sr[esid] = SR_INVALID;
-		return -ENOENT;
+		r = -ENOENT;
+		goto out;
 	}
 
 	map = find_sid_vsid(vcpu, gvsid);
@@ -315,17 +320,21 @@
 
 	dprintk_sr("MMU: mtsr %d, 0x%x\n", esid, sr);
 
-	return 0;
+out:
+	svcpu_put(svcpu);
+	return r;
 }
 
 void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
 {
 	int i;
-	struct kvmppc_book3s_shadow_vcpu *svcpu = to_svcpu(vcpu);
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
 
 	dprintk_sr("MMU: flushing all segments (%d)\n", ARRAY_SIZE(svcpu->sr));
 	for (i = 0; i < ARRAY_SIZE(svcpu->sr); i++)
 		svcpu->sr[i] = SR_INVALID;
+
+	svcpu_put(svcpu);
 }
 
 void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c
index fa2f084..6f87f39 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_host.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_host.c
@@ -88,12 +88,14 @@
 	int vflags = 0;
 	int attempt = 0;
 	struct kvmppc_sid_map *map;
+	int r = 0;
 
 	/* Get host physical address for gpa */
 	hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT);
 	if (is_error_pfn(hpaddr)) {
 		printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n", orig_pte->eaddr);
-		return -EINVAL;
+		r = -EINVAL;
+		goto out;
 	}
 	hpaddr <<= PAGE_SHIFT;
 	hpaddr |= orig_pte->raddr & (~0xfffULL & ~PAGE_MASK);
@@ -110,7 +112,8 @@
 		printk(KERN_ERR "KVM: Segment map for 0x%llx (0x%lx) failed\n",
 				vsid, orig_pte->eaddr);
 		WARN_ON(true);
-		return -EINVAL;
+		r = -EINVAL;
+		goto out;
 	}
 
 	vsid = map->host_vsid;
@@ -131,8 +134,10 @@
 
 	/* In case we tried normal mapping already, let's nuke old entries */
 	if (attempt > 1)
-		if (ppc_md.hpte_remove(hpteg) < 0)
-			return -1;
+		if (ppc_md.hpte_remove(hpteg) < 0) {
+			r = -1;
+			goto out;
+		}
 
 	ret = ppc_md.hpte_insert(hpteg, va, hpaddr, rflags, vflags, MMU_PAGE_4K, MMU_SEGSIZE_256M);
 
@@ -162,7 +167,8 @@
 		kvmppc_mmu_hpte_cache_map(vcpu, pte);
 	}
 
-	return 0;
+out:
+	return r;
 }
 
 static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
@@ -207,25 +213,30 @@
 
 static int kvmppc_mmu_next_segment(struct kvm_vcpu *vcpu, ulong esid)
 {
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
 	int i;
 	int max_slb_size = 64;
 	int found_inval = -1;
 	int r;
 
-	if (!to_svcpu(vcpu)->slb_max)
-		to_svcpu(vcpu)->slb_max = 1;
+	if (!svcpu->slb_max)
+		svcpu->slb_max = 1;
 
 	/* Are we overwriting? */
-	for (i = 1; i < to_svcpu(vcpu)->slb_max; i++) {
-		if (!(to_svcpu(vcpu)->slb[i].esid & SLB_ESID_V))
+	for (i = 1; i < svcpu->slb_max; i++) {
+		if (!(svcpu->slb[i].esid & SLB_ESID_V))
 			found_inval = i;
-		else if ((to_svcpu(vcpu)->slb[i].esid & ESID_MASK) == esid)
-			return i;
+		else if ((svcpu->slb[i].esid & ESID_MASK) == esid) {
+			r = i;
+			goto out;
+		}
 	}
 
 	/* Found a spare entry that was invalidated before */
-	if (found_inval > 0)
-		return found_inval;
+	if (found_inval > 0) {
+		r = found_inval;
+		goto out;
+	}
 
 	/* No spare invalid entry, so create one */
 
@@ -233,30 +244,35 @@
 		max_slb_size = mmu_slb_size;
 
 	/* Overflowing -> purge */
-	if ((to_svcpu(vcpu)->slb_max) == max_slb_size)
+	if ((svcpu->slb_max) == max_slb_size)
 		kvmppc_mmu_flush_segments(vcpu);
 
-	r = to_svcpu(vcpu)->slb_max;
-	to_svcpu(vcpu)->slb_max++;
+	r = svcpu->slb_max;
+	svcpu->slb_max++;
 
+out:
+	svcpu_put(svcpu);
 	return r;
 }
 
 int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr)
 {
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
 	u64 esid = eaddr >> SID_SHIFT;
 	u64 slb_esid = (eaddr & ESID_MASK) | SLB_ESID_V;
 	u64 slb_vsid = SLB_VSID_USER;
 	u64 gvsid;
 	int slb_index;
 	struct kvmppc_sid_map *map;
+	int r = 0;
 
 	slb_index = kvmppc_mmu_next_segment(vcpu, eaddr & ESID_MASK);
 
 	if (vcpu->arch.mmu.esid_to_vsid(vcpu, esid, &gvsid)) {
 		/* Invalidate an entry */
-		to_svcpu(vcpu)->slb[slb_index].esid = 0;
-		return -ENOENT;
+		svcpu->slb[slb_index].esid = 0;
+		r = -ENOENT;
+		goto out;
 	}
 
 	map = find_sid_vsid(vcpu, gvsid);
@@ -269,18 +285,22 @@
 	slb_vsid &= ~SLB_VSID_KP;
 	slb_esid |= slb_index;
 
-	to_svcpu(vcpu)->slb[slb_index].esid = slb_esid;
-	to_svcpu(vcpu)->slb[slb_index].vsid = slb_vsid;
+	svcpu->slb[slb_index].esid = slb_esid;
+	svcpu->slb[slb_index].vsid = slb_vsid;
 
 	trace_kvm_book3s_slbmte(slb_vsid, slb_esid);
 
-	return 0;
+out:
+	svcpu_put(svcpu);
+	return r;
 }
 
 void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
 {
-	to_svcpu(vcpu)->slb_max = 1;
-	to_svcpu(vcpu)->slb[0].esid = 0;
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	svcpu->slb_max = 1;
+	svcpu->slb[0].esid = 0;
+	svcpu_put(svcpu);
 }
 
 void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index bc3a2ea..ddc485a 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -23,6 +23,7 @@
 #include <linux/gfp.h>
 #include <linux/slab.h>
 #include <linux/hugetlb.h>
+#include <linux/vmalloc.h>
 
 #include <asm/tlbflush.h>
 #include <asm/kvm_ppc.h>
@@ -33,15 +34,6 @@
 #include <asm/ppc-opcode.h>
 #include <asm/cputable.h>
 
-/* For now use fixed-size 16MB page table */
-#define HPT_ORDER	24
-#define HPT_NPTEG	(1ul << (HPT_ORDER - 7))	/* 128B per pteg */
-#define HPT_HASH_MASK	(HPT_NPTEG - 1)
-
-/* Pages in the VRMA are 16MB pages */
-#define VRMA_PAGE_ORDER	24
-#define VRMA_VSID	0x1ffffffUL	/* 1TB VSID reserved for VRMA */
-
 /* POWER7 has 10-bit LPIDs, PPC970 has 6-bit LPIDs */
 #define MAX_LPID_970	63
 #define NR_LPIDS	(LPID_RSVD + 1)
@@ -51,21 +43,41 @@
 {
 	unsigned long hpt;
 	unsigned long lpid;
+	struct revmap_entry *rev;
+	struct kvmppc_linear_info *li;
 
-	hpt = __get_free_pages(GFP_KERNEL|__GFP_ZERO|__GFP_REPEAT|__GFP_NOWARN,
-			       HPT_ORDER - PAGE_SHIFT);
+	/* Allocate guest's hashed page table */
+	li = kvm_alloc_hpt();
+	if (li) {
+		/* using preallocated memory */
+		hpt = (ulong)li->base_virt;
+		kvm->arch.hpt_li = li;
+	} else {
+		/* using dynamic memory */
+		hpt = __get_free_pages(GFP_KERNEL|__GFP_ZERO|__GFP_REPEAT|
+				       __GFP_NOWARN, HPT_ORDER - PAGE_SHIFT);
+	}
+
 	if (!hpt) {
 		pr_err("kvm_alloc_hpt: Couldn't alloc HPT\n");
 		return -ENOMEM;
 	}
 	kvm->arch.hpt_virt = hpt;
 
+	/* Allocate reverse map array */
+	rev = vmalloc(sizeof(struct revmap_entry) * HPT_NPTE);
+	if (!rev) {
+		pr_err("kvmppc_alloc_hpt: Couldn't alloc reverse map array\n");
+		goto out_freehpt;
+	}
+	kvm->arch.revmap = rev;
+
+	/* Allocate the guest's logical partition ID */
 	do {
 		lpid = find_first_zero_bit(lpid_inuse, NR_LPIDS);
 		if (lpid >= NR_LPIDS) {
 			pr_err("kvm_alloc_hpt: No LPIDs free\n");
-			free_pages(hpt, HPT_ORDER - PAGE_SHIFT);
-			return -ENOMEM;
+			goto out_freeboth;
 		}
 	} while (test_and_set_bit(lpid, lpid_inuse));
 
@@ -74,37 +86,64 @@
 
 	pr_info("KVM guest htab at %lx, LPID %lx\n", hpt, lpid);
 	return 0;
+
+ out_freeboth:
+	vfree(rev);
+ out_freehpt:
+	free_pages(hpt, HPT_ORDER - PAGE_SHIFT);
+	return -ENOMEM;
 }
 
 void kvmppc_free_hpt(struct kvm *kvm)
 {
 	clear_bit(kvm->arch.lpid, lpid_inuse);
-	free_pages(kvm->arch.hpt_virt, HPT_ORDER - PAGE_SHIFT);
+	vfree(kvm->arch.revmap);
+	if (kvm->arch.hpt_li)
+		kvm_release_hpt(kvm->arch.hpt_li);
+	else
+		free_pages(kvm->arch.hpt_virt, HPT_ORDER - PAGE_SHIFT);
 }
 
-void kvmppc_map_vrma(struct kvm *kvm, struct kvm_userspace_memory_region *mem)
+/* Bits in first HPTE dword for pagesize 4k, 64k or 16M */
+static inline unsigned long hpte0_pgsize_encoding(unsigned long pgsize)
+{
+	return (pgsize > 0x1000) ? HPTE_V_LARGE : 0;
+}
+
+/* Bits in second HPTE dword for pagesize 4k, 64k or 16M */
+static inline unsigned long hpte1_pgsize_encoding(unsigned long pgsize)
+{
+	return (pgsize == 0x10000) ? 0x1000 : 0;
+}
+
+void kvmppc_map_vrma(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
+		     unsigned long porder)
 {
 	unsigned long i;
-	unsigned long npages = kvm->arch.ram_npages;
-	unsigned long pfn;
-	unsigned long *hpte;
-	unsigned long hash;
-	struct kvmppc_pginfo *pginfo = kvm->arch.ram_pginfo;
+	unsigned long npages;
+	unsigned long hp_v, hp_r;
+	unsigned long addr, hash;
+	unsigned long psize;
+	unsigned long hp0, hp1;
+	long ret;
 
-	if (!pginfo)
-		return;
+	psize = 1ul << porder;
+	npages = memslot->npages >> (porder - PAGE_SHIFT);
 
 	/* VRMA can't be > 1TB */
-	if (npages > 1ul << (40 - kvm->arch.ram_porder))
-		npages = 1ul << (40 - kvm->arch.ram_porder);
+	if (npages > 1ul << (40 - porder))
+		npages = 1ul << (40 - porder);
 	/* Can't use more than 1 HPTE per HPTEG */
 	if (npages > HPT_NPTEG)
 		npages = HPT_NPTEG;
 
+	hp0 = HPTE_V_1TB_SEG | (VRMA_VSID << (40 - 16)) |
+		HPTE_V_BOLTED | hpte0_pgsize_encoding(psize);
+	hp1 = hpte1_pgsize_encoding(psize) |
+		HPTE_R_R | HPTE_R_C | HPTE_R_M | PP_RWXX;
+
 	for (i = 0; i < npages; ++i) {
-		pfn = pginfo[i].pfn;
-		if (!pfn)
-			break;
+		addr = i << porder;
 		/* can't use hpt_hash since va > 64 bits */
 		hash = (i ^ (VRMA_VSID ^ (VRMA_VSID << 25))) & HPT_HASH_MASK;
 		/*
@@ -113,15 +152,15 @@
 		 * at most one HPTE per HPTEG, we just assume entry 7
 		 * is available and use it.
 		 */
-		hpte = (unsigned long *) (kvm->arch.hpt_virt + (hash << 7));
-		hpte += 7 * 2;
-		/* HPTE low word - RPN, protection, etc. */
-		hpte[1] = (pfn << PAGE_SHIFT) | HPTE_R_R | HPTE_R_C |
-			HPTE_R_M | PP_RWXX;
-		wmb();
-		hpte[0] = HPTE_V_1TB_SEG | (VRMA_VSID << (40 - 16)) |
-			(i << (VRMA_PAGE_ORDER - 16)) | HPTE_V_BOLTED |
-			HPTE_V_LARGE | HPTE_V_VALID;
+		hash = (hash << 3) + 7;
+		hp_v = hp0 | ((addr >> 16) & ~0x7fUL);
+		hp_r = hp1 | addr;
+		ret = kvmppc_virtmode_h_enter(vcpu, H_EXACT, hash, hp_v, hp_r);
+		if (ret != H_SUCCESS) {
+			pr_err("KVM: map_vrma at %lx failed, ret=%ld\n",
+			       addr, ret);
+			break;
+		}
 	}
 }
 
@@ -158,10 +197,814 @@
 	kvmppc_set_msr(vcpu, MSR_SF | MSR_ME);
 }
 
-static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
-				struct kvmppc_pte *gpte, bool data)
+/*
+ * This is called to get a reference to a guest page if there isn't
+ * one already in the kvm->arch.slot_phys[][] arrays.
+ */
+static long kvmppc_get_guest_page(struct kvm *kvm, unsigned long gfn,
+				  struct kvm_memory_slot *memslot,
+				  unsigned long psize)
 {
-	return -ENOENT;
+	unsigned long start;
+	long np, err;
+	struct page *page, *hpage, *pages[1];
+	unsigned long s, pgsize;
+	unsigned long *physp;
+	unsigned int is_io, got, pgorder;
+	struct vm_area_struct *vma;
+	unsigned long pfn, i, npages;
+
+	physp = kvm->arch.slot_phys[memslot->id];
+	if (!physp)
+		return -EINVAL;
+	if (physp[gfn - memslot->base_gfn])
+		return 0;
+
+	is_io = 0;
+	got = 0;
+	page = NULL;
+	pgsize = psize;
+	err = -EINVAL;
+	start = gfn_to_hva_memslot(memslot, gfn);
+
+	/* Instantiate and get the page we want access to */
+	np = get_user_pages_fast(start, 1, 1, pages);
+	if (np != 1) {
+		/* Look up the vma for the page */
+		down_read(&current->mm->mmap_sem);
+		vma = find_vma(current->mm, start);
+		if (!vma || vma->vm_start > start ||
+		    start + psize > vma->vm_end ||
+		    !(vma->vm_flags & VM_PFNMAP))
+			goto up_err;
+		is_io = hpte_cache_bits(pgprot_val(vma->vm_page_prot));
+		pfn = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
+		/* check alignment of pfn vs. requested page size */
+		if (psize > PAGE_SIZE && (pfn & ((psize >> PAGE_SHIFT) - 1)))
+			goto up_err;
+		up_read(&current->mm->mmap_sem);
+
+	} else {
+		page = pages[0];
+		got = KVMPPC_GOT_PAGE;
+
+		/* See if this is a large page */
+		s = PAGE_SIZE;
+		if (PageHuge(page)) {
+			hpage = compound_head(page);
+			s <<= compound_order(hpage);
+			/* Get the whole large page if slot alignment is ok */
+			if (s > psize && slot_is_aligned(memslot, s) &&
+			    !(memslot->userspace_addr & (s - 1))) {
+				start &= ~(s - 1);
+				pgsize = s;
+				page = hpage;
+			}
+		}
+		if (s < psize)
+			goto out;
+		pfn = page_to_pfn(page);
+	}
+
+	npages = pgsize >> PAGE_SHIFT;
+	pgorder = __ilog2(npages);
+	physp += (gfn - memslot->base_gfn) & ~(npages - 1);
+	spin_lock(&kvm->arch.slot_phys_lock);
+	for (i = 0; i < npages; ++i) {
+		if (!physp[i]) {
+			physp[i] = ((pfn + i) << PAGE_SHIFT) +
+				got + is_io + pgorder;
+			got = 0;
+		}
+	}
+	spin_unlock(&kvm->arch.slot_phys_lock);
+	err = 0;
+
+ out:
+	if (got) {
+		if (PageHuge(page))
+			page = compound_head(page);
+		put_page(page);
+	}
+	return err;
+
+ up_err:
+	up_read(&current->mm->mmap_sem);
+	return err;
+}
+
+/*
+ * We come here on a H_ENTER call from the guest when we are not
+ * using mmu notifiers and we don't have the requested page pinned
+ * already.
+ */
+long kvmppc_virtmode_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
+			long pte_index, unsigned long pteh, unsigned long ptel)
+{
+	struct kvm *kvm = vcpu->kvm;
+	unsigned long psize, gpa, gfn;
+	struct kvm_memory_slot *memslot;
+	long ret;
+
+	if (kvm->arch.using_mmu_notifiers)
+		goto do_insert;
+
+	psize = hpte_page_size(pteh, ptel);
+	if (!psize)
+		return H_PARAMETER;
+
+	pteh &= ~(HPTE_V_HVLOCK | HPTE_V_ABSENT | HPTE_V_VALID);
+
+	/* Find the memslot (if any) for this address */
+	gpa = (ptel & HPTE_R_RPN) & ~(psize - 1);
+	gfn = gpa >> PAGE_SHIFT;
+	memslot = gfn_to_memslot(kvm, gfn);
+	if (memslot && !(memslot->flags & KVM_MEMSLOT_INVALID)) {
+		if (!slot_is_aligned(memslot, psize))
+			return H_PARAMETER;
+		if (kvmppc_get_guest_page(kvm, gfn, memslot, psize) < 0)
+			return H_PARAMETER;
+	}
+
+ do_insert:
+	/* Protect linux PTE lookup from page table destruction */
+	rcu_read_lock_sched();	/* this disables preemption too */
+	vcpu->arch.pgdir = current->mm->pgd;
+	ret = kvmppc_h_enter(vcpu, flags, pte_index, pteh, ptel);
+	rcu_read_unlock_sched();
+	if (ret == H_TOO_HARD) {
+		/* this can't happen */
+		pr_err("KVM: Oops, kvmppc_h_enter returned too hard!\n");
+		ret = H_RESOURCE;	/* or something */
+	}
+	return ret;
+
+}
+
+static struct kvmppc_slb *kvmppc_mmu_book3s_hv_find_slbe(struct kvm_vcpu *vcpu,
+							 gva_t eaddr)
+{
+	u64 mask;
+	int i;
+
+	for (i = 0; i < vcpu->arch.slb_nr; i++) {
+		if (!(vcpu->arch.slb[i].orige & SLB_ESID_V))
+			continue;
+
+		if (vcpu->arch.slb[i].origv & SLB_VSID_B_1T)
+			mask = ESID_MASK_1T;
+		else
+			mask = ESID_MASK;
+
+		if (((vcpu->arch.slb[i].orige ^ eaddr) & mask) == 0)
+			return &vcpu->arch.slb[i];
+	}
+	return NULL;
+}
+
+static unsigned long kvmppc_mmu_get_real_addr(unsigned long v, unsigned long r,
+			unsigned long ea)
+{
+	unsigned long ra_mask;
+
+	ra_mask = hpte_page_size(v, r) - 1;
+	return (r & HPTE_R_RPN & ~ra_mask) | (ea & ra_mask);
+}
+
+static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
+			struct kvmppc_pte *gpte, bool data)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct kvmppc_slb *slbe;
+	unsigned long slb_v;
+	unsigned long pp, key;
+	unsigned long v, gr;
+	unsigned long *hptep;
+	int index;
+	int virtmode = vcpu->arch.shregs.msr & (data ? MSR_DR : MSR_IR);
+
+	/* Get SLB entry */
+	if (virtmode) {
+		slbe = kvmppc_mmu_book3s_hv_find_slbe(vcpu, eaddr);
+		if (!slbe)
+			return -EINVAL;
+		slb_v = slbe->origv;
+	} else {
+		/* real mode access */
+		slb_v = vcpu->kvm->arch.vrma_slb_v;
+	}
+
+	/* Find the HPTE in the hash table */
+	index = kvmppc_hv_find_lock_hpte(kvm, eaddr, slb_v,
+					 HPTE_V_VALID | HPTE_V_ABSENT);
+	if (index < 0)
+		return -ENOENT;
+	hptep = (unsigned long *)(kvm->arch.hpt_virt + (index << 4));
+	v = hptep[0] & ~HPTE_V_HVLOCK;
+	gr = kvm->arch.revmap[index].guest_rpte;
+
+	/* Unlock the HPTE */
+	asm volatile("lwsync" : : : "memory");
+	hptep[0] = v;
+
+	gpte->eaddr = eaddr;
+	gpte->vpage = ((v & HPTE_V_AVPN) << 4) | ((eaddr >> 12) & 0xfff);
+
+	/* Get PP bits and key for permission check */
+	pp = gr & (HPTE_R_PP0 | HPTE_R_PP);
+	key = (vcpu->arch.shregs.msr & MSR_PR) ? SLB_VSID_KP : SLB_VSID_KS;
+	key &= slb_v;
+
+	/* Calculate permissions */
+	gpte->may_read = hpte_read_permission(pp, key);
+	gpte->may_write = hpte_write_permission(pp, key);
+	gpte->may_execute = gpte->may_read && !(gr & (HPTE_R_N | HPTE_R_G));
+
+	/* Storage key permission check for POWER7 */
+	if (data && virtmode && cpu_has_feature(CPU_FTR_ARCH_206)) {
+		int amrfield = hpte_get_skey_perm(gr, vcpu->arch.amr);
+		if (amrfield & 1)
+			gpte->may_read = 0;
+		if (amrfield & 2)
+			gpte->may_write = 0;
+	}
+
+	/* Get the guest physical address */
+	gpte->raddr = kvmppc_mmu_get_real_addr(v, gr, eaddr);
+	return 0;
+}
+
+/*
+ * Quick test for whether an instruction is a load or a store.
+ * If the instruction is a load or a store, then this will indicate
+ * which it is, at least on server processors.  (Embedded processors
+ * have some external PID instructions that don't follow the rule
+ * embodied here.)  If the instruction isn't a load or store, then
+ * this doesn't return anything useful.
+ */
+static int instruction_is_store(unsigned int instr)
+{
+	unsigned int mask;
+
+	mask = 0x10000000;
+	if ((instr & 0xfc000000) == 0x7c000000)
+		mask = 0x100;		/* major opcode 31 */
+	return (instr & mask) != 0;
+}
+
+static int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
+				  unsigned long gpa, int is_store)
+{
+	int ret;
+	u32 last_inst;
+	unsigned long srr0 = kvmppc_get_pc(vcpu);
+
+	/* We try to load the last instruction.  We don't let
+	 * emulate_instruction do it as it doesn't check what
+	 * kvmppc_ld returns.
+	 * If we fail, we just return to the guest and try executing it again.
+	 */
+	if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED) {
+		ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false);
+		if (ret != EMULATE_DONE || last_inst == KVM_INST_FETCH_FAILED)
+			return RESUME_GUEST;
+		vcpu->arch.last_inst = last_inst;
+	}
+
+	/*
+	 * WARNING: We do not know for sure whether the instruction we just
+	 * read from memory is the same that caused the fault in the first
+	 * place.  If the instruction we read is neither an load or a store,
+	 * then it can't access memory, so we don't need to worry about
+	 * enforcing access permissions.  So, assuming it is a load or
+	 * store, we just check that its direction (load or store) is
+	 * consistent with the original fault, since that's what we
+	 * checked the access permissions against.  If there is a mismatch
+	 * we just return and retry the instruction.
+	 */
+
+	if (instruction_is_store(vcpu->arch.last_inst) != !!is_store)
+		return RESUME_GUEST;
+
+	/*
+	 * Emulated accesses are emulated by looking at the hash for
+	 * translation once, then performing the access later. The
+	 * translation could be invalidated in the meantime in which
+	 * point performing the subsequent memory access on the old
+	 * physical address could possibly be a security hole for the
+	 * guest (but not the host).
+	 *
+	 * This is less of an issue for MMIO stores since they aren't
+	 * globally visible. It could be an issue for MMIO loads to
+	 * a certain extent but we'll ignore it for now.
+	 */
+
+	vcpu->arch.paddr_accessed = gpa;
+	return kvmppc_emulate_mmio(run, vcpu);
+}
+
+int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
+				unsigned long ea, unsigned long dsisr)
+{
+	struct kvm *kvm = vcpu->kvm;
+	unsigned long *hptep, hpte[3], r;
+	unsigned long mmu_seq, psize, pte_size;
+	unsigned long gfn, hva, pfn;
+	struct kvm_memory_slot *memslot;
+	unsigned long *rmap;
+	struct revmap_entry *rev;
+	struct page *page, *pages[1];
+	long index, ret, npages;
+	unsigned long is_io;
+	unsigned int writing, write_ok;
+	struct vm_area_struct *vma;
+	unsigned long rcbits;
+
+	/*
+	 * Real-mode code has already searched the HPT and found the
+	 * entry we're interested in.  Lock the entry and check that
+	 * it hasn't changed.  If it has, just return and re-execute the
+	 * instruction.
+	 */
+	if (ea != vcpu->arch.pgfault_addr)
+		return RESUME_GUEST;
+	index = vcpu->arch.pgfault_index;
+	hptep = (unsigned long *)(kvm->arch.hpt_virt + (index << 4));
+	rev = &kvm->arch.revmap[index];
+	preempt_disable();
+	while (!try_lock_hpte(hptep, HPTE_V_HVLOCK))
+		cpu_relax();
+	hpte[0] = hptep[0] & ~HPTE_V_HVLOCK;
+	hpte[1] = hptep[1];
+	hpte[2] = r = rev->guest_rpte;
+	asm volatile("lwsync" : : : "memory");
+	hptep[0] = hpte[0];
+	preempt_enable();
+
+	if (hpte[0] != vcpu->arch.pgfault_hpte[0] ||
+	    hpte[1] != vcpu->arch.pgfault_hpte[1])
+		return RESUME_GUEST;
+
+	/* Translate the logical address and get the page */
+	psize = hpte_page_size(hpte[0], r);
+	gfn = hpte_rpn(r, psize);
+	memslot = gfn_to_memslot(kvm, gfn);
+
+	/* No memslot means it's an emulated MMIO region */
+	if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID)) {
+		unsigned long gpa = (gfn << PAGE_SHIFT) | (ea & (psize - 1));
+		return kvmppc_hv_emulate_mmio(run, vcpu, gpa,
+					      dsisr & DSISR_ISSTORE);
+	}
+
+	if (!kvm->arch.using_mmu_notifiers)
+		return -EFAULT;		/* should never get here */
+
+	/* used to check for invalidations in progress */
+	mmu_seq = kvm->mmu_notifier_seq;
+	smp_rmb();
+
+	is_io = 0;
+	pfn = 0;
+	page = NULL;
+	pte_size = PAGE_SIZE;
+	writing = (dsisr & DSISR_ISSTORE) != 0;
+	/* If writing != 0, then the HPTE must allow writing, if we get here */
+	write_ok = writing;
+	hva = gfn_to_hva_memslot(memslot, gfn);
+	npages = get_user_pages_fast(hva, 1, writing, pages);
+	if (npages < 1) {
+		/* Check if it's an I/O mapping */
+		down_read(&current->mm->mmap_sem);
+		vma = find_vma(current->mm, hva);
+		if (vma && vma->vm_start <= hva && hva + psize <= vma->vm_end &&
+		    (vma->vm_flags & VM_PFNMAP)) {
+			pfn = vma->vm_pgoff +
+				((hva - vma->vm_start) >> PAGE_SHIFT);
+			pte_size = psize;
+			is_io = hpte_cache_bits(pgprot_val(vma->vm_page_prot));
+			write_ok = vma->vm_flags & VM_WRITE;
+		}
+		up_read(&current->mm->mmap_sem);
+		if (!pfn)
+			return -EFAULT;
+	} else {
+		page = pages[0];
+		if (PageHuge(page)) {
+			page = compound_head(page);
+			pte_size <<= compound_order(page);
+		}
+		/* if the guest wants write access, see if that is OK */
+		if (!writing && hpte_is_writable(r)) {
+			pte_t *ptep, pte;
+
+			/*
+			 * We need to protect against page table destruction
+			 * while looking up and updating the pte.
+			 */
+			rcu_read_lock_sched();
+			ptep = find_linux_pte_or_hugepte(current->mm->pgd,
+							 hva, NULL);
+			if (ptep && pte_present(*ptep)) {
+				pte = kvmppc_read_update_linux_pte(ptep, 1);
+				if (pte_write(pte))
+					write_ok = 1;
+			}
+			rcu_read_unlock_sched();
+		}
+		pfn = page_to_pfn(page);
+	}
+
+	ret = -EFAULT;
+	if (psize > pte_size)
+		goto out_put;
+
+	/* Check WIMG vs. the actual page we're accessing */
+	if (!hpte_cache_flags_ok(r, is_io)) {
+		if (is_io)
+			return -EFAULT;
+		/*
+		 * Allow guest to map emulated device memory as
+		 * uncacheable, but actually make it cacheable.
+		 */
+		r = (r & ~(HPTE_R_W|HPTE_R_I|HPTE_R_G)) | HPTE_R_M;
+	}
+
+	/* Set the HPTE to point to pfn */
+	r = (r & ~(HPTE_R_PP0 - pte_size)) | (pfn << PAGE_SHIFT);
+	if (hpte_is_writable(r) && !write_ok)
+		r = hpte_make_readonly(r);
+	ret = RESUME_GUEST;
+	preempt_disable();
+	while (!try_lock_hpte(hptep, HPTE_V_HVLOCK))
+		cpu_relax();
+	if ((hptep[0] & ~HPTE_V_HVLOCK) != hpte[0] || hptep[1] != hpte[1] ||
+	    rev->guest_rpte != hpte[2])
+		/* HPTE has been changed under us; let the guest retry */
+		goto out_unlock;
+	hpte[0] = (hpte[0] & ~HPTE_V_ABSENT) | HPTE_V_VALID;
+
+	rmap = &memslot->rmap[gfn - memslot->base_gfn];
+	lock_rmap(rmap);
+
+	/* Check if we might have been invalidated; let the guest retry if so */
+	ret = RESUME_GUEST;
+	if (mmu_notifier_retry(vcpu, mmu_seq)) {
+		unlock_rmap(rmap);
+		goto out_unlock;
+	}
+
+	/* Only set R/C in real HPTE if set in both *rmap and guest_rpte */
+	rcbits = *rmap >> KVMPPC_RMAP_RC_SHIFT;
+	r &= rcbits | ~(HPTE_R_R | HPTE_R_C);
+
+	if (hptep[0] & HPTE_V_VALID) {
+		/* HPTE was previously valid, so we need to invalidate it */
+		unlock_rmap(rmap);
+		hptep[0] |= HPTE_V_ABSENT;
+		kvmppc_invalidate_hpte(kvm, hptep, index);
+		/* don't lose previous R and C bits */
+		r |= hptep[1] & (HPTE_R_R | HPTE_R_C);
+	} else {
+		kvmppc_add_revmap_chain(kvm, rev, rmap, index, 0);
+	}
+
+	hptep[1] = r;
+	eieio();
+	hptep[0] = hpte[0];
+	asm volatile("ptesync" : : : "memory");
+	preempt_enable();
+	if (page && hpte_is_writable(r))
+		SetPageDirty(page);
+
+ out_put:
+	if (page)
+		put_page(page);
+	return ret;
+
+ out_unlock:
+	hptep[0] &= ~HPTE_V_HVLOCK;
+	preempt_enable();
+	goto out_put;
+}
+
+static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
+			  int (*handler)(struct kvm *kvm, unsigned long *rmapp,
+					 unsigned long gfn))
+{
+	int ret;
+	int retval = 0;
+	struct kvm_memslots *slots;
+	struct kvm_memory_slot *memslot;
+
+	slots = kvm_memslots(kvm);
+	kvm_for_each_memslot(memslot, slots) {
+		unsigned long start = memslot->userspace_addr;
+		unsigned long end;
+
+		end = start + (memslot->npages << PAGE_SHIFT);
+		if (hva >= start && hva < end) {
+			gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT;
+
+			ret = handler(kvm, &memslot->rmap[gfn_offset],
+				      memslot->base_gfn + gfn_offset);
+			retval |= ret;
+		}
+	}
+
+	return retval;
+}
+
+static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
+			   unsigned long gfn)
+{
+	struct revmap_entry *rev = kvm->arch.revmap;
+	unsigned long h, i, j;
+	unsigned long *hptep;
+	unsigned long ptel, psize, rcbits;
+
+	for (;;) {
+		lock_rmap(rmapp);
+		if (!(*rmapp & KVMPPC_RMAP_PRESENT)) {
+			unlock_rmap(rmapp);
+			break;
+		}
+
+		/*
+		 * To avoid an ABBA deadlock with the HPTE lock bit,
+		 * we can't spin on the HPTE lock while holding the
+		 * rmap chain lock.
+		 */
+		i = *rmapp & KVMPPC_RMAP_INDEX;
+		hptep = (unsigned long *) (kvm->arch.hpt_virt + (i << 4));
+		if (!try_lock_hpte(hptep, HPTE_V_HVLOCK)) {
+			/* unlock rmap before spinning on the HPTE lock */
+			unlock_rmap(rmapp);
+			while (hptep[0] & HPTE_V_HVLOCK)
+				cpu_relax();
+			continue;
+		}
+		j = rev[i].forw;
+		if (j == i) {
+			/* chain is now empty */
+			*rmapp &= ~(KVMPPC_RMAP_PRESENT | KVMPPC_RMAP_INDEX);
+		} else {
+			/* remove i from chain */
+			h = rev[i].back;
+			rev[h].forw = j;
+			rev[j].back = h;
+			rev[i].forw = rev[i].back = i;
+			*rmapp = (*rmapp & ~KVMPPC_RMAP_INDEX) | j;
+		}
+
+		/* Now check and modify the HPTE */
+		ptel = rev[i].guest_rpte;
+		psize = hpte_page_size(hptep[0], ptel);
+		if ((hptep[0] & HPTE_V_VALID) &&
+		    hpte_rpn(ptel, psize) == gfn) {
+			hptep[0] |= HPTE_V_ABSENT;
+			kvmppc_invalidate_hpte(kvm, hptep, i);
+			/* Harvest R and C */
+			rcbits = hptep[1] & (HPTE_R_R | HPTE_R_C);
+			*rmapp |= rcbits << KVMPPC_RMAP_RC_SHIFT;
+			rev[i].guest_rpte = ptel | rcbits;
+		}
+		unlock_rmap(rmapp);
+		hptep[0] &= ~HPTE_V_HVLOCK;
+	}
+	return 0;
+}
+
+int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
+{
+	if (kvm->arch.using_mmu_notifiers)
+		kvm_handle_hva(kvm, hva, kvm_unmap_rmapp);
+	return 0;
+}
+
+static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
+			 unsigned long gfn)
+{
+	struct revmap_entry *rev = kvm->arch.revmap;
+	unsigned long head, i, j;
+	unsigned long *hptep;
+	int ret = 0;
+
+ retry:
+	lock_rmap(rmapp);
+	if (*rmapp & KVMPPC_RMAP_REFERENCED) {
+		*rmapp &= ~KVMPPC_RMAP_REFERENCED;
+		ret = 1;
+	}
+	if (!(*rmapp & KVMPPC_RMAP_PRESENT)) {
+		unlock_rmap(rmapp);
+		return ret;
+	}
+
+	i = head = *rmapp & KVMPPC_RMAP_INDEX;
+	do {
+		hptep = (unsigned long *) (kvm->arch.hpt_virt + (i << 4));
+		j = rev[i].forw;
+
+		/* If this HPTE isn't referenced, ignore it */
+		if (!(hptep[1] & HPTE_R_R))
+			continue;
+
+		if (!try_lock_hpte(hptep, HPTE_V_HVLOCK)) {
+			/* unlock rmap before spinning on the HPTE lock */
+			unlock_rmap(rmapp);
+			while (hptep[0] & HPTE_V_HVLOCK)
+				cpu_relax();
+			goto retry;
+		}
+
+		/* Now check and modify the HPTE */
+		if ((hptep[0] & HPTE_V_VALID) && (hptep[1] & HPTE_R_R)) {
+			kvmppc_clear_ref_hpte(kvm, hptep, i);
+			rev[i].guest_rpte |= HPTE_R_R;
+			ret = 1;
+		}
+		hptep[0] &= ~HPTE_V_HVLOCK;
+	} while ((i = j) != head);
+
+	unlock_rmap(rmapp);
+	return ret;
+}
+
+int kvm_age_hva(struct kvm *kvm, unsigned long hva)
+{
+	if (!kvm->arch.using_mmu_notifiers)
+		return 0;
+	return kvm_handle_hva(kvm, hva, kvm_age_rmapp);
+}
+
+static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
+			      unsigned long gfn)
+{
+	struct revmap_entry *rev = kvm->arch.revmap;
+	unsigned long head, i, j;
+	unsigned long *hp;
+	int ret = 1;
+
+	if (*rmapp & KVMPPC_RMAP_REFERENCED)
+		return 1;
+
+	lock_rmap(rmapp);
+	if (*rmapp & KVMPPC_RMAP_REFERENCED)
+		goto out;
+
+	if (*rmapp & KVMPPC_RMAP_PRESENT) {
+		i = head = *rmapp & KVMPPC_RMAP_INDEX;
+		do {
+			hp = (unsigned long *)(kvm->arch.hpt_virt + (i << 4));
+			j = rev[i].forw;
+			if (hp[1] & HPTE_R_R)
+				goto out;
+		} while ((i = j) != head);
+	}
+	ret = 0;
+
+ out:
+	unlock_rmap(rmapp);
+	return ret;
+}
+
+int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
+{
+	if (!kvm->arch.using_mmu_notifiers)
+		return 0;
+	return kvm_handle_hva(kvm, hva, kvm_test_age_rmapp);
+}
+
+void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
+{
+	if (!kvm->arch.using_mmu_notifiers)
+		return;
+	kvm_handle_hva(kvm, hva, kvm_unmap_rmapp);
+}
+
+static int kvm_test_clear_dirty(struct kvm *kvm, unsigned long *rmapp)
+{
+	struct revmap_entry *rev = kvm->arch.revmap;
+	unsigned long head, i, j;
+	unsigned long *hptep;
+	int ret = 0;
+
+ retry:
+	lock_rmap(rmapp);
+	if (*rmapp & KVMPPC_RMAP_CHANGED) {
+		*rmapp &= ~KVMPPC_RMAP_CHANGED;
+		ret = 1;
+	}
+	if (!(*rmapp & KVMPPC_RMAP_PRESENT)) {
+		unlock_rmap(rmapp);
+		return ret;
+	}
+
+	i = head = *rmapp & KVMPPC_RMAP_INDEX;
+	do {
+		hptep = (unsigned long *) (kvm->arch.hpt_virt + (i << 4));
+		j = rev[i].forw;
+
+		if (!(hptep[1] & HPTE_R_C))
+			continue;
+
+		if (!try_lock_hpte(hptep, HPTE_V_HVLOCK)) {
+			/* unlock rmap before spinning on the HPTE lock */
+			unlock_rmap(rmapp);
+			while (hptep[0] & HPTE_V_HVLOCK)
+				cpu_relax();
+			goto retry;
+		}
+
+		/* Now check and modify the HPTE */
+		if ((hptep[0] & HPTE_V_VALID) && (hptep[1] & HPTE_R_C)) {
+			/* need to make it temporarily absent to clear C */
+			hptep[0] |= HPTE_V_ABSENT;
+			kvmppc_invalidate_hpte(kvm, hptep, i);
+			hptep[1] &= ~HPTE_R_C;
+			eieio();
+			hptep[0] = (hptep[0] & ~HPTE_V_ABSENT) | HPTE_V_VALID;
+			rev[i].guest_rpte |= HPTE_R_C;
+			ret = 1;
+		}
+		hptep[0] &= ~HPTE_V_HVLOCK;
+	} while ((i = j) != head);
+
+	unlock_rmap(rmapp);
+	return ret;
+}
+
+long kvmppc_hv_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
+{
+	unsigned long i;
+	unsigned long *rmapp, *map;
+
+	preempt_disable();
+	rmapp = memslot->rmap;
+	map = memslot->dirty_bitmap;
+	for (i = 0; i < memslot->npages; ++i) {
+		if (kvm_test_clear_dirty(kvm, rmapp))
+			__set_bit_le(i, map);
+		++rmapp;
+	}
+	preempt_enable();
+	return 0;
+}
+
+void *kvmppc_pin_guest_page(struct kvm *kvm, unsigned long gpa,
+			    unsigned long *nb_ret)
+{
+	struct kvm_memory_slot *memslot;
+	unsigned long gfn = gpa >> PAGE_SHIFT;
+	struct page *page, *pages[1];
+	int npages;
+	unsigned long hva, psize, offset;
+	unsigned long pa;
+	unsigned long *physp;
+
+	memslot = gfn_to_memslot(kvm, gfn);
+	if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID))
+		return NULL;
+	if (!kvm->arch.using_mmu_notifiers) {
+		physp = kvm->arch.slot_phys[memslot->id];
+		if (!physp)
+			return NULL;
+		physp += gfn - memslot->base_gfn;
+		pa = *physp;
+		if (!pa) {
+			if (kvmppc_get_guest_page(kvm, gfn, memslot,
+						  PAGE_SIZE) < 0)
+				return NULL;
+			pa = *physp;
+		}
+		page = pfn_to_page(pa >> PAGE_SHIFT);
+	} else {
+		hva = gfn_to_hva_memslot(memslot, gfn);
+		npages = get_user_pages_fast(hva, 1, 1, pages);
+		if (npages < 1)
+			return NULL;
+		page = pages[0];
+	}
+	psize = PAGE_SIZE;
+	if (PageHuge(page)) {
+		page = compound_head(page);
+		psize <<= compound_order(page);
+	}
+	if (!kvm->arch.using_mmu_notifiers)
+		get_page(page);
+	offset = gpa & (psize - 1);
+	if (nb_ret)
+		*nb_ret = psize - offset;
+	return page_address(page) + offset;
+}
+
+void kvmppc_unpin_guest_page(struct kvm *kvm, void *va)
+{
+	struct page *page = virt_to_page(va);
+
+	page = compound_head(page);
+	put_page(page);
 }
 
 void kvmppc_mmu_book3s_hv_init(struct kvm_vcpu *vcpu)
diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c
index 0c9dc62..135663a 100644
--- a/arch/powerpc/kvm/book3s_emulate.c
+++ b/arch/powerpc/kvm/book3s_emulate.c
@@ -21,6 +21,7 @@
 #include <asm/disassemble.h>
 #include <asm/kvm_book3s.h>
 #include <asm/reg.h>
+#include <asm/switch_to.h>
 
 #define OP_19_XOP_RFID		18
 #define OP_19_XOP_RFI		50
@@ -230,9 +231,12 @@
 
 			r = kvmppc_st(vcpu, &addr, 32, zeros, true);
 			if ((r == -ENOENT) || (r == -EPERM)) {
+				struct kvmppc_book3s_shadow_vcpu *svcpu;
+
+				svcpu = svcpu_get(vcpu);
 				*advance = 0;
 				vcpu->arch.shared->dar = vaddr;
-				to_svcpu(vcpu)->fault_dar = vaddr;
+				svcpu->fault_dar = vaddr;
 
 				dsisr = DSISR_ISSTORE;
 				if (r == -ENOENT)
@@ -241,7 +245,8 @@
 					dsisr |= DSISR_PROTFAULT;
 
 				vcpu->arch.shared->dsisr = dsisr;
-				to_svcpu(vcpu)->fault_dsisr = dsisr;
+				svcpu->fault_dsisr = dsisr;
+				svcpu_put(svcpu);
 
 				kvmppc_book3s_queue_irqprio(vcpu,
 					BOOK3S_INTERRUPT_DATA_STORAGE);
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 336983d..01294a5 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -45,26 +45,18 @@
 #include <asm/cputhreads.h>
 #include <asm/page.h>
 #include <asm/hvcall.h>
+#include <asm/switch_to.h>
 #include <linux/gfp.h>
-#include <linux/sched.h>
 #include <linux/vmalloc.h>
 #include <linux/highmem.h>
-
-/*
- * For now, limit memory to 64GB and require it to be large pages.
- * This value is chosen because it makes the ram_pginfo array be
- * 64kB in size, which is about as large as we want to be trying
- * to allocate with kmalloc.
- */
-#define MAX_MEM_ORDER		36
-
-#define LARGE_PAGE_ORDER	24	/* 16MB pages */
+#include <linux/hugetlb.h>
 
 /* #define EXIT_DEBUG */
 /* #define EXIT_DEBUG_SIMPLE */
 /* #define EXIT_DEBUG_INT */
 
 static void kvmppc_end_cede(struct kvm_vcpu *vcpu);
+static int kvmppc_hv_setup_rma(struct kvm_vcpu *vcpu);
 
 void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
@@ -147,10 +139,10 @@
 				       unsigned long vcpuid, unsigned long vpa)
 {
 	struct kvm *kvm = vcpu->kvm;
-	unsigned long pg_index, ra, len;
-	unsigned long pg_offset;
+	unsigned long len, nb;
 	void *va;
 	struct kvm_vcpu *tvcpu;
+	int err = H_PARAMETER;
 
 	tvcpu = kvmppc_find_vcpu(kvm, vcpuid);
 	if (!tvcpu)
@@ -163,45 +155,41 @@
 	if (flags < 4) {
 		if (vpa & 0x7f)
 			return H_PARAMETER;
+		if (flags >= 2 && !tvcpu->arch.vpa)
+			return H_RESOURCE;
 		/* registering new area; convert logical addr to real */
-		pg_index = vpa >> kvm->arch.ram_porder;
-		pg_offset = vpa & (kvm->arch.ram_psize - 1);
-		if (pg_index >= kvm->arch.ram_npages)
+		va = kvmppc_pin_guest_page(kvm, vpa, &nb);
+		if (va == NULL)
 			return H_PARAMETER;
-		if (kvm->arch.ram_pginfo[pg_index].pfn == 0)
-			return H_PARAMETER;
-		ra = kvm->arch.ram_pginfo[pg_index].pfn << PAGE_SHIFT;
-		ra |= pg_offset;
-		va = __va(ra);
 		if (flags <= 1)
 			len = *(unsigned short *)(va + 4);
 		else
 			len = *(unsigned int *)(va + 4);
-		if (pg_offset + len > kvm->arch.ram_psize)
-			return H_PARAMETER;
+		if (len > nb)
+			goto out_unpin;
 		switch (flags) {
 		case 1:		/* register VPA */
 			if (len < 640)
-				return H_PARAMETER;
+				goto out_unpin;
+			if (tvcpu->arch.vpa)
+				kvmppc_unpin_guest_page(kvm, vcpu->arch.vpa);
 			tvcpu->arch.vpa = va;
 			init_vpa(vcpu, va);
 			break;
 		case 2:		/* register DTL */
 			if (len < 48)
-				return H_PARAMETER;
-			if (!tvcpu->arch.vpa)
-				return H_RESOURCE;
+				goto out_unpin;
 			len -= len % 48;
+			if (tvcpu->arch.dtl)
+				kvmppc_unpin_guest_page(kvm, vcpu->arch.dtl);
 			tvcpu->arch.dtl = va;
 			tvcpu->arch.dtl_end = va + len;
 			break;
 		case 3:		/* register SLB shadow buffer */
-			if (len < 8)
-				return H_PARAMETER;
-			if (!tvcpu->arch.vpa)
-				return H_RESOURCE;
-			tvcpu->arch.slb_shadow = va;
-			len = (len - 16) / 16;
+			if (len < 16)
+				goto out_unpin;
+			if (tvcpu->arch.slb_shadow)
+				kvmppc_unpin_guest_page(kvm, vcpu->arch.slb_shadow);
 			tvcpu->arch.slb_shadow = va;
 			break;
 		}
@@ -210,17 +198,30 @@
 		case 5:		/* unregister VPA */
 			if (tvcpu->arch.slb_shadow || tvcpu->arch.dtl)
 				return H_RESOURCE;
+			if (!tvcpu->arch.vpa)
+				break;
+			kvmppc_unpin_guest_page(kvm, tvcpu->arch.vpa);
 			tvcpu->arch.vpa = NULL;
 			break;
 		case 6:		/* unregister DTL */
+			if (!tvcpu->arch.dtl)
+				break;
+			kvmppc_unpin_guest_page(kvm, tvcpu->arch.dtl);
 			tvcpu->arch.dtl = NULL;
 			break;
 		case 7:		/* unregister SLB shadow buffer */
+			if (!tvcpu->arch.slb_shadow)
+				break;
+			kvmppc_unpin_guest_page(kvm, tvcpu->arch.slb_shadow);
 			tvcpu->arch.slb_shadow = NULL;
 			break;
 		}
 	}
 	return H_SUCCESS;
+
+ out_unpin:
+	kvmppc_unpin_guest_page(kvm, va);
+	return err;
 }
 
 int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
@@ -230,6 +231,12 @@
 	struct kvm_vcpu *tvcpu;
 
 	switch (req) {
+	case H_ENTER:
+		ret = kvmppc_virtmode_h_enter(vcpu, kvmppc_get_gpr(vcpu, 4),
+					      kvmppc_get_gpr(vcpu, 5),
+					      kvmppc_get_gpr(vcpu, 6),
+					      kvmppc_get_gpr(vcpu, 7));
+		break;
 	case H_CEDE:
 		break;
 	case H_PROD:
@@ -319,20 +326,19 @@
 		break;
 	}
 	/*
-	 * We get these next two if the guest does a bad real-mode access,
-	 * as we have enabled VRMA (virtualized real mode area) mode in the
-	 * LPCR.  We just generate an appropriate DSI/ISI to the guest.
+	 * We get these next two if the guest accesses a page which it thinks
+	 * it has mapped but which is not actually present, either because
+	 * it is for an emulated I/O device or because the corresonding
+	 * host page has been paged out.  Any other HDSI/HISI interrupts
+	 * have been handled already.
 	 */
 	case BOOK3S_INTERRUPT_H_DATA_STORAGE:
-		vcpu->arch.shregs.dsisr = vcpu->arch.fault_dsisr;
-		vcpu->arch.shregs.dar = vcpu->arch.fault_dar;
-		kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE, 0);
-		r = RESUME_GUEST;
+		r = kvmppc_book3s_hv_page_fault(run, vcpu,
+				vcpu->arch.fault_dar, vcpu->arch.fault_dsisr);
 		break;
 	case BOOK3S_INTERRUPT_H_INST_STORAGE:
-		kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_INST_STORAGE,
-					0x08000000);
-		r = RESUME_GUEST;
+		r = kvmppc_book3s_hv_page_fault(run, vcpu,
+				kvmppc_get_pc(vcpu), 0);
 		break;
 	/*
 	 * This occurs if the guest executes an illegal instruction.
@@ -392,6 +398,42 @@
 	return 0;
 }
 
+int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+{
+	int r = -EINVAL;
+
+	switch (reg->id) {
+	case KVM_REG_PPC_HIOR:
+		r = put_user(0, (u64 __user *)reg->addr);
+		break;
+	default:
+		break;
+	}
+
+	return r;
+}
+
+int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+{
+	int r = -EINVAL;
+
+	switch (reg->id) {
+	case KVM_REG_PPC_HIOR:
+	{
+		u64 hior;
+		/* Only allow this to be set to zero */
+		r = get_user(hior, (u64 __user *)reg->addr);
+		if (!r && (hior != 0))
+			r = -EINVAL;
+		break;
+	}
+	default:
+		break;
+	}
+
+	return r;
+}
+
 int kvmppc_core_check_processor_compat(void)
 {
 	if (cpu_has_feature(CPU_FTR_HVMODE))
@@ -411,7 +453,7 @@
 		goto out;
 
 	err = -ENOMEM;
-	vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
+	vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
 	if (!vcpu)
 		goto out;
 
@@ -463,15 +505,21 @@
 	return vcpu;
 
 free_vcpu:
-	kfree(vcpu);
+	kmem_cache_free(kvm_vcpu_cache, vcpu);
 out:
 	return ERR_PTR(err);
 }
 
 void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
 {
+	if (vcpu->arch.dtl)
+		kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.dtl);
+	if (vcpu->arch.slb_shadow)
+		kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.slb_shadow);
+	if (vcpu->arch.vpa)
+		kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.vpa);
 	kvm_vcpu_uninit(vcpu);
-	kfree(vcpu);
+	kmem_cache_free(kvm_vcpu_cache, vcpu);
 }
 
 static void kvmppc_set_timer(struct kvm_vcpu *vcpu)
@@ -482,7 +530,7 @@
 	if (now > vcpu->arch.dec_expires) {
 		/* decrementer has already gone negative */
 		kvmppc_core_queue_dec(vcpu);
-		kvmppc_core_deliver_interrupts(vcpu);
+		kvmppc_core_prepare_to_enter(vcpu);
 		return;
 	}
 	dec_nsec = (vcpu->arch.dec_expires - now) * NSEC_PER_SEC
@@ -797,7 +845,7 @@
 
 		list_for_each_entry_safe(v, vn, &vc->runnable_threads,
 					 arch.run_list) {
-			kvmppc_core_deliver_interrupts(v);
+			kvmppc_core_prepare_to_enter(v);
 			if (signal_pending(v->arch.run_task)) {
 				kvmppc_remove_runnable(vc, v);
 				v->stat.signal_exits++;
@@ -836,20 +884,26 @@
 		return -EINVAL;
 	}
 
+	kvmppc_core_prepare_to_enter(vcpu);
+
 	/* No need to go into the guest when all we'll do is come back out */
 	if (signal_pending(current)) {
 		run->exit_reason = KVM_EXIT_INTR;
 		return -EINTR;
 	}
 
-	/* On PPC970, check that we have an RMA region */
-	if (!vcpu->kvm->arch.rma && cpu_has_feature(CPU_FTR_ARCH_201))
-		return -EPERM;
+	/* On the first time here, set up VRMA or RMA */
+	if (!vcpu->kvm->arch.rma_setup_done) {
+		r = kvmppc_hv_setup_rma(vcpu);
+		if (r)
+			return r;
+	}
 
 	flush_fp_to_thread(current);
 	flush_altivec_to_thread(current);
 	flush_vsx_to_thread(current);
 	vcpu->arch.wqp = &vcpu->arch.vcore->wq;
+	vcpu->arch.pgdir = current->mm->pgd;
 
 	do {
 		r = kvmppc_run_vcpu(run, vcpu);
@@ -857,7 +911,7 @@
 		if (run->exit_reason == KVM_EXIT_PAPR_HCALL &&
 		    !(vcpu->arch.shregs.msr & MSR_PR)) {
 			r = kvmppc_pseries_do_hcall(vcpu);
-			kvmppc_core_deliver_interrupts(vcpu);
+			kvmppc_core_prepare_to_enter(vcpu);
 		}
 	} while (r == RESUME_GUEST);
 	return r;
@@ -1001,7 +1055,7 @@
 
 static int kvm_rma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
-	struct kvmppc_rma_info *ri = vma->vm_file->private_data;
+	struct kvmppc_linear_info *ri = vma->vm_file->private_data;
 	struct page *page;
 
 	if (vmf->pgoff >= ri->npages)
@@ -1026,7 +1080,7 @@
 
 static int kvm_rma_release(struct inode *inode, struct file *filp)
 {
-	struct kvmppc_rma_info *ri = filp->private_data;
+	struct kvmppc_linear_info *ri = filp->private_data;
 
 	kvm_release_rma(ri);
 	return 0;
@@ -1039,7 +1093,7 @@
 
 long kvm_vm_ioctl_allocate_rma(struct kvm *kvm, struct kvm_allocate_rma *ret)
 {
-	struct kvmppc_rma_info *ri;
+	struct kvmppc_linear_info *ri;
 	long fd;
 
 	ri = kvm_alloc_rma();
@@ -1054,89 +1108,189 @@
 	return fd;
 }
 
-static struct page *hva_to_page(unsigned long addr)
+/*
+ * Get (and clear) the dirty memory log for a memory slot.
+ */
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
 {
-	struct page *page[1];
-	int npages;
+	struct kvm_memory_slot *memslot;
+	int r;
+	unsigned long n;
 
-	might_sleep();
+	mutex_lock(&kvm->slots_lock);
 
-	npages = get_user_pages_fast(addr, 1, 1, page);
+	r = -EINVAL;
+	if (log->slot >= KVM_MEMORY_SLOTS)
+		goto out;
 
-	if (unlikely(npages != 1))
-		return 0;
+	memslot = id_to_memslot(kvm->memslots, log->slot);
+	r = -ENOENT;
+	if (!memslot->dirty_bitmap)
+		goto out;
 
-	return page[0];
+	n = kvm_dirty_bitmap_bytes(memslot);
+	memset(memslot->dirty_bitmap, 0, n);
+
+	r = kvmppc_hv_get_dirty_log(kvm, memslot);
+	if (r)
+		goto out;
+
+	r = -EFAULT;
+	if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
+		goto out;
+
+	r = 0;
+out:
+	mutex_unlock(&kvm->slots_lock);
+	return r;
+}
+
+static unsigned long slb_pgsize_encoding(unsigned long psize)
+{
+	unsigned long senc = 0;
+
+	if (psize > 0x1000) {
+		senc = SLB_VSID_L;
+		if (psize == 0x10000)
+			senc |= SLB_VSID_LP_01;
+	}
+	return senc;
 }
 
 int kvmppc_core_prepare_memory_region(struct kvm *kvm,
 				struct kvm_userspace_memory_region *mem)
 {
-	unsigned long psize, porder;
-	unsigned long i, npages, totalpages;
-	unsigned long pg_ix;
-	struct kvmppc_pginfo *pginfo;
-	unsigned long hva;
-	struct kvmppc_rma_info *ri = NULL;
+	unsigned long npages;
+	unsigned long *phys;
+
+	/* Allocate a slot_phys array */
+	phys = kvm->arch.slot_phys[mem->slot];
+	if (!kvm->arch.using_mmu_notifiers && !phys) {
+		npages = mem->memory_size >> PAGE_SHIFT;
+		phys = vzalloc(npages * sizeof(unsigned long));
+		if (!phys)
+			return -ENOMEM;
+		kvm->arch.slot_phys[mem->slot] = phys;
+		kvm->arch.slot_npages[mem->slot] = npages;
+	}
+
+	return 0;
+}
+
+static void unpin_slot(struct kvm *kvm, int slot_id)
+{
+	unsigned long *physp;
+	unsigned long j, npages, pfn;
 	struct page *page;
 
-	/* For now, only allow 16MB pages */
-	porder = LARGE_PAGE_ORDER;
-	psize = 1ul << porder;
-	if ((mem->memory_size & (psize - 1)) ||
-	    (mem->guest_phys_addr & (psize - 1))) {
-		pr_err("bad memory_size=%llx @ %llx\n",
-		       mem->memory_size, mem->guest_phys_addr);
-		return -EINVAL;
+	physp = kvm->arch.slot_phys[slot_id];
+	npages = kvm->arch.slot_npages[slot_id];
+	if (physp) {
+		spin_lock(&kvm->arch.slot_phys_lock);
+		for (j = 0; j < npages; j++) {
+			if (!(physp[j] & KVMPPC_GOT_PAGE))
+				continue;
+			pfn = physp[j] >> PAGE_SHIFT;
+			page = pfn_to_page(pfn);
+			if (PageHuge(page))
+				page = compound_head(page);
+			SetPageDirty(page);
+			put_page(page);
+		}
+		kvm->arch.slot_phys[slot_id] = NULL;
+		spin_unlock(&kvm->arch.slot_phys_lock);
+		vfree(physp);
 	}
+}
 
-	npages = mem->memory_size >> porder;
-	totalpages = (mem->guest_phys_addr + mem->memory_size) >> porder;
+void kvmppc_core_commit_memory_region(struct kvm *kvm,
+				struct kvm_userspace_memory_region *mem)
+{
+}
 
-	/* More memory than we have space to track? */
-	if (totalpages > (1ul << (MAX_MEM_ORDER - LARGE_PAGE_ORDER)))
-		return -EINVAL;
+static int kvmppc_hv_setup_rma(struct kvm_vcpu *vcpu)
+{
+	int err = 0;
+	struct kvm *kvm = vcpu->kvm;
+	struct kvmppc_linear_info *ri = NULL;
+	unsigned long hva;
+	struct kvm_memory_slot *memslot;
+	struct vm_area_struct *vma;
+	unsigned long lpcr, senc;
+	unsigned long psize, porder;
+	unsigned long rma_size;
+	unsigned long rmls;
+	unsigned long *physp;
+	unsigned long i, npages;
 
-	/* Do we already have an RMA registered? */
-	if (mem->guest_phys_addr == 0 && kvm->arch.rma)
-		return -EINVAL;
+	mutex_lock(&kvm->lock);
+	if (kvm->arch.rma_setup_done)
+		goto out;	/* another vcpu beat us to it */
 
-	if (totalpages > kvm->arch.ram_npages)
-		kvm->arch.ram_npages = totalpages;
+	/* Look up the memslot for guest physical address 0 */
+	memslot = gfn_to_memslot(kvm, 0);
+
+	/* We must have some memory at 0 by now */
+	err = -EINVAL;
+	if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID))
+		goto out;
+
+	/* Look up the VMA for the start of this memory slot */
+	hva = memslot->userspace_addr;
+	down_read(&current->mm->mmap_sem);
+	vma = find_vma(current->mm, hva);
+	if (!vma || vma->vm_start > hva || (vma->vm_flags & VM_IO))
+		goto up_out;
+
+	psize = vma_kernel_pagesize(vma);
+	porder = __ilog2(psize);
 
 	/* Is this one of our preallocated RMAs? */
-	if (mem->guest_phys_addr == 0) {
-		struct vm_area_struct *vma;
+	if (vma->vm_file && vma->vm_file->f_op == &kvm_rma_fops &&
+	    hva == vma->vm_start)
+		ri = vma->vm_file->private_data;
 
-		down_read(&current->mm->mmap_sem);
-		vma = find_vma(current->mm, mem->userspace_addr);
-		if (vma && vma->vm_file &&
-		    vma->vm_file->f_op == &kvm_rma_fops &&
-		    mem->userspace_addr == vma->vm_start)
-			ri = vma->vm_file->private_data;
-		up_read(&current->mm->mmap_sem);
-		if (!ri && cpu_has_feature(CPU_FTR_ARCH_201)) {
-			pr_err("CPU requires an RMO\n");
-			return -EINVAL;
+	up_read(&current->mm->mmap_sem);
+
+	if (!ri) {
+		/* On POWER7, use VRMA; on PPC970, give up */
+		err = -EPERM;
+		if (cpu_has_feature(CPU_FTR_ARCH_201)) {
+			pr_err("KVM: CPU requires an RMO\n");
+			goto out;
 		}
-	}
 
-	if (ri) {
-		unsigned long rma_size;
-		unsigned long lpcr;
-		long rmls;
+		/* We can handle 4k, 64k or 16M pages in the VRMA */
+		err = -EINVAL;
+		if (!(psize == 0x1000 || psize == 0x10000 ||
+		      psize == 0x1000000))
+			goto out;
 
-		rma_size = ri->npages << PAGE_SHIFT;
-		if (rma_size > mem->memory_size)
-			rma_size = mem->memory_size;
+		/* Update VRMASD field in the LPCR */
+		senc = slb_pgsize_encoding(psize);
+		kvm->arch.vrma_slb_v = senc | SLB_VSID_B_1T |
+			(VRMA_VSID << SLB_VSID_SHIFT_1T);
+		lpcr = kvm->arch.lpcr & ~LPCR_VRMASD;
+		lpcr |= senc << (LPCR_VRMASD_SH - 4);
+		kvm->arch.lpcr = lpcr;
+
+		/* Create HPTEs in the hash page table for the VRMA */
+		kvmppc_map_vrma(vcpu, memslot, porder);
+
+	} else {
+		/* Set up to use an RMO region */
+		rma_size = ri->npages;
+		if (rma_size > memslot->npages)
+			rma_size = memslot->npages;
+		rma_size <<= PAGE_SHIFT;
 		rmls = lpcr_rmls(rma_size);
+		err = -EINVAL;
 		if (rmls < 0) {
-			pr_err("Can't use RMA of 0x%lx bytes\n", rma_size);
-			return -EINVAL;
+			pr_err("KVM: Can't use RMA of 0x%lx bytes\n", rma_size);
+			goto out;
 		}
 		atomic_inc(&ri->use_count);
 		kvm->arch.rma = ri;
-		kvm->arch.n_rma_pages = rma_size >> porder;
 
 		/* Update LPCR and RMOR */
 		lpcr = kvm->arch.lpcr;
@@ -1156,53 +1310,35 @@
 			kvm->arch.rmor = kvm->arch.rma->base_pfn << PAGE_SHIFT;
 		}
 		kvm->arch.lpcr = lpcr;
-		pr_info("Using RMO at %lx size %lx (LPCR = %lx)\n",
+		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;
+		porder = __ilog2(npages);
+		physp = kvm->arch.slot_phys[memslot->id];
+		spin_lock(&kvm->arch.slot_phys_lock);
+		for (i = 0; i < npages; ++i)
+			physp[i] = ((ri->base_pfn + i) << PAGE_SHIFT) + porder;
+		spin_unlock(&kvm->arch.slot_phys_lock);
 	}
 
-	pg_ix = mem->guest_phys_addr >> porder;
-	pginfo = kvm->arch.ram_pginfo + pg_ix;
-	for (i = 0; i < npages; ++i, ++pg_ix) {
-		if (ri && pg_ix < kvm->arch.n_rma_pages) {
-			pginfo[i].pfn = ri->base_pfn +
-				(pg_ix << (porder - PAGE_SHIFT));
-			continue;
-		}
-		hva = mem->userspace_addr + (i << porder);
-		page = hva_to_page(hva);
-		if (!page) {
-			pr_err("oops, no pfn for hva %lx\n", hva);
-			goto err;
-		}
-		/* Check it's a 16MB page */
-		if (!PageHead(page) ||
-		    compound_order(page) != (LARGE_PAGE_ORDER - PAGE_SHIFT)) {
-			pr_err("page at %lx isn't 16MB (o=%d)\n",
-			       hva, compound_order(page));
-			goto err;
-		}
-		pginfo[i].pfn = page_to_pfn(page);
-	}
+	/* Order updates to kvm->arch.lpcr etc. vs. rma_setup_done */
+	smp_wmb();
+	kvm->arch.rma_setup_done = 1;
+	err = 0;
+ out:
+	mutex_unlock(&kvm->lock);
+	return err;
 
-	return 0;
-
- err:
-	return -EINVAL;
-}
-
-void kvmppc_core_commit_memory_region(struct kvm *kvm,
-				struct kvm_userspace_memory_region *mem)
-{
-	if (mem->guest_phys_addr == 0 && mem->memory_size != 0 &&
-	    !kvm->arch.rma)
-		kvmppc_map_vrma(kvm, mem);
+ up_out:
+	up_read(&current->mm->mmap_sem);
+	goto out;
 }
 
 int kvmppc_core_init_vm(struct kvm *kvm)
 {
 	long r;
-	unsigned long npages = 1ul << (MAX_MEM_ORDER - LARGE_PAGE_ORDER);
-	long err = -ENOMEM;
 	unsigned long lpcr;
 
 	/* Allocate hashed page table */
@@ -1212,19 +1348,7 @@
 
 	INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables);
 
-	kvm->arch.ram_pginfo = kzalloc(npages * sizeof(struct kvmppc_pginfo),
-				       GFP_KERNEL);
-	if (!kvm->arch.ram_pginfo) {
-		pr_err("kvmppc_core_init_vm: couldn't alloc %lu bytes\n",
-		       npages * sizeof(struct kvmppc_pginfo));
-		goto out_free;
-	}
-
-	kvm->arch.ram_npages = 0;
-	kvm->arch.ram_psize = 1ul << LARGE_PAGE_ORDER;
-	kvm->arch.ram_porder = LARGE_PAGE_ORDER;
 	kvm->arch.rma = NULL;
-	kvm->arch.n_rma_pages = 0;
 
 	kvm->arch.host_sdr1 = mfspr(SPRN_SDR1);
 
@@ -1242,30 +1366,25 @@
 		kvm->arch.host_lpcr = lpcr = mfspr(SPRN_LPCR);
 		lpcr &= LPCR_PECE | LPCR_LPES;
 		lpcr |= (4UL << LPCR_DPFD_SH) | LPCR_HDICE |
-			LPCR_VPM0 | LPCR_VRMA_L;
+			LPCR_VPM0 | LPCR_VPM1;
+		kvm->arch.vrma_slb_v = SLB_VSID_B_1T |
+			(VRMA_VSID << SLB_VSID_SHIFT_1T);
 	}
 	kvm->arch.lpcr = lpcr;
 
+	kvm->arch.using_mmu_notifiers = !!cpu_has_feature(CPU_FTR_ARCH_206);
+	spin_lock_init(&kvm->arch.slot_phys_lock);
 	return 0;
-
- out_free:
-	kvmppc_free_hpt(kvm);
-	return err;
 }
 
 void kvmppc_core_destroy_vm(struct kvm *kvm)
 {
-	struct kvmppc_pginfo *pginfo;
 	unsigned long i;
 
-	if (kvm->arch.ram_pginfo) {
-		pginfo = kvm->arch.ram_pginfo;
-		kvm->arch.ram_pginfo = NULL;
-		for (i = kvm->arch.n_rma_pages; i < kvm->arch.ram_npages; ++i)
-			if (pginfo[i].pfn)
-				put_page(pfn_to_page(pginfo[i].pfn));
-		kfree(pginfo);
-	}
+	if (!kvm->arch.using_mmu_notifiers)
+		for (i = 0; i < KVM_MEM_SLOTS_NUM; i++)
+			unpin_slot(kvm, i);
+
 	if (kvm->arch.rma) {
 		kvm_release_rma(kvm->arch.rma);
 		kvm->arch.rma = NULL;
diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c
index a795a13..bed1279 100644
--- a/arch/powerpc/kvm/book3s_hv_builtin.c
+++ b/arch/powerpc/kvm/book3s_hv_builtin.c
@@ -18,6 +18,15 @@
 #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);
+
+/*************** RMA *************/
+
 /*
  * This maintains a list of RMAs (real mode areas) for KVM guests to use.
  * Each RMA has to be physically contiguous and of a size that the
@@ -29,32 +38,6 @@
 static unsigned long kvm_rma_size = 64 << 20;	/* 64MB */
 static unsigned long kvm_rma_count;
 
-static int __init early_parse_rma_size(char *p)
-{
-	if (!p)
-		return 1;
-
-	kvm_rma_size = memparse(p, &p);
-
-	return 0;
-}
-early_param("kvm_rma_size", early_parse_rma_size);
-
-static int __init early_parse_rma_count(char *p)
-{
-	if (!p)
-		return 1;
-
-	kvm_rma_count = simple_strtoul(p, NULL, 0);
-
-	return 0;
-}
-early_param("kvm_rma_count", early_parse_rma_count);
-
-static struct kvmppc_rma_info *rma_info;
-static LIST_HEAD(free_rmas);
-static DEFINE_SPINLOCK(rma_lock);
-
 /* Work out RMLS (real mode limit selector) field value for a given RMA size.
    Assumes POWER7 or PPC970. */
 static inline int lpcr_rmls(unsigned long rma_size)
@@ -81,18 +64,153 @@
 	}
 }
 
+static int __init early_parse_rma_size(char *p)
+{
+	if (!p)
+		return 1;
+
+	kvm_rma_size = memparse(p, &p);
+
+	return 0;
+}
+early_param("kvm_rma_size", early_parse_rma_size);
+
+static int __init early_parse_rma_count(char *p)
+{
+	if (!p)
+		return 1;
+
+	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);
+}
+EXPORT_SYMBOL_GPL(kvm_alloc_rma);
+
+void kvm_release_rma(struct kvmppc_linear_info *ri)
+{
+	kvm_release_linear(ri);
+}
+EXPORT_SYMBOL_GPL(kvm_release_rma);
+
+/*************** HPT *************/
+
 /*
- * Called at boot time while the bootmem allocator is active,
- * to allocate contiguous physical memory for the real memory
- * areas for guests.
+ * 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.
  */
-void __init kvm_rma_init(void)
+
+static unsigned long kvm_hpt_count;
+
+static int __init early_parse_hpt_count(char *p)
+{
+	if (!p)
+		return 1;
+
+	kvm_hpt_count = simple_strtoul(p, NULL, 0);
+
+	return 0;
+}
+early_param("kvm_hpt_count", early_parse_hpt_count);
+
+struct kvmppc_linear_info *kvm_alloc_hpt(void)
+{
+	return kvm_alloc_linear(KVM_LINEAR_HPT);
+}
+EXPORT_SYMBOL_GPL(kvm_alloc_hpt);
+
+void kvm_release_hpt(struct kvmppc_linear_info *li)
+{
+	kvm_release_linear(li);
+}
+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 *rma;
+	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_info("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;
+
+	ri = 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);
+		break;
+	}
+	spin_unlock(&linear_lock);
+	memset(ri->base_virt, 0, ri->npages << PAGE_SHIFT);
+	return ri;
+}
+
+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.
+ */
+void __init kvm_linear_init(void)
+{
+	/* HPT */
+	kvm_linear_init_one(1 << HPT_ORDER, kvm_hpt_count, KVM_LINEAR_HPT);
+
+	/* RMA */
 	/* Only do this on PPC970 in HV mode */
 	if (!cpu_has_feature(CPU_FTR_HVMODE) ||
 	    !cpu_has_feature(CPU_FTR_ARCH_201))
@@ -107,50 +225,5 @@
 		return;
 	}
 
-	npages = kvm_rma_size >> PAGE_SHIFT;
-	rma_info = alloc_bootmem(kvm_rma_count * sizeof(struct kvmppc_rma_info));
-	for (i = 0; i < kvm_rma_count; ++i) {
-		rma = alloc_bootmem_align(kvm_rma_size, kvm_rma_size);
-		pr_info("Allocated KVM RMA at %p (%ld MB)\n", rma,
-			kvm_rma_size >> 20);
-		rma_info[i].base_virt = rma;
-		rma_info[i].base_pfn = __pa(rma) >> PAGE_SHIFT;
-		rma_info[i].npages = npages;
-		list_add_tail(&rma_info[i].list, &free_rmas);
-		atomic_set(&rma_info[i].use_count, 0);
-
-		pg = pfn_to_page(rma_info[i].base_pfn);
-		for (j = 0; j < npages; ++j) {
-			atomic_inc(&pg->_count);
-			++pg;
-		}
-	}
+	kvm_linear_init_one(kvm_rma_size, kvm_rma_count, KVM_LINEAR_RMA);
 }
-
-struct kvmppc_rma_info *kvm_alloc_rma(void)
-{
-	struct kvmppc_rma_info *ri;
-
-	ri = NULL;
-	spin_lock(&rma_lock);
-	if (!list_empty(&free_rmas)) {
-		ri = list_first_entry(&free_rmas, struct kvmppc_rma_info, list);
-		list_del(&ri->list);
-		atomic_inc(&ri->use_count);
-	}
-	spin_unlock(&rma_lock);
-	return ri;
-}
-EXPORT_SYMBOL_GPL(kvm_alloc_rma);
-
-void kvm_release_rma(struct kvmppc_rma_info *ri)
-{
-	if (atomic_dec_and_test(&ri->use_count)) {
-		spin_lock(&rma_lock);
-		list_add_tail(&ri->list, &free_rmas);
-		spin_unlock(&rma_lock);
-
-	}
-}
-EXPORT_SYMBOL_GPL(kvm_release_rma);
-
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index bacb0cf..def880a 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -11,6 +11,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/hugetlb.h>
+#include <linux/module.h>
 
 #include <asm/tlbflush.h>
 #include <asm/kvm_ppc.h>
@@ -20,95 +21,307 @@
 #include <asm/synch.h>
 #include <asm/ppc-opcode.h>
 
-/* For now use fixed-size 16MB page table */
-#define HPT_ORDER	24
-#define HPT_NPTEG	(1ul << (HPT_ORDER - 7))	/* 128B per pteg */
-#define HPT_HASH_MASK	(HPT_NPTEG - 1)
-
-#define HPTE_V_HVLOCK	0x40UL
-
-static inline long lock_hpte(unsigned long *hpte, unsigned long bits)
+/* Translate address of a vmalloc'd thing to a linear map address */
+static void *real_vmalloc_addr(void *x)
 {
-	unsigned long tmp, old;
+	unsigned long addr = (unsigned long) x;
+	pte_t *p;
 
-	asm volatile("	ldarx	%0,0,%2\n"
-		     "	and.	%1,%0,%3\n"
-		     "	bne	2f\n"
-		     "	ori	%0,%0,%4\n"
-		     "  stdcx.	%0,0,%2\n"
-		     "	beq+	2f\n"
-		     "	li	%1,%3\n"
-		     "2:	isync"
-		     : "=&r" (tmp), "=&r" (old)
-		     : "r" (hpte), "r" (bits), "i" (HPTE_V_HVLOCK)
-		     : "cc", "memory");
-	return old == 0;
+	p = find_linux_pte(swapper_pg_dir, addr);
+	if (!p || !pte_present(*p))
+		return NULL;
+	/* assume we don't have huge pages in vmalloc space... */
+	addr = (pte_pfn(*p) << PAGE_SHIFT) | (addr & ~PAGE_MASK);
+	return __va(addr);
+}
+
+/*
+ * Add this HPTE into the chain for the real page.
+ * Must be called with the chain locked; it unlocks the chain.
+ */
+void kvmppc_add_revmap_chain(struct kvm *kvm, struct revmap_entry *rev,
+			     unsigned long *rmap, long pte_index, int realmode)
+{
+	struct revmap_entry *head, *tail;
+	unsigned long i;
+
+	if (*rmap & KVMPPC_RMAP_PRESENT) {
+		i = *rmap & KVMPPC_RMAP_INDEX;
+		head = &kvm->arch.revmap[i];
+		if (realmode)
+			head = real_vmalloc_addr(head);
+		tail = &kvm->arch.revmap[head->back];
+		if (realmode)
+			tail = real_vmalloc_addr(tail);
+		rev->forw = i;
+		rev->back = head->back;
+		tail->forw = pte_index;
+		head->back = pte_index;
+	} else {
+		rev->forw = rev->back = pte_index;
+		i = pte_index;
+	}
+	smp_wmb();
+	*rmap = i | KVMPPC_RMAP_REFERENCED | KVMPPC_RMAP_PRESENT; /* unlock */
+}
+EXPORT_SYMBOL_GPL(kvmppc_add_revmap_chain);
+
+/* Remove this HPTE from the chain for a real page */
+static void remove_revmap_chain(struct kvm *kvm, long pte_index,
+				struct revmap_entry *rev,
+				unsigned long hpte_v, unsigned long hpte_r)
+{
+	struct revmap_entry *next, *prev;
+	unsigned long gfn, ptel, head;
+	struct kvm_memory_slot *memslot;
+	unsigned long *rmap;
+	unsigned long rcbits;
+
+	rcbits = hpte_r & (HPTE_R_R | HPTE_R_C);
+	ptel = rev->guest_rpte |= rcbits;
+	gfn = hpte_rpn(ptel, hpte_page_size(hpte_v, ptel));
+	memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn);
+	if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID))
+		return;
+
+	rmap = real_vmalloc_addr(&memslot->rmap[gfn - memslot->base_gfn]);
+	lock_rmap(rmap);
+
+	head = *rmap & KVMPPC_RMAP_INDEX;
+	next = real_vmalloc_addr(&kvm->arch.revmap[rev->forw]);
+	prev = real_vmalloc_addr(&kvm->arch.revmap[rev->back]);
+	next->back = rev->back;
+	prev->forw = rev->forw;
+	if (head == pte_index) {
+		head = rev->forw;
+		if (head == pte_index)
+			*rmap &= ~(KVMPPC_RMAP_PRESENT | KVMPPC_RMAP_INDEX);
+		else
+			*rmap = (*rmap & ~KVMPPC_RMAP_INDEX) | head;
+	}
+	*rmap |= rcbits << KVMPPC_RMAP_RC_SHIFT;
+	unlock_rmap(rmap);
+}
+
+static pte_t lookup_linux_pte(struct kvm_vcpu *vcpu, unsigned long hva,
+			      int writing, unsigned long *pte_sizep)
+{
+	pte_t *ptep;
+	unsigned long ps = *pte_sizep;
+	unsigned int shift;
+
+	ptep = find_linux_pte_or_hugepte(vcpu->arch.pgdir, hva, &shift);
+	if (!ptep)
+		return __pte(0);
+	if (shift)
+		*pte_sizep = 1ul << shift;
+	else
+		*pte_sizep = PAGE_SIZE;
+	if (ps > *pte_sizep)
+		return __pte(0);
+	if (!pte_present(*ptep))
+		return __pte(0);
+	return kvmppc_read_update_linux_pte(ptep, writing);
+}
+
+static inline void unlock_hpte(unsigned long *hpte, unsigned long hpte_v)
+{
+	asm volatile(PPC_RELEASE_BARRIER "" : : : "memory");
+	hpte[0] = hpte_v;
 }
 
 long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
 		    long pte_index, unsigned long pteh, unsigned long ptel)
 {
-	unsigned long porder;
 	struct kvm *kvm = vcpu->kvm;
-	unsigned long i, lpn, pa;
+	unsigned long i, pa, gpa, gfn, psize;
+	unsigned long slot_fn, hva;
 	unsigned long *hpte;
+	struct revmap_entry *rev;
+	unsigned long g_ptel = ptel;
+	struct kvm_memory_slot *memslot;
+	unsigned long *physp, pte_size;
+	unsigned long is_io;
+	unsigned long *rmap;
+	pte_t pte;
+	unsigned int writing;
+	unsigned long mmu_seq;
+	unsigned long rcbits;
+	bool realmode = vcpu->arch.vcore->vcore_state == VCORE_RUNNING;
 
-	/* only handle 4k, 64k and 16M pages for now */
-	porder = 12;
-	if (pteh & HPTE_V_LARGE) {
-		if (cpu_has_feature(CPU_FTR_ARCH_206) &&
-		    (ptel & 0xf000) == 0x1000) {
-			/* 64k page */
-			porder = 16;
-		} else if ((ptel & 0xff000) == 0) {
-			/* 16M page */
-			porder = 24;
-			/* lowest AVA bit must be 0 for 16M pages */
-			if (pteh & 0x80)
-				return H_PARAMETER;
-		} else
+	psize = hpte_page_size(pteh, ptel);
+	if (!psize)
+		return H_PARAMETER;
+	writing = hpte_is_writable(ptel);
+	pteh &= ~(HPTE_V_HVLOCK | HPTE_V_ABSENT | HPTE_V_VALID);
+
+	/* used later to detect if we might have been invalidated */
+	mmu_seq = kvm->mmu_notifier_seq;
+	smp_rmb();
+
+	/* Find the memslot (if any) for this address */
+	gpa = (ptel & HPTE_R_RPN) & ~(psize - 1);
+	gfn = gpa >> PAGE_SHIFT;
+	memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn);
+	pa = 0;
+	is_io = ~0ul;
+	rmap = NULL;
+	if (!(memslot && !(memslot->flags & KVM_MEMSLOT_INVALID))) {
+		/* PPC970 can't do emulated MMIO */
+		if (!cpu_has_feature(CPU_FTR_ARCH_206))
 			return H_PARAMETER;
+		/* Emulated MMIO - mark this with key=31 */
+		pteh |= HPTE_V_ABSENT;
+		ptel |= HPTE_R_KEY_HI | HPTE_R_KEY_LO;
+		goto do_insert;
 	}
-	lpn = (ptel & HPTE_R_RPN) >> kvm->arch.ram_porder;
-	if (lpn >= kvm->arch.ram_npages || porder > kvm->arch.ram_porder)
+
+	/* Check if the requested page fits entirely in the memslot. */
+	if (!slot_is_aligned(memslot, psize))
 		return H_PARAMETER;
-	pa = kvm->arch.ram_pginfo[lpn].pfn << PAGE_SHIFT;
-	if (!pa)
+	slot_fn = gfn - memslot->base_gfn;
+	rmap = &memslot->rmap[slot_fn];
+
+	if (!kvm->arch.using_mmu_notifiers) {
+		physp = kvm->arch.slot_phys[memslot->id];
+		if (!physp)
+			return H_PARAMETER;
+		physp += slot_fn;
+		if (realmode)
+			physp = real_vmalloc_addr(physp);
+		pa = *physp;
+		if (!pa)
+			return H_TOO_HARD;
+		is_io = pa & (HPTE_R_I | HPTE_R_W);
+		pte_size = PAGE_SIZE << (pa & KVMPPC_PAGE_ORDER_MASK);
+		pa &= PAGE_MASK;
+	} else {
+		/* Translate to host virtual address */
+		hva = gfn_to_hva_memslot(memslot, gfn);
+
+		/* Look up the Linux PTE for the backing page */
+		pte_size = psize;
+		pte = lookup_linux_pte(vcpu, hva, writing, &pte_size);
+		if (pte_present(pte)) {
+			if (writing && !pte_write(pte))
+				/* make the actual HPTE be read-only */
+				ptel = hpte_make_readonly(ptel);
+			is_io = hpte_cache_bits(pte_val(pte));
+			pa = pte_pfn(pte) << PAGE_SHIFT;
+		}
+	}
+	if (pte_size < psize)
 		return H_PARAMETER;
-	/* Check WIMG */
-	if ((ptel & HPTE_R_WIMG) != HPTE_R_M &&
-	    (ptel & HPTE_R_WIMG) != (HPTE_R_W | HPTE_R_I | HPTE_R_M))
-		return H_PARAMETER;
-	pteh &= ~0x60UL;
-	ptel &= ~(HPTE_R_PP0 - kvm->arch.ram_psize);
+	if (pa && pte_size > psize)
+		pa |= gpa & (pte_size - 1);
+
+	ptel &= ~(HPTE_R_PP0 - psize);
 	ptel |= pa;
-	if (pte_index >= (HPT_NPTEG << 3))
+
+	if (pa)
+		pteh |= HPTE_V_VALID;
+	else
+		pteh |= HPTE_V_ABSENT;
+
+	/* Check WIMG */
+	if (is_io != ~0ul && !hpte_cache_flags_ok(ptel, is_io)) {
+		if (is_io)
+			return H_PARAMETER;
+		/*
+		 * Allow guest to map emulated device memory as
+		 * uncacheable, but actually make it cacheable.
+		 */
+		ptel &= ~(HPTE_R_W|HPTE_R_I|HPTE_R_G);
+		ptel |= HPTE_R_M;
+	}
+
+	/* Find and lock the HPTEG slot to use */
+ do_insert:
+	if (pte_index >= HPT_NPTE)
 		return H_PARAMETER;
 	if (likely((flags & H_EXACT) == 0)) {
 		pte_index &= ~7UL;
 		hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4));
-		for (i = 0; ; ++i) {
-			if (i == 8)
-				return H_PTEG_FULL;
+		for (i = 0; i < 8; ++i) {
 			if ((*hpte & HPTE_V_VALID) == 0 &&
-			    lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID))
+			    try_lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID |
+					  HPTE_V_ABSENT))
 				break;
 			hpte += 2;
 		}
+		if (i == 8) {
+			/*
+			 * Since try_lock_hpte doesn't retry (not even stdcx.
+			 * failures), it could be that there is a free slot
+			 * but we transiently failed to lock it.  Try again,
+			 * actually locking each slot and checking it.
+			 */
+			hpte -= 16;
+			for (i = 0; i < 8; ++i) {
+				while (!try_lock_hpte(hpte, HPTE_V_HVLOCK))
+					cpu_relax();
+				if (!(*hpte & (HPTE_V_VALID | HPTE_V_ABSENT)))
+					break;
+				*hpte &= ~HPTE_V_HVLOCK;
+				hpte += 2;
+			}
+			if (i == 8)
+				return H_PTEG_FULL;
+		}
+		pte_index += i;
 	} else {
-		i = 0;
 		hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4));
-		if (!lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID))
-			return H_PTEG_FULL;
+		if (!try_lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID |
+				   HPTE_V_ABSENT)) {
+			/* Lock the slot and check again */
+			while (!try_lock_hpte(hpte, HPTE_V_HVLOCK))
+				cpu_relax();
+			if (*hpte & (HPTE_V_VALID | HPTE_V_ABSENT)) {
+				*hpte &= ~HPTE_V_HVLOCK;
+				return H_PTEG_FULL;
+			}
+		}
 	}
+
+	/* Save away the guest's idea of the second HPTE dword */
+	rev = &kvm->arch.revmap[pte_index];
+	if (realmode)
+		rev = real_vmalloc_addr(rev);
+	if (rev)
+		rev->guest_rpte = g_ptel;
+
+	/* Link HPTE into reverse-map chain */
+	if (pteh & HPTE_V_VALID) {
+		if (realmode)
+			rmap = real_vmalloc_addr(rmap);
+		lock_rmap(rmap);
+		/* Check for pending invalidations under the rmap chain lock */
+		if (kvm->arch.using_mmu_notifiers &&
+		    mmu_notifier_retry(vcpu, mmu_seq)) {
+			/* inval in progress, write a non-present HPTE */
+			pteh |= HPTE_V_ABSENT;
+			pteh &= ~HPTE_V_VALID;
+			unlock_rmap(rmap);
+		} else {
+			kvmppc_add_revmap_chain(kvm, rev, rmap, pte_index,
+						realmode);
+			/* Only set R/C in real HPTE if already set in *rmap */
+			rcbits = *rmap >> KVMPPC_RMAP_RC_SHIFT;
+			ptel &= rcbits | ~(HPTE_R_R | HPTE_R_C);
+		}
+	}
+
 	hpte[1] = ptel;
+
+	/* Write the first HPTE dword, unlocking the HPTE and making it valid */
 	eieio();
 	hpte[0] = pteh;
 	asm volatile("ptesync" : : : "memory");
-	atomic_inc(&kvm->arch.ram_pginfo[lpn].refcnt);
-	vcpu->arch.gpr[4] = pte_index + i;
+
+	vcpu->arch.gpr[4] = pte_index;
 	return H_SUCCESS;
 }
+EXPORT_SYMBOL_GPL(kvmppc_h_enter);
 
 #define LOCK_TOKEN	(*(u32 *)(&get_paca()->lock_token))
 
@@ -137,37 +350,46 @@
 	struct kvm *kvm = vcpu->kvm;
 	unsigned long *hpte;
 	unsigned long v, r, rb;
+	struct revmap_entry *rev;
 
-	if (pte_index >= (HPT_NPTEG << 3))
+	if (pte_index >= HPT_NPTE)
 		return H_PARAMETER;
 	hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4));
-	while (!lock_hpte(hpte, HPTE_V_HVLOCK))
+	while (!try_lock_hpte(hpte, HPTE_V_HVLOCK))
 		cpu_relax();
-	if ((hpte[0] & HPTE_V_VALID) == 0 ||
+	if ((hpte[0] & (HPTE_V_ABSENT | HPTE_V_VALID)) == 0 ||
 	    ((flags & H_AVPN) && (hpte[0] & ~0x7fUL) != avpn) ||
 	    ((flags & H_ANDCOND) && (hpte[0] & avpn) != 0)) {
 		hpte[0] &= ~HPTE_V_HVLOCK;
 		return H_NOT_FOUND;
 	}
-	if (atomic_read(&kvm->online_vcpus) == 1)
-		flags |= H_LOCAL;
-	vcpu->arch.gpr[4] = v = hpte[0] & ~HPTE_V_HVLOCK;
-	vcpu->arch.gpr[5] = r = hpte[1];
-	rb = compute_tlbie_rb(v, r, pte_index);
-	hpte[0] = 0;
-	if (!(flags & H_LOCAL)) {
-		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");
+
+	rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]);
+	v = hpte[0] & ~HPTE_V_HVLOCK;
+	if (v & HPTE_V_VALID) {
+		hpte[0] &= ~HPTE_V_VALID;
+		rb = compute_tlbie_rb(v, hpte[1], pte_index);
+		if (!(flags & H_LOCAL) && atomic_read(&kvm->online_vcpus) > 1) {
+			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");
+		}
+		/* Read PTE low word after tlbie to get final R/C values */
+		remove_revmap_chain(kvm, pte_index, rev, v, hpte[1]);
 	}
+	r = rev->guest_rpte;
+	unlock_hpte(hpte, 0);
+
+	vcpu->arch.gpr[4] = v;
+	vcpu->arch.gpr[5] = r;
 	return H_SUCCESS;
 }
 
@@ -175,78 +397,117 @@
 {
 	struct kvm *kvm = vcpu->kvm;
 	unsigned long *args = &vcpu->arch.gpr[4];
-	unsigned long *hp, tlbrb[4];
-	long int i, found;
-	long int n_inval = 0;
-	unsigned long flags, req, pte_index;
+	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;
 	long int ret = H_SUCCESS;
+	struct revmap_entry *rev, *revs[4];
 
 	if (atomic_read(&kvm->online_vcpus) == 1)
 		local = 1;
-	for (i = 0; i < 4; ++i) {
-		pte_index = args[i * 2];
-		flags = pte_index >> 56;
-		pte_index &= ((1ul << 56) - 1);
-		req = flags >> 6;
-		flags &= 3;
-		if (req == 3)
-			break;
-		if (req != 1 || flags == 3 ||
-		    pte_index >= (HPT_NPTEG << 3)) {
-			/* parameter error */
-			args[i * 2] = ((0xa0 | flags) << 56) + pte_index;
-			ret = H_PARAMETER;
-			break;
-		}
-		hp = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4));
-		while (!lock_hpte(hp, HPTE_V_HVLOCK))
-			cpu_relax();
-		found = 0;
-		if (hp[0] & HPTE_V_VALID) {
-			switch (flags & 3) {
-			case 0:		/* absolute */
-				found = 1;
-				break;
-			case 1:		/* andcond */
-				if (!(hp[0] & args[i * 2 + 1]))
-					found = 1;
-				break;
-			case 2:		/* AVPN */
-				if ((hp[0] & ~0x7fUL) == args[i * 2 + 1])
-					found = 1;
+	for (i = 0; i < 4 && ret == H_SUCCESS; ) {
+		n = 0;
+		for (; i < 4; ++i) {
+			j = i * 2;
+			pte_index = args[j];
+			flags = pte_index >> 56;
+			pte_index &= ((1ul << 56) - 1);
+			req = flags >> 6;
+			flags &= 3;
+			if (req == 3) {		/* no more requests */
+				i = 4;
 				break;
 			}
-		}
-		if (!found) {
-			hp[0] &= ~HPTE_V_HVLOCK;
-			args[i * 2] = ((0x90 | flags) << 56) + pte_index;
-			continue;
-		}
-		/* insert R and C bits from PTE */
-		flags |= (hp[1] >> 5) & 0x0c;
-		args[i * 2] = ((0x80 | flags) << 56) + pte_index;
-		tlbrb[n_inval++] = compute_tlbie_rb(hp[0], hp[1], pte_index);
-		hp[0] = 0;
-	}
-	if (n_inval == 0)
-		return ret;
+			if (req != 1 || flags == 3 || pte_index >= HPT_NPTE) {
+				/* parameter error */
+				args[j] = ((0xa0 | flags) << 56) + pte_index;
+				ret = H_PARAMETER;
+				break;
+			}
+			hp = (unsigned long *)
+				(kvm->arch.hpt_virt + (pte_index << 4));
+			/* to avoid deadlock, don't spin except for first */
+			if (!try_lock_hpte(hp, HPTE_V_HVLOCK)) {
+				if (n)
+					break;
+				while (!try_lock_hpte(hp, HPTE_V_HVLOCK))
+					cpu_relax();
+			}
+			found = 0;
+			if (hp[0] & (HPTE_V_ABSENT | HPTE_V_VALID)) {
+				switch (flags & 3) {
+				case 0:		/* absolute */
+					found = 1;
+					break;
+				case 1:		/* andcond */
+					if (!(hp[0] & args[j + 1]))
+						found = 1;
+					break;
+				case 2:		/* AVPN */
+					if ((hp[0] & ~0x7fUL) == args[j + 1])
+						found = 1;
+					break;
+				}
+			}
+			if (!found) {
+				hp[0] &= ~HPTE_V_HVLOCK;
+				args[j] = ((0x90 | flags) << 56) + pte_index;
+				continue;
+			}
 
-	if (!local) {
-		while(!try_lock_tlbie(&kvm->arch.tlbie_lock))
-			cpu_relax();
-		asm volatile("ptesync" : : : "memory");
-		for (i = 0; i < n_inval; ++i)
-			asm volatile(PPC_TLBIE(%1,%0)
-				     : : "r" (tlbrb[i]), "r" (kvm->arch.lpid));
-		asm volatile("eieio; tlbsync; ptesync" : : : "memory");
-		kvm->arch.tlbie_lock = 0;
-	} else {
-		asm volatile("ptesync" : : : "memory");
-		for (i = 0; i < n_inval; ++i)
-			asm volatile("tlbiel %0" : : "r" (tlbrb[i]));
-		asm volatile("ptesync" : : : "memory");
+			args[j] = ((0x80 | flags) << 56) + pte_index;
+			rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]);
+
+			if (!(hp[0] & HPTE_V_VALID)) {
+				/* insert R and C bits from PTE */
+				rcbits = rev->guest_rpte & (HPTE_R_R|HPTE_R_C);
+				args[j] |= rcbits << (56 - 5);
+				continue;
+			}
+
+			hp[0] &= ~HPTE_V_VALID;		/* leave it locked */
+			tlbrb[n] = compute_tlbie_rb(hp[0], hp[1], pte_index);
+			indexes[n] = j;
+			hptes[n] = hp;
+			revs[n] = rev;
+			++n;
+		}
+
+		if (!n)
+			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");
+		}
+
+		/* Read PTE low words after tlbie to get final R/C values */
+		for (k = 0; k < n; ++k) {
+			j = indexes[k];
+			pte_index = args[j] & ((1ul << 56) - 1);
+			hp = hptes[k];
+			rev = revs[k];
+			remove_revmap_chain(kvm, pte_index, rev, hp[0], hp[1]);
+			rcbits = rev->guest_rpte & (HPTE_R_R|HPTE_R_C);
+			args[j] |= rcbits << (56 - 5);
+			hp[0] = 0;
+		}
 	}
+
 	return ret;
 }
 
@@ -256,40 +517,55 @@
 {
 	struct kvm *kvm = vcpu->kvm;
 	unsigned long *hpte;
-	unsigned long v, r, rb;
+	struct revmap_entry *rev;
+	unsigned long v, r, rb, mask, bits;
 
-	if (pte_index >= (HPT_NPTEG << 3))
+	if (pte_index >= HPT_NPTE)
 		return H_PARAMETER;
+
 	hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4));
-	while (!lock_hpte(hpte, HPTE_V_HVLOCK))
+	while (!try_lock_hpte(hpte, HPTE_V_HVLOCK))
 		cpu_relax();
-	if ((hpte[0] & HPTE_V_VALID) == 0 ||
+	if ((hpte[0] & (HPTE_V_ABSENT | HPTE_V_VALID)) == 0 ||
 	    ((flags & H_AVPN) && (hpte[0] & ~0x7fUL) != avpn)) {
 		hpte[0] &= ~HPTE_V_HVLOCK;
 		return H_NOT_FOUND;
 	}
+
 	if (atomic_read(&kvm->online_vcpus) == 1)
 		flags |= H_LOCAL;
 	v = hpte[0];
-	r = hpte[1] & ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N |
-			HPTE_R_KEY_HI | HPTE_R_KEY_LO);
-	r |= (flags << 55) & HPTE_R_PP0;
-	r |= (flags << 48) & HPTE_R_KEY_HI;
-	r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
-	rb = compute_tlbie_rb(v, r, pte_index);
-	hpte[0] = v & ~HPTE_V_VALID;
-	if (!(flags & H_LOCAL)) {
-		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");
+	bits = (flags << 55) & HPTE_R_PP0;
+	bits |= (flags << 48) & HPTE_R_KEY_HI;
+	bits |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
+
+	/* Update guest view of 2nd HPTE dword */
+	mask = HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N |
+		HPTE_R_KEY_HI | HPTE_R_KEY_LO;
+	rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]);
+	if (rev) {
+		r = (rev->guest_rpte & ~mask) | bits;
+		rev->guest_rpte = r;
+	}
+	r = (hpte[1] & ~mask) | bits;
+
+	/* Update HPTE */
+	if (v & HPTE_V_VALID) {
+		rb = compute_tlbie_rb(v, r, pte_index);
+		hpte[0] = v & ~HPTE_V_VALID;
+		if (!(flags & H_LOCAL)) {
+			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");
+		}
 	}
 	hpte[1] = r;
 	eieio();
@@ -298,40 +574,243 @@
 	return H_SUCCESS;
 }
 
-static unsigned long reverse_xlate(struct kvm *kvm, unsigned long realaddr)
-{
-	long int i;
-	unsigned long offset, rpn;
-
-	offset = realaddr & (kvm->arch.ram_psize - 1);
-	rpn = (realaddr - offset) >> PAGE_SHIFT;
-	for (i = 0; i < kvm->arch.ram_npages; ++i)
-		if (rpn == kvm->arch.ram_pginfo[i].pfn)
-			return (i << PAGE_SHIFT) + offset;
-	return HPTE_R_RPN;	/* all 1s in the RPN field */
-}
-
 long kvmppc_h_read(struct kvm_vcpu *vcpu, unsigned long flags,
 		   unsigned long pte_index)
 {
 	struct kvm *kvm = vcpu->kvm;
-	unsigned long *hpte, r;
+	unsigned long *hpte, v, r;
 	int i, n = 1;
+	struct revmap_entry *rev = NULL;
 
-	if (pte_index >= (HPT_NPTEG << 3))
+	if (pte_index >= HPT_NPTE)
 		return H_PARAMETER;
 	if (flags & H_READ_4) {
 		pte_index &= ~3;
 		n = 4;
 	}
+	rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]);
 	for (i = 0; i < n; ++i, ++pte_index) {
 		hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4));
+		v = hpte[0] & ~HPTE_V_HVLOCK;
 		r = hpte[1];
-		if ((flags & H_R_XLATE) && (hpte[0] & HPTE_V_VALID))
-			r = reverse_xlate(kvm, r & HPTE_R_RPN) |
-				(r & ~HPTE_R_RPN);
-		vcpu->arch.gpr[4 + i * 2] = hpte[0];
+		if (v & HPTE_V_ABSENT) {
+			v &= ~HPTE_V_ABSENT;
+			v |= HPTE_V_VALID;
+		}
+		if (v & HPTE_V_VALID)
+			r = rev[i].guest_rpte | (r & (HPTE_R_R | HPTE_R_C));
+		vcpu->arch.gpr[4 + i * 2] = v;
 		vcpu->arch.gpr[5 + i * 2] = r;
 	}
 	return H_SUCCESS;
 }
+
+void kvmppc_invalidate_hpte(struct kvm *kvm, unsigned long *hptep,
+			unsigned long pte_index)
+{
+	unsigned long rb;
+
+	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;
+}
+EXPORT_SYMBOL_GPL(kvmppc_invalidate_hpte);
+
+void kvmppc_clear_ref_hpte(struct kvm *kvm, unsigned long *hptep,
+			   unsigned long pte_index)
+{
+	unsigned long rb;
+	unsigned char rbyte;
+
+	rb = compute_tlbie_rb(hptep[0], hptep[1], pte_index);
+	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;
+}
+EXPORT_SYMBOL_GPL(kvmppc_clear_ref_hpte);
+
+static int slb_base_page_shift[4] = {
+	24,	/* 16M */
+	16,	/* 64k */
+	34,	/* 16G */
+	20,	/* 1M, unsupported */
+};
+
+long kvmppc_hv_find_lock_hpte(struct kvm *kvm, gva_t eaddr, unsigned long slb_v,
+			      unsigned long valid)
+{
+	unsigned int i;
+	unsigned int pshift;
+	unsigned long somask;
+	unsigned long vsid, hash;
+	unsigned long avpn;
+	unsigned long *hpte;
+	unsigned long mask, val;
+	unsigned long v, r;
+
+	/* Get page shift, work out hash and AVPN etc. */
+	mask = SLB_VSID_B | HPTE_V_AVPN | HPTE_V_SECONDARY;
+	val = 0;
+	pshift = 12;
+	if (slb_v & SLB_VSID_L) {
+		mask |= HPTE_V_LARGE;
+		val |= HPTE_V_LARGE;
+		pshift = slb_base_page_shift[(slb_v & SLB_VSID_LP) >> 4];
+	}
+	if (slb_v & SLB_VSID_B_1T) {
+		somask = (1UL << 40) - 1;
+		vsid = (slb_v & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T;
+		vsid ^= vsid << 25;
+	} else {
+		somask = (1UL << 28) - 1;
+		vsid = (slb_v & ~SLB_VSID_B) >> SLB_VSID_SHIFT;
+	}
+	hash = (vsid ^ ((eaddr & somask) >> pshift)) & HPT_HASH_MASK;
+	avpn = slb_v & ~(somask >> 16);	/* also includes B */
+	avpn |= (eaddr & somask) >> 16;
+
+	if (pshift >= 24)
+		avpn &= ~((1UL << (pshift - 16)) - 1);
+	else
+		avpn &= ~0x7fUL;
+	val |= avpn;
+
+	for (;;) {
+		hpte = (unsigned long *)(kvm->arch.hpt_virt + (hash << 7));
+
+		for (i = 0; i < 16; i += 2) {
+			/* Read the PTE racily */
+			v = hpte[i] & ~HPTE_V_HVLOCK;
+
+			/* Check valid/absent, hash, segment size and AVPN */
+			if (!(v & valid) || (v & mask) != val)
+				continue;
+
+			/* Lock the PTE and read it under the lock */
+			while (!try_lock_hpte(&hpte[i], HPTE_V_HVLOCK))
+				cpu_relax();
+			v = hpte[i] & ~HPTE_V_HVLOCK;
+			r = hpte[i+1];
+
+			/*
+			 * Check the HPTE again, including large page size
+			 * Since we don't currently allow any MPSS (mixed
+			 * page-size segment) page sizes, it is sufficient
+			 * to check against the actual page size.
+			 */
+			if ((v & valid) && (v & mask) == val &&
+			    hpte_page_size(v, r) == (1ul << pshift))
+				/* Return with the HPTE still locked */
+				return (hash << 3) + (i >> 1);
+
+			/* Unlock and move on */
+			hpte[i] = v;
+		}
+
+		if (val & HPTE_V_SECONDARY)
+			break;
+		val |= HPTE_V_SECONDARY;
+		hash = hash ^ HPT_HASH_MASK;
+	}
+	return -1;
+}
+EXPORT_SYMBOL(kvmppc_hv_find_lock_hpte);
+
+/*
+ * Called in real mode to check whether an HPTE not found fault
+ * is due to accessing a paged-out page or an emulated MMIO page,
+ * or if a protection fault is due to accessing a page that the
+ * guest wanted read/write access to but which we made read-only.
+ * Returns a possibly modified status (DSISR) value if not
+ * (i.e. pass the interrupt to the guest),
+ * -1 to pass the fault up to host kernel mode code, -2 to do that
+ * and also load the instruction word (for MMIO emulation),
+ * or 0 if we should make the guest retry the access.
+ */
+long kvmppc_hpte_hv_fault(struct kvm_vcpu *vcpu, unsigned long addr,
+			  unsigned long slb_v, unsigned int status, bool data)
+{
+	struct kvm *kvm = vcpu->kvm;
+	long int index;
+	unsigned long v, r, gr;
+	unsigned long *hpte;
+	unsigned long valid;
+	struct revmap_entry *rev;
+	unsigned long pp, key;
+
+	/* For protection fault, expect to find a valid HPTE */
+	valid = HPTE_V_VALID;
+	if (status & DSISR_NOHPTE)
+		valid |= HPTE_V_ABSENT;
+
+	index = kvmppc_hv_find_lock_hpte(kvm, addr, slb_v, valid);
+	if (index < 0) {
+		if (status & DSISR_NOHPTE)
+			return status;	/* there really was no HPTE */
+		return 0;		/* for prot fault, HPTE disappeared */
+	}
+	hpte = (unsigned long *)(kvm->arch.hpt_virt + (index << 4));
+	v = hpte[0] & ~HPTE_V_HVLOCK;
+	r = hpte[1];
+	rev = real_vmalloc_addr(&kvm->arch.revmap[index]);
+	gr = rev->guest_rpte;
+
+	unlock_hpte(hpte, v);
+
+	/* For not found, if the HPTE is valid by now, retry the instruction */
+	if ((status & DSISR_NOHPTE) && (v & HPTE_V_VALID))
+		return 0;
+
+	/* Check access permissions to the page */
+	pp = gr & (HPTE_R_PP0 | HPTE_R_PP);
+	key = (vcpu->arch.shregs.msr & MSR_PR) ? SLB_VSID_KP : SLB_VSID_KS;
+	status &= ~DSISR_NOHPTE;	/* DSISR_NOHPTE == SRR1_ISI_NOPT */
+	if (!data) {
+		if (gr & (HPTE_R_N | HPTE_R_G))
+			return status | SRR1_ISI_N_OR_G;
+		if (!hpte_read_permission(pp, slb_v & key))
+			return status | SRR1_ISI_PROT;
+	} else if (status & DSISR_ISSTORE) {
+		/* check write permission */
+		if (!hpte_write_permission(pp, slb_v & key))
+			return status | DSISR_PROTFAULT;
+	} else {
+		if (!hpte_read_permission(pp, slb_v & key))
+			return status | DSISR_PROTFAULT;
+	}
+
+	/* Check storage key, if applicable */
+	if (data && (vcpu->arch.shregs.msr & MSR_DR)) {
+		unsigned int perm = hpte_get_skey_perm(gr, vcpu->arch.amr);
+		if (status & DSISR_ISSTORE)
+			perm >>= 1;
+		if (perm & 1)
+			return status | DSISR_KEYFAULT;
+	}
+
+	/* Save HPTE info for virtual-mode handler */
+	vcpu->arch.pgfault_addr = addr;
+	vcpu->arch.pgfault_index = index;
+	vcpu->arch.pgfault_hpte[0] = v;
+	vcpu->arch.pgfault_hpte[1] = r;
+
+	/* Check the storage key to see if it is possibly emulated MMIO */
+	if (data && (vcpu->arch.shregs.msr & MSR_IR) &&
+	    (r & (HPTE_R_KEY_HI | HPTE_R_KEY_LO)) ==
+	    (HPTE_R_KEY_HI | HPTE_R_KEY_LO))
+		return -2;	/* MMIO emulation - load instr word */
+
+	return -1;		/* send fault up to host kernel mode */
+}
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 5c8b261..b70bf22 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -601,6 +601,30 @@
 
 	stw	r12,VCPU_TRAP(r9)
 
+	/* Save HEIR (HV emulation assist reg) in last_inst
+	   if this is an HEI (HV emulation interrupt, e40) */
+	li	r3,KVM_INST_FETCH_FAILED
+BEGIN_FTR_SECTION
+	cmpwi	r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST
+	bne	11f
+	mfspr	r3,SPRN_HEIR
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
+11:	stw	r3,VCPU_LAST_INST(r9)
+
+	/* these are volatile across C function calls */
+	mfctr	r3
+	mfxer	r4
+	std	r3, VCPU_CTR(r9)
+	stw	r4, VCPU_XER(r9)
+
+BEGIN_FTR_SECTION
+	/* If this is a page table miss then see if it's theirs or ours */
+	cmpwi	r12, BOOK3S_INTERRUPT_H_DATA_STORAGE
+	beq	kvmppc_hdsi
+	cmpwi	r12, BOOK3S_INTERRUPT_H_INST_STORAGE
+	beq	kvmppc_hisi
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
+
 	/* See if this is a leftover HDEC interrupt */
 	cmpwi	r12,BOOK3S_INTERRUPT_HV_DECREMENTER
 	bne	2f
@@ -608,7 +632,7 @@
 	cmpwi	r3,0
 	bge	ignore_hdec
 2:
-	/* See if this is something we can handle in real mode */
+	/* See if this is an hcall we can handle in real mode */
 	cmpwi	r12,BOOK3S_INTERRUPT_SYSCALL
 	beq	hcall_try_real_mode
 
@@ -624,6 +648,7 @@
 1:
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
 
+nohpte_cont:
 hcall_real_cont:		/* r9 = vcpu, r12 = trap, r13 = paca */
 	/* Save DEC */
 	mfspr	r5,SPRN_DEC
@@ -632,36 +657,21 @@
 	add	r5,r5,r6
 	std	r5,VCPU_DEC_EXPIRES(r9)
 
-	/* Save HEIR (HV emulation assist reg) in last_inst
-	   if this is an HEI (HV emulation interrupt, e40) */
-	li	r3,-1
-BEGIN_FTR_SECTION
-	cmpwi	r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST
-	bne	11f
-	mfspr	r3,SPRN_HEIR
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
-11:	stw	r3,VCPU_LAST_INST(r9)
-
 	/* Save more register state  */
-	mfxer	r5
 	mfdar	r6
 	mfdsisr	r7
-	mfctr	r8
-
-	stw	r5, VCPU_XER(r9)
 	std	r6, VCPU_DAR(r9)
 	stw	r7, VCPU_DSISR(r9)
-	std	r8, VCPU_CTR(r9)
-	/* grab HDAR & HDSISR if HV data storage interrupt (HDSI) */
 BEGIN_FTR_SECTION
+	/* don't overwrite fault_dar/fault_dsisr if HDSI */
 	cmpwi	r12,BOOK3S_INTERRUPT_H_DATA_STORAGE
 	beq	6f
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
-7:	std	r6, VCPU_FAULT_DAR(r9)
+	std	r6, VCPU_FAULT_DAR(r9)
 	stw	r7, VCPU_FAULT_DSISR(r9)
 
 	/* Save guest CTRL register, set runlatch to 1 */
-	mfspr	r6,SPRN_CTRLF
+6:	mfspr	r6,SPRN_CTRLF
 	stw	r6,VCPU_CTRL(r9)
 	andi.	r0,r6,1
 	bne	4f
@@ -1094,9 +1104,131 @@
 	mtspr	SPRN_HSRR1, r7
 	ba	0x500
 
-6:	mfspr	r6,SPRN_HDAR
-	mfspr	r7,SPRN_HDSISR
-	b	7b
+/*
+ * Check whether an HDSI is an HPTE not found fault or something else.
+ * If it is an HPTE not found fault that is due to the guest accessing
+ * a page that they have mapped but which we have paged out, then
+ * we continue on with the guest exit path.  In all other cases,
+ * reflect the HDSI to the guest as a DSI.
+ */
+kvmppc_hdsi:
+	mfspr	r4, SPRN_HDAR
+	mfspr	r6, SPRN_HDSISR
+	/* HPTE not found fault or protection fault? */
+	andis.	r0, r6, (DSISR_NOHPTE | DSISR_PROTFAULT)@h
+	beq	1f			/* if not, send it to the guest */
+	andi.	r0, r11, MSR_DR		/* data relocation enabled? */
+	beq	3f
+	clrrdi	r0, r4, 28
+	PPC_SLBFEE_DOT(r5, r0)		/* if so, look up SLB */
+	bne	1f			/* if no SLB entry found */
+4:	std	r4, VCPU_FAULT_DAR(r9)
+	stw	r6, VCPU_FAULT_DSISR(r9)
+
+	/* Search the hash table. */
+	mr	r3, r9			/* vcpu pointer */
+	li	r7, 1			/* data fault */
+	bl	.kvmppc_hpte_hv_fault
+	ld	r9, HSTATE_KVM_VCPU(r13)
+	ld	r10, VCPU_PC(r9)
+	ld	r11, VCPU_MSR(r9)
+	li	r12, BOOK3S_INTERRUPT_H_DATA_STORAGE
+	cmpdi	r3, 0			/* retry the instruction */
+	beq	6f
+	cmpdi	r3, -1			/* handle in kernel mode */
+	beq	nohpte_cont
+	cmpdi	r3, -2			/* MMIO emulation; need instr word */
+	beq	2f
+
+	/* Synthesize a DSI for the guest */
+	ld	r4, VCPU_FAULT_DAR(r9)
+	mr	r6, r3
+1:	mtspr	SPRN_DAR, r4
+	mtspr	SPRN_DSISR, r6
+	mtspr	SPRN_SRR0, r10
+	mtspr	SPRN_SRR1, r11
+	li	r10, BOOK3S_INTERRUPT_DATA_STORAGE
+	li	r11, (MSR_ME << 1) | 1	/* synthesize MSR_SF | MSR_ME */
+	rotldi	r11, r11, 63
+6:	ld	r7, VCPU_CTR(r9)
+	lwz	r8, VCPU_XER(r9)
+	mtctr	r7
+	mtxer	r8
+	mr	r4, r9
+	b	fast_guest_return
+
+3:	ld	r5, VCPU_KVM(r9)	/* not relocated, use VRMA */
+	ld	r5, KVM_VRMA_SLB_V(r5)
+	b	4b
+
+	/* If this is for emulated MMIO, load the instruction word */
+2:	li	r8, KVM_INST_FETCH_FAILED	/* In case lwz faults */
+
+	/* Set guest mode to 'jump over instruction' so if lwz faults
+	 * we'll just continue at the next IP. */
+	li	r0, KVM_GUEST_MODE_SKIP
+	stb	r0, HSTATE_IN_GUEST(r13)
+
+	/* Do the access with MSR:DR enabled */
+	mfmsr	r3
+	ori	r4, r3, MSR_DR		/* Enable paging for data */
+	mtmsrd	r4
+	lwz	r8, 0(r10)
+	mtmsrd	r3
+
+	/* Store the result */
+	stw	r8, VCPU_LAST_INST(r9)
+
+	/* Unset guest mode. */
+	li	r0, KVM_GUEST_MODE_NONE
+	stb	r0, HSTATE_IN_GUEST(r13)
+	b	nohpte_cont
+
+/*
+ * Similarly for an HISI, reflect it to the guest as an ISI unless
+ * it is an HPTE not found fault for a page that we have paged out.
+ */
+kvmppc_hisi:
+	andis.	r0, r11, SRR1_ISI_NOPT@h
+	beq	1f
+	andi.	r0, r11, MSR_IR		/* instruction relocation enabled? */
+	beq	3f
+	clrrdi	r0, r10, 28
+	PPC_SLBFEE_DOT(r5, r0)		/* if so, look up SLB */
+	bne	1f			/* if no SLB entry found */
+4:
+	/* Search the hash table. */
+	mr	r3, r9			/* vcpu pointer */
+	mr	r4, r10
+	mr	r6, r11
+	li	r7, 0			/* instruction fault */
+	bl	.kvmppc_hpte_hv_fault
+	ld	r9, HSTATE_KVM_VCPU(r13)
+	ld	r10, VCPU_PC(r9)
+	ld	r11, VCPU_MSR(r9)
+	li	r12, BOOK3S_INTERRUPT_H_INST_STORAGE
+	cmpdi	r3, 0			/* retry the instruction */
+	beq	6f
+	cmpdi	r3, -1			/* handle in kernel mode */
+	beq	nohpte_cont
+
+	/* Synthesize an ISI for the guest */
+	mr	r11, r3
+1:	mtspr	SPRN_SRR0, r10
+	mtspr	SPRN_SRR1, r11
+	li	r10, BOOK3S_INTERRUPT_INST_STORAGE
+	li	r11, (MSR_ME << 1) | 1	/* synthesize MSR_SF | MSR_ME */
+	rotldi	r11, r11, 63
+6:	ld	r7, VCPU_CTR(r9)
+	lwz	r8, VCPU_XER(r9)
+	mtctr	r7
+	mtxer	r8
+	mr	r4, r9
+	b	fast_guest_return
+
+3:	ld	r6, VCPU_KVM(r9)	/* not relocated, use VRMA */
+	ld	r5, KVM_VRMA_SLB_V(r6)
+	b	4b
 
 /*
  * Try to handle an hcall in real mode.
diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c
index 7b0ee96c..a59a25a 100644
--- a/arch/powerpc/kvm/book3s_paired_singles.c
+++ b/arch/powerpc/kvm/book3s_paired_singles.c
@@ -24,6 +24,7 @@
 #include <asm/kvm_fpu.h>
 #include <asm/reg.h>
 #include <asm/cacheflush.h>
+#include <asm/switch_to.h>
 #include <linux/vmalloc.h>
 
 /* #define DEBUG */
@@ -196,7 +197,8 @@
 		kvmppc_inject_pf(vcpu, addr, false);
 		goto done_load;
 	} else if (r == EMULATE_DO_MMIO) {
-		emulated = kvmppc_handle_load(run, vcpu, KVM_REG_FPR | rs, len, 1);
+		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
+					      len, 1);
 		goto done_load;
 	}
 
@@ -286,11 +288,13 @@
 		kvmppc_inject_pf(vcpu, addr, false);
 		goto done_load;
 	} else if ((r == EMULATE_DO_MMIO) && w) {
-		emulated = kvmppc_handle_load(run, vcpu, KVM_REG_FPR | rs, 4, 1);
+		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
+					      4, 1);
 		vcpu->arch.qpr[rs] = tmp[1];
 		goto done_load;
 	} else if (r == EMULATE_DO_MMIO) {
-		emulated = kvmppc_handle_load(run, vcpu, KVM_REG_FQPR | rs, 8, 1);
+		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FQPR | rs,
+					      8, 1);
 		goto done_load;
 	}
 
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index 220fcdf..642d885 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -33,6 +33,7 @@
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_book3s.h>
 #include <asm/mmu_context.h>
+#include <asm/switch_to.h>
 #include <linux/gfp.h>
 #include <linux/sched.h>
 #include <linux/vmalloc.h>
@@ -51,15 +52,19 @@
 #define MSR_USER32 MSR_USER
 #define MSR_USER64 MSR_USER
 #define HW_PAGE_SIZE PAGE_SIZE
+#define __hard_irq_disable local_irq_disable
+#define __hard_irq_enable local_irq_enable
 #endif
 
 void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
 #ifdef CONFIG_PPC_BOOK3S_64
-	memcpy(to_svcpu(vcpu)->slb, to_book3s(vcpu)->slb_shadow, sizeof(to_svcpu(vcpu)->slb));
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	memcpy(svcpu->slb, to_book3s(vcpu)->slb_shadow, sizeof(svcpu->slb));
 	memcpy(&get_paca()->shadow_vcpu, to_book3s(vcpu)->shadow_vcpu,
 	       sizeof(get_paca()->shadow_vcpu));
-	to_svcpu(vcpu)->slb_max = to_book3s(vcpu)->slb_shadow_max;
+	svcpu->slb_max = to_book3s(vcpu)->slb_shadow_max;
+	svcpu_put(svcpu);
 #endif
 
 #ifdef CONFIG_PPC_BOOK3S_32
@@ -70,10 +75,12 @@
 void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
 {
 #ifdef CONFIG_PPC_BOOK3S_64
-	memcpy(to_book3s(vcpu)->slb_shadow, to_svcpu(vcpu)->slb, sizeof(to_svcpu(vcpu)->slb));
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	memcpy(to_book3s(vcpu)->slb_shadow, svcpu->slb, sizeof(svcpu->slb));
 	memcpy(to_book3s(vcpu)->shadow_vcpu, &get_paca()->shadow_vcpu,
 	       sizeof(get_paca()->shadow_vcpu));
-	to_book3s(vcpu)->slb_shadow_max = to_svcpu(vcpu)->slb_max;
+	to_book3s(vcpu)->slb_shadow_max = svcpu->slb_max;
+	svcpu_put(svcpu);
 #endif
 
 	kvmppc_giveup_ext(vcpu, MSR_FP);
@@ -151,14 +158,16 @@
 #ifdef CONFIG_PPC_BOOK3S_64
 	if ((pvr >= 0x330000) && (pvr < 0x70330000)) {
 		kvmppc_mmu_book3s_64_init(vcpu);
-		to_book3s(vcpu)->hior = 0xfff00000;
+		if (!to_book3s(vcpu)->hior_explicit)
+			to_book3s(vcpu)->hior = 0xfff00000;
 		to_book3s(vcpu)->msr_mask = 0xffffffffffffffffULL;
 		vcpu->arch.cpu_type = KVM_CPU_3S_64;
 	} else
 #endif
 	{
 		kvmppc_mmu_book3s_32_init(vcpu);
-		to_book3s(vcpu)->hior = 0;
+		if (!to_book3s(vcpu)->hior_explicit)
+			to_book3s(vcpu)->hior = 0;
 		to_book3s(vcpu)->msr_mask = 0xffffffffULL;
 		vcpu->arch.cpu_type = KVM_CPU_3S_32;
 	}
@@ -308,19 +317,22 @@
 
 	if (page_found == -ENOENT) {
 		/* Page not found in guest PTE entries */
+		struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
 		vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
-		vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr;
+		vcpu->arch.shared->dsisr = svcpu->fault_dsisr;
 		vcpu->arch.shared->msr |=
-			(to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
+			(svcpu->shadow_srr1 & 0x00000000f8000000ULL);
+		svcpu_put(svcpu);
 		kvmppc_book3s_queue_irqprio(vcpu, vec);
 	} else if (page_found == -EPERM) {
 		/* Storage protection */
+		struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
 		vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
-		vcpu->arch.shared->dsisr =
-			to_svcpu(vcpu)->fault_dsisr & ~DSISR_NOHPTE;
+		vcpu->arch.shared->dsisr = svcpu->fault_dsisr & ~DSISR_NOHPTE;
 		vcpu->arch.shared->dsisr |= DSISR_PROTFAULT;
 		vcpu->arch.shared->msr |=
-			(to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
+			svcpu->shadow_srr1 & 0x00000000f8000000ULL;
+		svcpu_put(svcpu);
 		kvmppc_book3s_queue_irqprio(vcpu, vec);
 	} else if (page_found == -EINVAL) {
 		/* Page not found in guest SLB */
@@ -517,24 +529,29 @@
 	run->ready_for_interrupt_injection = 1;
 
 	trace_kvm_book3s_exit(exit_nr, vcpu);
+	preempt_enable();
 	kvm_resched(vcpu);
 	switch (exit_nr) {
 	case BOOK3S_INTERRUPT_INST_STORAGE:
+	{
+		struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+		ulong shadow_srr1 = svcpu->shadow_srr1;
 		vcpu->stat.pf_instruc++;
 
 #ifdef CONFIG_PPC_BOOK3S_32
 		/* We set segments as unused segments when invalidating them. So
 		 * treat the respective fault as segment fault. */
-		if (to_svcpu(vcpu)->sr[kvmppc_get_pc(vcpu) >> SID_SHIFT]
-		    == SR_INVALID) {
+		if (svcpu->sr[kvmppc_get_pc(vcpu) >> SID_SHIFT] == SR_INVALID) {
 			kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
 			r = RESUME_GUEST;
+			svcpu_put(svcpu);
 			break;
 		}
 #endif
+		svcpu_put(svcpu);
 
 		/* only care about PTEG not found errors, but leave NX alone */
-		if (to_svcpu(vcpu)->shadow_srr1 & 0x40000000) {
+		if (shadow_srr1 & 0x40000000) {
 			r = kvmppc_handle_pagefault(run, vcpu, kvmppc_get_pc(vcpu), exit_nr);
 			vcpu->stat.sp_instruc++;
 		} else if (vcpu->arch.mmu.is_dcbz32(vcpu) &&
@@ -547,33 +564,37 @@
 			kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL);
 			r = RESUME_GUEST;
 		} else {
-			vcpu->arch.shared->msr |=
-				to_svcpu(vcpu)->shadow_srr1 & 0x58000000;
+			vcpu->arch.shared->msr |= shadow_srr1 & 0x58000000;
 			kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
 			r = RESUME_GUEST;
 		}
 		break;
+	}
 	case BOOK3S_INTERRUPT_DATA_STORAGE:
 	{
 		ulong dar = kvmppc_get_fault_dar(vcpu);
+		struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+		u32 fault_dsisr = svcpu->fault_dsisr;
 		vcpu->stat.pf_storage++;
 
 #ifdef CONFIG_PPC_BOOK3S_32
 		/* We set segments as unused segments when invalidating them. So
 		 * treat the respective fault as segment fault. */
-		if ((to_svcpu(vcpu)->sr[dar >> SID_SHIFT]) == SR_INVALID) {
+		if ((svcpu->sr[dar >> SID_SHIFT]) == SR_INVALID) {
 			kvmppc_mmu_map_segment(vcpu, dar);
 			r = RESUME_GUEST;
+			svcpu_put(svcpu);
 			break;
 		}
 #endif
+		svcpu_put(svcpu);
 
 		/* The only case we need to handle is missing shadow PTEs */
-		if (to_svcpu(vcpu)->fault_dsisr & DSISR_NOHPTE) {
+		if (fault_dsisr & DSISR_NOHPTE) {
 			r = kvmppc_handle_pagefault(run, vcpu, dar, exit_nr);
 		} else {
 			vcpu->arch.shared->dar = dar;
-			vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr;
+			vcpu->arch.shared->dsisr = fault_dsisr;
 			kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
 			r = RESUME_GUEST;
 		}
@@ -609,10 +630,13 @@
 	case BOOK3S_INTERRUPT_PROGRAM:
 	{
 		enum emulation_result er;
+		struct kvmppc_book3s_shadow_vcpu *svcpu;
 		ulong flags;
 
 program_interrupt:
-		flags = to_svcpu(vcpu)->shadow_srr1 & 0x1f0000ull;
+		svcpu = svcpu_get(vcpu);
+		flags = svcpu->shadow_srr1 & 0x1f0000ull;
+		svcpu_put(svcpu);
 
 		if (vcpu->arch.shared->msr & MSR_PR) {
 #ifdef EXIT_DEBUG
@@ -740,20 +764,33 @@
 		r = RESUME_GUEST;
 		break;
 	default:
+	{
+		struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+		ulong shadow_srr1 = svcpu->shadow_srr1;
+		svcpu_put(svcpu);
 		/* Ugh - bork here! What did we get? */
 		printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | msr=0x%lx\n",
-			exit_nr, kvmppc_get_pc(vcpu), to_svcpu(vcpu)->shadow_srr1);
+			exit_nr, kvmppc_get_pc(vcpu), shadow_srr1);
 		r = RESUME_HOST;
 		BUG();
 		break;
 	}
-
+	}
 
 	if (!(r & RESUME_HOST)) {
 		/* To avoid clobbering exit_reason, only check for signals if
 		 * we aren't already exiting to userspace for some other
 		 * reason. */
+
+		/*
+		 * Interrupts could be timers for the guest which we have to
+		 * inject again, so let's postpone them until we're in the guest
+		 * and if we really did time things so badly, then we just exit
+		 * again due to a host external interrupt.
+		 */
+		__hard_irq_disable();
 		if (signal_pending(current)) {
+			__hard_irq_enable();
 #ifdef EXIT_DEBUG
 			printk(KERN_EMERG "KVM: Going back to host\n");
 #endif
@@ -761,10 +798,12 @@
 			run->exit_reason = KVM_EXIT_INTR;
 			r = -EINTR;
 		} else {
+			preempt_disable();
+
 			/* In case an interrupt came in that was triggered
 			 * from userspace (like DEC), we need to check what
 			 * to inject now! */
-			kvmppc_core_deliver_interrupts(vcpu);
+			kvmppc_core_prepare_to_enter(vcpu);
 		}
 	}
 
@@ -836,6 +875,38 @@
 	return 0;
 }
 
+int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+{
+	int r = -EINVAL;
+
+	switch (reg->id) {
+	case KVM_REG_PPC_HIOR:
+		r = put_user(to_book3s(vcpu)->hior, (u64 __user *)reg->addr);
+		break;
+	default:
+		break;
+	}
+
+	return r;
+}
+
+int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+{
+	int r = -EINVAL;
+
+	switch (reg->id) {
+	case KVM_REG_PPC_HIOR:
+		r = get_user(to_book3s(vcpu)->hior, (u64 __user *)reg->addr);
+		if (!r)
+			to_book3s(vcpu)->hior_explicit = true;
+		break;
+	default:
+		break;
+	}
+
+	return r;
+}
+
 int kvmppc_core_check_processor_compat(void)
 {
 	return 0;
@@ -923,16 +994,31 @@
 #endif
 	ulong ext_msr;
 
+	preempt_disable();
+
 	/* Check if we can run the vcpu at all */
 	if (!vcpu->arch.sane) {
 		kvm_run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
+	kvmppc_core_prepare_to_enter(vcpu);
+
+	/*
+	 * Interrupts could be timers for the guest which we have to inject
+	 * again, so let's postpone them until we're in the guest and if we
+	 * really did time things so badly, then we just exit again due to
+	 * a host external interrupt.
+	 */
+	__hard_irq_disable();
+
 	/* No need to go into the guest when all we do is going out */
 	if (signal_pending(current)) {
+		__hard_irq_enable();
 		kvm_run->exit_reason = KVM_EXIT_INTR;
-		return -EINTR;
+		ret = -EINTR;
+		goto out;
 	}
 
 	/* Save FPU state in stack */
@@ -974,8 +1060,6 @@
 
 	kvm_guest_exit();
 
-	local_irq_disable();
-
 	current->thread.regs->msr = ext_msr;
 
 	/* Make sure we save the guest FPU/Altivec/VSX state */
@@ -1002,9 +1086,50 @@
 	current->thread.used_vsr = used_vsr;
 #endif
 
+out:
+	preempt_enable();
 	return ret;
 }
 
+/*
+ * Get (and clear) the dirty memory log for a memory slot.
+ */
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
+				      struct kvm_dirty_log *log)
+{
+	struct kvm_memory_slot *memslot;
+	struct kvm_vcpu *vcpu;
+	ulong ga, ga_end;
+	int is_dirty = 0;
+	int r;
+	unsigned long n;
+
+	mutex_lock(&kvm->slots_lock);
+
+	r = kvm_get_dirty_log(kvm, log, &is_dirty);
+	if (r)
+		goto out;
+
+	/* If nothing is dirty, don't bother messing with page tables. */
+	if (is_dirty) {
+		memslot = id_to_memslot(kvm->memslots, log->slot);
+
+		ga = memslot->base_gfn << PAGE_SHIFT;
+		ga_end = ga + (memslot->npages << PAGE_SHIFT);
+
+		kvm_for_each_vcpu(n, vcpu, kvm)
+			kvmppc_mmu_pte_pflush(vcpu, ga, ga_end);
+
+		n = kvm_dirty_bitmap_bytes(memslot);
+		memset(memslot->dirty_bitmap, 0, n);
+	}
+
+	r = 0;
+out:
+	mutex_unlock(&kvm->slots_lock);
+	return r;
+}
+
 int kvmppc_core_prepare_memory_region(struct kvm *kvm,
 				      struct kvm_userspace_memory_region *mem)
 {
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index bb6c988..ee9e1ee 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -124,12 +124,6 @@
 	vcpu->arch.shared->msr = new_msr;
 
 	kvmppc_mmu_msr_notify(vcpu, old_msr);
-
-	if (vcpu->arch.shared->msr & MSR_WE) {
-		kvm_vcpu_block(vcpu);
-		kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS);
-	};
-
 	kvmppc_vcpu_sync_spe(vcpu);
 }
 
@@ -258,9 +252,11 @@
 		allowed = vcpu->arch.shared->msr & MSR_ME;
 		msr_mask = 0;
 		break;
-	case BOOKE_IRQPRIO_EXTERNAL:
 	case BOOKE_IRQPRIO_DECREMENTER:
 	case BOOKE_IRQPRIO_FIT:
+		keep_irq = true;
+		/* fall through */
+	case BOOKE_IRQPRIO_EXTERNAL:
 		allowed = vcpu->arch.shared->msr & MSR_EE;
 		allowed = allowed && !crit;
 		msr_mask = MSR_CE|MSR_ME|MSR_DE;
@@ -276,7 +272,7 @@
 		vcpu->arch.shared->srr1 = vcpu->arch.shared->msr;
 		vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[priority];
 		if (update_esr == true)
-			vcpu->arch.esr = vcpu->arch.queued_esr;
+			vcpu->arch.shared->esr = vcpu->arch.queued_esr;
 		if (update_dear == true)
 			vcpu->arch.shared->dar = vcpu->arch.queued_dear;
 		kvmppc_set_msr(vcpu, vcpu->arch.shared->msr & msr_mask);
@@ -288,13 +284,26 @@
 	return allowed;
 }
 
-/* Check pending exceptions and deliver one, if possible. */
-void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
+static void update_timer_ints(struct kvm_vcpu *vcpu)
+{
+	if ((vcpu->arch.tcr & TCR_DIE) && (vcpu->arch.tsr & TSR_DIS))
+		kvmppc_core_queue_dec(vcpu);
+	else
+		kvmppc_core_dequeue_dec(vcpu);
+}
+
+static void kvmppc_core_check_exceptions(struct kvm_vcpu *vcpu)
 {
 	unsigned long *pending = &vcpu->arch.pending_exceptions;
-	unsigned long old_pending = vcpu->arch.pending_exceptions;
 	unsigned int priority;
 
+	if (vcpu->requests) {
+		if (kvm_check_request(KVM_REQ_PENDING_TIMER, vcpu)) {
+			smp_mb();
+			update_timer_ints(vcpu);
+		}
+	}
+
 	priority = __ffs(*pending);
 	while (priority <= BOOKE_IRQPRIO_MAX) {
 		if (kvmppc_booke_irqprio_deliver(vcpu, priority))
@@ -306,10 +315,24 @@
 	}
 
 	/* Tell the guest about our interrupt status */
-	if (*pending)
-		vcpu->arch.shared->int_pending = 1;
-	else if (old_pending)
-		vcpu->arch.shared->int_pending = 0;
+	vcpu->arch.shared->int_pending = !!*pending;
+}
+
+/* Check pending exceptions and deliver one, if possible. */
+void kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
+{
+	WARN_ON_ONCE(!irqs_disabled());
+
+	kvmppc_core_check_exceptions(vcpu);
+
+	if (vcpu->arch.shared->msr & MSR_WE) {
+		local_irq_enable();
+		kvm_vcpu_block(vcpu);
+		local_irq_disable();
+
+		kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS);
+		kvmppc_core_check_exceptions(vcpu);
+	};
 }
 
 int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
@@ -322,11 +345,21 @@
 	}
 
 	local_irq_disable();
+
+	kvmppc_core_prepare_to_enter(vcpu);
+
+	if (signal_pending(current)) {
+		kvm_run->exit_reason = KVM_EXIT_INTR;
+		ret = -EINTR;
+		goto out;
+	}
+
 	kvm_guest_enter();
 	ret = __kvmppc_vcpu_run(kvm_run, vcpu);
 	kvm_guest_exit();
-	local_irq_enable();
 
+out:
+	local_irq_enable();
 	return ret;
 }
 
@@ -603,7 +636,7 @@
 
 	local_irq_disable();
 
-	kvmppc_core_deliver_interrupts(vcpu);
+	kvmppc_core_prepare_to_enter(vcpu);
 
 	if (!(r & RESUME_HOST)) {
 		/* To avoid clobbering exit_reason, only check for signals if
@@ -628,6 +661,7 @@
 	vcpu->arch.pc = 0;
 	vcpu->arch.shared->msr = 0;
 	vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS;
+	vcpu->arch.shared->pir = vcpu->vcpu_id;
 	kvmppc_set_gpr(vcpu, 1, (16<<20) - 8); /* -8 for the callee-save LR slot */
 
 	vcpu->arch.shadow_pid = 1;
@@ -662,10 +696,10 @@
 	regs->sprg1 = vcpu->arch.shared->sprg1;
 	regs->sprg2 = vcpu->arch.shared->sprg2;
 	regs->sprg3 = vcpu->arch.shared->sprg3;
-	regs->sprg4 = vcpu->arch.sprg4;
-	regs->sprg5 = vcpu->arch.sprg5;
-	regs->sprg6 = vcpu->arch.sprg6;
-	regs->sprg7 = vcpu->arch.sprg7;
+	regs->sprg4 = vcpu->arch.shared->sprg4;
+	regs->sprg5 = vcpu->arch.shared->sprg5;
+	regs->sprg6 = vcpu->arch.shared->sprg6;
+	regs->sprg7 = vcpu->arch.shared->sprg7;
 
 	for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
 		regs->gpr[i] = kvmppc_get_gpr(vcpu, i);
@@ -690,10 +724,10 @@
 	vcpu->arch.shared->sprg1 = regs->sprg1;
 	vcpu->arch.shared->sprg2 = regs->sprg2;
 	vcpu->arch.shared->sprg3 = regs->sprg3;
-	vcpu->arch.sprg4 = regs->sprg4;
-	vcpu->arch.sprg5 = regs->sprg5;
-	vcpu->arch.sprg6 = regs->sprg6;
-	vcpu->arch.sprg7 = regs->sprg7;
+	vcpu->arch.shared->sprg4 = regs->sprg4;
+	vcpu->arch.shared->sprg5 = regs->sprg5;
+	vcpu->arch.shared->sprg6 = regs->sprg6;
+	vcpu->arch.shared->sprg7 = regs->sprg7;
 
 	for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
 		kvmppc_set_gpr(vcpu, i, regs->gpr[i]);
@@ -711,7 +745,7 @@
 	sregs->u.e.csrr0 = vcpu->arch.csrr0;
 	sregs->u.e.csrr1 = vcpu->arch.csrr1;
 	sregs->u.e.mcsr = vcpu->arch.mcsr;
-	sregs->u.e.esr = vcpu->arch.esr;
+	sregs->u.e.esr = vcpu->arch.shared->esr;
 	sregs->u.e.dear = vcpu->arch.shared->dar;
 	sregs->u.e.tsr = vcpu->arch.tsr;
 	sregs->u.e.tcr = vcpu->arch.tcr;
@@ -729,28 +763,19 @@
 	vcpu->arch.csrr0 = sregs->u.e.csrr0;
 	vcpu->arch.csrr1 = sregs->u.e.csrr1;
 	vcpu->arch.mcsr = sregs->u.e.mcsr;
-	vcpu->arch.esr = sregs->u.e.esr;
+	vcpu->arch.shared->esr = sregs->u.e.esr;
 	vcpu->arch.shared->dar = sregs->u.e.dear;
 	vcpu->arch.vrsave = sregs->u.e.vrsave;
-	vcpu->arch.tcr = sregs->u.e.tcr;
+	kvmppc_set_tcr(vcpu, sregs->u.e.tcr);
 
-	if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_DEC)
+	if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_DEC) {
 		vcpu->arch.dec = sregs->u.e.dec;
-
-	kvmppc_emulate_dec(vcpu);
+		kvmppc_emulate_dec(vcpu);
+	}
 
 	if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_TSR) {
-		/*
-		 * FIXME: existing KVM timer handling is incomplete.
-		 * TSR cannot be read by the guest, and its value in
-		 * vcpu->arch is always zero.  For now, just handle
-		 * the case where the caller is trying to inject a
-		 * decrementer interrupt.
-		 */
-
-		if ((sregs->u.e.tsr & TSR_DIS) &&
-		    (vcpu->arch.tcr & TCR_DIE))
-			kvmppc_core_queue_dec(vcpu);
+		vcpu->arch.tsr = sregs->u.e.tsr;
+		update_timer_ints(vcpu);
 	}
 
 	return 0;
@@ -761,7 +786,7 @@
 {
 	sregs->u.e.features |= KVM_SREGS_E_ARCH206;
 
-	sregs->u.e.pir = 0;
+	sregs->u.e.pir = vcpu->vcpu_id;
 	sregs->u.e.mcsrr0 = vcpu->arch.mcsrr0;
 	sregs->u.e.mcsrr1 = vcpu->arch.mcsrr1;
 	sregs->u.e.decar = vcpu->arch.decar;
@@ -774,7 +799,7 @@
 	if (!(sregs->u.e.features & KVM_SREGS_E_ARCH206))
 		return 0;
 
-	if (sregs->u.e.pir != 0)
+	if (sregs->u.e.pir != vcpu->vcpu_id)
 		return -EINVAL;
 
 	vcpu->arch.mcsrr0 = sregs->u.e.mcsrr0;
@@ -862,6 +887,16 @@
 	return kvmppc_core_set_sregs(vcpu, sregs);
 }
 
+int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+{
+	return -EINVAL;
+}
+
+int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+{
+	return -EINVAL;
+}
+
 int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
 	return -ENOTSUPP;
@@ -906,6 +941,33 @@
 {
 }
 
+void kvmppc_set_tcr(struct kvm_vcpu *vcpu, u32 new_tcr)
+{
+	vcpu->arch.tcr = new_tcr;
+	update_timer_ints(vcpu);
+}
+
+void kvmppc_set_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits)
+{
+	set_bits(tsr_bits, &vcpu->arch.tsr);
+	smp_wmb();
+	kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
+	kvm_vcpu_kick(vcpu);
+}
+
+void kvmppc_clr_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits)
+{
+	clear_bits(tsr_bits, &vcpu->arch.tsr);
+	update_timer_ints(vcpu);
+}
+
+void kvmppc_decrementer_func(unsigned long data)
+{
+	struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
+
+	kvmppc_set_tsr_bits(vcpu, TSR_DIS);
+}
+
 int __init kvmppc_booke_init(void)
 {
 	unsigned long ivor[16];
diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h
index 8e1fe33..2fe2027 100644
--- a/arch/powerpc/kvm/booke.h
+++ b/arch/powerpc/kvm/booke.h
@@ -55,6 +55,10 @@
 void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr);
 void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr);
 
+void kvmppc_set_tcr(struct kvm_vcpu *vcpu, u32 new_tcr);
+void kvmppc_set_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits);
+void kvmppc_clr_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits);
+
 int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                             unsigned int inst, int *advance);
 int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt);
diff --git a/arch/powerpc/kvm/booke_emulate.c b/arch/powerpc/kvm/booke_emulate.c
index 1260f5f..3e652da 100644
--- a/arch/powerpc/kvm/booke_emulate.c
+++ b/arch/powerpc/kvm/booke_emulate.c
@@ -13,6 +13,7 @@
  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  *
  * Copyright IBM Corp. 2008
+ * Copyright 2011 Freescale Semiconductor, Inc.
  *
  * Authors: Hollis Blanchard <hollisb@us.ibm.com>
  */
@@ -107,7 +108,7 @@
 	case SPRN_DEAR:
 		vcpu->arch.shared->dar = spr_val; break;
 	case SPRN_ESR:
-		vcpu->arch.esr = spr_val; break;
+		vcpu->arch.shared->esr = spr_val; break;
 	case SPRN_DBCR0:
 		vcpu->arch.dbcr0 = spr_val; break;
 	case SPRN_DBCR1:
@@ -115,23 +116,23 @@
 	case SPRN_DBSR:
 		vcpu->arch.dbsr &= ~spr_val; break;
 	case SPRN_TSR:
-		vcpu->arch.tsr &= ~spr_val; break;
+		kvmppc_clr_tsr_bits(vcpu, spr_val);
+		break;
 	case SPRN_TCR:
-		vcpu->arch.tcr = spr_val;
-		kvmppc_emulate_dec(vcpu);
+		kvmppc_set_tcr(vcpu, spr_val);
 		break;
 
 	/* Note: SPRG4-7 are user-readable. These values are
 	 * loaded into the real SPRGs when resuming the
 	 * guest. */
 	case SPRN_SPRG4:
-		vcpu->arch.sprg4 = spr_val; break;
+		vcpu->arch.shared->sprg4 = spr_val; break;
 	case SPRN_SPRG5:
-		vcpu->arch.sprg5 = spr_val; break;
+		vcpu->arch.shared->sprg5 = spr_val; break;
 	case SPRN_SPRG6:
-		vcpu->arch.sprg6 = spr_val; break;
+		vcpu->arch.shared->sprg6 = spr_val; break;
 	case SPRN_SPRG7:
-		vcpu->arch.sprg7 = spr_val; break;
+		vcpu->arch.shared->sprg7 = spr_val; break;
 
 	case SPRN_IVPR:
 		vcpu->arch.ivpr = spr_val;
@@ -202,13 +203,17 @@
 	case SPRN_DEAR:
 		kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->dar); break;
 	case SPRN_ESR:
-		kvmppc_set_gpr(vcpu, rt, vcpu->arch.esr); break;
+		kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->esr); break;
 	case SPRN_DBCR0:
 		kvmppc_set_gpr(vcpu, rt, vcpu->arch.dbcr0); break;
 	case SPRN_DBCR1:
 		kvmppc_set_gpr(vcpu, rt, vcpu->arch.dbcr1); break;
 	case SPRN_DBSR:
 		kvmppc_set_gpr(vcpu, rt, vcpu->arch.dbsr); break;
+	case SPRN_TSR:
+		kvmppc_set_gpr(vcpu, rt, vcpu->arch.tsr); break;
+	case SPRN_TCR:
+		kvmppc_set_gpr(vcpu, rt, vcpu->arch.tcr); break;
 
 	case SPRN_IVOR0:
 		kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL]);
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S
index 42f2fb1..10d8ef6 100644
--- a/arch/powerpc/kvm/booke_interrupts.S
+++ b/arch/powerpc/kvm/booke_interrupts.S
@@ -402,19 +402,25 @@
 	/* Save vcpu pointer for the exception handlers. */
 	mtspr	SPRN_SPRG_WVCPU, r4
 
+	lwz	r5, VCPU_SHARED(r4)
+
 	/* Can't switch the stack pointer until after IVPR is switched,
 	 * because host interrupt handlers would get confused. */
 	lwz	r1, VCPU_GPR(r1)(r4)
 
-	/* Host interrupt handlers may have clobbered these guest-readable
-	 * SPRGs, so we need to reload them here with the guest's values. */
-	lwz	r3, VCPU_SPRG4(r4)
+	/*
+	 * Host interrupt handlers may have clobbered these
+	 * guest-readable SPRGs, or the guest kernel may have
+	 * written directly to the shared area, so we
+	 * need to reload them here with the guest's values.
+	 */
+	lwz	r3, VCPU_SHARED_SPRG4(r5)
 	mtspr	SPRN_SPRG4W, r3
-	lwz	r3, VCPU_SPRG5(r4)
+	lwz	r3, VCPU_SHARED_SPRG5(r5)
 	mtspr	SPRN_SPRG5W, r3
-	lwz	r3, VCPU_SPRG6(r4)
+	lwz	r3, VCPU_SHARED_SPRG6(r5)
 	mtspr	SPRN_SPRG6W, r3
-	lwz	r3, VCPU_SPRG7(r4)
+	lwz	r3, VCPU_SHARED_SPRG7(r5)
 	mtspr	SPRN_SPRG7W, r3
 
 #ifdef CONFIG_KVM_EXIT_TIMING
diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c
index 8c0d45a..ddcd896 100644
--- a/arch/powerpc/kvm/e500.c
+++ b/arch/powerpc/kvm/e500.c
@@ -71,9 +71,6 @@
 	vcpu->arch.pvr = mfspr(SPRN_PVR);
 	vcpu_e500->svr = mfspr(SPRN_SVR);
 
-	/* Since booke kvm only support one core, update all vcpus' PIR to 0 */
-	vcpu->vcpu_id = 0;
-
 	vcpu->arch.cpu_type = KVM_CPU_E500V2;
 
 	return 0;
@@ -118,12 +115,12 @@
 	sregs->u.e.impl.fsl.hid0 = vcpu_e500->hid0;
 	sregs->u.e.impl.fsl.mcar = vcpu_e500->mcar;
 
-	sregs->u.e.mas0 = vcpu_e500->mas0;
-	sregs->u.e.mas1 = vcpu_e500->mas1;
-	sregs->u.e.mas2 = vcpu_e500->mas2;
-	sregs->u.e.mas7_3 = ((u64)vcpu_e500->mas7 << 32) | vcpu_e500->mas3;
-	sregs->u.e.mas4 = vcpu_e500->mas4;
-	sregs->u.e.mas6 = vcpu_e500->mas6;
+	sregs->u.e.mas0 = vcpu->arch.shared->mas0;
+	sregs->u.e.mas1 = vcpu->arch.shared->mas1;
+	sregs->u.e.mas2 = vcpu->arch.shared->mas2;
+	sregs->u.e.mas7_3 = vcpu->arch.shared->mas7_3;
+	sregs->u.e.mas4 = vcpu->arch.shared->mas4;
+	sregs->u.e.mas6 = vcpu->arch.shared->mas6;
 
 	sregs->u.e.mmucfg = mfspr(SPRN_MMUCFG);
 	sregs->u.e.tlbcfg[0] = vcpu_e500->tlb0cfg;
@@ -151,13 +148,12 @@
 	}
 
 	if (sregs->u.e.features & KVM_SREGS_E_ARCH206_MMU) {
-		vcpu_e500->mas0 = sregs->u.e.mas0;
-		vcpu_e500->mas1 = sregs->u.e.mas1;
-		vcpu_e500->mas2 = sregs->u.e.mas2;
-		vcpu_e500->mas7 = sregs->u.e.mas7_3 >> 32;
-		vcpu_e500->mas3 = (u32)sregs->u.e.mas7_3;
-		vcpu_e500->mas4 = sregs->u.e.mas4;
-		vcpu_e500->mas6 = sregs->u.e.mas6;
+		vcpu->arch.shared->mas0 = sregs->u.e.mas0;
+		vcpu->arch.shared->mas1 = sregs->u.e.mas1;
+		vcpu->arch.shared->mas2 = sregs->u.e.mas2;
+		vcpu->arch.shared->mas7_3 = sregs->u.e.mas7_3;
+		vcpu->arch.shared->mas4 = sregs->u.e.mas4;
+		vcpu->arch.shared->mas6 = sregs->u.e.mas6;
 	}
 
 	if (!(sregs->u.e.features & KVM_SREGS_E_IVOR))
@@ -233,6 +229,10 @@
 	unsigned long ivor[3];
 	unsigned long max_ivor = 0;
 
+	r = kvmppc_core_check_processor_compat();
+	if (r)
+		return r;
+
 	r = kvmppc_booke_init();
 	if (r)
 		return r;
diff --git a/arch/powerpc/kvm/e500_emulate.c b/arch/powerpc/kvm/e500_emulate.c
index d48ae39..6d0b2bd 100644
--- a/arch/powerpc/kvm/e500_emulate.c
+++ b/arch/powerpc/kvm/e500_emulate.c
@@ -89,19 +89,23 @@
 			return EMULATE_FAIL;
 		vcpu_e500->pid[2] = spr_val; break;
 	case SPRN_MAS0:
-		vcpu_e500->mas0 = spr_val; break;
+		vcpu->arch.shared->mas0 = spr_val; break;
 	case SPRN_MAS1:
-		vcpu_e500->mas1 = spr_val; break;
+		vcpu->arch.shared->mas1 = spr_val; break;
 	case SPRN_MAS2:
-		vcpu_e500->mas2 = spr_val; break;
+		vcpu->arch.shared->mas2 = spr_val; break;
 	case SPRN_MAS3:
-		vcpu_e500->mas3 = spr_val; break;
+		vcpu->arch.shared->mas7_3 &= ~(u64)0xffffffff;
+		vcpu->arch.shared->mas7_3 |= spr_val;
+		break;
 	case SPRN_MAS4:
-		vcpu_e500->mas4 = spr_val; break;
+		vcpu->arch.shared->mas4 = spr_val; break;
 	case SPRN_MAS6:
-		vcpu_e500->mas6 = spr_val; break;
+		vcpu->arch.shared->mas6 = spr_val; break;
 	case SPRN_MAS7:
-		vcpu_e500->mas7 = spr_val; break;
+		vcpu->arch.shared->mas7_3 &= (u64)0xffffffff;
+		vcpu->arch.shared->mas7_3 |= (u64)spr_val << 32;
+		break;
 	case SPRN_L1CSR0:
 		vcpu_e500->l1csr0 = spr_val;
 		vcpu_e500->l1csr0 &= ~(L1CSR0_DCFI | L1CSR0_CLFC);
@@ -143,6 +147,7 @@
 {
 	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
 	int emulated = EMULATE_DONE;
+	unsigned long val;
 
 	switch (sprn) {
 	case SPRN_PID:
@@ -152,20 +157,23 @@
 	case SPRN_PID2:
 		kvmppc_set_gpr(vcpu, rt, vcpu_e500->pid[2]); break;
 	case SPRN_MAS0:
-		kvmppc_set_gpr(vcpu, rt, vcpu_e500->mas0); break;
+		kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->mas0); break;
 	case SPRN_MAS1:
-		kvmppc_set_gpr(vcpu, rt, vcpu_e500->mas1); break;
+		kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->mas1); break;
 	case SPRN_MAS2:
-		kvmppc_set_gpr(vcpu, rt, vcpu_e500->mas2); break;
+		kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->mas2); break;
 	case SPRN_MAS3:
-		kvmppc_set_gpr(vcpu, rt, vcpu_e500->mas3); break;
+		val = (u32)vcpu->arch.shared->mas7_3;
+		kvmppc_set_gpr(vcpu, rt, val);
+		break;
 	case SPRN_MAS4:
-		kvmppc_set_gpr(vcpu, rt, vcpu_e500->mas4); break;
+		kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->mas4); break;
 	case SPRN_MAS6:
-		kvmppc_set_gpr(vcpu, rt, vcpu_e500->mas6); break;
+		kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->mas6); break;
 	case SPRN_MAS7:
-		kvmppc_set_gpr(vcpu, rt, vcpu_e500->mas7); break;
-
+		val = vcpu->arch.shared->mas7_3 >> 32;
+		kvmppc_set_gpr(vcpu, rt, val);
+		break;
 	case SPRN_TLB0CFG:
 		kvmppc_set_gpr(vcpu, rt, vcpu_e500->tlb0cfg); break;
 	case SPRN_TLB1CFG:
diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c
index 13c432e..6e53e41 100644
--- a/arch/powerpc/kvm/e500_tlb.c
+++ b/arch/powerpc/kvm/e500_tlb.c
@@ -12,12 +12,19 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/highmem.h>
+#include <linux/log2.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/rwsem.h>
+#include <linux/vmalloc.h>
+#include <linux/hugetlb.h>
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_e500.h>
 
@@ -26,7 +33,7 @@
 #include "trace.h"
 #include "timing.h"
 
-#define to_htlb1_esel(esel) (tlb1_entry_num - (esel) - 1)
+#define to_htlb1_esel(esel) (host_tlb_params[1].entries - (esel) - 1)
 
 struct id {
 	unsigned long val;
@@ -63,7 +70,14 @@
  * The valid range of shadow ID is [1..255] */
 static DEFINE_PER_CPU(unsigned long, pcpu_last_used_sid);
 
-static unsigned int tlb1_entry_num;
+static struct kvmppc_e500_tlb_params host_tlb_params[E500_TLB_NUM];
+
+static struct kvm_book3e_206_tlb_entry *get_entry(
+	struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel, int entry)
+{
+	int offset = vcpu_e500->gtlb_offset[tlbsel];
+	return &vcpu_e500->gtlb_arch[offset + entry];
+}
 
 /*
  * Allocate a free shadow id and setup a valid sid mapping in given entry.
@@ -116,13 +130,11 @@
 	return -1;
 }
 
-/* Invalidate all id mappings on local core */
+/* Invalidate all id mappings on local core -- call with preempt disabled */
 static inline void local_sid_destroy_all(void)
 {
-	preempt_disable();
 	__get_cpu_var(pcpu_last_used_sid) = 0;
 	memset(&__get_cpu_var(pcpu_sids), 0, sizeof(__get_cpu_var(pcpu_sids)));
-	preempt_enable();
 }
 
 static void *kvmppc_e500_id_table_alloc(struct kvmppc_vcpu_e500 *vcpu_e500)
@@ -218,34 +230,13 @@
 	preempt_enable();
 }
 
-void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu)
-{
-	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
-	struct tlbe *tlbe;
-	int i, tlbsel;
-
-	printk("| %8s | %8s | %8s | %8s | %8s |\n",
-			"nr", "mas1", "mas2", "mas3", "mas7");
-
-	for (tlbsel = 0; tlbsel < 2; tlbsel++) {
-		printk("Guest TLB%d:\n", tlbsel);
-		for (i = 0; i < vcpu_e500->gtlb_size[tlbsel]; i++) {
-			tlbe = &vcpu_e500->gtlb_arch[tlbsel][i];
-			if (tlbe->mas1 & MAS1_VALID)
-				printk(" G[%d][%3d] |  %08X | %08X | %08X | %08X |\n",
-					tlbsel, i, tlbe->mas1, tlbe->mas2,
-					tlbe->mas3, tlbe->mas7);
-		}
-	}
-}
-
-static inline unsigned int tlb0_get_next_victim(
+static inline unsigned int gtlb0_get_next_victim(
 		struct kvmppc_vcpu_e500 *vcpu_e500)
 {
 	unsigned int victim;
 
 	victim = vcpu_e500->gtlb_nv[0]++;
-	if (unlikely(vcpu_e500->gtlb_nv[0] >= KVM_E500_TLB0_WAY_NUM))
+	if (unlikely(vcpu_e500->gtlb_nv[0] >= vcpu_e500->gtlb_params[0].ways))
 		vcpu_e500->gtlb_nv[0] = 0;
 
 	return victim;
@@ -254,12 +245,12 @@
 static inline unsigned int tlb1_max_shadow_size(void)
 {
 	/* reserve one entry for magic page */
-	return tlb1_entry_num - tlbcam_index - 1;
+	return host_tlb_params[1].entries - tlbcam_index - 1;
 }
 
-static inline int tlbe_is_writable(struct tlbe *tlbe)
+static inline int tlbe_is_writable(struct kvm_book3e_206_tlb_entry *tlbe)
 {
-	return tlbe->mas3 & (MAS3_SW|MAS3_UW);
+	return tlbe->mas7_3 & (MAS3_SW|MAS3_UW);
 }
 
 static inline u32 e500_shadow_mas3_attrib(u32 mas3, int usermode)
@@ -290,40 +281,66 @@
 /*
  * writing shadow tlb entry to host TLB
  */
-static inline void __write_host_tlbe(struct tlbe *stlbe, uint32_t mas0)
+static inline void __write_host_tlbe(struct kvm_book3e_206_tlb_entry *stlbe,
+				     uint32_t mas0)
 {
 	unsigned long flags;
 
 	local_irq_save(flags);
 	mtspr(SPRN_MAS0, mas0);
 	mtspr(SPRN_MAS1, stlbe->mas1);
-	mtspr(SPRN_MAS2, stlbe->mas2);
-	mtspr(SPRN_MAS3, stlbe->mas3);
-	mtspr(SPRN_MAS7, stlbe->mas7);
+	mtspr(SPRN_MAS2, (unsigned long)stlbe->mas2);
+	mtspr(SPRN_MAS3, (u32)stlbe->mas7_3);
+	mtspr(SPRN_MAS7, (u32)(stlbe->mas7_3 >> 32));
 	asm volatile("isync; tlbwe" : : : "memory");
 	local_irq_restore(flags);
+
+	trace_kvm_booke206_stlb_write(mas0, stlbe->mas8, stlbe->mas1,
+	                              stlbe->mas2, stlbe->mas7_3);
 }
 
-static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500,
-		int tlbsel, int esel, struct tlbe *stlbe)
+/*
+ * Acquire a mas0 with victim hint, as if we just took a TLB miss.
+ *
+ * We don't care about the address we're searching for, other than that it's
+ * in the right set and is not present in the TLB.  Using a zero PID and a
+ * userspace address means we don't have to set and then restore MAS5, or
+ * calculate a proper MAS6 value.
+ */
+static u32 get_host_mas0(unsigned long eaddr)
 {
+	unsigned long flags;
+	u32 mas0;
+
+	local_irq_save(flags);
+	mtspr(SPRN_MAS6, 0);
+	asm volatile("tlbsx 0, %0" : : "b" (eaddr & ~CONFIG_PAGE_OFFSET));
+	mas0 = mfspr(SPRN_MAS0);
+	local_irq_restore(flags);
+
+	return mas0;
+}
+
+/* sesel is for tlb1 only */
+static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500,
+		int tlbsel, int sesel, struct kvm_book3e_206_tlb_entry *stlbe)
+{
+	u32 mas0;
+
 	if (tlbsel == 0) {
-		__write_host_tlbe(stlbe,
-				  MAS0_TLBSEL(0) |
-				  MAS0_ESEL(esel & (KVM_E500_TLB0_WAY_NUM - 1)));
+		mas0 = get_host_mas0(stlbe->mas2);
+		__write_host_tlbe(stlbe, mas0);
 	} else {
 		__write_host_tlbe(stlbe,
 				  MAS0_TLBSEL(1) |
-				  MAS0_ESEL(to_htlb1_esel(esel)));
+				  MAS0_ESEL(to_htlb1_esel(sesel)));
 	}
-	trace_kvm_stlb_write(index_of(tlbsel, esel), stlbe->mas1, stlbe->mas2,
-			     stlbe->mas3, stlbe->mas7);
 }
 
 void kvmppc_map_magic(struct kvm_vcpu *vcpu)
 {
 	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
-	struct tlbe magic;
+	struct kvm_book3e_206_tlb_entry magic;
 	ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK;
 	unsigned int stid;
 	pfn_t pfn;
@@ -337,9 +354,9 @@
 	magic.mas1 = MAS1_VALID | MAS1_TS | MAS1_TID(stid) |
 		     MAS1_TSIZE(BOOK3E_PAGESZ_4K);
 	magic.mas2 = vcpu->arch.magic_page_ea | MAS2_M;
-	magic.mas3 = (pfn << PAGE_SHIFT) |
-		     MAS3_SW | MAS3_SR | MAS3_UW | MAS3_UR;
-	magic.mas7 = pfn >> (32 - PAGE_SHIFT);
+	magic.mas7_3 = ((u64)pfn << PAGE_SHIFT) |
+		       MAS3_SW | MAS3_SR | MAS3_UW | MAS3_UR;
+	magic.mas8 = 0;
 
 	__write_host_tlbe(&magic, MAS0_TLBSEL(1) | MAS0_ESEL(tlbcam_index));
 	preempt_enable();
@@ -357,10 +374,11 @@
 {
 }
 
-static void kvmppc_e500_stlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500,
-					 int tlbsel, int esel)
+static void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500,
+				int tlbsel, int esel)
 {
-	struct tlbe *gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel];
+	struct kvm_book3e_206_tlb_entry *gtlbe =
+		get_entry(vcpu_e500, tlbsel, esel);
 	struct vcpu_id_table *idt = vcpu_e500->idt;
 	unsigned int pr, tid, ts, pid;
 	u32 val, eaddr;
@@ -414,25 +432,57 @@
 	preempt_enable();
 }
 
+static int tlb0_set_base(gva_t addr, int sets, int ways)
+{
+	int set_base;
+
+	set_base = (addr >> PAGE_SHIFT) & (sets - 1);
+	set_base *= ways;
+
+	return set_base;
+}
+
+static int gtlb0_set_base(struct kvmppc_vcpu_e500 *vcpu_e500, gva_t addr)
+{
+	return tlb0_set_base(addr, vcpu_e500->gtlb_params[0].sets,
+			     vcpu_e500->gtlb_params[0].ways);
+}
+
+static unsigned int get_tlb_esel(struct kvm_vcpu *vcpu, int tlbsel)
+{
+	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
+	int esel = get_tlb_esel_bit(vcpu);
+
+	if (tlbsel == 0) {
+		esel &= vcpu_e500->gtlb_params[0].ways - 1;
+		esel += gtlb0_set_base(vcpu_e500, vcpu->arch.shared->mas2);
+	} else {
+		esel &= vcpu_e500->gtlb_params[tlbsel].entries - 1;
+	}
+
+	return esel;
+}
+
 /* Search the guest TLB for a matching entry. */
 static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500,
 		gva_t eaddr, int tlbsel, unsigned int pid, int as)
 {
-	int size = vcpu_e500->gtlb_size[tlbsel];
-	int set_base;
+	int size = vcpu_e500->gtlb_params[tlbsel].entries;
+	unsigned int set_base, offset;
 	int i;
 
 	if (tlbsel == 0) {
-		int mask = size / KVM_E500_TLB0_WAY_NUM - 1;
-		set_base = (eaddr >> PAGE_SHIFT) & mask;
-		set_base *= KVM_E500_TLB0_WAY_NUM;
-		size = KVM_E500_TLB0_WAY_NUM;
+		set_base = gtlb0_set_base(vcpu_e500, eaddr);
+		size = vcpu_e500->gtlb_params[0].ways;
 	} else {
 		set_base = 0;
 	}
 
+	offset = vcpu_e500->gtlb_offset[tlbsel];
+
 	for (i = 0; i < size; i++) {
-		struct tlbe *tlbe = &vcpu_e500->gtlb_arch[tlbsel][set_base + i];
+		struct kvm_book3e_206_tlb_entry *tlbe =
+			&vcpu_e500->gtlb_arch[offset + set_base + i];
 		unsigned int tid;
 
 		if (eaddr < get_tlb_eaddr(tlbe))
@@ -457,29 +507,57 @@
 	return -1;
 }
 
-static inline void kvmppc_e500_priv_setup(struct tlbe_priv *priv,
-					  struct tlbe *gtlbe,
-					  pfn_t pfn)
+static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
+					 struct kvm_book3e_206_tlb_entry *gtlbe,
+					 pfn_t pfn)
 {
-	priv->pfn = pfn;
-	priv->flags = E500_TLB_VALID;
+	ref->pfn = pfn;
+	ref->flags = E500_TLB_VALID;
 
 	if (tlbe_is_writable(gtlbe))
-		priv->flags |= E500_TLB_DIRTY;
+		ref->flags |= E500_TLB_DIRTY;
 }
 
-static inline void kvmppc_e500_priv_release(struct tlbe_priv *priv)
+static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref)
 {
-	if (priv->flags & E500_TLB_VALID) {
-		if (priv->flags & E500_TLB_DIRTY)
-			kvm_release_pfn_dirty(priv->pfn);
+	if (ref->flags & E500_TLB_VALID) {
+		if (ref->flags & E500_TLB_DIRTY)
+			kvm_release_pfn_dirty(ref->pfn);
 		else
-			kvm_release_pfn_clean(priv->pfn);
+			kvm_release_pfn_clean(ref->pfn);
 
-		priv->flags = 0;
+		ref->flags = 0;
 	}
 }
 
+static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500)
+{
+	int tlbsel = 0;
+	int i;
+
+	for (i = 0; i < vcpu_e500->gtlb_params[tlbsel].entries; i++) {
+		struct tlbe_ref *ref =
+			&vcpu_e500->gtlb_priv[tlbsel][i].ref;
+		kvmppc_e500_ref_release(ref);
+	}
+}
+
+static void clear_tlb_refs(struct kvmppc_vcpu_e500 *vcpu_e500)
+{
+	int stlbsel = 1;
+	int i;
+
+	kvmppc_e500_id_table_reset_all(vcpu_e500);
+
+	for (i = 0; i < host_tlb_params[stlbsel].entries; i++) {
+		struct tlbe_ref *ref =
+			&vcpu_e500->tlb_refs[stlbsel][i];
+		kvmppc_e500_ref_release(ref);
+	}
+
+	clear_tlb_privs(vcpu_e500);
+}
+
 static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu,
 		unsigned int eaddr, int as)
 {
@@ -488,59 +566,54 @@
 	int tlbsel;
 
 	/* since we only have two TLBs, only lower bit is used. */
-	tlbsel = (vcpu_e500->mas4 >> 28) & 0x1;
-	victim = (tlbsel == 0) ? tlb0_get_next_victim(vcpu_e500) : 0;
-	pidsel = (vcpu_e500->mas4 >> 16) & 0xf;
-	tsized = (vcpu_e500->mas4 >> 7) & 0x1f;
+	tlbsel = (vcpu->arch.shared->mas4 >> 28) & 0x1;
+	victim = (tlbsel == 0) ? gtlb0_get_next_victim(vcpu_e500) : 0;
+	pidsel = (vcpu->arch.shared->mas4 >> 16) & 0xf;
+	tsized = (vcpu->arch.shared->mas4 >> 7) & 0x1f;
 
-	vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim)
+	vcpu->arch.shared->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim)
 		| MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]);
-	vcpu_e500->mas1 = MAS1_VALID | (as ? MAS1_TS : 0)
+	vcpu->arch.shared->mas1 = MAS1_VALID | (as ? MAS1_TS : 0)
 		| MAS1_TID(vcpu_e500->pid[pidsel])
 		| MAS1_TSIZE(tsized);
-	vcpu_e500->mas2 = (eaddr & MAS2_EPN)
-		| (vcpu_e500->mas4 & MAS2_ATTRIB_MASK);
-	vcpu_e500->mas3 &= MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3;
-	vcpu_e500->mas6 = (vcpu_e500->mas6 & MAS6_SPID1)
+	vcpu->arch.shared->mas2 = (eaddr & MAS2_EPN)
+		| (vcpu->arch.shared->mas4 & MAS2_ATTRIB_MASK);
+	vcpu->arch.shared->mas7_3 &= MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3;
+	vcpu->arch.shared->mas6 = (vcpu->arch.shared->mas6 & MAS6_SPID1)
 		| (get_cur_pid(vcpu) << 16)
 		| (as ? MAS6_SAS : 0);
-	vcpu_e500->mas7 = 0;
 }
 
-static inline void kvmppc_e500_setup_stlbe(struct kvmppc_vcpu_e500 *vcpu_e500,
-					   struct tlbe *gtlbe, int tsize,
-					   struct tlbe_priv *priv,
-					   u64 gvaddr, struct tlbe *stlbe)
+/* TID must be supplied by the caller */
+static inline void kvmppc_e500_setup_stlbe(
+	struct kvmppc_vcpu_e500 *vcpu_e500,
+	struct kvm_book3e_206_tlb_entry *gtlbe,
+	int tsize, struct tlbe_ref *ref, u64 gvaddr,
+	struct kvm_book3e_206_tlb_entry *stlbe)
 {
-	pfn_t pfn = priv->pfn;
-	unsigned int stid;
+	pfn_t pfn = ref->pfn;
 
-	stid = kvmppc_e500_get_sid(vcpu_e500, get_tlb_ts(gtlbe),
-				   get_tlb_tid(gtlbe),
-				   get_cur_pr(&vcpu_e500->vcpu), 0);
+	BUG_ON(!(ref->flags & E500_TLB_VALID));
 
 	/* Force TS=1 IPROT=0 for all guest mappings. */
-	stlbe->mas1 = MAS1_TSIZE(tsize)
-		| MAS1_TID(stid) | MAS1_TS | MAS1_VALID;
+	stlbe->mas1 = MAS1_TSIZE(tsize) | MAS1_TS | MAS1_VALID;
 	stlbe->mas2 = (gvaddr & MAS2_EPN)
 		| e500_shadow_mas2_attrib(gtlbe->mas2,
 				vcpu_e500->vcpu.arch.shared->msr & MSR_PR);
-	stlbe->mas3 = ((pfn << PAGE_SHIFT) & MAS3_RPN)
-		| e500_shadow_mas3_attrib(gtlbe->mas3,
+	stlbe->mas7_3 = ((u64)pfn << PAGE_SHIFT)
+		| e500_shadow_mas3_attrib(gtlbe->mas7_3,
 				vcpu_e500->vcpu.arch.shared->msr & MSR_PR);
-	stlbe->mas7 = (pfn >> (32 - PAGE_SHIFT)) & MAS7_RPN;
 }
 
-
 static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
-	u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, int tlbsel, int esel,
-	struct tlbe *stlbe)
+	u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe,
+	int tlbsel, struct kvm_book3e_206_tlb_entry *stlbe,
+	struct tlbe_ref *ref)
 {
 	struct kvm_memory_slot *slot;
 	unsigned long pfn, hva;
 	int pfnmap = 0;
 	int tsize = BOOK3E_PAGESZ_4K;
-	struct tlbe_priv *priv;
 
 	/*
 	 * Translate guest physical to true physical, acquiring
@@ -621,12 +694,31 @@
 				pfn &= ~(tsize_pages - 1);
 				break;
 			}
+		} else if (vma && hva >= vma->vm_start &&
+			   (vma->vm_flags & VM_HUGETLB)) {
+			unsigned long psize = vma_kernel_pagesize(vma);
+
+			tsize = (gtlbe->mas1 & MAS1_TSIZE_MASK) >>
+				MAS1_TSIZE_SHIFT;
+
+			/*
+			 * Take the largest page size that satisfies both host
+			 * and guest mapping
+			 */
+			tsize = min(__ilog2(psize) - 10, tsize);
+
+			/*
+			 * e500 doesn't implement the lowest tsize bit,
+			 * or 1K pages.
+			 */
+			tsize = max(BOOK3E_PAGESZ_4K, tsize & ~1);
 		}
 
 		up_read(&current->mm->mmap_sem);
 	}
 
 	if (likely(!pfnmap)) {
+		unsigned long tsize_pages = 1 << (tsize + 10 - PAGE_SHIFT);
 		pfn = gfn_to_pfn_memslot(vcpu_e500->vcpu.kvm, slot, gfn);
 		if (is_error_pfn(pfn)) {
 			printk(KERN_ERR "Couldn't get real page for gfn %lx!\n",
@@ -634,45 +726,52 @@
 			kvm_release_pfn_clean(pfn);
 			return;
 		}
+
+		/* Align guest and physical address to page map boundaries */
+		pfn &= ~(tsize_pages - 1);
+		gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1);
 	}
 
-	/* Drop old priv and setup new one. */
-	priv = &vcpu_e500->gtlb_priv[tlbsel][esel];
-	kvmppc_e500_priv_release(priv);
-	kvmppc_e500_priv_setup(priv, gtlbe, pfn);
+	/* Drop old ref and setup new one. */
+	kvmppc_e500_ref_release(ref);
+	kvmppc_e500_ref_setup(ref, gtlbe, pfn);
 
-	kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, tsize, priv, gvaddr, stlbe);
+	kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, tsize, ref, gvaddr, stlbe);
 }
 
 /* XXX only map the one-one case, for now use TLB0 */
-static int kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500,
-				int esel, struct tlbe *stlbe)
+static void kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500,
+				 int esel,
+				 struct kvm_book3e_206_tlb_entry *stlbe)
 {
-	struct tlbe *gtlbe;
+	struct kvm_book3e_206_tlb_entry *gtlbe;
+	struct tlbe_ref *ref;
 
-	gtlbe = &vcpu_e500->gtlb_arch[0][esel];
+	gtlbe = get_entry(vcpu_e500, 0, esel);
+	ref = &vcpu_e500->gtlb_priv[0][esel].ref;
 
 	kvmppc_e500_shadow_map(vcpu_e500, get_tlb_eaddr(gtlbe),
 			get_tlb_raddr(gtlbe) >> PAGE_SHIFT,
-			gtlbe, 0, esel, stlbe);
-
-	return esel;
+			gtlbe, 0, stlbe, ref);
 }
 
 /* Caller must ensure that the specified guest TLB entry is safe to insert into
  * the shadow TLB. */
 /* XXX for both one-one and one-to-many , for now use TLB1 */
 static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500,
-		u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, struct tlbe *stlbe)
+		u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe,
+		struct kvm_book3e_206_tlb_entry *stlbe)
 {
+	struct tlbe_ref *ref;
 	unsigned int victim;
 
-	victim = vcpu_e500->gtlb_nv[1]++;
+	victim = vcpu_e500->host_tlb1_nv++;
 
-	if (unlikely(vcpu_e500->gtlb_nv[1] >= tlb1_max_shadow_size()))
-		vcpu_e500->gtlb_nv[1] = 0;
+	if (unlikely(vcpu_e500->host_tlb1_nv >= tlb1_max_shadow_size()))
+		vcpu_e500->host_tlb1_nv = 0;
 
-	kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, victim, stlbe);
+	ref = &vcpu_e500->tlb_refs[1][victim];
+	kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, stlbe, ref);
 
 	return victim;
 }
@@ -689,7 +788,8 @@
 				struct kvmppc_vcpu_e500 *vcpu_e500,
 				int tlbsel, int esel)
 {
-	struct tlbe *gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel];
+	struct kvm_book3e_206_tlb_entry *gtlbe =
+		get_entry(vcpu_e500, tlbsel, esel);
 
 	if (unlikely(get_tlb_iprot(gtlbe)))
 		return -1;
@@ -704,10 +804,10 @@
 	int esel;
 
 	if (value & MMUCSR0_TLB0FI)
-		for (esel = 0; esel < vcpu_e500->gtlb_size[0]; esel++)
+		for (esel = 0; esel < vcpu_e500->gtlb_params[0].entries; esel++)
 			kvmppc_e500_gtlbe_invalidate(vcpu_e500, 0, esel);
 	if (value & MMUCSR0_TLB1FI)
-		for (esel = 0; esel < vcpu_e500->gtlb_size[1]; esel++)
+		for (esel = 0; esel < vcpu_e500->gtlb_params[1].entries; esel++)
 			kvmppc_e500_gtlbe_invalidate(vcpu_e500, 1, esel);
 
 	/* Invalidate all vcpu id mappings */
@@ -732,7 +832,8 @@
 
 	if (ia) {
 		/* invalidate all entries */
-		for (esel = 0; esel < vcpu_e500->gtlb_size[tlbsel]; esel++)
+		for (esel = 0; esel < vcpu_e500->gtlb_params[tlbsel].entries;
+		     esel++)
 			kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel);
 	} else {
 		ea &= 0xfffff000;
@@ -752,18 +853,17 @@
 {
 	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
 	int tlbsel, esel;
-	struct tlbe *gtlbe;
+	struct kvm_book3e_206_tlb_entry *gtlbe;
 
-	tlbsel = get_tlb_tlbsel(vcpu_e500);
-	esel = get_tlb_esel(vcpu_e500, tlbsel);
+	tlbsel = get_tlb_tlbsel(vcpu);
+	esel = get_tlb_esel(vcpu, tlbsel);
 
-	gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel];
-	vcpu_e500->mas0 &= ~MAS0_NV(~0);
-	vcpu_e500->mas0 |= MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]);
-	vcpu_e500->mas1 = gtlbe->mas1;
-	vcpu_e500->mas2 = gtlbe->mas2;
-	vcpu_e500->mas3 = gtlbe->mas3;
-	vcpu_e500->mas7 = gtlbe->mas7;
+	gtlbe = get_entry(vcpu_e500, tlbsel, esel);
+	vcpu->arch.shared->mas0 &= ~MAS0_NV(~0);
+	vcpu->arch.shared->mas0 |= MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]);
+	vcpu->arch.shared->mas1 = gtlbe->mas1;
+	vcpu->arch.shared->mas2 = gtlbe->mas2;
+	vcpu->arch.shared->mas7_3 = gtlbe->mas7_3;
 
 	return EMULATE_DONE;
 }
@@ -771,10 +871,10 @@
 int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb)
 {
 	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
-	int as = !!get_cur_sas(vcpu_e500);
-	unsigned int pid = get_cur_spid(vcpu_e500);
+	int as = !!get_cur_sas(vcpu);
+	unsigned int pid = get_cur_spid(vcpu);
 	int esel, tlbsel;
-	struct tlbe *gtlbe = NULL;
+	struct kvm_book3e_206_tlb_entry *gtlbe = NULL;
 	gva_t ea;
 
 	ea = kvmppc_get_gpr(vcpu, rb);
@@ -782,70 +882,90 @@
 	for (tlbsel = 0; tlbsel < 2; tlbsel++) {
 		esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel, pid, as);
 		if (esel >= 0) {
-			gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel];
+			gtlbe = get_entry(vcpu_e500, tlbsel, esel);
 			break;
 		}
 	}
 
 	if (gtlbe) {
-		vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(esel)
+		esel &= vcpu_e500->gtlb_params[tlbsel].ways - 1;
+
+		vcpu->arch.shared->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(esel)
 			| MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]);
-		vcpu_e500->mas1 = gtlbe->mas1;
-		vcpu_e500->mas2 = gtlbe->mas2;
-		vcpu_e500->mas3 = gtlbe->mas3;
-		vcpu_e500->mas7 = gtlbe->mas7;
+		vcpu->arch.shared->mas1 = gtlbe->mas1;
+		vcpu->arch.shared->mas2 = gtlbe->mas2;
+		vcpu->arch.shared->mas7_3 = gtlbe->mas7_3;
 	} else {
 		int victim;
 
 		/* since we only have two TLBs, only lower bit is used. */
-		tlbsel = vcpu_e500->mas4 >> 28 & 0x1;
-		victim = (tlbsel == 0) ? tlb0_get_next_victim(vcpu_e500) : 0;
+		tlbsel = vcpu->arch.shared->mas4 >> 28 & 0x1;
+		victim = (tlbsel == 0) ? gtlb0_get_next_victim(vcpu_e500) : 0;
 
-		vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim)
+		vcpu->arch.shared->mas0 = MAS0_TLBSEL(tlbsel)
+			| MAS0_ESEL(victim)
 			| MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]);
-		vcpu_e500->mas1 = (vcpu_e500->mas6 & MAS6_SPID0)
-			| (vcpu_e500->mas6 & (MAS6_SAS ? MAS1_TS : 0))
-			| (vcpu_e500->mas4 & MAS4_TSIZED(~0));
-		vcpu_e500->mas2 &= MAS2_EPN;
-		vcpu_e500->mas2 |= vcpu_e500->mas4 & MAS2_ATTRIB_MASK;
-		vcpu_e500->mas3 &= MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3;
-		vcpu_e500->mas7 = 0;
+		vcpu->arch.shared->mas1 =
+			  (vcpu->arch.shared->mas6 & MAS6_SPID0)
+			| (vcpu->arch.shared->mas6 & (MAS6_SAS ? MAS1_TS : 0))
+			| (vcpu->arch.shared->mas4 & MAS4_TSIZED(~0));
+		vcpu->arch.shared->mas2 &= MAS2_EPN;
+		vcpu->arch.shared->mas2 |= vcpu->arch.shared->mas4 &
+					   MAS2_ATTRIB_MASK;
+		vcpu->arch.shared->mas7_3 &= MAS3_U0 | MAS3_U1 |
+					     MAS3_U2 | MAS3_U3;
 	}
 
 	kvmppc_set_exit_type(vcpu, EMULATED_TLBSX_EXITS);
 	return EMULATE_DONE;
 }
 
+/* sesel is for tlb1 only */
+static void write_stlbe(struct kvmppc_vcpu_e500 *vcpu_e500,
+			struct kvm_book3e_206_tlb_entry *gtlbe,
+			struct kvm_book3e_206_tlb_entry *stlbe,
+			int stlbsel, int sesel)
+{
+	int stid;
+
+	preempt_disable();
+	stid = kvmppc_e500_get_sid(vcpu_e500, get_tlb_ts(gtlbe),
+				   get_tlb_tid(gtlbe),
+				   get_cur_pr(&vcpu_e500->vcpu), 0);
+
+	stlbe->mas1 |= MAS1_TID(stid);
+	write_host_tlbe(vcpu_e500, stlbsel, sesel, stlbe);
+	preempt_enable();
+}
+
 int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu)
 {
 	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
-	struct tlbe *gtlbe;
+	struct kvm_book3e_206_tlb_entry *gtlbe;
 	int tlbsel, esel;
 
-	tlbsel = get_tlb_tlbsel(vcpu_e500);
-	esel = get_tlb_esel(vcpu_e500, tlbsel);
+	tlbsel = get_tlb_tlbsel(vcpu);
+	esel = get_tlb_esel(vcpu, tlbsel);
 
-	gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel];
+	gtlbe = get_entry(vcpu_e500, tlbsel, esel);
 
 	if (get_tlb_v(gtlbe))
-		kvmppc_e500_stlbe_invalidate(vcpu_e500, tlbsel, esel);
+		inval_gtlbe_on_host(vcpu_e500, tlbsel, esel);
 
-	gtlbe->mas1 = vcpu_e500->mas1;
-	gtlbe->mas2 = vcpu_e500->mas2;
-	gtlbe->mas3 = vcpu_e500->mas3;
-	gtlbe->mas7 = vcpu_e500->mas7;
+	gtlbe->mas1 = vcpu->arch.shared->mas1;
+	gtlbe->mas2 = vcpu->arch.shared->mas2;
+	gtlbe->mas7_3 = vcpu->arch.shared->mas7_3;
 
-	trace_kvm_gtlb_write(vcpu_e500->mas0, gtlbe->mas1, gtlbe->mas2,
-			     gtlbe->mas3, gtlbe->mas7);
+	trace_kvm_booke206_gtlb_write(vcpu->arch.shared->mas0, gtlbe->mas1,
+	                              gtlbe->mas2, gtlbe->mas7_3);
 
 	/* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */
 	if (tlbe_is_host_safe(vcpu, gtlbe)) {
-		struct tlbe stlbe;
+		struct kvm_book3e_206_tlb_entry stlbe;
 		int stlbsel, sesel;
 		u64 eaddr;
 		u64 raddr;
 
-		preempt_disable();
 		switch (tlbsel) {
 		case 0:
 			/* TLB0 */
@@ -853,7 +973,8 @@
 			gtlbe->mas1 |= MAS1_TSIZE(BOOK3E_PAGESZ_4K);
 
 			stlbsel = 0;
-			sesel = kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe);
+			kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe);
+			sesel = 0; /* unused */
 
 			break;
 
@@ -874,8 +995,8 @@
 		default:
 			BUG();
 		}
-		write_host_tlbe(vcpu_e500, stlbsel, sesel, &stlbe);
-		preempt_enable();
+
+		write_stlbe(vcpu_e500, gtlbe, &stlbe, stlbsel, sesel);
 	}
 
 	kvmppc_set_exit_type(vcpu, EMULATED_TLBWE_EXITS);
@@ -914,9 +1035,11 @@
 			gva_t eaddr)
 {
 	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
-	struct tlbe *gtlbe =
-		&vcpu_e500->gtlb_arch[tlbsel_of(index)][esel_of(index)];
-	u64 pgmask = get_tlb_bytes(gtlbe) - 1;
+	struct kvm_book3e_206_tlb_entry *gtlbe;
+	u64 pgmask;
+
+	gtlbe = get_entry(vcpu_e500, tlbsel_of(index), esel_of(index));
+	pgmask = get_tlb_bytes(gtlbe) - 1;
 
 	return get_tlb_raddr(gtlbe) | (eaddr & pgmask);
 }
@@ -930,22 +1053,21 @@
 {
 	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
 	struct tlbe_priv *priv;
-	struct tlbe *gtlbe, stlbe;
+	struct kvm_book3e_206_tlb_entry *gtlbe, stlbe;
 	int tlbsel = tlbsel_of(index);
 	int esel = esel_of(index);
 	int stlbsel, sesel;
 
-	gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel];
+	gtlbe = get_entry(vcpu_e500, tlbsel, esel);
 
-	preempt_disable();
 	switch (tlbsel) {
 	case 0:
 		stlbsel = 0;
-		sesel = esel;
-		priv = &vcpu_e500->gtlb_priv[stlbsel][sesel];
+		sesel = 0; /* unused */
+		priv = &vcpu_e500->gtlb_priv[tlbsel][esel];
 
 		kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, BOOK3E_PAGESZ_4K,
-					priv, eaddr, &stlbe);
+					&priv->ref, eaddr, &stlbe);
 		break;
 
 	case 1: {
@@ -962,8 +1084,7 @@
 		break;
 	}
 
-	write_host_tlbe(vcpu_e500, stlbsel, sesel, &stlbe);
-	preempt_enable();
+	write_stlbe(vcpu_e500, gtlbe, &stlbe, stlbsel, sesel);
 }
 
 int kvmppc_e500_tlb_search(struct kvm_vcpu *vcpu,
@@ -993,85 +1114,279 @@
 
 void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
-	struct tlbe *tlbe;
+	struct kvm_book3e_206_tlb_entry *tlbe;
 
 	/* Insert large initial mapping for guest. */
-	tlbe = &vcpu_e500->gtlb_arch[1][0];
+	tlbe = get_entry(vcpu_e500, 1, 0);
 	tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOK3E_PAGESZ_256M);
 	tlbe->mas2 = 0;
-	tlbe->mas3 = E500_TLB_SUPER_PERM_MASK;
-	tlbe->mas7 = 0;
+	tlbe->mas7_3 = E500_TLB_SUPER_PERM_MASK;
 
 	/* 4K map for serial output. Used by kernel wrapper. */
-	tlbe = &vcpu_e500->gtlb_arch[1][1];
+	tlbe = get_entry(vcpu_e500, 1, 1);
 	tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOK3E_PAGESZ_4K);
 	tlbe->mas2 = (0xe0004500 & 0xFFFFF000) | MAS2_I | MAS2_G;
-	tlbe->mas3 = (0xe0004500 & 0xFFFFF000) | E500_TLB_SUPER_PERM_MASK;
-	tlbe->mas7 = 0;
+	tlbe->mas7_3 = (0xe0004500 & 0xFFFFF000) | E500_TLB_SUPER_PERM_MASK;
+}
+
+static void free_gtlb(struct kvmppc_vcpu_e500 *vcpu_e500)
+{
+	int i;
+
+	clear_tlb_refs(vcpu_e500);
+	kfree(vcpu_e500->gtlb_priv[0]);
+	kfree(vcpu_e500->gtlb_priv[1]);
+
+	if (vcpu_e500->shared_tlb_pages) {
+		vfree((void *)(round_down((uintptr_t)vcpu_e500->gtlb_arch,
+					  PAGE_SIZE)));
+
+		for (i = 0; i < vcpu_e500->num_shared_tlb_pages; i++) {
+			set_page_dirty_lock(vcpu_e500->shared_tlb_pages[i]);
+			put_page(vcpu_e500->shared_tlb_pages[i]);
+		}
+
+		vcpu_e500->num_shared_tlb_pages = 0;
+		vcpu_e500->shared_tlb_pages = NULL;
+	} else {
+		kfree(vcpu_e500->gtlb_arch);
+	}
+
+	vcpu_e500->gtlb_arch = NULL;
+}
+
+int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu,
+			      struct kvm_config_tlb *cfg)
+{
+	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
+	struct kvm_book3e_206_tlb_params params;
+	char *virt;
+	struct page **pages;
+	struct tlbe_priv *privs[2] = {};
+	size_t array_len;
+	u32 sets;
+	int num_pages, ret, i;
+
+	if (cfg->mmu_type != KVM_MMU_FSL_BOOKE_NOHV)
+		return -EINVAL;
+
+	if (copy_from_user(&params, (void __user *)(uintptr_t)cfg->params,
+			   sizeof(params)))
+		return -EFAULT;
+
+	if (params.tlb_sizes[1] > 64)
+		return -EINVAL;
+	if (params.tlb_ways[1] != params.tlb_sizes[1])
+		return -EINVAL;
+	if (params.tlb_sizes[2] != 0 || params.tlb_sizes[3] != 0)
+		return -EINVAL;
+	if (params.tlb_ways[2] != 0 || params.tlb_ways[3] != 0)
+		return -EINVAL;
+
+	if (!is_power_of_2(params.tlb_ways[0]))
+		return -EINVAL;
+
+	sets = params.tlb_sizes[0] >> ilog2(params.tlb_ways[0]);
+	if (!is_power_of_2(sets))
+		return -EINVAL;
+
+	array_len = params.tlb_sizes[0] + params.tlb_sizes[1];
+	array_len *= sizeof(struct kvm_book3e_206_tlb_entry);
+
+	if (cfg->array_len < array_len)
+		return -EINVAL;
+
+	num_pages = DIV_ROUND_UP(cfg->array + array_len - 1, PAGE_SIZE) -
+		    cfg->array / PAGE_SIZE;
+	pages = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL);
+	if (!pages)
+		return -ENOMEM;
+
+	ret = get_user_pages_fast(cfg->array, num_pages, 1, pages);
+	if (ret < 0)
+		goto err_pages;
+
+	if (ret != num_pages) {
+		num_pages = ret;
+		ret = -EFAULT;
+		goto err_put_page;
+	}
+
+	virt = vmap(pages, num_pages, VM_MAP, PAGE_KERNEL);
+	if (!virt)
+		goto err_put_page;
+
+	privs[0] = kzalloc(sizeof(struct tlbe_priv) * params.tlb_sizes[0],
+			   GFP_KERNEL);
+	privs[1] = kzalloc(sizeof(struct tlbe_priv) * params.tlb_sizes[1],
+			   GFP_KERNEL);
+
+	if (!privs[0] || !privs[1])
+		goto err_put_page;
+
+	free_gtlb(vcpu_e500);
+
+	vcpu_e500->gtlb_priv[0] = privs[0];
+	vcpu_e500->gtlb_priv[1] = privs[1];
+
+	vcpu_e500->gtlb_arch = (struct kvm_book3e_206_tlb_entry *)
+		(virt + (cfg->array & (PAGE_SIZE - 1)));
+
+	vcpu_e500->gtlb_params[0].entries = params.tlb_sizes[0];
+	vcpu_e500->gtlb_params[1].entries = params.tlb_sizes[1];
+
+	vcpu_e500->gtlb_offset[0] = 0;
+	vcpu_e500->gtlb_offset[1] = params.tlb_sizes[0];
+
+	vcpu_e500->tlb0cfg &= ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC);
+	if (params.tlb_sizes[0] <= 2048)
+		vcpu_e500->tlb0cfg |= params.tlb_sizes[0];
+	vcpu_e500->tlb0cfg |= params.tlb_ways[0] << TLBnCFG_ASSOC_SHIFT;
+
+	vcpu_e500->tlb1cfg &= ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC);
+	vcpu_e500->tlb1cfg |= params.tlb_sizes[1];
+	vcpu_e500->tlb1cfg |= params.tlb_ways[1] << TLBnCFG_ASSOC_SHIFT;
+
+	vcpu_e500->shared_tlb_pages = pages;
+	vcpu_e500->num_shared_tlb_pages = num_pages;
+
+	vcpu_e500->gtlb_params[0].ways = params.tlb_ways[0];
+	vcpu_e500->gtlb_params[0].sets = sets;
+
+	vcpu_e500->gtlb_params[1].ways = params.tlb_sizes[1];
+	vcpu_e500->gtlb_params[1].sets = 1;
+
+	return 0;
+
+err_put_page:
+	kfree(privs[0]);
+	kfree(privs[1]);
+
+	for (i = 0; i < num_pages; i++)
+		put_page(pages[i]);
+
+err_pages:
+	kfree(pages);
+	return ret;
+}
+
+int kvm_vcpu_ioctl_dirty_tlb(struct kvm_vcpu *vcpu,
+			     struct kvm_dirty_tlb *dirty)
+{
+	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
+
+	clear_tlb_refs(vcpu_e500);
+	return 0;
 }
 
 int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
-	tlb1_entry_num = mfspr(SPRN_TLB1CFG) & 0xFFF;
+	int entry_size = sizeof(struct kvm_book3e_206_tlb_entry);
+	int entries = KVM_E500_TLB0_SIZE + KVM_E500_TLB1_SIZE;
 
-	vcpu_e500->gtlb_size[0] = KVM_E500_TLB0_SIZE;
-	vcpu_e500->gtlb_arch[0] =
-		kzalloc(sizeof(struct tlbe) * KVM_E500_TLB0_SIZE, GFP_KERNEL);
-	if (vcpu_e500->gtlb_arch[0] == NULL)
-		goto err_out;
+	host_tlb_params[0].entries = mfspr(SPRN_TLB0CFG) & TLBnCFG_N_ENTRY;
+	host_tlb_params[1].entries = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY;
 
-	vcpu_e500->gtlb_size[1] = KVM_E500_TLB1_SIZE;
-	vcpu_e500->gtlb_arch[1] =
-		kzalloc(sizeof(struct tlbe) * KVM_E500_TLB1_SIZE, GFP_KERNEL);
-	if (vcpu_e500->gtlb_arch[1] == NULL)
-		goto err_out_guest0;
+	/*
+	 * This should never happen on real e500 hardware, but is
+	 * architecturally possible -- e.g. in some weird nested
+	 * virtualization case.
+	 */
+	if (host_tlb_params[0].entries == 0 ||
+	    host_tlb_params[1].entries == 0) {
+		pr_err("%s: need to know host tlb size\n", __func__);
+		return -ENODEV;
+	}
 
-	vcpu_e500->gtlb_priv[0] = (struct tlbe_priv *)
-		kzalloc(sizeof(struct tlbe_priv) * KVM_E500_TLB0_SIZE, GFP_KERNEL);
-	if (vcpu_e500->gtlb_priv[0] == NULL)
-		goto err_out_guest1;
-	vcpu_e500->gtlb_priv[1] = (struct tlbe_priv *)
-		kzalloc(sizeof(struct tlbe_priv) * KVM_E500_TLB1_SIZE, GFP_KERNEL);
+	host_tlb_params[0].ways = (mfspr(SPRN_TLB0CFG) & TLBnCFG_ASSOC) >>
+				  TLBnCFG_ASSOC_SHIFT;
+	host_tlb_params[1].ways = host_tlb_params[1].entries;
 
-	if (vcpu_e500->gtlb_priv[1] == NULL)
-		goto err_out_priv0;
+	if (!is_power_of_2(host_tlb_params[0].entries) ||
+	    !is_power_of_2(host_tlb_params[0].ways) ||
+	    host_tlb_params[0].entries < host_tlb_params[0].ways ||
+	    host_tlb_params[0].ways == 0) {
+		pr_err("%s: bad tlb0 host config: %u entries %u ways\n",
+		       __func__, host_tlb_params[0].entries,
+		       host_tlb_params[0].ways);
+		return -ENODEV;
+	}
+
+	host_tlb_params[0].sets =
+		host_tlb_params[0].entries / host_tlb_params[0].ways;
+	host_tlb_params[1].sets = 1;
+
+	vcpu_e500->gtlb_params[0].entries = KVM_E500_TLB0_SIZE;
+	vcpu_e500->gtlb_params[1].entries = KVM_E500_TLB1_SIZE;
+
+	vcpu_e500->gtlb_params[0].ways = KVM_E500_TLB0_WAY_NUM;
+	vcpu_e500->gtlb_params[0].sets =
+		KVM_E500_TLB0_SIZE / KVM_E500_TLB0_WAY_NUM;
+
+	vcpu_e500->gtlb_params[1].ways = KVM_E500_TLB1_SIZE;
+	vcpu_e500->gtlb_params[1].sets = 1;
+
+	vcpu_e500->gtlb_arch = kmalloc(entries * entry_size, GFP_KERNEL);
+	if (!vcpu_e500->gtlb_arch)
+		return -ENOMEM;
+
+	vcpu_e500->gtlb_offset[0] = 0;
+	vcpu_e500->gtlb_offset[1] = KVM_E500_TLB0_SIZE;
+
+	vcpu_e500->tlb_refs[0] =
+		kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[0].entries,
+			GFP_KERNEL);
+	if (!vcpu_e500->tlb_refs[0])
+		goto err;
+
+	vcpu_e500->tlb_refs[1] =
+		kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[1].entries,
+			GFP_KERNEL);
+	if (!vcpu_e500->tlb_refs[1])
+		goto err;
+
+	vcpu_e500->gtlb_priv[0] = kzalloc(sizeof(struct tlbe_ref) *
+					  vcpu_e500->gtlb_params[0].entries,
+					  GFP_KERNEL);
+	if (!vcpu_e500->gtlb_priv[0])
+		goto err;
+
+	vcpu_e500->gtlb_priv[1] = kzalloc(sizeof(struct tlbe_ref) *
+					  vcpu_e500->gtlb_params[1].entries,
+					  GFP_KERNEL);
+	if (!vcpu_e500->gtlb_priv[1])
+		goto err;
 
 	if (kvmppc_e500_id_table_alloc(vcpu_e500) == NULL)
-		goto err_out_priv1;
+		goto err;
 
 	/* Init TLB configuration register */
-	vcpu_e500->tlb0cfg = mfspr(SPRN_TLB0CFG) & ~0xfffUL;
-	vcpu_e500->tlb0cfg |= vcpu_e500->gtlb_size[0];
-	vcpu_e500->tlb1cfg = mfspr(SPRN_TLB1CFG) & ~0xfffUL;
-	vcpu_e500->tlb1cfg |= vcpu_e500->gtlb_size[1];
+	vcpu_e500->tlb0cfg = mfspr(SPRN_TLB0CFG) &
+			     ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC);
+	vcpu_e500->tlb0cfg |= vcpu_e500->gtlb_params[0].entries;
+	vcpu_e500->tlb0cfg |=
+		vcpu_e500->gtlb_params[0].ways << TLBnCFG_ASSOC_SHIFT;
+
+	vcpu_e500->tlb1cfg = mfspr(SPRN_TLB1CFG) &
+			     ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC);
+	vcpu_e500->tlb0cfg |= vcpu_e500->gtlb_params[1].entries;
+	vcpu_e500->tlb0cfg |=
+		vcpu_e500->gtlb_params[1].ways << TLBnCFG_ASSOC_SHIFT;
 
 	return 0;
 
-err_out_priv1:
-	kfree(vcpu_e500->gtlb_priv[1]);
-err_out_priv0:
-	kfree(vcpu_e500->gtlb_priv[0]);
-err_out_guest1:
-	kfree(vcpu_e500->gtlb_arch[1]);
-err_out_guest0:
-	kfree(vcpu_e500->gtlb_arch[0]);
-err_out:
+err:
+	free_gtlb(vcpu_e500);
+	kfree(vcpu_e500->tlb_refs[0]);
+	kfree(vcpu_e500->tlb_refs[1]);
 	return -1;
 }
 
 void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
-	int stlbsel, i;
-
-	/* release all privs */
-	for (stlbsel = 0; stlbsel < 2; stlbsel++)
-		for (i = 0; i < vcpu_e500->gtlb_size[stlbsel]; i++) {
-			struct tlbe_priv *priv =
-				&vcpu_e500->gtlb_priv[stlbsel][i];
-			kvmppc_e500_priv_release(priv);
-		}
-
+	free_gtlb(vcpu_e500);
 	kvmppc_e500_id_table_free(vcpu_e500);
-	kfree(vcpu_e500->gtlb_arch[1]);
-	kfree(vcpu_e500->gtlb_arch[0]);
+
+	kfree(vcpu_e500->tlb_refs[0]);
+	kfree(vcpu_e500->tlb_refs[1]);
 }
diff --git a/arch/powerpc/kvm/e500_tlb.h b/arch/powerpc/kvm/e500_tlb.h
index 59b88e9..5c6d2d7 100644
--- a/arch/powerpc/kvm/e500_tlb.h
+++ b/arch/powerpc/kvm/e500_tlb.h
@@ -20,13 +20,9 @@
 #include <asm/tlb.h>
 #include <asm/kvm_e500.h>
 
-#define KVM_E500_TLB0_WAY_SIZE_BIT	7	/* Fixed */
-#define KVM_E500_TLB0_WAY_SIZE		(1UL << KVM_E500_TLB0_WAY_SIZE_BIT)
-#define KVM_E500_TLB0_WAY_SIZE_MASK	(KVM_E500_TLB0_WAY_SIZE - 1)
-
-#define KVM_E500_TLB0_WAY_NUM_BIT	1	/* No greater than 7 */
-#define KVM_E500_TLB0_WAY_NUM		(1UL << KVM_E500_TLB0_WAY_NUM_BIT)
-#define KVM_E500_TLB0_WAY_NUM_MASK	(KVM_E500_TLB0_WAY_NUM - 1)
+/* This geometry is the legacy default -- can be overridden by userspace */
+#define KVM_E500_TLB0_WAY_SIZE		128
+#define KVM_E500_TLB0_WAY_NUM		2
 
 #define KVM_E500_TLB0_SIZE  (KVM_E500_TLB0_WAY_SIZE * KVM_E500_TLB0_WAY_NUM)
 #define KVM_E500_TLB1_SIZE  16
@@ -58,50 +54,54 @@
 extern void kvmppc_e500_recalc_shadow_pid(struct kvmppc_vcpu_e500 *);
 
 /* TLB helper functions */
-static inline unsigned int get_tlb_size(const struct tlbe *tlbe)
+static inline unsigned int
+get_tlb_size(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
 	return (tlbe->mas1 >> 7) & 0x1f;
 }
 
-static inline gva_t get_tlb_eaddr(const struct tlbe *tlbe)
+static inline gva_t get_tlb_eaddr(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
 	return tlbe->mas2 & 0xfffff000;
 }
 
-static inline u64 get_tlb_bytes(const struct tlbe *tlbe)
+static inline u64 get_tlb_bytes(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
 	unsigned int pgsize = get_tlb_size(tlbe);
 	return 1ULL << 10 << pgsize;
 }
 
-static inline gva_t get_tlb_end(const struct tlbe *tlbe)
+static inline gva_t get_tlb_end(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
 	u64 bytes = get_tlb_bytes(tlbe);
 	return get_tlb_eaddr(tlbe) + bytes - 1;
 }
 
-static inline u64 get_tlb_raddr(const struct tlbe *tlbe)
+static inline u64 get_tlb_raddr(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
-	u64 rpn = tlbe->mas7;
-	return (rpn << 32) | (tlbe->mas3 & 0xfffff000);
+	return tlbe->mas7_3 & ~0xfffULL;
 }
 
-static inline unsigned int get_tlb_tid(const struct tlbe *tlbe)
+static inline unsigned int
+get_tlb_tid(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
 	return (tlbe->mas1 >> 16) & 0xff;
 }
 
-static inline unsigned int get_tlb_ts(const struct tlbe *tlbe)
+static inline unsigned int
+get_tlb_ts(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
 	return (tlbe->mas1 >> 12) & 0x1;
 }
 
-static inline unsigned int get_tlb_v(const struct tlbe *tlbe)
+static inline unsigned int
+get_tlb_v(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
 	return (tlbe->mas1 >> 31) & 0x1;
 }
 
-static inline unsigned int get_tlb_iprot(const struct tlbe *tlbe)
+static inline unsigned int
+get_tlb_iprot(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
 	return (tlbe->mas1 >> 30) & 0x1;
 }
@@ -121,59 +121,37 @@
 	return !!(vcpu->arch.shared->msr & MSR_PR);
 }
 
-static inline unsigned int get_cur_spid(
-		const struct kvmppc_vcpu_e500 *vcpu_e500)
+static inline unsigned int get_cur_spid(const struct kvm_vcpu *vcpu)
 {
-	return (vcpu_e500->mas6 >> 16) & 0xff;
+	return (vcpu->arch.shared->mas6 >> 16) & 0xff;
 }
 
-static inline unsigned int get_cur_sas(
-		const struct kvmppc_vcpu_e500 *vcpu_e500)
+static inline unsigned int get_cur_sas(const struct kvm_vcpu *vcpu)
 {
-	return vcpu_e500->mas6 & 0x1;
+	return vcpu->arch.shared->mas6 & 0x1;
 }
 
-static inline unsigned int get_tlb_tlbsel(
-		const struct kvmppc_vcpu_e500 *vcpu_e500)
+static inline unsigned int get_tlb_tlbsel(const struct kvm_vcpu *vcpu)
 {
 	/*
 	 * Manual says that tlbsel has 2 bits wide.
 	 * Since we only have two TLBs, only lower bit is used.
 	 */
-	return (vcpu_e500->mas0 >> 28) & 0x1;
+	return (vcpu->arch.shared->mas0 >> 28) & 0x1;
 }
 
-static inline unsigned int get_tlb_nv_bit(
-		const struct kvmppc_vcpu_e500 *vcpu_e500)
+static inline unsigned int get_tlb_nv_bit(const struct kvm_vcpu *vcpu)
 {
-	return vcpu_e500->mas0 & 0xfff;
+	return vcpu->arch.shared->mas0 & 0xfff;
 }
 
-static inline unsigned int get_tlb_esel_bit(
-		const struct kvmppc_vcpu_e500 *vcpu_e500)
+static inline unsigned int get_tlb_esel_bit(const struct kvm_vcpu *vcpu)
 {
-	return (vcpu_e500->mas0 >> 16) & 0xfff;
-}
-
-static inline unsigned int get_tlb_esel(
-		const struct kvmppc_vcpu_e500 *vcpu_e500,
-		int tlbsel)
-{
-	unsigned int esel = get_tlb_esel_bit(vcpu_e500);
-
-	if (tlbsel == 0) {
-		esel &= KVM_E500_TLB0_WAY_NUM_MASK;
-		esel |= ((vcpu_e500->mas2 >> 12) & KVM_E500_TLB0_WAY_SIZE_MASK)
-				<< KVM_E500_TLB0_WAY_NUM_BIT;
-	} else {
-		esel &= KVM_E500_TLB1_SIZE - 1;
-	}
-
-	return esel;
+	return (vcpu->arch.shared->mas0 >> 16) & 0xfff;
 }
 
 static inline int tlbe_is_host_safe(const struct kvm_vcpu *vcpu,
-			const struct tlbe *tlbe)
+			const struct kvm_book3e_206_tlb_entry *tlbe)
 {
 	gpa_t gpa;
 
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index 141dce3..968f401 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -13,6 +13,7 @@
  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  *
  * Copyright IBM Corp. 2007
+ * Copyright 2011 Freescale Semiconductor, Inc.
  *
  * Authors: Hollis Blanchard <hollisb@us.ibm.com>
  */
@@ -69,54 +70,55 @@
 #define OP_STH  44
 #define OP_STHU 45
 
-#ifdef CONFIG_PPC_BOOK3S
-static int kvmppc_dec_enabled(struct kvm_vcpu *vcpu)
-{
-	return 1;
-}
-#else
-static int kvmppc_dec_enabled(struct kvm_vcpu *vcpu)
-{
-	return vcpu->arch.tcr & TCR_DIE;
-}
-#endif
-
 void kvmppc_emulate_dec(struct kvm_vcpu *vcpu)
 {
 	unsigned long dec_nsec;
+	unsigned long long dec_time;
 
 	pr_debug("mtDEC: %x\n", vcpu->arch.dec);
+	hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
+
 #ifdef CONFIG_PPC_BOOK3S
 	/* mtdec lowers the interrupt line when positive. */
 	kvmppc_core_dequeue_dec(vcpu);
 
 	/* POWER4+ triggers a dec interrupt if the value is < 0 */
 	if (vcpu->arch.dec & 0x80000000) {
-		hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
 		kvmppc_core_queue_dec(vcpu);
 		return;
 	}
 #endif
-	if (kvmppc_dec_enabled(vcpu)) {
-		/* The decrementer ticks at the same rate as the timebase, so
-		 * that's how we convert the guest DEC value to the number of
-		 * host ticks. */
 
-		hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
-		dec_nsec = vcpu->arch.dec;
-		dec_nsec *= 1000;
-		dec_nsec /= tb_ticks_per_usec;
-		hrtimer_start(&vcpu->arch.dec_timer, ktime_set(0, dec_nsec),
-			      HRTIMER_MODE_REL);
-		vcpu->arch.dec_jiffies = get_tb();
-	} else {
-		hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
-	}
+#ifdef CONFIG_BOOKE
+	/* On BOOKE, DEC = 0 is as good as decrementer not enabled */
+	if (vcpu->arch.dec == 0)
+		return;
+#endif
+
+	/*
+	 * The decrementer ticks at the same rate as the timebase, so
+	 * that's how we convert the guest DEC value to the number of
+	 * host ticks.
+	 */
+
+	dec_time = vcpu->arch.dec;
+	dec_time *= 1000;
+	do_div(dec_time, tb_ticks_per_usec);
+	dec_nsec = do_div(dec_time, NSEC_PER_SEC);
+	hrtimer_start(&vcpu->arch.dec_timer,
+		ktime_set(dec_time, dec_nsec), HRTIMER_MODE_REL);
+	vcpu->arch.dec_jiffies = get_tb();
 }
 
 u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb)
 {
 	u64 jd = tb - vcpu->arch.dec_jiffies;
+
+#ifdef CONFIG_BOOKE
+	if (vcpu->arch.dec < jd)
+		return 0;
+#endif
+
 	return vcpu->arch.dec - jd;
 }
 
@@ -159,7 +161,8 @@
 	case OP_TRAP_64:
 		kvmppc_core_queue_program(vcpu, SRR1_PROGTRAP);
 #else
-		kvmppc_core_queue_program(vcpu, vcpu->arch.esr | ESR_PTR);
+		kvmppc_core_queue_program(vcpu,
+					  vcpu->arch.shared->esr | ESR_PTR);
 #endif
 		advance = 0;
 		break;
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 607fbdf..00d7e34 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -39,7 +39,8 @@
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
 	return !(v->arch.shared->msr & MSR_WE) ||
-	       !!(v->arch.pending_exceptions);
+	       !!(v->arch.pending_exceptions) ||
+	       v->requests;
 }
 
 int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
@@ -66,7 +67,7 @@
 		vcpu->arch.magic_page_pa = param1;
 		vcpu->arch.magic_page_ea = param2;
 
-		r2 = KVM_MAGIC_FEAT_SR;
+		r2 = KVM_MAGIC_FEAT_SR | KVM_MAGIC_FEAT_MAS0_TO_SPRG7;
 
 		r = HC_EV_SUCCESS;
 		break;
@@ -171,8 +172,11 @@
 	*(int *)rtn = kvmppc_core_check_processor_compat();
 }
 
-int kvm_arch_init_vm(struct kvm *kvm)
+int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
+	if (type)
+		return -EINVAL;
+
 	return kvmppc_core_init_vm(kvm);
 }
 
@@ -208,17 +212,22 @@
 	case KVM_CAP_PPC_BOOKE_SREGS:
 #else
 	case KVM_CAP_PPC_SEGSTATE:
+	case KVM_CAP_PPC_HIOR:
 	case KVM_CAP_PPC_PAPR:
 #endif
 	case KVM_CAP_PPC_UNSET_IRQ:
 	case KVM_CAP_PPC_IRQ_LEVEL:
 	case KVM_CAP_ENABLE_CAP:
+	case KVM_CAP_ONE_REG:
 		r = 1;
 		break;
 #ifndef CONFIG_KVM_BOOK3S_64_HV
 	case KVM_CAP_PPC_PAIRED_SINGLES:
 	case KVM_CAP_PPC_OSI:
 	case KVM_CAP_PPC_GET_PVINFO:
+#ifdef CONFIG_KVM_E500
+	case KVM_CAP_SW_TLB:
+#endif
 		r = 1;
 		break;
 	case KVM_CAP_COALESCED_MMIO:
@@ -238,7 +247,26 @@
 		if (cpu_has_feature(CPU_FTR_ARCH_201))
 			r = 2;
 		break;
+	case KVM_CAP_SYNC_MMU:
+		r = cpu_has_feature(CPU_FTR_ARCH_206) ? 1 : 0;
+		break;
 #endif
+	case KVM_CAP_NR_VCPUS:
+		/*
+		 * Recommending a number of CPUs is somewhat arbitrary; we
+		 * return the number of present CPUs for -HV (since a host
+		 * will have secondary threads "offline"), and for other KVM
+		 * implementations just count online CPUs.
+		 */
+#ifdef CONFIG_KVM_BOOK3S_64_HV
+		r = num_present_cpus();
+#else
+		r = num_online_cpus();
+#endif
+		break;
+	case KVM_CAP_MAX_VCPUS:
+		r = KVM_MAX_VCPUS;
+		break;
 	default:
 		r = 0;
 		break;
@@ -253,6 +281,16 @@
 	return -EINVAL;
 }
 
+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)
+{
+	return 0;
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
                                    struct kvm_memory_slot *memslot,
                                    struct kvm_memory_slot old,
@@ -279,9 +317,10 @@
 {
 	struct kvm_vcpu *vcpu;
 	vcpu = kvmppc_core_vcpu_create(kvm, id);
-	vcpu->arch.wqp = &vcpu->wq;
-	if (!IS_ERR(vcpu))
+	if (!IS_ERR(vcpu)) {
+		vcpu->arch.wqp = &vcpu->wq;
 		kvmppc_create_vcpu_debugfs(vcpu, id);
+	}
 	return vcpu;
 }
 
@@ -305,18 +344,6 @@
 	return kvmppc_core_pending_dec(vcpu);
 }
 
-static void kvmppc_decrementer_func(unsigned long data)
-{
-	struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
-
-	kvmppc_core_queue_dec(vcpu);
-
-	if (waitqueue_active(vcpu->arch.wqp)) {
-		wake_up_interruptible(vcpu->arch.wqp);
-		vcpu->stat.halt_wakeup++;
-	}
-}
-
 /*
  * low level hrtimer wake routine. Because this runs in hardirq context
  * we schedule a tasklet to do the real work.
@@ -431,20 +458,20 @@
 
 	kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr);
 
-	switch (vcpu->arch.io_gpr & KVM_REG_EXT_MASK) {
-	case KVM_REG_GPR:
+	switch (vcpu->arch.io_gpr & KVM_MMIO_REG_EXT_MASK) {
+	case KVM_MMIO_REG_GPR:
 		kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr);
 		break;
-	case KVM_REG_FPR:
-		vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr;
+	case KVM_MMIO_REG_FPR:
+		vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
 		break;
 #ifdef CONFIG_PPC_BOOK3S
-	case KVM_REG_QPR:
-		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr;
+	case KVM_MMIO_REG_QPR:
+		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
 		break;
-	case KVM_REG_FQPR:
-		vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr;
-		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr;
+	case KVM_MMIO_REG_FQPR:
+		vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
+		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
 		break;
 #endif
 	default:
@@ -553,8 +580,6 @@
 		vcpu->arch.hcall_needed = 0;
 	}
 
-	kvmppc_core_deliver_interrupts(vcpu);
-
 	r = kvmppc_vcpu_run(run, vcpu);
 
 	if (vcpu->sigset_active)
@@ -563,6 +588,21 @@
 	return r;
 }
 
+void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
+{
+	int me;
+	int cpu = vcpu->cpu;
+
+	me = get_cpu();
+	if (waitqueue_active(vcpu->arch.wqp)) {
+		wake_up_interruptible(vcpu->arch.wqp);
+		vcpu->stat.halt_wakeup++;
+	} else if (cpu != me && cpu != -1) {
+		smp_send_reschedule(vcpu->cpu);
+	}
+	put_cpu();
+}
+
 int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
 {
 	if (irq->irq == KVM_INTERRUPT_UNSET) {
@@ -571,13 +611,7 @@
 	}
 
 	kvmppc_core_queue_external(vcpu, irq);
-
-	if (waitqueue_active(vcpu->arch.wqp)) {
-		wake_up_interruptible(vcpu->arch.wqp);
-		vcpu->stat.halt_wakeup++;
-	} else if (vcpu->cpu != -1) {
-		smp_send_reschedule(vcpu->cpu);
-	}
+	kvm_vcpu_kick(vcpu);
 
 	return 0;
 }
@@ -599,6 +633,19 @@
 		r = 0;
 		vcpu->arch.papr_enabled = true;
 		break;
+#ifdef CONFIG_KVM_E500
+	case KVM_CAP_SW_TLB: {
+		struct kvm_config_tlb cfg;
+		void __user *user_ptr = (void __user *)(uintptr_t)cap->args[0];
+
+		r = -EFAULT;
+		if (copy_from_user(&cfg, user_ptr, sizeof(cfg)))
+			break;
+
+		r = kvm_vcpu_ioctl_config_tlb(vcpu, &cfg);
+		break;
+	}
+#endif
 	default:
 		r = -EINVAL;
 		break;
@@ -648,6 +695,32 @@
 		r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
 		break;
 	}
+
+	case KVM_SET_ONE_REG:
+	case KVM_GET_ONE_REG:
+	{
+		struct kvm_one_reg reg;
+		r = -EFAULT;
+		if (copy_from_user(&reg, argp, sizeof(reg)))
+			goto out;
+		if (ioctl == KVM_SET_ONE_REG)
+			r = kvm_vcpu_ioctl_set_one_reg(vcpu, &reg);
+		else
+			r = kvm_vcpu_ioctl_get_one_reg(vcpu, &reg);
+		break;
+	}
+
+#ifdef CONFIG_KVM_E500
+	case KVM_DIRTY_TLB: {
+		struct kvm_dirty_tlb dirty;
+		r = -EFAULT;
+		if (copy_from_user(&dirty, argp, sizeof(dirty)))
+			goto out;
+		r = kvm_vcpu_ioctl_dirty_tlb(vcpu, &dirty);
+		break;
+	}
+#endif
+
 	default:
 		r = -EINVAL;
 	}
@@ -656,6 +729,11 @@
 	return r;
 }
 
+int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
+{
+	return VM_FAULT_SIGBUS;
+}
+
 static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)
 {
 	u32 inst_lis = 0x3c000000;
diff --git a/arch/powerpc/kvm/trace.h b/arch/powerpc/kvm/trace.h
index b135d3d..877186b 100644
--- a/arch/powerpc/kvm/trace.h
+++ b/arch/powerpc/kvm/trace.h
@@ -118,11 +118,14 @@
 	),
 
 	TP_fast_assign(
+		struct kvmppc_book3s_shadow_vcpu *svcpu;
 		__entry->exit_nr	= exit_nr;
 		__entry->pc		= kvmppc_get_pc(vcpu);
 		__entry->dar		= kvmppc_get_fault_dar(vcpu);
 		__entry->msr		= vcpu->arch.shared->msr;
-		__entry->srr1		= to_svcpu(vcpu)->shadow_srr1;
+		svcpu = svcpu_get(vcpu);
+		__entry->srr1		= svcpu->shadow_srr1;
+		svcpu_put(svcpu);
 	),
 
 	TP_printk("exit=0x%x | pc=0x%lx | msr=0x%lx | dar=0x%lx | srr1=0x%lx",
@@ -337,6 +340,63 @@
 
 #endif /* CONFIG_PPC_BOOK3S */
 
+
+/*************************************************************************
+ *                         Book3E trace points                           *
+ *************************************************************************/
+
+#ifdef CONFIG_BOOKE
+
+TRACE_EVENT(kvm_booke206_stlb_write,
+	TP_PROTO(__u32 mas0, __u32 mas8, __u32 mas1, __u64 mas2, __u64 mas7_3),
+	TP_ARGS(mas0, mas8, mas1, mas2, mas7_3),
+
+	TP_STRUCT__entry(
+		__field(	__u32,	mas0		)
+		__field(	__u32,	mas8		)
+		__field(	__u32,	mas1		)
+		__field(	__u64,	mas2		)
+		__field(	__u64,	mas7_3		)
+	),
+
+	TP_fast_assign(
+		__entry->mas0		= mas0;
+		__entry->mas8		= mas8;
+		__entry->mas1		= mas1;
+		__entry->mas2		= mas2;
+		__entry->mas7_3		= mas7_3;
+	),
+
+	TP_printk("mas0=%x mas8=%x mas1=%x mas2=%llx mas7_3=%llx",
+		__entry->mas0, __entry->mas8, __entry->mas1,
+		__entry->mas2, __entry->mas7_3)
+);
+
+TRACE_EVENT(kvm_booke206_gtlb_write,
+	TP_PROTO(__u32 mas0, __u32 mas1, __u64 mas2, __u64 mas7_3),
+	TP_ARGS(mas0, mas1, mas2, mas7_3),
+
+	TP_STRUCT__entry(
+		__field(	__u32,	mas0		)
+		__field(	__u32,	mas1		)
+		__field(	__u64,	mas2		)
+		__field(	__u64,	mas7_3		)
+	),
+
+	TP_fast_assign(
+		__entry->mas0		= mas0;
+		__entry->mas1		= mas1;
+		__entry->mas2		= mas2;
+		__entry->mas7_3		= mas7_3;
+	),
+
+	TP_printk("mas0=%x mas1=%x mas2=%llx mas7_3=%llx",
+		__entry->mas0, __entry->mas1,
+		__entry->mas2, __entry->mas7_3)
+);
+
+#endif
+
 #endif /* _TRACE_KVM_H */
 
 /* This part must be outside protection */
diff --git a/arch/powerpc/lib/alloc.c b/arch/powerpc/lib/alloc.c
index 13b676c..da22c84 100644
--- a/arch/powerpc/lib/alloc.c
+++ b/arch/powerpc/lib/alloc.c
@@ -3,8 +3,8 @@
 #include <linux/slab.h>
 #include <linux/bootmem.h>
 #include <linux/string.h>
+#include <asm/setup.h>
 
-#include <asm/system.h>
 
 void * __init_refok zalloc_maybe_bootmem(size_t size, gfp_t mask)
 {
diff --git a/arch/powerpc/lib/copyuser_power7_vmx.c b/arch/powerpc/lib/copyuser_power7_vmx.c
index 6e1efad..bf2654f2 100644
--- a/arch/powerpc/lib/copyuser_power7_vmx.c
+++ b/arch/powerpc/lib/copyuser_power7_vmx.c
@@ -20,6 +20,7 @@
  */
 #include <linux/uaccess.h>
 #include <linux/hardirq.h>
+#include <asm/switch_to.h>
 
 int enter_vmx_copy(void)
 {
diff --git a/arch/powerpc/lib/locks.c b/arch/powerpc/lib/locks.c
index a6ebba5..bb7cfec 100644
--- a/arch/powerpc/lib/locks.c
+++ b/arch/powerpc/lib/locks.c
@@ -19,11 +19,9 @@
 #include <linux/smp.h>
 
 /* waiting for a spinlock... */
-#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES)
+#if defined(CONFIG_PPC_SPLPAR)
 #include <asm/hvcall.h>
-#include <asm/iseries/hv_call.h>
 #include <asm/smp.h>
-#include <asm/firmware.h>
 
 void __spin_yield(arch_spinlock_t *lock)
 {
@@ -40,14 +38,8 @@
 	rmb();
 	if (lock->slock != lock_value)
 		return;		/* something has changed */
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
-			((u64)holder_cpu << 32) | yield_count);
-#ifdef CONFIG_PPC_SPLPAR
-	else
-		plpar_hcall_norets(H_CONFER,
-			get_hard_smp_processor_id(holder_cpu), yield_count);
-#endif
+	plpar_hcall_norets(H_CONFER,
+		get_hard_smp_processor_id(holder_cpu), yield_count);
 }
 
 /*
@@ -71,14 +63,8 @@
 	rmb();
 	if (rw->lock != lock_value)
 		return;		/* something has changed */
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
-			((u64)holder_cpu << 32) | yield_count);
-#ifdef CONFIG_PPC_SPLPAR
-	else
-		plpar_hcall_norets(H_CONFER,
-			get_hard_smp_processor_id(holder_cpu), yield_count);
-#endif
+	plpar_hcall_norets(H_CONFER,
+		get_hard_smp_processor_id(holder_cpu), yield_count);
 }
 #endif
 
diff --git a/arch/powerpc/mm/44x_mmu.c b/arch/powerpc/mm/44x_mmu.c
index 388b95e..2c9441e 100644
--- a/arch/powerpc/mm/44x_mmu.c
+++ b/arch/powerpc/mm/44x_mmu.c
@@ -27,7 +27,6 @@
 #include <linux/memblock.h>
 
 #include <asm/mmu.h>
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/cacheflush.h>
 
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 2f0d1b0..08ffcf5 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -38,10 +38,10 @@
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
 #include <asm/mmu_context.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/tlbflush.h>
 #include <asm/siginfo.h>
+#include <asm/debug.h>
 #include <mm/mmu_decl.h>
 
 #include "icswx.h"
@@ -105,6 +105,82 @@
 	}
 	return 0;
 }
+/*
+ * do_page_fault error handling helpers
+ */
+
+#define MM_FAULT_RETURN		0
+#define MM_FAULT_CONTINUE	-1
+#define MM_FAULT_ERR(sig)	(sig)
+
+static int out_of_memory(struct pt_regs *regs)
+{
+	/*
+	 * We ran out of memory, or some other thing happened to us that made
+	 * us unable to handle the page fault gracefully.
+	 */
+	up_read(&current->mm->mmap_sem);
+	if (!user_mode(regs))
+		return MM_FAULT_ERR(SIGKILL);
+	pagefault_out_of_memory();
+	return MM_FAULT_RETURN;
+}
+
+static int do_sigbus(struct pt_regs *regs, unsigned long address)
+{
+	siginfo_t info;
+
+	up_read(&current->mm->mmap_sem);
+
+	if (user_mode(regs)) {
+		info.si_signo = SIGBUS;
+		info.si_errno = 0;
+		info.si_code = BUS_ADRERR;
+		info.si_addr = (void __user *)address;
+		force_sig_info(SIGBUS, &info, current);
+		return MM_FAULT_RETURN;
+	}
+	return MM_FAULT_ERR(SIGBUS);
+}
+
+static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault)
+{
+	/*
+	 * Pagefault was interrupted by SIGKILL. We have no reason to
+	 * continue the pagefault.
+	 */
+	if (fatal_signal_pending(current)) {
+		/*
+		 * If we have retry set, the mmap semaphore will have
+		 * alrady been released in __lock_page_or_retry(). Else
+		 * we release it now.
+		 */
+		if (!(fault & VM_FAULT_RETRY))
+			up_read(&current->mm->mmap_sem);
+		/* Coming from kernel, we need to deal with uaccess fixups */
+		if (user_mode(regs))
+			return MM_FAULT_RETURN;
+		return MM_FAULT_ERR(SIGKILL);
+	}
+
+	/* No fault: be happy */
+	if (!(fault & VM_FAULT_ERROR))
+		return MM_FAULT_CONTINUE;
+
+	/* Out of memory */
+	if (fault & VM_FAULT_OOM)
+		return out_of_memory(regs);
+
+	/* Bus error. x86 handles HWPOISON here, we'll add this if/when
+	 * we support the feature in HW
+	 */
+	if (fault & VM_FAULT_SIGBUS)
+		return do_sigbus(regs, addr);
+
+	/* We don't understand the fault code, this is fatal */
+	BUG();
+	return MM_FAULT_CONTINUE;
+}
 
 /*
  * For 600- and 800-family processors, the error_code parameter is DSISR
@@ -124,11 +200,12 @@
 {
 	struct vm_area_struct * vma;
 	struct mm_struct *mm = current->mm;
-	siginfo_t info;
+	unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 	int code = SEGV_MAPERR;
-	int is_write = 0, ret;
+	int is_write = 0;
 	int trap = TRAP(regs);
  	int is_exec = trap == 0x400;
+	int fault;
 
 #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
 	/*
@@ -145,6 +222,9 @@
 	is_write = error_code & ESR_DST;
 #endif /* CONFIG_4xx || CONFIG_BOOKE */
 
+	if (is_write)
+		flags |= FAULT_FLAG_WRITE;
+
 #ifdef CONFIG_PPC_ICSWX
 	/*
 	 * we need to do this early because this "data storage
@@ -152,13 +232,11 @@
 	 * look at it
 	 */
 	if (error_code & ICSWX_DSI_UCT) {
-		int ret;
-
-		ret = acop_handle_fault(regs, address, error_code);
-		if (ret)
-			return ret;
+		int rc = acop_handle_fault(regs, address, error_code);
+		if (rc)
+			return rc;
 	}
-#endif
+#endif /* CONFIG_PPC_ICSWX */
 
 	if (notify_page_fault(regs))
 		return 0;
@@ -179,6 +257,10 @@
 	}
 #endif
 
+	/* We restore the interrupt state now */
+	if (!arch_irq_disabled_regs(regs))
+		local_irq_enable();
+
 	if (in_atomic() || mm == NULL) {
 		if (!user_mode(regs))
 			return SIGSEGV;
@@ -212,7 +294,15 @@
 		if (!user_mode(regs) && !search_exception_tables(regs->nip))
 			goto bad_area_nosemaphore;
 
+retry:
 		down_read(&mm->mmap_sem);
+	} else {
+		/*
+		 * The above down_read_trylock() might have succeeded in
+		 * which case we'll have missed the might_sleep() from
+		 * down_read():
+		 */
+		might_sleep();
 	}
 
 	vma = find_vma(mm, address);
@@ -327,30 +417,43 @@
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	ret = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0);
-	if (unlikely(ret & VM_FAULT_ERROR)) {
-		if (ret & VM_FAULT_OOM)
-			goto out_of_memory;
-		else if (ret & VM_FAULT_SIGBUS)
-			goto do_sigbus;
-		BUG();
+	fault = handle_mm_fault(mm, vma, address, flags);
+	if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) {
+		int rc = mm_fault_error(regs, address, fault);
+		if (rc >= MM_FAULT_RETURN)
+			return rc;
 	}
-	if (ret & VM_FAULT_MAJOR) {
-		current->maj_flt++;
-		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
-				     regs, address);
+
+	/*
+	 * Major/minor page fault accounting is only done on the
+	 * initial attempt. If we go through a retry, it is extremely
+	 * likely that the page will be found in page cache at that point.
+	 */
+	if (flags & FAULT_FLAG_ALLOW_RETRY) {
+		if (fault & VM_FAULT_MAJOR) {
+			current->maj_flt++;
+			perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
+				      regs, address);
 #ifdef CONFIG_PPC_SMLPAR
-		if (firmware_has_feature(FW_FEATURE_CMO)) {
-			preempt_disable();
-			get_lppaca()->page_ins += (1 << PAGE_FACTOR);
-			preempt_enable();
+			if (firmware_has_feature(FW_FEATURE_CMO)) {
+				preempt_disable();
+				get_lppaca()->page_ins += (1 << PAGE_FACTOR);
+				preempt_enable();
+			}
+#endif /* CONFIG_PPC_SMLPAR */
+		} else {
+			current->min_flt++;
+			perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
+				      regs, address);
 		}
-#endif
-	} else {
-		current->min_flt++;
-		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
-				     regs, address);
+		if (fault & VM_FAULT_RETRY) {
+			/* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
+			 * of starvation. */
+			flags &= ~FAULT_FLAG_ALLOW_RETRY;
+			goto retry;
+		}
 	}
+
 	up_read(&mm->mmap_sem);
 	return 0;
 
@@ -371,28 +474,6 @@
 
 	return SIGSEGV;
 
-/*
- * We ran out of memory, or some other thing happened to us that made
- * us unable to handle the page fault gracefully.
- */
-out_of_memory:
-	up_read(&mm->mmap_sem);
-	if (!user_mode(regs))
-		return SIGKILL;
-	pagefault_out_of_memory();
-	return 0;
-
-do_sigbus:
-	up_read(&mm->mmap_sem);
-	if (user_mode(regs)) {
-		info.si_signo = SIGBUS;
-		info.si_errno = 0;
-		info.si_code = BUS_ADRERR;
-		info.si_addr = (void __user *)address;
-		force_sig_info(SIGBUS, &info, current);
-		return 0;
-	}
-	return SIGBUS;
 }
 
 /*
diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c
index 66a6fd3..07ba45b 100644
--- a/arch/powerpc/mm/fsl_booke_mmu.c
+++ b/arch/powerpc/mm/fsl_booke_mmu.c
@@ -149,12 +149,19 @@
 unsigned long calc_cam_sz(unsigned long ram, unsigned long virt,
 			  phys_addr_t phys)
 {
-	unsigned int camsize = __ilog2(ram) & ~1U;
-	unsigned int align = __ffs(virt | phys) & ~1U;
-	unsigned long max_cam = (mfspr(SPRN_TLB1CFG) >> 16) & 0xf;
+	unsigned int camsize = __ilog2(ram);
+	unsigned int align = __ffs(virt | phys);
+	unsigned long max_cam;
 
-	/* Convert (4^max) kB to (2^max) bytes */
-	max_cam = max_cam * 2 + 10;
+	if ((mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1) {
+		/* Convert (4^max) kB to (2^max) bytes */
+		max_cam = ((mfspr(SPRN_TLB1CFG) >> 16) & 0xf) * 2 + 10;
+		camsize &= ~1U;
+		align &= ~1U;
+	} else {
+		/* Convert (2^max) kB to (2^max) bytes */
+		max_cam = __ilog2(mfspr(SPRN_TLB1PS)) + 10;
+	}
 
 	if (camsize > align)
 		camsize = align;
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 2d28218..377e5cb 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -40,7 +40,6 @@
 #include <asm/mmu_context.h>
 #include <asm/page.h>
 #include <asm/types.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/machdep.h>
 #include <asm/prom.h>
@@ -55,6 +54,8 @@
 #include <asm/spu.h>
 #include <asm/udbg.h>
 #include <asm/code-patching.h>
+#include <asm/fadump.h>
+#include <asm/firmware.h>
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -625,6 +626,16 @@
 		/* Using a hypervisor which owns the htab */
 		htab_address = NULL;
 		_SDR1 = 0; 
+#ifdef CONFIG_FA_DUMP
+		/*
+		 * If firmware assisted dump is active firmware preserves
+		 * the contents of htab along with entire partition memory.
+		 * Clear the htab if firmware assisted dump is active so
+		 * that we dont end up using old mappings.
+		 */
+		if (is_fadump_active() && ppc_md.hpte_clear_all)
+			ppc_md.hpte_clear_all();
+#endif
 	} else {
 		/* Find storage for the HPT.  Must be contiguous in
 		 * the absolute address space. On cell we want it to be
@@ -745,12 +756,9 @@
 	 */
 	htab_initialize();
 
-	/* Initialize stab / SLB management except on iSeries
-	 */
+	/* Initialize stab / SLB management */
 	if (mmu_has_feature(MMU_FTR_SLB))
 		slb_initialize();
-	else if (!firmware_has_feature(FW_FEATURE_ISERIES))
-		stab_initialize(get_paca()->stab_real);
 }
 
 #ifdef CONFIG_SMP
@@ -761,8 +769,7 @@
 		mtspr(SPRN_SDR1, _SDR1);
 
 	/* Initialize STAB/SLB. We use a virtual address as it works
-	 * in real mode on pSeries and we want a virtual address on
-	 * iSeries anyway
+	 * in real mode on pSeries.
 	 */
 	if (mmu_has_feature(MMU_FTR_SLB))
 		slb_initialize();
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 57c7465..fb05b12 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -12,6 +12,7 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/hugetlb.h>
+#include <linux/export.h>
 #include <linux/of_fdt.h>
 #include <linux/memblock.h>
 #include <linux/bootmem.h>
@@ -103,6 +104,7 @@
 		*shift = hugepd_shift(*hpdp);
 	return hugepte_offset(hpdp, ea, pdshift);
 }
+EXPORT_SYMBOL_GPL(find_linux_pte_or_hugepte);
 
 pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
 {
@@ -310,7 +312,8 @@
 	int i;
 
 	strlcpy(cmdline, boot_command_line, COMMAND_LINE_SIZE);
-	parse_args("hugetlb gpages", cmdline, NULL, 0, &do_gpage_early_setup);
+	parse_args("hugetlb gpages", cmdline, NULL, 0, 0, 0,
+			&do_gpage_early_setup);
 
 	/*
 	 * Walk gpage list in reverse, allocating larger page sizes first.
diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c
index 5d9a59e..8cdbd86 100644
--- a/arch/powerpc/mm/icswx.c
+++ b/arch/powerpc/mm/icswx.c
@@ -163,7 +163,7 @@
 
 static int acop_use_cop(int ct)
 {
-	/* todo */
+	/* There is no alternate policy, yet */
 	return -1;
 }
 
@@ -227,11 +227,30 @@
 		ct = (ccw >> 16) & 0x3f;
 	}
 
+	/*
+	 * We could be here because another thread has enabled acop
+	 * but the ACOP register has yet to be updated.
+	 *
+	 * This should have been taken care of by the IPI to sync all
+	 * the threads (see smp_call_function(sync_cop, mm, 1)), but
+	 * that could take forever if there are a significant amount
+	 * of threads.
+	 *
+	 * Given the number of threads on some of these systems,
+	 * perhaps this is the best way to sync ACOP rather than whack
+	 * every thread with an IPI.
+	 */
+	if ((acop_copro_type_bit(ct) & current->active_mm->context.acop) != 0) {
+		sync_cop(current->active_mm);
+		return 0;
+	}
+
+	/* check for alternate policy */
 	if (!acop_use_cop(ct))
 		return 0;
 
 	/* at this point the CT is unknown to the system */
-	pr_warn("%s[%d]: Coprocessor %d is unavailable",
+	pr_warn("%s[%d]: Coprocessor %d is unavailable\n",
 		current->comm, current->pid, ct);
 
 	/* get inst if we don't already have it */
diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h
index 42176bd..6dedc08 100644
--- a/arch/powerpc/mm/icswx.h
+++ b/arch/powerpc/mm/icswx.h
@@ -59,4 +59,10 @@
 
 extern int acop_handle_fault(struct pt_regs *regs, unsigned long address,
 			     unsigned long error_code);
+
+static inline u64 acop_copro_type_bit(unsigned int type)
+{
+	return 1ULL << (63 - type);
+}
+
 #endif /* !_ARCH_POWERPC_MM_ICSWX_H_ */
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 6157be2..01e2db9 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -45,7 +45,6 @@
 #include <asm/btext.h>
 #include <asm/tlb.h>
 #include <asm/sections.h>
-#include <asm/system.h>
 #include <asm/hugetlb.h>
 
 #include "mmu_decl.h"
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index e94b57f..620b7ac 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -61,7 +61,6 @@
 #include <asm/mmzone.h>
 #include <asm/cputable.h>
 #include <asm/sections.h>
-#include <asm/system.h>
 #include <asm/iommu.h>
 #include <asm/abs_addr.h>
 #include <asm/vdso.h>
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 3feefc3..b6edbb3 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -24,11 +24,11 @@
 #include <linux/node.h>
 #include <asm/sparsemem.h>
 #include <asm/prom.h>
-#include <asm/system.h>
 #include <asm/smp.h>
 #include <asm/firmware.h>
 #include <asm/paca.h>
 #include <asm/hvcall.h>
+#include <asm/setup.h>
 
 static int numa_enabled = 1;
 
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 51f8795..6c856fb 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -33,6 +33,7 @@
 #include <asm/pgalloc.h>
 #include <asm/fixmap.h>
 #include <asm/io.h>
+#include <asm/setup.h>
 
 #include "mmu_decl.h"
 
@@ -207,7 +208,7 @@
 	 */
 	if (mem_init_done && (p < virt_to_phys(high_memory)) &&
 	    !(__allow_ioremap_reserved && memblock_is_region_reserved(p, size))) {
-		printk("__ioremap(): phys addr 0x%llx is RAM lr %p\n",
+		printk("__ioremap(): phys addr 0x%llx is RAM lr %pf\n",
 		       (unsigned long long)p, __builtin_return_address(0));
 		return NULL;
 	}
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index ad36ede4..249a063 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -51,7 +51,6 @@
 #include <asm/processor.h>
 #include <asm/cputable.h>
 #include <asm/sections.h>
-#include <asm/system.h>
 #include <asm/abs_addr.h>
 #include <asm/firmware.h>
 
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index e22276c..a538c80 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -21,7 +21,6 @@
 #include <asm/cputable.h>
 #include <asm/cacheflush.h>
 #include <asm/smp.h>
-#include <asm/firmware.h>
 #include <linux/compiler.h>
 #include <asm/udbg.h>
 #include <asm/code-patching.h>
@@ -307,11 +306,6 @@
 
 	get_paca()->stab_rr = SLB_NUM_BOLTED;
 
-	/* On iSeries the bolted entries have already been set up by
-	 * the hypervisor from the lparMap data in head.S */
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		return;
-
 	lflags = SLB_VSID_KERNEL | linear_llp;
 	vflags = SLB_VSID_KERNEL | vmalloc_llp;
 
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
index ef653dc..b9ee79ce 100644
--- a/arch/powerpc/mm/slb_low.S
+++ b/arch/powerpc/mm/slb_low.S
@@ -217,21 +217,6 @@
 	 * free slot first but that took too long. Unfortunately we
  	 * dont have any LRU information to help us choose a slot.
  	 */
-#ifdef CONFIG_PPC_ISERIES
-BEGIN_FW_FTR_SECTION
-	/*
-	 * On iSeries, the "bolted" stack segment can be cast out on
-	 * shared processor switch so we need to check for a miss on
-	 * it and restore it to the right slot.
-	 */
-	ld	r9,PACAKSAVE(r13)
-	clrrdi	r9,r9,28
-	clrrdi	r3,r3,28
-	li	r10,SLB_NUM_BOLTED-1	/* Stack goes in last bolted slot */
-	cmpld	r9,r3
-	beq	3f
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif /* CONFIG_PPC_ISERIES */
 
 7:	ld	r10,PACASTABRR(r13)
 	addi	r10,r10,1
@@ -282,7 +267,6 @@
 
 /*
  * Finish loading of a 1T SLB entry (for the kernel linear mapping) and return.
- * We assume legacy iSeries will never have 1T segments.
  *
  * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9
  */
diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c
index 41e3164..9106ebb 100644
--- a/arch/powerpc/mm/stab.c
+++ b/arch/powerpc/mm/stab.c
@@ -21,8 +21,6 @@
 #include <asm/cputable.h>
 #include <asm/prom.h>
 #include <asm/abs_addr.h>
-#include <asm/firmware.h>
-#include <asm/iseries/hv_call.h>
 
 struct stab_entry {
 	unsigned long esid_data;
@@ -285,12 +283,5 @@
 	/* Set ASR */
 	stabreal = get_paca()->stab_real | 0x1ul;
 
-#ifdef CONFIG_PPC_ISERIES
-	if (firmware_has_feature(FW_FEATURE_ISERIES)) {
-		HvCall1(HvCallBaseSetASR, stabreal);
-		return;
-	}
-#endif /* CONFIG_PPC_ISERIES */
-
 	mtspr(SPRN_ASR, stabreal);
 }
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index d65e68f..4f51025 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -18,7 +18,6 @@
 #include <linux/smp.h>
 #include <linux/errno.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/pmc.h>
 #include <asm/cputable.h>
 #include <asm/oprofile_impl.h>
@@ -195,9 +194,6 @@
 	if (!cur_cpu_spec->oprofile_cpu_type)
 		return -ENODEV;
 
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		return -ENODEV;
-
 	switch (cur_cpu_spec->oprofile_type) {
 #ifdef CONFIG_PPC_BOOK3S_64
 #ifdef CONFIG_OPROFILE_CELL
diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c
index f8d36f9..ff61724 100644
--- a/arch/powerpc/oprofile/op_model_7450.c
+++ b/arch/powerpc/oprofile/op_model_7450.c
@@ -19,7 +19,6 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
 #include <asm/page.h>
diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c
index cb515cf..b9589c1 100644
--- a/arch/powerpc/oprofile/op_model_cell.c
+++ b/arch/powerpc/oprofile/op_model_cell.c
@@ -34,7 +34,6 @@
 #include <asm/ptrace.h>
 #include <asm/reg.h>
 #include <asm/rtas.h>
-#include <asm/system.h>
 #include <asm/cell-regs.h>
 
 #include "../platforms/cell/interrupt.h"
diff --git a/arch/powerpc/oprofile/op_model_fsl_emb.c b/arch/powerpc/oprofile/op_model_fsl_emb.c
index d4e6507..ccc1daa 100644
--- a/arch/powerpc/oprofile/op_model_fsl_emb.c
+++ b/arch/powerpc/oprofile/op_model_fsl_emb.c
@@ -17,7 +17,6 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
 #include <asm/reg_fsl_emb.h>
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
index e6bec74..95ae77d 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -14,7 +14,6 @@
 #include <linux/smp.h>
 #include <asm/firmware.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
 #include <asm/rtas.h>
diff --git a/arch/powerpc/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c
index a20afe4..9b801b8 100644
--- a/arch/powerpc/oprofile/op_model_rs64.c
+++ b/arch/powerpc/oprofile/op_model_rs64.c
@@ -11,7 +11,6 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
 #include <asm/oprofile_impl.h>
diff --git a/arch/powerpc/perf/Makefile b/arch/powerpc/perf/Makefile
new file mode 100644
index 0000000..af3fac2
--- /dev/null
+++ b/arch/powerpc/perf/Makefile
@@ -0,0 +1,14 @@
+subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
+
+obj-$(CONFIG_PERF_EVENTS)	+= callchain.o
+
+obj-$(CONFIG_PPC_PERF_CTRS)	+= core-book3s.o
+obj64-$(CONFIG_PPC_PERF_CTRS)	+= power4-pmu.o ppc970-pmu.o power5-pmu.o \
+				   power5+-pmu.o power6-pmu.o power7-pmu.o
+obj32-$(CONFIG_PPC_PERF_CTRS)	+= mpc7450-pmu.o
+
+obj-$(CONFIG_FSL_EMB_PERF_EVENT) += core-fsl-emb.o
+obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o
+
+obj-$(CONFIG_PPC64)		+= $(obj64-y)
+obj-$(CONFIG_PPC32)		+= $(obj32-y)
diff --git a/arch/powerpc/perf/callchain.c b/arch/powerpc/perf/callchain.c
new file mode 100644
index 0000000..e8a18d1
--- /dev/null
+++ b/arch/powerpc/perf/callchain.c
@@ -0,0 +1,492 @@
+/*
+ * Performance counter callchain support - powerpc architecture code
+ *
+ * Copyright © 2009 Paul Mackerras, 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.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/perf_event.h>
+#include <linux/percpu.h>
+#include <linux/uaccess.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/pgtable.h>
+#include <asm/sigcontext.h>
+#include <asm/ucontext.h>
+#include <asm/vdso.h>
+#ifdef CONFIG_PPC64
+#include "../kernel/ppc32.h"
+#endif
+
+
+/*
+ * Is sp valid as the address of the next kernel stack frame after prev_sp?
+ * The next frame may be in a different stack area but should not go
+ * back down in the same stack area.
+ */
+static int valid_next_sp(unsigned long sp, unsigned long prev_sp)
+{
+	if (sp & 0xf)
+		return 0;		/* must be 16-byte aligned */
+	if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
+		return 0;
+	if (sp >= prev_sp + STACK_FRAME_OVERHEAD)
+		return 1;
+	/*
+	 * sp could decrease when we jump off an interrupt stack
+	 * back to the regular process stack.
+	 */
+	if ((sp & ~(THREAD_SIZE - 1)) != (prev_sp & ~(THREAD_SIZE - 1)))
+		return 1;
+	return 0;
+}
+
+void
+perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
+{
+	unsigned long sp, next_sp;
+	unsigned long next_ip;
+	unsigned long lr;
+	long level = 0;
+	unsigned long *fp;
+
+	lr = regs->link;
+	sp = regs->gpr[1];
+	perf_callchain_store(entry, regs->nip);
+
+	if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
+		return;
+
+	for (;;) {
+		fp = (unsigned long *) sp;
+		next_sp = fp[0];
+
+		if (next_sp == sp + STACK_INT_FRAME_SIZE &&
+		    fp[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) {
+			/*
+			 * This looks like an interrupt frame for an
+			 * interrupt that occurred in the kernel
+			 */
+			regs = (struct pt_regs *)(sp + STACK_FRAME_OVERHEAD);
+			next_ip = regs->nip;
+			lr = regs->link;
+			level = 0;
+			perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
+
+		} else {
+			if (level == 0)
+				next_ip = lr;
+			else
+				next_ip = fp[STACK_FRAME_LR_SAVE];
+
+			/*
+			 * We can't tell which of the first two addresses
+			 * we get are valid, but we can filter out the
+			 * obviously bogus ones here.  We replace them
+			 * with 0 rather than removing them entirely so
+			 * that userspace can tell which is which.
+			 */
+			if ((level == 1 && next_ip == lr) ||
+			    (level <= 1 && !kernel_text_address(next_ip)))
+				next_ip = 0;
+
+			++level;
+		}
+
+		perf_callchain_store(entry, next_ip);
+		if (!valid_next_sp(next_sp, sp))
+			return;
+		sp = next_sp;
+	}
+}
+
+#ifdef CONFIG_PPC64
+/*
+ * On 64-bit we don't want to invoke hash_page on user addresses from
+ * interrupt context, so if the access faults, we read the page tables
+ * to find which page (if any) is mapped and access it directly.
+ */
+static int read_user_stack_slow(void __user *ptr, void *ret, int nb)
+{
+	pgd_t *pgdir;
+	pte_t *ptep, pte;
+	unsigned shift;
+	unsigned long addr = (unsigned long) ptr;
+	unsigned long offset;
+	unsigned long pfn;
+	void *kaddr;
+
+	pgdir = current->mm->pgd;
+	if (!pgdir)
+		return -EFAULT;
+
+	ptep = find_linux_pte_or_hugepte(pgdir, addr, &shift);
+	if (!shift)
+		shift = PAGE_SHIFT;
+
+	/* align address to page boundary */
+	offset = addr & ((1UL << shift) - 1);
+	addr -= offset;
+
+	if (ptep == NULL)
+		return -EFAULT;
+	pte = *ptep;
+	if (!pte_present(pte) || !(pte_val(pte) & _PAGE_USER))
+		return -EFAULT;
+	pfn = pte_pfn(pte);
+	if (!page_is_ram(pfn))
+		return -EFAULT;
+
+	/* no highmem to worry about here */
+	kaddr = pfn_to_kaddr(pfn);
+	memcpy(ret, kaddr + offset, nb);
+	return 0;
+}
+
+static int read_user_stack_64(unsigned long __user *ptr, unsigned long *ret)
+{
+	if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned long) ||
+	    ((unsigned long)ptr & 7))
+		return -EFAULT;
+
+	pagefault_disable();
+	if (!__get_user_inatomic(*ret, ptr)) {
+		pagefault_enable();
+		return 0;
+	}
+	pagefault_enable();
+
+	return read_user_stack_slow(ptr, ret, 8);
+}
+
+static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
+{
+	if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
+	    ((unsigned long)ptr & 3))
+		return -EFAULT;
+
+	pagefault_disable();
+	if (!__get_user_inatomic(*ret, ptr)) {
+		pagefault_enable();
+		return 0;
+	}
+	pagefault_enable();
+
+	return read_user_stack_slow(ptr, ret, 4);
+}
+
+static inline int valid_user_sp(unsigned long sp, int is_64)
+{
+	if (!sp || (sp & 7) || sp > (is_64 ? TASK_SIZE : 0x100000000UL) - 32)
+		return 0;
+	return 1;
+}
+
+/*
+ * 64-bit user processes use the same stack frame for RT and non-RT signals.
+ */
+struct signal_frame_64 {
+	char		dummy[__SIGNAL_FRAMESIZE];
+	struct ucontext	uc;
+	unsigned long	unused[2];
+	unsigned int	tramp[6];
+	struct siginfo	*pinfo;
+	void		*puc;
+	struct siginfo	info;
+	char		abigap[288];
+};
+
+static int is_sigreturn_64_address(unsigned long nip, unsigned long fp)
+{
+	if (nip == fp + offsetof(struct signal_frame_64, tramp))
+		return 1;
+	if (vdso64_rt_sigtramp && current->mm->context.vdso_base &&
+	    nip == current->mm->context.vdso_base + vdso64_rt_sigtramp)
+		return 1;
+	return 0;
+}
+
+/*
+ * Do some sanity checking on the signal frame pointed to by sp.
+ * We check the pinfo and puc pointers in the frame.
+ */
+static int sane_signal_64_frame(unsigned long sp)
+{
+	struct signal_frame_64 __user *sf;
+	unsigned long pinfo, puc;
+
+	sf = (struct signal_frame_64 __user *) sp;
+	if (read_user_stack_64((unsigned long __user *) &sf->pinfo, &pinfo) ||
+	    read_user_stack_64((unsigned long __user *) &sf->puc, &puc))
+		return 0;
+	return pinfo == (unsigned long) &sf->info &&
+		puc == (unsigned long) &sf->uc;
+}
+
+static void perf_callchain_user_64(struct perf_callchain_entry *entry,
+				   struct pt_regs *regs)
+{
+	unsigned long sp, next_sp;
+	unsigned long next_ip;
+	unsigned long lr;
+	long level = 0;
+	struct signal_frame_64 __user *sigframe;
+	unsigned long __user *fp, *uregs;
+
+	next_ip = regs->nip;
+	lr = regs->link;
+	sp = regs->gpr[1];
+	perf_callchain_store(entry, next_ip);
+
+	for (;;) {
+		fp = (unsigned long __user *) sp;
+		if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp))
+			return;
+		if (level > 0 && read_user_stack_64(&fp[2], &next_ip))
+			return;
+
+		/*
+		 * Note: the next_sp - sp >= signal frame size check
+		 * is true when next_sp < sp, which can happen when
+		 * transitioning from an alternate signal stack to the
+		 * normal stack.
+		 */
+		if (next_sp - sp >= sizeof(struct signal_frame_64) &&
+		    (is_sigreturn_64_address(next_ip, sp) ||
+		     (level <= 1 && is_sigreturn_64_address(lr, sp))) &&
+		    sane_signal_64_frame(sp)) {
+			/*
+			 * This looks like an signal frame
+			 */
+			sigframe = (struct signal_frame_64 __user *) sp;
+			uregs = sigframe->uc.uc_mcontext.gp_regs;
+			if (read_user_stack_64(&uregs[PT_NIP], &next_ip) ||
+			    read_user_stack_64(&uregs[PT_LNK], &lr) ||
+			    read_user_stack_64(&uregs[PT_R1], &sp))
+				return;
+			level = 0;
+			perf_callchain_store(entry, PERF_CONTEXT_USER);
+			perf_callchain_store(entry, next_ip);
+			continue;
+		}
+
+		if (level == 0)
+			next_ip = lr;
+		perf_callchain_store(entry, next_ip);
+		++level;
+		sp = next_sp;
+	}
+}
+
+static inline int current_is_64bit(void)
+{
+	/*
+	 * We can't use test_thread_flag() here because we may be on an
+	 * interrupt stack, and the thread flags don't get copied over
+	 * from the thread_info on the main stack to the interrupt stack.
+	 */
+	return !test_ti_thread_flag(task_thread_info(current), TIF_32BIT);
+}
+
+#else  /* CONFIG_PPC64 */
+/*
+ * On 32-bit we just access the address and let hash_page create a
+ * HPTE if necessary, so there is no need to fall back to reading
+ * the page tables.  Since this is called at interrupt level,
+ * do_page_fault() won't treat a DSI as a page fault.
+ */
+static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
+{
+	int rc;
+
+	if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
+	    ((unsigned long)ptr & 3))
+		return -EFAULT;
+
+	pagefault_disable();
+	rc = __get_user_inatomic(*ret, ptr);
+	pagefault_enable();
+
+	return rc;
+}
+
+static inline void perf_callchain_user_64(struct perf_callchain_entry *entry,
+					  struct pt_regs *regs)
+{
+}
+
+static inline int current_is_64bit(void)
+{
+	return 0;
+}
+
+static inline int valid_user_sp(unsigned long sp, int is_64)
+{
+	if (!sp || (sp & 7) || sp > TASK_SIZE - 32)
+		return 0;
+	return 1;
+}
+
+#define __SIGNAL_FRAMESIZE32	__SIGNAL_FRAMESIZE
+#define sigcontext32		sigcontext
+#define mcontext32		mcontext
+#define ucontext32		ucontext
+#define compat_siginfo_t	struct siginfo
+
+#endif /* CONFIG_PPC64 */
+
+/*
+ * Layout for non-RT signal frames
+ */
+struct signal_frame_32 {
+	char			dummy[__SIGNAL_FRAMESIZE32];
+	struct sigcontext32	sctx;
+	struct mcontext32	mctx;
+	int			abigap[56];
+};
+
+/*
+ * Layout for RT signal frames
+ */
+struct rt_signal_frame_32 {
+	char			dummy[__SIGNAL_FRAMESIZE32 + 16];
+	compat_siginfo_t	info;
+	struct ucontext32	uc;
+	int			abigap[56];
+};
+
+static int is_sigreturn_32_address(unsigned int nip, unsigned int fp)
+{
+	if (nip == fp + offsetof(struct signal_frame_32, mctx.mc_pad))
+		return 1;
+	if (vdso32_sigtramp && current->mm->context.vdso_base &&
+	    nip == current->mm->context.vdso_base + vdso32_sigtramp)
+		return 1;
+	return 0;
+}
+
+static int is_rt_sigreturn_32_address(unsigned int nip, unsigned int fp)
+{
+	if (nip == fp + offsetof(struct rt_signal_frame_32,
+				 uc.uc_mcontext.mc_pad))
+		return 1;
+	if (vdso32_rt_sigtramp && current->mm->context.vdso_base &&
+	    nip == current->mm->context.vdso_base + vdso32_rt_sigtramp)
+		return 1;
+	return 0;
+}
+
+static int sane_signal_32_frame(unsigned int sp)
+{
+	struct signal_frame_32 __user *sf;
+	unsigned int regs;
+
+	sf = (struct signal_frame_32 __user *) (unsigned long) sp;
+	if (read_user_stack_32((unsigned int __user *) &sf->sctx.regs, &regs))
+		return 0;
+	return regs == (unsigned long) &sf->mctx;
+}
+
+static int sane_rt_signal_32_frame(unsigned int sp)
+{
+	struct rt_signal_frame_32 __user *sf;
+	unsigned int regs;
+
+	sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
+	if (read_user_stack_32((unsigned int __user *) &sf->uc.uc_regs, &regs))
+		return 0;
+	return regs == (unsigned long) &sf->uc.uc_mcontext;
+}
+
+static unsigned int __user *signal_frame_32_regs(unsigned int sp,
+				unsigned int next_sp, unsigned int next_ip)
+{
+	struct mcontext32 __user *mctx = NULL;
+	struct signal_frame_32 __user *sf;
+	struct rt_signal_frame_32 __user *rt_sf;
+
+	/*
+	 * Note: the next_sp - sp >= signal frame size check
+	 * is true when next_sp < sp, for example, when
+	 * transitioning from an alternate signal stack to the
+	 * normal stack.
+	 */
+	if (next_sp - sp >= sizeof(struct signal_frame_32) &&
+	    is_sigreturn_32_address(next_ip, sp) &&
+	    sane_signal_32_frame(sp)) {
+		sf = (struct signal_frame_32 __user *) (unsigned long) sp;
+		mctx = &sf->mctx;
+	}
+
+	if (!mctx && next_sp - sp >= sizeof(struct rt_signal_frame_32) &&
+	    is_rt_sigreturn_32_address(next_ip, sp) &&
+	    sane_rt_signal_32_frame(sp)) {
+		rt_sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
+		mctx = &rt_sf->uc.uc_mcontext;
+	}
+
+	if (!mctx)
+		return NULL;
+	return mctx->mc_gregs;
+}
+
+static void perf_callchain_user_32(struct perf_callchain_entry *entry,
+				   struct pt_regs *regs)
+{
+	unsigned int sp, next_sp;
+	unsigned int next_ip;
+	unsigned int lr;
+	long level = 0;
+	unsigned int __user *fp, *uregs;
+
+	next_ip = regs->nip;
+	lr = regs->link;
+	sp = regs->gpr[1];
+	perf_callchain_store(entry, next_ip);
+
+	while (entry->nr < PERF_MAX_STACK_DEPTH) {
+		fp = (unsigned int __user *) (unsigned long) sp;
+		if (!valid_user_sp(sp, 0) || read_user_stack_32(fp, &next_sp))
+			return;
+		if (level > 0 && read_user_stack_32(&fp[1], &next_ip))
+			return;
+
+		uregs = signal_frame_32_regs(sp, next_sp, next_ip);
+		if (!uregs && level <= 1)
+			uregs = signal_frame_32_regs(sp, next_sp, lr);
+		if (uregs) {
+			/*
+			 * This looks like an signal frame, so restart
+			 * the stack trace with the values in it.
+			 */
+			if (read_user_stack_32(&uregs[PT_NIP], &next_ip) ||
+			    read_user_stack_32(&uregs[PT_LNK], &lr) ||
+			    read_user_stack_32(&uregs[PT_R1], &sp))
+				return;
+			level = 0;
+			perf_callchain_store(entry, PERF_CONTEXT_USER);
+			perf_callchain_store(entry, next_ip);
+			continue;
+		}
+
+		if (level == 0)
+			next_ip = lr;
+		perf_callchain_store(entry, next_ip);
+		++level;
+		sp = next_sp;
+	}
+}
+
+void
+perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
+{
+	if (current_is_64bit())
+		perf_callchain_user_64(entry, regs);
+	else
+		perf_callchain_user_32(entry, regs);
+}
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
new file mode 100644
index 0000000..02aee03
--- /dev/null
+++ b/arch/powerpc/perf/core-book3s.c
@@ -0,0 +1,1484 @@
+/*
+ * Performance event support - powerpc architecture code
+ *
+ * Copyright 2008-2009 Paul Mackerras, 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.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/perf_event.h>
+#include <linux/percpu.h>
+#include <linux/hardirq.h>
+#include <asm/reg.h>
+#include <asm/pmc.h>
+#include <asm/machdep.h>
+#include <asm/firmware.h>
+#include <asm/ptrace.h>
+
+struct cpu_hw_events {
+	int n_events;
+	int n_percpu;
+	int disabled;
+	int n_added;
+	int n_limited;
+	u8  pmcs_enabled;
+	struct perf_event *event[MAX_HWEVENTS];
+	u64 events[MAX_HWEVENTS];
+	unsigned int flags[MAX_HWEVENTS];
+	unsigned long mmcr[3];
+	struct perf_event *limited_counter[MAX_LIMITED_HWCOUNTERS];
+	u8  limited_hwidx[MAX_LIMITED_HWCOUNTERS];
+	u64 alternatives[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
+	unsigned long amasks[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
+	unsigned long avalues[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
+
+	unsigned int group_flag;
+	int n_txn_start;
+};
+DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
+
+struct power_pmu *ppmu;
+
+/*
+ * Normally, to ignore kernel events we set the FCS (freeze counters
+ * in supervisor mode) bit in MMCR0, but if the kernel runs with the
+ * hypervisor bit set in the MSR, or if we are running on a processor
+ * where the hypervisor bit is forced to 1 (as on Apple G5 processors),
+ * then we need to use the FCHV bit to ignore kernel events.
+ */
+static unsigned int freeze_events_kernel = MMCR0_FCS;
+
+/*
+ * 32-bit doesn't have MMCRA but does have an MMCR2,
+ * and a few other names are different.
+ */
+#ifdef CONFIG_PPC32
+
+#define MMCR0_FCHV		0
+#define MMCR0_PMCjCE		MMCR0_PMCnCE
+
+#define SPRN_MMCRA		SPRN_MMCR2
+#define MMCRA_SAMPLE_ENABLE	0
+
+static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
+{
+	return 0;
+}
+static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) { }
+static inline u32 perf_get_misc_flags(struct pt_regs *regs)
+{
+	return 0;
+}
+static inline void perf_read_regs(struct pt_regs *regs) { }
+static inline int perf_intr_is_nmi(struct pt_regs *regs)
+{
+	return 0;
+}
+
+#endif /* CONFIG_PPC32 */
+
+/*
+ * Things that are specific to 64-bit implementations.
+ */
+#ifdef CONFIG_PPC64
+
+static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
+{
+	unsigned long mmcra = regs->dsisr;
+
+	if ((mmcra & MMCRA_SAMPLE_ENABLE) && !(ppmu->flags & PPMU_ALT_SIPR)) {
+		unsigned long slot = (mmcra & MMCRA_SLOT) >> MMCRA_SLOT_SHIFT;
+		if (slot > 1)
+			return 4 * (slot - 1);
+	}
+	return 0;
+}
+
+/*
+ * The user wants a data address recorded.
+ * If we're not doing instruction sampling, give them the SDAR
+ * (sampled data address).  If we are doing instruction sampling, then
+ * only give them the SDAR if it corresponds to the instruction
+ * pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC
+ * bit in MMCRA.
+ */
+static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
+{
+	unsigned long mmcra = regs->dsisr;
+	unsigned long sdsync = (ppmu->flags & PPMU_ALT_SIPR) ?
+		POWER6_MMCRA_SDSYNC : MMCRA_SDSYNC;
+
+	if (!(mmcra & MMCRA_SAMPLE_ENABLE) || (mmcra & sdsync))
+		*addrp = mfspr(SPRN_SDAR);
+}
+
+static inline u32 perf_flags_from_msr(struct pt_regs *regs)
+{
+	if (regs->msr & MSR_PR)
+		return PERF_RECORD_MISC_USER;
+	if ((regs->msr & MSR_HV) && freeze_events_kernel != MMCR0_FCHV)
+		return PERF_RECORD_MISC_HYPERVISOR;
+	return PERF_RECORD_MISC_KERNEL;
+}
+
+static inline u32 perf_get_misc_flags(struct pt_regs *regs)
+{
+	unsigned long mmcra = regs->dsisr;
+	unsigned long sihv = MMCRA_SIHV;
+	unsigned long sipr = MMCRA_SIPR;
+
+	/* Not a PMU interrupt: Make up flags from regs->msr */
+	if (TRAP(regs) != 0xf00)
+		return perf_flags_from_msr(regs);
+
+	/*
+	 * If we don't support continuous sampling and this
+	 * is not a marked event, same deal
+	 */
+	if ((ppmu->flags & PPMU_NO_CONT_SAMPLING) &&
+	    !(mmcra & MMCRA_SAMPLE_ENABLE))
+		return perf_flags_from_msr(regs);
+
+	/*
+	 * If we don't have flags in MMCRA, rather than using
+	 * the MSR, we intuit the flags from the address in
+	 * SIAR which should give slightly more reliable
+	 * results
+	 */
+	if (ppmu->flags & PPMU_NO_SIPR) {
+		unsigned long siar = mfspr(SPRN_SIAR);
+		if (siar >= PAGE_OFFSET)
+			return PERF_RECORD_MISC_KERNEL;
+		return PERF_RECORD_MISC_USER;
+	}
+
+	if (ppmu->flags & PPMU_ALT_SIPR) {
+		sihv = POWER6_MMCRA_SIHV;
+		sipr = POWER6_MMCRA_SIPR;
+	}
+
+	/* PR has priority over HV, so order below is important */
+	if (mmcra & sipr)
+		return PERF_RECORD_MISC_USER;
+	if ((mmcra & sihv) && (freeze_events_kernel != MMCR0_FCHV))
+		return PERF_RECORD_MISC_HYPERVISOR;
+	return PERF_RECORD_MISC_KERNEL;
+}
+
+/*
+ * Overload regs->dsisr to store MMCRA so we only need to read it once
+ * on each interrupt.
+ */
+static inline void perf_read_regs(struct pt_regs *regs)
+{
+	regs->dsisr = mfspr(SPRN_MMCRA);
+}
+
+/*
+ * If interrupts were soft-disabled when a PMU interrupt occurs, treat
+ * it as an NMI.
+ */
+static inline int perf_intr_is_nmi(struct pt_regs *regs)
+{
+	return !regs->softe;
+}
+
+#endif /* CONFIG_PPC64 */
+
+static void perf_event_interrupt(struct pt_regs *regs);
+
+void perf_event_print_debug(void)
+{
+}
+
+/*
+ * Read one performance monitor counter (PMC).
+ */
+static unsigned long read_pmc(int idx)
+{
+	unsigned long val;
+
+	switch (idx) {
+	case 1:
+		val = mfspr(SPRN_PMC1);
+		break;
+	case 2:
+		val = mfspr(SPRN_PMC2);
+		break;
+	case 3:
+		val = mfspr(SPRN_PMC3);
+		break;
+	case 4:
+		val = mfspr(SPRN_PMC4);
+		break;
+	case 5:
+		val = mfspr(SPRN_PMC5);
+		break;
+	case 6:
+		val = mfspr(SPRN_PMC6);
+		break;
+#ifdef CONFIG_PPC64
+	case 7:
+		val = mfspr(SPRN_PMC7);
+		break;
+	case 8:
+		val = mfspr(SPRN_PMC8);
+		break;
+#endif /* CONFIG_PPC64 */
+	default:
+		printk(KERN_ERR "oops trying to read PMC%d\n", idx);
+		val = 0;
+	}
+	return val;
+}
+
+/*
+ * Write one PMC.
+ */
+static void write_pmc(int idx, unsigned long val)
+{
+	switch (idx) {
+	case 1:
+		mtspr(SPRN_PMC1, val);
+		break;
+	case 2:
+		mtspr(SPRN_PMC2, val);
+		break;
+	case 3:
+		mtspr(SPRN_PMC3, val);
+		break;
+	case 4:
+		mtspr(SPRN_PMC4, val);
+		break;
+	case 5:
+		mtspr(SPRN_PMC5, val);
+		break;
+	case 6:
+		mtspr(SPRN_PMC6, val);
+		break;
+#ifdef CONFIG_PPC64
+	case 7:
+		mtspr(SPRN_PMC7, val);
+		break;
+	case 8:
+		mtspr(SPRN_PMC8, val);
+		break;
+#endif /* CONFIG_PPC64 */
+	default:
+		printk(KERN_ERR "oops trying to write PMC%d\n", idx);
+	}
+}
+
+/*
+ * Check if a set of events can all go on the PMU at once.
+ * If they can't, this will look at alternative codes for the events
+ * and see if any combination of alternative codes is feasible.
+ * The feasible set is returned in event_id[].
+ */
+static int power_check_constraints(struct cpu_hw_events *cpuhw,
+				   u64 event_id[], unsigned int cflags[],
+				   int n_ev)
+{
+	unsigned long mask, value, nv;
+	unsigned long smasks[MAX_HWEVENTS], svalues[MAX_HWEVENTS];
+	int n_alt[MAX_HWEVENTS], choice[MAX_HWEVENTS];
+	int i, j;
+	unsigned long addf = ppmu->add_fields;
+	unsigned long tadd = ppmu->test_adder;
+
+	if (n_ev > ppmu->n_counter)
+		return -1;
+
+	/* First see if the events will go on as-is */
+	for (i = 0; i < n_ev; ++i) {
+		if ((cflags[i] & PPMU_LIMITED_PMC_REQD)
+		    && !ppmu->limited_pmc_event(event_id[i])) {
+			ppmu->get_alternatives(event_id[i], cflags[i],
+					       cpuhw->alternatives[i]);
+			event_id[i] = cpuhw->alternatives[i][0];
+		}
+		if (ppmu->get_constraint(event_id[i], &cpuhw->amasks[i][0],
+					 &cpuhw->avalues[i][0]))
+			return -1;
+	}
+	value = mask = 0;
+	for (i = 0; i < n_ev; ++i) {
+		nv = (value | cpuhw->avalues[i][0]) +
+			(value & cpuhw->avalues[i][0] & addf);
+		if ((((nv + tadd) ^ value) & mask) != 0 ||
+		    (((nv + tadd) ^ cpuhw->avalues[i][0]) &
+		     cpuhw->amasks[i][0]) != 0)
+			break;
+		value = nv;
+		mask |= cpuhw->amasks[i][0];
+	}
+	if (i == n_ev)
+		return 0;	/* all OK */
+
+	/* doesn't work, gather alternatives... */
+	if (!ppmu->get_alternatives)
+		return -1;
+	for (i = 0; i < n_ev; ++i) {
+		choice[i] = 0;
+		n_alt[i] = ppmu->get_alternatives(event_id[i], cflags[i],
+						  cpuhw->alternatives[i]);
+		for (j = 1; j < n_alt[i]; ++j)
+			ppmu->get_constraint(cpuhw->alternatives[i][j],
+					     &cpuhw->amasks[i][j],
+					     &cpuhw->avalues[i][j]);
+	}
+
+	/* enumerate all possibilities and see if any will work */
+	i = 0;
+	j = -1;
+	value = mask = nv = 0;
+	while (i < n_ev) {
+		if (j >= 0) {
+			/* we're backtracking, restore context */
+			value = svalues[i];
+			mask = smasks[i];
+			j = choice[i];
+		}
+		/*
+		 * See if any alternative k for event_id i,
+		 * where k > j, will satisfy the constraints.
+		 */
+		while (++j < n_alt[i]) {
+			nv = (value | cpuhw->avalues[i][j]) +
+				(value & cpuhw->avalues[i][j] & addf);
+			if ((((nv + tadd) ^ value) & mask) == 0 &&
+			    (((nv + tadd) ^ cpuhw->avalues[i][j])
+			     & cpuhw->amasks[i][j]) == 0)
+				break;
+		}
+		if (j >= n_alt[i]) {
+			/*
+			 * No feasible alternative, backtrack
+			 * to event_id i-1 and continue enumerating its
+			 * alternatives from where we got up to.
+			 */
+			if (--i < 0)
+				return -1;
+		} else {
+			/*
+			 * Found a feasible alternative for event_id i,
+			 * remember where we got up to with this event_id,
+			 * go on to the next event_id, and start with
+			 * the first alternative for it.
+			 */
+			choice[i] = j;
+			svalues[i] = value;
+			smasks[i] = mask;
+			value = nv;
+			mask |= cpuhw->amasks[i][j];
+			++i;
+			j = -1;
+		}
+	}
+
+	/* OK, we have a feasible combination, tell the caller the solution */
+	for (i = 0; i < n_ev; ++i)
+		event_id[i] = cpuhw->alternatives[i][choice[i]];
+	return 0;
+}
+
+/*
+ * Check if newly-added events have consistent settings for
+ * exclude_{user,kernel,hv} with each other and any previously
+ * added events.
+ */
+static int check_excludes(struct perf_event **ctrs, unsigned int cflags[],
+			  int n_prev, int n_new)
+{
+	int eu = 0, ek = 0, eh = 0;
+	int i, n, first;
+	struct perf_event *event;
+
+	n = n_prev + n_new;
+	if (n <= 1)
+		return 0;
+
+	first = 1;
+	for (i = 0; i < n; ++i) {
+		if (cflags[i] & PPMU_LIMITED_PMC_OK) {
+			cflags[i] &= ~PPMU_LIMITED_PMC_REQD;
+			continue;
+		}
+		event = ctrs[i];
+		if (first) {
+			eu = event->attr.exclude_user;
+			ek = event->attr.exclude_kernel;
+			eh = event->attr.exclude_hv;
+			first = 0;
+		} else if (event->attr.exclude_user != eu ||
+			   event->attr.exclude_kernel != ek ||
+			   event->attr.exclude_hv != eh) {
+			return -EAGAIN;
+		}
+	}
+
+	if (eu || ek || eh)
+		for (i = 0; i < n; ++i)
+			if (cflags[i] & PPMU_LIMITED_PMC_OK)
+				cflags[i] |= PPMU_LIMITED_PMC_REQD;
+
+	return 0;
+}
+
+static u64 check_and_compute_delta(u64 prev, u64 val)
+{
+	u64 delta = (val - prev) & 0xfffffffful;
+
+	/*
+	 * POWER7 can roll back counter values, if the new value is smaller
+	 * than the previous value it will cause the delta and the counter to
+	 * have bogus values unless we rolled a counter over.  If a coutner is
+	 * rolled back, it will be smaller, but within 256, which is the maximum
+	 * number of events to rollback at once.  If we dectect a rollback
+	 * return 0.  This can lead to a small lack of precision in the
+	 * counters.
+	 */
+	if (prev > val && (prev - val) < 256)
+		delta = 0;
+
+	return delta;
+}
+
+static void power_pmu_read(struct perf_event *event)
+{
+	s64 val, delta, prev;
+
+	if (event->hw.state & PERF_HES_STOPPED)
+		return;
+
+	if (!event->hw.idx)
+		return;
+	/*
+	 * Performance monitor interrupts come even when interrupts
+	 * are soft-disabled, as long as interrupts are hard-enabled.
+	 * Therefore we treat them like NMIs.
+	 */
+	do {
+		prev = local64_read(&event->hw.prev_count);
+		barrier();
+		val = read_pmc(event->hw.idx);
+		delta = check_and_compute_delta(prev, val);
+		if (!delta)
+			return;
+	} while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
+
+	local64_add(delta, &event->count);
+	local64_sub(delta, &event->hw.period_left);
+}
+
+/*
+ * On some machines, PMC5 and PMC6 can't be written, don't respect
+ * the freeze conditions, and don't generate interrupts.  This tells
+ * us if `event' is using such a PMC.
+ */
+static int is_limited_pmc(int pmcnum)
+{
+	return (ppmu->flags & PPMU_LIMITED_PMC5_6)
+		&& (pmcnum == 5 || pmcnum == 6);
+}
+
+static void freeze_limited_counters(struct cpu_hw_events *cpuhw,
+				    unsigned long pmc5, unsigned long pmc6)
+{
+	struct perf_event *event;
+	u64 val, prev, delta;
+	int i;
+
+	for (i = 0; i < cpuhw->n_limited; ++i) {
+		event = cpuhw->limited_counter[i];
+		if (!event->hw.idx)
+			continue;
+		val = (event->hw.idx == 5) ? pmc5 : pmc6;
+		prev = local64_read(&event->hw.prev_count);
+		event->hw.idx = 0;
+		delta = check_and_compute_delta(prev, val);
+		if (delta)
+			local64_add(delta, &event->count);
+	}
+}
+
+static void thaw_limited_counters(struct cpu_hw_events *cpuhw,
+				  unsigned long pmc5, unsigned long pmc6)
+{
+	struct perf_event *event;
+	u64 val, prev;
+	int i;
+
+	for (i = 0; i < cpuhw->n_limited; ++i) {
+		event = cpuhw->limited_counter[i];
+		event->hw.idx = cpuhw->limited_hwidx[i];
+		val = (event->hw.idx == 5) ? pmc5 : pmc6;
+		prev = local64_read(&event->hw.prev_count);
+		if (check_and_compute_delta(prev, val))
+			local64_set(&event->hw.prev_count, val);
+		perf_event_update_userpage(event);
+	}
+}
+
+/*
+ * Since limited events don't respect the freeze conditions, we
+ * have to read them immediately after freezing or unfreezing the
+ * other events.  We try to keep the values from the limited
+ * events as consistent as possible by keeping the delay (in
+ * cycles and instructions) between freezing/unfreezing and reading
+ * the limited events as small and consistent as possible.
+ * Therefore, if any limited events are in use, we read them
+ * both, and always in the same order, to minimize variability,
+ * and do it inside the same asm that writes MMCR0.
+ */
+static void write_mmcr0(struct cpu_hw_events *cpuhw, unsigned long mmcr0)
+{
+	unsigned long pmc5, pmc6;
+
+	if (!cpuhw->n_limited) {
+		mtspr(SPRN_MMCR0, mmcr0);
+		return;
+	}
+
+	/*
+	 * Write MMCR0, then read PMC5 and PMC6 immediately.
+	 * To ensure we don't get a performance monitor interrupt
+	 * between writing MMCR0 and freezing/thawing the limited
+	 * events, we first write MMCR0 with the event overflow
+	 * interrupt enable bits turned off.
+	 */
+	asm volatile("mtspr %3,%2; mfspr %0,%4; mfspr %1,%5"
+		     : "=&r" (pmc5), "=&r" (pmc6)
+		     : "r" (mmcr0 & ~(MMCR0_PMC1CE | MMCR0_PMCjCE)),
+		       "i" (SPRN_MMCR0),
+		       "i" (SPRN_PMC5), "i" (SPRN_PMC6));
+
+	if (mmcr0 & MMCR0_FC)
+		freeze_limited_counters(cpuhw, pmc5, pmc6);
+	else
+		thaw_limited_counters(cpuhw, pmc5, pmc6);
+
+	/*
+	 * Write the full MMCR0 including the event overflow interrupt
+	 * enable bits, if necessary.
+	 */
+	if (mmcr0 & (MMCR0_PMC1CE | MMCR0_PMCjCE))
+		mtspr(SPRN_MMCR0, mmcr0);
+}
+
+/*
+ * Disable all events to prevent PMU interrupts and to allow
+ * events to be added or removed.
+ */
+static void power_pmu_disable(struct pmu *pmu)
+{
+	struct cpu_hw_events *cpuhw;
+	unsigned long flags;
+
+	if (!ppmu)
+		return;
+	local_irq_save(flags);
+	cpuhw = &__get_cpu_var(cpu_hw_events);
+
+	if (!cpuhw->disabled) {
+		cpuhw->disabled = 1;
+		cpuhw->n_added = 0;
+
+		/*
+		 * Check if we ever enabled the PMU on this cpu.
+		 */
+		if (!cpuhw->pmcs_enabled) {
+			ppc_enable_pmcs();
+			cpuhw->pmcs_enabled = 1;
+		}
+
+		/*
+		 * Disable instruction sampling if it was enabled
+		 */
+		if (cpuhw->mmcr[2] & MMCRA_SAMPLE_ENABLE) {
+			mtspr(SPRN_MMCRA,
+			      cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
+			mb();
+		}
+
+		/*
+		 * Set the 'freeze counters' bit.
+		 * The barrier is to make sure the mtspr has been
+		 * executed and the PMU has frozen the events
+		 * before we return.
+		 */
+		write_mmcr0(cpuhw, mfspr(SPRN_MMCR0) | MMCR0_FC);
+		mb();
+	}
+	local_irq_restore(flags);
+}
+
+/*
+ * Re-enable all events if disable == 0.
+ * If we were previously disabled and events were added, then
+ * put the new config on the PMU.
+ */
+static void power_pmu_enable(struct pmu *pmu)
+{
+	struct perf_event *event;
+	struct cpu_hw_events *cpuhw;
+	unsigned long flags;
+	long i;
+	unsigned long val;
+	s64 left;
+	unsigned int hwc_index[MAX_HWEVENTS];
+	int n_lim;
+	int idx;
+
+	if (!ppmu)
+		return;
+	local_irq_save(flags);
+	cpuhw = &__get_cpu_var(cpu_hw_events);
+	if (!cpuhw->disabled) {
+		local_irq_restore(flags);
+		return;
+	}
+	cpuhw->disabled = 0;
+
+	/*
+	 * If we didn't change anything, or only removed events,
+	 * no need to recalculate MMCR* settings and reset the PMCs.
+	 * Just reenable the PMU with the current MMCR* settings
+	 * (possibly updated for removal of events).
+	 */
+	if (!cpuhw->n_added) {
+		mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
+		mtspr(SPRN_MMCR1, cpuhw->mmcr[1]);
+		if (cpuhw->n_events == 0)
+			ppc_set_pmu_inuse(0);
+		goto out_enable;
+	}
+
+	/*
+	 * Compute MMCR* values for the new set of events
+	 */
+	if (ppmu->compute_mmcr(cpuhw->events, cpuhw->n_events, hwc_index,
+			       cpuhw->mmcr)) {
+		/* shouldn't ever get here */
+		printk(KERN_ERR "oops compute_mmcr failed\n");
+		goto out;
+	}
+
+	/*
+	 * Add in MMCR0 freeze bits corresponding to the
+	 * attr.exclude_* bits for the first event.
+	 * We have already checked that all events have the
+	 * same values for these bits as the first event.
+	 */
+	event = cpuhw->event[0];
+	if (event->attr.exclude_user)
+		cpuhw->mmcr[0] |= MMCR0_FCP;
+	if (event->attr.exclude_kernel)
+		cpuhw->mmcr[0] |= freeze_events_kernel;
+	if (event->attr.exclude_hv)
+		cpuhw->mmcr[0] |= MMCR0_FCHV;
+
+	/*
+	 * Write the new configuration to MMCR* with the freeze
+	 * bit set and set the hardware events to their initial values.
+	 * Then unfreeze the events.
+	 */
+	ppc_set_pmu_inuse(1);
+	mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
+	mtspr(SPRN_MMCR1, cpuhw->mmcr[1]);
+	mtspr(SPRN_MMCR0, (cpuhw->mmcr[0] & ~(MMCR0_PMC1CE | MMCR0_PMCjCE))
+				| MMCR0_FC);
+
+	/*
+	 * Read off any pre-existing events that need to move
+	 * to another PMC.
+	 */
+	for (i = 0; i < cpuhw->n_events; ++i) {
+		event = cpuhw->event[i];
+		if (event->hw.idx && event->hw.idx != hwc_index[i] + 1) {
+			power_pmu_read(event);
+			write_pmc(event->hw.idx, 0);
+			event->hw.idx = 0;
+		}
+	}
+
+	/*
+	 * Initialize the PMCs for all the new and moved events.
+	 */
+	cpuhw->n_limited = n_lim = 0;
+	for (i = 0; i < cpuhw->n_events; ++i) {
+		event = cpuhw->event[i];
+		if (event->hw.idx)
+			continue;
+		idx = hwc_index[i] + 1;
+		if (is_limited_pmc(idx)) {
+			cpuhw->limited_counter[n_lim] = event;
+			cpuhw->limited_hwidx[n_lim] = idx;
+			++n_lim;
+			continue;
+		}
+		val = 0;
+		if (event->hw.sample_period) {
+			left = local64_read(&event->hw.period_left);
+			if (left < 0x80000000L)
+				val = 0x80000000L - left;
+		}
+		local64_set(&event->hw.prev_count, val);
+		event->hw.idx = idx;
+		if (event->hw.state & PERF_HES_STOPPED)
+			val = 0;
+		write_pmc(idx, val);
+		perf_event_update_userpage(event);
+	}
+	cpuhw->n_limited = n_lim;
+	cpuhw->mmcr[0] |= MMCR0_PMXE | MMCR0_FCECE;
+
+ out_enable:
+	mb();
+	write_mmcr0(cpuhw, cpuhw->mmcr[0]);
+
+	/*
+	 * Enable instruction sampling if necessary
+	 */
+	if (cpuhw->mmcr[2] & MMCRA_SAMPLE_ENABLE) {
+		mb();
+		mtspr(SPRN_MMCRA, cpuhw->mmcr[2]);
+	}
+
+ out:
+	local_irq_restore(flags);
+}
+
+static int collect_events(struct perf_event *group, int max_count,
+			  struct perf_event *ctrs[], u64 *events,
+			  unsigned int *flags)
+{
+	int n = 0;
+	struct perf_event *event;
+
+	if (!is_software_event(group)) {
+		if (n >= max_count)
+			return -1;
+		ctrs[n] = group;
+		flags[n] = group->hw.event_base;
+		events[n++] = group->hw.config;
+	}
+	list_for_each_entry(event, &group->sibling_list, group_entry) {
+		if (!is_software_event(event) &&
+		    event->state != PERF_EVENT_STATE_OFF) {
+			if (n >= max_count)
+				return -1;
+			ctrs[n] = event;
+			flags[n] = event->hw.event_base;
+			events[n++] = event->hw.config;
+		}
+	}
+	return n;
+}
+
+/*
+ * Add a event to the PMU.
+ * If all events are not already frozen, then we disable and
+ * re-enable the PMU in order to get hw_perf_enable to do the
+ * actual work of reconfiguring the PMU.
+ */
+static int power_pmu_add(struct perf_event *event, int ef_flags)
+{
+	struct cpu_hw_events *cpuhw;
+	unsigned long flags;
+	int n0;
+	int ret = -EAGAIN;
+
+	local_irq_save(flags);
+	perf_pmu_disable(event->pmu);
+
+	/*
+	 * Add the event to the list (if there is room)
+	 * and check whether the total set is still feasible.
+	 */
+	cpuhw = &__get_cpu_var(cpu_hw_events);
+	n0 = cpuhw->n_events;
+	if (n0 >= ppmu->n_counter)
+		goto out;
+	cpuhw->event[n0] = event;
+	cpuhw->events[n0] = event->hw.config;
+	cpuhw->flags[n0] = event->hw.event_base;
+
+	if (!(ef_flags & PERF_EF_START))
+		event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+
+	/*
+	 * If group events scheduling transaction was started,
+	 * skip the schedulability test here, it will be performed
+	 * at commit time(->commit_txn) as a whole
+	 */
+	if (cpuhw->group_flag & PERF_EVENT_TXN)
+		goto nocheck;
+
+	if (check_excludes(cpuhw->event, cpuhw->flags, n0, 1))
+		goto out;
+	if (power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n0 + 1))
+		goto out;
+	event->hw.config = cpuhw->events[n0];
+
+nocheck:
+	++cpuhw->n_events;
+	++cpuhw->n_added;
+
+	ret = 0;
+ out:
+	perf_pmu_enable(event->pmu);
+	local_irq_restore(flags);
+	return ret;
+}
+
+/*
+ * Remove a event from the PMU.
+ */
+static void power_pmu_del(struct perf_event *event, int ef_flags)
+{
+	struct cpu_hw_events *cpuhw;
+	long i;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	perf_pmu_disable(event->pmu);
+
+	power_pmu_read(event);
+
+	cpuhw = &__get_cpu_var(cpu_hw_events);
+	for (i = 0; i < cpuhw->n_events; ++i) {
+		if (event == cpuhw->event[i]) {
+			while (++i < cpuhw->n_events) {
+				cpuhw->event[i-1] = cpuhw->event[i];
+				cpuhw->events[i-1] = cpuhw->events[i];
+				cpuhw->flags[i-1] = cpuhw->flags[i];
+			}
+			--cpuhw->n_events;
+			ppmu->disable_pmc(event->hw.idx - 1, cpuhw->mmcr);
+			if (event->hw.idx) {
+				write_pmc(event->hw.idx, 0);
+				event->hw.idx = 0;
+			}
+			perf_event_update_userpage(event);
+			break;
+		}
+	}
+	for (i = 0; i < cpuhw->n_limited; ++i)
+		if (event == cpuhw->limited_counter[i])
+			break;
+	if (i < cpuhw->n_limited) {
+		while (++i < cpuhw->n_limited) {
+			cpuhw->limited_counter[i-1] = cpuhw->limited_counter[i];
+			cpuhw->limited_hwidx[i-1] = cpuhw->limited_hwidx[i];
+		}
+		--cpuhw->n_limited;
+	}
+	if (cpuhw->n_events == 0) {
+		/* disable exceptions if no events are running */
+		cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE);
+	}
+
+	perf_pmu_enable(event->pmu);
+	local_irq_restore(flags);
+}
+
+/*
+ * POWER-PMU does not support disabling individual counters, hence
+ * program their cycle counter to their max value and ignore the interrupts.
+ */
+
+static void power_pmu_start(struct perf_event *event, int ef_flags)
+{
+	unsigned long flags;
+	s64 left;
+	unsigned long val;
+
+	if (!event->hw.idx || !event->hw.sample_period)
+		return;
+
+	if (!(event->hw.state & PERF_HES_STOPPED))
+		return;
+
+	if (ef_flags & PERF_EF_RELOAD)
+		WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+
+	local_irq_save(flags);
+	perf_pmu_disable(event->pmu);
+
+	event->hw.state = 0;
+	left = local64_read(&event->hw.period_left);
+
+	val = 0;
+	if (left < 0x80000000L)
+		val = 0x80000000L - left;
+
+	write_pmc(event->hw.idx, val);
+
+	perf_event_update_userpage(event);
+	perf_pmu_enable(event->pmu);
+	local_irq_restore(flags);
+}
+
+static void power_pmu_stop(struct perf_event *event, int ef_flags)
+{
+	unsigned long flags;
+
+	if (!event->hw.idx || !event->hw.sample_period)
+		return;
+
+	if (event->hw.state & PERF_HES_STOPPED)
+		return;
+
+	local_irq_save(flags);
+	perf_pmu_disable(event->pmu);
+
+	power_pmu_read(event);
+	event->hw.state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+	write_pmc(event->hw.idx, 0);
+
+	perf_event_update_userpage(event);
+	perf_pmu_enable(event->pmu);
+	local_irq_restore(flags);
+}
+
+/*
+ * Start group events scheduling transaction
+ * Set the flag to make pmu::enable() not perform the
+ * schedulability test, it will be performed at commit time
+ */
+void power_pmu_start_txn(struct pmu *pmu)
+{
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+	perf_pmu_disable(pmu);
+	cpuhw->group_flag |= PERF_EVENT_TXN;
+	cpuhw->n_txn_start = cpuhw->n_events;
+}
+
+/*
+ * Stop group events scheduling transaction
+ * Clear the flag and pmu::enable() will perform the
+ * schedulability test.
+ */
+void power_pmu_cancel_txn(struct pmu *pmu)
+{
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+	cpuhw->group_flag &= ~PERF_EVENT_TXN;
+	perf_pmu_enable(pmu);
+}
+
+/*
+ * Commit group events scheduling transaction
+ * Perform the group schedulability test as a whole
+ * Return 0 if success
+ */
+int power_pmu_commit_txn(struct pmu *pmu)
+{
+	struct cpu_hw_events *cpuhw;
+	long i, n;
+
+	if (!ppmu)
+		return -EAGAIN;
+	cpuhw = &__get_cpu_var(cpu_hw_events);
+	n = cpuhw->n_events;
+	if (check_excludes(cpuhw->event, cpuhw->flags, 0, n))
+		return -EAGAIN;
+	i = power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n);
+	if (i < 0)
+		return -EAGAIN;
+
+	for (i = cpuhw->n_txn_start; i < n; ++i)
+		cpuhw->event[i]->hw.config = cpuhw->events[i];
+
+	cpuhw->group_flag &= ~PERF_EVENT_TXN;
+	perf_pmu_enable(pmu);
+	return 0;
+}
+
+/*
+ * Return 1 if we might be able to put event on a limited PMC,
+ * or 0 if not.
+ * A event can only go on a limited PMC if it counts something
+ * that a limited PMC can count, doesn't require interrupts, and
+ * doesn't exclude any processor mode.
+ */
+static int can_go_on_limited_pmc(struct perf_event *event, u64 ev,
+				 unsigned int flags)
+{
+	int n;
+	u64 alt[MAX_EVENT_ALTERNATIVES];
+
+	if (event->attr.exclude_user
+	    || event->attr.exclude_kernel
+	    || event->attr.exclude_hv
+	    || event->attr.sample_period)
+		return 0;
+
+	if (ppmu->limited_pmc_event(ev))
+		return 1;
+
+	/*
+	 * The requested event_id isn't on a limited PMC already;
+	 * see if any alternative code goes on a limited PMC.
+	 */
+	if (!ppmu->get_alternatives)
+		return 0;
+
+	flags |= PPMU_LIMITED_PMC_OK | PPMU_LIMITED_PMC_REQD;
+	n = ppmu->get_alternatives(ev, flags, alt);
+
+	return n > 0;
+}
+
+/*
+ * Find an alternative event_id that goes on a normal PMC, if possible,
+ * and return the event_id code, or 0 if there is no such alternative.
+ * (Note: event_id code 0 is "don't count" on all machines.)
+ */
+static u64 normal_pmc_alternative(u64 ev, unsigned long flags)
+{
+	u64 alt[MAX_EVENT_ALTERNATIVES];
+	int n;
+
+	flags &= ~(PPMU_LIMITED_PMC_OK | PPMU_LIMITED_PMC_REQD);
+	n = ppmu->get_alternatives(ev, flags, alt);
+	if (!n)
+		return 0;
+	return alt[0];
+}
+
+/* Number of perf_events counting hardware events */
+static atomic_t num_events;
+/* Used to avoid races in calling reserve/release_pmc_hardware */
+static DEFINE_MUTEX(pmc_reserve_mutex);
+
+/*
+ * Release the PMU if this is the last perf_event.
+ */
+static void hw_perf_event_destroy(struct perf_event *event)
+{
+	if (!atomic_add_unless(&num_events, -1, 1)) {
+		mutex_lock(&pmc_reserve_mutex);
+		if (atomic_dec_return(&num_events) == 0)
+			release_pmc_hardware();
+		mutex_unlock(&pmc_reserve_mutex);
+	}
+}
+
+/*
+ * Translate a generic cache event_id config to a raw event_id code.
+ */
+static int hw_perf_cache_event(u64 config, u64 *eventp)
+{
+	unsigned long type, op, result;
+	int ev;
+
+	if (!ppmu->cache_events)
+		return -EINVAL;
+
+	/* unpack config */
+	type = config & 0xff;
+	op = (config >> 8) & 0xff;
+	result = (config >> 16) & 0xff;
+
+	if (type >= PERF_COUNT_HW_CACHE_MAX ||
+	    op >= PERF_COUNT_HW_CACHE_OP_MAX ||
+	    result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+		return -EINVAL;
+
+	ev = (*ppmu->cache_events)[type][op][result];
+	if (ev == 0)
+		return -EOPNOTSUPP;
+	if (ev == -1)
+		return -EINVAL;
+	*eventp = ev;
+	return 0;
+}
+
+static int power_pmu_event_init(struct perf_event *event)
+{
+	u64 ev;
+	unsigned long flags;
+	struct perf_event *ctrs[MAX_HWEVENTS];
+	u64 events[MAX_HWEVENTS];
+	unsigned int cflags[MAX_HWEVENTS];
+	int n;
+	int err;
+	struct cpu_hw_events *cpuhw;
+
+	if (!ppmu)
+		return -ENOENT;
+
+	/* does not support taken branch sampling */
+	if (has_branch_stack(event))
+		return -EOPNOTSUPP;
+
+	switch (event->attr.type) {
+	case PERF_TYPE_HARDWARE:
+		ev = event->attr.config;
+		if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
+			return -EOPNOTSUPP;
+		ev = ppmu->generic_events[ev];
+		break;
+	case PERF_TYPE_HW_CACHE:
+		err = hw_perf_cache_event(event->attr.config, &ev);
+		if (err)
+			return err;
+		break;
+	case PERF_TYPE_RAW:
+		ev = event->attr.config;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	event->hw.config_base = ev;
+	event->hw.idx = 0;
+
+	/*
+	 * If we are not running on a hypervisor, force the
+	 * exclude_hv bit to 0 so that we don't care what
+	 * the user set it to.
+	 */
+	if (!firmware_has_feature(FW_FEATURE_LPAR))
+		event->attr.exclude_hv = 0;
+
+	/*
+	 * If this is a per-task event, then we can use
+	 * PM_RUN_* events interchangeably with their non RUN_*
+	 * equivalents, e.g. PM_RUN_CYC instead of PM_CYC.
+	 * XXX we should check if the task is an idle task.
+	 */
+	flags = 0;
+	if (event->attach_state & PERF_ATTACH_TASK)
+		flags |= PPMU_ONLY_COUNT_RUN;
+
+	/*
+	 * If this machine has limited events, check whether this
+	 * event_id could go on a limited event.
+	 */
+	if (ppmu->flags & PPMU_LIMITED_PMC5_6) {
+		if (can_go_on_limited_pmc(event, ev, flags)) {
+			flags |= PPMU_LIMITED_PMC_OK;
+		} else if (ppmu->limited_pmc_event(ev)) {
+			/*
+			 * The requested event_id is on a limited PMC,
+			 * but we can't use a limited PMC; see if any
+			 * alternative goes on a normal PMC.
+			 */
+			ev = normal_pmc_alternative(ev, flags);
+			if (!ev)
+				return -EINVAL;
+		}
+	}
+
+	/*
+	 * If this is in a group, check if it can go on with all the
+	 * other hardware events in the group.  We assume the event
+	 * hasn't been linked into its leader's sibling list at this point.
+	 */
+	n = 0;
+	if (event->group_leader != event) {
+		n = collect_events(event->group_leader, ppmu->n_counter - 1,
+				   ctrs, events, cflags);
+		if (n < 0)
+			return -EINVAL;
+	}
+	events[n] = ev;
+	ctrs[n] = event;
+	cflags[n] = flags;
+	if (check_excludes(ctrs, cflags, n, 1))
+		return -EINVAL;
+
+	cpuhw = &get_cpu_var(cpu_hw_events);
+	err = power_check_constraints(cpuhw, events, cflags, n + 1);
+	put_cpu_var(cpu_hw_events);
+	if (err)
+		return -EINVAL;
+
+	event->hw.config = events[n];
+	event->hw.event_base = cflags[n];
+	event->hw.last_period = event->hw.sample_period;
+	local64_set(&event->hw.period_left, event->hw.last_period);
+
+	/*
+	 * See if we need to reserve the PMU.
+	 * If no events are currently in use, then we have to take a
+	 * mutex to ensure that we don't race with another task doing
+	 * reserve_pmc_hardware or release_pmc_hardware.
+	 */
+	err = 0;
+	if (!atomic_inc_not_zero(&num_events)) {
+		mutex_lock(&pmc_reserve_mutex);
+		if (atomic_read(&num_events) == 0 &&
+		    reserve_pmc_hardware(perf_event_interrupt))
+			err = -EBUSY;
+		else
+			atomic_inc(&num_events);
+		mutex_unlock(&pmc_reserve_mutex);
+	}
+	event->destroy = hw_perf_event_destroy;
+
+	return err;
+}
+
+static int power_pmu_event_idx(struct perf_event *event)
+{
+	return event->hw.idx;
+}
+
+struct pmu power_pmu = {
+	.pmu_enable	= power_pmu_enable,
+	.pmu_disable	= power_pmu_disable,
+	.event_init	= power_pmu_event_init,
+	.add		= power_pmu_add,
+	.del		= power_pmu_del,
+	.start		= power_pmu_start,
+	.stop		= power_pmu_stop,
+	.read		= power_pmu_read,
+	.start_txn	= power_pmu_start_txn,
+	.cancel_txn	= power_pmu_cancel_txn,
+	.commit_txn	= power_pmu_commit_txn,
+	.event_idx	= power_pmu_event_idx,
+};
+
+/*
+ * A counter has overflowed; update its count and record
+ * things if requested.  Note that interrupts are hard-disabled
+ * here so there is no possibility of being interrupted.
+ */
+static void record_and_restart(struct perf_event *event, unsigned long val,
+			       struct pt_regs *regs)
+{
+	u64 period = event->hw.sample_period;
+	s64 prev, delta, left;
+	int record = 0;
+
+	if (event->hw.state & PERF_HES_STOPPED) {
+		write_pmc(event->hw.idx, 0);
+		return;
+	}
+
+	/* we don't have to worry about interrupts here */
+	prev = local64_read(&event->hw.prev_count);
+	delta = check_and_compute_delta(prev, val);
+	local64_add(delta, &event->count);
+
+	/*
+	 * See if the total period for this event has expired,
+	 * and update for the next period.
+	 */
+	val = 0;
+	left = local64_read(&event->hw.period_left) - delta;
+	if (period) {
+		if (left <= 0) {
+			left += period;
+			if (left <= 0)
+				left = period;
+			record = 1;
+			event->hw.last_period = event->hw.sample_period;
+		}
+		if (left < 0x80000000LL)
+			val = 0x80000000LL - left;
+	}
+
+	write_pmc(event->hw.idx, val);
+	local64_set(&event->hw.prev_count, val);
+	local64_set(&event->hw.period_left, left);
+	perf_event_update_userpage(event);
+
+	/*
+	 * Finally record data if requested.
+	 */
+	if (record) {
+		struct perf_sample_data data;
+
+		perf_sample_data_init(&data, ~0ULL);
+		data.period = event->hw.last_period;
+
+		if (event->attr.sample_type & PERF_SAMPLE_ADDR)
+			perf_get_data_addr(regs, &data.addr);
+
+		if (perf_event_overflow(event, &data, regs))
+			power_pmu_stop(event, 0);
+	}
+}
+
+/*
+ * Called from generic code to get the misc flags (i.e. processor mode)
+ * for an event_id.
+ */
+unsigned long perf_misc_flags(struct pt_regs *regs)
+{
+	u32 flags = perf_get_misc_flags(regs);
+
+	if (flags)
+		return flags;
+	return user_mode(regs) ? PERF_RECORD_MISC_USER :
+		PERF_RECORD_MISC_KERNEL;
+}
+
+/*
+ * Called from generic code to get the instruction pointer
+ * for an event_id.
+ */
+unsigned long perf_instruction_pointer(struct pt_regs *regs)
+{
+	unsigned long mmcra = regs->dsisr;
+
+	/* Not a PMU interrupt */
+	if (TRAP(regs) != 0xf00)
+		return regs->nip;
+
+	/* Processor doesn't support sampling non marked events */
+	if ((ppmu->flags & PPMU_NO_CONT_SAMPLING) &&
+	    !(mmcra & MMCRA_SAMPLE_ENABLE))
+		return regs->nip;
+
+	return mfspr(SPRN_SIAR) + perf_ip_adjust(regs);
+}
+
+static bool pmc_overflow(unsigned long val)
+{
+	if ((int)val < 0)
+		return true;
+
+	/*
+	 * Events on POWER7 can roll back if a speculative event doesn't
+	 * eventually complete. Unfortunately in some rare cases they will
+	 * raise a performance monitor exception. We need to catch this to
+	 * ensure we reset the PMC. In all cases the PMC will be 256 or less
+	 * cycles from overflow.
+	 *
+	 * We only do this if the first pass fails to find any overflowing
+	 * PMCs because a user might set a period of less than 256 and we
+	 * don't want to mistakenly reset them.
+	 */
+	if (__is_processor(PV_POWER7) && ((0x80000000 - val) <= 256))
+		return true;
+
+	return false;
+}
+
+/*
+ * Performance monitor interrupt stuff
+ */
+static void perf_event_interrupt(struct pt_regs *regs)
+{
+	int i;
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+	struct perf_event *event;
+	unsigned long val;
+	int found = 0;
+	int nmi;
+
+	if (cpuhw->n_limited)
+		freeze_limited_counters(cpuhw, mfspr(SPRN_PMC5),
+					mfspr(SPRN_PMC6));
+
+	perf_read_regs(regs);
+
+	nmi = perf_intr_is_nmi(regs);
+	if (nmi)
+		nmi_enter();
+	else
+		irq_enter();
+
+	for (i = 0; i < cpuhw->n_events; ++i) {
+		event = cpuhw->event[i];
+		if (!event->hw.idx || is_limited_pmc(event->hw.idx))
+			continue;
+		val = read_pmc(event->hw.idx);
+		if ((int)val < 0) {
+			/* event has overflowed */
+			found = 1;
+			record_and_restart(event, val, regs);
+		}
+	}
+
+	/*
+	 * In case we didn't find and reset the event that caused
+	 * the interrupt, scan all events and reset any that are
+	 * negative, to avoid getting continual interrupts.
+	 * Any that we processed in the previous loop will not be negative.
+	 */
+	if (!found) {
+		for (i = 0; i < ppmu->n_counter; ++i) {
+			if (is_limited_pmc(i + 1))
+				continue;
+			val = read_pmc(i + 1);
+			if (pmc_overflow(val))
+				write_pmc(i + 1, 0);
+		}
+	}
+
+	/*
+	 * Reset MMCR0 to its normal value.  This will set PMXE and
+	 * clear FC (freeze counters) and PMAO (perf mon alert occurred)
+	 * and thus allow interrupts to occur again.
+	 * XXX might want to use MSR.PM to keep the events frozen until
+	 * we get back out of this interrupt.
+	 */
+	write_mmcr0(cpuhw, cpuhw->mmcr[0]);
+
+	if (nmi)
+		nmi_exit();
+	else
+		irq_exit();
+}
+
+static void power_pmu_setup(int cpu)
+{
+	struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
+
+	if (!ppmu)
+		return;
+	memset(cpuhw, 0, sizeof(*cpuhw));
+	cpuhw->mmcr[0] = MMCR0_FC;
+}
+
+static int __cpuinit
+power_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (long)hcpu;
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_UP_PREPARE:
+		power_pmu_setup(cpu);
+		break;
+
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+int __cpuinit register_power_pmu(struct power_pmu *pmu)
+{
+	if (ppmu)
+		return -EBUSY;		/* something's already registered */
+
+	ppmu = pmu;
+	pr_info("%s performance monitor hardware support registered\n",
+		pmu->name);
+
+#ifdef MSR_HV
+	/*
+	 * Use FCHV to ignore kernel events if MSR.HV is set.
+	 */
+	if (mfmsr() & MSR_HV)
+		freeze_events_kernel = MMCR0_FCHV;
+#endif /* CONFIG_PPC64 */
+
+	perf_pmu_register(&power_pmu, "cpu", PERF_TYPE_RAW);
+	perf_cpu_notifier(power_pmu_notifier);
+
+	return 0;
+}
diff --git a/arch/powerpc/kernel/perf_event_fsl_emb.c b/arch/powerpc/perf/core-fsl-emb.c
similarity index 100%
rename from arch/powerpc/kernel/perf_event_fsl_emb.c
rename to arch/powerpc/perf/core-fsl-emb.c
diff --git a/arch/powerpc/kernel/e500-pmu.c b/arch/powerpc/perf/e500-pmu.c
similarity index 100%
rename from arch/powerpc/kernel/e500-pmu.c
rename to arch/powerpc/perf/e500-pmu.c
diff --git a/arch/powerpc/kernel/mpc7450-pmu.c b/arch/powerpc/perf/mpc7450-pmu.c
similarity index 100%
rename from arch/powerpc/kernel/mpc7450-pmu.c
rename to arch/powerpc/perf/mpc7450-pmu.c
diff --git a/arch/powerpc/perf/power4-pmu.c b/arch/powerpc/perf/power4-pmu.c
new file mode 100644
index 0000000..9103a1d
--- /dev/null
+++ b/arch/powerpc/perf/power4-pmu.c
@@ -0,0 +1,622 @@
+/*
+ * Performance counter support for POWER4 (GP) and POWER4+ (GQ) processors.
+ *
+ * Copyright 2009 Paul Mackerras, 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.
+ */
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/string.h>
+#include <asm/reg.h>
+#include <asm/cputable.h>
+
+/*
+ * Bits in event code for POWER4
+ */
+#define PM_PMC_SH	12	/* PMC number (1-based) for direct events */
+#define PM_PMC_MSK	0xf
+#define PM_UNIT_SH	8	/* TTMMUX number and setting - unit select */
+#define PM_UNIT_MSK	0xf
+#define PM_LOWER_SH	6
+#define PM_LOWER_MSK	1
+#define PM_LOWER_MSKS	0x40
+#define PM_BYTE_SH	4	/* Byte number of event bus to use */
+#define PM_BYTE_MSK	3
+#define PM_PMCSEL_MSK	7
+
+/*
+ * Unit code values
+ */
+#define PM_FPU		1
+#define PM_ISU1		2
+#define PM_IFU		3
+#define PM_IDU0		4
+#define PM_ISU1_ALT	6
+#define PM_ISU2		7
+#define PM_IFU_ALT	8
+#define PM_LSU0		9
+#define PM_LSU1		0xc
+#define PM_GPS		0xf
+
+/*
+ * Bits in MMCR0 for POWER4
+ */
+#define MMCR0_PMC1SEL_SH	8
+#define MMCR0_PMC2SEL_SH	1
+#define MMCR_PMCSEL_MSK		0x1f
+
+/*
+ * Bits in MMCR1 for POWER4
+ */
+#define MMCR1_TTM0SEL_SH	62
+#define MMCR1_TTC0SEL_SH	61
+#define MMCR1_TTM1SEL_SH	59
+#define MMCR1_TTC1SEL_SH	58
+#define MMCR1_TTM2SEL_SH	56
+#define MMCR1_TTC2SEL_SH	55
+#define MMCR1_TTM3SEL_SH	53
+#define MMCR1_TTC3SEL_SH	52
+#define MMCR1_TTMSEL_MSK	3
+#define MMCR1_TD_CP_DBG0SEL_SH	50
+#define MMCR1_TD_CP_DBG1SEL_SH	48
+#define MMCR1_TD_CP_DBG2SEL_SH	46
+#define MMCR1_TD_CP_DBG3SEL_SH	44
+#define MMCR1_DEBUG0SEL_SH	43
+#define MMCR1_DEBUG1SEL_SH	42
+#define MMCR1_DEBUG2SEL_SH	41
+#define MMCR1_DEBUG3SEL_SH	40
+#define MMCR1_PMC1_ADDER_SEL_SH	39
+#define MMCR1_PMC2_ADDER_SEL_SH	38
+#define MMCR1_PMC6_ADDER_SEL_SH	37
+#define MMCR1_PMC5_ADDER_SEL_SH	36
+#define MMCR1_PMC8_ADDER_SEL_SH	35
+#define MMCR1_PMC7_ADDER_SEL_SH	34
+#define MMCR1_PMC3_ADDER_SEL_SH	33
+#define MMCR1_PMC4_ADDER_SEL_SH	32
+#define MMCR1_PMC3SEL_SH	27
+#define MMCR1_PMC4SEL_SH	22
+#define MMCR1_PMC5SEL_SH	17
+#define MMCR1_PMC6SEL_SH	12
+#define MMCR1_PMC7SEL_SH	7
+#define MMCR1_PMC8SEL_SH	2	/* note bit 0 is in MMCRA for GP */
+
+static short mmcr1_adder_bits[8] = {
+	MMCR1_PMC1_ADDER_SEL_SH,
+	MMCR1_PMC2_ADDER_SEL_SH,
+	MMCR1_PMC3_ADDER_SEL_SH,
+	MMCR1_PMC4_ADDER_SEL_SH,
+	MMCR1_PMC5_ADDER_SEL_SH,
+	MMCR1_PMC6_ADDER_SEL_SH,
+	MMCR1_PMC7_ADDER_SEL_SH,
+	MMCR1_PMC8_ADDER_SEL_SH
+};
+
+/*
+ * Bits in MMCRA
+ */
+#define MMCRA_PMC8SEL0_SH	17	/* PMC8SEL bit 0 for GP */
+
+/*
+ * Layout of constraint bits:
+ * 6666555555555544444444443333333333222222222211111111110000000000
+ * 3210987654321098765432109876543210987654321098765432109876543210
+ *        |[  >[  >[   >|||[  >[  ><  ><  ><  ><  ><><><><><><><><>
+ *        | UC1 UC2 UC3 ||| PS1 PS2 B0  B1  B2  B3 P1P2P3P4P5P6P7P8
+ * 	  \SMPL	        ||\TTC3SEL
+ * 		        |\TTC_IFU_SEL
+ * 		        \TTM2SEL0
+ *
+ * SMPL - SAMPLE_ENABLE constraint
+ *     56: SAMPLE_ENABLE value 0x0100_0000_0000_0000
+ *
+ * UC1 - unit constraint 1: can't have all three of FPU/ISU1/IDU0|ISU2
+ *     55: UC1 error 0x0080_0000_0000_0000
+ *     54: FPU events needed 0x0040_0000_0000_0000
+ *     53: ISU1 events needed 0x0020_0000_0000_0000
+ *     52: IDU0|ISU2 events needed 0x0010_0000_0000_0000
+ *
+ * UC2 - unit constraint 2: can't have all three of FPU/IFU/LSU0
+ *     51: UC2 error 0x0008_0000_0000_0000
+ *     50: FPU events needed 0x0004_0000_0000_0000
+ *     49: IFU events needed 0x0002_0000_0000_0000
+ *     48: LSU0 events needed 0x0001_0000_0000_0000
+ *
+ * UC3 - unit constraint 3: can't have all four of LSU0/IFU/IDU0|ISU2/ISU1
+ *     47: UC3 error 0x8000_0000_0000
+ *     46: LSU0 events needed 0x4000_0000_0000
+ *     45: IFU events needed 0x2000_0000_0000
+ *     44: IDU0|ISU2 events needed 0x1000_0000_0000
+ *     43: ISU1 events needed 0x0800_0000_0000
+ *
+ * TTM2SEL0
+ *     42: 0 = IDU0 events needed
+ *     	   1 = ISU2 events needed 0x0400_0000_0000
+ *
+ * TTC_IFU_SEL
+ *     41: 0 = IFU.U events needed
+ *     	   1 = IFU.L events needed 0x0200_0000_0000
+ *
+ * TTC3SEL
+ *     40: 0 = LSU1.U events needed
+ *     	   1 = LSU1.L events needed 0x0100_0000_0000
+ *
+ * PS1
+ *     39: PS1 error 0x0080_0000_0000
+ *     36-38: count of events needing PMC1/2/5/6 0x0070_0000_0000
+ *
+ * PS2
+ *     35: PS2 error 0x0008_0000_0000
+ *     32-34: count of events needing PMC3/4/7/8 0x0007_0000_0000
+ *
+ * B0
+ *     28-31: Byte 0 event source 0xf000_0000
+ *     	   1 = FPU
+ * 	   2 = ISU1
+ * 	   3 = IFU
+ * 	   4 = IDU0
+ * 	   7 = ISU2
+ * 	   9 = LSU0
+ * 	   c = LSU1
+ * 	   f = GPS
+ *
+ * B1, B2, B3
+ *     24-27, 20-23, 16-19: Byte 1, 2, 3 event sources
+ *
+ * P8
+ *     15: P8 error 0x8000
+ *     14-15: Count of events needing PMC8
+ *
+ * P1..P7
+ *     0-13: Count of events needing PMC1..PMC7
+ *
+ * Note: this doesn't allow events using IFU.U to be combined with events
+ * using IFU.L, though that is feasible (using TTM0 and TTM2).  However
+ * there are no listed events for IFU.L (they are debug events not
+ * verified for performance monitoring) so this shouldn't cause a
+ * problem.
+ */
+
+static struct unitinfo {
+	unsigned long	value, mask;
+	int		unit;
+	int		lowerbit;
+} p4_unitinfo[16] = {
+	[PM_FPU]  = { 0x44000000000000ul, 0x88000000000000ul, PM_FPU, 0 },
+	[PM_ISU1] = { 0x20080000000000ul, 0x88000000000000ul, PM_ISU1, 0 },
+	[PM_ISU1_ALT] =
+		    { 0x20080000000000ul, 0x88000000000000ul, PM_ISU1, 0 },
+	[PM_IFU]  = { 0x02200000000000ul, 0x08820000000000ul, PM_IFU, 41 },
+	[PM_IFU_ALT] =
+		    { 0x02200000000000ul, 0x08820000000000ul, PM_IFU, 41 },
+	[PM_IDU0] = { 0x10100000000000ul, 0x80840000000000ul, PM_IDU0, 1 },
+	[PM_ISU2] = { 0x10140000000000ul, 0x80840000000000ul, PM_ISU2, 0 },
+	[PM_LSU0] = { 0x01400000000000ul, 0x08800000000000ul, PM_LSU0, 0 },
+	[PM_LSU1] = { 0x00000000000000ul, 0x00010000000000ul, PM_LSU1, 40 },
+	[PM_GPS]  = { 0x00000000000000ul, 0x00000000000000ul, PM_GPS, 0 }
+};
+
+static unsigned char direct_marked_event[8] = {
+	(1<<2) | (1<<3),	/* PMC1: PM_MRK_GRP_DISP, PM_MRK_ST_CMPL */
+	(1<<3) | (1<<5),	/* PMC2: PM_THRESH_TIMEO, PM_MRK_BRU_FIN */
+	(1<<3),			/* PMC3: PM_MRK_ST_CMPL_INT */
+	(1<<4) | (1<<5),	/* PMC4: PM_MRK_GRP_CMPL, PM_MRK_CRU_FIN */
+	(1<<4) | (1<<5),	/* PMC5: PM_MRK_GRP_TIMEO */
+	(1<<3) | (1<<4) | (1<<5),
+		/* PMC6: PM_MRK_ST_GPS, PM_MRK_FXU_FIN, PM_MRK_GRP_ISSUED */
+	(1<<4) | (1<<5),	/* PMC7: PM_MRK_FPU_FIN, PM_MRK_INST_FIN */
+	(1<<4),			/* PMC8: PM_MRK_LSU_FIN */
+};
+
+/*
+ * Returns 1 if event counts things relating to marked instructions
+ * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
+ */
+static int p4_marked_instr_event(u64 event)
+{
+	int pmc, psel, unit, byte, bit;
+	unsigned int mask;
+
+	pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+	psel = event & PM_PMCSEL_MSK;
+	if (pmc) {
+		if (direct_marked_event[pmc - 1] & (1 << psel))
+			return 1;
+		if (psel == 0)		/* add events */
+			bit = (pmc <= 4)? pmc - 1: 8 - pmc;
+		else if (psel == 6)	/* decode events */
+			bit = 4;
+		else
+			return 0;
+	} else
+		bit = psel;
+
+	byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+	unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+	mask = 0;
+	switch (unit) {
+	case PM_LSU1:
+		if (event & PM_LOWER_MSKS)
+			mask = 1 << 28;		/* byte 7 bit 4 */
+		else
+			mask = 6 << 24;		/* byte 3 bits 1 and 2 */
+		break;
+	case PM_LSU0:
+		/* byte 3, bit 3; byte 2 bits 0,2,3,4,5; byte 1 */
+		mask = 0x083dff00;
+	}
+	return (mask >> (byte * 8 + bit)) & 1;
+}
+
+static int p4_get_constraint(u64 event, unsigned long *maskp,
+			     unsigned long *valp)
+{
+	int pmc, byte, unit, lower, sh;
+	unsigned long mask = 0, value = 0;
+	int grp = -1;
+
+	pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+	if (pmc) {
+		if (pmc > 8)
+			return -1;
+		sh = (pmc - 1) * 2;
+		mask |= 2 << sh;
+		value |= 1 << sh;
+		grp = ((pmc - 1) >> 1) & 1;
+	}
+	unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+	byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+	if (unit) {
+		lower = (event >> PM_LOWER_SH) & PM_LOWER_MSK;
+
+		/*
+		 * Bus events on bytes 0 and 2 can be counted
+		 * on PMC1/2/5/6; bytes 1 and 3 on PMC3/4/7/8.
+		 */
+		if (!pmc)
+			grp = byte & 1;
+
+		if (!p4_unitinfo[unit].unit)
+			return -1;
+		mask  |= p4_unitinfo[unit].mask;
+		value |= p4_unitinfo[unit].value;
+		sh = p4_unitinfo[unit].lowerbit;
+		if (sh > 1)
+			value |= (unsigned long)lower << sh;
+		else if (lower != sh)
+			return -1;
+		unit = p4_unitinfo[unit].unit;
+
+		/* Set byte lane select field */
+		mask  |= 0xfULL << (28 - 4 * byte);
+		value |= (unsigned long)unit << (28 - 4 * byte);
+	}
+	if (grp == 0) {
+		/* increment PMC1/2/5/6 field */
+		mask  |= 0x8000000000ull;
+		value |= 0x1000000000ull;
+	} else {
+		/* increment PMC3/4/7/8 field */
+		mask  |= 0x800000000ull;
+		value |= 0x100000000ull;
+	}
+
+	/* Marked instruction events need sample_enable set */
+	if (p4_marked_instr_event(event)) {
+		mask  |= 1ull << 56;
+		value |= 1ull << 56;
+	}
+
+	/* PMCSEL=6 decode events on byte 2 need sample_enable clear */
+	if (pmc && (event & PM_PMCSEL_MSK) == 6 && byte == 2)
+		mask  |= 1ull << 56;
+
+	*maskp = mask;
+	*valp = value;
+	return 0;
+}
+
+static unsigned int ppc_inst_cmpl[] = {
+	0x1001, 0x4001, 0x6001, 0x7001, 0x8001
+};
+
+static int p4_get_alternatives(u64 event, unsigned int flags, u64 alt[])
+{
+	int i, j, na;
+
+	alt[0] = event;
+	na = 1;
+
+	/* 2 possibilities for PM_GRP_DISP_REJECT */
+	if (event == 0x8003 || event == 0x0224) {
+		alt[1] = event ^ (0x8003 ^ 0x0224);
+		return 2;
+	}
+
+	/* 2 possibilities for PM_ST_MISS_L1 */
+	if (event == 0x0c13 || event == 0x0c23) {
+		alt[1] = event ^ (0x0c13 ^ 0x0c23);
+		return 2;
+	}
+
+	/* several possibilities for PM_INST_CMPL */
+	for (i = 0; i < ARRAY_SIZE(ppc_inst_cmpl); ++i) {
+		if (event == ppc_inst_cmpl[i]) {
+			for (j = 0; j < ARRAY_SIZE(ppc_inst_cmpl); ++j)
+				if (j != i)
+					alt[na++] = ppc_inst_cmpl[j];
+			break;
+		}
+	}
+
+	return na;
+}
+
+static int p4_compute_mmcr(u64 event[], int n_ev,
+			   unsigned int hwc[], unsigned long mmcr[])
+{
+	unsigned long mmcr0 = 0, mmcr1 = 0, mmcra = 0;
+	unsigned int pmc, unit, byte, psel, lower;
+	unsigned int ttm, grp;
+	unsigned int pmc_inuse = 0;
+	unsigned int pmc_grp_use[2];
+	unsigned char busbyte[4];
+	unsigned char unituse[16];
+	unsigned int unitlower = 0;
+	int i;
+
+	if (n_ev > 8)
+		return -1;
+
+	/* First pass to count resource use */
+	pmc_grp_use[0] = pmc_grp_use[1] = 0;
+	memset(busbyte, 0, sizeof(busbyte));
+	memset(unituse, 0, sizeof(unituse));
+	for (i = 0; i < n_ev; ++i) {
+		pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+		if (pmc) {
+			if (pmc_inuse & (1 << (pmc - 1)))
+				return -1;
+			pmc_inuse |= 1 << (pmc - 1);
+			/* count 1/2/5/6 vs 3/4/7/8 use */
+			++pmc_grp_use[((pmc - 1) >> 1) & 1];
+		}
+		unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
+		byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
+		lower = (event[i] >> PM_LOWER_SH) & PM_LOWER_MSK;
+		if (unit) {
+			if (!pmc)
+				++pmc_grp_use[byte & 1];
+			if (unit == 6 || unit == 8)
+				/* map alt ISU1/IFU codes: 6->2, 8->3 */
+				unit = (unit >> 1) - 1;
+			if (busbyte[byte] && busbyte[byte] != unit)
+				return -1;
+			busbyte[byte] = unit;
+			lower <<= unit;
+			if (unituse[unit] && lower != (unitlower & lower))
+				return -1;
+			unituse[unit] = 1;
+			unitlower |= lower;
+		}
+	}
+	if (pmc_grp_use[0] > 4 || pmc_grp_use[1] > 4)
+		return -1;
+
+	/*
+	 * Assign resources and set multiplexer selects.
+	 *
+	 * Units 1,2,3 are on TTM0, 4,6,7 on TTM1, 8,10 on TTM2.
+	 * Each TTMx can only select one unit, but since
+	 * units 2 and 6 are both ISU1, and 3 and 8 are both IFU,
+	 * we have some choices.
+	 */
+	if (unituse[2] & (unituse[1] | (unituse[3] & unituse[9]))) {
+		unituse[6] = 1;		/* Move 2 to 6 */
+		unituse[2] = 0;
+	}
+	if (unituse[3] & (unituse[1] | unituse[2])) {
+		unituse[8] = 1;		/* Move 3 to 8 */
+		unituse[3] = 0;
+		unitlower = (unitlower & ~8) | ((unitlower & 8) << 5);
+	}
+	/* Check only one unit per TTMx */
+	if (unituse[1] + unituse[2] + unituse[3] > 1 ||
+	    unituse[4] + unituse[6] + unituse[7] > 1 ||
+	    unituse[8] + unituse[9] > 1 ||
+	    (unituse[5] | unituse[10] | unituse[11] |
+	     unituse[13] | unituse[14]))
+		return -1;
+
+	/* Set TTMxSEL fields.  Note, units 1-3 => TTM0SEL codes 0-2 */
+	mmcr1 |= (unsigned long)(unituse[3] * 2 + unituse[2])
+		<< MMCR1_TTM0SEL_SH;
+	mmcr1 |= (unsigned long)(unituse[7] * 3 + unituse[6] * 2)
+		<< MMCR1_TTM1SEL_SH;
+	mmcr1 |= (unsigned long)unituse[9] << MMCR1_TTM2SEL_SH;
+
+	/* Set TTCxSEL fields. */
+	if (unitlower & 0xe)
+		mmcr1 |= 1ull << MMCR1_TTC0SEL_SH;
+	if (unitlower & 0xf0)
+		mmcr1 |= 1ull << MMCR1_TTC1SEL_SH;
+	if (unitlower & 0xf00)
+		mmcr1 |= 1ull << MMCR1_TTC2SEL_SH;
+	if (unitlower & 0x7000)
+		mmcr1 |= 1ull << MMCR1_TTC3SEL_SH;
+
+	/* Set byte lane select fields. */
+	for (byte = 0; byte < 4; ++byte) {
+		unit = busbyte[byte];
+		if (!unit)
+			continue;
+		if (unit == 0xf) {
+			/* special case for GPS */
+			mmcr1 |= 1ull << (MMCR1_DEBUG0SEL_SH - byte);
+		} else {
+			if (!unituse[unit])
+				ttm = unit - 1;		/* 2->1, 3->2 */
+			else
+				ttm = unit >> 2;
+			mmcr1 |= (unsigned long)ttm
+				<< (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
+		}
+	}
+
+	/* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
+	for (i = 0; i < n_ev; ++i) {
+		pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+		unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
+		byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
+		psel = event[i] & PM_PMCSEL_MSK;
+		if (!pmc) {
+			/* Bus event or 00xxx direct event (off or cycles) */
+			if (unit)
+				psel |= 0x10 | ((byte & 2) << 2);
+			for (pmc = 0; pmc < 8; ++pmc) {
+				if (pmc_inuse & (1 << pmc))
+					continue;
+				grp = (pmc >> 1) & 1;
+				if (unit) {
+					if (grp == (byte & 1))
+						break;
+				} else if (pmc_grp_use[grp] < 4) {
+					++pmc_grp_use[grp];
+					break;
+				}
+			}
+			pmc_inuse |= 1 << pmc;
+		} else {
+			/* Direct event */
+			--pmc;
+			if (psel == 0 && (byte & 2))
+				/* add events on higher-numbered bus */
+				mmcr1 |= 1ull << mmcr1_adder_bits[pmc];
+			else if (psel == 6 && byte == 3)
+				/* seem to need to set sample_enable here */
+				mmcra |= MMCRA_SAMPLE_ENABLE;
+			psel |= 8;
+		}
+		if (pmc <= 1)
+			mmcr0 |= psel << (MMCR0_PMC1SEL_SH - 7 * pmc);
+		else
+			mmcr1 |= psel << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2));
+		if (pmc == 7)	/* PMC8 */
+			mmcra |= (psel & 1) << MMCRA_PMC8SEL0_SH;
+		hwc[i] = pmc;
+		if (p4_marked_instr_event(event[i]))
+			mmcra |= MMCRA_SAMPLE_ENABLE;
+	}
+
+	if (pmc_inuse & 1)
+		mmcr0 |= MMCR0_PMC1CE;
+	if (pmc_inuse & 0xfe)
+		mmcr0 |= MMCR0_PMCjCE;
+
+	mmcra |= 0x2000;	/* mark only one IOP per PPC instruction */
+
+	/* Return MMCRx values */
+	mmcr[0] = mmcr0;
+	mmcr[1] = mmcr1;
+	mmcr[2] = mmcra;
+	return 0;
+}
+
+static void p4_disable_pmc(unsigned int pmc, unsigned long mmcr[])
+{
+	/*
+	 * Setting the PMCxSEL field to 0 disables PMC x.
+	 * (Note that pmc is 0-based here, not 1-based.)
+	 */
+	if (pmc <= 1) {
+		mmcr[0] &= ~(0x1fUL << (MMCR0_PMC1SEL_SH - 7 * pmc));
+	} else {
+		mmcr[1] &= ~(0x1fUL << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2)));
+		if (pmc == 7)
+			mmcr[2] &= ~(1UL << MMCRA_PMC8SEL0_SH);
+	}
+}
+
+static int p4_generic_events[] = {
+	[PERF_COUNT_HW_CPU_CYCLES]		= 7,
+	[PERF_COUNT_HW_INSTRUCTIONS]		= 0x1001,
+	[PERF_COUNT_HW_CACHE_REFERENCES]	= 0x8c10, /* PM_LD_REF_L1 */
+	[PERF_COUNT_HW_CACHE_MISSES]		= 0x3c10, /* PM_LD_MISS_L1 */
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= 0x330,  /* PM_BR_ISSUED */
+	[PERF_COUNT_HW_BRANCH_MISSES]		= 0x331,  /* PM_BR_MPRED_CR */
+};
+
+#define C(x)	PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ */
+static int power4_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+	[C(L1D)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0x8c10,		0x3c10	},
+		[C(OP_WRITE)] = {	0x7c10,		0xc13	},
+		[C(OP_PREFETCH)] = {	0xc35,		0	},
+	},
+	[C(L1I)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0,		0	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	0,		0	},
+	},
+	[C(LL)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0,		0	},
+		[C(OP_WRITE)] = {	0,		0	},
+		[C(OP_PREFETCH)] = {	0xc34,		0	},
+	},
+	[C(DTLB)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0,		0x904	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	-1,		-1	},
+	},
+	[C(ITLB)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0,		0x900	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	-1,		-1	},
+	},
+	[C(BPU)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0x330,		0x331	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	-1,		-1	},
+	},
+	[C(NODE)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	-1,		-1	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	-1,		-1	},
+	},
+};
+
+static struct power_pmu power4_pmu = {
+	.name			= "POWER4/4+",
+	.n_counter		= 8,
+	.max_alternatives	= 5,
+	.add_fields		= 0x0000001100005555ul,
+	.test_adder		= 0x0011083300000000ul,
+	.compute_mmcr		= p4_compute_mmcr,
+	.get_constraint		= p4_get_constraint,
+	.get_alternatives	= p4_get_alternatives,
+	.disable_pmc		= p4_disable_pmc,
+	.n_generic		= ARRAY_SIZE(p4_generic_events),
+	.generic_events		= p4_generic_events,
+	.cache_events		= &power4_cache_events,
+	.flags			= PPMU_NO_SIPR | PPMU_NO_CONT_SAMPLING,
+};
+
+static int __init init_power4_pmu(void)
+{
+	if (!cur_cpu_spec->oprofile_cpu_type ||
+	    strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power4"))
+		return -ENODEV;
+
+	return register_power_pmu(&power4_pmu);
+}
+
+early_initcall(init_power4_pmu);
diff --git a/arch/powerpc/kernel/power5+-pmu.c b/arch/powerpc/perf/power5+-pmu.c
similarity index 100%
rename from arch/powerpc/kernel/power5+-pmu.c
rename to arch/powerpc/perf/power5+-pmu.c
diff --git a/arch/powerpc/kernel/power5-pmu.c b/arch/powerpc/perf/power5-pmu.c
similarity index 100%
rename from arch/powerpc/kernel/power5-pmu.c
rename to arch/powerpc/perf/power5-pmu.c
diff --git a/arch/powerpc/perf/power6-pmu.c b/arch/powerpc/perf/power6-pmu.c
new file mode 100644
index 0000000..31128e0
--- /dev/null
+++ b/arch/powerpc/perf/power6-pmu.c
@@ -0,0 +1,552 @@
+/*
+ * Performance counter support for POWER6 processors.
+ *
+ * Copyright 2008-2009 Paul Mackerras, 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.
+ */
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/string.h>
+#include <asm/reg.h>
+#include <asm/cputable.h>
+
+/*
+ * Bits in event code for POWER6
+ */
+#define PM_PMC_SH	20	/* PMC number (1-based) for direct events */
+#define PM_PMC_MSK	0x7
+#define PM_PMC_MSKS	(PM_PMC_MSK << PM_PMC_SH)
+#define PM_UNIT_SH	16	/* Unit event comes (TTMxSEL encoding) */
+#define PM_UNIT_MSK	0xf
+#define PM_UNIT_MSKS	(PM_UNIT_MSK << PM_UNIT_SH)
+#define PM_LLAV		0x8000	/* Load lookahead match value */
+#define PM_LLA		0x4000	/* Load lookahead match enable */
+#define PM_BYTE_SH	12	/* Byte of event bus to use */
+#define PM_BYTE_MSK	3
+#define PM_SUBUNIT_SH	8	/* Subunit event comes from (NEST_SEL enc.) */
+#define PM_SUBUNIT_MSK	7
+#define PM_SUBUNIT_MSKS	(PM_SUBUNIT_MSK << PM_SUBUNIT_SH)
+#define PM_PMCSEL_MSK	0xff	/* PMCxSEL value */
+#define PM_BUSEVENT_MSK	0xf3700
+
+/*
+ * Bits in MMCR1 for POWER6
+ */
+#define MMCR1_TTM0SEL_SH	60
+#define MMCR1_TTMSEL_SH(n)	(MMCR1_TTM0SEL_SH - (n) * 4)
+#define MMCR1_TTMSEL_MSK	0xf
+#define MMCR1_TTMSEL(m, n)	(((m) >> MMCR1_TTMSEL_SH(n)) & MMCR1_TTMSEL_MSK)
+#define MMCR1_NESTSEL_SH	45
+#define MMCR1_NESTSEL_MSK	0x7
+#define MMCR1_NESTSEL(m)	(((m) >> MMCR1_NESTSEL_SH) & MMCR1_NESTSEL_MSK)
+#define MMCR1_PMC1_LLA		(1ul << 44)
+#define MMCR1_PMC1_LLA_VALUE	(1ul << 39)
+#define MMCR1_PMC1_ADDR_SEL	(1ul << 35)
+#define MMCR1_PMC1SEL_SH	24
+#define MMCR1_PMCSEL_SH(n)	(MMCR1_PMC1SEL_SH - (n) * 8)
+#define MMCR1_PMCSEL_MSK	0xff
+
+/*
+ * Map of which direct events on which PMCs are marked instruction events.
+ * Indexed by PMCSEL value >> 1.
+ * Bottom 4 bits are a map of which PMCs are interesting,
+ * top 4 bits say what sort of event:
+ *   0 = direct marked event,
+ *   1 = byte decode event,
+ *   4 = add/and event (PMC1 -> bits 0 & 4),
+ *   5 = add/and event (PMC1 -> bits 1 & 5),
+ *   6 = add/and event (PMC1 -> bits 2 & 6),
+ *   7 = add/and event (PMC1 -> bits 3 & 7).
+ */
+static unsigned char direct_event_is_marked[0x60 >> 1] = {
+	0,	/* 00 */
+	0,	/* 02 */
+	0,	/* 04 */
+	0x07,	/* 06 PM_MRK_ST_CMPL, PM_MRK_ST_GPS, PM_MRK_ST_CMPL_INT */
+	0x04,	/* 08 PM_MRK_DFU_FIN */
+	0x06,	/* 0a PM_MRK_IFU_FIN, PM_MRK_INST_FIN */
+	0,	/* 0c */
+	0,	/* 0e */
+	0x02,	/* 10 PM_MRK_INST_DISP */
+	0x08,	/* 12 PM_MRK_LSU_DERAT_MISS */
+	0,	/* 14 */
+	0,	/* 16 */
+	0x0c,	/* 18 PM_THRESH_TIMEO, PM_MRK_INST_FIN */
+	0x0f,	/* 1a PM_MRK_INST_DISP, PM_MRK_{FXU,FPU,LSU}_FIN */
+	0x01,	/* 1c PM_MRK_INST_ISSUED */
+	0,	/* 1e */
+	0,	/* 20 */
+	0,	/* 22 */
+	0,	/* 24 */
+	0,	/* 26 */
+	0x15,	/* 28 PM_MRK_DATA_FROM_L2MISS, PM_MRK_DATA_FROM_L3MISS */
+	0,	/* 2a */
+	0,	/* 2c */
+	0,	/* 2e */
+	0x4f,	/* 30 */
+	0x7f,	/* 32 */
+	0x4f,	/* 34 */
+	0x5f,	/* 36 */
+	0x6f,	/* 38 */
+	0x4f,	/* 3a */
+	0,	/* 3c */
+	0x08,	/* 3e PM_MRK_INST_TIMEO */
+	0x1f,	/* 40 */
+	0x1f,	/* 42 */
+	0x1f,	/* 44 */
+	0x1f,	/* 46 */
+	0x1f,	/* 48 */
+	0x1f,	/* 4a */
+	0x1f,	/* 4c */
+	0x1f,	/* 4e */
+	0,	/* 50 */
+	0x05,	/* 52 PM_MRK_BR_TAKEN, PM_MRK_BR_MPRED */
+	0x1c,	/* 54 PM_MRK_PTEG_FROM_L3MISS, PM_MRK_PTEG_FROM_L2MISS */
+	0x02,	/* 56 PM_MRK_LD_MISS_L1 */
+	0,	/* 58 */
+	0,	/* 5a */
+	0,	/* 5c */
+	0,	/* 5e */
+};
+
+/*
+ * Masks showing for each unit which bits are marked events.
+ * These masks are in LE order, i.e. 0x00000001 is byte 0, bit 0.
+ */
+static u32 marked_bus_events[16] = {
+	0x01000000,	/* direct events set 1: byte 3 bit 0 */
+	0x00010000,	/* direct events set 2: byte 2 bit 0 */
+	0, 0, 0, 0,	/* IDU, IFU, nest: nothing */
+	0x00000088,	/* VMX set 1: byte 0 bits 3, 7 */
+	0x000000c0,	/* VMX set 2: byte 0 bits 4-7 */
+	0x04010000,	/* LSU set 1: byte 2 bit 0, byte 3 bit 2 */
+	0xff010000u,	/* LSU set 2: byte 2 bit 0, all of byte 3 */
+	0,		/* LSU set 3 */
+	0x00000010,	/* VMX set 3: byte 0 bit 4 */
+	0,		/* BFP set 1 */
+	0x00000022,	/* BFP set 2: byte 0 bits 1, 5 */
+	0, 0
+};
+
+/*
+ * Returns 1 if event counts things relating to marked instructions
+ * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
+ */
+static int power6_marked_instr_event(u64 event)
+{
+	int pmc, psel, ptype;
+	int bit, byte, unit;
+	u32 mask;
+
+	pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+	psel = (event & PM_PMCSEL_MSK) >> 1;	/* drop edge/level bit */
+	if (pmc >= 5)
+		return 0;
+
+	bit = -1;
+	if (psel < sizeof(direct_event_is_marked)) {
+		ptype = direct_event_is_marked[psel];
+		if (pmc == 0 || !(ptype & (1 << (pmc - 1))))
+			return 0;
+		ptype >>= 4;
+		if (ptype == 0)
+			return 1;
+		if (ptype == 1)
+			bit = 0;
+		else
+			bit = ptype ^ (pmc - 1);
+	} else if ((psel & 0x48) == 0x40)
+		bit = psel & 7;
+
+	if (!(event & PM_BUSEVENT_MSK) || bit == -1)
+		return 0;
+
+	byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+	unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+	mask = marked_bus_events[unit];
+	return (mask >> (byte * 8 + bit)) & 1;
+}
+
+/*
+ * Assign PMC numbers and compute MMCR1 value for a set of events
+ */
+static int p6_compute_mmcr(u64 event[], int n_ev,
+			   unsigned int hwc[], unsigned long mmcr[])
+{
+	unsigned long mmcr1 = 0;
+	unsigned long mmcra = MMCRA_SDAR_DCACHE_MISS | MMCRA_SDAR_ERAT_MISS;
+	int i;
+	unsigned int pmc, ev, b, u, s, psel;
+	unsigned int ttmset = 0;
+	unsigned int pmc_inuse = 0;
+
+	if (n_ev > 6)
+		return -1;
+	for (i = 0; i < n_ev; ++i) {
+		pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+		if (pmc) {
+			if (pmc_inuse & (1 << (pmc - 1)))
+				return -1;	/* collision! */
+			pmc_inuse |= 1 << (pmc - 1);
+		}
+	}
+	for (i = 0; i < n_ev; ++i) {
+		ev = event[i];
+		pmc = (ev >> PM_PMC_SH) & PM_PMC_MSK;
+		if (pmc) {
+			--pmc;
+		} else {
+			/* can go on any PMC; find a free one */
+			for (pmc = 0; pmc < 4; ++pmc)
+				if (!(pmc_inuse & (1 << pmc)))
+					break;
+			if (pmc >= 4)
+				return -1;
+			pmc_inuse |= 1 << pmc;
+		}
+		hwc[i] = pmc;
+		psel = ev & PM_PMCSEL_MSK;
+		if (ev & PM_BUSEVENT_MSK) {
+			/* this event uses the event bus */
+			b = (ev >> PM_BYTE_SH) & PM_BYTE_MSK;
+			u = (ev >> PM_UNIT_SH) & PM_UNIT_MSK;
+			/* check for conflict on this byte of event bus */
+			if ((ttmset & (1 << b)) && MMCR1_TTMSEL(mmcr1, b) != u)
+				return -1;
+			mmcr1 |= (unsigned long)u << MMCR1_TTMSEL_SH(b);
+			ttmset |= 1 << b;
+			if (u == 5) {
+				/* Nest events have a further mux */
+				s = (ev >> PM_SUBUNIT_SH) & PM_SUBUNIT_MSK;
+				if ((ttmset & 0x10) &&
+				    MMCR1_NESTSEL(mmcr1) != s)
+					return -1;
+				ttmset |= 0x10;
+				mmcr1 |= (unsigned long)s << MMCR1_NESTSEL_SH;
+			}
+			if (0x30 <= psel && psel <= 0x3d) {
+				/* these need the PMCx_ADDR_SEL bits */
+				if (b >= 2)
+					mmcr1 |= MMCR1_PMC1_ADDR_SEL >> pmc;
+			}
+			/* bus select values are different for PMC3/4 */
+			if (pmc >= 2 && (psel & 0x90) == 0x80)
+				psel ^= 0x20;
+		}
+		if (ev & PM_LLA) {
+			mmcr1 |= MMCR1_PMC1_LLA >> pmc;
+			if (ev & PM_LLAV)
+				mmcr1 |= MMCR1_PMC1_LLA_VALUE >> pmc;
+		}
+		if (power6_marked_instr_event(event[i]))
+			mmcra |= MMCRA_SAMPLE_ENABLE;
+		if (pmc < 4)
+			mmcr1 |= (unsigned long)psel << MMCR1_PMCSEL_SH(pmc);
+	}
+	mmcr[0] = 0;
+	if (pmc_inuse & 1)
+		mmcr[0] = MMCR0_PMC1CE;
+	if (pmc_inuse & 0xe)
+		mmcr[0] |= MMCR0_PMCjCE;
+	mmcr[1] = mmcr1;
+	mmcr[2] = mmcra;
+	return 0;
+}
+
+/*
+ * Layout of constraint bits:
+ *
+ *	0-1	add field: number of uses of PMC1 (max 1)
+ *	2-3, 4-5, 6-7, 8-9, 10-11: ditto for PMC2, 3, 4, 5, 6
+ *	12-15	add field: number of uses of PMC1-4 (max 4)
+ *	16-19	select field: unit on byte 0 of event bus
+ *	20-23, 24-27, 28-31 ditto for bytes 1, 2, 3
+ *	32-34	select field: nest (subunit) event selector
+ */
+static int p6_get_constraint(u64 event, unsigned long *maskp,
+			     unsigned long *valp)
+{
+	int pmc, byte, sh, subunit;
+	unsigned long mask = 0, value = 0;
+
+	pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+	if (pmc) {
+		if (pmc > 4 && !(event == 0x500009 || event == 0x600005))
+			return -1;
+		sh = (pmc - 1) * 2;
+		mask |= 2 << sh;
+		value |= 1 << sh;
+	}
+	if (event & PM_BUSEVENT_MSK) {
+		byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+		sh = byte * 4 + (16 - PM_UNIT_SH);
+		mask |= PM_UNIT_MSKS << sh;
+		value |= (unsigned long)(event & PM_UNIT_MSKS) << sh;
+		if ((event & PM_UNIT_MSKS) == (5 << PM_UNIT_SH)) {
+			subunit = (event >> PM_SUBUNIT_SH) & PM_SUBUNIT_MSK;
+			mask  |= (unsigned long)PM_SUBUNIT_MSK << 32;
+			value |= (unsigned long)subunit << 32;
+		}
+	}
+	if (pmc <= 4) {
+		mask  |= 0x8000;	/* add field for count of PMC1-4 uses */
+		value |= 0x1000;
+	}
+	*maskp = mask;
+	*valp = value;
+	return 0;
+}
+
+static int p6_limited_pmc_event(u64 event)
+{
+	int pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+
+	return pmc == 5 || pmc == 6;
+}
+
+#define MAX_ALT	4	/* at most 4 alternatives for any event */
+
+static const unsigned int event_alternatives[][MAX_ALT] = {
+	{ 0x0130e8, 0x2000f6, 0x3000fc },	/* PM_PTEG_RELOAD_VALID */
+	{ 0x080080, 0x10000d, 0x30000c, 0x4000f0 }, /* PM_LD_MISS_L1 */
+	{ 0x080088, 0x200054, 0x3000f0 },	/* PM_ST_MISS_L1 */
+	{ 0x10000a, 0x2000f4, 0x600005 },	/* PM_RUN_CYC */
+	{ 0x10000b, 0x2000f5 },			/* PM_RUN_COUNT */
+	{ 0x10000e, 0x400010 },			/* PM_PURR */
+	{ 0x100010, 0x4000f8 },			/* PM_FLUSH */
+	{ 0x10001a, 0x200010 },			/* PM_MRK_INST_DISP */
+	{ 0x100026, 0x3000f8 },			/* PM_TB_BIT_TRANS */
+	{ 0x100054, 0x2000f0 },			/* PM_ST_FIN */
+	{ 0x100056, 0x2000fc },			/* PM_L1_ICACHE_MISS */
+	{ 0x1000f0, 0x40000a },			/* PM_INST_IMC_MATCH_CMPL */
+	{ 0x1000f8, 0x200008 },			/* PM_GCT_EMPTY_CYC */
+	{ 0x1000fc, 0x400006 },			/* PM_LSU_DERAT_MISS_CYC */
+	{ 0x20000e, 0x400007 },			/* PM_LSU_DERAT_MISS */
+	{ 0x200012, 0x300012 },			/* PM_INST_DISP */
+	{ 0x2000f2, 0x3000f2 },			/* PM_INST_DISP */
+	{ 0x2000f8, 0x300010 },			/* PM_EXT_INT */
+	{ 0x2000fe, 0x300056 },			/* PM_DATA_FROM_L2MISS */
+	{ 0x2d0030, 0x30001a },			/* PM_MRK_FPU_FIN */
+	{ 0x30000a, 0x400018 },			/* PM_MRK_INST_FIN */
+	{ 0x3000f6, 0x40000e },			/* PM_L1_DCACHE_RELOAD_VALID */
+	{ 0x3000fe, 0x400056 },			/* PM_DATA_FROM_L3MISS */
+};
+
+/*
+ * This could be made more efficient with a binary search on
+ * a presorted list, if necessary
+ */
+static int find_alternatives_list(u64 event)
+{
+	int i, j;
+	unsigned int alt;
+
+	for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
+		if (event < event_alternatives[i][0])
+			return -1;
+		for (j = 0; j < MAX_ALT; ++j) {
+			alt = event_alternatives[i][j];
+			if (!alt || event < alt)
+				break;
+			if (event == alt)
+				return i;
+		}
+	}
+	return -1;
+}
+
+static int p6_get_alternatives(u64 event, unsigned int flags, u64 alt[])
+{
+	int i, j, nlim;
+	unsigned int psel, pmc;
+	unsigned int nalt = 1;
+	u64 aevent;
+
+	alt[0] = event;
+	nlim = p6_limited_pmc_event(event);
+
+	/* check the alternatives table */
+	i = find_alternatives_list(event);
+	if (i >= 0) {
+		/* copy out alternatives from list */
+		for (j = 0; j < MAX_ALT; ++j) {
+			aevent = event_alternatives[i][j];
+			if (!aevent)
+				break;
+			if (aevent != event)
+				alt[nalt++] = aevent;
+			nlim += p6_limited_pmc_event(aevent);
+		}
+
+	} else {
+		/* Check for alternative ways of computing sum events */
+		/* PMCSEL 0x32 counter N == PMCSEL 0x34 counter 5-N */
+		psel = event & (PM_PMCSEL_MSK & ~1);	/* ignore edge bit */
+		pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+		if (pmc && (psel == 0x32 || psel == 0x34))
+			alt[nalt++] = ((event ^ 0x6) & ~PM_PMC_MSKS) |
+				((5 - pmc) << PM_PMC_SH);
+
+		/* PMCSEL 0x38 counter N == PMCSEL 0x3a counter N+/-2 */
+		if (pmc && (psel == 0x38 || psel == 0x3a))
+			alt[nalt++] = ((event ^ 0x2) & ~PM_PMC_MSKS) |
+				((pmc > 2? pmc - 2: pmc + 2) << PM_PMC_SH);
+	}
+
+	if (flags & PPMU_ONLY_COUNT_RUN) {
+		/*
+		 * We're only counting in RUN state,
+		 * so PM_CYC is equivalent to PM_RUN_CYC,
+		 * PM_INST_CMPL === PM_RUN_INST_CMPL, PM_PURR === PM_RUN_PURR.
+		 * This doesn't include alternatives that don't provide
+		 * any extra flexibility in assigning PMCs (e.g.
+		 * 0x10000a for PM_RUN_CYC vs. 0x1e for PM_CYC).
+		 * Note that even with these additional alternatives
+		 * we never end up with more than 4 alternatives for any event.
+		 */
+		j = nalt;
+		for (i = 0; i < nalt; ++i) {
+			switch (alt[i]) {
+			case 0x1e:	/* PM_CYC */
+				alt[j++] = 0x600005;	/* PM_RUN_CYC */
+				++nlim;
+				break;
+			case 0x10000a:	/* PM_RUN_CYC */
+				alt[j++] = 0x1e;	/* PM_CYC */
+				break;
+			case 2:		/* PM_INST_CMPL */
+				alt[j++] = 0x500009;	/* PM_RUN_INST_CMPL */
+				++nlim;
+				break;
+			case 0x500009:	/* PM_RUN_INST_CMPL */
+				alt[j++] = 2;		/* PM_INST_CMPL */
+				break;
+			case 0x10000e:	/* PM_PURR */
+				alt[j++] = 0x4000f4;	/* PM_RUN_PURR */
+				break;
+			case 0x4000f4:	/* PM_RUN_PURR */
+				alt[j++] = 0x10000e;	/* PM_PURR */
+				break;
+			}
+		}
+		nalt = j;
+	}
+
+	if (!(flags & PPMU_LIMITED_PMC_OK) && nlim) {
+		/* remove the limited PMC events */
+		j = 0;
+		for (i = 0; i < nalt; ++i) {
+			if (!p6_limited_pmc_event(alt[i])) {
+				alt[j] = alt[i];
+				++j;
+			}
+		}
+		nalt = j;
+	} else if ((flags & PPMU_LIMITED_PMC_REQD) && nlim < nalt) {
+		/* remove all but the limited PMC events */
+		j = 0;
+		for (i = 0; i < nalt; ++i) {
+			if (p6_limited_pmc_event(alt[i])) {
+				alt[j] = alt[i];
+				++j;
+			}
+		}
+		nalt = j;
+	}
+
+	return nalt;
+}
+
+static void p6_disable_pmc(unsigned int pmc, unsigned long mmcr[])
+{
+	/* Set PMCxSEL to 0 to disable PMCx */
+	if (pmc <= 3)
+		mmcr[1] &= ~(0xffUL << MMCR1_PMCSEL_SH(pmc));
+}
+
+static int power6_generic_events[] = {
+	[PERF_COUNT_HW_CPU_CYCLES]		= 0x1e,
+	[PERF_COUNT_HW_INSTRUCTIONS]		= 2,
+	[PERF_COUNT_HW_CACHE_REFERENCES]	= 0x280030, /* LD_REF_L1 */
+	[PERF_COUNT_HW_CACHE_MISSES]		= 0x30000c, /* LD_MISS_L1 */
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= 0x410a0,  /* BR_PRED */
+	[PERF_COUNT_HW_BRANCH_MISSES]		= 0x400052, /* BR_MPRED */
+};
+
+#define C(x)	PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ * The "DTLB" and "ITLB" events relate to the DERAT and IERAT.
+ */
+static int power6_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+	[C(L1D)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0x280030,	0x80080		},
+		[C(OP_WRITE)] = {	0x180032,	0x80088		},
+		[C(OP_PREFETCH)] = {	0x810a4,	0		},
+	},
+	[C(L1I)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0,		0x100056 	},
+		[C(OP_WRITE)] = {	-1,		-1		},
+		[C(OP_PREFETCH)] = {	0x4008c,	0		},
+	},
+	[C(LL)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0x150730,	0x250532	},
+		[C(OP_WRITE)] = {	0x250432,	0x150432	},
+		[C(OP_PREFETCH)] = {	0x810a6,	0		},
+	},
+	[C(DTLB)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0,		0x20000e	},
+		[C(OP_WRITE)] = {	-1,		-1		},
+		[C(OP_PREFETCH)] = {	-1,		-1		},
+	},
+	[C(ITLB)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0,		0x420ce		},
+		[C(OP_WRITE)] = {	-1,		-1		},
+		[C(OP_PREFETCH)] = {	-1,		-1		},
+	},
+	[C(BPU)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0x430e6,	0x400052	},
+		[C(OP_WRITE)] = {	-1,		-1		},
+		[C(OP_PREFETCH)] = {	-1,		-1		},
+	},
+	[C(NODE)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	-1,		-1		},
+		[C(OP_WRITE)] = {	-1,		-1		},
+		[C(OP_PREFETCH)] = {	-1,		-1		},
+	},
+};
+
+static struct power_pmu power6_pmu = {
+	.name			= "POWER6",
+	.n_counter		= 6,
+	.max_alternatives	= MAX_ALT,
+	.add_fields		= 0x1555,
+	.test_adder		= 0x3000,
+	.compute_mmcr		= p6_compute_mmcr,
+	.get_constraint		= p6_get_constraint,
+	.get_alternatives	= p6_get_alternatives,
+	.disable_pmc		= p6_disable_pmc,
+	.limited_pmc_event	= p6_limited_pmc_event,
+	.flags			= PPMU_LIMITED_PMC5_6 | PPMU_ALT_SIPR,
+	.n_generic		= ARRAY_SIZE(power6_generic_events),
+	.generic_events		= power6_generic_events,
+	.cache_events		= &power6_cache_events,
+};
+
+static int __init init_power6_pmu(void)
+{
+	if (!cur_cpu_spec->oprofile_cpu_type ||
+	    strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power6"))
+		return -ENODEV;
+
+	return register_power_pmu(&power6_pmu);
+}
+
+early_initcall(init_power6_pmu);
diff --git a/arch/powerpc/kernel/power7-pmu.c b/arch/powerpc/perf/power7-pmu.c
similarity index 100%
rename from arch/powerpc/kernel/power7-pmu.c
rename to arch/powerpc/perf/power7-pmu.c
diff --git a/arch/powerpc/perf/ppc970-pmu.c b/arch/powerpc/perf/ppc970-pmu.c
new file mode 100644
index 0000000..20139ce
--- /dev/null
+++ b/arch/powerpc/perf/ppc970-pmu.c
@@ -0,0 +1,503 @@
+/*
+ * Performance counter support for PPC970-family processors.
+ *
+ * Copyright 2008-2009 Paul Mackerras, 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.
+ */
+#include <linux/string.h>
+#include <linux/perf_event.h>
+#include <asm/reg.h>
+#include <asm/cputable.h>
+
+/*
+ * Bits in event code for PPC970
+ */
+#define PM_PMC_SH	12	/* PMC number (1-based) for direct events */
+#define PM_PMC_MSK	0xf
+#define PM_UNIT_SH	8	/* TTMMUX number and setting - unit select */
+#define PM_UNIT_MSK	0xf
+#define PM_SPCSEL_SH	6
+#define PM_SPCSEL_MSK	3
+#define PM_BYTE_SH	4	/* Byte number of event bus to use */
+#define PM_BYTE_MSK	3
+#define PM_PMCSEL_MSK	0xf
+
+/* Values in PM_UNIT field */
+#define PM_NONE		0
+#define PM_FPU		1
+#define PM_VPU		2
+#define PM_ISU		3
+#define PM_IFU		4
+#define PM_IDU		5
+#define PM_STS		6
+#define PM_LSU0		7
+#define PM_LSU1U	8
+#define PM_LSU1L	9
+#define PM_LASTUNIT	9
+
+/*
+ * Bits in MMCR0 for PPC970
+ */
+#define MMCR0_PMC1SEL_SH	8
+#define MMCR0_PMC2SEL_SH	1
+#define MMCR_PMCSEL_MSK		0x1f
+
+/*
+ * Bits in MMCR1 for PPC970
+ */
+#define MMCR1_TTM0SEL_SH	62
+#define MMCR1_TTM1SEL_SH	59
+#define MMCR1_TTM3SEL_SH	53
+#define MMCR1_TTMSEL_MSK	3
+#define MMCR1_TD_CP_DBG0SEL_SH	50
+#define MMCR1_TD_CP_DBG1SEL_SH	48
+#define MMCR1_TD_CP_DBG2SEL_SH	46
+#define MMCR1_TD_CP_DBG3SEL_SH	44
+#define MMCR1_PMC1_ADDER_SEL_SH	39
+#define MMCR1_PMC2_ADDER_SEL_SH	38
+#define MMCR1_PMC6_ADDER_SEL_SH	37
+#define MMCR1_PMC5_ADDER_SEL_SH	36
+#define MMCR1_PMC8_ADDER_SEL_SH	35
+#define MMCR1_PMC7_ADDER_SEL_SH	34
+#define MMCR1_PMC3_ADDER_SEL_SH	33
+#define MMCR1_PMC4_ADDER_SEL_SH	32
+#define MMCR1_PMC3SEL_SH	27
+#define MMCR1_PMC4SEL_SH	22
+#define MMCR1_PMC5SEL_SH	17
+#define MMCR1_PMC6SEL_SH	12
+#define MMCR1_PMC7SEL_SH	7
+#define MMCR1_PMC8SEL_SH	2
+
+static short mmcr1_adder_bits[8] = {
+	MMCR1_PMC1_ADDER_SEL_SH,
+	MMCR1_PMC2_ADDER_SEL_SH,
+	MMCR1_PMC3_ADDER_SEL_SH,
+	MMCR1_PMC4_ADDER_SEL_SH,
+	MMCR1_PMC5_ADDER_SEL_SH,
+	MMCR1_PMC6_ADDER_SEL_SH,
+	MMCR1_PMC7_ADDER_SEL_SH,
+	MMCR1_PMC8_ADDER_SEL_SH
+};
+
+/*
+ * Layout of constraint bits:
+ * 6666555555555544444444443333333333222222222211111111110000000000
+ * 3210987654321098765432109876543210987654321098765432109876543210
+ *               <><><>[  >[  >[  ><  ><  ><  ><  ><><><><><><><><>
+ *               SPT0T1 UC  PS1 PS2 B0  B1  B2  B3 P1P2P3P4P5P6P7P8
+ *
+ * SP - SPCSEL constraint
+ *     48-49: SPCSEL value 0x3_0000_0000_0000
+ *
+ * T0 - TTM0 constraint
+ *     46-47: TTM0SEL value (0=FPU, 2=IFU, 3=VPU) 0xC000_0000_0000
+ *
+ * T1 - TTM1 constraint
+ *     44-45: TTM1SEL value (0=IDU, 3=STS) 0x3000_0000_0000
+ *
+ * UC - unit constraint: can't have all three of FPU|IFU|VPU, ISU, IDU|STS
+ *     43: UC3 error 0x0800_0000_0000
+ *     42: FPU|IFU|VPU events needed 0x0400_0000_0000
+ *     41: ISU events needed 0x0200_0000_0000
+ *     40: IDU|STS events needed 0x0100_0000_0000
+ *
+ * PS1
+ *     39: PS1 error 0x0080_0000_0000
+ *     36-38: count of events needing PMC1/2/5/6 0x0070_0000_0000
+ *
+ * PS2
+ *     35: PS2 error 0x0008_0000_0000
+ *     32-34: count of events needing PMC3/4/7/8 0x0007_0000_0000
+ *
+ * B0
+ *     28-31: Byte 0 event source 0xf000_0000
+ *	      Encoding as for the event code
+ *
+ * B1, B2, B3
+ *     24-27, 20-23, 16-19: Byte 1, 2, 3 event sources
+ *
+ * P1
+ *     15: P1 error 0x8000
+ *     14-15: Count of events needing PMC1
+ *
+ * P2..P8
+ *     0-13: Count of events needing PMC2..PMC8
+ */
+
+static unsigned char direct_marked_event[8] = {
+	(1<<2) | (1<<3),	/* PMC1: PM_MRK_GRP_DISP, PM_MRK_ST_CMPL */
+	(1<<3) | (1<<5),	/* PMC2: PM_THRESH_TIMEO, PM_MRK_BRU_FIN */
+	(1<<3) | (1<<5),	/* PMC3: PM_MRK_ST_CMPL_INT, PM_MRK_VMX_FIN */
+	(1<<4) | (1<<5),	/* PMC4: PM_MRK_GRP_CMPL, PM_MRK_CRU_FIN */
+	(1<<4) | (1<<5),	/* PMC5: PM_GRP_MRK, PM_MRK_GRP_TIMEO */
+	(1<<3) | (1<<4) | (1<<5),
+		/* PMC6: PM_MRK_ST_STS, PM_MRK_FXU_FIN, PM_MRK_GRP_ISSUED */
+	(1<<4) | (1<<5),	/* PMC7: PM_MRK_FPU_FIN, PM_MRK_INST_FIN */
+	(1<<4)			/* PMC8: PM_MRK_LSU_FIN */
+};
+
+/*
+ * Returns 1 if event counts things relating to marked instructions
+ * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
+ */
+static int p970_marked_instr_event(u64 event)
+{
+	int pmc, psel, unit, byte, bit;
+	unsigned int mask;
+
+	pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+	psel = event & PM_PMCSEL_MSK;
+	if (pmc) {
+		if (direct_marked_event[pmc - 1] & (1 << psel))
+			return 1;
+		if (psel == 0)		/* add events */
+			bit = (pmc <= 4)? pmc - 1: 8 - pmc;
+		else if (psel == 7 || psel == 13)	/* decode events */
+			bit = 4;
+		else
+			return 0;
+	} else
+		bit = psel;
+
+	byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+	unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+	mask = 0;
+	switch (unit) {
+	case PM_VPU:
+		mask = 0x4c;		/* byte 0 bits 2,3,6 */
+		break;
+	case PM_LSU0:
+		/* byte 2 bits 0,2,3,4,6; all of byte 1 */
+		mask = 0x085dff00;
+		break;
+	case PM_LSU1L:
+		mask = 0x50 << 24;	/* byte 3 bits 4,6 */
+		break;
+	}
+	return (mask >> (byte * 8 + bit)) & 1;
+}
+
+/* Masks and values for using events from the various units */
+static unsigned long unit_cons[PM_LASTUNIT+1][2] = {
+	[PM_FPU] =   { 0xc80000000000ull, 0x040000000000ull },
+	[PM_VPU] =   { 0xc80000000000ull, 0xc40000000000ull },
+	[PM_ISU] =   { 0x080000000000ull, 0x020000000000ull },
+	[PM_IFU] =   { 0xc80000000000ull, 0x840000000000ull },
+	[PM_IDU] =   { 0x380000000000ull, 0x010000000000ull },
+	[PM_STS] =   { 0x380000000000ull, 0x310000000000ull },
+};
+
+static int p970_get_constraint(u64 event, unsigned long *maskp,
+			       unsigned long *valp)
+{
+	int pmc, byte, unit, sh, spcsel;
+	unsigned long mask = 0, value = 0;
+	int grp = -1;
+
+	pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+	if (pmc) {
+		if (pmc > 8)
+			return -1;
+		sh = (pmc - 1) * 2;
+		mask |= 2 << sh;
+		value |= 1 << sh;
+		grp = ((pmc - 1) >> 1) & 1;
+	}
+	unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+	if (unit) {
+		if (unit > PM_LASTUNIT)
+			return -1;
+		mask |= unit_cons[unit][0];
+		value |= unit_cons[unit][1];
+		byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+		/*
+		 * Bus events on bytes 0 and 2 can be counted
+		 * on PMC1/2/5/6; bytes 1 and 3 on PMC3/4/7/8.
+		 */
+		if (!pmc)
+			grp = byte & 1;
+		/* Set byte lane select field */
+		mask  |= 0xfULL << (28 - 4 * byte);
+		value |= (unsigned long)unit << (28 - 4 * byte);
+	}
+	if (grp == 0) {
+		/* increment PMC1/2/5/6 field */
+		mask  |= 0x8000000000ull;
+		value |= 0x1000000000ull;
+	} else if (grp == 1) {
+		/* increment PMC3/4/7/8 field */
+		mask  |= 0x800000000ull;
+		value |= 0x100000000ull;
+	}
+	spcsel = (event >> PM_SPCSEL_SH) & PM_SPCSEL_MSK;
+	if (spcsel) {
+		mask  |= 3ull << 48;
+		value |= (unsigned long)spcsel << 48;
+	}
+	*maskp = mask;
+	*valp = value;
+	return 0;
+}
+
+static int p970_get_alternatives(u64 event, unsigned int flags, u64 alt[])
+{
+	alt[0] = event;
+
+	/* 2 alternatives for LSU empty */
+	if (event == 0x2002 || event == 0x3002) {
+		alt[1] = event ^ 0x1000;
+		return 2;
+	}
+
+	return 1;
+}
+
+static int p970_compute_mmcr(u64 event[], int n_ev,
+			     unsigned int hwc[], unsigned long mmcr[])
+{
+	unsigned long mmcr0 = 0, mmcr1 = 0, mmcra = 0;
+	unsigned int pmc, unit, byte, psel;
+	unsigned int ttm, grp;
+	unsigned int pmc_inuse = 0;
+	unsigned int pmc_grp_use[2];
+	unsigned char busbyte[4];
+	unsigned char unituse[16];
+	unsigned char unitmap[] = { 0, 0<<3, 3<<3, 1<<3, 2<<3, 0|4, 3|4 };
+	unsigned char ttmuse[2];
+	unsigned char pmcsel[8];
+	int i;
+	int spcsel;
+
+	if (n_ev > 8)
+		return -1;
+
+	/* First pass to count resource use */
+	pmc_grp_use[0] = pmc_grp_use[1] = 0;
+	memset(busbyte, 0, sizeof(busbyte));
+	memset(unituse, 0, sizeof(unituse));
+	for (i = 0; i < n_ev; ++i) {
+		pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+		if (pmc) {
+			if (pmc_inuse & (1 << (pmc - 1)))
+				return -1;
+			pmc_inuse |= 1 << (pmc - 1);
+			/* count 1/2/5/6 vs 3/4/7/8 use */
+			++pmc_grp_use[((pmc - 1) >> 1) & 1];
+		}
+		unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
+		byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
+		if (unit) {
+			if (unit > PM_LASTUNIT)
+				return -1;
+			if (!pmc)
+				++pmc_grp_use[byte & 1];
+			if (busbyte[byte] && busbyte[byte] != unit)
+				return -1;
+			busbyte[byte] = unit;
+			unituse[unit] = 1;
+		}
+	}
+	if (pmc_grp_use[0] > 4 || pmc_grp_use[1] > 4)
+		return -1;
+
+	/*
+	 * Assign resources and set multiplexer selects.
+	 *
+	 * PM_ISU can go either on TTM0 or TTM1, but that's the only
+	 * choice we have to deal with.
+	 */
+	if (unituse[PM_ISU] &
+	    (unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_VPU]))
+		unitmap[PM_ISU] = 2 | 4;	/* move ISU to TTM1 */
+	/* Set TTM[01]SEL fields. */
+	ttmuse[0] = ttmuse[1] = 0;
+	for (i = PM_FPU; i <= PM_STS; ++i) {
+		if (!unituse[i])
+			continue;
+		ttm = unitmap[i];
+		++ttmuse[(ttm >> 2) & 1];
+		mmcr1 |= (unsigned long)(ttm & ~4) << MMCR1_TTM1SEL_SH;
+	}
+	/* Check only one unit per TTMx */
+	if (ttmuse[0] > 1 || ttmuse[1] > 1)
+		return -1;
+
+	/* Set byte lane select fields and TTM3SEL. */
+	for (byte = 0; byte < 4; ++byte) {
+		unit = busbyte[byte];
+		if (!unit)
+			continue;
+		if (unit <= PM_STS)
+			ttm = (unitmap[unit] >> 2) & 1;
+		else if (unit == PM_LSU0)
+			ttm = 2;
+		else {
+			ttm = 3;
+			if (unit == PM_LSU1L && byte >= 2)
+				mmcr1 |= 1ull << (MMCR1_TTM3SEL_SH + 3 - byte);
+		}
+		mmcr1 |= (unsigned long)ttm
+			<< (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
+	}
+
+	/* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
+	memset(pmcsel, 0x8, sizeof(pmcsel));	/* 8 means don't count */
+	for (i = 0; i < n_ev; ++i) {
+		pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+		unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
+		byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
+		psel = event[i] & PM_PMCSEL_MSK;
+		if (!pmc) {
+			/* Bus event or any-PMC direct event */
+			if (unit)
+				psel |= 0x10 | ((byte & 2) << 2);
+			else
+				psel |= 8;
+			for (pmc = 0; pmc < 8; ++pmc) {
+				if (pmc_inuse & (1 << pmc))
+					continue;
+				grp = (pmc >> 1) & 1;
+				if (unit) {
+					if (grp == (byte & 1))
+						break;
+				} else if (pmc_grp_use[grp] < 4) {
+					++pmc_grp_use[grp];
+					break;
+				}
+			}
+			pmc_inuse |= 1 << pmc;
+		} else {
+			/* Direct event */
+			--pmc;
+			if (psel == 0 && (byte & 2))
+				/* add events on higher-numbered bus */
+				mmcr1 |= 1ull << mmcr1_adder_bits[pmc];
+		}
+		pmcsel[pmc] = psel;
+		hwc[i] = pmc;
+		spcsel = (event[i] >> PM_SPCSEL_SH) & PM_SPCSEL_MSK;
+		mmcr1 |= spcsel;
+		if (p970_marked_instr_event(event[i]))
+			mmcra |= MMCRA_SAMPLE_ENABLE;
+	}
+	for (pmc = 0; pmc < 2; ++pmc)
+		mmcr0 |= pmcsel[pmc] << (MMCR0_PMC1SEL_SH - 7 * pmc);
+	for (; pmc < 8; ++pmc)
+		mmcr1 |= (unsigned long)pmcsel[pmc]
+			<< (MMCR1_PMC3SEL_SH - 5 * (pmc - 2));
+	if (pmc_inuse & 1)
+		mmcr0 |= MMCR0_PMC1CE;
+	if (pmc_inuse & 0xfe)
+		mmcr0 |= MMCR0_PMCjCE;
+
+	mmcra |= 0x2000;	/* mark only one IOP per PPC instruction */
+
+	/* Return MMCRx values */
+	mmcr[0] = mmcr0;
+	mmcr[1] = mmcr1;
+	mmcr[2] = mmcra;
+	return 0;
+}
+
+static void p970_disable_pmc(unsigned int pmc, unsigned long mmcr[])
+{
+	int shift, i;
+
+	if (pmc <= 1) {
+		shift = MMCR0_PMC1SEL_SH - 7 * pmc;
+		i = 0;
+	} else {
+		shift = MMCR1_PMC3SEL_SH - 5 * (pmc - 2);
+		i = 1;
+	}
+	/*
+	 * Setting the PMCxSEL field to 0x08 disables PMC x.
+	 */
+	mmcr[i] = (mmcr[i] & ~(0x1fUL << shift)) | (0x08UL << shift);
+}
+
+static int ppc970_generic_events[] = {
+	[PERF_COUNT_HW_CPU_CYCLES]		= 7,
+	[PERF_COUNT_HW_INSTRUCTIONS]		= 1,
+	[PERF_COUNT_HW_CACHE_REFERENCES]	= 0x8810, /* PM_LD_REF_L1 */
+	[PERF_COUNT_HW_CACHE_MISSES]		= 0x3810, /* PM_LD_MISS_L1 */
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= 0x431,  /* PM_BR_ISSUED */
+	[PERF_COUNT_HW_BRANCH_MISSES] 		= 0x327,  /* PM_GRP_BR_MPRED */
+};
+
+#define C(x)	PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ */
+static int ppc970_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+	[C(L1D)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0x8810,		0x3810	},
+		[C(OP_WRITE)] = {	0x7810,		0x813	},
+		[C(OP_PREFETCH)] = {	0x731,		0	},
+	},
+	[C(L1I)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0,		0	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	0,		0	},
+	},
+	[C(LL)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0,		0	},
+		[C(OP_WRITE)] = {	0,		0	},
+		[C(OP_PREFETCH)] = {	0x733,		0	},
+	},
+	[C(DTLB)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0,		0x704	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	-1,		-1	},
+	},
+	[C(ITLB)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0,		0x700	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	-1,		-1	},
+	},
+	[C(BPU)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0x431,		0x327	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	-1,		-1	},
+	},
+	[C(NODE)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	-1,		-1	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	-1,		-1	},
+	},
+};
+
+static struct power_pmu ppc970_pmu = {
+	.name			= "PPC970/FX/MP",
+	.n_counter		= 8,
+	.max_alternatives	= 2,
+	.add_fields		= 0x001100005555ull,
+	.test_adder		= 0x013300000000ull,
+	.compute_mmcr		= p970_compute_mmcr,
+	.get_constraint		= p970_get_constraint,
+	.get_alternatives	= p970_get_alternatives,
+	.disable_pmc		= p970_disable_pmc,
+	.n_generic		= ARRAY_SIZE(ppc970_generic_events),
+	.generic_events		= ppc970_generic_events,
+	.cache_events		= &ppc970_cache_events,
+	.flags			= PPMU_NO_SIPR | PPMU_NO_CONT_SAMPLING,
+};
+
+static int __init init_ppc970_pmu(void)
+{
+	if (!cur_cpu_spec->oprofile_cpu_type ||
+	    (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970")
+	     && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970MP")))
+		return -ENODEV;
+
+	return register_power_pmu(&ppc970_pmu);
+}
+
+early_initcall(init_ppc970_pmu);
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index fcf6bf2..2e4e64a 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -23,6 +23,7 @@
 	default n
 	select PPC44x_SIMPLE
 	select APM821xx
+	select PPC4xx_PCI_EXPRESS
 	select IBM_EMAC_RGMII
 	help
 	  This option enables support for the APM APM821xx Evaluation board.
diff --git a/arch/powerpc/platforms/44x/currituck.c b/arch/powerpc/platforms/44x/currituck.c
index 3f6229b..583e67f 100644
--- a/arch/powerpc/platforms/44x/currituck.c
+++ b/arch/powerpc/platforms/44x/currituck.c
@@ -83,7 +83,7 @@
 		 * device-tree, just pass 0 to all arguments
 		 */
 		struct mpic *mpic =
-			mpic_alloc(np, 0, 0, 0, 0, " MPIC     ");
+			mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC     ");
 		BUG_ON(mpic == NULL);
 		mpic_init(mpic);
 		ppc_md.get_irq = mpic_get_irq;
diff --git a/arch/powerpc/platforms/44x/iss4xx.c b/arch/powerpc/platforms/44x/iss4xx.c
index 5b8cdbb..a28a862 100644
--- a/arch/powerpc/platforms/44x/iss4xx.c
+++ b/arch/powerpc/platforms/44x/iss4xx.c
@@ -71,8 +71,7 @@
 		/* The MPIC driver will get everything it needs from the
 		 * device-tree, just pass 0 to all arguments
 		 */
-		struct mpic *mpic = mpic_alloc(np, 0, 0, 0, 0,
-					       " MPIC     ");
+		struct mpic *mpic = mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC     ");
 		BUG_ON(mpic == NULL);
 		mpic_init(mpic);
 		ppc_md.get_irq = mpic_get_irq;
diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c
index 8d22027..3ffb915 100644
--- a/arch/powerpc/platforms/44x/ppc44x_simple.c
+++ b/arch/powerpc/platforms/44x/ppc44x_simple.c
@@ -52,7 +52,7 @@
 static char *board[] __initdata = {
 	"amcc,arches",
 	"amcc,bamboo",
-	"amcc,bluestone",
+	"apm,bluestone",
 	"amcc,glacier",
 	"ibm,ebony",
 	"amcc,eiger",
diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c
index eda0fc2..870b70f 100644
--- a/arch/powerpc/platforms/52xx/lite5200_pm.c
+++ b/arch/powerpc/platforms/52xx/lite5200_pm.c
@@ -3,6 +3,7 @@
 #include <asm/io.h>
 #include <asm/time.h>
 #include <asm/mpc52xx.h>
+#include <asm/switch_to.h>
 
 /* defined in lite5200_sleep.S and only used here */
 extern void lite5200_low_power(void __iomem *sram, void __iomem *mbar);
diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c
index 846b789..c0aa040 100644
--- a/arch/powerpc/platforms/52xx/mpc5200_simple.c
+++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c
@@ -50,6 +50,7 @@
 
 /* list of the supported boards */
 static const char *board[] __initdata = {
+	"anonymous,a4m072",
 	"anon,charon",
 	"intercontrol,digsy-mtc",
 	"manroland,mucmc52",
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c
index 369fd54..d7e94f4 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_common.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c
@@ -98,13 +98,11 @@
  *					of the localplus bus to the of_platform
  *					bus.
  */
-void __init
-mpc52xx_declare_of_platform_devices(void)
+void __init mpc52xx_declare_of_platform_devices(void)
 {
-	/* Find every child of the SOC node and add it to of_platform */
-	if (of_platform_bus_probe(NULL, mpc52xx_bus_ids, NULL))
-		printk(KERN_ERR __FILE__ ": "
-			"Error while probing of_platform bus\n");
+	/* Find all the 'platform' devices and register them. */
+	if (of_platform_populate(NULL, mpc52xx_bus_ids, NULL, NULL))
+		pr_err(__FILE__ ": Error while populating devices from DT\n");
 }
 
 /*
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
index bfb11e0..e2d401a 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
@@ -93,7 +93,7 @@
 };
 
 /* MPC5200 device tree match tables */
-const struct of_device_id mpc52xx_pci_ids[] __initdata = {
+const struct of_device_id mpc52xx_pci_ids[] __initconst = {
 	{ .type = "pci", .compatible = "fsl,mpc5200-pci", },
 	{ .type = "pci", .compatible = "mpc5200-pci", },
 	{}
diff --git a/arch/powerpc/platforms/82xx/pq2.c b/arch/powerpc/platforms/82xx/pq2.c
index d111b02..fb94d10 100644
--- a/arch/powerpc/platforms/82xx/pq2.c
+++ b/arch/powerpc/platforms/82xx/pq2.c
@@ -17,7 +17,6 @@
 #include <asm/cpm2.h>
 #include <asm/io.h>
 #include <asm/pci-bridge.h>
-#include <asm/system.h>
 
 #include <platforms/82xx/pq2.h>
 
diff --git a/arch/powerpc/platforms/83xx/km83xx.c b/arch/powerpc/platforms/83xx/km83xx.c
index 65eb792..a266ba8 100644
--- a/arch/powerpc/platforms/83xx/km83xx.c
+++ b/arch/powerpc/platforms/83xx/km83xx.c
@@ -27,7 +27,6 @@
 #include <linux/of_platform.h>
 #include <linux/of_device.h>
 
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/time.h>
 #include <asm/io.h>
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c
index e36bc61..d440435 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c
@@ -26,7 +26,6 @@
 #include <linux/of_platform.h>
 #include <linux/of_device.h>
 
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/time.h>
 #include <asm/io.h>
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c
index 39849dd..a494fa5 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_itx.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c
@@ -25,7 +25,6 @@
 #include <linux/root_dev.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/time.h>
 #include <asm/io.h>
diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c
index 5828d8e..553e793 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c
@@ -25,7 +25,6 @@
 #include <linux/root_dev.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/time.h>
 #include <asm/io.h>
diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c
index ad8e4bc..1b1f6c8 100644
--- a/arch/powerpc/platforms/83xx/mpc836x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c
@@ -33,7 +33,6 @@
 #include <linux/of_platform.h>
 #include <linux/of_device.h>
 
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/time.h>
 #include <asm/io.h>
diff --git a/arch/powerpc/platforms/83xx/sbc834x.c b/arch/powerpc/platforms/83xx/sbc834x.c
index 8a81d76..26cb3e9 100644
--- a/arch/powerpc/platforms/83xx/sbc834x.c
+++ b/arch/powerpc/platforms/83xx/sbc834x.c
@@ -27,7 +27,6 @@
 #include <linux/root_dev.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/time.h>
 #include <asm/io.h>
diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c
index edf6687..1a04671 100644
--- a/arch/powerpc/platforms/83xx/suspend.c
+++ b/arch/powerpc/platforms/83xx/suspend.c
@@ -27,6 +27,7 @@
 #include <asm/io.h>
 #include <asm/time.h>
 #include <asm/mpc6xx.h>
+#include <asm/switch_to.h>
 
 #include <sysdev/fsl_soc.h>
 
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index d7946be2..f000d81 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -6,6 +6,7 @@
 	select MPIC
 	select PPC_PCI_CHOICE
 	select FSL_PCI if PCI
+	select SERIAL_8250_EXTENDED if SERIAL_8250
 	select SERIAL_8250_SHARE_IRQ if SERIAL_8250
 	default y
 
@@ -13,6 +14,15 @@
 
 if PPC32
 
+config FSL_85XX_CACHE_SRAM
+	bool
+	select PPC_LIB_RHEAP
+	help
+	  When selected, this option enables cache-sram support
+	  for memory allocation on P1/P2 QorIQ platforms.
+	  cache-sram-size and cache-sram-offset kernel boot
+	  parameters should be passed when this option is enabled.
+
 config MPC8540_ADS
 	bool "Freescale MPC8540 ADS"
 	select DEFAULT_UIMAGE
@@ -30,6 +40,7 @@
 	bool "Freescale MPC85xx CDS"
 	select DEFAULT_UIMAGE
 	select PPC_I8259
+	select HAS_RAPIDIO
 	help
 	  This option enables support for the MPC85xx CDS board
 
@@ -80,7 +91,6 @@
 config P1022_DS
 	bool "Freescale P1022 DS"
 	select DEFAULT_UIMAGE
-	select PHYS_64BIT	# The DTS has 36-bit addresses
 	select SWIOTLB
 	help
 	  This option enables support for the Freescale P1022DS reference board.
@@ -171,6 +181,21 @@
 	help
 	  This option enables support for the Wind River SBC8560 board
 
+config GE_IMP3A
+	bool "GE Intelligent Platforms IMP3A"
+	select DEFAULT_UIMAGE
+	select SWIOTLB
+	select MMIO_NVRAM
+	select GENERIC_GPIO
+	select ARCH_REQUIRE_GPIOLIB
+	select GE_FPGA
+	help
+	  This option enables support for the GE Intelligent Platforms IMP3A
+	  board.
+
+	  This board is a 3U CompactPCI Single Board Computer with a Freescale
+	  P2020 processor.
+
 config P2041_RDB
 	bool "Freescale P2041 RDB"
 	select DEFAULT_UIMAGE
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 9cb2d43..2125d4c 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -27,3 +27,4 @@
 obj-$(CONFIG_SOCRATES)    += socrates.o socrates_fpga_pic.o
 obj-$(CONFIG_KSI8560)	  += ksi8560.o
 obj-$(CONFIG_XES_MPC85xx) += xes_mpc85xx.o
+obj-$(CONFIG_GE_IMP3A)	  += ge_imp3a.o
diff --git a/arch/powerpc/platforms/85xx/corenet_ds.c b/arch/powerpc/platforms/85xx/corenet_ds.c
index 07e3e6c..dd3617c 100644
--- a/arch/powerpc/platforms/85xx/corenet_ds.c
+++ b/arch/powerpc/platforms/85xx/corenet_ds.c
@@ -18,7 +18,6 @@
 #include <linux/interrupt.h>
 #include <linux/memblock.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -36,8 +35,8 @@
 void __init corenet_ds_pic_init(void)
 {
 	struct mpic *mpic;
-	unsigned int flags = MPIC_BIG_ENDIAN |
-				MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU;
+	unsigned int flags = MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU |
+		MPIC_NO_RESET;
 
 	if (ppc_md.get_irq == mpic_get_coreint_irq)
 		flags |= MPIC_ENABLE_COREINT;
diff --git a/arch/powerpc/platforms/85xx/ge_imp3a.c b/arch/powerpc/platforms/85xx/ge_imp3a.c
new file mode 100644
index 0000000..1801462
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/ge_imp3a.c
@@ -0,0 +1,245 @@
+/*
+ * GE IMP3A Board Setup
+ *
+ * Author Martyn Welch <martyn.welch@ge.com>
+ *
+ * Copyright 2010 GE Intelligent Platforms Embedded Systems, Inc.
+ *
+ * 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.
+ *
+ * Based on: mpc85xx_ds.c (MPC85xx DS Board Setup)
+ * Copyright 2007 Freescale Semiconductor Inc.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/of_platform.h>
+#include <linux/memblock.h>
+
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+#include <asm/swiotlb.h>
+#include <asm/nvram.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+#include "smp.h"
+
+#include "mpc85xx.h"
+#include <sysdev/ge/ge_pic.h>
+
+void __iomem *imp3a_regs;
+
+void __init ge_imp3a_pic_init(void)
+{
+	struct mpic *mpic;
+	struct device_node *np;
+	struct device_node *cascade_node = NULL;
+	unsigned long root = of_get_flat_dt_root();
+
+	if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) {
+		mpic = mpic_alloc(NULL, 0,
+			MPIC_NO_RESET |
+			MPIC_BIG_ENDIAN |
+			MPIC_SINGLE_DEST_CPU,
+			0, 256, " OpenPIC  ");
+	} else {
+		mpic = mpic_alloc(NULL, 0,
+			  MPIC_BIG_ENDIAN |
+			  MPIC_SINGLE_DEST_CPU,
+			0, 256, " OpenPIC  ");
+	}
+
+	BUG_ON(mpic == NULL);
+	mpic_init(mpic);
+	/*
+	 * There is a simple interrupt handler in the main FPGA, this needs
+	 * to be cascaded into the MPIC
+	 */
+	for_each_node_by_type(np, "interrupt-controller")
+		if (of_device_is_compatible(np, "gef,fpga-pic-1.00")) {
+			cascade_node = np;
+			break;
+		}
+
+	if (cascade_node == NULL) {
+		printk(KERN_WARNING "IMP3A: No FPGA PIC\n");
+		return;
+	}
+
+	gef_pic_init(cascade_node);
+	of_node_put(cascade_node);
+}
+
+#ifdef CONFIG_PCI
+static int primary_phb_addr;
+#endif	/* CONFIG_PCI */
+
+/*
+ * Setup the architecture
+ */
+static void __init ge_imp3a_setup_arch(void)
+{
+	struct device_node *regs;
+#ifdef CONFIG_PCI
+	struct device_node *np;
+	struct pci_controller *hose;
+#endif
+	dma_addr_t max = 0xffffffff;
+
+	if (ppc_md.progress)
+		ppc_md.progress("ge_imp3a_setup_arch()", 0);
+
+#ifdef CONFIG_PCI
+	for_each_node_by_type(np, "pci") {
+		if (of_device_is_compatible(np, "fsl,mpc8540-pci") ||
+		    of_device_is_compatible(np, "fsl,mpc8548-pcie") ||
+		    of_device_is_compatible(np, "fsl,p2020-pcie")) {
+			struct resource rsrc;
+			of_address_to_resource(np, 0, &rsrc);
+			if ((rsrc.start & 0xfffff) == primary_phb_addr)
+				fsl_add_bridge(np, 1);
+			else
+				fsl_add_bridge(np, 0);
+
+			hose = pci_find_hose_for_OF_device(np);
+			max = min(max, hose->dma_window_base_cur +
+					hose->dma_window_size);
+		}
+	}
+#endif
+
+	mpc85xx_smp_init();
+
+#ifdef CONFIG_SWIOTLB
+	if (memblock_end_of_DRAM() > max) {
+		ppc_swiotlb_enable = 1;
+		set_pci_dma_ops(&swiotlb_dma_ops);
+		ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
+	}
+#endif
+
+	/* Remap basic board registers */
+	regs = of_find_compatible_node(NULL, NULL, "ge,imp3a-fpga-regs");
+	if (regs) {
+		imp3a_regs = of_iomap(regs, 0);
+		if (imp3a_regs == NULL)
+			printk(KERN_WARNING "Unable to map board registers\n");
+		of_node_put(regs);
+	}
+
+#if defined(CONFIG_MMIO_NVRAM)
+	mmio_nvram_init();
+#endif
+
+	printk(KERN_INFO "GE Intelligent Platforms IMP3A 3U cPCI SBC\n");
+}
+
+/* Return the PCB revision */
+static unsigned int ge_imp3a_get_pcb_rev(void)
+{
+	unsigned int reg;
+
+	reg = ioread16(imp3a_regs);
+	return (reg >> 8) & 0xff;
+}
+
+/* Return the board (software) revision */
+static unsigned int ge_imp3a_get_board_rev(void)
+{
+	unsigned int reg;
+
+	reg = ioread16(imp3a_regs + 0x2);
+	return reg & 0xff;
+}
+
+/* Return the FPGA revision */
+static unsigned int ge_imp3a_get_fpga_rev(void)
+{
+	unsigned int reg;
+
+	reg = ioread16(imp3a_regs + 0x2);
+	return (reg >> 8) & 0xff;
+}
+
+/* Return compactPCI Geographical Address */
+static unsigned int ge_imp3a_get_cpci_geo_addr(void)
+{
+	unsigned int reg;
+
+	reg = ioread16(imp3a_regs + 0x6);
+	return (reg & 0x0f00) >> 8;
+}
+
+/* Return compactPCI System Controller Status */
+static unsigned int ge_imp3a_get_cpci_is_syscon(void)
+{
+	unsigned int reg;
+
+	reg = ioread16(imp3a_regs + 0x6);
+	return reg & (1 << 12);
+}
+
+static void ge_imp3a_show_cpuinfo(struct seq_file *m)
+{
+	seq_printf(m, "Vendor\t\t: GE Intelligent Platforms\n");
+
+	seq_printf(m, "Revision\t: %u%c\n", ge_imp3a_get_pcb_rev(),
+		('A' + ge_imp3a_get_board_rev() - 1));
+
+	seq_printf(m, "FPGA Revision\t: %u\n", ge_imp3a_get_fpga_rev());
+
+	seq_printf(m, "cPCI geo. addr\t: %u\n", ge_imp3a_get_cpci_geo_addr());
+
+	seq_printf(m, "cPCI syscon\t: %s\n",
+		ge_imp3a_get_cpci_is_syscon() ? "yes" : "no");
+}
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init ge_imp3a_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	if (of_flat_dt_is_compatible(root, "ge,IMP3A")) {
+#ifdef CONFIG_PCI
+		primary_phb_addr = 0x9000;
+#endif
+		return 1;
+	}
+
+	return 0;
+}
+
+machine_device_initcall(ge_imp3a, mpc85xx_common_publish_devices);
+
+machine_arch_initcall(ge_imp3a, swiotlb_setup_bus_notifier);
+
+define_machine(ge_imp3a) {
+	.name			= "GE_IMP3A",
+	.probe			= ge_imp3a_probe,
+	.setup_arch		= ge_imp3a_setup_arch,
+	.init_IRQ		= ge_imp3a_pic_init,
+	.show_cpuinfo		= ge_imp3a_show_cpuinfo,
+#ifdef CONFIG_PCI
+	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+#endif
+	.get_irq		= mpic_get_irq,
+	.restart		= fsl_rstcr_restart,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= udbg_progress,
+};
diff --git a/arch/powerpc/platforms/85xx/ksi8560.c b/arch/powerpc/platforms/85xx/ksi8560.c
index 20f75d7..3dc1bda 100644
--- a/arch/powerpc/platforms/85xx/ksi8560.c
+++ b/arch/powerpc/platforms/85xx/ksi8560.c
@@ -20,7 +20,6 @@
 #include <linux/seq_file.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -57,8 +56,7 @@
 
 static void __init ksi8560_pic_init(void)
 {
-	struct mpic *mpic = mpic_alloc(NULL, 0,
-			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
 			0, 256, " OpenPIC  ");
 	BUG_ON(mpic == NULL);
 	mpic_init(mpic);
diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c
index cf26682..585bd22b 100644
--- a/arch/powerpc/platforms/85xx/mpc8536_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c
@@ -19,7 +19,6 @@
 #include <linux/of_platform.h>
 #include <linux/memblock.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -36,9 +35,7 @@
 
 void __init mpc8536_ds_pic_init(void)
 {
-	struct mpic *mpic = mpic_alloc(NULL, 0,
-			  MPIC_WANTS_RESET |
-			  MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS,
+	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
 			0, 256, " OpenPIC  ");
 	BUG_ON(mpic == NULL);
 	mpic_init(mpic);
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
index 3bebb51..29ee8fc 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
@@ -19,7 +19,6 @@
 #include <linux/seq_file.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -50,8 +49,7 @@
 
 static void __init mpc85xx_ads_pic_init(void)
 {
-	struct mpic *mpic = mpic_alloc(NULL, 0,
-			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
 			0, 256, " OpenPIC  ");
 	BUG_ON(mpic == NULL);
 	mpic_init(mpic);
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
index 40f03da..11156fb 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -3,7 +3,7 @@
  *
  * Maintained by Kumar Gala (see MAINTAINERS for contact information)
  *
- * Copyright 2005 Freescale Semiconductor Inc.
+ * Copyright 2005, 2011-2012 Freescale Semiconductor Inc.
  *
  * 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
@@ -27,7 +27,6 @@
 #include <linux/fsl_devices.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/atomic.h>
@@ -48,17 +47,24 @@
 
 #include "mpc85xx.h"
 
-/* CADMUS info */
-/* xxx - galak, move into device tree */
-#define CADMUS_BASE (0xf8004000)
-#define CADMUS_SIZE (256)
-#define CM_VER	(0)
-#define CM_CSR	(1)
-#define CM_RST	(2)
+/*
+ * The CDS board contains an FPGA/CPLD called "Cadmus", which collects
+ * various logic and performs system control functions.
+ * Here is the FPGA/CPLD register map.
+ */
+struct cadmus_reg {
+	u8 cm_ver;		/* Board version */
+	u8 cm_csr;		/* General control/status */
+	u8 cm_rst;		/* Reset control */
+	u8 cm_hsclk;	/* High speed clock */
+	u8 cm_hsxclk;	/* High speed clock extended */
+	u8 cm_led;		/* LED data */
+	u8 cm_pci;		/* PCI control/status */
+	u8 cm_dma;		/* DMA control */
+	u8 res[248];	/* Total 256 bytes */
+};
 
-
-static int cds_pci_slot = 2;
-static volatile u8 *cadmus;
+static struct cadmus_reg *cadmus;
 
 #ifdef CONFIG_PCI
 
@@ -158,6 +164,33 @@
 DECLARE_PCI_FIXUP_EARLY(0x3fff, 0x1957, skip_fake_bridge);
 DECLARE_PCI_FIXUP_EARLY(0xff3f, 0x5719, skip_fake_bridge);
 
+#define PCI_DEVICE_ID_IDT_TSI310	0x01a7
+
+/*
+ * Fix Tsi310 PCI-X bridge resource.
+ * Force the bridge to open a window from 0x0000-0x1fff in PCI I/O space.
+ * This allows legacy I/O(i8259, etc) on the VIA southbridge to be accessed.
+ */
+void mpc85xx_cds_fixup_bus(struct pci_bus *bus)
+{
+	struct pci_dev *dev = bus->self;
+	struct resource *res = bus->resource[0];
+
+	if (dev != NULL &&
+	    dev->vendor == PCI_VENDOR_ID_IBM &&
+	    dev->device == PCI_DEVICE_ID_IDT_TSI310) {
+		if (res) {
+			res->start = 0;
+			res->end   = 0x1fff;
+			res->flags = IORESOURCE_IO;
+			pr_info("mpc85xx_cds: PCI bridge resource fixup applied\n");
+			pr_info("mpc85xx_cds: %pR\n", res);
+		}
+	}
+
+	fsl_pcibios_fixup_bus(bus);
+}
+
 #ifdef CONFIG_PPC_I8259
 static void mpc85xx_8259_cascade_handler(unsigned int irq,
 					 struct irq_desc *desc)
@@ -188,8 +221,7 @@
 static void __init mpc85xx_cds_pic_init(void)
 {
 	struct mpic *mpic;
-	mpic = mpic_alloc(NULL, 0,
-			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+	mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
 			0, 256, " OpenPIC  ");
 	BUG_ON(mpic == NULL);
 	mpic_init(mpic);
@@ -249,20 +281,30 @@
  */
 static void __init mpc85xx_cds_setup_arch(void)
 {
-#ifdef CONFIG_PCI
 	struct device_node *np;
-#endif
+	int cds_pci_slot;
 
 	if (ppc_md.progress)
 		ppc_md.progress("mpc85xx_cds_setup_arch()", 0);
 
-	cadmus = ioremap(CADMUS_BASE, CADMUS_SIZE);
-	cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1;
+	np = of_find_compatible_node(NULL, NULL, "fsl,mpc8548cds-fpga");
+	if (!np) {
+		pr_err("Could not find FPGA node.\n");
+		return;
+	}
+
+	cadmus = of_iomap(np, 0);
+	of_node_put(np);
+	if (!cadmus) {
+		pr_err("Fail to map FPGA area.\n");
+		return;
+	}
 
 	if (ppc_md.progress) {
 		char buf[40];
+		cds_pci_slot = ((in_8(&cadmus->cm_csr) >> 6) & 0x3) + 1;
 		snprintf(buf, 40, "CDS Version = 0x%x in slot %d\n",
-				cadmus[CM_VER], cds_pci_slot);
+				in_8(&cadmus->cm_ver), cds_pci_slot);
 		ppc_md.progress(buf, 0);
 	}
 
@@ -292,7 +334,8 @@
 	svid = mfspr(SPRN_SVR);
 
 	seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
-	seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n", cadmus[CM_VER]);
+	seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n",
+			in_8(&cadmus->cm_ver));
 	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
 	seq_printf(m, "SVR\t\t: 0x%x\n", svid);
 
@@ -323,7 +366,7 @@
 	.get_irq	= mpic_get_irq,
 #ifdef CONFIG_PCI
 	.restart	= mpc85xx_cds_restart,
-	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+	.pcibios_fixup_bus	= mpc85xx_cds_fixup_bus,
 #else
 	.restart	= fsl_rstcr_restart,
 #endif
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
index eefbb91..1fd91e9 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
@@ -22,7 +22,6 @@
 #include <linux/of_platform.h>
 #include <linux/memblock.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -72,13 +71,13 @@
 
 	if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) {
 		mpic = mpic_alloc(NULL, 0,
-			MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
+			MPIC_NO_RESET |
+			MPIC_BIG_ENDIAN |
 			MPIC_SINGLE_DEST_CPU,
 			0, 256, " OpenPIC  ");
 	} else {
 		mpic = mpic_alloc(NULL, 0,
-			  MPIC_WANTS_RESET |
-			  MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
+			  MPIC_BIG_ENDIAN |
 			  MPIC_SINGLE_DEST_CPU,
 			0, 256, " OpenPIC  ");
 	}
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 1d15a0c..9a6f044 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) Freescale Semicondutor, Inc. 2006-2010. All rights reserved.
+ * Copyright (C) 2006-2010, 2012 Freescale Semicondutor, Inc.
+ * All rights reserved.
  *
  * Author: Andy Fleming <afleming@freescale.com>
  *
@@ -34,7 +35,6 @@
 #include <linux/phy.h>
 #include <linux/memblock.h>
 
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/time.h>
 #include <asm/io.h>
@@ -51,6 +51,7 @@
 #include <asm/qe_ic.h>
 #include <asm/mpic.h>
 #include <asm/swiotlb.h>
+#include <asm/fsl_guts.h>
 #include "smp.h"
 
 #include "mpc85xx.h"
@@ -268,34 +269,27 @@
 	mpc85xx_mds_reset_ucc_phys();
 
 	if (machine_is(p1021_mds)) {
-#define MPC85xx_PMUXCR_OFFSET           0x60
-#define MPC85xx_PMUXCR_QE0              0x00008000
-#define MPC85xx_PMUXCR_QE3              0x00001000
-#define MPC85xx_PMUXCR_QE9              0x00000040
-#define MPC85xx_PMUXCR_QE12             0x00000008
-		static __be32 __iomem *pmuxcr;
+
+		struct ccsr_guts __iomem *guts;
 
 		np = of_find_node_by_name(NULL, "global-utilities");
-
 		if (np) {
-			pmuxcr = of_iomap(np, 0) + MPC85xx_PMUXCR_OFFSET;
-
-			if (!pmuxcr)
-				printk(KERN_EMERG "Error: Alternate function"
-					" signal multiplex control register not"
-					" mapped!\n");
-			else
+			guts = of_iomap(np, 0);
+			if (!guts)
+				pr_err("mpc85xx-rdb: could not map global utilities register\n");
+			else{
 			/* P1021 has pins muxed for QE and other functions. To
 			 * enable QE UEC mode, we need to set bit QE0 for UCC1
 			 * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9
 			 * and QE12 for QE MII management signals in PMUXCR
 			 * register.
 			 */
-				setbits32(pmuxcr, MPC85xx_PMUXCR_QE0 |
-						  MPC85xx_PMUXCR_QE3 |
-						  MPC85xx_PMUXCR_QE9 |
-						  MPC85xx_PMUXCR_QE12);
-
+				setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) |
+						  MPC85xx_PMUXCR_QE(3) |
+						  MPC85xx_PMUXCR_QE(9) |
+						  MPC85xx_PMUXCR_QE(12));
+				iounmap(guts);
+			}
 			of_node_put(np);
 		}
 
@@ -434,9 +428,8 @@
 
 static void __init mpc85xx_mds_pic_init(void)
 {
-	struct mpic *mpic = mpic_alloc(NULL, 0,
-			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN |
-			MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU,
+	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
+			MPIC_SINGLE_DEST_CPU,
 			0, 256, " OpenPIC  ");
 	BUG_ON(mpic == NULL);
 
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
index ccf520e..313fce4 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
@@ -1,7 +1,7 @@
 /*
  * MPC85xx RDB Board Setup
  *
- * Copyright 2009 Freescale Semiconductor Inc.
+ * Copyright 2009,2012 Freescale Semiconductor Inc.
  *
  * 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
@@ -18,7 +18,6 @@
 #include <linux/interrupt.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -26,6 +25,9 @@
 #include <asm/prom.h>
 #include <asm/udbg.h>
 #include <asm/mpic.h>
+#include <asm/qe.h>
+#include <asm/qe_ic.h>
+#include <asm/fsl_guts.h>
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
@@ -47,21 +49,36 @@
 	struct mpic *mpic;
 	unsigned long root = of_get_flat_dt_root();
 
+#ifdef CONFIG_QUICC_ENGINE
+	struct device_node *np;
+#endif
+
 	if (of_flat_dt_is_compatible(root, "fsl,MPC85XXRDB-CAMP")) {
-		mpic = mpic_alloc(NULL, 0,
-			MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
+		mpic = mpic_alloc(NULL, 0, MPIC_NO_RESET |
+			MPIC_BIG_ENDIAN |
 			MPIC_SINGLE_DEST_CPU,
 			0, 256, " OpenPIC  ");
 	} else {
 		mpic = mpic_alloc(NULL, 0,
-		  MPIC_WANTS_RESET |
-		  MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
+		  MPIC_BIG_ENDIAN |
 		  MPIC_SINGLE_DEST_CPU,
 		  0, 256, " OpenPIC  ");
 	}
 
 	BUG_ON(mpic == NULL);
 	mpic_init(mpic);
+
+#ifdef CONFIG_QUICC_ENGINE
+	np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
+	if (np) {
+		qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
+				qe_ic_cascade_high_mpic);
+		of_node_put(np);
+
+	} else
+		pr_err("%s: Could not find qe-ic node\n", __func__);
+#endif
+
 }
 
 /*
@@ -69,7 +86,7 @@
  */
 static void __init mpc85xx_rdb_setup_arch(void)
 {
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) || defined(CONFIG_QUICC_ENGINE)
 	struct device_node *np;
 #endif
 
@@ -85,11 +102,73 @@
 #endif
 
 	mpc85xx_smp_init();
+
+#ifdef CONFIG_QUICC_ENGINE
+	np = of_find_compatible_node(NULL, NULL, "fsl,qe");
+	if (!np) {
+		pr_err("%s: Could not find Quicc Engine node\n", __func__);
+		goto qe_fail;
+	}
+
+	qe_reset();
+	of_node_put(np);
+
+	np = of_find_node_by_name(NULL, "par_io");
+	if (np) {
+		struct device_node *ucc;
+
+		par_io_init(np);
+		of_node_put(np);
+
+		for_each_node_by_name(ucc, "ucc")
+			par_io_of_config(ucc);
+
+	}
+#if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE)
+	if (machine_is(p1025_rdb)) {
+
+		struct ccsr_guts __iomem *guts;
+
+		np = of_find_node_by_name(NULL, "global-utilities");
+		if (np) {
+			guts = of_iomap(np, 0);
+			if (!guts) {
+
+				pr_err("mpc85xx-rdb: could not map global utilities register\n");
+
+			} else {
+			/* P1025 has pins muxed for QE and other functions. To
+			* enable QE UEC mode, we need to set bit QE0 for UCC1
+			* in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9
+			* and QE12 for QE MII management singals in PMUXCR
+			* register.
+			*/
+				setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) |
+						MPC85xx_PMUXCR_QE(3) |
+						MPC85xx_PMUXCR_QE(9) |
+						MPC85xx_PMUXCR_QE(12));
+				iounmap(guts);
+			}
+			of_node_put(np);
+		}
+
+	}
+#endif
+
+qe_fail:
+#endif	/* CONFIG_QUICC_ENGINE */
+
 	printk(KERN_INFO "MPC85xx RDB board from Freescale Semiconductor\n");
 }
 
 machine_device_initcall(p2020_rdb, mpc85xx_common_publish_devices);
+machine_device_initcall(p2020_rdb_pc, mpc85xx_common_publish_devices);
+machine_device_initcall(p1020_mbg_pc, mpc85xx_common_publish_devices);
 machine_device_initcall(p1020_rdb, mpc85xx_common_publish_devices);
+machine_device_initcall(p1020_rdb_pc, mpc85xx_common_publish_devices);
+machine_device_initcall(p1020_utm_pc, mpc85xx_common_publish_devices);
+machine_device_initcall(p1021_rdb_pc, mpc85xx_common_publish_devices);
+machine_device_initcall(p1025_rdb, mpc85xx_common_publish_devices);
 
 /*
  * Called very early, device-tree isn't unflattened
@@ -112,6 +191,52 @@
 	return 0;
 }
 
+static int __init p1020_rdb_pc_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	return of_flat_dt_is_compatible(root, "fsl,P1020RDB-PC");
+}
+
+static int __init p1021_rdb_pc_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	if (of_flat_dt_is_compatible(root, "fsl,P1021RDB-PC"))
+		return 1;
+	return 0;
+}
+
+static int __init p2020_rdb_pc_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	if (of_flat_dt_is_compatible(root, "fsl,P2020RDB-PC"))
+		return 1;
+	return 0;
+}
+
+static int __init p1025_rdb_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	return of_flat_dt_is_compatible(root, "fsl,P1025RDB");
+}
+
+static int __init p1020_mbg_pc_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	return of_flat_dt_is_compatible(root, "fsl,P1020MBG-PC");
+}
+
+static int __init p1020_utm_pc_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	return of_flat_dt_is_compatible(root, "fsl,P1020UTM-PC");
+}
+
 define_machine(p2020_rdb) {
 	.name			= "P2020 RDB",
 	.probe			= p2020_rdb_probe,
@@ -139,3 +264,87 @@
 	.calibrate_decr		= generic_calibrate_decr,
 	.progress		= udbg_progress,
 };
+
+define_machine(p1021_rdb_pc) {
+	.name			= "P1021 RDB-PC",
+	.probe			= p1021_rdb_pc_probe,
+	.setup_arch		= mpc85xx_rdb_setup_arch,
+	.init_IRQ		= mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+#endif
+	.get_irq		= mpic_get_irq,
+	.restart		= fsl_rstcr_restart,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= udbg_progress,
+};
+
+define_machine(p2020_rdb_pc) {
+	.name			= "P2020RDB-PC",
+	.probe			= p2020_rdb_pc_probe,
+	.setup_arch		= mpc85xx_rdb_setup_arch,
+	.init_IRQ		= mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+#endif
+	.get_irq		= mpic_get_irq,
+	.restart		= fsl_rstcr_restart,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= udbg_progress,
+};
+
+define_machine(p1025_rdb) {
+	.name			= "P1025 RDB",
+	.probe			= p1025_rdb_probe,
+	.setup_arch		= mpc85xx_rdb_setup_arch,
+	.init_IRQ		= mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+#endif
+	.get_irq		= mpic_get_irq,
+	.restart		= fsl_rstcr_restart,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= udbg_progress,
+};
+
+define_machine(p1020_mbg_pc) {
+	.name			= "P1020 MBG-PC",
+	.probe			= p1020_mbg_pc_probe,
+	.setup_arch		= mpc85xx_rdb_setup_arch,
+	.init_IRQ		= mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+#endif
+	.get_irq		= mpic_get_irq,
+	.restart		= fsl_rstcr_restart,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= udbg_progress,
+};
+
+define_machine(p1020_utm_pc) {
+	.name			= "P1020 UTM-PC",
+	.probe			= p1020_utm_pc_probe,
+	.setup_arch		= mpc85xx_rdb_setup_arch,
+	.init_IRQ		= mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+#endif
+	.get_irq		= mpic_get_irq,
+	.restart		= fsl_rstcr_restart,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= udbg_progress,
+};
+
+define_machine(p1020_rdb_pc) {
+	.name			= "P1020RDB-PC",
+	.probe			= p1020_rdb_pc_probe,
+	.setup_arch		= mpc85xx_rdb_setup_arch,
+	.init_IRQ		= mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+#endif
+	.get_irq		= mpic_get_irq,
+	.restart		= fsl_rstcr_restart,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= udbg_progress,
+};
diff --git a/arch/powerpc/platforms/85xx/p1010rdb.c b/arch/powerpc/platforms/85xx/p1010rdb.c
index 538bc3f..dbaf443 100644
--- a/arch/powerpc/platforms/85xx/p1010rdb.c
+++ b/arch/powerpc/platforms/85xx/p1010rdb.c
@@ -16,7 +16,6 @@
 #include <linux/interrupt.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -32,9 +31,8 @@
 
 void __init p1010_rdb_pic_init(void)
 {
-	struct mpic *mpic = mpic_alloc(NULL, 0,
-	  MPIC_WANTS_RESET | MPIC_BIG_ENDIAN |
-	  MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU,
+	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
+	  MPIC_SINGLE_DEST_CPU,
 	  0, 256, " OpenPIC  ");
 
 	BUG_ON(mpic == NULL);
diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c
index b0984ad..e74b7cd 100644
--- a/arch/powerpc/platforms/85xx/p1022_ds.c
+++ b/arch/powerpc/platforms/85xx/p1022_ds.c
@@ -33,6 +33,10 @@
 
 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
 
+#define PMUXCR_ELBCDIU_MASK	0xc0000000
+#define PMUXCR_ELBCDIU_NOR16	0x80000000
+#define PMUXCR_ELBCDIU_DIU	0x40000000
+
 /*
  * Board-specific initialization of the DIU.  This code should probably be
  * executed when the DIU is opened, rather than in arch code, but the DIU
@@ -50,11 +54,22 @@
 #define CLKDVDR_PXCLK_MASK	0x00FF0000
 
 /* Some ngPIXIS register definitions */
+#define PX_CTL		3
+#define PX_BRDCFG0	8
+#define PX_BRDCFG1	9
+
+#define PX_BRDCFG0_ELBC_SPI_MASK	0xc0
+#define PX_BRDCFG0_ELBC_SPI_ELBC	0x00
+#define PX_BRDCFG0_ELBC_SPI_NULL	0xc0
+#define PX_BRDCFG0_ELBC_DIU		0x02
+
 #define PX_BRDCFG1_DVIEN	0x80
 #define PX_BRDCFG1_DFPEN	0x40
 #define PX_BRDCFG1_BACKLIGHT	0x20
 #define PX_BRDCFG1_DDCEN	0x10
 
+#define PX_CTL_ALTACC		0x80
+
 /*
  * DIU Area Descriptor
  *
@@ -133,44 +148,117 @@
  */
 static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port)
 {
-	struct device_node *np;
-	void __iomem *pixis;
-	u8 __iomem *brdcfg1;
+	struct device_node *guts_node;
+	struct device_node *indirect_node = NULL;
+	struct ccsr_guts __iomem *guts;
+	u8 __iomem *lbc_lcs0_ba = NULL;
+	u8 __iomem *lbc_lcs1_ba = NULL;
+	u8 b;
 
-	np = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga");
-	if (!np)
-		/* older device trees used "fsl,p1022ds-pixis" */
-		np = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis");
-	if (!np) {
-		pr_err("p1022ds: missing ngPIXIS node\n");
+	/* Map the global utilities registers. */
+	guts_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+	if (!guts_node) {
+		pr_err("p1022ds: missing global utilties device node\n");
 		return;
 	}
 
-	pixis = of_iomap(np, 0);
-	if (!pixis) {
-		pr_err("p1022ds: could not map ngPIXIS registers\n");
-		return;
+	guts = of_iomap(guts_node, 0);
+	if (!guts) {
+		pr_err("p1022ds: could not map global utilties device\n");
+		goto exit;
 	}
-	brdcfg1 = pixis + 9;	/* BRDCFG1 is at offset 9 in the ngPIXIS */
+
+	indirect_node = of_find_compatible_node(NULL, NULL,
+					     "fsl,p1022ds-indirect-pixis");
+	if (!indirect_node) {
+		pr_err("p1022ds: missing pixis indirect mode node\n");
+		goto exit;
+	}
+
+	lbc_lcs0_ba = of_iomap(indirect_node, 0);
+	if (!lbc_lcs0_ba) {
+		pr_err("p1022ds: could not map localbus chip select 0\n");
+		goto exit;
+	}
+
+	lbc_lcs1_ba = of_iomap(indirect_node, 1);
+	if (!lbc_lcs1_ba) {
+		pr_err("p1022ds: could not map localbus chip select 1\n");
+		goto exit;
+	}
+
+	/* Make sure we're in indirect mode first. */
+	if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) !=
+	    PMUXCR_ELBCDIU_DIU) {
+		struct device_node *pixis_node;
+		void __iomem *pixis;
+
+		pixis_node =
+			of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga");
+		if (!pixis_node) {
+			pr_err("p1022ds: missing pixis node\n");
+			goto exit;
+		}
+
+		pixis = of_iomap(pixis_node, 0);
+		of_node_put(pixis_node);
+		if (!pixis) {
+			pr_err("p1022ds: could not map pixis registers\n");
+			goto exit;
+		}
+
+		/* Enable indirect PIXIS mode.  */
+		setbits8(pixis + PX_CTL, PX_CTL_ALTACC);
+		iounmap(pixis);
+
+		/* Switch the board mux to the DIU */
+		out_8(lbc_lcs0_ba, PX_BRDCFG0);	/* BRDCFG0 */
+		b = in_8(lbc_lcs1_ba);
+		b |= PX_BRDCFG0_ELBC_DIU;
+		out_8(lbc_lcs1_ba, b);
+
+		/* Set the chip mux to DIU mode. */
+		clrsetbits_be32(&guts->pmuxcr, PMUXCR_ELBCDIU_MASK,
+				PMUXCR_ELBCDIU_DIU);
+		in_be32(&guts->pmuxcr);
+	}
+
 
 	switch (port) {
 	case FSL_DIU_PORT_DVI:
-		printk(KERN_INFO "%s:%u\n", __func__, __LINE__);
 		/* Enable the DVI port, disable the DFP and the backlight */
-		clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT,
-			     PX_BRDCFG1_DVIEN);
+		out_8(lbc_lcs0_ba, PX_BRDCFG1);
+		b = in_8(lbc_lcs1_ba);
+		b &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT);
+		b |= PX_BRDCFG1_DVIEN;
+		out_8(lbc_lcs1_ba, b);
 		break;
 	case FSL_DIU_PORT_LVDS:
-		printk(KERN_INFO "%s:%u\n", __func__, __LINE__);
+		/*
+		 * LVDS also needs backlight enabled, otherwise the display
+		 * will be blank.
+		 */
 		/* Enable the DFP port, disable the DVI and the backlight */
-		clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT,
-			     PX_BRDCFG1_DFPEN);
+		out_8(lbc_lcs0_ba, PX_BRDCFG1);
+		b = in_8(lbc_lcs1_ba);
+		b &= ~PX_BRDCFG1_DVIEN;
+		b |= PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT;
+		out_8(lbc_lcs1_ba, b);
 		break;
 	default:
 		pr_err("p1022ds: unsupported monitor port %i\n", port);
 	}
 
-	iounmap(pixis);
+exit:
+	if (lbc_lcs1_ba)
+		iounmap(lbc_lcs1_ba);
+	if (lbc_lcs0_ba)
+		iounmap(lbc_lcs0_ba);
+	if (guts)
+		iounmap(guts);
+
+	of_node_put(indirect_node);
+	of_node_put(guts_node);
 }
 
 /**
@@ -181,7 +269,7 @@
 void p1022ds_set_pixel_clock(unsigned int pixclock)
 {
 	struct device_node *guts_np = NULL;
-	struct ccsr_guts_85xx __iomem *guts;
+	struct ccsr_guts __iomem *guts;
 	unsigned long freq;
 	u64 temp;
 	u32 pxclk;
@@ -242,15 +330,56 @@
 
 void __init p1022_ds_pic_init(void)
 {
-	struct mpic *mpic = mpic_alloc(NULL, 0,
-		MPIC_WANTS_RESET |
-		MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
+	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
 		MPIC_SINGLE_DEST_CPU,
 		0, 256, " OpenPIC  ");
 	BUG_ON(mpic == NULL);
 	mpic_init(mpic);
 }
 
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+
+/*
+ * Disables a node in the device tree.
+ *
+ * This function is called before kmalloc() is available, so the 'new' object
+ * should be allocated in the global area.  The easiest way is to do that is
+ * to allocate one static local variable for each call to this function.
+ */
+static void __init disable_one_node(struct device_node *np, struct property *new)
+{
+	struct property *old;
+
+	old = of_find_property(np, new->name, NULL);
+	if (old)
+		prom_update_property(np, new, old);
+	else
+		prom_add_property(np, new);
+}
+
+/* TRUE if there is a "video=fslfb" command-line parameter. */
+static bool fslfb;
+
+/*
+ * Search for a "video=fslfb" command-line parameter, and set 'fslfb' to
+ * true if we find it.
+ *
+ * We need to use early_param() instead of __setup() because the normal
+ * __setup() gets called to late.  However, early_param() gets called very
+ * early, before the device tree is unflattened, so all we can do now is set a
+ * global variable.  Later on, p1022_ds_setup_arch() will use that variable
+ * to determine if we need to update the device tree.
+ */
+static int __init early_video_setup(char *options)
+{
+	fslfb = (strncmp(options, "fslfb:", 6) == 0);
+
+	return 0;
+}
+early_param("video", early_video_setup);
+
+#endif
+
 /*
  * Setup the architecture
  */
@@ -288,6 +417,34 @@
 	diu_ops.set_monitor_port	= p1022ds_set_monitor_port;
 	diu_ops.set_pixel_clock		= p1022ds_set_pixel_clock;
 	diu_ops.valid_monitor_port	= p1022ds_valid_monitor_port;
+
+	/*
+	 * Disable the NOR flash node if there is video=fslfb... command-line
+	 * parameter.  When the DIU is active, NOR flash is unavailable, so we
+	 * have to disable the node before the MTD driver loads.
+	 */
+	if (fslfb) {
+		struct device_node *np =
+			of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc");
+
+		if (np) {
+			np = of_find_compatible_node(np, NULL, "cfi-flash");
+			if (np) {
+				static struct property nor_status = {
+					.name = "status",
+					.value = "disabled",
+					.length = sizeof("disabled"),
+				};
+
+				pr_info("p1022ds: disabling %s node",
+					np->full_name);
+				disable_one_node(np, &nor_status);
+				of_node_put(np);
+			}
+		}
+
+	}
+
 #endif
 
 	mpc85xx_smp_init();
diff --git a/arch/powerpc/platforms/85xx/p1023_rds.c b/arch/powerpc/platforms/85xx/p1023_rds.c
index d951e70..2990e8b 100644
--- a/arch/powerpc/platforms/85xx/p1023_rds.c
+++ b/arch/powerpc/platforms/85xx/p1023_rds.c
@@ -22,7 +22,6 @@
 #include <linux/of_platform.h>
 #include <linux/of_device.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -93,9 +92,8 @@
 
 static void __init mpc85xx_rds_pic_init(void)
 {
-	struct mpic *mpic = mpic_alloc(NULL, 0,
-		MPIC_WANTS_RESET | MPIC_BIG_ENDIAN |
-		MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU,
+	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
+		MPIC_SINGLE_DEST_CPU,
 		0, 256, " OpenPIC  ");
 
 	BUG_ON(mpic == NULL);
diff --git a/arch/powerpc/platforms/85xx/p2041_rdb.c b/arch/powerpc/platforms/85xx/p2041_rdb.c
index eda6ed5..6541fa2 100644
--- a/arch/powerpc/platforms/85xx/p2041_rdb.c
+++ b/arch/powerpc/platforms/85xx/p2041_rdb.c
@@ -16,7 +16,6 @@
 #include <linux/interrupt.h>
 #include <linux/phy.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
diff --git a/arch/powerpc/platforms/85xx/p3041_ds.c b/arch/powerpc/platforms/85xx/p3041_ds.c
index 96d99a3..f238efa 100644
--- a/arch/powerpc/platforms/85xx/p3041_ds.c
+++ b/arch/powerpc/platforms/85xx/p3041_ds.c
@@ -18,7 +18,6 @@
 #include <linux/interrupt.h>
 #include <linux/phy.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
diff --git a/arch/powerpc/platforms/85xx/p4080_ds.c b/arch/powerpc/platforms/85xx/p4080_ds.c
index d1b21d7..c92417d 100644
--- a/arch/powerpc/platforms/85xx/p4080_ds.c
+++ b/arch/powerpc/platforms/85xx/p4080_ds.c
@@ -17,7 +17,6 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
diff --git a/arch/powerpc/platforms/85xx/p5020_ds.c b/arch/powerpc/platforms/85xx/p5020_ds.c
index e8cba50..17bef15 100644
--- a/arch/powerpc/platforms/85xx/p5020_ds.c
+++ b/arch/powerpc/platforms/85xx/p5020_ds.c
@@ -18,7 +18,6 @@
 #include <linux/interrupt.h>
 #include <linux/phy.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
diff --git a/arch/powerpc/platforms/85xx/sbc8548.c b/arch/powerpc/platforms/85xx/sbc8548.c
index 184a507..cd3a66b 100644
--- a/arch/powerpc/platforms/85xx/sbc8548.c
+++ b/arch/powerpc/platforms/85xx/sbc8548.c
@@ -30,7 +30,6 @@
 #include <linux/fsl_devices.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/atomic.h>
@@ -54,8 +53,7 @@
 
 static void __init sbc8548_pic_init(void)
 {
-	struct mpic *mpic = mpic_alloc(NULL, 0,
-			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
 			0, 256, " OpenPIC  ");
 	BUG_ON(mpic == NULL);
 	mpic_init(mpic);
diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c
index 940752e..b1be632 100644
--- a/arch/powerpc/platforms/85xx/sbc8560.c
+++ b/arch/powerpc/platforms/85xx/sbc8560.c
@@ -21,7 +21,6 @@
 #include <linux/seq_file.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -41,8 +40,7 @@
 
 static void __init sbc8560_pic_init(void)
 {
-	struct mpic *mpic = mpic_alloc(NULL, 0,
-			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
 			0, 256, " OpenPIC  ");
 	BUG_ON(mpic == NULL);
 	mpic_init(mpic);
diff --git a/arch/powerpc/platforms/85xx/socrates.c b/arch/powerpc/platforms/85xx/socrates.c
index 18f6359..b9c6daa 100644
--- a/arch/powerpc/platforms/85xx/socrates.c
+++ b/arch/powerpc/platforms/85xx/socrates.c
@@ -29,7 +29,6 @@
 #include <linux/seq_file.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -48,8 +47,7 @@
 {
 	struct device_node *np;
 
-	struct mpic *mpic = mpic_alloc(NULL, 0,
-			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
 			0, 256, " OpenPIC  ");
 	BUG_ON(mpic == NULL);
 	mpic_init(mpic);
diff --git a/arch/powerpc/platforms/85xx/stx_gp3.c b/arch/powerpc/platforms/85xx/stx_gp3.c
index e9e5234..e050800 100644
--- a/arch/powerpc/platforms/85xx/stx_gp3.c
+++ b/arch/powerpc/platforms/85xx/stx_gp3.c
@@ -28,7 +28,6 @@
 #include <linux/seq_file.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -48,8 +47,7 @@
 
 static void __init stx_gp3_pic_init(void)
 {
-	struct mpic *mpic = mpic_alloc(NULL, 0,
-			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
 			0, 256, " OpenPIC  ");
 	BUG_ON(mpic == NULL);
 	mpic_init(mpic);
diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c
index bf7c89f..4d786c2 100644
--- a/arch/powerpc/platforms/85xx/tqm85xx.c
+++ b/arch/powerpc/platforms/85xx/tqm85xx.c
@@ -26,7 +26,6 @@
 #include <linux/seq_file.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -47,7 +46,7 @@
 static void __init tqm85xx_pic_init(void)
 {
 	struct mpic *mpic = mpic_alloc(NULL, 0,
-			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+			MPIC_BIG_ENDIAN,
 			0, 256, " OpenPIC  ");
 	BUG_ON(mpic == NULL);
 	mpic_init(mpic);
diff --git a/arch/powerpc/platforms/85xx/xes_mpc85xx.c b/arch/powerpc/platforms/85xx/xes_mpc85xx.c
index 3a69f8b..41c6875 100644
--- a/arch/powerpc/platforms/85xx/xes_mpc85xx.c
+++ b/arch/powerpc/platforms/85xx/xes_mpc85xx.c
@@ -21,7 +21,6 @@
 #include <linux/interrupt.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -43,9 +42,7 @@
 
 void __init xes_mpc85xx_pic_init(void)
 {
-	struct mpic *mpic = mpic_alloc(NULL, 0,
-			  MPIC_WANTS_RESET |
-			  MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS,
+	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
 			0, 256, " OpenPIC  ");
 	BUG_ON(mpic == NULL);
 	mpic_init(mpic);
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
index 8d6599d..7a6279e 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -39,6 +39,7 @@
 	select MMIO_NVRAM
 	select GENERIC_GPIO
 	select ARCH_REQUIRE_GPIOLIB
+	select GE_FPGA
 	help
 	  This option enables support for the GE PPC9A.
 
@@ -48,6 +49,7 @@
 	select MMIO_NVRAM
 	select GENERIC_GPIO
 	select ARCH_REQUIRE_GPIOLIB
+	select GE_FPGA
 	help
 	  This option enables support for the GE SBC310.
 
@@ -57,6 +59,7 @@
 	select MMIO_NVRAM
 	select GENERIC_GPIO
 	select ARCH_REQUIRE_GPIOLIB
+	select GE_FPGA
 	select HAS_RAPIDIO
 	help
 	  This option enables support for the GE SBC610.
diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile
index 4b0d7b1..ede815d 100644
--- a/arch/powerpc/platforms/86xx/Makefile
+++ b/arch/powerpc/platforms/86xx/Makefile
@@ -7,7 +7,6 @@
 obj-$(CONFIG_MPC8641_HPCN)	+= mpc86xx_hpcn.o
 obj-$(CONFIG_SBC8641D)		+= sbc8641d.o
 obj-$(CONFIG_MPC8610_HPCD)	+= mpc8610_hpcd.o
-gef-gpio-$(CONFIG_GPIOLIB)	+= gef_gpio.o
-obj-$(CONFIG_GEF_SBC610)	+= gef_sbc610.o gef_pic.o $(gef-gpio-y)
-obj-$(CONFIG_GEF_SBC310)	+= gef_sbc310.o gef_pic.o $(gef-gpio-y)
-obj-$(CONFIG_GEF_PPC9A)		+= gef_ppc9a.o gef_pic.o $(gef-gpio-y)
+obj-$(CONFIG_GEF_SBC610)	+= gef_sbc610.o
+obj-$(CONFIG_GEF_SBC310)	+= gef_sbc310.o
+obj-$(CONFIG_GEF_PPC9A)		+= gef_ppc9a.o
diff --git a/arch/powerpc/platforms/86xx/gef_gpio.c b/arch/powerpc/platforms/86xx/gef_gpio.c
deleted file mode 100644
index 2a70336..0000000
--- a/arch/powerpc/platforms/86xx/gef_gpio.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Driver for GE FPGA based GPIO
- *
- * Author: Martyn Welch <martyn.welch@ge.com>
- *
- * 2008 (c) GE Intelligent Platforms Embedded Systems, 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.
- */
-
-/* TODO
- *
- * Configuration of output modes (totem-pole/open-drain)
- * Interrupt configuration - interrupts are always generated the FPGA relies on
- * 	the I/O interrupt controllers mask to stop them propergating
- */
-
-#include <linux/kernel.h>
-#include <linux/compiler.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
-#include <linux/gpio.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-
-#define GEF_GPIO_DIRECT		0x00
-#define GEF_GPIO_IN		0x04
-#define GEF_GPIO_OUT		0x08
-#define GEF_GPIO_TRIG		0x0C
-#define GEF_GPIO_POLAR_A	0x10
-#define GEF_GPIO_POLAR_B	0x14
-#define GEF_GPIO_INT_STAT	0x18
-#define GEF_GPIO_OVERRUN	0x1C
-#define GEF_GPIO_MODE		0x20
-
-static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value)
-{
-	unsigned int data;
-
-	data = ioread32be(reg);
-	/* value: 0=low; 1=high */
-	if (value & 0x1)
-		data = data | (0x1 << offset);
-	else
-		data = data & ~(0x1 << offset);
-
-	iowrite32be(data, reg);
-}
-
-
-static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
-{
-	unsigned int data;
-	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
-
-	data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
-	data = data | (0x1 << offset);
-	iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
-
-	return 0;
-}
-
-static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value)
-{
-	unsigned int data;
-	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
-
-	/* Set direction before switching to input */
-	_gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
-
-	data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
-	data = data & ~(0x1 << offset);
-	iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
-
-	return 0;
-}
-
-static int gef_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-	unsigned int data;
-	int state = 0;
-	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
-
-	data = ioread32be(mmchip->regs + GEF_GPIO_IN);
-	state = (int)((data >> offset) & 0x1);
-
-	return state;
-}
-
-static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
-
-	_gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
-}
-
-static int __init gef_gpio_init(void)
-{
-	struct device_node *np;
-	int retval;
-	struct of_mm_gpio_chip *gef_gpio_chip;
-
-	for_each_compatible_node(np, NULL, "gef,sbc610-gpio") {
-
-		pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
-
-		/* Allocate chip structure */
-		gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
-		if (!gef_gpio_chip) {
-			pr_err("%s: Unable to allocate structure\n",
-				np->full_name);
-			continue;
-		}
-
-		/* Setup pointers to chip functions */
-		gef_gpio_chip->gc.of_gpio_n_cells = 2;
-		gef_gpio_chip->gc.ngpio = 19;
-		gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
-		gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
-		gef_gpio_chip->gc.get = gef_gpio_get;
-		gef_gpio_chip->gc.set = gef_gpio_set;
-
-		/* This function adds a memory mapped GPIO chip */
-		retval = of_mm_gpiochip_add(np, gef_gpio_chip);
-		if (retval) {
-			kfree(gef_gpio_chip);
-			pr_err("%s: Unable to add GPIO\n", np->full_name);
-		}
-	}
-
-	for_each_compatible_node(np, NULL, "gef,sbc310-gpio") {
-
-		pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
-
-		/* Allocate chip structure */
-		gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
-		if (!gef_gpio_chip) {
-			pr_err("%s: Unable to allocate structure\n",
-				np->full_name);
-			continue;
-		}
-
-		/* Setup pointers to chip functions */
-		gef_gpio_chip->gc.of_gpio_n_cells = 2;
-		gef_gpio_chip->gc.ngpio = 6;
-		gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
-		gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
-		gef_gpio_chip->gc.get = gef_gpio_get;
-		gef_gpio_chip->gc.set = gef_gpio_set;
-
-		/* This function adds a memory mapped GPIO chip */
-		retval = of_mm_gpiochip_add(np, gef_gpio_chip);
-		if (retval) {
-			kfree(gef_gpio_chip);
-			pr_err("%s: Unable to add GPIO\n", np->full_name);
-		}
-	}
-
-	return 0;
-};
-arch_initcall(gef_gpio_init);
-
-MODULE_DESCRIPTION("GE I/O FPGA GPIO driver");
-MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
-MODULE_LICENSE("GPL");
diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c
deleted file mode 100644
index af3fd69..0000000
--- a/arch/powerpc/platforms/86xx/gef_pic.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Interrupt handling for GE FPGA based PIC
- *
- * Author: Martyn Welch <martyn.welch@ge.com>
- *
- * 2008 (c) GE Intelligent Platforms Embedded Systems, 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/stddef.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/irq.h>
-
-#include "gef_pic.h"
-
-#define DEBUG
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0)
-#else
-#define DBG(fmt...) do { } while (0)
-#endif
-
-#define GEF_PIC_NUM_IRQS	32
-
-/* Interrupt Controller Interface Registers */
-#define GEF_PIC_INTR_STATUS	0x0000
-
-#define GEF_PIC_INTR_MASK(cpu)	(0x0010 + (0x4 * cpu))
-#define GEF_PIC_CPU0_INTR_MASK	GEF_PIC_INTR_MASK(0)
-#define GEF_PIC_CPU1_INTR_MASK	GEF_PIC_INTR_MASK(1)
-
-#define GEF_PIC_MCP_MASK(cpu)	(0x0018 + (0x4 * cpu))
-#define GEF_PIC_CPU0_MCP_MASK	GEF_PIC_MCP_MASK(0)
-#define GEF_PIC_CPU1_MCP_MASK	GEF_PIC_MCP_MASK(1)
-
-
-static DEFINE_RAW_SPINLOCK(gef_pic_lock);
-
-static void __iomem *gef_pic_irq_reg_base;
-static struct irq_domain *gef_pic_irq_host;
-static int gef_pic_cascade_irq;
-
-/*
- * Interrupt Controller Handling
- *
- * The interrupt controller handles interrupts for most on board interrupts,
- * apart from PCI interrupts. For example on SBC610:
- *
- * 17:31 RO Reserved
- * 16    RO PCI Express Doorbell 3 Status
- * 15    RO PCI Express Doorbell 2 Status
- * 14    RO PCI Express Doorbell 1 Status
- * 13    RO PCI Express Doorbell 0 Status
- * 12    RO Real Time Clock Interrupt Status
- * 11    RO Temperature Interrupt Status
- * 10    RO Temperature Critical Interrupt Status
- * 9     RO Ethernet PHY1 Interrupt Status
- * 8     RO Ethernet PHY3 Interrupt Status
- * 7     RO PEX8548 Interrupt Status
- * 6     RO Reserved
- * 5     RO Watchdog 0 Interrupt Status
- * 4     RO Watchdog 1 Interrupt Status
- * 3     RO AXIS Message FIFO A Interrupt Status
- * 2     RO AXIS Message FIFO B Interrupt Status
- * 1     RO AXIS Message FIFO C Interrupt Status
- * 0     RO AXIS Message FIFO D Interrupt Status
- *
- * Interrupts can be forwarded to one of two output lines. Nothing
- * clever is done, so if the masks are incorrectly set, a single input
- * interrupt could generate interrupts on both output lines!
- *
- * The dual lines are there to allow the chained interrupts to be easily
- * passed into two different cores. We currently do not use this functionality
- * in this driver.
- *
- * Controller can also be configured to generate Machine checks (MCP), again on
- * two lines, to be attached to two different cores. It is suggested that these
- * should be masked out.
- */
-
-void gef_pic_cascade(unsigned int irq, struct irq_desc *desc)
-{
-	struct irq_chip *chip = irq_desc_get_chip(desc);
-	unsigned int cascade_irq;
-
-	/*
-	 * See if we actually have an interrupt, call generic handling code if
-	 * we do.
-	 */
-	cascade_irq = gef_pic_get_irq();
-
-	if (cascade_irq != NO_IRQ)
-		generic_handle_irq(cascade_irq);
-
-	chip->irq_eoi(&desc->irq_data);
-}
-
-static void gef_pic_mask(struct irq_data *d)
-{
-	unsigned long flags;
-	unsigned int hwirq = irqd_to_hwirq(d);
-	u32 mask;
-
-	raw_spin_lock_irqsave(&gef_pic_lock, flags);
-	mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
-	mask &= ~(1 << hwirq);
-	out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
-	raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
-}
-
-static void gef_pic_mask_ack(struct irq_data *d)
-{
-	/* Don't think we actually have to do anything to ack an interrupt,
-	 * we just need to clear down the devices interrupt and it will go away
-	 */
-	gef_pic_mask(d);
-}
-
-static void gef_pic_unmask(struct irq_data *d)
-{
-	unsigned long flags;
-	unsigned int hwirq = irqd_to_hwirq(d);
-	u32 mask;
-
-	raw_spin_lock_irqsave(&gef_pic_lock, flags);
-	mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
-	mask |= (1 << hwirq);
-	out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
-	raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
-}
-
-static struct irq_chip gef_pic_chip = {
-	.name		= "gefp",
-	.irq_mask	= gef_pic_mask,
-	.irq_mask_ack	= gef_pic_mask_ack,
-	.irq_unmask	= gef_pic_unmask,
-};
-
-
-/* When an interrupt is being configured, this call allows some flexibilty
- * in deciding which irq_chip structure is used
- */
-static int gef_pic_host_map(struct irq_domain *h, unsigned int virq,
-			  irq_hw_number_t hwirq)
-{
-	/* All interrupts are LEVEL sensitive */
-	irq_set_status_flags(virq, IRQ_LEVEL);
-	irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq);
-
-	return 0;
-}
-
-static int gef_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
-			    const u32 *intspec, unsigned int intsize,
-			    irq_hw_number_t *out_hwirq, unsigned int *out_flags)
-{
-
-	*out_hwirq = intspec[0];
-	if (intsize > 1)
-		*out_flags = intspec[1];
-	else
-		*out_flags = IRQ_TYPE_LEVEL_HIGH;
-
-	return 0;
-}
-
-static const struct irq_domain_ops gef_pic_host_ops = {
-	.map	= gef_pic_host_map,
-	.xlate	= gef_pic_host_xlate,
-};
-
-
-/*
- * Initialisation of PIC, this should be called in BSP
- */
-void __init gef_pic_init(struct device_node *np)
-{
-	unsigned long flags;
-
-	/* Map the devices registers into memory */
-	gef_pic_irq_reg_base = of_iomap(np, 0);
-
-	raw_spin_lock_irqsave(&gef_pic_lock, flags);
-
-	/* Initialise everything as masked. */
-	out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0);
-	out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0);
-
-	out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0);
-	out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0);
-
-	raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
-
-	/* Map controller */
-	gef_pic_cascade_irq = irq_of_parse_and_map(np, 0);
-	if (gef_pic_cascade_irq == NO_IRQ) {
-		printk(KERN_ERR "SBC610: failed to map cascade interrupt");
-		return;
-	}
-
-	/* Setup an irq_domain structure */
-	gef_pic_irq_host = irq_domain_add_linear(np, GEF_PIC_NUM_IRQS,
-					  &gef_pic_host_ops, NULL);
-	if (gef_pic_irq_host == NULL)
-		return;
-
-	/* Chain with parent controller */
-	irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade);
-}
-
-/*
- * This is called when we receive an interrupt with apparently comes from this
- * chip - check, returning the highest interrupt generated or return NO_IRQ
- */
-unsigned int gef_pic_get_irq(void)
-{
-	u32 cause, mask, active;
-	unsigned int virq = NO_IRQ;
-	int hwirq;
-
-	cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS);
-
-	mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
-
-	active = cause & mask;
-
-	if (active) {
-		for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) {
-			if (active & (0x1 << hwirq))
-				break;
-		}
-		virq = irq_linear_revmap(gef_pic_irq_host,
-			(irq_hw_number_t)hwirq);
-	}
-
-	return virq;
-}
-
diff --git a/arch/powerpc/platforms/86xx/gef_ppc9a.c b/arch/powerpc/platforms/86xx/gef_ppc9a.c
index 60ce07e..1fca663 100644
--- a/arch/powerpc/platforms/86xx/gef_ppc9a.c
+++ b/arch/powerpc/platforms/86xx/gef_ppc9a.c
@@ -24,7 +24,6 @@
 #include <linux/seq_file.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -37,9 +36,9 @@
 
 #include <sysdev/fsl_pci.h>
 #include <sysdev/fsl_soc.h>
+#include <sysdev/ge/ge_pic.h>
 
 #include "mpc86xx.h"
-#include "gef_pic.h"
 
 #undef DEBUG
 
diff --git a/arch/powerpc/platforms/86xx/gef_sbc310.c b/arch/powerpc/platforms/86xx/gef_sbc310.c
index 3ecee25..14e0e576 100644
--- a/arch/powerpc/platforms/86xx/gef_sbc310.c
+++ b/arch/powerpc/platforms/86xx/gef_sbc310.c
@@ -24,7 +24,6 @@
 #include <linux/seq_file.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -37,9 +36,9 @@
 
 #include <sysdev/fsl_pci.h>
 #include <sysdev/fsl_soc.h>
+#include <sysdev/ge/ge_pic.h>
 
 #include "mpc86xx.h"
-#include "gef_pic.h"
 
 #undef DEBUG
 
diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c
index 5090d60..1638f43 100644
--- a/arch/powerpc/platforms/86xx/gef_sbc610.c
+++ b/arch/powerpc/platforms/86xx/gef_sbc610.c
@@ -24,7 +24,6 @@
 #include <linux/seq_file.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -37,9 +36,9 @@
 
 #include <sysdev/fsl_pci.h>
 #include <sysdev/fsl_soc.h>
+#include <sysdev/ge/ge_pic.h>
 
 #include "mpc86xx.h"
-#include "gef_pic.h"
 
 #undef DEBUG
 
diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
index 13fa9a6..62cd3c5 100644
--- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
+++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
@@ -25,7 +25,6 @@
 #include <linux/seq_file.h>
 #include <linux/of.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
@@ -226,7 +225,7 @@
 void mpc8610hpcd_set_pixel_clock(unsigned int pixclock)
 {
 	struct device_node *guts_np = NULL;
-	struct ccsr_guts_86xx __iomem *guts;
+	struct ccsr_guts __iomem *guts;
 	unsigned long freq;
 	u64 temp;
 	u32 pxclk;
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
index 569262c..3755e61 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
@@ -21,7 +21,6 @@
 #include <linux/of_platform.h>
 #include <linux/memblock.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
diff --git a/arch/powerpc/platforms/86xx/pic.c b/arch/powerpc/platforms/86xx/pic.c
index 52bbfa0..9982f57 100644
--- a/arch/powerpc/platforms/86xx/pic.c
+++ b/arch/powerpc/platforms/86xx/pic.c
@@ -12,7 +12,6 @@
 #include <linux/interrupt.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/mpic.h>
 #include <asm/i8259.h>
 
@@ -37,9 +36,8 @@
 	int cascade_irq;
 #endif
 
-	struct mpic *mpic = mpic_alloc(NULL, 0,
-			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN |
-			MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU,
+	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
+			MPIC_SINGLE_DEST_CPU,
 			0, 256, " MPIC     ");
 	BUG_ON(mpic == NULL);
 
diff --git a/arch/powerpc/platforms/86xx/sbc8641d.c b/arch/powerpc/platforms/86xx/sbc8641d.c
index 51c8f33..e7007d0 100644
--- a/arch/powerpc/platforms/86xx/sbc8641d.c
+++ b/arch/powerpc/platforms/86xx/sbc8641d.c
@@ -21,7 +21,6 @@
 #include <linux/seq_file.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
index caaec29..866feff 100644
--- a/arch/powerpc/platforms/8xx/mpc86xads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
@@ -19,7 +19,6 @@
 
 #include <asm/io.h>
 #include <asm/machdep.h>
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/8xx_immap.h>
 #include <asm/cpm1.h>
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
index 45ed6cd..5d98398 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -32,7 +32,6 @@
 #include <asm/machdep.h>
 #include <asm/page.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/mpc8xx.h>
 #include <asm/8xx_immap.h>
diff --git a/arch/powerpc/platforms/8xx/tqm8xx_setup.c b/arch/powerpc/platforms/8xx/tqm8xx_setup.c
index 528e00d..8d21ab7 100644
--- a/arch/powerpc/platforms/8xx/tqm8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/tqm8xx_setup.c
@@ -35,7 +35,6 @@
 #include <asm/machdep.h>
 #include <asm/page.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/mpc8xx.h>
 #include <asm/8xx_immap.h>
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 0cfb46d..a35ca44 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -2,7 +2,6 @@
 
 source "arch/powerpc/platforms/powernv/Kconfig"
 source "arch/powerpc/platforms/pseries/Kconfig"
-source "arch/powerpc/platforms/iseries/Kconfig"
 source "arch/powerpc/platforms/chrp/Kconfig"
 source "arch/powerpc/platforms/512x/Kconfig"
 source "arch/powerpc/platforms/52xx/Kconfig"
@@ -87,6 +86,14 @@
 	bool
 	default n
 
+config MPIC_MSGR
+	bool "MPIC message register support"
+	depends on MPIC
+	default n
+	help
+	  Enables support for the MPIC message registers.  These
+	  registers are used for inter-processor communication.
+
 config PPC_I8259
 	bool
 	default n
@@ -138,7 +145,7 @@
 	  of the register contents in software.
 
 config IBMVIO
-	depends on PPC_PSERIES || PPC_ISERIES
+	depends on PPC_PSERIES
 	bool
 	default y
 
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
index 2635a22..879b4a4 100644
--- a/arch/powerpc/platforms/Makefile
+++ b/arch/powerpc/platforms/Makefile
@@ -16,7 +16,6 @@
 obj-$(CONFIG_PPC_86xx)		+= 86xx/
 obj-$(CONFIG_PPC_POWERNV)	+= powernv/
 obj-$(CONFIG_PPC_PSERIES)	+= pseries/
-obj-$(CONFIG_PPC_ISERIES)	+= iseries/
 obj-$(CONFIG_PPC_MAPLE)		+= maple/
 obj-$(CONFIG_PPC_PASEMI)	+= pasemi/
 obj-$(CONFIG_PPC_CELL)		+= cell/
diff --git a/arch/powerpc/platforms/cell/beat_htab.c b/arch/powerpc/platforms/cell/beat_htab.c
index 2516c1c..943c9d3 100644
--- a/arch/powerpc/platforms/cell/beat_htab.c
+++ b/arch/powerpc/platforms/cell/beat_htab.c
@@ -95,7 +95,6 @@
 	unsigned long lpar_rc;
 	u64 hpte_v, hpte_r, slot;
 
-	/* same as iseries */
 	if (vflags & HPTE_V_SECONDARY)
 		return -1;
 
@@ -319,7 +318,6 @@
 	unsigned long lpar_rc;
 	u64 hpte_v, hpte_r, slot;
 
-	/* same as iseries */
 	if (vflags & HPTE_V_SECONDARY)
 		return -1;
 
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index ae9fc7b..b9f509a 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -564,7 +564,8 @@
 /* A coherent allocation implies strong ordering */
 
 static void *dma_fixed_alloc_coherent(struct device *dev, size_t size,
-				      dma_addr_t *dma_handle, gfp_t flag)
+				      dma_addr_t *dma_handle, gfp_t flag,
+				      struct dma_attrs *attrs)
 {
 	if (iommu_fixed_is_weak)
 		return iommu_alloc_coherent(dev, cell_get_iommu_table(dev),
@@ -572,18 +573,19 @@
 					    device_to_mask(dev), flag,
 					    dev_to_node(dev));
 	else
-		return dma_direct_ops.alloc_coherent(dev, size, dma_handle,
-						     flag);
+		return dma_direct_ops.alloc(dev, size, dma_handle, flag,
+					    attrs);
 }
 
 static void dma_fixed_free_coherent(struct device *dev, size_t size,
-				    void *vaddr, dma_addr_t dma_handle)
+				    void *vaddr, dma_addr_t dma_handle,
+				    struct dma_attrs *attrs)
 {
 	if (iommu_fixed_is_weak)
 		iommu_free_coherent(cell_get_iommu_table(dev), size, vaddr,
 				    dma_handle);
 	else
-		dma_direct_ops.free_coherent(dev, size, vaddr, dma_handle);
+		dma_direct_ops.free(dev, size, vaddr, dma_handle, attrs);
 }
 
 static dma_addr_t dma_fixed_map_page(struct device *dev, struct page *page,
@@ -642,8 +644,8 @@
 static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask);
 
 struct dma_map_ops dma_iommu_fixed_ops = {
-	.alloc_coherent = dma_fixed_alloc_coherent,
-	.free_coherent  = dma_fixed_free_coherent,
+	.alloc          = dma_fixed_alloc_coherent,
+	.free           = dma_fixed_free_coherent,
 	.map_sg         = dma_fixed_map_sg,
 	.unmap_sg       = dma_fixed_unmap_sg,
 	.dma_supported  = dma_fixed_dma_supported,
diff --git a/arch/powerpc/platforms/cell/qpace_setup.c b/arch/powerpc/platforms/cell/qpace_setup.c
index 7f9b674..6e3409d 100644
--- a/arch/powerpc/platforms/cell/qpace_setup.c
+++ b/arch/powerpc/platforms/cell/qpace_setup.c
@@ -61,7 +61,7 @@
 	printk("*** %04x : %s\n", hex, s ? s : "");
 }
 
-static const struct of_device_id qpace_bus_ids[] __initdata = {
+static const struct of_device_id qpace_bus_ids[] __initconst = {
 	{ .type = "soc", },
 	{ .compatible = "soc", },
 	{ .type = "spider", },
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index 62002a7..4ab0876 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -140,7 +140,7 @@
 	return 0;
 }
 
-static const struct of_device_id cell_bus_ids[] __initdata = {
+static const struct of_device_id cell_bus_ids[] __initconst = {
 	{ .type = "soc", },
 	{ .compatible = "soc", },
 	{ .type = "spider", },
@@ -197,7 +197,8 @@
 		/* The MPIC driver will get everything it needs from the
 		 * device-tree, just pass 0 to all arguments
 		 */
-		mpic = mpic_alloc(dn, 0, MPIC_SECONDARY, 0, 0, " MPIC     ");
+		mpic = mpic_alloc(dn, 0, MPIC_SECONDARY | MPIC_NO_RESET,
+				0, 0, " MPIC     ");
 		if (mpic == NULL)
 			continue;
 		mpic_init(mpic);
diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c
index 4a255cf..49a65e2 100644
--- a/arch/powerpc/platforms/cell/smp.c
+++ b/arch/powerpc/platforms/cell/smp.c
@@ -38,7 +38,6 @@
 #include <asm/machdep.h>
 #include <asm/cputable.h>
 #include <asm/firmware.h>
-#include <asm/system.h>
 #include <asm/rtas.h>
 #include <asm/cputhreads.h>
 
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index 03c5fce..c2c5b07 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -122,7 +122,7 @@
 	struct spu_context *ctx = NULL;
 
 	for (; *fd < fdt->max_fds; (*fd)++) {
-		if (!FD_ISSET(*fd, fdt->open_fds))
+		if (!fd_is_open(*fd, fdt))
 			continue;
 
 		file = fcheck(*fd);
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index d4a094c..1d75c92 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -646,6 +646,7 @@
 
 out:
 	mutex_unlock(&path->dentry->d_inode->i_mutex);
+	dput(dentry);
 	return ret;
 }
 
@@ -757,9 +758,9 @@
 		goto out_iput;
 
 	ret = -ENOMEM;
-	sb->s_root = d_alloc_root(inode);
+	sb->s_root = d_make_root(inode);
 	if (!sb->s_root)
-		goto out_iput;
+		goto out;
 
 	return 0;
 out_iput:
@@ -828,19 +829,19 @@
 	ret = spu_sched_init();
 	if (ret)
 		goto out_cache;
-	ret = register_filesystem(&spufs_type);
-	if (ret)
-		goto out_sched;
 	ret = register_spu_syscalls(&spufs_calls);
 	if (ret)
-		goto out_fs;
+		goto out_sched;
+	ret = register_filesystem(&spufs_type);
+	if (ret)
+		goto out_syscalls;
 
 	spufs_init_isolated_loader();
 
 	return 0;
 
-out_fs:
-	unregister_filesystem(&spufs_type);
+out_syscalls:
+	unregister_spu_syscalls(&spufs_calls);
 out_sched:
 	spu_sched_exit();
 out_cache:
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c
index 8591bb6..5665dcc 100644
--- a/arch/powerpc/platforms/cell/spufs/syscalls.c
+++ b/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -70,8 +70,6 @@
 	ret = PTR_ERR(dentry);
 	if (!IS_ERR(dentry)) {
 		ret = spufs_create(&path, dentry, flags, mode, neighbor);
-		mutex_unlock(&path.dentry->d_inode->i_mutex);
-		dput(dentry);
 		path_put(&path);
 	}
 
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index f1f17bb..c665d7d 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -435,7 +435,8 @@
 	if (len > 1)
 		isu_size = iranges[3];
 
-	chrp_mpic = mpic_alloc(np, opaddr, 0, isu_size, 0, " MPIC    ");
+	chrp_mpic = mpic_alloc(np, opaddr, MPIC_NO_RESET,
+			isu_size, 0, " MPIC    ");
 	if (chrp_mpic == NULL) {
 		printk(KERN_ERR "Failed to allocate MPIC structure\n");
 		goto bail;
diff --git a/arch/powerpc/platforms/embedded6xx/c2k.c b/arch/powerpc/platforms/embedded6xx/c2k.c
index 8cab573..ebd3963 100644
--- a/arch/powerpc/platforms/embedded6xx/c2k.c
+++ b/arch/powerpc/platforms/embedded6xx/c2k.c
@@ -23,7 +23,6 @@
 
 #include <asm/machdep.h>
 #include <asm/prom.h>
-#include <asm/system.h>
 #include <asm/time.h>
 
 #include <mm/mmu_decl.h>
diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c
index 9cfcf20..8c305c7 100644
--- a/arch/powerpc/platforms/embedded6xx/holly.c
+++ b/arch/powerpc/platforms/embedded6xx/holly.c
@@ -28,7 +28,6 @@
 #include <linux/of_platform.h>
 #include <linux/module.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/prom.h>
@@ -154,11 +153,9 @@
 	struct device_node *cascade_node = NULL;
 #endif
 
-	mpic = mpic_alloc(NULL, 0,
-			MPIC_BIG_ENDIAN | MPIC_WANTS_RESET |
+	mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
 			MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108,
-			24,
-			NR_IRQS-4, /* num_sources used */
+			24, 0,
 			"Tsi108_PIC");
 
 	BUG_ON(mpic == NULL);
diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c
index bcfad92..455e7c08 100644
--- a/arch/powerpc/platforms/embedded6xx/linkstation.c
+++ b/arch/powerpc/platforms/embedded6xx/linkstation.c
@@ -82,8 +82,7 @@
 {
 	struct mpic *mpic;
 
-	mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET,
-			4, 32, " EPIC     ");
+	mpic = mpic_alloc(NULL, 0, 0, 4, 0, " EPIC     ");
 	BUG_ON(mpic == NULL);
 
 	/* PCI IRQs */
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
index f3350d7..beeaf4a 100644
--- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
+++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
@@ -32,7 +32,6 @@
 #include <linux/tty.h>
 #include <linux/serial_core.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/prom.h>
@@ -108,11 +107,9 @@
 	struct device_node *cascade_node = NULL;
 #endif
 
-	mpic = mpic_alloc(NULL, 0,
-			MPIC_BIG_ENDIAN | MPIC_WANTS_RESET |
+	mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
 			MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108,
-			24,
-			NR_IRQS-4, /* num_sources used */
+			24, 0,
 			"Tsi108_PIC");
 
 	BUG_ON(mpic == NULL);
diff --git a/arch/powerpc/platforms/embedded6xx/prpmc2800.c b/arch/powerpc/platforms/embedded6xx/prpmc2800.c
index 670035f..d455f08 100644
--- a/arch/powerpc/platforms/embedded6xx/prpmc2800.c
+++ b/arch/powerpc/platforms/embedded6xx/prpmc2800.c
@@ -17,7 +17,6 @@
 
 #include <asm/machdep.h>
 #include <asm/prom.h>
-#include <asm/system.h>
 #include <asm/time.h>
 
 #include <mm/mmu_decl.h>
diff --git a/arch/powerpc/platforms/embedded6xx/storcenter.c b/arch/powerpc/platforms/embedded6xx/storcenter.c
index afa6388..c458b60 100644
--- a/arch/powerpc/platforms/embedded6xx/storcenter.c
+++ b/arch/powerpc/platforms/embedded6xx/storcenter.c
@@ -16,7 +16,6 @@
 #include <linux/initrd.h>
 #include <linux/of_platform.h>
 
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/prom.h>
 #include <asm/mpic.h>
@@ -84,8 +83,7 @@
 {
 	struct mpic *mpic;
 
-	mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET,
-			16, 32, " OpenPIC  ");
+	mpic = mpic_alloc(NULL, 0, 0, 16, 0, " OpenPIC  ");
 	BUG_ON(mpic == NULL);
 
 	/*
diff --git a/arch/powerpc/platforms/fsl_uli1575.c b/arch/powerpc/platforms/fsl_uli1575.c
index 8b0c208..64fde05 100644
--- a/arch/powerpc/platforms/fsl_uli1575.c
+++ b/arch/powerpc/platforms/fsl_uli1575.c
@@ -15,7 +15,6 @@
 #include <linux/interrupt.h>
 #include <linux/mc146818rtc.h>
 
-#include <asm/system.h>
 #include <asm/pci-bridge.h>
 
 #define ULI_PIRQA	0x08
diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig
deleted file mode 100644
index 63835e0..0000000
--- a/arch/powerpc/platforms/iseries/Kconfig
+++ /dev/null
@@ -1,39 +0,0 @@
-config PPC_ISERIES
-	bool "IBM Legacy iSeries"
-	depends on PPC64 && PPC_BOOK3S
-	select OF_DYNAMIC
-	select PPC_SMP_MUXED_IPI
-	select PPC_INDIRECT_PIO
-	select PPC_INDIRECT_MMIO
-	select PPC_PCI_CHOICE if EXPERT
-
-menu "iSeries device drivers"
-	depends on PPC_ISERIES
-
-config VIODASD
-	tristate "iSeries Virtual I/O disk support"
-	depends on BLOCK
-	select VIOPATH
-	help
-	  If you are running on an iSeries system and you want to use
-	  virtual disks created and managed by OS/400, say Y.
-
-config VIOCD
-	tristate "iSeries Virtual I/O CD support"
-	depends on BLOCK
-	select VIOPATH
-	help
-	  If you are running Linux on an IBM iSeries system and you want to
-	  read a CD drive owned by OS/400, say Y here.
-
-config VIOTAPE
-	tristate "iSeries Virtual Tape Support"
-	select VIOPATH
-	help
-	  If you are running Linux on an iSeries system and you want Linux
-	  to read and/or write a tape drive owned by OS/400, say Y here.
-
-endmenu
-
-config VIOPATH
-	bool
diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile
deleted file mode 100644
index a7602b1..0000000
--- a/arch/powerpc/platforms/iseries/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-ccflags-y	:= -mno-minimal-toc
-
-obj-y += exception.o
-obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt.o mf.o lpevents.o \
-	hvcall.o proc.o htab.o iommu.o misc.o irq.o
-obj-$(CONFIG_PCI) += pci.o
-obj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_VIOPATH) += viopath.o vio.o
-obj-$(CONFIG_MODULES) += ksyms.o
diff --git a/arch/powerpc/platforms/iseries/call_hpt.h b/arch/powerpc/platforms/iseries/call_hpt.h
deleted file mode 100644
index 8d95fe4b..0000000
--- a/arch/powerpc/platforms/iseries/call_hpt.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef _PLATFORMS_ISERIES_CALL_HPT_H
-#define _PLATFORMS_ISERIES_CALL_HPT_H
-
-/*
- * This file contains the "hypervisor call" interface which is used to
- * drive the hypervisor from the OS.
- */
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/mmu.h>
-
-#define HvCallHptGetHptAddress		HvCallHpt +  0
-#define HvCallHptGetHptPages		HvCallHpt +  1
-#define HvCallHptSetPp			HvCallHpt +  5
-#define HvCallHptSetSwBits		HvCallHpt +  6
-#define HvCallHptUpdate			HvCallHpt +  7
-#define HvCallHptInvalidateNoSyncICache	HvCallHpt +  8
-#define HvCallHptGet			HvCallHpt + 11
-#define HvCallHptFindNextValid		HvCallHpt + 12
-#define HvCallHptFindValid		HvCallHpt + 13
-#define HvCallHptAddValidate		HvCallHpt + 16
-#define HvCallHptInvalidateSetSwBitsGet HvCallHpt + 18
-
-
-static inline u64 HvCallHpt_getHptAddress(void)
-{
-	return HvCall0(HvCallHptGetHptAddress);
-}
-
-static inline u64 HvCallHpt_getHptPages(void)
-{
-	return HvCall0(HvCallHptGetHptPages);
-}
-
-static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value)
-{
-	HvCall2(HvCallHptSetPp, hpteIndex, value);
-}
-
-static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff)
-{
-	HvCall3(HvCallHptSetSwBits, hpteIndex, bitson, bitsoff);
-}
-
-static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex)
-{
-	HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex);
-}
-
-static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson,
-		u8 bitsoff)
-{
-	u64 compressedStatus;
-
-	compressedStatus = HvCall4(HvCallHptInvalidateSetSwBitsGet,
-			hpteIndex, bitson, bitsoff, 1);
-	HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex);
-	return compressedStatus;
-}
-
-static inline u64 HvCallHpt_findValid(struct hash_pte *hpte, u64 vpn)
-{
-	return HvCall3Ret16(HvCallHptFindValid, hpte, vpn, 0, 0);
-}
-
-static inline u64 HvCallHpt_findNextValid(struct hash_pte *hpte, u32 hpteIndex,
-		u8 bitson, u8 bitsoff)
-{
-	return HvCall3Ret16(HvCallHptFindNextValid, hpte, hpteIndex,
-			bitson, bitsoff);
-}
-
-static inline void HvCallHpt_get(struct hash_pte *hpte, u32 hpteIndex)
-{
-	HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0);
-}
-
-static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit,
-					 struct hash_pte *hpte)
-{
-	HvCall4(HvCallHptAddValidate, hpteIndex, hBit, hpte->v, hpte->r);
-}
-
-#endif /* _PLATFORMS_ISERIES_CALL_HPT_H */
diff --git a/arch/powerpc/platforms/iseries/call_pci.h b/arch/powerpc/platforms/iseries/call_pci.h
deleted file mode 100644
index dbdf698..0000000
--- a/arch/powerpc/platforms/iseries/call_pci.h
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Provides the Hypervisor PCI calls for iSeries Linux Parition.
- * Copyright (C) 2001  <Wayne G Holm> <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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- *
- * Change Activity:
- *   Created, Jan 9, 2001
- */
-
-#ifndef _PLATFORMS_ISERIES_CALL_PCI_H
-#define _PLATFORMS_ISERIES_CALL_PCI_H
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-
-/*
- * DSA == Direct Select Address
- * this struct must be 64 bits in total
- */
-struct HvCallPci_DsaAddr {
-	u16		busNumber;		/* PHB index? */
-	u8		subBusNumber;		/* PCI bus number? */
-	u8		deviceId;		/* device and function? */
-	u8		barNumber;
-	u8		reserved[3];
-};
-
-union HvDsaMap {
-	u64	DsaAddr;
-	struct HvCallPci_DsaAddr Dsa;
-};
-
-struct HvCallPci_LoadReturn {
-	u64		rc;
-	u64		value;
-};
-
-enum HvCallPci_DeviceType {
-	HvCallPci_NodeDevice	= 1,
-	HvCallPci_SpDevice	= 2,
-	HvCallPci_IopDevice     = 3,
-	HvCallPci_BridgeDevice	= 4,
-	HvCallPci_MultiFunctionDevice = 5,
-	HvCallPci_IoaDevice	= 6
-};
-
-
-struct HvCallPci_DeviceInfo {
-	u32	deviceType;		/* See DeviceType enum for values */
-};
-
-struct HvCallPci_BusUnitInfo {
-	u32	sizeReturned;		/* length of data returned */
-	u32	deviceType;		/* see DeviceType enum for values */
-};
-
-struct HvCallPci_BridgeInfo {
-	struct HvCallPci_BusUnitInfo busUnitInfo;  /* Generic bus unit info */
-	u8		subBusNumber;	/* Bus number of secondary bus */
-	u8		maxAgents;	/* Max idsels on secondary bus */
-        u8              maxSubBusNumber; /* Max Sub Bus */
-	u8		logicalSlotNumber; /* Logical Slot Number for IOA */
-};
-
-
-/*
- * Maximum BusUnitInfo buffer size.  Provided for clients so
- * they can allocate a buffer big enough for any type of bus
- * unit.  Increase as needed.
- */
-enum {HvCallPci_MaxBusUnitInfoSize = 128};
-
-struct HvCallPci_BarParms {
-	u64		vaddr;
-	u64		raddr;
-	u64		size;
-	u64		protectStart;
-	u64		protectEnd;
-	u64		relocationOffset;
-	u64		pciAddress;
-	u64		reserved[3];
-};
-
-enum HvCallPci_VpdType {
-	HvCallPci_BusVpd	= 1,
-	HvCallPci_BusAdapterVpd	= 2
-};
-
-#define HvCallPciConfigLoad8		HvCallPci + 0
-#define HvCallPciConfigLoad16		HvCallPci + 1
-#define HvCallPciConfigLoad32		HvCallPci + 2
-#define HvCallPciConfigStore8		HvCallPci + 3
-#define HvCallPciConfigStore16		HvCallPci + 4
-#define HvCallPciConfigStore32		HvCallPci + 5
-#define HvCallPciEoi			HvCallPci + 16
-#define HvCallPciGetBarParms		HvCallPci + 18
-#define HvCallPciMaskFisr		HvCallPci + 20
-#define HvCallPciUnmaskFisr		HvCallPci + 21
-#define HvCallPciSetSlotReset		HvCallPci + 25
-#define HvCallPciGetDeviceInfo		HvCallPci + 27
-#define HvCallPciGetCardVpd		HvCallPci + 28
-#define HvCallPciBarLoad8		HvCallPci + 40
-#define HvCallPciBarLoad16		HvCallPci + 41
-#define HvCallPciBarLoad32		HvCallPci + 42
-#define HvCallPciBarLoad64		HvCallPci + 43
-#define HvCallPciBarStore8		HvCallPci + 44
-#define HvCallPciBarStore16		HvCallPci + 45
-#define HvCallPciBarStore32		HvCallPci + 46
-#define HvCallPciBarStore64		HvCallPci + 47
-#define HvCallPciMaskInterrupts		HvCallPci + 48
-#define HvCallPciUnmaskInterrupts	HvCallPci + 49
-#define HvCallPciGetBusUnitInfo		HvCallPci + 50
-
-static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber,
-		u8 deviceId, u32 offset, u16 *value)
-{
-	struct HvCallPci_DsaAddr dsa;
-	struct HvCallPci_LoadReturn retVal;
-
-	*((u64*)&dsa) = 0;
-
-	dsa.busNumber = busNumber;
-	dsa.subBusNumber = subBusNumber;
-	dsa.deviceId = deviceId;
-
-	HvCall3Ret16(HvCallPciConfigLoad16, &retVal, *(u64 *)&dsa, offset, 0);
-
-	*value = retVal.value;
-
-	return retVal.rc;
-}
-
-static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber,
-		u8 deviceId, u32 offset, u32 *value)
-{
-	struct HvCallPci_DsaAddr dsa;
-	struct HvCallPci_LoadReturn retVal;
-
-	*((u64*)&dsa) = 0;
-
-	dsa.busNumber = busNumber;
-	dsa.subBusNumber = subBusNumber;
-	dsa.deviceId = deviceId;
-
-	HvCall3Ret16(HvCallPciConfigLoad32, &retVal, *(u64 *)&dsa, offset, 0);
-
-	*value = retVal.value;
-
-	return retVal.rc;
-}
-
-static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber,
-		u8 deviceId, u32 offset, u8 value)
-{
-	struct HvCallPci_DsaAddr dsa;
-
-	*((u64*)&dsa) = 0;
-
-	dsa.busNumber = busNumber;
-	dsa.subBusNumber = subBusNumber;
-	dsa.deviceId = deviceId;
-
-	return HvCall4(HvCallPciConfigStore8, *(u64 *)&dsa, offset, value, 0);
-}
-
-static inline u64 HvCallPci_eoi(u16 busNumberParm, u8 subBusParm,
-		u8 deviceIdParm)
-{
-	struct HvCallPci_DsaAddr dsa;
-	struct HvCallPci_LoadReturn retVal;
-
-	*((u64*)&dsa) = 0;
-
-	dsa.busNumber = busNumberParm;
-	dsa.subBusNumber = subBusParm;
-	dsa.deviceId = deviceIdParm;
-
-	HvCall1Ret16(HvCallPciEoi, &retVal, *(u64*)&dsa);
-
-	return retVal.rc;
-}
-
-static inline u64 HvCallPci_getBarParms(u16 busNumberParm, u8 subBusParm,
-		u8 deviceIdParm, u8 barNumberParm, u64 parms, u32 sizeofParms)
-{
-	struct HvCallPci_DsaAddr dsa;
-
-	*((u64*)&dsa) = 0;
-
-	dsa.busNumber = busNumberParm;
-	dsa.subBusNumber = subBusParm;
-	dsa.deviceId = deviceIdParm;
-	dsa.barNumber = barNumberParm;
-
-	return HvCall3(HvCallPciGetBarParms, *(u64*)&dsa, parms, sizeofParms);
-}
-
-static inline u64 HvCallPci_maskFisr(u16 busNumberParm, u8 subBusParm,
-		u8 deviceIdParm, u64 fisrMask)
-{
-	struct HvCallPci_DsaAddr dsa;
-
-	*((u64*)&dsa) = 0;
-
-	dsa.busNumber = busNumberParm;
-	dsa.subBusNumber = subBusParm;
-	dsa.deviceId = deviceIdParm;
-
-	return HvCall2(HvCallPciMaskFisr, *(u64*)&dsa, fisrMask);
-}
-
-static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, u8 subBusParm,
-		u8 deviceIdParm, u64 fisrMask)
-{
-	struct HvCallPci_DsaAddr dsa;
-
-	*((u64*)&dsa) = 0;
-
-	dsa.busNumber = busNumberParm;
-	dsa.subBusNumber = subBusParm;
-	dsa.deviceId = deviceIdParm;
-
-	return HvCall2(HvCallPciUnmaskFisr, *(u64*)&dsa, fisrMask);
-}
-
-static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, u8 subBusParm,
-		u8 deviceNumberParm, u64 parms, u32 sizeofParms)
-{
-	struct HvCallPci_DsaAddr dsa;
-
-	*((u64*)&dsa) = 0;
-
-	dsa.busNumber = busNumberParm;
-	dsa.subBusNumber = subBusParm;
-	dsa.deviceId = deviceNumberParm << 4;
-
-	return HvCall3(HvCallPciGetDeviceInfo, *(u64*)&dsa, parms, sizeofParms);
-}
-
-static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, u8 subBusParm,
-		u8 deviceIdParm, u64 interruptMask)
-{
-	struct HvCallPci_DsaAddr dsa;
-
-	*((u64*)&dsa) = 0;
-
-	dsa.busNumber = busNumberParm;
-	dsa.subBusNumber = subBusParm;
-	dsa.deviceId = deviceIdParm;
-
-	return HvCall2(HvCallPciMaskInterrupts, *(u64*)&dsa, interruptMask);
-}
-
-static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, u8 subBusParm,
-		u8 deviceIdParm, u64 interruptMask)
-{
-	struct HvCallPci_DsaAddr dsa;
-
-	*((u64*)&dsa) = 0;
-
-	dsa.busNumber = busNumberParm;
-	dsa.subBusNumber = subBusParm;
-	dsa.deviceId = deviceIdParm;
-
-	return HvCall2(HvCallPciUnmaskInterrupts, *(u64*)&dsa, interruptMask);
-}
-
-static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, u8 subBusParm,
-		u8 deviceIdParm, u64 parms, u32 sizeofParms)
-{
-	struct HvCallPci_DsaAddr dsa;
-
-	*((u64*)&dsa) = 0;
-
-	dsa.busNumber = busNumberParm;
-	dsa.subBusNumber = subBusParm;
-	dsa.deviceId = deviceIdParm;
-
-	return HvCall3(HvCallPciGetBusUnitInfo, *(u64*)&dsa, parms,
-			sizeofParms);
-}
-
-static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm,
-		u16 sizeParm)
-{
-	u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm,
-			sizeParm, HvCallPci_BusVpd);
-	if (xRc == -1)
-		return -1;
-	else
-		return xRc & 0xFFFF;
-}
-
-#endif /* _PLATFORMS_ISERIES_CALL_PCI_H */
diff --git a/arch/powerpc/platforms/iseries/call_sm.h b/arch/powerpc/platforms/iseries/call_sm.h
deleted file mode 100644
index c7e2516..0000000
--- a/arch/powerpc/platforms/iseries/call_sm.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef _ISERIES_CALL_SM_H
-#define _ISERIES_CALL_SM_H
-
-/*
- * This file contains the "hypervisor call" interface which is used to
- * drive the hypervisor from the OS.
- */
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-
-#define HvCallSmGet64BitsOfAccessMap	HvCallSm  + 11
-
-static inline u64 HvCallSm_get64BitsOfAccessMap(HvLpIndex lpIndex,
-		u64 indexIntoBitMap)
-{
-	return HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex, indexIntoBitMap);
-}
-
-#endif /* _ISERIES_CALL_SM_H */
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c
deleted file mode 100644
index f0491cc..0000000
--- a/arch/powerpc/platforms/iseries/dt.c
+++ /dev/null
@@ -1,643 +0,0 @@
-/*
- *    Copyright (C) 2005-2006 Michael Ellerman, IBM Corporation
- *    Copyright (C) 2000-2004, IBM Corporation
- *
- *    Description:
- *      This file contains all the routines to build a flattened device
- *      tree for a legacy iSeries machine.
- *
- *      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.
- */
-
-#undef DEBUG
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/pci_regs.h>
-#include <linux/pci_ids.h>
-#include <linux/threads.h>
-#include <linux/bitops.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/if_ether.h>	/* ETH_ALEN */
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/lppaca.h>
-#include <asm/cputable.h>
-#include <asm/abs_addr.h>
-#include <asm/system.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/udbg.h>
-
-#include "processor_vpd.h"
-#include "call_hpt.h"
-#include "call_pci.h"
-#include "pci.h"
-#include "it_exp_vpd_panel.h"
-#include "naca.h"
-
-#ifdef DEBUG
-#define DBG(fmt...) udbg_printf(fmt)
-#else
-#define DBG(fmt...)
-#endif
-
-/*
- * These are created by the linker script at the start and end
- * of the section containing all the strings marked with the DS macro.
- */
-extern char __dt_strings_start[];
-extern char __dt_strings_end[];
-
-#define DS(s)	({	\
-	static const char __s[] __attribute__((section(".dt_strings"))) = s; \
-	__s;		\
-})
-
-struct iseries_flat_dt {
-	struct boot_param_header header;
-	u64 reserve_map[2];
-};
-
-static void * __initdata dt_data;
-
-/*
- * Putting these strings here keeps them out of the .dt_strings section
- * that we capture for the strings blob of the flattened device tree.
- */
-static char __initdata device_type_cpu[] = "cpu";
-static char __initdata device_type_memory[] = "memory";
-static char __initdata device_type_serial[] = "serial";
-static char __initdata device_type_network[] = "network";
-static char __initdata device_type_pci[] = "pci";
-static char __initdata device_type_vdevice[] = "vdevice";
-static char __initdata device_type_vscsi[] = "vscsi";
-
-
-/* EBCDIC to ASCII conversion routines */
-
-static unsigned char __init e2a(unsigned char x)
-{
-	switch (x) {
-	case 0x81 ... 0x89:
-		return x - 0x81 + 'a';
-	case 0x91 ... 0x99:
-		return x - 0x91 + 'j';
-	case 0xA2 ... 0xA9:
-		return x - 0xA2 + 's';
-	case 0xC1 ... 0xC9:
-		return x - 0xC1 + 'A';
-	case 0xD1 ... 0xD9:
-		return x - 0xD1 + 'J';
-	case 0xE2 ... 0xE9:
-		return x - 0xE2 + 'S';
-	case 0xF0 ... 0xF9:
-		return x - 0xF0 + '0';
-	}
-	return ' ';
-}
-
-static unsigned char * __init strne2a(unsigned char *dest,
-		const unsigned char *src, size_t n)
-{
-	int i;
-
-	n = strnlen(src, n);
-
-	for (i = 0; i < n; i++)
-		dest[i] = e2a(src[i]);
-
-	return dest;
-}
-
-static struct iseries_flat_dt * __init dt_init(void)
-{
-	struct iseries_flat_dt *dt;
-	unsigned long str_len;
-
-	str_len = __dt_strings_end - __dt_strings_start;
-	dt = (struct iseries_flat_dt *)ALIGN(klimit, 8);
-	dt->header.off_mem_rsvmap =
-		offsetof(struct iseries_flat_dt, reserve_map);
-	dt->header.off_dt_strings = ALIGN(sizeof(*dt), 8);
-	dt->header.off_dt_struct = dt->header.off_dt_strings
-		+ ALIGN(str_len, 8);
-	dt_data = (void *)((unsigned long)dt + dt->header.off_dt_struct);
-	dt->header.dt_strings_size = str_len;
-
-	/* There is no notion of hardware cpu id on iSeries */
-	dt->header.boot_cpuid_phys = smp_processor_id();
-
-	memcpy((char *)dt + dt->header.off_dt_strings, __dt_strings_start,
-			str_len);
-
-	dt->header.magic = OF_DT_HEADER;
-	dt->header.version = 0x10;
-	dt->header.last_comp_version = 0x10;
-
-	dt->reserve_map[0] = 0;
-	dt->reserve_map[1] = 0;
-
-	return dt;
-}
-
-static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value)
-{
-	*((u32 *)dt_data) = value;
-	dt_data += sizeof(u32);
-}
-
-#ifdef notyet
-static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value)
-{
-	*((u64 *)dt_data) = value;
-	dt_data += sizeof(u64);
-}
-#endif
-
-static void __init dt_push_bytes(struct iseries_flat_dt *dt, const char *data,
-		int len)
-{
-	memcpy(dt_data, data, len);
-	dt_data += ALIGN(len, 4);
-}
-
-static void __init dt_start_node(struct iseries_flat_dt *dt, const char *name)
-{
-	dt_push_u32(dt, OF_DT_BEGIN_NODE);
-	dt_push_bytes(dt, name, strlen(name) + 1);
-}
-
-#define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE)
-
-static void __init __dt_prop(struct iseries_flat_dt *dt, const char *name,
-		const void *data, int len)
-{
-	unsigned long offset;
-
-	dt_push_u32(dt, OF_DT_PROP);
-
-	/* Length of the data */
-	dt_push_u32(dt, len);
-
-	offset = name - __dt_strings_start;
-
-	/* The offset of the properties name in the string blob. */
-	dt_push_u32(dt, (u32)offset);
-
-	/* The actual data. */
-	dt_push_bytes(dt, data, len);
-}
-#define dt_prop(dt, name, data, len)	__dt_prop((dt), DS(name), (data), (len))
-
-#define dt_prop_str(dt, name, data)	\
-	dt_prop((dt), name, (data), strlen((data)) + 1); /* + 1 for NULL */
-
-static void __init __dt_prop_u32(struct iseries_flat_dt *dt, const char *name,
-		u32 data)
-{
-	__dt_prop(dt, name, &data, sizeof(u32));
-}
-#define dt_prop_u32(dt, name, data)	__dt_prop_u32((dt), DS(name), (data))
-
-static void __init __maybe_unused __dt_prop_u64(struct iseries_flat_dt *dt,
-		const char *name, u64 data)
-{
-	__dt_prop(dt, name, &data, sizeof(u64));
-}
-#define dt_prop_u64(dt, name, data)	__dt_prop_u64((dt), DS(name), (data))
-
-#define dt_prop_u64_list(dt, name, data, n)	\
-	dt_prop((dt), name, (data), sizeof(u64) * (n))
-
-#define dt_prop_u32_list(dt, name, data, n)	\
-	dt_prop((dt), name, (data), sizeof(u32) * (n))
-
-#define dt_prop_empty(dt, name)		dt_prop((dt), name, NULL, 0)
-
-static void __init dt_cpus(struct iseries_flat_dt *dt)
-{
-	unsigned char buf[32];
-	unsigned char *p;
-	unsigned int i, index;
-	struct IoHriProcessorVpd *d;
-	u32 pft_size[2];
-
-	/* yuck */
-	snprintf(buf, 32, "PowerPC,%s", cur_cpu_spec->cpu_name);
-	p = strchr(buf, ' ');
-	if (!p) p = buf + strlen(buf);
-
-	dt_start_node(dt, "cpus");
-	dt_prop_u32(dt, "#address-cells", 1);
-	dt_prop_u32(dt, "#size-cells", 0);
-
-	pft_size[0] = 0; /* NUMA CEC cookie, 0 for non NUMA  */
-	pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE);
-
-	for (i = 0; i < NR_LPPACAS; i++) {
-		if (lppaca[i].dyn_proc_status >= 2)
-			continue;
-
-		snprintf(p, 32 - (p - buf), "@%d", i);
-		dt_start_node(dt, buf);
-
-		dt_prop_str(dt, "device_type", device_type_cpu);
-
-		index = lppaca[i].dyn_hv_phys_proc_index;
-		d = &xIoHriProcessorVpd[index];
-
-		dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024);
-		dt_prop_u32(dt, "i-cache-line-size", d->xInstCacheOperandSize);
-
-		dt_prop_u32(dt, "d-cache-size", d->xDataL1CacheSizeKB * 1024);
-		dt_prop_u32(dt, "d-cache-line-size", d->xDataCacheOperandSize);
-
-		/* magic conversions to Hz copied from old code */
-		dt_prop_u32(dt, "clock-frequency",
-			((1UL << 34) * 1000000) / d->xProcFreq);
-		dt_prop_u32(dt, "timebase-frequency",
-			((1UL << 32) * 1000000) / d->xTimeBaseFreq);
-
-		dt_prop_u32(dt, "reg", i);
-
-		dt_prop_u32_list(dt, "ibm,pft-size", pft_size, 2);
-
-		dt_end_node(dt);
-	}
-
-	dt_end_node(dt);
-}
-
-static void __init dt_model(struct iseries_flat_dt *dt)
-{
-	char buf[16] = "IBM,";
-
-	/* N.B. lparcfg.c knows about the "IBM," prefixes ... */
-	/* "IBM," + mfgId[2:3] + systemSerial[1:5] */
-	strne2a(buf + 4, xItExtVpdPanel.mfgID + 2, 2);
-	strne2a(buf + 6, xItExtVpdPanel.systemSerial + 1, 5);
-	buf[11] = '\0';
-	dt_prop_str(dt, "system-id", buf);
-
-	/* "IBM," + machineType[0:4] */
-	strne2a(buf + 4, xItExtVpdPanel.machineType, 4);
-	buf[8] = '\0';
-	dt_prop_str(dt, "model", buf);
-
-	dt_prop_str(dt, "compatible", "IBM,iSeries");
-	dt_prop_u32(dt, "ibm,partition-no", HvLpConfig_getLpIndex());
-}
-
-static void __init dt_initrd(struct iseries_flat_dt *dt)
-{
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (naca.xRamDisk) {
-		dt_prop_u64(dt, "linux,initrd-start", (u64)naca.xRamDisk);
-		dt_prop_u64(dt, "linux,initrd-end",
-			(u64)naca.xRamDisk + naca.xRamDiskSize * HW_PAGE_SIZE);
-	}
-#endif
-}
-
-static void __init dt_do_vdevice(struct iseries_flat_dt *dt,
-		const char *name, u32 reg, int unit,
-		const char *type, const char *compat, int end)
-{
-	char buf[32];
-
-	snprintf(buf, 32, "%s@%08x", name, reg + ((unit >= 0) ? unit : 0));
-	dt_start_node(dt, buf);
-	dt_prop_str(dt, "device_type", type);
-	if (compat)
-		dt_prop_str(dt, "compatible", compat);
-	dt_prop_u32(dt, "reg", reg + ((unit >= 0) ? unit : 0));
-	if (unit >= 0)
-		dt_prop_u32(dt, "linux,unit_address", unit);
-	if (end)
-		dt_end_node(dt);
-}
-
-static void __init dt_vdevices(struct iseries_flat_dt *dt)
-{
-	u32 reg = 0;
-	HvLpIndexMap vlan_map;
-	int i;
-
-	dt_start_node(dt, "vdevice");
-	dt_prop_str(dt, "device_type", device_type_vdevice);
-	dt_prop_str(dt, "compatible", "IBM,iSeries-vdevice");
-	dt_prop_u32(dt, "#address-cells", 1);
-	dt_prop_u32(dt, "#size-cells", 0);
-
-	dt_do_vdevice(dt, "vty", reg, -1, device_type_serial,
-			"IBM,iSeries-vty", 1);
-	reg++;
-
-	dt_do_vdevice(dt, "v-scsi", reg, -1, device_type_vscsi,
-			"IBM,v-scsi", 1);
-	reg++;
-
-	vlan_map = HvLpConfig_getVirtualLanIndexMap();
-	for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
-		unsigned char mac_addr[ETH_ALEN];
-
-		if ((vlan_map & (0x8000 >> i)) == 0)
-			continue;
-		dt_do_vdevice(dt, "l-lan", reg, i, device_type_network,
-				"IBM,iSeries-l-lan", 0);
-		mac_addr[0] = 0x02;
-		mac_addr[1] = 0x01;
-		mac_addr[2] = 0xff;
-		mac_addr[3] = i;
-		mac_addr[4] = 0xff;
-		mac_addr[5] = HvLpConfig_getLpIndex_outline();
-		dt_prop(dt, "local-mac-address", (char *)mac_addr, ETH_ALEN);
-		dt_prop(dt, "mac-address", (char *)mac_addr, ETH_ALEN);
-		dt_prop_u32(dt, "max-frame-size", 9000);
-		dt_prop_u32(dt, "address-bits", 48);
-
-		dt_end_node(dt);
-	}
-
-	dt_end_node(dt);
-}
-
-struct pci_class_name {
-	u16 code;
-	const char *name;
-	const char *type;
-};
-
-static struct pci_class_name __initdata pci_class_name[] = {
-	{ PCI_CLASS_NETWORK_ETHERNET, "ethernet", device_type_network },
-};
-
-static struct pci_class_name * __init dt_find_pci_class_name(u16 class_code)
-{
-	struct pci_class_name *cp;
-
-	for (cp = pci_class_name;
-			cp < &pci_class_name[ARRAY_SIZE(pci_class_name)]; cp++)
-		if (cp->code == class_code)
-			return cp;
-	return NULL;
-}
-
-/*
- * This assumes that the node slot is always on the primary bus!
- */
-static void __init scan_bridge_slot(struct iseries_flat_dt *dt,
-		HvBusNumber bus, struct HvCallPci_BridgeInfo *bridge_info)
-{
-	HvSubBusNumber sub_bus = bridge_info->subBusNumber;
-	u16 vendor_id;
-	u16 device_id;
-	u32 class_id;
-	int err;
-	char buf[32];
-	u32 reg[5];
-	int id_sel = ISERIES_GET_DEVICE_FROM_SUBBUS(sub_bus);
-	int function = ISERIES_GET_FUNCTION_FROM_SUBBUS(sub_bus);
-	HvAgentId eads_id_sel = ISERIES_PCI_AGENTID(id_sel, function);
-	u8 devfn;
-	struct pci_class_name *cp;
-
-	/*
-	 * Connect all functions of any device found.
-	 */
-	for (id_sel = 1; id_sel <= bridge_info->maxAgents; id_sel++) {
-		for (function = 0; function < 8; function++) {
-			HvAgentId agent_id = ISERIES_PCI_AGENTID(id_sel,
-					function);
-			err = HvCallXm_connectBusUnit(bus, sub_bus,
-					agent_id, 0);
-			if (err) {
-				if (err != 0x302)
-					DBG("connectBusUnit(%x, %x, %x) %x\n",
-						bus, sub_bus, agent_id, err);
-				continue;
-			}
-
-			err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
-					PCI_VENDOR_ID, &vendor_id);
-			if (err) {
-				DBG("ReadVendor(%x, %x, %x) %x\n",
-					bus, sub_bus, agent_id, err);
-				continue;
-			}
-			err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
-					PCI_DEVICE_ID, &device_id);
-			if (err) {
-				DBG("ReadDevice(%x, %x, %x) %x\n",
-					bus, sub_bus, agent_id, err);
-				continue;
-			}
-			err = HvCallPci_configLoad32(bus, sub_bus, agent_id,
-					PCI_CLASS_REVISION , &class_id);
-			if (err) {
-				DBG("ReadClass(%x, %x, %x) %x\n",
-					bus, sub_bus, agent_id, err);
-				continue;
-			}
-
-			devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(eads_id_sel),
-					function);
-			cp = dt_find_pci_class_name(class_id >> 16);
-			if (cp && cp->name)
-				strncpy(buf, cp->name, sizeof(buf) - 1);
-			else
-				snprintf(buf, sizeof(buf), "pci%x,%x",
-						vendor_id, device_id);
-			buf[sizeof(buf) - 1] = '\0';
-			snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-					"@%x", PCI_SLOT(devfn));
-			buf[sizeof(buf) - 1] = '\0';
-			if (function != 0)
-				snprintf(buf + strlen(buf),
-					sizeof(buf) - strlen(buf),
-					",%x", function);
-			dt_start_node(dt, buf);
-			reg[0] = (bus << 16) | (devfn << 8);
-			reg[1] = 0;
-			reg[2] = 0;
-			reg[3] = 0;
-			reg[4] = 0;
-			dt_prop_u32_list(dt, "reg", reg, 5);
-			if (cp && (cp->type || cp->name))
-				dt_prop_str(dt, "device_type",
-					cp->type ? cp->type : cp->name);
-			dt_prop_u32(dt, "vendor-id", vendor_id);
-			dt_prop_u32(dt, "device-id", device_id);
-			dt_prop_u32(dt, "class-code", class_id >> 8);
-			dt_prop_u32(dt, "revision-id", class_id & 0xff);
-			dt_prop_u32(dt, "linux,subbus", sub_bus);
-			dt_prop_u32(dt, "linux,agent-id", agent_id);
-			dt_prop_u32(dt, "linux,logical-slot-number",
-					bridge_info->logicalSlotNumber);
-			dt_end_node(dt);
-
-		}
-	}
-}
-
-static void __init scan_bridge(struct iseries_flat_dt *dt, HvBusNumber bus,
-		HvSubBusNumber sub_bus, int id_sel)
-{
-	struct HvCallPci_BridgeInfo bridge_info;
-	HvAgentId agent_id;
-	int function;
-	int ret;
-
-	/* Note: hvSubBus and irq is always be 0 at this level! */
-	for (function = 0; function < 8; ++function) {
-		agent_id = ISERIES_PCI_AGENTID(id_sel, function);
-		ret = HvCallXm_connectBusUnit(bus, sub_bus, agent_id, 0);
-		if (ret != 0) {
-			if (ret != 0xb)
-				DBG("connectBusUnit(%x, %x, %x) %x\n",
-						bus, sub_bus, agent_id, ret);
-			continue;
-		}
-		DBG("found device at bus %d idsel %d func %d (AgentId %x)\n",
-				bus, id_sel, function, agent_id);
-		ret = HvCallPci_getBusUnitInfo(bus, sub_bus, agent_id,
-				iseries_hv_addr(&bridge_info),
-				sizeof(struct HvCallPci_BridgeInfo));
-		if (ret != 0)
-			continue;
-		DBG("bridge info: type %x subbus %x "
-			"maxAgents %x maxsubbus %x logslot %x\n",
-			bridge_info.busUnitInfo.deviceType,
-			bridge_info.subBusNumber,
-			bridge_info.maxAgents,
-			bridge_info.maxSubBusNumber,
-			bridge_info.logicalSlotNumber);
-		if (bridge_info.busUnitInfo.deviceType ==
-				HvCallPci_BridgeDevice)
-			scan_bridge_slot(dt, bus, &bridge_info);
-		else
-			DBG("PCI: Invalid Bridge Configuration(0x%02X)",
-				bridge_info.busUnitInfo.deviceType);
-	}
-}
-
-static void __init scan_phb(struct iseries_flat_dt *dt, HvBusNumber bus)
-{
-	struct HvCallPci_DeviceInfo dev_info;
-	const HvSubBusNumber sub_bus = 0;	/* EADs is always 0. */
-	int err;
-	int id_sel;
-	const int max_agents = 8;
-
-	/*
-	 * Probe for EADs Bridges
-	 */
-	for (id_sel = 1; id_sel < max_agents; ++id_sel) {
-		err = HvCallPci_getDeviceInfo(bus, sub_bus, id_sel,
-				iseries_hv_addr(&dev_info),
-				sizeof(struct HvCallPci_DeviceInfo));
-		if (err) {
-			if (err != 0x302)
-				DBG("getDeviceInfo(%x, %x, %x) %x\n",
-						bus, sub_bus, id_sel, err);
-			continue;
-		}
-		if (dev_info.deviceType != HvCallPci_NodeDevice) {
-			DBG("PCI: Invalid System Configuration"
-					"(0x%02X) for bus 0x%02x id 0x%02x.\n",
-					dev_info.deviceType, bus, id_sel);
-			continue;
-		}
-		scan_bridge(dt, bus, sub_bus, id_sel);
-	}
-}
-
-static void __init dt_pci_devices(struct iseries_flat_dt *dt)
-{
-	HvBusNumber bus;
-	char buf[32];
-	u32 buses[2];
-	int phb_num = 0;
-
-	/* Check all possible buses. */
-	for (bus = 0; bus < 256; bus++) {
-		int err = HvCallXm_testBus(bus);
-
-		if (err) {
-			/*
-			 * Check for Unexpected Return code, a clue that
-			 * something has gone wrong.
-			 */
-			if (err != 0x0301)
-				DBG("Unexpected Return on Probe(0x%02X) "
-						"0x%04X\n", bus, err);
-			continue;
-		}
-		DBG("bus %d appears to exist\n", bus);
-		snprintf(buf, 32, "pci@%d", phb_num);
-		dt_start_node(dt, buf);
-		dt_prop_str(dt, "device_type", device_type_pci);
-		dt_prop_str(dt, "compatible", "IBM,iSeries-Logical-PHB");
-		dt_prop_u32(dt, "#address-cells", 3);
-		dt_prop_u32(dt, "#size-cells", 2);
-		buses[0] = buses[1] = bus;
-		dt_prop_u32_list(dt, "bus-range", buses, 2);
-		scan_phb(dt, bus);
-		dt_end_node(dt);
-		phb_num++;
-	}
-}
-
-static void dt_finish(struct iseries_flat_dt *dt)
-{
-	dt_push_u32(dt, OF_DT_END);
-	dt->header.totalsize = (unsigned long)dt_data - (unsigned long)dt;
-	klimit = ALIGN((unsigned long)dt_data, 8);
-}
-
-void * __init build_flat_dt(unsigned long phys_mem_size)
-{
-	struct iseries_flat_dt *iseries_dt;
-	u64 tmp[2];
-
-	iseries_dt = dt_init();
-
-	dt_start_node(iseries_dt, "");
-
-	dt_prop_u32(iseries_dt, "#address-cells", 2);
-	dt_prop_u32(iseries_dt, "#size-cells", 2);
-	dt_model(iseries_dt);
-
-	/* /memory */
-	dt_start_node(iseries_dt, "memory@0");
-	dt_prop_str(iseries_dt, "device_type", device_type_memory);
-	tmp[0] = 0;
-	tmp[1] = phys_mem_size;
-	dt_prop_u64_list(iseries_dt, "reg", tmp, 2);
-	dt_end_node(iseries_dt);
-
-	/* /chosen */
-	dt_start_node(iseries_dt, "chosen");
-	dt_prop_str(iseries_dt, "bootargs", cmd_line);
-	dt_initrd(iseries_dt);
-	dt_end_node(iseries_dt);
-
-	dt_cpus(iseries_dt);
-
-	dt_vdevices(iseries_dt);
-	dt_pci_devices(iseries_dt);
-
-	dt_end_node(iseries_dt);
-
-	dt_finish(iseries_dt);
-
-	return iseries_dt;
-}
diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S
deleted file mode 100644
index f519ee1..0000000
--- a/arch/powerpc/platforms/iseries/exception.S
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- *  Low level routines for legacy iSeries support.
- *
- *  Extracted from head_64.S
- *
- *  PowerPC version
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
- *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
- *  Adapted for Power Macintosh by Paul Mackerras.
- *  Low-level exception handlers and MMU support
- *  rewritten by Paul Mackerras.
- *    Copyright (C) 1996 Paul Mackerras.
- *
- *  Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and
- *    Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com
- *
- *  This file contains the low-level support and setup for the
- *  PowerPC-64 platform, including trap and interrupt dispatch.
- *
- *  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 <asm/reg.h>
-#include <asm/ppc_asm.h>
-#include <asm/asm-offsets.h>
-#include <asm/thread_info.h>
-#include <asm/ptrace.h>
-#include <asm/cputable.h>
-#include <asm/mmu.h>
-
-#include "exception.h"
-
-	.text
-
-	.globl system_reset_iSeries
-system_reset_iSeries:
-	bl	.relative_toc
-	mfspr	r13,SPRN_SPRG3		/* Get alpaca address */
-	LOAD_REG_ADDR(r23, alpaca)
-	li	r0,ALPACA_SIZE
-	sub	r23,r13,r23
-	divdu	r24,r23,r0		/* r24 has cpu number */
-	cmpwi	0,r24,0			/* Are we processor 0? */
-	bne	1f
-	LOAD_REG_ADDR(r13, boot_paca)
-	mtspr	SPRN_SPRG_PACA,r13	/* Save it away for the future */
-	mfmsr	r23
-	ori	r23,r23,MSR_RI
-	mtmsrd	r23			/* RI on */
-	b	.__start_initialization_iSeries	/* Start up the first processor */
-1:	mfspr	r4,SPRN_CTRLF
-	li	r5,CTRL_RUNLATCH	/* Turn off the run light */
-	andc	r4,r4,r5
-	mtspr	SPRN_CTRLT,r4
-
-/* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */
-/* In the UP case we'll yield() later, and we will not access the paca anyway */
-#ifdef CONFIG_SMP
-iSeries_secondary_wait_paca:
-	HMT_LOW
-	LOAD_REG_ADDR(r23, __secondary_hold_spinloop)
-	ld	r23,0(r23)
-
-	cmpdi	0,r23,0
-	bne	2f			/* go on when the master is ready */
-
-	/* Keep poking the Hypervisor until we're released */
-	/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
-	lis	r3,0x8002
-	rldicr	r3,r3,32,15		/* r0 = (r3 << 32) & 0xffff000000000000 */
-	li	r0,-1			/* r0=-1 indicates a Hypervisor call */
-	sc				/* Invoke the hypervisor via a system call */
-	b	iSeries_secondary_wait_paca
-
-2:
-	HMT_MEDIUM
-	sync
-
-	LOAD_REG_ADDR(r3, nr_cpu_ids)	/* get number of pacas allocated */
-	lwz	r3,0(r3)		/* nr_cpus= or NR_CPUS can limit */
-	cmpld	0,r24,r3		/* is our cpu number allocated? */
-	bge	iSeries_secondary_yield	/* no, yield forever */
-
-	/* Load our paca now that it's been allocated */
-	LOAD_REG_ADDR(r13, paca)
-	ld	r13,0(r13)
-	mulli	r0,r24,PACA_SIZE
-	add	r13,r13,r0
-	mtspr	SPRN_SPRG_PACA,r13	/* Save it away for the future */
-	mfmsr	r23
-	ori	r23,r23,MSR_RI
-	mtmsrd	r23			/* RI on */
-
-iSeries_secondary_smp_loop:
-	lbz	r23,PACAPROCSTART(r13)	/* Test if this processor
-					 * should start */
-	cmpwi	0,r23,0
-	bne	3f			/* go on when we are told */
-
-	HMT_LOW
-	/* Let the Hypervisor know we are alive */
-	/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
-	lis	r3,0x8002
-	rldicr	r3,r3,32,15		/* r0 = (r3 << 32) & 0xffff000000000000 */
-	li	r0,-1			/* r0=-1 indicates a Hypervisor call */
-	sc				/* Invoke the hypervisor via a system call */
-	mfspr	r13,SPRN_SPRG_PACA	/* Put r13 back ???? */
-	b	iSeries_secondary_smp_loop /* wait for signal to start */
-
-3:
-	HMT_MEDIUM
-	sync
-	LOAD_REG_ADDR(r3,current_set)
-	sldi	r28,r24,3		/* get current_set[cpu#] */
-	ldx	r3,r3,r28
-	addi	r1,r3,THREAD_SIZE
-	subi	r1,r1,STACK_FRAME_OVERHEAD
-
-	b	__secondary_start		/* Loop until told to go */
-#endif /* CONFIG_SMP */
-
-iSeries_secondary_yield:
-	/* Yield the processor.  This is required for non-SMP kernels
-		which are running on multi-threaded machines. */
-	HMT_LOW
-	lis	r3,0x8000
-	rldicr	r3,r3,32,15		/* r3 = (r3 << 32) & 0xffff000000000000 */
-	addi	r3,r3,18		/* r3 = 0x8000000000000012 which is "yield" */
-	li	r4,0			/* "yield timed" */
-	li	r5,-1			/* "yield forever" */
-	li	r0,-1			/* r0=-1 indicates a Hypervisor call */
-	sc				/* Invoke the hypervisor via a system call */
-	mfspr	r13,SPRN_SPRG_PACA	/* Put r13 back ???? */
-	b	iSeries_secondary_yield	/* If SMP not configured, secondaries
-					 * loop forever */
-
-/***  ISeries-LPAR interrupt handlers ***/
-
-	STD_EXCEPTION_ISERIES(machine_check, PACA_EXMC)
-
-	.globl data_access_iSeries
-data_access_iSeries:
-	mtspr	SPRN_SPRG_SCRATCH0,r13
-BEGIN_FTR_SECTION
-	mfspr	r13,SPRN_SPRG_PACA
-	std	r9,PACA_EXSLB+EX_R9(r13)
-	std	r10,PACA_EXSLB+EX_R10(r13)
-	mfspr	r10,SPRN_DAR
-	mfspr	r9,SPRN_DSISR
-	srdi	r10,r10,60
-	rlwimi	r10,r9,16,0x20
-	mfcr	r9
-	cmpwi	r10,0x2c
-	beq	.do_stab_bolted_iSeries
-	ld	r10,PACA_EXSLB+EX_R10(r13)
-	std	r11,PACA_EXGEN+EX_R11(r13)
-	ld	r11,PACA_EXSLB+EX_R9(r13)
-	std	r12,PACA_EXGEN+EX_R12(r13)
-	mfspr	r12,SPRN_SPRG_SCRATCH0
-	std	r10,PACA_EXGEN+EX_R10(r13)
-	std	r11,PACA_EXGEN+EX_R9(r13)
-	std	r12,PACA_EXGEN+EX_R13(r13)
-	EXCEPTION_PROLOG_ISERIES_1
-FTR_SECTION_ELSE
-	EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0)
-	EXCEPTION_PROLOG_ISERIES_1
-ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB)
-	b	data_access_common
-
-.do_stab_bolted_iSeries:
-	std	r11,PACA_EXSLB+EX_R11(r13)
-	std	r12,PACA_EXSLB+EX_R12(r13)
-	mfspr	r10,SPRN_SPRG_SCRATCH0
-	std	r10,PACA_EXSLB+EX_R13(r13)
-	EXCEPTION_PROLOG_ISERIES_1
-	b	.do_stab_bolted
-
-	.globl	data_access_slb_iSeries
-data_access_slb_iSeries:
-	mtspr	SPRN_SPRG_SCRATCH0,r13	/* save r13 */
-	mfspr	r13,SPRN_SPRG_PACA	/* get paca address into r13 */
-	std	r3,PACA_EXSLB+EX_R3(r13)
-	mfspr	r3,SPRN_DAR
-	std	r9,PACA_EXSLB+EX_R9(r13)
-	mfcr	r9
-#ifdef __DISABLED__
-	cmpdi	r3,0
-	bge	slb_miss_user_iseries
-#endif
-	std	r10,PACA_EXSLB+EX_R10(r13)
-	std	r11,PACA_EXSLB+EX_R11(r13)
-	std	r12,PACA_EXSLB+EX_R12(r13)
-	mfspr	r10,SPRN_SPRG_SCRATCH0
-	std	r10,PACA_EXSLB+EX_R13(r13)
-	ld	r12,PACALPPACAPTR(r13)
-	ld	r12,LPPACASRR1(r12)
-	b	.slb_miss_realmode
-
-	STD_EXCEPTION_ISERIES(instruction_access, PACA_EXGEN)
-
-	.globl	instruction_access_slb_iSeries
-instruction_access_slb_iSeries:
-	mtspr	SPRN_SPRG_SCRATCH0,r13	/* save r13 */
-	mfspr	r13,SPRN_SPRG_PACA	/* get paca address into r13 */
-	std	r3,PACA_EXSLB+EX_R3(r13)
-	ld	r3,PACALPPACAPTR(r13)
-	ld	r3,LPPACASRR0(r3)	/* get SRR0 value */
-	std	r9,PACA_EXSLB+EX_R9(r13)
-	mfcr	r9
-#ifdef __DISABLED__
-	cmpdi	r3,0
-	bge	slb_miss_user_iseries
-#endif
-	std	r10,PACA_EXSLB+EX_R10(r13)
-	std	r11,PACA_EXSLB+EX_R11(r13)
-	std	r12,PACA_EXSLB+EX_R12(r13)
-	mfspr	r10,SPRN_SPRG_SCRATCH0
-	std	r10,PACA_EXSLB+EX_R13(r13)
-	ld	r12,PACALPPACAPTR(r13)
-	ld	r12,LPPACASRR1(r12)
-	b	.slb_miss_realmode
-
-#ifdef __DISABLED__
-slb_miss_user_iseries:
-	std	r10,PACA_EXGEN+EX_R10(r13)
-	std	r11,PACA_EXGEN+EX_R11(r13)
-	std	r12,PACA_EXGEN+EX_R12(r13)
-	mfspr	r10,SPRG_SCRATCH0
-	ld	r11,PACA_EXSLB+EX_R9(r13)
-	ld	r12,PACA_EXSLB+EX_R3(r13)
-	std	r10,PACA_EXGEN+EX_R13(r13)
-	std	r11,PACA_EXGEN+EX_R9(r13)
-	std	r12,PACA_EXGEN+EX_R3(r13)
-	EXCEPTION_PROLOG_ISERIES_1
-	b	slb_miss_user_common
-#endif
-
-	MASKABLE_EXCEPTION_ISERIES(hardware_interrupt)
-	STD_EXCEPTION_ISERIES(alignment, PACA_EXGEN)
-	STD_EXCEPTION_ISERIES(program_check, PACA_EXGEN)
-	STD_EXCEPTION_ISERIES(fp_unavailable, PACA_EXGEN)
-	MASKABLE_EXCEPTION_ISERIES(decrementer)
-	STD_EXCEPTION_ISERIES(trap_0a, PACA_EXGEN)
-	STD_EXCEPTION_ISERIES(trap_0b, PACA_EXGEN)
-
-	.globl	system_call_iSeries
-system_call_iSeries:
-	mr	r9,r13
-	mfspr	r13,SPRN_SPRG_PACA
-	EXCEPTION_PROLOG_ISERIES_1
-	b	system_call_common
-
-	STD_EXCEPTION_ISERIES(single_step, PACA_EXGEN)
-	STD_EXCEPTION_ISERIES(trap_0e, PACA_EXGEN)
-	STD_EXCEPTION_ISERIES(performance_monitor, PACA_EXGEN)
-
-decrementer_iSeries_masked:
-	/* We may not have a valid TOC pointer in here. */
-	li	r11,1
-	ld	r12,PACALPPACAPTR(r13)
-	stb	r11,LPPACADECRINT(r12)
-	li	r12,-1
-	clrldi	r12,r12,33	/* set DEC to 0x7fffffff */
-	mtspr	SPRN_DEC,r12
-	/* fall through */
-
-hardware_interrupt_iSeries_masked:
-	mtcrf	0x80,r9		/* Restore regs */
-	ld	r12,PACALPPACAPTR(r13)
-	ld	r11,LPPACASRR0(r12)
-	ld	r12,LPPACASRR1(r12)
-	mtspr	SPRN_SRR0,r11
-	mtspr	SPRN_SRR1,r12
-	ld	r9,PACA_EXGEN+EX_R9(r13)
-	ld	r10,PACA_EXGEN+EX_R10(r13)
-	ld	r11,PACA_EXGEN+EX_R11(r13)
-	ld	r12,PACA_EXGEN+EX_R12(r13)
-	ld	r13,PACA_EXGEN+EX_R13(r13)
-	rfid
-	b	.	/* prevent speculative execution */
-
-_INIT_STATIC(__start_initialization_iSeries)
-	/* Clear out the BSS */
-	LOAD_REG_ADDR(r11,__bss_stop)
-	LOAD_REG_ADDR(r8,__bss_start)
-	sub	r11,r11,r8		/* bss size			*/
-	addi	r11,r11,7		/* round up to an even double word */
-	rldicl. r11,r11,61,3		/* shift right by 3		*/
-	beq	4f
-	addi	r8,r8,-8
-	li	r0,0
-	mtctr	r11			/* zero this many doublewords	*/
-3:	stdu	r0,8(r8)
-	bdnz	3b
-4:
-	LOAD_REG_ADDR(r1,init_thread_union)
-	addi	r1,r1,THREAD_SIZE
-	li	r0,0
-	stdu	r0,-STACK_FRAME_OVERHEAD(r1)
-
-	bl	.iSeries_early_setup
-	bl	.early_setup
-
-	/* relocation is on at this point */
-
-	b	.start_here_common
diff --git a/arch/powerpc/platforms/iseries/exception.h b/arch/powerpc/platforms/iseries/exception.h
deleted file mode 100644
index 50271b5..0000000
--- a/arch/powerpc/platforms/iseries/exception.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef _ASM_POWERPC_ISERIES_EXCEPTION_H
-#define _ASM_POWERPC_ISERIES_EXCEPTION_H
-/*
- * Extracted from head_64.S
- *
- *  PowerPC version
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
- *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
- *  Adapted for Power Macintosh by Paul Mackerras.
- *  Low-level exception handlers and MMU support
- *  rewritten by Paul Mackerras.
- *    Copyright (C) 1996 Paul Mackerras.
- *
- *  Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and
- *    Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com
- *
- *  This file contains the low-level support and setup for the
- *  PowerPC-64 platform, including trap and interrupt dispatch.
- *
- *  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 <asm/exception-64s.h>
-
-#define EXCEPTION_PROLOG_ISERIES_1					\
-	mfmsr	r10;							\
-	ld	r12,PACALPPACAPTR(r13);					\
-	ld	r11,LPPACASRR0(r12);					\
-	ld	r12,LPPACASRR1(r12);					\
-	ori	r10,r10,MSR_RI;						\
-	mtmsrd	r10,1
-
-#define STD_EXCEPTION_ISERIES(label, area)				\
-	.globl label##_iSeries;						\
-label##_iSeries:							\
-	HMT_MEDIUM;							\
-	mtspr	SPRN_SPRG_SCRATCH0,r13;	/* save r13 */			\
-	EXCEPTION_PROLOG_1(area, NOTEST, 0);				\
-	EXCEPTION_PROLOG_ISERIES_1;					\
-	b	label##_common
-
-#define MASKABLE_EXCEPTION_ISERIES(label)				\
-	.globl label##_iSeries;						\
-label##_iSeries:							\
-	HMT_MEDIUM;							\
-	mtspr	SPRN_SPRG_SCRATCH0,r13;	/* save r13 */			\
-	EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0);			\
-	lbz	r10,PACASOFTIRQEN(r13);					\
-	cmpwi	0,r10,0;						\
-	beq-	label##_iSeries_masked;					\
-	EXCEPTION_PROLOG_ISERIES_1;					\
-	b	label##_common;						\
-
-#endif	/* _ASM_POWERPC_ISERIES_EXCEPTION_H */
diff --git a/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c
deleted file mode 100644
index 3ae66ab..0000000
--- a/arch/powerpc/platforms/iseries/htab.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * iSeries hashtable management.
- *	Derived from pSeries_htab.c
- *
- * SMP scalability work:
- *    Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
- *
- * 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 <asm/machdep.h>
-#include <asm/pgtable.h>
-#include <asm/mmu.h>
-#include <asm/mmu_context.h>
-#include <asm/abs_addr.h>
-#include <linux/spinlock.h>
-
-#include "call_hpt.h"
-
-static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp;
-
-/*
- * Very primitive algorithm for picking up a lock
- */
-static inline void iSeries_hlock(unsigned long slot)
-{
-	if (slot & 0x8)
-		slot = ~slot;
-	spin_lock(&iSeries_hlocks[(slot >> 4) & 0x3f]);
-}
-
-static inline void iSeries_hunlock(unsigned long slot)
-{
-	if (slot & 0x8)
-		slot = ~slot;
-	spin_unlock(&iSeries_hlocks[(slot >> 4) & 0x3f]);
-}
-
-static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
-			 unsigned long pa, unsigned long rflags,
-			 unsigned long vflags, int psize, int ssize)
-{
-	long slot;
-	struct hash_pte lhpte;
-	int secondary = 0;
-
-	BUG_ON(psize != MMU_PAGE_4K);
-
-	/*
-	 * The hypervisor tries both primary and secondary.
-	 * If we are being called to insert in the secondary,
-	 * it means we have already tried both primary and secondary,
-	 * so we return failure immediately.
-	 */
-	if (vflags & HPTE_V_SECONDARY)
-		return -1;
-
-	iSeries_hlock(hpte_group);
-
-	slot = HvCallHpt_findValid(&lhpte, va >> HW_PAGE_SHIFT);
-	if (unlikely(lhpte.v & HPTE_V_VALID)) {
-		if (vflags & HPTE_V_BOLTED) {
-			HvCallHpt_setSwBits(slot, 0x10, 0);
-			HvCallHpt_setPp(slot, PP_RWXX);
-			iSeries_hunlock(hpte_group);
-			if (slot < 0)
-				return 0x8 | (slot & 7);
-			else
-				return slot & 7;
-		}
-		BUG();
-	}
-
-	if (slot == -1)	{ /* No available entry found in either group */
-		iSeries_hunlock(hpte_group);
-		return -1;
-	}
-
-	if (slot < 0) {		/* MSB set means secondary group */
-		vflags |= HPTE_V_SECONDARY;
-		secondary = 1;
-		slot &= 0x7fffffffffffffff;
-	}
-
-
-	lhpte.v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M) |
-		vflags | HPTE_V_VALID;
-	lhpte.r = hpte_encode_r(phys_to_abs(pa), MMU_PAGE_4K) | rflags;
-
-	/* Now fill in the actual HPTE */
-	HvCallHpt_addValidate(slot, secondary, &lhpte);
-
-	iSeries_hunlock(hpte_group);
-
-	return (secondary << 3) | (slot & 7);
-}
-
-static unsigned long iSeries_hpte_getword0(unsigned long slot)
-{
-	struct hash_pte hpte;
-
-	HvCallHpt_get(&hpte, slot);
-	return hpte.v;
-}
-
-static long iSeries_hpte_remove(unsigned long hpte_group)
-{
-	unsigned long slot_offset;
-	int i;
-	unsigned long hpte_v;
-
-	/* Pick a random slot to start at */
-	slot_offset = mftb() & 0x7;
-
-	iSeries_hlock(hpte_group);
-
-	for (i = 0; i < HPTES_PER_GROUP; i++) {
-		hpte_v = iSeries_hpte_getword0(hpte_group + slot_offset);
-
-		if (! (hpte_v & HPTE_V_BOLTED)) {
-			HvCallHpt_invalidateSetSwBitsGet(hpte_group +
-							 slot_offset, 0, 0);
-			iSeries_hunlock(hpte_group);
-			return i;
-		}
-
-		slot_offset++;
-		slot_offset &= 0x7;
-	}
-
-	iSeries_hunlock(hpte_group);
-
-	return -1;
-}
-
-/*
- * The HyperVisor expects the "flags" argument in this form:
- *	bits  0..59 : reserved
- *	bit      60 : N
- *	bits 61..63 : PP2,PP1,PP0
- */
-static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp,
-			unsigned long va, int psize, int ssize, int local)
-{
-	struct hash_pte hpte;
-	unsigned long want_v;
-
-	iSeries_hlock(slot);
-
-	HvCallHpt_get(&hpte, slot);
-	want_v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M);
-
-	if (HPTE_V_COMPARE(hpte.v, want_v) && (hpte.v & HPTE_V_VALID)) {
-		/*
-		 * Hypervisor expects bits as NPPP, which is
-		 * different from how they are mapped in our PP.
-		 */
-		HvCallHpt_setPp(slot, (newpp & 0x3) | ((newpp & 0x4) << 1));
-		iSeries_hunlock(slot);
-		return 0;
-	}
-	iSeries_hunlock(slot);
-
-	return -1;
-}
-
-/*
- * Functions used to find the PTE for a particular virtual address.
- * Only used during boot when bolting pages.
- *
- * Input : vpn      : virtual page number
- * Output: PTE index within the page table of the entry
- *         -1 on failure
- */
-static long iSeries_hpte_find(unsigned long vpn)
-{
-	struct hash_pte hpte;
-	long slot;
-
-	/*
-	 * The HvCallHpt_findValid interface is as follows:
-	 * 0xffffffffffffffff : No entry found.
-	 * 0x00000000xxxxxxxx : Entry found in primary group, slot x
-	 * 0x80000000xxxxxxxx : Entry found in secondary group, slot x
-	 */
-	slot = HvCallHpt_findValid(&hpte, vpn);
-	if (hpte.v & HPTE_V_VALID) {
-		if (slot < 0) {
-			slot &= 0x7fffffffffffffff;
-			slot = -slot;
-		}
-	} else
-		slot = -1;
-	return slot;
-}
-
-/*
- * Update the page protection bits. Intended to be used to create
- * guard pages for kernel data structures on pages which are bolted
- * in the HPT. Assumes pages being operated on will not be stolen.
- * Does not work on large pages.
- *
- * No need to lock here because we should be the only user.
- */
-static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
-					int psize, int ssize)
-{
-	unsigned long vsid,va,vpn;
-	long slot;
-
-	BUG_ON(psize != MMU_PAGE_4K);
-
-	vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M);
-	va = (vsid << 28) | (ea & 0x0fffffff);
-	vpn = va >> HW_PAGE_SHIFT;
-	slot = iSeries_hpte_find(vpn);
-	if (slot == -1)
-		panic("updateboltedpp: Could not find page to bolt\n");
-	HvCallHpt_setPp(slot, newpp);
-}
-
-static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va,
-				    int psize, int ssize, int local)
-{
-	unsigned long hpte_v;
-	unsigned long avpn = va >> 23;
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	iSeries_hlock(slot);
-
-	hpte_v = iSeries_hpte_getword0(slot);
-
-	if ((HPTE_V_AVPN_VAL(hpte_v) == avpn) && (hpte_v & HPTE_V_VALID))
-		HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0);
-
-	iSeries_hunlock(slot);
-
-	local_irq_restore(flags);
-}
-
-void __init hpte_init_iSeries(void)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(iSeries_hlocks); i++)
-		spin_lock_init(&iSeries_hlocks[i]);
-
-	ppc_md.hpte_invalidate	= iSeries_hpte_invalidate;
-	ppc_md.hpte_updatepp	= iSeries_hpte_updatepp;
-	ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp;
-	ppc_md.hpte_insert	= iSeries_hpte_insert;
-	ppc_md.hpte_remove	= iSeries_hpte_remove;
-}
diff --git a/arch/powerpc/platforms/iseries/hvcall.S b/arch/powerpc/platforms/iseries/hvcall.S
deleted file mode 100644
index 07ae6ad..0000000
--- a/arch/powerpc/platforms/iseries/hvcall.S
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * This file contains the code to perform calls to the
- * iSeries LPAR hypervisor
- *
- * 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 <asm/ppc_asm.h>
-#include <asm/processor.h>
-#include <asm/ptrace.h>		/* XXX for STACK_FRAME_OVERHEAD */
-
-	.text
-
-/*
- * Hypervisor call
- *
- * Invoke the iSeries hypervisor via the System Call instruction
- * Parameters are passed to this routine in registers r3 - r10
- *
- * r3 contains the HV function to be called
- * r4-r10 contain the operands to the hypervisor function
- *
- */
-
-_GLOBAL(HvCall)
-_GLOBAL(HvCall0)
-_GLOBAL(HvCall1)
-_GLOBAL(HvCall2)
-_GLOBAL(HvCall3)
-_GLOBAL(HvCall4)
-_GLOBAL(HvCall5)
-_GLOBAL(HvCall6)
-_GLOBAL(HvCall7)
-
-
-	mfcr	r0
-	std	r0,-8(r1)
-	stdu	r1,-(STACK_FRAME_OVERHEAD+16)(r1)
-
-	/* r0 = 0xffffffffffffffff indicates a hypervisor call */
-
-	li	r0,-1
-
-	/* Invoke the hypervisor */
-
-	sc
-
-	ld	r1,0(r1)
-	ld	r0,-8(r1)
-	mtcrf	0xff,r0
-
-	/*  return to caller, return value in r3 */
-
-	blr
-
-_GLOBAL(HvCall0Ret16)
-_GLOBAL(HvCall1Ret16)
-_GLOBAL(HvCall2Ret16)
-_GLOBAL(HvCall3Ret16)
-_GLOBAL(HvCall4Ret16)
-_GLOBAL(HvCall5Ret16)
-_GLOBAL(HvCall6Ret16)
-_GLOBAL(HvCall7Ret16)
-
-	mfcr	r0
-	std	r0,-8(r1)
-	std	r31,-16(r1)
-	stdu	r1,-(STACK_FRAME_OVERHEAD+32)(r1)
-
-	mr	r31,r4
-	li	r0,-1
-	mr	r4,r5
-	mr	r5,r6
-	mr	r6,r7
-	mr	r7,r8
-	mr	r8,r9
-	mr	r9,r10
-
-	sc
-
-	std	r3,0(r31)
-	std	r4,8(r31)
-
-	mr	r3,r5
-
-	ld	r1,0(r1)
-	ld	r0,-8(r1)
-	mtcrf	0xff,r0
-	ld	r31,-16(r1)
-
-	blr
diff --git a/arch/powerpc/platforms/iseries/hvlog.c b/arch/powerpc/platforms/iseries/hvlog.c
deleted file mode 100644
index f476d71..0000000
--- a/arch/powerpc/platforms/iseries/hvlog.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- */
-
-#include <asm/page.h>
-#include <asm/abs_addr.h>
-#include <asm/iseries/hv_call.h>
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-
-
-void HvCall_writeLogBuffer(const void *buffer, u64 len)
-{
-	struct HvLpBufferList hv_buf;
-	u64 left_this_page;
-	u64 cur = virt_to_abs(buffer);
-
-	while (len) {
-		hv_buf.addr = cur;
-		left_this_page = ((cur & HW_PAGE_MASK) + HW_PAGE_SIZE) - cur;
-		if (left_this_page > len)
-			left_this_page = len;
-		hv_buf.len = left_this_page;
-		len -= left_this_page;
-		HvCall2(HvCallBaseWriteLogBuffer,
-				virt_to_abs(&hv_buf),
-				left_this_page);
-		cur = (cur & HW_PAGE_MASK) + HW_PAGE_SIZE;
-	}
-}
diff --git a/arch/powerpc/platforms/iseries/hvlpconfig.c b/arch/powerpc/platforms/iseries/hvlpconfig.c
deleted file mode 100644
index f62a0c5..0000000
--- a/arch/powerpc/platforms/iseries/hvlpconfig.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2001  Kyle A. Lucke, 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.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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/export.h>
-#include <asm/iseries/hv_lp_config.h>
-#include "it_lp_naca.h"
-
-HvLpIndex HvLpConfig_getLpIndex_outline(void)
-{
-	return HvLpConfig_getLpIndex();
-}
-EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline);
-
-HvLpIndex HvLpConfig_getLpIndex(void)
-{
-	return itLpNaca.xLpIndex;
-}
-EXPORT_SYMBOL(HvLpConfig_getLpIndex);
-
-HvLpIndex HvLpConfig_getPrimaryLpIndex(void)
-{
-	return itLpNaca.xPrimaryLpIndex;
-}
-EXPORT_SYMBOL_GPL(HvLpConfig_getPrimaryLpIndex);
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
deleted file mode 100644
index 2f3d911..0000000
--- a/arch/powerpc/platforms/iseries/iommu.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
- *
- * Rewrite, cleanup:
- *
- * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
- * Copyright (C) 2006 Olof Johansson <olof@lixom.net>
- *
- * Dynamic DMA mapping support, iSeries-specific parts.
- *
- *
- * 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/types.h>
-#include <linux/dma-mapping.h>
-#include <linux/list.h>
-#include <linux/pci.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-
-#include <asm/iommu.h>
-#include <asm/vio.h>
-#include <asm/tce.h>
-#include <asm/machdep.h>
-#include <asm/abs_addr.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/iseries/hv_call_event.h>
-#include <asm/iseries/iommu.h>
-
-static int tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
-		unsigned long uaddr, enum dma_data_direction direction,
-		struct dma_attrs *attrs)
-{
-	u64 rc;
-	u64 tce, rpn;
-
-	while (npages--) {
-		rpn = virt_to_abs(uaddr) >> TCE_SHIFT;
-		tce = (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;
-
-		if (tbl->it_type == TCE_VB) {
-			/* Virtual Bus */
-			tce |= TCE_VALID|TCE_ALLIO;
-			if (direction != DMA_TO_DEVICE)
-				tce |= TCE_VB_WRITE;
-		} else {
-			/* PCI Bus */
-			tce |= TCE_PCI_READ; /* Read allowed */
-			if (direction != DMA_TO_DEVICE)
-				tce |= TCE_PCI_WRITE;
-		}
-
-		rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, tce);
-		if (rc)
-			panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n",
-					rc);
-		index++;
-		uaddr += TCE_PAGE_SIZE;
-	}
-	return 0;
-}
-
-static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages)
-{
-	u64 rc;
-
-	while (npages--) {
-		rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, 0);
-		if (rc)
-			panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n",
-					rc);
-		index++;
-	}
-}
-
-/*
- * Structure passed to HvCallXm_getTceTableParms
- */
-struct iommu_table_cb {
-	unsigned long	itc_busno;	/* Bus number for this tce table */
-	unsigned long	itc_start;	/* Will be NULL for secondary */
-	unsigned long	itc_totalsize;	/* Size (in pages) of whole table */
-	unsigned long	itc_offset;	/* Index into real tce table of the
-					   start of our section */
-	unsigned long	itc_size;	/* Size (in pages) of our section */
-	unsigned long	itc_index;	/* Index of this tce table */
-	unsigned short	itc_maxtables;	/* Max num of tables for partition */
-	unsigned char	itc_virtbus;	/* Flag to indicate virtual bus */
-	unsigned char	itc_slotno;	/* IOA Tce Slot Index */
-	unsigned char	itc_rsvd[4];
-};
-
-/*
- * Call Hv with the architected data structure to get TCE table info.
- * info. Put the returned data into the Linux representation of the
- * TCE table data.
- * The Hardware Tce table comes in three flavors.
- * 1. TCE table shared between Buses.
- * 2. TCE table per Bus.
- * 3. TCE Table per IOA.
- */
-void iommu_table_getparms_iSeries(unsigned long busno,
-				  unsigned char slotno,
-				  unsigned char virtbus,
-				  struct iommu_table* tbl)
-{
-	struct iommu_table_cb *parms;
-
-	parms = kzalloc(sizeof(*parms), GFP_KERNEL);
-	if (parms == NULL)
-		panic("PCI_DMA: TCE Table Allocation failed.");
-
-	parms->itc_busno = busno;
-	parms->itc_slotno = slotno;
-	parms->itc_virtbus = virtbus;
-
-	HvCallXm_getTceTableParms(iseries_hv_addr(parms));
-
-	if (parms->itc_size == 0)
-		panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms);
-
-	/* itc_size is in pages worth of table, it_size is in # of entries */
-	tbl->it_size = (parms->itc_size * TCE_PAGE_SIZE) / TCE_ENTRY_SIZE;
-	tbl->it_busno = parms->itc_busno;
-	tbl->it_offset = parms->itc_offset;
-	tbl->it_index = parms->itc_index;
-	tbl->it_blocksize = 1;
-	tbl->it_type = virtbus ? TCE_VB : TCE_PCI;
-
-	kfree(parms);
-}
-
-
-#ifdef CONFIG_PCI
-/*
- * This function compares the known tables to find an iommu_table
- * that has already been built for hardware TCEs.
- */
-static struct iommu_table *iommu_table_find(struct iommu_table * tbl)
-{
-	struct device_node *node;
-
-	for (node = NULL; (node = of_find_all_nodes(node)); ) {
-		struct pci_dn *pdn = PCI_DN(node);
-		struct iommu_table *it;
-
-		if (pdn == NULL)
-			continue;
-		it = pdn->iommu_table;
-		if ((it != NULL) &&
-		    (it->it_type == TCE_PCI) &&
-		    (it->it_offset == tbl->it_offset) &&
-		    (it->it_index == tbl->it_index) &&
-		    (it->it_size == tbl->it_size)) {
-			of_node_put(node);
-			return it;
-		}
-	}
-	return NULL;
-}
-
-
-static void pci_dma_dev_setup_iseries(struct pci_dev *pdev)
-{
-	struct iommu_table *tbl;
-	struct device_node *dn = pci_device_to_OF_node(pdev);
-	struct pci_dn *pdn = PCI_DN(dn);
-	const u32 *lsn = of_get_property(dn, "linux,logical-slot-number", NULL);
-
-	BUG_ON(lsn == NULL);
-
-	tbl = kzalloc(sizeof(struct iommu_table), GFP_KERNEL);
-
-	iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl);
-
-	/* Look for existing tce table */
-	pdn->iommu_table = iommu_table_find(tbl);
-	if (pdn->iommu_table == NULL)
-		pdn->iommu_table = iommu_init_table(tbl, -1);
-	else
-		kfree(tbl);
-	set_iommu_table_base(&pdev->dev, pdn->iommu_table);
-}
-#else
-#define pci_dma_dev_setup_iseries	NULL
-#endif
-
-static struct iommu_table veth_iommu_table;
-static struct iommu_table vio_iommu_table;
-
-void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag)
-{
-	return iommu_alloc_coherent(NULL, &vio_iommu_table, size, dma_handle,
-				DMA_BIT_MASK(32), flag, -1);
-}
-EXPORT_SYMBOL_GPL(iseries_hv_alloc);
-
-void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle)
-{
-	iommu_free_coherent(&vio_iommu_table, size, vaddr, dma_handle);
-}
-EXPORT_SYMBOL_GPL(iseries_hv_free);
-
-dma_addr_t iseries_hv_map(void *vaddr, size_t size,
-			enum dma_data_direction direction)
-{
-	return iommu_map_page(NULL, &vio_iommu_table, virt_to_page(vaddr),
-			      (unsigned long)vaddr % PAGE_SIZE, size,
-			      DMA_BIT_MASK(32), direction, NULL);
-}
-
-void iseries_hv_unmap(dma_addr_t dma_handle, size_t size,
-			enum dma_data_direction direction)
-{
-	iommu_unmap_page(&vio_iommu_table, dma_handle, size, direction, NULL);
-}
-
-void __init iommu_vio_init(void)
-{
-	iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table);
-	veth_iommu_table.it_size /= 2;
-	vio_iommu_table = veth_iommu_table;
-	vio_iommu_table.it_offset += veth_iommu_table.it_size;
-
-	if (!iommu_init_table(&veth_iommu_table, -1))
-		printk("Virtual Bus VETH TCE table failed.\n");
-	if (!iommu_init_table(&vio_iommu_table, -1))
-		printk("Virtual Bus VIO TCE table failed.\n");
-}
-
-struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev)
-{
-	if (strcmp(dev->type, "network") == 0)
-		return &veth_iommu_table;
-	return &vio_iommu_table;
-}
-
-void iommu_init_early_iSeries(void)
-{
-	ppc_md.tce_build = tce_build_iSeries;
-	ppc_md.tce_free  = tce_free_iSeries;
-
-	ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_iseries;
-	set_pci_dma_ops(&dma_iommu_ops);
-}
diff --git a/arch/powerpc/platforms/iseries/ipl_parms.h b/arch/powerpc/platforms/iseries/ipl_parms.h
deleted file mode 100644
index 83e4ca4..0000000
--- a/arch/powerpc/platforms/iseries/ipl_parms.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef _ISERIES_IPL_PARMS_H
-#define _ISERIES_IPL_PARMS_H
-
-/*
- *	This struct maps the IPL Parameters DMA'd from the SP.
- *
- * Warning:
- *	This data must map in exactly 64 bytes and match the architecture for
- *	the IPL parms
- */
-
-#include <asm/types.h>
-
-struct ItIplParmsReal {
-	u8	xFormat;		// Defines format of IplParms	x00-x00
-	u8	xRsvd01:6;		// Reserved			x01-x01
-	u8	xAlternateSearch:1;	// Alternate search indicator	...
-	u8	xUaSupplied:1;		// UA Supplied on programmed IPL...
-	u8	xLsUaFormat;		// Format byte for UA		x02-x02
-	u8	xRsvd02;		// Reserved			x03-x03
-	u32	xLsUa;			// LS UA			x04-x07
-	u32	xUnusedLsLid;		// First OS LID to load		x08-x0B
-	u16	xLsBusNumber;		// LS Bus Number		x0C-x0D
-	u8	xLsCardAdr;		// LS Card Address		x0E-x0E
-	u8	xLsBoardAdr;		// LS Board Address		x0F-x0F
-	u32	xRsvd03;		// Reserved			x10-x13
-	u8	xSpcnPresent:1;		// SPCN present			x14-x14
-	u8	xCpmPresent:1;		// CPM present			...
-	u8	xRsvd04:6;		// Reserved			...
-	u8	xRsvd05:4;		// Reserved			x15-x15
-	u8	xKeyLock:4;		// Keylock setting		...
-	u8	xRsvd06:6;		// Reserved			x16-x16
-	u8	xIplMode:2;		// Ipl mode (A|B|C|D)		...
-	u8	xHwIplType;		// Fast v slow v slow EC HW IPL	x17-x17
-	u16	xCpmEnabledIpl:1;	// CPM in effect when IPL initiatedx18-x19
-	u16	xPowerOnResetIpl:1;	// Indicate POR condition	...
-	u16	xMainStorePreserved:1;	// Main Storage is preserved	...
-	u16	xRsvd07:13;		// Reserved			...
-	u16	xIplSource:16;		// Ipl source			x1A-x1B
-	u8	xIplReason:8;		// Reason for this IPL		x1C-x1C
-	u8	xRsvd08;		// Reserved			x1D-x1D
-	u16	xRsvd09;		// Reserved			x1E-x1F
-	u16	xSysBoxType;		// System Box Type		x20-x21
-	u16	xSysProcType;		// System Processor Type	x22-x23
-	u32	xRsvd10;		// Reserved			x24-x27
-	u64	xRsvd11;		// Reserved			x28-x2F
-	u64	xRsvd12;		// Reserved			x30-x37
-	u64	xRsvd13;		// Reserved			x38-x3F
-};
-
-#endif /* _ISERIES_IPL_PARMS_H */
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
deleted file mode 100644
index 05ce516..0000000
--- a/arch/powerpc/platforms/iseries/irq.c
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * This module supports the iSeries PCI bus interrupt handling
- * Copyright (C) 20yy  <Robert L Holtorf> <IBM Corp>
- * Copyright (C) 2004-2005 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- *
- * Change Activity:
- *   Created, December 13, 2000 by Wayne Holm
- * End Change Activity
- */
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/threads.h>
-#include <linux/smp.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/bootmem.h>
-#include <linux/irq.h>
-#include <linux/spinlock.h>
-
-#include <asm/paca.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/iseries/it_lp_queue.h>
-
-#include "irq.h"
-#include "pci.h"
-#include "call_pci.h"
-
-#ifdef CONFIG_PCI
-
-enum pci_event_type {
-	pe_bus_created		= 0,	/* PHB has been created */
-	pe_bus_error		= 1,	/* PHB has failed */
-	pe_bus_failed		= 2,	/* Msg to Secondary, Primary failed bus */
-	pe_node_failed		= 4,	/* Multi-adapter bridge has failed */
-	pe_node_recovered	= 5,	/* Multi-adapter bridge has recovered */
-	pe_bus_recovered	= 12,	/* PHB has been recovered */
-	pe_unquiese_bus		= 18,	/* Secondary bus unqiescing */
-	pe_bridge_error		= 21,	/* Bridge Error */
-	pe_slot_interrupt	= 22	/* Slot interrupt */
-};
-
-struct pci_event {
-	struct HvLpEvent event;
-	union {
-		u64 __align;		/* Align on an 8-byte boundary */
-		struct {
-			u32		fisr;
-			HvBusNumber	bus_number;
-			HvSubBusNumber	sub_bus_number;
-			HvAgentId	dev_id;
-		} slot;
-		struct {
-			HvBusNumber	bus_number;
-			HvSubBusNumber	sub_bus_number;
-		} bus;
-		struct {
-			HvBusNumber	bus_number;
-			HvSubBusNumber	sub_bus_number;
-			HvAgentId	dev_id;
-		} node;
-	} data;
-};
-
-static DEFINE_SPINLOCK(pending_irqs_lock);
-static int num_pending_irqs;
-static int pending_irqs[NR_IRQS];
-
-static void int_received(struct pci_event *event)
-{
-	int irq;
-
-	switch (event->event.xSubtype) {
-	case pe_slot_interrupt:
-		irq = event->event.xCorrelationToken;
-		if (irq < NR_IRQS) {
-			spin_lock(&pending_irqs_lock);
-			pending_irqs[irq]++;
-			num_pending_irqs++;
-			spin_unlock(&pending_irqs_lock);
-		} else {
-			printk(KERN_WARNING "int_received: bad irq number %d\n",
-					irq);
-			HvCallPci_eoi(event->data.slot.bus_number,
-					event->data.slot.sub_bus_number,
-					event->data.slot.dev_id);
-		}
-		break;
-		/* Ignore error recovery events for now */
-	case pe_bus_created:
-		printk(KERN_INFO "int_received: system bus %d created\n",
-			event->data.bus.bus_number);
-		break;
-	case pe_bus_error:
-	case pe_bus_failed:
-		printk(KERN_INFO "int_received: system bus %d failed\n",
-			event->data.bus.bus_number);
-		break;
-	case pe_bus_recovered:
-	case pe_unquiese_bus:
-		printk(KERN_INFO "int_received: system bus %d recovered\n",
-			event->data.bus.bus_number);
-		break;
-	case pe_node_failed:
-	case pe_bridge_error:
-		printk(KERN_INFO
-			"int_received: multi-adapter bridge %d/%d/%d failed\n",
-			event->data.node.bus_number,
-			event->data.node.sub_bus_number,
-			event->data.node.dev_id);
-		break;
-	case pe_node_recovered:
-		printk(KERN_INFO
-			"int_received: multi-adapter bridge %d/%d/%d recovered\n",
-			event->data.node.bus_number,
-			event->data.node.sub_bus_number,
-			event->data.node.dev_id);
-		break;
-	default:
-		printk(KERN_ERR
-			"int_received: unrecognized event subtype 0x%x\n",
-			event->event.xSubtype);
-		break;
-	}
-}
-
-static void pci_event_handler(struct HvLpEvent *event)
-{
-	if (event && (event->xType == HvLpEvent_Type_PciIo)) {
-		if (hvlpevent_is_int(event))
-			int_received((struct pci_event *)event);
-		else
-			printk(KERN_ERR
-				"pci_event_handler: unexpected ack received\n");
-	} else if (event)
-		printk(KERN_ERR
-			"pci_event_handler: Unrecognized PCI event type 0x%x\n",
-			(int)event->xType);
-	else
-		printk(KERN_ERR "pci_event_handler: NULL event received\n");
-}
-
-#define REAL_IRQ_TO_SUBBUS(irq)	(((irq) >> 14) & 0xff)
-#define REAL_IRQ_TO_BUS(irq)	((((irq) >> 6) & 0xff) + 1)
-#define REAL_IRQ_TO_IDSEL(irq)	((((irq) >> 3) & 7) + 1)
-#define REAL_IRQ_TO_FUNC(irq)	((irq) & 7)
-
-/*
- * This will be called by device drivers (via enable_IRQ)
- * to enable INTA in the bridge interrupt status register.
- */
-static void iseries_enable_IRQ(struct irq_data *d)
-{
-	u32 bus, dev_id, function, mask;
-	const u32 sub_bus = 0;
-	unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
-
-	/* The IRQ has already been locked by the caller */
-	bus = REAL_IRQ_TO_BUS(rirq);
-	function = REAL_IRQ_TO_FUNC(rirq);
-	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
-
-	/* Unmask secondary INTA */
-	mask = 0x80000000;
-	HvCallPci_unmaskInterrupts(bus, sub_bus, dev_id, mask);
-}
-
-/* This is called by iseries_activate_IRQs */
-static unsigned int iseries_startup_IRQ(struct irq_data *d)
-{
-	u32 bus, dev_id, function, mask;
-	const u32 sub_bus = 0;
-	unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
-
-	bus = REAL_IRQ_TO_BUS(rirq);
-	function = REAL_IRQ_TO_FUNC(rirq);
-	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
-
-	/* Link the IRQ number to the bridge */
-	HvCallXm_connectBusUnit(bus, sub_bus, dev_id, d->irq);
-
-	/* Unmask bridge interrupts in the FISR */
-	mask = 0x01010000 << function;
-	HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask);
-	iseries_enable_IRQ(d);
-	return 0;
-}
-
-/*
- * This is called out of iSeries_fixup to activate interrupt
- * generation for usable slots
- */
-void __init iSeries_activate_IRQs()
-{
-	int irq;
-	unsigned long flags;
-
-	for_each_irq (irq) {
-		struct irq_desc *desc = irq_to_desc(irq);
-		struct irq_chip *chip;
-
-		if (!desc)
-			continue;
-
-		chip = irq_desc_get_chip(desc);
-		if (chip && chip->irq_startup) {
-			raw_spin_lock_irqsave(&desc->lock, flags);
-			chip->irq_startup(&desc->irq_data);
-			raw_spin_unlock_irqrestore(&desc->lock, flags);
-		}
-	}
-}
-
-/*  this is not called anywhere currently */
-static void iseries_shutdown_IRQ(struct irq_data *d)
-{
-	u32 bus, dev_id, function, mask;
-	const u32 sub_bus = 0;
-	unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
-
-	/* irq should be locked by the caller */
-	bus = REAL_IRQ_TO_BUS(rirq);
-	function = REAL_IRQ_TO_FUNC(rirq);
-	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
-
-	/* Invalidate the IRQ number in the bridge */
-	HvCallXm_connectBusUnit(bus, sub_bus, dev_id, 0);
-
-	/* Mask bridge interrupts in the FISR */
-	mask = 0x01010000 << function;
-	HvCallPci_maskFisr(bus, sub_bus, dev_id, mask);
-}
-
-/*
- * This will be called by device drivers (via disable_IRQ)
- * to disable INTA in the bridge interrupt status register.
- */
-static void iseries_disable_IRQ(struct irq_data *d)
-{
-	u32 bus, dev_id, function, mask;
-	const u32 sub_bus = 0;
-	unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
-
-	/* The IRQ has already been locked by the caller */
-	bus = REAL_IRQ_TO_BUS(rirq);
-	function = REAL_IRQ_TO_FUNC(rirq);
-	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
-
-	/* Mask secondary INTA   */
-	mask = 0x80000000;
-	HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask);
-}
-
-static void iseries_end_IRQ(struct irq_data *d)
-{
-	unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
-
-	HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq),
-		(REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
-}
-
-static struct irq_chip iseries_pic = {
-	.name		= "iSeries",
-	.irq_startup	= iseries_startup_IRQ,
-	.irq_shutdown	= iseries_shutdown_IRQ,
-	.irq_unmask	= iseries_enable_IRQ,
-	.irq_mask	= iseries_disable_IRQ,
-	.irq_eoi	= iseries_end_IRQ
-};
-
-/*
- * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot
- * It calculates the irq value for the slot.
- * Note that sub_bus is always 0 (at the moment at least).
- */
-int __init iSeries_allocate_IRQ(HvBusNumber bus,
-		HvSubBusNumber sub_bus, u32 bsubbus)
-{
-	unsigned int realirq;
-	u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus);
-	u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus);
-
-	realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
-		+ function;
-
-	return irq_create_mapping(NULL, realirq);
-}
-
-#endif /* CONFIG_PCI */
-
-/*
- * Get the next pending IRQ.
- */
-unsigned int iSeries_get_irq(void)
-{
-	int irq = NO_IRQ_IGNORE;
-
-#ifdef CONFIG_SMP
-	if (get_lppaca()->int_dword.fields.ipi_cnt) {
-		get_lppaca()->int_dword.fields.ipi_cnt = 0;
-		smp_ipi_demux();
-	}
-#endif /* CONFIG_SMP */
-	if (hvlpevent_is_pending())
-		process_hvlpevents();
-
-#ifdef CONFIG_PCI
-	if (num_pending_irqs) {
-		spin_lock(&pending_irqs_lock);
-		for (irq = 0; irq < NR_IRQS; irq++) {
-			if (pending_irqs[irq]) {
-				pending_irqs[irq]--;
-				num_pending_irqs--;
-				break;
-			}
-		}
-		spin_unlock(&pending_irqs_lock);
-		if (irq >= NR_IRQS)
-			irq = NO_IRQ_IGNORE;
-	}
-#endif
-
-	return irq;
-}
-
-#ifdef CONFIG_PCI
-
-static int iseries_irq_host_map(struct irq_domain *h, unsigned int virq,
-				irq_hw_number_t hw)
-{
-	irq_set_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq);
-
-	return 0;
-}
-
-static int iseries_irq_host_match(struct irq_domain *h, struct device_node *np)
-{
-	/* Match all */
-	return 1;
-}
-
-static const struct irq_domain_ops iseries_irq_domain_ops = {
-	.map = iseries_irq_host_map,
-	.match = iseries_irq_host_match,
-};
-
-/*
- * This is called by init_IRQ.  set in ppc_md.init_IRQ by iSeries_setup.c
- * It must be called before the bus walk.
- */
-void __init iSeries_init_IRQ(void)
-{
-	/* Register PCI event handler and open an event path */
-	struct irq_domain *host;
-	int ret;
-
-	/*
-	 * The Hypervisor only allows us up to 256 interrupt
-	 * sources (the irq number is passed in a u8).
-	 */
-	irq_set_virq_count(256);
-
-	/* Create irq host. No need for a revmap since HV will give us
-	 * back our virtual irq number
-	 */
-	host = irq_domain_add_nomap(NULL, &iseries_irq_domain_ops, NULL);
-	BUG_ON(host == NULL);
-	irq_set_default_host(host);
-
-	ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
-			&pci_event_handler);
-	if (ret == 0) {
-		ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
-		if (ret != 0)
-			printk(KERN_ERR "iseries_init_IRQ: open event path "
-					"failed with rc 0x%x\n", ret);
-	} else
-		printk(KERN_ERR "iseries_init_IRQ: register handler "
-				"failed with rc 0x%x\n", ret);
-}
-
-#endif	/* CONFIG_PCI */
diff --git a/arch/powerpc/platforms/iseries/irq.h b/arch/powerpc/platforms/iseries/irq.h
deleted file mode 100644
index a1c2360..0000000
--- a/arch/powerpc/platforms/iseries/irq.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef	_ISERIES_IRQ_H
-#define	_ISERIES_IRQ_H
-
-#ifdef CONFIG_PCI
-extern void iSeries_init_IRQ(void);
-extern int  iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32);
-extern void iSeries_activate_IRQs(void);
-#else
-#define iSeries_init_IRQ	NULL
-#endif
-extern unsigned int iSeries_get_irq(void);
-
-#endif /* _ISERIES_IRQ_H */
diff --git a/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h b/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h
deleted file mode 100644
index 6de9097..0000000
--- a/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2002  Dave Boutcher 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H
-#define _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H
-
-/*
- *	This struct maps the panel information
- *
- * Warning:
- *	This data must match the architecture for the panel information
- */
-
-#include <asm/types.h>
-
-struct ItExtVpdPanel {
-	/* Definition of the Extended Vpd On Panel Data Area */
-	char	systemSerial[8];
-	char	mfgID[4];
-	char	reserved1[24];
-	char	machineType[4];
-	char	systemID[6];
-	char	somUniqueCnt[4];
-	char	serialNumberCount;
-	char	reserved2[7];
-	u16	bbu3;
-	u16	bbu2;
-	u16	bbu1;
-	char	xLocationLabel[8];
-	u8	xRsvd1[6];
-	u16	xFrameId;
-	u8	xRsvd2[48];
-};
-
-extern struct ItExtVpdPanel	xItExtVpdPanel;
-
-#endif /* _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H */
diff --git a/arch/powerpc/platforms/iseries/it_lp_naca.h b/arch/powerpc/platforms/iseries/it_lp_naca.h
deleted file mode 100644
index cf6dcf6..0000000
--- a/arch/powerpc/platforms/iseries/it_lp_naca.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef _PLATFORMS_ISERIES_IT_LP_NACA_H
-#define _PLATFORMS_ISERIES_IT_LP_NACA_H
-
-#include <linux/types.h>
-
-/*
- *	This control block contains the data that is shared between the
- *	hypervisor (PLIC) and the OS.
- */
-
-struct ItLpNaca {
-// CACHE_LINE_1 0x0000 - 0x007F Contains read-only data
-	u32	xDesc;			// Eye catcher			x00-x03
-	u16	xSize;			// Size of this class		x04-x05
-	u16	xIntHdlrOffset;		// Offset to IntHdlr array	x06-x07
-	u8	xMaxIntHdlrEntries;	// Number of entries in array	x08-x08
-	u8	xPrimaryLpIndex;	// LP Index of Primary		x09-x09
-	u8	xServiceLpIndex;	// LP Ind of Service Focal Pointx0A-x0A
-	u8	xLpIndex;		// LP Index			x0B-x0B
-	u16	xMaxLpQueues;		// Number of allocated queues	x0C-x0D
-	u16	xLpQueueOffset;		// Offset to start of LP queues	x0E-x0F
-	u8	xPirEnvironMode;	// Piranha or hardware		x10-x10
-	u8	xPirConsoleMode;	// Piranha console indicator	x11-x11
-	u8	xPirDasdMode;		// Piranha dasd indicator	x12-x12
-	u8	xRsvd1_0[5];		// Reserved for Piranha related	x13-x17
-	u8	flags;			// flags, see below		x18-x1F
-	u8	xSpVpdFormat;		// VPD areas are in CSP format	...
-	u8	xIntProcRatio;		// Ratio of int procs to procs	...
-	u8	xRsvd1_2[5];		// Reserved			...
-	u16	xRsvd1_3;		// Reserved			x20-x21
-	u16	xPlicVrmIndex;		// VRM index of PLIC		x22-x23
-	u16	xMinSupportedSlicVrmInd;// Min supported OS VRM index	x24-x25
-	u16	xMinCompatableSlicVrmInd;// Min compatible OS VRM index x26-x27
-	u64	xLoadAreaAddr;		// ER address of load area	x28-x2F
-	u32	xLoadAreaChunks;	// Chunks for the load area	x30-x33
-	u32	xPaseSysCallCRMask;	// Mask used to test CR before  x34-x37
-					// doing an ASR switch on PASE
-					// system call.
-	u64	xSlicSegmentTablePtr;	// Pointer to Slic seg table.   x38-x3f
-	u8	xRsvd1_4[64];		//				x40-x7F
-
-// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data
-	u8	xRsvd2_0[128];		// Reserved			x00-x7F
-
-// CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators
-// NB: Padding required to keep xInterruptHdlr at x300 which is required
-// for v4r4 PLIC.
-	u8	xOldLpQueue[128];	// LP Queue needed for v4r4	100-17F
-	u8	xRsvd3_0[384];		// Reserved			180-2FF
-
-// CACHE_LINE_7-8 0x0300 - 0x03FF Contains the address of the OS interrupt
-//  handlers
-	u64	xInterruptHdlr[32];	// Interrupt handlers		300-x3FF
-};
-
-extern struct ItLpNaca		itLpNaca;
-
-#define ITLPNACA_LPAR		0x80	/* Is LPAR installed on the system */
-#define ITLPNACA_PARTITIONED	0x40	/* Is the system partitioned */
-#define ITLPNACA_HWSYNCEDTBS	0x20	/* Hardware synced TBs */
-#define ITLPNACA_HMTINT		0x10	/* Utilize MHT for interrupts */
-
-#endif /* _PLATFORMS_ISERIES_IT_LP_NACA_H */
diff --git a/arch/powerpc/platforms/iseries/ksyms.c b/arch/powerpc/platforms/iseries/ksyms.c
deleted file mode 100644
index 997e234..0000000
--- a/arch/powerpc/platforms/iseries/ksyms.c
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * (C) 2001-2005 PPC 64 Team, IBM Corp
- *
- *      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/export.h>
-
-#include <asm/hw_irq.h>
-#include <asm/iseries/hv_call_sc.h>
-
-EXPORT_SYMBOL(HvCall0);
-EXPORT_SYMBOL(HvCall1);
-EXPORT_SYMBOL(HvCall2);
-EXPORT_SYMBOL(HvCall3);
-EXPORT_SYMBOL(HvCall4);
-EXPORT_SYMBOL(HvCall5);
-EXPORT_SYMBOL(HvCall6);
-EXPORT_SYMBOL(HvCall7);
diff --git a/arch/powerpc/platforms/iseries/lpardata.c b/arch/powerpc/platforms/iseries/lpardata.c
deleted file mode 100644
index 00e0ec8..0000000
--- a/arch/powerpc/platforms/iseries/lpardata.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright 2001 Mike Corrigan, IBM Corp
- *
- * 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/types.h>
-#include <linux/threads.h>
-#include <linux/bitops.h>
-#include <asm/processor.h>
-#include <asm/ptrace.h>
-#include <asm/abs_addr.h>
-#include <asm/lppaca.h>
-#include <asm/paca.h>
-#include <asm/iseries/lpar_map.h>
-#include <asm/iseries/it_lp_queue.h>
-#include <asm/iseries/alpaca.h>
-
-#include "naca.h"
-#include "vpd_areas.h"
-#include "spcomm_area.h"
-#include "ipl_parms.h"
-#include "processor_vpd.h"
-#include "release_data.h"
-#include "it_exp_vpd_panel.h"
-#include "it_lp_naca.h"
-
-/* The HvReleaseData is the root of the information shared between
- * the hypervisor and Linux.
- */
-const struct HvReleaseData hvReleaseData = {
-	.xDesc = 0xc8a5d9c4,	/* "HvRD" ebcdic */
-	.xSize = sizeof(struct HvReleaseData),
-	.xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas),
-	.xSlicNacaAddr = &naca,		/* 64-bit Naca address */
-	.xMsNucDataOffset = LPARMAP_PHYS,
-	.xFlags = HVREL_TAGSINACTIVE	/* tags inactive       */
-					/* 64 bit              */
-					/* shared processors   */
-					/* HMT allowed         */
-		  | 6,			/* TEMP: This allows non-GA driver */
-	.xVrmIndex = 4,			/* We are v5r2m0               */
-	.xMinSupportedPlicVrmIndex = 3,		/* v5r1m0 */
-	.xMinCompatablePlicVrmIndex = 3,	/* v5r1m0 */
-	.xVrmName = { 0xd3, 0x89, 0x95, 0xa4,	/* "Linux 2.4.64" ebcdic */
-		0xa7, 0x40, 0xf2, 0x4b,
-		0xf4, 0x4b, 0xf6, 0xf4 },
-};
-
-/*
- * The NACA.  The first dword of the naca is required by the iSeries
- * hypervisor to point to itVpdAreas.  The hypervisor finds the NACA
- * through the pointer in hvReleaseData.
- */
-struct naca_struct naca = {
-	.xItVpdAreas = &itVpdAreas,
-	.xRamDisk = 0,
-	.xRamDiskSize = 0,
-};
-
-struct ItLpRegSave {
-	u32	xDesc;		// Eye catcher  "LpRS" ebcdic	000-003
-	u16	xSize;		// Size of this class		004-005
-	u8	xInUse;         // Area is live                 006-007
-	u8	xRsvd1[9];	// Reserved			007-00F
-
-	u8      xFixedRegSave[352]; // Fixed Register Save Area 010-16F
-	u32	xCTRL;		// Control Register		170-173
-	u32	xDEC;		// Decrementer			174-177
-	u32	xFPSCR;		// FP Status and Control Reg	178-17B
-	u32	xPVR;		// Processor Version Number	17C-17F
-
-	u64	xMMCR0;		// Monitor Mode Control Reg 0	180-187
-	u32	xPMC1;		// Perf Monitor Counter 1	188-18B
-	u32	xPMC2;		// Perf Monitor Counter 2	18C-18F
-	u32	xPMC3;		// Perf Monitor Counter 3	190-193
-	u32	xPMC4;		// Perf Monitor Counter 4	194-197
-	u32	xPIR;		// Processor ID Reg		198-19B
-
-	u32	xMMCR1;		// Monitor Mode Control Reg 1	19C-19F
-	u32	xMMCRA;		// Monitor Mode Control Reg A	1A0-1A3
-	u32	xPMC5;		// Perf Monitor Counter 5	1A4-1A7
-	u32	xPMC6;		// Perf Monitor Counter 6	1A8-1AB
-	u32	xPMC7;		// Perf Monitor Counter 7	1AC-1AF
-	u32	xPMC8;		// Perf Monitor Counter 8	1B0-1B3
-	u32	xTSC;		// Thread Switch Control	1B4-1B7
-	u32	xTST;		// Thread Switch Timeout	1B8-1BB
-	u32	xRsvd;          // Reserved                     1BC-1BF
-
-	u64	xACCR;		// Address Compare Control Reg	1C0-1C7
-	u64	xIMR;		// Instruction Match Register	1C8-1CF
-	u64	xSDR1;		// Storage Description Reg 1	1D0-1D7
-	u64	xSPRG0;		// Special Purpose Reg General0	1D8-1DF
-	u64	xSPRG1;		// Special Purpose Reg General1	1E0-1E7
-	u64	xSPRG2;		// Special Purpose Reg General2	1E8-1EF
-	u64	xSPRG3;		// Special Purpose Reg General3	1F0-1F7
-	u64	xTB;		// Time Base Register		1F8-1FF
-
-	u64	xFPR[32];	// Floating Point Registers	200-2FF
-
-	u64	xMSR;		// Machine State Register	300-307
-	u64	xNIA;		// Next Instruction Address	308-30F
-
-	u64	xDABR;		// Data Address Breakpoint Reg	310-317
-	u64	xIABR;		// Inst Address Breakpoint Reg	318-31F
-
-	u64	xHID0;		// HW Implementation Dependent0	320-327
-
-	u64	xHID4;		// HW Implementation Dependent4	328-32F
-	u64	xSCOMd;		// SCON Data Reg (SPRG4)	330-337
-	u64	xSCOMc;		// SCON Command Reg (SPRG5)	338-33F
-	u64	xSDAR;		// Sample Data Address Register	340-347
-	u64	xSIAR;		// Sample Inst Address Register	348-34F
-
-	u8	xRsvd3[176];	// Reserved			350-3FF
-};
-
-extern void system_reset_iSeries(void);
-extern void machine_check_iSeries(void);
-extern void data_access_iSeries(void);
-extern void instruction_access_iSeries(void);
-extern void hardware_interrupt_iSeries(void);
-extern void alignment_iSeries(void);
-extern void program_check_iSeries(void);
-extern void fp_unavailable_iSeries(void);
-extern void decrementer_iSeries(void);
-extern void trap_0a_iSeries(void);
-extern void trap_0b_iSeries(void);
-extern void system_call_iSeries(void);
-extern void single_step_iSeries(void);
-extern void trap_0e_iSeries(void);
-extern void performance_monitor_iSeries(void);
-extern void data_access_slb_iSeries(void);
-extern void instruction_access_slb_iSeries(void);
-
-struct ItLpNaca itLpNaca = {
-	.xDesc = 0xd397d581,		/* "LpNa" ebcdic */
-	.xSize = 0x0400,		/* size of ItLpNaca */
-	.xIntHdlrOffset = 0x0300,	/* offset to int array */
-	.xMaxIntHdlrEntries = 19,	/* # ents */
-	.xPrimaryLpIndex = 0,		/* Part # of primary */
-	.xServiceLpIndex = 0,		/* Part # of serv */
-	.xLpIndex = 0,			/* Part # of me */
-	.xMaxLpQueues = 0,		/* # of LP queues */
-	.xLpQueueOffset = 0x100,	/* offset of start of LP queues */
-	.xPirEnvironMode = 0,		/* Piranha stuff */
-	.xPirConsoleMode = 0,
-	.xPirDasdMode = 0,
-	.flags = 0,
-	.xSpVpdFormat = 0,
-	.xIntProcRatio = 0,
-	.xPlicVrmIndex = 0,		/* VRM index of PLIC */
-	.xMinSupportedSlicVrmInd = 0,	/* min supported SLIC */
-	.xMinCompatableSlicVrmInd = 0,	/* min compat SLIC */
-	.xLoadAreaAddr = 0,		/* 64-bit addr of load area */
-	.xLoadAreaChunks = 0,		/* chunks for load area */
-	.xPaseSysCallCRMask = 0,	/* PASE mask */
-	.xSlicSegmentTablePtr = 0,	/* seg table */
-	.xOldLpQueue = { 0 },		/* Old LP Queue */
-	.xInterruptHdlr = {
-		(u64)system_reset_iSeries,	/* 0x100 System Reset */
-		(u64)machine_check_iSeries,	/* 0x200 Machine Check */
-		(u64)data_access_iSeries,	/* 0x300 Data Access */
-		(u64)instruction_access_iSeries, /* 0x400 Instruction Access */
-		(u64)hardware_interrupt_iSeries, /* 0x500 External */
-		(u64)alignment_iSeries,		/* 0x600 Alignment */
-		(u64)program_check_iSeries,	/* 0x700 Program Check */
-		(u64)fp_unavailable_iSeries,	/* 0x800 FP Unavailable */
-		(u64)decrementer_iSeries,	/* 0x900 Decrementer */
-		(u64)trap_0a_iSeries,		/* 0xa00 Trap 0A */
-		(u64)trap_0b_iSeries,		/* 0xb00 Trap 0B */
-		(u64)system_call_iSeries,	/* 0xc00 System Call */
-		(u64)single_step_iSeries,	/* 0xd00 Single Step */
-		(u64)trap_0e_iSeries,		/* 0xe00 Trap 0E */
-		(u64)performance_monitor_iSeries,/* 0xf00 Performance Monitor */
-		0,				/* int 0x1000 */
-		0,				/* int 0x1010 */
-		0,				/* int 0x1020 CPU ctls */
-		(u64)hardware_interrupt_iSeries, /* SC Ret Hdlr */
-		(u64)data_access_slb_iSeries,	/* 0x380 D-SLB */
-		(u64)instruction_access_slb_iSeries /* 0x480 I-SLB */
-	}
-};
-
-/* May be filled in by the hypervisor so cannot end up in the BSS */
-static struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data")));
-
-/* May be filled in by the hypervisor so cannot end up in the BSS */
-struct ItExtVpdPanel xItExtVpdPanel __attribute__((__section__(".data")));
-
-#define maxPhysicalProcessors 32
-
-struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = {
-	{
-		.xInstCacheOperandSize = 32,
-		.xDataCacheOperandSize = 32,
-		.xProcFreq     = 50000000,
-		.xTimeBaseFreq = 50000000,
-		.xPVR = 0x3600
-	}
-};
-
-/* Space for Main Store Vpd 27,200 bytes */
-/* May be filled in by the hypervisor so cannot end up in the BSS */
-u64    xMsVpd[3400] __attribute__((__section__(".data")));
-
-/* Space for Recovery Log Buffer */
-/* May be filled in by the hypervisor so cannot end up in the BSS */
-static u64    xRecoveryLogBuffer[32] __attribute__((__section__(".data")));
-
-static const struct SpCommArea xSpCommArea = {
-	.xDesc = 0xE2D7C3C2,
-	.xFormat = 1,
-};
-
-static const struct ItLpRegSave iseries_reg_save[] = {
-	[0 ... (NR_CPUS-1)] = {
-		.xDesc = 0xd397d9e2,	/* "LpRS" */
-		.xSize = sizeof(struct ItLpRegSave),
-	},
-};
-
-#define ALPACA_INIT(number)						\
-{									\
-	.lppaca_ptr = &lppaca[number],					\
-	.reg_save_ptr = &iseries_reg_save[number],			\
-}
-
-const struct alpaca alpaca[] = {
-	ALPACA_INIT( 0),
-#if NR_CPUS > 1
-	ALPACA_INIT( 1), ALPACA_INIT( 2), ALPACA_INIT( 3),
-#if NR_CPUS > 4
-	ALPACA_INIT( 4), ALPACA_INIT( 5), ALPACA_INIT( 6), ALPACA_INIT( 7),
-#if NR_CPUS > 8
-	ALPACA_INIT( 8), ALPACA_INIT( 9), ALPACA_INIT(10), ALPACA_INIT(11),
-	ALPACA_INIT(12), ALPACA_INIT(13), ALPACA_INIT(14), ALPACA_INIT(15),
-	ALPACA_INIT(16), ALPACA_INIT(17), ALPACA_INIT(18), ALPACA_INIT(19),
-	ALPACA_INIT(20), ALPACA_INIT(21), ALPACA_INIT(22), ALPACA_INIT(23),
-	ALPACA_INIT(24), ALPACA_INIT(25), ALPACA_INIT(26), ALPACA_INIT(27),
-	ALPACA_INIT(28), ALPACA_INIT(29), ALPACA_INIT(30), ALPACA_INIT(31),
-#if NR_CPUS > 32
-	ALPACA_INIT(32), ALPACA_INIT(33), ALPACA_INIT(34), ALPACA_INIT(35),
-	ALPACA_INIT(36), ALPACA_INIT(37), ALPACA_INIT(38), ALPACA_INIT(39),
-	ALPACA_INIT(40), ALPACA_INIT(41), ALPACA_INIT(42), ALPACA_INIT(43),
-	ALPACA_INIT(44), ALPACA_INIT(45), ALPACA_INIT(46), ALPACA_INIT(47),
-	ALPACA_INIT(48), ALPACA_INIT(49), ALPACA_INIT(50), ALPACA_INIT(51),
-	ALPACA_INIT(52), ALPACA_INIT(53), ALPACA_INIT(54), ALPACA_INIT(55),
-	ALPACA_INIT(56), ALPACA_INIT(57), ALPACA_INIT(58), ALPACA_INIT(59),
-	ALPACA_INIT(60), ALPACA_INIT(61), ALPACA_INIT(62), ALPACA_INIT(63),
-#endif
-#endif
-#endif
-#endif
-};
-
-/* The LparMap data is now located at offset 0x6000 in head.S
- * It was put there so that the HvReleaseData could address it
- * with a 32-bit offset as required by the iSeries hypervisor
- *
- * The Naca has a pointer to the ItVpdAreas.  The hypervisor finds
- * the Naca via the HvReleaseData area.  The HvReleaseData has the
- * offset into the Naca of the pointer to the ItVpdAreas.
- */
-const struct ItVpdAreas itVpdAreas = {
-	.xSlicDesc = 0xc9a3e5c1,		/* "ItVA" */
-	.xSlicSize = sizeof(struct ItVpdAreas),
-	.xSlicVpdEntries = ItVpdMaxEntries,	/* # VPD array entries */
-	.xSlicDmaEntries = ItDmaMaxEntries,	/* # DMA array entries */
-	.xSlicMaxLogicalProcs = NR_CPUS * 2,	/* Max logical procs */
-	.xSlicMaxPhysicalProcs = maxPhysicalProcessors,	/* Max physical procs */
-	.xSlicDmaToksOffset = offsetof(struct ItVpdAreas, xPlicDmaToks),
-	.xSlicVpdAdrsOffset = offsetof(struct ItVpdAreas, xSlicVpdAdrs),
-	.xSlicDmaLensOffset = offsetof(struct ItVpdAreas, xPlicDmaLens),
-	.xSlicVpdLensOffset = offsetof(struct ItVpdAreas, xSlicVpdLens),
-	.xSlicMaxSlotLabels = 0,		/* max slot labels */
-	.xSlicMaxLpQueues = 1,			/* max LP queues */
-	.xPlicDmaLens = { 0 },			/* DMA lengths */
-	.xPlicDmaToks = { 0 },			/* DMA tokens */
-	.xSlicVpdLens = {			/* VPD lengths */
-	        0,0,0,		        /*  0 - 2 */
-		sizeof(xItExtVpdPanel), /*       3 Extended VPD   */
-		sizeof(struct alpaca),	/*       4 length of (fake) Paca  */
-		0,			/*       5 */
-		sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */
-		26992,			/*	 7 length of MS VPD */
-		0,			/*       8 */
-		sizeof(struct ItLpNaca),/*       9 length of LP Naca */
-		0,			/*	10 */
-		256,			/*	11 length of Recovery Log Buf */
-		sizeof(struct SpCommArea), /*   12 length of SP Comm Area */
-		0,0,0,			/* 13 - 15 */
-		sizeof(struct IoHriProcessorVpd),/* 16 length of Proc Vpd */
-		0,0,0,0,0,0,		/* 17 - 22  */
-		sizeof(struct hvlpevent_queue),	/* 23 length of Lp Queue */
-		0,0			/* 24 - 25 */
-		},
-	.xSlicVpdAdrs = {			/* VPD addresses */
-		0,0,0,			/*	 0 -  2 */
-		&xItExtVpdPanel,        /*       3 Extended VPD */
-		&alpaca[0],		/*       4 first (fake) Paca */
-		0,			/*       5 */
-		&xItIplParmsReal,	/*	 6 IPL parms */
-		&xMsVpd,		/*	 7 MS Vpd */
-		0,			/*       8 */
-		&itLpNaca,		/*       9 LpNaca */
-		0,			/*	10 */
-		&xRecoveryLogBuffer,	/*	11 Recovery Log Buffer */
-		&xSpCommArea,		/*	12 SP Comm Area */
-		0,0,0,			/* 13 - 15 */
-		&xIoHriProcessorVpd,	/*      16 Proc Vpd */
-		0,0,0,0,0,0,		/* 17 - 22 */
-		&hvlpevent_queue,	/*      23 Lp Queue */
-		0,0
-	}
-};
diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c
deleted file mode 100644
index 202e227..0000000
--- a/arch/powerpc/platforms/iseries/lpevents.c
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright (C) 2001 Mike Corrigan  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.
- */
-
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-#include <linux/seq_file.h>
-#include <linux/proc_fs.h>
-#include <linux/export.h>
-
-#include <asm/system.h>
-#include <asm/paca.h>
-#include <asm/firmware.h>
-#include <asm/iseries/it_lp_queue.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_call_event.h>
-#include "it_lp_naca.h"
-
-/*
- * The LpQueue is used to pass event data from the hypervisor to
- * the partition.  This is where I/O interrupt events are communicated.
- *
- * It is written to by the hypervisor so cannot end up in the BSS.
- */
-struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data")));
-
-DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts);
-
-static char *event_types[HvLpEvent_Type_NumTypes] = {
-	"Hypervisor",
-	"Machine Facilities",
-	"Session Manager",
-	"SPD I/O",
-	"Virtual Bus",
-	"PCI I/O",
-	"RIO I/O",
-	"Virtual Lan",
-	"Virtual I/O"
-};
-
-/* Array of LpEvent handler functions */
-static LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes];
-static unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes];
-
-static struct HvLpEvent * get_next_hvlpevent(void)
-{
-	struct HvLpEvent * event;
-	event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event;
-
-	if (hvlpevent_is_valid(event)) {
-		/* rmb() needed only for weakly consistent machines (regatta) */
-		rmb();
-		/* Set pointer to next potential event */
-		hvlpevent_queue.hq_current_event += ((event->xSizeMinus1 +
-				IT_LP_EVENT_ALIGN) / IT_LP_EVENT_ALIGN) *
-					IT_LP_EVENT_ALIGN;
-
-		/* Wrap to beginning if no room at end */
-		if (hvlpevent_queue.hq_current_event >
-				hvlpevent_queue.hq_last_event) {
-			hvlpevent_queue.hq_current_event =
-				hvlpevent_queue.hq_event_stack;
-		}
-	} else {
-		event = NULL;
-	}
-
-	return event;
-}
-
-static unsigned long spread_lpevents = NR_CPUS;
-
-int hvlpevent_is_pending(void)
-{
-	struct HvLpEvent *next_event;
-
-	if (smp_processor_id() >= spread_lpevents)
-		return 0;
-
-	next_event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event;
-
-	return hvlpevent_is_valid(next_event) ||
-		hvlpevent_queue.hq_overflow_pending;
-}
-
-static void hvlpevent_clear_valid(struct HvLpEvent * event)
-{
-	/* Tell the Hypervisor that we're done with this event.
-	 * Also clear bits within this event that might look like valid bits.
-	 * ie. on 64-byte boundaries.
-	 */
-	struct HvLpEvent *tmp;
-	unsigned extra = ((event->xSizeMinus1 + IT_LP_EVENT_ALIGN) /
-				IT_LP_EVENT_ALIGN) - 1;
-
-	switch (extra) {
-	case 3:
-		tmp = (struct HvLpEvent*)((char*)event + 3 * IT_LP_EVENT_ALIGN);
-		hvlpevent_invalidate(tmp);
-	case 2:
-		tmp = (struct HvLpEvent*)((char*)event + 2 * IT_LP_EVENT_ALIGN);
-		hvlpevent_invalidate(tmp);
-	case 1:
-		tmp = (struct HvLpEvent*)((char*)event + 1 * IT_LP_EVENT_ALIGN);
-		hvlpevent_invalidate(tmp);
-	}
-
-	mb();
-
-	hvlpevent_invalidate(event);
-}
-
-void process_hvlpevents(void)
-{
-	struct HvLpEvent * event;
-
- restart:
-	/* If we have recursed, just return */
-	if (!spin_trylock(&hvlpevent_queue.hq_lock))
-		return;
-
-	for (;;) {
-		event = get_next_hvlpevent();
-		if (event) {
-			/* Call appropriate handler here, passing
-			 * a pointer to the LpEvent.  The handler
-			 * must make a copy of the LpEvent if it
-			 * needs it in a bottom half. (perhaps for
-			 * an ACK)
-			 *
-			 *  Handlers are responsible for ACK processing
-			 *
-			 * The Hypervisor guarantees that LpEvents will
-			 * only be delivered with types that we have
-			 * registered for, so no type check is necessary
-			 * here!
-			 */
-			if (event->xType < HvLpEvent_Type_NumTypes)
-				__get_cpu_var(hvlpevent_counts)[event->xType]++;
-			if (event->xType < HvLpEvent_Type_NumTypes &&
-					lpEventHandler[event->xType])
-				lpEventHandler[event->xType](event);
-			else {
-				u8 type = event->xType;
-
-				/*
-				 * Don't printk in the spinlock as printk
-				 * may require ack events form the HV to send
-				 * any characters there.
-				 */
-				hvlpevent_clear_valid(event);
-				spin_unlock(&hvlpevent_queue.hq_lock);
-				printk(KERN_INFO
-					"Unexpected Lp Event type=%d\n", type);
-				goto restart;
-			}
-
-			hvlpevent_clear_valid(event);
-		} else if (hvlpevent_queue.hq_overflow_pending)
-			/*
-			 * No more valid events. If overflow events are
-			 * pending process them
-			 */
-			HvCallEvent_getOverflowLpEvents(hvlpevent_queue.hq_index);
-		else
-			break;
-	}
-
-	spin_unlock(&hvlpevent_queue.hq_lock);
-}
-
-static int set_spread_lpevents(char *str)
-{
-	unsigned long val = simple_strtoul(str, NULL, 0);
-
-	/*
-	 * The parameter is the number of processors to share in processing
-	 * lp events.
-	 */
-	if (( val > 0) && (val <= NR_CPUS)) {
-		spread_lpevents = val;
-		printk("lpevent processing spread over %ld processors\n", val);
-	} else {
-		printk("invalid spread_lpevents %ld\n", val);
-	}
-
-	return 1;
-}
-__setup("spread_lpevents=", set_spread_lpevents);
-
-void __init setup_hvlpevent_queue(void)
-{
-	void *eventStack;
-
-	spin_lock_init(&hvlpevent_queue.hq_lock);
-
-	/* Allocate a page for the Event Stack. */
-	eventStack = alloc_bootmem_pages(IT_LP_EVENT_STACK_SIZE);
-	memset(eventStack, 0, IT_LP_EVENT_STACK_SIZE);
-
-	/* Invoke the hypervisor to initialize the event stack */
-	HvCallEvent_setLpEventStack(0, eventStack, IT_LP_EVENT_STACK_SIZE);
-
-	hvlpevent_queue.hq_event_stack = eventStack;
-	hvlpevent_queue.hq_current_event = eventStack;
-	hvlpevent_queue.hq_last_event = (char *)eventStack +
-		(IT_LP_EVENT_STACK_SIZE - IT_LP_EVENT_MAX_SIZE);
-	hvlpevent_queue.hq_index = 0;
-}
-
-/* Register a handler for an LpEvent type */
-int HvLpEvent_registerHandler(HvLpEvent_Type eventType, LpEventHandler handler)
-{
-	if (eventType < HvLpEvent_Type_NumTypes) {
-		lpEventHandler[eventType] = handler;
-		return 0;
-	}
-	return 1;
-}
-EXPORT_SYMBOL(HvLpEvent_registerHandler);
-
-int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType)
-{
-	might_sleep();
-
-	if (eventType < HvLpEvent_Type_NumTypes) {
-		if (!lpEventHandlerPaths[eventType]) {
-			lpEventHandler[eventType] = NULL;
-			/*
-			 * We now sleep until all other CPUs have scheduled.
-			 * This ensures that the deletion is seen by all
-			 * other CPUs, and that the deleted handler isn't
-			 * still running on another CPU when we return.
-			 */
-			synchronize_sched();
-			return 0;
-		}
-	}
-	return 1;
-}
-EXPORT_SYMBOL(HvLpEvent_unregisterHandler);
-
-/*
- * lpIndex is the partition index of the target partition.
- * needed only for VirtualIo, VirtualLan and SessionMgr.  Zero
- * indicates to use our partition index - for the other types.
- */
-int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex)
-{
-	if ((eventType < HvLpEvent_Type_NumTypes) &&
-			lpEventHandler[eventType]) {
-		if (lpIndex == 0)
-			lpIndex = itLpNaca.xLpIndex;
-		HvCallEvent_openLpEventPath(lpIndex, eventType);
-		++lpEventHandlerPaths[eventType];
-		return 0;
-	}
-	return 1;
-}
-
-int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex)
-{
-	if ((eventType < HvLpEvent_Type_NumTypes) &&
-			lpEventHandler[eventType] &&
-			lpEventHandlerPaths[eventType]) {
-		if (lpIndex == 0)
-			lpIndex = itLpNaca.xLpIndex;
-		HvCallEvent_closeLpEventPath(lpIndex, eventType);
-		--lpEventHandlerPaths[eventType];
-		return 0;
-	}
-	return 1;
-}
-
-static int proc_lpevents_show(struct seq_file *m, void *v)
-{
-	int cpu, i;
-	unsigned long sum;
-	static unsigned long cpu_totals[NR_CPUS];
-
-	/* FIXME: do we care that there's no locking here? */
-	sum = 0;
-	for_each_online_cpu(cpu) {
-		cpu_totals[cpu] = 0;
-		for (i = 0; i < HvLpEvent_Type_NumTypes; i++) {
-			cpu_totals[cpu] += per_cpu(hvlpevent_counts, cpu)[i];
-		}
-		sum += cpu_totals[cpu];
-	}
-
-	seq_printf(m, "LpEventQueue 0\n");
-	seq_printf(m, "  events processed:\t%lu\n", sum);
-
-	for (i = 0; i < HvLpEvent_Type_NumTypes; ++i) {
-		sum = 0;
-		for_each_online_cpu(cpu) {
-			sum += per_cpu(hvlpevent_counts, cpu)[i];
-		}
-
-		seq_printf(m, "    %-20s %10lu\n", event_types[i], sum);
-	}
-
-	seq_printf(m, "\n  events processed by processor:\n");
-
-	for_each_online_cpu(cpu) {
-		seq_printf(m, "    CPU%02d  %10lu\n", cpu, cpu_totals[cpu]);
-	}
-
-	return 0;
-}
-
-static int proc_lpevents_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, proc_lpevents_show, NULL);
-}
-
-static const struct file_operations proc_lpevents_operations = {
-	.open		= proc_lpevents_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int __init proc_lpevents_init(void)
-{
-	if (!firmware_has_feature(FW_FEATURE_ISERIES))
-		return 0;
-
-	proc_create("iSeries/lpevents", S_IFREG|S_IRUGO, NULL,
-		    &proc_lpevents_operations);
-	return 0;
-}
-__initcall(proc_lpevents_init);
-
diff --git a/arch/powerpc/platforms/iseries/main_store.h b/arch/powerpc/platforms/iseries/main_store.h
deleted file mode 100644
index 1a7a3f5..0000000
--- a/arch/powerpc/platforms/iseries/main_store.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-
-#ifndef _ISERIES_MAIN_STORE_H
-#define _ISERIES_MAIN_STORE_H
-
-/* Main Store Vpd for Condor,iStar,sStar */
-struct IoHriMainStoreSegment4 {
-	u8	msArea0Exists:1;
-	u8	msArea1Exists:1;
-	u8	msArea2Exists:1;
-	u8	msArea3Exists:1;
-	u8	reserved1:4;
-	u8	reserved2;
-
-	u8	msArea0Functional:1;
-	u8	msArea1Functional:1;
-	u8	msArea2Functional:1;
-	u8	msArea3Functional:1;
-	u8	reserved3:4;
-	u8	reserved4;
-
-	u32	totalMainStore;
-
-	u64	msArea0Ptr;
-	u64	msArea1Ptr;
-	u64	msArea2Ptr;
-	u64	msArea3Ptr;
-
-	u32	cardProductionLevel;
-
-	u32	msAdrHole;
-
-	u8	msArea0HasRiserVpd:1;
-	u8	msArea1HasRiserVpd:1;
-	u8	msArea2HasRiserVpd:1;
-	u8	msArea3HasRiserVpd:1;
-	u8	reserved5:4;
-	u8	reserved6;
-	u16	reserved7;
-
-	u8	reserved8[28];
-
-	u64	nonInterleavedBlocksStartAdr;
-	u64	nonInterleavedBlocksEndAdr;
-};
-
-/* Main Store VPD for Power4 */
-struct __attribute((packed)) IoHriMainStoreChipInfo1 {
-	u32	chipMfgID;
-	char	chipECLevel[4];
-};
-
-struct IoHriMainStoreVpdIdData {
-	char	typeNumber[4];
-	char	modelNumber[4];
-	char	partNumber[12];
-	char	serialNumber[12];
-};
-
-struct	__attribute((packed)) IoHriMainStoreVpdFruData {
-	char	fruLabel[8];
-	u8	numberOfSlots;
-	u8	pluggingType;
-	u16	slotMapIndex;
-};
-
-struct  __attribute((packed)) IoHriMainStoreAdrRangeBlock {
-	void	*blockStart;
-	void	*blockEnd;
-	u32	blockProcChipId;
-};
-
-#define MaxAreaAdrRangeBlocks 4
-
-struct __attribute((packed)) IoHriMainStoreArea4 {
-	u32	msVpdFormat;
-	u8	containedVpdType;
-	u8	reserved1;
-	u16	reserved2;
-
-	u64	msExists;
-	u64	msFunctional;
-
-	u32	memorySize;
-	u32	procNodeId;
-
-	u32	numAdrRangeBlocks;
-	struct IoHriMainStoreAdrRangeBlock xAdrRangeBlock[MaxAreaAdrRangeBlocks];
-
-	struct IoHriMainStoreChipInfo1	chipInfo0;
-	struct IoHriMainStoreChipInfo1	chipInfo1;
-	struct IoHriMainStoreChipInfo1	chipInfo2;
-	struct IoHriMainStoreChipInfo1	chipInfo3;
-	struct IoHriMainStoreChipInfo1	chipInfo4;
-	struct IoHriMainStoreChipInfo1	chipInfo5;
-	struct IoHriMainStoreChipInfo1	chipInfo6;
-	struct IoHriMainStoreChipInfo1	chipInfo7;
-
-	void	*msRamAreaArray;
-	u32	msRamAreaArrayNumEntries;
-	u32	msRamAreaArrayEntrySize;
-
-	u32	numaDimmExists;
-	u32	numaDimmFunctional;
-	void	*numaDimmArray;
-	u32	numaDimmArrayNumEntries;
-	u32	numaDimmArrayEntrySize;
-
-	struct IoHriMainStoreVpdIdData idData;
-
-	u64	powerData;
-	u64	cardAssemblyPartNum;
-	u64	chipSerialNum;
-
-	u64	reserved3;
-	char	reserved4[16];
-
-	struct IoHriMainStoreVpdFruData fruData;
-
-	u8	vpdPortNum;
-	u8	reserved5;
-	u8	frameId;
-	u8	rackUnit;
-	char	asciiKeywordVpd[256];
-	u32	reserved6;
-};
-
-
-struct IoHriMainStoreSegment5 {
-	u16	reserved1;
-	u8	reserved2;
-	u8	msVpdFormat;
-
-	u32	totalMainStore;
-	u64	maxConfiguredMsAdr;
-
-	struct IoHriMainStoreArea4	*msAreaArray;
-	u32	msAreaArrayNumEntries;
-	u32	msAreaArrayEntrySize;
-
-	u32	msAreaExists;
-	u32	msAreaFunctional;
-
-	u64	reserved3;
-};
-
-extern u64	xMsVpd[];
-
-#endif	/* _ISERIES_MAIN_STORE_H */
diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c
deleted file mode 100644
index 254c1fc..0000000
--- a/arch/powerpc/platforms/iseries/mf.c
+++ /dev/null
@@ -1,1275 +0,0 @@
-/*
- * Copyright (C) 2001 Troy D. Armstrong  IBM Corporation
- * Copyright (C) 2004-2005 Stephen Rothwell  IBM Corporation
- *
- * This modules exists as an interface between a Linux secondary partition
- * running on an iSeries and the primary partition's Virtual Service
- * Processor (VSP) object.  The VSP has final authority over powering on/off
- * all partitions in the iSeries.  It also provides miscellaneous low-level
- * machine facility type operations.
- *
- *
- * 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/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/export.h>
-#include <linux/proc_fs.h>
-#include <linux/dma-mapping.h>
-#include <linux/bcd.h>
-#include <linux/rtc.h>
-#include <linux/slab.h>
-
-#include <asm/time.h>
-#include <asm/uaccess.h>
-#include <asm/paca.h>
-#include <asm/abs_addr.h>
-#include <asm/firmware.h>
-#include <asm/iseries/mf.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/it_lp_queue.h>
-
-#include "setup.h"
-
-static int mf_initialized;
-
-/*
- * This is the structure layout for the Machine Facilities LPAR event
- * flows.
- */
-struct vsp_cmd_data {
-	u64 token;
-	u16 cmd;
-	HvLpIndex lp_index;
-	u8 result_code;
-	u32 reserved;
-	union {
-		u64 state;	/* GetStateOut */
-		u64 ipl_type;	/* GetIplTypeOut, Function02SelectIplTypeIn */
-		u64 ipl_mode;	/* GetIplModeOut, Function02SelectIplModeIn */
-		u64 page[4];	/* GetSrcHistoryIn */
-		u64 flag;	/* GetAutoIplWhenPrimaryIplsOut,
-				   SetAutoIplWhenPrimaryIplsIn,
-				   WhiteButtonPowerOffIn,
-				   Function08FastPowerOffIn,
-				   IsSpcnRackPowerIncompleteOut */
-		struct {
-			u64 token;
-			u64 address_type;
-			u64 side;
-			u32 length;
-			u32 offset;
-		} kern;		/* SetKernelImageIn, GetKernelImageIn,
-				   SetKernelCmdLineIn, GetKernelCmdLineIn */
-		u32 length_out;	/* GetKernelImageOut, GetKernelCmdLineOut */
-		u8 reserved[80];
-	} sub_data;
-};
-
-struct vsp_rsp_data {
-	struct completion com;
-	struct vsp_cmd_data *response;
-};
-
-struct alloc_data {
-	u16 size;
-	u16 type;
-	u32 count;
-	u16 reserved1;
-	u8 reserved2;
-	HvLpIndex target_lp;
-};
-
-struct ce_msg_data;
-
-typedef void (*ce_msg_comp_hdlr)(void *token, struct ce_msg_data *vsp_cmd_rsp);
-
-struct ce_msg_comp_data {
-	ce_msg_comp_hdlr handler;
-	void *token;
-};
-
-struct ce_msg_data {
-	u8 ce_msg[12];
-	char reserved[4];
-	struct ce_msg_comp_data *completion;
-};
-
-struct io_mf_lp_event {
-	struct HvLpEvent hp_lp_event;
-	u16 subtype_result_code;
-	u16 reserved1;
-	u32 reserved2;
-	union {
-		struct alloc_data alloc;
-		struct ce_msg_data ce_msg;
-		struct vsp_cmd_data vsp_cmd;
-	} data;
-};
-
-#define subtype_data(a, b, c, d)	\
-		(((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
-
-/*
- * All outgoing event traffic is kept on a FIFO queue.  The first
- * pointer points to the one that is outstanding, and all new
- * requests get stuck on the end.  Also, we keep a certain number of
- * preallocated pending events so that we can operate very early in
- * the boot up sequence (before kmalloc is ready).
- */
-struct pending_event {
-	struct pending_event *next;
-	struct io_mf_lp_event event;
-	MFCompleteHandler hdlr;
-	char dma_data[72];
-	unsigned dma_data_length;
-	unsigned remote_address;
-};
-static spinlock_t pending_event_spinlock;
-static struct pending_event *pending_event_head;
-static struct pending_event *pending_event_tail;
-static struct pending_event *pending_event_avail;
-#define PENDING_EVENT_PREALLOC_LEN 16
-static struct pending_event pending_event_prealloc[PENDING_EVENT_PREALLOC_LEN];
-
-/*
- * Put a pending event onto the available queue, so it can get reused.
- * Attention! You must have the pending_event_spinlock before calling!
- */
-static void free_pending_event(struct pending_event *ev)
-{
-	if (ev != NULL) {
-		ev->next = pending_event_avail;
-		pending_event_avail = ev;
-	}
-}
-
-/*
- * Enqueue the outbound event onto the stack.  If the queue was
- * empty to begin with, we must also issue it via the Hypervisor
- * interface.  There is a section of code below that will touch
- * the first stack pointer without the protection of the pending_event_spinlock.
- * This is OK, because we know that nobody else will be modifying
- * the first pointer when we do this.
- */
-static int signal_event(struct pending_event *ev)
-{
-	int rc = 0;
-	unsigned long flags;
-	int go = 1;
-	struct pending_event *ev1;
-	HvLpEvent_Rc hv_rc;
-
-	/* enqueue the event */
-	if (ev != NULL) {
-		ev->next = NULL;
-		spin_lock_irqsave(&pending_event_spinlock, flags);
-		if (pending_event_head == NULL)
-			pending_event_head = ev;
-		else {
-			go = 0;
-			pending_event_tail->next = ev;
-		}
-		pending_event_tail = ev;
-		spin_unlock_irqrestore(&pending_event_spinlock, flags);
-	}
-
-	/* send the event */
-	while (go) {
-		go = 0;
-
-		/* any DMA data to send beforehand? */
-		if (pending_event_head->dma_data_length > 0)
-			HvCallEvent_dmaToSp(pending_event_head->dma_data,
-					pending_event_head->remote_address,
-					pending_event_head->dma_data_length,
-					HvLpDma_Direction_LocalToRemote);
-
-		hv_rc = HvCallEvent_signalLpEvent(
-				&pending_event_head->event.hp_lp_event);
-		if (hv_rc != HvLpEvent_Rc_Good) {
-			printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() "
-					"failed with %d\n", (int)hv_rc);
-
-			spin_lock_irqsave(&pending_event_spinlock, flags);
-			ev1 = pending_event_head;
-			pending_event_head = pending_event_head->next;
-			if (pending_event_head != NULL)
-				go = 1;
-			spin_unlock_irqrestore(&pending_event_spinlock, flags);
-
-			if (ev1 == ev)
-				rc = -EIO;
-			else if (ev1->hdlr != NULL)
-				(*ev1->hdlr)((void *)ev1->event.hp_lp_event.xCorrelationToken, -EIO);
-
-			spin_lock_irqsave(&pending_event_spinlock, flags);
-			free_pending_event(ev1);
-			spin_unlock_irqrestore(&pending_event_spinlock, flags);
-		}
-	}
-
-	return rc;
-}
-
-/*
- * Allocate a new pending_event structure, and initialize it.
- */
-static struct pending_event *new_pending_event(void)
-{
-	struct pending_event *ev = NULL;
-	HvLpIndex primary_lp = HvLpConfig_getPrimaryLpIndex();
-	unsigned long flags;
-	struct HvLpEvent *hev;
-
-	spin_lock_irqsave(&pending_event_spinlock, flags);
-	if (pending_event_avail != NULL) {
-		ev = pending_event_avail;
-		pending_event_avail = pending_event_avail->next;
-	}
-	spin_unlock_irqrestore(&pending_event_spinlock, flags);
-	if (ev == NULL) {
-		ev = kmalloc(sizeof(struct pending_event), GFP_ATOMIC);
-		if (ev == NULL) {
-			printk(KERN_ERR "mf.c: unable to kmalloc %ld bytes\n",
-					sizeof(struct pending_event));
-			return NULL;
-		}
-	}
-	memset(ev, 0, sizeof(struct pending_event));
-	hev = &ev->event.hp_lp_event;
-	hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK | HV_LP_EVENT_INT;
-	hev->xType = HvLpEvent_Type_MachineFac;
-	hev->xSourceLp = HvLpConfig_getLpIndex();
-	hev->xTargetLp = primary_lp;
-	hev->xSizeMinus1 = sizeof(ev->event) - 1;
-	hev->xRc = HvLpEvent_Rc_Good;
-	hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primary_lp,
-			HvLpEvent_Type_MachineFac);
-	hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primary_lp,
-			HvLpEvent_Type_MachineFac);
-
-	return ev;
-}
-
-static int __maybe_unused
-signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd)
-{
-	struct pending_event *ev = new_pending_event();
-	int rc;
-	struct vsp_rsp_data response;
-
-	if (ev == NULL)
-		return -ENOMEM;
-
-	init_completion(&response.com);
-	response.response = vsp_cmd;
-	ev->event.hp_lp_event.xSubtype = 6;
-	ev->event.hp_lp_event.x.xSubtypeData =
-		subtype_data('M', 'F',  'V',  'I');
-	ev->event.data.vsp_cmd.token = (u64)&response;
-	ev->event.data.vsp_cmd.cmd = vsp_cmd->cmd;
-	ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex();
-	ev->event.data.vsp_cmd.result_code = 0xFF;
-	ev->event.data.vsp_cmd.reserved = 0;
-	memcpy(&(ev->event.data.vsp_cmd.sub_data),
-			&(vsp_cmd->sub_data), sizeof(vsp_cmd->sub_data));
-	mb();
-
-	rc = signal_event(ev);
-	if (rc == 0)
-		wait_for_completion(&response.com);
-	return rc;
-}
-
-
-/*
- * Send a 12-byte CE message to the primary partition VSP object
- */
-static int signal_ce_msg(char *ce_msg, struct ce_msg_comp_data *completion)
-{
-	struct pending_event *ev = new_pending_event();
-
-	if (ev == NULL)
-		return -ENOMEM;
-
-	ev->event.hp_lp_event.xSubtype = 0;
-	ev->event.hp_lp_event.x.xSubtypeData =
-		subtype_data('M',  'F',  'C',  'E');
-	memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12);
-	ev->event.data.ce_msg.completion = completion;
-	return signal_event(ev);
-}
-
-/*
- * Send a 12-byte CE message (with no data) to the primary partition VSP object
- */
-static int signal_ce_msg_simple(u8 ce_op, struct ce_msg_comp_data *completion)
-{
-	u8 ce_msg[12];
-
-	memset(ce_msg, 0, sizeof(ce_msg));
-	ce_msg[3] = ce_op;
-	return signal_ce_msg(ce_msg, completion);
-}
-
-/*
- * Send a 12-byte CE message and DMA data to the primary partition VSP object
- */
-static int dma_and_signal_ce_msg(char *ce_msg,
-		struct ce_msg_comp_data *completion, void *dma_data,
-		unsigned dma_data_length, unsigned remote_address)
-{
-	struct pending_event *ev = new_pending_event();
-
-	if (ev == NULL)
-		return -ENOMEM;
-
-	ev->event.hp_lp_event.xSubtype = 0;
-	ev->event.hp_lp_event.x.xSubtypeData =
-		subtype_data('M', 'F', 'C', 'E');
-	memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12);
-	ev->event.data.ce_msg.completion = completion;
-	memcpy(ev->dma_data, dma_data, dma_data_length);
-	ev->dma_data_length = dma_data_length;
-	ev->remote_address = remote_address;
-	return signal_event(ev);
-}
-
-/*
- * Initiate a nice (hopefully) shutdown of Linux.  We simply are
- * going to try and send the init process a SIGINT signal.  If
- * this fails (why?), we'll simply force it off in a not-so-nice
- * manner.
- */
-static int shutdown(void)
-{
-	int rc = kill_cad_pid(SIGINT, 1);
-
-	if (rc) {
-		printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), "
-				"hard shutdown commencing\n", rc);
-		mf_power_off();
-	} else
-		printk(KERN_INFO "mf.c: init has been successfully notified "
-				"to proceed with shutdown\n");
-	return rc;
-}
-
-/*
- * The primary partition VSP object is sending us a new
- * event flow.  Handle it...
- */
-static void handle_int(struct io_mf_lp_event *event)
-{
-	struct ce_msg_data *ce_msg_data;
-	struct ce_msg_data *pce_msg_data;
-	unsigned long flags;
-	struct pending_event *pev;
-
-	/* ack the interrupt */
-	event->hp_lp_event.xRc = HvLpEvent_Rc_Good;
-	HvCallEvent_ackLpEvent(&event->hp_lp_event);
-
-	/* process interrupt */
-	switch (event->hp_lp_event.xSubtype) {
-	case 0:	/* CE message */
-		ce_msg_data = &event->data.ce_msg;
-		switch (ce_msg_data->ce_msg[3]) {
-		case 0x5B:	/* power control notification */
-			if ((ce_msg_data->ce_msg[5] & 0x20) != 0) {
-				printk(KERN_INFO "mf.c: Commencing partition shutdown\n");
-				if (shutdown() == 0)
-					signal_ce_msg_simple(0xDB, NULL);
-			}
-			break;
-		case 0xC0:	/* get time */
-			spin_lock_irqsave(&pending_event_spinlock, flags);
-			pev = pending_event_head;
-			if (pev != NULL)
-				pending_event_head = pending_event_head->next;
-			spin_unlock_irqrestore(&pending_event_spinlock, flags);
-			if (pev == NULL)
-				break;
-			pce_msg_data = &pev->event.data.ce_msg;
-			if (pce_msg_data->ce_msg[3] != 0x40)
-				break;
-			if (pce_msg_data->completion != NULL) {
-				ce_msg_comp_hdlr handler =
-					pce_msg_data->completion->handler;
-				void *token = pce_msg_data->completion->token;
-
-				if (handler != NULL)
-					(*handler)(token, ce_msg_data);
-			}
-			spin_lock_irqsave(&pending_event_spinlock, flags);
-			free_pending_event(pev);
-			spin_unlock_irqrestore(&pending_event_spinlock, flags);
-			/* send next waiting event */
-			if (pending_event_head != NULL)
-				signal_event(NULL);
-			break;
-		}
-		break;
-	case 1:	/* IT sys shutdown */
-		printk(KERN_INFO "mf.c: Commencing system shutdown\n");
-		shutdown();
-		break;
-	}
-}
-
-/*
- * The primary partition VSP object is acknowledging the receipt
- * of a flow we sent to them.  If there are other flows queued
- * up, we must send another one now...
- */
-static void handle_ack(struct io_mf_lp_event *event)
-{
-	unsigned long flags;
-	struct pending_event *two = NULL;
-	unsigned long free_it = 0;
-	struct ce_msg_data *ce_msg_data;
-	struct ce_msg_data *pce_msg_data;
-	struct vsp_rsp_data *rsp;
-
-	/* handle current event */
-	if (pending_event_head == NULL) {
-		printk(KERN_ERR "mf.c: stack empty for receiving ack\n");
-		return;
-	}
-
-	switch (event->hp_lp_event.xSubtype) {
-	case 0:     /* CE msg */
-		ce_msg_data = &event->data.ce_msg;
-		if (ce_msg_data->ce_msg[3] != 0x40) {
-			free_it = 1;
-			break;
-		}
-		if (ce_msg_data->ce_msg[2] == 0)
-			break;
-		free_it = 1;
-		pce_msg_data = &pending_event_head->event.data.ce_msg;
-		if (pce_msg_data->completion != NULL) {
-			ce_msg_comp_hdlr handler =
-				pce_msg_data->completion->handler;
-			void *token = pce_msg_data->completion->token;
-
-			if (handler != NULL)
-				(*handler)(token, ce_msg_data);
-		}
-		break;
-	case 4:	/* allocate */
-	case 5:	/* deallocate */
-		if (pending_event_head->hdlr != NULL)
-			(*pending_event_head->hdlr)((void *)event->hp_lp_event.xCorrelationToken, event->data.alloc.count);
-		free_it = 1;
-		break;
-	case 6:
-		free_it = 1;
-		rsp = (struct vsp_rsp_data *)event->data.vsp_cmd.token;
-		if (rsp == NULL) {
-			printk(KERN_ERR "mf.c: no rsp\n");
-			break;
-		}
-		if (rsp->response != NULL)
-			memcpy(rsp->response, &event->data.vsp_cmd,
-					sizeof(event->data.vsp_cmd));
-		complete(&rsp->com);
-		break;
-	}
-
-	/* remove from queue */
-	spin_lock_irqsave(&pending_event_spinlock, flags);
-	if ((pending_event_head != NULL) && (free_it == 1)) {
-		struct pending_event *oldHead = pending_event_head;
-
-		pending_event_head = pending_event_head->next;
-		two = pending_event_head;
-		free_pending_event(oldHead);
-	}
-	spin_unlock_irqrestore(&pending_event_spinlock, flags);
-
-	/* send next waiting event */
-	if (two != NULL)
-		signal_event(NULL);
-}
-
-/*
- * This is the generic event handler we are registering with
- * the Hypervisor.  Ensure the flows are for us, and then
- * parse it enough to know if it is an interrupt or an
- * acknowledge.
- */
-static void hv_handler(struct HvLpEvent *event)
-{
-	if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) {
-		if (hvlpevent_is_ack(event))
-			handle_ack((struct io_mf_lp_event *)event);
-		else
-			handle_int((struct io_mf_lp_event *)event);
-	} else
-		printk(KERN_ERR "mf.c: alien event received\n");
-}
-
-/*
- * Global kernel interface to allocate and seed events into the
- * Hypervisor.
- */
-void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,
-		unsigned size, unsigned count, MFCompleteHandler hdlr,
-		void *user_token)
-{
-	struct pending_event *ev = new_pending_event();
-	int rc;
-
-	if (ev == NULL) {
-		rc = -ENOMEM;
-	} else {
-		ev->event.hp_lp_event.xSubtype = 4;
-		ev->event.hp_lp_event.xCorrelationToken = (u64)user_token;
-		ev->event.hp_lp_event.x.xSubtypeData =
-			subtype_data('M', 'F', 'M', 'A');
-		ev->event.data.alloc.target_lp = target_lp;
-		ev->event.data.alloc.type = type;
-		ev->event.data.alloc.size = size;
-		ev->event.data.alloc.count = count;
-		ev->hdlr = hdlr;
-		rc = signal_event(ev);
-	}
-	if ((rc != 0) && (hdlr != NULL))
-		(*hdlr)(user_token, rc);
-}
-EXPORT_SYMBOL(mf_allocate_lp_events);
-
-/*
- * Global kernel interface to unseed and deallocate events already in
- * Hypervisor.
- */
-void mf_deallocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,
-		unsigned count, MFCompleteHandler hdlr, void *user_token)
-{
-	struct pending_event *ev = new_pending_event();
-	int rc;
-
-	if (ev == NULL)
-		rc = -ENOMEM;
-	else {
-		ev->event.hp_lp_event.xSubtype = 5;
-		ev->event.hp_lp_event.xCorrelationToken = (u64)user_token;
-		ev->event.hp_lp_event.x.xSubtypeData =
-			subtype_data('M', 'F', 'M', 'D');
-		ev->event.data.alloc.target_lp = target_lp;
-		ev->event.data.alloc.type = type;
-		ev->event.data.alloc.count = count;
-		ev->hdlr = hdlr;
-		rc = signal_event(ev);
-	}
-	if ((rc != 0) && (hdlr != NULL))
-		(*hdlr)(user_token, rc);
-}
-EXPORT_SYMBOL(mf_deallocate_lp_events);
-
-/*
- * Global kernel interface to tell the VSP object in the primary
- * partition to power this partition off.
- */
-void mf_power_off(void)
-{
-	printk(KERN_INFO "mf.c: Down it goes...\n");
-	signal_ce_msg_simple(0x4d, NULL);
-	for (;;)
-		;
-}
-
-/*
- * Global kernel interface to tell the VSP object in the primary
- * partition to reboot this partition.
- */
-void mf_reboot(char *cmd)
-{
-	printk(KERN_INFO "mf.c: Preparing to bounce...\n");
-	signal_ce_msg_simple(0x4e, NULL);
-	for (;;)
-		;
-}
-
-/*
- * Display a single word SRC onto the VSP control panel.
- */
-void mf_display_src(u32 word)
-{
-	u8 ce[12];
-
-	memset(ce, 0, sizeof(ce));
-	ce[3] = 0x4a;
-	ce[7] = 0x01;
-	ce[8] = word >> 24;
-	ce[9] = word >> 16;
-	ce[10] = word >> 8;
-	ce[11] = word;
-	signal_ce_msg(ce, NULL);
-}
-
-/*
- * Display a single word SRC of the form "PROGXXXX" on the VSP control panel.
- */
-static __init void mf_display_progress_src(u16 value)
-{
-	u8 ce[12];
-	u8 src[72];
-
-	memcpy(ce, "\x00\x00\x04\x4A\x00\x00\x00\x48\x00\x00\x00\x00", 12);
-	memcpy(src, "\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
-		"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-		"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-		"\x00\x00\x00\x00PROGxxxx                        ",
-		72);
-	src[6] = value >> 8;
-	src[7] = value & 255;
-	src[44] = "0123456789ABCDEF"[(value >> 12) & 15];
-	src[45] = "0123456789ABCDEF"[(value >> 8) & 15];
-	src[46] = "0123456789ABCDEF"[(value >> 4) & 15];
-	src[47] = "0123456789ABCDEF"[value & 15];
-	dma_and_signal_ce_msg(ce, NULL, src, sizeof(src), 9 * 64 * 1024);
-}
-
-/*
- * Clear the VSP control panel.  Used to "erase" an SRC that was
- * previously displayed.
- */
-static void mf_clear_src(void)
-{
-	signal_ce_msg_simple(0x4b, NULL);
-}
-
-void __init mf_display_progress(u16 value)
-{
-	if (!mf_initialized)
-		return;
-
-	if (0xFFFF == value)
-		mf_clear_src();
-	else
-		mf_display_progress_src(value);
-}
-
-/*
- * Initialization code here.
- */
-void __init mf_init(void)
-{
-	int i;
-
-	spin_lock_init(&pending_event_spinlock);
-
-	for (i = 0; i < PENDING_EVENT_PREALLOC_LEN; i++)
-		free_pending_event(&pending_event_prealloc[i]);
-
-	HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hv_handler);
-
-	/* virtual continue ack */
-	signal_ce_msg_simple(0x57, NULL);
-
-	mf_initialized = 1;
-	mb();
-
-	printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities "
-			"initialized\n");
-}
-
-struct rtc_time_data {
-	struct completion com;
-	struct ce_msg_data ce_msg;
-	int rc;
-};
-
-static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg)
-{
-	struct rtc_time_data *rtc = token;
-
-	memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg));
-	rtc->rc = 0;
-	complete(&rtc->com);
-}
-
-static int mf_set_rtc(struct rtc_time *tm)
-{
-	char ce_time[12];
-	u8 day, mon, hour, min, sec, y1, y2;
-	unsigned year;
-
-	year = 1900 + tm->tm_year;
-	y1 = year / 100;
-	y2 = year % 100;
-
-	sec = tm->tm_sec;
-	min = tm->tm_min;
-	hour = tm->tm_hour;
-	day = tm->tm_mday;
-	mon = tm->tm_mon + 1;
-
-	sec = bin2bcd(sec);
-	min = bin2bcd(min);
-	hour = bin2bcd(hour);
-	mon = bin2bcd(mon);
-	day = bin2bcd(day);
-	y1 = bin2bcd(y1);
-	y2 = bin2bcd(y2);
-
-	memset(ce_time, 0, sizeof(ce_time));
-	ce_time[3] = 0x41;
-	ce_time[4] = y1;
-	ce_time[5] = y2;
-	ce_time[6] = sec;
-	ce_time[7] = min;
-	ce_time[8] = hour;
-	ce_time[10] = day;
-	ce_time[11] = mon;
-
-	return signal_ce_msg(ce_time, NULL);
-}
-
-static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm)
-{
-	tm->tm_wday = 0;
-	tm->tm_yday = 0;
-	tm->tm_isdst = 0;
-	if (rc) {
-		tm->tm_sec = 0;
-		tm->tm_min = 0;
-		tm->tm_hour = 0;
-		tm->tm_mday = 15;
-		tm->tm_mon = 5;
-		tm->tm_year = 52;
-		return rc;
-	}
-
-	if ((ce_msg[2] == 0xa9) ||
-	    (ce_msg[2] == 0xaf)) {
-		/* TOD clock is not set */
-		tm->tm_sec = 1;
-		tm->tm_min = 1;
-		tm->tm_hour = 1;
-		tm->tm_mday = 10;
-		tm->tm_mon = 8;
-		tm->tm_year = 71;
-		mf_set_rtc(tm);
-	}
-	{
-		u8 year = ce_msg[5];
-		u8 sec = ce_msg[6];
-		u8 min = ce_msg[7];
-		u8 hour = ce_msg[8];
-		u8 day = ce_msg[10];
-		u8 mon = ce_msg[11];
-
-		sec = bcd2bin(sec);
-		min = bcd2bin(min);
-		hour = bcd2bin(hour);
-		day = bcd2bin(day);
-		mon = bcd2bin(mon);
-		year = bcd2bin(year);
-
-		if (year <= 69)
-			year += 100;
-
-		tm->tm_sec = sec;
-		tm->tm_min = min;
-		tm->tm_hour = hour;
-		tm->tm_mday = day;
-		tm->tm_mon = mon;
-		tm->tm_year = year;
-	}
-
-	return 0;
-}
-
-static int mf_get_rtc(struct rtc_time *tm)
-{
-	struct ce_msg_comp_data ce_complete;
-	struct rtc_time_data rtc_data;
-	int rc;
-
-	memset(&ce_complete, 0, sizeof(ce_complete));
-	memset(&rtc_data, 0, sizeof(rtc_data));
-	init_completion(&rtc_data.com);
-	ce_complete.handler = &get_rtc_time_complete;
-	ce_complete.token = &rtc_data;
-	rc = signal_ce_msg_simple(0x40, &ce_complete);
-	if (rc)
-		return rc;
-	wait_for_completion(&rtc_data.com);
-	return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);
-}
-
-struct boot_rtc_time_data {
-	int busy;
-	struct ce_msg_data ce_msg;
-	int rc;
-};
-
-static void get_boot_rtc_time_complete(void *token, struct ce_msg_data *ce_msg)
-{
-	struct boot_rtc_time_data *rtc = token;
-
-	memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg));
-	rtc->rc = 0;
-	rtc->busy = 0;
-}
-
-static int mf_get_boot_rtc(struct rtc_time *tm)
-{
-	struct ce_msg_comp_data ce_complete;
-	struct boot_rtc_time_data rtc_data;
-	int rc;
-
-	memset(&ce_complete, 0, sizeof(ce_complete));
-	memset(&rtc_data, 0, sizeof(rtc_data));
-	rtc_data.busy = 1;
-	ce_complete.handler = &get_boot_rtc_time_complete;
-	ce_complete.token = &rtc_data;
-	rc = signal_ce_msg_simple(0x40, &ce_complete);
-	if (rc)
-		return rc;
-	/* We need to poll here as we are not yet taking interrupts */
-	while (rtc_data.busy) {
-		if (hvlpevent_is_pending())
-			process_hvlpevents();
-	}
-	return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);
-}
-
-#ifdef CONFIG_PROC_FS
-static int mf_cmdline_proc_show(struct seq_file *m, void *v)
-{
-	char *page, *p;
-	struct vsp_cmd_data vsp_cmd;
-	int rc;
-	dma_addr_t dma_addr;
-
-	/* The HV appears to return no more than 256 bytes of command line */
-	page = kmalloc(256, GFP_KERNEL);
-	if (!page)
-		return -ENOMEM;
-
-	dma_addr = iseries_hv_map(page, 256, DMA_FROM_DEVICE);
-	if (dma_addr == DMA_ERROR_CODE) {
-		kfree(page);
-		return -ENOMEM;
-	}
-	memset(page, 0, 256);
-	memset(&vsp_cmd, 0, sizeof(vsp_cmd));
-	vsp_cmd.cmd = 33;
-	vsp_cmd.sub_data.kern.token = dma_addr;
-	vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-	vsp_cmd.sub_data.kern.side = (u64)m->private;
-	vsp_cmd.sub_data.kern.length = 256;
-	mb();
-	rc = signal_vsp_instruction(&vsp_cmd);
-	iseries_hv_unmap(dma_addr, 256, DMA_FROM_DEVICE);
-	if (rc) {
-		kfree(page);
-		return rc;
-	}
-	if (vsp_cmd.result_code != 0) {
-		kfree(page);
-		return -ENOMEM;
-	}
-	p = page;
-	while (p - page < 256) {
-		if (*p == '\0' || *p == '\n') {
-			*p = '\n';
-			break;
-		}
-		p++;
-
-	}
-	seq_write(m, page, p - page);
-	kfree(page);
-	return 0;
-}
-
-static int mf_cmdline_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, mf_cmdline_proc_show, PDE(inode)->data);
-}
-
-#if 0
-static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
-{
-	struct vsp_cmd_data vsp_cmd;
-	int rc;
-	int len = *size;
-	dma_addr_t dma_addr;
-
-	dma_addr = iseries_hv_map(buffer, len, DMA_FROM_DEVICE);
-	memset(buffer, 0, len);
-	memset(&vsp_cmd, 0, sizeof(vsp_cmd));
-	vsp_cmd.cmd = 32;
-	vsp_cmd.sub_data.kern.token = dma_addr;
-	vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-	vsp_cmd.sub_data.kern.side = side;
-	vsp_cmd.sub_data.kern.offset = offset;
-	vsp_cmd.sub_data.kern.length = len;
-	mb();
-	rc = signal_vsp_instruction(&vsp_cmd);
-	if (rc == 0) {
-		if (vsp_cmd.result_code == 0)
-			*size = vsp_cmd.sub_data.length_out;
-		else
-			rc = -ENOMEM;
-	}
-
-	iseries_hv_unmap(dma_addr, len, DMA_FROM_DEVICE);
-
-	return rc;
-}
-
-static int proc_mf_dump_vmlinux(char *page, char **start, off_t off,
-		int count, int *eof, void *data)
-{
-	int sizeToGet = count;
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-
-	if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0) {
-		if (sizeToGet != 0) {
-			*start = page + off;
-			return sizeToGet;
-		}
-		*eof = 1;
-		return 0;
-	}
-	*eof = 1;
-	return 0;
-}
-#endif
-
-static int mf_side_proc_show(struct seq_file *m, void *v)
-{
-	char mf_current_side = ' ';
-	struct vsp_cmd_data vsp_cmd;
-
-	memset(&vsp_cmd, 0, sizeof(vsp_cmd));
-	vsp_cmd.cmd = 2;
-	vsp_cmd.sub_data.ipl_type = 0;
-	mb();
-
-	if (signal_vsp_instruction(&vsp_cmd) == 0) {
-		if (vsp_cmd.result_code == 0) {
-			switch (vsp_cmd.sub_data.ipl_type) {
-			case 0:	mf_current_side = 'A';
-				break;
-			case 1:	mf_current_side = 'B';
-				break;
-			case 2:	mf_current_side = 'C';
-				break;
-			default:	mf_current_side = 'D';
-				break;
-			}
-		}
-	}
-
-	seq_printf(m, "%c\n", mf_current_side);
-	return 0;
-}
-
-static int mf_side_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, mf_side_proc_show, NULL);
-}
-
-static ssize_t mf_side_proc_write(struct file *file, const char __user *buffer,
-				  size_t count, loff_t *pos)
-{
-	char side;
-	u64 newSide;
-	struct vsp_cmd_data vsp_cmd;
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-
-	if (count == 0)
-		return 0;
-
-	if (get_user(side, buffer))
-		return -EFAULT;
-
-	switch (side) {
-	case 'A':	newSide = 0;
-			break;
-	case 'B':	newSide = 1;
-			break;
-	case 'C':	newSide = 2;
-			break;
-	case 'D':	newSide = 3;
-			break;
-	default:
-		printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n");
-		return -EINVAL;
-	}
-
-	memset(&vsp_cmd, 0, sizeof(vsp_cmd));
-	vsp_cmd.sub_data.ipl_type = newSide;
-	vsp_cmd.cmd = 10;
-
-	(void)signal_vsp_instruction(&vsp_cmd);
-
-	return count;
-}
-
-static const struct file_operations mf_side_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= mf_side_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-	.write		= mf_side_proc_write,
-};
-
-static int mf_src_proc_show(struct seq_file *m, void *v)
-{
-	return 0;
-}
-
-static int mf_src_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, mf_src_proc_show, NULL);
-}
-
-static ssize_t mf_src_proc_write(struct file *file, const char __user *buffer,
-				 size_t count, loff_t *pos)
-{
-	char stkbuf[10];
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-
-	if ((count < 4) && (count != 1)) {
-		printk(KERN_ERR "mf_proc: invalid src\n");
-		return -EINVAL;
-	}
-
-	if (count > (sizeof(stkbuf) - 1))
-		count = sizeof(stkbuf) - 1;
-	if (copy_from_user(stkbuf, buffer, count))
-		return -EFAULT;
-
-	if ((count == 1) && (*stkbuf == '\0'))
-		mf_clear_src();
-	else
-		mf_display_src(*(u32 *)stkbuf);
-
-	return count;
-}
-
-static const struct file_operations mf_src_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= mf_src_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-	.write		= mf_src_proc_write,
-};
-
-static ssize_t mf_cmdline_proc_write(struct file *file, const char __user *buffer,
-				     size_t count, loff_t *pos)
-{
-	void *data = PDE(file->f_path.dentry->d_inode)->data;
-	struct vsp_cmd_data vsp_cmd;
-	dma_addr_t dma_addr;
-	char *page;
-	int ret = -EACCES;
-
-	if (!capable(CAP_SYS_ADMIN))
-		goto out;
-
-	dma_addr = 0;
-	page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC);
-	ret = -ENOMEM;
-	if (page == NULL)
-		goto out;
-
-	ret = -EFAULT;
-	if (copy_from_user(page, buffer, count))
-		goto out_free;
-
-	memset(&vsp_cmd, 0, sizeof(vsp_cmd));
-	vsp_cmd.cmd = 31;
-	vsp_cmd.sub_data.kern.token = dma_addr;
-	vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-	vsp_cmd.sub_data.kern.side = (u64)data;
-	vsp_cmd.sub_data.kern.length = count;
-	mb();
-	(void)signal_vsp_instruction(&vsp_cmd);
-	ret = count;
-
-out_free:
-	iseries_hv_free(count, page, dma_addr);
-out:
-	return ret;
-}
-
-static const struct file_operations mf_cmdline_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= mf_cmdline_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-	.write		= mf_cmdline_proc_write,
-};
-
-static ssize_t proc_mf_change_vmlinux(struct file *file,
-				      const char __user *buf,
-				      size_t count, loff_t *ppos)
-{
-	struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
-	ssize_t rc;
-	dma_addr_t dma_addr;
-	char *page;
-	struct vsp_cmd_data vsp_cmd;
-
-	rc = -EACCES;
-	if (!capable(CAP_SYS_ADMIN))
-		goto out;
-
-	dma_addr = 0;
-	page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC);
-	rc = -ENOMEM;
-	if (page == NULL) {
-		printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n");
-		goto out;
-	}
-	rc = -EFAULT;
-	if (copy_from_user(page, buf, count))
-		goto out_free;
-
-	memset(&vsp_cmd, 0, sizeof(vsp_cmd));
-	vsp_cmd.cmd = 30;
-	vsp_cmd.sub_data.kern.token = dma_addr;
-	vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-	vsp_cmd.sub_data.kern.side = (u64)dp->data;
-	vsp_cmd.sub_data.kern.offset = *ppos;
-	vsp_cmd.sub_data.kern.length = count;
-	mb();
-	rc = signal_vsp_instruction(&vsp_cmd);
-	if (rc)
-		goto out_free;
-	rc = -ENOMEM;
-	if (vsp_cmd.result_code != 0)
-		goto out_free;
-
-	*ppos += count;
-	rc = count;
-out_free:
-	iseries_hv_free(count, page, dma_addr);
-out:
-	return rc;
-}
-
-static const struct file_operations proc_vmlinux_operations = {
-	.write		= proc_mf_change_vmlinux,
-	.llseek		= default_llseek,
-};
-
-static int __init mf_proc_init(void)
-{
-	struct proc_dir_entry *mf_proc_root;
-	struct proc_dir_entry *ent;
-	struct proc_dir_entry *mf;
-	char name[2];
-	int i;
-
-	if (!firmware_has_feature(FW_FEATURE_ISERIES))
-		return 0;
-
-	mf_proc_root = proc_mkdir("iSeries/mf", NULL);
-	if (!mf_proc_root)
-		return 1;
-
-	name[1] = '\0';
-	for (i = 0; i < 4; i++) {
-		name[0] = 'A' + i;
-		mf = proc_mkdir(name, mf_proc_root);
-		if (!mf)
-			return 1;
-
-		ent = proc_create_data("cmdline", S_IRUSR|S_IWUSR, mf,
-				       &mf_cmdline_proc_fops, (void *)(long)i);
-		if (!ent)
-			return 1;
-
-		if (i == 3)	/* no vmlinux entry for 'D' */
-			continue;
-
-		ent = proc_create_data("vmlinux", S_IFREG|S_IWUSR, mf,
-				       &proc_vmlinux_operations,
-				       (void *)(long)i);
-		if (!ent)
-			return 1;
-	}
-
-	ent = proc_create("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root,
-			  &mf_side_proc_fops);
-	if (!ent)
-		return 1;
-
-	ent = proc_create("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root,
-			  &mf_src_proc_fops);
-	if (!ent)
-		return 1;
-
-	return 0;
-}
-
-__initcall(mf_proc_init);
-
-#endif /* CONFIG_PROC_FS */
-
-/*
- * Get the RTC from the virtual service processor
- * This requires flowing LpEvents to the primary partition
- */
-void iSeries_get_rtc_time(struct rtc_time *rtc_tm)
-{
-	mf_get_rtc(rtc_tm);
-	rtc_tm->tm_mon--;
-}
-
-/*
- * Set the RTC in the virtual service processor
- * This requires flowing LpEvents to the primary partition
- */
-int iSeries_set_rtc_time(struct rtc_time *tm)
-{
-	mf_set_rtc(tm);
-	return 0;
-}
-
-unsigned long iSeries_get_boot_time(void)
-{
-	struct rtc_time tm;
-
-	mf_get_boot_rtc(&tm);
-	return mktime(tm.tm_year + 1900, tm.tm_mon, tm.tm_mday,
-		      tm.tm_hour, tm.tm_min, tm.tm_sec);
-}
diff --git a/arch/powerpc/platforms/iseries/misc.S b/arch/powerpc/platforms/iseries/misc.S
deleted file mode 100644
index 2c6ff0f..0000000
--- a/arch/powerpc/platforms/iseries/misc.S
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file contains miscellaneous low-level functions.
- *    Copyright (C) 1995-2005 IBM Corp
- *
- * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
- * and Paul Mackerras.
- * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
- * PPC64 updates by Dave Engebretsen (engebret@us.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 option) any later version.
- */
-
-#include <asm/processor.h>
-#include <asm/asm-offsets.h>
-#include <asm/ppc_asm.h>
-
-	.text
-
-/* Handle pending interrupts in interrupt context */
-_GLOBAL(iseries_handle_interrupts)
-	li	r0,0x5555
-	sc
-	blr
diff --git a/arch/powerpc/platforms/iseries/naca.h b/arch/powerpc/platforms/iseries/naca.h
deleted file mode 100644
index f01708e..0000000
--- a/arch/powerpc/platforms/iseries/naca.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef _PLATFORMS_ISERIES_NACA_H
-#define _PLATFORMS_ISERIES_NACA_H
-
-/*
- * c 2001 PPC 64 Team, IBM Corp
- *
- * 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 <asm/types.h>
-
-struct naca_struct {
-	/* Kernel only data - undefined for user space */
-	const void *xItVpdAreas;	/* VPD Data                  0x00 */
-	void *xRamDisk;                 /* iSeries ramdisk           0x08 */
-	u64   xRamDiskSize;		/* In pages                  0x10 */
-};
-
-extern struct naca_struct naca;
-
-#endif /* _PLATFORMS_ISERIES_NACA_H */
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
deleted file mode 100644
index c754128..0000000
--- a/arch/powerpc/platforms/iseries/pci.c
+++ /dev/null
@@ -1,919 +0,0 @@
-/*
- * Copyright (C) 2001 Allan Trautman, IBM Corporation
- * Copyright (C) 2005,2007  Stephen Rothwell, IBM Corp
- *
- * iSeries specific routines for PCI.
- *
- * Based on code from pci.c and iSeries_pci.c 32bit
- *
- * 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
- */
-
-#undef DEBUG
-
-#include <linux/jiffies.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/of.h>
-#include <linux/ratelimit.h>
-
-#include <asm/types.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-#include <asm/iommu.h>
-#include <asm/abs_addr.h>
-#include <asm/firmware.h>
-
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/iseries/mf.h>
-#include <asm/iseries/iommu.h>
-
-#include <asm/ppc-pci.h>
-
-#include "irq.h"
-#include "pci.h"
-#include "call_pci.h"
-
-#define PCI_RETRY_MAX	3
-static int limit_pci_retries = 1;	/* Set Retry Error on. */
-
-/*
- * Table defines
- * Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space.
- */
-#define IOMM_TABLE_MAX_ENTRIES	1024
-#define IOMM_TABLE_ENTRY_SIZE	0x0000000000400000UL
-#define BASE_IO_MEMORY		0xE000000000000000UL
-#define END_IO_MEMORY		0xEFFFFFFFFFFFFFFFUL
-
-static unsigned long max_io_memory = BASE_IO_MEMORY;
-static long current_iomm_table_entry;
-
-/*
- * Lookup Tables.
- */
-static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES];
-static u64 ds_addr_table[IOMM_TABLE_MAX_ENTRIES];
-
-static DEFINE_SPINLOCK(iomm_table_lock);
-
-/*
- * Generate a Direct Select Address for the Hypervisor
- */
-static inline u64 iseries_ds_addr(struct device_node *node)
-{
-	struct pci_dn *pdn = PCI_DN(node);
-	const u32 *sbp = of_get_property(node, "linux,subbus", NULL);
-
-	return ((u64)pdn->busno << 48) + ((u64)(sbp ? *sbp : 0) << 40)
-			+ ((u64)0x10 << 32);
-}
-
-/*
- * Size of Bus VPD data
- */
-#define BUS_VPDSIZE      1024
-
-/*
- * Bus Vpd Tags
- */
-#define VPD_END_OF_AREA		0x79
-#define VPD_ID_STRING		0x82
-#define VPD_VENDOR_AREA		0x84
-
-/*
- * Mfg Area Tags
- */
-#define VPD_FRU_FRAME_ID	0x4649	/* "FI" */
-#define VPD_SLOT_MAP_FORMAT	0x4D46	/* "MF" */
-#define VPD_SLOT_MAP		0x534D	/* "SM" */
-
-/*
- * Structures of the areas
- */
-struct mfg_vpd_area {
-	u16	tag;
-	u8	length;
-	u8	data1;
-	u8	data2;
-};
-#define MFG_ENTRY_SIZE   3
-
-struct slot_map {
-	u8	agent;
-	u8	secondary_agent;
-	u8	phb;
-	char	card_location[3];
-	char	parms[8];
-	char	reserved[2];
-};
-#define SLOT_ENTRY_SIZE   16
-
-/*
- * Parse the Slot Area
- */
-static void __init iseries_parse_slot_area(struct slot_map *map, int len,
-		HvAgentId agent, u8 *phb, char card[4])
-{
-	/*
-	 * Parse Slot label until we find the one requested
-	 */
-	while (len > 0) {
-		if (map->agent == agent) {
-			/*
-			 * If Phb wasn't found, grab the entry first one found.
-			 */
-			if (*phb == 0xff)
-				*phb = map->phb;
-			/* Found it, extract the data. */
-			if (map->phb == *phb) {
-				memcpy(card, &map->card_location, 3);
-				card[3]  = 0;
-				break;
-			}
-		}
-		/* Point to the next Slot */
-		map = (struct slot_map *)((char *)map + SLOT_ENTRY_SIZE);
-		len -= SLOT_ENTRY_SIZE;
-	}
-}
-
-/*
- * Parse the Mfg Area
- */
-static void __init iseries_parse_mfg_area(struct mfg_vpd_area *area, int len,
-		HvAgentId agent, u8 *phb, u8 *frame, char card[4])
-{
-	u16 slot_map_fmt = 0;
-
-	/* Parse Mfg Data */
-	while (len > 0) {
-		int mfg_tag_len = area->length;
-		/* Frame ID         (FI 4649020310 ) */
-		if (area->tag == VPD_FRU_FRAME_ID)
-			*frame = area->data1;
-		/* Slot Map Format  (MF 4D46020004 ) */
-		else if (area->tag == VPD_SLOT_MAP_FORMAT)
-			slot_map_fmt = (area->data1 * 256)
-				+ area->data2;
-		/* Slot Map         (SM 534D90 */
-		else if (area->tag == VPD_SLOT_MAP) {
-			struct slot_map *slot_map;
-
-			if (slot_map_fmt == 0x1004)
-				slot_map = (struct slot_map *)((char *)area
-						+ MFG_ENTRY_SIZE + 1);
-			else
-				slot_map = (struct slot_map *)((char *)area
-						+ MFG_ENTRY_SIZE);
-			iseries_parse_slot_area(slot_map, mfg_tag_len,
-					agent, phb, card);
-		}
-		/*
-		 * Point to the next Mfg Area
-		 * Use defined size, sizeof give wrong answer
-		 */
-		area = (struct mfg_vpd_area *)((char *)area + mfg_tag_len
-				+ MFG_ENTRY_SIZE);
-		len -= (mfg_tag_len + MFG_ENTRY_SIZE);
-	}
-}
-
-/*
- * Look for "BUS".. Data is not Null terminated.
- * PHBID of 0xFF indicates PHB was not found in VPD Data.
- */
-static u8 __init iseries_parse_phbid(u8 *area, int len)
-{
-	while (len > 0) {
-		if ((*area == 'B') && (*(area + 1) == 'U')
-				&& (*(area + 2) == 'S')) {
-			area += 3;
-			while (*area == ' ')
-				area++;
-			return *area & 0x0F;
-		}
-		area++;
-		len--;
-	}
-	return 0xff;
-}
-
-/*
- * Parse out the VPD Areas
- */
-static void __init iseries_parse_vpd(u8 *data, int data_len,
-		HvAgentId agent, u8 *frame, char card[4])
-{
-	u8 phb = 0xff;
-
-	while (data_len > 0) {
-		int len;
-		u8 tag = *data;
-
-		if (tag == VPD_END_OF_AREA)
-			break;
-		len = *(data + 1) + (*(data + 2) * 256);
-		data += 3;
-		data_len -= 3;
-		if (tag == VPD_ID_STRING)
-			phb = iseries_parse_phbid(data, len);
-		else if (tag == VPD_VENDOR_AREA)
-			iseries_parse_mfg_area((struct mfg_vpd_area *)data, len,
-					agent, &phb, frame, card);
-		/* Point to next Area. */
-		data += len;
-		data_len -= len;
-	}
-}
-
-static int __init iseries_get_location_code(u16 bus, HvAgentId agent,
-		u8 *frame, char card[4])
-{
-	int status = 0;
-	int bus_vpd_len = 0;
-	u8 *bus_vpd = kmalloc(BUS_VPDSIZE, GFP_KERNEL);
-
-	if (bus_vpd == NULL) {
-		printk("PCI: Bus VPD Buffer allocation failure.\n");
-		return 0;
-	}
-	bus_vpd_len = HvCallPci_getBusVpd(bus, iseries_hv_addr(bus_vpd),
-					BUS_VPDSIZE);
-	if (bus_vpd_len == 0) {
-		printk("PCI: Bus VPD Buffer zero length.\n");
-		goto out_free;
-	}
-	/* printk("PCI: bus_vpd: %p, %d\n",bus_vpd, bus_vpd_len); */
-	/* Make sure this is what I think it is */
-	if (*bus_vpd != VPD_ID_STRING) {
-		printk("PCI: Bus VPD Buffer missing starting tag.\n");
-		goto out_free;
-	}
-	iseries_parse_vpd(bus_vpd, bus_vpd_len, agent, frame, card);
-	status = 1;
-out_free:
-	kfree(bus_vpd);
-	return status;
-}
-
-/*
- * Prints the device information.
- * - Pass in pci_dev* pointer to the device.
- * - Pass in the device count
- *
- * Format:
- * PCI: Bus  0, Device 26, Vendor 0x12AE  Frame  1, Card  C10  Ethernet
- * controller
- */
-static void __init iseries_device_information(struct pci_dev *pdev,
-					      u16 bus, HvSubBusNumber subbus)
-{
-	u8 frame = 0;
-	char card[4];
-	HvAgentId agent;
-
-	agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus),
-			ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));
-
-	if (iseries_get_location_code(bus, agent, &frame, card)) {
-		printk(KERN_INFO "PCI: %s, Vendor %04X Frame%3d, "
-		       "Card %4s  0x%04X\n", pci_name(pdev), pdev->vendor,
-		       frame, card, (int)(pdev->class >> 8));
-	}
-}
-
-/*
- * iomm_table_allocate_entry
- *
- * Adds pci_dev entry in address translation table
- *
- * - Allocates the number of entries required in table base on BAR
- *   size.
- * - Allocates starting at BASE_IO_MEMORY and increases.
- * - The size is round up to be a multiple of entry size.
- * - CurrentIndex is incremented to keep track of the last entry.
- * - Builds the resource entry for allocated BARs.
- */
-static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
-{
-	struct resource *bar_res = &dev->resource[bar_num];
-	long bar_size = pci_resource_len(dev, bar_num);
-	struct device_node *dn = pci_device_to_OF_node(dev);
-
-	/*
-	 * No space to allocate, quick exit, skip Allocation.
-	 */
-	if (bar_size == 0)
-		return;
-	/*
-	 * Set Resource values.
-	 */
-	spin_lock(&iomm_table_lock);
-	bar_res->start = BASE_IO_MEMORY +
-		IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
-	bar_res->end = bar_res->start + bar_size - 1;
-	/*
-	 * Allocate the number of table entries needed for BAR.
-	 */
-	while (bar_size > 0 ) {
-		iomm_table[current_iomm_table_entry] = dn;
-		ds_addr_table[current_iomm_table_entry] =
-			iseries_ds_addr(dn) | (bar_num << 24);
-		bar_size -= IOMM_TABLE_ENTRY_SIZE;
-		++current_iomm_table_entry;
-	}
-	max_io_memory = BASE_IO_MEMORY +
-		IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
-	spin_unlock(&iomm_table_lock);
-}
-
-/*
- * allocate_device_bars
- *
- * - Allocates ALL pci_dev BAR's and updates the resources with the
- *   BAR value.  BARS with zero length will have the resources
- *   The HvCallPci_getBarParms is used to get the size of the BAR
- *   space.  It calls iomm_table_allocate_entry to allocate
- *   each entry.
- * - Loops through The Bar resources(0 - 5) including the ROM
- *   is resource(6).
- */
-static void __init allocate_device_bars(struct pci_dev *dev)
-{
-	int bar_num;
-
-	for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num)
-		iomm_table_allocate_entry(dev, bar_num);
-}
-
-/*
- * Log error information to system console.
- * Filter out the device not there errors.
- * PCI: EADs Connect Failed 0x18.58.10 Rc: 0x00xx
- * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx
- * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx
- */
-static void pci_log_error(char *error, int bus, int subbus,
-		int agent, int hv_res)
-{
-	if (hv_res == 0x0302)
-		return;
-	printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X",
-	       error, bus, subbus, agent, hv_res);
-}
-
-/*
- * Look down the chain to find the matching Device Device
- */
-static struct device_node *find_device_node(int bus, int devfn)
-{
-	struct device_node *node;
-
-	for (node = NULL; (node = of_find_all_nodes(node)); ) {
-		struct pci_dn *pdn = PCI_DN(node);
-
-		if (pdn && (bus == pdn->busno) && (devfn == pdn->devfn))
-			return node;
-	}
-	return NULL;
-}
-
-/*
- * iSeries_pcibios_fixup_resources
- *
- * Fixes up all resources for devices
- */
-void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev)
-{
-	const u32 *agent;
-	const u32 *sub_bus;
-	unsigned char bus = pdev->bus->number;
-	struct device_node *node;
-	int i;
-
-	node = pci_device_to_OF_node(pdev);
-	pr_debug("PCI: iSeries %s, pdev %p, node %p\n",
-		 pci_name(pdev), pdev, node);
-	if (!node) {
-		printk("PCI: %s disabled, device tree entry not found !\n",
-		       pci_name(pdev));
-		for (i = 0; i <= PCI_ROM_RESOURCE; i++)
-			pdev->resource[i].flags = 0;
-		return;
-	}
-	sub_bus = of_get_property(node, "linux,subbus", NULL);
-	agent = of_get_property(node, "linux,agent-id", NULL);
-	if (agent && sub_bus) {
-		u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus);
-		int err;
-
-		err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq);
-		if (err)
-			pci_log_error("Connect Bus Unit",
-				      bus, *sub_bus, *agent, err);
-		else {
-			err = HvCallPci_configStore8(bus, *sub_bus,
-					*agent, PCI_INTERRUPT_LINE, irq);
-			if (err)
-				pci_log_error("PciCfgStore Irq Failed!",
-						bus, *sub_bus, *agent, err);
-			else
-				pdev->irq = irq;
-		}
-	}
-
-	allocate_device_bars(pdev);
-	if (likely(sub_bus))
-		iseries_device_information(pdev, bus, *sub_bus);
-	else
-		printk(KERN_ERR "PCI: Device node %s has missing or invalid "
-				"linux,subbus property\n", node->full_name);
-}
-
-/*
- * iSeries_pci_final_fixup(void)
- */
-void __init iSeries_pci_final_fixup(void)
-{
-	/* Fix up at the device node and pci_dev relationship */
-	mf_display_src(0xC9000100);
-	iSeries_activate_IRQs();
-	mf_display_src(0xC9000200);
-}
-
-/*
- * Config space read and write functions.
- * For now at least, we look for the device node for the bus and devfn
- * that we are asked to access.  It may be possible to translate the devfn
- * to a subbus and deviceid more directly.
- */
-static u64 hv_cfg_read_func[4]  = {
-	HvCallPciConfigLoad8, HvCallPciConfigLoad16,
-	HvCallPciConfigLoad32, HvCallPciConfigLoad32
-};
-
-static u64 hv_cfg_write_func[4] = {
-	HvCallPciConfigStore8, HvCallPciConfigStore16,
-	HvCallPciConfigStore32, HvCallPciConfigStore32
-};
-
-/*
- * Read PCI config space
- */
-static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn,
-		int offset, int size, u32 *val)
-{
-	struct device_node *node = find_device_node(bus->number, devfn);
-	u64 fn;
-	struct HvCallPci_LoadReturn ret;
-
-	if (node == NULL)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	if (offset > 255) {
-		*val = ~0;
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	}
-
-	fn = hv_cfg_read_func[(size - 1) & 3];
-	HvCall3Ret16(fn, &ret, iseries_ds_addr(node), offset, 0);
-
-	if (ret.rc != 0) {
-		*val = ~0;
-		return PCIBIOS_DEVICE_NOT_FOUND;	/* or something */
-	}
-
-	*val = ret.value;
-	return 0;
-}
-
-/*
- * Write PCI config space
- */
-
-static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn,
-		int offset, int size, u32 val)
-{
-	struct device_node *node = find_device_node(bus->number, devfn);
-	u64 fn;
-	u64 ret;
-
-	if (node == NULL)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	if (offset > 255)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-
-	fn = hv_cfg_write_func[(size - 1) & 3];
-	ret = HvCall4(fn, iseries_ds_addr(node), offset, val, 0);
-
-	if (ret != 0)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	return 0;
-}
-
-static struct pci_ops iSeries_pci_ops = {
-	.read = iSeries_pci_read_config,
-	.write = iSeries_pci_write_config
-};
-
-/*
- * Check Return Code
- * -> On Failure, print and log information.
- *    Increment Retry Count, if exceeds max, panic partition.
- *
- * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234
- * PCI: Device 23.90 ReadL Retry( 1)
- * PCI: Device 23.90 ReadL Retry Successful(1)
- */
-static int check_return_code(char *type, struct device_node *dn,
-		int *retry, u64 ret)
-{
-	if (ret != 0)  {
-		struct pci_dn *pdn = PCI_DN(dn);
-
-		(*retry)++;
-		printk("PCI: %s: Device 0x%04X:%02X  I/O Error(%2d): 0x%04X\n",
-				type, pdn->busno, pdn->devfn,
-				*retry, (int)ret);
-		/*
-		 * Bump the retry and check for retry count exceeded.
-		 * If, Exceeded, panic the system.
-		 */
-		if (((*retry) > PCI_RETRY_MAX) &&
-				(limit_pci_retries > 0)) {
-			mf_display_src(0xB6000103);
-			panic_timeout = 0;
-			panic("PCI: Hardware I/O Error, SRC B6000103, "
-					"Automatic Reboot Disabled.\n");
-		}
-		return -1;	/* Retry Try */
-	}
-	return 0;
-}
-
-/*
- * Translate the I/O Address into a device node, bar, and bar offset.
- * Note: Make sure the passed variable end up on the stack to avoid
- * the exposure of being device global.
- */
-static inline struct device_node *xlate_iomm_address(
-		const volatile void __iomem *addr,
-		u64 *dsaptr, u64 *bar_offset, const char *func)
-{
-	unsigned long orig_addr;
-	unsigned long base_addr;
-	unsigned long ind;
-	struct device_node *dn;
-
-	orig_addr = (unsigned long __force)addr;
-	if ((orig_addr < BASE_IO_MEMORY) || (orig_addr >= max_io_memory)) {
-		static DEFINE_RATELIMIT_STATE(ratelimit, 60 * HZ, 10);
-
-		if (__ratelimit(&ratelimit))
-			printk(KERN_ERR
-				"iSeries_%s: invalid access at IO address %p\n",
-				func, addr);
-		return NULL;
-	}
-	base_addr = orig_addr - BASE_IO_MEMORY;
-	ind = base_addr / IOMM_TABLE_ENTRY_SIZE;
-	dn = iomm_table[ind];
-
-	if (dn != NULL) {
-		*dsaptr = ds_addr_table[ind];
-		*bar_offset = base_addr % IOMM_TABLE_ENTRY_SIZE;
-	} else
-		panic("PCI: Invalid PCI IO address detected!\n");
-	return dn;
-}
-
-/*
- * Read MM I/O Instructions for the iSeries
- * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal
- * else, data is returned in Big Endian format.
- */
-static u8 iseries_readb(const volatile void __iomem *addr)
-{
-	u64 bar_offset;
-	u64 dsa;
-	int retry = 0;
-	struct HvCallPci_LoadReturn ret;
-	struct device_node *dn =
-		xlate_iomm_address(addr, &dsa, &bar_offset, "read_byte");
-
-	if (dn == NULL)
-		return 0xff;
-	do {
-		HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, bar_offset, 0);
-	} while (check_return_code("RDB", dn, &retry, ret.rc) != 0);
-
-	return ret.value;
-}
-
-static u16 iseries_readw_be(const volatile void __iomem *addr)
-{
-	u64 bar_offset;
-	u64 dsa;
-	int retry = 0;
-	struct HvCallPci_LoadReturn ret;
-	struct device_node *dn =
-		xlate_iomm_address(addr, &dsa, &bar_offset, "read_word");
-
-	if (dn == NULL)
-		return 0xffff;
-	do {
-		HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa,
-				bar_offset, 0);
-	} while (check_return_code("RDW", dn, &retry, ret.rc) != 0);
-
-	return ret.value;
-}
-
-static u32 iseries_readl_be(const volatile void __iomem *addr)
-{
-	u64 bar_offset;
-	u64 dsa;
-	int retry = 0;
-	struct HvCallPci_LoadReturn ret;
-	struct device_node *dn =
-		xlate_iomm_address(addr, &dsa, &bar_offset, "read_long");
-
-	if (dn == NULL)
-		return 0xffffffff;
-	do {
-		HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa,
-				bar_offset, 0);
-	} while (check_return_code("RDL", dn, &retry, ret.rc) != 0);
-
-	return ret.value;
-}
-
-/*
- * Write MM I/O Instructions for the iSeries
- *
- */
-static void iseries_writeb(u8 data, volatile void __iomem *addr)
-{
-	u64 bar_offset;
-	u64 dsa;
-	int retry = 0;
-	u64 rc;
-	struct device_node *dn =
-		xlate_iomm_address(addr, &dsa, &bar_offset, "write_byte");
-
-	if (dn == NULL)
-		return;
-	do {
-		rc = HvCall4(HvCallPciBarStore8, dsa, bar_offset, data, 0);
-	} while (check_return_code("WWB", dn, &retry, rc) != 0);
-}
-
-static void iseries_writew_be(u16 data, volatile void __iomem *addr)
-{
-	u64 bar_offset;
-	u64 dsa;
-	int retry = 0;
-	u64 rc;
-	struct device_node *dn =
-		xlate_iomm_address(addr, &dsa, &bar_offset, "write_word");
-
-	if (dn == NULL)
-		return;
-	do {
-		rc = HvCall4(HvCallPciBarStore16, dsa, bar_offset, data, 0);
-	} while (check_return_code("WWW", dn, &retry, rc) != 0);
-}
-
-static void iseries_writel_be(u32 data, volatile void __iomem *addr)
-{
-	u64 bar_offset;
-	u64 dsa;
-	int retry = 0;
-	u64 rc;
-	struct device_node *dn =
-		xlate_iomm_address(addr, &dsa, &bar_offset, "write_long");
-
-	if (dn == NULL)
-		return;
-	do {
-		rc = HvCall4(HvCallPciBarStore32, dsa, bar_offset, data, 0);
-	} while (check_return_code("WWL", dn, &retry, rc) != 0);
-}
-
-static u16 iseries_readw(const volatile void __iomem *addr)
-{
-	return le16_to_cpu(iseries_readw_be(addr));
-}
-
-static u32 iseries_readl(const volatile void __iomem *addr)
-{
-	return le32_to_cpu(iseries_readl_be(addr));
-}
-
-static void iseries_writew(u16 data, volatile void __iomem *addr)
-{
-	iseries_writew_be(cpu_to_le16(data), addr);
-}
-
-static void iseries_writel(u32 data, volatile void __iomem *addr)
-{
-	iseries_writel(cpu_to_le32(data), addr);
-}
-
-static void iseries_readsb(const volatile void __iomem *addr, void *buf,
-			   unsigned long count)
-{
-	u8 *dst = buf;
-	while(count-- > 0)
-		*(dst++) = iseries_readb(addr);
-}
-
-static void iseries_readsw(const volatile void __iomem *addr, void *buf,
-			   unsigned long count)
-{
-	u16 *dst = buf;
-	while(count-- > 0)
-		*(dst++) = iseries_readw_be(addr);
-}
-
-static void iseries_readsl(const volatile void __iomem *addr, void *buf,
-			   unsigned long count)
-{
-	u32 *dst = buf;
-	while(count-- > 0)
-		*(dst++) = iseries_readl_be(addr);
-}
-
-static void iseries_writesb(volatile void __iomem *addr, const void *buf,
-			    unsigned long count)
-{
-	const u8 *src = buf;
-	while(count-- > 0)
-		iseries_writeb(*(src++), addr);
-}
-
-static void iseries_writesw(volatile void __iomem *addr, const void *buf,
-			    unsigned long count)
-{
-	const u16 *src = buf;
-	while(count-- > 0)
-		iseries_writew_be(*(src++), addr);
-}
-
-static void iseries_writesl(volatile void __iomem *addr, const void *buf,
-			    unsigned long count)
-{
-	const u32 *src = buf;
-	while(count-- > 0)
-		iseries_writel_be(*(src++), addr);
-}
-
-static void iseries_memset_io(volatile void __iomem *addr, int c,
-			      unsigned long n)
-{
-	volatile char __iomem *d = addr;
-
-	while (n-- > 0)
-		iseries_writeb(c, d++);
-}
-
-static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src,
-				  unsigned long n)
-{
-	char *d = dest;
-	const volatile char __iomem *s = src;
-
-	while (n-- > 0)
-		*d++ = iseries_readb(s++);
-}
-
-static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src,
-				unsigned long n)
-{
-	const char *s = src;
-	volatile char __iomem *d = dest;
-
-	while (n-- > 0)
-		iseries_writeb(*s++, d++);
-}
-
-/* We only set MMIO ops. The default PIO ops will be default
- * to the MMIO ops + pci_io_base which is 0 on iSeries as
- * expected so both should work.
- *
- * Note that we don't implement the readq/writeq versions as
- * I don't know of an HV call for doing so. Thus, the default
- * operation will be used instead, which will fault a the value
- * return by iSeries for MMIO addresses always hits a non mapped
- * area. This is as good as the BUG() we used to have there.
- */
-static struct ppc_pci_io __initdata iseries_pci_io = {
-	.readb = iseries_readb,
-	.readw = iseries_readw,
-	.readl = iseries_readl,
-	.readw_be = iseries_readw_be,
-	.readl_be = iseries_readl_be,
-	.writeb = iseries_writeb,
-	.writew = iseries_writew,
-	.writel = iseries_writel,
-	.writew_be = iseries_writew_be,
-	.writel_be = iseries_writel_be,
-	.readsb = iseries_readsb,
-	.readsw = iseries_readsw,
-	.readsl = iseries_readsl,
-	.writesb = iseries_writesb,
-	.writesw = iseries_writesw,
-	.writesl = iseries_writesl,
-	.memset_io = iseries_memset_io,
-	.memcpy_fromio = iseries_memcpy_fromio,
-	.memcpy_toio = iseries_memcpy_toio,
-};
-
-/*
- * iSeries_pcibios_init
- *
- * Description:
- *   This function checks for all possible system PCI host bridges that connect
- *   PCI buses.  The system hypervisor is queried as to the guest partition
- *   ownership status.  A pci_controller is built for any bus which is partially
- *   owned or fully owned by this guest partition.
- */
-void __init iSeries_pcibios_init(void)
-{
-	struct pci_controller *phb;
-	struct device_node *root = of_find_node_by_path("/");
-	struct device_node *node = NULL;
-
-	/* Install IO hooks */
-	ppc_pci_io = iseries_pci_io;
-
-	pci_probe_only = 1;
-
-	/* iSeries has no IO space in the common sense, it needs to set
-	 * the IO base to 0
-	 */
-	pci_io_base = 0;
-
-	if (root == NULL) {
-		printk(KERN_CRIT "iSeries_pcibios_init: can't find root "
-				"of device tree\n");
-		return;
-	}
-	while ((node = of_get_next_child(root, node)) != NULL) {
-		HvBusNumber bus;
-		const u32 *busp;
-
-		if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
-			continue;
-
-		busp = of_get_property(node, "bus-range", NULL);
-		if (busp == NULL)
-			continue;
-		bus = *busp;
-		printk("bus %d appears to exist\n", bus);
-		phb = pcibios_alloc_controller(node);
-		if (phb == NULL)
-			continue;
-		/* All legacy iSeries PHBs are in domain zero */
-		phb->global_number = 0;
-
-		phb->first_busno = bus;
-		phb->last_busno = bus;
-		phb->ops = &iSeries_pci_ops;
-		phb->io_base_virt = (void __iomem *)_IO_BASE;
-		phb->io_resource.flags = IORESOURCE_IO;
-		phb->io_resource.start = BASE_IO_MEMORY;
-		phb->io_resource.end = END_IO_MEMORY;
-		phb->io_resource.name = "iSeries PCI IO";
-		phb->mem_resources[0].flags = IORESOURCE_MEM;
-		phb->mem_resources[0].start = BASE_IO_MEMORY;
-		phb->mem_resources[0].end = END_IO_MEMORY;
-		phb->mem_resources[0].name = "Series PCI MEM";
-	}
-
-	of_node_put(root);
-
-	pci_devs_phb_init();
-}
-
diff --git a/arch/powerpc/platforms/iseries/pci.h b/arch/powerpc/platforms/iseries/pci.h
deleted file mode 100644
index d9cf974..0000000
--- a/arch/powerpc/platforms/iseries/pci.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef _PLATFORMS_ISERIES_PCI_H
-#define _PLATFORMS_ISERIES_PCI_H
-
-/*
- * Created by Allan Trautman on Tue Feb 20, 2001.
- *
- * Define some useful macros for the iSeries pci routines.
- * Copyright (C) 2001  Allan H Trautman, 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- *
- * Change Activity:
- *   Created Feb 20, 2001
- *   Added device reset, March 22, 2001
- *   Ported to ppc64, May 25, 2001
- * End Change Activity
- */
-
-/*
- * Decodes Linux DevFn to iSeries DevFn, bridge device, or function.
- * For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h
- */
-
-#define ISERIES_PCI_AGENTID(idsel, func)	\
-	(((idsel & 0x0F) << 4) | (func & 0x07))
-#define ISERIES_ENCODE_DEVICE(agentid)		\
-	((0x10) | ((agentid & 0x20) >> 2) | (agentid & 0x07))
-
-#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus)		((subbus >> 5) & 0x7)
-#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)	((subbus >> 2) & 0x7)
-
-struct pci_dev;
-
-#ifdef CONFIG_PCI
-extern void	iSeries_pcibios_init(void);
-extern void	iSeries_pci_final_fixup(void);
-extern void 	iSeries_pcibios_fixup_resources(struct pci_dev *dev);
-#else
-static inline void	iSeries_pcibios_init(void) { }
-static inline void	iSeries_pci_final_fixup(void) { }
-static inline void 	iSeries_pcibios_fixup_resources(struct pci_dev *dev) {}
-#endif
-
-#endif /* _PLATFORMS_ISERIES_PCI_H */
diff --git a/arch/powerpc/platforms/iseries/proc.c b/arch/powerpc/platforms/iseries/proc.c
deleted file mode 100644
index 0676368..0000000
--- a/arch/powerpc/platforms/iseries/proc.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2001  Kyle A. Lucke IBM Corporation
- * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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/init.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/param.h>		/* for HZ */
-#include <asm/paca.h>
-#include <asm/processor.h>
-#include <asm/time.h>
-#include <asm/lppaca.h>
-#include <asm/firmware.h>
-#include <asm/iseries/hv_call_xm.h>
-
-#include "processor_vpd.h"
-#include "main_store.h"
-
-static int __init iseries_proc_create(void)
-{
-	struct proc_dir_entry *e;
-
-	if (!firmware_has_feature(FW_FEATURE_ISERIES))
-		return 0;
-
-	e = proc_mkdir("iSeries", 0);
-	if (!e)
-		return 1;
-
-	return 0;
-}
-core_initcall(iseries_proc_create);
-
-static unsigned long startTitan = 0;
-static unsigned long startTb = 0;
-
-static int proc_titantod_show(struct seq_file *m, void *v)
-{
-	unsigned long tb0, titan_tod;
-
-	tb0 = get_tb();
-	titan_tod = HvCallXm_loadTod();
-
-	seq_printf(m, "Titan\n" );
-	seq_printf(m, "  time base =          %016lx\n", tb0);
-	seq_printf(m, "  titan tod =          %016lx\n", titan_tod);
-	seq_printf(m, "  xProcFreq =          %016x\n",
-		   xIoHriProcessorVpd[0].xProcFreq);
-	seq_printf(m, "  xTimeBaseFreq =      %016x\n",
-		   xIoHriProcessorVpd[0].xTimeBaseFreq);
-	seq_printf(m, "  tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy);
-	seq_printf(m, "  tb_ticks_per_usec  = %lu\n", tb_ticks_per_usec);
-
-	if (!startTitan) {
-		startTitan = titan_tod;
-		startTb = tb0;
-	} else {
-		unsigned long titan_usec = (titan_tod - startTitan) >> 12;
-		unsigned long tb_ticks = (tb0 - startTb);
-		unsigned long titan_jiffies = titan_usec / (1000000/HZ);
-		unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ);
-		unsigned long titan_jiff_rem_usec =
-			titan_usec - titan_jiff_usec;
-		unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy;
-		unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy;
-		unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks;
-		unsigned long tb_jiff_rem_usec =
-			tb_jiff_rem_ticks / tb_ticks_per_usec;
-		unsigned long new_tb_ticks_per_jiffy =
-			(tb_ticks * (1000000/HZ))/titan_usec;
-
-		seq_printf(m, "  titan elapsed = %lu uSec\n", titan_usec);
-		seq_printf(m, "  tb elapsed    = %lu ticks\n", tb_ticks);
-		seq_printf(m, "  titan jiffies = %lu.%04lu\n", titan_jiffies,
-			   titan_jiff_rem_usec);
-		seq_printf(m, "  tb jiffies    = %lu.%04lu\n", tb_jiffies,
-			   tb_jiff_rem_usec);
-		seq_printf(m, "  new tb_ticks_per_jiffy = %lu\n",
-			   new_tb_ticks_per_jiffy);
-	}
-
-	return 0;
-}
-
-static int proc_titantod_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, proc_titantod_show, NULL);
-}
-
-static const struct file_operations proc_titantod_operations = {
-	.open		= proc_titantod_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int __init iseries_proc_init(void)
-{
-	if (!firmware_has_feature(FW_FEATURE_ISERIES))
-		return 0;
-
-	proc_create("iSeries/titanTod", S_IFREG|S_IRUGO, NULL,
-		    &proc_titantod_operations);
-	return 0;
-}
-__initcall(iseries_proc_init);
diff --git a/arch/powerpc/platforms/iseries/processor_vpd.h b/arch/powerpc/platforms/iseries/processor_vpd.h
deleted file mode 100644
index 7ac5d0d..0000000
--- a/arch/powerpc/platforms/iseries/processor_vpd.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef _ISERIES_PROCESSOR_VPD_H
-#define _ISERIES_PROCESSOR_VPD_H
-
-#include <asm/types.h>
-
-/*
- * This struct maps Processor Vpd that is DMAd to SLIC by CSP
- */
-struct IoHriProcessorVpd {
-	u8	xFormat;		// VPD format indicator		x00-x00
-	u8	xProcStatus:8;		// Processor State		x01-x01
-	u8	xSecondaryThreadCount;	// Secondary thread cnt		x02-x02
-	u8	xSrcType:1;		// Src Type			x03-x03
-	u8	xSrcSoft:1;		// Src stay soft		...
-	u8	xSrcParable:1;		// Src parable			...
-	u8	xRsvd1:5;		// Reserved			...
-	u16	xHvPhysicalProcIndex;	// Hypervisor physical proc index04-x05
-	u16	xRsvd2;			// Reserved			x06-x07
-	u32	xHwNodeId;		// Hardware node id		x08-x0B
-	u32	xHwProcId;		// Hardware processor id	x0C-x0F
-
-	u32	xTypeNum;		// Card Type/CCIN number	x10-x13
-	u32	xModelNum;		// Model/Feature number		x14-x17
-	u64	xSerialNum;		// Serial number		x18-x1F
-	char	xPartNum[12];		// Book Part or FPU number	x20-x2B
-	char	xMfgID[4];		// Manufacturing ID		x2C-x2F
-
-	u32	xProcFreq;		// Processor Frequency		x30-x33
-	u32	xTimeBaseFreq;		// Time Base Frequency		x34-x37
-
-	u32	xChipEcLevel;		// Chip EC Levels		x38-x3B
-	u32	xProcIdReg;		// PIR SPR value		x3C-x3F
-	u32	xPVR;			// PVR value			x40-x43
-	u8	xRsvd3[12];		// Reserved			x44-x4F
-
-	u32	xInstCacheSize;		// Instruction cache size in KB	x50-x53
-	u32	xInstBlockSize;		// Instruction cache block size	x54-x57
-	u32	xDataCacheOperandSize;	// Data cache operand size	x58-x5B
-	u32	xInstCacheOperandSize;	// Inst cache operand size	x5C-x5F
-
-	u32	xDataL1CacheSizeKB;	// L1 data cache size in KB	x60-x63
-	u32	xDataL1CacheLineSize;	// L1 data cache block size	x64-x67
-	u64	xRsvd4;			// Reserved			x68-x6F
-
-	u32	xDataL2CacheSizeKB;	// L2 data cache size in KB	x70-x73
-	u32	xDataL2CacheLineSize;	// L2 data cache block size	x74-x77
-	u64	xRsvd5;			// Reserved			x78-x7F
-
-	u32	xDataL3CacheSizeKB;	// L3 data cache size in KB	x80-x83
-	u32	xDataL3CacheLineSize;	// L3 data cache block size	x84-x87
-	u64	xRsvd6;			// Reserved			x88-x8F
-
-	u64	xFruLabel;		// Card Location Label		x90-x97
-	u8	xSlotsOnCard;		// Slots on card (0=no slots)	x98-x98
-	u8	xPartLocFlag;		// Location flag (0-pluggable 1-imbedded) x99-x99
-	u16	xSlotMapIndex;		// Index in slot map table	x9A-x9B
-	u8	xSmartCardPortNo;	// Smart card port number	x9C-x9C
-	u8	xRsvd7;			// Reserved			x9D-x9D
-	u16	xFrameIdAndRackUnit;	// Frame ID and rack unit adr	x9E-x9F
-
-	u8	xRsvd8[24];		// Reserved			xA0-xB7
-
-	char	xProcSrc[72];		// CSP format SRC		xB8-xFF
-};
-
-extern struct IoHriProcessorVpd	xIoHriProcessorVpd[];
-
-#endif /* _ISERIES_PROCESSOR_VPD_H */
diff --git a/arch/powerpc/platforms/iseries/release_data.h b/arch/powerpc/platforms/iseries/release_data.h
deleted file mode 100644
index 6ad7d84..0000000
--- a/arch/powerpc/platforms/iseries/release_data.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef _ISERIES_RELEASE_DATA_H
-#define _ISERIES_RELEASE_DATA_H
-
-/*
- * This control block contains the critical information about the
- * release so that it can be changed in the future (ie, the virtual
- * address of the OS's NACA).
- */
-#include <asm/types.h>
-#include "naca.h"
-
-/*
- * When we IPL a secondary partition, we will check if if the
- * secondary xMinPlicVrmIndex > the primary xVrmIndex.
- * If it is then this tells PLIC that this secondary is not
- * supported running on this "old" of a level of PLIC.
- *
- * Likewise, we will compare the primary xMinSlicVrmIndex to
- * the secondary xVrmIndex.
- * If the primary xMinSlicVrmDelta > secondary xVrmDelta then we
- * know that this PLIC does not support running an OS "that old".
- */
-
-#define	HVREL_TAGSINACTIVE	0x8000
-#define HVREL_32BIT		0x4000
-#define HVREL_NOSHAREDPROCS	0x2000
-#define HVREL_NOHMT		0x1000
-
-struct HvReleaseData {
-	u32	xDesc;		/* Descriptor "HvRD" ebcdic	x00-x03 */
-	u16	xSize;		/* Size of this control block	x04-x05 */
-	u16	xVpdAreasPtrOffset; /* Offset in NACA of ItVpdAreas x06-x07 */
-	struct  naca_struct	*xSlicNacaAddr; /* Virt addr of SLIC NACA x08-x0F */
-	u32	xMsNucDataOffset; /* Offset of Linux Mapping Data x10-x13 */
-	u32	xRsvd1;		/* Reserved			x14-x17 */
-	u16	xFlags;
-	u16	xVrmIndex;	/* VRM Index of OS image	x1A-x1B */
-	u16	xMinSupportedPlicVrmIndex; /* Min PLIC level  (soft) x1C-x1D */
-	u16	xMinCompatablePlicVrmIndex; /* Min PLIC levelP (hard) x1E-x1F */
-	char	xVrmName[12];	/* Displayable name		x20-x2B */
-	char	xRsvd3[20];	/* Reserved			x2C-x3F */
-};
-
-extern const struct HvReleaseData	hvReleaseData;
-
-#endif /* _ISERIES_RELEASE_DATA_H */
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
deleted file mode 100644
index a5fbf4c..0000000
--- a/arch/powerpc/platforms/iseries/setup.c
+++ /dev/null
@@ -1,718 +0,0 @@
-/*
- *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      the IBM iSeries LPAR.  Adapted from original code by Grant Erickson and
- *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
- *      <dan@net4x.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.
- */
-
-#undef DEBUG
-
-#include <linux/init.h>
-#include <linux/threads.h>
-#include <linux/smp.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/export.h>
-#include <linux/seq_file.h>
-#include <linux/kdev_t.h>
-#include <linux/kexec.h>
-#include <linux/major.h>
-#include <linux/root_dev.h>
-#include <linux/kernel.h>
-#include <linux/hrtimer.h>
-#include <linux/tick.h>
-
-#include <asm/processor.h>
-#include <asm/machdep.h>
-#include <asm/page.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-#include <asm/mmu_context.h>
-#include <asm/cputable.h>
-#include <asm/sections.h>
-#include <asm/iommu.h>
-#include <asm/firmware.h>
-#include <asm/system.h>
-#include <asm/time.h>
-#include <asm/paca.h>
-#include <asm/cache.h>
-#include <asm/abs_addr.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_call_event.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/iseries/it_lp_queue.h>
-#include <asm/iseries/mf.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/lpar_map.h>
-#include <asm/udbg.h>
-#include <asm/irq.h>
-
-#include "naca.h"
-#include "setup.h"
-#include "irq.h"
-#include "vpd_areas.h"
-#include "processor_vpd.h"
-#include "it_lp_naca.h"
-#include "main_store.h"
-#include "call_sm.h"
-#include "call_hpt.h"
-#include "pci.h"
-
-#ifdef DEBUG
-#define DBG(fmt...) udbg_printf(fmt)
-#else
-#define DBG(fmt...)
-#endif
-
-/* Function Prototypes */
-static unsigned long build_iSeries_Memory_Map(void);
-static void iseries_shared_idle(void);
-static void iseries_dedicated_idle(void);
-
-
-struct MemoryBlock {
-	unsigned long absStart;
-	unsigned long absEnd;
-	unsigned long logicalStart;
-	unsigned long logicalEnd;
-};
-
-/*
- * Process the main store vpd to determine where the holes in memory are
- * and return the number of physical blocks and fill in the array of
- * block data.
- */
-static unsigned long iSeries_process_Condor_mainstore_vpd(
-		struct MemoryBlock *mb_array, unsigned long max_entries)
-{
-	unsigned long holeFirstChunk, holeSizeChunks;
-	unsigned long numMemoryBlocks = 1;
-	struct IoHriMainStoreSegment4 *msVpd =
-		(struct IoHriMainStoreSegment4 *)xMsVpd;
-	unsigned long holeStart = msVpd->nonInterleavedBlocksStartAdr;
-	unsigned long holeEnd = msVpd->nonInterleavedBlocksEndAdr;
-	unsigned long holeSize = holeEnd - holeStart;
-
-	printk("Mainstore_VPD: Condor\n");
-	/*
-	 * Determine if absolute memory has any
-	 * holes so that we can interpret the
-	 * access map we get back from the hypervisor
-	 * correctly.
-	 */
-	mb_array[0].logicalStart = 0;
-	mb_array[0].logicalEnd = 0x100000000UL;
-	mb_array[0].absStart = 0;
-	mb_array[0].absEnd = 0x100000000UL;
-
-	if (holeSize) {
-		numMemoryBlocks = 2;
-		holeStart = holeStart & 0x000fffffffffffffUL;
-		holeStart = addr_to_chunk(holeStart);
-		holeFirstChunk = holeStart;
-		holeSize = addr_to_chunk(holeSize);
-		holeSizeChunks = holeSize;
-		printk( "Main store hole: start chunk = %0lx, size = %0lx chunks\n",
-				holeFirstChunk, holeSizeChunks );
-		mb_array[0].logicalEnd = holeFirstChunk;
-		mb_array[0].absEnd = holeFirstChunk;
-		mb_array[1].logicalStart = holeFirstChunk;
-		mb_array[1].logicalEnd = 0x100000000UL - holeSizeChunks;
-		mb_array[1].absStart = holeFirstChunk + holeSizeChunks;
-		mb_array[1].absEnd = 0x100000000UL;
-	}
-	return numMemoryBlocks;
-}
-
-#define MaxSegmentAreas			32
-#define MaxSegmentAdrRangeBlocks	128
-#define MaxAreaRangeBlocks		4
-
-static unsigned long iSeries_process_Regatta_mainstore_vpd(
-		struct MemoryBlock *mb_array, unsigned long max_entries)
-{
-	struct IoHriMainStoreSegment5 *msVpdP =
-		(struct IoHriMainStoreSegment5 *)xMsVpd;
-	unsigned long numSegmentBlocks = 0;
-	u32 existsBits = msVpdP->msAreaExists;
-	unsigned long area_num;
-
-	printk("Mainstore_VPD: Regatta\n");
-
-	for (area_num = 0; area_num < MaxSegmentAreas; ++area_num ) {
-		unsigned long numAreaBlocks;
-		struct IoHriMainStoreArea4 *currentArea;
-
-		if (existsBits & 0x80000000) {
-			unsigned long block_num;
-
-			currentArea = &msVpdP->msAreaArray[area_num];
-			numAreaBlocks = currentArea->numAdrRangeBlocks;
-			printk("ms_vpd: processing area %2ld  blocks=%ld",
-					area_num, numAreaBlocks);
-			for (block_num = 0; block_num < numAreaBlocks;
-					++block_num ) {
-				/* Process an address range block */
-				struct MemoryBlock tempBlock;
-				unsigned long i;
-
-				tempBlock.absStart =
-					(unsigned long)currentArea->xAdrRangeBlock[block_num].blockStart;
-				tempBlock.absEnd =
-					(unsigned long)currentArea->xAdrRangeBlock[block_num].blockEnd;
-				tempBlock.logicalStart = 0;
-				tempBlock.logicalEnd   = 0;
-				printk("\n          block %ld absStart=%016lx absEnd=%016lx",
-						block_num, tempBlock.absStart,
-						tempBlock.absEnd);
-
-				for (i = 0; i < numSegmentBlocks; ++i) {
-					if (mb_array[i].absStart ==
-							tempBlock.absStart)
-						break;
-				}
-				if (i == numSegmentBlocks) {
-					if (numSegmentBlocks == max_entries)
-						panic("iSeries_process_mainstore_vpd: too many memory blocks");
-					mb_array[numSegmentBlocks] = tempBlock;
-					++numSegmentBlocks;
-				} else
-					printk(" (duplicate)");
-			}
-			printk("\n");
-		}
-		existsBits <<= 1;
-	}
-	/* Now sort the blocks found into ascending sequence */
-	if (numSegmentBlocks > 1) {
-		unsigned long m, n;
-
-		for (m = 0; m < numSegmentBlocks - 1; ++m) {
-			for (n = numSegmentBlocks - 1; m < n; --n) {
-				if (mb_array[n].absStart <
-						mb_array[n-1].absStart) {
-					struct MemoryBlock tempBlock;
-
-					tempBlock = mb_array[n];
-					mb_array[n] = mb_array[n-1];
-					mb_array[n-1] = tempBlock;
-				}
-			}
-		}
-	}
-	/*
-	 * Assign "logical" addresses to each block.  These
-	 * addresses correspond to the hypervisor "bitmap" space.
-	 * Convert all addresses into units of 256K chunks.
-	 */
-	{
-	unsigned long i, nextBitmapAddress;
-
-	printk("ms_vpd: %ld sorted memory blocks\n", numSegmentBlocks);
-	nextBitmapAddress = 0;
-	for (i = 0; i < numSegmentBlocks; ++i) {
-		unsigned long length = mb_array[i].absEnd -
-			mb_array[i].absStart;
-
-		mb_array[i].logicalStart = nextBitmapAddress;
-		mb_array[i].logicalEnd = nextBitmapAddress + length;
-		nextBitmapAddress += length;
-		printk("          Bitmap range: %016lx - %016lx\n"
-				"        Absolute range: %016lx - %016lx\n",
-				mb_array[i].logicalStart,
-				mb_array[i].logicalEnd,
-				mb_array[i].absStart, mb_array[i].absEnd);
-		mb_array[i].absStart = addr_to_chunk(mb_array[i].absStart &
-				0x000fffffffffffffUL);
-		mb_array[i].absEnd = addr_to_chunk(mb_array[i].absEnd &
-				0x000fffffffffffffUL);
-		mb_array[i].logicalStart =
-			addr_to_chunk(mb_array[i].logicalStart);
-		mb_array[i].logicalEnd = addr_to_chunk(mb_array[i].logicalEnd);
-	}
-	}
-
-	return numSegmentBlocks;
-}
-
-static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array,
-		unsigned long max_entries)
-{
-	unsigned long i;
-	unsigned long mem_blocks = 0;
-
-	if (mmu_has_feature(MMU_FTR_SLB))
-		mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array,
-				max_entries);
-	else
-		mem_blocks = iSeries_process_Condor_mainstore_vpd(mb_array,
-				max_entries);
-
-	printk("Mainstore_VPD: numMemoryBlocks = %ld\n", mem_blocks);
-	for (i = 0; i < mem_blocks; ++i) {
-		printk("Mainstore_VPD: block %3ld logical chunks %016lx - %016lx\n"
-		       "                             abs chunks %016lx - %016lx\n",
-			i, mb_array[i].logicalStart, mb_array[i].logicalEnd,
-			mb_array[i].absStart, mb_array[i].absEnd);
-	}
-	return mem_blocks;
-}
-
-static void __init iSeries_get_cmdline(void)
-{
-	char *p, *q;
-
-	/* copy the command line parameter from the primary VSP  */
-	HvCallEvent_dmaToSp(cmd_line, 2 * 64* 1024, 256,
-			HvLpDma_Direction_RemoteToLocal);
-
-	p = cmd_line;
-	q = cmd_line + 255;
-	while(p < q) {
-		if (!*p || *p == '\n')
-			break;
-		++p;
-	}
-	*p = 0;
-}
-
-static void __init iSeries_init_early(void)
-{
-	DBG(" -> iSeries_init_early()\n");
-
-	/* Snapshot the timebase, for use in later recalibration */
-	iSeries_time_init_early();
-
-	/*
-	 * Initialize the DMA/TCE management
-	 */
-	iommu_init_early_iSeries();
-
-	/* Initialize machine-dependency vectors */
-#ifdef CONFIG_SMP
-	smp_init_iSeries();
-#endif
-
-	/* Associate Lp Event Queue 0 with processor 0 */
-	HvCallEvent_setLpEventQueueInterruptProc(0, 0);
-
-	mf_init();
-
-	DBG(" <- iSeries_init_early()\n");
-}
-
-struct mschunks_map mschunks_map = {
-	/* XXX We don't use these, but Piranha might need them. */
-	.chunk_size  = MSCHUNKS_CHUNK_SIZE,
-	.chunk_shift = MSCHUNKS_CHUNK_SHIFT,
-	.chunk_mask  = MSCHUNKS_OFFSET_MASK,
-};
-EXPORT_SYMBOL(mschunks_map);
-
-static void mschunks_alloc(unsigned long num_chunks)
-{
-	klimit = _ALIGN(klimit, sizeof(u32));
-	mschunks_map.mapping = (u32 *)klimit;
-	klimit += num_chunks * sizeof(u32);
-	mschunks_map.num_chunks = num_chunks;
-}
-
-/*
- * The iSeries may have very large memories ( > 128 GB ) and a partition
- * may get memory in "chunks" that may be anywhere in the 2**52 real
- * address space.  The chunks are 256K in size.  To map this to the
- * memory model Linux expects, the AS/400 specific code builds a
- * translation table to translate what Linux thinks are "physical"
- * addresses to the actual real addresses.  This allows us to make
- * it appear to Linux that we have contiguous memory starting at
- * physical address zero while in fact this could be far from the truth.
- * To avoid confusion, I'll let the words physical and/or real address
- * apply to the Linux addresses while I'll use "absolute address" to
- * refer to the actual hardware real address.
- *
- * build_iSeries_Memory_Map gets information from the Hypervisor and
- * looks at the Main Store VPD to determine the absolute addresses
- * of the memory that has been assigned to our partition and builds
- * a table used to translate Linux's physical addresses to these
- * absolute addresses.  Absolute addresses are needed when
- * communicating with the hypervisor (e.g. to build HPT entries)
- *
- * Returns the physical memory size
- */
-
-static unsigned long __init build_iSeries_Memory_Map(void)
-{
-	u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize;
-	u32 nextPhysChunk;
-	u32 hptFirstChunk, hptLastChunk, hptSizeChunks, hptSizePages;
-	u32 totalChunks,moreChunks;
-	u32 currChunk, thisChunk, absChunk;
-	u32 currDword;
-	u32 chunkBit;
-	u64 map;
-	struct MemoryBlock mb[32];
-	unsigned long numMemoryBlocks, curBlock;
-
-	/* Chunk size on iSeries is 256K bytes */
-	totalChunks = (u32)HvLpConfig_getMsChunks();
-	mschunks_alloc(totalChunks);
-
-	/*
-	 * Get absolute address of our load area
-	 * and map it to physical address 0
-	 * This guarantees that the loadarea ends up at physical 0
-	 * otherwise, it might not be returned by PLIC as the first
-	 * chunks
-	 */
-
-	loadAreaFirstChunk = (u32)addr_to_chunk(itLpNaca.xLoadAreaAddr);
-	loadAreaSize =  itLpNaca.xLoadAreaChunks;
-
-	/*
-	 * Only add the pages already mapped here.
-	 * Otherwise we might add the hpt pages
-	 * The rest of the pages of the load area
-	 * aren't in the HPT yet and can still
-	 * be assigned an arbitrary physical address
-	 */
-	if ((loadAreaSize * 64) > HvPagesToMap)
-		loadAreaSize = HvPagesToMap / 64;
-
-	loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1;
-
-	/*
-	 * TODO Do we need to do something if the HPT is in the 64MB load area?
-	 * This would be required if the itLpNaca.xLoadAreaChunks includes
-	 * the HPT size
-	 */
-
-	printk("Mapping load area - physical addr = 0000000000000000\n"
-		"                    absolute addr = %016lx\n",
-		chunk_to_addr(loadAreaFirstChunk));
-	printk("Load area size %dK\n", loadAreaSize * 256);
-
-	for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk)
-		mschunks_map.mapping[nextPhysChunk] =
-			loadAreaFirstChunk + nextPhysChunk;
-
-	/*
-	 * Get absolute address of our HPT and remember it so
-	 * we won't map it to any physical address
-	 */
-	hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress());
-	hptSizePages = (u32)HvCallHpt_getHptPages();
-	hptSizeChunks = hptSizePages >>
-		(MSCHUNKS_CHUNK_SHIFT - HW_PAGE_SHIFT);
-	hptLastChunk = hptFirstChunk + hptSizeChunks - 1;
-
-	printk("HPT absolute addr = %016lx, size = %dK\n",
-			chunk_to_addr(hptFirstChunk), hptSizeChunks * 256);
-
-	/*
-	 * Determine if absolute memory has any
-	 * holes so that we can interpret the
-	 * access map we get back from the hypervisor
-	 * correctly.
-	 */
-	numMemoryBlocks = iSeries_process_mainstore_vpd(mb, 32);
-
-	/*
-	 * Process the main store access map from the hypervisor
-	 * to build up our physical -> absolute translation table
-	 */
-	curBlock = 0;
-	currChunk = 0;
-	currDword = 0;
-	moreChunks = totalChunks;
-
-	while (moreChunks) {
-		map = HvCallSm_get64BitsOfAccessMap(itLpNaca.xLpIndex,
-				currDword);
-		thisChunk = currChunk;
-		while (map) {
-			chunkBit = map >> 63;
-			map <<= 1;
-			if (chunkBit) {
-				--moreChunks;
-				while (thisChunk >= mb[curBlock].logicalEnd) {
-					++curBlock;
-					if (curBlock >= numMemoryBlocks)
-						panic("out of memory blocks");
-				}
-				if (thisChunk < mb[curBlock].logicalStart)
-					panic("memory block error");
-
-				absChunk = mb[curBlock].absStart +
-					(thisChunk - mb[curBlock].logicalStart);
-				if (((absChunk < hptFirstChunk) ||
-				     (absChunk > hptLastChunk)) &&
-				    ((absChunk < loadAreaFirstChunk) ||
-				     (absChunk > loadAreaLastChunk))) {
-					mschunks_map.mapping[nextPhysChunk] =
-						absChunk;
-					++nextPhysChunk;
-				}
-			}
-			++thisChunk;
-		}
-		++currDword;
-		currChunk += 64;
-	}
-
-	/*
-	 * main store size (in chunks) is
-	 *   totalChunks - hptSizeChunks
-	 * which should be equal to
-	 *   nextPhysChunk
-	 */
-	return chunk_to_addr(nextPhysChunk);
-}
-
-/*
- * Document me.
- */
-static void __init iSeries_setup_arch(void)
-{
-	if (get_lppaca()->shared_proc) {
-		ppc_md.idle_loop = iseries_shared_idle;
-		printk(KERN_DEBUG "Using shared processor idle loop\n");
-	} else {
-		ppc_md.idle_loop = iseries_dedicated_idle;
-		printk(KERN_DEBUG "Using dedicated idle loop\n");
-	}
-
-	/* Setup the Lp Event Queue */
-	setup_hvlpevent_queue();
-
-	printk("Max  logical processors = %d\n",
-			itVpdAreas.xSlicMaxLogicalProcs);
-	printk("Max physical processors = %d\n",
-			itVpdAreas.xSlicMaxPhysicalProcs);
-
-	iSeries_pcibios_init();
-}
-
-static void iSeries_show_cpuinfo(struct seq_file *m)
-{
-	seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n");
-}
-
-static void __init iSeries_progress(char * st, unsigned short code)
-{
-	printk("Progress: [%04x] - %s\n", (unsigned)code, st);
-	mf_display_progress(code);
-}
-
-static void __init iSeries_fixup_klimit(void)
-{
-	/*
-	 * Change klimit to take into account any ram disk
-	 * that may be included
-	 */
-	if (naca.xRamDisk)
-		klimit = KERNELBASE + (u64)naca.xRamDisk +
-			(naca.xRamDiskSize * HW_PAGE_SIZE);
-}
-
-static int __init iSeries_src_init(void)
-{
-        /* clear the progress line */
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		ppc_md.progress(" ", 0xffff);
-        return 0;
-}
-
-late_initcall(iSeries_src_init);
-
-static inline void process_iSeries_events(void)
-{
-	asm volatile ("li 0,0x5555; sc" : : : "r0", "r3");
-}
-
-static void yield_shared_processor(void)
-{
-	unsigned long tb;
-
-	HvCall_setEnabledInterrupts(HvCall_MaskIPI |
-				    HvCall_MaskLpEvent |
-				    HvCall_MaskLpProd |
-				    HvCall_MaskTimeout);
-
-	tb = get_tb();
-	/* Compute future tb value when yield should expire */
-	HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy);
-
-	/*
-	 * The decrementer stops during the yield.  Force a fake decrementer
-	 * here and let the timer_interrupt code sort out the actual time.
-	 */
-	get_lppaca()->int_dword.fields.decr_int = 1;
-	ppc64_runlatch_on();
-	process_iSeries_events();
-}
-
-static void iseries_shared_idle(void)
-{
-	while (1) {
-		tick_nohz_idle_enter();
-		rcu_idle_enter();
-		while (!need_resched() && !hvlpevent_is_pending()) {
-			local_irq_disable();
-			ppc64_runlatch_off();
-
-			/* Recheck with irqs off */
-			if (!need_resched() && !hvlpevent_is_pending())
-				yield_shared_processor();
-
-			HMT_medium();
-			local_irq_enable();
-		}
-
-		ppc64_runlatch_on();
-		rcu_idle_exit();
-		tick_nohz_idle_exit();
-
-		if (hvlpevent_is_pending())
-			process_iSeries_events();
-
-		schedule_preempt_disabled();
-	}
-}
-
-static void iseries_dedicated_idle(void)
-{
-	set_thread_flag(TIF_POLLING_NRFLAG);
-
-	while (1) {
-		tick_nohz_idle_enter();
-		rcu_idle_enter();
-		if (!need_resched()) {
-			while (!need_resched()) {
-				ppc64_runlatch_off();
-				HMT_low();
-
-				if (hvlpevent_is_pending()) {
-					HMT_medium();
-					ppc64_runlatch_on();
-					process_iSeries_events();
-				}
-			}
-
-			HMT_medium();
-		}
-
-		ppc64_runlatch_on();
-		rcu_idle_exit();
-		tick_nohz_idle_exit();
-		schedule_preempt_disabled();
-	}
-}
-
-static void __iomem *iseries_ioremap(phys_addr_t address, unsigned long size,
-				     unsigned long flags, void *caller)
-{
-	return (void __iomem *)address;
-}
-
-static void iseries_iounmap(volatile void __iomem *token)
-{
-}
-
-static int __init iseries_probe(void)
-{
-	unsigned long root = of_get_flat_dt_root();
-	if (!of_flat_dt_is_compatible(root, "IBM,iSeries"))
-		return 0;
-
-	hpte_init_iSeries();
-	/* iSeries does not support 16M pages */
-	cur_cpu_spec->mmu_features &= ~MMU_FTR_16M_PAGE;
-
-	return 1;
-}
-
-#ifdef CONFIG_KEXEC
-static int iseries_kexec_prepare(struct kimage *image)
-{
-	return -ENOSYS;
-}
-#endif
-
-define_machine(iseries) {
-	.name			= "iSeries",
-	.setup_arch		= iSeries_setup_arch,
-	.show_cpuinfo		= iSeries_show_cpuinfo,
-	.init_IRQ		= iSeries_init_IRQ,
-	.get_irq		= iSeries_get_irq,
-	.init_early		= iSeries_init_early,
-	.pcibios_fixup		= iSeries_pci_final_fixup,
-	.pcibios_fixup_resources= iSeries_pcibios_fixup_resources,
-	.restart		= mf_reboot,
-	.power_off		= mf_power_off,
-	.halt			= mf_power_off,
-	.get_boot_time		= iSeries_get_boot_time,
-	.set_rtc_time		= iSeries_set_rtc_time,
-	.get_rtc_time		= iSeries_get_rtc_time,
-	.calibrate_decr		= generic_calibrate_decr,
-	.progress		= iSeries_progress,
-	.probe			= iseries_probe,
-	.ioremap		= iseries_ioremap,
-	.iounmap		= iseries_iounmap,
-#ifdef CONFIG_KEXEC
-	.machine_kexec_prepare	= iseries_kexec_prepare,
-#endif
-	/* XXX Implement enable_pmcs for iSeries */
-};
-
-void * __init iSeries_early_setup(void)
-{
-	unsigned long phys_mem_size;
-
-	/* Identify CPU type. This is done again by the common code later
-	 * on but calling this function multiple times is fine.
-	 */
-	identify_cpu(0, mfspr(SPRN_PVR));
-	initialise_paca(&boot_paca, 0);
-
-	powerpc_firmware_features |= FW_FEATURE_ISERIES;
-	powerpc_firmware_features |= FW_FEATURE_LPAR;
-
-#ifdef CONFIG_SMP
-	/* On iSeries we know we can never have more than 64 cpus */
-	nr_cpu_ids = max(nr_cpu_ids, 64);
-#endif
-
-	iSeries_fixup_klimit();
-
-	/*
-	 * Initialize the table which translate Linux physical addresses to
-	 * AS/400 absolute addresses
-	 */
-	phys_mem_size = build_iSeries_Memory_Map();
-
-	iSeries_get_cmdline();
-
-	return (void *) __pa(build_flat_dt(phys_mem_size));
-}
-
-static void hvputc(char c)
-{
-	if (c == '\n')
-		hvputc('\r');
-
-	HvCall_writeLogBuffer(&c, 1);
-}
-
-void __init udbg_init_iseries(void)
-{
-	udbg_putc = hvputc;
-}
diff --git a/arch/powerpc/platforms/iseries/setup.h b/arch/powerpc/platforms/iseries/setup.h
deleted file mode 100644
index 729754b..0000000
--- a/arch/powerpc/platforms/iseries/setup.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      the IBM AS/400 LPAR. Adapted from original code by Grant Erickson and
- *      code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
- *      <dan@netx4.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	__ISERIES_SETUP_H__
-#define	__ISERIES_SETUP_H__
-
-extern void *iSeries_early_setup(void);
-extern unsigned long iSeries_get_boot_time(void);
-extern int iSeries_set_rtc_time(struct rtc_time *tm);
-extern void iSeries_get_rtc_time(struct rtc_time *tm);
-
-extern void *build_flat_dt(unsigned long phys_mem_size);
-
-#endif /* __ISERIES_SETUP_H__ */
diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c
deleted file mode 100644
index 02df49f..0000000
--- a/arch/powerpc/platforms/iseries/smp.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * SMP support for iSeries machines.
- *
- * Dave Engebretsen, Peter Bergner, and
- * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
- *
- * Plus various changes from other IBM teams...
- *
- *      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.
- */
-
-#undef DEBUG
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/cache.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/cpu.h>
-
-#include <asm/ptrace.h>
-#include <linux/atomic.h>
-#include <asm/irq.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/paca.h>
-#include <asm/iseries/hv_call.h>
-#include <asm/time.h>
-#include <asm/machdep.h>
-#include <asm/cputable.h>
-#include <asm/system.h>
-
-static void smp_iSeries_cause_ipi(int cpu, unsigned long data)
-{
-	HvCall_sendIPI(&(paca[cpu]));
-}
-
-static int smp_iSeries_probe(void)
-{
-	return cpumask_weight(cpu_possible_mask);
-}
-
-static int smp_iSeries_kick_cpu(int nr)
-{
-	BUG_ON((nr < 0) || (nr >= NR_CPUS));
-
-	/* Verify that our partition has a processor nr */
-	if (lppaca_of(nr).dyn_proc_status >= 2)
-		return -ENOENT;
-
-	/* The processor is currently spinning, waiting
-	 * for the cpu_start field to become non-zero
-	 * After we set cpu_start, the processor will
-	 * continue on to secondary_start in iSeries_head.S
-	 */
-	paca[nr].cpu_start = 1;
-
-	return 0;
-}
-
-static void __devinit smp_iSeries_setup_cpu(int nr)
-{
-}
-
-static struct smp_ops_t iSeries_smp_ops = {
-	.message_pass = NULL,	/* Use smp_muxed_ipi_message_pass */
-	.cause_ipi    = smp_iSeries_cause_ipi,
-	.probe        = smp_iSeries_probe,
-	.kick_cpu     = smp_iSeries_kick_cpu,
-	.setup_cpu    = smp_iSeries_setup_cpu,
-};
-
-/* This is called very early. */
-void __init smp_init_iSeries(void)
-{
-	smp_ops = &iSeries_smp_ops;
-}
diff --git a/arch/powerpc/platforms/iseries/spcomm_area.h b/arch/powerpc/platforms/iseries/spcomm_area.h
deleted file mode 100644
index 598b7c1..0000000
--- a/arch/powerpc/platforms/iseries/spcomm_area.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-
-#ifndef _ISERIES_SPCOMM_AREA_H
-#define _ISERIES_SPCOMM_AREA_H
-
-
-struct SpCommArea {
-	u32	xDesc;			// Descriptor (only in new formats)	000-003
-	u8	xFormat;		// Format (only in new formats)		004-004
-	u8	xRsvd1[11];		// Reserved				005-00F
-	u64	xRawTbAtIplStart;	// Raw HW TB value when IPL is started	010-017
-	u64	xRawTodAtIplStart;	// Raw HW TOD value when IPL is started	018-01F
-	u64	xBcdTimeAtIplStart;	// BCD time when IPL is started		020-027
-	u64	xBcdTimeAtOsStart;	// BCD time when OS passed control	028-02F
-	u8	xRsvd2[80];		// Reserved				030-07F
-};
-
-#endif /* _ISERIES_SPCOMM_AREA_H */
diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c
deleted file mode 100644
index 04be62d..0000000
--- a/arch/powerpc/platforms/iseries/vio.c
+++ /dev/null
@@ -1,556 +0,0 @@
-/*
- * Legacy iSeries specific vio initialisation
- * that needs to be built in (not a module).
- *
- * © Copyright 2007 IBM Corporation
- *	Author: Stephen Rothwell
- *	Some parts collected from various other files
- *
- * 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/of.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/completion.h>
-#include <linux/proc_fs.h>
-#include <linux/export.h>
-
-#include <asm/firmware.h>
-#include <asm/vio.h>
-#include <asm/iseries/vio.h>
-#include <asm/iseries/iommu.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-
-#define FIRST_VTY	0
-#define NUM_VTYS	1
-#define FIRST_VSCSI	(FIRST_VTY + NUM_VTYS)
-#define NUM_VSCSIS	1
-#define FIRST_VLAN	(FIRST_VSCSI + NUM_VSCSIS)
-#define NUM_VLANS	HVMAXARCHITECTEDVIRTUALLANS
-#define FIRST_VIODASD	(FIRST_VLAN + NUM_VLANS)
-#define NUM_VIODASDS	HVMAXARCHITECTEDVIRTUALDISKS
-#define FIRST_VIOCD	(FIRST_VIODASD + NUM_VIODASDS)
-#define NUM_VIOCDS	HVMAXARCHITECTEDVIRTUALCDROMS
-#define FIRST_VIOTAPE	(FIRST_VIOCD + NUM_VIOCDS)
-#define NUM_VIOTAPES	HVMAXARCHITECTEDVIRTUALTAPES
-
-struct vio_waitevent {
-	struct completion	com;
-	int			rc;
-	u16			sub_result;
-};
-
-struct vio_resource {
-	char	rsrcname[10];
-	char	type[4];
-	char	model[3];
-};
-
-static struct property *new_property(const char *name, int length,
-		const void *value)
-{
-	struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length,
-			GFP_KERNEL);
-
-	if (!np)
-		return NULL;
-	np->name = (char *)(np + 1);
-	np->value = np->name + strlen(name) + 1;
-	strcpy(np->name, name);
-	memcpy(np->value, value, length);
-	np->length = length;
-	return np;
-}
-
-static void free_property(struct property *np)
-{
-	kfree(np);
-}
-
-static struct device_node *new_node(const char *path,
-		struct device_node *parent)
-{
-	struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL);
-
-	if (!np)
-		return NULL;
-	np->full_name = kstrdup(path, GFP_KERNEL);
-	if (!np->full_name) {
-		kfree(np);
-		return NULL;
-	}
-	of_node_set_flag(np, OF_DYNAMIC);
-	kref_init(&np->kref);
-	np->parent = of_node_get(parent);
-	return np;
-}
-
-static void free_node(struct device_node *np)
-{
-	struct property *next;
-	struct property *prop;
-
-	next = np->properties;
-	while (next) {
-		prop = next;
-		next = prop->next;
-		free_property(prop);
-	}
-	of_node_put(np->parent);
-	kfree(np->full_name);
-	kfree(np);
-}
-
-static int add_string_property(struct device_node *np, const char *name,
-		const char *value)
-{
-	struct property *nprop = new_property(name, strlen(value) + 1, value);
-
-	if (!nprop)
-		return 0;
-	prom_add_property(np, nprop);
-	return 1;
-}
-
-static int add_raw_property(struct device_node *np, const char *name,
-		int length, const void *value)
-{
-	struct property *nprop = new_property(name, length, value);
-
-	if (!nprop)
-		return 0;
-	prom_add_property(np, nprop);
-	return 1;
-}
-
-static struct device_node *do_device_node(struct device_node *parent,
-		const char *name, u32 reg, u32 unit, const char *type,
-		const char *compat, struct vio_resource *res)
-{
-	struct device_node *np;
-	char path[32];
-
-	snprintf(path, sizeof(path), "/vdevice/%s@%08x", name, reg);
-	np = new_node(path, parent);
-	if (!np)
-		return NULL;
-	if (!add_string_property(np, "name", name) ||
-		!add_string_property(np, "device_type", type) ||
-		!add_string_property(np, "compatible", compat) ||
-		!add_raw_property(np, "reg", sizeof(reg), &reg) ||
-		!add_raw_property(np, "linux,unit_address",
-			sizeof(unit), &unit)) {
-		goto node_free;
-	}
-	if (res) {
-		if (!add_raw_property(np, "linux,vio_rsrcname",
-				sizeof(res->rsrcname), res->rsrcname) ||
-			!add_raw_property(np, "linux,vio_type",
-				sizeof(res->type), res->type) ||
-			!add_raw_property(np, "linux,vio_model",
-				sizeof(res->model), res->model))
-			goto node_free;
-	}
-	np->name = of_get_property(np, "name", NULL);
-	np->type = of_get_property(np, "device_type", NULL);
-	of_attach_node(np);
-#ifdef CONFIG_PROC_DEVICETREE
-	if (parent->pde) {
-		struct proc_dir_entry *ent;
-
-		ent = proc_mkdir(strrchr(np->full_name, '/') + 1, parent->pde);
-		if (ent)
-			proc_device_tree_add_node(np, ent);
-	}
-#endif
-	return np;
-
- node_free:
-	free_node(np);
-	return NULL;
-}
-
-/*
- * This is here so that we can dynamically add viodasd
- * devices without exposing all the above infrastructure.
- */
-struct vio_dev *vio_create_viodasd(u32 unit)
-{
-	struct device_node *vio_root;
-	struct device_node *np;
-	struct vio_dev *vdev = NULL;
-
-	vio_root = of_find_node_by_path("/vdevice");
-	if (!vio_root)
-		return NULL;
-	np = do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit,
-			"block", "IBM,iSeries-viodasd", NULL);
-	of_node_put(vio_root);
-	if (np) {
-		vdev = vio_register_device_node(np);
-		if (!vdev)
-			free_node(np);
-	}
-	return vdev;
-}
-EXPORT_SYMBOL_GPL(vio_create_viodasd);
-
-static void __init handle_block_event(struct HvLpEvent *event)
-{
-	struct vioblocklpevent *bevent = (struct vioblocklpevent *)event;
-	struct vio_waitevent *pwe;
-
-	if (event == NULL)
-		/* Notification that a partition went away! */
-		return;
-	/* First, we should NEVER get an int here...only acks */
-	if (hvlpevent_is_int(event)) {
-		printk(KERN_WARNING "handle_viod_request: "
-		       "Yikes! got an int in viodasd event handler!\n");
-		if (hvlpevent_need_ack(event)) {
-			event->xRc = HvLpEvent_Rc_InvalidSubtype;
-			HvCallEvent_ackLpEvent(event);
-		}
-		return;
-	}
-
-	switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
-	case vioblockopen:
-		/*
-		 * Handle a response to an open request.  We get all the
-		 * disk information in the response, so update it.  The
-		 * correlation token contains a pointer to a waitevent
-		 * structure that has a completion in it.  update the
-		 * return code in the waitevent structure and post the
-		 * completion to wake up the guy who sent the request
-		 */
-		pwe = (struct vio_waitevent *)event->xCorrelationToken;
-		pwe->rc = event->xRc;
-		pwe->sub_result = bevent->sub_result;
-		complete(&pwe->com);
-		break;
-	case vioblockclose:
-		break;
-	default:
-		printk(KERN_WARNING "handle_viod_request: unexpected subtype!");
-		if (hvlpevent_need_ack(event)) {
-			event->xRc = HvLpEvent_Rc_InvalidSubtype;
-			HvCallEvent_ackLpEvent(event);
-		}
-	}
-}
-
-static void __init probe_disk(struct device_node *vio_root, u32 unit)
-{
-	HvLpEvent_Rc hvrc;
-	struct vio_waitevent we;
-	u16 flags = 0;
-
-retry:
-	init_completion(&we.com);
-
-	/* Send the open event to OS/400 */
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_blockio | vioblockopen,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64)(unsigned long)&we, VIOVERSION << 16,
-			((u64)unit << 48) | ((u64)flags<< 32),
-			0, 0, 0);
-	if (hvrc != 0) {
-		printk(KERN_WARNING "probe_disk: bad rc on HV open %d\n",
-			(int)hvrc);
-		return;
-	}
-
-	wait_for_completion(&we.com);
-
-	if (we.rc != 0) {
-		if (flags != 0)
-			return;
-		/* try again with read only flag set */
-		flags = vioblockflags_ro;
-		goto retry;
-	}
-
-	/* Send the close event to OS/400.  We DON'T expect a response */
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_blockio | vioblockclose,
-			HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			0, VIOVERSION << 16,
-			((u64)unit << 48) | ((u64)flags << 32),
-			0, 0, 0);
-	if (hvrc != 0) {
-		printk(KERN_WARNING "probe_disk: "
-		       "bad rc sending event to OS/400 %d\n", (int)hvrc);
-		return;
-	}
-
-	do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit,
-			"block", "IBM,iSeries-viodasd", NULL);
-}
-
-static void __init get_viodasd_info(struct device_node *vio_root)
-{
-	int rc;
-	u32 unit;
-
-	rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, 2);
-	if (rc) {
-		printk(KERN_WARNING "get_viodasd_info: "
-		       "error opening path to host partition %d\n",
-		       viopath_hostLp);
-		return;
-	}
-
-	/* Initialize our request handler */
-	vio_setHandler(viomajorsubtype_blockio, handle_block_event);
-
-	for (unit = 0; unit < HVMAXARCHITECTEDVIRTUALDISKS; unit++)
-		probe_disk(vio_root, unit);
-
-	vio_clearHandler(viomajorsubtype_blockio);
-	viopath_close(viopath_hostLp, viomajorsubtype_blockio, 2);
-}
-
-static void __init handle_cd_event(struct HvLpEvent *event)
-{
-	struct viocdlpevent *bevent;
-	struct vio_waitevent *pwe;
-
-	if (!event)
-		/* Notification that a partition went away! */
-		return;
-
-	/* First, we should NEVER get an int here...only acks */
-	if (hvlpevent_is_int(event)) {
-		printk(KERN_WARNING "handle_cd_event: got an unexpected int\n");
-		if (hvlpevent_need_ack(event)) {
-			event->xRc = HvLpEvent_Rc_InvalidSubtype;
-			HvCallEvent_ackLpEvent(event);
-		}
-		return;
-	}
-
-	bevent = (struct viocdlpevent *)event;
-
-	switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
-	case viocdgetinfo:
-		pwe = (struct vio_waitevent *)event->xCorrelationToken;
-		pwe->rc = event->xRc;
-		pwe->sub_result = bevent->sub_result;
-		complete(&pwe->com);
-		break;
-
-	default:
-		printk(KERN_WARNING "handle_cd_event: "
-			"message with unexpected subtype %0x04X!\n",
-			event->xSubtype & VIOMINOR_SUBTYPE_MASK);
-		if (hvlpevent_need_ack(event)) {
-			event->xRc = HvLpEvent_Rc_InvalidSubtype;
-			HvCallEvent_ackLpEvent(event);
-		}
-	}
-}
-
-static void __init get_viocd_info(struct device_node *vio_root)
-{
-	HvLpEvent_Rc hvrc;
-	u32 unit;
-	struct vio_waitevent we;
-	struct vio_resource *unitinfo;
-	dma_addr_t unitinfo_dmaaddr;
-	int ret;
-
-	ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, 2);
-	if (ret) {
-		printk(KERN_WARNING
-			"get_viocd_info: error opening path to host partition %d\n",
-			viopath_hostLp);
-		return;
-	}
-
-	/* Initialize our request handler */
-	vio_setHandler(viomajorsubtype_cdio, handle_cd_event);
-
-	unitinfo = iseries_hv_alloc(
-			sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS,
-			&unitinfo_dmaaddr, GFP_ATOMIC);
-	if (!unitinfo) {
-		printk(KERN_WARNING
-			"get_viocd_info: error allocating unitinfo\n");
-		goto clear_handler;
-	}
-
-	memset(unitinfo, 0, sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS);
-
-	init_completion(&we.com);
-
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_cdio | viocdgetinfo,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0,
-			sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, 0);
-	if (hvrc != HvLpEvent_Rc_Good) {
-		printk(KERN_WARNING
-			"get_viocd_info: cdrom error sending event. rc %d\n",
-			(int)hvrc);
-		goto hv_free;
-	}
-
-	wait_for_completion(&we.com);
-
-	if (we.rc) {
-		printk(KERN_WARNING "get_viocd_info: bad rc %d:0x%04X\n",
-			we.rc, we.sub_result);
-		goto hv_free;
-	}
-
-	for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) &&
-			unitinfo[unit].rsrcname[0]; unit++) {
-		if (!do_device_node(vio_root, "viocd", FIRST_VIOCD + unit, unit,
-				"block", "IBM,iSeries-viocd", &unitinfo[unit]))
-			break;
-	}
-
- hv_free:
-	iseries_hv_free(sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS,
-			unitinfo, unitinfo_dmaaddr);
- clear_handler:
-	vio_clearHandler(viomajorsubtype_cdio);
-	viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2);
-}
-
-/* Handle interrupt events for tape */
-static void __init handle_tape_event(struct HvLpEvent *event)
-{
-	struct vio_waitevent *we;
-	struct viotapelpevent *tevent = (struct viotapelpevent *)event;
-
-	if (event == NULL)
-		/* Notification that a partition went away! */
-		return;
-
-	we = (struct vio_waitevent *)event->xCorrelationToken;
-	switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
-	case viotapegetinfo:
-		we->rc = tevent->sub_type_result;
-		complete(&we->com);
-		break;
-	default:
-		printk(KERN_WARNING "handle_tape_event: weird ack\n");
-	}
-}
-
-static void __init get_viotape_info(struct device_node *vio_root)
-{
-	HvLpEvent_Rc hvrc;
-	u32 unit;
-	struct vio_resource *unitinfo;
-	dma_addr_t unitinfo_dmaaddr;
-	size_t len = sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALTAPES;
-	struct vio_waitevent we;
-	int ret;
-
-	init_completion(&we.com);
-
-	ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, 2);
-	if (ret) {
-		printk(KERN_WARNING "get_viotape_info: "
-			"error on viopath_open to hostlp %d\n", ret);
-		return;
-	}
-
-	vio_setHandler(viomajorsubtype_tape, handle_tape_event);
-
-	unitinfo = iseries_hv_alloc(len, &unitinfo_dmaaddr, GFP_ATOMIC);
-	if (!unitinfo)
-		goto clear_handler;
-
-	memset(unitinfo, 0, len);
-
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_tape | viotapegetinfo,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64)(unsigned long)&we, VIOVERSION << 16,
-			unitinfo_dmaaddr, len, 0, 0);
-	if (hvrc != HvLpEvent_Rc_Good) {
-		printk(KERN_WARNING "get_viotape_info: hv error on op %d\n",
-				(int)hvrc);
-		goto hv_free;
-	}
-
-	wait_for_completion(&we.com);
-
-	for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) &&
-			unitinfo[unit].rsrcname[0]; unit++) {
-		if (!do_device_node(vio_root, "viotape", FIRST_VIOTAPE + unit,
-				unit, "byte", "IBM,iSeries-viotape",
-				&unitinfo[unit]))
-			break;
-	}
-
- hv_free:
-	iseries_hv_free(len, unitinfo, unitinfo_dmaaddr);
- clear_handler:
-	vio_clearHandler(viomajorsubtype_tape);
-	viopath_close(viopath_hostLp, viomajorsubtype_tape, 2);
-}
-
-static int __init iseries_vio_init(void)
-{
-	struct device_node *vio_root;
-	int ret = -ENODEV;
-
-	if (!firmware_has_feature(FW_FEATURE_ISERIES))
-		goto out;
-
-	iommu_vio_init();
-
-	vio_root = of_find_node_by_path("/vdevice");
-	if (!vio_root)
-		goto out;
-
-	if (viopath_hostLp == HvLpIndexInvalid) {
-		vio_set_hostlp();
-		/* If we don't have a host, bail out */
-		if (viopath_hostLp == HvLpIndexInvalid)
-			goto put_node;
-	}
-
-	get_viodasd_info(vio_root);
-	get_viocd_info(vio_root);
-	get_viotape_info(vio_root);
-
-	ret = 0;
-
- put_node:
-	of_node_put(vio_root);
- out:
-	return ret;
-}
-arch_initcall(iseries_vio_init);
diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c
deleted file mode 100644
index 40dad08..0000000
--- a/arch/powerpc/platforms/iseries/viopath.c
+++ /dev/null
@@ -1,677 +0,0 @@
-/* -*- linux-c -*-
- *
- *  iSeries Virtual I/O Message Path code
- *
- *  Authors: Dave Boutcher <boutcher@us.ibm.com>
- *           Ryan Arnold <ryanarn@us.ibm.com>
- *           Colin Devilbiss <devilbis@us.ibm.com>
- *
- * (C) Copyright 2000-2005 IBM Corporation
- *
- * This code is used by the iSeries virtual disk, cd,
- * tape, and console to communicate with OS/400 in another
- * partition.
- *
- * 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) anyu 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/export.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/vmalloc.h>
-#include <linux/string.h>
-#include <linux/proc_fs.h>
-#include <linux/dma-mapping.h>
-#include <linux/wait.h>
-#include <linux/seq_file.h>
-#include <linux/interrupt.h>
-#include <linux/completion.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/prom.h>
-#include <asm/firmware.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/mf.h>
-#include <asm/iseries/vio.h>
-
-/* Status of the path to each other partition in the system.
- * This is overkill, since we will only ever establish connections
- * to our hosting partition and the primary partition on the system.
- * But this allows for other support in the future.
- */
-static struct viopathStatus {
-	int isOpen;		/* Did we open the path?            */
-	int isActive;		/* Do we have a mon msg outstanding */
-	int users[VIO_MAX_SUBTYPES];
-	HvLpInstanceId mSourceInst;
-	HvLpInstanceId mTargetInst;
-	int numberAllocated;
-} viopathStatus[HVMAXARCHITECTEDLPS];
-
-static DEFINE_SPINLOCK(statuslock);
-
-/*
- * For each kind of event we allocate a buffer that is
- * guaranteed not to cross a page boundary
- */
-static unsigned char event_buffer[VIO_MAX_SUBTYPES * 256]
-	__attribute__((__aligned__(4096)));
-static atomic_t event_buffer_available[VIO_MAX_SUBTYPES];
-static int event_buffer_initialised;
-
-static void handleMonitorEvent(struct HvLpEvent *event);
-
-/*
- * We use this structure to handle asynchronous responses.  The caller
- * blocks on the semaphore and the handler posts the semaphore.  However,
- * if system_state is not SYSTEM_RUNNING, then wait_atomic is used ...
- */
-struct alloc_parms {
-	struct completion done;
-	int number;
-	atomic_t wait_atomic;
-	int used_wait_atomic;
-};
-
-/* Put a sequence number in each mon msg.  The value is not
- * important.  Start at something other than 0 just for
- * readability.  wrapping this is ok.
- */
-static u8 viomonseq = 22;
-
-/* Our hosting logical partition.  We get this at startup
- * time, and different modules access this variable directly.
- */
-HvLpIndex viopath_hostLp = HvLpIndexInvalid;
-EXPORT_SYMBOL(viopath_hostLp);
-HvLpIndex viopath_ourLp = HvLpIndexInvalid;
-EXPORT_SYMBOL(viopath_ourLp);
-
-/* For each kind of incoming event we set a pointer to a
- * routine to call.
- */
-static vio_event_handler_t *vio_handler[VIO_MAX_SUBTYPES];
-
-#define VIOPATH_KERN_WARN	KERN_WARNING "viopath: "
-#define VIOPATH_KERN_INFO	KERN_INFO "viopath: "
-
-static int proc_viopath_show(struct seq_file *m, void *v)
-{
-	char *buf;
-	u16 vlanMap;
-	dma_addr_t handle;
-	HvLpEvent_Rc hvrc;
-	DECLARE_COMPLETION_ONSTACK(done);
-	struct device_node *node;
-	const char *sysid;
-
-	buf = kzalloc(HW_PAGE_SIZE, GFP_KERNEL);
-	if (!buf)
-		return 0;
-
-	handle = iseries_hv_map(buf, HW_PAGE_SIZE, DMA_FROM_DEVICE);
-
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_config | vioconfigget,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64)(unsigned long)&done, VIOVERSION << 16,
-			((u64)handle) << 32, HW_PAGE_SIZE, 0, 0);
-
-	if (hvrc != HvLpEvent_Rc_Good)
-		printk(VIOPATH_KERN_WARN "hv error on op %d\n", (int)hvrc);
-
-	wait_for_completion(&done);
-
-	vlanMap = HvLpConfig_getVirtualLanIndexMap();
-
-	buf[HW_PAGE_SIZE-1] = '\0';
-	seq_printf(m, "%s", buf);
-
-	iseries_hv_unmap(handle, HW_PAGE_SIZE, DMA_FROM_DEVICE);
-	kfree(buf);
-
-	seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap);
-
-	node = of_find_node_by_path("/");
-	sysid = NULL;
-	if (node != NULL)
-		sysid = of_get_property(node, "system-id", NULL);
-
-	if (sysid == NULL)
-		seq_printf(m, "SRLNBR=<UNKNOWN>\n");
-	else
-		/* Skip "IBM," on front of serial number, see dt.c */
-		seq_printf(m, "SRLNBR=%s\n", sysid + 4);
-
-	of_node_put(node);
-
-	return 0;
-}
-
-static int proc_viopath_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, proc_viopath_show, NULL);
-}
-
-static const struct file_operations proc_viopath_operations = {
-	.open		= proc_viopath_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int __init vio_proc_init(void)
-{
-	if (!firmware_has_feature(FW_FEATURE_ISERIES))
-		return 0;
-
-	proc_create("iSeries/config", 0, NULL, &proc_viopath_operations);
-        return 0;
-}
-__initcall(vio_proc_init);
-
-/* See if a given LP is active.  Allow for invalid lps to be passed in
- * and just return invalid
- */
-int viopath_isactive(HvLpIndex lp)
-{
-	if (lp == HvLpIndexInvalid)
-		return 0;
-	if (lp < HVMAXARCHITECTEDLPS)
-		return viopathStatus[lp].isActive;
-	else
-		return 0;
-}
-EXPORT_SYMBOL(viopath_isactive);
-
-/*
- * We cache the source and target instance ids for each
- * partition.
- */
-HvLpInstanceId viopath_sourceinst(HvLpIndex lp)
-{
-	return viopathStatus[lp].mSourceInst;
-}
-EXPORT_SYMBOL(viopath_sourceinst);
-
-HvLpInstanceId viopath_targetinst(HvLpIndex lp)
-{
-	return viopathStatus[lp].mTargetInst;
-}
-EXPORT_SYMBOL(viopath_targetinst);
-
-/*
- * Send a monitor message.  This is a message with the acknowledge
- * bit on that the other side will NOT explicitly acknowledge.  When
- * the other side goes down, the hypervisor will acknowledge any
- * outstanding messages....so we will know when the other side dies.
- */
-static void sendMonMsg(HvLpIndex remoteLp)
-{
-	HvLpEvent_Rc hvrc;
-
-	viopathStatus[remoteLp].mSourceInst =
-		HvCallEvent_getSourceLpInstanceId(remoteLp,
-				HvLpEvent_Type_VirtualIo);
-	viopathStatus[remoteLp].mTargetInst =
-		HvCallEvent_getTargetLpInstanceId(remoteLp,
-				HvLpEvent_Type_VirtualIo);
-
-	/*
-	 * Deliberately ignore the return code here.  if we call this
-	 * more than once, we don't care.
-	 */
-	vio_setHandler(viomajorsubtype_monitor, handleMonitorEvent);
-
-	hvrc = HvCallEvent_signalLpEventFast(remoteLp, HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_monitor, HvLpEvent_AckInd_DoAck,
-			HvLpEvent_AckType_DeferredAck,
-			viopathStatus[remoteLp].mSourceInst,
-			viopathStatus[remoteLp].mTargetInst,
-			viomonseq++, 0, 0, 0, 0, 0);
-
-	if (hvrc == HvLpEvent_Rc_Good)
-		viopathStatus[remoteLp].isActive = 1;
-	else {
-		printk(VIOPATH_KERN_WARN "could not connect to partition %d\n",
-				remoteLp);
-		viopathStatus[remoteLp].isActive = 0;
-	}
-}
-
-static void handleMonitorEvent(struct HvLpEvent *event)
-{
-	HvLpIndex remoteLp;
-	int i;
-
-	/*
-	 * This handler is _also_ called as part of the loop
-	 * at the end of this routine, so it must be able to
-	 * ignore NULL events...
-	 */
-	if (!event)
-		return;
-
-	/*
-	 * First see if this is just a normal monitor message from the
-	 * other partition
-	 */
-	if (hvlpevent_is_int(event)) {
-		remoteLp = event->xSourceLp;
-		if (!viopathStatus[remoteLp].isActive)
-			sendMonMsg(remoteLp);
-		return;
-	}
-
-	/*
-	 * This path is for an acknowledgement; the other partition
-	 * died
-	 */
-	remoteLp = event->xTargetLp;
-	if ((event->xSourceInstanceId != viopathStatus[remoteLp].mSourceInst) ||
-	    (event->xTargetInstanceId != viopathStatus[remoteLp].mTargetInst)) {
-		printk(VIOPATH_KERN_WARN "ignoring ack....mismatched instances\n");
-		return;
-	}
-
-	printk(VIOPATH_KERN_WARN "partition %d ended\n", remoteLp);
-
-	viopathStatus[remoteLp].isActive = 0;
-
-	/*
-	 * For each active handler, pass them a NULL
-	 * message to indicate that the other partition
-	 * died
-	 */
-	for (i = 0; i < VIO_MAX_SUBTYPES; i++) {
-		if (vio_handler[i] != NULL)
-			(*vio_handler[i])(NULL);
-	}
-}
-
-int vio_setHandler(int subtype, vio_event_handler_t *beh)
-{
-	subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
-	if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
-		return -EINVAL;
-	if (vio_handler[subtype] != NULL)
-		return -EBUSY;
-	vio_handler[subtype] = beh;
-	return 0;
-}
-EXPORT_SYMBOL(vio_setHandler);
-
-int vio_clearHandler(int subtype)
-{
-	subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
-	if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
-		return -EINVAL;
-	if (vio_handler[subtype] == NULL)
-		return -EAGAIN;
-	vio_handler[subtype] = NULL;
-	return 0;
-}
-EXPORT_SYMBOL(vio_clearHandler);
-
-static void handleConfig(struct HvLpEvent *event)
-{
-	if (!event)
-		return;
-	if (hvlpevent_is_int(event)) {
-		printk(VIOPATH_KERN_WARN
-		       "unexpected config request from partition %d",
-		       event->xSourceLp);
-
-		if (hvlpevent_need_ack(event)) {
-			event->xRc = HvLpEvent_Rc_InvalidSubtype;
-			HvCallEvent_ackLpEvent(event);
-		}
-		return;
-	}
-
-	complete((struct completion *)event->xCorrelationToken);
-}
-
-/*
- * Initialization of the hosting partition
- */
-void vio_set_hostlp(void)
-{
-	/*
-	 * If this has already been set then we DON'T want to either change
-	 * it or re-register the proc file system
-	 */
-	if (viopath_hostLp != HvLpIndexInvalid)
-		return;
-
-	/*
-	 * Figure out our hosting partition.  This isn't allowed to change
-	 * while we're active
-	 */
-	viopath_ourLp = HvLpConfig_getLpIndex();
-	viopath_hostLp = HvLpConfig_getHostingLpIndex(viopath_ourLp);
-
-	if (viopath_hostLp != HvLpIndexInvalid)
-		vio_setHandler(viomajorsubtype_config, handleConfig);
-}
-EXPORT_SYMBOL(vio_set_hostlp);
-
-static void vio_handleEvent(struct HvLpEvent *event)
-{
-	HvLpIndex remoteLp;
-	int subtype = (event->xSubtype & VIOMAJOR_SUBTYPE_MASK)
-		>> VIOMAJOR_SUBTYPE_SHIFT;
-
-	if (hvlpevent_is_int(event)) {
-		remoteLp = event->xSourceLp;
-		/*
-		 * The isActive is checked because if the hosting partition
-		 * went down and came back up it would not be active but it
-		 * would have different source and target instances, in which
-		 * case we'd want to reset them.  This case really protects
-		 * against an unauthorized active partition sending interrupts
-		 * or acks to this linux partition.
-		 */
-		if (viopathStatus[remoteLp].isActive
-		    && (event->xSourceInstanceId !=
-			viopathStatus[remoteLp].mTargetInst)) {
-			printk(VIOPATH_KERN_WARN
-			       "message from invalid partition. "
-			       "int msg rcvd, source inst (%d) doesn't match (%d)\n",
-			       viopathStatus[remoteLp].mTargetInst,
-			       event->xSourceInstanceId);
-			return;
-		}
-
-		if (viopathStatus[remoteLp].isActive
-		    && (event->xTargetInstanceId !=
-			viopathStatus[remoteLp].mSourceInst)) {
-			printk(VIOPATH_KERN_WARN
-			       "message from invalid partition. "
-			       "int msg rcvd, target inst (%d) doesn't match (%d)\n",
-			       viopathStatus[remoteLp].mSourceInst,
-			       event->xTargetInstanceId);
-			return;
-		}
-	} else {
-		remoteLp = event->xTargetLp;
-		if (event->xSourceInstanceId !=
-		    viopathStatus[remoteLp].mSourceInst) {
-			printk(VIOPATH_KERN_WARN
-			       "message from invalid partition. "
-			       "ack msg rcvd, source inst (%d) doesn't match (%d)\n",
-			       viopathStatus[remoteLp].mSourceInst,
-			       event->xSourceInstanceId);
-			return;
-		}
-
-		if (event->xTargetInstanceId !=
-		    viopathStatus[remoteLp].mTargetInst) {
-			printk(VIOPATH_KERN_WARN
-			       "message from invalid partition. "
-			       "viopath: ack msg rcvd, target inst (%d) doesn't match (%d)\n",
-			       viopathStatus[remoteLp].mTargetInst,
-			       event->xTargetInstanceId);
-			return;
-		}
-	}
-
-	if (vio_handler[subtype] == NULL) {
-		printk(VIOPATH_KERN_WARN
-		       "unexpected virtual io event subtype %d from partition %d\n",
-		       event->xSubtype, remoteLp);
-		/* No handler.  Ack if necessary */
-		if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {
-			event->xRc = HvLpEvent_Rc_InvalidSubtype;
-			HvCallEvent_ackLpEvent(event);
-		}
-		return;
-	}
-
-	/* This innocuous little line is where all the real work happens */
-	(*vio_handler[subtype])(event);
-}
-
-static void viopath_donealloc(void *parm, int number)
-{
-	struct alloc_parms *parmsp = parm;
-
-	parmsp->number = number;
-	if (parmsp->used_wait_atomic)
-		atomic_set(&parmsp->wait_atomic, 0);
-	else
-		complete(&parmsp->done);
-}
-
-static int allocateEvents(HvLpIndex remoteLp, int numEvents)
-{
-	struct alloc_parms parms;
-
-	if (system_state != SYSTEM_RUNNING) {
-		parms.used_wait_atomic = 1;
-		atomic_set(&parms.wait_atomic, 1);
-	} else {
-		parms.used_wait_atomic = 0;
-		init_completion(&parms.done);
-	}
-	mf_allocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, 250,	/* It would be nice to put a real number here! */
-			    numEvents, &viopath_donealloc, &parms);
-	if (system_state != SYSTEM_RUNNING) {
-		while (atomic_read(&parms.wait_atomic))
-			mb();
-	} else
-		wait_for_completion(&parms.done);
-	return parms.number;
-}
-
-int viopath_open(HvLpIndex remoteLp, int subtype, int numReq)
-{
-	int i;
-	unsigned long flags;
-	int tempNumAllocated;
-
-	if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid))
-		return -EINVAL;
-
-	subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
-	if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
-		return -EINVAL;
-
-	spin_lock_irqsave(&statuslock, flags);
-
-	if (!event_buffer_initialised) {
-		for (i = 0; i < VIO_MAX_SUBTYPES; i++)
-			atomic_set(&event_buffer_available[i], 1);
-		event_buffer_initialised = 1;
-	}
-
-	viopathStatus[remoteLp].users[subtype]++;
-
-	if (!viopathStatus[remoteLp].isOpen) {
-		viopathStatus[remoteLp].isOpen = 1;
-		HvCallEvent_openLpEventPath(remoteLp, HvLpEvent_Type_VirtualIo);
-
-		/*
-		 * Don't hold the spinlock during an operation that
-		 * can sleep.
-		 */
-		spin_unlock_irqrestore(&statuslock, flags);
-		tempNumAllocated = allocateEvents(remoteLp, 1);
-		spin_lock_irqsave(&statuslock, flags);
-
-		viopathStatus[remoteLp].numberAllocated += tempNumAllocated;
-
-		if (viopathStatus[remoteLp].numberAllocated == 0) {
-			HvCallEvent_closeLpEventPath(remoteLp,
-					HvLpEvent_Type_VirtualIo);
-
-			spin_unlock_irqrestore(&statuslock, flags);
-			return -ENOMEM;
-		}
-
-		viopathStatus[remoteLp].mSourceInst =
-			HvCallEvent_getSourceLpInstanceId(remoteLp,
-					HvLpEvent_Type_VirtualIo);
-		viopathStatus[remoteLp].mTargetInst =
-			HvCallEvent_getTargetLpInstanceId(remoteLp,
-					HvLpEvent_Type_VirtualIo);
-		HvLpEvent_registerHandler(HvLpEvent_Type_VirtualIo,
-					  &vio_handleEvent);
-		sendMonMsg(remoteLp);
-		printk(VIOPATH_KERN_INFO "opening connection to partition %d, "
-				"setting sinst %d, tinst %d\n",
-				remoteLp, viopathStatus[remoteLp].mSourceInst,
-				viopathStatus[remoteLp].mTargetInst);
-	}
-
-	spin_unlock_irqrestore(&statuslock, flags);
-	tempNumAllocated = allocateEvents(remoteLp, numReq);
-	spin_lock_irqsave(&statuslock, flags);
-	viopathStatus[remoteLp].numberAllocated += tempNumAllocated;
-	spin_unlock_irqrestore(&statuslock, flags);
-
-	return 0;
-}
-EXPORT_SYMBOL(viopath_open);
-
-int viopath_close(HvLpIndex remoteLp, int subtype, int numReq)
-{
-	unsigned long flags;
-	int i;
-	int numOpen;
-	struct alloc_parms parms;
-
-	if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid))
-		return -EINVAL;
-
-	subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
-	if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
-		return -EINVAL;
-
-	spin_lock_irqsave(&statuslock, flags);
-	/*
-	 * If the viopath_close somehow gets called before a
-	 * viopath_open it could decrement to -1 which is a non
-	 * recoverable state so we'll prevent this from
-	 * happening.
-	 */
-	if (viopathStatus[remoteLp].users[subtype] > 0)
-		viopathStatus[remoteLp].users[subtype]--;
-
-	spin_unlock_irqrestore(&statuslock, flags);
-
-	parms.used_wait_atomic = 0;
-	init_completion(&parms.done);
-	mf_deallocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo,
-			      numReq, &viopath_donealloc, &parms);
-	wait_for_completion(&parms.done);
-
-	spin_lock_irqsave(&statuslock, flags);
-	for (i = 0, numOpen = 0; i < VIO_MAX_SUBTYPES; i++)
-		numOpen += viopathStatus[remoteLp].users[i];
-
-	if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) {
-		printk(VIOPATH_KERN_INFO "closing connection to partition %d\n",
-				remoteLp);
-
-		HvCallEvent_closeLpEventPath(remoteLp,
-					     HvLpEvent_Type_VirtualIo);
-		viopathStatus[remoteLp].isOpen = 0;
-		viopathStatus[remoteLp].isActive = 0;
-
-		for (i = 0; i < VIO_MAX_SUBTYPES; i++)
-			atomic_set(&event_buffer_available[i], 0);
-		event_buffer_initialised = 0;
-	}
-	spin_unlock_irqrestore(&statuslock, flags);
-	return 0;
-}
-EXPORT_SYMBOL(viopath_close);
-
-void *vio_get_event_buffer(int subtype)
-{
-	subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
-	if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
-		return NULL;
-
-	if (atomic_dec_if_positive(&event_buffer_available[subtype]) == 0)
-		return &event_buffer[subtype * 256];
-	else
-		return NULL;
-}
-EXPORT_SYMBOL(vio_get_event_buffer);
-
-void vio_free_event_buffer(int subtype, void *buffer)
-{
-	subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
-	if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) {
-		printk(VIOPATH_KERN_WARN
-		       "unexpected subtype %d freeing event buffer\n", subtype);
-		return;
-	}
-
-	if (atomic_read(&event_buffer_available[subtype]) != 0) {
-		printk(VIOPATH_KERN_WARN
-		       "freeing unallocated event buffer, subtype %d\n",
-		       subtype);
-		return;
-	}
-
-	if (buffer != &event_buffer[subtype * 256]) {
-		printk(VIOPATH_KERN_WARN
-		       "freeing invalid event buffer, subtype %d\n", subtype);
-	}
-
-	atomic_set(&event_buffer_available[subtype], 1);
-}
-EXPORT_SYMBOL(vio_free_event_buffer);
-
-static const struct vio_error_entry vio_no_error =
-    { 0, 0, "Non-VIO Error" };
-static const struct vio_error_entry vio_unknown_error =
-    { 0, EIO, "Unknown Error" };
-
-static const struct vio_error_entry vio_default_errors[] = {
-	{0x0001, EIO, "No Connection"},
-	{0x0002, EIO, "No Receiver"},
-	{0x0003, EIO, "No Buffer Available"},
-	{0x0004, EBADRQC, "Invalid Message Type"},
-	{0x0000, 0, NULL},
-};
-
-const struct vio_error_entry *vio_lookup_rc(
-		const struct vio_error_entry *local_table, u16 rc)
-{
-	const struct vio_error_entry *cur;
-
-	if (!rc)
-		return &vio_no_error;
-	if (local_table)
-		for (cur = local_table; cur->rc; ++cur)
-			if (cur->rc == rc)
-				return cur;
-	for (cur = vio_default_errors; cur->rc; ++cur)
-		if (cur->rc == rc)
-			return cur;
-	return &vio_unknown_error;
-}
-EXPORT_SYMBOL(vio_lookup_rc);
diff --git a/arch/powerpc/platforms/iseries/vpd_areas.h b/arch/powerpc/platforms/iseries/vpd_areas.h
deleted file mode 100644
index feb001f..0000000
--- a/arch/powerpc/platforms/iseries/vpd_areas.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- */
-#ifndef _ISERIES_VPD_AREAS_H
-#define _ISERIES_VPD_AREAS_H
-
-/*
- * This file defines the address and length of all of the VPD area passed to
- * the OS from PLIC (most of which start from the SP).
- */
-
-#include <asm/types.h>
-
-/* VPD Entry index is carved in stone - cannot be changed (easily). */
-#define ItVpdCecVpd				0
-#define ItVpdDynamicSpace			1
-#define ItVpdExtVpd				2
-#define ItVpdExtVpdOnPanel			3
-#define ItVpdFirstPaca				4
-#define ItVpdIoVpd				5
-#define ItVpdIplParms				6
-#define ItVpdMsVpd				7
-#define ItVpdPanelVpd				8
-#define ItVpdLpNaca				9
-#define ItVpdBackplaneAndMaybeClockCardVpd	10
-#define ItVpdRecoveryLogBuffer			11
-#define ItVpdSpCommArea				12
-#define ItVpdSpLogBuffer			13
-#define ItVpdSpLogBufferSave			14
-#define ItVpdSpCardVpd				15
-#define ItVpdFirstProcVpd			16
-#define ItVpdApModelVpd				17
-#define ItVpdClockCardVpd			18
-#define ItVpdBusExtCardVpd			19
-#define ItVpdProcCapacityVpd			20
-#define ItVpdInteractiveCapacityVpd		21
-#define ItVpdFirstSlotLabel			22
-#define ItVpdFirstLpQueue			23
-#define ItVpdFirstL3CacheVpd			24
-#define ItVpdFirstProcFruVpd			25
-
-#define ItVpdMaxEntries				26
-
-#define ItDmaMaxEntries				10
-
-#define ItVpdAreasMaxSlotLabels			192
-
-
-struct ItVpdAreas {
-	u32	xSlicDesc;		// Descriptor			000-003
-	u16	xSlicSize;		// Size of this control block	004-005
-	u16	xPlicAdjustVpdLens:1;	// Flag to indicate new interface006-007
-	u16	xRsvd1:15;		// Reserved bits		...
-	u16	xSlicVpdEntries;	// Number of VPD entries	008-009
-	u16	xSlicDmaEntries;	// Number of DMA entries	00A-00B
-	u16	xSlicMaxLogicalProcs;	// Maximum logical processors	00C-00D
-	u16	xSlicMaxPhysicalProcs;	// Maximum physical processors	00E-00F
-	u16	xSlicDmaToksOffset;	// Offset into this of array	010-011
-	u16	xSlicVpdAdrsOffset;	// Offset into this of array	012-013
-	u16	xSlicDmaLensOffset;	// Offset into this of array	014-015
-	u16	xSlicVpdLensOffset;	// Offset into this of array	016-017
-	u16	xSlicMaxSlotLabels;	// Maximum number of slot labels018-019
-	u16	xSlicMaxLpQueues;	// Maximum number of LP Queues	01A-01B
-	u8	xRsvd2[4];		// Reserved			01C-01F
-	u64	xRsvd3[12];		// Reserved			020-07F
-	u32	xPlicDmaLens[ItDmaMaxEntries];// Array of DMA lengths	080-0A7
-	u32	xPlicDmaToks[ItDmaMaxEntries];// Array of DMA tokens	0A8-0CF
-	u32	xSlicVpdLens[ItVpdMaxEntries];// Array of VPD lengths	0D0-12F
-	const void *xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF
-};
-
-extern const struct ItVpdAreas	itVpdAreas;
-
-#endif /* _ISERIES_VPD_AREAS_H */
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
index 401e3f3..465ee8f 100644
--- a/arch/powerpc/platforms/maple/pci.c
+++ b/arch/powerpc/platforms/maple/pci.c
@@ -620,7 +620,7 @@
 	}
 
 	/* Tell pci.c to not change any resource allocations.  */
-	pci_probe_only = 1;
+	pci_add_flags(PCI_PROBE_ONLY);
 }
 
 int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel)
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index 0bcbfe7..cb1b0b3 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -47,7 +47,6 @@
 #include <asm/processor.h>
 #include <asm/sections.h>
 #include <asm/prom.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
 #include <asm/pci-bridge.h>
@@ -262,7 +261,7 @@
 		flags |= MPIC_BIG_ENDIAN;
 
 	/* XXX Maple specific bits */
-	flags |= MPIC_U3_HT_IRQS | MPIC_WANTS_RESET;
+	flags |= MPIC_U3_HT_IRQS;
 	/* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */
 	flags |= MPIC_BIG_ENDIAN;
 
diff --git a/arch/powerpc/platforms/maple/time.c b/arch/powerpc/platforms/maple/time.c
index eac569d..b4a369d 100644
--- a/arch/powerpc/platforms/maple/time.c
+++ b/arch/powerpc/platforms/maple/time.c
@@ -27,7 +27,6 @@
 
 #include <asm/sections.h>
 #include <asm/prom.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/machdep.h>
diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c
index b6a0ec4..aa86271 100644
--- a/arch/powerpc/platforms/pasemi/pci.c
+++ b/arch/powerpc/platforms/pasemi/pci.c
@@ -229,9 +229,6 @@
 
 	/* Setup the linkage between OF nodes and PHBs */
 	pci_devs_phb_init();
-
-	/* Use the common resource allocation mechanism */
-	pci_probe_only = 1;
 }
 
 void __iomem *pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset)
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index 98b7a7c..2ed9212 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -32,13 +32,13 @@
 #include <linux/gfp.h>
 
 #include <asm/prom.h>
-#include <asm/system.h>
 #include <asm/iommu.h>
 #include <asm/machdep.h>
 #include <asm/mpic.h>
 #include <asm/smp.h>
 #include <asm/time.h>
 #include <asm/mmu.h>
+#include <asm/debug.h>
 
 #include <pcmcia/ss.h>
 #include <pcmcia/cistpl.h>
@@ -224,7 +224,7 @@
 	openpic_addr = of_read_number(opprop, naddr);
 	printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
 
-	mpic_flags = MPIC_LARGE_VECTORS | MPIC_NO_BIAS;
+	mpic_flags = MPIC_LARGE_VECTORS | MPIC_NO_BIAS | MPIC_NO_RESET;
 
 	nmiprop = of_get_property(mpic_node, "nmi-source", NULL);
 	if (nmiprop)
diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c
index 84d7fd9..3e91ef5 100644
--- a/arch/powerpc/platforms/powermac/bootx_init.c
+++ b/arch/powerpc/platforms/powermac/bootx_init.c
@@ -19,6 +19,7 @@
 #include <asm/bootx.h>
 #include <asm/btext.h>
 #include <asm/io.h>
+#include <asm/setup.h>
 
 #undef DEBUG
 #define SET_BOOT_BAT
diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
index 1fc386a..6417119 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_32.c
@@ -33,9 +33,9 @@
 #include <asm/sections.h>
 #include <asm/cputable.h>
 #include <asm/time.h>
-#include <asm/system.h>
 #include <asm/mpic.h>
 #include <asm/keylargo.h>
+#include <asm/switch_to.h>
 
 /* WARNING !!! This will cause calibrate_delay() to be called,
  * but this is an __init function ! So you MUST go edit
diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c
index 54d2271..014d06e6 100644
--- a/arch/powerpc/platforms/powermac/nvram.c
+++ b/arch/powerpc/platforms/powermac/nvram.c
@@ -23,7 +23,6 @@
 #include <linux/spinlock.h>
 #include <asm/sections.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/nvram.h>
@@ -279,7 +278,7 @@
 
 static int sm_erase_bank(int bank)
 {
-	int stat, i;
+	int stat;
 	unsigned long timeout;
 
 	u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
@@ -301,11 +300,10 @@
 	out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
 	out_8(base, SM_FLASH_CMD_RESET);
 
-	for (i=0; i<NVRAM_SIZE; i++)
-		if (base[i] != 0xff) {
-			printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n");
-			return -ENXIO;
-		}
+	if (memchr_inv(base, 0xff, NVRAM_SIZE)) {
+		printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n");
+		return -ENXIO;
+	}
 	return 0;
 }
 
@@ -336,17 +334,16 @@
 	}
 	out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
 	out_8(base, SM_FLASH_CMD_RESET);
-	for (i=0; i<NVRAM_SIZE; i++)
-		if (base[i] != datas[i]) {
-			printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n");
-			return -ENXIO;
-		}
+	if (memcmp(base, datas, NVRAM_SIZE)) {
+		printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n");
+		return -ENXIO;
+	}
 	return 0;
 }
 
 static int amd_erase_bank(int bank)
 {
-	int i, stat = 0;
+	int stat = 0;
 	unsigned long timeout;
 
 	u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
@@ -382,12 +379,11 @@
 	/* Reset */
 	out_8(base, 0xf0);
 	udelay(1);
-	
-	for (i=0; i<NVRAM_SIZE; i++)
-		if (base[i] != 0xff) {
-			printk(KERN_ERR "nvram: AMD flash erase failed !\n");
-			return -ENXIO;
-		}
+
+	if (memchr_inv(base, 0xff, NVRAM_SIZE)) {
+		printk(KERN_ERR "nvram: AMD flash erase failed !\n");
+		return -ENXIO;
+	}
 	return 0;
 }
 
@@ -429,11 +425,10 @@
 	out_8(base, 0xf0);
 	udelay(1);
 
-	for (i=0; i<NVRAM_SIZE; i++)
-		if (base[i] != datas[i]) {
-			printk(KERN_ERR "nvram: AMD flash write failed !\n");
-			return -ENXIO;
-		}
+	if (memcmp(base, datas, NVRAM_SIZE)) {
+		printk(KERN_ERR "nvram: AMD flash write failed !\n");
+		return -ENXIO;
+	}
 	return 0;
 }
 
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index 31a7d3a..43bbe1b 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -1059,9 +1059,6 @@
 	}
 	/* pmac_check_ht_link(); */
 
-	/* We can allocate missing resources if any */
-	pci_probe_only = 0;
-
 #else /* CONFIG_PPC64 */
 	init_p2pbridge();
 	init_second_ohare();
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 92afc38..66ad93d 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -457,7 +457,6 @@
 
 	pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0);
 
-	flags |= MPIC_WANTS_RESET;
 	if (of_get_property(np, "big-endian", NULL))
 		flags |= MPIC_BIG_ENDIAN;
 
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 970ea1d..141f8899 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -57,7 +57,6 @@
 #include <asm/reg.h>
 #include <asm/sections.h>
 #include <asm/prom.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
 #include <asm/pci-bridge.h>
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index 11c9fce..8680bb6 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -26,7 +26,6 @@
 
 #include <asm/sections.h>
 #include <asm/prom.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/machdep.h>
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 5e155df..fbdd74d 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -1299,15 +1299,14 @@
 	/* Setup MSI support */
 	pnv_pci_init_ioda_msis(phb);
 
-	/* We set both probe_only and PCI_REASSIGN_ALL_RSRC. This is an
+	/* We set both PCI_PROBE_ONLY and PCI_REASSIGN_ALL_RSRC. This is an
 	 * odd combination which essentially means that we skip all resource
 	 * fixups and assignments in the generic code, and do it all
 	 * ourselves here
 	 */
-	pci_probe_only = 1;
 	ppc_md.pcibios_fixup_phb = pnv_pci_ioda_fixup_phb;
 	ppc_md.pcibios_enable_device_hook = pnv_pci_enable_device_hook;
-	pci_add_flags(PCI_REASSIGN_ALL_RSRC);
+	pci_add_flags(PCI_PROBE_ONLY | PCI_REASSIGN_ALL_RSRC);
 
 	/* Reset IODA tables to a clean state */
 	rc = opal_pci_reset(phb_id, OPAL_PCI_IODA_TABLE_RESET, OPAL_ASSERT_RESET);
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index f92b9ef..be3cfc5 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -31,6 +31,7 @@
 #include <asm/iommu.h>
 #include <asm/tce.h>
 #include <asm/abs_addr.h>
+#include <asm/firmware.h>
 
 #include "powernv.h"
 #include "pci.h"
@@ -561,10 +562,7 @@
 {
 	struct device_node *np;
 
-	pci_set_flags(PCI_CAN_SKIP_ISA_ALIGN);
-
-	/* We do not want to just probe */
-	pci_probe_only = 0;
+	pci_add_flags(PCI_CAN_SKIP_ISA_ALIGN);
 
 	/* OPAL absent, try POPAL first then RTAS detection of PHBs */
 	if (!firmware_has_feature(FW_FEATURE_OPAL)) {
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index 467bd4a..db1ad1c 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -31,7 +31,6 @@
 #include <asm/xics.h>
 #include <asm/rtas.h>
 #include <asm/opal.h>
-#include <asm/xics.h>
 
 #include "powernv.h"
 
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c
index 17210c5..3ef4625 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -25,7 +25,6 @@
 #include <asm/machdep.h>
 #include <asm/cputable.h>
 #include <asm/firmware.h>
-#include <asm/system.h>
 #include <asm/rtas.h>
 #include <asm/vdso_datapage.h>
 #include <asm/cputhreads.h>
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
index 8bd6ba5..de2aea4 100644
--- a/arch/powerpc/platforms/ps3/mm.c
+++ b/arch/powerpc/platforms/ps3/mm.c
@@ -29,6 +29,7 @@
 #include <asm/prom.h>
 #include <asm/udbg.h>
 #include <asm/lv1call.h>
+#include <asm/setup.h>
 
 #include "platform.h"
 
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c
index 880eb9c..5606fe3 100644
--- a/arch/powerpc/platforms/ps3/system-bus.c
+++ b/arch/powerpc/platforms/ps3/system-bus.c
@@ -515,7 +515,8 @@
  * to the dma address (mapping) of the first page.
  */
 static void * ps3_alloc_coherent(struct device *_dev, size_t size,
-				      dma_addr_t *dma_handle, gfp_t flag)
+				 dma_addr_t *dma_handle, gfp_t flag,
+				 struct dma_attrs *attrs)
 {
 	int result;
 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
@@ -552,7 +553,7 @@
 }
 
 static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
-	dma_addr_t dma_handle)
+			      dma_addr_t dma_handle, struct dma_attrs *attrs)
 {
 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
 
@@ -701,8 +702,8 @@
 }
 
 static struct dma_map_ops ps3_sb_dma_ops = {
-	.alloc_coherent = ps3_alloc_coherent,
-	.free_coherent = ps3_free_coherent,
+	.alloc = ps3_alloc_coherent,
+	.free = ps3_free_coherent,
 	.map_sg = ps3_sb_map_sg,
 	.unmap_sg = ps3_sb_unmap_sg,
 	.dma_supported = ps3_dma_supported,
@@ -712,8 +713,8 @@
 };
 
 static struct dma_map_ops ps3_ioc0_dma_ops = {
-	.alloc_coherent = ps3_alloc_coherent,
-	.free_coherent = ps3_free_coherent,
+	.alloc = ps3_alloc_coherent,
+	.free = ps3_free_coherent,
 	.map_sg = ps3_ioc0_map_sg,
 	.unmap_sg = ps3_ioc0_unmap_sg,
 	.dma_supported = ps3_dma_supported,
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index f255625..aadbe4f 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -73,7 +73,7 @@
 
 config LPARCFG
 	bool "LPAR Configuration Data"
-	depends on PPC_PSERIES || PPC_ISERIES
+	depends on PPC_PSERIES
 	help
 	Provide system capacity information via human readable
 	<key word>=<value> pairs through a /proc/ppc64/lparcfg interface.
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 236db46b..c222189 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -6,7 +6,8 @@
 			   firmware.o power.o dlpar.o mobility.o
 obj-$(CONFIG_SMP)	+= smp.o
 obj-$(CONFIG_SCANLOG)	+= scanlog.o
-obj-$(CONFIG_EEH)	+= eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o
+obj-$(CONFIG_EEH)	+= eeh.o eeh_dev.o eeh_cache.o eeh_driver.o \
+			   eeh_event.o eeh_sysfs.o eeh_pseries.o
 obj-$(CONFIG_KEXEC)	+= kexec.o
 obj-$(CONFIG_PCI)	+= pci.o pci_dlpar.o
 obj-$(CONFIG_PSERIES_MSI)	+= msi.o
@@ -18,7 +19,6 @@
 obj-$(CONFIG_HVC_CONSOLE)	+= hvconsole.o
 obj-$(CONFIG_HVCS)		+= hvcserver.o
 obj-$(CONFIG_HCALL_STATS)	+= hvCall_inst.o
-obj-$(CONFIG_PHYP_DUMP)		+= phyp_dump.o
 obj-$(CONFIG_CMM)		+= cmm.o
 obj-$(CONFIG_DTL)		+= dtl.o
 obj-$(CONFIG_IO_EVENT_IRQ)	+= io_event_irq.o
diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c
index 0e86563..a764854 100644
--- a/arch/powerpc/platforms/pseries/dtl.c
+++ b/arch/powerpc/platforms/pseries/dtl.c
@@ -25,10 +25,10 @@
 #include <linux/debugfs.h>
 #include <linux/spinlock.h>
 #include <asm/smp.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/firmware.h>
 #include <asm/lppaca.h>
+#include <asm/debug.h>
 
 #include "plpar_wrappers.h"
 
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index c0b40af..309d38e 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -1,8 +1,8 @@
 /*
- * eeh.c
  * Copyright IBM Corporation 2001, 2005, 2006
  * Copyright Dave Engebretsen & Todd Inglett 2001
  * Copyright Linas Vepstas 2005, 2006
+ * Copyright 2001-2012 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
@@ -22,7 +22,7 @@
  */
 
 #include <linux/delay.h>
-#include <linux/sched.h>	/* for init_mm */
+#include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/pci.h>
@@ -86,16 +86,8 @@
 /* Time to wait for a PCI slot to report status, in milliseconds */
 #define PCI_BUS_RESET_WAIT_MSEC (60*1000)
 
-/* RTAS tokens */
-static int ibm_set_eeh_option;
-static int ibm_set_slot_reset;
-static int ibm_read_slot_reset_state;
-static int ibm_read_slot_reset_state2;
-static int ibm_slot_error_detail;
-static int ibm_get_config_addr_info;
-static int ibm_get_config_addr_info2;
-static int ibm_configure_bridge;
-static int ibm_configure_pe;
+/* Platform dependent EEH operations */
+struct eeh_ops *eeh_ops = NULL;
 
 int eeh_subsystem_enabled;
 EXPORT_SYMBOL(eeh_subsystem_enabled);
@@ -103,14 +95,6 @@
 /* Lock to avoid races due to multiple reports of an error */
 static DEFINE_RAW_SPINLOCK(confirm_error_lock);
 
-/* Buffer for reporting slot-error-detail rtas calls. Its here
- * in BSS, and not dynamically alloced, so that it ends up in
- * RMO where RTAS can access it.
- */
-static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX];
-static DEFINE_SPINLOCK(slot_errbuf_lock);
-static int eeh_error_buf_size;
-
 /* Buffer for reporting pci register dumps. Its here in BSS, and
  * not dynamically alloced, so that it ends up in RMO where RTAS
  * can access it.
@@ -118,74 +102,50 @@
 #define EEH_PCI_REGS_LOG_LEN 4096
 static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN];
 
-/* System monitoring statistics */
-static unsigned long no_device;
-static unsigned long no_dn;
-static unsigned long no_cfg_addr;
-static unsigned long ignored_check;
-static unsigned long total_mmio_ffs;
-static unsigned long false_positives;
-static unsigned long slot_resets;
+/*
+ * The struct is used to maintain the EEH global statistic
+ * information. Besides, the EEH global statistics will be
+ * exported to user space through procfs
+ */
+struct eeh_stats {
+	u64 no_device;		/* PCI device not found		*/
+	u64 no_dn;		/* OF node not found		*/
+	u64 no_cfg_addr;	/* Config address not found	*/
+	u64 ignored_check;	/* EEH check skipped		*/
+	u64 total_mmio_ffs;	/* Total EEH checks		*/
+	u64 false_positives;	/* Unnecessary EEH checks	*/
+	u64 slot_resets;	/* PE reset			*/
+};
+
+static struct eeh_stats eeh_stats;
 
 #define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE)
 
-/* --------------------------------------------------------------- */
-/* Below lies the EEH event infrastructure */
-
-static void rtas_slot_error_detail(struct pci_dn *pdn, int severity,
-                                   char *driver_log, size_t loglen)
-{
-	int config_addr;
-	unsigned long flags;
-	int rc;
-
-	/* Log the error with the rtas logger */
-	spin_lock_irqsave(&slot_errbuf_lock, flags);
-	memset(slot_errbuf, 0, eeh_error_buf_size);
-
-	/* Use PE configuration address, if present */
-	config_addr = pdn->eeh_config_addr;
-	if (pdn->eeh_pe_config_addr)
-		config_addr = pdn->eeh_pe_config_addr;
-
-	rc = rtas_call(ibm_slot_error_detail,
-	               8, 1, NULL, config_addr,
-	               BUID_HI(pdn->phb->buid),
-	               BUID_LO(pdn->phb->buid),
-	               virt_to_phys(driver_log), loglen,
-	               virt_to_phys(slot_errbuf),
-	               eeh_error_buf_size,
-	               severity);
-
-	if (rc == 0)
-		log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0);
-	spin_unlock_irqrestore(&slot_errbuf_lock, flags);
-}
-
 /**
- * gather_pci_data - copy assorted PCI config space registers to buff
- * @pdn: device to report data for
+ * eeh_gather_pci_data - Copy assorted PCI config space registers to buff
+ * @edev: device to report data for
  * @buf: point to buffer in which to log
  * @len: amount of room in buffer
  *
  * This routine captures assorted PCI configuration space data,
  * and puts them into a buffer for RTAS error logging.
  */
-static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
+static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
 {
-	struct pci_dev *dev = pdn->pcidev;
+	struct device_node *dn = eeh_dev_to_of_node(edev);
+	struct pci_dev *dev = eeh_dev_to_pci_dev(edev);
 	u32 cfg;
 	int cap, i;
 	int n = 0;
 
-	n += scnprintf(buf+n, len-n, "%s\n", pdn->node->full_name);
-	printk(KERN_WARNING "EEH: of node=%s\n", pdn->node->full_name);
+	n += scnprintf(buf+n, len-n, "%s\n", dn->full_name);
+	printk(KERN_WARNING "EEH: of node=%s\n", dn->full_name);
 
-	rtas_read_config(pdn, PCI_VENDOR_ID, 4, &cfg);
+	eeh_ops->read_config(dn, PCI_VENDOR_ID, 4, &cfg);
 	n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg);
 	printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg);
 
-	rtas_read_config(pdn, PCI_COMMAND, 4, &cfg);
+	eeh_ops->read_config(dn, PCI_COMMAND, 4, &cfg);
 	n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg);
 	printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg);
 
@@ -196,11 +156,11 @@
 
 	/* Gather bridge-specific registers */
 	if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) {
-		rtas_read_config(pdn, PCI_SEC_STATUS, 2, &cfg);
+		eeh_ops->read_config(dn, PCI_SEC_STATUS, 2, &cfg);
 		n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg);
 		printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg);
 
-		rtas_read_config(pdn, PCI_BRIDGE_CONTROL, 2, &cfg);
+		eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &cfg);
 		n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg);
 		printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg);
 	}
@@ -208,11 +168,11 @@
 	/* Dump out the PCI-X command and status regs */
 	cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
 	if (cap) {
-		rtas_read_config(pdn, cap, 4, &cfg);
+		eeh_ops->read_config(dn, cap, 4, &cfg);
 		n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg);
 		printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg);
 
-		rtas_read_config(pdn, cap+4, 4, &cfg);
+		eeh_ops->read_config(dn, cap+4, 4, &cfg);
 		n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg);
 		printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg);
 	}
@@ -225,7 +185,7 @@
 		       "EEH: PCI-E capabilities and status follow:\n");
 
 		for (i=0; i<=8; i++) {
-			rtas_read_config(pdn, cap+4*i, 4, &cfg);
+			eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
 			n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
 			printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg);
 		}
@@ -237,7 +197,7 @@
 			       "EEH: PCI-E AER capability register set follows:\n");
 
 			for (i=0; i<14; i++) {
-				rtas_read_config(pdn, cap+4*i, 4, &cfg);
+				eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
 				n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
 				printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg);
 			}
@@ -246,111 +206,46 @@
 
 	/* Gather status on devices under the bridge */
 	if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) {
-		struct device_node *dn;
+		struct device_node *child;
 
-		for_each_child_of_node(pdn->node, dn) {
-			pdn = PCI_DN(dn);
-			if (pdn)
-				n += gather_pci_data(pdn, buf+n, len-n);
+		for_each_child_of_node(dn, child) {
+			if (of_node_to_eeh_dev(child))
+				n += eeh_gather_pci_data(of_node_to_eeh_dev(child), buf+n, len-n);
 		}
 	}
 
 	return n;
 }
 
-void eeh_slot_error_detail(struct pci_dn *pdn, int severity)
+/**
+ * eeh_slot_error_detail - Generate combined log including driver log and error log
+ * @edev: device to report error log for
+ * @severity: temporary or permanent error log
+ *
+ * This routine should be called to generate the combined log, which
+ * is comprised of driver log and error log. The driver log is figured
+ * out from the config space of the corresponding PCI device, while
+ * the error log is fetched through platform dependent function call.
+ */
+void eeh_slot_error_detail(struct eeh_dev *edev, int severity)
 {
 	size_t loglen = 0;
 	pci_regs_buf[0] = 0;
 
-	rtas_pci_enable(pdn, EEH_THAW_MMIO);
-	rtas_configure_bridge(pdn);
-	eeh_restore_bars(pdn);
-	loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
+	eeh_pci_enable(edev, EEH_OPT_THAW_MMIO);
+	eeh_ops->configure_bridge(eeh_dev_to_of_node(edev));
+	eeh_restore_bars(edev);
+	loglen = eeh_gather_pci_data(edev, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
 
-	rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen);
+	eeh_ops->get_log(eeh_dev_to_of_node(edev), severity, pci_regs_buf, loglen);
 }
 
 /**
- * read_slot_reset_state - Read the reset state of a device node's slot
- * @dn: device node to read
- * @rets: array to return results in
- */
-static int read_slot_reset_state(struct pci_dn *pdn, int rets[])
-{
-	int token, outputs;
-	int config_addr;
-
-	if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) {
-		token = ibm_read_slot_reset_state2;
-		outputs = 4;
-	} else {
-		token = ibm_read_slot_reset_state;
-		rets[2] = 0; /* fake PE Unavailable info */
-		outputs = 3;
-	}
-
-	/* Use PE configuration address, if present */
-	config_addr = pdn->eeh_config_addr;
-	if (pdn->eeh_pe_config_addr)
-		config_addr = pdn->eeh_pe_config_addr;
-
-	return rtas_call(token, 3, outputs, rets, config_addr,
-			 BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid));
-}
-
-/**
- * eeh_wait_for_slot_status - returns error status of slot
- * @pdn pci device node
- * @max_wait_msecs maximum number to millisecs to wait
+ * eeh_token_to_phys - Convert EEH address token to phys address
+ * @token: I/O token, should be address in the form 0xA....
  *
- * Return negative value if a permanent error, else return
- * Partition Endpoint (PE) status value.
- *
- * If @max_wait_msecs is positive, then this routine will
- * sleep until a valid status can be obtained, or until
- * the max allowed wait time is exceeded, in which case
- * a -2 is returned.
- */
-int
-eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs)
-{
-	int rc;
-	int rets[3];
-	int mwait;
-
-	while (1) {
-		rc = read_slot_reset_state(pdn, rets);
-		if (rc) return rc;
-		if (rets[1] == 0) return -1;  /* EEH is not supported */
-
-		if (rets[0] != 5) return rets[0]; /* return actual status */
-
-		if (rets[2] == 0) return -1; /* permanently unavailable */
-
-		if (max_wait_msecs <= 0) break;
-
-		mwait = rets[2];
-		if (mwait <= 0) {
-			printk (KERN_WARNING
-			        "EEH: Firmware returned bad wait value=%d\n", mwait);
-			mwait = 1000;
-		} else if (mwait > 300*1000) {
-			printk (KERN_WARNING
-			        "EEH: Firmware is taking too long, time=%d\n", mwait);
-			mwait = 300*1000;
-		}
-		max_wait_msecs -= mwait;
-		msleep (mwait);
-	}
-
-	printk(KERN_WARNING "EEH: Timed out waiting for slot status\n");
-	return -2;
-}
-
-/**
- * eeh_token_to_phys - convert EEH address token to phys address
- * @token i/o token, should be address in the form 0xA....
+ * This routine should be called to convert virtual I/O address
+ * to physical one.
  */
 static inline unsigned long eeh_token_to_phys(unsigned long token)
 {
@@ -365,36 +260,43 @@
 	return pa | (token & (PAGE_SIZE-1));
 }
 
-/** 
- * Return the "partitionable endpoint" (pe) under which this device lies
+/**
+ * eeh_find_device_pe - Retrieve the PE for the given device
+ * @dn: device node
+ *
+ * Return the PE under which this device lies
  */
-struct device_node * find_device_pe(struct device_node *dn)
+struct device_node *eeh_find_device_pe(struct device_node *dn)
 {
-	while ((dn->parent) && PCI_DN(dn->parent) &&
-	      (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) {
+	while (dn->parent && of_node_to_eeh_dev(dn->parent) &&
+	       (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) {
 		dn = dn->parent;
 	}
 	return dn;
 }
 
-/** Mark all devices that are children of this device as failed.
- *  Mark the device driver too, so that it can see the failure
- *  immediately; this is critical, since some drivers poll
- *  status registers in interrupts ... If a driver is polling,
- *  and the slot is frozen, then the driver can deadlock in
- *  an interrupt context, which is bad.
+/**
+ * __eeh_mark_slot - Mark all child devices as failed
+ * @parent: parent device
+ * @mode_flag: failure flag
+ *
+ * Mark all devices that are children of this device as failed.
+ * Mark the device driver too, so that it can see the failure
+ * immediately; this is critical, since some drivers poll
+ * status registers in interrupts ... If a driver is polling,
+ * and the slot is frozen, then the driver can deadlock in
+ * an interrupt context, which is bad.
  */
-
 static void __eeh_mark_slot(struct device_node *parent, int mode_flag)
 {
 	struct device_node *dn;
 
 	for_each_child_of_node(parent, dn) {
-		if (PCI_DN(dn)) {
+		if (of_node_to_eeh_dev(dn)) {
 			/* Mark the pci device driver too */
-			struct pci_dev *dev = PCI_DN(dn)->pcidev;
+			struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev;
 
-			PCI_DN(dn)->eeh_mode |= mode_flag;
+			of_node_to_eeh_dev(dn)->mode |= mode_flag;
 
 			if (dev && dev->driver)
 				dev->error_state = pci_channel_io_frozen;
@@ -404,92 +306,81 @@
 	}
 }
 
-void eeh_mark_slot (struct device_node *dn, int mode_flag)
+/**
+ * eeh_mark_slot - Mark the indicated device and its children as failed
+ * @dn: parent device
+ * @mode_flag: failure flag
+ *
+ * Mark the indicated device and its child devices as failed.
+ * The device drivers are marked as failed as well.
+ */
+void eeh_mark_slot(struct device_node *dn, int mode_flag)
 {
 	struct pci_dev *dev;
-	dn = find_device_pe (dn);
+	dn = eeh_find_device_pe(dn);
 
 	/* Back up one, since config addrs might be shared */
-	if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
+	if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent))
 		dn = dn->parent;
 
-	PCI_DN(dn)->eeh_mode |= mode_flag;
+	of_node_to_eeh_dev(dn)->mode |= mode_flag;
 
 	/* Mark the pci device too */
-	dev = PCI_DN(dn)->pcidev;
+	dev = of_node_to_eeh_dev(dn)->pdev;
 	if (dev)
 		dev->error_state = pci_channel_io_frozen;
 
 	__eeh_mark_slot(dn, mode_flag);
 }
 
+/**
+ * __eeh_clear_slot - Clear failure flag for the child devices
+ * @parent: parent device
+ * @mode_flag: flag to be cleared
+ *
+ * Clear failure flag for the child devices.
+ */
 static void __eeh_clear_slot(struct device_node *parent, int mode_flag)
 {
 	struct device_node *dn;
 
 	for_each_child_of_node(parent, dn) {
-		if (PCI_DN(dn)) {
-			PCI_DN(dn)->eeh_mode &= ~mode_flag;
-			PCI_DN(dn)->eeh_check_count = 0;
+		if (of_node_to_eeh_dev(dn)) {
+			of_node_to_eeh_dev(dn)->mode &= ~mode_flag;
+			of_node_to_eeh_dev(dn)->check_count = 0;
 			__eeh_clear_slot(dn, mode_flag);
 		}
 	}
 }
 
-void eeh_clear_slot (struct device_node *dn, int mode_flag)
+/**
+ * eeh_clear_slot - Clear failure flag for the indicated device and its children
+ * @dn: parent device
+ * @mode_flag: flag to be cleared
+ *
+ * Clear failure flag for the indicated device and its children.
+ */
+void eeh_clear_slot(struct device_node *dn, int mode_flag)
 {
 	unsigned long flags;
 	raw_spin_lock_irqsave(&confirm_error_lock, flags);
 	
-	dn = find_device_pe (dn);
+	dn = eeh_find_device_pe(dn);
 	
 	/* Back up one, since config addrs might be shared */
-	if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
+	if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent))
 		dn = dn->parent;
 
-	PCI_DN(dn)->eeh_mode &= ~mode_flag;
-	PCI_DN(dn)->eeh_check_count = 0;
+	of_node_to_eeh_dev(dn)->mode &= ~mode_flag;
+	of_node_to_eeh_dev(dn)->check_count = 0;
 	__eeh_clear_slot(dn, mode_flag);
 	raw_spin_unlock_irqrestore(&confirm_error_lock, flags);
 }
 
-void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset)
-{
-	struct device_node *dn;
-
-	for_each_child_of_node(parent, dn) {
-		if (PCI_DN(dn)) {
-
-			struct pci_dev *dev = PCI_DN(dn)->pcidev;
-
-			if (dev && dev->driver)
-				*freset |= dev->needs_freset;
-
-			__eeh_set_pe_freset(dn, freset);
-		}
-	}
-}
-
-void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset)
-{
-	struct pci_dev *dev;
-	dn = find_device_pe(dn);
-
-	/* Back up one, since config addrs might be shared */
-	if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
-		dn = dn->parent;
-
-	dev = PCI_DN(dn)->pcidev;
-	if (dev)
-		*freset |= dev->needs_freset;
-
-	__eeh_set_pe_freset(dn, freset);
-}
-
 /**
- * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze
- * @dn device node
- * @dev pci device, if known
+ * eeh_dn_check_failure - Check if all 1's data is due to EEH slot freeze
+ * @dn: device node
+ * @dev: pci device, if known
  *
  * Check for an EEH failure for the given device node.  Call this
  * routine if the result of a read was all 0xff's and you want to
@@ -504,35 +395,34 @@
 int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
 {
 	int ret;
-	int rets[3];
 	unsigned long flags;
-	struct pci_dn *pdn;
+	struct eeh_dev *edev;
 	int rc = 0;
 	const char *location;
 
-	total_mmio_ffs++;
+	eeh_stats.total_mmio_ffs++;
 
 	if (!eeh_subsystem_enabled)
 		return 0;
 
 	if (!dn) {
-		no_dn++;
+		eeh_stats.no_dn++;
 		return 0;
 	}
-	dn = find_device_pe(dn);
-	pdn = PCI_DN(dn);
+	dn = eeh_find_device_pe(dn);
+	edev = of_node_to_eeh_dev(dn);
 
 	/* Access to IO BARs might get this far and still not want checking. */
-	if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) ||
-	    pdn->eeh_mode & EEH_MODE_NOCHECK) {
-		ignored_check++;
+	if (!(edev->mode & EEH_MODE_SUPPORTED) ||
+	    edev->mode & EEH_MODE_NOCHECK) {
+		eeh_stats.ignored_check++;
 		pr_debug("EEH: Ignored check (%x) for %s %s\n",
-			 pdn->eeh_mode, eeh_pci_name(dev), dn->full_name);
+			edev->mode, eeh_pci_name(dev), dn->full_name);
 		return 0;
 	}
 
-	if (!pdn->eeh_config_addr && !pdn->eeh_pe_config_addr) {
-		no_cfg_addr++;
+	if (!edev->config_addr && !edev->pe_config_addr) {
+		eeh_stats.no_cfg_addr++;
 		return 0;
 	}
 
@@ -544,15 +434,15 @@
 	 */
 	raw_spin_lock_irqsave(&confirm_error_lock, flags);
 	rc = 1;
-	if (pdn->eeh_mode & EEH_MODE_ISOLATED) {
-		pdn->eeh_check_count ++;
-		if (pdn->eeh_check_count % EEH_MAX_FAILS == 0) {
+	if (edev->mode & EEH_MODE_ISOLATED) {
+		edev->check_count++;
+		if (edev->check_count % EEH_MAX_FAILS == 0) {
 			location = of_get_property(dn, "ibm,loc-code", NULL);
-			printk (KERN_ERR "EEH: %d reads ignored for recovering device at "
+			printk(KERN_ERR "EEH: %d reads ignored for recovering device at "
 				"location=%s driver=%s pci addr=%s\n",
-				pdn->eeh_check_count, location,
+				edev->check_count, location,
 				eeh_driver_name(dev), eeh_pci_name(dev));
-			printk (KERN_ERR "EEH: Might be infinite loop in %s driver\n",
+			printk(KERN_ERR "EEH: Might be infinite loop in %s driver\n",
 				eeh_driver_name(dev));
 			dump_stack();
 		}
@@ -566,58 +456,39 @@
 	 * function zero of a multi-function device.
 	 * In any case they must share a common PHB.
 	 */
-	ret = read_slot_reset_state(pdn, rets);
-
-	/* If the call to firmware failed, punt */
-	if (ret != 0) {
-		printk(KERN_WARNING "EEH: read_slot_reset_state() failed; rc=%d dn=%s\n",
-		       ret, dn->full_name);
-		false_positives++;
-		pdn->eeh_false_positives ++;
-		rc = 0;
-		goto dn_unlock;
-	}
+	ret = eeh_ops->get_state(dn, NULL);
 
 	/* Note that config-io to empty slots may fail;
-	 * they are empty when they don't have children. */
-	if ((rets[0] == 5) && (rets[2] == 0) && (dn->child == NULL)) {
-		false_positives++;
-		pdn->eeh_false_positives ++;
+	 * they are empty when they don't have children.
+	 * We will punt with the following conditions: Failure to get
+	 * PE's state, EEH not support and Permanently unavailable
+	 * state, PE is in good state.
+	 */
+	if ((ret < 0) ||
+	    (ret == EEH_STATE_NOT_SUPPORT) ||
+	    (ret & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) ==
+	    (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) {
+		eeh_stats.false_positives++;
+		edev->false_positives ++;
 		rc = 0;
 		goto dn_unlock;
 	}
 
-	/* If EEH is not supported on this device, punt. */
-	if (rets[1] != 1) {
-		printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n",
-		       ret, dn->full_name);
-		false_positives++;
-		pdn->eeh_false_positives ++;
-		rc = 0;
-		goto dn_unlock;
-	}
-
-	/* If not the kind of error we know about, punt. */
-	if (rets[0] != 1 && rets[0] != 2 && rets[0] != 4 && rets[0] != 5) {
-		false_positives++;
-		pdn->eeh_false_positives ++;
-		rc = 0;
-		goto dn_unlock;
-	}
-
-	slot_resets++;
+	eeh_stats.slot_resets++;
  
 	/* Avoid repeated reports of this failure, including problems
 	 * with other functions on this device, and functions under
-	 * bridges. */
-	eeh_mark_slot (dn, EEH_MODE_ISOLATED);
+	 * bridges.
+	 */
+	eeh_mark_slot(dn, EEH_MODE_ISOLATED);
 	raw_spin_unlock_irqrestore(&confirm_error_lock, flags);
 
-	eeh_send_failure_event (dn, dev);
+	eeh_send_failure_event(edev);
 
 	/* Most EEH events are due to device driver bugs.  Having
 	 * a stack trace will help the device-driver authors figure
-	 * out what happened.  So print that out. */
+	 * out what happened.  So print that out.
+	 */
 	dump_stack();
 	return 1;
 
@@ -629,9 +500,9 @@
 EXPORT_SYMBOL_GPL(eeh_dn_check_failure);
 
 /**
- * eeh_check_failure - check if all 1's data is due to EEH slot freeze
- * @token i/o token, should be address in the form 0xA....
- * @val value, should be all 1's (XXX why do we need this arg??)
+ * eeh_check_failure - Check if all 1's data is due to EEH slot freeze
+ * @token: I/O token, should be address in the form 0xA....
+ * @val: value, should be all 1's (XXX why do we need this arg??)
  *
  * Check for an EEH failure at the given token address.  Call this
  * routine if the result of a read was all 0xff's and you want to
@@ -648,14 +519,14 @@
 
 	/* Finding the phys addr + pci device; this is pretty quick. */
 	addr = eeh_token_to_phys((unsigned long __force) token);
-	dev = pci_get_device_by_addr(addr);
+	dev = pci_addr_cache_get_device(addr);
 	if (!dev) {
-		no_device++;
+		eeh_stats.no_device++;
 		return val;
 	}
 
 	dn = pci_device_to_OF_node(dev);
-	eeh_dn_check_failure (dn, dev);
+	eeh_dn_check_failure(dn, dev);
 
 	pci_dev_put(dev);
 	return val;
@@ -663,115 +534,54 @@
 
 EXPORT_SYMBOL(eeh_check_failure);
 
-/* ------------------------------------------------------------- */
-/* The code below deals with error recovery */
 
 /**
- * rtas_pci_enable - enable MMIO or DMA transfers for this slot
- * @pdn pci device node
+ * eeh_pci_enable - Enable MMIO or DMA transfers for this slot
+ * @edev: pci device node
+ *
+ * This routine should be called to reenable frozen MMIO or DMA
+ * so that it would work correctly again. It's useful while doing
+ * recovery or log collection on the indicated device.
  */
-
-int
-rtas_pci_enable(struct pci_dn *pdn, int function)
+int eeh_pci_enable(struct eeh_dev *edev, int function)
 {
-	int config_addr;
 	int rc;
+	struct device_node *dn = eeh_dev_to_of_node(edev);
 
-	/* Use PE configuration address, if present */
-	config_addr = pdn->eeh_config_addr;
-	if (pdn->eeh_pe_config_addr)
-		config_addr = pdn->eeh_pe_config_addr;
-
-	rc = rtas_call(ibm_set_eeh_option, 4, 1, NULL,
-	               config_addr,
-	               BUID_HI(pdn->phb->buid),
-	               BUID_LO(pdn->phb->buid),
-		            function);
-
+	rc = eeh_ops->set_option(dn, function);
 	if (rc)
 		printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n",
-		        function, rc, pdn->node->full_name);
+		        function, rc, dn->full_name);
 
-	rc = eeh_wait_for_slot_status (pdn, PCI_BUS_RESET_WAIT_MSEC);
-	if ((rc == 4) && (function == EEH_THAW_MMIO))
+	rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC);
+	if (rc > 0 && (rc & EEH_STATE_MMIO_ENABLED) &&
+	   (function == EEH_OPT_THAW_MMIO))
 		return 0;
 
 	return rc;
 }
 
 /**
- * rtas_pci_slot_reset - raises/lowers the pci #RST line
- * @pdn pci device node
- * @state: 1/0 to raise/lower the #RST
- *
- * Clear the EEH-frozen condition on a slot.  This routine
- * asserts the PCI #RST line if the 'state' argument is '1',
- * and drops the #RST line if 'state is '0'.  This routine is
- * safe to call in an interrupt context.
- *
- */
-
-static void
-rtas_pci_slot_reset(struct pci_dn *pdn, int state)
-{
-	int config_addr;
-	int rc;
-
-	BUG_ON (pdn==NULL); 
-
-	if (!pdn->phb) {
-		printk (KERN_WARNING "EEH: in slot reset, device node %s has no phb\n",
-		        pdn->node->full_name);
-		return;
-	}
-
-	/* Use PE configuration address, if present */
-	config_addr = pdn->eeh_config_addr;
-	if (pdn->eeh_pe_config_addr)
-		config_addr = pdn->eeh_pe_config_addr;
-
-	rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL,
-	               config_addr,
-	               BUID_HI(pdn->phb->buid),
-	               BUID_LO(pdn->phb->buid),
-	               state);
-
-	/* Fundamental-reset not supported on this PE, try hot-reset */
-	if (rc == -8 && state == 3) {
-		rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL,
-			       config_addr,
-			       BUID_HI(pdn->phb->buid),
-			       BUID_LO(pdn->phb->buid), 1);
-		if (rc)
-			printk(KERN_WARNING
-				"EEH: Unable to reset the failed slot,"
-				" #RST=%d dn=%s\n",
-				rc, pdn->node->full_name);
-	}
-}
-
-/**
  * pcibios_set_pcie_slot_reset - Set PCI-E reset state
- * @dev:	pci device struct
- * @state:	reset state to enter
+ * @dev: pci device struct
+ * @state: reset state to enter
  *
  * Return value:
  * 	0 if success
- **/
+ */
 int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
 {
 	struct device_node *dn = pci_device_to_OF_node(dev);
-	struct pci_dn *pdn = PCI_DN(dn);
 
 	switch (state) {
 	case pcie_deassert_reset:
-		rtas_pci_slot_reset(pdn, 0);
+		eeh_ops->reset(dn, EEH_RESET_DEACTIVATE);
 		break;
 	case pcie_hot_reset:
-		rtas_pci_slot_reset(pdn, 1);
+		eeh_ops->reset(dn, EEH_RESET_HOT);
 		break;
 	case pcie_warm_reset:
-		rtas_pci_slot_reset(pdn, 3);
+		eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL);
 		break;
 	default:
 		return -EINVAL;
@@ -781,13 +591,66 @@
 }
 
 /**
- * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second
- * @pdn: pci device node to be reset.
+ * __eeh_set_pe_freset - Check the required reset for child devices
+ * @parent: parent device
+ * @freset: return value
+ *
+ * Each device might have its preferred reset type: fundamental or
+ * hot reset. The routine is used to collect the information from
+ * the child devices so that they could be reset accordingly.
  */
+void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset)
+{
+	struct device_node *dn;
 
-static void __rtas_set_slot_reset(struct pci_dn *pdn)
+	for_each_child_of_node(parent, dn) {
+		if (of_node_to_eeh_dev(dn)) {
+			struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev;
+
+			if (dev && dev->driver)
+				*freset |= dev->needs_freset;
+
+			__eeh_set_pe_freset(dn, freset);
+		}
+	}
+}
+
+/**
+ * eeh_set_pe_freset - Check the required reset for the indicated device and its children
+ * @dn: parent device
+ * @freset: return value
+ *
+ * Each device might have its preferred reset type: fundamental or
+ * hot reset. The routine is used to collected the information for
+ * the indicated device and its children so that the bunch of the
+ * devices could be reset properly.
+ */
+void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset)
+{
+	struct pci_dev *dev;
+	dn = eeh_find_device_pe(dn);
+
+	/* Back up one, since config addrs might be shared */
+	if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent))
+		dn = dn->parent;
+
+	dev = of_node_to_eeh_dev(dn)->pdev;
+	if (dev)
+		*freset |= dev->needs_freset;
+
+	__eeh_set_pe_freset(dn, freset);
+}
+
+/**
+ * eeh_reset_pe_once - Assert the pci #RST line for 1/4 second
+ * @edev: pci device node to be reset.
+ *
+ * Assert the PCI #RST line for 1/4 second.
+ */
+static void eeh_reset_pe_once(struct eeh_dev *edev)
 {
 	unsigned int freset = 0;
+	struct device_node *dn = eeh_dev_to_of_node(edev);
 
 	/* Determine type of EEH reset required for
 	 * Partitionable Endpoint, a hot-reset (1)
@@ -795,58 +658,68 @@
 	 * A fundamental reset required by any device under
 	 * Partitionable Endpoint trumps hot-reset.
   	 */
-	eeh_set_pe_freset(pdn->node, &freset);
+	eeh_set_pe_freset(dn, &freset);
 
 	if (freset)
-		rtas_pci_slot_reset(pdn, 3);
+		eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL);
 	else
-		rtas_pci_slot_reset(pdn, 1);
+		eeh_ops->reset(dn, EEH_RESET_HOT);
 
 	/* The PCI bus requires that the reset be held high for at least
-	 * a 100 milliseconds. We wait a bit longer 'just in case'.  */
-
+	 * a 100 milliseconds. We wait a bit longer 'just in case'.
+	 */
 #define PCI_BUS_RST_HOLD_TIME_MSEC 250
-	msleep (PCI_BUS_RST_HOLD_TIME_MSEC);
+	msleep(PCI_BUS_RST_HOLD_TIME_MSEC);
 	
 	/* We might get hit with another EEH freeze as soon as the 
 	 * pci slot reset line is dropped. Make sure we don't miss
-	 * these, and clear the flag now. */
-	eeh_clear_slot (pdn->node, EEH_MODE_ISOLATED);
+	 * these, and clear the flag now.
+	 */
+	eeh_clear_slot(dn, EEH_MODE_ISOLATED);
 
-	rtas_pci_slot_reset (pdn, 0);
+	eeh_ops->reset(dn, EEH_RESET_DEACTIVATE);
 
 	/* After a PCI slot has been reset, the PCI Express spec requires
 	 * a 1.5 second idle time for the bus to stabilize, before starting
-	 * up traffic. */
+	 * up traffic.
+	 */
 #define PCI_BUS_SETTLE_TIME_MSEC 1800
-	msleep (PCI_BUS_SETTLE_TIME_MSEC);
+	msleep(PCI_BUS_SETTLE_TIME_MSEC);
 }
 
-int rtas_set_slot_reset(struct pci_dn *pdn)
+/**
+ * eeh_reset_pe - Reset the indicated PE
+ * @edev: PCI device associated EEH device
+ *
+ * This routine should be called to reset indicated device, including
+ * PE. A PE might include multiple PCI devices and sometimes PCI bridges
+ * might be involved as well.
+ */
+int eeh_reset_pe(struct eeh_dev *edev)
 {
 	int i, rc;
+	struct device_node *dn = eeh_dev_to_of_node(edev);
 
 	/* Take three shots at resetting the bus */
 	for (i=0; i<3; i++) {
-		__rtas_set_slot_reset(pdn);
+		eeh_reset_pe_once(edev);
 
-		rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC);
-		if (rc == 0)
+		rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC);
+		if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE))
 			return 0;
 
 		if (rc < 0) {
 			printk(KERN_ERR "EEH: unrecoverable slot failure %s\n",
-			       pdn->node->full_name);
+			       dn->full_name);
 			return -1;
 		}
 		printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n",
-		       i+1, pdn->node->full_name, rc);
+		       i+1, dn->full_name, rc);
 	}
 
 	return -1;
 }
 
-/* ------------------------------------------------------- */
 /** Save and restore of PCI BARs
  *
  * Although firmware will set up BARs during boot, it doesn't
@@ -856,181 +729,122 @@
  */
 
 /**
- * __restore_bars - Restore the Base Address Registers
- * @pdn: pci device node
+ * eeh_restore_one_device_bars - Restore the Base Address Registers for one device
+ * @edev: PCI device associated EEH device
  *
  * Loads the PCI configuration space base address registers,
  * the expansion ROM base address, the latency timer, and etc.
  * from the saved values in the device node.
  */
-static inline void __restore_bars (struct pci_dn *pdn)
+static inline void eeh_restore_one_device_bars(struct eeh_dev *edev)
 {
 	int i;
 	u32 cmd;
+	struct device_node *dn = eeh_dev_to_of_node(edev);
 
-	if (NULL==pdn->phb) return;
+	if (!edev->phb)
+		return;
+
 	for (i=4; i<10; i++) {
-		rtas_write_config(pdn, i*4, 4, pdn->config_space[i]);
+		eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]);
 	}
 
 	/* 12 == Expansion ROM Address */
-	rtas_write_config(pdn, 12*4, 4, pdn->config_space[12]);
+	eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]);
 
 #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
-#define SAVED_BYTE(OFF) (((u8 *)(pdn->config_space))[BYTE_SWAP(OFF)])
+#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)])
 
-	rtas_write_config (pdn, PCI_CACHE_LINE_SIZE, 1,
+	eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1,
 	            SAVED_BYTE(PCI_CACHE_LINE_SIZE));
 
-	rtas_write_config (pdn, PCI_LATENCY_TIMER, 1,
+	eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1,
 	            SAVED_BYTE(PCI_LATENCY_TIMER));
 
 	/* max latency, min grant, interrupt pin and line */
-	rtas_write_config(pdn, 15*4, 4, pdn->config_space[15]);
+	eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]);
 
 	/* Restore PERR & SERR bits, some devices require it,
-	   don't touch the other command bits */
-	rtas_read_config(pdn, PCI_COMMAND, 4, &cmd);
-	if (pdn->config_space[1] & PCI_COMMAND_PARITY)
+	 * don't touch the other command bits
+	 */
+	eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd);
+	if (edev->config_space[1] & PCI_COMMAND_PARITY)
 		cmd |= PCI_COMMAND_PARITY;
 	else
 		cmd &= ~PCI_COMMAND_PARITY;
-	if (pdn->config_space[1] & PCI_COMMAND_SERR)
+	if (edev->config_space[1] & PCI_COMMAND_SERR)
 		cmd |= PCI_COMMAND_SERR;
 	else
 		cmd &= ~PCI_COMMAND_SERR;
-	rtas_write_config(pdn, PCI_COMMAND, 4, cmd);
+	eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd);
 }
 
 /**
- * eeh_restore_bars - restore the PCI config space info
+ * eeh_restore_bars - Restore the PCI config space info
+ * @edev: EEH device
  *
  * This routine performs a recursive walk to the children
  * of this device as well.
  */
-void eeh_restore_bars(struct pci_dn *pdn)
+void eeh_restore_bars(struct eeh_dev *edev)
 {
 	struct device_node *dn;
-	if (!pdn) 
+	if (!edev)
 		return;
 	
-	if ((pdn->eeh_mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(pdn->class_code))
-		__restore_bars (pdn);
+	if ((edev->mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(edev->class_code))
+		eeh_restore_one_device_bars(edev);
 
-	for_each_child_of_node(pdn->node, dn)
-		eeh_restore_bars (PCI_DN(dn));
+	for_each_child_of_node(eeh_dev_to_of_node(edev), dn)
+		eeh_restore_bars(of_node_to_eeh_dev(dn));
 }
 
 /**
- * eeh_save_bars - save device bars
+ * eeh_save_bars - Save device bars
+ * @edev: PCI device associated EEH device
  *
  * Save the values of the device bars. Unlike the restore
  * routine, this routine is *not* recursive. This is because
  * PCI devices are added individually; but, for the restore,
  * an entire slot is reset at a time.
  */
-static void eeh_save_bars(struct pci_dn *pdn)
+static void eeh_save_bars(struct eeh_dev *edev)
 {
 	int i;
+	struct device_node *dn;
 
-	if (!pdn )
+	if (!edev)
 		return;
+	dn = eeh_dev_to_of_node(edev);
 	
 	for (i = 0; i < 16; i++)
-		rtas_read_config(pdn, i * 4, 4, &pdn->config_space[i]);
+		eeh_ops->read_config(dn, i * 4, 4, &edev->config_space[i]);
 }
 
-void
-rtas_configure_bridge(struct pci_dn *pdn)
-{
-	int config_addr;
-	int rc;
-	int token;
-
-	/* Use PE configuration address, if present */
-	config_addr = pdn->eeh_config_addr;
-	if (pdn->eeh_pe_config_addr)
-		config_addr = pdn->eeh_pe_config_addr;
-
-	/* Use new configure-pe function, if supported */
-	if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE)
-		token = ibm_configure_pe;
-	else
-		token = ibm_configure_bridge;
-
-	rc = rtas_call(token, 3, 1, NULL,
-	               config_addr,
-	               BUID_HI(pdn->phb->buid),
-	               BUID_LO(pdn->phb->buid));
-	if (rc) {
-		printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n",
-		        rc, pdn->node->full_name);
-	}
-}
-
-/* ------------------------------------------------------------- */
-/* The code below deals with enabling EEH for devices during  the
- * early boot sequence.  EEH must be enabled before any PCI probing
- * can be done.
+/**
+ * eeh_early_enable - Early enable EEH on the indicated device
+ * @dn: device node
+ * @data: BUID
+ *
+ * Enable EEH functionality on the specified PCI device. The function
+ * is expected to be called before real PCI probing is done. However,
+ * the PHBs have been initialized at this point.
  */
-
-#define EEH_ENABLE 1
-
-struct eeh_early_enable_info {
-	unsigned int buid_hi;
-	unsigned int buid_lo;
-};
-
-static int get_pe_addr (int config_addr,
-                        struct eeh_early_enable_info *info)
+static void *eeh_early_enable(struct device_node *dn, void *data)
 {
-	unsigned int rets[3];
-	int ret;
-
-	/* Use latest config-addr token on power6 */
-	if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) {
-		/* Make sure we have a PE in hand */
-		ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets,
-			config_addr, info->buid_hi, info->buid_lo, 1);
-		if (ret || (rets[0]==0))
-			return 0;
-
-		ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets,
-			config_addr, info->buid_hi, info->buid_lo, 0);
-		if (ret)
-			return 0;
-		return rets[0];
-	}
-
-	/* Use older config-addr token on power5 */
-	if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
-		ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets,
-			config_addr, info->buid_hi, info->buid_lo, 0);
-		if (ret)
-			return 0;
-		return rets[0];
-	}
-	return 0;
-}
-
-/* Enable eeh for the given device node. */
-static void *early_enable_eeh(struct device_node *dn, void *data)
-{
-	unsigned int rets[3];
-	struct eeh_early_enable_info *info = data;
 	int ret;
 	const u32 *class_code = of_get_property(dn, "class-code", NULL);
 	const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL);
 	const u32 *device_id = of_get_property(dn, "device-id", NULL);
 	const u32 *regs;
 	int enable;
-	struct pci_dn *pdn = PCI_DN(dn);
+	struct eeh_dev *edev = of_node_to_eeh_dev(dn);
 
-	pdn->class_code = 0;
-	pdn->eeh_mode = 0;
-	pdn->eeh_check_count = 0;
-	pdn->eeh_freeze_count = 0;
-	pdn->eeh_false_positives = 0;
+	edev->class_code = 0;
+	edev->mode = 0;
+	edev->check_count = 0;
+	edev->freeze_count = 0;
+	edev->false_positives = 0;
 
 	if (!of_device_is_available(dn))
 		return NULL;
@@ -1041,54 +855,56 @@
 
 	/* There is nothing to check on PCI to ISA bridges */
 	if (dn->type && !strcmp(dn->type, "isa")) {
-		pdn->eeh_mode |= EEH_MODE_NOCHECK;
+		edev->mode |= EEH_MODE_NOCHECK;
 		return NULL;
 	}
-	pdn->class_code = *class_code;
+	edev->class_code = *class_code;
 
 	/* Ok... see if this device supports EEH.  Some do, some don't,
-	 * and the only way to find out is to check each and every one. */
+	 * and the only way to find out is to check each and every one.
+	 */
 	regs = of_get_property(dn, "reg", NULL);
 	if (regs) {
 		/* First register entry is addr (00BBSS00)  */
 		/* Try to enable eeh */
-		ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL,
-		                regs[0], info->buid_hi, info->buid_lo,
-		                EEH_ENABLE);
+		ret = eeh_ops->set_option(dn, EEH_OPT_ENABLE);
 
 		enable = 0;
 		if (ret == 0) {
-			pdn->eeh_config_addr = regs[0];
+			edev->config_addr = regs[0];
 
 			/* If the newer, better, ibm,get-config-addr-info is supported, 
-			 * then use that instead. */
-			pdn->eeh_pe_config_addr = get_pe_addr(pdn->eeh_config_addr, info);
+			 * then use that instead.
+			 */
+			edev->pe_config_addr = eeh_ops->get_pe_addr(dn);
 
 			/* Some older systems (Power4) allow the
 			 * ibm,set-eeh-option call to succeed even on nodes
 			 * where EEH is not supported. Verify support
-			 * explicitly. */
-			ret = read_slot_reset_state(pdn, rets);
-			if ((ret == 0) && (rets[1] == 1))
+			 * explicitly.
+			 */
+			ret = eeh_ops->get_state(dn, NULL);
+			if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT)
 				enable = 1;
 		}
 
 		if (enable) {
 			eeh_subsystem_enabled = 1;
-			pdn->eeh_mode |= EEH_MODE_SUPPORTED;
+			edev->mode |= EEH_MODE_SUPPORTED;
 
 			pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n",
-				 dn->full_name, pdn->eeh_config_addr,
-				 pdn->eeh_pe_config_addr);
+				 dn->full_name, edev->config_addr,
+				 edev->pe_config_addr);
 		} else {
 
 			/* This device doesn't support EEH, but it may have an
-			 * EEH parent, in which case we mark it as supported. */
-			if (dn->parent && PCI_DN(dn->parent)
-			    && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) {
+			 * EEH parent, in which case we mark it as supported.
+			 */
+			if (dn->parent && of_node_to_eeh_dev(dn->parent) &&
+			    (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) {
 				/* Parent supports EEH. */
-				pdn->eeh_mode |= EEH_MODE_SUPPORTED;
-				pdn->eeh_config_addr = PCI_DN(dn->parent)->eeh_config_addr;
+				edev->mode |= EEH_MODE_SUPPORTED;
+				edev->config_addr = of_node_to_eeh_dev(dn->parent)->config_addr;
 				return NULL;
 			}
 		}
@@ -1097,11 +913,63 @@
 		       dn->full_name);
 	}
 
-	eeh_save_bars(pdn);
+	eeh_save_bars(edev);
 	return NULL;
 }
 
-/*
+/**
+ * eeh_ops_register - Register platform dependent EEH operations
+ * @ops: platform dependent EEH operations
+ *
+ * Register the platform dependent EEH operation callback
+ * functions. The platform should call this function before
+ * any other EEH operations.
+ */
+int __init eeh_ops_register(struct eeh_ops *ops)
+{
+	if (!ops->name) {
+		pr_warning("%s: Invalid EEH ops name for %p\n",
+			__func__, ops);
+		return -EINVAL;
+	}
+
+	if (eeh_ops && eeh_ops != ops) {
+		pr_warning("%s: EEH ops of platform %s already existing (%s)\n",
+			__func__, eeh_ops->name, ops->name);
+		return -EEXIST;
+	}
+
+	eeh_ops = ops;
+
+	return 0;
+}
+
+/**
+ * eeh_ops_unregister - Unreigster platform dependent EEH operations
+ * @name: name of EEH platform operations
+ *
+ * Unregister the platform dependent EEH operation callback
+ * functions.
+ */
+int __exit eeh_ops_unregister(const char *name)
+{
+	if (!name || !strlen(name)) {
+		pr_warning("%s: Invalid EEH ops name\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (eeh_ops && !strcmp(eeh_ops->name, name)) {
+		eeh_ops = NULL;
+		return 0;
+	}
+
+	return -EEXIST;
+}
+
+/**
+ * eeh_init - EEH initialization
+ *
  * Initialize EEH by trying to enable it for all of the adapters in the system.
  * As a side effect we can determine here if eeh is supported at all.
  * Note that we leave EEH on so failed config cycles won't cause a machine
@@ -1116,51 +984,27 @@
  */
 void __init eeh_init(void)
 {
-	struct device_node *phb, *np;
-	struct eeh_early_enable_info info;
+	struct pci_controller *hose, *tmp;
+	struct device_node *phb;
+	int ret;
+
+	/* call platform initialization function */
+	if (!eeh_ops) {
+		pr_warning("%s: Platform EEH operation not found\n",
+			__func__);
+		return;
+	} else if ((ret = eeh_ops->init())) {
+		pr_warning("%s: Failed to call platform init function (%d)\n",
+			__func__, ret);
+		return;
+	}
 
 	raw_spin_lock_init(&confirm_error_lock);
-	spin_lock_init(&slot_errbuf_lock);
 
-	np = of_find_node_by_path("/rtas");
-	if (np == NULL)
-		return;
-
-	ibm_set_eeh_option = rtas_token("ibm,set-eeh-option");
-	ibm_set_slot_reset = rtas_token("ibm,set-slot-reset");
-	ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2");
-	ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
-	ibm_slot_error_detail = rtas_token("ibm,slot-error-detail");
-	ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info");
-	ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2");
-	ibm_configure_bridge = rtas_token ("ibm,configure-bridge");
-	ibm_configure_pe = rtas_token("ibm,configure-pe");
-
-	if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE)
-		return;
-
-	eeh_error_buf_size = rtas_token("rtas-error-log-max");
-	if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) {
-		eeh_error_buf_size = 1024;
-	}
-	if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {
-		printk(KERN_WARNING "EEH: rtas-error-log-max is bigger than allocated "
-		      "buffer ! (%d vs %d)", eeh_error_buf_size, RTAS_ERROR_LOG_MAX);
-		eeh_error_buf_size = RTAS_ERROR_LOG_MAX;
-	}
-
-	/* Enable EEH for all adapters.  Note that eeh requires buid's */
-	for (phb = of_find_node_by_name(NULL, "pci"); phb;
-	     phb = of_find_node_by_name(phb, "pci")) {
-		unsigned long buid;
-
-		buid = get_phb_buid(phb);
-		if (buid == 0 || PCI_DN(phb) == NULL)
-			continue;
-
-		info.buid_lo = BUID_LO(buid);
-		info.buid_hi = BUID_HI(buid);
-		traverse_pci_devices(phb, early_enable_eeh, &info);
+	/* Enable EEH for all adapters */
+	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+		phb = hose->dn;
+		traverse_pci_devices(phb, eeh_early_enable, NULL);
 	}
 
 	if (eeh_subsystem_enabled)
@@ -1170,7 +1014,7 @@
 }
 
 /**
- * eeh_add_device_early - enable EEH for the indicated device_node
+ * eeh_add_device_early - Enable EEH for the indicated device_node
  * @dn: device node for which to set up EEH
  *
  * This routine must be used to perform EEH initialization for PCI
@@ -1184,21 +1028,26 @@
 static void eeh_add_device_early(struct device_node *dn)
 {
 	struct pci_controller *phb;
-	struct eeh_early_enable_info info;
 
-	if (!dn || !PCI_DN(dn))
+	if (!dn || !of_node_to_eeh_dev(dn))
 		return;
-	phb = PCI_DN(dn)->phb;
+	phb = of_node_to_eeh_dev(dn)->phb;
 
 	/* USB Bus children of PCI devices will not have BUID's */
 	if (NULL == phb || 0 == phb->buid)
 		return;
 
-	info.buid_hi = BUID_HI(phb->buid);
-	info.buid_lo = BUID_LO(phb->buid);
-	early_enable_eeh(dn, &info);
+	eeh_early_enable(dn, NULL);
 }
 
+/**
+ * eeh_add_device_tree_early - Enable EEH for the indicated device
+ * @dn: device node
+ *
+ * This routine must be used to perform EEH initialization for the
+ * indicated PCI device that was added after system boot (e.g.
+ * hotplug, dlpar).
+ */
 void eeh_add_device_tree_early(struct device_node *dn)
 {
 	struct device_node *sib;
@@ -1210,7 +1059,7 @@
 EXPORT_SYMBOL_GPL(eeh_add_device_tree_early);
 
 /**
- * eeh_add_device_late - perform EEH initialization for the indicated pci device
+ * eeh_add_device_late - Perform EEH initialization for the indicated pci device
  * @dev: pci device for which to set up EEH
  *
  * This routine must be used to complete EEH initialization for PCI
@@ -1219,7 +1068,7 @@
 static void eeh_add_device_late(struct pci_dev *dev)
 {
 	struct device_node *dn;
-	struct pci_dn *pdn;
+	struct eeh_dev *edev;
 
 	if (!dev || !eeh_subsystem_enabled)
 		return;
@@ -1227,20 +1076,29 @@
 	pr_debug("EEH: Adding device %s\n", pci_name(dev));
 
 	dn = pci_device_to_OF_node(dev);
-	pdn = PCI_DN(dn);
-	if (pdn->pcidev == dev) {
+	edev = pci_dev_to_eeh_dev(dev);
+	if (edev->pdev == dev) {
 		pr_debug("EEH: Already referenced !\n");
 		return;
 	}
-	WARN_ON(pdn->pcidev);
+	WARN_ON(edev->pdev);
 
-	pci_dev_get (dev);
-	pdn->pcidev = dev;
+	pci_dev_get(dev);
+	edev->pdev = dev;
+	dev->dev.archdata.edev = edev;
 
 	pci_addr_cache_insert_device(dev);
 	eeh_sysfs_add_device(dev);
 }
 
+/**
+ * eeh_add_device_tree_late - Perform EEH initialization for the indicated PCI bus
+ * @bus: PCI bus
+ *
+ * This routine must be used to perform EEH initialization for PCI
+ * devices which are attached to the indicated PCI bus. The PCI bus
+ * is added after system boot through hotplug or dlpar.
+ */
 void eeh_add_device_tree_late(struct pci_bus *bus)
 {
 	struct pci_dev *dev;
@@ -1257,7 +1115,7 @@
 EXPORT_SYMBOL_GPL(eeh_add_device_tree_late);
 
 /**
- * eeh_remove_device - undo EEH setup for the indicated pci device
+ * eeh_remove_device - Undo EEH setup for the indicated pci device
  * @dev: pci device to be removed
  *
  * This routine should be called when a device is removed from
@@ -1268,25 +1126,35 @@
  */
 static void eeh_remove_device(struct pci_dev *dev)
 {
-	struct device_node *dn;
+	struct eeh_dev *edev;
+
 	if (!dev || !eeh_subsystem_enabled)
 		return;
+	edev = pci_dev_to_eeh_dev(dev);
 
 	/* Unregister the device with the EEH/PCI address search system */
 	pr_debug("EEH: Removing device %s\n", pci_name(dev));
 
-	dn = pci_device_to_OF_node(dev);
-	if (PCI_DN(dn)->pcidev == NULL) {
+	if (!edev || !edev->pdev) {
 		pr_debug("EEH: Not referenced !\n");
 		return;
 	}
-	PCI_DN(dn)->pcidev = NULL;
-	pci_dev_put (dev);
+	edev->pdev = NULL;
+	dev->dev.archdata.edev = NULL;
+	pci_dev_put(dev);
 
 	pci_addr_cache_remove_device(dev);
 	eeh_sysfs_remove_device(dev);
 }
 
+/**
+ * eeh_remove_bus_device - Undo EEH setup for the indicated PCI device
+ * @dev: PCI device
+ *
+ * This routine must be called when a device is removed from the
+ * running system through hotplug or dlpar. The corresponding
+ * PCI address cache will be removed.
+ */
 void eeh_remove_bus_device(struct pci_dev *dev)
 {
 	struct pci_bus *bus = dev->subordinate;
@@ -1305,21 +1173,24 @@
 {
 	if (0 == eeh_subsystem_enabled) {
 		seq_printf(m, "EEH Subsystem is globally disabled\n");
-		seq_printf(m, "eeh_total_mmio_ffs=%ld\n", total_mmio_ffs);
+		seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs);
 	} else {
 		seq_printf(m, "EEH Subsystem is enabled\n");
 		seq_printf(m,
-				"no device=%ld\n"
-				"no device node=%ld\n"
-				"no config address=%ld\n"
-				"check not wanted=%ld\n"
-				"eeh_total_mmio_ffs=%ld\n"
-				"eeh_false_positives=%ld\n"
-				"eeh_slot_resets=%ld\n",
-				no_device, no_dn, no_cfg_addr, 
-				ignored_check, total_mmio_ffs, 
-				false_positives,
-				slot_resets);
+				"no device=%llu\n"
+				"no device node=%llu\n"
+				"no config address=%llu\n"
+				"check not wanted=%llu\n"
+				"eeh_total_mmio_ffs=%llu\n"
+				"eeh_false_positives=%llu\n"
+				"eeh_slot_resets=%llu\n",
+				eeh_stats.no_device,
+				eeh_stats.no_dn,
+				eeh_stats.no_cfg_addr,
+				eeh_stats.ignored_check,
+				eeh_stats.total_mmio_ffs,
+				eeh_stats.false_positives,
+				eeh_stats.slot_resets);
 	}
 
 	return 0;
diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c
index fc5ae76..e5ae1c6 100644
--- a/arch/powerpc/platforms/pseries/eeh_cache.c
+++ b/arch/powerpc/platforms/pseries/eeh_cache.c
@@ -1,5 +1,4 @@
 /*
- * eeh_cache.c
  * PCI address cache; allows the lookup of PCI devices based on I/O address
  *
  * Copyright IBM Corporation 2004
@@ -47,8 +46,7 @@
  * than any hash algo I could think of for this problem, even
  * with the penalty of slow pointer chases for d-cache misses).
  */
-struct pci_io_addr_range
-{
+struct pci_io_addr_range {
 	struct rb_node rb_node;
 	unsigned long addr_lo;
 	unsigned long addr_hi;
@@ -56,13 +54,12 @@
 	unsigned int flags;
 };
 
-static struct pci_io_addr_cache
-{
+static struct pci_io_addr_cache {
 	struct rb_root rb_root;
 	spinlock_t piar_lock;
 } pci_io_addr_cache_root;
 
-static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr)
+static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr)
 {
 	struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node;
 
@@ -86,7 +83,7 @@
 }
 
 /**
- * pci_get_device_by_addr - Get device, given only address
+ * pci_addr_cache_get_device - Get device, given only address
  * @addr: mmio (PIO) phys address or i/o port number
  *
  * Given an mmio phys address, or a port number, find a pci device
@@ -95,13 +92,13 @@
  * from zero (that is, they do *not* have pci_io_addr added in).
  * It is safe to call this function within an interrupt.
  */
-struct pci_dev *pci_get_device_by_addr(unsigned long addr)
+struct pci_dev *pci_addr_cache_get_device(unsigned long addr)
 {
 	struct pci_dev *dev;
 	unsigned long flags;
 
 	spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags);
-	dev = __pci_get_device_by_addr(addr);
+	dev = __pci_addr_cache_get_device(addr);
 	spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags);
 	return dev;
 }
@@ -166,7 +163,7 @@
 
 #ifdef DEBUG
 	printk(KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n",
-	                  alo, ahi, pci_name (dev));
+	                  alo, ahi, pci_name(dev));
 #endif
 
 	rb_link_node(&piar->rb_node, parent, p);
@@ -178,7 +175,7 @@
 static void __pci_addr_cache_insert_device(struct pci_dev *dev)
 {
 	struct device_node *dn;
-	struct pci_dn *pdn;
+	struct eeh_dev *edev;
 	int i;
 
 	dn = pci_device_to_OF_node(dev);
@@ -187,13 +184,19 @@
 		return;
 	}
 
+	edev = of_node_to_eeh_dev(dn);
+	if (!edev) {
+		pr_warning("PCI: no EEH dev found for dn=%s\n",
+			dn->full_name);
+		return;
+	}
+
 	/* Skip any devices for which EEH is not enabled. */
-	pdn = PCI_DN(dn);
-	if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) ||
-	    pdn->eeh_mode & EEH_MODE_NOCHECK) {
+	if (!(edev->mode & EEH_MODE_SUPPORTED) ||
+	    edev->mode & EEH_MODE_NOCHECK) {
 #ifdef DEBUG
-		printk(KERN_INFO "PCI: skip building address cache for=%s - %s\n",
-		       pci_name(dev), pdn->node->full_name);
+		pr_info("PCI: skip building address cache for=%s - %s\n",
+			pci_name(dev), dn->full_name);
 #endif
 		return;
 	}
@@ -284,6 +287,7 @@
 void __init pci_addr_cache_build(void)
 {
 	struct device_node *dn;
+	struct eeh_dev *edev;
 	struct pci_dev *dev = NULL;
 
 	spin_lock_init(&pci_io_addr_cache_root.piar_lock);
@@ -294,8 +298,14 @@
 		dn = pci_device_to_OF_node(dev);
 		if (!dn)
 			continue;
+
+		edev = of_node_to_eeh_dev(dn);
+		if (!edev)
+			continue;
+
 		pci_dev_get(dev);  /* matching put is in eeh_remove_device() */
-		PCI_DN(dn)->pcidev = dev;
+		dev->dev.archdata.edev = edev;
+		edev->pdev = dev;
 
 		eeh_sysfs_add_device(dev);
 	}
diff --git a/arch/powerpc/platforms/pseries/eeh_dev.c b/arch/powerpc/platforms/pseries/eeh_dev.c
new file mode 100644
index 0000000..c4507d0
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/eeh_dev.c
@@ -0,0 +1,102 @@
+/*
+ * The file intends to implement dynamic creation of EEH device, which will
+ * be bound with OF node and PCI device simutaneously. The EEH devices would
+ * be foundamental information for EEH core components to work proerly. Besides,
+ * We have to support multiple situations where dynamic creation of EEH device
+ * is required:
+ *
+ * 1) Before PCI emunation starts, we need create EEH devices according to the
+ *    PCI sensitive OF nodes.
+ * 2) When PCI emunation is done, we need do the binding between PCI device and
+ *    the associated EEH device.
+ * 3) DR (Dynamic Reconfiguration) would create PCI sensitive OF node. EEH device
+ *    will be created while PCI sensitive OF node is detected from DR.
+ * 4) PCI hotplug needs redoing the binding between PCI device and EEH device. If
+ *    PHB is newly inserted, we also need create EEH devices accordingly.
+ *
+ * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2012.
+ *
+ * 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/export.h>
+#include <linux/gfp.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+
+/**
+ * eeh_dev_init - Create EEH device according to OF node
+ * @dn: device node
+ * @data: PHB
+ *
+ * It will create EEH device according to the given OF node. The function
+ * might be called by PCI emunation, DR, PHB hotplug.
+ */
+void * __devinit eeh_dev_init(struct device_node *dn, void *data)
+{
+	struct pci_controller *phb = data;
+	struct eeh_dev *edev;
+
+	/* Allocate EEH device */
+	edev = zalloc_maybe_bootmem(sizeof(*edev), GFP_KERNEL);
+	if (!edev) {
+		pr_warning("%s: out of memory\n", __func__);
+		return NULL;
+	}
+
+	/* Associate EEH device with OF node */
+	PCI_DN(dn)->edev = edev;
+	edev->dn  = dn;
+	edev->phb = phb;
+
+	return NULL;
+}
+
+/**
+ * eeh_dev_phb_init_dynamic - Create EEH devices for devices included in PHB
+ * @phb: PHB
+ *
+ * Scan the PHB OF node and its child association, then create the
+ * EEH devices accordingly
+ */
+void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb)
+{
+	struct device_node *dn = phb->dn;
+
+	/* EEH device for PHB */
+	eeh_dev_init(dn, phb);
+
+	/* EEH devices for children OF nodes */
+	traverse_pci_devices(dn, eeh_dev_init, phb);
+}
+
+/**
+ * eeh_dev_phb_init - Create EEH devices for devices included in existing PHBs
+ *
+ * Scan all the existing PHBs and create EEH devices for their OF
+ * nodes and their children OF nodes
+ */
+void __init eeh_dev_phb_init(void)
+{
+	struct pci_controller *phb, *tmp;
+
+	list_for_each_entry_safe(phb, tmp, &hose_list, list_node)
+		eeh_dev_phb_init_dynamic(phb);
+}
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 1b6cb10..baf92cd 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -33,8 +33,14 @@
 #include <asm/prom.h>
 #include <asm/rtas.h>
 
-
-static inline const char * pcid_name (struct pci_dev *pdev)
+/**
+ * eeh_pcid_name - Retrieve name of PCI device driver
+ * @pdev: PCI device
+ *
+ * This routine is used to retrieve the name of PCI device driver
+ * if that's valid.
+ */
+static inline const char *eeh_pcid_name(struct pci_dev *pdev)
 {
 	if (pdev && pdev->dev.driver)
 		return pdev->dev.driver->name;
@@ -64,48 +70,59 @@
 #endif
 
 /**
- * eeh_disable_irq - disable interrupt for the recovering device
+ * eeh_disable_irq - Disable interrupt for the recovering device
+ * @dev: PCI device
+ *
+ * This routine must be called when reporting temporary or permanent
+ * error to the particular PCI device to disable interrupt of that
+ * device. If the device has enabled MSI or MSI-X interrupt, we needn't
+ * do real work because EEH should freeze DMA transfers for those PCI
+ * devices encountering EEH errors, which includes MSI or MSI-X.
  */
 static void eeh_disable_irq(struct pci_dev *dev)
 {
-	struct device_node *dn = pci_device_to_OF_node(dev);
+	struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
 
 	/* Don't disable MSI and MSI-X interrupts. They are
 	 * effectively disabled by the DMA Stopped state
 	 * when an EEH error occurs.
-	*/
+	 */
 	if (dev->msi_enabled || dev->msix_enabled)
 		return;
 
 	if (!irq_has_action(dev->irq))
 		return;
 
-	PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED;
+	edev->mode |= EEH_MODE_IRQ_DISABLED;
 	disable_irq_nosync(dev->irq);
 }
 
 /**
- * eeh_enable_irq - enable interrupt for the recovering device
+ * eeh_enable_irq - Enable interrupt for the recovering device
+ * @dev: PCI device
+ *
+ * This routine must be called to enable interrupt while failed
+ * device could be resumed.
  */
 static void eeh_enable_irq(struct pci_dev *dev)
 {
-	struct device_node *dn = pci_device_to_OF_node(dev);
+	struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
 
-	if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
-		PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
+	if ((edev->mode) & EEH_MODE_IRQ_DISABLED) {
+		edev->mode &= ~EEH_MODE_IRQ_DISABLED;
 		enable_irq(dev->irq);
 	}
 }
 
-/* ------------------------------------------------------- */
 /**
- * eeh_report_error - report pci error to each device driver
+ * eeh_report_error - Report pci error to each device driver
+ * @dev: PCI device
+ * @userdata: return value
  * 
  * Report an EEH error to each device driver, collect up and 
  * merge the device driver responses. Cumulative response 
  * passed back in "userdata".
  */
-
 static int eeh_report_error(struct pci_dev *dev, void *userdata)
 {
 	enum pci_ers_result rc, *res = userdata;
@@ -122,7 +139,7 @@
 	    !driver->err_handler->error_detected)
 		return 0;
 
-	rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen);
+	rc = driver->err_handler->error_detected(dev, pci_channel_io_frozen);
 
 	/* A driver that needs a reset trumps all others */
 	if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
@@ -132,13 +149,14 @@
 }
 
 /**
- * eeh_report_mmio_enabled - tell drivers that MMIO has been enabled
+ * eeh_report_mmio_enabled - Tell drivers that MMIO has been enabled
+ * @dev: PCI device
+ * @userdata: return value
  *
  * Tells each device driver that IO ports, MMIO and config space I/O
  * are now enabled. Collects up and merges the device driver responses.
  * Cumulative response passed back in "userdata".
  */
-
 static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
 {
 	enum pci_ers_result rc, *res = userdata;
@@ -149,7 +167,7 @@
 	    !driver->err_handler->mmio_enabled)
 		return 0;
 
-	rc = driver->err_handler->mmio_enabled (dev);
+	rc = driver->err_handler->mmio_enabled(dev);
 
 	/* A driver that needs a reset trumps all others */
 	if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
@@ -159,9 +177,15 @@
 }
 
 /**
- * eeh_report_reset - tell device that slot has been reset
+ * eeh_report_reset - Tell device that slot has been reset
+ * @dev: PCI device
+ * @userdata: return value
+ *
+ * This routine must be called while EEH tries to reset particular
+ * PCI device so that the associated PCI device driver could take
+ * some actions, usually to save data the driver needs so that the
+ * driver can work again while the device is recovered.
  */
-
 static int eeh_report_reset(struct pci_dev *dev, void *userdata)
 {
 	enum pci_ers_result rc, *res = userdata;
@@ -188,9 +212,14 @@
 }
 
 /**
- * eeh_report_resume - tell device to resume normal operations
+ * eeh_report_resume - Tell device to resume normal operations
+ * @dev: PCI device
+ * @userdata: return value
+ *
+ * This routine must be called to notify the device driver that it
+ * could resume so that the device driver can do some initialization
+ * to make the recovered device work again.
  */
-
 static int eeh_report_resume(struct pci_dev *dev, void *userdata)
 {
 	struct pci_driver *driver = dev->driver;
@@ -212,12 +241,13 @@
 }
 
 /**
- * eeh_report_failure - tell device driver that device is dead.
+ * eeh_report_failure - Tell device driver that device is dead.
+ * @dev: PCI device
+ * @userdata: return value
  *
  * This informs the device driver that the device is permanently
  * dead, and that no further recovery attempts will be made on it.
  */
-
 static int eeh_report_failure(struct pci_dev *dev, void *userdata)
 {
 	struct pci_driver *driver = dev->driver;
@@ -238,65 +268,46 @@
 	return 0;
 }
 
-/* ------------------------------------------------------- */
 /**
- * handle_eeh_events -- reset a PCI device after hard lockup.
+ * eeh_reset_device - Perform actual reset of a pci slot
+ * @edev: PE associated EEH device
+ * @bus: PCI bus corresponding to the isolcated slot
  *
- * pSeries systems will isolate a PCI slot if the PCI-Host
- * bridge detects address or data parity errors, DMA's
- * occurring to wild addresses (which usually happen due to
- * bugs in device drivers or in PCI adapter firmware).
- * Slot isolations also occur if #SERR, #PERR or other misc
- * PCI-related errors are detected.
- *
- * Recovery process consists of unplugging the device driver
- * (which generated hotplug events to userspace), then issuing
- * a PCI #RST to the device, then reconfiguring the PCI config
- * space for all bridges & devices under this slot, and then
- * finally restarting the device drivers (which cause a second
- * set of hotplug events to go out to userspace).
+ * This routine must be called to do reset on the indicated PE.
+ * During the reset, udev might be invoked because those affected
+ * PCI devices will be removed and then added.
  */
-
-/**
- * eeh_reset_device() -- perform actual reset of a pci slot
- * @bus: pointer to the pci bus structure corresponding
- *            to the isolated slot. A non-null value will
- *            cause all devices under the bus to be removed
- *            and then re-added.
- * @pe_dn: pointer to a "Partionable Endpoint" device node.
- *            This is the top-level structure on which pci
- *            bus resets can be performed.
- */
-
-static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
+static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus)
 {
 	struct device_node *dn;
 	int cnt, rc;
 
 	/* pcibios will clear the counter; save the value */
-	cnt = pe_dn->eeh_freeze_count;
+	cnt = edev->freeze_count;
 
 	if (bus)
 		pcibios_remove_pci_devices(bus);
 
 	/* Reset the pci controller. (Asserts RST#; resets config space).
 	 * Reconfigure bridges and devices. Don't try to bring the system
-	 * up if the reset failed for some reason. */
-	rc = rtas_set_slot_reset(pe_dn);
+	 * up if the reset failed for some reason.
+	 */
+	rc = eeh_reset_pe(edev);
 	if (rc)
 		return rc;
 
-	/* Walk over all functions on this device.  */
-	dn = pe_dn->node;
-	if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
+	/* Walk over all functions on this device. */
+	dn = eeh_dev_to_of_node(edev);
+	if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent))
 		dn = dn->parent->child;
 
 	while (dn) {
-		struct pci_dn *ppe = PCI_DN(dn);
+		struct eeh_dev *pedev = of_node_to_eeh_dev(dn);
+
 		/* On Power4, always true because eeh_pe_config_addr=0 */
-		if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) {
-			rtas_configure_bridge(ppe);
-			eeh_restore_bars(ppe);
+		if (edev->pe_config_addr == pedev->pe_config_addr) {
+			eeh_ops->configure_bridge(dn);
+			eeh_restore_bars(pedev);
  		}
 		dn = dn->sibling;
 	}
@@ -308,10 +319,10 @@
 	 * potentially weird things happen.
 	 */
 	if (bus) {
-		ssleep (5);
+		ssleep(5);
 		pcibios_add_pci_devices(bus);
 	}
-	pe_dn->eeh_freeze_count = cnt;
+	edev->freeze_count = cnt;
 
 	return 0;
 }
@@ -321,23 +332,39 @@
  */
 #define MAX_WAIT_FOR_RECOVERY 150
 
-struct pci_dn * handle_eeh_events (struct eeh_event *event)
+/**
+ * eeh_handle_event - Reset a PCI device after hard lockup.
+ * @event: EEH event
+ *
+ * While PHB detects address or data parity errors on particular PCI
+ * slot, the associated PE will be frozen. Besides, DMA's occurring
+ * to wild addresses (which usually happen due to bugs in device
+ * drivers or in PCI adapter firmware) can cause EEH error. #SERR,
+ * #PERR or other misc PCI-related errors also can trigger EEH errors.
+ *
+ * Recovery process consists of unplugging the device driver (which
+ * generated hotplug events to userspace), then issuing a PCI #RST to
+ * the device, then reconfiguring the PCI config space for all bridges
+ * & devices under this slot, and then finally restarting the device
+ * drivers (which cause a second set of hotplug events to go out to
+ * userspace).
+ */
+struct eeh_dev *handle_eeh_events(struct eeh_event *event)
 {
 	struct device_node *frozen_dn;
-	struct pci_dn *frozen_pdn;
+	struct eeh_dev *frozen_edev;
 	struct pci_bus *frozen_bus;
 	int rc = 0;
 	enum pci_ers_result result = PCI_ERS_RESULT_NONE;
 	const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str;
 
-	frozen_dn = find_device_pe(event->dn);
+	frozen_dn = eeh_find_device_pe(eeh_dev_to_of_node(event->edev));
 	if (!frozen_dn) {
-
-		location = of_get_property(event->dn, "ibm,loc-code", NULL);
+		location = of_get_property(eeh_dev_to_of_node(event->edev), "ibm,loc-code", NULL);
 		location = location ? location : "unknown";
 		printk(KERN_ERR "EEH: Error: Cannot find partition endpoint "
 		                "for location=%s pci addr=%s\n",
-		        location, eeh_pci_name(event->dev));
+			location, eeh_pci_name(eeh_dev_to_pci_dev(event->edev)));
 		return NULL;
 	}
 
@@ -350,9 +377,10 @@
 	 * which was always an EADS pci bridge.  In the new style,
 	 * there might not be any EADS bridges, and even when there are,
 	 * the firmware marks them as "EEH incapable". So another
-	 * two-step is needed to find the pci bus.. */
+	 * two-step is needed to find the pci bus..
+	 */
 	if (!frozen_bus)
-		frozen_bus = pcibios_find_pci_bus (frozen_dn->parent);
+		frozen_bus = pcibios_find_pci_bus(frozen_dn->parent);
 
 	if (!frozen_bus) {
 		printk(KERN_ERR "EEH: Cannot find PCI bus "
@@ -361,22 +389,21 @@
 		return NULL;
 	}
 
-	frozen_pdn = PCI_DN(frozen_dn);
-	frozen_pdn->eeh_freeze_count++;
+	frozen_edev = of_node_to_eeh_dev(frozen_dn);
+	frozen_edev->freeze_count++;
+	pci_str = eeh_pci_name(eeh_dev_to_pci_dev(event->edev));
+	drv_str = eeh_pcid_name(eeh_dev_to_pci_dev(event->edev));
 
-	pci_str = eeh_pci_name(event->dev);
-	drv_str = pcid_name(event->dev);
-	
-	if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES)
+	if (frozen_edev->freeze_count > EEH_MAX_ALLOWED_FREEZES)
 		goto excess_failures;
 
 	printk(KERN_WARNING
 	   "EEH: This PCI device has failed %d times in the last hour:\n",
-		frozen_pdn->eeh_freeze_count);
+		frozen_edev->freeze_count);
 
-	if (frozen_pdn->pcidev) {
-		bus_pci_str = pci_name(frozen_pdn->pcidev);
-		bus_drv_str = pcid_name(frozen_pdn->pcidev);
+	if (frozen_edev->pdev) {
+		bus_pci_str = pci_name(frozen_edev->pdev);
+		bus_drv_str = eeh_pcid_name(frozen_edev->pdev);
 		printk(KERN_WARNING
 			"EEH: Bus location=%s driver=%s pci addr=%s\n",
 			location, bus_drv_str, bus_pci_str);
@@ -395,9 +422,10 @@
 	pci_walk_bus(frozen_bus, eeh_report_error, &result);
 
 	/* Get the current PCI slot state. This can take a long time,
-	 * sometimes over 3 seconds for certain systems. */
-	rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000);
-	if (rc < 0) {
+	 * sometimes over 3 seconds for certain systems.
+	 */
+	rc = eeh_ops->wait_state(eeh_dev_to_of_node(frozen_edev), MAX_WAIT_FOR_RECOVERY*1000);
+	if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) {
 		printk(KERN_WARNING "EEH: Permanent failure\n");
 		goto hard_fail;
 	}
@@ -406,14 +434,14 @@
 	 * don't post the error log until after all dev drivers
 	 * have been informed.
 	 */
-	eeh_slot_error_detail(frozen_pdn, EEH_LOG_TEMP_FAILURE);
+	eeh_slot_error_detail(frozen_edev, EEH_LOG_TEMP);
 
 	/* If all device drivers were EEH-unaware, then shut
 	 * down all of the device drivers, and hope they
 	 * go down willingly, without panicing the system.
 	 */
 	if (result == PCI_ERS_RESULT_NONE) {
-		rc = eeh_reset_device(frozen_pdn, frozen_bus);
+		rc = eeh_reset_device(frozen_edev, frozen_bus);
 		if (rc) {
 			printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc);
 			goto hard_fail;
@@ -422,7 +450,7 @@
 
 	/* If all devices reported they can proceed, then re-enable MMIO */
 	if (result == PCI_ERS_RESULT_CAN_RECOVER) {
-		rc = rtas_pci_enable(frozen_pdn, EEH_THAW_MMIO);
+		rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_MMIO);
 
 		if (rc < 0)
 			goto hard_fail;
@@ -436,7 +464,7 @@
 
 	/* If all devices reported they can proceed, then re-enable DMA */
 	if (result == PCI_ERS_RESULT_CAN_RECOVER) {
-		rc = rtas_pci_enable(frozen_pdn, EEH_THAW_DMA);
+		rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_DMA);
 
 		if (rc < 0)
 			goto hard_fail;
@@ -454,7 +482,7 @@
 
 	/* If any device called out for a reset, then reset the slot */
 	if (result == PCI_ERS_RESULT_NEED_RESET) {
-		rc = eeh_reset_device(frozen_pdn, NULL);
+		rc = eeh_reset_device(frozen_edev, NULL);
 		if (rc) {
 			printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc);
 			goto hard_fail;
@@ -473,7 +501,7 @@
 	/* Tell all device drivers that they can resume operations */
 	pci_walk_bus(frozen_bus, eeh_report_resume, NULL);
 
-	return frozen_pdn;
+	return frozen_edev;
 	
 excess_failures:
 	/*
@@ -486,7 +514,7 @@
 		"has failed %d times in the last hour "
 		"and has been permanently disabled.\n"
 		"Please try reseating this device or replacing it.\n",
-		location, drv_str, pci_str, frozen_pdn->eeh_freeze_count);
+		location, drv_str, pci_str, frozen_edev->freeze_count);
 	goto perm_error;
 
 hard_fail:
@@ -497,7 +525,7 @@
 		location, drv_str, pci_str);
 
 perm_error:
-	eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM_FAILURE);
+	eeh_slot_error_detail(frozen_edev, EEH_LOG_PERM);
 
 	/* Notify all devices that they're about to go down. */
 	pci_walk_bus(frozen_bus, eeh_report_failure, NULL);
@@ -508,4 +536,3 @@
 	return NULL;
 }
 
-/* ---------- end of file ---------- */
diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c
index d2383cf..4cb375c 100644
--- a/arch/powerpc/platforms/pseries/eeh_event.c
+++ b/arch/powerpc/platforms/pseries/eeh_event.c
@@ -1,6 +1,4 @@
 /*
- * eeh_event.c
- *
  * 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
@@ -46,7 +44,7 @@
 DEFINE_MUTEX(eeh_event_mutex);
 
 /**
- * eeh_event_handler - dispatch EEH events.
+ * eeh_event_handler - Dispatch EEH events.
  * @dummy - unused
  *
  * The detection of a frozen slot can occur inside an interrupt,
@@ -58,11 +56,10 @@
 static int eeh_event_handler(void * dummy)
 {
 	unsigned long flags;
-	struct eeh_event	*event;
-	struct pci_dn *pdn;
+	struct eeh_event *event;
+	struct eeh_dev *edev;
 
-	daemonize ("eehd");
-	set_current_state(TASK_INTERRUPTIBLE);
+	set_task_comm(current, "eehd");
 
 	spin_lock_irqsave(&eeh_eventlist_lock, flags);
 	event = NULL;
@@ -79,31 +76,38 @@
 
 	/* Serialize processing of EEH events */
 	mutex_lock(&eeh_event_mutex);
-	eeh_mark_slot(event->dn, EEH_MODE_RECOVERING);
+	edev = event->edev;
+	eeh_mark_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING);
 
 	printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n",
-	       eeh_pci_name(event->dev));
+	       eeh_pci_name(edev->pdev));
 
-	pdn = handle_eeh_events(event);
+	set_current_state(TASK_INTERRUPTIBLE);	/* Don't add to load average */
+	edev = handle_eeh_events(event);
 
-	eeh_clear_slot(event->dn, EEH_MODE_RECOVERING);
-	pci_dev_put(event->dev);
+	eeh_clear_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING);
+	pci_dev_put(edev->pdev);
+
 	kfree(event);
 	mutex_unlock(&eeh_event_mutex);
 
 	/* If there are no new errors after an hour, clear the counter. */
-	if (pdn && pdn->eeh_freeze_count>0) {
-		msleep_interruptible (3600*1000);
-		if (pdn->eeh_freeze_count>0)
-			pdn->eeh_freeze_count--;
+	if (edev && edev->freeze_count>0) {
+		msleep_interruptible(3600*1000);
+		if (edev->freeze_count>0)
+			edev->freeze_count--;
+
 	}
 
 	return 0;
 }
 
 /**
- * eeh_thread_launcher
+ * eeh_thread_launcher - Start kernel thread to handle EEH events
  * @dummy - unused
+ *
+ * This routine is called to start the kernel thread for processing
+ * EEH event.
  */
 static void eeh_thread_launcher(struct work_struct *dummy)
 {
@@ -112,18 +116,18 @@
 }
 
 /**
- * eeh_send_failure_event - generate a PCI error event
- * @dev pci device
+ * eeh_send_failure_event - Generate a PCI error event
+ * @edev: EEH device
  *
  * This routine can be called within an interrupt context;
  * the actual event will be delivered in a normal context
  * (from a workqueue).
  */
-int eeh_send_failure_event (struct device_node *dn,
-                            struct pci_dev *dev)
+int eeh_send_failure_event(struct eeh_dev *edev)
 {
 	unsigned long flags;
 	struct eeh_event *event;
+	struct device_node *dn = eeh_dev_to_of_node(edev);
 	const char *location;
 
 	if (!mem_init_done) {
@@ -135,15 +139,14 @@
 	}
 	event = kmalloc(sizeof(*event), GFP_ATOMIC);
 	if (event == NULL) {
-		printk (KERN_ERR "EEH: out of memory, event not handled\n");
+		printk(KERN_ERR "EEH: out of memory, event not handled\n");
 		return 1;
  	}
 
-	if (dev)
-		pci_dev_get(dev);
+	if (edev->pdev)
+		pci_dev_get(edev->pdev);
 
-	event->dn = dn;
-	event->dev = dev;
+	event->edev = edev;
 
 	/* We may or may not be called in an interrupt context */
 	spin_lock_irqsave(&eeh_eventlist_lock, flags);
@@ -154,5 +157,3 @@
 
 	return 0;
 }
-
-/********************** END OF FILE ******************************/
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
new file mode 100644
index 0000000..8752f79
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -0,0 +1,565 @@
+/*
+ * The file intends to implement the platform dependent EEH operations on pseries.
+ * Actually, the pseries platform is built based on RTAS heavily. That means the
+ * pseries platform dependent EEH operations will be built on RTAS calls. The functions
+ * are devired from arch/powerpc/platforms/pseries/eeh.c and necessary cleanup has
+ * been done.
+ *
+ * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2011.
+ * Copyright IBM Corporation 2001, 2005, 2006
+ * Copyright Dave Engebretsen & Todd Inglett 2001
+ * Copyright Linas Vepstas 2005, 2006
+ *
+ * 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/atomic.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/of.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/rbtree.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/spinlock.h>
+
+#include <asm/eeh.h>
+#include <asm/eeh_event.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ppc-pci.h>
+#include <asm/rtas.h>
+
+/* RTAS tokens */
+static int ibm_set_eeh_option;
+static int ibm_set_slot_reset;
+static int ibm_read_slot_reset_state;
+static int ibm_read_slot_reset_state2;
+static int ibm_slot_error_detail;
+static int ibm_get_config_addr_info;
+static int ibm_get_config_addr_info2;
+static int ibm_configure_bridge;
+static int ibm_configure_pe;
+
+/*
+ * Buffer for reporting slot-error-detail rtas calls. Its here
+ * in BSS, and not dynamically alloced, so that it ends up in
+ * RMO where RTAS can access it.
+ */
+static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX];
+static DEFINE_SPINLOCK(slot_errbuf_lock);
+static int eeh_error_buf_size;
+
+/**
+ * pseries_eeh_init - EEH platform dependent initialization
+ *
+ * EEH platform dependent initialization on pseries.
+ */
+static int pseries_eeh_init(void)
+{
+	/* figure out EEH RTAS function call tokens */
+	ibm_set_eeh_option		= rtas_token("ibm,set-eeh-option");
+	ibm_set_slot_reset		= rtas_token("ibm,set-slot-reset");
+	ibm_read_slot_reset_state2	= rtas_token("ibm,read-slot-reset-state2");
+	ibm_read_slot_reset_state	= rtas_token("ibm,read-slot-reset-state");
+	ibm_slot_error_detail		= rtas_token("ibm,slot-error-detail");
+	ibm_get_config_addr_info2	= rtas_token("ibm,get-config-addr-info2");
+	ibm_get_config_addr_info	= rtas_token("ibm,get-config-addr-info");
+	ibm_configure_pe		= rtas_token("ibm,configure-pe");
+	ibm_configure_bridge		= rtas_token ("ibm,configure-bridge");
+
+	/* necessary sanity check */
+	if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) {
+		pr_warning("%s: RTAS service <ibm,set-eeh-option> invalid\n",
+			__func__);
+		return -EINVAL;
+	} else if (ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE) {
+		pr_warning("%s: RTAS service <ibm, set-slot-reset> invalid\n",
+			__func__);
+		return -EINVAL;
+	} else if (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE &&
+		   ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) {
+		pr_warning("%s: RTAS service <ibm,read-slot-reset-state2> and "
+			"<ibm,read-slot-reset-state> invalid\n",
+			__func__);
+		return -EINVAL;
+	} else if (ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE) {
+		pr_warning("%s: RTAS service <ibm,slot-error-detail> invalid\n",
+			__func__);
+		return -EINVAL;
+	} else if (ibm_get_config_addr_info2 == RTAS_UNKNOWN_SERVICE &&
+		   ibm_get_config_addr_info == RTAS_UNKNOWN_SERVICE) {
+		pr_warning("%s: RTAS service <ibm,get-config-addr-info2> and "
+			"<ibm,get-config-addr-info> invalid\n",
+			__func__);
+		return -EINVAL;
+	} else if (ibm_configure_pe == RTAS_UNKNOWN_SERVICE &&
+		   ibm_configure_bridge == RTAS_UNKNOWN_SERVICE) {
+		pr_warning("%s: RTAS service <ibm,configure-pe> and "
+			"<ibm,configure-bridge> invalid\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	/* Initialize error log lock and size */
+	spin_lock_init(&slot_errbuf_lock);
+	eeh_error_buf_size = rtas_token("rtas-error-log-max");
+	if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) {
+		pr_warning("%s: unknown EEH error log size\n",
+			__func__);
+		eeh_error_buf_size = 1024;
+	} else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {
+		pr_warning("%s: EEH error log size %d exceeds the maximal %d\n",
+			__func__, eeh_error_buf_size, RTAS_ERROR_LOG_MAX);
+		eeh_error_buf_size = RTAS_ERROR_LOG_MAX;
+	}
+
+	return 0;
+}
+
+/**
+ * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable
+ * @dn: device node
+ * @option: operation to be issued
+ *
+ * The function is used to control the EEH functionality globally.
+ * Currently, following options are support according to PAPR:
+ * Enable EEH, Disable EEH, Enable MMIO and Enable DMA
+ */
+static int pseries_eeh_set_option(struct device_node *dn, int option)
+{
+	int ret = 0;
+	struct eeh_dev *edev;
+	const u32 *reg;
+	int config_addr;
+
+	edev = of_node_to_eeh_dev(dn);
+
+	/*
+	 * When we're enabling or disabling EEH functioality on
+	 * the particular PE, the PE config address is possibly
+	 * unavailable. Therefore, we have to figure it out from
+	 * the FDT node.
+	 */
+	switch (option) {
+	case EEH_OPT_DISABLE:
+	case EEH_OPT_ENABLE:
+		reg = of_get_property(dn, "reg", NULL);
+		config_addr = reg[0];
+		break;
+
+	case EEH_OPT_THAW_MMIO:
+	case EEH_OPT_THAW_DMA:
+		config_addr = edev->config_addr;
+		if (edev->pe_config_addr)
+			config_addr = edev->pe_config_addr;
+		break;
+
+	default:
+		pr_err("%s: Invalid option %d\n",
+			__func__, option);
+		return -EINVAL;
+	}
+
+	ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL,
+			config_addr, BUID_HI(edev->phb->buid),
+			BUID_LO(edev->phb->buid), option);
+
+	return ret;
+}
+
+/**
+ * pseries_eeh_get_pe_addr - Retrieve PE address
+ * @dn: device node
+ *
+ * Retrieve the assocated PE address. Actually, there're 2 RTAS
+ * function calls dedicated for the purpose. We need implement
+ * it through the new function and then the old one. Besides,
+ * you should make sure the config address is figured out from
+ * FDT node before calling the function.
+ *
+ * It's notable that zero'ed return value means invalid PE config
+ * address.
+ */
+static int pseries_eeh_get_pe_addr(struct device_node *dn)
+{
+	struct eeh_dev *edev;
+	int ret = 0;
+	int rets[3];
+
+	edev = of_node_to_eeh_dev(dn);
+
+	if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) {
+		/*
+		 * First of all, we need to make sure there has one PE
+		 * associated with the device. Otherwise, PE address is
+		 * meaningless.
+		 */
+		ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets,
+				edev->config_addr, BUID_HI(edev->phb->buid),
+				BUID_LO(edev->phb->buid), 1);
+		if (ret || (rets[0] == 0))
+			return 0;
+
+		/* Retrieve the associated PE config address */
+		ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets,
+				edev->config_addr, BUID_HI(edev->phb->buid),
+				BUID_LO(edev->phb->buid), 0);
+		if (ret) {
+			pr_warning("%s: Failed to get PE address for %s\n",
+				__func__, dn->full_name);
+			return 0;
+		}
+
+		return rets[0];
+	}
+
+	if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
+		ret = rtas_call(ibm_get_config_addr_info, 4, 2, rets,
+				edev->config_addr, BUID_HI(edev->phb->buid),
+				BUID_LO(edev->phb->buid), 0);
+		if (ret) {
+			pr_warning("%s: Failed to get PE address for %s\n",
+				__func__, dn->full_name);
+			return 0;
+		}
+
+		return rets[0];
+	}
+
+	return ret;
+}
+
+/**
+ * pseries_eeh_get_state - Retrieve PE state
+ * @dn: PE associated device node
+ * @state: return value
+ *
+ * Retrieve the state of the specified PE. On RTAS compliant
+ * pseries platform, there already has one dedicated RTAS function
+ * for the purpose. It's notable that the associated PE config address
+ * might be ready when calling the function. Therefore, endeavour to
+ * use the PE config address if possible. Further more, there're 2
+ * RTAS calls for the purpose, we need to try the new one and back
+ * to the old one if the new one couldn't work properly.
+ */
+static int pseries_eeh_get_state(struct device_node *dn, int *state)
+{
+	struct eeh_dev *edev;
+	int config_addr;
+	int ret;
+	int rets[4];
+	int result;
+
+	/* Figure out PE config address if possible */
+	edev = of_node_to_eeh_dev(dn);
+	config_addr = edev->config_addr;
+	if (edev->pe_config_addr)
+		config_addr = edev->pe_config_addr;
+
+	if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) {
+		ret = rtas_call(ibm_read_slot_reset_state2, 3, 4, rets,
+				config_addr, BUID_HI(edev->phb->buid),
+				BUID_LO(edev->phb->buid));
+	} else if (ibm_read_slot_reset_state != RTAS_UNKNOWN_SERVICE) {
+		/* Fake PE unavailable info */
+		rets[2] = 0;
+		ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
+				config_addr, BUID_HI(edev->phb->buid),
+				BUID_LO(edev->phb->buid));
+	} else {
+		return EEH_STATE_NOT_SUPPORT;
+	}
+
+	if (ret)
+		return ret;
+
+	/* Parse the result out */
+	result = 0;
+	if (rets[1]) {
+		switch(rets[0]) {
+		case 0:
+			result &= ~EEH_STATE_RESET_ACTIVE;
+			result |= EEH_STATE_MMIO_ACTIVE;
+			result |= EEH_STATE_DMA_ACTIVE;
+			break;
+		case 1:
+			result |= EEH_STATE_RESET_ACTIVE;
+			result |= EEH_STATE_MMIO_ACTIVE;
+			result |= EEH_STATE_DMA_ACTIVE;
+			break;
+		case 2:
+			result &= ~EEH_STATE_RESET_ACTIVE;
+			result &= ~EEH_STATE_MMIO_ACTIVE;
+			result &= ~EEH_STATE_DMA_ACTIVE;
+			break;
+		case 4:
+			result &= ~EEH_STATE_RESET_ACTIVE;
+			result &= ~EEH_STATE_MMIO_ACTIVE;
+			result &= ~EEH_STATE_DMA_ACTIVE;
+			result |= EEH_STATE_MMIO_ENABLED;
+			break;
+		case 5:
+			if (rets[2]) {
+				if (state) *state = rets[2];
+				result = EEH_STATE_UNAVAILABLE;
+			} else {
+				result = EEH_STATE_NOT_SUPPORT;
+			}
+		default:
+			result = EEH_STATE_NOT_SUPPORT;
+		}
+	} else {
+		result = EEH_STATE_NOT_SUPPORT;
+	}
+
+	return result;
+}
+
+/**
+ * pseries_eeh_reset - Reset the specified PE
+ * @dn: PE associated device node
+ * @option: reset option
+ *
+ * Reset the specified PE
+ */
+static int pseries_eeh_reset(struct device_node *dn, int option)
+{
+	struct eeh_dev *edev;
+	int config_addr;
+	int ret;
+
+	/* Figure out PE address */
+	edev = of_node_to_eeh_dev(dn);
+	config_addr = edev->config_addr;
+	if (edev->pe_config_addr)
+		config_addr = edev->pe_config_addr;
+
+	/* Reset PE through RTAS call */
+	ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL,
+			config_addr, BUID_HI(edev->phb->buid),
+			BUID_LO(edev->phb->buid), option);
+
+	/* If fundamental-reset not supported, try hot-reset */
+	if (option == EEH_RESET_FUNDAMENTAL &&
+	    ret == -8) {
+		ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL,
+				config_addr, BUID_HI(edev->phb->buid),
+				BUID_LO(edev->phb->buid), EEH_RESET_HOT);
+	}
+
+	return ret;
+}
+
+/**
+ * pseries_eeh_wait_state - Wait for PE state
+ * @dn: PE associated device node
+ * @max_wait: maximal period in microsecond
+ *
+ * Wait for the state of associated PE. It might take some time
+ * to retrieve the PE's state.
+ */
+static int pseries_eeh_wait_state(struct device_node *dn, int max_wait)
+{
+	int ret;
+	int mwait;
+
+	/*
+	 * According to PAPR, the state of PE might be temporarily
+	 * unavailable. Under the circumstance, we have to wait
+	 * for indicated time determined by firmware. The maximal
+	 * wait time is 5 minutes, which is acquired from the original
+	 * EEH implementation. Also, the original implementation
+	 * also defined the minimal wait time as 1 second.
+	 */
+#define EEH_STATE_MIN_WAIT_TIME	(1000)
+#define EEH_STATE_MAX_WAIT_TIME	(300 * 1000)
+
+	while (1) {
+		ret = pseries_eeh_get_state(dn, &mwait);
+
+		/*
+		 * If the PE's state is temporarily unavailable,
+		 * we have to wait for the specified time. Otherwise,
+		 * the PE's state will be returned immediately.
+		 */
+		if (ret != EEH_STATE_UNAVAILABLE)
+			return ret;
+
+		if (max_wait <= 0) {
+			pr_warning("%s: Timeout when getting PE's state (%d)\n",
+				__func__, max_wait);
+			return EEH_STATE_NOT_SUPPORT;
+		}
+
+		if (mwait <= 0) {
+			pr_warning("%s: Firmware returned bad wait value %d\n",
+				__func__, mwait);
+			mwait = EEH_STATE_MIN_WAIT_TIME;
+		} else if (mwait > EEH_STATE_MAX_WAIT_TIME) {
+			pr_warning("%s: Firmware returned too long wait value %d\n",
+				__func__, mwait);
+			mwait = EEH_STATE_MAX_WAIT_TIME;
+		}
+
+		max_wait -= mwait;
+		msleep(mwait);
+	}
+
+	return EEH_STATE_NOT_SUPPORT;
+}
+
+/**
+ * pseries_eeh_get_log - Retrieve error log
+ * @dn: device node
+ * @severity: temporary or permanent error log
+ * @drv_log: driver log to be combined with retrieved error log
+ * @len: length of driver log
+ *
+ * Retrieve the temporary or permanent error from the PE.
+ * Actually, the error will be retrieved through the dedicated
+ * RTAS call.
+ */
+static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_log, unsigned long len)
+{
+	struct eeh_dev *edev;
+	int config_addr;
+	unsigned long flags;
+	int ret;
+
+	edev = of_node_to_eeh_dev(dn);
+	spin_lock_irqsave(&slot_errbuf_lock, flags);
+	memset(slot_errbuf, 0, eeh_error_buf_size);
+
+	/* Figure out the PE address */
+	config_addr = edev->config_addr;
+	if (edev->pe_config_addr)
+		config_addr = edev->pe_config_addr;
+
+	ret = rtas_call(ibm_slot_error_detail, 8, 1, NULL, config_addr,
+			BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid),
+			virt_to_phys(drv_log), len,
+			virt_to_phys(slot_errbuf), eeh_error_buf_size,
+			severity);
+	if (!ret)
+		log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0);
+	spin_unlock_irqrestore(&slot_errbuf_lock, flags);
+
+	return ret;
+}
+
+/**
+ * pseries_eeh_configure_bridge - Configure PCI bridges in the indicated PE
+ * @dn: PE associated device node
+ *
+ * The function will be called to reconfigure the bridges included
+ * in the specified PE so that the mulfunctional PE would be recovered
+ * again.
+ */
+static int pseries_eeh_configure_bridge(struct device_node *dn)
+{
+	struct eeh_dev *edev;
+	int config_addr;
+	int ret;
+
+	/* Figure out the PE address */
+	edev = of_node_to_eeh_dev(dn);
+	config_addr = edev->config_addr;
+	if (edev->pe_config_addr)
+		config_addr = edev->pe_config_addr;
+
+	/* Use new configure-pe function, if supported */
+	if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) {
+		ret = rtas_call(ibm_configure_pe, 3, 1, NULL,
+				config_addr, BUID_HI(edev->phb->buid),
+				BUID_LO(edev->phb->buid));
+	} else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) {
+		ret = rtas_call(ibm_configure_bridge, 3, 1, NULL,
+				config_addr, BUID_HI(edev->phb->buid),
+				BUID_LO(edev->phb->buid));
+	} else {
+		return -EFAULT;
+	}
+
+	if (ret)
+		pr_warning("%s: Unable to configure bridge %d for %s\n",
+			__func__, ret, dn->full_name);
+
+	return ret;
+}
+
+/**
+ * pseries_eeh_read_config - Read PCI config space
+ * @dn: device node
+ * @where: PCI address
+ * @size: size to read
+ * @val: return value
+ *
+ * Read config space from the speicifed device
+ */
+static int pseries_eeh_read_config(struct device_node *dn, int where, int size, u32 *val)
+{
+	struct pci_dn *pdn;
+
+	pdn = PCI_DN(dn);
+
+	return rtas_read_config(pdn, where, size, val);
+}
+
+/**
+ * pseries_eeh_write_config - Write PCI config space
+ * @dn: device node
+ * @where: PCI address
+ * @size: size to write
+ * @val: value to be written
+ *
+ * Write config space to the specified device
+ */
+static int pseries_eeh_write_config(struct device_node *dn, int where, int size, u32 val)
+{
+	struct pci_dn *pdn;
+
+	pdn = PCI_DN(dn);
+
+	return rtas_write_config(pdn, where, size, val);
+}
+
+static struct eeh_ops pseries_eeh_ops = {
+	.name			= "pseries",
+	.init			= pseries_eeh_init,
+	.set_option		= pseries_eeh_set_option,
+	.get_pe_addr		= pseries_eeh_get_pe_addr,
+	.get_state		= pseries_eeh_get_state,
+	.reset			= pseries_eeh_reset,
+	.wait_state		= pseries_eeh_wait_state,
+	.get_log		= pseries_eeh_get_log,
+	.configure_bridge       = pseries_eeh_configure_bridge,
+	.read_config		= pseries_eeh_read_config,
+	.write_config		= pseries_eeh_write_config
+};
+
+/**
+ * eeh_pseries_init - Register platform dependent EEH operations
+ *
+ * EEH initialization on pseries platform. This function should be
+ * called before any EEH related functions.
+ */
+int __init eeh_pseries_init(void)
+{
+	return eeh_ops_register(&pseries_eeh_ops);
+}
diff --git a/arch/powerpc/platforms/pseries/eeh_sysfs.c b/arch/powerpc/platforms/pseries/eeh_sysfs.c
index eb744ee..243b351 100644
--- a/arch/powerpc/platforms/pseries/eeh_sysfs.c
+++ b/arch/powerpc/platforms/pseries/eeh_sysfs.c
@@ -28,7 +28,7 @@
 #include <asm/pci-bridge.h>
 
 /**
- * EEH_SHOW_ATTR -- create sysfs entry for eeh statistic
+ * EEH_SHOW_ATTR -- Create sysfs entry for eeh statistic
  * @_name: name of file in sysfs directory
  * @_memb: name of member in struct pci_dn to access
  * @_format: printf format for display
@@ -41,24 +41,21 @@
 		struct device_attribute *attr, char *buf)          \
 {                                                        \
 	struct pci_dev *pdev = to_pci_dev(dev);               \
-	struct device_node *dn = pci_device_to_OF_node(pdev); \
-	struct pci_dn *pdn;                                   \
+	struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);      \
 	                                                      \
-	if (!dn || PCI_DN(dn) == NULL)                        \
-		return 0;                                          \
+	if (!edev)                                            \
+		return 0;                                     \
 	                                                      \
-	pdn = PCI_DN(dn);                                     \
-	return sprintf(buf, _format "\n", pdn->_memb);        \
+	return sprintf(buf, _format "\n", edev->_memb);       \
 }                                                        \
 static DEVICE_ATTR(_name, S_IRUGO, eeh_show_##_name, NULL);
 
-
-EEH_SHOW_ATTR(eeh_mode, eeh_mode, "0x%x");
-EEH_SHOW_ATTR(eeh_config_addr, eeh_config_addr, "0x%x");
-EEH_SHOW_ATTR(eeh_pe_config_addr, eeh_pe_config_addr, "0x%x");
-EEH_SHOW_ATTR(eeh_check_count, eeh_check_count, "%d");
-EEH_SHOW_ATTR(eeh_freeze_count, eeh_freeze_count, "%d");
-EEH_SHOW_ATTR(eeh_false_positives, eeh_false_positives, "%d");
+EEH_SHOW_ATTR(eeh_mode,            mode,            "0x%x");
+EEH_SHOW_ATTR(eeh_config_addr,     config_addr,     "0x%x");
+EEH_SHOW_ATTR(eeh_pe_config_addr,  pe_config_addr,  "0x%x");
+EEH_SHOW_ATTR(eeh_check_count,     check_count,     "%d"  );
+EEH_SHOW_ATTR(eeh_freeze_count,    freeze_count,    "%d"  );
+EEH_SHOW_ATTR(eeh_false_positives, false_positives, "%d"  );
 
 void eeh_sysfs_add_device(struct pci_dev *pdev)
 {
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index c986d08..64c97d8 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -23,7 +23,6 @@
 #include <linux/delay.h>
 #include <linux/sched.h>	/* for idle_task_exit */
 #include <linux/cpu.h>
-#include <asm/system.h>
 #include <asm/prom.h>
 #include <asm/rtas.h>
 #include <asm/firmware.h>
diff --git a/arch/powerpc/platforms/pseries/io_event_irq.c b/arch/powerpc/platforms/pseries/io_event_irq.c
index 1a709bc..ef9d9d8 100644
--- a/arch/powerpc/platforms/pseries/io_event_irq.c
+++ b/arch/powerpc/platforms/pseries/io_event_irq.c
@@ -63,73 +63,9 @@
 
 static int ioei_check_exception_token;
 
-/* pSeries event log format */
-
-/* Two bytes ASCII section IDs */
-#define PSERIES_ELOG_SECT_ID_PRIV_HDR		(('P' << 8) | 'H')
-#define PSERIES_ELOG_SECT_ID_USER_HDR		(('U' << 8) | 'H')
-#define PSERIES_ELOG_SECT_ID_PRIMARY_SRC	(('P' << 8) | 'S')
-#define PSERIES_ELOG_SECT_ID_EXTENDED_UH	(('E' << 8) | 'H')
-#define PSERIES_ELOG_SECT_ID_FAILING_MTMS	(('M' << 8) | 'T')
-#define PSERIES_ELOG_SECT_ID_SECONDARY_SRC	(('S' << 8) | 'S')
-#define PSERIES_ELOG_SECT_ID_DUMP_LOCATOR	(('D' << 8) | 'H')
-#define PSERIES_ELOG_SECT_ID_FW_ERROR		(('S' << 8) | 'W')
-#define PSERIES_ELOG_SECT_ID_IMPACT_PART_ID	(('L' << 8) | 'P')
-#define PSERIES_ELOG_SECT_ID_LOGIC_RESOURCE_ID	(('L' << 8) | 'R')
-#define PSERIES_ELOG_SECT_ID_HMC_ID		(('H' << 8) | 'M')
-#define PSERIES_ELOG_SECT_ID_EPOW		(('E' << 8) | 'P')
-#define PSERIES_ELOG_SECT_ID_IO_EVENT		(('I' << 8) | 'E')
-#define PSERIES_ELOG_SECT_ID_MANUFACT_INFO	(('M' << 8) | 'I')
-#define PSERIES_ELOG_SECT_ID_CALL_HOME		(('C' << 8) | 'H')
-#define PSERIES_ELOG_SECT_ID_USER_DEF		(('U' << 8) | 'D')
-
-/* Vendor specific Platform Event Log Format, Version 6, section header */
-struct pseries_elog_section {
-	uint16_t id;			/* 0x00 2-byte ASCII section ID	*/
-	uint16_t length;		/* 0x02 Section length in bytes	*/
-	uint8_t version;		/* 0x04 Section version		*/
-	uint8_t subtype;		/* 0x05 Section subtype		*/
-	uint16_t creator_component;	/* 0x06 Creator component ID	*/
-	uint8_t data[];			/* 0x08 Start of section data	*/
-};
-
 static char ioei_rtas_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;
 
 /**
- * Find data portion of a specific section in RTAS extended event log.
- * @elog: RTAS error/event log.
- * @sect_id: secsion ID.
- *
- * Return:
- *	pointer to the section data of the specified section
- *	NULL if not found
- */
-static struct pseries_elog_section *find_xelog_section(struct rtas_error_log *elog,
-						       uint16_t sect_id)
-{
-	struct rtas_ext_event_log_v6 *xelog =
-		(struct rtas_ext_event_log_v6 *) elog->buffer;
-	struct pseries_elog_section *sect;
-	unsigned char *p, *log_end;
-
-	/* Check that we understand the format */
-	if (elog->extended_log_length < sizeof(struct rtas_ext_event_log_v6) ||
-	    xelog->log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG ||
-	    xelog->company_id != RTAS_V6EXT_COMPANY_ID_IBM)
-		return NULL;
-
-	log_end = elog->buffer + elog->extended_log_length;
-	p = xelog->vendor_log;
-	while (p < log_end) {
-		sect = (struct pseries_elog_section *)p;
-		if (sect->id == sect_id)
-			return sect;
-		p += sect->length;
-	}
-	return NULL;
-}
-
-/**
  * Find the data portion of an IO Event section from event log.
  * @elog: RTAS error/event log.
  *
@@ -138,7 +74,7 @@
  */
 static struct pseries_io_event * ioei_find_event(struct rtas_error_log *elog)
 {
-	struct pseries_elog_section *sect;
+	struct pseries_errorlog *sect;
 
 	/* We should only ever get called for io-event interrupts, but if
 	 * we do get called for another type then something went wrong so
@@ -152,7 +88,7 @@
 		return NULL;
 	}
 
-	sect = find_xelog_section(elog, PSERIES_ELOG_SECT_ID_IO_EVENT);
+	sect = get_pseries_errorlog(elog, PSERIES_ELOG_SECT_ID_IO_EVENT);
 	if (unlikely(!sect)) {
 		printk_once(KERN_WARNING "io_event_irq: RTAS extended event "
 			    "log does not contain an IO Event section. "
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index c442f2b..0915b1a 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -809,8 +809,7 @@
 static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail,
 			struct ddw_query_response *query)
 {
-	struct device_node *dn;
-	struct pci_dn *pcidn;
+	struct eeh_dev *edev;
 	u32 cfg_addr;
 	u64 buid;
 	int ret;
@@ -821,12 +820,12 @@
 	 * Retrieve them from the pci device, not the node with the
 	 * dma-window property
 	 */
-	dn = pci_device_to_OF_node(dev);
-	pcidn = PCI_DN(dn);
-	cfg_addr = pcidn->eeh_config_addr;
-	if (pcidn->eeh_pe_config_addr)
-		cfg_addr = pcidn->eeh_pe_config_addr;
-	buid = pcidn->phb->buid;
+	edev = pci_dev_to_eeh_dev(dev);
+	cfg_addr = edev->config_addr;
+	if (edev->pe_config_addr)
+		cfg_addr = edev->pe_config_addr;
+	buid = edev->phb->buid;
+
 	ret = rtas_call(ddw_avail[0], 3, 5, (u32 *)query,
 		  cfg_addr, BUID_HI(buid), BUID_LO(buid));
 	dev_info(&dev->dev, "ibm,query-pe-dma-windows(%x) %x %x %x"
@@ -839,8 +838,7 @@
 			struct ddw_create_response *create, int page_shift,
 			int window_shift)
 {
-	struct device_node *dn;
-	struct pci_dn *pcidn;
+	struct eeh_dev *edev;
 	u32 cfg_addr;
 	u64 buid;
 	int ret;
@@ -851,12 +849,11 @@
 	 * Retrieve them from the pci device, not the node with the
 	 * dma-window property
 	 */
-	dn = pci_device_to_OF_node(dev);
-	pcidn = PCI_DN(dn);
-	cfg_addr = pcidn->eeh_config_addr;
-	if (pcidn->eeh_pe_config_addr)
-		cfg_addr = pcidn->eeh_pe_config_addr;
-	buid = pcidn->phb->buid;
+	edev = pci_dev_to_eeh_dev(dev);
+	cfg_addr = edev->config_addr;
+	if (edev->pe_config_addr)
+		cfg_addr = edev->pe_config_addr;
+	buid = edev->phb->buid;
 
 	do {
 		/* extra outputs are LIOBN and dma-addr (hi, lo) */
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 7bc73af..5f3ef87 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -41,6 +41,7 @@
 #include <asm/udbg.h>
 #include <asm/smp.h>
 #include <asm/trace.h>
+#include <asm/firmware.h>
 
 #include "plpar_wrappers.h"
 #include "pseries.h"
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c
index 38d24e7..109fdb7 100644
--- a/arch/powerpc/platforms/pseries/msi.c
+++ b/arch/powerpc/platforms/pseries/msi.c
@@ -217,7 +217,7 @@
 	if (!dn)
 		return NULL;
 
-	dn = find_device_pe(dn);
+	dn = eeh_find_device_pe(dn);
 	if (!dn)
 		return NULL;
 
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index 55d4ec1..8b7bafa 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -84,7 +84,7 @@
 	list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
 		pr_debug("     * Removing %s...\n", pci_name(dev));
 		eeh_remove_bus_device(dev);
- 		pci_remove_bus_device(dev);
+ 		pci_stop_and_remove_bus_device(dev);
  	}
 }
 EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
@@ -147,6 +147,9 @@
 
 	pci_devs_phb_init_dynamic(phb);
 
+	/* Create EEH devices for the PHB */
+	eeh_dev_phb_init_dynamic(phb);
+
 	if (dn->child)
 		eeh_add_device_tree_early(dn);
 
diff --git a/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c
deleted file mode 100644
index 6e7742d..0000000
--- a/arch/powerpc/platforms/pseries/phyp_dump.c
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * Hypervisor-assisted dump
- *
- * Linas Vepstas, Manish Ahuja 2008
- * Copyright 2008 IBM Corp.
- *
- *      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/gfp.h>
-#include <linux/init.h>
-#include <linux/kobject.h>
-#include <linux/mm.h>
-#include <linux/of.h>
-#include <linux/pfn.h>
-#include <linux/swap.h>
-#include <linux/sysfs.h>
-
-#include <asm/page.h>
-#include <asm/phyp_dump.h>
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/rtas.h>
-
-/* Variables, used to communicate data between early boot and late boot */
-static struct phyp_dump phyp_dump_vars;
-struct phyp_dump *phyp_dump_info = &phyp_dump_vars;
-
-static int ibm_configure_kernel_dump;
-/* ------------------------------------------------- */
-/* RTAS interfaces to declare the dump regions */
-
-struct dump_section {
-	u32 dump_flags;
-	u16 source_type;
-	u16 error_flags;
-	u64 source_address;
-	u64 source_length;
-	u64 length_copied;
-	u64 destination_address;
-};
-
-struct phyp_dump_header {
-	u32 version;
-	u16 num_of_sections;
-	u16 status;
-
-	u32 first_offset_section;
-	u32 dump_disk_section;
-	u64 block_num_dd;
-	u64 num_of_blocks_dd;
-	u32 offset_dd;
-	u32 maxtime_to_auto;
-	/* No dump disk path string used */
-
-	struct dump_section cpu_data;
-	struct dump_section hpte_data;
-	struct dump_section kernel_data;
-};
-
-/* The dump header *must be* in low memory, so .bss it */
-static struct phyp_dump_header phdr;
-
-#define NUM_DUMP_SECTIONS	3
-#define DUMP_HEADER_VERSION	0x1
-#define DUMP_REQUEST_FLAG	0x1
-#define DUMP_SOURCE_CPU		0x0001
-#define DUMP_SOURCE_HPTE	0x0002
-#define DUMP_SOURCE_RMO		0x0011
-#define DUMP_ERROR_FLAG		0x2000
-#define DUMP_TRIGGERED		0x4000
-#define DUMP_PERFORMED		0x8000
-
-
-/**
- * init_dump_header() - initialize the header declaring a dump
- * Returns: length of dump save area.
- *
- * When the hypervisor saves crashed state, it needs to put
- * it somewhere. The dump header tells the hypervisor where
- * the data can be saved.
- */
-static unsigned long init_dump_header(struct phyp_dump_header *ph)
-{
-	unsigned long addr_offset = 0;
-
-	/* Set up the dump header */
-	ph->version = DUMP_HEADER_VERSION;
-	ph->num_of_sections = NUM_DUMP_SECTIONS;
-	ph->status = 0;
-
-	ph->first_offset_section =
-		(u32)offsetof(struct phyp_dump_header, cpu_data);
-	ph->dump_disk_section = 0;
-	ph->block_num_dd = 0;
-	ph->num_of_blocks_dd = 0;
-	ph->offset_dd = 0;
-
-	ph->maxtime_to_auto = 0; /* disabled */
-
-	/* The first two sections are mandatory */
-	ph->cpu_data.dump_flags = DUMP_REQUEST_FLAG;
-	ph->cpu_data.source_type = DUMP_SOURCE_CPU;
-	ph->cpu_data.source_address = 0;
-	ph->cpu_data.source_length = phyp_dump_info->cpu_state_size;
-	ph->cpu_data.destination_address = addr_offset;
-	addr_offset += phyp_dump_info->cpu_state_size;
-
-	ph->hpte_data.dump_flags = DUMP_REQUEST_FLAG;
-	ph->hpte_data.source_type = DUMP_SOURCE_HPTE;
-	ph->hpte_data.source_address = 0;
-	ph->hpte_data.source_length = phyp_dump_info->hpte_region_size;
-	ph->hpte_data.destination_address = addr_offset;
-	addr_offset += phyp_dump_info->hpte_region_size;
-
-	/* This section describes the low kernel region */
-	ph->kernel_data.dump_flags = DUMP_REQUEST_FLAG;
-	ph->kernel_data.source_type = DUMP_SOURCE_RMO;
-	ph->kernel_data.source_address = PHYP_DUMP_RMR_START;
-	ph->kernel_data.source_length = PHYP_DUMP_RMR_END;
-	ph->kernel_data.destination_address = addr_offset;
-	addr_offset += ph->kernel_data.source_length;
-
-	return addr_offset;
-}
-
-static void print_dump_header(const struct phyp_dump_header *ph)
-{
-#ifdef DEBUG
-	if (ph == NULL)
-		return;
-
-	printk(KERN_INFO "dump header:\n");
-	/* setup some ph->sections required */
-	printk(KERN_INFO "version = %d\n", ph->version);
-	printk(KERN_INFO "Sections = %d\n", ph->num_of_sections);
-	printk(KERN_INFO "Status = 0x%x\n", ph->status);
-
-	/* No ph->disk, so all should be set to 0 */
-	printk(KERN_INFO "Offset to first section 0x%x\n",
-		ph->first_offset_section);
-	printk(KERN_INFO "dump disk sections should be zero\n");
-	printk(KERN_INFO "dump disk section = %d\n", ph->dump_disk_section);
-	printk(KERN_INFO "block num = %lld\n", ph->block_num_dd);
-	printk(KERN_INFO "number of blocks = %lld\n", ph->num_of_blocks_dd);
-	printk(KERN_INFO "dump disk offset = %d\n", ph->offset_dd);
-	printk(KERN_INFO "Max auto time= %d\n", ph->maxtime_to_auto);
-
-	/*set cpu state and hpte states as well scratch pad area */
-	printk(KERN_INFO " CPU AREA\n");
-	printk(KERN_INFO "cpu dump_flags =%d\n", ph->cpu_data.dump_flags);
-	printk(KERN_INFO "cpu source_type =%d\n", ph->cpu_data.source_type);
-	printk(KERN_INFO "cpu error_flags =%d\n", ph->cpu_data.error_flags);
-	printk(KERN_INFO "cpu source_address =%llx\n",
-		ph->cpu_data.source_address);
-	printk(KERN_INFO "cpu source_length =%llx\n",
-		ph->cpu_data.source_length);
-	printk(KERN_INFO "cpu length_copied =%llx\n",
-		ph->cpu_data.length_copied);
-
-	printk(KERN_INFO " HPTE AREA\n");
-	printk(KERN_INFO "HPTE dump_flags =%d\n", ph->hpte_data.dump_flags);
-	printk(KERN_INFO "HPTE source_type =%d\n", ph->hpte_data.source_type);
-	printk(KERN_INFO "HPTE error_flags =%d\n", ph->hpte_data.error_flags);
-	printk(KERN_INFO "HPTE source_address =%llx\n",
-		ph->hpte_data.source_address);
-	printk(KERN_INFO "HPTE source_length =%llx\n",
-		ph->hpte_data.source_length);
-	printk(KERN_INFO "HPTE length_copied =%llx\n",
-		ph->hpte_data.length_copied);
-
-	printk(KERN_INFO " SRSD AREA\n");
-	printk(KERN_INFO "SRSD dump_flags =%d\n", ph->kernel_data.dump_flags);
-	printk(KERN_INFO "SRSD source_type =%d\n", ph->kernel_data.source_type);
-	printk(KERN_INFO "SRSD error_flags =%d\n", ph->kernel_data.error_flags);
-	printk(KERN_INFO "SRSD source_address =%llx\n",
-		ph->kernel_data.source_address);
-	printk(KERN_INFO "SRSD source_length =%llx\n",
-		ph->kernel_data.source_length);
-	printk(KERN_INFO "SRSD length_copied =%llx\n",
-		ph->kernel_data.length_copied);
-#endif
-}
-
-static ssize_t show_phyp_dump_active(struct kobject *kobj,
-			struct kobj_attribute *attr, char *buf)
-{
-
-	/* create filesystem entry so kdump is phyp-dump aware */
-	return sprintf(buf, "%lx\n", phyp_dump_info->phyp_dump_at_boot);
-}
-
-static struct kobj_attribute pdl = __ATTR(phyp_dump_active, 0600,
-					show_phyp_dump_active,
-					NULL);
-
-static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr)
-{
-	int rc;
-
-	/* Add addr value if not initialized before */
-	if (ph->cpu_data.destination_address == 0) {
-		ph->cpu_data.destination_address += addr;
-		ph->hpte_data.destination_address += addr;
-		ph->kernel_data.destination_address += addr;
-	}
-
-	/* ToDo Invalidate kdump and free memory range. */
-
-	do {
-		rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL,
-				1, ph, sizeof(struct phyp_dump_header));
-	} while (rtas_busy_delay(rc));
-
-	if (rc) {
-		printk(KERN_ERR "phyp-dump: unexpected error (%d) on "
-						"register\n", rc);
-		print_dump_header(ph);
-		return;
-	}
-
-	rc = sysfs_create_file(kernel_kobj, &pdl.attr);
-	if (rc)
-		printk(KERN_ERR "phyp-dump: unable to create sysfs"
-				" file (%d)\n", rc);
-}
-
-static
-void invalidate_last_dump(struct phyp_dump_header *ph, unsigned long addr)
-{
-	int rc;
-
-	/* Add addr value if not initialized before */
-	if (ph->cpu_data.destination_address == 0) {
-		ph->cpu_data.destination_address += addr;
-		ph->hpte_data.destination_address += addr;
-		ph->kernel_data.destination_address += addr;
-	}
-
-	do {
-		rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL,
-				2, ph, sizeof(struct phyp_dump_header));
-	} while (rtas_busy_delay(rc));
-
-	if (rc) {
-		printk(KERN_ERR "phyp-dump: unexpected error (%d) "
-						"on invalidate\n", rc);
-		print_dump_header(ph);
-	}
-}
-
-/* ------------------------------------------------- */
-/**
- * release_memory_range -- release memory previously memblock_reserved
- * @start_pfn: starting physical frame number
- * @nr_pages: number of pages to free.
- *
- * This routine will release memory that had been previously
- * memblock_reserved in early boot. The released memory becomes
- * available for genreal use.
- */
-static void release_memory_range(unsigned long start_pfn,
-			unsigned long nr_pages)
-{
-	struct page *rpage;
-	unsigned long end_pfn;
-	long i;
-
-	end_pfn = start_pfn + nr_pages;
-
-	for (i = start_pfn; i <= end_pfn; i++) {
-		rpage = pfn_to_page(i);
-		if (PageReserved(rpage)) {
-			ClearPageReserved(rpage);
-			init_page_count(rpage);
-			__free_page(rpage);
-			totalram_pages++;
-		}
-	}
-}
-
-/**
- * track_freed_range -- Counts the range being freed.
- * Once the counter goes to zero, it re-registers dump for
- * future use.
- */
-static void
-track_freed_range(unsigned long addr, unsigned long length)
-{
-	static unsigned long scratch_area_size, reserved_area_size;
-
-	if (addr < phyp_dump_info->init_reserve_start)
-		return;
-
-	if ((addr >= phyp_dump_info->init_reserve_start) &&
-	    (addr <= phyp_dump_info->init_reserve_start +
-	     phyp_dump_info->init_reserve_size))
-		reserved_area_size += length;
-
-	if ((addr >= phyp_dump_info->reserved_scratch_addr) &&
-	    (addr <= phyp_dump_info->reserved_scratch_addr +
-	     phyp_dump_info->reserved_scratch_size))
-		scratch_area_size += length;
-
-	if ((reserved_area_size == phyp_dump_info->init_reserve_size) &&
-	    (scratch_area_size == phyp_dump_info->reserved_scratch_size)) {
-
-		invalidate_last_dump(&phdr,
-				phyp_dump_info->reserved_scratch_addr);
-		register_dump_area(&phdr,
-				phyp_dump_info->reserved_scratch_addr);
-	}
-}
-
-/* ------------------------------------------------- */
-/**
- * sysfs_release_region -- sysfs interface to release memory range.
- *
- * Usage:
- *   "echo <start addr> <length> > /sys/kernel/release_region"
- *
- * Example:
- *   "echo 0x40000000 0x10000000 > /sys/kernel/release_region"
- *
- * will release 256MB starting at 1GB.
- */
-static ssize_t store_release_region(struct kobject *kobj,
-				struct kobj_attribute *attr,
-				const char *buf, size_t count)
-{
-	unsigned long start_addr, length, end_addr;
-	unsigned long start_pfn, nr_pages;
-	ssize_t ret;
-
-	ret = sscanf(buf, "%lx %lx", &start_addr, &length);
-	if (ret != 2)
-		return -EINVAL;
-
-	track_freed_range(start_addr, length);
-
-	/* Range-check - don't free any reserved memory that
-	 * wasn't reserved for phyp-dump */
-	if (start_addr < phyp_dump_info->init_reserve_start)
-		start_addr = phyp_dump_info->init_reserve_start;
-
-	end_addr = phyp_dump_info->init_reserve_start +
-			phyp_dump_info->init_reserve_size;
-	if (start_addr+length > end_addr)
-		length = end_addr - start_addr;
-
-	/* Release the region of memory assed in by user */
-	start_pfn = PFN_DOWN(start_addr);
-	nr_pages = PFN_DOWN(length);
-	release_memory_range(start_pfn, nr_pages);
-
-	return count;
-}
-
-static ssize_t show_release_region(struct kobject *kobj,
-			struct kobj_attribute *attr, char *buf)
-{
-	u64 second_addr_range;
-
-	/* total reserved size - start of scratch area */
-	second_addr_range = phyp_dump_info->init_reserve_size -
-				phyp_dump_info->reserved_scratch_size;
-	return sprintf(buf, "CPU:0x%llx-0x%llx: HPTE:0x%llx-0x%llx:"
-			    " DUMP:0x%llx-0x%llx, 0x%lx-0x%llx:\n",
-		phdr.cpu_data.destination_address,
-		phdr.cpu_data.length_copied,
-		phdr.hpte_data.destination_address,
-		phdr.hpte_data.length_copied,
-		phdr.kernel_data.destination_address,
-		phdr.kernel_data.length_copied,
-		phyp_dump_info->init_reserve_start,
-		second_addr_range);
-}
-
-static struct kobj_attribute rr = __ATTR(release_region, 0600,
-					show_release_region,
-					store_release_region);
-
-static int __init phyp_dump_setup(void)
-{
-	struct device_node *rtas;
-	const struct phyp_dump_header *dump_header = NULL;
-	unsigned long dump_area_start;
-	unsigned long dump_area_length;
-	int header_len = 0;
-	int rc;
-
-	/* If no memory was reserved in early boot, there is nothing to do */
-	if (phyp_dump_info->init_reserve_size == 0)
-		return 0;
-
-	/* Return if phyp dump not supported */
-	if (!phyp_dump_info->phyp_dump_configured)
-		return -ENOSYS;
-
-	/* Is there dump data waiting for us? If there isn't,
-	 * then register a new dump area, and release all of
-	 * the rest of the reserved ram.
-	 *
-	 * The /rtas/ibm,kernel-dump rtas node is present only
-	 * if there is dump data waiting for us.
-	 */
-	rtas = of_find_node_by_path("/rtas");
-	if (rtas) {
-		dump_header = of_get_property(rtas, "ibm,kernel-dump",
-						&header_len);
-		of_node_put(rtas);
-	}
-
-	ibm_configure_kernel_dump = rtas_token("ibm,configure-kernel-dump");
-
-	print_dump_header(dump_header);
-	dump_area_length = init_dump_header(&phdr);
-	/* align down */
-	dump_area_start = phyp_dump_info->init_reserve_start & PAGE_MASK;
-
-	if (dump_header == NULL) {
-		register_dump_area(&phdr, dump_area_start);
-		return 0;
-	}
-
-	/* re-register the dump area, if old dump was invalid */
-	if ((dump_header) && (dump_header->status & DUMP_ERROR_FLAG)) {
-		invalidate_last_dump(&phdr, dump_area_start);
-		register_dump_area(&phdr, dump_area_start);
-		return 0;
-	}
-
-	if (dump_header) {
-		phyp_dump_info->reserved_scratch_addr =
-				dump_header->cpu_data.destination_address;
-		phyp_dump_info->reserved_scratch_size =
-				dump_header->cpu_data.source_length +
-				dump_header->hpte_data.source_length +
-				dump_header->kernel_data.source_length;
-	}
-
-	/* Should we create a dump_subsys, analogous to s390/ipl.c ? */
-	rc = sysfs_create_file(kernel_kobj, &rr.attr);
-	if (rc)
-		printk(KERN_ERR "phyp-dump: unable to create sysfs file (%d)\n",
-									rc);
-
-	/* ToDo: re-register the dump area, for next time. */
-	return 0;
-}
-machine_subsys_initcall(pseries, phyp_dump_setup);
-
-int __init early_init_dt_scan_phyp_dump(unsigned long node,
-		const char *uname, int depth, void *data)
-{
-	const unsigned int *sizes;
-
-	phyp_dump_info->phyp_dump_configured = 0;
-	phyp_dump_info->phyp_dump_is_active = 0;
-
-	if (depth != 1 || strcmp(uname, "rtas") != 0)
-		return 0;
-
-	if (of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL))
-		phyp_dump_info->phyp_dump_configured++;
-
-	if (of_get_flat_dt_prop(node, "ibm,dump-kernel", NULL))
-		phyp_dump_info->phyp_dump_is_active++;
-
-	sizes = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes",
-				    NULL);
-	if (!sizes)
-		return 0;
-
-	if (sizes[0] == 1)
-		phyp_dump_info->cpu_state_size = *((unsigned long *)&sizes[1]);
-
-	if (sizes[3] == 2)
-		phyp_dump_info->hpte_region_size =
-						*((unsigned long *)&sizes[4]);
-	return 1;
-}
-
-/* Look for phyp_dump= cmdline option */
-static int __init early_phyp_dump_enabled(char *p)
-{
-	phyp_dump_info->phyp_dump_at_boot = 1;
-
-        if (!p)
-                return 0;
-
-        if (strncmp(p, "1", 1) == 0)
-		phyp_dump_info->phyp_dump_at_boot = 1;
-        else if (strncmp(p, "0", 1) == 0)
-		phyp_dump_info->phyp_dump_at_boot = 0;
-
-        return 0;
-}
-early_param("phyp_dump", early_phyp_dump_enabled);
-
-/* Look for phyp_dump_reserve_size= cmdline option */
-static int __init early_phyp_dump_reserve_size(char *p)
-{
-        if (p)
-		phyp_dump_info->reserve_bootvar = memparse(p, &p);
-
-        return 0;
-}
-early_param("phyp_dump_reserve_size", early_phyp_dump_reserve_size);
diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c
index 085fd3f..41a34bc 100644
--- a/arch/powerpc/platforms/pseries/processor_idle.c
+++ b/arch/powerpc/platforms/pseries/processor_idle.c
@@ -14,9 +14,9 @@
 
 #include <asm/paca.h>
 #include <asm/reg.h>
-#include <asm/system.h>
 #include <asm/machdep.h>
 #include <asm/firmware.h>
+#include <asm/runlatch.h>
 
 #include "plpar_wrappers.h"
 #include "pseries.h"
@@ -96,6 +96,20 @@
 	return index;
 }
 
+static void check_and_cede_processor(void)
+{
+	/*
+	 * Interrupts are soft-disabled at this point,
+	 * but not hard disabled. So an interrupt might have
+	 * occurred before entering NAP, and would be potentially
+	 * lost (edge events, decrementer events, etc...) unless
+	 * we first hard disable then check.
+	 */
+	hard_irq_disable();
+	if (get_paca()->irq_happened == 0)
+		cede_processor();
+}
+
 static int dedicated_cede_loop(struct cpuidle_device *dev,
 				struct cpuidle_driver *drv,
 				int index)
@@ -108,7 +122,7 @@
 
 	ppc64_runlatch_off();
 	HMT_medium();
-	cede_processor();
+	check_and_cede_processor();
 
 	get_lppaca()->donate_dedicated_cpu = 0;
 	dev->last_residency =
@@ -132,7 +146,7 @@
 	 * processor. When returning here, external interrupts
 	 * are enabled.
 	 */
-	cede_processor();
+	check_and_cede_processor();
 
 	dev->last_residency =
 		(int)idle_loop_epilog(in_purr, kt_before);
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index 086d2ae..c4dfccd 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -16,37 +16,15 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-/* Change Activity:
- * 2001/09/21 : engebret : Created with minimal EPOW and HW exception support.
- * End Change Activity
- */
-
-#include <linux/errno.h>
-#include <linux/threads.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <linux/timex.h>
-#include <linux/init.h>
-#include <linux/delay.h>
 #include <linux/irq.h>
-#include <linux/random.h>
-#include <linux/sysrq.h>
-#include <linux/bitops.h>
+#include <linux/of.h>
+#include <linux/fs.h>
+#include <linux/reboot.h>
 
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/cache.h>
-#include <asm/prom.h>
-#include <asm/ptrace.h>
 #include <asm/machdep.h>
 #include <asm/rtas.h>
-#include <asm/udbg.h>
 #include <asm/firmware.h>
 
 #include "pseries.h"
@@ -57,7 +35,6 @@
 static char global_mce_data_buf[RTAS_ERROR_LOG_MAX];
 static DEFINE_PER_CPU(__u64, mce_data_buf);
 
-static int ras_get_sensor_state_token;
 static int ras_check_exception_token;
 
 #define EPOW_SENSOR_TOKEN	9
@@ -75,7 +52,6 @@
 {
 	struct device_node *np;
 
-	ras_get_sensor_state_token = rtas_token("get-sensor-state");
 	ras_check_exception_token = rtas_token("check-exception");
 
 	/* Internal Errors */
@@ -95,26 +71,126 @@
 
 	return 0;
 }
-__initcall(init_ras_IRQ);
+subsys_initcall(init_ras_IRQ);
 
-/*
- * Handle power subsystem events (EPOW).
- *
- * Presently we just log the event has occurred.  This should be fixed
- * to examine the type of power failure and take appropriate action where
- * the time horizon permits something useful to be done.
- */
+#define EPOW_SHUTDOWN_NORMAL				1
+#define EPOW_SHUTDOWN_ON_UPS				2
+#define EPOW_SHUTDOWN_LOSS_OF_CRITICAL_FUNCTIONS	3
+#define EPOW_SHUTDOWN_AMBIENT_TEMPERATURE_TOO_HIGH	4
+
+static void handle_system_shutdown(char event_modifier)
+{
+	switch (event_modifier) {
+	case EPOW_SHUTDOWN_NORMAL:
+		pr_emerg("Firmware initiated power off");
+		orderly_poweroff(1);
+		break;
+
+	case EPOW_SHUTDOWN_ON_UPS:
+		pr_emerg("Loss of power reported by firmware, system is "
+			"running on UPS/battery");
+		break;
+
+	case EPOW_SHUTDOWN_LOSS_OF_CRITICAL_FUNCTIONS:
+		pr_emerg("Loss of system critical functions reported by "
+			"firmware");
+		pr_emerg("Check RTAS error log for details");
+		orderly_poweroff(1);
+		break;
+
+	case EPOW_SHUTDOWN_AMBIENT_TEMPERATURE_TOO_HIGH:
+		pr_emerg("Ambient temperature too high reported by firmware");
+		pr_emerg("Check RTAS error log for details");
+		orderly_poweroff(1);
+		break;
+
+	default:
+		pr_err("Unknown power/cooling shutdown event (modifier %d)",
+			event_modifier);
+	}
+}
+
+struct epow_errorlog {
+	unsigned char sensor_value;
+	unsigned char event_modifier;
+	unsigned char extended_modifier;
+	unsigned char reserved;
+	unsigned char platform_reason;
+};
+
+#define EPOW_RESET			0
+#define EPOW_WARN_COOLING		1
+#define EPOW_WARN_POWER			2
+#define EPOW_SYSTEM_SHUTDOWN		3
+#define EPOW_SYSTEM_HALT		4
+#define EPOW_MAIN_ENCLOSURE		5
+#define EPOW_POWER_OFF			7
+
+void rtas_parse_epow_errlog(struct rtas_error_log *log)
+{
+	struct pseries_errorlog *pseries_log;
+	struct epow_errorlog *epow_log;
+	char action_code;
+	char modifier;
+
+	pseries_log = get_pseries_errorlog(log, PSERIES_ELOG_SECT_ID_EPOW);
+	if (pseries_log == NULL)
+		return;
+
+	epow_log = (struct epow_errorlog *)pseries_log->data;
+	action_code = epow_log->sensor_value & 0xF;	/* bottom 4 bits */
+	modifier = epow_log->event_modifier & 0xF;	/* bottom 4 bits */
+
+	switch (action_code) {
+	case EPOW_RESET:
+		pr_err("Non critical power or cooling issue cleared");
+		break;
+
+	case EPOW_WARN_COOLING:
+		pr_err("Non critical cooling issue reported by firmware");
+		pr_err("Check RTAS error log for details");
+		break;
+
+	case EPOW_WARN_POWER:
+		pr_err("Non critical power issue reported by firmware");
+		pr_err("Check RTAS error log for details");
+		break;
+
+	case EPOW_SYSTEM_SHUTDOWN:
+		handle_system_shutdown(epow_log->event_modifier);
+		break;
+
+	case EPOW_SYSTEM_HALT:
+		pr_emerg("Firmware initiated power off");
+		orderly_poweroff(1);
+		break;
+
+	case EPOW_MAIN_ENCLOSURE:
+	case EPOW_POWER_OFF:
+		pr_emerg("Critical power/cooling issue reported by firmware");
+		pr_emerg("Check RTAS error log for details");
+		pr_emerg("Immediate power off");
+		emergency_sync();
+		kernel_power_off();
+		break;
+
+	default:
+		pr_err("Unknown power/cooling event (action code %d)",
+			action_code);
+	}
+}
+
+/* Handle environmental and power warning (EPOW) interrupts. */
 static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
 {
-	int status = 0xdeadbeef;
-	int state = 0;
+	int status;
+	int state;
 	int critical;
 
-	status = rtas_call(ras_get_sensor_state_token, 2, 2, &state,
-			   EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX);
+	status = rtas_get_sensor(EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX, &state);
 
 	if (state > 3)
-		critical = 1;  /* Time Critical */
+		critical = 1;		/* Time Critical */
 	else
 		critical = 0;
 
@@ -123,18 +199,14 @@
 	status = rtas_call(ras_check_exception_token, 6, 1, NULL,
 			   RTAS_VECTOR_EXTERNAL_INTERRUPT,
 			   virq_to_hw(irq),
-			   RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS,
+			   RTAS_EPOW_WARNING,
 			   critical, __pa(&ras_log_buf),
 				rtas_get_error_log_max());
 
-	udbg_printf("EPOW <0x%lx 0x%x 0x%x>\n",
-		    *((unsigned long *)&ras_log_buf), status, state);
-	printk(KERN_WARNING "EPOW <0x%lx 0x%x 0x%x>\n",
-	       *((unsigned long *)&ras_log_buf), status, state);
-
-	/* format and print the extended information */
 	log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0);
 
+	rtas_parse_epow_errlog((struct rtas_error_log *)ras_log_buf);
+
 	spin_unlock(&ras_log_buf_lock);
 	return IRQ_HANDLED;
 }
@@ -150,7 +222,7 @@
 static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
 {
 	struct rtas_error_log *rtas_elog;
-	int status = 0xdeadbeef;
+	int status;
 	int fatal;
 
 	spin_lock(&ras_log_buf_lock);
@@ -158,7 +230,7 @@
 	status = rtas_call(ras_check_exception_token, 6, 1, NULL,
 			   RTAS_VECTOR_EXTERNAL_INTERRUPT,
 			   virq_to_hw(irq),
-			   RTAS_INTERNAL_ERROR, 1 /*Time Critical */,
+			   RTAS_INTERNAL_ERROR, 1 /* Time Critical */,
 			   __pa(&ras_log_buf),
 				rtas_get_error_log_max());
 
@@ -173,24 +245,13 @@
 	log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, fatal);
 
 	if (fatal) {
-		udbg_printf("Fatal HW Error <0x%lx 0x%x>\n",
-			    *((unsigned long *)&ras_log_buf), status);
-		printk(KERN_EMERG "Error: Fatal hardware error <0x%lx 0x%x>\n",
-		       *((unsigned long *)&ras_log_buf), status);
-
-#ifndef DEBUG_RTAS_POWER_OFF
-		/* Don't actually power off when debugging so we can test
-		 * without actually failing while injecting errors.
-		 * Error data will not be logged to syslog.
-		 */
-		ppc_md.power_off();
-#endif
+		pr_emerg("Fatal hardware error reported by firmware");
+		pr_emerg("Check RTAS error log for details");
+		pr_emerg("Immediate power off");
+		emergency_sync();
+		kernel_power_off();
 	} else {
-		udbg_printf("Recoverable HW Error <0x%lx 0x%x>\n",
-			    *((unsigned long *)&ras_log_buf), status);
-		printk(KERN_WARNING
-		       "Warning: Recoverable hardware error <0x%lx 0x%x>\n",
-		       *((unsigned long *)&ras_log_buf), status);
+		pr_err("Recoverable hardware error reported by firmware");
 	}
 
 	spin_unlock(&ras_log_buf_lock);
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index f79f127..51ecac9 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -190,9 +190,8 @@
 	BUG_ON(openpic_addr == 0);
 
 	/* Setup the openpic driver */
-	mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, 0,
-			  16, 250, /* isu size, irq count */
-			  " MPIC     ");
+	mpic = mpic_alloc(pSeries_mpic_node, openpic_addr,
+			MPIC_NO_RESET, 16, 0, " MPIC     ");
 	BUG_ON(mpic == NULL);
 
 	/* Add ISUs */
@@ -261,8 +260,12 @@
 	switch (action) {
 	case PSERIES_RECONFIG_ADD:
 		pci = np->parent->data;
-		if (pci)
+		if (pci) {
 			update_dn_pci_info(np, pci->phb);
+
+			/* Create EEH device for the OF node */
+			eeh_dev_init(np, pci->phb);
+		}
 		break;
 	default:
 		err = NOTIFY_DONE;
@@ -380,8 +383,12 @@
 
 	fwnmi_init();
 
+	/* By default, only probe PCI (can be overriden by rtas_pci) */
+	pci_add_flags(PCI_PROBE_ONLY);
+
 	/* Find and initialize PCI host bridges */
 	init_pci_config_tokens();
+	eeh_pseries_init();
 	find_and_init_phbs();
 	pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb);
 	eeh_init();
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index eadba95..e16bb8d 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -37,7 +37,6 @@
 #include <asm/machdep.h>
 #include <asm/cputable.h>
 #include <asm/firmware.h>
-#include <asm/system.h>
 #include <asm/rtas.h>
 #include <asm/pSeries_reconfig.h>
 #include <asm/mpic.h>
diff --git a/arch/powerpc/platforms/wsp/chroma.c b/arch/powerpc/platforms/wsp/chroma.c
index ca6fa26..8ef53bc 100644
--- a/arch/powerpc/platforms/wsp/chroma.c
+++ b/arch/powerpc/platforms/wsp/chroma.c
@@ -17,7 +17,6 @@
 #include <linux/time.h>
 
 #include <asm/machdep.h>
-#include <asm/system.h>
 #include <asm/udbg.h>
 
 #include "ics.h"
diff --git a/arch/powerpc/platforms/wsp/psr2.c b/arch/powerpc/platforms/wsp/psr2.c
index 0c1ae06..508ec82 100644
--- a/arch/powerpc/platforms/wsp/psr2.c
+++ b/arch/powerpc/platforms/wsp/psr2.c
@@ -17,7 +17,6 @@
 #include <linux/time.h>
 
 #include <asm/machdep.h>
-#include <asm/system.h>
 #include <asm/udbg.h>
 
 #include "ics.h"
diff --git a/arch/powerpc/platforms/wsp/wsp_pci.c b/arch/powerpc/platforms/wsp/wsp_pci.c
index d24b3ac..1526551 100644
--- a/arch/powerpc/platforms/wsp/wsp_pci.c
+++ b/arch/powerpc/platforms/wsp/wsp_pci.c
@@ -27,6 +27,7 @@
 #include <asm/ppc-pci.h>
 #include <asm/iommu.h>
 #include <asm/io-workarounds.h>
+#include <asm/debug.h>
 
 #include "wsp.h"
 #include "wsp_pci.h"
@@ -682,7 +683,6 @@
 	/* XXX Force re-assigning of everything for now */
 	pci_add_flags(PCI_REASSIGN_ALL_BUS | PCI_REASSIGN_ALL_RSRC |
 		      PCI_ENABLE_PROC_DOMAINS);
-	pci_probe_only = 0;
 
 	/* Calculate how the TCE space is divided */
 	phb->dma32_base		= 0;
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
index 7b4df37..a84fecf 100644
--- a/arch/powerpc/sysdev/Kconfig
+++ b/arch/powerpc/sysdev/Kconfig
@@ -29,3 +29,7 @@
 	bool "Expose SCOM controllers via debugfs"
 	depends on PPC_SCOM
 	default n
+
+config GE_FPGA
+	bool
+	default n
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 5e37b47..1bd7ecb 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -4,6 +4,8 @@
 
 mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
 obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y)
+mpic-msgr-obj-$(CONFIG_MPIC_MSGR)	+= mpic_msgr.o
+obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y) $(mpic-msgr-obj-y)
 obj-$(CONFIG_PPC_EPAPR_HV_PIC)	+= ehv_pic.o
 fsl-msi-obj-$(CONFIG_PCI_MSI)	+= fsl_msi.o
 obj-$(CONFIG_PPC_MSI_BITMAP)	+= msi_bitmap.o
@@ -65,3 +67,5 @@
 subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
 obj-$(CONFIG_PPC_XICS)		+= xics/
+
+obj-$(CONFIG_GE_FPGA)		+= ge/
diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c
index bf6c7cc..4dd5341 100644
--- a/arch/powerpc/sysdev/cpm_common.c
+++ b/arch/powerpc/sysdev/cpm_common.c
@@ -26,7 +26,6 @@
 
 #include <asm/udbg.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/rheap.h>
 #include <asm/cpm.h>
 
diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c
index 1164158..37a6909 100644
--- a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c
+++ b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c
@@ -24,6 +24,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/of_platform.h>
diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
index 5f88797..cedabd0 100644
--- a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
+++ b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
@@ -21,6 +21,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/of_platform.h>
 #include <asm/io.h>
 
@@ -200,6 +201,9 @@
 	{
 		.compatible = "fsl,p1022-l2-cache-controller",
 	},
+	{
+		.compatible = "fsl,mpc8548-l2-cache-controller",
+	},
 	{},
 };
 
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index 0c01deb..6e097de 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -410,6 +410,7 @@
 
 		msi->msi_regs = ioremap(res.start, resource_size(&res));
 		if (!msi->msi_regs) {
+			err = -ENOMEM;
 			dev_err(&dev->dev, "could not map node %s\n",
 				dev->dev.of_node->full_name);
 			goto error_out;
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index a4c4f4a..5b6f556 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -66,8 +66,8 @@
 		"	li %0,%3\n"			\
 		"	b 2b\n"				\
 		".section __ex_table,\"a\"\n"		\
-		"	.align 2\n"			\
-		"	.long 1b,3b\n"			\
+			PPC_LONG_ALIGN "\n"		\
+			PPC_LONG "1b,3b\n"		\
 		".text"					\
 		: "=r" (err), "=r" (x)			\
 		: "b" (addr), "i" (-EFAULT), "0" (err))
diff --git a/arch/powerpc/sysdev/fsl_rmu.c b/arch/powerpc/sysdev/fsl_rmu.c
index 1548578..14bd522 100644
--- a/arch/powerpc/sysdev/fsl_rmu.c
+++ b/arch/powerpc/sysdev/fsl_rmu.c
@@ -100,14 +100,8 @@
 #define DOORBELL_DSR_TE		0x00000080
 #define DOORBELL_DSR_QFI	0x00000010
 #define DOORBELL_DSR_DIQI	0x00000001
-#define DOORBELL_TID_OFFSET	0x02
-#define DOORBELL_SID_OFFSET	0x04
-#define DOORBELL_INFO_OFFSET	0x06
 
 #define DOORBELL_MESSAGE_SIZE	0x08
-#define DBELL_SID(x)		(*(u16 *)(x + DOORBELL_SID_OFFSET))
-#define DBELL_TID(x)		(*(u16 *)(x + DOORBELL_TID_OFFSET))
-#define DBELL_INF(x)		(*(u16 *)(x + DOORBELL_INFO_OFFSET))
 
 struct rio_msg_regs {
 	u32 omr;
@@ -193,6 +187,13 @@
 	int rxirq;
 };
 
+struct rio_dbell_msg {
+	u16 pad1;
+	u16 tid;
+	u16 sid;
+	u16 info;
+};
+
 /**
  * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler
  * @irq: Linux interrupt number
@@ -311,8 +312,8 @@
 
 	/* XXX Need to check/dispatch until queue empty */
 	if (dsr & DOORBELL_DSR_DIQI) {
-		u32 dmsg =
-			(u32) fsl_dbell->dbell_ring.virt +
+		struct rio_dbell_msg *dmsg =
+			fsl_dbell->dbell_ring.virt +
 			(in_be32(&fsl_dbell->dbell_regs->dqdpar) & 0xfff);
 		struct rio_dbell *dbell;
 		int found = 0;
@@ -320,25 +321,25 @@
 		pr_debug
 			("RIO: processing doorbell,"
 			" sid %2.2x tid %2.2x info %4.4x\n",
-			DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg));
+			dmsg->sid, dmsg->tid, dmsg->info);
 
 		for (i = 0; i < MAX_PORT_NUM; i++) {
 			if (fsl_dbell->mport[i]) {
 				list_for_each_entry(dbell,
 					&fsl_dbell->mport[i]->dbells, node) {
 					if ((dbell->res->start
-						<= DBELL_INF(dmsg))
+						<= dmsg->info)
 						&& (dbell->res->end
-						>= DBELL_INF(dmsg))) {
+						>= dmsg->info)) {
 						found = 1;
 						break;
 					}
 				}
 				if (found && dbell->dinb) {
 					dbell->dinb(fsl_dbell->mport[i],
-						dbell->dev_id, DBELL_SID(dmsg),
-						DBELL_TID(dmsg),
-						DBELL_INF(dmsg));
+						dbell->dev_id, dmsg->sid,
+						dmsg->tid,
+						dmsg->info);
 					break;
 				}
 			}
@@ -348,8 +349,8 @@
 			pr_debug
 				("RIO: spurious doorbell,"
 				" sid %2.2x tid %2.2x info %4.4x\n",
-				DBELL_SID(dmsg), DBELL_TID(dmsg),
-				DBELL_INF(dmsg));
+				dmsg->sid, dmsg->tid,
+				dmsg->info);
 		}
 		setbits32(&fsl_dbell->dbell_regs->dmr, DOORBELL_DMR_DI);
 		out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_DIQI);
@@ -657,7 +658,7 @@
 	int ret = 0;
 
 	pr_debug("RIO: fsl_add_outb_message(): destid %4.4x mbox %d buffer " \
-		 "%8.8x len %8.8x\n", rdev->destid, mbox, (int)buffer, len);
+		 "%p len %8.8zx\n", rdev->destid, mbox, buffer, len);
 	if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) {
 		ret = -EINVAL;
 		goto out;
@@ -972,7 +973,8 @@
 void *fsl_get_inb_message(struct rio_mport *mport, int mbox)
 {
 	struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
-	u32 phys_buf, virt_buf;
+	u32 phys_buf;
+	void *virt_buf;
 	void *buf = NULL;
 	int buf_idx;
 
@@ -982,7 +984,7 @@
 	if (phys_buf == in_be32(&rmu->msg_regs->ifqepar))
 		goto out2;
 
-	virt_buf = (u32) rmu->msg_rx_ring.virt + (phys_buf
+	virt_buf = rmu->msg_rx_ring.virt + (phys_buf
 						- rmu->msg_rx_ring.phys);
 	buf_idx = (phys_buf - rmu->msg_rx_ring.phys) / RIO_MAX_MSG_SIZE;
 	buf = rmu->msg_rx_ring.virt_buffer[buf_idx];
@@ -994,7 +996,7 @@
 	}
 
 	/* Copy max message size, caller is expected to allocate that big */
-	memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE);
+	memcpy(buf, virt_buf, RIO_MAX_MSG_SIZE);
 
 	/* Clear the available buffer */
 	rmu->msg_rx_ring.virt_buffer[buf_idx] = NULL;
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index e8f385f..c449dbd 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -31,7 +31,6 @@
 #include <linux/fs_enet_pd.h>
 #include <linux/fs_uart_pd.h>
 
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/io.h>
 #include <asm/irq.h>
diff --git a/arch/powerpc/sysdev/ge/Makefile b/arch/powerpc/sysdev/ge/Makefile
new file mode 100644
index 0000000..8731ffc
--- /dev/null
+++ b/arch/powerpc/sysdev/ge/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_GE_FPGA)		+= ge_pic.o
diff --git a/arch/powerpc/sysdev/ge/ge_pic.c b/arch/powerpc/sysdev/ge/ge_pic.c
new file mode 100644
index 0000000..2bcb78b
--- /dev/null
+++ b/arch/powerpc/sysdev/ge/ge_pic.c
@@ -0,0 +1,251 @@
+/*
+ * Interrupt handling for GE FPGA based PIC
+ *
+ * Author: Martyn Welch <martyn.welch@ge.com>
+ *
+ * 2008 (c) GE Intelligent Platforms Embedded Systems, 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/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/irq.h>
+
+#include "ge_pic.h"
+
+#define DEBUG
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0)
+#else
+#define DBG(fmt...) do { } while (0)
+#endif
+
+#define GEF_PIC_NUM_IRQS	32
+
+/* Interrupt Controller Interface Registers */
+#define GEF_PIC_INTR_STATUS	0x0000
+
+#define GEF_PIC_INTR_MASK(cpu)	(0x0010 + (0x4 * cpu))
+#define GEF_PIC_CPU0_INTR_MASK	GEF_PIC_INTR_MASK(0)
+#define GEF_PIC_CPU1_INTR_MASK	GEF_PIC_INTR_MASK(1)
+
+#define GEF_PIC_MCP_MASK(cpu)	(0x0018 + (0x4 * cpu))
+#define GEF_PIC_CPU0_MCP_MASK	GEF_PIC_MCP_MASK(0)
+#define GEF_PIC_CPU1_MCP_MASK	GEF_PIC_MCP_MASK(1)
+
+
+static DEFINE_RAW_SPINLOCK(gef_pic_lock);
+
+static void __iomem *gef_pic_irq_reg_base;
+static struct irq_domain *gef_pic_irq_host;
+static int gef_pic_cascade_irq;
+
+/*
+ * Interrupt Controller Handling
+ *
+ * The interrupt controller handles interrupts for most on board interrupts,
+ * apart from PCI interrupts. For example on SBC610:
+ *
+ * 17:31 RO Reserved
+ * 16    RO PCI Express Doorbell 3 Status
+ * 15    RO PCI Express Doorbell 2 Status
+ * 14    RO PCI Express Doorbell 1 Status
+ * 13    RO PCI Express Doorbell 0 Status
+ * 12    RO Real Time Clock Interrupt Status
+ * 11    RO Temperature Interrupt Status
+ * 10    RO Temperature Critical Interrupt Status
+ * 9     RO Ethernet PHY1 Interrupt Status
+ * 8     RO Ethernet PHY3 Interrupt Status
+ * 7     RO PEX8548 Interrupt Status
+ * 6     RO Reserved
+ * 5     RO Watchdog 0 Interrupt Status
+ * 4     RO Watchdog 1 Interrupt Status
+ * 3     RO AXIS Message FIFO A Interrupt Status
+ * 2     RO AXIS Message FIFO B Interrupt Status
+ * 1     RO AXIS Message FIFO C Interrupt Status
+ * 0     RO AXIS Message FIFO D Interrupt Status
+ *
+ * Interrupts can be forwarded to one of two output lines. Nothing
+ * clever is done, so if the masks are incorrectly set, a single input
+ * interrupt could generate interrupts on both output lines!
+ *
+ * The dual lines are there to allow the chained interrupts to be easily
+ * passed into two different cores. We currently do not use this functionality
+ * in this driver.
+ *
+ * Controller can also be configured to generate Machine checks (MCP), again on
+ * two lines, to be attached to two different cores. It is suggested that these
+ * should be masked out.
+ */
+
+void gef_pic_cascade(unsigned int irq, struct irq_desc *desc)
+{
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	unsigned int cascade_irq;
+
+	/*
+	 * See if we actually have an interrupt, call generic handling code if
+	 * we do.
+	 */
+	cascade_irq = gef_pic_get_irq();
+
+	if (cascade_irq != NO_IRQ)
+		generic_handle_irq(cascade_irq);
+
+	chip->irq_eoi(&desc->irq_data);
+}
+
+static void gef_pic_mask(struct irq_data *d)
+{
+	unsigned long flags;
+	unsigned int hwirq = irqd_to_hwirq(d);
+	u32 mask;
+
+	raw_spin_lock_irqsave(&gef_pic_lock, flags);
+	mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
+	mask &= ~(1 << hwirq);
+	out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
+	raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
+}
+
+static void gef_pic_mask_ack(struct irq_data *d)
+{
+	/* Don't think we actually have to do anything to ack an interrupt,
+	 * we just need to clear down the devices interrupt and it will go away
+	 */
+	gef_pic_mask(d);
+}
+
+static void gef_pic_unmask(struct irq_data *d)
+{
+	unsigned long flags;
+	unsigned int hwirq = irqd_to_hwirq(d);
+	u32 mask;
+
+	raw_spin_lock_irqsave(&gef_pic_lock, flags);
+	mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
+	mask |= (1 << hwirq);
+	out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
+	raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
+}
+
+static struct irq_chip gef_pic_chip = {
+	.name		= "gefp",
+	.irq_mask	= gef_pic_mask,
+	.irq_mask_ack	= gef_pic_mask_ack,
+	.irq_unmask	= gef_pic_unmask,
+};
+
+
+/* When an interrupt is being configured, this call allows some flexibilty
+ * in deciding which irq_chip structure is used
+ */
+static int gef_pic_host_map(struct irq_domain *h, unsigned int virq,
+			  irq_hw_number_t hwirq)
+{
+	/* All interrupts are LEVEL sensitive */
+	irq_set_status_flags(virq, IRQ_LEVEL);
+	irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq);
+
+	return 0;
+}
+
+static int gef_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
+			    const u32 *intspec, unsigned int intsize,
+			    irq_hw_number_t *out_hwirq, unsigned int *out_flags)
+{
+
+	*out_hwirq = intspec[0];
+	if (intsize > 1)
+		*out_flags = intspec[1];
+	else
+		*out_flags = IRQ_TYPE_LEVEL_HIGH;
+
+	return 0;
+}
+
+static const struct irq_domain_ops gef_pic_host_ops = {
+	.map	= gef_pic_host_map,
+	.xlate	= gef_pic_host_xlate,
+};
+
+
+/*
+ * Initialisation of PIC, this should be called in BSP
+ */
+void __init gef_pic_init(struct device_node *np)
+{
+	unsigned long flags;
+
+	/* Map the devices registers into memory */
+	gef_pic_irq_reg_base = of_iomap(np, 0);
+
+	raw_spin_lock_irqsave(&gef_pic_lock, flags);
+
+	/* Initialise everything as masked. */
+	out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0);
+	out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0);
+
+	out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0);
+	out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0);
+
+	raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
+
+	/* Map controller */
+	gef_pic_cascade_irq = irq_of_parse_and_map(np, 0);
+	if (gef_pic_cascade_irq == NO_IRQ) {
+		printk(KERN_ERR "SBC610: failed to map cascade interrupt");
+		return;
+	}
+
+	/* Setup an irq_domain structure */
+	gef_pic_irq_host = irq_domain_add_linear(np, GEF_PIC_NUM_IRQS,
+					  &gef_pic_host_ops, NULL);
+	if (gef_pic_irq_host == NULL)
+		return;
+
+	/* Chain with parent controller */
+	irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade);
+}
+
+/*
+ * This is called when we receive an interrupt with apparently comes from this
+ * chip - check, returning the highest interrupt generated or return NO_IRQ
+ */
+unsigned int gef_pic_get_irq(void)
+{
+	u32 cause, mask, active;
+	unsigned int virq = NO_IRQ;
+	int hwirq;
+
+	cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS);
+
+	mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
+
+	active = cause & mask;
+
+	if (active) {
+		for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) {
+			if (active & (0x1 << hwirq))
+				break;
+		}
+		virq = irq_linear_revmap(gef_pic_irq_host,
+			(irq_hw_number_t)hwirq);
+	}
+
+	return virq;
+}
+
diff --git a/arch/powerpc/platforms/86xx/gef_pic.h b/arch/powerpc/sysdev/ge/ge_pic.h
similarity index 100%
rename from arch/powerpc/platforms/86xx/gef_pic.h
rename to arch/powerpc/sysdev/ge/ge_pic.h
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index c83a512..9ac71eb 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -873,7 +873,7 @@
 	DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n",
 	    mpic, d->irq, src, flow_type);
 
-	if (src >= mpic->irq_count)
+	if (src >= mpic->num_sources)
 		return -EINVAL;
 
 	if (flow_type == IRQ_TYPE_NONE)
@@ -909,7 +909,7 @@
 	DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n",
 	    mpic, virq, src, vector);
 
-	if (src >= mpic->irq_count)
+	if (src >= mpic->num_sources)
 		return;
 
 	vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
@@ -926,7 +926,7 @@
 	DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n",
 	    mpic, virq, src, cpuid);
 
-	if (src >= mpic->irq_count)
+	if (src >= mpic->num_sources)
 		return;
 
 	mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid);
@@ -1006,7 +1006,7 @@
 		return 0;
 	}
 
-	if (hw >= mpic->irq_count)
+	if (hw >= mpic->num_sources)
 		return -EINVAL;
 
 	mpic_msi_reserve_hwirq(mpic, hw);
@@ -1149,6 +1149,7 @@
 	u32 greg_feature;
 	const char *vers;
 	const u32 *psrc;
+	u32 last_irq;
 
 	/* Default MPIC search parameters */
 	static const struct of_device_id __initconst mpic_device_id[] = {
@@ -1182,6 +1183,16 @@
 		}
 	}
 
+	/* Read extra device-tree properties into the flags variable */
+	if (of_get_property(node, "big-endian", NULL))
+		flags |= MPIC_BIG_ENDIAN;
+	if (of_get_property(node, "pic-no-reset", NULL))
+		flags |= MPIC_NO_RESET;
+	if (of_get_property(node, "single-cpu-affinity", NULL))
+		flags |= MPIC_SINGLE_DEST_CPU;
+	if (of_device_is_compatible(node, "fsl,mpic"))
+		flags |= MPIC_FSL;
+
 	mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL);
 	if (mpic == NULL)
 		goto err_of_node_put;
@@ -1189,15 +1200,16 @@
 	mpic->name = name;
 	mpic->node = node;
 	mpic->paddr = phys_addr;
+	mpic->flags = flags;
 
 	mpic->hc_irq = mpic_irq_chip;
 	mpic->hc_irq.name = name;
-	if (!(flags & MPIC_SECONDARY))
+	if (!(mpic->flags & MPIC_SECONDARY))
 		mpic->hc_irq.irq_set_affinity = mpic_set_affinity;
 #ifdef CONFIG_MPIC_U3_HT_IRQS
 	mpic->hc_ht_irq = mpic_irq_ht_chip;
 	mpic->hc_ht_irq.name = name;
-	if (!(flags & MPIC_SECONDARY))
+	if (!(mpic->flags & MPIC_SECONDARY))
 		mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity;
 #endif /* CONFIG_MPIC_U3_HT_IRQS */
 
@@ -1209,12 +1221,9 @@
 	mpic->hc_tm = mpic_tm_chip;
 	mpic->hc_tm.name = name;
 
-	mpic->flags = flags;
-	mpic->isu_size = isu_size;
-	mpic->irq_count = irq_count;
 	mpic->num_sources = 0; /* so far */
 
-	if (flags & MPIC_LARGE_VECTORS)
+	if (mpic->flags & MPIC_LARGE_VECTORS)
 		intvec_top = 2047;
 	else
 		intvec_top = 255;
@@ -1233,12 +1242,6 @@
 	mpic->ipi_vecs[3]   = intvec_top - 1;
 	mpic->spurious_vec  = intvec_top;
 
-	/* Check for "big-endian" in device-tree */
-	if (of_get_property(mpic->node, "big-endian", NULL) != NULL)
-		mpic->flags |= MPIC_BIG_ENDIAN;
-	if (of_device_is_compatible(mpic->node, "fsl,mpic"))
-		mpic->flags |= MPIC_FSL;
-
 	/* Look for protected sources */
 	psrc = of_get_property(mpic->node, "protected-sources", &psize);
 	if (psrc) {
@@ -1254,11 +1257,11 @@
 	}
 
 #ifdef CONFIG_MPIC_WEIRD
-	mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)];
+	mpic->hw_set = mpic_infos[MPIC_GET_REGSET(mpic->flags)];
 #endif
 
 	/* default register type */
-	if (flags & MPIC_BIG_ENDIAN)
+	if (mpic->flags & MPIC_BIG_ENDIAN)
 		mpic->reg_type = mpic_access_mmio_be;
 	else
 		mpic->reg_type = mpic_access_mmio_le;
@@ -1268,10 +1271,10 @@
 	 * only if the kernel includes DCR support.
 	 */
 #ifdef CONFIG_PPC_DCR
-	if (flags & MPIC_USES_DCR)
+	if (mpic->flags & MPIC_USES_DCR)
 		mpic->reg_type = mpic_access_dcr;
 #else
-	BUG_ON(flags & MPIC_USES_DCR);
+	BUG_ON(mpic->flags & MPIC_USES_DCR);
 #endif
 
 	/* Map the global registers */
@@ -1283,10 +1286,7 @@
 	/* When using a device-node, reset requests are only honored if the MPIC
 	 * is allowed to reset.
 	 */
-	if (of_get_property(mpic->node, "pic-no-reset", NULL))
-		mpic->flags |= MPIC_NO_RESET;
-
-	if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) {
+	if (!(mpic->flags & MPIC_NO_RESET)) {
 		printk(KERN_DEBUG "mpic: Resetting\n");
 		mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
 			   mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
@@ -1297,31 +1297,17 @@
 	}
 
 	/* CoreInt */
-	if (flags & MPIC_ENABLE_COREINT)
+	if (mpic->flags & MPIC_ENABLE_COREINT)
 		mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
 			   mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
 			   | MPIC_GREG_GCONF_COREINT);
 
-	if (flags & MPIC_ENABLE_MCK)
+	if (mpic->flags & MPIC_ENABLE_MCK)
 		mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
 			   mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
 			   | MPIC_GREG_GCONF_MCK);
 
 	/*
-	 * Read feature register.  For non-ISU MPICs, num sources as well. On
-	 * ISU MPICs, sources are counted as ISUs are added
-	 */
-	greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0));
-	if (isu_size == 0) {
-		if (flags & MPIC_BROKEN_FRR_NIRQS)
-			mpic->num_sources = mpic->irq_count;
-		else
-			mpic->num_sources =
-				((greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK)
-				 >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1;
-	}
-
-	/*
 	 * The MPIC driver will crash if there are more cores than we
 	 * can initialize, so we may as well catch that problem here.
 	 */
@@ -1336,17 +1322,41 @@
 			 0x1000);
 	}
 
+	/*
+	 * Read feature register.  For non-ISU MPICs, num sources as well. On
+	 * ISU MPICs, sources are counted as ISUs are added
+	 */
+	greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0));
+
+	/*
+	 * By default, the last source number comes from the MPIC, but the
+	 * device-tree and board support code can override it on buggy hw.
+	 * If we get passed an isu_size (multi-isu MPIC) then we use that
+	 * as a default instead of the value read from the HW.
+	 */
+	last_irq = (greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK)
+				>> MPIC_GREG_FEATURE_LAST_SRC_SHIFT;	
+	if (isu_size)
+		last_irq = isu_size  * MPIC_MAX_ISU - 1;
+	of_property_read_u32(mpic->node, "last-interrupt-source", &last_irq);
+	if (irq_count)
+		last_irq = irq_count - 1;
+
 	/* Initialize main ISU if none provided */
-	if (mpic->isu_size == 0) {
-		mpic->isu_size = mpic->num_sources;
+	if (!isu_size) {
+		isu_size = last_irq + 1;
+		mpic->num_sources = isu_size;
 		mpic_map(mpic, mpic->paddr, &mpic->isus[0],
-			 MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
+				MPIC_INFO(IRQ_BASE),
+				MPIC_INFO(IRQ_STRIDE) * isu_size);
 	}
+
+	mpic->isu_size = isu_size;
 	mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
 	mpic->isu_mask = (1 << mpic->isu_shift) - 1;
 
 	mpic->irqhost = irq_domain_add_linear(mpic->node,
-				       isu_size ? isu_size : mpic->num_sources,
+				       last_irq + 1,
 				       &mpic_host_ops, mpic);
 
 	/*
@@ -1380,7 +1390,7 @@
 	mpic->next = mpics;
 	mpics = mpic;
 
-	if (!(flags & MPIC_SECONDARY)) {
+	if (!(mpic->flags & MPIC_SECONDARY)) {
 		mpic_primary = mpic;
 		irq_set_default_host(mpic->irqhost);
 	}
@@ -1447,10 +1457,6 @@
 			       (mpic->ipi_vecs[0] + i));
 	}
 
-	/* Initialize interrupt sources */
-	if (mpic->irq_count == 0)
-		mpic->irq_count = mpic->num_sources;
-
 	/* Do the HT PIC fixups on U3 broken mpic */
 	DBG("MPIC flags: %x\n", mpic->flags);
 	if ((mpic->flags & MPIC_U3_HT_IRQS) && !(mpic->flags & MPIC_SECONDARY)) {
diff --git a/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c
new file mode 100644
index 0000000..6e7fa38
--- /dev/null
+++ b/arch/powerpc/sysdev/mpic_msgr.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2011-2012, Meador Inge, Mentor Graphics Corporation.
+ *
+ * Some ideas based on un-pushed work done by Vivek Mahajan, Jason Jin, and
+ * Mingkai Hu from Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/list.h>
+#include <linux/of_platform.h>
+#include <linux/errno.h>
+#include <asm/prom.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+#include <asm/mpic_msgr.h>
+
+#define MPIC_MSGR_REGISTERS_PER_BLOCK	4
+#define MPIC_MSGR_STRIDE		0x10
+#define MPIC_MSGR_MER_OFFSET		0x100
+#define MSGR_INUSE			0
+#define MSGR_FREE			1
+
+static struct mpic_msgr **mpic_msgrs;
+static unsigned int mpic_msgr_count;
+
+static inline void _mpic_msgr_mer_write(struct mpic_msgr *msgr, u32 value)
+{
+	out_be32(msgr->mer, value);
+}
+
+static inline u32 _mpic_msgr_mer_read(struct mpic_msgr *msgr)
+{
+	return in_be32(msgr->mer);
+}
+
+static inline void _mpic_msgr_disable(struct mpic_msgr *msgr)
+{
+	u32 mer = _mpic_msgr_mer_read(msgr);
+
+	_mpic_msgr_mer_write(msgr, mer & ~(1 << msgr->num));
+}
+
+struct mpic_msgr *mpic_msgr_get(unsigned int reg_num)
+{
+	unsigned long flags;
+	struct mpic_msgr *msgr;
+
+	/* Assume busy until proven otherwise.  */
+	msgr = ERR_PTR(-EBUSY);
+
+	if (reg_num >= mpic_msgr_count)
+		return ERR_PTR(-ENODEV);
+
+	raw_spin_lock_irqsave(&msgr->lock, flags);
+	if (mpic_msgrs[reg_num]->in_use == MSGR_FREE) {
+		msgr = mpic_msgrs[reg_num];
+		msgr->in_use = MSGR_INUSE;
+	}
+	raw_spin_unlock_irqrestore(&msgr->lock, flags);
+
+	return msgr;
+}
+EXPORT_SYMBOL_GPL(mpic_msgr_get);
+
+void mpic_msgr_put(struct mpic_msgr *msgr)
+{
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&msgr->lock, flags);
+	msgr->in_use = MSGR_FREE;
+	_mpic_msgr_disable(msgr);
+	raw_spin_unlock_irqrestore(&msgr->lock, flags);
+}
+EXPORT_SYMBOL_GPL(mpic_msgr_put);
+
+void mpic_msgr_enable(struct mpic_msgr *msgr)
+{
+	unsigned long flags;
+	u32 mer;
+
+	raw_spin_lock_irqsave(&msgr->lock, flags);
+	mer = _mpic_msgr_mer_read(msgr);
+	_mpic_msgr_mer_write(msgr, mer | (1 << msgr->num));
+	raw_spin_unlock_irqrestore(&msgr->lock, flags);
+}
+EXPORT_SYMBOL_GPL(mpic_msgr_enable);
+
+void mpic_msgr_disable(struct mpic_msgr *msgr)
+{
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&msgr->lock, flags);
+	_mpic_msgr_disable(msgr);
+	raw_spin_unlock_irqrestore(&msgr->lock, flags);
+}
+EXPORT_SYMBOL_GPL(mpic_msgr_disable);
+
+/* The following three functions are used to compute the order and number of
+ * the message register blocks.  They are clearly very inefficent.  However,
+ * they are called *only* a few times during device initialization.
+ */
+static unsigned int mpic_msgr_number_of_blocks(void)
+{
+	unsigned int count;
+	struct device_node *aliases;
+
+	count = 0;
+	aliases = of_find_node_by_name(NULL, "aliases");
+
+	if (aliases) {
+		char buf[32];
+
+		for (;;) {
+			snprintf(buf, sizeof(buf), "mpic-msgr-block%d", count);
+			if (!of_find_property(aliases, buf, NULL))
+				break;
+
+			count += 1;
+		}
+	}
+
+	return count;
+}
+
+static unsigned int mpic_msgr_number_of_registers(void)
+{
+	return mpic_msgr_number_of_blocks() * MPIC_MSGR_REGISTERS_PER_BLOCK;
+}
+
+static int mpic_msgr_block_number(struct device_node *node)
+{
+	struct device_node *aliases;
+	unsigned int index, number_of_blocks;
+	char buf[64];
+
+	number_of_blocks = mpic_msgr_number_of_blocks();
+	aliases = of_find_node_by_name(NULL, "aliases");
+	if (!aliases)
+		return -1;
+
+	for (index = 0; index < number_of_blocks; ++index) {
+		struct property *prop;
+
+		snprintf(buf, sizeof(buf), "mpic-msgr-block%d", index);
+		prop = of_find_property(aliases, buf, NULL);
+		if (node == of_find_node_by_path(prop->value))
+			break;
+	}
+
+	return index == number_of_blocks ? -1 : index;
+}
+
+/* The probe function for a single message register block.
+ */
+static __devinit int mpic_msgr_probe(struct platform_device *dev)
+{
+	void __iomem *msgr_block_addr;
+	int block_number;
+	struct resource rsrc;
+	unsigned int i;
+	unsigned int irq_index;
+	struct device_node *np = dev->dev.of_node;
+	unsigned int receive_mask;
+	const unsigned int *prop;
+
+	if (!np) {
+		dev_err(&dev->dev, "Device OF-Node is NULL");
+		return -EFAULT;
+	}
+
+	/* Allocate the message register array upon the first device
+	 * registered.
+	 */
+	if (!mpic_msgrs) {
+		mpic_msgr_count = mpic_msgr_number_of_registers();
+		dev_info(&dev->dev, "Found %d message registers\n",
+				mpic_msgr_count);
+
+		mpic_msgrs = kzalloc(sizeof(struct mpic_msgr) * mpic_msgr_count,
+							 GFP_KERNEL);
+		if (!mpic_msgrs) {
+			dev_err(&dev->dev,
+				"No memory for message register blocks\n");
+			return -ENOMEM;
+		}
+	}
+	dev_info(&dev->dev, "Of-device full name %s\n", np->full_name);
+
+	/* IO map the message register block. */
+	of_address_to_resource(np, 0, &rsrc);
+	msgr_block_addr = ioremap(rsrc.start, rsrc.end - rsrc.start);
+	if (!msgr_block_addr) {
+		dev_err(&dev->dev, "Failed to iomap MPIC message registers");
+		return -EFAULT;
+	}
+
+	/* Ensure the block has a defined order. */
+	block_number = mpic_msgr_block_number(np);
+	if (block_number < 0) {
+		dev_err(&dev->dev,
+			"Failed to find message register block alias\n");
+		return -ENODEV;
+	}
+	dev_info(&dev->dev, "Setting up message register block %d\n",
+			block_number);
+
+	/* Grab the receive mask which specifies what registers can receive
+	 * interrupts.
+	 */
+	prop = of_get_property(np, "mpic-msgr-receive-mask", NULL);
+	receive_mask = (prop) ? *prop : 0xF;
+
+	/* Build up the appropriate message register data structures. */
+	for (i = 0, irq_index = 0; i < MPIC_MSGR_REGISTERS_PER_BLOCK; ++i) {
+		struct mpic_msgr *msgr;
+		unsigned int reg_number;
+
+		msgr = kzalloc(sizeof(struct mpic_msgr), GFP_KERNEL);
+		if (!msgr) {
+			dev_err(&dev->dev, "No memory for message register\n");
+			return -ENOMEM;
+		}
+
+		reg_number = block_number * MPIC_MSGR_REGISTERS_PER_BLOCK + i;
+		msgr->base = msgr_block_addr + i * MPIC_MSGR_STRIDE;
+		msgr->mer = msgr->base + MPIC_MSGR_MER_OFFSET;
+		msgr->in_use = MSGR_FREE;
+		msgr->num = i;
+		raw_spin_lock_init(&msgr->lock);
+
+		if (receive_mask & (1 << i)) {
+			struct resource irq;
+
+			if (of_irq_to_resource(np, irq_index, &irq) == NO_IRQ) {
+				dev_err(&dev->dev,
+						"Missing interrupt specifier");
+				kfree(msgr);
+				return -EFAULT;
+			}
+			msgr->irq = irq.start;
+			irq_index += 1;
+		} else {
+			msgr->irq = NO_IRQ;
+		}
+
+		mpic_msgrs[reg_number] = msgr;
+		mpic_msgr_disable(msgr);
+		dev_info(&dev->dev, "Register %d initialized: irq %d\n",
+				reg_number, msgr->irq);
+
+	}
+
+	return 0;
+}
+
+static const struct of_device_id mpic_msgr_ids[] = {
+	{
+		.compatible = "fsl,mpic-v3.1-msgr",
+		.data = NULL,
+	},
+	{}
+};
+
+static struct platform_driver mpic_msgr_driver = {
+	.driver = {
+		.name = "mpic-msgr",
+		.owner = THIS_MODULE,
+		.of_match_table = mpic_msgr_ids,
+	},
+	.probe = mpic_msgr_probe,
+};
+
+static __init int mpic_msgr_init(void)
+{
+	return platform_driver_register(&mpic_msgr_driver);
+}
+subsys_initcall(mpic_msgr_init);
diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c
index 0622aa9..bbf342c 100644
--- a/arch/powerpc/sysdev/mpic_msi.c
+++ b/arch/powerpc/sysdev/mpic_msi.c
@@ -54,7 +54,7 @@
 	for (i = 100; i < 105; i++)
 		msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
 
-	for (i = 124; i < mpic->irq_count; i++)
+	for (i = 124; i < mpic->num_sources; i++)
 		msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
 
 
@@ -83,7 +83,7 @@
 {
 	int rc;
 
-	rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->irq_count,
+	rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->num_sources,
 			      mpic->irqhost->of_node);
 	if (rc)
 		return rc;
diff --git a/arch/powerpc/sysdev/msi_bitmap.c b/arch/powerpc/sysdev/msi_bitmap.c
index 5287e95..0968b66 100644
--- a/arch/powerpc/sysdev/msi_bitmap.c
+++ b/arch/powerpc/sysdev/msi_bitmap.c
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/bitmap.h>
 #include <asm/msi_bitmap.h>
+#include <asm/setup.h>
 
 int msi_bitmap_alloc_hwirqs(struct msi_bitmap *bmp, int num)
 {
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
index 4f05f75..56e8b3c 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
@@ -1050,6 +1050,74 @@
 	.check_link	= ppc4xx_pciex_check_link_sdr,
 };
 
+static int __init apm821xx_pciex_core_init(struct device_node *np)
+{
+	/* Return the number of pcie port */
+	return 1;
+}
+
+static int apm821xx_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
+{
+	u32 val;
+
+	/*
+	 * Do a software reset on PCIe ports.
+	 * This code is to fix the issue that pci drivers doesn't re-assign
+	 * bus number for PCIE devices after Uboot
+	 * scanned and configured all the buses (eg. PCIE NIC IntelPro/1000
+	 * PT quad port, SAS LSI 1064E)
+	 */
+
+	mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x0);
+	mdelay(10);
+
+	if (port->endpoint)
+		val = PTYPE_LEGACY_ENDPOINT << 20;
+	else
+		val = PTYPE_ROOT_PORT << 20;
+
+	val |= LNKW_X1 << 12;
+
+	mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val);
+	mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x00000000);
+	mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01010000);
+
+	mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230);
+	mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130);
+	mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006);
+
+	mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x10000000);
+	mdelay(50);
+	mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x30000000);
+
+	mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
+		mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) |
+		(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTPYN));
+
+	/* Poll for PHY reset */
+	val = PESDR0_460EX_RSTSTA - port->sdr_base;
+	if (ppc4xx_pciex_wait_on_sdr(port, val, 0x1, 1,	100)) {
+		printk(KERN_WARNING "%s: PCIE: Can't reset PHY\n", __func__);
+		return -EBUSY;
+	} else {
+		mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
+			(mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) &
+			~(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL)) |
+			PESDRx_RCSSET_RSTPYN);
+
+		port->has_ibpre = 1;
+		return 0;
+	}
+}
+
+static struct ppc4xx_pciex_hwops apm821xx_pcie_hwops __initdata = {
+	.want_sdr   = true,
+	.core_init	= apm821xx_pciex_core_init,
+	.port_init_hw	= apm821xx_pciex_init_port_hw,
+	.setup_utl	= ppc460ex_pciex_init_utl,
+	.check_link = ppc4xx_pciex_check_link_sdr,
+};
+
 static int __init ppc460sx_pciex_core_init(struct device_node *np)
 {
 	/* HSS drive amplitude */
@@ -1362,6 +1430,8 @@
 		ppc4xx_pciex_hwops = &ppc460ex_pcie_hwops;
 	if (of_device_is_compatible(np, "ibm,plb-pciex-460sx"))
 		ppc4xx_pciex_hwops = &ppc460sx_pcie_hwops;
+	if (of_device_is_compatible(np, "ibm,plb-pciex-apm821xx"))
+		ppc4xx_pciex_hwops = &apm821xx_pcie_hwops;
 #endif /* CONFIG_44x    */
 #ifdef CONFIG_40x
 	if (of_device_is_compatible(np, "ibm,plb-pciex-405ex"))
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
index ceb09cb..818e763 100644
--- a/arch/powerpc/sysdev/qe_lib/qe.c
+++ b/arch/powerpc/sysdev/qe_lib/qe.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2006-2010 Freescale Semicondutor, Inc. All rights reserved.
  *
  * Authors: 	Shlomi Gridish <gridish@freescale.com>
  * 		Li Yang <leoli@freescale.com>
@@ -266,7 +266,19 @@
 static void qe_snums_init(void)
 {
 	int i;
-	static const u8 snum_init[] = {
+	static const u8 snum_init_76[] = {
+		0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
+		0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
+		0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
+		0xD8, 0xD9, 0xE8, 0xE9, 0x44, 0x45, 0x4C, 0x4D,
+		0x54, 0x55, 0x5C, 0x5D, 0x64, 0x65, 0x6C, 0x6D,
+		0x74, 0x75, 0x7C, 0x7D, 0x84, 0x85, 0x8C, 0x8D,
+		0x94, 0x95, 0x9C, 0x9D, 0xA4, 0xA5, 0xAC, 0xAD,
+		0xB4, 0xB5, 0xBC, 0xBD, 0xC4, 0xC5, 0xCC, 0xCD,
+		0xD4, 0xD5, 0xDC, 0xDD, 0xE4, 0xE5, 0xEC, 0xED,
+		0xF4, 0xF5, 0xFC, 0xFD,
+	};
+	static const u8 snum_init_46[] = {
 		0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
 		0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
 		0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
@@ -274,9 +286,15 @@
 		0x28, 0x29, 0x38, 0x39, 0x48, 0x49, 0x58, 0x59,
 		0x68, 0x69, 0x78, 0x79, 0x80, 0x81,
 	};
+	static const u8 *snum_init;
 
 	qe_num_of_snum = qe_get_num_of_snums();
 
+	if (qe_num_of_snum == 76)
+		snum_init = snum_init_76;
+	else
+		snum_init = snum_init_46;
+
 	for (i = 0; i < qe_num_of_snum; i++) {
 		snums[i].num = snum_init[i];
 		snums[i].state = QE_SNUM_STATE_FREE;
diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c
index 2370e1c..1fd0717 100644
--- a/arch/powerpc/sysdev/tsi108_dev.c
+++ b/arch/powerpc/sysdev/tsi108_dev.c
@@ -22,7 +22,6 @@
 #include <linux/of_net.h>
 #include <asm/tsi108.h>
 
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/io.h>
 #include <asm/irq.h>
diff --git a/arch/powerpc/xmon/ppc-opc.c b/arch/powerpc/xmon/ppc-opc.c
index af3780e..6845e91 100644
--- a/arch/powerpc/xmon/ppc-opc.c
+++ b/arch/powerpc/xmon/ppc-opc.c
@@ -22,6 +22,7 @@
 
 #include <linux/stddef.h>
 #include <linux/kernel.h>
+#include <linux/bug.h>
 #include "nonstdio.h"
 #include "ppc.h"
 
diff --git a/arch/powerpc/xmon/spu-opc.c b/arch/powerpc/xmon/spu-opc.c
index 530df3d..7d37597c 100644
--- a/arch/powerpc/xmon/spu-opc.c
+++ b/arch/powerpc/xmon/spu-opc.c
@@ -19,6 +19,7 @@
    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 #include <linux/kernel.h>
+#include <linux/bug.h>
 #include "spu.h"
 
 /* This file holds the Spu opcode table */
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index cb95eea..0f3ab06 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -39,9 +39,9 @@
 #include <asm/irq_regs.h>
 #include <asm/spu.h>
 #include <asm/spu_priv1.h>
-#include <asm/firmware.h>
 #include <asm/setjmp.h>
 #include <asm/reg.h>
+#include <asm/debug.h>
 
 #ifdef CONFIG_PPC64
 #include <asm/hvcall.h>
@@ -1437,7 +1437,8 @@
 
 	printf("  current = 0x%lx\n", current);
 #ifdef CONFIG_PPC64
-	printf("  paca    = 0x%lx\n", get_paca());
+	printf("  paca    = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
+	       local_paca, local_paca->soft_enabled, local_paca->irq_happened);
 #endif
 	if (current) {
 		printf("    pid   = %ld, comm = %s\n",
@@ -1634,25 +1635,6 @@
 		       mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
 		printf("sp   = "REG"  sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
 		printf("toc  = "REG"  dar  = "REG"\n", toc, mfspr(SPRN_DAR));
-#ifdef CONFIG_PPC_ISERIES
-		if (firmware_has_feature(FW_FEATURE_ISERIES)) {
-			struct paca_struct *ptrPaca;
-			struct lppaca *ptrLpPaca;
-
-			/* Dump out relevant Paca data areas. */
-			printf("Paca: \n");
-			ptrPaca = get_paca();
-
-			printf("  Local Processor Control Area (LpPaca): \n");
-			ptrLpPaca = ptrPaca->lppaca_ptr;
-			printf("    Saved Srr0=%.16lx  Saved Srr1=%.16lx \n",
-			       ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
-			printf("    Saved Gpr3=%.16lx  Saved Gpr4=%.16lx \n",
-			       ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
-			printf("    Saved Gpr5=%.16lx \n",
-				ptrLpPaca->gpr5_dword.saved_gpr5);
-		}
-#endif
 
 		return;
 	}
@@ -2644,7 +2626,7 @@
 static void dump_stab(void)
 {
 	int i;
-	unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
+	unsigned long *tmp = (unsigned long *)local_paca->stab_addr;
 
 	printf("Segment table contents of cpu %x\n", smp_processor_id());
 
@@ -2855,10 +2837,6 @@
 
 static void xmon_init(int enable)
 {
-#ifdef CONFIG_PPC_ISERIES
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		return;
-#endif
 	if (enable) {
 		__debugger = xmon;
 		__debugger_ipi = xmon_ipi;
@@ -2895,10 +2873,6 @@
 
 static int __init setup_xmon_sysrq(void)
 {
-#ifdef CONFIG_PPC_ISERIES
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		return 0;
-#endif
 	register_sysrq_key('x', &sysrq_xmon_op);
 	return 0;
 }
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 6d99a5f..2b7c0fb 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -64,6 +64,7 @@
 config S390
 	def_bool y
 	select USE_GENERIC_SMP_HELPERS if SMP
+	select GENERIC_CPU_DEVICES if !SMP
 	select HAVE_SYSCALL_WRAPPERS
 	select HAVE_FUNCTION_TRACER
 	select HAVE_FUNCTION_TRACE_MCOUNT_TEST
@@ -218,6 +219,7 @@
 	prompt "Kernel support for 31 bit emulation"
 	depends on 64BIT
 	select COMPAT_BINFMT_ELF
+	select ARCH_WANT_OLD_COMPAT_IPC
 	help
 	  Select this option if you want to enable your system kernel to
 	  handle system-calls from ELF binaries for 31 bit ESA.  This option
diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h
index ffd1ac2..9178db6 100644
--- a/arch/s390/crypto/crypt_s390.h
+++ b/arch/s390/crypto/crypt_s390.h
@@ -17,6 +17,7 @@
 #define _CRYPTO_ARCH_S390_CRYPT_S390_H
 
 #include <asm/errno.h>
+#include <asm/facility.h>
 
 #define CRYPT_S390_OP_MASK 0xFF00
 #define CRYPT_S390_FUNC_MASK 0x00FF
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index 8a2a887..6a2cb56 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -293,11 +293,9 @@
 		return -ENOMEM;
 	root_inode->i_op = &simple_dir_inode_operations;
 	root_inode->i_fop = &simple_dir_operations;
-	sb->s_root = root_dentry = d_alloc_root(root_inode);
-	if (!root_dentry) {
-		iput(root_inode);
+	sb->s_root = root_dentry = d_make_root(root_inode);
+	if (!root_dentry)
 		return -ENOMEM;
-	}
 	if (MACHINE_IS_VM)
 		rc = hypfs_vm_create_files(sb, root_dentry);
 	else
diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h
index 8517d2a..748347b 100644
--- a/arch/s390/include/asm/atomic.h
+++ b/arch/s390/include/asm/atomic.h
@@ -15,7 +15,7 @@
 
 #include <linux/compiler.h>
 #include <linux/types.h>
-#include <asm/system.h>
+#include <asm/cmpxchg.h>
 
 #define ATOMIC_INIT(i)  { (i) }
 
diff --git a/arch/s390/include/asm/barrier.h b/arch/s390/include/asm/barrier.h
new file mode 100644
index 0000000..451273a
--- /dev/null
+++ b/arch/s390/include/asm/barrier.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright IBM Corp. 1999, 2009
+ *
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#ifndef __ASM_BARRIER_H
+#define __ASM_BARRIER_H
+
+/*
+ * Force strict CPU ordering.
+ * And yes, this is required on UP too when we're talking
+ * to devices.
+ *
+ * This is very similar to the ppc eieio/sync instruction in that is
+ * does a checkpoint syncronisation & makes sure that 
+ * all memory ops have completed wrt other CPU's ( see 7-15 POP  DJB ).
+ */
+
+#define eieio()	asm volatile("bcr 15,0" : : : "memory")
+#define SYNC_OTHER_CORES(x)   eieio()
+#define mb()    eieio()
+#define rmb()   eieio()
+#define wmb()   eieio()
+#define read_barrier_depends() do { } while(0)
+#define smp_mb()       mb()
+#define smp_rmb()      rmb()
+#define smp_wmb()      wmb()
+#define smp_read_barrier_depends()    read_barrier_depends()
+#define smp_mb__before_clear_bit()     smp_mb()
+#define smp_mb__after_clear_bit()      smp_mb()
+
+#define set_mb(var, value)      do { var = value; mb(); } while (0)
+
+#endif /* __ASM_BARRIER_H */
diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h
new file mode 100644
index 0000000..a3afecd
--- /dev/null
+++ b/arch/s390/include/asm/cpu_mf.h
@@ -0,0 +1,97 @@
+/*
+ * CPU-measurement facilities
+ *
+ *  Copyright IBM Corp. 2012
+ *  Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+ *	       Jan Glauber <jang@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 (version 2 only)
+ * as published by the Free Software Foundation.
+ */
+#ifndef _ASM_S390_CPU_MF_H
+#define _ASM_S390_CPU_MF_H
+
+#include <asm/facility.h>
+
+#define CPU_MF_INT_SF_IAE	(1 << 31)	/* invalid entry address */
+#define CPU_MF_INT_SF_ISE	(1 << 30)	/* incorrect SDBT entry */
+#define CPU_MF_INT_SF_PRA	(1 << 29)	/* program request alert */
+#define CPU_MF_INT_SF_SACA	(1 << 23)	/* sampler auth. change alert */
+#define CPU_MF_INT_SF_LSDA	(1 << 22)	/* loss of sample data alert */
+#define CPU_MF_INT_CF_CACA	(1 <<  7)	/* counter auth. change alert */
+#define CPU_MF_INT_CF_LCDA	(1 <<  6)	/* loss of counter data alert */
+
+#define CPU_MF_INT_CF_MASK	(CPU_MF_INT_CF_CACA|CPU_MF_INT_CF_LCDA)
+#define CPU_MF_INT_SF_MASK	(CPU_MF_INT_SF_IAE|CPU_MF_INT_SF_ISE|	\
+				 CPU_MF_INT_SF_PRA|CPU_MF_INT_SF_SACA|	\
+				 CPU_MF_INT_SF_LSDA)
+
+/* CPU measurement facility support */
+static inline int cpum_cf_avail(void)
+{
+	return MACHINE_HAS_SPP && test_facility(67);
+}
+
+static inline int cpum_sf_avail(void)
+{
+	return MACHINE_HAS_SPP && test_facility(68);
+}
+
+
+struct cpumf_ctr_info {
+	u16   cfvn;
+	u16   auth_ctl;
+	u16   enable_ctl;
+	u16   act_ctl;
+	u16   max_cpu;
+	u16   csvn;
+	u16   max_cg;
+	u16   reserved1;
+	u32   reserved2[12];
+} __packed;
+
+/* Query counter information */
+static inline int qctri(struct cpumf_ctr_info *info)
+{
+	int rc = -EINVAL;
+
+	asm volatile (
+		"0:	.insn	s,0xb28e0000,%1\n"
+		"1:	lhi	%0,0\n"
+		"2:\n"
+		EX_TABLE(1b, 2b)
+		: "+d" (rc), "=Q" (*info));
+	return rc;
+}
+
+/* Load CPU-counter-set controls */
+static inline int lcctl(u64 ctl)
+{
+	int cc;
+
+	asm volatile (
+		"	.insn	s,0xb2840000,%1\n"
+		"	ipm	%0\n"
+		"	srl	%0,28\n"
+		: "=d" (cc) : "m" (ctl) : "cc");
+	return cc;
+}
+
+/* Extract CPU counter */
+static inline int ecctr(u64 ctr, u64 *val)
+{
+	register u64 content asm("4") = 0;
+	int cc;
+
+	asm volatile (
+		"	.insn	rre,0xb2e40000,%0,%2\n"
+		"	ipm	%1\n"
+		"	srl	%1,28\n"
+		: "=d" (content), "=d" (cc) : "d" (ctr) : "cc");
+	if (!cc)
+		*val = content;
+	return cc;
+}
+
+#endif /* _ASM_S390_CPU_MF_H */
diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h
index c23c390..24ef186 100644
--- a/arch/s390/include/asm/cputime.h
+++ b/arch/s390/include/asm/cputime.h
@@ -170,24 +170,17 @@
 	unsigned int sequence;
 	unsigned long long idle_count;
 	unsigned long long idle_enter;
+	unsigned long long idle_exit;
 	unsigned long long idle_time;
 	int nohz_delay;
 };
 
 DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
 
-void vtime_start_cpu(__u64 int_clock, __u64 enter_timer);
 cputime64_t s390_get_idle_time(int cpu);
 
 #define arch_idle_time(cpu) s390_get_idle_time(cpu)
 
-static inline void s390_idle_check(struct pt_regs *regs, __u64 int_clock,
-				   __u64 enter_timer)
-{
-	if (regs->psw.mask & PSW_MASK_WAIT)
-		vtime_start_cpu(int_clock, enter_timer);
-}
-
 static inline int s390_nohz_delay(int cpu)
 {
 	return __get_cpu_var(s390_idle).nohz_delay != 0;
diff --git a/arch/s390/include/asm/ctl_reg.h b/arch/s390/include/asm/ctl_reg.h
new file mode 100644
index 0000000..ecde941
--- /dev/null
+++ b/arch/s390/include/asm/ctl_reg.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright IBM Corp. 1999, 2009
+ *
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#ifndef __ASM_CTL_REG_H
+#define __ASM_CTL_REG_H
+
+#ifdef __s390x__
+
+#define __ctl_load(array, low, high) ({				\
+	typedef struct { char _[sizeof(array)]; } addrtype;	\
+	asm volatile(						\
+		"	lctlg	%1,%2,%0\n"			\
+		: : "Q" (*(addrtype *)(&array)),		\
+		    "i" (low), "i" (high));			\
+	})
+
+#define __ctl_store(array, low, high) ({			\
+	typedef struct { char _[sizeof(array)]; } addrtype;	\
+	asm volatile(						\
+		"	stctg	%1,%2,%0\n"			\
+		: "=Q" (*(addrtype *)(&array))			\
+		: "i" (low), "i" (high));			\
+	})
+
+#else /* __s390x__ */
+
+#define __ctl_load(array, low, high) ({				\
+	typedef struct { char _[sizeof(array)]; } addrtype;	\
+	asm volatile(						\
+		"	lctl	%1,%2,%0\n"			\
+		: : "Q" (*(addrtype *)(&array)),		\
+		    "i" (low), "i" (high));			\
+})
+
+#define __ctl_store(array, low, high) ({			\
+	typedef struct { char _[sizeof(array)]; } addrtype;	\
+	asm volatile(						\
+		"	stctl	%1,%2,%0\n"			\
+		: "=Q" (*(addrtype *)(&array))			\
+		: "i" (low), "i" (high));			\
+	})
+
+#endif /* __s390x__ */
+
+#define __ctl_set_bit(cr, bit) ({	\
+	unsigned long __dummy;		\
+	__ctl_store(__dummy, cr, cr);	\
+	__dummy |= 1UL << (bit);	\
+	__ctl_load(__dummy, cr, cr);	\
+})
+
+#define __ctl_clear_bit(cr, bit) ({	\
+	unsigned long __dummy;		\
+	__ctl_store(__dummy, cr, cr);	\
+	__dummy &= ~(1UL << (bit));	\
+	__ctl_load(__dummy, cr, cr);	\
+})
+
+#ifdef CONFIG_SMP
+
+extern void smp_ctl_set_bit(int cr, int bit);
+extern void smp_ctl_clear_bit(int cr, int bit);
+#define ctl_set_bit(cr, bit) smp_ctl_set_bit(cr, bit)
+#define ctl_clear_bit(cr, bit) smp_ctl_clear_bit(cr, bit)
+
+#else
+
+#define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit)
+#define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit)
+
+#endif /* CONFIG_SMP */
+
+#endif /* __ASM_CTL_REG_H */
diff --git a/arch/s390/include/asm/debug.h b/arch/s390/include/asm/debug.h
index 9d88db1..8a8245e 100644
--- a/arch/s390/include/asm/debug.h
+++ b/arch/s390/include/asm/debug.h
@@ -131,6 +131,7 @@
 
 void debug_set_level(debug_info_t* id, int new_level);
 
+void debug_set_critical(void);
 void debug_stop_all(void);
 
 static inline debug_entry_t*
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h
index 547f1a6..c4ee39f 100644
--- a/arch/s390/include/asm/elf.h
+++ b/arch/s390/include/asm/elf.h
@@ -129,7 +129,6 @@
 typedef s390_compat_regs compat_elf_gregset_t;
 
 #include <linux/sched.h>	/* for task_struct */
-#include <asm/system.h>		/* for save_access_regs */
 #include <asm/mmu_context.h>
 
 #include <asm/vdso.h>
diff --git a/arch/s390/include/asm/exec.h b/arch/s390/include/asm/exec.h
new file mode 100644
index 0000000..c4a93d6
--- /dev/null
+++ b/arch/s390/include/asm/exec.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright IBM Corp. 1999, 2009
+ *
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#ifndef __ASM_EXEC_H
+#define __ASM_EXEC_H
+
+extern unsigned long arch_align_stack(unsigned long sp);
+
+#endif /* __ASM_EXEC_H */
diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h
new file mode 100644
index 0000000..1e5b27e
--- /dev/null
+++ b/arch/s390/include/asm/facility.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright IBM Corp. 1999, 2009
+ *
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#ifndef __ASM_FACILITY_H
+#define __ASM_FACILITY_H
+
+#include <linux/string.h>
+#include <linux/preempt.h>
+#include <asm/lowcore.h>
+
+#define MAX_FACILITY_BIT (256*8)	/* stfle_fac_list has 256 bytes */
+
+/*
+ * The test_facility function uses the bit odering where the MSB is bit 0.
+ * That makes it easier to query facility bits with the bit number as
+ * documented in the Principles of Operation.
+ */
+static inline int test_facility(unsigned long nr)
+{
+	unsigned char *ptr;
+
+	if (nr >= MAX_FACILITY_BIT)
+		return 0;
+	ptr = (unsigned char *) &S390_lowcore.stfle_fac_list + (nr >> 3);
+	return (*ptr & (0x80 >> (nr & 7))) != 0;
+}
+
+/**
+ * stfle - Store facility list extended
+ * @stfle_fac_list: array where facility list can be stored
+ * @size: size of passed in array in double words
+ */
+static inline void stfle(u64 *stfle_fac_list, int size)
+{
+	unsigned long nr;
+
+	preempt_disable();
+	S390_lowcore.stfl_fac_list = 0;
+	asm volatile(
+		"	.insn s,0xb2b10000,0(0)\n" /* stfl */
+		"0:\n"
+		EX_TABLE(0b, 0b)
+		: "=m" (S390_lowcore.stfl_fac_list));
+	nr = 4; /* bytes stored by stfl */
+	memcpy(stfle_fac_list, &S390_lowcore.stfl_fac_list, 4);
+	if (S390_lowcore.stfl_fac_list & 0x01000000) {
+		/* More facility bits available with stfle */
+		register unsigned long reg0 asm("0") = size - 1;
+
+		asm volatile(".insn s,0xb2b00000,0(%1)" /* stfle */
+			     : "+d" (reg0)
+			     : "a" (stfle_fac_list)
+			     : "memory", "cc");
+		nr = (reg0 + 1) * 8; /* # bytes stored by stfle */
+	}
+	memset((char *) stfle_fac_list + nr, 0, size * 8 - nr);
+	preempt_enable();
+}
+
+#endif /* __ASM_FACILITY_H */
diff --git a/arch/s390/include/asm/hardirq.h b/arch/s390/include/asm/hardirq.h
index e4155d3..510ba9e 100644
--- a/arch/s390/include/asm/hardirq.h
+++ b/arch/s390/include/asm/hardirq.h
@@ -18,6 +18,7 @@
 
 #define __ARCH_IRQ_STAT
 #define __ARCH_HAS_DO_SOFTIRQ
+#define __ARCH_IRQ_EXIT_IRQS_DISABLED
 
 #define HARDIRQ_BITS	8
 
diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h
index 6940abf..2bd6cb89 100644
--- a/arch/s390/include/asm/ipl.h
+++ b/arch/s390/include/asm/ipl.h
@@ -169,5 +169,6 @@
 extern int diag308(unsigned long subcode, void *addr);
 extern void diag308_reset(void);
 extern void store_status(void);
+extern void lgr_info_log(void);
 
 #endif /* _ASM_S390_IPL_H */
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h
index ba6d85f..5289cac 100644
--- a/arch/s390/include/asm/irq.h
+++ b/arch/s390/include/asm/irq.h
@@ -34,11 +34,18 @@
 	NR_IRQS,
 };
 
-typedef void (*ext_int_handler_t)(unsigned int, unsigned int, unsigned long);
+struct ext_code {
+	unsigned short subcode;
+	unsigned short code;
+};
+
+typedef void (*ext_int_handler_t)(struct ext_code, unsigned int, unsigned long);
 
 int register_external_interrupt(u16 code, ext_int_handler_t handler);
 int unregister_external_interrupt(u16 code, ext_int_handler_t handler);
 void service_subclass_irq_register(void);
 void service_subclass_irq_unregister(void);
+void measurement_alert_subclass_register(void);
+void measurement_alert_subclass_unregister(void);
 
 #endif /* _ASM_IRQ_H */
diff --git a/arch/s390/include/asm/kvm.h b/arch/s390/include/asm/kvm.h
index 82b32a1..9607667 100644
--- a/arch/s390/include/asm/kvm.h
+++ b/arch/s390/include/asm/kvm.h
@@ -41,4 +41,15 @@
 struct kvm_guest_debug_arch {
 };
 
+#define KVM_SYNC_PREFIX (1UL << 0)
+#define KVM_SYNC_GPRS   (1UL << 1)
+#define KVM_SYNC_ACRS   (1UL << 2)
+#define KVM_SYNC_CRS    (1UL << 3)
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+	__u64 prefix;	/* prefix register */
+	__u64 gprs[16];	/* general purpose registers */
+	__u32 acrs[16];	/* access registers */
+	__u64 crs[16];	/* control registers */
+};
 #endif
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index b0c235c..7343872 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -220,18 +220,17 @@
 	struct list_head list;
 	atomic_t active;
 	int next_rr_cpu;
-	unsigned long idle_mask [(64 + sizeof(long) - 1) / sizeof(long)];
-	struct kvm_s390_local_interrupt *local_int[64];
+	unsigned long idle_mask[(KVM_MAX_VCPUS + sizeof(long) - 1)
+				/ sizeof(long)];
+	struct kvm_s390_local_interrupt *local_int[KVM_MAX_VCPUS];
 };
 
 
 struct kvm_vcpu_arch {
 	struct kvm_s390_sie_block *sie_block;
-	unsigned long	  guest_gprs[16];
 	s390_fp_regs      host_fpregs;
 	unsigned int      host_acrs[NUM_ACRS];
 	s390_fp_regs      guest_fpregs;
-	unsigned int      guest_acrs[NUM_ACRS];
 	struct kvm_s390_local_interrupt local_int;
 	struct hrtimer    ckc_timer;
 	struct tasklet_struct tasklet;
@@ -246,6 +245,9 @@
 	u32 remote_tlb_flush;
 };
 
+struct kvm_arch_memory_slot {
+};
+
 struct kvm_arch{
 	struct sca_block *sca;
 	debug_info_t *dbf;
@@ -253,5 +255,5 @@
 	struct gmap *gmap;
 };
 
-extern int sie64a(struct kvm_s390_sie_block *, unsigned long *);
+extern int sie64a(struct kvm_s390_sie_block *, u64 *);
 #endif
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h
index 707f230..47853de 100644
--- a/arch/s390/include/asm/lowcore.h
+++ b/arch/s390/include/asm/lowcore.h
@@ -1,5 +1,5 @@
 /*
- *    Copyright IBM Corp. 1999,2010
+ *    Copyright IBM Corp. 1999,2012
  *    Author(s): Hartmut Penner <hp@de.ibm.com>,
  *		 Martin Schwidefsky <schwidefsky@de.ibm.com>,
  *		 Denis Joseph Barrow,
@@ -12,14 +12,6 @@
 #include <asm/ptrace.h>
 #include <asm/cpu.h>
 
-void restart_int_handler(void);
-void ext_int_handler(void);
-void system_call(void);
-void pgm_check_handler(void);
-void mcck_int_handler(void);
-void io_int_handler(void);
-void psw_restart_int_handler(void);
-
 #ifdef CONFIG_32BIT
 
 #define LC_ORDER 0
@@ -56,7 +48,7 @@
 	psw_t	mcck_new_psw;			/* 0x0070 */
 	psw_t	io_new_psw;			/* 0x0078 */
 	__u32	ext_params;			/* 0x0080 */
-	__u16	cpu_addr;			/* 0x0084 */
+	__u16	ext_cpu_addr;			/* 0x0084 */
 	__u16	ext_int_code;			/* 0x0086 */
 	__u16	svc_ilc;			/* 0x0088 */
 	__u16	svc_code;			/* 0x008a */
@@ -117,32 +109,37 @@
 	__u64	steal_timer;			/* 0x0288 */
 	__u64	last_update_timer;		/* 0x0290 */
 	__u64	last_update_clock;		/* 0x0298 */
+	__u64	int_clock;			/* 0x02a0 */
+	__u64	mcck_clock;			/* 0x02a8 */
+	__u64	clock_comparator;		/* 0x02b0 */
 
 	/* Current process. */
-	__u32	current_task;			/* 0x02a0 */
-	__u32	thread_info;			/* 0x02a4 */
-	__u32	kernel_stack;			/* 0x02a8 */
+	__u32	current_task;			/* 0x02b8 */
+	__u32	thread_info;			/* 0x02bc */
+	__u32	kernel_stack;			/* 0x02c0 */
 
-	/* Interrupt and panic stack. */
-	__u32	async_stack;			/* 0x02ac */
-	__u32	panic_stack;			/* 0x02b0 */
+	/* Interrupt, panic and restart stack. */
+	__u32	async_stack;			/* 0x02c4 */
+	__u32	panic_stack;			/* 0x02c8 */
+	__u32	restart_stack;			/* 0x02cc */
+
+	/* Restart function and parameter. */
+	__u32	restart_fn;			/* 0x02d0 */
+	__u32	restart_data;			/* 0x02d4 */
+	__u32	restart_source;			/* 0x02d8 */
 
 	/* Address space pointer. */
-	__u32	kernel_asce;			/* 0x02b4 */
-	__u32	user_asce;			/* 0x02b8 */
-	__u32	current_pid;			/* 0x02bc */
+	__u32	kernel_asce;			/* 0x02dc */
+	__u32	user_asce;			/* 0x02e0 */
+	__u32	current_pid;			/* 0x02e4 */
 
 	/* SMP info area */
-	__u32	cpu_nr;				/* 0x02c0 */
-	__u32	softirq_pending;		/* 0x02c4 */
-	__u32	percpu_offset;			/* 0x02c8 */
-	__u32	ext_call_fast;			/* 0x02cc */
-	__u64	int_clock;			/* 0x02d0 */
-	__u64	mcck_clock;			/* 0x02d8 */
-	__u64	clock_comparator;		/* 0x02e0 */
-	__u32	machine_flags;			/* 0x02e8 */
-	__u32	ftrace_func;			/* 0x02ec */
-	__u8	pad_0x02f8[0x0300-0x02f0];	/* 0x02f0 */
+	__u32	cpu_nr;				/* 0x02e8 */
+	__u32	softirq_pending;		/* 0x02ec */
+	__u32	percpu_offset;			/* 0x02f0 */
+	__u32	machine_flags;			/* 0x02f4 */
+	__u32	ftrace_func;			/* 0x02f8 */
+	__u8	pad_0x02fc[0x0300-0x02fc];	/* 0x02fc */
 
 	/* Interrupt response block */
 	__u8	irb[64];			/* 0x0300 */
@@ -157,7 +154,9 @@
 	__u32	ipib;				/* 0x0e00 */
 	__u32	ipib_checksum;			/* 0x0e04 */
 	__u32	vmcore_info;			/* 0x0e08 */
-	__u8	pad_0x0e0c[0x0f00-0x0e0c];	/* 0x0e0c */
+	__u8	pad_0x0e0c[0x0e18-0x0e0c];	/* 0x0e0c */
+	__u32	os_info;			/* 0x0e18 */
+	__u8	pad_0x0e1c[0x0f00-0x0e1c];	/* 0x0e1c */
 
 	/* Extended facility list */
 	__u64	stfle_fac_list[32];		/* 0x0f00 */
@@ -189,7 +188,7 @@
 	__u32	ipl_parmblock_ptr;		/* 0x0014 */
 	__u8	pad_0x0018[0x0080-0x0018];	/* 0x0018 */
 	__u32	ext_params;			/* 0x0080 */
-	__u16	cpu_addr;			/* 0x0084 */
+	__u16	ext_cpu_addr;			/* 0x0084 */
 	__u16	ext_int_code;			/* 0x0086 */
 	__u16	svc_ilc;			/* 0x0088 */
 	__u16	svc_code;			/* 0x008a */
@@ -254,34 +253,39 @@
 	__u64	steal_timer;			/* 0x02e0 */
 	__u64	last_update_timer;		/* 0x02e8 */
 	__u64	last_update_clock;		/* 0x02f0 */
+	__u64	int_clock;			/* 0x02f8 */
+	__u64	mcck_clock;			/* 0x0300 */
+	__u64	clock_comparator;		/* 0x0308 */
 
 	/* Current process. */
-	__u64	current_task;			/* 0x02f8 */
-	__u64	thread_info;			/* 0x0300 */
-	__u64	kernel_stack;			/* 0x0308 */
+	__u64	current_task;			/* 0x0310 */
+	__u64	thread_info;			/* 0x0318 */
+	__u64	kernel_stack;			/* 0x0320 */
 
-	/* Interrupt and panic stack. */
-	__u64	async_stack;			/* 0x0310 */
-	__u64	panic_stack;			/* 0x0318 */
+	/* Interrupt, panic and restart stack. */
+	__u64	async_stack;			/* 0x0328 */
+	__u64	panic_stack;			/* 0x0330 */
+	__u64	restart_stack;			/* 0x0338 */
+
+	/* Restart function and parameter. */
+	__u64	restart_fn;			/* 0x0340 */
+	__u64	restart_data;			/* 0x0348 */
+	__u64	restart_source;			/* 0x0350 */
 
 	/* Address space pointer. */
-	__u64	kernel_asce;			/* 0x0320 */
-	__u64	user_asce;			/* 0x0328 */
-	__u64	current_pid;			/* 0x0330 */
+	__u64	kernel_asce;			/* 0x0358 */
+	__u64	user_asce;			/* 0x0360 */
+	__u64	current_pid;			/* 0x0368 */
 
 	/* SMP info area */
-	__u32	cpu_nr;				/* 0x0338 */
-	__u32	softirq_pending;		/* 0x033c */
-	__u64	percpu_offset;			/* 0x0340 */
-	__u64	ext_call_fast;			/* 0x0348 */
-	__u64	int_clock;			/* 0x0350 */
-	__u64	mcck_clock;			/* 0x0358 */
-	__u64	clock_comparator;		/* 0x0360 */
-	__u64	vdso_per_cpu_data;		/* 0x0368 */
-	__u64	machine_flags;			/* 0x0370 */
-	__u64	ftrace_func;			/* 0x0378 */
-	__u64	gmap;				/* 0x0380 */
-	__u8	pad_0x0388[0x0400-0x0388];	/* 0x0388 */
+	__u32	cpu_nr;				/* 0x0370 */
+	__u32	softirq_pending;		/* 0x0374 */
+	__u64	percpu_offset;			/* 0x0378 */
+	__u64	vdso_per_cpu_data;		/* 0x0380 */
+	__u64	machine_flags;			/* 0x0388 */
+	__u64	ftrace_func;			/* 0x0390 */
+	__u64	gmap;				/* 0x0398 */
+	__u8	pad_0x03a0[0x0400-0x03a0];	/* 0x03a0 */
 
 	/* Interrupt response block. */
 	__u8	irb[64];			/* 0x0400 */
@@ -298,8 +302,15 @@
 	 */
 	__u64	ipib;				/* 0x0e00 */
 	__u32	ipib_checksum;			/* 0x0e08 */
-	__u64	vmcore_info;			/* 0x0e0c */
-	__u8	pad_0x0e14[0x0f00-0x0e14];	/* 0x0e14 */
+	/*
+	 * Because the vmcore_info pointer is not 8 byte aligned it never
+	 * should not be accessed directly. For accessing the pointer, first
+	 * copy it to a local pointer variable.
+	 */
+	__u8	vmcore_info[8];			/* 0x0e0c */
+	__u8	pad_0x0e14[0x0e18-0x0e14];	/* 0x0e14 */
+	__u64	os_info;			/* 0x0e18 */
+	__u8	pad_0x0e20[0x0f00-0x0e20];	/* 0x0e20 */
 
 	/* Extended facility list */
 	__u64	stfle_fac_list[32];		/* 0x0f00 */
diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h
index 4506791..6340178 100644
--- a/arch/s390/include/asm/mmu.h
+++ b/arch/s390/include/asm/mmu.h
@@ -1,6 +1,8 @@
 #ifndef __MMU_H
 #define __MMU_H
 
+#include <linux/errno.h>
+
 typedef struct {
 	atomic_t attach_count;
 	unsigned int flush_mm;
@@ -21,4 +23,18 @@
 	.context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list),    \
 	.context.gmap_list = LIST_HEAD_INIT(name.context.gmap_list),
 
+static inline int tprot(unsigned long addr)
+{
+	int rc = -EFAULT;
+
+	asm volatile(
+		"	tprot	0(%1),0\n"
+		"0:	ipm	%0\n"
+		"	srl	%0,28\n"
+		"1:\n"
+		EX_TABLE(0b,1b)
+		: "+d" (rc) : "a" (addr) : "cc");
+	return rc;
+}
+
 #endif
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h
index 5682f16..5d09e40 100644
--- a/arch/s390/include/asm/mmu_context.h
+++ b/arch/s390/include/asm/mmu_context.h
@@ -12,6 +12,7 @@
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
 #include <asm/tlbflush.h>
+#include <asm/ctl_reg.h>
 #include <asm-generic/mm_hooks.h>
 
 static inline int init_new_context(struct task_struct *tsk,
diff --git a/arch/s390/include/asm/os_info.h b/arch/s390/include/asm/os_info.h
new file mode 100644
index 0000000..d07518a
--- /dev/null
+++ b/arch/s390/include/asm/os_info.h
@@ -0,0 +1,50 @@
+/*
+ * OS info memory interface
+ *
+ * Copyright IBM Corp. 2012
+ * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+#ifndef _ASM_S390_OS_INFO_H
+#define _ASM_S390_OS_INFO_H
+
+#define OS_INFO_VERSION_MAJOR	1
+#define OS_INFO_VERSION_MINOR	1
+#define OS_INFO_MAGIC		0x4f53494e464f535aULL /* OSINFOSZ */
+
+#define OS_INFO_VMCOREINFO	0
+#define OS_INFO_REIPL_BLOCK	1
+#define OS_INFO_INIT_FN		2
+
+struct os_info_entry {
+	u64	addr;
+	u64	size;
+	u32	csum;
+} __packed;
+
+struct os_info {
+	u64	magic;
+	u32	csum;
+	u16	version_major;
+	u16	version_minor;
+	u64	crashkernel_addr;
+	u64	crashkernel_size;
+	struct os_info_entry entry[3];
+	u8	reserved[4004];
+} __packed;
+
+void os_info_init(void);
+void os_info_entry_add(int nr, void *ptr, u64 len);
+void os_info_crashkernel_add(unsigned long base, unsigned long size);
+u32 os_info_csum(struct os_info *os_info);
+
+#ifdef CONFIG_CRASH_DUMP
+void *os_info_old_entry(int nr, unsigned long *size);
+int copy_from_oldmem(void *dest, void *src, size_t count);
+#else
+static inline void *os_info_old_entry(int nr, unsigned long *size)
+{
+	return NULL;
+}
+#endif
+
+#endif /* _ASM_S390_OS_INFO_H */
diff --git a/arch/s390/include/asm/perf_event.h b/arch/s390/include/asm/perf_event.h
index 4eb444e..7941968 100644
--- a/arch/s390/include/asm/perf_event.h
+++ b/arch/s390/include/asm/perf_event.h
@@ -1,8 +1,16 @@
 /*
  * Performance event support - s390 specific definitions.
  *
- * Copyright 2009 Martin Schwidefsky, IBM Corporation.
+ * Copyright IBM Corp. 2009, 2012
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *	      Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
  */
 
-/* Empty, just to avoid compiling error */
+#include <asm/cpu_mf.h>
 
+/* CPU-measurement counter facility */
+#define PERF_CPUM_CF_MAX_CTR		160
+
+/* Per-CPU flags for PMU states */
+#define PMU_F_RESERVED			0x1000
+#define PMU_F_ENABLED			0x2000
diff --git a/arch/s390/include/asm/posix_types.h b/arch/s390/include/asm/posix_types.h
index 8cc113f..edf8527 100644
--- a/arch/s390/include/asm/posix_types.h
+++ b/arch/s390/include/asm/posix_types.h
@@ -3,7 +3,6 @@
  *
  *  S390 version
  *
- *  Derived from "include/asm-i386/posix_types.h"
  */
 
 #ifndef __ARCH_S390_POSIX_TYPES_H
@@ -15,22 +14,11 @@
  * assume GCC is being used.
  */
 
-typedef long            __kernel_off_t;
-typedef int             __kernel_pid_t;
 typedef unsigned long   __kernel_size_t;
-typedef long            __kernel_time_t;
-typedef long            __kernel_suseconds_t;
-typedef long            __kernel_clock_t;
-typedef int		__kernel_timer_t;
-typedef int		__kernel_clockid_t;
-typedef int             __kernel_daddr_t;
-typedef char *          __kernel_caddr_t;
-typedef unsigned short	__kernel_uid16_t;
-typedef unsigned short	__kernel_gid16_t;
+#define __kernel_size_t __kernel_size_t
 
-#ifdef __GNUC__
-typedef long long       __kernel_loff_t;
-#endif
+typedef unsigned short	__kernel_old_dev_t;
+#define __kernel_old_dev_t __kernel_old_dev_t
 
 #ifndef __s390x__
 
@@ -42,11 +30,6 @@
 typedef unsigned short  __kernel_gid_t;
 typedef int             __kernel_ssize_t;
 typedef int             __kernel_ptrdiff_t;
-typedef unsigned int	__kernel_uid32_t;
-typedef unsigned int	__kernel_gid32_t;
-typedef unsigned short	__kernel_old_uid_t;
-typedef unsigned short	__kernel_old_gid_t;
-typedef unsigned short	__kernel_old_dev_t;
 
 #else /* __s390x__ */
 
@@ -59,49 +42,16 @@
 typedef long            __kernel_ssize_t;
 typedef long            __kernel_ptrdiff_t;
 typedef unsigned long   __kernel_sigset_t;      /* at least 32 bits */
-typedef __kernel_uid_t __kernel_old_uid_t;
-typedef __kernel_gid_t __kernel_old_gid_t;
-typedef __kernel_uid_t __kernel_uid32_t;
-typedef __kernel_gid_t __kernel_gid32_t;
-typedef unsigned short __kernel_old_dev_t;
 
 #endif /* __s390x__ */
 
-typedef struct {
-        int     val[2];
-} __kernel_fsid_t;
+#define __kernel_ino_t  __kernel_ino_t
+#define __kernel_mode_t __kernel_mode_t
+#define __kernel_nlink_t __kernel_nlink_t
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
+#define __kernel_uid_t __kernel_uid_t
+#define __kernel_gid_t __kernel_gid_t
 
-
-#ifdef __KERNEL__
-
-#undef __FD_SET
-static inline void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	fdsetp->fds_bits[_tmp] |= (1UL<<_rem);
-}
-
-#undef __FD_CLR
-static inline void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem);
-}
-
-#undef __FD_ISSET
-static inline int __FD_ISSET(unsigned long fd, const __kernel_fd_set *fdsetp)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	return (fdsetp->fds_bits[_tmp] & (1UL<<_rem)) != 0;
-}
-
-#undef  __FD_ZERO
-#define __FD_ZERO(fdsetp) \
-	((void) memset ((void *) (fdsetp), 0, sizeof (__kernel_fd_set)))
-
-#endif     /* __KERNEL__ */
+#include <asm-generic/posix_types.h>
 
 #endif
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index d25843a..d499b30 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -14,6 +14,7 @@
 #define __ASM_S390_PROCESSOR_H
 
 #include <linux/linkage.h>
+#include <linux/irqflags.h>
 #include <asm/cpu.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
@@ -156,6 +157,14 @@
 #define KSTK_EIP(tsk)	(task_pt_regs(tsk)->psw.addr)
 #define KSTK_ESP(tsk)	(task_pt_regs(tsk)->gprs[15])
 
+static inline unsigned short stap(void)
+{
+	unsigned short cpu_address;
+
+	asm volatile("stap %0" : "=m" (cpu_address));
+	return cpu_address;
+}
+
 /*
  * Give up the time slice of the virtual PU.
  */
@@ -304,6 +313,21 @@
 }
 
 /*
+ * Use to set psw mask except for the first byte which
+ * won't be changed by this function.
+ */
+static inline void
+__set_psw_mask(unsigned long mask)
+{
+	__load_psw_mask(mask | (arch_local_save_flags() & ~(-1UL >> 8)));
+}
+
+#define local_mcck_enable() \
+	__set_psw_mask(psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_MCHECK)
+#define local_mcck_disable() \
+	__set_psw_mask(psw_kernel_bits | PSW_MASK_DAT)
+
+/*
  * Basic Machine Check/Program Check Handler.
  */
 
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index 097183c..b21e46e 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -140,6 +140,20 @@
 #define NSS_NAME_SIZE	8
 extern char kernel_nss_name[];
 
+#ifdef CONFIG_PFAULT
+extern int pfault_init(void);
+extern void pfault_fini(void);
+#else /* CONFIG_PFAULT */
+#define pfault_init()		({-1;})
+#define pfault_fini()		do { } while (0)
+#endif /* CONFIG_PFAULT */
+
+extern void cmma_init(void);
+
+extern void (*_machine_restart)(char *command);
+extern void (*_machine_halt)(void);
+extern void (*_machine_power_off)(void);
+
 #else /* __ASSEMBLY__ */
 
 #ifndef __s390x__
diff --git a/arch/s390/include/asm/sigp.h b/arch/s390/include/asm/sigp.h
deleted file mode 100644
index 7040b85..0000000
--- a/arch/s390/include/asm/sigp.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- *  Routines and structures for signalling other processors.
- *
- *    Copyright IBM Corp. 1999,2010
- *    Author(s): Denis Joseph Barrow,
- *		 Martin Schwidefsky <schwidefsky@de.ibm.com>,
- *		 Heiko Carstens <heiko.carstens@de.ibm.com>,
- */
-
-#ifndef __ASM_SIGP_H
-#define __ASM_SIGP_H
-
-#include <asm/system.h>
-
-/* Get real cpu address from logical cpu number. */
-extern unsigned short __cpu_logical_map[];
-
-static inline int cpu_logical_map(int cpu)
-{
-#ifdef CONFIG_SMP
-	return __cpu_logical_map[cpu];
-#else
-	return stap();
-#endif
-}
-
-enum {
-	sigp_sense = 1,
-	sigp_external_call = 2,
-	sigp_emergency_signal = 3,
-	sigp_start = 4,
-	sigp_stop = 5,
-	sigp_restart = 6,
-	sigp_stop_and_store_status = 9,
-	sigp_initial_cpu_reset = 11,
-	sigp_cpu_reset = 12,
-	sigp_set_prefix = 13,
-	sigp_store_status_at_address = 14,
-	sigp_store_extended_status_at_address = 15,
-	sigp_set_architecture = 18,
-	sigp_conditional_emergency_signal = 19,
-	sigp_sense_running = 21,
-};
-
-enum {
-	sigp_order_code_accepted = 0,
-	sigp_status_stored = 1,
-	sigp_busy = 2,
-	sigp_not_operational = 3,
-};
-
-/*
- * Definitions for external call.
- */
-enum {
-	ec_schedule = 0,
-	ec_call_function,
-	ec_call_function_single,
-	ec_stop_cpu,
-};
-
-/*
- * Signal processor.
- */
-static inline int raw_sigp(u16 cpu, int order)
-{
-	register unsigned long reg1 asm ("1") = 0;
-	int ccode;
-
-	asm volatile(
-		"	sigp	%1,%2,0(%3)\n"
-		"	ipm	%0\n"
-		"	srl	%0,28\n"
-		:	"=d"	(ccode)
-		: "d" (reg1), "d" (cpu),
-		  "a" (order) : "cc" , "memory");
-	return ccode;
-}
-
-/*
- * Signal processor with parameter.
- */
-static inline int raw_sigp_p(u32 parameter, u16 cpu, int order)
-{
-	register unsigned int reg1 asm ("1") = parameter;
-	int ccode;
-
-	asm volatile(
-		"	sigp	%1,%2,0(%3)\n"
-		"	ipm	%0\n"
-		"	srl	%0,28\n"
-		: "=d" (ccode)
-		: "d" (reg1), "d" (cpu),
-		  "a" (order) : "cc" , "memory");
-	return ccode;
-}
-
-/*
- * Signal processor with parameter and return status.
- */
-static inline int raw_sigp_ps(u32 *status, u32 parm, u16 cpu, int order)
-{
-	register unsigned int reg1 asm ("1") = parm;
-	int ccode;
-
-	asm volatile(
-		"	sigp	%1,%2,0(%3)\n"
-		"	ipm	%0\n"
-		"	srl	%0,28\n"
-		: "=d" (ccode), "+d" (reg1)
-		: "d" (cpu), "a" (order)
-		: "cc" , "memory");
-	*status = reg1;
-	return ccode;
-}
-
-static inline int sigp(int cpu, int order)
-{
-	return raw_sigp(cpu_logical_map(cpu), order);
-}
-
-static inline int sigp_p(u32 parameter, int cpu, int order)
-{
-	return raw_sigp_p(parameter, cpu_logical_map(cpu), order);
-}
-
-static inline int sigp_ps(u32 *status, u32 parm, int cpu, int order)
-{
-	return raw_sigp_ps(status, parm, cpu_logical_map(cpu), order);
-}
-
-#endif /* __ASM_SIGP_H */
diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h
index c32e912..c77c6de 100644
--- a/arch/s390/include/asm/smp.h
+++ b/arch/s390/include/asm/smp.h
@@ -1,5 +1,5 @@
 /*
- *    Copyright IBM Corp. 1999,2009
+ *    Copyright IBM Corp. 1999,2012
  *    Author(s): Denis Joseph Barrow,
  *		 Martin Schwidefsky <schwidefsky@de.ibm.com>,
  *		 Heiko Carstens <heiko.carstens@de.ibm.com>,
@@ -9,72 +9,53 @@
 
 #ifdef CONFIG_SMP
 
-#include <asm/system.h>
-#include <asm/sigp.h>
-
-extern void machine_restart_smp(char *);
-extern void machine_halt_smp(void);
-extern void machine_power_off_smp(void);
+#include <asm/lowcore.h>
 
 #define raw_smp_processor_id()	(S390_lowcore.cpu_nr)
 
-extern int __cpu_disable (void);
-extern void __cpu_die (unsigned int cpu);
-extern int __cpu_up (unsigned int cpu);
-
 extern struct mutex smp_cpu_state_mutex;
+extern struct save_area *zfcpdump_save_areas[NR_CPUS + 1];
+
+extern int __cpu_up(unsigned int cpu);
 
 extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 
-extern struct save_area *zfcpdump_save_areas[NR_CPUS + 1];
+extern void smp_call_online_cpu(void (*func)(void *), void *);
+extern void smp_call_ipl_cpu(void (*func)(void *), void *);
 
-extern void smp_switch_to_ipl_cpu(void (*func)(void *), void *);
-extern void smp_switch_to_cpu(void (*)(void *), void *, unsigned long sp,
-			      int from, int to);
-extern void smp_restart_with_online_cpu(void);
-extern void smp_restart_cpu(void);
-
-/*
- * returns 1 if (virtual) cpu is scheduled
- * returns 0 otherwise
- */
-static inline int smp_vcpu_scheduled(int cpu)
-{
-	u32 status;
-
-	switch (sigp_ps(&status, 0, cpu, sigp_sense_running)) {
-	case sigp_status_stored:
-		/* Check for running status */
-		if (status & 0x400)
-			return 0;
-		break;
-	case sigp_not_operational:
-		return 0;
-	default:
-		break;
-	}
-	return 1;
-}
+extern int smp_find_processor_id(u16 address);
+extern int smp_store_status(int cpu);
+extern int smp_vcpu_scheduled(int cpu);
+extern void smp_yield_cpu(int cpu);
+extern void smp_yield(void);
+extern void smp_stop_cpu(void);
 
 #else /* CONFIG_SMP */
 
-static inline void smp_switch_to_ipl_cpu(void (*func)(void *), void *data)
+static inline void smp_call_ipl_cpu(void (*func)(void *), void *data)
 {
 	func(data);
 }
 
-static inline void smp_restart_with_online_cpu(void)
+static inline void smp_call_online_cpu(void (*func)(void *), void *data)
 {
+	func(data);
 }
 
-#define smp_vcpu_scheduled	(1)
+static inline int smp_find_processor_id(int address) { return 0; }
+static inline int smp_vcpu_scheduled(int cpu) { return 1; }
+static inline void smp_yield_cpu(int cpu) { }
+static inline void smp_yield(void) { }
+static inline void smp_stop_cpu(void) { }
 
 #endif /* CONFIG_SMP */
 
 #ifdef CONFIG_HOTPLUG_CPU
 extern int smp_rescan_cpus(void);
 extern void __noreturn cpu_die(void);
+extern void __cpu_die(unsigned int cpu);
+extern int __cpu_disable(void);
 #else
 static inline int smp_rescan_cpus(void) { return 0; }
 static inline void cpu_die(void) { }
diff --git a/arch/s390/include/asm/switch_to.h b/arch/s390/include/asm/switch_to.h
new file mode 100644
index 0000000..f223068
--- /dev/null
+++ b/arch/s390/include/asm/switch_to.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright IBM Corp. 1999, 2009
+ *
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#ifndef __ASM_SWITCH_TO_H
+#define __ASM_SWITCH_TO_H
+
+#include <linux/thread_info.h>
+
+extern struct task_struct *__switch_to(void *, void *);
+extern void update_per_regs(struct task_struct *task);
+
+static inline void save_fp_regs(s390_fp_regs *fpregs)
+{
+	asm volatile(
+		"	std	0,%O0+8(%R0)\n"
+		"	std	2,%O0+24(%R0)\n"
+		"	std	4,%O0+40(%R0)\n"
+		"	std	6,%O0+56(%R0)"
+		: "=Q" (*fpregs) : "Q" (*fpregs));
+	if (!MACHINE_HAS_IEEE)
+		return;
+	asm volatile(
+		"	stfpc	%0\n"
+		"	std	1,%O0+16(%R0)\n"
+		"	std	3,%O0+32(%R0)\n"
+		"	std	5,%O0+48(%R0)\n"
+		"	std	7,%O0+64(%R0)\n"
+		"	std	8,%O0+72(%R0)\n"
+		"	std	9,%O0+80(%R0)\n"
+		"	std	10,%O0+88(%R0)\n"
+		"	std	11,%O0+96(%R0)\n"
+		"	std	12,%O0+104(%R0)\n"
+		"	std	13,%O0+112(%R0)\n"
+		"	std	14,%O0+120(%R0)\n"
+		"	std	15,%O0+128(%R0)\n"
+		: "=Q" (*fpregs) : "Q" (*fpregs));
+}
+
+static inline void restore_fp_regs(s390_fp_regs *fpregs)
+{
+	asm volatile(
+		"	ld	0,%O0+8(%R0)\n"
+		"	ld	2,%O0+24(%R0)\n"
+		"	ld	4,%O0+40(%R0)\n"
+		"	ld	6,%O0+56(%R0)"
+		: : "Q" (*fpregs));
+	if (!MACHINE_HAS_IEEE)
+		return;
+	asm volatile(
+		"	lfpc	%0\n"
+		"	ld	1,%O0+16(%R0)\n"
+		"	ld	3,%O0+32(%R0)\n"
+		"	ld	5,%O0+48(%R0)\n"
+		"	ld	7,%O0+64(%R0)\n"
+		"	ld	8,%O0+72(%R0)\n"
+		"	ld	9,%O0+80(%R0)\n"
+		"	ld	10,%O0+88(%R0)\n"
+		"	ld	11,%O0+96(%R0)\n"
+		"	ld	12,%O0+104(%R0)\n"
+		"	ld	13,%O0+112(%R0)\n"
+		"	ld	14,%O0+120(%R0)\n"
+		"	ld	15,%O0+128(%R0)\n"
+		: : "Q" (*fpregs));
+}
+
+static inline void save_access_regs(unsigned int *acrs)
+{
+	asm volatile("stam 0,15,%0" : "=Q" (*acrs));
+}
+
+static inline void restore_access_regs(unsigned int *acrs)
+{
+	asm volatile("lam 0,15,%0" : : "Q" (*acrs));
+}
+
+#define switch_to(prev,next,last) do {					\
+	if (prev->mm) {							\
+		save_fp_regs(&prev->thread.fp_regs);			\
+		save_access_regs(&prev->thread.acrs[0]);		\
+	}								\
+	if (next->mm) {							\
+		restore_fp_regs(&next->thread.fp_regs);			\
+		restore_access_regs(&next->thread.acrs[0]);		\
+		update_per_regs(next);					\
+	}								\
+	prev = __switch_to(prev,next);					\
+} while (0)
+
+extern void account_vtime(struct task_struct *, struct task_struct *);
+extern void account_tick_vtime(struct task_struct *);
+
+#define finish_arch_switch(prev) do {					     \
+	set_fs(current->thread.mm_segment);				     \
+	account_vtime(prev, current);					     \
+} while (0)
+
+#endif /* __ASM_SWITCH_TO_H */
diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h
deleted file mode 100644
index d73cc6b..0000000
--- a/arch/s390/include/asm/system.h
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright IBM Corp. 1999, 2009
- *
- * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
- */
-
-#ifndef __ASM_SYSTEM_H
-#define __ASM_SYSTEM_H
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <asm/types.h>
-#include <asm/ptrace.h>
-#include <asm/setup.h>
-#include <asm/processor.h>
-#include <asm/lowcore.h>
-#include <asm/cmpxchg.h>
-
-#ifdef __KERNEL__
-
-struct task_struct;
-
-extern struct task_struct *__switch_to(void *, void *);
-extern void update_per_regs(struct task_struct *task);
-
-static inline void save_fp_regs(s390_fp_regs *fpregs)
-{
-	asm volatile(
-		"	std	0,%O0+8(%R0)\n"
-		"	std	2,%O0+24(%R0)\n"
-		"	std	4,%O0+40(%R0)\n"
-		"	std	6,%O0+56(%R0)"
-		: "=Q" (*fpregs) : "Q" (*fpregs));
-	if (!MACHINE_HAS_IEEE)
-		return;
-	asm volatile(
-		"	stfpc	%0\n"
-		"	std	1,%O0+16(%R0)\n"
-		"	std	3,%O0+32(%R0)\n"
-		"	std	5,%O0+48(%R0)\n"
-		"	std	7,%O0+64(%R0)\n"
-		"	std	8,%O0+72(%R0)\n"
-		"	std	9,%O0+80(%R0)\n"
-		"	std	10,%O0+88(%R0)\n"
-		"	std	11,%O0+96(%R0)\n"
-		"	std	12,%O0+104(%R0)\n"
-		"	std	13,%O0+112(%R0)\n"
-		"	std	14,%O0+120(%R0)\n"
-		"	std	15,%O0+128(%R0)\n"
-		: "=Q" (*fpregs) : "Q" (*fpregs));
-}
-
-static inline void restore_fp_regs(s390_fp_regs *fpregs)
-{
-	asm volatile(
-		"	ld	0,%O0+8(%R0)\n"
-		"	ld	2,%O0+24(%R0)\n"
-		"	ld	4,%O0+40(%R0)\n"
-		"	ld	6,%O0+56(%R0)"
-		: : "Q" (*fpregs));
-	if (!MACHINE_HAS_IEEE)
-		return;
-	asm volatile(
-		"	lfpc	%0\n"
-		"	ld	1,%O0+16(%R0)\n"
-		"	ld	3,%O0+32(%R0)\n"
-		"	ld	5,%O0+48(%R0)\n"
-		"	ld	7,%O0+64(%R0)\n"
-		"	ld	8,%O0+72(%R0)\n"
-		"	ld	9,%O0+80(%R0)\n"
-		"	ld	10,%O0+88(%R0)\n"
-		"	ld	11,%O0+96(%R0)\n"
-		"	ld	12,%O0+104(%R0)\n"
-		"	ld	13,%O0+112(%R0)\n"
-		"	ld	14,%O0+120(%R0)\n"
-		"	ld	15,%O0+128(%R0)\n"
-		: : "Q" (*fpregs));
-}
-
-static inline void save_access_regs(unsigned int *acrs)
-{
-	asm volatile("stam 0,15,%0" : "=Q" (*acrs));
-}
-
-static inline void restore_access_regs(unsigned int *acrs)
-{
-	asm volatile("lam 0,15,%0" : : "Q" (*acrs));
-}
-
-#define switch_to(prev,next,last) do {					\
-	if (prev->mm) {							\
-		save_fp_regs(&prev->thread.fp_regs);			\
-		save_access_regs(&prev->thread.acrs[0]);		\
-	}								\
-	if (next->mm) {							\
-		restore_fp_regs(&next->thread.fp_regs);			\
-		restore_access_regs(&next->thread.acrs[0]);		\
-		update_per_regs(next);					\
-	}								\
-	prev = __switch_to(prev,next);					\
-} while (0)
-
-extern void account_vtime(struct task_struct *, struct task_struct *);
-extern void account_tick_vtime(struct task_struct *);
-
-#ifdef CONFIG_PFAULT
-extern int pfault_init(void);
-extern void pfault_fini(void);
-#else /* CONFIG_PFAULT */
-#define pfault_init()		({-1;})
-#define pfault_fini()		do { } while (0)
-#endif /* CONFIG_PFAULT */
-
-extern void cmma_init(void);
-extern int memcpy_real(void *, void *, size_t);
-extern void copy_to_absolute_zero(void *dest, void *src, size_t count);
-extern int copy_to_user_real(void __user *dest, void *src, size_t count);
-extern int copy_from_user_real(void *dest, void __user *src, size_t count);
-
-#define finish_arch_switch(prev) do {					     \
-	set_fs(current->thread.mm_segment);				     \
-	account_vtime(prev, current);					     \
-} while (0)
-
-#define nop() asm volatile("nop")
-
-/*
- * Force strict CPU ordering.
- * And yes, this is required on UP too when we're talking
- * to devices.
- *
- * This is very similar to the ppc eieio/sync instruction in that is
- * does a checkpoint syncronisation & makes sure that 
- * all memory ops have completed wrt other CPU's ( see 7-15 POP  DJB ).
- */
-
-#define eieio()	asm volatile("bcr 15,0" : : : "memory")
-#define SYNC_OTHER_CORES(x)   eieio()
-#define mb()    eieio()
-#define rmb()   eieio()
-#define wmb()   eieio()
-#define read_barrier_depends() do { } while(0)
-#define smp_mb()       mb()
-#define smp_rmb()      rmb()
-#define smp_wmb()      wmb()
-#define smp_read_barrier_depends()    read_barrier_depends()
-#define smp_mb__before_clear_bit()     smp_mb()
-#define smp_mb__after_clear_bit()      smp_mb()
-
-
-#define set_mb(var, value)      do { var = value; mb(); } while (0)
-
-#ifdef __s390x__
-
-#define __ctl_load(array, low, high) ({				\
-	typedef struct { char _[sizeof(array)]; } addrtype;	\
-	asm volatile(						\
-		"	lctlg	%1,%2,%0\n"			\
-		: : "Q" (*(addrtype *)(&array)),		\
-		    "i" (low), "i" (high));			\
-	})
-
-#define __ctl_store(array, low, high) ({			\
-	typedef struct { char _[sizeof(array)]; } addrtype;	\
-	asm volatile(						\
-		"	stctg	%1,%2,%0\n"			\
-		: "=Q" (*(addrtype *)(&array))			\
-		: "i" (low), "i" (high));			\
-	})
-
-#else /* __s390x__ */
-
-#define __ctl_load(array, low, high) ({				\
-	typedef struct { char _[sizeof(array)]; } addrtype;	\
-	asm volatile(						\
-		"	lctl	%1,%2,%0\n"			\
-		: : "Q" (*(addrtype *)(&array)),		\
-		    "i" (low), "i" (high));			\
-})
-
-#define __ctl_store(array, low, high) ({			\
-	typedef struct { char _[sizeof(array)]; } addrtype;	\
-	asm volatile(						\
-		"	stctl	%1,%2,%0\n"			\
-		: "=Q" (*(addrtype *)(&array))			\
-		: "i" (low), "i" (high));			\
-	})
-
-#endif /* __s390x__ */
-
-#define __ctl_set_bit(cr, bit) ({	\
-	unsigned long __dummy;		\
-	__ctl_store(__dummy, cr, cr);	\
-	__dummy |= 1UL << (bit);	\
-	__ctl_load(__dummy, cr, cr);	\
-})
-
-#define __ctl_clear_bit(cr, bit) ({	\
-	unsigned long __dummy;		\
-	__ctl_store(__dummy, cr, cr);	\
-	__dummy &= ~(1UL << (bit));	\
-	__ctl_load(__dummy, cr, cr);	\
-})
-
-/*
- * Use to set psw mask except for the first byte which
- * won't be changed by this function.
- */
-static inline void
-__set_psw_mask(unsigned long mask)
-{
-	__load_psw_mask(mask | (arch_local_save_flags() & ~(-1UL >> 8)));
-}
-
-#define local_mcck_enable() \
-	__set_psw_mask(psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_MCHECK)
-#define local_mcck_disable() \
-	__set_psw_mask(psw_kernel_bits | PSW_MASK_DAT)
-
-#ifdef CONFIG_SMP
-
-extern void smp_ctl_set_bit(int cr, int bit);
-extern void smp_ctl_clear_bit(int cr, int bit);
-#define ctl_set_bit(cr, bit) smp_ctl_set_bit(cr, bit)
-#define ctl_clear_bit(cr, bit) smp_ctl_clear_bit(cr, bit)
-
-#else
-
-#define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit)
-#define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit)
-
-#endif /* CONFIG_SMP */
-
-#define MAX_FACILITY_BIT (256*8)	/* stfle_fac_list has 256 bytes */
-
-/*
- * The test_facility function uses the bit odering where the MSB is bit 0.
- * That makes it easier to query facility bits with the bit number as
- * documented in the Principles of Operation.
- */
-static inline int test_facility(unsigned long nr)
-{
-	unsigned char *ptr;
-
-	if (nr >= MAX_FACILITY_BIT)
-		return 0;
-	ptr = (unsigned char *) &S390_lowcore.stfle_fac_list + (nr >> 3);
-	return (*ptr & (0x80 >> (nr & 7))) != 0;
-}
-
-static inline unsigned short stap(void)
-{
-	unsigned short cpu_address;
-
-	asm volatile("stap %0" : "=m" (cpu_address));
-	return cpu_address;
-}
-
-extern void (*_machine_restart)(char *command);
-extern void (*_machine_halt)(void);
-extern void (*_machine_power_off)(void);
-
-extern unsigned long arch_align_stack(unsigned long sp);
-
-static inline int tprot(unsigned long addr)
-{
-	int rc = -EFAULT;
-
-	asm volatile(
-		"	tprot	0(%1),0\n"
-		"0:	ipm	%0\n"
-		"	srl	%0,28\n"
-		"1:\n"
-		EX_TABLE(0b,1b)
-		: "+d" (rc) : "a" (addr) : "cc");
-	return rc;
-}
-
-#endif /* __KERNEL__ */
-
-#endif
diff --git a/arch/s390/include/asm/timer.h b/arch/s390/include/asm/timer.h
index 814243c..e63069b 100644
--- a/arch/s390/include/asm/timer.h
+++ b/arch/s390/include/asm/timer.h
@@ -33,8 +33,8 @@
 	spinlock_t lock;
 	__u64 timer;		/* last programmed timer */
 	__u64 elapsed;		/* elapsed time of timer expire values */
-	__u64 idle;		/* temp var for idle */
-	int do_spt;		/* =1: reprogram cpu timer in idle */
+	__u64 idle_enter;	/* cpu timer on idle enter */
+	__u64 idle_exit;	/* cpu timer on idle exit */
 };
 
 extern void init_virt_timer(struct vtimer_list *timer);
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index 2b23885..8f2cada 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -16,6 +16,7 @@
  */
 #include <linux/sched.h>
 #include <linux/errno.h>
+#include <asm/ctl_reg.h>
 
 #define VERIFY_READ     0
 #define VERIFY_WRITE    1
@@ -375,4 +376,9 @@
 	return n;
 }
 
+extern int memcpy_real(void *, void *, size_t);
+extern void copy_to_absolute_zero(void *dest, void *src, size_t count);
+extern int copy_to_user_real(void __user *dest, void *src, size_t count);
+extern int copy_from_user_real(void *dest, void __user *src, size_t count);
+
 #endif /* __S390_UACCESS_H */
diff --git a/arch/s390/include/asm/vdso.h b/arch/s390/include/asm/vdso.h
index 533f357..c4a11cf 100644
--- a/arch/s390/include/asm/vdso.h
+++ b/arch/s390/include/asm/vdso.h
@@ -40,8 +40,8 @@
 extern struct vdso_data *vdso_data;
 
 #ifdef CONFIG_64BIT
-int vdso_alloc_per_cpu(int cpu, struct _lowcore *lowcore);
-void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore);
+int vdso_alloc_per_cpu(struct _lowcore *lowcore);
+void vdso_free_per_cpu(struct _lowcore *lowcore);
 #endif
 
 #endif /* __ASSEMBLY__ */
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 7d9ec92..884b18a 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -23,7 +23,7 @@
 obj-y	:=  bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \
 	    processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \
 	    debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \
-	    sysinfo.o jump_label.o
+	    sysinfo.o jump_label.o lgr.o os_info.o
 
 obj-y	+= $(if $(CONFIG_64BIT),entry64.o,entry.o)
 obj-y	+= $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
@@ -34,8 +34,6 @@
 obj-$(CONFIG_MODULES)		+= s390_ksyms.o module.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_SCHED_BOOK)	+= topology.o
-obj-$(CONFIG_SMP)		+= $(if $(CONFIG_64BIT),switch_cpu64.o, \
-							switch_cpu.o)
 obj-$(CONFIG_HIBERNATION)	+= suspend.o swsusp_asm64.o
 obj-$(CONFIG_AUDIT)		+= audit.o
 compat-obj-$(CONFIG_AUDIT)	+= compat_audit.o
@@ -50,6 +48,7 @@
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
 obj-$(CONFIG_FTRACE_SYSCALLS)  += ftrace.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
+obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o perf_cpum_cf.o
 
 # Kexec part
 S390_KEXEC_OBJS := machine_kexec.o crash.o
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 6e6a72e..83e6edf 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -8,8 +8,9 @@
 
 #include <linux/kbuild.h>
 #include <linux/sched.h>
+#include <asm/cputime.h>
+#include <asm/timer.h>
 #include <asm/vdso.h>
-#include <asm/sigp.h>
 #include <asm/pgtable.h>
 
 /*
@@ -70,15 +71,15 @@
 	DEFINE(__CLOCK_MONOTONIC, CLOCK_MONOTONIC);
 	DEFINE(__CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC);
 	BLANK();
-	/* constants for SIGP */
-	DEFINE(__SIGP_STOP, sigp_stop);
-	DEFINE(__SIGP_RESTART, sigp_restart);
-	DEFINE(__SIGP_SENSE, sigp_sense);
-	DEFINE(__SIGP_INITIAL_CPU_RESET, sigp_initial_cpu_reset);
-	BLANK();
+	/* idle data offsets */
+	DEFINE(__IDLE_ENTER, offsetof(struct s390_idle_data, idle_enter));
+	DEFINE(__IDLE_EXIT, offsetof(struct s390_idle_data, idle_exit));
+	/* vtimer queue offsets */
+	DEFINE(__VQ_IDLE_ENTER, offsetof(struct vtimer_queue, idle_enter));
+	DEFINE(__VQ_IDLE_EXIT, offsetof(struct vtimer_queue, idle_exit));
 	/* lowcore offsets */
 	DEFINE(__LC_EXT_PARAMS, offsetof(struct _lowcore, ext_params));
-	DEFINE(__LC_CPU_ADDRESS, offsetof(struct _lowcore, cpu_addr));
+	DEFINE(__LC_EXT_CPU_ADDR, offsetof(struct _lowcore, ext_cpu_addr));
 	DEFINE(__LC_EXT_INT_CODE, offsetof(struct _lowcore, ext_int_code));
 	DEFINE(__LC_SVC_ILC, offsetof(struct _lowcore, svc_ilc));
 	DEFINE(__LC_SVC_INT_CODE, offsetof(struct _lowcore, svc_code));
@@ -95,20 +96,19 @@
 	DEFINE(__LC_IO_INT_WORD, offsetof(struct _lowcore, io_int_word));
 	DEFINE(__LC_STFL_FAC_LIST, offsetof(struct _lowcore, stfl_fac_list));
 	DEFINE(__LC_MCCK_CODE, offsetof(struct _lowcore, mcck_interruption_code));
-	DEFINE(__LC_DUMP_REIPL, offsetof(struct _lowcore, ipib));
-	BLANK();
-	DEFINE(__LC_RST_NEW_PSW, offsetof(struct _lowcore, restart_psw));
 	DEFINE(__LC_RST_OLD_PSW, offsetof(struct _lowcore, restart_old_psw));
 	DEFINE(__LC_EXT_OLD_PSW, offsetof(struct _lowcore, external_old_psw));
 	DEFINE(__LC_SVC_OLD_PSW, offsetof(struct _lowcore, svc_old_psw));
 	DEFINE(__LC_PGM_OLD_PSW, offsetof(struct _lowcore, program_old_psw));
 	DEFINE(__LC_MCK_OLD_PSW, offsetof(struct _lowcore, mcck_old_psw));
 	DEFINE(__LC_IO_OLD_PSW, offsetof(struct _lowcore, io_old_psw));
+	DEFINE(__LC_RST_NEW_PSW, offsetof(struct _lowcore, restart_psw));
 	DEFINE(__LC_EXT_NEW_PSW, offsetof(struct _lowcore, external_new_psw));
 	DEFINE(__LC_SVC_NEW_PSW, offsetof(struct _lowcore, svc_new_psw));
 	DEFINE(__LC_PGM_NEW_PSW, offsetof(struct _lowcore, program_new_psw));
 	DEFINE(__LC_MCK_NEW_PSW, offsetof(struct _lowcore, mcck_new_psw));
 	DEFINE(__LC_IO_NEW_PSW, offsetof(struct _lowcore, io_new_psw));
+	BLANK();
 	DEFINE(__LC_SAVE_AREA_SYNC, offsetof(struct _lowcore, save_area_sync));
 	DEFINE(__LC_SAVE_AREA_ASYNC, offsetof(struct _lowcore, save_area_async));
 	DEFINE(__LC_SAVE_AREA_RESTART, offsetof(struct _lowcore, save_area_restart));
@@ -129,12 +129,16 @@
 	DEFINE(__LC_KERNEL_STACK, offsetof(struct _lowcore, kernel_stack));
 	DEFINE(__LC_ASYNC_STACK, offsetof(struct _lowcore, async_stack));
 	DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack));
+	DEFINE(__LC_RESTART_STACK, offsetof(struct _lowcore, restart_stack));
+	DEFINE(__LC_RESTART_FN, offsetof(struct _lowcore, restart_fn));
 	DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce));
 	DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock));
 	DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
 	DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags));
 	DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func));
 	DEFINE(__LC_IRB, offsetof(struct _lowcore, irb));
+	DEFINE(__LC_DUMP_REIPL, offsetof(struct _lowcore, ipib));
+	BLANK();
 	DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area));
 	DEFINE(__LC_CLOCK_COMP_SAVE_AREA, offsetof(struct _lowcore, clock_comp_save_area));
 	DEFINE(__LC_PSW_SAVE_AREA, offsetof(struct _lowcore, psw_save_area));
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index 6fe78c2..28040fd 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -27,6 +27,7 @@
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/lowcore.h>
+#include <asm/switch_to.h>
 #include "compat_linux.h"
 #include "compat_ptrace.h"
 #include "entry.h"
@@ -581,7 +582,6 @@
 int handle_signal32(unsigned long sig, struct k_sigaction *ka,
 		    siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
 {
-	sigset_t blocked;
 	int ret;
 
 	/* Set up the stack frame */
@@ -591,10 +591,7 @@
 		ret = setup_frame32(sig, ka, oldset, regs);
 	if (ret)
 		return ret;
-	sigorsets(&blocked, &current->blocked, &ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&blocked, sig);
-	set_current_blocked(&blocked);
+	block_sigmask(ka, sig);
 	return 0;
 }
 
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c
index 3e8b881..e3dd886 100644
--- a/arch/s390/kernel/cpcmd.c
+++ b/arch/s390/kernel/cpcmd.c
@@ -18,7 +18,6 @@
 #include <linux/string.h>
 #include <asm/ebcdic.h>
 #include <asm/cpcmd.h>
-#include <asm/system.h>
 #include <asm/io.h>
 
 static DEFINE_SPINLOCK(cpcmd_lock);
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c
index c383ce4..cc1172b 100644
--- a/arch/s390/kernel/crash_dump.c
+++ b/arch/s390/kernel/crash_dump.c
@@ -14,6 +14,7 @@
 #include <linux/bootmem.h>
 #include <linux/elf.h>
 #include <asm/ipl.h>
+#include <asm/os_info.h>
 
 #define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y)))
 #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
@@ -51,7 +52,7 @@
 /*
  * Copy memory from old kernel
  */
-static int copy_from_oldmem(void *dest, void *src, size_t count)
+int copy_from_oldmem(void *dest, void *src, size_t count)
 {
 	unsigned long copied = 0;
 	int rc;
@@ -224,28 +225,44 @@
 }
 
 /*
- * Initialize vmcoreinfo note (new kernel)
+ * Get vmcoreinfo using lowcore->vmcore_info (new kernel)
  */
-static void *nt_vmcoreinfo(void *ptr)
+static void *get_vmcoreinfo_old(unsigned long *size)
 {
 	char nt_name[11], *vmcoreinfo;
 	Elf64_Nhdr note;
 	void *addr;
 
 	if (copy_from_oldmem(&addr, &S390_lowcore.vmcore_info, sizeof(addr)))
-		return ptr;
+		return NULL;
 	memset(nt_name, 0, sizeof(nt_name));
 	if (copy_from_oldmem(&note, addr, sizeof(note)))
-		return ptr;
+		return NULL;
 	if (copy_from_oldmem(nt_name, addr + sizeof(note), sizeof(nt_name) - 1))
-		return ptr;
+		return NULL;
 	if (strcmp(nt_name, "VMCOREINFO") != 0)
-		return ptr;
-	vmcoreinfo = kzalloc_panic(note.n_descsz + 1);
+		return NULL;
+	vmcoreinfo = kzalloc_panic(note.n_descsz);
 	if (copy_from_oldmem(vmcoreinfo, addr + 24, note.n_descsz))
+		return NULL;
+	*size = note.n_descsz;
+	return vmcoreinfo;
+}
+
+/*
+ * Initialize vmcoreinfo note (new kernel)
+ */
+static void *nt_vmcoreinfo(void *ptr)
+{
+	unsigned long size;
+	void *vmcoreinfo;
+
+	vmcoreinfo = os_info_old_entry(OS_INFO_VMCOREINFO, &size);
+	if (!vmcoreinfo)
+		vmcoreinfo = get_vmcoreinfo_old(&size);
+	if (!vmcoreinfo)
 		return ptr;
-	vmcoreinfo[note.n_descsz + 1] = 0;
-	return nt_init(ptr, 0, vmcoreinfo, note.n_descsz, "VMCOREINFO");
+	return nt_init(ptr, 0, vmcoreinfo, size, "VMCOREINFO");
 }
 
 /*
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
index 6848828..19e5e9e 100644
--- a/arch/s390/kernel/debug.c
+++ b/arch/s390/kernel/debug.c
@@ -2,8 +2,8 @@
  *  arch/s390/kernel/debug.c
  *   S/390 debug facility
  *
- *    Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
- *                             IBM Corporation
+ *    Copyright IBM Corp. 1999, 2012
+ *
  *    Author(s): Michael Holzheu (holzheu@de.ibm.com),
  *               Holger Smolinski (Holger.Smolinski@de.ibm.com)
  *
@@ -167,6 +167,7 @@
 static DEFINE_MUTEX(debug_mutex);
 
 static int initialized;
+static int debug_critical;
 
 static const struct file_operations debug_file_ops = {
 	.owner   = THIS_MODULE,
@@ -932,6 +933,11 @@
 }
 
 
+void debug_set_critical(void)
+{
+	debug_critical = 1;
+}
+
 /*
  * debug_event_common:
  * - write debug entry with given size
@@ -945,7 +951,11 @@
 
 	if (!debug_active || !id->areas)
 		return NULL;
-	spin_lock_irqsave(&id->lock, flags);
+	if (debug_critical) {
+		if (!spin_trylock_irqsave(&id->lock, flags))
+			return NULL;
+	} else
+		spin_lock_irqsave(&id->lock, flags);
 	active = get_active_entry(id);
 	memset(DEBUG_DATA(active), 0, id->buf_size);
 	memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
@@ -968,7 +978,11 @@
 
 	if (!debug_active || !id->areas)
 		return NULL;
-	spin_lock_irqsave(&id->lock, flags);
+	if (debug_critical) {
+		if (!spin_trylock_irqsave(&id->lock, flags))
+			return NULL;
+	} else
+		spin_lock_irqsave(&id->lock, flags);
 	active = get_active_entry(id);
 	memset(DEBUG_DATA(active), 0, id->buf_size);
 	memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
@@ -1013,7 +1027,11 @@
 		return NULL;
 	numargs=debug_count_numargs(string);
 
-	spin_lock_irqsave(&id->lock, flags);
+	if (debug_critical) {
+		if (!spin_trylock_irqsave(&id->lock, flags))
+			return NULL;
+	} else
+		spin_lock_irqsave(&id->lock, flags);
 	active = get_active_entry(id);
 	curr_event=(debug_sprintf_entry_t *) DEBUG_DATA(active);
 	va_start(ap,string);
@@ -1047,7 +1065,11 @@
 
 	numargs=debug_count_numargs(string);
 
-	spin_lock_irqsave(&id->lock, flags);
+	if (debug_critical) {
+		if (!spin_trylock_irqsave(&id->lock, flags))
+			return NULL;
+	} else
+		spin_lock_irqsave(&id->lock, flags);
 	active = get_active_entry(id);
 	curr_event=(debug_sprintf_entry_t *)DEBUG_DATA(active);
 	va_start(ap,string);
@@ -1428,10 +1450,10 @@
 	rc += sprintf(out_buf + rc, "| ");
 	for (i = 0; i < id->buf_size; i++) {
 		unsigned char c = in_buf[i];
-		if (!isprint(c))
-			rc += sprintf(out_buf + rc, ".");
-		else
+		if (isascii(c) && isprint(c))
 			rc += sprintf(out_buf + rc, "%c", c);
+		else
+			rc += sprintf(out_buf + rc, ".");
 	}
 	rc += sprintf(out_buf + rc, "\n");
 	return rc;
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index e2f8475..3221c6f 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -24,7 +24,6 @@
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/atomic.h>
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 52098d6..9475e68 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -29,6 +29,7 @@
 #include <asm/sysinfo.h>
 #include <asm/cpcmd.h>
 #include <asm/sclp.h>
+#include <asm/facility.h>
 #include "entry.h"
 
 /*
@@ -262,25 +263,8 @@
 
 static noinline __init void setup_facility_list(void)
 {
-	unsigned long nr;
-
-	S390_lowcore.stfl_fac_list = 0;
-	asm volatile(
-		"	.insn	s,0xb2b10000,0(0)\n" /* stfl */
-		"0:\n"
-		EX_TABLE(0b,0b) : "=m" (S390_lowcore.stfl_fac_list));
-	memcpy(&S390_lowcore.stfle_fac_list, &S390_lowcore.stfl_fac_list, 4);
-	nr = 4;				/* # bytes stored by stfl */
-	if (test_facility(7)) {
-		/* More facility bits available with stfle */
-		register unsigned long reg0 asm("0") = MAX_FACILITY_BIT/64 - 1;
-		asm volatile(".insn s,0xb2b00000,%0" /* stfle */
-			     : "=m" (S390_lowcore.stfle_fac_list), "+d" (reg0)
-			     : : "cc");
-		nr = (reg0 + 1) * 8;	/* # bytes stored by stfle */
-	}
-	memset((char *) S390_lowcore.stfle_fac_list + nr, 0,
-	       MAX_FACILITY_BIT/8 - nr);
+	stfle(S390_lowcore.stfle_fac_list,
+	      ARRAY_SIZE(S390_lowcore.stfle_fac_list));
 }
 
 static noinline __init void setup_hpage(void)
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 3705700..74ee563 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -2,7 +2,7 @@
  *  arch/s390/kernel/entry.S
  *    S390 low-level entry points.
  *
- *    Copyright (C) IBM Corp. 1999,2006
+ *    Copyright (C) IBM Corp. 1999,2012
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  *		 Hartmut Penner (hp@de.ibm.com),
  *		 Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
@@ -105,14 +105,14 @@
 
 	.macro	ADD64 high,low,timer
 	al	\high,\timer
-	al	\low,\timer+4
+	al	\low,4+\timer
 	brc	12,.+8
 	ahi	\high,1
 	.endm
 
 	.macro	SUB64 high,low,timer
 	sl	\high,\timer
-	sl	\low,\timer+4
+	sl	\low,4+\timer
 	brc	3,.+8
 	ahi	\high,-1
 	.endm
@@ -471,7 +471,6 @@
 	jnz	io_work			# there is work to do (signals etc.)
 io_restore:
 	mvc	__LC_RETURN_PSW(8),__PT_PSW(%r11)
-	ni	__LC_RETURN_PSW+1,0xfd	# clean wait state bit
 	stpt	__LC_EXIT_TIMER
 	lm	%r0,%r15,__PT_R0(%r11)
 	lpsw	__LC_RETURN_PSW
@@ -606,12 +605,32 @@
 	stm	%r8,%r9,__PT_PSW(%r11)
 	TRACE_IRQS_OFF
 	lr	%r2,%r11		# pass pointer to pt_regs
-	l	%r3,__LC_CPU_ADDRESS	# get cpu address + interruption code
+	l	%r3,__LC_EXT_CPU_ADDR	# get cpu address + interruption code
 	l	%r4,__LC_EXT_PARAMS	# get external parameters
 	l	%r1,BASED(.Ldo_extint)
 	basr	%r14,%r1		# call do_extint
 	j	io_return
 
+/*
+ * Load idle PSW. The second "half" of this function is in cleanup_idle.
+ */
+ENTRY(psw_idle)
+	st	%r4,__SF_EMPTY(%r15)
+	basr	%r1,0
+	la	%r1,psw_idle_lpsw+4-.(%r1)
+	st	%r1,__SF_EMPTY+4(%r15)
+	oi	__SF_EMPTY+4(%r15),0x80
+	la	%r1,.Lvtimer_max-psw_idle_lpsw-4(%r1)
+	stck	__IDLE_ENTER(%r2)
+	ltr	%r5,%r5
+	stpt	__VQ_IDLE_ENTER(%r3)
+	jz	psw_idle_lpsw
+	spt	0(%r1)
+psw_idle_lpsw:
+	lpsw	__SF_EMPTY(%r15)
+	br	%r14
+psw_idle_end:
+
 __critical_end:
 
 /*
@@ -673,7 +692,6 @@
 	TRACE_IRQS_ON
 mcck_return:
 	mvc	__LC_RETURN_MCCK_PSW(8),__PT_PSW(%r11) # move return PSW
-	ni	__LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit
 	tm	__LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
 	jno	0f
 	lm	%r0,%r15,__PT_R0(%r11)
@@ -691,77 +709,30 @@
 0:	ahi	%r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
 	j	mcck_skip
 
-/*
- * Restart interruption handler, kick starter for additional CPUs
- */
-#ifdef CONFIG_SMP
-	__CPUINIT
-ENTRY(restart_int_handler)
-	basr	%r1,0
-restart_base:
-	spt	restart_vtime-restart_base(%r1)
-	stck	__LC_LAST_UPDATE_CLOCK
-	mvc	__LC_LAST_UPDATE_TIMER(8),restart_vtime-restart_base(%r1)
-	mvc	__LC_EXIT_TIMER(8),restart_vtime-restart_base(%r1)
-	l	%r15,__LC_GPREGS_SAVE_AREA+60 # load ksp
-	lctl	%c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs
-	lam	%a0,%a15,__LC_AREGS_SAVE_AREA
-	lm	%r6,%r15,__SF_GPRS(%r15)# load registers from clone
-	l	%r1,__LC_THREAD_INFO
-	mvc	__LC_USER_TIMER(8),__TI_user_timer(%r1)
-	mvc	__LC_SYSTEM_TIMER(8),__TI_system_timer(%r1)
-	xc	__LC_STEAL_TIMER(8),__LC_STEAL_TIMER
-	ssm	__LC_PGM_NEW_PSW	# turn dat on, keep irqs off
-	basr	%r14,0
-	l	%r14,restart_addr-.(%r14)
-	basr	%r14,%r14		# call start_secondary
-restart_addr:
-	.long	start_secondary
-	.align	8
-restart_vtime:
-	.long	0x7fffffff,0xffffffff
-	.previous
-#else
-/*
- * If we do not run with SMP enabled, let the new CPU crash ...
- */
-ENTRY(restart_int_handler)
-	basr	%r1,0
-restart_base:
-	lpsw	restart_crash-restart_base(%r1)
-	.align	8
-restart_crash:
-	.long	0x000a0000,0x00000000
-restart_go:
-#endif
-
 #
 # PSW restart interrupt handler
 #
-ENTRY(psw_restart_int_handler)
+ENTRY(restart_int_handler)
 	st	%r15,__LC_SAVE_AREA_RESTART
-	basr	%r15,0
-0:	l	%r15,.Lrestart_stack-0b(%r15)	# load restart stack
-	l	%r15,0(%r15)
+	l	%r15,__LC_RESTART_STACK
 	ahi	%r15,-__PT_SIZE			# create pt_regs on stack
+	xc	0(__PT_SIZE,%r15),0(%r15)
 	stm	%r0,%r14,__PT_R0(%r15)
 	mvc	__PT_R15(4,%r15),__LC_SAVE_AREA_RESTART
 	mvc	__PT_PSW(8,%r15),__LC_RST_OLD_PSW # store restart old psw
-	ahi	%r15,-STACK_FRAME_OVERHEAD
-	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
-	basr	%r14,0
-1:	l	%r14,.Ldo_restart-1b(%r14)
-	basr	%r14,%r14
-	basr	%r14,0				# load disabled wait PSW if
-2:	lpsw	restart_psw_crash-2b(%r14)	# do_restart returns
-	.align 4
-.Ldo_restart:
-	.long	do_restart
-.Lrestart_stack:
-	.long	restart_stack
-	.align 8
-restart_psw_crash:
-	.long	0x000a0000,0x00000000 + restart_psw_crash
+	ahi	%r15,-STACK_FRAME_OVERHEAD	# create stack frame on stack
+	xc	0(STACK_FRAME_OVERHEAD,%r15),0(%r15)
+	lm	%r1,%r3,__LC_RESTART_FN		# load fn, parm & source cpu
+	ltr	%r3,%r3				# test source cpu address
+	jm	1f				# negative -> skip source stop
+0:	sigp	%r4,%r3,1			# sigp sense to source cpu
+	brc	10,0b				# wait for status stored
+1:	basr	%r14,%r1			# call function
+	stap	__SF_EMPTY(%r15)		# store cpu address
+	lh	%r3,__SF_EMPTY(%r15)
+2:	sigp	%r4,%r3,5			# sigp stop to current cpu
+	brc	2,2b
+3:	j	3b
 
 	.section .kprobes.text, "ax"
 
@@ -795,6 +766,8 @@
 	.long	io_tif + 0x80000000
 	.long	io_restore + 0x80000000
 	.long	io_done + 0x80000000
+	.long	psw_idle + 0x80000000
+	.long	psw_idle_end + 0x80000000
 
 cleanup_critical:
 	cl	%r9,BASED(cleanup_table)	# system_call
@@ -813,6 +786,10 @@
 	jl	cleanup_io_tif
 	cl	%r9,BASED(cleanup_table+28)	# io_done
 	jl	cleanup_io_restore
+	cl	%r9,BASED(cleanup_table+32)	# psw_idle
+	jl	0f
+	cl	%r9,BASED(cleanup_table+36)	# psw_idle_end
+	jl	cleanup_idle
 0:	br	%r14
 
 cleanup_system_call:
@@ -896,7 +873,6 @@
 	jhe	0f
 	l	%r9,12(%r11)		# get saved r11 pointer to pt_regs
 	mvc	__LC_RETURN_PSW(8),__PT_PSW(%r9)
-	ni	__LC_RETURN_PSW+1,0xfd	# clear wait state bit
 	mvc	0(32,%r11),__PT_R8(%r9)
 	lm	%r0,%r7,__PT_R0(%r9)
 0:	lm	%r8,%r9,__LC_RETURN_PSW
@@ -904,11 +880,52 @@
 cleanup_io_restore_insn:
 	.long	io_done - 4 + 0x80000000
 
+cleanup_idle:
+	# copy interrupt clock & cpu timer
+	mvc	__IDLE_EXIT(8,%r2),__LC_INT_CLOCK
+	mvc	__VQ_IDLE_EXIT(8,%r3),__LC_ASYNC_ENTER_TIMER
+	chi	%r11,__LC_SAVE_AREA_ASYNC
+	je	0f
+	mvc	__IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK
+	mvc	__VQ_IDLE_EXIT(8,%r3),__LC_MCCK_ENTER_TIMER
+0:	# check if stck has been executed
+	cl	%r9,BASED(cleanup_idle_insn)
+	jhe	1f
+	mvc	__IDLE_ENTER(8,%r2),__IDLE_EXIT(%r2)
+	mvc	__VQ_IDLE_ENTER(8,%r3),__VQ_IDLE_EXIT(%r3)
+	j	2f
+1:	# check if the cpu timer has been reprogrammed
+	ltr	%r5,%r5
+	jz	2f
+	spt	__VQ_IDLE_ENTER(%r3)
+2:	# account system time going idle
+	lm	%r9,%r10,__LC_STEAL_TIMER
+	ADD64	%r9,%r10,__IDLE_ENTER(%r2)
+	SUB64	%r9,%r10,__LC_LAST_UPDATE_CLOCK
+	stm	%r9,%r10,__LC_STEAL_TIMER
+	mvc	__LC_LAST_UPDATE_CLOCK(8),__IDLE_EXIT(%r2)
+	lm	%r9,%r10,__LC_SYSTEM_TIMER
+	ADD64	%r9,%r10,__LC_LAST_UPDATE_TIMER
+	SUB64	%r9,%r10,__VQ_IDLE_ENTER(%r3)
+	stm	%r9,%r10,__LC_SYSTEM_TIMER
+	mvc	__LC_LAST_UPDATE_TIMER(8),__VQ_IDLE_EXIT(%r3)
+	# prepare return psw
+	n	%r8,BASED(cleanup_idle_wait)	# clear wait state bit
+	l	%r9,24(%r11)			# return from psw_idle
+	br	%r14
+cleanup_idle_insn:
+	.long	psw_idle_lpsw + 0x80000000
+cleanup_idle_wait:
+	.long	0xfffdffff
+
 /*
  * Integer constants
  */
 	.align	4
-.Lnr_syscalls:		.long	NR_syscalls
+.Lnr_syscalls:
+	.long	NR_syscalls
+.Lvtimer_max:
+	.quad	0x7fffffffffffffff
 
 /*
  * Symbol constants
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index bf538aa..6cdddac 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -4,11 +4,22 @@
 #include <linux/types.h>
 #include <linux/signal.h>
 #include <asm/ptrace.h>
-
+#include <asm/cputime.h>
+#include <asm/timer.h>
 
 extern void (*pgm_check_table[128])(struct pt_regs *);
 extern void *restart_stack;
 
+void system_call(void);
+void pgm_check_handler(void);
+void ext_int_handler(void);
+void io_int_handler(void);
+void mcck_int_handler(void);
+void restart_int_handler(void);
+void restart_call_handler(void);
+void psw_idle(struct s390_idle_data *, struct vtimer_queue *,
+	      unsigned long, int);
+
 asmlinkage long do_syscall_trace_enter(struct pt_regs *regs);
 asmlinkage void do_syscall_trace_exit(struct pt_regs *regs);
 
@@ -24,9 +35,9 @@
 		    siginfo_t *info, sigset_t *oldset, struct pt_regs *regs);
 void do_notify_resume(struct pt_regs *regs);
 
-void do_extint(struct pt_regs *regs, unsigned int, unsigned int, unsigned long);
+struct ext_code;
+void do_extint(struct pt_regs *regs, struct ext_code, unsigned int, unsigned long);
 void do_restart(void);
-int __cpuinit start_secondary(void *cpuvoid);
 void __init startup_init(void);
 void die(struct pt_regs *regs, const char *str);
 
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 412a7b8..4e1c292 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -2,7 +2,7 @@
  *  arch/s390/kernel/entry64.S
  *    S390 low-level entry points.
  *
- *    Copyright (C) IBM Corp. 1999,2010
+ *    Copyright (C) IBM Corp. 1999,2012
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  *		 Hartmut Penner (hp@de.ibm.com),
  *		 Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
@@ -489,7 +489,6 @@
 	lg	%r14,__LC_VDSO_PER_CPU
 	lmg	%r0,%r10,__PT_R0(%r11)
 	mvc	__LC_RETURN_PSW(16),__PT_PSW(%r11)
-	ni	__LC_RETURN_PSW+1,0xfd	# clear wait state bit
 	stpt	__LC_EXIT_TIMER
 	mvc	__VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
 	lmg	%r11,%r15,__PT_R11(%r11)
@@ -625,12 +624,30 @@
 	TRACE_IRQS_OFF
 	lghi	%r1,4096
 	lgr	%r2,%r11		# pass pointer to pt_regs
-	llgf	%r3,__LC_CPU_ADDRESS	# get cpu address + interruption code
+	llgf	%r3,__LC_EXT_CPU_ADDR	# get cpu address + interruption code
 	llgf	%r4,__LC_EXT_PARAMS	# get external parameter
 	lg	%r5,__LC_EXT_PARAMS2-4096(%r1)	# get 64 bit external parameter
 	brasl	%r14,do_extint
 	j	io_return
 
+/*
+ * Load idle PSW. The second "half" of this function is in cleanup_idle.
+ */
+ENTRY(psw_idle)
+	stg	%r4,__SF_EMPTY(%r15)
+	larl	%r1,psw_idle_lpsw+4
+	stg	%r1,__SF_EMPTY+8(%r15)
+	larl	%r1,.Lvtimer_max
+	stck	__IDLE_ENTER(%r2)
+	ltr	%r5,%r5
+	stpt	__VQ_IDLE_ENTER(%r3)
+	jz	psw_idle_lpsw
+	spt	0(%r1)
+psw_idle_lpsw:
+	lpswe	__SF_EMPTY(%r15)
+	br	%r14
+psw_idle_end:
+
 __critical_end:
 
 /*
@@ -696,7 +713,6 @@
 	lg	%r14,__LC_VDSO_PER_CPU
 	lmg	%r0,%r10,__PT_R0(%r11)
 	mvc	__LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW
-	ni	__LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit
 	tm	__LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
 	jno	0f
 	stpt	__LC_EXIT_TIMER
@@ -713,68 +729,30 @@
 0:	aghi	%r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
 	j	mcck_skip
 
-/*
- * Restart interruption handler, kick starter for additional CPUs
- */
-#ifdef CONFIG_SMP
-	__CPUINIT
-ENTRY(restart_int_handler)
-	basr	%r1,0
-restart_base:
-	spt	restart_vtime-restart_base(%r1)
-	stck	__LC_LAST_UPDATE_CLOCK
-	mvc	__LC_LAST_UPDATE_TIMER(8),restart_vtime-restart_base(%r1)
-	mvc	__LC_EXIT_TIMER(8),restart_vtime-restart_base(%r1)
-	lghi	%r10,__LC_GPREGS_SAVE_AREA
-	lg	%r15,120(%r10)		# load ksp
-	lghi	%r10,__LC_CREGS_SAVE_AREA
-	lctlg	%c0,%c15,0(%r10)	# get new ctl regs
-	lghi	%r10,__LC_AREGS_SAVE_AREA
-	lam	%a0,%a15,0(%r10)
-	lmg	%r6,%r15,__SF_GPRS(%r15)# load registers from clone
-	lg	%r1,__LC_THREAD_INFO
-	mvc	__LC_USER_TIMER(8),__TI_user_timer(%r1)
-	mvc	__LC_SYSTEM_TIMER(8),__TI_system_timer(%r1)
-	xc	__LC_STEAL_TIMER(8),__LC_STEAL_TIMER
-	ssm	__LC_PGM_NEW_PSW	# turn dat on, keep irqs off
-	brasl	%r14,start_secondary
-	.align	8
-restart_vtime:
-	.long	0x7fffffff,0xffffffff
-	.previous
-#else
-/*
- * If we do not run with SMP enabled, let the new CPU crash ...
- */
-ENTRY(restart_int_handler)
-	basr	%r1,0
-restart_base:
-	lpswe	restart_crash-restart_base(%r1)
-	.align 8
-restart_crash:
-	.long  0x000a0000,0x00000000,0x00000000,0x00000000
-restart_go:
-#endif
-
 #
 # PSW restart interrupt handler
 #
-ENTRY(psw_restart_int_handler)
+ENTRY(restart_int_handler)
 	stg	%r15,__LC_SAVE_AREA_RESTART
-	larl	%r15,restart_stack		# load restart stack
-	lg	%r15,0(%r15)
+	lg	%r15,__LC_RESTART_STACK
 	aghi	%r15,-__PT_SIZE			# create pt_regs on stack
+	xc	0(__PT_SIZE,%r15),0(%r15)
 	stmg	%r0,%r14,__PT_R0(%r15)
 	mvc	__PT_R15(8,%r15),__LC_SAVE_AREA_RESTART
 	mvc	__PT_PSW(16,%r15),__LC_RST_OLD_PSW # store restart old psw
-	aghi	%r15,-STACK_FRAME_OVERHEAD
-	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
-	brasl	%r14,do_restart
-	larl	%r14,restart_psw_crash		# load disabled wait PSW if
-	lpswe	0(%r14)				# do_restart returns
-	.align 8
-restart_psw_crash:
-	.quad	0x0002000080000000,0x0000000000000000 + restart_psw_crash
+	aghi	%r15,-STACK_FRAME_OVERHEAD	# create stack frame on stack
+	xc	0(STACK_FRAME_OVERHEAD,%r15),0(%r15)
+	lmg	%r1,%r3,__LC_RESTART_FN		# load fn, parm & source cpu
+	ltgr	%r3,%r3				# test source cpu address
+	jm	1f				# negative -> skip source stop
+0:	sigp	%r4,%r3,1			# sigp sense to source cpu
+	brc	10,0b				# wait for status stored
+1:	basr	%r14,%r1			# call function
+	stap	__SF_EMPTY(%r15)		# store cpu address
+	llgh	%r3,__SF_EMPTY(%r15)
+2:	sigp	%r4,%r3,5			# sigp stop to current cpu
+	brc	2,2b
+3:	j	3b
 
 	.section .kprobes.text, "ax"
 
@@ -808,6 +786,8 @@
 	.quad	io_tif
 	.quad	io_restore
 	.quad	io_done
+	.quad	psw_idle
+	.quad	psw_idle_end
 
 cleanup_critical:
 	clg	%r9,BASED(cleanup_table)	# system_call
@@ -826,6 +806,10 @@
 	jl	cleanup_io_tif
 	clg	%r9,BASED(cleanup_table+56)	# io_done
 	jl	cleanup_io_restore
+	clg	%r9,BASED(cleanup_table+64)	# psw_idle
+	jl	0f
+	clg	%r9,BASED(cleanup_table+72)	# psw_idle_end
+	jl	cleanup_idle
 0:	br	%r14
 
 
@@ -915,7 +899,6 @@
 	je	0f
 	lg	%r9,24(%r11)		# get saved r11 pointer to pt_regs
 	mvc	__LC_RETURN_PSW(16),__PT_PSW(%r9)
-	ni	__LC_RETURN_PSW+1,0xfd	# clear wait state bit
 	mvc	0(64,%r11),__PT_R8(%r9)
 	lmg	%r0,%r7,__PT_R0(%r9)
 0:	lmg	%r8,%r9,__LC_RETURN_PSW
@@ -923,6 +906,42 @@
 cleanup_io_restore_insn:
 	.quad	io_done - 4
 
+cleanup_idle:
+	# copy interrupt clock & cpu timer
+	mvc	__IDLE_EXIT(8,%r2),__LC_INT_CLOCK
+	mvc	__VQ_IDLE_EXIT(8,%r3),__LC_ASYNC_ENTER_TIMER
+	cghi	%r11,__LC_SAVE_AREA_ASYNC
+	je	0f
+	mvc	__IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK
+	mvc	__VQ_IDLE_EXIT(8,%r3),__LC_MCCK_ENTER_TIMER
+0:	# check if stck & stpt have been executed
+	clg	%r9,BASED(cleanup_idle_insn)
+	jhe	1f
+	mvc	__IDLE_ENTER(8,%r2),__IDLE_EXIT(%r2)
+	mvc	__VQ_IDLE_ENTER(8,%r3),__VQ_IDLE_EXIT(%r3)
+	j	2f
+1:	# check if the cpu timer has been reprogrammed
+	ltr	%r5,%r5
+	jz	2f
+	spt	__VQ_IDLE_ENTER(%r3)
+2:	# account system time going idle
+	lg	%r9,__LC_STEAL_TIMER
+	alg	%r9,__IDLE_ENTER(%r2)
+	slg	%r9,__LC_LAST_UPDATE_CLOCK
+	stg	%r9,__LC_STEAL_TIMER
+	mvc	__LC_LAST_UPDATE_CLOCK(8),__IDLE_EXIT(%r2)
+	lg	%r9,__LC_SYSTEM_TIMER
+	alg	%r9,__LC_LAST_UPDATE_TIMER
+	slg	%r9,__VQ_IDLE_ENTER(%r3)
+	stg	%r9,__LC_SYSTEM_TIMER
+	mvc	__LC_LAST_UPDATE_TIMER(8),__VQ_IDLE_EXIT(%r3)
+	# prepare return psw
+	nihh	%r8,0xfffd		# clear wait state bit
+	lg	%r9,48(%r11)		# return from psw_idle
+	br	%r14
+cleanup_idle_insn:
+	.quad	psw_idle_lpsw
+
 /*
  * Integer constants
  */
@@ -931,6 +950,8 @@
 	.quad	__critical_start
 .Lcritical_length:
 	.quad	__critical_end - __critical_start
+.Lvtimer_max:
+	.quad	0x7fffffffffffffff
 
 
 #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index affa8e6..8342e65 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -2,7 +2,7 @@
  *  arch/s390/kernel/ipl.c
  *    ipl/reipl/dump support for Linux on s390.
  *
- *    Copyright IBM Corp. 2005,2007
+ *    Copyright IBM Corp. 2005,2012
  *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
  *		 Heiko Carstens <heiko.carstens@de.ibm.com>
  *		 Volker Sameske <sameske@de.ibm.com>
@@ -17,6 +17,7 @@
 #include <linux/fs.h>
 #include <linux/gfp.h>
 #include <linux/crash_dump.h>
+#include <linux/debug_locks.h>
 #include <asm/ipl.h>
 #include <asm/smp.h>
 #include <asm/setup.h>
@@ -25,8 +26,9 @@
 #include <asm/ebcdic.h>
 #include <asm/reset.h>
 #include <asm/sclp.h>
-#include <asm/sigp.h>
 #include <asm/checksum.h>
+#include <asm/debug.h>
+#include <asm/os_info.h>
 #include "entry.h"
 
 #define IPL_PARM_BLOCK_VERSION 0
@@ -571,7 +573,7 @@
 
 static void ipl_run(struct shutdown_trigger *trigger)
 {
-	smp_switch_to_ipl_cpu(__ipl_run, NULL);
+	smp_call_ipl_cpu(__ipl_run, NULL);
 }
 
 static int __init ipl_init(void)
@@ -950,6 +952,13 @@
 	.attrs = reipl_nss_attrs,
 };
 
+static void set_reipl_block_actual(struct ipl_parameter_block *reipl_block)
+{
+	reipl_block_actual = reipl_block;
+	os_info_entry_add(OS_INFO_REIPL_BLOCK, reipl_block_actual,
+			  reipl_block->hdr.len);
+}
+
 /* reipl type */
 
 static int reipl_set_type(enum ipl_type type)
@@ -965,7 +974,7 @@
 			reipl_method = REIPL_METHOD_CCW_VM;
 		else
 			reipl_method = REIPL_METHOD_CCW_CIO;
-		reipl_block_actual = reipl_block_ccw;
+		set_reipl_block_actual(reipl_block_ccw);
 		break;
 	case IPL_TYPE_FCP:
 		if (diag308_set_works)
@@ -974,7 +983,7 @@
 			reipl_method = REIPL_METHOD_FCP_RO_VM;
 		else
 			reipl_method = REIPL_METHOD_FCP_RO_DIAG;
-		reipl_block_actual = reipl_block_fcp;
+		set_reipl_block_actual(reipl_block_fcp);
 		break;
 	case IPL_TYPE_FCP_DUMP:
 		reipl_method = REIPL_METHOD_FCP_DUMP;
@@ -984,7 +993,7 @@
 			reipl_method = REIPL_METHOD_NSS_DIAG;
 		else
 			reipl_method = REIPL_METHOD_NSS;
-		reipl_block_actual = reipl_block_nss;
+		set_reipl_block_actual(reipl_block_nss);
 		break;
 	case IPL_TYPE_UNKNOWN:
 		reipl_method = REIPL_METHOD_DEFAULT;
@@ -1101,7 +1110,7 @@
 
 static void reipl_run(struct shutdown_trigger *trigger)
 {
-	smp_switch_to_ipl_cpu(__reipl_run, NULL);
+	smp_call_ipl_cpu(__reipl_run, NULL);
 }
 
 static void reipl_block_ccw_init(struct ipl_parameter_block *ipb)
@@ -1256,6 +1265,29 @@
 	return 0;
 }
 
+static int __init reipl_type_init(void)
+{
+	enum ipl_type reipl_type = ipl_info.type;
+	struct ipl_parameter_block *reipl_block;
+	unsigned long size;
+
+	reipl_block = os_info_old_entry(OS_INFO_REIPL_BLOCK, &size);
+	if (!reipl_block)
+		goto out;
+	/*
+	 * If we have an OS info reipl block, this will be used
+	 */
+	if (reipl_block->hdr.pbt == DIAG308_IPL_TYPE_FCP) {
+		memcpy(reipl_block_fcp, reipl_block, size);
+		reipl_type = IPL_TYPE_FCP;
+	} else if (reipl_block->hdr.pbt == DIAG308_IPL_TYPE_CCW) {
+		memcpy(reipl_block_ccw, reipl_block, size);
+		reipl_type = IPL_TYPE_CCW;
+	}
+out:
+	return reipl_set_type(reipl_type);
+}
+
 static int __init reipl_init(void)
 {
 	int rc;
@@ -1277,10 +1309,7 @@
 	rc = reipl_nss_init();
 	if (rc)
 		return rc;
-	rc = reipl_set_type(ipl_info.type);
-	if (rc)
-		return rc;
-	return 0;
+	return reipl_type_init();
 }
 
 static struct shutdown_action __refdata reipl_action = {
@@ -1421,7 +1450,7 @@
 	if (dump_method == DUMP_METHOD_NONE)
 		return;
 	smp_send_stop();
-	smp_switch_to_ipl_cpu(__dump_run, NULL);
+	smp_call_ipl_cpu(__dump_run, NULL);
 }
 
 static int __init dump_ccw_init(void)
@@ -1499,30 +1528,12 @@
 
 static void dump_reipl_run(struct shutdown_trigger *trigger)
 {
-	preempt_disable();
-	/*
-	 * Bypass dynamic address translation (DAT) when storing IPL parameter
-	 * information block address and checksum into the prefix area
-	 * (corresponding to absolute addresses 0-8191).
-	 * When enhanced DAT applies and the STE format control in one,
-	 * the absolute address is formed without prefixing. In this case a
-	 * normal store (stg/st) into the prefix area would no more match to
-	 * absolute addresses 0-8191.
-	 */
-#ifdef CONFIG_64BIT
-	asm volatile("sturg %0,%1"
-		:: "a" ((unsigned long) reipl_block_actual),
-		"a" (&lowcore_ptr[smp_processor_id()]->ipib));
-#else
-	asm volatile("stura %0,%1"
-		:: "a" ((unsigned long) reipl_block_actual),
-		"a" (&lowcore_ptr[smp_processor_id()]->ipib));
-#endif
-	asm volatile("stura %0,%1"
-		:: "a" (csum_partial(reipl_block_actual,
-				     reipl_block_actual->hdr.len, 0)),
-		"a" (&lowcore_ptr[smp_processor_id()]->ipib_checksum));
-	preempt_enable();
+	u32 csum;
+
+	csum = csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0);
+	copy_to_absolute_zero(&S390_lowcore.ipib_checksum, &csum, sizeof(csum));
+	copy_to_absolute_zero(&S390_lowcore.ipib, &reipl_block_actual,
+			      sizeof(reipl_block_actual));
 	dump_run(trigger);
 }
 
@@ -1623,9 +1634,7 @@
 	if (strcmp(trigger->name, ON_PANIC_STR) == 0 ||
 	    strcmp(trigger->name, ON_RESTART_STR) == 0)
 		disabled_wait((unsigned long) __builtin_return_address(0));
-	while (sigp(smp_processor_id(), sigp_stop) == sigp_busy)
-		cpu_relax();
-	for (;;);
+	smp_stop_cpu();
 }
 
 static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR,
@@ -1713,6 +1722,7 @@
 
 static void do_panic(void)
 {
+	lgr_info_log();
 	on_panic_trigger.action->fn(&on_panic_trigger);
 	stop_run(&on_panic_trigger);
 }
@@ -1738,9 +1748,8 @@
 static struct kobj_attribute on_restart_attr =
 	__ATTR(on_restart, 0644, on_restart_show, on_restart_store);
 
-void do_restart(void)
+static void __do_restart(void *ignore)
 {
-	smp_restart_with_online_cpu();
 	smp_send_stop();
 #ifdef CONFIG_CRASH_DUMP
 	crash_kexec(NULL);
@@ -1749,6 +1758,14 @@
 	stop_run(&on_restart_trigger);
 }
 
+void do_restart(void)
+{
+	tracing_off();
+	debug_locks_off();
+	lgr_info_log();
+	smp_call_online_cpu(__do_restart, NULL);
+}
+
 /* on halt */
 
 static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action};
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index e30b2df..1c2cdd5 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -202,31 +202,27 @@
 }
 EXPORT_SYMBOL(unregister_external_interrupt);
 
-void __irq_entry do_extint(struct pt_regs *regs, unsigned int ext_int_code,
+void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,
 			   unsigned int param32, unsigned long param64)
 {
 	struct pt_regs *old_regs;
-	unsigned short code;
 	struct ext_int_info *p;
 	int index;
 
-	code = (unsigned short) ext_int_code;
 	old_regs = set_irq_regs(regs);
-	s390_idle_check(regs, S390_lowcore.int_clock,
-			S390_lowcore.async_enter_timer);
 	irq_enter();
 	if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
 		/* Serve timer interrupts first. */
 		clock_comparator_work();
 	kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
-	if (code != 0x1004)
+	if (ext_code.code != 0x1004)
 		__get_cpu_var(s390_idle).nohz_delay = 1;
 
-	index = ext_hash(code);
+	index = ext_hash(ext_code.code);
 	rcu_read_lock();
 	list_for_each_entry_rcu(p, &ext_int_hash[index], entry)
-		if (likely(p->code == code))
-			p->handler(ext_int_code, param32, param64);
+		if (likely(p->code == ext_code.code))
+			p->handler(ext_code, param32, param64);
 	rcu_read_unlock();
 	irq_exit();
 	set_irq_regs(old_regs);
@@ -259,3 +255,26 @@
 	spin_unlock(&sc_irq_lock);
 }
 EXPORT_SYMBOL(service_subclass_irq_unregister);
+
+static DEFINE_SPINLOCK(ma_subclass_lock);
+static int ma_subclass_refcount;
+
+void measurement_alert_subclass_register(void)
+{
+	spin_lock(&ma_subclass_lock);
+	if (!ma_subclass_refcount)
+		ctl_set_bit(0, 5);
+	ma_subclass_refcount++;
+	spin_unlock(&ma_subclass_lock);
+}
+EXPORT_SYMBOL(measurement_alert_subclass_register);
+
+void measurement_alert_subclass_unregister(void)
+{
+	spin_lock(&ma_subclass_lock);
+	ma_subclass_refcount--;
+	if (!ma_subclass_refcount)
+		ctl_clear_bit(0, 5);
+	spin_unlock(&ma_subclass_lock);
+}
+EXPORT_SYMBOL(measurement_alert_subclass_unregister);
diff --git a/arch/s390/kernel/lgr.c b/arch/s390/kernel/lgr.c
new file mode 100644
index 0000000..87f080b
--- /dev/null
+++ b/arch/s390/kernel/lgr.c
@@ -0,0 +1,200 @@
+/*
+ * Linux Guest Relocation (LGR) detection
+ *
+ * Copyright IBM Corp. 2012
+ * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <asm/facility.h>
+#include <asm/sysinfo.h>
+#include <asm/ebcdic.h>
+#include <asm/debug.h>
+#include <asm/ipl.h>
+
+#define LGR_TIMER_INTERVAL_SECS (30 * 60)
+#define VM_LEVEL_MAX 2 /* Maximum is 8, but we only record two levels */
+
+/*
+ * LGR info: Contains stfle and stsi data
+ */
+struct lgr_info {
+	/* Bit field with facility information: 4 DWORDs are stored */
+	u64 stfle_fac_list[4];
+	/* Level of system (1 = CEC, 2 = LPAR, 3 = z/VM */
+	u32 level;
+	/* Level 1: CEC info (stsi 1.1.1) */
+	char manufacturer[16];
+	char type[4];
+	char sequence[16];
+	char plant[4];
+	char model[16];
+	/* Level 2: LPAR info (stsi 2.2.2) */
+	u16 lpar_number;
+	char name[8];
+	/* Level 3: VM info (stsi 3.2.2) */
+	u8 vm_count;
+	struct {
+		char name[8];
+		char cpi[16];
+	} vm[VM_LEVEL_MAX];
+} __packed __aligned(8);
+
+/*
+ * LGR globals
+ */
+static void *lgr_page;
+static struct lgr_info lgr_info_last;
+static struct lgr_info lgr_info_cur;
+static struct debug_info *lgr_dbf;
+
+/*
+ * Return number of valid stsi levels
+ */
+static inline int stsi_0(void)
+{
+	int rc = stsi(NULL, 0, 0, 0);
+
+	return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28);
+}
+
+/*
+ * Copy buffer and then convert it to ASCII
+ */
+static void cpascii(char *dst, char *src, int size)
+{
+	memcpy(dst, src, size);
+	EBCASC(dst, size);
+}
+
+/*
+ * Fill LGR info with 1.1.1 stsi data
+ */
+static void lgr_stsi_1_1_1(struct lgr_info *lgr_info)
+{
+	struct sysinfo_1_1_1 *si = lgr_page;
+
+	if (stsi(si, 1, 1, 1) == -ENOSYS)
+		return;
+	cpascii(lgr_info->manufacturer, si->manufacturer,
+		sizeof(si->manufacturer));
+	cpascii(lgr_info->type, si->type, sizeof(si->type));
+	cpascii(lgr_info->model, si->model, sizeof(si->model));
+	cpascii(lgr_info->sequence, si->sequence, sizeof(si->sequence));
+	cpascii(lgr_info->plant, si->plant, sizeof(si->plant));
+}
+
+/*
+ * Fill LGR info with 2.2.2 stsi data
+ */
+static void lgr_stsi_2_2_2(struct lgr_info *lgr_info)
+{
+	struct sysinfo_2_2_2 *si = lgr_page;
+
+	if (stsi(si, 2, 2, 2) == -ENOSYS)
+		return;
+	cpascii(lgr_info->name, si->name, sizeof(si->name));
+	memcpy(&lgr_info->lpar_number, &si->lpar_number,
+	       sizeof(lgr_info->lpar_number));
+}
+
+/*
+ * Fill LGR info with 3.2.2 stsi data
+ */
+static void lgr_stsi_3_2_2(struct lgr_info *lgr_info)
+{
+	struct sysinfo_3_2_2 *si = lgr_page;
+	int i;
+
+	if (stsi(si, 3, 2, 2) == -ENOSYS)
+		return;
+	for (i = 0; i < min_t(u8, si->count, VM_LEVEL_MAX); i++) {
+		cpascii(lgr_info->vm[i].name, si->vm[i].name,
+			sizeof(si->vm[i].name));
+		cpascii(lgr_info->vm[i].cpi, si->vm[i].cpi,
+			sizeof(si->vm[i].cpi));
+	}
+	lgr_info->vm_count = si->count;
+}
+
+/*
+ * Fill LGR info with current data
+ */
+static void lgr_info_get(struct lgr_info *lgr_info)
+{
+	memset(lgr_info, 0, sizeof(*lgr_info));
+	stfle(lgr_info->stfle_fac_list, ARRAY_SIZE(lgr_info->stfle_fac_list));
+	lgr_info->level = stsi_0();
+	if (lgr_info->level == -ENOSYS)
+		return;
+	if (lgr_info->level >= 1)
+		lgr_stsi_1_1_1(lgr_info);
+	if (lgr_info->level >= 2)
+		lgr_stsi_2_2_2(lgr_info);
+	if (lgr_info->level >= 3)
+		lgr_stsi_3_2_2(lgr_info);
+}
+
+/*
+ * Check if LGR info has changed and if yes log new LGR info to s390dbf
+ */
+void lgr_info_log(void)
+{
+	static DEFINE_SPINLOCK(lgr_info_lock);
+	unsigned long flags;
+
+	if (!spin_trylock_irqsave(&lgr_info_lock, flags))
+		return;
+	lgr_info_get(&lgr_info_cur);
+	if (memcmp(&lgr_info_last, &lgr_info_cur, sizeof(lgr_info_cur)) != 0) {
+		debug_event(lgr_dbf, 1, &lgr_info_cur, sizeof(lgr_info_cur));
+		lgr_info_last = lgr_info_cur;
+	}
+	spin_unlock_irqrestore(&lgr_info_lock, flags);
+}
+EXPORT_SYMBOL_GPL(lgr_info_log);
+
+static void lgr_timer_set(void);
+
+/*
+ * LGR timer callback
+ */
+static void lgr_timer_fn(unsigned long ignored)
+{
+	lgr_info_log();
+	lgr_timer_set();
+}
+
+static struct timer_list lgr_timer =
+	TIMER_DEFERRED_INITIALIZER(lgr_timer_fn, 0, 0);
+
+/*
+ * Setup next LGR timer
+ */
+static void lgr_timer_set(void)
+{
+	mod_timer(&lgr_timer, jiffies + LGR_TIMER_INTERVAL_SECS * HZ);
+}
+
+/*
+ * Initialize LGR: Add s390dbf, write initial lgr_info and setup timer
+ */
+static int __init lgr_init(void)
+{
+	lgr_page = (void *) __get_free_pages(GFP_KERNEL, 0);
+	if (!lgr_page)
+		return -ENOMEM;
+	lgr_dbf = debug_register("lgr", 1, 1, sizeof(struct lgr_info));
+	if (!lgr_dbf) {
+		free_page((unsigned long) lgr_page);
+		return -ENOMEM;
+	}
+	debug_register_view(lgr_dbf, &debug_hex_ascii_view);
+	lgr_info_get(&lgr_info_last);
+	debug_event(lgr_dbf, 1, &lgr_info_last, sizeof(lgr_info_last));
+	lgr_timer_set();
+	return 0;
+}
+module_init(lgr_init);
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
index 47b168f..bdad47d 100644
--- a/arch/s390/kernel/machine_kexec.c
+++ b/arch/s390/kernel/machine_kexec.c
@@ -14,11 +14,11 @@
 #include <linux/delay.h>
 #include <linux/reboot.h>
 #include <linux/ftrace.h>
+#include <linux/debug_locks.h>
 #include <asm/cio.h>
 #include <asm/setup.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
-#include <asm/system.h>
 #include <asm/smp.h>
 #include <asm/reset.h>
 #include <asm/ipl.h>
@@ -49,50 +49,21 @@
 }
 
 /*
- * Store status of next available physical CPU
- */
-static int store_status_next(int start_cpu, int this_cpu)
-{
-	struct save_area *sa = (void *) 4608 + store_prefix();
-	int cpu, rc;
-
-	for (cpu = start_cpu; cpu < 65536; cpu++) {
-		if (cpu == this_cpu)
-			continue;
-		do {
-			rc = raw_sigp(cpu, sigp_stop_and_store_status);
-		} while (rc == sigp_busy);
-		if (rc != sigp_order_code_accepted)
-			continue;
-		if (sa->pref_reg)
-			return cpu;
-	}
-	return -1;
-}
-
-/*
  * Initialize CPU ELF notes
  */
 void setup_regs(void)
 {
 	unsigned long sa = S390_lowcore.prefixreg_save_area + SAVE_AREA_BASE;
-	int cpu, this_cpu, phys_cpu = 0, first = 1;
+	int cpu, this_cpu;
 
-	this_cpu = stap();
-
-	if (!S390_lowcore.prefixreg_save_area)
-		first = 0;
+	this_cpu = smp_find_processor_id(stap());
+	add_elf_notes(this_cpu);
 	for_each_online_cpu(cpu) {
-		if (first) {
-			add_elf_notes(cpu);
-			first = 0;
+		if (cpu == this_cpu)
 			continue;
-		}
-		phys_cpu = store_status_next(phys_cpu, this_cpu);
-		if (phys_cpu == -1)
-			break;
+		if (smp_store_status(cpu))
+			continue;
 		add_elf_notes(cpu);
-		phys_cpu++;
 	}
 	/* Copy dump CPU store status info to absolute zero */
 	memcpy((void *) SAVE_AREA_BASE, (void *) sa, sizeof(struct save_area));
@@ -238,10 +209,14 @@
 	struct kimage *image = data;
 
 	pfault_fini();
-	if (image->type == KEXEC_TYPE_CRASH)
+	tracing_off();
+	debug_locks_off();
+	if (image->type == KEXEC_TYPE_CRASH) {
+		lgr_info_log();
 		s390_reset_system(__do_machine_kdump, data);
-	else
+	} else {
 		s390_reset_system(__do_machine_kexec, data);
+	}
 	disabled_wait((unsigned long) __builtin_return_address(0));
 }
 
@@ -255,5 +230,5 @@
 		return;
 	tracer_disable();
 	smp_send_stop();
-	smp_switch_to_ipl_cpu(__machine_kexec, image);
+	smp_call_ipl_cpu(__machine_kexec, image);
 }
diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c
index 0fd2e86..8c372ca 100644
--- a/arch/s390/kernel/nmi.c
+++ b/arch/s390/kernel/nmi.c
@@ -254,8 +254,6 @@
 	int umode;
 
 	nmi_enter();
-	s390_idle_check(regs, S390_lowcore.mcck_clock,
-			S390_lowcore.mcck_enter_timer);
 	kstat_cpu(smp_processor_id()).irqs[NMI_NMI]++;
 	mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
 	mcck = &__get_cpu_var(cpu_mcck);
diff --git a/arch/s390/kernel/os_info.c b/arch/s390/kernel/os_info.c
new file mode 100644
index 0000000..e8d6c21
--- /dev/null
+++ b/arch/s390/kernel/os_info.c
@@ -0,0 +1,168 @@
+/*
+ * OS info memory interface
+ *
+ * Copyright IBM Corp. 2012
+ * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+
+#define KMSG_COMPONENT "os_info"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/crash_dump.h>
+#include <linux/kernel.h>
+#include <asm/checksum.h>
+#include <asm/lowcore.h>
+#include <asm/os_info.h>
+
+/*
+ * OS info structure has to be page aligned
+ */
+static struct os_info os_info __page_aligned_data;
+
+/*
+ * Compute checksum over OS info structure
+ */
+u32 os_info_csum(struct os_info *os_info)
+{
+	int size = sizeof(*os_info) - offsetof(struct os_info, version_major);
+	return csum_partial(&os_info->version_major, size, 0);
+}
+
+/*
+ * Add crashkernel info to OS info and update checksum
+ */
+void os_info_crashkernel_add(unsigned long base, unsigned long size)
+{
+	os_info.crashkernel_addr = (u64)(unsigned long)base;
+	os_info.crashkernel_size = (u64)(unsigned long)size;
+	os_info.csum = os_info_csum(&os_info);
+}
+
+/*
+ * Add OS info entry and update checksum
+ */
+void os_info_entry_add(int nr, void *ptr, u64 size)
+{
+	os_info.entry[nr].addr = (u64)(unsigned long)ptr;
+	os_info.entry[nr].size = size;
+	os_info.entry[nr].csum = csum_partial(ptr, size, 0);
+	os_info.csum = os_info_csum(&os_info);
+}
+
+/*
+ * Initialize OS info struture and set lowcore pointer
+ */
+void __init os_info_init(void)
+{
+	void *ptr = &os_info;
+
+	os_info.version_major = OS_INFO_VERSION_MAJOR;
+	os_info.version_minor = OS_INFO_VERSION_MINOR;
+	os_info.magic = OS_INFO_MAGIC;
+	os_info.csum = os_info_csum(&os_info);
+	copy_to_absolute_zero(&S390_lowcore.os_info, &ptr, sizeof(ptr));
+}
+
+#ifdef CONFIG_CRASH_DUMP
+
+static struct os_info *os_info_old;
+
+/*
+ * Allocate and copy OS info entry from oldmem
+ */
+static void os_info_old_alloc(int nr, int align)
+{
+	unsigned long addr, size = 0;
+	char *buf, *buf_align, *msg;
+	u32 csum;
+
+	addr = os_info_old->entry[nr].addr;
+	if (!addr) {
+		msg = "not available";
+		goto fail;
+	}
+	size = os_info_old->entry[nr].size;
+	buf = kmalloc(size + align - 1, GFP_KERNEL);
+	if (!buf) {
+		msg = "alloc failed";
+		goto fail;
+	}
+	buf_align = PTR_ALIGN(buf, align);
+	if (copy_from_oldmem(buf_align, (void *) addr, size)) {
+		msg = "copy failed";
+		goto fail_free;
+	}
+	csum = csum_partial(buf_align, size, 0);
+	if (csum != os_info_old->entry[nr].csum) {
+		msg = "checksum failed";
+		goto fail_free;
+	}
+	os_info_old->entry[nr].addr = (u64)(unsigned long)buf_align;
+	msg = "copied";
+	goto out;
+fail_free:
+	kfree(buf);
+fail:
+	os_info_old->entry[nr].addr = 0;
+out:
+	pr_info("entry %i: %s (addr=0x%lx size=%lu)\n",
+		nr, msg, addr, size);
+}
+
+/*
+ * Initialize os info and os info entries from oldmem
+ */
+static void os_info_old_init(void)
+{
+	static int os_info_init;
+	unsigned long addr;
+
+	if (os_info_init)
+		return;
+	if (!OLDMEM_BASE)
+		goto fail;
+	if (copy_from_oldmem(&addr, &S390_lowcore.os_info, sizeof(addr)))
+		goto fail;
+	if (addr == 0 || addr % PAGE_SIZE)
+		goto fail;
+	os_info_old = kzalloc(sizeof(*os_info_old), GFP_KERNEL);
+	if (!os_info_old)
+		goto fail;
+	if (copy_from_oldmem(os_info_old, (void *) addr, sizeof(*os_info_old)))
+		goto fail_free;
+	if (os_info_old->magic != OS_INFO_MAGIC)
+		goto fail_free;
+	if (os_info_old->csum != os_info_csum(os_info_old))
+		goto fail_free;
+	if (os_info_old->version_major > OS_INFO_VERSION_MAJOR)
+		goto fail_free;
+	os_info_old_alloc(OS_INFO_VMCOREINFO, 1);
+	os_info_old_alloc(OS_INFO_REIPL_BLOCK, 1);
+	os_info_old_alloc(OS_INFO_INIT_FN, PAGE_SIZE);
+	pr_info("crashkernel: addr=0x%lx size=%lu\n",
+		(unsigned long) os_info_old->crashkernel_addr,
+		(unsigned long) os_info_old->crashkernel_size);
+	os_info_init = 1;
+	return;
+fail_free:
+	kfree(os_info_old);
+fail:
+	os_info_init = 1;
+	os_info_old = NULL;
+}
+
+/*
+ * Return pointer to os infor entry and its size
+ */
+void *os_info_old_entry(int nr, unsigned long *size)
+{
+	os_info_old_init();
+
+	if (!os_info_old)
+		return NULL;
+	if (!os_info_old->entry[nr].addr)
+		return NULL;
+	*size = (unsigned long) os_info_old->entry[nr].size;
+	return (void *)(unsigned long)os_info_old->entry[nr].addr;
+}
+#endif
diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c
new file mode 100644
index 0000000..4640508
--- /dev/null
+++ b/arch/s390/kernel/perf_cpum_cf.c
@@ -0,0 +1,690 @@
+/*
+ * Performance event support for s390x - CPU-measurement Counter Facility
+ *
+ *  Copyright IBM Corp. 2012
+ *  Author(s): Hendrik Brueckner <brueckner@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 (version 2 only)
+ * as published by the Free Software Foundation.
+ */
+#define KMSG_COMPONENT	"cpum_cf"
+#define pr_fmt(fmt)	KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/perf_event.h>
+#include <linux/percpu.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
+#include <linux/export.h>
+#include <asm/ctl_reg.h>
+#include <asm/irq.h>
+#include <asm/cpu_mf.h>
+
+/* CPU-measurement counter facility supports these CPU counter sets:
+ * For CPU counter sets:
+ *    Basic counter set:	     0-31
+ *    Problem-state counter set:    32-63
+ *    Crypto-activity counter set:  64-127
+ *    Extented counter set:	   128-159
+ */
+enum cpumf_ctr_set {
+	/* CPU counter sets */
+	CPUMF_CTR_SET_BASIC   = 0,
+	CPUMF_CTR_SET_USER    = 1,
+	CPUMF_CTR_SET_CRYPTO  = 2,
+	CPUMF_CTR_SET_EXT     = 3,
+
+	/* Maximum number of counter sets */
+	CPUMF_CTR_SET_MAX,
+};
+
+#define CPUMF_LCCTL_ENABLE_SHIFT    16
+#define CPUMF_LCCTL_ACTCTL_SHIFT     0
+static const u64 cpumf_state_ctl[CPUMF_CTR_SET_MAX] = {
+	[CPUMF_CTR_SET_BASIC]	= 0x02,
+	[CPUMF_CTR_SET_USER]	= 0x04,
+	[CPUMF_CTR_SET_CRYPTO]	= 0x08,
+	[CPUMF_CTR_SET_EXT]	= 0x01,
+};
+
+static void ctr_set_enable(u64 *state, int ctr_set)
+{
+	*state |= cpumf_state_ctl[ctr_set] << CPUMF_LCCTL_ENABLE_SHIFT;
+}
+static void ctr_set_disable(u64 *state, int ctr_set)
+{
+	*state &= ~(cpumf_state_ctl[ctr_set] << CPUMF_LCCTL_ENABLE_SHIFT);
+}
+static void ctr_set_start(u64 *state, int ctr_set)
+{
+	*state |= cpumf_state_ctl[ctr_set] << CPUMF_LCCTL_ACTCTL_SHIFT;
+}
+static void ctr_set_stop(u64 *state, int ctr_set)
+{
+	*state &= ~(cpumf_state_ctl[ctr_set] << CPUMF_LCCTL_ACTCTL_SHIFT);
+}
+
+/* Local CPUMF event structure */
+struct cpu_hw_events {
+	struct cpumf_ctr_info	info;
+	atomic_t		ctr_set[CPUMF_CTR_SET_MAX];
+	u64			state, tx_state;
+	unsigned int		flags;
+};
+static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
+	.ctr_set = {
+		[CPUMF_CTR_SET_BASIC]  = ATOMIC_INIT(0),
+		[CPUMF_CTR_SET_USER]   = ATOMIC_INIT(0),
+		[CPUMF_CTR_SET_CRYPTO] = ATOMIC_INIT(0),
+		[CPUMF_CTR_SET_EXT]    = ATOMIC_INIT(0),
+	},
+	.state = 0,
+	.flags = 0,
+};
+
+static int get_counter_set(u64 event)
+{
+	int set = -1;
+
+	if (event < 32)
+		set = CPUMF_CTR_SET_BASIC;
+	else if (event < 64)
+		set = CPUMF_CTR_SET_USER;
+	else if (event < 128)
+		set = CPUMF_CTR_SET_CRYPTO;
+	else if (event < 160)
+		set = CPUMF_CTR_SET_EXT;
+
+	return set;
+}
+
+static int validate_event(const struct hw_perf_event *hwc)
+{
+	switch (hwc->config_base) {
+	case CPUMF_CTR_SET_BASIC:
+	case CPUMF_CTR_SET_USER:
+	case CPUMF_CTR_SET_CRYPTO:
+	case CPUMF_CTR_SET_EXT:
+		/* check for reserved counters */
+		if ((hwc->config >=  6 && hwc->config <=  31) ||
+		    (hwc->config >= 38 && hwc->config <=  63) ||
+		    (hwc->config >= 80 && hwc->config <= 127))
+			return -EOPNOTSUPP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int validate_ctr_version(const struct hw_perf_event *hwc)
+{
+	struct cpu_hw_events *cpuhw;
+	int err = 0;
+
+	cpuhw = &get_cpu_var(cpu_hw_events);
+
+	/* check required version for counter sets */
+	switch (hwc->config_base) {
+	case CPUMF_CTR_SET_BASIC:
+	case CPUMF_CTR_SET_USER:
+		if (cpuhw->info.cfvn < 1)
+			err = -EOPNOTSUPP;
+		break;
+	case CPUMF_CTR_SET_CRYPTO:
+	case CPUMF_CTR_SET_EXT:
+		if (cpuhw->info.csvn < 1)
+			err = -EOPNOTSUPP;
+		break;
+	}
+
+	put_cpu_var(cpu_hw_events);
+	return err;
+}
+
+static int validate_ctr_auth(const struct hw_perf_event *hwc)
+{
+	struct cpu_hw_events *cpuhw;
+	u64 ctrs_state;
+	int err = 0;
+
+	cpuhw = &get_cpu_var(cpu_hw_events);
+
+	/* check authorization for cpu counter sets */
+	ctrs_state = cpumf_state_ctl[hwc->config_base];
+	if (!(ctrs_state & cpuhw->info.auth_ctl))
+		err = -EPERM;
+
+	put_cpu_var(cpu_hw_events);
+	return err;
+}
+
+/*
+ * Change the CPUMF state to active.
+ * Enable and activate the CPU-counter sets according
+ * to the per-cpu control state.
+ */
+static void cpumf_pmu_enable(struct pmu *pmu)
+{
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+	int err;
+
+	if (cpuhw->flags & PMU_F_ENABLED)
+		return;
+
+	err = lcctl(cpuhw->state);
+	if (err) {
+		pr_err("Enabling the performance measuring unit "
+		       "failed with rc=%lx\n", err);
+		return;
+	}
+
+	cpuhw->flags |= PMU_F_ENABLED;
+}
+
+/*
+ * Change the CPUMF state to inactive.
+ * Disable and enable (inactive) the CPU-counter sets according
+ * to the per-cpu control state.
+ */
+static void cpumf_pmu_disable(struct pmu *pmu)
+{
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+	int err;
+	u64 inactive;
+
+	if (!(cpuhw->flags & PMU_F_ENABLED))
+		return;
+
+	inactive = cpuhw->state & ~((1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1);
+	err = lcctl(inactive);
+	if (err) {
+		pr_err("Disabling the performance measuring unit "
+		       "failed with rc=%lx\n", err);
+		return;
+	}
+
+	cpuhw->flags &= ~PMU_F_ENABLED;
+}
+
+
+/* Number of perf events counting hardware events */
+static atomic_t num_events = ATOMIC_INIT(0);
+/* Used to avoid races in calling reserve/release_cpumf_hardware */
+static DEFINE_MUTEX(pmc_reserve_mutex);
+
+/* CPU-measurement alerts for the counter facility */
+static void cpumf_measurement_alert(struct ext_code ext_code,
+				    unsigned int alert, unsigned long unused)
+{
+	struct cpu_hw_events *cpuhw;
+
+	if (!(alert & CPU_MF_INT_CF_MASK))
+		return;
+
+	kstat_cpu(smp_processor_id()).irqs[EXTINT_CPM]++;
+	cpuhw = &__get_cpu_var(cpu_hw_events);
+
+	/* Measurement alerts are shared and might happen when the PMU
+	 * is not reserved.  Ignore these alerts in this case. */
+	if (!(cpuhw->flags & PMU_F_RESERVED))
+		return;
+
+	/* counter authorization change alert */
+	if (alert & CPU_MF_INT_CF_CACA)
+		qctri(&cpuhw->info);
+
+	/* loss of counter data alert */
+	if (alert & CPU_MF_INT_CF_LCDA)
+		pr_err("CPU[%i] Counter data was lost\n", smp_processor_id());
+}
+
+#define PMC_INIT      0
+#define PMC_RELEASE   1
+static void setup_pmc_cpu(void *flags)
+{
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+	switch (*((int *) flags)) {
+	case PMC_INIT:
+		memset(&cpuhw->info, 0, sizeof(cpuhw->info));
+		qctri(&cpuhw->info);
+		cpuhw->flags |= PMU_F_RESERVED;
+		break;
+
+	case PMC_RELEASE:
+		cpuhw->flags &= ~PMU_F_RESERVED;
+		break;
+	}
+
+	/* Disable CPU counter sets */
+	lcctl(0);
+}
+
+/* Initialize the CPU-measurement facility */
+static int reserve_pmc_hardware(void)
+{
+	int flags = PMC_INIT;
+
+	on_each_cpu(setup_pmc_cpu, &flags, 1);
+	measurement_alert_subclass_register();
+
+	return 0;
+}
+
+/* Release the CPU-measurement facility */
+static void release_pmc_hardware(void)
+{
+	int flags = PMC_RELEASE;
+
+	on_each_cpu(setup_pmc_cpu, &flags, 1);
+	measurement_alert_subclass_unregister();
+}
+
+/* Release the PMU if event is the last perf event */
+static void hw_perf_event_destroy(struct perf_event *event)
+{
+	if (!atomic_add_unless(&num_events, -1, 1)) {
+		mutex_lock(&pmc_reserve_mutex);
+		if (atomic_dec_return(&num_events) == 0)
+			release_pmc_hardware();
+		mutex_unlock(&pmc_reserve_mutex);
+	}
+}
+
+/* CPUMF <-> perf event mappings for kernel+userspace (basic set) */
+static const int cpumf_generic_events_basic[] = {
+	[PERF_COUNT_HW_CPU_CYCLES]	    = 0,
+	[PERF_COUNT_HW_INSTRUCTIONS]	    = 1,
+	[PERF_COUNT_HW_CACHE_REFERENCES]    = -1,
+	[PERF_COUNT_HW_CACHE_MISSES]	    = -1,
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = -1,
+	[PERF_COUNT_HW_BRANCH_MISSES]	    = -1,
+	[PERF_COUNT_HW_BUS_CYCLES]	    = -1,
+};
+/* CPUMF <-> perf event mappings for userspace (problem-state set) */
+static const int cpumf_generic_events_user[] = {
+	[PERF_COUNT_HW_CPU_CYCLES]	    = 32,
+	[PERF_COUNT_HW_INSTRUCTIONS]	    = 33,
+	[PERF_COUNT_HW_CACHE_REFERENCES]    = -1,
+	[PERF_COUNT_HW_CACHE_MISSES]	    = -1,
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = -1,
+	[PERF_COUNT_HW_BRANCH_MISSES]	    = -1,
+	[PERF_COUNT_HW_BUS_CYCLES]	    = -1,
+};
+
+static int __hw_perf_event_init(struct perf_event *event)
+{
+	struct perf_event_attr *attr = &event->attr;
+	struct hw_perf_event *hwc = &event->hw;
+	int err;
+	u64 ev;
+
+	switch (attr->type) {
+	case PERF_TYPE_RAW:
+		/* Raw events are used to access counters directly,
+		 * hence do not permit excludes */
+		if (attr->exclude_kernel || attr->exclude_user ||
+		    attr->exclude_hv)
+			return -EOPNOTSUPP;
+		ev = attr->config;
+		break;
+
+	case PERF_TYPE_HARDWARE:
+		ev = attr->config;
+		/* Count user space (problem-state) only */
+		if (!attr->exclude_user && attr->exclude_kernel) {
+			if (ev >= ARRAY_SIZE(cpumf_generic_events_user))
+				return -EOPNOTSUPP;
+			ev = cpumf_generic_events_user[ev];
+
+		/* No support for kernel space counters only */
+		} else if (!attr->exclude_kernel && attr->exclude_user) {
+			return -EOPNOTSUPP;
+
+		/* Count user and kernel space */
+		} else {
+			if (ev >= ARRAY_SIZE(cpumf_generic_events_basic))
+				return -EOPNOTSUPP;
+			ev = cpumf_generic_events_basic[ev];
+		}
+		break;
+
+	default:
+		return -ENOENT;
+	}
+
+	if (ev == -1)
+		return -ENOENT;
+
+	if (ev >= PERF_CPUM_CF_MAX_CTR)
+		return -EINVAL;
+
+	/* The CPU measurement counter facility does not have any interrupts
+	 * to do sampling.  Sampling must be provided by external means,
+	 * for example, by timers.
+	 */
+	if (hwc->sample_period)
+		return -EINVAL;
+
+	/* Use the hardware perf event structure to store the counter number
+	 * in 'config' member and the counter set to which the counter belongs
+	 * in the 'config_base'.  The counter set (config_base) is then used
+	 * to enable/disable the counters.
+	 */
+	hwc->config = ev;
+	hwc->config_base = get_counter_set(ev);
+
+	/* Validate the counter that is assigned to this event.
+	 * Because the counter facility can use numerous counters at the
+	 * same time without constraints, it is not necessary to explicity
+	 * validate event groups (event->group_leader != event).
+	 */
+	err = validate_event(hwc);
+	if (err)
+		return err;
+
+	/* Initialize for using the CPU-measurement counter facility */
+	if (!atomic_inc_not_zero(&num_events)) {
+		mutex_lock(&pmc_reserve_mutex);
+		if (atomic_read(&num_events) == 0 && reserve_pmc_hardware())
+			err = -EBUSY;
+		else
+			atomic_inc(&num_events);
+		mutex_unlock(&pmc_reserve_mutex);
+	}
+	event->destroy = hw_perf_event_destroy;
+
+	/* Finally, validate version and authorization of the counter set */
+	err = validate_ctr_auth(hwc);
+	if (!err)
+		err = validate_ctr_version(hwc);
+
+	return err;
+}
+
+static int cpumf_pmu_event_init(struct perf_event *event)
+{
+	int err;
+
+	switch (event->attr.type) {
+	case PERF_TYPE_HARDWARE:
+	case PERF_TYPE_HW_CACHE:
+	case PERF_TYPE_RAW:
+		err = __hw_perf_event_init(event);
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	if (unlikely(err) && event->destroy)
+		event->destroy(event);
+
+	return err;
+}
+
+static int hw_perf_event_reset(struct perf_event *event)
+{
+	u64 prev, new;
+	int err;
+
+	do {
+		prev = local64_read(&event->hw.prev_count);
+		err = ecctr(event->hw.config, &new);
+		if (err) {
+			if (err != 3)
+				break;
+			/* The counter is not (yet) available. This
+			 * might happen if the counter set to which
+			 * this counter belongs is in the disabled
+			 * state.
+			 */
+			new = 0;
+		}
+	} while (local64_cmpxchg(&event->hw.prev_count, prev, new) != prev);
+
+	return err;
+}
+
+static int hw_perf_event_update(struct perf_event *event)
+{
+	u64 prev, new, delta;
+	int err;
+
+	do {
+		prev = local64_read(&event->hw.prev_count);
+		err = ecctr(event->hw.config, &new);
+		if (err)
+			goto out;
+	} while (local64_cmpxchg(&event->hw.prev_count, prev, new) != prev);
+
+	delta = (prev <= new) ? new - prev
+			      : (-1ULL - prev) + new + 1;	 /* overflow */
+	local64_add(delta, &event->count);
+out:
+	return err;
+}
+
+static void cpumf_pmu_read(struct perf_event *event)
+{
+	if (event->hw.state & PERF_HES_STOPPED)
+		return;
+
+	hw_perf_event_update(event);
+}
+
+static void cpumf_pmu_start(struct perf_event *event, int flags)
+{
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+	struct hw_perf_event *hwc = &event->hw;
+
+	if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
+		return;
+
+	if (WARN_ON_ONCE(hwc->config == -1))
+		return;
+
+	if (flags & PERF_EF_RELOAD)
+		WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+
+	hwc->state = 0;
+
+	/* (Re-)enable and activate the counter set */
+	ctr_set_enable(&cpuhw->state, hwc->config_base);
+	ctr_set_start(&cpuhw->state, hwc->config_base);
+
+	/* The counter set to which this counter belongs can be already active.
+	 * Because all counters in a set are active, the event->hw.prev_count
+	 * needs to be synchronized.  At this point, the counter set can be in
+	 * the inactive or disabled state.
+	 */
+	hw_perf_event_reset(event);
+
+	/* increment refcount for this counter set */
+	atomic_inc(&cpuhw->ctr_set[hwc->config_base]);
+}
+
+static void cpumf_pmu_stop(struct perf_event *event, int flags)
+{
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+	struct hw_perf_event *hwc = &event->hw;
+
+	if (!(hwc->state & PERF_HES_STOPPED)) {
+		/* Decrement reference count for this counter set and if this
+		 * is the last used counter in the set, clear activation
+		 * control and set the counter set state to inactive.
+		 */
+		if (!atomic_dec_return(&cpuhw->ctr_set[hwc->config_base]))
+			ctr_set_stop(&cpuhw->state, hwc->config_base);
+		event->hw.state |= PERF_HES_STOPPED;
+	}
+
+	if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+		hw_perf_event_update(event);
+		event->hw.state |= PERF_HES_UPTODATE;
+	}
+}
+
+static int cpumf_pmu_add(struct perf_event *event, int flags)
+{
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+	/* Check authorization for the counter set to which this
+	 * counter belongs.
+	 * For group events transaction, the authorization check is
+	 * done in cpumf_pmu_commit_txn().
+	 */
+	if (!(cpuhw->flags & PERF_EVENT_TXN))
+		if (validate_ctr_auth(&event->hw))
+			return -EPERM;
+
+	ctr_set_enable(&cpuhw->state, event->hw.config_base);
+	event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+	if (flags & PERF_EF_START)
+		cpumf_pmu_start(event, PERF_EF_RELOAD);
+
+	perf_event_update_userpage(event);
+
+	return 0;
+}
+
+static void cpumf_pmu_del(struct perf_event *event, int flags)
+{
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+	cpumf_pmu_stop(event, PERF_EF_UPDATE);
+
+	/* Check if any counter in the counter set is still used.  If not used,
+	 * change the counter set to the disabled state.  This also clears the
+	 * content of all counters in the set.
+	 *
+	 * When a new perf event has been added but not yet started, this can
+	 * clear enable control and resets all counters in a set.  Therefore,
+	 * cpumf_pmu_start() always has to reenable a counter set.
+	 */
+	if (!atomic_read(&cpuhw->ctr_set[event->hw.config_base]))
+		ctr_set_disable(&cpuhw->state, event->hw.config_base);
+
+	perf_event_update_userpage(event);
+}
+
+/*
+ * Start group events scheduling transaction.
+ * Set flags to perform a single test at commit time.
+ */
+static void cpumf_pmu_start_txn(struct pmu *pmu)
+{
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+	perf_pmu_disable(pmu);
+	cpuhw->flags |= PERF_EVENT_TXN;
+	cpuhw->tx_state = cpuhw->state;
+}
+
+/*
+ * Stop and cancel a group events scheduling tranctions.
+ * Assumes cpumf_pmu_del() is called for each successful added
+ * cpumf_pmu_add() during the transaction.
+ */
+static void cpumf_pmu_cancel_txn(struct pmu *pmu)
+{
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+	WARN_ON(cpuhw->tx_state != cpuhw->state);
+
+	cpuhw->flags &= ~PERF_EVENT_TXN;
+	perf_pmu_enable(pmu);
+}
+
+/*
+ * Commit the group events scheduling transaction.  On success, the
+ * transaction is closed.   On error, the transaction is kept open
+ * until cpumf_pmu_cancel_txn() is called.
+ */
+static int cpumf_pmu_commit_txn(struct pmu *pmu)
+{
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+	u64 state;
+
+	/* check if the updated state can be scheduled */
+	state = cpuhw->state & ~((1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1);
+	state >>= CPUMF_LCCTL_ENABLE_SHIFT;
+	if ((state & cpuhw->info.auth_ctl) != state)
+		return -EPERM;
+
+	cpuhw->flags &= ~PERF_EVENT_TXN;
+	perf_pmu_enable(pmu);
+	return 0;
+}
+
+/* Performance monitoring unit for s390x */
+static struct pmu cpumf_pmu = {
+	.pmu_enable   = cpumf_pmu_enable,
+	.pmu_disable  = cpumf_pmu_disable,
+	.event_init   = cpumf_pmu_event_init,
+	.add	      = cpumf_pmu_add,
+	.del	      = cpumf_pmu_del,
+	.start	      = cpumf_pmu_start,
+	.stop	      = cpumf_pmu_stop,
+	.read	      = cpumf_pmu_read,
+	.start_txn    = cpumf_pmu_start_txn,
+	.commit_txn   = cpumf_pmu_commit_txn,
+	.cancel_txn   = cpumf_pmu_cancel_txn,
+};
+
+static int __cpuinit cpumf_pmu_notifier(struct notifier_block *self,
+					unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (long) hcpu;
+	int flags;
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_ONLINE:
+		flags = PMC_INIT;
+		smp_call_function_single(cpu, setup_pmc_cpu, &flags, 1);
+		break;
+	case CPU_DOWN_PREPARE:
+		flags = PMC_RELEASE;
+		smp_call_function_single(cpu, setup_pmc_cpu, &flags, 1);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static int __init cpumf_pmu_init(void)
+{
+	int rc;
+
+	if (!cpum_cf_avail())
+		return -ENODEV;
+
+	/* clear bit 15 of cr0 to unauthorize problem-state to
+	 * extract measurement counters */
+	ctl_clear_bit(0, 48);
+
+	/* register handler for measurement-alert interruptions */
+	rc = register_external_interrupt(0x1407, cpumf_measurement_alert);
+	if (rc) {
+		pr_err("Registering for CPU-measurement alerts "
+		       "failed with rc=%i\n", rc);
+		goto out;
+	}
+
+	rc = perf_pmu_register(&cpumf_pmu, "cpum_cf", PERF_TYPE_RAW);
+	if (rc) {
+		pr_err("Registering the cpum_cf PMU failed with rc=%i\n", rc);
+		unregister_external_interrupt(0x1407, cpumf_measurement_alert);
+		goto out;
+	}
+	perf_cpu_notifier(cpumf_pmu_notifier);
+out:
+	return rc;
+}
+early_initcall(cpumf_pmu_init);
diff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c
new file mode 100644
index 0000000..f58f37f
--- /dev/null
+++ b/arch/s390/kernel/perf_event.c
@@ -0,0 +1,124 @@
+/*
+ * Performance event support for s390x
+ *
+ *  Copyright IBM Corp. 2012
+ *  Author(s): Hendrik Brueckner <brueckner@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 (version 2 only)
+ * as published by the Free Software Foundation.
+ */
+#define KMSG_COMPONENT	"perf"
+#define pr_fmt(fmt)	KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/percpu.h>
+#include <linux/export.h>
+#include <asm/irq.h>
+#include <asm/cpu_mf.h>
+#include <asm/lowcore.h>
+#include <asm/processor.h>
+
+const char *perf_pmu_name(void)
+{
+	if (cpum_cf_avail() || cpum_sf_avail())
+		return "CPU-measurement facilities (CPUMF)";
+	return "pmu";
+}
+EXPORT_SYMBOL(perf_pmu_name);
+
+int perf_num_counters(void)
+{
+	int num = 0;
+
+	if (cpum_cf_avail())
+		num += PERF_CPUM_CF_MAX_CTR;
+
+	return num;
+}
+EXPORT_SYMBOL(perf_num_counters);
+
+void perf_event_print_debug(void)
+{
+	struct cpumf_ctr_info cf_info;
+	unsigned long flags;
+	int cpu;
+
+	if (!cpum_cf_avail())
+		return;
+
+	local_irq_save(flags);
+
+	cpu = smp_processor_id();
+	memset(&cf_info, 0, sizeof(cf_info));
+	if (!qctri(&cf_info)) {
+		pr_info("CPU[%i] CPUM_CF: ver=%u.%u A=%04x E=%04x C=%04x\n",
+			cpu, cf_info.cfvn, cf_info.csvn,
+			cf_info.auth_ctl, cf_info.enable_ctl, cf_info.act_ctl);
+		print_hex_dump_bytes("CPUMF Query: ", DUMP_PREFIX_OFFSET,
+				     &cf_info, sizeof(cf_info));
+	}
+
+	local_irq_restore(flags);
+}
+
+/* See also arch/s390/kernel/traps.c */
+static unsigned long __store_trace(struct perf_callchain_entry *entry,
+				   unsigned long sp,
+				   unsigned long low, unsigned long high)
+{
+	struct stack_frame *sf;
+	struct pt_regs *regs;
+
+	while (1) {
+		sp = sp & PSW_ADDR_INSN;
+		if (sp < low || sp > high - sizeof(*sf))
+			return sp;
+		sf = (struct stack_frame *) sp;
+		perf_callchain_store(entry, sf->gprs[8] & PSW_ADDR_INSN);
+		/* Follow the backchain. */
+		while (1) {
+			low = sp;
+			sp = sf->back_chain & PSW_ADDR_INSN;
+			if (!sp)
+				break;
+			if (sp <= low || sp > high - sizeof(*sf))
+				return sp;
+			sf = (struct stack_frame *) sp;
+			perf_callchain_store(entry,
+					     sf->gprs[8] & PSW_ADDR_INSN);
+		}
+		/* Zero backchain detected, check for interrupt frame. */
+		sp = (unsigned long) (sf + 1);
+		if (sp <= low || sp > high - sizeof(*regs))
+			return sp;
+		regs = (struct pt_regs *) sp;
+		perf_callchain_store(entry, sf->gprs[8] & PSW_ADDR_INSN);
+		low = sp;
+		sp = regs->gprs[15];
+	}
+}
+
+void perf_callchain_kernel(struct perf_callchain_entry *entry,
+			   struct pt_regs *regs)
+{
+	unsigned long head;
+	struct stack_frame *head_sf;
+
+	if (user_mode(regs))
+		return;
+
+	head = regs->gprs[15];
+	head_sf = (struct stack_frame *) head;
+
+	if (!head_sf || !head_sf->back_chain)
+		return;
+
+	head = head_sf->back_chain;
+	head = __store_trace(entry, head, S390_lowcore.async_stack - ASYNC_SIZE,
+			     S390_lowcore.async_stack);
+
+	__store_trace(entry, head, S390_lowcore.thread_info,
+		      S390_lowcore.thread_info + THREAD_SIZE);
+}
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 7618085..60055ce 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -23,13 +23,13 @@
 #include <linux/kprobes.h>
 #include <linux/random.h>
 #include <linux/module.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/irq.h>
 #include <asm/timer.h>
 #include <asm/nmi.h>
 #include <asm/smp.h>
+#include <asm/switch_to.h>
 #include "entry.h"
 
 asmlinkage void ret_from_fork(void) asm ("ret_from_fork");
@@ -77,13 +77,8 @@
 		local_irq_enable();
 		return;
 	}
-	trace_hardirqs_on();
-	/* Don't trace preempt off for idle. */
-	stop_critical_timings();
-	/* Stop virtual timer and halt the cpu. */
+	/* Halt the cpu and keep track of cpu time accounting. */
 	vtime_stop_cpu();
-	/* Reenable preemption tracer. */
-	start_critical_timings();
 }
 
 void cpu_idle(void)
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 61f9548..02f300f 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -26,9 +26,9 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
+#include <asm/switch_to.h>
 #include "entry.h"
 
 #ifdef CONFIG_COMPAT
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 3b2efc8..06264ae 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -2,7 +2,7 @@
  *  arch/s390/kernel/setup.c
  *
  *  S390 version
- *    Copyright (C) IBM Corp. 1999,2010
+ *    Copyright (C) IBM Corp. 1999,2012
  *    Author(s): Hartmut Penner (hp@de.ibm.com),
  *               Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
@@ -50,7 +50,7 @@
 
 #include <asm/ipl.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
+#include <asm/facility.h>
 #include <asm/smp.h>
 #include <asm/mmu_context.h>
 #include <asm/cpcmd.h>
@@ -62,6 +62,8 @@
 #include <asm/ebcdic.h>
 #include <asm/kvm_virtio.h>
 #include <asm/diag.h>
+#include <asm/os_info.h>
+#include "entry.h"
 
 long psw_kernel_bits	= PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_ASC_PRIMARY |
 			  PSW_MASK_EA | PSW_MASK_BA;
@@ -351,8 +353,9 @@
 	}
 }
 
-static void __init
-setup_lowcore(void)
+void *restart_stack __attribute__((__section__(".data")));
+
+static void __init setup_lowcore(void)
 {
 	struct _lowcore *lc;
 
@@ -363,7 +366,7 @@
 	lc = __alloc_bootmem_low(LC_PAGES * PAGE_SIZE, LC_PAGES * PAGE_SIZE, 0);
 	lc->restart_psw.mask = psw_kernel_bits;
 	lc->restart_psw.addr =
-		PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler;
+		PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
 	lc->external_new_psw.mask = psw_kernel_bits |
 		PSW_MASK_DAT | PSW_MASK_MCHECK;
 	lc->external_new_psw.addr =
@@ -412,6 +415,24 @@
 	lc->last_update_timer = S390_lowcore.last_update_timer;
 	lc->last_update_clock = S390_lowcore.last_update_clock;
 	lc->ftrace_func = S390_lowcore.ftrace_func;
+
+	restart_stack = __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0);
+	restart_stack += ASYNC_SIZE;
+
+	/*
+	 * Set up PSW restart to call ipl.c:do_restart(). Copy the relevant
+	 * restart data to the absolute zero lowcore. This is necesary if
+	 * PSW restart is done on an offline CPU that has lowcore zero.
+	 */
+	lc->restart_stack = (unsigned long) restart_stack;
+	lc->restart_fn = (unsigned long) do_restart;
+	lc->restart_data = 0;
+	lc->restart_source = -1UL;
+	memcpy(&S390_lowcore.restart_stack, &lc->restart_stack,
+	       4*sizeof(unsigned long));
+	copy_to_absolute_zero(&S390_lowcore.restart_psw,
+			      &lc->restart_psw, sizeof(psw_t));
+
 	set_prefix((u32)(unsigned long) lc);
 	lowcore_ptr[0] = lc;
 }
@@ -572,27 +593,6 @@
 	}
 }
 
-void *restart_stack __attribute__((__section__(".data")));
-
-/*
- * Setup new PSW and allocate stack for PSW restart interrupt
- */
-static void __init setup_restart_psw(void)
-{
-	psw_t psw;
-
-	restart_stack = __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0);
-	restart_stack += ASYNC_SIZE;
-
-	/*
-	 * Setup restart PSW for absolute zero lowcore. This is necesary
-	 * if PSW restart is done on an offline CPU that has lowcore zero
-	 */
-	psw.mask = PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA | PSW_MASK_BA;
-	psw.addr = PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler;
-	copy_to_absolute_zero(&S390_lowcore.restart_psw, &psw, sizeof(psw));
-}
-
 static void __init setup_vmcoreinfo(void)
 {
 #ifdef CONFIG_KEXEC
@@ -747,7 +747,7 @@
 {
 #ifdef CONFIG_CRASH_DUMP
 	unsigned long long crash_base, crash_size;
-	char *msg;
+	char *msg = NULL;
 	int rc;
 
 	rc = parse_crashkernel(boot_command_line, memory_end, &crash_size,
@@ -779,11 +779,11 @@
 	pr_info("Reserving %lluMB of memory at %lluMB "
 		"for crashkernel (System RAM: %luMB)\n",
 		crash_size >> 20, crash_base >> 20, memory_end >> 20);
+	os_info_crashkernel_add(crash_base, crash_size);
 #endif
 }
 
-static void __init
-setup_memory(void)
+static void __init setup_memory(void)
 {
         unsigned long bootmap_size;
 	unsigned long start_pfn, end_pfn;
@@ -1014,8 +1014,7 @@
  * was printed.
  */
 
-void __init
-setup_arch(char **cmdline_p)
+void __init setup_arch(char **cmdline_p)
 {
         /*
          * print what head.S has found out about the machine
@@ -1060,6 +1059,7 @@
 
 	parse_early_param();
 
+	os_info_init();
 	setup_ipl();
 	setup_memory_end();
 	setup_addressing_mode();
@@ -1068,7 +1068,6 @@
 	setup_memory();
 	setup_resources();
 	setup_vmcoreinfo();
-	setup_restart_psw();
 	setup_lowcore();
 
         cpu_init();
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 2d421d9..f7582b2 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -30,6 +30,7 @@
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/lowcore.h>
+#include <asm/switch_to.h>
 #include "entry.h"
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -384,7 +385,6 @@
 			 siginfo_t *info, sigset_t *oldset,
 			 struct pt_regs *regs)
 {
-	sigset_t blocked;
 	int ret;
 
 	/* Set up the stack frame */
@@ -394,10 +394,7 @@
 		ret = setup_frame(sig, ka, oldset, regs);
 	if (ret)
 		return ret;
-	sigorsets(&blocked, &current->blocked, &ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&blocked, sig);
-	set_current_blocked(&blocked);
+	block_sigmask(ka, sig);
 	return 0;
 }
 
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index b0e28c4..1f77227 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -1,23 +1,18 @@
 /*
- *  arch/s390/kernel/smp.c
+ *  SMP related functions
  *
- *    Copyright IBM Corp. 1999, 2009
- *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
- *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
- *		 Heiko Carstens (heiko.carstens@de.ibm.com)
+ *    Copyright IBM Corp. 1999,2012
+ *    Author(s): Denis Joseph Barrow,
+ *		 Martin Schwidefsky <schwidefsky@de.ibm.com>,
+ *		 Heiko Carstens <heiko.carstens@de.ibm.com>,
  *
  *  based on other smp stuff by
  *    (c) 1995 Alan Cox, CymruNET Ltd  <alan@cymru.net>
  *    (c) 1998 Ingo Molnar
  *
- * We work with logical cpu numbering everywhere we can. The only
- * functions using the real cpu address (got from STAP) are the sigp
- * functions. For all other functions we use the identity mapping.
- * That means that cpu_number_map[i] == i for every cpu. cpu_number_map is
- * used e.g. to find the idle task belonging to a logical cpu. Every array
- * in the kernel is sorted by the logical cpu number and not by the physical
- * one which is causing all the confusion with __cpu_logical_map and
- * cpu_number_map in other architectures.
+ * The code outside of smp.c uses logical cpu numbers, only smp.c does
+ * the translation of logical to physical cpu ids. All new code that
+ * operates on physical cpu numbers needs to go into smp.c.
  */
 
 #define KMSG_COMPONENT "cpu"
@@ -31,198 +26,435 @@
 #include <linux/spinlock.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
-#include <linux/cache.h>
 #include <linux/interrupt.h>
 #include <linux/irqflags.h>
 #include <linux/cpu.h>
-#include <linux/timex.h>
-#include <linux/bootmem.h>
 #include <linux/slab.h>
 #include <linux/crash_dump.h>
 #include <asm/asm-offsets.h>
+#include <asm/switch_to.h>
+#include <asm/facility.h>
 #include <asm/ipl.h>
 #include <asm/setup.h>
-#include <asm/sigp.h>
-#include <asm/pgalloc.h>
 #include <asm/irq.h>
-#include <asm/cpcmd.h>
 #include <asm/tlbflush.h>
 #include <asm/timer.h>
 #include <asm/lowcore.h>
 #include <asm/sclp.h>
-#include <asm/cputime.h>
 #include <asm/vdso.h>
-#include <asm/cpu.h>
+#include <asm/debug.h>
+#include <asm/os_info.h>
 #include "entry.h"
 
-/* logical cpu to cpu address */
-unsigned short __cpu_logical_map[NR_CPUS];
+enum {
+	sigp_sense = 1,
+	sigp_external_call = 2,
+	sigp_emergency_signal = 3,
+	sigp_start = 4,
+	sigp_stop = 5,
+	sigp_restart = 6,
+	sigp_stop_and_store_status = 9,
+	sigp_initial_cpu_reset = 11,
+	sigp_cpu_reset = 12,
+	sigp_set_prefix = 13,
+	sigp_store_status_at_address = 14,
+	sigp_store_extended_status_at_address = 15,
+	sigp_set_architecture = 18,
+	sigp_conditional_emergency_signal = 19,
+	sigp_sense_running = 21,
+};
 
-static struct task_struct *current_set[NR_CPUS];
+enum {
+	sigp_order_code_accepted = 0,
+	sigp_status_stored = 1,
+	sigp_busy = 2,
+	sigp_not_operational = 3,
+};
 
-static u8 smp_cpu_type;
-static int smp_use_sigp_detection;
+enum {
+	ec_schedule = 0,
+	ec_call_function,
+	ec_call_function_single,
+	ec_stop_cpu,
+};
 
-enum s390_cpu_state {
+enum {
 	CPU_STATE_STANDBY,
 	CPU_STATE_CONFIGURED,
 };
 
+struct pcpu {
+	struct cpu cpu;
+	struct task_struct *idle;	/* idle process for the cpu */
+	struct _lowcore *lowcore;	/* lowcore page(s) for the cpu */
+	unsigned long async_stack;	/* async stack for the cpu */
+	unsigned long panic_stack;	/* panic stack for the cpu */
+	unsigned long ec_mask;		/* bit mask for ec_xxx functions */
+	int state;			/* physical cpu state */
+	u32 status;			/* last status received via sigp */
+	u16 address;			/* physical cpu address */
+};
+
+static u8 boot_cpu_type;
+static u16 boot_cpu_address;
+static struct pcpu pcpu_devices[NR_CPUS];
+
 DEFINE_MUTEX(smp_cpu_state_mutex);
-static int smp_cpu_state[NR_CPUS];
 
-static DEFINE_PER_CPU(struct cpu, cpu_devices);
-
-static void smp_ext_bitcall(int, int);
-
-static int raw_cpu_stopped(int cpu)
+/*
+ * Signal processor helper functions.
+ */
+static inline int __pcpu_sigp(u16 addr, u8 order, u32 parm, u32 *status)
 {
-	u32 status;
+	register unsigned int reg1 asm ("1") = parm;
+	int cc;
 
-	switch (raw_sigp_ps(&status, 0, cpu, sigp_sense)) {
-	case sigp_status_stored:
-		/* Check for stopped and check stop state */
-		if (status & 0x50)
-			return 1;
-		break;
-	default:
-		break;
-	}
-	return 0;
+	asm volatile(
+		"	sigp	%1,%2,0(%3)\n"
+		"	ipm	%0\n"
+		"	srl	%0,28\n"
+		: "=d" (cc), "+d" (reg1) : "d" (addr), "a" (order) : "cc");
+	if (status && cc == 1)
+		*status = reg1;
+	return cc;
 }
 
-static inline int cpu_stopped(int cpu)
+static inline int __pcpu_sigp_relax(u16 addr, u8 order, u32 parm, u32 *status)
 {
-	return raw_cpu_stopped(cpu_logical_map(cpu));
+	int cc;
+
+	while (1) {
+		cc = __pcpu_sigp(addr, order, parm, status);
+		if (cc != sigp_busy)
+			return cc;
+		cpu_relax();
+	}
+}
+
+static int pcpu_sigp_retry(struct pcpu *pcpu, u8 order, u32 parm)
+{
+	int cc, retry;
+
+	for (retry = 0; ; retry++) {
+		cc = __pcpu_sigp(pcpu->address, order, parm, &pcpu->status);
+		if (cc != sigp_busy)
+			break;
+		if (retry >= 3)
+			udelay(10);
+	}
+	return cc;
+}
+
+static inline int pcpu_stopped(struct pcpu *pcpu)
+{
+	if (__pcpu_sigp(pcpu->address, sigp_sense,
+			0, &pcpu->status) != sigp_status_stored)
+		return 0;
+	/* Check for stopped and check stop state */
+	return !!(pcpu->status & 0x50);
+}
+
+static inline int pcpu_running(struct pcpu *pcpu)
+{
+	if (__pcpu_sigp(pcpu->address, sigp_sense_running,
+			0, &pcpu->status) != sigp_status_stored)
+		return 1;
+	/* Check for running status */
+	return !(pcpu->status & 0x400);
 }
 
 /*
- * Ensure that PSW restart is done on an online CPU
+ * Find struct pcpu by cpu address.
  */
-void smp_restart_with_online_cpu(void)
+static struct pcpu *pcpu_find_address(const struct cpumask *mask, int address)
 {
 	int cpu;
 
-	for_each_online_cpu(cpu) {
-		if (stap() == __cpu_logical_map[cpu]) {
-			/* We are online: Enable DAT again and return */
-			__load_psw_mask(psw_kernel_bits | PSW_MASK_DAT);
-			return;
-		}
+	for_each_cpu(cpu, mask)
+		if (pcpu_devices[cpu].address == address)
+			return pcpu_devices + cpu;
+	return NULL;
+}
+
+static void pcpu_ec_call(struct pcpu *pcpu, int ec_bit)
+{
+	int order;
+
+	set_bit(ec_bit, &pcpu->ec_mask);
+	order = pcpu_running(pcpu) ?
+		sigp_external_call : sigp_emergency_signal;
+	pcpu_sigp_retry(pcpu, order, 0);
+}
+
+static int __cpuinit pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
+{
+	struct _lowcore *lc;
+
+	if (pcpu != &pcpu_devices[0]) {
+		pcpu->lowcore =	(struct _lowcore *)
+			__get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER);
+		pcpu->async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
+		pcpu->panic_stack = __get_free_page(GFP_KERNEL);
+		if (!pcpu->lowcore || !pcpu->panic_stack || !pcpu->async_stack)
+			goto out;
 	}
-	/* We are not online: Do PSW restart on an online CPU */
-	while (sigp(cpu, sigp_restart) == sigp_busy)
-		cpu_relax();
-	/* And stop ourself */
-	while (raw_sigp(stap(), sigp_stop) == sigp_busy)
-		cpu_relax();
-	for (;;);
+	lc = pcpu->lowcore;
+	memcpy(lc, &S390_lowcore, 512);
+	memset((char *) lc + 512, 0, sizeof(*lc) - 512);
+	lc->async_stack = pcpu->async_stack + ASYNC_SIZE;
+	lc->panic_stack = pcpu->panic_stack + PAGE_SIZE;
+	lc->cpu_nr = cpu;
+#ifndef CONFIG_64BIT
+	if (MACHINE_HAS_IEEE) {
+		lc->extended_save_area_addr = get_zeroed_page(GFP_KERNEL);
+		if (!lc->extended_save_area_addr)
+			goto out;
+	}
+#else
+	if (vdso_alloc_per_cpu(lc))
+		goto out;
+#endif
+	lowcore_ptr[cpu] = lc;
+	pcpu_sigp_retry(pcpu, sigp_set_prefix, (u32)(unsigned long) lc);
+	return 0;
+out:
+	if (pcpu != &pcpu_devices[0]) {
+		free_page(pcpu->panic_stack);
+		free_pages(pcpu->async_stack, ASYNC_ORDER);
+		free_pages((unsigned long) pcpu->lowcore, LC_ORDER);
+	}
+	return -ENOMEM;
 }
 
-void smp_switch_to_ipl_cpu(void (*func)(void *), void *data)
+static void pcpu_free_lowcore(struct pcpu *pcpu)
 {
-	struct _lowcore *lc, *current_lc;
-	struct stack_frame *sf;
-	struct pt_regs *regs;
-	unsigned long sp;
+	pcpu_sigp_retry(pcpu, sigp_set_prefix, 0);
+	lowcore_ptr[pcpu - pcpu_devices] = NULL;
+#ifndef CONFIG_64BIT
+	if (MACHINE_HAS_IEEE) {
+		struct _lowcore *lc = pcpu->lowcore;
 
-	if (smp_processor_id() == 0)
-		func(data);
-	__load_psw_mask(PSW_DEFAULT_KEY | PSW_MASK_BASE |
-			PSW_MASK_EA | PSW_MASK_BA);
-	/* Disable lowcore protection */
-	__ctl_clear_bit(0, 28);
-	current_lc = lowcore_ptr[smp_processor_id()];
-	lc = lowcore_ptr[0];
-	if (!lc)
-		lc = current_lc;
-	lc->restart_psw.mask =
-		PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA | PSW_MASK_BA;
-	lc->restart_psw.addr = PSW_ADDR_AMODE | (unsigned long) smp_restart_cpu;
-	if (!cpu_online(0))
-		smp_switch_to_cpu(func, data, 0, stap(), __cpu_logical_map[0]);
-	while (sigp(0, sigp_stop_and_store_status) == sigp_busy)
-		cpu_relax();
-	sp = lc->panic_stack;
-	sp -= sizeof(struct pt_regs);
-	regs = (struct pt_regs *) sp;
-	memcpy(&regs->gprs, &current_lc->gpregs_save_area, sizeof(regs->gprs));
-	regs->psw = current_lc->psw_save_area;
-	sp -= STACK_FRAME_OVERHEAD;
-	sf = (struct stack_frame *) sp;
-	sf->back_chain = 0;
-	smp_switch_to_cpu(func, data, sp, stap(), __cpu_logical_map[0]);
+		free_page((unsigned long) lc->extended_save_area_addr);
+		lc->extended_save_area_addr = 0;
+	}
+#else
+	vdso_free_per_cpu(pcpu->lowcore);
+#endif
+	if (pcpu != &pcpu_devices[0]) {
+		free_page(pcpu->panic_stack);
+		free_pages(pcpu->async_stack, ASYNC_ORDER);
+		free_pages((unsigned long) pcpu->lowcore, LC_ORDER);
+	}
 }
 
-static void smp_stop_cpu(void)
+static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
 {
-	while (sigp(smp_processor_id(), sigp_stop) == sigp_busy)
-		cpu_relax();
+	struct _lowcore *lc = pcpu->lowcore;
+
+	atomic_inc(&init_mm.context.attach_count);
+	lc->cpu_nr = cpu;
+	lc->percpu_offset = __per_cpu_offset[cpu];
+	lc->kernel_asce = S390_lowcore.kernel_asce;
+	lc->machine_flags = S390_lowcore.machine_flags;
+	lc->ftrace_func = S390_lowcore.ftrace_func;
+	lc->user_timer = lc->system_timer = lc->steal_timer = 0;
+	__ctl_store(lc->cregs_save_area, 0, 15);
+	save_access_regs((unsigned int *) lc->access_regs_save_area);
+	memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
+	       MAX_FACILITY_BIT/8);
 }
 
+static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk)
+{
+	struct _lowcore *lc = pcpu->lowcore;
+	struct thread_info *ti = task_thread_info(tsk);
+
+	lc->kernel_stack = (unsigned long) task_stack_page(tsk) + THREAD_SIZE;
+	lc->thread_info = (unsigned long) task_thread_info(tsk);
+	lc->current_task = (unsigned long) tsk;
+	lc->user_timer = ti->user_timer;
+	lc->system_timer = ti->system_timer;
+	lc->steal_timer = 0;
+}
+
+static void pcpu_start_fn(struct pcpu *pcpu, void (*func)(void *), void *data)
+{
+	struct _lowcore *lc = pcpu->lowcore;
+
+	lc->restart_stack = lc->kernel_stack;
+	lc->restart_fn = (unsigned long) func;
+	lc->restart_data = (unsigned long) data;
+	lc->restart_source = -1UL;
+	pcpu_sigp_retry(pcpu, sigp_restart, 0);
+}
+
+/*
+ * Call function via PSW restart on pcpu and stop the current cpu.
+ */
+static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *),
+			  void *data, unsigned long stack)
+{
+	struct _lowcore *lc = pcpu->lowcore;
+	unsigned short this_cpu;
+
+	__load_psw_mask(psw_kernel_bits);
+	this_cpu = stap();
+	if (pcpu->address == this_cpu)
+		func(data);	/* should not return */
+	/* Stop target cpu (if func returns this stops the current cpu). */
+	pcpu_sigp_retry(pcpu, sigp_stop, 0);
+	/* Restart func on the target cpu and stop the current cpu. */
+	lc->restart_stack = stack;
+	lc->restart_fn = (unsigned long) func;
+	lc->restart_data = (unsigned long) data;
+	lc->restart_source = (unsigned long) this_cpu;
+	asm volatile(
+		"0:	sigp	0,%0,6	# sigp restart to target cpu\n"
+		"	brc	2,0b	# busy, try again\n"
+		"1:	sigp	0,%1,5	# sigp stop to current cpu\n"
+		"	brc	2,1b	# busy, try again\n"
+		: : "d" (pcpu->address), "d" (this_cpu) : "0", "1", "cc");
+	for (;;) ;
+}
+
+/*
+ * Call function on an online CPU.
+ */
+void smp_call_online_cpu(void (*func)(void *), void *data)
+{
+	struct pcpu *pcpu;
+
+	/* Use the current cpu if it is online. */
+	pcpu = pcpu_find_address(cpu_online_mask, stap());
+	if (!pcpu)
+		/* Use the first online cpu. */
+		pcpu = pcpu_devices + cpumask_first(cpu_online_mask);
+	pcpu_delegate(pcpu, func, data, (unsigned long) restart_stack);
+}
+
+/*
+ * Call function on the ipl CPU.
+ */
+void smp_call_ipl_cpu(void (*func)(void *), void *data)
+{
+	pcpu_delegate(&pcpu_devices[0], func, data,
+		      pcpu_devices->panic_stack + PAGE_SIZE);
+}
+
+int smp_find_processor_id(u16 address)
+{
+	int cpu;
+
+	for_each_present_cpu(cpu)
+		if (pcpu_devices[cpu].address == address)
+			return cpu;
+	return -1;
+}
+
+int smp_vcpu_scheduled(int cpu)
+{
+	return pcpu_running(pcpu_devices + cpu);
+}
+
+void smp_yield(void)
+{
+	if (MACHINE_HAS_DIAG44)
+		asm volatile("diag 0,0,0x44");
+}
+
+void smp_yield_cpu(int cpu)
+{
+	if (MACHINE_HAS_DIAG9C)
+		asm volatile("diag %0,0,0x9c"
+			     : : "d" (pcpu_devices[cpu].address));
+	else if (MACHINE_HAS_DIAG44)
+		asm volatile("diag 0,0,0x44");
+}
+
+/*
+ * Send cpus emergency shutdown signal. This gives the cpus the
+ * opportunity to complete outstanding interrupts.
+ */
+void smp_emergency_stop(cpumask_t *cpumask)
+{
+	u64 end;
+	int cpu;
+
+	end = get_clock() + (1000000UL << 12);
+	for_each_cpu(cpu, cpumask) {
+		struct pcpu *pcpu = pcpu_devices + cpu;
+		set_bit(ec_stop_cpu, &pcpu->ec_mask);
+		while (__pcpu_sigp(pcpu->address, sigp_emergency_signal,
+				   0, NULL) == sigp_busy &&
+		       get_clock() < end)
+			cpu_relax();
+	}
+	while (get_clock() < end) {
+		for_each_cpu(cpu, cpumask)
+			if (pcpu_stopped(pcpu_devices + cpu))
+				cpumask_clear_cpu(cpu, cpumask);
+		if (cpumask_empty(cpumask))
+			break;
+		cpu_relax();
+	}
+}
+
+/*
+ * Stop all cpus but the current one.
+ */
 void smp_send_stop(void)
 {
 	cpumask_t cpumask;
 	int cpu;
-	u64 end;
 
 	/* Disable all interrupts/machine checks */
 	__load_psw_mask(psw_kernel_bits | PSW_MASK_DAT);
 	trace_hardirqs_off();
 
+	debug_set_critical();
 	cpumask_copy(&cpumask, cpu_online_mask);
 	cpumask_clear_cpu(smp_processor_id(), &cpumask);
 
-	if (oops_in_progress) {
-		/*
-		 * Give the other cpus the opportunity to complete
-		 * outstanding interrupts before stopping them.
-		 */
-		end = get_clock() + (1000000UL << 12);
-		for_each_cpu(cpu, &cpumask) {
-			set_bit(ec_stop_cpu, (unsigned long *)
-				&lowcore_ptr[cpu]->ext_call_fast);
-			while (sigp(cpu, sigp_emergency_signal) == sigp_busy &&
-			       get_clock() < end)
-				cpu_relax();
-		}
-		while (get_clock() < end) {
-			for_each_cpu(cpu, &cpumask)
-				if (cpu_stopped(cpu))
-					cpumask_clear_cpu(cpu, &cpumask);
-			if (cpumask_empty(&cpumask))
-				break;
-			cpu_relax();
-		}
-	}
+	if (oops_in_progress)
+		smp_emergency_stop(&cpumask);
 
 	/* stop all processors */
 	for_each_cpu(cpu, &cpumask) {
-		while (sigp(cpu, sigp_stop) == sigp_busy)
-			cpu_relax();
-		while (!cpu_stopped(cpu))
+		struct pcpu *pcpu = pcpu_devices + cpu;
+		pcpu_sigp_retry(pcpu, sigp_stop, 0);
+		while (!pcpu_stopped(pcpu))
 			cpu_relax();
 	}
 }
 
 /*
+ * Stop the current cpu.
+ */
+void smp_stop_cpu(void)
+{
+	pcpu_sigp_retry(pcpu_devices + smp_processor_id(), sigp_stop, 0);
+	for (;;) ;
+}
+
+/*
  * This is the main routine where commands issued by other
  * cpus are handled.
  */
-
-static void do_ext_call_interrupt(unsigned int ext_int_code,
+static void do_ext_call_interrupt(struct ext_code ext_code,
 				  unsigned int param32, unsigned long param64)
 {
 	unsigned long bits;
+	int cpu;
 
-	if ((ext_int_code & 0xffff) == 0x1202)
-		kstat_cpu(smp_processor_id()).irqs[EXTINT_EXC]++;
+	cpu = smp_processor_id();
+	if (ext_code.code == 0x1202)
+		kstat_cpu(cpu).irqs[EXTINT_EXC]++;
 	else
-		kstat_cpu(smp_processor_id()).irqs[EXTINT_EMS]++;
+		kstat_cpu(cpu).irqs[EXTINT_EMS]++;
 	/*
 	 * handle bit signal external calls
 	 */
-	bits = xchg(&S390_lowcore.ext_call_fast, 0);
+	bits = xchg(&pcpu_devices[cpu].ec_mask, 0);
 
 	if (test_bit(ec_stop_cpu, &bits))
 		smp_stop_cpu();
@@ -238,38 +470,17 @@
 
 }
 
-/*
- * Send an external call sigp to another cpu and return without waiting
- * for its completion.
- */
-static void smp_ext_bitcall(int cpu, int sig)
-{
-	int order;
-
-	/*
-	 * Set signaling bit in lowcore of target cpu and kick it
-	 */
-	set_bit(sig, (unsigned long *) &lowcore_ptr[cpu]->ext_call_fast);
-	while (1) {
-		order = smp_vcpu_scheduled(cpu) ?
-			sigp_external_call : sigp_emergency_signal;
-		if (sigp(cpu, order) != sigp_busy)
-			break;
-		udelay(10);
-	}
-}
-
 void arch_send_call_function_ipi_mask(const struct cpumask *mask)
 {
 	int cpu;
 
 	for_each_cpu(cpu, mask)
-		smp_ext_bitcall(cpu, ec_call_function);
+		pcpu_ec_call(pcpu_devices + cpu, ec_call_function);
 }
 
 void arch_send_call_function_single_ipi(int cpu)
 {
-	smp_ext_bitcall(cpu, ec_call_function_single);
+	pcpu_ec_call(pcpu_devices + cpu, ec_call_function_single);
 }
 
 #ifndef CONFIG_64BIT
@@ -295,15 +506,16 @@
  */
 void smp_send_reschedule(int cpu)
 {
-	smp_ext_bitcall(cpu, ec_schedule);
+	pcpu_ec_call(pcpu_devices + cpu, ec_schedule);
 }
 
 /*
  * parameter area for the set/clear control bit callbacks
  */
 struct ec_creg_mask_parms {
-	unsigned long orvals[16];
-	unsigned long andvals[16];
+	unsigned long orval;
+	unsigned long andval;
+	int cr;
 };
 
 /*
@@ -313,11 +525,9 @@
 {
 	struct ec_creg_mask_parms *pp = info;
 	unsigned long cregs[16];
-	int i;
 
 	__ctl_store(cregs, 0, 15);
-	for (i = 0; i <= 15; i++)
-		cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i];
+	cregs[pp->cr] = (cregs[pp->cr] & pp->andval) | pp->orval;
 	__ctl_load(cregs, 0, 15);
 }
 
@@ -326,11 +536,8 @@
  */
 void smp_ctl_set_bit(int cr, int bit)
 {
-	struct ec_creg_mask_parms parms;
+	struct ec_creg_mask_parms parms = { 1UL << bit, -1UL, cr };
 
-	memset(&parms.orvals, 0, sizeof(parms.orvals));
-	memset(&parms.andvals, 0xff, sizeof(parms.andvals));
-	parms.orvals[cr] = 1UL << bit;
 	on_each_cpu(smp_ctl_bit_callback, &parms, 1);
 }
 EXPORT_SYMBOL(smp_ctl_set_bit);
@@ -340,220 +547,178 @@
  */
 void smp_ctl_clear_bit(int cr, int bit)
 {
-	struct ec_creg_mask_parms parms;
+	struct ec_creg_mask_parms parms = { 0, ~(1UL << bit), cr };
 
-	memset(&parms.orvals, 0, sizeof(parms.orvals));
-	memset(&parms.andvals, 0xff, sizeof(parms.andvals));
-	parms.andvals[cr] = ~(1UL << bit);
 	on_each_cpu(smp_ctl_bit_callback, &parms, 1);
 }
 EXPORT_SYMBOL(smp_ctl_clear_bit);
 
 #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_CRASH_DUMP)
 
-static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu)
-{
-	if (ipl_info.type != IPL_TYPE_FCP_DUMP && !OLDMEM_BASE)
-		return;
-	if (is_kdump_kernel())
-		return;
-	if (cpu >= NR_CPUS) {
-		pr_warning("CPU %i exceeds the maximum %i and is excluded from "
-			   "the dump\n", cpu, NR_CPUS - 1);
-		return;
-	}
-	zfcpdump_save_areas[cpu] = kmalloc(sizeof(struct save_area), GFP_KERNEL);
-	while (raw_sigp(phy_cpu, sigp_stop_and_store_status) == sigp_busy)
-		cpu_relax();
-	memcpy_real(zfcpdump_save_areas[cpu],
-		    (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE,
-		    sizeof(struct save_area));
-}
-
 struct save_area *zfcpdump_save_areas[NR_CPUS + 1];
 EXPORT_SYMBOL_GPL(zfcpdump_save_areas);
 
-#else
-
-static inline void smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) { }
-
-#endif /* CONFIG_ZFCPDUMP */
-
-static int cpu_known(int cpu_id)
+static void __init smp_get_save_area(int cpu, u16 address)
 {
-	int cpu;
+	void *lc = pcpu_devices[0].lowcore;
+	struct save_area *save_area;
 
-	for_each_present_cpu(cpu) {
-		if (__cpu_logical_map[cpu] == cpu_id)
-			return 1;
+	if (is_kdump_kernel())
+		return;
+	if (!OLDMEM_BASE && (address == boot_cpu_address ||
+			     ipl_info.type != IPL_TYPE_FCP_DUMP))
+		return;
+	if (cpu >= NR_CPUS) {
+		pr_warning("CPU %i exceeds the maximum %i and is excluded "
+			   "from the dump\n", cpu, NR_CPUS - 1);
+		return;
 	}
+	save_area = kmalloc(sizeof(struct save_area), GFP_KERNEL);
+	if (!save_area)
+		panic("could not allocate memory for save area\n");
+	zfcpdump_save_areas[cpu] = save_area;
+#ifdef CONFIG_CRASH_DUMP
+	if (address == boot_cpu_address) {
+		/* Copy the registers of the boot cpu. */
+		copy_oldmem_page(1, (void *) save_area, sizeof(*save_area),
+				 SAVE_AREA_BASE - PAGE_SIZE, 0);
+		return;
+	}
+#endif
+	/* Get the registers of a non-boot cpu. */
+	__pcpu_sigp_relax(address, sigp_stop_and_store_status, 0, NULL);
+	memcpy_real(save_area, lc + SAVE_AREA_BASE, sizeof(*save_area));
+}
+
+int smp_store_status(int cpu)
+{
+	struct pcpu *pcpu;
+
+	pcpu = pcpu_devices + cpu;
+	if (__pcpu_sigp_relax(pcpu->address, sigp_stop_and_store_status,
+			      0, NULL) != sigp_order_code_accepted)
+		return -EIO;
 	return 0;
 }
 
-static int smp_rescan_cpus_sigp(cpumask_t avail)
-{
-	int cpu_id, logical_cpu;
+#else /* CONFIG_ZFCPDUMP || CONFIG_CRASH_DUMP */
 
-	logical_cpu = cpumask_first(&avail);
-	if (logical_cpu >= nr_cpu_ids)
-		return 0;
-	for (cpu_id = 0; cpu_id <= MAX_CPU_ADDRESS; cpu_id++) {
-		if (cpu_known(cpu_id))
-			continue;
-		__cpu_logical_map[logical_cpu] = cpu_id;
-		cpu_set_polarization(logical_cpu, POLARIZATION_UNKNOWN);
-		if (!cpu_stopped(logical_cpu))
-			continue;
-		set_cpu_present(logical_cpu, true);
-		smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
-		logical_cpu = cpumask_next(logical_cpu, &avail);
-		if (logical_cpu >= nr_cpu_ids)
-			break;
-	}
-	return 0;
-}
+static inline void smp_get_save_area(int cpu, u16 address) { }
 
-static int smp_rescan_cpus_sclp(cpumask_t avail)
+#endif /* CONFIG_ZFCPDUMP || CONFIG_CRASH_DUMP */
+
+static struct sclp_cpu_info *smp_get_cpu_info(void)
 {
+	static int use_sigp_detection;
 	struct sclp_cpu_info *info;
-	int cpu_id, logical_cpu, cpu;
-	int rc;
+	int address;
 
-	logical_cpu = cpumask_first(&avail);
-	if (logical_cpu >= nr_cpu_ids)
-		return 0;
-	info = kmalloc(sizeof(*info), GFP_KERNEL);
-	if (!info)
-		return -ENOMEM;
-	rc = sclp_get_cpu_info(info);
-	if (rc)
-		goto out;
-	for (cpu = 0; cpu < info->combined; cpu++) {
-		if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type)
-			continue;
-		cpu_id = info->cpu[cpu].address;
-		if (cpu_known(cpu_id))
-			continue;
-		__cpu_logical_map[logical_cpu] = cpu_id;
-		cpu_set_polarization(logical_cpu, POLARIZATION_UNKNOWN);
-		set_cpu_present(logical_cpu, true);
-		if (cpu >= info->configured)
-			smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY;
-		else
-			smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
-		logical_cpu = cpumask_next(logical_cpu, &avail);
-		if (logical_cpu >= nr_cpu_ids)
-			break;
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (info && (use_sigp_detection || sclp_get_cpu_info(info))) {
+		use_sigp_detection = 1;
+		for (address = 0; address <= MAX_CPU_ADDRESS; address++) {
+			if (__pcpu_sigp_relax(address, sigp_sense, 0, NULL) ==
+			    sigp_not_operational)
+				continue;
+			info->cpu[info->configured].address = address;
+			info->configured++;
+		}
+		info->combined = info->configured;
 	}
-out:
-	kfree(info);
-	return rc;
+	return info;
 }
 
-static int __smp_rescan_cpus(void)
-{
-	cpumask_t avail;
+static int __devinit smp_add_present_cpu(int cpu);
 
+static int __devinit __smp_rescan_cpus(struct sclp_cpu_info *info,
+				       int sysfs_add)
+{
+	struct pcpu *pcpu;
+	cpumask_t avail;
+	int cpu, nr, i;
+
+	nr = 0;
 	cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask);
-	if (smp_use_sigp_detection)
-		return smp_rescan_cpus_sigp(avail);
-	else
-		return smp_rescan_cpus_sclp(avail);
+	cpu = cpumask_first(&avail);
+	for (i = 0; (i < info->combined) && (cpu < nr_cpu_ids); i++) {
+		if (info->has_cpu_type && info->cpu[i].type != boot_cpu_type)
+			continue;
+		if (pcpu_find_address(cpu_present_mask, info->cpu[i].address))
+			continue;
+		pcpu = pcpu_devices + cpu;
+		pcpu->address = info->cpu[i].address;
+		pcpu->state = (cpu >= info->configured) ?
+			CPU_STATE_STANDBY : CPU_STATE_CONFIGURED;
+		cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
+		set_cpu_present(cpu, true);
+		if (sysfs_add && smp_add_present_cpu(cpu) != 0)
+			set_cpu_present(cpu, false);
+		else
+			nr++;
+		cpu = cpumask_next(cpu, &avail);
+	}
+	return nr;
 }
 
 static void __init smp_detect_cpus(void)
 {
 	unsigned int cpu, c_cpus, s_cpus;
 	struct sclp_cpu_info *info;
-	u16 boot_cpu_addr, cpu_addr;
 
-	c_cpus = 1;
-	s_cpus = 0;
-	boot_cpu_addr = __cpu_logical_map[0];
-	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	info = smp_get_cpu_info();
 	if (!info)
 		panic("smp_detect_cpus failed to allocate memory\n");
-#ifdef CONFIG_CRASH_DUMP
-	if (OLDMEM_BASE && !is_kdump_kernel()) {
-		struct save_area *save_area;
-
-		save_area = kmalloc(sizeof(*save_area), GFP_KERNEL);
-		if (!save_area)
-			panic("could not allocate memory for save area\n");
-		copy_oldmem_page(1, (void *) save_area, sizeof(*save_area),
-				 0x200, 0);
-		zfcpdump_save_areas[0] = save_area;
-	}
-#endif
-	/* Use sigp detection algorithm if sclp doesn't work. */
-	if (sclp_get_cpu_info(info)) {
-		smp_use_sigp_detection = 1;
-		for (cpu = 0; cpu <= MAX_CPU_ADDRESS; cpu++) {
-			if (cpu == boot_cpu_addr)
-				continue;
-			if (!raw_cpu_stopped(cpu))
-				continue;
-			smp_get_save_area(c_cpus, cpu);
-			c_cpus++;
-		}
-		goto out;
-	}
-
 	if (info->has_cpu_type) {
 		for (cpu = 0; cpu < info->combined; cpu++) {
-			if (info->cpu[cpu].address == boot_cpu_addr) {
-				smp_cpu_type = info->cpu[cpu].type;
-				break;
-			}
+			if (info->cpu[cpu].address != boot_cpu_address)
+				continue;
+			/* The boot cpu dictates the cpu type. */
+			boot_cpu_type = info->cpu[cpu].type;
+			break;
 		}
 	}
-
+	c_cpus = s_cpus = 0;
 	for (cpu = 0; cpu < info->combined; cpu++) {
-		if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type)
+		if (info->has_cpu_type && info->cpu[cpu].type != boot_cpu_type)
 			continue;
-		cpu_addr = info->cpu[cpu].address;
-		if (cpu_addr == boot_cpu_addr)
-			continue;
-		if (!raw_cpu_stopped(cpu_addr)) {
+		if (cpu < info->configured) {
+			smp_get_save_area(c_cpus, info->cpu[cpu].address);
+			c_cpus++;
+		} else
 			s_cpus++;
-			continue;
-		}
-		smp_get_save_area(c_cpus, cpu_addr);
-		c_cpus++;
 	}
-out:
-	kfree(info);
 	pr_info("%d configured CPUs, %d standby CPUs\n", c_cpus, s_cpus);
 	get_online_cpus();
-	__smp_rescan_cpus();
+	__smp_rescan_cpus(info, 0);
 	put_online_cpus();
+	kfree(info);
 }
 
 /*
  *	Activate a secondary processor.
  */
-int __cpuinit start_secondary(void *cpuvoid)
+static void __cpuinit smp_start_secondary(void *cpuvoid)
 {
+	S390_lowcore.last_update_clock = get_clock();
+	S390_lowcore.restart_stack = (unsigned long) restart_stack;
+	S390_lowcore.restart_fn = (unsigned long) do_restart;
+	S390_lowcore.restart_data = 0;
+	S390_lowcore.restart_source = -1UL;
+	restore_access_regs(S390_lowcore.access_regs_save_area);
+	__ctl_load(S390_lowcore.cregs_save_area, 0, 15);
+	__load_psw_mask(psw_kernel_bits | PSW_MASK_DAT);
 	cpu_init();
 	preempt_disable();
 	init_cpu_timer();
 	init_cpu_vtimer();
 	pfault_init();
-
 	notify_cpu_starting(smp_processor_id());
 	ipi_call_lock();
 	set_cpu_online(smp_processor_id(), true);
 	ipi_call_unlock();
-	__ctl_clear_bit(0, 28); /* Disable lowcore protection */
-	S390_lowcore.restart_psw.mask =
-		PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA | PSW_MASK_BA;
-	S390_lowcore.restart_psw.addr =
-		PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler;
-	__ctl_set_bit(0, 28); /* Enable lowcore protection */
 	local_irq_enable();
 	/* cpu_idle will call schedule for us */
 	cpu_idle();
-	return 0;
 }
 
 struct create_idle {
@@ -572,82 +737,20 @@
 	complete(&c_idle->done);
 }
 
-static int __cpuinit smp_alloc_lowcore(int cpu)
-{
-	unsigned long async_stack, panic_stack;
-	struct _lowcore *lowcore;
-
-	lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER);
-	if (!lowcore)
-		return -ENOMEM;
-	async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
-	panic_stack = __get_free_page(GFP_KERNEL);
-	if (!panic_stack || !async_stack)
-		goto out;
-	memcpy(lowcore, &S390_lowcore, 512);
-	memset((char *)lowcore + 512, 0, sizeof(*lowcore) - 512);
-	lowcore->async_stack = async_stack + ASYNC_SIZE;
-	lowcore->panic_stack = panic_stack + PAGE_SIZE;
-	lowcore->restart_psw.mask =
-		PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA | PSW_MASK_BA;
-	lowcore->restart_psw.addr =
-		PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
-	if (user_mode != HOME_SPACE_MODE)
-		lowcore->restart_psw.mask |= PSW_ASC_HOME;
-#ifndef CONFIG_64BIT
-	if (MACHINE_HAS_IEEE) {
-		unsigned long save_area;
-
-		save_area = get_zeroed_page(GFP_KERNEL);
-		if (!save_area)
-			goto out;
-		lowcore->extended_save_area_addr = (u32) save_area;
-	}
-#else
-	if (vdso_alloc_per_cpu(cpu, lowcore))
-		goto out;
-#endif
-	lowcore_ptr[cpu] = lowcore;
-	return 0;
-
-out:
-	free_page(panic_stack);
-	free_pages(async_stack, ASYNC_ORDER);
-	free_pages((unsigned long) lowcore, LC_ORDER);
-	return -ENOMEM;
-}
-
-static void smp_free_lowcore(int cpu)
-{
-	struct _lowcore *lowcore;
-
-	lowcore = lowcore_ptr[cpu];
-#ifndef CONFIG_64BIT
-	if (MACHINE_HAS_IEEE)
-		free_page((unsigned long) lowcore->extended_save_area_addr);
-#else
-	vdso_free_per_cpu(cpu, lowcore);
-#endif
-	free_page(lowcore->panic_stack - PAGE_SIZE);
-	free_pages(lowcore->async_stack - ASYNC_SIZE, ASYNC_ORDER);
-	free_pages((unsigned long) lowcore, LC_ORDER);
-	lowcore_ptr[cpu] = NULL;
-}
-
 /* Upping and downing of CPUs */
 int __cpuinit __cpu_up(unsigned int cpu)
 {
-	struct _lowcore *cpu_lowcore;
 	struct create_idle c_idle;
-	struct task_struct *idle;
-	struct stack_frame *sf;
-	u32 lowcore;
-	int ccode;
+	struct pcpu *pcpu;
+	int rc;
 
-	if (smp_cpu_state[cpu] != CPU_STATE_CONFIGURED)
+	pcpu = pcpu_devices + cpu;
+	if (pcpu->state != CPU_STATE_CONFIGURED)
 		return -EIO;
-	idle = current_set[cpu];
-	if (!idle) {
+	if (pcpu_sigp_retry(pcpu, sigp_initial_cpu_reset, 0) !=
+	    sigp_order_code_accepted)
+		return -EIO;
+	if (!pcpu->idle) {
 		c_idle.done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done);
 		INIT_WORK_ONSTACK(&c_idle.work, smp_fork_idle);
 		c_idle.cpu = cpu;
@@ -655,68 +758,28 @@
 		wait_for_completion(&c_idle.done);
 		if (IS_ERR(c_idle.idle))
 			return PTR_ERR(c_idle.idle);
-		idle = c_idle.idle;
-		current_set[cpu] = c_idle.idle;
+		pcpu->idle = c_idle.idle;
 	}
-	init_idle(idle, cpu);
-	if (smp_alloc_lowcore(cpu))
-		return -ENOMEM;
-	do {
-		ccode = sigp(cpu, sigp_initial_cpu_reset);
-		if (ccode == sigp_busy)
-			udelay(10);
-		if (ccode == sigp_not_operational)
-			goto err_out;
-	} while (ccode == sigp_busy);
-
-	lowcore = (u32)(unsigned long)lowcore_ptr[cpu];
-	while (sigp_p(lowcore, cpu, sigp_set_prefix) == sigp_busy)
-		udelay(10);
-
-	cpu_lowcore = lowcore_ptr[cpu];
-	cpu_lowcore->kernel_stack = (unsigned long)
-		task_stack_page(idle) + THREAD_SIZE;
-	cpu_lowcore->thread_info = (unsigned long) task_thread_info(idle);
-	sf = (struct stack_frame *) (cpu_lowcore->kernel_stack
-				     - sizeof(struct pt_regs)
-				     - sizeof(struct stack_frame));
-	memset(sf, 0, sizeof(struct stack_frame));
-	sf->gprs[9] = (unsigned long) sf;
-	cpu_lowcore->gpregs_save_area[15] = (unsigned long) sf;
-	__ctl_store(cpu_lowcore->cregs_save_area, 0, 15);
-	atomic_inc(&init_mm.context.attach_count);
-	asm volatile(
-		"	stam	0,15,0(%0)"
-		: : "a" (&cpu_lowcore->access_regs_save_area) : "memory");
-	cpu_lowcore->percpu_offset = __per_cpu_offset[cpu];
-	cpu_lowcore->current_task = (unsigned long) idle;
-	cpu_lowcore->cpu_nr = cpu;
-	cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce;
-	cpu_lowcore->machine_flags = S390_lowcore.machine_flags;
-	cpu_lowcore->ftrace_func = S390_lowcore.ftrace_func;
-	memcpy(cpu_lowcore->stfle_fac_list, S390_lowcore.stfle_fac_list,
-	       MAX_FACILITY_BIT/8);
-	eieio();
-
-	while (sigp(cpu, sigp_restart) == sigp_busy)
-		udelay(10);
-
+	init_idle(pcpu->idle, cpu);
+	rc = pcpu_alloc_lowcore(pcpu, cpu);
+	if (rc)
+		return rc;
+	pcpu_prepare_secondary(pcpu, cpu);
+	pcpu_attach_task(pcpu, pcpu->idle);
+	pcpu_start_fn(pcpu, smp_start_secondary, NULL);
 	while (!cpu_online(cpu))
 		cpu_relax();
 	return 0;
-
-err_out:
-	smp_free_lowcore(cpu);
-	return -EIO;
 }
 
 static int __init setup_possible_cpus(char *s)
 {
-	int pcpus, cpu;
+	int max, cpu;
 
-	pcpus = simple_strtoul(s, NULL, 0);
+	if (kstrtoint(s, 0, &max) < 0)
+		return 0;
 	init_cpu_possible(cpumask_of(0));
-	for (cpu = 1; cpu < pcpus && cpu < nr_cpu_ids; cpu++)
+	for (cpu = 1; cpu < max && cpu < nr_cpu_ids; cpu++)
 		set_cpu_possible(cpu, true);
 	return 0;
 }
@@ -726,113 +789,79 @@
 
 int __cpu_disable(void)
 {
-	struct ec_creg_mask_parms cr_parms;
-	int cpu = smp_processor_id();
+	unsigned long cregs[16];
 
-	set_cpu_online(cpu, false);
-
-	/* Disable pfault pseudo page faults on this cpu. */
+	set_cpu_online(smp_processor_id(), false);
+	/* Disable pseudo page faults on this cpu. */
 	pfault_fini();
-
-	memset(&cr_parms.orvals, 0, sizeof(cr_parms.orvals));
-	memset(&cr_parms.andvals, 0xff, sizeof(cr_parms.andvals));
-
-	/* disable all external interrupts */
-	cr_parms.orvals[0] = 0;
-	cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 11 |
-				1 << 10 | 1 <<	9 | 1 <<  6 | 1 <<  5 |
-				1 <<  4);
-	/* disable all I/O interrupts */
-	cr_parms.orvals[6] = 0;
-	cr_parms.andvals[6] = ~(1 << 31 | 1 << 30 | 1 << 29 | 1 << 28 |
-				1 << 27 | 1 << 26 | 1 << 25 | 1 << 24);
-	/* disable most machine checks */
-	cr_parms.orvals[14] = 0;
-	cr_parms.andvals[14] = ~(1 << 28 | 1 << 27 | 1 << 26 |
-				 1 << 25 | 1 << 24);
-
-	smp_ctl_bit_callback(&cr_parms);
-
+	/* Disable interrupt sources via control register. */
+	__ctl_store(cregs, 0, 15);
+	cregs[0]  &= ~0x0000ee70UL;	/* disable all external interrupts */
+	cregs[6]  &= ~0xff000000UL;	/* disable all I/O interrupts */
+	cregs[14] &= ~0x1f000000UL;	/* disable most machine checks */
+	__ctl_load(cregs, 0, 15);
 	return 0;
 }
 
 void __cpu_die(unsigned int cpu)
 {
+	struct pcpu *pcpu;
+
 	/* Wait until target cpu is down */
-	while (!cpu_stopped(cpu))
+	pcpu = pcpu_devices + cpu;
+	while (!pcpu_stopped(pcpu))
 		cpu_relax();
-	while (sigp_p(0, cpu, sigp_set_prefix) == sigp_busy)
-		udelay(10);
-	smp_free_lowcore(cpu);
+	pcpu_free_lowcore(pcpu);
 	atomic_dec(&init_mm.context.attach_count);
 }
 
 void __noreturn cpu_die(void)
 {
 	idle_task_exit();
-	while (sigp(smp_processor_id(), sigp_stop) == sigp_busy)
-		cpu_relax();
-	for (;;);
+	pcpu_sigp_retry(pcpu_devices + smp_processor_id(), sigp_stop, 0);
+	for (;;) ;
 }
 
 #endif /* CONFIG_HOTPLUG_CPU */
 
+static void smp_call_os_info_init_fn(void)
+{
+	int (*init_fn)(void);
+	unsigned long size;
+
+	init_fn = os_info_old_entry(OS_INFO_INIT_FN, &size);
+	if (!init_fn)
+		return;
+	init_fn();
+}
+
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
-#ifndef CONFIG_64BIT
-	unsigned long save_area = 0;
-#endif
-	unsigned long async_stack, panic_stack;
-	struct _lowcore *lowcore;
-
-	smp_detect_cpus();
-
 	/* request the 0x1201 emergency signal external interrupt */
 	if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0)
 		panic("Couldn't request external interrupt 0x1201");
 	/* request the 0x1202 external call external interrupt */
 	if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0)
 		panic("Couldn't request external interrupt 0x1202");
-
-	/* Reallocate current lowcore, but keep its contents. */
-	lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER);
-	panic_stack = __get_free_page(GFP_KERNEL);
-	async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
-	BUG_ON(!lowcore || !panic_stack || !async_stack);
-#ifndef CONFIG_64BIT
-	if (MACHINE_HAS_IEEE)
-		save_area = get_zeroed_page(GFP_KERNEL);
-#endif
-	local_irq_disable();
-	local_mcck_disable();
-	lowcore_ptr[smp_processor_id()] = lowcore;
-	*lowcore = S390_lowcore;
-	lowcore->panic_stack = panic_stack + PAGE_SIZE;
-	lowcore->async_stack = async_stack + ASYNC_SIZE;
-#ifndef CONFIG_64BIT
-	if (MACHINE_HAS_IEEE)
-		lowcore->extended_save_area_addr = (u32) save_area;
-#endif
-	set_prefix((u32)(unsigned long) lowcore);
-	local_mcck_enable();
-	local_irq_enable();
-#ifdef CONFIG_64BIT
-	if (vdso_alloc_per_cpu(smp_processor_id(), &S390_lowcore))
-		BUG();
-#endif
+	smp_call_os_info_init_fn();
+	smp_detect_cpus();
 }
 
 void __init smp_prepare_boot_cpu(void)
 {
-	BUG_ON(smp_processor_id() != 0);
+	struct pcpu *pcpu = pcpu_devices;
 
-	current_thread_info()->cpu = 0;
+	boot_cpu_address = stap();
+	pcpu->idle = current;
+	pcpu->state = CPU_STATE_CONFIGURED;
+	pcpu->address = boot_cpu_address;
+	pcpu->lowcore = (struct _lowcore *)(unsigned long) store_prefix();
+	pcpu->async_stack = S390_lowcore.async_stack - ASYNC_SIZE;
+	pcpu->panic_stack = S390_lowcore.panic_stack - PAGE_SIZE;
+	S390_lowcore.percpu_offset = __per_cpu_offset[0];
+	cpu_set_polarization(0, POLARIZATION_UNKNOWN);
 	set_cpu_present(0, true);
 	set_cpu_online(0, true);
-	S390_lowcore.percpu_offset = __per_cpu_offset[0];
-	current_set[0] = current;
-	smp_cpu_state[0] = CPU_STATE_CONFIGURED;
-	cpu_set_polarization(0, POLARIZATION_UNKNOWN);
 }
 
 void __init smp_cpus_done(unsigned int max_cpus)
@@ -842,7 +871,6 @@
 void __init smp_setup_processor_id(void)
 {
 	S390_lowcore.cpu_nr = 0;
-	__cpu_logical_map[0] = stap();
 }
 
 /*
@@ -858,56 +886,57 @@
 
 #ifdef CONFIG_HOTPLUG_CPU
 static ssize_t cpu_configure_show(struct device *dev,
-				struct device_attribute *attr, char *buf)
+				  struct device_attribute *attr, char *buf)
 {
 	ssize_t count;
 
 	mutex_lock(&smp_cpu_state_mutex);
-	count = sprintf(buf, "%d\n", smp_cpu_state[dev->id]);
+	count = sprintf(buf, "%d\n", pcpu_devices[dev->id].state);
 	mutex_unlock(&smp_cpu_state_mutex);
 	return count;
 }
 
 static ssize_t cpu_configure_store(struct device *dev,
-				  struct device_attribute *attr,
-				  const char *buf, size_t count)
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
 {
-	int cpu = dev->id;
-	int val, rc;
+	struct pcpu *pcpu;
+	int cpu, val, rc;
 	char delim;
 
 	if (sscanf(buf, "%d %c", &val, &delim) != 1)
 		return -EINVAL;
 	if (val != 0 && val != 1)
 		return -EINVAL;
-
 	get_online_cpus();
 	mutex_lock(&smp_cpu_state_mutex);
 	rc = -EBUSY;
 	/* disallow configuration changes of online cpus and cpu 0 */
+	cpu = dev->id;
 	if (cpu_online(cpu) || cpu == 0)
 		goto out;
+	pcpu = pcpu_devices + cpu;
 	rc = 0;
 	switch (val) {
 	case 0:
-		if (smp_cpu_state[cpu] == CPU_STATE_CONFIGURED) {
-			rc = sclp_cpu_deconfigure(__cpu_logical_map[cpu]);
-			if (!rc) {
-				smp_cpu_state[cpu] = CPU_STATE_STANDBY;
-				cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
-				topology_expect_change();
-			}
-		}
+		if (pcpu->state != CPU_STATE_CONFIGURED)
+			break;
+		rc = sclp_cpu_deconfigure(pcpu->address);
+		if (rc)
+			break;
+		pcpu->state = CPU_STATE_STANDBY;
+		cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
+		topology_expect_change();
 		break;
 	case 1:
-		if (smp_cpu_state[cpu] == CPU_STATE_STANDBY) {
-			rc = sclp_cpu_configure(__cpu_logical_map[cpu]);
-			if (!rc) {
-				smp_cpu_state[cpu] = CPU_STATE_CONFIGURED;
-				cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
-				topology_expect_change();
-			}
-		}
+		if (pcpu->state != CPU_STATE_STANDBY)
+			break;
+		rc = sclp_cpu_configure(pcpu->address);
+		if (rc)
+			break;
+		pcpu->state = CPU_STATE_CONFIGURED;
+		cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
+		topology_expect_change();
 		break;
 	default:
 		break;
@@ -923,7 +952,7 @@
 static ssize_t show_cpu_address(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	return sprintf(buf, "%d\n", __cpu_logical_map[dev->id]);
+	return sprintf(buf, "%d\n", pcpu_devices[dev->id].address);
 }
 static DEVICE_ATTR(address, 0444, show_cpu_address, NULL);
 
@@ -955,22 +984,16 @@
 static ssize_t show_idle_count(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	struct s390_idle_data *idle;
+	struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
 	unsigned long long idle_count;
 	unsigned int sequence;
 
-	idle = &per_cpu(s390_idle, dev->id);
-repeat:
-	sequence = idle->sequence;
-	smp_rmb();
-	if (sequence & 1)
-		goto repeat;
-	idle_count = idle->idle_count;
-	if (idle->idle_enter)
-		idle_count++;
-	smp_rmb();
-	if (idle->sequence != sequence)
-		goto repeat;
+	do {
+		sequence = ACCESS_ONCE(idle->sequence);
+		idle_count = ACCESS_ONCE(idle->idle_count);
+		if (ACCESS_ONCE(idle->idle_enter))
+			idle_count++;
+	} while ((sequence & 1) || (idle->sequence != sequence));
 	return sprintf(buf, "%llu\n", idle_count);
 }
 static DEVICE_ATTR(idle_count, 0444, show_idle_count, NULL);
@@ -978,24 +1001,18 @@
 static ssize_t show_idle_time(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	struct s390_idle_data *idle;
-	unsigned long long now, idle_time, idle_enter;
+	struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
+	unsigned long long now, idle_time, idle_enter, idle_exit;
 	unsigned int sequence;
 
-	idle = &per_cpu(s390_idle, dev->id);
-	now = get_clock();
-repeat:
-	sequence = idle->sequence;
-	smp_rmb();
-	if (sequence & 1)
-		goto repeat;
-	idle_time = idle->idle_time;
-	idle_enter = idle->idle_enter;
-	if (idle_enter != 0ULL && idle_enter < now)
-		idle_time += now - idle_enter;
-	smp_rmb();
-	if (idle->sequence != sequence)
-		goto repeat;
+	do {
+		now = get_clock();
+		sequence = ACCESS_ONCE(idle->sequence);
+		idle_time = ACCESS_ONCE(idle->idle_time);
+		idle_enter = ACCESS_ONCE(idle->idle_enter);
+		idle_exit = ACCESS_ONCE(idle->idle_exit);
+	} while ((sequence & 1) || (idle->sequence != sequence));
+	idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0;
 	return sprintf(buf, "%llu\n", idle_time >> 12);
 }
 static DEVICE_ATTR(idle_time_us, 0444, show_idle_time, NULL);
@@ -1015,7 +1032,7 @@
 				    unsigned long action, void *hcpu)
 {
 	unsigned int cpu = (unsigned int)(long)hcpu;
-	struct cpu *c = &per_cpu(cpu_devices, cpu);
+	struct cpu *c = &pcpu_devices[cpu].cpu;
 	struct device *s = &c->dev;
 	struct s390_idle_data *idle;
 	int err = 0;
@@ -1041,7 +1058,7 @@
 
 static int __devinit smp_add_present_cpu(int cpu)
 {
-	struct cpu *c = &per_cpu(cpu_devices, cpu);
+	struct cpu *c = &pcpu_devices[cpu].cpu;
 	struct device *s = &c->dev;
 	int rc;
 
@@ -1079,29 +1096,21 @@
 
 int __ref smp_rescan_cpus(void)
 {
-	cpumask_t newcpus;
-	int cpu;
-	int rc;
+	struct sclp_cpu_info *info;
+	int nr;
 
+	info = smp_get_cpu_info();
+	if (!info)
+		return -ENOMEM;
 	get_online_cpus();
 	mutex_lock(&smp_cpu_state_mutex);
-	cpumask_copy(&newcpus, cpu_present_mask);
-	rc = __smp_rescan_cpus();
-	if (rc)
-		goto out;
-	cpumask_andnot(&newcpus, cpu_present_mask, &newcpus);
-	for_each_cpu(cpu, &newcpus) {
-		rc = smp_add_present_cpu(cpu);
-		if (rc)
-			set_cpu_present(cpu, false);
-	}
-	rc = 0;
-out:
+	nr = __smp_rescan_cpus(info, 1);
 	mutex_unlock(&smp_cpu_state_mutex);
 	put_online_cpus();
-	if (!cpumask_empty(&newcpus))
+	kfree(info);
+	if (nr)
 		topology_schedule_update();
-	return rc;
+	return 0;
 }
 
 static ssize_t __ref rescan_store(struct device *dev,
diff --git a/arch/s390/kernel/suspend.c b/arch/s390/kernel/suspend.c
index 47df775..aa1494d 100644
--- a/arch/s390/kernel/suspend.c
+++ b/arch/s390/kernel/suspend.c
@@ -9,7 +9,7 @@
 #include <linux/pfn.h>
 #include <linux/suspend.h>
 #include <linux/mm.h>
-#include <asm/system.h>
+#include <asm/ctl_reg.h>
 
 /*
  * References to section boundaries
diff --git a/arch/s390/kernel/switch_cpu.S b/arch/s390/kernel/switch_cpu.S
deleted file mode 100644
index bfe070b..0000000
--- a/arch/s390/kernel/switch_cpu.S
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 31-bit switch cpu code
- *
- * Copyright IBM Corp. 2009
- *
- */
-
-#include <linux/linkage.h>
-#include <asm/asm-offsets.h>
-#include <asm/ptrace.h>
-
-# smp_switch_to_cpu switches to destination cpu and executes the passed function
-# Parameter: %r2 - function to call
-#	     %r3 - function parameter
-#	     %r4 - stack poiner
-#	     %r5 - current cpu
-#	     %r6 - destination cpu
-
-	.section .text
-ENTRY(smp_switch_to_cpu)
-	stm	%r6,%r15,__SF_GPRS(%r15)
-	lr	%r1,%r15
-	ahi	%r15,-STACK_FRAME_OVERHEAD
-	st	%r1,__SF_BACKCHAIN(%r15)
-	basr	%r13,0
-0:	la	%r1,.gprregs_addr-0b(%r13)
-	l	%r1,0(%r1)
-	stm	%r0,%r15,0(%r1)
-1:	sigp	%r0,%r6,__SIGP_RESTART	/* start destination CPU */
-	brc	2,1b			/* busy, try again */
-2:	sigp	%r0,%r5,__SIGP_STOP	/* stop current CPU */
-	brc	2,2b			/* busy, try again */
-3:	j	3b
-
-ENTRY(smp_restart_cpu)
-	basr	%r13,0
-0:	la	%r1,.gprregs_addr-0b(%r13)
-	l	%r1,0(%r1)
-	lm	%r0,%r15,0(%r1)
-1:	sigp	%r0,%r5,__SIGP_SENSE	/* Wait for calling CPU */
-	brc	10,1b			/* busy, accepted (status 0), running */
-	tmll	%r0,0x40		/* Test if calling CPU is stopped */
-	jz	1b
-	ltr	%r4,%r4			/* New stack ? */
-	jz	1f
-	lr	%r15,%r4
-1:	lr	%r14,%r2		/* r14: Function to call */
-	lr	%r2,%r3			/* r2 : Parameter for function*/
-	basr	%r14,%r14		/* Call function */
-
-.gprregs_addr:
-	.long	.gprregs
-
-	.section .data,"aw",@progbits
-.gprregs:
-	.rept	16
-	.long	0
-	.endr
diff --git a/arch/s390/kernel/switch_cpu64.S b/arch/s390/kernel/switch_cpu64.S
deleted file mode 100644
index fcc42d7..0000000
--- a/arch/s390/kernel/switch_cpu64.S
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 64-bit switch cpu code
- *
- * Copyright IBM Corp. 2009
- *
- */
-
-#include <linux/linkage.h>
-#include <asm/asm-offsets.h>
-#include <asm/ptrace.h>
-
-# smp_switch_to_cpu switches to destination cpu and executes the passed function
-# Parameter: %r2 - function to call
-#	     %r3 - function parameter
-#	     %r4 - stack poiner
-#	     %r5 - current cpu
-#	     %r6 - destination cpu
-
-	.section .text
-ENTRY(smp_switch_to_cpu)
-	stmg	%r6,%r15,__SF_GPRS(%r15)
-	lgr	%r1,%r15
-	aghi	%r15,-STACK_FRAME_OVERHEAD
-	stg	%r1,__SF_BACKCHAIN(%r15)
-	larl	%r1,.gprregs
-	stmg	%r0,%r15,0(%r1)
-1:	sigp	%r0,%r6,__SIGP_RESTART	/* start destination CPU */
-	brc	2,1b			/* busy, try again */
-2:	sigp	%r0,%r5,__SIGP_STOP	/* stop current CPU */
-	brc	2,2b			/* busy, try again */
-3:	j	3b
-
-ENTRY(smp_restart_cpu)
-	larl	%r1,.gprregs
-	lmg	%r0,%r15,0(%r1)
-1:	sigp	%r0,%r5,__SIGP_SENSE	/* Wait for calling CPU */
-	brc	10,1b			/* busy, accepted (status 0), running */
-	tmll	%r0,0x40		/* Test if calling CPU is stopped */
-	jz	1b
-	ltgr	%r4,%r4			/* New stack ? */
-	jz	1f
-	lgr	%r15,%r4
-1:	lgr	%r14,%r2		/* r14: Function to call */
-	lgr	%r2,%r3			/* r2 : Parameter for function*/
-	basr	%r14,%r14		/* Call function */
-
-	.section .data,"aw",@progbits
-.gprregs:
-	.rept	16
-	.quad	0
-	.endr
diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S
index acb78cd..dd70ef0 100644
--- a/arch/s390/kernel/swsusp_asm64.S
+++ b/arch/s390/kernel/swsusp_asm64.S
@@ -42,7 +42,7 @@
 	lghi	%r1,0x1000
 
 	/* Save CPU address */
-	stap	__LC_CPU_ADDRESS(%r0)
+	stap	__LC_EXT_CPU_ADDR(%r0)
 
 	/* Store registers */
 	mvc	0x318(4,%r1),__SF_EMPTY(%r15)	/* move prefix to lowcore */
@@ -173,15 +173,15 @@
 	larl	%r1,.Lresume_cpu		/* Resume CPU address: r2 */
 	stap	0(%r1)
 	llgh	%r2,0(%r1)
-	llgh	%r1,__LC_CPU_ADDRESS(%r0)	/* Suspend CPU address: r1 */
+	llgh	%r1,__LC_EXT_CPU_ADDR(%r0)	/* Suspend CPU address: r1 */
 	cgr	%r1,%r2
 	je	restore_registers		/* r1 = r2 -> nothing to do */
 	larl	%r4,.Lrestart_suspend_psw	/* Set new restart PSW */
 	mvc	__LC_RST_NEW_PSW(16,%r0),0(%r4)
 3:
-	sigp	%r9,%r1,__SIGP_INITIAL_CPU_RESET
-	brc	8,4f	/* accepted */
-	brc	2,3b	/* busy, try again */
+	sigp	%r9,%r1,11			/* sigp initial cpu reset */
+	brc	8,4f				/* accepted */
+	brc	2,3b				/* busy, try again */
 
 	/* Suspend CPU not available -> panic */
 	larl	%r15,init_thread_union
@@ -196,10 +196,10 @@
 	lpsw	0(%r3)
 4:
 	/* Switch to suspend CPU */
-	sigp	%r9,%r1,__SIGP_RESTART	/* start suspend CPU */
+	sigp	%r9,%r1,6		/* sigp restart to suspend CPU */
 	brc	2,4b			/* busy, try again */
 5:
-	sigp	%r9,%r2,__SIGP_STOP	/* stop resume (current) CPU */
+	sigp	%r9,%r2,5		/* sigp stop to current resume CPU */
 	brc	2,5b			/* busy, try again */
 6:	j	6b
 
@@ -207,7 +207,7 @@
 	larl	%r1,.Lresume_cpu
 	llgh	%r2,0(%r1)
 7:
-	sigp	%r9,%r2,__SIGP_SENSE	/* Wait for resume CPU */
+	sigp	%r9,%r2,1		/* sigp sense, wait for resume CPU */
 	brc	8,7b			/* accepted, status 0, still running */
 	brc	2,7b			/* busy, try again */
 	tmll	%r9,0x40		/* Test if resume CPU is stopped */
@@ -257,6 +257,9 @@
 	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
 
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 14da278..d4e1cb1 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -165,7 +165,7 @@
 	__ctl_set_bit(0, 4);
 }
 
-static void clock_comparator_interrupt(unsigned int ext_int_code,
+static void clock_comparator_interrupt(struct ext_code ext_code,
 				       unsigned int param32,
 				       unsigned long param64)
 {
@@ -177,7 +177,7 @@
 static void etr_timing_alert(struct etr_irq_parm *);
 static void stp_timing_alert(struct stp_irq_parm *);
 
-static void timing_alert_interrupt(unsigned int ext_int_code,
+static void timing_alert_interrupt(struct ext_code ext_code,
 				   unsigned int param32, unsigned long param64)
 {
 	kstat_cpu(smp_processor_id()).irqs[EXTINT_TLA]++;
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c
index 7370a41..4f8dc94 100644
--- a/arch/s390/kernel/topology.c
+++ b/arch/s390/kernel/topology.c
@@ -79,12 +79,12 @@
 	     cpu < TOPOLOGY_CPU_BITS;
 	     cpu = find_next_bit(&tl_cpu->mask[0], TOPOLOGY_CPU_BITS, cpu + 1))
 	{
-		unsigned int rcpu, lcpu;
+		unsigned int rcpu;
+		int lcpu;
 
 		rcpu = TOPOLOGY_CPU_BITS - 1 - cpu + tl_cpu->origin;
-		for_each_present_cpu(lcpu) {
-			if (cpu_logical_map(lcpu) != rcpu)
-				continue;
+		lcpu = smp_find_processor_id(rcpu);
+		if (lcpu >= 0) {
 			cpumask_set_cpu(lcpu, &book->mask);
 			cpu_book_id[lcpu] = book->id;
 			cpumask_set_cpu(lcpu, &core->mask);
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 5ce3750..77cdf42 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -33,7 +33,6 @@
 #include <linux/kprobes.h>
 #include <linux/bug.h>
 #include <linux/utsname.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/atomic.h>
@@ -41,6 +40,7 @@
 #include <asm/cpcmd.h>
 #include <asm/lowcore.h>
 #include <asm/debug.h>
+#include <asm/ipl.h>
 #include "entry.h"
 
 void (*pgm_check_table[128])(struct pt_regs *regs);
@@ -144,8 +144,8 @@
 	for (i = 0; i < kstack_depth_to_print; i++) {
 		if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
 			break;
-		if (i && ((i * sizeof (long) % 32) == 0))
-			printk("\n       ");
+		if ((i * sizeof(long) % 32) == 0)
+			printk("%s       ", i == 0 ? "" : "\n");
 		printk(LONG, *stack++);
 	}
 	printk("\n");
@@ -239,6 +239,7 @@
 	static int die_counter;
 
 	oops_enter();
+	lgr_info_log();
 	debug_stop_all();
 	console_verbose();
 	spin_lock_irq(&die_lock);
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index d73630b..ea5590f 100644
--- a/arch/s390/kernel/vdso.c
+++ b/arch/s390/kernel/vdso.c
@@ -25,12 +25,12 @@
 #include <linux/compat.h>
 #include <asm/asm-offsets.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/mmu.h>
 #include <asm/mmu_context.h>
 #include <asm/sections.h>
 #include <asm/vdso.h>
+#include <asm/facility.h>
 
 #if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT)
 extern char vdso32_start, vdso32_end;
@@ -89,18 +89,11 @@
 
 #ifdef CONFIG_64BIT
 /*
- * Setup per cpu vdso data page.
- */
-static void vdso_init_per_cpu_data(int cpu, struct vdso_per_cpu_data *vpcd)
-{
-}
-
-/*
  * Allocate/free per cpu vdso data.
  */
 #define SEGMENT_ORDER	2
 
-int vdso_alloc_per_cpu(int cpu, struct _lowcore *lowcore)
+int vdso_alloc_per_cpu(struct _lowcore *lowcore)
 {
 	unsigned long segment_table, page_table, page_frame;
 	u32 *psal, *aste;
@@ -139,7 +132,6 @@
 	aste[4] = (u32)(addr_t) psal;
 	lowcore->vdso_per_cpu_data = page_frame;
 
-	vdso_init_per_cpu_data(cpu, (struct vdso_per_cpu_data *) page_frame);
 	return 0;
 
 out:
@@ -149,7 +141,7 @@
 	return -ENOMEM;
 }
 
-void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore)
+void vdso_free_per_cpu(struct _lowcore *lowcore)
 {
 	unsigned long segment_table, page_table, page_frame;
 	u32 *psal, *aste;
@@ -168,19 +160,15 @@
 	free_pages(segment_table, SEGMENT_ORDER);
 }
 
-static void __vdso_init_cr5(void *dummy)
+static void vdso_init_cr5(void)
 {
 	unsigned long cr5;
 
+	if (user_mode == HOME_SPACE_MODE || !vdso_enabled)
+		return;
 	cr5 = offsetof(struct _lowcore, paste);
 	__ctl_load(cr5, 5, 5);
 }
-
-static void vdso_init_cr5(void)
-{
-	if (user_mode != HOME_SPACE_MODE && vdso_enabled)
-		on_each_cpu(__vdso_init_cr5, NULL, 1);
-}
 #endif /* CONFIG_64BIT */
 
 /*
@@ -253,17 +241,11 @@
 	 * on the "data" page of the vDSO or you'll stop getting kernel
 	 * updates and your nice userland gettimeofday will be totally dead.
 	 * It's fine to use that for setting breakpoints in the vDSO code
-	 * pages though
-	 *
-	 * Make sure the vDSO gets into every core dump.
-	 * Dumping its contents makes post-mortem fully interpretable later
-	 * without matching up the same kernel and hardware config to see
-	 * what PC values meant.
+	 * pages though.
 	 */
 	rc = install_special_mapping(mm, vdso_base, vdso_pages << PAGE_SHIFT,
 				     VM_READ|VM_EXEC|
-				     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-				     VM_ALWAYSDUMP,
+				     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
 				     vdso_pagelist);
 	if (rc)
 		current->mm->context.vdso_base = 0;
@@ -322,10 +304,8 @@
 	}
 	vdso64_pagelist[vdso64_pages - 1] = virt_to_page(vdso_data);
 	vdso64_pagelist[vdso64_pages] = NULL;
-#ifndef CONFIG_SMP
-	if (vdso_alloc_per_cpu(0, &S390_lowcore))
+	if (vdso_alloc_per_cpu(&S390_lowcore))
 		BUG();
-#endif
 	vdso_init_cr5();
 #endif /* CONFIG_64BIT */
 
@@ -335,7 +315,7 @@
 
 	return 0;
 }
-arch_initcall(vdso_init);
+early_initcall(vdso_init);
 
 int in_gate_area_no_mm(unsigned long addr)
 {
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index bb48977..39ebff5 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -26,6 +26,7 @@
 #include <asm/irq_regs.h>
 #include <asm/cputime.h>
 #include <asm/irq.h>
+#include "entry.h"
 
 static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
 
@@ -123,153 +124,53 @@
 }
 EXPORT_SYMBOL_GPL(account_system_vtime);
 
-void __kprobes vtime_start_cpu(__u64 int_clock, __u64 enter_timer)
-{
-	struct s390_idle_data *idle = &__get_cpu_var(s390_idle);
-	struct vtimer_queue *vq = &__get_cpu_var(virt_cpu_timer);
-	__u64 idle_time, expires;
-
-	if (idle->idle_enter == 0ULL)
-		return;
-
-	/* Account time spent with enabled wait psw loaded as idle time. */
-	idle_time = int_clock - idle->idle_enter;
-	account_idle_time(idle_time);
-	S390_lowcore.steal_timer +=
-		idle->idle_enter - S390_lowcore.last_update_clock;
-	S390_lowcore.last_update_clock = int_clock;
-
-	/* Account system time spent going idle. */
-	S390_lowcore.system_timer += S390_lowcore.last_update_timer - vq->idle;
-	S390_lowcore.last_update_timer = enter_timer;
-
-	/* Restart vtime CPU timer */
-	if (vq->do_spt) {
-		/* Program old expire value but first save progress. */
-		expires = vq->idle - enter_timer;
-		expires += get_vtimer();
-		set_vtimer(expires);
-	} else {
-		/* Don't account the CPU timer delta while the cpu was idle. */
-		vq->elapsed -= vq->idle - enter_timer;
-	}
-
-	idle->sequence++;
-	smp_wmb();
-	idle->idle_time += idle_time;
-	idle->idle_enter = 0ULL;
-	idle->idle_count++;
-	smp_wmb();
-	idle->sequence++;
-}
-
 void __kprobes vtime_stop_cpu(void)
 {
 	struct s390_idle_data *idle = &__get_cpu_var(s390_idle);
 	struct vtimer_queue *vq = &__get_cpu_var(virt_cpu_timer);
-	psw_t psw;
+	unsigned long long idle_time;
+	unsigned long psw_mask;
+
+	trace_hardirqs_on();
+	/* Don't trace preempt off for idle. */
+	stop_critical_timings();
 
 	/* Wait for external, I/O or machine check interrupt. */
-	psw.mask = psw_kernel_bits | PSW_MASK_WAIT |
-		PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
-
+	psw_mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_DAT |
+		PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
 	idle->nohz_delay = 0;
 
-	/* Check if the CPU timer needs to be reprogrammed. */
-	if (vq->do_spt) {
-		__u64 vmax = VTIMER_MAX_SLICE;
-		/*
-		 * The inline assembly is equivalent to
-		 *	vq->idle = get_cpu_timer();
-		 *	set_cpu_timer(VTIMER_MAX_SLICE);
-		 *	idle->idle_enter = get_clock();
-		 *	__load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT |
-		 *			   PSW_MASK_DAT | PSW_MASK_IO |
-		 *			   PSW_MASK_EXT | PSW_MASK_MCHECK);
-		 * The difference is that the inline assembly makes sure that
-		 * the last three instruction are stpt, stck and lpsw in that
-		 * order. This is done to increase the precision.
-		 */
-		asm volatile(
-#ifndef CONFIG_64BIT
-			"	basr	1,0\n"
-			"0:	ahi	1,1f-0b\n"
-			"	st	1,4(%2)\n"
-#else /* CONFIG_64BIT */
-			"	larl	1,1f\n"
-			"	stg	1,8(%2)\n"
-#endif /* CONFIG_64BIT */
-			"	stpt	0(%4)\n"
-			"	spt	0(%5)\n"
-			"	stck	0(%3)\n"
-#ifndef CONFIG_64BIT
-			"	lpsw	0(%2)\n"
-#else /* CONFIG_64BIT */
-			"	lpswe	0(%2)\n"
-#endif /* CONFIG_64BIT */
-			"1:"
-			: "=m" (idle->idle_enter), "=m" (vq->idle)
-			: "a" (&psw), "a" (&idle->idle_enter),
-			  "a" (&vq->idle), "a" (&vmax), "m" (vmax), "m" (psw)
-			: "memory", "cc", "1");
-	} else {
-		/*
-		 * The inline assembly is equivalent to
-		 *	vq->idle = get_cpu_timer();
-		 *	idle->idle_enter = get_clock();
-		 *	__load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT |
-		 *			   PSW_MASK_DAT | PSW_MASK_IO |
-		 *			   PSW_MASK_EXT | PSW_MASK_MCHECK);
-		 * The difference is that the inline assembly makes sure that
-		 * the last three instruction are stpt, stck and lpsw in that
-		 * order. This is done to increase the precision.
-		 */
-		asm volatile(
-#ifndef CONFIG_64BIT
-			"	basr	1,0\n"
-			"0:	ahi	1,1f-0b\n"
-			"	st	1,4(%2)\n"
-#else /* CONFIG_64BIT */
-			"	larl	1,1f\n"
-			"	stg	1,8(%2)\n"
-#endif /* CONFIG_64BIT */
-			"	stpt	0(%4)\n"
-			"	stck	0(%3)\n"
-#ifndef CONFIG_64BIT
-			"	lpsw	0(%2)\n"
-#else /* CONFIG_64BIT */
-			"	lpswe	0(%2)\n"
-#endif /* CONFIG_64BIT */
-			"1:"
-			: "=m" (idle->idle_enter), "=m" (vq->idle)
-			: "a" (&psw), "a" (&idle->idle_enter),
-			  "a" (&vq->idle), "m" (psw)
-			: "memory", "cc", "1");
-	}
+	/* Call the assembler magic in entry.S */
+	psw_idle(idle, vq, psw_mask, !list_empty(&vq->list));
+
+	/* Reenable preemption tracer. */
+	start_critical_timings();
+
+	/* Account time spent with enabled wait psw loaded as idle time. */
+	idle->sequence++;
+	smp_wmb();
+	idle_time = idle->idle_exit - idle->idle_enter;
+	idle->idle_time += idle_time;
+	idle->idle_enter = idle->idle_exit = 0ULL;
+	idle->idle_count++;
+	account_idle_time(idle_time);
+	smp_wmb();
+	idle->sequence++;
 }
 
 cputime64_t s390_get_idle_time(int cpu)
 {
-	struct s390_idle_data *idle;
-	unsigned long long now, idle_time, idle_enter;
+	struct s390_idle_data *idle = &per_cpu(s390_idle, cpu);
+	unsigned long long now, idle_enter, idle_exit;
 	unsigned int sequence;
 
-	idle = &per_cpu(s390_idle, cpu);
-
-	now = get_clock();
-repeat:
-	sequence = idle->sequence;
-	smp_rmb();
-	if (sequence & 1)
-		goto repeat;
-	idle_time = 0;
-	idle_enter = idle->idle_enter;
-	if (idle_enter != 0ULL && idle_enter < now)
-		idle_time = now - idle_enter;
-	smp_rmb();
-	if (idle->sequence != sequence)
-		goto repeat;
-	return idle_time;
+	do {
+		now = get_clock();
+		sequence = ACCESS_ONCE(idle->sequence);
+		idle_enter = ACCESS_ONCE(idle->idle_enter);
+		idle_exit = ACCESS_ONCE(idle->idle_exit);
+	} while ((sequence & 1) || (idle->sequence != sequence));
+	return idle_enter ? ((idle_exit ? : now) - idle_enter) : 0;
 }
 
 /*
@@ -319,7 +220,7 @@
 /*
  * Handler for the virtual CPU timer.
  */
-static void do_cpu_timer_interrupt(unsigned int ext_int_code,
+static void do_cpu_timer_interrupt(struct ext_code ext_code,
 				   unsigned int param32, unsigned long param64)
 {
 	struct vtimer_queue *vq;
@@ -346,7 +247,6 @@
 	}
 	spin_unlock(&vq->lock);
 
-	vq->do_spt = list_empty(&cb_list);
 	do_callbacks(&cb_list);
 
 	/* next event is first in list */
@@ -355,8 +255,7 @@
 	if (!list_empty(&vq->list)) {
 		event = list_first_entry(&vq->list, struct vtimer_list, entry);
 		next = event->expires;
-	} else
-		vq->do_spt = 0;
+	}
 	spin_unlock(&vq->lock);
 	/*
 	 * To improve precision add the time spent by the
@@ -570,6 +469,9 @@
 
 	/* enable cpu timer interrupts */
 	__ctl_set_bit(0,10);
+
+	/* set initial cpu timer */
+	set_vtimer(0x7fffffffffffffffULL);
 }
 
 static int __cpuinit s390_nohz_notify(struct notifier_block *self,
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
index a216341..78eb984 100644
--- a/arch/s390/kvm/Kconfig
+++ b/arch/s390/kvm/Kconfig
@@ -34,6 +34,15 @@
 
 	  If unsure, say N.
 
+config KVM_S390_UCONTROL
+	bool "Userspace controlled virtual machines"
+	depends on KVM
+	---help---
+	  Allow CAP_SYS_ADMIN users to create KVM virtual machines that are
+	  controlled by userspace.
+
+	  If unsure, say N.
+
 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
 source drivers/vhost/Kconfig
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c
index 8943e82..a353f0e 100644
--- a/arch/s390/kvm/diag.c
+++ b/arch/s390/kvm/diag.c
@@ -20,8 +20,8 @@
 	unsigned long start, end;
 	unsigned long prefix  = vcpu->arch.sie_block->prefix;
 
-	start = vcpu->arch.guest_gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4];
-	end = vcpu->arch.guest_gprs[vcpu->arch.sie_block->ipa & 0xf] + 4096;
+	start = vcpu->run->s.regs.gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4];
+	end = vcpu->run->s.regs.gprs[vcpu->arch.sie_block->ipa & 0xf] + 4096;
 
 	if (start & ~PAGE_MASK || end & ~PAGE_MASK || start > end
 	    || start < 2 * PAGE_SIZE)
@@ -56,7 +56,7 @@
 static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
 {
 	unsigned int reg = vcpu->arch.sie_block->ipa & 0xf;
-	unsigned long subcode = vcpu->arch.guest_gprs[reg] & 0xffff;
+	unsigned long subcode = vcpu->run->s.regs.gprs[reg] & 0xffff;
 
 	VCPU_EVENT(vcpu, 5, "diag ipl functions, subcode %lx", subcode);
 	switch (subcode) {
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 0243454..3614565 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -36,7 +36,7 @@
 
 	useraddr = disp2;
 	if (base2)
-		useraddr += vcpu->arch.guest_gprs[base2];
+		useraddr += vcpu->run->s.regs.gprs[base2];
 
 	if (useraddr & 7)
 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -75,7 +75,7 @@
 
 	useraddr = disp2;
 	if (base2)
-		useraddr += vcpu->arch.guest_gprs[base2];
+		useraddr += vcpu->run->s.regs.gprs[base2];
 
 	if (useraddr & 3)
 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -133,13 +133,6 @@
 
 	vcpu->stat.exit_stop_request++;
 	spin_lock_bh(&vcpu->arch.local_int.lock);
-	if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) {
-		vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP;
-		rc = kvm_s390_vcpu_store_status(vcpu,
-						  KVM_S390_STORE_STATUS_NOADDR);
-		if (rc >= 0)
-			rc = -EOPNOTSUPP;
-	}
 
 	if (vcpu->arch.local_int.action_bits & ACTION_RELOADVCPU_ON_STOP) {
 		vcpu->arch.local_int.action_bits &= ~ACTION_RELOADVCPU_ON_STOP;
@@ -155,7 +148,18 @@
 		rc = -EOPNOTSUPP;
 	}
 
-	spin_unlock_bh(&vcpu->arch.local_int.lock);
+	if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) {
+		vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP;
+		/* store status must be called unlocked. Since local_int.lock
+		 * only protects local_int.* and not guest memory we can give
+		 * up the lock here */
+		spin_unlock_bh(&vcpu->arch.local_int.lock);
+		rc = kvm_s390_vcpu_store_status(vcpu,
+						KVM_S390_STORE_STATUS_NOADDR);
+		if (rc >= 0)
+			rc = -EOPNOTSUPP;
+	} else
+		spin_unlock_bh(&vcpu->arch.local_int.lock);
 	return rc;
 }
 
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 278ee00..2d9f9a7 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -134,7 +134,7 @@
 		if (rc == -EFAULT)
 			exception = 1;
 
-		rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, inti->emerg.code);
+		rc = put_guest_u16(vcpu, __LC_EXT_CPU_ADDR, inti->emerg.code);
 		if (rc == -EFAULT)
 			exception = 1;
 
@@ -156,7 +156,7 @@
 		if (rc == -EFAULT)
 			exception = 1;
 
-		rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, inti->extcall.code);
+		rc = put_guest_u16(vcpu, __LC_EXT_CPU_ADDR, inti->extcall.code);
 		if (rc == -EFAULT)
 			exception = 1;
 
@@ -202,7 +202,7 @@
 		if (rc == -EFAULT)
 			exception = 1;
 
-		rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, 0x0d00);
+		rc = put_guest_u16(vcpu, __LC_EXT_CPU_ADDR, 0x0d00);
 		if (rc == -EFAULT)
 			exception = 1;
 
@@ -236,8 +236,7 @@
 		VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x",
 			   inti->prefix.address);
 		vcpu->stat.deliver_prefix_signal++;
-		vcpu->arch.sie_block->prefix = inti->prefix.address;
-		vcpu->arch.sie_block->ihcpu = 0xffff;
+		kvm_s390_set_prefix(vcpu, inti->prefix.address);
 		break;
 
 	case KVM_S390_RESTART:
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index d1c44573..217ce44 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -27,7 +27,7 @@
 #include <asm/lowcore.h>
 #include <asm/pgtable.h>
 #include <asm/nmi.h>
-#include <asm/system.h>
+#include <asm/switch_to.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
 
@@ -129,6 +129,10 @@
 	case KVM_CAP_S390_PSW:
 	case KVM_CAP_S390_GMAP:
 	case KVM_CAP_SYNC_MMU:
+#ifdef CONFIG_KVM_S390_UCONTROL
+	case KVM_CAP_S390_UCONTROL:
+#endif
+	case KVM_CAP_SYNC_REGS:
 		r = 1;
 		break;
 	default:
@@ -171,11 +175,22 @@
 	return r;
 }
 
-int kvm_arch_init_vm(struct kvm *kvm)
+int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
 	int rc;
 	char debug_name[16];
 
+	rc = -EINVAL;
+#ifdef CONFIG_KVM_S390_UCONTROL
+	if (type & ~KVM_VM_S390_UCONTROL)
+		goto out_err;
+	if ((type & KVM_VM_S390_UCONTROL) && (!capable(CAP_SYS_ADMIN)))
+		goto out_err;
+#else
+	if (type)
+		goto out_err;
+#endif
+
 	rc = s390_enable_sie();
 	if (rc)
 		goto out_err;
@@ -198,10 +213,13 @@
 	debug_register_view(kvm->arch.dbf, &debug_sprintf_view);
 	VM_EVENT(kvm, 3, "%s", "vm created");
 
-	kvm->arch.gmap = gmap_alloc(current->mm);
-	if (!kvm->arch.gmap)
-		goto out_nogmap;
-
+	if (type & KVM_VM_S390_UCONTROL) {
+		kvm->arch.gmap = NULL;
+	} else {
+		kvm->arch.gmap = gmap_alloc(current->mm);
+		if (!kvm->arch.gmap)
+			goto out_nogmap;
+	}
 	return 0;
 out_nogmap:
 	debug_unregister(kvm->arch.dbf);
@@ -214,11 +232,18 @@
 void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 {
 	VCPU_EVENT(vcpu, 3, "%s", "free cpu");
-	clear_bit(63 - vcpu->vcpu_id, (unsigned long *) &vcpu->kvm->arch.sca->mcn);
-	if (vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda ==
-		(__u64) vcpu->arch.sie_block)
-		vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda = 0;
+	if (!kvm_is_ucontrol(vcpu->kvm)) {
+		clear_bit(63 - vcpu->vcpu_id,
+			  (unsigned long *) &vcpu->kvm->arch.sca->mcn);
+		if (vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda ==
+		    (__u64) vcpu->arch.sie_block)
+			vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda = 0;
+	}
 	smp_mb();
+
+	if (kvm_is_ucontrol(vcpu->kvm))
+		gmap_free(vcpu->arch.gmap);
+
 	free_page((unsigned long)(vcpu->arch.sie_block));
 	kvm_vcpu_uninit(vcpu);
 	kfree(vcpu);
@@ -249,13 +274,25 @@
 	kvm_free_vcpus(kvm);
 	free_page((unsigned long)(kvm->arch.sca));
 	debug_unregister(kvm->arch.dbf);
-	gmap_free(kvm->arch.gmap);
+	if (!kvm_is_ucontrol(kvm))
+		gmap_free(kvm->arch.gmap);
 }
 
 /* Section: vcpu related */
 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 {
+	if (kvm_is_ucontrol(vcpu->kvm)) {
+		vcpu->arch.gmap = gmap_alloc(current->mm);
+		if (!vcpu->arch.gmap)
+			return -ENOMEM;
+		return 0;
+	}
+
 	vcpu->arch.gmap = vcpu->kvm->arch.gmap;
+	vcpu->run->kvm_valid_regs = KVM_SYNC_PREFIX |
+				    KVM_SYNC_GPRS |
+				    KVM_SYNC_ACRS |
+				    KVM_SYNC_CRS;
 	return 0;
 }
 
@@ -270,7 +307,7 @@
 	save_access_regs(vcpu->arch.host_acrs);
 	vcpu->arch.guest_fpregs.fpc &= FPC_VALID_MASK;
 	restore_fp_regs(&vcpu->arch.guest_fpregs);
-	restore_access_regs(vcpu->arch.guest_acrs);
+	restore_access_regs(vcpu->run->s.regs.acrs);
 	gmap_enable(vcpu->arch.gmap);
 	atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
 }
@@ -280,7 +317,7 @@
 	atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
 	gmap_disable(vcpu->arch.gmap);
 	save_fp_regs(&vcpu->arch.guest_fpregs);
-	save_access_regs(vcpu->arch.guest_acrs);
+	save_access_regs(vcpu->run->s.regs.acrs);
 	restore_fp_regs(&vcpu->arch.host_fpregs);
 	restore_access_regs(vcpu->arch.host_acrs);
 }
@@ -290,8 +327,7 @@
 	/* this equals initial cpu reset in pop, but we don't switch to ESA */
 	vcpu->arch.sie_block->gpsw.mask = 0UL;
 	vcpu->arch.sie_block->gpsw.addr = 0UL;
-	vcpu->arch.sie_block->prefix    = 0UL;
-	vcpu->arch.sie_block->ihcpu     = 0xffff;
+	kvm_s390_set_prefix(vcpu, 0);
 	vcpu->arch.sie_block->cputm     = 0UL;
 	vcpu->arch.sie_block->ckc       = 0UL;
 	vcpu->arch.sie_block->todpr     = 0;
@@ -342,12 +378,19 @@
 		goto out_free_cpu;
 
 	vcpu->arch.sie_block->icpua = id;
-	BUG_ON(!kvm->arch.sca);
-	if (!kvm->arch.sca->cpu[id].sda)
-		kvm->arch.sca->cpu[id].sda = (__u64) vcpu->arch.sie_block;
-	vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32);
-	vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
-	set_bit(63 - id, (unsigned long *) &kvm->arch.sca->mcn);
+	if (!kvm_is_ucontrol(kvm)) {
+		if (!kvm->arch.sca) {
+			WARN_ON_ONCE(1);
+			goto out_free_cpu;
+		}
+		if (!kvm->arch.sca->cpu[id].sda)
+			kvm->arch.sca->cpu[id].sda =
+				(__u64) vcpu->arch.sie_block;
+		vcpu->arch.sie_block->scaoh =
+			(__u32)(((__u64)kvm->arch.sca) >> 32);
+		vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
+		set_bit(63 - id, (unsigned long *) &kvm->arch.sca->mcn);
+	}
 
 	spin_lock_init(&vcpu->arch.local_int.lock);
 	INIT_LIST_HEAD(&vcpu->arch.local_int.list);
@@ -388,29 +431,29 @@
 
 int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
-	memcpy(&vcpu->arch.guest_gprs, &regs->gprs, sizeof(regs->gprs));
+	memcpy(&vcpu->run->s.regs.gprs, &regs->gprs, sizeof(regs->gprs));
 	return 0;
 }
 
 int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
-	memcpy(&regs->gprs, &vcpu->arch.guest_gprs, sizeof(regs->gprs));
+	memcpy(&regs->gprs, &vcpu->run->s.regs.gprs, sizeof(regs->gprs));
 	return 0;
 }
 
 int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 				  struct kvm_sregs *sregs)
 {
-	memcpy(&vcpu->arch.guest_acrs, &sregs->acrs, sizeof(sregs->acrs));
+	memcpy(&vcpu->run->s.regs.acrs, &sregs->acrs, sizeof(sregs->acrs));
 	memcpy(&vcpu->arch.sie_block->gcr, &sregs->crs, sizeof(sregs->crs));
-	restore_access_regs(vcpu->arch.guest_acrs);
+	restore_access_regs(vcpu->run->s.regs.acrs);
 	return 0;
 }
 
 int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
 				  struct kvm_sregs *sregs)
 {
-	memcpy(&sregs->acrs, &vcpu->arch.guest_acrs, sizeof(sregs->acrs));
+	memcpy(&sregs->acrs, &vcpu->run->s.regs.acrs, sizeof(sregs->acrs));
 	memcpy(&sregs->crs, &vcpu->arch.sie_block->gcr, sizeof(sregs->crs));
 	return 0;
 }
@@ -418,7 +461,7 @@
 int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
 	memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs));
-	vcpu->arch.guest_fpregs.fpc = fpu->fpc;
+	vcpu->arch.guest_fpregs.fpc = fpu->fpc & FPC_VALID_MASK;
 	restore_fp_regs(&vcpu->arch.guest_fpregs);
 	return 0;
 }
@@ -467,9 +510,11 @@
 	return -EINVAL; /* not implemented yet */
 }
 
-static void __vcpu_run(struct kvm_vcpu *vcpu)
+static int __vcpu_run(struct kvm_vcpu *vcpu)
 {
-	memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16);
+	int rc;
+
+	memcpy(&vcpu->arch.sie_block->gg14, &vcpu->run->s.regs.gprs[14], 16);
 
 	if (need_resched())
 		schedule();
@@ -477,7 +522,8 @@
 	if (test_thread_flag(TIF_MCCK_PENDING))
 		s390_handle_mcck();
 
-	kvm_s390_deliver_pending_interrupts(vcpu);
+	if (!kvm_is_ucontrol(vcpu->kvm))
+		kvm_s390_deliver_pending_interrupts(vcpu);
 
 	vcpu->arch.sie_block->icptcode = 0;
 	local_irq_disable();
@@ -485,9 +531,15 @@
 	local_irq_enable();
 	VCPU_EVENT(vcpu, 6, "entering sie flags %x",
 		   atomic_read(&vcpu->arch.sie_block->cpuflags));
-	if (sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs)) {
-		VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction");
-		kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+	rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs);
+	if (rc) {
+		if (kvm_is_ucontrol(vcpu->kvm)) {
+			rc = SIE_INTERCEPT_UCONTROL;
+		} else {
+			VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction");
+			kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+			rc = 0;
+		}
 	}
 	VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
 		   vcpu->arch.sie_block->icptcode);
@@ -495,7 +547,8 @@
 	kvm_guest_exit();
 	local_irq_enable();
 
-	memcpy(&vcpu->arch.guest_gprs[14], &vcpu->arch.sie_block->gg14, 16);
+	memcpy(&vcpu->run->s.regs.gprs[14], &vcpu->arch.sie_block->gg14, 16);
+	return rc;
 }
 
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -516,6 +569,7 @@
 	case KVM_EXIT_UNKNOWN:
 	case KVM_EXIT_INTR:
 	case KVM_EXIT_S390_RESET:
+	case KVM_EXIT_S390_UCONTROL:
 		break;
 	default:
 		BUG();
@@ -523,12 +577,26 @@
 
 	vcpu->arch.sie_block->gpsw.mask = kvm_run->psw_mask;
 	vcpu->arch.sie_block->gpsw.addr = kvm_run->psw_addr;
+	if (kvm_run->kvm_dirty_regs & KVM_SYNC_PREFIX) {
+		kvm_run->kvm_dirty_regs &= ~KVM_SYNC_PREFIX;
+		kvm_s390_set_prefix(vcpu, kvm_run->s.regs.prefix);
+	}
+	if (kvm_run->kvm_dirty_regs & KVM_SYNC_CRS) {
+		kvm_run->kvm_dirty_regs &= ~KVM_SYNC_CRS;
+		memcpy(&vcpu->arch.sie_block->gcr, &kvm_run->s.regs.crs, 128);
+		kvm_s390_set_prefix(vcpu, kvm_run->s.regs.prefix);
+	}
 
 	might_fault();
 
 	do {
-		__vcpu_run(vcpu);
-		rc = kvm_handle_sie_intercept(vcpu);
+		rc = __vcpu_run(vcpu);
+		if (rc)
+			break;
+		if (kvm_is_ucontrol(vcpu->kvm))
+			rc = -EOPNOTSUPP;
+		else
+			rc = kvm_handle_sie_intercept(vcpu);
 	} while (!signal_pending(current) && !rc);
 
 	if (rc == SIE_INTERCEPT_RERUNVCPU)
@@ -539,6 +607,16 @@
 		rc = -EINTR;
 	}
 
+#ifdef CONFIG_KVM_S390_UCONTROL
+	if (rc == SIE_INTERCEPT_UCONTROL) {
+		kvm_run->exit_reason = KVM_EXIT_S390_UCONTROL;
+		kvm_run->s390_ucontrol.trans_exc_code =
+			current->thread.gmap_addr;
+		kvm_run->s390_ucontrol.pgm_code = 0x10;
+		rc = 0;
+	}
+#endif
+
 	if (rc == -EOPNOTSUPP) {
 		/* intercept cannot be handled in-kernel, prepare kvm-run */
 		kvm_run->exit_reason         = KVM_EXIT_S390_SIEIC;
@@ -556,6 +634,8 @@
 
 	kvm_run->psw_mask     = vcpu->arch.sie_block->gpsw.mask;
 	kvm_run->psw_addr     = vcpu->arch.sie_block->gpsw.addr;
+	kvm_run->s.regs.prefix = vcpu->arch.sie_block->prefix;
+	memcpy(&kvm_run->s.regs.crs, &vcpu->arch.sie_block->gcr, 128);
 
 	if (vcpu->sigset_active)
 		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
@@ -602,7 +682,7 @@
 		return -EFAULT;
 
 	if (__guestcopy(vcpu, addr + offsetof(struct save_area, gp_regs),
-			vcpu->arch.guest_gprs, 128, prefix))
+			vcpu->run->s.regs.gprs, 128, prefix))
 		return -EFAULT;
 
 	if (__guestcopy(vcpu, addr + offsetof(struct save_area, psw),
@@ -631,7 +711,7 @@
 		return -EFAULT;
 
 	if (__guestcopy(vcpu, addr + offsetof(struct save_area, acc_regs),
-			&vcpu->arch.guest_acrs, 64, prefix))
+			&vcpu->run->s.regs.acrs, 64, prefix))
 		return -EFAULT;
 
 	if (__guestcopy(vcpu,
@@ -673,12 +753,77 @@
 	case KVM_S390_INITIAL_RESET:
 		r = kvm_arch_vcpu_ioctl_initial_reset(vcpu);
 		break;
+#ifdef CONFIG_KVM_S390_UCONTROL
+	case KVM_S390_UCAS_MAP: {
+		struct kvm_s390_ucas_mapping ucasmap;
+
+		if (copy_from_user(&ucasmap, argp, sizeof(ucasmap))) {
+			r = -EFAULT;
+			break;
+		}
+
+		if (!kvm_is_ucontrol(vcpu->kvm)) {
+			r = -EINVAL;
+			break;
+		}
+
+		r = gmap_map_segment(vcpu->arch.gmap, ucasmap.user_addr,
+				     ucasmap.vcpu_addr, ucasmap.length);
+		break;
+	}
+	case KVM_S390_UCAS_UNMAP: {
+		struct kvm_s390_ucas_mapping ucasmap;
+
+		if (copy_from_user(&ucasmap, argp, sizeof(ucasmap))) {
+			r = -EFAULT;
+			break;
+		}
+
+		if (!kvm_is_ucontrol(vcpu->kvm)) {
+			r = -EINVAL;
+			break;
+		}
+
+		r = gmap_unmap_segment(vcpu->arch.gmap, ucasmap.vcpu_addr,
+			ucasmap.length);
+		break;
+	}
+#endif
+	case KVM_S390_VCPU_FAULT: {
+		r = gmap_fault(arg, vcpu->arch.gmap);
+		if (!IS_ERR_VALUE(r))
+			r = 0;
+		break;
+	}
 	default:
-		r = -EINVAL;
+		r = -ENOTTY;
 	}
 	return r;
 }
 
+int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
+{
+#ifdef CONFIG_KVM_S390_UCONTROL
+	if ((vmf->pgoff == KVM_S390_SIE_PAGE_OFFSET)
+		 && (kvm_is_ucontrol(vcpu->kvm))) {
+		vmf->page = virt_to_page(vcpu->arch.sie_block);
+		get_page(vmf->page);
+		return 0;
+	}
+#endif
+	return VM_FAULT_SIGBUS;
+}
+
+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)
+{
+	return 0;
+}
+
 /* Section: memory related */
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
 				   struct kvm_memory_slot *memslot,
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 99b0b75..ff28f9d 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -26,6 +26,7 @@
 
 /* negativ values are error codes, positive values for internal conditions */
 #define SIE_INTERCEPT_RERUNVCPU		(1<<0)
+#define SIE_INTERCEPT_UCONTROL		(1<<1)
 int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
 
 #define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\
@@ -47,6 +48,23 @@
 	return atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_STOP_INT;
 }
 
+static inline int kvm_is_ucontrol(struct kvm *kvm)
+{
+#ifdef CONFIG_KVM_S390_UCONTROL
+	if (kvm->arch.gmap)
+		return 0;
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+static inline void kvm_s390_set_prefix(struct kvm_vcpu *vcpu, u32 prefix)
+{
+	vcpu->arch.sie_block->prefix = prefix & 0x7fffe000u;
+	vcpu->arch.sie_block->ihcpu  = 0xffff;
+}
+
 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 d026389..e5a45db 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -33,7 +33,7 @@
 
 	operand2 = disp2;
 	if (base2)
-		operand2 += vcpu->arch.guest_gprs[base2];
+		operand2 += vcpu->run->s.regs.gprs[base2];
 
 	/* must be word boundary */
 	if (operand2 & 3) {
@@ -56,8 +56,7 @@
 		goto out;
 	}
 
-	vcpu->arch.sie_block->prefix = address;
-	vcpu->arch.sie_block->ihcpu = 0xffff;
+	kvm_s390_set_prefix(vcpu, address);
 
 	VCPU_EVENT(vcpu, 5, "setting prefix to %x", address);
 out:
@@ -74,7 +73,7 @@
 	vcpu->stat.instruction_stpx++;
 	operand2 = disp2;
 	if (base2)
-		operand2 += vcpu->arch.guest_gprs[base2];
+		operand2 += vcpu->run->s.regs.gprs[base2];
 
 	/* must be word boundary */
 	if (operand2 & 3) {
@@ -106,7 +105,7 @@
 	vcpu->stat.instruction_stap++;
 	useraddr = disp2;
 	if (base2)
-		useraddr += vcpu->arch.guest_gprs[base2];
+		useraddr += vcpu->run->s.regs.gprs[base2];
 
 	if (useraddr & 1) {
 		kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -181,7 +180,7 @@
 	vcpu->stat.instruction_stidp++;
 	operand2 = disp2;
 	if (base2)
-		operand2 += vcpu->arch.guest_gprs[base2];
+		operand2 += vcpu->run->s.regs.gprs[base2];
 
 	if (operand2 & 7) {
 		kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -232,9 +231,9 @@
 
 static int handle_stsi(struct kvm_vcpu *vcpu)
 {
-	int fc = (vcpu->arch.guest_gprs[0] & 0xf0000000) >> 28;
-	int sel1 = vcpu->arch.guest_gprs[0] & 0xff;
-	int sel2 = vcpu->arch.guest_gprs[1] & 0xffff;
+	int fc = (vcpu->run->s.regs.gprs[0] & 0xf0000000) >> 28;
+	int sel1 = vcpu->run->s.regs.gprs[0] & 0xff;
+	int sel2 = vcpu->run->s.regs.gprs[1] & 0xffff;
 	int base2 = vcpu->arch.sie_block->ipb >> 28;
 	int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
 	u64 operand2;
@@ -245,14 +244,14 @@
 
 	operand2 = disp2;
 	if (base2)
-		operand2 += vcpu->arch.guest_gprs[base2];
+		operand2 += vcpu->run->s.regs.gprs[base2];
 
 	if (operand2 & 0xfff && fc > 0)
 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
 
 	switch (fc) {
 	case 0:
-		vcpu->arch.guest_gprs[0] = 3 << 28;
+		vcpu->run->s.regs.gprs[0] = 3 << 28;
 		vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
 		return 0;
 	case 1: /* same handling for 1 and 2 */
@@ -281,7 +280,7 @@
 	}
 	free_page(mem);
 	vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
-	vcpu->arch.guest_gprs[0] = 0;
+	vcpu->run->s.regs.gprs[0] = 0;
 	return 0;
 out_mem:
 	free_page(mem);
@@ -333,8 +332,8 @@
 	int disp1 = (vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16;
 	int base2 = (vcpu->arch.sie_block->ipb & 0xf000) >> 12;
 	int disp2 = vcpu->arch.sie_block->ipb & 0x0fff;
-	u64 address1 = disp1 + base1 ? vcpu->arch.guest_gprs[base1] : 0;
-	u64 address2 = disp2 + base2 ? vcpu->arch.guest_gprs[base2] : 0;
+	u64 address1 = disp1 + base1 ? vcpu->run->s.regs.gprs[base1] : 0;
+	u64 address2 = disp2 + base2 ? vcpu->run->s.regs.gprs[base2] : 0;
 	struct vm_area_struct *vma;
 	unsigned long user_address;
 
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index 0a7941d..0ad4cf2 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -48,7 +48,7 @@
 
 
 static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
-			unsigned long *reg)
+			u64 *reg)
 {
 	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
 	int rc;
@@ -160,12 +160,15 @@
 	inti->type = KVM_S390_SIGP_STOP;
 
 	spin_lock_bh(&li->lock);
+	if ((atomic_read(li->cpuflags) & CPUSTAT_STOPPED))
+		goto out;
 	list_add_tail(&inti->list, &li->list);
 	atomic_set(&li->active, 1);
 	atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
 	li->action_bits |= action;
 	if (waitqueue_active(&li->wq))
 		wake_up_interruptible(&li->wq);
+out:
 	spin_unlock_bh(&li->lock);
 
 	return 0; /* order accepted */
@@ -220,7 +223,7 @@
 }
 
 static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
-			     unsigned long *reg)
+			     u64 *reg)
 {
 	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
 	struct kvm_s390_local_interrupt *li = NULL;
@@ -278,7 +281,7 @@
 }
 
 static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr,
-				unsigned long *reg)
+				u64 *reg)
 {
 	int rc;
 	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
@@ -309,6 +312,34 @@
 	return rc;
 }
 
+static int __sigp_restart(struct kvm_vcpu *vcpu, u16 cpu_addr)
+{
+	int rc = 0;
+	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
+	struct kvm_s390_local_interrupt *li;
+
+	if (cpu_addr >= KVM_MAX_VCPUS)
+		return 3; /* not operational */
+
+	spin_lock(&fi->lock);
+	li = fi->local_int[cpu_addr];
+	if (li == NULL) {
+		rc = 3; /* not operational */
+		goto out;
+	}
+
+	spin_lock_bh(&li->lock);
+	if (li->action_bits & ACTION_STOP_ON_STOP)
+		rc = 2; /* busy */
+	else
+		VCPU_EVENT(vcpu, 4, "sigp restart %x to handle userspace",
+			cpu_addr);
+	spin_unlock_bh(&li->lock);
+out:
+	spin_unlock(&fi->lock);
+	return rc;
+}
+
 int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
 {
 	int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
@@ -316,7 +347,7 @@
 	int base2 = vcpu->arch.sie_block->ipb >> 28;
 	int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
 	u32 parameter;
-	u16 cpu_addr = vcpu->arch.guest_gprs[r3];
+	u16 cpu_addr = vcpu->run->s.regs.gprs[r3];
 	u8 order_code;
 	int rc;
 
@@ -327,18 +358,18 @@
 
 	order_code = disp2;
 	if (base2)
-		order_code += vcpu->arch.guest_gprs[base2];
+		order_code += vcpu->run->s.regs.gprs[base2];
 
 	if (r1 % 2)
-		parameter = vcpu->arch.guest_gprs[r1];
+		parameter = vcpu->run->s.regs.gprs[r1];
 	else
-		parameter = vcpu->arch.guest_gprs[r1 + 1];
+		parameter = vcpu->run->s.regs.gprs[r1 + 1];
 
 	switch (order_code) {
 	case SIGP_SENSE:
 		vcpu->stat.instruction_sigp_sense++;
 		rc = __sigp_sense(vcpu, cpu_addr,
-				  &vcpu->arch.guest_gprs[r1]);
+				  &vcpu->run->s.regs.gprs[r1]);
 		break;
 	case SIGP_EXTERNAL_CALL:
 		vcpu->stat.instruction_sigp_external_call++;
@@ -354,7 +385,8 @@
 		break;
 	case SIGP_STOP_STORE_STATUS:
 		vcpu->stat.instruction_sigp_stop++;
-		rc = __sigp_stop(vcpu, cpu_addr, ACTION_STORE_ON_STOP);
+		rc = __sigp_stop(vcpu, cpu_addr, ACTION_STORE_ON_STOP |
+						 ACTION_STOP_ON_STOP);
 		break;
 	case SIGP_SET_ARCH:
 		vcpu->stat.instruction_sigp_arch++;
@@ -363,15 +395,18 @@
 	case SIGP_SET_PREFIX:
 		vcpu->stat.instruction_sigp_prefix++;
 		rc = __sigp_set_prefix(vcpu, cpu_addr, parameter,
-				       &vcpu->arch.guest_gprs[r1]);
+				       &vcpu->run->s.regs.gprs[r1]);
 		break;
 	case SIGP_SENSE_RUNNING:
 		vcpu->stat.instruction_sigp_sense_running++;
 		rc = __sigp_sense_running(vcpu, cpu_addr,
-					  &vcpu->arch.guest_gprs[r1]);
+					  &vcpu->run->s.regs.gprs[r1]);
 		break;
 	case SIGP_RESTART:
 		vcpu->stat.instruction_sigp_restart++;
+		rc = __sigp_restart(vcpu, cpu_addr);
+		if (rc == 2) /* busy */
+			break;
 		/* user space must know about restart */
 	default:
 		return -EOPNOTSUPP;
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index db92f04..9f1f71e 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -13,6 +13,7 @@
 #include <linux/irqflags.h>
 #include <linux/interrupt.h>
 #include <asm/div64.h>
+#include <asm/timer.h>
 
 void __delay(unsigned long loops)
 {
@@ -28,36 +29,33 @@
 
 static void __udelay_disabled(unsigned long long usecs)
 {
-	unsigned long mask, cr0, cr0_saved;
-	u64 clock_saved;
-	u64 end;
+	unsigned long cr0, cr6, new;
+	u64 clock_saved, end;
 
-	mask = psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_WAIT |
-		PSW_MASK_EXT | PSW_MASK_MCHECK;
 	end = get_clock() + (usecs << 12);
 	clock_saved = local_tick_disable();
-	__ctl_store(cr0_saved, 0, 0);
-	cr0 = (cr0_saved & 0xffff00e0) | 0x00000800;
-	__ctl_load(cr0 , 0, 0);
+	__ctl_store(cr0, 0, 0);
+	__ctl_store(cr6, 6, 6);
+	new = (cr0 &  0xffff00e0) | 0x00000800;
+	__ctl_load(new , 0, 0);
+	new = 0;
+	__ctl_load(new, 6, 6);
 	lockdep_off();
 	do {
 		set_clock_comparator(end);
-		trace_hardirqs_on();
-		__load_psw_mask(mask);
+		vtime_stop_cpu();
 		local_irq_disable();
 	} while (get_clock() < end);
 	lockdep_on();
-	__ctl_load(cr0_saved, 0, 0);
+	__ctl_load(cr0, 0, 0);
+	__ctl_load(cr6, 6, 6);
 	local_tick_enable(clock_saved);
 }
 
 static void __udelay_enabled(unsigned long long usecs)
 {
-	unsigned long mask;
-	u64 clock_saved;
-	u64 end;
+	u64 clock_saved, end;
 
-	mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT | PSW_MASK_IO;
 	end = get_clock() + (usecs << 12);
 	do {
 		clock_saved = 0;
@@ -65,8 +63,7 @@
 			clock_saved = local_tick_disable();
 			set_clock_comparator(end);
 		}
-		trace_hardirqs_on();
-		__load_psw_mask(mask);
+		vtime_stop_cpu();
 		local_irq_disable();
 		if (clock_saved)
 			local_tick_enable(clock_saved);
diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c
index 91754ff..093eb69 100644
--- a/arch/s390/lib/spinlock.c
+++ b/arch/s390/lib/spinlock.c
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/smp.h>
 #include <asm/io.h>
 
 int spin_retry = 1000;
@@ -24,21 +25,6 @@
 }
 __setup("spin_retry=", spin_retry_setup);
 
-static inline void _raw_yield(void)
-{
-	if (MACHINE_HAS_DIAG44)
-		asm volatile("diag 0,0,0x44");
-}
-
-static inline void _raw_yield_cpu(int cpu)
-{
-	if (MACHINE_HAS_DIAG9C)
-		asm volatile("diag %0,0,0x9c"
-			     : : "d" (cpu_logical_map(cpu)));
-	else
-		_raw_yield();
-}
-
 void arch_spin_lock_wait(arch_spinlock_t *lp)
 {
 	int count = spin_retry;
@@ -60,7 +46,7 @@
 		}
 		owner = lp->owner_cpu;
 		if (owner)
-			_raw_yield_cpu(~owner);
+			smp_yield_cpu(~owner);
 		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
 			return;
 	}
@@ -91,7 +77,7 @@
 		}
 		owner = lp->owner_cpu;
 		if (owner)
-			_raw_yield_cpu(~owner);
+			smp_yield_cpu(~owner);
 		local_irq_disable();
 		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
 			return;
@@ -121,7 +107,7 @@
 	if (cpu != 0) {
 		if (MACHINE_IS_VM || MACHINE_IS_KVM ||
 		    !smp_vcpu_scheduled(~cpu))
-			_raw_yield_cpu(~cpu);
+			smp_yield_cpu(~cpu);
 	}
 }
 EXPORT_SYMBOL(arch_spin_relax);
@@ -133,7 +119,7 @@
 
 	while (1) {
 		if (count-- <= 0) {
-			_raw_yield();
+			smp_yield();
 			count = spin_retry;
 		}
 		if (!arch_read_can_lock(rw))
@@ -153,7 +139,7 @@
 	local_irq_restore(flags);
 	while (1) {
 		if (count-- <= 0) {
-			_raw_yield();
+			smp_yield();
 			count = spin_retry;
 		}
 		if (!arch_read_can_lock(rw))
@@ -188,7 +174,7 @@
 
 	while (1) {
 		if (count-- <= 0) {
-			_raw_yield();
+			smp_yield();
 			count = spin_retry;
 		}
 		if (!arch_write_can_lock(rw))
@@ -206,7 +192,7 @@
 	local_irq_restore(flags);
 	while (1) {
 		if (count-- <= 0) {
-			_raw_yield();
+			smp_yield();
 			count = spin_retry;
 		}
 		if (!arch_write_can_lock(rw))
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index e8fcd92..46ef3fd 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -32,10 +32,10 @@
 #include <linux/uaccess.h>
 #include <linux/hugetlb.h>
 #include <asm/asm-offsets.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
+#include <asm/facility.h>
 #include "../kernel/entry.h"
 
 #ifndef CONFIG_64BIT
@@ -532,7 +532,7 @@
 static DEFINE_SPINLOCK(pfault_lock);
 static LIST_HEAD(pfault_list);
 
-static void pfault_interrupt(unsigned int ext_int_code,
+static void pfault_interrupt(struct ext_code ext_code,
 			     unsigned int param32, unsigned long param64)
 {
 	struct task_struct *tsk;
@@ -545,7 +545,7 @@
 	 * in the 'cpu address' field associated with the
          * external interrupt. 
 	 */
-	subcode = ext_int_code >> 16;
+	subcode = ext_code.subcode;
 	if ((subcode & 0xff00) != __SUBCODE_MASK)
 		return;
 	kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++;
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 5023661..2bea060 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -29,7 +29,6 @@
 #include <linux/export.h>
 #include <linux/gfp.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -38,6 +37,7 @@
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 #include <asm/sections.h>
+#include <asm/ctl_reg.h>
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
 
diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c
index 1cb8427..7bb15fc 100644
--- a/arch/s390/mm/maccess.c
+++ b/arch/s390/mm/maccess.c
@@ -12,7 +12,7 @@
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/gfp.h>
-#include <asm/system.h>
+#include <asm/ctl_reg.h>
 
 /*
  * This function writes to kernel memory bypassing DAT and possible
diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c
index a0155c0..2857c48 100644
--- a/arch/s390/mm/mmap.c
+++ b/arch/s390/mm/mmap.c
@@ -100,7 +100,6 @@
 		mm->unmap_area = arch_unmap_area_topdown;
 	}
 }
-EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
 
 #else
 
@@ -175,6 +174,5 @@
 		mm->unmap_area = arch_unmap_area_topdown;
 	}
 }
-EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
 
 #endif
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 51b0738..373adf6 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -18,7 +18,6 @@
 #include <linux/rcupdate.h>
 #include <linux/slab.h>
 
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/tlb.h>
diff --git a/arch/s390/oprofile/hwsampler.c b/arch/s390/oprofile/hwsampler.c
index 9daee91..c6646de 100644
--- a/arch/s390/oprofile/hwsampler.c
+++ b/arch/s390/oprofile/hwsampler.c
@@ -18,7 +18,8 @@
 #include <linux/oom.h>
 #include <linux/oprofile.h>
 
-#include <asm/lowcore.h>
+#include <asm/facility.h>
+#include <asm/cpu_mf.h>
 #include <asm/irq.h>
 
 #include "hwsampler.h"
@@ -30,12 +31,6 @@
 #define ALERT_REQ_MASK   0x4000000000000000ul
 #define BUFFER_FULL_MASK 0x8000000000000000ul
 
-#define EI_IEA      (1 << 31)	/* invalid entry address              */
-#define EI_ISE      (1 << 30)	/* incorrect SDBT entry               */
-#define EI_PRA      (1 << 29)	/* program request alert              */
-#define EI_SACA     (1 << 23)	/* sampler authorization change alert */
-#define EI_LSDA     (1 << 22)	/* loss of sample data alert          */
-
 DECLARE_PER_CPU(struct hws_cpu_buffer, sampler_cpu_buffer);
 
 struct hws_execute_parms {
@@ -232,9 +227,20 @@
 	return (unsigned long *) ret;
 }
 
-/* prototypes for external interrupt handler and worker */
-static void hws_ext_handler(unsigned int ext_int_code,
-				unsigned int param32, unsigned long param64);
+static void hws_ext_handler(struct ext_code ext_code,
+			    unsigned int param32, unsigned long param64)
+{
+	struct hws_cpu_buffer *cb = &__get_cpu_var(sampler_cpu_buffer);
+
+	if (!(param32 & CPU_MF_INT_SF_MASK))
+		return;
+
+	kstat_cpu(smp_processor_id()).irqs[EXTINT_CPM]++;
+	atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32);
+
+	if (hws_wq)
+		queue_work(hws_wq, &cb->worker);
+}
 
 static void worker(struct work_struct *work);
 
@@ -673,18 +679,6 @@
 	return rc;
 }
 
-static void hws_ext_handler(unsigned int ext_int_code,
-			    unsigned int param32, unsigned long param64)
-{
-	struct hws_cpu_buffer *cb;
-
-	kstat_cpu(smp_processor_id()).irqs[EXTINT_CPM]++;
-	cb = &__get_cpu_var(sampler_cpu_buffer);
-	atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32);
-	if (hws_wq)
-		queue_work(hws_wq, &cb->worker);
-}
-
 static int check_qsi_on_setup(void)
 {
 	int rc;
@@ -760,23 +754,23 @@
 	if (!sdbt || !*sdbt)
 		return -EINVAL;
 
-	if (ext_params & EI_PRA)
+	if (ext_params & CPU_MF_INT_SF_PRA)
 		cb->req_alert++;
 
-	if (ext_params & EI_LSDA)
+	if (ext_params & CPU_MF_INT_SF_LSDA)
 		cb->loss_of_sample_data++;
 
-	if (ext_params & EI_IEA) {
+	if (ext_params & CPU_MF_INT_SF_IAE) {
 		cb->invalid_entry_address++;
 		rc = -EINVAL;
 	}
 
-	if (ext_params & EI_ISE) {
+	if (ext_params & CPU_MF_INT_SF_ISE) {
 		cb->incorrect_sdbt_entry++;
 		rc = -EINVAL;
 	}
 
-	if (ext_params & EI_SACA) {
+	if (ext_params & CPU_MF_INT_SF_SACA) {
 		cb->sample_auth_change_alert++;
 		rc = -EINVAL;
 	}
@@ -1009,7 +1003,7 @@
 	if (hws_state != HWS_STOPPED)
 		goto deallocate_exit;
 
-	ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
+	measurement_alert_subclass_unregister();
 	deallocate_sdbt();
 
 	hws_state = HWS_DEALLOCATED;
@@ -1123,7 +1117,7 @@
 		mutex_lock(&hws_sem);
 
 		if (hws_state == HWS_STOPPED) {
-			ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
+			measurement_alert_subclass_unregister();
 			deallocate_sdbt();
 		}
 		if (hws_wq) {
@@ -1198,7 +1192,7 @@
 	hws_oom = 1;
 	hws_flush_all = 0;
 	/* now let them in, 1407 CPUMF external interrupts */
-	ctl_set_bit(0, 5); /* set CR0 bit 58 */
+	measurement_alert_subclass_register();
 
 	return 0;
 }
diff --git a/arch/score/include/asm/atomic.h b/arch/score/include/asm/atomic.h
index 84eb8dd..edf33db 100644
--- a/arch/score/include/asm/atomic.h
+++ b/arch/score/include/asm/atomic.h
@@ -1,6 +1,7 @@
 #ifndef _ASM_SCORE_ATOMIC_H
 #define _ASM_SCORE_ATOMIC_H
 
+#include <asm/cmpxchg.h>
 #include <asm-generic/atomic.h>
 
 #endif /* _ASM_SCORE_ATOMIC_H */
diff --git a/arch/score/include/asm/barrier.h b/arch/score/include/asm/barrier.h
new file mode 100644
index 0000000..0eacb64
--- /dev/null
+++ b/arch/score/include/asm/barrier.h
@@ -0,0 +1,16 @@
+#ifndef _ASM_SCORE_BARRIER_H
+#define _ASM_SCORE_BARRIER_H
+
+#define mb()		barrier()
+#define rmb()		barrier()
+#define wmb()		barrier()
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+
+#define read_barrier_depends()		do {} while (0)
+#define smp_read_barrier_depends()	do {} while (0)
+
+#define set_mb(var, value) 		do {var = value; wmb(); } while (0)
+
+#endif /* _ASM_SCORE_BARRIER_H */
diff --git a/arch/score/include/asm/bitops.h b/arch/score/include/asm/bitops.h
index 2763b05..a304096 100644
--- a/arch/score/include/asm/bitops.h
+++ b/arch/score/include/asm/bitops.h
@@ -2,7 +2,6 @@
 #define _ASM_SCORE_BITOPS_H
 
 #include <asm/byteorder.h> /* swab32 */
-#include <asm/system.h> /* save_flags */
 
 /*
  * clear_bit() doesn't provide any barrier for the compiler.
diff --git a/arch/score/include/asm/bug.h b/arch/score/include/asm/bug.h
index bb76a33..fd7164a 100644
--- a/arch/score/include/asm/bug.h
+++ b/arch/score/include/asm/bug.h
@@ -3,4 +3,15 @@
 
 #include <asm-generic/bug.h>
 
+struct pt_regs;
+extern void __die(const char *, struct pt_regs *, const char *,
+	const char *, unsigned long) __attribute__((noreturn));
+extern void __die_if_kernel(const char *, struct pt_regs *, const char *,
+	const char *, unsigned long);
+
+#define die(msg, regs)							\
+	__die(msg, regs, __FILE__ ":", __func__, __LINE__)
+#define die_if_kernel(msg, regs)					\
+	__die_if_kernel(msg, regs, __FILE__ ":", __func__, __LINE__)
+
 #endif /* _ASM_SCORE_BUG_H */
diff --git a/arch/score/include/asm/cmpxchg.h b/arch/score/include/asm/cmpxchg.h
new file mode 100644
index 0000000..f384839
--- /dev/null
+++ b/arch/score/include/asm/cmpxchg.h
@@ -0,0 +1,49 @@
+#ifndef _ASM_SCORE_CMPXCHG_H
+#define _ASM_SCORE_CMPXCHG_H
+
+#include <linux/irqflags.h>
+
+struct __xchg_dummy { unsigned long a[100]; };
+#define __xg(x) ((struct __xchg_dummy *)(x))
+
+static inline
+unsigned long __xchg(volatile unsigned long *m, unsigned long val)
+{
+	unsigned long retval;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	retval = *m;
+	*m = val;
+	local_irq_restore(flags);
+	return retval;
+}
+
+#define xchg(ptr, v)						\
+	((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr),	\
+					(unsigned long)(v)))
+
+static inline unsigned long __cmpxchg(volatile unsigned long *m,
+				unsigned long old, unsigned long new)
+{
+	unsigned long retval;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	retval = *m;
+	if (retval == old)
+		*m = new;
+	local_irq_restore(flags);
+	return retval;
+}
+
+#define cmpxchg(ptr, o, n)					\
+	((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr),	\
+					(unsigned long)(o),	\
+					(unsigned long)(n)))
+
+#define __HAVE_ARCH_CMPXCHG	1
+
+#include <asm-generic/cmpxchg-local.h>
+
+#endif /* _ASM_SCORE_CMPXCHG_H */
diff --git a/arch/score/include/asm/exec.h b/arch/score/include/asm/exec.h
new file mode 100644
index 0000000..f9f3cd5
--- /dev/null
+++ b/arch/score/include/asm/exec.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_SCORE_EXEC_H
+#define _ASM_SCORE_EXEC_H
+
+extern unsigned long arch_align_stack(unsigned long sp);
+
+#endif /* _ASM_SCORE_EXEC_H */
diff --git a/arch/score/include/asm/switch_to.h b/arch/score/include/asm/switch_to.h
new file mode 100644
index 0000000..031756b
--- /dev/null
+++ b/arch/score/include/asm/switch_to.h
@@ -0,0 +1,13 @@
+#ifndef _ASM_SCORE_SWITCH_TO_H
+#define _ASM_SCORE_SWITCH_TO_H
+
+extern void *resume(void *last, void *next, void *next_ti);
+
+#define switch_to(prev, next, last)				\
+do {								\
+	(last) = resume(prev, next, task_thread_info(next));	\
+} while (0)
+
+#define finish_arch_switch(prev)	do {} while (0)
+
+#endif /* _ASM_SCORE_SWITCH_TO_H */
diff --git a/arch/score/include/asm/system.h b/arch/score/include/asm/system.h
deleted file mode 100644
index 589d5c7..0000000
--- a/arch/score/include/asm/system.h
+++ /dev/null
@@ -1,90 +0,0 @@
-#ifndef _ASM_SCORE_SYSTEM_H
-#define _ASM_SCORE_SYSTEM_H
-
-#include <linux/types.h>
-#include <linux/irqflags.h>
-
-struct pt_regs;
-struct task_struct;
-
-extern void *resume(void *last, void *next, void *next_ti);
-
-#define switch_to(prev, next, last)				\
-do {								\
-	(last) = resume(prev, next, task_thread_info(next));	\
-} while (0)
-
-#define finish_arch_switch(prev)	do {} while (0)
-
-typedef void (*vi_handler_t)(void);
-extern unsigned long arch_align_stack(unsigned long sp);
-
-#define mb()		barrier()
-#define rmb()		barrier()
-#define wmb()		barrier()
-#define smp_mb()	barrier()
-#define smp_rmb()	barrier()
-#define smp_wmb()	barrier()
-
-#define read_barrier_depends()		do {} while (0)
-#define smp_read_barrier_depends()	do {} while (0)
-
-#define set_mb(var, value) 		do {var = value; wmb(); } while (0)
-
-#define __HAVE_ARCH_CMPXCHG	1
-
-#include <asm-generic/cmpxchg-local.h>
-
-#ifndef __ASSEMBLY__
-
-struct __xchg_dummy { unsigned long a[100]; };
-#define __xg(x) ((struct __xchg_dummy *)(x))
-
-static inline
-unsigned long __xchg(volatile unsigned long *m, unsigned long val)
-{
-	unsigned long retval;
-	unsigned long flags;
-
-	local_irq_save(flags);
-	retval = *m;
-	*m = val;
-	local_irq_restore(flags);
-	return retval;
-}
-
-#define xchg(ptr, v)						\
-	((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr),	\
-					(unsigned long)(v)))
-
-static inline unsigned long __cmpxchg(volatile unsigned long *m,
-				unsigned long old, unsigned long new)
-{
-	unsigned long retval;
-	unsigned long flags;
-
-	local_irq_save(flags);
-	retval = *m;
-	if (retval == old)
-		*m = new;
-	local_irq_restore(flags);
-	return retval;
-}
-
-#define cmpxchg(ptr, o, n)					\
-	((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr),	\
-					(unsigned long)(o),	\
-					(unsigned long)(n)))
-
-extern void __die(const char *, struct pt_regs *, const char *,
-	const char *, unsigned long) __attribute__((noreturn));
-extern void __die_if_kernel(const char *, struct pt_regs *, const char *,
-	const char *, unsigned long);
-
-#define die(msg, regs)							\
-	__die(msg, regs, __FILE__ ":", __func__, __LINE__)
-#define die_if_kernel(msg, regs)					\
-	__die_if_kernel(msg, regs, __FILE__ ":", __func__, __LINE__)
-
-#endif /* !__ASSEMBLY__ */
-#endif /* _ASM_SCORE_SYSTEM_H */
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 713fb58..ff9e033 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -5,6 +5,7 @@
 	select HAVE_IDE if HAS_IOPORT
 	select HAVE_MEMBLOCK
 	select HAVE_MEMBLOCK_NODE_MAP
+	select ARCH_DISCARD_MEMBLOCK
 	select HAVE_OPROFILE
 	select HAVE_GENERIC_DMA_COHERENT
 	select HAVE_ARCH_TRACEHOOK
@@ -22,7 +23,7 @@
 	select HAVE_SYSCALL_TRACEPOINTS
 	select HAVE_REGS_AND_STACK_ACCESS_API
 	select HAVE_GENERIC_HARDIRQS
-	select HAVE_SPARSE_IRQ
+	select MAY_HAVE_SPARSE_IRQ
 	select IRQ_FORCED_THREADING
 	select RTC_LIB
 	select GENERIC_ATOMIC64
@@ -161,6 +162,9 @@
 config IO_TRAPPED
 	bool
 
+config SWAP_IO_SPACE
+	bool
+
 config DMA_COHERENT
 	bool
 
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c
index ebd0f81..8cf02e3 100644
--- a/arch/sh/boards/mach-ap325rxa/setup.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -157,7 +157,7 @@
 #define PORT_DRVCRA	0xA405018A
 #define PORT_DRVCRB	0xA405018C
 
-static int ap320_wvga_set_brightness(void *board_data, int brightness)
+static int ap320_wvga_set_brightness(int brightness)
 {
 	if (brightness) {
 		gpio_set_value(GPIO_PTS3, 0);
@@ -170,12 +170,12 @@
 	return 0;
 }
 
-static int ap320_wvga_get_brightness(void *board_data)
+static int ap320_wvga_get_brightness(void)
 {
 	return gpio_get_value(GPIO_PTS3);
 }
 
-static void ap320_wvga_power_on(void *board_data, struct fb_info *info)
+static void ap320_wvga_power_on(void)
 {
 	msleep(100);
 
@@ -183,7 +183,7 @@
 	__raw_writew(FPGA_LCDREG_VAL, FPGA_LCDREG);
 }
 
-static void ap320_wvga_power_off(void *board_data)
+static void ap320_wvga_power_off(void)
 {
 	/* ASD AP-320/325 LCD OFF */
 	__raw_writew(0, FPGA_LCDREG);
@@ -211,21 +211,19 @@
 		.fourcc = V4L2_PIX_FMT_RGB565,
 		.interface_type = RGB18,
 		.clock_divider = 1,
-		.lcd_cfg = ap325rxa_lcdc_modes,
-		.num_cfg = ARRAY_SIZE(ap325rxa_lcdc_modes),
-		.lcd_size_cfg = { /* 7.0 inch */
-			.width = 152,
+		.lcd_modes = ap325rxa_lcdc_modes,
+		.num_modes = ARRAY_SIZE(ap325rxa_lcdc_modes),
+		.panel_cfg = {
+			.width = 152,	/* 7.0 inch */
 			.height = 91,
-		},
-		.board_cfg = {
 			.display_on = ap320_wvga_power_on,
 			.display_off = ap320_wvga_power_off,
-			.set_brightness = ap320_wvga_set_brightness,
-			.get_brightness = ap320_wvga_get_brightness,
 		},
 		.bl_info = {
 			.name = "sh_mobile_lcdc_bl",
 			.max_brightness = 1,
+			.set_brightness = ap320_wvga_set_brightness,
+			.get_brightness = ap320_wvga_get_brightness,
 		},
 	}
 };
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index cde7c00..d12fe9d 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -310,14 +310,14 @@
 	},
 };
 
-static int ecovec24_set_brightness(void *board_data, int brightness)
+static int ecovec24_set_brightness(int brightness)
 {
 	gpio_set_value(GPIO_PTR1, brightness);
 
 	return 0;
 }
 
-static int ecovec24_get_brightness(void *board_data)
+static int ecovec24_get_brightness(void)
 {
 	return gpio_get_value(GPIO_PTR1);
 }
@@ -327,17 +327,15 @@
 		.interface_type = RGB18,
 		.chan = LCDC_CHAN_MAINLCD,
 		.fourcc = V4L2_PIX_FMT_RGB565,
-		.lcd_size_cfg = { /* 7.0 inch */
+		.panel_cfg = { /* 7.0 inch */
 			.width = 152,
 			.height = 91,
 		},
-		.board_cfg = {
-			.set_brightness = ecovec24_set_brightness,
-			.get_brightness = ecovec24_get_brightness,
-		},
 		.bl_info = {
 			.name = "sh_mobile_lcdc_bl",
 			.max_brightness = 1,
+			.set_brightness = ecovec24_set_brightness,
+			.get_brightness = ecovec24_get_brightness,
 		},
 	}
 };
@@ -524,11 +522,18 @@
 	gpio_set_value(GPIO_PTB6, state);
 }
 
+static int sdhi0_get_cd(struct platform_device *pdev)
+{
+	return !gpio_get_value(GPIO_PTY7);
+}
+
 static struct sh_mobile_sdhi_info sdhi0_info = {
 	.dma_slave_tx	= SHDMA_SLAVE_SDHI0_TX,
 	.dma_slave_rx	= SHDMA_SLAVE_SDHI0_RX,
 	.set_pwr	= sdhi0_set_pwr,
-	.tmio_caps      = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD,
+	.tmio_caps      = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD |
+			  MMC_CAP_NEEDS_POLL,
+	.get_cd		= sdhi0_get_cd,
 };
 
 static struct resource sdhi0_resources[] = {
@@ -561,11 +566,18 @@
 	gpio_set_value(GPIO_PTB7, state);
 }
 
+static int sdhi1_get_cd(struct platform_device *pdev)
+{
+	return !gpio_get_value(GPIO_PTW7);
+}
+
 static struct sh_mobile_sdhi_info sdhi1_info = {
 	.dma_slave_tx	= SHDMA_SLAVE_SDHI1_TX,
 	.dma_slave_rx	= SHDMA_SLAVE_SDHI1_RX,
-	.tmio_caps      = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD,
+	.tmio_caps      = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD |
+			  MMC_CAP_NEEDS_POLL,
 	.set_pwr	= sdhi1_set_pwr,
+	.get_cd		= sdhi1_get_cd,
 };
 
 static struct resource sdhi1_resources[] = {
@@ -769,7 +781,9 @@
 
 /* FSI */
 static struct sh_fsi_platform_info fsi_info = {
-	.portb_flags = SH_FSI_BRS_INV,
+	.port_b = {
+		.flags = SH_FSI_BRS_INV,
+	},
 };
 
 static struct resource fsi_resources[] = {
@@ -1001,6 +1015,7 @@
 static int __init arch_setup(void)
 {
 	struct clk *clk;
+	bool cn12_enabled = false;
 
 	/* register board specific self-refresh code */
 	sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF |
@@ -1116,8 +1131,8 @@
 		/* DVI */
 		lcdc_info.clock_source			= LCDC_CLK_EXTERNAL;
 		lcdc_info.ch[0].clock_divider		= 1;
-		lcdc_info.ch[0].lcd_cfg			= ecovec_dvi_modes;
-		lcdc_info.ch[0].num_cfg			= ARRAY_SIZE(ecovec_dvi_modes);
+		lcdc_info.ch[0].lcd_modes		= ecovec_dvi_modes;
+		lcdc_info.ch[0].num_modes		= ARRAY_SIZE(ecovec_dvi_modes);
 
 		gpio_set_value(GPIO_PTA2, 1);
 		gpio_set_value(GPIO_PTU1, 1);
@@ -1125,8 +1140,8 @@
 		/* Panel */
 		lcdc_info.clock_source			= LCDC_CLK_PERIPHERAL;
 		lcdc_info.ch[0].clock_divider		= 2;
-		lcdc_info.ch[0].lcd_cfg			= ecovec_lcd_modes;
-		lcdc_info.ch[0].num_cfg			= ARRAY_SIZE(ecovec_lcd_modes);
+		lcdc_info.ch[0].lcd_modes		= ecovec_lcd_modes;
+		lcdc_info.ch[0].num_modes		= ARRAY_SIZE(ecovec_lcd_modes);
 
 		gpio_set_value(GPIO_PTR1, 1);
 
@@ -1201,9 +1216,13 @@
 	gpio_direction_input(GPIO_PTR5);
 	gpio_direction_input(GPIO_PTR6);
 
+	/* SD-card slot CN11 */
+	/* Card-detect, used on CN11, either with SDHI0 or with SPI */
+	gpio_request(GPIO_PTY7, NULL);
+	gpio_direction_input(GPIO_PTY7);
+
 #if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
 	/* enable SDHI0 on CN11 (needs DS2.4 set to ON) */
-	gpio_request(GPIO_FN_SDHI0CD,  NULL);
 	gpio_request(GPIO_FN_SDHI0WP,  NULL);
 	gpio_request(GPIO_FN_SDHI0CMD, NULL);
 	gpio_request(GPIO_FN_SDHI0CLK, NULL);
@@ -1213,23 +1232,6 @@
 	gpio_request(GPIO_FN_SDHI0D0,  NULL);
 	gpio_request(GPIO_PTB6, NULL);
 	gpio_direction_output(GPIO_PTB6, 0);
-
-#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
-	/* enable SDHI1 on CN12 (needs DS2.6,7 set to ON,OFF) */
-	gpio_request(GPIO_FN_SDHI1CD,  NULL);
-	gpio_request(GPIO_FN_SDHI1WP,  NULL);
-	gpio_request(GPIO_FN_SDHI1CMD, NULL);
-	gpio_request(GPIO_FN_SDHI1CLK, NULL);
-	gpio_request(GPIO_FN_SDHI1D3,  NULL);
-	gpio_request(GPIO_FN_SDHI1D2,  NULL);
-	gpio_request(GPIO_FN_SDHI1D1,  NULL);
-	gpio_request(GPIO_FN_SDHI1D0,  NULL);
-	gpio_request(GPIO_PTB7, NULL);
-	gpio_direction_output(GPIO_PTB7, 0);
-
-	/* I/O buffer drive ability is high for SDHI1 */
-	__raw_writew((__raw_readw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA);
-#endif /* CONFIG_MMC_SH_MMCIF */
 #else
 	/* enable MSIOF0 on CN11 (needs DS2.4 set to OFF) */
 	gpio_request(GPIO_FN_MSIOF0_TXD, NULL);
@@ -1241,12 +1243,51 @@
 	gpio_direction_output(GPIO_PTB6, 0); /* disable power by default */
 	gpio_request(GPIO_PTY6, NULL); /* write protect */
 	gpio_direction_input(GPIO_PTY6);
-	gpio_request(GPIO_PTY7, NULL); /* card detect */
-	gpio_direction_input(GPIO_PTY7);
 
 	spi_register_board_info(spi_bus, ARRAY_SIZE(spi_bus));
 #endif
 
+	/* MMC/SD-card slot CN12 */
+#if defined(CONFIG_MMC_SH_MMCIF) || defined(CONFIG_MMC_SH_MMCIF_MODULE)
+	/* enable MMCIF (needs DS2.6,7 set to OFF,ON) */
+	gpio_request(GPIO_FN_MMC_D7, NULL);
+	gpio_request(GPIO_FN_MMC_D6, NULL);
+	gpio_request(GPIO_FN_MMC_D5, NULL);
+	gpio_request(GPIO_FN_MMC_D4, NULL);
+	gpio_request(GPIO_FN_MMC_D3, NULL);
+	gpio_request(GPIO_FN_MMC_D2, NULL);
+	gpio_request(GPIO_FN_MMC_D1, NULL);
+	gpio_request(GPIO_FN_MMC_D0, NULL);
+	gpio_request(GPIO_FN_MMC_CLK, NULL);
+	gpio_request(GPIO_FN_MMC_CMD, NULL);
+	gpio_request(GPIO_PTB7, NULL);
+	gpio_direction_output(GPIO_PTB7, 0);
+
+	cn12_enabled = true;
+#elif defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
+	/* enable SDHI1 on CN12 (needs DS2.6,7 set to ON,OFF) */
+	gpio_request(GPIO_FN_SDHI1WP,  NULL);
+	gpio_request(GPIO_FN_SDHI1CMD, NULL);
+	gpio_request(GPIO_FN_SDHI1CLK, NULL);
+	gpio_request(GPIO_FN_SDHI1D3,  NULL);
+	gpio_request(GPIO_FN_SDHI1D2,  NULL);
+	gpio_request(GPIO_FN_SDHI1D1,  NULL);
+	gpio_request(GPIO_FN_SDHI1D0,  NULL);
+	gpio_request(GPIO_PTB7, NULL);
+	gpio_direction_output(GPIO_PTB7, 0);
+
+	/* Card-detect, used on CN12 with SDHI1 */
+	gpio_request(GPIO_PTW7, NULL);
+	gpio_direction_input(GPIO_PTW7);
+
+	cn12_enabled = true;
+#endif
+
+	if (cn12_enabled)
+		/* I/O buffer drive ability is high for CN12 */
+		__raw_writew((__raw_readw(IODRIVEA) & ~0x3000) | 0x2000,
+			     IODRIVEA);
+
 	/* enable Video */
 	gpio_request(GPIO_PTU2, NULL);
 	gpio_direction_output(GPIO_PTU2, 1);
@@ -1305,25 +1346,6 @@
 	gpio_request(GPIO_PTU5, NULL);
 	gpio_direction_output(GPIO_PTU5, 0);
 
-#if defined(CONFIG_MMC_SH_MMCIF) || defined(CONFIG_MMC_SH_MMCIF_MODULE)
-	/* enable MMCIF (needs DS2.6,7 set to OFF,ON) */
-	gpio_request(GPIO_FN_MMC_D7, NULL);
-	gpio_request(GPIO_FN_MMC_D6, NULL);
-	gpio_request(GPIO_FN_MMC_D5, NULL);
-	gpio_request(GPIO_FN_MMC_D4, NULL);
-	gpio_request(GPIO_FN_MMC_D3, NULL);
-	gpio_request(GPIO_FN_MMC_D2, NULL);
-	gpio_request(GPIO_FN_MMC_D1, NULL);
-	gpio_request(GPIO_FN_MMC_D0, NULL);
-	gpio_request(GPIO_FN_MMC_CLK, NULL);
-	gpio_request(GPIO_FN_MMC_CMD, NULL);
-	gpio_request(GPIO_PTB7, NULL);
-	gpio_direction_output(GPIO_PTB7, 0);
-
-	/* I/O buffer drive ability is high for MMCIF */
-	__raw_writew((__raw_readw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA);
-#endif
-
 	/* enable I2C device */
 	i2c_register_board_info(0, i2c0_devices,
 				ARRAY_SIZE(i2c0_devices));
diff --git a/arch/sh/boards/mach-highlander/setup.c b/arch/sh/boards/mach-highlander/setup.c
index 74b8db1..4a52590 100644
--- a/arch/sh/boards/mach-highlander/setup.c
+++ b/arch/sh/boards/mach-highlander/setup.c
@@ -322,7 +322,7 @@
 	__raw_writew(__raw_readw(PA_IVDRCTL) & ~(1 << IVDR_CK_ON), PA_IVDRCTL);
 }
 
-static struct clk_ops ivdr_clk_ops = {
+static struct sh_clk_ops ivdr_clk_ops = {
 	.enable		= ivdr_clk_enable,
 	.disable	= ivdr_clk_disable,
 };
diff --git a/arch/sh/boards/mach-kfr2r09/lcd_wqvga.c b/arch/sh/boards/mach-kfr2r09/lcd_wqvga.c
index 25e145f..c148b36 100644
--- a/arch/sh/boards/mach-kfr2r09/lcd_wqvga.c
+++ b/arch/sh/boards/mach-kfr2r09/lcd_wqvga.c
@@ -251,8 +251,7 @@
 	write_memory_start(sohandle, so);
 }
 
-int kfr2r09_lcd_setup(void *board_data, void *sohandle,
-		      struct sh_mobile_lcdc_sys_bus_ops *so)
+int kfr2r09_lcd_setup(void *sohandle, struct sh_mobile_lcdc_sys_bus_ops *so)
 {
 	/* power on */
 	gpio_set_value(GPIO_PTF4, 0);  /* PROTECT/ -> L */
@@ -273,8 +272,7 @@
 	return 0;
 }
 
-void kfr2r09_lcd_start(void *board_data, void *sohandle,
-		       struct sh_mobile_lcdc_sys_bus_ops *so)
+void kfr2r09_lcd_start(void *sohandle, struct sh_mobile_lcdc_sys_bus_ops *so)
 {
 	write_memory_start(sohandle, so);
 }
@@ -327,12 +325,12 @@
 	return 0;
 }
 
-void kfr2r09_lcd_on(void *board_data, struct fb_info *info)
+void kfr2r09_lcd_on(void)
 {
 	kfr2r09_lcd_backlight(1);
 }
 
-void kfr2r09_lcd_off(void *board_data)
+void kfr2r09_lcd_off(void)
 {
 	kfr2r09_lcd_backlight(0);
 }
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index 5b382e1..d04a55d 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -148,13 +148,11 @@
 		.interface_type = SYS18,
 		.clock_divider = 6,
 		.flags = LCDC_FLAGS_DWPOL,
-		.lcd_cfg = kfr2r09_lcdc_modes,
-		.num_cfg = ARRAY_SIZE(kfr2r09_lcdc_modes),
-		.lcd_size_cfg = {
+		.lcd_modes = kfr2r09_lcdc_modes,
+		.num_modes = ARRAY_SIZE(kfr2r09_lcdc_modes),
+		.panel_cfg = {
 			.width = 35,
 			.height = 58,
-		},
-		.board_cfg = {
 			.setup_sys = kfr2r09_lcd_setup,
 			.start_transfer = kfr2r09_lcd_start,
 			.display_on = kfr2r09_lcd_on,
diff --git a/arch/sh/boards/mach-microdev/irq.c b/arch/sh/boards/mach-microdev/irq.c
index 4fb0036..9a8aff3 100644
--- a/arch/sh/boards/mach-microdev/irq.c
+++ b/arch/sh/boards/mach-microdev/irq.c
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <mach/microdev.h>
 
diff --git a/arch/sh/boards/mach-migor/lcd_qvga.c b/arch/sh/boards/mach-migor/lcd_qvga.c
index de9014a..8bccd34 100644
--- a/arch/sh/boards/mach-migor/lcd_qvga.c
+++ b/arch/sh/boards/mach-migor/lcd_qvga.c
@@ -113,8 +113,7 @@
 	0x0010, 0x16B0, 0x0011, 0x0111, 0x0007, 0x0061,
 };
 
-int migor_lcd_qvga_setup(void *board_data, void *sohandle,
-			 struct sh_mobile_lcdc_sys_bus_ops *so)
+int migor_lcd_qvga_setup(void *sohandle, struct sh_mobile_lcdc_sys_bus_ops *so)
 {
 	unsigned long xres = 320;
 	unsigned long yres = 240;
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index d37ba27..ff6f69c 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -246,9 +246,9 @@
 		.fourcc = V4L2_PIX_FMT_RGB565,
 		.interface_type = RGB16,
 		.clock_divider = 2,
-		.lcd_cfg = migor_lcd_modes,
-		.num_cfg = ARRAY_SIZE(migor_lcd_modes),
-		.lcd_size_cfg = { /* 7.0 inch */
+		.lcd_modes = migor_lcd_modes,
+		.num_modes = ARRAY_SIZE(migor_lcd_modes),
+		.panel_cfg = { /* 7.0 inch */
 			.width = 152,
 			.height = 91,
 		},
@@ -260,13 +260,11 @@
 		.fourcc = V4L2_PIX_FMT_RGB565,
 		.interface_type = SYS16A,
 		.clock_divider = 10,
-		.lcd_cfg = migor_lcd_modes,
-		.num_cfg = ARRAY_SIZE(migor_lcd_modes),
-		.lcd_size_cfg = { /* 2.4 inch */
-			.width = 49,
+		.lcd_modes = migor_lcd_modes,
+		.num_modes = ARRAY_SIZE(migor_lcd_modes),
+		.panel_cfg = {
+			.width = 49,	/* 2.4 inch */
 			.height = 37,
-		},
-		.board_cfg = {
 			.setup_sys = migor_lcd_qvga_setup,
 		},
 		.sys_bus_cfg = {
diff --git a/arch/sh/boards/mach-sdk7786/setup.c b/arch/sh/boards/mach-sdk7786/setup.c
index 486d1ac..27a2314 100644
--- a/arch/sh/boards/mach-sdk7786/setup.c
+++ b/arch/sh/boards/mach-sdk7786/setup.c
@@ -167,7 +167,7 @@
 	fpga_write_reg(fpga_read_reg(PCIECR) & ~PCIECR_CLKEN, PCIECR);
 }
 
-static struct clk_ops sdk7786_pcie_clk_ops = {
+static struct sh_clk_ops sdk7786_pcie_clk_ops = {
 	.enable		= sdk7786_pcie_clk_enable,
 	.disable	= sdk7786_pcie_clk_disable,
 };
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index 2b07fc0..c540b16 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -182,12 +182,10 @@
 		.chan = LCDC_CHAN_MAINLCD,
 		.fourcc = V4L2_PIX_FMT_RGB565,
 		.clock_divider = 1,
-		.lcd_size_cfg = { /* 7.0 inch */
+		.panel_cfg = { /* 7.0 inch */
 			.width = 152,
 			.height = 91,
 		},
-		.board_cfg = {
-		},
 	}
 };
 
@@ -278,7 +276,9 @@
 /* FSI */
 /* change J20, J21, J22 pin to 1-2 connection to use slave mode */
 static struct sh_fsi_platform_info fsi_info = {
-	.porta_flags = SH_FSI_BRS_INV,
+	.port_a = {
+		.flags = SH_FSI_BRS_INV,
+	},
 };
 
 static struct resource fsi_resources[] = {
@@ -888,12 +888,12 @@
 
 	if (sw & SW41_B) {
 		/* 720p */
-		lcdc_info.ch[0].lcd_cfg	= lcdc_720p_modes;
-		lcdc_info.ch[0].num_cfg	= ARRAY_SIZE(lcdc_720p_modes);
+		lcdc_info.ch[0].lcd_modes = lcdc_720p_modes;
+		lcdc_info.ch[0].num_modes = ARRAY_SIZE(lcdc_720p_modes);
 	} else {
 		/* VGA */
-		lcdc_info.ch[0].lcd_cfg	= lcdc_vga_modes;
-		lcdc_info.ch[0].num_cfg	= ARRAY_SIZE(lcdc_vga_modes);
+		lcdc_info.ch[0].lcd_modes = lcdc_vga_modes;
+		lcdc_info.ch[0].num_modes = ARRAY_SIZE(lcdc_vga_modes);
 	}
 
 	if (sw & SW41_A) {
diff --git a/arch/sh/boot/Makefile b/arch/sh/boot/Makefile
index e4ea31a..58592df 100644
--- a/arch/sh/boot/Makefile
+++ b/arch/sh/boot/Makefile
@@ -8,8 +8,6 @@
 # Copyright (C) 1999 Stuart Menefy
 #
 
-MKIMAGE := $(srctree)/scripts/mkuboot.sh
-
 #
 # Assign safe dummy values if these variables are not defined,
 # in order to suppress error message.
@@ -61,10 +59,8 @@
 			$(KERNEL_MEMORY) + \
 			$(CONFIG_ZERO_PAGE_OFFSET) + $(CONFIG_ENTRY_OFFSET)]')
 
-quiet_cmd_uimage = UIMAGE  $@
-      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A sh -O linux -T kernel \
-		   -C $(2) -a $(KERNEL_LOAD) -e $(KERNEL_ENTRY) \
-		   -n 'Linux-$(KERNELRELEASE)' -d $< $@
+UIMAGE_LOADADDR = $(KERNEL_LOAD)
+UIMAGE_ENTRYADDR = $(KERNEL_ENTRY)
 
 $(obj)/vmlinux.bin: vmlinux FORCE
 	$(call if_changed,objcopy)
diff --git a/arch/sh/drivers/dma/dma-g2.c b/arch/sh/drivers/dma/dma-g2.c
index be9ca7c..e1ab6eb 100644
--- a/arch/sh/drivers/dma/dma-g2.c
+++ b/arch/sh/drivers/dma/dma-g2.c
@@ -181,14 +181,14 @@
 
 	ret = register_dmac(&g2_dma_info);
 	if (unlikely(ret != 0))
-		free_irq(HW_EVENT_G2_DMA, 0);
+		free_irq(HW_EVENT_G2_DMA, &g2_dma_info);
 
 	return ret;
 }
 
 static void __exit g2_dma_exit(void)
 {
-	free_irq(HW_EVENT_G2_DMA, 0);
+	free_irq(HW_EVENT_G2_DMA, &g2_dma_info);
 	unregister_dmac(&g2_dma_info);
 }
 
diff --git a/arch/sh/drivers/dma/dmabrg.c b/arch/sh/drivers/dma/dmabrg.c
index 3d66a32..c0dd904 100644
--- a/arch/sh/drivers/dma/dmabrg.c
+++ b/arch/sh/drivers/dma/dmabrg.c
@@ -189,8 +189,8 @@
 	if (ret == 0)
 		return ret;
 
-	free_irq(DMABRGI1, 0);
-out1:	free_irq(DMABRGI0, 0);
+	free_irq(DMABRGI1, NULL);
+out1:	free_irq(DMABRGI0, NULL);
 out0:	kfree(dmabrg_handlers);
 	return ret;
 }
diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c
index fb8f1499..5a6dab6 100644
--- a/arch/sh/drivers/pci/pci-sh7780.c
+++ b/arch/sh/drivers/pci/pci-sh7780.c
@@ -21,6 +21,13 @@
 #include <asm/mmu.h>
 #include <asm/sizes.h>
 
+#if defined(CONFIG_CPU_BIG_ENDIAN)
+# define PCICR_ENDIANNESS SH4_PCICR_BSWP
+#else
+# define PCICR_ENDIANNESS 0
+#endif
+
+
 static struct resource sh7785_pci_resources[] = {
 	{
 		.name	= "PCI IO",
@@ -254,7 +261,7 @@
 	__raw_writel(PCIECR_ENBL, PCIECR);
 
 	/* Reset */
-	__raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_PRST,
+	__raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_PRST | PCICR_ENDIANNESS,
 		     chan->reg_base + SH4_PCICR);
 
 	/*
@@ -290,7 +297,8 @@
 	 * Now throw it in to register initialization mode and
 	 * start the real work.
 	 */
-	__raw_writel(SH4_PCICR_PREFIX, chan->reg_base + SH4_PCICR);
+	__raw_writel(SH4_PCICR_PREFIX | PCICR_ENDIANNESS,
+		     chan->reg_base + SH4_PCICR);
 
 	memphys = __pa(memory_start);
 	memsize = roundup_pow_of_two(memory_end - memory_start);
@@ -380,7 +388,8 @@
 	 * Initialization mode complete, release the control register and
 	 * enable round robin mode to stop device overruns/starvation.
 	 */
-	__raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO,
+	__raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO |
+		     PCICR_ENDIANNESS,
 		     chan->reg_base + SH4_PCICR);
 
 	ret = register_pci_controller(chan);
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 1e7b0e2..9d10a3c 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -37,11 +37,20 @@
 	static int next_busno;
 	static int need_domain_info;
 	LIST_HEAD(resources);
+	struct resource *res;
+	resource_size_t offset;
 	int i;
 	struct pci_bus *bus;
 
-	for (i = 0; i < hose->nr_resources; i++)
-		pci_add_resource(&resources, hose->resources + i);
+	for (i = 0; i < hose->nr_resources; i++) {
+		res = hose->resources + i;
+		offset = 0;
+		if (res->flags & IORESOURCE_IO)
+			offset = hose->io_offset;
+		else if (res->flags & IORESOURCE_MEM)
+			offset = hose->mem_offset;
+		pci_add_resource_offset(&resources, res, offset);
+	}
 
 	bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
 				&resources);
@@ -143,42 +152,12 @@
 }
 subsys_initcall(pcibios_init);
 
-static void pcibios_fixup_device_resources(struct pci_dev *dev,
-	struct pci_bus *bus)
-{
-	/* Update device resources.  */
-	struct pci_channel *hose = bus->sysdata;
-	unsigned long offset = 0;
-	int i;
-
-	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-		if (!dev->resource[i].start)
-			continue;
-		if (dev->resource[i].flags & IORESOURCE_IO)
-			offset = hose->io_offset;
-		else if (dev->resource[i].flags & IORESOURCE_MEM)
-			offset = hose->mem_offset;
-
-		dev->resource[i].start += offset;
-		dev->resource[i].end += offset;
-	}
-}
-
 /*
  *  Called after each bus is probed, but before its children
  *  are examined.
  */
 void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
-	struct pci_dev *dev;
-	struct list_head *ln;
-
-	for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
-		dev = pci_dev_b(ln);
-
-		if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
-			pcibios_fixup_device_resources(dev, bus);
-	}
 }
 
 /*
@@ -208,36 +187,6 @@
 	return start;
 }
 
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-			     struct resource *res)
-{
-	struct pci_channel *hose = dev->sysdata;
-	unsigned long offset = 0;
-
-	if (res->flags & IORESOURCE_IO)
-		offset = hose->io_offset;
-	else if (res->flags & IORESOURCE_MEM)
-		offset = hose->mem_offset;
-
-	region->start = res->start - offset;
-	region->end = res->end - offset;
-}
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-			     struct pci_bus_region *region)
-{
-	struct pci_channel *hose = dev->sysdata;
-	unsigned long offset = 0;
-
-	if (res->flags & IORESOURCE_IO)
-		offset = hose->io_offset;
-	else if (res->flags & IORESOURCE_MEM)
-		offset = hose->mem_offset;
-
-	res->start = region->start + offset;
-	res->end = region->end + offset;
-}
-
 int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	return pci_enable_resources(dev, mask);
@@ -381,8 +330,6 @@
 #endif /* CONFIG_GENERIC_IOMAP */
 
 #ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-EXPORT_SYMBOL(pcibios_bus_to_resource);
 EXPORT_SYMBOL(PCIBIOS_MIN_IO);
 EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
 #endif
diff --git a/arch/sh/include/asm/atomic-irq.h b/arch/sh/include/asm/atomic-irq.h
index 467d941..9f7c566 100644
--- a/arch/sh/include/asm/atomic-irq.h
+++ b/arch/sh/include/asm/atomic-irq.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_SH_ATOMIC_IRQ_H
 #define __ASM_SH_ATOMIC_IRQ_H
 
+#include <linux/irqflags.h>
+
 /*
  * To get proper branch prediction for the main line, we must branch
  * forward to code at the end of this object's .text section, then
diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h
index 63a27db..37f2f4a 100644
--- a/arch/sh/include/asm/atomic.h
+++ b/arch/sh/include/asm/atomic.h
@@ -9,7 +9,7 @@
 
 #include <linux/compiler.h>
 #include <linux/types.h>
-#include <asm/system.h>
+#include <asm/cmpxchg.h>
 
 #define ATOMIC_INIT(i)	( (atomic_t) { (i) } )
 
diff --git a/arch/sh/include/asm/auxvec.h b/arch/sh/include/asm/auxvec.h
index 483effd..8bcc51a 100644
--- a/arch/sh/include/asm/auxvec.h
+++ b/arch/sh/include/asm/auxvec.h
@@ -33,4 +33,6 @@
 #define AT_L1D_CACHESHAPE	35
 #define AT_L2_CACHESHAPE	36
 
+#define AT_VECTOR_SIZE_ARCH 5 /* entries in ARCH_DLINFO */
+
 #endif /* __ASM_SH_AUXVEC_H */
diff --git a/arch/sh/include/asm/barrier.h b/arch/sh/include/asm/barrier.h
new file mode 100644
index 0000000..72c103d
--- /dev/null
+++ b/arch/sh/include/asm/barrier.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 1999, 2000  Niibe Yutaka  &  Kaz Kojima
+ * Copyright (C) 2002 Paul Mundt
+ */
+#ifndef __ASM_SH_BARRIER_H
+#define __ASM_SH_BARRIER_H
+
+#if defined(CONFIG_CPU_SH4A) || defined(CONFIG_CPU_SH5)
+#include <asm/cache_insns.h>
+#endif
+
+/*
+ * A brief note on ctrl_barrier(), the control register write barrier.
+ *
+ * Legacy SH cores typically require a sequence of 8 nops after
+ * modification of a control register in order for the changes to take
+ * effect. On newer cores (like the sh4a and sh5) this is accomplished
+ * with icbi.
+ *
+ * Also note that on sh4a in the icbi case we can forego a synco for the
+ * write barrier, as it's not necessary for control registers.
+ *
+ * Historically we have only done this type of barrier for the MMUCR, but
+ * it's also necessary for the CCR, so we make it generic here instead.
+ */
+#if defined(CONFIG_CPU_SH4A) || defined(CONFIG_CPU_SH5)
+#define mb()		__asm__ __volatile__ ("synco": : :"memory")
+#define rmb()		mb()
+#define wmb()		__asm__ __volatile__ ("synco": : :"memory")
+#define ctrl_barrier()	__icbi(PAGE_OFFSET)
+#define read_barrier_depends()	do { } while(0)
+#else
+#define mb()		__asm__ __volatile__ ("": : :"memory")
+#define rmb()		mb()
+#define wmb()		__asm__ __volatile__ ("": : :"memory")
+#define ctrl_barrier()	__asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop")
+#define read_barrier_depends()	do { } while(0)
+#endif
+
+#ifdef CONFIG_SMP
+#define smp_mb()	mb()
+#define smp_rmb()	rmb()
+#define smp_wmb()	wmb()
+#define smp_read_barrier_depends()	read_barrier_depends()
+#else
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+#define smp_read_barrier_depends()	do { } while(0)
+#endif
+
+#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
+
+#endif /* __ASM_SH_BARRIER_H */
diff --git a/arch/sh/include/asm/bitops.h b/arch/sh/include/asm/bitops.h
index 90fa3e4..ea8706d 100644
--- a/arch/sh/include/asm/bitops.h
+++ b/arch/sh/include/asm/bitops.h
@@ -7,7 +7,6 @@
 #error only <linux/bitops.h> can be included directly
 #endif
 
-#include <asm/system.h>
 /* For __swab32 */
 #include <asm/byteorder.h>
 
diff --git a/arch/sh/include/asm/bl_bit.h b/arch/sh/include/asm/bl_bit.h
new file mode 100644
index 0000000..45e6b9f
--- /dev/null
+++ b/arch/sh/include/asm/bl_bit.h
@@ -0,0 +1,10 @@
+#ifndef __ASM_SH_BL_BIT_H
+#define __ASM_SH_BL_BIT_H
+
+#ifdef CONFIG_SUPERH32
+# include "bl_bit_32.h"
+#else
+# include "bl_bit_64.h"
+#endif
+
+#endif /* __ASM_SH_BL_BIT_H */
diff --git a/arch/sh/include/asm/bl_bit_32.h b/arch/sh/include/asm/bl_bit_32.h
new file mode 100644
index 0000000..fd21eee
--- /dev/null
+++ b/arch/sh/include/asm/bl_bit_32.h
@@ -0,0 +1,33 @@
+#ifndef __ASM_SH_BL_BIT_32_H
+#define __ASM_SH_BL_BIT_32_H
+
+static inline void set_bl_bit(void)
+{
+	unsigned long __dummy0, __dummy1;
+
+	__asm__ __volatile__ (
+		"stc	sr, %0\n\t"
+		"or	%2, %0\n\t"
+		"and	%3, %0\n\t"
+		"ldc	%0, sr\n\t"
+		: "=&r" (__dummy0), "=r" (__dummy1)
+		: "r" (0x10000000), "r" (0xffffff0f)
+		: "memory"
+	);
+}
+
+static inline void clear_bl_bit(void)
+{
+	unsigned long __dummy0, __dummy1;
+
+	__asm__ __volatile__ (
+		"stc	sr, %0\n\t"
+		"and	%2, %0\n\t"
+		"ldc	%0, sr\n\t"
+		: "=&r" (__dummy0), "=r" (__dummy1)
+		: "1" (~0x10000000)
+		: "memory"
+	);
+}
+
+#endif /* __ASM_SH_BL_BIT_32_H */
diff --git a/arch/sh/include/asm/bl_bit_64.h b/arch/sh/include/asm/bl_bit_64.h
new file mode 100644
index 0000000..6cc8711
--- /dev/null
+++ b/arch/sh/include/asm/bl_bit_64.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2000, 2001  Paolo Alberelli
+ * Copyright (C) 2003  Paul Mundt
+ * Copyright (C) 2004  Richard Curnow
+ *
+ * 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.
+ */
+#ifndef __ASM_SH_BL_BIT_64_H
+#define __ASM_SH_BL_BIT_64_H
+
+#include <asm/processor.h>
+
+#define SR_BL_LL	0x0000000010000000LL
+
+static inline void set_bl_bit(void)
+{
+	unsigned long long __dummy0, __dummy1 = SR_BL_LL;
+
+	__asm__ __volatile__("getcon	" __SR ", %0\n\t"
+			     "or	%0, %1, %0\n\t"
+			     "putcon	%0, " __SR "\n\t"
+			     : "=&r" (__dummy0)
+			     : "r" (__dummy1));
+
+}
+
+static inline void clear_bl_bit(void)
+{
+	unsigned long long __dummy0, __dummy1 = ~SR_BL_LL;
+
+	__asm__ __volatile__("getcon	" __SR ", %0\n\t"
+			     "and	%0, %1, %0\n\t"
+			     "putcon	%0, " __SR "\n\t"
+			     : "=&r" (__dummy0)
+			     : "r" (__dummy1));
+}
+
+#endif /* __ASM_SH_BL_BIT_64_H */
diff --git a/arch/sh/include/asm/bug.h b/arch/sh/include/asm/bug.h
index 6323f86..2b87d86 100644
--- a/arch/sh/include/asm/bug.h
+++ b/arch/sh/include/asm/bug.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_SH_BUG_H
 #define __ASM_SH_BUG_H
 
+#include <linux/linkage.h>
+
 #define TRAPA_BUG_OPCODE	0xc33e	/* trapa #0x3e */
 #define BUGFLAG_UNWINDER	(1 << 1)
 
@@ -107,4 +109,7 @@
 
 #include <asm-generic/bug.h>
 
+struct pt_regs;
+extern void die(const char *str, struct pt_regs *regs, long err) __attribute__ ((noreturn));
+
 #endif /* __ASM_SH_BUG_H */
diff --git a/arch/sh/include/asm/cache_insns.h b/arch/sh/include/asm/cache_insns.h
new file mode 100644
index 0000000..d25fbe5
--- /dev/null
+++ b/arch/sh/include/asm/cache_insns.h
@@ -0,0 +1,11 @@
+#ifndef __ASM_SH_CACHE_INSNS_H
+#define __ASM_SH_CACHE_INSNS_H
+
+
+#ifdef CONFIG_SUPERH32
+# include "cache_insns_32.h"
+#else
+# include "cache_insns_64.h"
+#endif
+
+#endif /* __ASM_SH_CACHE_INSNS_H */
diff --git a/arch/sh/include/asm/cache_insns_32.h b/arch/sh/include/asm/cache_insns_32.h
new file mode 100644
index 0000000..b92fe54
--- /dev/null
+++ b/arch/sh/include/asm/cache_insns_32.h
@@ -0,0 +1,21 @@
+#ifndef __ASM_SH_CACHE_INSNS_32_H
+#define __ASM_SH_CACHE_INSNS_32_H
+
+#include <linux/types.h>
+
+#if defined(CONFIG_CPU_SH4A)
+#define __icbi(addr)	__asm__ __volatile__ ( "icbi @%0\n\t" : : "r" (addr))
+#else
+#define __icbi(addr)	mb()
+#endif
+
+#define __ocbp(addr)	__asm__ __volatile__ ( "ocbp @%0\n\t" : : "r" (addr))
+#define __ocbi(addr)	__asm__ __volatile__ ( "ocbi @%0\n\t" : : "r" (addr))
+#define __ocbwb(addr)	__asm__ __volatile__ ( "ocbwb @%0\n\t" : : "r" (addr))
+
+static inline reg_size_t register_align(void *val)
+{
+	return (unsigned long)(signed long)val;
+}
+
+#endif /* __ASM_SH_CACHE_INSNS_32_H */
diff --git a/arch/sh/include/asm/cache_insns_64.h b/arch/sh/include/asm/cache_insns_64.h
new file mode 100644
index 0000000..70b6357
--- /dev/null
+++ b/arch/sh/include/asm/cache_insns_64.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2000, 2001  Paolo Alberelli
+ * Copyright (C) 2003  Paul Mundt
+ * Copyright (C) 2004  Richard Curnow
+ *
+ * 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.
+ */
+#ifndef __ASM_SH_CACHE_INSNS_64_H
+#define __ASM_SH_CACHE_INSNS_64_H
+
+#define __icbi(addr)	__asm__ __volatile__ ( "icbi %0, 0\n\t" : : "r" (addr))
+#define __ocbp(addr)	__asm__ __volatile__ ( "ocbp %0, 0\n\t" : : "r" (addr))
+#define __ocbi(addr)	__asm__ __volatile__ ( "ocbi %0, 0\n\t" : : "r" (addr))
+#define __ocbwb(addr)	__asm__ __volatile__ ( "ocbwb %0, 0\n\t" : : "r" (addr))
+
+static inline reg_size_t register_align(void *val)
+{
+	return (unsigned long long)(signed long long)(signed long)val;
+}
+
+#endif /* __ASM_SH_CACHE_INSNS_64_H */
diff --git a/arch/sh/include/asm/clock.h b/arch/sh/include/asm/clock.h
index 803d4c7..0390a07 100644
--- a/arch/sh/include/asm/clock.h
+++ b/arch/sh/include/asm/clock.h
@@ -4,7 +4,7 @@
 #include <linux/sh_clk.h>
 
 /* Should be defined by processor-specific code */
-void __deprecated arch_init_clk_ops(struct clk_ops **, int type);
+void __deprecated arch_init_clk_ops(struct sh_clk_ops **, int type);
 int __init arch_clk_init(void);
 
 /* arch/sh/kernel/cpu/clock-cpg.c */
diff --git a/arch/sh/include/asm/cmpxchg-irq.h b/arch/sh/include/asm/cmpxchg-irq.h
index 43049ec..bd11f63 100644
--- a/arch/sh/include/asm/cmpxchg-irq.h
+++ b/arch/sh/include/asm/cmpxchg-irq.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_SH_CMPXCHG_IRQ_H
 #define __ASM_SH_CMPXCHG_IRQ_H
 
+#include <linux/irqflags.h>
+
 static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val)
 {
 	unsigned long flags, retval;
diff --git a/arch/sh/include/asm/cmpxchg.h b/arch/sh/include/asm/cmpxchg.h
new file mode 100644
index 0000000..f6bd140
--- /dev/null
+++ b/arch/sh/include/asm/cmpxchg.h
@@ -0,0 +1,70 @@
+#ifndef __ASM_SH_CMPXCHG_H
+#define __ASM_SH_CMPXCHG_H
+
+/*
+ * Atomic operations that C can't guarantee us.  Useful for
+ * resource counting etc..
+ */
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#if defined(CONFIG_GUSA_RB)
+#include <asm/cmpxchg-grb.h>
+#elif defined(CONFIG_CPU_SH4A)
+#include <asm/cmpxchg-llsc.h>
+#else
+#include <asm/cmpxchg-irq.h>
+#endif
+
+extern void __xchg_called_with_bad_pointer(void);
+
+#define __xchg(ptr, x, size)				\
+({							\
+	unsigned long __xchg__res;			\
+	volatile void *__xchg_ptr = (ptr);		\
+	switch (size) {					\
+	case 4:						\
+		__xchg__res = xchg_u32(__xchg_ptr, x);	\
+		break;					\
+	case 1:						\
+		__xchg__res = xchg_u8(__xchg_ptr, x);	\
+		break;					\
+	default:					\
+		__xchg_called_with_bad_pointer();	\
+		__xchg__res = x;			\
+		break;					\
+	}						\
+							\
+	__xchg__res;					\
+})
+
+#define xchg(ptr,x)	\
+	((__typeof__(*(ptr)))__xchg((ptr),(unsigned long)(x), sizeof(*(ptr))))
+
+/* This function doesn't exist, so you'll get a linker error
+ * if something tries to do an invalid cmpxchg(). */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+#define __HAVE_ARCH_CMPXCHG 1
+
+static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
+		unsigned long new, int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32(ptr, old, new);
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg(ptr,o,n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
+
+#endif /* __ASM_SH_CMPXCHG_H */
diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h
index 1a73c3e..8bd965e 100644
--- a/arch/sh/include/asm/dma-mapping.h
+++ b/arch/sh/include/asm/dma-mapping.h
@@ -52,25 +52,31 @@
 	return dma_addr == 0;
 }
 
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-				       dma_addr_t *dma_handle, gfp_t gfp)
+#define dma_alloc_coherent(d,s,h,f)	dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+				    dma_addr_t *dma_handle, gfp_t gfp,
+				    struct dma_attrs *attrs)
 {
 	struct dma_map_ops *ops = get_dma_ops(dev);
 	void *memory;
 
 	if (dma_alloc_from_coherent(dev, size, dma_handle, &memory))
 		return memory;
-	if (!ops->alloc_coherent)
+	if (!ops->alloc)
 		return NULL;
 
-	memory = ops->alloc_coherent(dev, size, dma_handle, gfp);
+	memory = ops->alloc(dev, size, dma_handle, gfp, attrs);
 	debug_dma_alloc_coherent(dev, size, *dma_handle, memory);
 
 	return memory;
 }
 
-static inline void dma_free_coherent(struct device *dev, size_t size,
-				     void *vaddr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+				  void *vaddr, dma_addr_t dma_handle,
+				  struct dma_attrs *attrs)
 {
 	struct dma_map_ops *ops = get_dma_ops(dev);
 
@@ -78,14 +84,16 @@
 		return;
 
 	debug_dma_free_coherent(dev, size, vaddr, dma_handle);
-	if (ops->free_coherent)
-		ops->free_coherent(dev, size, vaddr, dma_handle);
+	if (ops->free)
+		ops->free(dev, size, vaddr, dma_handle, attrs);
 }
 
 /* arch/sh/mm/consistent.c */
 extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
-					dma_addr_t *dma_addr, gfp_t flag);
+					dma_addr_t *dma_addr, gfp_t flag,
+					struct dma_attrs *attrs);
 extern void dma_generic_free_coherent(struct device *dev, size_t size,
-				      void *vaddr, dma_addr_t dma_handle);
+				      void *vaddr, dma_addr_t dma_handle,
+				      struct dma_attrs *attrs);
 
 #endif /* __ASM_SH_DMA_MAPPING_H */
diff --git a/arch/sh/include/asm/exec.h b/arch/sh/include/asm/exec.h
new file mode 100644
index 0000000..69486a9
--- /dev/null
+++ b/arch/sh/include/asm/exec.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 1999, 2000  Niibe Yutaka  &  Kaz Kojima
+ * Copyright (C) 2002 Paul Mundt
+ */
+#ifndef __ASM_SH_EXEC_H
+#define __ASM_SH_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* __ASM_SH_EXEC_H */
diff --git a/arch/sh/include/asm/futex-irq.h b/arch/sh/include/asm/futex-irq.h
index 6cb9f19..63d3312 100644
--- a/arch/sh/include/asm/futex-irq.h
+++ b/arch/sh/include/asm/futex-irq.h
@@ -1,7 +1,6 @@
 #ifndef __ASM_SH_FUTEX_IRQ_H
 #define __ASM_SH_FUTEX_IRQ_H
 
-#include <asm/system.h>
 
 static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr,
 					   int *oldval)
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h
index 28c5aa5..ec464a6 100644
--- a/arch/sh/include/asm/io.h
+++ b/arch/sh/include/asm/io.h
@@ -14,7 +14,6 @@
  */
 #include <linux/errno.h>
 #include <asm/cache.h>
-#include <asm/system.h>
 #include <asm/addrspace.h>
 #include <asm/machvec.h>
 #include <asm/pgtable.h>
@@ -24,6 +23,7 @@
 #define __IO_PREFIX     generic
 #include <asm/io_generic.h>
 #include <asm/io_trapped.h>
+#include <mach/mangle-port.h>
 
 #define __raw_writeb(v,a)	(__chk_io_ptr(a), *(volatile u8  __force *)(a) = (v))
 #define __raw_writew(v,a)	(__chk_io_ptr(a), *(volatile u16 __force *)(a) = (v))
@@ -35,21 +35,15 @@
 #define __raw_readl(a)		(__chk_io_ptr(a), *(volatile u32 __force *)(a))
 #define __raw_readq(a)		(__chk_io_ptr(a), *(volatile u64 __force *)(a))
 
-#define readb_relaxed(c)	({ u8  __v = __raw_readb(c); __v; })
-#define readw_relaxed(c)	({ u16 __v = le16_to_cpu((__force __le16) \
-					__raw_readw(c)); __v; })
-#define readl_relaxed(c)	({ u32 __v = le32_to_cpu((__force __le32) \
-					__raw_readl(c)); __v; })
-#define readq_relaxed(c)	({ u64 __v = le64_to_cpu((__force __le64) \
-					__raw_readq(c)); __v; })
+#define readb_relaxed(c)	({ u8  __v = ioswabb(__raw_readb(c)); __v; })
+#define readw_relaxed(c)	({ u16 __v = ioswabw(__raw_readw(c)); __v; })
+#define readl_relaxed(c)	({ u32 __v = ioswabl(__raw_readl(c)); __v; })
+#define readq_relaxed(c)	({ u64 __v = ioswabq(__raw_readq(c)); __v; })
 
-#define writeb_relaxed(v,c)	((void)__raw_writeb(v,c))
-#define writew_relaxed(v,c)	((void)__raw_writew((__force u16) \
-					cpu_to_le16(v),c))
-#define writel_relaxed(v,c)	((void)__raw_writel((__force u32) \
-					cpu_to_le32(v),c))
-#define writeq_relaxed(v,c)	((void)__raw_writeq((__force u64) \
-					cpu_to_le64(v),c))
+#define writeb_relaxed(v,c)	((void)__raw_writeb((__force  u8)ioswabb(v),c))
+#define writew_relaxed(v,c)	((void)__raw_writew((__force u16)ioswabw(v),c))
+#define writel_relaxed(v,c)	((void)__raw_writel((__force u32)ioswabl(v),c))
+#define writeq_relaxed(v,c)	((void)__raw_writeq((__force u64)ioswabq(v),c))
 
 #define readb(a)		({ u8  r_ = readb_relaxed(a); rmb(); r_; })
 #define readw(a)		({ u16 r_ = readw_relaxed(a); rmb(); r_; })
diff --git a/arch/sh/include/asm/irq.h b/arch/sh/include/asm/irq.h
index 45d08b6..2a62017 100644
--- a/arch/sh/include/asm/irq.h
+++ b/arch/sh/include/asm/irq.h
@@ -21,17 +21,6 @@
 #define NO_IRQ_IGNORE		((unsigned int)-1)
 
 /*
- * Convert back and forth between INTEVT and IRQ values.
- */
-#ifdef CONFIG_CPU_HAS_INTEVT
-#define evt2irq(evt)		(((evt) >> 5) - 16)
-#define irq2evt(irq)		(((irq) + 16) << 5)
-#else
-#define evt2irq(evt)		(evt)
-#define irq2evt(irq)		(irq)
-#endif
-
-/*
  * Simple Mask Register Support
  */
 extern void make_maskreg_irq(unsigned int irq);
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index cb21e23..bff96c2 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -114,12 +114,6 @@
 /* Board-specific fixup routines. */
 int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin);
 
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
-	struct pci_bus_region *region, struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-				    struct pci_bus_region *region);
-
 #define pci_domain_nr(bus) ((struct pci_channel *)(bus)->sysdata)->index
 
 static inline int pci_proc_domain(struct pci_bus *bus)
diff --git a/arch/sh/include/asm/posix_types_32.h b/arch/sh/include/asm/posix_types_32.h
index 6a9ceaa..abda584 100644
--- a/arch/sh/include/asm/posix_types_32.h
+++ b/arch/sh/include/asm/posix_types_32.h
@@ -12,11 +12,6 @@
 typedef unsigned short	__kernel_gid_t;
 #define __kernel_gid_t __kernel_gid_t
 
-typedef unsigned int	__kernel_uid32_t;
-#define __kernel_uid32_t __kernel_uid32_t
-typedef unsigned int	__kernel_gid32_t;
-#define __kernel_gid32_t __kernel_gid32_t
-
 typedef unsigned short	__kernel_old_uid_t;
 #define __kernel_old_uid_t __kernel_old_uid_t
 typedef unsigned short	__kernel_old_gid_t;
diff --git a/arch/sh/include/asm/posix_types_64.h b/arch/sh/include/asm/posix_types_64.h
index 8cd1148..fcda07b 100644
--- a/arch/sh/include/asm/posix_types_64.h
+++ b/arch/sh/include/asm/posix_types_64.h
@@ -17,10 +17,6 @@
 #define __kernel_ssize_t __kernel_ssize_t
 typedef int		__kernel_ptrdiff_t;
 #define __kernel_ptrdiff_t __kernel_ptrdiff_t
-typedef unsigned int	__kernel_uid32_t;
-#define __kernel_uid32_t __kernel_uid32_t
-typedef unsigned int	__kernel_gid32_t;
-#define __kernel_gid32_t __kernel_gid32_t
 
 typedef unsigned short	__kernel_old_uid_t;
 #define __kernel_old_uid_t __kernel_old_uid_t
diff --git a/arch/sh/include/asm/processor.h b/arch/sh/include/asm/processor.h
index 9c7bdfc..a229c39 100644
--- a/arch/sh/include/asm/processor.h
+++ b/arch/sh/include/asm/processor.h
@@ -101,6 +101,10 @@
 #define cpu_sleep()	__asm__ __volatile__ ("sleep" : : : "memory")
 #define cpu_relax()	barrier()
 
+void default_idle(void);
+void cpu_idle_wait(void);
+void stop_this_cpu(void *);
+
 /* Forward decl */
 struct seq_operations;
 struct task_struct;
@@ -161,6 +165,17 @@
 #define vsyscall_init() do { } while (0)
 #endif
 
+/*
+ * SH-2A has both 16 and 32-bit opcodes, do lame encoding checks.
+ */
+#ifdef CONFIG_CPU_SH2A
+extern unsigned int instruction_size(unsigned int insn);
+#elif defined(CONFIG_SUPERH32)
+#define instruction_size(insn)	(2)
+#else
+#define instruction_size(insn)	(4)
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #ifdef CONFIG_SUPERH32
diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h
index 2d3679b..c7b7e1e 100644
--- a/arch/sh/include/asm/ptrace.h
+++ b/arch/sh/include/asm/ptrace.h
@@ -37,7 +37,6 @@
 #include <linux/thread_info.h>
 #include <asm/addrspace.h>
 #include <asm/page.h>
-#include <asm/system.h>
 
 #define user_mode(regs)			(((regs)->sr & 0x40000000)==0)
 #define kernel_stack_pointer(_regs)	((unsigned long)(_regs)->regs[15])
diff --git a/arch/sh/include/asm/setup.h b/arch/sh/include/asm/setup.h
index 01fa17a..465a22d 100644
--- a/arch/sh/include/asm/setup.h
+++ b/arch/sh/include/asm/setup.h
@@ -20,6 +20,7 @@
 
 void sh_mv_setup(void);
 void check_for_initrd(void);
+void per_cpu_trap_init(void);
 
 #endif /* __KERNEL__ */
 
diff --git a/arch/sh/include/asm/switch_to.h b/arch/sh/include/asm/switch_to.h
new file mode 100644
index 0000000..62b19418
--- /dev/null
+++ b/arch/sh/include/asm/switch_to.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2000, 2001  Paolo Alberelli
+ * Copyright (C) 2003  Paul Mundt
+ * Copyright (C) 2004  Richard Curnow
+ *
+ * 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.
+ */
+#ifndef __ASM_SH_SWITCH_TO_H
+#define __ASM_SH_SWITCH_TO_H
+
+#ifdef CONFIG_SUPERH32
+# include "switch_to_32.h"
+#else
+# include "switch_to_64.h"
+#endif
+
+#endif /* __ASM_SH_SWITCH_TO_H */
diff --git a/arch/sh/include/asm/switch_to_32.h b/arch/sh/include/asm/switch_to_32.h
new file mode 100644
index 0000000..0c06551
--- /dev/null
+++ b/arch/sh/include/asm/switch_to_32.h
@@ -0,0 +1,134 @@
+#ifndef __ASM_SH_SWITCH_TO_32_H
+#define __ASM_SH_SWITCH_TO_32_H
+
+#ifdef CONFIG_SH_DSP
+
+#define is_dsp_enabled(tsk)						\
+	(!!(tsk->thread.dsp_status.status & SR_DSP))
+
+#define __restore_dsp(tsk)						\
+do {									\
+	register u32 *__ts2 __asm__ ("r2") =				\
+			(u32 *)&tsk->thread.dsp_status;			\
+	__asm__ __volatile__ (						\
+		".balign 4\n\t"						\
+		"movs.l	@r2+, a0\n\t"					\
+		"movs.l	@r2+, a1\n\t"					\
+		"movs.l	@r2+, a0g\n\t"					\
+		"movs.l	@r2+, a1g\n\t"					\
+		"movs.l	@r2+, m0\n\t"					\
+		"movs.l	@r2+, m1\n\t"					\
+		"movs.l	@r2+, x0\n\t"					\
+		"movs.l	@r2+, x1\n\t"					\
+		"movs.l	@r2+, y0\n\t"					\
+		"movs.l	@r2+, y1\n\t"					\
+		"lds.l	@r2+, dsr\n\t"					\
+		"ldc.l	@r2+, rs\n\t"					\
+		"ldc.l	@r2+, re\n\t"					\
+		"ldc.l	@r2+, mod\n\t"					\
+		: : "r" (__ts2));					\
+} while (0)
+
+#define __save_dsp(tsk)							\
+do {									\
+	register u32 *__ts2 __asm__ ("r2") =				\
+			(u32 *)&tsk->thread.dsp_status + 14;		\
+									\
+	__asm__ __volatile__ (						\
+		".balign 4\n\t"						\
+		"stc.l	mod, @-r2\n\t"					\
+		"stc.l	re, @-r2\n\t"					\
+		"stc.l	rs, @-r2\n\t"					\
+		"sts.l	dsr, @-r2\n\t"					\
+		"movs.l	y1, @-r2\n\t"					\
+		"movs.l	y0, @-r2\n\t"					\
+		"movs.l	x1, @-r2\n\t"					\
+		"movs.l	x0, @-r2\n\t"					\
+		"movs.l	m1, @-r2\n\t"					\
+		"movs.l	m0, @-r2\n\t"					\
+		"movs.l	a1g, @-r2\n\t"					\
+		"movs.l	a0g, @-r2\n\t"					\
+		"movs.l	a1, @-r2\n\t"					\
+		"movs.l	a0, @-r2\n\t"					\
+		: : "r" (__ts2));					\
+} while (0)
+
+#else
+
+#define is_dsp_enabled(tsk)	(0)
+#define __save_dsp(tsk)		do { } while (0)
+#define __restore_dsp(tsk)	do { } while (0)
+#endif
+
+struct task_struct *__switch_to(struct task_struct *prev,
+				struct task_struct *next);
+
+/*
+ *	switch_to() should switch tasks to task nr n, first
+ */
+#define switch_to(prev, next, last)				\
+do {								\
+	register u32 *__ts1 __asm__ ("r1");			\
+	register u32 *__ts2 __asm__ ("r2");			\
+	register u32 *__ts4 __asm__ ("r4");			\
+	register u32 *__ts5 __asm__ ("r5");			\
+	register u32 *__ts6 __asm__ ("r6");			\
+	register u32 __ts7 __asm__ ("r7");			\
+	struct task_struct *__last;				\
+								\
+	if (is_dsp_enabled(prev))				\
+		__save_dsp(prev);				\
+								\
+	__ts1 = (u32 *)&prev->thread.sp;			\
+	__ts2 = (u32 *)&prev->thread.pc;			\
+	__ts4 = (u32 *)prev;					\
+	__ts5 = (u32 *)next;					\
+	__ts6 = (u32 *)&next->thread.sp;			\
+	__ts7 = next->thread.pc;				\
+								\
+	__asm__ __volatile__ (					\
+		".balign 4\n\t"					\
+		"stc.l	gbr, @-r15\n\t"				\
+		"sts.l	pr, @-r15\n\t"				\
+		"mov.l	r8, @-r15\n\t"				\
+		"mov.l	r9, @-r15\n\t"				\
+		"mov.l	r10, @-r15\n\t"				\
+		"mov.l	r11, @-r15\n\t"				\
+		"mov.l	r12, @-r15\n\t"				\
+		"mov.l	r13, @-r15\n\t"				\
+		"mov.l	r14, @-r15\n\t"				\
+		"mov.l	r15, @r1\t! save SP\n\t"		\
+		"mov.l	@r6, r15\t! change to new stack\n\t"	\
+		"mova	1f, %0\n\t"				\
+		"mov.l	%0, @r2\t! save PC\n\t"			\
+		"mov.l	2f, %0\n\t"				\
+		"jmp	@%0\t! call __switch_to\n\t"		\
+		" lds	r7, pr\t!  with return to new PC\n\t"	\
+		".balign	4\n"				\
+		"2:\n\t"					\
+		".long	__switch_to\n"				\
+		"1:\n\t"					\
+		"mov.l	@r15+, r14\n\t"				\
+		"mov.l	@r15+, r13\n\t"				\
+		"mov.l	@r15+, r12\n\t"				\
+		"mov.l	@r15+, r11\n\t"				\
+		"mov.l	@r15+, r10\n\t"				\
+		"mov.l	@r15+, r9\n\t"				\
+		"mov.l	@r15+, r8\n\t"				\
+		"lds.l	@r15+, pr\n\t"				\
+		"ldc.l	@r15+, gbr\n\t"				\
+		: "=z" (__last)					\
+		: "r" (__ts1), "r" (__ts2), "r" (__ts4),	\
+		  "r" (__ts5), "r" (__ts6), "r" (__ts7)		\
+		: "r3", "t");					\
+								\
+	last = __last;						\
+} while (0)
+
+#define finish_arch_switch(prev)				\
+do {								\
+	if (is_dsp_enabled(prev))				\
+		__restore_dsp(prev);				\
+} while (0)
+
+#endif /* __ASM_SH_SWITCH_TO_32_H */
diff --git a/arch/sh/include/asm/switch_to_64.h b/arch/sh/include/asm/switch_to_64.h
new file mode 100644
index 0000000..ba3129d
--- /dev/null
+++ b/arch/sh/include/asm/switch_to_64.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2000, 2001  Paolo Alberelli
+ * Copyright (C) 2003  Paul Mundt
+ * Copyright (C) 2004  Richard Curnow
+ *
+ * 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.
+ */
+#ifndef __ASM_SH_SWITCH_TO_64_H
+#define __ASM_SH_SWITCH_TO_64_H
+
+struct thread_struct;
+struct task_struct;
+
+/*
+ *	switch_to() should switch tasks to task nr n, first
+ */
+struct task_struct *sh64_switch_to(struct task_struct *prev,
+				   struct thread_struct *prev_thread,
+				   struct task_struct *next,
+				   struct thread_struct *next_thread);
+
+#define switch_to(prev,next,last)				\
+do {								\
+	if (last_task_used_math != next) {			\
+		struct pt_regs *regs = next->thread.uregs;	\
+		if (regs) regs->sr |= SR_FD;			\
+	}							\
+	last = sh64_switch_to(prev, &prev->thread, next,	\
+			      &next->thread);			\
+} while (0)
+
+
+#endif /* __ASM_SH_SWITCH_TO_64_H */
diff --git a/arch/sh/include/asm/system.h b/arch/sh/include/asm/system.h
deleted file mode 100644
index 10c8b18..0000000
--- a/arch/sh/include/asm/system.h
+++ /dev/null
@@ -1,184 +0,0 @@
-#ifndef __ASM_SH_SYSTEM_H
-#define __ASM_SH_SYSTEM_H
-
-/*
- * Copyright (C) 1999, 2000  Niibe Yutaka  &  Kaz Kojima
- * Copyright (C) 2002 Paul Mundt
- */
-
-#include <linux/irqflags.h>
-#include <linux/compiler.h>
-#include <linux/linkage.h>
-#include <asm/types.h>
-#include <asm/uncached.h>
-
-#define AT_VECTOR_SIZE_ARCH 5 /* entries in ARCH_DLINFO */
-
-/*
- * A brief note on ctrl_barrier(), the control register write barrier.
- *
- * Legacy SH cores typically require a sequence of 8 nops after
- * modification of a control register in order for the changes to take
- * effect. On newer cores (like the sh4a and sh5) this is accomplished
- * with icbi.
- *
- * Also note that on sh4a in the icbi case we can forego a synco for the
- * write barrier, as it's not necessary for control registers.
- *
- * Historically we have only done this type of barrier for the MMUCR, but
- * it's also necessary for the CCR, so we make it generic here instead.
- */
-#if defined(CONFIG_CPU_SH4A) || defined(CONFIG_CPU_SH5)
-#define mb()		__asm__ __volatile__ ("synco": : :"memory")
-#define rmb()		mb()
-#define wmb()		__asm__ __volatile__ ("synco": : :"memory")
-#define ctrl_barrier()	__icbi(PAGE_OFFSET)
-#define read_barrier_depends()	do { } while(0)
-#else
-#define mb()		__asm__ __volatile__ ("": : :"memory")
-#define rmb()		mb()
-#define wmb()		__asm__ __volatile__ ("": : :"memory")
-#define ctrl_barrier()	__asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop")
-#define read_barrier_depends()	do { } while(0)
-#endif
-
-#ifdef CONFIG_SMP
-#define smp_mb()	mb()
-#define smp_rmb()	rmb()
-#define smp_wmb()	wmb()
-#define smp_read_barrier_depends()	read_barrier_depends()
-#else
-#define smp_mb()	barrier()
-#define smp_rmb()	barrier()
-#define smp_wmb()	barrier()
-#define smp_read_barrier_depends()	do { } while(0)
-#endif
-
-#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
-
-#ifdef CONFIG_GUSA_RB
-#include <asm/cmpxchg-grb.h>
-#elif defined(CONFIG_CPU_SH4A)
-#include <asm/cmpxchg-llsc.h>
-#else
-#include <asm/cmpxchg-irq.h>
-#endif
-
-extern void __xchg_called_with_bad_pointer(void);
-
-#define __xchg(ptr, x, size)				\
-({							\
-	unsigned long __xchg__res;			\
-	volatile void *__xchg_ptr = (ptr);		\
-	switch (size) {					\
-	case 4:						\
-		__xchg__res = xchg_u32(__xchg_ptr, x);	\
-		break;					\
-	case 1:						\
-		__xchg__res = xchg_u8(__xchg_ptr, x);	\
-		break;					\
-	default:					\
-		__xchg_called_with_bad_pointer();	\
-		__xchg__res = x;			\
-		break;					\
-	}						\
-							\
-	__xchg__res;					\
-})
-
-#define xchg(ptr,x)	\
-	((__typeof__(*(ptr)))__xchg((ptr),(unsigned long)(x), sizeof(*(ptr))))
-
-/* This function doesn't exist, so you'll get a linker error
- * if something tries to do an invalid cmpxchg(). */
-extern void __cmpxchg_called_with_bad_pointer(void);
-
-#define __HAVE_ARCH_CMPXCHG 1
-
-static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
-		unsigned long new, int size)
-{
-	switch (size) {
-	case 4:
-		return __cmpxchg_u32(ptr, old, new);
-	}
-	__cmpxchg_called_with_bad_pointer();
-	return old;
-}
-
-#define cmpxchg(ptr,o,n)						 \
-  ({									 \
-     __typeof__(*(ptr)) _o_ = (o);					 \
-     __typeof__(*(ptr)) _n_ = (n);					 \
-     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
-				    (unsigned long)_n_, sizeof(*(ptr))); \
-  })
-
-struct pt_regs;
-
-extern void die(const char *str, struct pt_regs *regs, long err) __attribute__ ((noreturn));
-void free_initmem(void);
-void free_initrd_mem(unsigned long start, unsigned long end);
-
-extern void *set_exception_table_vec(unsigned int vec, void *handler);
-
-static inline void *set_exception_table_evt(unsigned int evt, void *handler)
-{
-	return set_exception_table_vec(evt >> 5, handler);
-}
-
-/*
- * SH-2A has both 16 and 32-bit opcodes, do lame encoding checks.
- */
-#ifdef CONFIG_CPU_SH2A
-extern unsigned int instruction_size(unsigned int insn);
-#elif defined(CONFIG_SUPERH32)
-#define instruction_size(insn)	(2)
-#else
-#define instruction_size(insn)	(4)
-#endif
-
-void per_cpu_trap_init(void);
-void default_idle(void);
-void cpu_idle_wait(void);
-void stop_this_cpu(void *);
-
-#ifdef CONFIG_SUPERH32
-#define BUILD_TRAP_HANDLER(name)					\
-asmlinkage void name##_trap_handler(unsigned long r4, unsigned long r5,	\
-				    unsigned long r6, unsigned long r7,	\
-				    struct pt_regs __regs)
-
-#define TRAP_HANDLER_DECL				\
-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);	\
-	unsigned int vec = regs->tra;			\
-	(void)vec;
-#else
-#define BUILD_TRAP_HANDLER(name)	\
-asmlinkage void name##_trap_handler(unsigned int vec, struct pt_regs *regs)
-#define TRAP_HANDLER_DECL
-#endif
-
-BUILD_TRAP_HANDLER(address_error);
-BUILD_TRAP_HANDLER(debug);
-BUILD_TRAP_HANDLER(bug);
-BUILD_TRAP_HANDLER(breakpoint);
-BUILD_TRAP_HANDLER(singlestep);
-BUILD_TRAP_HANDLER(fpu_error);
-BUILD_TRAP_HANDLER(fpu_state_restore);
-BUILD_TRAP_HANDLER(nmi);
-
-#define arch_align_stack(x) (x)
-
-struct mem_access {
-	unsigned long (*from)(void *dst, const void __user *src, unsigned long cnt);
-	unsigned long (*to)(void __user *dst, const void *src, unsigned long cnt);
-};
-
-#ifdef CONFIG_SUPERH32
-# include "system_32.h"
-#else
-# include "system_64.h"
-#endif
-
-#endif
diff --git a/arch/sh/include/asm/system_32.h b/arch/sh/include/asm/system_32.h
deleted file mode 100644
index a4ad1cd..0000000
--- a/arch/sh/include/asm/system_32.h
+++ /dev/null
@@ -1,236 +0,0 @@
-#ifndef __ASM_SH_SYSTEM_32_H
-#define __ASM_SH_SYSTEM_32_H
-
-#include <linux/types.h>
-#include <asm/mmu.h>
-
-#ifdef CONFIG_SH_DSP
-
-#define is_dsp_enabled(tsk)						\
-	(!!(tsk->thread.dsp_status.status & SR_DSP))
-
-#define __restore_dsp(tsk)						\
-do {									\
-	register u32 *__ts2 __asm__ ("r2") =				\
-			(u32 *)&tsk->thread.dsp_status;			\
-	__asm__ __volatile__ (						\
-		".balign 4\n\t"						\
-		"movs.l	@r2+, a0\n\t"					\
-		"movs.l	@r2+, a1\n\t"					\
-		"movs.l	@r2+, a0g\n\t"					\
-		"movs.l	@r2+, a1g\n\t"					\
-		"movs.l	@r2+, m0\n\t"					\
-		"movs.l	@r2+, m1\n\t"					\
-		"movs.l	@r2+, x0\n\t"					\
-		"movs.l	@r2+, x1\n\t"					\
-		"movs.l	@r2+, y0\n\t"					\
-		"movs.l	@r2+, y1\n\t"					\
-		"lds.l	@r2+, dsr\n\t"					\
-		"ldc.l	@r2+, rs\n\t"					\
-		"ldc.l	@r2+, re\n\t"					\
-		"ldc.l	@r2+, mod\n\t"					\
-		: : "r" (__ts2));					\
-} while (0)
-
-
-#define __save_dsp(tsk)							\
-do {									\
-	register u32 *__ts2 __asm__ ("r2") =				\
-			(u32 *)&tsk->thread.dsp_status + 14;		\
-									\
-	__asm__ __volatile__ (						\
-		".balign 4\n\t"						\
-		"stc.l	mod, @-r2\n\t"					\
-		"stc.l	re, @-r2\n\t"					\
-		"stc.l	rs, @-r2\n\t"					\
-		"sts.l	dsr, @-r2\n\t"					\
-		"movs.l	y1, @-r2\n\t"					\
-		"movs.l	y0, @-r2\n\t"					\
-		"movs.l	x1, @-r2\n\t"					\
-		"movs.l	x0, @-r2\n\t"					\
-		"movs.l	m1, @-r2\n\t"					\
-		"movs.l	m0, @-r2\n\t"					\
-		"movs.l	a1g, @-r2\n\t"					\
-		"movs.l	a0g, @-r2\n\t"					\
-		"movs.l	a1, @-r2\n\t"					\
-		"movs.l	a0, @-r2\n\t"					\
-		: : "r" (__ts2));					\
-} while (0)
-
-#else
-
-#define is_dsp_enabled(tsk)	(0)
-#define __save_dsp(tsk)		do { } while (0)
-#define __restore_dsp(tsk)	do { } while (0)
-#endif
-
-#if defined(CONFIG_CPU_SH4A)
-#define __icbi(addr)	__asm__ __volatile__ ( "icbi @%0\n\t" : : "r" (addr))
-#else
-#define __icbi(addr)	mb()
-#endif
-
-#define __ocbp(addr)	__asm__ __volatile__ ( "ocbp @%0\n\t" : : "r" (addr))
-#define __ocbi(addr)	__asm__ __volatile__ ( "ocbi @%0\n\t" : : "r" (addr))
-#define __ocbwb(addr)	__asm__ __volatile__ ( "ocbwb @%0\n\t" : : "r" (addr))
-
-struct task_struct *__switch_to(struct task_struct *prev,
-				struct task_struct *next);
-
-/*
- *	switch_to() should switch tasks to task nr n, first
- */
-#define switch_to(prev, next, last)				\
-do {								\
-	register u32 *__ts1 __asm__ ("r1");			\
-	register u32 *__ts2 __asm__ ("r2");			\
-	register u32 *__ts4 __asm__ ("r4");			\
-	register u32 *__ts5 __asm__ ("r5");			\
-	register u32 *__ts6 __asm__ ("r6");			\
-	register u32 __ts7 __asm__ ("r7");			\
-	struct task_struct *__last;				\
-								\
-	if (is_dsp_enabled(prev))				\
-		__save_dsp(prev);				\
-								\
-	__ts1 = (u32 *)&prev->thread.sp;			\
-	__ts2 = (u32 *)&prev->thread.pc;			\
-	__ts4 = (u32 *)prev;					\
-	__ts5 = (u32 *)next;					\
-	__ts6 = (u32 *)&next->thread.sp;			\
-	__ts7 = next->thread.pc;				\
-								\
-	__asm__ __volatile__ (					\
-		".balign 4\n\t"					\
-		"stc.l	gbr, @-r15\n\t"				\
-		"sts.l	pr, @-r15\n\t"				\
-		"mov.l	r8, @-r15\n\t"				\
-		"mov.l	r9, @-r15\n\t"				\
-		"mov.l	r10, @-r15\n\t"				\
-		"mov.l	r11, @-r15\n\t"				\
-		"mov.l	r12, @-r15\n\t"				\
-		"mov.l	r13, @-r15\n\t"				\
-		"mov.l	r14, @-r15\n\t"				\
-		"mov.l	r15, @r1\t! save SP\n\t"		\
-		"mov.l	@r6, r15\t! change to new stack\n\t"	\
-		"mova	1f, %0\n\t"				\
-		"mov.l	%0, @r2\t! save PC\n\t"			\
-		"mov.l	2f, %0\n\t"				\
-		"jmp	@%0\t! call __switch_to\n\t"		\
-		" lds	r7, pr\t!  with return to new PC\n\t"	\
-		".balign	4\n"				\
-		"2:\n\t"					\
-		".long	__switch_to\n"				\
-		"1:\n\t"					\
-		"mov.l	@r15+, r14\n\t"				\
-		"mov.l	@r15+, r13\n\t"				\
-		"mov.l	@r15+, r12\n\t"				\
-		"mov.l	@r15+, r11\n\t"				\
-		"mov.l	@r15+, r10\n\t"				\
-		"mov.l	@r15+, r9\n\t"				\
-		"mov.l	@r15+, r8\n\t"				\
-		"lds.l	@r15+, pr\n\t"				\
-		"ldc.l	@r15+, gbr\n\t"				\
-		: "=z" (__last)					\
-		: "r" (__ts1), "r" (__ts2), "r" (__ts4),	\
-		  "r" (__ts5), "r" (__ts6), "r" (__ts7)		\
-		: "r3", "t");					\
-								\
-	last = __last;						\
-} while (0)
-
-#define finish_arch_switch(prev)				\
-do {								\
-	if (is_dsp_enabled(prev))				\
-		__restore_dsp(prev);				\
-} while (0)
-
-#ifdef CONFIG_CPU_HAS_SR_RB
-#define lookup_exception_vector()	\
-({					\
-	unsigned long _vec;		\
-					\
-	__asm__ __volatile__ (		\
-		"stc r2_bank, %0\n\t"	\
-		: "=r" (_vec)		\
-	);				\
-					\
-	_vec;				\
-})
-#else
-#define lookup_exception_vector()	\
-({					\
-	unsigned long _vec;		\
-	__asm__ __volatile__ (		\
-		"mov r4, %0\n\t"	\
-		: "=r" (_vec)		\
-	);				\
-					\
-	_vec;				\
-})
-#endif
-
-static inline reg_size_t register_align(void *val)
-{
-	return (unsigned long)(signed long)val;
-}
-
-int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
-			    struct mem_access *ma, int, unsigned long address);
-
-static inline void trigger_address_error(void)
-{
-	__asm__ __volatile__ (
-		"ldc %0, sr\n\t"
-		"mov.l @%1, %0"
-		:
-		: "r" (0x10000000), "r" (0x80000001)
-	);
-}
-
-asmlinkage void do_address_error(struct pt_regs *regs,
-				 unsigned long writeaccess,
-				 unsigned long address);
-asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
-				unsigned long r6, unsigned long r7,
-				struct pt_regs __regs);
-asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
-				unsigned long r6, unsigned long r7,
-				struct pt_regs __regs);
-asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
-				unsigned long r6, unsigned long r7,
-				struct pt_regs __regs);
-asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
-				   unsigned long r6, unsigned long r7,
-				   struct pt_regs __regs);
-
-static inline void set_bl_bit(void)
-{
-	unsigned long __dummy0, __dummy1;
-
-	__asm__ __volatile__ (
-		"stc	sr, %0\n\t"
-		"or	%2, %0\n\t"
-		"and	%3, %0\n\t"
-		"ldc	%0, sr\n\t"
-		: "=&r" (__dummy0), "=r" (__dummy1)
-		: "r" (0x10000000), "r" (0xffffff0f)
-		: "memory"
-	);
-}
-
-static inline void clear_bl_bit(void)
-{
-	unsigned long __dummy0, __dummy1;
-
-	__asm__ __volatile__ (
-		"stc	sr, %0\n\t"
-		"and	%2, %0\n\t"
-		"ldc	%0, sr\n\t"
-		: "=&r" (__dummy0), "=r" (__dummy1)
-		: "1" (~0x10000000)
-		: "memory"
-	);
-}
-
-#endif /* __ASM_SH_SYSTEM_32_H */
diff --git a/arch/sh/include/asm/system_64.h b/arch/sh/include/asm/system_64.h
deleted file mode 100644
index 8593bc8d..0000000
--- a/arch/sh/include/asm/system_64.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef __ASM_SH_SYSTEM_64_H
-#define __ASM_SH_SYSTEM_64_H
-
-/*
- * include/asm-sh/system_64.h
- *
- * Copyright (C) 2000, 2001  Paolo Alberelli
- * Copyright (C) 2003  Paul Mundt
- * Copyright (C) 2004  Richard Curnow
- *
- * 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 <cpu/registers.h>
-#include <asm/processor.h>
-
-/*
- *	switch_to() should switch tasks to task nr n, first
- */
-struct thread_struct;
-struct task_struct *sh64_switch_to(struct task_struct *prev,
-				   struct thread_struct *prev_thread,
-				   struct task_struct *next,
-				   struct thread_struct *next_thread);
-
-#define switch_to(prev,next,last)				\
-do {								\
-	if (last_task_used_math != next) {			\
-		struct pt_regs *regs = next->thread.uregs;	\
-		if (regs) regs->sr |= SR_FD;			\
-	}							\
-	last = sh64_switch_to(prev, &prev->thread, next,	\
-			      &next->thread);			\
-} while (0)
-
-#define __icbi(addr)	__asm__ __volatile__ ( "icbi %0, 0\n\t" : : "r" (addr))
-#define __ocbp(addr)	__asm__ __volatile__ ( "ocbp %0, 0\n\t" : : "r" (addr))
-#define __ocbi(addr)	__asm__ __volatile__ ( "ocbi %0, 0\n\t" : : "r" (addr))
-#define __ocbwb(addr)	__asm__ __volatile__ ( "ocbwb %0, 0\n\t" : : "r" (addr))
-
-static inline reg_size_t register_align(void *val)
-{
-	return (unsigned long long)(signed long long)(signed long)val;
-}
-
-extern void phys_stext(void);
-
-static inline void trigger_address_error(void)
-{
-	phys_stext();
-}
-
-#define SR_BL_LL	0x0000000010000000LL
-
-static inline void set_bl_bit(void)
-{
-	unsigned long long __dummy0, __dummy1 = SR_BL_LL;
-
-	__asm__ __volatile__("getcon	" __SR ", %0\n\t"
-			     "or	%0, %1, %0\n\t"
-			     "putcon	%0, " __SR "\n\t"
-			     : "=&r" (__dummy0)
-			     : "r" (__dummy1));
-
-}
-
-static inline void clear_bl_bit(void)
-{
-	unsigned long long __dummy0, __dummy1 = ~SR_BL_LL;
-
-	__asm__ __volatile__("getcon	" __SR ", %0\n\t"
-			     "and	%0, %1, %0\n\t"
-			     "putcon	%0, " __SR "\n\t"
-			     : "=&r" (__dummy0)
-			     : "r" (__dummy1));
-}
-
-#endif /* __ASM_SH_SYSTEM_64_H */
diff --git a/arch/sh/include/asm/traps.h b/arch/sh/include/asm/traps.h
new file mode 100644
index 0000000..afd9df8
--- /dev/null
+++ b/arch/sh/include/asm/traps.h
@@ -0,0 +1,21 @@
+#ifndef __ASM_SH_TRAPS_H
+#define __ASM_SH_TRAPS_H
+
+#include <linux/compiler.h>
+
+#ifdef CONFIG_SUPERH32
+# include "traps_32.h"
+#else
+# include "traps_64.h"
+#endif
+
+BUILD_TRAP_HANDLER(address_error);
+BUILD_TRAP_HANDLER(debug);
+BUILD_TRAP_HANDLER(bug);
+BUILD_TRAP_HANDLER(breakpoint);
+BUILD_TRAP_HANDLER(singlestep);
+BUILD_TRAP_HANDLER(fpu_error);
+BUILD_TRAP_HANDLER(fpu_state_restore);
+BUILD_TRAP_HANDLER(nmi);
+
+#endif /* __ASM_SH_TRAPS_H */
diff --git a/arch/sh/include/asm/traps_32.h b/arch/sh/include/asm/traps_32.h
new file mode 100644
index 0000000..cfd55ff
--- /dev/null
+++ b/arch/sh/include/asm/traps_32.h
@@ -0,0 +1,68 @@
+#ifndef __ASM_SH_TRAPS_32_H
+#define __ASM_SH_TRAPS_32_H
+
+#include <linux/types.h>
+#include <asm/mmu.h>
+
+#ifdef CONFIG_CPU_HAS_SR_RB
+#define lookup_exception_vector()	\
+({					\
+	unsigned long _vec;		\
+					\
+	__asm__ __volatile__ (		\
+		"stc r2_bank, %0\n\t"	\
+		: "=r" (_vec)		\
+	);				\
+					\
+	_vec;				\
+})
+#else
+#define lookup_exception_vector()	\
+({					\
+	unsigned long _vec;		\
+	__asm__ __volatile__ (		\
+		"mov r4, %0\n\t"	\
+		: "=r" (_vec)		\
+	);				\
+					\
+	_vec;				\
+})
+#endif
+
+static inline void trigger_address_error(void)
+{
+	__asm__ __volatile__ (
+		"ldc %0, sr\n\t"
+		"mov.l @%1, %0"
+		:
+		: "r" (0x10000000), "r" (0x80000001)
+	);
+}
+
+asmlinkage void do_address_error(struct pt_regs *regs,
+				 unsigned long writeaccess,
+				 unsigned long address);
+asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
+				unsigned long r6, unsigned long r7,
+				struct pt_regs __regs);
+asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
+				unsigned long r6, unsigned long r7,
+				struct pt_regs __regs);
+asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
+				unsigned long r6, unsigned long r7,
+				struct pt_regs __regs);
+asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
+				   unsigned long r6, unsigned long r7,
+				   struct pt_regs __regs);
+
+#define BUILD_TRAP_HANDLER(name)					\
+asmlinkage void name##_trap_handler(unsigned long r4, unsigned long r5,	\
+				    unsigned long r6, unsigned long r7,	\
+				    struct pt_regs __regs)
+
+#define TRAP_HANDLER_DECL				\
+	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);	\
+	unsigned int vec = regs->tra;			\
+	(void)vec;
+
+#endif /* __ASM_SH_TRAPS_32_H */
diff --git a/arch/sh/include/asm/traps_64.h b/arch/sh/include/asm/traps_64.h
new file mode 100644
index 0000000..c52d7f9
--- /dev/null
+++ b/arch/sh/include/asm/traps_64.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2000, 2001  Paolo Alberelli
+ * Copyright (C) 2003  Paul Mundt
+ * Copyright (C) 2004  Richard Curnow
+ *
+ * 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.
+ */
+#ifndef __ASM_SH_TRAPS_64_H
+#define __ASM_SH_TRAPS_64_H
+
+extern void phys_stext(void);
+
+static inline void trigger_address_error(void)
+{
+	phys_stext();
+}
+
+#define BUILD_TRAP_HANDLER(name)	\
+asmlinkage void name##_trap_handler(unsigned int vec, struct pt_regs *regs)
+#define TRAP_HANDLER_DECL
+
+#endif /* __ASM_SH_TRAPS_64_H */
diff --git a/arch/sh/include/asm/uaccess.h b/arch/sh/include/asm/uaccess.h
index 075848f..050f221 100644
--- a/arch/sh/include/asm/uaccess.h
+++ b/arch/sh/include/asm/uaccess.h
@@ -254,5 +254,19 @@
 unsigned long search_exception_table(unsigned long addr);
 const struct exception_table_entry *search_exception_tables(unsigned long addr);
 
+extern void *set_exception_table_vec(unsigned int vec, void *handler);
+
+static inline void *set_exception_table_evt(unsigned int evt, void *handler)
+{
+	return set_exception_table_vec(evt >> 5, handler);
+}
+
+struct mem_access {
+	unsigned long (*from)(void *dst, const void __user *src, unsigned long cnt);
+	unsigned long (*to)(void __user *dst, const void *src, unsigned long cnt);
+};
+
+int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
+			    struct mem_access *ma, int, unsigned long address);
 
 #endif /* __ASM_SH_UACCESS_H */
diff --git a/arch/sh/include/asm/unistd.h b/arch/sh/include/asm/unistd.h
index 65be656..a42a561 100644
--- a/arch/sh/include/asm/unistd.h
+++ b/arch/sh/include/asm/unistd.h
@@ -1,9 +1,46 @@
 #ifdef __KERNEL__
 # ifdef CONFIG_SUPERH32
+
 #  include "unistd_32.h"
+#  define __ARCH_WANT_SYS_RT_SIGSUSPEND
+
 # else
 #  include "unistd_64.h"
 # endif
+
+# define __ARCH_WANT_IPC_PARSE_VERSION
+# define __ARCH_WANT_OLD_READDIR
+# define __ARCH_WANT_OLD_STAT
+# define __ARCH_WANT_STAT64
+# define __ARCH_WANT_SYS_ALARM
+# define __ARCH_WANT_SYS_GETHOSTNAME
+# define __ARCH_WANT_SYS_IPC
+# define __ARCH_WANT_SYS_PAUSE
+# define __ARCH_WANT_SYS_SGETMASK
+# define __ARCH_WANT_SYS_SIGNAL
+# define __ARCH_WANT_SYS_TIME
+# define __ARCH_WANT_SYS_UTIME
+# define __ARCH_WANT_SYS_WAITPID
+# define __ARCH_WANT_SYS_SOCKETCALL
+# define __ARCH_WANT_SYS_FADVISE64
+# define __ARCH_WANT_SYS_GETPGRP
+# define __ARCH_WANT_SYS_LLSEEK
+# define __ARCH_WANT_SYS_NICE
+# define __ARCH_WANT_SYS_OLD_GETRLIMIT
+# define __ARCH_WANT_SYS_OLD_UNAME
+# define __ARCH_WANT_SYS_OLDUMOUNT
+# define __ARCH_WANT_SYS_SIGPENDING
+# define __ARCH_WANT_SYS_SIGPROCMASK
+# define __ARCH_WANT_SYS_RT_SIGACTION
+
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+# define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
+
 #else
 # ifdef __SH5__
 #  include "unistd_64.h"
diff --git a/arch/sh/include/asm/unistd_32.h b/arch/sh/include/asm/unistd_32.h
index 152b862..72fd1e0 100644
--- a/arch/sh/include/asm/unistd_32.h
+++ b/arch/sh/include/asm/unistd_32.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_SH_UNISTD_H
-#define __ASM_SH_UNISTD_H
+#ifndef __ASM_SH_UNISTD_32_H
+#define __ASM_SH_UNISTD_32_H
 
 /*
  * Copyright (C) 1999  Niibe Yutaka
@@ -26,7 +26,7 @@
 #define __NR_mknod		 14
 #define __NR_chmod		 15
 #define __NR_lchown		 16
-#define __NR_break		 17
+				 /* 17 was sys_break */
 #define __NR_oldstat		 18
 #define __NR_lseek		 19
 #define __NR_getpid		 20
@@ -40,11 +40,11 @@
 #define __NR_oldfstat		 28
 #define __NR_pause		 29
 #define __NR_utime		 30
-#define __NR_stty		 31
-#define __NR_gtty		 32
+				 /* 31 was sys_stty */
+				 /* 32 was sys_gtty */
 #define __NR_access		 33
 #define __NR_nice		 34
-#define __NR_ftime		 35
+				 /* 35 was sys_ftime */
 #define __NR_sync		 36
 #define __NR_kill		 37
 #define __NR_rename		 38
@@ -53,7 +53,7 @@
 #define __NR_dup		 41
 #define __NR_pipe		 42
 #define __NR_times		 43
-#define __NR_prof		 44
+				 /* 44 was sys_prof */
 #define __NR_brk		 45
 #define __NR_setgid		 46
 #define __NR_getgid		 47
@@ -62,13 +62,13 @@
 #define __NR_getegid		 50
 #define __NR_acct		 51
 #define __NR_umount2		 52
-#define __NR_lock		 53
+				 /* 53 was sys_lock */
 #define __NR_ioctl		 54
 #define __NR_fcntl		 55
-#define __NR_mpx		 56
+				 /* 56 was sys_mpx */
 #define __NR_setpgid		 57
-#define __NR_ulimit		 58
-#define __NR_oldolduname	 59
+				 /* 58 was sys_ulimit */
+				 /* 59 was sys_olduname */
 #define __NR_umask		 60
 #define __NR_chroot		 61
 #define __NR_ustat		 62
@@ -91,7 +91,7 @@
 #define __NR_settimeofday	 79
 #define __NR_getgroups		 80
 #define __NR_setgroups		 81
-#define __NR_select		 82
+				 /* 82 was sys_oldselect */
 #define __NR_symlink		 83
 #define __NR_oldlstat		 84
 #define __NR_readlink		 85
@@ -107,10 +107,10 @@
 #define __NR_fchown		 95
 #define __NR_getpriority	 96
 #define __NR_setpriority	 97
-#define __NR_profil		 98
+				 /* 98 was sys_profil */
 #define __NR_statfs		 99
 #define __NR_fstatfs		100
-#define __NR_ioperm		101
+				/* 101 was sys_ioperm */
 #define __NR_socketcall		102
 #define __NR_syslog		103
 #define __NR_setitimer		104
@@ -119,10 +119,10 @@
 #define __NR_lstat		107
 #define __NR_fstat		108
 #define __NR_olduname		109
-#define __NR_iopl		110
+				/* 110 was sys_iopl */
 #define __NR_vhangup		111
-#define __NR_idle		112
-#define __NR_vm86old		113
+				/* 112 was sys_idle */
+				/* 113 was sys_vm86old */
 #define __NR_wait4		114
 #define __NR_swapoff		115
 #define __NR_sysinfo		116
@@ -136,17 +136,17 @@
 #define __NR_adjtimex		124
 #define __NR_mprotect		125
 #define __NR_sigprocmask	126
-#define __NR_create_module	127
+				/* 127 was sys_create_module */
 #define __NR_init_module	128
 #define __NR_delete_module	129
-#define __NR_get_kernel_syms	130
+				/* 130 was sys_get_kernel_syms */
 #define __NR_quotactl		131
 #define __NR_getpgid		132
 #define __NR_fchdir		133
 #define __NR_bdflush		134
 #define __NR_sysfs		135
 #define __NR_personality	136
-#define __NR_afs_syscall	137 /* Syscall for Andrew File System */
+				/* 137 was sys_afs_syscall */
 #define __NR_setfsuid		138
 #define __NR_setfsgid		139
 #define __NR__llseek		140
@@ -175,8 +175,8 @@
 #define __NR_mremap		163
 #define __NR_setresuid		164
 #define __NR_getresuid		165
-#define __NR_vm86		166
-#define __NR_query_module	167
+				/* 166 was sys_vm86 */
+				/* 167 was sys_query_module */
 #define __NR_poll		168
 #define __NR_nfsservctl		169
 #define __NR_setresgid		170
@@ -197,8 +197,8 @@
 #define __NR_capset		185
 #define __NR_sigaltstack	186
 #define __NR_sendfile		187
-#define __NR_streams1		188	/* some people actually want it */
-#define __NR_streams2		189	/* some people actually want it */
+				/* 188 reserved for sys_getpmsg */
+				/* 189 reserved for sys_putpmsg */
 #define __NR_vfork		190
 #define __NR_ugetrlimit		191	/* SuS compliant getrlimit */
 #define __NR_mmap2		192
@@ -231,7 +231,8 @@
 #define __NR_madvise		219
 #define __NR_getdents64		220
 #define __NR_fcntl64		221
-/* 223 is unused */
+				/* 222 is reserved for tux */
+				/* 223 is unused */
 #define __NR_gettid		224
 #define __NR_readahead		225
 #define __NR_setxattr		226
@@ -251,15 +252,15 @@
 #define __NR_futex		240
 #define __NR_sched_setaffinity	241
 #define __NR_sched_getaffinity	242
-#define __NR_set_thread_area	243
-#define __NR_get_thread_area	244
+				/* 243 is reserved for set_thread_area */
+				/* 244 is reserved for get_thread_area */
 #define __NR_io_setup		245
 #define __NR_io_destroy		246
 #define __NR_io_getevents	247
 #define __NR_io_submit		248
 #define __NR_io_cancel		249
 #define __NR_fadvise64		250
-
+				/* 251 is unused */
 #define __NR_exit_group		252
 #define __NR_lookup_dcookie	253
 #define __NR_epoll_create	254
@@ -281,7 +282,7 @@
 #define __NR_tgkill		270
 #define __NR_utimes		271
 #define __NR_fadvise64_64	272
-#define __NR_vserver		273
+				/* 273 is reserved for vserver */
 #define __NR_mbind              274
 #define __NR_get_mempolicy      275
 #define __NR_set_mempolicy      276
@@ -301,7 +302,7 @@
 #define __NR_inotify_init	290
 #define __NR_inotify_add_watch	291
 #define __NR_inotify_rm_watch	292
-/* 293 is unused */
+				/* 293 is unused */
 #define __NR_migrate_pages	294
 #define __NR_openat		295
 #define __NR_mkdirat		296
@@ -380,43 +381,4 @@
 
 #define NR_syscalls 367
 
-#ifdef __KERNEL__
-
-#define __ARCH_WANT_IPC_PARSE_VERSION
-#define __ARCH_WANT_OLD_READDIR
-#define __ARCH_WANT_OLD_STAT
-#define __ARCH_WANT_STAT64
-#define __ARCH_WANT_SYS_ALARM
-#define __ARCH_WANT_SYS_GETHOSTNAME
-#define __ARCH_WANT_SYS_IPC
-#define __ARCH_WANT_SYS_PAUSE
-#define __ARCH_WANT_SYS_SGETMASK
-#define __ARCH_WANT_SYS_SIGNAL
-#define __ARCH_WANT_SYS_TIME
-#define __ARCH_WANT_SYS_UTIME
-#define __ARCH_WANT_SYS_WAITPID
-#define __ARCH_WANT_SYS_SOCKETCALL
-#define __ARCH_WANT_SYS_FADVISE64
-#define __ARCH_WANT_SYS_GETPGRP
-#define __ARCH_WANT_SYS_LLSEEK
-#define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_OLD_GETRLIMIT
-#define __ARCH_WANT_SYS_OLD_UNAME
-#define __ARCH_WANT_SYS_OLDUMOUNT
-#define __ARCH_WANT_SYS_SIGPENDING
-#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
-
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#ifndef cond_syscall
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-#endif
-
-#endif /* __KERNEL__ */
-#endif /* __ASM_SH_UNISTD_H */
+#endif /* __ASM_SH_UNISTD_32_H */
diff --git a/arch/sh/include/asm/unistd_64.h b/arch/sh/include/asm/unistd_64.h
index c330c23..a28edc3 100644
--- a/arch/sh/include/asm/unistd_64.h
+++ b/arch/sh/include/asm/unistd_64.h
@@ -31,7 +31,7 @@
 #define __NR_mknod		 14
 #define __NR_chmod		 15
 #define __NR_lchown		 16
-#define __NR_break		 17
+				 /* 17 was sys_break */
 #define __NR_oldstat		 18
 #define __NR_lseek		 19
 #define __NR_getpid		 20
@@ -45,11 +45,11 @@
 #define __NR_oldfstat		 28
 #define __NR_pause		 29
 #define __NR_utime		 30
-#define __NR_stty		 31
-#define __NR_gtty		 32
+				 /* 31 was sys_stty */
+				 /* 32 was sys_gtty */
 #define __NR_access		 33
 #define __NR_nice		 34
-#define __NR_ftime		 35
+				 /* 35 was sys_ftime */
 #define __NR_sync		 36
 #define __NR_kill		 37
 #define __NR_rename		 38
@@ -58,7 +58,7 @@
 #define __NR_dup		 41
 #define __NR_pipe		 42
 #define __NR_times		 43
-#define __NR_prof		 44
+				 /* 44 was sys_prof */
 #define __NR_brk		 45
 #define __NR_setgid		 46
 #define __NR_getgid		 47
@@ -67,13 +67,13 @@
 #define __NR_getegid		 50
 #define __NR_acct		 51
 #define __NR_umount2		 52
-#define __NR_lock		 53
+				 /* 53 was sys_lock */
 #define __NR_ioctl		 54
 #define __NR_fcntl		 55
-#define __NR_mpx		 56
+				 /* 56 was sys_mpx */
 #define __NR_setpgid		 57
-#define __NR_ulimit		 58
-#define __NR_oldolduname	 59
+				 /* 58 was sys_ulimit */
+				 /* 59 was sys_olduname */
 #define __NR_umask		 60
 #define __NR_chroot		 61
 #define __NR_ustat		 62
@@ -96,7 +96,7 @@
 #define __NR_settimeofday	 79
 #define __NR_getgroups		 80
 #define __NR_setgroups		 81
-#define __NR_select		 82
+				 /* 82 was sys_select */
 #define __NR_symlink		 83
 #define __NR_oldlstat		 84
 #define __NR_readlink		 85
@@ -112,10 +112,10 @@
 #define __NR_fchown		 95
 #define __NR_getpriority	 96
 #define __NR_setpriority	 97
-#define __NR_profil		 98
+				 /* 98 was sys_profil */
 #define __NR_statfs		 99
 #define __NR_fstatfs		100
-#define __NR_ioperm		101
+				/* 101 was sys_ioperm */
 #define __NR_socketcall		102	/* old implementation of socket systemcall */
 #define __NR_syslog		103
 #define __NR_setitimer		104
@@ -124,10 +124,10 @@
 #define __NR_lstat		107
 #define __NR_fstat		108
 #define __NR_olduname		109
-#define __NR_iopl		110
+				/* 110 was sys_iopl */
 #define __NR_vhangup		111
-#define __NR_idle		112
-#define __NR_vm86old		113
+				/* 112 was sys_idle */
+				/* 113 was sys_vm86old */
 #define __NR_wait4		114
 #define __NR_swapoff		115
 #define __NR_sysinfo		116
@@ -141,17 +141,17 @@
 #define __NR_adjtimex		124
 #define __NR_mprotect		125
 #define __NR_sigprocmask	126
-#define __NR_create_module	127
+				/* 127 was sys_create_module */
 #define __NR_init_module	128
 #define __NR_delete_module	129
-#define __NR_get_kernel_syms	130
+				/* 130 was sys_get_kernel_syms */
 #define __NR_quotactl		131
 #define __NR_getpgid		132
 #define __NR_fchdir		133
 #define __NR_bdflush		134
 #define __NR_sysfs		135
 #define __NR_personality	136
-#define __NR_afs_syscall	137 /* Syscall for Andrew File System */
+				/* 137 was sys_afs_syscall */
 #define __NR_setfsuid		138
 #define __NR_setfsgid		139
 #define __NR__llseek		140
@@ -180,8 +180,8 @@
 #define __NR_mremap		163
 #define __NR_setresuid		164
 #define __NR_getresuid		165
-#define __NR_vm86		166
-#define __NR_query_module	167
+				/* 166 was sys_vm86 */
+				/* 167 was sys_query_module */
 #define __NR_poll		168
 #define __NR_nfsservctl		169
 #define __NR_setresgid		170
@@ -202,8 +202,8 @@
 #define __NR_capset		185
 #define __NR_sigaltstack	186
 #define __NR_sendfile		187
-#define __NR_streams1		188	/* some people actually want it */
-#define __NR_streams2		189	/* some people actually want it */
+				/* 188 reserved for getpmsg */
+				/* 189 reserved for putpmsg */
 #define __NR_vfork		190
 #define __NR_ugetrlimit		191	/* SuS compliant getrlimit */
 #define __NR_mmap2		192
@@ -262,16 +262,15 @@
 #define __NR_msgrcv		241
 #define __NR_msgget		242
 #define __NR_msgctl		243
-#if 0
-#define __NR_shmatcall		244
-#endif
+#define __NR_shmat		244
 #define __NR_shmdt		245
 #define __NR_shmget		246
 #define __NR_shmctl		247
 
 #define __NR_getdents64		248
 #define __NR_fcntl64		249
-/* 223 is unused */
+				/* 250 is reserved for tux */
+				/* 251 is unused */
 #define __NR_gettid		252
 #define __NR_readahead		253
 #define __NR_setxattr		254
@@ -291,14 +290,15 @@
 #define __NR_futex		268
 #define __NR_sched_setaffinity	269
 #define __NR_sched_getaffinity	270
-#define __NR_set_thread_area	271
-#define __NR_get_thread_area	272
+				/* 271 is reserved for set_thread_area */
+				/* 272 is reserved for get_thread_area */
 #define __NR_io_setup		273
 #define __NR_io_destroy		274
 #define __NR_io_getevents	275
 #define __NR_io_submit		276
 #define __NR_io_cancel		277
 #define __NR_fadvise64		278
+				/* 279 is unused */
 #define __NR_exit_group		280
 
 #define __NR_lookup_dcookie	281
@@ -321,17 +321,17 @@
 #define __NR_tgkill		298
 #define __NR_utimes		299
 #define __NR_fadvise64_64	300
-#define __NR_vserver		301
-#define __NR_mbind              302
-#define __NR_get_mempolicy      303
-#define __NR_set_mempolicy      304
+				/* 301 is reserved for vserver */
+				/* 302 is reserved for mbind */
+				/* 303 is reserved for get_mempolicy */
+				/* 304 is reserved for set_mempolicy */
 #define __NR_mq_open            305
 #define __NR_mq_unlink          (__NR_mq_open+1)
 #define __NR_mq_timedsend       (__NR_mq_open+2)
 #define __NR_mq_timedreceive    (__NR_mq_open+3)
 #define __NR_mq_notify          (__NR_mq_open+4)
 #define __NR_mq_getsetattr      (__NR_mq_open+5)
-#define __NR_kexec_load		311
+				/* 311 is reserved for kexec */
 #define __NR_waitid		312
 #define __NR_add_key		313
 #define __NR_request_key	314
@@ -341,7 +341,7 @@
 #define __NR_inotify_init	318
 #define __NR_inotify_add_watch	319
 #define __NR_inotify_rm_watch	320
-/* 321 is unused */
+				/* 321 is unused */
 #define __NR_migrate_pages	322
 #define __NR_openat		323
 #define __NR_mkdirat		324
@@ -399,44 +399,6 @@
 #define __NR_process_vm_readv	376
 #define __NR_process_vm_writev	377
 
-#ifdef __KERNEL__
-
 #define NR_syscalls 378
 
-#define __ARCH_WANT_IPC_PARSE_VERSION
-#define __ARCH_WANT_OLD_READDIR
-#define __ARCH_WANT_OLD_STAT
-#define __ARCH_WANT_STAT64
-#define __ARCH_WANT_SYS_ALARM
-#define __ARCH_WANT_SYS_GETHOSTNAME
-#define __ARCH_WANT_SYS_IPC
-#define __ARCH_WANT_SYS_PAUSE
-#define __ARCH_WANT_SYS_SGETMASK
-#define __ARCH_WANT_SYS_SIGNAL
-#define __ARCH_WANT_SYS_TIME
-#define __ARCH_WANT_SYS_UTIME
-#define __ARCH_WANT_SYS_WAITPID
-#define __ARCH_WANT_SYS_SOCKETCALL
-#define __ARCH_WANT_SYS_FADVISE64
-#define __ARCH_WANT_SYS_GETPGRP
-#define __ARCH_WANT_SYS_LLSEEK
-#define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_OLD_GETRLIMIT
-#define __ARCH_WANT_SYS_OLD_UNAME
-#define __ARCH_WANT_SYS_OLDUMOUNT
-#define __ARCH_WANT_SYS_SIGPENDING
-#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGACTION
-
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#ifndef cond_syscall
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-#endif
-
-#endif /* __KERNEL__ */
 #endif /* __ASM_SH_UNISTD_64_H */
diff --git a/arch/sh/include/cpu-sh4/cpu/dma-register.h b/arch/sh/include/cpu-sh4/cpu/dma-register.h
index 18fa80a..02788b6 100644
--- a/arch/sh/include/cpu-sh4/cpu/dma-register.h
+++ b/arch/sh/include/cpu-sh4/cpu/dma-register.h
@@ -16,45 +16,29 @@
 
 #define DMAOR_INIT	DMAOR_DME
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7343) || \
-	defined(CONFIG_CPU_SUBTYPE_SH7730)
+#if defined(CONFIG_CPU_SUBTYPE_SH7343)
 #define CHCR_TS_LOW_MASK	0x00000018
 #define CHCR_TS_LOW_SHIFT	3
 #define CHCR_TS_HIGH_MASK	0
 #define CHCR_TS_HIGH_SHIFT	0
 #elif defined(CONFIG_CPU_SUBTYPE_SH7722) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7723) || \
 	defined(CONFIG_CPU_SUBTYPE_SH7724) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7730) || \
 	defined(CONFIG_CPU_SUBTYPE_SH7786)
 #define CHCR_TS_LOW_MASK	0x00000018
 #define CHCR_TS_LOW_SHIFT	3
 #define CHCR_TS_HIGH_MASK	0x00300000
 #define CHCR_TS_HIGH_SHIFT	(20 - 2)	/* 2 bits for shifted low TS */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \
-	defined(CONFIG_CPU_SUBTYPE_SH7764)
-#define CHCR_TS_LOW_MASK	0x00000018
-#define CHCR_TS_LOW_SHIFT	3
-#define CHCR_TS_HIGH_MASK	0
-#define CHCR_TS_HIGH_SHIFT	0
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
-#define CHCR_TS_LOW_MASK	0x00000018
-#define CHCR_TS_LOW_SHIFT	3
-#define CHCR_TS_HIGH_MASK	0
-#define CHCR_TS_HIGH_SHIFT	0
-#elif defined(CONFIG_CPU_SUBTYPE_SH7757)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7757) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7764) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7785)
 #define CHCR_TS_LOW_MASK	0x00000018
 #define CHCR_TS_LOW_SHIFT	3
 #define CHCR_TS_HIGH_MASK	0x00100000
 #define CHCR_TS_HIGH_SHIFT	(20 - 2)	/* 2 bits for shifted low TS */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
-#define CHCR_TS_LOW_MASK	0x00000018
-#define CHCR_TS_LOW_SHIFT	3
-#define CHCR_TS_HIGH_MASK	0
-#define CHCR_TS_HIGH_SHIFT	0
-#else /* SH7785 */
-#define CHCR_TS_LOW_MASK	0x00000018
-#define CHCR_TS_LOW_SHIFT	3
-#define CHCR_TS_HIGH_MASK	0
-#define CHCR_TS_HIGH_SHIFT	0
 #endif
 
 /* Transmit sizes and respective CHCR register values */
diff --git a/arch/sh/include/mach-common/mach/mangle-port.h b/arch/sh/include/mach-common/mach/mangle-port.h
new file mode 100644
index 0000000..4ca1769
--- /dev/null
+++ b/arch/sh/include/mach-common/mach/mangle-port.h
@@ -0,0 +1,49 @@
+/*
+ * SH version cribbed from the MIPS copy:
+ *
+ * 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.
+ *
+ * Copyright (C) 2003, 2004 Ralf Baechle
+ */
+#ifndef __MACH_COMMON_MANGLE_PORT_H
+#define __MACH_COMMON_MANGLE_PORT_H
+
+/*
+ * Sane hardware offers swapping of PCI/ISA I/O space accesses in hardware;
+ * less sane hardware forces software to fiddle with this...
+ *
+ * Regardless, if the host bus endianness mismatches that of PCI/ISA, then
+ * you can't have the numerical value of data and byte addresses within
+ * multibyte quantities both preserved at the same time.  Hence two
+ * variations of functions: non-prefixed ones that preserve the value
+ * and prefixed ones that preserve byte addresses.  The latters are
+ * typically used for moving raw data between a peripheral and memory (cf.
+ * string I/O functions), hence the "__mem_" prefix.
+ */
+#if defined(CONFIG_SWAP_IO_SPACE)
+
+# define ioswabb(x)		(x)
+# define __mem_ioswabb(x)	(x)
+# define ioswabw(x)		le16_to_cpu(x)
+# define __mem_ioswabw(x)	(x)
+# define ioswabl(x)		le32_to_cpu(x)
+# define __mem_ioswabl(x)	(x)
+# define ioswabq(x)		le64_to_cpu(x)
+# define __mem_ioswabq(x)	(x)
+
+#else
+
+# define ioswabb(x)		(x)
+# define __mem_ioswabb(x)	(x)
+# define ioswabw(x)		(x)
+# define __mem_ioswabw(x)	cpu_to_le16(x)
+# define ioswabl(x)		(x)
+# define __mem_ioswabl(x)	cpu_to_le32(x)
+# define ioswabq(x)		(x)
+# define __mem_ioswabq(x)	cpu_to_le32(x)
+
+#endif
+
+#endif /* __MACH_COMMON_MANGLE_PORT_H */
diff --git a/arch/sh/include/mach-kfr2r09/mach/kfr2r09.h b/arch/sh/include/mach-kfr2r09/mach/kfr2r09.h
index 07e635b..ba3d93d 100644
--- a/arch/sh/include/mach-kfr2r09/mach/kfr2r09.h
+++ b/arch/sh/include/mach-kfr2r09/mach/kfr2r09.h
@@ -4,21 +4,21 @@
 #include <video/sh_mobile_lcdc.h>
 
 #if defined(CONFIG_FB_SH_MOBILE_LCDC) || defined(CONFIG_FB_SH_MOBILE_LCDC_MODULE)
-void kfr2r09_lcd_on(void *board_data, struct fb_info *info);
-void kfr2r09_lcd_off(void *board_data);
-int kfr2r09_lcd_setup(void *board_data, void *sys_ops_handle,
+void kfr2r09_lcd_on(void);
+void kfr2r09_lcd_off(void);
+int kfr2r09_lcd_setup(void *sys_ops_handle,
 		      struct sh_mobile_lcdc_sys_bus_ops *sys_ops);
-void kfr2r09_lcd_start(void *board_data, void *sys_ops_handle,
+void kfr2r09_lcd_start(void *sys_ops_handle,
 		       struct sh_mobile_lcdc_sys_bus_ops *sys_ops);
 #else
-static void kfr2r09_lcd_on(void *board_data) {}
-static void kfr2r09_lcd_off(void *board_data) {}
-static int kfr2r09_lcd_setup(void *board_data, void *sys_ops_handle,
+static void kfr2r09_lcd_on(void) {}
+static void kfr2r09_lcd_off(void) {}
+static int kfr2r09_lcd_setup(void *sys_ops_handle,
 				struct sh_mobile_lcdc_sys_bus_ops *sys_ops)
 {
 	return -ENODEV;
 }
-static void kfr2r09_lcd_start(void *board_data, void *sys_ops_handle,
+static void kfr2r09_lcd_start(void *sys_ops_handle,
 				struct sh_mobile_lcdc_sys_bus_ops *sys_ops)
 {
 }
diff --git a/arch/sh/include/mach-migor/mach/migor.h b/arch/sh/include/mach-migor/mach/migor.h
index 42fccf9..7de7bb7 100644
--- a/arch/sh/include/mach-migor/mach/migor.h
+++ b/arch/sh/include/mach-migor/mach/migor.h
@@ -9,7 +9,7 @@
 
 #include <video/sh_mobile_lcdc.h>
 
-int migor_lcd_qvga_setup(void *board_data, void *sys_ops_handle,
+int migor_lcd_qvga_setup(void *sys_ops_handle,
 			 struct sh_mobile_lcdc_sys_bus_ops *sys_ops);
 
 #endif /* __ASM_SH_MIGOR_H */
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index fac742e..61a07da 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -18,13 +18,13 @@
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <asm/cacheflush.h>
 #include <asm/cache.h>
 #include <asm/elf.h>
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/sh_bios.h>
+#include <asm/setup.h>
 
 #ifdef CONFIG_SH_FPU
 #define cpu_has_fpu	1
diff --git a/arch/sh/kernel/cpu/irq/imask.c b/arch/sh/kernel/cpu/irq/imask.c
index 39b6a24..e7f1745 100644
--- a/arch/sh/kernel/cpu/irq/imask.c
+++ b/arch/sh/kernel/cpu/irq/imask.c
@@ -19,7 +19,6 @@
 #include <linux/cache.h>
 #include <linux/irq.h>
 #include <linux/bitmap.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 
 /* Bitmap of IRQ masked */
diff --git a/arch/sh/kernel/cpu/sh2/clock-sh7619.c b/arch/sh/kernel/cpu/sh2/clock-sh7619.c
index 5b7f12e..e80252a 100644
--- a/arch/sh/kernel/cpu/sh2/clock-sh7619.c
+++ b/arch/sh/kernel/cpu/sh2/clock-sh7619.c
@@ -28,7 +28,7 @@
 	clk->rate *= pll2_mult * pll1rate[(__raw_readw(FREQCR) >> 8) & 7];
 }
 
-static struct clk_ops sh7619_master_clk_ops = {
+static struct sh_clk_ops sh7619_master_clk_ops = {
 	.init		= master_clk_init,
 };
 
@@ -38,7 +38,7 @@
 	return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7619_module_clk_ops = {
+static struct sh_clk_ops sh7619_module_clk_ops = {
 	.recalc		= module_clk_recalc,
 };
 
@@ -47,22 +47,22 @@
 	return clk->parent->rate / pll1rate[(__raw_readw(FREQCR) >> 8) & 7];
 }
 
-static struct clk_ops sh7619_bus_clk_ops = {
+static struct sh_clk_ops sh7619_bus_clk_ops = {
 	.recalc		= bus_clk_recalc,
 };
 
-static struct clk_ops sh7619_cpu_clk_ops = {
+static struct sh_clk_ops sh7619_cpu_clk_ops = {
 	.recalc		= followparent_recalc,
 };
 
-static struct clk_ops *sh7619_clk_ops[] = {
+static struct sh_clk_ops *sh7619_clk_ops[] = {
 	&sh7619_master_clk_ops,
 	&sh7619_module_clk_ops,
 	&sh7619_bus_clk_ops,
 	&sh7619_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
 	if (test_mode_pin(MODE_PIN2 | MODE_PIN0) ||
 	    test_mode_pin(MODE_PIN2 | MODE_PIN1))
diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7201.c b/arch/sh/kernel/cpu/sh2a/clock-sh7201.c
index 1174e2d..532a36c 100644
--- a/arch/sh/kernel/cpu/sh2a/clock-sh7201.c
+++ b/arch/sh/kernel/cpu/sh2a/clock-sh7201.c
@@ -30,7 +30,7 @@
 	       pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007];
 }
 
-static struct clk_ops sh7201_master_clk_ops = {
+static struct sh_clk_ops sh7201_master_clk_ops = {
 	.init		= master_clk_init,
 };
 
@@ -40,7 +40,7 @@
 	return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7201_module_clk_ops = {
+static struct sh_clk_ops sh7201_module_clk_ops = {
 	.recalc		= module_clk_recalc,
 };
 
@@ -50,7 +50,7 @@
 	return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7201_bus_clk_ops = {
+static struct sh_clk_ops sh7201_bus_clk_ops = {
 	.recalc		= bus_clk_recalc,
 };
 
@@ -60,18 +60,18 @@
 	return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh7201_cpu_clk_ops = {
+static struct sh_clk_ops sh7201_cpu_clk_ops = {
 	.recalc		= cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7201_clk_ops[] = {
+static struct sh_clk_ops *sh7201_clk_ops[] = {
 	&sh7201_master_clk_ops,
 	&sh7201_module_clk_ops,
 	&sh7201_bus_clk_ops,
 	&sh7201_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
 	if (test_mode_pin(MODE_PIN1 | MODE_PIN0))
 		pll2_mult = 1;
diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7203.c b/arch/sh/kernel/cpu/sh2a/clock-sh7203.c
index 95a008e..529f719 100644
--- a/arch/sh/kernel/cpu/sh2a/clock-sh7203.c
+++ b/arch/sh/kernel/cpu/sh2a/clock-sh7203.c
@@ -32,7 +32,7 @@
 	clk->rate *= pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0003] * pll2_mult;
 }
 
-static struct clk_ops sh7203_master_clk_ops = {
+static struct sh_clk_ops sh7203_master_clk_ops = {
 	.init		= master_clk_init,
 };
 
@@ -42,7 +42,7 @@
 	return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7203_module_clk_ops = {
+static struct sh_clk_ops sh7203_module_clk_ops = {
 	.recalc		= module_clk_recalc,
 };
 
@@ -52,22 +52,22 @@
 	return clk->parent->rate / pfc_divisors[idx-2];
 }
 
-static struct clk_ops sh7203_bus_clk_ops = {
+static struct sh_clk_ops sh7203_bus_clk_ops = {
 	.recalc		= bus_clk_recalc,
 };
 
-static struct clk_ops sh7203_cpu_clk_ops = {
+static struct sh_clk_ops sh7203_cpu_clk_ops = {
 	.recalc		= followparent_recalc,
 };
 
-static struct clk_ops *sh7203_clk_ops[] = {
+static struct sh_clk_ops *sh7203_clk_ops[] = {
 	&sh7203_master_clk_ops,
 	&sh7203_module_clk_ops,
 	&sh7203_bus_clk_ops,
 	&sh7203_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
 	if (test_mode_pin(MODE_PIN1))
 		pll2_mult = 4;
diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7206.c b/arch/sh/kernel/cpu/sh2a/clock-sh7206.c
index 3c314d7..1777898 100644
--- a/arch/sh/kernel/cpu/sh2a/clock-sh7206.c
+++ b/arch/sh/kernel/cpu/sh2a/clock-sh7206.c
@@ -29,7 +29,7 @@
 	clk->rate *= pll2_mult * pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007];
 }
 
-static struct clk_ops sh7206_master_clk_ops = {
+static struct sh_clk_ops sh7206_master_clk_ops = {
 	.init		= master_clk_init,
 };
 
@@ -39,7 +39,7 @@
 	return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7206_module_clk_ops = {
+static struct sh_clk_ops sh7206_module_clk_ops = {
 	.recalc		= module_clk_recalc,
 };
 
@@ -48,7 +48,7 @@
 	return clk->parent->rate / pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007];
 }
 
-static struct clk_ops sh7206_bus_clk_ops = {
+static struct sh_clk_ops sh7206_bus_clk_ops = {
 	.recalc		= bus_clk_recalc,
 };
 
@@ -58,18 +58,18 @@
 	return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh7206_cpu_clk_ops = {
+static struct sh_clk_ops sh7206_cpu_clk_ops = {
 	.recalc		= cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7206_clk_ops[] = {
+static struct sh_clk_ops *sh7206_clk_ops[] = {
 	&sh7206_master_clk_ops,
 	&sh7206_module_clk_ops,
 	&sh7206_bus_clk_ops,
 	&sh7206_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
 	if (test_mode_pin(MODE_PIN2 | MODE_PIN1 | MODE_PIN0))
 		pll2_mult = 1;
diff --git a/arch/sh/kernel/cpu/sh2a/opcode_helper.c b/arch/sh/kernel/cpu/sh2a/opcode_helper.c
index 9704b79..72aa61c 100644
--- a/arch/sh/kernel/cpu/sh2a/opcode_helper.c
+++ b/arch/sh/kernel/cpu/sh2a/opcode_helper.c
@@ -10,7 +10,6 @@
  * for more details.
  */
 #include <linux/kernel.h>
-#include <asm/system.h>
 
 /*
  * Instructions on SH are generally fixed at 16-bits, however, SH-2A
diff --git a/arch/sh/kernel/cpu/sh3/clock-sh3.c b/arch/sh/kernel/cpu/sh3/clock-sh3.c
index b78384a..90faa44 100644
--- a/arch/sh/kernel/cpu/sh3/clock-sh3.c
+++ b/arch/sh/kernel/cpu/sh3/clock-sh3.c
@@ -34,7 +34,7 @@
 	clk->rate *= pfc_divisors[idx];
 }
 
-static struct clk_ops sh3_master_clk_ops = {
+static struct sh_clk_ops sh3_master_clk_ops = {
 	.init		= master_clk_init,
 };
 
@@ -46,7 +46,7 @@
 	return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh3_module_clk_ops = {
+static struct sh_clk_ops sh3_module_clk_ops = {
 	.recalc		= module_clk_recalc,
 };
 
@@ -58,7 +58,7 @@
 	return clk->parent->rate / stc_multipliers[idx];
 }
 
-static struct clk_ops sh3_bus_clk_ops = {
+static struct sh_clk_ops sh3_bus_clk_ops = {
 	.recalc		= bus_clk_recalc,
 };
 
@@ -70,18 +70,18 @@
 	return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh3_cpu_clk_ops = {
+static struct sh_clk_ops sh3_cpu_clk_ops = {
 	.recalc		= cpu_clk_recalc,
 };
 
-static struct clk_ops *sh3_clk_ops[] = {
+static struct sh_clk_ops *sh3_clk_ops[] = {
 	&sh3_master_clk_ops,
 	&sh3_module_clk_ops,
 	&sh3_bus_clk_ops,
 	&sh3_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
 	if (idx < ARRAY_SIZE(sh3_clk_ops))
 		*ops = sh3_clk_ops[idx];
diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7705.c b/arch/sh/kernel/cpu/sh3/clock-sh7705.c
index 0ecea14..a8da4a9 100644
--- a/arch/sh/kernel/cpu/sh3/clock-sh7705.c
+++ b/arch/sh/kernel/cpu/sh3/clock-sh7705.c
@@ -35,7 +35,7 @@
 	clk->rate *= pfc_divisors[__raw_readw(FRQCR) & 0x0003];
 }
 
-static struct clk_ops sh7705_master_clk_ops = {
+static struct sh_clk_ops sh7705_master_clk_ops = {
 	.init		= master_clk_init,
 };
 
@@ -45,7 +45,7 @@
 	return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7705_module_clk_ops = {
+static struct sh_clk_ops sh7705_module_clk_ops = {
 	.recalc		= module_clk_recalc,
 };
 
@@ -55,7 +55,7 @@
 	return clk->parent->rate / stc_multipliers[idx];
 }
 
-static struct clk_ops sh7705_bus_clk_ops = {
+static struct sh_clk_ops sh7705_bus_clk_ops = {
 	.recalc		= bus_clk_recalc,
 };
 
@@ -65,18 +65,18 @@
 	return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh7705_cpu_clk_ops = {
+static struct sh_clk_ops sh7705_cpu_clk_ops = {
 	.recalc		= cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7705_clk_ops[] = {
+static struct sh_clk_ops *sh7705_clk_ops[] = {
 	&sh7705_master_clk_ops,
 	&sh7705_module_clk_ops,
 	&sh7705_bus_clk_ops,
 	&sh7705_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
 	if (idx < ARRAY_SIZE(sh7705_clk_ops))
 		*ops = sh7705_clk_ops[idx];
diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7706.c b/arch/sh/kernel/cpu/sh3/clock-sh7706.c
index 6f9ff8b..a4088e5 100644
--- a/arch/sh/kernel/cpu/sh3/clock-sh7706.c
+++ b/arch/sh/kernel/cpu/sh3/clock-sh7706.c
@@ -30,7 +30,7 @@
 	clk->rate *= pfc_divisors[idx];
 }
 
-static struct clk_ops sh7706_master_clk_ops = {
+static struct sh_clk_ops sh7706_master_clk_ops = {
 	.init		= master_clk_init,
 };
 
@@ -42,7 +42,7 @@
 	return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7706_module_clk_ops = {
+static struct sh_clk_ops sh7706_module_clk_ops = {
 	.recalc		= module_clk_recalc,
 };
 
@@ -54,7 +54,7 @@
 	return clk->parent->rate / stc_multipliers[idx];
 }
 
-static struct clk_ops sh7706_bus_clk_ops = {
+static struct sh_clk_ops sh7706_bus_clk_ops = {
 	.recalc		= bus_clk_recalc,
 };
 
@@ -66,18 +66,18 @@
 	return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh7706_cpu_clk_ops = {
+static struct sh_clk_ops sh7706_cpu_clk_ops = {
 	.recalc		= cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7706_clk_ops[] = {
+static struct sh_clk_ops *sh7706_clk_ops[] = {
 	&sh7706_master_clk_ops,
 	&sh7706_module_clk_ops,
 	&sh7706_bus_clk_ops,
 	&sh7706_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
 	if (idx < ARRAY_SIZE(sh7706_clk_ops))
 		*ops = sh7706_clk_ops[idx];
diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7709.c b/arch/sh/kernel/cpu/sh3/clock-sh7709.c
index f302ba0..54a6d4b 100644
--- a/arch/sh/kernel/cpu/sh3/clock-sh7709.c
+++ b/arch/sh/kernel/cpu/sh3/clock-sh7709.c
@@ -30,7 +30,7 @@
 	clk->rate *= pfc_divisors[idx];
 }
 
-static struct clk_ops sh7709_master_clk_ops = {
+static struct sh_clk_ops sh7709_master_clk_ops = {
 	.init		= master_clk_init,
 };
 
@@ -42,7 +42,7 @@
 	return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7709_module_clk_ops = {
+static struct sh_clk_ops sh7709_module_clk_ops = {
 	.recalc		= module_clk_recalc,
 };
 
@@ -55,7 +55,7 @@
 	return clk->parent->rate * stc_multipliers[idx];
 }
 
-static struct clk_ops sh7709_bus_clk_ops = {
+static struct sh_clk_ops sh7709_bus_clk_ops = {
 	.recalc		= bus_clk_recalc,
 };
 
@@ -67,18 +67,18 @@
 	return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh7709_cpu_clk_ops = {
+static struct sh_clk_ops sh7709_cpu_clk_ops = {
 	.recalc		= cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7709_clk_ops[] = {
+static struct sh_clk_ops *sh7709_clk_ops[] = {
 	&sh7709_master_clk_ops,
 	&sh7709_module_clk_ops,
 	&sh7709_bus_clk_ops,
 	&sh7709_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
 	if (idx < ARRAY_SIZE(sh7709_clk_ops))
 		*ops = sh7709_clk_ops[idx];
diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7710.c b/arch/sh/kernel/cpu/sh3/clock-sh7710.c
index 29a87d8..ce601b2 100644
--- a/arch/sh/kernel/cpu/sh3/clock-sh7710.c
+++ b/arch/sh/kernel/cpu/sh3/clock-sh7710.c
@@ -29,7 +29,7 @@
 	clk->rate *= md_table[__raw_readw(FRQCR) & 0x0007];
 }
 
-static struct clk_ops sh7710_master_clk_ops = {
+static struct sh_clk_ops sh7710_master_clk_ops = {
 	.init		= master_clk_init,
 };
 
@@ -39,7 +39,7 @@
 	return clk->parent->rate / md_table[idx];
 }
 
-static struct clk_ops sh7710_module_clk_ops = {
+static struct sh_clk_ops sh7710_module_clk_ops = {
 	.recalc		= module_clk_recalc,
 };
 
@@ -49,7 +49,7 @@
 	return clk->parent->rate / md_table[idx];
 }
 
-static struct clk_ops sh7710_bus_clk_ops = {
+static struct sh_clk_ops sh7710_bus_clk_ops = {
 	.recalc		= bus_clk_recalc,
 };
 
@@ -59,18 +59,18 @@
 	return clk->parent->rate / md_table[idx];
 }
 
-static struct clk_ops sh7710_cpu_clk_ops = {
+static struct sh_clk_ops sh7710_cpu_clk_ops = {
 	.recalc		= cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7710_clk_ops[] = {
+static struct sh_clk_ops *sh7710_clk_ops[] = {
 	&sh7710_master_clk_ops,
 	&sh7710_module_clk_ops,
 	&sh7710_bus_clk_ops,
 	&sh7710_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
 	if (idx < ARRAY_SIZE(sh7710_clk_ops))
 		*ops = sh7710_clk_ops[idx];
diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7712.c b/arch/sh/kernel/cpu/sh3/clock-sh7712.c
index b0d0c52..21438a9 100644
--- a/arch/sh/kernel/cpu/sh3/clock-sh7712.c
+++ b/arch/sh/kernel/cpu/sh3/clock-sh7712.c
@@ -29,7 +29,7 @@
 	clk->rate *= multipliers[idx];
 }
 
-static struct clk_ops sh7712_master_clk_ops = {
+static struct sh_clk_ops sh7712_master_clk_ops = {
 	.init		= master_clk_init,
 };
 
@@ -41,7 +41,7 @@
 	return clk->parent->rate / divisors[idx];
 }
 
-static struct clk_ops sh7712_module_clk_ops = {
+static struct sh_clk_ops sh7712_module_clk_ops = {
 	.recalc		= module_clk_recalc,
 };
 
@@ -53,17 +53,17 @@
 	return clk->parent->rate / divisors[idx];
 }
 
-static struct clk_ops sh7712_cpu_clk_ops = {
+static struct sh_clk_ops sh7712_cpu_clk_ops = {
 	.recalc		= cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7712_clk_ops[] = {
+static struct sh_clk_ops *sh7712_clk_ops[] = {
 	&sh7712_master_clk_ops,
 	&sh7712_module_clk_ops,
 	&sh7712_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
 	if (idx < ARRAY_SIZE(sh7712_clk_ops))
 		*ops = sh7712_clk_ops[idx];
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
index f4e262a..4b5bab5 100644
--- a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
+++ b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
@@ -41,7 +41,7 @@
 	return 5;
 }
 
-static struct clk_ops sh4202_emi_clk_ops = {
+static struct sh_clk_ops sh4202_emi_clk_ops = {
 	.recalc		= emi_clk_recalc,
 };
 
@@ -56,7 +56,7 @@
 	return clk->parent->rate / frqcr3_divisors[idx];
 }
 
-static struct clk_ops sh4202_femi_clk_ops = {
+static struct sh_clk_ops sh4202_femi_clk_ops = {
 	.recalc		= femi_clk_recalc,
 };
 
@@ -130,7 +130,7 @@
 	return 0;
 }
 
-static struct clk_ops sh4202_shoc_clk_ops = {
+static struct sh_clk_ops sh4202_shoc_clk_ops = {
 	.init		= shoc_clk_init,
 	.recalc		= shoc_clk_recalc,
 	.set_rate	= shoc_clk_set_rate,
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4.c b/arch/sh/kernel/cpu/sh4/clock-sh4.c
index 5add75c..99e5ec8 100644
--- a/arch/sh/kernel/cpu/sh4/clock-sh4.c
+++ b/arch/sh/kernel/cpu/sh4/clock-sh4.c
@@ -31,7 +31,7 @@
 	clk->rate *= pfc_divisors[__raw_readw(FRQCR) & 0x0007];
 }
 
-static struct clk_ops sh4_master_clk_ops = {
+static struct sh_clk_ops sh4_master_clk_ops = {
 	.init		= master_clk_init,
 };
 
@@ -41,7 +41,7 @@
 	return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh4_module_clk_ops = {
+static struct sh_clk_ops sh4_module_clk_ops = {
 	.recalc		= module_clk_recalc,
 };
 
@@ -51,7 +51,7 @@
 	return clk->parent->rate / bfc_divisors[idx];
 }
 
-static struct clk_ops sh4_bus_clk_ops = {
+static struct sh_clk_ops sh4_bus_clk_ops = {
 	.recalc		= bus_clk_recalc,
 };
 
@@ -61,18 +61,18 @@
 	return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh4_cpu_clk_ops = {
+static struct sh_clk_ops sh4_cpu_clk_ops = {
 	.recalc		= cpu_clk_recalc,
 };
 
-static struct clk_ops *sh4_clk_ops[] = {
+static struct sh_clk_ops *sh4_clk_ops[] = {
 	&sh4_master_clk_ops,
 	&sh4_module_clk_ops,
 	&sh4_bus_clk_ops,
 	&sh4_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
 	if (idx < ARRAY_SIZE(sh4_clk_ops))
 		*ops = sh4_clk_ops[idx];
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c
index 447482d..e74cd6c 100644
--- a/arch/sh/kernel/cpu/sh4/fpu.c
+++ b/arch/sh/kernel/cpu/sh4/fpu.c
@@ -15,7 +15,6 @@
 #include <linux/io.h>
 #include <cpu/fpu.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/fpu.h>
 
 /* The PR (precision) bit in the FP Status Register must be clear when
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
index 70e45bd..ea01a72 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
@@ -61,7 +61,7 @@
 	return clk->parent->rate * mult;
 }
 
-static struct clk_ops dll_clk_ops = {
+static struct sh_clk_ops dll_clk_ops = {
 	.recalc		= dll_recalc,
 };
 
@@ -81,7 +81,7 @@
 	return clk->parent->rate * mult;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
 	.recalc		= pll_recalc,
 };
 
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7366.c b/arch/sh/kernel/cpu/sh4a/clock-sh7366.c
index 3c31650..7ac07b4 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7366.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7366.c
@@ -61,7 +61,7 @@
 	return clk->parent->rate * mult;
 }
 
-static struct clk_ops dll_clk_ops = {
+static struct sh_clk_ops dll_clk_ops = {
 	.recalc		= dll_recalc,
 };
 
@@ -84,7 +84,7 @@
 	return (clk->parent->rate * mult) / div;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
 	.recalc		= pll_recalc,
 };
 
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
index 212c72e..8e1f970 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
@@ -64,7 +64,7 @@
 	return clk->parent->rate * mult;
 }
 
-static struct clk_ops dll_clk_ops = {
+static struct sh_clk_ops dll_clk_ops = {
 	.recalc		= dll_recalc,
 };
 
@@ -87,7 +87,7 @@
 	return (clk->parent->rate * mult) / div;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
 	.recalc		= pll_recalc,
 };
 
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
index 2f8c917..35f75cf 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c
@@ -65,7 +65,7 @@
 	return clk->parent->rate * mult;
 }
 
-static struct clk_ops dll_clk_ops = {
+static struct sh_clk_ops dll_clk_ops = {
 	.recalc		= dll_recalc,
 };
 
@@ -88,7 +88,7 @@
 	return (clk->parent->rate * mult) / div;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
 	.recalc		= pll_recalc,
 };
 
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
index 70bd966..2a87901 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
@@ -70,7 +70,7 @@
 	return (clk->parent->rate * mult) / div;
 }
 
-static struct clk_ops fll_clk_ops = {
+static struct sh_clk_ops fll_clk_ops = {
 	.recalc		= fll_recalc,
 };
 
@@ -90,7 +90,7 @@
 	return clk->parent->rate * mult;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
 	.recalc		= pll_recalc,
 };
 
@@ -105,7 +105,7 @@
 	return clk->parent->rate / 3;
 }
 
-static struct clk_ops div3_clk_ops = {
+static struct sh_clk_ops div3_clk_ops = {
 	.recalc		= div3_recalc,
 };
 
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
index 0bd21c8..5853989 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
@@ -33,7 +33,7 @@
 	return clk->parent->rate * multiplier;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
 	.recalc		= pll_recalc,
 };
 
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7763.c b/arch/sh/kernel/cpu/sh4a/clock-sh7763.c
index 2d4c7fd..7707e35a 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7763.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7763.c
@@ -27,7 +27,7 @@
 	clk->rate *= p0fc_divisors[(__raw_readl(FRQCR) >> 4) & 0x07];
 }
 
-static struct clk_ops sh7763_master_clk_ops = {
+static struct sh_clk_ops sh7763_master_clk_ops = {
 	.init		= master_clk_init,
 };
 
@@ -37,7 +37,7 @@
 	return clk->parent->rate / p0fc_divisors[idx];
 }
 
-static struct clk_ops sh7763_module_clk_ops = {
+static struct sh_clk_ops sh7763_module_clk_ops = {
 	.recalc		= module_clk_recalc,
 };
 
@@ -47,22 +47,22 @@
 	return clk->parent->rate / bfc_divisors[idx];
 }
 
-static struct clk_ops sh7763_bus_clk_ops = {
+static struct sh_clk_ops sh7763_bus_clk_ops = {
 	.recalc		= bus_clk_recalc,
 };
 
-static struct clk_ops sh7763_cpu_clk_ops = {
+static struct sh_clk_ops sh7763_cpu_clk_ops = {
 	.recalc		= followparent_recalc,
 };
 
-static struct clk_ops *sh7763_clk_ops[] = {
+static struct sh_clk_ops *sh7763_clk_ops[] = {
 	&sh7763_master_clk_ops,
 	&sh7763_module_clk_ops,
 	&sh7763_bus_clk_ops,
 	&sh7763_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
 	if (idx < ARRAY_SIZE(sh7763_clk_ops))
 		*ops = sh7763_clk_ops[idx];
@@ -74,7 +74,7 @@
 	return clk->parent->rate / cfc_divisors[idx];
 }
 
-static struct clk_ops sh7763_shyway_clk_ops = {
+static struct sh_clk_ops sh7763_shyway_clk_ops = {
 	.recalc		= shyway_clk_recalc,
 };
 
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7770.c b/arch/sh/kernel/cpu/sh4a/clock-sh7770.c
index 9e33543..5d36f33 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7770.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7770.c
@@ -24,7 +24,7 @@
 	clk->rate *= pfc_divisors[(__raw_readl(FRQCR) >> 28) & 0x000f];
 }
 
-static struct clk_ops sh7770_master_clk_ops = {
+static struct sh_clk_ops sh7770_master_clk_ops = {
 	.init		= master_clk_init,
 };
 
@@ -34,7 +34,7 @@
 	return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7770_module_clk_ops = {
+static struct sh_clk_ops sh7770_module_clk_ops = {
 	.recalc		= module_clk_recalc,
 };
 
@@ -44,7 +44,7 @@
 	return clk->parent->rate / bfc_divisors[idx];
 }
 
-static struct clk_ops sh7770_bus_clk_ops = {
+static struct sh_clk_ops sh7770_bus_clk_ops = {
 	.recalc		= bus_clk_recalc,
 };
 
@@ -54,18 +54,18 @@
 	return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh7770_cpu_clk_ops = {
+static struct sh_clk_ops sh7770_cpu_clk_ops = {
 	.recalc		= cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7770_clk_ops[] = {
+static struct sh_clk_ops *sh7770_clk_ops[] = {
 	&sh7770_master_clk_ops,
 	&sh7770_module_clk_ops,
 	&sh7770_bus_clk_ops,
 	&sh7770_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
 	if (idx < ARRAY_SIZE(sh7770_clk_ops))
 		*ops = sh7770_clk_ops[idx];
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7780.c b/arch/sh/kernel/cpu/sh4a/clock-sh7780.c
index 3b53348..793dae4 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7780.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7780.c
@@ -27,7 +27,7 @@
 	clk->rate *= pfc_divisors[__raw_readl(FRQCR) & 0x0003];
 }
 
-static struct clk_ops sh7780_master_clk_ops = {
+static struct sh_clk_ops sh7780_master_clk_ops = {
 	.init		= master_clk_init,
 };
 
@@ -37,7 +37,7 @@
 	return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7780_module_clk_ops = {
+static struct sh_clk_ops sh7780_module_clk_ops = {
 	.recalc		= module_clk_recalc,
 };
 
@@ -47,7 +47,7 @@
 	return clk->parent->rate / bfc_divisors[idx];
 }
 
-static struct clk_ops sh7780_bus_clk_ops = {
+static struct sh_clk_ops sh7780_bus_clk_ops = {
 	.recalc		= bus_clk_recalc,
 };
 
@@ -57,18 +57,18 @@
 	return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh7780_cpu_clk_ops = {
+static struct sh_clk_ops sh7780_cpu_clk_ops = {
 	.recalc		= cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7780_clk_ops[] = {
+static struct sh_clk_ops *sh7780_clk_ops[] = {
 	&sh7780_master_clk_ops,
 	&sh7780_module_clk_ops,
 	&sh7780_bus_clk_ops,
 	&sh7780_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
 	if (idx < ARRAY_SIZE(sh7780_clk_ops))
 		*ops = sh7780_clk_ops[idx];
@@ -80,7 +80,7 @@
 	return clk->parent->rate / cfc_divisors[idx];
 }
 
-static struct clk_ops sh7780_shyway_clk_ops = {
+static struct sh_clk_ops sh7780_shyway_clk_ops = {
 	.recalc		= shyway_clk_recalc,
 };
 
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
index 2b31443..ab1c58f 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
@@ -36,7 +36,7 @@
 	return clk->parent->rate * multiplier;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
 	.recalc		= pll_recalc,
 };
 
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c
index f6c0c3d..4917094 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c
@@ -38,7 +38,7 @@
 	return clk->parent->rate * multiplier;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
 	.recalc		= pll_recalc,
 };
 
diff --git a/arch/sh/kernel/cpu/sh4a/clock-shx3.c b/arch/sh/kernel/cpu/sh4a/clock-shx3.c
index bf2d00b..0f11b39 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-shx3.c
@@ -32,7 +32,7 @@
 	return clk->parent->rate * 72;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
 	.recalc		= pll_recalc,
 };
 
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
index 2875e8b..c8836cf 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
@@ -680,6 +680,25 @@
 	.resource	= spi1_resources,
 };
 
+static struct resource rspi_resources[] = {
+	{
+		.start	= 0xfe480000,
+		.end	= 0xfe4800ff,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= 220,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device rspi_device = {
+	.name	= "rspi",
+	.id	= 2,
+	.num_resources	= ARRAY_SIZE(rspi_resources),
+	.resource	= rspi_resources,
+};
+
 static struct resource usb_ehci_resources[] = {
 	[0] = {
 		.start	= 0xfe4f1000,
@@ -740,6 +759,7 @@
 	&dma3_device,
 	&spi0_device,
 	&spi1_device,
+	&rspi_device,
 	&usb_ehci_device,
 	&usb_ohci_device,
 };
diff --git a/arch/sh/kernel/cpu/sh5/clock-sh5.c b/arch/sh/kernel/cpu/sh5/clock-sh5.c
index 9cfc19b..c48b93d 100644
--- a/arch/sh/kernel/cpu/sh5/clock-sh5.c
+++ b/arch/sh/kernel/cpu/sh5/clock-sh5.c
@@ -28,7 +28,7 @@
 	clk->rate *= ifc_table[idx];
 }
 
-static struct clk_ops sh5_master_clk_ops = {
+static struct sh_clk_ops sh5_master_clk_ops = {
 	.init		= master_clk_init,
 };
 
@@ -38,7 +38,7 @@
 	return clk->parent->rate / ifc_table[idx];
 }
 
-static struct clk_ops sh5_module_clk_ops = {
+static struct sh_clk_ops sh5_module_clk_ops = {
 	.recalc		= module_clk_recalc,
 };
 
@@ -48,7 +48,7 @@
 	return clk->parent->rate / ifc_table[idx];
 }
 
-static struct clk_ops sh5_bus_clk_ops = {
+static struct sh_clk_ops sh5_bus_clk_ops = {
 	.recalc		= bus_clk_recalc,
 };
 
@@ -58,18 +58,18 @@
 	return clk->parent->rate / ifc_table[idx];
 }
 
-static struct clk_ops sh5_cpu_clk_ops = {
+static struct sh_clk_ops sh5_cpu_clk_ops = {
 	.recalc		= cpu_clk_recalc,
 };
 
-static struct clk_ops *sh5_clk_ops[] = {
+static struct sh_clk_ops *sh5_clk_ops[] = {
 	&sh5_master_clk_ops,
 	&sh5_module_clk_ops,
 	&sh5_bus_clk_ops,
 	&sh5_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
 	cprc_base = (unsigned long)ioremap_nocache(CPRC_BASE, 1024);
 	BUG_ON(!cprc_base);
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
index 6d62eb4..1ddc876 100644
--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -29,7 +29,6 @@
 				int index)
 {
 	unsigned long allowed_mode = SUSP_SH_SLEEP;
-	ktime_t before, after;
 	int requested_state = index;
 	int allowed_state;
 	int k;
@@ -47,19 +46,16 @@
 	 */
 	k = min_t(int, allowed_state, requested_state);
 
-	before = ktime_get();
 	sh_mobile_call_standby(cpuidle_mode[k]);
-	after = ktime_get();
-
-	dev->last_residency = (int)ktime_to_ns(ktime_sub(after, before)) >> 10;
 
 	return k;
 }
 
 static struct cpuidle_device cpuidle_dev;
 static struct cpuidle_driver cpuidle_driver = {
-	.name =		"sh_idle",
-	.owner =	THIS_MODULE,
+	.name			= "sh_idle",
+	.owner			= THIS_MODULE,
+	.en_core_tk_irqen	= 1,
 };
 
 void sh_mobile_setup_cpuidle(void)
diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c
index 0ffface..e68b45b 100644
--- a/arch/sh/kernel/cpufreq.c
+++ b/arch/sh/kernel/cpufreq.c
@@ -3,7 +3,7 @@
  *
  * cpufreq driver for the SuperH processors.
  *
- * Copyright (C) 2002 - 2007 Paul Mundt
+ * Copyright (C) 2002 - 2012 Paul Mundt
  * Copyright (C) 2002 M. R. Brown
  *
  * Clock framework bits from arch/avr32/mach-at32ap/cpufreq.c
@@ -14,6 +14,8 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
+#define pr_fmt(fmt) "cpufreq: " fmt
+
 #include <linux/types.h>
 #include <linux/cpufreq.h>
 #include <linux/kernel.h>
@@ -21,15 +23,18 @@
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/cpumask.h>
+#include <linux/cpu.h>
 #include <linux/smp.h>
 #include <linux/sched.h>	/* set_cpus_allowed() */
 #include <linux/clk.h>
+#include <linux/percpu.h>
+#include <linux/sh_clk.h>
 
-static struct clk *cpuclk;
+static DEFINE_PER_CPU(struct clk, sh_cpuclk);
 
 static unsigned int sh_cpufreq_get(unsigned int cpu)
 {
-	return (clk_get_rate(cpuclk) + 500) / 1000;
+	return (clk_get_rate(&per_cpu(sh_cpuclk, cpu)) + 500) / 1000;
 }
 
 /*
@@ -40,8 +45,10 @@
 			     unsigned int relation)
 {
 	unsigned int cpu = policy->cpu;
+	struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
 	cpumask_t cpus_allowed;
 	struct cpufreq_freqs freqs;
+	struct device *dev;
 	long freq;
 
 	if (!cpu_online(cpu))
@@ -52,13 +59,15 @@
 
 	BUG_ON(smp_processor_id() != cpu);
 
+	dev = get_cpu_device(cpu);
+
 	/* Convert target_freq from kHz to Hz */
 	freq = clk_round_rate(cpuclk, target_freq * 1000);
 
 	if (freq < (policy->min * 1000) || freq > (policy->max * 1000))
 		return -EINVAL;
 
-	pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);
+	dev_dbg(dev, "requested frequency %u Hz\n", target_freq * 1000);
 
 	freqs.cpu	= cpu;
 	freqs.old	= sh_cpufreq_get(cpu);
@@ -70,78 +79,112 @@
 	clk_set_rate(cpuclk, freq);
 	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
-	pr_debug("cpufreq: set frequency %lu Hz\n", freq);
-
-	return 0;
-}
-
-static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
-{
-	if (!cpu_online(policy->cpu))
-		return -ENODEV;
-
-	cpuclk = clk_get(NULL, "cpu_clk");
-	if (IS_ERR(cpuclk)) {
-		printk(KERN_ERR "cpufreq: couldn't get CPU#%d clk\n",
-		       policy->cpu);
-		return PTR_ERR(cpuclk);
-	}
-
-	/* cpuinfo and default policy values */
-	policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000;
-	policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
-	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
-
-	policy->cur		= sh_cpufreq_get(policy->cpu);
-	policy->min		= policy->cpuinfo.min_freq;
-	policy->max		= policy->cpuinfo.max_freq;
-
-	/*
-	 * Catch the cases where the clock framework hasn't been wired up
-	 * properly to support scaling.
-	 */
-	if (unlikely(policy->min == policy->max)) {
-		printk(KERN_ERR "cpufreq: clock framework rate rounding "
-		       "not supported on CPU#%d.\n", policy->cpu);
-
-		clk_put(cpuclk);
-		return -EINVAL;
-	}
-
-	printk(KERN_INFO "cpufreq: CPU#%d Frequencies - Minimum %u.%03u MHz, "
-	       "Maximum %u.%03u MHz.\n",
-	       policy->cpu, policy->min / 1000, policy->min % 1000,
-	       policy->max / 1000, policy->max % 1000);
+	dev_dbg(dev, "set frequency %lu Hz\n", freq);
 
 	return 0;
 }
 
 static int sh_cpufreq_verify(struct cpufreq_policy *policy)
 {
+	struct clk *cpuclk = &per_cpu(sh_cpuclk, policy->cpu);
+	struct cpufreq_frequency_table *freq_table;
+
+	freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL;
+	if (freq_table)
+		return cpufreq_frequency_table_verify(policy, freq_table);
+
 	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
 				     policy->cpuinfo.max_freq);
+
+	policy->min = (clk_round_rate(cpuclk, 1) + 500) / 1000;
+	policy->max = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
+
+	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+				     policy->cpuinfo.max_freq);
+
 	return 0;
 }
 
-static int sh_cpufreq_exit(struct cpufreq_policy *policy)
+static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-	clk_put(cpuclk);
+	unsigned int cpu = policy->cpu;
+	struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
+	struct cpufreq_frequency_table *freq_table;
+	struct device *dev;
+
+	if (!cpu_online(cpu))
+		return -ENODEV;
+
+	dev = get_cpu_device(cpu);
+
+	cpuclk = clk_get(dev, "cpu_clk");
+	if (IS_ERR(cpuclk)) {
+		dev_err(dev, "couldn't get CPU clk\n");
+		return PTR_ERR(cpuclk);
+	}
+
+	policy->cur = policy->min = policy->max = sh_cpufreq_get(cpu);
+
+	freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL;
+	if (freq_table) {
+		int result;
+
+		result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+		if (!result)
+			cpufreq_frequency_table_get_attr(freq_table, cpu);
+	} else {
+		dev_notice(dev, "no frequency table found, falling back "
+			   "to rate rounding.\n");
+
+		policy->cpuinfo.min_freq =
+			(clk_round_rate(cpuclk, 1) + 500) / 1000;
+		policy->cpuinfo.max_freq =
+			(clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
+	}
+
+	policy->min = policy->cpuinfo.min_freq;
+	policy->max = policy->cpuinfo.max_freq;
+
+	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+
+	dev_info(dev, "CPU Frequencies - Minimum %u.%03u MHz, "
+	       "Maximum %u.%03u MHz.\n",
+	       policy->min / 1000, policy->min % 1000,
+	       policy->max / 1000, policy->max % 1000);
+
 	return 0;
 }
 
+static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+	unsigned int cpu = policy->cpu;
+	struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
+
+	cpufreq_frequency_table_put_attr(cpu);
+	clk_put(cpuclk);
+
+	return 0;
+}
+
+static struct freq_attr *sh_freq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
 static struct cpufreq_driver sh_cpufreq_driver = {
 	.owner		= THIS_MODULE,
 	.name		= "sh",
-	.init		= sh_cpufreq_cpu_init,
-	.verify		= sh_cpufreq_verify,
-	.target		= sh_cpufreq_target,
 	.get		= sh_cpufreq_get,
-	.exit		= sh_cpufreq_exit,
+	.target		= sh_cpufreq_target,
+	.verify		= sh_cpufreq_verify,
+	.init		= sh_cpufreq_cpu_init,
+	.exit		= sh_cpufreq_cpu_exit,
+	.attr		= sh_freq_attr,
 };
 
 static int __init sh_cpufreq_module_init(void)
 {
-	printk(KERN_INFO "cpufreq: SuperH CPU frequency driver.\n");
+	pr_notice("SuperH CPU frequency driver.\n");
 	return cpufreq_register_driver(&sh_cpufreq_driver);
 }
 
diff --git a/arch/sh/kernel/dma-nommu.c b/arch/sh/kernel/dma-nommu.c
index 3c55b87..5b0bfcd 100644
--- a/arch/sh/kernel/dma-nommu.c
+++ b/arch/sh/kernel/dma-nommu.c
@@ -63,8 +63,8 @@
 #endif
 
 struct dma_map_ops nommu_dma_ops = {
-	.alloc_coherent		= dma_generic_alloc_coherent,
-	.free_coherent		= dma_generic_free_coherent,
+	.alloc			= dma_generic_alloc_coherent,
+	.free			= dma_generic_free_coherent,
 	.map_page		= nommu_map_page,
 	.map_sg			= nommu_map_sg,
 #ifdef CONFIG_DMA_NONCOHERENT
diff --git a/arch/sh/kernel/hw_breakpoint.c b/arch/sh/kernel/hw_breakpoint.c
index efae6ab..f9173766 100644
--- a/arch/sh/kernel/hw_breakpoint.c
+++ b/arch/sh/kernel/hw_breakpoint.c
@@ -22,6 +22,7 @@
 #include <asm/hw_breakpoint.h>
 #include <asm/mmu_context.h>
 #include <asm/ptrace.h>
+#include <asm/traps.h>
 
 /*
  * Stores the breakpoints currently in use on each breakpoint address
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c
index 7e48928..64852ec 100644
--- a/arch/sh/kernel/idle.c
+++ b/arch/sh/kernel/idle.c
@@ -18,9 +18,9 @@
 #include <linux/smp.h>
 #include <linux/cpuidle.h>
 #include <asm/pgalloc.h>
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/smp.h>
+#include <asm/bl_bit.h>
 
 void (*pm_idle)(void);
 
diff --git a/arch/sh/kernel/io_trapped.c b/arch/sh/kernel/io_trapped.c
index 0f62f46..c0a9761 100644
--- a/arch/sh/kernel/io_trapped.c
+++ b/arch/sh/kernel/io_trapped.c
@@ -15,7 +15,6 @@
 #include <linux/vmalloc.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index 7ec6651..f72e3a9 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -24,7 +24,6 @@
 #include <linux/prefetch.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
-#include <asm/system.h>
 #include <asm/fpu.h>
 #include <asm/syscalls.h>
 
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c
index cbd4e4b..4264583e 100644
--- a/arch/sh/kernel/process_64.c
+++ b/arch/sh/kernel/process_64.c
@@ -30,6 +30,7 @@
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
 #include <asm/fpu.h>
+#include <asm/switch_to.h>
 
 struct task_struct *last_task_used_math = NULL;
 
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c
index a3e6515..9698671 100644
--- a/arch/sh/kernel/ptrace_32.c
+++ b/arch/sh/kernel/ptrace_32.c
@@ -28,7 +28,6 @@
 #include <linux/hw_breakpoint.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/mmu_context.h>
 #include <asm/syscalls.h>
diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c
index 3d0080b..bc81e07 100644
--- a/arch/sh/kernel/ptrace_64.c
+++ b/arch/sh/kernel/ptrace_64.c
@@ -34,11 +34,11 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/mmu_context.h>
 #include <asm/syscalls.h>
 #include <asm/fpu.h>
+#include <asm/traps.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/syscalls.h>
diff --git a/arch/sh/kernel/reboot.c b/arch/sh/kernel/reboot.c
index ca6a5ca..04afe5b 100644
--- a/arch/sh/kernel/reboot.c
+++ b/arch/sh/kernel/reboot.c
@@ -8,8 +8,8 @@
 #endif
 #include <asm/addrspace.h>
 #include <asm/reboot.h>
-#include <asm/system.h>
 #include <asm/tlbflush.h>
+#include <asm/traps.h>
 
 void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c
index a7a55ed..5901fba 100644
--- a/arch/sh/kernel/signal_32.c
+++ b/arch/sh/kernel/signal_32.c
@@ -25,7 +25,6 @@
 #include <linux/freezer.h>
 #include <linux/io.h>
 #include <linux/tracehook.h>
-#include <asm/system.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -58,12 +57,13 @@
 	       unsigned long r5, unsigned long r6, unsigned long r7,
 	       struct pt_regs __regs)
 {
-	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sighand->siglock);
+	sigset_t blocked;
+
 	current->saved_sigmask = current->blocked;
-	siginitset(&current->blocked, mask);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+
+	mask &= _BLOCKABLE;
+	siginitset(&blocked, mask);
+	set_current_blocked(&blocked);
 
 	current->state = TASK_INTERRUPTIBLE;
 	schedule();
@@ -240,11 +240,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->sc, &r0))
 		goto badframe;
@@ -274,10 +270,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
 		goto badframe;
@@ -548,17 +541,8 @@
 	else
 		ret = setup_frame(sig, ka, oldset, regs);
 
-	if (ka->sa.sa_flags & SA_ONESHOT)
-		ka->sa.sa_handler = SIG_DFL;
-
-	if (ret == 0) {
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-		if (!(ka->sa.sa_flags & SA_NODEFER))
-			sigaddset(&current->blocked,sig);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
-	}
+	if (ret == 0)
+		block_sigmask(ka, sig);
 
 	return ret;
 }
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
index 6b5603f..3c9a6f7 100644
--- a/arch/sh/kernel/signal_64.c
+++ b/arch/sh/kernel/signal_64.c
@@ -159,14 +159,13 @@
 	       unsigned long r6, unsigned long r7,
 	       struct pt_regs * regs)
 {
-	sigset_t saveset;
+	sigset_t saveset, blocked;
+
+	saveset = current->blocked;
 
 	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
-	siginitset(&current->blocked, mask);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	siginitset(&blocked, mask);
+	set_current_blocked(&blocked);
 
 	REF_REG_RET = -EINTR;
 	while (1) {
@@ -198,11 +197,8 @@
 	if (copy_from_user(&newset, unewset, sizeof(newset)))
 		return -EFAULT;
 	sigdelsetmask(&newset, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
 	saveset = current->blocked;
-	current->blocked = newset;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&newset);
 
 	REF_REG_RET = -EINTR;
 	while (1) {
@@ -408,11 +404,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->sc, &ret))
 		goto badframe;
@@ -445,10 +437,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret))
 		goto badframe;
@@ -734,17 +723,8 @@
 	else
 		ret = setup_frame(sig, ka, oldset, regs);
 
-	if (ka->sa.sa_flags & SA_ONESHOT)
-		ka->sa.sa_handler = SIG_DFL;
-
-	if (ret == 0) {
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-		if (!(ka->sa.sa_flags & SA_NODEFER))
-			sigaddset(&current->blocked,sig);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
-	}
+	if (ret == 0)
+		block_sigmask(ka, sig);
 
 	return ret;
 }
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
index f624174..a17a14d 100644
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -23,7 +23,6 @@
 #include <linux/sched.h>
 #include <linux/atomic.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/smp.h>
 #include <asm/cacheflush.h>
diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S
index ee56a9b..4b68f0f 100644
--- a/arch/sh/kernel/syscalls_32.S
+++ b/arch/sh/kernel/syscalls_32.S
@@ -204,8 +204,8 @@
 	.long sys_capset           /* 185 */
 	.long sys_sigaltstack
 	.long sys_sendfile
-	.long sys_ni_syscall	/* streams1 */
-	.long sys_ni_syscall	/* streams2 */
+	.long sys_ni_syscall	/* getpmsg */
+	.long sys_ni_syscall	/* putpmsg */
 	.long sys_vfork            /* 190 */
 	.long sys_getrlimit
 	.long sys_mmap2
@@ -259,8 +259,8 @@
 	.long sys_futex		/* 240 */
 	.long sys_sched_setaffinity
 	.long sys_sched_getaffinity
-	.long sys_ni_syscall
-	.long sys_ni_syscall
+	.long sys_ni_syscall	/* reserved for set_thread_area */
+	.long sys_ni_syscall	/* reserved for get_thread_area */
 	.long sys_io_setup	/* 245 */
 	.long sys_io_destroy
 	.long sys_io_getevents
diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S
index 9af7de2..0956345 100644
--- a/arch/sh/kernel/syscalls_64.S
+++ b/arch/sh/kernel/syscalls_64.S
@@ -208,8 +208,8 @@
 	.long sys_capset		/* 185 */
 	.long sys_sigaltstack
 	.long sys_sendfile
-	.long sys_ni_syscall	/* streams1 */
-	.long sys_ni_syscall	/* streams2 */
+	.long sys_ni_syscall	/* getpmsg */
+	.long sys_ni_syscall	/* putpmsg */
 	.long sys_vfork			/* 190 */
 	.long sys_getrlimit
 	.long sys_mmap2
@@ -296,8 +296,8 @@
 	.long sys_futex
 	.long sys_sched_setaffinity
 	.long sys_sched_getaffinity	/* 270 */
-	.long sys_ni_syscall
-	.long sys_ni_syscall
+	.long sys_ni_syscall		/* reserved for set_thread_area */
+	.long sys_ni_syscall		/* reserved for get_thread_area */
 	.long sys_io_setup
 	.long sys_io_destroy
 	.long sys_io_getevents		/* 275 */
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index 0830c2a..a87e58a 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -7,7 +7,7 @@
 #include <linux/uaccess.h>
 #include <linux/hardirq.h>
 #include <asm/unwinder.h>
-#include <asm/system.h>
+#include <asm/traps.h>
 
 #ifdef CONFIG_GENERIC_BUG
 static void handle_BUG(struct pt_regs *regs)
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index 7bbef95..a37175d 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -27,10 +27,11 @@
 #include <linux/sysfs.h>
 #include <linux/uaccess.h>
 #include <linux/perf_event.h>
-#include <asm/system.h>
 #include <asm/alignment.h>
 #include <asm/fpu.h>
 #include <asm/kprobes.h>
+#include <asm/traps.h>
+#include <asm/bl_bit.h>
 
 #ifdef CONFIG_CPU_SH2
 # define TRAP_RESERVED_INST	4
diff --git a/arch/sh/kernel/traps_64.c b/arch/sh/kernel/traps_64.c
index cd3a404..6c04860 100644
--- a/arch/sh/kernel/traps_64.c
+++ b/arch/sh/kernel/traps_64.c
@@ -25,7 +25,6 @@
 #include <linux/sysctl.h>
 #include <linux/module.h>
 #include <linux/perf_event.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/atomic.h>
diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c
index 1d6d51a..5ca5797 100644
--- a/arch/sh/kernel/vsyscall/vsyscall.c
+++ b/arch/sh/kernel/vsyscall/vsyscall.c
@@ -73,8 +73,7 @@
 
 	ret = install_special_mapping(mm, addr, PAGE_SIZE,
 				      VM_READ | VM_EXEC |
-				      VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC |
-				      VM_ALWAYSDUMP,
+				      VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
 				      syscall_pages);
 	if (unlikely(ret))
 		goto up_fail;
diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c
index 9771952..b876780 100644
--- a/arch/sh/math-emu/math.c
+++ b/arch/sh/math-emu/math.c
@@ -14,7 +14,6 @@
 #include <linux/signal.h>
 #include <linux/perf_event.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include <asm/io.h>
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index f251b5f..b81d9db 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -33,7 +33,8 @@
 fs_initcall(dma_init);
 
 void *dma_generic_alloc_coherent(struct device *dev, size_t size,
-				 dma_addr_t *dma_handle, gfp_t gfp)
+				 dma_addr_t *dma_handle, gfp_t gfp,
+				 struct dma_attrs *attrs)
 {
 	void *ret, *ret_nocache;
 	int order = get_order(size);
@@ -64,7 +65,8 @@
 }
 
 void dma_generic_free_coherent(struct device *dev, size_t size,
-			       void *vaddr, dma_addr_t dma_handle)
+			       void *vaddr, dma_addr_t dma_handle,
+			       struct dma_attrs *attrs)
 {
 	int order = get_order(size);
 	unsigned long pfn = dma_handle >> PAGE_SHIFT;
diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c
index 7bebd04..324eef9 100644
--- a/arch/sh/mm/fault_32.c
+++ b/arch/sh/mm/fault_32.c
@@ -17,9 +17,9 @@
 #include <linux/kprobes.h>
 #include <linux/perf_event.h>
 #include <asm/io_trapped.h>
-#include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/tlbflush.h>
+#include <asm/traps.h>
 
 static inline int notify_page_fault(struct pt_regs *regs, int trap)
 {
diff --git a/arch/sh/mm/fault_64.c b/arch/sh/mm/fault_64.c
index 2b356ce..44a3410 100644
--- a/arch/sh/mm/fault_64.c
+++ b/arch/sh/mm/fault_64.c
@@ -33,7 +33,6 @@
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/interrupt.h>
-#include <asm/system.h>
 #include <asm/tlb.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
diff --git a/arch/sh/mm/flush-sh4.c b/arch/sh/mm/flush-sh4.c
index cef4026..75a17f5 100644
--- a/arch/sh/mm/flush-sh4.c
+++ b/arch/sh/mm/flush-sh4.c
@@ -1,6 +1,7 @@
 #include <linux/mm.h>
 #include <asm/mmu_context.h>
 #include <asm/cacheflush.h>
+#include <asm/traps.h>
 
 /*
  * Write back the dirty D-caches, but not invalidate them.
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
index fad52f1..7160c9f 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -25,7 +25,6 @@
 #include <linux/vmalloc.h>
 #include <asm/cacheflush.h>
 #include <asm/sizes.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
diff --git a/arch/sh/mm/tlb-pteaex.c b/arch/sh/mm/tlb-pteaex.c
index b71db6a..4db21ad 100644
--- a/arch/sh/mm/tlb-pteaex.c
+++ b/arch/sh/mm/tlb-pteaex.c
@@ -12,7 +12,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/io.h>
-#include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/cacheflush.h>
 
diff --git a/arch/sh/mm/tlb-sh3.c b/arch/sh/mm/tlb-sh3.c
index 7a940db..6554fb4 100644
--- a/arch/sh/mm/tlb-sh3.c
+++ b/arch/sh/mm/tlb-sh3.c
@@ -20,7 +20,6 @@
 #include <linux/smp.h>
 #include <linux/interrupt.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c
index cfdf793..d42dd7e 100644
--- a/arch/sh/mm/tlb-sh4.c
+++ b/arch/sh/mm/tlb-sh4.c
@@ -11,7 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/io.h>
-#include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/cacheflush.h>
 
diff --git a/arch/sh/mm/tlbflush_64.c b/arch/sh/mm/tlbflush_64.c
index e3430e0..11c5a18 100644
--- a/arch/sh/mm/tlbflush_64.c
+++ b/arch/sh/mm/tlbflush_64.c
@@ -22,7 +22,6 @@
 #include <linux/smp.h>
 #include <linux/perf_event.h>
 #include <linux/interrupt.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/tlb.h>
 #include <asm/uaccess.h>
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index ca5580e..6c0683d 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -29,6 +29,7 @@
 	select GENERIC_IRQ_SHOW
 	select USE_GENERIC_SMP_HELPERS if SMP
 	select GENERIC_PCI_IOMAP
+	select HAVE_NMI_WATCHDOG if SPARC64
 
 config SPARC32
 	def_bool !64BIT
@@ -576,6 +577,7 @@
 	depends on SPARC64
 	default y
 	select COMPAT_BINFMT_ELF
+	select ARCH_WANT_OLD_COMPAT_IPC
 
 config SYSVIPC_COMPAT
 	bool
diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile
index 9205416..d56d199 100644
--- a/arch/sparc/boot/Makefile
+++ b/arch/sparc/boot/Makefile
@@ -5,7 +5,6 @@
 
 ROOT_IMG	:= /usr/src/root.img
 ELFTOAOUT	:= elftoaout
-MKIMAGE 	:= $(srctree)/scripts/mkuboot.sh
 
 hostprogs-y	:= piggyback btfixupprep
 targets		:= tftpboot.img btfix.o btfix.S image zImage vmlinux.aout
@@ -92,11 +91,9 @@
 $(obj)/image.gz: $(obj)/image.bin
 	$(call if_changed,gzip)
 
-quiet_cmd_uimage = UIMAGE  $@
-      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A sparc -O linux -T kernel \
-               -C gzip -a $(CONFIG_UBOOT_LOAD_ADDR) \
-	       -e $(CONFIG_UBOOT_ENTRY_ADDR) -n 'Linux-$(KERNELRELEASE)' \
-               -d $< $@
+UIMAGE_LOADADDR = $(CONFIG_UBOOT_LOAD_ADDR)
+UIMAGE_ENTRYADDR = $(CONFIG_UBOOT_ENTRY_ADDR)
+UIMAGE_COMPRESSION = gzip
 
 quiet_cmd_uimage.o = UIMAGE.O $@
       cmd_uimage.o = $(LD) -Tdata $(CONFIG_UBOOT_FLASH_ADDR) \
diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h
index 9dd0a76..905832a 100644
--- a/arch/sparc/include/asm/atomic_32.h
+++ b/arch/sparc/include/asm/atomic_32.h
@@ -13,9 +13,9 @@
 
 #include <linux/types.h>
 
+#include <asm/cmpxchg.h>
 #include <asm-generic/atomic64.h>
 
-#include <asm/system.h>
 
 #define ATOMIC_INIT(i)  { (i) }
 
diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h
index 9f421df..ce35a1c 100644
--- a/arch/sparc/include/asm/atomic_64.h
+++ b/arch/sparc/include/asm/atomic_64.h
@@ -8,7 +8,7 @@
 #define __ARCH_SPARC64_ATOMIC__
 
 #include <linux/types.h>
-#include <asm/system.h>
+#include <asm/cmpxchg.h>
 
 #define ATOMIC_INIT(i)		{ (i) }
 #define ATOMIC64_INIT(i)	{ (i) }
@@ -85,7 +85,6 @@
 	return c;
 }
 
-
 #define atomic64_cmpxchg(v, o, n) \
 	((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
 #define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
diff --git a/arch/sparc/include/asm/auxio_32.h b/arch/sparc/include/asm/auxio_32.h
index e03e088..3a31977 100644
--- a/arch/sparc/include/asm/auxio_32.h
+++ b/arch/sparc/include/asm/auxio_32.h
@@ -6,7 +6,6 @@
 #ifndef _SPARC_AUXIO_H
 #define _SPARC_AUXIO_H
 
-#include <asm/system.h>
 #include <asm/vaddrs.h>
 
 /* This register is an unsigned char in IO space.  It does two things.
diff --git a/arch/sparc/include/asm/barrier.h b/arch/sparc/include/asm/barrier.h
new file mode 100644
index 0000000..b25f02a
--- /dev/null
+++ b/arch/sparc/include/asm/barrier.h
@@ -0,0 +1,8 @@
+#ifndef ___ASM_SPARC_BARRIER_H
+#define ___ASM_SPARC_BARRIER_H
+#if defined(__sparc__) && defined(__arch64__)
+#include <asm/barrier_64.h>
+#else
+#include <asm/barrier_32.h>
+#endif
+#endif
diff --git a/arch/sparc/include/asm/barrier_32.h b/arch/sparc/include/asm/barrier_32.h
new file mode 100644
index 0000000..c1b7665
--- /dev/null
+++ b/arch/sparc/include/asm/barrier_32.h
@@ -0,0 +1,15 @@
+#ifndef __SPARC_BARRIER_H
+#define __SPARC_BARRIER_H
+
+/* XXX Change this if we ever use a PSO mode kernel. */
+#define mb()	__asm__ __volatile__ ("" : : : "memory")
+#define rmb()	mb()
+#define wmb()	mb()
+#define read_barrier_depends()	do { } while(0)
+#define set_mb(__var, __value)  do { __var = __value; mb(); } while(0)
+#define smp_mb()	__asm__ __volatile__("":::"memory")
+#define smp_rmb()	__asm__ __volatile__("":::"memory")
+#define smp_wmb()	__asm__ __volatile__("":::"memory")
+#define smp_read_barrier_depends()	do { } while(0)
+
+#endif /* !(__SPARC_BARRIER_H) */
diff --git a/arch/sparc/include/asm/barrier_64.h b/arch/sparc/include/asm/barrier_64.h
new file mode 100644
index 0000000..95d4598
--- /dev/null
+++ b/arch/sparc/include/asm/barrier_64.h
@@ -0,0 +1,56 @@
+#ifndef __SPARC64_BARRIER_H
+#define __SPARC64_BARRIER_H
+
+/* These are here in an effort to more fully work around Spitfire Errata
+ * #51.  Essentially, if a memory barrier occurs soon after a mispredicted
+ * branch, the chip can stop executing instructions until a trap occurs.
+ * Therefore, if interrupts are disabled, the chip can hang forever.
+ *
+ * It used to be believed that the memory barrier had to be right in the
+ * delay slot, but a case has been traced recently wherein the memory barrier
+ * was one instruction after the branch delay slot and the chip still hung.
+ * The offending sequence was the following in sym_wakeup_done() of the
+ * sym53c8xx_2 driver:
+ *
+ *	call	sym_ccb_from_dsa, 0
+ *	 movge	%icc, 0, %l0
+ *	brz,pn	%o0, .LL1303
+ *	 mov	%o0, %l2
+ *	membar	#LoadLoad
+ *
+ * The branch has to be mispredicted for the bug to occur.  Therefore, we put
+ * the memory barrier explicitly into a "branch always, predicted taken"
+ * delay slot to avoid the problem case.
+ */
+#define membar_safe(type) \
+do {	__asm__ __volatile__("ba,pt	%%xcc, 1f\n\t" \
+			     " membar	" type "\n" \
+			     "1:\n" \
+			     : : : "memory"); \
+} while (0)
+
+/* The kernel always executes in TSO memory model these days,
+ * and furthermore most sparc64 chips implement more stringent
+ * memory ordering than required by the specifications.
+ */
+#define mb()	membar_safe("#StoreLoad")
+#define rmb()	__asm__ __volatile__("":::"memory")
+#define wmb()	__asm__ __volatile__("":::"memory")
+
+#define read_barrier_depends()		do { } while(0)
+#define set_mb(__var, __value) \
+	do { __var = __value; membar_safe("#StoreLoad"); } while(0)
+
+#ifdef CONFIG_SMP
+#define smp_mb()	mb()
+#define smp_rmb()	rmb()
+#define smp_wmb()	wmb()
+#else
+#define smp_mb()	__asm__ __volatile__("":::"memory")
+#define smp_rmb()	__asm__ __volatile__("":::"memory")
+#define smp_wmb()	__asm__ __volatile__("":::"memory")
+#endif
+
+#define smp_read_barrier_depends()	do { } while(0)
+
+#endif /* !(__SPARC64_BARRIER_H) */
diff --git a/arch/sparc/include/asm/bug.h b/arch/sparc/include/asm/bug.h
index 8a59e5a..6bd9f43 100644
--- a/arch/sparc/include/asm/bug.h
+++ b/arch/sparc/include/asm/bug.h
@@ -19,4 +19,7 @@
 
 #include <asm-generic/bug.h>
 
+struct pt_regs;
+extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn));
+
 #endif
diff --git a/arch/sparc/include/asm/cacheflush_32.h b/arch/sparc/include/asm/cacheflush_32.h
index 2e46877..68431b4 100644
--- a/arch/sparc/include/asm/cacheflush_32.h
+++ b/arch/sparc/include/asm/cacheflush_32.h
@@ -83,4 +83,13 @@
 #define flush_cache_vmap(start, end)		flush_cache_all()
 #define flush_cache_vunmap(start, end)		flush_cache_all()
 
+/* When a context switch happens we must flush all user windows so that
+ * the windows of the current process are flushed onto its stack. This
+ * way the windows are all clean for the next process and the stack
+ * frames are up to date.
+ */
+extern void flush_user_windows(void);
+extern void kill_user_windows(void);
+extern void flushw_all(void);
+
 #endif /* _SPARC_CACHEFLUSH_H */
diff --git a/arch/sparc/include/asm/cacheflush_64.h b/arch/sparc/include/asm/cacheflush_64.h
index b953840..2efea2f 100644
--- a/arch/sparc/include/asm/cacheflush_64.h
+++ b/arch/sparc/include/asm/cacheflush_64.h
@@ -9,6 +9,16 @@
 
 /* Cache flush operations. */
 
+
+#define flushi(addr)	__asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory")
+#define flushw_all()	__asm__ __volatile__("flushw")
+
+extern void __flushw_user(void);
+#define flushw_user() __flushw_user()
+
+#define flush_user_windows flushw_user
+#define flush_register_windows flushw_all
+
 /* These are the same regardless of whether this is an SMP kernel or not. */
 #define flush_cache_mm(__mm) \
 	do { if ((__mm) == current->mm) flushw_user(); } while(0)
diff --git a/arch/sparc/include/asm/cmpxchg.h b/arch/sparc/include/asm/cmpxchg.h
new file mode 100644
index 0000000..9355893
--- /dev/null
+++ b/arch/sparc/include/asm/cmpxchg.h
@@ -0,0 +1,8 @@
+#ifndef ___ASM_SPARC_CMPXCHG_H
+#define ___ASM_SPARC_CMPXCHG_H
+#if defined(__sparc__) && defined(__arch64__)
+#include <asm/cmpxchg_64.h>
+#else
+#include <asm/cmpxchg_32.h>
+#endif
+#endif
diff --git a/arch/sparc/include/asm/cmpxchg_32.h b/arch/sparc/include/asm/cmpxchg_32.h
new file mode 100644
index 0000000..c786b0a
--- /dev/null
+++ b/arch/sparc/include/asm/cmpxchg_32.h
@@ -0,0 +1,112 @@
+/* 32-bit atomic xchg() and cmpxchg() definitions.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com.au)
+ * Copyright (C) 2007 Kyle McMartin (kyle@parisc-linux.org)
+ *
+ * Additions by Keith M Wesolowski (wesolows@foobazco.org) based
+ * on asm-parisc/atomic.h Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>.
+ */
+
+#ifndef __ARCH_SPARC_CMPXCHG__
+#define __ARCH_SPARC_CMPXCHG__
+
+#include <asm/btfixup.h>
+
+/* This has special calling conventions */
+#ifndef CONFIG_SMP
+BTFIXUPDEF_CALL(void, ___xchg32, void)
+#endif
+
+static inline unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned long val)
+{
+#ifdef CONFIG_SMP
+	__asm__ __volatile__("swap [%2], %0"
+			     : "=&r" (val)
+			     : "0" (val), "r" (m)
+			     : "memory");
+	return val;
+#else
+	register unsigned long *ptr asm("g1");
+	register unsigned long ret asm("g2");
+
+	ptr = (unsigned long *) m;
+	ret = val;
+
+	/* Note: this is magic and the nop there is
+	   really needed. */
+	__asm__ __volatile__(
+	"mov	%%o7, %%g4\n\t"
+	"call	___f____xchg32\n\t"
+	" nop\n\t"
+	: "=&r" (ret)
+	: "0" (ret), "r" (ptr)
+	: "g3", "g4", "g7", "memory", "cc");
+
+	return ret;
+#endif
+}
+
+extern void __xchg_called_with_bad_pointer(void);
+
+static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int size)
+{
+	switch (size) {
+	case 4:
+		return xchg_u32(ptr, x);
+	}
+	__xchg_called_with_bad_pointer();
+	return x;
+}
+
+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+/* Emulate cmpxchg() the same way we emulate atomics,
+ * by hashing the object address and indexing into an array
+ * of spinlocks to get a bit of performance...
+ *
+ * See arch/sparc/lib/atomic32.c for implementation.
+ *
+ * Cribbed from <asm-parisc/atomic.h>
+ */
+#define __HAVE_ARCH_CMPXCHG	1
+
+/* bug catcher for when unsupported size is used - won't link */
+extern void __cmpxchg_called_with_bad_pointer(void);
+/* we only need to support cmpxchg of a u32 on sparc */
+extern unsigned long __cmpxchg_u32(volatile u32 *m, u32 old, u32 new_);
+
+/* don't worry...optimizer will get rid of most of this */
+static inline unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32((u32 *)ptr, (u32)old, (u32)new_);
+	default:
+		__cmpxchg_called_with_bad_pointer();
+		break;
+	}
+	return old;
+}
+
+#define cmpxchg(ptr, o, n)						\
+({									\
+	__typeof__(*(ptr)) _o_ = (o);					\
+	__typeof__(*(ptr)) _n_ = (n);					\
+	(__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,	\
+			(unsigned long)_n_, sizeof(*(ptr)));		\
+})
+
+#include <asm-generic/cmpxchg-local.h>
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)				  	       \
+	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+			(unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#endif /* __ARCH_SPARC_CMPXCHG__ */
diff --git a/arch/sparc/include/asm/cmpxchg_64.h b/arch/sparc/include/asm/cmpxchg_64.h
new file mode 100644
index 0000000..b30eb37
--- /dev/null
+++ b/arch/sparc/include/asm/cmpxchg_64.h
@@ -0,0 +1,145 @@
+/* 64-bit atomic xchg() and cmpxchg() definitions.
+ *
+ * Copyright (C) 1996, 1997, 2000 David S. Miller (davem@redhat.com)
+ */
+
+#ifndef __ARCH_SPARC64_CMPXCHG__
+#define __ARCH_SPARC64_CMPXCHG__
+
+static inline unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val)
+{
+	unsigned long tmp1, tmp2;
+
+	__asm__ __volatile__(
+"	mov		%0, %1\n"
+"1:	lduw		[%4], %2\n"
+"	cas		[%4], %2, %0\n"
+"	cmp		%2, %0\n"
+"	bne,a,pn	%%icc, 1b\n"
+"	 mov		%1, %0\n"
+	: "=&r" (val), "=&r" (tmp1), "=&r" (tmp2)
+	: "0" (val), "r" (m)
+	: "cc", "memory");
+	return val;
+}
+
+static inline unsigned long xchg64(__volatile__ unsigned long *m, unsigned long val)
+{
+	unsigned long tmp1, tmp2;
+
+	__asm__ __volatile__(
+"	mov		%0, %1\n"
+"1:	ldx		[%4], %2\n"
+"	casx		[%4], %2, %0\n"
+"	cmp		%2, %0\n"
+"	bne,a,pn	%%xcc, 1b\n"
+"	 mov		%1, %0\n"
+	: "=&r" (val), "=&r" (tmp1), "=&r" (tmp2)
+	: "0" (val), "r" (m)
+	: "cc", "memory");
+	return val;
+}
+
+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+extern void __xchg_called_with_bad_pointer(void);
+
+static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr,
+				       int size)
+{
+	switch (size) {
+	case 4:
+		return xchg32(ptr, x);
+	case 8:
+		return xchg64(ptr, x);
+	}
+	__xchg_called_with_bad_pointer();
+	return x;
+}
+
+/*
+ * Atomic compare and exchange.  Compare OLD with MEM, if identical,
+ * store NEW in MEM.  Return the initial value in MEM.  Success is
+ * indicated by comparing RETURN with OLD.
+ */
+
+#include <asm-generic/cmpxchg-local.h>
+
+#define __HAVE_ARCH_CMPXCHG 1
+
+static inline unsigned long
+__cmpxchg_u32(volatile int *m, int old, int new)
+{
+	__asm__ __volatile__("cas [%2], %3, %0"
+			     : "=&r" (new)
+			     : "0" (new), "r" (m), "r" (old)
+			     : "memory");
+
+	return new;
+}
+
+static inline unsigned long
+__cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
+{
+	__asm__ __volatile__("casx [%2], %3, %0"
+			     : "=&r" (new)
+			     : "0" (new), "r" (m), "r" (old)
+			     : "memory");
+
+	return new;
+}
+
+/* This function doesn't exist, so you'll get a linker error
+   if something tries to do an invalid cmpxchg().  */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+static inline unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
+{
+	switch (size) {
+		case 4:
+			return __cmpxchg_u32(ptr, old, new);
+		case 8:
+			return __cmpxchg_u64(ptr, old, new);
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg(ptr,o,n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+				      unsigned long old,
+				      unsigned long new, int size)
+{
+	switch (size) {
+	case 4:
+	case 8:	return __cmpxchg(ptr, old, new, size);
+	default:
+		return __cmpxchg_local_generic(ptr, old, new, size);
+	}
+
+	return old;
+}
+
+#define cmpxchg_local(ptr, o, n)				  	\
+	((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o),	\
+			(unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n)					\
+  ({									\
+	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
+	cmpxchg_local((ptr), (o), (n));					\
+  })
+
+#endif /* __ARCH_SPARC64_CMPXCHG__ */
diff --git a/arch/sparc/include/asm/cpu_type.h b/arch/sparc/include/asm/cpu_type.h
new file mode 100644
index 0000000..4ca184d
--- /dev/null
+++ b/arch/sparc/include/asm/cpu_type.h
@@ -0,0 +1,34 @@
+#ifndef __ASM_CPU_TYPE_H
+#define __ASM_CPU_TYPE_H
+
+/*
+ * Sparc (general) CPU types
+ */
+enum sparc_cpu {
+  sun4        = 0x00,
+  sun4c       = 0x01,
+  sun4m       = 0x02,
+  sun4d       = 0x03,
+  sun4e       = 0x04,
+  sun4u       = 0x05, /* V8 ploos ploos */
+  sun_unknown = 0x06,
+  ap1000      = 0x07, /* almost a sun4m */
+  sparc_leon  = 0x08, /* Leon SoC */
+};
+
+#ifdef CONFIG_SPARC32
+extern enum sparc_cpu sparc_cpu_model;
+
+#define ARCH_SUN4C (sparc_cpu_model==sun4c)
+
+#define SUN4M_NCPUS            4              /* Architectural limit of sun4m. */
+
+#else
+
+#define sparc_cpu_model sun4u
+
+/* This cannot ever be a sun4c :) That's just history. */
+#define ARCH_SUN4C 0
+#endif
+
+#endif /* __ASM_CPU_TYPE_H */
diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h
index 8c0e4f7..48a7c65 100644
--- a/arch/sparc/include/asm/dma-mapping.h
+++ b/arch/sparc/include/asm/dma-mapping.h
@@ -26,24 +26,30 @@
 
 #include <asm-generic/dma-mapping-common.h>
 
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-				       dma_addr_t *dma_handle, gfp_t flag)
+#define dma_alloc_coherent(d,s,h,f)	dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+				    dma_addr_t *dma_handle, gfp_t flag,
+				    struct dma_attrs *attrs)
 {
 	struct dma_map_ops *ops = get_dma_ops(dev);
 	void *cpu_addr;
 
-	cpu_addr = ops->alloc_coherent(dev, size, dma_handle, flag);
+	cpu_addr = ops->alloc(dev, size, dma_handle, flag, attrs);
 	debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr);
 	return cpu_addr;
 }
 
-static inline void dma_free_coherent(struct device *dev, size_t size,
-				     void *cpu_addr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+				  void *cpu_addr, dma_addr_t dma_handle,
+				  struct dma_attrs *attrs)
 {
 	struct dma_map_ops *ops = get_dma_ops(dev);
 
 	debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
-	ops->free_coherent(dev, size, cpu_addr, dma_handle);
+	ops->free(dev, size, cpu_addr, dma_handle, attrs);
 }
 
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
diff --git a/arch/sparc/include/asm/exec.h b/arch/sparc/include/asm/exec.h
new file mode 100644
index 0000000..2e08588
--- /dev/null
+++ b/arch/sparc/include/asm/exec.h
@@ -0,0 +1,6 @@
+#ifndef __SPARC_EXEC_H
+#define __SPARC_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* __SPARC_EXEC_H */
diff --git a/arch/sparc/include/asm/floppy_32.h b/arch/sparc/include/asm/floppy_32.h
index 7440915..698d955 100644
--- a/arch/sparc/include/asm/floppy_32.h
+++ b/arch/sparc/include/asm/floppy_32.h
@@ -11,7 +11,6 @@
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>
 #include <asm/oplib.h>
diff --git a/arch/sparc/include/asm/futex_64.h b/arch/sparc/include/asm/futex_64.h
index 444e7be..4e899b0 100644
--- a/arch/sparc/include/asm/futex_64.h
+++ b/arch/sparc/include/asm/futex_64.h
@@ -4,7 +4,6 @@
 #include <linux/futex.h>
 #include <linux/uaccess.h>
 #include <asm/errno.h>
-#include <asm/system.h>
 
 #define __futex_cas_op(insn, ret, oldval, uaddr, oparg)	\
 	__asm__ __volatile__(				\
diff --git a/arch/sparc/include/asm/io_32.h b/arch/sparc/include/asm/io_32.h
index 2006e5d..c1acbd8 100644
--- a/arch/sparc/include/asm/io_32.h
+++ b/arch/sparc/include/asm/io_32.h
@@ -6,7 +6,6 @@
 #include <linux/ioport.h>  /* struct resource */
 
 #include <asm/page.h>      /* IO address mapping routines need this */
-#include <asm/system.h>
 #include <asm-generic/pci_iomap.h>
 
 #define page_to_phys(page)	(page_to_pfn(page) << PAGE_SHIFT)
diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h
index 9481e5a..09b0b88 100644
--- a/arch/sparc/include/asm/io_64.h
+++ b/arch/sparc/include/asm/io_64.h
@@ -6,7 +6,6 @@
 #include <linux/types.h>
 
 #include <asm/page.h>      /* IO address mapping routines need this */
-#include <asm/system.h>
 #include <asm/asi.h>
 #include <asm-generic/pci_iomap.h>
 
diff --git a/arch/sparc/include/asm/irq_64.h b/arch/sparc/include/asm/irq_64.h
index 16dcae6d..abf6afe 100644
--- a/arch/sparc/include/asm/irq_64.h
+++ b/arch/sparc/include/asm/irq_64.h
@@ -95,7 +95,6 @@
 extern void *hardirq_stack[NR_CPUS];
 extern void *softirq_stack[NR_CPUS];
 #define __ARCH_HAS_DO_SOFTIRQ
-#define ARCH_HAS_NMI_WATCHDOG
 
 #define NO_IRQ		0xffffffff
 
diff --git a/arch/sparc/include/asm/irqflags_32.h b/arch/sparc/include/asm/irqflags_32.h
index 1484890..e414c06 100644
--- a/arch/sparc/include/asm/irqflags_32.h
+++ b/arch/sparc/include/asm/irqflags_32.h
@@ -13,6 +13,7 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
+#include <asm/psr.h>
 
 extern void arch_local_irq_restore(unsigned long);
 extern unsigned long arch_local_irq_save(void);
diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h
index 666a73fe..a97fd08 100644
--- a/arch/sparc/include/asm/mmu_context_64.h
+++ b/arch/sparc/include/asm/mmu_context_64.h
@@ -6,7 +6,6 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/spinlock.h>
-#include <asm/system.h>
 #include <asm/spitfire.h>
 #include <asm-generic/mm_hooks.h>
 
diff --git a/arch/sparc/include/asm/ns87303.h b/arch/sparc/include/asm/ns87303.h
index af75548..6b947ee 100644
--- a/arch/sparc/include/asm/ns87303.h
+++ b/arch/sparc/include/asm/ns87303.h
@@ -79,7 +79,6 @@
 
 #include <linux/spinlock.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 
 extern spinlock_t ns87303_lock;
diff --git a/arch/sparc/include/asm/pci_32.h b/arch/sparc/include/asm/pci_32.h
index 6de7f7b..dc50329 100644
--- a/arch/sparc/include/asm/pci_32.h
+++ b/arch/sparc/include/asm/pci_32.h
@@ -52,14 +52,6 @@
  * 64Kbytes by the Host controller.
  */
 
-extern void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-			struct resource *res);
-
-extern void
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-			struct pci_bus_region *region);
-
 static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
 {
 	return PCI_IRQ_NONE;
diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h
index 755a4bb..1633b71 100644
--- a/arch/sparc/include/asm/pci_64.h
+++ b/arch/sparc/include/asm/pci_64.h
@@ -73,14 +73,6 @@
 			       enum pci_mmap_state mmap_state,
 			       int write_combine);
 
-extern void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-			struct resource *res);
-
-extern void
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-			struct pci_bus_region *region);
-
 static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
 {
 	return PCI_IRQ_NONE;
diff --git a/arch/sparc/include/asm/perfctr.h b/arch/sparc/include/asm/perfctr.h
index 8d8720a..3332d2c 100644
--- a/arch/sparc/include/asm/perfctr.h
+++ b/arch/sparc/include/asm/perfctr.h
@@ -168,6 +168,29 @@
   unsigned long long vcnt1;
 };
 
+#else /* !(__KERNEL__) */
+
+#ifndef CONFIG_SPARC32
+
+/* Performance counter register access. */
+#define read_pcr(__p)  __asm__ __volatile__("rd	%%pcr, %0" : "=r" (__p))
+#define write_pcr(__p) __asm__ __volatile__("wr	%0, 0x0, %%pcr" : : "r" (__p))
+#define read_pic(__p)  __asm__ __volatile__("rd %%pic, %0" : "=r" (__p))
+
+/* Blackbird errata workaround.  See commentary in
+ * arch/sparc64/kernel/smp.c:smp_percpu_timer_interrupt()
+ * for more information.
+ */
+#define write_pic(__p)  					\
+	__asm__ __volatile__("ba,pt	%%xcc, 99f\n\t"		\
+			     " nop\n\t"				\
+			     ".align	64\n"			\
+			  "99:wr	%0, 0x0, %%pic\n\t"	\
+			     "rd	%%pic, %%g0" : : "r" (__p))
+#define reset_pic()	write_pic(0)
+
+#endif /* !CONFIG_SPARC32 */
+
 #endif /* !(__KERNEL__) */
 
 #endif /* !(PERF_COUNTER_API) */
diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h
index a790cc6..3d71018 100644
--- a/arch/sparc/include/asm/pgtable_32.h
+++ b/arch/sparc/include/asm/pgtable_32.h
@@ -21,7 +21,7 @@
 #include <asm/vac-ops.h>
 #include <asm/oplib.h>
 #include <asm/btfixup.h>
-#include <asm/system.h>
+#include <asm/cpu_type.h>
 
 
 struct vm_area_struct;
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index 38ebb2c..76e4a52 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -12,17 +12,16 @@
  * the SpitFire page tables.
  */
 
-#include <asm-generic/pgtable-nopud.h>
-
 #include <linux/compiler.h>
 #include <linux/const.h>
 #include <asm/types.h>
 #include <asm/spitfire.h>
 #include <asm/asi.h>
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/processor.h>
 
+#include <asm-generic/pgtable-nopud.h>
+
 /* The kernel image occupies 0x4000000 to 0x6000000 (4MB --> 96MB).
  * The page copy blockops can use 0x6000000 to 0x8000000.
  * The TSB is mapped in the 0x8000000 to 0xa000000 range.
diff --git a/arch/sparc/include/asm/posix_types.h b/arch/sparc/include/asm/posix_types.h
index dbfc1a3..3070f25 100644
--- a/arch/sparc/include/asm/posix_types.h
+++ b/arch/sparc/include/asm/posix_types.h
@@ -9,35 +9,16 @@
 
 #if defined(__sparc__) && defined(__arch64__)
 /* sparc 64 bit */
-typedef unsigned long          __kernel_size_t;
-typedef long                   __kernel_ssize_t;
-typedef long                   __kernel_ptrdiff_t;
-typedef long                   __kernel_time_t;
-typedef long                   __kernel_clock_t;
-typedef int                    __kernel_pid_t;
-typedef int                    __kernel_ipc_pid_t;
-typedef unsigned int           __kernel_uid_t;
-typedef unsigned int           __kernel_gid_t;
-typedef unsigned long          __kernel_ino_t;
-typedef unsigned int           __kernel_mode_t;
 typedef unsigned int           __kernel_nlink_t;
-typedef int                    __kernel_daddr_t;
-typedef long                   __kernel_off_t;
-typedef char *                 __kernel_caddr_t;
-typedef unsigned short	       __kernel_uid16_t;
-typedef unsigned short	       __kernel_gid16_t;
-typedef int                    __kernel_clockid_t;
-typedef int                    __kernel_timer_t;
+#define __kernel_nlink_t __kernel_nlink_t
 
 typedef unsigned short 	       __kernel_old_uid_t;
 typedef unsigned short         __kernel_old_gid_t;
-typedef __kernel_uid_t	       __kernel_uid32_t;
-typedef __kernel_gid_t	       __kernel_gid32_t;
-
-typedef unsigned int	       __kernel_old_dev_t;
+#define __kernel_old_uid_t __kernel_old_uid_t
 
 /* Note this piece of asymmetry from the v9 ABI.  */
 typedef int		       __kernel_suseconds_t;
+#define __kernel_suseconds_t __kernel_suseconds_t
 
 #else
 /* sparc 32 bit */
@@ -45,109 +26,29 @@
 typedef unsigned int           __kernel_size_t;
 typedef int                    __kernel_ssize_t;
 typedef long int               __kernel_ptrdiff_t;
-typedef long                   __kernel_time_t;
-typedef long		       __kernel_suseconds_t;
-typedef long                   __kernel_clock_t;
-typedef int                    __kernel_pid_t;
+#define __kernel_size_t __kernel_size_t
+
 typedef unsigned short         __kernel_ipc_pid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
+
 typedef unsigned short         __kernel_uid_t;
 typedef unsigned short         __kernel_gid_t;
-typedef unsigned long          __kernel_ino_t;
+#define __kernel_uid_t __kernel_uid_t
+
 typedef unsigned short         __kernel_mode_t;
+#define __kernel_mode_t __kernel_mode_t
+
 typedef short                  __kernel_nlink_t;
+#define __kernel_nlink_t __kernel_nlink_t
+
 typedef long                   __kernel_daddr_t;
-typedef long                   __kernel_off_t;
-typedef char *                 __kernel_caddr_t;
-typedef unsigned short	       __kernel_uid16_t;
-typedef unsigned short	       __kernel_gid16_t;
-typedef unsigned int	       __kernel_uid32_t;
-typedef unsigned int	       __kernel_gid32_t;
-typedef unsigned short	       __kernel_old_uid_t;
-typedef unsigned short	       __kernel_old_gid_t;
+#define __kernel_daddr_t __kernel_daddr_t
+
 typedef unsigned short	       __kernel_old_dev_t;
-typedef int                    __kernel_clockid_t;
-typedef int                    __kernel_timer_t;
+#define __kernel_old_dev_t __kernel_old_dev_t
 
 #endif /* defined(__sparc__) && defined(__arch64__) */
 
-#ifdef __GNUC__
-typedef long long              __kernel_loff_t;
-#endif
+#include <asm-generic/posix_types.h>
 
-typedef struct {
-	int	val[2];
-} __kernel_fsid_t;
-
-#ifdef __KERNEL__
-
-#undef __FD_SET
-static inline void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	fdsetp->fds_bits[_tmp] |= (1UL<<_rem);
-}
-
-#undef __FD_CLR
-static inline void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem);
-}
-
-#undef __FD_ISSET
-static inline int __FD_ISSET(unsigned long fd, __const__ __kernel_fd_set *p)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0;
-}
-
-/*
- * This will unroll the loop for the normal constant cases (8 or 32 longs,
- * for 256 and 1024-bit fd_sets respectively)
- */
-#undef __FD_ZERO
-static inline void __FD_ZERO(__kernel_fd_set *p)
-{
-	unsigned long *tmp = p->fds_bits;
-	int i;
-
-	if (__builtin_constant_p(__FDSET_LONGS)) {
-		switch (__FDSET_LONGS) {
-			case 32:
-			  tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
-			  tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
-			  tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
-			  tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
-			  tmp[16] = 0; tmp[17] = 0; tmp[18] = 0; tmp[19] = 0;
-			  tmp[20] = 0; tmp[21] = 0; tmp[22] = 0; tmp[23] = 0;
-			  tmp[24] = 0; tmp[25] = 0; tmp[26] = 0; tmp[27] = 0;
-			  tmp[28] = 0; tmp[29] = 0; tmp[30] = 0; tmp[31] = 0;
-			  return;
-			case 16:
-			  tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
-			  tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
-			  tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
-			  tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
-			  return;
-			case 8:
-			  tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
-			  tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
-			  return;
-			case 4:
-			  tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
-			  return;
-		}
-	}
-	i = __FDSET_LONGS;
-	while (i) {
-		i--;
-		*tmp = 0;
-		tmp++;
-	}
-}
-
-#endif /* __KERNEL__ */
 #endif /* __SPARC_POSIX_TYPES_H */
diff --git a/arch/sparc/include/asm/processor.h b/arch/sparc/include/asm/processor.h
index 9da9646..2fe99e6 100644
--- a/arch/sparc/include/asm/processor.h
+++ b/arch/sparc/include/asm/processor.h
@@ -5,4 +5,7 @@
 #else
 #include <asm/processor_32.h>
 #endif
+
+#define nop() 		__asm__ __volatile__ ("nop")
+
 #endif
diff --git a/arch/sparc/include/asm/processor_64.h b/arch/sparc/include/asm/processor_64.h
index 59fcebb..e713db2 100644
--- a/arch/sparc/include/asm/processor_64.h
+++ b/arch/sparc/include/asm/processor_64.h
@@ -18,6 +18,9 @@
 #include <asm/ptrace.h>
 #include <asm/page.h>
 
+/* Don't hold the runqueue lock over context switch */
+#define __ARCH_WANT_UNLOCKED_CTXSW
+
 /* The sparc has no problems with write protection */
 #define wp_works_ok 1
 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */
diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h
index c00c3b5..fd9c3f2 100644
--- a/arch/sparc/include/asm/ptrace.h
+++ b/arch/sparc/include/asm/ptrace.h
@@ -98,6 +98,8 @@
  */
 #ifndef __ASSEMBLY__
 
+#include <linux/types.h>
+
 struct pt_regs {
 	unsigned long psr;
 	unsigned long pc;
@@ -163,7 +165,7 @@
 #ifdef __KERNEL__
 
 #include <linux/threads.h>
-#include <asm/system.h>
+#include <asm/switch_to.h>
 
 static inline int pt_regs_trap_type(struct pt_regs *regs)
 {
@@ -239,8 +241,7 @@
 #ifndef __ASSEMBLY__
 
 #ifdef __KERNEL__
-
-#include <asm/system.h>
+#include <asm/switch_to.h>
 
 static inline bool pt_regs_is_syscall(struct pt_regs *regs)
 {
diff --git a/arch/sparc/include/asm/setup.h b/arch/sparc/include/asm/setup.h
index 64718ba..00497ab 100644
--- a/arch/sparc/include/asm/setup.h
+++ b/arch/sparc/include/asm/setup.h
@@ -13,14 +13,30 @@
 
 #ifdef __KERNEL__
 
+extern char reboot_command[];
+
 #ifdef CONFIG_SPARC32
 /* The CPU that was used for booting
  * Only sun4d + leon may have boot_cpu_id != 0
  */
 extern unsigned char boot_cpu_id;
 extern unsigned char boot_cpu_id4;
+
+extern unsigned long empty_bad_page;
+extern unsigned long empty_bad_page_table;
+extern unsigned long empty_zero_page;
+
+extern int serial_console;
+static inline int con_is_present(void)
+{
+	return serial_console ? 0 : 1;
+}
 #endif
 
+extern void sun_do_break(void);
+extern int stop_a_enabled;
+extern int scons_pwroff;
+
 #endif /* __KERNEL__ */
 
 #endif /* _SPARC_SETUP_H */
diff --git a/arch/sparc/include/asm/switch_to.h b/arch/sparc/include/asm/switch_to.h
new file mode 100644
index 0000000..2dc4fa5
--- /dev/null
+++ b/arch/sparc/include/asm/switch_to.h
@@ -0,0 +1,8 @@
+#ifndef ___ASM_SPARC_SWITCH_TO_H
+#define ___ASM_SPARC_SWITCH_TO_H
+#if defined(__sparc__) && defined(__arch64__)
+#include <asm/switch_to_64.h>
+#else
+#include <asm/switch_to_32.h>
+#endif
+#endif
diff --git a/arch/sparc/include/asm/switch_to_32.h b/arch/sparc/include/asm/switch_to_32.h
new file mode 100644
index 0000000..e32e82b
--- /dev/null
+++ b/arch/sparc/include/asm/switch_to_32.h
@@ -0,0 +1,106 @@
+#ifndef __SPARC_SWITCH_TO_H
+#define __SPARC_SWITCH_TO_H
+
+#include <asm/smp.h>
+
+extern struct thread_info *current_set[NR_CPUS];
+
+/*
+ * Flush windows so that the VM switch which follows
+ * would not pull the stack from under us.
+ *
+ * SWITCH_ENTER and SWITH_DO_LAZY_FPU do not work yet (e.g. SMP does not work)
+ * XXX WTF is the above comment? Found in late teen 2.4.x.
+ */
+#ifdef CONFIG_SMP
+#define SWITCH_ENTER(prv) \
+	do {			\
+	if (test_tsk_thread_flag(prv, TIF_USEDFPU)) { \
+		put_psr(get_psr() | PSR_EF); \
+		fpsave(&(prv)->thread.float_regs[0], &(prv)->thread.fsr, \
+		       &(prv)->thread.fpqueue[0], &(prv)->thread.fpqdepth); \
+		clear_tsk_thread_flag(prv, TIF_USEDFPU); \
+		(prv)->thread.kregs->psr &= ~PSR_EF; \
+	} \
+	} while(0)
+
+#define SWITCH_DO_LAZY_FPU(next)	/* */
+#else
+#define SWITCH_ENTER(prv)		/* */
+#define SWITCH_DO_LAZY_FPU(nxt)	\
+	do {			\
+	if (last_task_used_math != (nxt))		\
+		(nxt)->thread.kregs->psr&=~PSR_EF;	\
+	} while(0)
+#endif
+
+#define prepare_arch_switch(next) do { \
+	__asm__ __volatile__( \
+	".globl\tflush_patch_switch\nflush_patch_switch:\n\t" \
+	"save %sp, -0x40, %sp; save %sp, -0x40, %sp; save %sp, -0x40, %sp\n\t" \
+	"save %sp, -0x40, %sp; save %sp, -0x40, %sp; save %sp, -0x40, %sp\n\t" \
+	"save %sp, -0x40, %sp\n\t" \
+	"restore; restore; restore; restore; restore; restore; restore"); \
+} while(0)
+
+	/* Much care has gone into this code, do not touch it.
+	 *
+	 * We need to loadup regs l0/l1 for the newly forked child
+	 * case because the trap return path relies on those registers
+	 * holding certain values, gcc is told that they are clobbered.
+	 * Gcc needs registers for 3 values in and 1 value out, so we
+	 * clobber every non-fixed-usage register besides l2/l3/o4/o5.  -DaveM
+	 *
+	 * Hey Dave, that do not touch sign is too much of an incentive
+	 * - Anton & Pete
+	 */
+#define switch_to(prev, next, last) do {						\
+	SWITCH_ENTER(prev);								\
+	SWITCH_DO_LAZY_FPU(next);							\
+	cpumask_set_cpu(smp_processor_id(), mm_cpumask(next->active_mm));		\
+	__asm__ __volatile__(								\
+	"sethi	%%hi(here - 0x8), %%o7\n\t"						\
+	"mov	%%g6, %%g3\n\t"								\
+	"or	%%o7, %%lo(here - 0x8), %%o7\n\t"					\
+	"rd	%%psr, %%g4\n\t"							\
+	"std	%%sp, [%%g6 + %4]\n\t"							\
+	"rd	%%wim, %%g5\n\t"							\
+	"wr	%%g4, 0x20, %%psr\n\t"							\
+	"nop\n\t"									\
+	"std	%%g4, [%%g6 + %3]\n\t"							\
+	"ldd	[%2 + %3], %%g4\n\t"							\
+	"mov	%2, %%g6\n\t"								\
+	".globl	patchme_store_new_current\n"						\
+"patchme_store_new_current:\n\t"							\
+	"st	%2, [%1]\n\t"								\
+	"wr	%%g4, 0x20, %%psr\n\t"							\
+	"nop\n\t"									\
+	"nop\n\t"									\
+	"nop\n\t"	/* LEON needs all 3 nops: load to %sp depends on CWP. */		\
+	"ldd	[%%g6 + %4], %%sp\n\t"							\
+	"wr	%%g5, 0x0, %%wim\n\t"							\
+	"ldd	[%%sp + 0x00], %%l0\n\t"						\
+	"ldd	[%%sp + 0x38], %%i6\n\t"						\
+	"wr	%%g4, 0x0, %%psr\n\t"							\
+	"nop\n\t"									\
+	"nop\n\t"									\
+	"jmpl	%%o7 + 0x8, %%g0\n\t"							\
+	" ld	[%%g3 + %5], %0\n\t"							\
+	"here:\n"									\
+        : "=&r" (last)									\
+        : "r" (&(current_set[hard_smp_processor_id()])),	\
+	  "r" (task_thread_info(next)),				\
+	  "i" (TI_KPSR),					\
+	  "i" (TI_KSP),						\
+	  "i" (TI_TASK)						\
+	:       "g1", "g2", "g3", "g4", "g5",       "g7",	\
+	  "l0", "l1",       "l3", "l4", "l5", "l6", "l7",	\
+	  "i0", "i1", "i2", "i3", "i4", "i5",			\
+	  "o0", "o1", "o2", "o3",                   "o7");	\
+	} while(0)
+
+extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
+		   void *fpqueue, unsigned long *fpqdepth);
+extern void synchronize_user_stack(void);
+
+#endif /* __SPARC_SWITCH_TO_H */
diff --git a/arch/sparc/include/asm/switch_to_64.h b/arch/sparc/include/asm/switch_to_64.h
new file mode 100644
index 0000000..7923c4a
--- /dev/null
+++ b/arch/sparc/include/asm/switch_to_64.h
@@ -0,0 +1,72 @@
+#ifndef __SPARC64_SWITCH_TO_64_H
+#define __SPARC64_SWITCH_TO_64_H
+
+#include <asm/visasm.h>
+
+#define prepare_arch_switch(next)		\
+do {						\
+	flushw_all();				\
+} while (0)
+
+	/* See what happens when you design the chip correctly?
+	 *
+	 * We tell gcc we clobber all non-fixed-usage registers except
+	 * for l0/l1.  It will use one for 'next' and the other to hold
+	 * the output value of 'last'.  'next' is not referenced again
+	 * past the invocation of switch_to in the scheduler, so we need
+	 * not preserve it's value.  Hairy, but it lets us remove 2 loads
+	 * and 2 stores in this critical code path.  -DaveM
+	 */
+#define switch_to(prev, next, last)					\
+do {	flush_tlb_pending();						\
+	save_and_clear_fpu();						\
+	/* If you are tempted to conditionalize the following */	\
+	/* so that ASI is only written if it changes, think again. */	\
+	__asm__ __volatile__("wr %%g0, %0, %%asi"			\
+	: : "r" (__thread_flag_byte_ptr(task_thread_info(next))[TI_FLAG_BYTE_CURRENT_DS]));\
+	trap_block[current_thread_info()->cpu].thread =			\
+		task_thread_info(next);					\
+	__asm__ __volatile__(						\
+	"mov	%%g4, %%g7\n\t"						\
+	"stx	%%i6, [%%sp + 2047 + 0x70]\n\t"				\
+	"stx	%%i7, [%%sp + 2047 + 0x78]\n\t"				\
+	"rdpr	%%wstate, %%o5\n\t"					\
+	"stx	%%o6, [%%g6 + %6]\n\t"					\
+	"stb	%%o5, [%%g6 + %5]\n\t"					\
+	"rdpr	%%cwp, %%o5\n\t"					\
+	"stb	%%o5, [%%g6 + %8]\n\t"					\
+	"wrpr	%%g0, 15, %%pil\n\t"					\
+	"mov	%4, %%g6\n\t"						\
+	"ldub	[%4 + %8], %%g1\n\t"					\
+	"wrpr	%%g1, %%cwp\n\t"					\
+	"ldx	[%%g6 + %6], %%o6\n\t"					\
+	"ldub	[%%g6 + %5], %%o5\n\t"					\
+	"ldub	[%%g6 + %7], %%o7\n\t"					\
+	"wrpr	%%o5, 0x0, %%wstate\n\t"				\
+	"ldx	[%%sp + 2047 + 0x70], %%i6\n\t"				\
+	"ldx	[%%sp + 2047 + 0x78], %%i7\n\t"				\
+	"ldx	[%%g6 + %9], %%g4\n\t"					\
+	"wrpr	%%g0, 14, %%pil\n\t"					\
+	"brz,pt %%o7, switch_to_pc\n\t"					\
+	" mov	%%g7, %0\n\t"						\
+	"sethi	%%hi(ret_from_syscall), %%g1\n\t"			\
+	"jmpl	%%g1 + %%lo(ret_from_syscall), %%g0\n\t"		\
+	" nop\n\t"							\
+	".globl switch_to_pc\n\t"					\
+	"switch_to_pc:\n\t"						\
+	: "=&r" (last), "=r" (current), "=r" (current_thread_info_reg),	\
+	  "=r" (__local_per_cpu_offset)					\
+	: "0" (task_thread_info(next)),					\
+	  "i" (TI_WSTATE), "i" (TI_KSP), "i" (TI_NEW_CHILD),            \
+	  "i" (TI_CWP), "i" (TI_TASK)					\
+	: "cc",								\
+	        "g1", "g2", "g3",                   "g7",		\
+	        "l1", "l2", "l3", "l4", "l5", "l6", "l7",		\
+	  "i0", "i1", "i2", "i3", "i4", "i5",				\
+	  "o0", "o1", "o2", "o3", "o4", "o5",       "o7");		\
+} while(0)
+
+extern void synchronize_user_stack(void);
+extern void fault_in_user_windows(void);
+
+#endif /* __SPARC64_SWITCH_TO_64_H */
diff --git a/arch/sparc/include/asm/system.h b/arch/sparc/include/asm/system.h
deleted file mode 100644
index 7944a7c..0000000
--- a/arch/sparc/include/asm/system.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_SYSTEM_H
-#define ___ASM_SPARC_SYSTEM_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/system_64.h>
-#else
-#include <asm/system_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/system_32.h b/arch/sparc/include/asm/system_32.h
deleted file mode 100644
index aba1609..0000000
--- a/arch/sparc/include/asm/system_32.h
+++ /dev/null
@@ -1,284 +0,0 @@
-#ifndef __SPARC_SYSTEM_H
-#define __SPARC_SYSTEM_H
-
-#include <linux/kernel.h>
-#include <linux/threads.h>	/* NR_CPUS */
-#include <linux/thread_info.h>
-
-#include <asm/page.h>
-#include <asm/psr.h>
-#include <asm/ptrace.h>
-#include <asm/btfixup.h>
-#include <asm/smp.h>
-
-#ifndef __ASSEMBLY__
-
-#include <linux/irqflags.h>
-
-/*
- * Sparc (general) CPU types
- */
-enum sparc_cpu {
-  sun4        = 0x00,
-  sun4c       = 0x01,
-  sun4m       = 0x02,
-  sun4d       = 0x03,
-  sun4e       = 0x04,
-  sun4u       = 0x05, /* V8 ploos ploos */
-  sun_unknown = 0x06,
-  ap1000      = 0x07, /* almost a sun4m */
-  sparc_leon  = 0x08, /* Leon SoC */
-};
-
-/* Really, userland should not be looking at any of this... */
-#ifdef __KERNEL__
-
-extern enum sparc_cpu sparc_cpu_model;
-
-#define ARCH_SUN4C (sparc_cpu_model==sun4c)
-
-#define SUN4M_NCPUS            4              /* Architectural limit of sun4m. */
-
-extern char reboot_command[];
-
-extern struct thread_info *current_set[NR_CPUS];
-
-extern unsigned long empty_bad_page;
-extern unsigned long empty_bad_page_table;
-extern unsigned long empty_zero_page;
-
-extern void sun_do_break(void);
-extern int serial_console;
-extern int stop_a_enabled;
-extern int scons_pwroff;
-
-static inline int con_is_present(void)
-{
-	return serial_console ? 0 : 1;
-}
-
-/* When a context switch happens we must flush all user windows so that
- * the windows of the current process are flushed onto its stack. This
- * way the windows are all clean for the next process and the stack
- * frames are up to date.
- */
-extern void flush_user_windows(void);
-extern void kill_user_windows(void);
-extern void synchronize_user_stack(void);
-extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
-		   void *fpqueue, unsigned long *fpqdepth);
-
-#ifdef CONFIG_SMP
-#define SWITCH_ENTER(prv) \
-	do {			\
-	if (test_tsk_thread_flag(prv, TIF_USEDFPU)) { \
-		put_psr(get_psr() | PSR_EF); \
-		fpsave(&(prv)->thread.float_regs[0], &(prv)->thread.fsr, \
-		       &(prv)->thread.fpqueue[0], &(prv)->thread.fpqdepth); \
-		clear_tsk_thread_flag(prv, TIF_USEDFPU); \
-		(prv)->thread.kregs->psr &= ~PSR_EF; \
-	} \
-	} while(0)
-
-#define SWITCH_DO_LAZY_FPU(next)	/* */
-#else
-#define SWITCH_ENTER(prv)		/* */
-#define SWITCH_DO_LAZY_FPU(nxt)	\
-	do {			\
-	if (last_task_used_math != (nxt))		\
-		(nxt)->thread.kregs->psr&=~PSR_EF;	\
-	} while(0)
-#endif
-
-extern void flushw_all(void);
-
-/*
- * Flush windows so that the VM switch which follows
- * would not pull the stack from under us.
- *
- * SWITCH_ENTER and SWITH_DO_LAZY_FPU do not work yet (e.g. SMP does not work)
- * XXX WTF is the above comment? Found in late teen 2.4.x.
- */
-#define prepare_arch_switch(next) do { \
-	__asm__ __volatile__( \
-	".globl\tflush_patch_switch\nflush_patch_switch:\n\t" \
-	"save %sp, -0x40, %sp; save %sp, -0x40, %sp; save %sp, -0x40, %sp\n\t" \
-	"save %sp, -0x40, %sp; save %sp, -0x40, %sp; save %sp, -0x40, %sp\n\t" \
-	"save %sp, -0x40, %sp\n\t" \
-	"restore; restore; restore; restore; restore; restore; restore"); \
-} while(0)
-
-	/* Much care has gone into this code, do not touch it.
-	 *
-	 * We need to loadup regs l0/l1 for the newly forked child
-	 * case because the trap return path relies on those registers
-	 * holding certain values, gcc is told that they are clobbered.
-	 * Gcc needs registers for 3 values in and 1 value out, so we
-	 * clobber every non-fixed-usage register besides l2/l3/o4/o5.  -DaveM
-	 *
-	 * Hey Dave, that do not touch sign is too much of an incentive
-	 * - Anton & Pete
-	 */
-#define switch_to(prev, next, last) do {						\
-	SWITCH_ENTER(prev);								\
-	SWITCH_DO_LAZY_FPU(next);							\
-	cpumask_set_cpu(smp_processor_id(), mm_cpumask(next->active_mm));		\
-	__asm__ __volatile__(								\
-	"sethi	%%hi(here - 0x8), %%o7\n\t"						\
-	"mov	%%g6, %%g3\n\t"								\
-	"or	%%o7, %%lo(here - 0x8), %%o7\n\t"					\
-	"rd	%%psr, %%g4\n\t"							\
-	"std	%%sp, [%%g6 + %4]\n\t"							\
-	"rd	%%wim, %%g5\n\t"							\
-	"wr	%%g4, 0x20, %%psr\n\t"							\
-	"nop\n\t"									\
-	"std	%%g4, [%%g6 + %3]\n\t"							\
-	"ldd	[%2 + %3], %%g4\n\t"							\
-	"mov	%2, %%g6\n\t"								\
-	".globl	patchme_store_new_current\n"						\
-"patchme_store_new_current:\n\t"							\
-	"st	%2, [%1]\n\t"								\
-	"wr	%%g4, 0x20, %%psr\n\t"							\
-	"nop\n\t"									\
-	"nop\n\t"									\
-	"nop\n\t"	/* LEON needs all 3 nops: load to %sp depends on CWP. */		\
-	"ldd	[%%g6 + %4], %%sp\n\t"							\
-	"wr	%%g5, 0x0, %%wim\n\t"							\
-	"ldd	[%%sp + 0x00], %%l0\n\t"						\
-	"ldd	[%%sp + 0x38], %%i6\n\t"						\
-	"wr	%%g4, 0x0, %%psr\n\t"							\
-	"nop\n\t"									\
-	"nop\n\t"									\
-	"jmpl	%%o7 + 0x8, %%g0\n\t"							\
-	" ld	[%%g3 + %5], %0\n\t"							\
-	"here:\n"									\
-        : "=&r" (last)									\
-        : "r" (&(current_set[hard_smp_processor_id()])),	\
-	  "r" (task_thread_info(next)),				\
-	  "i" (TI_KPSR),					\
-	  "i" (TI_KSP),						\
-	  "i" (TI_TASK)						\
-	:       "g1", "g2", "g3", "g4", "g5",       "g7",	\
-	  "l0", "l1",       "l3", "l4", "l5", "l6", "l7",	\
-	  "i0", "i1", "i2", "i3", "i4", "i5",			\
-	  "o0", "o1", "o2", "o3",                   "o7");	\
-	} while(0)
-
-/* XXX Change this if we ever use a PSO mode kernel. */
-#define mb()	__asm__ __volatile__ ("" : : : "memory")
-#define rmb()	mb()
-#define wmb()	mb()
-#define read_barrier_depends()	do { } while(0)
-#define set_mb(__var, __value)  do { __var = __value; mb(); } while(0)
-#define smp_mb()	__asm__ __volatile__("":::"memory")
-#define smp_rmb()	__asm__ __volatile__("":::"memory")
-#define smp_wmb()	__asm__ __volatile__("":::"memory")
-#define smp_read_barrier_depends()	do { } while(0)
-
-#define nop() __asm__ __volatile__ ("nop")
-
-/* This has special calling conventions */
-#ifndef CONFIG_SMP
-BTFIXUPDEF_CALL(void, ___xchg32, void)
-#endif
-
-static inline unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned long val)
-{
-#ifdef CONFIG_SMP
-	__asm__ __volatile__("swap [%2], %0"
-			     : "=&r" (val)
-			     : "0" (val), "r" (m)
-			     : "memory");
-	return val;
-#else
-	register unsigned long *ptr asm("g1");
-	register unsigned long ret asm("g2");
-
-	ptr = (unsigned long *) m;
-	ret = val;
-
-	/* Note: this is magic and the nop there is
-	   really needed. */
-	__asm__ __volatile__(
-	"mov	%%o7, %%g4\n\t"
-	"call	___f____xchg32\n\t"
-	" nop\n\t"
-	: "=&r" (ret)
-	: "0" (ret), "r" (ptr)
-	: "g3", "g4", "g7", "memory", "cc");
-
-	return ret;
-#endif
-}
-
-#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-
-extern void __xchg_called_with_bad_pointer(void);
-
-static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int size)
-{
-	switch (size) {
-	case 4:
-		return xchg_u32(ptr, x);
-	}
-	__xchg_called_with_bad_pointer();
-	return x;
-}
-
-/* Emulate cmpxchg() the same way we emulate atomics,
- * by hashing the object address and indexing into an array
- * of spinlocks to get a bit of performance...
- *
- * See arch/sparc/lib/atomic32.c for implementation.
- *
- * Cribbed from <asm-parisc/atomic.h>
- */
-#define __HAVE_ARCH_CMPXCHG	1
-
-/* bug catcher for when unsupported size is used - won't link */
-extern void __cmpxchg_called_with_bad_pointer(void);
-/* we only need to support cmpxchg of a u32 on sparc */
-extern unsigned long __cmpxchg_u32(volatile u32 *m, u32 old, u32 new_);
-
-/* don't worry...optimizer will get rid of most of this */
-static inline unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
-{
-	switch (size) {
-	case 4:
-		return __cmpxchg_u32((u32 *)ptr, (u32)old, (u32)new_);
-	default:
-		__cmpxchg_called_with_bad_pointer();
-		break;
-	}
-	return old;
-}
-
-#define cmpxchg(ptr, o, n)						\
-({									\
-	__typeof__(*(ptr)) _o_ = (o);					\
-	__typeof__(*(ptr)) _n_ = (n);					\
-	(__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,	\
-			(unsigned long)_n_, sizeof(*(ptr)));		\
-})
-
-#include <asm-generic/cmpxchg-local.h>
-
-/*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
- */
-#define cmpxchg_local(ptr, o, n)				  	       \
-	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
-			(unsigned long)(n), sizeof(*(ptr))))
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-
-extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn));
-
-#endif /* __KERNEL__ */
-
-#endif /* __ASSEMBLY__ */
-
-#define arch_align_stack(x) (x)
-
-#endif /* !(__SPARC_SYSTEM_H) */
diff --git a/arch/sparc/include/asm/system_64.h b/arch/sparc/include/asm/system_64.h
deleted file mode 100644
index 10bcabc..0000000
--- a/arch/sparc/include/asm/system_64.h
+++ /dev/null
@@ -1,331 +0,0 @@
-#ifndef __SPARC64_SYSTEM_H
-#define __SPARC64_SYSTEM_H
-
-#include <asm/ptrace.h>
-#include <asm/processor.h>
-#include <asm/visasm.h>
-
-#ifndef __ASSEMBLY__
-
-#include <linux/irqflags.h>
-#include <asm-generic/cmpxchg-local.h>
-
-/*
- * Sparc (general) CPU types
- */
-enum sparc_cpu {
-  sun4        = 0x00,
-  sun4c       = 0x01,
-  sun4m       = 0x02,
-  sun4d       = 0x03,
-  sun4e       = 0x04,
-  sun4u       = 0x05, /* V8 ploos ploos */
-  sun_unknown = 0x06,
-  ap1000      = 0x07, /* almost a sun4m */
-};
-
-#define sparc_cpu_model sun4u
-
-/* This cannot ever be a sun4c :) That's just history. */
-#define ARCH_SUN4C 0
-
-extern char reboot_command[];
-
-/* These are here in an effort to more fully work around Spitfire Errata
- * #51.  Essentially, if a memory barrier occurs soon after a mispredicted
- * branch, the chip can stop executing instructions until a trap occurs.
- * Therefore, if interrupts are disabled, the chip can hang forever.
- *
- * It used to be believed that the memory barrier had to be right in the
- * delay slot, but a case has been traced recently wherein the memory barrier
- * was one instruction after the branch delay slot and the chip still hung.
- * The offending sequence was the following in sym_wakeup_done() of the
- * sym53c8xx_2 driver:
- *
- *	call	sym_ccb_from_dsa, 0
- *	 movge	%icc, 0, %l0
- *	brz,pn	%o0, .LL1303
- *	 mov	%o0, %l2
- *	membar	#LoadLoad
- *
- * The branch has to be mispredicted for the bug to occur.  Therefore, we put
- * the memory barrier explicitly into a "branch always, predicted taken"
- * delay slot to avoid the problem case.
- */
-#define membar_safe(type) \
-do {	__asm__ __volatile__("ba,pt	%%xcc, 1f\n\t" \
-			     " membar	" type "\n" \
-			     "1:\n" \
-			     : : : "memory"); \
-} while (0)
-
-/* The kernel always executes in TSO memory model these days,
- * and furthermore most sparc64 chips implement more stringent
- * memory ordering than required by the specifications.
- */
-#define mb()	membar_safe("#StoreLoad")
-#define rmb()	__asm__ __volatile__("":::"memory")
-#define wmb()	__asm__ __volatile__("":::"memory")
-
-#endif
-
-#define nop() 		__asm__ __volatile__ ("nop")
-
-#define read_barrier_depends()		do { } while(0)
-#define set_mb(__var, __value) \
-	do { __var = __value; membar_safe("#StoreLoad"); } while(0)
-
-#ifdef CONFIG_SMP
-#define smp_mb()	mb()
-#define smp_rmb()	rmb()
-#define smp_wmb()	wmb()
-#else
-#define smp_mb()	__asm__ __volatile__("":::"memory")
-#define smp_rmb()	__asm__ __volatile__("":::"memory")
-#define smp_wmb()	__asm__ __volatile__("":::"memory")
-#endif
-
-#define smp_read_barrier_depends()	do { } while(0)
-
-#define flushi(addr)	__asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory")
-
-#define flushw_all()	__asm__ __volatile__("flushw")
-
-/* Performance counter register access. */
-#define read_pcr(__p)  __asm__ __volatile__("rd	%%pcr, %0" : "=r" (__p))
-#define write_pcr(__p) __asm__ __volatile__("wr	%0, 0x0, %%pcr" : : "r" (__p))
-#define read_pic(__p)  __asm__ __volatile__("rd %%pic, %0" : "=r" (__p))
-
-/* Blackbird errata workaround.  See commentary in
- * arch/sparc64/kernel/smp.c:smp_percpu_timer_interrupt()
- * for more information.
- */
-#define write_pic(__p)  					\
-	__asm__ __volatile__("ba,pt	%%xcc, 99f\n\t"		\
-			     " nop\n\t"				\
-			     ".align	64\n"			\
-			  "99:wr	%0, 0x0, %%pic\n\t"	\
-			     "rd	%%pic, %%g0" : : "r" (__p))
-#define reset_pic()	write_pic(0)
-
-#ifndef __ASSEMBLY__
-
-extern void sun_do_break(void);
-extern int stop_a_enabled;
-extern int scons_pwroff;
-
-extern void fault_in_user_windows(void);
-extern void synchronize_user_stack(void);
-
-extern void __flushw_user(void);
-#define flushw_user() __flushw_user()
-
-#define flush_user_windows flushw_user
-#define flush_register_windows flushw_all
-
-/* Don't hold the runqueue lock over context switch */
-#define __ARCH_WANT_UNLOCKED_CTXSW
-#define prepare_arch_switch(next)		\
-do {						\
-	flushw_all();				\
-} while (0)
-
-	/* See what happens when you design the chip correctly?
-	 *
-	 * We tell gcc we clobber all non-fixed-usage registers except
-	 * for l0/l1.  It will use one for 'next' and the other to hold
-	 * the output value of 'last'.  'next' is not referenced again
-	 * past the invocation of switch_to in the scheduler, so we need
-	 * not preserve it's value.  Hairy, but it lets us remove 2 loads
-	 * and 2 stores in this critical code path.  -DaveM
-	 */
-#define switch_to(prev, next, last)					\
-do {	flush_tlb_pending();						\
-	save_and_clear_fpu();						\
-	/* If you are tempted to conditionalize the following */	\
-	/* so that ASI is only written if it changes, think again. */	\
-	__asm__ __volatile__("wr %%g0, %0, %%asi"			\
-	: : "r" (__thread_flag_byte_ptr(task_thread_info(next))[TI_FLAG_BYTE_CURRENT_DS]));\
-	trap_block[current_thread_info()->cpu].thread =			\
-		task_thread_info(next);					\
-	__asm__ __volatile__(						\
-	"mov	%%g4, %%g7\n\t"						\
-	"stx	%%i6, [%%sp + 2047 + 0x70]\n\t"				\
-	"stx	%%i7, [%%sp + 2047 + 0x78]\n\t"				\
-	"rdpr	%%wstate, %%o5\n\t"					\
-	"stx	%%o6, [%%g6 + %6]\n\t"					\
-	"stb	%%o5, [%%g6 + %5]\n\t"					\
-	"rdpr	%%cwp, %%o5\n\t"					\
-	"stb	%%o5, [%%g6 + %8]\n\t"					\
-	"wrpr	%%g0, 15, %%pil\n\t"					\
-	"mov	%4, %%g6\n\t"						\
-	"ldub	[%4 + %8], %%g1\n\t"					\
-	"wrpr	%%g1, %%cwp\n\t"					\
-	"ldx	[%%g6 + %6], %%o6\n\t"					\
-	"ldub	[%%g6 + %5], %%o5\n\t"					\
-	"ldub	[%%g6 + %7], %%o7\n\t"					\
-	"wrpr	%%o5, 0x0, %%wstate\n\t"				\
-	"ldx	[%%sp + 2047 + 0x70], %%i6\n\t"				\
-	"ldx	[%%sp + 2047 + 0x78], %%i7\n\t"				\
-	"ldx	[%%g6 + %9], %%g4\n\t"					\
-	"wrpr	%%g0, 14, %%pil\n\t"					\
-	"brz,pt %%o7, switch_to_pc\n\t"					\
-	" mov	%%g7, %0\n\t"						\
-	"sethi	%%hi(ret_from_syscall), %%g1\n\t"			\
-	"jmpl	%%g1 + %%lo(ret_from_syscall), %%g0\n\t"		\
-	" nop\n\t"							\
-	".globl switch_to_pc\n\t"					\
-	"switch_to_pc:\n\t"						\
-	: "=&r" (last), "=r" (current), "=r" (current_thread_info_reg),	\
-	  "=r" (__local_per_cpu_offset)					\
-	: "0" (task_thread_info(next)),					\
-	  "i" (TI_WSTATE), "i" (TI_KSP), "i" (TI_NEW_CHILD),            \
-	  "i" (TI_CWP), "i" (TI_TASK)					\
-	: "cc",								\
-	        "g1", "g2", "g3",                   "g7",		\
-	        "l1", "l2", "l3", "l4", "l5", "l6", "l7",		\
-	  "i0", "i1", "i2", "i3", "i4", "i5",				\
-	  "o0", "o1", "o2", "o3", "o4", "o5",       "o7");		\
-} while(0)
-
-static inline unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val)
-{
-	unsigned long tmp1, tmp2;
-
-	__asm__ __volatile__(
-"	mov		%0, %1\n"
-"1:	lduw		[%4], %2\n"
-"	cas		[%4], %2, %0\n"
-"	cmp		%2, %0\n"
-"	bne,a,pn	%%icc, 1b\n"
-"	 mov		%1, %0\n"
-	: "=&r" (val), "=&r" (tmp1), "=&r" (tmp2)
-	: "0" (val), "r" (m)
-	: "cc", "memory");
-	return val;
-}
-
-static inline unsigned long xchg64(__volatile__ unsigned long *m, unsigned long val)
-{
-	unsigned long tmp1, tmp2;
-
-	__asm__ __volatile__(
-"	mov		%0, %1\n"
-"1:	ldx		[%4], %2\n"
-"	casx		[%4], %2, %0\n"
-"	cmp		%2, %0\n"
-"	bne,a,pn	%%xcc, 1b\n"
-"	 mov		%1, %0\n"
-	: "=&r" (val), "=&r" (tmp1), "=&r" (tmp2)
-	: "0" (val), "r" (m)
-	: "cc", "memory");
-	return val;
-}
-
-#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-
-extern void __xchg_called_with_bad_pointer(void);
-
-static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr,
-				       int size)
-{
-	switch (size) {
-	case 4:
-		return xchg32(ptr, x);
-	case 8:
-		return xchg64(ptr, x);
-	}
-	__xchg_called_with_bad_pointer();
-	return x;
-}
-
-extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn));
-
-/*
- * Atomic compare and exchange.  Compare OLD with MEM, if identical,
- * store NEW in MEM.  Return the initial value in MEM.  Success is
- * indicated by comparing RETURN with OLD.
- */
-
-#define __HAVE_ARCH_CMPXCHG 1
-
-static inline unsigned long
-__cmpxchg_u32(volatile int *m, int old, int new)
-{
-	__asm__ __volatile__("cas [%2], %3, %0"
-			     : "=&r" (new)
-			     : "0" (new), "r" (m), "r" (old)
-			     : "memory");
-
-	return new;
-}
-
-static inline unsigned long
-__cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
-{
-	__asm__ __volatile__("casx [%2], %3, %0"
-			     : "=&r" (new)
-			     : "0" (new), "r" (m), "r" (old)
-			     : "memory");
-
-	return new;
-}
-
-/* This function doesn't exist, so you'll get a linker error
-   if something tries to do an invalid cmpxchg().  */
-extern void __cmpxchg_called_with_bad_pointer(void);
-
-static inline unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
-{
-	switch (size) {
-		case 4:
-			return __cmpxchg_u32(ptr, old, new);
-		case 8:
-			return __cmpxchg_u64(ptr, old, new);
-	}
-	__cmpxchg_called_with_bad_pointer();
-	return old;
-}
-
-#define cmpxchg(ptr,o,n)						 \
-  ({									 \
-     __typeof__(*(ptr)) _o_ = (o);					 \
-     __typeof__(*(ptr)) _n_ = (n);					 \
-     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
-				    (unsigned long)_n_, sizeof(*(ptr))); \
-  })
-
-/*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
- */
-
-static inline unsigned long __cmpxchg_local(volatile void *ptr,
-				      unsigned long old,
-				      unsigned long new, int size)
-{
-	switch (size) {
-	case 4:
-	case 8:	return __cmpxchg(ptr, old, new, size);
-	default:
-		return __cmpxchg_local_generic(ptr, old, new, size);
-	}
-
-	return old;
-}
-
-#define cmpxchg_local(ptr, o, n)				  	\
-	((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o),	\
-			(unsigned long)(n), sizeof(*(ptr))))
-#define cmpxchg64_local(ptr, o, n)					\
-  ({									\
-	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
-	cmpxchg_local((ptr), (o), (n));					\
-  })
-
-#endif /* !(__ASSEMBLY__) */
-
-#define arch_align_stack(x) (x)
-
-#endif /* !(__SPARC64_SYSTEM_H) */
diff --git a/arch/sparc/include/asm/timer_32.h b/arch/sparc/include/asm/timer_32.h
index 2ec030e..1a91e11 100644
--- a/arch/sparc/include/asm/timer_32.h
+++ b/arch/sparc/include/asm/timer_32.h
@@ -8,12 +8,13 @@
 #ifndef _SPARC_TIMER_H
 #define _SPARC_TIMER_H
 
-#include <asm/system.h>  /* For SUN4M_NCPUS */
+#include <asm/cpu_type.h>  /* For SUN4M_NCPUS */
 #include <asm/btfixup.h>
 
 extern __volatile__ unsigned int *master_l10_counter;
 
 /* FIXME: Make do_[gs]ettimeofday btfixup calls */
+struct timespec;
 BTFIXUPDEF_CALL(int, bus_do_settimeofday, struct timespec *tv)
 #define bus_do_settimeofday(tv) BTFIXUP_CALL(bus_do_settimeofday)(tv)
 
diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h
index 3e1449f..a1091afb 100644
--- a/arch/sparc/include/asm/uaccess_64.h
+++ b/arch/sparc/include/asm/uaccess_64.h
@@ -11,7 +11,6 @@
 #include <linux/string.h>
 #include <linux/thread_info.h>
 #include <asm/asi.h>
-#include <asm/system.h>
 #include <asm/spitfire.h>
 #include <asm-generic/uaccess-unaligned.h>
 #endif
diff --git a/arch/sparc/include/asm/vga.h b/arch/sparc/include/asm/vga.h
index c69d5b2..ec0e996 100644
--- a/arch/sparc/include/asm/vga.h
+++ b/arch/sparc/include/asm/vga.h
@@ -7,6 +7,7 @@
 #ifndef _LINUX_ASM_VGA_H_
 #define _LINUX_ASM_VGA_H_
 
+#include <linux/bug.h>
 #include <asm/types.h>
 
 #define VT_BUF_HAVE_RW
diff --git a/arch/sparc/include/asm/vio.h b/arch/sparc/include/asm/vio.h
index 9d83d3b..432afa8 100644
--- a/arch/sparc/include/asm/vio.h
+++ b/arch/sparc/include/asm/vio.h
@@ -284,6 +284,7 @@
 };
 
 struct vio_driver {
+	const char			*name;
 	struct list_head		node;
 	const struct vio_device_id	*id_table;
 	int (*probe)(struct vio_dev *dev, const struct vio_device_id *id);
@@ -371,7 +372,13 @@
 		       vio->vdev->channel_id, ## a); \
 } while (0)
 
-extern int vio_register_driver(struct vio_driver *drv);
+extern int __vio_register_driver(struct vio_driver *drv, struct module *owner,
+				 const char *mod_name);
+/*
+ * vio_register_driver must be a macro so that KBUILD_MODNAME can be expanded
+ */
+#define vio_register_driver(driver)		\
+	__vio_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
 extern void vio_unregister_driver(struct vio_driver *drv);
 
 static inline struct vio_driver *to_vio_driver(struct device_driver *drv)
diff --git a/arch/sparc/kernel/auxio_32.c b/arch/sparc/kernel/auxio_32.c
index f7ea8f0..56d0f52 100644
--- a/arch/sparc/kernel/auxio_32.c
+++ b/arch/sparc/kernel/auxio_32.c
@@ -13,6 +13,7 @@
 #include <asm/io.h>
 #include <asm/auxio.h>
 #include <asm/string.h>		/* memset(), Linux has no bzero() */
+#include <asm/cpu_type.h>
 
 /* Probe and map in the Auxiliary I/O register */
 
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
index 113c052..6b2f56a 100644
--- a/arch/sparc/kernel/devices.c
+++ b/arch/sparc/kernel/devices.c
@@ -17,8 +17,8 @@
 #include <asm/oplib.h>
 #include <asm/prom.h>
 #include <asm/smp.h>
-#include <asm/system.h>
 #include <asm/cpudata.h>
+#include <asm/cpu_type.h>
 
 extern void clock_stop_probe(void); /* tadpole.c */
 extern void sun4c_probe_memerr_reg(void);
diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c
index 381edcd..fea13c7 100644
--- a/arch/sparc/kernel/ds.c
+++ b/arch/sparc/kernel/ds.c
@@ -1244,10 +1244,7 @@
 	.id_table	= ds_match,
 	.probe		= ds_probe,
 	.remove		= ds_remove,
-	.driver		= {
-		.name	= "ds",
-		.owner	= THIS_MODULE,
-	}
+	.name		= "ds",
 };
 
 static int __init ds_init(void)
diff --git a/arch/sparc/kernel/iommu.c b/arch/sparc/kernel/iommu.c
index 4643d68..070ed14 100644
--- a/arch/sparc/kernel/iommu.c
+++ b/arch/sparc/kernel/iommu.c
@@ -280,7 +280,8 @@
 }
 
 static void *dma_4u_alloc_coherent(struct device *dev, size_t size,
-				   dma_addr_t *dma_addrp, gfp_t gfp)
+				   dma_addr_t *dma_addrp, gfp_t gfp,
+				   struct dma_attrs *attrs)
 {
 	unsigned long flags, order, first_page;
 	struct iommu *iommu;
@@ -330,7 +331,8 @@
 }
 
 static void dma_4u_free_coherent(struct device *dev, size_t size,
-				 void *cpu, dma_addr_t dvma)
+				 void *cpu, dma_addr_t dvma,
+				 struct dma_attrs *attrs)
 {
 	struct iommu *iommu;
 	unsigned long flags, order, npages;
@@ -825,8 +827,8 @@
 }
 
 static struct dma_map_ops sun4u_dma_ops = {
-	.alloc_coherent		= dma_4u_alloc_coherent,
-	.free_coherent		= dma_4u_free_coherent,
+	.alloc			= dma_4u_alloc_coherent,
+	.free			= dma_4u_free_coherent,
 	.map_page		= dma_4u_map_page,
 	.unmap_page		= dma_4u_unmap_page,
 	.map_sg			= dma_4u_map_sg,
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index d0479e2..21bd739 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -261,7 +261,8 @@
  * CPU may access them without any explicit flushing.
  */
 static void *sbus_alloc_coherent(struct device *dev, size_t len,
-				 dma_addr_t *dma_addrp, gfp_t gfp)
+				 dma_addr_t *dma_addrp, gfp_t gfp,
+				 struct dma_attrs *attrs)
 {
 	struct platform_device *op = to_platform_device(dev);
 	unsigned long len_total = PAGE_ALIGN(len);
@@ -315,7 +316,7 @@
 }
 
 static void sbus_free_coherent(struct device *dev, size_t n, void *p,
-			       dma_addr_t ba)
+			       dma_addr_t ba, struct dma_attrs *attrs)
 {
 	struct resource *res;
 	struct page *pgv;
@@ -407,8 +408,8 @@
 }
 
 struct dma_map_ops sbus_dma_ops = {
-	.alloc_coherent		= sbus_alloc_coherent,
-	.free_coherent		= sbus_free_coherent,
+	.alloc			= sbus_alloc_coherent,
+	.free			= sbus_free_coherent,
 	.map_page		= sbus_map_page,
 	.unmap_page		= sbus_unmap_page,
 	.map_sg			= sbus_map_sg,
@@ -436,7 +437,8 @@
  * hwdev should be valid struct pci_dev pointer for PCI devices.
  */
 static void *pci32_alloc_coherent(struct device *dev, size_t len,
-				  dma_addr_t *pba, gfp_t gfp)
+				  dma_addr_t *pba, gfp_t gfp,
+				  struct dma_attrs *attrs)
 {
 	unsigned long len_total = PAGE_ALIGN(len);
 	void *va;
@@ -489,7 +491,7 @@
  * past this call are illegal.
  */
 static void pci32_free_coherent(struct device *dev, size_t n, void *p,
-				dma_addr_t ba)
+				dma_addr_t ba, struct dma_attrs *attrs)
 {
 	struct resource *res;
 
@@ -645,8 +647,8 @@
 }
 
 struct dma_map_ops pci32_dma_ops = {
-	.alloc_coherent		= pci32_alloc_coherent,
-	.free_coherent		= pci32_free_coherent,
+	.alloc			= pci32_alloc_coherent,
+	.free			= pci32_free_coherent,
 	.map_page		= pci32_map_page,
 	.unmap_page		= pci32_unmap_page,
 	.map_sg			= pci32_map_sg,
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h
index 4285112..5a021dd 100644
--- a/arch/sparc/kernel/irq.h
+++ b/arch/sparc/kernel/irq.h
@@ -1,6 +1,7 @@
 #include <linux/platform_device.h>
 
 #include <asm/btfixup.h>
+#include <asm/cpu_type.h>
 
 struct irq_bucket {
         struct irq_bucket *next;
diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c
index d45b710..dff2c3d 100644
--- a/arch/sparc/kernel/irq_64.c
+++ b/arch/sparc/kernel/irq_64.c
@@ -26,7 +26,6 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <linux/atomic.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/iommu.h>
diff --git a/arch/sparc/kernel/jump_label.c b/arch/sparc/kernel/jump_label.c
index 971fd43..48565c1 100644
--- a/arch/sparc/kernel/jump_label.c
+++ b/arch/sparc/kernel/jump_label.c
@@ -6,6 +6,8 @@
 #include <linux/jump_label.h>
 #include <linux/memory.h>
 
+#include <asm/cacheflush.h>
+
 #ifdef HAVE_JUMP_LABEL
 
 void arch_jump_label_transform(struct jump_entry *entry,
diff --git a/arch/sparc/kernel/kgdb_32.c b/arch/sparc/kernel/kgdb_32.c
index 539243b..2e424a5 100644
--- a/arch/sparc/kernel/kgdb_32.c
+++ b/arch/sparc/kernel/kgdb_32.c
@@ -9,6 +9,7 @@
 #include <asm/kdebug.h>
 #include <asm/ptrace.h>
 #include <asm/irq.h>
+#include <asm/cacheflush.h>
 
 extern unsigned long trapbase;
 
diff --git a/arch/sparc/kernel/kgdb_64.c b/arch/sparc/kernel/kgdb_64.c
index 768290a..c875955 100644
--- a/arch/sparc/kernel/kgdb_64.c
+++ b/arch/sparc/kernel/kgdb_64.c
@@ -7,6 +7,7 @@
 #include <linux/kdebug.h>
 #include <linux/ftrace.h>
 
+#include <asm/cacheflush.h>
 #include <asm/kdebug.h>
 #include <asm/ptrace.h>
 #include <asm/irq.h>
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c
index a19c8a0..35e4367 100644
--- a/arch/sparc/kernel/leon_kernel.c
+++ b/arch/sparc/kernel/leon_kernel.c
@@ -104,11 +104,11 @@
 {
 	cpumask_t mask;
 
-	cpus_and(mask, cpu_online_map, *affinity);
-	if (cpus_equal(mask, cpu_online_map) || cpus_empty(mask))
+	cpumask_and(&mask, cpu_online_mask, affinity);
+	if (cpumask_equal(&mask, cpu_online_mask) || cpumask_empty(&mask))
 		return boot_cpu_id;
 	else
-		return first_cpu(mask);
+		return cpumask_first(&mask);
 }
 #else
 #define irq_choose_cpu(affinity) boot_cpu_id
diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c
index c7bec25f..aba6b95 100644
--- a/arch/sparc/kernel/leon_pci.c
+++ b/arch/sparc/kernel/leon_pci.c
@@ -15,14 +15,19 @@
 
 /* The LEON architecture does not rely on a BIOS or bootloader to setup
  * PCI for us. The Linux generic routines are used to setup resources,
- * reset values of confuration-space registers settings ae preseved.
+ * reset values of configuration-space register settings are preserved.
+ *
+ * PCI Memory and Prefetchable Memory is direct-mapped. However I/O Space is
+ * accessed through a Window which is translated to low 64KB in PCI space, the
+ * first 4KB is not used so 60KB is available.
  */
 void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
 {
 	LIST_HEAD(resources);
 	struct pci_bus *root_bus;
 
-	pci_add_resource(&resources, &info->io_space);
+	pci_add_resource_offset(&resources, &info->io_space,
+				info->io_space.start - 0x1000);
 	pci_add_resource(&resources, &info->mem_space);
 
 	root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info,
@@ -38,44 +43,6 @@
 	}
 }
 
-/* PCI Memory and Prefetchable Memory is direct-mapped. However I/O Space is
- * accessed through a Window which is translated to low 64KB in PCI space, the
- * first 4KB is not used so 60KB is available.
- *
- * This function is used by generic code to translate resource addresses into
- * PCI addresses.
- */
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-			     struct resource *res)
-{
-	struct leon_pci_info *info = dev->bus->sysdata;
-
-	region->start = res->start;
-	region->end = res->end;
-
-	if (res->flags & IORESOURCE_IO) {
-		region->start -= (info->io_space.start - 0x1000);
-		region->end -= (info->io_space.start - 0x1000);
-	}
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-/* see pcibios_resource_to_bus() comment */
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-			     struct pci_bus_region *region)
-{
-	struct leon_pci_info *info = dev->bus->sysdata;
-
-	res->start = region->start;
-	res->end = region->end;
-
-	if (res->flags & IORESOURCE_IO) {
-		res->start += (info->io_space.start - 0x1000);
-		res->end += (info->io_space.start - 0x1000);
-	}
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
 void __devinit pcibios_fixup_bus(struct pci_bus *pbus)
 {
 	struct leon_pci_info *info = pbus->sysdata;
diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c
index e551987..276359e 100644
--- a/arch/sparc/kernel/module.c
+++ b/arch/sparc/kernel/module.c
@@ -16,6 +16,7 @@
 
 #include <asm/processor.h>
 #include <asm/spitfire.h>
+#include <asm/cacheflush.h>
 
 #include "entry.h"
 
diff --git a/arch/sparc/kernel/muldiv.c b/arch/sparc/kernel/muldiv.c
index 6ce1021..f7db516 100644
--- a/arch/sparc/kernel/muldiv.c
+++ b/arch/sparc/kernel/muldiv.c
@@ -14,7 +14,6 @@
 #include <linux/mm.h>
 #include <asm/ptrace.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 #include "kernel.h"
diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c
index c76fe0b..eb1c1f0 100644
--- a/arch/sparc/kernel/nmi.c
+++ b/arch/sparc/kernel/nmi.c
@@ -22,6 +22,7 @@
 #include <asm/perf_event.h>
 #include <asm/ptrace.h>
 #include <asm/pcr.h>
+#include <asm/perfctr.h>
 
 #include "kstack.h"
 
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index bb8bc2e..fdaf218 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -375,13 +375,6 @@
 	*last_p = last;
 }
 
-static void pci_resource_adjust(struct resource *res,
-				struct resource *root)
-{
-	res->start += root->start;
-	res->end += root->start;
-}
-
 /* For PCI bus devices which lack a 'ranges' property we interrogate
  * the config space values to set the resources, just like the generic
  * Linux PCI probing code does.
@@ -390,7 +383,8 @@
 					  struct pci_bus *bus,
 					  struct pci_pbm_info *pbm)
 {
-	struct resource *res;
+	struct pci_bus_region region;
+	struct resource *res, res2;
 	u8 io_base_lo, io_limit_lo;
 	u16 mem_base_lo, mem_limit_lo;
 	unsigned long base, limit;
@@ -412,11 +406,14 @@
 	res = bus->resource[0];
 	if (base <= limit) {
 		res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
+		res2.flags = res->flags;
+		region.start = base;
+		region.end = limit + 0xfff;
+		pcibios_bus_to_resource(dev, &res2, &region);
 		if (!res->start)
-			res->start = base;
+			res->start = res2.start;
 		if (!res->end)
-			res->end = limit + 0xfff;
-		pci_resource_adjust(res, &pbm->io_space);
+			res->end = res2.end;
 	}
 
 	pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
@@ -428,9 +425,9 @@
 	if (base <= limit) {
 		res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) |
 			      IORESOURCE_MEM);
-		res->start = base;
-		res->end = limit + 0xfffff;
-		pci_resource_adjust(res, &pbm->mem_space);
+		region.start = base;
+		region.end = limit + 0xfffff;
+		pcibios_bus_to_resource(dev, res, &region);
 	}
 
 	pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
@@ -459,9 +456,9 @@
 	if (base <= limit) {
 		res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) |
 			      IORESOURCE_MEM | IORESOURCE_PREFETCH);
-		res->start = base;
-		res->end = limit + 0xfffff;
-		pci_resource_adjust(res, &pbm->mem_space);
+		region.start = base;
+		region.end = limit + 0xfffff;
+		pcibios_bus_to_resource(dev, res, &region);
 	}
 }
 
@@ -472,6 +469,7 @@
 				      struct pci_bus *bus,
 				      struct pci_pbm_info *pbm)
 {
+	struct pci_bus_region region;
 	struct resource *res;
 	u32 first, last;
 	u8 map;
@@ -479,18 +477,18 @@
 	pci_read_config_byte(dev, APB_IO_ADDRESS_MAP, &map);
 	apb_calc_first_last(map, &first, &last);
 	res = bus->resource[0];
-	res->start = (first << 21);
-	res->end = (last << 21) + ((1 << 21) - 1);
 	res->flags = IORESOURCE_IO;
-	pci_resource_adjust(res, &pbm->io_space);
+	region.start = (first << 21);
+	region.end = (last << 21) + ((1 << 21) - 1);
+	pcibios_bus_to_resource(dev, res, &region);
 
 	pci_read_config_byte(dev, APB_MEM_ADDRESS_MAP, &map);
 	apb_calc_first_last(map, &first, &last);
 	res = bus->resource[1];
-	res->start = (first << 21);
-	res->end = (last << 21) + ((1 << 21) - 1);
 	res->flags = IORESOURCE_MEM;
-	pci_resource_adjust(res, &pbm->mem_space);
+	region.start = (first << 21);
+	region.end = (last << 21) + ((1 << 21) - 1);
+	pcibios_bus_to_resource(dev, res, &region);
 }
 
 static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
@@ -506,6 +504,7 @@
 	struct pci_bus *bus;
 	const u32 *busrange, *ranges;
 	int len, i, simba;
+	struct pci_bus_region region;
 	struct resource *res;
 	unsigned int flags;
 	u64 size;
@@ -556,8 +555,6 @@
 	}
 	i = 1;
 	for (; len >= 32; len -= 32, ranges += 8) {
-		struct resource *root;
-
 		flags = pci_parse_of_flags(ranges[0]);
 		size = GET_64BIT(ranges, 6);
 		if (flags == 0 || size == 0)
@@ -569,7 +566,6 @@
 				       " for bridge %s\n", node->full_name);
 				continue;
 			}
-			root = &pbm->io_space;
 		} else {
 			if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) {
 				printk(KERN_ERR "PCI: too many memory ranges"
@@ -578,18 +574,12 @@
 			}
 			res = bus->resource[i];
 			++i;
-			root = &pbm->mem_space;
 		}
 
-		res->start = GET_64BIT(ranges, 1);
-		res->end = res->start + size - 1;
 		res->flags = flags;
-
-		/* Another way to implement this would be to add an of_device
-		 * layer routine that can calculate a resource for a given
-		 * range property value in a PCI device.
-		 */
-		pci_resource_adjust(res, root);
+		region.start = GET_64BIT(ranges, 1);
+		region.end = region.start + size - 1;
+		pcibios_bus_to_resource(dev, res, &region);
 	}
 after_ranges:
 	sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
@@ -691,8 +681,10 @@
 
 	printk("PCI: Scanning PBM %s\n", node->full_name);
 
-	pci_add_resource(&resources, &pbm->io_space);
-	pci_add_resource(&resources, &pbm->mem_space);
+	pci_add_resource_offset(&resources, &pbm->io_space,
+				pbm->io_space.start);
+	pci_add_resource_offset(&resources, &pbm->mem_space,
+				pbm->mem_space.start);
 	bus = pci_create_root_bus(parent, pbm->pci_first_busno, pbm->pci_ops,
 				  pbm, &resources);
 	if (!bus) {
@@ -755,46 +747,6 @@
 	return 0;
 }
 
-void pcibios_resource_to_bus(struct pci_dev *pdev, struct pci_bus_region *region,
-			     struct resource *res)
-{
-	struct pci_pbm_info *pbm = pdev->bus->sysdata;
-	struct resource zero_res, *root;
-
-	zero_res.start = 0;
-	zero_res.end = 0;
-	zero_res.flags = res->flags;
-
-	if (res->flags & IORESOURCE_IO)
-		root = &pbm->io_space;
-	else
-		root = &pbm->mem_space;
-
-	pci_resource_adjust(&zero_res, root);
-
-	region->start = res->start - zero_res.start;
-	region->end = res->end - zero_res.start;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res,
-			     struct pci_bus_region *region)
-{
-	struct pci_pbm_info *pbm = pdev->bus->sysdata;
-	struct resource *root;
-
-	res->start = region->start;
-	res->end = region->end;
-
-	if (res->flags & IORESOURCE_IO)
-		root = &pbm->io_space;
-	else
-		root = &pbm->mem_space;
-
-	pci_resource_adjust(res, root);
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
 char * __devinit pcibios_setup(char *str)
 {
 	return str;
diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c
index af5755d..7661e84 100644
--- a/arch/sparc/kernel/pci_sun4v.c
+++ b/arch/sparc/kernel/pci_sun4v.c
@@ -128,7 +128,8 @@
 }
 
 static void *dma_4v_alloc_coherent(struct device *dev, size_t size,
-				   dma_addr_t *dma_addrp, gfp_t gfp)
+				   dma_addr_t *dma_addrp, gfp_t gfp,
+				   struct dma_attrs *attrs)
 {
 	unsigned long flags, order, first_page, npages, n;
 	struct iommu *iommu;
@@ -198,7 +199,7 @@
 }
 
 static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu,
-				 dma_addr_t dvma)
+				 dma_addr_t dvma, struct dma_attrs *attrs)
 {
 	struct pci_pbm_info *pbm;
 	struct iommu *iommu;
@@ -527,8 +528,8 @@
 }
 
 static struct dma_map_ops sun4v_dma_ops = {
-	.alloc_coherent			= dma_4v_alloc_coherent,
-	.free_coherent			= dma_4v_free_coherent,
+	.alloc				= dma_4v_alloc_coherent,
+	.free				= dma_4v_free_coherent,
 	.map_page			= dma_4v_map_page,
 	.unmap_page			= dma_4v_unmap_page,
 	.map_sg				= dma_4v_map_sg,
diff --git a/arch/sparc/kernel/pcr.c b/arch/sparc/kernel/pcr.c
index a24072a..0ce0dd2 100644
--- a/arch/sparc/kernel/pcr.c
+++ b/arch/sparc/kernel/pcr.c
@@ -14,6 +14,7 @@
 #include <asm/pcr.h>
 #include <asm/nmi.h>
 #include <asm/spitfire.h>
+#include <asm/perfctr.h>
 
 /* This code is shared between various users of the performance
  * counters.  Users will be oprofile, pseudo-NMI watchdog, and the
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c
index 8e16a4a..28559ce 100644
--- a/arch/sparc/kernel/perf_event.c
+++ b/arch/sparc/kernel/perf_event.c
@@ -25,6 +25,8 @@
 #include <linux/atomic.h>
 #include <asm/nmi.h>
 #include <asm/pcr.h>
+#include <asm/perfctr.h>
+#include <asm/cacheflush.h>
 
 #include "kernel.h"
 #include "kstack.h"
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
index 935fdbc..efa0754 100644
--- a/arch/sparc/kernel/process_32.c
+++ b/arch/sparc/kernel/process_32.c
@@ -28,7 +28,6 @@
 #include <asm/auxio.h>
 #include <asm/oplib.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
@@ -38,6 +37,7 @@
 #include <asm/elf.h>
 #include <asm/prom.h>
 #include <asm/unistd.h>
+#include <asm/setup.h>
 
 /* 
  * Power management idle function 
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index 06b5b5f..aff0c72 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -32,7 +32,6 @@
 #include <linux/nmi.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
diff --git a/arch/sparc/kernel/ptrace_32.c b/arch/sparc/kernel/ptrace_32.c
index 27b9e93..896ba7c 100644
--- a/arch/sparc/kernel/ptrace_32.c
+++ b/arch/sparc/kernel/ptrace_32.c
@@ -23,8 +23,8 @@
 #include <linux/tracehook.h>
 
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/cacheflush.h>
 
 /* #define ALLOW_INIT_TRACING */
 
diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c
index 9388844..6f97c07 100644
--- a/arch/sparc/kernel/ptrace_64.c
+++ b/arch/sparc/kernel/ptrace_64.c
@@ -29,7 +29,6 @@
 
 #include <asm/asi.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/psrcompat.h>
 #include <asm/visasm.h>
diff --git a/arch/sparc/kernel/reboot.c b/arch/sparc/kernel/reboot.c
index 006a42d..eba7d91 100644
--- a/arch/sparc/kernel/reboot.c
+++ b/arch/sparc/kernel/reboot.c
@@ -7,9 +7,9 @@
 #include <linux/export.h>
 #include <linux/pm.h>
 
-#include <asm/system.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
+#include <asm/setup.h>
 
 /* sysctl - toggle power-off restriction for serial console
  * systems in machine_power_off()
diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c
index ffb883d..d444468 100644
--- a/arch/sparc/kernel/setup_32.c
+++ b/arch/sparc/kernel/setup_32.c
@@ -33,7 +33,6 @@
 #include <linux/kdebug.h>
 #include <linux/export.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/oplib.h>
@@ -46,6 +45,7 @@
 #include <asm/machines.h>
 #include <asm/cpudata.h>
 #include <asm/setup.h>
+#include <asm/cacheflush.h>
 
 #include "kernel.h"
 
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index a854a1c..1414d16 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -31,7 +31,6 @@
 #include <linux/initrd.h>
 #include <linux/module.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/oplib.h>
@@ -49,6 +48,7 @@
 #include <asm/btext.h>
 #include <asm/elf.h>
 #include <asm/mdesc.h>
+#include <asm/cacheflush.h>
 
 #ifdef CONFIG_IP_PNP
 #include <net/ipconfig.h>
diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c
index 023b886..948700f 100644
--- a/arch/sparc/kernel/signal32.c
+++ b/arch/sparc/kernel/signal32.c
@@ -28,6 +28,7 @@
 #include <asm/fpumacro.h>
 #include <asm/visasm.h>
 #include <asm/compat_signal.h>
+#include <asm/switch_to.h>
 
 #include "sigutil.h"
 
@@ -776,7 +777,6 @@
 				  siginfo_t *info,
 				  sigset_t *oldset, struct pt_regs *regs)
 {
-	sigset_t blocked;
 	int err;
 
 	if (ka->sa.sa_flags & SA_SIGINFO)
@@ -787,11 +787,7 @@
 	if (err)
 		return err;
 
-	sigorsets(&blocked, &current->blocked, &ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NOMASK))
-		sigaddset(&blocked, signr);
-	set_current_blocked(&blocked);
-
+	block_sigmask(ka, signr);
 	tracehook_signal_handler(signr, info, ka, regs, 0);
 
 	return 0;
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
index d54c6e5..1e750e41 100644
--- a/arch/sparc/kernel/signal_32.c
+++ b/arch/sparc/kernel/signal_32.c
@@ -25,6 +25,7 @@
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>	/* flush_sig_insns */
+#include <asm/switch_to.h>
 
 #include "sigutil.h"
 
@@ -465,7 +466,6 @@
 handle_signal(unsigned long signr, struct k_sigaction *ka,
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
 {
-	sigset_t blocked;
 	int err;
 
 	if (ka->sa.sa_flags & SA_SIGINFO)
@@ -476,11 +476,7 @@
 	if (err)
 		return err;
 
-	sigorsets(&blocked, &current->blocked, &ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NOMASK))
-		sigaddset(&blocked, signr);
-	set_current_blocked(&blocked);
-
+	block_sigmask(ka, signr);
 	tracehook_signal_handler(signr, info, ka, regs, 0);
 
 	return 0;
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c
index f0836cd..48b0f57 100644
--- a/arch/sparc/kernel/signal_64.c
+++ b/arch/sparc/kernel/signal_64.c
@@ -31,6 +31,8 @@
 #include <asm/uctx.h>
 #include <asm/siginfo.h>
 #include <asm/visasm.h>
+#include <asm/switch_to.h>
+#include <asm/cacheflush.h>
 
 #include "entry.h"
 #include "systbls.h"
@@ -479,18 +481,14 @@
 				siginfo_t *info,
 				sigset_t *oldset, struct pt_regs *regs)
 {
-	sigset_t blocked;
 	int err;
 
 	err = setup_rt_frame(ka, regs, signr, oldset,
 			     (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
 	if (err)
 		return err;
-	sigorsets(&blocked, &current->blocked, &ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NOMASK))
-		sigaddset(&blocked, signr);
-	set_current_blocked(&blocked);
 
+	block_sigmask(ka, signr);
 	tracehook_signal_handler(signr, info, ka, regs, 0);
 
 	return 0;
diff --git a/arch/sparc/kernel/sigutil_32.c b/arch/sparc/kernel/sigutil_32.c
index 35c7897..0f6eebe 100644
--- a/arch/sparc/kernel/sigutil_32.c
+++ b/arch/sparc/kernel/sigutil_32.c
@@ -7,6 +7,7 @@
 #include <asm/sigcontext.h>
 #include <asm/fpumacro.h>
 #include <asm/ptrace.h>
+#include <asm/switch_to.h>
 
 #include "sigutil.h"
 
diff --git a/arch/sparc/kernel/sigutil_64.c b/arch/sparc/kernel/sigutil_64.c
index b19570d..387834a 100644
--- a/arch/sparc/kernel/sigutil_64.c
+++ b/arch/sparc/kernel/sigutil_64.c
@@ -7,6 +7,7 @@
 #include <asm/sigcontext.h>
 #include <asm/fpumacro.h>
 #include <asm/ptrace.h>
+#include <asm/switch_to.h>
 
 #include "sigutil.h"
 
diff --git a/arch/sparc/kernel/sparc_ksyms_64.c b/arch/sparc/kernel/sparc_ksyms_64.c
index 12ff098..9f5e24d 100644
--- a/arch/sparc/kernel/sparc_ksyms_64.c
+++ b/arch/sparc/kernel/sparc_ksyms_64.c
@@ -10,12 +10,12 @@
 #include <linux/init.h>
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 #include <asm/cpudata.h>
 #include <asm/uaccess.h>
 #include <asm/spitfire.h>
 #include <asm/oplib.h>
 #include <asm/hypervisor.h>
+#include <asm/cacheflush.h>
 
 struct poll {
 	int fd;
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 1333879..540b2fe 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -14,6 +14,7 @@
 #include <asm/sbi.h>
 #include <asm/mmu.h>
 #include <asm/tlbflush.h>
+#include <asm/switch_to.h>
 #include <asm/cacheflush.h>
 
 #include "kernel.h"
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 5947686..02db9a0 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -10,6 +10,7 @@
 #include <linux/cpu.h>
 
 #include <asm/cacheflush.h>
+#include <asm/switch_to.h>
 #include <asm/tlbflush.h>
 
 #include "irq.h"
diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c
index 1060e06..7d0c088 100644
--- a/arch/sparc/kernel/time_32.c
+++ b/arch/sparc/kernel/time_32.c
@@ -37,7 +37,6 @@
 #include <asm/oplib.h>
 #include <asm/timex.h>
 #include <asm/timer.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/idprom.h>
diff --git a/arch/sparc/kernel/traps_32.c b/arch/sparc/kernel/traps_32.c
index 591f20c..d2de213 100644
--- a/arch/sparc/kernel/traps_32.c
+++ b/arch/sparc/kernel/traps_32.c
@@ -17,7 +17,6 @@
 #include <linux/export.h>
 
 #include <asm/delay.h>
-#include <asm/system.h>
 #include <asm/ptrace.h>
 #include <asm/oplib.h>
 #include <asm/page.h>
diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c
index 0cbdaa4..c72fdf5 100644
--- a/arch/sparc/kernel/traps_64.c
+++ b/arch/sparc/kernel/traps_64.c
@@ -22,7 +22,6 @@
 
 #include <asm/smp.h>
 #include <asm/delay.h>
-#include <asm/system.h>
 #include <asm/ptrace.h>
 #include <asm/oplib.h>
 #include <asm/page.h>
@@ -41,6 +40,7 @@
 #include <asm/head.h>
 #include <asm/prom.h>
 #include <asm/memctrl.h>
+#include <asm/cacheflush.h>
 
 #include "entry.h"
 #include "kstack.h"
diff --git a/arch/sparc/kernel/unaligned_32.c b/arch/sparc/kernel/unaligned_32.c
index 4d043a1..c0ec897 100644
--- a/arch/sparc/kernel/unaligned_32.c
+++ b/arch/sparc/kernel/unaligned_32.c
@@ -12,7 +12,6 @@
 #include <linux/mm.h>
 #include <asm/ptrace.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/smp.h>
 #include <linux/perf_event.h>
diff --git a/arch/sparc/kernel/unaligned_64.c b/arch/sparc/kernel/unaligned_64.c
index 76e4ac1..dae85bc 100644
--- a/arch/sparc/kernel/unaligned_64.c
+++ b/arch/sparc/kernel/unaligned_64.c
@@ -16,7 +16,6 @@
 #include <asm/ptrace.h>
 #include <asm/pstate.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/smp.h>
 #include <linux/bitops.h>
@@ -24,6 +23,7 @@
 #include <linux/ratelimit.h>
 #include <linux/bitops.h>
 #include <asm/fpumacro.h>
+#include <asm/cacheflush.h>
 
 enum direction {
 	load,    /* ld, ldd, ldh, ldsh */
diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c
index f67e28e..5cffdc5 100644
--- a/arch/sparc/kernel/vio.c
+++ b/arch/sparc/kernel/vio.c
@@ -119,13 +119,17 @@
 	.remove		= vio_device_remove,
 };
 
-int vio_register_driver(struct vio_driver *viodrv)
+int __vio_register_driver(struct vio_driver *viodrv, struct module *owner,
+			const char *mod_name)
 {
 	viodrv->driver.bus = &vio_bus_type;
+	viodrv->driver.name = viodrv->name;
+	viodrv->driver.owner = owner;
+	viodrv->driver.mod_name = mod_name;
 
 	return driver_register(&viodrv->driver);
 }
-EXPORT_SYMBOL(vio_register_driver);
+EXPORT_SYMBOL(__vio_register_driver);
 
 void vio_unregister_driver(struct vio_driver *viodrv)
 {
diff --git a/arch/sparc/kernel/visemul.c b/arch/sparc/kernel/visemul.c
index 7337067..08e074b7 100644
--- a/arch/sparc/kernel/visemul.c
+++ b/arch/sparc/kernel/visemul.c
@@ -9,9 +9,9 @@
 
 #include <asm/ptrace.h>
 #include <asm/pstate.h>
-#include <asm/system.h>
 #include <asm/fpumacro.h>
 #include <asm/uaccess.h>
+#include <asm/cacheflush.h>
 
 /* OPF field of various VIS instructions.  */
 
diff --git a/arch/sparc/math-emu/math_64.c b/arch/sparc/math-emu/math_64.c
index e575bd2..2bbe2f2 100644
--- a/arch/sparc/math-emu/math_64.c
+++ b/arch/sparc/math-emu/math_64.c
@@ -16,6 +16,7 @@
 #include <asm/fpumacro.h>
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
+#include <asm/cacheflush.h>
 
 #include "sfp-util_64.h"
 #include <math-emu/soft-fp.h>
diff --git a/arch/sparc/mm/btfixup.c b/arch/sparc/mm/btfixup.c
index 8a7f817..09d6af2 100644
--- a/arch/sparc/mm/btfixup.c
+++ b/arch/sparc/mm/btfixup.c
@@ -12,7 +12,6 @@
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
-#include <asm/system.h>
 #include <asm/cacheflush.h>
 
 #define BTFIXUP_OPTIMIZE_NOP
diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c
index 8023fd7..7705c67 100644
--- a/arch/sparc/mm/fault_32.c
+++ b/arch/sparc/mm/fault_32.c
@@ -22,7 +22,6 @@
 #include <linux/interrupt.h>
 #include <linux/kdebug.h>
 
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/memreg.h>
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
index 7b00de6..c5f9021 100644
--- a/arch/sparc/mm/init_32.c
+++ b/arch/sparc/mm/init_32.c
@@ -27,7 +27,6 @@
 #include <linux/gfp.h>
 
 #include <asm/sections.h>
-#include <asm/system.h>
 #include <asm/vac-ops.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index b3f5e7d..21faaee 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -28,7 +28,6 @@
 #include <linux/gfp.h>
 
 #include <asm/head.h>
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
diff --git a/arch/sparc/mm/init_64.h b/arch/sparc/mm/init_64.h
index 77d1b31..3e1ac8b 100644
--- a/arch/sparc/mm/init_64.h
+++ b/arch/sparc/mm/init_64.h
@@ -36,8 +36,6 @@
 
 extern void prom_world(int enter);
 
-extern void free_initmem(void);
-
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
 #define VMEMMAP_CHUNK_SHIFT	22
 #define VMEMMAP_CHUNK		(1UL << VMEMMAP_CHUNK_SHIFT)
diff --git a/arch/sparc/mm/loadmmu.c b/arch/sparc/mm/loadmmu.c
index 82ec8f6..c5bf2a6 100644
--- a/arch/sparc/mm/loadmmu.c
+++ b/arch/sparc/mm/loadmmu.c
@@ -11,7 +11,6 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c
index 536412d..c52add7 100644
--- a/arch/sparc/mm/tsb.c
+++ b/arch/sparc/mm/tsb.c
@@ -6,7 +6,6 @@
 #include <linux/kernel.h>
 #include <linux/preempt.h>
 #include <linux/slab.h>
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/tlbflush.h>
 #include <asm/tlb.h>
diff --git a/arch/sparc/prom/console_32.c b/arch/sparc/prom/console_32.c
index a00f47b..1cfb50f 100644
--- a/arch/sparc/prom/console_32.c
+++ b/arch/sparc/prom/console_32.c
@@ -11,7 +11,6 @@
 #include <linux/sched.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
-#include <asm/system.h>
 #include <linux/string.h>
 
 extern void restore_current(void);
diff --git a/arch/sparc/prom/console_64.c b/arch/sparc/prom/console_64.c
index 9de6c8c..f95edcc 100644
--- a/arch/sparc/prom/console_64.c
+++ b/arch/sparc/prom/console_64.c
@@ -10,7 +10,6 @@
 #include <linux/sched.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
-#include <asm/system.h>
 #include <linux/string.h>
 
 static int __prom_console_write_buf(const char *buf, int len)
diff --git a/arch/sparc/prom/misc_32.c b/arch/sparc/prom/misc_32.c
index 677b6a1..8dc0b6b 100644
--- a/arch/sparc/prom/misc_32.c
+++ b/arch/sparc/prom/misc_32.c
@@ -13,7 +13,6 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/auxio.h>
-#include <asm/system.h>
 
 extern void restore_current(void);
 
diff --git a/arch/sparc/prom/misc_64.c b/arch/sparc/prom/misc_64.c
index e4f31d4..f178b9d 100644
--- a/arch/sparc/prom/misc_64.c
+++ b/arch/sparc/prom/misc_64.c
@@ -15,7 +15,6 @@
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
-#include <asm/system.h>
 #include <asm/ldc.h>
 
 static int prom_service_exists(const char *service_name)
diff --git a/arch/sparc/prom/p1275.c b/arch/sparc/prom/p1275.c
index d9850c2..04a4540 100644
--- a/arch/sparc/prom/p1275.c
+++ b/arch/sparc/prom/p1275.c
@@ -13,7 +13,6 @@
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
-#include <asm/system.h>
 #include <asm/spitfire.h>
 #include <asm/pstate.h>
 #include <asm/ldc.h>
diff --git a/arch/sparc/prom/ranges.c b/arch/sparc/prom/ranges.c
index 0857aa9..ad143c1 100644
--- a/arch/sparc/prom/ranges.c
+++ b/arch/sparc/prom/ranges.c
@@ -11,7 +11,6 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/types.h>
-#include <asm/system.h>
 
 static struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX];
 static int num_obio_ranges;
diff --git a/arch/tile/include/asm/atomic.h b/arch/tile/include/asm/atomic.h
index 921dbeb..bb696da 100644
--- a/arch/tile/include/asm/atomic.h
+++ b/arch/tile/include/asm/atomic.h
@@ -20,7 +20,7 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/compiler.h>
-#include <asm/system.h>
+#include <linux/types.h>
 
 #define ATOMIC_INIT(i)	{ (i) }
 
diff --git a/arch/tile/include/asm/atomic_32.h b/arch/tile/include/asm/atomic_32.h
index c03349e0..466dc4a 100644
--- a/arch/tile/include/asm/atomic_32.h
+++ b/arch/tile/include/asm/atomic_32.h
@@ -17,6 +17,7 @@
 #ifndef _ASM_TILE_ATOMIC_32_H
 #define _ASM_TILE_ATOMIC_32_H
 
+#include <asm/barrier.h>
 #include <arch/chip.h>
 
 #ifndef __ASSEMBLY__
diff --git a/arch/tile/include/asm/atomic_64.h b/arch/tile/include/asm/atomic_64.h
index 27fe667..f4500c6 100644
--- a/arch/tile/include/asm/atomic_64.h
+++ b/arch/tile/include/asm/atomic_64.h
@@ -19,6 +19,7 @@
 
 #ifndef __ASSEMBLY__
 
+#include <asm/barrier.h>
 #include <arch/spr_def.h>
 
 /* First, the 32-bit atomic ops that are "real" on our 64-bit platform. */
diff --git a/arch/tile/include/asm/barrier.h b/arch/tile/include/asm/barrier.h
new file mode 100644
index 0000000..990a217
--- /dev/null
+++ b/arch/tile/include/asm/barrier.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#ifndef _ASM_TILE_BARRIER_H
+#define _ASM_TILE_BARRIER_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+#include <arch/chip.h>
+#include <arch/spr_def.h>
+#include <asm/timex.h>
+
+/*
+ * read_barrier_depends - Flush all pending reads that subsequents reads
+ * depend on.
+ *
+ * No data-dependent reads from memory-like regions are ever reordered
+ * over this barrier.  All reads preceding this primitive are guaranteed
+ * to access memory (but not necessarily other CPUs' caches) before any
+ * reads following this primitive that depend on the data return by
+ * any of the preceding reads.  This primitive is much lighter weight than
+ * rmb() on most CPUs, and is never heavier weight than is
+ * rmb().
+ *
+ * These ordering constraints are respected by both the local CPU
+ * and the compiler.
+ *
+ * Ordering is not guaranteed by anything other than these primitives,
+ * not even by data dependencies.  See the documentation for
+ * memory_barrier() for examples and URLs to more information.
+ *
+ * For example, the following code would force ordering (the initial
+ * value of "a" is zero, "b" is one, and "p" is "&a"):
+ *
+ * <programlisting>
+ *	CPU 0				CPU 1
+ *
+ *	b = 2;
+ *	memory_barrier();
+ *	p = &b;				q = p;
+ *					read_barrier_depends();
+ *					d = *q;
+ * </programlisting>
+ *
+ * because the read of "*q" depends on the read of "p" and these
+ * two reads are separated by a read_barrier_depends().  However,
+ * the following code, with the same initial values for "a" and "b":
+ *
+ * <programlisting>
+ *	CPU 0				CPU 1
+ *
+ *	a = 2;
+ *	memory_barrier();
+ *	b = 3;				y = b;
+ *					read_barrier_depends();
+ *					x = a;
+ * </programlisting>
+ *
+ * does not enforce ordering, since there is no data dependency between
+ * the read of "a" and the read of "b".  Therefore, on some CPUs, such
+ * as Alpha, "y" could be set to 3 and "x" to 0.  Use rmb()
+ * in cases like this where there are no data dependencies.
+ */
+#define read_barrier_depends()	do { } while (0)
+
+#define __sync()	__insn_mf()
+
+#if !CHIP_HAS_MF_WAITS_FOR_VICTIMS()
+#include <hv/syscall_public.h>
+/*
+ * Issue an uncacheable load to each memory controller, then
+ * wait until those loads have completed.
+ */
+static inline void __mb_incoherent(void)
+{
+	long clobber_r10;
+	asm volatile("swint2"
+		     : "=R10" (clobber_r10)
+		     : "R10" (HV_SYS_fence_incoherent)
+		     : "r0", "r1", "r2", "r3", "r4",
+		       "r5", "r6", "r7", "r8", "r9",
+		       "r11", "r12", "r13", "r14",
+		       "r15", "r16", "r17", "r18", "r19",
+		       "r20", "r21", "r22", "r23", "r24",
+		       "r25", "r26", "r27", "r28", "r29");
+}
+#endif
+
+/* Fence to guarantee visibility of stores to incoherent memory. */
+static inline void
+mb_incoherent(void)
+{
+	__insn_mf();
+
+#if !CHIP_HAS_MF_WAITS_FOR_VICTIMS()
+	{
+#if CHIP_HAS_TILE_WRITE_PENDING()
+		const unsigned long WRITE_TIMEOUT_CYCLES = 400;
+		unsigned long start = get_cycles_low();
+		do {
+			if (__insn_mfspr(SPR_TILE_WRITE_PENDING) == 0)
+				return;
+		} while ((get_cycles_low() - start) < WRITE_TIMEOUT_CYCLES);
+#endif /* CHIP_HAS_TILE_WRITE_PENDING() */
+		(void) __mb_incoherent();
+	}
+#endif /* CHIP_HAS_MF_WAITS_FOR_VICTIMS() */
+}
+
+#define fast_wmb()	__sync()
+#define fast_rmb()	__sync()
+#define fast_mb()	__sync()
+#define fast_iob()	mb_incoherent()
+
+#define wmb()		fast_wmb()
+#define rmb()		fast_rmb()
+#define mb()		fast_mb()
+#define iob()		fast_iob()
+
+#ifdef CONFIG_SMP
+#define smp_mb()	mb()
+#define smp_rmb()	rmb()
+#define smp_wmb()	wmb()
+#define smp_read_barrier_depends()	read_barrier_depends()
+#else
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+#define smp_read_barrier_depends()	do { } while (0)
+#endif
+
+#define set_mb(var, value) \
+	do { var = value; mb(); } while (0)
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASM_TILE_BARRIER_H */
diff --git a/arch/tile/include/asm/bitops_32.h b/arch/tile/include/asm/bitops_32.h
index 571b118..ddc4c1e 100644
--- a/arch/tile/include/asm/bitops_32.h
+++ b/arch/tile/include/asm/bitops_32.h
@@ -17,7 +17,6 @@
 
 #include <linux/compiler.h>
 #include <linux/atomic.h>
-#include <asm/system.h>
 
 /* Tile-specific routines to support <asm/bitops.h>. */
 unsigned long _atomic_or(volatile unsigned long *p, unsigned long mask);
diff --git a/arch/tile/include/asm/bitops_64.h b/arch/tile/include/asm/bitops_64.h
index e9c8e38..58d021a 100644
--- a/arch/tile/include/asm/bitops_64.h
+++ b/arch/tile/include/asm/bitops_64.h
@@ -17,7 +17,6 @@
 
 #include <linux/compiler.h>
 #include <linux/atomic.h>
-#include <asm/system.h>
 
 /* See <asm/bitops.h> for API comments. */
 
diff --git a/arch/tile/include/asm/cacheflush.h b/arch/tile/include/asm/cacheflush.h
index e925f4b..0fc63c4 100644
--- a/arch/tile/include/asm/cacheflush.h
+++ b/arch/tile/include/asm/cacheflush.h
@@ -20,7 +20,6 @@
 /* Keep includes the same across arches.  */
 #include <linux/mm.h>
 #include <linux/cache.h>
-#include <asm/system.h>
 #include <arch/icache.h>
 
 /* Caches are physically-indexed and so don't need special treatment */
@@ -152,4 +151,14 @@
  */
 void finv_buffer_remote(void *buffer, size_t size, int hfh);
 
+/*
+ * On SMP systems, when the scheduler does migration-cost autodetection,
+ * it needs a way to flush as much of the CPU's caches as possible:
+ *
+ * TODO: fill this in!
+ */
+static inline void sched_cacheflush(void)
+{
+}
+
 #endif /* _ASM_TILE_CACHEFLUSH_H */
diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h
index bf95f55..4b4b289 100644
--- a/arch/tile/include/asm/compat.h
+++ b/arch/tile/include/asm/compat.h
@@ -242,17 +242,6 @@
 long compat_sys_sched_rr_get_interval(compat_pid_t pid,
 				      struct compat_timespec __user *interval);
 
-/* Versions of compat functions that differ from generic Linux. */
-struct compat_msgbuf;
-long tile_compat_sys_msgsnd(int msqid,
-			    struct compat_msgbuf __user *msgp,
-			    size_t msgsz, int msgflg);
-long tile_compat_sys_msgrcv(int msqid,
-			    struct compat_msgbuf __user *msgp,
-			    size_t msgsz, long msgtyp, int msgflg);
-long tile_compat_sys_ptrace(compat_long_t request, compat_long_t pid,
-			    compat_long_t addr, compat_long_t data);
-
 /* Tilera Linux syscalls that don't have "compat" versions. */
 #define compat_sys_flush_cache sys_flush_cache
 
diff --git a/arch/tile/include/asm/exec.h b/arch/tile/include/asm/exec.h
new file mode 100644
index 0000000..a714e19
--- /dev/null
+++ b/arch/tile/include/asm/exec.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#ifndef _ASM_TILE_EXEC_H
+#define _ASM_TILE_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* _ASM_TILE_EXEC_H */
diff --git a/arch/tile/include/asm/pgtable.h b/arch/tile/include/asm/pgtable.h
index 1a20b7e..6749091 100644
--- a/arch/tile/include/asm/pgtable.h
+++ b/arch/tile/include/asm/pgtable.h
@@ -29,7 +29,6 @@
 #include <linux/spinlock.h>
 #include <asm/processor.h>
 #include <asm/fixmap.h>
-#include <asm/system.h>
 
 struct mm_struct;
 struct vm_area_struct;
diff --git a/arch/tile/include/asm/setup.h b/arch/tile/include/asm/setup.h
index 7caf0f3..e58613e 100644
--- a/arch/tile/include/asm/setup.h
+++ b/arch/tile/include/asm/setup.h
@@ -31,6 +31,28 @@
 void warn_early_printk(void);
 void __init disable_early_printk(void);
 
+/* Init-time routine to do tile-specific per-cpu setup. */
+void setup_cpu(int boot);
+
+/* User-level DMA management functions */
+void grant_dma_mpls(void);
+void restrict_dma_mpls(void);
+
+#ifdef CONFIG_HARDWALL
+/* User-level network management functions */
+void reset_network_state(void);
+void grant_network_mpls(void);
+void restrict_network_mpls(void);
+struct task_struct;
+int hardwall_deactivate(struct task_struct *task);
+
+/* Hook hardwall code into changes in affinity. */
+#define arch_set_cpus_allowed(p, new_mask) do { \
+	if (p->thread.hardwall && !cpumask_equal(&p->cpus_allowed, new_mask)) \
+		hardwall_deactivate(p); \
+} while (0)
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_TILE_SETUP_H */
diff --git a/arch/tile/include/asm/smp.h b/arch/tile/include/asm/smp.h
index 532124a..1aa759a 100644
--- a/arch/tile/include/asm/smp.h
+++ b/arch/tile/include/asm/smp.h
@@ -43,10 +43,6 @@
 /* Boot a secondary cpu */
 void online_secondary(void);
 
-/* Call a function on a specified set of CPUs (may include this one). */
-extern void on_each_cpu_mask(const struct cpumask *mask,
-			     void (*func)(void *), void *info, bool wait);
-
 /* Topology of the supervisor tile grid, and coordinates of boot processor */
 extern HV_Topology smp_topology;
 
@@ -91,9 +87,6 @@
 
 #else /* !CONFIG_SMP */
 
-#define on_each_cpu_mask(mask, func, info, wait)		\
-  do { if (cpumask_test_cpu(0, (mask))) func(info); } while (0)
-
 #define smp_master_cpu		0
 #define smp_height		1
 #define smp_width		1
diff --git a/arch/tile/include/asm/spinlock_32.h b/arch/tile/include/asm/spinlock_32.h
index a5e4208..c0a77b3 100644
--- a/arch/tile/include/asm/spinlock_32.h
+++ b/arch/tile/include/asm/spinlock_32.h
@@ -19,7 +19,6 @@
 
 #include <linux/atomic.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <linux/compiler.h>
 
 /*
diff --git a/arch/tile/include/asm/switch_to.h b/arch/tile/include/asm/switch_to.h
new file mode 100644
index 0000000..1d48c5f
--- /dev/null
+++ b/arch/tile/include/asm/switch_to.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#ifndef _ASM_TILE_SWITCH_TO_H
+#define _ASM_TILE_SWITCH_TO_H
+
+#include <arch/sim_def.h>
+
+/*
+ * switch_to(n) should switch tasks to task nr n, first
+ * checking that n isn't the current task, in which case it does nothing.
+ * The number of callee-saved registers saved on the kernel stack
+ * is defined here for use in copy_thread() and must agree with __switch_to().
+ */
+#define CALLEE_SAVED_FIRST_REG 30
+#define CALLEE_SAVED_REGS_COUNT 24   /* r30 to r52, plus an empty to align */
+
+#ifndef __ASSEMBLY__
+
+struct task_struct;
+
+/*
+ * Pause the DMA engine and static network before task switching.
+ */
+#define prepare_arch_switch(next) _prepare_arch_switch(next)
+void _prepare_arch_switch(struct task_struct *next);
+
+struct task_struct;
+#define switch_to(prev, next, last) ((last) = _switch_to((prev), (next)))
+extern struct task_struct *_switch_to(struct task_struct *prev,
+				      struct task_struct *next);
+
+/* Helper function for _switch_to(). */
+extern struct task_struct *__switch_to(struct task_struct *prev,
+				       struct task_struct *next,
+				       unsigned long new_system_save_k_0);
+
+/* Address that switched-away from tasks are at. */
+extern unsigned long get_switch_to_pc(void);
+
+/*
+ * Kernel threads can check to see if they need to migrate their
+ * stack whenever they return from a context switch; for user
+ * threads, we defer until they are returning to user-space.
+ */
+#define finish_arch_switch(prev) do {                                     \
+	if (unlikely((prev)->state == TASK_DEAD))                         \
+		__insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_OS_EXIT |       \
+			((prev)->pid << _SIM_CONTROL_OPERATOR_BITS));     \
+	__insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_OS_SWITCH |             \
+		(current->pid << _SIM_CONTROL_OPERATOR_BITS));            \
+	if (current->mm == NULL && !kstack_hash &&                        \
+	    current_thread_info()->homecache_cpu != smp_processor_id())   \
+		homecache_migrate_kthread();                              \
+} while (0)
+
+/* Support function for forking a new task. */
+void ret_from_fork(void);
+
+/* Called from ret_from_fork() when a new process starts up. */
+struct task_struct *sim_notify_fork(struct task_struct *prev);
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_TILE_SWITCH_TO_H */
diff --git a/arch/tile/include/asm/system.h b/arch/tile/include/asm/system.h
deleted file mode 100644
index 23d1842..0000000
--- a/arch/tile/include/asm/system.h
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
- *
- *   This program is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU General Public License
- *   as published by the Free Software Foundation, version 2.
- *
- *   This program is distributed in the hope that it will be useful, but
- *   WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- *   NON INFRINGEMENT.  See the GNU General Public License for
- *   more details.
- */
-
-#ifndef _ASM_TILE_SYSTEM_H
-#define _ASM_TILE_SYSTEM_H
-
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-#include <linux/irqflags.h>
-
-/* NOTE: we can't include <linux/ptrace.h> due to #include dependencies. */
-#include <asm/ptrace.h>
-
-#include <arch/chip.h>
-#include <arch/sim_def.h>
-#include <arch/spr_def.h>
-
-/*
- * read_barrier_depends - Flush all pending reads that subsequents reads
- * depend on.
- *
- * No data-dependent reads from memory-like regions are ever reordered
- * over this barrier.  All reads preceding this primitive are guaranteed
- * to access memory (but not necessarily other CPUs' caches) before any
- * reads following this primitive that depend on the data return by
- * any of the preceding reads.  This primitive is much lighter weight than
- * rmb() on most CPUs, and is never heavier weight than is
- * rmb().
- *
- * These ordering constraints are respected by both the local CPU
- * and the compiler.
- *
- * Ordering is not guaranteed by anything other than these primitives,
- * not even by data dependencies.  See the documentation for
- * memory_barrier() for examples and URLs to more information.
- *
- * For example, the following code would force ordering (the initial
- * value of "a" is zero, "b" is one, and "p" is "&a"):
- *
- * <programlisting>
- *	CPU 0				CPU 1
- *
- *	b = 2;
- *	memory_barrier();
- *	p = &b;				q = p;
- *					read_barrier_depends();
- *					d = *q;
- * </programlisting>
- *
- * because the read of "*q" depends on the read of "p" and these
- * two reads are separated by a read_barrier_depends().  However,
- * the following code, with the same initial values for "a" and "b":
- *
- * <programlisting>
- *	CPU 0				CPU 1
- *
- *	a = 2;
- *	memory_barrier();
- *	b = 3;				y = b;
- *					read_barrier_depends();
- *					x = a;
- * </programlisting>
- *
- * does not enforce ordering, since there is no data dependency between
- * the read of "a" and the read of "b".  Therefore, on some CPUs, such
- * as Alpha, "y" could be set to 3 and "x" to 0.  Use rmb()
- * in cases like this where there are no data dependencies.
- */
-
-#define read_barrier_depends()	do { } while (0)
-
-#define __sync()	__insn_mf()
-
-#if CHIP_HAS_SPLIT_CYCLE()
-#define get_cycles_low() __insn_mfspr(SPR_CYCLE_LOW)
-#else
-#define get_cycles_low() __insn_mfspr(SPR_CYCLE)   /* just get all 64 bits */
-#endif
-
-#if !CHIP_HAS_MF_WAITS_FOR_VICTIMS()
-#include <hv/syscall_public.h>
-/*
- * Issue an uncacheable load to each memory controller, then
- * wait until those loads have completed.
- */
-static inline void __mb_incoherent(void)
-{
-	long clobber_r10;
-	asm volatile("swint2"
-		     : "=R10" (clobber_r10)
-		     : "R10" (HV_SYS_fence_incoherent)
-		     : "r0", "r1", "r2", "r3", "r4",
-		       "r5", "r6", "r7", "r8", "r9",
-		       "r11", "r12", "r13", "r14",
-		       "r15", "r16", "r17", "r18", "r19",
-		       "r20", "r21", "r22", "r23", "r24",
-		       "r25", "r26", "r27", "r28", "r29");
-}
-#endif
-
-/* Fence to guarantee visibility of stores to incoherent memory. */
-static inline void
-mb_incoherent(void)
-{
-	__insn_mf();
-
-#if !CHIP_HAS_MF_WAITS_FOR_VICTIMS()
-	{
-#if CHIP_HAS_TILE_WRITE_PENDING()
-		const unsigned long WRITE_TIMEOUT_CYCLES = 400;
-		unsigned long start = get_cycles_low();
-		do {
-			if (__insn_mfspr(SPR_TILE_WRITE_PENDING) == 0)
-				return;
-		} while ((get_cycles_low() - start) < WRITE_TIMEOUT_CYCLES);
-#endif /* CHIP_HAS_TILE_WRITE_PENDING() */
-		(void) __mb_incoherent();
-	}
-#endif /* CHIP_HAS_MF_WAITS_FOR_VICTIMS() */
-}
-
-#define fast_wmb()	__sync()
-#define fast_rmb()	__sync()
-#define fast_mb()	__sync()
-#define fast_iob()	mb_incoherent()
-
-#define wmb()		fast_wmb()
-#define rmb()		fast_rmb()
-#define mb()		fast_mb()
-#define iob()		fast_iob()
-
-#ifdef CONFIG_SMP
-#define smp_mb()	mb()
-#define smp_rmb()	rmb()
-#define smp_wmb()	wmb()
-#define smp_read_barrier_depends()	read_barrier_depends()
-#else
-#define smp_mb()	barrier()
-#define smp_rmb()	barrier()
-#define smp_wmb()	barrier()
-#define smp_read_barrier_depends()	do { } while (0)
-#endif
-
-#define set_mb(var, value) \
-	do { var = value; mb(); } while (0)
-
-/*
- * Pause the DMA engine and static network before task switching.
- */
-#define prepare_arch_switch(next) _prepare_arch_switch(next)
-void _prepare_arch_switch(struct task_struct *next);
-
-
-/*
- * switch_to(n) should switch tasks to task nr n, first
- * checking that n isn't the current task, in which case it does nothing.
- * The number of callee-saved registers saved on the kernel stack
- * is defined here for use in copy_thread() and must agree with __switch_to().
- */
-#endif /* !__ASSEMBLY__ */
-#define CALLEE_SAVED_FIRST_REG 30
-#define CALLEE_SAVED_REGS_COUNT 24   /* r30 to r52, plus an empty to align */
-#ifndef __ASSEMBLY__
-struct task_struct;
-#define switch_to(prev, next, last) ((last) = _switch_to((prev), (next)))
-extern struct task_struct *_switch_to(struct task_struct *prev,
-				      struct task_struct *next);
-
-/* Helper function for _switch_to(). */
-extern struct task_struct *__switch_to(struct task_struct *prev,
-				       struct task_struct *next,
-				       unsigned long new_system_save_k_0);
-
-/* Address that switched-away from tasks are at. */
-extern unsigned long get_switch_to_pc(void);
-
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible:
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
-#define arch_align_stack(x) (x)
-
-/*
- * Is the kernel doing fixups of unaligned accesses?  If <0, no kernel
- * intervention occurs and SIGBUS is delivered with no data address
- * info.  If 0, the kernel single-steps the instruction to discover
- * the data address to provide with the SIGBUS.  If 1, the kernel does
- * a fixup.
- */
-extern int unaligned_fixup;
-
-/* Is the kernel printing on each unaligned fixup? */
-extern int unaligned_printk;
-
-/* Number of unaligned fixups performed */
-extern unsigned int unaligned_fixup_count;
-
-/* Init-time routine to do tile-specific per-cpu setup. */
-void setup_cpu(int boot);
-
-/* User-level DMA management functions */
-void grant_dma_mpls(void);
-void restrict_dma_mpls(void);
-
-#ifdef CONFIG_HARDWALL
-/* User-level network management functions */
-void reset_network_state(void);
-void grant_network_mpls(void);
-void restrict_network_mpls(void);
-int hardwall_deactivate(struct task_struct *task);
-
-/* Hook hardwall code into changes in affinity. */
-#define arch_set_cpus_allowed(p, new_mask) do { \
-	if (p->thread.hardwall && !cpumask_equal(&p->cpus_allowed, new_mask)) \
-		hardwall_deactivate(p); \
-} while (0)
-#endif
-
-/*
- * Kernel threads can check to see if they need to migrate their
- * stack whenever they return from a context switch; for user
- * threads, we defer until they are returning to user-space.
- */
-#define finish_arch_switch(prev) do {                                     \
-	if (unlikely((prev)->state == TASK_DEAD))                         \
-		__insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_OS_EXIT |       \
-			((prev)->pid << _SIM_CONTROL_OPERATOR_BITS));     \
-	__insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_OS_SWITCH |             \
-		(current->pid << _SIM_CONTROL_OPERATOR_BITS));            \
-	if (current->mm == NULL && !kstack_hash &&                        \
-	    current_thread_info()->homecache_cpu != smp_processor_id())   \
-		homecache_migrate_kthread();                              \
-} while (0)
-
-/* Support function for forking a new task. */
-void ret_from_fork(void);
-
-/* Called from ret_from_fork() when a new process starts up. */
-struct task_struct *sim_notify_fork(struct task_struct *prev);
-
-#endif /* !__ASSEMBLY__ */
-
-#endif /* _ASM_TILE_SYSTEM_H */
diff --git a/arch/tile/include/asm/timex.h b/arch/tile/include/asm/timex.h
index 29921f0..dc987d5 100644
--- a/arch/tile/include/asm/timex.h
+++ b/arch/tile/include/asm/timex.h
@@ -29,11 +29,13 @@
 
 #if CHIP_HAS_SPLIT_CYCLE()
 cycles_t get_cycles(void);
+#define get_cycles_low() __insn_mfspr(SPR_CYCLE_LOW)
 #else
 static inline cycles_t get_cycles(void)
 {
 	return __insn_mfspr(SPR_CYCLE);
 }
+#define get_cycles_low() __insn_mfspr(SPR_CYCLE)   /* just get all 64 bits */
 #endif
 
 cycles_t get_clock_rate(void);
diff --git a/arch/tile/include/asm/unaligned.h b/arch/tile/include/asm/unaligned.h
index 137e2de..37dfbe5 100644
--- a/arch/tile/include/asm/unaligned.h
+++ b/arch/tile/include/asm/unaligned.h
@@ -21,4 +21,19 @@
 #define get_unaligned	__get_unaligned_le
 #define put_unaligned	__put_unaligned_le
 
+/*
+ * Is the kernel doing fixups of unaligned accesses?  If <0, no kernel
+ * intervention occurs and SIGBUS is delivered with no data address
+ * info.  If 0, the kernel single-steps the instruction to discover
+ * the data address to provide with the SIGBUS.  If 1, the kernel does
+ * a fixup.
+ */
+extern int unaligned_fixup;
+
+/* Is the kernel printing on each unaligned fixup? */
+extern int unaligned_printk;
+
+/* Number of unaligned fixups performed */
+extern unsigned int unaligned_fixup_count;
+
 #endif /* _ASM_TILE_UNALIGNED_H */
diff --git a/arch/tile/kernel/compat.c b/arch/tile/kernel/compat.c
index bf5e9d7..d67459b 100644
--- a/arch/tile/kernel/compat.c
+++ b/arch/tile/kernel/compat.c
@@ -16,7 +16,6 @@
 #define __SYSCALL_COMPAT
 
 #include <linux/compat.h>
-#include <linux/msg.h>
 #include <linux/syscalls.h>
 #include <linux/kdev_t.h>
 #include <linux/fs.h>
@@ -95,52 +94,10 @@
 	return ret;
 }
 
-/*
- * The usual compat_sys_msgsnd() and _msgrcv() seem to be assuming
- * some different calling convention than our normal 32-bit tile code.
- */
-
-/* Already defined in ipc/compat.c, but we need it here. */
-struct compat_msgbuf {
-	compat_long_t mtype;
-	char mtext[1];
-};
-
-long tile_compat_sys_msgsnd(int msqid,
-			    struct compat_msgbuf __user *msgp,
-			    size_t msgsz, int msgflg)
-{
-	compat_long_t mtype;
-
-	if (get_user(mtype, &msgp->mtype))
-		return -EFAULT;
-	return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg);
-}
-
-long tile_compat_sys_msgrcv(int msqid,
-			    struct compat_msgbuf __user *msgp,
-			    size_t msgsz, long msgtyp, int msgflg)
-{
-	long err, mtype;
-
-	err =  do_msgrcv(msqid, &mtype, msgp->mtext, msgsz, msgtyp, msgflg);
-	if (err < 0)
-		goto out;
-
-	if (put_user(mtype, &msgp->mtype))
-		err = -EFAULT;
- out:
-	return err;
-}
-
 /* Provide the compat syscall number to call mapping. */
 #undef __SYSCALL
 #define __SYSCALL(nr, call) [nr] = (call),
 
-/* The generic versions of these don't work for Tile. */
-#define compat_sys_msgrcv tile_compat_sys_msgrcv
-#define compat_sys_msgsnd tile_compat_sys_msgsnd
-
 /* See comments in sys.c */
 #define compat_sys_fadvise64_64 sys32_fadvise64_64
 #define compat_sys_readahead sys32_readahead
diff --git a/arch/tile/kernel/early_printk.c b/arch/tile/kernel/early_printk.c
index 493a0e6..afb9c9a 100644
--- a/arch/tile/kernel/early_printk.c
+++ b/arch/tile/kernel/early_printk.c
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/string.h>
+#include <linux/irqflags.h>
 #include <asm/setup.h>
 #include <hv/hypervisor.h>
 
diff --git a/arch/tile/kernel/proc.c b/arch/tile/kernel/proc.c
index 62d8208..7a93270 100644
--- a/arch/tile/kernel/proc.c
+++ b/arch/tile/kernel/proc.c
@@ -23,6 +23,7 @@
 #include <linux/sysctl.h>
 #include <linux/hardirq.h>
 #include <linux/mman.h>
+#include <asm/unaligned.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/sections.h>
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index 6ae495e..30caeca 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -27,16 +27,17 @@
 #include <linux/kernel.h>
 #include <linux/tracehook.h>
 #include <linux/signal.h>
-#include <asm/system.h>
 #include <asm/stack.h>
 #include <asm/homecache.h>
 #include <asm/syscalls.h>
 #include <asm/traps.h>
+#include <asm/setup.h>
 #ifdef CONFIG_HARDWALL
 #include <asm/hardwall.h>
 #endif
 #include <arch/chip.h>
 #include <arch/abi.h>
+#include <arch/sim_def.h>
 
 
 /*
diff --git a/arch/tile/kernel/regs_32.S b/arch/tile/kernel/regs_32.S
index caa1310..c12280c 100644
--- a/arch/tile/kernel/regs_32.S
+++ b/arch/tile/kernel/regs_32.S
@@ -13,11 +13,11 @@
  */
 
 #include <linux/linkage.h>
-#include <asm/system.h>
 #include <asm/ptrace.h>
 #include <asm/asm-offsets.h>
 #include <arch/spr_def.h>
 #include <asm/processor.h>
+#include <asm/switch_to.h>
 
 /*
  * See <asm/system.h>; called with prev and next task_struct pointers.
diff --git a/arch/tile/kernel/regs_64.S b/arch/tile/kernel/regs_64.S
index f748c1e..0829fd0 100644
--- a/arch/tile/kernel/regs_64.S
+++ b/arch/tile/kernel/regs_64.S
@@ -13,11 +13,11 @@
  */
 
 #include <linux/linkage.h>
-#include <asm/system.h>
 #include <asm/ptrace.h>
 #include <asm/asm-offsets.h>
 #include <arch/spr_def.h>
 #include <asm/processor.h>
+#include <asm/switch_to.h>
 
 /*
  * See <asm/system.h>; called with prev and next task_struct pointers.
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
index 5f85d8b..92a94f4 100644
--- a/arch/tile/kernel/setup.c
+++ b/arch/tile/kernel/setup.c
@@ -1100,7 +1100,7 @@
 
 /*
  * cpu_cacheable_map lists all the cpus whose caches the hypervisor can
- * flush on our behalf.  It is set to cpu_possible_map OR'ed with
+ * flush on our behalf.  It is set to cpu_possible_mask OR'ed with
  * hash_for_home_map, and it is what should be passed to
  * hv_flush_remote() to flush all caches.  Note that if there are
  * dedicated hypervisor driver tiles that have authorized use of their
@@ -1186,7 +1186,7 @@
 			      sizeof(cpu_lotar_map));
 	if (rc < 0) {
 		pr_err("warning: no HV_INQ_TILES_LOTAR; using AVAIL\n");
-		cpu_lotar_map = cpu_possible_map;
+		cpu_lotar_map = *cpu_possible_mask;
 	}
 
 #if CHIP_HAS_CBOX_HOME_MAP()
@@ -1196,9 +1196,9 @@
 			      sizeof(hash_for_home_map));
 	if (rc < 0)
 		early_panic("hv_inquire_tiles(HFH_CACHE) failed: rc %d\n", rc);
-	cpumask_or(&cpu_cacheable_map, &cpu_possible_map, &hash_for_home_map);
+	cpumask_or(&cpu_cacheable_map, cpu_possible_mask, &hash_for_home_map);
 #else
-	cpu_cacheable_map = cpu_possible_map;
+	cpu_cacheable_map = *cpu_possible_mask;
 #endif
 }
 
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c
index b7a8795..bc1eb58 100644
--- a/arch/tile/kernel/single_step.c
+++ b/arch/tile/kernel/single_step.c
@@ -25,6 +25,7 @@
 #include <linux/types.h>
 #include <linux/err.h>
 #include <asm/cacheflush.h>
+#include <asm/unaligned.h>
 #include <arch/abi.h>
 #include <arch/opcode.h>
 
diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c
index c52224d..a44e103 100644
--- a/arch/tile/kernel/smp.c
+++ b/arch/tile/kernel/smp.c
@@ -87,25 +87,6 @@
 	send_IPI_many(&mask, tag);
 }
 
-
-/*
- * Provide smp_call_function_mask, but also run function locally
- * if specified in the mask.
- */
-void on_each_cpu_mask(const struct cpumask *mask, void (*func)(void *),
-		      void *info, bool wait)
-{
-	int cpu = get_cpu();
-	smp_call_function_many(mask, func, info, wait);
-	if (cpumask_test_cpu(cpu, mask)) {
-		local_irq_disable();
-		func(info);
-		local_irq_enable();
-	}
-	put_cpu();
-}
-
-
 /*
  * Functions related to starting/stopping cpus.
  */
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c
index 4f47b8a..2bb6602 100644
--- a/arch/tile/kernel/traps.c
+++ b/arch/tile/kernel/traps.c
@@ -21,6 +21,7 @@
 #include <linux/ptrace.h>
 #include <asm/stack.h>
 #include <asm/traps.h>
+#include <asm/setup.h>
 
 #include <arch/interrupts.h>
 #include <arch/spr_def.h>
diff --git a/arch/tile/mm/elf.c b/arch/tile/mm/elf.c
index 55e58e9..758b603 100644
--- a/arch/tile/mm/elf.c
+++ b/arch/tile/mm/elf.c
@@ -21,6 +21,7 @@
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/sections.h>
+#include <arch/sim_def.h>
 
 /* Notify a running simulator, if any, that an exec just occurred. */
 static void sim_notify_exec(const char *binary_name)
@@ -117,17 +118,11 @@
 
 	/*
 	 * MAYWRITE to allow gdb to COW and set breakpoints
-	 *
-	 * Make sure the vDSO gets into every core dump.  Dumping its
-	 * contents makes post-mortem fully interpretable later
-	 * without matching up the same kernel and hardware config to
-	 * see what PC values meant.
 	 */
 	vdso_base = VDSO_BASE;
 	retval = install_special_mapping(mm, vdso_base, PAGE_SIZE,
 					 VM_READ|VM_EXEC|
-					 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-					 VM_ALWAYSDUMP,
+					 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
 					 vdso_pages);
 
 #ifndef __tilegx__
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c
index c1eaaa1..cba30e9 100644
--- a/arch/tile/mm/fault.c
+++ b/arch/tile/mm/fault.c
@@ -35,7 +35,6 @@
 #include <linux/syscalls.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 #include <asm/pgalloc.h>
 #include <asm/sections.h>
 #include <asm/traps.h>
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c
index 7309988c..830c490 100644
--- a/arch/tile/mm/init.c
+++ b/arch/tile/mm/init.c
@@ -38,7 +38,6 @@
 #include <linux/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/dma.h>
diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c
index de7d8e2..8730369 100644
--- a/arch/tile/mm/pgtable.c
+++ b/arch/tile/mm/pgtable.c
@@ -27,7 +27,6 @@
 #include <linux/vmalloc.h>
 #include <linux/smp.h>
 
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/fixmap.h>
diff --git a/arch/um/Kconfig.common b/arch/um/Kconfig.common
index b37ae70..20a49ba 100644
--- a/arch/um/Kconfig.common
+++ b/arch/um/Kconfig.common
@@ -9,6 +9,7 @@
 	select HAVE_GENERIC_HARDIRQS
 	select GENERIC_IRQ_SHOW
 	select GENERIC_CPU_DEVICES
+	select GENERIC_IO
 
 config MMU
 	bool
diff --git a/arch/um/Makefile b/arch/um/Makefile
index 28688e6..55c0661 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -28,6 +28,7 @@
 endif
 ifeq ($(SUBARCH),x86_64)
         HEADER_ARCH := x86
+	KBUILD_CFLAGS += -mcmodel=large
 endif
 
 HOST_DIR := arch/$(HEADER_ARCH)
@@ -50,7 +51,7 @@
 #
 # These apply to USER_CFLAGS to.
 
-KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
+KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ \
 	$(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap	\
 	-Din6addr_loopback=kernel_in6addr_loopback \
 	-Din6addr_any=kernel_in6addr_any -Dstrrchr=kernel_strrchr
@@ -99,7 +100,7 @@
 
 archheaders:
 	$(Q)$(MAKE) -C '$(srctree)' KBUILD_SRC= \
-		ARCH=$(SUBARCH) O='$(objtree)' archheaders
+		ARCH=$(HEADER_ARCH) O='$(objtree)' archheaders
 
 archprepare: include/generated/user_constants.h
 
diff --git a/arch/um/defconfig b/arch/um/defconfig
index 761f5e1..fdc97e2 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -1,10 +1,8 @@
 #
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.24
-# Thu Feb  7 11:48:55 2008
+# Automatically generated file; DO NOT EDIT.
+# User Mode Linux/i386 3.3.0 Kernel Configuration
 #
 CONFIG_DEFCONFIG_LIST="arch/$ARCH/defconfig"
-CONFIG_GENERIC_HARDIRQS=y
 CONFIG_UML=y
 CONFIG_MMU=y
 CONFIG_NO_IOMEM=y
@@ -20,12 +18,10 @@
 #
 # UML-specific options
 #
-# CONFIG_STATIC_LINK is not set
 
 #
 # Host processor type and features
 #
-# CONFIG_M386 is not set
 # CONFIG_M486 is not set
 # CONFIG_M586 is not set
 # CONFIG_M586TSC is not set
@@ -41,17 +37,17 @@
 # CONFIG_MCRUSOE is not set
 # CONFIG_MEFFICEON is not set
 # CONFIG_MWINCHIPC6 is not set
-# CONFIG_MWINCHIP2 is not set
 # CONFIG_MWINCHIP3D is not set
+# CONFIG_MELAN is not set
 # CONFIG_MGEODEGX1 is not set
 # CONFIG_MGEODE_LX is not set
 # CONFIG_MCYRIXIII is not set
 # CONFIG_MVIAC3_2 is not set
 # CONFIG_MVIAC7 is not set
-# CONFIG_MPSC is not set
 # CONFIG_MCORE2 is not set
-# CONFIG_GENERIC_CPU is not set
+# CONFIG_MATOM is not set
 # CONFIG_X86_GENERIC is not set
+CONFIG_X86_INTERNODE_CACHE_SHIFT=5
 CONFIG_X86_CMPXCHG=y
 CONFIG_X86_L1_CACHE_SHIFT=5
 CONFIG_X86_XADD=y
@@ -60,47 +56,59 @@
 CONFIG_X86_INVLPG=y
 CONFIG_X86_BSWAP=y
 CONFIG_X86_POPAD_OK=y
-CONFIG_X86_GOOD_APIC=y
 CONFIG_X86_USE_PPRO_CHECKSUM=y
 CONFIG_X86_TSC=y
+CONFIG_X86_CMPXCHG64=y
 CONFIG_X86_CMOV=y
-CONFIG_X86_MINIMUM_CPU_FAMILY=4
-CONFIG_X86_DEBUGCTLMSR=y
+CONFIG_X86_MINIMUM_CPU_FAMILY=5
+CONFIG_CPU_SUP_INTEL=y
+CONFIG_CPU_SUP_CYRIX_32=y
+CONFIG_CPU_SUP_AMD=y
+CONFIG_CPU_SUP_CENTAUR=y
+CONFIG_CPU_SUP_TRANSMETA_32=y
+CONFIG_CPU_SUP_UMC_32=y
 CONFIG_UML_X86=y
-CONFIG_X86_32=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_64BIT is not set
-CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_X86_32=y
+# CONFIG_X86_64 is not set
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_3_LEVEL_PGTABLES is not set
 CONFIG_ARCH_HAS_SC_SIGNALS=y
 CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y
 CONFIG_GENERIC_HWEIGHT=y
+# CONFIG_STATIC_LINK is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
-# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_COMPACTION is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=0
 CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_NEED_PER_CPU_KM=y
+# CONFIG_CLEANCACHE is not set
 CONFIG_TICK_ONESHOT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 CONFIG_LD_SCRIPT_DYN=y
 CONFIG_BINFMT_ELF=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_HAVE_AOUT=y
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_MISC=m
 CONFIG_HOSTFS=y
 # CONFIG_HPPFS is not set
 CONFIG_MCONSOLE=y
 CONFIG_MAGIC_SYSRQ=y
-# CONFIG_HIGHMEM is not set
 CONFIG_KERNEL_STACK_ORDER=0
+# CONFIG_MMAPPER is not set
+CONFIG_NO_DMA=y
 
 #
 # General setup
@@ -108,99 +116,169 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=128
+CONFIG_CROSS_COMPILE=""
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
+CONFIG_DEFAULT_HOSTNAME="(none)"
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_FHANDLE is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_PID_NS is not set
 # CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_SHOW=y
+
+#
+# RCU Subsystem
+#
+CONFIG_TINY_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+# CONFIG_TREE_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_MEM_RES_CTLR=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
+# CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED is not set
+# CONFIG_CGROUP_MEM_RES_CTLR_KMEM is not set
+CONFIG_CGROUP_SCHED=y
 CONFIG_FAIR_GROUP_SCHED=y
-CONFIG_FAIR_USER_SCHED=y
-# CONFIG_FAIR_CGROUP_SCHED is not set
+# CONFIG_CFS_BANDWIDTH is not set
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_BLK_CGROUP=m
+# CONFIG_DEBUG_BLK_CGROUP is not set
+# CONFIG_CHECKPOINT_RESTORE is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_NET_NS=y
+# CONFIG_SCHED_AUTOGROUP is not set
+CONFIG_MM_OWNER=y
 CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
 # CONFIG_BLK_DEV_INITRD is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 # CONFIG_EXPERT is not set
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
-CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
 CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
+CONFIG_AIO=y
+# CONFIG_EMBEDDED is not set
+
+#
+# Kernel Performance Events And Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
-# CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
-# CONFIG_HAVE_OPROFILE is not set
-# CONFIG_HAVE_KPROBES is not set
-CONFIG_PROC_PAGE_MONITOR=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
+CONFIG_LBDAF=y
 # CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
 
 #
 # IO Schedulers
 #
 CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-CONFIG_DEFAULT_AS=y
-# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=m
+# CONFIG_CFQ_GROUP_IOSCHED is not set
+CONFIG_DEFAULT_DEADLINE=y
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="anticipatory"
-CONFIG_CLASSIC_RCU=y
-# CONFIG_PREEMPT_RCU is not set
-CONFIG_BLK_DEV=y
-CONFIG_BLK_DEV_UBD=y
-# CONFIG_BLK_DEV_UBD_SYNC is not set
-CONFIG_BLK_DEV_COW_COMMON=y
-CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-CONFIG_BLK_DEV_NBD=m
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_ATA_OVER_ETH is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+CONFIG_FREEZER=y
 
 #
-# Character Devices
+# UML Character Devices
 #
 CONFIG_STDERR_CONSOLE=y
 CONFIG_STDIO_CONSOLE=y
@@ -214,40 +292,191 @@
 CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
 CONFIG_CON_CHAN="xterm"
 CONFIG_SSL_CHAN="pts"
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-# CONFIG_RAW_DRIVER is not set
-CONFIG_LEGACY_PTY_COUNT=32
-# CONFIG_WATCHDOG is not set
 CONFIG_UML_SOUND=m
 CONFIG_SOUND=m
+CONFIG_SOUND_OSS_CORE=y
 CONFIG_HOSTAUDIO=m
-# CONFIG_HW_RANDOM is not set
-CONFIG_UML_RANDOM=y
-# CONFIG_MMAPPER is not set
+
+#
+# Device Drivers
+#
 
 #
 # Generic Driver Options
 #
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
+CONFIG_GENERIC_CPU_DEVICES=y
+# CONFIG_DMA_SHARED_BUFFER is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+CONFIG_BLK_DEV=y
+CONFIG_BLK_DEV_UBD=y
+# CONFIG_BLK_DEV_UBD_SYNC is not set
+CONFIG_BLK_DEV_COW_COMMON=y
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
 
 #
-# Networking
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
 #
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_RBD is not set
+
+#
+# Misc devices
+#
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+
+#
+# Altera FPGA firmware download module
+#
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_CORE=y
+# CONFIG_BONDING is not set
+CONFIG_DUMMY=m
+# CONFIG_EQUALIZER is not set
+# CONFIG_MII is not set
+# CONFIG_NET_TEAM is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+CONFIG_TUN=m
+# CONFIG_VETH is not set
+
+#
+# CAIF transport drivers
+#
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_CHELSIO=y
+CONFIG_NET_VENDOR_INTEL=y
+CONFIG_NET_VENDOR_I825XX=y
+CONFIG_NET_VENDOR_MARVELL=y
+CONFIG_NET_VENDOR_NATSEMI=y
+CONFIG_NET_VENDOR_8390=y
+# CONFIG_PHYLIB is not set
+CONFIG_PPP=m
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_SLIP=m
+CONFIG_SLHC=m
+# CONFIG_SLIP_COMPRESSED is not set
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+CONFIG_WLAN=y
+# CONFIG_HOSTAP is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+
+#
+# Character devices
+#
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=32
+# CONFIG_N_GSM is not set
+# CONFIG_TRACE_SINK is not set
+CONFIG_DEVKMEM=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_UML_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_NSC_GPIO is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+
+#
+# Enable Device Drivers -> PPS to see the PTP clock options.
+#
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_REGULATOR is not set
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# Virtio drivers
+#
+# CONFIG_VIRTIO_BALLOON is not set
+
+#
+# Microsoft Hyper-V guest support
+#
+# CONFIG_STAGING is not set
+
+#
+# Hardware Spinlock drivers
+#
+CONFIG_IOMMU_SUPPORT=y
+# CONFIG_VIRT_DRIVERS is not set
+# CONFIG_PM_DEVFREQ is not set
 CONFIG_NET=y
 
 #
 # Networking options
 #
 CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
+# CONFIG_UNIX_DIAG is not set
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
 # CONFIG_XFRM_SUB_POLICY is not set
@@ -257,10 +486,9 @@
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
 # CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
 # CONFIG_ARPD is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
@@ -274,20 +502,23 @@
 # CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
+# CONFIG_INET_UDP_DIAG is not set
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TCP_MD5SIG is not set
 # CONFIG_IPV6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
+# CONFIG_L2TP is not set
 # CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_DECNET is not set
 # CONFIG_LLC2 is not set
@@ -297,7 +528,14 @@
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_NETPRIO_CGROUP is not set
+CONFIG_BQL=y
 
 #
 # Network testing
@@ -308,16 +546,19 @@
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_LIB80211 is not set
 
 #
-# Wireless
+# CFG80211 needs to be enabled for MAC80211
 #
-# CONFIG_CFG80211 is not set
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_NFC is not set
 
 #
 # UML Network Devices
@@ -331,76 +572,51 @@
 CONFIG_UML_NET_MCAST=y
 # CONFIG_UML_NET_PCAP is not set
 CONFIG_UML_NET_SLIRP=y
-CONFIG_NETDEVICES=y
-# CONFIG_NETDEVICES_MULTIQUEUE is not set
-CONFIG_DUMMY=m
-# CONFIG_BONDING is not set
-# CONFIG_MACVLAN is not set
-# CONFIG_EQUALIZER is not set
-CONFIG_TUN=m
-# CONFIG_VETH is not set
-
-#
-# Wireless LAN
-#
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_WAN is not set
-CONFIG_PPP=m
-# CONFIG_PPP_MULTILINK is not set
-# CONFIG_PPP_FILTER is not set
-# CONFIG_PPP_ASYNC is not set
-# CONFIG_PPP_SYNC_TTY is not set
-# CONFIG_PPP_DEFLATE is not set
-# CONFIG_PPP_BSDCOMP is not set
-# CONFIG_PPP_MPPE is not set
-# CONFIG_PPPOE is not set
-# CONFIG_PPPOL2TP is not set
-CONFIG_SLIP=m
-# CONFIG_SLIP_COMPRESSED is not set
-CONFIG_SLHC=m
-# CONFIG_SLIP_SMART is not set
-# CONFIG_SLIP_MODE_SLIP6 is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_CONNECTOR is not set
 
 #
 # File systems
 #
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-# CONFIG_EXT4DEV_FS is not set
-CONFIG_JBD=y
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_USE_FOR_EXT23=y
+CONFIG_EXT4_FS_XATTR=y
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+# CONFIG_EXT4_FS_SECURITY is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD2=y
+CONFIG_FS_MBCACHE=y
 CONFIG_REISERFS_FS=y
 # CONFIG_REISERFS_CHECK is not set
 # CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_REISERFS_FS_XATTR is not set
 # CONFIG_JFS_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
 # CONFIG_GFS2_FS is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_INOTIFY=y
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
 CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
 CONFIG_QUOTA=y
 # CONFIG_QUOTA_NETLINK_INTERFACE is not set
 CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QUOTA_DEBUG is not set
 # CONFIG_QFMT_V1 is not set
 # CONFIG_QFMT_V2 is not set
 CONFIG_QUOTACTL=y
-CONFIG_DNOTIFY=y
-CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 # CONFIG_FUSE_FS is not set
 
 #
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=m
@@ -421,15 +637,14 @@
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
@@ -437,26 +652,26 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
+# CONFIG_LOGFS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_PSTORE is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
-# CONFIG_SMB_FS is not set
+# CONFIG_CEPH_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
 CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_CODEPAGE_437 is not set
@@ -497,119 +712,191 @@
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
-# CONFIG_DLM is not set
 
 #
 # Security options
 #
 # CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
 # CONFIG_SECURITY is not set
-# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
 CONFIG_CRYPTO=y
-# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=m
 # CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_USER is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_XCBC is not set
-# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
 # CONFIG_CRYPTO_SHA1 is not set
 # CONFIG_CRYPTO_SHA256 is not set
 # CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
 # CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_GF128MUL is not set
-# CONFIG_CRYPTO_ECB is not set
-# CONFIG_CRYPTO_CBC is not set
-# CONFIG_CRYPTO_PCBC is not set
-# CONFIG_CRYPTO_LRW is not set
-# CONFIG_CRYPTO_XTS is not set
-# CONFIG_CRYPTO_CTR is not set
-# CONFIG_CRYPTO_GCM is not set
-# CONFIG_CRYPTO_CCM is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-# CONFIG_CRYPTO_DES is not set
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_TWOFISH_586 is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
 # CONFIG_CRYPTO_AES_586 is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_CAST5 is not set
 # CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
 # CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_SEED is not set
 # CONFIG_CRYPTO_SALSA20 is not set
 # CONFIG_CRYPTO_SALSA20_586 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_TWOFISH_586 is not set
+
+#
+# Compression
+#
 # CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_CAMELLIA is not set
-# CONFIG_CRYPTO_TEST is not set
-# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_ZLIB is not set
 # CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
 #
-CONFIG_BITREVERSE=m
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_IO=y
 # CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
 # CONFIG_CRC_ITU_T is not set
-CONFIG_CRC32=m
+CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
-CONFIG_PLIST=y
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
-# CONFIG_SCSI_DMA is not set
-# CONFIG_SCSI_NETLINK is not set
-# CONFIG_MD is not set
-# CONFIG_INPUT is not set
+# CONFIG_CRC8 is not set
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_DQL=y
+CONFIG_NLATTR=y
+# CONFIG_AVERAGE is not set
+# CONFIG_CORDIC is not set
 
 #
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
 CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 # CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
-CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+# CONFIG_DETECT_HUNG_TASK is not set
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_INFO_REDUCED is not set
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
 # CONFIG_DEBUG_LIST is not set
+# CONFIG_TEST_LIST_SORT is not set
 # CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
 CONFIG_FRAME_POINTER=y
-CONFIG_FORCED_INLINING=y
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
 # CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
 # CONFIG_SAMPLES is not set
+# CONFIG_TEST_KSTRTOX is not set
 # CONFIG_GPROF is not set
 # CONFIG_GCOV is not set
-# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_EARLY_PRINTK=y
diff --git a/arch/um/drivers/chan.h b/arch/um/drivers/chan.h
index 8df0fd90..02b5a76 100644
--- a/arch/um/drivers/chan.h
+++ b/arch/um/drivers/chan.h
@@ -27,24 +27,24 @@
 	void *data;
 };
 
-extern void chan_interrupt(struct list_head *chans, struct delayed_work *task,
+extern void chan_interrupt(struct line *line,
 			   struct tty_struct *tty, int irq);
 extern int parse_chan_pair(char *str, struct line *line, int device,
 			   const struct chan_opts *opts, char **error_out);
-extern int write_chan(struct list_head *chans, const char *buf, int len,
+extern int write_chan(struct chan *chan, const char *buf, int len,
 			     int write_irq);
-extern int console_write_chan(struct list_head *chans, const char *buf, 
+extern int console_write_chan(struct chan *chan, const char *buf, 
 			      int len);
 extern int console_open_chan(struct line *line, struct console *co);
-extern void deactivate_chan(struct list_head *chans, int irq);
-extern void reactivate_chan(struct list_head *chans, int irq);
-extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty);
+extern void deactivate_chan(struct chan *chan, int irq);
+extern void reactivate_chan(struct chan *chan, int irq);
+extern void chan_enable_winch(struct chan *chan, struct tty_struct *tty);
 extern int enable_chan(struct line *line);
-extern void close_chan(struct list_head *chans, int delay_free_irq);
-extern int chan_window_size(struct list_head *chans, 
+extern void close_chan(struct line *line);
+extern int chan_window_size(struct line *line, 
 			     unsigned short *rows_out, 
 			     unsigned short *cols_out);
-extern int chan_config_string(struct list_head *chans, char *str, int size,
+extern int chan_config_string(struct line *line, char *str, int size,
 			      char **error_out);
 
 #endif
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 420e2c8..ca4c7eb 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -140,18 +140,18 @@
 	return err;
 }
 
-void chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
+void chan_enable_winch(struct chan *chan, struct tty_struct *tty)
 {
-	struct list_head *ele;
-	struct chan *chan;
+	if (chan && chan->primary && chan->ops->winch)
+		register_winch(chan->fd, tty);
+}
 
-	list_for_each(ele, chans) {
-		chan = list_entry(ele, struct chan, list);
-		if (chan->primary && chan->output && chan->ops->winch) {
-			register_winch(chan->fd, tty);
-			return;
-		}
-	}
+static void line_timer_cb(struct work_struct *work)
+{
+	struct line *line = container_of(work, struct line, task.work);
+
+	if (!line->throttled)
+		chan_interrupt(line, line->tty, line->driver->read_irq);
 }
 
 int enable_chan(struct line *line)
@@ -160,6 +160,8 @@
 	struct chan *chan;
 	int err;
 
+	INIT_DELAYED_WORK(&line->task, line_timer_cb);
+
 	list_for_each(ele, &line->chan_list) {
 		chan = list_entry(ele, struct chan, list);
 		err = open_one_chan(chan);
@@ -183,7 +185,7 @@
 	return 0;
 
  out_close:
-	close_chan(&line->chan_list, 0);
+	close_chan(line);
 	return err;
 }
 
@@ -244,7 +246,7 @@
 	chan->fd = -1;
 }
 
-void close_chan(struct list_head *chans, int delay_free_irq)
+void close_chan(struct line *line)
 {
 	struct chan *chan;
 
@@ -253,77 +255,50 @@
 	 * state.  Then, the first one opened will have the original state,
 	 * so it must be the last closed.
 	 */
-	list_for_each_entry_reverse(chan, chans, list) {
-		close_one_chan(chan, delay_free_irq);
+	list_for_each_entry_reverse(chan, &line->chan_list, list) {
+		close_one_chan(chan, 0);
 	}
 }
 
-void deactivate_chan(struct list_head *chans, int irq)
+void deactivate_chan(struct chan *chan, int irq)
 {
-	struct list_head *ele;
-
-	struct chan *chan;
-	list_for_each(ele, chans) {
-		chan = list_entry(ele, struct chan, list);
-
-		if (chan->enabled && chan->input)
-			deactivate_fd(chan->fd, irq);
-	}
+	if (chan && chan->enabled)
+		deactivate_fd(chan->fd, irq);
 }
 
-void reactivate_chan(struct list_head *chans, int irq)
+void reactivate_chan(struct chan *chan, int irq)
 {
-	struct list_head *ele;
-	struct chan *chan;
-
-	list_for_each(ele, chans) {
-		chan = list_entry(ele, struct chan, list);
-
-		if (chan->enabled && chan->input)
-			reactivate_fd(chan->fd, irq);
-	}
+	if (chan && chan->enabled)
+		reactivate_fd(chan->fd, irq);
 }
 
-int write_chan(struct list_head *chans, const char *buf, int len,
+int write_chan(struct chan *chan, const char *buf, int len,
 	       int write_irq)
 {
-	struct list_head *ele;
-	struct chan *chan = NULL;
 	int n, ret = 0;
 
-	if (len == 0)
+	if (len == 0 || !chan || !chan->ops->write)
 		return 0;
 
-	list_for_each(ele, chans) {
-		chan = list_entry(ele, struct chan, list);
-		if (!chan->output || (chan->ops->write == NULL))
-			continue;
-
-		n = chan->ops->write(chan->fd, buf, len, chan->data);
-		if (chan->primary) {
-			ret = n;
-			if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
-				reactivate_fd(chan->fd, write_irq);
-		}
+	n = chan->ops->write(chan->fd, buf, len, chan->data);
+	if (chan->primary) {
+		ret = n;
+		if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
+			reactivate_fd(chan->fd, write_irq);
 	}
 	return ret;
 }
 
-int console_write_chan(struct list_head *chans, const char *buf, int len)
+int console_write_chan(struct chan *chan, const char *buf, int len)
 {
-	struct list_head *ele;
-	struct chan *chan;
 	int n, ret = 0;
 
-	list_for_each(ele, chans) {
-		chan = list_entry(ele, struct chan, list);
-		if (!chan->output || (chan->ops->console_write == NULL))
-			continue;
+	if (!chan || !chan->ops->console_write)
+		return 0;
 
-		n = chan->ops->console_write(chan->fd, buf, len);
-		if (chan->primary)
-			ret = n;
-	}
+	n = chan->ops->console_write(chan->fd, buf, len);
+	if (chan->primary)
+		ret = n;
 	return ret;
 }
 
@@ -340,20 +315,24 @@
 	return 0;
 }
 
-int chan_window_size(struct list_head *chans, unsigned short *rows_out,
+int chan_window_size(struct line *line, unsigned short *rows_out,
 		      unsigned short *cols_out)
 {
-	struct list_head *ele;
 	struct chan *chan;
 
-	list_for_each(ele, chans) {
-		chan = list_entry(ele, struct chan, list);
-		if (chan->primary) {
-			if (chan->ops->window_size == NULL)
-				return 0;
-			return chan->ops->window_size(chan->fd, chan->data,
-						      rows_out, cols_out);
-		}
+	chan = line->chan_in;
+	if (chan && chan->primary) {
+		if (chan->ops->window_size == NULL)
+			return 0;
+		return chan->ops->window_size(chan->fd, chan->data,
+					      rows_out, cols_out);
+	}
+	chan = line->chan_out;
+	if (chan && chan->primary) {
+		if (chan->ops->window_size == NULL)
+			return 0;
+		return chan->ops->window_size(chan->fd, chan->data,
+					      rows_out, cols_out);
 	}
 	return 0;
 }
@@ -429,21 +408,15 @@
 	return n;
 }
 
-int chan_config_string(struct list_head *chans, char *str, int size,
+int chan_config_string(struct line *line, char *str, int size,
 		       char **error_out)
 {
-	struct list_head *ele;
-	struct chan *chan, *in = NULL, *out = NULL;
+	struct chan *in = line->chan_in, *out = line->chan_out;
 
-	list_for_each(ele, chans) {
-		chan = list_entry(ele, struct chan, list);
-		if (!chan->primary)
-			continue;
-		if (chan->input)
-			in = chan;
-		if (chan->output)
-			out = chan;
-	}
+	if (in && !in->primary)
+		in = NULL;
+	if (out && !out->primary)
+		out = NULL;
 
 	return chan_pair_config_string(in, out, str, size, error_out);
 }
@@ -547,10 +520,14 @@
 	char *in, *out;
 
 	if (!list_empty(chans)) {
+		line->chan_in = line->chan_out = NULL;
 		free_chan(chans);
 		INIT_LIST_HEAD(chans);
 	}
 
+	if (!str)
+		return 0;
+
 	out = strchr(str, ',');
 	if (out != NULL) {
 		in = str;
@@ -562,6 +539,7 @@
 
 		new->input = 1;
 		list_add(&new->list, chans);
+		line->chan_in = new;
 
 		new = parse_chan(line, out, device, opts, error_out);
 		if (new == NULL)
@@ -569,6 +547,7 @@
 
 		list_add(&new->list, chans);
 		new->output = 1;
+		line->chan_out = new;
 	}
 	else {
 		new = parse_chan(line, str, device, opts, error_out);
@@ -578,43 +557,42 @@
 		list_add(&new->list, chans);
 		new->input = 1;
 		new->output = 1;
+		line->chan_in = line->chan_out = new;
 	}
 	return 0;
 }
 
-void chan_interrupt(struct list_head *chans, struct delayed_work *task,
-		    struct tty_struct *tty, int irq)
+void chan_interrupt(struct line *line, struct tty_struct *tty, int irq)
 {
-	struct list_head *ele, *next;
-	struct chan *chan;
+	struct chan *chan = line->chan_in;
 	int err;
 	char c;
 
-	list_for_each_safe(ele, next, chans) {
-		chan = list_entry(ele, struct chan, list);
-		if (!chan->input || (chan->ops->read == NULL))
-			continue;
-		do {
-			if (tty && !tty_buffer_request_room(tty, 1)) {
-				schedule_delayed_work(task, 1);
-				goto out;
-			}
-			err = chan->ops->read(chan->fd, &c, chan->data);
-			if (err > 0)
-				tty_receive_char(tty, c);
-		} while (err > 0);
+	if (!chan || !chan->ops->read)
+		goto out;
 
-		if (err == 0)
-			reactivate_fd(chan->fd, irq);
-		if (err == -EIO) {
-			if (chan->primary) {
-				if (tty != NULL)
-					tty_hangup(tty);
-				close_chan(chans, 1);
-				return;
-			}
-			else close_one_chan(chan, 1);
+	do {
+		if (tty && !tty_buffer_request_room(tty, 1)) {
+			schedule_delayed_work(&line->task, 1);
+			goto out;
 		}
+		err = chan->ops->read(chan->fd, &c, chan->data);
+		if (err > 0)
+			tty_receive_char(tty, c);
+	} while (err > 0);
+
+	if (err == 0)
+		reactivate_fd(chan->fd, irq);
+	if (err == -EIO) {
+		if (chan->primary) {
+			if (tty != NULL)
+				tty_hangup(tty);
+			if (line->chan_out != chan)
+				close_one_chan(line->chan_out, 1);
+		}
+		close_one_chan(chan, 1);
+		if (chan->primary)
+			return;
 	}
  out:
 	if (tty)
diff --git a/arch/um/drivers/chan_user.h b/arch/um/drivers/chan_user.h
index 9b9ced8..6257b7a 100644
--- a/arch/um/drivers/chan_user.h
+++ b/arch/um/drivers/chan_user.h
@@ -14,8 +14,6 @@
 	const int raw;
 };
 
-enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE };
-
 struct chan_ops {
 	char *type;
 	void *(*init)(char *, int, const struct chan_opts *);
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index c1cf220..4ab0d9c 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -21,19 +21,10 @@
 	struct line *line = chan->line;
 
 	if (line)
-		chan_interrupt(&line->chan_list, &line->task, line->tty, irq);
+		chan_interrupt(line, line->tty, irq);
 	return IRQ_HANDLED;
 }
 
-static void line_timer_cb(struct work_struct *work)
-{
-	struct line *line = container_of(work, struct line, task.work);
-
-	if (!line->throttled)
-		chan_interrupt(&line->chan_list, &line->task, line->tty,
-			       line->driver->read_irq);
-}
-
 /*
  * Returns the free space inside the ring buffer of this line.
  *
@@ -145,7 +136,7 @@
 		/* line->buffer + LINE_BUFSIZE is the end of the buffer! */
 		count = line->buffer + LINE_BUFSIZE - line->head;
 
-		n = write_chan(&line->chan_list, line->head, count,
+		n = write_chan(line->chan_out, line->head, count,
 			       line->driver->write_irq);
 		if (n < 0)
 			return n;
@@ -162,7 +153,7 @@
 	}
 
 	count = line->tail - line->head;
-	n = write_chan(&line->chan_list, line->head, count,
+	n = write_chan(line->chan_out, line->head, count,
 		       line->driver->write_irq);
 
 	if (n < 0)
@@ -206,7 +197,7 @@
 	if (line->head != line->tail)
 		ret = buffer_data(line, buf, len);
 	else {
-		n = write_chan(&line->chan_list, buf, len,
+		n = write_chan(line->chan_out, buf, len,
 			       line->driver->write_irq);
 		if (n < 0) {
 			ret = n;
@@ -318,7 +309,7 @@
 {
 	struct line *line = tty->driver_data;
 
-	deactivate_chan(&line->chan_list, line->driver->read_irq);
+	deactivate_chan(line->chan_in, line->driver->read_irq);
 	line->throttled = 1;
 }
 
@@ -327,8 +318,7 @@
 	struct line *line = tty->driver_data;
 
 	line->throttled = 0;
-	chan_interrupt(&line->chan_list, &line->task, tty,
-		       line->driver->read_irq);
+	chan_interrupt(line, tty, line->driver->read_irq);
 
 	/*
 	 * Maybe there is enough stuff pending that calling the interrupt
@@ -336,7 +326,7 @@
 	 * again and we shouldn't turn the interrupt back on.
 	 */
 	if (!line->throttled)
-		reactivate_chan(&line->chan_list, line->driver->read_irq);
+		reactivate_chan(line->chan_in, line->driver->read_irq);
 }
 
 static irqreturn_t line_write_interrupt(int irq, void *data)
@@ -347,13 +337,14 @@
 	int err;
 
 	/*
-	 * Interrupts are disabled here because we registered the interrupt with
-	 * IRQF_DISABLED (see line_setup_irq).
+	 * Interrupts are disabled here because genirq keep irqs disabled when
+	 * calling the action handler.
 	 */
 
 	spin_lock(&line->lock);
 	err = flush_buffer(line);
 	if (err == 0) {
+		spin_unlock(&line->lock);
 		return IRQ_NONE;
 	} else if (err < 0) {
 		line->head = line->buffer;
@@ -371,7 +362,7 @@
 int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
 {
 	const struct line_driver *driver = line->driver;
-	int err = 0, flags = IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM;
+	int err = 0, flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM;
 
 	if (input)
 		err = um_request_irq(driver->read_irq, fd, IRQ_READ,
@@ -383,7 +374,6 @@
 		err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
 					line_write_interrupt, flags,
 					driver->write_irq_name, data);
-	line->have_irq = 1;
 	return err;
 }
 
@@ -409,7 +399,7 @@
 	struct line *line = &lines[tty->index];
 	int err = -ENODEV;
 
-	spin_lock(&line->count_lock);
+	mutex_lock(&line->count_lock);
 	if (!line->valid)
 		goto out_unlock;
 
@@ -421,25 +411,19 @@
 	tty->driver_data = line;
 	line->tty = tty;
 
-	spin_unlock(&line->count_lock);
 	err = enable_chan(line);
 	if (err) /* line_close() will be called by our caller */
-		return err;
-
-	INIT_DELAYED_WORK(&line->task, line_timer_cb);
+		goto out_unlock;
 
 	if (!line->sigio) {
-		chan_enable_winch(&line->chan_list, tty);
+		chan_enable_winch(line->chan_out, tty);
 		line->sigio = 1;
 	}
 
-	chan_window_size(&line->chan_list, &tty->winsize.ws_row,
+	chan_window_size(line, &tty->winsize.ws_row,
 			 &tty->winsize.ws_col);
-
-	return 0;
-
 out_unlock:
-	spin_unlock(&line->count_lock);
+	mutex_unlock(&line->count_lock);
 	return err;
 }
 
@@ -459,7 +443,7 @@
 	/* We ignore the error anyway! */
 	flush_buffer(line);
 
-	spin_lock(&line->count_lock);
+	mutex_lock(&line->count_lock);
 	BUG_ON(!line->valid);
 
 	if (--line->count)
@@ -468,17 +452,13 @@
 	line->tty = NULL;
 	tty->driver_data = NULL;
 
-	spin_unlock(&line->count_lock);
-
 	if (line->sigio) {
 		unregister_winch(tty);
 		line->sigio = 0;
 	}
 
-	return;
-
 out_unlock:
-	spin_unlock(&line->count_lock);
+	mutex_unlock(&line->count_lock);
 }
 
 void close_lines(struct line *lines, int nlines)
@@ -486,34 +466,60 @@
 	int i;
 
 	for(i = 0; i < nlines; i++)
-		close_chan(&lines[i].chan_list, 0);
+		close_chan(&lines[i]);
 }
 
-static int setup_one_line(struct line *lines, int n, char *init, int init_prio,
-			  char **error_out)
+int setup_one_line(struct line *lines, int n, char *init,
+		   const struct chan_opts *opts, char **error_out)
 {
 	struct line *line = &lines[n];
+	struct tty_driver *driver = line->driver->driver;
 	int err = -EINVAL;
 
-	spin_lock(&line->count_lock);
+	mutex_lock(&line->count_lock);
 
 	if (line->count) {
 		*error_out = "Device is already open";
 		goto out;
 	}
 
-	if (line->init_pri <= init_prio) {
-		line->init_pri = init_prio;
-		if (!strcmp(init, "none"))
+	if (!strcmp(init, "none")) {
+		if (line->valid) {
 			line->valid = 0;
-		else {
-			line->init_str = init;
-			line->valid = 1;
+			kfree(line->init_str);
+			tty_unregister_device(driver, n);
+			parse_chan_pair(NULL, line, n, opts, error_out);
+			err = 0;
+		}
+	} else {
+		char *new = kstrdup(init, GFP_KERNEL);
+		if (!new) {
+			*error_out = "Failed to allocate memory";
+			return -ENOMEM;
+		}
+		if (line->valid) {
+			tty_unregister_device(driver, n);
+			kfree(line->init_str);
+		}
+		line->init_str = new;
+		line->valid = 1;
+		err = parse_chan_pair(new, line, n, opts, error_out);
+		if (!err) {
+			struct device *d = tty_register_device(driver, n, NULL);
+			if (IS_ERR(d)) {
+				*error_out = "Failed to register device";
+				err = PTR_ERR(d);
+				parse_chan_pair(NULL, line, n, opts, error_out);
+			}
+		}
+		if (err) {
+			line->init_str = NULL;
+			line->valid = 0;
+			kfree(new);
 		}
 	}
-	err = 0;
 out:
-	spin_unlock(&line->count_lock);
+	mutex_unlock(&line->count_lock);
 	return err;
 }
 
@@ -524,54 +530,43 @@
  * @error_out is an error string in the case of failure;
  */
 
-int line_setup(struct line *lines, unsigned int num, char *init,
-	       char **error_out)
+int line_setup(char **conf, unsigned int num, char **def,
+	       char *init, char *name)
 {
-	int i, n, err;
-	char *end;
+	char *error;
 
 	if (*init == '=') {
 		/*
 		 * We said con=/ssl= instead of con#=, so we are configuring all
 		 * consoles at once.
 		 */
-		n = -1;
-	}
-	else {
-		n = simple_strtoul(init, &end, 0);
-		if (*end != '=') {
-			*error_out = "Couldn't parse device number";
-			return -EINVAL;
-		}
-		init = end;
-	}
-	init++;
+		*def = init + 1;
+	} else {
+		char *end;
+		unsigned n = simple_strtoul(init, &end, 0);
 
-	if (n >= (signed int) num) {
-		*error_out = "Device number out of range";
-		return -EINVAL;
-	}
-	else if (n >= 0) {
-		err = setup_one_line(lines, n, init, INIT_ONE, error_out);
-		if (err)
-			return err;
-	}
-	else {
-		for(i = 0; i < num; i++) {
-			err = setup_one_line(lines, i, init, INIT_ALL,
-					     error_out);
-			if (err)
-				return err;
+		if (*end != '=') {
+			error = "Couldn't parse device number";
+			goto out;
 		}
+		if (n >= num) {
+			error = "Device number out of range";
+			goto out;
+		}
+		conf[n] = end + 1;
 	}
-	return n == -1 ? num : n;
+	return 0;
+
+out:
+	printk(KERN_ERR "Failed to set up %s with "
+	       "configuration string \"%s\" : %s\n", name, init, error);
+	return -EINVAL;
 }
 
 int line_config(struct line *lines, unsigned int num, char *str,
 		const struct chan_opts *opts, char **error_out)
 {
-	struct line *line;
-	char *new;
+	char *end;
 	int n;
 
 	if (*str == '=') {
@@ -579,17 +574,17 @@
 		return -EINVAL;
 	}
 
-	new = kstrdup(str, GFP_KERNEL);
-	if (new == NULL) {
-		*error_out = "Failed to allocate memory";
-		return -ENOMEM;
+	n = simple_strtoul(str, &end, 0);
+	if (*end++ != '=') {
+		*error_out = "Couldn't parse device number";
+		return -EINVAL;
 	}
-	n = line_setup(lines, num, new, error_out);
-	if (n < 0)
-		return n;
+	if (n >= num) {
+		*error_out = "Device number out of range";
+		return -EINVAL;
+	}
 
-	line = &lines[n];
-	return parse_chan_pair(line->init_str, line, n, opts, error_out);
+	return setup_one_line(lines, n, end, opts, error_out);
 }
 
 int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
@@ -612,13 +607,13 @@
 
 	line = &lines[dev];
 
-	spin_lock(&line->count_lock);
+	mutex_lock(&line->count_lock);
 	if (!line->valid)
 		CONFIG_CHUNK(str, size, n, "none", 1);
 	else if (line->tty == NULL)
 		CONFIG_CHUNK(str, size, n, line->init_str, 1);
-	else n = chan_config_string(&line->chan_list, str, size, error_out);
-	spin_unlock(&line->count_lock);
+	else n = chan_config_string(line, str, size, error_out);
+	mutex_unlock(&line->count_lock);
 
 	return n;
 }
@@ -640,25 +635,23 @@
 
 int line_remove(struct line *lines, unsigned int num, int n, char **error_out)
 {
-	int err;
-	char config[sizeof("conxxxx=none\0")];
-
-	sprintf(config, "%d=none", n);
-	err = line_setup(lines, num, config, error_out);
-	if (err >= 0)
-		err = 0;
-	return err;
+	if (n >= num) {
+		*error_out = "Device number out of range";
+		return -EINVAL;
+	}
+	return setup_one_line(lines, n, "none", NULL, error_out);
 }
 
-struct tty_driver *register_lines(struct line_driver *line_driver,
-				  const struct tty_operations *ops,
-				  struct line *lines, int nlines)
+int register_lines(struct line_driver *line_driver,
+		   const struct tty_operations *ops,
+		   struct line *lines, int nlines)
 {
-	int i;
 	struct tty_driver *driver = alloc_tty_driver(nlines);
+	int err;
+	int i;
 
 	if (!driver)
-		return NULL;
+		return -ENOMEM;
 
 	driver->driver_name = line_driver->name;
 	driver->name = line_driver->device_name;
@@ -666,54 +659,33 @@
 	driver->minor_start = line_driver->minor_start;
 	driver->type = line_driver->type;
 	driver->subtype = line_driver->subtype;
-	driver->flags = TTY_DRIVER_REAL_RAW;
+	driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
 	driver->init_termios = tty_std_termios;
+	
+	for (i = 0; i < nlines; i++) {
+		spin_lock_init(&lines[i].lock);
+		mutex_init(&lines[i].count_lock);
+		lines[i].driver = line_driver;
+		INIT_LIST_HEAD(&lines[i].chan_list);
+	}
 	tty_set_operations(driver, ops);
 
-	if (tty_register_driver(driver)) {
+	err = tty_register_driver(driver);
+	if (err) {
 		printk(KERN_ERR "register_lines : can't register %s driver\n",
 		       line_driver->name);
 		put_tty_driver(driver);
-		return NULL;
+		return err;
 	}
 
-	for(i = 0; i < nlines; i++) {
-		if (!lines[i].valid)
-			tty_unregister_device(driver, i);
-	}
-
+	line_driver->driver = driver;
 	mconsole_register_dev(&line_driver->mc);
-	return driver;
+	return 0;
 }
 
 static DEFINE_SPINLOCK(winch_handler_lock);
 static LIST_HEAD(winch_handlers);
 
-void lines_init(struct line *lines, int nlines, struct chan_opts *opts)
-{
-	struct line *line;
-	char *error;
-	int i;
-
-	for(i = 0; i < nlines; i++) {
-		line = &lines[i];
-		INIT_LIST_HEAD(&line->chan_list);
-
-		if (line->init_str == NULL)
-			continue;
-
-		line->init_str = kstrdup(line->init_str, GFP_KERNEL);
-		if (line->init_str == NULL)
-			printk(KERN_ERR "lines_init - kstrdup returned NULL\n");
-
-		if (parse_chan_pair(line->init_str, line, i, opts, &error)) {
-			printk(KERN_ERR "parse_chan_pair failed for "
-			       "device %d : %s\n", i, error);
-			line->valid = 0;
-		}
-	}
-}
-
 struct winch {
 	struct list_head list;
 	int fd;
@@ -777,7 +749,7 @@
 	if (tty != NULL) {
 		line = tty->driver_data;
 		if (line != NULL) {
-			chan_window_size(&line->chan_list, &tty->winsize.ws_row,
+			chan_window_size(line, &tty->winsize.ws_row,
 					 &tty->winsize.ws_col);
 			kill_pgrp(tty->pgrp, SIGWINCH, 1);
 		}
@@ -807,7 +779,7 @@
 				   .stack	= stack });
 
 	if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
-			   IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+			   IRQF_SHARED | IRQF_SAMPLE_RANDOM,
 			   "winch", winch) < 0) {
 		printk(KERN_ERR "register_winch_irq - failed to register "
 		       "IRQ\n");
diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h
index 63df3ca..0a18347 100644
--- a/arch/um/drivers/line.h
+++ b/arch/um/drivers/line.h
@@ -15,7 +15,7 @@
 #include "chan_user.h"
 #include "mconsole_kern.h"
 
-/* There's only one modifiable field in this - .mc.list */
+/* There's only two modifiable fields in this - .mc.list and .driver */
 struct line_driver {
 	const char *name;
 	const char *device_name;
@@ -28,17 +28,18 @@
 	const int write_irq;
 	const char *write_irq_name;
 	struct mc_device mc;
+	struct tty_driver *driver;
 };
 
 struct line {
 	struct tty_struct *tty;
-	spinlock_t count_lock;
+	struct mutex count_lock;
 	unsigned long count;
 	int valid;
 
 	char *init_str;
-	int init_pri;
 	struct list_head chan_list;
+	struct chan *chan_in, *chan_out;
 
 	/*This lock is actually, mostly, local to*/
 	spinlock_t lock;
@@ -55,21 +56,12 @@
 	int sigio;
 	struct delayed_work task;
 	const struct line_driver *driver;
-	int have_irq;
 };
 
-#define LINE_INIT(str, d) \
-	{ .count_lock =	__SPIN_LOCK_UNLOCKED((str).count_lock), \
-	  .init_str =	str,	\
-	  .init_pri =	INIT_STATIC, \
-	  .valid =	1, \
-	  .lock =	__SPIN_LOCK_UNLOCKED((str).lock), \
-	  .driver =	d }
-
 extern void line_close(struct tty_struct *tty, struct file * filp);
 extern int line_open(struct line *lines, struct tty_struct *tty);
-extern int line_setup(struct line *lines, unsigned int sizeof_lines,
-		      char *init, char **error_out);
+extern int line_setup(char **conf, unsigned nlines, char **def,
+		      char *init, char *name);
 extern int line_write(struct tty_struct *tty, const unsigned char *buf,
 		      int len);
 extern int line_put_char(struct tty_struct *tty, unsigned char ch);
@@ -87,10 +79,11 @@
 extern int line_setup_irq(int fd, int input, int output, struct line *line,
 			  void *data);
 extern void line_close_chan(struct line *line);
-extern struct tty_driver *register_lines(struct line_driver *line_driver,
-					 const struct tty_operations *driver,
-					 struct line *lines, int nlines);
-extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts);
+extern int register_lines(struct line_driver *line_driver,
+			  const struct tty_operations *driver,
+			  struct line *lines, int nlines);
+extern int setup_one_line(struct line *lines, int n, char *init,
+			  const struct chan_opts *opts, char **error_out);
 extern void close_lines(struct line *lines, int nlines);
 
 extern int line_config(struct line *lines, unsigned int sizeof_lines,
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index c70e047..e672bd6 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -773,7 +773,7 @@
 	register_reboot_notifier(&reboot_notifier);
 
 	err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt,
-			     IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+			     IRQF_SHARED | IRQF_SAMPLE_RANDOM,
 			     "mconsole", (void *)sock);
 	if (err) {
 		printk(KERN_ERR "Failed to get IRQ for management console\n");
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index d299618..95f4416 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -161,7 +161,7 @@
 	}
 
 	err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt,
-			     IRQF_DISABLED | IRQF_SHARED, dev->name, dev);
+			     IRQF_SHARED, dev->name, dev);
 	if (err != 0) {
 		printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err);
 		err = -ENETUNREACH;
diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
index a11573b..e31680e 100644
--- a/arch/um/drivers/port_kern.c
+++ b/arch/um/drivers/port_kern.c
@@ -100,7 +100,7 @@
 		  .port 	= port });
 
 	if (um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt,
-			  IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+			  IRQF_SHARED | IRQF_SAMPLE_RANDOM,
 			  "telnetd", conn)) {
 		printk(KERN_ERR "port_accept : failed to get IRQ for "
 		       "telnetd\n");
@@ -184,7 +184,7 @@
 	}
 
 	if (um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt,
-			  IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+			  IRQF_SHARED | IRQF_SAMPLE_RANDOM,
 			  "port", port)) {
 		printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num);
 		goto out_close;
diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c
index 981085a..b25296e 100644
--- a/arch/um/drivers/random.c
+++ b/arch/um/drivers/random.c
@@ -131,7 +131,7 @@
 	random_fd = err;
 
 	err = um_request_irq(RANDOM_IRQ, random_fd, IRQ_READ, random_interrupt,
-			     IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "random",
+			     IRQF_SAMPLE_RANDOM, "random",
 			     NULL);
 	if (err)
 		goto err_out_cleanup_hw;
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
index 9d8c20a..e09801a 100644
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -20,12 +20,6 @@
 
 static const int ssl_version = 1;
 
-/* Referenced only by tty_driver below - presumably it's locked correctly
- * by the tty driver.
- */
-
-static struct tty_driver *ssl_driver;
-
 #define NR_PORTS 64
 
 static void ssl_announce(char *dev_name, int dev)
@@ -71,8 +65,9 @@
 /* The array is initialized by line_init, at initcall time.  The
  * elements are locked individually as needed.
  */
-static struct line serial_lines[NR_PORTS] =
-	{ [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, &driver) };
+static char *conf[NR_PORTS];
+static char *def_conf = CONFIG_SSL_CHAN;
+static struct line serial_lines[NR_PORTS];
 
 static int ssl_config(char *str, char **error_out)
 {
@@ -156,14 +151,14 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&line->lock, flags);
-	console_write_chan(&line->chan_list, string, len);
+	console_write_chan(line->chan_out, string, len);
 	spin_unlock_irqrestore(&line->lock, flags);
 }
 
 static struct tty_driver *ssl_console_device(struct console *c, int *index)
 {
 	*index = c->index;
-	return ssl_driver;
+	return driver.driver;
 }
 
 static int ssl_console_setup(struct console *co, char *options)
@@ -186,17 +181,30 @@
 static int ssl_init(void)
 {
 	char *new_title;
+	int err;
+	int i;
 
 	printk(KERN_INFO "Initializing software serial port version %d\n",
 	       ssl_version);
-	ssl_driver = register_lines(&driver, &ssl_ops, serial_lines,
+
+	err = register_lines(&driver, &ssl_ops, serial_lines,
 				    ARRAY_SIZE(serial_lines));
+	if (err)
+		return err;
 
 	new_title = add_xterm_umid(opts.xterm_title);
 	if (new_title != NULL)
 		opts.xterm_title = new_title;
 
-	lines_init(serial_lines, ARRAY_SIZE(serial_lines), &opts);
+	for (i = 0; i < NR_PORTS; i++) {
+		char *error;
+		char *s = conf[i];
+		if (!s)
+			s = def_conf;
+		if (setup_one_line(serial_lines, i, s, &opts, &error))
+			printk(KERN_ERR "setup_one_line failed for "
+			       "device %d : %s\n", i, error);
+	}
 
 	ssl_init_done = 1;
 	register_console(&ssl_cons);
@@ -214,14 +222,7 @@
 
 static int ssl_chan_setup(char *str)
 {
-	char *error;
-	int ret;
-
-	ret = line_setup(serial_lines, ARRAY_SIZE(serial_lines), str, &error);
-	if(ret < 0)
-		printk(KERN_ERR "Failed to set up serial line with "
-		       "configuration string \"%s\" : %s\n", str, error);
-
+	line_setup(conf, NR_PORTS, &def_conf, str, "serial line");
 	return 1;
 }
 
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
index 088776f..7663541 100644
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -27,12 +27,6 @@
 
 #define MAX_TTYS (16)
 
-/* Referenced only by tty_driver below - presumably it's locked correctly
- * by the tty driver.
- */
-
-static struct tty_driver *console_driver;
-
 static void stdio_announce(char *dev_name, int dev)
 {
 	printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev,
@@ -76,9 +70,9 @@
 /* The array is initialized by line_init, at initcall time.  The
  * elements are locked individually as needed.
  */
-static struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver),
-				     [ 1 ... MAX_TTYS - 1 ] =
-				     LINE_INIT(CONFIG_CON_CHAN, &driver) };
+static char *vt_conf[MAX_TTYS];
+static char *def_conf;
+static struct line vts[MAX_TTYS];
 
 static int con_config(char *str, char **error_out)
 {
@@ -130,14 +124,14 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&line->lock, flags);
-	console_write_chan(&line->chan_list, string, len);
+	console_write_chan(line->chan_out, string, len);
 	spin_unlock_irqrestore(&line->lock, flags);
 }
 
 static struct tty_driver *uml_console_device(struct console *c, int *index)
 {
 	*index = c->index;
-	return console_driver;
+	return driver.driver;
 }
 
 static int uml_console_setup(struct console *co, char *options)
@@ -160,18 +154,31 @@
 static int stdio_init(void)
 {
 	char *new_title;
+	int err;
+	int i;
 
-	console_driver = register_lines(&driver, &console_ops, vts,
+	err = register_lines(&driver, &console_ops, vts,
 					ARRAY_SIZE(vts));
-	if (console_driver == NULL)
-		return -1;
+	if (err)
+		return err;
+
 	printk(KERN_INFO "Initialized stdio console driver\n");
 
 	new_title = add_xterm_umid(opts.xterm_title);
 	if(new_title != NULL)
 		opts.xterm_title = new_title;
 
-	lines_init(vts, ARRAY_SIZE(vts), &opts);
+	for (i = 0; i < MAX_TTYS; i++) {
+		char *error;
+		char *s = vt_conf[i];
+		if (!s)
+			s = def_conf;
+		if (!s)
+			s = i ? CONFIG_CON_CHAN : CONFIG_CON_ZERO_CHAN;
+		if (setup_one_line(vts, i, s, &opts, &error))
+			printk(KERN_ERR "setup_one_line failed for "
+			       "device %d : %s\n", i, error);
+	}
 
 	con_init_done = 1;
 	register_console(&stdiocons);
@@ -189,14 +196,7 @@
 
 static int console_chan_setup(char *str)
 {
-	char *error;
-	int ret;
-
-	ret = line_setup(vts, ARRAY_SIZE(vts), str, &error);
-	if(ret < 0)
-		printk(KERN_ERR "Failed to set up console with "
-		       "configuration string \"%s\" : %s\n", str, error);
-
+	line_setup(vt_conf, MAX_TTYS, &def_conf, str, "console");
 	return 1;
 }
 __setup("con", console_chan_setup);
diff --git a/arch/um/drivers/ubd_user.h b/arch/um/drivers/ubd.h
similarity index 100%
rename from arch/um/drivers/ubd_user.h
rename to arch/um/drivers/ubd.h
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 944453a..20505ca 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -19,40 +19,26 @@
 
 #define UBD_SHIFT 4
 
-#include "linux/kernel.h"
-#include "linux/module.h"
-#include "linux/blkdev.h"
-#include "linux/ata.h"
-#include "linux/hdreg.h"
-#include "linux/init.h"
-#include "linux/cdrom.h"
-#include "linux/proc_fs.h"
-#include "linux/seq_file.h"
-#include "linux/ctype.h"
-#include "linux/capability.h"
-#include "linux/mm.h"
-#include "linux/slab.h"
-#include "linux/vmalloc.h"
-#include "linux/mutex.h"
-#include "linux/blkpg.h"
-#include "linux/genhd.h"
-#include "linux/spinlock.h"
-#include "linux/platform_device.h"
-#include "linux/scatterlist.h"
-#include "asm/segment.h"
-#include "asm/uaccess.h"
-#include "asm/irq.h"
-#include "asm/types.h"
-#include "asm/tlbflush.h"
-#include "mem_user.h"
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/ata.h>
+#include <linux/hdreg.h>
+#include <linux/cdrom.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <asm/tlbflush.h>
 #include "kern_util.h"
 #include "mconsole_kern.h"
 #include "init.h"
-#include "irq_user.h"
 #include "irq_kern.h"
-#include "ubd_user.h"
+#include "ubd.h"
 #include "os.h"
-#include "mem.h"
 #include "cow.h"
 
 enum ubd_req { UBD_READ, UBD_WRITE };
@@ -1115,7 +1101,7 @@
 		return 0;
 	}
 	err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
-			     IRQF_DISABLED, "ubd", ubd_devs);
+			     0, "ubd", ubd_devs);
 	if(err != 0)
 		printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
 	return 0;
diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
index 007b94d..ffe02c4 100644
--- a/arch/um/drivers/ubd_user.c
+++ b/arch/um/drivers/ubd_user.c
@@ -15,14 +15,12 @@
 #include <sys/socket.h>
 #include <sys/mman.h>
 #include <sys/param.h>
-#include "asm/types.h"
-#include "ubd_user.h"
-#include "os.h"
-#include "cow.h"
-
 #include <endian.h>
 #include <byteswap.h>
 
+#include "ubd.h"
+#include "os.h"
+
 void ignore_sigwinch_sig(void)
 {
 	signal(SIGWINCH, SIG_IGN);
diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c
index b646bcc..8bd130f 100644
--- a/arch/um/drivers/xterm_kern.c
+++ b/arch/um/drivers/xterm_kern.c
@@ -50,7 +50,7 @@
 	init_completion(&data->ready);
 
 	err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt,
-			     IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+			     IRQF_SHARED | IRQF_SAMPLE_RANDOM,
 			     "xterm", data);
 	if (err) {
 		printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, "
diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild
index 451f451..8419f5c 100644
--- a/arch/um/include/asm/Kbuild
+++ b/arch/um/include/asm/Kbuild
@@ -1,3 +1,3 @@
 generic-y += bug.h cputime.h device.h emergency-restart.h futex.h hardirq.h
 generic-y += hw_irq.h irq_regs.h kdebug.h percpu.h sections.h topology.h xor.h
-generic-y += ftrace.h
+generic-y += ftrace.h pci.h io.h param.h delay.h mutex.h current.h
diff --git a/arch/um/include/asm/asm-offsets.h b/arch/um/include/asm/asm-offsets.h
deleted file mode 100644
index d370ee3..0000000
--- a/arch/um/include/asm/asm-offsets.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <generated/asm-offsets.h>
diff --git a/arch/um/include/asm/auxvec.h b/arch/um/include/asm/auxvec.h
deleted file mode 100644
index 1e5e1c2..0000000
--- a/arch/um/include/asm/auxvec.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef __UM_AUXVEC_H
-#define __UM_AUXVEC_H
-
-#endif
diff --git a/arch/um/include/asm/current.h b/arch/um/include/asm/current.h
deleted file mode 100644
index c2191d9..0000000
--- a/arch/um/include/asm/current.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- * Licensed under the GPL
- */
-
-#ifndef __UM_CURRENT_H
-#define __UM_CURRENT_H
-
-#include "linux/thread_info.h"
-
-#define current (current_thread_info()->task)
-
-#endif
diff --git a/arch/um/include/asm/delay.h b/arch/um/include/asm/delay.h
deleted file mode 100644
index 8a5576d..0000000
--- a/arch/um/include/asm/delay.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef __UM_DELAY_H
-#define __UM_DELAY_H
-
-/* Undefined on purpose */
-extern void __bad_udelay(void);
-extern void __bad_ndelay(void);
-
-extern void __udelay(unsigned long usecs);
-extern void __ndelay(unsigned long usecs);
-extern void __delay(unsigned long loops);
-
-#define udelay(n) ((__builtin_constant_p(n) && (n) > 20000) ? \
-	__bad_udelay() : __udelay(n))
-
-#define ndelay(n) ((__builtin_constant_p(n) && (n) > 20000) ? \
-	__bad_ndelay() : __ndelay(n))
-
-#endif
diff --git a/arch/um/include/asm/fixmap.h b/arch/um/include/asm/fixmap.h
index 69c0252..21a423b 100644
--- a/arch/um/include/asm/fixmap.h
+++ b/arch/um/include/asm/fixmap.h
@@ -2,7 +2,6 @@
 #define __UM_FIXMAP_H
 
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/kmap_types.h>
 #include <asm/archparam.h>
 #include <asm/page.h>
diff --git a/arch/um/include/asm/io.h b/arch/um/include/asm/io.h
deleted file mode 100644
index 44e8b8c..0000000
--- a/arch/um/include/asm/io.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef __UM_IO_H
-#define __UM_IO_H
-
-#include "asm/page.h"
-
-#define IO_SPACE_LIMIT 0xdeadbeef /* Sure hope nothing uses this */
-
-static inline int inb(unsigned long i) { return(0); }
-static inline void outb(char c, unsigned long i) { }
-
-/*
- * Change virtual addresses to physical addresses and vv.
- * These are pretty trivial
- */
-static inline unsigned long virt_to_phys(volatile void * address)
-{
-	return __pa((void *) address);
-}
-
-static inline void * phys_to_virt(unsigned long address)
-{
-	return __va(address);
-}
-
-/*
- * Convert a physical pointer to a virtual kernel pointer for /dev/mem
- * access
- */
-#define xlate_dev_mem_ptr(p)	__va(p)
-
-/*
- * Convert a virtual cached pointer to an uncached pointer
- */
-#define xlate_dev_kmem_ptr(p)	p
-
-static inline void writeb(unsigned char b, volatile void __iomem *addr)
-{
-	*(volatile unsigned char __force *) addr = b;
-}
-static inline void writew(unsigned short b, volatile void __iomem *addr)
-{
-	*(volatile unsigned short __force *) addr = b;
-}
-static inline void writel(unsigned int b, volatile void __iomem *addr)
-{
-	*(volatile unsigned int __force *) addr = b;
-}
-static inline void writeq(unsigned int b, volatile void __iomem *addr)
-{
-	*(volatile unsigned long long __force *) addr = b;
-}
-#define __raw_writeb writeb
-#define __raw_writew writew
-#define __raw_writel writel
-#define __raw_writeq writeq
-
-#endif
diff --git a/arch/um/include/asm/mmu.h b/arch/um/include/asm/mmu.h
index 30509b9..53e8b49 100644
--- a/arch/um/include/asm/mmu.h
+++ b/arch/um/include/asm/mmu.h
@@ -12,7 +12,7 @@
 typedef struct mm_context {
 	struct mm_id id;
 	struct uml_arch_mm_context arch;
-	struct page **stub_pages;
+	struct page *stub_pages[2];
 } mm_context_t;
 
 extern void __switch_mm(struct mm_id * mm_idp);
diff --git a/arch/um/include/asm/mmu_context.h b/arch/um/include/asm/mmu_context.h
index 591b3d8..aa4a743 100644
--- a/arch/um/include/asm/mmu_context.h
+++ b/arch/um/include/asm/mmu_context.h
@@ -9,7 +9,7 @@
 #include <linux/sched.h>
 #include <asm/mmu.h>
 
-extern void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
+extern void uml_setup_stubs(struct mm_struct *mm);
 extern void arch_exit_mmap(struct mm_struct *mm);
 
 #define deactivate_mm(tsk,mm)	do { } while (0)
@@ -23,7 +23,9 @@
 	 * when the new ->mm is used for the first time.
 	 */
 	__switch_mm(&new->context.id);
-	arch_dup_mmap(old, new);
+	down_write(&new->mmap_sem);
+	uml_setup_stubs(new);
+	up_write(&new->mmap_sem);
 }
 
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
@@ -39,6 +41,11 @@
 	}
 }
 
+static inline void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
+{
+	uml_setup_stubs(mm);
+}
+
 static inline void enter_lazy_tlb(struct mm_struct *mm, 
 				  struct task_struct *tsk)
 {
diff --git a/arch/um/include/asm/mutex.h b/arch/um/include/asm/mutex.h
deleted file mode 100644
index 458c1f7..0000000
--- a/arch/um/include/asm/mutex.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Pull in the generic implementation for the mutex fastpath.
- *
- * TODO: implement optimized primitives instead, or leave the generic
- * implementation in place, or pick the atomic_xchg() based generic
- * implementation. (see asm-generic/mutex-xchg.h for details)
- */
-
-#include <asm-generic/mutex-dec.h>
diff --git a/arch/um/include/asm/param.h b/arch/um/include/asm/param.h
deleted file mode 100644
index e44f4e6..0000000
--- a/arch/um/include/asm/param.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _UM_PARAM_H
-#define _UM_PARAM_H
-
-#define EXEC_PAGESIZE   4096
-
-#ifndef NOGROUP
-#define NOGROUP         (-1)
-#endif
-
-#define MAXHOSTNAMELEN  64      /* max length of hostname */
-
-#ifdef __KERNEL__
-#define HZ CONFIG_HZ
-#define USER_HZ	100	   /* .. some user interfaces are in "ticks" */
-#define CLOCKS_PER_SEC (USER_HZ)  /* frequency at which times() counts */
-#else
-#define HZ 100
-#endif
-
-#endif
diff --git a/arch/um/include/asm/pci.h b/arch/um/include/asm/pci.h
deleted file mode 100644
index b44cf59..0000000
--- a/arch/um/include/asm/pci.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __UM_PCI_H
-#define __UM_PCI_H
-
-#define PCI_DMA_BUS_IS_PHYS     (1)
-
-#endif
diff --git a/arch/um/include/asm/pgalloc.h b/arch/um/include/asm/pgalloc.h
index 32c8ce4..bf90b2a 100644
--- a/arch/um/include/asm/pgalloc.h
+++ b/arch/um/include/asm/pgalloc.h
@@ -8,8 +8,7 @@
 #ifndef __UM_PGALLOC_H
 #define __UM_PGALLOC_H
 
-#include "linux/mm.h"
-#include "asm/fixmap.h"
+#include <linux/mm.h>
 
 #define pmd_populate_kernel(mm, pmd, pte) \
 	set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) __pa(pte)))
diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h
index 41474fb..6a3f984 100644
--- a/arch/um/include/asm/pgtable.h
+++ b/arch/um/include/asm/pgtable.h
@@ -69,6 +69,8 @@
 #define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
 #define PAGE_KERNEL_EXEC	__pgprot(__PAGE_KERNEL_EXEC)
 
+#define io_remap_pfn_range	remap_pfn_range
+
 /*
  * The i386 can't do page protection for execute, and considers that the same
  * are read.
diff --git a/arch/um/include/asm/ptrace-generic.h b/arch/um/include/asm/ptrace-generic.h
index f605d3c..e786a6a 100644
--- a/arch/um/include/asm/ptrace-generic.h
+++ b/arch/um/include/asm/ptrace-generic.h
@@ -9,7 +9,6 @@
 #ifndef __ASSEMBLY__
 
 #include <asm/ptrace-abi.h>
-#include <asm/user.h>
 #include "sysdep/ptrace.h"
 
 struct pt_regs {
diff --git a/arch/um/include/shared/common-offsets.h b/arch/um/include/shared/common-offsets.h
index d7fe563..40db8f7 100644
--- a/arch/um/include/shared/common-offsets.h
+++ b/arch/um/include/shared/common-offsets.h
@@ -2,8 +2,6 @@
 
 DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE);
 
-OFFSET(HOST_TASK_PID, task_struct, pid);
-
 DEFINE(UM_KERN_PAGE_SIZE, PAGE_SIZE);
 DEFINE(UM_KERN_PAGE_MASK, PAGE_MASK);
 DEFINE(UM_KERN_PAGE_SHIFT, PAGE_SHIFT);
diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h
index 0f14838..00965d0 100644
--- a/arch/um/include/shared/kern_util.h
+++ b/arch/um/include/shared/kern_util.h
@@ -48,7 +48,7 @@
  * GFP_ATOMIC.
  */
 extern int __cant_sleep(void);
-extern void *get_current(void);
+extern int get_current_pid(void);
 extern int copy_from_user_proc(void *to, void *from, int size);
 extern int cpu(void);
 extern char *uml_strdup(const char *string);
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index bc49474..492bc4c 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -3,7 +3,7 @@
 # Licensed under the GPL
 #
 
-CPPFLAGS_vmlinux.lds := -U$(SUBARCH) -DSTART=$(LDS_START) \
+CPPFLAGS_vmlinux.lds := -DSTART=$(LDS_START) \
                         -DELF_ARCH=$(LDS_ELF_ARCH)        \
                         -DELF_FORMAT=$(LDS_ELF_FORMAT)
 extra-y := vmlinux.lds
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 69f2490..f386d04 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -126,9 +126,9 @@
 {
 }
 
-void *get_current(void)
+int get_current_pid(void)
 {
-	return current;
+	return task_pid_nr(current);
 }
 
 /*
diff --git a/arch/um/kernel/sigio.c b/arch/um/kernel/sigio.c
index 2b272b6..2a16392 100644
--- a/arch/um/kernel/sigio.c
+++ b/arch/um/kernel/sigio.c
@@ -25,7 +25,7 @@
 	int err;
 
 	err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt,
-			     IRQF_DISABLED|IRQF_SAMPLE_RANDOM, "write sigio",
+			     IRQF_SAMPLE_RANDOM, "write sigio",
 			     NULL);
 	if (err) {
 		printk(KERN_ERR "write_sigio_irq : um_request_irq failed, "
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
index e8b889d..fb12f4c 100644
--- a/arch/um/kernel/signal.c
+++ b/arch/um/kernel/signal.c
@@ -65,21 +65,10 @@
 #endif
 		err = setup_signal_stack_si(sp, signr, ka, regs, info, oldset);
 
-	if (err) {
-		spin_lock_irq(&current->sighand->siglock);
-		current->blocked = *oldset;
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
+	if (err)
 		force_sigsegv(signr, current);
-	} else {
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked, &current->blocked,
-			  &ka->sa.sa_mask);
-		if (!(ka->sa.sa_flags & SA_NODEFER))
-			sigaddset(&current->blocked, signr);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
-	}
+	else
+		block_sigmask(ka, signr);
 
 	return err;
 }
@@ -162,12 +151,11 @@
  */
 long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
 {
+	sigset_t blocked;
+
 	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sighand->siglock);
-	current->saved_sigmask = current->blocked;
-	siginitset(&current->blocked, mask);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	siginitset(&blocked, mask);
+	set_current_blocked(&blocked);
 
 	current->state = TASK_INTERRUPTIBLE;
 	schedule();
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 1aee587..4947b31 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -92,8 +92,6 @@
 		goto out_free;
 	}
 
-	to_mm->stub_pages = NULL;
-
 	return 0;
 
  out_free:
@@ -103,7 +101,7 @@
 	return ret;
 }
 
-void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
+void uml_setup_stubs(struct mm_struct *mm)
 {
 	struct page **pages;
 	int err, ret;
@@ -120,29 +118,20 @@
 	if (ret)
 		goto out;
 
-	pages = kmalloc(2 * sizeof(struct page *), GFP_KERNEL);
-	if (pages == NULL) {
-		printk(KERN_ERR "arch_dup_mmap failed to allocate 2 page "
-		       "pointers\n");
-		goto out;
-	}
-
-	pages[0] = virt_to_page(&__syscall_stub_start);
-	pages[1] = virt_to_page(mm->context.id.stack);
-	mm->context.stub_pages = pages;
+	mm->context.stub_pages[0] = virt_to_page(&__syscall_stub_start);
+	mm->context.stub_pages[1] = virt_to_page(mm->context.id.stack);
 
 	/* dup_mmap already holds mmap_sem */
 	err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START,
 				      VM_READ | VM_MAYREAD | VM_EXEC |
-				      VM_MAYEXEC | VM_DONTCOPY, pages);
+				      VM_MAYEXEC | VM_DONTCOPY,
+				      mm->context.stub_pages);
 	if (err) {
 		printk(KERN_ERR "install_special_mapping returned %d\n", err);
-		goto out_free;
+		goto out;
 	}
 	return;
 
-out_free:
-	kfree(pages);
 out:
 	force_sigsegv(SIGSEGV, current);
 }
@@ -151,8 +140,6 @@
 {
 	pte_t *pte;
 
-	if (mm->context.stub_pages != NULL)
-		kfree(mm->context.stub_pages);
 	pte = virt_to_pte(mm, STUB_CODE);
 	if (pte != NULL)
 		pte_clear(mm, STUB_CODE, pte);
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index 2e9852c..0a9e57e 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -41,7 +41,7 @@
 	cpu_tasks[0].pid = pid;
 	cpu_tasks[0].task = current;
 #ifdef CONFIG_SMP
-	cpu_online_map = cpumask_of_cpu(0);
+	init_cpu_online(get_cpu_mask(0));
 #endif
 	start_kernel();
 	return 0;
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
index 155206a..6f588e1 100644
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -76,7 +76,7 @@
 		cpu_relax();
 
 	notify_cpu_starting(cpu);
-	cpu_set(cpu, cpu_online_map);
+	set_cpu_online(cpu, true);
 	default_idle();
 	return 0;
 }
@@ -110,8 +110,7 @@
 	for (i = 0; i < ncpus; ++i)
 		set_cpu_possible(i, true);
 
-	cpu_clear(me, cpu_online_map);
-	cpu_set(me, cpu_online_map);
+	set_cpu_online(me, true);
 	cpu_set(me, cpu_callin_map);
 
 	err = os_pipe(cpu_data[me].ipi_pipe, 1, 1);
@@ -138,13 +137,13 @@
 
 void smp_prepare_boot_cpu(void)
 {
-	cpu_set(smp_processor_id(), cpu_online_map);
+	set_cpu_online(smp_processor_id(), true);
 }
 
 int __cpu_up(unsigned int cpu)
 {
 	cpu_set(cpu, smp_commenced_mask);
-	while (!cpu_isset(cpu, cpu_online_map))
+	while (!cpu_online(cpu))
 		mb();
 	return 0;
 }
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 82a6e22..d1a23fb 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -82,7 +82,7 @@
 {
 	int err;
 
-	err = request_irq(TIMER_IRQ, um_timer, IRQF_DISABLED, "timer", NULL);
+	err = request_irq(TIMER_IRQ, um_timer, 0, "timer", NULL);
 	if (err != 0)
 		printk(KERN_ERR "register_timer : request_irq failed - "
 		       "errno = %d\n", -err);
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
index dd76410..08ff509 100644
--- a/arch/um/os-Linux/Makefile
+++ b/arch/um/os-Linux/Makefile
@@ -13,8 +13,6 @@
 	main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \
 	tty.o umid.o util.o
 
-CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
-
 HAVE_AIO_ABI := $(shell [ -r /usr/include/linux/aio_abi.h ] && \
 	echo -DHAVE_AIO_ABI )
 CFLAGS_aio.o += $(HAVE_AIO_ABI)
diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c
index 45ffe46..73926fa 100644
--- a/arch/um/os-Linux/user_syms.c
+++ b/arch/um/os-Linux/user_syms.c
@@ -45,7 +45,7 @@
 extern void truncate64(void) __attribute__((weak));
 EXPORT_SYMBOL(truncate64);
 
-#ifdef SUBARCH_i386
+#ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
 EXPORT_SYMBOL(vsyscall_ehdr);
 EXPORT_SYMBOL(vsyscall_end);
 #endif
diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules
index 2eb2843..d50270d 100644
--- a/arch/um/scripts/Makefile.rules
+++ b/arch/um/scripts/Makefile.rules
@@ -9,8 +9,6 @@
 
 $(USER_OBJS:.o=.%): \
 	c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) -include user.h $(CFLAGS_$(basetarget).o)
-$(USER_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \
-	-Dunix -D__unix__ -D__$(SUBARCH)__ $(CF)
 
 # These are like USER_OBJS but filter USER_CFLAGS through unprofile instead of
 # using it directly.
@@ -18,8 +16,9 @@
 
 $(UNPROFILE_OBJS:.o=.%): \
 	c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) $(CFLAGS_$(basetarget).o)
-$(UNPROFILE_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \
-	-Dunix -D__unix__ -D__$(SUBARCH)__ $(CF)
+
+$(USER_OBJS) $(UNPROFILE_OBJS): \
+	CHECKFLAGS := $(patsubst $(NOSTDINC_FLAGS),,$(CHECKFLAGS))
 
 # The stubs can't try to call mcount or update basic block data
 define unprofile
diff --git a/arch/unicore32/boot/Makefile b/arch/unicore32/boot/Makefile
index 79e5f88..ec7fb70 100644
--- a/arch/unicore32/boot/Makefile
+++ b/arch/unicore32/boot/Makefile
@@ -11,8 +11,6 @@
 # Copyright (C) 2001~2010 GUAN Xue-tao
 #
 
-MKIMAGE := $(srctree)/scripts/mkuboot.sh
-
 targets := Image zImage uImage
 
 $(obj)/Image: vmlinux FORCE
@@ -26,14 +24,8 @@
 	$(call if_changed,objcopy)
 	@echo '  Kernel: $@ is ready'
 
-quiet_cmd_uimage = UIMAGE  $@
-      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A unicore -O linux -T kernel \
-		   -C none -a $(LOADADDR) -e $(STARTADDR) \
-		   -n 'Linux-$(KERNELRELEASE)' -d $< $@
-
-$(obj)/uImage: LOADADDR=0x0
-
-$(obj)/uImage: STARTADDR=$(LOADADDR)
+UIMAGE_ARCH = unicore
+UIMAGE_LOADADDR = 0x0
 
 $(obj)/uImage: $(obj)/zImage FORCE
 	$(call if_changed,uimage)
diff --git a/arch/unicore32/include/asm/Kbuild b/arch/unicore32/include/asm/Kbuild
index ca113d6..34b789b 100644
--- a/arch/unicore32/include/asm/Kbuild
+++ b/arch/unicore32/include/asm/Kbuild
@@ -3,7 +3,6 @@
 generic-y += atomic.h
 generic-y += auxvec.h
 generic-y += bitsperlong.h
-generic-y += bug.h
 generic-y += bugs.h
 generic-y += cputime.h
 generic-y += current.h
diff --git a/arch/unicore32/include/asm/barrier.h b/arch/unicore32/include/asm/barrier.h
new file mode 100644
index 0000000..a6620e5
--- /dev/null
+++ b/arch/unicore32/include/asm/barrier.h
@@ -0,0 +1,28 @@
+/*
+ * Memory barrier implementations for PKUnity SoC and UniCore ISA
+ *
+ * Copyright (C) 2001-2012 GUAN Xue-tao
+ *
+ * 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 __UNICORE_BARRIER_H__
+#define __UNICORE_BARRIER_H__
+
+#define isb() __asm__ __volatile__ ("" : : : "memory")
+#define dsb() __asm__ __volatile__ ("" : : : "memory")
+#define dmb() __asm__ __volatile__ ("" : : : "memory")
+
+#define mb()				barrier()
+#define rmb()				barrier()
+#define wmb()				barrier()
+#define smp_mb()			barrier()
+#define smp_rmb()			barrier()
+#define smp_wmb()			barrier()
+#define read_barrier_depends()		do { } while (0)
+#define smp_read_barrier_depends()	do { } while (0)
+
+#define set_mb(var, value)		do { var = value; smp_mb(); } while (0)
+
+#endif /* __UNICORE_BARRIER_H__ */
diff --git a/arch/unicore32/include/asm/bug.h b/arch/unicore32/include/asm/bug.h
new file mode 100644
index 0000000..b1ff8ca
--- /dev/null
+++ b/arch/unicore32/include/asm/bug.h
@@ -0,0 +1,27 @@
+/*
+ * Bug handling for PKUnity SoC and UniCore ISA
+ *
+ * Copyright (C) 2001-2012 GUAN Xue-tao
+ *
+ * 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 __UNICORE_BUG_H__
+#define __UNICORE_BUG_H__
+
+#include <asm-generic/bug.h>
+
+struct pt_regs;
+struct siginfo;
+
+extern void die(const char *msg, struct pt_regs *regs, int err);
+extern void uc32_notify_die(const char *str, struct pt_regs *regs,
+		struct siginfo *info, unsigned long err, unsigned long trap);
+
+extern asmlinkage void __backtrace(void);
+extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
+
+extern void __show_regs(struct pt_regs *);
+
+#endif /* __UNICORE_BUG_H__ */
diff --git a/arch/unicore32/include/asm/cmpxchg.h b/arch/unicore32/include/asm/cmpxchg.h
new file mode 100644
index 0000000..df4d5ac
--- /dev/null
+++ b/arch/unicore32/include/asm/cmpxchg.h
@@ -0,0 +1,61 @@
+/*
+ * Atomics xchg/cmpxchg for PKUnity SoC and UniCore ISA
+ *
+ * Copyright (C) 2001-2012 GUAN Xue-tao
+ *
+ * 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 __UNICORE_CMPXCHG_H__
+#define __UNICORE_CMPXCHG_H__
+
+/*
+ * Generate a link failure on undefined symbol if the pointer points to a value
+ * of unsupported size.
+ */
+extern void __xchg_bad_pointer(void);
+
+static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
+		int size)
+{
+	unsigned long ret;
+
+	switch (size) {
+	case 1:
+		asm volatile("swapb	%0, %1, [%2]"
+			: "=&r" (ret)
+			: "r" (x), "r" (ptr)
+			: "memory", "cc");
+		break;
+	case 4:
+		asm volatile("swapw	%0, %1, [%2]"
+			: "=&r" (ret)
+			: "r" (x), "r" (ptr)
+			: "memory", "cc");
+		break;
+	default:
+		ret = __xchg_bad_pointer();
+	}
+
+	return ret;
+}
+
+#define xchg(ptr, x) \
+	((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
+
+#include <asm-generic/cmpxchg-local.h>
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)					\
+		((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr),	\
+		(unsigned long)(o), (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n)					\
+		__cmpxchg64_local_generic((ptr), (o), (n))
+
+#include <asm-generic/cmpxchg.h>
+
+#endif /* __UNICORE_CMPXCHG_H__ */
diff --git a/arch/unicore32/include/asm/dma-mapping.h b/arch/unicore32/include/asm/dma-mapping.h
index 9258e59..366460a 100644
--- a/arch/unicore32/include/asm/dma-mapping.h
+++ b/arch/unicore32/include/asm/dma-mapping.h
@@ -82,20 +82,26 @@
 	return 0;
 }
 
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-				       dma_addr_t *dma_handle, gfp_t flag)
+#define dma_alloc_coherent(d,s,h,f)	dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+				    dma_addr_t *dma_handle, gfp_t flag,
+				    struct dma_attrs *attrs)
 {
 	struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
-	return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
+	return dma_ops->alloc(dev, size, dma_handle, flag, attrs);
 }
 
-static inline void dma_free_coherent(struct device *dev, size_t size,
-				     void *cpu_addr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+				  void *cpu_addr, dma_addr_t dma_handle,
+				  struct dma_attrs *attrs)
 {
 	struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
-	dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
+	dma_ops->free(dev, size, cpu_addr, dma_handle, attrs);
 }
 
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
diff --git a/arch/unicore32/include/asm/exec.h b/arch/unicore32/include/asm/exec.h
new file mode 100644
index 0000000..06d1f0f
--- /dev/null
+++ b/arch/unicore32/include/asm/exec.h
@@ -0,0 +1,15 @@
+/*
+ * Process execution bits for PKUnity SoC and UniCore ISA
+ *
+ * Copyright (C) 2001-2012 GUAN Xue-tao
+ *
+ * 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 __UNICORE_EXEC_H__
+#define __UNICORE_EXEC_H__
+
+#define arch_align_stack(x)		(x)
+
+#endif /* __UNICORE_EXEC_H__ */
diff --git a/arch/unicore32/include/asm/hwdef-copro.h b/arch/unicore32/include/asm/hwdef-copro.h
new file mode 100644
index 0000000..a3292f0
--- /dev/null
+++ b/arch/unicore32/include/asm/hwdef-copro.h
@@ -0,0 +1,48 @@
+/*
+ * Co-processor register definitions for PKUnity SoC and UniCore ISA
+ *
+ * Copyright (C) 2001-2012 GUAN Xue-tao
+ *
+ * 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 __UNICORE_HWDEF_COPRO_H__
+#define __UNICORE_HWDEF_COPRO_H__
+
+/*
+ * Control Register bits (CP#0 CR1)
+ */
+#define CR_M	(1 << 0)	/* MMU enable				*/
+#define CR_A	(1 << 1)	/* Alignment abort enable		*/
+#define CR_D	(1 << 2)	/* Dcache enable			*/
+#define CR_I	(1 << 3)	/* Icache enable			*/
+#define CR_B	(1 << 4)	/* Dcache write mechanism: write back	*/
+#define CR_T	(1 << 5)	/* Burst enable				*/
+#define CR_V	(1 << 13)	/* Vectors relocated to 0xffff0000	*/
+
+#ifndef __ASSEMBLY__
+
+#define vectors_high()		(cr_alignment & CR_V)
+
+extern unsigned long cr_no_alignment;	/* defined in entry.S */
+extern unsigned long cr_alignment;	/* defined in entry.S */
+
+static inline unsigned int get_cr(void)
+{
+	unsigned int val;
+	asm("movc %0, p0.c1, #0" : "=r" (val) : : "cc");
+	return val;
+}
+
+static inline void set_cr(unsigned int val)
+{
+	asm volatile("movc p0.c1, %0, #0" : : "r" (val) : "cc");
+	isb();
+}
+
+extern void adjust_cr(unsigned long mask, unsigned long set);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __UNICORE_HWDEF_COPRO_H__ */
diff --git a/arch/unicore32/include/asm/io.h b/arch/unicore32/include/asm/io.h
index adddf6d..39decb6 100644
--- a/arch/unicore32/include/asm/io.h
+++ b/arch/unicore32/include/asm/io.h
@@ -16,7 +16,6 @@
 
 #include <asm/byteorder.h>
 #include <asm/memory.h>
-#include <asm/system.h>
 
 #define PCI_IOBASE	PKUNITY_PCILIO_BASE
 #include <asm-generic/io.h>
diff --git a/arch/unicore32/include/asm/pci.h b/arch/unicore32/include/asm/pci.h
index dd38677..f5e108f 100644
--- a/arch/unicore32/include/asm/pci.h
+++ b/arch/unicore32/include/asm/pci.h
@@ -14,6 +14,7 @@
 
 #ifdef __KERNEL__
 #include <asm-generic/pci-dma-compat.h>
+#include <asm-generic/pci-bridge.h>
 #include <asm-generic/pci.h>
 #include <mach/hardware.h> /* for PCIBIOS_MIN_* */
 
diff --git a/arch/unicore32/include/asm/switch_to.h b/arch/unicore32/include/asm/switch_to.h
new file mode 100644
index 0000000..39572d2
--- /dev/null
+++ b/arch/unicore32/include/asm/switch_to.h
@@ -0,0 +1,30 @@
+/*
+ * Task switching for PKUnity SoC and UniCore ISA
+ *
+ * Copyright (C) 2001-2012 GUAN Xue-tao
+ *
+ * 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 __UNICORE_SWITCH_TO_H__
+#define __UNICORE_SWITCH_TO_H__
+
+struct task_struct;
+struct thread_info;
+
+/*
+ * switch_to(prev, next) should switch from task `prev' to `next'
+ * `prev' will never be the same as `next'.  schedule() itself
+ * contains the memory barrier to tell GCC not to cache `current'.
+ */
+extern struct task_struct *__switch_to(struct task_struct *,
+		struct thread_info *, struct thread_info *);
+
+#define switch_to(prev, next, last)					\
+	do {								\
+		last = __switch_to(prev, task_thread_info(prev),	\
+					task_thread_info(next));	\
+	} while (0)
+
+#endif /* __UNICORE_SWITCH_TO_H__ */
diff --git a/arch/unicore32/include/asm/system.h b/arch/unicore32/include/asm/system.h
deleted file mode 100644
index 246b71c..0000000
--- a/arch/unicore32/include/asm/system.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * linux/arch/unicore32/include/asm/system.h
- *
- * Code specific to PKUnity SoC and UniCore ISA
- *
- * Copyright (C) 2001-2010 GUAN Xue-tao
- *
- * 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 __UNICORE_SYSTEM_H__
-#define __UNICORE_SYSTEM_H__
-
-#ifdef __KERNEL__
-
-/*
- * CR1 bits (CP#0 CR1)
- */
-#define CR_M	(1 << 0)	/* MMU enable				*/
-#define CR_A	(1 << 1)	/* Alignment abort enable		*/
-#define CR_D	(1 << 2)	/* Dcache enable			*/
-#define CR_I	(1 << 3)	/* Icache enable			*/
-#define CR_B	(1 << 4)	/* Dcache write mechanism: write back	*/
-#define CR_T	(1 << 5)	/* Burst enable				*/
-#define CR_V	(1 << 13)	/* Vectors relocated to 0xffff0000	*/
-
-#ifndef __ASSEMBLY__
-
-#include <linux/linkage.h>
-#include <linux/irqflags.h>
-
-struct thread_info;
-struct task_struct;
-
-struct pt_regs;
-
-void die(const char *msg, struct pt_regs *regs, int err);
-
-struct siginfo;
-void uc32_notify_die(const char *str, struct pt_regs *regs,
-		struct siginfo *info, unsigned long err, unsigned long trap);
-
-void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
-				       struct pt_regs *),
-		     int sig, int code, const char *name);
-
-#define xchg(ptr, x) \
-	((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
-
-extern asmlinkage void __backtrace(void);
-extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
-
-struct mm_struct;
-extern void show_pte(struct mm_struct *mm, unsigned long addr);
-extern void __show_regs(struct pt_regs *);
-
-extern int cpu_architecture(void);
-extern void cpu_init(void);
-
-#define vectors_high()	(cr_alignment & CR_V)
-
-#define isb() __asm__ __volatile__ ("" : : : "memory")
-#define dsb() __asm__ __volatile__ ("" : : : "memory")
-#define dmb() __asm__ __volatile__ ("" : : : "memory")
-
-#define mb()		barrier()
-#define rmb()		barrier()
-#define wmb()		barrier()
-#define smp_mb()	barrier()
-#define smp_rmb()	barrier()
-#define smp_wmb()	barrier()
-#define read_barrier_depends()		do { } while (0)
-#define smp_read_barrier_depends()	do { } while (0)
-
-#define set_mb(var, value)	do { var = value; smp_mb(); } while (0)
-#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
-
-extern unsigned long cr_no_alignment;	/* defined in entry-unicore.S */
-extern unsigned long cr_alignment;	/* defined in entry-unicore.S */
-
-static inline unsigned int get_cr(void)
-{
-	unsigned int val;
-	asm("movc %0, p0.c1, #0" : "=r" (val) : : "cc");
-	return val;
-}
-
-static inline void set_cr(unsigned int val)
-{
-	asm volatile("movc p0.c1, %0, #0	@set CR"
-	  : : "r" (val) : "cc");
-	isb();
-}
-
-extern void adjust_cr(unsigned long mask, unsigned long set);
-
-/*
- * switch_to(prev, next) should switch from task `prev' to `next'
- * `prev' will never be the same as `next'.  schedule() itself
- * contains the memory barrier to tell GCC not to cache `current'.
- */
-extern struct task_struct *__switch_to(struct task_struct *,
-		struct thread_info *, struct thread_info *);
-extern void panic(const char *fmt, ...);
-
-#define switch_to(prev, next, last)					\
-do {									\
-	last = __switch_to(prev,					\
-		task_thread_info(prev), task_thread_info(next));	\
-} while (0)
-
-static inline unsigned long
-__xchg(unsigned long x, volatile void *ptr, int size)
-{
-	unsigned long ret;
-
-	switch (size) {
-	case 1:
-		asm volatile("@	__xchg1\n"
-		"	swapb	%0, %1, [%2]"
-			: "=&r" (ret)
-			: "r" (x), "r" (ptr)
-			: "memory", "cc");
-		break;
-	case 4:
-		asm volatile("@	__xchg4\n"
-		"	swapw	%0, %1, [%2]"
-			: "=&r" (ret)
-			: "r" (x), "r" (ptr)
-			: "memory", "cc");
-		break;
-	default:
-		panic("xchg: bad data size: ptr 0x%p, size %d\n",
-			ptr, size);
-	}
-
-	return ret;
-}
-
-#include <asm-generic/cmpxchg-local.h>
-
-/*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
- */
-#define cmpxchg_local(ptr, o, n)					\
-		((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr),	\
-		(unsigned long)(o), (unsigned long)(n), sizeof(*(ptr))))
-#define cmpxchg64_local(ptr, o, n)					\
-		__cmpxchg64_local_generic((ptr), (o), (n))
-
-#include <asm-generic/cmpxchg.h>
-
-#endif /* __ASSEMBLY__ */
-
-#define arch_align_stack(x) (x)
-
-#endif /* __KERNEL__ */
-
-#endif
diff --git a/arch/unicore32/include/asm/uaccess.h b/arch/unicore32/include/asm/uaccess.h
index 2acda50..897e11ad 100644
--- a/arch/unicore32/include/asm/uaccess.h
+++ b/arch/unicore32/include/asm/uaccess.h
@@ -16,7 +16,6 @@
 #include <linux/errno.h>
 
 #include <asm/memory.h>
-#include <asm/system.h>
 
 #define __copy_from_user	__copy_from_user
 #define __copy_to_user		__copy_to_user
diff --git a/arch/unicore32/kernel/dma.c b/arch/unicore32/kernel/dma.c
index ae441bc..ed2d4d78 100644
--- a/arch/unicore32/kernel/dma.c
+++ b/arch/unicore32/kernel/dma.c
@@ -18,7 +18,6 @@
 #include <linux/errno.h>
 #include <linux/io.h>
 
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
 #include <mach/dma.h>
diff --git a/arch/unicore32/kernel/head.S b/arch/unicore32/kernel/head.S
index 8caf322..e8f0b98 100644
--- a/arch/unicore32/kernel/head.S
+++ b/arch/unicore32/kernel/head.S
@@ -17,7 +17,7 @@
 #include <generated/asm-offsets.h>
 #include <asm/memory.h>
 #include <asm/thread_info.h>
-#include <asm/system.h>
+#include <asm/hwdef-copro.h>
 #include <asm/pgtable-hwdef.h>
 
 #if (PHYS_OFFSET & 0x003fffff)
diff --git a/arch/unicore32/kernel/hibernate.c b/arch/unicore32/kernel/hibernate.c
index 7d0f0b7..d75ef8b 100644
--- a/arch/unicore32/kernel/hibernate.c
+++ b/arch/unicore32/kernel/hibernate.c
@@ -15,7 +15,6 @@
 #include <linux/suspend.h>
 #include <linux/bootmem.h>
 
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
diff --git a/arch/unicore32/kernel/irq.c b/arch/unicore32/kernel/irq.c
index d4efa7d..0be5ccd 100644
--- a/arch/unicore32/kernel/irq.c
+++ b/arch/unicore32/kernel/irq.c
@@ -26,7 +26,6 @@
 #include <linux/syscore_ops.h>
 #include <linux/gpio.h>
 
-#include <asm/system.h>
 #include <mach/hardware.h>
 
 #include "setup.h"
diff --git a/arch/unicore32/kernel/ksyms.c b/arch/unicore32/kernel/ksyms.c
index d98bd81..d285d71 100644
--- a/arch/unicore32/kernel/ksyms.c
+++ b/arch/unicore32/kernel/ksyms.c
@@ -20,7 +20,6 @@
 #include <linux/io.h>
 
 #include <asm/checksum.h>
-#include <asm/system.h>
 
 #include "ksyms.h"
 
diff --git a/arch/unicore32/kernel/pci.c b/arch/unicore32/kernel/pci.c
index a8f07fe..2fc2b1b 100644
--- a/arch/unicore32/kernel/pci.c
+++ b/arch/unicore32/kernel/pci.c
@@ -21,7 +21,6 @@
 #include <linux/io.h>
 
 static int debug_pci;
-static int use_firmware;
 
 #define CONFIG_CMD(bus, devfn, where)	\
 	(0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
@@ -276,7 +275,7 @@
 
 	pci_fixup_irqs(pci_common_swizzle, pci_puv3_map_irq);
 
-	if (!use_firmware) {
+	if (!pci_has_flag(PCI_PROBE_ONLY)) {
 		/*
 		 * Size the bridge windows.
 		 */
@@ -303,7 +302,7 @@
 		debug_pci = 1;
 		return NULL;
 	} else if (!strcmp(str, "firmware")) {
-		use_firmware = 1;
+		pci_add_flags(PCI_PROBE_ONLY);
 		return NULL;
 	}
 	return str;
diff --git a/arch/unicore32/kernel/process.c b/arch/unicore32/kernel/process.c
index 52edc2b..b6f0458 100644
--- a/arch/unicore32/kernel/process.c
+++ b/arch/unicore32/kernel/process.c
@@ -34,7 +34,6 @@
 
 #include <asm/cacheflush.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/stacktrace.h>
 
 #include "setup.h"
@@ -381,7 +380,7 @@
 	return install_special_mapping(mm, 0xffff0000, PAGE_SIZE,
 				       VM_READ | VM_EXEC |
 				       VM_MAYREAD | VM_MAYEXEC |
-				       VM_ALWAYSDUMP | VM_RESERVED,
+				       VM_RESERVED,
 				       NULL);
 }
 
diff --git a/arch/unicore32/kernel/setup.h b/arch/unicore32/kernel/setup.h
index dcd1306..f239550 100644
--- a/arch/unicore32/kernel/setup.h
+++ b/arch/unicore32/kernel/setup.h
@@ -12,8 +12,11 @@
 #ifndef __UNICORE_KERNEL_SETUP_H__
 #define __UNICORE_KERNEL_SETUP_H__
 
+#include <asm/hwdef-copro.h>
+
 extern void paging_init(void);
 extern void puv3_core_init(void);
+extern void cpu_init(void);
 
 extern void puv3_ps2_init(void);
 extern void pci_puv3_preinit(void);
diff --git a/arch/unicore32/kernel/traps.c b/arch/unicore32/kernel/traps.c
index b9a2646..2054f0d 100644
--- a/arch/unicore32/kernel/traps.c
+++ b/arch/unicore32/kernel/traps.c
@@ -26,7 +26,6 @@
 #include <linux/unistd.h>
 
 #include <asm/cacheflush.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 
 #include "setup.h"
diff --git a/arch/unicore32/mm/alignment.c b/arch/unicore32/mm/alignment.c
index 28f576d..de7dc5f 100644
--- a/arch/unicore32/mm/alignment.c
+++ b/arch/unicore32/mm/alignment.c
@@ -24,6 +24,8 @@
 #include <asm/tlbflush.h>
 #include <asm/unaligned.h>
 
+#include "mm.h"
+
 #define CODING_BITS(i)	(i & 0xe0000120)
 
 #define LDST_P_BIT(i)	(i & (1 << 28))	/* Preindex             */
diff --git a/arch/unicore32/mm/dma-swiotlb.c b/arch/unicore32/mm/dma-swiotlb.c
index bfa9fbb..16c08b2 100644
--- a/arch/unicore32/mm/dma-swiotlb.c
+++ b/arch/unicore32/mm/dma-swiotlb.c
@@ -17,9 +17,23 @@
 
 #include <asm/dma.h>
 
+static void *unicore_swiotlb_alloc_coherent(struct device *dev, size_t size,
+					    dma_addr_t *dma_handle, gfp_t flags,
+					    struct dma_attrs *attrs)
+{
+	return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
+}
+
+static void unicore_swiotlb_free_coherent(struct device *dev, size_t size,
+					  void *vaddr, dma_addr_t dma_addr,
+					  struct dma_attrs *attrs)
+{
+	swiotlb_free_coherent(dev, size, vaddr, dma_addr);
+}
+
 struct dma_map_ops swiotlb_dma_map_ops = {
-	.alloc_coherent = swiotlb_alloc_coherent,
-	.free_coherent = swiotlb_free_coherent,
+	.alloc = unicore_swiotlb_alloc_coherent,
+	.free = unicore_swiotlb_free_coherent,
 	.map_sg = swiotlb_map_sg_attrs,
 	.unmap_sg = swiotlb_unmap_sg_attrs,
 	.dma_supported = swiotlb_dma_supported,
diff --git a/arch/unicore32/mm/fault.c b/arch/unicore32/mm/fault.c
index 283aa4b..2eeb9c0 100644
--- a/arch/unicore32/mm/fault.c
+++ b/arch/unicore32/mm/fault.c
@@ -20,7 +20,6 @@
 #include <linux/sched.h>
 #include <linux/io.h>
 
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 
diff --git a/arch/unicore32/mm/flush.c b/arch/unicore32/mm/flush.c
index 93478cc..6d4c096 100644
--- a/arch/unicore32/mm/flush.c
+++ b/arch/unicore32/mm/flush.c
@@ -14,7 +14,6 @@
 #include <linux/pagemap.h>
 
 #include <asm/cacheflush.h>
-#include <asm/system.h>
 #include <asm/tlbflush.h>
 
 void flush_cache_mm(struct mm_struct *mm)
diff --git a/arch/unicore32/mm/mm.h b/arch/unicore32/mm/mm.h
index 3296bca..05c7f53 100644
--- a/arch/unicore32/mm/mm.h
+++ b/arch/unicore32/mm/mm.h
@@ -9,6 +9,8 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <asm/hwdef-copro.h>
+
 /* the upper-most page table pointer */
 extern pmd_t *top_pmd;
 extern int sysctl_overcommit_memory;
@@ -34,6 +36,9 @@
 const struct mem_type *get_mem_type(unsigned int type);
 
 extern void __flush_dcache_page(struct address_space *, struct page *);
+extern void hook_fault_code(int nr, int (*fn)
+		(unsigned long, unsigned int, struct pt_regs *),
+		int sig, int code, const char *name);
 
 void __init bootmem_init(void);
 void uc32_mm_memblock_reserve(void);
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 6c29256a..1d14cc6 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -69,7 +69,6 @@
 	select HAVE_ARCH_JUMP_LABEL
 	select HAVE_TEXT_POKE_SMP
 	select HAVE_GENERIC_HARDIRQS
-	select HAVE_SPARSE_IRQ
 	select SPARSE_IRQ
 	select GENERIC_FIND_FIRST_BIT
 	select GENERIC_IRQ_PROBE
@@ -422,27 +421,6 @@
 config X86_INTEL_MID
 	bool
 
-config X86_MRST
-       bool "Moorestown MID platform"
-	depends on PCI
-	depends on PCI_GOANY
-	depends on X86_IO_APIC
-	select X86_INTEL_MID
-	select SFI
-	select DW_APB_TIMER
-	select APB_TIMER
-	select I2C
-	select SPI
-	select INTEL_SCU_IPC
-	select X86_PLATFORM_DEVICES
-	---help---
-	  Moorestown is Intel's Low Power Intel Architecture (LPIA) based Moblin
-	  Internet Device(MID) platform. Moorestown consists of two chips:
-	  Lincroft (CPU core, graphics, and memory controller) and Langwell IOH.
-	  Unlike standard x86 PCs, Moorestown does not have many legacy devices
-	  nor standard legacy replacement devices/features. e.g. Moorestown does
-	  not contain i8259, i8254, HPET, legacy BIOS, most of the io ports.
-
 config X86_MDFLD
        bool "Medfield MID platform"
 	depends on PCI
@@ -456,6 +434,7 @@
 	select SPI
 	select INTEL_SCU_IPC
 	select X86_PLATFORM_DEVICES
+	select MFD_INTEL_MSIC
 	---help---
 	  Medfield is Intel's Low Power Intel Architecture (LPIA) based Moblin
 	  Internet Device(MID) platform. 
@@ -2139,6 +2118,19 @@
 
 	  Note: You have to set alix.force=1 for boards with Award BIOS.
 
+config NET5501
+	bool "Soekris Engineering net5501 System Support (LEDS, GPIO, etc)"
+	select GPIOLIB
+	---help---
+	  This option enables system support for the Soekris Engineering net5501.
+
+config GEOS
+	bool "Traverse Technologies GEOS System Support (LEDS, GPIO, etc)"
+	select GPIOLIB
+	depends on DMI
+	---help---
+	  This option enables system support for the Traverse Technologies GEOS.
+
 endif # X86_32
 
 config AMD_NB
@@ -2171,9 +2163,9 @@
 	depends on X86_64
 	select COMPAT_BINFMT_ELF
 	---help---
-	  Include code to run 32-bit programs under a 64-bit kernel. You should
-	  likely turn this on, unless you're 100% sure that you don't have any
-	  32-bit programs left.
+	  Include code to run legacy 32-bit programs under a
+	  64-bit kernel. You should likely turn this on, unless you're
+	  100% sure that you don't have any 32-bit programs left.
 
 config IA32_AOUT
 	tristate "IA32 a.out support"
@@ -2181,9 +2173,23 @@
 	---help---
 	  Support old a.out binaries in the 32bit emulation.
 
+config X86_X32
+	bool "x32 ABI for 64-bit mode (EXPERIMENTAL)"
+	depends on X86_64 && IA32_EMULATION && EXPERIMENTAL
+	---help---
+	  Include code to run binaries for the x32 native 32-bit ABI
+	  for 64-bit processors.  An x32 process gets access to the
+	  full 64-bit register file and wide data path while leaving
+	  pointers at 32 bits for smaller memory footprint.
+
+	  You will need a recent binutils (2.22 or later) with
+	  elf32_x86_64 support enabled to compile a kernel with this
+	  option set.
+
 config COMPAT
 	def_bool y
-	depends on IA32_EMULATION
+	depends on IA32_EMULATION || X86_X32
+	select ARCH_WANT_OLD_COMPAT_IPC
 
 config COMPAT_FOR_U64_ALIGNMENT
 	def_bool COMPAT
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index 3c57033..706e12e 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -303,7 +303,6 @@
 config X86_INTERNODE_CACHE_SHIFT
 	int
 	default "12" if X86_VSMP
-	default "7" if NUMA
 	default X86_L1_CACHE_SHIFT
 
 config X86_CMPXCHG
@@ -441,7 +440,7 @@
 config CPU_SUP_CYRIX_32
 	default y
 	bool "Support Cyrix processors" if PROCESSOR_SELECT
-	depends on !64BIT
+	depends on M386 || M486 || M586 || M586TSC || M586MMX || (EXPERT && !64BIT)
 	---help---
 	  This enables detection, tunings and quirks for Cyrix processors
 
@@ -495,7 +494,7 @@
 config CPU_SUP_UMC_32
 	default y
 	bool "Support UMC processors" if PROCESSOR_SELECT
-	depends on !64BIT
+	depends on M386 || M486 || (EXPERT && !64BIT)
 	---help---
 	  This enables detection, tunings and quirks for UMC processors
 
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 209ba12..41a7237 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -82,6 +82,22 @@
         endif
 endif
 
+ifdef CONFIG_X86_X32
+	x32_ld_ok := $(call try-run,\
+			/bin/echo -e '1: .quad 1b' | \
+			$(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" - && \
+			$(OBJCOPY) -O elf32-x86-64 "$$TMP" "$$TMPO" && \
+			$(LD) -m elf32_x86_64 "$$TMPO" -o "$$TMP",y,n)
+        ifeq ($(x32_ld_ok),y)
+                CONFIG_X86_X32_ABI := y
+                KBUILD_AFLAGS += -DCONFIG_X86_X32_ABI
+                KBUILD_CFLAGS += -DCONFIG_X86_X32_ABI
+        else
+                $(warning CONFIG_X86_X32 enabled but no binutils support)
+        endif
+endif
+export CONFIG_X86_X32_ABI
+
 # Don't unroll struct assignments with kmemcheck enabled
 ifeq ($(CONFIG_KMEMCHECK),y)
 	KBUILD_CFLAGS += $(call cc-option,-fno-builtin-memcpy)
@@ -113,6 +129,7 @@
 KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
 # prevent gcc from generating any FP code by mistake
 KBUILD_CFLAGS += $(call cc-option,-mno-sse -mno-mmx -mno-sse2 -mno-3dnow,)
+KBUILD_CFLAGS += $(call cc-option,-mno-avx,)
 
 KBUILD_CFLAGS += $(mflags-y)
 KBUILD_AFLAGS += $(mflags-y)
diff --git a/arch/x86/Makefile.um b/arch/x86/Makefile.um
index 36ddec6..4be406a 100644
--- a/arch/x86/Makefile.um
+++ b/arch/x86/Makefile.um
@@ -8,15 +8,11 @@
 ELF_FORMAT 		:= elf32-i386
 CHECKFLAGS	+= -D__i386__
 
-ifeq ("$(origin SUBARCH)", "command line")
-ifneq ("$(shell uname -m | sed -e s/i.86/i386/)", "$(SUBARCH)")
 KBUILD_CFLAGS		+= $(call cc-option,-m32)
 KBUILD_AFLAGS		+= $(call cc-option,-m32)
 LINK-y			+= $(call cc-option,-m32)
 
 export LDFLAGS
-endif
-endif
 
 # First of all, tune CFLAGS for the specific CPU. This actually sets cflags-y.
 include $(srctree)/arch/x86/Makefile_32.cpu
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 95365a8..5a747dd 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -37,7 +37,8 @@
 targets		+= $(setup-y)
 hostprogs-y	:= mkcpustr tools/build
 
-HOST_EXTRACFLAGS += $(LINUXINCLUDE)
+HOST_EXTRACFLAGS += -I$(srctree)/tools/include $(LINUXINCLUDE) \
+	            -D__EXPORTED_HEADERS__
 
 $(obj)/cpu.o: $(obj)/cpustr.h
 
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
index c7093bd..18997e5 100644
--- a/arch/x86/boot/boot.h
+++ b/arch/x86/boot/boot.h
@@ -67,7 +67,7 @@
 {
 	asm volatile("outl %0,%1" : : "a" (v), "dN" (port));
 }
-static inline u32 inl(u32 port)
+static inline u32 inl(u16 port)
 {
 	u32 v;
 	asm volatile("inl %1,%0" : "=a" (v) : "dN" (port));
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index b123b9a..fd55a2f 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -22,6 +22,7 @@
 LDFLAGS_vmlinux := -T
 
 hostprogs-y	:= mkpiggy
+HOST_EXTRACFLAGS += -I$(srctree)/tools/include
 
 VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
 	$(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index fec216f..0cdfc0d 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -539,7 +539,7 @@
 		struct initrd *initrd;
 		efi_file_handle_t *h;
 		efi_file_info_t *info;
-		efi_char16_t filename[256];
+		efi_char16_t filename_16[256];
 		unsigned long info_sz;
 		efi_guid_t info_guid = EFI_FILE_INFO_ID;
 		efi_char16_t *p;
@@ -552,14 +552,14 @@
 		str += 7;
 
 		initrd = &initrds[i];
-		p = filename;
+		p = filename_16;
 
 		/* Skip any leading slashes */
 		while (*str == '/' || *str == '\\')
 			str++;
 
 		while (*str && *str != ' ' && *str != '\n') {
-			if (p >= filename + sizeof(filename))
+			if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16))
 				break;
 
 			*p++ = *str++;
@@ -583,7 +583,7 @@
 				goto free_initrds;
 		}
 
-		status = efi_call_phys5(fh->open, fh, &h, filename,
+		status = efi_call_phys5(fh->open, fh, &h, filename_16,
 					EFI_FILE_MODE_READ, (u64)0);
 		if (status != EFI_SUCCESS)
 			goto close_handles;
diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c
index 46a8238..958a641 100644
--- a/arch/x86/boot/compressed/mkpiggy.c
+++ b/arch/x86/boot/compressed/mkpiggy.c
@@ -29,14 +29,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <inttypes.h>
-
-static uint32_t getle32(const void *p)
-{
-	const uint8_t *cp = p;
-
-	return (uint32_t)cp[0] + ((uint32_t)cp[1] << 8) +
-		((uint32_t)cp[2] << 16) + ((uint32_t)cp[3] << 24);
-}
+#include <tools/le_byteshift.h>
 
 int main(int argc, char *argv[])
 {
@@ -69,7 +62,7 @@
 	}
 
 	ilen = ftell(f);
-	olen = getle32(&olen);
+	olen = get_unaligned_le32(&olen);
 	fclose(f);
 
 	/*
diff --git a/arch/x86/boot/compressed/relocs.c b/arch/x86/boot/compressed/relocs.c
index 89bbf4e..d3c0b02 100644
--- a/arch/x86/boot/compressed/relocs.c
+++ b/arch/x86/boot/compressed/relocs.c
@@ -10,6 +10,7 @@
 #define USE_BSD
 #include <endian.h>
 #include <regex.h>
+#include <tools/le_byteshift.h>
 
 static void die(char *fmt, ...);
 
@@ -605,10 +606,7 @@
 		fwrite("\0\0\0\0", 4, 1, stdout);
 		/* Now print each relocation */
 		for (i = 0; i < reloc_count; i++) {
-			buf[0] = (relocs[i] >>  0) & 0xff;
-			buf[1] = (relocs[i] >>  8) & 0xff;
-			buf[2] = (relocs[i] >> 16) & 0xff;
-			buf[3] = (relocs[i] >> 24) & 0xff;
+			put_unaligned_le32(relocs[i], buf);
 			fwrite(buf, 4, 1, stdout);
 		}
 	}
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c
index 4e9bd6b..ed54976 100644
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -29,18 +29,18 @@
 #include <stdarg.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/sysmacros.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/mman.h>
-#include <asm/boot.h>
+#include <tools/le_byteshift.h>
 
 typedef unsigned char  u8;
 typedef unsigned short u16;
-typedef unsigned long  u32;
+typedef unsigned int   u32;
 
 #define DEFAULT_MAJOR_ROOT 0
 #define DEFAULT_MINOR_ROOT 0
+#define DEFAULT_ROOT_DEV (DEFAULT_MAJOR_ROOT << 8 | DEFAULT_MINOR_ROOT)
 
 /* Minimal number of setup sectors */
 #define SETUP_SECT_MIN 5
@@ -159,7 +159,7 @@
 		die("read-error on `setup'");
 	if (c < 1024)
 		die("The setup must be at least 1024 bytes");
-	if (buf[510] != 0x55 || buf[511] != 0xaa)
+	if (get_unaligned_le16(&buf[510]) != 0xAA55)
 		die("Boot block hasn't got boot flag (0xAA55)");
 	fclose(file);
 
@@ -171,8 +171,7 @@
 	memset(buf+c, 0, i-c);
 
 	/* Set the default root device */
-	buf[508] = DEFAULT_MINOR_ROOT;
-	buf[509] = DEFAULT_MAJOR_ROOT;
+	put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
 
 	fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i);
 
@@ -192,44 +191,42 @@
 
 	/* Patch the setup code with the appropriate size parameters */
 	buf[0x1f1] = setup_sectors-1;
-	buf[0x1f4] = sys_size;
-	buf[0x1f5] = sys_size >> 8;
-	buf[0x1f6] = sys_size >> 16;
-	buf[0x1f7] = sys_size >> 24;
+	put_unaligned_le32(sys_size, &buf[0x1f4]);
 
 #ifdef CONFIG_EFI_STUB
 	file_sz = sz + i + ((sys_size * 16) - sz);
 
-	pe_header = *(unsigned int *)&buf[0x3c];
+	pe_header = get_unaligned_le32(&buf[0x3c]);
 
 	/* Size of code */
-	*(unsigned int *)&buf[pe_header + 0x1c] = file_sz;
+	put_unaligned_le32(file_sz, &buf[pe_header + 0x1c]);
 
 	/* Size of image */
-	*(unsigned int *)&buf[pe_header + 0x50] = file_sz;
+	put_unaligned_le32(file_sz, &buf[pe_header + 0x50]);
 
 #ifdef CONFIG_X86_32
 	/* Address of entry point */
-	*(unsigned int *)&buf[pe_header + 0x28] = i;
+	put_unaligned_le32(i, &buf[pe_header + 0x28]);
 
 	/* .text size */
-	*(unsigned int *)&buf[pe_header + 0xb0] = file_sz;
+	put_unaligned_le32(file_sz, &buf[pe_header + 0xb0]);
 
 	/* .text size of initialised data */
-	*(unsigned int *)&buf[pe_header + 0xb8] = file_sz;
+	put_unaligned_le32(file_sz, &buf[pe_header + 0xb8]);
 #else
 	/*
 	 * Address of entry point. startup_32 is at the beginning and
 	 * the 64-bit entry point (startup_64) is always 512 bytes
 	 * after.
 	 */
-	*(unsigned int *)&buf[pe_header + 0x28] = i + 512;
+	put_unaligned_le32(i + 512, &buf[pe_header + 0x28]);
 
 	/* .text size */
-	*(unsigned int *)&buf[pe_header + 0xc0] = file_sz;
+	put_unaligned_le32(file_sz, &buf[pe_header + 0xc0]);
 
 	/* .text size of initialised data */
-	*(unsigned int *)&buf[pe_header + 0xc8] = file_sz;
+	put_unaligned_le32(file_sz, &buf[pe_header + 0xc8]);
+
 #endif /* CONFIG_X86_32 */
 #endif /* CONFIG_EFI_STUB */
 
@@ -250,8 +247,9 @@
 	}
 
 	/* Write the CRC */
-	fprintf(stderr, "CRC %lx\n", crc);
-	if (fwrite(&crc, 1, 4, stdout) != 4)
+	fprintf(stderr, "CRC %x\n", crc);
+	put_unaligned_le32(crc, buf);
+	if (fwrite(buf, 1, 4, stdout) != 4)
 		die("Writing CRC failed");
 
 	close(fd);
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig
index 2bf18059f..119db67 100644
--- a/arch/x86/configs/i386_defconfig
+++ b/arch/x86/configs/i386_defconfig
@@ -15,23 +15,28 @@
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_RESOURCE_COUNTERS=y
 CONFIG_CGROUP_SCHED=y
-CONFIG_UTS_NS=y
-CONFIG_IPC_NS=y
-CONFIG_USER_NS=y
-CONFIG_PID_NS=y
-CONFIG_NET_NS=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_KALLSYMS_EXTRA_PASS=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
 CONFIG_KPROBES=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_SGI_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_EFI_PARTITION=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
-CONFIG_SPARSE_IRQ=y
 CONFIG_X86_GENERIC=y
 CONFIG_HPET_TIMER=y
 CONFIG_SCHED_SMT=y
@@ -51,14 +56,12 @@
 CONFIG_KEXEC=y
 CONFIG_CRASH_DUMP=y
 # CONFIG_COMPAT_VDSO is not set
-CONFIG_PM=y
+CONFIG_HIBERNATION=y
 CONFIG_PM_DEBUG=y
 CONFIG_PM_TRACE_RTC=y
-CONFIG_HIBERNATION=y
 CONFIG_ACPI_PROCFS=y
 CONFIG_ACPI_DOCK=y
 CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_DEBUG=y
 # CONFIG_CPU_FREQ_STAT is not set
 CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
@@ -69,7 +72,6 @@
 CONFIG_PCCARD=y
 CONFIG_YENTA=y
 CONFIG_HOTPLUG_PCI=y
-CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
 CONFIG_BINFMT_MISC=y
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -120,7 +122,6 @@
 CONFIG_IP_NF_IPTABLES=y
 CONFIG_IP_NF_FILTER=y
 CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_TARGET_LOG=y
 CONFIG_IP_NF_TARGET_ULOG=y
 CONFIG_NF_NAT=y
 CONFIG_IP_NF_TARGET_MASQUERADE=y
@@ -128,7 +129,6 @@
 CONFIG_NF_CONNTRACK_IPV6=y
 CONFIG_IP6_NF_IPTABLES=y
 CONFIG_IP6_NF_MATCH_IPV6HEADER=y
-CONFIG_IP6_NF_TARGET_LOG=y
 CONFIG_IP6_NF_FILTER=y
 CONFIG_IP6_NF_TARGET_REJECT=y
 CONFIG_IP6_NF_MANGLE=y
@@ -169,25 +169,20 @@
 CONFIG_MACINTOSH_DRIVERS=y
 CONFIG_MAC_EMUMOUSEBTN=y
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_VENDOR_3COM=y
+CONFIG_NETCONSOLE=y
+CONFIG_BNX2=y
+CONFIG_TIGON3=y
 CONFIG_NET_TULIP=y
-CONFIG_NET_PCI=y
-CONFIG_FORCEDETH=y
 CONFIG_E100=y
-CONFIG_NE2K_PCI=y
-CONFIG_8139TOO=y
-# CONFIG_8139TOO_PIO is not set
 CONFIG_E1000=y
 CONFIG_E1000E=y
-CONFIG_R8169=y
 CONFIG_SKY2=y
-CONFIG_TIGON3=y
-CONFIG_BNX2=y
-CONFIG_TR=y
-CONFIG_NET_PCMCIA=y
+CONFIG_NE2K_PCI=y
+CONFIG_FORCEDETH=y
+CONFIG_8139TOO=y
+# CONFIG_8139TOO_PIO is not set
+CONFIG_R8169=y
 CONFIG_FDDI=y
-CONFIG_NETCONSOLE=y
 CONFIG_INPUT_POLLDEV=y
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 CONFIG_INPUT_EVDEV=y
@@ -196,6 +191,7 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_INPUT_MISC=y
 CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_NONSTANDARD=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
@@ -205,7 +201,6 @@
 CONFIG_SERIAL_8250_SHARE_IRQ=y
 CONFIG_SERIAL_8250_DETECT_IRQ=y
 CONFIG_SERIAL_8250_RSA=y
-# CONFIG_LEGACY_PTYS is not set
 CONFIG_HW_RANDOM=y
 CONFIG_NVRAM=y
 CONFIG_HPET=y
@@ -220,7 +215,6 @@
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
 CONFIG_FB_EFI=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_LOGO=y
@@ -283,7 +277,6 @@
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_HUGETLBFS=y
 CONFIG_NFS_FS=y
@@ -291,18 +284,6 @@
 CONFIG_NFS_V3_ACL=y
 CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_OSF_PARTITION=y
-CONFIG_AMIGA_PARTITION=y
-CONFIG_MAC_PARTITION=y
-CONFIG_BSD_DISKLABEL=y
-CONFIG_MINIX_SUBPARTITION=y
-CONFIG_SOLARIS_X86_PARTITION=y
-CONFIG_UNIXWARE_DISKLABEL=y
-CONFIG_SGI_PARTITION=y
-CONFIG_SUN_PARTITION=y
-CONFIG_KARMA_PARTITION=y
-CONFIG_EFI_PARTITION=y
 CONFIG_NLS_DEFAULT="utf8"
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=y
@@ -317,13 +298,12 @@
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
 CONFIG_EARLY_PRINTK_DBGP=y
 CONFIG_DEBUG_STACKOVERFLOW=y
-CONFIG_DEBUG_STACK_USAGE=y
 # CONFIG_DEBUG_RODATA_TEST is not set
 CONFIG_DEBUG_NX_TEST=m
 CONFIG_DEBUG_BOOT_PARAMS=y
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig
index 058a35b..76eb290 100644
--- a/arch/x86/configs/x86_64_defconfig
+++ b/arch/x86/configs/x86_64_defconfig
@@ -1,4 +1,3 @@
-CONFIG_64BIT=y
 CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
@@ -16,26 +15,29 @@
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_RESOURCE_COUNTERS=y
 CONFIG_CGROUP_SCHED=y
-CONFIG_UTS_NS=y
-CONFIG_IPC_NS=y
-CONFIG_USER_NS=y
-CONFIG_PID_NS=y
-CONFIG_NET_NS=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_KALLSYMS_EXTRA_PASS=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
 CONFIG_KPROBES=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_SGI_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_EFI_PARTITION=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
-CONFIG_SPARSE_IRQ=y
 CONFIG_CALGARY_IOMMU=y
-CONFIG_AMD_IOMMU=y
-CONFIG_AMD_IOMMU_STATS=y
 CONFIG_NR_CPUS=64
 CONFIG_SCHED_SMT=y
 CONFIG_PREEMPT_VOLUNTARY=y
@@ -53,27 +55,22 @@
 CONFIG_KEXEC=y
 CONFIG_CRASH_DUMP=y
 # CONFIG_COMPAT_VDSO is not set
-CONFIG_PM=y
+CONFIG_HIBERNATION=y
 CONFIG_PM_DEBUG=y
 CONFIG_PM_TRACE_RTC=y
-CONFIG_HIBERNATION=y
 CONFIG_ACPI_PROCFS=y
 CONFIG_ACPI_DOCK=y
 CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_DEBUG=y
 # CONFIG_CPU_FREQ_STAT is not set
 CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 CONFIG_X86_ACPI_CPUFREQ=y
 CONFIG_PCI_MMCONFIG=y
-CONFIG_INTEL_IOMMU=y
-# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set
 CONFIG_PCIEPORTBUS=y
 CONFIG_PCCARD=y
 CONFIG_YENTA=y
 CONFIG_HOTPLUG_PCI=y
-CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
 CONFIG_BINFMT_MISC=y
 CONFIG_IA32_EMULATION=y
 CONFIG_NET=y
@@ -125,7 +122,6 @@
 CONFIG_IP_NF_IPTABLES=y
 CONFIG_IP_NF_FILTER=y
 CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_TARGET_LOG=y
 CONFIG_IP_NF_TARGET_ULOG=y
 CONFIG_NF_NAT=y
 CONFIG_IP_NF_TARGET_MASQUERADE=y
@@ -133,7 +129,6 @@
 CONFIG_NF_CONNTRACK_IPV6=y
 CONFIG_IP6_NF_IPTABLES=y
 CONFIG_IP6_NF_MATCH_IPV6HEADER=y
-CONFIG_IP6_NF_TARGET_LOG=y
 CONFIG_IP6_NF_FILTER=y
 CONFIG_IP6_NF_TARGET_REJECT=y
 CONFIG_IP6_NF_MANGLE=y
@@ -172,20 +167,15 @@
 CONFIG_MACINTOSH_DRIVERS=y
 CONFIG_MAC_EMUMOUSEBTN=y
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_VENDOR_3COM=y
+CONFIG_NETCONSOLE=y
+CONFIG_TIGON3=y
 CONFIG_NET_TULIP=y
-CONFIG_NET_PCI=y
-CONFIG_FORCEDETH=y
 CONFIG_E100=y
-CONFIG_8139TOO=y
 CONFIG_E1000=y
 CONFIG_SKY2=y
-CONFIG_TIGON3=y
-CONFIG_TR=y
-CONFIG_NET_PCMCIA=y
+CONFIG_FORCEDETH=y
+CONFIG_8139TOO=y
 CONFIG_FDDI=y
-CONFIG_NETCONSOLE=y
 CONFIG_INPUT_POLLDEV=y
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 CONFIG_INPUT_EVDEV=y
@@ -194,6 +184,7 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_INPUT_MISC=y
 CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_NONSTANDARD=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
@@ -203,7 +194,6 @@
 CONFIG_SERIAL_8250_SHARE_IRQ=y
 CONFIG_SERIAL_8250_DETECT_IRQ=y
 CONFIG_SERIAL_8250_RSA=y
-# CONFIG_LEGACY_PTYS is not set
 CONFIG_HW_RANDOM=y
 # CONFIG_HW_RANDOM_INTEL is not set
 # CONFIG_HW_RANDOM_AMD is not set
@@ -221,7 +211,6 @@
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
 CONFIG_FB_EFI=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_LOGO=y
@@ -268,6 +257,10 @@
 # CONFIG_RTC_HCTOSYS is not set
 CONFIG_DMADEVICES=y
 CONFIG_EEEPC_LAPTOP=y
+CONFIG_AMD_IOMMU=y
+CONFIG_AMD_IOMMU_STATS=y
+CONFIG_INTEL_IOMMU=y
+# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set
 CONFIG_EFI_VARS=y
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
@@ -284,7 +277,6 @@
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_HUGETLBFS=y
 CONFIG_NFS_FS=y
@@ -292,18 +284,6 @@
 CONFIG_NFS_V3_ACL=y
 CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_OSF_PARTITION=y
-CONFIG_AMIGA_PARTITION=y
-CONFIG_MAC_PARTITION=y
-CONFIG_BSD_DISKLABEL=y
-CONFIG_MINIX_SUBPARTITION=y
-CONFIG_SOLARIS_X86_PARTITION=y
-CONFIG_UNIXWARE_DISKLABEL=y
-CONFIG_SGI_PARTITION=y
-CONFIG_SUN_PARTITION=y
-CONFIG_KARMA_PARTITION=y
-CONFIG_EFI_PARTITION=y
 CONFIG_NLS_DEFAULT="utf8"
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=y
@@ -317,13 +297,12 @@
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
 CONFIG_EARLY_PRINTK_DBGP=y
 CONFIG_DEBUG_STACKOVERFLOW=y
-CONFIG_DEBUG_STACK_USAGE=y
 # CONFIG_DEBUG_RODATA_TEST is not set
 CONFIG_DEBUG_NX_TEST=m
 CONFIG_DEBUG_BOOT_PARAMS=y
diff --git a/arch/x86/crypto/camellia_glue.c b/arch/x86/crypto/camellia_glue.c
index 1ca36a9..3306dc0 100644
--- a/arch/x86/crypto/camellia_glue.c
+++ b/arch/x86/crypto/camellia_glue.c
@@ -1925,7 +1925,7 @@
 module_param(force, int, 0);
 MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
 
-int __init init(void)
+static int __init init(void)
 {
 	if (!force && is_blacklisted_cpu()) {
 		printk(KERN_INFO
@@ -1938,7 +1938,7 @@
 	return crypto_register_algs(camellia_algs, ARRAY_SIZE(camellia_algs));
 }
 
-void __exit fini(void)
+static void __exit fini(void)
 {
 	crypto_unregister_algs(camellia_algs, ARRAY_SIZE(camellia_algs));
 }
diff --git a/arch/x86/crypto/twofish_glue_3way.c b/arch/x86/crypto/twofish_glue_3way.c
index 408fc0c..922ab24 100644
--- a/arch/x86/crypto/twofish_glue_3way.c
+++ b/arch/x86/crypto/twofish_glue_3way.c
@@ -668,7 +668,7 @@
 module_param(force, int, 0);
 MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
 
-int __init init(void)
+static int __init init(void)
 {
 	if (!force && is_blacklisted_cpu()) {
 		printk(KERN_INFO
@@ -681,7 +681,7 @@
 	return crypto_register_algs(tf_algs, ARRAY_SIZE(tf_algs));
 }
 
-void __exit fini(void)
+static void __exit fini(void)
 {
 	crypto_unregister_algs(tf_algs, ARRAY_SIZE(tf_algs));
 }
diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c
index 39e4909..d511d95 100644
--- a/arch/x86/ia32/ia32_aout.c
+++ b/arch/x86/ia32/ia32_aout.c
@@ -26,7 +26,6 @@
 #include <linux/init.h>
 #include <linux/jiffies.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 #include <asm/cacheflush.h>
@@ -323,7 +322,6 @@
 	}
 
 	install_exec_creds(bprm);
-	current->flags &= ~PF_FORKNOEXEC;
 
 	if (N_MAGIC(ex) == OMAGIC) {
 		unsigned long text_addr, map_size;
@@ -519,7 +517,8 @@
 
 static int __init init_aout_binfmt(void)
 {
-	return register_binfmt(&aout_format);
+	register_binfmt(&aout_format);
+	return 0;
 }
 
 static void __exit exit_aout_binfmt(void)
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index 6557769..a69245b 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -12,10 +12,8 @@
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/kernel.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/wait.h>
-#include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
 #include <linux/personality.h>
@@ -24,6 +22,7 @@
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/i387.h>
+#include <asm/fpu-internal.h>
 #include <asm/ptrace.h>
 #include <asm/ia32_unistd.h>
 #include <asm/user32.h>
@@ -31,20 +30,15 @@
 #include <asm/proto.h>
 #include <asm/vdso.h>
 #include <asm/sigframe.h>
+#include <asm/sighandling.h>
 #include <asm/sys_ia32.h>
 
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
-#define FIX_EFLAGS	(X86_EFLAGS_AC | X86_EFLAGS_OF | \
-			 X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \
-			 X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \
-			 X86_EFLAGS_CF)
-
-void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
+#define FIX_EFLAGS	__FIX_EFLAGS
 
 int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
 {
 	int err = 0;
+	bool ia32 = is_ia32_task();
 
 	if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
 		return -EFAULT;
@@ -74,8 +68,13 @@
 			case __SI_FAULT >> 16:
 				break;
 			case __SI_CHLD >> 16:
-				put_user_ex(from->si_utime, &to->si_utime);
-				put_user_ex(from->si_stime, &to->si_stime);
+				if (ia32) {
+					put_user_ex(from->si_utime, &to->si_utime);
+					put_user_ex(from->si_stime, &to->si_stime);
+				} else {
+					put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime);
+					put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime);
+				}
 				put_user_ex(from->si_status, &to->si_status);
 				/* FALL THROUGH */
 			default:
@@ -347,7 +346,7 @@
 		put_user_ex(regs->dx, &sc->dx);
 		put_user_ex(regs->cx, &sc->cx);
 		put_user_ex(regs->ax, &sc->ax);
-		put_user_ex(current->thread.trap_no, &sc->trapno);
+		put_user_ex(current->thread.trap_nr, &sc->trapno);
 		put_user_ex(current->thread.error_code, &sc->err);
 		put_user_ex(regs->ip, &sc->ip);
 		put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
index f6f5c53..aec2202 100644
--- a/arch/x86/ia32/sys_ia32.c
+++ b/arch/x86/ia32/sys_ia32.c
@@ -287,46 +287,6 @@
 	return ret;
 }
 
-asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
-				     compat_sigset_t __user *oset,
-				     unsigned int sigsetsize)
-{
-	sigset_t s;
-	compat_sigset_t s32;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-
-	if (set) {
-		if (copy_from_user(&s32, set, sizeof(compat_sigset_t)))
-			return -EFAULT;
-		switch (_NSIG_WORDS) {
-		case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
-		case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
-		case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
-		case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
-		}
-	}
-	set_fs(KERNEL_DS);
-	ret = sys_rt_sigprocmask(how,
-				 set ? (sigset_t __user *)&s : NULL,
-				 oset ? (sigset_t __user *)&s : NULL,
-				 sigsetsize);
-	set_fs(old_fs);
-	if (ret)
-		return ret;
-	if (oset) {
-		switch (_NSIG_WORDS) {
-		case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
-		case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
-		case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
-		case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
-		}
-		if (copy_to_user(oset, &s32, sizeof(compat_sigset_t)))
-			return -EFAULT;
-	}
-	return 0;
-}
-
 asmlinkage long sys32_alarm(unsigned int seconds)
 {
 	return alarm_setitimer(seconds);
diff --git a/arch/x86/include/asm/Kbuild b/arch/x86/include/asm/Kbuild
index b57e6a4..f9c0d3b 100644
--- a/arch/x86/include/asm/Kbuild
+++ b/arch/x86/include/asm/Kbuild
@@ -14,6 +14,7 @@
 header-y += mtrr.h
 header-y += posix_types_32.h
 header-y += posix_types_64.h
+header-y += posix_types_x32.h
 header-y += prctl.h
 header-y += processor-flags.h
 header-y += ptrace-abi.h
@@ -24,3 +25,4 @@
 
 genhdr-y += unistd_32.h
 genhdr-y += unistd_64.h
+genhdr-y += unistd_x32.h
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h
index 37ad100..49331be 100644
--- a/arch/x86/include/asm/alternative.h
+++ b/arch/x86/include/asm/alternative.h
@@ -145,6 +145,12 @@
  */
 #define ASM_OUTPUT2(a...) a
 
+/*
+ * use this macro if you need clobbers but no inputs in
+ * alternative_{input,io,call}()
+ */
+#define ASM_NO_INPUT_CLOBBER(clbr...) "i" (0) : clbr
+
 struct paravirt_patch_site;
 #ifdef CONFIG_PARAVIRT
 void apply_paravirt(struct paravirt_patch_site *start,
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 3ab9bdd..d854101 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -11,7 +11,6 @@
 #include <linux/atomic.h>
 #include <asm/fixmap.h>
 #include <asm/mpspec.h>
-#include <asm/system.h>
 #include <asm/msr.h>
 
 #define ARCH_APICTIMER_STOPS_ON_C3	1
@@ -288,6 +287,7 @@
 
 	int (*probe)(void);
 	int (*acpi_madt_oem_check)(char *oem_id, char *oem_table_id);
+	int (*apic_id_valid)(int apicid);
 	int (*apic_id_registered)(void);
 
 	u32 irq_delivery_mode;
@@ -532,6 +532,11 @@
 	return apic->get_apic_id(reg);
 }
 
+static inline int default_apic_id_valid(int apicid)
+{
+	return (apicid < 255);
+}
+
 extern void default_setup_apic_routing(void);
 
 extern struct apic apic_noop;
diff --git a/arch/x86/include/asm/atomic64_32.h b/arch/x86/include/asm/atomic64_32.h
index fa13f0e..1981199 100644
--- a/arch/x86/include/asm/atomic64_32.h
+++ b/arch/x86/include/asm/atomic64_32.h
@@ -14,13 +14,52 @@
 
 #define ATOMIC64_INIT(val)	{ (val) }
 
-#ifdef CONFIG_X86_CMPXCHG64
-#define ATOMIC64_ALTERNATIVE_(f, g) "call atomic64_" #g "_cx8"
+#define __ATOMIC64_DECL(sym) void atomic64_##sym(atomic64_t *, ...)
+#ifndef ATOMIC64_EXPORT
+#define ATOMIC64_DECL_ONE __ATOMIC64_DECL
 #else
-#define ATOMIC64_ALTERNATIVE_(f, g) ALTERNATIVE("call atomic64_" #f "_386", "call atomic64_" #g "_cx8", X86_FEATURE_CX8)
+#define ATOMIC64_DECL_ONE(sym) __ATOMIC64_DECL(sym); \
+	ATOMIC64_EXPORT(atomic64_##sym)
 #endif
 
-#define ATOMIC64_ALTERNATIVE(f) ATOMIC64_ALTERNATIVE_(f, f)
+#ifdef CONFIG_X86_CMPXCHG64
+#define __alternative_atomic64(f, g, out, in...) \
+	asm volatile("call %P[func]" \
+		     : out : [func] "i" (atomic64_##g##_cx8), ## in)
+
+#define ATOMIC64_DECL(sym) ATOMIC64_DECL_ONE(sym##_cx8)
+#else
+#define __alternative_atomic64(f, g, out, in...) \
+	alternative_call(atomic64_##f##_386, atomic64_##g##_cx8, \
+			 X86_FEATURE_CX8, ASM_OUTPUT2(out), ## in)
+
+#define ATOMIC64_DECL(sym) ATOMIC64_DECL_ONE(sym##_cx8); \
+	ATOMIC64_DECL_ONE(sym##_386)
+
+ATOMIC64_DECL_ONE(add_386);
+ATOMIC64_DECL_ONE(sub_386);
+ATOMIC64_DECL_ONE(inc_386);
+ATOMIC64_DECL_ONE(dec_386);
+#endif
+
+#define alternative_atomic64(f, out, in...) \
+	__alternative_atomic64(f, f, ASM_OUTPUT2(out), ## in)
+
+ATOMIC64_DECL(read);
+ATOMIC64_DECL(set);
+ATOMIC64_DECL(xchg);
+ATOMIC64_DECL(add_return);
+ATOMIC64_DECL(sub_return);
+ATOMIC64_DECL(inc_return);
+ATOMIC64_DECL(dec_return);
+ATOMIC64_DECL(dec_if_positive);
+ATOMIC64_DECL(inc_not_zero);
+ATOMIC64_DECL(add_unless);
+
+#undef ATOMIC64_DECL
+#undef ATOMIC64_DECL_ONE
+#undef __ATOMIC64_DECL
+#undef ATOMIC64_EXPORT
 
 /**
  * atomic64_cmpxchg - cmpxchg atomic64 variable
@@ -50,11 +89,9 @@
 	long long o;
 	unsigned high = (unsigned)(n >> 32);
 	unsigned low = (unsigned)n;
-	asm volatile(ATOMIC64_ALTERNATIVE(xchg)
-		     : "=A" (o), "+b" (low), "+c" (high)
-		     : "S" (v)
-		     : "memory"
-		     );
+	alternative_atomic64(xchg, "=&A" (o),
+			     "S" (v), "b" (low), "c" (high)
+			     : "memory");
 	return o;
 }
 
@@ -69,11 +106,9 @@
 {
 	unsigned high = (unsigned)(i >> 32);
 	unsigned low = (unsigned)i;
-	asm volatile(ATOMIC64_ALTERNATIVE(set)
-		     : "+b" (low), "+c" (high)
-		     : "S" (v)
-		     : "eax", "edx", "memory"
-		     );
+	alternative_atomic64(set, /* no output */,
+			     "S" (v), "b" (low), "c" (high)
+			     : "eax", "edx", "memory");
 }
 
 /**
@@ -85,10 +120,7 @@
 static inline long long atomic64_read(const atomic64_t *v)
 {
 	long long r;
-	asm volatile(ATOMIC64_ALTERNATIVE(read)
-		     : "=A" (r), "+c" (v)
-		     : : "memory"
-		     );
+	alternative_atomic64(read, "=&A" (r), "c" (v) : "memory");
 	return r;
  }
 
@@ -101,10 +133,9 @@
  */
 static inline long long atomic64_add_return(long long i, atomic64_t *v)
 {
-	asm volatile(ATOMIC64_ALTERNATIVE(add_return)
-		     : "+A" (i), "+c" (v)
-		     : : "memory"
-		     );
+	alternative_atomic64(add_return,
+			     ASM_OUTPUT2("+A" (i), "+c" (v)),
+			     ASM_NO_INPUT_CLOBBER("memory"));
 	return i;
 }
 
@@ -113,32 +144,25 @@
  */
 static inline long long atomic64_sub_return(long long i, atomic64_t *v)
 {
-	asm volatile(ATOMIC64_ALTERNATIVE(sub_return)
-		     : "+A" (i), "+c" (v)
-		     : : "memory"
-		     );
+	alternative_atomic64(sub_return,
+			     ASM_OUTPUT2("+A" (i), "+c" (v)),
+			     ASM_NO_INPUT_CLOBBER("memory"));
 	return i;
 }
 
 static inline long long atomic64_inc_return(atomic64_t *v)
 {
 	long long a;
-	asm volatile(ATOMIC64_ALTERNATIVE(inc_return)
-		     : "=A" (a)
-		     : "S" (v)
-		     : "memory", "ecx"
-		     );
+	alternative_atomic64(inc_return, "=&A" (a),
+			     "S" (v) : "memory", "ecx");
 	return a;
 }
 
 static inline long long atomic64_dec_return(atomic64_t *v)
 {
 	long long a;
-	asm volatile(ATOMIC64_ALTERNATIVE(dec_return)
-		     : "=A" (a)
-		     : "S" (v)
-		     : "memory", "ecx"
-		     );
+	alternative_atomic64(dec_return, "=&A" (a),
+			     "S" (v) : "memory", "ecx");
 	return a;
 }
 
@@ -151,10 +175,9 @@
  */
 static inline long long atomic64_add(long long i, atomic64_t *v)
 {
-	asm volatile(ATOMIC64_ALTERNATIVE_(add, add_return)
-		     : "+A" (i), "+c" (v)
-		     : : "memory"
-		     );
+	__alternative_atomic64(add, add_return,
+			       ASM_OUTPUT2("+A" (i), "+c" (v)),
+			       ASM_NO_INPUT_CLOBBER("memory"));
 	return i;
 }
 
@@ -167,10 +190,9 @@
  */
 static inline long long atomic64_sub(long long i, atomic64_t *v)
 {
-	asm volatile(ATOMIC64_ALTERNATIVE_(sub, sub_return)
-		     : "+A" (i), "+c" (v)
-		     : : "memory"
-		     );
+	__alternative_atomic64(sub, sub_return,
+			       ASM_OUTPUT2("+A" (i), "+c" (v)),
+			       ASM_NO_INPUT_CLOBBER("memory"));
 	return i;
 }
 
@@ -196,10 +218,8 @@
  */
 static inline void atomic64_inc(atomic64_t *v)
 {
-	asm volatile(ATOMIC64_ALTERNATIVE_(inc, inc_return)
-		     : : "S" (v)
-		     : "memory", "eax", "ecx", "edx"
-		     );
+	__alternative_atomic64(inc, inc_return, /* no output */,
+			       "S" (v) : "memory", "eax", "ecx", "edx");
 }
 
 /**
@@ -210,10 +230,8 @@
  */
 static inline void atomic64_dec(atomic64_t *v)
 {
-	asm volatile(ATOMIC64_ALTERNATIVE_(dec, dec_return)
-		     : : "S" (v)
-		     : "memory", "eax", "ecx", "edx"
-		     );
+	__alternative_atomic64(dec, dec_return, /* no output */,
+			       "S" (v) : "memory", "eax", "ecx", "edx");
 }
 
 /**
@@ -263,15 +281,15 @@
  * @u: ...unless v is equal to u.
  *
  * Atomically adds @a to @v, so long as it was not @u.
- * Returns the old value of @v.
+ * Returns non-zero if the add was done, zero otherwise.
  */
 static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u)
 {
 	unsigned low = (unsigned)u;
 	unsigned high = (unsigned)(u >> 32);
-	asm volatile(ATOMIC64_ALTERNATIVE(add_unless) "\n\t"
-		     : "+A" (a), "+c" (v), "+S" (low), "+D" (high)
-		     : : "memory");
+	alternative_atomic64(add_unless,
+			     ASM_OUTPUT2("+A" (a), "+c" (low), "+D" (high)),
+			     "S" (v) : "memory");
 	return (int)a;
 }
 
@@ -279,26 +297,20 @@
 static inline int atomic64_inc_not_zero(atomic64_t *v)
 {
 	int r;
-	asm volatile(ATOMIC64_ALTERNATIVE(inc_not_zero)
-		     : "=a" (r)
-		     : "S" (v)
-		     : "ecx", "edx", "memory"
-		     );
+	alternative_atomic64(inc_not_zero, "=&a" (r),
+			     "S" (v) : "ecx", "edx", "memory");
 	return r;
 }
 
 static inline long long atomic64_dec_if_positive(atomic64_t *v)
 {
 	long long r;
-	asm volatile(ATOMIC64_ALTERNATIVE(dec_if_positive)
-		     : "=A" (r)
-		     : "S" (v)
-		     : "ecx", "memory"
-		     );
+	alternative_atomic64(dec_if_positive, "=&A" (r),
+			     "S" (v) : "ecx", "memory");
 	return r;
 }
 
-#undef ATOMIC64_ALTERNATIVE
-#undef ATOMIC64_ALTERNATIVE_
+#undef alternative_atomic64
+#undef __alternative_atomic64
 
 #endif /* _ASM_X86_ATOMIC64_32_H */
diff --git a/arch/x86/include/asm/auxvec.h b/arch/x86/include/asm/auxvec.h
index 1316b4c..77203ac 100644
--- a/arch/x86/include/asm/auxvec.h
+++ b/arch/x86/include/asm/auxvec.h
@@ -9,4 +9,11 @@
 #endif
 #define AT_SYSINFO_EHDR		33
 
+/* entries in ARCH_DLINFO: */
+#if defined(CONFIG_IA32_EMULATION) || !defined(CONFIG_X86_64)
+# define AT_VECTOR_SIZE_ARCH 2
+#else /* else it's non-compat x86-64 */
+# define AT_VECTOR_SIZE_ARCH 1
+#endif
+
 #endif /* _ASM_X86_AUXVEC_H */
diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h
new file mode 100644
index 0000000..c6cd358
--- /dev/null
+++ b/arch/x86/include/asm/barrier.h
@@ -0,0 +1,116 @@
+#ifndef _ASM_X86_BARRIER_H
+#define _ASM_X86_BARRIER_H
+
+#include <asm/alternative.h>
+#include <asm/nops.h>
+
+/*
+ * Force strict CPU ordering.
+ * And yes, this is required on UP too when we're talking
+ * to devices.
+ */
+
+#ifdef CONFIG_X86_32
+/*
+ * Some non-Intel clones support out of order store. wmb() ceases to be a
+ * nop for these.
+ */
+#define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2)
+#define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2)
+#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM)
+#else
+#define mb() 	asm volatile("mfence":::"memory")
+#define rmb()	asm volatile("lfence":::"memory")
+#define wmb()	asm volatile("sfence" ::: "memory")
+#endif
+
+/**
+ * read_barrier_depends - Flush all pending reads that subsequents reads
+ * depend on.
+ *
+ * No data-dependent reads from memory-like regions are ever reordered
+ * over this barrier.  All reads preceding this primitive are guaranteed
+ * to access memory (but not necessarily other CPUs' caches) before any
+ * reads following this primitive that depend on the data return by
+ * any of the preceding reads.  This primitive is much lighter weight than
+ * rmb() on most CPUs, and is never heavier weight than is
+ * rmb().
+ *
+ * These ordering constraints are respected by both the local CPU
+ * and the compiler.
+ *
+ * Ordering is not guaranteed by anything other than these primitives,
+ * not even by data dependencies.  See the documentation for
+ * memory_barrier() for examples and URLs to more information.
+ *
+ * For example, the following code would force ordering (the initial
+ * value of "a" is zero, "b" is one, and "p" is "&a"):
+ *
+ * <programlisting>
+ *	CPU 0				CPU 1
+ *
+ *	b = 2;
+ *	memory_barrier();
+ *	p = &b;				q = p;
+ *					read_barrier_depends();
+ *					d = *q;
+ * </programlisting>
+ *
+ * because the read of "*q" depends on the read of "p" and these
+ * two reads are separated by a read_barrier_depends().  However,
+ * the following code, with the same initial values for "a" and "b":
+ *
+ * <programlisting>
+ *	CPU 0				CPU 1
+ *
+ *	a = 2;
+ *	memory_barrier();
+ *	b = 3;				y = b;
+ *					read_barrier_depends();
+ *					x = a;
+ * </programlisting>
+ *
+ * does not enforce ordering, since there is no data dependency between
+ * the read of "a" and the read of "b".  Therefore, on some CPUs, such
+ * as Alpha, "y" could be set to 3 and "x" to 0.  Use rmb()
+ * in cases like this where there are no data dependencies.
+ **/
+
+#define read_barrier_depends()	do { } while (0)
+
+#ifdef CONFIG_SMP
+#define smp_mb()	mb()
+#ifdef CONFIG_X86_PPRO_FENCE
+# define smp_rmb()	rmb()
+#else
+# define smp_rmb()	barrier()
+#endif
+#ifdef CONFIG_X86_OOSTORE
+# define smp_wmb() 	wmb()
+#else
+# define smp_wmb()	barrier()
+#endif
+#define smp_read_barrier_depends()	read_barrier_depends()
+#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
+#else
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+#define smp_read_barrier_depends()	do { } while (0)
+#define set_mb(var, value) do { var = value; barrier(); } while (0)
+#endif
+
+/*
+ * Stop RDTSC speculation. This is needed when you need to use RDTSC
+ * (or get_cycles or vread that possibly accesses the TSC) in a defined
+ * code region.
+ *
+ * (Could use an alternative three way for this if there was one.)
+ */
+static __always_inline void rdtsc_barrier(void)
+{
+	alternative(ASM_NOP3, "mfence", X86_FEATURE_MFENCE_RDTSC);
+	alternative(ASM_NOP3, "lfence", X86_FEATURE_LFENCE_RDTSC);
+}
+
+#endif /* _ASM_X86_BARRIER_H */
diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h
index f654d1b..11e1152 100644
--- a/arch/x86/include/asm/bug.h
+++ b/arch/x86/include/asm/bug.h
@@ -36,4 +36,8 @@
 #endif /* !CONFIG_BUG */
 
 #include <asm-generic/bug.h>
+
+
+extern void show_regs_common(void);
+
 #endif /* _ASM_X86_BUG_H */
diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h
index 4e12668..9863ee3 100644
--- a/arch/x86/include/asm/cacheflush.h
+++ b/arch/x86/include/asm/cacheflush.h
@@ -3,6 +3,7 @@
 
 /* Caches aren't brain-dead on the intel. */
 #include <asm-generic/cacheflush.h>
+#include <asm/special_insns.h>
 
 #ifdef CONFIG_X86_PAT
 /*
diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h
index 30d737e..d680579 100644
--- a/arch/x86/include/asm/compat.h
+++ b/arch/x86/include/asm/compat.h
@@ -6,7 +6,9 @@
  */
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <asm/processor.h>
 #include <asm/user32.h>
+#include <asm/unistd.h>
 
 #define COMPAT_USER_HZ		100
 #define COMPAT_UTS_MACHINE	"i686\0\0"
@@ -186,7 +188,20 @@
 /*
  * The type of struct elf_prstatus.pr_reg in compatible core dumps.
  */
+#ifdef CONFIG_X86_X32_ABI
+typedef struct user_regs_struct compat_elf_gregset_t;
+
+#define PR_REG_SIZE(S) (test_thread_flag(TIF_IA32) ? 68 : 216)
+#define PRSTATUS_SIZE(S) (test_thread_flag(TIF_IA32) ? 144 : 296)
+#define SET_PR_FPVALID(S,V) \
+  do { *(int *) (((void *) &((S)->pr_reg)) + PR_REG_SIZE(0)) = (V); } \
+  while (0)
+
+#define COMPAT_USE_64BIT_TIME \
+	(!!(task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT))
+#else
 typedef struct user_regs_struct32 compat_elf_gregset_t;
+#endif
 
 /*
  * A pointer passed in from user mode. This should not
@@ -208,13 +223,30 @@
 
 static inline void __user *arch_compat_alloc_user_space(long len)
 {
-	struct pt_regs *regs = task_pt_regs(current);
-	return (void __user *)regs->sp - len;
+	compat_uptr_t sp;
+
+	if (test_thread_flag(TIF_IA32)) {
+		sp = task_pt_regs(current)->sp;
+	} else {
+		/* -128 for the x32 ABI redzone */
+		sp = percpu_read(old_rsp) - 128;
+	}
+
+	return (void __user *)round_down(sp - len, 16);
 }
 
-static inline int is_compat_task(void)
+static inline bool is_x32_task(void)
 {
-	return current_thread_info()->status & TS_COMPAT;
+#ifdef CONFIG_X86_X32_ABI
+	if (task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT)
+		return true;
+#endif
+	return false;
+}
+
+static inline bool is_compat_task(void)
+{
+	return is_ia32_task() || is_x32_task();
 }
 
 #endif /* _ASM_X86_COMPAT_H */
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index dcb839e..340ee49 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -200,10 +200,13 @@
 /* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
 #define X86_FEATURE_FSGSBASE	(9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/
 #define X86_FEATURE_BMI1	(9*32+ 3) /* 1st group bit manipulation extensions */
+#define X86_FEATURE_HLE		(9*32+ 4) /* Hardware Lock Elision */
 #define X86_FEATURE_AVX2	(9*32+ 5) /* AVX2 instructions */
 #define X86_FEATURE_SMEP	(9*32+ 7) /* Supervisor Mode Execution Protection */
 #define X86_FEATURE_BMI2	(9*32+ 8) /* 2nd group bit manipulation extensions */
 #define X86_FEATURE_ERMS	(9*32+ 9) /* Enhanced REP MOVSB/STOSB */
+#define X86_FEATURE_INVPCID	(9*32+10) /* Invalidate Processor Context ID */
+#define X86_FEATURE_RTM		(9*32+11) /* Restricted Transactional Memory */
 
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
 
diff --git a/arch/x86/include/asm/debugreg.h b/arch/x86/include/asm/debugreg.h
index b903d5e..2d91580 100644
--- a/arch/x86/include/asm/debugreg.h
+++ b/arch/x86/include/asm/debugreg.h
@@ -78,8 +78,75 @@
  */
 #ifdef __KERNEL__
 
+#include <linux/bug.h>
+
 DECLARE_PER_CPU(unsigned long, cpu_dr7);
 
+#ifndef CONFIG_PARAVIRT
+/*
+ * These special macros can be used to get or set a debugging register
+ */
+#define get_debugreg(var, register)				\
+	(var) = native_get_debugreg(register)
+#define set_debugreg(value, register)				\
+	native_set_debugreg(register, value)
+#endif
+
+static inline unsigned long native_get_debugreg(int regno)
+{
+	unsigned long val = 0;	/* Damn you, gcc! */
+
+	switch (regno) {
+	case 0:
+		asm("mov %%db0, %0" :"=r" (val));
+		break;
+	case 1:
+		asm("mov %%db1, %0" :"=r" (val));
+		break;
+	case 2:
+		asm("mov %%db2, %0" :"=r" (val));
+		break;
+	case 3:
+		asm("mov %%db3, %0" :"=r" (val));
+		break;
+	case 6:
+		asm("mov %%db6, %0" :"=r" (val));
+		break;
+	case 7:
+		asm("mov %%db7, %0" :"=r" (val));
+		break;
+	default:
+		BUG();
+	}
+	return val;
+}
+
+static inline void native_set_debugreg(int regno, unsigned long value)
+{
+	switch (regno) {
+	case 0:
+		asm("mov %0, %%db0"	::"r" (value));
+		break;
+	case 1:
+		asm("mov %0, %%db1"	::"r" (value));
+		break;
+	case 2:
+		asm("mov %0, %%db2"	::"r" (value));
+		break;
+	case 3:
+		asm("mov %0, %%db3"	::"r" (value));
+		break;
+	case 6:
+		asm("mov %0, %%db6"	::"r" (value));
+		break;
+	case 7:
+		asm("mov %0, %%db7"	::"r" (value));
+		break;
+	default:
+		BUG();
+	}
+}
+
 static inline void hw_breakpoint_disable(void)
 {
 	/* Zero the control register for HW Breakpoint */
diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h
index ed3065f..4b4331d 100644
--- a/arch/x86/include/asm/dma-mapping.h
+++ b/arch/x86/include/asm/dma-mapping.h
@@ -59,7 +59,8 @@
 extern int dma_set_mask(struct device *dev, u64 mask);
 
 extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
-					dma_addr_t *dma_addr, gfp_t flag);
+					dma_addr_t *dma_addr, gfp_t flag,
+					struct dma_attrs *attrs);
 
 static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
 {
@@ -111,9 +112,11 @@
        return gfp;
 }
 
+#define dma_alloc_coherent(d,s,h,f)	dma_alloc_attrs(d,s,h,f,NULL)
+
 static inline void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-		gfp_t gfp)
+dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
+		gfp_t gfp, struct dma_attrs *attrs)
 {
 	struct dma_map_ops *ops = get_dma_ops(dev);
 	void *memory;
@@ -129,18 +132,21 @@
 	if (!is_device_dma_capable(dev))
 		return NULL;
 
-	if (!ops->alloc_coherent)
+	if (!ops->alloc)
 		return NULL;
 
-	memory = ops->alloc_coherent(dev, size, dma_handle,
-				     dma_alloc_coherent_gfp_flags(dev, gfp));
+	memory = ops->alloc(dev, size, dma_handle,
+			    dma_alloc_coherent_gfp_flags(dev, gfp), attrs);
 	debug_dma_alloc_coherent(dev, size, *dma_handle, memory);
 
 	return memory;
 }
 
-static inline void dma_free_coherent(struct device *dev, size_t size,
-				     void *vaddr, dma_addr_t bus)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+				  void *vaddr, dma_addr_t bus,
+				  struct dma_attrs *attrs)
 {
 	struct dma_map_ops *ops = get_dma_ops(dev);
 
@@ -150,8 +156,8 @@
 		return;
 
 	debug_dma_free_coherent(dev, size, vaddr, bus);
-	if (ops->free_coherent)
-		ops->free_coherent(dev, size, vaddr, bus);
+	if (ops->free)
+		ops->free(dev, size, vaddr, bus, attrs);
 }
 
 #endif
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 844f735..c9dcc18 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -95,7 +95,7 @@
 
 extern int add_efi_memmap;
 extern void efi_set_executable(efi_memory_desc_t *md, bool executable);
-extern void efi_memblock_x86_reserve_range(void);
+extern int efi_memblock_x86_reserve_range(void);
 extern void efi_call_phys_prelog(void);
 extern void efi_call_phys_epilog(void);
 
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index 5f962df..5939f44 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -84,7 +84,6 @@
 	(((x)->e_machine == EM_386) || ((x)->e_machine == EM_486))
 
 #include <asm/processor.h>
-#include <asm/system.h>
 
 #ifdef CONFIG_X86_32
 #include <asm/desc.h>
@@ -156,7 +155,12 @@
 #define elf_check_arch(x)			\
 	((x)->e_machine == EM_X86_64)
 
-#define compat_elf_check_arch(x)	elf_check_arch_ia32(x)
+#define compat_elf_check_arch(x)		\
+	(elf_check_arch_ia32(x) || (x)->e_machine == EM_X86_64)
+
+#if __USER32_DS != __USER_DS
+# error "The following code assumes __USER32_DS == __USER_DS"
+#endif
 
 static inline void elf_common_init(struct thread_struct *t,
 				   struct pt_regs *regs, const u16 ds)
@@ -179,8 +183,9 @@
 void start_thread_ia32(struct pt_regs *regs, u32 new_ip, u32 new_sp);
 #define compat_start_thread start_thread_ia32
 
-void set_personality_ia32(void);
-#define COMPAT_SET_PERSONALITY(ex) set_personality_ia32()
+void set_personality_ia32(bool);
+#define COMPAT_SET_PERSONALITY(ex)			\
+	set_personality_ia32((ex).e_machine == EM_X86_64)
 
 #define COMPAT_ELF_PLATFORM			("i686")
 
@@ -287,7 +292,7 @@
 #define VDSO_HIGH_BASE		0xffffe000U /* CONFIG_COMPAT_VDSO address */
 
 /* 1GB for 64bit, 8MB for 32bit */
-#define STACK_RND_MASK (test_thread_flag(TIF_IA32) ? 0x7ff : 0x3fffff)
+#define STACK_RND_MASK (test_thread_flag(TIF_ADDR32) ? 0x7ff : 0x3fffff)
 
 #define ARCH_DLINFO							\
 do {									\
@@ -296,9 +301,20 @@
 			    (unsigned long)current->mm->context.vdso);	\
 } while (0)
 
+#define ARCH_DLINFO_X32							\
+do {									\
+	if (vdso_enabled)						\
+		NEW_AUX_ENT(AT_SYSINFO_EHDR,				\
+			    (unsigned long)current->mm->context.vdso);	\
+} while (0)
+
 #define AT_SYSINFO		32
 
-#define COMPAT_ARCH_DLINFO	ARCH_DLINFO_IA32(sysctl_vsyscall32)
+#define COMPAT_ARCH_DLINFO						\
+if (test_thread_flag(TIF_X32))						\
+	ARCH_DLINFO_X32;						\
+else									\
+	ARCH_DLINFO_IA32(sysctl_vsyscall32)
 
 #define COMPAT_ELF_ET_DYN_BASE	(TASK_UNMAPPED_BASE + 0x1000000)
 
@@ -314,6 +330,8 @@
 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
 extern int arch_setup_additional_pages(struct linux_binprm *bprm,
 				       int uses_interp);
+extern int x32_setup_additional_pages(struct linux_binprm *bprm,
+				      int uses_interp);
 
 extern int syscall32_setup_pages(struct linux_binprm *, int exstack);
 #define compat_arch_setup_additional_pages	syscall32_setup_pages
@@ -330,7 +348,7 @@
 	return 1;
 #endif
 #ifdef CONFIG_IA32_EMULATION
-	if (test_thread_flag(TIF_IA32))
+	if (test_thread_flag(TIF_ADDR32))
 		return 1;
 #endif
 	return 0;
diff --git a/arch/x86/include/asm/exec.h b/arch/x86/include/asm/exec.h
new file mode 100644
index 0000000..54c2e1d
--- /dev/null
+++ b/arch/x86/include/asm/exec.h
@@ -0,0 +1 @@
+/* define arch_align_stack() here */
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h
new file mode 100644
index 0000000..4fa8815
--- /dev/null
+++ b/arch/x86/include/asm/fpu-internal.h
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 1994 Linus Torvalds
+ *
+ * Pentium III FXSR, SSE support
+ * General FPU state handling cleanups
+ *	Gareth Hughes <gareth@valinux.com>, May 2000
+ * x86-64 work by Andi Kleen 2002
+ */
+
+#ifndef _FPU_INTERNAL_H
+#define _FPU_INTERNAL_H
+
+#include <linux/kernel_stat.h>
+#include <linux/regset.h>
+#include <linux/slab.h>
+#include <asm/asm.h>
+#include <asm/cpufeature.h>
+#include <asm/processor.h>
+#include <asm/sigcontext.h>
+#include <asm/user.h>
+#include <asm/uaccess.h>
+#include <asm/xsave.h>
+
+extern unsigned int sig_xstate_size;
+extern void fpu_init(void);
+
+DECLARE_PER_CPU(struct task_struct *, fpu_owner_task);
+
+extern user_regset_active_fn fpregs_active, xfpregs_active;
+extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get,
+				xstateregs_get;
+extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
+				 xstateregs_set;
+
+
+/*
+ * xstateregs_active == fpregs_active. Please refer to the comment
+ * at the definition of fpregs_active.
+ */
+#define xstateregs_active	fpregs_active
+
+extern struct _fpx_sw_bytes fx_sw_reserved;
+#ifdef CONFIG_IA32_EMULATION
+extern unsigned int sig_xstate_ia32_size;
+extern struct _fpx_sw_bytes fx_sw_reserved_ia32;
+struct _fpstate_ia32;
+struct _xstate_ia32;
+extern int save_i387_xstate_ia32(void __user *buf);
+extern int restore_i387_xstate_ia32(void __user *buf);
+#endif
+
+#ifdef CONFIG_MATH_EMULATION
+extern void finit_soft_fpu(struct i387_soft_struct *soft);
+#else
+static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
+#endif
+
+#define X87_FSW_ES (1 << 7)	/* Exception Summary */
+
+static __always_inline __pure bool use_xsaveopt(void)
+{
+	return static_cpu_has(X86_FEATURE_XSAVEOPT);
+}
+
+static __always_inline __pure bool use_xsave(void)
+{
+	return static_cpu_has(X86_FEATURE_XSAVE);
+}
+
+static __always_inline __pure bool use_fxsr(void)
+{
+        return static_cpu_has(X86_FEATURE_FXSR);
+}
+
+extern void __sanitize_i387_state(struct task_struct *);
+
+static inline void sanitize_i387_state(struct task_struct *tsk)
+{
+	if (!use_xsaveopt())
+		return;
+	__sanitize_i387_state(tsk);
+}
+
+#ifdef CONFIG_X86_64
+static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
+{
+	int err;
+
+	/* See comment in fxsave() below. */
+#ifdef CONFIG_AS_FXSAVEQ
+	asm volatile("1:  fxrstorq %[fx]\n\t"
+		     "2:\n"
+		     ".section .fixup,\"ax\"\n"
+		     "3:  movl $-1,%[err]\n"
+		     "    jmp  2b\n"
+		     ".previous\n"
+		     _ASM_EXTABLE(1b, 3b)
+		     : [err] "=r" (err)
+		     : [fx] "m" (*fx), "0" (0));
+#else
+	asm volatile("1:  rex64/fxrstor (%[fx])\n\t"
+		     "2:\n"
+		     ".section .fixup,\"ax\"\n"
+		     "3:  movl $-1,%[err]\n"
+		     "    jmp  2b\n"
+		     ".previous\n"
+		     _ASM_EXTABLE(1b, 3b)
+		     : [err] "=r" (err)
+		     : [fx] "R" (fx), "m" (*fx), "0" (0));
+#endif
+	return err;
+}
+
+static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
+{
+	int err;
+
+	/*
+	 * Clear the bytes not touched by the fxsave and reserved
+	 * for the SW usage.
+	 */
+	err = __clear_user(&fx->sw_reserved,
+			   sizeof(struct _fpx_sw_bytes));
+	if (unlikely(err))
+		return -EFAULT;
+
+	/* See comment in fxsave() below. */
+#ifdef CONFIG_AS_FXSAVEQ
+	asm volatile("1:  fxsaveq %[fx]\n\t"
+		     "2:\n"
+		     ".section .fixup,\"ax\"\n"
+		     "3:  movl $-1,%[err]\n"
+		     "    jmp  2b\n"
+		     ".previous\n"
+		     _ASM_EXTABLE(1b, 3b)
+		     : [err] "=r" (err), [fx] "=m" (*fx)
+		     : "0" (0));
+#else
+	asm volatile("1:  rex64/fxsave (%[fx])\n\t"
+		     "2:\n"
+		     ".section .fixup,\"ax\"\n"
+		     "3:  movl $-1,%[err]\n"
+		     "    jmp  2b\n"
+		     ".previous\n"
+		     _ASM_EXTABLE(1b, 3b)
+		     : [err] "=r" (err), "=m" (*fx)
+		     : [fx] "R" (fx), "0" (0));
+#endif
+	if (unlikely(err) &&
+	    __clear_user(fx, sizeof(struct i387_fxsave_struct)))
+		err = -EFAULT;
+	/* No need to clear here because the caller clears USED_MATH */
+	return err;
+}
+
+static inline void fpu_fxsave(struct fpu *fpu)
+{
+	/* Using "rex64; fxsave %0" is broken because, if the memory operand
+	   uses any extended registers for addressing, a second REX prefix
+	   will be generated (to the assembler, rex64 followed by semicolon
+	   is a separate instruction), and hence the 64-bitness is lost. */
+
+#ifdef CONFIG_AS_FXSAVEQ
+	/* Using "fxsaveq %0" would be the ideal choice, but is only supported
+	   starting with gas 2.16. */
+	__asm__ __volatile__("fxsaveq %0"
+			     : "=m" (fpu->state->fxsave));
+#else
+	/* Using, as a workaround, the properly prefixed form below isn't
+	   accepted by any binutils version so far released, complaining that
+	   the same type of prefix is used twice if an extended register is
+	   needed for addressing (fix submitted to mainline 2005-11-21).
+	asm volatile("rex64/fxsave %0"
+		     : "=m" (fpu->state->fxsave));
+	   This, however, we can work around by forcing the compiler to select
+	   an addressing mode that doesn't require extended registers. */
+	asm volatile("rex64/fxsave (%[fx])"
+		     : "=m" (fpu->state->fxsave)
+		     : [fx] "R" (&fpu->state->fxsave));
+#endif
+}
+
+#else  /* CONFIG_X86_32 */
+
+/* perform fxrstor iff the processor has extended states, otherwise frstor */
+static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
+{
+	/*
+	 * The "nop" is needed to make the instructions the same
+	 * length.
+	 */
+	alternative_input(
+		"nop ; frstor %1",
+		"fxrstor %1",
+		X86_FEATURE_FXSR,
+		"m" (*fx));
+
+	return 0;
+}
+
+static inline void fpu_fxsave(struct fpu *fpu)
+{
+	asm volatile("fxsave %[fx]"
+		     : [fx] "=m" (fpu->state->fxsave));
+}
+
+#endif	/* CONFIG_X86_64 */
+
+/*
+ * These must be called with preempt disabled. Returns
+ * 'true' if the FPU state is still intact.
+ */
+static inline int fpu_save_init(struct fpu *fpu)
+{
+	if (use_xsave()) {
+		fpu_xsave(fpu);
+
+		/*
+		 * xsave header may indicate the init state of the FP.
+		 */
+		if (!(fpu->state->xsave.xsave_hdr.xstate_bv & XSTATE_FP))
+			return 1;
+	} else if (use_fxsr()) {
+		fpu_fxsave(fpu);
+	} else {
+		asm volatile("fnsave %[fx]; fwait"
+			     : [fx] "=m" (fpu->state->fsave));
+		return 0;
+	}
+
+	/*
+	 * If exceptions are pending, we need to clear them so
+	 * that we don't randomly get exceptions later.
+	 *
+	 * FIXME! Is this perhaps only true for the old-style
+	 * irq13 case? Maybe we could leave the x87 state
+	 * intact otherwise?
+	 */
+	if (unlikely(fpu->state->fxsave.swd & X87_FSW_ES)) {
+		asm volatile("fnclex");
+		return 0;
+	}
+	return 1;
+}
+
+static inline int __save_init_fpu(struct task_struct *tsk)
+{
+	return fpu_save_init(&tsk->thread.fpu);
+}
+
+static inline int fpu_fxrstor_checking(struct fpu *fpu)
+{
+	return fxrstor_checking(&fpu->state->fxsave);
+}
+
+static inline int fpu_restore_checking(struct fpu *fpu)
+{
+	if (use_xsave())
+		return fpu_xrstor_checking(fpu);
+	else
+		return fpu_fxrstor_checking(fpu);
+}
+
+static inline int restore_fpu_checking(struct task_struct *tsk)
+{
+	/* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
+	   is pending.  Clear the x87 state here by setting it to fixed
+	   values. "m" is a random variable that should be in L1 */
+	alternative_input(
+		ASM_NOP8 ASM_NOP2,
+		"emms\n\t"		/* clear stack tags */
+		"fildl %P[addr]",	/* set F?P to defined value */
+		X86_FEATURE_FXSAVE_LEAK,
+		[addr] "m" (tsk->thread.fpu.has_fpu));
+
+	return fpu_restore_checking(&tsk->thread.fpu);
+}
+
+/*
+ * Software FPU state helpers. Careful: these need to
+ * be preemption protection *and* they need to be
+ * properly paired with the CR0.TS changes!
+ */
+static inline int __thread_has_fpu(struct task_struct *tsk)
+{
+	return tsk->thread.fpu.has_fpu;
+}
+
+/* Must be paired with an 'stts' after! */
+static inline void __thread_clear_has_fpu(struct task_struct *tsk)
+{
+	tsk->thread.fpu.has_fpu = 0;
+	percpu_write(fpu_owner_task, NULL);
+}
+
+/* Must be paired with a 'clts' before! */
+static inline void __thread_set_has_fpu(struct task_struct *tsk)
+{
+	tsk->thread.fpu.has_fpu = 1;
+	percpu_write(fpu_owner_task, tsk);
+}
+
+/*
+ * Encapsulate the CR0.TS handling together with the
+ * software flag.
+ *
+ * These generally need preemption protection to work,
+ * do try to avoid using these on their own.
+ */
+static inline void __thread_fpu_end(struct task_struct *tsk)
+{
+	__thread_clear_has_fpu(tsk);
+	stts();
+}
+
+static inline void __thread_fpu_begin(struct task_struct *tsk)
+{
+	clts();
+	__thread_set_has_fpu(tsk);
+}
+
+/*
+ * FPU state switching for scheduling.
+ *
+ * This is a two-stage process:
+ *
+ *  - switch_fpu_prepare() saves the old state and
+ *    sets the new state of the CR0.TS bit. This is
+ *    done within the context of the old process.
+ *
+ *  - switch_fpu_finish() restores the new state as
+ *    necessary.
+ */
+typedef struct { int preload; } fpu_switch_t;
+
+/*
+ * FIXME! We could do a totally lazy restore, but we need to
+ * add a per-cpu "this was the task that last touched the FPU
+ * on this CPU" variable, and the task needs to have a "I last
+ * touched the FPU on this CPU" and check them.
+ *
+ * We don't do that yet, so "fpu_lazy_restore()" always returns
+ * false, but some day..
+ */
+static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu)
+{
+	return new == percpu_read_stable(fpu_owner_task) &&
+		cpu == new->thread.fpu.last_cpu;
+}
+
+static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct task_struct *new, int cpu)
+{
+	fpu_switch_t fpu;
+
+	fpu.preload = tsk_used_math(new) && new->fpu_counter > 5;
+	if (__thread_has_fpu(old)) {
+		if (!__save_init_fpu(old))
+			cpu = ~0;
+		old->thread.fpu.last_cpu = cpu;
+		old->thread.fpu.has_fpu = 0;	/* But leave fpu_owner_task! */
+
+		/* Don't change CR0.TS if we just switch! */
+		if (fpu.preload) {
+			new->fpu_counter++;
+			__thread_set_has_fpu(new);
+			prefetch(new->thread.fpu.state);
+		} else
+			stts();
+	} else {
+		old->fpu_counter = 0;
+		old->thread.fpu.last_cpu = ~0;
+		if (fpu.preload) {
+			new->fpu_counter++;
+			if (fpu_lazy_restore(new, cpu))
+				fpu.preload = 0;
+			else
+				prefetch(new->thread.fpu.state);
+			__thread_fpu_begin(new);
+		}
+	}
+	return fpu;
+}
+
+/*
+ * By the time this gets called, we've already cleared CR0.TS and
+ * given the process the FPU if we are going to preload the FPU
+ * state - all we need to do is to conditionally restore the register
+ * state itself.
+ */
+static inline void switch_fpu_finish(struct task_struct *new, fpu_switch_t fpu)
+{
+	if (fpu.preload) {
+		if (unlikely(restore_fpu_checking(new)))
+			__thread_fpu_end(new);
+	}
+}
+
+/*
+ * Signal frame handlers...
+ */
+extern int save_i387_xstate(void __user *buf);
+extern int restore_i387_xstate(void __user *buf);
+
+static inline void __clear_fpu(struct task_struct *tsk)
+{
+	if (__thread_has_fpu(tsk)) {
+		/* Ignore delayed exceptions from user space */
+		asm volatile("1: fwait\n"
+			     "2:\n"
+			     _ASM_EXTABLE(1b, 2b));
+		__thread_fpu_end(tsk);
+	}
+}
+
+/*
+ * The actual user_fpu_begin/end() functions
+ * need to be preemption-safe.
+ *
+ * NOTE! user_fpu_end() must be used only after you
+ * have saved the FP state, and user_fpu_begin() must
+ * be used only immediately before restoring it.
+ * These functions do not do any save/restore on
+ * their own.
+ */
+static inline void user_fpu_end(void)
+{
+	preempt_disable();
+	__thread_fpu_end(current);
+	preempt_enable();
+}
+
+static inline void user_fpu_begin(void)
+{
+	preempt_disable();
+	if (!user_has_fpu())
+		__thread_fpu_begin(current);
+	preempt_enable();
+}
+
+/*
+ * These disable preemption on their own and are safe
+ */
+static inline void save_init_fpu(struct task_struct *tsk)
+{
+	WARN_ON_ONCE(!__thread_has_fpu(tsk));
+	preempt_disable();
+	__save_init_fpu(tsk);
+	__thread_fpu_end(tsk);
+	preempt_enable();
+}
+
+static inline void clear_fpu(struct task_struct *tsk)
+{
+	preempt_disable();
+	__clear_fpu(tsk);
+	preempt_enable();
+}
+
+/*
+ * i387 state interaction
+ */
+static inline unsigned short get_fpu_cwd(struct task_struct *tsk)
+{
+	if (cpu_has_fxsr) {
+		return tsk->thread.fpu.state->fxsave.cwd;
+	} else {
+		return (unsigned short)tsk->thread.fpu.state->fsave.cwd;
+	}
+}
+
+static inline unsigned short get_fpu_swd(struct task_struct *tsk)
+{
+	if (cpu_has_fxsr) {
+		return tsk->thread.fpu.state->fxsave.swd;
+	} else {
+		return (unsigned short)tsk->thread.fpu.state->fsave.swd;
+	}
+}
+
+static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk)
+{
+	if (cpu_has_xmm) {
+		return tsk->thread.fpu.state->fxsave.mxcsr;
+	} else {
+		return MXCSR_DEFAULT;
+	}
+}
+
+static bool fpu_allocated(struct fpu *fpu)
+{
+	return fpu->state != NULL;
+}
+
+static inline int fpu_alloc(struct fpu *fpu)
+{
+	if (fpu_allocated(fpu))
+		return 0;
+	fpu->state = kmem_cache_alloc(task_xstate_cachep, GFP_KERNEL);
+	if (!fpu->state)
+		return -ENOMEM;
+	WARN_ON((unsigned long)fpu->state & 15);
+	return 0;
+}
+
+static inline void fpu_free(struct fpu *fpu)
+{
+	if (fpu->state) {
+		kmem_cache_free(task_xstate_cachep, fpu->state);
+		fpu->state = NULL;
+	}
+}
+
+static inline void fpu_copy(struct fpu *dst, struct fpu *src)
+{
+	memcpy(dst->state, src->state, xstate_size);
+}
+
+extern void fpu_finit(struct fpu *fpu);
+
+#endif
diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
index d09bb03..71ecbcb 100644
--- a/arch/x86/include/asm/futex.h
+++ b/arch/x86/include/asm/futex.h
@@ -9,7 +9,6 @@
 #include <asm/asm.h>
 #include <asm/errno.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 
 #define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg)	\
 	asm volatile("1:\t" insn "\n"				\
diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h
index 2479049..257d9cc 100644
--- a/arch/x86/include/asm/i387.h
+++ b/arch/x86/include/asm/i387.h
@@ -13,476 +13,18 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/regset.h>
 #include <linux/hardirq.h>
-#include <linux/slab.h>
-#include <asm/asm.h>
-#include <asm/cpufeature.h>
-#include <asm/processor.h>
-#include <asm/sigcontext.h>
-#include <asm/user.h>
-#include <asm/uaccess.h>
-#include <asm/xsave.h>
 
-extern unsigned int sig_xstate_size;
-extern void fpu_init(void);
-extern void mxcsr_feature_mask_init(void);
+struct pt_regs;
+struct user_i387_struct;
+
 extern int init_fpu(struct task_struct *child);
-extern void math_state_restore(void);
 extern int dump_fpu(struct pt_regs *, struct user_i387_struct *);
+extern void math_state_restore(void);
 
-DECLARE_PER_CPU(struct task_struct *, fpu_owner_task);
-
-extern user_regset_active_fn fpregs_active, xfpregs_active;
-extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get,
-				xstateregs_get;
-extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
-				 xstateregs_set;
-
-/*
- * xstateregs_active == fpregs_active. Please refer to the comment
- * at the definition of fpregs_active.
- */
-#define xstateregs_active	fpregs_active
-
-extern struct _fpx_sw_bytes fx_sw_reserved;
-#ifdef CONFIG_IA32_EMULATION
-extern unsigned int sig_xstate_ia32_size;
-extern struct _fpx_sw_bytes fx_sw_reserved_ia32;
-struct _fpstate_ia32;
-struct _xstate_ia32;
-extern int save_i387_xstate_ia32(void __user *buf);
-extern int restore_i387_xstate_ia32(void __user *buf);
-#endif
-
-#ifdef CONFIG_MATH_EMULATION
-extern void finit_soft_fpu(struct i387_soft_struct *soft);
-#else
-static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
-#endif
-
-#define X87_FSW_ES (1 << 7)	/* Exception Summary */
-
-static __always_inline __pure bool use_xsaveopt(void)
-{
-	return static_cpu_has(X86_FEATURE_XSAVEOPT);
-}
-
-static __always_inline __pure bool use_xsave(void)
-{
-	return static_cpu_has(X86_FEATURE_XSAVE);
-}
-
-static __always_inline __pure bool use_fxsr(void)
-{
-        return static_cpu_has(X86_FEATURE_FXSR);
-}
-
-extern void __sanitize_i387_state(struct task_struct *);
-
-static inline void sanitize_i387_state(struct task_struct *tsk)
-{
-	if (!use_xsaveopt())
-		return;
-	__sanitize_i387_state(tsk);
-}
-
-#ifdef CONFIG_X86_64
-static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
-{
-	int err;
-
-	/* See comment in fxsave() below. */
-#ifdef CONFIG_AS_FXSAVEQ
-	asm volatile("1:  fxrstorq %[fx]\n\t"
-		     "2:\n"
-		     ".section .fixup,\"ax\"\n"
-		     "3:  movl $-1,%[err]\n"
-		     "    jmp  2b\n"
-		     ".previous\n"
-		     _ASM_EXTABLE(1b, 3b)
-		     : [err] "=r" (err)
-		     : [fx] "m" (*fx), "0" (0));
-#else
-	asm volatile("1:  rex64/fxrstor (%[fx])\n\t"
-		     "2:\n"
-		     ".section .fixup,\"ax\"\n"
-		     "3:  movl $-1,%[err]\n"
-		     "    jmp  2b\n"
-		     ".previous\n"
-		     _ASM_EXTABLE(1b, 3b)
-		     : [err] "=r" (err)
-		     : [fx] "R" (fx), "m" (*fx), "0" (0));
-#endif
-	return err;
-}
-
-static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
-{
-	int err;
-
-	/*
-	 * Clear the bytes not touched by the fxsave and reserved
-	 * for the SW usage.
-	 */
-	err = __clear_user(&fx->sw_reserved,
-			   sizeof(struct _fpx_sw_bytes));
-	if (unlikely(err))
-		return -EFAULT;
-
-	/* See comment in fxsave() below. */
-#ifdef CONFIG_AS_FXSAVEQ
-	asm volatile("1:  fxsaveq %[fx]\n\t"
-		     "2:\n"
-		     ".section .fixup,\"ax\"\n"
-		     "3:  movl $-1,%[err]\n"
-		     "    jmp  2b\n"
-		     ".previous\n"
-		     _ASM_EXTABLE(1b, 3b)
-		     : [err] "=r" (err), [fx] "=m" (*fx)
-		     : "0" (0));
-#else
-	asm volatile("1:  rex64/fxsave (%[fx])\n\t"
-		     "2:\n"
-		     ".section .fixup,\"ax\"\n"
-		     "3:  movl $-1,%[err]\n"
-		     "    jmp  2b\n"
-		     ".previous\n"
-		     _ASM_EXTABLE(1b, 3b)
-		     : [err] "=r" (err), "=m" (*fx)
-		     : [fx] "R" (fx), "0" (0));
-#endif
-	if (unlikely(err) &&
-	    __clear_user(fx, sizeof(struct i387_fxsave_struct)))
-		err = -EFAULT;
-	/* No need to clear here because the caller clears USED_MATH */
-	return err;
-}
-
-static inline void fpu_fxsave(struct fpu *fpu)
-{
-	/* Using "rex64; fxsave %0" is broken because, if the memory operand
-	   uses any extended registers for addressing, a second REX prefix
-	   will be generated (to the assembler, rex64 followed by semicolon
-	   is a separate instruction), and hence the 64-bitness is lost. */
-
-#ifdef CONFIG_AS_FXSAVEQ
-	/* Using "fxsaveq %0" would be the ideal choice, but is only supported
-	   starting with gas 2.16. */
-	__asm__ __volatile__("fxsaveq %0"
-			     : "=m" (fpu->state->fxsave));
-#else
-	/* Using, as a workaround, the properly prefixed form below isn't
-	   accepted by any binutils version so far released, complaining that
-	   the same type of prefix is used twice if an extended register is
-	   needed for addressing (fix submitted to mainline 2005-11-21).
-	asm volatile("rex64/fxsave %0"
-		     : "=m" (fpu->state->fxsave));
-	   This, however, we can work around by forcing the compiler to select
-	   an addressing mode that doesn't require extended registers. */
-	asm volatile("rex64/fxsave (%[fx])"
-		     : "=m" (fpu->state->fxsave)
-		     : [fx] "R" (&fpu->state->fxsave));
-#endif
-}
-
-#else  /* CONFIG_X86_32 */
-
-/* perform fxrstor iff the processor has extended states, otherwise frstor */
-static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
-{
-	/*
-	 * The "nop" is needed to make the instructions the same
-	 * length.
-	 */
-	alternative_input(
-		"nop ; frstor %1",
-		"fxrstor %1",
-		X86_FEATURE_FXSR,
-		"m" (*fx));
-
-	return 0;
-}
-
-static inline void fpu_fxsave(struct fpu *fpu)
-{
-	asm volatile("fxsave %[fx]"
-		     : [fx] "=m" (fpu->state->fxsave));
-}
-
-#endif	/* CONFIG_X86_64 */
-
-/*
- * These must be called with preempt disabled. Returns
- * 'true' if the FPU state is still intact.
- */
-static inline int fpu_save_init(struct fpu *fpu)
-{
-	if (use_xsave()) {
-		fpu_xsave(fpu);
-
-		/*
-		 * xsave header may indicate the init state of the FP.
-		 */
-		if (!(fpu->state->xsave.xsave_hdr.xstate_bv & XSTATE_FP))
-			return 1;
-	} else if (use_fxsr()) {
-		fpu_fxsave(fpu);
-	} else {
-		asm volatile("fnsave %[fx]; fwait"
-			     : [fx] "=m" (fpu->state->fsave));
-		return 0;
-	}
-
-	/*
-	 * If exceptions are pending, we need to clear them so
-	 * that we don't randomly get exceptions later.
-	 *
-	 * FIXME! Is this perhaps only true for the old-style
-	 * irq13 case? Maybe we could leave the x87 state
-	 * intact otherwise?
-	 */
-	if (unlikely(fpu->state->fxsave.swd & X87_FSW_ES)) {
-		asm volatile("fnclex");
-		return 0;
-	}
-	return 1;
-}
-
-static inline int __save_init_fpu(struct task_struct *tsk)
-{
-	return fpu_save_init(&tsk->thread.fpu);
-}
-
-static inline int fpu_fxrstor_checking(struct fpu *fpu)
-{
-	return fxrstor_checking(&fpu->state->fxsave);
-}
-
-static inline int fpu_restore_checking(struct fpu *fpu)
-{
-	if (use_xsave())
-		return fpu_xrstor_checking(fpu);
-	else
-		return fpu_fxrstor_checking(fpu);
-}
-
-static inline int restore_fpu_checking(struct task_struct *tsk)
-{
-	/* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
-	   is pending.  Clear the x87 state here by setting it to fixed
-	   values. "m" is a random variable that should be in L1 */
-	alternative_input(
-		ASM_NOP8 ASM_NOP2,
-		"emms\n\t"	  	/* clear stack tags */
-		"fildl %P[addr]",	/* set F?P to defined value */
-		X86_FEATURE_FXSAVE_LEAK,
-		[addr] "m" (tsk->thread.fpu.has_fpu));
-
-	return fpu_restore_checking(&tsk->thread.fpu);
-}
-
-/*
- * Software FPU state helpers. Careful: these need to
- * be preemption protection *and* they need to be
- * properly paired with the CR0.TS changes!
- */
-static inline int __thread_has_fpu(struct task_struct *tsk)
-{
-	return tsk->thread.fpu.has_fpu;
-}
-
-/* Must be paired with an 'stts' after! */
-static inline void __thread_clear_has_fpu(struct task_struct *tsk)
-{
-	tsk->thread.fpu.has_fpu = 0;
-	percpu_write(fpu_owner_task, NULL);
-}
-
-/* Must be paired with a 'clts' before! */
-static inline void __thread_set_has_fpu(struct task_struct *tsk)
-{
-	tsk->thread.fpu.has_fpu = 1;
-	percpu_write(fpu_owner_task, tsk);
-}
-
-/*
- * Encapsulate the CR0.TS handling together with the
- * software flag.
- *
- * These generally need preemption protection to work,
- * do try to avoid using these on their own.
- */
-static inline void __thread_fpu_end(struct task_struct *tsk)
-{
-	__thread_clear_has_fpu(tsk);
-	stts();
-}
-
-static inline void __thread_fpu_begin(struct task_struct *tsk)
-{
-	clts();
-	__thread_set_has_fpu(tsk);
-}
-
-/*
- * FPU state switching for scheduling.
- *
- * This is a two-stage process:
- *
- *  - switch_fpu_prepare() saves the old state and
- *    sets the new state of the CR0.TS bit. This is
- *    done within the context of the old process.
- *
- *  - switch_fpu_finish() restores the new state as
- *    necessary.
- */
-typedef struct { int preload; } fpu_switch_t;
-
-/*
- * FIXME! We could do a totally lazy restore, but we need to
- * add a per-cpu "this was the task that last touched the FPU
- * on this CPU" variable, and the task needs to have a "I last
- * touched the FPU on this CPU" and check them.
- *
- * We don't do that yet, so "fpu_lazy_restore()" always returns
- * false, but some day..
- */
-static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu)
-{
-	return new == percpu_read_stable(fpu_owner_task) &&
-		cpu == new->thread.fpu.last_cpu;
-}
-
-static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct task_struct *new, int cpu)
-{
-	fpu_switch_t fpu;
-
-	fpu.preload = tsk_used_math(new) && new->fpu_counter > 5;
-	if (__thread_has_fpu(old)) {
-		if (!__save_init_fpu(old))
-			cpu = ~0;
-		old->thread.fpu.last_cpu = cpu;
-		old->thread.fpu.has_fpu = 0;	/* But leave fpu_owner_task! */
-
-		/* Don't change CR0.TS if we just switch! */
-		if (fpu.preload) {
-			new->fpu_counter++;
-			__thread_set_has_fpu(new);
-			prefetch(new->thread.fpu.state);
-		} else
-			stts();
-	} else {
-		old->fpu_counter = 0;
-		old->thread.fpu.last_cpu = ~0;
-		if (fpu.preload) {
-			new->fpu_counter++;
-			if (fpu_lazy_restore(new, cpu))
-				fpu.preload = 0;
-			else
-				prefetch(new->thread.fpu.state);
-			__thread_fpu_begin(new);
-		}
-	}
-	return fpu;
-}
-
-/*
- * By the time this gets called, we've already cleared CR0.TS and
- * given the process the FPU if we are going to preload the FPU
- * state - all we need to do is to conditionally restore the register
- * state itself.
- */
-static inline void switch_fpu_finish(struct task_struct *new, fpu_switch_t fpu)
-{
-	if (fpu.preload) {
-		if (unlikely(restore_fpu_checking(new)))
-			__thread_fpu_end(new);
-	}
-}
-
-/*
- * Signal frame handlers...
- */
-extern int save_i387_xstate(void __user *buf);
-extern int restore_i387_xstate(void __user *buf);
-
-static inline void __clear_fpu(struct task_struct *tsk)
-{
-	if (__thread_has_fpu(tsk)) {
-		/* Ignore delayed exceptions from user space */
-		asm volatile("1: fwait\n"
-			     "2:\n"
-			     _ASM_EXTABLE(1b, 2b));
-		__thread_fpu_end(tsk);
-	}
-}
-
-/*
- * Were we in an interrupt that interrupted kernel mode?
- *
- * We can do a kernel_fpu_begin/end() pair *ONLY* if that
- * pair does nothing at all: the thread must not have fpu (so
- * that we don't try to save the FPU state), and TS must
- * be set (so that the clts/stts pair does nothing that is
- * visible in the interrupted kernel thread).
- */
-static inline bool interrupted_kernel_fpu_idle(void)
-{
-	return !__thread_has_fpu(current) &&
-		(read_cr0() & X86_CR0_TS);
-}
-
-/*
- * Were we in user mode (or vm86 mode) when we were
- * interrupted?
- *
- * Doing kernel_fpu_begin/end() is ok if we are running
- * in an interrupt context from user mode - we'll just
- * save the FPU state as required.
- */
-static inline bool interrupted_user_mode(void)
-{
-	struct pt_regs *regs = get_irq_regs();
-	return regs && user_mode_vm(regs);
-}
-
-/*
- * Can we use the FPU in kernel mode with the
- * whole "kernel_fpu_begin/end()" sequence?
- *
- * It's always ok in process context (ie "not interrupt")
- * but it is sometimes ok even from an irq.
- */
-static inline bool irq_fpu_usable(void)
-{
-	return !in_interrupt() ||
-		interrupted_user_mode() ||
-		interrupted_kernel_fpu_idle();
-}
-
-static inline void kernel_fpu_begin(void)
-{
-	struct task_struct *me = current;
-
-	WARN_ON_ONCE(!irq_fpu_usable());
-	preempt_disable();
-	if (__thread_has_fpu(me)) {
-		__save_init_fpu(me);
-		__thread_clear_has_fpu(me);
-		/* We do 'stts()' in kernel_fpu_end() */
-	} else {
-		percpu_write(fpu_owner_task, NULL);
-		clts();
-	}
-}
-
-static inline void kernel_fpu_end(void)
-{
-	stts();
-	preempt_enable();
-}
+extern bool irq_fpu_usable(void);
+extern void kernel_fpu_begin(void);
+extern void kernel_fpu_end(void);
 
 /*
  * Some instructions like VIA's padlock instructions generate a spurious
@@ -524,126 +66,13 @@
  * we can just assume we have FPU access - typically
  * to save the FP state - we'll just take a #NM
  * fault and get the FPU access back.
- *
- * The actual user_fpu_begin/end() functions
- * need to be preemption-safe, though.
- *
- * NOTE! user_fpu_end() must be used only after you
- * have saved the FP state, and user_fpu_begin() must
- * be used only immediately before restoring it.
- * These functions do not do any save/restore on
- * their own.
  */
 static inline int user_has_fpu(void)
 {
-	return __thread_has_fpu(current);
+	return current->thread.fpu.has_fpu;
 }
 
-static inline void user_fpu_end(void)
-{
-	preempt_disable();
-	__thread_fpu_end(current);
-	preempt_enable();
-}
-
-static inline void user_fpu_begin(void)
-{
-	preempt_disable();
-	if (!user_has_fpu())
-		__thread_fpu_begin(current);
-	preempt_enable();
-}
-
-/*
- * These disable preemption on their own and are safe
- */
-static inline void save_init_fpu(struct task_struct *tsk)
-{
-	WARN_ON_ONCE(!__thread_has_fpu(tsk));
-	preempt_disable();
-	__save_init_fpu(tsk);
-	__thread_fpu_end(tsk);
-	preempt_enable();
-}
-
-static inline void unlazy_fpu(struct task_struct *tsk)
-{
-	preempt_disable();
-	if (__thread_has_fpu(tsk)) {
-		__save_init_fpu(tsk);
-		__thread_fpu_end(tsk);
-	} else
-		tsk->fpu_counter = 0;
-	preempt_enable();
-}
-
-static inline void clear_fpu(struct task_struct *tsk)
-{
-	preempt_disable();
-	__clear_fpu(tsk);
-	preempt_enable();
-}
-
-/*
- * i387 state interaction
- */
-static inline unsigned short get_fpu_cwd(struct task_struct *tsk)
-{
-	if (cpu_has_fxsr) {
-		return tsk->thread.fpu.state->fxsave.cwd;
-	} else {
-		return (unsigned short)tsk->thread.fpu.state->fsave.cwd;
-	}
-}
-
-static inline unsigned short get_fpu_swd(struct task_struct *tsk)
-{
-	if (cpu_has_fxsr) {
-		return tsk->thread.fpu.state->fxsave.swd;
-	} else {
-		return (unsigned short)tsk->thread.fpu.state->fsave.swd;
-	}
-}
-
-static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk)
-{
-	if (cpu_has_xmm) {
-		return tsk->thread.fpu.state->fxsave.mxcsr;
-	} else {
-		return MXCSR_DEFAULT;
-	}
-}
-
-static bool fpu_allocated(struct fpu *fpu)
-{
-	return fpu->state != NULL;
-}
-
-static inline int fpu_alloc(struct fpu *fpu)
-{
-	if (fpu_allocated(fpu))
-		return 0;
-	fpu->state = kmem_cache_alloc(task_xstate_cachep, GFP_KERNEL);
-	if (!fpu->state)
-		return -ENOMEM;
-	WARN_ON((unsigned long)fpu->state & 15);
-	return 0;
-}
-
-static inline void fpu_free(struct fpu *fpu)
-{
-	if (fpu->state) {
-		kmem_cache_free(task_xstate_cachep, fpu->state);
-		fpu->state = NULL;
-	}
-}
-
-static inline void fpu_copy(struct fpu *dst, struct fpu *src)
-{
-	memcpy(dst->state, src->state, xstate_size);
-}
-
-extern void fpu_finit(struct fpu *fpu);
+extern void unlazy_fpu(struct task_struct *tsk);
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/arch/x86/include/asm/ia32.h b/arch/x86/include/asm/ia32.h
index 1f7e625..ee52760 100644
--- a/arch/x86/include/asm/ia32.h
+++ b/arch/x86/include/asm/ia32.h
@@ -43,6 +43,15 @@
 	compat_sigset_t	  uc_sigmask;	/* mask last for extensibility */
 };
 
+struct ucontext_x32 {
+	unsigned int	  uc_flags;
+	unsigned int 	  uc_link;
+	stack_ia32_t	  uc_stack;
+	unsigned int	  uc__pad0;     /* needed for alignment */
+	struct sigcontext uc_mcontext;  /* the 64-bit sigcontext type */
+	compat_sigset_t	  uc_sigmask;	/* mask last for extensibility */
+};
+
 /* This matches struct stat64 in glibc2.2, hence the absolutely
  * insane amounts of padding around dev_t's.
  */
@@ -116,6 +125,15 @@
 			compat_clock_t _stime;
 		} _sigchld;
 
+		/* SIGCHLD (x32 version) */
+		struct {
+			unsigned int _pid;	/* which child */
+			unsigned int _uid;	/* sender's uid */
+			int _status;		/* exit code */
+			compat_s64 _utime;
+			compat_s64 _stime;
+		} _sigchld_x32;
+
 		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
 		struct {
 			unsigned int _addr;	/* faulting insn/memory ref. */
diff --git a/arch/x86/include/asm/idle.h b/arch/x86/include/asm/idle.h
index f49253d7..c5d1785 100644
--- a/arch/x86/include/asm/idle.h
+++ b/arch/x86/include/asm/idle.h
@@ -14,6 +14,7 @@
 #else /* !CONFIG_X86_64 */
 static inline void enter_idle(void) { }
 static inline void exit_idle(void) { }
+static inline void __exit_idle(void) { }
 #endif /* CONFIG_X86_64 */
 
 void amd_e400_remove_cpu(int cpu);
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
index 690d1cc..2c4943d 100644
--- a/arch/x86/include/asm/io_apic.h
+++ b/arch/x86/include/asm/io_apic.h
@@ -21,6 +21,15 @@
 #define IO_APIC_REDIR_LEVEL_TRIGGER	(1 << 15)
 #define IO_APIC_REDIR_MASKED		(1 << 16)
 
+struct io_apic_ops {
+	void		(*init)  (void);
+	unsigned int	(*read)  (unsigned int apic, unsigned int reg);
+	void		(*write) (unsigned int apic, unsigned int reg, unsigned int value);
+	void		(*modify)(unsigned int apic, unsigned int reg, unsigned int value);
+};
+
+void __init set_io_apic_ops(const struct io_apic_ops *);
+
 /*
  * The structure of the IO-APIC:
  */
diff --git a/arch/x86/include/asm/kgdb.h b/arch/x86/include/asm/kgdb.h
index 77e95f5..332f98c 100644
--- a/arch/x86/include/asm/kgdb.h
+++ b/arch/x86/include/asm/kgdb.h
@@ -64,11 +64,15 @@
 	GDB_PS,			/* 17 */
 	GDB_CS,			/* 18 */
 	GDB_SS,			/* 19 */
+	GDB_DS,			/* 20 */
+	GDB_ES,			/* 21 */
+	GDB_FS,			/* 22 */
+	GDB_GS,			/* 23 */
 };
 #define GDB_ORIG_AX		57
-#define DBG_MAX_REG_NUM		20
-/* 17 64 bit regs and 3 32 bit regs */
-#define NUMREGBYTES		((17 * 8) + (3 * 4))
+#define DBG_MAX_REG_NUM		24
+/* 17 64 bit regs and 5 32 bit regs */
+#define NUMREGBYTES		((17 * 8) + (5 * 4))
 #endif /* ! CONFIG_X86_32 */
 
 static inline void arch_kgdb_breakpoint(void)
diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
index 4d8dcbd..e7d1c19 100644
--- a/arch/x86/include/asm/kvm.h
+++ b/arch/x86/include/asm/kvm.h
@@ -321,4 +321,8 @@
 	__u64 padding[16];
 };
 
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+};
+
 #endif /* _ASM_X86_KVM_H */
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 7b9cfc4..c222e1a 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -176,6 +176,7 @@
 	void (*set_idt)(struct x86_emulate_ctxt *ctxt, struct desc_ptr *dt);
 	ulong (*get_cr)(struct x86_emulate_ctxt *ctxt, int cr);
 	int (*set_cr)(struct x86_emulate_ctxt *ctxt, int cr, ulong val);
+	void (*set_rflags)(struct x86_emulate_ctxt *ctxt, ulong val);
 	int (*cpl)(struct x86_emulate_ctxt *ctxt);
 	int (*get_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong *dest);
 	int (*set_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong value);
@@ -388,7 +389,7 @@
 #define EMULATION_INTERCEPTED 2
 int x86_emulate_insn(struct x86_emulate_ctxt *ctxt);
 int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
-			 u16 tss_selector, int reason,
+			 u16 tss_selector, int idt_index, int reason,
 			 bool has_error_code, u32 error_code);
 int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq);
 #endif /* _ASM_X86_KVM_X86_EMULATE_H */
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 52d6640..e216ba0 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -29,7 +29,7 @@
 #include <asm/msr-index.h>
 
 #define KVM_MAX_VCPUS 254
-#define KVM_SOFT_MAX_VCPUS 64
+#define KVM_SOFT_MAX_VCPUS 160
 #define KVM_MEMORY_SLOTS 32
 /* memory slots that does not exposed to userspace */
 #define KVM_PRIVATE_MEM_SLOTS 4
@@ -181,13 +181,6 @@
 	void *objects[KVM_NR_MEM_OBJS];
 };
 
-#define NR_PTE_CHAIN_ENTRIES 5
-
-struct kvm_pte_chain {
-	u64 *parent_ptes[NR_PTE_CHAIN_ENTRIES];
-	struct hlist_node link;
-};
-
 /*
  * kvm_mmu_page_role, below, is defined as:
  *
@@ -427,12 +420,16 @@
 
 	u64 last_guest_tsc;
 	u64 last_kernel_ns;
-	u64 last_tsc_nsec;
-	u64 last_tsc_write;
-	u32 virtual_tsc_khz;
+	u64 last_host_tsc;
+	u64 tsc_offset_adjustment;
+	u64 this_tsc_nsec;
+	u64 this_tsc_write;
+	u8  this_tsc_generation;
 	bool tsc_catchup;
-	u32  tsc_catchup_mult;
-	s8   tsc_catchup_shift;
+	bool tsc_always_catchup;
+	s8 virtual_tsc_shift;
+	u32 virtual_tsc_mult;
+	u32 virtual_tsc_khz;
 
 	atomic_t nmi_queued;  /* unprocessed asynchronous NMIs */
 	unsigned nmi_pending; /* NMI queued after currently running handler */
@@ -478,6 +475,21 @@
 		u32 id;
 		bool send_user_only;
 	} apf;
+
+	/* OSVW MSRs (AMD only) */
+	struct {
+		u64 length;
+		u64 status;
+	} osvw;
+};
+
+struct kvm_lpage_info {
+	unsigned long rmap_pde;
+	int write_count;
+};
+
+struct kvm_arch_memory_slot {
+	struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1];
 };
 
 struct kvm_arch {
@@ -511,8 +523,12 @@
 	s64 kvmclock_offset;
 	raw_spinlock_t tsc_write_lock;
 	u64 last_tsc_nsec;
-	u64 last_tsc_offset;
 	u64 last_tsc_write;
+	u32 last_tsc_khz;
+	u64 cur_tsc_nsec;
+	u64 cur_tsc_write;
+	u64 cur_tsc_offset;
+	u8  cur_tsc_generation;
 
 	struct kvm_xen_hvm_config xen_hvm_config;
 
@@ -644,7 +660,7 @@
 	u64 (*get_mt_mask)(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio);
 	int (*get_lpage_level)(void);
 	bool (*rdtscp_supported)(void);
-	void (*adjust_tsc_offset)(struct kvm_vcpu *vcpu, s64 adjustment);
+	void (*adjust_tsc_offset)(struct kvm_vcpu *vcpu, s64 adjustment, bool host);
 
 	void (*set_tdp_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
 
@@ -652,7 +668,7 @@
 
 	bool (*has_wbinvd_exit)(void);
 
-	void (*set_tsc_khz)(struct kvm_vcpu *vcpu, u32 user_tsc_khz);
+	void (*set_tsc_khz)(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale);
 	void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
 
 	u64 (*compute_tsc_offset)(struct kvm_vcpu *vcpu, u64 target_tsc);
@@ -674,6 +690,17 @@
 
 extern struct kvm_x86_ops *kvm_x86_ops;
 
+static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu,
+					   s64 adjustment)
+{
+	kvm_x86_ops->adjust_tsc_offset(vcpu, adjustment, false);
+}
+
+static inline void adjust_tsc_offset_host(struct kvm_vcpu *vcpu, s64 adjustment)
+{
+	kvm_x86_ops->adjust_tsc_offset(vcpu, adjustment, true);
+}
+
 int kvm_mmu_module_init(void);
 void kvm_mmu_module_exit(void);
 
@@ -741,8 +768,8 @@
 void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
 int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg);
 
-int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
-		    bool has_error_code, u32 error_code);
+int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index,
+		    int reason, bool has_error_code, u32 error_code);
 
 int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
 int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3);
diff --git a/arch/x86/include/asm/local.h b/arch/x86/include/asm/local.h
index 9cdae5d..c8bed0d 100644
--- a/arch/x86/include/asm/local.h
+++ b/arch/x86/include/asm/local.h
@@ -3,7 +3,6 @@
 
 #include <linux/percpu.h>
 
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/asm.h>
 
diff --git a/arch/x86/include/asm/mc146818rtc.h b/arch/x86/include/asm/mc146818rtc.h
index 0e8e85b..d354fb7 100644
--- a/arch/x86/include/asm/mc146818rtc.h
+++ b/arch/x86/include/asm/mc146818rtc.h
@@ -5,7 +5,6 @@
 #define _ASM_X86_MC146818RTC_H
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <linux/mc146818rtc.h>
 
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index 6aefb14..441520e 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -151,7 +151,7 @@
 
 void mce_setup(struct mce *m);
 void mce_log(struct mce *m);
-extern struct device *mce_device[CONFIG_NR_CPUS];
+DECLARE_PER_CPU(struct device *, mce_device);
 
 /*
  * Maximum banks number.
diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h
index 0a0a954..fc18bf3 100644
--- a/arch/x86/include/asm/mrst.h
+++ b/arch/x86/include/asm/mrst.h
@@ -26,8 +26,8 @@
  * identified via MSRs.
  */
 enum mrst_cpu_type {
-	MRST_CPU_CHIP_LINCROFT = 1,
-	MRST_CPU_CHIP_PENWELL,
+	/* 1 was Moorestown */
+	MRST_CPU_CHIP_PENWELL = 2,
 };
 
 extern enum mrst_cpu_type __mrst_cpu_chip;
diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h
index 4365ffd..7e3f17f 100644
--- a/arch/x86/include/asm/mtrr.h
+++ b/arch/x86/include/asm/mtrr.h
@@ -29,18 +29,18 @@
 
 #define	MTRR_IOCTL_BASE	'M'
 
-struct mtrr_sentry {
-    unsigned long base;    /*  Base address     */
-    unsigned int size;    /*  Size of region   */
-    unsigned int type;     /*  Type of region   */
-};
-
 /* Warning: this structure has a different order from i386
    on x86-64. The 32bit emulation code takes care of that.
    But you need to use this for 64bit, otherwise your X server
    will break. */
 
 #ifdef __i386__
+struct mtrr_sentry {
+    unsigned long base;    /*  Base address     */
+    unsigned int size;    /*  Size of region   */
+    unsigned int type;     /*  Type of region   */
+};
+
 struct mtrr_gentry {
     unsigned int regnum;   /*  Register number  */
     unsigned long base;    /*  Base address     */
@@ -50,12 +50,20 @@
 
 #else /* __i386__ */
 
-struct mtrr_gentry {
-    unsigned long base;    /*  Base address     */
-    unsigned int size;    /*  Size of region   */
-    unsigned int regnum;   /*  Register number  */
-    unsigned int type;     /*  Type of region   */
+struct mtrr_sentry {
+	__u64 base;		/*  Base address     */
+	__u32 size;		/*  Size of region   */
+	__u32 type;		/*  Type of region   */
 };
+
+struct mtrr_gentry {
+	__u64 base;		/*  Base address     */
+	__u32 size;		/*  Size of region   */
+	__u32 regnum;		/*  Register number  */
+	__u32 type;		/*  Type of region   */
+	__u32 _pad;		/*  Unused	     */
+};
+
 #endif /* !__i386__ */
 
 struct mtrr_var_range {
diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h
index bce688d..e21fdd1 100644
--- a/arch/x86/include/asm/page_types.h
+++ b/arch/x86/include/asm/page_types.h
@@ -55,7 +55,6 @@
 					 unsigned long end);
 
 extern void initmem_init(void);
-extern void free_initmem(void);
 
 #endif	/* !__ASSEMBLY__ */
 
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index c0180fd..aa0f913 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -10,6 +10,7 @@
 #include <asm/paravirt_types.h>
 
 #ifndef __ASSEMBLY__
+#include <linux/bug.h>
 #include <linux/types.h>
 #include <linux/cpumask.h>
 
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index e8fb2c7..2291895 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -23,6 +23,7 @@
 #define ARCH_PERFMON_EVENTSEL_USR			(1ULL << 16)
 #define ARCH_PERFMON_EVENTSEL_OS			(1ULL << 17)
 #define ARCH_PERFMON_EVENTSEL_EDGE			(1ULL << 18)
+#define ARCH_PERFMON_EVENTSEL_PIN_CONTROL		(1ULL << 19)
 #define ARCH_PERFMON_EVENTSEL_INT			(1ULL << 20)
 #define ARCH_PERFMON_EVENTSEL_ANY			(1ULL << 21)
 #define ARCH_PERFMON_EVENTSEL_ENABLE			(1ULL << 22)
diff --git a/arch/x86/include/asm/posix_types.h b/arch/x86/include/asm/posix_types.h
index bb7133d..3427b77 100644
--- a/arch/x86/include/asm/posix_types.h
+++ b/arch/x86/include/asm/posix_types.h
@@ -7,7 +7,9 @@
 #else
 # ifdef __i386__
 #  include "posix_types_32.h"
-# else
+# elif defined(__LP64__)
 #  include "posix_types_64.h"
+# else
+#  include "posix_types_x32.h"
 # endif
 #endif
diff --git a/arch/x86/include/asm/posix_types_32.h b/arch/x86/include/asm/posix_types_32.h
index f7d9adf..99f262e 100644
--- a/arch/x86/include/asm/posix_types_32.h
+++ b/arch/x86/include/asm/posix_types_32.h
@@ -7,79 +7,22 @@
  * assume GCC is being used.
  */
 
-typedef unsigned long	__kernel_ino_t;
 typedef unsigned short	__kernel_mode_t;
+#define __kernel_mode_t __kernel_mode_t
+
 typedef unsigned short	__kernel_nlink_t;
-typedef long		__kernel_off_t;
-typedef int		__kernel_pid_t;
+#define __kernel_nlink_t __kernel_nlink_t
+
 typedef unsigned short	__kernel_ipc_pid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
+
 typedef unsigned short	__kernel_uid_t;
 typedef unsigned short	__kernel_gid_t;
-typedef unsigned int	__kernel_size_t;
-typedef int		__kernel_ssize_t;
-typedef int		__kernel_ptrdiff_t;
-typedef long		__kernel_time_t;
-typedef long		__kernel_suseconds_t;
-typedef long		__kernel_clock_t;
-typedef int		__kernel_timer_t;
-typedef int		__kernel_clockid_t;
-typedef int		__kernel_daddr_t;
-typedef char *		__kernel_caddr_t;
-typedef unsigned short	__kernel_uid16_t;
-typedef unsigned short	__kernel_gid16_t;
-typedef unsigned int	__kernel_uid32_t;
-typedef unsigned int	__kernel_gid32_t;
+#define __kernel_uid_t __kernel_uid_t
 
-typedef unsigned short	__kernel_old_uid_t;
-typedef unsigned short	__kernel_old_gid_t;
 typedef unsigned short	__kernel_old_dev_t;
+#define __kernel_old_dev_t __kernel_old_dev_t
 
-#ifdef __GNUC__
-typedef long long	__kernel_loff_t;
-#endif
-
-typedef struct {
-	int	val[2];
-} __kernel_fsid_t;
-
-#if defined(__KERNEL__)
-
-#undef	__FD_SET
-#define __FD_SET(fd,fdsetp)					\
-	asm volatile("btsl %1,%0":				\
-		     "+m" (*(__kernel_fd_set *)(fdsetp))	\
-		     : "r" ((int)(fd)))
-
-#undef	__FD_CLR
-#define __FD_CLR(fd,fdsetp)					\
-	asm volatile("btrl %1,%0":				\
-		     "+m" (*(__kernel_fd_set *)(fdsetp))	\
-		     : "r" ((int) (fd)))
-
-#undef	__FD_ISSET
-#define __FD_ISSET(fd,fdsetp)					\
-	(__extension__						\
-	 ({							\
-	 unsigned char __result;				\
-	 asm volatile("btl %1,%2 ; setb %0"			\
-		      : "=q" (__result)				\
-		      : "r" ((int)(fd)),			\
-			"m" (*(__kernel_fd_set *)(fdsetp)));	\
-	 __result;						\
-}))
-
-#undef	__FD_ZERO
-#define __FD_ZERO(fdsetp)					\
-do {								\
-	int __d0, __d1;						\
-	asm volatile("cld ; rep ; stosl"			\
-		     : "=m" (*(__kernel_fd_set *)(fdsetp)),	\
-		       "=&c" (__d0), "=&D" (__d1)		\
-		     : "a" (0), "1" (__FDSET_LONGS),		\
-		       "2" ((__kernel_fd_set *)(fdsetp))	\
-		     : "memory");				\
-} while (0)
-
-#endif /* defined(__KERNEL__) */
+#include <asm-generic/posix_types.h>
 
 #endif /* _ASM_X86_POSIX_TYPES_32_H */
diff --git a/arch/x86/include/asm/posix_types_64.h b/arch/x86/include/asm/posix_types_64.h
index eb8d2d9..cba0c1e 100644
--- a/arch/x86/include/asm/posix_types_64.h
+++ b/arch/x86/include/asm/posix_types_64.h
@@ -7,113 +7,13 @@
  * assume GCC is being used.
  */
 
-typedef unsigned long	__kernel_ino_t;
-typedef unsigned int	__kernel_mode_t;
-typedef unsigned long	__kernel_nlink_t;
-typedef long		__kernel_off_t;
-typedef int		__kernel_pid_t;
-typedef int		__kernel_ipc_pid_t;
-typedef unsigned int	__kernel_uid_t;
-typedef unsigned int	__kernel_gid_t;
-typedef unsigned long	__kernel_size_t;
-typedef long		__kernel_ssize_t;
-typedef long		__kernel_ptrdiff_t;
-typedef long		__kernel_time_t;
-typedef long		__kernel_suseconds_t;
-typedef long		__kernel_clock_t;
-typedef int		__kernel_timer_t;
-typedef int		__kernel_clockid_t;
-typedef int		__kernel_daddr_t;
-typedef char *		__kernel_caddr_t;
-typedef unsigned short	__kernel_uid16_t;
-typedef unsigned short	__kernel_gid16_t;
-
-#ifdef __GNUC__
-typedef long long	__kernel_loff_t;
-#endif
-
-typedef struct {
-	int	val[2];
-} __kernel_fsid_t;
-
 typedef unsigned short __kernel_old_uid_t;
 typedef unsigned short __kernel_old_gid_t;
-typedef __kernel_uid_t __kernel_uid32_t;
-typedef __kernel_gid_t __kernel_gid32_t;
+#define __kernel_old_uid_t __kernel_old_uid_t
 
 typedef unsigned long	__kernel_old_dev_t;
+#define __kernel_old_dev_t __kernel_old_dev_t
 
-#ifdef __KERNEL__
-
-#undef __FD_SET
-static inline void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	fdsetp->fds_bits[_tmp] |= (1UL<<_rem);
-}
-
-#undef __FD_CLR
-static inline void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem);
-}
-
-#undef __FD_ISSET
-static inline int __FD_ISSET(unsigned long fd, __const__ __kernel_fd_set *p)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0;
-}
-
-/*
- * This will unroll the loop for the normal constant cases (8 or 32 longs,
- * for 256 and 1024-bit fd_sets respectively)
- */
-#undef __FD_ZERO
-static inline void __FD_ZERO(__kernel_fd_set *p)
-{
-	unsigned long *tmp = p->fds_bits;
-	int i;
-
-	if (__builtin_constant_p(__FDSET_LONGS)) {
-		switch (__FDSET_LONGS) {
-		case 32:
-			tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
-			tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
-			tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
-			tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
-			tmp[16] = 0; tmp[17] = 0; tmp[18] = 0; tmp[19] = 0;
-			tmp[20] = 0; tmp[21] = 0; tmp[22] = 0; tmp[23] = 0;
-			tmp[24] = 0; tmp[25] = 0; tmp[26] = 0; tmp[27] = 0;
-			tmp[28] = 0; tmp[29] = 0; tmp[30] = 0; tmp[31] = 0;
-			return;
-		case 16:
-			tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
-			tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
-			tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
-			tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
-			return;
-		case 8:
-			tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
-			tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
-			return;
-		case 4:
-			tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
-			return;
-		}
-	}
-	i = __FDSET_LONGS;
-	while (i) {
-		i--;
-		*tmp = 0;
-		tmp++;
-	}
-}
-
-#endif /* defined(__KERNEL__) */
+#include <asm-generic/posix_types.h>
 
 #endif /* _ASM_X86_POSIX_TYPES_64_H */
diff --git a/arch/x86/include/asm/posix_types_x32.h b/arch/x86/include/asm/posix_types_x32.h
new file mode 100644
index 0000000..85f9bda
--- /dev/null
+++ b/arch/x86/include/asm/posix_types_x32.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_X86_POSIX_TYPES_X32_H
+#define _ASM_X86_POSIX_TYPES_X32_H
+
+/*
+ * This file is only used by user-level software, so you need to
+ * be a little careful about namespace pollution etc.  Also, we cannot
+ * assume GCC is being used.
+ *
+ * These types should generally match the ones used by the 64-bit kernel,
+ *
+ */
+
+typedef long long __kernel_long_t;
+typedef unsigned long long __kernel_ulong_t;
+#define __kernel_long_t __kernel_long_t
+
+#include <asm/posix_types_64.h>
+
+#endif /* _ASM_X86_POSIX_TYPES_X32_H */
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 58545c9..4fa7dcc 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -14,13 +14,13 @@
 #include <asm/sigcontext.h>
 #include <asm/current.h>
 #include <asm/cpufeature.h>
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable_types.h>
 #include <asm/percpu.h>
 #include <asm/msr.h>
 #include <asm/desc_defs.h>
 #include <asm/nops.h>
+#include <asm/special_insns.h>
 
 #include <linux/personality.h>
 #include <linux/cpumask.h>
@@ -29,6 +29,15 @@
 #include <linux/math64.h>
 #include <linux/init.h>
 #include <linux/err.h>
+#include <linux/irqflags.h>
+
+/*
+ * We handle most unaligned accesses in hardware.  On the other hand
+ * unaligned DMA can be quite expensive on some Nehalem processors.
+ *
+ * Based on this we disable the IP header alignment in network drivers.
+ */
+#define NET_IP_ALIGN	0
 
 #define HBP_NUM 4
 /*
@@ -162,6 +171,7 @@
 extern void identify_boot_cpu(void);
 extern void identify_secondary_cpu(struct cpuinfo_x86 *);
 extern void print_cpu_info(struct cpuinfo_x86 *);
+void print_cpu_msr(struct cpuinfo_x86 *);
 extern void init_scattered_cpuid_features(struct cpuinfo_x86 *c);
 extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
 extern unsigned short num_cache_leaves;
@@ -453,7 +463,7 @@
 	unsigned long           ptrace_dr7;
 	/* Fault info: */
 	unsigned long		cr2;
-	unsigned long		trap_no;
+	unsigned long		trap_nr;
 	unsigned long		error_code;
 	/* floating point and extended processor state */
 	struct fpu		fpu;
@@ -474,61 +484,6 @@
 	unsigned		io_bitmap_max;
 };
 
-static inline unsigned long native_get_debugreg(int regno)
-{
-	unsigned long val = 0;	/* Damn you, gcc! */
-
-	switch (regno) {
-	case 0:
-		asm("mov %%db0, %0" :"=r" (val));
-		break;
-	case 1:
-		asm("mov %%db1, %0" :"=r" (val));
-		break;
-	case 2:
-		asm("mov %%db2, %0" :"=r" (val));
-		break;
-	case 3:
-		asm("mov %%db3, %0" :"=r" (val));
-		break;
-	case 6:
-		asm("mov %%db6, %0" :"=r" (val));
-		break;
-	case 7:
-		asm("mov %%db7, %0" :"=r" (val));
-		break;
-	default:
-		BUG();
-	}
-	return val;
-}
-
-static inline void native_set_debugreg(int regno, unsigned long value)
-{
-	switch (regno) {
-	case 0:
-		asm("mov %0, %%db0"	::"r" (value));
-		break;
-	case 1:
-		asm("mov %0, %%db1"	::"r" (value));
-		break;
-	case 2:
-		asm("mov %0, %%db2"	::"r" (value));
-		break;
-	case 3:
-		asm("mov %0, %%db3"	::"r" (value));
-		break;
-	case 6:
-		asm("mov %0, %%db6"	::"r" (value));
-		break;
-	case 7:
-		asm("mov %0, %%db7"	::"r" (value));
-		break;
-	default:
-		BUG();
-	}
-}
-
 /*
  * Set IOPL bits in EFLAGS from given mask
  */
@@ -574,14 +529,6 @@
 #define __cpuid			native_cpuid
 #define paravirt_enabled()	0
 
-/*
- * These special macros can be used to get or set a debugging register
- */
-#define get_debugreg(var, register)				\
-	(var) = native_get_debugreg(register)
-#define set_debugreg(value, register)				\
-	native_set_debugreg(register, value)
-
 static inline void load_sp0(struct tss_struct *tss,
 			    struct thread_struct *thread)
 {
@@ -926,9 +873,9 @@
 #define IA32_PAGE_OFFSET	((current->personality & ADDR_LIMIT_3GB) ? \
 					0xc0000000 : 0xFFFFe000)
 
-#define TASK_SIZE		(test_thread_flag(TIF_IA32) ? \
+#define TASK_SIZE		(test_thread_flag(TIF_ADDR32) ? \
 					IA32_PAGE_OFFSET : TASK_SIZE_MAX)
-#define TASK_SIZE_OF(child)	((test_tsk_thread_flag(child, TIF_IA32)) ? \
+#define TASK_SIZE_OF(child)	((test_tsk_thread_flag(child, TIF_ADDR32)) ? \
 					IA32_PAGE_OFFSET : TASK_SIZE_MAX)
 
 #define STACK_TOP		TASK_SIZE
@@ -950,6 +897,12 @@
 
 #define task_pt_regs(tsk)	((struct pt_regs *)(tsk)->thread.sp0 - 1)
 extern unsigned long KSTK_ESP(struct task_struct *task);
+
+/*
+ * User space RSP while inside the SYSCALL fast path
+ */
+DECLARE_PER_CPU(unsigned long, old_rsp);
+
 #endif /* CONFIG_X86_64 */
 
 extern void start_thread(struct pt_regs *regs, unsigned long new_ip,
@@ -1021,4 +974,14 @@
 #define cpu_has_amd_erratum(x)	(false)
 #endif /* CONFIG_CPU_SUP_AMD */
 
+void cpu_idle_wait(void);
+
+extern unsigned long arch_align_stack(unsigned long sp);
+extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
+
+void default_idle(void);
+bool set_pm_idle_to_default(void);
+
+void stop_this_cpu(void *dummy);
+
 #endif /* _ASM_X86_PROCESSOR_H */
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
index 3566454..dcfde52 100644
--- a/arch/x86/include/asm/ptrace.h
+++ b/arch/x86/include/asm/ptrace.h
@@ -145,7 +145,6 @@
 convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs);
 extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
 			 int error_code, int si_code);
-void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
 
 extern long syscall_trace_enter(struct pt_regs *);
 extern void syscall_trace_leave(struct pt_regs *);
diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h
index 5e64171..1654662 100644
--- a/arch/x86/include/asm/segment.h
+++ b/arch/x86/include/asm/segment.h
@@ -212,7 +212,61 @@
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][10];
-#endif
-#endif
+
+/*
+ * Load a segment. Fall back on loading the zero
+ * segment if something goes wrong..
+ */
+#define loadsegment(seg, value)						\
+do {									\
+	unsigned short __val = (value);					\
+									\
+	asm volatile("						\n"	\
+		     "1:	movl %k0,%%" #seg "		\n"	\
+									\
+		     ".section .fixup,\"ax\"			\n"	\
+		     "2:	xorl %k0,%k0			\n"	\
+		     "		jmp 1b				\n"	\
+		     ".previous					\n"	\
+									\
+		     _ASM_EXTABLE(1b, 2b)				\
+									\
+		     : "+r" (__val) : : "memory");			\
+} while (0)
+
+/*
+ * Save a segment register away
+ */
+#define savesegment(seg, value)				\
+	asm("mov %%" #seg ",%0":"=r" (value) : : "memory")
+
+/*
+ * x86_32 user gs accessors.
+ */
+#ifdef CONFIG_X86_32
+#ifdef CONFIG_X86_32_LAZY_GS
+#define get_user_gs(regs)	(u16)({unsigned long v; savesegment(gs, v); v;})
+#define set_user_gs(regs, v)	loadsegment(gs, (unsigned long)(v))
+#define task_user_gs(tsk)	((tsk)->thread.gs)
+#define lazy_save_gs(v)		savesegment(gs, (v))
+#define lazy_load_gs(v)		loadsegment(gs, (v))
+#else	/* X86_32_LAZY_GS */
+#define get_user_gs(regs)	(u16)((regs)->gs)
+#define set_user_gs(regs, v)	do { (regs)->gs = (v); } while (0)
+#define task_user_gs(tsk)	(task_pt_regs(tsk)->gs)
+#define lazy_save_gs(v)		do { } while (0)
+#define lazy_load_gs(v)		do { } while (0)
+#endif	/* X86_32_LAZY_GS */
+#endif	/* X86_32 */
+
+static inline unsigned long get_limit(unsigned long segment)
+{
+	unsigned long __limit;
+	asm("lsll %1,%0" : "=r" (__limit) : "r" (segment));
+	return __limit + 1;
+}
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __KERNEL__ */
 
 #endif /* _ASM_X86_SEGMENT_H */
diff --git a/arch/x86/include/asm/sigcontext.h b/arch/x86/include/asm/sigcontext.h
index 04459d2..4a08538 100644
--- a/arch/x86/include/asm/sigcontext.h
+++ b/arch/x86/include/asm/sigcontext.h
@@ -230,34 +230,37 @@
  * User-space might still rely on the old definition:
  */
 struct sigcontext {
-	unsigned long r8;
-	unsigned long r9;
-	unsigned long r10;
-	unsigned long r11;
-	unsigned long r12;
-	unsigned long r13;
-	unsigned long r14;
-	unsigned long r15;
-	unsigned long rdi;
-	unsigned long rsi;
-	unsigned long rbp;
-	unsigned long rbx;
-	unsigned long rdx;
-	unsigned long rax;
-	unsigned long rcx;
-	unsigned long rsp;
-	unsigned long rip;
-	unsigned long eflags;		/* RFLAGS */
-	unsigned short cs;
-	unsigned short gs;
-	unsigned short fs;
-	unsigned short __pad0;
-	unsigned long err;
-	unsigned long trapno;
-	unsigned long oldmask;
-	unsigned long cr2;
+	__u64 r8;
+	__u64 r9;
+	__u64 r10;
+	__u64 r11;
+	__u64 r12;
+	__u64 r13;
+	__u64 r14;
+	__u64 r15;
+	__u64 rdi;
+	__u64 rsi;
+	__u64 rbp;
+	__u64 rbx;
+	__u64 rdx;
+	__u64 rax;
+	__u64 rcx;
+	__u64 rsp;
+	__u64 rip;
+	__u64 eflags;		/* RFLAGS */
+	__u16 cs;
+	__u16 gs;
+	__u16 fs;
+	__u16 __pad0;
+	__u64 err;
+	__u64 trapno;
+	__u64 oldmask;
+	__u64 cr2;
 	struct _fpstate __user *fpstate;	/* zero when no FPU context */
-	unsigned long reserved1[8];
+#ifndef __LP64__
+	__u32 __fpstate_pad;
+#endif
+	__u64 reserved1[8];
 };
 #endif /* !__KERNEL__ */
 
diff --git a/arch/x86/include/asm/sigframe.h b/arch/x86/include/asm/sigframe.h
index 4e0fe26..7c7c27c 100644
--- a/arch/x86/include/asm/sigframe.h
+++ b/arch/x86/include/asm/sigframe.h
@@ -59,12 +59,25 @@
 #endif /* defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) */
 
 #ifdef CONFIG_X86_64
+
 struct rt_sigframe {
 	char __user *pretcode;
 	struct ucontext uc;
 	struct siginfo info;
 	/* fp state follows here */
 };
+
+#ifdef CONFIG_X86_X32_ABI
+
+struct rt_sigframe_x32 {
+	u64 pretcode;
+	struct ucontext_x32 uc;
+	compat_siginfo_t info;
+	/* fp state follows here */
+};
+
+#endif /* CONFIG_X86_X32_ABI */
+
 #endif /* CONFIG_X86_64 */
 
 #endif /* _ASM_X86_SIGFRAME_H */
diff --git a/arch/x86/include/asm/sighandling.h b/arch/x86/include/asm/sighandling.h
new file mode 100644
index 0000000..ada93b3
--- /dev/null
+++ b/arch/x86/include/asm/sighandling.h
@@ -0,0 +1,24 @@
+#ifndef _ASM_X86_SIGHANDLING_H
+#define _ASM_X86_SIGHANDLING_H
+
+#include <linux/compiler.h>
+#include <linux/ptrace.h>
+#include <linux/signal.h>
+
+#include <asm/processor-flags.h>
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+#define __FIX_EFLAGS	(X86_EFLAGS_AC | X86_EFLAGS_OF | \
+			 X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \
+			 X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \
+			 X86_EFLAGS_CF)
+
+void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
+
+int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
+		       unsigned long *pax);
+int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
+		     struct pt_regs *regs, unsigned long mask);
+
+#endif /* _ASM_X86_SIGHANDLING_H */
diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h
new file mode 100644
index 0000000..41fc93a
--- /dev/null
+++ b/arch/x86/include/asm/special_insns.h
@@ -0,0 +1,199 @@
+#ifndef _ASM_X86_SPECIAL_INSNS_H
+#define _ASM_X86_SPECIAL_INSNS_H
+
+
+#ifdef __KERNEL__
+
+static inline void native_clts(void)
+{
+	asm volatile("clts");
+}
+
+/*
+ * Volatile isn't enough to prevent the compiler from reordering the
+ * read/write functions for the control registers and messing everything up.
+ * A memory clobber would solve the problem, but would prevent reordering of
+ * all loads stores around it, which can hurt performance. Solution is to
+ * use a variable and mimic reads and writes to it to enforce serialization
+ */
+static unsigned long __force_order;
+
+static inline unsigned long native_read_cr0(void)
+{
+	unsigned long val;
+	asm volatile("mov %%cr0,%0\n\t" : "=r" (val), "=m" (__force_order));
+	return val;
+}
+
+static inline void native_write_cr0(unsigned long val)
+{
+	asm volatile("mov %0,%%cr0": : "r" (val), "m" (__force_order));
+}
+
+static inline unsigned long native_read_cr2(void)
+{
+	unsigned long val;
+	asm volatile("mov %%cr2,%0\n\t" : "=r" (val), "=m" (__force_order));
+	return val;
+}
+
+static inline void native_write_cr2(unsigned long val)
+{
+	asm volatile("mov %0,%%cr2": : "r" (val), "m" (__force_order));
+}
+
+static inline unsigned long native_read_cr3(void)
+{
+	unsigned long val;
+	asm volatile("mov %%cr3,%0\n\t" : "=r" (val), "=m" (__force_order));
+	return val;
+}
+
+static inline void native_write_cr3(unsigned long val)
+{
+	asm volatile("mov %0,%%cr3": : "r" (val), "m" (__force_order));
+}
+
+static inline unsigned long native_read_cr4(void)
+{
+	unsigned long val;
+	asm volatile("mov %%cr4,%0\n\t" : "=r" (val), "=m" (__force_order));
+	return val;
+}
+
+static inline unsigned long native_read_cr4_safe(void)
+{
+	unsigned long val;
+	/* This could fault if %cr4 does not exist. In x86_64, a cr4 always
+	 * exists, so it will never fail. */
+#ifdef CONFIG_X86_32
+	asm volatile("1: mov %%cr4, %0\n"
+		     "2:\n"
+		     _ASM_EXTABLE(1b, 2b)
+		     : "=r" (val), "=m" (__force_order) : "0" (0));
+#else
+	val = native_read_cr4();
+#endif
+	return val;
+}
+
+static inline void native_write_cr4(unsigned long val)
+{
+	asm volatile("mov %0,%%cr4": : "r" (val), "m" (__force_order));
+}
+
+#ifdef CONFIG_X86_64
+static inline unsigned long native_read_cr8(void)
+{
+	unsigned long cr8;
+	asm volatile("movq %%cr8,%0" : "=r" (cr8));
+	return cr8;
+}
+
+static inline void native_write_cr8(unsigned long val)
+{
+	asm volatile("movq %0,%%cr8" :: "r" (val) : "memory");
+}
+#endif
+
+static inline void native_wbinvd(void)
+{
+	asm volatile("wbinvd": : :"memory");
+}
+
+extern void native_load_gs_index(unsigned);
+
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
+#else
+
+static inline unsigned long read_cr0(void)
+{
+	return native_read_cr0();
+}
+
+static inline void write_cr0(unsigned long x)
+{
+	native_write_cr0(x);
+}
+
+static inline unsigned long read_cr2(void)
+{
+	return native_read_cr2();
+}
+
+static inline void write_cr2(unsigned long x)
+{
+	native_write_cr2(x);
+}
+
+static inline unsigned long read_cr3(void)
+{
+	return native_read_cr3();
+}
+
+static inline void write_cr3(unsigned long x)
+{
+	native_write_cr3(x);
+}
+
+static inline unsigned long read_cr4(void)
+{
+	return native_read_cr4();
+}
+
+static inline unsigned long read_cr4_safe(void)
+{
+	return native_read_cr4_safe();
+}
+
+static inline void write_cr4(unsigned long x)
+{
+	native_write_cr4(x);
+}
+
+static inline void wbinvd(void)
+{
+	native_wbinvd();
+}
+
+#ifdef CONFIG_X86_64
+
+static inline unsigned long read_cr8(void)
+{
+	return native_read_cr8();
+}
+
+static inline void write_cr8(unsigned long x)
+{
+	native_write_cr8(x);
+}
+
+static inline void load_gs_index(unsigned selector)
+{
+	native_load_gs_index(selector);
+}
+
+#endif
+
+/* Clear the 'TS' bit */
+static inline void clts(void)
+{
+	native_clts();
+}
+
+#endif/* CONFIG_PARAVIRT */
+
+#define stts() write_cr0(read_cr0() | X86_CR0_TS)
+
+static inline void clflush(volatile void *__p)
+{
+	asm volatile("clflush %0" : "+m" (*(volatile char __force *)__p));
+}
+
+#define nop() asm volatile ("nop")
+
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_X86_SPECIAL_INSNS_H */
diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index a82c2bf..76bfa2c 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -88,14 +88,14 @@
 {
 	struct __raw_tickets tmp = ACCESS_ONCE(lock->tickets);
 
-	return !!(tmp.tail ^ tmp.head);
+	return tmp.tail != tmp.head;
 }
 
 static inline int __ticket_spin_is_contended(arch_spinlock_t *lock)
 {
 	struct __raw_tickets tmp = ACCESS_ONCE(lock->tickets);
 
-	return ((tmp.tail - tmp.head) & TICKET_MASK) > 1;
+	return (__ticket_t)(tmp.tail - tmp.head) > 1;
 }
 
 #ifndef CONFIG_PARAVIRT_SPINLOCKS
diff --git a/arch/x86/include/asm/spinlock_types.h b/arch/x86/include/asm/spinlock_types.h
index 8ebd5df..ad0ad07 100644
--- a/arch/x86/include/asm/spinlock_types.h
+++ b/arch/x86/include/asm/spinlock_types.h
@@ -16,7 +16,6 @@
 #endif
 
 #define TICKET_SHIFT	(sizeof(__ticket_t) * 8)
-#define TICKET_MASK	((__ticket_t)((1 << TICKET_SHIFT) - 1))
 
 typedef struct arch_spinlock {
 	union {
diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h
index 1575177..b5d9533 100644
--- a/arch/x86/include/asm/stackprotector.h
+++ b/arch/x86/include/asm/stackprotector.h
@@ -38,7 +38,6 @@
 #include <asm/tsc.h>
 #include <asm/processor.h>
 #include <asm/percpu.h>
-#include <asm/system.h>
 #include <asm/desc.h>
 #include <linux/random.h>
 
diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h
new file mode 100644
index 0000000..4ec45b3
--- /dev/null
+++ b/arch/x86/include/asm/switch_to.h
@@ -0,0 +1,129 @@
+#ifndef _ASM_X86_SWITCH_TO_H
+#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);
+struct tss_struct;
+void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
+		      struct tss_struct *tss);
+
+#ifdef CONFIG_X86_32
+
+#ifdef CONFIG_CC_STACKPROTECTOR
+#define __switch_canary							\
+	"movl %P[task_canary](%[next]), %%ebx\n\t"			\
+	"movl %%ebx, "__percpu_arg([stack_canary])"\n\t"
+#define __switch_canary_oparam						\
+	, [stack_canary] "=m" (stack_canary.canary)
+#define __switch_canary_iparam						\
+	, [task_canary] "i" (offsetof(struct task_struct, stack_canary))
+#else	/* CC_STACKPROTECTOR */
+#define __switch_canary
+#define __switch_canary_oparam
+#define __switch_canary_iparam
+#endif	/* CC_STACKPROTECTOR */
+
+/*
+ * Saving eflags is important. It switches not only IOPL between tasks,
+ * it also protects other tasks from NT leaking through sysenter etc.
+ */
+#define switch_to(prev, next, last)					\
+do {									\
+	/*								\
+	 * Context-switching clobbers all registers, so we clobber	\
+	 * them explicitly, via unused output variables.		\
+	 * (EAX and EBP is not listed because EBP is saved/restored	\
+	 * explicitly for wchan access and EAX is the return value of	\
+	 * __switch_to())						\
+	 */								\
+	unsigned long ebx, ecx, edx, esi, edi;				\
+									\
+	asm volatile("pushfl\n\t"		/* save    flags */	\
+		     "pushl %%ebp\n\t"		/* save    EBP   */	\
+		     "movl %%esp,%[prev_sp]\n\t"	/* save    ESP   */ \
+		     "movl %[next_sp],%%esp\n\t"	/* restore ESP   */ \
+		     "movl $1f,%[prev_ip]\n\t"	/* save    EIP   */	\
+		     "pushl %[next_ip]\n\t"	/* restore EIP   */	\
+		     __switch_canary					\
+		     "jmp __switch_to\n"	/* regparm call  */	\
+		     "1:\t"						\
+		     "popl %%ebp\n\t"		/* restore EBP   */	\
+		     "popfl\n"			/* restore flags */	\
+									\
+		     /* output parameters */				\
+		     : [prev_sp] "=m" (prev->thread.sp),		\
+		       [prev_ip] "=m" (prev->thread.ip),		\
+		       "=a" (last),					\
+									\
+		       /* clobbered output registers: */		\
+		       "=b" (ebx), "=c" (ecx), "=d" (edx),		\
+		       "=S" (esi), "=D" (edi)				\
+		       							\
+		       __switch_canary_oparam				\
+									\
+		       /* input parameters: */				\
+		     : [next_sp]  "m" (next->thread.sp),		\
+		       [next_ip]  "m" (next->thread.ip),		\
+		       							\
+		       /* regparm parameters for __switch_to(): */	\
+		       [prev]     "a" (prev),				\
+		       [next]     "d" (next)				\
+									\
+		       __switch_canary_iparam				\
+									\
+		     : /* reloaded segment registers */			\
+			"memory");					\
+} while (0)
+
+#else /* CONFIG_X86_32 */
+
+/* frame pointer must be last for get_wchan */
+#define SAVE_CONTEXT    "pushf ; pushq %%rbp ; movq %%rsi,%%rbp\n\t"
+#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp ; popf\t"
+
+#define __EXTRA_CLOBBER  \
+	, "rcx", "rbx", "rdx", "r8", "r9", "r10", "r11", \
+	  "r12", "r13", "r14", "r15"
+
+#ifdef CONFIG_CC_STACKPROTECTOR
+#define __switch_canary							  \
+	"movq %P[task_canary](%%rsi),%%r8\n\t"				  \
+	"movq %%r8,"__percpu_arg([gs_canary])"\n\t"
+#define __switch_canary_oparam						  \
+	, [gs_canary] "=m" (irq_stack_union.stack_canary)
+#define __switch_canary_iparam						  \
+	, [task_canary] "i" (offsetof(struct task_struct, stack_canary))
+#else	/* CC_STACKPROTECTOR */
+#define __switch_canary
+#define __switch_canary_oparam
+#define __switch_canary_iparam
+#endif	/* CC_STACKPROTECTOR */
+
+/* Save restore flags to clear handle leaking NT */
+#define switch_to(prev, next, last) \
+	asm volatile(SAVE_CONTEXT					  \
+	     "movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */	  \
+	     "movq %P[threadrsp](%[next]),%%rsp\n\t" /* restore RSP */	  \
+	     "call __switch_to\n\t"					  \
+	     "movq "__percpu_arg([current_task])",%%rsi\n\t"		  \
+	     __switch_canary						  \
+	     "movq %P[thread_info](%%rsi),%%r8\n\t"			  \
+	     "movq %%rax,%%rdi\n\t" 					  \
+	     "testl  %[_tif_fork],%P[ti_flags](%%r8)\n\t"		  \
+	     "jnz   ret_from_fork\n\t"					  \
+	     RESTORE_CONTEXT						  \
+	     : "=a" (last)					  	  \
+	       __switch_canary_oparam					  \
+	     : [next] "S" (next), [prev] "D" (prev),			  \
+	       [threadrsp] "i" (offsetof(struct task_struct, thread.sp)), \
+	       [ti_flags] "i" (offsetof(struct thread_info, flags)),	  \
+	       [_tif_fork] "i" (_TIF_FORK),			  	  \
+	       [thread_info] "i" (offsetof(struct task_struct, stack)),   \
+	       [current_task] "m" (current_task)			  \
+	       __switch_canary_iparam					  \
+	     : "memory", "cc" __EXTRA_CLOBBER)
+
+#endif /* CONFIG_X86_32 */
+
+#endif /* _ASM_X86_SWITCH_TO_H */
diff --git a/arch/x86/include/asm/sys_ia32.h b/arch/x86/include/asm/sys_ia32.h
index cb23852..3fda9db4 100644
--- a/arch/x86/include/asm/sys_ia32.h
+++ b/arch/x86/include/asm/sys_ia32.h
@@ -10,6 +10,8 @@
 #ifndef _ASM_X86_SYS_IA32_H
 #define _ASM_X86_SYS_IA32_H
 
+#ifdef CONFIG_COMPAT
+
 #include <linux/compiler.h>
 #include <linux/linkage.h>
 #include <linux/types.h>
@@ -36,8 +38,6 @@
 				   struct sigaction32 __user *, unsigned int);
 asmlinkage long sys32_sigaction(int, struct old_sigaction32 __user *,
 				struct old_sigaction32 __user *);
-asmlinkage long sys32_rt_sigprocmask(int, compat_sigset_t __user *,
-				     compat_sigset_t __user *, unsigned int);
 asmlinkage long sys32_alarm(unsigned int);
 
 asmlinkage long sys32_waitpid(compat_pid_t, unsigned int *, int);
@@ -83,4 +83,7 @@
 
 asmlinkage long sys32_fanotify_mark(int, unsigned int, u32, u32, int,
 				    const char __user *);
+
+#endif /* CONFIG_COMPAT */
+
 #endif /* _ASM_X86_SYS_IA32_H */
diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h
index d962e56..386b786 100644
--- a/arch/x86/include/asm/syscall.h
+++ b/arch/x86/include/asm/syscall.h
@@ -16,6 +16,7 @@
 #include <linux/sched.h>
 #include <linux/err.h>
 #include <asm/asm-offsets.h>	/* For NR_syscalls */
+#include <asm/unistd.h>
 
 extern const unsigned long sys_call_table[];
 
@@ -26,13 +27,13 @@
  */
 static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
 {
-	return regs->orig_ax;
+	return regs->orig_ax & __SYSCALL_MASK;
 }
 
 static inline void syscall_rollback(struct task_struct *task,
 				    struct pt_regs *regs)
 {
-	regs->ax = regs->orig_ax;
+	regs->ax = regs->orig_ax & __SYSCALL_MASK;
 }
 
 static inline long syscall_get_error(struct task_struct *task,
diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h
deleted file mode 100644
index 2d2f01c..0000000
--- a/arch/x86/include/asm/system.h
+++ /dev/null
@@ -1,523 +0,0 @@
-#ifndef _ASM_X86_SYSTEM_H
-#define _ASM_X86_SYSTEM_H
-
-#include <asm/asm.h>
-#include <asm/segment.h>
-#include <asm/cpufeature.h>
-#include <asm/cmpxchg.h>
-#include <asm/nops.h>
-
-#include <linux/kernel.h>
-#include <linux/irqflags.h>
-
-/* entries in ARCH_DLINFO: */
-#if defined(CONFIG_IA32_EMULATION) || !defined(CONFIG_X86_64)
-# define AT_VECTOR_SIZE_ARCH 2
-#else /* else it's non-compat x86-64 */
-# define AT_VECTOR_SIZE_ARCH 1
-#endif
-
-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);
-struct tss_struct;
-void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
-		      struct tss_struct *tss);
-extern void show_regs_common(void);
-
-#ifdef CONFIG_X86_32
-
-#ifdef CONFIG_CC_STACKPROTECTOR
-#define __switch_canary							\
-	"movl %P[task_canary](%[next]), %%ebx\n\t"			\
-	"movl %%ebx, "__percpu_arg([stack_canary])"\n\t"
-#define __switch_canary_oparam						\
-	, [stack_canary] "=m" (stack_canary.canary)
-#define __switch_canary_iparam						\
-	, [task_canary] "i" (offsetof(struct task_struct, stack_canary))
-#else	/* CC_STACKPROTECTOR */
-#define __switch_canary
-#define __switch_canary_oparam
-#define __switch_canary_iparam
-#endif	/* CC_STACKPROTECTOR */
-
-/*
- * Saving eflags is important. It switches not only IOPL between tasks,
- * it also protects other tasks from NT leaking through sysenter etc.
- */
-#define switch_to(prev, next, last)					\
-do {									\
-	/*								\
-	 * Context-switching clobbers all registers, so we clobber	\
-	 * them explicitly, via unused output variables.		\
-	 * (EAX and EBP is not listed because EBP is saved/restored	\
-	 * explicitly for wchan access and EAX is the return value of	\
-	 * __switch_to())						\
-	 */								\
-	unsigned long ebx, ecx, edx, esi, edi;				\
-									\
-	asm volatile("pushfl\n\t"		/* save    flags */	\
-		     "pushl %%ebp\n\t"		/* save    EBP   */	\
-		     "movl %%esp,%[prev_sp]\n\t"	/* save    ESP   */ \
-		     "movl %[next_sp],%%esp\n\t"	/* restore ESP   */ \
-		     "movl $1f,%[prev_ip]\n\t"	/* save    EIP   */	\
-		     "pushl %[next_ip]\n\t"	/* restore EIP   */	\
-		     __switch_canary					\
-		     "jmp __switch_to\n"	/* regparm call  */	\
-		     "1:\t"						\
-		     "popl %%ebp\n\t"		/* restore EBP   */	\
-		     "popfl\n"			/* restore flags */	\
-									\
-		     /* output parameters */				\
-		     : [prev_sp] "=m" (prev->thread.sp),		\
-		       [prev_ip] "=m" (prev->thread.ip),		\
-		       "=a" (last),					\
-									\
-		       /* clobbered output registers: */		\
-		       "=b" (ebx), "=c" (ecx), "=d" (edx),		\
-		       "=S" (esi), "=D" (edi)				\
-		       							\
-		       __switch_canary_oparam				\
-									\
-		       /* input parameters: */				\
-		     : [next_sp]  "m" (next->thread.sp),		\
-		       [next_ip]  "m" (next->thread.ip),		\
-		       							\
-		       /* regparm parameters for __switch_to(): */	\
-		       [prev]     "a" (prev),				\
-		       [next]     "d" (next)				\
-									\
-		       __switch_canary_iparam				\
-									\
-		     : /* reloaded segment registers */			\
-			"memory");					\
-} while (0)
-
-/*
- * disable hlt during certain critical i/o operations
- */
-#define HAVE_DISABLE_HLT
-#else
-
-/* frame pointer must be last for get_wchan */
-#define SAVE_CONTEXT    "pushf ; pushq %%rbp ; movq %%rsi,%%rbp\n\t"
-#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp ; popf\t"
-
-#define __EXTRA_CLOBBER  \
-	, "rcx", "rbx", "rdx", "r8", "r9", "r10", "r11", \
-	  "r12", "r13", "r14", "r15"
-
-#ifdef CONFIG_CC_STACKPROTECTOR
-#define __switch_canary							  \
-	"movq %P[task_canary](%%rsi),%%r8\n\t"				  \
-	"movq %%r8,"__percpu_arg([gs_canary])"\n\t"
-#define __switch_canary_oparam						  \
-	, [gs_canary] "=m" (irq_stack_union.stack_canary)
-#define __switch_canary_iparam						  \
-	, [task_canary] "i" (offsetof(struct task_struct, stack_canary))
-#else	/* CC_STACKPROTECTOR */
-#define __switch_canary
-#define __switch_canary_oparam
-#define __switch_canary_iparam
-#endif	/* CC_STACKPROTECTOR */
-
-/* Save restore flags to clear handle leaking NT */
-#define switch_to(prev, next, last) \
-	asm volatile(SAVE_CONTEXT					  \
-	     "movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */	  \
-	     "movq %P[threadrsp](%[next]),%%rsp\n\t" /* restore RSP */	  \
-	     "call __switch_to\n\t"					  \
-	     "movq "__percpu_arg([current_task])",%%rsi\n\t"		  \
-	     __switch_canary						  \
-	     "movq %P[thread_info](%%rsi),%%r8\n\t"			  \
-	     "movq %%rax,%%rdi\n\t" 					  \
-	     "testl  %[_tif_fork],%P[ti_flags](%%r8)\n\t"		  \
-	     "jnz   ret_from_fork\n\t"					  \
-	     RESTORE_CONTEXT						  \
-	     : "=a" (last)					  	  \
-	       __switch_canary_oparam					  \
-	     : [next] "S" (next), [prev] "D" (prev),			  \
-	       [threadrsp] "i" (offsetof(struct task_struct, thread.sp)), \
-	       [ti_flags] "i" (offsetof(struct thread_info, flags)),	  \
-	       [_tif_fork] "i" (_TIF_FORK),			  	  \
-	       [thread_info] "i" (offsetof(struct task_struct, stack)),   \
-	       [current_task] "m" (current_task)			  \
-	       __switch_canary_iparam					  \
-	     : "memory", "cc" __EXTRA_CLOBBER)
-#endif
-
-#ifdef __KERNEL__
-
-extern void native_load_gs_index(unsigned);
-
-/*
- * Load a segment. Fall back on loading the zero
- * segment if something goes wrong..
- */
-#define loadsegment(seg, value)						\
-do {									\
-	unsigned short __val = (value);					\
-									\
-	asm volatile("						\n"	\
-		     "1:	movl %k0,%%" #seg "		\n"	\
-									\
-		     ".section .fixup,\"ax\"			\n"	\
-		     "2:	xorl %k0,%k0			\n"	\
-		     "		jmp 1b				\n"	\
-		     ".previous					\n"	\
-									\
-		     _ASM_EXTABLE(1b, 2b)				\
-									\
-		     : "+r" (__val) : : "memory");			\
-} while (0)
-
-/*
- * Save a segment register away
- */
-#define savesegment(seg, value)				\
-	asm("mov %%" #seg ",%0":"=r" (value) : : "memory")
-
-/*
- * x86_32 user gs accessors.
- */
-#ifdef CONFIG_X86_32
-#ifdef CONFIG_X86_32_LAZY_GS
-#define get_user_gs(regs)	(u16)({unsigned long v; savesegment(gs, v); v;})
-#define set_user_gs(regs, v)	loadsegment(gs, (unsigned long)(v))
-#define task_user_gs(tsk)	((tsk)->thread.gs)
-#define lazy_save_gs(v)		savesegment(gs, (v))
-#define lazy_load_gs(v)		loadsegment(gs, (v))
-#else	/* X86_32_LAZY_GS */
-#define get_user_gs(regs)	(u16)((regs)->gs)
-#define set_user_gs(regs, v)	do { (regs)->gs = (v); } while (0)
-#define task_user_gs(tsk)	(task_pt_regs(tsk)->gs)
-#define lazy_save_gs(v)		do { } while (0)
-#define lazy_load_gs(v)		do { } while (0)
-#endif	/* X86_32_LAZY_GS */
-#endif	/* X86_32 */
-
-static inline unsigned long get_limit(unsigned long segment)
-{
-	unsigned long __limit;
-	asm("lsll %1,%0" : "=r" (__limit) : "r" (segment));
-	return __limit + 1;
-}
-
-static inline void native_clts(void)
-{
-	asm volatile("clts");
-}
-
-/*
- * Volatile isn't enough to prevent the compiler from reordering the
- * read/write functions for the control registers and messing everything up.
- * A memory clobber would solve the problem, but would prevent reordering of
- * all loads stores around it, which can hurt performance. Solution is to
- * use a variable and mimic reads and writes to it to enforce serialization
- */
-static unsigned long __force_order;
-
-static inline unsigned long native_read_cr0(void)
-{
-	unsigned long val;
-	asm volatile("mov %%cr0,%0\n\t" : "=r" (val), "=m" (__force_order));
-	return val;
-}
-
-static inline void native_write_cr0(unsigned long val)
-{
-	asm volatile("mov %0,%%cr0": : "r" (val), "m" (__force_order));
-}
-
-static inline unsigned long native_read_cr2(void)
-{
-	unsigned long val;
-	asm volatile("mov %%cr2,%0\n\t" : "=r" (val), "=m" (__force_order));
-	return val;
-}
-
-static inline void native_write_cr2(unsigned long val)
-{
-	asm volatile("mov %0,%%cr2": : "r" (val), "m" (__force_order));
-}
-
-static inline unsigned long native_read_cr3(void)
-{
-	unsigned long val;
-	asm volatile("mov %%cr3,%0\n\t" : "=r" (val), "=m" (__force_order));
-	return val;
-}
-
-static inline void native_write_cr3(unsigned long val)
-{
-	asm volatile("mov %0,%%cr3": : "r" (val), "m" (__force_order));
-}
-
-static inline unsigned long native_read_cr4(void)
-{
-	unsigned long val;
-	asm volatile("mov %%cr4,%0\n\t" : "=r" (val), "=m" (__force_order));
-	return val;
-}
-
-static inline unsigned long native_read_cr4_safe(void)
-{
-	unsigned long val;
-	/* This could fault if %cr4 does not exist. In x86_64, a cr4 always
-	 * exists, so it will never fail. */
-#ifdef CONFIG_X86_32
-	asm volatile("1: mov %%cr4, %0\n"
-		     "2:\n"
-		     _ASM_EXTABLE(1b, 2b)
-		     : "=r" (val), "=m" (__force_order) : "0" (0));
-#else
-	val = native_read_cr4();
-#endif
-	return val;
-}
-
-static inline void native_write_cr4(unsigned long val)
-{
-	asm volatile("mov %0,%%cr4": : "r" (val), "m" (__force_order));
-}
-
-#ifdef CONFIG_X86_64
-static inline unsigned long native_read_cr8(void)
-{
-	unsigned long cr8;
-	asm volatile("movq %%cr8,%0" : "=r" (cr8));
-	return cr8;
-}
-
-static inline void native_write_cr8(unsigned long val)
-{
-	asm volatile("movq %0,%%cr8" :: "r" (val) : "memory");
-}
-#endif
-
-static inline void native_wbinvd(void)
-{
-	asm volatile("wbinvd": : :"memory");
-}
-
-#ifdef CONFIG_PARAVIRT
-#include <asm/paravirt.h>
-#else
-
-static inline unsigned long read_cr0(void)
-{
-	return native_read_cr0();
-}
-
-static inline void write_cr0(unsigned long x)
-{
-	native_write_cr0(x);
-}
-
-static inline unsigned long read_cr2(void)
-{
-	return native_read_cr2();
-}
-
-static inline void write_cr2(unsigned long x)
-{
-	native_write_cr2(x);
-}
-
-static inline unsigned long read_cr3(void)
-{
-	return native_read_cr3();
-}
-
-static inline void write_cr3(unsigned long x)
-{
-	native_write_cr3(x);
-}
-
-static inline unsigned long read_cr4(void)
-{
-	return native_read_cr4();
-}
-
-static inline unsigned long read_cr4_safe(void)
-{
-	return native_read_cr4_safe();
-}
-
-static inline void write_cr4(unsigned long x)
-{
-	native_write_cr4(x);
-}
-
-static inline void wbinvd(void)
-{
-	native_wbinvd();
-}
-
-#ifdef CONFIG_X86_64
-
-static inline unsigned long read_cr8(void)
-{
-	return native_read_cr8();
-}
-
-static inline void write_cr8(unsigned long x)
-{
-	native_write_cr8(x);
-}
-
-static inline void load_gs_index(unsigned selector)
-{
-	native_load_gs_index(selector);
-}
-
-#endif
-
-/* Clear the 'TS' bit */
-static inline void clts(void)
-{
-	native_clts();
-}
-
-#endif/* CONFIG_PARAVIRT */
-
-#define stts() write_cr0(read_cr0() | X86_CR0_TS)
-
-#endif /* __KERNEL__ */
-
-static inline void clflush(volatile void *__p)
-{
-	asm volatile("clflush %0" : "+m" (*(volatile char __force *)__p));
-}
-
-#define nop() asm volatile ("nop")
-
-void disable_hlt(void);
-void enable_hlt(void);
-
-void cpu_idle_wait(void);
-
-extern unsigned long arch_align_stack(unsigned long sp);
-extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
-
-void default_idle(void);
-bool set_pm_idle_to_default(void);
-
-void stop_this_cpu(void *dummy);
-
-/*
- * Force strict CPU ordering.
- * And yes, this is required on UP too when we're talking
- * to devices.
- */
-#ifdef CONFIG_X86_32
-/*
- * Some non-Intel clones support out of order store. wmb() ceases to be a
- * nop for these.
- */
-#define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2)
-#define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2)
-#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM)
-#else
-#define mb() 	asm volatile("mfence":::"memory")
-#define rmb()	asm volatile("lfence":::"memory")
-#define wmb()	asm volatile("sfence" ::: "memory")
-#endif
-
-/**
- * read_barrier_depends - Flush all pending reads that subsequents reads
- * depend on.
- *
- * No data-dependent reads from memory-like regions are ever reordered
- * over this barrier.  All reads preceding this primitive are guaranteed
- * to access memory (but not necessarily other CPUs' caches) before any
- * reads following this primitive that depend on the data return by
- * any of the preceding reads.  This primitive is much lighter weight than
- * rmb() on most CPUs, and is never heavier weight than is
- * rmb().
- *
- * These ordering constraints are respected by both the local CPU
- * and the compiler.
- *
- * Ordering is not guaranteed by anything other than these primitives,
- * not even by data dependencies.  See the documentation for
- * memory_barrier() for examples and URLs to more information.
- *
- * For example, the following code would force ordering (the initial
- * value of "a" is zero, "b" is one, and "p" is "&a"):
- *
- * <programlisting>
- *	CPU 0				CPU 1
- *
- *	b = 2;
- *	memory_barrier();
- *	p = &b;				q = p;
- *					read_barrier_depends();
- *					d = *q;
- * </programlisting>
- *
- * because the read of "*q" depends on the read of "p" and these
- * two reads are separated by a read_barrier_depends().  However,
- * the following code, with the same initial values for "a" and "b":
- *
- * <programlisting>
- *	CPU 0				CPU 1
- *
- *	a = 2;
- *	memory_barrier();
- *	b = 3;				y = b;
- *					read_barrier_depends();
- *					x = a;
- * </programlisting>
- *
- * does not enforce ordering, since there is no data dependency between
- * the read of "a" and the read of "b".  Therefore, on some CPUs, such
- * as Alpha, "y" could be set to 3 and "x" to 0.  Use rmb()
- * in cases like this where there are no data dependencies.
- **/
-
-#define read_barrier_depends()	do { } while (0)
-
-#ifdef CONFIG_SMP
-#define smp_mb()	mb()
-#ifdef CONFIG_X86_PPRO_FENCE
-# define smp_rmb()	rmb()
-#else
-# define smp_rmb()	barrier()
-#endif
-#ifdef CONFIG_X86_OOSTORE
-# define smp_wmb() 	wmb()
-#else
-# define smp_wmb()	barrier()
-#endif
-#define smp_read_barrier_depends()	read_barrier_depends()
-#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
-#else
-#define smp_mb()	barrier()
-#define smp_rmb()	barrier()
-#define smp_wmb()	barrier()
-#define smp_read_barrier_depends()	do { } while (0)
-#define set_mb(var, value) do { var = value; barrier(); } while (0)
-#endif
-
-/*
- * Stop RDTSC speculation. This is needed when you need to use RDTSC
- * (or get_cycles or vread that possibly accesses the TSC) in a defined
- * code region.
- *
- * (Could use an alternative three way for this if there was one.)
- */
-static __always_inline void rdtsc_barrier(void)
-{
-	alternative(ASM_NOP3, "mfence", X86_FEATURE_MFENCE_RDTSC);
-	alternative(ASM_NOP3, "lfence", X86_FEATURE_LFENCE_RDTSC);
-}
-
-/*
- * We handle most unaligned accesses in hardware.  On the other hand
- * unaligned DMA can be quite expensive on some Nehalem processors.
- *
- * Based on this we disable the IP header alignment in network drivers.
- */
-#define NET_IP_ALIGN	0
-#endif /* _ASM_X86_SYSTEM_H */
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index cfd8144..ad6df8c 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -86,7 +86,7 @@
 #define TIF_MCE_NOTIFY		10	/* notify userspace of an MCE */
 #define TIF_USER_RETURN_NOTIFY	11	/* notify kernel of userspace return */
 #define TIF_NOTSC		16	/* TSC is not accessible in userland */
-#define TIF_IA32		17	/* 32bit process */
+#define TIF_IA32		17	/* IA32 compatibility process */
 #define TIF_FORK		18	/* ret_from_fork */
 #define TIF_MEMDIE		20	/* is terminating due to OOM killer */
 #define TIF_DEBUG		21	/* uses debug registers */
@@ -95,6 +95,8 @@
 #define TIF_BLOCKSTEP		25	/* set when we want DEBUGCTLMSR_BTF */
 #define TIF_LAZY_MMU_UPDATES	27	/* task is updating the mmu lazily */
 #define TIF_SYSCALL_TRACEPOINT	28	/* syscall tracepoint instrumentation */
+#define TIF_ADDR32		29	/* 32-bit address space on 64 bits */
+#define TIF_X32			30	/* 32-bit native x86-64 binary */
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
@@ -116,6 +118,8 @@
 #define _TIF_BLOCKSTEP		(1 << TIF_BLOCKSTEP)
 #define _TIF_LAZY_MMU_UPDATES	(1 << TIF_LAZY_MMU_UPDATES)
 #define _TIF_SYSCALL_TRACEPOINT	(1 << TIF_SYSCALL_TRACEPOINT)
+#define _TIF_ADDR32		(1 << TIF_ADDR32)
+#define _TIF_X32		(1 << TIF_X32)
 
 /* work to do in syscall_trace_enter() */
 #define _TIF_WORK_SYSCALL_ENTRY	\
@@ -262,6 +266,18 @@
 	ti->status |= TS_RESTORE_SIGMASK;
 	set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags);
 }
+
+static inline bool is_ia32_task(void)
+{
+#ifdef CONFIG_X86_32
+	return true;
+#endif
+#ifdef CONFIG_IA32_EMULATION
+	if (current_thread_info()->status & TS_COMPAT)
+		return true;
+#endif
+	return false;
+}
 #endif	/* !__ASSEMBLY__ */
 
 #ifndef __ASSEMBLY__
diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
index 169be89..c0e108e 100644
--- a/arch/x86/include/asm/tlbflush.h
+++ b/arch/x86/include/asm/tlbflush.h
@@ -5,7 +5,7 @@
 #include <linux/sched.h>
 
 #include <asm/processor.h>
-#include <asm/system.h>
+#include <asm/special_insns.h>
 
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
index 0012d09..88eae2a 100644
--- a/arch/x86/include/asm/traps.h
+++ b/arch/x86/include/asm/traps.h
@@ -89,4 +89,29 @@
 asmlinkage void mce_threshold_interrupt(void);
 #endif
 
+/* Interrupts/Exceptions */
+enum {
+	X86_TRAP_DE = 0,	/*  0, Divide-by-zero */
+	X86_TRAP_DB,		/*  1, Debug */
+	X86_TRAP_NMI,		/*  2, Non-maskable Interrupt */
+	X86_TRAP_BP,		/*  3, Breakpoint */
+	X86_TRAP_OF,		/*  4, Overflow */
+	X86_TRAP_BR,		/*  5, Bound Range Exceeded */
+	X86_TRAP_UD,		/*  6, Invalid Opcode */
+	X86_TRAP_NM,		/*  7, Device Not Available */
+	X86_TRAP_DF,		/*  8, Double Fault */
+	X86_TRAP_OLD_MF,	/*  9, Coprocessor Segment Overrun */
+	X86_TRAP_TS,		/* 10, Invalid TSS */
+	X86_TRAP_NP,		/* 11, Segment Not Present */
+	X86_TRAP_SS,		/* 12, Stack Segment Fault */
+	X86_TRAP_GP,		/* 13, General Protection Fault */
+	X86_TRAP_PF,		/* 14, Page Fault */
+	X86_TRAP_SPURIOUS,	/* 15, Spurious Interrupt */
+	X86_TRAP_MF,		/* 16, x87 Floating-Point Exception */
+	X86_TRAP_AC,		/* 17, Alignment Check */
+	X86_TRAP_MC,		/* 18, Machine Check */
+	X86_TRAP_XF,		/* 19, SIMD Floating-Point Exception */
+	X86_TRAP_IRET = 32,	/* 32, IRET Exception */
+};
+
 #endif /* _ASM_X86_TRAPS_H */
diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h
index 15d9915..c91e8b9 100644
--- a/arch/x86/include/asm/tsc.h
+++ b/arch/x86/include/asm/tsc.h
@@ -61,7 +61,7 @@
 extern void check_tsc_sync_target(void);
 
 extern int notsc_setup(char *);
-extern void save_sched_clock_state(void);
-extern void restore_sched_clock_state(void);
+extern void tsc_save_sched_clock_state(void);
+extern void tsc_restore_sched_clock_state(void);
 
 #endif /* _ASM_X86_TSC_H */
diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h
index 21f77b8..37cdc9d 100644
--- a/arch/x86/include/asm/unistd.h
+++ b/arch/x86/include/asm/unistd.h
@@ -1,7 +1,17 @@
 #ifndef _ASM_X86_UNISTD_H
 #define _ASM_X86_UNISTD_H 1
 
+/* x32 syscall flag bit */
+#define __X32_SYSCALL_BIT	0x40000000
+
 #ifdef __KERNEL__
+
+# ifdef CONFIG_X86_X32_ABI
+#  define __SYSCALL_MASK (~(__X32_SYSCALL_BIT))
+# else
+#  define __SYSCALL_MASK (~0)
+# endif
+
 # ifdef CONFIG_X86_32
 
 #  include <asm/unistd_32.h>
@@ -14,6 +24,7 @@
 # else
 
 #  include <asm/unistd_64.h>
+#  include <asm/unistd_64_x32.h>
 #  define __ARCH_WANT_COMPAT_SYS_TIME
 
 # endif
@@ -52,8 +63,10 @@
 #else
 # ifdef __i386__
 #  include <asm/unistd_32.h>
-# else
+# elif defined(__LP64__)
 #  include <asm/unistd_64.h>
+# else
+#  include <asm/unistd_x32.h>
 # endif
 #endif
 
diff --git a/arch/x86/include/asm/vgtod.h b/arch/x86/include/asm/vgtod.h
index 815285b..8b38be2 100644
--- a/arch/x86/include/asm/vgtod.h
+++ b/arch/x86/include/asm/vgtod.h
@@ -5,13 +5,8 @@
 #include <linux/clocksource.h>
 
 struct vsyscall_gtod_data {
-	seqlock_t	lock;
+	seqcount_t	seq;
 
-	/* open coded 'struct timespec' */
-	time_t		wall_time_sec;
-	u32		wall_time_nsec;
-
-	struct timezone sys_tz;
 	struct { /* extract of a clocksource struct */
 		int vclock_mode;
 		cycle_t	cycle_last;
@@ -19,8 +14,16 @@
 		u32	mult;
 		u32	shift;
 	} clock;
-	struct timespec wall_to_monotonic;
+
+	/* open coded 'struct timespec' */
+	time_t		wall_time_sec;
+	u32		wall_time_nsec;
+	u32		monotonic_time_nsec;
+	time_t		monotonic_time_sec;
+
+	struct timezone sys_tz;
 	struct timespec wall_time_coarse;
+	struct timespec monotonic_time_coarse;
 };
 extern struct vsyscall_gtod_data vsyscall_gtod_data;
 
diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
index e0f9aa1..5da71c2 100644
--- a/arch/x86/include/asm/virtext.h
+++ b/arch/x86/include/asm/virtext.h
@@ -16,7 +16,6 @@
 #define _ASM_X86_VIRTEX_H
 
 #include <asm/processor.h>
-#include <asm/system.h>
 
 #include <asm/vmx.h>
 #include <asm/svm.h>
diff --git a/arch/x86/include/asm/word-at-a-time.h b/arch/x86/include/asm/word-at-a-time.h
new file mode 100644
index 0000000..6fe6767
--- /dev/null
+++ b/arch/x86/include/asm/word-at-a-time.h
@@ -0,0 +1,46 @@
+#ifndef _ASM_WORD_AT_A_TIME_H
+#define _ASM_WORD_AT_A_TIME_H
+
+/*
+ * This is largely generic for little-endian machines, but the
+ * optimal byte mask counting is probably going to be something
+ * that is architecture-specific. If you have a reliably fast
+ * bit count instruction, that might be better than the multiply
+ * and shift, for example.
+ */
+
+#ifdef CONFIG_64BIT
+
+/*
+ * Jan Achrenius on G+: microoptimized version of
+ * the simpler "(mask & ONEBYTES) * ONEBYTES >> 56"
+ * that works for the bytemasks without having to
+ * mask them first.
+ */
+static inline long count_masked_bytes(unsigned long mask)
+{
+	return mask*0x0001020304050608ul >> 56;
+}
+
+#else	/* 32-bit case */
+
+/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
+static inline long count_masked_bytes(long mask)
+{
+	/* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
+	long a = (0x0ff0001+mask) >> 23;
+	/* Fix the 1 for 00 case */
+	return a & mask;
+}
+
+#endif
+
+#define REPEAT_BYTE(x)	((~0ul / 0xff) * (x))
+
+/* Return the high bit set in the first byte that is a zero */
+static inline unsigned long has_zero(unsigned long a)
+{
+	return ((a - REPEAT_BYTE(0x01)) & ~a) & REPEAT_BYTE(0x80);
+}
+
+#endif /* _ASM_WORD_AT_A_TIME_H */
diff --git a/arch/x86/include/asm/x2apic.h b/arch/x86/include/asm/x2apic.h
index 6bf5b8e..92e54ab 100644
--- a/arch/x86/include/asm/x2apic.h
+++ b/arch/x86/include/asm/x2apic.h
@@ -18,6 +18,11 @@
 	return cpu_online_mask;
 }
 
+static int x2apic_apic_id_valid(int apicid)
+{
+	return 1;
+}
+
 static int x2apic_apic_id_registered(void)
 {
 	return 1;
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index 517d476..baaca8d 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -145,9 +145,11 @@
 /**
  * struct x86_cpuinit_ops - platform specific cpu hotplug setups
  * @setup_percpu_clockev:	set up the per cpu clock event device
+ * @early_percpu_clock_init:	early init of the per cpu clock event device
  */
 struct x86_cpuinit_ops {
 	void (*setup_percpu_clockev)(void);
+	void (*early_percpu_clock_init)(void);
 	void (*fixup_cpu_id)(struct cpuinfo_x86 *c, int node);
 };
 
@@ -160,6 +162,8 @@
  * @is_untracked_pat_range	exclude from PAT logic
  * @nmi_init			enable NMI on cpus
  * @i8042_detect		pre-detect if i8042 controller exists
+ * @save_sched_clock_state:	save state for sched_clock() on suspend
+ * @restore_sched_clock_state:	restore state for sched_clock() on resume
  */
 struct x86_platform_ops {
 	unsigned long (*calibrate_tsc)(void);
@@ -171,6 +175,8 @@
 	void (*nmi_init)(void);
 	unsigned char (*get_nmi_reason)(void);
 	int (*i8042_detect)(void);
+	void (*save_sched_clock_state)(void);
+	void (*restore_sched_clock_state)(void);
 };
 
 struct pci_dev;
diff --git a/arch/x86/include/asm/xen/interface.h b/arch/x86/include/asm/xen/interface.h
index a1f2db5..cbf0c9d 100644
--- a/arch/x86/include/asm/xen/interface.h
+++ b/arch/x86/include/asm/xen/interface.h
@@ -56,6 +56,7 @@
 DEFINE_GUEST_HANDLE(long);
 DEFINE_GUEST_HANDLE(void);
 DEFINE_GUEST_HANDLE(uint64_t);
+DEFINE_GUEST_HANDLE(uint32_t);
 #endif
 
 #ifndef HYPERVISOR_VIRT_START
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index ce664f3..a415b1f 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -239,7 +239,7 @@
 	 * to not preallocating memory for all NR_CPUS
 	 * when we use CPU hotplug.
 	 */
-	if (!cpu_has_x2apic && (apic_id >= 0xff) && enabled)
+	if (!apic->apic_id_valid(apic_id) && enabled)
 		printk(KERN_WARNING PREFIX "x2apic entry ignored\n");
 	else
 		acpi_register_lapic(apic_id, enabled);
@@ -593,7 +593,7 @@
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
 #include <acpi/processor.h>
 
-static void acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
+static void __cpuinitdata acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
 {
 #ifdef CONFIG_ACPI_NUMA
 	int nid;
@@ -642,6 +642,7 @@
 	kfree(buffer.pointer);
 	buffer.length = ACPI_ALLOCATE_BUFFER;
 	buffer.pointer = NULL;
+	lapic = NULL;
 
 	if (!alloc_cpumask_var(&tmp_map, GFP_KERNEL))
 		goto out;
@@ -650,7 +651,7 @@
 		goto free_tmp_map;
 
 	cpumask_copy(tmp_map, cpu_present_mask);
-	acpi_register_lapic(physid, lapic->lapic_flags & ACPI_MADT_ENABLED);
+	acpi_register_lapic(physid, ACPI_MADT_ENABLED);
 
 	/*
 	 * If mp_register_lapic successfully generates a new logical cpu
diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c
index f50e7fb..d2b7f27 100644
--- a/arch/x86/kernel/acpi/cstate.c
+++ b/arch/x86/kernel/acpi/cstate.c
@@ -14,6 +14,7 @@
 #include <acpi/processor.h>
 #include <asm/acpi.h>
 #include <asm/mwait.h>
+#include <asm/special_insns.h>
 
 /*
  * Initialize bm_flags based on the CPU cache properties
diff --git a/arch/x86/kernel/amd_gart_64.c b/arch/x86/kernel/amd_gart_64.c
index b1e7c7f..e6631120 100644
--- a/arch/x86/kernel/amd_gart_64.c
+++ b/arch/x86/kernel/amd_gart_64.c
@@ -477,7 +477,7 @@
 /* allocate and map a coherent mapping */
 static void *
 gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr,
-		    gfp_t flag)
+		    gfp_t flag, struct dma_attrs *attrs)
 {
 	dma_addr_t paddr;
 	unsigned long align_mask;
@@ -500,7 +500,8 @@
 		}
 		__free_pages(page, get_order(size));
 	} else
-		return dma_generic_alloc_coherent(dev, size, dma_addr, flag);
+		return dma_generic_alloc_coherent(dev, size, dma_addr, flag,
+						  attrs);
 
 	return NULL;
 }
@@ -508,7 +509,7 @@
 /* free a coherent mapping */
 static void
 gart_free_coherent(struct device *dev, size_t size, void *vaddr,
-		   dma_addr_t dma_addr)
+		   dma_addr_t dma_addr, struct dma_attrs *attrs)
 {
 	gart_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL, NULL);
 	free_pages((unsigned long)vaddr, get_order(size));
@@ -700,8 +701,8 @@
 	.unmap_sg			= gart_unmap_sg,
 	.map_page			= gart_map_page,
 	.unmap_page			= gart_unmap_page,
-	.alloc_coherent			= gart_alloc_coherent,
-	.free_coherent			= gart_free_coherent,
+	.alloc				= gart_alloc_coherent,
+	.free				= gart_free_coherent,
 	.mapping_error			= gart_mapping_error,
 };
 
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 2eec05b..11544d8 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -383,20 +383,25 @@
 
 static unsigned int reserve_eilvt_offset(int offset, unsigned int new)
 {
-	unsigned int rsvd;			/* 0: uninitialized */
+	unsigned int rsvd, vector;
 
 	if (offset >= APIC_EILVT_NR_MAX)
 		return ~0;
 
-	rsvd = atomic_read(&eilvt_offsets[offset]) & ~APIC_EILVT_MASKED;
+	rsvd = atomic_read(&eilvt_offsets[offset]);
 	do {
-		if (rsvd &&
-		    !eilvt_entry_is_changeable(rsvd, new))
+		vector = rsvd & ~APIC_EILVT_MASKED;	/* 0: unassigned */
+		if (vector && !eilvt_entry_is_changeable(vector, new))
 			/* may not change if vectors are different */
 			return rsvd;
 		rsvd = atomic_cmpxchg(&eilvt_offsets[offset], rsvd, new);
 	} while (rsvd != new);
 
+	rsvd &= ~APIC_EILVT_MASKED;
+	if (rsvd && rsvd != vector)
+		pr_info("LVT offset %d assigned for vector 0x%02x\n",
+			offset, rsvd);
+
 	return new;
 }
 
diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c
index 8c3cdde..359b689 100644
--- a/arch/x86/kernel/apic/apic_flat_64.c
+++ b/arch/x86/kernel/apic/apic_flat_64.c
@@ -180,6 +180,7 @@
 	.name				= "flat",
 	.probe				= flat_probe,
 	.acpi_madt_oem_check		= flat_acpi_madt_oem_check,
+	.apic_id_valid			= default_apic_id_valid,
 	.apic_id_registered		= flat_apic_id_registered,
 
 	.irq_delivery_mode		= dest_LowestPrio,
@@ -337,6 +338,7 @@
 	.name				= "physical flat",
 	.probe				= physflat_probe,
 	.acpi_madt_oem_check		= physflat_acpi_madt_oem_check,
+	.apic_id_valid			= default_apic_id_valid,
 	.apic_id_registered		= flat_apic_id_registered,
 
 	.irq_delivery_mode		= dest_Fixed,
diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c
index 775b82b..634ae6c 100644
--- a/arch/x86/kernel/apic/apic_noop.c
+++ b/arch/x86/kernel/apic/apic_noop.c
@@ -124,6 +124,7 @@
 	.probe				= noop_probe,
 	.acpi_madt_oem_check		= NULL,
 
+	.apic_id_valid			= default_apic_id_valid,
 	.apic_id_registered		= noop_apic_id_registered,
 
 	.irq_delivery_mode		= dest_LowestPrio,
diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c
index 09d3d8c..899803e 100644
--- a/arch/x86/kernel/apic/apic_numachip.c
+++ b/arch/x86/kernel/apic/apic_numachip.c
@@ -56,6 +56,12 @@
 	return get_apic_id(apic_read(APIC_ID));
 }
 
+static int numachip_apic_id_valid(int apicid)
+{
+	/* Trust what bootloader passes in MADT */
+	return 1;
+}
+
 static int numachip_apic_id_registered(void)
 {
 	return physid_isset(read_xapic_id(), phys_cpu_present_map);
@@ -238,6 +244,7 @@
 	.name				= "NumaConnect system",
 	.probe				= numachip_probe,
 	.acpi_madt_oem_check		= numachip_acpi_madt_oem_check,
+	.apic_id_valid			= numachip_apic_id_valid,
 	.apic_id_registered		= numachip_apic_id_registered,
 
 	.irq_delivery_mode		= dest_Fixed,
diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c
index 521bead..0cdec70 100644
--- a/arch/x86/kernel/apic/bigsmp_32.c
+++ b/arch/x86/kernel/apic/bigsmp_32.c
@@ -198,6 +198,7 @@
 	.name				= "bigsmp",
 	.probe				= probe_bigsmp,
 	.acpi_madt_oem_check		= NULL,
+	.apic_id_valid			= default_apic_id_valid,
 	.apic_id_registered		= bigsmp_apic_id_registered,
 
 	.irq_delivery_mode		= dest_Fixed,
diff --git a/arch/x86/kernel/apic/es7000_32.c b/arch/x86/kernel/apic/es7000_32.c
index 5d513bc..e42d1d3b9 100644
--- a/arch/x86/kernel/apic/es7000_32.c
+++ b/arch/x86/kernel/apic/es7000_32.c
@@ -625,6 +625,7 @@
 	.name				= "es7000",
 	.probe				= probe_es7000,
 	.acpi_madt_oem_check		= es7000_acpi_madt_oem_check_cluster,
+	.apic_id_valid			= default_apic_id_valid,
 	.apic_id_registered		= es7000_apic_id_registered,
 
 	.irq_delivery_mode		= dest_LowestPrio,
@@ -690,6 +691,7 @@
 	.name				= "es7000",
 	.probe				= probe_es7000,
 	.acpi_madt_oem_check		= es7000_acpi_madt_oem_check,
+	.apic_id_valid			= default_apic_id_valid,
 	.apic_id_registered		= es7000_apic_id_registered,
 
 	.irq_delivery_mode		= dest_Fixed,
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index fb07275..e88300d 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -64,9 +64,28 @@
 #include <asm/apic.h>
 
 #define __apicdebuginit(type) static type __init
+
 #define for_each_irq_pin(entry, head) \
 	for (entry = head; entry; entry = entry->next)
 
+static void		__init __ioapic_init_mappings(void);
+
+static unsigned int	__io_apic_read  (unsigned int apic, unsigned int reg);
+static void		__io_apic_write (unsigned int apic, unsigned int reg, unsigned int val);
+static void		__io_apic_modify(unsigned int apic, unsigned int reg, unsigned int val);
+
+static struct io_apic_ops io_apic_ops = {
+	.init	= __ioapic_init_mappings,
+	.read	= __io_apic_read,
+	.write	= __io_apic_write,
+	.modify = __io_apic_modify,
+};
+
+void __init set_io_apic_ops(const struct io_apic_ops *ops)
+{
+	io_apic_ops = *ops;
+}
+
 /*
  *      Is the SiS APIC rmw bug present ?
  *      -1 = don't know, 0 = no, 1 = yes
@@ -294,6 +313,22 @@
 	irq_free_desc(at);
 }
 
+static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
+{
+	return io_apic_ops.read(apic, reg);
+}
+
+static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
+{
+	io_apic_ops.write(apic, reg, value);
+}
+
+static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
+{
+	io_apic_ops.modify(apic, reg, value);
+}
+
+
 struct io_apic {
 	unsigned int index;
 	unsigned int unused[3];
@@ -314,16 +349,17 @@
 	writel(vector, &io_apic->eoi);
 }
 
-static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
+static unsigned int __io_apic_read(unsigned int apic, unsigned int reg)
 {
 	struct io_apic __iomem *io_apic = io_apic_base(apic);
 	writel(reg, &io_apic->index);
 	return readl(&io_apic->data);
 }
 
-static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
+static void __io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
 {
 	struct io_apic __iomem *io_apic = io_apic_base(apic);
+
 	writel(reg, &io_apic->index);
 	writel(value, &io_apic->data);
 }
@@ -334,7 +370,7 @@
  *
  * Older SiS APIC requires we rewrite the index register
  */
-static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
+static void __io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
 {
 	struct io_apic __iomem *io_apic = io_apic_base(apic);
 
@@ -377,6 +413,7 @@
 
 	eu.w1 = io_apic_read(apic, 0x10 + 2 * pin);
 	eu.w2 = io_apic_read(apic, 0x11 + 2 * pin);
+
 	return eu.entry;
 }
 
@@ -384,9 +421,11 @@
 {
 	union entry_union eu;
 	unsigned long flags;
+
 	raw_spin_lock_irqsave(&ioapic_lock, flags);
 	eu.entry = __ioapic_read_entry(apic, pin);
 	raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+
 	return eu.entry;
 }
 
@@ -396,8 +435,7 @@
  * the interrupt, and we need to make sure the entry is fully populated
  * before that happens.
  */
-static void
-__ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
+static void __ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
 {
 	union entry_union eu = {{0, 0}};
 
@@ -409,6 +447,7 @@
 static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
 {
 	unsigned long flags;
+
 	raw_spin_lock_irqsave(&ioapic_lock, flags);
 	__ioapic_write_entry(apic, pin, e);
 	raw_spin_unlock_irqrestore(&ioapic_lock, flags);
@@ -435,8 +474,7 @@
  * shared ISA-space IRQs, so we have to support them. We are super
  * fast in the common case, and fast for shared ISA-space IRQs.
  */
-static int
-__add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
+static int __add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
 {
 	struct irq_pin_list **last, *entry;
 
@@ -521,6 +559,7 @@
 	 * a dummy read from the IO-APIC
 	 */
 	struct io_apic __iomem *io_apic;
+
 	io_apic = io_apic_base(entry->apic);
 	readl(&io_apic->data);
 }
@@ -2512,20 +2551,72 @@
 
 atomic_t irq_mis_count;
 
+#ifdef CONFIG_GENERIC_PENDING_IRQ
+static inline bool ioapic_irqd_mask(struct irq_data *data, struct irq_cfg *cfg)
+{
+	/* If we are moving the irq we need to mask it */
+	if (unlikely(irqd_is_setaffinity_pending(data))) {
+		mask_ioapic(cfg);
+		return true;
+	}
+	return false;
+}
+
+static inline void ioapic_irqd_unmask(struct irq_data *data,
+				      struct irq_cfg *cfg, bool masked)
+{
+	if (unlikely(masked)) {
+		/* Only migrate the irq if the ack has been received.
+		 *
+		 * On rare occasions the broadcast level triggered ack gets
+		 * delayed going to ioapics, and if we reprogram the
+		 * vector while Remote IRR is still set the irq will never
+		 * fire again.
+		 *
+		 * To prevent this scenario we read the Remote IRR bit
+		 * of the ioapic.  This has two effects.
+		 * - On any sane system the read of the ioapic will
+		 *   flush writes (and acks) going to the ioapic from
+		 *   this cpu.
+		 * - We get to see if the ACK has actually been delivered.
+		 *
+		 * Based on failed experiments of reprogramming the
+		 * ioapic entry from outside of irq context starting
+		 * with masking the ioapic entry and then polling until
+		 * Remote IRR was clear before reprogramming the
+		 * ioapic I don't trust the Remote IRR bit to be
+		 * completey accurate.
+		 *
+		 * However there appears to be no other way to plug
+		 * this race, so if the Remote IRR bit is not
+		 * accurate and is causing problems then it is a hardware bug
+		 * and you can go talk to the chipset vendor about it.
+		 */
+		if (!io_apic_level_ack_pending(cfg))
+			irq_move_masked_irq(data);
+		unmask_ioapic(cfg);
+	}
+}
+#else
+static inline bool ioapic_irqd_mask(struct irq_data *data, struct irq_cfg *cfg)
+{
+	return false;
+}
+static inline void ioapic_irqd_unmask(struct irq_data *data,
+				      struct irq_cfg *cfg, bool masked)
+{
+}
+#endif
+
 static void ack_apic_level(struct irq_data *data)
 {
 	struct irq_cfg *cfg = data->chip_data;
-	int i, do_unmask_irq = 0, irq = data->irq;
+	int i, irq = data->irq;
 	unsigned long v;
+	bool masked;
 
 	irq_complete_move(cfg);
-#ifdef CONFIG_GENERIC_PENDING_IRQ
-	/* If we are moving the irq we need to mask it */
-	if (unlikely(irqd_is_setaffinity_pending(data))) {
-		do_unmask_irq = 1;
-		mask_ioapic(cfg);
-	}
-#endif
+	masked = ioapic_irqd_mask(data, cfg);
 
 	/*
 	 * It appears there is an erratum which affects at least version 0x11
@@ -2581,38 +2672,7 @@
 		eoi_ioapic_irq(irq, cfg);
 	}
 
-	/* Now we can move and renable the irq */
-	if (unlikely(do_unmask_irq)) {
-		/* Only migrate the irq if the ack has been received.
-		 *
-		 * On rare occasions the broadcast level triggered ack gets
-		 * delayed going to ioapics, and if we reprogram the
-		 * vector while Remote IRR is still set the irq will never
-		 * fire again.
-		 *
-		 * To prevent this scenario we read the Remote IRR bit
-		 * of the ioapic.  This has two effects.
-		 * - On any sane system the read of the ioapic will
-		 *   flush writes (and acks) going to the ioapic from
-		 *   this cpu.
-		 * - We get to see if the ACK has actually been delivered.
-		 *
-		 * Based on failed experiments of reprogramming the
-		 * ioapic entry from outside of irq context starting
-		 * with masking the ioapic entry and then polling until
-		 * Remote IRR was clear before reprogramming the
-		 * ioapic I don't trust the Remote IRR bit to be
-		 * completey accurate.
-		 *
-		 * However there appears to be no other way to plug
-		 * this race, so if the Remote IRR bit is not
-		 * accurate and is causing problems then it is a hardware bug
-		 * and you can go talk to the chipset vendor about it.
-		 */
-		if (!io_apic_level_ack_pending(cfg))
-			irq_move_masked_irq(data);
-		unmask_ioapic(cfg);
-	}
+	ioapic_irqd_unmask(data, cfg, masked);
 }
 
 #ifdef CONFIG_IRQ_REMAP
@@ -3873,6 +3933,11 @@
 
 void __init ioapic_and_gsi_init(void)
 {
+	io_apic_ops.init();
+}
+
+static void __init __ioapic_init_mappings(void)
+{
 	unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
 	struct resource *ioapic_res;
 	int i;
@@ -3967,18 +4032,36 @@
 static __init int bad_ioapic(unsigned long address)
 {
 	if (nr_ioapics >= MAX_IO_APICS) {
-		printk(KERN_WARNING "WARNING: Max # of I/O APICs (%d) exceeded "
-		       "(found %d), skipping\n", MAX_IO_APICS, nr_ioapics);
+		pr_warn("WARNING: Max # of I/O APICs (%d) exceeded (found %d), skipping\n",
+			MAX_IO_APICS, nr_ioapics);
 		return 1;
 	}
 	if (!address) {
-		printk(KERN_WARNING "WARNING: Bogus (zero) I/O APIC address"
-		       " found in table, skipping!\n");
+		pr_warn("WARNING: Bogus (zero) I/O APIC address found in table, skipping!\n");
 		return 1;
 	}
 	return 0;
 }
 
+static __init int bad_ioapic_register(int idx)
+{
+	union IO_APIC_reg_00 reg_00;
+	union IO_APIC_reg_01 reg_01;
+	union IO_APIC_reg_02 reg_02;
+
+	reg_00.raw = io_apic_read(idx, 0);
+	reg_01.raw = io_apic_read(idx, 1);
+	reg_02.raw = io_apic_read(idx, 2);
+
+	if (reg_00.raw == -1 && reg_01.raw == -1 && reg_02.raw == -1) {
+		pr_warn("I/O APIC 0x%x registers return all ones, skipping!\n",
+			mpc_ioapic_addr(idx));
+		return 1;
+	}
+
+	return 0;
+}
+
 void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
 {
 	int idx = 0;
@@ -3995,6 +4078,12 @@
 	ioapics[idx].mp_config.apicaddr = address;
 
 	set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
+
+	if (bad_ioapic_register(idx)) {
+		clear_fixmap(FIX_IO_APIC_BASE_0 + idx);
+		return;
+	}
+
 	ioapics[idx].mp_config.apicid = io_apic_unique_id(id);
 	ioapics[idx].mp_config.apicver = io_apic_get_version(idx);
 
@@ -4015,10 +4104,10 @@
 	if (gsi_cfg->gsi_end >= gsi_top)
 		gsi_top = gsi_cfg->gsi_end + 1;
 
-	printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, "
-	       "GSI %d-%d\n", idx, mpc_ioapic_id(idx),
-	       mpc_ioapic_ver(idx), mpc_ioapic_addr(idx),
-	       gsi_cfg->gsi_base, gsi_cfg->gsi_end);
+	pr_info("IOAPIC[%d]: apic_id %d, version %d, address 0x%x, GSI %d-%d\n",
+		idx, mpc_ioapic_id(idx),
+		mpc_ioapic_ver(idx), mpc_ioapic_addr(idx),
+		gsi_cfg->gsi_base, gsi_cfg->gsi_end);
 
 	nr_ioapics++;
 }
diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c
index c4a61ca..00d2422 100644
--- a/arch/x86/kernel/apic/numaq_32.c
+++ b/arch/x86/kernel/apic/numaq_32.c
@@ -478,6 +478,7 @@
 	.name				= "NUMAQ",
 	.probe				= probe_numaq,
 	.acpi_madt_oem_check		= NULL,
+	.apic_id_valid			= default_apic_id_valid,
 	.apic_id_registered		= numaq_apic_id_registered,
 
 	.irq_delivery_mode		= dest_LowestPrio,
diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c
index 0787bb3..ff2c1b9 100644
--- a/arch/x86/kernel/apic/probe_32.c
+++ b/arch/x86/kernel/apic/probe_32.c
@@ -92,6 +92,7 @@
 	.name				= "default",
 	.probe				= probe_default,
 	.acpi_madt_oem_check		= NULL,
+	.apic_id_valid			= default_apic_id_valid,
 	.apic_id_registered		= default_apic_id_registered,
 
 	.irq_delivery_mode		= dest_LowestPrio,
diff --git a/arch/x86/kernel/apic/summit_32.c b/arch/x86/kernel/apic/summit_32.c
index 1911442..fea000b 100644
--- a/arch/x86/kernel/apic/summit_32.c
+++ b/arch/x86/kernel/apic/summit_32.c
@@ -496,6 +496,7 @@
 	.name				= "summit",
 	.probe				= probe_summit,
 	.acpi_madt_oem_check		= summit_acpi_madt_oem_check,
+	.apic_id_valid			= default_apic_id_valid,
 	.apic_id_registered		= summit_apic_id_registered,
 
 	.irq_delivery_mode		= dest_LowestPrio,
diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c
index 5007958..48f3103 100644
--- a/arch/x86/kernel/apic/x2apic_cluster.c
+++ b/arch/x86/kernel/apic/x2apic_cluster.c
@@ -213,6 +213,7 @@
 	.name				= "cluster x2apic",
 	.probe				= x2apic_cluster_probe,
 	.acpi_madt_oem_check		= x2apic_acpi_madt_oem_check,
+	.apic_id_valid			= x2apic_apic_id_valid,
 	.apic_id_registered		= x2apic_apic_id_registered,
 
 	.irq_delivery_mode		= dest_LowestPrio,
diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c
index f5373df..8a778db 100644
--- a/arch/x86/kernel/apic/x2apic_phys.c
+++ b/arch/x86/kernel/apic/x2apic_phys.c
@@ -119,6 +119,7 @@
 	.name				= "physical x2apic",
 	.probe				= x2apic_phys_probe,
 	.acpi_madt_oem_check		= x2apic_acpi_madt_oem_check,
+	.apic_id_valid			= x2apic_apic_id_valid,
 	.apic_id_registered		= x2apic_apic_id_registered,
 
 	.irq_delivery_mode		= dest_Fixed,
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 79b05b8..87bfa69 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -266,6 +266,11 @@
 	uv_send_IPI_mask(cpu_online_mask, vector);
 }
 
+static int uv_apic_id_valid(int apicid)
+{
+	return 1;
+}
+
 static int uv_apic_id_registered(void)
 {
 	return 1;
@@ -351,6 +356,7 @@
 	.name				= "UV large system",
 	.probe				= uv_probe,
 	.acpi_madt_oem_check		= uv_acpi_madt_oem_check,
+	.apic_id_valid			= uv_apic_id_valid,
 	.apic_id_registered		= uv_apic_id_registered,
 
 	.irq_delivery_mode		= dest_Fixed,
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index 5d56931..459e78c 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -231,7 +231,6 @@
 #include <linux/syscore_ops.h>
 #include <linux/i8253.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/desc.h>
 #include <asm/olpc.h>
diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c
index 834e897..1b4754f 100644
--- a/arch/x86/kernel/asm-offsets_64.c
+++ b/arch/x86/kernel/asm-offsets_64.c
@@ -1,6 +1,12 @@
 #include <asm/ia32.h>
 
 #define __SYSCALL_64(nr, sym, compat) [nr] = 1,
+#define __SYSCALL_COMMON(nr, sym, compat) [nr] = 1,
+#ifdef CONFIG_X86_X32_ABI
+# define __SYSCALL_X32(nr, sym, compat) [nr] = 1,
+#else
+# define __SYSCALL_X32(nr, sym, compat) /* nothing */
+#endif
 static char syscalls_64[] = {
 #include <asm/syscalls_64.h>
 };
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index c0f7d68..67e2583 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -18,6 +18,7 @@
 #include <asm/archrandom.h>
 #include <asm/hypervisor.h>
 #include <asm/processor.h>
+#include <asm/debugreg.h>
 #include <asm/sections.h>
 #include <linux/topology.h>
 #include <linux/cpumask.h>
@@ -28,6 +29,7 @@
 #include <asm/apic.h>
 #include <asm/desc.h>
 #include <asm/i387.h>
+#include <asm/fpu-internal.h>
 #include <asm/mtrr.h>
 #include <linux/numa.h>
 #include <asm/asm.h>
@@ -933,7 +935,7 @@
 	{ 0xc0011000, 0xc001103b},
 };
 
-static void __cpuinit print_cpu_msr(void)
+static void __cpuinit __print_cpu_msr(void)
 {
 	unsigned index_min, index_max;
 	unsigned index;
@@ -997,13 +999,13 @@
 	else
 		printk(KERN_CONT "\n");
 
-#ifdef CONFIG_SMP
+	print_cpu_msr(c);
+}
+
+void __cpuinit print_cpu_msr(struct cpuinfo_x86 *c)
+{
 	if (c->cpu_index < show_msr)
-		print_cpu_msr();
-#else
-	if (show_msr)
-		print_cpu_msr();
-#endif
+		__print_cpu_msr();
 }
 
 static __init int setup_disablecpuid(char *arg)
@@ -1045,7 +1047,6 @@
 DEFINE_PER_CPU(unsigned int, irq_count) = -1;
 
 DEFINE_PER_CPU(struct task_struct *, fpu_owner_task);
-EXPORT_PER_CPU_SYMBOL(fpu_owner_task);
 
 /*
  * Special IST stacks which the CPU switches to when it calls
@@ -1115,7 +1116,6 @@
 DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
 EXPORT_PER_CPU_SYMBOL(current_task);
 DEFINE_PER_CPU(struct task_struct *, fpu_owner_task);
-EXPORT_PER_CPU_SYMBOL(fpu_owner_task);
 
 #ifdef CONFIG_CC_STACKPROTECTOR
 DEFINE_PER_CPU_ALIGNED(struct stack_canary, stack_canary);
diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c
index 7395d5f..0c82091 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-severity.c
+++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c
@@ -54,7 +54,14 @@
 #define  MASK(x, y)	.mask = x, .result = y
 #define MCI_UC_S (MCI_STATUS_UC|MCI_STATUS_S)
 #define MCI_UC_SAR (MCI_STATUS_UC|MCI_STATUS_S|MCI_STATUS_AR)
+#define	MCI_ADDR (MCI_STATUS_ADDRV|MCI_STATUS_MISCV)
 #define MCACOD 0xffff
+/* Architecturally defined codes from SDM Vol. 3B Chapter 15 */
+#define MCACOD_SCRUB	0x00C0	/* 0xC0-0xCF Memory Scrubbing */
+#define MCACOD_SCRUBMSK	0xfff0
+#define MCACOD_L3WB	0x017A	/* L3 Explicit Writeback */
+#define MCACOD_DATA	0x0134	/* Data Load */
+#define MCACOD_INSTR	0x0150	/* Instruction Fetch */
 
 	MCESEV(
 		NO, "Invalid",
@@ -102,11 +109,24 @@
 		SER, BITCLR(MCI_STATUS_S)
 		),
 
-	/* AR add known MCACODs here */
 	MCESEV(
 		PANIC, "Action required with lost events",
 		SER, BITSET(MCI_STATUS_OVER|MCI_UC_SAR)
 		),
+
+	/* known AR MCACODs: */
+#ifdef	CONFIG_MEMORY_FAILURE
+	MCESEV(
+		KEEP, "HT thread notices Action required: data load error",
+		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA),
+		MCGMASK(MCG_STATUS_EIPV, 0)
+		),
+	MCESEV(
+		AR, "Action required: data load error",
+		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA),
+		USER
+		),
+#endif
 	MCESEV(
 		PANIC, "Action required: unknown MCACOD",
 		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_SAR)
@@ -115,11 +135,11 @@
 	/* known AO MCACODs: */
 	MCESEV(
 		AO, "Action optional: memory scrubbing error",
-		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|0xfff0, MCI_UC_S|0x00c0)
+		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCACOD_SCRUBMSK, MCI_UC_S|MCACOD_SCRUB)
 		),
 	MCESEV(
 		AO, "Action optional: last level cache writeback error",
-		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCACOD, MCI_UC_S|0x017a)
+		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCACOD, MCI_UC_S|MCACOD_L3WB)
 		),
 	MCESEV(
 		SOME, "Action optional: unknown MCACOD",
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 5a11ae2..d086a09 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -191,7 +191,7 @@
 {
 	unsigned int next, i, prev = 0;
 
-	next = rcu_dereference_check_mce(mcelog.next);
+	next = ACCESS_ONCE(mcelog.next);
 
 	do {
 		struct mce *m;
@@ -540,6 +540,27 @@
 	irq_work_queue(&__get_cpu_var(mce_irq_work));
 }
 
+/*
+ * Read ADDR and MISC registers.
+ */
+static void mce_read_aux(struct mce *m, int i)
+{
+	if (m->status & MCI_STATUS_MISCV)
+		m->misc = mce_rdmsrl(MSR_IA32_MCx_MISC(i));
+	if (m->status & MCI_STATUS_ADDRV) {
+		m->addr = mce_rdmsrl(MSR_IA32_MCx_ADDR(i));
+
+		/*
+		 * Mask the reported address by the reported granularity.
+		 */
+		if (mce_ser && (m->status & MCI_STATUS_MISCV)) {
+			u8 shift = MCI_MISC_ADDR_LSB(m->misc);
+			m->addr >>= shift;
+			m->addr <<= shift;
+		}
+	}
+}
+
 DEFINE_PER_CPU(unsigned, mce_poll_count);
 
 /*
@@ -590,10 +611,7 @@
 		    (m.status & (mce_ser ? MCI_STATUS_S : MCI_STATUS_UC)))
 			continue;
 
-		if (m.status & MCI_STATUS_MISCV)
-			m.misc = mce_rdmsrl(MSR_IA32_MCx_MISC(i));
-		if (m.status & MCI_STATUS_ADDRV)
-			m.addr = mce_rdmsrl(MSR_IA32_MCx_ADDR(i));
+		mce_read_aux(&m, i);
 
 		if (!(flags & MCP_TIMESTAMP))
 			m.tsc = 0;
@@ -917,6 +935,49 @@
 }
 
 /*
+ * Need to save faulting physical address associated with a process
+ * in the machine check handler some place where we can grab it back
+ * later in mce_notify_process()
+ */
+#define	MCE_INFO_MAX	16
+
+struct mce_info {
+	atomic_t		inuse;
+	struct task_struct	*t;
+	__u64			paddr;
+} mce_info[MCE_INFO_MAX];
+
+static void mce_save_info(__u64 addr)
+{
+	struct mce_info *mi;
+
+	for (mi = mce_info; mi < &mce_info[MCE_INFO_MAX]; mi++) {
+		if (atomic_cmpxchg(&mi->inuse, 0, 1) == 0) {
+			mi->t = current;
+			mi->paddr = addr;
+			return;
+		}
+	}
+
+	mce_panic("Too many concurrent recoverable errors", NULL, NULL);
+}
+
+static struct mce_info *mce_find_info(void)
+{
+	struct mce_info *mi;
+
+	for (mi = mce_info; mi < &mce_info[MCE_INFO_MAX]; mi++)
+		if (atomic_read(&mi->inuse) && mi->t == current)
+			return mi;
+	return NULL;
+}
+
+static void mce_clear_info(struct mce_info *mi)
+{
+	atomic_set(&mi->inuse, 0);
+}
+
+/*
  * The actual machine check handler. This only handles real
  * exceptions when something got corrupted coming in through int 18.
  *
@@ -969,7 +1030,9 @@
 	barrier();
 
 	/*
-	 * When no restart IP must always kill or panic.
+	 * When no restart IP might need to kill or panic.
+	 * Assume the worst for now, but if we find the
+	 * severity is MCE_AR_SEVERITY we have other options.
 	 */
 	if (!(m.mcgstatus & MCG_STATUS_RIPV))
 		kill_it = 1;
@@ -1023,16 +1086,7 @@
 			continue;
 		}
 
-		/*
-		 * Kill on action required.
-		 */
-		if (severity == MCE_AR_SEVERITY)
-			kill_it = 1;
-
-		if (m.status & MCI_STATUS_MISCV)
-			m.misc = mce_rdmsrl(MSR_IA32_MCx_MISC(i));
-		if (m.status & MCI_STATUS_ADDRV)
-			m.addr = mce_rdmsrl(MSR_IA32_MCx_ADDR(i));
+		mce_read_aux(&m, i);
 
 		/*
 		 * Action optional error. Queue address for later processing.
@@ -1052,6 +1106,9 @@
 		}
 	}
 
+	/* mce_clear_state will clear *final, save locally for use later */
+	m = *final;
+
 	if (!no_way_out)
 		mce_clear_state(toclear);
 
@@ -1063,27 +1120,22 @@
 		no_way_out = worst >= MCE_PANIC_SEVERITY;
 
 	/*
-	 * If we have decided that we just CAN'T continue, and the user
-	 * has not set tolerant to an insane level, give up and die.
-	 *
-	 * This is mainly used in the case when the system doesn't
-	 * support MCE broadcasting or it has been disabled.
+	 * At insane "tolerant" levels we take no action. Otherwise
+	 * we only die if we have no other choice. For less serious
+	 * issues we try to recover, or limit damage to the current
+	 * process.
 	 */
-	if (no_way_out && tolerant < 3)
-		mce_panic("Fatal machine check on current CPU", final, msg);
-
-	/*
-	 * If the error seems to be unrecoverable, something should be
-	 * done.  Try to kill as little as possible.  If we can kill just
-	 * one task, do that.  If the user has set the tolerance very
-	 * high, don't try to do anything at all.
-	 */
-
-	if (kill_it && tolerant < 3)
-		force_sig(SIGBUS, current);
-
-	/* notify userspace ASAP */
-	set_thread_flag(TIF_MCE_NOTIFY);
+	if (tolerant < 3) {
+		if (no_way_out)
+			mce_panic("Fatal machine check on current CPU", &m, msg);
+		if (worst == MCE_AR_SEVERITY) {
+			/* schedule action before return to userland */
+			mce_save_info(m.addr);
+			set_thread_flag(TIF_MCE_NOTIFY);
+		} else if (kill_it) {
+			force_sig(SIGBUS, current);
+		}
+	}
 
 	if (worst > 0)
 		mce_report_event(regs);
@@ -1094,34 +1146,57 @@
 }
 EXPORT_SYMBOL_GPL(do_machine_check);
 
-/* dummy to break dependency. actual code is in mm/memory-failure.c */
-void __attribute__((weak)) memory_failure(unsigned long pfn, int vector)
+#ifndef CONFIG_MEMORY_FAILURE
+int memory_failure(unsigned long pfn, int vector, int flags)
 {
-	printk(KERN_ERR "Action optional memory failure at %lx ignored\n", pfn);
+	/* mce_severity() should not hand us an ACTION_REQUIRED error */
+	BUG_ON(flags & MF_ACTION_REQUIRED);
+	printk(KERN_ERR "Uncorrected memory error in page 0x%lx ignored\n"
+		"Rebuild kernel with CONFIG_MEMORY_FAILURE=y for smarter handling\n", pfn);
+
+	return 0;
 }
+#endif
 
 /*
- * Called after mce notification in process context. This code
- * is allowed to sleep. Call the high level VM handler to process
- * any corrupted pages.
- * Assume that the work queue code only calls this one at a time
- * per CPU.
- * Note we don't disable preemption, so this code might run on the wrong
- * CPU. In this case the event is picked up by the scheduled work queue.
- * This is merely a fast path to expedite processing in some common
- * cases.
+ * Called in process context that interrupted by MCE and marked with
+ * TIF_MCE_NOTIFY, just before returning to erroneous userland.
+ * This code is allowed to sleep.
+ * Attempt possible recovery such as calling the high level VM handler to
+ * process any corrupted pages, and kill/signal current process if required.
+ * Action required errors are handled here.
  */
 void mce_notify_process(void)
 {
 	unsigned long pfn;
-	mce_notify_irq();
-	while (mce_ring_get(&pfn))
-		memory_failure(pfn, MCE_VECTOR);
+	struct mce_info *mi = mce_find_info();
+
+	if (!mi)
+		mce_panic("Lost physical address for unconsumed uncorrectable error", NULL, NULL);
+	pfn = mi->paddr >> PAGE_SHIFT;
+
+	clear_thread_flag(TIF_MCE_NOTIFY);
+
+	pr_err("Uncorrected hardware memory error in user-access at %llx",
+		 mi->paddr);
+	if (memory_failure(pfn, MCE_VECTOR, MF_ACTION_REQUIRED) < 0) {
+		pr_err("Memory error not recovered");
+		force_sig(SIGBUS, current);
+	}
+	mce_clear_info(mi);
 }
 
+/*
+ * Action optional processing happens here (picking up
+ * from the list of faulting pages that do_machine_check()
+ * placed into the "ring").
+ */
 static void mce_process_work(struct work_struct *dummy)
 {
-	mce_notify_process();
+	unsigned long pfn;
+
+	while (mce_ring_get(&pfn))
+		memory_failure(pfn, MCE_VECTOR, 0);
 }
 
 #ifdef CONFIG_X86_MCE_INTEL
@@ -1211,8 +1286,6 @@
 	/* Not more than two messages every minute */
 	static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2);
 
-	clear_thread_flag(TIF_MCE_NOTIFY);
-
 	if (test_and_clear_bit(0, &mce_need_notify)) {
 		/* wake processes polling /dev/mcelog */
 		wake_up_interruptible(&mce_chrdev_wait);
@@ -1541,6 +1614,12 @@
 	/* Error or no more MCE record */
 	if (rc <= 0) {
 		mce_apei_read_done = 1;
+		/*
+		 * When ERST is disabled, mce_chrdev_read() should return
+		 * "no record" instead of "no device."
+		 */
+		if (rc == -ENODEV)
+			return 0;
 		return rc;
 	}
 	rc = -EFAULT;
@@ -1859,7 +1938,7 @@
 	.dev_name	= "machinecheck",
 };
 
-struct device *mce_device[CONFIG_NR_CPUS];
+DEFINE_PER_CPU(struct device *, mce_device);
 
 __cpuinitdata
 void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu);
@@ -2038,7 +2117,7 @@
 			goto error2;
 	}
 	cpumask_set_cpu(cpu, mce_device_initialized);
-	mce_device[cpu] = dev;
+	per_cpu(mce_device, cpu) = dev;
 
 	return 0;
 error2:
@@ -2055,7 +2134,7 @@
 
 static __cpuinit void mce_device_remove(unsigned int cpu)
 {
-	struct device *dev = mce_device[cpu];
+	struct device *dev = per_cpu(mce_device, cpu);
 	int i;
 
 	if (!cpumask_test_cpu(cpu, mce_device_initialized))
@@ -2069,7 +2148,7 @@
 
 	device_unregister(dev);
 	cpumask_clear_cpu(cpu, mce_device_initialized);
-	mce_device[cpu] = NULL;
+	per_cpu(mce_device, cpu) = NULL;
 }
 
 /* Make sure there are no machine checks on offlined CPUs. */
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index e4eeaaf..99b5717 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -523,7 +523,7 @@
 {
 	int i, err = 0;
 	struct threshold_bank *b = NULL;
-	struct device *dev = mce_device[cpu];
+	struct device *dev = per_cpu(mce_device, cpu);
 	char name[32];
 
 	sprintf(name, "threshold_bank%i", bank);
@@ -587,7 +587,7 @@
 		if (i == cpu)
 			continue;
 
-		dev = mce_device[i];
+		dev = per_cpu(mce_device, i);
 		if (dev)
 			err = sysfs_create_link(&dev->kobj,b->kobj, name);
 		if (err)
@@ -667,7 +667,8 @@
 #ifdef CONFIG_SMP
 	/* sibling symlink */
 	if (shared_bank[bank] && b->blocks->cpu != cpu) {
-		sysfs_remove_link(&mce_device[cpu]->kobj, name);
+		dev = per_cpu(mce_device, cpu);
+		sysfs_remove_link(&dev->kobj, name);
 		per_cpu(threshold_banks, cpu)[bank] = NULL;
 
 		return;
@@ -679,7 +680,7 @@
 		if (i == cpu)
 			continue;
 
-		dev = mce_device[i];
+		dev = per_cpu(mce_device, i);
 		if (dev)
 			sysfs_remove_link(&dev->kobj, name);
 		per_cpu(threshold_banks, i)[bank] = NULL;
diff --git a/arch/x86/kernel/cpu/mcheck/p5.c b/arch/x86/kernel/cpu/mcheck/p5.c
index 5c0e653..2d5454c 100644
--- a/arch/x86/kernel/cpu/mcheck/p5.c
+++ b/arch/x86/kernel/cpu/mcheck/p5.c
@@ -9,7 +9,6 @@
 #include <linux/smp.h>
 
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/mce.h>
 #include <asm/msr.h>
 
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c
index 67bb17a..47a1870 100644
--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c
@@ -25,7 +25,6 @@
 #include <linux/cpu.h>
 
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/apic.h>
 #include <asm/idle.h>
 #include <asm/mce.h>
diff --git a/arch/x86/kernel/cpu/mcheck/winchip.c b/arch/x86/kernel/cpu/mcheck/winchip.c
index 54060f5..2d7998f 100644
--- a/arch/x86/kernel/cpu/mcheck/winchip.c
+++ b/arch/x86/kernel/cpu/mcheck/winchip.c
@@ -8,7 +8,6 @@
 #include <linux/init.h>
 
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/mce.h>
 #include <asm/msr.h>
 
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c
index 97b2635..75772ae 100644
--- a/arch/x86/kernel/cpu/mtrr/generic.c
+++ b/arch/x86/kernel/cpu/mtrr/generic.c
@@ -12,7 +12,6 @@
 #include <asm/processor-flags.h>
 #include <asm/cpufeature.h>
 #include <asm/tlbflush.h>
-#include <asm/system.h>
 #include <asm/mtrr.h>
 #include <asm/msr.h>
 #include <asm/pat.h>
diff --git a/arch/x86/kernel/cpu/mtrr/if.c b/arch/x86/kernel/cpu/mtrr/if.c
index 7928963..a041e09 100644
--- a/arch/x86/kernel/cpu/mtrr/if.c
+++ b/arch/x86/kernel/cpu/mtrr/if.c
@@ -167,6 +167,7 @@
 {
 	int err = 0;
 	mtrr_type type;
+	unsigned long base;
 	unsigned long size;
 	struct mtrr_sentry sentry;
 	struct mtrr_gentry gentry;
@@ -267,14 +268,14 @@
 #endif
 		if (gentry.regnum >= num_var_ranges)
 			return -EINVAL;
-		mtrr_if->get(gentry.regnum, &gentry.base, &size, &type);
+		mtrr_if->get(gentry.regnum, &base, &size, &type);
 
 		/* Hide entries that go above 4GB */
-		if (gentry.base + size - 1 >= (1UL << (8 * sizeof(gentry.size) - PAGE_SHIFT))
+		if (base + size - 1 >= (1UL << (8 * sizeof(gentry.size) - PAGE_SHIFT))
 		    || size >= (1UL << (8 * sizeof(gentry.size) - PAGE_SHIFT)))
 			gentry.base = gentry.size = gentry.type = 0;
 		else {
-			gentry.base <<= PAGE_SHIFT;
+			gentry.base = base << PAGE_SHIFT;
 			gentry.size = size << PAGE_SHIFT;
 			gentry.type = type;
 		}
@@ -321,11 +322,12 @@
 #endif
 		if (gentry.regnum >= num_var_ranges)
 			return -EINVAL;
-		mtrr_if->get(gentry.regnum, &gentry.base, &size, &type);
+		mtrr_if->get(gentry.regnum, &base, &size, &type);
 		/* Hide entries that would overflow */
 		if (size != (__typeof__(gentry.size))size)
 			gentry.base = gentry.size = gentry.type = 0;
 		else {
+			gentry.base = base;
 			gentry.size = size;
 			gentry.type = type;
 		}
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 0a18d16..bb8e034 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -29,7 +29,6 @@
 #include <asm/apic.h>
 #include <asm/stacktrace.h>
 #include <asm/nmi.h>
-#include <asm/compat.h>
 #include <asm/smp.h>
 #include <asm/alternative.h>
 #include <asm/timer.h>
@@ -643,14 +642,14 @@
 	/* Prefer fixed purpose counters */
 	if (x86_pmu.num_counters_fixed) {
 		idx = X86_PMC_IDX_FIXED;
-		for_each_set_bit_cont(idx, c->idxmsk, X86_PMC_IDX_MAX) {
+		for_each_set_bit_from(idx, c->idxmsk, X86_PMC_IDX_MAX) {
 			if (!__test_and_set_bit(idx, sched->state.used))
 				goto done;
 		}
 	}
 	/* Grab the first unused counter starting with idx */
 	idx = sched->state.counter;
-	for_each_set_bit_cont(idx, c->idxmsk, X86_PMC_IDX_FIXED) {
+	for_each_set_bit_from(idx, c->idxmsk, X86_PMC_IDX_FIXED) {
 		if (!__test_and_set_bit(idx, sched->state.used))
 			goto done;
 	}
@@ -1314,6 +1313,11 @@
 	pr_info("no hardware sampling interrupt available.\n");
 }
 
+static struct attribute_group x86_pmu_format_group = {
+	.name = "format",
+	.attrs = NULL,
+};
+
 static int __init init_hw_perf_events(void)
 {
 	struct x86_pmu_quirk *quirk;
@@ -1388,6 +1392,7 @@
 	}
 
 	x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
+	x86_pmu_format_group.attrs = x86_pmu.format_attrs;
 
 	pr_info("... version:                %d\n",     x86_pmu.version);
 	pr_info("... bit width:              %d\n",     x86_pmu.cntval_bits);
@@ -1616,6 +1621,9 @@
 {
 	int idx = event->hw.idx;
 
+	if (!x86_pmu.attr_rdpmc)
+		return 0;
+
 	if (x86_pmu.num_counters_fixed && idx >= X86_PMC_IDX_FIXED) {
 		idx -= X86_PMC_IDX_FIXED;
 		idx |= 1 << 30;
@@ -1668,6 +1676,7 @@
 
 static const struct attribute_group *x86_pmu_attr_groups[] = {
 	&x86_pmu_attr_group,
+	&x86_pmu_format_group,
 	NULL,
 };
 
@@ -1699,14 +1708,19 @@
 	.flush_branch_stack	= x86_pmu_flush_branch_stack,
 };
 
-void perf_update_user_clock(struct perf_event_mmap_page *userpg, u64 now)
+void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
 {
+	userpg->cap_usr_time = 0;
+	userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc;
+	userpg->pmc_width = x86_pmu.cntval_bits;
+
 	if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
 		return;
 
 	if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
 		return;
 
+	userpg->cap_usr_time = 1;
 	userpg->time_mult = this_cpu_read(cyc2ns);
 	userpg->time_shift = CYC2NS_SCALE_FACTOR;
 	userpg->time_offset = this_cpu_read(cyc2ns_offset) - now;
@@ -1748,6 +1762,9 @@
 }
 
 #ifdef CONFIG_COMPAT
+
+#include <asm/compat.h>
+
 static inline int
 perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
 {
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index 8484e77..6638aaf 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -339,6 +339,7 @@
 	 * sysfs attrs
 	 */
 	int		attr_rdpmc;
+	struct attribute **format_attrs;
 
 	/*
 	 * CPU Hotplug hooks
diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c
index dd002fa..95e7fe1 100644
--- a/arch/x86/kernel/cpu/perf_event_amd.c
+++ b/arch/x86/kernel/cpu/perf_event_amd.c
@@ -404,6 +404,21 @@
 	}
 }
 
+PMU_FORMAT_ATTR(event,	"config:0-7,32-35");
+PMU_FORMAT_ATTR(umask,	"config:8-15"	);
+PMU_FORMAT_ATTR(edge,	"config:18"	);
+PMU_FORMAT_ATTR(inv,	"config:23"	);
+PMU_FORMAT_ATTR(cmask,	"config:24-31"	);
+
+static struct attribute *amd_format_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+	NULL,
+};
+
 static __initconst const struct x86_pmu amd_pmu = {
 	.name			= "AMD",
 	.handle_irq		= x86_pmu_handle_irq,
@@ -426,6 +441,8 @@
 	.get_event_constraints	= amd_get_event_constraints,
 	.put_event_constraints	= amd_put_event_constraints,
 
+	.format_attrs		= amd_format_attr,
+
 	.cpu_prepare		= amd_pmu_cpu_prepare,
 	.cpu_starting		= amd_pmu_cpu_starting,
 	.cpu_dead		= amd_pmu_cpu_dead,
@@ -596,6 +613,7 @@
 	.cpu_dead		= amd_pmu_cpu_dead,
 #endif
 	.cpu_starting		= amd_pmu_cpu_starting,
+	.format_attrs		= amd_format_attr,
 };
 
 __init int amd_pmu_init(void)
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 6a84e7f..26b3e2f 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -1431,6 +1431,24 @@
 	}
 }
 
+PMU_FORMAT_ATTR(event,	"config:0-7"	);
+PMU_FORMAT_ATTR(umask,	"config:8-15"	);
+PMU_FORMAT_ATTR(edge,	"config:18"	);
+PMU_FORMAT_ATTR(pc,	"config:19"	);
+PMU_FORMAT_ATTR(any,	"config:21"	); /* v3 + */
+PMU_FORMAT_ATTR(inv,	"config:23"	);
+PMU_FORMAT_ATTR(cmask,	"config:24-31"	);
+
+static struct attribute *intel_arch_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_pc.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+	NULL,
+};
+
 static __initconst const struct x86_pmu core_pmu = {
 	.name			= "core",
 	.handle_irq		= x86_pmu_handle_irq,
@@ -1455,6 +1473,7 @@
 	.put_event_constraints	= intel_put_event_constraints,
 	.event_constraints	= intel_core_event_constraints,
 	.guest_get_msrs		= core_guest_get_msrs,
+	.format_attrs		= intel_arch_formats_attr,
 };
 
 struct intel_shared_regs *allocate_shared_regs(int cpu)
@@ -1553,6 +1572,21 @@
 		intel_pmu_lbr_reset();
 }
 
+PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63");
+
+static struct attribute *intel_arch3_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_pc.attr,
+	&format_attr_any.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+
+	&format_attr_offcore_rsp.attr, /* XXX do NHM/WSM + SNB breakout */
+	NULL,
+};
+
 static __initconst const struct x86_pmu intel_pmu = {
 	.name			= "Intel",
 	.handle_irq		= intel_pmu_handle_irq,
@@ -1576,6 +1610,8 @@
 	.get_event_constraints	= intel_get_event_constraints,
 	.put_event_constraints	= intel_put_event_constraints,
 
+	.format_attrs		= intel_arch3_formats_attr,
+
 	.cpu_prepare		= intel_pmu_cpu_prepare,
 	.cpu_starting		= intel_pmu_cpu_starting,
 	.cpu_dying		= intel_pmu_cpu_dying,
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c
index ef484d9..a2dfacf 100644
--- a/arch/x86/kernel/cpu/perf_event_p4.c
+++ b/arch/x86/kernel/cpu/perf_event_p4.c
@@ -1271,6 +1271,17 @@
 	return num ? -EINVAL : 0;
 }
 
+PMU_FORMAT_ATTR(cccr, "config:0-31" );
+PMU_FORMAT_ATTR(escr, "config:32-62");
+PMU_FORMAT_ATTR(ht,   "config:63"   );
+
+static struct attribute *intel_p4_formats_attr[] = {
+	&format_attr_cccr.attr,
+	&format_attr_escr.attr,
+	&format_attr_ht.attr,
+	NULL,
+};
+
 static __initconst const struct x86_pmu p4_pmu = {
 	.name			= "Netburst P4/Xeon",
 	.handle_irq		= p4_pmu_handle_irq,
@@ -1305,6 +1316,8 @@
 	 * the former idea is taken from OProfile code
 	 */
 	.perfctr_second_write	= 1,
+
+	.format_attrs		= intel_p4_formats_attr,
 };
 
 __init int p4_pmu_init(void)
diff --git a/arch/x86/kernel/cpu/perf_event_p6.c b/arch/x86/kernel/cpu/perf_event_p6.c
index c7181be..32bcfc7 100644
--- a/arch/x86/kernel/cpu/perf_event_p6.c
+++ b/arch/x86/kernel/cpu/perf_event_p6.c
@@ -87,6 +87,23 @@
 	(void)checking_wrmsrl(hwc->config_base, val);
 }
 
+PMU_FORMAT_ATTR(event,	"config:0-7"	);
+PMU_FORMAT_ATTR(umask,	"config:8-15"	);
+PMU_FORMAT_ATTR(edge,	"config:18"	);
+PMU_FORMAT_ATTR(pc,	"config:19"	);
+PMU_FORMAT_ATTR(inv,	"config:23"	);
+PMU_FORMAT_ATTR(cmask,	"config:24-31"	);
+
+static struct attribute *intel_p6_formats_attr[] = {
+	&format_attr_event.attr,
+	&format_attr_umask.attr,
+	&format_attr_edge.attr,
+	&format_attr_pc.attr,
+	&format_attr_inv.attr,
+	&format_attr_cmask.attr,
+	NULL,
+};
+
 static __initconst const struct x86_pmu p6_pmu = {
 	.name			= "p6",
 	.handle_irq		= x86_pmu_handle_irq,
@@ -115,6 +132,8 @@
 	.cntval_mask		= (1ULL << 32) - 1,
 	.get_event_constraints	= x86_get_event_constraints,
 	.event_constraints	= p6_event_constraints,
+
+	.format_attrs		= intel_p6_formats_attr,
 };
 
 __init int p6_pmu_init(void)
diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c
index a524353..39472dd 100644
--- a/arch/x86/kernel/cpuid.c
+++ b/arch/x86/kernel/cpuid.c
@@ -43,7 +43,6 @@
 
 #include <asm/processor.h>
 #include <asm/msr.h>
-#include <asm/system.h>
 
 static struct class *cpuid_class;
 
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 4025fe4..1b81839 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -37,13 +37,16 @@
 			const struct stacktrace_ops *ops,
 			struct thread_info *tinfo, int *graph)
 {
-	struct task_struct *task = tinfo->task;
+	struct task_struct *task;
 	unsigned long ret_addr;
-	int index = task->curr_ret_stack;
+	int index;
 
 	if (addr != (unsigned long)return_to_handler)
 		return;
 
+	task = tinfo->task;
+	index = task->curr_ret_stack;
+
 	if (!task->ret_stack || index < *graph)
 		return;
 
@@ -265,7 +268,7 @@
 #endif
 	printk("\n");
 	if (notify_die(DIE_OOPS, str, regs, err,
-			current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
+			current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP)
 		return 1;
 
 	show_registers(regs);
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index c99f9ed..88ec912 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -87,7 +87,7 @@
 	int i;
 
 	print_modules();
-	__show_regs(regs, 0);
+	__show_regs(regs, !user_mode_vm(regs));
 
 	printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)\n",
 		TASK_COMM_LEN, current->comm, task_pid_nr(current),
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 79d97e6..7b784f4 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -98,12 +98,6 @@
 #endif
 .endm
 
-#ifdef CONFIG_VM86
-#define resume_userspace_sig	check_userspace
-#else
-#define resume_userspace_sig	resume_userspace
-#endif
-
 /*
  * User gs save/restore
  *
@@ -327,10 +321,19 @@
 	preempt_stop(CLBR_ANY)
 ret_from_intr:
 	GET_THREAD_INFO(%ebp)
-check_userspace:
+resume_userspace_sig:
+#ifdef CONFIG_VM86
 	movl PT_EFLAGS(%esp), %eax	# mix EFLAGS and CS
 	movb PT_CS(%esp), %al
 	andl $(X86_EFLAGS_VM | SEGMENT_RPL_MASK), %eax
+#else
+	/*
+	 * We can be coming here from a syscall done in the kernel space,
+	 * e.g. a failed kernel_execve().
+	 */
+	movl PT_CS(%esp), %eax
+	andl $SEGMENT_RPL_MASK, %eax
+#endif
 	cmpl $USER_RPL, %eax
 	jb resume_kernel		# not returning to v8086 or userspace
 
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 1333d98..cdc79b5 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -320,7 +320,7 @@
 	movq %rsp, %rsi
 
 	leaq -RBP(%rsp),%rdi	/* arg1 for handler */
-	testl $3, CS(%rdi)
+	testl $3, CS-RBP(%rsi)
 	je 1f
 	SWAPGS
 	/*
@@ -330,11 +330,10 @@
 	 * moving irq_enter into assembly, which would be too much work)
 	 */
 1:	incl PER_CPU_VAR(irq_count)
-	jne 2f
-	mov PER_CPU_VAR(irq_stack_ptr),%rsp
+	cmovzq PER_CPU_VAR(irq_stack_ptr),%rsp
 	CFI_DEF_CFA_REGISTER	rsi
 
-2:	/* Store previous stack value */
+	/* Store previous stack value */
 	pushq %rsi
 	CFI_ESCAPE	0x0f /* DW_CFA_def_cfa_expression */, 6, \
 			0x77 /* DW_OP_breg7 */, 0, \
@@ -482,7 +481,12 @@
 	testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	jnz tracesys
 system_call_fastpath:
+#if __SYSCALL_MASK == ~0
 	cmpq $__NR_syscall_max,%rax
+#else
+	andl $__SYSCALL_MASK,%eax
+	cmpl $__NR_syscall_max,%eax
+#endif
 	ja badsys
 	movq %r10,%rcx
 	call *sys_call_table(,%rax,8)  # XXX:	 rip relative
@@ -596,7 +600,12 @@
 	 */
 	LOAD_ARGS ARGOFFSET, 1
 	RESTORE_REST
+#if __SYSCALL_MASK == ~0
 	cmpq $__NR_syscall_max,%rax
+#else
+	andl $__SYSCALL_MASK,%eax
+	cmpl $__NR_syscall_max,%eax
+#endif
 	ja   int_ret_from_sys_call	/* RAX(%rsp) set to -ENOSYS above */
 	movq %r10,%rcx	/* fixup for C */
 	call *sys_call_table(,%rax,8)
@@ -736,6 +745,40 @@
 	CFI_ENDPROC
 END(stub_rt_sigreturn)
 
+#ifdef CONFIG_X86_X32_ABI
+	PTREGSCALL stub_x32_sigaltstack, sys32_sigaltstack, %rdx
+
+ENTRY(stub_x32_rt_sigreturn)
+	CFI_STARTPROC
+	addq $8, %rsp
+	PARTIAL_FRAME 0
+	SAVE_REST
+	movq %rsp,%rdi
+	FIXUP_TOP_OF_STACK %r11
+	call sys32_x32_rt_sigreturn
+	movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
+	RESTORE_REST
+	jmp int_ret_from_sys_call
+	CFI_ENDPROC
+END(stub_x32_rt_sigreturn)
+
+ENTRY(stub_x32_execve)
+	CFI_STARTPROC
+	addq $8, %rsp
+	PARTIAL_FRAME 0
+	SAVE_REST
+	FIXUP_TOP_OF_STACK %r11
+	movq %rsp, %rcx
+	call sys32_execve
+	RESTORE_TOP_OF_STACK %r11
+	movq %rax,RAX(%rsp)
+	RESTORE_REST
+	jmp int_ret_from_sys_call
+	CFI_ENDPROC
+END(stub_x32_execve)
+
+#endif
+
 /*
  * Build the entry stubs and pointer table with some assembler magic.
  * We pack 7 stubs into a single 32-byte chunk, which will fit in a
@@ -813,7 +856,7 @@
 
 	/* Restore saved previous stack */
 	popq %rsi
-	CFI_DEF_CFA_REGISTER	rsi
+	CFI_DEF_CFA rsi,SS+8-RBP	/* reg/off reset after def_cfa_expr */
 	leaq ARGOFFSET-RBP(%rsi), %rsp
 	CFI_DEF_CFA_REGISTER	rsp
 	CFI_ADJUST_CFA_OFFSET	RBP-ARGOFFSET
@@ -1530,6 +1573,7 @@
 
 	/* Use %rdx as out temp variable throughout */
 	pushq_cfi %rdx
+	CFI_REL_OFFSET rdx, 0
 
 	/*
 	 * If %cs was not the kernel segment, then the NMI triggered in user
@@ -1554,6 +1598,7 @@
 	 */
 	lea 6*8(%rsp), %rdx
 	test_in_nmi rdx, 4*8(%rsp), nested_nmi, first_nmi
+	CFI_REMEMBER_STATE
 
 nested_nmi:
 	/*
@@ -1585,10 +1630,12 @@
 
 nested_nmi_out:
 	popq_cfi %rdx
+	CFI_RESTORE rdx
 
 	/* No need to check faults here */
 	INTERRUPT_RETURN
 
+	CFI_RESTORE_STATE
 first_nmi:
 	/*
 	 * Because nested NMIs will use the pushed location that we
@@ -1620,10 +1667,15 @@
 	 * | pt_regs                 |
 	 * +-------------------------+
 	 *
-	 * The saved RIP is used to fix up the copied RIP that a nested
-	 * NMI may zero out. The original stack frame and the temp storage
+	 * The saved stack frame is used to fix up the copied stack frame
+	 * that a nested NMI may change to make the interrupted NMI iret jump
+	 * to the repeat_nmi. The original stack frame and the temp storage
 	 * is also used by nested NMIs and can not be trusted on exit.
 	 */
+	/* Do not pop rdx, nested NMIs will corrupt that part of the stack */
+	movq (%rsp), %rdx
+	CFI_RESTORE rdx
+
 	/* Set the NMI executing variable on the stack. */
 	pushq_cfi $1
 
@@ -1631,22 +1683,39 @@
 	.rept 5
 	pushq_cfi 6*8(%rsp)
 	.endr
+	CFI_DEF_CFA_OFFSET SS+8-RIP
+
+	/* Everything up to here is safe from nested NMIs */
+
+	/*
+	 * If there was a nested NMI, the first NMI's iret will return
+	 * here. But NMIs are still enabled and we can take another
+	 * nested NMI. The nested NMI checks the interrupted RIP to see
+	 * if it is between repeat_nmi and end_repeat_nmi, and if so
+	 * it will just return, as we are about to repeat an NMI anyway.
+	 * This makes it safe to copy to the stack frame that a nested
+	 * NMI will update.
+	 */
+repeat_nmi:
+	/*
+	 * Update the stack variable to say we are still in NMI (the update
+	 * is benign for the non-repeat case, where 1 was pushed just above
+	 * to this very stack slot).
+	 */
+	movq $1, 5*8(%rsp)
 
 	/* Make another copy, this one may be modified by nested NMIs */
 	.rept 5
 	pushq_cfi 4*8(%rsp)
 	.endr
-
-	/* Do not pop rdx, nested NMIs will corrupt it */
-	movq 11*8(%rsp), %rdx
+	CFI_DEF_CFA_OFFSET SS+8-RIP
+end_repeat_nmi:
 
 	/*
 	 * Everything below this point can be preempted by a nested
-	 * NMI if the first NMI took an exception. Repeated NMIs
-	 * caused by an exception and nested NMI will start here, and
-	 * can still be preempted by another NMI.
+	 * NMI if the first NMI took an exception and reset our iret stack
+	 * so that we repeat another NMI.
 	 */
-restart_nmi:
 	pushq_cfi $-1		/* ORIG_RAX: no syscall to restart */
 	subq $ORIG_RAX-R15, %rsp
 	CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
@@ -1675,26 +1744,6 @@
 	CFI_ENDPROC
 END(nmi)
 
-	/*
-	 * If an NMI hit an iret because of an exception or breakpoint,
-	 * it can lose its NMI context, and a nested NMI may come in.
-	 * In that case, the nested NMI will change the preempted NMI's
-	 * stack to jump to here when it does the final iret.
-	 */
-repeat_nmi:
-	INTR_FRAME
-	/* Update the stack variable to say we are still in NMI */
-	movq $1, 5*8(%rsp)
-
-	/* copy the saved stack back to copy stack */
-	.rept 5
-	pushq_cfi 4*8(%rsp)
-	.endr
-
-	jmp restart_nmi
-	CFI_ENDPROC
-end_repeat_nmi:
-
 ENTRY(ignore_sysret)
 	CFI_STARTPROC
 	mov $-ENOSYS,%eax
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index 739d859..7734bcb 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -16,6 +16,7 @@
 #include <asm/uaccess.h>
 #include <asm/ptrace.h>
 #include <asm/i387.h>
+#include <asm/fpu-internal.h>
 #include <asm/user.h>
 
 #ifdef CONFIG_X86_64
@@ -32,6 +33,86 @@
 # define user32_fxsr_struct	user_fxsr_struct
 #endif
 
+/*
+ * Were we in an interrupt that interrupted kernel mode?
+ *
+ * We can do a kernel_fpu_begin/end() pair *ONLY* if that
+ * pair does nothing at all: the thread must not have fpu (so
+ * that we don't try to save the FPU state), and TS must
+ * be set (so that the clts/stts pair does nothing that is
+ * visible in the interrupted kernel thread).
+ */
+static inline bool interrupted_kernel_fpu_idle(void)
+{
+	return !__thread_has_fpu(current) &&
+		(read_cr0() & X86_CR0_TS);
+}
+
+/*
+ * Were we in user mode (or vm86 mode) when we were
+ * interrupted?
+ *
+ * Doing kernel_fpu_begin/end() is ok if we are running
+ * in an interrupt context from user mode - we'll just
+ * save the FPU state as required.
+ */
+static inline bool interrupted_user_mode(void)
+{
+	struct pt_regs *regs = get_irq_regs();
+	return regs && user_mode_vm(regs);
+}
+
+/*
+ * Can we use the FPU in kernel mode with the
+ * whole "kernel_fpu_begin/end()" sequence?
+ *
+ * It's always ok in process context (ie "not interrupt")
+ * but it is sometimes ok even from an irq.
+ */
+bool irq_fpu_usable(void)
+{
+	return !in_interrupt() ||
+		interrupted_user_mode() ||
+		interrupted_kernel_fpu_idle();
+}
+EXPORT_SYMBOL(irq_fpu_usable);
+
+void kernel_fpu_begin(void)
+{
+	struct task_struct *me = current;
+
+	WARN_ON_ONCE(!irq_fpu_usable());
+	preempt_disable();
+	if (__thread_has_fpu(me)) {
+		__save_init_fpu(me);
+		__thread_clear_has_fpu(me);
+		/* We do 'stts()' in kernel_fpu_end() */
+	} else {
+		percpu_write(fpu_owner_task, NULL);
+		clts();
+	}
+}
+EXPORT_SYMBOL(kernel_fpu_begin);
+
+void kernel_fpu_end(void)
+{
+	stts();
+	preempt_enable();
+}
+EXPORT_SYMBOL(kernel_fpu_end);
+
+void unlazy_fpu(struct task_struct *tsk)
+{
+	preempt_disable();
+	if (__thread_has_fpu(tsk)) {
+		__save_init_fpu(tsk);
+		__thread_fpu_end(tsk);
+	} else
+		tsk->fpu_counter = 0;
+	preempt_enable();
+}
+EXPORT_SYMBOL(unlazy_fpu);
+
 #ifdef CONFIG_MATH_EMULATION
 # define HAVE_HWFP		(boot_cpu_data.hard_math)
 #else
@@ -44,7 +125,7 @@
 unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32);
 static struct i387_fxsave_struct fx_scratch __cpuinitdata;
 
-void __cpuinit mxcsr_feature_mask_init(void)
+static void __cpuinit mxcsr_feature_mask_init(void)
 {
 	unsigned long mask = 0;
 
diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c
index 6104852..36d1853 100644
--- a/arch/x86/kernel/i8259.c
+++ b/arch/x86/kernel/i8259.c
@@ -15,7 +15,6 @@
 #include <linux/delay.h>
 
 #include <linux/atomic.h>
-#include <asm/system.h>
 #include <asm/timer.h>
 #include <asm/hw_irq.h>
 #include <asm/pgtable.h>
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 7943e0c..3dafc60 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -282,8 +282,13 @@
 		else if (!(warned++))
 			set_affinity = 0;
 
+		/*
+		 * We unmask if the irq was not marked masked by the
+		 * core code. That respects the lazy irq disable
+		 * behaviour.
+		 */
 		if (!irqd_can_move_in_process_context(data) &&
-		    !irqd_irq_disabled(data) && chip->irq_unmask)
+		    !irqd_irq_masked(data) && chip->irq_unmask)
 			chip->irq_unmask(data);
 
 		raw_spin_unlock(&desc->lock);
diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c
index 313fb5c..252981a 100644
--- a/arch/x86/kernel/irqinit.c
+++ b/arch/x86/kernel/irqinit.c
@@ -16,7 +16,6 @@
 #include <linux/delay.h>
 
 #include <linux/atomic.h>
-#include <asm/system.h>
 #include <asm/timer.h>
 #include <asm/hw_irq.h>
 #include <asm/pgtable.h>
@@ -61,7 +60,7 @@
 	outb(0, 0xF0);
 	if (ignore_fpu_irq || !boot_cpu_data.hard_math)
 		return IRQ_NONE;
-	math_error(get_irq_regs(), 0, 16);
+	math_error(get_irq_regs(), 0, X86_TRAP_MF);
 	return IRQ_HANDLED;
 }
 
@@ -306,10 +305,10 @@
 	 * us. (some of these will be overridden and become
 	 * 'special' SMP interrupts)
 	 */
-	for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) {
+	i = FIRST_EXTERNAL_VECTOR;
+	for_each_clear_bit_from(i, used_vectors, NR_VECTORS) {
 		/* IA32_SYSCALL_VECTOR could be used in trap_init already. */
-		if (!test_bit(i, used_vectors))
-			set_intr_gate(i, interrupt[i-FIRST_EXTERNAL_VECTOR]);
+		set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]);
 	}
 
 	if (!acpi_ioapic && !of_ioapic)
diff --git a/arch/x86/kernel/kdebugfs.c b/arch/x86/kernel/kdebugfs.c
index 90fcf62..1d5d31e 100644
--- a/arch/x86/kernel/kdebugfs.c
+++ b/arch/x86/kernel/kdebugfs.c
@@ -68,16 +68,9 @@
 	return count;
 }
 
-static int setup_data_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-
-	return 0;
-}
-
 static const struct file_operations fops_setup_data = {
 	.read		= setup_data_read,
-	.open		= setup_data_open,
+	.open		= simple_open,
 	.llseek		= default_llseek,
 };
 
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
index faba577..8bfb614 100644
--- a/arch/x86/kernel/kgdb.c
+++ b/arch/x86/kernel/kgdb.c
@@ -43,10 +43,11 @@
 #include <linux/smp.h>
 #include <linux/nmi.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/uaccess.h>
+#include <linux/memory.h>
 
 #include <asm/debugreg.h>
 #include <asm/apicdef.h>
-#include <asm/system.h>
 #include <asm/apic.h>
 #include <asm/nmi.h>
 
@@ -67,8 +68,6 @@
 	{ "ss", 4, offsetof(struct pt_regs, ss) },
 	{ "ds", 4, offsetof(struct pt_regs, ds) },
 	{ "es", 4, offsetof(struct pt_regs, es) },
-	{ "fs", 4, -1 },
-	{ "gs", 4, -1 },
 #else
 	{ "ax", 8, offsetof(struct pt_regs, ax) },
 	{ "bx", 8, offsetof(struct pt_regs, bx) },
@@ -90,7 +89,11 @@
 	{ "flags", 4, offsetof(struct pt_regs, flags) },
 	{ "cs", 4, offsetof(struct pt_regs, cs) },
 	{ "ss", 4, offsetof(struct pt_regs, ss) },
+	{ "ds", 4, -1 },
+	{ "es", 4, -1 },
 #endif
+	{ "fs", 4, -1 },
+	{ "gs", 4, -1 },
 };
 
 int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
@@ -740,6 +743,64 @@
 	regs->ip = ip;
 }
 
+int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
+{
+	int err;
+	char opc[BREAK_INSTR_SIZE];
+
+	bpt->type = BP_BREAKPOINT;
+	err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr,
+				BREAK_INSTR_SIZE);
+	if (err)
+		return err;
+	err = probe_kernel_write((char *)bpt->bpt_addr,
+				 arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE);
+#ifdef CONFIG_DEBUG_RODATA
+	if (!err)
+		return err;
+	/*
+	 * It is safe to call text_poke() because normal kernel execution
+	 * is stopped on all cores, so long as the text_mutex is not locked.
+	 */
+	if (mutex_is_locked(&text_mutex))
+		return -EBUSY;
+	text_poke((void *)bpt->bpt_addr, arch_kgdb_ops.gdb_bpt_instr,
+		  BREAK_INSTR_SIZE);
+	err = probe_kernel_read(opc, (char *)bpt->bpt_addr, BREAK_INSTR_SIZE);
+	if (err)
+		return err;
+	if (memcmp(opc, arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE))
+		return -EINVAL;
+	bpt->type = BP_POKE_BREAKPOINT;
+#endif /* CONFIG_DEBUG_RODATA */
+	return err;
+}
+
+int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
+{
+#ifdef CONFIG_DEBUG_RODATA
+	int err;
+	char opc[BREAK_INSTR_SIZE];
+
+	if (bpt->type != BP_POKE_BREAKPOINT)
+		goto knl_write;
+	/*
+	 * It is safe to call text_poke() because normal kernel execution
+	 * is stopped on all cores, so long as the text_mutex is not locked.
+	 */
+	if (mutex_is_locked(&text_mutex))
+		goto knl_write;
+	text_poke((void *)bpt->bpt_addr, bpt->saved_instr, BREAK_INSTR_SIZE);
+	err = probe_kernel_read(opc, (char *)bpt->bpt_addr, BREAK_INSTR_SIZE);
+	if (err || memcmp(opc, bpt->saved_instr, BREAK_INSTR_SIZE))
+		goto knl_write;
+	return err;
+knl_write:
+#endif /* CONFIG_DEBUG_RODATA */
+	return probe_kernel_write((char *)bpt->bpt_addr,
+				  (char *)bpt->saved_instr, BREAK_INSTR_SIZE);
+}
+
 struct kgdb_arch arch_kgdb_ops = {
 	/* Breakpoint instruction: */
 	.gdb_bpt_instr		= { 0xcc },
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
index 44842d7..f8492da6 100644
--- a/arch/x86/kernel/kvmclock.c
+++ b/arch/x86/kernel/kvmclock.c
@@ -136,6 +136,15 @@
 	return ret;
 }
 
+static void kvm_save_sched_clock_state(void)
+{
+}
+
+static void kvm_restore_sched_clock_state(void)
+{
+	kvm_register_clock("primary cpu clock, resume");
+}
+
 #ifdef CONFIG_X86_LOCAL_APIC
 static void __cpuinit kvm_setup_secondary_clock(void)
 {
@@ -144,8 +153,6 @@
 	 * we shouldn't fail.
 	 */
 	WARN_ON(kvm_register_clock("secondary cpu clock"));
-	/* ok, done with our trickery, call native */
-	setup_secondary_APIC_clock();
 }
 #endif
 
@@ -194,9 +201,11 @@
 	x86_platform.get_wallclock = kvm_get_wallclock;
 	x86_platform.set_wallclock = kvm_set_wallclock;
 #ifdef CONFIG_X86_LOCAL_APIC
-	x86_cpuinit.setup_percpu_clockev =
+	x86_cpuinit.early_percpu_clock_init =
 		kvm_setup_secondary_clock;
 #endif
+	x86_platform.save_sched_clock_state = kvm_save_sched_clock_state;
+	x86_platform.restore_sched_clock_state = kvm_restore_sched_clock_state;
 	machine_ops.shutdown  = kvm_shutdown;
 #ifdef CONFIG_KEXEC
 	machine_ops.crash_shutdown  = kvm_crash_shutdown;
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
index ea69726..ebc9873 100644
--- a/arch/x86/kernel/ldt.c
+++ b/arch/x86/kernel/ldt.c
@@ -15,7 +15,6 @@
 #include <linux/vmalloc.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 #include <asm/ldt.h>
 #include <asm/desc.h>
 #include <asm/mmu_context.h>
diff --git a/arch/x86/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c
index a3fa43b..5b19e4d 100644
--- a/arch/x86/kernel/machine_kexec_32.c
+++ b/arch/x86/kernel/machine_kexec_32.c
@@ -23,7 +23,6 @@
 #include <asm/apic.h>
 #include <asm/cpufeature.h>
 #include <asm/desc.h>
-#include <asm/system.h>
 #include <asm/cacheflush.h>
 #include <asm/debugreg.h>
 
diff --git a/arch/x86/kernel/mca_32.c b/arch/x86/kernel/mca_32.c
index 177183c..7eb1e2b 100644
--- a/arch/x86/kernel/mca_32.c
+++ b/arch/x86/kernel/mca_32.c
@@ -43,7 +43,6 @@
 #include <linux/mca.h>
 #include <linux/kprobes.h>
 #include <linux/slab.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <linux/proc_fs.h>
 #include <linux/mman.h>
diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c
index 925179f..f21fd94 100644
--- a/arch/x86/kernel/module.c
+++ b/arch/x86/kernel/module.c
@@ -26,7 +26,6 @@
 #include <linux/gfp.h>
 #include <linux/jump_label.h>
 
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
index 9635676..eb11369 100644
--- a/arch/x86/kernel/msr.c
+++ b/arch/x86/kernel/msr.c
@@ -40,7 +40,6 @@
 
 #include <asm/processor.h>
 #include <asm/msr.h>
-#include <asm/system.h>
 
 static struct class *msr_class;
 
diff --git a/arch/x86/kernel/nmi_selftest.c b/arch/x86/kernel/nmi_selftest.c
index 0d01a8e..2c39dcd 100644
--- a/arch/x86/kernel/nmi_selftest.c
+++ b/arch/x86/kernel/nmi_selftest.c
@@ -12,6 +12,7 @@
 #include <linux/smp.h>
 #include <linux/cpumask.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/apic.h>
 #include <asm/nmi.h>
@@ -20,35 +21,35 @@
 #define FAILURE		1
 #define TIMEOUT		2
 
-static int nmi_fail;
+static int __initdata nmi_fail;
 
 /* check to see if NMI IPIs work on this machine */
-static DECLARE_BITMAP(nmi_ipi_mask, NR_CPUS) __read_mostly;
+static DECLARE_BITMAP(nmi_ipi_mask, NR_CPUS) __initdata;
 
-static int testcase_total;
-static int testcase_successes;
-static int expected_testcase_failures;
-static int unexpected_testcase_failures;
-static int unexpected_testcase_unknowns;
+static int __initdata testcase_total;
+static int __initdata testcase_successes;
+static int __initdata expected_testcase_failures;
+static int __initdata unexpected_testcase_failures;
+static int __initdata unexpected_testcase_unknowns;
 
-static int nmi_unk_cb(unsigned int val, struct pt_regs *regs)
+static int __init nmi_unk_cb(unsigned int val, struct pt_regs *regs)
 {
 	unexpected_testcase_unknowns++;
 	return NMI_HANDLED;
 }
 
-static void init_nmi_testsuite(void)
+static void __init init_nmi_testsuite(void)
 {
 	/* trap all the unknown NMIs we may generate */
 	register_nmi_handler(NMI_UNKNOWN, nmi_unk_cb, 0, "nmi_selftest_unk");
 }
 
-static void cleanup_nmi_testsuite(void)
+static void __init cleanup_nmi_testsuite(void)
 {
 	unregister_nmi_handler(NMI_UNKNOWN, "nmi_selftest_unk");
 }
 
-static int test_nmi_ipi_callback(unsigned int val, struct pt_regs *regs)
+static int __init test_nmi_ipi_callback(unsigned int val, struct pt_regs *regs)
 {
         int cpu = raw_smp_processor_id();
 
@@ -58,7 +59,7 @@
         return NMI_DONE;
 }
 
-static void test_nmi_ipi(struct cpumask *mask)
+static void __init test_nmi_ipi(struct cpumask *mask)
 {
 	unsigned long timeout;
 
@@ -86,7 +87,7 @@
 	return;
 }
 
-static void remote_ipi(void)
+static void __init remote_ipi(void)
 {
 	cpumask_copy(to_cpumask(nmi_ipi_mask), cpu_online_mask);
 	cpumask_clear_cpu(smp_processor_id(), to_cpumask(nmi_ipi_mask));
@@ -94,19 +95,19 @@
 		test_nmi_ipi(to_cpumask(nmi_ipi_mask));
 }
 
-static void local_ipi(void)
+static void __init local_ipi(void)
 {
 	cpumask_clear(to_cpumask(nmi_ipi_mask));
 	cpumask_set_cpu(smp_processor_id(), to_cpumask(nmi_ipi_mask));
 	test_nmi_ipi(to_cpumask(nmi_ipi_mask));
 }
 
-static void reset_nmi(void)
+static void __init reset_nmi(void)
 {
 	nmi_fail = 0;
 }
 
-static void dotest(void (*testcase_fn)(void), int expected)
+static void __init dotest(void (*testcase_fn)(void), int expected)
 {
 	testcase_fn();
 	/*
@@ -131,12 +132,12 @@
 	reset_nmi();
 }
 
-static inline void print_testname(const char *testname)
+static inline void __init print_testname(const char *testname)
 {
 	printk("%12s:", testname);
 }
 
-void nmi_selftest(void)
+void __init nmi_selftest(void)
 {
 	init_nmi_testsuite();
 
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index ada2f99..ab13760 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -26,6 +26,7 @@
 
 #include <asm/bug.h>
 #include <asm/paravirt.h>
+#include <asm/debugreg.h>
 #include <asm/desc.h>
 #include <asm/setup.h>
 #include <asm/pgtable.h>
@@ -37,6 +38,7 @@
 #include <asm/apic.h>
 #include <asm/tlbflush.h>
 #include <asm/timer.h>
+#include <asm/special_insns.h>
 
 /* nop stub */
 void _paravirt_nop(void)
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index 726494b..d0b2fb9 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -42,7 +42,6 @@
 #include <asm/calgary.h>
 #include <asm/tce.h>
 #include <asm/pci-direct.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/rio.h>
 #include <asm/bios_ebda.h>
@@ -431,7 +430,7 @@
 }
 
 static void* calgary_alloc_coherent(struct device *dev, size_t size,
-	dma_addr_t *dma_handle, gfp_t flag)
+	dma_addr_t *dma_handle, gfp_t flag, struct dma_attrs *attrs)
 {
 	void *ret = NULL;
 	dma_addr_t mapping;
@@ -464,7 +463,8 @@
 }
 
 static void calgary_free_coherent(struct device *dev, size_t size,
-				  void *vaddr, dma_addr_t dma_handle)
+				  void *vaddr, dma_addr_t dma_handle,
+				  struct dma_attrs *attrs)
 {
 	unsigned int npages;
 	struct iommu_table *tbl = find_iommu_table(dev);
@@ -477,8 +477,8 @@
 }
 
 static struct dma_map_ops calgary_dma_ops = {
-	.alloc_coherent = calgary_alloc_coherent,
-	.free_coherent = calgary_free_coherent,
+	.alloc = calgary_alloc_coherent,
+	.free = calgary_free_coherent,
 	.map_sg = calgary_map_sg,
 	.unmap_sg = calgary_unmap_sg,
 	.map_page = calgary_map_page,
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 1c4d769..3003250 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -96,7 +96,8 @@
 	}
 }
 void *dma_generic_alloc_coherent(struct device *dev, size_t size,
-				 dma_addr_t *dma_addr, gfp_t flag)
+				 dma_addr_t *dma_addr, gfp_t flag,
+				 struct dma_attrs *attrs)
 {
 	unsigned long dma_mask;
 	struct page *page;
@@ -262,10 +263,11 @@
 
 static __devinit void via_no_dac(struct pci_dev *dev)
 {
-	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && forbid_dac == 0) {
+	if (forbid_dac == 0) {
 		dev_info(&dev->dev, "disabling DAC on VIA PCI bridge\n");
 		forbid_dac = 1;
 	}
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_ANY_ID, via_no_dac);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_VIA, PCI_ANY_ID,
+				PCI_CLASS_BRIDGE_PCI, 8, via_no_dac);
 #endif
diff --git a/arch/x86/kernel/pci-nommu.c b/arch/x86/kernel/pci-nommu.c
index 3af4af81..f960506 100644
--- a/arch/x86/kernel/pci-nommu.c
+++ b/arch/x86/kernel/pci-nommu.c
@@ -75,7 +75,7 @@
 }
 
 static void nommu_free_coherent(struct device *dev, size_t size, void *vaddr,
-				dma_addr_t dma_addr)
+				dma_addr_t dma_addr, struct dma_attrs *attrs)
 {
 	free_pages((unsigned long)vaddr, get_order(size));
 }
@@ -96,8 +96,8 @@
 }
 
 struct dma_map_ops nommu_dma_ops = {
-	.alloc_coherent		= dma_generic_alloc_coherent,
-	.free_coherent		= nommu_free_coherent,
+	.alloc			= dma_generic_alloc_coherent,
+	.free			= nommu_free_coherent,
 	.map_sg			= nommu_map_sg,
 	.map_page		= nommu_map_page,
 	.sync_single_for_device = nommu_sync_single_for_device,
diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c
index 8f972cb..6c483ba 100644
--- a/arch/x86/kernel/pci-swiotlb.c
+++ b/arch/x86/kernel/pci-swiotlb.c
@@ -15,21 +15,30 @@
 int swiotlb __read_mostly;
 
 static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
-					dma_addr_t *dma_handle, gfp_t flags)
+					dma_addr_t *dma_handle, gfp_t flags,
+					struct dma_attrs *attrs)
 {
 	void *vaddr;
 
-	vaddr = dma_generic_alloc_coherent(hwdev, size, dma_handle, flags);
+	vaddr = dma_generic_alloc_coherent(hwdev, size, dma_handle, flags,
+					   attrs);
 	if (vaddr)
 		return vaddr;
 
 	return swiotlb_alloc_coherent(hwdev, size, dma_handle, flags);
 }
 
+static void x86_swiotlb_free_coherent(struct device *dev, size_t size,
+				      void *vaddr, dma_addr_t dma_addr,
+				      struct dma_attrs *attrs)
+{
+	swiotlb_free_coherent(dev, size, vaddr, dma_addr);
+}
+
 static struct dma_map_ops swiotlb_dma_ops = {
 	.mapping_error = swiotlb_dma_mapping_error,
-	.alloc_coherent = x86_swiotlb_alloc_coherent,
-	.free_coherent = swiotlb_free_coherent,
+	.alloc = x86_swiotlb_alloc_coherent,
+	.free = x86_swiotlb_free_coherent,
 	.sync_single_for_cpu = swiotlb_sync_single_for_cpu,
 	.sync_single_for_device = swiotlb_sync_single_for_device,
 	.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
diff --git a/arch/x86/kernel/probe_roms.c b/arch/x86/kernel/probe_roms.c
index 34e06e8..0bc72e2 100644
--- a/arch/x86/kernel/probe_roms.c
+++ b/arch/x86/kernel/probe_roms.c
@@ -12,6 +12,7 @@
 #include <linux/pci.h>
 #include <linux/export.h>
 
+#include <asm/probe_roms.h>
 #include <asm/pci-direct.h>
 #include <asm/e820.h>
 #include <asm/mmzone.h>
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 44eefde..1d92a5a 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -12,16 +12,37 @@
 #include <linux/user-return-notifier.h>
 #include <linux/dmi.h>
 #include <linux/utsname.h>
+#include <linux/stackprotector.h>
+#include <linux/tick.h>
+#include <linux/cpuidle.h>
 #include <trace/events/power.h>
 #include <linux/hw_breakpoint.h>
 #include <asm/cpu.h>
-#include <asm/system.h>
 #include <asm/apic.h>
 #include <asm/syscalls.h>
 #include <asm/idle.h>
 #include <asm/uaccess.h>
 #include <asm/i387.h>
+#include <asm/fpu-internal.h>
 #include <asm/debugreg.h>
+#include <asm/nmi.h>
+
+#ifdef CONFIG_X86_64
+static DEFINE_PER_CPU(unsigned char, is_idle);
+static ATOMIC_NOTIFIER_HEAD(idle_notifier);
+
+void idle_notifier_register(struct notifier_block *n)
+{
+	atomic_notifier_chain_register(&idle_notifier, n);
+}
+EXPORT_SYMBOL_GPL(idle_notifier_register);
+
+void idle_notifier_unregister(struct notifier_block *n)
+{
+	atomic_notifier_chain_unregister(&idle_notifier, n);
+}
+EXPORT_SYMBOL_GPL(idle_notifier_unregister);
+#endif
 
 struct kmem_cache *task_xstate_cachep;
 EXPORT_SYMBOL_GPL(task_xstate_cachep);
@@ -341,35 +362,104 @@
 EXPORT_SYMBOL(pm_idle);
 #endif
 
-#ifdef CONFIG_X86_32
-/*
- * This halt magic was a workaround for ancient floppy DMA
- * wreckage. It should be safe to remove.
- */
-static int hlt_counter;
-void disable_hlt(void)
-{
-	hlt_counter++;
-}
-EXPORT_SYMBOL(disable_hlt);
-
-void enable_hlt(void)
-{
-	hlt_counter--;
-}
-EXPORT_SYMBOL(enable_hlt);
-
-static inline int hlt_use_halt(void)
-{
-	return (!hlt_counter && boot_cpu_data.hlt_works_ok);
-}
-#else
 static inline int hlt_use_halt(void)
 {
 	return 1;
 }
+
+#ifndef CONFIG_SMP
+static inline void play_dead(void)
+{
+	BUG();
+}
 #endif
 
+#ifdef CONFIG_X86_64
+void enter_idle(void)
+{
+	percpu_write(is_idle, 1);
+	atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL);
+}
+
+static void __exit_idle(void)
+{
+	if (x86_test_and_clear_bit_percpu(0, is_idle) == 0)
+		return;
+	atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL);
+}
+
+/* Called from interrupts to signify idle end */
+void exit_idle(void)
+{
+	/* idle loop has pid 0 */
+	if (current->pid)
+		return;
+	__exit_idle();
+}
+#endif
+
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle(void)
+{
+	/*
+	 * If we're the non-boot CPU, nothing set the stack canary up
+	 * for us.  CPU0 already has it initialized but no harm in
+	 * doing it again.  This is a good place for updating it, as
+	 * we wont ever return from this function (so the invalid
+	 * canaries already on the stack wont ever trigger).
+	 */
+	boot_init_stack_canary();
+	current_thread_info()->status |= TS_POLLING;
+
+	while (1) {
+		tick_nohz_idle_enter();
+
+		while (!need_resched()) {
+			rmb();
+
+			if (cpu_is_offline(smp_processor_id()))
+				play_dead();
+
+			/*
+			 * Idle routines should keep interrupts disabled
+			 * from here on, until they go to idle.
+			 * Otherwise, idle callbacks can misfire.
+			 */
+			local_touch_nmi();
+			local_irq_disable();
+
+			enter_idle();
+
+			/* Don't trace irqs off for idle */
+			stop_critical_timings();
+
+			/* enter_idle() needs rcu for notifiers */
+			rcu_idle_enter();
+
+			if (cpuidle_idle_call())
+				pm_idle();
+
+			rcu_idle_exit();
+			start_critical_timings();
+
+			/* In many cases the interrupt that ended idle
+			   has already called exit_idle. But some idle
+			   loops can be woken up without interrupt. */
+			__exit_idle();
+		}
+
+		tick_nohz_idle_exit();
+		preempt_enable_no_resched();
+		schedule();
+		preempt_disable();
+	}
+}
+
 /*
  * We use this if we don't have any better
  * idle routine..
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 49888fe..ae68473 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -9,7 +9,6 @@
  * This file handles the architecture-dependent parts of process handling..
  */
 
-#include <linux/stackprotector.h>
 #include <linux/cpu.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -31,20 +30,18 @@
 #include <linux/kallsyms.h>
 #include <linux/ptrace.h>
 #include <linux/personality.h>
-#include <linux/tick.h>
 #include <linux/percpu.h>
 #include <linux/prctl.h>
 #include <linux/ftrace.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/kdebug.h>
-#include <linux/cpuidle.h>
 
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/ldt.h>
 #include <asm/processor.h>
 #include <asm/i387.h>
+#include <asm/fpu-internal.h>
 #include <asm/desc.h>
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
@@ -57,7 +54,7 @@
 #include <asm/idle.h>
 #include <asm/syscalls.h>
 #include <asm/debugreg.h>
-#include <asm/nmi.h>
+#include <asm/switch_to.h>
 
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
@@ -69,60 +66,6 @@
 	return ((unsigned long *)tsk->thread.sp)[3];
 }
 
-#ifndef CONFIG_SMP
-static inline void play_dead(void)
-{
-	BUG();
-}
-#endif
-
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle(void)
-{
-	int cpu = smp_processor_id();
-
-	/*
-	 * If we're the non-boot CPU, nothing set the stack canary up
-	 * for us.  CPU0 already has it initialized but no harm in
-	 * doing it again.  This is a good place for updating it, as
-	 * we wont ever return from this function (so the invalid
-	 * canaries already on the stack wont ever trigger).
-	 */
-	boot_init_stack_canary();
-
-	current_thread_info()->status |= TS_POLLING;
-
-	/* endless idle loop with no priority at all */
-	while (1) {
-		tick_nohz_idle_enter();
-		rcu_idle_enter();
-		while (!need_resched()) {
-
-			check_pgt_cache();
-			rmb();
-
-			if (cpu_is_offline(cpu))
-				play_dead();
-
-			local_touch_nmi();
-			local_irq_disable();
-			/* Don't trace irqs off for idle */
-			stop_critical_timings();
-			if (cpuidle_idle_call())
-				pm_idle();
-			start_critical_timings();
-		}
-		rcu_idle_exit();
-		tick_nohz_idle_exit();
-		schedule_preempt_disabled();
-	}
-}
-
 void __show_regs(struct pt_regs *regs, int all)
 {
 	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index e34257c..733ca39 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -14,7 +14,6 @@
  * This file handles the architecture-dependent parts of process handling..
  */
 
-#include <linux/stackprotector.h>
 #include <linux/cpu.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -32,17 +31,15 @@
 #include <linux/notifier.h>
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
-#include <linux/tick.h>
 #include <linux/prctl.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/ftrace.h>
-#include <linux/cpuidle.h>
 
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/i387.h>
+#include <asm/fpu-internal.h>
 #include <asm/mmu_context.h>
 #include <asm/prctl.h>
 #include <asm/desc.h>
@@ -51,114 +48,11 @@
 #include <asm/idle.h>
 #include <asm/syscalls.h>
 #include <asm/debugreg.h>
-#include <asm/nmi.h>
+#include <asm/switch_to.h>
 
 asmlinkage extern void ret_from_fork(void);
 
 DEFINE_PER_CPU(unsigned long, old_rsp);
-static DEFINE_PER_CPU(unsigned char, is_idle);
-
-static ATOMIC_NOTIFIER_HEAD(idle_notifier);
-
-void idle_notifier_register(struct notifier_block *n)
-{
-	atomic_notifier_chain_register(&idle_notifier, n);
-}
-EXPORT_SYMBOL_GPL(idle_notifier_register);
-
-void idle_notifier_unregister(struct notifier_block *n)
-{
-	atomic_notifier_chain_unregister(&idle_notifier, n);
-}
-EXPORT_SYMBOL_GPL(idle_notifier_unregister);
-
-void enter_idle(void)
-{
-	percpu_write(is_idle, 1);
-	atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL);
-}
-
-static void __exit_idle(void)
-{
-	if (x86_test_and_clear_bit_percpu(0, is_idle) == 0)
-		return;
-	atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL);
-}
-
-/* Called from interrupts to signify idle end */
-void exit_idle(void)
-{
-	/* idle loop has pid 0 */
-	if (current->pid)
-		return;
-	__exit_idle();
-}
-
-#ifndef CONFIG_SMP
-static inline void play_dead(void)
-{
-	BUG();
-}
-#endif
-
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle(void)
-{
-	current_thread_info()->status |= TS_POLLING;
-
-	/*
-	 * If we're the non-boot CPU, nothing set the stack canary up
-	 * for us.  CPU0 already has it initialized but no harm in
-	 * doing it again.  This is a good place for updating it, as
-	 * we wont ever return from this function (so the invalid
-	 * canaries already on the stack wont ever trigger).
-	 */
-	boot_init_stack_canary();
-
-	/* endless idle loop with no priority at all */
-	while (1) {
-		tick_nohz_idle_enter();
-		while (!need_resched()) {
-
-			rmb();
-
-			if (cpu_is_offline(smp_processor_id()))
-				play_dead();
-			/*
-			 * Idle routines should keep interrupts disabled
-			 * from here on, until they go to idle.
-			 * Otherwise, idle callbacks can misfire.
-			 */
-			local_touch_nmi();
-			local_irq_disable();
-			enter_idle();
-			/* Don't trace irqs off for idle */
-			stop_critical_timings();
-
-			/* enter_idle() needs rcu for notifiers */
-			rcu_idle_enter();
-
-			if (cpuidle_idle_call())
-				pm_idle();
-
-			rcu_idle_exit();
-			start_critical_timings();
-
-			/* In many cases the interrupt that ended idle
-			   has already called exit_idle. But some idle
-			   loops can be woken up without interrupt. */
-			__exit_idle();
-		}
-
-		tick_nohz_idle_exit();
-		schedule_preempt_disabled();
-	}
-}
 
 /* Prints also some state that isn't saved in the pt_regs */
 void __show_regs(struct pt_regs *regs, int all)
@@ -340,6 +234,7 @@
 	loadsegment(es, _ds);
 	loadsegment(ds, _ds);
 	load_gs_index(0);
+	current->thread.usersp	= new_sp;
 	regs->ip		= new_ip;
 	regs->sp		= new_sp;
 	percpu_write(old_rsp, new_sp);
@@ -363,7 +258,9 @@
 void start_thread_ia32(struct pt_regs *regs, u32 new_ip, u32 new_sp)
 {
 	start_thread_common(regs, new_ip, new_sp,
-			    __USER32_CS, __USER32_DS, __USER32_DS);
+			    test_thread_flag(TIF_X32)
+			    ? __USER_CS : __USER32_CS,
+			    __USER_DS, __USER_DS);
 }
 #endif
 
@@ -486,6 +383,8 @@
 
 	/* Make sure to be in 64bit mode */
 	clear_thread_flag(TIF_IA32);
+	clear_thread_flag(TIF_ADDR32);
+	clear_thread_flag(TIF_X32);
 
 	/* Ensure the corresponding mm is not marked. */
 	if (current->mm)
@@ -498,20 +397,31 @@
 	current->personality &= ~READ_IMPLIES_EXEC;
 }
 
-void set_personality_ia32(void)
+void set_personality_ia32(bool x32)
 {
 	/* inherit personality from parent */
 
 	/* Make sure to be in 32bit mode */
-	set_thread_flag(TIF_IA32);
-	current->personality |= force_personality32;
+	set_thread_flag(TIF_ADDR32);
 
 	/* Mark the associated mm as containing 32-bit tasks. */
 	if (current->mm)
 		current->mm->context.ia32_compat = 1;
 
-	/* Prepare the first "return" to user space */
-	current_thread_info()->status |= TS_COMPAT;
+	if (x32) {
+		clear_thread_flag(TIF_IA32);
+		set_thread_flag(TIF_X32);
+		current->personality &= ~READ_IMPLIES_EXEC;
+		/* is_compat_task() uses the presence of the x32
+		   syscall bit flag to determine compat status */
+		current_thread_info()->status &= ~TS_COMPAT;
+	} else {
+		set_thread_flag(TIF_IA32);
+		clear_thread_flag(TIF_X32);
+		current->personality |= force_personality32;
+		/* Prepare the first "return" to user space */
+		current_thread_info()->status |= TS_COMPAT;
+	}
 }
 
 unsigned long get_wchan(struct task_struct *p)
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 5026738..685845c 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -24,15 +24,16 @@
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/i387.h>
+#include <asm/fpu-internal.h>
 #include <asm/debugreg.h>
 #include <asm/ldt.h>
 #include <asm/desc.h>
 #include <asm/prctl.h>
 #include <asm/proto.h>
 #include <asm/hw_breakpoint.h>
+#include <asm/traps.h>
 
 #include "tls.h"
 
@@ -1130,6 +1131,100 @@
 	return ret;
 }
 
+#ifdef CONFIG_X86_X32_ABI
+static long x32_arch_ptrace(struct task_struct *child,
+			    compat_long_t request, compat_ulong_t caddr,
+			    compat_ulong_t cdata)
+{
+	unsigned long addr = caddr;
+	unsigned long data = cdata;
+	void __user *datap = compat_ptr(data);
+	int ret;
+
+	switch (request) {
+	/* Read 32bits at location addr in the USER area.  Only allow
+	   to return the lower 32bits of segment and debug registers.  */
+	case PTRACE_PEEKUSR: {
+		u32 tmp;
+
+		ret = -EIO;
+		if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user) ||
+		    addr < offsetof(struct user_regs_struct, cs))
+			break;
+
+		tmp = 0;  /* Default return condition */
+		if (addr < sizeof(struct user_regs_struct))
+			tmp = getreg(child, addr);
+		else if (addr >= offsetof(struct user, u_debugreg[0]) &&
+			 addr <= offsetof(struct user, u_debugreg[7])) {
+			addr -= offsetof(struct user, u_debugreg[0]);
+			tmp = ptrace_get_debugreg(child, addr / sizeof(data));
+		}
+		ret = put_user(tmp, (__u32 __user *)datap);
+		break;
+	}
+
+	/* Write the word at location addr in the USER area.  Only allow
+	   to update segment and debug registers with the upper 32bits
+	   zero-extended. */
+	case PTRACE_POKEUSR:
+		ret = -EIO;
+		if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user) ||
+		    addr < offsetof(struct user_regs_struct, cs))
+			break;
+
+		if (addr < sizeof(struct user_regs_struct))
+			ret = putreg(child, addr, data);
+		else if (addr >= offsetof(struct user, u_debugreg[0]) &&
+			 addr <= offsetof(struct user, u_debugreg[7])) {
+			addr -= offsetof(struct user, u_debugreg[0]);
+			ret = ptrace_set_debugreg(child,
+						  addr / sizeof(data), data);
+		}
+		break;
+
+	case PTRACE_GETREGS:	/* Get all gp regs from the child. */
+		return copy_regset_to_user(child,
+					   task_user_regset_view(current),
+					   REGSET_GENERAL,
+					   0, sizeof(struct user_regs_struct),
+					   datap);
+
+	case PTRACE_SETREGS:	/* Set all gp regs in the child. */
+		return copy_regset_from_user(child,
+					     task_user_regset_view(current),
+					     REGSET_GENERAL,
+					     0, sizeof(struct user_regs_struct),
+					     datap);
+
+	case PTRACE_GETFPREGS:	/* Get the child FPU state. */
+		return copy_regset_to_user(child,
+					   task_user_regset_view(current),
+					   REGSET_FP,
+					   0, sizeof(struct user_i387_struct),
+					   datap);
+
+	case PTRACE_SETFPREGS:	/* Set the child FPU state. */
+		return copy_regset_from_user(child,
+					     task_user_regset_view(current),
+					     REGSET_FP,
+					     0, sizeof(struct user_i387_struct),
+					     datap);
+
+		/* normal 64bit interface to access TLS data.
+		   Works just like arch_prctl, except that the arguments
+		   are reversed. */
+	case PTRACE_ARCH_PRCTL:
+		return do_arch_prctl(child, data, addr);
+
+	default:
+		return compat_ptrace_request(child, request, addr, data);
+	}
+
+	return ret;
+}
+#endif
+
 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 			compat_ulong_t caddr, compat_ulong_t cdata)
 {
@@ -1139,6 +1234,11 @@
 	int ret;
 	__u32 val;
 
+#ifdef CONFIG_X86_X32_ABI
+	if (!is_ia32_task())
+		return x32_arch_ptrace(child, request, caddr, cdata);
+#endif
+
 	switch (request) {
 	case PTRACE_PEEKUSR:
 		ret = getreg32(child, addr, &val);
@@ -1326,7 +1426,7 @@
 				int error_code, int si_code,
 				struct siginfo *info)
 {
-	tsk->thread.trap_no = 1;
+	tsk->thread.trap_nr = X86_TRAP_DB;
 	tsk->thread.error_code = error_code;
 
 	memset(info, 0, sizeof(*info));
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index d7d5099..1a29015 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -90,7 +90,6 @@
 #include <asm/processor.h>
 #include <asm/bugs.h>
 
-#include <asm/system.h>
 #include <asm/vsyscall.h>
 #include <asm/cpu.h>
 #include <asm/desc.h>
@@ -509,15 +508,6 @@
 
 #ifdef CONFIG_KEXEC
 
-static inline unsigned long long get_total_mem(void)
-{
-	unsigned long long total;
-
-	total = max_pfn - min_low_pfn;
-
-	return total << PAGE_SHIFT;
-}
-
 /*
  * Keep the crash kernel below this limit.  On 32 bits earlier kernels
  * would limit the kernel to the low 512 MiB due to mapping restrictions.
@@ -536,7 +526,7 @@
 	unsigned long long crash_size, crash_base;
 	int ret;
 
-	total_mem = get_total_mem();
+	total_mem = memblock_phys_mem_size();
 
 	ret = parse_crashkernel(boot_command_line, total_mem,
 			&crash_size, &crash_base);
@@ -749,10 +739,16 @@
 #endif
 #ifdef CONFIG_EFI
 	if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
-		     EFI_LOADER_SIGNATURE, 4)) {
+		     "EL32", 4)) {
 		efi_enabled = 1;
-		efi_memblock_x86_reserve_range();
+		efi_64bit = false;
+	} else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
+		     "EL64", 4)) {
+		efi_enabled = 1;
+		efi_64bit = true;
 	}
+	if (efi_enabled && efi_memblock_x86_reserve_range())
+		efi_enabled = 0;
 #endif
 
 	x86_init.oem.arch_setup();
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 46a01bdc..115eac4 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -10,10 +10,8 @@
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/kernel.h>
-#include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/wait.h>
-#include <linux/ptrace.h>
 #include <linux/tracehook.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
@@ -24,12 +22,15 @@
 #include <asm/processor.h>
 #include <asm/ucontext.h>
 #include <asm/i387.h>
+#include <asm/fpu-internal.h>
 #include <asm/vdso.h>
 #include <asm/mce.h>
+#include <asm/sighandling.h>
 
 #ifdef CONFIG_X86_64
 #include <asm/proto.h>
 #include <asm/ia32_unistd.h>
+#include <asm/sys_ia32.h>
 #endif /* CONFIG_X86_64 */
 
 #include <asm/syscall.h>
@@ -37,13 +38,6 @@
 
 #include <asm/sigframe.h>
 
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
-#define __FIX_EFLAGS	(X86_EFLAGS_AC | X86_EFLAGS_OF | \
-			 X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \
-			 X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \
-			 X86_EFLAGS_CF)
-
 #ifdef CONFIG_X86_32
 # define FIX_EFLAGS	(__FIX_EFLAGS | X86_EFLAGS_RF)
 #else
@@ -68,9 +62,8 @@
 	regs->seg = GET_SEG(seg) | 3;			\
 } while (0)
 
-static int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
-		   unsigned long *pax)
+int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
+		       unsigned long *pax)
 {
 	void __user *buf;
 	unsigned int tmpflags;
@@ -125,9 +118,8 @@
 	return err;
 }
 
-static int
-setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
-		 struct pt_regs *regs, unsigned long mask)
+int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
+		     struct pt_regs *regs, unsigned long mask)
 {
 	int err = 0;
 
@@ -159,7 +151,7 @@
 		put_user_ex(regs->r15, &sc->r15);
 #endif /* CONFIG_X86_64 */
 
-		put_user_ex(current->thread.trap_no, &sc->trapno);
+		put_user_ex(current->thread.trap_nr, &sc->trapno);
 		put_user_ex(current->thread.error_code, &sc->err);
 		put_user_ex(regs->ip, &sc->ip);
 #ifdef CONFIG_X86_32
@@ -642,6 +634,16 @@
 #define is_ia32	0
 #endif /* CONFIG_IA32_EMULATION */
 
+#ifdef CONFIG_X86_X32_ABI
+#define is_x32	test_thread_flag(TIF_X32)
+
+static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
+			      siginfo_t *info, compat_sigset_t *set,
+			      struct pt_regs *regs);
+#else /* !CONFIG_X86_X32_ABI */
+#define is_x32	0
+#endif /* CONFIG_X86_X32_ABI */
+
 int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		sigset_t *set, struct pt_regs *regs);
 int ia32_setup_frame(int sig, struct k_sigaction *ka,
@@ -666,8 +668,14 @@
 			ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
 		else
 			ret = ia32_setup_frame(usig, ka, set, regs);
-	} else
+#ifdef CONFIG_X86_X32_ABI
+	} else if (is_x32) {
+		ret = x32_setup_rt_frame(usig, ka, info,
+					 (compat_sigset_t *)set, regs);
+#endif
+	} else {
 		ret = __setup_rt_frame(sig, ka, info, set, regs);
+	}
 
 	if (ret) {
 		force_sigsegv(sig, current);
@@ -850,3 +858,102 @@
 
 	force_sig(SIGSEGV, me);
 }
+
+#ifdef CONFIG_X86_X32_ABI
+static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
+			      siginfo_t *info, compat_sigset_t *set,
+			      struct pt_regs *regs)
+{
+	struct rt_sigframe_x32 __user *frame;
+	void __user *restorer;
+	int err = 0;
+	void __user *fpstate = NULL;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		return -EFAULT;
+
+	if (ka->sa.sa_flags & SA_SIGINFO) {
+		if (copy_siginfo_to_user32(&frame->info, info))
+			return -EFAULT;
+	}
+
+	put_user_try {
+		/* Create the ucontext.  */
+		if (cpu_has_xsave)
+			put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
+		else
+			put_user_ex(0, &frame->uc.uc_flags);
+		put_user_ex(0, &frame->uc.uc_link);
+		put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+		put_user_ex(sas_ss_flags(regs->sp),
+			    &frame->uc.uc_stack.ss_flags);
+		put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+		put_user_ex(0, &frame->uc.uc__pad0);
+		err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
+					regs, set->sig[0]);
+		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+		if (ka->sa.sa_flags & SA_RESTORER) {
+			restorer = ka->sa.sa_restorer;
+		} else {
+			/* could use a vstub here */
+			restorer = NULL;
+			err |= -EFAULT;
+		}
+		put_user_ex(restorer, &frame->pretcode);
+	} put_user_catch(err);
+
+	if (err)
+		return -EFAULT;
+
+	/* Set up registers for signal handler */
+	regs->sp = (unsigned long) frame;
+	regs->ip = (unsigned long) ka->sa.sa_handler;
+
+	/* We use the x32 calling convention here... */
+	regs->di = sig;
+	regs->si = (unsigned long) &frame->info;
+	regs->dx = (unsigned long) &frame->uc;
+
+	loadsegment(ds, __USER_DS);
+	loadsegment(es, __USER_DS);
+
+	regs->cs = __USER_CS;
+	regs->ss = __USER_DS;
+
+	return 0;
+}
+
+asmlinkage long sys32_x32_rt_sigreturn(struct pt_regs *regs)
+{
+	struct rt_sigframe_x32 __user *frame;
+	sigset_t set;
+	unsigned long ax;
+	struct pt_regs tregs;
+
+	frame = (struct rt_sigframe_x32 __user *)(regs->sp - 8);
+
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	set_current_blocked(&set);
+
+	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
+		goto badframe;
+
+	tregs = *regs;
+	if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
+		goto badframe;
+
+	return ax;
+
+badframe:
+	signal_fault(regs, frame, "x32 rt_sigreturn");
+	return 0;
+}
+#endif
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 58f7816..6e1e406 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -50,6 +50,7 @@
 #include <linux/tboot.h>
 #include <linux/stackprotector.h>
 #include <linux/gfp.h>
+#include <linux/cpuidle.h>
 
 #include <asm/acpi.h>
 #include <asm/desc.h>
@@ -219,14 +220,9 @@
 	 * Update loops_per_jiffy in cpu_data. Previous call to
 	 * smp_store_cpu_info() stored a value that is close but not as
 	 * accurate as the value just calculated.
-	 *
-	 * Need to enable IRQs because it can take longer and then
-	 * the NMI watchdog might kill us.
 	 */
-	local_irq_enable();
 	calibrate_delay();
 	cpu_data(cpuid).loops_per_jiffy = loops_per_jiffy;
-	local_irq_disable();
 	pr_debug("Stack at about %p\n", &cpuid);
 
 	/*
@@ -255,6 +251,7 @@
 	 * most necessary things.
 	 */
 	cpu_init();
+	x86_cpuinit.early_percpu_clock_init();
 	preempt_disable();
 	smp_callin();
 
@@ -727,8 +724,6 @@
 	 * the targeted processor.
 	 */
 
-	printk(KERN_DEBUG "smpboot cpu %d: start_ip = %lx\n", cpu, start_ip);
-
 	atomic_set(&init_deasserted, 0);
 
 	if (get_uv_system_type() != UV_NON_UNIQUE_APIC) {
@@ -778,9 +773,10 @@
 			schedule();
 		}
 
-		if (cpumask_test_cpu(cpu, cpu_callin_mask))
+		if (cpumask_test_cpu(cpu, cpu_callin_mask)) {
+			print_cpu_msr(&cpu_data(cpu));
 			pr_debug("CPU%d: has booted.\n", cpu);
-		else {
+		} else {
 			boot_error = 1;
 			if (*(volatile u32 *)TRAMPOLINE_SYM(trampoline_status)
 			    == 0xA5A5A5A5)
@@ -834,7 +830,7 @@
 
 	if (apicid == BAD_APICID || apicid == boot_cpu_physical_apicid ||
 	    !physid_isset(apicid, phys_cpu_present_map) ||
-	    (!x2apic_mode && apicid >= 255)) {
+	    !apic->apic_id_valid(apicid)) {
 		printk(KERN_ERR "%s: bad cpu %d\n", __func__, cpu);
 		return -EINVAL;
 	}
@@ -1409,7 +1405,8 @@
 	tboot_shutdown(TB_SHUTDOWN_WFS);
 
 	mwait_play_dead();	/* Only returns on failure */
-	hlt_play_dead();
+	if (cpuidle_play_dead())
+		hlt_play_dead();
 }
 
 #else /* ... !CONFIG_HOTPLUG_CPU */
diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c
index 0514890..b4d3c39 100644
--- a/arch/x86/kernel/sys_x86_64.c
+++ b/arch/x86/kernel/sys_x86_64.c
@@ -98,7 +98,7 @@
 static void find_start_end(unsigned long flags, unsigned long *begin,
 			   unsigned long *end)
 {
-	if (!test_thread_flag(TIF_IA32) && (flags & MAP_32BIT)) {
+	if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT)) {
 		unsigned long new_begin;
 		/* This is usually used needed to map code in small
 		   model, so it needs to be in the first 31bit. Limit
@@ -144,7 +144,7 @@
 		    (!vma || addr + len <= vma->vm_start))
 			return addr;
 	}
-	if (((flags & MAP_32BIT) || test_thread_flag(TIF_IA32))
+	if (((flags & MAP_32BIT) || test_thread_flag(TIF_ADDR32))
 	    && len <= mm->cached_hole_size) {
 		mm->cached_hole_size = 0;
 		mm->free_area_cache = begin;
@@ -195,7 +195,7 @@
 {
 	struct vm_area_struct *vma;
 	struct mm_struct *mm = current->mm;
-	unsigned long addr = addr0;
+	unsigned long addr = addr0, start_addr;
 
 	/* requested length too big for entire address space */
 	if (len > TASK_SIZE)
@@ -205,7 +205,7 @@
 		return addr;
 
 	/* for MAP_32BIT mappings we force the legact mmap base */
-	if (!test_thread_flag(TIF_IA32) && (flags & MAP_32BIT))
+	if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT))
 		goto bottomup;
 
 	/* requesting a specific address */
@@ -223,25 +223,14 @@
 		mm->free_area_cache = mm->mmap_base;
 	}
 
+try_again:
 	/* either no address requested or can't fit in requested address hole */
-	addr = mm->free_area_cache;
+	start_addr = addr = mm->free_area_cache;
 
-	/* make sure it can fit in the remaining address space */
-	if (addr > len) {
-		unsigned long tmp_addr = align_addr(addr - len, filp,
-						    ALIGN_TOPDOWN);
+	if (addr < len)
+		goto fail;
 
-		vma = find_vma(mm, tmp_addr);
-		if (!vma || tmp_addr + len <= vma->vm_start)
-			/* remember the address as a hint for next time */
-			return mm->free_area_cache = tmp_addr;
-	}
-
-	if (mm->mmap_base < len)
-		goto bottomup;
-
-	addr = mm->mmap_base-len;
-
+	addr -= len;
 	do {
 		addr = align_addr(addr, filp, ALIGN_TOPDOWN);
 
@@ -263,6 +252,17 @@
 		addr = vma->vm_start-len;
 	} while (len < vma->vm_start);
 
+fail:
+	/*
+	 * if hint left us with no space for the requested
+	 * mapping then try again:
+	 */
+	if (start_addr != mm->mmap_base) {
+		mm->free_area_cache = mm->mmap_base;
+		mm->cached_hole_size = 0;
+		goto try_again;
+	}
+
 bottomup:
 	/*
 	 * A failed mmap() very likely causes application failure,
diff --git a/arch/x86/kernel/syscall_64.c b/arch/x86/kernel/syscall_64.c
index 7ac7943..5c7f8c2 100644
--- a/arch/x86/kernel/syscall_64.c
+++ b/arch/x86/kernel/syscall_64.c
@@ -5,6 +5,14 @@
 #include <linux/cache.h>
 #include <asm/asm-offsets.h>
 
+#define __SYSCALL_COMMON(nr, sym, compat) __SYSCALL_64(nr, sym, compat)
+
+#ifdef CONFIG_X86_X32_ABI
+# define __SYSCALL_X32(nr, sym, compat) __SYSCALL_64(nr, sym, compat)
+#else
+# define __SYSCALL_X32(nr, sym, compat) /* nothing */
+#endif
+
 #define __SYSCALL_64(nr, sym, compat) extern asmlinkage void sym(void) ;
 #include <asm/syscalls_64.h>
 #undef __SYSCALL_64
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c
index e2410e2..6410744 100644
--- a/arch/x86/kernel/tboot.c
+++ b/arch/x86/kernel/tboot.c
@@ -272,7 +272,7 @@
 		offsetof(struct acpi_table_facs, firmware_waking_vector);
 }
 
-void tboot_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control)
+static int tboot_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control)
 {
 	static u32 acpi_shutdown_map[ACPI_S_STATE_COUNT] = {
 		/* S0,1,2: */ -1, -1, -1,
@@ -281,7 +281,7 @@
 		/* S5: */ TB_SHUTDOWN_S5 };
 
 	if (!tboot_enabled())
-		return;
+		return 0;
 
 	tboot_copy_fadt(&acpi_gbl_FADT);
 	tboot->acpi_sinfo.pm1a_cnt_val = pm1a_control;
@@ -292,10 +292,11 @@
 	if (sleep_state >= ACPI_S_STATE_COUNT ||
 	    acpi_shutdown_map[sleep_state] == -1) {
 		pr_warning("unsupported sleep state 0x%x\n", sleep_state);
-		return;
+		return -1;
 	}
 
 	tboot_shutdown(acpi_shutdown_map[sleep_state]);
+	return 0;
 }
 
 static atomic_t ap_wfs_count;
@@ -345,6 +346,8 @@
 
 	atomic_set(&ap_wfs_count, 0);
 	register_hotcpu_notifier(&tboot_cpu_notifier);
+
+	acpi_os_set_prepare_sleep(&tboot_sleep);
 	return 0;
 }
 
diff --git a/arch/x86/kernel/tce_64.c b/arch/x86/kernel/tce_64.c
index 9e540fe..ab40954 100644
--- a/arch/x86/kernel/tce_64.c
+++ b/arch/x86/kernel/tce_64.c
@@ -34,6 +34,7 @@
 #include <asm/tce.h>
 #include <asm/calgary.h>
 #include <asm/proto.h>
+#include <asm/cacheflush.h>
 
 /* flush a tce at 'tceaddr' to main memory */
 static inline void flush_tce(void* tceaddr)
diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c
index 6bb7b85..9d9d2f9 100644
--- a/arch/x86/kernel/tls.c
+++ b/arch/x86/kernel/tls.c
@@ -6,7 +6,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/desc.h>
-#include <asm/system.h>
 #include <asm/ldt.h>
 #include <asm/processor.h>
 #include <asm/proto.h>
@@ -163,7 +162,7 @@
 {
 	const struct desc_struct *tls;
 
-	if (pos > GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) ||
+	if (pos >= GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) ||
 	    (pos % sizeof(struct user_desc)) != 0 ||
 	    (count % sizeof(struct user_desc)) != 0)
 		return -EINVAL;
@@ -198,7 +197,7 @@
 	struct user_desc infobuf[GDT_ENTRY_TLS_ENTRIES];
 	const struct user_desc *info;
 
-	if (pos > GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) ||
+	if (pos >= GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) ||
 	    (pos % sizeof(struct user_desc)) != 0 ||
 	    (count % sizeof(struct user_desc)) != 0)
 		return -EINVAL;
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 4bbe04d..ff9281f1 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -50,10 +50,10 @@
 #include <asm/processor.h>
 #include <asm/debugreg.h>
 #include <linux/atomic.h>
-#include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/desc.h>
 #include <asm/i387.h>
+#include <asm/fpu-internal.h>
 #include <asm/mce.h>
 
 #include <asm/mach_traps.h>
@@ -119,7 +119,7 @@
 		 * traps 0, 1, 3, 4, and 5 should be forwarded to vm86.
 		 * On nmi (interrupt 2), do_trap should not be called.
 		 */
-		if (trapnr < 6)
+		if (trapnr < X86_TRAP_UD)
 			goto vm86_trap;
 		goto trap_signal;
 	}
@@ -132,7 +132,7 @@
 trap_signal:
 #endif
 	/*
-	 * We want error_code and trap_no set for userspace faults and
+	 * We want error_code and trap_nr set for userspace faults and
 	 * kernelspace faults which result in die(), but not
 	 * kernelspace faults which are fixed up.  die() gives the
 	 * process no chance to handle the signal and notice the
@@ -141,7 +141,7 @@
 	 * delivered, faults.  See also do_general_protection below.
 	 */
 	tsk->thread.error_code = error_code;
-	tsk->thread.trap_no = trapnr;
+	tsk->thread.trap_nr = trapnr;
 
 #ifdef CONFIG_X86_64
 	if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
@@ -164,7 +164,7 @@
 kernel_trap:
 	if (!fixup_exception(regs)) {
 		tsk->thread.error_code = error_code;
-		tsk->thread.trap_no = trapnr;
+		tsk->thread.trap_nr = trapnr;
 		die(str, regs, error_code);
 	}
 	return;
@@ -203,27 +203,31 @@
 	do_trap(trapnr, signr, str, regs, error_code, &info);		\
 }
 
-DO_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
-DO_ERROR(4, SIGSEGV, "overflow", overflow)
-DO_ERROR(5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip)
-DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
-DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
-DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
+DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV,
+		regs->ip)
+DO_ERROR(X86_TRAP_OF, SIGSEGV, "overflow", overflow)
+DO_ERROR(X86_TRAP_BR, SIGSEGV, "bounds", bounds)
+DO_ERROR_INFO(X86_TRAP_UD, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN,
+		regs->ip)
+DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun",
+		coprocessor_segment_overrun)
+DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS)
+DO_ERROR(X86_TRAP_NP, SIGBUS, "segment not present", segment_not_present)
 #ifdef CONFIG_X86_32
-DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
+DO_ERROR(X86_TRAP_SS, SIGBUS, "stack segment", stack_segment)
 #endif
-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
+DO_ERROR_INFO(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check,
+		BUS_ADRALN, 0)
 
 #ifdef CONFIG_X86_64
 /* Runs on IST stack */
 dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
 {
 	if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
-			12, SIGBUS) == NOTIFY_STOP)
+			X86_TRAP_SS, SIGBUS) == NOTIFY_STOP)
 		return;
 	preempt_conditional_sti(regs);
-	do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL);
+	do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL);
 	preempt_conditional_cli(regs);
 }
 
@@ -233,10 +237,10 @@
 	struct task_struct *tsk = current;
 
 	/* Return not checked because double check cannot be ignored */
-	notify_die(DIE_TRAP, str, regs, error_code, 8, SIGSEGV);
+	notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
 
 	tsk->thread.error_code = error_code;
-	tsk->thread.trap_no = 8;
+	tsk->thread.trap_nr = X86_TRAP_DF;
 
 	/*
 	 * This is always a kernel trap and never fixable (and thus must
@@ -264,7 +268,7 @@
 		goto gp_in_kernel;
 
 	tsk->thread.error_code = error_code;
-	tsk->thread.trap_no = 13;
+	tsk->thread.trap_nr = X86_TRAP_GP;
 
 	if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
 			printk_ratelimit()) {
@@ -291,9 +295,9 @@
 		return;
 
 	tsk->thread.error_code = error_code;
-	tsk->thread.trap_no = 13;
-	if (notify_die(DIE_GPF, "general protection fault", regs,
-				error_code, 13, SIGSEGV) == NOTIFY_STOP)
+	tsk->thread.trap_nr = X86_TRAP_GP;
+	if (notify_die(DIE_GPF, "general protection fault", regs, error_code,
+			X86_TRAP_GP, SIGSEGV) == NOTIFY_STOP)
 		return;
 	die("general protection fault", regs, error_code);
 }
@@ -302,13 +306,13 @@
 dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
 {
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
-	if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
-			== NOTIFY_STOP)
+	if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
+				SIGTRAP) == NOTIFY_STOP)
 		return;
 #endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */
 
-	if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
-			== NOTIFY_STOP)
+	if (notify_die(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
+			SIGTRAP) == NOTIFY_STOP)
 		return;
 
 	/*
@@ -317,7 +321,7 @@
 	 */
 	debug_stack_usage_inc();
 	preempt_conditional_sti(regs);
-	do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
+	do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL);
 	preempt_conditional_cli(regs);
 	debug_stack_usage_dec();
 }
@@ -422,8 +426,8 @@
 	preempt_conditional_sti(regs);
 
 	if (regs->flags & X86_VM_MASK) {
-		handle_vm86_trap((struct kernel_vm86_regs *) regs,
-				error_code, 1);
+		handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code,
+					X86_TRAP_DB);
 		preempt_conditional_cli(regs);
 		debug_stack_usage_dec();
 		return;
@@ -460,7 +464,8 @@
 	struct task_struct *task = current;
 	siginfo_t info;
 	unsigned short err;
-	char *str = (trapnr == 16) ? "fpu exception" : "simd exception";
+	char *str = (trapnr == X86_TRAP_MF) ? "fpu exception" :
+						"simd exception";
 
 	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, SIGFPE) == NOTIFY_STOP)
 		return;
@@ -470,7 +475,7 @@
 	{
 		if (!fixup_exception(regs)) {
 			task->thread.error_code = error_code;
-			task->thread.trap_no = trapnr;
+			task->thread.trap_nr = trapnr;
 			die(str, regs, error_code);
 		}
 		return;
@@ -480,12 +485,12 @@
 	 * Save the info for the exception handler and clear the error.
 	 */
 	save_init_fpu(task);
-	task->thread.trap_no = trapnr;
+	task->thread.trap_nr = trapnr;
 	task->thread.error_code = error_code;
 	info.si_signo = SIGFPE;
 	info.si_errno = 0;
 	info.si_addr = (void __user *)regs->ip;
-	if (trapnr == 16) {
+	if (trapnr == X86_TRAP_MF) {
 		unsigned short cwd, swd;
 		/*
 		 * (~cwd & swd) will mask out exceptions that are not set to unmasked
@@ -529,10 +534,11 @@
 		info.si_code = FPE_FLTRES;
 	} else {
 		/*
-		 * If we're using IRQ 13, or supposedly even some trap 16
-		 * implementations, it's possible we get a spurious trap...
+		 * If we're using IRQ 13, or supposedly even some trap
+		 * X86_TRAP_MF implementations, it's possible
+		 * we get a spurious trap, which is not an error.
 		 */
-		return;		/* Spurious trap, no error */
+		return;
 	}
 	force_sig_info(SIGFPE, &info, task);
 }
@@ -543,13 +549,13 @@
 	ignore_fpu_irq = 1;
 #endif
 
-	math_error(regs, error_code, 16);
+	math_error(regs, error_code, X86_TRAP_MF);
 }
 
 dotraplinkage void
 do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
 {
-	math_error(regs, error_code, 19);
+	math_error(regs, error_code, X86_TRAP_XF);
 }
 
 dotraplinkage void
@@ -643,20 +649,21 @@
 	info.si_errno = 0;
 	info.si_code = ILL_BADSTK;
 	info.si_addr = NULL;
-	if (notify_die(DIE_TRAP, "iret exception",
-			regs, error_code, 32, SIGILL) == NOTIFY_STOP)
+	if (notify_die(DIE_TRAP, "iret exception", regs, error_code,
+			X86_TRAP_IRET, SIGILL) == NOTIFY_STOP)
 		return;
-	do_trap(32, SIGILL, "iret exception", regs, error_code, &info);
+	do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code,
+		&info);
 }
 #endif
 
 /* Set of traps needed for early debugging. */
 void __init early_trap_init(void)
 {
-	set_intr_gate_ist(1, &debug, DEBUG_STACK);
+	set_intr_gate_ist(X86_TRAP_DB, &debug, DEBUG_STACK);
 	/* int3 can be called from all */
-	set_system_intr_gate_ist(3, &int3, DEBUG_STACK);
-	set_intr_gate(14, &page_fault);
+	set_system_intr_gate_ist(X86_TRAP_BP, &int3, DEBUG_STACK);
+	set_intr_gate(X86_TRAP_PF, &page_fault);
 	load_idt(&idt_descr);
 }
 
@@ -672,30 +679,30 @@
 	early_iounmap(p, 4);
 #endif
 
-	set_intr_gate(0, &divide_error);
-	set_intr_gate_ist(2, &nmi, NMI_STACK);
+	set_intr_gate(X86_TRAP_DE, &divide_error);
+	set_intr_gate_ist(X86_TRAP_NMI, &nmi, NMI_STACK);
 	/* int4 can be called from all */
-	set_system_intr_gate(4, &overflow);
-	set_intr_gate(5, &bounds);
-	set_intr_gate(6, &invalid_op);
-	set_intr_gate(7, &device_not_available);
+	set_system_intr_gate(X86_TRAP_OF, &overflow);
+	set_intr_gate(X86_TRAP_BR, &bounds);
+	set_intr_gate(X86_TRAP_UD, &invalid_op);
+	set_intr_gate(X86_TRAP_NM, &device_not_available);
 #ifdef CONFIG_X86_32
-	set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS);
+	set_task_gate(X86_TRAP_DF, GDT_ENTRY_DOUBLEFAULT_TSS);
 #else
-	set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK);
+	set_intr_gate_ist(X86_TRAP_DF, &double_fault, DOUBLEFAULT_STACK);
 #endif
-	set_intr_gate(9, &coprocessor_segment_overrun);
-	set_intr_gate(10, &invalid_TSS);
-	set_intr_gate(11, &segment_not_present);
-	set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK);
-	set_intr_gate(13, &general_protection);
-	set_intr_gate(15, &spurious_interrupt_bug);
-	set_intr_gate(16, &coprocessor_error);
-	set_intr_gate(17, &alignment_check);
+	set_intr_gate(X86_TRAP_OLD_MF, &coprocessor_segment_overrun);
+	set_intr_gate(X86_TRAP_TS, &invalid_TSS);
+	set_intr_gate(X86_TRAP_NP, &segment_not_present);
+	set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK);
+	set_intr_gate(X86_TRAP_GP, &general_protection);
+	set_intr_gate(X86_TRAP_SPURIOUS, &spurious_interrupt_bug);
+	set_intr_gate(X86_TRAP_MF, &coprocessor_error);
+	set_intr_gate(X86_TRAP_AC, &alignment_check);
 #ifdef CONFIG_X86_MCE
-	set_intr_gate_ist(18, &machine_check, MCE_STACK);
+	set_intr_gate_ist(X86_TRAP_MC, &machine_check, MCE_STACK);
 #endif
-	set_intr_gate(19, &simd_coprocessor_error);
+	set_intr_gate(X86_TRAP_XF, &simd_coprocessor_error);
 
 	/* Reserve all the builtin and the syscall vector: */
 	for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++)
@@ -720,7 +727,7 @@
 
 #ifdef CONFIG_X86_64
 	memcpy(&nmi_idt_table, &idt_table, IDT_ENTRIES * 16);
-	set_nmi_gate(1, &debug);
-	set_nmi_gate(3, &int3);
+	set_nmi_gate(X86_TRAP_DB, &debug);
+	set_nmi_gate(X86_TRAP_BP, &int3);
 #endif
 }
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 183c592..fc0a147 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -630,7 +630,7 @@
 
 static unsigned long long cyc2ns_suspend;
 
-void save_sched_clock_state(void)
+void tsc_save_sched_clock_state(void)
 {
 	if (!sched_clock_stable)
 		return;
@@ -646,7 +646,7 @@
  * that sched_clock() continues from the point where it was left off during
  * suspend.
  */
-void restore_sched_clock_state(void)
+void tsc_restore_sched_clock_state(void)
 {
 	unsigned long long offset;
 	unsigned long flags;
@@ -933,6 +933,16 @@
 		clocksource_tsc.rating = 0;
 		clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS;
 	}
+
+	/*
+	 * Trust the results of the earlier calibration on systems
+	 * exporting a reliable TSC.
+	 */
+	if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) {
+		clocksource_register_khz(&clocksource_tsc, tsc_khz);
+		return 0;
+	}
+
 	schedule_delayed_work(&tsc_irqwork, 0);
 	return 0;
 }
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
index b466cab..255f58a 100644
--- a/arch/x86/kernel/vm86_32.c
+++ b/arch/x86/kernel/vm86_32.c
@@ -172,6 +172,7 @@
 	spinlock_t *ptl;
 	int i;
 
+	down_write(&mm->mmap_sem);
 	pgd = pgd_offset(mm, 0xA0000);
 	if (pgd_none_or_clear_bad(pgd))
 		goto out;
@@ -190,6 +191,7 @@
 	}
 	pte_unmap_unlock(pte, ptl);
 out:
+	up_write(&mm->mmap_sem);
 	flush_tlb();
 }
 
@@ -567,7 +569,7 @@
 	}
 	if (trapno != 1)
 		return 1; /* we let this handle by the calling routine */
-	current->thread.trap_no = trapno;
+	current->thread.trap_nr = trapno;
 	current->thread.error_code = error_code;
 	force_sig(SIGTRAP, current);
 	return 0;
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c
index b07ba93..f386dc4 100644
--- a/arch/x86/kernel/vsyscall_64.c
+++ b/arch/x86/kernel/vsyscall_64.c
@@ -52,10 +52,7 @@
 #include "vsyscall_trace.h"
 
 DEFINE_VVAR(int, vgetcpu_mode);
-DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data) =
-{
-	.lock = __SEQLOCK_UNLOCKED(__vsyscall_gtod_data.lock),
-};
+DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data);
 
 static enum { EMULATE, NATIVE, NONE } vsyscall_mode = EMULATE;
 
@@ -80,20 +77,15 @@
 
 void update_vsyscall_tz(void)
 {
-	unsigned long flags;
-
-	write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags);
-	/* sys_tz has changed */
 	vsyscall_gtod_data.sys_tz = sys_tz;
-	write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
 }
 
 void update_vsyscall(struct timespec *wall_time, struct timespec *wtm,
 			struct clocksource *clock, u32 mult)
 {
-	unsigned long flags;
+	struct timespec monotonic;
 
-	write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags);
+	write_seqcount_begin(&vsyscall_gtod_data.seq);
 
 	/* copy vsyscall data */
 	vsyscall_gtod_data.clock.vclock_mode	= clock->archdata.vclock_mode;
@@ -101,12 +93,19 @@
 	vsyscall_gtod_data.clock.mask		= clock->mask;
 	vsyscall_gtod_data.clock.mult		= mult;
 	vsyscall_gtod_data.clock.shift		= clock->shift;
+
 	vsyscall_gtod_data.wall_time_sec	= wall_time->tv_sec;
 	vsyscall_gtod_data.wall_time_nsec	= wall_time->tv_nsec;
-	vsyscall_gtod_data.wall_to_monotonic	= *wtm;
-	vsyscall_gtod_data.wall_time_coarse	= __current_kernel_time();
 
-	write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
+	monotonic = timespec_add(*wall_time, *wtm);
+	vsyscall_gtod_data.monotonic_time_sec	= monotonic.tv_sec;
+	vsyscall_gtod_data.monotonic_time_nsec	= monotonic.tv_nsec;
+
+	vsyscall_gtod_data.wall_time_coarse	= __current_kernel_time();
+	vsyscall_gtod_data.monotonic_time_coarse =
+		timespec_add(vsyscall_gtod_data.wall_time_coarse, *wtm);
+
+	write_seqcount_end(&vsyscall_gtod_data.seq);
 }
 
 static void warn_bad_vsyscall(const char *level, struct pt_regs *regs,
@@ -153,7 +152,7 @@
 
 		thread->error_code	= 6;  /* user fault, no page, write */
 		thread->cr2		= ptr;
-		thread->trap_no		= 14;
+		thread->trap_nr		= X86_TRAP_PF;
 
 		memset(&info, 0, sizeof(info));
 		info.si_signo		= SIGSEGV;
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 947a06c..e9f265f 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -91,6 +91,7 @@
 };
 
 struct x86_cpuinit_ops x86_cpuinit __cpuinitdata = {
+	.early_percpu_clock_init	= x86_init_noop,
 	.setup_percpu_clockev		= setup_secondary_APIC_clock,
 	.fixup_cpu_id			= x86_default_fixup_cpu_id,
 };
@@ -107,7 +108,9 @@
 	.is_untracked_pat_range		= is_ISA_range,
 	.nmi_init			= default_nmi_init,
 	.get_nmi_reason			= default_get_nmi_reason,
-	.i8042_detect			= default_i8042_detect
+	.i8042_detect			= default_i8042_detect,
+	.save_sched_clock_state 	= tsc_save_sched_clock_state,
+	.restore_sched_clock_state 	= tsc_restore_sched_clock_state,
 };
 
 EXPORT_SYMBOL_GPL(x86_platform);
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index 7110911..e62728e 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -6,6 +6,7 @@
 #include <linux/bootmem.h>
 #include <linux/compat.h>
 #include <asm/i387.h>
+#include <asm/fpu-internal.h>
 #ifdef CONFIG_IA32_EMULATION
 #include <asm/sigcontext32.h>
 #endif
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 89b02bf..9fed5be 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -236,7 +236,7 @@
 	const u32 kvm_supported_word6_x86_features =
 		F(LAHF_LM) | F(CMP_LEGACY) | 0 /*SVM*/ | 0 /* ExtApicSpace */ |
 		F(CR8_LEGACY) | F(ABM) | F(SSE4A) | F(MISALIGNSSE) |
-		F(3DNOWPREFETCH) | 0 /* OSVW */ | 0 /* IBS */ | F(XOP) |
+		F(3DNOWPREFETCH) | F(OSVW) | 0 /* IBS */ | F(XOP) |
 		0 /* SKINIT, WDT, LWP */ | F(FMA4) | F(TBM);
 
 	/* cpuid 0xC0000001.edx */
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index 5b97e17..26d1fb4 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -43,4 +43,12 @@
 	return best && (best->ebx & bit(X86_FEATURE_FSGSBASE));
 }
 
+static inline bool guest_cpuid_has_osvw(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpuid_entry2 *best;
+
+	best = kvm_find_cpuid_entry(vcpu, 0x80000001, 0);
+	return best && (best->ecx & bit(X86_FEATURE_OSVW));
+}
+
 #endif
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 0982507..8375622 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -57,6 +57,7 @@
 #define OpDS              23ull  /* DS */
 #define OpFS              24ull  /* FS */
 #define OpGS              25ull  /* GS */
+#define OpMem8            26ull  /* 8-bit zero extended memory operand */
 
 #define OpBits             5  /* Width of operand field */
 #define OpMask             ((1ull << OpBits) - 1)
@@ -101,6 +102,7 @@
 #define SrcAcc      (OpAcc << SrcShift)
 #define SrcImmU16   (OpImmU16 << SrcShift)
 #define SrcDX       (OpDX << SrcShift)
+#define SrcMem8     (OpMem8 << SrcShift)
 #define SrcMask     (OpMask << SrcShift)
 #define BitOp       (1<<11)
 #define MemAbs      (1<<12)      /* Memory operand is absolute displacement */
@@ -858,8 +860,7 @@
 }
 
 static void decode_register_operand(struct x86_emulate_ctxt *ctxt,
-				    struct operand *op,
-				    int inhibit_bytereg)
+				    struct operand *op)
 {
 	unsigned reg = ctxt->modrm_reg;
 	int highbyte_regs = ctxt->rex_prefix == 0;
@@ -876,7 +877,7 @@
 	}
 
 	op->type = OP_REG;
-	if ((ctxt->d & ByteOp) && !inhibit_bytereg) {
+	if (ctxt->d & ByteOp) {
 		op->addr.reg = decode_register(reg, ctxt->regs, highbyte_regs);
 		op->bytes = 1;
 	} else {
@@ -1151,6 +1152,22 @@
 	return 1;
 }
 
+static int read_interrupt_descriptor(struct x86_emulate_ctxt *ctxt,
+				     u16 index, struct desc_struct *desc)
+{
+	struct desc_ptr dt;
+	ulong addr;
+
+	ctxt->ops->get_idt(ctxt, &dt);
+
+	if (dt.size < index * 8 + 7)
+		return emulate_gp(ctxt, index << 3 | 0x2);
+
+	addr = dt.address + index * 8;
+	return ctxt->ops->read_std(ctxt, addr, desc, sizeof *desc,
+				   &ctxt->exception);
+}
+
 static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt,
 				     u16 selector, struct desc_ptr *dt)
 {
@@ -1227,6 +1244,8 @@
 		seg_desc.type = 3;
 		seg_desc.p = 1;
 		seg_desc.s = 1;
+		if (ctxt->mode == X86EMUL_MODE_VM86)
+			seg_desc.dpl = 3;
 		goto load;
 	}
 
@@ -1891,6 +1910,17 @@
 	ss->p = 1;
 }
 
+static bool vendor_intel(struct x86_emulate_ctxt *ctxt)
+{
+	u32 eax, ebx, ecx, edx;
+
+	eax = ecx = 0;
+	return ctxt->ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx)
+		&& ebx == X86EMUL_CPUID_VENDOR_GenuineIntel_ebx
+		&& ecx == X86EMUL_CPUID_VENDOR_GenuineIntel_ecx
+		&& edx == X86EMUL_CPUID_VENDOR_GenuineIntel_edx;
+}
+
 static bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt)
 {
 	struct x86_emulate_ops *ops = ctxt->ops;
@@ -2007,6 +2037,14 @@
 	if (ctxt->mode == X86EMUL_MODE_REAL)
 		return emulate_gp(ctxt, 0);
 
+	/*
+	 * Not recognized on AMD in compat mode (but is recognized in legacy
+	 * mode).
+	 */
+	if ((ctxt->mode == X86EMUL_MODE_PROT32) && (efer & EFER_LMA)
+	    && !vendor_intel(ctxt))
+		return emulate_ud(ctxt);
+
 	/* XXX sysenter/sysexit have not been tested in 64bit mode.
 	* Therefore, we inject an #UD.
 	*/
@@ -2306,6 +2344,8 @@
 		return emulate_gp(ctxt, 0);
 	ctxt->_eip = tss->eip;
 	ctxt->eflags = tss->eflags | 2;
+
+	/* General purpose registers */
 	ctxt->regs[VCPU_REGS_RAX] = tss->eax;
 	ctxt->regs[VCPU_REGS_RCX] = tss->ecx;
 	ctxt->regs[VCPU_REGS_RDX] = tss->edx;
@@ -2328,6 +2368,24 @@
 	set_segment_selector(ctxt, tss->gs, VCPU_SREG_GS);
 
 	/*
+	 * If we're switching between Protected Mode and VM86, we need to make
+	 * sure to update the mode before loading the segment descriptors so
+	 * that the selectors are interpreted correctly.
+	 *
+	 * Need to get rflags to the vcpu struct immediately because it
+	 * influences the CPL which is checked at least when loading the segment
+	 * descriptors and when pushing an error code to the new kernel stack.
+	 *
+	 * TODO Introduce a separate ctxt->ops->set_cpl callback
+	 */
+	if (ctxt->eflags & X86_EFLAGS_VM)
+		ctxt->mode = X86EMUL_MODE_VM86;
+	else
+		ctxt->mode = X86EMUL_MODE_PROT32;
+
+	ctxt->ops->set_rflags(ctxt, ctxt->eflags);
+
+	/*
 	 * Now load segment descriptors. If fault happenes at this stage
 	 * it is handled in a context of new task
 	 */
@@ -2401,7 +2459,7 @@
 }
 
 static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
-				   u16 tss_selector, int reason,
+				   u16 tss_selector, int idt_index, int reason,
 				   bool has_error_code, u32 error_code)
 {
 	struct x86_emulate_ops *ops = ctxt->ops;
@@ -2423,12 +2481,35 @@
 
 	/* FIXME: check that next_tss_desc is tss */
 
-	if (reason != TASK_SWITCH_IRET) {
-		if ((tss_selector & 3) > next_tss_desc.dpl ||
-		    ops->cpl(ctxt) > next_tss_desc.dpl)
-			return emulate_gp(ctxt, 0);
+	/*
+	 * Check privileges. The three cases are task switch caused by...
+	 *
+	 * 1. jmp/call/int to task gate: Check against DPL of the task gate
+	 * 2. Exception/IRQ/iret: No check is performed
+	 * 3. jmp/call to TSS: Check agains DPL of the TSS
+	 */
+	if (reason == TASK_SWITCH_GATE) {
+		if (idt_index != -1) {
+			/* Software interrupts */
+			struct desc_struct task_gate_desc;
+			int dpl;
+
+			ret = read_interrupt_descriptor(ctxt, idt_index,
+							&task_gate_desc);
+			if (ret != X86EMUL_CONTINUE)
+				return ret;
+
+			dpl = task_gate_desc.dpl;
+			if ((tss_selector & 3) > dpl || ops->cpl(ctxt) > dpl)
+				return emulate_gp(ctxt, (idt_index << 3) | 0x2);
+		}
+	} else if (reason != TASK_SWITCH_IRET) {
+		int dpl = next_tss_desc.dpl;
+		if ((tss_selector & 3) > dpl || ops->cpl(ctxt) > dpl)
+			return emulate_gp(ctxt, tss_selector);
 	}
 
+
 	desc_limit = desc_limit_scaled(&next_tss_desc);
 	if (!next_tss_desc.p ||
 	    ((desc_limit < 0x67 && (next_tss_desc.type & 8)) ||
@@ -2481,7 +2562,7 @@
 }
 
 int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
-			 u16 tss_selector, int reason,
+			 u16 tss_selector, int idt_index, int reason,
 			 bool has_error_code, u32 error_code)
 {
 	int rc;
@@ -2489,7 +2570,7 @@
 	ctxt->_eip = ctxt->eip;
 	ctxt->dst.type = OP_NONE;
 
-	rc = emulator_do_task_switch(ctxt, tss_selector, reason,
+	rc = emulator_do_task_switch(ctxt, tss_selector, idt_index, reason,
 				     has_error_code, error_code);
 
 	if (rc == X86EMUL_CONTINUE)
@@ -3514,13 +3595,13 @@
 	I(DstMem | SrcReg | ModRM | BitOp | Lock, em_btr),
 	I(DstReg | SrcMemFAddr | ModRM | Src2FS, em_lseg),
 	I(DstReg | SrcMemFAddr | ModRM | Src2GS, em_lseg),
-	D(ByteOp | DstReg | SrcMem | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
+	D(DstReg | SrcMem8 | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
 	/* 0xB8 - 0xBF */
 	N, N,
 	G(BitOp, group8),
 	I(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_btc),
 	I(DstReg | SrcMem | ModRM, em_bsf), I(DstReg | SrcMem | ModRM, em_bsr),
-	D(ByteOp | DstReg | SrcMem | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
+	D(DstReg | SrcMem8 | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
 	/* 0xC0 - 0xCF */
 	D2bv(DstMem | SrcReg | ModRM | Lock),
 	N, D(DstMem | SrcReg | ModRM | Mov),
@@ -3602,9 +3683,7 @@
 
 	switch (d) {
 	case OpReg:
-		decode_register_operand(ctxt, op,
-			 op == &ctxt->dst &&
-			 ctxt->twobyte && (ctxt->b == 0xb6 || ctxt->b == 0xb7));
+		decode_register_operand(ctxt, op);
 		break;
 	case OpImmUByte:
 		rc = decode_imm(ctxt, op, 1, false);
@@ -3656,6 +3735,9 @@
 	case OpImm:
 		rc = decode_imm(ctxt, op, imm_size(ctxt), true);
 		break;
+	case OpMem8:
+		ctxt->memop.bytes = 1;
+		goto mem_common;
 	case OpMem16:
 		ctxt->memop.bytes = 2;
 		goto mem_common;
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c
index b6a7353..81cf4fa 100644
--- a/arch/x86/kvm/i8259.c
+++ b/arch/x86/kvm/i8259.c
@@ -307,6 +307,7 @@
 		if (val & 0x10) {
 			s->init4 = val & 1;
 			s->last_irr = 0;
+			s->irr &= s->elcr;
 			s->imr = 0;
 			s->priority_add = 0;
 			s->special_mask = 0;
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 31bfc69..8584322 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -433,7 +433,7 @@
 		break;
 
 	case APIC_DM_INIT:
-		if (level) {
+		if (!trig_mode || level) {
 			result = 1;
 			vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED;
 			kvm_make_request(KVM_REQ_EVENT, vcpu);
@@ -731,7 +731,7 @@
 		u64 guest_tsc, tscdeadline = apic->lapic_timer.tscdeadline;
 		u64 ns = 0;
 		struct kvm_vcpu *vcpu = apic->vcpu;
-		unsigned long this_tsc_khz = vcpu_tsc_khz(vcpu);
+		unsigned long this_tsc_khz = vcpu->arch.virtual_tsc_khz;
 		unsigned long flags;
 
 		if (unlikely(!tscdeadline || !this_tsc_khz))
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 224b02c..4cb1642 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -688,9 +688,8 @@
 {
 	unsigned long idx;
 
-	idx = (gfn >> KVM_HPAGE_GFN_SHIFT(level)) -
-	      (slot->base_gfn >> KVM_HPAGE_GFN_SHIFT(level));
-	return &slot->lpage_info[level - 2][idx];
+	idx = gfn_to_index(gfn, slot->base_gfn, level);
+	return &slot->arch.lpage_info[level - 2][idx];
 }
 
 static void account_shadowed(struct kvm *kvm, gfn_t gfn)
@@ -946,7 +945,7 @@
 	}
 }
 
-static unsigned long *__gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int level,
+static unsigned long *__gfn_to_rmap(gfn_t gfn, int level,
 				    struct kvm_memory_slot *slot)
 {
 	struct kvm_lpage_info *linfo;
@@ -966,7 +965,7 @@
 	struct kvm_memory_slot *slot;
 
 	slot = gfn_to_memslot(kvm, gfn);
-	return __gfn_to_rmap(kvm, gfn, level, slot);
+	return __gfn_to_rmap(gfn, level, slot);
 }
 
 static bool rmap_can_add(struct kvm_vcpu *vcpu)
@@ -988,7 +987,7 @@
 	return pte_list_add(vcpu, spte, rmapp);
 }
 
-static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte)
+static u64 *rmap_next(unsigned long *rmapp, u64 *spte)
 {
 	return pte_list_next(rmapp, spte);
 }
@@ -1018,8 +1017,8 @@
 	u64 *spte;
 	int i, write_protected = 0;
 
-	rmapp = __gfn_to_rmap(kvm, gfn, PT_PAGE_TABLE_LEVEL, slot);
-	spte = rmap_next(kvm, rmapp, NULL);
+	rmapp = __gfn_to_rmap(gfn, PT_PAGE_TABLE_LEVEL, slot);
+	spte = rmap_next(rmapp, NULL);
 	while (spte) {
 		BUG_ON(!(*spte & PT_PRESENT_MASK));
 		rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
@@ -1027,14 +1026,14 @@
 			mmu_spte_update(spte, *spte & ~PT_WRITABLE_MASK);
 			write_protected = 1;
 		}
-		spte = rmap_next(kvm, rmapp, spte);
+		spte = rmap_next(rmapp, spte);
 	}
 
 	/* check for huge page mappings */
 	for (i = PT_DIRECTORY_LEVEL;
 	     i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
-		rmapp = __gfn_to_rmap(kvm, gfn, i, slot);
-		spte = rmap_next(kvm, rmapp, NULL);
+		rmapp = __gfn_to_rmap(gfn, i, slot);
+		spte = rmap_next(rmapp, NULL);
 		while (spte) {
 			BUG_ON(!(*spte & PT_PRESENT_MASK));
 			BUG_ON(!is_large_pte(*spte));
@@ -1045,7 +1044,7 @@
 				spte = NULL;
 				write_protected = 1;
 			}
-			spte = rmap_next(kvm, rmapp, spte);
+			spte = rmap_next(rmapp, spte);
 		}
 	}
 
@@ -1066,7 +1065,7 @@
 	u64 *spte;
 	int need_tlb_flush = 0;
 
-	while ((spte = rmap_next(kvm, rmapp, NULL))) {
+	while ((spte = rmap_next(rmapp, NULL))) {
 		BUG_ON(!(*spte & PT_PRESENT_MASK));
 		rmap_printk("kvm_rmap_unmap_hva: spte %p %llx\n", spte, *spte);
 		drop_spte(kvm, spte);
@@ -1085,14 +1084,14 @@
 
 	WARN_ON(pte_huge(*ptep));
 	new_pfn = pte_pfn(*ptep);
-	spte = rmap_next(kvm, rmapp, NULL);
+	spte = rmap_next(rmapp, NULL);
 	while (spte) {
 		BUG_ON(!is_shadow_present_pte(*spte));
 		rmap_printk("kvm_set_pte_rmapp: spte %p %llx\n", spte, *spte);
 		need_flush = 1;
 		if (pte_write(*ptep)) {
 			drop_spte(kvm, spte);
-			spte = rmap_next(kvm, rmapp, NULL);
+			spte = rmap_next(rmapp, NULL);
 		} else {
 			new_spte = *spte &~ (PT64_BASE_ADDR_MASK);
 			new_spte |= (u64)new_pfn << PAGE_SHIFT;
@@ -1102,7 +1101,7 @@
 			new_spte &= ~shadow_accessed_mask;
 			mmu_spte_clear_track_bits(spte);
 			mmu_spte_set(spte, new_spte);
-			spte = rmap_next(kvm, rmapp, spte);
+			spte = rmap_next(rmapp, spte);
 		}
 	}
 	if (need_flush)
@@ -1176,7 +1175,7 @@
 	if (!shadow_accessed_mask)
 		return kvm_unmap_rmapp(kvm, rmapp, data);
 
-	spte = rmap_next(kvm, rmapp, NULL);
+	spte = rmap_next(rmapp, NULL);
 	while (spte) {
 		int _young;
 		u64 _spte = *spte;
@@ -1186,7 +1185,7 @@
 			young = 1;
 			clear_bit(PT_ACCESSED_SHIFT, (unsigned long *)spte);
 		}
-		spte = rmap_next(kvm, rmapp, spte);
+		spte = rmap_next(rmapp, spte);
 	}
 	return young;
 }
@@ -1205,7 +1204,7 @@
 	if (!shadow_accessed_mask)
 		goto out;
 
-	spte = rmap_next(kvm, rmapp, NULL);
+	spte = rmap_next(rmapp, NULL);
 	while (spte) {
 		u64 _spte = *spte;
 		BUG_ON(!(_spte & PT_PRESENT_MASK));
@@ -1214,7 +1213,7 @@
 			young = 1;
 			break;
 		}
-		spte = rmap_next(kvm, rmapp, spte);
+		spte = rmap_next(rmapp, spte);
 	}
 out:
 	return young;
@@ -1391,11 +1390,6 @@
 	unsigned int nr;
 };
 
-#define for_each_unsync_children(bitmap, idx)		\
-	for (idx = find_first_bit(bitmap, 512);		\
-	     idx < 512;					\
-	     idx = find_next_bit(bitmap, 512, idx+1))
-
 static int mmu_pages_add(struct kvm_mmu_pages *pvec, struct kvm_mmu_page *sp,
 			 int idx)
 {
@@ -1417,7 +1411,7 @@
 {
 	int i, ret, nr_unsync_leaf = 0;
 
-	for_each_unsync_children(sp->unsync_child_bitmap, i) {
+	for_each_set_bit(i, sp->unsync_child_bitmap, 512) {
 		struct kvm_mmu_page *child;
 		u64 ent = sp->spt[i];
 
@@ -1803,6 +1797,7 @@
 {
 	if (is_large_pte(*sptep)) {
 		drop_spte(vcpu->kvm, sptep);
+		--vcpu->kvm->stat.lpages;
 		kvm_flush_remote_tlbs(vcpu->kvm);
 	}
 }
@@ -3190,15 +3185,14 @@
 #undef PTTYPE
 
 static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
-				  struct kvm_mmu *context,
-				  int level)
+				  struct kvm_mmu *context)
 {
 	int maxphyaddr = cpuid_maxphyaddr(vcpu);
 	u64 exb_bit_rsvd = 0;
 
 	if (!context->nx)
 		exb_bit_rsvd = rsvd_bits(63, 63);
-	switch (level) {
+	switch (context->root_level) {
 	case PT32_ROOT_LEVEL:
 		/* no rsvd bits for 2 level 4K page table entries */
 		context->rsvd_bits_mask[0][1] = 0;
@@ -3256,8 +3250,9 @@
 					int level)
 {
 	context->nx = is_nx(vcpu);
+	context->root_level = level;
 
-	reset_rsvds_bits_mask(vcpu, context, level);
+	reset_rsvds_bits_mask(vcpu, context);
 
 	ASSERT(is_pae(vcpu));
 	context->new_cr3 = paging_new_cr3;
@@ -3267,7 +3262,6 @@
 	context->invlpg = paging64_invlpg;
 	context->update_pte = paging64_update_pte;
 	context->free = paging_free;
-	context->root_level = level;
 	context->shadow_root_level = level;
 	context->root_hpa = INVALID_PAGE;
 	context->direct_map = false;
@@ -3284,8 +3278,9 @@
 				 struct kvm_mmu *context)
 {
 	context->nx = false;
+	context->root_level = PT32_ROOT_LEVEL;
 
-	reset_rsvds_bits_mask(vcpu, context, PT32_ROOT_LEVEL);
+	reset_rsvds_bits_mask(vcpu, context);
 
 	context->new_cr3 = paging_new_cr3;
 	context->page_fault = paging32_page_fault;
@@ -3294,7 +3289,6 @@
 	context->sync_page = paging32_sync_page;
 	context->invlpg = paging32_invlpg;
 	context->update_pte = paging32_update_pte;
-	context->root_level = PT32_ROOT_LEVEL;
 	context->shadow_root_level = PT32E_ROOT_LEVEL;
 	context->root_hpa = INVALID_PAGE;
 	context->direct_map = false;
@@ -3325,7 +3319,6 @@
 	context->get_cr3 = get_cr3;
 	context->get_pdptr = kvm_pdptr_read;
 	context->inject_page_fault = kvm_inject_page_fault;
-	context->nx = is_nx(vcpu);
 
 	if (!is_paging(vcpu)) {
 		context->nx = false;
@@ -3333,19 +3326,19 @@
 		context->root_level = 0;
 	} else if (is_long_mode(vcpu)) {
 		context->nx = is_nx(vcpu);
-		reset_rsvds_bits_mask(vcpu, context, PT64_ROOT_LEVEL);
-		context->gva_to_gpa = paging64_gva_to_gpa;
 		context->root_level = PT64_ROOT_LEVEL;
+		reset_rsvds_bits_mask(vcpu, context);
+		context->gva_to_gpa = paging64_gva_to_gpa;
 	} else if (is_pae(vcpu)) {
 		context->nx = is_nx(vcpu);
-		reset_rsvds_bits_mask(vcpu, context, PT32E_ROOT_LEVEL);
-		context->gva_to_gpa = paging64_gva_to_gpa;
 		context->root_level = PT32E_ROOT_LEVEL;
+		reset_rsvds_bits_mask(vcpu, context);
+		context->gva_to_gpa = paging64_gva_to_gpa;
 	} else {
 		context->nx = false;
-		reset_rsvds_bits_mask(vcpu, context, PT32_ROOT_LEVEL);
-		context->gva_to_gpa = paging32_gva_to_gpa;
 		context->root_level = PT32_ROOT_LEVEL;
+		reset_rsvds_bits_mask(vcpu, context);
+		context->gva_to_gpa = paging32_gva_to_gpa;
 	}
 
 	return 0;
@@ -3408,18 +3401,18 @@
 		g_context->gva_to_gpa = nonpaging_gva_to_gpa_nested;
 	} else if (is_long_mode(vcpu)) {
 		g_context->nx = is_nx(vcpu);
-		reset_rsvds_bits_mask(vcpu, g_context, PT64_ROOT_LEVEL);
 		g_context->root_level = PT64_ROOT_LEVEL;
+		reset_rsvds_bits_mask(vcpu, g_context);
 		g_context->gva_to_gpa = paging64_gva_to_gpa_nested;
 	} else if (is_pae(vcpu)) {
 		g_context->nx = is_nx(vcpu);
-		reset_rsvds_bits_mask(vcpu, g_context, PT32E_ROOT_LEVEL);
 		g_context->root_level = PT32E_ROOT_LEVEL;
+		reset_rsvds_bits_mask(vcpu, g_context);
 		g_context->gva_to_gpa = paging64_gva_to_gpa_nested;
 	} else {
 		g_context->nx = false;
-		reset_rsvds_bits_mask(vcpu, g_context, PT32_ROOT_LEVEL);
 		g_context->root_level = PT32_ROOT_LEVEL;
+		reset_rsvds_bits_mask(vcpu, g_context);
 		g_context->gva_to_gpa = paging32_gva_to_gpa_nested;
 	}
 
@@ -3555,7 +3548,7 @@
  * If we're seeing too many writes to a page, it may no longer be a page table,
  * or we may be forking, in which case it is better to unmap the page.
  */
-static bool detect_write_flooding(struct kvm_mmu_page *sp, u64 *spte)
+static bool detect_write_flooding(struct kvm_mmu_page *sp)
 {
 	/*
 	 * Skip write-flooding detected for the sp whose level is 1, because
@@ -3664,10 +3657,8 @@
 
 	mask.cr0_wp = mask.cr4_pae = mask.nxe = 1;
 	for_each_gfn_indirect_valid_sp(vcpu->kvm, sp, gfn, node) {
-		spte = get_written_sptes(sp, gpa, &npte);
-
 		if (detect_write_misaligned(sp, gpa, bytes) ||
-		      detect_write_flooding(sp, spte)) {
+		      detect_write_flooding(sp)) {
 			zap_page |= !!kvm_mmu_prepare_zap_page(vcpu->kvm, sp,
 						     &invalid_list);
 			++vcpu->kvm->stat.mmu_flooded;
diff --git a/arch/x86/kvm/mmu_audit.c b/arch/x86/kvm/mmu_audit.c
index ea7b4fd..715da5a 100644
--- a/arch/x86/kvm/mmu_audit.c
+++ b/arch/x86/kvm/mmu_audit.c
@@ -200,13 +200,13 @@
 	slot = gfn_to_memslot(kvm, sp->gfn);
 	rmapp = &slot->rmap[sp->gfn - slot->base_gfn];
 
-	spte = rmap_next(kvm, rmapp, NULL);
+	spte = rmap_next(rmapp, NULL);
 	while (spte) {
 		if (is_writable_pte(*spte))
 			audit_printk(kvm, "shadow page has writable "
 				     "mappings: gfn %llx role %x\n",
 				     sp->gfn, sp->role.word);
-		spte = rmap_next(kvm, rmapp, spte);
+		spte = rmap_next(rmapp, spte);
 	}
 }
 
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 7aad544..a73f0c1 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -33,10 +33,11 @@
 	[4] = { 0x2e, 0x41, PERF_COUNT_HW_CACHE_MISSES },
 	[5] = { 0xc4, 0x00, PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
 	[6] = { 0xc5, 0x00, PERF_COUNT_HW_BRANCH_MISSES },
+	[7] = { 0x00, 0x30, PERF_COUNT_HW_REF_CPU_CYCLES },
 };
 
 /* mapping between fixed pmc index and arch_events array */
-int fixed_pmc_events[] = {1, 0, 2};
+int fixed_pmc_events[] = {1, 0, 7};
 
 static bool pmc_is_gp(struct kvm_pmc *pmc)
 {
@@ -210,6 +211,9 @@
 	unsigned config, type = PERF_TYPE_RAW;
 	u8 event_select, unit_mask;
 
+	if (eventsel & ARCH_PERFMON_EVENTSEL_PIN_CONTROL)
+		printk_once("kvm pmu: pin control bit is ignored\n");
+
 	pmc->eventsel = eventsel;
 
 	stop_counter(pmc);
@@ -220,7 +224,7 @@
 	event_select = eventsel & ARCH_PERFMON_EVENTSEL_EVENT;
 	unit_mask = (eventsel & ARCH_PERFMON_EVENTSEL_UMASK) >> 8;
 
-	if (!(event_select & (ARCH_PERFMON_EVENTSEL_EDGE |
+	if (!(eventsel & (ARCH_PERFMON_EVENTSEL_EDGE |
 				ARCH_PERFMON_EVENTSEL_INV |
 				ARCH_PERFMON_EVENTSEL_CMASK))) {
 		config = find_arch_event(&pmc->vcpu->arch.pmu, event_select,
@@ -413,7 +417,7 @@
 	struct kvm_pmc *counters;
 	u64 ctr;
 
-	pmc &= (3u << 30) - 1;
+	pmc &= ~(3u << 30);
 	if (!fixed && pmc >= pmu->nr_arch_gp_counters)
 		return 1;
 	if (fixed && pmc >= pmu->nr_arch_fixed_counters)
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index e385214..e334389 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -111,6 +111,12 @@
 #define MSRPM_OFFSETS	16
 static u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly;
 
+/*
+ * Set osvw_len to higher value when updated Revision Guides
+ * are published and we know what the new status bits are
+ */
+static uint64_t osvw_len = 4, osvw_status;
+
 struct vcpu_svm {
 	struct kvm_vcpu vcpu;
 	struct vmcb *vmcb;
@@ -177,11 +183,13 @@
 #else
 static bool npt_enabled;
 #endif
-static int npt = 1;
 
+/* allow nested paging (virtualized MMU) for all guests */
+static int npt = true;
 module_param(npt, int, S_IRUGO);
 
-static int nested = 1;
+/* allow nested virtualization in KVM/SVM */
+static int nested = true;
 module_param(nested, int, S_IRUGO);
 
 static void svm_flush_tlb(struct kvm_vcpu *vcpu);
@@ -557,6 +565,27 @@
 	erratum_383_found = true;
 }
 
+static void svm_init_osvw(struct kvm_vcpu *vcpu)
+{
+	/*
+	 * Guests should see errata 400 and 415 as fixed (assuming that
+	 * HLT and IO instructions are intercepted).
+	 */
+	vcpu->arch.osvw.length = (osvw_len >= 3) ? (osvw_len) : 3;
+	vcpu->arch.osvw.status = osvw_status & ~(6ULL);
+
+	/*
+	 * By increasing VCPU's osvw.length to 3 we are telling the guest that
+	 * all osvw.status bits inside that length, including bit 0 (which is
+	 * reserved for erratum 298), are valid. However, if host processor's
+	 * osvw_len is 0 then osvw_status[0] carries no information. We need to
+	 * be conservative here and therefore we tell the guest that erratum 298
+	 * is present (because we really don't know).
+	 */
+	if (osvw_len == 0 && boot_cpu_data.x86 == 0x10)
+		vcpu->arch.osvw.status |= 1;
+}
+
 static int has_svm(void)
 {
 	const char *msg;
@@ -623,6 +652,36 @@
 		__get_cpu_var(current_tsc_ratio) = TSC_RATIO_DEFAULT;
 	}
 
+
+	/*
+	 * Get OSVW bits.
+	 *
+	 * Note that it is possible to have a system with mixed processor
+	 * revisions and therefore different OSVW bits. If bits are not the same
+	 * on different processors then choose the worst case (i.e. if erratum
+	 * is present on one processor and not on another then assume that the
+	 * erratum is present everywhere).
+	 */
+	if (cpu_has(&boot_cpu_data, X86_FEATURE_OSVW)) {
+		uint64_t len, status = 0;
+		int err;
+
+		len = native_read_msr_safe(MSR_AMD64_OSVW_ID_LENGTH, &err);
+		if (!err)
+			status = native_read_msr_safe(MSR_AMD64_OSVW_STATUS,
+						      &err);
+
+		if (err)
+			osvw_status = osvw_len = 0;
+		else {
+			if (len < osvw_len)
+				osvw_len = len;
+			osvw_status |= status;
+			osvw_status &= (1ULL << osvw_len) - 1;
+		}
+	} else
+		osvw_status = osvw_len = 0;
+
 	svm_init_erratum_383();
 
 	amd_pmu_enable_virt();
@@ -910,23 +969,28 @@
 	return _tsc;
 }
 
-static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
+static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
 	u64 ratio;
 	u64 khz;
 
-	/* TSC scaling supported? */
-	if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR))
-		return;
-
-	/* TSC-Scaling disabled or guest TSC same frequency as host TSC? */
-	if (user_tsc_khz == 0) {
-		vcpu->arch.virtual_tsc_khz = 0;
+	/* Guest TSC same frequency as host TSC? */
+	if (!scale) {
 		svm->tsc_ratio = TSC_RATIO_DEFAULT;
 		return;
 	}
 
+	/* TSC scaling supported? */
+	if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR)) {
+		if (user_tsc_khz > tsc_khz) {
+			vcpu->arch.tsc_catchup = 1;
+			vcpu->arch.tsc_always_catchup = 1;
+		} else
+			WARN(1, "user requested TSC rate below hardware speed\n");
+		return;
+	}
+
 	khz = user_tsc_khz;
 
 	/* TSC scaling required  - calculate ratio */
@@ -938,7 +1002,6 @@
 				user_tsc_khz);
 		return;
 	}
-	vcpu->arch.virtual_tsc_khz = user_tsc_khz;
 	svm->tsc_ratio             = ratio;
 }
 
@@ -958,10 +1021,14 @@
 	mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
 }
 
-static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment)
+static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool host)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
 
+	WARN_ON(adjustment < 0);
+	if (host)
+		adjustment = svm_scale_tsc(vcpu, adjustment);
+
 	svm->vmcb->control.tsc_offset += adjustment;
 	if (is_guest_mode(vcpu))
 		svm->nested.hsave->control.tsc_offset += adjustment;
@@ -1191,6 +1258,8 @@
 	if (kvm_vcpu_is_bsp(&svm->vcpu))
 		svm->vcpu.arch.apic_base |= MSR_IA32_APICBASE_BSP;
 
+	svm_init_osvw(&svm->vcpu);
+
 	return &svm->vcpu;
 
 free_page4:
@@ -1268,6 +1337,21 @@
 		wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
 }
 
+static void svm_update_cpl(struct kvm_vcpu *vcpu)
+{
+	struct vcpu_svm *svm = to_svm(vcpu);
+	int cpl;
+
+	if (!is_protmode(vcpu))
+		cpl = 0;
+	else if (svm->vmcb->save.rflags & X86_EFLAGS_VM)
+		cpl = 3;
+	else
+		cpl = svm->vmcb->save.cs.selector & 0x3;
+
+	svm->vmcb->save.cpl = cpl;
+}
+
 static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
 {
 	return to_svm(vcpu)->vmcb->save.rflags;
@@ -1275,7 +1359,11 @@
 
 static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
 {
+	unsigned long old_rflags = to_svm(vcpu)->vmcb->save.rflags;
+
 	to_svm(vcpu)->vmcb->save.rflags = rflags;
+	if ((old_rflags ^ rflags) & X86_EFLAGS_VM)
+		svm_update_cpl(vcpu);
 }
 
 static void svm_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
@@ -1543,9 +1631,7 @@
 		s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
 	}
 	if (seg == VCPU_SREG_CS)
-		svm->vmcb->save.cpl
-			= (svm->vmcb->save.cs.attrib
-			   >> SVM_SELECTOR_DPL_SHIFT) & 3;
+		svm_update_cpl(vcpu);
 
 	mark_dirty(svm->vmcb, VMCB_SEG);
 }
@@ -2735,7 +2821,10 @@
 	     (int_vec == OF_VECTOR || int_vec == BP_VECTOR)))
 		skip_emulated_instruction(&svm->vcpu);
 
-	if (kvm_task_switch(&svm->vcpu, tss_selector, reason,
+	if (int_type != SVM_EXITINTINFO_TYPE_SOFT)
+		int_vec = -1;
+
+	if (kvm_task_switch(&svm->vcpu, tss_selector, int_vec, reason,
 				has_error_code, error_code) == EMULATE_FAIL) {
 		svm->vcpu.run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
 		svm->vcpu.run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 3b4c8d8..280751c 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -70,9 +70,6 @@
 static bool __read_mostly vmm_exclusive = 1;
 module_param(vmm_exclusive, bool, S_IRUGO);
 
-static bool __read_mostly yield_on_hlt = 1;
-module_param(yield_on_hlt, bool, S_IRUGO);
-
 static bool __read_mostly fasteoi = 1;
 module_param(fasteoi, bool, S_IRUGO);
 
@@ -1457,7 +1454,7 @@
 #ifdef CONFIG_X86_64
 	wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
 #endif
-	if (__thread_has_fpu(current))
+	if (user_has_fpu())
 		clts();
 	load_gdt(&__get_cpu_var(host_gdt));
 }
@@ -1655,17 +1652,6 @@
 	vmx_set_interrupt_shadow(vcpu, 0);
 }
 
-static void vmx_clear_hlt(struct kvm_vcpu *vcpu)
-{
-	/* Ensure that we clear the HLT state in the VMCS.  We don't need to
-	 * explicitly skip the instruction because if the HLT state is set, then
-	 * the instruction is already executing and RIP has already been
-	 * advanced. */
-	if (!yield_on_hlt &&
-	    vmcs_read32(GUEST_ACTIVITY_STATE) == GUEST_ACTIVITY_HLT)
-		vmcs_write32(GUEST_ACTIVITY_STATE, GUEST_ACTIVITY_ACTIVE);
-}
-
 /*
  * KVM wants to inject page-faults which it got to the guest. This function
  * checks whether in a nested guest, we need to inject them to L1 or L2.
@@ -1678,7 +1664,7 @@
 	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
 
 	/* TODO: also check PFEC_MATCH/MASK, not just EB.PF. */
-	if (!(vmcs12->exception_bitmap & PF_VECTOR))
+	if (!(vmcs12->exception_bitmap & (1u << PF_VECTOR)))
 		return 0;
 
 	nested_vmx_vmexit(vcpu);
@@ -1718,7 +1704,6 @@
 		intr_info |= INTR_TYPE_HARD_EXCEPTION;
 
 	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info);
-	vmx_clear_hlt(vcpu);
 }
 
 static bool vmx_rdtscp_supported(void)
@@ -1817,13 +1802,19 @@
 }
 
 /*
- * Empty call-back. Needs to be implemented when VMX enables the SET_TSC_KHZ
- * ioctl. In this case the call-back should update internal vmx state to make
- * the changes effective.
+ * Engage any workarounds for mis-matched TSC rates.  Currently limited to
+ * software catchup for faster rates on slower CPUs.
  */
-static void vmx_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
+static void vmx_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
 {
-	/* Nothing to do here */
+	if (!scale)
+		return;
+
+	if (user_tsc_khz > tsc_khz) {
+		vcpu->arch.tsc_catchup = 1;
+		vcpu->arch.tsc_always_catchup = 1;
+	} else
+		WARN(1, "user requested TSC rate below hardware speed\n");
 }
 
 /*
@@ -1850,7 +1841,7 @@
 	}
 }
 
-static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment)
+static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool host)
 {
 	u64 offset = vmcs_read64(TSC_OFFSET);
 	vmcs_write64(TSC_OFFSET, offset + adjustment);
@@ -2219,6 +2210,9 @@
 		msr = find_msr_entry(vmx, msr_index);
 		if (msr) {
 			msr->data = data;
+			if (msr - vmx->guest_msrs < vmx->save_nmsrs)
+				kvm_set_shared_msr(msr->index, msr->data,
+						   msr->mask);
 			break;
 		}
 		ret = kvm_set_msr_common(vcpu, msr_index, data);
@@ -2399,7 +2393,7 @@
 				&_pin_based_exec_control) < 0)
 		return -EIO;
 
-	min =
+	min = CPU_BASED_HLT_EXITING |
 #ifdef CONFIG_X86_64
 	      CPU_BASED_CR8_LOAD_EXITING |
 	      CPU_BASED_CR8_STORE_EXITING |
@@ -2414,9 +2408,6 @@
 	      CPU_BASED_INVLPG_EXITING |
 	      CPU_BASED_RDPMC_EXITING;
 
-	if (yield_on_hlt)
-		min |= CPU_BASED_HLT_EXITING;
-
 	opt = CPU_BASED_TPR_SHADOW |
 	      CPU_BASED_USE_MSR_BITMAPS |
 	      CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
@@ -4003,7 +3994,6 @@
 	} else
 		intr |= INTR_TYPE_EXT_INTR;
 	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr);
-	vmx_clear_hlt(vcpu);
 }
 
 static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
@@ -4035,7 +4025,6 @@
 	}
 	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
 			INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK | NMI_VECTOR);
-	vmx_clear_hlt(vcpu);
 }
 
 static int vmx_nmi_allowed(struct kvm_vcpu *vcpu)
@@ -4672,9 +4661,10 @@
 	bool has_error_code = false;
 	u32 error_code = 0;
 	u16 tss_selector;
-	int reason, type, idt_v;
+	int reason, type, idt_v, idt_index;
 
 	idt_v = (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK);
+	idt_index = (vmx->idt_vectoring_info & VECTORING_INFO_VECTOR_MASK);
 	type = (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK);
 
 	exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
@@ -4712,8 +4702,9 @@
 		       type != INTR_TYPE_NMI_INTR))
 		skip_emulated_instruction(vcpu);
 
-	if (kvm_task_switch(vcpu, tss_selector, reason,
-				has_error_code, error_code) == EMULATE_FAIL) {
+	if (kvm_task_switch(vcpu, tss_selector,
+			    type == INTR_TYPE_SOFT_INTR ? idt_index : -1, reason,
+			    has_error_code, error_code) == EMULATE_FAIL) {
 		vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
 		vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
 		vcpu->run->internal.ndata = 0;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index bb4fd263..4044ce0 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -57,6 +57,7 @@
 #include <asm/mtrr.h>
 #include <asm/mce.h>
 #include <asm/i387.h>
+#include <asm/fpu-internal.h> /* Ugh! */
 #include <asm/xcr.h>
 #include <asm/pvclock.h>
 #include <asm/div64.h>
@@ -96,6 +97,10 @@
 u32  kvm_max_guest_tsc_khz;
 EXPORT_SYMBOL_GPL(kvm_max_guest_tsc_khz);
 
+/* tsc tolerance in parts per million - default to 1/2 of the NTP threshold */
+static u32 tsc_tolerance_ppm = 250;
+module_param(tsc_tolerance_ppm, uint, S_IRUGO | S_IWUSR);
+
 #define KVM_NR_SHARED_MSRS 16
 
 struct kvm_shared_msrs_global {
@@ -968,50 +973,51 @@
 static DEFINE_PER_CPU(unsigned long, cpu_tsc_khz);
 unsigned long max_tsc_khz;
 
-static inline int kvm_tsc_changes_freq(void)
-{
-	int cpu = get_cpu();
-	int ret = !boot_cpu_has(X86_FEATURE_CONSTANT_TSC) &&
-		  cpufreq_quick_get(cpu) != 0;
-	put_cpu();
-	return ret;
-}
-
-u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu)
-{
-	if (vcpu->arch.virtual_tsc_khz)
-		return vcpu->arch.virtual_tsc_khz;
-	else
-		return __this_cpu_read(cpu_tsc_khz);
-}
-
 static inline u64 nsec_to_cycles(struct kvm_vcpu *vcpu, u64 nsec)
 {
-	u64 ret;
-
-	WARN_ON(preemptible());
-	if (kvm_tsc_changes_freq())
-		printk_once(KERN_WARNING
-		 "kvm: unreliable cycle conversion on adjustable rate TSC\n");
-	ret = nsec * vcpu_tsc_khz(vcpu);
-	do_div(ret, USEC_PER_SEC);
-	return ret;
+	return pvclock_scale_delta(nsec, vcpu->arch.virtual_tsc_mult,
+				   vcpu->arch.virtual_tsc_shift);
 }
 
-static void kvm_init_tsc_catchup(struct kvm_vcpu *vcpu, u32 this_tsc_khz)
+static u32 adjust_tsc_khz(u32 khz, s32 ppm)
 {
+	u64 v = (u64)khz * (1000000 + ppm);
+	do_div(v, 1000000);
+	return v;
+}
+
+static void kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 this_tsc_khz)
+{
+	u32 thresh_lo, thresh_hi;
+	int use_scaling = 0;
+
 	/* Compute a scale to convert nanoseconds in TSC cycles */
 	kvm_get_time_scale(this_tsc_khz, NSEC_PER_SEC / 1000,
-			   &vcpu->arch.tsc_catchup_shift,
-			   &vcpu->arch.tsc_catchup_mult);
+			   &vcpu->arch.virtual_tsc_shift,
+			   &vcpu->arch.virtual_tsc_mult);
+	vcpu->arch.virtual_tsc_khz = this_tsc_khz;
+
+	/*
+	 * Compute the variation in TSC rate which is acceptable
+	 * within the range of tolerance and decide if the
+	 * rate being applied is within that bounds of the hardware
+	 * rate.  If so, no scaling or compensation need be done.
+	 */
+	thresh_lo = adjust_tsc_khz(tsc_khz, -tsc_tolerance_ppm);
+	thresh_hi = adjust_tsc_khz(tsc_khz, tsc_tolerance_ppm);
+	if (this_tsc_khz < thresh_lo || this_tsc_khz > thresh_hi) {
+		pr_debug("kvm: requested TSC rate %u falls outside tolerance [%u,%u]\n", this_tsc_khz, thresh_lo, thresh_hi);
+		use_scaling = 1;
+	}
+	kvm_x86_ops->set_tsc_khz(vcpu, this_tsc_khz, use_scaling);
 }
 
 static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
 {
-	u64 tsc = pvclock_scale_delta(kernel_ns-vcpu->arch.last_tsc_nsec,
-				      vcpu->arch.tsc_catchup_mult,
-				      vcpu->arch.tsc_catchup_shift);
-	tsc += vcpu->arch.last_tsc_write;
+	u64 tsc = pvclock_scale_delta(kernel_ns-vcpu->arch.this_tsc_nsec,
+				      vcpu->arch.virtual_tsc_mult,
+				      vcpu->arch.virtual_tsc_shift);
+	tsc += vcpu->arch.this_tsc_write;
 	return tsc;
 }
 
@@ -1020,48 +1026,88 @@
 	struct kvm *kvm = vcpu->kvm;
 	u64 offset, ns, elapsed;
 	unsigned long flags;
-	s64 sdiff;
+	s64 usdiff;
 
 	raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
 	offset = kvm_x86_ops->compute_tsc_offset(vcpu, data);
 	ns = get_kernel_ns();
 	elapsed = ns - kvm->arch.last_tsc_nsec;
-	sdiff = data - kvm->arch.last_tsc_write;
-	if (sdiff < 0)
-		sdiff = -sdiff;
+
+	/* n.b - signed multiplication and division required */
+	usdiff = data - kvm->arch.last_tsc_write;
+#ifdef CONFIG_X86_64
+	usdiff = (usdiff * 1000) / vcpu->arch.virtual_tsc_khz;
+#else
+	/* do_div() only does unsigned */
+	asm("idivl %2; xor %%edx, %%edx"
+	    : "=A"(usdiff)
+	    : "A"(usdiff * 1000), "rm"(vcpu->arch.virtual_tsc_khz));
+#endif
+	do_div(elapsed, 1000);
+	usdiff -= elapsed;
+	if (usdiff < 0)
+		usdiff = -usdiff;
 
 	/*
-	 * Special case: close write to TSC within 5 seconds of
-	 * another CPU is interpreted as an attempt to synchronize
-	 * The 5 seconds is to accommodate host load / swapping as
-	 * well as any reset of TSC during the boot process.
-	 *
-	 * In that case, for a reliable TSC, we can match TSC offsets,
-	 * or make a best guest using elapsed value.
-	 */
-	if (sdiff < nsec_to_cycles(vcpu, 5ULL * NSEC_PER_SEC) &&
-	    elapsed < 5ULL * NSEC_PER_SEC) {
+	 * Special case: TSC write with a small delta (1 second) of virtual
+	 * cycle time against real time is interpreted as an attempt to
+	 * synchronize the CPU.
+         *
+	 * For a reliable TSC, we can match TSC offsets, and for an unstable
+	 * TSC, we add elapsed time in this computation.  We could let the
+	 * compensation code attempt to catch up if we fall behind, but
+	 * it's better to try to match offsets from the beginning.
+         */
+	if (usdiff < USEC_PER_SEC &&
+	    vcpu->arch.virtual_tsc_khz == kvm->arch.last_tsc_khz) {
 		if (!check_tsc_unstable()) {
-			offset = kvm->arch.last_tsc_offset;
+			offset = kvm->arch.cur_tsc_offset;
 			pr_debug("kvm: matched tsc offset for %llu\n", data);
 		} else {
 			u64 delta = nsec_to_cycles(vcpu, elapsed);
-			offset += delta;
+			data += delta;
+			offset = kvm_x86_ops->compute_tsc_offset(vcpu, data);
 			pr_debug("kvm: adjusted tsc offset by %llu\n", delta);
 		}
-		ns = kvm->arch.last_tsc_nsec;
+	} else {
+		/*
+		 * We split periods of matched TSC writes into generations.
+		 * For each generation, we track the original measured
+		 * nanosecond time, offset, and write, so if TSCs are in
+		 * sync, we can match exact offset, and if not, we can match
+		 * exact software computaion in compute_guest_tsc()
+		 *
+		 * These values are tracked in kvm->arch.cur_xxx variables.
+		 */
+		kvm->arch.cur_tsc_generation++;
+		kvm->arch.cur_tsc_nsec = ns;
+		kvm->arch.cur_tsc_write = data;
+		kvm->arch.cur_tsc_offset = offset;
+		pr_debug("kvm: new tsc generation %u, clock %llu\n",
+			 kvm->arch.cur_tsc_generation, data);
 	}
+
+	/*
+	 * We also track th most recent recorded KHZ, write and time to
+	 * allow the matching interval to be extended at each write.
+	 */
 	kvm->arch.last_tsc_nsec = ns;
 	kvm->arch.last_tsc_write = data;
-	kvm->arch.last_tsc_offset = offset;
-	kvm_x86_ops->write_tsc_offset(vcpu, offset);
-	raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
+	kvm->arch.last_tsc_khz = vcpu->arch.virtual_tsc_khz;
 
 	/* Reset of TSC must disable overshoot protection below */
 	vcpu->arch.hv_clock.tsc_timestamp = 0;
-	vcpu->arch.last_tsc_write = data;
-	vcpu->arch.last_tsc_nsec = ns;
+	vcpu->arch.last_guest_tsc = data;
+
+	/* Keep track of which generation this VCPU has synchronized to */
+	vcpu->arch.this_tsc_generation = kvm->arch.cur_tsc_generation;
+	vcpu->arch.this_tsc_nsec = kvm->arch.cur_tsc_nsec;
+	vcpu->arch.this_tsc_write = kvm->arch.cur_tsc_write;
+
+	kvm_x86_ops->write_tsc_offset(vcpu, offset);
+	raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
 }
+
 EXPORT_SYMBOL_GPL(kvm_write_tsc);
 
 static int kvm_guest_time_update(struct kvm_vcpu *v)
@@ -1077,7 +1123,7 @@
 	local_irq_save(flags);
 	tsc_timestamp = kvm_x86_ops->read_l1_tsc(v);
 	kernel_ns = get_kernel_ns();
-	this_tsc_khz = vcpu_tsc_khz(v);
+	this_tsc_khz = __get_cpu_var(cpu_tsc_khz);
 	if (unlikely(this_tsc_khz == 0)) {
 		local_irq_restore(flags);
 		kvm_make_request(KVM_REQ_CLOCK_UPDATE, v);
@@ -1097,7 +1143,7 @@
 	if (vcpu->tsc_catchup) {
 		u64 tsc = compute_guest_tsc(v, kernel_ns);
 		if (tsc > tsc_timestamp) {
-			kvm_x86_ops->adjust_tsc_offset(v, tsc - tsc_timestamp);
+			adjust_tsc_offset_guest(v, tsc - tsc_timestamp);
 			tsc_timestamp = tsc;
 		}
 	}
@@ -1129,7 +1175,7 @@
 	 * observed by the guest and ensure the new system time is greater.
 	 */
 	max_kernel_ns = 0;
-	if (vcpu->hv_clock.tsc_timestamp && vcpu->last_guest_tsc) {
+	if (vcpu->hv_clock.tsc_timestamp) {
 		max_kernel_ns = vcpu->last_guest_tsc -
 				vcpu->hv_clock.tsc_timestamp;
 		max_kernel_ns = pvclock_scale_delta(max_kernel_ns,
@@ -1503,6 +1549,7 @@
 	case MSR_K7_HWCR:
 		data &= ~(u64)0x40;	/* ignore flush filter disable */
 		data &= ~(u64)0x100;	/* ignore ignne emulation enable */
+		data &= ~(u64)0x8;	/* ignore TLB cache disable */
 		if (data != 0) {
 			pr_unimpl(vcpu, "unimplemented HWCR wrmsr: 0x%llx\n",
 				data);
@@ -1675,6 +1722,16 @@
 		 */
 		pr_unimpl(vcpu, "ignored wrmsr: 0x%x data %llx\n", msr, data);
 		break;
+	case MSR_AMD64_OSVW_ID_LENGTH:
+		if (!guest_cpuid_has_osvw(vcpu))
+			return 1;
+		vcpu->arch.osvw.length = data;
+		break;
+	case MSR_AMD64_OSVW_STATUS:
+		if (!guest_cpuid_has_osvw(vcpu))
+			return 1;
+		vcpu->arch.osvw.status = data;
+		break;
 	default:
 		if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr))
 			return xen_hvm_config(vcpu, data);
@@ -1959,6 +2016,16 @@
 		 */
 		data = 0xbe702111;
 		break;
+	case MSR_AMD64_OSVW_ID_LENGTH:
+		if (!guest_cpuid_has_osvw(vcpu))
+			return 1;
+		data = vcpu->arch.osvw.length;
+		break;
+	case MSR_AMD64_OSVW_STATUS:
+		if (!guest_cpuid_has_osvw(vcpu))
+			return 1;
+		data = vcpu->arch.osvw.status;
+		break;
 	default:
 		if (kvm_pmu_msr(vcpu, msr))
 			return kvm_pmu_get_msr(vcpu, msr, pdata);
@@ -2079,6 +2146,7 @@
 	case KVM_CAP_XSAVE:
 	case KVM_CAP_ASYNC_PF:
 	case KVM_CAP_GET_TSC_KHZ:
+	case KVM_CAP_PCI_2_3:
 		r = 1;
 		break;
 	case KVM_CAP_COALESCED_MMIO:
@@ -2213,19 +2281,23 @@
 	}
 
 	kvm_x86_ops->vcpu_load(vcpu, cpu);
+
+	/* Apply any externally detected TSC adjustments (due to suspend) */
+	if (unlikely(vcpu->arch.tsc_offset_adjustment)) {
+		adjust_tsc_offset_host(vcpu, vcpu->arch.tsc_offset_adjustment);
+		vcpu->arch.tsc_offset_adjustment = 0;
+		set_bit(KVM_REQ_CLOCK_UPDATE, &vcpu->requests);
+	}
+
 	if (unlikely(vcpu->cpu != cpu) || check_tsc_unstable()) {
-		/* Make sure TSC doesn't go backwards */
-		s64 tsc_delta;
-		u64 tsc;
-
-		tsc = kvm_x86_ops->read_l1_tsc(vcpu);
-		tsc_delta = !vcpu->arch.last_guest_tsc ? 0 :
-			     tsc - vcpu->arch.last_guest_tsc;
-
+		s64 tsc_delta = !vcpu->arch.last_host_tsc ? 0 :
+				native_read_tsc() - vcpu->arch.last_host_tsc;
 		if (tsc_delta < 0)
 			mark_tsc_unstable("KVM discovered backwards TSC");
 		if (check_tsc_unstable()) {
-			kvm_x86_ops->adjust_tsc_offset(vcpu, -tsc_delta);
+			u64 offset = kvm_x86_ops->compute_tsc_offset(vcpu,
+						vcpu->arch.last_guest_tsc);
+			kvm_x86_ops->write_tsc_offset(vcpu, offset);
 			vcpu->arch.tsc_catchup = 1;
 		}
 		kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
@@ -2242,7 +2314,7 @@
 {
 	kvm_x86_ops->vcpu_put(vcpu);
 	kvm_put_guest_fpu(vcpu);
-	vcpu->arch.last_guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu);
+	vcpu->arch.last_host_tsc = native_read_tsc();
 }
 
 static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
@@ -2784,26 +2856,21 @@
 		u32 user_tsc_khz;
 
 		r = -EINVAL;
-		if (!kvm_has_tsc_control)
-			break;
-
 		user_tsc_khz = (u32)arg;
 
 		if (user_tsc_khz >= kvm_max_guest_tsc_khz)
 			goto out;
 
-		kvm_x86_ops->set_tsc_khz(vcpu, user_tsc_khz);
+		if (user_tsc_khz == 0)
+			user_tsc_khz = tsc_khz;
+
+		kvm_set_tsc_khz(vcpu, user_tsc_khz);
 
 		r = 0;
 		goto out;
 	}
 	case KVM_GET_TSC_KHZ: {
-		r = -EIO;
-		if (check_tsc_unstable())
-			goto out;
-
-		r = vcpu_tsc_khz(vcpu);
-
+		r = vcpu->arch.virtual_tsc_khz;
 		goto out;
 	}
 	default:
@@ -2814,6 +2881,11 @@
 	return r;
 }
 
+int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
+{
+	return VM_FAULT_SIGBUS;
+}
+
 static int kvm_vm_ioctl_set_tss_addr(struct kvm *kvm, unsigned long addr)
 {
 	int ret;
@@ -2997,6 +3069,8 @@
 			       unsigned long *dirty_bitmap,
 			       unsigned long nr_dirty_pages)
 {
+	spin_lock(&kvm->mmu_lock);
+
 	/* Not many dirty pages compared to # of shadow pages. */
 	if (nr_dirty_pages < kvm->arch.n_used_mmu_pages) {
 		unsigned long gfn_offset;
@@ -3004,16 +3078,13 @@
 		for_each_set_bit(gfn_offset, dirty_bitmap, memslot->npages) {
 			unsigned long gfn = memslot->base_gfn + gfn_offset;
 
-			spin_lock(&kvm->mmu_lock);
 			kvm_mmu_rmap_write_protect(kvm, gfn, memslot);
-			spin_unlock(&kvm->mmu_lock);
 		}
 		kvm_flush_remote_tlbs(kvm);
-	} else {
-		spin_lock(&kvm->mmu_lock);
+	} else
 		kvm_mmu_slot_remove_write_access(kvm, memslot->id);
-		spin_unlock(&kvm->mmu_lock);
-	}
+
+	spin_unlock(&kvm->mmu_lock);
 }
 
 /*
@@ -3132,6 +3203,9 @@
 		r = -EEXIST;
 		if (kvm->arch.vpic)
 			goto create_irqchip_unlock;
+		r = -EINVAL;
+		if (atomic_read(&kvm->online_vcpus))
+			goto create_irqchip_unlock;
 		r = -ENOMEM;
 		vpic = kvm_create_pic(kvm);
 		if (vpic) {
@@ -4062,6 +4136,11 @@
 	return res;
 }
 
+static void emulator_set_rflags(struct x86_emulate_ctxt *ctxt, ulong val)
+{
+	kvm_set_rflags(emul_to_vcpu(ctxt), val);
+}
+
 static int emulator_get_cpl(struct x86_emulate_ctxt *ctxt)
 {
 	return kvm_x86_ops->get_cpl(emul_to_vcpu(ctxt));
@@ -4243,6 +4322,7 @@
 	.set_idt	     = emulator_set_idt,
 	.get_cr              = emulator_get_cr,
 	.set_cr              = emulator_set_cr,
+	.set_rflags          = emulator_set_rflags,
 	.cpl                 = emulator_get_cpl,
 	.get_dr              = emulator_get_dr,
 	.set_dr              = emulator_set_dr,
@@ -5287,6 +5367,8 @@
 		profile_hit(KVM_PROFILING, (void *)rip);
 	}
 
+	if (unlikely(vcpu->arch.tsc_always_catchup))
+		kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
 
 	kvm_lapic_sync_from_vapic(vcpu);
 
@@ -5586,15 +5668,15 @@
 	return 0;
 }
 
-int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
-		    bool has_error_code, u32 error_code)
+int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index,
+		    int reason, bool has_error_code, u32 error_code)
 {
 	struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
 	int ret;
 
 	init_emulate_ctxt(vcpu);
 
-	ret = emulator_task_switch(ctxt, tss_selector, reason,
+	ret = emulator_task_switch(ctxt, tss_selector, idt_index, reason,
 				   has_error_code, error_code);
 
 	if (ret)
@@ -5927,13 +6009,88 @@
 	struct kvm *kvm;
 	struct kvm_vcpu *vcpu;
 	int i;
+	int ret;
+	u64 local_tsc;
+	u64 max_tsc = 0;
+	bool stable, backwards_tsc = false;
 
 	kvm_shared_msr_cpu_online();
-	list_for_each_entry(kvm, &vm_list, vm_list)
-		kvm_for_each_vcpu(i, vcpu, kvm)
-			if (vcpu->cpu == smp_processor_id())
-				kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
-	return kvm_x86_ops->hardware_enable(garbage);
+	ret = kvm_x86_ops->hardware_enable(garbage);
+	if (ret != 0)
+		return ret;
+
+	local_tsc = native_read_tsc();
+	stable = !check_tsc_unstable();
+	list_for_each_entry(kvm, &vm_list, vm_list) {
+		kvm_for_each_vcpu(i, vcpu, kvm) {
+			if (!stable && vcpu->cpu == smp_processor_id())
+				set_bit(KVM_REQ_CLOCK_UPDATE, &vcpu->requests);
+			if (stable && vcpu->arch.last_host_tsc > local_tsc) {
+				backwards_tsc = true;
+				if (vcpu->arch.last_host_tsc > max_tsc)
+					max_tsc = vcpu->arch.last_host_tsc;
+			}
+		}
+	}
+
+	/*
+	 * Sometimes, even reliable TSCs go backwards.  This happens on
+	 * platforms that reset TSC during suspend or hibernate actions, but
+	 * maintain synchronization.  We must compensate.  Fortunately, we can
+	 * detect that condition here, which happens early in CPU bringup,
+	 * before any KVM threads can be running.  Unfortunately, we can't
+	 * bring the TSCs fully up to date with real time, as we aren't yet far
+	 * enough into CPU bringup that we know how much real time has actually
+	 * elapsed; our helper function, get_kernel_ns() will be using boot
+	 * variables that haven't been updated yet.
+	 *
+	 * So we simply find the maximum observed TSC above, then record the
+	 * adjustment to TSC in each VCPU.  When the VCPU later gets loaded,
+	 * the adjustment will be applied.  Note that we accumulate
+	 * adjustments, in case multiple suspend cycles happen before some VCPU
+	 * gets a chance to run again.  In the event that no KVM threads get a
+	 * chance to run, we will miss the entire elapsed period, as we'll have
+	 * reset last_host_tsc, so VCPUs will not have the TSC adjusted and may
+	 * loose cycle time.  This isn't too big a deal, since the loss will be
+	 * uniform across all VCPUs (not to mention the scenario is extremely
+	 * unlikely). It is possible that a second hibernate recovery happens
+	 * much faster than a first, causing the observed TSC here to be
+	 * smaller; this would require additional padding adjustment, which is
+	 * why we set last_host_tsc to the local tsc observed here.
+	 *
+	 * N.B. - this code below runs only on platforms with reliable TSC,
+	 * as that is the only way backwards_tsc is set above.  Also note
+	 * that this runs for ALL vcpus, which is not a bug; all VCPUs should
+	 * have the same delta_cyc adjustment applied if backwards_tsc
+	 * is detected.  Note further, this adjustment is only done once,
+	 * as we reset last_host_tsc on all VCPUs to stop this from being
+	 * called multiple times (one for each physical CPU bringup).
+	 *
+	 * Platforms with unnreliable TSCs don't have to deal with this, they
+	 * will be compensated by the logic in vcpu_load, which sets the TSC to
+	 * catchup mode.  This will catchup all VCPUs to real time, but cannot
+	 * guarantee that they stay in perfect synchronization.
+	 */
+	if (backwards_tsc) {
+		u64 delta_cyc = max_tsc - local_tsc;
+		list_for_each_entry(kvm, &vm_list, vm_list) {
+			kvm_for_each_vcpu(i, vcpu, kvm) {
+				vcpu->arch.tsc_offset_adjustment += delta_cyc;
+				vcpu->arch.last_host_tsc = local_tsc;
+			}
+
+			/*
+			 * We have to disable TSC offset matching.. if you were
+			 * booting a VM while issuing an S4 host suspend....
+			 * you may have some problem.  Solving this issue is
+			 * left as an exercise to the reader.
+			 */
+			kvm->arch.last_tsc_nsec = 0;
+			kvm->arch.last_tsc_write = 0;
+		}
+
+	}
+	return 0;
 }
 
 void kvm_arch_hardware_disable(void *garbage)
@@ -5957,6 +6114,11 @@
 	kvm_x86_ops->check_processor_compatibility(rtn);
 }
 
+bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu)
+{
+	return irqchip_in_kernel(vcpu->kvm) == (vcpu->arch.apic != NULL);
+}
+
 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 {
 	struct page *page;
@@ -5979,7 +6141,7 @@
 	}
 	vcpu->arch.pio_data = page_address(page);
 
-	kvm_init_tsc_catchup(vcpu, max_tsc_khz);
+	kvm_set_tsc_khz(vcpu, max_tsc_khz);
 
 	r = kvm_mmu_create(vcpu);
 	if (r < 0)
@@ -6031,8 +6193,11 @@
 	free_page((unsigned long)vcpu->arch.pio_data);
 }
 
-int kvm_arch_init_vm(struct kvm *kvm)
+int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
+	if (type)
+		return -EINVAL;
+
 	INIT_LIST_HEAD(&kvm->arch.active_mmu_pages);
 	INIT_LIST_HEAD(&kvm->arch.assigned_dev_head);
 
@@ -6092,6 +6257,65 @@
 		put_page(kvm->arch.ept_identity_pagetable);
 }
 
+void kvm_arch_free_memslot(struct kvm_memory_slot *free,
+			   struct kvm_memory_slot *dont)
+{
+	int i;
+
+	for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
+		if (!dont || free->arch.lpage_info[i] != dont->arch.lpage_info[i]) {
+			vfree(free->arch.lpage_info[i]);
+			free->arch.lpage_info[i] = NULL;
+		}
+	}
+}
+
+int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
+{
+	int i;
+
+	for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
+		unsigned long ugfn;
+		int lpages;
+		int level = i + 2;
+
+		lpages = gfn_to_index(slot->base_gfn + npages - 1,
+				      slot->base_gfn, level) + 1;
+
+		slot->arch.lpage_info[i] =
+			vzalloc(lpages * sizeof(*slot->arch.lpage_info[i]));
+		if (!slot->arch.lpage_info[i])
+			goto out_free;
+
+		if (slot->base_gfn & (KVM_PAGES_PER_HPAGE(level) - 1))
+			slot->arch.lpage_info[i][0].write_count = 1;
+		if ((slot->base_gfn + npages) & (KVM_PAGES_PER_HPAGE(level) - 1))
+			slot->arch.lpage_info[i][lpages - 1].write_count = 1;
+		ugfn = slot->userspace_addr >> PAGE_SHIFT;
+		/*
+		 * If the gfn and userspace address are not aligned wrt each
+		 * other, or if explicitly asked to, disable large page
+		 * support for this slot
+		 */
+		if ((slot->base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE(level) - 1) ||
+		    !kvm_largepages_enabled()) {
+			unsigned long j;
+
+			for (j = 0; j < lpages; ++j)
+				slot->arch.lpage_info[i][j].write_count = 1;
+		}
+	}
+
+	return 0;
+
+out_free:
+	for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
+		vfree(slot->arch.lpage_info[i]);
+		slot->arch.lpage_info[i] = NULL;
+	}
+	return -ENOMEM;
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
 				struct kvm_memory_slot *memslot,
 				struct kvm_memory_slot old,
diff --git a/arch/x86/lib/atomic64_32.c b/arch/x86/lib/atomic64_32.c
index 042f682..a0b4a35 100644
--- a/arch/x86/lib/atomic64_32.c
+++ b/arch/x86/lib/atomic64_32.c
@@ -1,59 +1,4 @@
-#include <linux/compiler.h>
-#include <linux/module.h>
-#include <linux/types.h>
+#define ATOMIC64_EXPORT EXPORT_SYMBOL
 
-#include <asm/processor.h>
-#include <asm/cmpxchg.h>
+#include <linux/export.h>
 #include <linux/atomic.h>
-
-long long atomic64_read_cx8(long long, const atomic64_t *v);
-EXPORT_SYMBOL(atomic64_read_cx8);
-long long atomic64_set_cx8(long long, const atomic64_t *v);
-EXPORT_SYMBOL(atomic64_set_cx8);
-long long atomic64_xchg_cx8(long long, unsigned high);
-EXPORT_SYMBOL(atomic64_xchg_cx8);
-long long atomic64_add_return_cx8(long long a, atomic64_t *v);
-EXPORT_SYMBOL(atomic64_add_return_cx8);
-long long atomic64_sub_return_cx8(long long a, atomic64_t *v);
-EXPORT_SYMBOL(atomic64_sub_return_cx8);
-long long atomic64_inc_return_cx8(long long a, atomic64_t *v);
-EXPORT_SYMBOL(atomic64_inc_return_cx8);
-long long atomic64_dec_return_cx8(long long a, atomic64_t *v);
-EXPORT_SYMBOL(atomic64_dec_return_cx8);
-long long atomic64_dec_if_positive_cx8(atomic64_t *v);
-EXPORT_SYMBOL(atomic64_dec_if_positive_cx8);
-int atomic64_inc_not_zero_cx8(atomic64_t *v);
-EXPORT_SYMBOL(atomic64_inc_not_zero_cx8);
-int atomic64_add_unless_cx8(atomic64_t *v, long long a, long long u);
-EXPORT_SYMBOL(atomic64_add_unless_cx8);
-
-#ifndef CONFIG_X86_CMPXCHG64
-long long atomic64_read_386(long long, const atomic64_t *v);
-EXPORT_SYMBOL(atomic64_read_386);
-long long atomic64_set_386(long long, const atomic64_t *v);
-EXPORT_SYMBOL(atomic64_set_386);
-long long atomic64_xchg_386(long long, unsigned high);
-EXPORT_SYMBOL(atomic64_xchg_386);
-long long atomic64_add_return_386(long long a, atomic64_t *v);
-EXPORT_SYMBOL(atomic64_add_return_386);
-long long atomic64_sub_return_386(long long a, atomic64_t *v);
-EXPORT_SYMBOL(atomic64_sub_return_386);
-long long atomic64_inc_return_386(long long a, atomic64_t *v);
-EXPORT_SYMBOL(atomic64_inc_return_386);
-long long atomic64_dec_return_386(long long a, atomic64_t *v);
-EXPORT_SYMBOL(atomic64_dec_return_386);
-long long atomic64_add_386(long long a, atomic64_t *v);
-EXPORT_SYMBOL(atomic64_add_386);
-long long atomic64_sub_386(long long a, atomic64_t *v);
-EXPORT_SYMBOL(atomic64_sub_386);
-long long atomic64_inc_386(long long a, atomic64_t *v);
-EXPORT_SYMBOL(atomic64_inc_386);
-long long atomic64_dec_386(long long a, atomic64_t *v);
-EXPORT_SYMBOL(atomic64_dec_386);
-long long atomic64_dec_if_positive_386(atomic64_t *v);
-EXPORT_SYMBOL(atomic64_dec_if_positive_386);
-int atomic64_inc_not_zero_386(atomic64_t *v);
-EXPORT_SYMBOL(atomic64_inc_not_zero_386);
-int atomic64_add_unless_386(atomic64_t *v, long long a, long long u);
-EXPORT_SYMBOL(atomic64_add_unless_386);
-#endif
diff --git a/arch/x86/lib/atomic64_386_32.S b/arch/x86/lib/atomic64_386_32.S
index e8e7e0d..00933d5 100644
--- a/arch/x86/lib/atomic64_386_32.S
+++ b/arch/x86/lib/atomic64_386_32.S
@@ -137,13 +137,13 @@
 RET_ENDP
 #undef v
 
-#define v %ecx
+#define v %esi
 BEGIN(add_unless)
-	addl %eax, %esi
+	addl %eax, %ecx
 	adcl %edx, %edi
 	addl  (v), %eax
 	adcl 4(v), %edx
-	cmpl %eax, %esi
+	cmpl %eax, %ecx
 	je 3f
 1:
 	movl %eax,  (v)
diff --git a/arch/x86/lib/atomic64_cx8_32.S b/arch/x86/lib/atomic64_cx8_32.S
index 391a083..f5cc9eb 100644
--- a/arch/x86/lib/atomic64_cx8_32.S
+++ b/arch/x86/lib/atomic64_cx8_32.S
@@ -55,8 +55,6 @@
 ENTRY(atomic64_xchg_cx8)
 	CFI_STARTPROC
 
-	movl %ebx, %eax
-	movl %ecx, %edx
 1:
 	LOCK_PREFIX
 	cmpxchg8b (%esi)
@@ -78,7 +76,7 @@
 	movl %edx, %edi
 	movl %ecx, %ebp
 
-	read64 %ebp
+	read64 %ecx
 1:
 	movl %eax, %ebx
 	movl %edx, %ecx
@@ -159,23 +157,22 @@
 	SAVE ebx
 /* these just push these two parameters on the stack */
 	SAVE edi
-	SAVE esi
+	SAVE ecx
 
-	movl %ecx, %ebp
-	movl %eax, %esi
+	movl %eax, %ebp
 	movl %edx, %edi
 
-	read64 %ebp
+	read64 %esi
 1:
 	cmpl %eax, 0(%esp)
 	je 4f
 2:
 	movl %eax, %ebx
 	movl %edx, %ecx
-	addl %esi, %ebx
+	addl %ebp, %ebx
 	adcl %edi, %ecx
 	LOCK_PREFIX
-	cmpxchg8b (%ebp)
+	cmpxchg8b (%esi)
 	jne 1b
 
 	movl $1, %eax
@@ -199,13 +196,13 @@
 
 	read64 %esi
 1:
-	testl %eax, %eax
-	je 4f
-2:
+	movl %eax, %ecx
+	orl %edx, %ecx
+	jz 3f
 	movl %eax, %ebx
-	movl %edx, %ecx
+	xorl %ecx, %ecx
 	addl $1, %ebx
-	adcl $0, %ecx
+	adcl %edx, %ecx
 	LOCK_PREFIX
 	cmpxchg8b (%esi)
 	jne 1b
@@ -214,9 +211,5 @@
 3:
 	RESTORE ebx
 	ret
-4:
-	testl %edx, %edx
-	jne 2b
-	jmp 3b
 	CFI_ENDPROC
 ENDPROC(atomic64_inc_not_zero_cx8)
diff --git a/arch/x86/lib/copy_page_64.S b/arch/x86/lib/copy_page_64.S
index 01c805b..6b34d04 100644
--- a/arch/x86/lib/copy_page_64.S
+++ b/arch/x86/lib/copy_page_64.S
@@ -20,14 +20,12 @@
 
 ENTRY(copy_page)
 	CFI_STARTPROC
-	subq	$3*8,%rsp
-	CFI_ADJUST_CFA_OFFSET 3*8
+	subq	$2*8,%rsp
+	CFI_ADJUST_CFA_OFFSET 2*8
 	movq	%rbx,(%rsp)
 	CFI_REL_OFFSET rbx, 0
 	movq	%r12,1*8(%rsp)
 	CFI_REL_OFFSET r12, 1*8
-	movq	%r13,2*8(%rsp)
-	CFI_REL_OFFSET r13, 2*8
 
 	movl	$(4096/64)-5,%ecx
 	.p2align 4
@@ -91,10 +89,8 @@
 	CFI_RESTORE rbx
 	movq	1*8(%rsp),%r12
 	CFI_RESTORE r12
-	movq	2*8(%rsp),%r13
-	CFI_RESTORE r13
-	addq	$3*8,%rsp
-	CFI_ADJUST_CFA_OFFSET -3*8
+	addq	$2*8,%rsp
+	CFI_ADJUST_CFA_OFFSET -2*8
 	ret
 .Lcopy_page_end:
 	CFI_ENDPROC
diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S
index efbf2a0..1c273be 100644
--- a/arch/x86/lib/memcpy_64.S
+++ b/arch/x86/lib/memcpy_64.S
@@ -27,9 +27,8 @@
 	.section .altinstr_replacement, "ax", @progbits
 .Lmemcpy_c:
 	movq %rdi, %rax
-
-	movl %edx, %ecx
-	shrl $3, %ecx
+	movq %rdx, %rcx
+	shrq $3, %rcx
 	andl $7, %edx
 	rep movsq
 	movl %edx, %ecx
@@ -48,8 +47,7 @@
 	.section .altinstr_replacement, "ax", @progbits
 .Lmemcpy_c_e:
 	movq %rdi, %rax
-
-	movl %edx, %ecx
+	movq %rdx, %rcx
 	rep movsb
 	ret
 .Lmemcpy_e_e:
@@ -60,10 +58,7 @@
 	CFI_STARTPROC
 	movq %rdi, %rax
 
-	/*
-	 * Use 32bit CMP here to avoid long NOP padding.
-	 */
-	cmp  $0x20, %edx
+	cmpq $0x20, %rdx
 	jb .Lhandle_tail
 
 	/*
@@ -72,7 +67,7 @@
 	 */
 	cmp  %dil, %sil
 	jl .Lcopy_backward
-	subl $0x20, %edx
+	subq $0x20, %rdx
 .Lcopy_forward_loop:
 	subq $0x20,	%rdx
 
@@ -91,7 +86,7 @@
 	movq %r11,	3*8(%rdi)
 	leaq 4*8(%rdi),	%rdi
 	jae  .Lcopy_forward_loop
-	addq $0x20,	%rdx
+	addl $0x20,	%edx
 	jmp  .Lhandle_tail
 
 .Lcopy_backward:
@@ -123,11 +118,11 @@
 	/*
 	 * Calculate copy position to head.
 	 */
-	addq $0x20,	%rdx
+	addl $0x20,	%edx
 	subq %rdx,	%rsi
 	subq %rdx,	%rdi
 .Lhandle_tail:
-	cmpq $16,	%rdx
+	cmpl $16,	%edx
 	jb   .Lless_16bytes
 
 	/*
@@ -144,7 +139,7 @@
 	retq
 	.p2align 4
 .Lless_16bytes:
-	cmpq $8,	%rdx
+	cmpl $8,	%edx
 	jb   .Lless_8bytes
 	/*
 	 * Move data from 8 bytes to 15 bytes.
@@ -156,7 +151,7 @@
 	retq
 	.p2align 4
 .Lless_8bytes:
-	cmpq $4,	%rdx
+	cmpl $4,	%edx
 	jb   .Lless_3bytes
 
 	/*
@@ -169,18 +164,19 @@
 	retq
 	.p2align 4
 .Lless_3bytes:
-	cmpl $0, %edx
-	je .Lend
+	subl $1, %edx
+	jb .Lend
 	/*
 	 * Move data from 1 bytes to 3 bytes.
 	 */
-.Lloop_1:
-	movb (%rsi), %r8b
-	movb %r8b, (%rdi)
-	incq %rdi
-	incq %rsi
-	decl %edx
-	jnz .Lloop_1
+	movzbl (%rsi), %ecx
+	jz .Lstore_1byte
+	movzbq 1(%rsi), %r8
+	movzbq (%rsi, %rdx), %r9
+	movb %r8b, 1(%rdi)
+	movb %r9b, (%rdi, %rdx)
+.Lstore_1byte:
+	movb %cl, (%rdi)
 
 .Lend:
 	retq
diff --git a/arch/x86/lib/memset_64.S b/arch/x86/lib/memset_64.S
index 79bd454..2dcb380 100644
--- a/arch/x86/lib/memset_64.S
+++ b/arch/x86/lib/memset_64.S
@@ -19,16 +19,15 @@
 	.section .altinstr_replacement, "ax", @progbits
 .Lmemset_c:
 	movq %rdi,%r9
-	movl %edx,%r8d
-	andl $7,%r8d
-	movl %edx,%ecx
-	shrl $3,%ecx
+	movq %rdx,%rcx
+	andl $7,%edx
+	shrq $3,%rcx
 	/* expand byte value  */
 	movzbl %sil,%esi
 	movabs $0x0101010101010101,%rax
-	mulq %rsi		/* with rax, clobbers rdx */
+	imulq %rsi,%rax
 	rep stosq
-	movl %r8d,%ecx
+	movl %edx,%ecx
 	rep stosb
 	movq %r9,%rax
 	ret
@@ -50,7 +49,7 @@
 .Lmemset_c_e:
 	movq %rdi,%r9
 	movb %sil,%al
-	movl %edx,%ecx
+	movq %rdx,%rcx
 	rep stosb
 	movq %r9,%rax
 	ret
@@ -61,12 +60,11 @@
 ENTRY(__memset)
 	CFI_STARTPROC
 	movq %rdi,%r10
-	movq %rdx,%r11
 
 	/* expand byte value  */
 	movzbl %sil,%ecx
 	movabs $0x0101010101010101,%rax
-	mul    %rcx		/* with rax, clobbers rdx */
+	imulq  %rcx,%rax
 
 	/* align dst */
 	movl  %edi,%r9d
@@ -75,13 +73,13 @@
 	CFI_REMEMBER_STATE
 .Lafter_bad_alignment:
 
-	movl %r11d,%ecx
-	shrl $6,%ecx
+	movq  %rdx,%rcx
+	shrq  $6,%rcx
 	jz	 .Lhandle_tail
 
 	.p2align 4
 .Lloop_64:
-	decl   %ecx
+	decq  %rcx
 	movq  %rax,(%rdi)
 	movq  %rax,8(%rdi)
 	movq  %rax,16(%rdi)
@@ -97,7 +95,7 @@
 	   to predict jump tables. */
 	.p2align 4
 .Lhandle_tail:
-	movl	%r11d,%ecx
+	movl	%edx,%ecx
 	andl    $63&(~7),%ecx
 	jz 		.Lhandle_7
 	shrl	$3,%ecx
@@ -109,12 +107,11 @@
 	jnz    .Lloop_8
 
 .Lhandle_7:
-	movl	%r11d,%ecx
-	andl	$7,%ecx
+	andl	$7,%edx
 	jz      .Lende
 	.p2align 4
 .Lloop_1:
-	decl    %ecx
+	decl    %edx
 	movb 	%al,(%rdi)
 	leaq	1(%rdi),%rdi
 	jnz     .Lloop_1
@@ -125,13 +122,13 @@
 
 	CFI_RESTORE_STATE
 .Lbad_alignment:
-	cmpq $7,%r11
+	cmpq $7,%rdx
 	jbe	.Lhandle_7
 	movq %rax,(%rdi)	/* unaligned store */
 	movq $8,%r8
 	subq %r9,%r8
 	addq %r8,%rdi
-	subq %r8,%r11
+	subq %r8,%rdx
 	jmp .Lafter_bad_alignment
 .Lfinal:
 	CFI_ENDPROC
diff --git a/arch/x86/math-emu/fpu_entry.c b/arch/x86/math-emu/fpu_entry.c
index 7718541..9b86812 100644
--- a/arch/x86/math-emu/fpu_entry.c
+++ b/arch/x86/math-emu/fpu_entry.c
@@ -28,6 +28,7 @@
 #include <linux/regset.h>
 
 #include <asm/uaccess.h>
+#include <asm/traps.h>
 #include <asm/desc.h>
 #include <asm/user.h>
 #include <asm/i387.h>
@@ -269,7 +270,7 @@
 			FPU_EIP = FPU_ORIG_EIP;	/* Point to current FPU instruction. */
 
 			RE_ENTRANT_CHECK_OFF;
-			current->thread.trap_no = 16;
+			current->thread.trap_nr = X86_TRAP_MF;
 			current->thread.error_code = 0;
 			send_sig(SIGFPE, current, 1);
 			return;
@@ -662,7 +663,7 @@
 void math_abort(struct math_emu_info *info, unsigned int signal)
 {
 	FPU_EIP = FPU_ORIG_EIP;
-	current->thread.trap_no = 16;
+	current->thread.trap_nr = X86_TRAP_MF;
 	current->thread.error_code = 0;
 	send_sig(signal, current, 1);
 	RE_ENTRANT_CHECK_OFF;
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index f0b4caf..3ecfd1aa 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -615,7 +615,7 @@
 	dump_pagetable(address);
 
 	tsk->thread.cr2		= address;
-	tsk->thread.trap_no	= 14;
+	tsk->thread.trap_nr	= X86_TRAP_PF;
 	tsk->thread.error_code	= error_code;
 
 	if (__die("Bad pagetable", regs, error_code))
@@ -636,7 +636,7 @@
 	/* Are we prepared to handle this kernel fault? */
 	if (fixup_exception(regs)) {
 		if (current_thread_info()->sig_on_uaccess_error && signal) {
-			tsk->thread.trap_no = 14;
+			tsk->thread.trap_nr = X86_TRAP_PF;
 			tsk->thread.error_code = error_code | PF_USER;
 			tsk->thread.cr2 = address;
 
@@ -676,7 +676,7 @@
 		printk(KERN_EMERG "Thread overran stack, or stack corrupted\n");
 
 	tsk->thread.cr2		= address;
-	tsk->thread.trap_no	= 14;
+	tsk->thread.trap_nr	= X86_TRAP_PF;
 	tsk->thread.error_code	= error_code;
 
 	sig = SIGKILL;
@@ -754,7 +754,7 @@
 		/* Kernel addresses are always protection faults: */
 		tsk->thread.cr2		= address;
 		tsk->thread.error_code	= error_code | (address >= TASK_SIZE);
-		tsk->thread.trap_no	= 14;
+		tsk->thread.trap_nr	= X86_TRAP_PF;
 
 		force_sig_info_fault(SIGSEGV, si_code, address, tsk, 0);
 
@@ -838,7 +838,7 @@
 
 	tsk->thread.cr2		= address;
 	tsk->thread.error_code	= error_code;
-	tsk->thread.trap_no	= 14;
+	tsk->thread.trap_nr	= X86_TRAP_PF;
 
 #ifdef CONFIG_MEMORY_FAILURE
 	if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) {
diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c
index 8ecbb4b..f6679a7 100644
--- a/arch/x86/mm/hugetlbpage.c
+++ b/arch/x86/mm/hugetlbpage.c
@@ -308,10 +308,11 @@
 {
 	struct hstate *h = hstate_file(file);
 	struct mm_struct *mm = current->mm;
-	struct vm_area_struct *vma, *prev_vma;
-	unsigned long base = mm->mmap_base, addr = addr0;
+	struct vm_area_struct *vma;
+	unsigned long base = mm->mmap_base;
+	unsigned long addr = addr0;
 	unsigned long largest_hole = mm->cached_hole_size;
-	int first_time = 1;
+	unsigned long start_addr;
 
 	/* don't allow allocations above current base */
 	if (mm->free_area_cache > base)
@@ -322,6 +323,8 @@
 		mm->free_area_cache  = base;
 	}
 try_again:
+	start_addr = mm->free_area_cache;
+
 	/* make sure it can fit in the remaining address space */
 	if (mm->free_area_cache < len)
 		goto fail;
@@ -337,22 +340,14 @@
 		if (!vma)
 			return addr;
 
-		/*
-		 * new region fits between prev_vma->vm_end and
-		 * vma->vm_start, use it:
-		 */
-		prev_vma = vma->vm_prev;
-		if (addr + len <= vma->vm_start &&
-		            (!prev_vma || (addr >= prev_vma->vm_end))) {
+		if (addr + len <= vma->vm_start) {
 			/* remember the address as a hint for next time */
 		        mm->cached_hole_size = largest_hole;
 		        return (mm->free_area_cache = addr);
-		} else {
+		} else if (mm->free_area_cache == vma->vm_end) {
 			/* pull free_area_cache down to the first hole */
-		        if (mm->free_area_cache == vma->vm_end) {
-				mm->free_area_cache = vma->vm_start;
-				mm->cached_hole_size = largest_hole;
-			}
+			mm->free_area_cache = vma->vm_start;
+			mm->cached_hole_size = largest_hole;
 		}
 
 		/* remember the largest hole we saw so far */
@@ -368,10 +363,9 @@
 	 * if hint left us with no space for the requested
 	 * mapping then try again:
 	 */
-	if (first_time) {
+	if (start_addr != base) {
 		mm->free_area_cache = base;
 		largest_hole = 0;
-		first_time = 0;
 		goto try_again;
 	}
 	/*
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 6cabf65..4f0cec7 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -12,7 +12,6 @@
 #include <asm/page_types.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
-#include <asm/system.h>
 #include <asm/tlbflush.h>
 #include <asm/tlb.h>
 #include <asm/proto.h>
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 8663f6c..575d86f 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -35,7 +35,6 @@
 #include <asm/asm.h>
 #include <asm/bios_ebda.h>
 #include <asm/processor.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/dma.h>
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 436a030..fc18be0 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -35,7 +35,6 @@
 
 #include <asm/processor.h>
 #include <asm/bios_ebda.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
diff --git a/arch/x86/mm/kmemcheck/selftest.c b/arch/x86/mm/kmemcheck/selftest.c
index 036efbe..aef7140 100644
--- a/arch/x86/mm/kmemcheck/selftest.c
+++ b/arch/x86/mm/kmemcheck/selftest.c
@@ -1,3 +1,4 @@
+#include <linux/bug.h>
 #include <linux/kernel.h>
 
 #include "opcode.h"
diff --git a/arch/x86/mm/numa_emulation.c b/arch/x86/mm/numa_emulation.c
index 46db568..53489ff 100644
--- a/arch/x86/mm/numa_emulation.c
+++ b/arch/x86/mm/numa_emulation.c
@@ -28,7 +28,7 @@
 	return -ENOENT;
 }
 
-static u64 mem_hole_size(u64 start, u64 end)
+static u64 __init mem_hole_size(u64 start, u64 end)
 {
 	unsigned long start_pfn = PFN_UP(start);
 	unsigned long end_pfn = PFN_DOWN(end);
@@ -60,7 +60,7 @@
 	eb->nid = nid;
 
 	if (emu_nid_to_phys[nid] == NUMA_NO_NODE)
-		emu_nid_to_phys[nid] = pb->nid;
+		emu_nid_to_phys[nid] = nid;
 
 	pb->start += size;
 	if (pb->start >= pb->end) {
diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c
index cac7184..a69bcb8 100644
--- a/arch/x86/mm/pgtable_32.c
+++ b/arch/x86/mm/pgtable_32.c
@@ -10,7 +10,6 @@
 #include <linux/spinlock.h>
 #include <linux/module.h>
 
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/fixmap.h>
diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c
index 1c1c4f4..efb5b4b 100644
--- a/arch/x86/mm/srat.c
+++ b/arch/x86/mm/srat.c
@@ -70,7 +70,7 @@
 		return;
 	pxm = pa->proximity_domain;
 	apic_id = pa->apic_id;
-	if (!cpu_has_x2apic && (apic_id >= 0xff)) {
+	if (!apic->apic_id_valid(apic_id)) {
 		printk(KERN_INFO "SRAT: PXM %u -> X2APIC 0x%04x ignored\n",
 			 pxm, apic_id);
 		return;
diff --git a/arch/x86/net/bpf_jit.S b/arch/x86/net/bpf_jit.S
index 6687022..877b9a1 100644
--- a/arch/x86/net/bpf_jit.S
+++ b/arch/x86/net/bpf_jit.S
@@ -18,17 +18,17 @@
  * r9d : hlen = skb->len - skb->data_len
  */
 #define SKBDATA	%r8
-
-sk_load_word_ind:
-	.globl	sk_load_word_ind
-
-	add	%ebx,%esi	/* offset += X */
-#	test    %esi,%esi	/* if (offset < 0) goto bpf_error; */
-	js	bpf_error
+#define SKF_MAX_NEG_OFF    $(-0x200000) /* SKF_LL_OFF from filter.h */
 
 sk_load_word:
 	.globl	sk_load_word
 
+	test	%esi,%esi
+	js	bpf_slow_path_word_neg
+
+sk_load_word_positive_offset:
+	.globl	sk_load_word_positive_offset
+
 	mov	%r9d,%eax		# hlen
 	sub	%esi,%eax		# hlen - offset
 	cmp	$3,%eax
@@ -37,16 +37,15 @@
 	bswap   %eax  			/* ntohl() */
 	ret
 
-
-sk_load_half_ind:
-	.globl sk_load_half_ind
-
-	add	%ebx,%esi	/* offset += X */
-	js	bpf_error
-
 sk_load_half:
 	.globl	sk_load_half
 
+	test	%esi,%esi
+	js	bpf_slow_path_half_neg
+
+sk_load_half_positive_offset:
+	.globl	sk_load_half_positive_offset
+
 	mov	%r9d,%eax
 	sub	%esi,%eax		#	hlen - offset
 	cmp	$1,%eax
@@ -55,14 +54,15 @@
 	rol	$8,%ax			# ntohs()
 	ret
 
-sk_load_byte_ind:
-	.globl sk_load_byte_ind
-	add	%ebx,%esi	/* offset += X */
-	js	bpf_error
-
 sk_load_byte:
 	.globl	sk_load_byte
 
+	test	%esi,%esi
+	js	bpf_slow_path_byte_neg
+
+sk_load_byte_positive_offset:
+	.globl	sk_load_byte_positive_offset
+
 	cmp	%esi,%r9d   /* if (offset >= hlen) goto bpf_slow_path_byte */
 	jle	bpf_slow_path_byte
 	movzbl	(SKBDATA,%rsi),%eax
@@ -73,25 +73,21 @@
  *
  * Implements BPF_S_LDX_B_MSH : ldxb  4*([offset]&0xf)
  * Must preserve A accumulator (%eax)
- * Inputs : %esi is the offset value, already known positive
+ * Inputs : %esi is the offset value
  */
-ENTRY(sk_load_byte_msh)
-	CFI_STARTPROC
+sk_load_byte_msh:
+	.globl	sk_load_byte_msh
+	test	%esi,%esi
+	js	bpf_slow_path_byte_msh_neg
+
+sk_load_byte_msh_positive_offset:
+	.globl	sk_load_byte_msh_positive_offset
 	cmp	%esi,%r9d      /* if (offset >= hlen) goto bpf_slow_path_byte_msh */
 	jle	bpf_slow_path_byte_msh
 	movzbl	(SKBDATA,%rsi),%ebx
 	and	$15,%bl
 	shl	$2,%bl
 	ret
-	CFI_ENDPROC
-ENDPROC(sk_load_byte_msh)
-
-bpf_error:
-# force a return 0 from jit handler
-	xor		%eax,%eax
-	mov		-8(%rbp),%rbx
-	leaveq
-	ret
 
 /* rsi contains offset and can be scratched */
 #define bpf_slow_path_common(LEN)		\
@@ -138,3 +134,67 @@
 	shl	$2,%al
 	xchg	%eax,%ebx
 	ret
+
+#define sk_negative_common(SIZE)				\
+	push	%rdi;	/* save skb */				\
+	push	%r9;						\
+	push	SKBDATA;					\
+/* rsi already has offset */					\
+	mov	$SIZE,%ecx;	/* size */			\
+	call	bpf_internal_load_pointer_neg_helper;		\
+	test	%rax,%rax;					\
+	pop	SKBDATA;					\
+	pop	%r9;						\
+	pop	%rdi;						\
+	jz	bpf_error
+
+
+bpf_slow_path_word_neg:
+	cmp	SKF_MAX_NEG_OFF, %esi	/* test range */
+	jl	bpf_error	/* offset lower -> error  */
+sk_load_word_negative_offset:
+	.globl	sk_load_word_negative_offset
+	sk_negative_common(4)
+	mov	(%rax), %eax
+	bswap	%eax
+	ret
+
+bpf_slow_path_half_neg:
+	cmp	SKF_MAX_NEG_OFF, %esi
+	jl	bpf_error
+sk_load_half_negative_offset:
+	.globl	sk_load_half_negative_offset
+	sk_negative_common(2)
+	mov	(%rax),%ax
+	rol	$8,%ax
+	movzwl	%ax,%eax
+	ret
+
+bpf_slow_path_byte_neg:
+	cmp	SKF_MAX_NEG_OFF, %esi
+	jl	bpf_error
+sk_load_byte_negative_offset:
+	.globl	sk_load_byte_negative_offset
+	sk_negative_common(1)
+	movzbl	(%rax), %eax
+	ret
+
+bpf_slow_path_byte_msh_neg:
+	cmp	SKF_MAX_NEG_OFF, %esi
+	jl	bpf_error
+sk_load_byte_msh_negative_offset:
+	.globl	sk_load_byte_msh_negative_offset
+	xchg	%eax,%ebx /* dont lose A , X is about to be scratched */
+	sk_negative_common(1)
+	movzbl	(%rax),%eax
+	and	$15,%al
+	shl	$2,%al
+	xchg	%eax,%ebx
+	ret
+
+bpf_error:
+# force a return 0 from jit handler
+	xor		%eax,%eax
+	mov		-8(%rbp),%rbx
+	leaveq
+	ret
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 5671752..0597f95 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -30,7 +30,10 @@
  * assembly code in arch/x86/net/bpf_jit.S
  */
 extern u8 sk_load_word[], sk_load_half[], sk_load_byte[], sk_load_byte_msh[];
-extern u8 sk_load_word_ind[], sk_load_half_ind[], sk_load_byte_ind[];
+extern u8 sk_load_word_positive_offset[], sk_load_half_positive_offset[];
+extern u8 sk_load_byte_positive_offset[], sk_load_byte_msh_positive_offset[];
+extern u8 sk_load_word_negative_offset[], sk_load_half_negative_offset[];
+extern u8 sk_load_byte_negative_offset[], sk_load_byte_msh_negative_offset[];
 
 static inline u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
 {
@@ -117,6 +120,8 @@
 	set_fs(old_fs);
 }
 
+#define CHOOSE_LOAD_FUNC(K, func) \
+	((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative_offset : func) : func##_positive_offset)
 
 void bpf_jit_compile(struct sk_filter *fp)
 {
@@ -289,7 +294,7 @@
 					EMIT2(0x24, K & 0xFF); /* and imm8,%al */
 				} else if (K >= 0xFFFF0000) {
 					EMIT2(0x66, 0x25);	/* and imm16,%ax */
-					EMIT2(K, 2);
+					EMIT(K, 2);
 				} else {
 					EMIT1_off32(0x25, K);	/* and imm32,%eax */
 				}
@@ -473,44 +478,46 @@
 #endif
 				break;
 			case BPF_S_LD_W_ABS:
-				func = sk_load_word;
+				func = CHOOSE_LOAD_FUNC(K, sk_load_word);
 common_load:			seen |= SEEN_DATAREF;
-				if ((int)K < 0) {
-					/* Abort the JIT because __load_pointer() is needed. */
-					goto out;
-				}
 				t_offset = func - (image + addrs[i]);
 				EMIT1_off32(0xbe, K); /* mov imm32,%esi */
 				EMIT1_off32(0xe8, t_offset); /* call */
 				break;
 			case BPF_S_LD_H_ABS:
-				func = sk_load_half;
+				func = CHOOSE_LOAD_FUNC(K, sk_load_half);
 				goto common_load;
 			case BPF_S_LD_B_ABS:
-				func = sk_load_byte;
+				func = CHOOSE_LOAD_FUNC(K, sk_load_byte);
 				goto common_load;
 			case BPF_S_LDX_B_MSH:
-				if ((int)K < 0) {
-					/* Abort the JIT because __load_pointer() is needed. */
-					goto out;
-				}
+				func = CHOOSE_LOAD_FUNC(K, sk_load_byte_msh);
 				seen |= SEEN_DATAREF | SEEN_XREG;
-				t_offset = sk_load_byte_msh - (image + addrs[i]);
+				t_offset = func - (image + addrs[i]);
 				EMIT1_off32(0xbe, K);	/* mov imm32,%esi */
 				EMIT1_off32(0xe8, t_offset); /* call sk_load_byte_msh */
 				break;
 			case BPF_S_LD_W_IND:
-				func = sk_load_word_ind;
+				func = sk_load_word;
 common_load_ind:		seen |= SEEN_DATAREF | SEEN_XREG;
 				t_offset = func - (image + addrs[i]);
-				EMIT1_off32(0xbe, K);	/* mov imm32,%esi   */
+				if (K) {
+					if (is_imm8(K)) {
+						EMIT3(0x8d, 0x73, K); /* lea imm8(%rbx), %esi */
+					} else {
+						EMIT2(0x8d, 0xb3); /* lea imm32(%rbx),%esi */
+						EMIT(K, 4);
+					}
+				} else {
+					EMIT2(0x89,0xde); /* mov %ebx,%esi */
+				}
 				EMIT1_off32(0xe8, t_offset);	/* call sk_load_xxx_ind */
 				break;
 			case BPF_S_LD_H_IND:
-				func = sk_load_half_ind;
+				func = sk_load_half;
 				goto common_load_ind;
 			case BPF_S_LD_B_IND:
-				func = sk_load_byte_ind;
+				func = sk_load_byte;
 				goto common_load_ind;
 			case BPF_S_JMP_JA:
 				t_offset = addrs[i + K] - addrs[i];
diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c
index bff89df..d6aa6e8 100644
--- a/arch/x86/oprofile/backtrace.c
+++ b/arch/x86/oprofile/backtrace.c
@@ -67,7 +67,7 @@
 {
 	struct stack_frame_ia32 *head;
 
-	/* User process is 32-bit */
+	/* User process is IA32 */
 	if (!current || !test_thread_flag(TIF_IA32))
 		return 0;
 
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 49a5cb5..ed2835e 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -416,7 +416,12 @@
 		kfree(sd);
 	} else {
 		get_current_resources(device, busnum, domain, &resources);
-		if (list_empty(&resources))
+
+		/*
+		 * _CRS with no apertures is normal, so only fall back to
+		 * defaults or native bridge info if we're ignoring _CRS.
+		 */
+		if (!pci_use_crs)
 			x86_pci_root_bus_resources(busnum, &resources);
 		bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd,
 					  &resources);
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
index 6dd8955..d0e6e40 100644
--- a/arch/x86/pci/fixup.c
+++ b/arch/x86/pci/fixup.c
@@ -164,11 +164,11 @@
  */
 static void __devinit pci_fixup_transparent_bridge(struct pci_dev *dev)
 {
-	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
-	    (dev->device & 0xff00) == 0x2400)
+	if ((dev->device & 0xff00) == 0x2400)
 		dev->transparent = 1;
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixup_transparent_bridge);
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
+			 PCI_CLASS_BRIDGE_PCI, 8, pci_fixup_transparent_bridge);
 
 /*
  * Fixup for C1 Halt Disconnect problem on nForce2 systems.
@@ -322,9 +322,6 @@
 	struct pci_bus *bus;
 	u16 config;
 
-	if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
-		return;
-
 	/* Is VGA routed to us? */
 	bus = pdev->bus;
 	while (bus) {
@@ -353,7 +350,8 @@
 		dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
 	}
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+				PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
 
 
 static const struct dmi_system_id __devinitconst msi_k8t_dmi_table[] = {
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 91821a1..831971e 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -39,6 +39,87 @@
 #include <asm/io_apic.h>
 
 
+/*
+ * This list of dynamic mappings is for temporarily maintaining
+ * original BIOS BAR addresses for possible reinstatement.
+ */
+struct pcibios_fwaddrmap {
+	struct list_head list;
+	struct pci_dev *dev;
+	resource_size_t fw_addr[DEVICE_COUNT_RESOURCE];
+};
+
+static LIST_HEAD(pcibios_fwaddrmappings);
+static DEFINE_SPINLOCK(pcibios_fwaddrmap_lock);
+
+/* Must be called with 'pcibios_fwaddrmap_lock' lock held. */
+static struct pcibios_fwaddrmap *pcibios_fwaddrmap_lookup(struct pci_dev *dev)
+{
+	struct pcibios_fwaddrmap *map;
+
+	WARN_ON(!spin_is_locked(&pcibios_fwaddrmap_lock));
+
+	list_for_each_entry(map, &pcibios_fwaddrmappings, list)
+		if (map->dev == dev)
+			return map;
+
+	return NULL;
+}
+
+static void
+pcibios_save_fw_addr(struct pci_dev *dev, int idx, resource_size_t fw_addr)
+{
+	unsigned long flags;
+	struct pcibios_fwaddrmap *map;
+
+	spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
+	map = pcibios_fwaddrmap_lookup(dev);
+	if (!map) {
+		spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
+		map = kzalloc(sizeof(*map), GFP_KERNEL);
+		if (!map)
+			return;
+
+		map->dev = pci_dev_get(dev);
+		map->fw_addr[idx] = fw_addr;
+		INIT_LIST_HEAD(&map->list);
+
+		spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
+		list_add_tail(&map->list, &pcibios_fwaddrmappings);
+	} else
+		map->fw_addr[idx] = fw_addr;
+	spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
+}
+
+resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
+{
+	unsigned long flags;
+	struct pcibios_fwaddrmap *map;
+	resource_size_t fw_addr = 0;
+
+	spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
+	map = pcibios_fwaddrmap_lookup(dev);
+	if (map)
+		fw_addr = map->fw_addr[idx];
+	spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
+
+	return fw_addr;
+}
+
+static void pcibios_fw_addr_list_del(void)
+{
+	unsigned long flags;
+	struct pcibios_fwaddrmap *entry, *next;
+
+	spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
+	list_for_each_entry_safe(entry, next, &pcibios_fwaddrmappings, list) {
+		list_del(&entry->list);
+		pci_dev_put(entry->dev);
+		kfree(entry);
+	}
+	spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
+}
+
 static int
 skip_isa_ioresource_align(struct pci_dev *dev) {
 
@@ -182,7 +263,8 @@
 					idx, r, disabled, pass);
 				if (pci_claim_resource(dev, idx) < 0) {
 					/* We'll assign a new address later */
-					dev->fw_addr[idx] = r->start;
+					pcibios_save_fw_addr(dev,
+							idx, r->start);
 					r->end -= r->start;
 					r->start = 0;
 				}
@@ -228,6 +310,7 @@
 	}
 
 	pci_assign_unassigned_resources();
+	pcibios_fw_addr_list_del();
 
 	return 0;
 }
diff --git a/arch/x86/pci/mrst.c b/arch/x86/pci/mrst.c
index cb29191..140942f 100644
--- a/arch/x86/pci/mrst.c
+++ b/arch/x86/pci/mrst.c
@@ -43,6 +43,8 @@
 #define PCI_FIXED_BAR_4_SIZE	0x14
 #define PCI_FIXED_BAR_5_SIZE	0x1c
 
+static int pci_soc_mode = 0;
+
 /**
  * fixed_bar_cap - return the offset of the fixed BAR cap if found
  * @bus: PCI bus
@@ -148,7 +150,9 @@
 	 */
 	if (reg >= 0x100 || reg == PCI_STATUS || reg == PCI_HEADER_TYPE)
 		return 0;
-	if (bus == 0 && (devfn == PCI_DEVFN(2, 0) || devfn == PCI_DEVFN(0, 0)))
+	if (bus == 0 && (devfn == PCI_DEVFN(2, 0)
+				|| devfn == PCI_DEVFN(0, 0)
+				|| devfn == PCI_DEVFN(3, 0)))
 		return 1;
 	return 0; /* langwell on others */
 }
@@ -231,14 +235,43 @@
  */
 int __init pci_mrst_init(void)
 {
-	printk(KERN_INFO "Moorestown platform detected, using MRST PCI ops\n");
+	printk(KERN_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;
+	pci_soc_mode = 1;
 	/* Continue with standard init */
 	return 1;
 }
 
+/* Langwell devices are not true pci devices, they are not subject to 10 ms
+ * d3 to d0 delay required by pci spec.
+ */
+static void __devinit 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.
+	 */
+	if (type1_access_ok(dev->bus->number, dev->devfn, PCI_DEVICE_ID))
+		return;
+	dev->d3_delay = 0;
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3delay_fixup);
+
+static void __devinit mrst_power_off_unused_dev(struct pci_dev *dev)
+{
+	pci_set_power_state(dev, PCI_D3cold);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0801, mrst_power_off_unused_dev);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0809, mrst_power_off_unused_dev);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x080C, mrst_power_off_unused_dev);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0812, mrst_power_off_unused_dev);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0815, mrst_power_off_unused_dev);
+
 /*
  * Langwell devices reside at fixed offsets, don't try to move them.
  */
@@ -248,6 +281,9 @@
 	u32 size;
 	int i;
 
+	if (!pci_soc_mode)
+		return;
+
 	/* Must have extended configuration space */
 	if (dev->cfg_size < PCIE_CAP_OFFSET + 4)
 		return;
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index d99346e..7415aa9 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -324,6 +324,32 @@
 out:
 	return ret;
 }
+
+static void xen_initdom_restore_msi_irqs(struct pci_dev *dev, int irq)
+{
+	int ret = 0;
+
+	if (pci_seg_supported) {
+		struct physdev_pci_device restore_ext;
+
+		restore_ext.seg = pci_domain_nr(dev->bus);
+		restore_ext.bus = dev->bus->number;
+		restore_ext.devfn = dev->devfn;
+		ret = HYPERVISOR_physdev_op(PHYSDEVOP_restore_msi_ext,
+					&restore_ext);
+		if (ret == -ENOSYS)
+			pci_seg_supported = false;
+		WARN(ret && ret != -ENOSYS, "restore_msi_ext -> %d\n", ret);
+	}
+	if (!pci_seg_supported) {
+		struct physdev_restore_msi restore;
+
+		restore.bus = dev->bus->number;
+		restore.devfn = dev->devfn;
+		ret = HYPERVISOR_physdev_op(PHYSDEVOP_restore_msi, &restore);
+		WARN(ret && ret != -ENOSYS, "restore_msi -> %d\n", ret);
+	}
+}
 #endif
 
 static void xen_teardown_msi_irqs(struct pci_dev *dev)
@@ -446,6 +472,7 @@
 #ifdef CONFIG_PCI_MSI
 	x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs;
 	x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
+	x86_msi.restore_msi_irqs = xen_initdom_restore_msi_irqs;
 #endif
 	xen_setup_acpi_sci();
 	__acpi_register_gsi = acpi_register_gsi_xen;
diff --git a/arch/x86/platform/ce4100/falconfalls.dts b/arch/x86/platform/ce4100/falconfalls.dts
index e70be38..ce874f8 100644
--- a/arch/x86/platform/ce4100/falconfalls.dts
+++ b/arch/x86/platform/ce4100/falconfalls.dts
@@ -208,16 +208,19 @@
 					interrupts = <14 1>;
 				};
 
-				gpio@b,1 {
+				pcigpio: gpio@b,1 {
+					#gpio-cells = <2>;
+					#interrupt-cells = <2>;
 					compatible = "pci8086,2e67.2",
 						   "pci8086,2e67",
 						   "pciclassff0000",
 						   "pciclassff00";
 
-					#gpio-cells = <2>;
 					reg = <0x15900 0x0 0x0 0x0 0x0>;
 					interrupts = <15 1>;
+					interrupt-controller;
 					gpio-controller;
+					intel,muxctl = <0>;
 				};
 
 				i2c-controller@b,2 {
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 4cf9bd0..92660eda 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -26,6 +26,8 @@
  *	Skip non-WB memory and ignore empty memory ranges.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/efi.h>
@@ -47,7 +49,6 @@
 #include <asm/x86_init.h>
 
 #define EFI_DEBUG	1
-#define PFX 		"EFI: "
 
 int efi_enabled;
 EXPORT_SYMBOL(efi_enabled);
@@ -67,6 +68,9 @@
 
 struct efi_memory_map memmap;
 
+bool efi_64bit;
+static bool efi_native;
+
 static struct efi efi_phys __initdata;
 static efi_system_table_t efi_systab __initdata;
 
@@ -254,7 +258,7 @@
 
 	status = efi.get_time(&eft, &cap);
 	if (status != EFI_SUCCESS) {
-		printk(KERN_ERR "Oops: efitime: can't read time!\n");
+		pr_err("Oops: efitime: can't read time!\n");
 		return -1;
 	}
 
@@ -268,7 +272,7 @@
 
 	status = efi.set_time(&eft);
 	if (status != EFI_SUCCESS) {
-		printk(KERN_ERR "Oops: efitime: can't write time!\n");
+		pr_err("Oops: efitime: can't write time!\n");
 		return -1;
 	}
 	return 0;
@@ -282,7 +286,7 @@
 
 	status = efi.get_time(&eft, &cap);
 	if (status != EFI_SUCCESS)
-		printk(KERN_ERR "Oops: efitime: can't read time!\n");
+		pr_err("Oops: efitime: can't read time!\n");
 
 	return mktime(eft.year, eft.month, eft.day, eft.hour,
 		      eft.minute, eft.second);
@@ -338,11 +342,16 @@
 	sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
 }
 
-void __init efi_memblock_x86_reserve_range(void)
+int __init efi_memblock_x86_reserve_range(void)
 {
 	unsigned long pmap;
 
 #ifdef CONFIG_X86_32
+	/* Can't handle data above 4GB at this time */
+	if (boot_params.efi_info.efi_memmap_hi) {
+		pr_err("Memory map is above 4GB, disabling EFI.\n");
+		return -EINVAL;
+	}
 	pmap = boot_params.efi_info.efi_memmap;
 #else
 	pmap = (boot_params.efi_info.efi_memmap |
@@ -354,6 +363,8 @@
 	memmap.desc_version = boot_params.efi_info.efi_memdesc_version;
 	memmap.desc_size = boot_params.efi_info.efi_memdesc_size;
 	memblock_reserve(pmap, memmap.nr_map * memmap.desc_size);
+
+	return 0;
 }
 
 #if EFI_DEBUG
@@ -367,7 +378,7 @@
 	     p < memmap.map_end;
 	     p += memmap.desc_size, i++) {
 		md = p;
-		printk(KERN_INFO PFX "mem%02u: type=%u, attr=0x%llx, "
+		pr_info("mem%02u: type=%u, attr=0x%llx, "
 			"range=[0x%016llx-0x%016llx) (%lluMB)\n",
 			i, md->type, md->attribute, md->phys_addr,
 			md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
@@ -400,7 +411,7 @@
 			memblock_is_region_reserved(start, size)) {
 			/* Could not reserve, skip it */
 			md->num_pages = 0;
-			memblock_dbg(PFX "Could not reserve boot range "
+			memblock_dbg("Could not reserve boot range "
 					"[0x%010llx-0x%010llx]\n",
 						start, start+size-1);
 		} else
@@ -429,41 +440,248 @@
 	}
 }
 
+static int __init efi_systab_init(void *phys)
+{
+	if (efi_64bit) {
+		efi_system_table_64_t *systab64;
+		u64 tmp = 0;
+
+		systab64 = early_ioremap((unsigned long)phys,
+					 sizeof(*systab64));
+		if (systab64 == NULL) {
+			pr_err("Couldn't map the system table!\n");
+			return -ENOMEM;
+		}
+
+		efi_systab.hdr = systab64->hdr;
+		efi_systab.fw_vendor = systab64->fw_vendor;
+		tmp |= systab64->fw_vendor;
+		efi_systab.fw_revision = systab64->fw_revision;
+		efi_systab.con_in_handle = systab64->con_in_handle;
+		tmp |= systab64->con_in_handle;
+		efi_systab.con_in = systab64->con_in;
+		tmp |= systab64->con_in;
+		efi_systab.con_out_handle = systab64->con_out_handle;
+		tmp |= systab64->con_out_handle;
+		efi_systab.con_out = systab64->con_out;
+		tmp |= systab64->con_out;
+		efi_systab.stderr_handle = systab64->stderr_handle;
+		tmp |= systab64->stderr_handle;
+		efi_systab.stderr = systab64->stderr;
+		tmp |= systab64->stderr;
+		efi_systab.runtime = (void *)(unsigned long)systab64->runtime;
+		tmp |= systab64->runtime;
+		efi_systab.boottime = (void *)(unsigned long)systab64->boottime;
+		tmp |= systab64->boottime;
+		efi_systab.nr_tables = systab64->nr_tables;
+		efi_systab.tables = systab64->tables;
+		tmp |= systab64->tables;
+
+		early_iounmap(systab64, sizeof(*systab64));
+#ifdef CONFIG_X86_32
+		if (tmp >> 32) {
+			pr_err("EFI data located above 4GB, disabling EFI.\n");
+			return -EINVAL;
+		}
+#endif
+	} else {
+		efi_system_table_32_t *systab32;
+
+		systab32 = early_ioremap((unsigned long)phys,
+					 sizeof(*systab32));
+		if (systab32 == NULL) {
+			pr_err("Couldn't map the system table!\n");
+			return -ENOMEM;
+		}
+
+		efi_systab.hdr = systab32->hdr;
+		efi_systab.fw_vendor = systab32->fw_vendor;
+		efi_systab.fw_revision = systab32->fw_revision;
+		efi_systab.con_in_handle = systab32->con_in_handle;
+		efi_systab.con_in = systab32->con_in;
+		efi_systab.con_out_handle = systab32->con_out_handle;
+		efi_systab.con_out = systab32->con_out;
+		efi_systab.stderr_handle = systab32->stderr_handle;
+		efi_systab.stderr = systab32->stderr;
+		efi_systab.runtime = (void *)(unsigned long)systab32->runtime;
+		efi_systab.boottime = (void *)(unsigned long)systab32->boottime;
+		efi_systab.nr_tables = systab32->nr_tables;
+		efi_systab.tables = systab32->tables;
+
+		early_iounmap(systab32, sizeof(*systab32));
+	}
+
+	efi.systab = &efi_systab;
+
+	/*
+	 * Verify the EFI Table
+	 */
+	if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
+		pr_err("System table signature incorrect!\n");
+		return -EINVAL;
+	}
+	if ((efi.systab->hdr.revision >> 16) == 0)
+		pr_err("Warning: System table version "
+		       "%d.%02d, expected 1.00 or greater!\n",
+		       efi.systab->hdr.revision >> 16,
+		       efi.systab->hdr.revision & 0xffff);
+
+	return 0;
+}
+
+static int __init efi_config_init(u64 tables, int nr_tables)
+{
+	void *config_tables, *tablep;
+	int i, sz;
+
+	if (efi_64bit)
+		sz = sizeof(efi_config_table_64_t);
+	else
+		sz = sizeof(efi_config_table_32_t);
+
+	/*
+	 * Let's see what config tables the firmware passed to us.
+	 */
+	config_tables = early_ioremap(tables, nr_tables * sz);
+	if (config_tables == NULL) {
+		pr_err("Could not map Configuration table!\n");
+		return -ENOMEM;
+	}
+
+	tablep = config_tables;
+	pr_info("");
+	for (i = 0; i < efi.systab->nr_tables; i++) {
+		efi_guid_t guid;
+		unsigned long table;
+
+		if (efi_64bit) {
+			u64 table64;
+			guid = ((efi_config_table_64_t *)tablep)->guid;
+			table64 = ((efi_config_table_64_t *)tablep)->table;
+			table = table64;
+#ifdef CONFIG_X86_32
+			if (table64 >> 32) {
+				pr_cont("\n");
+				pr_err("Table located above 4GB, disabling EFI.\n");
+				early_iounmap(config_tables,
+					      efi.systab->nr_tables * sz);
+				return -EINVAL;
+			}
+#endif
+		} else {
+			guid = ((efi_config_table_32_t *)tablep)->guid;
+			table = ((efi_config_table_32_t *)tablep)->table;
+		}
+		if (!efi_guidcmp(guid, MPS_TABLE_GUID)) {
+			efi.mps = table;
+			pr_cont(" MPS=0x%lx ", table);
+		} else if (!efi_guidcmp(guid, ACPI_20_TABLE_GUID)) {
+			efi.acpi20 = table;
+			pr_cont(" ACPI 2.0=0x%lx ", table);
+		} else if (!efi_guidcmp(guid, ACPI_TABLE_GUID)) {
+			efi.acpi = table;
+			pr_cont(" ACPI=0x%lx ", table);
+		} else if (!efi_guidcmp(guid, SMBIOS_TABLE_GUID)) {
+			efi.smbios = table;
+			pr_cont(" SMBIOS=0x%lx ", table);
+#ifdef CONFIG_X86_UV
+		} else if (!efi_guidcmp(guid, UV_SYSTEM_TABLE_GUID)) {
+			efi.uv_systab = table;
+			pr_cont(" UVsystab=0x%lx ", table);
+#endif
+		} else if (!efi_guidcmp(guid, HCDP_TABLE_GUID)) {
+			efi.hcdp = table;
+			pr_cont(" HCDP=0x%lx ", table);
+		} else if (!efi_guidcmp(guid, UGA_IO_PROTOCOL_GUID)) {
+			efi.uga = table;
+			pr_cont(" UGA=0x%lx ", table);
+		}
+		tablep += sz;
+	}
+	pr_cont("\n");
+	early_iounmap(config_tables, efi.systab->nr_tables * sz);
+	return 0;
+}
+
+static int __init efi_runtime_init(void)
+{
+	efi_runtime_services_t *runtime;
+
+	/*
+	 * Check out the runtime services table. We need to map
+	 * the runtime services table so that we can grab the physical
+	 * address of several of the EFI runtime functions, needed to
+	 * set the firmware into virtual mode.
+	 */
+	runtime = early_ioremap((unsigned long)efi.systab->runtime,
+				sizeof(efi_runtime_services_t));
+	if (!runtime) {
+		pr_err("Could not map the runtime service table!\n");
+		return -ENOMEM;
+	}
+	/*
+	 * We will only need *early* access to the following
+	 * two EFI runtime services before set_virtual_address_map
+	 * is invoked.
+	 */
+	efi_phys.get_time = (efi_get_time_t *)runtime->get_time;
+	efi_phys.set_virtual_address_map =
+		(efi_set_virtual_address_map_t *)
+		runtime->set_virtual_address_map;
+	/*
+	 * Make efi_get_time can be called before entering
+	 * virtual mode.
+	 */
+	efi.get_time = phys_efi_get_time;
+	early_iounmap(runtime, sizeof(efi_runtime_services_t));
+
+	return 0;
+}
+
+static int __init efi_memmap_init(void)
+{
+	/* Map the EFI memory map */
+	memmap.map = early_ioremap((unsigned long)memmap.phys_map,
+				   memmap.nr_map * memmap.desc_size);
+	if (memmap.map == NULL) {
+		pr_err("Could not map the memory map!\n");
+		return -ENOMEM;
+	}
+	memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
+
+	if (add_efi_memmap)
+		do_add_efi_memmap();
+
+	return 0;
+}
+
 void __init efi_init(void)
 {
-	efi_config_table_t *config_tables;
-	efi_runtime_services_t *runtime;
 	efi_char16_t *c16;
 	char vendor[100] = "unknown";
 	int i = 0;
 	void *tmp;
 
 #ifdef CONFIG_X86_32
+	if (boot_params.efi_info.efi_systab_hi ||
+	    boot_params.efi_info.efi_memmap_hi) {
+		pr_info("Table located above 4GB, disabling EFI.\n");
+		efi_enabled = 0;
+		return;
+	}
 	efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
+	efi_native = !efi_64bit;
 #else
 	efi_phys.systab = (efi_system_table_t *)
-		(boot_params.efi_info.efi_systab |
-		 ((__u64)boot_params.efi_info.efi_systab_hi<<32));
+			  (boot_params.efi_info.efi_systab |
+			  ((__u64)boot_params.efi_info.efi_systab_hi<<32));
+	efi_native = efi_64bit;
 #endif
 
-	efi.systab = early_ioremap((unsigned long)efi_phys.systab,
-				   sizeof(efi_system_table_t));
-	if (efi.systab == NULL)
-		printk(KERN_ERR "Couldn't map the EFI system table!\n");
-	memcpy(&efi_systab, efi.systab, sizeof(efi_system_table_t));
-	early_iounmap(efi.systab, sizeof(efi_system_table_t));
-	efi.systab = &efi_systab;
-
-	/*
-	 * Verify the EFI Table
-	 */
-	if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
-		printk(KERN_ERR "EFI system table signature incorrect!\n");
-	if ((efi.systab->hdr.revision >> 16) == 0)
-		printk(KERN_ERR "Warning: EFI system table version "
-		       "%d.%02d, expected 1.00 or greater!\n",
-		       efi.systab->hdr.revision >> 16,
-		       efi.systab->hdr.revision & 0xffff);
+	if (efi_systab_init(efi_phys.systab)) {
+		efi_enabled = 0;
+		return;
+	}
 
 	/*
 	 * Show what we know for posterity
@@ -474,104 +692,39 @@
 			vendor[i] = *c16++;
 		vendor[i] = '\0';
 	} else
-		printk(KERN_ERR PFX "Could not map the firmware vendor!\n");
+		pr_err("Could not map the firmware vendor!\n");
 	early_iounmap(tmp, 2);
 
-	printk(KERN_INFO "EFI v%u.%.02u by %s\n",
-	       efi.systab->hdr.revision >> 16,
-	       efi.systab->hdr.revision & 0xffff, vendor);
+	pr_info("EFI v%u.%.02u by %s\n",
+		efi.systab->hdr.revision >> 16,
+		efi.systab->hdr.revision & 0xffff, vendor);
 
-	/*
-	 * Let's see what config tables the firmware passed to us.
-	 */
-	config_tables = early_ioremap(
-		efi.systab->tables,
-		efi.systab->nr_tables * sizeof(efi_config_table_t));
-	if (config_tables == NULL)
-		printk(KERN_ERR "Could not map EFI Configuration Table!\n");
-
-	printk(KERN_INFO);
-	for (i = 0; i < efi.systab->nr_tables; i++) {
-		if (!efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID)) {
-			efi.mps = config_tables[i].table;
-			printk(" MPS=0x%lx ", config_tables[i].table);
-		} else if (!efi_guidcmp(config_tables[i].guid,
-					ACPI_20_TABLE_GUID)) {
-			efi.acpi20 = config_tables[i].table;
-			printk(" ACPI 2.0=0x%lx ", config_tables[i].table);
-		} else if (!efi_guidcmp(config_tables[i].guid,
-					ACPI_TABLE_GUID)) {
-			efi.acpi = config_tables[i].table;
-			printk(" ACPI=0x%lx ", config_tables[i].table);
-		} else if (!efi_guidcmp(config_tables[i].guid,
-					SMBIOS_TABLE_GUID)) {
-			efi.smbios = config_tables[i].table;
-			printk(" SMBIOS=0x%lx ", config_tables[i].table);
-#ifdef CONFIG_X86_UV
-		} else if (!efi_guidcmp(config_tables[i].guid,
-					UV_SYSTEM_TABLE_GUID)) {
-			efi.uv_systab = config_tables[i].table;
-			printk(" UVsystab=0x%lx ", config_tables[i].table);
-#endif
-		} else if (!efi_guidcmp(config_tables[i].guid,
-					HCDP_TABLE_GUID)) {
-			efi.hcdp = config_tables[i].table;
-			printk(" HCDP=0x%lx ", config_tables[i].table);
-		} else if (!efi_guidcmp(config_tables[i].guid,
-					UGA_IO_PROTOCOL_GUID)) {
-			efi.uga = config_tables[i].table;
-			printk(" UGA=0x%lx ", config_tables[i].table);
-		}
+	if (efi_config_init(efi.systab->tables, efi.systab->nr_tables)) {
+		efi_enabled = 0;
+		return;
 	}
-	printk("\n");
-	early_iounmap(config_tables,
-			  efi.systab->nr_tables * sizeof(efi_config_table_t));
 
 	/*
-	 * Check out the runtime services table. We need to map
-	 * the runtime services table so that we can grab the physical
-	 * address of several of the EFI runtime functions, needed to
-	 * set the firmware into virtual mode.
+	 * Note: We currently don't support runtime services on an EFI
+	 * that doesn't match the kernel 32/64-bit mode.
 	 */
-	runtime = early_ioremap((unsigned long)efi.systab->runtime,
-				sizeof(efi_runtime_services_t));
-	if (runtime != NULL) {
-		/*
-		 * We will only need *early* access to the following
-		 * two EFI runtime services before set_virtual_address_map
-		 * is invoked.
-		 */
-		efi_phys.get_time = (efi_get_time_t *)runtime->get_time;
-		efi_phys.set_virtual_address_map =
-			(efi_set_virtual_address_map_t *)
-			runtime->set_virtual_address_map;
-		/*
-		 * Make efi_get_time can be called before entering
-		 * virtual mode.
-		 */
-		efi.get_time = phys_efi_get_time;
-	} else
-		printk(KERN_ERR "Could not map the EFI runtime service "
-		       "table!\n");
-	early_iounmap(runtime, sizeof(efi_runtime_services_t));
 
-	/* Map the EFI memory map */
-	memmap.map = early_ioremap((unsigned long)memmap.phys_map,
-				   memmap.nr_map * memmap.desc_size);
-	if (memmap.map == NULL)
-		printk(KERN_ERR "Could not map the EFI memory map!\n");
-	memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
+	if (!efi_native)
+		pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n");
+	else if (efi_runtime_init()) {
+		efi_enabled = 0;
+		return;
+	}
 
-	if (memmap.desc_size != sizeof(efi_memory_desc_t))
-		printk(KERN_WARNING
-		  "Kernel-defined memdesc doesn't match the one from EFI!\n");
-
-	if (add_efi_memmap)
-		do_add_efi_memmap();
-
+	if (efi_memmap_init()) {
+		efi_enabled = 0;
+		return;
+	}
 #ifdef CONFIG_X86_32
-	x86_platform.get_wallclock = efi_get_time;
-	x86_platform.set_wallclock = efi_set_rtc_mmss;
+	if (efi_native) {
+		x86_platform.get_wallclock = efi_get_time;
+		x86_platform.set_wallclock = efi_set_rtc_mmss;
+	}
 #endif
 
 #if EFI_DEBUG
@@ -629,6 +782,14 @@
 
 	efi.systab = NULL;
 
+	/*
+	 * We don't do virtual mode, since we don't do runtime services, on
+	 * non-native EFI
+	 */
+
+	if (!efi_native)
+		goto out;
+
 	/* Merge contiguous regions of the same type and attribute */
 	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
 		u64 prev_size;
@@ -677,7 +838,7 @@
 		md->virt_addr = (u64) (unsigned long) va;
 
 		if (!va) {
-			printk(KERN_ERR PFX "ioremap of 0x%llX failed!\n",
+			pr_err("ioremap of 0x%llX failed!\n",
 			       (unsigned long long)md->phys_addr);
 			continue;
 		}
@@ -711,8 +872,8 @@
 		(efi_memory_desc_t *)__pa(new_memmap));
 
 	if (status != EFI_SUCCESS) {
-		printk(KERN_ALERT "Unable to switch EFI into virtual mode "
-		       "(status=%lx)!\n", status);
+		pr_alert("Unable to switch EFI into virtual mode "
+			 "(status=%lx)!\n", status);
 		panic("EFI call to SetVirtualAddressMap() failed!");
 	}
 
@@ -744,6 +905,8 @@
 	efi.query_capsule_caps = virt_efi_query_capsule_caps;
 	if (__supported_pte_mask & _PAGE_NX)
 		runtime_code_page_mkexec();
+
+out:
 	early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
 	memmap.map = NULL;
 	kfree(new_memmap);
diff --git a/arch/x86/platform/geode/Makefile b/arch/x86/platform/geode/Makefile
index 07c9cd0..5b51194 100644
--- a/arch/x86/platform/geode/Makefile
+++ b/arch/x86/platform/geode/Makefile
@@ -1 +1,3 @@
 obj-$(CONFIG_ALIX)		+= alix.o
+obj-$(CONFIG_NET5501)		+= net5501.o
+obj-$(CONFIG_GEOS)		+= geos.o
diff --git a/arch/x86/platform/geode/alix.c b/arch/x86/platform/geode/alix.c
index dc5f1d3..90e23e7 100644
--- a/arch/x86/platform/geode/alix.c
+++ b/arch/x86/platform/geode/alix.c
@@ -6,6 +6,7 @@
  *
  * Copyright (C) 2008 Constantin Baranov <const@mimas.ru>
  * Copyright (C) 2011 Ed Wildgoose <kernel@wildgooses.com>
+ *                and Philip Prindeville <philipp@redfish-solutions.com>
  *
  * TODO: There are large similarities with leds-net5501.c
  * by Alessandro Zummo <a.zummo@towertech.it>
@@ -24,14 +25,47 @@
 #include <linux/leds.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/dmi.h>
 
 #include <asm/geode.h>
 
+#define BIOS_SIGNATURE_TINYBIOS		0xf0000
+#define BIOS_SIGNATURE_COREBOOT		0x500
+#define BIOS_REGION_SIZE		0x10000
+
 static bool force = 0;
 module_param(force, bool, 0444);
 /* FIXME: Award bios is not automatically detected as Alix platform */
 MODULE_PARM_DESC(force, "Force detection as ALIX.2/ALIX.3 platform");
 
+static struct gpio_keys_button alix_gpio_buttons[] = {
+	{
+		.code			= KEY_RESTART,
+		.gpio			= 24,
+		.active_low		= 1,
+		.desc			= "Reset button",
+		.type			= EV_KEY,
+		.wakeup			= 0,
+		.debounce_interval	= 100,
+		.can_disable		= 0,
+	}
+};
+static struct gpio_keys_platform_data alix_buttons_data = {
+	.buttons			= alix_gpio_buttons,
+	.nbuttons			= ARRAY_SIZE(alix_gpio_buttons),
+	.poll_interval			= 20,
+};
+
+static struct platform_device alix_buttons_dev = {
+	.name				= "gpio-keys-polled",
+	.id				= 1,
+	.dev = {
+		.platform_data		= &alix_buttons_data,
+	}
+};
+
 static struct gpio_led alix_leds[] = {
 	{
 		.name = "alix:1",
@@ -64,17 +98,22 @@
 	.dev.platform_data = &alix_leds_data,
 };
 
+static struct __initdata platform_device *alix_devs[] = {
+	&alix_buttons_dev,
+	&alix_leds_dev,
+};
+
 static void __init register_alix(void)
 {
 	/* Setup LED control through leds-gpio driver */
-	platform_device_register(&alix_leds_dev);
+	platform_add_devices(alix_devs, ARRAY_SIZE(alix_devs));
 }
 
-static int __init alix_present(unsigned long bios_phys,
+static bool __init alix_present(unsigned long bios_phys,
 				const char *alix_sig,
 				size_t alix_sig_len)
 {
-	const size_t bios_len = 0x00010000;
+	const size_t bios_len = BIOS_REGION_SIZE;
 	const char *bios_virt;
 	const char *scan_end;
 	const char *p;
@@ -84,7 +123,7 @@
 		printk(KERN_NOTICE "%s: forced to skip BIOS test, "
 		       "assume system is ALIX.2/ALIX.3\n",
 		       KBUILD_MODNAME);
-		return 1;
+		return true;
 	}
 
 	bios_virt = phys_to_virt(bios_phys);
@@ -109,15 +148,33 @@
 			*a = '\0';
 
 		tail = p + alix_sig_len;
-		if ((tail[0] == '2' || tail[0] == '3')) {
+		if ((tail[0] == '2' || tail[0] == '3' || tail[0] == '6')) {
 			printk(KERN_INFO
 			       "%s: system is recognized as \"%s\"\n",
 			       KBUILD_MODNAME, name);
-			return 1;
+			return true;
 		}
 	}
 
-	return 0;
+	return false;
+}
+
+static bool __init alix_present_dmi(void)
+{
+	const char *vendor, *product;
+
+	vendor = dmi_get_system_info(DMI_SYS_VENDOR);
+	if (!vendor || strcmp(vendor, "PC Engines"))
+		return false;
+
+	product = dmi_get_system_info(DMI_PRODUCT_NAME);
+	if (!product || (strcmp(product, "ALIX.2D") && strcmp(product, "ALIX.6")))
+		return false;
+
+	printk(KERN_INFO "%s: system is recognized as \"%s %s\"\n",
+	       KBUILD_MODNAME, vendor, product);
+
+	return true;
 }
 
 static int __init alix_init(void)
@@ -128,8 +185,9 @@
 	if (!is_geode())
 		return 0;
 
-	if (alix_present(0xf0000, tinybios_sig, sizeof(tinybios_sig) - 1) ||
-	    alix_present(0x500, coreboot_sig, sizeof(coreboot_sig) - 1))
+	if (alix_present(BIOS_SIGNATURE_TINYBIOS, tinybios_sig, sizeof(tinybios_sig) - 1) ||
+	    alix_present(BIOS_SIGNATURE_COREBOOT, coreboot_sig, sizeof(coreboot_sig) - 1) ||
+	    alix_present_dmi())
 		register_alix();
 
 	return 0;
diff --git a/arch/x86/platform/geode/geos.c b/arch/x86/platform/geode/geos.c
new file mode 100644
index 0000000..c2e6d53
--- /dev/null
+++ b/arch/x86/platform/geode/geos.c
@@ -0,0 +1,128 @@
+/*
+ * System Specific setup for Traverse Technologies GEOS.
+ * At the moment this means setup of GPIO control of LEDs.
+ *
+ * Copyright (C) 2008 Constantin Baranov <const@mimas.ru>
+ * Copyright (C) 2011 Ed Wildgoose <kernel@wildgooses.com>
+ *                and Philip Prindeville <philipp@redfish-solutions.com>
+ *
+ * TODO: There are large similarities with leds-net5501.c
+ * by Alessandro Zummo <a.zummo@towertech.it>
+ * In the future leds-net5501.c should be migrated over to platform
+ *
+ * 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/io.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/dmi.h>
+
+#include <asm/geode.h>
+
+static struct gpio_keys_button geos_gpio_buttons[] = {
+	{
+		.code = KEY_RESTART,
+		.gpio = 3,
+		.active_low = 1,
+		.desc = "Reset button",
+		.type = EV_KEY,
+		.wakeup = 0,
+		.debounce_interval = 100,
+		.can_disable = 0,
+	}
+};
+static struct gpio_keys_platform_data geos_buttons_data = {
+	.buttons = geos_gpio_buttons,
+	.nbuttons = ARRAY_SIZE(geos_gpio_buttons),
+	.poll_interval = 20,
+};
+
+static struct platform_device geos_buttons_dev = {
+	.name = "gpio-keys-polled",
+	.id = 1,
+	.dev = {
+		.platform_data = &geos_buttons_data,
+	}
+};
+
+static struct gpio_led geos_leds[] = {
+	{
+		.name = "geos:1",
+		.gpio = 6,
+		.default_trigger = "default-on",
+		.active_low = 1,
+	},
+	{
+		.name = "geos:2",
+		.gpio = 25,
+		.default_trigger = "default-off",
+		.active_low = 1,
+	},
+	{
+		.name = "geos:3",
+		.gpio = 27,
+		.default_trigger = "default-off",
+		.active_low = 1,
+	},
+};
+
+static struct gpio_led_platform_data geos_leds_data = {
+	.num_leds = ARRAY_SIZE(geos_leds),
+	.leds = geos_leds,
+};
+
+static struct platform_device geos_leds_dev = {
+	.name = "leds-gpio",
+	.id = -1,
+	.dev.platform_data = &geos_leds_data,
+};
+
+static struct __initdata platform_device *geos_devs[] = {
+	&geos_buttons_dev,
+	&geos_leds_dev,
+};
+
+static void __init register_geos(void)
+{
+	/* Setup LED control through leds-gpio driver */
+	platform_add_devices(geos_devs, ARRAY_SIZE(geos_devs));
+}
+
+static int __init geos_init(void)
+{
+	const char *vendor, *product;
+
+	if (!is_geode())
+		return 0;
+
+	vendor = dmi_get_system_info(DMI_SYS_VENDOR);
+	if (!vendor || strcmp(vendor, "Traverse Technologies"))
+		return 0;
+
+	product = dmi_get_system_info(DMI_PRODUCT_NAME);
+	if (!product || strcmp(product, "Geos"))
+		return 0;
+
+	printk(KERN_INFO "%s: system is recognized as \"%s %s\"\n",
+	       KBUILD_MODNAME, vendor, product);
+
+	register_geos();
+
+	return 0;
+}
+
+module_init(geos_init);
+
+MODULE_AUTHOR("Philip Prindeville <philipp@redfish-solutions.com>");
+MODULE_DESCRIPTION("Traverse Technologies Geos System Setup");
+MODULE_LICENSE("GPL");
diff --git a/arch/x86/platform/geode/net5501.c b/arch/x86/platform/geode/net5501.c
new file mode 100644
index 0000000..66d377e
--- /dev/null
+++ b/arch/x86/platform/geode/net5501.c
@@ -0,0 +1,154 @@
+/*
+ * System Specific setup for Soekris net5501
+ * At the moment this means setup of GPIO control of LEDs and buttons
+ * on net5501 boards.
+ *
+ *
+ * Copyright (C) 2008-2009 Tower Technologies
+ * Written by Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * Copyright (C) 2008 Constantin Baranov <const@mimas.ru>
+ * Copyright (C) 2011 Ed Wildgoose <kernel@wildgooses.com>
+ *                and Philip Prindeville <philipp@redfish-solutions.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/io.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+#include <asm/geode.h>
+
+#define BIOS_REGION_BASE		0xffff0000
+#define BIOS_REGION_SIZE		0x00010000
+
+static struct gpio_keys_button net5501_gpio_buttons[] = {
+	{
+		.code = KEY_RESTART,
+		.gpio = 24,
+		.active_low = 1,
+		.desc = "Reset button",
+		.type = EV_KEY,
+		.wakeup = 0,
+		.debounce_interval = 100,
+		.can_disable = 0,
+	}
+};
+static struct gpio_keys_platform_data net5501_buttons_data = {
+	.buttons = net5501_gpio_buttons,
+	.nbuttons = ARRAY_SIZE(net5501_gpio_buttons),
+	.poll_interval = 20,
+};
+
+static struct platform_device net5501_buttons_dev = {
+	.name = "gpio-keys-polled",
+	.id = 1,
+	.dev = {
+		.platform_data = &net5501_buttons_data,
+	}
+};
+
+static struct gpio_led net5501_leds[] = {
+	{
+		.name = "net5501:1",
+		.gpio = 6,
+		.default_trigger = "default-on",
+		.active_low = 1,
+	},
+};
+
+static struct gpio_led_platform_data net5501_leds_data = {
+	.num_leds = ARRAY_SIZE(net5501_leds),
+	.leds = net5501_leds,
+};
+
+static struct platform_device net5501_leds_dev = {
+	.name = "leds-gpio",
+	.id = -1,
+	.dev.platform_data = &net5501_leds_data,
+};
+
+static struct __initdata platform_device *net5501_devs[] = {
+	&net5501_buttons_dev,
+	&net5501_leds_dev,
+};
+
+static void __init register_net5501(void)
+{
+	/* Setup LED control through leds-gpio driver */
+	platform_add_devices(net5501_devs, ARRAY_SIZE(net5501_devs));
+}
+
+struct net5501_board {
+	u16	offset;
+	u16	len;
+	char	*sig;
+};
+
+static struct net5501_board __initdata boards[] = {
+	{ 0xb7b, 7, "net5501" },	/* net5501 v1.33/1.33c */
+	{ 0xb1f, 7, "net5501" },	/* net5501 v1.32i */
+};
+
+static bool __init net5501_present(void)
+{
+	int i;
+	unsigned char *rombase, *bios;
+	bool found = false;
+
+	rombase = ioremap(BIOS_REGION_BASE, BIOS_REGION_SIZE - 1);
+	if (!rombase) {
+		printk(KERN_ERR "%s: failed to get rombase\n", KBUILD_MODNAME);
+		return found;
+	}
+
+	bios = rombase + 0x20;	/* null terminated */
+
+	if (memcmp(bios, "comBIOS", 7))
+		goto unmap;
+
+	for (i = 0; i < ARRAY_SIZE(boards); i++) {
+		unsigned char *model = rombase + boards[i].offset;
+
+		if (!memcmp(model, boards[i].sig, boards[i].len)) {
+			printk(KERN_INFO "%s: system is recognized as \"%s\"\n",
+			       KBUILD_MODNAME, model);
+
+			found = true;
+			break;
+		}
+	}
+
+unmap:
+	iounmap(rombase);
+	return found;
+}
+
+static int __init net5501_init(void)
+{
+	if (!is_geode())
+		return 0;
+
+	if (!net5501_present())
+		return 0;
+
+	register_net5501();
+
+	return 0;
+}
+
+module_init(net5501_init);
+
+MODULE_AUTHOR("Philip Prindeville <philipp@redfish-solutions.com>");
+MODULE_DESCRIPTION("Soekris net5501 System Setup");
+MODULE_LICENSE("GPL");
diff --git a/arch/x86/platform/mrst/Makefile b/arch/x86/platform/mrst/Makefile
index 7baed51..af1da7e 100644
--- a/arch/x86/platform/mrst/Makefile
+++ b/arch/x86/platform/mrst/Makefile
@@ -1,4 +1,3 @@
 obj-$(CONFIG_X86_INTEL_MID)	+= mrst.o
 obj-$(CONFIG_X86_INTEL_MID)	+= vrtc.o
 obj-$(CONFIG_EARLY_PRINTK_INTEL_MID)	+= early_printk_mrst.o
-obj-$(CONFIG_X86_MRST)		+= pmu.o
diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c
index 475e2cd..e0a3723 100644
--- a/arch/x86/platform/mrst/mrst.c
+++ b/arch/x86/platform/mrst/mrst.c
@@ -28,6 +28,8 @@
 #include <linux/module.h>
 #include <linux/notifier.h>
 #include <linux/mfd/intel_msic.h>
+#include <linux/gpio.h>
+#include <linux/i2c/tc35876x.h>
 
 #include <asm/setup.h>
 #include <asm/mpspec_def.h>
@@ -78,16 +80,11 @@
 
 static void mrst_power_off(void)
 {
-	if (__mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT)
-		intel_scu_ipc_simple_command(IPCMSG_COLD_RESET, 1);
 }
 
 static void mrst_reboot(void)
 {
-	if (__mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT)
-		intel_scu_ipc_simple_command(IPCMSG_COLD_RESET, 0);
-	else
-		intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0);
+	intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0);
 }
 
 /* parse all the mtimer info to a static mtimer array */
@@ -200,34 +197,28 @@
 
 static unsigned long __init mrst_calibrate_tsc(void)
 {
-	unsigned long flags, fast_calibrate;
-	if (__mrst_cpu_chip == MRST_CPU_CHIP_PENWELL) {
-		u32 lo, hi, ratio, fsb;
+	unsigned long fast_calibrate;
+	u32 lo, hi, ratio, fsb;
 
-		rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
-		pr_debug("IA32 perf status is 0x%x, 0x%0x\n", lo, hi);
-		ratio = (hi >> 8) & 0x1f;
-		pr_debug("ratio is %d\n", ratio);
-		if (!ratio) {
-			pr_err("read a zero ratio, should be incorrect!\n");
-			pr_err("force tsc ratio to 16 ...\n");
-			ratio = 16;
-		}
-		rdmsr(MSR_FSB_FREQ, lo, hi);
-		if ((lo & 0x7) == 0x7)
-			fsb = PENWELL_FSB_FREQ_83SKU;
-		else
-			fsb = PENWELL_FSB_FREQ_100SKU;
-		fast_calibrate = ratio * fsb;
-		pr_debug("read penwell tsc %lu khz\n", fast_calibrate);
-		lapic_timer_frequency = fsb * 1000 / HZ;
-		/* mark tsc clocksource as reliable */
-		set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE);
-	} else {
-		local_irq_save(flags);
-		fast_calibrate = apbt_quick_calibrate();
-		local_irq_restore(flags);
+	rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
+	pr_debug("IA32 perf status is 0x%x, 0x%0x\n", lo, hi);
+	ratio = (hi >> 8) & 0x1f;
+	pr_debug("ratio is %d\n", ratio);
+	if (!ratio) {
+		pr_err("read a zero ratio, should be incorrect!\n");
+		pr_err("force tsc ratio to 16 ...\n");
+		ratio = 16;
 	}
+	rdmsr(MSR_FSB_FREQ, lo, hi);
+	if ((lo & 0x7) == 0x7)
+		fsb = PENWELL_FSB_FREQ_83SKU;
+	else
+		fsb = PENWELL_FSB_FREQ_100SKU;
+	fast_calibrate = ratio * fsb;
+	pr_debug("read penwell tsc %lu khz\n", fast_calibrate);
+	lapic_timer_frequency = fsb * 1000 / HZ;
+	/* mark tsc clocksource as reliable */
+	set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE);
 	
 	if (fast_calibrate)
 		return fast_calibrate;
@@ -261,16 +252,11 @@
 {
 	if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27)
 		__mrst_cpu_chip = MRST_CPU_CHIP_PENWELL;
-	else if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x26)
-		__mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT;
 	else {
-		pr_err("Unknown Moorestown CPU (%d:%d), default to Lincroft\n",
+		pr_err("Unknown Intel MID CPU (%d:%d), default to Penwell\n",
 			boot_cpu_data.x86, boot_cpu_data.x86_model);
-		__mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT;
+		__mrst_cpu_chip = MRST_CPU_CHIP_PENWELL;
 	}
-	pr_debug("Moorestown CPU %s identified\n",
-		(__mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT) ?
-		"Lincroft" : "Penwell");
 }
 
 /* MID systems don't have i8042 controller */
@@ -686,6 +672,24 @@
 	return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_OCD);
 }
 
+static void *msic_thermal_platform_data(void *info)
+{
+	return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_THERMAL);
+}
+
+/* tc35876x DSI-LVDS bridge chip and panel platform data */
+static void *tc35876x_platform_data(void *data)
+{
+       static struct tc35876x_platform_data pdata;
+
+       /* gpio pins set to -1 will not be used by the driver */
+       pdata.gpio_bridge_reset = get_gpio_by_name("LCMB_RXEN");
+       pdata.gpio_panel_bl_en = get_gpio_by_name("6S6P_BL_EN");
+       pdata.gpio_panel_vadd = get_gpio_by_name("EN_VREG_LCD_V3P3");
+
+       return &pdata;
+}
+
 static const struct devs_id __initconst device_ids[] = {
 	{"bma023", SFI_DEV_TYPE_I2C, 1, &no_platform_data},
 	{"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data},
@@ -698,6 +702,7 @@
 	{"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data},
 	{"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data},
 	{"mpu3050", SFI_DEV_TYPE_I2C, 1, &mpu3050_platform_data},
+	{"i2c_disp_brig", SFI_DEV_TYPE_I2C, 0, &tc35876x_platform_data},
 
 	/* MSIC subdevices */
 	{"msic_battery", SFI_DEV_TYPE_IPC, 1, &msic_battery_platform_data},
@@ -705,6 +710,7 @@
 	{"msic_audio", SFI_DEV_TYPE_IPC, 1, &msic_audio_platform_data},
 	{"msic_power_btn", SFI_DEV_TYPE_IPC, 1, &msic_power_btn_platform_data},
 	{"msic_ocd", SFI_DEV_TYPE_IPC, 1, &msic_ocd_platform_data},
+	{"msic_thermal", SFI_DEV_TYPE_IPC, 1, &msic_thermal_platform_data},
 
 	{},
 };
diff --git a/arch/x86/platform/mrst/pmu.c b/arch/x86/platform/mrst/pmu.c
deleted file mode 100644
index c0ac06d..0000000
--- a/arch/x86/platform/mrst/pmu.c
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
- * mrst/pmu.c - driver for MRST Power Management Unit
- *
- * Copyright (c) 2011, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * 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/cpuidle.h>
-#include <linux/debugfs.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/seq_file.h>
-#include <linux/sfi.h>
-#include <asm/intel_scu_ipc.h>
-#include "pmu.h"
-
-#define IPCMSG_FW_REVISION	0xF4
-
-struct mrst_device {
-	u16 pci_dev_num;	/* DEBUG only */
-	u16 lss;
-	u16 latest_request;
-	unsigned int pci_state_counts[PCI_D3cold + 1]; /* DEBUG only */
-};
-
-/*
- * comlete list of MRST PCI devices
- */
-static struct mrst_device mrst_devs[] = {
-/*  0 */ { 0x0800, LSS_SPI0 },		/* Moorestown SPI Ctrl 0 */
-/*  1 */ { 0x0801, LSS_SPI1 },		/* Moorestown SPI Ctrl 1 */
-/*  2 */ { 0x0802, LSS_I2C0 },		/* Moorestown I2C 0 */
-/*  3 */ { 0x0803, LSS_I2C1 },		/* Moorestown I2C 1 */
-/*  4 */ { 0x0804, LSS_I2C2 },		/* Moorestown I2C 2 */
-/*  5 */ { 0x0805, LSS_KBD },		/* Moorestown Keyboard Ctrl */
-/*  6 */ { 0x0806, LSS_USB_HC },	/* Moorestown USB Ctrl */
-/*  7 */ { 0x0807, LSS_SD_HC0 },	/* Moorestown SD Host Ctrl 0 */
-/*  8 */ { 0x0808, LSS_SD_HC1 },	/* Moorestown SD Host Ctrl 1 */
-/*  9 */ { 0x0809, LSS_NAND },		/* Moorestown NAND Ctrl */
-/* 10 */ { 0x080a, LSS_AUDIO },		/* Moorestown Audio Ctrl */
-/* 11 */ { 0x080b, LSS_IMAGING },	/* Moorestown ISP */
-/* 12 */ { 0x080c, LSS_SECURITY },	/* Moorestown Security Controller */
-/* 13 */ { 0x080d, LSS_DISPLAY },	/* Moorestown External Displays */
-/* 14 */ { 0x080e, 0 },			/* Moorestown SCU IPC */
-/* 15 */ { 0x080f, LSS_GPIO },		/* Moorestown GPIO Controller */
-/* 16 */ { 0x0810, 0 },			/* Moorestown Power Management Unit */
-/* 17 */ { 0x0811, LSS_USB_OTG },	/* Moorestown OTG Ctrl */
-/* 18 */ { 0x0812, LSS_SPI2 },		/* Moorestown SPI Ctrl 2 */
-/* 19 */ { 0x0813, 0 },			/* Moorestown SC DMA */
-/* 20 */ { 0x0814, LSS_AUDIO_LPE },	/* Moorestown LPE DMA */
-/* 21 */ { 0x0815, LSS_AUDIO_SSP },	/* Moorestown SSP0 */
-
-/* 22 */ { 0x084F, LSS_SD_HC2 },	/* Moorestown SD Host Ctrl 2 */
-
-/* 23 */ { 0x4102, 0 },			/* Lincroft */
-/* 24 */ { 0x4110, 0 },			/* Lincroft */
-};
-
-/* n.b. We ignore PCI-id 0x815 in LSS9 b/c Linux has no driver for it */
-static u16 mrst_lss9_pci_ids[] = {0x080a, 0x0814, 0};
-static u16 mrst_lss10_pci_ids[] = {0x0800, 0x0801, 0x0802, 0x0803,
-					0x0804, 0x0805, 0x080f, 0};
-
-/* handle concurrent SMP invokations of pmu_pci_set_power_state() */
-static spinlock_t mrst_pmu_power_state_lock;
-
-static unsigned int wake_counters[MRST_NUM_LSS];	/* DEBUG only */
-static unsigned int pmu_irq_stats[INT_INVALID + 1];	/* DEBUG only */
-
-static int graphics_is_off;
-static int lss_s0i3_enabled;
-static bool mrst_pmu_s0i3_enable;
-
-/*  debug counters */
-static u32 pmu_wait_ready_calls;
-static u32 pmu_wait_ready_udelays;
-static u32 pmu_wait_ready_udelays_max;
-static u32 pmu_wait_done_calls;
-static u32 pmu_wait_done_udelays;
-static u32 pmu_wait_done_udelays_max;
-static u32 pmu_set_power_state_entry;
-static u32 pmu_set_power_state_send_cmd;
-
-static struct mrst_device *pci_id_2_mrst_dev(u16 pci_dev_num)
-{
-	int index = 0;
-
-	if ((pci_dev_num >= 0x0800) && (pci_dev_num <= 0x815))
-		index = pci_dev_num - 0x800;
-	else if (pci_dev_num == 0x084F)
-		index = 22;
-	else if (pci_dev_num == 0x4102)
-		index = 23;
-	else if (pci_dev_num == 0x4110)
-		index = 24;
-
-	if (pci_dev_num != mrst_devs[index].pci_dev_num) {
-		WARN_ONCE(1, FW_BUG "Unknown PCI device 0x%04X\n", pci_dev_num);
-		return 0;
-	}
-
-	return &mrst_devs[index];
-}
-
-/**
- * mrst_pmu_validate_cstates
- * @dev: cpuidle_device
- *
- * Certain states are not appropriate for governor to pick in some cases.
- * This function will be called as cpuidle_device's prepare callback and
- * thus tells governor to ignore such states when selecting the next state
- * to enter.
- */
-
-#define IDLE_STATE4_IS_C6	4
-#define IDLE_STATE5_IS_S0I3	5
-
-int mrst_pmu_invalid_cstates(void)
-{
-	int cpu = smp_processor_id();
-
-	/*
-	 * Demote to C4 if the PMU is busy.
-	 * Since LSS changes leave the busy bit clear...
-	 * busy means either the PMU is waiting for an ACK-C6 that
-	 * isn't coming due to an MWAIT that returned immediately;
-	 * or we returned from S0i3 successfully, and the PMU
-	 * is not done sending us interrupts.
-	 */
-	if (pmu_read_busy_status())
-		return 1 << IDLE_STATE4_IS_C6 | 1 << IDLE_STATE5_IS_S0I3;
-
-	/*
-	 * Disallow S0i3 if: PMU is not initialized, or CPU1 is active,
-	 * or if device LSS is insufficient, or the GPU is active,
-	 * or if it has been explicitly disabled.
-	 */
-	if (!pmu_reg || !cpumask_equal(cpu_online_mask, cpumask_of(cpu)) ||
-	    !lss_s0i3_enabled || !graphics_is_off || !mrst_pmu_s0i3_enable)
-		return 1 << IDLE_STATE5_IS_S0I3;
-	else
-		return 0;
-}
-
-/*
- * pmu_update_wake_counters(): read PM_WKS, update wake_counters[]
- * DEBUG only.
- */
-static void pmu_update_wake_counters(void)
-{
-	int lss;
-	u32 wake_status;
-
-	wake_status = pmu_read_wks();
-
-	for (lss = 0; lss < MRST_NUM_LSS; ++lss) {
-		if (wake_status & (1 << lss))
-			wake_counters[lss]++;
-	}
-}
-
-int mrst_pmu_s0i3_entry(void)
-{
-	int status;
-
-	/* Clear any possible error conditions */
-	pmu_write_ics(0x300);
-
-	/* set wake control to current D-states */
-	pmu_write_wssc(S0I3_SSS_TARGET);
-
-	status = mrst_s0i3_entry(PM_S0I3_COMMAND, &pmu_reg->pm_cmd);
-	pmu_update_wake_counters();
-	return status;
-}
-
-/* poll for maximum of 5ms for busy bit to clear */
-static int pmu_wait_ready(void)
-{
-	int udelays;
-
-	pmu_wait_ready_calls++;
-
-	for (udelays = 0; udelays < 500; ++udelays) {
-		if (udelays > pmu_wait_ready_udelays_max)
-			pmu_wait_ready_udelays_max = udelays;
-
-		if (pmu_read_busy_status() == 0)
-			return 0;
-
-		udelay(10);
-		pmu_wait_ready_udelays++;
-	}
-
-	/*
-	 * if this fires, observe
-	 * /sys/kernel/debug/mrst_pmu_wait_ready_calls
-	 * /sys/kernel/debug/mrst_pmu_wait_ready_udelays
-	 */
-	WARN_ONCE(1, "SCU not ready for 5ms");
-	return -EBUSY;
-}
-/* poll for maximum of 50ms us for busy bit to clear */
-static int pmu_wait_done(void)
-{
-	int udelays;
-
-	pmu_wait_done_calls++;
-
-	for (udelays = 0; udelays < 500; ++udelays) {
-		if (udelays > pmu_wait_done_udelays_max)
-			pmu_wait_done_udelays_max = udelays;
-
-		if (pmu_read_busy_status() == 0)
-			return 0;
-
-		udelay(100);
-		pmu_wait_done_udelays++;
-	}
-
-	/*
-	 * if this fires, observe
-	 * /sys/kernel/debug/mrst_pmu_wait_done_calls
-	 * /sys/kernel/debug/mrst_pmu_wait_done_udelays
-	 */
-	WARN_ONCE(1, "SCU not done for 50ms");
-	return -EBUSY;
-}
-
-u32 mrst_pmu_msi_is_disabled(void)
-{
-	return pmu_msi_is_disabled();
-}
-
-void mrst_pmu_enable_msi(void)
-{
-	pmu_msi_enable();
-}
-
-/**
- * pmu_irq - pmu driver interrupt handler
- * Context: interrupt context
- */
-static irqreturn_t pmu_irq(int irq, void *dummy)
-{
-	union pmu_pm_ics pmu_ics;
-
-	pmu_ics.value = pmu_read_ics();
-
-	if (!pmu_ics.bits.pending)
-		return IRQ_NONE;
-
-	switch (pmu_ics.bits.cause) {
-	case INT_SPURIOUS:
-	case INT_CMD_DONE:
-	case INT_CMD_ERR:
-	case INT_WAKE_RX:
-	case INT_SS_ERROR:
-	case INT_S0IX_MISS:
-	case INT_NO_ACKC6:
-		pmu_irq_stats[pmu_ics.bits.cause]++;
-		break;
-	default:
-		pmu_irq_stats[INT_INVALID]++;
-	}
-
-	pmu_write_ics(pmu_ics.value); /* Clear pending interrupt */
-
-	return IRQ_HANDLED;
-}
-
-/*
- * Translate PCI power management to MRST LSS D-states
- */
-static int pci_2_mrst_state(int lss, pci_power_t pci_state)
-{
-	switch (pci_state) {
-	case PCI_D0:
-		if (SSMSK(D0i1, lss) & D0I1_ACG_SSS_TARGET)
-			return D0i1;
-		else
-			return D0;
-	case PCI_D1:
-		return D0i1;
-	case PCI_D2:
-		return D0i2;
-	case PCI_D3hot:
-	case PCI_D3cold:
-		return D0i3;
-	default:
-		WARN(1, "pci_state %d\n", pci_state);
-		return 0;
-	}
-}
-
-static int pmu_issue_command(u32 pm_ssc)
-{
-	union pmu_pm_set_cfg_cmd_t command;
-
-	if (pmu_read_busy_status()) {
-		pr_debug("pmu is busy, Operation not permitted\n");
-		return -1;
-	}
-
-	/*
-	 * enable interrupts in PMU so that interrupts are
-	 * propagated when ioc bit for a particular set
-	 * command is set
-	 */
-
-	pmu_irq_enable();
-
-	/* Configure the sub systems for pmu2 */
-
-	pmu_write_ssc(pm_ssc);
-
-	/*
-	 * Send the set config command for pmu its configured
-	 * for mode CM_IMMEDIATE & hence with No Trigger
-	 */
-
-	command.pmu2_params.d_param.cfg_mode = CM_IMMEDIATE;
-	command.pmu2_params.d_param.cfg_delay = 0;
-	command.pmu2_params.d_param.rsvd = 0;
-
-	/* construct the command to send SET_CFG to particular PMU */
-	command.pmu2_params.d_param.cmd = SET_CFG_CMD;
-	command.pmu2_params.d_param.ioc = 0;
-	command.pmu2_params.d_param.mode_id = 0;
-	command.pmu2_params.d_param.sys_state = SYS_STATE_S0I0;
-
-	/* write the value of PM_CMD into particular PMU */
-	pr_debug("pmu command being written %x\n",
-			command.pmu_pm_set_cfg_cmd_value);
-
-	pmu_write_cmd(command.pmu_pm_set_cfg_cmd_value);
-
-	return 0;
-}
-
-static u16 pmu_min_lss_pci_req(u16 *ids, u16 pci_state)
-{
-	u16 existing_request;
-	int i;
-
-	for (i = 0; ids[i]; ++i) {
-		struct mrst_device *mrst_dev;
-
-		mrst_dev = pci_id_2_mrst_dev(ids[i]);
-		if (unlikely(!mrst_dev))
-			continue;
-
-		existing_request = mrst_dev->latest_request;
-		if (existing_request < pci_state)
-			pci_state = existing_request;
-	}
-	return pci_state;
-}
-
-/**
- * pmu_pci_set_power_state - Callback function is used by all the PCI devices
- *			for a platform  specific device power on/shutdown.
- */
-
-int pmu_pci_set_power_state(struct pci_dev *pdev, pci_power_t pci_state)
-{
-	u32 old_sss, new_sss;
-	int status = 0;
-	struct mrst_device *mrst_dev;
-
-	pmu_set_power_state_entry++;
-
-	BUG_ON(pdev->vendor != PCI_VENDOR_ID_INTEL);
-	BUG_ON(pci_state < PCI_D0 || pci_state > PCI_D3cold);
-
-	mrst_dev = pci_id_2_mrst_dev(pdev->device);
-	if (unlikely(!mrst_dev))
-		return -ENODEV;
-
-	mrst_dev->pci_state_counts[pci_state]++;	/* count invocations */
-
-	/* PMU driver calls self as part of PCI initialization, ignore */
-	if (pdev->device == PCI_DEV_ID_MRST_PMU)
-		return 0;
-
-	BUG_ON(!pmu_reg); /* SW bug if called before initialized */
-
-	spin_lock(&mrst_pmu_power_state_lock);
-
-	if (pdev->d3_delay) {
-		dev_dbg(&pdev->dev, "d3_delay %d, should be 0\n",
-			pdev->d3_delay);
-		pdev->d3_delay = 0;
-	}
-	/*
-	 * If Lincroft graphics, simply remember state
-	 */
-	if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY
-		&& !((pdev->class & PCI_SUB_CLASS_MASK) >> 8)) {
-		if (pci_state == PCI_D0)
-			graphics_is_off = 0;
-		else
-			graphics_is_off = 1;
-		goto ret;
-	}
-
-	if (!mrst_dev->lss)
-		goto ret;	/* device with no LSS */
-
-	if (mrst_dev->latest_request == pci_state)
-		goto ret;	/* no change */
-
-	mrst_dev->latest_request = pci_state;	/* record latest request */
-
-	/*
-	 * LSS9 and LSS10 contain multiple PCI devices.
-	 * Use the lowest numbered (highest power) state in the LSS
-	 */
-	if (mrst_dev->lss == 9)
-		pci_state = pmu_min_lss_pci_req(mrst_lss9_pci_ids, pci_state);
-	else if (mrst_dev->lss == 10)
-		pci_state = pmu_min_lss_pci_req(mrst_lss10_pci_ids, pci_state);
-
-	status = pmu_wait_ready();
-	if (status)
-		goto ret;
-
-	old_sss = pmu_read_sss();
-	new_sss = old_sss & ~SSMSK(3, mrst_dev->lss);
-	new_sss |= SSMSK(pci_2_mrst_state(mrst_dev->lss, pci_state),
-			mrst_dev->lss);
-
-	if (new_sss == old_sss)
-		goto ret;	/* nothing to do */
-
-	pmu_set_power_state_send_cmd++;
-
-	status = pmu_issue_command(new_sss);
-
-	if (unlikely(status != 0)) {
-		dev_err(&pdev->dev, "Failed to Issue a PM command\n");
-		goto ret;
-	}
-
-	if (pmu_wait_done())
-		goto ret;
-
-	lss_s0i3_enabled =
-	((pmu_read_sss() & S0I3_SSS_TARGET) == S0I3_SSS_TARGET);
-ret:
-	spin_unlock(&mrst_pmu_power_state_lock);
-	return status;
-}
-
-#ifdef CONFIG_DEBUG_FS
-static char *d0ix_names[] = {"D0", "D0i1", "D0i2", "D0i3"};
-
-static inline const char *d0ix_name(int state)
-{
-	return d0ix_names[(int) state];
-}
-
-static int debug_mrst_pmu_show(struct seq_file *s, void *unused)
-{
-	struct pci_dev *pdev = NULL;
-	u32 cur_pmsss;
-	int lss;
-
-	seq_printf(s, "0x%08X D0I1_ACG_SSS_TARGET\n", D0I1_ACG_SSS_TARGET);
-
-	cur_pmsss = pmu_read_sss();
-
-	seq_printf(s, "0x%08X S0I3_SSS_TARGET\n", S0I3_SSS_TARGET);
-
-	seq_printf(s, "0x%08X Current SSS ", cur_pmsss);
-	seq_printf(s, lss_s0i3_enabled ? "\n" : "[BLOCKS s0i3]\n");
-
-	if (cpumask_equal(cpu_online_mask, cpumask_of(0)))
-		seq_printf(s, "cpu0 is only cpu online\n");
-	else
-		seq_printf(s, "cpu0 is NOT only cpu online [BLOCKS S0i3]\n");
-
-	seq_printf(s, "GFX: %s\n", graphics_is_off ? "" : "[BLOCKS s0i3]");
-
-
-	for_each_pci_dev(pdev) {
-		int pos;
-		u16 pmcsr;
-		struct mrst_device *mrst_dev;
-		int i;
-
-		mrst_dev = pci_id_2_mrst_dev(pdev->device);
-
-		seq_printf(s, "%s %04x/%04X %-16.16s ",
-			dev_name(&pdev->dev),
-			pdev->vendor, pdev->device,
-			dev_driver_string(&pdev->dev));
-
-		if (unlikely (!mrst_dev)) {
-			seq_printf(s, " UNKNOWN\n");
-			continue;
-		}
-
-		if (mrst_dev->lss)
-			seq_printf(s, "LSS %2d %-4s ", mrst_dev->lss,
-				d0ix_name(((cur_pmsss >>
-					(mrst_dev->lss * 2)) & 0x3)));
-		else
-			seq_printf(s, "            ");
-
-		/* PCI PM config space setting */
-		pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
-		if (pos != 0) {
-			pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
-		seq_printf(s, "PCI-%-4s",
-			pci_power_name(pmcsr & PCI_PM_CTRL_STATE_MASK));
-		} else {
-			seq_printf(s, "        ");
-		}
-
-		seq_printf(s, " %s ", pci_power_name(mrst_dev->latest_request));
-		for (i = 0; i <= PCI_D3cold; ++i)
-			seq_printf(s, "%d ", mrst_dev->pci_state_counts[i]);
-
-		if (mrst_dev->lss) {
-			unsigned int lssmask;
-
-			lssmask = SSMSK(D0i3, mrst_dev->lss);
-
-			if ((lssmask & S0I3_SSS_TARGET) &&
-				((lssmask & cur_pmsss) !=
-					(lssmask & S0I3_SSS_TARGET)))
-						seq_printf(s , "[BLOCKS s0i3]");
-		}
-
-		seq_printf(s, "\n");
-	}
-	seq_printf(s, "Wake Counters:\n");
-	for (lss = 0; lss < MRST_NUM_LSS; ++lss)
-		seq_printf(s, "LSS%d %d\n", lss, wake_counters[lss]);
-
-	seq_printf(s, "Interrupt Counters:\n");
-	seq_printf(s,
-		"INT_SPURIOUS \t%8u\n" "INT_CMD_DONE \t%8u\n"
-		"INT_CMD_ERR  \t%8u\n" "INT_WAKE_RX  \t%8u\n"
-		"INT_SS_ERROR \t%8u\n" "INT_S0IX_MISS\t%8u\n"
-		"INT_NO_ACKC6 \t%8u\n" "INT_INVALID  \t%8u\n",
-		pmu_irq_stats[INT_SPURIOUS], pmu_irq_stats[INT_CMD_DONE],
-		pmu_irq_stats[INT_CMD_ERR], pmu_irq_stats[INT_WAKE_RX],
-		pmu_irq_stats[INT_SS_ERROR], pmu_irq_stats[INT_S0IX_MISS],
-		pmu_irq_stats[INT_NO_ACKC6], pmu_irq_stats[INT_INVALID]);
-
-	seq_printf(s, "mrst_pmu_wait_ready_calls          %8d\n",
-			pmu_wait_ready_calls);
-	seq_printf(s, "mrst_pmu_wait_ready_udelays        %8d\n",
-			pmu_wait_ready_udelays);
-	seq_printf(s, "mrst_pmu_wait_ready_udelays_max    %8d\n",
-			pmu_wait_ready_udelays_max);
-	seq_printf(s, "mrst_pmu_wait_done_calls           %8d\n",
-			pmu_wait_done_calls);
-	seq_printf(s, "mrst_pmu_wait_done_udelays         %8d\n",
-			pmu_wait_done_udelays);
-	seq_printf(s, "mrst_pmu_wait_done_udelays_max     %8d\n",
-			pmu_wait_done_udelays_max);
-	seq_printf(s, "mrst_pmu_set_power_state_entry     %8d\n",
-			pmu_set_power_state_entry);
-	seq_printf(s, "mrst_pmu_set_power_state_send_cmd  %8d\n",
-			pmu_set_power_state_send_cmd);
-	seq_printf(s, "SCU busy: %d\n", pmu_read_busy_status());
-
-	return 0;
-}
-
-static int debug_mrst_pmu_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, debug_mrst_pmu_show, NULL);
-}
-
-static const struct file_operations devices_state_operations = {
-	.open		= debug_mrst_pmu_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-#endif	/* DEBUG_FS */
-
-/*
- * Validate SCU PCI shim PCI vendor capability byte
- * against LSS hard-coded in mrst_devs[] above.
- * DEBUG only.
- */
-static void pmu_scu_firmware_debug(void)
-{
-	struct pci_dev *pdev = NULL;
-
-	for_each_pci_dev(pdev) {
-		struct mrst_device *mrst_dev;
-		u8 pci_config_lss;
-		int pos;
-
-		mrst_dev = pci_id_2_mrst_dev(pdev->device);
-		if (unlikely(!mrst_dev)) {
-			printk(KERN_ERR FW_BUG "pmu: Unknown "
-				"PCI device 0x%04X\n", pdev->device);
-			continue;
-		}
-
-		if (mrst_dev->lss == 0)
-			continue;	 /* no LSS in our table */
-
-		pos = pci_find_capability(pdev, PCI_CAP_ID_VNDR);
-		if (!pos != 0) {
-			printk(KERN_ERR FW_BUG "pmu: 0x%04X "
-				"missing PCI Vendor Capability\n",
-				pdev->device);
-			continue;
-		}
-		pci_read_config_byte(pdev, pos + 4, &pci_config_lss);
-		if (!(pci_config_lss & PCI_VENDOR_CAP_LOG_SS_MASK)) {
-			printk(KERN_ERR FW_BUG "pmu: 0x%04X "
-				"invalid PCI Vendor Capability 0x%x "
-				" expected LSS 0x%X\n",
-				pdev->device, pci_config_lss, mrst_dev->lss);
-			continue;
-		}
-		pci_config_lss &= PCI_VENDOR_CAP_LOG_ID_MASK;
-
-		if (mrst_dev->lss == pci_config_lss)
-			continue;
-
-		printk(KERN_ERR FW_BUG "pmu: 0x%04X LSS = %d, expected %d\n",
-			pdev->device, pci_config_lss, mrst_dev->lss);
-	}
-}
-
-/**
- * pmu_probe
- */
-static int __devinit pmu_probe(struct pci_dev *pdev,
-				   const struct pci_device_id *pci_id)
-{
-	int ret;
-	struct mrst_pmu_reg *pmu;
-
-	/* Init the device */
-	ret = pci_enable_device(pdev);
-	if (ret) {
-		dev_err(&pdev->dev, "Unable to Enable PCI device\n");
-		return ret;
-	}
-
-	ret = pci_request_regions(pdev, MRST_PMU_DRV_NAME);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
-		goto out_err1;
-	}
-
-	/* Map the memory of PMU reg base */
-	pmu = pci_iomap(pdev, 0, 0);
-	if (!pmu) {
-		dev_err(&pdev->dev, "Unable to map the PMU address space\n");
-		ret = -ENOMEM;
-		goto out_err2;
-	}
-
-#ifdef CONFIG_DEBUG_FS
-	/* /sys/kernel/debug/mrst_pmu */
-	(void) debugfs_create_file("mrst_pmu", S_IFREG | S_IRUGO,
-				NULL, NULL, &devices_state_operations);
-#endif
-	pmu_reg = pmu;	/* success */
-
-	if (request_irq(pdev->irq, pmu_irq, 0, MRST_PMU_DRV_NAME, NULL)) {
-		dev_err(&pdev->dev, "Registering isr has failed\n");
-		ret = -1;
-		goto out_err3;
-	}
-
-	pmu_scu_firmware_debug();
-
-	pmu_write_wkc(S0I3_WAKE_SOURCES);	/* Enable S0i3 wakeup sources */
-
-	pmu_wait_ready();
-
-	pmu_write_ssc(D0I1_ACG_SSS_TARGET);	/* Enable Auto-Clock_Gating */
-	pmu_write_cmd(0x201);
-
-	spin_lock_init(&mrst_pmu_power_state_lock);
-
-	/* Enable the hardware interrupt */
-	pmu_irq_enable();
-	return 0;
-
-out_err3:
-	free_irq(pdev->irq, NULL);
-	pci_iounmap(pdev, pmu_reg);
-	pmu_reg = NULL;
-out_err2:
-	pci_release_region(pdev, 0);
-out_err1:
-	pci_disable_device(pdev);
-	return ret;
-}
-
-static void __devexit pmu_remove(struct pci_dev *pdev)
-{
-	dev_err(&pdev->dev, "Mid PM pmu_remove called\n");
-
-	/* Freeing up the irq */
-	free_irq(pdev->irq, NULL);
-
-	pci_iounmap(pdev, pmu_reg);
-	pmu_reg = NULL;
-
-	/* disable the current PCI device */
-	pci_release_region(pdev, 0);
-	pci_disable_device(pdev);
-}
-
-static DEFINE_PCI_DEVICE_TABLE(pmu_pci_ids) = {
-	{ PCI_VDEVICE(INTEL, PCI_DEV_ID_MRST_PMU), 0 },
-	{ }
-};
-
-MODULE_DEVICE_TABLE(pci, pmu_pci_ids);
-
-static struct pci_driver driver = {
-	.name = MRST_PMU_DRV_NAME,
-	.id_table = pmu_pci_ids,
-	.probe = pmu_probe,
-	.remove = __devexit_p(pmu_remove),
-};
-
-/**
- * pmu_pci_register - register the PMU driver as PCI device
- */
-static int __init pmu_pci_register(void)
-{
-	return pci_register_driver(&driver);
-}
-
-/* Register and probe via fs_initcall() to preceed device_initcall() */
-fs_initcall(pmu_pci_register);
-
-static void __exit mid_pci_cleanup(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-static int ia_major;
-static int ia_minor;
-
-static int pmu_sfi_parse_oem(struct sfi_table_header *table)
-{
-	struct sfi_table_simple *sb;
-
-	sb = (struct sfi_table_simple *)table;
-	ia_major = (sb->pentry[1] >> 0) & 0xFFFF;
-	ia_minor = (sb->pentry[1] >> 16) & 0xFFFF;
-	printk(KERN_INFO "mrst_pmu: IA FW version v%x.%x\n",
-		ia_major, ia_minor);
-
-	return 0;
-}
-
-static int __init scu_fw_check(void)
-{
-	int ret;
-	u32 fw_version;
-
-	if (!pmu_reg)
-		return 0;	/* this driver didn't probe-out */
-
-	sfi_table_parse("OEMB", NULL, NULL, pmu_sfi_parse_oem);
-
-	if (ia_major < 0x6005 || ia_minor < 0x1525) {
-		WARN(1, "mrst_pmu: IA FW version too old\n");
-		return -1;
-	}
-
-	ret = intel_scu_ipc_command(IPCMSG_FW_REVISION, 0, NULL, 0,
-					&fw_version, 1);
-
-	if (ret) {
-		WARN(1, "mrst_pmu: IPC FW version? %d\n", ret);
-	} else {
-		int scu_major = (fw_version >> 8) & 0xFF;
-		int scu_minor = (fw_version >> 0) & 0xFF;
-
-		printk(KERN_INFO "mrst_pmu: firmware v%x\n", fw_version);
-
-		if ((scu_major >= 0xC0) && (scu_minor >= 0x49)) {
-			printk(KERN_INFO "mrst_pmu: enabling S0i3\n");
-			mrst_pmu_s0i3_enable = true;
-		} else {
-			WARN(1, "mrst_pmu: S0i3 disabled, old firmware %X.%X",
-					scu_major, scu_minor);
-		}
-	}
-	return 0;
-}
-late_initcall(scu_fw_check);
-module_exit(mid_pci_cleanup);
diff --git a/arch/x86/platform/mrst/pmu.h b/arch/x86/platform/mrst/pmu.h
deleted file mode 100644
index bfbfe64..0000000
--- a/arch/x86/platform/mrst/pmu.h
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * mrst/pmu.h - private definitions for MRST Power Management Unit mrst/pmu.c
- *
- * Copyright (c) 2011, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * 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 _MRST_PMU_H_
-#define _MRST_PMU_H_
-
-#define PCI_DEV_ID_MRST_PMU		0x0810
-#define MRST_PMU_DRV_NAME		"mrst_pmu"
-#define	PCI_SUB_CLASS_MASK		0xFF00
-
-#define	PCI_VENDOR_CAP_LOG_ID_MASK	0x7F
-#define PCI_VENDOR_CAP_LOG_SS_MASK	0x80
-
-#define SUB_SYS_ALL_D0I1	0x01155555
-#define S0I3_WAKE_SOURCES	0x00001FFF
-
-#define PM_S0I3_COMMAND					\
-	((0 << 31) |	/* Reserved */			\
-	(0 << 30) |	/* Core must be idle */		\
-	(0xc2 << 22) |	/* ACK C6 trigger */		\
-	(3 << 19) |	/* Trigger on DMI message */	\
-	(3 << 16) |	/* Enter S0i3 */		\
-	(0 << 13) |	/* Numeric mode ID (sw) */	\
-	(3 << 9) |	/* Trigger mode */		\
-	(0 << 8) |	/* Do not interrupt */		\
-	(1 << 0))	/* Set configuration */
-
-#define	LSS_DMI		0
-#define	LSS_SD_HC0	1
-#define	LSS_SD_HC1	2
-#define	LSS_NAND	3
-#define	LSS_IMAGING	4
-#define	LSS_SECURITY	5
-#define	LSS_DISPLAY	6
-#define	LSS_USB_HC	7
-#define	LSS_USB_OTG	8
-#define	LSS_AUDIO	9
-#define	LSS_AUDIO_LPE	9
-#define	LSS_AUDIO_SSP	9
-#define	LSS_I2C0	10
-#define	LSS_I2C1	10
-#define	LSS_I2C2	10
-#define	LSS_KBD		10
-#define	LSS_SPI0	10
-#define	LSS_SPI1	10
-#define	LSS_SPI2	10
-#define	LSS_GPIO	10
-#define	LSS_SRAM	11	/* used by SCU, do not touch */
-#define	LSS_SD_HC2	12
-/* LSS hardware bits 15,14,13 are hardwired to 0, thus unusable */
-#define MRST_NUM_LSS	13
-
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-
-#define	SSMSK(mask, lss) ((mask) << ((lss) * 2))
-#define	D0	0
-#define	D0i1	1
-#define	D0i2	2
-#define	D0i3	3
-
-#define S0I3_SSS_TARGET	(		\
-	SSMSK(D0i1, LSS_DMI) |		\
-	SSMSK(D0i3, LSS_SD_HC0) |	\
-	SSMSK(D0i3, LSS_SD_HC1) |	\
-	SSMSK(D0i3, LSS_NAND) |		\
-	SSMSK(D0i3, LSS_SD_HC2) |	\
-	SSMSK(D0i3, LSS_IMAGING) |	\
-	SSMSK(D0i3, LSS_SECURITY) |	\
-	SSMSK(D0i3, LSS_DISPLAY) |	\
-	SSMSK(D0i3, LSS_USB_HC) |	\
-	SSMSK(D0i3, LSS_USB_OTG) |	\
-	SSMSK(D0i3, LSS_AUDIO) |	\
-	SSMSK(D0i1, LSS_I2C0))
-
-/*
- * D0i1 on Langwell is Autonomous Clock Gating (ACG).
- * Enable ACG on every LSS except camera and audio
- */
-#define D0I1_ACG_SSS_TARGET	 \
-	(SUB_SYS_ALL_D0I1 & ~SSMSK(D0i1, LSS_IMAGING) & ~SSMSK(D0i1, LSS_AUDIO))
-
-enum cm_mode {
-	CM_NOP,			/* ignore the config mode value */
-	CM_IMMEDIATE,
-	CM_DELAY,
-	CM_TRIGGER,
-	CM_INVALID
-};
-
-enum sys_state {
-	SYS_STATE_S0I0,
-	SYS_STATE_S0I1,
-	SYS_STATE_S0I2,
-	SYS_STATE_S0I3,
-	SYS_STATE_S3,
-	SYS_STATE_S5
-};
-
-#define SET_CFG_CMD	1
-
-enum int_status {
-	INT_SPURIOUS = 0,
-	INT_CMD_DONE = 1,
-	INT_CMD_ERR = 2,
-	INT_WAKE_RX = 3,
-	INT_SS_ERROR = 4,
-	INT_S0IX_MISS = 5,
-	INT_NO_ACKC6 = 6,
-	INT_INVALID = 7,
-};
-
-/* PMU register interface */
-static struct mrst_pmu_reg {
-	u32 pm_sts;		/* 0x00 */
-	u32 pm_cmd;		/* 0x04 */
-	u32 pm_ics;		/* 0x08 */
-	u32 _resv1;		/* 0x0C */
-	u32 pm_wkc[2];		/* 0x10 */
-	u32 pm_wks[2];		/* 0x18 */
-	u32 pm_ssc[4];		/* 0x20 */
-	u32 pm_sss[4];		/* 0x30 */
-	u32 pm_wssc[4];		/* 0x40 */
-	u32 pm_c3c4;		/* 0x50 */
-	u32 pm_c5c6;		/* 0x54 */
-	u32 pm_msi_disable;	/* 0x58 */
-} *pmu_reg;
-
-static inline u32 pmu_read_sts(void) { return readl(&pmu_reg->pm_sts); }
-static inline u32 pmu_read_ics(void) { return readl(&pmu_reg->pm_ics); }
-static inline u32 pmu_read_wks(void) { return readl(&pmu_reg->pm_wks[0]); }
-static inline u32 pmu_read_sss(void) { return readl(&pmu_reg->pm_sss[0]); }
-
-static inline void pmu_write_cmd(u32 arg) { writel(arg, &pmu_reg->pm_cmd); }
-static inline void pmu_write_ics(u32 arg) { writel(arg, &pmu_reg->pm_ics); }
-static inline void pmu_write_wkc(u32 arg) { writel(arg, &pmu_reg->pm_wkc[0]); }
-static inline void pmu_write_ssc(u32 arg) { writel(arg, &pmu_reg->pm_ssc[0]); }
-static inline void pmu_write_wssc(u32 arg)
-					{ writel(arg, &pmu_reg->pm_wssc[0]); }
-
-static inline void pmu_msi_enable(void) { writel(0, &pmu_reg->pm_msi_disable); }
-static inline u32 pmu_msi_is_disabled(void)
-				{ return readl(&pmu_reg->pm_msi_disable); }
-
-union pmu_pm_ics {
-	struct {
-		u32 cause:8;
-		u32 enable:1;
-		u32 pending:1;
-		u32 reserved:22;
-	} bits;
-	u32 value;
-};
-
-static inline void pmu_irq_enable(void)
-{
-	union pmu_pm_ics pmu_ics;
-
-	pmu_ics.value = pmu_read_ics();
-	pmu_ics.bits.enable = 1;
-	pmu_write_ics(pmu_ics.value);
-}
-
-union pmu_pm_status {
-	struct {
-		u32 pmu_rev:8;
-		u32 pmu_busy:1;
-		u32 mode_id:4;
-		u32 Reserved:19;
-	} pmu_status_parts;
-	u32 pmu_status_value;
-};
-
-static inline int pmu_read_busy_status(void)
-{
-	union pmu_pm_status result;
-
-	result.pmu_status_value = pmu_read_sts();
-
-	return result.pmu_status_parts.pmu_busy;
-}
-
-/* pmu set config parameters */
-struct cfg_delay_param_t {
-	u32 cmd:8;
-	u32 ioc:1;
-	u32 cfg_mode:4;
-	u32 mode_id:3;
-	u32 sys_state:3;
-	u32 cfg_delay:8;
-	u32 rsvd:5;
-};
-
-struct cfg_trig_param_t {
-	u32 cmd:8;
-	u32 ioc:1;
-	u32 cfg_mode:4;
-	u32 mode_id:3;
-	u32 sys_state:3;
-	u32 cfg_trig_type:3;
-	u32 cfg_trig_val:8;
-	u32 cmbi:1;
-	u32 rsvd1:1;
-};
-
-union pmu_pm_set_cfg_cmd_t {
-	union {
-		struct cfg_delay_param_t d_param;
-		struct cfg_trig_param_t t_param;
-	} pmu2_params;
-	u32 pmu_pm_set_cfg_cmd_value;
-};
-
-#ifdef FUTURE_PATCH
-extern int mrst_s0i3_entry(u32 regval, u32 *regaddr);
-#else
-static inline int mrst_s0i3_entry(u32 regval, u32 *regaddr) { return -1; }
-#endif
-#endif
diff --git a/arch/x86/platform/olpc/olpc-xo15-sci.c b/arch/x86/platform/olpc/olpc-xo15-sci.c
index 2b235b7..23e5b9d 100644
--- a/arch/x86/platform/olpc/olpc-xo15-sci.c
+++ b/arch/x86/platform/olpc/olpc-xo15-sci.c
@@ -23,7 +23,66 @@
 #define XO15_SCI_CLASS			DRV_NAME
 #define XO15_SCI_DEVICE_NAME		"OLPC XO-1.5 SCI"
 
-static unsigned long xo15_sci_gpe;
+static unsigned long			xo15_sci_gpe;
+static bool				lid_wake_on_close;
+
+/*
+ * The normal ACPI LID wakeup behavior is wake-on-open, but not
+ * wake-on-close. This is implemented as standard by the XO-1.5 DSDT.
+ *
+ * We provide here a sysfs attribute that will additionally enable
+ * wake-on-close behavior. This is useful (e.g.) when we oportunistically
+ * suspend with the display running; if the lid is then closed, we want to
+ * wake up to turn the display off.
+ *
+ * This is controlled through a custom method in the XO-1.5 DSDT.
+ */
+static int set_lid_wake_behavior(bool wake_on_close)
+{
+	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	= wake_on_close;
+
+	status = acpi_evaluate_object(NULL, "\\_SB.PCI0.LID.LIDW", &arg_list, NULL);
+	if (ACPI_FAILURE(status)) {
+		pr_warning(PFX "failed to set lid behavior\n");
+		return 1;
+	}
+
+	lid_wake_on_close = wake_on_close;
+
+	return 0;
+}
+
+static ssize_t
+lid_wake_on_close_show(struct kobject *s, struct kobj_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%u\n", lid_wake_on_close);
+}
+
+static ssize_t lid_wake_on_close_store(struct kobject *s,
+				       struct kobj_attribute *attr,
+				       const char *buf, size_t n)
+{
+	unsigned int val;
+
+	if (sscanf(buf, "%u", &val) != 1)
+		return -EINVAL;
+
+	set_lid_wake_behavior(!!val);
+
+	return n;
+}
+
+static struct kobj_attribute lid_wake_on_close_attr =
+	__ATTR(lid_wake_on_close, 0644,
+	       lid_wake_on_close_show,
+	       lid_wake_on_close_store);
 
 static void battery_status_changed(void)
 {
@@ -91,6 +150,7 @@
 {
 	unsigned long long tmp;
 	acpi_status status;
+	int r;
 
 	if (!device)
 		return -EINVAL;
@@ -112,6 +172,10 @@
 
 	dev_info(&device->dev, "Initialized, GPE = 0x%lx\n", xo15_sci_gpe);
 
+	r = sysfs_create_file(&device->dev.kobj, &lid_wake_on_close_attr.attr);
+	if (r)
+		goto err_sysfs;
+
 	/* Flush queue, and enable all SCI events */
 	process_sci_queue();
 	olpc_ec_mask_write(EC_SCI_SRC_ALL);
@@ -123,6 +187,11 @@
 		device_init_wakeup(&device->dev, true);
 
 	return 0;
+
+err_sysfs:
+	acpi_remove_gpe_handler(NULL, xo15_sci_gpe, xo15_sci_gpe_handler);
+	cancel_work_sync(&sci_work);
+	return r;
 }
 
 static int xo15_sci_remove(struct acpi_device *device, int type)
@@ -130,6 +199,7 @@
 	acpi_disable_gpe(NULL, xo15_sci_gpe);
 	acpi_remove_gpe_handler(NULL, xo15_sci_gpe, xo15_sci_gpe_handler);
 	cancel_work_sync(&sci_work);
+	sysfs_remove_file(&device->dev.kobj, &lid_wake_on_close_attr.attr);
 	return 0;
 }
 
diff --git a/arch/x86/platform/olpc/olpc.c b/arch/x86/platform/olpc/olpc.c
index 7cce722..a4bee53 100644
--- a/arch/x86/platform/olpc/olpc.c
+++ b/arch/x86/platform/olpc/olpc.c
@@ -20,6 +20,8 @@
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/syscore_ops.h>
+#include <linux/debugfs.h>
+#include <linux/mutex.h>
 
 #include <asm/geode.h>
 #include <asm/setup.h>
@@ -31,6 +33,15 @@
 
 static DEFINE_SPINLOCK(ec_lock);
 
+/* debugfs interface to EC commands */
+#define EC_MAX_CMD_ARGS (5 + 1)	/* cmd byte + 5 args */
+#define EC_MAX_CMD_REPLY (8)
+
+static struct dentry *ec_debugfs_dir;
+static DEFINE_MUTEX(ec_debugfs_cmd_lock);
+static unsigned char ec_debugfs_resp[EC_MAX_CMD_REPLY];
+static unsigned int ec_debugfs_resp_bytes;
+
 /* EC event mask to be applied during suspend (defining wakeup sources). */
 static u16 ec_wakeup_mask;
 
@@ -269,6 +280,91 @@
 }
 EXPORT_SYMBOL_GPL(olpc_ec_sci_query);
 
+static ssize_t ec_debugfs_cmd_write(struct file *file, const char __user *buf,
+				    size_t size, loff_t *ppos)
+{
+	int i, m;
+	unsigned char ec_cmd[EC_MAX_CMD_ARGS];
+	unsigned int ec_cmd_int[EC_MAX_CMD_ARGS];
+	char cmdbuf[64];
+	int ec_cmd_bytes;
+
+	mutex_lock(&ec_debugfs_cmd_lock);
+
+	size = simple_write_to_buffer(cmdbuf, sizeof(cmdbuf), ppos, buf, size);
+
+	m = sscanf(cmdbuf, "%x:%u %x %x %x %x %x", &ec_cmd_int[0],
+		   &ec_debugfs_resp_bytes,
+		   &ec_cmd_int[1], &ec_cmd_int[2], &ec_cmd_int[3],
+		   &ec_cmd_int[4], &ec_cmd_int[5]);
+	if (m < 2 || ec_debugfs_resp_bytes > EC_MAX_CMD_REPLY) {
+		/* reset to prevent overflow on read */
+		ec_debugfs_resp_bytes = 0;
+
+		printk(KERN_DEBUG "olpc-ec: bad ec cmd:  "
+		       "cmd:response-count [arg1 [arg2 ...]]\n");
+		size = -EINVAL;
+		goto out;
+	}
+
+	/* convert scanf'd ints to char */
+	ec_cmd_bytes = m - 2;
+	for (i = 0; i <= ec_cmd_bytes; i++)
+		ec_cmd[i] = ec_cmd_int[i];
+
+	printk(KERN_DEBUG "olpc-ec: debugfs cmd 0x%02x with %d args "
+	       "%02x %02x %02x %02x %02x, want %d returns\n",
+	       ec_cmd[0], ec_cmd_bytes, ec_cmd[1], ec_cmd[2], ec_cmd[3],
+	       ec_cmd[4], ec_cmd[5], ec_debugfs_resp_bytes);
+
+	olpc_ec_cmd(ec_cmd[0], (ec_cmd_bytes == 0) ? NULL : &ec_cmd[1],
+		    ec_cmd_bytes, ec_debugfs_resp, ec_debugfs_resp_bytes);
+
+	printk(KERN_DEBUG "olpc-ec: response "
+	       "%02x %02x %02x %02x %02x %02x %02x %02x (%d bytes expected)\n",
+	       ec_debugfs_resp[0], ec_debugfs_resp[1], ec_debugfs_resp[2],
+	       ec_debugfs_resp[3], ec_debugfs_resp[4], ec_debugfs_resp[5],
+	       ec_debugfs_resp[6], ec_debugfs_resp[7], ec_debugfs_resp_bytes);
+
+out:
+	mutex_unlock(&ec_debugfs_cmd_lock);
+	return size;
+}
+
+static ssize_t ec_debugfs_cmd_read(struct file *file, char __user *buf,
+				   size_t size, loff_t *ppos)
+{
+	unsigned int i, r;
+	char *rp;
+	char respbuf[64];
+
+	mutex_lock(&ec_debugfs_cmd_lock);
+	rp = respbuf;
+	rp += sprintf(rp, "%02x", ec_debugfs_resp[0]);
+	for (i = 1; i < ec_debugfs_resp_bytes; i++)
+		rp += sprintf(rp, ", %02x", ec_debugfs_resp[i]);
+	mutex_unlock(&ec_debugfs_cmd_lock);
+	rp += sprintf(rp, "\n");
+
+	r = rp - respbuf;
+	return simple_read_from_buffer(buf, size, ppos, respbuf, r);
+}
+
+static const struct file_operations ec_debugfs_genops = {
+	.write	 = ec_debugfs_cmd_write,
+	.read	 = ec_debugfs_cmd_read,
+};
+
+static void setup_debugfs(void)
+{
+	ec_debugfs_dir = debugfs_create_dir("olpc-ec", 0);
+	if (ec_debugfs_dir == ERR_PTR(-ENODEV))
+		return;
+
+	debugfs_create_file("cmd", 0600, ec_debugfs_dir, NULL,
+			    &ec_debugfs_genops);
+}
+
 static int olpc_ec_suspend(void)
 {
 	return olpc_ec_mask_write(ec_wakeup_mask);
@@ -372,6 +468,7 @@
 	}
 
 	register_syscore_ops(&olpc_syscore_ops);
+	setup_debugfs();
 
 	return 0;
 }
diff --git a/arch/x86/platform/uv/uv_time.c b/arch/x86/platform/uv/uv_time.c
index 9f29a01..5032e0d 100644
--- a/arch/x86/platform/uv/uv_time.c
+++ b/arch/x86/platform/uv/uv_time.c
@@ -37,7 +37,7 @@
 
 static struct clocksource clocksource_uv = {
 	.name		= RTC_NAME,
-	.rating		= 400,
+	.rating		= 299,
 	.read		= uv_read_rtc,
 	.mask		= (cycle_t)UVH_RTC_REAL_TIME_CLOCK_MASK,
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
@@ -379,10 +379,6 @@
 	if (!is_uv_system())
 		return -ENODEV;
 
-	/* If single blade, prefer tsc */
-	if (uv_num_possible_blades() == 1)
-		clocksource_uv.rating = 250;
-
 	rc = clocksource_register_hz(&clocksource_uv, sn_rtc_cycles_per_second);
 	if (rc)
 		printk(KERN_INFO "UV RTC clocksource failed rc %d\n", rc);
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index f10c0af..218cdb1 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -20,6 +20,7 @@
 #include <asm/xcr.h>
 #include <asm/suspend.h>
 #include <asm/debugreg.h>
+#include <asm/fpu-internal.h> /* pcntxt_mask */
 
 #ifdef CONFIG_X86_32
 static struct saved_context saved_context;
@@ -114,7 +115,7 @@
 void save_processor_state(void)
 {
 	__save_processor_state(&saved_context);
-	save_sched_clock_state();
+	x86_platform.save_sched_clock_state();
 }
 #ifdef CONFIG_X86_32
 EXPORT_SYMBOL(save_processor_state);
@@ -224,6 +225,7 @@
 	fix_processor_context();
 
 	do_fpu_end();
+	x86_platform.restore_sched_clock_state();
 	mtrr_bp_restore();
 }
 
@@ -231,7 +233,6 @@
 void restore_processor_state(void)
 {
 	__restore_processor_state(&saved_context);
-	restore_sched_clock_state();
 }
 #ifdef CONFIG_X86_32
 EXPORT_SYMBOL(restore_processor_state);
diff --git a/arch/x86/power/hibernate_32.c b/arch/x86/power/hibernate_32.c
index 3769079..74202c1 100644
--- a/arch/x86/power/hibernate_32.c
+++ b/arch/x86/power/hibernate_32.c
@@ -10,7 +10,6 @@
 #include <linux/suspend.h>
 #include <linux/bootmem.h>
 
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/mmzone.h>
diff --git a/arch/x86/syscalls/Makefile b/arch/x86/syscalls/Makefile
index 564b247..3236aeb 100644
--- a/arch/x86/syscalls/Makefile
+++ b/arch/x86/syscalls/Makefile
@@ -10,8 +10,10 @@
 systbl := $(srctree)/$(src)/syscalltbl.sh
 
 quiet_cmd_syshdr = SYSHDR  $@
-      cmd_syshdr = $(CONFIG_SHELL) '$(syshdr)' $< $@ \
-		   $(syshdr_abi_$(basetarget)) $(syshdr_pfx_$(basetarget))
+      cmd_syshdr = $(CONFIG_SHELL) '$(syshdr)' '$<' '$@' \
+		   '$(syshdr_abi_$(basetarget))' \
+		   '$(syshdr_pfx_$(basetarget))' \
+		   '$(syshdr_offset_$(basetarget))'
 quiet_cmd_systbl = SYSTBL  $@
       cmd_systbl = $(CONFIG_SHELL) '$(systbl)' $< $@
 
@@ -24,18 +26,28 @@
 $(out)/unistd_32_ia32.h: $(syscall32) $(syshdr)
 	$(call if_changed,syshdr)
 
-syshdr_abi_unistd_64 := 64
+syshdr_abi_unistd_x32 := common,x32
+syshdr_offset_unistd_x32 := __X32_SYSCALL_BIT
+$(out)/unistd_x32.h: $(syscall64) $(syshdr)
+	$(call if_changed,syshdr)
+
+syshdr_abi_unistd_64 := common,64
 $(out)/unistd_64.h: $(syscall64) $(syshdr)
 	$(call if_changed,syshdr)
 
+syshdr_abi_unistd_64_x32 := x32
+syshdr_pfx_unistd_64_x32 := x32_
+$(out)/unistd_64_x32.h: $(syscall64) $(syshdr)
+	$(call if_changed,syshdr)
+
 $(out)/syscalls_32.h: $(syscall32) $(systbl)
 	$(call if_changed,systbl)
 $(out)/syscalls_64.h: $(syscall64) $(systbl)
 	$(call if_changed,systbl)
 
-syshdr-y			+= unistd_32.h unistd_64.h
+syshdr-y			+= unistd_32.h unistd_64.h unistd_x32.h
 syshdr-y			+= syscalls_32.h
-syshdr-$(CONFIG_X86_64)		+= unistd_32_ia32.h
+syshdr-$(CONFIG_X86_64)		+= unistd_32_ia32.h unistd_64_x32.h
 syshdr-$(CONFIG_X86_64)		+= syscalls_64.h
 
 targets	+= $(syshdr-y)
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl
index ce98e28..29f9f05 100644
--- a/arch/x86/syscalls/syscall_32.tbl
+++ b/arch/x86/syscalls/syscall_32.tbl
@@ -181,7 +181,7 @@
 172	i386	prctl			sys_prctl
 173	i386	rt_sigreturn		ptregs_rt_sigreturn		stub32_rt_sigreturn
 174	i386	rt_sigaction		sys_rt_sigaction		sys32_rt_sigaction
-175	i386	rt_sigprocmask		sys_rt_sigprocmask		sys32_rt_sigprocmask
+175	i386	rt_sigprocmask		sys_rt_sigprocmask
 176	i386	rt_sigpending		sys_rt_sigpending		sys32_rt_sigpending
 177	i386	rt_sigtimedwait		sys_rt_sigtimedwait		compat_sys_rt_sigtimedwait
 178	i386	rt_sigqueueinfo		sys_rt_sigqueueinfo		sys32_rt_sigqueueinfo
@@ -288,7 +288,7 @@
 279	i386	mq_timedsend		sys_mq_timedsend		compat_sys_mq_timedsend
 280	i386	mq_timedreceive		sys_mq_timedreceive		compat_sys_mq_timedreceive
 281	i386	mq_notify		sys_mq_notify			compat_sys_mq_notify
-282	i386	mq_getsetaddr		sys_mq_getsetattr		compat_sys_mq_getsetattr
+282	i386	mq_getsetattr		sys_mq_getsetattr		compat_sys_mq_getsetattr
 283	i386	kexec_load		sys_kexec_load			compat_sys_kexec_load
 284	i386	waitid			sys_waitid			compat_sys_waitid
 # 285 sys_setaltroot
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl
index b440a8f..dd29a9e 100644
--- a/arch/x86/syscalls/syscall_64.tbl
+++ b/arch/x86/syscalls/syscall_64.tbl
@@ -4,317 +4,350 @@
 # The format is:
 # <number> <abi> <name> <entry point>
 #
-# The abi is always "64" for this file (for now.)
+# The abi is "common", "64" or "x32" for this file.
 #
-0	64	read			sys_read
-1	64	write			sys_write
-2	64	open			sys_open
-3	64	close			sys_close
-4	64	stat			sys_newstat
-5	64	fstat			sys_newfstat
-6	64	lstat			sys_newlstat
-7	64	poll			sys_poll
-8	64	lseek			sys_lseek
-9	64	mmap			sys_mmap
-10	64	mprotect		sys_mprotect
-11	64	munmap			sys_munmap
-12	64	brk			sys_brk
+0	common	read			sys_read
+1	common	write			sys_write
+2	common	open			sys_open
+3	common	close			sys_close
+4	common	stat			sys_newstat
+5	common	fstat			sys_newfstat
+6	common	lstat			sys_newlstat
+7	common	poll			sys_poll
+8	common	lseek			sys_lseek
+9	common	mmap			sys_mmap
+10	common	mprotect		sys_mprotect
+11	common	munmap			sys_munmap
+12	common	brk			sys_brk
 13	64	rt_sigaction		sys_rt_sigaction
-14	64	rt_sigprocmask		sys_rt_sigprocmask
+14	common	rt_sigprocmask		sys_rt_sigprocmask
 15	64	rt_sigreturn		stub_rt_sigreturn
 16	64	ioctl			sys_ioctl
-17	64	pread64			sys_pread64
-18	64	pwrite64		sys_pwrite64
+17	common	pread64			sys_pread64
+18	common	pwrite64		sys_pwrite64
 19	64	readv			sys_readv
 20	64	writev			sys_writev
-21	64	access			sys_access
-22	64	pipe			sys_pipe
-23	64	select			sys_select
-24	64	sched_yield		sys_sched_yield
-25	64	mremap			sys_mremap
-26	64	msync			sys_msync
-27	64	mincore			sys_mincore
-28	64	madvise			sys_madvise
-29	64	shmget			sys_shmget
-30	64	shmat			sys_shmat
-31	64	shmctl			sys_shmctl
-32	64	dup			sys_dup
-33	64	dup2			sys_dup2
-34	64	pause			sys_pause
-35	64	nanosleep		sys_nanosleep
-36	64	getitimer		sys_getitimer
-37	64	alarm			sys_alarm
-38	64	setitimer		sys_setitimer
-39	64	getpid			sys_getpid
-40	64	sendfile		sys_sendfile64
-41	64	socket			sys_socket
-42	64	connect			sys_connect
-43	64	accept			sys_accept
-44	64	sendto			sys_sendto
+21	common	access			sys_access
+22	common	pipe			sys_pipe
+23	common	select			sys_select
+24	common	sched_yield		sys_sched_yield
+25	common	mremap			sys_mremap
+26	common	msync			sys_msync
+27	common	mincore			sys_mincore
+28	common	madvise			sys_madvise
+29	common	shmget			sys_shmget
+30	common	shmat			sys_shmat
+31	common	shmctl			sys_shmctl
+32	common	dup			sys_dup
+33	common	dup2			sys_dup2
+34	common	pause			sys_pause
+35	common	nanosleep		sys_nanosleep
+36	common	getitimer		sys_getitimer
+37	common	alarm			sys_alarm
+38	common	setitimer		sys_setitimer
+39	common	getpid			sys_getpid
+40	common	sendfile		sys_sendfile64
+41	common	socket			sys_socket
+42	common	connect			sys_connect
+43	common	accept			sys_accept
+44	common	sendto			sys_sendto
 45	64	recvfrom		sys_recvfrom
 46	64	sendmsg			sys_sendmsg
 47	64	recvmsg			sys_recvmsg
-48	64	shutdown		sys_shutdown
-49	64	bind			sys_bind
-50	64	listen			sys_listen
-51	64	getsockname		sys_getsockname
-52	64	getpeername		sys_getpeername
-53	64	socketpair		sys_socketpair
-54	64	setsockopt		sys_setsockopt
-55	64	getsockopt		sys_getsockopt
-56	64	clone			stub_clone
-57	64	fork			stub_fork
-58	64	vfork			stub_vfork
+48	common	shutdown		sys_shutdown
+49	common	bind			sys_bind
+50	common	listen			sys_listen
+51	common	getsockname		sys_getsockname
+52	common	getpeername		sys_getpeername
+53	common	socketpair		sys_socketpair
+54	common	setsockopt		sys_setsockopt
+55	common	getsockopt		sys_getsockopt
+56	common	clone			stub_clone
+57	common	fork			stub_fork
+58	common	vfork			stub_vfork
 59	64	execve			stub_execve
-60	64	exit			sys_exit
-61	64	wait4			sys_wait4
-62	64	kill			sys_kill
-63	64	uname			sys_newuname
-64	64	semget			sys_semget
-65	64	semop			sys_semop
-66	64	semctl			sys_semctl
-67	64	shmdt			sys_shmdt
-68	64	msgget			sys_msgget
-69	64	msgsnd			sys_msgsnd
-70	64	msgrcv			sys_msgrcv
-71	64	msgctl			sys_msgctl
-72	64	fcntl			sys_fcntl
-73	64	flock			sys_flock
-74	64	fsync			sys_fsync
-75	64	fdatasync		sys_fdatasync
-76	64	truncate		sys_truncate
-77	64	ftruncate		sys_ftruncate
-78	64	getdents		sys_getdents
-79	64	getcwd			sys_getcwd
-80	64	chdir			sys_chdir
-81	64	fchdir			sys_fchdir
-82	64	rename			sys_rename
-83	64	mkdir			sys_mkdir
-84	64	rmdir			sys_rmdir
-85	64	creat			sys_creat
-86	64	link			sys_link
-87	64	unlink			sys_unlink
-88	64	symlink			sys_symlink
-89	64	readlink		sys_readlink
-90	64	chmod			sys_chmod
-91	64	fchmod			sys_fchmod
-92	64	chown			sys_chown
-93	64	fchown			sys_fchown
-94	64	lchown			sys_lchown
-95	64	umask			sys_umask
-96	64	gettimeofday		sys_gettimeofday
-97	64	getrlimit		sys_getrlimit
-98	64	getrusage		sys_getrusage
-99	64	sysinfo			sys_sysinfo
-100	64	times			sys_times
+60	common	exit			sys_exit
+61	common	wait4			sys_wait4
+62	common	kill			sys_kill
+63	common	uname			sys_newuname
+64	common	semget			sys_semget
+65	common	semop			sys_semop
+66	common	semctl			sys_semctl
+67	common	shmdt			sys_shmdt
+68	common	msgget			sys_msgget
+69	common	msgsnd			sys_msgsnd
+70	common	msgrcv			sys_msgrcv
+71	common	msgctl			sys_msgctl
+72	common	fcntl			sys_fcntl
+73	common	flock			sys_flock
+74	common	fsync			sys_fsync
+75	common	fdatasync		sys_fdatasync
+76	common	truncate		sys_truncate
+77	common	ftruncate		sys_ftruncate
+78	common	getdents		sys_getdents
+79	common	getcwd			sys_getcwd
+80	common	chdir			sys_chdir
+81	common	fchdir			sys_fchdir
+82	common	rename			sys_rename
+83	common	mkdir			sys_mkdir
+84	common	rmdir			sys_rmdir
+85	common	creat			sys_creat
+86	common	link			sys_link
+87	common	unlink			sys_unlink
+88	common	symlink			sys_symlink
+89	common	readlink		sys_readlink
+90	common	chmod			sys_chmod
+91	common	fchmod			sys_fchmod
+92	common	chown			sys_chown
+93	common	fchown			sys_fchown
+94	common	lchown			sys_lchown
+95	common	umask			sys_umask
+96	common	gettimeofday		sys_gettimeofday
+97	common	getrlimit		sys_getrlimit
+98	common	getrusage		sys_getrusage
+99	common	sysinfo			sys_sysinfo
+100	common	times			sys_times
 101	64	ptrace			sys_ptrace
-102	64	getuid			sys_getuid
-103	64	syslog			sys_syslog
-104	64	getgid			sys_getgid
-105	64	setuid			sys_setuid
-106	64	setgid			sys_setgid
-107	64	geteuid			sys_geteuid
-108	64	getegid			sys_getegid
-109	64	setpgid			sys_setpgid
-110	64	getppid			sys_getppid
-111	64	getpgrp			sys_getpgrp
-112	64	setsid			sys_setsid
-113	64	setreuid		sys_setreuid
-114	64	setregid		sys_setregid
-115	64	getgroups		sys_getgroups
-116	64	setgroups		sys_setgroups
-117	64	setresuid		sys_setresuid
-118	64	getresuid		sys_getresuid
-119	64	setresgid		sys_setresgid
-120	64	getresgid		sys_getresgid
-121	64	getpgid			sys_getpgid
-122	64	setfsuid		sys_setfsuid
-123	64	setfsgid		sys_setfsgid
-124	64	getsid			sys_getsid
-125	64	capget			sys_capget
-126	64	capset			sys_capset
+102	common	getuid			sys_getuid
+103	common	syslog			sys_syslog
+104	common	getgid			sys_getgid
+105	common	setuid			sys_setuid
+106	common	setgid			sys_setgid
+107	common	geteuid			sys_geteuid
+108	common	getegid			sys_getegid
+109	common	setpgid			sys_setpgid
+110	common	getppid			sys_getppid
+111	common	getpgrp			sys_getpgrp
+112	common	setsid			sys_setsid
+113	common	setreuid		sys_setreuid
+114	common	setregid		sys_setregid
+115	common	getgroups		sys_getgroups
+116	common	setgroups		sys_setgroups
+117	common	setresuid		sys_setresuid
+118	common	getresuid		sys_getresuid
+119	common	setresgid		sys_setresgid
+120	common	getresgid		sys_getresgid
+121	common	getpgid			sys_getpgid
+122	common	setfsuid		sys_setfsuid
+123	common	setfsgid		sys_setfsgid
+124	common	getsid			sys_getsid
+125	common	capget			sys_capget
+126	common	capset			sys_capset
 127	64	rt_sigpending		sys_rt_sigpending
 128	64	rt_sigtimedwait		sys_rt_sigtimedwait
 129	64	rt_sigqueueinfo		sys_rt_sigqueueinfo
-130	64	rt_sigsuspend		sys_rt_sigsuspend
+130	common	rt_sigsuspend		sys_rt_sigsuspend
 131	64	sigaltstack		stub_sigaltstack
-132	64	utime			sys_utime
-133	64	mknod			sys_mknod
+132	common	utime			sys_utime
+133	common	mknod			sys_mknod
 134	64	uselib
-135	64	personality		sys_personality
-136	64	ustat			sys_ustat
-137	64	statfs			sys_statfs
-138	64	fstatfs			sys_fstatfs
-139	64	sysfs			sys_sysfs
-140	64	getpriority		sys_getpriority
-141	64	setpriority		sys_setpriority
-142	64	sched_setparam		sys_sched_setparam
-143	64	sched_getparam		sys_sched_getparam
-144	64	sched_setscheduler	sys_sched_setscheduler
-145	64	sched_getscheduler	sys_sched_getscheduler
-146	64	sched_get_priority_max	sys_sched_get_priority_max
-147	64	sched_get_priority_min	sys_sched_get_priority_min
-148	64	sched_rr_get_interval	sys_sched_rr_get_interval
-149	64	mlock			sys_mlock
-150	64	munlock			sys_munlock
-151	64	mlockall		sys_mlockall
-152	64	munlockall		sys_munlockall
-153	64	vhangup			sys_vhangup
-154	64	modify_ldt		sys_modify_ldt
-155	64	pivot_root		sys_pivot_root
+135	common	personality		sys_personality
+136	common	ustat			sys_ustat
+137	common	statfs			sys_statfs
+138	common	fstatfs			sys_fstatfs
+139	common	sysfs			sys_sysfs
+140	common	getpriority		sys_getpriority
+141	common	setpriority		sys_setpriority
+142	common	sched_setparam		sys_sched_setparam
+143	common	sched_getparam		sys_sched_getparam
+144	common	sched_setscheduler	sys_sched_setscheduler
+145	common	sched_getscheduler	sys_sched_getscheduler
+146	common	sched_get_priority_max	sys_sched_get_priority_max
+147	common	sched_get_priority_min	sys_sched_get_priority_min
+148	common	sched_rr_get_interval	sys_sched_rr_get_interval
+149	common	mlock			sys_mlock
+150	common	munlock			sys_munlock
+151	common	mlockall		sys_mlockall
+152	common	munlockall		sys_munlockall
+153	common	vhangup			sys_vhangup
+154	common	modify_ldt		sys_modify_ldt
+155	common	pivot_root		sys_pivot_root
 156	64	_sysctl			sys_sysctl
-157	64	prctl			sys_prctl
-158	64	arch_prctl		sys_arch_prctl
-159	64	adjtimex		sys_adjtimex
-160	64	setrlimit		sys_setrlimit
-161	64	chroot			sys_chroot
-162	64	sync			sys_sync
-163	64	acct			sys_acct
-164	64	settimeofday		sys_settimeofday
-165	64	mount			sys_mount
-166	64	umount2			sys_umount
-167	64	swapon			sys_swapon
-168	64	swapoff			sys_swapoff
-169	64	reboot			sys_reboot
-170	64	sethostname		sys_sethostname
-171	64	setdomainname		sys_setdomainname
-172	64	iopl			stub_iopl
-173	64	ioperm			sys_ioperm
+157	common	prctl			sys_prctl
+158	common	arch_prctl		sys_arch_prctl
+159	common	adjtimex		sys_adjtimex
+160	common	setrlimit		sys_setrlimit
+161	common	chroot			sys_chroot
+162	common	sync			sys_sync
+163	common	acct			sys_acct
+164	common	settimeofday		sys_settimeofday
+165	common	mount			sys_mount
+166	common	umount2			sys_umount
+167	common	swapon			sys_swapon
+168	common	swapoff			sys_swapoff
+169	common	reboot			sys_reboot
+170	common	sethostname		sys_sethostname
+171	common	setdomainname		sys_setdomainname
+172	common	iopl			stub_iopl
+173	common	ioperm			sys_ioperm
 174	64	create_module
-175	64	init_module		sys_init_module
-176	64	delete_module		sys_delete_module
+175	common	init_module		sys_init_module
+176	common	delete_module		sys_delete_module
 177	64	get_kernel_syms
 178	64	query_module
-179	64	quotactl		sys_quotactl
+179	common	quotactl		sys_quotactl
 180	64	nfsservctl
-181	64	getpmsg
-182	64	putpmsg
-183	64	afs_syscall
-184	64	tuxcall
-185	64	security
-186	64	gettid			sys_gettid
-187	64	readahead		sys_readahead
-188	64	setxattr		sys_setxattr
-189	64	lsetxattr		sys_lsetxattr
-190	64	fsetxattr		sys_fsetxattr
-191	64	getxattr		sys_getxattr
-192	64	lgetxattr		sys_lgetxattr
-193	64	fgetxattr		sys_fgetxattr
-194	64	listxattr		sys_listxattr
-195	64	llistxattr		sys_llistxattr
-196	64	flistxattr		sys_flistxattr
-197	64	removexattr		sys_removexattr
-198	64	lremovexattr		sys_lremovexattr
-199	64	fremovexattr		sys_fremovexattr
-200	64	tkill			sys_tkill
-201	64	time			sys_time
-202	64	futex			sys_futex
-203	64	sched_setaffinity	sys_sched_setaffinity
-204	64	sched_getaffinity	sys_sched_getaffinity
+181	common	getpmsg
+182	common	putpmsg
+183	common	afs_syscall
+184	common	tuxcall
+185	common	security
+186	common	gettid			sys_gettid
+187	common	readahead		sys_readahead
+188	common	setxattr		sys_setxattr
+189	common	lsetxattr		sys_lsetxattr
+190	common	fsetxattr		sys_fsetxattr
+191	common	getxattr		sys_getxattr
+192	common	lgetxattr		sys_lgetxattr
+193	common	fgetxattr		sys_fgetxattr
+194	common	listxattr		sys_listxattr
+195	common	llistxattr		sys_llistxattr
+196	common	flistxattr		sys_flistxattr
+197	common	removexattr		sys_removexattr
+198	common	lremovexattr		sys_lremovexattr
+199	common	fremovexattr		sys_fremovexattr
+200	common	tkill			sys_tkill
+201	common	time			sys_time
+202	common	futex			sys_futex
+203	common	sched_setaffinity	sys_sched_setaffinity
+204	common	sched_getaffinity	sys_sched_getaffinity
 205	64	set_thread_area
-206	64	io_setup		sys_io_setup
-207	64	io_destroy		sys_io_destroy
-208	64	io_getevents		sys_io_getevents
-209	64	io_submit		sys_io_submit
-210	64	io_cancel		sys_io_cancel
+206	common	io_setup		sys_io_setup
+207	common	io_destroy		sys_io_destroy
+208	common	io_getevents		sys_io_getevents
+209	common	io_submit		sys_io_submit
+210	common	io_cancel		sys_io_cancel
 211	64	get_thread_area
-212	64	lookup_dcookie		sys_lookup_dcookie
-213	64	epoll_create		sys_epoll_create
+212	common	lookup_dcookie		sys_lookup_dcookie
+213	common	epoll_create		sys_epoll_create
 214	64	epoll_ctl_old
 215	64	epoll_wait_old
-216	64	remap_file_pages	sys_remap_file_pages
-217	64	getdents64		sys_getdents64
-218	64	set_tid_address		sys_set_tid_address
-219	64	restart_syscall		sys_restart_syscall
-220	64	semtimedop		sys_semtimedop
-221	64	fadvise64		sys_fadvise64
+216	common	remap_file_pages	sys_remap_file_pages
+217	common	getdents64		sys_getdents64
+218	common	set_tid_address		sys_set_tid_address
+219	common	restart_syscall		sys_restart_syscall
+220	common	semtimedop		sys_semtimedop
+221	common	fadvise64		sys_fadvise64
 222	64	timer_create		sys_timer_create
-223	64	timer_settime		sys_timer_settime
-224	64	timer_gettime		sys_timer_gettime
-225	64	timer_getoverrun	sys_timer_getoverrun
-226	64	timer_delete		sys_timer_delete
-227	64	clock_settime		sys_clock_settime
-228	64	clock_gettime		sys_clock_gettime
-229	64	clock_getres		sys_clock_getres
-230	64	clock_nanosleep		sys_clock_nanosleep
-231	64	exit_group		sys_exit_group
-232	64	epoll_wait		sys_epoll_wait
-233	64	epoll_ctl		sys_epoll_ctl
-234	64	tgkill			sys_tgkill
-235	64	utimes			sys_utimes
+223	common	timer_settime		sys_timer_settime
+224	common	timer_gettime		sys_timer_gettime
+225	common	timer_getoverrun	sys_timer_getoverrun
+226	common	timer_delete		sys_timer_delete
+227	common	clock_settime		sys_clock_settime
+228	common	clock_gettime		sys_clock_gettime
+229	common	clock_getres		sys_clock_getres
+230	common	clock_nanosleep		sys_clock_nanosleep
+231	common	exit_group		sys_exit_group
+232	common	epoll_wait		sys_epoll_wait
+233	common	epoll_ctl		sys_epoll_ctl
+234	common	tgkill			sys_tgkill
+235	common	utimes			sys_utimes
 236	64	vserver
-237	64	mbind			sys_mbind
-238	64	set_mempolicy		sys_set_mempolicy
-239	64	get_mempolicy		sys_get_mempolicy
-240	64	mq_open			sys_mq_open
-241	64	mq_unlink		sys_mq_unlink
-242	64	mq_timedsend		sys_mq_timedsend
-243	64	mq_timedreceive		sys_mq_timedreceive
+237	common	mbind			sys_mbind
+238	common	set_mempolicy		sys_set_mempolicy
+239	common	get_mempolicy		sys_get_mempolicy
+240	common	mq_open			sys_mq_open
+241	common	mq_unlink		sys_mq_unlink
+242	common	mq_timedsend		sys_mq_timedsend
+243	common	mq_timedreceive		sys_mq_timedreceive
 244	64	mq_notify		sys_mq_notify
-245	64	mq_getsetattr		sys_mq_getsetattr
+245	common	mq_getsetattr		sys_mq_getsetattr
 246	64	kexec_load		sys_kexec_load
 247	64	waitid			sys_waitid
-248	64	add_key			sys_add_key
-249	64	request_key		sys_request_key
-250	64	keyctl			sys_keyctl
-251	64	ioprio_set		sys_ioprio_set
-252	64	ioprio_get		sys_ioprio_get
-253	64	inotify_init		sys_inotify_init
-254	64	inotify_add_watch	sys_inotify_add_watch
-255	64	inotify_rm_watch	sys_inotify_rm_watch
-256	64	migrate_pages		sys_migrate_pages
-257	64	openat			sys_openat
-258	64	mkdirat			sys_mkdirat
-259	64	mknodat			sys_mknodat
-260	64	fchownat		sys_fchownat
-261	64	futimesat		sys_futimesat
-262	64	newfstatat		sys_newfstatat
-263	64	unlinkat		sys_unlinkat
-264	64	renameat		sys_renameat
-265	64	linkat			sys_linkat
-266	64	symlinkat		sys_symlinkat
-267	64	readlinkat		sys_readlinkat
-268	64	fchmodat		sys_fchmodat
-269	64	faccessat		sys_faccessat
-270	64	pselect6		sys_pselect6
-271	64	ppoll			sys_ppoll
-272	64	unshare			sys_unshare
+248	common	add_key			sys_add_key
+249	common	request_key		sys_request_key
+250	common	keyctl			sys_keyctl
+251	common	ioprio_set		sys_ioprio_set
+252	common	ioprio_get		sys_ioprio_get
+253	common	inotify_init		sys_inotify_init
+254	common	inotify_add_watch	sys_inotify_add_watch
+255	common	inotify_rm_watch	sys_inotify_rm_watch
+256	common	migrate_pages		sys_migrate_pages
+257	common	openat			sys_openat
+258	common	mkdirat			sys_mkdirat
+259	common	mknodat			sys_mknodat
+260	common	fchownat		sys_fchownat
+261	common	futimesat		sys_futimesat
+262	common	newfstatat		sys_newfstatat
+263	common	unlinkat		sys_unlinkat
+264	common	renameat		sys_renameat
+265	common	linkat			sys_linkat
+266	common	symlinkat		sys_symlinkat
+267	common	readlinkat		sys_readlinkat
+268	common	fchmodat		sys_fchmodat
+269	common	faccessat		sys_faccessat
+270	common	pselect6		sys_pselect6
+271	common	ppoll			sys_ppoll
+272	common	unshare			sys_unshare
 273	64	set_robust_list		sys_set_robust_list
 274	64	get_robust_list		sys_get_robust_list
-275	64	splice			sys_splice
-276	64	tee			sys_tee
-277	64	sync_file_range		sys_sync_file_range
+275	common	splice			sys_splice
+276	common	tee			sys_tee
+277	common	sync_file_range		sys_sync_file_range
 278	64	vmsplice		sys_vmsplice
 279	64	move_pages		sys_move_pages
-280	64	utimensat		sys_utimensat
-281	64	epoll_pwait		sys_epoll_pwait
-282	64	signalfd		sys_signalfd
-283	64	timerfd_create		sys_timerfd_create
-284	64	eventfd			sys_eventfd
-285	64	fallocate		sys_fallocate
-286	64	timerfd_settime		sys_timerfd_settime
-287	64	timerfd_gettime		sys_timerfd_gettime
-288	64	accept4			sys_accept4
-289	64	signalfd4		sys_signalfd4
-290	64	eventfd2		sys_eventfd2
-291	64	epoll_create1		sys_epoll_create1
-292	64	dup3			sys_dup3
-293	64	pipe2			sys_pipe2
-294	64	inotify_init1		sys_inotify_init1
+280	common	utimensat		sys_utimensat
+281	common	epoll_pwait		sys_epoll_pwait
+282	common	signalfd		sys_signalfd
+283	common	timerfd_create		sys_timerfd_create
+284	common	eventfd			sys_eventfd
+285	common	fallocate		sys_fallocate
+286	common	timerfd_settime		sys_timerfd_settime
+287	common	timerfd_gettime		sys_timerfd_gettime
+288	common	accept4			sys_accept4
+289	common	signalfd4		sys_signalfd4
+290	common	eventfd2		sys_eventfd2
+291	common	epoll_create1		sys_epoll_create1
+292	common	dup3			sys_dup3
+293	common	pipe2			sys_pipe2
+294	common	inotify_init1		sys_inotify_init1
 295	64	preadv			sys_preadv
 296	64	pwritev			sys_pwritev
 297	64	rt_tgsigqueueinfo	sys_rt_tgsigqueueinfo
-298	64	perf_event_open		sys_perf_event_open
+298	common	perf_event_open		sys_perf_event_open
 299	64	recvmmsg		sys_recvmmsg
-300	64	fanotify_init		sys_fanotify_init
-301	64	fanotify_mark		sys_fanotify_mark
-302	64	prlimit64		sys_prlimit64
-303	64	name_to_handle_at	sys_name_to_handle_at
-304	64	open_by_handle_at	sys_open_by_handle_at
-305	64	clock_adjtime		sys_clock_adjtime
-306	64	syncfs			sys_syncfs
+300	common	fanotify_init		sys_fanotify_init
+301	common	fanotify_mark		sys_fanotify_mark
+302	common	prlimit64		sys_prlimit64
+303	common	name_to_handle_at	sys_name_to_handle_at
+304	common	open_by_handle_at	sys_open_by_handle_at
+305	common	clock_adjtime		sys_clock_adjtime
+306	common	syncfs			sys_syncfs
 307	64	sendmmsg		sys_sendmmsg
-308	64	setns			sys_setns
-309	64	getcpu			sys_getcpu
+308	common	setns			sys_setns
+309	common	getcpu			sys_getcpu
 310	64	process_vm_readv	sys_process_vm_readv
 311	64	process_vm_writev	sys_process_vm_writev
+#
+# x32-specific system call numbers start at 512 to avoid cache impact
+# for native 64-bit operation.
+#
+512	x32	rt_sigaction		sys32_rt_sigaction
+513	x32	rt_sigreturn		stub_x32_rt_sigreturn
+514	x32	ioctl			compat_sys_ioctl
+515	x32	readv			compat_sys_readv
+516	x32	writev			compat_sys_writev
+517	x32	recvfrom		compat_sys_recvfrom
+518	x32	sendmsg			compat_sys_sendmsg
+519	x32	recvmsg			compat_sys_recvmsg
+520	x32	execve			stub_x32_execve
+521	x32	ptrace			compat_sys_ptrace
+522	x32	rt_sigpending		sys32_rt_sigpending
+523	x32	rt_sigtimedwait		compat_sys_rt_sigtimedwait
+524	x32	rt_sigqueueinfo		sys32_rt_sigqueueinfo
+525	x32	sigaltstack		stub_x32_sigaltstack
+526	x32	timer_create		compat_sys_timer_create
+527	x32	mq_notify		compat_sys_mq_notify
+528	x32	kexec_load		compat_sys_kexec_load
+529	x32	waitid			compat_sys_waitid
+530	x32	set_robust_list		compat_sys_set_robust_list
+531	x32	get_robust_list		compat_sys_get_robust_list
+532	x32	vmsplice		compat_sys_vmsplice
+533	x32	move_pages		compat_sys_move_pages
+534	x32	preadv			compat_sys_preadv64
+535	x32	pwritev			compat_sys_pwritev64
+536	x32	rt_tgsigqueueinfo	compat_sys_rt_tgsigqueueinfo
+537	x32	recvmmsg		compat_sys_recvmmsg
+538	x32	sendmmsg		compat_sys_sendmmsg
+539	x32	process_vm_readv	compat_sys_process_vm_readv
+540	x32	process_vm_writev	compat_sys_process_vm_writev
diff --git a/arch/x86/um/Kconfig b/arch/x86/um/Kconfig
index b2b54d2..9926e11 100644
--- a/arch/x86/um/Kconfig
+++ b/arch/x86/um/Kconfig
@@ -15,8 +15,8 @@
 	select GENERIC_FIND_FIRST_BIT
 
 config 64BIT
-	bool
-	default SUBARCH = "x86_64"
+	bool "64-bit kernel" if SUBARCH = "x86"
+	default SUBARCH != "i386"
 
 config X86_32
 	def_bool !64BIT
diff --git a/arch/x86/um/asm/processor.h b/arch/x86/um/asm/processor.h
index 2c32df6..04f82e0 100644
--- a/arch/x86/um/asm/processor.h
+++ b/arch/x86/um/asm/processor.h
@@ -17,6 +17,16 @@
 #define ARCH_IS_STACKGROW(address) \
        (address + 65536 + 32 * sizeof(unsigned long) >= UPT_SP(&current->thread.regs.regs))
 
+#include <asm/user.h>
+
+/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
+static inline void rep_nop(void)
+{
+	__asm__ __volatile__("rep;nop": : :"memory");
+}
+
+#define cpu_relax()	rep_nop()
+
 #include <asm/processor-generic.h>
 
 #endif
diff --git a/arch/x86/um/asm/processor_32.h b/arch/x86/um/asm/processor_32.h
index 018f732..6c6689e 100644
--- a/arch/x86/um/asm/processor_32.h
+++ b/arch/x86/um/asm/processor_32.h
@@ -45,16 +45,6 @@
         memcpy(&to->tls_array, &from->tls_array, sizeof(from->tls_array));
 }
 
-#include <asm/user.h>
-
-/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
-static inline void rep_nop(void)
-{
-	__asm__ __volatile__("rep;nop": : :"memory");
-}
-
-#define cpu_relax()	rep_nop()
-
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter"). Stolen
diff --git a/arch/x86/um/asm/processor_64.h b/arch/x86/um/asm/processor_64.h
index 61de92d..4b02a84 100644
--- a/arch/x86/um/asm/processor_64.h
+++ b/arch/x86/um/asm/processor_64.h
@@ -14,14 +14,6 @@
         struct faultinfo faultinfo;
 };
 
-/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
-static inline void rep_nop(void)
-{
-	__asm__ __volatile__("rep;nop": : :"memory");
-}
-
-#define cpu_relax()   rep_nop()
-
 #define INIT_ARCH_THREAD { .debugregs  		= { [ 0 ... 7 ] = 0 }, \
 			   .debugregs_seq	= 0, \
 			   .fs			= 0, \
@@ -37,8 +29,6 @@
 	to->fs = from->fs;
 }
 
-#include <asm/user.h>
-
 #define current_text_addr() \
 	({ void *pc; __asm__("movq $1f,%0\n1:":"=g" (pc)); pc; })
 
diff --git a/arch/x86/um/bugs_32.c b/arch/x86/um/bugs_32.c
index a1fba5f..17d88cf 100644
--- a/arch/x86/um/bugs_32.c
+++ b/arch/x86/um/bugs_32.c
@@ -13,8 +13,6 @@
 static int host_has_cmov = 1;
 static jmp_buf cmov_test_return;
 
-#define TASK_PID(task) *((int *) &(((char *) (task))[HOST_TASK_PID]))
-
 static void cmov_sigill_test_handler(int sig)
 {
 	host_has_cmov = 0;
@@ -51,7 +49,7 @@
 	 * This is testing for a cmov (0x0f 0x4x) instruction causing a
 	 * SIGILL in init.
 	 */
-	if ((sig != SIGILL) || (TASK_PID(get_current()) != 1))
+	if ((sig != SIGILL) || (get_current_pid() != 1))
 		return;
 
 	if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) {
diff --git a/arch/x86/um/mem_32.c b/arch/x86/um/mem_32.c
index 639900a..f40281e 100644
--- a/arch/x86/um/mem_32.c
+++ b/arch/x86/um/mem_32.c
@@ -23,14 +23,6 @@
 	gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
 	gate_vma.vm_page_prot = __P101;
 
-	/*
-	 * Make sure the vDSO gets into every core dump.
-	 * Dumping its contents makes post-mortem fully interpretable later
-	 * without matching up the same kernel and hardware config to see
-	 * what PC values meant.
-	 */
-	gate_vma.vm_flags |= VM_ALWAYSDUMP;
-
 	return 0;
 }
 __initcall(gate_vma_init);
diff --git a/arch/x86/um/sys_call_table_64.c b/arch/x86/um/sys_call_table_64.c
index fe626c3..9924776 100644
--- a/arch/x86/um/sys_call_table_64.c
+++ b/arch/x86/um/sys_call_table_64.c
@@ -35,6 +35,9 @@
 #define stub_sigaltstack sys_sigaltstack
 #define stub_rt_sigreturn sys_rt_sigreturn
 
+#define __SYSCALL_COMMON(nr, sym, compat) __SYSCALL_64(nr, sym, compat)
+#define __SYSCALL_X32(nr, sym, compat) /* Not supported */
+
 #define __SYSCALL_64(nr, sym, compat) extern asmlinkage void sym(void) ;
 #include <asm/syscalls_64.h>
 
diff --git a/arch/x86/um/user-offsets.c b/arch/x86/um/user-offsets.c
index 5edf4f4..ce7e360 100644
--- a/arch/x86/um/user-offsets.c
+++ b/arch/x86/um/user-offsets.c
@@ -15,6 +15,8 @@
 };
 #else
 #define __SYSCALL_64(nr, sym, compat) [nr] = 1,
+#define __SYSCALL_COMMON(nr, sym, compat) [nr] = 1,
+#define __SYSCALL_X32(nr, sym, compat) /* Not supported */
 static char syscalls[] = {
 #include <asm/syscalls_64.h>
 };
diff --git a/arch/x86/um/vdso/vma.c b/arch/x86/um/vdso/vma.c
index 91f4ec9..af91901 100644
--- a/arch/x86/um/vdso/vma.c
+++ b/arch/x86/um/vdso/vma.c
@@ -64,8 +64,7 @@
 
 	err = install_special_mapping(mm, um_vdso_addr, PAGE_SIZE,
 		VM_READ|VM_EXEC|
-		VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-		VM_ALWAYSDUMP,
+		VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
 		vdsop);
 
 	up_write(&mm->mmap_sem);
diff --git a/arch/x86/vdso/.gitignore b/arch/x86/vdso/.gitignore
index 60274d5..3282874 100644
--- a/arch/x86/vdso/.gitignore
+++ b/arch/x86/vdso/.gitignore
@@ -1,5 +1,7 @@
 vdso.lds
 vdso-syms.lds
+vdsox32.lds
+vdsox32-syms.lds
 vdso32-syms.lds
 vdso32-syscall-syms.lds
 vdso32-sysenter-syms.lds
diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index 5d17950..fd14be1 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -3,21 +3,29 @@
 #
 
 VDSO64-$(CONFIG_X86_64)		:= y
+VDSOX32-$(CONFIG_X86_X32_ABI)	:= y
 VDSO32-$(CONFIG_X86_32)		:= y
 VDSO32-$(CONFIG_COMPAT)		:= y
 
 vdso-install-$(VDSO64-y)	+= vdso.so
+vdso-install-$(VDSOX32-y)	+= vdsox32.so
 vdso-install-$(VDSO32-y)	+= $(vdso32-images)
 
 
 # files to link into the vdso
 vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o
 
+vobjs-$(VDSOX32-y) += $(vobjx32s-compat)
+
+# Filter out x32 objects.
+vobj64s := $(filter-out $(vobjx32s-compat),$(vobjs-y))
+
 # files to link into kernel
 obj-$(VDSO64-y)			+= vma.o vdso.o
+obj-$(VDSOX32-y)		+= vdsox32.o
 obj-$(VDSO32-y)			+= vdso32.o vdso32-setup.o
 
-vobjs := $(foreach F,$(vobjs-y),$(obj)/$F)
+vobjs := $(foreach F,$(vobj64s),$(obj)/$F)
 
 $(obj)/vdso.o: $(obj)/vdso.so
 
@@ -73,6 +81,42 @@
 	$(call if_changed,vdsosym)
 
 #
+# X32 processes use x32 vDSO to access 64bit kernel data.
+#
+# Build x32 vDSO image:
+# 1. Compile x32 vDSO as 64bit.
+# 2. Convert object files to x32.
+# 3. Build x32 VDSO image with x32 objects, which contains 64bit codes
+# so that it can reach 64bit address space with 64bit pointers.
+#
+
+targets += vdsox32-syms.lds
+obj-$(VDSOX32-y)		+= vdsox32-syms.lds
+
+CPPFLAGS_vdsox32.lds = $(CPPFLAGS_vdso.lds)
+VDSO_LDFLAGS_vdsox32.lds = -Wl,-m,elf32_x86_64 \
+			   -Wl,-soname=linux-vdso.so.1 \
+			   -Wl,-z,max-page-size=4096 \
+			   -Wl,-z,common-page-size=4096
+
+vobjx32s-y := $(vobj64s:.o=-x32.o)
+vobjx32s := $(foreach F,$(vobjx32s-y),$(obj)/$F)
+
+# Convert 64bit object file to x32 for x32 vDSO.
+quiet_cmd_x32 = X32     $@
+      cmd_x32 = $(OBJCOPY) -O elf32-x86-64 $< $@
+
+$(obj)/%-x32.o: $(obj)/%.o FORCE
+	$(call if_changed,x32)
+
+targets += vdsox32.so vdsox32.so.dbg vdsox32.lds $(vobjx32s-y)
+
+$(obj)/vdsox32.o: $(src)/vdsox32.S $(obj)/vdsox32.so
+
+$(obj)/vdsox32.so.dbg: $(src)/vdsox32.lds $(vobjx32s) FORCE
+	$(call if_changed,vdso)
+
+#
 # Build multiple 32-bit vDSO images to choose from at boot time.
 #
 obj-$(VDSO32-y)			+= vdso32-syms.lds
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c
index 6bc0e72..885eff4 100644
--- a/arch/x86/vdso/vclock_gettime.c
+++ b/arch/x86/vdso/vclock_gettime.c
@@ -70,100 +70,98 @@
 	return ret;
 }
 
+notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
+{
+	long ret;
+
+	asm("syscall" : "=a" (ret) :
+	    "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory");
+	return ret;
+}
+
+
 notrace static inline long vgetns(void)
 {
 	long v;
 	cycles_t cycles;
 	if (gtod->clock.vclock_mode == VCLOCK_TSC)
 		cycles = vread_tsc();
-	else
+	else if (gtod->clock.vclock_mode == VCLOCK_HPET)
 		cycles = vread_hpet();
+	else
+		return 0;
 	v = (cycles - gtod->clock.cycle_last) & gtod->clock.mask;
 	return (v * gtod->clock.mult) >> gtod->clock.shift;
 }
 
-notrace static noinline int do_realtime(struct timespec *ts)
+/* Code size doesn't matter (vdso is 4k anyway) and this is faster. */
+notrace static int __always_inline do_realtime(struct timespec *ts)
 {
 	unsigned long seq, ns;
+	int mode;
+
 	do {
-		seq = read_seqbegin(&gtod->lock);
+		seq = read_seqcount_begin(&gtod->seq);
+		mode = gtod->clock.vclock_mode;
 		ts->tv_sec = gtod->wall_time_sec;
 		ts->tv_nsec = gtod->wall_time_nsec;
 		ns = vgetns();
-	} while (unlikely(read_seqretry(&gtod->lock, seq)));
+	} while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
+
 	timespec_add_ns(ts, ns);
-	return 0;
+	return mode;
 }
 
-notrace static noinline int do_monotonic(struct timespec *ts)
+notrace static int do_monotonic(struct timespec *ts)
 {
-	unsigned long seq, ns, secs;
+	unsigned long seq, ns;
+	int mode;
+
 	do {
-		seq = read_seqbegin(&gtod->lock);
-		secs = gtod->wall_time_sec;
-		ns = gtod->wall_time_nsec + vgetns();
-		secs += gtod->wall_to_monotonic.tv_sec;
-		ns += gtod->wall_to_monotonic.tv_nsec;
-	} while (unlikely(read_seqretry(&gtod->lock, seq)));
+		seq = read_seqcount_begin(&gtod->seq);
+		mode = gtod->clock.vclock_mode;
+		ts->tv_sec = gtod->monotonic_time_sec;
+		ts->tv_nsec = gtod->monotonic_time_nsec;
+		ns = vgetns();
+	} while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
+	timespec_add_ns(ts, ns);
 
-	/* wall_time_nsec, vgetns(), and wall_to_monotonic.tv_nsec
-	 * are all guaranteed to be nonnegative.
-	 */
-	while (ns >= NSEC_PER_SEC) {
-		ns -= NSEC_PER_SEC;
-		++secs;
-	}
-	ts->tv_sec = secs;
-	ts->tv_nsec = ns;
-
-	return 0;
+	return mode;
 }
 
-notrace static noinline int do_realtime_coarse(struct timespec *ts)
+notrace static int do_realtime_coarse(struct timespec *ts)
 {
 	unsigned long seq;
 	do {
-		seq = read_seqbegin(&gtod->lock);
+		seq = read_seqcount_begin(&gtod->seq);
 		ts->tv_sec = gtod->wall_time_coarse.tv_sec;
 		ts->tv_nsec = gtod->wall_time_coarse.tv_nsec;
-	} while (unlikely(read_seqretry(&gtod->lock, seq)));
+	} while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
 	return 0;
 }
 
-notrace static noinline int do_monotonic_coarse(struct timespec *ts)
+notrace static int do_monotonic_coarse(struct timespec *ts)
 {
-	unsigned long seq, ns, secs;
+	unsigned long seq;
 	do {
-		seq = read_seqbegin(&gtod->lock);
-		secs = gtod->wall_time_coarse.tv_sec;
-		ns = gtod->wall_time_coarse.tv_nsec;
-		secs += gtod->wall_to_monotonic.tv_sec;
-		ns += gtod->wall_to_monotonic.tv_nsec;
-	} while (unlikely(read_seqretry(&gtod->lock, seq)));
-
-	/* wall_time_nsec and wall_to_monotonic.tv_nsec are
-	 * guaranteed to be between 0 and NSEC_PER_SEC.
-	 */
-	if (ns >= NSEC_PER_SEC) {
-		ns -= NSEC_PER_SEC;
-		++secs;
-	}
-	ts->tv_sec = secs;
-	ts->tv_nsec = ns;
+		seq = read_seqcount_begin(&gtod->seq);
+		ts->tv_sec = gtod->monotonic_time_coarse.tv_sec;
+		ts->tv_nsec = gtod->monotonic_time_coarse.tv_nsec;
+	} while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
 
 	return 0;
 }
 
 notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
 {
+	int ret = VCLOCK_NONE;
+
 	switch (clock) {
 	case CLOCK_REALTIME:
-		if (likely(gtod->clock.vclock_mode != VCLOCK_NONE))
-			return do_realtime(ts);
+		ret = do_realtime(ts);
 		break;
 	case CLOCK_MONOTONIC:
-		if (likely(gtod->clock.vclock_mode != VCLOCK_NONE))
-			return do_monotonic(ts);
+		ret = do_monotonic(ts);
 		break;
 	case CLOCK_REALTIME_COARSE:
 		return do_realtime_coarse(ts);
@@ -171,32 +169,33 @@
 		return do_monotonic_coarse(ts);
 	}
 
-	return vdso_fallback_gettime(clock, ts);
+	if (ret == VCLOCK_NONE)
+		return vdso_fallback_gettime(clock, ts);
+	return 0;
 }
 int clock_gettime(clockid_t, struct timespec *)
 	__attribute__((weak, alias("__vdso_clock_gettime")));
 
 notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
 {
-	long ret;
-	if (likely(gtod->clock.vclock_mode != VCLOCK_NONE)) {
-		if (likely(tv != NULL)) {
-			BUILD_BUG_ON(offsetof(struct timeval, tv_usec) !=
-				     offsetof(struct timespec, tv_nsec) ||
-				     sizeof(*tv) != sizeof(struct timespec));
-			do_realtime((struct timespec *)tv);
-			tv->tv_usec /= 1000;
-		}
-		if (unlikely(tz != NULL)) {
-			/* Avoid memcpy. Some old compilers fail to inline it */
-			tz->tz_minuteswest = gtod->sys_tz.tz_minuteswest;
-			tz->tz_dsttime = gtod->sys_tz.tz_dsttime;
-		}
-		return 0;
+	long ret = VCLOCK_NONE;
+
+	if (likely(tv != NULL)) {
+		BUILD_BUG_ON(offsetof(struct timeval, tv_usec) !=
+			     offsetof(struct timespec, tv_nsec) ||
+			     sizeof(*tv) != sizeof(struct timespec));
+		ret = do_realtime((struct timespec *)tv);
+		tv->tv_usec /= 1000;
 	}
-	asm("syscall" : "=a" (ret) :
-	    "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory");
-	return ret;
+	if (unlikely(tz != NULL)) {
+		/* Avoid memcpy. Some old compilers fail to inline it */
+		tz->tz_minuteswest = gtod->sys_tz.tz_minuteswest;
+		tz->tz_dsttime = gtod->sys_tz.tz_dsttime;
+	}
+
+	if (ret == VCLOCK_NONE)
+		return vdso_fallback_gtod(tv, tz);
+	return 0;
 }
 int gettimeofday(struct timeval *, struct timezone *)
 	__attribute__((weak, alias("__vdso_gettimeofday")));
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c
index 468d591..66e6d93 100644
--- a/arch/x86/vdso/vdso32-setup.c
+++ b/arch/x86/vdso/vdso32-setup.c
@@ -250,13 +250,7 @@
 	gate_vma.vm_end = FIXADDR_USER_END;
 	gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
 	gate_vma.vm_page_prot = __P101;
-	/*
-	 * Make sure the vDSO gets into every core dump.
-	 * Dumping its contents makes post-mortem fully interpretable later
-	 * without matching up the same kernel and hardware config to see
-	 * what PC values meant.
-	 */
-	gate_vma.vm_flags |= VM_ALWAYSDUMP;
+
 	return 0;
 }
 
@@ -317,6 +311,11 @@
 	int ret = 0;
 	bool compat;
 
+#ifdef CONFIG_X86_X32_ABI
+	if (test_thread_flag(TIF_X32))
+		return x32_setup_additional_pages(bprm, uses_interp);
+#endif
+
 	if (vdso_enabled == VDSO_DISABLED)
 		return 0;
 
@@ -343,17 +342,10 @@
 	if (compat_uses_vma || !compat) {
 		/*
 		 * MAYWRITE to allow gdb to COW and set breakpoints
-		 *
-		 * Make sure the vDSO gets into every core dump.
-		 * Dumping its contents makes post-mortem fully
-		 * interpretable later without matching up the same
-		 * kernel and hardware config to see what PC values
-		 * meant.
 		 */
 		ret = install_special_mapping(mm, addr, PAGE_SIZE,
 					      VM_READ|VM_EXEC|
-					      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-					      VM_ALWAYSDUMP,
+					      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
 					      vdso32_pages);
 
 		if (ret)
diff --git a/arch/x86/vdso/vdsox32.S b/arch/x86/vdso/vdsox32.S
new file mode 100644
index 0000000..d6b9a7f
--- /dev/null
+++ b/arch/x86/vdso/vdsox32.S
@@ -0,0 +1,22 @@
+#include <asm/page_types.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+__PAGE_ALIGNED_DATA
+
+	.globl vdsox32_start, vdsox32_end
+	.align PAGE_SIZE
+vdsox32_start:
+	.incbin "arch/x86/vdso/vdsox32.so"
+vdsox32_end:
+	.align PAGE_SIZE /* extra data here leaks to userspace. */
+
+.previous
+
+	.globl vdsox32_pages
+	.bss
+	.align 8
+	.type vdsox32_pages, @object
+vdsox32_pages:
+	.zero (vdsox32_end - vdsox32_start + PAGE_SIZE - 1) / PAGE_SIZE * 8
+	.size vdsox32_pages, .-vdsox32_pages
diff --git a/arch/x86/vdso/vdsox32.lds.S b/arch/x86/vdso/vdsox32.lds.S
new file mode 100644
index 0000000..62272aa
--- /dev/null
+++ b/arch/x86/vdso/vdsox32.lds.S
@@ -0,0 +1,28 @@
+/*
+ * Linker script for x32 vDSO.
+ * We #include the file to define the layout details.
+ * Here we only choose the prelinked virtual address.
+ *
+ * This file defines the version script giving the user-exported symbols in
+ * the DSO.  We can define local symbols here called VDSO* to make their
+ * values visible using the asm-x86/vdso.h macros from the kernel proper.
+ */
+
+#define VDSO_PRELINK 0
+#include "vdso-layout.lds.S"
+
+/*
+ * This controls what userland symbols we export from the vDSO.
+ */
+VERSION {
+	LINUX_2.6 {
+	global:
+		__vdso_clock_gettime;
+		__vdso_gettimeofday;
+		__vdso_getcpu;
+		__vdso_time;
+	local: *;
+	};
+}
+
+VDSOX32_PRELINK = VDSO_PRELINK;
diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c
index 153407c..00aaf04 100644
--- a/arch/x86/vdso/vma.c
+++ b/arch/x86/vdso/vma.c
@@ -24,7 +24,44 @@
 extern struct page *vdso_pages[];
 static unsigned vdso_size;
 
-static void __init patch_vdso(void *vdso, size_t len)
+#ifdef CONFIG_X86_X32_ABI
+extern char vdsox32_start[], vdsox32_end[];
+extern struct page *vdsox32_pages[];
+static unsigned vdsox32_size;
+
+static void __init patch_vdsox32(void *vdso, size_t len)
+{
+	Elf32_Ehdr *hdr = vdso;
+	Elf32_Shdr *sechdrs, *alt_sec = 0;
+	char *secstrings;
+	void *alt_data;
+	int i;
+
+	BUG_ON(len < sizeof(Elf32_Ehdr));
+	BUG_ON(memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0);
+
+	sechdrs = (void *)hdr + hdr->e_shoff;
+	secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+	for (i = 1; i < hdr->e_shnum; i++) {
+		Elf32_Shdr *shdr = &sechdrs[i];
+		if (!strcmp(secstrings + shdr->sh_name, ".altinstructions")) {
+			alt_sec = shdr;
+			goto found;
+		}
+	}
+
+	/* If we get here, it's probably a bug. */
+	pr_warning("patch_vdsox32: .altinstructions not found\n");
+	return;  /* nothing to patch */
+
+found:
+	alt_data = (void *)hdr + alt_sec->sh_offset;
+	apply_alternatives(alt_data, alt_data + alt_sec->sh_size);
+}
+#endif
+
+static void __init patch_vdso64(void *vdso, size_t len)
 {
 	Elf64_Ehdr *hdr = vdso;
 	Elf64_Shdr *sechdrs, *alt_sec = 0;
@@ -47,7 +84,7 @@
 	}
 
 	/* If we get here, it's probably a bug. */
-	pr_warning("patch_vdso: .altinstructions not found\n");
+	pr_warning("patch_vdso64: .altinstructions not found\n");
 	return;  /* nothing to patch */
 
 found:
@@ -60,12 +97,20 @@
 	int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE;
 	int i;
 
-	patch_vdso(vdso_start, vdso_end - vdso_start);
+	patch_vdso64(vdso_start, vdso_end - vdso_start);
 
 	vdso_size = npages << PAGE_SHIFT;
 	for (i = 0; i < npages; i++)
 		vdso_pages[i] = virt_to_page(vdso_start + i*PAGE_SIZE);
 
+#ifdef CONFIG_X86_X32_ABI
+	patch_vdsox32(vdsox32_start, vdsox32_end - vdsox32_start);
+	npages = (vdsox32_end - vdsox32_start + PAGE_SIZE - 1) / PAGE_SIZE;
+	vdsox32_size = npages << PAGE_SHIFT;
+	for (i = 0; i < npages; i++)
+		vdsox32_pages[i] = virt_to_page(vdsox32_start + i*PAGE_SIZE);
+#endif
+
 	return 0;
 }
 subsys_initcall(init_vdso);
@@ -103,7 +148,10 @@
 
 /* Setup a VMA at program startup for the vsyscall page.
    Not called for compat tasks */
-int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+static int setup_additional_pages(struct linux_binprm *bprm,
+				  int uses_interp,
+				  struct page **pages,
+				  unsigned size)
 {
 	struct mm_struct *mm = current->mm;
 	unsigned long addr;
@@ -113,8 +161,8 @@
 		return 0;
 
 	down_write(&mm->mmap_sem);
-	addr = vdso_addr(mm->start_stack, vdso_size);
-	addr = get_unmapped_area(NULL, addr, vdso_size, 0, 0);
+	addr = vdso_addr(mm->start_stack, size);
+	addr = get_unmapped_area(NULL, addr, size, 0, 0);
 	if (IS_ERR_VALUE(addr)) {
 		ret = addr;
 		goto up_fail;
@@ -122,11 +170,10 @@
 
 	current->mm->context.vdso = (void *)addr;
 
-	ret = install_special_mapping(mm, addr, vdso_size,
+	ret = install_special_mapping(mm, addr, size,
 				      VM_READ|VM_EXEC|
-				      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-				      VM_ALWAYSDUMP,
-				      vdso_pages);
+				      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
+				      pages);
 	if (ret) {
 		current->mm->context.vdso = NULL;
 		goto up_fail;
@@ -137,6 +184,20 @@
 	return ret;
 }
 
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+{
+	return setup_additional_pages(bprm, uses_interp, vdso_pages,
+				      vdso_size);
+}
+
+#ifdef CONFIG_X86_X32_ABI
+int x32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+{
+	return setup_additional_pages(bprm, uses_interp, vdsox32_pages,
+				      vdsox32_size);
+}
+#endif
+
 static __init int vdso_setup(char *s)
 {
 	vdso_enabled = simple_strtoul(s, NULL, 0);
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 4172af8..4f51beb 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -62,6 +62,15 @@
 #include <asm/reboot.h>
 #include <asm/stackprotector.h>
 #include <asm/hypervisor.h>
+#include <asm/mwait.h>
+
+#ifdef CONFIG_ACPI
+#include <linux/acpi.h>
+#include <asm/acpi.h>
+#include <acpi/pdc_intel.h>
+#include <acpi/processor.h>
+#include <xen/interface/platform.h>
+#endif
 
 #include "xen-ops.h"
 #include "mmu.h"
@@ -200,13 +209,17 @@
 static __read_mostly unsigned int cpuid_leaf1_edx_mask = ~0;
 static __read_mostly unsigned int cpuid_leaf1_ecx_mask = ~0;
 
+static __read_mostly unsigned int cpuid_leaf1_ecx_set_mask;
+static __read_mostly unsigned int cpuid_leaf5_ecx_val;
+static __read_mostly unsigned int cpuid_leaf5_edx_val;
+
 static void xen_cpuid(unsigned int *ax, unsigned int *bx,
 		      unsigned int *cx, unsigned int *dx)
 {
 	unsigned maskebx = ~0;
 	unsigned maskecx = ~0;
 	unsigned maskedx = ~0;
-
+	unsigned setecx = 0;
 	/*
 	 * Mask out inconvenient features, to try and disable as many
 	 * unsupported kernel subsystems as possible.
@@ -214,9 +227,18 @@
 	switch (*ax) {
 	case 1:
 		maskecx = cpuid_leaf1_ecx_mask;
+		setecx = cpuid_leaf1_ecx_set_mask;
 		maskedx = cpuid_leaf1_edx_mask;
 		break;
 
+	case CPUID_MWAIT_LEAF:
+		/* Synthesize the values.. */
+		*ax = 0;
+		*bx = 0;
+		*cx = cpuid_leaf5_ecx_val;
+		*dx = cpuid_leaf5_edx_val;
+		return;
+
 	case 0xb:
 		/* Suppress extended topology stuff */
 		maskebx = 0;
@@ -232,9 +254,75 @@
 
 	*bx &= maskebx;
 	*cx &= maskecx;
+	*cx |= setecx;
 	*dx &= maskedx;
+
 }
 
+static bool __init xen_check_mwait(void)
+{
+#ifdef CONFIG_ACPI
+	struct xen_platform_op op = {
+		.cmd			= XENPF_set_processor_pminfo,
+		.u.set_pminfo.id	= -1,
+		.u.set_pminfo.type	= XEN_PM_PDC,
+	};
+	uint32_t buf[3];
+	unsigned int ax, bx, cx, dx;
+	unsigned int mwait_mask;
+
+	/* We need to determine whether it is OK to expose the MWAIT
+	 * capability to the kernel to harvest deeper than C3 states from ACPI
+	 * _CST using the processor_harvest_xen.c module. For this to work, we
+	 * need to gather the MWAIT_LEAF values (which the cstate.c code
+	 * checks against). The hypervisor won't expose the MWAIT flag because
+	 * it would break backwards compatibility; so we will find out directly
+	 * from the hardware and hypercall.
+	 */
+	if (!xen_initial_domain())
+		return false;
+
+	ax = 1;
+	cx = 0;
+
+	native_cpuid(&ax, &bx, &cx, &dx);
+
+	mwait_mask = (1 << (X86_FEATURE_EST % 32)) |
+		     (1 << (X86_FEATURE_MWAIT % 32));
+
+	if ((cx & mwait_mask) != mwait_mask)
+		return false;
+
+	/* We need to emulate the MWAIT_LEAF and for that we need both
+	 * ecx and edx. The hypercall provides only partial information.
+	 */
+
+	ax = CPUID_MWAIT_LEAF;
+	bx = 0;
+	cx = 0;
+	dx = 0;
+
+	native_cpuid(&ax, &bx, &cx, &dx);
+
+	/* Ask the Hypervisor whether to clear ACPI_PDC_C_C2C3_FFH. If so,
+	 * don't expose MWAIT_LEAF and let ACPI pick the IOPORT version of C3.
+	 */
+	buf[0] = ACPI_PDC_REVISION_ID;
+	buf[1] = 1;
+	buf[2] = (ACPI_PDC_C_CAPABILITY_SMP | ACPI_PDC_EST_CAPABILITY_SWSMP);
+
+	set_xen_guest_handle(op.u.set_pminfo.pdc, buf);
+
+	if ((HYPERVISOR_dom0_op(&op) == 0) &&
+	    (buf[2] & (ACPI_PDC_C_C1_FFH | ACPI_PDC_C_C2C3_FFH))) {
+		cpuid_leaf5_ecx_val = cx;
+		cpuid_leaf5_edx_val = dx;
+	}
+	return true;
+#else
+	return false;
+#endif
+}
 static void __init xen_init_cpuid_mask(void)
 {
 	unsigned int ax, bx, cx, dx;
@@ -261,6 +349,9 @@
 	/* Xen will set CR4.OSXSAVE if supported and not disabled by force */
 	if ((cx & xsave_mask) != xsave_mask)
 		cpuid_leaf1_ecx_mask &= ~xsave_mask; /* disable XSAVE & OSXSAVE */
+
+	if (xen_check_mwait())
+		cpuid_leaf1_ecx_set_mask = (1 << (X86_FEATURE_MWAIT % 32));
 }
 
 static void xen_set_debugreg(int reg, unsigned long val)
@@ -777,11 +868,11 @@
 
 static unsigned long xen_read_cr0(void)
 {
-	unsigned long cr0 = percpu_read(xen_cr0_value);
+	unsigned long cr0 = this_cpu_read(xen_cr0_value);
 
 	if (unlikely(cr0 == 0)) {
 		cr0 = native_read_cr0();
-		percpu_write(xen_cr0_value, cr0);
+		this_cpu_write(xen_cr0_value, cr0);
 	}
 
 	return cr0;
@@ -791,7 +882,7 @@
 {
 	struct multicall_space mcs;
 
-	percpu_write(xen_cr0_value, cr0);
+	this_cpu_write(xen_cr0_value, cr0);
 
 	/* Only pay attention to cr0.TS; everything else is
 	   ignored. */
@@ -876,7 +967,7 @@
 	xen_setup_mfn_list_list();
 }
 
-/* This is called once we have the cpu_possible_map */
+/* This is called once we have the cpu_possible_mask */
 void xen_setup_vcpu_info_placement(void)
 {
 	int cpu;
diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c
index 8bbb465..1573376 100644
--- a/arch/x86/xen/irq.c
+++ b/arch/x86/xen/irq.c
@@ -26,7 +26,7 @@
 	struct vcpu_info *vcpu;
 	unsigned long flags;
 
-	vcpu = percpu_read(xen_vcpu);
+	vcpu = this_cpu_read(xen_vcpu);
 
 	/* flag has opposite sense of mask */
 	flags = !vcpu->evtchn_upcall_mask;
@@ -50,7 +50,7 @@
 	   make sure we're don't switch CPUs between getting the vcpu
 	   pointer and updating the mask. */
 	preempt_disable();
-	vcpu = percpu_read(xen_vcpu);
+	vcpu = this_cpu_read(xen_vcpu);
 	vcpu->evtchn_upcall_mask = flags;
 	preempt_enable_no_resched();
 
@@ -72,7 +72,7 @@
 	   make sure we're don't switch CPUs between getting the vcpu
 	   pointer and updating the mask. */
 	preempt_disable();
-	percpu_read(xen_vcpu)->evtchn_upcall_mask = 1;
+	this_cpu_read(xen_vcpu)->evtchn_upcall_mask = 1;
 	preempt_enable_no_resched();
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_irq_disable);
@@ -86,7 +86,7 @@
 	   the caller is confused and is trying to re-enable interrupts
 	   on an indeterminate processor. */
 
-	vcpu = percpu_read(xen_vcpu);
+	vcpu = this_cpu_read(xen_vcpu);
 	vcpu->evtchn_upcall_mask = 0;
 
 	/* Doesn't matter if we get preempted here, because any
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 95c1cf6..988828b 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -1071,14 +1071,14 @@
 	struct mm_struct *mm = info;
 	struct mm_struct *active_mm;
 
-	active_mm = percpu_read(cpu_tlbstate.active_mm);
+	active_mm = this_cpu_read(cpu_tlbstate.active_mm);
 
-	if (active_mm == mm && percpu_read(cpu_tlbstate.state) != TLBSTATE_OK)
+	if (active_mm == mm && this_cpu_read(cpu_tlbstate.state) != TLBSTATE_OK)
 		leave_mm(smp_processor_id());
 
 	/* If this cpu still has a stale cr3 reference, then make sure
 	   it has been flushed. */
-	if (percpu_read(xen_current_cr3) == __pa(mm->pgd))
+	if (this_cpu_read(xen_current_cr3) == __pa(mm->pgd))
 		load_cr3(swapper_pg_dir);
 }
 
@@ -1185,17 +1185,17 @@
 
 static void xen_write_cr2(unsigned long cr2)
 {
-	percpu_read(xen_vcpu)->arch.cr2 = cr2;
+	this_cpu_read(xen_vcpu)->arch.cr2 = cr2;
 }
 
 static unsigned long xen_read_cr2(void)
 {
-	return percpu_read(xen_vcpu)->arch.cr2;
+	return this_cpu_read(xen_vcpu)->arch.cr2;
 }
 
 unsigned long xen_read_cr2_direct(void)
 {
-	return percpu_read(xen_vcpu_info.arch.cr2);
+	return this_cpu_read(xen_vcpu_info.arch.cr2);
 }
 
 static void xen_flush_tlb(void)
@@ -1278,12 +1278,12 @@
 
 static unsigned long xen_read_cr3(void)
 {
-	return percpu_read(xen_cr3);
+	return this_cpu_read(xen_cr3);
 }
 
 static void set_current_cr3(void *v)
 {
-	percpu_write(xen_current_cr3, (unsigned long)v);
+	this_cpu_write(xen_current_cr3, (unsigned long)v);
 }
 
 static void __xen_write_cr3(bool kernel, unsigned long cr3)
@@ -1306,7 +1306,7 @@
 	xen_extend_mmuext_op(&op);
 
 	if (kernel) {
-		percpu_write(xen_cr3, cr3);
+		this_cpu_write(xen_cr3, cr3);
 
 		/* Update xen_current_cr3 once the batch has actually
 		   been submitted. */
@@ -1322,7 +1322,7 @@
 
 	/* Update while interrupts are disabled, so its atomic with
 	   respect to ipis */
-	percpu_write(xen_cr3, cr3);
+	this_cpu_write(xen_cr3, cr3);
 
 	__xen_write_cr3(true, cr3);
 
diff --git a/arch/x86/xen/multicalls.h b/arch/x86/xen/multicalls.h
index dee79b7..9c2e74f 100644
--- a/arch/x86/xen/multicalls.h
+++ b/arch/x86/xen/multicalls.h
@@ -47,7 +47,7 @@
 		xen_mc_flush();
 
 	/* restore flags saved in xen_mc_batch */
-	local_irq_restore(percpu_read(xen_mc_irq_flags));
+	local_irq_restore(this_cpu_read(xen_mc_irq_flags));
 }
 
 /* Set up a callback to be called when the current batch is flushed */
diff --git a/arch/x86/xen/pci-swiotlb-xen.c b/arch/x86/xen/pci-swiotlb-xen.c
index b480d42..967633a 100644
--- a/arch/x86/xen/pci-swiotlb-xen.c
+++ b/arch/x86/xen/pci-swiotlb-xen.c
@@ -12,8 +12,8 @@
 
 static struct dma_map_ops xen_swiotlb_dma_ops = {
 	.mapping_error = xen_swiotlb_dma_mapping_error,
-	.alloc_coherent = xen_swiotlb_alloc_coherent,
-	.free_coherent = xen_swiotlb_free_coherent,
+	.alloc = xen_swiotlb_alloc_coherent,
+	.free = xen_swiotlb_free_coherent,
 	.sync_single_for_cpu = xen_swiotlb_sync_single_for_cpu,
 	.sync_single_for_device = xen_swiotlb_sync_single_for_device,
 	.sync_sg_for_cpu = xen_swiotlb_sync_sg_for_cpu,
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index e03c636..1ba8dff 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -10,6 +10,7 @@
 #include <linux/pm.h>
 #include <linux/memblock.h>
 #include <linux/cpuidle.h>
+#include <linux/cpufreq.h>
 
 #include <asm/elf.h>
 #include <asm/vdso.h>
@@ -420,7 +421,7 @@
 	boot_cpu_data.hlt_works_ok = 1;
 #endif
 	disable_cpuidle();
-	boot_option_idle_override = IDLE_HALT;
+	disable_cpufreq();
 	WARN_ON(set_pm_idle_to_default());
 	fiddle_vdso();
 }
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index 501d4e0..02900e8 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -75,8 +75,14 @@
 
 	xen_setup_cpu_clockevents();
 
+	notify_cpu_starting(cpu);
+
+	ipi_call_lock();
 	set_cpu_online(cpu, true);
-	percpu_write(cpu_state, CPU_ONLINE);
+	ipi_call_unlock();
+
+	this_cpu_write(cpu_state, CPU_ONLINE);
+
 	wmb();
 
 	/* We can take interrupts now: we're officially "up". */
diff --git a/arch/xtensa/configs/iss_defconfig b/arch/xtensa/configs/iss_defconfig
index f932b30..ddab37b 100644
--- a/arch/xtensa/configs/iss_defconfig
+++ b/arch/xtensa/configs/iss_defconfig
@@ -113,7 +113,7 @@
 # CONFIG_INLINE_SPIN_LOCK_BH is not set
 # CONFIG_INLINE_SPIN_LOCK_IRQ is not set
 # CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
-CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_UNINLINE_SPIN_UNLOCK is not set
 # CONFIG_INLINE_SPIN_UNLOCK_BH is not set
 CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
 # CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h
index 23592ef..b409893 100644
--- a/arch/xtensa/include/asm/atomic.h
+++ b/arch/xtensa/include/asm/atomic.h
@@ -18,7 +18,7 @@
 
 #ifdef __KERNEL__
 #include <asm/processor.h>
-#include <asm/system.h>
+#include <asm/cmpxchg.h>
 
 #define ATOMIC_INIT(i)	{ (i) }
 
diff --git a/arch/xtensa/include/asm/barrier.h b/arch/xtensa/include/asm/barrier.h
new file mode 100644
index 0000000..55707a8
--- /dev/null
+++ b/arch/xtensa/include/asm/barrier.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SYSTEM_H
+#define _XTENSA_SYSTEM_H
+
+#define smp_read_barrier_depends() do { } while(0)
+#define read_barrier_depends() do { } while(0)
+
+#define mb()  barrier()
+#define rmb() mb()
+#define wmb() mb()
+
+#ifdef CONFIG_SMP
+#error smp_* not defined
+#else
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+#endif
+
+#define set_mb(var, value)	do { var = value; mb(); } while (0)
+
+#endif /* _XTENSA_SYSTEM_H */
diff --git a/arch/xtensa/include/asm/bitops.h b/arch/xtensa/include/asm/bitops.h
index 40aa7fe..5270197 100644
--- a/arch/xtensa/include/asm/bitops.h
+++ b/arch/xtensa/include/asm/bitops.h
@@ -21,7 +21,6 @@
 
 #include <asm/processor.h>
 #include <asm/byteorder.h>
-#include <asm/system.h>
 
 #ifdef CONFIG_SMP
 # error SMP not supported on this architecture
diff --git a/arch/xtensa/include/asm/cmpxchg.h b/arch/xtensa/include/asm/cmpxchg.h
new file mode 100644
index 0000000..e321490
--- /dev/null
+++ b/arch/xtensa/include/asm/cmpxchg.h
@@ -0,0 +1,131 @@
+/*
+ * Atomic xchg and cmpxchg operations.
+ *
+ * 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.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CMPXCHG_H
+#define _XTENSA_CMPXCHG_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/stringify.h>
+
+/*
+ * cmpxchg
+ */
+
+static inline unsigned long
+__cmpxchg_u32(volatile int *p, int old, int new)
+{
+  __asm__ __volatile__("rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
+		       "l32i    %0, %1, 0              \n\t"
+		       "bne	%0, %2, 1f             \n\t"
+		       "s32i    %3, %1, 0              \n\t"
+		       "1:                             \n\t"
+		       "wsr     a15, "__stringify(PS)" \n\t"
+		       "rsync                          \n\t"
+		       : "=&a" (old)
+		       : "a" (p), "a" (old), "r" (new)
+		       : "a15", "memory");
+  return old;
+}
+/* This function doesn't exist, so you'll get a linker error
+ * if something tries to do an invalid cmpxchg(). */
+
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+static __inline__ unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
+{
+	switch (size) {
+	case 4:  return __cmpxchg_u32(ptr, old, new);
+	default: __cmpxchg_called_with_bad_pointer();
+		 return old;
+	}
+}
+
+#define cmpxchg(ptr,o,n)						      \
+	({ __typeof__(*(ptr)) _o_ = (o);				      \
+	   __typeof__(*(ptr)) _n_ = (n);				      \
+	   (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,	      \
+	   			        (unsigned long)_n_, sizeof (*(ptr))); \
+	})
+
+#include <asm-generic/cmpxchg-local.h>
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+				      unsigned long old,
+				      unsigned long new, int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32(ptr, old, new);
+	default:
+		return __cmpxchg_local_generic(ptr, old, new, size);
+	}
+
+	return old;
+}
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)				  	       \
+	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+			(unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+/*
+ * xchg_u32
+ *
+ * Note that a15 is used here because the register allocation
+ * done by the compiler is not guaranteed and a window overflow
+ * may not occur between the rsil and wsr instructions. By using
+ * a15 in the rsil, the machine is guaranteed to be in a state
+ * where no register reference will cause an overflow.
+ */
+
+static inline unsigned long xchg_u32(volatile int * m, unsigned long val)
+{
+  unsigned long tmp;
+  __asm__ __volatile__("rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
+		       "l32i    %0, %1, 0              \n\t"
+		       "s32i    %2, %1, 0              \n\t"
+		       "wsr     a15, "__stringify(PS)" \n\t"
+		       "rsync                          \n\t"
+		       : "=&a" (tmp)
+		       : "a" (m), "a" (val)
+		       : "a15", "memory");
+  return tmp;
+}
+
+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+/*
+ * This only works if the compiler isn't horribly bad at optimizing.
+ * gcc-2.5.8 reportedly can't handle this, but I define that one to
+ * be dead anyway.
+ */
+
+extern void __xchg_called_with_bad_pointer(void);
+
+static __inline__ unsigned long
+__xchg(unsigned long x, volatile void * ptr, int size)
+{
+	switch (size) {
+		case 4:
+			return xchg_u32(ptr, x);
+	}
+	__xchg_called_with_bad_pointer();
+	return x;
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _XTENSA_CMPXCHG_H */
diff --git a/arch/xtensa/include/asm/exec.h b/arch/xtensa/include/asm/exec.h
new file mode 100644
index 0000000..af949e2
--- /dev/null
+++ b/arch/xtensa/include/asm/exec.h
@@ -0,0 +1,14 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_EXEC_H
+#define _XTENSA_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* _XTENSA_EXEC_H */
diff --git a/arch/xtensa/include/asm/mman.h b/arch/xtensa/include/asm/mman.h
index 3078901..25bc6c1 100644
--- a/arch/xtensa/include/asm/mman.h
+++ b/arch/xtensa/include/asm/mman.h
@@ -86,6 +86,10 @@
 #define MADV_HUGEPAGE	14		/* Worth backing with hugepages */
 #define MADV_NOHUGEPAGE	15		/* Not worth backing with hugepages */
 
+#define MADV_DONTDUMP   16		/* Explicity exclude from the core dump,
+					   overrides the coredump filter bits */
+#define MADV_DODUMP	17		/* Clear the MADV_NODUMP flag */
+
 /* compatibility flags */
 #define MAP_FILE	0
 
diff --git a/arch/xtensa/include/asm/posix_types.h b/arch/xtensa/include/asm/posix_types.h
index 6b2190c..6e96be0 100644
--- a/arch/xtensa/include/asm/posix_types.h
+++ b/arch/xtensa/include/asm/posix_types.h
@@ -19,104 +19,21 @@
  * assume GCC is being used.
  */
 
-typedef unsigned long	__kernel_ino_t;
-typedef unsigned int	__kernel_mode_t;
-typedef unsigned long	__kernel_nlink_t;
-typedef long		__kernel_off_t;
-typedef int		__kernel_pid_t;
 typedef unsigned short	__kernel_ipc_pid_t;
-typedef unsigned int	__kernel_uid_t;
-typedef unsigned int	__kernel_gid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
+
 typedef unsigned int	__kernel_size_t;
 typedef int		__kernel_ssize_t;
 typedef long		__kernel_ptrdiff_t;
-typedef long		__kernel_time_t;
-typedef long		__kernel_suseconds_t;
-typedef long		__kernel_clock_t;
-typedef int		__kernel_timer_t;
-typedef int		__kernel_clockid_t;
-typedef int		__kernel_daddr_t;
-typedef char *		__kernel_caddr_t;
-typedef unsigned short	__kernel_uid16_t;
-typedef unsigned short	__kernel_gid16_t;
-typedef unsigned int	__kernel_uid32_t;
-typedef unsigned int	__kernel_gid32_t;
+#define __kernel_size_t __kernel_size_t
 
 typedef unsigned short	__kernel_old_uid_t;
 typedef unsigned short	__kernel_old_gid_t;
+#define __kernel_old_uid_t __kernel_old_uid_t
+
 typedef unsigned short	__kernel_old_dev_t;
+#define __kernel_old_dev_t __kernel_old_dev_t
 
-#ifdef __GNUC__
-typedef long long	__kernel_loff_t;
-#endif
+#include <asm-generic/posix_types.h>
 
-typedef struct {
-	int	val[2];
-} __kernel_fsid_t;
-
-#ifndef __GNUC__
-
-#define	__FD_SET(d, set)	((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
-#define	__FD_CLR(d, set)	((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
-#define	__FD_ISSET(d, set)	(!!((set)->fds_bits[__FDELT(d)] & __FDMASK(d)))
-#define	__FD_ZERO(set)	\
-  ((void) memset ((void *) (set), 0, sizeof (__kernel_fd_set)))
-
-#else /* __GNUC__ */
-
-#if defined(__KERNEL__)
-/* With GNU C, use inline functions instead so args are evaluated only once: */
-
-#undef __FD_SET
-static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	fdsetp->fds_bits[_tmp] |= (1UL<<_rem);
-}
-
-#undef __FD_CLR
-static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem);
-}
-
-#undef __FD_ISSET
-static __inline__ int __FD_ISSET(unsigned long fd, __kernel_fd_set *p)
-{
-	unsigned long _tmp = fd / __NFDBITS;
-	unsigned long _rem = fd % __NFDBITS;
-	return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0;
-}
-
-/*
- * This will unroll the loop for the normal constant case (8 ints,
- * for a 256-bit fd_set)
- */
-#undef __FD_ZERO
-static __inline__ void __FD_ZERO(__kernel_fd_set *p)
-{
-	unsigned int *tmp = (unsigned int *)p->fds_bits;
-	int i;
-
-	if (__builtin_constant_p(__FDSET_LONGS)) {
-		switch (__FDSET_LONGS) {
-			case 8:
-				tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0;
-				tmp[4] = 0; tmp[5] = 0; tmp[6] = 0; tmp[7] = 0;
-				return;
-		}
-	}
-	i = __FDSET_LONGS;
-	while (i) {
-		i--;
-		*tmp = 0;
-		tmp++;
-	}
-}
-
-#endif /* defined(__KERNEL__) */
-#endif /* __GNUC__ */
 #endif /* _XTENSA_POSIX_TYPES_H */
diff --git a/arch/xtensa/include/asm/setup.h b/arch/xtensa/include/asm/setup.h
index e363652..9fa8ad9 100644
--- a/arch/xtensa/include/asm/setup.h
+++ b/arch/xtensa/include/asm/setup.h
@@ -13,4 +13,6 @@
 
 #define COMMAND_LINE_SIZE	256
 
+extern void set_except_vector(int n, void *addr);
+
 #endif
diff --git a/arch/xtensa/include/asm/switch_to.h b/arch/xtensa/include/asm/switch_to.h
new file mode 100644
index 0000000..6b73bf0
--- /dev/null
+++ b/arch/xtensa/include/asm/switch_to.h
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SWITCH_TO_H
+#define _XTENSA_SWITCH_TO_H
+
+/* * switch_to(n) should switch tasks to task nr n, first
+ * checking that n isn't the current task, in which case it does nothing.
+ */
+extern void *_switch_to(void *last, void *next);
+
+#define switch_to(prev,next,last)		\
+do {						\
+	(last) = _switch_to(prev, next);	\
+} while(0)
+
+#endif /* _XTENSA_SWITCH_TO_H */
diff --git a/arch/xtensa/include/asm/system.h b/arch/xtensa/include/asm/system.h
deleted file mode 100644
index 1e7e09a..0000000
--- a/arch/xtensa/include/asm/system.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * include/asm-xtensa/system.h
- *
- * 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.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_SYSTEM_H
-#define _XTENSA_SYSTEM_H
-
-#include <linux/stringify.h>
-#include <linux/irqflags.h>
-
-#include <asm/processor.h>
-
-#define smp_read_barrier_depends() do { } while(0)
-#define read_barrier_depends() do { } while(0)
-
-#define mb()  barrier()
-#define rmb() mb()
-#define wmb() mb()
-
-#ifdef CONFIG_SMP
-#error smp_* not defined
-#else
-#define smp_mb()	barrier()
-#define smp_rmb()	barrier()
-#define smp_wmb()	barrier()
-#endif
-
-#define set_mb(var, value)	do { var = value; mb(); } while (0)
-
-#if !defined (__ASSEMBLY__)
-
-/* * switch_to(n) should switch tasks to task nr n, first
- * checking that n isn't the current task, in which case it does nothing.
- */
-extern void *_switch_to(void *last, void *next);
-
-#endif	/* __ASSEMBLY__ */
-
-#define switch_to(prev,next,last)		\
-do {						\
-	(last) = _switch_to(prev, next);	\
-} while(0)
-
-/*
- * cmpxchg
- */
-
-static inline unsigned long
-__cmpxchg_u32(volatile int *p, int old, int new)
-{
-  __asm__ __volatile__("rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
-		       "l32i    %0, %1, 0              \n\t"
-		       "bne	%0, %2, 1f             \n\t"
-		       "s32i    %3, %1, 0              \n\t"
-		       "1:                             \n\t"
-		       "wsr     a15, "__stringify(PS)" \n\t"
-		       "rsync                          \n\t"
-		       : "=&a" (old)
-		       : "a" (p), "a" (old), "r" (new)
-		       : "a15", "memory");
-  return old;
-}
-/* This function doesn't exist, so you'll get a linker error
- * if something tries to do an invalid cmpxchg(). */
-
-extern void __cmpxchg_called_with_bad_pointer(void);
-
-static __inline__ unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
-{
-	switch (size) {
-	case 4:  return __cmpxchg_u32(ptr, old, new);
-	default: __cmpxchg_called_with_bad_pointer();
-		 return old;
-	}
-}
-
-#define cmpxchg(ptr,o,n)						      \
-	({ __typeof__(*(ptr)) _o_ = (o);				      \
-	   __typeof__(*(ptr)) _n_ = (n);				      \
-	   (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,	      \
-	   			        (unsigned long)_n_, sizeof (*(ptr))); \
-	})
-
-#include <asm-generic/cmpxchg-local.h>
-
-static inline unsigned long __cmpxchg_local(volatile void *ptr,
-				      unsigned long old,
-				      unsigned long new, int size)
-{
-	switch (size) {
-	case 4:
-		return __cmpxchg_u32(ptr, old, new);
-	default:
-		return __cmpxchg_local_generic(ptr, old, new, size);
-	}
-
-	return old;
-}
-
-/*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
- */
-#define cmpxchg_local(ptr, o, n)				  	       \
-	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
-			(unsigned long)(n), sizeof(*(ptr))))
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-
-/*
- * xchg_u32
- *
- * Note that a15 is used here because the register allocation
- * done by the compiler is not guaranteed and a window overflow
- * may not occur between the rsil and wsr instructions. By using
- * a15 in the rsil, the machine is guaranteed to be in a state
- * where no register reference will cause an overflow.
- */
-
-static inline unsigned long xchg_u32(volatile int * m, unsigned long val)
-{
-  unsigned long tmp;
-  __asm__ __volatile__("rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
-		       "l32i    %0, %1, 0              \n\t"
-		       "s32i    %2, %1, 0              \n\t"
-		       "wsr     a15, "__stringify(PS)" \n\t"
-		       "rsync                          \n\t"
-		       : "=&a" (tmp)
-		       : "a" (m), "a" (val)
-		       : "a15", "memory");
-  return tmp;
-}
-
-#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-
-/*
- * This only works if the compiler isn't horribly bad at optimizing.
- * gcc-2.5.8 reportedly can't handle this, but I define that one to
- * be dead anyway.
- */
-
-extern void __xchg_called_with_bad_pointer(void);
-
-static __inline__ unsigned long
-__xchg(unsigned long x, volatile void * ptr, int size)
-{
-	switch (size) {
-		case 4:
-			return xchg_u32(ptr, x);
-	}
-	__xchg_called_with_bad_pointer();
-	return x;
-}
-
-extern void set_except_vector(int n, void *addr);
-
-static inline void spill_registers(void)
-{
-	unsigned int a0, ps;
-
-	__asm__ __volatile__ (
-		"movi	a14," __stringify (PS_EXCM_BIT) " | 1\n\t"
-		"mov	a12, a0\n\t"
-		"rsr	a13," __stringify(SAR) "\n\t"
-		"xsr	a14," __stringify(PS) "\n\t"
-		"movi	a0, _spill_registers\n\t"
-		"rsync\n\t"
-		"callx0 a0\n\t"
-		"mov	a0, a12\n\t"
-		"wsr	a13," __stringify(SAR) "\n\t"
-		"wsr	a14," __stringify(PS) "\n\t"
-		:: "a" (&a0), "a" (&ps)
-		: "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15", "memory");
-}
-
-#define arch_align_stack(x) (x)
-
-#endif	/* _XTENSA_SYSTEM_H */
diff --git a/arch/xtensa/include/asm/uaccess.h b/arch/xtensa/include/asm/uaccess.h
index 3fa526f..6e4bb3b 100644
--- a/arch/xtensa/include/asm/uaccess.h
+++ b/arch/xtensa/include/asm/uaccess.h
@@ -17,7 +17,9 @@
 #define _XTENSA_UACCESS_H
 
 #include <linux/errno.h>
+#ifndef __ASSEMBLY__
 #include <linux/prefetch.h>
+#endif
 #include <asm/types.h>
 
 #define VERIFY_READ    0
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index 61045c1..eb30e35 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -153,7 +153,7 @@
 	}
 	res->start += io_offset;
 	res->end += io_offset;
-	pci_add_resource(resources, res);
+	pci_add_resource_offset(resources, res, io_offset);
 
 	for (i = 0; i < 3; i++) {
 		res = &pci_ctrl->mem_resources[i];
@@ -200,24 +200,9 @@
 
 void __init pcibios_fixup_bus(struct pci_bus *bus)
 {
-	struct pci_controller *pci_ctrl = bus->sysdata;
-	struct resource *res;
-	unsigned long io_offset;
-	int i;
-
-	io_offset = (unsigned long)pci_ctrl->io_space.base;
 	if (bus->parent) {
 		/* This is a subordinate bridge */
 		pci_read_bridge_bases(bus);
-
-		for (i = 0; i < 4; i++) {
-			if ((res = bus->resource[i]) == NULL || !res->flags)
-				continue;
-			if (io_offset && (res->flags & IORESOURCE_IO)) {
-				res->start += io_offset;
-				res->end += io_offset;
-			}
-		}
 	}
 }
 
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index 2c90047..6a2d6ed 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -34,7 +34,6 @@
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/platform.h>
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
index 2dff698..33eea4c 100644
--- a/arch/xtensa/kernel/ptrace.c
+++ b/arch/xtensa/kernel/ptrace.c
@@ -24,7 +24,6 @@
 
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/ptrace.h>
 #include <asm/elf.h>
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
index 1e5a034..17e746f 100644
--- a/arch/xtensa/kernel/setup.c
+++ b/arch/xtensa/kernel/setup.c
@@ -34,7 +34,6 @@
 # include <linux/seq_file.h>
 #endif
 
-#include <asm/system.h>
 #include <asm/bootparam.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
index f2220b5..b69b000 100644
--- a/arch/xtensa/kernel/signal.c
+++ b/arch/xtensa/kernel/signal.c
@@ -260,10 +260,7 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&set);
 
 	if (restore_sigcontext(regs, frame))
 		goto badframe;
@@ -336,8 +333,8 @@
 }
 
 
-static void setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-			sigset_t *set, struct pt_regs *regs)
+static int setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+		       sigset_t *set, struct pt_regs *regs)
 {
 	struct rt_sigframe *frame;
 	int err = 0;
@@ -422,12 +419,11 @@
 		current->comm, current->pid, signal, frame, regs->pc);
 #endif
 
-	return;
+	return 0;
 
 give_sigsegv:
-	if (sig == SIGSEGV)
-		ka->sa.sa_handler = SIG_DFL;
-	force_sig(SIGSEGV, current);
+	force_sigsegv(sig, current);
+	return -EFAULT;
 }
 
 /*
@@ -449,11 +445,8 @@
 		return -EFAULT;
 
 	sigdelsetmask(&newset, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
 	saveset = current->blocked;
-	current->blocked = newset;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	set_current_blocked(&newset);
 
 	regs->areg[2] = -EINTR;
 	while (1) {
@@ -536,17 +529,11 @@
 
 		/* Whee!  Actually deliver the signal.  */
 		/* Set up the stack frame */
-		setup_frame(signr, &ka, &info, oldset, regs);
+		ret = setup_frame(signr, &ka, &info, oldset, regs);
+		if (ret)
+			return ret;
 
-		if (ka.sa.sa_flags & SA_ONESHOT)
-			ka.sa.sa_handler = SIG_DFL;
-
-		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked, &current->blocked, &ka.sa.sa_mask);
-		if (!(ka.sa.sa_flags & SA_NODEFER))
-			sigaddset(&current->blocked, signr);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sighand->siglock);
+		block_sigmask(&ka, signr);
 		if (current->ptrace & PT_SINGLESTEP)
 			task_pt_regs(current)->icountlevel = 1;
 
diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c
index e64efac..bc1e14c 100644
--- a/arch/xtensa/kernel/traps.c
+++ b/arch/xtensa/kernel/traps.c
@@ -381,6 +381,25 @@
 	return sp;
 }
 
+static inline void spill_registers(void)
+{
+	unsigned int a0, ps;
+
+	__asm__ __volatile__ (
+		"movi	a14," __stringify (PS_EXCM_BIT) " | 1\n\t"
+		"mov	a12, a0\n\t"
+		"rsr	a13," __stringify(SAR) "\n\t"
+		"xsr	a14," __stringify(PS) "\n\t"
+		"movi	a0, _spill_registers\n\t"
+		"rsync\n\t"
+		"callx0 a0\n\t"
+		"mov	a0, a12\n\t"
+		"wsr	a13," __stringify(SAR) "\n\t"
+		"wsr	a14," __stringify(PS) "\n\t"
+		:: "a" (&a0), "a" (&ps)
+		: "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15", "memory");
+}
+
 void show_trace(struct task_struct *task, unsigned long *sp)
 {
 	unsigned long a0, a1, pc;
diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
index e367e30..b17885a 100644
--- a/arch/xtensa/mm/fault.c
+++ b/arch/xtensa/mm/fault.c
@@ -19,7 +19,6 @@
 #include <asm/cacheflush.h>
 #include <asm/hardirq.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/pgalloc.h>
 
 unsigned long asid_cache = ASID_USER_FIRST;
diff --git a/arch/xtensa/mm/tlb.c b/arch/xtensa/mm/tlb.c
index 239461d..e2700b2 100644
--- a/arch/xtensa/mm/tlb.c
+++ b/arch/xtensa/mm/tlb.c
@@ -18,7 +18,6 @@
 #include <asm/processor.h>
 #include <asm/mmu_context.h>
 #include <asm/tlbflush.h>
-#include <asm/system.h>
 #include <asm/cacheflush.h>
 
 
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 6318edd..21ff9d0 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -308,6 +308,7 @@
 config CRYPTO_CRC32C
 	tristate "CRC32c CRC algorithm"
 	select CRYPTO_HASH
+	select CRC32
 	help
 	  Castagnoli, et al Cyclic Redundancy-Check Algorithm.  Used
 	  by iSCSI for header and data digests and by others.
diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c
index a0f768c..8d3a056 100644
--- a/crypto/ablkcipher.c
+++ b/crypto/ablkcipher.c
@@ -613,8 +613,7 @@
 	return err;
 }
 
-static struct crypto_alg *crypto_lookup_skcipher(const char *name, u32 type,
-						 u32 mask)
+struct crypto_alg *crypto_lookup_skcipher(const char *name, u32 type, u32 mask)
 {
 	struct crypto_alg *alg;
 
@@ -652,6 +651,7 @@
 
 	return ERR_PTR(crypto_givcipher_default(alg, type, mask));
 }
+EXPORT_SYMBOL_GPL(crypto_lookup_skcipher);
 
 int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name,
 			 u32 type, u32 mask)
diff --git a/crypto/aead.c b/crypto/aead.c
index 04add3dc..e4cb351 100644
--- a/crypto/aead.c
+++ b/crypto/aead.c
@@ -470,8 +470,7 @@
 	return err;
 }
 
-static struct crypto_alg *crypto_lookup_aead(const char *name, u32 type,
-					     u32 mask)
+struct crypto_alg *crypto_lookup_aead(const char *name, u32 type, u32 mask)
 {
 	struct crypto_alg *alg;
 
@@ -503,6 +502,7 @@
 
 	return ERR_PTR(crypto_nivaead_default(alg, type, mask));
 }
+EXPORT_SYMBOL_GPL(crypto_lookup_aead);
 
 int crypto_grab_aead(struct crypto_aead_spawn *spawn, const char *name,
 		     u32 type, u32 mask)
diff --git a/crypto/crc32c.c b/crypto/crc32c.c
index 3f9ad28..06f7018 100644
--- a/crypto/crc32c.c
+++ b/crypto/crc32c.c
@@ -40,6 +40,7 @@
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/crc32.h>
 
 #define CHKSUM_BLOCK_SIZE	1
 #define CHKSUM_DIGEST_SIZE	4
@@ -53,95 +54,6 @@
 };
 
 /*
- * This is the CRC-32C table
- * Generated with:
- * width = 32 bits
- * poly = 0x1EDC6F41
- * reflect input bytes = true
- * reflect output bytes = true
- */
-
-static const u32 crc32c_table[256] = {
-	0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
-	0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
-	0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
-	0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
-	0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
-	0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
-	0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
-	0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
-	0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
-	0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
-	0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
-	0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
-	0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
-	0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
-	0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
-	0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
-	0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
-	0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
-	0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
-	0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
-	0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
-	0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
-	0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
-	0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
-	0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
-	0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
-	0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
-	0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
-	0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
-	0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
-	0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
-	0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
-	0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
-	0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
-	0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
-	0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
-	0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
-	0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
-	0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
-	0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
-	0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
-	0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
-	0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
-	0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
-	0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
-	0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
-	0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
-	0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
-	0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
-	0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
-	0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
-	0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
-	0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
-	0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
-	0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
-	0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
-	0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
-	0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
-	0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
-	0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
-	0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
-	0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
-	0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
-	0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
-};
-
-/*
- * Steps through buffer one byte at at time, calculates reflected
- * crc using table.
- */
-
-static u32 crc32c(u32 crc, const u8 *data, unsigned int length)
-{
-	while (length--)
-		crc = crc32c_table[(crc ^ *data++) & 0xFFL] ^ (crc >> 8);
-
-	return crc;
-}
-
-/*
  * Steps through buffer one byte at at time, calculates reflected
  * crc using table.
  */
@@ -179,7 +91,7 @@
 {
 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 
-	ctx->crc = crc32c(ctx->crc, data, length);
+	ctx->crc = __crc32c_le(ctx->crc, data, length);
 	return 0;
 }
 
@@ -193,7 +105,7 @@
 
 static int __chksum_finup(u32 *crcp, const u8 *data, unsigned int len, u8 *out)
 {
-	*(__le32 *)out = ~cpu_to_le32(crc32c(*crcp, data, len));
+	*(__le32 *)out = ~cpu_to_le32(__crc32c_le(*crcp, data, len));
 	return 0;
 }
 
diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c
index f76e42b..f1ea0a0 100644
--- a/crypto/crypto_user.c
+++ b/crypto/crypto_user.c
@@ -21,9 +21,13 @@
 #include <linux/module.h>
 #include <linux/crypto.h>
 #include <linux/cryptouser.h>
+#include <linux/sched.h>
 #include <net/netlink.h>
 #include <linux/security.h>
 #include <net/net_namespace.h>
+#include <crypto/internal/aead.h>
+#include <crypto/internal/skcipher.h>
+
 #include "internal.h"
 
 DEFINE_MUTEX(crypto_cfg_mutex);
@@ -301,6 +305,60 @@
 	return crypto_unregister_instance(alg);
 }
 
+static struct crypto_alg *crypto_user_skcipher_alg(const char *name, u32 type,
+						   u32 mask)
+{
+	int err;
+	struct crypto_alg *alg;
+
+	type = crypto_skcipher_type(type);
+	mask = crypto_skcipher_mask(mask);
+
+	for (;;) {
+		alg = crypto_lookup_skcipher(name,  type, mask);
+		if (!IS_ERR(alg))
+			return alg;
+
+		err = PTR_ERR(alg);
+		if (err != -EAGAIN)
+			break;
+		if (signal_pending(current)) {
+			err = -EINTR;
+			break;
+		}
+	}
+
+	return ERR_PTR(err);
+}
+
+static struct crypto_alg *crypto_user_aead_alg(const char *name, u32 type,
+					       u32 mask)
+{
+	int err;
+	struct crypto_alg *alg;
+
+	type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+	type |= CRYPTO_ALG_TYPE_AEAD;
+	mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+	mask |= CRYPTO_ALG_TYPE_MASK;
+
+	for (;;) {
+		alg = crypto_lookup_aead(name,  type, mask);
+		if (!IS_ERR(alg))
+			return alg;
+
+		err = PTR_ERR(alg);
+		if (err != -EAGAIN)
+			break;
+		if (signal_pending(current)) {
+			err = -EINTR;
+			break;
+		}
+	}
+
+	return ERR_PTR(err);
+}
+
 static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
 			  struct nlattr **attrs)
 {
@@ -325,7 +383,19 @@
 	else
 		name = p->cru_name;
 
-	alg = crypto_alg_mod_lookup(name, p->cru_type, p->cru_mask);
+	switch (p->cru_type & p->cru_mask & CRYPTO_ALG_TYPE_MASK) {
+	case CRYPTO_ALG_TYPE_AEAD:
+		alg = crypto_user_aead_alg(name, p->cru_type, p->cru_mask);
+		break;
+	case CRYPTO_ALG_TYPE_GIVCIPHER:
+	case CRYPTO_ALG_TYPE_BLKCIPHER:
+	case CRYPTO_ALG_TYPE_ABLKCIPHER:
+		alg = crypto_user_skcipher_alg(name, p->cru_type, p->cru_mask);
+		break;
+	default:
+		alg = crypto_alg_mod_lookup(name, p->cru_type, p->cru_mask);
+	}
+
 	if (IS_ERR(alg))
 		return PTR_ERR(alg);
 
@@ -387,12 +457,20 @@
 
 	if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) &&
 	    (nlh->nlmsg_flags & NLM_F_DUMP))) {
+		struct crypto_alg *alg;
+		u16 dump_alloc = 0;
+
 		if (link->dump == NULL)
 			return -EINVAL;
+
+		list_for_each_entry(alg, &crypto_alg_list, cra_list)
+			dump_alloc += CRYPTO_REPORT_MAXSIZE;
+
 		{
 			struct netlink_dump_control c = {
 				.dump = link->dump,
 				.done = link->done,
+				.min_dump_alloc = dump_alloc,
 			};
 			return netlink_dump_start(crypto_nlsk, skb, nlh, &c);
 		}
diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c
index 29a89da..b2c99dc 100644
--- a/crypto/pcrypt.c
+++ b/crypto/pcrypt.c
@@ -280,11 +280,11 @@
 
 	ictx->tfm_count++;
 
-	cpu_index = ictx->tfm_count % cpumask_weight(cpu_active_mask);
+	cpu_index = ictx->tfm_count % cpumask_weight(cpu_online_mask);
 
-	ctx->cb_cpu = cpumask_first(cpu_active_mask);
+	ctx->cb_cpu = cpumask_first(cpu_online_mask);
 	for (cpu = 0; cpu < cpu_index; cpu++)
-		ctx->cb_cpu = cpumask_next(ctx->cb_cpu, cpu_active_mask);
+		ctx->cb_cpu = cpumask_next(ctx->cb_cpu, cpu_online_mask);
 
 	cipher = crypto_spawn_aead(crypto_instance_ctx(inst));
 
@@ -472,7 +472,7 @@
 		goto err_free_padata;
 	}
 
-	cpumask_and(mask->mask, cpu_possible_mask, cpu_active_mask);
+	cpumask_and(mask->mask, cpu_possible_mask, cpu_online_mask);
 	rcu_assign_pointer(pcrypt->cb_cpumask, mask);
 
 	pcrypt->nblock.notifier_call = pcrypt_cpumask_change_notify;
diff --git a/drivers/Kconfig b/drivers/Kconfig
index decf8e4..d236aef 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -50,6 +50,8 @@
 
 source "drivers/spi/Kconfig"
 
+source "drivers/hsi/Kconfig"
+
 source "drivers/pps/Kconfig"
 
 source "drivers/ptp/Kconfig"
@@ -130,6 +132,10 @@
 
 source "drivers/iommu/Kconfig"
 
+source "drivers/remoteproc/Kconfig"
+
+source "drivers/rpmsg/Kconfig"
+
 source "drivers/virt/Kconfig"
 
 source "drivers/devfreq/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 932e8bf..95952c8 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -53,6 +53,7 @@
 obj-$(CONFIG_TARGET_CORE)	+= target/
 obj-$(CONFIG_MTD)		+= mtd/
 obj-$(CONFIG_SPI)		+= spi/
+obj-y				+= hsi/
 obj-y				+= net/
 obj-$(CONFIG_ATM)		+= atm/
 obj-$(CONFIG_FUSION)		+= message/
@@ -125,6 +126,8 @@
 obj-$(CONFIG_HWSPINLOCK)	+= hwspinlock/
 obj-$(CONFIG_NFC)		+= nfc/
 obj-$(CONFIG_IOMMU_SUPPORT)	+= iommu/
+obj-$(CONFIG_REMOTEPROC)	+= remoteproc/
+obj-$(CONFIG_RPMSG)		+= rpmsg/
 
 # Virtualization drivers
 obj-$(CONFIG_VIRT_DRIVERS)	+= virt/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 7556913..47768ff 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -384,6 +384,15 @@
 	  load additional kernel modules after boot, this feature may be used
 	  to override that restriction).
 
+config ACPI_BGRT
+        tristate "Boottime Graphics Resource Table support"
+        default n
+        help
+	  This driver adds support for exposing the ACPI Boottime Graphics
+	  Resource Table, which allows the operating system to obtain
+	  data from the firmware boot splash. It will appear under
+	  /sys/firmware/acpi/bgrt/ .
+
 source "drivers/acpi/apei/Kconfig"
 
 endif	# ACPI
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 1567028..47199e2 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -62,6 +62,7 @@
 obj-$(CONFIG_ACPI_HED)		+= hed.o
 obj-$(CONFIG_ACPI_EC_DEBUGFS)	+= ec_sys.o
 obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
+obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
 
 # processor has its own "processor." module_param namespace
 processor-y			:= processor_driver.o processor_throttling.o
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index 0ca208b..793b8cc 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -68,12 +68,14 @@
 
 acpi-y +=		\
 	hwacpi.o	\
+	hwesleep.o	\
 	hwgpe.o		\
 	hwpci.o		\
 	hwregs.o	\
 	hwsleep.o	\
 	hwvalid.o	\
-	hwxface.o
+	hwxface.o	\
+	hwxfsleep.o
 
 acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o
 
diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h
index a44bd42..8a7d51b 100644
--- a/drivers/acpi/acpica/accommon.h
+++ b/drivers/acpi/acpica/accommon.h
@@ -51,7 +51,6 @@
  *
  * Note: The order of these include files is important.
  */
-#include "acconfig.h"		/* Global configuration constants */
 #include "acmacros.h"		/* C macros */
 #include "aclocal.h"		/* Internal data types */
 #include "acobject.h"		/* ACPI internal object */
diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h
deleted file mode 100644
index 1f30af6..0000000
--- a/drivers/acpi/acpica/acconfig.h
+++ /dev/null
@@ -1,231 +0,0 @@
-/******************************************************************************
- *
- * Name: acconfig.h - Global configuration constants
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2012, Intel Corp.
- * All rights reserved.
- *
- * 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 at minimum a disclaimer
- *    substantially similar to the "NO WARRANTY" disclaimer below
- *    ("Disclaimer") and any redistribution must be conditioned upon
- *    including a substantially similar Disclaimer requirement for further
- *    binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * 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.
- *
- * NO WARRANTY
- * 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 MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#ifndef _ACCONFIG_H
-#define _ACCONFIG_H
-
-/******************************************************************************
- *
- * Configuration options
- *
- *****************************************************************************/
-
-/*
- * ACPI_DEBUG_OUTPUT    - This switch enables all the debug facilities of the
- *                        ACPI subsystem.  This includes the DEBUG_PRINT output
- *                        statements.  When disabled, all DEBUG_PRINT
- *                        statements are compiled out.
- *
- * ACPI_APPLICATION     - Use this switch if the subsystem is going to be run
- *                        at the application level.
- *
- */
-
-/*
- * OS name, used for the _OS object.  The _OS object is essentially obsolete,
- * but there is a large base of ASL/AML code in existing machines that check
- * for the string below.  The use of this string usually guarantees that
- * the ASL will execute down the most tested code path.  Also, there is some
- * code that will not execute the _OSI method unless _OS matches the string
- * below.  Therefore, change this string at your own risk.
- */
-#define ACPI_OS_NAME                    "Microsoft Windows NT"
-
-/* Maximum objects in the various object caches */
-
-#define ACPI_MAX_STATE_CACHE_DEPTH      96	/* State objects */
-#define ACPI_MAX_PARSE_CACHE_DEPTH      96	/* Parse tree objects */
-#define ACPI_MAX_EXTPARSE_CACHE_DEPTH   96	/* Parse tree objects */
-#define ACPI_MAX_OBJECT_CACHE_DEPTH     96	/* Interpreter operand objects */
-#define ACPI_MAX_NAMESPACE_CACHE_DEPTH  96	/* Namespace objects */
-
-/*
- * Should the subsystem abort the loading of an ACPI table if the
- * table checksum is incorrect?
- */
-#define ACPI_CHECKSUM_ABORT             FALSE
-
-/******************************************************************************
- *
- * Subsystem Constants
- *
- *****************************************************************************/
-
-/* Version of ACPI supported */
-
-#define ACPI_CA_SUPPORT_LEVEL           3
-
-/* Maximum count for a semaphore object */
-
-#define ACPI_MAX_SEMAPHORE_COUNT        256
-
-/* Maximum object reference count (detects object deletion issues) */
-
-#define ACPI_MAX_REFERENCE_COUNT        0x1000
-
-/* Default page size for use in mapping memory for operation regions */
-
-#define ACPI_DEFAULT_PAGE_SIZE          4096	/* Must be power of 2 */
-
-/* owner_id tracking. 8 entries allows for 255 owner_ids */
-
-#define ACPI_NUM_OWNERID_MASKS          8
-
-/* Size of the root table array is increased by this increment */
-
-#define ACPI_ROOT_TABLE_SIZE_INCREMENT  4
-
-/* Maximum number of While() loop iterations before forced abort */
-
-#define ACPI_MAX_LOOP_ITERATIONS        0xFFFF
-
-/* Maximum sleep allowed via Sleep() operator */
-
-#define ACPI_MAX_SLEEP                  2000	/* Two seconds */
-
-/* Address Range lists are per-space_id (Memory and I/O only) */
-
-#define ACPI_ADDRESS_RANGE_MAX          2
-
-/******************************************************************************
- *
- * ACPI Specification constants (Do not change unless the specification changes)
- *
- *****************************************************************************/
-
-/* Number of distinct GPE register blocks and register width */
-
-#define ACPI_MAX_GPE_BLOCKS             2
-#define ACPI_GPE_REGISTER_WIDTH         8
-
-/* Method info (in WALK_STATE), containing local variables and argumetns */
-
-#define ACPI_METHOD_NUM_LOCALS          8
-#define ACPI_METHOD_MAX_LOCAL           7
-
-#define ACPI_METHOD_NUM_ARGS            7
-#define ACPI_METHOD_MAX_ARG             6
-
-/* Length of _HID, _UID, _CID, and UUID values */
-
-#define ACPI_DEVICE_ID_LENGTH           0x09
-#define ACPI_MAX_CID_LENGTH             48
-#define ACPI_UUID_LENGTH                16
-
-/*
- * Operand Stack (in WALK_STATE), Must be large enough to contain METHOD_MAX_ARG
- */
-#define ACPI_OBJ_NUM_OPERANDS           8
-#define ACPI_OBJ_MAX_OPERAND            7
-
-/* Number of elements in the Result Stack frame, can be an arbitrary value */
-
-#define ACPI_RESULTS_FRAME_OBJ_NUM      8
-
-/*
- * Maximal number of elements the Result Stack can contain,
- * it may be an arbitray value not exceeding the types of
- * result_size and result_count (now u8).
- */
-#define ACPI_RESULTS_OBJ_NUM_MAX        255
-
-/* Names within the namespace are 4 bytes long */
-
-#define ACPI_NAME_SIZE                  4
-#define ACPI_PATH_SEGMENT_LENGTH        5	/* 4 chars for name + 1 char for separator */
-#define ACPI_PATH_SEPARATOR             '.'
-
-/* Sizes for ACPI table headers */
-
-#define ACPI_OEM_ID_SIZE                6
-#define ACPI_OEM_TABLE_ID_SIZE          8
-
-/* Constants used in searching for the RSDP in low memory */
-
-#define ACPI_EBDA_PTR_LOCATION          0x0000040E	/* Physical Address */
-#define ACPI_EBDA_PTR_LENGTH            2
-#define ACPI_EBDA_WINDOW_SIZE           1024
-#define ACPI_HI_RSDP_WINDOW_BASE        0x000E0000	/* Physical Address */
-#define ACPI_HI_RSDP_WINDOW_SIZE        0x00020000
-#define ACPI_RSDP_SCAN_STEP             16
-
-/* Operation regions */
-
-#define ACPI_USER_REGION_BEGIN          0x80
-
-/* Maximum space_ids for Operation Regions */
-
-#define ACPI_MAX_ADDRESS_SPACE          255
-
-/* Array sizes.  Used for range checking also */
-
-#define ACPI_MAX_MATCH_OPCODE           5
-
-/* RSDP checksums */
-
-#define ACPI_RSDP_CHECKSUM_LENGTH       20
-#define ACPI_RSDP_XCHECKSUM_LENGTH      36
-
-/* SMBus, GSBus and IPMI bidirectional buffer size */
-
-#define ACPI_SMBUS_BUFFER_SIZE          34
-#define ACPI_GSBUS_BUFFER_SIZE          34
-#define ACPI_IPMI_BUFFER_SIZE           66
-
-/* _sx_d and _sx_w control methods */
-
-#define ACPI_NUM_sx_d_METHODS           4
-#define ACPI_NUM_sx_w_METHODS           5
-
-/******************************************************************************
- *
- * ACPI AML Debugger
- *
- *****************************************************************************/
-
-#define ACPI_DEBUGGER_MAX_ARGS          8	/* Must be max method args + 1 */
-
-#define ACPI_DEBUGGER_COMMAND_PROMPT    '-'
-#define ACPI_DEBUGGER_EXECUTE_PROMPT    '%'
-
-#endif				/* _ACCONFIG_H */
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index deaa819..5e8abb0 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -111,7 +111,7 @@
 
 void acpi_db_set_scope(char *name);
 
-acpi_status acpi_db_sleep(char *object_arg);
+ACPI_HW_DEPENDENT_RETURN_OK(acpi_status acpi_db_sleep(char *object_arg))
 
 void acpi_db_find_references(char *object_arg);
 
@@ -119,11 +119,13 @@
 
 void acpi_db_display_resources(char *object_arg);
 
-void acpi_db_display_gpes(void);
+ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_db_display_gpes(void))
 
 void acpi_db_check_integrity(void);
 
-void acpi_db_generate_gpe(char *gpe_arg, char *block_arg);
+ACPI_HW_DEPENDENT_RETURN_VOID(void
+			      acpi_db_generate_gpe(char *gpe_arg,
+						   char *block_arg))
 
 void acpi_db_check_predefined_names(void);
 
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index c53caa5..d700f63 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -69,11 +69,10 @@
  */
 acpi_status acpi_ev_init_global_lock_handler(void);
 
-acpi_status acpi_ev_acquire_global_lock(u16 timeout);
-
-acpi_status acpi_ev_release_global_lock(void);
-
-acpi_status acpi_ev_remove_global_lock_handler(void);
+ACPI_HW_DEPENDENT_RETURN_OK(acpi_status
+			    acpi_ev_acquire_global_lock(u16 timeout))
+ ACPI_HW_DEPENDENT_RETURN_OK(acpi_status acpi_ev_release_global_lock(void))
+ acpi_status acpi_ev_remove_global_lock_handler(void);
 
 /*
  * evgpe - Low-level GPE support
@@ -114,7 +113,9 @@
 			     struct acpi_gpe_block_info *gpe_block,
 			     void *context);
 
-acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block);
+ACPI_HW_DEPENDENT_RETURN_OK(acpi_status
+			    acpi_ev_delete_gpe_block(struct acpi_gpe_block_info
+						     *gpe_block))
 
 u32
 acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
@@ -126,9 +127,10 @@
  */
 acpi_status acpi_ev_gpe_initialize(void);
 
-void acpi_ev_update_gpes(acpi_owner_id table_owner_id);
+ACPI_HW_DEPENDENT_RETURN_VOID(void
+			      acpi_ev_update_gpes(acpi_owner_id table_owner_id))
 
-acpi_status
+ acpi_status
 acpi_ev_match_gpe_method(acpi_handle obj_handle,
 			 u32 level, void *context, void **return_value);
 
@@ -237,6 +239,5 @@
 
 u32 acpi_ev_initialize_sCI(u32 program_sCI);
 
-void acpi_ev_terminate(void);
-
+ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_ev_terminate(void))
 #endif				/* __ACEVENTS_H__  */
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 2853f76..4f7d3f5 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -147,7 +147,7 @@
  */
 u8 acpi_gbl_reduced_hardware;
 
-#endif
+#endif				/* DEFINE_ACPI_GLOBALS */
 
 /* Do not disassemble buffers to resource descriptors */
 
@@ -184,8 +184,12 @@
  * found in the RSDT/XSDT.
  */
 ACPI_EXTERN struct acpi_table_list acpi_gbl_root_table_list;
+
+#if (!ACPI_REDUCED_HARDWARE)
 ACPI_EXTERN struct acpi_table_facs *acpi_gbl_FACS;
 
+#endif				/* !ACPI_REDUCED_HARDWARE */
+
 /* These addresses are calculated from the FADT Event Block addresses */
 
 ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_status;
@@ -397,10 +401,15 @@
 ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
 ACPI_EXTERN struct acpi_gpe_block_info
 *acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
+
+#if (!ACPI_REDUCED_HARDWARE)
+
 ACPI_EXTERN u8 acpi_gbl_all_gpes_initialized;
 ACPI_EXTERN ACPI_GBL_EVENT_HANDLER acpi_gbl_global_event_handler;
 ACPI_EXTERN void *acpi_gbl_global_event_handler_context;
 
+#endif				/* !ACPI_REDUCED_HARDWARE */
+
 /*****************************************************************************
  *
  * Debugger globals
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
index 677793e..5ccb99a 100644
--- a/drivers/acpi/acpica/achware.h
+++ b/drivers/acpi/acpica/achware.h
@@ -81,6 +81,26 @@
 acpi_status acpi_hw_clear_acpi_status(void);
 
 /*
+ * hwsleep - sleep/wake support (Legacy sleep registers)
+ */
+acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags);
+
+acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags);
+
+acpi_status acpi_hw_legacy_wake(u8 sleep_state, u8 flags);
+
+/*
+ * hwesleep - sleep/wake support (Extended FADT-V5 sleep registers)
+ */
+void acpi_hw_execute_sleep_method(char *method_name, u32 integer_argument);
+
+acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags);
+
+acpi_status acpi_hw_extended_wake_prep(u8 sleep_state, u8 flags);
+
+acpi_status acpi_hw_extended_wake(u8 sleep_state, u8 flags);
+
+/*
  * hwvalid - Port I/O with validation
  */
 acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width);
@@ -128,16 +148,4 @@
 acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
 		      acpi_handle root_pci_device, acpi_handle pci_region);
 
-#ifdef	ACPI_FUTURE_USAGE
-/*
- * hwtimer - ACPI Timer prototypes
- */
-acpi_status acpi_get_timer_resolution(u32 * resolution);
-
-acpi_status acpi_get_timer(u32 * ticks);
-
-acpi_status
-acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed);
-#endif				/* ACPI_FUTURE_USAGE */
-
 #endif				/* __ACHWARE_H__ */
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 3f24068..e3922ca 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -370,6 +370,7 @@
 /* Defines for Flags field above */
 
 #define ACPI_OBJECT_REPAIRED    1
+#define ACPI_OBJECT_WRAPPED     2
 
 /*
  * Bitmapped return value types
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index ef338a9..f119f47 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -516,6 +516,12 @@
 
 #endif				/* ACPI_DEBUG_OUTPUT */
 
+#if (!ACPI_REDUCED_HARDWARE)
+#define ACPI_HW_OPTIONAL_FUNCTION(addr)     addr
+#else
+#define ACPI_HW_OPTIONAL_FUNCTION(addr)     NULL
+#endif
+
 /*
  * Some code only gets executed when the debugger is built in.
  * Note that this is entirely independent of whether the
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index 2c9e0f0..9b19d4b 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -283,8 +283,9 @@
 		      union acpi_operand_object **return_object_ptr);
 
 acpi_status
-acpi_ns_repair_package_list(struct acpi_predefined_data *data,
-			    union acpi_operand_object **obj_desc_ptr);
+acpi_ns_wrap_with_package(struct acpi_predefined_data *data,
+			  union acpi_operand_object *original_object,
+			  union acpi_operand_object **obj_desc_ptr);
 
 acpi_status
 acpi_ns_repair_null_element(struct acpi_predefined_data *data,
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
index d5bec30..6712965 100644
--- a/drivers/acpi/acpica/actables.h
+++ b/drivers/acpi/acpica/actables.h
@@ -67,6 +67,11 @@
 
 acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc);
 
+struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header
+						 *table_header,
+						 struct acpi_table_desc
+						 *table_desc);
+
 acpi_status
 acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index);
 
diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c
index 6729ebe..07e4dc4 100644
--- a/drivers/acpi/acpica/evevent.c
+++ b/drivers/acpi/acpica/evevent.c
@@ -47,7 +47,7 @@
 
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evevent")
-
+#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
 /* Local prototypes */
 static acpi_status acpi_ev_fixed_event_initialize(void);
 
@@ -291,3 +291,5 @@
 	return ((acpi_gbl_fixed_event_handlers[event].
 		 handler) (acpi_gbl_fixed_event_handlers[event].context));
 }
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/evglock.c b/drivers/acpi/acpica/evglock.c
index 5e5683c..cfeab38 100644
--- a/drivers/acpi/acpica/evglock.c
+++ b/drivers/acpi/acpica/evglock.c
@@ -48,7 +48,7 @@
 
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evglock")
-
+#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
 /* Local prototypes */
 static u32 acpi_ev_global_lock_handler(void *context);
 
@@ -339,3 +339,5 @@
 	acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex);
 	return_ACPI_STATUS(status);
 }
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index 9e88cb6..8ba0e5f 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -48,7 +48,7 @@
 
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evgpe")
-
+#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
 /* Local prototypes */
 static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context);
 
@@ -766,3 +766,5 @@
 
 	return_UINT32(ACPI_INTERRUPT_HANDLED);
 }
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index be75339..23a3ca8 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -48,7 +48,7 @@
 
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evgpeblk")
-
+#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
 /* Local prototypes */
 static acpi_status
 acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
@@ -504,3 +504,5 @@
 
 	return_ACPI_STATUS(AE_OK);
 }
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index adf7494..da0add8 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -48,7 +48,7 @@
 
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evgpeinit")
-
+#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
 /*
  * Note: History of _PRW support in ACPICA
  *
@@ -440,3 +440,5 @@
 			  name, gpe_number));
 	return_ACPI_STATUS(AE_OK);
 }
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c
index 2507393..3c43796 100644
--- a/drivers/acpi/acpica/evgpeutil.c
+++ b/drivers/acpi/acpica/evgpeutil.c
@@ -48,6 +48,7 @@
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evgpeutil")
 
+#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ev_walk_gpe_list
@@ -374,3 +375,5 @@
 
 	return_ACPI_STATUS(AE_OK);
 }
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c
index 84966f4..51ef9f5 100644
--- a/drivers/acpi/acpica/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -108,27 +108,30 @@
 	ACPI_FUNCTION_NAME(ev_queue_notify_request);
 
 	/*
-	 * For value 3 (Ejection Request), some device method may need to be run.
-	 * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need
-	 *   to be run.
+	 * For value 0x03 (Ejection Request), may need to run a device method.
+	 * For value 0x02 (Device Wake), if _PRW exists, may need to run
+	 *   the _PS0 method.
 	 * For value 0x80 (Status Change) on the power button or sleep button,
-	 *   initiate soft-off or sleep operation?
+	 *   initiate soft-off or sleep operation.
+	 *
+	 * For all cases, simply dispatch the notify to the handler.
 	 */
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-			  "Dispatching Notify on [%4.4s] Node %p Value 0x%2.2X (%s)\n",
-			  acpi_ut_get_node_name(node), node, notify_value,
-			  acpi_ut_get_notify_name(notify_value)));
+			  "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
+			  acpi_ut_get_node_name(node),
+			  acpi_ut_get_type_name(node->type), notify_value,
+			  acpi_ut_get_notify_name(notify_value), node));
 
 	/* Get the notify object attached to the NS Node */
 
 	obj_desc = acpi_ns_get_attached_object(node);
 	if (obj_desc) {
 
-		/* We have the notify object, Get the right handler */
+		/* We have the notify object, Get the correct handler */
 
 		switch (node->type) {
 
-			/* Notify allowed only on these types */
+			/* Notify is allowed only on these types */
 
 		case ACPI_TYPE_DEVICE:
 		case ACPI_TYPE_THERMAL:
@@ -152,7 +155,7 @@
 	}
 
 	/*
-	 * If there is any handler to run, schedule the dispatcher.
+	 * If there is a handler to run, schedule the dispatcher.
 	 * Check for:
 	 * 1) Global system notify handler
 	 * 2) Global device notify handler
@@ -270,6 +273,7 @@
 	acpi_ut_delete_generic_state(notify_info);
 }
 
+#if (!ACPI_REDUCED_HARDWARE)
 /******************************************************************************
  *
  * FUNCTION:    acpi_ev_terminate
@@ -338,3 +342,5 @@
 	}
 	return_VOID;
 }
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c
index 26065c6..6a57aa2 100644
--- a/drivers/acpi/acpica/evsci.c
+++ b/drivers/acpi/acpica/evsci.c
@@ -48,7 +48,7 @@
 
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evsci")
-
+#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
 /* Local prototypes */
 static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context);
 
@@ -181,3 +181,5 @@
 
 	return_ACPI_STATUS(status);
 }
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 61944e8..44bef57 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -51,222 +51,6 @@
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evxface")
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_install_exception_handler
- *
- * PARAMETERS:  Handler         - Pointer to the handler function for the
- *                                event
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Saves the pointer to the handler function
- *
- ******************************************************************************/
-#ifdef ACPI_FUTURE_USAGE
-acpi_status acpi_install_exception_handler(acpi_exception_handler handler)
-{
-	acpi_status status;
-
-	ACPI_FUNCTION_TRACE(acpi_install_exception_handler);
-
-	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Don't allow two handlers. */
-
-	if (acpi_gbl_exception_handler) {
-		status = AE_ALREADY_EXISTS;
-		goto cleanup;
-	}
-
-	/* Install the handler */
-
-	acpi_gbl_exception_handler = handler;
-
-      cleanup:
-	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-	return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_install_exception_handler)
-#endif				/*  ACPI_FUTURE_USAGE  */
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_install_global_event_handler
- *
- * PARAMETERS:  Handler         - Pointer to the global event handler function
- *              Context         - Value passed to the handler on each event
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Saves the pointer to the handler function. The global handler
- *              is invoked upon each incoming GPE and Fixed Event. It is
- *              invoked at interrupt level at the time of the event dispatch.
- *              Can be used to update event counters, etc.
- *
- ******************************************************************************/
-acpi_status
-acpi_install_global_event_handler(ACPI_GBL_EVENT_HANDLER handler, void *context)
-{
-	acpi_status status;
-
-	ACPI_FUNCTION_TRACE(acpi_install_global_event_handler);
-
-	/* Parameter validation */
-
-	if (!handler) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Don't allow two handlers. */
-
-	if (acpi_gbl_global_event_handler) {
-		status = AE_ALREADY_EXISTS;
-		goto cleanup;
-	}
-
-	acpi_gbl_global_event_handler = handler;
-	acpi_gbl_global_event_handler_context = context;
-
-      cleanup:
-	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-	return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_install_global_event_handler)
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_install_fixed_event_handler
- *
- * PARAMETERS:  Event           - Event type to enable.
- *              Handler         - Pointer to the handler function for the
- *                                event
- *              Context         - Value passed to the handler on each GPE
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Saves the pointer to the handler function and then enables the
- *              event.
- *
- ******************************************************************************/
-acpi_status
-acpi_install_fixed_event_handler(u32 event,
-				 acpi_event_handler handler, void *context)
-{
-	acpi_status status;
-
-	ACPI_FUNCTION_TRACE(acpi_install_fixed_event_handler);
-
-	/* Parameter validation */
-
-	if (event > ACPI_EVENT_MAX) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Don't allow two handlers. */
-
-	if (NULL != acpi_gbl_fixed_event_handlers[event].handler) {
-		status = AE_ALREADY_EXISTS;
-		goto cleanup;
-	}
-
-	/* Install the handler before enabling the event */
-
-	acpi_gbl_fixed_event_handlers[event].handler = handler;
-	acpi_gbl_fixed_event_handlers[event].context = context;
-
-	status = acpi_clear_event(event);
-	if (ACPI_SUCCESS(status))
-		status = acpi_enable_event(event, 0);
-	if (ACPI_FAILURE(status)) {
-		ACPI_WARNING((AE_INFO, "Could not enable fixed event 0x%X",
-			      event));
-
-		/* Remove the handler */
-
-		acpi_gbl_fixed_event_handlers[event].handler = NULL;
-		acpi_gbl_fixed_event_handlers[event].context = NULL;
-	} else {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "Enabled fixed event %X, Handler=%p\n", event,
-				  handler));
-	}
-
-      cleanup:
-	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-	return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_install_fixed_event_handler)
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_remove_fixed_event_handler
- *
- * PARAMETERS:  Event           - Event type to disable.
- *              Handler         - Address of the handler
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Disables the event and unregisters the event handler.
- *
- ******************************************************************************/
-acpi_status
-acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler)
-{
-	acpi_status status = AE_OK;
-
-	ACPI_FUNCTION_TRACE(acpi_remove_fixed_event_handler);
-
-	/* Parameter validation */
-
-	if (event > ACPI_EVENT_MAX) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Disable the event before removing the handler */
-
-	status = acpi_disable_event(event, 0);
-
-	/* Always Remove the handler */
-
-	acpi_gbl_fixed_event_handlers[event].handler = NULL;
-	acpi_gbl_fixed_event_handlers[event].context = NULL;
-
-	if (ACPI_FAILURE(status)) {
-		ACPI_WARNING((AE_INFO,
-			      "Could not write to fixed event enable register 0x%X",
-			      event));
-	} else {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Disabled fixed event %X\n",
-				  event));
-	}
-
-	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-	return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler)
 
 /*******************************************************************************
  *
@@ -334,6 +118,7 @@
 	return AE_OK;
 }
 
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_install_notify_handler
@@ -705,6 +490,224 @@
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_install_exception_handler
+ *
+ * PARAMETERS:  Handler         - Pointer to the handler function for the
+ *                                event
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Saves the pointer to the handler function
+ *
+ ******************************************************************************/
+#ifdef ACPI_FUTURE_USAGE
+acpi_status acpi_install_exception_handler(acpi_exception_handler handler)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_install_exception_handler);
+
+	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	/* Don't allow two handlers. */
+
+	if (acpi_gbl_exception_handler) {
+		status = AE_ALREADY_EXISTS;
+		goto cleanup;
+	}
+
+	/* Install the handler */
+
+	acpi_gbl_exception_handler = handler;
+
+      cleanup:
+	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_exception_handler)
+#endif				/*  ACPI_FUTURE_USAGE  */
+
+#if (!ACPI_REDUCED_HARDWARE)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_install_global_event_handler
+ *
+ * PARAMETERS:  Handler         - Pointer to the global event handler function
+ *              Context         - Value passed to the handler on each event
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Saves the pointer to the handler function. The global handler
+ *              is invoked upon each incoming GPE and Fixed Event. It is
+ *              invoked at interrupt level at the time of the event dispatch.
+ *              Can be used to update event counters, etc.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_install_global_event_handler(ACPI_GBL_EVENT_HANDLER handler, void *context)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_install_global_event_handler);
+
+	/* Parameter validation */
+
+	if (!handler) {
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
+	}
+
+	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	/* Don't allow two handlers. */
+
+	if (acpi_gbl_global_event_handler) {
+		status = AE_ALREADY_EXISTS;
+		goto cleanup;
+	}
+
+	acpi_gbl_global_event_handler = handler;
+	acpi_gbl_global_event_handler_context = context;
+
+      cleanup:
+	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_global_event_handler)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_install_fixed_event_handler
+ *
+ * PARAMETERS:  Event           - Event type to enable.
+ *              Handler         - Pointer to the handler function for the
+ *                                event
+ *              Context         - Value passed to the handler on each GPE
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Saves the pointer to the handler function and then enables the
+ *              event.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_install_fixed_event_handler(u32 event,
+				 acpi_event_handler handler, void *context)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_install_fixed_event_handler);
+
+	/* Parameter validation */
+
+	if (event > ACPI_EVENT_MAX) {
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
+	}
+
+	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	/* Don't allow two handlers. */
+
+	if (NULL != acpi_gbl_fixed_event_handlers[event].handler) {
+		status = AE_ALREADY_EXISTS;
+		goto cleanup;
+	}
+
+	/* Install the handler before enabling the event */
+
+	acpi_gbl_fixed_event_handlers[event].handler = handler;
+	acpi_gbl_fixed_event_handlers[event].context = context;
+
+	status = acpi_clear_event(event);
+	if (ACPI_SUCCESS(status))
+		status = acpi_enable_event(event, 0);
+	if (ACPI_FAILURE(status)) {
+		ACPI_WARNING((AE_INFO, "Could not enable fixed event 0x%X",
+			      event));
+
+		/* Remove the handler */
+
+		acpi_gbl_fixed_event_handlers[event].handler = NULL;
+		acpi_gbl_fixed_event_handlers[event].context = NULL;
+	} else {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				  "Enabled fixed event %X, Handler=%p\n", event,
+				  handler));
+	}
+
+      cleanup:
+	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_fixed_event_handler)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_remove_fixed_event_handler
+ *
+ * PARAMETERS:  Event           - Event type to disable.
+ *              Handler         - Address of the handler
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Disables the event and unregisters the event handler.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler)
+{
+	acpi_status status = AE_OK;
+
+	ACPI_FUNCTION_TRACE(acpi_remove_fixed_event_handler);
+
+	/* Parameter validation */
+
+	if (event > ACPI_EVENT_MAX) {
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
+	}
+
+	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	/* Disable the event before removing the handler */
+
+	status = acpi_disable_event(event, 0);
+
+	/* Always Remove the handler */
+
+	acpi_gbl_fixed_event_handlers[event].handler = NULL;
+	acpi_gbl_fixed_event_handlers[event].context = NULL;
+
+	if (ACPI_FAILURE(status)) {
+		ACPI_WARNING((AE_INFO,
+			      "Could not write to fixed event enable register 0x%X",
+			      event));
+	} else {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Disabled fixed event %X\n",
+				  event));
+	}
+
+	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler)
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_install_gpe_handler
  *
  * PARAMETERS:  gpe_device      - Namespace node for the GPE (NULL for FADT
@@ -984,3 +987,4 @@
 }
 
 ACPI_EXPORT_SYMBOL(acpi_release_global_lock)
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index 1768bbe..77cee5a 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -49,6 +49,7 @@
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evxfevnt")
 
+#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
 /*******************************************************************************
  *
  * FUNCTION:    acpi_enable
@@ -352,3 +353,4 @@
 }
 
 ACPI_EXPORT_SYMBOL(acpi_get_event_status)
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index 33388fd..86f9b34 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -50,6 +50,7 @@
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evxfgpe")
 
+#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
 /******************************************************************************
  *
  * FUNCTION:    acpi_update_all_gpes
@@ -695,3 +696,4 @@
 }
 
 ACPI_EXPORT_SYMBOL(acpi_get_gpe_device)
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c
index d21ec5f..d0b9ed5 100644
--- a/drivers/acpi/acpica/hwacpi.c
+++ b/drivers/acpi/acpica/hwacpi.c
@@ -48,6 +48,7 @@
 #define _COMPONENT          ACPI_HARDWARE
 ACPI_MODULE_NAME("hwacpi")
 
+#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
 /******************************************************************************
  *
  * FUNCTION:    acpi_hw_set_mode
@@ -166,3 +167,5 @@
 		return_UINT32(ACPI_SYS_MODE_LEGACY);
 	}
 }
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c
new file mode 100644
index 0000000..29e8592
--- /dev/null
+++ b/drivers/acpi/acpica/hwesleep.c
@@ -0,0 +1,247 @@
+/******************************************************************************
+ *
+ * Name: hwesleep.c - ACPI Hardware Sleep/Wake Support functions for the
+ *                    extended FADT-V5 sleep registers.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2012, Intel Corp.
+ * All rights reserved.
+ *
+ * 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 at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+
+#define _COMPONENT          ACPI_HARDWARE
+ACPI_MODULE_NAME("hwesleep")
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_execute_sleep_method
+ *
+ * PARAMETERS:  method_pathname     - Pathname of method to execute
+ *              integer_argument    - Argument to pass to the method
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Execute a sleep/wake related method with one integer argument
+ *              and no return value.
+ *
+ ******************************************************************************/
+void acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument)
+{
+	struct acpi_object_list arg_list;
+	union acpi_object arg;
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(hw_execute_sleep_method);
+
+	/* One argument, integer_argument; No return value expected */
+
+	arg_list.count = 1;
+	arg_list.pointer = &arg;
+	arg.type = ACPI_TYPE_INTEGER;
+	arg.integer.value = (u64)integer_argument;
+
+	status = acpi_evaluate_object(NULL, method_pathname, &arg_list, NULL);
+	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+		ACPI_EXCEPTION((AE_INFO, status, "While executing method %s",
+				method_pathname));
+	}
+
+	return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_extended_sleep
+ *
+ * PARAMETERS:  sleep_state         - Which sleep state to enter
+ *              Flags               - ACPI_EXECUTE_GTS to run optional method
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Enter a system sleep state via the extended FADT sleep
+ *              registers (V5 FADT).
+ *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
+ *
+ ******************************************************************************/
+
+acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags)
+{
+	acpi_status status;
+	u8 sleep_type_value;
+	u64 sleep_status;
+
+	ACPI_FUNCTION_TRACE(hw_extended_sleep);
+
+	/* Extended sleep registers must be valid */
+
+	if (!acpi_gbl_FADT.sleep_control.address ||
+	    !acpi_gbl_FADT.sleep_status.address) {
+		return_ACPI_STATUS(AE_NOT_EXIST);
+	}
+
+	/* Clear wake status (WAK_STS) */
+
+	status = acpi_write(ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	acpi_gbl_system_awake_and_running = FALSE;
+
+	/* Optionally execute _GTS (Going To Sleep) */
+
+	if (flags & ACPI_EXECUTE_GTS) {
+		acpi_hw_execute_sleep_method(METHOD_PATHNAME__GTS, sleep_state);
+	}
+
+	/* Flush caches, as per ACPI specification */
+
+	ACPI_FLUSH_CPU_CACHE();
+
+	/*
+	 * Set the SLP_TYP and SLP_EN bits.
+	 *
+	 * Note: We only use the first value returned by the \_Sx method
+	 * (acpi_gbl_sleep_type_a) - As per ACPI specification.
+	 */
+	ACPI_DEBUG_PRINT((ACPI_DB_INIT,
+			  "Entering sleep state [S%u]\n", sleep_state));
+
+	sleep_type_value =
+	    ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
+	     ACPI_X_SLEEP_TYPE_MASK);
+
+	status = acpi_write((sleep_type_value | ACPI_X_SLEEP_ENABLE),
+			    &acpi_gbl_FADT.sleep_control);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	/* Wait for transition back to Working State */
+
+	do {
+		status = acpi_read(&sleep_status, &acpi_gbl_FADT.sleep_status);
+		if (ACPI_FAILURE(status)) {
+			return_ACPI_STATUS(status);
+		}
+
+	} while (!(((u8)sleep_status) & ACPI_X_WAKE_STATUS));
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_extended_wake_prep
+ *
+ * PARAMETERS:  sleep_state         - Which sleep state we just exited
+ *              Flags               - ACPI_EXECUTE_BFS to run optional method
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Perform first part of OS-independent ACPI cleanup after
+ *              a sleep. Called with interrupts ENABLED.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_hw_extended_wake_prep(u8 sleep_state, u8 flags)
+{
+	acpi_status status;
+	u8 sleep_type_value;
+
+	ACPI_FUNCTION_TRACE(hw_extended_wake_prep);
+
+	status = acpi_get_sleep_type_data(ACPI_STATE_S0,
+					  &acpi_gbl_sleep_type_a,
+					  &acpi_gbl_sleep_type_b);
+	if (ACPI_SUCCESS(status)) {
+		sleep_type_value =
+		    ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
+		     ACPI_X_SLEEP_TYPE_MASK);
+
+		(void)acpi_write((sleep_type_value | ACPI_X_SLEEP_ENABLE),
+				 &acpi_gbl_FADT.sleep_control);
+	}
+
+	/* Optionally execute _BFS (Back From Sleep) */
+
+	if (flags & ACPI_EXECUTE_BFS) {
+		acpi_hw_execute_sleep_method(METHOD_PATHNAME__BFS, sleep_state);
+	}
+	return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_extended_wake
+ *
+ * PARAMETERS:  sleep_state         - Which sleep state we just exited
+ *              Flags               - Reserved, set to zero
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
+ *              Called with interrupts ENABLED.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_hw_extended_wake(u8 sleep_state, u8 flags)
+{
+	ACPI_FUNCTION_TRACE(hw_extended_wake);
+
+	/* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
+
+	acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
+
+	/* Execute the wake methods */
+
+	acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WAKING);
+	acpi_hw_execute_sleep_method(METHOD_PATHNAME__WAK, sleep_state);
+
+	/*
+	 * Some BIOS code assumes that WAK_STS will be cleared on resume
+	 * and use it to determine whether the system is rebooting or
+	 * resuming. Clear WAK_STS for compatibility.
+	 */
+	(void)acpi_write(ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status);
+	acpi_gbl_system_awake_and_running = TRUE;
+
+	acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING);
+	return_ACPI_STATUS(AE_OK);
+}
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index 1a6894a..25bd28c 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -48,7 +48,7 @@
 
 #define _COMPONENT          ACPI_HARDWARE
 ACPI_MODULE_NAME("hwgpe")
-
+#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
 /* Local prototypes */
 static acpi_status
 acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
@@ -479,3 +479,5 @@
 	status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block, NULL);
 	return_ACPI_STATUS(status);
 }
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index 4ea4eeb5..6b6c83b 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -51,6 +51,7 @@
 #define _COMPONENT          ACPI_HARDWARE
 ACPI_MODULE_NAME("hwregs")
 
+#if (!ACPI_REDUCED_HARDWARE)
 /* Local Prototypes */
 static acpi_status
 acpi_hw_read_multiple(u32 *value,
@@ -62,6 +63,8 @@
 		       struct acpi_generic_address *register_a,
 		       struct acpi_generic_address *register_b);
 
+#endif				/* !ACPI_REDUCED_HARDWARE */
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_hw_validate_register
@@ -154,6 +157,7 @@
 acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
 {
 	u64 address;
+	u64 value64;
 	acpi_status status;
 
 	ACPI_FUNCTION_NAME(hw_read);
@@ -175,7 +179,9 @@
 	 */
 	if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
 		status = acpi_os_read_memory((acpi_physical_address)
-					     address, value, reg->bit_width);
+					     address, &value64, reg->bit_width);
+
+		*value = (u32)value64;
 	} else {		/* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
 
 		status = acpi_hw_read_port((acpi_io_address)
@@ -225,7 +231,8 @@
 	 */
 	if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
 		status = acpi_os_write_memory((acpi_physical_address)
-					      address, value, reg->bit_width);
+					      address, (u64)value,
+					      reg->bit_width);
 	} else {		/* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
 
 		status = acpi_hw_write_port((acpi_io_address)
@@ -240,6 +247,7 @@
 	return (status);
 }
 
+#if (!ACPI_REDUCED_HARDWARE)
 /*******************************************************************************
  *
  * FUNCTION:    acpi_hw_clear_acpi_status
@@ -285,7 +293,7 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_hw_get_register_bit_mask
+ * FUNCTION:    acpi_hw_get_bit_register_info
  *
  * PARAMETERS:  register_id         - Index of ACPI Register to access
  *
@@ -658,3 +666,5 @@
 
 	return (status);
 }
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index 3c4a922..0ed85ca 100644
--- a/drivers/acpi/acpica/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -1,7 +1,7 @@
-
 /******************************************************************************
  *
- * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface
+ * Name: hwsleep.c - ACPI Hardware Sleep/Wake Support functions for the
+ *                   original/legacy sleep/PM registers.
  *
  *****************************************************************************/
 
@@ -43,213 +43,37 @@
  */
 
 #include <acpi/acpi.h>
+#include <linux/acpi.h>
 #include "accommon.h"
-#include "actables.h"
-#include <linux/tboot.h>
 #include <linux/module.h>
 
 #define _COMPONENT          ACPI_HARDWARE
 ACPI_MODULE_NAME("hwsleep")
 
+#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
 /*******************************************************************************
  *
- * FUNCTION:    acpi_set_firmware_waking_vector
- *
- * PARAMETERS:  physical_address    - 32-bit physical address of ACPI real mode
- *                                    entry point.
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS
- *
- ******************************************************************************/
-acpi_status
-acpi_set_firmware_waking_vector(u32 physical_address)
-{
-	ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);
-
-
-	/*
-	 * According to the ACPI specification 2.0c and later, the 64-bit
-	 * waking vector should be cleared and the 32-bit waking vector should
-	 * be used, unless we want the wake-up code to be called by the BIOS in
-	 * Protected Mode.  Some systems (for example HP dv5-1004nr) are known
-	 * to fail to resume if the 64-bit vector is used.
-	 */
-
-	/* Set the 32-bit vector */
-
-	acpi_gbl_FACS->firmware_waking_vector = physical_address;
-
-	/* Clear the 64-bit vector if it exists */
-
-	if ((acpi_gbl_FACS->length > 32) && (acpi_gbl_FACS->version >= 1)) {
-		acpi_gbl_FACS->xfirmware_waking_vector = 0;
-	}
-
-	return_ACPI_STATUS(AE_OK);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)
-
-#if ACPI_MACHINE_WIDTH == 64
-/*******************************************************************************
- *
- * FUNCTION:    acpi_set_firmware_waking_vector64
- *
- * PARAMETERS:  physical_address    - 64-bit physical address of ACPI protected
- *                                    mode entry point.
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Sets the 64-bit X_firmware_waking_vector field of the FACS, if
- *              it exists in the table. This function is intended for use with
- *              64-bit host operating systems.
- *
- ******************************************************************************/
-acpi_status
-acpi_set_firmware_waking_vector64(u64 physical_address)
-{
-	ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64);
-
-
-	/* Determine if the 64-bit vector actually exists */
-
-	if ((acpi_gbl_FACS->length <= 32) || (acpi_gbl_FACS->version < 1)) {
-		return_ACPI_STATUS(AE_NOT_EXIST);
-	}
-
-	/* Clear 32-bit vector, set the 64-bit X_ vector */
-
-	acpi_gbl_FACS->firmware_waking_vector = 0;
-	acpi_gbl_FACS->xfirmware_waking_vector = physical_address;
-
-	return_ACPI_STATUS(AE_OK);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64)
-#endif
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_enter_sleep_state_prep
+ * FUNCTION:    acpi_hw_legacy_sleep
  *
  * PARAMETERS:  sleep_state         - Which sleep state to enter
+ *              Flags               - ACPI_EXECUTE_GTS to run optional method
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Prepare to enter a system sleep state (see ACPI 2.0 spec p 231)
- *              This function must execute with interrupts enabled.
- *              We break sleeping into 2 stages so that OSPM can handle
- *              various OS-specific tasks between the two steps.
- *
- ******************************************************************************/
-acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
-{
-	acpi_status status;
-	struct acpi_object_list arg_list;
-	union acpi_object arg;
-
-	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep);
-
-	/* _PSW methods could be run here to enable wake-on keyboard, LAN, etc. */
-
-	status = acpi_get_sleep_type_data(sleep_state,
-					  &acpi_gbl_sleep_type_a,
-					  &acpi_gbl_sleep_type_b);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Setup parameter object */
-
-	arg_list.count = 1;
-	arg_list.pointer = &arg;
-
-	arg.type = ACPI_TYPE_INTEGER;
-	arg.integer.value = sleep_state;
-
-	/* Run the _PTS method */
-
-	status = acpi_evaluate_object(NULL, METHOD_NAME__PTS, &arg_list, NULL);
-	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Setup the argument to _SST */
-
-	switch (sleep_state) {
-	case ACPI_STATE_S0:
-		arg.integer.value = ACPI_SST_WORKING;
-		break;
-
-	case ACPI_STATE_S1:
-	case ACPI_STATE_S2:
-	case ACPI_STATE_S3:
-		arg.integer.value = ACPI_SST_SLEEPING;
-		break;
-
-	case ACPI_STATE_S4:
-		arg.integer.value = ACPI_SST_SLEEP_CONTEXT;
-		break;
-
-	default:
-		arg.integer.value = ACPI_SST_INDICATOR_OFF;	/* Default is off */
-		break;
-	}
-
-	/*
-	 * Set the system indicators to show the desired sleep state.
-	 * _SST is an optional method (return no error if not found)
-	 */
-	status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
-	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-		ACPI_EXCEPTION((AE_INFO, status,
-				"While executing method _SST"));
-	}
-
-	return_ACPI_STATUS(AE_OK);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)
-
-static unsigned int gts, bfs;
-module_param(gts, uint, 0644);
-module_param(bfs, uint, 0644);
-MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend.");
-MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".);
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_enter_sleep_state
- *
- * PARAMETERS:  sleep_state         - Which sleep state to enter
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231)
+ * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers
  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
  *
  ******************************************************************************/
-acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
+acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags)
 {
-	u32 pm1a_control;
-	u32 pm1b_control;
 	struct acpi_bit_register_info *sleep_type_reg_info;
 	struct acpi_bit_register_info *sleep_enable_reg_info;
+	u32 pm1a_control;
+	u32 pm1b_control;
 	u32 in_value;
-	struct acpi_object_list arg_list;
-	union acpi_object arg;
 	acpi_status status;
 
-	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state);
-
-	if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) ||
-	    (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) {
-		ACPI_ERROR((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X",
-			    acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b));
-		return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
-	}
+	ACPI_FUNCTION_TRACE(hw_legacy_sleep);
 
 	sleep_type_reg_info =
 	    acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE);
@@ -271,6 +95,18 @@
 		return_ACPI_STATUS(status);
 	}
 
+	if (sleep_state != ACPI_STATE_S5) {
+		/*
+		 * Disable BM arbitration. This feature is contained within an
+		 * optional register (PM2 Control), so ignore a BAD_ADDRESS
+		 * exception.
+		 */
+		status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1);
+		if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) {
+			return_ACPI_STATUS(status);
+		}
+	}
+
 	/*
 	 * 1) Disable/Clear all GPEs
 	 * 2) Enable all wakeup GPEs
@@ -286,18 +122,10 @@
 		return_ACPI_STATUS(status);
 	}
 
-	if (gts) {
-		/* Execute the _GTS method */
+	/* Optionally execute _GTS (Going To Sleep) */
 
-		arg_list.count = 1;
-		arg_list.pointer = &arg;
-		arg.type = ACPI_TYPE_INTEGER;
-		arg.integer.value = sleep_state;
-
-		status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL);
-		if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-			return_ACPI_STATUS(status);
-		}
+	if (flags & ACPI_EXECUTE_GTS) {
+		acpi_hw_execute_sleep_method(METHOD_PATHNAME__GTS, sleep_state);
 	}
 
 	/* Get current value of PM1A control */
@@ -344,8 +172,12 @@
 
 	ACPI_FLUSH_CPU_CACHE();
 
-	tboot_sleep(sleep_state, pm1a_control, pm1b_control);
-
+	status = acpi_os_prepare_sleep(sleep_state, pm1a_control,
+				       pm1b_control);
+	if (ACPI_SKIP(status))
+		return_ACPI_STATUS(AE_OK);
+	if (ACPI_FAILURE(status))
+		return_ACPI_STATUS(status);
 	/* Write #2: Write both SLP_TYP + SLP_EN */
 
 	status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
@@ -375,114 +207,44 @@
 		}
 	}
 
-	/* Wait until we enter sleep state */
+	/* Wait for transition back to Working State */
 
 	do {
-		status = acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS,
-						    &in_value);
-		if (ACPI_FAILURE(status)) {
-			return_ACPI_STATUS(status);
-		}
-
-		/* Spin until we wake */
-
-	} while (!in_value);
-
-	return_ACPI_STATUS(AE_OK);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state)
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_enter_sleep_state_s4bios
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Perform a S4 bios request.
- *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
- *
- ******************************************************************************/
-acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)
-{
-	u32 in_value;
-	acpi_status status;
-
-	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios);
-
-	/* Clear the wake status bit (PM1) */
-
-	status =
-	    acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	status = acpi_hw_clear_acpi_status();
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/*
-	 * 1) Disable/Clear all GPEs
-	 * 2) Enable all wakeup GPEs
-	 */
-	status = acpi_hw_disable_all_gpes();
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-	acpi_gbl_system_awake_and_running = FALSE;
-
-	status = acpi_hw_enable_all_wakeup_gpes();
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	ACPI_FLUSH_CPU_CACHE();
-
-	status = acpi_hw_write_port(acpi_gbl_FADT.smi_command,
-				    (u32) acpi_gbl_FADT.S4bios_request, 8);
-
-	do {
-		acpi_os_stall(1000);
 		status =
 		    acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value);
 		if (ACPI_FAILURE(status)) {
 			return_ACPI_STATUS(status);
 		}
+
 	} while (!in_value);
 
 	return_ACPI_STATUS(AE_OK);
 }
 
-ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios)
-
 /*******************************************************************************
  *
- * FUNCTION:    acpi_leave_sleep_state_prep
+ * FUNCTION:    acpi_hw_legacy_wake_prep
  *
- * PARAMETERS:  sleep_state         - Which sleep state we are exiting
+ * PARAMETERS:  sleep_state         - Which sleep state we just exited
+ *              Flags               - ACPI_EXECUTE_BFS to run optional method
  *
  * RETURN:      Status
  *
  * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
  *              sleep.
- *              Called with interrupts DISABLED.
+ *              Called with interrupts ENABLED.
  *
  ******************************************************************************/
-acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)
+
+acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags)
 {
-	struct acpi_object_list arg_list;
-	union acpi_object arg;
 	acpi_status status;
 	struct acpi_bit_register_info *sleep_type_reg_info;
 	struct acpi_bit_register_info *sleep_enable_reg_info;
 	u32 pm1a_control;
 	u32 pm1b_control;
 
-	ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep);
+	ACPI_FUNCTION_TRACE(hw_legacy_wake_prep);
 
 	/*
 	 * Set SLP_TYPE and SLP_EN to state S0.
@@ -525,27 +287,20 @@
 		}
 	}
 
-	if (bfs) {
-		/* Execute the _BFS method */
+	/* Optionally execute _BFS (Back From Sleep) */
 
-		arg_list.count = 1;
-		arg_list.pointer = &arg;
-		arg.type = ACPI_TYPE_INTEGER;
-		arg.integer.value = sleep_state;
-
-		status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL);
-		if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-			ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS"));
-		}
+	if (flags & ACPI_EXECUTE_BFS) {
+		acpi_hw_execute_sleep_method(METHOD_PATHNAME__BFS, sleep_state);
 	}
 	return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_leave_sleep_state
+ * FUNCTION:    acpi_hw_legacy_wake
  *
  * PARAMETERS:  sleep_state         - Which sleep state we just exited
+ *              Flags               - Reserved, set to zero
  *
  * RETURN:      Status
  *
@@ -553,31 +308,17 @@
  *              Called with interrupts ENABLED.
  *
  ******************************************************************************/
-acpi_status acpi_leave_sleep_state(u8 sleep_state)
+
+acpi_status acpi_hw_legacy_wake(u8 sleep_state, u8 flags)
 {
-	struct acpi_object_list arg_list;
-	union acpi_object arg;
 	acpi_status status;
 
-	ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
+	ACPI_FUNCTION_TRACE(hw_legacy_wake);
 
 	/* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
 
 	acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
-
-	/* Setup parameter object */
-
-	arg_list.count = 1;
-	arg_list.pointer = &arg;
-	arg.type = ACPI_TYPE_INTEGER;
-
-	/* Ignore any errors from these methods */
-
-	arg.integer.value = ACPI_SST_WAKING;
-	status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
-	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-		ACPI_EXCEPTION((AE_INFO, status, "During Method _SST"));
-	}
+	acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WAKING);
 
 	/*
 	 * GPEs must be enabled before _WAK is called as GPEs
@@ -591,46 +332,50 @@
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
+
 	status = acpi_hw_enable_all_runtime_gpes();
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
 
-	arg.integer.value = sleep_state;
-	status = acpi_evaluate_object(NULL, METHOD_NAME__WAK, &arg_list, NULL);
-	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-		ACPI_EXCEPTION((AE_INFO, status, "During Method _WAK"));
-	}
-	/* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
+	/*
+	 * Now we can execute _WAK, etc. Some machines require that the GPEs
+	 * are enabled before the wake methods are executed.
+	 */
+	acpi_hw_execute_sleep_method(METHOD_PATHNAME__WAK, sleep_state);
 
 	/*
-	 * Some BIOSes assume that WAK_STS will be cleared on resume and use
-	 * it to determine whether the system is rebooting or resuming. Clear
-	 * it for compatibility.
+	 * Some BIOS code assumes that WAK_STS will be cleared on resume
+	 * and use it to determine whether the system is rebooting or
+	 * resuming. Clear WAK_STS for compatibility.
 	 */
 	acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, 1);
-
 	acpi_gbl_system_awake_and_running = TRUE;
 
 	/* Enable power button */
 
 	(void)
 	    acpi_write_bit_register(acpi_gbl_fixed_event_info
-			      [ACPI_EVENT_POWER_BUTTON].
-			      enable_register_id, ACPI_ENABLE_EVENT);
+				    [ACPI_EVENT_POWER_BUTTON].
+				    enable_register_id, ACPI_ENABLE_EVENT);
 
 	(void)
 	    acpi_write_bit_register(acpi_gbl_fixed_event_info
-			      [ACPI_EVENT_POWER_BUTTON].
-			      status_register_id, ACPI_CLEAR_STATUS);
+				    [ACPI_EVENT_POWER_BUTTON].
+				    status_register_id, ACPI_CLEAR_STATUS);
 
-	arg.integer.value = ACPI_SST_WORKING;
-	status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
-	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-		ACPI_EXCEPTION((AE_INFO, status, "During Method _SST"));
+	/*
+	 * Enable BM arbitration. This feature is contained within an
+	 * optional register (PM2 Control), so ignore a BAD_ADDRESS
+	 * exception.
+	 */
+	status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0);
+	if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) {
+		return_ACPI_STATUS(status);
 	}
 
+	acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING);
 	return_ACPI_STATUS(status);
 }
 
-ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state)
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c
index d4973d9..f1b2c3b 100644
--- a/drivers/acpi/acpica/hwtimer.c
+++ b/drivers/acpi/acpica/hwtimer.c
@@ -49,6 +49,7 @@
 #define _COMPONENT          ACPI_HARDWARE
 ACPI_MODULE_NAME("hwtimer")
 
+#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
 /******************************************************************************
  *
  * FUNCTION:    acpi_get_timer_resolution
@@ -187,3 +188,4 @@
 }
 
 ACPI_EXPORT_SYMBOL(acpi_get_timer_duration)
+#endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c
index 9d38eb6..ab513a9 100644
--- a/drivers/acpi/acpica/hwxface.c
+++ b/drivers/acpi/acpica/hwxface.c
@@ -74,8 +74,7 @@
 
 	/* Check if the reset register is supported */
 
-	if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) ||
-	    !reset_reg->address) {
+	if (!reset_reg->address) {
 		return_ACPI_STATUS(AE_NOT_EXIST);
 	}
 
@@ -138,11 +137,6 @@
 		return (status);
 	}
 
-	width = reg->bit_width;
-	if (width == 64) {
-		width = 32;	/* Break into two 32-bit transfers */
-	}
-
 	/* Initialize entire 64-bit return value to zero */
 
 	*return_value = 0;
@@ -154,25 +148,18 @@
 	 */
 	if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
 		status = acpi_os_read_memory((acpi_physical_address)
-					     address, &value, width);
+					     address, return_value,
+					     reg->bit_width);
 		if (ACPI_FAILURE(status)) {
 			return (status);
 		}
-		*return_value = value;
-
-		if (reg->bit_width == 64) {
-
-			/* Read the top 32 bits */
-
-			status = acpi_os_read_memory((acpi_physical_address)
-						     (address + 4), &value, 32);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-			*return_value |= ((u64)value << 32);
-		}
 	} else {		/* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
 
+		width = reg->bit_width;
+		if (width == 64) {
+			width = 32;	/* Break into two 32-bit transfers */
+		}
+
 		status = acpi_hw_read_port((acpi_io_address)
 					   address, &value, width);
 		if (ACPI_FAILURE(status)) {
@@ -231,33 +218,23 @@
 		return (status);
 	}
 
-	width = reg->bit_width;
-	if (width == 64) {
-		width = 32;	/* Break into two 32-bit transfers */
-	}
-
 	/*
 	 * Two address spaces supported: Memory or IO. PCI_Config is
 	 * not supported here because the GAS structure is insufficient
 	 */
 	if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
 		status = acpi_os_write_memory((acpi_physical_address)
-					      address, ACPI_LODWORD(value),
-					      width);
+					      address, value, reg->bit_width);
 		if (ACPI_FAILURE(status)) {
 			return (status);
 		}
-
-		if (reg->bit_width == 64) {
-			status = acpi_os_write_memory((acpi_physical_address)
-						      (address + 4),
-						      ACPI_HIDWORD(value), 32);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-		}
 	} else {		/* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
 
+		width = reg->bit_width;
+		if (width == 64) {
+			width = 32;	/* Break into two 32-bit transfers */
+		}
+
 		status = acpi_hw_write_port((acpi_io_address)
 					    address, ACPI_LODWORD(value),
 					    width);
@@ -286,6 +263,7 @@
 
 ACPI_EXPORT_SYMBOL(acpi_write)
 
+#if (!ACPI_REDUCED_HARDWARE)
 /*******************************************************************************
  *
  * FUNCTION:    acpi_read_bit_register
@@ -453,7 +431,7 @@
 }
 
 ACPI_EXPORT_SYMBOL(acpi_write_bit_register)
-
+#endif				/* !ACPI_REDUCED_HARDWARE */
 /*******************************************************************************
  *
  * FUNCTION:    acpi_get_sleep_type_data
diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c
new file mode 100644
index 0000000..762d059
--- /dev/null
+++ b/drivers/acpi/acpica/hwxfsleep.c
@@ -0,0 +1,431 @@
+/******************************************************************************
+ *
+ * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2012, Intel Corp.
+ * All rights reserved.
+ *
+ * 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 at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include <linux/module.h>
+
+#define _COMPONENT          ACPI_HARDWARE
+ACPI_MODULE_NAME("hwxfsleep")
+
+/* Local prototypes */
+static acpi_status
+acpi_hw_sleep_dispatch(u8 sleep_state, u8 flags, u32 function_id);
+
+/*
+ * Dispatch table used to efficiently branch to the various sleep
+ * functions.
+ */
+#define ACPI_SLEEP_FUNCTION_ID         0
+#define ACPI_WAKE_PREP_FUNCTION_ID     1
+#define ACPI_WAKE_FUNCTION_ID          2
+
+/* Legacy functions are optional, based upon ACPI_REDUCED_HARDWARE */
+
+static struct acpi_sleep_functions acpi_sleep_dispatch[] = {
+	{ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_sleep),
+	 acpi_hw_extended_sleep},
+	{ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake_prep),
+	 acpi_hw_extended_wake_prep},
+	{ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake), acpi_hw_extended_wake}
+};
+
+/*
+ * These functions are removed for the ACPI_REDUCED_HARDWARE case:
+ *      acpi_set_firmware_waking_vector
+ *      acpi_set_firmware_waking_vector64
+ *      acpi_enter_sleep_state_s4bios
+ */
+
+#if (!ACPI_REDUCED_HARDWARE)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_set_firmware_waking_vector
+ *
+ * PARAMETERS:  physical_address    - 32-bit physical address of ACPI real mode
+ *                                    entry point.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS
+ *
+ ******************************************************************************/
+
+acpi_status acpi_set_firmware_waking_vector(u32 physical_address)
+{
+	ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);
+
+
+	/*
+	 * According to the ACPI specification 2.0c and later, the 64-bit
+	 * waking vector should be cleared and the 32-bit waking vector should
+	 * be used, unless we want the wake-up code to be called by the BIOS in
+	 * Protected Mode.  Some systems (for example HP dv5-1004nr) are known
+	 * to fail to resume if the 64-bit vector is used.
+	 */
+
+	/* Set the 32-bit vector */
+
+	acpi_gbl_FACS->firmware_waking_vector = physical_address;
+
+	/* Clear the 64-bit vector if it exists */
+
+	if ((acpi_gbl_FACS->length > 32) && (acpi_gbl_FACS->version >= 1)) {
+		acpi_gbl_FACS->xfirmware_waking_vector = 0;
+	}
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)
+
+#if ACPI_MACHINE_WIDTH == 64
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_set_firmware_waking_vector64
+ *
+ * PARAMETERS:  physical_address    - 64-bit physical address of ACPI protected
+ *                                    mode entry point.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Sets the 64-bit X_firmware_waking_vector field of the FACS, if
+ *              it exists in the table. This function is intended for use with
+ *              64-bit host operating systems.
+ *
+ ******************************************************************************/
+acpi_status acpi_set_firmware_waking_vector64(u64 physical_address)
+{
+	ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64);
+
+
+	/* Determine if the 64-bit vector actually exists */
+
+	if ((acpi_gbl_FACS->length <= 32) || (acpi_gbl_FACS->version < 1)) {
+		return_ACPI_STATUS(AE_NOT_EXIST);
+	}
+
+	/* Clear 32-bit vector, set the 64-bit X_ vector */
+
+	acpi_gbl_FACS->firmware_waking_vector = 0;
+	acpi_gbl_FACS->xfirmware_waking_vector = physical_address;
+	return_ACPI_STATUS(AE_OK);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64)
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_enter_sleep_state_s4bios
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Perform a S4 bios request.
+ *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
+ *
+ ******************************************************************************/
+acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)
+{
+	u32 in_value;
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios);
+
+	/* Clear the wake status bit (PM1) */
+
+	status =
+	    acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	status = acpi_hw_clear_acpi_status();
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	/*
+	 * 1) Disable/Clear all GPEs
+	 * 2) Enable all wakeup GPEs
+	 */
+	status = acpi_hw_disable_all_gpes();
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+	acpi_gbl_system_awake_and_running = FALSE;
+
+	status = acpi_hw_enable_all_wakeup_gpes();
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	ACPI_FLUSH_CPU_CACHE();
+
+	status = acpi_hw_write_port(acpi_gbl_FADT.smi_command,
+				    (u32)acpi_gbl_FADT.S4bios_request, 8);
+
+	do {
+		acpi_os_stall(1000);
+		status =
+		    acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value);
+		if (ACPI_FAILURE(status)) {
+			return_ACPI_STATUS(status);
+		}
+	} while (!in_value);
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios)
+#endif				/* !ACPI_REDUCED_HARDWARE */
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_sleep_dispatch
+ *
+ * PARAMETERS:  sleep_state         - Which sleep state to enter/exit
+ *              function_id         - Sleep, wake_prep, or Wake
+ *
+ * RETURN:      Status from the invoked sleep handling function.
+ *
+ * DESCRIPTION: Dispatch a sleep/wake request to the appropriate handling
+ *              function.
+ *
+ ******************************************************************************/
+static acpi_status
+acpi_hw_sleep_dispatch(u8 sleep_state, u8 flags, u32 function_id)
+{
+	acpi_status status;
+	struct acpi_sleep_functions *sleep_functions =
+	    &acpi_sleep_dispatch[function_id];
+
+#if (!ACPI_REDUCED_HARDWARE)
+
+	/*
+	 * If the Hardware Reduced flag is set (from the FADT), we must
+	 * use the extended sleep registers
+	 */
+	if (acpi_gbl_reduced_hardware || acpi_gbl_FADT.sleep_control.address) {
+		status = sleep_functions->extended_function(sleep_state, flags);
+	} else {
+		/* Legacy sleep */
+
+		status = sleep_functions->legacy_function(sleep_state, flags);
+	}
+
+	return (status);
+
+#else
+	/*
+	 * For the case where reduced-hardware-only code is being generated,
+	 * we know that only the extended sleep registers are available
+	 */
+	status = sleep_functions->extended_function(sleep_state, flags);
+	return (status);
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_enter_sleep_state_prep
+ *
+ * PARAMETERS:  sleep_state         - Which sleep state to enter
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Prepare to enter a system sleep state.
+ *              This function must execute with interrupts enabled.
+ *              We break sleeping into 2 stages so that OSPM can handle
+ *              various OS-specific tasks between the two steps.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
+{
+	acpi_status status;
+	struct acpi_object_list arg_list;
+	union acpi_object arg;
+	u32 sst_value;
+
+	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep);
+
+	status = acpi_get_sleep_type_data(sleep_state,
+					  &acpi_gbl_sleep_type_a,
+					  &acpi_gbl_sleep_type_b);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	/* Execute the _PTS method (Prepare To Sleep) */
+
+	arg_list.count = 1;
+	arg_list.pointer = &arg;
+	arg.type = ACPI_TYPE_INTEGER;
+	arg.integer.value = sleep_state;
+
+	status =
+	    acpi_evaluate_object(NULL, METHOD_PATHNAME__PTS, &arg_list, NULL);
+	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+		return_ACPI_STATUS(status);
+	}
+
+	/* Setup the argument to the _SST method (System STatus) */
+
+	switch (sleep_state) {
+	case ACPI_STATE_S0:
+		sst_value = ACPI_SST_WORKING;
+		break;
+
+	case ACPI_STATE_S1:
+	case ACPI_STATE_S2:
+	case ACPI_STATE_S3:
+		sst_value = ACPI_SST_SLEEPING;
+		break;
+
+	case ACPI_STATE_S4:
+		sst_value = ACPI_SST_SLEEP_CONTEXT;
+		break;
+
+	default:
+		sst_value = ACPI_SST_INDICATOR_OFF;	/* Default is off */
+		break;
+	}
+
+	/*
+	 * Set the system indicators to show the desired sleep state.
+	 * _SST is an optional method (return no error if not found)
+	 */
+	acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, sst_value);
+	return_ACPI_STATUS(AE_OK);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_enter_sleep_state
+ *
+ * PARAMETERS:  sleep_state         - Which sleep state to enter
+ *              Flags               - ACPI_EXECUTE_GTS to run optional method
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231)
+ *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
+ *
+ ******************************************************************************/
+acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state, u8 flags)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state);
+
+	if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) ||
+	    (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) {
+		ACPI_ERROR((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X",
+			    acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b));
+		return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
+	}
+
+	status =
+	    acpi_hw_sleep_dispatch(sleep_state, flags, ACPI_SLEEP_FUNCTION_ID);
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_leave_sleep_state_prep
+ *
+ * PARAMETERS:  sleep_state         - Which sleep state we are exiting
+ *              Flags               - ACPI_EXECUTE_BFS to run optional method
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
+ *              sleep.
+ *              Called with interrupts DISABLED.
+ *
+ ******************************************************************************/
+acpi_status acpi_leave_sleep_state_prep(u8 sleep_state, u8 flags)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep);
+
+	status =
+	    acpi_hw_sleep_dispatch(sleep_state, flags,
+				   ACPI_WAKE_PREP_FUNCTION_ID);
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state_prep)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_leave_sleep_state
+ *
+ * PARAMETERS:  sleep_state         - Which sleep state we are exiting
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
+ *              Called with interrupts ENABLED.
+ *
+ ******************************************************************************/
+acpi_status acpi_leave_sleep_state(u8 sleep_state)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
+
+
+	status = acpi_hw_sleep_dispatch(sleep_state, 0, ACPI_WAKE_FUNCTION_ID);
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state)
diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c
index b7f2b3b..3f7f3f6 100644
--- a/drivers/acpi/acpica/nsdump.c
+++ b/drivers/acpi/acpica/nsdump.c
@@ -242,7 +242,20 @@
 
 		if (!obj_desc) {
 
-			/* No attached object, we are done */
+			/* No attached object. Some types should always have an object */
+
+			switch (type) {
+			case ACPI_TYPE_INTEGER:
+			case ACPI_TYPE_PACKAGE:
+			case ACPI_TYPE_BUFFER:
+			case ACPI_TYPE_STRING:
+			case ACPI_TYPE_METHOD:
+				acpi_os_printf("<No attached object>");
+				break;
+
+			default:
+				break;
+			}
 
 			acpi_os_printf("\n");
 			return (AE_OK);
diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c
index 30ea5bc..3b5acb0 100644
--- a/drivers/acpi/acpica/nsdumpdv.c
+++ b/drivers/acpi/acpica/nsdumpdv.c
@@ -121,7 +121,7 @@
 		return;
 	}
 
-	status = acpi_get_handle(NULL, ACPI_NS_SYSTEM_BUS, &sys_bus_handle);
+	status = acpi_get_handle(NULL, METHOD_NAME__SB_, &sys_bus_handle);
 	if (ACPI_FAILURE(status)) {
 		return;
 	}
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index bbe46a4..23ce096 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -638,8 +638,8 @@
 			/* Create the new outer package and populate it */
 
 			status =
-			    acpi_ns_repair_package_list(data,
-							return_object_ptr);
+			    acpi_ns_wrap_with_package(data, *elements,
+						      return_object_ptr);
 			if (ACPI_FAILURE(status)) {
 				return (status);
 			}
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c
index 9c35d20..5519a64 100644
--- a/drivers/acpi/acpica/nsrepair.c
+++ b/drivers/acpi/acpica/nsrepair.c
@@ -71,11 +71,10 @@
  * Buffer  -> String
  * Buffer  -> Package of Integers
  * Package -> Package of one Package
+ * An incorrect standalone object is wrapped with required outer package
  *
  * Additional possible repairs:
- *
  * Required package elements that are NULL replaced by Integer/String/Buffer
- * Incorrect standalone package wrapped with required outer package
  *
  ******************************************************************************/
 /* Local prototypes */
@@ -91,10 +90,6 @@
 acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
 			  union acpi_operand_object **return_object);
 
-static acpi_status
-acpi_ns_convert_to_package(union acpi_operand_object *original_object,
-			   union acpi_operand_object **return_object);
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ns_repair_object
@@ -151,9 +146,24 @@
 		}
 	}
 	if (expected_btypes & ACPI_RTYPE_PACKAGE) {
-		status = acpi_ns_convert_to_package(return_object, &new_object);
+		/*
+		 * A package is expected. We will wrap the existing object with a
+		 * new package object. It is often the case that if a variable-length
+		 * package is required, but there is only a single object needed, the
+		 * BIOS will return that object instead of wrapping it with a Package
+		 * object. Note: after the wrapping, the package will be validated
+		 * for correct contents (expected object type or types).
+		 */
+		status =
+		    acpi_ns_wrap_with_package(data, return_object, &new_object);
 		if (ACPI_SUCCESS(status)) {
-			goto object_repaired;
+			/*
+			 * The original object just had its reference count
+			 * incremented for being inserted into the new package.
+			 */
+			*return_object_ptr = new_object;	/* New Package object */
+			data->flags |= ACPI_OBJECT_REPAIRED;
+			return (AE_OK);
 		}
 	}
 
@@ -165,22 +175,27 @@
 
 	/* Object was successfully repaired */
 
-	/*
-	 * If the original object is a package element, we need to:
-	 * 1. Set the reference count of the new object to match the
-	 *    reference count of the old object.
-	 * 2. Decrement the reference count of the original object.
-	 */
 	if (package_index != ACPI_NOT_PACKAGE_ELEMENT) {
-		new_object->common.reference_count =
-		    return_object->common.reference_count;
+		/*
+		 * The original object is a package element. We need to
+		 * decrement the reference count of the original object,
+		 * for removing it from the package.
+		 *
+		 * However, if the original object was just wrapped with a
+		 * package object as part of the repair, we don't need to
+		 * change the reference count.
+		 */
+		if (!(data->flags & ACPI_OBJECT_WRAPPED)) {
+			new_object->common.reference_count =
+			    return_object->common.reference_count;
 
-		if (return_object->common.reference_count > 1) {
-			return_object->common.reference_count--;
+			if (return_object->common.reference_count > 1) {
+				return_object->common.reference_count--;
+			}
 		}
 
 		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
-				  "%s: Converted %s to expected %s at index %u\n",
+				  "%s: Converted %s to expected %s at Package index %u\n",
 				  data->pathname,
 				  acpi_ut_get_object_type_name(return_object),
 				  acpi_ut_get_object_type_name(new_object),
@@ -453,65 +468,6 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ns_convert_to_package
- *
- * PARAMETERS:  original_object     - Object to be converted
- *              return_object       - Where the new converted object is returned
- *
- * RETURN:      Status. AE_OK if conversion was successful.
- *
- * DESCRIPTION: Attempt to convert a Buffer object to a Package. Each byte of
- *              the buffer is converted to a single integer package element.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ns_convert_to_package(union acpi_operand_object *original_object,
-			   union acpi_operand_object **return_object)
-{
-	union acpi_operand_object *new_object;
-	union acpi_operand_object **elements;
-	u32 length;
-	u8 *buffer;
-
-	switch (original_object->common.type) {
-	case ACPI_TYPE_BUFFER:
-
-		/* Buffer-to-Package conversion */
-
-		length = original_object->buffer.length;
-		new_object = acpi_ut_create_package_object(length);
-		if (!new_object) {
-			return (AE_NO_MEMORY);
-		}
-
-		/* Convert each buffer byte to an integer package element */
-
-		elements = new_object->package.elements;
-		buffer = original_object->buffer.pointer;
-
-		while (length--) {
-			*elements =
-			    acpi_ut_create_integer_object((u64) *buffer);
-			if (!*elements) {
-				acpi_ut_remove_reference(new_object);
-				return (AE_NO_MEMORY);
-			}
-			elements++;
-			buffer++;
-		}
-		break;
-
-	default:
-		return (AE_AML_OPERAND_TYPE);
-	}
-
-	*return_object = new_object;
-	return (AE_OK);
-}
-
-/*******************************************************************************
- *
  * FUNCTION:    acpi_ns_repair_null_element
  *
  * PARAMETERS:  Data                - Pointer to validation data structure
@@ -677,55 +633,56 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ns_repair_package_list
+ * FUNCTION:    acpi_ns_wrap_with_package
  *
  * PARAMETERS:  Data                - Pointer to validation data structure
- *              obj_desc_ptr        - Pointer to the object to repair. The new
- *                                    package object is returned here,
- *                                    overwriting the old object.
+ *              original_object     - Pointer to the object to repair.
+ *              obj_desc_ptr        - The new package object is returned here
  *
  * RETURN:      Status, new object in *obj_desc_ptr
  *
- * DESCRIPTION: Repair a common problem with objects that are defined to return
- *              a variable-length Package of Packages. If the variable-length
- *              is one, some BIOS code mistakenly simply declares a single
- *              Package instead of a Package with one sub-Package. This
- *              function attempts to repair this error by wrapping a Package
- *              object around the original Package, creating the correct
- *              Package with one sub-Package.
+ * DESCRIPTION: Repair a common problem with objects that are defined to
+ *              return a variable-length Package of sub-objects. If there is
+ *              only one sub-object, some BIOS code mistakenly simply declares
+ *              the single object instead of a Package with one sub-object.
+ *              This function attempts to repair this error by wrapping a
+ *              Package object around the original object, creating the
+ *              correct and expected Package with one sub-object.
  *
  *              Names that can be repaired in this manner include:
- *              _ALR, _CSD, _HPX, _MLS, _PRT, _PSS, _TRT, TSS
+ *              _ALR, _CSD, _HPX, _MLS, _PLD, _PRT, _PSS, _TRT, _TSS,
+ *              _BCL, _DOD, _FIX, _Sx
  *
  ******************************************************************************/
 
 acpi_status
-acpi_ns_repair_package_list(struct acpi_predefined_data *data,
-			    union acpi_operand_object **obj_desc_ptr)
+acpi_ns_wrap_with_package(struct acpi_predefined_data *data,
+			  union acpi_operand_object *original_object,
+			  union acpi_operand_object **obj_desc_ptr)
 {
 	union acpi_operand_object *pkg_obj_desc;
 
-	ACPI_FUNCTION_NAME(ns_repair_package_list);
+	ACPI_FUNCTION_NAME(ns_wrap_with_package);
 
 	/*
 	 * Create the new outer package and populate it. The new package will
-	 * have a single element, the lone subpackage.
+	 * have a single element, the lone sub-object.
 	 */
 	pkg_obj_desc = acpi_ut_create_package_object(1);
 	if (!pkg_obj_desc) {
 		return (AE_NO_MEMORY);
 	}
 
-	pkg_obj_desc->package.elements[0] = *obj_desc_ptr;
+	pkg_obj_desc->package.elements[0] = original_object;
+
+	ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
+			  "%s: Wrapped %s with expected Package object\n",
+			  data->pathname,
+			  acpi_ut_get_object_type_name(original_object)));
 
 	/* Return the new object in the object pointer */
 
 	*obj_desc_ptr = pkg_obj_desc;
-	data->flags |= ACPI_OBJECT_REPAIRED;
-
-	ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
-			  "%s: Repaired incorrectly formed Package\n",
-			  data->pathname));
-
+	data->flags |= ACPI_OBJECT_REPAIRED | ACPI_OBJECT_WRAPPED;
 	return (AE_OK);
 }
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index a535b7a..7511375 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -341,7 +341,7 @@
 
 		if (!acpi_ns_valid_path_separator(*external_name) &&
 		    (*external_name != 0)) {
-			return_ACPI_STATUS(AE_BAD_PARAMETER);
+			return_ACPI_STATUS(AE_BAD_PATHNAME);
 		}
 
 		/* Move on the next segment */
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index c5d8704..4c9c760 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -363,10 +363,6 @@
 	u32 address32;
 	u32 i;
 
-	/* Update the local FADT table header length */
-
-	acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
-
 	/*
 	 * Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary.
 	 * Later code will always use the X 64-bit field. Also, check for an
@@ -408,6 +404,10 @@
 		acpi_gbl_FADT.boot_flags = 0;
 	}
 
+	/* Update the local FADT table header length */
+
+	acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
+
 	/*
 	 * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X"
 	 * generic address structures as necessary. Later code will always use
diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c
index 1aecf7b..c03500b 100644
--- a/drivers/acpi/acpica/tbinstal.c
+++ b/drivers/acpi/acpica/tbinstal.c
@@ -114,7 +114,6 @@
 {
 	u32 i;
 	acpi_status status = AE_OK;
-	struct acpi_table_header *override_table = NULL;
 
 	ACPI_FUNCTION_TRACE(tb_add_table);
 
@@ -224,25 +223,10 @@
 	/*
 	 * ACPI Table Override:
 	 * Allow the host to override dynamically loaded tables.
+	 * NOTE: the table is fully mapped at this point, and the mapping will
+	 * be deleted by tb_table_override if the table is actually overridden.
 	 */
-	status = acpi_os_table_override(table_desc->pointer, &override_table);
-	if (ACPI_SUCCESS(status) && override_table) {
-		ACPI_INFO((AE_INFO,
-			   "%4.4s @ 0x%p Table override, replaced with:",
-			   table_desc->pointer->signature,
-			   ACPI_CAST_PTR(void, table_desc->address)));
-
-		/* We can delete the table that was passed as a parameter */
-
-		acpi_tb_delete_table(table_desc);
-
-		/* Setup descriptor for the new table */
-
-		table_desc->address = ACPI_PTR_TO_PHYSADDR(override_table);
-		table_desc->pointer = override_table;
-		table_desc->length = override_table->length;
-		table_desc->flags = ACPI_TABLE_ORIGIN_OVERRIDE;
-	}
+	(void)acpi_tb_table_override(table_desc->pointer, table_desc);
 
 	/* Add the table to the global root table list */
 
@@ -263,6 +247,95 @@
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_tb_table_override
+ *
+ * PARAMETERS:  table_header        - Header for the original table
+ *              table_desc          - Table descriptor initialized for the
+ *                                    original table. May or may not be mapped.
+ *
+ * RETURN:      Pointer to the entire new table. NULL if table not overridden.
+ *              If overridden, installs the new table within the input table
+ *              descriptor.
+ *
+ * DESCRIPTION: Attempt table override by calling the OSL override functions.
+ *              Note: If the table is overridden, then the entire new table
+ *              is mapped and returned by this function.
+ *
+ ******************************************************************************/
+
+struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header
+						 *table_header,
+						 struct acpi_table_desc
+						 *table_desc)
+{
+	acpi_status status;
+	struct acpi_table_header *new_table = NULL;
+	acpi_physical_address new_address = 0;
+	u32 new_table_length = 0;
+	u8 new_flags;
+	char *override_type;
+
+	/* (1) Attempt logical override (returns a logical address) */
+
+	status = acpi_os_table_override(table_header, &new_table);
+	if (ACPI_SUCCESS(status) && new_table) {
+		new_address = ACPI_PTR_TO_PHYSADDR(new_table);
+		new_table_length = new_table->length;
+		new_flags = ACPI_TABLE_ORIGIN_OVERRIDE;
+		override_type = "Logical";
+		goto finish_override;
+	}
+
+	/* (2) Attempt physical override (returns a physical address) */
+
+	status = acpi_os_physical_table_override(table_header,
+						 &new_address,
+						 &new_table_length);
+	if (ACPI_SUCCESS(status) && new_address && new_table_length) {
+
+		/* Map the entire new table */
+
+		new_table = acpi_os_map_memory(new_address, new_table_length);
+		if (!new_table) {
+			ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY,
+					"%4.4s %p Attempted physical table override failed",
+					table_header->signature,
+					ACPI_CAST_PTR(void,
+						      table_desc->address)));
+			return (NULL);
+		}
+
+		override_type = "Physical";
+		new_flags = ACPI_TABLE_ORIGIN_MAPPED;
+		goto finish_override;
+	}
+
+	return (NULL);		/* There was no override */
+
+      finish_override:
+
+	ACPI_INFO((AE_INFO,
+		   "%4.4s %p %s table override, new table: %p",
+		   table_header->signature,
+		   ACPI_CAST_PTR(void, table_desc->address),
+		   override_type, new_table));
+
+	/* We can now unmap/delete the original table (if fully mapped) */
+
+	acpi_tb_delete_table(table_desc);
+
+	/* Setup descriptor for the new table */
+
+	table_desc->address = new_address;
+	table_desc->pointer = new_table;
+	table_desc->length = new_table_length;
+	table_desc->flags = new_flags;
+
+	return (new_table);
+}
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_tb_resize_root_table_list
  *
  * PARAMETERS:  None
@@ -396,7 +469,11 @@
 	case ACPI_TABLE_ORIGIN_ALLOCATED:
 		ACPI_FREE(table_desc->pointer);
 		break;
-	default:;
+
+		/* Not mapped or allocated, there is nothing we can do */
+
+	default:
+		return;
 	}
 
 	table_desc->pointer = NULL;
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 09ca39e..0a706ca 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -118,6 +118,7 @@
 		return AE_OK;
 }
 
+#if (!ACPI_REDUCED_HARDWARE)
 /*******************************************************************************
  *
  * FUNCTION:    acpi_tb_initialize_facs
@@ -148,6 +149,7 @@
 								&acpi_gbl_FACS));
 	return status;
 }
+#endif				/* !ACPI_REDUCED_HARDWARE */
 
 /*******************************************************************************
  *
@@ -444,7 +446,7 @@
  * RETURN:      None
  *
  * DESCRIPTION: Install an ACPI table into the global data structure. The
- *              table override mechanism is implemented here to allow the host
+ *              table override mechanism is called to allow the host
  *              OS to replace any table before it is installed in the root
  *              table array.
  *
@@ -454,11 +456,9 @@
 acpi_tb_install_table(acpi_physical_address address,
 		      char *signature, u32 table_index)
 {
-	u8 flags;
-	acpi_status status;
-	struct acpi_table_header *table_to_install;
-	struct acpi_table_header *mapped_table;
-	struct acpi_table_header *override_table = NULL;
+	struct acpi_table_header *table;
+	struct acpi_table_header *final_table;
+	struct acpi_table_desc *table_desc;
 
 	if (!address) {
 		ACPI_ERROR((AE_INFO,
@@ -469,69 +469,78 @@
 
 	/* Map just the table header */
 
-	mapped_table =
-	    acpi_os_map_memory(address, sizeof(struct acpi_table_header));
-	if (!mapped_table) {
+	table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+	if (!table) {
+		ACPI_ERROR((AE_INFO,
+			    "Could not map memory for table [%s] at %p",
+			    signature, ACPI_CAST_PTR(void, address)));
 		return;
 	}
 
 	/* If a particular signature is expected (DSDT/FACS), it must match */
 
-	if (signature && !ACPI_COMPARE_NAME(mapped_table->signature, signature)) {
+	if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) {
 		ACPI_ERROR((AE_INFO,
 			    "Invalid signature 0x%X for ACPI table, expected [%s]",
-			    *ACPI_CAST_PTR(u32, mapped_table->signature),
-			    signature));
+			    *ACPI_CAST_PTR(u32, table->signature), signature));
 		goto unmap_and_exit;
 	}
 
 	/*
+	 * Initialize the table entry. Set the pointer to NULL, since the
+	 * table is not fully mapped at this time.
+	 */
+	table_desc = &acpi_gbl_root_table_list.tables[table_index];
+
+	table_desc->address = address;
+	table_desc->pointer = NULL;
+	table_desc->length = table->length;
+	table_desc->flags = ACPI_TABLE_ORIGIN_MAPPED;
+	ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature);
+
+	/*
 	 * ACPI Table Override:
 	 *
 	 * Before we install the table, let the host OS override it with a new
 	 * one if desired. Any table within the RSDT/XSDT can be replaced,
 	 * including the DSDT which is pointed to by the FADT.
+	 *
+	 * NOTE: If the table is overridden, then final_table will contain a
+	 * mapped pointer to the full new table. If the table is not overridden,
+	 * or if there has been a physical override, then the table will be
+	 * fully mapped later (in verify table). In any case, we must
+	 * unmap the header that was mapped above.
 	 */
-	status = acpi_os_table_override(mapped_table, &override_table);
-	if (ACPI_SUCCESS(status) && override_table) {
-		ACPI_INFO((AE_INFO,
-			   "%4.4s @ 0x%p Table override, replaced with:",
-			   mapped_table->signature, ACPI_CAST_PTR(void,
-								  address)));
-
-		acpi_gbl_root_table_list.tables[table_index].pointer =
-		    override_table;
-		address = ACPI_PTR_TO_PHYSADDR(override_table);
-
-		table_to_install = override_table;
-		flags = ACPI_TABLE_ORIGIN_OVERRIDE;
-	} else {
-		table_to_install = mapped_table;
-		flags = ACPI_TABLE_ORIGIN_MAPPED;
+	final_table = acpi_tb_table_override(table, table_desc);
+	if (!final_table) {
+		final_table = table;	/* There was no override */
 	}
 
-	/* Initialize the table entry */
+	acpi_tb_print_table_header(table_desc->address, final_table);
 
-	acpi_gbl_root_table_list.tables[table_index].address = address;
-	acpi_gbl_root_table_list.tables[table_index].length =
-	    table_to_install->length;
-	acpi_gbl_root_table_list.tables[table_index].flags = flags;
-
-	ACPI_MOVE_32_TO_32(&
-			   (acpi_gbl_root_table_list.tables[table_index].
-			    signature), table_to_install->signature);
-
-	acpi_tb_print_table_header(address, table_to_install);
+	/* Set the global integer width (based upon revision of the DSDT) */
 
 	if (table_index == ACPI_TABLE_INDEX_DSDT) {
+		acpi_ut_set_integer_width(final_table->revision);
+	}
 
-		/* Global integer width is based upon revision of the DSDT */
-
-		acpi_ut_set_integer_width(table_to_install->revision);
+	/*
+	 * If we have a physical override during this early loading of the ACPI
+	 * tables, unmap the table for now. It will be mapped again later when
+	 * it is actually used. This supports very early loading of ACPI tables,
+	 * before virtual memory is fully initialized and running within the
+	 * host OS. Note: A logical override has the ACPI_TABLE_ORIGIN_OVERRIDE
+	 * flag set and will not be deleted below.
+	 */
+	if (final_table != table) {
+		acpi_tb_delete_table(table_desc);
 	}
 
       unmap_and_exit:
-	acpi_os_unmap_memory(mapped_table, sizeof(struct acpi_table_header));
+
+	/* Always unmap the table header that we mapped above */
+
+	acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
 }
 
 /*******************************************************************************
diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c
index d42ede52..6848499 100644
--- a/drivers/acpi/acpica/utdecode.c
+++ b/drivers/acpi/acpica/utdecode.c
@@ -497,19 +497,20 @@
 
 /* Names for Notify() values, used for debug output */
 
-static const char *acpi_gbl_notify_value_names[] = {
-	"Bus Check",
-	"Device Check",
-	"Device Wake",
-	"Eject Request",
-	"Device Check Light",
-	"Frequency Mismatch",
-	"Bus Mode Mismatch",
-	"Power Fault",
-	"Capabilities Check",
-	"Device PLD Check",
-	"Reserved",
-	"System Locality Update"
+static const char *acpi_gbl_notify_value_names[ACPI_NOTIFY_MAX + 1] = {
+	/* 00 */ "Bus Check",
+	/* 01 */ "Device Check",
+	/* 02 */ "Device Wake",
+	/* 03 */ "Eject Request",
+	/* 04 */ "Device Check Light",
+	/* 05 */ "Frequency Mismatch",
+	/* 06 */ "Bus Mode Mismatch",
+	/* 07 */ "Power Fault",
+	/* 08 */ "Capabilities Check",
+	/* 09 */ "Device PLD Check",
+	/* 10 */ "Reserved",
+	/* 11 */ "System Locality Update",
+	/* 12 */ "Shutdown Request"
 };
 
 const char *acpi_ut_get_notify_name(u32 notify_value)
@@ -519,9 +520,10 @@
 		return (acpi_gbl_notify_value_names[notify_value]);
 	} else if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
 		return ("Reserved");
-	} else {		/* Greater or equal to 0x80 */
-
-		return ("**Device Specific**");
+	} else if (notify_value <= ACPI_MAX_DEVICE_SPECIFIC_NOTIFY) {
+		return ("Device Specific");
+	} else {
+		return ("Hardware Specific");
 	}
 }
 #endif
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index 4153584..90f53b4 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -140,6 +140,7 @@
 	{NULL, ACPI_TYPE_ANY, NULL}
 };
 
+#if (!ACPI_REDUCED_HARDWARE)
 /******************************************************************************
  *
  * Event and Hardware globals
@@ -236,6 +237,7 @@
 					ACPI_BITMASK_RT_CLOCK_STATUS,
 					ACPI_BITMASK_RT_CLOCK_ENABLE},
 };
+#endif				/* !ACPI_REDUCED_HARDWARE */
 
 /*******************************************************************************
  *
@@ -286,6 +288,8 @@
 
 	acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS - 1] = 0x80000000;
 
+#if (!ACPI_REDUCED_HARDWARE)
+
 	/* GPE support */
 
 	acpi_gbl_gpe_xrupt_list_head = NULL;
@@ -294,6 +298,10 @@
 	acpi_current_gpe_count = 0;
 	acpi_gbl_all_gpes_initialized = FALSE;
 
+	acpi_gbl_global_event_handler = NULL;
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
+
 	/* Global handlers */
 
 	acpi_gbl_system_notify.handler = NULL;
@@ -302,7 +310,6 @@
 	acpi_gbl_init_handler = NULL;
 	acpi_gbl_table_handler = NULL;
 	acpi_gbl_interface_handler = NULL;
-	acpi_gbl_global_event_handler = NULL;
 
 	/* Global Lock support */
 
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index 8359c0c..246798e 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -53,27 +53,35 @@
 /* Local prototypes */
 static void acpi_ut_terminate(void);
 
+#if (!ACPI_REDUCED_HARDWARE)
+
+static void acpi_ut_free_gpe_lists(void);
+
+#else
+
+#define acpi_ut_free_gpe_lists()
+#endif				/* !ACPI_REDUCED_HARDWARE */
+
+#if (!ACPI_REDUCED_HARDWARE)
 /******************************************************************************
  *
- * FUNCTION:    acpi_ut_terminate
+ * FUNCTION:    acpi_ut_free_gpe_lists
  *
  * PARAMETERS:  none
  *
  * RETURN:      none
  *
- * DESCRIPTION: Free global memory
+ * DESCRIPTION: Free global GPE lists
  *
  ******************************************************************************/
 
-static void acpi_ut_terminate(void)
+static void acpi_ut_free_gpe_lists(void)
 {
 	struct acpi_gpe_block_info *gpe_block;
 	struct acpi_gpe_block_info *next_gpe_block;
 	struct acpi_gpe_xrupt_info *gpe_xrupt_info;
 	struct acpi_gpe_xrupt_info *next_gpe_xrupt_info;
 
-	ACPI_FUNCTION_TRACE(ut_terminate);
-
 	/* Free global GPE blocks and related info structures */
 
 	gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
@@ -91,7 +99,26 @@
 		ACPI_FREE(gpe_xrupt_info);
 		gpe_xrupt_info = next_gpe_xrupt_info;
 	}
+}
+#endif				/* !ACPI_REDUCED_HARDWARE */
 
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_terminate
+ *
+ * PARAMETERS:  none
+ *
+ * RETURN:      none
+ *
+ * DESCRIPTION: Free global memory
+ *
+ ******************************************************************************/
+
+static void acpi_ut_terminate(void)
+{
+	ACPI_FUNCTION_TRACE(ut_terminate);
+
+	acpi_ut_free_gpe_lists();
 	acpi_ut_delete_address_lists();
 	return_VOID;
 }
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index 644e8c8..afa94f5 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -145,6 +145,8 @@
 
 	ACPI_FUNCTION_TRACE(acpi_enable_subsystem);
 
+#if (!ACPI_REDUCED_HARDWARE)
+
 	/* Enable ACPI mode */
 
 	if (!(flags & ACPI_NO_ACPI_ENABLE)) {
@@ -169,6 +171,7 @@
 		ACPI_WARNING((AE_INFO, "Could not map the FACS table"));
 		return_ACPI_STATUS(status);
 	}
+#endif				/* !ACPI_REDUCED_HARDWARE */
 
 	/*
 	 * Install the default op_region handlers. These are installed unless
@@ -184,7 +187,7 @@
 			return_ACPI_STATUS(status);
 		}
 	}
-
+#if (!ACPI_REDUCED_HARDWARE)
 	/*
 	 * Initialize ACPI Event handling (Fixed and General Purpose)
 	 *
@@ -220,6 +223,7 @@
 			return_ACPI_STATUS(status);
 		}
 	}
+#endif				/* !ACPI_REDUCED_HARDWARE */
 
 	return_ACPI_STATUS(status);
 }
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index e5d53b7..5577762 100644
--- a/drivers/acpi/apei/apei-base.c
+++ b/drivers/acpi/apei/apei-base.c
@@ -558,33 +558,48 @@
 }
 EXPORT_SYMBOL_GPL(apei_resources_release);
 
-static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr)
+static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr,
+				u32 *access_bit_width)
 {
-	u32 width, space_id;
+	u32 bit_width, bit_offset, access_size_code, space_id;
 
-	width = reg->bit_width;
+	bit_width = reg->bit_width;
+	bit_offset = reg->bit_offset;
+	access_size_code = reg->access_width;
 	space_id = reg->space_id;
 	/* Handle possible alignment issues */
 	memcpy(paddr, &reg->address, sizeof(*paddr));
 	if (!*paddr) {
 		pr_warning(FW_BUG APEI_PFX
-			   "Invalid physical address in GAR [0x%llx/%u/%u]\n",
-			   *paddr, width, space_id);
+			   "Invalid physical address in GAR [0x%llx/%u/%u/%u/%u]\n",
+			   *paddr, bit_width, bit_offset, access_size_code,
+			   space_id);
 		return -EINVAL;
 	}
 
-	if ((width != 8) && (width != 16) && (width != 32) && (width != 64)) {
+	if (access_size_code < 1 || access_size_code > 4) {
 		pr_warning(FW_BUG APEI_PFX
-			   "Invalid bit width in GAR [0x%llx/%u/%u]\n",
-			   *paddr, width, space_id);
+			   "Invalid access size code in GAR [0x%llx/%u/%u/%u/%u]\n",
+			   *paddr, bit_width, bit_offset, access_size_code,
+			   space_id);
+		return -EINVAL;
+	}
+	*access_bit_width = 1UL << (access_size_code + 2);
+
+	if ((bit_width + bit_offset) > *access_bit_width) {
+		pr_warning(FW_BUG APEI_PFX
+			   "Invalid bit width + offset in GAR [0x%llx/%u/%u/%u/%u]\n",
+			   *paddr, bit_width, bit_offset, access_size_code,
+			   space_id);
 		return -EINVAL;
 	}
 
 	if (space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY &&
 	    space_id != ACPI_ADR_SPACE_SYSTEM_IO) {
 		pr_warning(FW_BUG APEI_PFX
-			   "Invalid address space type in GAR [0x%llx/%u/%u]\n",
-			   *paddr, width, space_id);
+			   "Invalid address space type in GAR [0x%llx/%u/%u/%u/%u]\n",
+			   *paddr, bit_width, bit_offset, access_size_code,
+			   space_id);
 		return -EINVAL;
 	}
 
@@ -595,23 +610,25 @@
 int apei_read(u64 *val, struct acpi_generic_address *reg)
 {
 	int rc;
+	u32 access_bit_width;
 	u64 address;
 	acpi_status status;
 
-	rc = apei_check_gar(reg, &address);
+	rc = apei_check_gar(reg, &address, &access_bit_width);
 	if (rc)
 		return rc;
 
 	*val = 0;
 	switch(reg->space_id) {
 	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
-		status = acpi_os_read_memory64((acpi_physical_address)
-					     address, val, reg->bit_width);
+		status = acpi_os_read_memory((acpi_physical_address) address,
+					       val, access_bit_width);
 		if (ACPI_FAILURE(status))
 			return -EIO;
 		break;
 	case ACPI_ADR_SPACE_SYSTEM_IO:
-		status = acpi_os_read_port(address, (u32 *)val, reg->bit_width);
+		status = acpi_os_read_port(address, (u32 *)val,
+					   access_bit_width);
 		if (ACPI_FAILURE(status))
 			return -EIO;
 		break;
@@ -627,22 +644,23 @@
 int apei_write(u64 val, struct acpi_generic_address *reg)
 {
 	int rc;
+	u32 access_bit_width;
 	u64 address;
 	acpi_status status;
 
-	rc = apei_check_gar(reg, &address);
+	rc = apei_check_gar(reg, &address, &access_bit_width);
 	if (rc)
 		return rc;
 
 	switch (reg->space_id) {
 	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
-		status = acpi_os_write_memory64((acpi_physical_address)
-					      address, val, reg->bit_width);
+		status = acpi_os_write_memory((acpi_physical_address) address,
+						val, access_bit_width);
 		if (ACPI_FAILURE(status))
 			return -EIO;
 		break;
 	case ACPI_ADR_SPACE_SYSTEM_IO:
-		status = acpi_os_write_port(address, val, reg->bit_width);
+		status = acpi_os_write_port(address, val, access_bit_width);
 		if (ACPI_FAILURE(status))
 			return -EIO;
 		break;
@@ -661,23 +679,24 @@
 	struct apei_resources *resources = data;
 	struct acpi_generic_address *reg = &entry->register_region;
 	u8 ins = entry->instruction;
+	u32 access_bit_width;
 	u64 paddr;
 	int rc;
 
 	if (!(ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER))
 		return 0;
 
-	rc = apei_check_gar(reg, &paddr);
+	rc = apei_check_gar(reg, &paddr, &access_bit_width);
 	if (rc)
 		return rc;
 
 	switch (reg->space_id) {
 	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
 		return apei_res_add(&resources->iomem, paddr,
-				    reg->bit_width / 8);
+				    access_bit_width / 8);
 	case ACPI_ADR_SPACE_SYSTEM_IO:
 		return apei_res_add(&resources->ioport, paddr,
-				    reg->bit_width / 8);
+				    access_bit_width / 8);
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c
index 5d41894..e6defd8 100644
--- a/drivers/acpi/apei/cper.c
+++ b/drivers/acpi/apei/cper.c
@@ -362,6 +362,7 @@
 		gedata_len = gdata->error_data_length;
 		apei_estatus_print_section(pfx, gdata, sec_no);
 		data_len -= gedata_len + sizeof(*gdata);
+		gdata = (void *)(gdata + 1) + gedata_len;
 		sec_no++;
 	}
 }
@@ -396,6 +397,7 @@
 		if (gedata_len > data_len - sizeof(*gdata))
 			return -EINVAL;
 		data_len -= gedata_len + sizeof(*gdata);
+		gdata = (void *)(gdata + 1) + gedata_len;
 	}
 	if (data_len)
 		return -EINVAL;
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index 4ca087d..8e17936 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -74,6 +74,8 @@
 	u8	reserved[3];
 };
 
+static u32 notrigger;
+
 static u32 vendor_flags;
 static struct debugfs_blob_wrapper vendor_blob;
 static char vendor_dev[64];
@@ -238,7 +240,7 @@
 			return v5param;
 		}
 	}
-	if (paddrv4) {
+	if (param_extension && paddrv4) {
 		struct einj_parameter *v4param;
 
 		v4param = acpi_os_map_memory(paddrv4, sizeof(*v4param));
@@ -496,9 +498,11 @@
 	if (rc)
 		return rc;
 	trigger_paddr = apei_exec_ctx_get_output(&ctx);
-	rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
-	if (rc)
-		return rc;
+	if (notrigger == 0) {
+		rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
+		if (rc)
+			return rc;
+	}
 	rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION);
 
 	return rc;
@@ -700,6 +704,11 @@
 					    einj_debug_dir, &error_param2);
 		if (!fentry)
 			goto err_unmap;
+
+		fentry = debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR,
+					    einj_debug_dir, &notrigger);
+		if (!fentry)
+			goto err_unmap;
 	}
 
 	if (vendor_dev[0]) {
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index eb9fab5..e4d9d24 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -917,7 +917,7 @@
 {
 	if ((erst_tab->header_length !=
 	     (sizeof(struct acpi_table_erst) - sizeof(erst_tab->header)))
-	    && (erst_tab->header_length != sizeof(struct acpi_table_einj)))
+	    && (erst_tab->header_length != sizeof(struct acpi_table_erst)))
 		return -EINVAL;
 	if (erst_tab->header.length < sizeof(struct acpi_table_erst))
 		return -EINVAL;
diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c
new file mode 100644
index 0000000..8cf6c46
--- /dev/null
+++ b/drivers/acpi/bgrt.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2012 Red Hat, Inc <mjg@redhat.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/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <acpi/acpi.h>
+#include <acpi/acpi_bus.h>
+
+static struct acpi_table_bgrt *bgrt_tab;
+static struct kobject *bgrt_kobj;
+
+struct bmp_header {
+	u16 id;
+	u32 size;
+} __attribute ((packed));
+
+static struct bmp_header bmp_header;
+
+static ssize_t show_version(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->version);
+}
+static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+
+static ssize_t show_status(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->status);
+}
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+static ssize_t show_type(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_type);
+}
+static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
+
+static ssize_t show_xoffset(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_offset_x);
+}
+static DEVICE_ATTR(xoffset, S_IRUGO, show_xoffset, NULL);
+
+static ssize_t show_yoffset(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_offset_y);
+}
+static DEVICE_ATTR(yoffset, S_IRUGO, show_yoffset, NULL);
+
+static ssize_t show_image(struct file *file, struct kobject *kobj,
+	       struct bin_attribute *attr, char *buf, loff_t off, size_t count)
+{
+	int size = attr->size;
+	void __iomem *image = attr->private;
+
+	if (off >= size) {
+		count = 0;
+	} else {
+		if (off + count > size)
+			count = size - off;
+
+		memcpy_fromio(buf, image+off, count);
+	}
+
+	return count;
+}
+
+static struct bin_attribute image_attr = {
+	.attr = {
+		.name = "image",
+		.mode = S_IRUGO,
+	},
+	.read = show_image,
+};
+
+static struct attribute *bgrt_attributes[] = {
+	&dev_attr_version.attr,
+	&dev_attr_status.attr,
+	&dev_attr_type.attr,
+	&dev_attr_xoffset.attr,
+	&dev_attr_yoffset.attr,
+	NULL,
+};
+
+static struct attribute_group bgrt_attribute_group = {
+	.attrs = bgrt_attributes,
+};
+
+static int __init bgrt_init(void)
+{
+	acpi_status status;
+	int ret;
+	void __iomem *bgrt;
+
+	if (acpi_disabled)
+		return -ENODEV;
+
+	status = acpi_get_table("BGRT", 0,
+				(struct acpi_table_header **)&bgrt_tab);
+
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	sysfs_bin_attr_init(&image_attr);
+
+	bgrt = ioremap(bgrt_tab->image_address, sizeof(struct bmp_header));
+
+	if (!bgrt) {
+		ret = -EINVAL;
+		goto out_err;
+	}
+
+	memcpy_fromio(&bmp_header, bgrt, sizeof(bmp_header));
+	image_attr.size = bmp_header.size;
+	iounmap(bgrt);
+
+	image_attr.private = ioremap(bgrt_tab->image_address, image_attr.size);
+
+	if (!image_attr.private) {
+		ret = -EINVAL;
+		goto out_err;
+	}
+
+
+	bgrt_kobj = kobject_create_and_add("bgrt", acpi_kobj);
+	if (!bgrt_kobj) {
+		ret = -EINVAL;
+		goto out_iounmap;
+	}
+
+	ret = sysfs_create_group(bgrt_kobj, &bgrt_attribute_group);
+	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);
+out_iounmap:
+	iounmap(image_attr.private);
+out_err:
+	return ret;
+}
+
+static void __exit bgrt_exit(void)
+{
+	iounmap(image_attr.private);
+	sysfs_remove_group(bgrt_kobj, &bgrt_attribute_group);
+	sysfs_remove_bin_file(bgrt_kobj, &image_attr);
+}
+
+module_init(bgrt_init);
+module_exit(bgrt_exit);
+
+MODULE_AUTHOR("Matthew Garrett");
+MODULE_DESCRIPTION("BGRT boot graphic support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 9ecec98..3263b68 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -1010,6 +1010,7 @@
 }
 
 struct kobject *acpi_kobj;
+EXPORT_SYMBOL_GPL(acpi_kobj);
 
 static int __init acpi_init(void)
 {
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index b19a18d..7edaccc 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -445,6 +445,16 @@
 
 EXPORT_SYMBOL(ec_transaction);
 
+/* Get the handle to the EC device */
+acpi_handle ec_get_handle(void)
+{
+	if (!first_ec)
+		return NULL;
+	return first_ec->handle;
+}
+
+EXPORT_SYMBOL(ec_get_handle);
+
 void acpi_ec_block_transactions(void)
 {
 	struct acpi_ec *ec = first_ec;
@@ -812,10 +822,10 @@
 		first_ec = ec;
 	device->driver_data = ec;
 
-	WARN(!request_region(ec->data_addr, 1, "EC data"),
-	     "Could not request EC data io port 0x%lx", ec->data_addr);
-	WARN(!request_region(ec->command_addr, 1, "EC cmd"),
-	     "Could not request EC cmd io port 0x%lx", ec->command_addr);
+	ret = !!request_region(ec->data_addr, 1, "EC data");
+	WARN(!ret, "Could not request EC data io port 0x%lx", ec->data_addr);
+	ret = !!request_region(ec->command_addr, 1, "EC cmd");
+	WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr);
 
 	pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
 			  ec->gpe, ec->command_addr, ec->data_addr);
diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c
index b258cab..7586544 100644
--- a/drivers/acpi/ec_sys.c
+++ b/drivers/acpi/ec_sys.c
@@ -27,12 +27,6 @@
 
 static struct dentry *acpi_ec_debugfs_dir;
 
-static int acpi_ec_open_io(struct inode *i, struct file *f)
-{
-	f->private_data = i->i_private;
-	return 0;
-}
-
 static ssize_t acpi_ec_read_io(struct file *f, char __user *buf,
 			       size_t count, loff_t *off)
 {
@@ -95,7 +89,7 @@
 
 static const struct file_operations acpi_ec_io_ops = {
 	.owner = THIS_MODULE,
-	.open  = acpi_ec_open_io,
+	.open  = simple_open,
 	.read  = acpi_ec_read_io,
 	.write = acpi_ec_write_io,
 	.llseek = default_llseek,
diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c
index 7a2035f..266bc58 100644
--- a/drivers/acpi/nvs.c
+++ b/drivers/acpi/nvs.c
@@ -95,8 +95,8 @@
 {
 	struct nvs_page *entry, *next;
 
-	pr_info("PM: Registering ACPI NVS region at %lx (%ld bytes)\n",
-		start, size);
+	pr_info("PM: Registering ACPI NVS region [mem %#010lx-%#010lx] (%ld bytes)\n",
+		start, start + size - 1, size);
 
 	while (size > 0) {
 		unsigned int nr_bytes;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 412a1e0..ba14fb9 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -77,6 +77,9 @@
 extern char line_buf[80];
 #endif				/*ENABLE_DEBUGGER */
 
+static int (*__acpi_os_prepare_sleep)(u8 sleep_state, u32 pm1a_ctrl,
+				      u32 pm1b_ctrl);
+
 static acpi_osd_handler acpi_irq_handler;
 static void *acpi_irq_context;
 static struct workqueue_struct *kacpid_wq;
@@ -347,7 +350,7 @@
 	unsigned long pfn;
 
 	pfn = pg_off >> PAGE_SHIFT;
-	if (page_is_ram(pfn))
+	if (should_use_kmap(pfn))
 		kunmap(pfn_to_page(pfn));
 	else
 		iounmap(vaddr);
@@ -554,6 +557,15 @@
 	return AE_OK;
 }
 
+acpi_status
+acpi_os_physical_table_override(struct acpi_table_header *existing_table,
+				acpi_physical_address * new_address,
+				u32 *new_table_length)
+{
+	return AE_SUPPORT;
+}
+
+
 static irqreturn_t acpi_irq(int irq, void *dev_id)
 {
 	u32 handled;
@@ -595,7 +607,8 @@
 
 	acpi_irq_handler = handler;
 	acpi_irq_context = context;
-	if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) {
+	if (request_threaded_irq(irq, NULL, acpi_irq, IRQF_SHARED, "acpi",
+				 acpi_irq)) {
 		printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq);
 		acpi_irq_handler = NULL;
 		return AE_NOT_ACQUIRED;
@@ -699,49 +712,6 @@
 
 EXPORT_SYMBOL(acpi_os_write_port);
 
-acpi_status
-acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
-{
-	void __iomem *virt_addr;
-	unsigned int size = width / 8;
-	bool unmap = false;
-	u32 dummy;
-
-	rcu_read_lock();
-	virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
-	if (!virt_addr) {
-		rcu_read_unlock();
-		virt_addr = acpi_os_ioremap(phys_addr, size);
-		if (!virt_addr)
-			return AE_BAD_ADDRESS;
-		unmap = true;
-	}
-
-	if (!value)
-		value = &dummy;
-
-	switch (width) {
-	case 8:
-		*(u8 *) value = readb(virt_addr);
-		break;
-	case 16:
-		*(u16 *) value = readw(virt_addr);
-		break;
-	case 32:
-		*(u32 *) value = readl(virt_addr);
-		break;
-	default:
-		BUG();
-	}
-
-	if (unmap)
-		iounmap(virt_addr);
-	else
-		rcu_read_unlock();
-
-	return AE_OK;
-}
-
 #ifdef readq
 static inline u64 read64(const volatile void __iomem *addr)
 {
@@ -758,7 +728,7 @@
 #endif
 
 acpi_status
-acpi_os_read_memory64(acpi_physical_address phys_addr, u64 *value, u32 width)
+acpi_os_read_memory(acpi_physical_address phys_addr, u64 *value, u32 width)
 {
 	void __iomem *virt_addr;
 	unsigned int size = width / 8;
@@ -803,45 +773,6 @@
 	return AE_OK;
 }
 
-acpi_status
-acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
-{
-	void __iomem *virt_addr;
-	unsigned int size = width / 8;
-	bool unmap = false;
-
-	rcu_read_lock();
-	virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
-	if (!virt_addr) {
-		rcu_read_unlock();
-		virt_addr = acpi_os_ioremap(phys_addr, size);
-		if (!virt_addr)
-			return AE_BAD_ADDRESS;
-		unmap = true;
-	}
-
-	switch (width) {
-	case 8:
-		writeb(value, virt_addr);
-		break;
-	case 16:
-		writew(value, virt_addr);
-		break;
-	case 32:
-		writel(value, virt_addr);
-		break;
-	default:
-		BUG();
-	}
-
-	if (unmap)
-		iounmap(virt_addr);
-	else
-		rcu_read_unlock();
-
-	return AE_OK;
-}
-
 #ifdef writeq
 static inline void write64(u64 val, volatile void __iomem *addr)
 {
@@ -856,7 +787,7 @@
 #endif
 
 acpi_status
-acpi_os_write_memory64(acpi_physical_address phys_addr, u64 value, u32 width)
+acpi_os_write_memory(acpi_physical_address phys_addr, u64 value, u32 width)
 {
 	void __iomem *virt_addr;
 	unsigned int size = width / 8;
@@ -1641,3 +1572,24 @@
 
 	return AE_OK;
 }
+
+acpi_status acpi_os_prepare_sleep(u8 sleep_state, u32 pm1a_control,
+				  u32 pm1b_control)
+{
+	int rc = 0;
+	if (__acpi_os_prepare_sleep)
+		rc = __acpi_os_prepare_sleep(sleep_state,
+					     pm1a_control, pm1b_control);
+	if (rc < 0)
+		return AE_ERROR;
+	else if (rc > 0)
+		return AE_CTRL_SKIP;
+
+	return AE_OK;
+}
+
+void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state,
+			       u32 pm1a_ctrl, u32 pm1b_ctrl))
+{
+	__acpi_os_prepare_sleep = func;
+}
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 9ac2a9f..7049a7d 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -40,9 +40,11 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include "sleep.h"
+#include "internal.h"
 
 #define PREFIX "ACPI: "
 
@@ -77,6 +79,20 @@
 		},
 };
 
+/*
+ * A power managed device
+ * A device may rely on multiple power resources.
+ * */
+struct acpi_power_managed_device {
+	struct device *dev; /* The physical device */
+	acpi_handle *handle;
+};
+
+struct acpi_power_resource_device {
+	struct acpi_power_managed_device *device;
+	struct acpi_power_resource_device *next;
+};
+
 struct acpi_power_resource {
 	struct acpi_device * device;
 	acpi_bus_id name;
@@ -84,6 +100,9 @@
 	u32 order;
 	unsigned int ref_count;
 	struct mutex resource_lock;
+
+	/* List of devices relying on this power resource */
+	struct acpi_power_resource_device *devices;
 };
 
 static struct list_head acpi_power_resource_list;
@@ -183,8 +202,26 @@
 	return 0;
 }
 
+/* Resume the device when all power resources in _PR0 are on */
+static void acpi_power_on_device(struct acpi_power_managed_device *device)
+{
+	struct acpi_device *acpi_dev;
+	acpi_handle handle = device->handle;
+	int state;
+
+	if (acpi_bus_get_device(handle, &acpi_dev))
+		return;
+
+	if(acpi_power_get_inferred_state(acpi_dev, &state))
+		return;
+
+	if (state == ACPI_STATE_D0 && pm_runtime_suspended(device->dev))
+		pm_request_resume(device->dev);
+}
+
 static int __acpi_power_on(struct acpi_power_resource *resource)
 {
+	struct acpi_power_resource_device *device_list = resource->devices;
 	acpi_status status = AE_OK;
 
 	status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
@@ -197,6 +234,12 @@
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
 			  resource->name));
 
+	while (device_list) {
+		acpi_power_on_device(device_list->device);
+
+		device_list = device_list->next;
+	}
+
 	return 0;
 }
 
@@ -299,6 +342,125 @@
 	return result;
 }
 
+static void __acpi_power_resource_unregister_device(struct device *dev,
+		acpi_handle res_handle)
+{
+	struct acpi_power_resource *resource = NULL;
+	struct acpi_power_resource_device *prev, *curr;
+
+	if (acpi_power_get_context(res_handle, &resource))
+		return;
+
+	mutex_lock(&resource->resource_lock);
+	prev = NULL;
+	curr = resource->devices;
+	while (curr) {
+		if (curr->device->dev == dev) {
+			if (!prev)
+				resource->devices = curr->next;
+			else
+				prev->next = curr->next;
+
+			kfree(curr);
+			break;
+		}
+
+		prev = curr;
+		curr = curr->next;
+	}
+	mutex_unlock(&resource->resource_lock);
+}
+
+/* Unlink dev from all power resources in _PR0 */
+void acpi_power_resource_unregister_device(struct device *dev, acpi_handle handle)
+{
+	struct acpi_device *acpi_dev;
+	struct acpi_handle_list *list;
+	int i;
+
+	if (!dev || !handle)
+		return;
+
+	if (acpi_bus_get_device(handle, &acpi_dev))
+		return;
+
+	list = &acpi_dev->power.states[ACPI_STATE_D0].resources;
+
+	for (i = 0; i < list->count; i++)
+		__acpi_power_resource_unregister_device(dev,
+			list->handles[i]);
+}
+
+static int __acpi_power_resource_register_device(
+	struct acpi_power_managed_device *powered_device, acpi_handle handle)
+{
+	struct acpi_power_resource *resource = NULL;
+	struct acpi_power_resource_device *power_resource_device;
+	int result;
+
+	result = acpi_power_get_context(handle, &resource);
+	if (result)
+		return result;
+
+	power_resource_device = kzalloc(
+		sizeof(*power_resource_device), GFP_KERNEL);
+	if (!power_resource_device)
+		return -ENOMEM;
+
+	power_resource_device->device = powered_device;
+
+	mutex_lock(&resource->resource_lock);
+	power_resource_device->next = resource->devices;
+	resource->devices = power_resource_device;
+	mutex_unlock(&resource->resource_lock);
+
+	return 0;
+}
+
+/* Link dev to all power resources in _PR0 */
+int acpi_power_resource_register_device(struct device *dev, acpi_handle handle)
+{
+	struct acpi_device *acpi_dev;
+	struct acpi_handle_list *list;
+	struct acpi_power_managed_device *powered_device;
+	int i, ret;
+
+	if (!dev || !handle)
+		return -ENODEV;
+
+	ret = acpi_bus_get_device(handle, &acpi_dev);
+	if (ret)
+		goto no_power_resource;
+
+	if (!acpi_dev->power.flags.power_resources)
+		goto no_power_resource;
+
+	powered_device = kzalloc(sizeof(*powered_device), GFP_KERNEL);
+	if (!powered_device)
+		return -ENOMEM;
+
+	powered_device->dev = dev;
+	powered_device->handle = handle;
+
+	list = &acpi_dev->power.states[ACPI_STATE_D0].resources;
+
+	for (i = 0; i < list->count; i++) {
+		ret = __acpi_power_resource_register_device(powered_device,
+			list->handles[i]);
+
+		if (ret) {
+			acpi_power_resource_unregister_device(dev, handle);
+			break;
+		}
+	}
+
+	return ret;
+
+no_power_resource:
+	printk(KERN_WARNING PREFIX "Invalid Power Resource to register!");
+	return -ENODEV;
+}
+
 /**
  * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
  *                          ACPI 3.0) _PSW (Power State Wake)
@@ -500,14 +662,14 @@
 {
 	int result;
 
-	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
+	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
 		return -EINVAL;
 
 	if (device->power.state == state)
 		return 0;
 
 	if ((device->power.state < ACPI_STATE_D0)
-	    || (device->power.state > ACPI_STATE_D3))
+	    || (device->power.state > ACPI_STATE_D3_COLD))
 		return -ENODEV;
 
 	/* TBD: Resources must be ordered. */
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 2801b41..0734086 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -46,7 +46,6 @@
 #include <linux/slab.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/cpu.h>
 #include <asm/delay.h>
 #include <asm/uaccess.h>
@@ -68,6 +67,7 @@
 #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
 #define ACPI_PROCESSOR_NOTIFY_POWER	0x81
 #define ACPI_PROCESSOR_NOTIFY_THROTTLING	0x82
+#define ACPI_PROCESSOR_DEVICE_HID	"ACPI0007"
 
 #define ACPI_PROCESSOR_LIMIT_USER	0
 #define ACPI_PROCESSOR_LIMIT_THERMAL	1
@@ -88,7 +88,7 @@
 
 static const struct acpi_device_id processor_device_ids[] = {
 	{ACPI_PROCESSOR_OBJECT_HID, 0},
-	{"ACPI0007", 0},
+	{ACPI_PROCESSOR_DEVICE_HID, 0},
 	{"", 0},
 };
 MODULE_DEVICE_TABLE(acpi, processor_device_ids);
@@ -536,8 +536,8 @@
 		return -ENOMEM;
 
 	if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) {
-		kfree(pr);
-		return -ENOMEM;
+		result = -ENOMEM;
+		goto err_free_pr;
 	}
 
 	pr->handle = device->handle;
@@ -577,7 +577,7 @@
 	dev = get_cpu_device(pr->id);
 	if (sysfs_create_link(&device->dev.kobj, &dev->kobj, "sysdev")) {
 		result = -EFAULT;
-		goto err_free_cpumask;
+		goto err_clear_processor;
 	}
 
 	/*
@@ -595,9 +595,15 @@
 
 err_remove_sysfs:
 	sysfs_remove_link(&device->dev.kobj, "sysdev");
+err_clear_processor:
+	/*
+	 * processor_device_array is not cleared to allow checks for buggy BIOS
+	 */ 
+	per_cpu(processors, pr->id) = NULL;
 err_free_cpumask:
 	free_cpumask_var(pr->throttling.shared_cpu_map);
-
+err_free_pr:
+	kfree(pr);
 	return result;
 }
 
@@ -742,20 +748,46 @@
 	return;
 }
 
+static acpi_status is_processor_device(acpi_handle handle)
+{
+	struct acpi_device_info *info;
+	char *hid;
+	acpi_status status;
+
+	status = acpi_get_object_info(handle, &info);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	if (info->type == ACPI_TYPE_PROCESSOR) {
+		kfree(info);
+		return AE_OK;	/* found a processor object */
+	}
+
+	if (!(info->valid & ACPI_VALID_HID)) {
+		kfree(info);
+		return AE_ERROR;
+	}
+
+	hid = info->hardware_id.string;
+	if ((hid == NULL) || strcmp(hid, ACPI_PROCESSOR_DEVICE_HID)) {
+		kfree(info);
+		return AE_ERROR;
+	}
+
+	kfree(info);
+	return AE_OK;	/* found a processor device object */
+}
+
 static acpi_status
 processor_walk_namespace_cb(acpi_handle handle,
 			    u32 lvl, void *context, void **rv)
 {
 	acpi_status status;
 	int *action = context;
-	acpi_object_type type = 0;
 
-	status = acpi_get_type(handle, &type);
+	status = is_processor_device(handle);
 	if (ACPI_FAILURE(status))
-		return (AE_OK);
-
-	if (type != ACPI_TYPE_PROCESSOR)
-		return (AE_OK);
+		return AE_OK;	/* not a processor; continue to walk */
 
 	switch (*action) {
 	case INSTALL_NOTIFY_HANDLER:
@@ -773,7 +805,8 @@
 		break;
 	}
 
-	return (AE_OK);
+	/* found a processor; skip walking underneath */
+	return AE_CTRL_DEPTH;
 }
 
 static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
@@ -831,7 +864,7 @@
 {
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
 	int action = INSTALL_NOTIFY_HANDLER;
-	acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+	acpi_walk_namespace(ACPI_TYPE_ANY,
 			    ACPI_ROOT_OBJECT,
 			    ACPI_UINT32_MAX,
 			    processor_walk_namespace_cb, NULL, &action, NULL);
@@ -844,7 +877,7 @@
 {
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
 	int action = UNINSTALL_NOTIFY_HANDLER;
-	acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+	acpi_walk_namespace(ACPI_TYPE_ANY,
 			    ACPI_ROOT_OBJECT,
 			    ACPI_UINT32_MAX,
 			    processor_walk_namespace_cb, NULL, &action, NULL);
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 0e8e2de..b3447f6 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -770,6 +770,35 @@
 	return index;
 }
 
+
+/**
+ * acpi_idle_play_dead - enters an ACPI state for long-term idle (i.e. off-lining)
+ * @dev: the target CPU
+ * @index: the index of suggested state
+ */
+static int acpi_idle_play_dead(struct cpuidle_device *dev, int index)
+{
+	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+	struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
+
+	ACPI_FLUSH_CPU_CACHE();
+
+	while (1) {
+
+		if (cx->entry_method == ACPI_CSTATE_HALT)
+			halt();
+		else if (cx->entry_method == ACPI_CSTATE_SYSTEMIO) {
+			inb(cx->address);
+			/* See comment in acpi_idle_do_entry() */
+			inl(acpi_gbl_FADT.xpm_timer_block.address);
+		} else
+			return -ENODEV;
+	}
+
+	/* Never reached */
+	return 0;
+}
+
 /**
  * acpi_idle_enter_simple - enters an ACPI state without BM handling
  * @dev: the target CPU
@@ -1077,12 +1106,14 @@
 				state->flags |= CPUIDLE_FLAG_TIME_VALID;
 
 			state->enter = acpi_idle_enter_c1;
+			state->enter_dead = acpi_idle_play_dead;
 			drv->safe_state_index = count;
 			break;
 
 			case ACPI_STATE_C2:
 			state->flags |= CPUIDLE_FLAG_TIME_VALID;
 			state->enter = acpi_idle_enter_simple;
+			state->enter_dead = acpi_idle_play_dead;
 			drv->safe_state_index = count;
 			break;
 
@@ -1159,8 +1190,7 @@
 	 * to make the code that updates C-States be called once.
 	 */
 
-	if (smp_processor_id() == 0 &&
-			cpuidle_get_driver() == &acpi_idle_driver) {
+	if (pr->id == 0 && cpuidle_get_driver() == &acpi_idle_driver) {
 
 		cpuidle_pause_and_lock();
 		/* Protect against cpu-hotplug */
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 3b599ab..641b545 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -57,6 +57,27 @@
 static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg);
 static unsigned int acpi_thermal_cpufreq_is_init = 0;
 
+#define reduction_pctg(cpu) \
+	per_cpu(cpufreq_thermal_reduction_pctg, phys_package_first_cpu(cpu))
+
+/*
+ * Emulate "per package data" using per cpu data (which should really be
+ * provided elsewhere)
+ *
+ * Note we can lose a CPU on cpu hotunplug, in this case we forget the state
+ * temporarily. Fortunately that's not a big issue here (I hope)
+ */
+static int phys_package_first_cpu(int cpu)
+{
+	int i;
+	int id = topology_physical_package_id(cpu);
+
+	for_each_online_cpu(i)
+		if (topology_physical_package_id(i) == id)
+			return i;
+	return 0;
+}
+
 static int cpu_has_cpufreq(unsigned int cpu)
 {
 	struct cpufreq_policy policy;
@@ -76,7 +97,7 @@
 
 	max_freq = (
 	    policy->cpuinfo.max_freq *
-	    (100 - per_cpu(cpufreq_thermal_reduction_pctg, policy->cpu) * 20)
+	    (100 - reduction_pctg(policy->cpu) * 20)
 	) / 100;
 
 	cpufreq_verify_within_limits(policy, 0, max_freq);
@@ -102,16 +123,28 @@
 	if (!cpu_has_cpufreq(cpu))
 		return 0;
 
-	return per_cpu(cpufreq_thermal_reduction_pctg, cpu);
+	return reduction_pctg(cpu);
 }
 
 static int cpufreq_set_cur_state(unsigned int cpu, int state)
 {
+	int i;
+
 	if (!cpu_has_cpufreq(cpu))
 		return 0;
 
-	per_cpu(cpufreq_thermal_reduction_pctg, cpu) = state;
-	cpufreq_update_policy(cpu);
+	reduction_pctg(cpu) = state;
+
+	/*
+	 * Update all the CPUs in the same package because they all
+	 * contribute to the temperature and often share the same
+	 * frequency.
+	 */
+	for_each_online_cpu(i) {
+		if (topology_physical_package_id(i) ==
+		    topology_physical_package_id(cpu))
+			cpufreq_update_policy(i);
+	}
 	return 0;
 }
 
@@ -119,10 +152,6 @@
 {
 	int i;
 
-	for (i = 0; i < nr_cpu_ids; i++)
-		if (cpu_present(i))
-			per_cpu(cpufreq_thermal_reduction_pctg, i) = 0;
-
 	i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block,
 				      CPUFREQ_POLICY_NOTIFIER);
 	if (!i)
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 605a295..1d02b7b 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -769,7 +769,7 @@
 					u64 *value)
 {
 	u32 bit_width, bit_offset;
-	u64 ptc_value;
+	u32 ptc_value;
 	u64 ptc_mask;
 	struct acpi_processor_throttling *throttling;
 	int ret = -1;
@@ -777,12 +777,11 @@
 	throttling = &pr->throttling;
 	switch (throttling->status_register.space_id) {
 	case ACPI_ADR_SPACE_SYSTEM_IO:
-		ptc_value = 0;
 		bit_width = throttling->status_register.bit_width;
 		bit_offset = throttling->status_register.bit_offset;
 
 		acpi_os_read_port((acpi_io_address) throttling->status_register.
-				  address, (u32 *) &ptc_value,
+				  address, &ptc_value,
 				  (u32) (bit_width + bit_offset));
 		ptc_mask = (1 << bit_width) - 1;
 		*value = (u64) ((ptc_value >> bit_offset) & ptc_mask);
diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c
index a6c77e8b..c1d6124 100644
--- a/drivers/acpi/reboot.c
+++ b/drivers/acpi/reboot.c
@@ -23,8 +23,7 @@
 	/* Is the reset register supported? The spec says we should be
 	 * checking the bit width and bit offset, but Windows ignores
 	 * these fields */
-	if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER))
-		return;
+	/* Ignore also acpi_gbl_FADT.flags.ACPI_FADT_RESET_REGISTER */
 
 	reset_value = acpi_gbl_FADT.reset_value;
 
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 8ab80ba..767e2dc 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -880,18 +880,22 @@
 			int j;
 
 			device->power.flags.power_resources = 1;
-			ps->flags.valid = 1;
 			for (j = 0; j < ps->resources.count; j++)
 				acpi_bus_add_power_resource(ps->resources.handles[j]);
 		}
 
+		/* The exist of _PR3 indicates D3Cold support */
+		if (i == ACPI_STATE_D3) {
+			status = acpi_get_handle(device->handle, object_name, &handle);
+			if (ACPI_SUCCESS(status))
+				device->power.states[ACPI_STATE_D3_COLD].flags.valid = 1;
+		}
+
 		/* Evaluate "_PSx" to see if we can do explicit sets */
 		object_name[2] = 'S';
 		status = acpi_get_handle(device->handle, object_name, &handle);
-		if (ACPI_SUCCESS(status)) {
+		if (ACPI_SUCCESS(status))
 			ps->flags.explicit_set = 1;
-			ps->flags.valid = 1;
-		}
 
 		/* State is valid if we have some power control */
 		if (ps->resources.count || ps->flags.explicit_set)
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index ca191ff..1d661b5 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -17,6 +17,8 @@
 #include <linux/suspend.h>
 #include <linux/reboot.h>
 #include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
 
 #include <asm/io.h>
 
@@ -26,6 +28,24 @@
 #include "internal.h"
 #include "sleep.h"
 
+static unsigned int gts, bfs;
+module_param(gts, uint, 0644);
+module_param(bfs, uint, 0644);
+MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend.");
+MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".);
+
+static u8 wake_sleep_flags(void)
+{
+	u8 flags = ACPI_NO_OPTIONAL_METHODS;
+
+	if (gts)
+		flags |= ACPI_EXECUTE_GTS;
+	if (bfs)
+		flags |= ACPI_EXECUTE_BFS;
+
+	return flags;
+}
+
 static u8 sleep_states[ACPI_S_STATE_COUNT];
 
 static void acpi_sleep_tts_switch(u32 acpi_state)
@@ -243,6 +263,7 @@
 {
 	acpi_status status = AE_OK;
 	u32 acpi_state = acpi_target_sleep_state;
+	u8 flags = wake_sleep_flags();
 	int error;
 
 	ACPI_FLUSH_CPU_CACHE();
@@ -250,7 +271,7 @@
 	switch (acpi_state) {
 	case ACPI_STATE_S1:
 		barrier();
-		status = acpi_enter_sleep_state(acpi_state);
+		status = acpi_enter_sleep_state(acpi_state, flags);
 		break;
 
 	case ACPI_STATE_S3:
@@ -265,7 +286,7 @@
 	acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1);
 
 	/* Reprogram control registers and execute _BFS */
-	acpi_leave_sleep_state_prep(acpi_state);
+	acpi_leave_sleep_state_prep(acpi_state, flags);
 
 	/* ACPI 3.0 specs (P62) says that it's the responsibility
 	 * of the OSPM to clear the status bit [ implying that the
@@ -529,27 +550,30 @@
 
 static int acpi_hibernation_enter(void)
 {
+	u8 flags = wake_sleep_flags();
 	acpi_status status = AE_OK;
 
 	ACPI_FLUSH_CPU_CACHE();
 
 	/* This shouldn't return.  If it returns, we have a problem */
-	status = acpi_enter_sleep_state(ACPI_STATE_S4);
+	status = acpi_enter_sleep_state(ACPI_STATE_S4, flags);
 	/* Reprogram control registers and execute _BFS */
-	acpi_leave_sleep_state_prep(ACPI_STATE_S4);
+	acpi_leave_sleep_state_prep(ACPI_STATE_S4, flags);
 
 	return ACPI_SUCCESS(status) ? 0 : -EFAULT;
 }
 
 static void acpi_hibernation_leave(void)
 {
+	u8 flags = wake_sleep_flags();
+
 	/*
 	 * If ACPI is not enabled by the BIOS and the boot kernel, we need to
 	 * enable it here.
 	 */
 	acpi_enable();
 	/* Reprogram control registers and execute _BFS */
-	acpi_leave_sleep_state_prep(ACPI_STATE_S4);
+	acpi_leave_sleep_state_prep(ACPI_STATE_S4, flags);
 	/* Check the hardware signature */
 	if (facs && s4_hardware_signature != facs->hardware_signature) {
 		printk(KERN_EMERG "ACPI: Hardware changed while hibernated, "
@@ -730,6 +754,40 @@
 
 #ifdef CONFIG_PM_SLEEP
 /**
+ * acpi_pm_device_run_wake - Enable/disable wake-up for given device.
+ * @phys_dev: Device to enable/disable the platform to wake-up the system for.
+ * @enable: Whether enable or disable the wake-up functionality.
+ *
+ * Find the ACPI device object corresponding to @pci_dev and try to
+ * enable/disable the GPE associated with it.
+ */
+int acpi_pm_device_run_wake(struct device *phys_dev, bool enable)
+{
+	struct acpi_device *dev;
+	acpi_handle handle;
+
+	if (!device_run_wake(phys_dev))
+		return -EINVAL;
+
+	handle = DEVICE_ACPI_HANDLE(phys_dev);
+	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &dev))) {
+		dev_dbg(phys_dev, "ACPI handle has no context in %s!\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	if (enable) {
+		acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0);
+		acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number);
+	} else {
+		acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number);
+		acpi_disable_wakeup_device_power(dev);
+	}
+
+	return 0;
+}
+
+/**
  *	acpi_pm_device_sleep_wake - enable or disable the system wake-up
  *                                  capability of given device
  *	@dev: device to handle
@@ -770,10 +828,12 @@
 
 static void acpi_power_off(void)
 {
+	u8 flags = wake_sleep_flags();
+
 	/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
 	printk(KERN_DEBUG "%s called\n", __func__);
 	local_irq_disable();
-	acpi_enter_sleep_state(ACPI_STATE_S5);
+	acpi_enter_sleep_state(ACPI_STATE_S5, flags);
 }
 
 /*
@@ -788,13 +848,13 @@
 {
 	acpi_handle dummy;
 
-	if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_NAME__GTS, &dummy)))
+	if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_PATHNAME__GTS, &dummy)))
 	{
 		printk(KERN_NOTICE PREFIX "BIOS offers _GTS\n");
 		printk(KERN_NOTICE PREFIX "If \"acpi.gts=1\" improves suspend, "
 			"please notify linux-acpi@vger.kernel.org\n");
 	}
-	if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_NAME__BFS, &dummy)))
+	if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_PATHNAME__BFS, &dummy)))
 	{
 		printk(KERN_NOTICE PREFIX "BIOS offers _BFS\n");
 		printk(KERN_NOTICE PREFIX "If \"acpi.bfs=1\" improves resume, "
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 48fbc64..7dbebea 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -941,13 +941,13 @@
 	if (!tz)
 		return -EINVAL;
 
-	/* Get temperature [_TMP] (required) */
-	result = acpi_thermal_get_temperature(tz);
+	/* Get trip points [_CRT, _PSV, etc.] (required) */
+	result = acpi_thermal_get_trip_points(tz);
 	if (result)
 		return result;
 
-	/* Get trip points [_CRT, _PSV, etc.] (required) */
-	result = acpi_thermal_get_trip_points(tz);
+	/* Get temperature [_TMP] (required) */
+	result = acpi_thermal_get_temperature(tz);
 	if (result)
 		return result;
 
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index eaef02a..9577b6f 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -548,27 +548,27 @@
  *		1. 	The system BIOS should NOT automatically control the brightness 
  *			level of the LCD when the power changes from AC to DC.
  * Return Value:
- * 		-1	wrong arg.
+ *		-EINVAL	wrong arg.
  */
 
 static int
 acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
 {
-	u64 status = 0;
+	acpi_status status;
 	union acpi_object arg0 = { ACPI_TYPE_INTEGER };
 	struct acpi_object_list args = { 1, &arg0 };
 
 
-	if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1) {
-		status = -1;
-		goto Failed;
-	}
+	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;
-	acpi_evaluate_object(video->device->handle, "_DOS", &args, NULL);
+	status = acpi_evaluate_object(video->device->handle, "_DOS",
+		&args, NULL);
+	if (ACPI_FAILURE(status))
+		return -EIO;
 
-      Failed:
-	return status;
+	return 0;
 }
 
 /*
@@ -1343,15 +1343,17 @@
 acpi_video_bus_get_devices(struct acpi_video_bus *video,
 			   struct acpi_device *device)
 {
-	int status = 0;
+	int status;
 	struct acpi_device *dev;
 
-	acpi_video_device_enumerate(video);
+	status = acpi_video_device_enumerate(video);
+	if (status)
+		return status;
 
 	list_for_each_entry(dev, &device->children, node) {
 
 		status = acpi_video_bus_get_one_device(dev, video);
-		if (ACPI_FAILURE(status)) {
+		if (status) {
 			printk(KERN_WARNING PREFIX
 					"Can't attach device\n");
 			continue;
@@ -1653,15 +1655,20 @@
 	mutex_init(&video->device_list_lock);
 	INIT_LIST_HEAD(&video->video_device_list);
 
-	acpi_video_bus_get_devices(video, device);
-	acpi_video_bus_start_devices(video);
+	error = acpi_video_bus_get_devices(video, device);
+	if (error)
+		goto err_free_video;
 
 	video->input = input = input_allocate_device();
 	if (!input) {
 		error = -ENOMEM;
-		goto err_stop_video;
+		goto err_put_video;
 	}
 
+	error = acpi_video_bus_start_devices(video);
+	if (error)
+		goto err_free_input_dev;
+
 	snprintf(video->phys, sizeof(video->phys),
 		"%s/video/input0", acpi_device_hid(video->device));
 
@@ -1682,7 +1689,7 @@
 
 	error = input_register_device(input);
 	if (error)
-		goto err_free_input_dev;
+		goto err_stop_video;
 
 	printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s  rom: %s  post: %s)\n",
 	       ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
@@ -1692,14 +1699,19 @@
 
 	video->pm_nb.notifier_call = acpi_video_resume;
 	video->pm_nb.priority = 0;
-	register_pm_notifier(&video->pm_nb);
+	error = register_pm_notifier(&video->pm_nb);
+	if (error)
+		goto err_unregister_input_dev;
 
 	return 0;
 
- err_free_input_dev:
-	input_free_device(input);
+ err_unregister_input_dev:
+	input_unregister_device(input);
  err_stop_video:
 	acpi_video_bus_stop_devices(video);
+ err_free_input_dev:
+	input_free_device(input);
+ err_put_video:
 	acpi_video_bus_put_devices(video);
 	kfree(video->attached_array);
  err_free_video:
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index f3f0fe7..45d8097 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -23,7 +23,7 @@
  * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B)
  * are available, video.ko should be used to handle the device.
  *
- * Otherwise vendor specific drivers like thinkpad_acpi, asus_acpi,
+ * Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop,
  * sony_acpi,... can take care about backlight brightness.
  *
  * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 54eaf96..01c2cf4 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -497,37 +497,22 @@
 }
 
 /**
- *	amba_device_register - register an AMBA device
- *	@dev: AMBA device to register
- *	@parent: parent memory resource
+ *	amba_device_add - add a previously allocated AMBA device structure
+ *	@dev: AMBA device allocated by amba_device_alloc
+ *	@parent: resource parent for this devices resources
  *
- *	Setup the AMBA device, reading the cell ID if present.
- *	Claim the resource, and register the AMBA device with
- *	the Linux device manager.
+ *	Claim the resource, and read the device cell ID if not already
+ *	initialized.  Register the AMBA device with the Linux device
+ *	manager.
  */
-int amba_device_register(struct amba_device *dev, struct resource *parent)
+int amba_device_add(struct amba_device *dev, struct resource *parent)
 {
 	u32 size;
 	void __iomem *tmp;
 	int i, ret;
 
-	device_initialize(&dev->dev);
-
-	/*
-	 * Copy from device_add
-	 */
-	if (dev->dev.init_name) {
-		dev_set_name(&dev->dev, "%s", dev->dev.init_name);
-		dev->dev.init_name = NULL;
-	}
-
-	dev->dev.release = amba_device_release;
-	dev->dev.bus = &amba_bustype;
-	dev->dev.dma_mask = &dev->dma_mask;
-	dev->res.name = dev_name(&dev->dev);
-
-	if (!dev->dev.coherent_dma_mask && dev->dma_mask)
-		dev_warn(&dev->dev, "coherent dma mask is unset\n");
+	WARN_ON(dev->irq[0] == (unsigned int)-1);
+	WARN_ON(dev->irq[1] == (unsigned int)-1);
 
 	ret = request_resource(parent, &dev->res);
 	if (ret)
@@ -582,9 +567,9 @@
 	if (ret)
 		goto err_release;
 
-	if (dev->irq[0] != NO_IRQ)
+	if (dev->irq[0] && dev->irq[0] != NO_IRQ)
 		ret = device_create_file(&dev->dev, &dev_attr_irq0);
-	if (ret == 0 && dev->irq[1] != NO_IRQ)
+	if (ret == 0 && dev->irq[1] && dev->irq[1] != NO_IRQ)
 		ret = device_create_file(&dev->dev, &dev_attr_irq1);
 	if (ret == 0)
 		return ret;
@@ -596,6 +581,74 @@
  err_out:
 	return ret;
 }
+EXPORT_SYMBOL_GPL(amba_device_add);
+
+static void amba_device_initialize(struct amba_device *dev, const char *name)
+{
+	device_initialize(&dev->dev);
+	if (name)
+		dev_set_name(&dev->dev, "%s", name);
+	dev->dev.release = amba_device_release;
+	dev->dev.bus = &amba_bustype;
+	dev->dev.dma_mask = &dev->dma_mask;
+	dev->res.name = dev_name(&dev->dev);
+}
+
+/**
+ *	amba_device_alloc - allocate an AMBA device
+ *	@name: sysfs name of the AMBA device
+ *	@base: base of AMBA device
+ *	@size: size of AMBA device
+ *
+ *	Allocate and initialize an AMBA device structure.  Returns %NULL
+ *	on failure.
+ */
+struct amba_device *amba_device_alloc(const char *name, resource_size_t base,
+	size_t size)
+{
+	struct amba_device *dev;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev) {
+		amba_device_initialize(dev, name);
+		dev->res.start = base;
+		dev->res.end = base + size - 1;
+		dev->res.flags = IORESOURCE_MEM;
+	}
+
+	return dev;
+}
+EXPORT_SYMBOL_GPL(amba_device_alloc);
+
+/**
+ *	amba_device_register - register an AMBA device
+ *	@dev: AMBA device to register
+ *	@parent: parent memory resource
+ *
+ *	Setup the AMBA device, reading the cell ID if present.
+ *	Claim the resource, and register the AMBA device with
+ *	the Linux device manager.
+ */
+int amba_device_register(struct amba_device *dev, struct resource *parent)
+{
+	amba_device_initialize(dev, dev->dev.init_name);
+	dev->dev.init_name = NULL;
+
+	if (!dev->dev.coherent_dma_mask && dev->dma_mask)
+		dev_warn(&dev->dev, "coherent dma mask is unset\n");
+
+	return amba_device_add(dev, parent);
+}
+
+/**
+ *	amba_device_put - put an AMBA device
+ *	@dev: AMBA device to put
+ */
+void amba_device_put(struct amba_device *dev)
+{
+	put_device(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(amba_device_put);
 
 /**
  *	amba_device_unregister - unregister an AMBA device
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index d07bf03..79a1e9d 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -103,8 +103,6 @@
 	.hardreset		= ahci_p5wdh_hardreset,
 };
 
-#define AHCI_HFLAGS(flags)	.private_data	= (void *)(flags)
-
 static const struct ata_port_info ahci_port_info[] = {
 	/* by features */
 	[board_ahci] =
@@ -261,6 +259,14 @@
 	{ PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
 	{ PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */
 	{ PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */
+	{ PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point AHCI */
+	{ PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */
+	{ PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */
 
 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index b175000..c2594dd 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -195,6 +195,9 @@
 	PORT_FBS_EN		= (1 << 0), /* Enable FBS */
 
 	/* hpriv->flags bits */
+
+#define AHCI_HFLAGS(flags)		.private_data	= (void *)(flags)
+
 	AHCI_HFLAG_NO_NCQ		= (1 << 0),
 	AHCI_HFLAG_IGN_IRQ_IF_ERR	= (1 << 1), /* ignore IRQ_IF_ERR */
 	AHCI_HFLAG_IGN_SERR_INTERNAL	= (1 << 2), /* ignore SERR_INTERNAL */
@@ -210,6 +213,9 @@
 	AHCI_HFLAG_NO_SNTF		= (1 << 12), /* no sntf */
 	AHCI_HFLAG_NO_FPDMA_AA		= (1 << 13), /* no FPDMA AA */
 	AHCI_HFLAG_YES_FBS		= (1 << 14), /* force FBS cap on */
+	AHCI_HFLAG_DELAY_ENGINE		= (1 << 15), /* do not start engine on
+						        port start (wait until
+						        error-handling stage) */
 
 	/* ap->flags bits */
 
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 48be4e1..0c86c77 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -26,6 +26,7 @@
 enum ahci_type {
 	AHCI,		/* standard platform ahci */
 	IMX53_AHCI,	/* ahci on i.mx53 */
+	STRICT_AHCI,	/* delayed DMA engine start */
 };
 
 static struct platform_device_id ahci_devtype[] = {
@@ -36,6 +37,9 @@
 		.name = "imx53-ahci",
 		.driver_data = IMX53_AHCI,
 	}, {
+		.name = "strict-ahci",
+		.driver_data = STRICT_AHCI,
+	}, {
 		/* sentinel */
 	}
 };
@@ -56,6 +60,13 @@
 		.udma_mask	= ATA_UDMA6,
 		.port_ops	= &ahci_pmp_retry_srst_ops,
 	},
+	[STRICT_AHCI] = {
+		AHCI_HFLAGS	(AHCI_HFLAG_DELAY_ENGINE),
+		.flags		= AHCI_FLAG_COMMON,
+		.pio_mask	= ATA_PIO4,
+		.udma_mask	= ATA_UDMA6,
+		.port_ops	= &ahci_ops,
+	},
 };
 
 static struct scsi_host_template ahci_platform_sht = {
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index fdf27b9..68013f9 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -321,6 +321,14 @@
 	{ 0x8086, 0x1e08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
 	/* SATA Controller IDE (Panther Point) */
 	{ 0x8086, 0x1e09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+	/* SATA Controller IDE (Lynx Point) */
+	{ 0x8086, 0x8c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+	/* SATA Controller IDE (Lynx Point) */
+	{ 0x8086, 0x8c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+	/* SATA Controller IDE (Lynx Point) */
+	{ 0x8086, 0x8c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+	/* SATA Controller IDE (Lynx Point) */
+	{ 0x8086, 0x8c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
 	{ }	/* terminate list */
 };
 
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index a72bfd0..f9eaa82 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -737,6 +737,7 @@
 
 static void ahci_start_port(struct ata_port *ap)
 {
+	struct ahci_host_priv *hpriv = ap->host->private_data;
 	struct ahci_port_priv *pp = ap->private_data;
 	struct ata_link *link;
 	struct ahci_em_priv *emp;
@@ -746,6 +747,10 @@
 	/* enable FIS reception */
 	ahci_start_fis_rx(ap);
 
+	/* enable DMA */
+	if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE))
+		ahci_start_engine(ap);
+
 	/* turn on LEDs */
 	if (ap->flags & ATA_FLAG_EM) {
 		ata_for_each_link(link, ap, EDGE) {
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index c06e0ec..e0bda9f 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5936,29 +5936,31 @@
 	host->ops = ops;
 }
 
+void __ata_port_probe(struct ata_port *ap)
+{
+	struct ata_eh_info *ehi = &ap->link.eh_info;
+	unsigned long flags;
+
+	/* kick EH for boot probing */
+	spin_lock_irqsave(ap->lock, flags);
+
+	ehi->probe_mask |= ATA_ALL_DEVICES;
+	ehi->action |= ATA_EH_RESET;
+	ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
+
+	ap->pflags &= ~ATA_PFLAG_INITIALIZING;
+	ap->pflags |= ATA_PFLAG_LOADING;
+	ata_port_schedule_eh(ap);
+
+	spin_unlock_irqrestore(ap->lock, flags);
+}
+
 int ata_port_probe(struct ata_port *ap)
 {
 	int rc = 0;
 
-	/* probe */
 	if (ap->ops->error_handler) {
-		struct ata_eh_info *ehi = &ap->link.eh_info;
-		unsigned long flags;
-
-		/* kick EH for boot probing */
-		spin_lock_irqsave(ap->lock, flags);
-
-		ehi->probe_mask |= ATA_ALL_DEVICES;
-		ehi->action |= ATA_EH_RESET;
-		ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
-
-		ap->pflags &= ~ATA_PFLAG_INITIALIZING;
-		ap->pflags |= ATA_PFLAG_LOADING;
-		ata_port_schedule_eh(ap);
-
-		spin_unlock_irqrestore(ap->lock, flags);
-
-		/* wait for EH to finish */
+		__ata_port_probe(ap);
 		ata_port_wait_eh(ap);
 	} else {
 		DPRINTK("ata%u: bus probe begin\n", ap->print_id);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index a9b2820..c61316e 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -863,6 +863,7 @@
 		goto retry;
 	}
 }
+EXPORT_SYMBOL_GPL(ata_port_wait_eh);
 
 static int ata_eh_nr_in_flight(struct ata_port *ap)
 {
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 508a60b..1ee00c8 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3838,6 +3838,19 @@
 }
 EXPORT_SYMBOL_GPL(ata_sas_port_stop);
 
+int ata_sas_async_port_init(struct ata_port *ap)
+{
+	int rc = ap->ops->port_start(ap);
+
+	if (!rc) {
+		ap->print_id = ata_print_id++;
+		__ata_port_probe(ap);
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(ata_sas_async_port_init);
+
 /**
  *	ata_sas_port_init - Initialize a SATA device
  *	@ap: SATA port to initialize
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 814486d..2e26fca 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -105,6 +105,7 @@
 extern struct ata_port *ata_port_alloc(struct ata_host *host);
 extern const char *sata_spd_string(unsigned int spd);
 extern int ata_port_probe(struct ata_port *ap);
+extern void __ata_port_probe(struct ata_port *ap);
 
 /* libata-acpi.c */
 #ifdef CONFIG_ATA_ACPI
@@ -151,7 +152,6 @@
 extern void ata_eh_release(struct ata_port *ap);
 extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
-extern void ata_port_wait_eh(struct ata_port *ap);
 extern void ata_eh_fastdrain_timerfn(unsigned long arg);
 extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
 extern void ata_dev_disable(struct ata_device *dev);
diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c
index 048589f..fc2db2a 100644
--- a/drivers/ata/pata_arasan_cf.c
+++ b/drivers/ata/pata_arasan_cf.c
@@ -925,11 +925,10 @@
 	struct ata_host *host = dev_get_drvdata(dev);
 	struct arasan_cf_dev *acdev = host->ports[0]->private_data;
 
-	if (acdev->dma_chan) {
+	if (acdev->dma_chan)
 		acdev->dma_chan->device->device_control(acdev->dma_chan,
 				DMA_TERMINATE_ALL, 0);
-		dma_release_channel(acdev->dma_chan);
-	}
+
 	cf_exit(acdev);
 	return ata_host_suspend(host, PMSG_SUSPEND);
 }
@@ -945,10 +944,7 @@
 	return 0;
 }
 
-static const struct dev_pm_ops arasan_cf_pm_ops = {
-	.suspend	= arasan_cf_suspend,
-	.resume		= arasan_cf_resume,
-};
+static SIMPLE_DEV_PM_OPS(arasan_cf_pm_ops, arasan_cf_suspend, arasan_cf_resume);
 #endif
 
 static struct platform_driver arasan_cf_driver = {
@@ -958,7 +954,7 @@
 		.name	= DRIVER_NAME,
 		.owner	= THIS_MODULE,
 #ifdef CONFIG_PM
-		.pm		= &arasan_cf_pm_ops,
+		.pm	= &arasan_cf_pm_ops,
 #endif
 	},
 };
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index e1fb39a..1c17cd1 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -3,6 +3,7 @@
  *			  (C) 2005 Red Hat Inc
  *			  Alan Cox <alan@lxorguk.ukuu.org.uk>
  *			  (C) 2009-2010 Bartlomiej Zolnierkiewicz
+ *			  (C) 2012 MontaVista Software, LLC <source@mvista.com>
  *
  * Based upon
  * linux/drivers/ide/pci/cmd64x.c		Version 1.30	Sept 10, 2002
@@ -32,7 +33,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_cmd64x"
-#define DRV_VERSION "0.2.5"
+#define DRV_VERSION "0.2.18"
 
 /*
  * CMD64x specific registers definition.
@@ -229,28 +230,85 @@
 }
 
 /**
- *	cmd648_dma_stop	-	DMA stop callback
- *	@qc: Command in progress
+ *	cmd64x_sff_irq_check	-	check IDE interrupt
+ *	@ap: ATA interface
  *
- *	DMA has completed.
+ *	Check IDE interrupt in CFR/ARTTIM23 registers.
  */
 
-static void cmd648_bmdma_stop(struct ata_queued_cmd *qc)
+static bool cmd64x_sff_irq_check(struct ata_port *ap)
 {
-	struct ata_port *ap = qc->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-	u8 dma_intr;
-	int dma_mask = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
-	int dma_reg = ap->port_no ? ARTTIM23 : CFR;
+	int irq_mask = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
+	int irq_reg  = ap->port_no ? ARTTIM23 : CFR;
+	u8 irq_stat;
 
-	ata_bmdma_stop(qc);
+	/* NOTE: reading the register should clear the interrupt */
+	pci_read_config_byte(pdev, irq_reg, &irq_stat);
 
-	pci_read_config_byte(pdev, dma_reg, &dma_intr);
-	pci_write_config_byte(pdev, dma_reg, dma_intr | dma_mask);
+	return irq_stat & irq_mask;
 }
 
 /**
- *	cmd646r1_dma_stop	-	DMA stop callback
+ *	cmd64x_sff_irq_clear	-	clear IDE interrupt
+ *	@ap: ATA interface
+ *
+ *	Clear IDE interrupt in CFR/ARTTIM23 and DMA status registers.
+ */
+
+static void cmd64x_sff_irq_clear(struct ata_port *ap)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+	int irq_reg = ap->port_no ? ARTTIM23 : CFR;
+	u8 irq_stat;
+
+	ata_bmdma_irq_clear(ap);
+
+	/* Reading the register should be enough to clear the interrupt */
+	pci_read_config_byte(pdev, irq_reg, &irq_stat);
+}
+
+/**
+ *	cmd648_sff_irq_check	-	check IDE interrupt
+ *	@ap: ATA interface
+ *
+ *	Check IDE interrupt in MRDMODE register.
+ */
+
+static bool cmd648_sff_irq_check(struct ata_port *ap)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+	unsigned long base = pci_resource_start(pdev, 4);
+	int irq_mask = ap->port_no ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
+	u8 mrdmode = inb(base + 1);
+
+	return mrdmode & irq_mask;
+}
+
+/**
+ *	cmd648_sff_irq_clear	-	clear IDE interrupt
+ *	@ap: ATA interface
+ *
+ *	Clear IDE interrupt in MRDMODE and DMA status registers.
+ */
+
+static void cmd648_sff_irq_clear(struct ata_port *ap)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+	unsigned long base = pci_resource_start(pdev, 4);
+	int irq_mask = ap->port_no ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
+	u8 mrdmode;
+
+	ata_bmdma_irq_clear(ap);
+
+	/* Clear this port's interrupt bit (leaving the other port alone) */
+	mrdmode  = inb(base + 1);
+	mrdmode &= ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1);
+	outb(mrdmode | irq_mask, base + 1);
+}
+
+/**
+ *	cmd646r1_bmdma_stop	-	DMA stop callback
  *	@qc: Command in progress
  *
  *	Stub for now while investigating the r1 quirk in the old driver.
@@ -273,18 +331,30 @@
 
 static struct ata_port_operations cmd64x_port_ops = {
 	.inherits	= &cmd64x_base_ops,
+	.sff_irq_check	= cmd64x_sff_irq_check,
+	.sff_irq_clear	= cmd64x_sff_irq_clear,
 	.cable_detect	= ata_cable_40wire,
 };
 
 static struct ata_port_operations cmd646r1_port_ops = {
 	.inherits	= &cmd64x_base_ops,
+	.sff_irq_check	= cmd64x_sff_irq_check,
+	.sff_irq_clear	= cmd64x_sff_irq_clear,
 	.bmdma_stop	= cmd646r1_bmdma_stop,
 	.cable_detect	= ata_cable_40wire,
 };
 
+static struct ata_port_operations cmd646r3_port_ops = {
+	.inherits	= &cmd64x_base_ops,
+	.sff_irq_check	= cmd648_sff_irq_check,
+	.sff_irq_clear	= cmd648_sff_irq_clear,
+	.cable_detect	= ata_cable_40wire,
+};
+
 static struct ata_port_operations cmd648_port_ops = {
 	.inherits	= &cmd64x_base_ops,
-	.bmdma_stop	= cmd648_bmdma_stop,
+	.sff_irq_check	= cmd648_sff_irq_check,
+	.sff_irq_clear	= cmd648_sff_irq_clear,
 	.cable_detect	= cmd648_cable_detect,
 };
 
@@ -306,7 +376,7 @@
 
 static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-	static const struct ata_port_info cmd_info[6] = {
+	static const struct ata_port_info cmd_info[7] = {
 		{	/* CMD 643 - no UDMA */
 			.flags = ATA_FLAG_SLAVE_POSS,
 			.pio_mask = ATA_PIO4,
@@ -319,12 +389,18 @@
 			.mwdma_mask = ATA_MWDMA2,
 			.port_ops = &cmd64x_port_ops
 		},
-		{	/* CMD 646 with working UDMA */
+		{	/* CMD 646U with broken UDMA */
+			.flags = ATA_FLAG_SLAVE_POSS,
+			.pio_mask = ATA_PIO4,
+			.mwdma_mask = ATA_MWDMA2,
+			.port_ops = &cmd646r3_port_ops
+		},
+		{	/* CMD 646U2 with working UDMA */
 			.flags = ATA_FLAG_SLAVE_POSS,
 			.pio_mask = ATA_PIO4,
 			.mwdma_mask = ATA_MWDMA2,
 			.udma_mask = ATA_UDMA2,
-			.port_ops = &cmd64x_port_ops
+			.port_ops = &cmd646r3_port_ops
 		},
 		{	/* CMD 646 rev 1  */
 			.flags = ATA_FLAG_SLAVE_POSS,
@@ -368,21 +444,30 @@
 	if (id->driver_data == 0)	/* 643 */
 		ata_pci_bmdma_clear_simplex(pdev);
 
-	if (pdev->device == PCI_DEVICE_ID_CMD_646) {
-		/* Does UDMA work ? */
-		if (pdev->revision > 4) {
-			ppi[0] = &cmd_info[2];
-			ppi[1] = &cmd_info[2];
-		}
-		/* Early rev with other problems ? */
-		else if (pdev->revision == 1) {
+	if (pdev->device == PCI_DEVICE_ID_CMD_646)
+		switch (pdev->revision) {
+		/* UDMA works since rev 5 */
+		default:
 			ppi[0] = &cmd_info[3];
 			ppi[1] = &cmd_info[3];
-		}
-		/* revs 1,2 have no CNTRL_CH0 */
-		if (pdev->revision < 3)
+			break;
+		/* Interrupts in MRDMODE since rev 3 */
+		case 3:
+		case 4:
+			ppi[0] = &cmd_info[2];
+			ppi[1] = &cmd_info[2];
+			break;
+		/* Rev 1 with other problems? */
+		case 1:
+			ppi[0] = &cmd_info[4];
+			ppi[1] = &cmd_info[4];
+			/* FALL THRU */
+		/* Early revs have no CNTRL_CH0 */
+		case 2:
+		case 0:
 			cntrl_ch0_ok = 0;
-	}
+			break;
+		}
 
 	cmd64x_fixup(pdev);
 
@@ -423,8 +508,8 @@
 static const struct pci_device_id cmd64x[] = {
 	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 },
 	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 },
-	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 4 },
-	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 5 },
+	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 5 },
+	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 6 },
 
 	{ },
 };
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index 35aca7d..4fe9d21 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -401,8 +401,7 @@
 	ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
 
 	active = clamp_val(t.active, 2, 15);
-	recover = clamp_val(t.recover, 2, 16);
-	recover &= 0x15;
+	recover = clamp_val(t.recover, 2, 16) & 0x0F;
 
 	inb(0x3E6);
 	inb(0x3E6);
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 00748ae..d2c102f 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -687,11 +687,11 @@
 	int ata_irq = 0;
 	struct mpc52xx_ata __iomem *ata_regs;
 	struct mpc52xx_ata_priv *priv = NULL;
-	int rv, ret, task_irq = 0;
+	int rv, task_irq;
 	int mwdma_mask = 0, udma_mask = 0;
 	const __be32 *prop;
 	int proplen;
-	struct bcom_task *dmatsk = NULL;
+	struct bcom_task *dmatsk;
 
 	/* Get ipb frequency */
 	ipb_freq = mpc5xxx_get_bus_frequency(op->dev.of_node);
@@ -717,8 +717,7 @@
 	ata_regs = devm_ioremap(&op->dev, res_mem.start, sizeof(*ata_regs));
 	if (!ata_regs) {
 		dev_err(&op->dev, "error mapping device registers\n");
-		rv = -ENOMEM;
-		goto err;
+		return -ENOMEM;
 	}
 
 	/*
@@ -753,7 +752,7 @@
 	if (!priv) {
 		dev_err(&op->dev, "error allocating private structure\n");
 		rv = -ENOMEM;
-		goto err;
+		goto err1;
 	}
 
 	priv->ipb_period = 1000000000 / (ipb_freq / 1000);
@@ -776,15 +775,15 @@
 	if (!dmatsk) {
 		dev_err(&op->dev, "bestcomm initialization failed\n");
 		rv = -ENOMEM;
-		goto err;
+		goto err1;
 	}
 
 	task_irq = bcom_get_task_irq(dmatsk);
-	ret = request_irq(task_irq, &mpc52xx_ata_task_irq, 0,
+	rv = devm_request_irq(&op->dev, task_irq, &mpc52xx_ata_task_irq, 0,
 				"ATA task", priv);
-	if (ret) {
+	if (rv) {
 		dev_err(&op->dev, "error requesting DMA IRQ\n");
-		goto err;
+		goto err2;
 	}
 	priv->dmatsk = dmatsk;
 
@@ -792,7 +791,7 @@
 	rv = mpc52xx_ata_hw_init(priv);
 	if (rv) {
 		dev_err(&op->dev, "error initializing hardware\n");
-		goto err;
+		goto err2;
 	}
 
 	/* Register ourselves to libata */
@@ -800,23 +799,16 @@
 				  mwdma_mask, udma_mask);
 	if (rv) {
 		dev_err(&op->dev, "error registering with ATA layer\n");
-		goto err;
+		goto err2;
 	}
 
 	return 0;
 
- err:
-	devm_release_mem_region(&op->dev, res_mem.start, sizeof(*ata_regs));
-	if (ata_irq)
-		irq_dispose_mapping(ata_irq);
-	if (task_irq)
-		irq_dispose_mapping(task_irq);
-	if (dmatsk)
-		bcom_ata_release(dmatsk);
-	if (ata_regs)
-		devm_iounmap(&op->dev, ata_regs);
-	if (priv)
-		devm_kfree(&op->dev, priv);
+ err2:
+	irq_dispose_mapping(task_irq);
+	bcom_ata_release(dmatsk);
+ err1:
+	irq_dispose_mapping(ata_irq);
 	return rv;
 }
 
@@ -835,12 +827,6 @@
 	bcom_ata_release(priv->dmatsk);
 	irq_dispose_mapping(priv->ata_irq);
 
-	/* Clear up IO allocations */
-	devm_iounmap(&op->dev, priv->ata_regs);
-	devm_release_mem_region(&op->dev, priv->ata_regs_pa,
-				sizeof(*priv->ata_regs));
-	devm_kfree(&op->dev, priv);
-
 	return 0;
 }
 
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 0120b0d..d6577b9 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -6,7 +6,7 @@
  * Author: Ashish Kalra <ashish.kalra@freescale.com>
  * Li Yang <leoli@freescale.com>
  *
- * Copyright (c) 2006-2007, 2011 Freescale Semiconductor, Inc.
+ * Copyright (c) 2006-2007, 2011-2012 Freescale Semiconductor, Inc.
  *
  * 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
@@ -26,6 +26,15 @@
 #include <asm/io.h>
 #include <linux/of_platform.h>
 
+static unsigned int intr_coalescing_count;
+module_param(intr_coalescing_count, int, S_IRUGO);
+MODULE_PARM_DESC(intr_coalescing_count,
+				 "INT coalescing count threshold (1..31)");
+
+static unsigned int intr_coalescing_ticks;
+module_param(intr_coalescing_ticks, int, S_IRUGO);
+MODULE_PARM_DESC(intr_coalescing_ticks,
+				 "INT coalescing timer threshold in AHB ticks");
 /* Controller information */
 enum {
 	SATA_FSL_QUEUE_DEPTH	= 16,
@@ -83,6 +92,16 @@
 };
 
 /*
+ * Interrupt Coalescing Control Register bitdefs  */
+enum {
+	ICC_MIN_INT_COUNT_THRESHOLD	= 1,
+	ICC_MAX_INT_COUNT_THRESHOLD	= ((1 << 5) - 1),
+	ICC_MIN_INT_TICKS_THRESHOLD	= 0,
+	ICC_MAX_INT_TICKS_THRESHOLD	= ((1 << 19) - 1),
+	ICC_SAFE_INT_TICKS		= 1,
+};
+
+/*
 * Host Controller command register set - per port
 */
 enum {
@@ -263,8 +282,65 @@
 	void __iomem *csr_base;
 	int irq;
 	int data_snoop;
+	struct device_attribute intr_coalescing;
 };
 
+static void fsl_sata_set_irq_coalescing(struct ata_host *host,
+		unsigned int count, unsigned int ticks)
+{
+	struct sata_fsl_host_priv *host_priv = host->private_data;
+	void __iomem *hcr_base = host_priv->hcr_base;
+
+	if (count > ICC_MAX_INT_COUNT_THRESHOLD)
+		count = ICC_MAX_INT_COUNT_THRESHOLD;
+	else if (count < ICC_MIN_INT_COUNT_THRESHOLD)
+		count = ICC_MIN_INT_COUNT_THRESHOLD;
+
+	if (ticks > ICC_MAX_INT_TICKS_THRESHOLD)
+		ticks = ICC_MAX_INT_TICKS_THRESHOLD;
+	else if ((ICC_MIN_INT_TICKS_THRESHOLD == ticks) &&
+			(count > ICC_MIN_INT_COUNT_THRESHOLD))
+		ticks = ICC_SAFE_INT_TICKS;
+
+	spin_lock(&host->lock);
+	iowrite32((count << 24 | ticks), hcr_base + ICC);
+
+	intr_coalescing_count = count;
+	intr_coalescing_ticks = ticks;
+	spin_unlock(&host->lock);
+
+	DPRINTK("intrrupt coalescing, count = 0x%x, ticks = %x\n",
+			intr_coalescing_count, intr_coalescing_ticks);
+	DPRINTK("ICC register status: (hcr base: 0x%x) = 0x%x\n",
+			hcr_base, ioread32(hcr_base + ICC));
+}
+
+static ssize_t fsl_sata_intr_coalescing_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d	%d\n",
+			intr_coalescing_count, intr_coalescing_ticks);
+}
+
+static ssize_t fsl_sata_intr_coalescing_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	unsigned int coalescing_count,	coalescing_ticks;
+
+	if (sscanf(buf, "%d%d",
+				&coalescing_count,
+				&coalescing_ticks) != 2) {
+		printk(KERN_ERR "fsl-sata: wrong parameter format.\n");
+		return -EINVAL;
+	}
+
+	fsl_sata_set_irq_coalescing(dev_get_drvdata(dev),
+			coalescing_count, coalescing_ticks);
+
+	return strlen(buf);
+}
+
 static inline unsigned int sata_fsl_tag(unsigned int tag,
 					void __iomem *hcr_base)
 {
@@ -346,10 +422,10 @@
 			(unsigned long long)sg_addr, sg_len);
 
 		/* warn if each s/g element is not dword aligned */
-		if (sg_addr & 0x03)
+		if (unlikely(sg_addr & 0x03))
 			ata_port_err(qc->ap, "s/g addr unaligned : 0x%llx\n",
 				     (unsigned long long)sg_addr);
-		if (sg_len & 0x03)
+		if (unlikely(sg_len & 0x03))
 			ata_port_err(qc->ap, "s/g len unaligned : 0x%x\n",
 				     sg_len);
 
@@ -1245,6 +1321,13 @@
 	iowrite32(0x00000FFFF, hcr_base + CE);
 	iowrite32(0x00000FFFF, hcr_base + DE);
 
+ 	/*
+	 * reset the number of command complete bits which will cause the
+	 * interrupt to be signaled
+	 */
+	fsl_sata_set_irq_coalescing(host, intr_coalescing_count,
+			intr_coalescing_ticks);
+
 	/*
 	 * host controller will be brought on-line, during xx_port_start()
 	 * callback, that should also initiate the OOB, COMINIT sequence
@@ -1309,7 +1392,7 @@
 	void __iomem *csr_base = NULL;
 	struct sata_fsl_host_priv *host_priv = NULL;
 	int irq;
-	struct ata_host *host;
+	struct ata_host *host = NULL;
 	u32 temp;
 
 	struct ata_port_info pi = sata_fsl_port_info[0];
@@ -1356,6 +1439,10 @@
 
 	/* allocate host structure */
 	host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_FSL_MAX_PORTS);
+	if (!host) {
+		retval = -ENOMEM;
+		goto error_exit_with_cleanup;
+	}
 
 	/* host->iomap is not used currently */
 	host->private_data = host_priv;
@@ -1373,10 +1460,24 @@
 
 	dev_set_drvdata(&ofdev->dev, host);
 
+	host_priv->intr_coalescing.show = fsl_sata_intr_coalescing_show;
+	host_priv->intr_coalescing.store = fsl_sata_intr_coalescing_store;
+	sysfs_attr_init(&host_priv->intr_coalescing.attr);
+	host_priv->intr_coalescing.attr.name = "intr_coalescing";
+	host_priv->intr_coalescing.attr.mode = S_IRUGO | S_IWUSR;
+	retval = device_create_file(host->dev, &host_priv->intr_coalescing);
+	if (retval)
+		goto error_exit_with_cleanup;
+
 	return 0;
 
 error_exit_with_cleanup:
 
+	if (host) {
+		dev_set_drvdata(&ofdev->dev, NULL);
+		ata_host_detach(host);
+	}
+
 	if (hcr_base)
 		iounmap(hcr_base);
 	if (host_priv)
@@ -1390,6 +1491,8 @@
 	struct ata_host *host = dev_get_drvdata(&ofdev->dev);
 	struct sata_fsl_host_priv *host_priv = host->private_data;
 
+	device_remove_file(&ofdev->dev, &host_priv->intr_coalescing);
+
 	ata_host_detach(host);
 
 	dev_set_drvdata(&ofdev->dev, NULL);
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 6ff612d..2059ee4 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -19,7 +19,6 @@
 #include <linux/atm_eni.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <linux/atomic.h>
 #include <asm/uaccess.h>
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 5072f8a..86fed1b 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -49,7 +49,6 @@
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <asm/byteorder.h>
-#include <asm/system.h>
 #include <asm/string.h>
 #include <asm/io.h>
 #include <linux/atomic.h>
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index b812103..75fd691 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -43,7 +43,6 @@
 #include <linux/wait.h>
 #include <linux/slab.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <linux/atomic.h>
 #include <asm/uaccess.h>
diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c
index 487a547..45d5063 100644
--- a/drivers/atm/idt77105.c
+++ b/drivers/atm/idt77105.c
@@ -16,7 +16,6 @@
 #include <linux/atm_idt77105.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
-#include <asm/system.h>
 #include <asm/param.h>
 #include <asm/uaccess.h>
 
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 9e373ba..d438601 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -56,7 +56,6 @@
 #include <linux/interrupt.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
-#include <asm/system.h>  
 #include <asm/io.h>  
 #include <linux/atomic.h>
 #include <asm/uaccess.h>  
diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c
index 90f1ccc..0215934 100644
--- a/drivers/atm/suni.c
+++ b/drivers/atm/suni.c
@@ -22,7 +22,6 @@
 #include <linux/capability.h>
 #include <linux/atm_suni.h>
 #include <linux/slab.h>
-#include <asm/system.h>
 #include <asm/param.h>
 #include <asm/uaccess.h>
 #include <linux/atomic.h>
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index d889f56..abe4e20 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -24,7 +24,6 @@
 #include <linux/wait.h>
 #include <linux/slab.h>
 #include <asm/byteorder.h>
-#include <asm/system.h>
 #include <asm/string.h>
 #include <asm/io.h>
 #include <linux/atomic.h>
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index e38ad24..07cbbc6 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -71,7 +71,7 @@
  * ops, or error in allocating struct dma_buf, will return negative error.
  *
  */
-struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
+struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
 				size_t size, int flags)
 {
 	struct dma_buf *dmabuf;
@@ -80,7 +80,9 @@
 	if (WARN_ON(!priv || !ops
 			  || !ops->map_dma_buf
 			  || !ops->unmap_dma_buf
-			  || !ops->release)) {
+			  || !ops->release
+			  || !ops->kmap_atomic
+			  || !ops->kmap)) {
 		return ERR_PTR(-EINVAL);
 	}
 
@@ -107,17 +109,18 @@
 /**
  * dma_buf_fd - returns a file descriptor for the given dma_buf
  * @dmabuf:	[in]	pointer to dma_buf for which fd is required.
+ * @flags:      [in]    flags to give to fd
  *
  * On success, returns an associated 'fd'. Else, returns error.
  */
-int dma_buf_fd(struct dma_buf *dmabuf)
+int dma_buf_fd(struct dma_buf *dmabuf, int flags)
 {
 	int error, fd;
 
 	if (!dmabuf || !dmabuf->file)
 		return -EINVAL;
 
-	error = get_unused_fd();
+	error = get_unused_fd_flags(flags);
 	if (error < 0)
 		return error;
 	fd = error;
@@ -185,17 +188,18 @@
 	struct dma_buf_attachment *attach;
 	int ret;
 
-	if (WARN_ON(!dmabuf || !dev || !dmabuf->ops))
+	if (WARN_ON(!dmabuf || !dev))
 		return ERR_PTR(-EINVAL);
 
 	attach = kzalloc(sizeof(struct dma_buf_attachment), GFP_KERNEL);
 	if (attach == NULL)
-		goto err_alloc;
-
-	mutex_lock(&dmabuf->lock);
+		return ERR_PTR(-ENOMEM);
 
 	attach->dev = dev;
 	attach->dmabuf = dmabuf;
+
+	mutex_lock(&dmabuf->lock);
+
 	if (dmabuf->ops->attach) {
 		ret = dmabuf->ops->attach(dmabuf, dev, attach);
 		if (ret)
@@ -206,8 +210,6 @@
 	mutex_unlock(&dmabuf->lock);
 	return attach;
 
-err_alloc:
-	return ERR_PTR(-ENOMEM);
 err_attach:
 	kfree(attach);
 	mutex_unlock(&dmabuf->lock);
@@ -224,7 +226,7 @@
  */
 void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach)
 {
-	if (WARN_ON(!dmabuf || !attach || !dmabuf->ops))
+	if (WARN_ON(!dmabuf || !attach))
 		return;
 
 	mutex_lock(&dmabuf->lock);
@@ -255,13 +257,10 @@
 
 	might_sleep();
 
-	if (WARN_ON(!attach || !attach->dmabuf || !attach->dmabuf->ops))
+	if (WARN_ON(!attach || !attach->dmabuf))
 		return ERR_PTR(-EINVAL);
 
-	mutex_lock(&attach->dmabuf->lock);
-	if (attach->dmabuf->ops->map_dma_buf)
-		sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);
-	mutex_unlock(&attach->dmabuf->lock);
+	sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);
 
 	return sg_table;
 }
@@ -273,19 +272,137 @@
  * dma_buf_ops.
  * @attach:	[in]	attachment to unmap buffer from
  * @sg_table:	[in]	scatterlist info of the buffer to unmap
+ * @direction:  [in]    direction of DMA transfer
  *
  */
 void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
-				struct sg_table *sg_table)
+				struct sg_table *sg_table,
+				enum dma_data_direction direction)
 {
-	if (WARN_ON(!attach || !attach->dmabuf || !sg_table
-			    || !attach->dmabuf->ops))
+	if (WARN_ON(!attach || !attach->dmabuf || !sg_table))
 		return;
 
-	mutex_lock(&attach->dmabuf->lock);
-	if (attach->dmabuf->ops->unmap_dma_buf)
-		attach->dmabuf->ops->unmap_dma_buf(attach, sg_table);
-	mutex_unlock(&attach->dmabuf->lock);
-
+	attach->dmabuf->ops->unmap_dma_buf(attach, sg_table,
+						direction);
 }
 EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment);
+
+
+/**
+ * dma_buf_begin_cpu_access - Must be called before accessing a dma_buf from the
+ * cpu in the kernel context. Calls begin_cpu_access to allow exporter-specific
+ * preparations. Coherency is only guaranteed in the specified range for the
+ * specified access direction.
+ * @dma_buf:	[in]	buffer to prepare cpu access for.
+ * @start:	[in]	start of range for cpu access.
+ * @len:	[in]	length of range for cpu access.
+ * @direction:	[in]	length of range for cpu access.
+ *
+ * Can return negative error values, returns 0 on success.
+ */
+int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len,
+			     enum dma_data_direction direction)
+{
+	int ret = 0;
+
+	if (WARN_ON(!dmabuf))
+		return -EINVAL;
+
+	if (dmabuf->ops->begin_cpu_access)
+		ret = dmabuf->ops->begin_cpu_access(dmabuf, start, len, direction);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(dma_buf_begin_cpu_access);
+
+/**
+ * dma_buf_end_cpu_access - Must be called after accessing a dma_buf from the
+ * cpu in the kernel context. Calls end_cpu_access to allow exporter-specific
+ * actions. Coherency is only guaranteed in the specified range for the
+ * specified access direction.
+ * @dma_buf:	[in]	buffer to complete cpu access for.
+ * @start:	[in]	start of range for cpu access.
+ * @len:	[in]	length of range for cpu access.
+ * @direction:	[in]	length of range for cpu access.
+ *
+ * This call must always succeed.
+ */
+void dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len,
+			    enum dma_data_direction direction)
+{
+	WARN_ON(!dmabuf);
+
+	if (dmabuf->ops->end_cpu_access)
+		dmabuf->ops->end_cpu_access(dmabuf, start, len, direction);
+}
+EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access);
+
+/**
+ * dma_buf_kmap_atomic - Map a page of the buffer object into kernel address
+ * space. The same restrictions as for kmap_atomic and friends apply.
+ * @dma_buf:	[in]	buffer to map page from.
+ * @page_num:	[in]	page in PAGE_SIZE units to map.
+ *
+ * This call must always succeed, any necessary preparations that might fail
+ * need to be done in begin_cpu_access.
+ */
+void *dma_buf_kmap_atomic(struct dma_buf *dmabuf, unsigned long page_num)
+{
+	WARN_ON(!dmabuf);
+
+	return dmabuf->ops->kmap_atomic(dmabuf, page_num);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kmap_atomic);
+
+/**
+ * dma_buf_kunmap_atomic - Unmap a page obtained by dma_buf_kmap_atomic.
+ * @dma_buf:	[in]	buffer to unmap page from.
+ * @page_num:	[in]	page in PAGE_SIZE units to unmap.
+ * @vaddr:	[in]	kernel space pointer obtained from dma_buf_kmap_atomic.
+ *
+ * This call must always succeed.
+ */
+void dma_buf_kunmap_atomic(struct dma_buf *dmabuf, unsigned long page_num,
+			   void *vaddr)
+{
+	WARN_ON(!dmabuf);
+
+	if (dmabuf->ops->kunmap_atomic)
+		dmabuf->ops->kunmap_atomic(dmabuf, page_num, vaddr);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kunmap_atomic);
+
+/**
+ * dma_buf_kmap - Map a page of the buffer object into kernel address space. The
+ * same restrictions as for kmap and friends apply.
+ * @dma_buf:	[in]	buffer to map page from.
+ * @page_num:	[in]	page in PAGE_SIZE units to map.
+ *
+ * This call must always succeed, any necessary preparations that might fail
+ * need to be done in begin_cpu_access.
+ */
+void *dma_buf_kmap(struct dma_buf *dmabuf, unsigned long page_num)
+{
+	WARN_ON(!dmabuf);
+
+	return dmabuf->ops->kmap(dmabuf, page_num);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kmap);
+
+/**
+ * dma_buf_kunmap - Unmap a page obtained by dma_buf_kmap.
+ * @dma_buf:	[in]	buffer to unmap page from.
+ * @page_num:	[in]	page in PAGE_SIZE units to unmap.
+ * @vaddr:	[in]	kernel space pointer obtained from dma_buf_kmap.
+ *
+ * This call must always succeed.
+ */
+void dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long page_num,
+		    void *vaddr)
+{
+	WARN_ON(!dmabuf);
+
+	if (dmabuf->ops->kunmap)
+		dmabuf->ops->kunmap(dmabuf, page_num, vaddr);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kunmap);
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 60e4f77..3ec3896 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -123,36 +123,6 @@
 }
 EXPORT_SYMBOL_GPL(driver_remove_file);
 
-/**
- * driver_add_kobj - add a kobject below the specified driver
- * @drv: requesting device driver
- * @kobj: kobject to add below this driver
- * @fmt: format string that names the kobject
- *
- * You really don't want to do this, this is only here due to one looney
- * iseries driver, go poke those developers if you are annoyed about
- * this...
- */
-int driver_add_kobj(struct device_driver *drv, struct kobject *kobj,
-		    const char *fmt, ...)
-{
-	va_list args;
-	char *name;
-	int ret;
-
-	va_start(args, fmt);
-	name = kvasprintf(GFP_KERNEL, fmt, args);
-	va_end(args);
-
-	if (!name)
-		return -ENOMEM;
-
-	ret = kobject_add(kobj, &drv->p->kobj, "%s", name);
-	kfree(name);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(driver_add_kobj);
-
 static int driver_add_groups(struct device_driver *drv,
 			     const struct attribute_group **groups)
 {
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 6c9387d..5401814 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -16,10 +16,11 @@
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/mutex.h>
-#include <linux/kthread.h>
+#include <linux/workqueue.h>
 #include <linux/highmem.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
 
 #define to_dev(obj) container_of(obj, struct device, kobj)
 
@@ -81,6 +82,11 @@
 
 static int loading_timeout = 60;	/* In seconds */
 
+static inline long firmware_loading_timeout(void)
+{
+	return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT;
+}
+
 /* fw_lock could be moved to 'struct firmware_priv' but since it is just
  * guarding for corner cases a global lock should be OK */
 static DEFINE_MUTEX(fw_lock);
@@ -440,13 +446,11 @@
 {
 	struct firmware_priv *fw_priv;
 	struct device *f_dev;
-	int error;
 
 	fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
 	if (!fw_priv) {
 		dev_err(device, "%s: kmalloc failed\n", __func__);
-		error = -ENOMEM;
-		goto err_out;
+		return ERR_PTR(-ENOMEM);
 	}
 
 	fw_priv->fw = firmware;
@@ -463,98 +467,80 @@
 	f_dev->parent = device;
 	f_dev->class = &firmware_class;
 
-	dev_set_uevent_suppress(f_dev, true);
-
-	/* Need to pin this module until class device is destroyed */
-	__module_get(THIS_MODULE);
-
-	error = device_add(f_dev);
-	if (error) {
-		dev_err(device, "%s: device_register failed\n", __func__);
-		goto err_put_dev;
-	}
-
-	error = device_create_bin_file(f_dev, &firmware_attr_data);
-	if (error) {
-		dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__);
-		goto err_del_dev;
-	}
-
-	error = device_create_file(f_dev, &dev_attr_loading);
-	if (error) {
-		dev_err(device, "%s: device_create_file failed\n", __func__);
-		goto err_del_bin_attr;
-	}
-
-	if (uevent)
-		dev_set_uevent_suppress(f_dev, false);
-
 	return fw_priv;
-
-err_del_bin_attr:
-	device_remove_bin_file(f_dev, &firmware_attr_data);
-err_del_dev:
-	device_del(f_dev);
-err_put_dev:
-	put_device(f_dev);
-err_out:
-	return ERR_PTR(error);
 }
 
-static void fw_destroy_instance(struct firmware_priv *fw_priv)
+static struct firmware_priv *
+_request_firmware_prepare(const struct firmware **firmware_p, const char *name,
+			  struct device *device, bool uevent, bool nowait)
 {
-	struct device *f_dev = &fw_priv->dev;
-
-	device_remove_file(f_dev, &dev_attr_loading);
-	device_remove_bin_file(f_dev, &firmware_attr_data);
-	device_unregister(f_dev);
-}
-
-static int _request_firmware(const struct firmware **firmware_p,
-			     const char *name, struct device *device,
-			     bool uevent, bool nowait)
-{
-	struct firmware_priv *fw_priv;
 	struct firmware *firmware;
-	int retval = 0;
+	struct firmware_priv *fw_priv;
 
 	if (!firmware_p)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
 	*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
 	if (!firmware) {
 		dev_err(device, "%s: kmalloc(struct firmware) failed\n",
 			__func__);
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 	}
 
 	if (fw_get_builtin_firmware(firmware, name)) {
 		dev_dbg(device, "firmware: using built-in firmware %s\n", name);
-		return 0;
+		return NULL;
 	}
 
-	read_lock_usermodehelper();
-
-	if (WARN_ON(usermodehelper_is_disabled())) {
-		dev_err(device, "firmware: %s will not be loaded\n", name);
-		retval = -EBUSY;
-		goto out;
-	}
-
-	if (uevent)
-		dev_dbg(device, "firmware: requesting %s\n", name);
-
 	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
 	if (IS_ERR(fw_priv)) {
-		retval = PTR_ERR(fw_priv);
-		goto out;
+		release_firmware(firmware);
+		*firmware_p = NULL;
+	}
+	return fw_priv;
+}
+
+static void _request_firmware_cleanup(const struct firmware **firmware_p)
+{
+	release_firmware(*firmware_p);
+	*firmware_p = NULL;
+}
+
+static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
+				  long timeout)
+{
+	int retval = 0;
+	struct device *f_dev = &fw_priv->dev;
+
+	dev_set_uevent_suppress(f_dev, true);
+
+	/* Need to pin this module until class device is destroyed */
+	__module_get(THIS_MODULE);
+
+	retval = device_add(f_dev);
+	if (retval) {
+		dev_err(f_dev, "%s: device_register failed\n", __func__);
+		goto err_put_dev;
+	}
+
+	retval = device_create_bin_file(f_dev, &firmware_attr_data);
+	if (retval) {
+		dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__);
+		goto err_del_dev;
+	}
+
+	retval = device_create_file(f_dev, &dev_attr_loading);
+	if (retval) {
+		dev_err(f_dev, "%s: device_create_file failed\n", __func__);
+		goto err_del_bin_attr;
 	}
 
 	if (uevent) {
-		if (loading_timeout > 0)
+		dev_set_uevent_suppress(f_dev, false);
+		dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_id);
+		if (timeout != MAX_SCHEDULE_TIMEOUT)
 			mod_timer(&fw_priv->timeout,
-				  round_jiffies_up(jiffies +
-						   loading_timeout * HZ));
+				  round_jiffies_up(jiffies + timeout));
 
 		kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
 	}
@@ -570,16 +556,13 @@
 	fw_priv->fw = NULL;
 	mutex_unlock(&fw_lock);
 
-	fw_destroy_instance(fw_priv);
-
-out:
-	read_unlock_usermodehelper();
-
-	if (retval) {
-		release_firmware(firmware);
-		*firmware_p = NULL;
-	}
-
+	device_remove_file(f_dev, &dev_attr_loading);
+err_del_bin_attr:
+	device_remove_bin_file(f_dev, &firmware_attr_data);
+err_del_dev:
+	device_del(f_dev);
+err_put_dev:
+	put_device(f_dev);
 	return retval;
 }
 
@@ -602,7 +585,26 @@
 request_firmware(const struct firmware **firmware_p, const char *name,
                  struct device *device)
 {
-        return _request_firmware(firmware_p, name, device, true, false);
+	struct firmware_priv *fw_priv;
+	int ret;
+
+	fw_priv = _request_firmware_prepare(firmware_p, name, device, true,
+					    false);
+	if (IS_ERR_OR_NULL(fw_priv))
+		return PTR_RET(fw_priv);
+
+	ret = usermodehelper_read_trylock();
+	if (WARN_ON(ret)) {
+		dev_err(device, "firmware: %s will not be loaded\n", name);
+	} else {
+		ret = _request_firmware_load(fw_priv, true,
+					firmware_loading_timeout());
+		usermodehelper_read_unlock();
+	}
+	if (ret)
+		_request_firmware_cleanup(firmware_p);
+
+	return ret;
 }
 
 /**
@@ -629,25 +631,39 @@
 	bool uevent;
 };
 
-static int request_firmware_work_func(void *arg)
+static void request_firmware_work_func(struct work_struct *work)
 {
-	struct firmware_work *fw_work = arg;
+	struct firmware_work *fw_work;
 	const struct firmware *fw;
+	struct firmware_priv *fw_priv;
+	long timeout;
 	int ret;
 
-	if (!arg) {
-		WARN_ON(1);
-		return 0;
+	fw_work = container_of(work, struct firmware_work, work);
+	fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device,
+			fw_work->uevent, true);
+	if (IS_ERR_OR_NULL(fw_priv)) {
+		ret = PTR_RET(fw_priv);
+		goto out;
 	}
 
-	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
-				fw_work->uevent, true);
+	timeout = usermodehelper_read_lock_wait(firmware_loading_timeout());
+	if (timeout) {
+		ret = _request_firmware_load(fw_priv, fw_work->uevent, timeout);
+		usermodehelper_read_unlock();
+	} else {
+		dev_dbg(fw_work->device, "firmware: %s loading timed out\n",
+			fw_work->name);
+		ret = -EAGAIN;
+	}
+	if (ret)
+		_request_firmware_cleanup(&fw);
+
+ out:
 	fw_work->cont(fw, fw_work->context);
 
 	module_put(fw_work->module);
 	kfree(fw_work);
-
-	return ret;
 }
 
 /**
@@ -673,7 +689,6 @@
 	const char *name, struct device *device, gfp_t gfp, void *context,
 	void (*cont)(const struct firmware *fw, void *context))
 {
-	struct task_struct *task;
 	struct firmware_work *fw_work;
 
 	fw_work = kzalloc(sizeof (struct firmware_work), gfp);
@@ -692,15 +707,8 @@
 		return -EFAULT;
 	}
 
-	task = kthread_run(request_firmware_work_func, fw_work,
-			    "firmware/%s", name);
-	if (IS_ERR(task)) {
-		fw_work->cont(NULL, fw_work->context);
-		module_put(fw_work->module);
-		kfree(fw_work);
-		return PTR_ERR(task);
-	}
-
+	INIT_WORK(&fw_work->work, request_firmware_work_func);
+	schedule_work(&fw_work->work);
 	return 0;
 }
 
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 9e60dbe..7dda4f7 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -466,7 +466,7 @@
 	if (strict_strtoull(buf, 0, &pfn) < 0)
 		return -EINVAL;
 	pfn >>= PAGE_SHIFT;
-	ret = __memory_failure(pfn, 0, 0);
+	ret = memory_failure(pfn, 0, 0);
 	return ret ? ret : count;
 }
 
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index 428e55e..869d7ff 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -8,6 +8,7 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/device.h>
 #include <linux/io.h>
 #include <linux/pm.h>
 #include <linux/pm_clock.h>
diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c
index 4af7c1c..a14085c 100644
--- a/drivers/base/power/common.c
+++ b/drivers/base/power/common.c
@@ -8,6 +8,7 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/device.h>
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/pm_clock.h>
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index 95706fa..ac993ea 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/cpufreq.h>
+#include <linux/device.h>
 #include <linux/list.h>
 #include <linux/rculist.h>
 #include <linux/rcupdate.h>
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 541f821..bd0f394 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -532,6 +532,8 @@
 	dev->power.suspend_time = ktime_set(0, 0);
 	dev->power.max_time_suspended_ns = -1;
 	dev->power.deferred_resume = false;
+	wake_up_all(&dev->power.wait_queue);
+
 	if (retval == -EAGAIN || retval == -EBUSY) {
 		dev->power.runtime_error = 0;
 
@@ -547,7 +549,6 @@
 	} else {
 		pm_runtime_cancel_pending(dev);
 	}
-	wake_up_all(&dev->power.wait_queue);
 	goto out;
 }
 
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 1a02b75..fcafc5b 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -22,6 +22,7 @@
 struct regmap_format {
 	size_t buf_size;
 	size_t reg_bytes;
+	size_t pad_bytes;
 	size_t val_bytes;
 	void (*format_write)(struct regmap *map,
 			     unsigned int reg, unsigned int val);
@@ -65,16 +66,19 @@
 	unsigned int num_reg_defaults_raw;
 
 	/* if set, only the cache is modified not the HW */
-	unsigned int cache_only:1;
+	u32 cache_only;
 	/* if set, only the HW is modified not the cache */
-	unsigned int cache_bypass:1;
+	u32 cache_bypass;
 	/* if set, remember to free reg_defaults_raw */
-	unsigned int cache_free:1;
+	bool cache_free;
 
 	struct reg_default *reg_defaults;
 	const void *reg_defaults_raw;
 	void *cache;
-	bool cache_dirty;
+	u32 cache_dirty;
+
+	struct reg_default *patch;
+	int patch_regs;
 };
 
 struct regcache_ops {
@@ -84,7 +88,7 @@
 	int (*exit)(struct regmap *map);
 	int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);
 	int (*write)(struct regmap *map, unsigned int reg, unsigned int value);
-	int (*sync)(struct regmap *map);
+	int (*sync)(struct regmap *map, unsigned int min, unsigned int max);
 };
 
 bool regmap_writeable(struct regmap *map, unsigned int reg);
diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c
index b7d1614..483b06d 100644
--- a/drivers/base/regmap/regcache-lzo.c
+++ b/drivers/base/regmap/regcache-lzo.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/device.h>
 #include <linux/lzo.h>
 
 #include "internal.h"
@@ -331,7 +332,8 @@
 	return ret;
 }
 
-static int regcache_lzo_sync(struct regmap *map)
+static int regcache_lzo_sync(struct regmap *map, unsigned int min,
+			     unsigned int max)
 {
 	struct regcache_lzo_ctx **lzo_blocks;
 	unsigned int val;
@@ -339,10 +341,21 @@
 	int ret;
 
 	lzo_blocks = map->cache;
-	for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
+	i = min;
+	for_each_set_bit_from(i, lzo_blocks[0]->sync_bmp,
+			      lzo_blocks[0]->sync_bmp_nbits) {
+		if (i > max)
+			continue;
+
 		ret = regcache_read(map, i, &val);
 		if (ret)
 			return ret;
+
+		/* Is this the hardware default?  If so skip. */
+		ret = regcache_lookup_reg(map, i);
+		if (ret > 0 && val == map->reg_defaults[ret].def)
+			continue;
+
 		map->cache_bypass = 1;
 		ret = _regmap_write(map, i, val);
 		map->cache_bypass = 0;
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 32620c4..fb14a63 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/device.h>
 #include <linux/debugfs.h>
 #include <linux/rbtree.h>
 #include <linux/seq_file.h>
@@ -357,7 +358,8 @@
 	return 0;
 }
 
-static int regcache_rbtree_sync(struct regmap *map)
+static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
+				unsigned int max)
 {
 	struct regcache_rbtree_ctx *rbtree_ctx;
 	struct rb_node *node;
@@ -365,19 +367,37 @@
 	unsigned int regtmp;
 	unsigned int val;
 	int ret;
-	int i;
+	int i, 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);
-		for (i = 0; i < rbnode->blklen; i++) {
+
+		if (rbnode->base_reg < min)
+			continue;
+		if (rbnode->base_reg > max)
+			break;
+		if (rbnode->base_reg + rbnode->blklen < min)
+			continue;
+
+		if (min > rbnode->base_reg)
+			base = min - rbnode->base_reg;
+		else
+			base = 0;
+
+		if (max < rbnode->base_reg + rbnode->blklen)
+			end = rbnode->base_reg + rbnode->blklen - max;
+		else
+			end = rbnode->blklen;
+
+		for (i = base; i < end; i++) {
 			regtmp = rbnode->base_reg + i;
 			val = regcache_rbtree_get_register(rbnode, i,
 							   map->cache_word_size);
 
 			/* Is this the hardware default?  If so skip. */
-			ret = regcache_lookup_reg(map, i);
-			if (ret > 0 && val == map->reg_defaults[ret].def)
+			ret = regcache_lookup_reg(map, regtmp);
+			if (ret >= 0 && val == map->reg_defaults[ret].def)
 				continue;
 
 			map->cache_bypass = 1;
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index d1daa5e..87f54db 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -12,6 +12,7 @@
 
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/device.h>
 #include <trace/events/regmap.h>
 #include <linux/bsearch.h>
 #include <linux/sort.h>
@@ -35,12 +36,17 @@
 		return -EINVAL;
 
 	if (!map->reg_defaults_raw) {
+		u32 cache_bypass = map->cache_bypass;
 		dev_warn(map->dev, "No cache defaults, reading back from HW\n");
+
+		/* Bypass the cache access till data read from HW*/
+		map->cache_bypass = 1;
 		tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL);
 		if (!tmp_buf)
 			return -EINVAL;
 		ret = regmap_bulk_read(map, 0, tmp_buf,
 				       map->num_reg_defaults_raw);
+		map->cache_bypass = cache_bypass;
 		if (ret < 0) {
 			kfree(tmp_buf);
 			return ret;
@@ -211,7 +217,6 @@
 
 	return -EINVAL;
 }
-EXPORT_SYMBOL_GPL(regcache_read);
 
 /**
  * regcache_write: Set the value of a given register in the cache.
@@ -238,7 +243,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(regcache_write);
 
 /**
  * regcache_sync: Sync the register cache with the hardware.
@@ -254,12 +258,11 @@
 int regcache_sync(struct regmap *map)
 {
 	int ret = 0;
-	unsigned int val;
 	unsigned int i;
 	const char *name;
 	unsigned int bypass;
 
-	BUG_ON(!map->cache_ops);
+	BUG_ON(!map->cache_ops || !map->cache_ops->sync);
 
 	mutex_lock(&map->lock);
 	/* Remember the initial bypass state */
@@ -268,26 +271,27 @@
 		map->cache_ops->name);
 	name = map->cache_ops->name;
 	trace_regcache_sync(map->dev, name, "start");
+
 	if (!map->cache_dirty)
 		goto out;
-	if (map->cache_ops->sync) {
-		ret = map->cache_ops->sync(map);
-	} else {
-		for (i = 0; i < map->num_reg_defaults; i++) {
-			ret = regcache_read(map, i, &val);
-			if (ret < 0)
-				goto out;
-			map->cache_bypass = 1;
-			ret = _regmap_write(map, i, val);
-			map->cache_bypass = 0;
-			if (ret < 0)
-				goto out;
-			dev_dbg(map->dev, "Synced register %#x, value %#x\n",
-				map->reg_defaults[i].reg,
-				map->reg_defaults[i].def);
-		}
 
+	/* Apply any patch first */
+	map->cache_bypass = 1;
+	for (i = 0; i < map->patch_regs; i++) {
+		ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def);
+		if (ret != 0) {
+			dev_err(map->dev, "Failed to write %x = %x: %d\n",
+				map->patch[i].reg, map->patch[i].def, ret);
+			goto out;
+		}
 	}
+	map->cache_bypass = 0;
+
+	ret = map->cache_ops->sync(map, 0, map->max_register);
+
+	if (ret == 0)
+		map->cache_dirty = false;
+
 out:
 	trace_regcache_sync(map->dev, name, "stop");
 	/* Restore the bypass state */
@@ -299,6 +303,51 @@
 EXPORT_SYMBOL_GPL(regcache_sync);
 
 /**
+ * regcache_sync_region: Sync part  of the register cache with the hardware.
+ *
+ * @map: map to sync.
+ * @min: first register to sync
+ * @max: last register to sync
+ *
+ * Write all non-default register values in the specified region to
+ * the hardware.
+ *
+ * Return a negative value on failure, 0 on success.
+ */
+int regcache_sync_region(struct regmap *map, unsigned int min,
+			 unsigned int max)
+{
+	int ret = 0;
+	const char *name;
+	unsigned int bypass;
+
+	BUG_ON(!map->cache_ops || !map->cache_ops->sync);
+
+	mutex_lock(&map->lock);
+
+	/* Remember the initial bypass state */
+	bypass = map->cache_bypass;
+
+	name = map->cache_ops->name;
+	dev_dbg(map->dev, "Syncing %s cache from %d-%d\n", name, min, max);
+
+	trace_regcache_sync(map->dev, name, "start region");
+
+	if (!map->cache_dirty)
+		goto out;
+
+	ret = map->cache_ops->sync(map, min, max);
+
+out:
+	trace_regcache_sync(map->dev, name, "stop region");
+	/* Restore the bypass state */
+	map->cache_bypass = bypass;
+	mutex_unlock(&map->lock);
+
+	return ret;
+}
+
+/**
  * regcache_cache_only: Put a register map into cache only mode
  *
  * @map: map to configure
@@ -315,6 +364,7 @@
 	mutex_lock(&map->lock);
 	WARN_ON(map->cache_bypass && enable);
 	map->cache_only = enable;
+	trace_regmap_cache_only(map->dev, enable);
 	mutex_unlock(&map->lock);
 }
 EXPORT_SYMBOL_GPL(regcache_cache_only);
@@ -352,6 +402,7 @@
 	mutex_lock(&map->lock);
 	WARN_ON(map->cache_only && enable);
 	map->cache_bypass = enable;
+	trace_regmap_cache_bypass(map->dev, enable);
 	mutex_unlock(&map->lock);
 }
 EXPORT_SYMBOL_GPL(regcache_cache_bypass);
@@ -374,10 +425,16 @@
 		cache[idx] = val;
 		break;
 	}
+	case 4: {
+		u32 *cache = base;
+		if (cache[idx] == val)
+			return true;
+		cache[idx] = val;
+		break;
+	}
 	default:
 		BUG();
 	}
-	/* unreachable */
 	return false;
 }
 
@@ -396,6 +453,10 @@
 		const u16 *cache = base;
 		return cache[idx];
 	}
+	case 4: {
+		const u32 *cache = base;
+		return cache[idx];
+	}
 	default:
 		BUG();
 	}
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 6f39747..251eb70 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -11,10 +11,10 @@
  */
 
 #include <linux/slab.h>
-#include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
+#include <linux/device.h>
 
 #include "internal.h"
 
@@ -27,12 +27,35 @@
 	return strlen(buf);
 }
 
-static int regmap_open_file(struct inode *inode, struct file *file)
+static ssize_t regmap_name_read_file(struct file *file,
+				     char __user *user_buf, size_t count,
+				     loff_t *ppos)
 {
-	file->private_data = inode->i_private;
-	return 0;
+	struct regmap *map = file->private_data;
+	int ret;
+	char *buf;
+
+	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = snprintf(buf, PAGE_SIZE, "%s\n", map->dev->driver->name);
+	if (ret < 0) {
+		kfree(buf);
+		return ret;
+	}
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+	kfree(buf);
+	return ret;
 }
 
+static const struct file_operations regmap_name_fops = {
+	.open = simple_open,
+	.read = regmap_name_read_file,
+	.llseek = default_llseek,
+};
+
 static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
 				    size_t count, loff_t *ppos)
 {
@@ -103,9 +126,51 @@
 	return ret;
 }
 
+#undef REGMAP_ALLOW_WRITE_DEBUGFS
+#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
+/*
+ * This can be dangerous especially when we have clients such as
+ * PMICs, therefore don't provide any real compile time configuration option
+ * for this feature, people who want to use this will need to modify
+ * the source code directly.
+ */
+static ssize_t regmap_map_write_file(struct file *file,
+				     const char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	char buf[32];
+	size_t buf_size;
+	char *start = buf;
+	unsigned long reg, value;
+	struct regmap *map = file->private_data;
+
+	buf_size = min(count, (sizeof(buf)-1));
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+	buf[buf_size] = 0;
+
+	while (*start == ' ')
+		start++;
+	reg = simple_strtoul(start, &start, 16);
+	while (*start == ' ')
+		start++;
+	if (strict_strtoul(start, 16, &value))
+		return -EINVAL;
+
+	/* Userspace has been fiddling around behind the kernel's back */
+	add_taint(TAINT_USER);
+
+	regmap_write(map, reg, value);
+	return buf_size;
+}
+#else
+#define regmap_map_write_file NULL
+#endif
+
 static const struct file_operations regmap_map_fops = {
-	.open = regmap_open_file,
+	.open = simple_open,
 	.read = regmap_map_read_file,
+	.write = regmap_map_write_file,
 	.llseek = default_llseek,
 };
 
@@ -172,7 +237,7 @@
 }
 
 static const struct file_operations regmap_access_fops = {
-	.open = regmap_open_file,
+	.open = simple_open,
 	.read = regmap_access_read_file,
 	.llseek = default_llseek,
 };
@@ -186,12 +251,24 @@
 		return;
 	}
 
+	debugfs_create_file("name", 0400, map->debugfs,
+			    map, &regmap_name_fops);
+
 	if (map->max_register) {
 		debugfs_create_file("registers", 0400, map->debugfs,
 				    map, &regmap_map_fops);
 		debugfs_create_file("access", 0400, map->debugfs,
 				    map, &regmap_access_fops);
 	}
+
+	if (map->cache_type) {
+		debugfs_create_bool("cache_only", 0400, map->debugfs,
+				    &map->cache_only);
+		debugfs_create_bool("cache_dirty", 0400, map->debugfs,
+				    &map->cache_dirty);
+		debugfs_create_bool("cache_bypass", 0400, map->debugfs,
+				    &map->cache_bypass);
+	}
 }
 
 void regmap_debugfs_exit(struct regmap *map)
diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c
index 38621ec..9a3a8c5 100644
--- a/drivers/base/regmap/regmap-i2c.c
+++ b/drivers/base/regmap/regmap-i2c.c
@@ -111,4 +111,21 @@
 }
 EXPORT_SYMBOL_GPL(regmap_init_i2c);
 
+/**
+ * devm_regmap_init_i2c(): Initialise managed register map
+ *
+ * @i2c: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap.  The regmap will be automatically freed by the
+ * device management code.
+ */
+struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
+				    const struct regmap_config *config)
+{
+	return devm_regmap_init(&i2c->dev, &regmap_i2c, config);
+}
+EXPORT_SYMBOL_GPL(devm_regmap_init_i2c);
+
 MODULE_LICENSE("GPL");
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 428836f..1befaa7 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/export.h>
+#include <linux/device.h>
 #include <linux/regmap.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c
index 2560658..7c0c35a 100644
--- a/drivers/base/regmap/regmap-spi.c
+++ b/drivers/base/regmap/regmap-spi.c
@@ -70,4 +70,21 @@
 }
 EXPORT_SYMBOL_GPL(regmap_init_spi);
 
+/**
+ * devm_regmap_init_spi(): Initialise register map
+ *
+ * @spi: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap.  The map will be automatically freed by the
+ * device management code.
+ */
+struct regmap *devm_regmap_init_spi(struct spi_device *spi,
+				    const struct regmap_config *config)
+{
+	return devm_regmap_init(&spi->dev, &regmap_spi, config);
+}
+EXPORT_SYMBOL_GPL(devm_regmap_init_spi);
+
 MODULE_LICENSE("GPL");
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 6555803..7a3f535 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -10,8 +10,9 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/device.h>
 #include <linux/slab.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/mutex.h>
 #include <linux/err.h>
 
@@ -36,6 +37,9 @@
 	if (map->max_register && reg > map->max_register)
 		return false;
 
+	if (map->format.format_write)
+		return false;
+
 	if (map->readable_reg)
 		return map->readable_reg(map->dev, reg);
 
@@ -44,7 +48,7 @@
 
 bool regmap_volatile(struct regmap *map, unsigned int reg)
 {
-	if (map->max_register && reg > map->max_register)
+	if (!regmap_readable(map, reg))
 		return false;
 
 	if (map->volatile_reg)
@@ -55,7 +59,7 @@
 
 bool regmap_precious(struct regmap *map, unsigned int reg)
 {
-	if (map->max_register && reg > map->max_register)
+	if (!regmap_readable(map, reg))
 		return false;
 
 	if (map->precious_reg)
@@ -76,6 +80,14 @@
 	return true;
 }
 
+static void regmap_format_2_6_write(struct regmap *map,
+				     unsigned int reg, unsigned int val)
+{
+	u8 *out = map->work_buf;
+
+	*out = (reg << 6) | val;
+}
+
 static void regmap_format_4_12_write(struct regmap *map,
 				     unsigned int reg, unsigned int val)
 {
@@ -114,6 +126,13 @@
 	b[0] = cpu_to_be16(val);
 }
 
+static void regmap_format_32(void *buf, unsigned int val)
+{
+	__be32 *b = buf;
+
+	b[0] = cpu_to_be32(val);
+}
+
 static unsigned int regmap_parse_8(void *buf)
 {
 	u8 *b = buf;
@@ -130,6 +149,15 @@
 	return b[0];
 }
 
+static unsigned int regmap_parse_32(void *buf)
+{
+	__be32 *b = buf;
+
+	b[0] = be32_to_cpu(b[0]);
+
+	return b[0];
+}
+
 /**
  * regmap_init(): Initialise register map
  *
@@ -159,8 +187,10 @@
 
 	mutex_init(&map->lock);
 	map->format.buf_size = (config->reg_bits + config->val_bits) / 8;
-	map->format.reg_bytes = config->reg_bits / 8;
-	map->format.val_bytes = config->val_bits / 8;
+	map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8);
+	map->format.pad_bytes = config->pad_bits / 8;
+	map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8);
+	map->format.buf_size += map->format.pad_bytes;
 	map->dev = dev;
 	map->bus = bus;
 	map->max_register = config->max_register;
@@ -178,6 +208,16 @@
 	}
 
 	switch (config->reg_bits) {
+	case 2:
+		switch (config->val_bits) {
+		case 6:
+			map->format.format_write = regmap_format_2_6_write;
+			break;
+		default:
+			goto err_map;
+		}
+		break;
+
 	case 4:
 		switch (config->val_bits) {
 		case 12:
@@ -216,6 +256,10 @@
 		map->format.format_reg = regmap_format_16;
 		break;
 
+	case 32:
+		map->format.format_reg = regmap_format_32;
+		break;
+
 	default:
 		goto err_map;
 	}
@@ -229,13 +273,17 @@
 		map->format.format_val = regmap_format_16;
 		map->format.parse_val = regmap_parse_16;
 		break;
+	case 32:
+		map->format.format_val = regmap_format_32;
+		map->format.parse_val = regmap_parse_32;
+		break;
 	}
 
 	if (!map->format.format_write &&
 	    !(map->format.format_reg && map->format.format_val))
 		goto err_map;
 
-	map->work_buf = kmalloc(map->format.buf_size, GFP_KERNEL);
+	map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL);
 	if (map->work_buf == NULL) {
 		ret = -ENOMEM;
 		goto err_map;
@@ -258,6 +306,45 @@
 }
 EXPORT_SYMBOL_GPL(regmap_init);
 
+static void devm_regmap_release(struct device *dev, void *res)
+{
+	regmap_exit(*(struct regmap **)res);
+}
+
+/**
+ * devm_regmap_init(): Initialise managed register map
+ *
+ * @dev: Device that will be interacted with
+ * @bus: Bus-specific callbacks to use with device
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap.  This function should generally not be called
+ * directly, it should be called by bus-specific init functions.  The
+ * map will be automatically freed by the device management code.
+ */
+struct regmap *devm_regmap_init(struct device *dev,
+				const struct regmap_bus *bus,
+				const struct regmap_config *config)
+{
+	struct regmap **ptr, *regmap;
+
+	ptr = devres_alloc(devm_regmap_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	regmap = regmap_init(dev, bus, config);
+	if (!IS_ERR(regmap)) {
+		*ptr = regmap;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return regmap;
+}
+EXPORT_SYMBOL_GPL(devm_regmap_init);
+
 /**
  * regmap_reinit_cache(): Reinitialise the current register cache
  *
@@ -276,6 +363,7 @@
 	mutex_lock(&map->lock);
 
 	regcache_exit(map);
+	regmap_debugfs_exit(map);
 
 	map->max_register = config->max_register;
 	map->writeable_reg = config->writeable_reg;
@@ -284,6 +372,8 @@
 	map->precious_reg = config->precious_reg;
 	map->cache_type = config->cache_type;
 
+	regmap_debugfs_init(map);
+
 	map->cache_bypass = false;
 	map->cache_only = false;
 
@@ -321,6 +411,26 @@
 			if (!map->writeable_reg(map->dev, reg + i))
 				return -EINVAL;
 
+	if (!map->cache_bypass && map->format.parse_val) {
+		unsigned int ival;
+		int val_bytes = map->format.val_bytes;
+		for (i = 0; i < val_len / val_bytes; i++) {
+			memcpy(map->work_buf, val + (i * val_bytes), val_bytes);
+			ival = map->format.parse_val(map->work_buf);
+			ret = regcache_write(map, reg + i, ival);
+			if (ret) {
+				dev_err(map->dev,
+				   "Error in caching of register: %u ret: %d\n",
+					reg + i, ret);
+				return ret;
+			}
+		}
+		if (map->cache_only) {
+			map->cache_dirty = true;
+			return 0;
+		}
+	}
+
 	map->format.format_reg(map->work_buf, reg);
 
 	u8[0] |= map->write_flag_mask;
@@ -332,23 +442,28 @@
 	 * send the work_buf directly, otherwise try to do a gather
 	 * write.
 	 */
-	if (val == map->work_buf + map->format.reg_bytes)
+	if (val == (map->work_buf + map->format.pad_bytes +
+		    map->format.reg_bytes))
 		ret = map->bus->write(map->dev, map->work_buf,
-				      map->format.reg_bytes + val_len);
+				      map->format.reg_bytes +
+				      map->format.pad_bytes +
+				      val_len);
 	else if (map->bus->gather_write)
 		ret = map->bus->gather_write(map->dev, map->work_buf,
-					     map->format.reg_bytes,
+					     map->format.reg_bytes +
+					     map->format.pad_bytes,
 					     val, val_len);
 
 	/* If that didn't work fall back on linearising by hand. */
 	if (ret == -ENOTSUPP) {
-		len = map->format.reg_bytes + val_len;
-		buf = kmalloc(len, GFP_KERNEL);
+		len = map->format.reg_bytes + map->format.pad_bytes + val_len;
+		buf = kzalloc(len, GFP_KERNEL);
 		if (!buf)
 			return -ENOMEM;
 
 		memcpy(buf, map->work_buf, map->format.reg_bytes);
-		memcpy(buf + map->format.reg_bytes, val, val_len);
+		memcpy(buf + map->format.reg_bytes + map->format.pad_bytes,
+		       val, val_len);
 		ret = map->bus->write(map->dev, buf, len);
 
 		kfree(buf);
@@ -366,7 +481,7 @@
 	int ret;
 	BUG_ON(!map->format.format_write && !map->format.format_val);
 
-	if (!map->cache_bypass) {
+	if (!map->cache_bypass && map->format.format_write) {
 		ret = regcache_write(map, reg, val);
 		if (ret != 0)
 			return ret;
@@ -390,10 +505,12 @@
 
 		return ret;
 	} else {
-		map->format.format_val(map->work_buf + map->format.reg_bytes,
-				       val);
+		map->format.format_val(map->work_buf + map->format.reg_bytes
+				       + map->format.pad_bytes, val);
 		return _regmap_raw_write(map, reg,
-					 map->work_buf + map->format.reg_bytes,
+					 map->work_buf +
+					 map->format.reg_bytes +
+					 map->format.pad_bytes,
 					 map->format.val_bytes);
 	}
 }
@@ -441,12 +558,8 @@
 int regmap_raw_write(struct regmap *map, unsigned int reg,
 		     const void *val, size_t val_len)
 {
-	size_t val_count = val_len / map->format.val_bytes;
 	int ret;
 
-	WARN_ON(!regmap_volatile_range(map, reg, val_count) &&
-		map->cache_type != REGCACHE_NONE);
-
 	mutex_lock(&map->lock);
 
 	ret = _regmap_raw_write(map, reg, val, val_len);
@@ -457,6 +570,56 @@
 }
 EXPORT_SYMBOL_GPL(regmap_raw_write);
 
+/*
+ * regmap_bulk_write(): Write multiple registers to the device
+ *
+ * @map: Register map to write to
+ * @reg: First register to be write from
+ * @val: Block of data to be written, in native register size for device
+ * @val_count: Number of registers to write
+ *
+ * This function is intended to be used for writing a large block of
+ * data to be device either in single transfer or multiple transfer.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
+		     size_t val_count)
+{
+	int ret = 0, i;
+	size_t val_bytes = map->format.val_bytes;
+	void *wval;
+
+	if (!map->format.parse_val)
+		return -EINVAL;
+
+	mutex_lock(&map->lock);
+
+	/* No formatting is require if val_byte is 1 */
+	if (val_bytes == 1) {
+		wval = (void *)val;
+	} else {
+		wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL);
+		if (!wval) {
+			ret = -ENOMEM;
+			dev_err(map->dev, "Error in memory allocation\n");
+			goto out;
+		}
+		for (i = 0; i < val_count * val_bytes; i += val_bytes)
+			map->format.parse_val(wval + i);
+	}
+	ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
+
+	if (val_bytes != 1)
+		kfree(wval);
+
+out:
+	mutex_unlock(&map->lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_bulk_write);
+
 static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
 			    unsigned int val_len)
 {
@@ -476,7 +639,8 @@
 	trace_regmap_hw_read_start(map->dev, reg,
 				   val_len / map->format.val_bytes);
 
-	ret = map->bus->read(map->dev, map->work_buf, map->format.reg_bytes,
+	ret = map->bus->read(map->dev, map->work_buf,
+			     map->format.reg_bytes + map->format.pad_bytes,
 			     val, val_len);
 
 	trace_regmap_hw_read_done(map->dev, reg,
@@ -549,16 +713,32 @@
 int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
 		    size_t val_len)
 {
-	size_t val_count = val_len / map->format.val_bytes;
-	int ret;
-
-	WARN_ON(!regmap_volatile_range(map, reg, val_count) &&
-		map->cache_type != REGCACHE_NONE);
+	size_t val_bytes = map->format.val_bytes;
+	size_t val_count = val_len / val_bytes;
+	unsigned int v;
+	int ret, i;
 
 	mutex_lock(&map->lock);
 
-	ret = _regmap_raw_read(map, reg, val, val_len);
+	if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass ||
+	    map->cache_type == REGCACHE_NONE) {
+		/* Physical block read if there's no cache involved */
+		ret = _regmap_raw_read(map, reg, val, val_len);
 
+	} else {
+		/* Otherwise go word by word for the cache; should be low
+		 * cost as we expect to hit the cache.
+		 */
+		for (i = 0; i < val_count; i++) {
+			ret = _regmap_read(map, reg + i, &v);
+			if (ret != 0)
+				goto out;
+
+			map->format.format_val(val + (i * val_bytes), v);
+		}
+	}
+
+ out:
 	mutex_unlock(&map->lock);
 
 	return ret;
@@ -672,6 +852,79 @@
 }
 EXPORT_SYMBOL_GPL(regmap_update_bits_check);
 
+/**
+ * regmap_register_patch: Register and apply register updates to be applied
+ *                        on device initialistion
+ *
+ * @map: Register map to apply updates to.
+ * @regs: Values to update.
+ * @num_regs: Number of entries in regs.
+ *
+ * Register a set of register updates to be applied to the device
+ * whenever the device registers are synchronised with the cache and
+ * apply them immediately.  Typically this is used to apply
+ * corrections to be applied to the device defaults on startup, such
+ * as the updates some vendors provide to undocumented registers.
+ */
+int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
+			  int num_regs)
+{
+	int i, ret;
+	bool bypass;
+
+	/* If needed the implementation can be extended to support this */
+	if (map->patch)
+		return -EBUSY;
+
+	mutex_lock(&map->lock);
+
+	bypass = map->cache_bypass;
+
+	map->cache_bypass = true;
+
+	/* Write out first; it's useful to apply even if we fail later. */
+	for (i = 0; i < num_regs; i++) {
+		ret = _regmap_write(map, regs[i].reg, regs[i].def);
+		if (ret != 0) {
+			dev_err(map->dev, "Failed to write %x = %x: %d\n",
+				regs[i].reg, regs[i].def, ret);
+			goto out;
+		}
+	}
+
+	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;
+	} else {
+		ret = -ENOMEM;
+	}
+
+out:
+	map->cache_bypass = bypass;
+
+	mutex_unlock(&map->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_register_patch);
+
+/*
+ * regmap_get_val_bytes(): Report the size of a register value
+ *
+ * Report the size of a register value, mainly intended to for use by
+ * generic infrastructure built on top of regmap.
+ */
+int regmap_get_val_bytes(struct regmap *map)
+{
+	if (map->format.format_write)
+		return -EINVAL;
+
+	return map->format.val_bytes;
+}
+EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
+
 static int __init regmap_initcall(void)
 {
 	regmap_debugfs_initcall();
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index e09f9ce..abfaaca 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -179,7 +179,7 @@
 	dev_info(DEV, "helper command: %s %s %s\n", usermode_helper, cmd, mb);
 
 	drbd_bcast_ev_helper(mdev, cmd);
-	ret = call_usermodehelper(usermode_helper, argv, envp, 1);
+	ret = call_usermodehelper(usermode_helper, argv, envp, UMH_WAIT_PROC);
 	if (ret)
 		dev_warn(DEV, "helper command: %s %s %s exit code %u (0x%x)\n",
 				usermode_helper, cmd, mb,
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 744f078..b0b00d7 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -202,7 +202,6 @@
 
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 
 static int FLOPPY_IRQ = 6;
 static int FLOPPY_DMA = 2;
@@ -1031,37 +1030,6 @@
 	return 0;
 }
 
-static DEFINE_SPINLOCK(floppy_hlt_lock);
-static int hlt_disabled;
-static void floppy_disable_hlt(void)
-{
-	unsigned long flags;
-
-	WARN_ONCE(1, "floppy_disable_hlt() scheduled for removal in 2012");
-	spin_lock_irqsave(&floppy_hlt_lock, flags);
-	if (!hlt_disabled) {
-		hlt_disabled = 1;
-#ifdef HAVE_DISABLE_HLT
-		disable_hlt();
-#endif
-	}
-	spin_unlock_irqrestore(&floppy_hlt_lock, flags);
-}
-
-static void floppy_enable_hlt(void)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&floppy_hlt_lock, flags);
-	if (hlt_disabled) {
-		hlt_disabled = 0;
-#ifdef HAVE_DISABLE_HLT
-		enable_hlt();
-#endif
-	}
-	spin_unlock_irqrestore(&floppy_hlt_lock, flags);
-}
-
 static void setup_DMA(void)
 {
 	unsigned long f;
@@ -1106,7 +1074,6 @@
 	fd_enable_dma();
 	release_dma_lock(f);
 #endif
-	floppy_disable_hlt();
 }
 
 static void show_floppy(void);
@@ -1708,7 +1675,6 @@
 	fd_disable_dma();
 	release_dma_lock(f);
 
-	floppy_enable_hlt();
 	do_floppy = NULL;
 	if (fdc >= N_FDC || FDCS->address == -1) {
 		/* we don't even know which FDC is the culprit */
@@ -1857,8 +1823,6 @@
 		show_floppy();
 	cancel_activity();
 
-	floppy_enable_hlt();
-
 	flags = claim_dma_lock();
 	fd_disable_dma();
 	release_dma_lock(flags);
@@ -4509,7 +4473,6 @@
 #if N_FDC > 1
 	set_dor(1, ~8, 0);
 #endif
-	floppy_enable_hlt();
 
 	if (floppy_track_buffer && max_buffer_sectors) {
 		tmpsize = max_buffer_sectors * 1024;
diff --git a/drivers/block/hd.c b/drivers/block/hd.c
index b52c9ca..bf397bf 100644
--- a/drivers/block/hd.c
+++ b/drivers/block/hd.c
@@ -44,7 +44,6 @@
 #define HD_IRQ 14
 
 #define REALLY_SLOW_IO
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index c3f0ee1..061427a 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -34,12 +34,11 @@
 #include <linux/kthread.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/types.h>
 
 #include <linux/nbd.h>
 
-#define LO_MAGIC 0x68797548
+#define NBD_MAGIC 0x68797548
 
 #ifdef NDEBUG
 #define dprintk(flags, fmt...)
@@ -116,7 +115,7 @@
 	spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
-static void sock_shutdown(struct nbd_device *lo, int lock)
+static void sock_shutdown(struct nbd_device *nbd, int lock)
 {
 	/* Forcibly shutdown the socket causing all listeners
 	 * to error
@@ -125,14 +124,14 @@
 	 * there should be a more generic interface rather than
 	 * calling socket ops directly here */
 	if (lock)
-		mutex_lock(&lo->tx_lock);
-	if (lo->sock) {
-		dev_warn(disk_to_dev(lo->disk), "shutting down socket\n");
-		kernel_sock_shutdown(lo->sock, SHUT_RDWR);
-		lo->sock = NULL;
+		mutex_lock(&nbd->tx_lock);
+	if (nbd->sock) {
+		dev_warn(disk_to_dev(nbd->disk), "shutting down socket\n");
+		kernel_sock_shutdown(nbd->sock, SHUT_RDWR);
+		nbd->sock = NULL;
 	}
 	if (lock)
-		mutex_unlock(&lo->tx_lock);
+		mutex_unlock(&nbd->tx_lock);
 }
 
 static void nbd_xmit_timeout(unsigned long arg)
@@ -147,17 +146,17 @@
 /*
  *  Send or receive packet.
  */
-static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
+static int sock_xmit(struct nbd_device *nbd, int send, void *buf, int size,
 		int msg_flags)
 {
-	struct socket *sock = lo->sock;
+	struct socket *sock = nbd->sock;
 	int result;
 	struct msghdr msg;
 	struct kvec iov;
 	sigset_t blocked, oldset;
 
 	if (unlikely(!sock)) {
-		dev_err(disk_to_dev(lo->disk),
+		dev_err(disk_to_dev(nbd->disk),
 			"Attempted %s on closed socket in sock_xmit\n",
 			(send ? "send" : "recv"));
 		return -EINVAL;
@@ -181,15 +180,15 @@
 		if (send) {
 			struct timer_list ti;
 
-			if (lo->xmit_timeout) {
+			if (nbd->xmit_timeout) {
 				init_timer(&ti);
 				ti.function = nbd_xmit_timeout;
 				ti.data = (unsigned long)current;
-				ti.expires = jiffies + lo->xmit_timeout;
+				ti.expires = jiffies + nbd->xmit_timeout;
 				add_timer(&ti);
 			}
 			result = kernel_sendmsg(sock, &msg, &iov, 1, size);
-			if (lo->xmit_timeout)
+			if (nbd->xmit_timeout)
 				del_timer_sync(&ti);
 		} else
 			result = kernel_recvmsg(sock, &msg, &iov, 1, size,
@@ -201,7 +200,7 @@
 				task_pid_nr(current), current->comm,
 				dequeue_signal_lock(current, &current->blocked, &info));
 			result = -EINTR;
-			sock_shutdown(lo, !send);
+			sock_shutdown(nbd, !send);
 			break;
 		}
 
@@ -219,18 +218,19 @@
 	return result;
 }
 
-static inline int sock_send_bvec(struct nbd_device *lo, struct bio_vec *bvec,
+static inline int sock_send_bvec(struct nbd_device *nbd, struct bio_vec *bvec,
 		int flags)
 {
 	int result;
 	void *kaddr = kmap(bvec->bv_page);
-	result = sock_xmit(lo, 1, kaddr + bvec->bv_offset, bvec->bv_len, flags);
+	result = sock_xmit(nbd, 1, kaddr + bvec->bv_offset,
+			   bvec->bv_len, flags);
 	kunmap(bvec->bv_page);
 	return result;
 }
 
 /* always call with the tx_lock held */
-static int nbd_send_req(struct nbd_device *lo, struct request *req)
+static int nbd_send_req(struct nbd_device *nbd, struct request *req)
 {
 	int result, flags;
 	struct nbd_request request;
@@ -243,14 +243,14 @@
 	memcpy(request.handle, &req, sizeof(req));
 
 	dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%uB)\n",
-			lo->disk->disk_name, req,
+			nbd->disk->disk_name, req,
 			nbdcmd_to_ascii(nbd_cmd(req)),
 			(unsigned long long)blk_rq_pos(req) << 9,
 			blk_rq_bytes(req));
-	result = sock_xmit(lo, 1, &request, sizeof(request),
+	result = sock_xmit(nbd, 1, &request, sizeof(request),
 			(nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0);
 	if (result <= 0) {
-		dev_err(disk_to_dev(lo->disk),
+		dev_err(disk_to_dev(nbd->disk),
 			"Send control failed (result %d)\n", result);
 		goto error_out;
 	}
@@ -267,10 +267,10 @@
 			if (!rq_iter_last(req, iter))
 				flags = MSG_MORE;
 			dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n",
-					lo->disk->disk_name, req, bvec->bv_len);
-			result = sock_send_bvec(lo, bvec, flags);
+					nbd->disk->disk_name, req, bvec->bv_len);
+			result = sock_send_bvec(nbd, bvec, flags);
 			if (result <= 0) {
-				dev_err(disk_to_dev(lo->disk),
+				dev_err(disk_to_dev(nbd->disk),
 					"Send data failed (result %d)\n",
 					result);
 				goto error_out;
@@ -283,25 +283,25 @@
 	return -EIO;
 }
 
-static struct request *nbd_find_request(struct nbd_device *lo,
+static struct request *nbd_find_request(struct nbd_device *nbd,
 					struct request *xreq)
 {
 	struct request *req, *tmp;
 	int err;
 
-	err = wait_event_interruptible(lo->active_wq, lo->active_req != xreq);
+	err = wait_event_interruptible(nbd->active_wq, nbd->active_req != xreq);
 	if (unlikely(err))
 		goto out;
 
-	spin_lock(&lo->queue_lock);
-	list_for_each_entry_safe(req, tmp, &lo->queue_head, queuelist) {
+	spin_lock(&nbd->queue_lock);
+	list_for_each_entry_safe(req, tmp, &nbd->queue_head, queuelist) {
 		if (req != xreq)
 			continue;
 		list_del_init(&req->queuelist);
-		spin_unlock(&lo->queue_lock);
+		spin_unlock(&nbd->queue_lock);
 		return req;
 	}
-	spin_unlock(&lo->queue_lock);
+	spin_unlock(&nbd->queue_lock);
 
 	err = -ENOENT;
 
@@ -309,78 +309,78 @@
 	return ERR_PTR(err);
 }
 
-static inline int sock_recv_bvec(struct nbd_device *lo, struct bio_vec *bvec)
+static inline int sock_recv_bvec(struct nbd_device *nbd, struct bio_vec *bvec)
 {
 	int result;
 	void *kaddr = kmap(bvec->bv_page);
-	result = sock_xmit(lo, 0, kaddr + bvec->bv_offset, bvec->bv_len,
+	result = sock_xmit(nbd, 0, kaddr + bvec->bv_offset, bvec->bv_len,
 			MSG_WAITALL);
 	kunmap(bvec->bv_page);
 	return result;
 }
 
 /* NULL returned = something went wrong, inform userspace */
-static struct request *nbd_read_stat(struct nbd_device *lo)
+static struct request *nbd_read_stat(struct nbd_device *nbd)
 {
 	int result;
 	struct nbd_reply reply;
 	struct request *req;
 
 	reply.magic = 0;
-	result = sock_xmit(lo, 0, &reply, sizeof(reply), MSG_WAITALL);
+	result = sock_xmit(nbd, 0, &reply, sizeof(reply), MSG_WAITALL);
 	if (result <= 0) {
-		dev_err(disk_to_dev(lo->disk),
+		dev_err(disk_to_dev(nbd->disk),
 			"Receive control failed (result %d)\n", result);
 		goto harderror;
 	}
 
 	if (ntohl(reply.magic) != NBD_REPLY_MAGIC) {
-		dev_err(disk_to_dev(lo->disk), "Wrong magic (0x%lx)\n",
+		dev_err(disk_to_dev(nbd->disk), "Wrong magic (0x%lx)\n",
 				(unsigned long)ntohl(reply.magic));
 		result = -EPROTO;
 		goto harderror;
 	}
 
-	req = nbd_find_request(lo, *(struct request **)reply.handle);
+	req = nbd_find_request(nbd, *(struct request **)reply.handle);
 	if (IS_ERR(req)) {
 		result = PTR_ERR(req);
 		if (result != -ENOENT)
 			goto harderror;
 
-		dev_err(disk_to_dev(lo->disk), "Unexpected reply (%p)\n",
+		dev_err(disk_to_dev(nbd->disk), "Unexpected reply (%p)\n",
 			reply.handle);
 		result = -EBADR;
 		goto harderror;
 	}
 
 	if (ntohl(reply.error)) {
-		dev_err(disk_to_dev(lo->disk), "Other side returned error (%d)\n",
+		dev_err(disk_to_dev(nbd->disk), "Other side returned error (%d)\n",
 			ntohl(reply.error));
 		req->errors++;
 		return req;
 	}
 
 	dprintk(DBG_RX, "%s: request %p: got reply\n",
-			lo->disk->disk_name, req);
+			nbd->disk->disk_name, req);
 	if (nbd_cmd(req) == NBD_CMD_READ) {
 		struct req_iterator iter;
 		struct bio_vec *bvec;
 
 		rq_for_each_segment(bvec, req, iter) {
-			result = sock_recv_bvec(lo, bvec);
+			result = sock_recv_bvec(nbd, bvec);
 			if (result <= 0) {
-				dev_err(disk_to_dev(lo->disk), "Receive data failed (result %d)\n",
+				dev_err(disk_to_dev(nbd->disk), "Receive data failed (result %d)\n",
 					result);
 				req->errors++;
 				return req;
 			}
 			dprintk(DBG_RX, "%s: request %p: got %d bytes data\n",
-				lo->disk->disk_name, req, bvec->bv_len);
+				nbd->disk->disk_name, req, bvec->bv_len);
 		}
 	}
 	return req;
 harderror:
-	lo->harderror = result;
+	nbd->harderror = result;
 	return NULL;
 }
 
@@ -398,48 +398,48 @@
 	.show = pid_show,
 };
 
-static int nbd_do_it(struct nbd_device *lo)
+static int nbd_do_it(struct nbd_device *nbd)
 {
 	struct request *req;
 	int ret;
 
-	BUG_ON(lo->magic != LO_MAGIC);
+	BUG_ON(nbd->magic != NBD_MAGIC);
 
-	lo->pid = task_pid_nr(current);
-	ret = device_create_file(disk_to_dev(lo->disk), &pid_attr);
+	nbd->pid = task_pid_nr(current);
+	ret = device_create_file(disk_to_dev(nbd->disk), &pid_attr);
 	if (ret) {
-		dev_err(disk_to_dev(lo->disk), "device_create_file failed!\n");
-		lo->pid = 0;
+		dev_err(disk_to_dev(nbd->disk), "device_create_file failed!\n");
+		nbd->pid = 0;
 		return ret;
 	}
 
-	while ((req = nbd_read_stat(lo)) != NULL)
+	while ((req = nbd_read_stat(nbd)) != NULL)
 		nbd_end_request(req);
 
-	device_remove_file(disk_to_dev(lo->disk), &pid_attr);
-	lo->pid = 0;
+	device_remove_file(disk_to_dev(nbd->disk), &pid_attr);
+	nbd->pid = 0;
 	return 0;
 }
 
-static void nbd_clear_que(struct nbd_device *lo)
+static void nbd_clear_que(struct nbd_device *nbd)
 {
 	struct request *req;
 
-	BUG_ON(lo->magic != LO_MAGIC);
+	BUG_ON(nbd->magic != NBD_MAGIC);
 
 	/*
-	 * Because we have set lo->sock to NULL under the tx_lock, all
+	 * Because we have set nbd->sock to NULL under the tx_lock, all
 	 * modifications to the list must have completed by now.  For
 	 * the same reason, the active_req must be NULL.
 	 *
 	 * As a consequence, we don't need to take the spin lock while
 	 * purging the list here.
 	 */
-	BUG_ON(lo->sock);
-	BUG_ON(lo->active_req);
+	BUG_ON(nbd->sock);
+	BUG_ON(nbd->active_req);
 
-	while (!list_empty(&lo->queue_head)) {
-		req = list_entry(lo->queue_head.next, struct request,
+	while (!list_empty(&nbd->queue_head)) {
+		req = list_entry(nbd->queue_head.next, struct request,
 				 queuelist);
 		list_del_init(&req->queuelist);
 		req->errors++;
@@ -448,7 +448,7 @@
 }
 
 
-static void nbd_handle_req(struct nbd_device *lo, struct request *req)
+static void nbd_handle_req(struct nbd_device *nbd, struct request *req)
 {
 	if (req->cmd_type != REQ_TYPE_FS)
 		goto error_out;
@@ -456,8 +456,8 @@
 	nbd_cmd(req) = NBD_CMD_READ;
 	if (rq_data_dir(req) == WRITE) {
 		nbd_cmd(req) = NBD_CMD_WRITE;
-		if (lo->flags & NBD_READ_ONLY) {
-			dev_err(disk_to_dev(lo->disk),
+		if (nbd->flags & NBD_READ_ONLY) {
+			dev_err(disk_to_dev(nbd->disk),
 				"Write on read-only\n");
 			goto error_out;
 		}
@@ -465,29 +465,29 @@
 
 	req->errors = 0;
 
-	mutex_lock(&lo->tx_lock);
-	if (unlikely(!lo->sock)) {
-		mutex_unlock(&lo->tx_lock);
-		dev_err(disk_to_dev(lo->disk),
+	mutex_lock(&nbd->tx_lock);
+	if (unlikely(!nbd->sock)) {
+		mutex_unlock(&nbd->tx_lock);
+		dev_err(disk_to_dev(nbd->disk),
 			"Attempted send on closed socket\n");
 		goto error_out;
 	}
 
-	lo->active_req = req;
+	nbd->active_req = req;
 
-	if (nbd_send_req(lo, req) != 0) {
-		dev_err(disk_to_dev(lo->disk), "Request send failed\n");
+	if (nbd_send_req(nbd, req) != 0) {
+		dev_err(disk_to_dev(nbd->disk), "Request send failed\n");
 		req->errors++;
 		nbd_end_request(req);
 	} else {
-		spin_lock(&lo->queue_lock);
-		list_add(&req->queuelist, &lo->queue_head);
-		spin_unlock(&lo->queue_lock);
+		spin_lock(&nbd->queue_lock);
+		list_add(&req->queuelist, &nbd->queue_head);
+		spin_unlock(&nbd->queue_lock);
 	}
 
-	lo->active_req = NULL;
-	mutex_unlock(&lo->tx_lock);
-	wake_up_all(&lo->active_wq);
+	nbd->active_req = NULL;
+	mutex_unlock(&nbd->tx_lock);
+	wake_up_all(&nbd->active_wq);
 
 	return;
 
@@ -498,28 +498,28 @@
 
 static int nbd_thread(void *data)
 {
-	struct nbd_device *lo = data;
+	struct nbd_device *nbd = data;
 	struct request *req;
 
 	set_user_nice(current, -20);
-	while (!kthread_should_stop() || !list_empty(&lo->waiting_queue)) {
+	while (!kthread_should_stop() || !list_empty(&nbd->waiting_queue)) {
 		/* wait for something to do */
-		wait_event_interruptible(lo->waiting_wq,
+		wait_event_interruptible(nbd->waiting_wq,
 					 kthread_should_stop() ||
-					 !list_empty(&lo->waiting_queue));
+					 !list_empty(&nbd->waiting_queue));
 
 		/* extract request */
-		if (list_empty(&lo->waiting_queue))
+		if (list_empty(&nbd->waiting_queue))
 			continue;
 
-		spin_lock_irq(&lo->queue_lock);
-		req = list_entry(lo->waiting_queue.next, struct request,
+		spin_lock_irq(&nbd->queue_lock);
+		req = list_entry(nbd->waiting_queue.next, struct request,
 				 queuelist);
 		list_del_init(&req->queuelist);
-		spin_unlock_irq(&lo->queue_lock);
+		spin_unlock_irq(&nbd->queue_lock);
 
 		/* handle request */
-		nbd_handle_req(lo, req);
+		nbd_handle_req(nbd, req);
 	}
 	return 0;
 }
@@ -527,7 +527,7 @@
 /*
  * We always wait for result of write, for now. It would be nice to make it optional
  * in future
- * if ((rq_data_dir(req) == WRITE) && (lo->flags & NBD_WRITE_NOCHK))
+ * if ((rq_data_dir(req) == WRITE) && (nbd->flags & NBD_WRITE_NOCHK))
  *   { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); }
  */
 
@@ -536,19 +536,19 @@
 	struct request *req;
 	
 	while ((req = blk_fetch_request(q)) != NULL) {
-		struct nbd_device *lo;
+		struct nbd_device *nbd;
 
 		spin_unlock_irq(q->queue_lock);
 
 		dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n",
 				req->rq_disk->disk_name, req, req->cmd_type);
 
-		lo = req->rq_disk->private_data;
+		nbd = req->rq_disk->private_data;
 
-		BUG_ON(lo->magic != LO_MAGIC);
+		BUG_ON(nbd->magic != NBD_MAGIC);
 
-		if (unlikely(!lo->sock)) {
-			dev_err(disk_to_dev(lo->disk),
+		if (unlikely(!nbd->sock)) {
+			dev_err(disk_to_dev(nbd->disk),
 				"Attempted send on closed socket\n");
 			req->errors++;
 			nbd_end_request(req);
@@ -556,11 +556,11 @@
 			continue;
 		}
 
-		spin_lock_irq(&lo->queue_lock);
-		list_add_tail(&req->queuelist, &lo->waiting_queue);
-		spin_unlock_irq(&lo->queue_lock);
+		spin_lock_irq(&nbd->queue_lock);
+		list_add_tail(&req->queuelist, &nbd->waiting_queue);
+		spin_unlock_irq(&nbd->queue_lock);
 
-		wake_up(&lo->waiting_wq);
+		wake_up(&nbd->waiting_wq);
 
 		spin_lock_irq(q->queue_lock);
 	}
@@ -568,32 +568,32 @@
 
 /* Must be called with tx_lock held */
 
-static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
+static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
 		       unsigned int cmd, unsigned long arg)
 {
 	switch (cmd) {
 	case NBD_DISCONNECT: {
 		struct request sreq;
 
-		dev_info(disk_to_dev(lo->disk), "NBD_DISCONNECT\n");
+		dev_info(disk_to_dev(nbd->disk), "NBD_DISCONNECT\n");
 
 		blk_rq_init(NULL, &sreq);
 		sreq.cmd_type = REQ_TYPE_SPECIAL;
 		nbd_cmd(&sreq) = NBD_CMD_DISC;
-		if (!lo->sock)
+		if (!nbd->sock)
 			return -EINVAL;
-		nbd_send_req(lo, &sreq);
+		nbd_send_req(nbd, &sreq);
                 return 0;
 	}
  
 	case NBD_CLEAR_SOCK: {
 		struct file *file;
 
-		lo->sock = NULL;
-		file = lo->file;
-		lo->file = NULL;
-		nbd_clear_que(lo);
-		BUG_ON(!list_empty(&lo->queue_head));
+		nbd->sock = NULL;
+		file = nbd->file;
+		nbd->file = NULL;
+		nbd_clear_que(nbd);
+		BUG_ON(!list_empty(&nbd->queue_head));
 		if (file)
 			fput(file);
 		return 0;
@@ -601,14 +601,14 @@
 
 	case NBD_SET_SOCK: {
 		struct file *file;
-		if (lo->file)
+		if (nbd->file)
 			return -EBUSY;
 		file = fget(arg);
 		if (file) {
 			struct inode *inode = file->f_path.dentry->d_inode;
 			if (S_ISSOCK(inode->i_mode)) {
-				lo->file = file;
-				lo->sock = SOCKET_I(inode);
+				nbd->file = file;
+				nbd->sock = SOCKET_I(inode);
 				if (max_part > 0)
 					bdev->bd_invalidated = 1;
 				return 0;
@@ -620,29 +620,29 @@
 	}
 
 	case NBD_SET_BLKSIZE:
-		lo->blksize = arg;
-		lo->bytesize &= ~(lo->blksize-1);
-		bdev->bd_inode->i_size = lo->bytesize;
-		set_blocksize(bdev, lo->blksize);
-		set_capacity(lo->disk, lo->bytesize >> 9);
+		nbd->blksize = arg;
+		nbd->bytesize &= ~(nbd->blksize-1);
+		bdev->bd_inode->i_size = nbd->bytesize;
+		set_blocksize(bdev, nbd->blksize);
+		set_capacity(nbd->disk, nbd->bytesize >> 9);
 		return 0;
 
 	case NBD_SET_SIZE:
-		lo->bytesize = arg & ~(lo->blksize-1);
-		bdev->bd_inode->i_size = lo->bytesize;
-		set_blocksize(bdev, lo->blksize);
-		set_capacity(lo->disk, lo->bytesize >> 9);
+		nbd->bytesize = arg & ~(nbd->blksize-1);
+		bdev->bd_inode->i_size = nbd->bytesize;
+		set_blocksize(bdev, nbd->blksize);
+		set_capacity(nbd->disk, nbd->bytesize >> 9);
 		return 0;
 
 	case NBD_SET_TIMEOUT:
-		lo->xmit_timeout = arg * HZ;
+		nbd->xmit_timeout = arg * HZ;
 		return 0;
 
 	case NBD_SET_SIZE_BLOCKS:
-		lo->bytesize = ((u64) arg) * lo->blksize;
-		bdev->bd_inode->i_size = lo->bytesize;
-		set_blocksize(bdev, lo->blksize);
-		set_capacity(lo->disk, lo->bytesize >> 9);
+		nbd->bytesize = ((u64) arg) * nbd->blksize;
+		bdev->bd_inode->i_size = nbd->bytesize;
+		set_blocksize(bdev, nbd->blksize);
+		set_capacity(nbd->disk, nbd->bytesize >> 9);
 		return 0;
 
 	case NBD_DO_IT: {
@@ -650,38 +650,38 @@
 		struct file *file;
 		int error;
 
-		if (lo->pid)
+		if (nbd->pid)
 			return -EBUSY;
-		if (!lo->file)
+		if (!nbd->file)
 			return -EINVAL;
 
-		mutex_unlock(&lo->tx_lock);
+		mutex_unlock(&nbd->tx_lock);
 
-		thread = kthread_create(nbd_thread, lo, lo->disk->disk_name);
+		thread = kthread_create(nbd_thread, nbd, nbd->disk->disk_name);
 		if (IS_ERR(thread)) {
-			mutex_lock(&lo->tx_lock);
+			mutex_lock(&nbd->tx_lock);
 			return PTR_ERR(thread);
 		}
 		wake_up_process(thread);
-		error = nbd_do_it(lo);
+		error = nbd_do_it(nbd);
 		kthread_stop(thread);
 
-		mutex_lock(&lo->tx_lock);
+		mutex_lock(&nbd->tx_lock);
 		if (error)
 			return error;
-		sock_shutdown(lo, 0);
-		file = lo->file;
-		lo->file = NULL;
-		nbd_clear_que(lo);
-		dev_warn(disk_to_dev(lo->disk), "queue cleared\n");
+		sock_shutdown(nbd, 0);
+		file = nbd->file;
+		nbd->file = NULL;
+		nbd_clear_que(nbd);
+		dev_warn(disk_to_dev(nbd->disk), "queue cleared\n");
 		if (file)
 			fput(file);
-		lo->bytesize = 0;
+		nbd->bytesize = 0;
 		bdev->bd_inode->i_size = 0;
-		set_capacity(lo->disk, 0);
+		set_capacity(nbd->disk, 0);
 		if (max_part > 0)
 			ioctl_by_bdev(bdev, BLKRRPART, 0);
-		return lo->harderror;
+		return nbd->harderror;
 	}
 
 	case NBD_CLEAR_QUE:
@@ -689,14 +689,14 @@
 		 * This is for compatibility only.  The queue is always cleared
 		 * by NBD_DO_IT or NBD_CLEAR_SOCK.
 		 */
-		BUG_ON(!lo->sock && !list_empty(&lo->queue_head));
+		BUG_ON(!nbd->sock && !list_empty(&nbd->queue_head));
 		return 0;
 
 	case NBD_PRINT_DEBUG:
-		dev_info(disk_to_dev(lo->disk),
+		dev_info(disk_to_dev(nbd->disk),
 			"next = %p, prev = %p, head = %p\n",
-			lo->queue_head.next, lo->queue_head.prev,
-			&lo->queue_head);
+			nbd->queue_head.next, nbd->queue_head.prev,
+			&nbd->queue_head);
 		return 0;
 	}
 	return -ENOTTY;
@@ -705,21 +705,21 @@
 static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
 		     unsigned int cmd, unsigned long arg)
 {
-	struct nbd_device *lo = bdev->bd_disk->private_data;
+	struct nbd_device *nbd = bdev->bd_disk->private_data;
 	int error;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	BUG_ON(lo->magic != LO_MAGIC);
+	BUG_ON(nbd->magic != NBD_MAGIC);
 
 	/* Anyone capable of this syscall can do *real bad* things */
 	dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
-			lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
+		nbd->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
 
-	mutex_lock(&lo->tx_lock);
-	error = __nbd_ioctl(bdev, lo, cmd, arg);
-	mutex_unlock(&lo->tx_lock);
+	mutex_lock(&nbd->tx_lock);
+	error = __nbd_ioctl(bdev, nbd, cmd, arg);
+	mutex_unlock(&nbd->tx_lock);
 
 	return error;
 }
@@ -805,7 +805,7 @@
 	for (i = 0; i < nbds_max; i++) {
 		struct gendisk *disk = nbd_dev[i].disk;
 		nbd_dev[i].file = NULL;
-		nbd_dev[i].magic = LO_MAGIC;
+		nbd_dev[i].magic = NBD_MAGIC;
 		nbd_dev[i].flags = 0;
 		INIT_LIST_HEAD(&nbd_dev[i].waiting_queue);
 		spin_lock_init(&nbd_dev[i].queue_lock);
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index a6278e7..013c7a5 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -41,19 +41,35 @@
 
 #include "rbd_types.h"
 
-#define DRV_NAME "rbd"
-#define DRV_NAME_LONG "rbd (rados block device)"
+/*
+ * The basic unit of block I/O is a sector.  It is interpreted in a
+ * number of contexts in Linux (blk, bio, genhd), but the default is
+ * universally 512 bytes.  These symbols are just slightly more
+ * meaningful than the bare numbers they represent.
+ */
+#define	SECTOR_SHIFT	9
+#define	SECTOR_SIZE	(1ULL << SECTOR_SHIFT)
+
+#define RBD_DRV_NAME "rbd"
+#define RBD_DRV_NAME_LONG "rbd (rados block device)"
 
 #define RBD_MINORS_PER_MAJOR	256		/* max minors per blkdev */
 
-#define RBD_MAX_MD_NAME_LEN	(96 + sizeof(RBD_SUFFIX))
+#define RBD_MAX_MD_NAME_LEN	(RBD_MAX_OBJ_NAME_LEN + sizeof(RBD_SUFFIX))
 #define RBD_MAX_POOL_NAME_LEN	64
 #define RBD_MAX_SNAP_NAME_LEN	32
 #define RBD_MAX_OPT_LEN		1024
 
 #define RBD_SNAP_HEAD_NAME	"-"
 
+/*
+ * An RBD device name will be "rbd#", where the "rbd" comes from
+ * RBD_DRV_NAME above, and # is a unique integer identifier.
+ * MAX_INT_FORMAT_WIDTH is used in ensuring DEV_NAME_LEN is big
+ * enough to hold all possible device names.
+ */
 #define DEV_NAME_LEN		32
+#define MAX_INT_FORMAT_WIDTH	((5 * sizeof (int)) / 2 + 1)
 
 #define RBD_NOTIFY_TIMEOUT_DEFAULT 10
 
@@ -66,7 +82,6 @@
 	__u8 obj_order;
 	__u8 crypt_type;
 	__u8 comp_type;
-	struct rw_semaphore snap_rwsem;
 	struct ceph_snap_context *snapc;
 	size_t snap_names_len;
 	u64 snap_seq;
@@ -83,7 +98,7 @@
 };
 
 /*
- * an instance of the client.  multiple devices may share a client.
+ * an instance of the client.  multiple devices may share an rbd client.
  */
 struct rbd_client {
 	struct ceph_client	*client;
@@ -92,20 +107,9 @@
 	struct list_head	node;
 };
 
-struct rbd_req_coll;
-
 /*
- * a single io request
+ * a request completion status
  */
-struct rbd_request {
-	struct request		*rq;		/* blk layer request */
-	struct bio		*bio;		/* cloned bio */
-	struct page		**pages;	/* list of used pages */
-	u64			len;
-	int			coll_index;
-	struct rbd_req_coll	*coll;
-};
-
 struct rbd_req_status {
 	int done;
 	int rc;
@@ -122,6 +126,18 @@
 	struct rbd_req_status	status[0];
 };
 
+/*
+ * a single io request
+ */
+struct rbd_request {
+	struct request		*rq;		/* blk layer request */
+	struct bio		*bio;		/* cloned bio */
+	struct page		**pages;	/* list of used pages */
+	u64			len;
+	int			coll_index;
+	struct rbd_req_coll	*coll;
+};
+
 struct rbd_snap {
 	struct	device		dev;
 	const char		*name;
@@ -140,7 +156,6 @@
 	struct gendisk		*disk;		/* blkdev's gendisk and rq */
 	struct request_queue	*q;
 
-	struct ceph_client	*client;
 	struct rbd_client	*rbd_client;
 
 	char			name[DEV_NAME_LEN]; /* blkdev name, e.g. rbd3 */
@@ -157,6 +172,8 @@
 	struct ceph_osd_event   *watch_event;
 	struct ceph_osd_request *watch_request;
 
+	/* protects updating the header */
+	struct rw_semaphore     header_rwsem;
 	char                    snap_name[RBD_MAX_SNAP_NAME_LEN];
 	u32 cur_snap;	/* index+1 of current snapshot within snap context
 			   0 - for the head */
@@ -171,15 +188,13 @@
 	struct device		dev;
 };
 
-static struct bus_type rbd_bus_type = {
-	.name		= "rbd",
-};
-
-static spinlock_t node_lock;      /* protects client get/put */
-
 static DEFINE_MUTEX(ctl_mutex);	  /* Serialize open/close/setup/teardown */
+
 static LIST_HEAD(rbd_dev_list);    /* devices */
-static LIST_HEAD(rbd_client_list);      /* clients */
+static DEFINE_SPINLOCK(rbd_dev_list_lock);
+
+static LIST_HEAD(rbd_client_list);		/* clients */
+static DEFINE_SPINLOCK(rbd_client_list_lock);
 
 static int __rbd_init_snaps_header(struct rbd_device *rbd_dev);
 static void rbd_dev_release(struct device *dev);
@@ -190,12 +205,32 @@
 static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev,
 				  struct rbd_snap *snap);
 
+static ssize_t rbd_add(struct bus_type *bus, const char *buf,
+		       size_t count);
+static ssize_t rbd_remove(struct bus_type *bus, const char *buf,
+			  size_t count);
 
-static struct rbd_device *dev_to_rbd(struct device *dev)
+static struct bus_attribute rbd_bus_attrs[] = {
+	__ATTR(add, S_IWUSR, NULL, rbd_add),
+	__ATTR(remove, S_IWUSR, NULL, rbd_remove),
+	__ATTR_NULL
+};
+
+static struct bus_type rbd_bus_type = {
+	.name		= "rbd",
+	.bus_attrs	= rbd_bus_attrs,
+};
+
+static void rbd_root_dev_release(struct device *dev)
 {
-	return container_of(dev, struct rbd_device, dev);
 }
 
+static struct device rbd_root_dev = {
+	.init_name =    "rbd",
+	.release =      rbd_root_dev_release,
+};
+
+
 static struct device *rbd_get_dev(struct rbd_device *rbd_dev)
 {
 	return get_device(&rbd_dev->dev);
@@ -210,8 +245,7 @@
 
 static int rbd_open(struct block_device *bdev, fmode_t mode)
 {
-	struct gendisk *disk = bdev->bd_disk;
-	struct rbd_device *rbd_dev = disk->private_data;
+	struct rbd_device *rbd_dev = bdev->bd_disk->private_data;
 
 	rbd_get_dev(rbd_dev);
 
@@ -256,9 +290,11 @@
 	kref_init(&rbdc->kref);
 	INIT_LIST_HEAD(&rbdc->node);
 
+	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
 	rbdc->client = ceph_create_client(opt, rbdc, 0, 0);
 	if (IS_ERR(rbdc->client))
-		goto out_rbdc;
+		goto out_mutex;
 	opt = NULL; /* Now rbdc->client is responsible for opt */
 
 	ret = ceph_open_session(rbdc->client);
@@ -267,16 +303,19 @@
 
 	rbdc->rbd_opts = rbd_opts;
 
-	spin_lock(&node_lock);
+	spin_lock(&rbd_client_list_lock);
 	list_add_tail(&rbdc->node, &rbd_client_list);
-	spin_unlock(&node_lock);
+	spin_unlock(&rbd_client_list_lock);
+
+	mutex_unlock(&ctl_mutex);
 
 	dout("rbd_client_create created %p\n", rbdc);
 	return rbdc;
 
 out_err:
 	ceph_destroy_client(rbdc->client);
-out_rbdc:
+out_mutex:
+	mutex_unlock(&ctl_mutex);
 	kfree(rbdc);
 out_opt:
 	if (opt)
@@ -324,7 +363,7 @@
 	substring_t argstr[MAX_OPT_ARGS];
 	int token, intval, ret;
 
-	token = match_token((char *)c, rbdopt_tokens, argstr);
+	token = match_token(c, rbdopt_tokens, argstr);
 	if (token < 0)
 		return -EINVAL;
 
@@ -357,58 +396,54 @@
  * Get a ceph client with specific addr and configuration, if one does
  * not exist create it.
  */
-static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr,
-			  char *options)
+static struct rbd_client *rbd_get_client(const char *mon_addr,
+					 size_t mon_addr_len,
+					 char *options)
 {
 	struct rbd_client *rbdc;
 	struct ceph_options *opt;
-	int ret;
 	struct rbd_options *rbd_opts;
 
 	rbd_opts = kzalloc(sizeof(*rbd_opts), GFP_KERNEL);
 	if (!rbd_opts)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	rbd_opts->notify_timeout = RBD_NOTIFY_TIMEOUT_DEFAULT;
 
-	ret = ceph_parse_options(&opt, options, mon_addr,
-				 mon_addr + strlen(mon_addr), parse_rbd_opts_token, rbd_opts);
-	if (ret < 0)
-		goto done_err;
+	opt = ceph_parse_options(options, mon_addr,
+				mon_addr + mon_addr_len,
+				parse_rbd_opts_token, rbd_opts);
+	if (IS_ERR(opt)) {
+		kfree(rbd_opts);
+		return ERR_CAST(opt);
+	}
 
-	spin_lock(&node_lock);
+	spin_lock(&rbd_client_list_lock);
 	rbdc = __rbd_client_find(opt);
 	if (rbdc) {
+		/* using an existing client */
+		kref_get(&rbdc->kref);
+		spin_unlock(&rbd_client_list_lock);
+
 		ceph_destroy_options(opt);
 		kfree(rbd_opts);
 
-		/* using an existing client */
-		kref_get(&rbdc->kref);
-		rbd_dev->rbd_client = rbdc;
-		rbd_dev->client = rbdc->client;
-		spin_unlock(&node_lock);
-		return 0;
+		return rbdc;
 	}
-	spin_unlock(&node_lock);
+	spin_unlock(&rbd_client_list_lock);
 
 	rbdc = rbd_client_create(opt, rbd_opts);
-	if (IS_ERR(rbdc)) {
-		ret = PTR_ERR(rbdc);
-		goto done_err;
-	}
 
-	rbd_dev->rbd_client = rbdc;
-	rbd_dev->client = rbdc->client;
-	return 0;
-done_err:
-	kfree(rbd_opts);
-	return ret;
+	if (IS_ERR(rbdc))
+		kfree(rbd_opts);
+
+	return rbdc;
 }
 
 /*
  * Destroy ceph client
  *
- * Caller must hold node_lock.
+ * Caller must hold rbd_client_list_lock.
  */
 static void rbd_client_release(struct kref *kref)
 {
@@ -428,11 +463,10 @@
  */
 static void rbd_put_client(struct rbd_device *rbd_dev)
 {
-	spin_lock(&node_lock);
+	spin_lock(&rbd_client_list_lock);
 	kref_put(&rbd_dev->rbd_client->kref, rbd_client_release);
-	spin_unlock(&node_lock);
+	spin_unlock(&rbd_client_list_lock);
 	rbd_dev->rbd_client = NULL;
-	rbd_dev->client = NULL;
 }
 
 /*
@@ -457,21 +491,19 @@
 				 gfp_t gfp_flags)
 {
 	int i;
-	u32 snap_count = le32_to_cpu(ondisk->snap_count);
-	int ret = -ENOMEM;
+	u32 snap_count;
 
-	if (memcmp(ondisk, RBD_HEADER_TEXT, sizeof(RBD_HEADER_TEXT))) {
+	if (memcmp(ondisk, RBD_HEADER_TEXT, sizeof(RBD_HEADER_TEXT)))
 		return -ENXIO;
-	}
 
-	init_rwsem(&header->snap_rwsem);
-	header->snap_names_len = le64_to_cpu(ondisk->snap_names_len);
+	snap_count = le32_to_cpu(ondisk->snap_count);
 	header->snapc = kmalloc(sizeof(struct ceph_snap_context) +
-				snap_count *
-				 sizeof(struct rbd_image_snap_ondisk),
+				snap_count * sizeof (*ondisk),
 				gfp_flags);
 	if (!header->snapc)
 		return -ENOMEM;
+
+	header->snap_names_len = le64_to_cpu(ondisk->snap_names_len);
 	if (snap_count) {
 		header->snap_names = kmalloc(header->snap_names_len,
 					     GFP_KERNEL);
@@ -498,8 +530,7 @@
 	header->snapc->num_snaps = snap_count;
 	header->total_snaps = snap_count;
 
-	if (snap_count &&
-	    allocated_snaps == snap_count) {
+	if (snap_count && allocated_snaps == snap_count) {
 		for (i = 0; i < snap_count; i++) {
 			header->snapc->snaps[i] =
 				le64_to_cpu(ondisk->snaps[i].id);
@@ -518,7 +549,7 @@
 	kfree(header->snap_names);
 err_snapc:
 	kfree(header->snapc);
-	return ret;
+	return -ENOMEM;
 }
 
 static int snap_index(struct rbd_image_header *header, int snap_num)
@@ -542,35 +573,34 @@
 	int i;
 	char *p = header->snap_names;
 
-	for (i = 0; i < header->total_snaps; i++, p += strlen(p) + 1) {
-		if (strcmp(snap_name, p) == 0)
-			break;
+	for (i = 0; i < header->total_snaps; i++) {
+		if (!strcmp(snap_name, p)) {
+
+			/* Found it.  Pass back its id and/or size */
+
+			if (seq)
+				*seq = header->snapc->snaps[i];
+			if (size)
+				*size = header->snap_sizes[i];
+			return i;
+		}
+		p += strlen(p) + 1;	/* Skip ahead to the next name */
 	}
-	if (i == header->total_snaps)
-		return -ENOENT;
-	if (seq)
-		*seq = header->snapc->snaps[i];
-
-	if (size)
-		*size = header->snap_sizes[i];
-
-	return i;
+	return -ENOENT;
 }
 
-static int rbd_header_set_snap(struct rbd_device *dev,
-			       const char *snap_name,
-			       u64 *size)
+static int rbd_header_set_snap(struct rbd_device *dev, u64 *size)
 {
 	struct rbd_image_header *header = &dev->header;
 	struct ceph_snap_context *snapc = header->snapc;
 	int ret = -ENOENT;
 
-	down_write(&header->snap_rwsem);
+	BUILD_BUG_ON(sizeof (dev->snap_name) < sizeof (RBD_SNAP_HEAD_NAME));
 
-	if (!snap_name ||
-	    !*snap_name ||
-	    strcmp(snap_name, "-") == 0 ||
-	    strcmp(snap_name, RBD_SNAP_HEAD_NAME) == 0) {
+	down_write(&dev->header_rwsem);
+
+	if (!memcmp(dev->snap_name, RBD_SNAP_HEAD_NAME,
+		    sizeof (RBD_SNAP_HEAD_NAME))) {
 		if (header->total_snaps)
 			snapc->seq = header->snap_seq;
 		else
@@ -580,7 +610,7 @@
 		if (size)
 			*size = header->image_size;
 	} else {
-		ret = snap_by_name(header, snap_name, &snapc->seq, size);
+		ret = snap_by_name(header, dev->snap_name, &snapc->seq, size);
 		if (ret < 0)
 			goto done;
 
@@ -590,7 +620,7 @@
 
 	ret = 0;
 done:
-	up_write(&header->snap_rwsem);
+	up_write(&dev->header_rwsem);
 	return ret;
 }
 
@@ -717,7 +747,7 @@
 
 			/* split the bio. We'll release it either in the next
 			   call, or it will have to be released outside */
-			bp = bio_split(old_chain, (len - total) / 512ULL);
+			bp = bio_split(old_chain, (len - total) / SECTOR_SIZE);
 			if (!bp)
 				goto err_out;
 
@@ -857,7 +887,7 @@
 	struct timespec mtime = CURRENT_TIME;
 	struct rbd_request *req_data;
 	struct ceph_osd_request_head *reqhead;
-	struct rbd_image_header *header = &dev->header;
+	struct ceph_osd_client *osdc;
 
 	req_data = kzalloc(sizeof(*req_data), GFP_NOIO);
 	if (!req_data) {
@@ -874,15 +904,13 @@
 
 	dout("rbd_do_request obj=%s ofs=%lld len=%lld\n", obj, len, ofs);
 
-	down_read(&header->snap_rwsem);
+	down_read(&dev->header_rwsem);
 
-	req = ceph_osdc_alloc_request(&dev->client->osdc, flags,
-				      snapc,
-				      ops,
-				      false,
-				      GFP_NOIO, pages, bio);
+	osdc = &dev->rbd_client->client->osdc;
+	req = ceph_osdc_alloc_request(osdc, flags, snapc, ops,
+					false, GFP_NOIO, pages, bio);
 	if (!req) {
-		up_read(&header->snap_rwsem);
+		up_read(&dev->header_rwsem);
 		ret = -ENOMEM;
 		goto done_pages;
 	}
@@ -909,27 +937,27 @@
 	layout->fl_object_size = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER);
 	layout->fl_pg_preferred = cpu_to_le32(-1);
 	layout->fl_pg_pool = cpu_to_le32(dev->poolid);
-	ceph_calc_raw_layout(&dev->client->osdc, layout, snapid,
-			     ofs, &len, &bno, req, ops);
+	ceph_calc_raw_layout(osdc, layout, snapid, ofs, &len, &bno,
+				req, ops);
 
 	ceph_osdc_build_request(req, ofs, &len,
 				ops,
 				snapc,
 				&mtime,
 				req->r_oid, req->r_oid_len);
-	up_read(&header->snap_rwsem);
+	up_read(&dev->header_rwsem);
 
 	if (linger_req) {
-		ceph_osdc_set_request_linger(&dev->client->osdc, req);
+		ceph_osdc_set_request_linger(osdc, req);
 		*linger_req = req;
 	}
 
-	ret = ceph_osdc_start_request(&dev->client->osdc, req, false);
+	ret = ceph_osdc_start_request(osdc, req, false);
 	if (ret < 0)
 		goto done_err;
 
 	if (!rbd_cb) {
-		ret = ceph_osdc_wait_request(&dev->client->osdc, req);
+		ret = ceph_osdc_wait_request(osdc, req);
 		if (ver)
 			*ver = le64_to_cpu(req->r_reassert_version.version);
 		dout("reassert_ver=%lld\n",
@@ -1213,8 +1241,8 @@
 	rc = __rbd_update_snaps(dev);
 	mutex_unlock(&ctl_mutex);
 	if (rc)
-		pr_warning(DRV_NAME "%d got notification but failed to update"
-			   " snaps: %d\n", dev->major, rc);
+		pr_warning(RBD_DRV_NAME "%d got notification but failed to "
+			   " update snaps: %d\n", dev->major, rc);
 
 	rbd_req_sync_notify_ack(dev, ver, notify_id, dev->obj_md_name);
 }
@@ -1227,7 +1255,7 @@
 			      u64 ver)
 {
 	struct ceph_osd_req_op *ops;
-	struct ceph_osd_client *osdc = &dev->client->osdc;
+	struct ceph_osd_client *osdc = &dev->rbd_client->client->osdc;
 
 	int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_WATCH, 0);
 	if (ret < 0)
@@ -1314,7 +1342,7 @@
 		          const char *obj)
 {
 	struct ceph_osd_req_op *ops;
-	struct ceph_osd_client *osdc = &dev->client->osdc;
+	struct ceph_osd_client *osdc = &dev->rbd_client->client->osdc;
 	struct ceph_osd_event *event;
 	struct rbd_notify_info info;
 	int payload_len = sizeof(u32) + sizeof(u32);
@@ -1421,9 +1449,7 @@
 	struct request *rq;
 	struct bio_pair *bp = NULL;
 
-	rq = blk_fetch_request(q);
-
-	while (1) {
+	while ((rq = blk_fetch_request(q))) {
 		struct bio *bio;
 		struct bio *rq_bio, *next_bio = NULL;
 		bool do_write;
@@ -1441,32 +1467,32 @@
 		/* filter out block requests we don't understand */
 		if ((rq->cmd_type != REQ_TYPE_FS)) {
 			__blk_end_request_all(rq, 0);
-			goto next;
+			continue;
 		}
 
 		/* deduce our operation (read, write) */
 		do_write = (rq_data_dir(rq) == WRITE);
 
 		size = blk_rq_bytes(rq);
-		ofs = blk_rq_pos(rq) * 512ULL;
+		ofs = blk_rq_pos(rq) * SECTOR_SIZE;
 		rq_bio = rq->bio;
 		if (do_write && rbd_dev->read_only) {
 			__blk_end_request_all(rq, -EROFS);
-			goto next;
+			continue;
 		}
 
 		spin_unlock_irq(q->queue_lock);
 
 		dout("%s 0x%x bytes at 0x%llx\n",
 		     do_write ? "write" : "read",
-		     size, blk_rq_pos(rq) * 512ULL);
+		     size, blk_rq_pos(rq) * SECTOR_SIZE);
 
 		num_segs = rbd_get_num_segments(&rbd_dev->header, ofs, size);
 		coll = rbd_alloc_coll(num_segs);
 		if (!coll) {
 			spin_lock_irq(q->queue_lock);
 			__blk_end_request_all(rq, -ENOMEM);
-			goto next;
+			continue;
 		}
 
 		do {
@@ -1512,8 +1538,6 @@
 		if (bp)
 			bio_pair_release(bp);
 		spin_lock_irq(q->queue_lock);
-next:
-		rq = blk_fetch_request(q);
 	}
 }
 
@@ -1526,13 +1550,17 @@
 			  struct bio_vec *bvec)
 {
 	struct rbd_device *rbd_dev = q->queuedata;
-	unsigned int chunk_sectors = 1 << (rbd_dev->header.obj_order - 9);
-	sector_t sector = bmd->bi_sector + get_start_sect(bmd->bi_bdev);
-	unsigned int bio_sectors = bmd->bi_size >> 9;
+	unsigned int chunk_sectors;
+	sector_t sector;
+	unsigned int bio_sectors;
 	int max;
 
+	chunk_sectors = 1 << (rbd_dev->header.obj_order - SECTOR_SHIFT);
+	sector = bmd->bi_sector + get_start_sect(bmd->bi_bdev);
+	bio_sectors = bmd->bi_size >> SECTOR_SHIFT;
+
 	max =  (chunk_sectors - ((sector & (chunk_sectors - 1))
-				 + bio_sectors)) << 9;
+				 + bio_sectors)) << SECTOR_SHIFT;
 	if (max < 0)
 		max = 0; /* bio_add cannot handle a negative return */
 	if (max <= bvec->bv_len && bio_sectors == 0)
@@ -1565,15 +1593,16 @@
 	ssize_t rc;
 	struct rbd_image_header_ondisk *dh;
 	int snap_count = 0;
-	u64 snap_names_len = 0;
 	u64 ver;
+	size_t len;
 
+	/*
+	 * First reads the fixed-size header to determine the number
+	 * of snapshots, then re-reads it, along with all snapshot
+	 * records as well as their stored names.
+	 */
+	len = sizeof (*dh);
 	while (1) {
-		int len = sizeof(*dh) +
-			  snap_count * sizeof(struct rbd_image_snap_ondisk) +
-			  snap_names_len;
-
-		rc = -ENOMEM;
 		dh = kmalloc(len, GFP_KERNEL);
 		if (!dh)
 			return -ENOMEM;
@@ -1588,21 +1617,22 @@
 
 		rc = rbd_header_from_disk(header, dh, snap_count, GFP_KERNEL);
 		if (rc < 0) {
-			if (rc == -ENXIO) {
+			if (rc == -ENXIO)
 				pr_warning("unrecognized header format"
 					   " for image %s", rbd_dev->obj);
-			}
 			goto out_dh;
 		}
 
-		if (snap_count != header->total_snaps) {
-			snap_count = header->total_snaps;
-			snap_names_len = header->snap_names_len;
-			rbd_header_free(header);
-			kfree(dh);
-			continue;
-		}
-		break;
+		if (snap_count == header->total_snaps)
+			break;
+
+		snap_count = header->total_snaps;
+		len = sizeof (*dh) +
+			snap_count * sizeof(struct rbd_image_snap_ondisk) +
+			header->snap_names_len;
+
+		rbd_header_free(header);
+		kfree(dh);
 	}
 	header->obj_version = ver;
 
@@ -1623,13 +1653,14 @@
 	int ret;
 	void *data, *p, *e;
 	u64 ver;
+	struct ceph_mon_client *monc;
 
 	/* we should create a snapshot only if we're pointing at the head */
 	if (dev->cur_snap)
 		return -EINVAL;
 
-	ret = ceph_monc_create_snapid(&dev->client->monc, dev->poolid,
-				      &new_snapid);
+	monc = &dev->rbd_client->client->monc;
+	ret = ceph_monc_create_snapid(monc, dev->poolid, &new_snapid);
 	dout("created snapid=%lld\n", new_snapid);
 	if (ret < 0)
 		return ret;
@@ -1684,9 +1715,9 @@
 		return ret;
 
 	/* resized? */
-	set_capacity(rbd_dev->disk, h.image_size / 512ULL);
+	set_capacity(rbd_dev->disk, h.image_size / SECTOR_SIZE);
 
-	down_write(&rbd_dev->header.snap_rwsem);
+	down_write(&rbd_dev->header_rwsem);
 
 	snap_seq = rbd_dev->header.snapc->seq;
 	if (rbd_dev->header.total_snaps &&
@@ -1711,7 +1742,7 @@
 
 	ret = __rbd_init_snaps_header(rbd_dev);
 
-	up_write(&rbd_dev->header.snap_rwsem);
+	up_write(&rbd_dev->header_rwsem);
 
 	return ret;
 }
@@ -1721,6 +1752,7 @@
 	struct gendisk *disk;
 	struct request_queue *q;
 	int rc;
+	u64 segment_size;
 	u64 total_size = 0;
 
 	/* contact OSD, request size info about the object being mapped */
@@ -1733,7 +1765,7 @@
 	if (rc)
 		return rc;
 
-	rc = rbd_header_set_snap(rbd_dev, rbd_dev->snap_name, &total_size);
+	rc = rbd_header_set_snap(rbd_dev, &total_size);
 	if (rc)
 		return rc;
 
@@ -1743,7 +1775,7 @@
 	if (!disk)
 		goto out;
 
-	snprintf(disk->disk_name, sizeof(disk->disk_name), DRV_NAME "%d",
+	snprintf(disk->disk_name, sizeof(disk->disk_name), RBD_DRV_NAME "%d",
 		 rbd_dev->id);
 	disk->major = rbd_dev->major;
 	disk->first_minor = 0;
@@ -1756,11 +1788,15 @@
 	if (!q)
 		goto out_disk;
 
+	/* We use the default size, but let's be explicit about it. */
+	blk_queue_physical_block_size(q, SECTOR_SIZE);
+
 	/* set io sizes to object size */
-	blk_queue_max_hw_sectors(q, rbd_obj_bytes(&rbd_dev->header) / 512ULL);
-	blk_queue_max_segment_size(q, rbd_obj_bytes(&rbd_dev->header));
-	blk_queue_io_min(q, rbd_obj_bytes(&rbd_dev->header));
-	blk_queue_io_opt(q, rbd_obj_bytes(&rbd_dev->header));
+	segment_size = rbd_obj_bytes(&rbd_dev->header);
+	blk_queue_max_hw_sectors(q, segment_size / SECTOR_SIZE);
+	blk_queue_max_segment_size(q, segment_size);
+	blk_queue_io_min(q, segment_size);
+	blk_queue_io_opt(q, segment_size);
 
 	blk_queue_merge_bvec(q, rbd_merge_bvec);
 	disk->queue = q;
@@ -1771,7 +1807,7 @@
 	rbd_dev->q = q;
 
 	/* finally, announce the disk to the world */
-	set_capacity(disk, total_size / 512ULL);
+	set_capacity(disk, total_size / SECTOR_SIZE);
 	add_disk(disk);
 
 	pr_info("%s: added with size 0x%llx\n",
@@ -1788,10 +1824,15 @@
   sysfs
 */
 
+static struct rbd_device *dev_to_rbd_dev(struct device *dev)
+{
+	return container_of(dev, struct rbd_device, dev);
+}
+
 static ssize_t rbd_size_show(struct device *dev,
 			     struct device_attribute *attr, char *buf)
 {
-	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+	struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
 	return sprintf(buf, "%llu\n", (unsigned long long)rbd_dev->header.image_size);
 }
@@ -1799,7 +1840,7 @@
 static ssize_t rbd_major_show(struct device *dev,
 			      struct device_attribute *attr, char *buf)
 {
-	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+	struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
 	return sprintf(buf, "%d\n", rbd_dev->major);
 }
@@ -1807,15 +1848,16 @@
 static ssize_t rbd_client_id_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
-	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+	struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
-	return sprintf(buf, "client%lld\n", ceph_client_id(rbd_dev->client));
+	return sprintf(buf, "client%lld\n",
+			ceph_client_id(rbd_dev->rbd_client->client));
 }
 
 static ssize_t rbd_pool_show(struct device *dev,
 			     struct device_attribute *attr, char *buf)
 {
-	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+	struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
 	return sprintf(buf, "%s\n", rbd_dev->pool_name);
 }
@@ -1823,7 +1865,7 @@
 static ssize_t rbd_name_show(struct device *dev,
 			     struct device_attribute *attr, char *buf)
 {
-	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+	struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
 	return sprintf(buf, "%s\n", rbd_dev->obj);
 }
@@ -1832,7 +1874,7 @@
 			     struct device_attribute *attr,
 			     char *buf)
 {
-	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+	struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
 	return sprintf(buf, "%s\n", rbd_dev->snap_name);
 }
@@ -1842,7 +1884,7 @@
 				 const char *buf,
 				 size_t size)
 {
-	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+	struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 	int rc;
 	int ret = size;
 
@@ -1907,7 +1949,7 @@
 {
 	struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev);
 
-	return sprintf(buf, "%lld\n", (long long)snap->size);
+	return sprintf(buf, "%zd\n", snap->size);
 }
 
 static ssize_t rbd_snap_id_show(struct device *dev,
@@ -1916,7 +1958,7 @@
 {
 	struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev);
 
-	return sprintf(buf, "%lld\n", (long long)snap->id);
+	return sprintf(buf, "%llu\n", (unsigned long long) snap->id);
 }
 
 static DEVICE_ATTR(snap_size, S_IRUGO, rbd_snap_size_show, NULL);
@@ -2088,19 +2130,9 @@
 	return 0;
 }
 
-
-static void rbd_root_dev_release(struct device *dev)
-{
-}
-
-static struct device rbd_root_dev = {
-	.init_name =    "rbd",
-	.release =      rbd_root_dev_release,
-};
-
 static int rbd_bus_add_dev(struct rbd_device *rbd_dev)
 {
-	int ret = -ENOMEM;
+	int ret;
 	struct device *dev;
 	struct rbd_snap *snap;
 
@@ -2114,7 +2146,7 @@
 	dev_set_name(dev, "%d", rbd_dev->id);
 	ret = device_register(dev);
 	if (ret < 0)
-		goto done_free;
+		goto out;
 
 	list_for_each_entry(snap, &rbd_dev->snaps, node) {
 		ret = rbd_register_snap_dev(rbd_dev, snap,
@@ -2122,10 +2154,7 @@
 		if (ret < 0)
 			break;
 	}
-
-	mutex_unlock(&ctl_mutex);
-	return 0;
-done_free:
+out:
 	mutex_unlock(&ctl_mutex);
 	return ret;
 }
@@ -2154,104 +2183,250 @@
 	return ret;
 }
 
+static atomic64_t rbd_id_max = ATOMIC64_INIT(0);
+
+/*
+ * Get a unique rbd identifier for the given new rbd_dev, and add
+ * the rbd_dev to the global list.  The minimum rbd id is 1.
+ */
+static void rbd_id_get(struct rbd_device *rbd_dev)
+{
+	rbd_dev->id = atomic64_inc_return(&rbd_id_max);
+
+	spin_lock(&rbd_dev_list_lock);
+	list_add_tail(&rbd_dev->node, &rbd_dev_list);
+	spin_unlock(&rbd_dev_list_lock);
+}
+
+/*
+ * Remove an rbd_dev from the global list, and record that its
+ * identifier is no longer in use.
+ */
+static void rbd_id_put(struct rbd_device *rbd_dev)
+{
+	struct list_head *tmp;
+	int rbd_id = rbd_dev->id;
+	int max_id;
+
+	BUG_ON(rbd_id < 1);
+
+	spin_lock(&rbd_dev_list_lock);
+	list_del_init(&rbd_dev->node);
+
+	/*
+	 * If the id being "put" is not the current maximum, there
+	 * is nothing special we need to do.
+	 */
+	if (rbd_id != atomic64_read(&rbd_id_max)) {
+		spin_unlock(&rbd_dev_list_lock);
+		return;
+	}
+
+	/*
+	 * We need to update the current maximum id.  Search the
+	 * list to find out what it is.  We're more likely to find
+	 * the maximum at the end, so search the list backward.
+	 */
+	max_id = 0;
+	list_for_each_prev(tmp, &rbd_dev_list) {
+		struct rbd_device *rbd_dev;
+
+		rbd_dev = list_entry(tmp, struct rbd_device, node);
+		if (rbd_id > max_id)
+			max_id = rbd_id;
+	}
+	spin_unlock(&rbd_dev_list_lock);
+
+	/*
+	 * The max id could have been updated by rbd_id_get(), in
+	 * which case it now accurately reflects the new maximum.
+	 * Be careful not to overwrite the maximum value in that
+	 * case.
+	 */
+	atomic64_cmpxchg(&rbd_id_max, rbd_id, max_id);
+}
+
+/*
+ * Skips over white space at *buf, and updates *buf to point to the
+ * first found non-space character (if any). Returns the length of
+ * the token (string of non-white space characters) found.  Note
+ * that *buf must be terminated with '\0'.
+ */
+static inline size_t next_token(const char **buf)
+{
+        /*
+        * These are the characters that produce nonzero for
+        * isspace() in the "C" and "POSIX" locales.
+        */
+        const char *spaces = " \f\n\r\t\v";
+
+        *buf += strspn(*buf, spaces);	/* Find start of token */
+
+	return strcspn(*buf, spaces);   /* Return token length */
+}
+
+/*
+ * Finds the next token in *buf, and if the provided token buffer is
+ * big enough, copies the found token into it.  The result, if
+ * copied, is guaranteed to be terminated with '\0'.  Note that *buf
+ * must be terminated with '\0' on entry.
+ *
+ * Returns the length of the token found (not including the '\0').
+ * Return value will be 0 if no token is found, and it will be >=
+ * token_size if the token would not fit.
+ *
+ * The *buf pointer will be updated to point beyond the end of the
+ * found token.  Note that this occurs even if the token buffer is
+ * too small to hold it.
+ */
+static inline size_t copy_token(const char **buf,
+				char *token,
+				size_t token_size)
+{
+        size_t len;
+
+	len = next_token(buf);
+	if (len < token_size) {
+		memcpy(token, *buf, len);
+		*(token + len) = '\0';
+	}
+	*buf += len;
+
+        return len;
+}
+
+/*
+ * This fills in the pool_name, obj, obj_len, snap_name, obj_len,
+ * rbd_dev, rbd_md_name, and name fields of the given rbd_dev, based
+ * on the list of monitor addresses and other options provided via
+ * /sys/bus/rbd/add.
+ */
+static int rbd_add_parse_args(struct rbd_device *rbd_dev,
+			      const char *buf,
+			      const char **mon_addrs,
+			      size_t *mon_addrs_size,
+			      char *options,
+			      size_t options_size)
+{
+	size_t	len;
+
+	/* The first four tokens are required */
+
+	len = next_token(&buf);
+	if (!len)
+		return -EINVAL;
+	*mon_addrs_size = len + 1;
+	*mon_addrs = buf;
+
+	buf += len;
+
+	len = copy_token(&buf, options, options_size);
+	if (!len || len >= options_size)
+		return -EINVAL;
+
+	len = copy_token(&buf, rbd_dev->pool_name, sizeof (rbd_dev->pool_name));
+	if (!len || len >= sizeof (rbd_dev->pool_name))
+		return -EINVAL;
+
+	len = copy_token(&buf, rbd_dev->obj, sizeof (rbd_dev->obj));
+	if (!len || len >= sizeof (rbd_dev->obj))
+		return -EINVAL;
+
+	/* We have the object length in hand, save it. */
+
+	rbd_dev->obj_len = len;
+
+	BUILD_BUG_ON(RBD_MAX_MD_NAME_LEN
+				< RBD_MAX_OBJ_NAME_LEN + sizeof (RBD_SUFFIX));
+	sprintf(rbd_dev->obj_md_name, "%s%s", rbd_dev->obj, RBD_SUFFIX);
+
+	/*
+	 * The snapshot name is optional, but it's an error if it's
+	 * too long.  If no snapshot is supplied, fill in the default.
+	 */
+	len = copy_token(&buf, rbd_dev->snap_name, sizeof (rbd_dev->snap_name));
+	if (!len)
+		memcpy(rbd_dev->snap_name, RBD_SNAP_HEAD_NAME,
+			sizeof (RBD_SNAP_HEAD_NAME));
+	else if (len >= sizeof (rbd_dev->snap_name))
+		return -EINVAL;
+
+	return 0;
+}
+
 static ssize_t rbd_add(struct bus_type *bus,
 		       const char *buf,
 		       size_t count)
 {
-	struct ceph_osd_client *osdc;
 	struct rbd_device *rbd_dev;
-	ssize_t rc = -ENOMEM;
-	int irc, new_id = 0;
-	struct list_head *tmp;
-	char *mon_dev_name;
-	char *options;
+	const char *mon_addrs = NULL;
+	size_t mon_addrs_size = 0;
+	char *options = NULL;
+	struct ceph_osd_client *osdc;
+	int rc = -ENOMEM;
 
 	if (!try_module_get(THIS_MODULE))
 		return -ENODEV;
 
-	mon_dev_name = kmalloc(RBD_MAX_OPT_LEN, GFP_KERNEL);
-	if (!mon_dev_name)
-		goto err_out_mod;
-
-	options = kmalloc(RBD_MAX_OPT_LEN, GFP_KERNEL);
-	if (!options)
-		goto err_mon_dev;
-
-	/* new rbd_device object */
 	rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL);
 	if (!rbd_dev)
-		goto err_out_opt;
+		goto err_nomem;
+	options = kmalloc(count, GFP_KERNEL);
+	if (!options)
+		goto err_nomem;
 
 	/* static rbd_device initialization */
 	spin_lock_init(&rbd_dev->lock);
 	INIT_LIST_HEAD(&rbd_dev->node);
 	INIT_LIST_HEAD(&rbd_dev->snaps);
+	init_rwsem(&rbd_dev->header_rwsem);
 
-	init_rwsem(&rbd_dev->header.snap_rwsem);
+	init_rwsem(&rbd_dev->header_rwsem);
 
 	/* generate unique id: find highest unique id, add one */
-	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+	rbd_id_get(rbd_dev);
 
-	list_for_each(tmp, &rbd_dev_list) {
-		struct rbd_device *rbd_dev;
-
-		rbd_dev = list_entry(tmp, struct rbd_device, node);
-		if (rbd_dev->id >= new_id)
-			new_id = rbd_dev->id + 1;
-	}
-
-	rbd_dev->id = new_id;
-
-	/* add to global list */
-	list_add_tail(&rbd_dev->node, &rbd_dev_list);
+	/* Fill in the device name, now that we have its id. */
+	BUILD_BUG_ON(DEV_NAME_LEN
+			< sizeof (RBD_DRV_NAME) + MAX_INT_FORMAT_WIDTH);
+	sprintf(rbd_dev->name, "%s%d", RBD_DRV_NAME, rbd_dev->id);
 
 	/* parse add command */
-	if (sscanf(buf, "%" __stringify(RBD_MAX_OPT_LEN) "s "
-		   "%" __stringify(RBD_MAX_OPT_LEN) "s "
-		   "%" __stringify(RBD_MAX_POOL_NAME_LEN) "s "
-		   "%" __stringify(RBD_MAX_OBJ_NAME_LEN) "s"
-		   "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s",
-		   mon_dev_name, options, rbd_dev->pool_name,
-		   rbd_dev->obj, rbd_dev->snap_name) < 4) {
-		rc = -EINVAL;
-		goto err_out_slot;
+	rc = rbd_add_parse_args(rbd_dev, buf, &mon_addrs, &mon_addrs_size,
+				options, count);
+	if (rc)
+		goto err_put_id;
+
+	rbd_dev->rbd_client = rbd_get_client(mon_addrs, mon_addrs_size - 1,
+						options);
+	if (IS_ERR(rbd_dev->rbd_client)) {
+		rc = PTR_ERR(rbd_dev->rbd_client);
+		goto err_put_id;
 	}
 
-	if (rbd_dev->snap_name[0] == 0)
-		rbd_dev->snap_name[0] = '-';
-
-	rbd_dev->obj_len = strlen(rbd_dev->obj);
-	snprintf(rbd_dev->obj_md_name, sizeof(rbd_dev->obj_md_name), "%s%s",
-		 rbd_dev->obj, RBD_SUFFIX);
-
-	/* initialize rest of new object */
-	snprintf(rbd_dev->name, DEV_NAME_LEN, DRV_NAME "%d", rbd_dev->id);
-	rc = rbd_get_client(rbd_dev, mon_dev_name, options);
-	if (rc < 0)
-		goto err_out_slot;
-
-	mutex_unlock(&ctl_mutex);
-
 	/* pick the pool */
-	osdc = &rbd_dev->client->osdc;
+	osdc = &rbd_dev->rbd_client->client->osdc;
 	rc = ceph_pg_poolid_by_name(osdc->osdmap, rbd_dev->pool_name);
 	if (rc < 0)
 		goto err_out_client;
 	rbd_dev->poolid = rc;
 
 	/* register our block device */
-	irc = register_blkdev(0, rbd_dev->name);
-	if (irc < 0) {
-		rc = irc;
+	rc = register_blkdev(0, rbd_dev->name);
+	if (rc < 0)
 		goto err_out_client;
-	}
-	rbd_dev->major = irc;
+	rbd_dev->major = rc;
 
 	rc = rbd_bus_add_dev(rbd_dev);
 	if (rc)
 		goto err_out_blkdev;
 
-	/* set up and announce blkdev mapping */
+	/*
+	 * At this point cleanup in the event of an error is the job
+	 * of the sysfs code (initiated by rbd_bus_del_dev()).
+	 *
+	 * Set up and announce blkdev mapping.
+	 */
 	rc = rbd_init_disk(rbd_dev);
 	if (rc)
 		goto err_out_bus;
@@ -2263,35 +2438,26 @@
 	return count;
 
 err_out_bus:
-	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-	list_del_init(&rbd_dev->node);
-	mutex_unlock(&ctl_mutex);
-
 	/* this will also clean up rest of rbd_dev stuff */
 
 	rbd_bus_del_dev(rbd_dev);
 	kfree(options);
-	kfree(mon_dev_name);
 	return rc;
 
 err_out_blkdev:
 	unregister_blkdev(rbd_dev->major, rbd_dev->name);
 err_out_client:
 	rbd_put_client(rbd_dev);
-	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-err_out_slot:
-	list_del_init(&rbd_dev->node);
-	mutex_unlock(&ctl_mutex);
-
-	kfree(rbd_dev);
-err_out_opt:
+err_put_id:
+	rbd_id_put(rbd_dev);
+err_nomem:
 	kfree(options);
-err_mon_dev:
-	kfree(mon_dev_name);
-err_out_mod:
+	kfree(rbd_dev);
+
 	dout("Error adding device %s\n", buf);
 	module_put(THIS_MODULE);
-	return rc;
+
+	return (ssize_t) rc;
 }
 
 static struct rbd_device *__rbd_get_dev(unsigned long id)
@@ -2299,22 +2465,28 @@
 	struct list_head *tmp;
 	struct rbd_device *rbd_dev;
 
+	spin_lock(&rbd_dev_list_lock);
 	list_for_each(tmp, &rbd_dev_list) {
 		rbd_dev = list_entry(tmp, struct rbd_device, node);
-		if (rbd_dev->id == id)
+		if (rbd_dev->id == id) {
+			spin_unlock(&rbd_dev_list_lock);
 			return rbd_dev;
+		}
 	}
+	spin_unlock(&rbd_dev_list_lock);
 	return NULL;
 }
 
 static void rbd_dev_release(struct device *dev)
 {
-	struct rbd_device *rbd_dev =
-			container_of(dev, struct rbd_device, dev);
+	struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
-	if (rbd_dev->watch_request)
-		ceph_osdc_unregister_linger_request(&rbd_dev->client->osdc,
+	if (rbd_dev->watch_request) {
+		struct ceph_client *client = rbd_dev->rbd_client->client;
+
+		ceph_osdc_unregister_linger_request(&client->osdc,
 						    rbd_dev->watch_request);
+	}
 	if (rbd_dev->watch_event)
 		rbd_req_sync_unwatch(rbd_dev, rbd_dev->obj_md_name);
 
@@ -2323,6 +2495,9 @@
 	/* clean up and free blkdev */
 	rbd_free_disk(rbd_dev);
 	unregister_blkdev(rbd_dev->major, rbd_dev->name);
+
+	/* done with the id, and with the rbd_dev */
+	rbd_id_put(rbd_dev);
 	kfree(rbd_dev);
 
 	/* release module ref */
@@ -2355,8 +2530,6 @@
 		goto done;
 	}
 
-	list_del_init(&rbd_dev->node);
-
 	__rbd_remove_all_snaps(rbd_dev);
 	rbd_bus_del_dev(rbd_dev);
 
@@ -2370,7 +2543,7 @@
 			    const char *buf,
 			    size_t count)
 {
-	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+	struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 	int ret;
 	char *name = kmalloc(count + 1, GFP_KERNEL);
 	if (!name)
@@ -2406,12 +2579,6 @@
 	return ret;
 }
 
-static struct bus_attribute rbd_bus_attrs[] = {
-	__ATTR(add, S_IWUSR, NULL, rbd_add),
-	__ATTR(remove, S_IWUSR, NULL, rbd_remove),
-	__ATTR_NULL
-};
-
 /*
  * create control files in sysfs
  * /sys/bus/rbd/...
@@ -2420,21 +2587,21 @@
 {
 	int ret;
 
-	rbd_bus_type.bus_attrs = rbd_bus_attrs;
-
-	ret = bus_register(&rbd_bus_type);
-	 if (ret < 0)
+	ret = device_register(&rbd_root_dev);
+	if (ret < 0)
 		return ret;
 
-	ret = device_register(&rbd_root_dev);
+	ret = bus_register(&rbd_bus_type);
+	if (ret < 0)
+		device_unregister(&rbd_root_dev);
 
 	return ret;
 }
 
 static void rbd_sysfs_cleanup(void)
 {
-	device_unregister(&rbd_root_dev);
 	bus_unregister(&rbd_bus_type);
+	device_unregister(&rbd_root_dev);
 }
 
 int __init rbd_init(void)
@@ -2444,8 +2611,7 @@
 	rc = rbd_sysfs_init();
 	if (rc)
 		return rc;
-	spin_lock_init(&node_lock);
-	pr_info("loaded " DRV_NAME_LONG "\n");
+	pr_info("loaded " RBD_DRV_NAME_LONG "\n");
 	return 0;
 }
 
diff --git a/drivers/block/rbd_types.h b/drivers/block/rbd_types.h
index fc6c678..9507086 100644
--- a/drivers/block/rbd_types.h
+++ b/drivers/block/rbd_types.h
@@ -41,10 +41,6 @@
 #define RBD_HEADER_SIGNATURE	"RBD"
 #define RBD_HEADER_VERSION	"001.005"
 
-struct rbd_info {
-	__le64 max_id;
-} __attribute__ ((packed));
-
 struct rbd_image_snap_ondisk {
 	__le64 id;
 	__le64 image_size;
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 48e8fee..9dcf76a 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -839,10 +839,7 @@
 	.id_table	= vdc_port_match,
 	.probe		= vdc_port_probe,
 	.remove		= vdc_port_remove,
-	.driver		= {
-		.name	= "vdc_port",
-		.owner	= THIS_MODULE,
-	}
+	.name		= "vdc_port",
 };
 
 static int __init vdc_init(void)
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
deleted file mode 100644
index 9a5b2a2..0000000
--- a/drivers/block/viodasd.c
+++ /dev/null
@@ -1,809 +0,0 @@
-/* -*- linux-c -*-
- * viodasd.c
- *  Authors: Dave Boutcher <boutcher@us.ibm.com>
- *           Ryan Arnold <ryanarn@us.ibm.com>
- *           Colin Devilbiss <devilbis@us.ibm.com>
- *           Stephen Rothwell
- *
- * (C) Copyright 2000-2004 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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
- *
- * This routine provides access to disk space (termed "DASD" in historical
- * IBM terms) owned and managed by an OS/400 partition running on the
- * same box as this Linux partition.
- *
- * All disk operations are performed by sending messages back and forth to
- * the OS/400 partition.
- */
-
-#define pr_fmt(fmt) "viod: " fmt
-
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/blkdev.h>
-#include <linux/genhd.h>
-#include <linux/hdreg.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/mutex.h>
-#include <linux/dma-mapping.h>
-#include <linux/completion.h>
-#include <linux/device.h>
-#include <linux/scatterlist.h>
-
-#include <asm/uaccess.h>
-#include <asm/vio.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/vio.h>
-#include <asm/firmware.h>
-
-MODULE_DESCRIPTION("iSeries Virtual DASD");
-MODULE_AUTHOR("Dave Boutcher");
-MODULE_LICENSE("GPL");
-
-/*
- * We only support 7 partitions per physical disk....so with minor
- * numbers 0-255 we get a maximum of 32 disks.
- */
-#define VIOD_GENHD_NAME		"iseries/vd"
-
-#define VIOD_VERS		"1.64"
-
-enum {
-	PARTITION_SHIFT = 3,
-	MAX_DISKNO = HVMAXARCHITECTEDVIRTUALDISKS,
-	MAX_DISK_NAME = FIELD_SIZEOF(struct gendisk, disk_name)
-};
-
-static DEFINE_MUTEX(viodasd_mutex);
-static DEFINE_SPINLOCK(viodasd_spinlock);
-
-#define VIOMAXREQ		16
-
-#define DEVICE_NO(cell)	((struct viodasd_device *)(cell) - &viodasd_devices[0])
-
-struct viodasd_waitevent {
-	struct completion	com;
-	int			rc;
-	u16			sub_result;
-	int			max_disk;	/* open */
-};
-
-static const struct vio_error_entry viodasd_err_table[] = {
-	{ 0x0201, EINVAL, "Invalid Range" },
-	{ 0x0202, EINVAL, "Invalid Token" },
-	{ 0x0203, EIO, "DMA Error" },
-	{ 0x0204, EIO, "Use Error" },
-	{ 0x0205, EIO, "Release Error" },
-	{ 0x0206, EINVAL, "Invalid Disk" },
-	{ 0x0207, EBUSY, "Can't Lock" },
-	{ 0x0208, EIO, "Already Locked" },
-	{ 0x0209, EIO, "Already Unlocked" },
-	{ 0x020A, EIO, "Invalid Arg" },
-	{ 0x020B, EIO, "Bad IFS File" },
-	{ 0x020C, EROFS, "Read Only Device" },
-	{ 0x02FF, EIO, "Internal Error" },
-	{ 0x0000, 0, NULL },
-};
-
-/*
- * Figure out the biggest I/O request (in sectors) we can accept
- */
-#define VIODASD_MAXSECTORS (4096 / 512 * VIOMAXBLOCKDMA)
-
-/*
- * Number of disk I/O requests we've sent to OS/400
- */
-static int num_req_outstanding;
-
-/*
- * This is our internal structure for keeping track of disk devices
- */
-struct viodasd_device {
-	u16		cylinders;
-	u16		tracks;
-	u16		sectors;
-	u16		bytes_per_sector;
-	u64		size;
-	int		read_only;
-	spinlock_t	q_lock;
-	struct gendisk	*disk;
-	struct device	*dev;
-} viodasd_devices[MAX_DISKNO];
-
-/*
- * External open entry point.
- */
-static int viodasd_open(struct block_device *bdev, fmode_t mode)
-{
-	struct viodasd_device *d = bdev->bd_disk->private_data;
-	HvLpEvent_Rc hvrc;
-	struct viodasd_waitevent we;
-	u16 flags = 0;
-
-	if (d->read_only) {
-		if (mode & FMODE_WRITE)
-			return -EROFS;
-		flags = vioblockflags_ro;
-	}
-
-	init_completion(&we.com);
-
-	/* Send the open event to OS/400 */
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_blockio | vioblockopen,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64)(unsigned long)&we, VIOVERSION << 16,
-			((u64)DEVICE_NO(d) << 48) | ((u64)flags << 32),
-			0, 0, 0);
-	if (hvrc != 0) {
-		pr_warning("HV open failed %d\n", (int)hvrc);
-		return -EIO;
-	}
-
-	wait_for_completion(&we.com);
-
-	/* Check the return code */
-	if (we.rc != 0) {
-		const struct vio_error_entry *err =
-			vio_lookup_rc(viodasd_err_table, we.sub_result);
-
-		pr_warning("bad rc opening disk: %d:0x%04x (%s)\n",
-			   (int)we.rc, we.sub_result, err->msg);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int viodasd_unlocked_open(struct block_device *bdev, fmode_t mode)
-{
-	int ret;
-
-	mutex_lock(&viodasd_mutex);
-	ret = viodasd_open(bdev, mode);
-	mutex_unlock(&viodasd_mutex);
-
-	return ret;
-}
-
-
-/*
- * External release entry point.
- */
-static int viodasd_release(struct gendisk *disk, fmode_t mode)
-{
-	struct viodasd_device *d = disk->private_data;
-	HvLpEvent_Rc hvrc;
-
-	mutex_lock(&viodasd_mutex);
-	/* Send the event to OS/400.  We DON'T expect a response */
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_blockio | vioblockclose,
-			HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			0, VIOVERSION << 16,
-			((u64)DEVICE_NO(d) << 48) /* | ((u64)flags << 32) */,
-			0, 0, 0);
-	if (hvrc != 0)
-		pr_warning("HV close call failed %d\n", (int)hvrc);
-
-	mutex_unlock(&viodasd_mutex);
-
-	return 0;
-}
-
-
-/* External ioctl entry point.
- */
-static int viodasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
-	struct gendisk *disk = bdev->bd_disk;
-	struct viodasd_device *d = disk->private_data;
-
-	geo->sectors = d->sectors ? d->sectors : 32;
-	geo->heads = d->tracks ? d->tracks  : 64;
-	geo->cylinders = d->cylinders ? d->cylinders :
-		get_capacity(disk) / (geo->sectors * geo->heads);
-
-	return 0;
-}
-
-/*
- * Our file operations table
- */
-static const struct block_device_operations viodasd_fops = {
-	.owner = THIS_MODULE,
-	.open = viodasd_unlocked_open,
-	.release = viodasd_release,
-	.getgeo = viodasd_getgeo,
-};
-
-/*
- * End a request
- */
-static void viodasd_end_request(struct request *req, int error,
-		int num_sectors)
-{
-	__blk_end_request(req, error, num_sectors << 9);
-}
-
-/*
- * Send an actual I/O request to OS/400
- */
-static int send_request(struct request *req)
-{
-	u64 start;
-	int direction;
-	int nsg;
-	u16 viocmd;
-	HvLpEvent_Rc hvrc;
-	struct vioblocklpevent *bevent;
-	struct HvLpEvent *hev;
-	struct scatterlist sg[VIOMAXBLOCKDMA];
-	int sgindex;
-	struct viodasd_device *d;
-	unsigned long flags;
-
-	start = (u64)blk_rq_pos(req) << 9;
-
-	if (rq_data_dir(req) == READ) {
-		direction = DMA_FROM_DEVICE;
-		viocmd = viomajorsubtype_blockio | vioblockread;
-	} else {
-		direction = DMA_TO_DEVICE;
-		viocmd = viomajorsubtype_blockio | vioblockwrite;
-	}
-
-        d = req->rq_disk->private_data;
-
-	/* Now build the scatter-gather list */
-	sg_init_table(sg, VIOMAXBLOCKDMA);
-	nsg = blk_rq_map_sg(req->q, req, sg);
-	nsg = dma_map_sg(d->dev, sg, nsg, direction);
-
-	spin_lock_irqsave(&viodasd_spinlock, flags);
-	num_req_outstanding++;
-
-	/* This optimization handles a single DMA block */
-	if (nsg == 1)
-		hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-				HvLpEvent_Type_VirtualIo, viocmd,
-				HvLpEvent_AckInd_DoAck,
-				HvLpEvent_AckType_ImmediateAck,
-				viopath_sourceinst(viopath_hostLp),
-				viopath_targetinst(viopath_hostLp),
-				(u64)(unsigned long)req, VIOVERSION << 16,
-				((u64)DEVICE_NO(d) << 48), start,
-				((u64)sg_dma_address(&sg[0])) << 32,
-				sg_dma_len(&sg[0]));
-	else {
-		bevent = (struct vioblocklpevent *)
-			vio_get_event_buffer(viomajorsubtype_blockio);
-		if (bevent == NULL) {
-			pr_warning("error allocating disk event buffer\n");
-			goto error_ret;
-		}
-
-		/*
-		 * Now build up the actual request.  Note that we store
-		 * the pointer to the request in the correlation
-		 * token so we can match the response up later
-		 */
-		memset(bevent, 0, sizeof(struct vioblocklpevent));
-		hev = &bevent->event;
-		hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK |
-			HV_LP_EVENT_INT;
-		hev->xType = HvLpEvent_Type_VirtualIo;
-		hev->xSubtype = viocmd;
-		hev->xSourceLp = HvLpConfig_getLpIndex();
-		hev->xTargetLp = viopath_hostLp;
-		hev->xSizeMinus1 =
-			offsetof(struct vioblocklpevent, u.rw_data.dma_info) +
-			(sizeof(bevent->u.rw_data.dma_info[0]) * nsg) - 1;
-		hev->xSourceInstanceId = viopath_sourceinst(viopath_hostLp);
-		hev->xTargetInstanceId = viopath_targetinst(viopath_hostLp);
-		hev->xCorrelationToken = (u64)req;
-		bevent->version = VIOVERSION;
-		bevent->disk = DEVICE_NO(d);
-		bevent->u.rw_data.offset = start;
-
-		/*
-		 * Copy just the dma information from the sg list
-		 * into the request
-		 */
-		for (sgindex = 0; sgindex < nsg; sgindex++) {
-			bevent->u.rw_data.dma_info[sgindex].token =
-				sg_dma_address(&sg[sgindex]);
-			bevent->u.rw_data.dma_info[sgindex].len =
-				sg_dma_len(&sg[sgindex]);
-		}
-
-		/* Send the request */
-		hvrc = HvCallEvent_signalLpEvent(&bevent->event);
-		vio_free_event_buffer(viomajorsubtype_blockio, bevent);
-	}
-
-	if (hvrc != HvLpEvent_Rc_Good) {
-		pr_warning("error sending disk event to OS/400 (rc %d)\n",
-			   (int)hvrc);
-		goto error_ret;
-	}
-	spin_unlock_irqrestore(&viodasd_spinlock, flags);
-	return 0;
-
-error_ret:
-	num_req_outstanding--;
-	spin_unlock_irqrestore(&viodasd_spinlock, flags);
-	dma_unmap_sg(d->dev, sg, nsg, direction);
-	return -1;
-}
-
-/*
- * This is the external request processing routine
- */
-static void do_viodasd_request(struct request_queue *q)
-{
-	struct request *req;
-
-	/*
-	 * If we already have the maximum number of requests
-	 * outstanding to OS/400 just bail out. We'll come
-	 * back later.
-	 */
-	while (num_req_outstanding < VIOMAXREQ) {
-		req = blk_fetch_request(q);
-		if (req == NULL)
-			return;
-		/* check that request contains a valid command */
-		if (req->cmd_type != REQ_TYPE_FS) {
-			viodasd_end_request(req, -EIO, blk_rq_sectors(req));
-			continue;
-		}
-		/* Try sending the request */
-		if (send_request(req) != 0)
-			viodasd_end_request(req, -EIO, blk_rq_sectors(req));
-	}
-}
-
-/*
- * Probe a single disk and fill in the viodasd_device structure
- * for it.
- */
-static int probe_disk(struct viodasd_device *d)
-{
-	HvLpEvent_Rc hvrc;
-	struct viodasd_waitevent we;
-	int dev_no = DEVICE_NO(d);
-	struct gendisk *g;
-	struct request_queue *q;
-	u16 flags = 0;
-
-retry:
-	init_completion(&we.com);
-
-	/* Send the open event to OS/400 */
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_blockio | vioblockopen,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64)(unsigned long)&we, VIOVERSION << 16,
-			((u64)dev_no << 48) | ((u64)flags<< 32),
-			0, 0, 0);
-	if (hvrc != 0) {
-		pr_warning("bad rc on HV open %d\n", (int)hvrc);
-		return 0;
-	}
-
-	wait_for_completion(&we.com);
-
-	if (we.rc != 0) {
-		if (flags != 0)
-			return 0;
-		/* try again with read only flag set */
-		flags = vioblockflags_ro;
-		goto retry;
-	}
-	if (we.max_disk > (MAX_DISKNO - 1)) {
-		printk_once(KERN_INFO pr_fmt("Only examining the first %d of %d disks connected\n"),
-			    MAX_DISKNO, we.max_disk + 1);
-	}
-
-	/* Send the close event to OS/400.  We DON'T expect a response */
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_blockio | vioblockclose,
-			HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			0, VIOVERSION << 16,
-			((u64)dev_no << 48) | ((u64)flags << 32),
-			0, 0, 0);
-	if (hvrc != 0) {
-		pr_warning("bad rc sending event to OS/400 %d\n", (int)hvrc);
-		return 0;
-	}
-
-	if (d->dev == NULL) {
-		/* this is when we reprobe for new disks */
-		if (vio_create_viodasd(dev_no) == NULL) {
-			pr_warning("cannot allocate virtual device for disk %d\n",
-				   dev_no);
-			return 0;
-		}
-		/*
-		 * The vio_create_viodasd will have recursed into this
-		 * routine with d->dev set to the new vio device and
-		 * will finish the setup of the disk below.
-		 */
-		return 1;
-	}
-
-	/* create the request queue for the disk */
-	spin_lock_init(&d->q_lock);
-	q = blk_init_queue(do_viodasd_request, &d->q_lock);
-	if (q == NULL) {
-		pr_warning("cannot allocate queue for disk %d\n", dev_no);
-		return 0;
-	}
-	g = alloc_disk(1 << PARTITION_SHIFT);
-	if (g == NULL) {
-		pr_warning("cannot allocate disk structure for disk %d\n",
-			   dev_no);
-		blk_cleanup_queue(q);
-		return 0;
-	}
-
-	d->disk = g;
-	blk_queue_max_segments(q, VIOMAXBLOCKDMA);
-	blk_queue_max_hw_sectors(q, VIODASD_MAXSECTORS);
-	g->major = VIODASD_MAJOR;
-	g->first_minor = dev_no << PARTITION_SHIFT;
-	if (dev_no >= 26)
-		snprintf(g->disk_name, sizeof(g->disk_name),
-				VIOD_GENHD_NAME "%c%c",
-				'a' + (dev_no / 26) - 1, 'a' + (dev_no % 26));
-	else
-		snprintf(g->disk_name, sizeof(g->disk_name),
-				VIOD_GENHD_NAME "%c", 'a' + (dev_no % 26));
-	g->fops = &viodasd_fops;
-	g->queue = q;
-	g->private_data = d;
-	g->driverfs_dev = d->dev;
-	set_capacity(g, d->size >> 9);
-
-	pr_info("disk %d: %lu sectors (%lu MB) CHS=%d/%d/%d sector size %d%s\n",
-		dev_no, (unsigned long)(d->size >> 9),
-		(unsigned long)(d->size >> 20),
-		(int)d->cylinders, (int)d->tracks,
-		(int)d->sectors, (int)d->bytes_per_sector,
-		d->read_only ? " (RO)" : "");
-
-	/* register us in the global list */
-	add_disk(g);
-	return 1;
-}
-
-/* returns the total number of scatterlist elements converted */
-static int block_event_to_scatterlist(const struct vioblocklpevent *bevent,
-		struct scatterlist *sg, int *total_len)
-{
-	int i, numsg;
-	const struct rw_data *rw_data = &bevent->u.rw_data;
-	static const int offset =
-		offsetof(struct vioblocklpevent, u.rw_data.dma_info);
-	static const int element_size = sizeof(rw_data->dma_info[0]);
-
-	numsg = ((bevent->event.xSizeMinus1 + 1) - offset) / element_size;
-	if (numsg > VIOMAXBLOCKDMA)
-		numsg = VIOMAXBLOCKDMA;
-
-	*total_len = 0;
-	sg_init_table(sg, VIOMAXBLOCKDMA);
-	for (i = 0; (i < numsg) && (rw_data->dma_info[i].len > 0); ++i) {
-		sg_dma_address(&sg[i]) = rw_data->dma_info[i].token;
-		sg_dma_len(&sg[i]) = rw_data->dma_info[i].len;
-		*total_len += rw_data->dma_info[i].len;
-	}
-	return i;
-}
-
-/*
- * Restart all queues, starting with the one _after_ the disk given,
- * thus reducing the chance of starvation of higher numbered disks.
- */
-static void viodasd_restart_all_queues_starting_from(int first_index)
-{
-	int i;
-
-	for (i = first_index + 1; i < MAX_DISKNO; ++i)
-		if (viodasd_devices[i].disk)
-			blk_run_queue(viodasd_devices[i].disk->queue);
-	for (i = 0; i <= first_index; ++i)
-		if (viodasd_devices[i].disk)
-			blk_run_queue(viodasd_devices[i].disk->queue);
-}
-
-/*
- * For read and write requests, decrement the number of outstanding requests,
- * Free the DMA buffers we allocated.
- */
-static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
-{
-	int num_sg, num_sect, pci_direction, total_len;
-	struct request *req;
-	struct scatterlist sg[VIOMAXBLOCKDMA];
-	struct HvLpEvent *event = &bevent->event;
-	unsigned long irq_flags;
-	struct viodasd_device *d;
-	int error;
-	spinlock_t *qlock;
-
-	num_sg = block_event_to_scatterlist(bevent, sg, &total_len);
-	num_sect = total_len >> 9;
-	if (event->xSubtype == (viomajorsubtype_blockio | vioblockread))
-		pci_direction = DMA_FROM_DEVICE;
-	else
-		pci_direction = DMA_TO_DEVICE;
-	req = (struct request *)bevent->event.xCorrelationToken;
-	d = req->rq_disk->private_data;
-
-	dma_unmap_sg(d->dev, sg, num_sg, pci_direction);
-
-	/*
-	 * Since this is running in interrupt mode, we need to make sure
-	 * we're not stepping on any global I/O operations
-	 */
-	spin_lock_irqsave(&viodasd_spinlock, irq_flags);
-	num_req_outstanding--;
-	spin_unlock_irqrestore(&viodasd_spinlock, irq_flags);
-
-	error = (event->xRc == HvLpEvent_Rc_Good) ? 0 : -EIO;
-	if (error) {
-		const struct vio_error_entry *err;
-		err = vio_lookup_rc(viodasd_err_table, bevent->sub_result);
-		pr_warning("read/write error %d:0x%04x (%s)\n",
-			   event->xRc, bevent->sub_result, err->msg);
-		num_sect = blk_rq_sectors(req);
-	}
-	qlock = req->q->queue_lock;
-	spin_lock_irqsave(qlock, irq_flags);
-	viodasd_end_request(req, error, num_sect);
-	spin_unlock_irqrestore(qlock, irq_flags);
-
-	/* Finally, try to get more requests off of this device's queue */
-	viodasd_restart_all_queues_starting_from(DEVICE_NO(d));
-
-	return 0;
-}
-
-/* This routine handles incoming block LP events */
-static void handle_block_event(struct HvLpEvent *event)
-{
-	struct vioblocklpevent *bevent = (struct vioblocklpevent *)event;
-	struct viodasd_waitevent *pwe;
-
-	if (event == NULL)
-		/* Notification that a partition went away! */
-		return;
-	/* First, we should NEVER get an int here...only acks */
-	if (hvlpevent_is_int(event)) {
-		pr_warning("Yikes! got an int in viodasd event handler!\n");
-		if (hvlpevent_need_ack(event)) {
-			event->xRc = HvLpEvent_Rc_InvalidSubtype;
-			HvCallEvent_ackLpEvent(event);
-		}
-	}
-
-	switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
-	case vioblockopen:
-		/*
-		 * Handle a response to an open request.  We get all the
-		 * disk information in the response, so update it.  The
-		 * correlation token contains a pointer to a waitevent
-		 * structure that has a completion in it.  update the
-		 * return code in the waitevent structure and post the
-		 * completion to wake up the guy who sent the request
-		 */
-		pwe = (struct viodasd_waitevent *)event->xCorrelationToken;
-		pwe->rc = event->xRc;
-		pwe->sub_result = bevent->sub_result;
-		if (event->xRc == HvLpEvent_Rc_Good) {
-			const struct open_data *data = &bevent->u.open_data;
-			struct viodasd_device *device =
-				&viodasd_devices[bevent->disk];
-			device->read_only =
-				bevent->flags & vioblockflags_ro;
-			device->size = data->disk_size;
-			device->cylinders = data->cylinders;
-			device->tracks = data->tracks;
-			device->sectors = data->sectors;
-			device->bytes_per_sector = data->bytes_per_sector;
-			pwe->max_disk = data->max_disk;
-		}
-		complete(&pwe->com);
-		break;
-	case vioblockclose:
-		break;
-	case vioblockread:
-	case vioblockwrite:
-		viodasd_handle_read_write(bevent);
-		break;
-
-	default:
-		pr_warning("invalid subtype!");
-		if (hvlpevent_need_ack(event)) {
-			event->xRc = HvLpEvent_Rc_InvalidSubtype;
-			HvCallEvent_ackLpEvent(event);
-		}
-	}
-}
-
-/*
- * Get the driver to reprobe for more disks.
- */
-static ssize_t probe_disks(struct device_driver *drv, const char *buf,
-		size_t count)
-{
-	struct viodasd_device *d;
-
-	for (d = viodasd_devices; d < &viodasd_devices[MAX_DISKNO]; d++) {
-		if (d->disk == NULL)
-			probe_disk(d);
-	}
-	return count;
-}
-static DRIVER_ATTR(probe, S_IWUSR, NULL, probe_disks);
-
-static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
-{
-	struct viodasd_device *d = &viodasd_devices[vdev->unit_address];
-
-	d->dev = &vdev->dev;
-	if (!probe_disk(d))
-		return -ENODEV;
-	return 0;
-}
-
-static int viodasd_remove(struct vio_dev *vdev)
-{
-	struct viodasd_device *d;
-
-	d = &viodasd_devices[vdev->unit_address];
-	if (d->disk) {
-		del_gendisk(d->disk);
-		blk_cleanup_queue(d->disk->queue);
-		put_disk(d->disk);
-		d->disk = NULL;
-	}
-	d->dev = NULL;
-	return 0;
-}
-
-/**
- * viodasd_device_table: Used by vio.c to match devices that we
- * support.
- */
-static struct vio_device_id viodasd_device_table[] __devinitdata = {
-	{ "block", "IBM,iSeries-viodasd" },
-	{ "", "" }
-};
-MODULE_DEVICE_TABLE(vio, viodasd_device_table);
-
-static struct vio_driver viodasd_driver = {
-	.id_table = viodasd_device_table,
-	.probe = viodasd_probe,
-	.remove = viodasd_remove,
-	.driver = {
-		.name = "viodasd",
-		.owner = THIS_MODULE,
-	}
-};
-
-static int need_delete_probe;
-
-/*
- * Initialize the whole device driver.  Handle module and non-module
- * versions
- */
-static int __init viodasd_init(void)
-{
-	int rc;
-
-	if (!firmware_has_feature(FW_FEATURE_ISERIES)) {
-		rc = -ENODEV;
-		goto early_fail;
-	}
-
-	/* Try to open to our host lp */
-	if (viopath_hostLp == HvLpIndexInvalid)
-		vio_set_hostlp();
-
-	if (viopath_hostLp == HvLpIndexInvalid) {
-		pr_warning("invalid hosting partition\n");
-		rc = -EIO;
-		goto early_fail;
-	}
-
-	pr_info("vers " VIOD_VERS ", hosting partition %d\n", viopath_hostLp);
-
-        /* register the block device */
-	rc =  register_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
-	if (rc) {
-		pr_warning("Unable to get major number %d for %s\n",
-			   VIODASD_MAJOR, VIOD_GENHD_NAME);
-		goto early_fail;
-	}
-	/* Actually open the path to the hosting partition */
-	rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio,
-				VIOMAXREQ + 2);
-	if (rc) {
-		pr_warning("error opening path to host partition %d\n",
-			   viopath_hostLp);
-		goto unregister_blk;
-	}
-
-	/* Initialize our request handler */
-	vio_setHandler(viomajorsubtype_blockio, handle_block_event);
-
-	rc = vio_register_driver(&viodasd_driver);
-	if (rc) {
-		pr_warning("vio_register_driver failed\n");
-		goto unset_handler;
-	}
-
-	/*
-	 * If this call fails, it just means that we cannot dynamically
-	 * add virtual disks, but the driver will still work fine for
-	 * all existing disk, so ignore the failure.
-	 */
-	if (!driver_create_file(&viodasd_driver.driver, &driver_attr_probe))
-		need_delete_probe = 1;
-
-	return 0;
-
-unset_handler:
-	vio_clearHandler(viomajorsubtype_blockio);
-	viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2);
-unregister_blk:
-	unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
-early_fail:
-	return rc;
-}
-module_init(viodasd_init);
-
-void __exit viodasd_exit(void)
-{
-	if (need_delete_probe)
-		driver_remove_file(&viodasd_driver.driver, &driver_attr_probe);
-	vio_unregister_driver(&viodasd_driver);
-	vio_clearHandler(viomajorsubtype_blockio);
-	viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2);
-	unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
-}
-module_exit(viodasd_exit);
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index 51a9727..ff54052 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -52,7 +52,6 @@
 #include <linux/io.h>
 #include <linux/gfp.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/dma.h>
 
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 2f22874..d5e1ab9 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -1475,6 +1475,9 @@
 	if (!xen_domain())
 		return -ENODEV;
 
+	if (!xen_platform_pci_unplug)
+		return -ENODEV;
+
 	if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) {
 		printk(KERN_WARNING "xen_blk: can't get major %d with name %s\n",
 		       XENVBD_MAJOR, DEV_NAME);
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 9c09d6f..308c859 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -39,7 +39,6 @@
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
 #include <linux/bitops.h>
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include <linux/device.h>
diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c
index 6c20bbb..428dbb7 100644
--- a/drivers/bluetooth/btmrvl_debugfs.c
+++ b/drivers/bluetooth/btmrvl_debugfs.c
@@ -45,12 +45,6 @@
 	struct dentry *txdnldready;
 };
 
-static int btmrvl_open_generic(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t btmrvl_hscfgcmd_write(struct file *file,
 			const char __user *ubuf, size_t count, loff_t *ppos)
 {
@@ -93,7 +87,7 @@
 static const struct file_operations btmrvl_hscfgcmd_fops = {
 	.read	= btmrvl_hscfgcmd_read,
 	.write	= btmrvl_hscfgcmd_write,
-	.open	= btmrvl_open_generic,
+	.open	= simple_open,
 	.llseek = default_llseek,
 };
 
@@ -134,7 +128,7 @@
 static const struct file_operations btmrvl_psmode_fops = {
 	.read	= btmrvl_psmode_read,
 	.write	= btmrvl_psmode_write,
-	.open	= btmrvl_open_generic,
+	.open	= simple_open,
 	.llseek = default_llseek,
 };
 
@@ -180,7 +174,7 @@
 static const struct file_operations btmrvl_pscmd_fops = {
 	.read = btmrvl_pscmd_read,
 	.write = btmrvl_pscmd_write,
-	.open = btmrvl_open_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -221,7 +215,7 @@
 static const struct file_operations btmrvl_gpiogap_fops = {
 	.read	= btmrvl_gpiogap_read,
 	.write	= btmrvl_gpiogap_write,
-	.open	= btmrvl_open_generic,
+	.open	= simple_open,
 	.llseek = default_llseek,
 };
 
@@ -265,7 +259,7 @@
 static const struct file_operations btmrvl_hscmd_fops = {
 	.read	= btmrvl_hscmd_read,
 	.write	= btmrvl_hscmd_write,
-	.open	= btmrvl_open_generic,
+	.open	= simple_open,
 	.llseek = default_llseek,
 };
 
@@ -305,7 +299,7 @@
 static const struct file_operations btmrvl_hsmode_fops = {
 	.read	= btmrvl_hsmode_read,
 	.write	= btmrvl_hsmode_write,
-	.open	= btmrvl_open_generic,
+	.open	= simple_open,
 	.llseek = default_llseek,
 };
 
@@ -323,7 +317,7 @@
 
 static const struct file_operations btmrvl_curpsmode_fops = {
 	.read	= btmrvl_curpsmode_read,
-	.open	= btmrvl_open_generic,
+	.open	= simple_open,
 	.llseek = default_llseek,
 };
 
@@ -341,7 +335,7 @@
 
 static const struct file_operations btmrvl_psstate_fops = {
 	.read	= btmrvl_psstate_read,
-	.open	= btmrvl_open_generic,
+	.open	= simple_open,
 	.llseek = default_llseek,
 };
 
@@ -359,7 +353,7 @@
 
 static const struct file_operations btmrvl_hsstate_fops = {
 	.read	= btmrvl_hsstate_read,
-	.open	= btmrvl_open_generic,
+	.open	= simple_open,
 	.llseek = default_llseek,
 };
 
@@ -378,7 +372,7 @@
 
 static const struct file_operations btmrvl_txdnldready_fops = {
 	.read	= btmrvl_txdnldready_read,
-	.open	= btmrvl_open_generic,
+	.open	= simple_open,
 	.llseek = default_llseek,
 };
 
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index 194224d..c4fc2f3 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -38,7 +38,6 @@
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
 #include <linux/bitops.h>
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include <pcmcia/cistpl.h>
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 049c059..6e8d961 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -38,7 +38,6 @@
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
 #include <linux/bitops.h>
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include <pcmcia/cistpl.h>
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
deleted file mode 100644
index 7878da8..0000000
--- a/drivers/cdrom/viocd.c
+++ /dev/null
@@ -1,739 +0,0 @@
-/* -*- linux-c -*-
- *  drivers/cdrom/viocd.c
- *
- *  iSeries Virtual CD Rom
- *
- *  Authors: Dave Boutcher <boutcher@us.ibm.com>
- *           Ryan Arnold <ryanarn@us.ibm.com>
- *           Colin Devilbiss <devilbis@us.ibm.com>
- *           Stephen Rothwell
- *
- * (C) Copyright 2000-2004 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) anyu 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
- *
- * This routine provides access to CD ROM drives owned and managed by an
- * OS/400 partition running on the same box as this Linux partition.
- *
- * All operations are performed by sending messages back and forth to
- * the OS/400 partition.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/major.h>
-#include <linux/blkdev.h>
-#include <linux/cdrom.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/dma-mapping.h>
-#include <linux/module.h>
-#include <linux/completion.h>
-#include <linux/proc_fs.h>
-#include <linux/mutex.h>
-#include <linux/seq_file.h>
-#include <linux/scatterlist.h>
-
-#include <asm/vio.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/vio.h>
-#include <asm/firmware.h>
-
-#define VIOCD_DEVICE			"iseries/vcd"
-
-#define VIOCD_VERS "1.06"
-
-/*
- * Should probably make this a module parameter....sigh
- */
-#define VIOCD_MAX_CD	HVMAXARCHITECTEDVIRTUALCDROMS
-
-static DEFINE_MUTEX(viocd_mutex);
-static const struct vio_error_entry viocd_err_table[] = {
-	{0x0201, EINVAL, "Invalid Range"},
-	{0x0202, EINVAL, "Invalid Token"},
-	{0x0203, EIO, "DMA Error"},
-	{0x0204, EIO, "Use Error"},
-	{0x0205, EIO, "Release Error"},
-	{0x0206, EINVAL, "Invalid CD"},
-	{0x020C, EROFS, "Read Only Device"},
-	{0x020D, ENOMEDIUM, "Changed or Missing Volume (or Varied Off?)"},
-	{0x020E, EIO, "Optical System Error (Varied Off?)"},
-	{0x02FF, EIO, "Internal Error"},
-	{0x3010, EIO, "Changed Volume"},
-	{0xC100, EIO, "Optical System Error"},
-	{0x0000, 0, NULL},
-};
-
-/*
- * This is the structure we use to exchange info between driver and interrupt
- * handler
- */
-struct viocd_waitevent {
-	struct completion	com;
-	int			rc;
-	u16			sub_result;
-	int			changed;
-};
-
-/* this is a lookup table for the true capabilities of a device */
-struct capability_entry {
-	char	*type;
-	int	capability;
-};
-
-static struct capability_entry capability_table[] __initdata = {
-	{ "6330", CDC_LOCK | CDC_DVD_RAM | CDC_RAM },
-	{ "6331", CDC_LOCK | CDC_DVD_RAM | CDC_RAM },
-	{ "6333", CDC_LOCK | CDC_DVD_RAM | CDC_RAM },
-	{ "632A", CDC_LOCK | CDC_DVD_RAM | CDC_RAM },
-	{ "6321", CDC_LOCK },
-	{ "632B", 0 },
-	{ NULL  , CDC_LOCK },
-};
-
-/* These are our internal structures for keeping track of devices */
-static int viocd_numdev;
-
-struct disk_info {
-	struct gendisk			*viocd_disk;
-	struct cdrom_device_info	viocd_info;
-	struct device			*dev;
-	const char			*rsrcname;
-	const char			*type;
-	const char			*model;
-};
-static struct disk_info viocd_diskinfo[VIOCD_MAX_CD];
-
-#define DEVICE_NR(di)	((di) - &viocd_diskinfo[0])
-
-static spinlock_t viocd_reqlock;
-
-#define MAX_CD_REQ	1
-
-/* procfs support */
-static int proc_viocd_show(struct seq_file *m, void *v)
-{
-	int i;
-
-	for (i = 0; i < viocd_numdev; i++) {
-		seq_printf(m, "viocd device %d is iSeries resource %10.10s"
-				"type %4.4s, model %3.3s\n",
-				i, viocd_diskinfo[i].rsrcname,
-				viocd_diskinfo[i].type,
-				viocd_diskinfo[i].model);
-	}
-	return 0;
-}
-
-static int proc_viocd_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, proc_viocd_show, NULL);
-}
-
-static const struct file_operations proc_viocd_operations = {
-	.owner		= THIS_MODULE,
-	.open		= proc_viocd_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int viocd_blk_open(struct block_device *bdev, fmode_t mode)
-{
-	struct disk_info *di = bdev->bd_disk->private_data;
-	int ret;
-
-	mutex_lock(&viocd_mutex);
-	ret = cdrom_open(&di->viocd_info, bdev, mode);
-	mutex_unlock(&viocd_mutex);
-
-	return ret;
-}
-
-static int viocd_blk_release(struct gendisk *disk, fmode_t mode)
-{
-	struct disk_info *di = disk->private_data;
-	mutex_lock(&viocd_mutex);
-	cdrom_release(&di->viocd_info, mode);
-	mutex_unlock(&viocd_mutex);
-	return 0;
-}
-
-static int viocd_blk_ioctl(struct block_device *bdev, fmode_t mode,
-		unsigned cmd, unsigned long arg)
-{
-	struct disk_info *di = bdev->bd_disk->private_data;
-	int ret;
-
-	mutex_lock(&viocd_mutex);
-	ret = cdrom_ioctl(&di->viocd_info, bdev, mode, cmd, arg);
-	mutex_unlock(&viocd_mutex);
-
-	return ret;
-}
-
-static unsigned int viocd_blk_check_events(struct gendisk *disk,
-					   unsigned int clearing)
-{
-	struct disk_info *di = disk->private_data;
-	return cdrom_check_events(&di->viocd_info, clearing);
-}
-
-static const struct block_device_operations viocd_fops = {
-	.owner =		THIS_MODULE,
-	.open =			viocd_blk_open,
-	.release =		viocd_blk_release,
-	.ioctl =		viocd_blk_ioctl,
-	.check_events =		viocd_blk_check_events,
-};
-
-static int viocd_open(struct cdrom_device_info *cdi, int purpose)
-{
-        struct disk_info *diskinfo = cdi->handle;
-	int device_no = DEVICE_NR(diskinfo);
-	HvLpEvent_Rc hvrc;
-	struct viocd_waitevent we;
-
-	init_completion(&we.com);
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_cdio | viocdopen,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64)&we, VIOVERSION << 16, ((u64)device_no << 48),
-			0, 0, 0);
-	if (hvrc != 0) {
-		pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n",
-			   (int)hvrc);
-		return -EIO;
-	}
-
-	wait_for_completion(&we.com);
-
-	if (we.rc) {
-		const struct vio_error_entry *err =
-			vio_lookup_rc(viocd_err_table, we.sub_result);
-		pr_warning("bad rc %d:0x%04X on open: %s\n",
-			   we.rc, we.sub_result, err->msg);
-		return -err->errno;
-	}
-
-	return 0;
-}
-
-static void viocd_release(struct cdrom_device_info *cdi)
-{
-	int device_no = DEVICE_NR((struct disk_info *)cdi->handle);
-	HvLpEvent_Rc hvrc;
-
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_cdio | viocdclose,
-			HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp), 0,
-			VIOVERSION << 16, ((u64)device_no << 48), 0, 0, 0);
-	if (hvrc != 0)
-		pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n",
-			   (int)hvrc);
-}
-
-/* Send a read or write request to OS/400 */
-static int send_request(struct request *req)
-{
-	HvLpEvent_Rc hvrc;
-	struct disk_info *diskinfo = req->rq_disk->private_data;
-	u64 len;
-	dma_addr_t dmaaddr;
-	int direction;
-	u16 cmd;
-	struct scatterlist sg;
-
-	BUG_ON(req->nr_phys_segments > 1);
-
-	if (rq_data_dir(req) == READ) {
-		direction = DMA_FROM_DEVICE;
-		cmd = viomajorsubtype_cdio | viocdread;
-	} else {
-		direction = DMA_TO_DEVICE;
-		cmd = viomajorsubtype_cdio | viocdwrite;
-	}
-
-	sg_init_table(&sg, 1);
-        if (blk_rq_map_sg(req->q, req, &sg) == 0) {
-		pr_warning("error setting up scatter/gather list\n");
-		return -1;
-	}
-
-	if (dma_map_sg(diskinfo->dev, &sg, 1, direction) == 0) {
-		pr_warning("error allocating sg tce\n");
-		return -1;
-	}
-	dmaaddr = sg_dma_address(&sg);
-	len = sg_dma_len(&sg);
-
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo, cmd,
-			HvLpEvent_AckInd_DoAck,
-			HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64)req, VIOVERSION << 16,
-			((u64)DEVICE_NR(diskinfo) << 48) | dmaaddr,
-			(u64)blk_rq_pos(req) * 512, len, 0);
-	if (hvrc != HvLpEvent_Rc_Good) {
-		pr_warning("hv error on op %d\n", (int)hvrc);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int rwreq;
-
-static void do_viocd_request(struct request_queue *q)
-{
-	struct request *req;
-
-	while ((rwreq == 0) && ((req = blk_fetch_request(q)) != NULL)) {
-		if (req->cmd_type != REQ_TYPE_FS)
-			__blk_end_request_all(req, -EIO);
-		else if (send_request(req) < 0) {
-			pr_warning("unable to send message to OS/400!\n");
-			__blk_end_request_all(req, -EIO);
-		} else
-			rwreq++;
-	}
-}
-
-static unsigned int viocd_check_events(struct cdrom_device_info *cdi,
-				       unsigned int clearing, int disc_nr)
-{
-	struct viocd_waitevent we;
-	HvLpEvent_Rc hvrc;
-	int device_no = DEVICE_NR((struct disk_info *)cdi->handle);
-
-	init_completion(&we.com);
-
-	/* Send the open event to OS/400 */
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_cdio | viocdcheck,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64)&we, VIOVERSION << 16, ((u64)device_no << 48),
-			0, 0, 0);
-	if (hvrc != 0) {
-		pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n",
-			   (int)hvrc);
-		return 0;
-	}
-
-	wait_for_completion(&we.com);
-
-	/* Check the return code.  If bad, assume no change */
-	if (we.rc) {
-		const struct vio_error_entry *err =
-			vio_lookup_rc(viocd_err_table, we.sub_result);
-		pr_warning("bad rc %d:0x%04X on check_change: %s; Assuming no change\n",
-			   we.rc, we.sub_result, err->msg);
-		return 0;
-	}
-
-	return we.changed ? DISK_EVENT_MEDIA_CHANGE : 0;
-}
-
-static int viocd_lock_door(struct cdrom_device_info *cdi, int locking)
-{
-	HvLpEvent_Rc hvrc;
-	u64 device_no = DEVICE_NR((struct disk_info *)cdi->handle);
-	/* NOTE: flags is 1 or 0 so it won't overwrite the device_no */
-	u64 flags = !!locking;
-	struct viocd_waitevent we;
-
-	init_completion(&we.com);
-
-	/* Send the lockdoor event to OS/400 */
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_cdio | viocdlockdoor,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64)&we, VIOVERSION << 16,
-			(device_no << 48) | (flags << 32), 0, 0, 0);
-	if (hvrc != 0) {
-		pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n",
-			   (int)hvrc);
-		return -EIO;
-	}
-
-	wait_for_completion(&we.com);
-
-	if (we.rc != 0)
-		return -EIO;
-	return 0;
-}
-
-static int viocd_packet(struct cdrom_device_info *cdi,
-		struct packet_command *cgc)
-{
-	unsigned int buflen = cgc->buflen;
-	int ret = -EIO;
-
-	switch (cgc->cmd[0]) {
-	case GPCMD_READ_DISC_INFO:
-		{
-			disc_information *di = (disc_information *)cgc->buffer;
-
-			if (buflen >= 2) {
-				di->disc_information_length = cpu_to_be16(1);
-				ret = 0;
-			}
-			if (buflen >= 3)
-				di->erasable =
-					(cdi->ops->capability & ~cdi->mask
-					 & (CDC_DVD_RAM | CDC_RAM)) != 0;
-		}
-		break;
-	case GPCMD_GET_CONFIGURATION:
-		if (cgc->cmd[3] == CDF_RWRT) {
-			struct rwrt_feature_desc *rfd = (struct rwrt_feature_desc *)(cgc->buffer + sizeof(struct feature_header));
-
-			if ((buflen >=
-			     (sizeof(struct feature_header) + sizeof(*rfd))) &&
-			    (cdi->ops->capability & ~cdi->mask
-			     & (CDC_DVD_RAM | CDC_RAM))) {
-				rfd->feature_code = cpu_to_be16(CDF_RWRT);
-				rfd->curr = 1;
-				ret = 0;
-			}
-		}
-		break;
-	default:
-		if (cgc->sense) {
-			/* indicate Unknown code */
-			cgc->sense->sense_key = 0x05;
-			cgc->sense->asc = 0x20;
-			cgc->sense->ascq = 0x00;
-		}
-		break;
-	}
-
-	cgc->stat = ret;
-	return ret;
-}
-
-static void restart_all_queues(int first_index)
-{
-	int i;
-
-	for (i = first_index + 1; i < viocd_numdev; i++)
-		if (viocd_diskinfo[i].viocd_disk)
-			blk_run_queue(viocd_diskinfo[i].viocd_disk->queue);
-	for (i = 0; i <= first_index; i++)
-		if (viocd_diskinfo[i].viocd_disk)
-			blk_run_queue(viocd_diskinfo[i].viocd_disk->queue);
-}
-
-/* This routine handles incoming CD LP events */
-static void vio_handle_cd_event(struct HvLpEvent *event)
-{
-	struct viocdlpevent *bevent;
-	struct viocd_waitevent *pwe;
-	struct disk_info *di;
-	unsigned long flags;
-	struct request *req;
-
-
-	if (event == NULL)
-		/* Notification that a partition went away! */
-		return;
-	/* First, we should NEVER get an int here...only acks */
-	if (hvlpevent_is_int(event)) {
-		pr_warning("Yikes! got an int in viocd event handler!\n");
-		if (hvlpevent_need_ack(event)) {
-			event->xRc = HvLpEvent_Rc_InvalidSubtype;
-			HvCallEvent_ackLpEvent(event);
-		}
-	}
-
-	bevent = (struct viocdlpevent *)event;
-
-	switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
-	case viocdopen:
-		if (event->xRc == 0) {
-			di = &viocd_diskinfo[bevent->disk];
-			blk_queue_logical_block_size(di->viocd_disk->queue,
-						     bevent->block_size);
-			set_capacity(di->viocd_disk,
-					bevent->media_size *
-					bevent->block_size / 512);
-		}
-		/* FALLTHROUGH !! */
-	case viocdlockdoor:
-		pwe = (struct viocd_waitevent *)event->xCorrelationToken;
-return_complete:
-		pwe->rc = event->xRc;
-		pwe->sub_result = bevent->sub_result;
-		complete(&pwe->com);
-		break;
-
-	case viocdcheck:
-		pwe = (struct viocd_waitevent *)event->xCorrelationToken;
-		pwe->changed = bevent->flags;
-		goto return_complete;
-
-	case viocdclose:
-		break;
-
-	case viocdwrite:
-	case viocdread:
-		/*
-		 * Since this is running in interrupt mode, we need to
-		 * make sure we're not stepping on any global I/O operations
-		 */
-		di = &viocd_diskinfo[bevent->disk];
-		spin_lock_irqsave(&viocd_reqlock, flags);
-		dma_unmap_single(di->dev, bevent->token, bevent->len,
-				((event->xSubtype & VIOMINOR_SUBTYPE_MASK) == viocdread)
-				?  DMA_FROM_DEVICE : DMA_TO_DEVICE);
-		req = (struct request *)bevent->event.xCorrelationToken;
-		rwreq--;
-
-		if (event->xRc != HvLpEvent_Rc_Good) {
-			const struct vio_error_entry *err =
-				vio_lookup_rc(viocd_err_table,
-						bevent->sub_result);
-			pr_warning("request %p failed with rc %d:0x%04X: %s\n",
-				   req, event->xRc,
-				   bevent->sub_result, err->msg);
-			__blk_end_request_all(req, -EIO);
-		} else
-			__blk_end_request_all(req, 0);
-
-		/* restart handling of incoming requests */
-		spin_unlock_irqrestore(&viocd_reqlock, flags);
-		restart_all_queues(bevent->disk);
-		break;
-
-	default:
-		pr_warning("message with invalid subtype %0x04X!\n",
-			   event->xSubtype & VIOMINOR_SUBTYPE_MASK);
-		if (hvlpevent_need_ack(event)) {
-			event->xRc = HvLpEvent_Rc_InvalidSubtype;
-			HvCallEvent_ackLpEvent(event);
-		}
-	}
-}
-
-static int viocd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
-			     void *arg)
-{
-	return -EINVAL;
-}
-
-static struct cdrom_device_ops viocd_dops = {
-	.open = viocd_open,
-	.release = viocd_release,
-	.check_events = viocd_check_events,
-	.lock_door = viocd_lock_door,
-	.generic_packet = viocd_packet,
-	.audio_ioctl = viocd_audio_ioctl,
-	.capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM
-};
-
-static int find_capability(const char *type)
-{
-	struct capability_entry *entry;
-
-	for(entry = capability_table; entry->type; ++entry)
-		if(!strncmp(entry->type, type, 4))
-			break;
-	return entry->capability;
-}
-
-static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
-{
-	struct gendisk *gendisk;
-	int deviceno;
-	struct disk_info *d;
-	struct cdrom_device_info *c;
-	struct request_queue *q;
-	struct device_node *node = vdev->dev.of_node;
-
-	deviceno = vdev->unit_address;
-	if (deviceno >= VIOCD_MAX_CD)
-		return -ENODEV;
-	if (!node)
-		return -ENODEV;
-
-	if (deviceno >= viocd_numdev)
-		viocd_numdev = deviceno + 1;
-
-	d = &viocd_diskinfo[deviceno];
-	d->rsrcname = of_get_property(node, "linux,vio_rsrcname", NULL);
-	d->type = of_get_property(node, "linux,vio_type", NULL);
-	d->model = of_get_property(node, "linux,vio_model", NULL);
-
-	c = &d->viocd_info;
-
-	c->ops = &viocd_dops;
-	c->speed = 4;
-	c->capacity = 1;
-	c->handle = d;
-	c->mask = ~find_capability(d->type);
-	sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno);
-
-	if (register_cdrom(c) != 0) {
-		pr_warning("Cannot register viocd CD-ROM %s!\n", c->name);
-		goto out;
-	}
-	pr_info("cd %s is iSeries resource %10.10s type %4.4s, model %3.3s\n",
-		c->name, d->rsrcname, d->type, d->model);
-	q = blk_init_queue(do_viocd_request, &viocd_reqlock);
-	if (q == NULL) {
-		pr_warning("Cannot allocate queue for %s!\n", c->name);
-		goto out_unregister_cdrom;
-	}
-	gendisk = alloc_disk(1);
-	if (gendisk == NULL) {
-		pr_warning("Cannot create gendisk for %s!\n", c->name);
-		goto out_cleanup_queue;
-	}
-	gendisk->major = VIOCD_MAJOR;
-	gendisk->first_minor = deviceno;
-	strncpy(gendisk->disk_name, c->name,
-			sizeof(gendisk->disk_name));
-	blk_queue_max_segments(q, 1);
-	blk_queue_max_hw_sectors(q, 4096 / 512);
-	gendisk->queue = q;
-	gendisk->fops = &viocd_fops;
-	gendisk->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE |
-			 GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
-	set_capacity(gendisk, 0);
-	gendisk->private_data = d;
-	d->viocd_disk = gendisk;
-	d->dev = &vdev->dev;
-	gendisk->driverfs_dev = d->dev;
-	add_disk(gendisk);
-	return 0;
-
-out_cleanup_queue:
-	blk_cleanup_queue(q);
-out_unregister_cdrom:
-	unregister_cdrom(c);
-out:
-	return -ENODEV;
-}
-
-static int viocd_remove(struct vio_dev *vdev)
-{
-	struct disk_info *d = &viocd_diskinfo[vdev->unit_address];
-
-	unregister_cdrom(&d->viocd_info);
-	del_gendisk(d->viocd_disk);
-	blk_cleanup_queue(d->viocd_disk->queue);
-	put_disk(d->viocd_disk);
-	return 0;
-}
-
-/**
- * viocd_device_table: Used by vio.c to match devices that we
- * support.
- */
-static struct vio_device_id viocd_device_table[] __devinitdata = {
-	{ "block", "IBM,iSeries-viocd" },
-	{ "", "" }
-};
-MODULE_DEVICE_TABLE(vio, viocd_device_table);
-
-static struct vio_driver viocd_driver = {
-	.id_table = viocd_device_table,
-	.probe = viocd_probe,
-	.remove = viocd_remove,
-	.driver = {
-		.name = "viocd",
-		.owner = THIS_MODULE,
-	}
-};
-
-static int __init viocd_init(void)
-{
-	int ret = 0;
-
-	if (!firmware_has_feature(FW_FEATURE_ISERIES))
-		return -ENODEV;
-
-	if (viopath_hostLp == HvLpIndexInvalid) {
-		vio_set_hostlp();
-		/* If we don't have a host, bail out */
-		if (viopath_hostLp == HvLpIndexInvalid)
-			return -ENODEV;
-	}
-
-	pr_info("vers " VIOCD_VERS ", hosting partition %d\n", viopath_hostLp);
-
-	if (register_blkdev(VIOCD_MAJOR, VIOCD_DEVICE) != 0) {
-		pr_warning("Unable to get major %d for %s\n",
-			   VIOCD_MAJOR, VIOCD_DEVICE);
-		return -EIO;
-	}
-
-	ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio,
-			MAX_CD_REQ + 2);
-	if (ret) {
-		pr_warning("error opening path to host partition %d\n",
-			   viopath_hostLp);
-		goto out_unregister;
-	}
-
-	/* Initialize our request handler */
-	vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event);
-
-	spin_lock_init(&viocd_reqlock);
-
-	ret = vio_register_driver(&viocd_driver);
-	if (ret)
-		goto out_free_info;
-
-	proc_create("iSeries/viocd", S_IFREG|S_IRUGO, NULL,
-		    &proc_viocd_operations);
-	return 0;
-
-out_free_info:
-	vio_clearHandler(viomajorsubtype_cdio);
-	viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
-out_unregister:
-	unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE);
-	return ret;
-}
-
-static void __exit viocd_exit(void)
-{
-	remove_proc_entry("iSeries/viocd", NULL);
-	vio_unregister_driver(&viocd_driver);
-	viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
-	vio_clearHandler(viomajorsubtype_cdio);
-	unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE);
-}
-
-module_init(viocd_init);
-module_exit(viocd_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index b427711..962e75d 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -850,6 +850,7 @@
 	.subvendor	= PCI_ANY_ID,			\
 	.subdevice	= PCI_ANY_ID,			\
 	}
+	ID(PCI_DEVICE_ID_INTEL_82441), /* for HAS2 support */
 	ID(PCI_DEVICE_ID_INTEL_82443LX_0),
 	ID(PCI_DEVICE_ID_INTEL_82443BX_0),
 	ID(PCI_DEVICE_ID_INTEL_82443GX_0),
diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h
index 5da67f1..7ea18a5 100644
--- a/drivers/char/agp/intel-agp.h
+++ b/drivers/char/agp/intel-agp.h
@@ -234,6 +234,7 @@
 #define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT2_IG		0x0166
 #define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB		0x0158  /* Server */
 #define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG		0x015A
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT2_IG		0x016A
 
 int intel_gmch_probe(struct pci_dev *pdev,
 			       struct agp_bridge_data *bridge);
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index c92424c..7f025fb 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -76,7 +76,6 @@
 	struct resource ifp_resource;
 	int resource_valid;
 	struct page *scratch_page;
-	dma_addr_t scratch_page_dma;
 } intel_private;
 
 #define INTEL_GTT_GEN	intel_private.driver->gen
@@ -306,9 +305,9 @@
 		if (pci_dma_mapping_error(intel_private.pcidev, dma_addr))
 			return -EINVAL;
 
-		intel_private.scratch_page_dma = dma_addr;
+		intel_private.base.scratch_page_dma = dma_addr;
 	} else
-		intel_private.scratch_page_dma = page_to_phys(page);
+		intel_private.base.scratch_page_dma = page_to_phys(page);
 
 	intel_private.scratch_page = page;
 
@@ -631,7 +630,7 @@
 static void intel_gtt_teardown_scratch_page(void)
 {
 	set_pages_wb(intel_private.scratch_page, 1);
-	pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma,
+	pci_unmap_page(intel_private.pcidev, intel_private.base.scratch_page_dma,
 		       PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
 	put_page(intel_private.scratch_page);
 	__free_page(intel_private.scratch_page);
@@ -681,6 +680,7 @@
 		iounmap(intel_private.registers);
 		return -ENOMEM;
 	}
+	intel_private.base.gtt = intel_private.gtt;
 
 	global_cache_flush();   /* FIXME: ? */
 
@@ -975,7 +975,7 @@
 	unsigned int i;
 
 	for (i = first_entry; i < (first_entry + num_entries); i++) {
-		intel_private.driver->write_entry(intel_private.scratch_page_dma,
+		intel_private.driver->write_entry(intel_private.base.scratch_page_dma,
 						  i, 0);
 	}
 	readl(intel_private.gtt+i-1);
@@ -1190,7 +1190,6 @@
 {
 #ifdef CONFIG_INTEL_IOMMU
 	const unsigned short gpu_devid = intel_private.pcidev->device;
-	extern int intel_iommu_gfx_mapped;
 
 	/* Query intel_iommu to see if we need the workaround. Presumably that
 	 * was loaded first.
@@ -1459,6 +1458,8 @@
 	    "Ivybridge", &sandybridge_gtt_driver },
 	{ PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG,
 	    "Ivybridge", &sandybridge_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT2_IG,
+	    "Ivybridge", &sandybridge_gtt_driver },
 	{ 0, NULL, NULL }
 };
 
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index f4837a8..46118f8 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -31,7 +31,6 @@
 #include <linux/kthread.h>
 #include <linux/delay.h>
 
-#include <asm/system.h>
 
 /*
  * The apm_bios device is one of the misc char devices.
@@ -302,7 +301,7 @@
 			 * anything critical, chill a bit on each iteration.
 			 */
 			while (wait_event_freezable(apm_suspend_waitqueue,
-					as->suspend_state == SUSPEND_DONE))
+					as->suspend_state != SUSPEND_ACKED))
 				msleep(10);
 			break;
 		case SUSPEND_ACKTO:
diff --git a/drivers/char/ds1302.c b/drivers/char/ds1302.c
index ed8303f9..7d34b20 100644
--- a/drivers/char/ds1302.c
+++ b/drivers/char/ds1302.c
@@ -24,7 +24,6 @@
 #include <linux/uaccess.h>
 #include <linux/io.h>
 
-#include <asm/system.h>
 #include <asm/rtc.h>
 #if defined(CONFIG_M32R)
 #include <asm/m32r.h>
diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c
index 53c524e..a082d00 100644
--- a/drivers/char/efirtc.c
+++ b/drivers/char/efirtc.c
@@ -37,7 +37,6 @@
 #include <linux/efi.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 
 #define EFI_RTC_VERSION		"0.4"
 
diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c
index f773a9d..21cb980 100644
--- a/drivers/char/genrtc.c
+++ b/drivers/char/genrtc.c
@@ -56,7 +56,6 @@
 #include <linux/workqueue.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/rtc.h>
 
 /*
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 0833896..3845ab4 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -36,7 +36,6 @@
 #include <linux/io.h>
 
 #include <asm/current.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/div64.h>
 
diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c
index 3d3c1e6..96de024 100644
--- a/drivers/char/hw_random/nomadik-rng.c
+++ b/drivers/char/hw_random/nomadik-rng.c
@@ -107,17 +107,6 @@
 	.id_table = nmk_rng_ids,
 };
 
-static int __init nmk_rng_init(void)
-{
-	return amba_driver_register(&nmk_rng_driver);
-}
-
-static void __devexit nmk_rng_exit(void)
-{
-	amba_driver_unregister(&nmk_rng_driver);
-}
-
-module_init(nmk_rng_init);
-module_exit(nmk_rng_exit);
+module_amba_driver(nmk_rng_driver);
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index b757fac..a07a5ca 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -26,6 +26,8 @@
 
 #include <asm/io.h>
 
+#include <plat/cpu.h>
+
 #define RNG_OUT_REG		0x00		/* Output register */
 #define RNG_STAT_REG		0x04		/* Status register
 							[0] = STAT_BUSY */
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index 2aa3977..9eb360f 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -34,7 +34,6 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/errno.h>
-#include <asm/system.h>
 #include <linux/poll.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c
index cf82fed..e53fc24 100644
--- a/drivers/char/ipmi/ipmi_kcs_sm.c
+++ b/drivers/char/ipmi/ipmi_kcs_sm.c
@@ -118,8 +118,8 @@
 #define MAX_KCS_WRITE_SIZE IPMI_MAX_MSG_LENGTH
 
 /* Timeouts in microseconds. */
-#define IBF_RETRY_TIMEOUT 1000000
-#define OBF_RETRY_TIMEOUT 1000000
+#define IBF_RETRY_TIMEOUT 5000000
+#define OBF_RETRY_TIMEOUT 5000000
 #define MAX_ERROR_RETRIES 10
 #define ERROR0_OBF_WAIT_JIFFIES (2*HZ)
 
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 58c0e63..2c29942 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -33,7 +33,6 @@
 
 #include <linux/module.h>
 #include <linux/errno.h>
-#include <asm/system.h>
 #include <linux/poll.h>
 #include <linux/sched.h>
 #include <linux/seq_file.h>
@@ -46,6 +45,7 @@
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/rcupdate.h>
+#include <linux/interrupt.h>
 
 #define PFX "IPMI message handler: "
 
@@ -53,6 +53,8 @@
 
 static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
 static int ipmi_init_msghandler(void);
+static void smi_recv_tasklet(unsigned long);
+static void handle_new_recv_msgs(ipmi_smi_t intf);
 
 static int initialized;
 
@@ -355,12 +357,15 @@
 	int curr_seq;
 
 	/*
-	 * Messages that were delayed for some reason (out of memory,
-	 * for instance), will go in here to be processed later in a
-	 * periodic timer interrupt.
+	 * Messages queued for delivery.  If delivery fails (out of memory
+	 * for instance), They will stay in here to be processed later in a
+	 * periodic timer interrupt.  The tasklet is for handling received
+	 * messages directly from the handler.
 	 */
 	spinlock_t       waiting_msgs_lock;
 	struct list_head waiting_msgs;
+	atomic_t	 watchdog_pretimeouts_to_deliver;
+	struct tasklet_struct recv_tasklet;
 
 	/*
 	 * The list of command receivers that are registered for commands
@@ -493,6 +498,8 @@
 	struct cmd_rcvr  *rcvr, *rcvr2;
 	struct list_head list;
 
+	tasklet_kill(&intf->recv_tasklet);
+
 	free_smi_msg_list(&intf->waiting_msgs);
 	free_recv_msg_list(&intf->waiting_events);
 
@@ -2786,12 +2793,17 @@
 	return;
 }
 
-void ipmi_poll_interface(ipmi_user_t user)
+static void ipmi_poll(ipmi_smi_t intf)
 {
-	ipmi_smi_t intf = user->intf;
-
 	if (intf->handlers->poll)
 		intf->handlers->poll(intf->send_info);
+	/* In case something came in */
+	handle_new_recv_msgs(intf);
+}
+
+void ipmi_poll_interface(ipmi_user_t user)
+{
+	ipmi_poll(user->intf);
 }
 EXPORT_SYMBOL(ipmi_poll_interface);
 
@@ -2860,6 +2872,10 @@
 #endif
 	spin_lock_init(&intf->waiting_msgs_lock);
 	INIT_LIST_HEAD(&intf->waiting_msgs);
+	tasklet_init(&intf->recv_tasklet,
+		     smi_recv_tasklet,
+		     (unsigned long) intf);
+	atomic_set(&intf->watchdog_pretimeouts_to_deliver, 0);
 	spin_lock_init(&intf->events_lock);
 	INIT_LIST_HEAD(&intf->waiting_events);
 	intf->waiting_events_count = 0;
@@ -3622,11 +3638,11 @@
 }
 
 /*
- * Handle a new message.  Return 1 if the message should be requeued,
+ * Handle a received message.  Return 1 if the message should be requeued,
  * 0 if the message should be freed, or -1 if the message should not
  * be freed or requeued.
  */
-static int handle_new_recv_msg(ipmi_smi_t          intf,
+static int handle_one_recv_msg(ipmi_smi_t          intf,
 			       struct ipmi_smi_msg *msg)
 {
 	int requeue;
@@ -3784,12 +3800,72 @@
 	return requeue;
 }
 
+/*
+ * If there are messages in the queue or pretimeouts, handle them.
+ */
+static void handle_new_recv_msgs(ipmi_smi_t intf)
+{
+	struct ipmi_smi_msg  *smi_msg;
+	unsigned long        flags = 0;
+	int                  rv;
+	int                  run_to_completion = intf->run_to_completion;
+
+	/* See if any waiting messages need to be processed. */
+	if (!run_to_completion)
+		spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
+	while (!list_empty(&intf->waiting_msgs)) {
+		smi_msg = list_entry(intf->waiting_msgs.next,
+				     struct ipmi_smi_msg, link);
+		list_del(&smi_msg->link);
+		if (!run_to_completion)
+			spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
+		rv = handle_one_recv_msg(intf, smi_msg);
+		if (!run_to_completion)
+			spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
+		if (rv == 0) {
+			/* Message handled */
+			ipmi_free_smi_msg(smi_msg);
+		} else if (rv < 0) {
+			/* Fatal error on the message, del but don't free. */
+		} else {
+			/*
+			 * To preserve message order, quit if we
+			 * can't handle a message.
+			 */
+			list_add(&smi_msg->link, &intf->waiting_msgs);
+			break;
+		}
+	}
+	if (!run_to_completion)
+		spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
+
+	/*
+	 * If the pretimout count is non-zero, decrement one from it and
+	 * deliver pretimeouts to all the users.
+	 */
+	if (atomic_add_unless(&intf->watchdog_pretimeouts_to_deliver, -1, 0)) {
+		ipmi_user_t user;
+
+		rcu_read_lock();
+		list_for_each_entry_rcu(user, &intf->users, link) {
+			if (user->handler->ipmi_watchdog_pretimeout)
+				user->handler->ipmi_watchdog_pretimeout(
+					user->handler_data);
+		}
+		rcu_read_unlock();
+	}
+}
+
+static void smi_recv_tasklet(unsigned long val)
+{
+	handle_new_recv_msgs((ipmi_smi_t) val);
+}
+
 /* Handle a new message from the lower layer. */
 void ipmi_smi_msg_received(ipmi_smi_t          intf,
 			   struct ipmi_smi_msg *msg)
 {
 	unsigned long flags = 0; /* keep us warning-free. */
-	int           rv;
 	int           run_to_completion;
 
 
@@ -3843,31 +3919,11 @@
 	run_to_completion = intf->run_to_completion;
 	if (!run_to_completion)
 		spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
-	if (!list_empty(&intf->waiting_msgs)) {
-		list_add_tail(&msg->link, &intf->waiting_msgs);
-		if (!run_to_completion)
-			spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
-		goto out;
-	}
+	list_add_tail(&msg->link, &intf->waiting_msgs);
 	if (!run_to_completion)
 		spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
 
-	rv = handle_new_recv_msg(intf, msg);
-	if (rv > 0) {
-		/*
-		 * Could not handle the message now, just add it to a
-		 * list to handle later.
-		 */
-		run_to_completion = intf->run_to_completion;
-		if (!run_to_completion)
-			spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
-		list_add_tail(&msg->link, &intf->waiting_msgs);
-		if (!run_to_completion)
-			spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
-	} else if (rv == 0) {
-		ipmi_free_smi_msg(msg);
-	}
-
+	tasklet_schedule(&intf->recv_tasklet);
  out:
 	return;
 }
@@ -3875,16 +3931,8 @@
 
 void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
 {
-	ipmi_user_t user;
-
-	rcu_read_lock();
-	list_for_each_entry_rcu(user, &intf->users, link) {
-		if (!user->handler->ipmi_watchdog_pretimeout)
-			continue;
-
-		user->handler->ipmi_watchdog_pretimeout(user->handler_data);
-	}
-	rcu_read_unlock();
+	atomic_set(&intf->watchdog_pretimeouts_to_deliver, 1);
+	tasklet_schedule(&intf->recv_tasklet);
 }
 EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
 
@@ -3998,28 +4046,12 @@
 	ipmi_smi_t           intf;
 	struct list_head     timeouts;
 	struct ipmi_recv_msg *msg, *msg2;
-	struct ipmi_smi_msg  *smi_msg, *smi_msg2;
 	unsigned long        flags;
 	int                  i;
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
-		/* See if any waiting messages need to be processed. */
-		spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
-		list_for_each_entry_safe(smi_msg, smi_msg2,
-					 &intf->waiting_msgs, link) {
-			if (!handle_new_recv_msg(intf, smi_msg)) {
-				list_del(&smi_msg->link);
-				ipmi_free_smi_msg(smi_msg);
-			} else {
-				/*
-				 * To preserve message order, quit if we
-				 * can't handle a message.
-				 */
-				break;
-			}
-		}
-		spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
+		tasklet_schedule(&intf->recv_tasklet);
 
 		/*
 		 * Go through the seq table and find any messages that
@@ -4173,12 +4205,48 @@
 
 #ifdef CONFIG_IPMI_PANIC_EVENT
 
+static atomic_t panic_done_count = ATOMIC_INIT(0);
+
 static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
 {
+	atomic_dec(&panic_done_count);
 }
 
 static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
 {
+	atomic_dec(&panic_done_count);
+}
+
+/*
+ * Inside a panic, send a message and wait for a response.
+ */
+static void ipmi_panic_request_and_wait(ipmi_smi_t           intf,
+					struct ipmi_addr     *addr,
+					struct kernel_ipmi_msg *msg)
+{
+	struct ipmi_smi_msg  smi_msg;
+	struct ipmi_recv_msg recv_msg;
+	int rv;
+
+	smi_msg.done = dummy_smi_done_handler;
+	recv_msg.done = dummy_recv_done_handler;
+	atomic_add(2, &panic_done_count);
+	rv = i_ipmi_request(NULL,
+			    intf,
+			    addr,
+			    0,
+			    msg,
+			    intf,
+			    &smi_msg,
+			    &recv_msg,
+			    0,
+			    intf->channels[0].address,
+			    intf->channels[0].lun,
+			    0, 1); /* Don't retry, and don't wait. */
+	if (rv)
+		atomic_sub(2, &panic_done_count);
+	while (atomic_read(&panic_done_count) != 0)
+		ipmi_poll(intf);
 }
 
 #ifdef CONFIG_IPMI_PANIC_STRING
@@ -4217,8 +4285,6 @@
 	unsigned char                     data[16];
 	struct ipmi_system_interface_addr *si;
 	struct ipmi_addr                  addr;
-	struct ipmi_smi_msg               smi_msg;
-	struct ipmi_recv_msg              recv_msg;
 
 	si = (struct ipmi_system_interface_addr *) &addr;
 	si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
@@ -4246,9 +4312,6 @@
 		data[7] = str[2];
 	}
 
-	smi_msg.done = dummy_smi_done_handler;
-	recv_msg.done = dummy_recv_done_handler;
-
 	/* For every registered interface, send the event. */
 	list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
 		if (!intf->handlers)
@@ -4258,18 +4321,7 @@
 		intf->run_to_completion = 1;
 		/* Send the event announcing the panic. */
 		intf->handlers->set_run_to_completion(intf->send_info, 1);
-		i_ipmi_request(NULL,
-			       intf,
-			       &addr,
-			       0,
-			       &msg,
-			       intf,
-			       &smi_msg,
-			       &recv_msg,
-			       0,
-			       intf->channels[0].address,
-			       intf->channels[0].lun,
-			       0, 1); /* Don't retry, and don't wait. */
+		ipmi_panic_request_and_wait(intf, &addr, &msg);
 	}
 
 #ifdef CONFIG_IPMI_PANIC_STRING
@@ -4317,18 +4369,7 @@
 		msg.data = NULL;
 		msg.data_len = 0;
 		intf->null_user_handler = device_id_fetcher;
-		i_ipmi_request(NULL,
-			       intf,
-			       &addr,
-			       0,
-			       &msg,
-			       intf,
-			       &smi_msg,
-			       &recv_msg,
-			       0,
-			       intf->channels[0].address,
-			       intf->channels[0].lun,
-			       0, 1); /* Don't retry, and don't wait. */
+		ipmi_panic_request_and_wait(intf, &addr, &msg);
 
 		if (intf->local_event_generator) {
 			/* Request the event receiver from the local MC. */
@@ -4337,18 +4378,7 @@
 			msg.data = NULL;
 			msg.data_len = 0;
 			intf->null_user_handler = event_receiver_fetcher;
-			i_ipmi_request(NULL,
-				       intf,
-				       &addr,
-				       0,
-				       &msg,
-				       intf,
-				       &smi_msg,
-				       &recv_msg,
-				       0,
-				       intf->channels[0].address,
-				       intf->channels[0].lun,
-				       0, 1); /* no retry, and no wait. */
+			ipmi_panic_request_and_wait(intf, &addr, &msg);
 		}
 		intf->null_user_handler = NULL;
 
@@ -4405,18 +4435,7 @@
 			strncpy(data+5, p, 11);
 			p += size;
 
-			i_ipmi_request(NULL,
-				       intf,
-				       &addr,
-				       0,
-				       &msg,
-				       intf,
-				       &smi_msg,
-				       &recv_msg,
-				       0,
-				       intf->channels[0].address,
-				       intf->channels[0].lun,
-				       0, 1); /* no retry, and no wait. */
+			ipmi_panic_request_and_wait(intf, &addr, &msg);
 		}
 	}
 #endif /* CONFIG_IPMI_PANIC_STRING */
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 50fcf9c..1e638ff 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -41,7 +41,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <asm/system.h>
 #include <linux/sched.h>
 #include <linux/seq_file.h>
 #include <linux/timer.h>
@@ -171,7 +170,6 @@
 	struct si_sm_handlers  *handlers;
 	enum si_type           si_type;
 	spinlock_t             si_lock;
-	spinlock_t             msg_lock;
 	struct list_head       xmit_msgs;
 	struct list_head       hp_xmit_msgs;
 	struct ipmi_smi_msg    *curr_msg;
@@ -320,16 +318,8 @@
 static void deliver_recv_msg(struct smi_info *smi_info,
 			     struct ipmi_smi_msg *msg)
 {
-	/* Deliver the message to the upper layer with the lock
-	   released. */
-
-	if (smi_info->run_to_completion) {
-		ipmi_smi_msg_received(smi_info->intf, msg);
-	} else {
-		spin_unlock(&(smi_info->si_lock));
-		ipmi_smi_msg_received(smi_info->intf, msg);
-		spin_lock(&(smi_info->si_lock));
-	}
+	/* Deliver the message to the upper layer. */
+	ipmi_smi_msg_received(smi_info->intf, msg);
 }
 
 static void return_hosed_msg(struct smi_info *smi_info, int cCode)
@@ -358,13 +348,6 @@
 	struct timeval t;
 #endif
 
-	/*
-	 * No need to save flags, we aleady have interrupts off and we
-	 * already hold the SMI lock.
-	 */
-	if (!smi_info->run_to_completion)
-		spin_lock(&(smi_info->msg_lock));
-
 	/* Pick the high priority queue first. */
 	if (!list_empty(&(smi_info->hp_xmit_msgs))) {
 		entry = smi_info->hp_xmit_msgs.next;
@@ -402,9 +385,6 @@
 		rv = SI_SM_CALL_WITHOUT_DELAY;
 	}
  out:
-	if (!smi_info->run_to_completion)
-		spin_unlock(&(smi_info->msg_lock));
-
 	return rv;
 }
 
@@ -481,9 +461,7 @@
 
 		start_clear_flags(smi_info);
 		smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
-		spin_unlock(&(smi_info->si_lock));
 		ipmi_smi_watchdog_pretimeout(smi_info->intf);
-		spin_lock(&(smi_info->si_lock));
 	} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
 		/* Messages available. */
 		smi_info->curr_msg = ipmi_alloc_smi_msg();
@@ -889,19 +867,6 @@
 	printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
 #endif
 
-	/*
-	 * last_timeout_jiffies is updated here to avoid
-	 * smi_timeout() handler passing very large time_diff
-	 * value to smi_event_handler() that causes
-	 * the send command to abort.
-	 */
-	smi_info->last_timeout_jiffies = jiffies;
-
-	mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
-
-	if (smi_info->thread)
-		wake_up_process(smi_info->thread);
-
 	if (smi_info->run_to_completion) {
 		/*
 		 * If we are running to completion, then throw it in
@@ -924,16 +889,29 @@
 		return;
 	}
 
-	spin_lock_irqsave(&smi_info->msg_lock, flags);
+	spin_lock_irqsave(&smi_info->si_lock, flags);
 	if (priority > 0)
 		list_add_tail(&msg->link, &smi_info->hp_xmit_msgs);
 	else
 		list_add_tail(&msg->link, &smi_info->xmit_msgs);
-	spin_unlock_irqrestore(&smi_info->msg_lock, flags);
 
-	spin_lock_irqsave(&smi_info->si_lock, flags);
-	if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL)
+	if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) {
+		/*
+		 * last_timeout_jiffies is updated here to avoid
+		 * smi_timeout() handler passing very large time_diff
+		 * value to smi_event_handler() that causes
+		 * the send command to abort.
+		 */
+		smi_info->last_timeout_jiffies = jiffies;
+
+		mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
+
+		if (smi_info->thread)
+			wake_up_process(smi_info->thread);
+
 		start_next_msg(smi_info);
+		smi_event_handler(smi_info, 0);
+	}
 	spin_unlock_irqrestore(&smi_info->si_lock, flags);
 }
 
@@ -1034,16 +1012,19 @@
 static void poll(void *send_info)
 {
 	struct smi_info *smi_info = send_info;
-	unsigned long flags;
+	unsigned long flags = 0;
+	int run_to_completion = smi_info->run_to_completion;
 
 	/*
 	 * Make sure there is some delay in the poll loop so we can
 	 * drive time forward and timeout things.
 	 */
 	udelay(10);
-	spin_lock_irqsave(&smi_info->si_lock, flags);
+	if (!run_to_completion)
+		spin_lock_irqsave(&smi_info->si_lock, flags);
 	smi_event_handler(smi_info, 10);
-	spin_unlock_irqrestore(&smi_info->si_lock, flags);
+	if (!run_to_completion)
+		spin_unlock_irqrestore(&smi_info->si_lock, flags);
 }
 
 static void request_events(void *send_info)
@@ -1680,10 +1661,8 @@
 {
 	struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL);
 
-	if (info) {
+	if (info)
 		spin_lock_init(&info->si_lock);
-		spin_lock_init(&info->msg_lock);
-	}
 	return info;
 }
 
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 34767a6..7ed356e 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -153,7 +153,7 @@
 #endif
 
 static DEFINE_MUTEX(ipmi_watchdog_mutex);
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 static ipmi_user_t watchdog_user;
 static int watchdog_ifnum;
@@ -320,7 +320,7 @@
 MODULE_PARM_DESC(start_now, "Set to 1 to start the watchdog as"
 		 "soon as the driver is loaded.");
 
-module_param(nowayout, int, 0644);
+module_param(nowayout, bool, 0644);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
 		 "(default=CONFIG_WATCHDOG_NOWAYOUT)");
 
@@ -520,6 +520,7 @@
 	msg.cmd = IPMI_WDOG_RESET_TIMER;
 	msg.data = NULL;
 	msg.data_len = 0;
+	atomic_add(2, &panic_done_count);
 	rv = ipmi_request_supply_msgs(watchdog_user,
 				      (struct ipmi_addr *) &addr,
 				      0,
@@ -528,8 +529,8 @@
 				      &panic_halt_heartbeat_smi_msg,
 				      &panic_halt_heartbeat_recv_msg,
 				      1);
-	if (!rv)
-		atomic_add(2, &panic_done_count);
+	if (rv)
+		atomic_sub(2, &panic_done_count);
 }
 
 static struct ipmi_smi_msg panic_halt_smi_msg = {
@@ -553,16 +554,18 @@
 	/* Wait for the messages to be free. */
 	while (atomic_read(&panic_done_count) != 0)
 		ipmi_poll_interface(watchdog_user);
+	atomic_add(2, &panic_done_count);
 	rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
 				&panic_halt_recv_msg,
 				&send_heartbeat_now);
-	if (!rv) {
-		atomic_add(2, &panic_done_count);
-		if (send_heartbeat_now)
-			panic_halt_ipmi_heartbeat();
-	} else
+	if (rv) {
+		atomic_sub(2, &panic_done_count);
 		printk(KERN_WARNING PFX
 		       "Unable to extend the watchdog timeout.");
+	} else {
+		if (send_heartbeat_now)
+			panic_halt_ipmi_heartbeat();
+	}
 	while (atomic_read(&panic_done_count) != 0)
 		ipmi_poll_interface(watchdog_user);
 }
@@ -1164,7 +1167,7 @@
 		if (code == SYS_POWER_OFF || code == SYS_HALT) {
 			/* Disable the WDT if we are shutting down. */
 			ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
-			panic_halt_ipmi_set_timeout();
+			ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
 		} else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
 			/* Set a long timer to let the reboot happens, but
 			   reboot if it hangs, but only if the watchdog
@@ -1172,7 +1175,7 @@
 			timeout = 120;
 			pretimeout = 0;
 			ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
-			panic_halt_ipmi_set_timeout();
+			ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
 		}
 	}
 	return NOTIFY_OK;
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index f434856..a741e41 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -135,7 +135,6 @@
 
 #include <asm/irq.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 /* if you have more than 8 printers, remember to increase LP_NO */
 #define LP_NO 8
@@ -706,16 +705,13 @@
 {
 	unsigned int minor;
 	struct timeval par_timeout;
-	struct compat_timeval __user *tc;
 	int ret;
 
 	minor = iminor(file->f_path.dentry->d_inode);
 	mutex_lock(&lp_mutex);
 	switch (cmd) {
 	case LPSETTIMEOUT:
-		tc = compat_ptr(arg);
-		if (get_user(par_timeout.tv_sec, &tc->tv_sec) ||
-		    get_user(par_timeout.tv_usec, &tc->tv_usec)) {
+		if (compat_get_timeval(&par_timeout, compat_ptr(arg))) {
 			ret = -EFAULT;
 			break;
 		}
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
index 1aeaaba..47ff7e4 100644
--- a/drivers/char/mbcs.c
+++ b/drivers/char/mbcs.c
@@ -28,7 +28,6 @@
 #include <linux/slab.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/intr.h>
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index 5c0d96a..8b78750 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -44,7 +44,6 @@
 #include <linux/slab.h>
 #include <linux/numa.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <linux/atomic.h>
 #include <asm/tlbflush.h>
diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c
index 492dbfb..881c9e5 100644
--- a/drivers/char/mwave/3780i.c
+++ b/drivers/char/mwave/3780i.c
@@ -56,7 +56,6 @@
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 #include "smapi.h"
 #include "mwavedd.h"
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index eaade8a..9df78e2 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -111,7 +111,6 @@
 #include <linux/uaccess.h>
 #include <linux/mutex.h>
 
-#include <asm/system.h>
 
 static DEFINE_MUTEX(nvram_mutex);
 static DEFINE_SPINLOCK(nvram_state_lock);
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c
index bf586ae..d45c334 100644
--- a/drivers/char/nwflash.c
+++ b/drivers/char/nwflash.c
@@ -32,7 +32,6 @@
 #include <asm/io.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 /*****************************************************************************/
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index f6453df..0a484b4 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -60,7 +60,6 @@
 #include <linux/ioctl.h>
 #include <linux/synclink.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/dma.h>
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 872e09a..af94374 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -83,7 +83,6 @@
 #include <linux/ratelimit.h>
 
 #include <asm/current.h>
-#include <asm/system.h>
 
 #ifdef CONFIG_X86
 #include <asm/hpet.h>
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 1ee8ce7..45713f0 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -54,7 +54,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <linux/sonypi.h>
 
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
deleted file mode 100644
index 8b34c65..0000000
--- a/drivers/char/viotape.c
+++ /dev/null
@@ -1,1041 +0,0 @@
-/* -*- linux-c -*-
- *  drivers/char/viotape.c
- *
- *  iSeries Virtual Tape
- *
- *  Authors: Dave Boutcher <boutcher@us.ibm.com>
- *           Ryan Arnold <ryanarn@us.ibm.com>
- *           Colin Devilbiss <devilbis@us.ibm.com>
- *           Stephen Rothwell
- *
- * (C) Copyright 2000-2004 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) anyu 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
- *
- * This routine provides access to tape drives owned and managed by an OS/400
- * partition running on the same box as this Linux partition.
- *
- * All tape operations are performed by sending messages back and forth to
- * the OS/400 partition.  The format of the messages is defined in
- * iseries/vio.h
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/spinlock.h>
-#include <linux/mtio.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/major.h>
-#include <linux/completion.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-
-#include <asm/uaccess.h>
-#include <asm/ioctls.h>
-#include <asm/firmware.h>
-#include <asm/vio.h>
-#include <asm/iseries/vio.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_call_event.h>
-#include <asm/iseries/hv_lp_config.h>
-
-#define VIOTAPE_VERSION		"1.2"
-#define VIOTAPE_MAXREQ		1
-
-#define VIOTAPE_KERN_WARN	KERN_WARNING "viotape: "
-#define VIOTAPE_KERN_INFO	KERN_INFO "viotape: "
-
-static DEFINE_MUTEX(proc_viotape_mutex);
-static int viotape_numdev;
-
-/*
- * The minor number follows the conventions of the SCSI tape drives.  The
- * rewind and mode are encoded in the minor #.  We use this struct to break
- * them out
- */
-struct viot_devinfo_struct {
-	int devno;
-	int mode;
-	int rewind;
-};
-
-#define VIOTAPOP_RESET          0
-#define VIOTAPOP_FSF	        1
-#define VIOTAPOP_BSF	        2
-#define VIOTAPOP_FSR	        3
-#define VIOTAPOP_BSR	        4
-#define VIOTAPOP_WEOF	        5
-#define VIOTAPOP_REW	        6
-#define VIOTAPOP_NOP	        7
-#define VIOTAPOP_EOM	        8
-#define VIOTAPOP_ERASE          9
-#define VIOTAPOP_SETBLK        10
-#define VIOTAPOP_SETDENSITY    11
-#define VIOTAPOP_SETPOS	       12
-#define VIOTAPOP_GETPOS	       13
-#define VIOTAPOP_SETPART       14
-#define VIOTAPOP_UNLOAD        15
-
-enum viotaperc {
-	viotape_InvalidRange = 0x0601,
-	viotape_InvalidToken = 0x0602,
-	viotape_DMAError = 0x0603,
-	viotape_UseError = 0x0604,
-	viotape_ReleaseError = 0x0605,
-	viotape_InvalidTape = 0x0606,
-	viotape_InvalidOp = 0x0607,
-	viotape_TapeErr = 0x0608,
-
-	viotape_AllocTimedOut = 0x0640,
-	viotape_BOTEnc = 0x0641,
-	viotape_BlankTape = 0x0642,
-	viotape_BufferEmpty = 0x0643,
-	viotape_CleanCartFound = 0x0644,
-	viotape_CmdNotAllowed = 0x0645,
-	viotape_CmdNotSupported = 0x0646,
-	viotape_DataCheck = 0x0647,
-	viotape_DecompressErr = 0x0648,
-	viotape_DeviceTimeout = 0x0649,
-	viotape_DeviceUnavail = 0x064a,
-	viotape_DeviceBusy = 0x064b,
-	viotape_EndOfMedia = 0x064c,
-	viotape_EndOfTape = 0x064d,
-	viotape_EquipCheck = 0x064e,
-	viotape_InsufficientRs = 0x064f,
-	viotape_InvalidLogBlk = 0x0650,
-	viotape_LengthError = 0x0651,
-	viotape_LibDoorOpen = 0x0652,
-	viotape_LoadFailure = 0x0653,
-	viotape_NotCapable = 0x0654,
-	viotape_NotOperational = 0x0655,
-	viotape_NotReady = 0x0656,
-	viotape_OpCancelled = 0x0657,
-	viotape_PhyLinkErr = 0x0658,
-	viotape_RdyNotBOT = 0x0659,
-	viotape_TapeMark = 0x065a,
-	viotape_WriteProt = 0x065b
-};
-
-static const struct vio_error_entry viotape_err_table[] = {
-	{ viotape_InvalidRange, EIO, "Internal error" },
-	{ viotape_InvalidToken, EIO, "Internal error" },
-	{ viotape_DMAError, EIO, "DMA error" },
-	{ viotape_UseError, EIO, "Internal error" },
-	{ viotape_ReleaseError, EIO, "Internal error" },
-	{ viotape_InvalidTape, EIO, "Invalid tape device" },
-	{ viotape_InvalidOp, EIO, "Invalid operation" },
-	{ viotape_TapeErr, EIO, "Tape error" },
-	{ viotape_AllocTimedOut, EBUSY, "Allocate timed out" },
-	{ viotape_BOTEnc, EIO, "Beginning of tape encountered" },
-	{ viotape_BlankTape, EIO, "Blank tape" },
-	{ viotape_BufferEmpty, EIO, "Buffer empty" },
-	{ viotape_CleanCartFound, ENOMEDIUM, "Cleaning cartridge found" },
-	{ viotape_CmdNotAllowed, EIO, "Command not allowed" },
-	{ viotape_CmdNotSupported, EIO, "Command not supported" },
-	{ viotape_DataCheck, EIO, "Data check" },
-	{ viotape_DecompressErr, EIO, "Decompression error" },
-	{ viotape_DeviceTimeout, EBUSY, "Device timeout" },
-	{ viotape_DeviceUnavail, EIO, "Device unavailable" },
-	{ viotape_DeviceBusy, EBUSY, "Device busy" },
-	{ viotape_EndOfMedia, ENOSPC, "End of media" },
-	{ viotape_EndOfTape, ENOSPC, "End of tape" },
-	{ viotape_EquipCheck, EIO, "Equipment check" },
-	{ viotape_InsufficientRs, EOVERFLOW, "Insufficient tape resources" },
-	{ viotape_InvalidLogBlk, EIO, "Invalid logical block location" },
-	{ viotape_LengthError, EOVERFLOW, "Length error" },
-	{ viotape_LibDoorOpen, EBUSY, "Door open" },
-	{ viotape_LoadFailure, ENOMEDIUM, "Load failure" },
-	{ viotape_NotCapable, EIO, "Not capable" },
-	{ viotape_NotOperational, EIO, "Not operational" },
-	{ viotape_NotReady, EIO, "Not ready" },
-	{ viotape_OpCancelled, EIO, "Operation cancelled" },
-	{ viotape_PhyLinkErr, EIO, "Physical link error" },
-	{ viotape_RdyNotBOT, EIO, "Ready but not beginning of tape" },
-	{ viotape_TapeMark, EIO, "Tape mark" },
-	{ viotape_WriteProt, EROFS, "Write protection error" },
-	{ 0, 0, NULL },
-};
-
-/* Maximum number of tapes we support */
-#define VIOTAPE_MAX_TAPE	HVMAXARCHITECTEDVIRTUALTAPES
-#define MAX_PARTITIONS		4
-
-/* defines for current tape state */
-#define VIOT_IDLE		0
-#define VIOT_READING		1
-#define VIOT_WRITING		2
-
-/* Our info on the tapes */
-static struct {
-	const char *rsrcname;
-	const char *type;
-	const char *model;
-} viotape_unitinfo[VIOTAPE_MAX_TAPE];
-
-static struct mtget viomtget[VIOTAPE_MAX_TAPE];
-
-static struct class *tape_class;
-
-static struct device *tape_device[VIOTAPE_MAX_TAPE];
-
-/*
- * maintain the current state of each tape (and partition)
- * so that we know when to write EOF marks.
- */
-static struct {
-	unsigned char	cur_part;
-	unsigned char	part_stat_rwi[MAX_PARTITIONS];
-} state[VIOTAPE_MAX_TAPE];
-
-/* We single-thread */
-static struct semaphore reqSem;
-
-/*
- * When we send a request, we use this struct to get the response back
- * from the interrupt handler
- */
-struct op_struct {
-	void			*buffer;
-	dma_addr_t		dmaaddr;
-	size_t			count;
-	int			rc;
-	int			non_blocking;
-	struct completion	com;
-	struct device		*dev;
-	struct op_struct	*next;
-};
-
-static spinlock_t	op_struct_list_lock;
-static struct op_struct	*op_struct_list;
-
-/* forward declaration to resolve interdependence */
-static int chg_state(int index, unsigned char new_state, struct file *file);
-
-/* procfs support */
-static int proc_viotape_show(struct seq_file *m, void *v)
-{
-	int i;
-
-	seq_printf(m, "viotape driver version " VIOTAPE_VERSION "\n");
-	for (i = 0; i < viotape_numdev; i++) {
-		seq_printf(m, "viotape device %d is iSeries resource %10.10s"
-				"type %4.4s, model %3.3s\n",
-				i, viotape_unitinfo[i].rsrcname,
-				viotape_unitinfo[i].type,
-				viotape_unitinfo[i].model);
-	}
-	return 0;
-}
-
-static int proc_viotape_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, proc_viotape_show, NULL);
-}
-
-static const struct file_operations proc_viotape_operations = {
-	.owner		= THIS_MODULE,
-	.open		= proc_viotape_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-/* Decode the device minor number into its parts */
-void get_dev_info(struct inode *ino, struct viot_devinfo_struct *devi)
-{
-	devi->devno = iminor(ino) & 0x1F;
-	devi->mode = (iminor(ino) & 0x60) >> 5;
-	/* if bit is set in the minor, do _not_ rewind automatically */
-	devi->rewind = (iminor(ino) & 0x80) == 0;
-}
-
-/* This is called only from the exit and init paths, so no need for locking */
-static void clear_op_struct_pool(void)
-{
-	while (op_struct_list) {
-		struct op_struct *toFree = op_struct_list;
-		op_struct_list = op_struct_list->next;
-		kfree(toFree);
-	}
-}
-
-/* Likewise, this is only called from the init path */
-static int add_op_structs(int structs)
-{
-	int i;
-
-	for (i = 0; i < structs; ++i) {
-		struct op_struct *new_struct =
-			kmalloc(sizeof(*new_struct), GFP_KERNEL);
-		if (!new_struct) {
-			clear_op_struct_pool();
-			return -ENOMEM;
-		}
-		new_struct->next = op_struct_list;
-		op_struct_list = new_struct;
-	}
-	return 0;
-}
-
-/* Allocate an op structure from our pool */
-static struct op_struct *get_op_struct(void)
-{
-	struct op_struct *retval;
-	unsigned long flags;
-
-	spin_lock_irqsave(&op_struct_list_lock, flags);
-	retval = op_struct_list;
-	if (retval)
-		op_struct_list = retval->next;
-	spin_unlock_irqrestore(&op_struct_list_lock, flags);
-	if (retval) {
-		memset(retval, 0, sizeof(*retval));
-		init_completion(&retval->com);
-	}
-
-	return retval;
-}
-
-/* Return an op structure to our pool */
-static void free_op_struct(struct op_struct *op_struct)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&op_struct_list_lock, flags);
-	op_struct->next = op_struct_list;
-	op_struct_list = op_struct;
-	spin_unlock_irqrestore(&op_struct_list_lock, flags);
-}
-
-/* Map our tape return codes to errno values */
-int tape_rc_to_errno(int tape_rc, char *operation, int tapeno)
-{
-	const struct vio_error_entry *err;
-
-	if (tape_rc == 0)
-		return 0;
-
-	err = vio_lookup_rc(viotape_err_table, tape_rc);
-	printk(VIOTAPE_KERN_WARN "error(%s) 0x%04x on Device %d (%-10s): %s\n",
-			operation, tape_rc, tapeno,
-			viotape_unitinfo[tapeno].rsrcname, err->msg);
-	return -err->errno;
-}
-
-/* Write */
-static ssize_t viotap_write(struct file *file, const char *buf,
-		size_t count, loff_t * ppos)
-{
-	HvLpEvent_Rc hvrc;
-	unsigned short flags = file->f_flags;
-	int noblock = ((flags & O_NONBLOCK) != 0);
-	ssize_t ret;
-	struct viot_devinfo_struct devi;
-	struct op_struct *op = get_op_struct();
-
-	if (op == NULL)
-		return -ENOMEM;
-
-	get_dev_info(file->f_path.dentry->d_inode, &devi);
-
-	/*
-	 * We need to make sure we can send a request.  We use
-	 * a semaphore to keep track of # requests in use.  If
-	 * we are non-blocking, make sure we don't block on the
-	 * semaphore
-	 */
-	if (noblock) {
-		if (down_trylock(&reqSem)) {
-			ret = -EWOULDBLOCK;
-			goto free_op;
-		}
-	} else
-		down(&reqSem);
-
-	/* Allocate a DMA buffer */
-	op->dev = tape_device[devi.devno];
-	op->buffer = dma_alloc_coherent(op->dev, count, &op->dmaaddr,
-			GFP_ATOMIC);
-
-	if (op->buffer == NULL) {
-		printk(VIOTAPE_KERN_WARN
-				"error allocating dma buffer for len %ld\n",
-				count);
-		ret = -EFAULT;
-		goto up_sem;
-	}
-
-	/* Copy the data into the buffer */
-	if (copy_from_user(op->buffer, buf, count)) {
-		printk(VIOTAPE_KERN_WARN "tape: error on copy from user\n");
-		ret = -EFAULT;
-		goto free_dma;
-	}
-
-	op->non_blocking = noblock;
-	init_completion(&op->com);
-	op->count = count;
-
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_tape | viotapewrite,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64)(unsigned long)op, VIOVERSION << 16,
-			((u64)devi.devno << 48) | op->dmaaddr, count, 0, 0);
-	if (hvrc != HvLpEvent_Rc_Good) {
-		printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
-				(int)hvrc);
-		ret = -EIO;
-		goto free_dma;
-	}
-
-	if (noblock)
-		return count;
-
-	wait_for_completion(&op->com);
-
-	if (op->rc)
-		ret = tape_rc_to_errno(op->rc, "write", devi.devno);
-	else {
-		chg_state(devi.devno, VIOT_WRITING, file);
-		ret = op->count;
-	}
-
-free_dma:
-	dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr);
-up_sem:
-	up(&reqSem);
-free_op:
-	free_op_struct(op);
-	return ret;
-}
-
-/* read */
-static ssize_t viotap_read(struct file *file, char *buf, size_t count,
-		loff_t *ptr)
-{
-	HvLpEvent_Rc hvrc;
-	unsigned short flags = file->f_flags;
-	struct op_struct *op = get_op_struct();
-	int noblock = ((flags & O_NONBLOCK) != 0);
-	ssize_t ret;
-	struct viot_devinfo_struct devi;
-
-	if (op == NULL)
-		return -ENOMEM;
-
-	get_dev_info(file->f_path.dentry->d_inode, &devi);
-
-	/*
-	 * We need to make sure we can send a request.  We use
-	 * a semaphore to keep track of # requests in use.  If
-	 * we are non-blocking, make sure we don't block on the
-	 * semaphore
-	 */
-	if (noblock) {
-		if (down_trylock(&reqSem)) {
-			ret = -EWOULDBLOCK;
-			goto free_op;
-		}
-	} else
-		down(&reqSem);
-
-	chg_state(devi.devno, VIOT_READING, file);
-
-	/* Allocate a DMA buffer */
-	op->dev = tape_device[devi.devno];
-	op->buffer = dma_alloc_coherent(op->dev, count, &op->dmaaddr,
-			GFP_ATOMIC);
-	if (op->buffer == NULL) {
-		ret = -EFAULT;
-		goto up_sem;
-	}
-
-	op->count = count;
-	init_completion(&op->com);
-
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_tape | viotaperead,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64)(unsigned long)op, VIOVERSION << 16,
-			((u64)devi.devno << 48) | op->dmaaddr, count, 0, 0);
-	if (hvrc != HvLpEvent_Rc_Good) {
-		printk(VIOTAPE_KERN_WARN "tape hv error on op %d\n",
-				(int)hvrc);
-		ret = -EIO;
-		goto free_dma;
-	}
-
-	wait_for_completion(&op->com);
-
-	if (op->rc)
-		ret = tape_rc_to_errno(op->rc, "read", devi.devno);
-	else {
-		ret = op->count;
-		if (ret && copy_to_user(buf, op->buffer, ret)) {
-			printk(VIOTAPE_KERN_WARN "error on copy_to_user\n");
-			ret = -EFAULT;
-		}
-	}
-
-free_dma:
-	dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr);
-up_sem:
-	up(&reqSem);
-free_op:
-	free_op_struct(op);
-	return ret;
-}
-
-/* ioctl */
-static int viotap_ioctl(struct inode *inode, struct file *file,
-		unsigned int cmd, unsigned long arg)
-{
-	HvLpEvent_Rc hvrc;
-	int ret;
-	struct viot_devinfo_struct devi;
-	struct mtop mtc;
-	u32 myOp;
-	struct op_struct *op = get_op_struct();
-
-	if (op == NULL)
-		return -ENOMEM;
-
-	get_dev_info(file->f_path.dentry->d_inode, &devi);
-
-	down(&reqSem);
-
-	ret = -EINVAL;
-
-	switch (cmd) {
-	case MTIOCTOP:
-		ret = -EFAULT;
-		/*
-		 * inode is null if and only if we (the kernel)
-		 * made the request
-		 */
-		if (inode == NULL)
-			memcpy(&mtc, (void *) arg, sizeof(struct mtop));
-		else if (copy_from_user((char *)&mtc, (char *)arg,
-					sizeof(struct mtop)))
-			goto free_op;
-
-		ret = -EIO;
-		switch (mtc.mt_op) {
-		case MTRESET:
-			myOp = VIOTAPOP_RESET;
-			break;
-		case MTFSF:
-			myOp = VIOTAPOP_FSF;
-			break;
-		case MTBSF:
-			myOp = VIOTAPOP_BSF;
-			break;
-		case MTFSR:
-			myOp = VIOTAPOP_FSR;
-			break;
-		case MTBSR:
-			myOp = VIOTAPOP_BSR;
-			break;
-		case MTWEOF:
-			myOp = VIOTAPOP_WEOF;
-			break;
-		case MTREW:
-			myOp = VIOTAPOP_REW;
-			break;
-		case MTNOP:
-			myOp = VIOTAPOP_NOP;
-			break;
-		case MTEOM:
-			myOp = VIOTAPOP_EOM;
-			break;
-		case MTERASE:
-			myOp = VIOTAPOP_ERASE;
-			break;
-		case MTSETBLK:
-			myOp = VIOTAPOP_SETBLK;
-			break;
-		case MTSETDENSITY:
-			myOp = VIOTAPOP_SETDENSITY;
-			break;
-		case MTTELL:
-			myOp = VIOTAPOP_GETPOS;
-			break;
-		case MTSEEK:
-			myOp = VIOTAPOP_SETPOS;
-			break;
-		case MTSETPART:
-			myOp = VIOTAPOP_SETPART;
-			break;
-		case MTOFFL:
-			myOp = VIOTAPOP_UNLOAD;
-			break;
-		default:
-			printk(VIOTAPE_KERN_WARN "MTIOCTOP called "
-					"with invalid op 0x%x\n", mtc.mt_op);
-			goto free_op;
-		}
-
-		/*
-		 * if we moved the head, we are no longer
-		 * reading or writing
-		 */
-		switch (mtc.mt_op) {
-		case MTFSF:
-		case MTBSF:
-		case MTFSR:
-		case MTBSR:
-		case MTTELL:
-		case MTSEEK:
-		case MTREW:
-			chg_state(devi.devno, VIOT_IDLE, file);
-		}
-
-		init_completion(&op->com);
-		hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-				HvLpEvent_Type_VirtualIo,
-				viomajorsubtype_tape | viotapeop,
-				HvLpEvent_AckInd_DoAck,
-				HvLpEvent_AckType_ImmediateAck,
-				viopath_sourceinst(viopath_hostLp),
-				viopath_targetinst(viopath_hostLp),
-				(u64)(unsigned long)op,
-				VIOVERSION << 16,
-				((u64)devi.devno << 48), 0,
-				(((u64)myOp) << 32) | mtc.mt_count, 0);
-		if (hvrc != HvLpEvent_Rc_Good) {
-			printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
-					(int)hvrc);
-			goto free_op;
-		}
-		wait_for_completion(&op->com);
-		ret = tape_rc_to_errno(op->rc, "tape operation", devi.devno);
-		goto free_op;
-
-	case MTIOCGET:
-		ret = -EIO;
-		init_completion(&op->com);
-		hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-				HvLpEvent_Type_VirtualIo,
-				viomajorsubtype_tape | viotapegetstatus,
-				HvLpEvent_AckInd_DoAck,
-				HvLpEvent_AckType_ImmediateAck,
-				viopath_sourceinst(viopath_hostLp),
-				viopath_targetinst(viopath_hostLp),
-				(u64)(unsigned long)op, VIOVERSION << 16,
-				((u64)devi.devno << 48), 0, 0, 0);
-		if (hvrc != HvLpEvent_Rc_Good) {
-			printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
-					(int)hvrc);
-			goto free_op;
-		}
-		wait_for_completion(&op->com);
-
-		/* Operation is complete - grab the error code */
-		ret = tape_rc_to_errno(op->rc, "get status", devi.devno);
-		free_op_struct(op);
-		up(&reqSem);
-
-		if ((ret == 0) && copy_to_user((void *)arg,
-					&viomtget[devi.devno],
-					sizeof(viomtget[0])))
-			ret = -EFAULT;
-		return ret;
-	case MTIOCPOS:
-		printk(VIOTAPE_KERN_WARN "Got an (unsupported) MTIOCPOS\n");
-		break;
-	default:
-		printk(VIOTAPE_KERN_WARN "got an unsupported ioctl 0x%0x\n",
-				cmd);
-		break;
-	}
-
-free_op:
-	free_op_struct(op);
-	up(&reqSem);
-	return ret;
-}
-
-static long viotap_unlocked_ioctl(struct file *file,
-		unsigned int cmd, unsigned long arg)
-{
-	long rc;
-
-	mutex_lock(&proc_viotape_mutex);
-	rc = viotap_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
-	mutex_unlock(&proc_viotape_mutex);
-	return rc;
-}
-
-static int viotap_open(struct inode *inode, struct file *file)
-{
-	HvLpEvent_Rc hvrc;
-	struct viot_devinfo_struct devi;
-	int ret;
-	struct op_struct *op = get_op_struct();
-
-	if (op == NULL)
-		return -ENOMEM;
-
-	mutex_lock(&proc_viotape_mutex);
-	get_dev_info(file->f_path.dentry->d_inode, &devi);
-
-	/* Note: We currently only support one mode! */
-	if ((devi.devno >= viotape_numdev) || (devi.mode)) {
-		ret = -ENODEV;
-		goto free_op;
-	}
-
-	init_completion(&op->com);
-
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_tape | viotapeopen,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64)(unsigned long)op, VIOVERSION << 16,
-			((u64)devi.devno << 48), 0, 0, 0);
-	if (hvrc != 0) {
-		printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n",
-				(int) hvrc);
-		ret = -EIO;
-		goto free_op;
-	}
-
-	wait_for_completion(&op->com);
-	ret = tape_rc_to_errno(op->rc, "open", devi.devno);
-
-free_op:
-	free_op_struct(op);
-	mutex_unlock(&proc_viotape_mutex);
-	return ret;
-}
-
-
-static int viotap_release(struct inode *inode, struct file *file)
-{
-	HvLpEvent_Rc hvrc;
-	struct viot_devinfo_struct devi;
-	int ret = 0;
-	struct op_struct *op = get_op_struct();
-
-	if (op == NULL)
-		return -ENOMEM;
-	init_completion(&op->com);
-
-	get_dev_info(file->f_path.dentry->d_inode, &devi);
-
-	if (devi.devno >= viotape_numdev) {
-		ret = -ENODEV;
-		goto free_op;
-	}
-
-	chg_state(devi.devno, VIOT_IDLE, file);
-
-	if (devi.rewind) {
-		hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-				HvLpEvent_Type_VirtualIo,
-				viomajorsubtype_tape | viotapeop,
-				HvLpEvent_AckInd_DoAck,
-				HvLpEvent_AckType_ImmediateAck,
-				viopath_sourceinst(viopath_hostLp),
-				viopath_targetinst(viopath_hostLp),
-				(u64)(unsigned long)op, VIOVERSION << 16,
-				((u64)devi.devno << 48), 0,
-				((u64)VIOTAPOP_REW) << 32, 0);
-		wait_for_completion(&op->com);
-
-		tape_rc_to_errno(op->rc, "rewind", devi.devno);
-	}
-
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_tape | viotapeclose,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64)(unsigned long)op, VIOVERSION << 16,
-			((u64)devi.devno << 48), 0, 0, 0);
-	if (hvrc != 0) {
-		printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n",
-				(int) hvrc);
-		ret = -EIO;
-		goto free_op;
-	}
-
-	wait_for_completion(&op->com);
-
-	if (op->rc)
-		printk(VIOTAPE_KERN_WARN "close failed\n");
-
-free_op:
-	free_op_struct(op);
-	return ret;
-}
-
-const struct file_operations viotap_fops = {
-	.owner =		THIS_MODULE,
-	.read =			viotap_read,
-	.write =		viotap_write,
-	.unlocked_ioctl =	viotap_unlocked_ioctl,
-	.open =			viotap_open,
-	.release =		viotap_release,
-	.llseek = 		noop_llseek,
-};
-
-/* Handle interrupt events for tape */
-static void vioHandleTapeEvent(struct HvLpEvent *event)
-{
-	int tapeminor;
-	struct op_struct *op;
-	struct viotapelpevent *tevent = (struct viotapelpevent *)event;
-
-	if (event == NULL) {
-		/* Notification that a partition went away! */
-		if (!viopath_isactive(viopath_hostLp)) {
-			/* TODO! Clean up */
-		}
-		return;
-	}
-
-	tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
-	op = (struct op_struct *)event->xCorrelationToken;
-	switch (tapeminor) {
-	case viotapeopen:
-	case viotapeclose:
-		op->rc = tevent->sub_type_result;
-		complete(&op->com);
-		break;
-	case viotaperead:
-		op->rc = tevent->sub_type_result;
-		op->count = tevent->len;
-		complete(&op->com);
-		break;
-	case viotapewrite:
-		if (op->non_blocking) {
-			dma_free_coherent(op->dev, op->count,
-					op->buffer, op->dmaaddr);
-			free_op_struct(op);
-			up(&reqSem);
-		} else {
-			op->rc = tevent->sub_type_result;
-			op->count = tevent->len;
-			complete(&op->com);
-		}
-		break;
-	case viotapeop:
-	case viotapegetpos:
-	case viotapesetpos:
-	case viotapegetstatus:
-		if (op) {
-			op->count = tevent->u.op.count;
-			op->rc = tevent->sub_type_result;
-			if (!op->non_blocking)
-				complete(&op->com);
-		}
-		break;
-	default:
-		printk(VIOTAPE_KERN_WARN "weird ack\n");
-	}
-}
-
-static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
-{
-	int i = vdev->unit_address;
-	int j;
-	struct device_node *node = vdev->dev.of_node;
-
-	if (i >= VIOTAPE_MAX_TAPE)
-		return -ENODEV;
-	if (!node)
-		return -ENODEV;
-
-	if (i >= viotape_numdev)
-		viotape_numdev = i + 1;
-
-	tape_device[i] = &vdev->dev;
-	viotape_unitinfo[i].rsrcname = of_get_property(node,
-					"linux,vio_rsrcname", NULL);
-	viotape_unitinfo[i].type = of_get_property(node, "linux,vio_type",
-					NULL);
-	viotape_unitinfo[i].model = of_get_property(node, "linux,vio_model",
-					NULL);
-
-	state[i].cur_part = 0;
-	for (j = 0; j < MAX_PARTITIONS; ++j)
-		state[i].part_stat_rwi[j] = VIOT_IDLE;
-	device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL,
-		      "iseries!vt%d", i);
-	device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), NULL,
-		      "iseries!nvt%d", i);
-	printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries "
-			"resource %10.10s type %4.4s, model %3.3s\n",
-			i, viotape_unitinfo[i].rsrcname,
-			viotape_unitinfo[i].type, viotape_unitinfo[i].model);
-	return 0;
-}
-
-static int viotape_remove(struct vio_dev *vdev)
-{
-	int i = vdev->unit_address;
-
-	device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
-	device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
-	return 0;
-}
-
-/**
- * viotape_device_table: Used by vio.c to match devices that we
- * support.
- */
-static struct vio_device_id viotape_device_table[] __devinitdata = {
-	{ "byte", "IBM,iSeries-viotape" },
-	{ "", "" }
-};
-MODULE_DEVICE_TABLE(vio, viotape_device_table);
-
-static struct vio_driver viotape_driver = {
-	.id_table = viotape_device_table,
-	.probe = viotape_probe,
-	.remove = viotape_remove,
-	.driver = {
-		.name = "viotape",
-		.owner = THIS_MODULE,
-	}
-};
-
-
-int __init viotap_init(void)
-{
-	int ret;
-
-	if (!firmware_has_feature(FW_FEATURE_ISERIES))
-		return -ENODEV;
-
-	op_struct_list = NULL;
-	if ((ret = add_op_structs(VIOTAPE_MAXREQ)) < 0) {
-		printk(VIOTAPE_KERN_WARN "couldn't allocate op structs\n");
-		return ret;
-	}
-	spin_lock_init(&op_struct_list_lock);
-
-	sema_init(&reqSem, VIOTAPE_MAXREQ);
-
-	if (viopath_hostLp == HvLpIndexInvalid) {
-		vio_set_hostlp();
-		if (viopath_hostLp == HvLpIndexInvalid) {
-			ret = -ENODEV;
-			goto clear_op;
-		}
-	}
-
-	ret = viopath_open(viopath_hostLp, viomajorsubtype_tape,
-			VIOTAPE_MAXREQ + 2);
-	if (ret) {
-		printk(VIOTAPE_KERN_WARN
-				"error on viopath_open to hostlp %d\n", ret);
-		ret = -EIO;
-		goto clear_op;
-	}
-
-	printk(VIOTAPE_KERN_INFO "vers " VIOTAPE_VERSION
-			", hosting partition %d\n", viopath_hostLp);
-
-	vio_setHandler(viomajorsubtype_tape, vioHandleTapeEvent);
-
-	ret = register_chrdev(VIOTAPE_MAJOR, "viotape", &viotap_fops);
-	if (ret < 0) {
-		printk(VIOTAPE_KERN_WARN "Error registering viotape device\n");
-		goto clear_handler;
-	}
-
-	tape_class = class_create(THIS_MODULE, "tape");
-	if (IS_ERR(tape_class)) {
-		printk(VIOTAPE_KERN_WARN "Unable to allocate class\n");
-		ret = PTR_ERR(tape_class);
-		goto unreg_chrdev;
-	}
-
-	ret = vio_register_driver(&viotape_driver);
-	if (ret)
-		goto unreg_class;
-
-	proc_create("iSeries/viotape", S_IFREG|S_IRUGO, NULL,
-		    &proc_viotape_operations);
-
-	return 0;
-
-unreg_class:
-	class_destroy(tape_class);
-unreg_chrdev:
-	unregister_chrdev(VIOTAPE_MAJOR, "viotape");
-clear_handler:
-	vio_clearHandler(viomajorsubtype_tape);
-	viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2);
-clear_op:
-	clear_op_struct_pool();
-	return ret;
-}
-
-/* Give a new state to the tape object */
-static int chg_state(int index, unsigned char new_state, struct file *file)
-{
-	unsigned char *cur_state =
-	    &state[index].part_stat_rwi[state[index].cur_part];
-	int rc = 0;
-
-	/* if the same state, don't bother */
-	if (*cur_state == new_state)
-		return 0;
-
-	/* write an EOF if changing from writing to some other state */
-	if (*cur_state == VIOT_WRITING) {
-		struct mtop write_eof = { MTWEOF, 1 };
-
-		rc = viotap_ioctl(NULL, file, MTIOCTOP,
-				  (unsigned long)&write_eof);
-	}
-	*cur_state = new_state;
-	return rc;
-}
-
-/* Cleanup */
-static void __exit viotap_exit(void)
-{
-	remove_proc_entry("iSeries/viotape", NULL);
-	vio_unregister_driver(&viotape_driver);
-	class_destroy(tape_class);
-	unregister_chrdev(VIOTAPE_MAJOR, "viotape");
-	viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2);
-	vio_clearHandler(viomajorsubtype_tape);
-	clear_op_struct_pool();
-}
-
-MODULE_LICENSE("GPL");
-module_init(viotap_init);
-module_exit(viotap_exit);
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index b58b561..ddf86b6 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1038,12 +1038,6 @@
 	.attrs = port_sysfs_entries,
 };
 
-static int debugfs_open(struct inode *inode, struct file *filp)
-{
-	filp->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
 			    size_t count, loff_t *offp)
 {
@@ -1087,7 +1081,7 @@
 
 static const struct file_operations port_debugfs_ops = {
 	.owner = THIS_MODULE,
-	.open  = debugfs_open,
+	.open  = simple_open,
 	.read  = debugfs_read,
 };
 
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
index e90e1c7..31ba11c 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -89,7 +89,6 @@
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #ifdef CONFIG_OF
 /* For open firmware. */
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 9b3cd08..165e1fe 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -8,3 +8,40 @@
 
 config HAVE_MACH_CLKDEV
 	bool
+
+config COMMON_CLK
+	bool
+	select HAVE_CLK_PREPARE
+	---help---
+	  The common clock framework is a single definition of struct
+	  clk, useful across many platforms, as well as an
+	  implementation of the clock API in include/linux/clk.h.
+	  Architectures utilizing the common struct clk should select
+	  this option.
+
+menu "Common Clock Framework"
+	depends on COMMON_CLK
+
+config COMMON_CLK_DISABLE_UNUSED
+	bool "Disabled unused clocks at boot"
+	depends on COMMON_CLK
+	---help---
+	  Traverses the entire clock tree and disables any clocks that are
+	  enabled in hardware but have not been enabled by any device drivers.
+	  This saves power and keeps the software model of the clock in line
+	  with reality.
+
+	  If in doubt, say "N".
+
+config COMMON_CLK_DEBUG
+	bool "DebugFS representation of clock tree"
+	depends on COMMON_CLK
+	select DEBUG_FS
+	---help---
+	  Creates a directory hierchy in debugfs for visualizing the clk
+	  tree structure.  Each directory contains read-only members
+	  that export information specific to that clk node: clk_rate,
+	  clk_flags, clk_prepare_count, clk_enable_count &
+	  clk_notifier_count.
+
+endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 07613fa..1f736bc 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,2 +1,4 @@
 
 obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
+obj-$(CONFIG_COMMON_CLK)	+= clk.o clk-fixed-rate.o clk-gate.o \
+				   clk-mux.o clk-divider.o
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
new file mode 100644
index 0000000..d5ac6a7
--- /dev/null
+++ b/drivers/clk/clk-divider.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Adjustable divider clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/string.h>
+
+/*
+ * DOC: basic adjustable divider clock that cannot gate
+ *
+ * Traits of this clock:
+ * prepare - clk_prepare only ensures that parents are prepared
+ * enable - clk_enable only ensures that parents are enabled
+ * rate - rate is adjustable.  clk->rate = parent->rate / divisor
+ * parent - fixed parent.  No clk_set_parent support
+ */
+
+#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
+
+#define div_mask(d)	((1 << (d->width)) - 1)
+
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_divider *divider = to_clk_divider(hw);
+	unsigned int div;
+
+	div = readl(divider->reg) >> divider->shift;
+	div &= div_mask(divider);
+
+	if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
+		div++;
+
+	return parent_rate / div;
+}
+EXPORT_SYMBOL_GPL(clk_divider_recalc_rate);
+
+/*
+ * The reverse of DIV_ROUND_UP: The maximum number which
+ * divided by m is r
+ */
+#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
+
+static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
+		unsigned long *best_parent_rate)
+{
+	struct clk_divider *divider = to_clk_divider(hw);
+	int i, bestdiv = 0;
+	unsigned long parent_rate, best = 0, now, maxdiv;
+
+	if (!rate)
+		rate = 1;
+
+	maxdiv = (1 << divider->width);
+
+	if (divider->flags & CLK_DIVIDER_ONE_BASED)
+		maxdiv--;
+
+	if (!best_parent_rate) {
+		parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
+		bestdiv = DIV_ROUND_UP(parent_rate, rate);
+		bestdiv = bestdiv == 0 ? 1 : bestdiv;
+		bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
+		return bestdiv;
+	}
+
+	/*
+	 * The maximum divider we can use without overflowing
+	 * unsigned long in rate * i below
+	 */
+	maxdiv = min(ULONG_MAX / rate, maxdiv);
+
+	for (i = 1; i <= maxdiv; i++) {
+		parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
+				MULT_ROUND_UP(rate, i));
+		now = parent_rate / i;
+		if (now <= rate && now > best) {
+			bestdiv = i;
+			best = now;
+			*best_parent_rate = parent_rate;
+		}
+	}
+
+	if (!bestdiv) {
+		bestdiv = (1 << divider->width);
+		if (divider->flags & CLK_DIVIDER_ONE_BASED)
+			bestdiv--;
+		*best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
+	}
+
+	return bestdiv;
+}
+
+static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	int div;
+	div = clk_divider_bestdiv(hw, rate, prate);
+
+	if (prate)
+		return *prate / div;
+	else {
+		unsigned long r;
+		r = __clk_get_rate(__clk_get_parent(hw->clk));
+		return r / div;
+	}
+}
+EXPORT_SYMBOL_GPL(clk_divider_round_rate);
+
+static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate)
+{
+	struct clk_divider *divider = to_clk_divider(hw);
+	unsigned int div;
+	unsigned long flags = 0;
+	u32 val;
+
+	div = __clk_get_rate(__clk_get_parent(hw->clk)) / rate;
+
+	if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
+		div--;
+
+	if (div > div_mask(divider))
+		div = div_mask(divider);
+
+	if (divider->lock)
+		spin_lock_irqsave(divider->lock, flags);
+
+	val = readl(divider->reg);
+	val &= ~(div_mask(divider) << divider->shift);
+	val |= div << divider->shift;
+	writel(val, divider->reg);
+
+	if (divider->lock)
+		spin_unlock_irqrestore(divider->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_divider_set_rate);
+
+struct clk_ops clk_divider_ops = {
+	.recalc_rate = clk_divider_recalc_rate,
+	.round_rate = clk_divider_round_rate,
+	.set_rate = clk_divider_set_rate,
+};
+EXPORT_SYMBOL_GPL(clk_divider_ops);
+
+struct clk *clk_register_divider(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags, spinlock_t *lock)
+{
+	struct clk_divider *div;
+	struct clk *clk;
+
+	div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
+
+	if (!div) {
+		pr_err("%s: could not allocate divider clk\n", __func__);
+		return NULL;
+	}
+
+	/* struct clk_divider assignments */
+	div->reg = reg;
+	div->shift = shift;
+	div->width = width;
+	div->flags = clk_divider_flags;
+	div->lock = lock;
+
+	if (parent_name) {
+		div->parent[0] = kstrdup(parent_name, GFP_KERNEL);
+		if (!div->parent[0])
+			goto out;
+	}
+
+	clk = clk_register(dev, name,
+			&clk_divider_ops, &div->hw,
+			div->parent,
+			(parent_name ? 1 : 0),
+			flags);
+	if (clk)
+		return clk;
+
+out:
+	kfree(div->parent[0]);
+	kfree(div);
+
+	return NULL;
+}
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c
new file mode 100644
index 0000000..90c79fb
--- /dev/null
+++ b/drivers/clk/clk-fixed-rate.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Fixed rate clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+/*
+ * DOC: basic fixed-rate clock that cannot gate
+ *
+ * Traits of this clock:
+ * prepare - clk_(un)prepare only ensures parents are prepared
+ * enable - clk_enable only ensures parents are enabled
+ * rate - rate is always a fixed value.  No clk_set_rate support
+ * parent - fixed parent.  No clk_set_parent support
+ */
+
+#define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw)
+
+static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	return to_clk_fixed_rate(hw)->fixed_rate;
+}
+EXPORT_SYMBOL_GPL(clk_fixed_rate_recalc_rate);
+
+struct clk_ops clk_fixed_rate_ops = {
+	.recalc_rate = clk_fixed_rate_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(clk_fixed_rate_ops);
+
+struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		unsigned long fixed_rate)
+{
+	struct clk_fixed_rate *fixed;
+	char **parent_names = NULL;
+	u8 len;
+
+	fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
+
+	if (!fixed) {
+		pr_err("%s: could not allocate fixed clk\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* struct clk_fixed_rate assignments */
+	fixed->fixed_rate = fixed_rate;
+
+	if (parent_name) {
+		parent_names = kmalloc(sizeof(char *), GFP_KERNEL);
+
+		if (! parent_names)
+			goto out;
+
+		len = sizeof(char) * strlen(parent_name);
+
+		parent_names[0] = kmalloc(len, GFP_KERNEL);
+
+		if (!parent_names[0])
+			goto out;
+
+		strncpy(parent_names[0], parent_name, len);
+	}
+
+out:
+	return clk_register(dev, name,
+			&clk_fixed_rate_ops, &fixed->hw,
+			parent_names,
+			(parent_name ? 1 : 0),
+			flags);
+}
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
new file mode 100644
index 0000000..b5902e2
--- /dev/null
+++ b/drivers/clk/clk-gate.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Gated clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/string.h>
+
+/**
+ * DOC: basic gatable clock which can gate and ungate it's ouput
+ *
+ * Traits of this clock:
+ * prepare - clk_(un)prepare only ensures parent is (un)prepared
+ * enable - clk_enable and clk_disable are functional & control gating
+ * rate - inherits rate from parent.  No clk_set_rate support
+ * parent - fixed parent.  No clk_set_parent support
+ */
+
+#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+
+static void clk_gate_set_bit(struct clk_gate *gate)
+{
+	u32 reg;
+	unsigned long flags = 0;
+
+	if (gate->lock)
+		spin_lock_irqsave(gate->lock, flags);
+
+	reg = readl(gate->reg);
+	reg |= BIT(gate->bit_idx);
+	writel(reg, gate->reg);
+
+	if (gate->lock)
+		spin_unlock_irqrestore(gate->lock, flags);
+}
+
+static void clk_gate_clear_bit(struct clk_gate *gate)
+{
+	u32 reg;
+	unsigned long flags = 0;
+
+	if (gate->lock)
+		spin_lock_irqsave(gate->lock, flags);
+
+	reg = readl(gate->reg);
+	reg &= ~BIT(gate->bit_idx);
+	writel(reg, gate->reg);
+
+	if (gate->lock)
+		spin_unlock_irqrestore(gate->lock, flags);
+}
+
+static int clk_gate_enable(struct clk_hw *hw)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+
+	if (gate->flags & CLK_GATE_SET_TO_DISABLE)
+		clk_gate_clear_bit(gate);
+	else
+		clk_gate_set_bit(gate);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_gate_enable);
+
+static void clk_gate_disable(struct clk_hw *hw)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+
+	if (gate->flags & CLK_GATE_SET_TO_DISABLE)
+		clk_gate_set_bit(gate);
+	else
+		clk_gate_clear_bit(gate);
+}
+EXPORT_SYMBOL_GPL(clk_gate_disable);
+
+static int clk_gate_is_enabled(struct clk_hw *hw)
+{
+	u32 reg;
+	struct clk_gate *gate = to_clk_gate(hw);
+
+	reg = readl(gate->reg);
+
+	/* if a set bit disables this clk, flip it before masking */
+	if (gate->flags & CLK_GATE_SET_TO_DISABLE)
+		reg ^= BIT(gate->bit_idx);
+
+	reg &= BIT(gate->bit_idx);
+
+	return reg ? 1 : 0;
+}
+EXPORT_SYMBOL_GPL(clk_gate_is_enabled);
+
+struct clk_ops clk_gate_ops = {
+	.enable = clk_gate_enable,
+	.disable = clk_gate_disable,
+	.is_enabled = clk_gate_is_enabled,
+};
+EXPORT_SYMBOL_GPL(clk_gate_ops);
+
+struct clk *clk_register_gate(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock)
+{
+	struct clk_gate *gate;
+	struct clk *clk;
+
+	gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
+
+	if (!gate) {
+		pr_err("%s: could not allocate gated clk\n", __func__);
+		return NULL;
+	}
+
+	/* struct clk_gate assignments */
+	gate->reg = reg;
+	gate->bit_idx = bit_idx;
+	gate->flags = clk_gate_flags;
+	gate->lock = lock;
+
+	if (parent_name) {
+		gate->parent[0] = kstrdup(parent_name, GFP_KERNEL);
+		if (!gate->parent[0])
+			goto out;
+	}
+
+	clk = clk_register(dev, name,
+			&clk_gate_ops, &gate->hw,
+			gate->parent,
+			(parent_name ? 1 : 0),
+			flags);
+	if (clk)
+		return clk;
+out:
+	kfree(gate->parent[0]);
+	kfree(gate);
+
+	return NULL;
+}
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
new file mode 100644
index 0000000..c71ad1f
--- /dev/null
+++ b/drivers/clk/clk-mux.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Simple multiplexer clock implementation
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+/*
+ * DOC: basic adjustable multiplexer clock that cannot gate
+ *
+ * Traits of this clock:
+ * prepare - clk_prepare only ensures that parents are prepared
+ * enable - clk_enable only ensures that parents are enabled
+ * rate - rate is only affected by parent switching.  No clk_set_rate support
+ * parent - parent is adjustable through clk_set_parent
+ */
+
+#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw)
+
+static u8 clk_mux_get_parent(struct clk_hw *hw)
+{
+	struct clk_mux *mux = to_clk_mux(hw);
+	u32 val;
+
+	/*
+	 * FIXME need a mux-specific flag to determine if val is bitwise or numeric
+	 * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1
+	 * to 0x7 (index starts at one)
+	 * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
+	 * val = 0x4 really means "bit 2, index starts at bit 0"
+	 */
+	val = readl(mux->reg) >> mux->shift;
+	val &= (1 << mux->width) - 1;
+
+	if (val && (mux->flags & CLK_MUX_INDEX_BIT))
+		val = ffs(val) - 1;
+
+	if (val && (mux->flags & CLK_MUX_INDEX_ONE))
+		val--;
+
+	if (val >= __clk_get_num_parents(hw->clk))
+		return -EINVAL;
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(clk_mux_get_parent);
+
+static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_mux *mux = to_clk_mux(hw);
+	u32 val;
+	unsigned long flags = 0;
+
+	if (mux->flags & CLK_MUX_INDEX_BIT)
+		index = (1 << ffs(index));
+
+	if (mux->flags & CLK_MUX_INDEX_ONE)
+		index++;
+
+	if (mux->lock)
+		spin_lock_irqsave(mux->lock, flags);
+
+	val = readl(mux->reg);
+	val &= ~(((1 << mux->width) - 1) << mux->shift);
+	val |= index << mux->shift;
+	writel(val, mux->reg);
+
+	if (mux->lock)
+		spin_unlock_irqrestore(mux->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_mux_set_parent);
+
+struct clk_ops clk_mux_ops = {
+	.get_parent = clk_mux_get_parent,
+	.set_parent = clk_mux_set_parent,
+};
+EXPORT_SYMBOL_GPL(clk_mux_ops);
+
+struct clk *clk_register_mux(struct device *dev, const char *name,
+		char **parent_names, u8 num_parents, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_mux_flags, spinlock_t *lock)
+{
+	struct clk_mux *mux;
+
+	mux = kmalloc(sizeof(struct clk_mux), GFP_KERNEL);
+
+	if (!mux) {
+		pr_err("%s: could not allocate mux clk\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* struct clk_mux assignments */
+	mux->reg = reg;
+	mux->shift = shift;
+	mux->width = width;
+	mux->flags = clk_mux_flags;
+	mux->lock = lock;
+
+	return clk_register(dev, name, &clk_mux_ops, &mux->hw,
+			parent_names, num_parents, flags);
+}
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000..9cf6f59e
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,1461 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ * Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Standard functionality for the common clock API.  See Documentation/clk.txt
+ */
+
+#include <linux/clk-private.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+static DEFINE_SPINLOCK(enable_lock);
+static DEFINE_MUTEX(prepare_lock);
+
+static HLIST_HEAD(clk_root_list);
+static HLIST_HEAD(clk_orphan_list);
+static LIST_HEAD(clk_notifier_list);
+
+/***        debugfs support        ***/
+
+#ifdef CONFIG_COMMON_CLK_DEBUG
+#include <linux/debugfs.h>
+
+static struct dentry *rootdir;
+static struct dentry *orphandir;
+static int inited = 0;
+
+/* caller must hold prepare_lock */
+static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
+{
+	struct dentry *d;
+	int ret = -ENOMEM;
+
+	if (!clk || !pdentry) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	d = debugfs_create_dir(clk->name, pdentry);
+	if (!d)
+		goto out;
+
+	clk->dentry = d;
+
+	d = debugfs_create_u32("clk_rate", S_IRUGO, clk->dentry,
+			(u32 *)&clk->rate);
+	if (!d)
+		goto err_out;
+
+	d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry,
+			(u32 *)&clk->flags);
+	if (!d)
+		goto err_out;
+
+	d = debugfs_create_u32("clk_prepare_count", S_IRUGO, clk->dentry,
+			(u32 *)&clk->prepare_count);
+	if (!d)
+		goto err_out;
+
+	d = debugfs_create_u32("clk_enable_count", S_IRUGO, clk->dentry,
+			(u32 *)&clk->enable_count);
+	if (!d)
+		goto err_out;
+
+	d = debugfs_create_u32("clk_notifier_count", S_IRUGO, clk->dentry,
+			(u32 *)&clk->notifier_count);
+	if (!d)
+		goto err_out;
+
+	ret = 0;
+	goto out;
+
+err_out:
+	debugfs_remove(clk->dentry);
+out:
+	return ret;
+}
+
+/* caller must hold prepare_lock */
+static int clk_debug_create_subtree(struct clk *clk, struct dentry *pdentry)
+{
+	struct clk *child;
+	struct hlist_node *tmp;
+	int ret = -EINVAL;;
+
+	if (!clk || !pdentry)
+		goto out;
+
+	ret = clk_debug_create_one(clk, pdentry);
+
+	if (ret)
+		goto out;
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node)
+		clk_debug_create_subtree(child, clk->dentry);
+
+	ret = 0;
+out:
+	return ret;
+}
+
+/**
+ * clk_debug_register - add a clk node to the debugfs clk tree
+ * @clk: the clk being added to the debugfs clk tree
+ *
+ * Dynamically adds a clk to the debugfs clk tree if debugfs has been
+ * initialized.  Otherwise it bails out early since the debugfs clk tree
+ * will be created lazily by clk_debug_init as part of a late_initcall.
+ *
+ * Caller must hold prepare_lock.  Only clk_init calls this function (so
+ * far) so this is taken care.
+ */
+static int clk_debug_register(struct clk *clk)
+{
+	struct clk *parent;
+	struct dentry *pdentry;
+	int ret = 0;
+
+	if (!inited)
+		goto out;
+
+	parent = clk->parent;
+
+	/*
+	 * Check to see if a clk is a root clk.  Also check that it is
+	 * safe to add this clk to debugfs
+	 */
+	if (!parent)
+		if (clk->flags & CLK_IS_ROOT)
+			pdentry = rootdir;
+		else
+			pdentry = orphandir;
+	else
+		if (parent->dentry)
+			pdentry = parent->dentry;
+		else
+			goto out;
+
+	ret = clk_debug_create_subtree(clk, pdentry);
+
+out:
+	return ret;
+}
+
+/**
+ * clk_debug_init - lazily create the debugfs clk tree visualization
+ *
+ * clks are often initialized very early during boot before memory can
+ * be dynamically allocated and well before debugfs is setup.
+ * clk_debug_init walks the clk tree hierarchy while holding
+ * prepare_lock and creates the topology as part of a late_initcall,
+ * thus insuring that clks initialized very early will still be
+ * represented in the debugfs clk tree.  This function should only be
+ * called once at boot-time, and all other clks added dynamically will
+ * be done so with clk_debug_register.
+ */
+static int __init clk_debug_init(void)
+{
+	struct clk *clk;
+	struct hlist_node *tmp;
+
+	rootdir = debugfs_create_dir("clk", NULL);
+
+	if (!rootdir)
+		return -ENOMEM;
+
+	orphandir = debugfs_create_dir("orphans", rootdir);
+
+	if (!orphandir)
+		return -ENOMEM;
+
+	mutex_lock(&prepare_lock);
+
+	hlist_for_each_entry(clk, tmp, &clk_root_list, child_node)
+		clk_debug_create_subtree(clk, rootdir);
+
+	hlist_for_each_entry(clk, tmp, &clk_orphan_list, child_node)
+		clk_debug_create_subtree(clk, orphandir);
+
+	inited = 1;
+
+	mutex_unlock(&prepare_lock);
+
+	return 0;
+}
+late_initcall(clk_debug_init);
+#else
+static inline int clk_debug_register(struct clk *clk) { return 0; }
+#endif /* CONFIG_COMMON_CLK_DEBUG */
+
+#ifdef CONFIG_COMMON_CLK_DISABLE_UNUSED
+/* caller must hold prepare_lock */
+static void clk_disable_unused_subtree(struct clk *clk)
+{
+	struct clk *child;
+	struct hlist_node *tmp;
+	unsigned long flags;
+
+	if (!clk)
+		goto out;
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node)
+		clk_disable_unused_subtree(child);
+
+	spin_lock_irqsave(&enable_lock, flags);
+
+	if (clk->enable_count)
+		goto unlock_out;
+
+	if (clk->flags & CLK_IGNORE_UNUSED)
+		goto unlock_out;
+
+	if (__clk_is_enabled(clk) && clk->ops->disable)
+		clk->ops->disable(clk->hw);
+
+unlock_out:
+	spin_unlock_irqrestore(&enable_lock, flags);
+
+out:
+	return;
+}
+
+static int clk_disable_unused(void)
+{
+	struct clk *clk;
+	struct hlist_node *tmp;
+
+	mutex_lock(&prepare_lock);
+
+	hlist_for_each_entry(clk, tmp, &clk_root_list, child_node)
+		clk_disable_unused_subtree(clk);
+
+	hlist_for_each_entry(clk, tmp, &clk_orphan_list, child_node)
+		clk_disable_unused_subtree(clk);
+
+	mutex_unlock(&prepare_lock);
+
+	return 0;
+}
+late_initcall(clk_disable_unused);
+#else
+static inline int clk_disable_unused(struct clk *clk) { return 0; }
+#endif /* CONFIG_COMMON_CLK_DISABLE_UNUSED */
+
+/***    helper functions   ***/
+
+inline const char *__clk_get_name(struct clk *clk)
+{
+	return !clk ? NULL : clk->name;
+}
+
+inline struct clk_hw *__clk_get_hw(struct clk *clk)
+{
+	return !clk ? NULL : clk->hw;
+}
+
+inline u8 __clk_get_num_parents(struct clk *clk)
+{
+	return !clk ? -EINVAL : clk->num_parents;
+}
+
+inline struct clk *__clk_get_parent(struct clk *clk)
+{
+	return !clk ? NULL : clk->parent;
+}
+
+inline int __clk_get_enable_count(struct clk *clk)
+{
+	return !clk ? -EINVAL : clk->enable_count;
+}
+
+inline int __clk_get_prepare_count(struct clk *clk)
+{
+	return !clk ? -EINVAL : clk->prepare_count;
+}
+
+unsigned long __clk_get_rate(struct clk *clk)
+{
+	unsigned long ret;
+
+	if (!clk) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = clk->rate;
+
+	if (clk->flags & CLK_IS_ROOT)
+		goto out;
+
+	if (!clk->parent)
+		ret = -ENODEV;
+
+out:
+	return ret;
+}
+
+inline unsigned long __clk_get_flags(struct clk *clk)
+{
+	return !clk ? -EINVAL : clk->flags;
+}
+
+int __clk_is_enabled(struct clk *clk)
+{
+	int ret;
+
+	if (!clk)
+		return -EINVAL;
+
+	/*
+	 * .is_enabled is only mandatory for clocks that gate
+	 * fall back to software usage counter if .is_enabled is missing
+	 */
+	if (!clk->ops->is_enabled) {
+		ret = clk->enable_count ? 1 : 0;
+		goto out;
+	}
+
+	ret = clk->ops->is_enabled(clk->hw);
+out:
+	return ret;
+}
+
+static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
+{
+	struct clk *child;
+	struct clk *ret;
+	struct hlist_node *tmp;
+
+	if (!strcmp(clk->name, name))
+		return clk;
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+		ret = __clk_lookup_subtree(name, child);
+		if (ret)
+			return ret;
+	}
+
+	return NULL;
+}
+
+struct clk *__clk_lookup(const char *name)
+{
+	struct clk *root_clk;
+	struct clk *ret;
+	struct hlist_node *tmp;
+
+	if (!name)
+		return NULL;
+
+	/* search the 'proper' clk tree first */
+	hlist_for_each_entry(root_clk, tmp, &clk_root_list, child_node) {
+		ret = __clk_lookup_subtree(name, root_clk);
+		if (ret)
+			return ret;
+	}
+
+	/* if not found, then search the orphan tree */
+	hlist_for_each_entry(root_clk, tmp, &clk_orphan_list, child_node) {
+		ret = __clk_lookup_subtree(name, root_clk);
+		if (ret)
+			return ret;
+	}
+
+	return NULL;
+}
+
+/***        clk api        ***/
+
+void __clk_unprepare(struct clk *clk)
+{
+	if (!clk)
+		return;
+
+	if (WARN_ON(clk->prepare_count == 0))
+		return;
+
+	if (--clk->prepare_count > 0)
+		return;
+
+	WARN_ON(clk->enable_count > 0);
+
+	if (clk->ops->unprepare)
+		clk->ops->unprepare(clk->hw);
+
+	__clk_unprepare(clk->parent);
+}
+
+/**
+ * clk_unprepare - undo preparation of a clock source
+ * @clk: the clk being unprepare
+ *
+ * clk_unprepare may sleep, which differentiates it from clk_disable.  In a
+ * simple case, clk_unprepare can be used instead of clk_disable to gate a clk
+ * if the operation may sleep.  One example is a clk which is accessed over
+ * I2c.  In the complex case a clk gate operation may require a fast and a slow
+ * part.  It is this reason that clk_unprepare and clk_disable are not mutually
+ * exclusive.  In fact clk_disable must be called before clk_unprepare.
+ */
+void clk_unprepare(struct clk *clk)
+{
+	mutex_lock(&prepare_lock);
+	__clk_unprepare(clk);
+	mutex_unlock(&prepare_lock);
+}
+EXPORT_SYMBOL_GPL(clk_unprepare);
+
+int __clk_prepare(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk)
+		return 0;
+
+	if (clk->prepare_count == 0) {
+		ret = __clk_prepare(clk->parent);
+		if (ret)
+			return ret;
+
+		if (clk->ops->prepare) {
+			ret = clk->ops->prepare(clk->hw);
+			if (ret) {
+				__clk_unprepare(clk->parent);
+				return ret;
+			}
+		}
+	}
+
+	clk->prepare_count++;
+
+	return 0;
+}
+
+/**
+ * clk_prepare - prepare a clock source
+ * @clk: the clk being prepared
+ *
+ * clk_prepare may sleep, which differentiates it from clk_enable.  In a simple
+ * case, clk_prepare can be used instead of clk_enable to ungate a clk if the
+ * operation may sleep.  One example is a clk which is accessed over I2c.  In
+ * the complex case a clk ungate operation may require a fast and a slow part.
+ * It is this reason that clk_prepare and clk_enable are not mutually
+ * exclusive.  In fact clk_prepare must be called before clk_enable.
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int clk_prepare(struct clk *clk)
+{
+	int ret;
+
+	mutex_lock(&prepare_lock);
+	ret = __clk_prepare(clk);
+	mutex_unlock(&prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_prepare);
+
+static void __clk_disable(struct clk *clk)
+{
+	if (!clk)
+		return;
+
+	if (WARN_ON(clk->enable_count == 0))
+		return;
+
+	if (--clk->enable_count > 0)
+		return;
+
+	if (clk->ops->disable)
+		clk->ops->disable(clk->hw);
+
+	__clk_disable(clk->parent);
+}
+
+/**
+ * clk_disable - gate a clock
+ * @clk: the clk being gated
+ *
+ * clk_disable must not sleep, which differentiates it from clk_unprepare.  In
+ * a simple case, clk_disable can be used instead of clk_unprepare to gate a
+ * clk if the operation is fast and will never sleep.  One example is a
+ * SoC-internal clk which is controlled via simple register writes.  In the
+ * complex case a clk gate operation may require a fast and a slow part.  It is
+ * this reason that clk_unprepare and clk_disable are not mutually exclusive.
+ * In fact clk_disable must be called before clk_unprepare.
+ */
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&enable_lock, flags);
+	__clk_disable(clk);
+	spin_unlock_irqrestore(&enable_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+static int __clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk)
+		return 0;
+
+	if (WARN_ON(clk->prepare_count == 0))
+		return -ESHUTDOWN;
+
+	if (clk->enable_count == 0) {
+		ret = __clk_enable(clk->parent);
+
+		if (ret)
+			return ret;
+
+		if (clk->ops->enable) {
+			ret = clk->ops->enable(clk->hw);
+			if (ret) {
+				__clk_disable(clk->parent);
+				return ret;
+			}
+		}
+	}
+
+	clk->enable_count++;
+	return 0;
+}
+
+/**
+ * clk_enable - ungate a clock
+ * @clk: the clk being ungated
+ *
+ * clk_enable must not sleep, which differentiates it from clk_prepare.  In a
+ * simple case, clk_enable can be used instead of clk_prepare to ungate a clk
+ * if the operation will never sleep.  One example is a SoC-internal clk which
+ * is controlled via simple register writes.  In the complex case a clk ungate
+ * operation may require a fast and a slow part.  It is this reason that
+ * clk_enable and clk_prepare are not mutually exclusive.  In fact clk_prepare
+ * must be called before clk_enable.  Returns 0 on success, -EERROR
+ * otherwise.
+ */
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&enable_lock, flags);
+	ret = __clk_enable(clk);
+	spin_unlock_irqrestore(&enable_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+/**
+ * clk_get_rate - return the rate of clk
+ * @clk: the clk whose rate is being returned
+ *
+ * Simply returns the cached rate of the clk.  Does not query the hardware.  If
+ * clk is NULL then returns -EINVAL.
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+	unsigned long rate;
+
+	mutex_lock(&prepare_lock);
+	rate = __clk_get_rate(clk);
+	mutex_unlock(&prepare_lock);
+
+	return rate;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+/**
+ * __clk_round_rate - round the given rate for a clk
+ * @clk: round the rate of this clock
+ *
+ * Caller must hold prepare_lock.  Useful for clk_ops such as .set_rate
+ */
+unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long unused;
+
+	if (!clk)
+		return -EINVAL;
+
+	if (!clk->ops->round_rate)
+		return clk->rate;
+
+	if (clk->flags & CLK_SET_RATE_PARENT)
+		return clk->ops->round_rate(clk->hw, rate, &unused);
+	else
+		return clk->ops->round_rate(clk->hw, rate, NULL);
+}
+
+/**
+ * clk_round_rate - round the given rate for a clk
+ * @clk: the clk for which we are rounding a rate
+ * @rate: the rate which is to be rounded
+ *
+ * Takes in a rate as input and rounds it to a rate that the clk can actually
+ * use which is then returned.  If clk doesn't support round_rate operation
+ * then the parent rate is returned.
+ */
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long ret;
+
+	mutex_lock(&prepare_lock);
+	ret = __clk_round_rate(clk, rate);
+	mutex_unlock(&prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+/**
+ * __clk_notify - call clk notifier chain
+ * @clk: struct clk * that is changing rate
+ * @msg: clk notifier type (see include/linux/clk.h)
+ * @old_rate: old clk rate
+ * @new_rate: new clk rate
+ *
+ * Triggers a notifier call chain on the clk rate-change notification
+ * for 'clk'.  Passes a pointer to the struct clk and the previous
+ * and current rates to the notifier callback.  Intended to be called by
+ * internal clock code only.  Returns NOTIFY_DONE from the last driver
+ * called if all went well, or NOTIFY_STOP or NOTIFY_BAD immediately if
+ * a driver returns that.
+ */
+static int __clk_notify(struct clk *clk, unsigned long msg,
+		unsigned long old_rate, unsigned long new_rate)
+{
+	struct clk_notifier *cn;
+	struct clk_notifier_data cnd;
+	int ret = NOTIFY_DONE;
+
+	cnd.clk = clk;
+	cnd.old_rate = old_rate;
+	cnd.new_rate = new_rate;
+
+	list_for_each_entry(cn, &clk_notifier_list, node) {
+		if (cn->clk == clk) {
+			ret = srcu_notifier_call_chain(&cn->notifier_head, msg,
+					&cnd);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * __clk_recalc_rates
+ * @clk: first clk in the subtree
+ * @msg: notification type (see include/linux/clk.h)
+ *
+ * Walks the subtree of clks starting with clk and recalculates rates as it
+ * goes.  Note that if a clk does not implement the .recalc_rate callback then
+ * it is assumed that the clock will take on the rate of it's parent.
+ *
+ * clk_recalc_rates also propagates the POST_RATE_CHANGE notification,
+ * if necessary.
+ *
+ * Caller must hold prepare_lock.
+ */
+static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
+{
+	unsigned long old_rate;
+	unsigned long parent_rate = 0;
+	struct hlist_node *tmp;
+	struct clk *child;
+
+	old_rate = clk->rate;
+
+	if (clk->parent)
+		parent_rate = clk->parent->rate;
+
+	if (clk->ops->recalc_rate)
+		clk->rate = clk->ops->recalc_rate(clk->hw, parent_rate);
+	else
+		clk->rate = parent_rate;
+
+	/*
+	 * ignore NOTIFY_STOP and NOTIFY_BAD return values for POST_RATE_CHANGE
+	 * & ABORT_RATE_CHANGE notifiers
+	 */
+	if (clk->notifier_count && msg)
+		__clk_notify(clk, msg, old_rate, clk->rate);
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node)
+		__clk_recalc_rates(child, msg);
+}
+
+/**
+ * __clk_speculate_rates
+ * @clk: first clk in the subtree
+ * @parent_rate: the "future" rate of clk's parent
+ *
+ * Walks the subtree of clks starting with clk, speculating rates as it
+ * goes and firing off PRE_RATE_CHANGE notifications as necessary.
+ *
+ * Unlike clk_recalc_rates, clk_speculate_rates exists only for sending
+ * pre-rate change notifications and returns early if no clks in the
+ * subtree have subscribed to the notifications.  Note that if a clk does not
+ * implement the .recalc_rate callback then it is assumed that the clock will
+ * take on the rate of it's parent.
+ *
+ * Caller must hold prepare_lock.
+ */
+static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate)
+{
+	struct hlist_node *tmp;
+	struct clk *child;
+	unsigned long new_rate;
+	int ret = NOTIFY_DONE;
+
+	if (clk->ops->recalc_rate)
+		new_rate = clk->ops->recalc_rate(clk->hw, parent_rate);
+	else
+		new_rate = parent_rate;
+
+	/* abort the rate change if a driver returns NOTIFY_BAD */
+	if (clk->notifier_count)
+		ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
+
+	if (ret == NOTIFY_BAD)
+		goto out;
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+		ret = __clk_speculate_rates(child, new_rate);
+		if (ret == NOTIFY_BAD)
+			break;
+	}
+
+out:
+	return ret;
+}
+
+static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
+{
+	struct clk *child;
+	struct hlist_node *tmp;
+
+	clk->new_rate = new_rate;
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+		if (child->ops->recalc_rate)
+			child->new_rate = child->ops->recalc_rate(child->hw, new_rate);
+		else
+			child->new_rate = new_rate;
+		clk_calc_subtree(child, child->new_rate);
+	}
+}
+
+/*
+ * calculate the new rates returning the topmost clock that has to be
+ * changed.
+ */
+static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
+{
+	struct clk *top = clk;
+	unsigned long best_parent_rate = clk->parent->rate;
+	unsigned long new_rate;
+
+	if (!clk->ops->round_rate && !(clk->flags & CLK_SET_RATE_PARENT)) {
+		clk->new_rate = clk->rate;
+		return NULL;
+	}
+
+	if (!clk->ops->round_rate && (clk->flags & CLK_SET_RATE_PARENT)) {
+		top = clk_calc_new_rates(clk->parent, rate);
+		new_rate = clk->new_rate = clk->parent->new_rate;
+
+		goto out;
+	}
+
+	if (clk->flags & CLK_SET_RATE_PARENT)
+		new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
+	else
+		new_rate = clk->ops->round_rate(clk->hw, rate, NULL);
+
+	if (best_parent_rate != clk->parent->rate) {
+		top = clk_calc_new_rates(clk->parent, best_parent_rate);
+
+		goto out;
+	}
+
+out:
+	clk_calc_subtree(clk, new_rate);
+
+	return top;
+}
+
+/*
+ * Notify about rate changes in a subtree. Always walk down the whole tree
+ * so that in case of an error we can walk down the whole tree again and
+ * abort the change.
+ */
+static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
+{
+	struct hlist_node *tmp;
+	struct clk *child, *fail_clk = NULL;
+	int ret = NOTIFY_DONE;
+
+	if (clk->rate == clk->new_rate)
+		return 0;
+
+	if (clk->notifier_count) {
+		ret = __clk_notify(clk, event, clk->rate, clk->new_rate);
+		if (ret == NOTIFY_BAD)
+			fail_clk = clk;
+	}
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+		clk = clk_propagate_rate_change(child, event);
+		if (clk)
+			fail_clk = clk;
+	}
+
+	return fail_clk;
+}
+
+/*
+ * walk down a subtree and set the new rates notifying the rate
+ * change on the way
+ */
+static void clk_change_rate(struct clk *clk)
+{
+	struct clk *child;
+	unsigned long old_rate;
+	struct hlist_node *tmp;
+
+	old_rate = clk->rate;
+
+	if (clk->ops->set_rate)
+		clk->ops->set_rate(clk->hw, clk->new_rate);
+
+	if (clk->ops->recalc_rate)
+		clk->rate = clk->ops->recalc_rate(clk->hw,
+				clk->parent->rate);
+	else
+		clk->rate = clk->parent->rate;
+
+	if (clk->notifier_count && old_rate != clk->rate)
+		__clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node)
+		clk_change_rate(child);
+}
+
+/**
+ * clk_set_rate - specify a new rate for clk
+ * @clk: the clk whose rate is being changed
+ * @rate: the new rate for clk
+ *
+ * In the simplest case clk_set_rate will only change the rate of clk.
+ *
+ * If clk has the CLK_SET_RATE_GATE flag set and it is enabled this call
+ * will fail; only when the clk is disabled will it be able to change
+ * its rate.
+ *
+ * Setting the CLK_SET_RATE_PARENT flag allows clk_set_rate to
+ * recursively propagate up to clk's parent; whether or not this happens
+ * depends on the outcome of clk's .round_rate implementation.  If
+ * *parent_rate is 0 after calling .round_rate then upstream parent
+ * propagation is ignored.  If *parent_rate comes back with a new rate
+ * for clk's parent then we propagate up to clk's parent and set it's
+ * rate.  Upward propagation will continue until either a clk does not
+ * support the CLK_SET_RATE_PARENT flag or .round_rate stops requesting
+ * changes to clk's parent_rate.  If there is a failure during upstream
+ * propagation then clk_set_rate will unwind and restore each clk's rate
+ * that had been successfully changed.  Afterwards a rate change abort
+ * notification will be propagated downstream, starting from the clk
+ * that failed.
+ *
+ * At the end of all of the rate setting, clk_set_rate internally calls
+ * __clk_recalc_rates and propagates the rate changes downstream,
+ * starting from the highest clk whose rate was changed.  This has the
+ * added benefit of propagating post-rate change notifiers.
+ *
+ * Note that while post-rate change and rate change abort notifications
+ * are guaranteed to be sent to a clk only once per call to
+ * clk_set_rate, pre-change notifications will be sent for every clk
+ * whose rate is changed.  Stacking pre-change notifications is noisy
+ * for the drivers subscribed to them, but this allows drivers to react
+ * to intermediate clk rate changes up until the point where the final
+ * rate is achieved at the end of upstream propagation.
+ *
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	struct clk *top, *fail_clk;
+	int ret = 0;
+
+	/* prevent racing with updates to the clock topology */
+	mutex_lock(&prepare_lock);
+
+	/* bail early if nothing to do */
+	if (rate == clk->rate)
+		goto out;
+
+	/* calculate new rates and get the topmost changed clock */
+	top = clk_calc_new_rates(clk, rate);
+	if (!top) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* notify that we are about to change rates */
+	fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
+	if (fail_clk) {
+		pr_warn("%s: failed to set %s rate\n", __func__,
+				fail_clk->name);
+		clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
+		ret = -EBUSY;
+		goto out;
+	}
+
+	/* change the rates */
+	clk_change_rate(top);
+
+	mutex_unlock(&prepare_lock);
+
+	return 0;
+out:
+	mutex_unlock(&prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+/**
+ * clk_get_parent - return the parent of a clk
+ * @clk: the clk whose parent gets returned
+ *
+ * Simply returns clk->parent.  Returns NULL if clk is NULL.
+ */
+struct clk *clk_get_parent(struct clk *clk)
+{
+	struct clk *parent;
+
+	mutex_lock(&prepare_lock);
+	parent = __clk_get_parent(clk);
+	mutex_unlock(&prepare_lock);
+
+	return parent;
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+/*
+ * .get_parent is mandatory for clocks with multiple possible parents.  It is
+ * optional for single-parent clocks.  Always call .get_parent if it is
+ * available and WARN if it is missing for multi-parent clocks.
+ *
+ * For single-parent clocks without .get_parent, first check to see if the
+ * .parents array exists, and if so use it to avoid an expensive tree
+ * traversal.  If .parents does not exist then walk the tree with __clk_lookup.
+ */
+static struct clk *__clk_init_parent(struct clk *clk)
+{
+	struct clk *ret = NULL;
+	u8 index;
+
+	/* handle the trivial cases */
+
+	if (!clk->num_parents)
+		goto out;
+
+	if (clk->num_parents == 1) {
+		if (IS_ERR_OR_NULL(clk->parent))
+			ret = clk->parent = __clk_lookup(clk->parent_names[0]);
+		ret = clk->parent;
+		goto out;
+	}
+
+	if (!clk->ops->get_parent) {
+		WARN(!clk->ops->get_parent,
+			"%s: multi-parent clocks must implement .get_parent\n",
+			__func__);
+		goto out;
+	};
+
+	/*
+	 * Do our best to cache parent clocks in clk->parents.  This prevents
+	 * unnecessary and expensive calls to __clk_lookup.  We don't set
+	 * clk->parent here; that is done by the calling function
+	 */
+
+	index = clk->ops->get_parent(clk->hw);
+
+	if (!clk->parents)
+		clk->parents =
+			kmalloc((sizeof(struct clk*) * clk->num_parents),
+					GFP_KERNEL);
+
+	if (!clk->parents)
+		ret = __clk_lookup(clk->parent_names[index]);
+	else if (!clk->parents[index])
+		ret = clk->parents[index] =
+			__clk_lookup(clk->parent_names[index]);
+	else
+		ret = clk->parents[index];
+
+out:
+	return ret;
+}
+
+void __clk_reparent(struct clk *clk, struct clk *new_parent)
+{
+#ifdef CONFIG_COMMON_CLK_DEBUG
+	struct dentry *d;
+	struct dentry *new_parent_d;
+#endif
+
+	if (!clk || !new_parent)
+		return;
+
+	hlist_del(&clk->child_node);
+
+	if (new_parent)
+		hlist_add_head(&clk->child_node, &new_parent->children);
+	else
+		hlist_add_head(&clk->child_node, &clk_orphan_list);
+
+#ifdef CONFIG_COMMON_CLK_DEBUG
+	if (!inited)
+		goto out;
+
+	if (new_parent)
+		new_parent_d = new_parent->dentry;
+	else
+		new_parent_d = orphandir;
+
+	d = debugfs_rename(clk->dentry->d_parent, clk->dentry,
+			new_parent_d, clk->name);
+	if (d)
+		clk->dentry = d;
+	else
+		pr_debug("%s: failed to rename debugfs entry for %s\n",
+				__func__, clk->name);
+out:
+#endif
+
+	clk->parent = new_parent;
+
+	__clk_recalc_rates(clk, POST_RATE_CHANGE);
+}
+
+static int __clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	struct clk *old_parent;
+	unsigned long flags;
+	int ret = -EINVAL;
+	u8 i;
+
+	old_parent = clk->parent;
+
+	/* find index of new parent clock using cached parent ptrs */
+	for (i = 0; i < clk->num_parents; i++)
+		if (clk->parents[i] == parent)
+			break;
+
+	/*
+	 * find index of new parent clock using string name comparison
+	 * also try to cache the parent to avoid future calls to __clk_lookup
+	 */
+	if (i == clk->num_parents)
+		for (i = 0; i < clk->num_parents; i++)
+			if (!strcmp(clk->parent_names[i], parent->name)) {
+				clk->parents[i] = __clk_lookup(parent->name);
+				break;
+			}
+
+	if (i == clk->num_parents) {
+		pr_debug("%s: clock %s is not a possible parent of clock %s\n",
+				__func__, parent->name, clk->name);
+		goto out;
+	}
+
+	/* migrate prepare and enable */
+	if (clk->prepare_count)
+		__clk_prepare(parent);
+
+	/* FIXME replace with clk_is_enabled(clk) someday */
+	spin_lock_irqsave(&enable_lock, flags);
+	if (clk->enable_count)
+		__clk_enable(parent);
+	spin_unlock_irqrestore(&enable_lock, flags);
+
+	/* change clock input source */
+	ret = clk->ops->set_parent(clk->hw, i);
+
+	/* clean up old prepare and enable */
+	spin_lock_irqsave(&enable_lock, flags);
+	if (clk->enable_count)
+		__clk_disable(old_parent);
+	spin_unlock_irqrestore(&enable_lock, flags);
+
+	if (clk->prepare_count)
+		__clk_unprepare(old_parent);
+
+out:
+	return ret;
+}
+
+/**
+ * clk_set_parent - switch the parent of a mux clk
+ * @clk: the mux clk whose input we are switching
+ * @parent: the new input to clk
+ *
+ * Re-parent clk to use parent as it's new input source.  If clk has the
+ * CLK_SET_PARENT_GATE flag set then clk must be gated for this
+ * operation to succeed.  After successfully changing clk's parent
+ * clk_set_parent will update the clk topology, sysfs topology and
+ * propagate rate recalculation via __clk_recalc_rates.  Returns 0 on
+ * success, -EERROR otherwise.
+ */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	int ret = 0;
+
+	if (!clk || !clk->ops)
+		return -EINVAL;
+
+	if (!clk->ops->set_parent)
+		return -ENOSYS;
+
+	/* prevent racing with updates to the clock topology */
+	mutex_lock(&prepare_lock);
+
+	if (clk->parent == parent)
+		goto out;
+
+	/* propagate PRE_RATE_CHANGE notifications */
+	if (clk->notifier_count)
+		ret = __clk_speculate_rates(clk, parent->rate);
+
+	/* abort if a driver objects */
+	if (ret == NOTIFY_STOP)
+		goto out;
+
+	/* only re-parent if the clock is not in use */
+	if ((clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count)
+		ret = -EBUSY;
+	else
+		ret = __clk_set_parent(clk, parent);
+
+	/* propagate ABORT_RATE_CHANGE if .set_parent failed */
+	if (ret) {
+		__clk_recalc_rates(clk, ABORT_RATE_CHANGE);
+		goto out;
+	}
+
+	/* propagate rate recalculation downstream */
+	__clk_reparent(clk, parent);
+
+out:
+	mutex_unlock(&prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+/**
+ * __clk_init - initialize the data structures in a struct clk
+ * @dev:	device initializing this clk, placeholder for now
+ * @clk:	clk being initialized
+ *
+ * Initializes the lists in struct clk, queries the hardware for the
+ * parent and rate and sets them both.
+ *
+ * Any struct clk passed into __clk_init must have the following members
+ * populated:
+ * 	.name
+ * 	.ops
+ * 	.hw
+ * 	.parent_names
+ * 	.num_parents
+ * 	.flags
+ *
+ * Essentially, everything that would normally be passed into clk_register is
+ * assumed to be initialized already in __clk_init.  The other members may be
+ * populated, but are optional.
+ *
+ * __clk_init is only exposed via clk-private.h and is intended for use with
+ * very large numbers of clocks that need to be statically initialized.  It is
+ * a layering violation to include clk-private.h from any code which implements
+ * a clock's .ops; as such any statically initialized clock data MUST be in a
+ * separate C file from the logic that implements it's operations.
+ */
+void __clk_init(struct device *dev, struct clk *clk)
+{
+	int i;
+	struct clk *orphan;
+	struct hlist_node *tmp, *tmp2;
+
+	if (!clk)
+		return;
+
+	mutex_lock(&prepare_lock);
+
+	/* check to see if a clock with this name is already registered */
+	if (__clk_lookup(clk->name))
+		goto out;
+
+	/* throw a WARN if any entries in parent_names are NULL */
+	for (i = 0; i < clk->num_parents; i++)
+		WARN(!clk->parent_names[i],
+				"%s: invalid NULL in %s's .parent_names\n",
+				__func__, clk->name);
+
+	/*
+	 * Allocate an array of struct clk *'s to avoid unnecessary string
+	 * look-ups of clk's possible parents.  This can fail for clocks passed
+	 * in to clk_init during early boot; thus any access to clk->parents[]
+	 * must always check for a NULL pointer and try to populate it if
+	 * necessary.
+	 *
+	 * If clk->parents is not NULL we skip this entire block.  This allows
+	 * for clock drivers to statically initialize clk->parents.
+	 */
+	if (clk->num_parents && !clk->parents) {
+		clk->parents = kmalloc((sizeof(struct clk*) * clk->num_parents),
+				GFP_KERNEL);
+		/*
+		 * __clk_lookup returns NULL for parents that have not been
+		 * clk_init'd; thus any access to clk->parents[] must check
+		 * for a NULL pointer.  We can always perform lazy lookups for
+		 * missing parents later on.
+		 */
+		if (clk->parents)
+			for (i = 0; i < clk->num_parents; i++)
+				clk->parents[i] =
+					__clk_lookup(clk->parent_names[i]);
+	}
+
+	clk->parent = __clk_init_parent(clk);
+
+	/*
+	 * Populate clk->parent if parent has already been __clk_init'd.  If
+	 * parent has not yet been __clk_init'd then place clk in the orphan
+	 * list.  If clk has set the CLK_IS_ROOT flag then place it in the root
+	 * clk list.
+	 *
+	 * Every time a new clk is clk_init'd then we walk the list of orphan
+	 * clocks and re-parent any that are children of the clock currently
+	 * being clk_init'd.
+	 */
+	if (clk->parent)
+		hlist_add_head(&clk->child_node,
+				&clk->parent->children);
+	else if (clk->flags & CLK_IS_ROOT)
+		hlist_add_head(&clk->child_node, &clk_root_list);
+	else
+		hlist_add_head(&clk->child_node, &clk_orphan_list);
+
+	/*
+	 * Set clk's rate.  The preferred method is to use .recalc_rate.  For
+	 * simple clocks and lazy developers the default fallback is to use the
+	 * parent's rate.  If a clock doesn't have a parent (or is orphaned)
+	 * then rate is set to zero.
+	 */
+	if (clk->ops->recalc_rate)
+		clk->rate = clk->ops->recalc_rate(clk->hw,
+				__clk_get_rate(clk->parent));
+	else if (clk->parent)
+		clk->rate = clk->parent->rate;
+	else
+		clk->rate = 0;
+
+	/*
+	 * walk the list of orphan clocks and reparent any that are children of
+	 * this clock
+	 */
+	hlist_for_each_entry_safe(orphan, tmp, tmp2, &clk_orphan_list, child_node)
+		for (i = 0; i < orphan->num_parents; i++)
+			if (!strcmp(clk->name, orphan->parent_names[i])) {
+				__clk_reparent(orphan, clk);
+				break;
+			}
+
+	/*
+	 * optional platform-specific magic
+	 *
+	 * The .init callback is not used by any of the basic clock types, but
+	 * exists for weird hardware that must perform initialization magic.
+	 * Please consider other ways of solving initialization problems before
+	 * using this callback, as it's use is discouraged.
+	 */
+	if (clk->ops->init)
+		clk->ops->init(clk->hw);
+
+	clk_debug_register(clk);
+
+out:
+	mutex_unlock(&prepare_lock);
+
+	return;
+}
+
+/**
+ * clk_register - allocate a new clock, register it and return an opaque cookie
+ * @dev: device that is registering this clock
+ * @name: clock name
+ * @ops: operations this clock supports
+ * @hw: link to hardware-specific clock data
+ * @parent_names: array of string names for all possible parents
+ * @num_parents: number of possible parents
+ * @flags: framework-level hints and quirks
+ *
+ * clk_register is the primary interface for populating the clock tree with new
+ * clock nodes.  It returns a pointer to the newly allocated struct clk which
+ * cannot be dereferenced by driver code but may be used in conjuction with the
+ * rest of the clock API.
+ */
+struct clk *clk_register(struct device *dev, const char *name,
+		const struct clk_ops *ops, struct clk_hw *hw,
+		char **parent_names, u8 num_parents, unsigned long flags)
+{
+	struct clk *clk;
+
+	clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+	if (!clk)
+		return NULL;
+
+	clk->name = name;
+	clk->ops = ops;
+	clk->hw = hw;
+	clk->flags = flags;
+	clk->parent_names = parent_names;
+	clk->num_parents = num_parents;
+	hw->clk = clk;
+
+	__clk_init(dev, clk);
+
+	return clk;
+}
+EXPORT_SYMBOL_GPL(clk_register);
+
+/***        clk rate change notifiers        ***/
+
+/**
+ * clk_notifier_register - add a clk rate change notifier
+ * @clk: struct clk * to watch
+ * @nb: struct notifier_block * with callback info
+ *
+ * Request notification when clk's rate changes.  This uses an SRCU
+ * notifier because we want it to block and notifier unregistrations are
+ * uncommon.  The callbacks associated with the notifier must not
+ * re-enter into the clk framework by calling any top-level clk APIs;
+ * this will cause a nested prepare_lock mutex.
+ *
+ * Pre-change notifier callbacks will be passed the current, pre-change
+ * rate of the clk via struct clk_notifier_data.old_rate.  The new,
+ * post-change rate of the clk is passed via struct
+ * clk_notifier_data.new_rate.
+ *
+ * Post-change notifiers will pass the now-current, post-change rate of
+ * the clk in both struct clk_notifier_data.old_rate and struct
+ * clk_notifier_data.new_rate.
+ *
+ * Abort-change notifiers are effectively the opposite of pre-change
+ * notifiers: the original pre-change clk rate is passed in via struct
+ * clk_notifier_data.new_rate and the failed post-change rate is passed
+ * in via struct clk_notifier_data.old_rate.
+ *
+ * clk_notifier_register() must be called from non-atomic context.
+ * Returns -EINVAL if called with null arguments, -ENOMEM upon
+ * allocation failure; otherwise, passes along the return value of
+ * srcu_notifier_chain_register().
+ */
+int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
+{
+	struct clk_notifier *cn;
+	int ret = -ENOMEM;
+
+	if (!clk || !nb)
+		return -EINVAL;
+
+	mutex_lock(&prepare_lock);
+
+	/* search the list of notifiers for this clk */
+	list_for_each_entry(cn, &clk_notifier_list, node)
+		if (cn->clk == clk)
+			break;
+
+	/* if clk wasn't in the notifier list, allocate new clk_notifier */
+	if (cn->clk != clk) {
+		cn = kzalloc(sizeof(struct clk_notifier), GFP_KERNEL);
+		if (!cn)
+			goto out;
+
+		cn->clk = clk;
+		srcu_init_notifier_head(&cn->notifier_head);
+
+		list_add(&cn->node, &clk_notifier_list);
+	}
+
+	ret = srcu_notifier_chain_register(&cn->notifier_head, nb);
+
+	clk->notifier_count++;
+
+out:
+	mutex_unlock(&prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_notifier_register);
+
+/**
+ * clk_notifier_unregister - remove a clk rate change notifier
+ * @clk: struct clk *
+ * @nb: struct notifier_block * with callback info
+ *
+ * Request no further notification for changes to 'clk' and frees memory
+ * allocated in clk_notifier_register.
+ *
+ * Returns -EINVAL if called with null arguments; otherwise, passes
+ * along the return value of srcu_notifier_chain_unregister().
+ */
+int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
+{
+	struct clk_notifier *cn = NULL;
+	int ret = -EINVAL;
+
+	if (!clk || !nb)
+		return -EINVAL;
+
+	mutex_lock(&prepare_lock);
+
+	list_for_each_entry(cn, &clk_notifier_list, node)
+		if (cn->clk == clk)
+			break;
+
+	if (cn->clk == clk) {
+		ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);
+
+		clk->notifier_count--;
+
+		/* XXX the notifier code should handle this better */
+		if (!cn->notifier_head.head) {
+			srcu_cleanup_notifier_head(&cn->notifier_head);
+			kfree(cn);
+		}
+
+	} else {
+		ret = -ENOENT;
+	}
+
+	mutex_unlock(&prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_notifier_unregister);
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 999d6a0..5138927 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -26,7 +26,6 @@
 config CLKSRC_DBX500_PRCMU_SCHED_CLOCK
 	bool "Clocksource PRCMU Timer sched_clock"
 	depends on (CLKSRC_DBX500_PRCMU && !NOMADIK_MTU_SCHED_CLOCK)
-	select HAVE_SCHED_CLOCK
 	default y
 	help
 	  Use the always on PRCMU Timer as sched_clock
diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c
index 55d0f95..32cb929 100644
--- a/drivers/clocksource/tcb_clksrc.c
+++ b/drivers/clocksource/tcb_clksrc.c
@@ -19,6 +19,8 @@
  *   - Two channels combine to create a free-running 32 bit counter
  *     with a base rate of 5+ MHz, packaged as a clocksource (with
  *     resolution better than 200 nsec).
+ *   - Some chips support 32 bit counter. A single channel is used for
+ *     this 32 bit free-running counter. the second channel is not used.
  *
  *   - The third channel may be used to provide a 16-bit clockevent
  *     source, used in either periodic or oneshot mode.  This runs
@@ -54,6 +56,11 @@
 	return (upper << 16) | lower;
 }
 
+static cycle_t tc_get_cycles32(struct clocksource *cs)
+{
+	return __raw_readl(tcaddr + ATMEL_TC_REG(0, CV));
+}
+
 static struct clocksource clksrc = {
 	.name           = "tcb_clksrc",
 	.rating         = 200,
@@ -209,6 +216,48 @@
 
 #endif
 
+static void __init tcb_setup_dual_chan(struct atmel_tc *tc, int mck_divisor_idx)
+{
+	/* channel 0:  waveform mode, input mclk/8, clock TIOA0 on overflow */
+	__raw_writel(mck_divisor_idx			/* likely divide-by-8 */
+			| ATMEL_TC_WAVE
+			| ATMEL_TC_WAVESEL_UP		/* free-run */
+			| ATMEL_TC_ACPA_SET		/* TIOA0 rises at 0 */
+			| ATMEL_TC_ACPC_CLEAR,		/* (duty cycle 50%) */
+			tcaddr + ATMEL_TC_REG(0, CMR));
+	__raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
+	__raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
+	__raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));	/* no irqs */
+	__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
+
+	/* channel 1:  waveform mode, input TIOA0 */
+	__raw_writel(ATMEL_TC_XC1			/* input: TIOA0 */
+			| ATMEL_TC_WAVE
+			| ATMEL_TC_WAVESEL_UP,		/* free-run */
+			tcaddr + ATMEL_TC_REG(1, CMR));
+	__raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR));	/* no irqs */
+	__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
+
+	/* chain channel 0 to channel 1*/
+	__raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);
+	/* then reset all the timers */
+	__raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
+}
+
+static void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_idx)
+{
+	/* channel 0:  waveform mode, input mclk/8 */
+	__raw_writel(mck_divisor_idx			/* likely divide-by-8 */
+			| ATMEL_TC_WAVE
+			| ATMEL_TC_WAVESEL_UP,		/* free-run */
+			tcaddr + ATMEL_TC_REG(0, CMR));
+	__raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));	/* no irqs */
+	__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
+
+	/* then reset all the timers */
+	__raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
+}
+
 static int __init tcb_clksrc_init(void)
 {
 	static char bootinfo[] __initdata
@@ -260,34 +309,19 @@
 			divided_rate / 1000000,
 			((divided_rate + 500000) % 1000000) / 1000);
 
-	/* tclib will give us three clocks no matter what the
-	 * underlying platform supports.
-	 */
-	clk_enable(tc->clk[1]);
-
-	/* channel 0:  waveform mode, input mclk/8, clock TIOA0 on overflow */
-	__raw_writel(best_divisor_idx			/* likely divide-by-8 */
-			| ATMEL_TC_WAVE
-			| ATMEL_TC_WAVESEL_UP		/* free-run */
-			| ATMEL_TC_ACPA_SET		/* TIOA0 rises at 0 */
-			| ATMEL_TC_ACPC_CLEAR,		/* (duty cycle 50%) */
-			tcaddr + ATMEL_TC_REG(0, CMR));
-	__raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
-	__raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
-	__raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));	/* no irqs */
-	__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
-
-	/* channel 1:  waveform mode, input TIOA0 */
-	__raw_writel(ATMEL_TC_XC1			/* input: TIOA0 */
-			| ATMEL_TC_WAVE
-			| ATMEL_TC_WAVESEL_UP,		/* free-run */
-			tcaddr + ATMEL_TC_REG(1, CMR));
-	__raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR));	/* no irqs */
-	__raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
-
-	/* chain channel 0 to channel 1, then reset all the timers */
-	__raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);
-	__raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
+	if (tc->tcb_config && tc->tcb_config->counter_width == 32) {
+		/* use apropriate function to read 32 bit counter */
+		clksrc.read = tc_get_cycles32;
+		/* setup ony channel 0 */
+		tcb_setup_single_chan(tc, best_divisor_idx);
+	} else {
+		/* tclib will give us three clocks no matter what the
+		 * underlying platform supports.
+		 */
+		clk_enable(tc->clk[1]);
+		/* setup both channel 0 & 1 */
+		tcb_setup_dual_chan(tc, best_divisor_idx);
+	}
 
 	/* and away we go! */
 	clocksource_register_hz(&clksrc, divided_rate);
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index e0664fe..ffbb446 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -2,6 +2,33 @@
 # ARM CPU Frequency scaling drivers
 #
 
+config ARM_OMAP2PLUS_CPUFREQ
+	bool "TI OMAP2+"
+	default ARCH_OMAP2PLUS
+	select CPU_FREQ_TABLE
+
+config ARM_S3C2416_CPUFREQ
+	bool "S3C2416 CPU Frequency scaling support"
+	depends on CPU_S3C2416
+	help
+	  This adds the CPUFreq driver for the Samsung S3C2416 and
+	  S3C2450 SoC. The S3C2416 supports changing the rate of the
+	  armdiv clock source and also entering a so called dynamic
+	  voltage scaling mode in which it is possible to reduce the
+	  core voltage of the cpu.
+
+	  If in doubt, say N.
+
+config ARM_S3C2416_CPUFREQ_VCORESCALE
+	bool "Allow voltage scaling for S3C2416 arm core (EXPERIMENTAL)"
+	depends on ARM_S3C2416_CPUFREQ && REGULATOR && EXPERIMENTAL
+	help
+	  Enable CPU voltage scaling when entering the dvs mode.
+	  It uses information gathered through existing hardware and
+	  tests but not documented in any datasheet.
+
+	  If in doubt, say N.
+
 config ARM_S3C64XX_CPUFREQ
 	bool "Samsung S3C64XX"
 	depends on CPU_S3C6410
@@ -24,7 +51,6 @@
 config ARM_EXYNOS_CPUFREQ
 	bool "SAMSUNG EXYNOS SoCs"
 	depends on ARCH_EXYNOS
-	select ARM_EXYNOS4210_CPUFREQ if CPU_EXYNOS4210
 	default y
 	help
 	  This adds the CPUFreq driver common part for Samsung
@@ -33,7 +59,19 @@
 	  If in doubt, say N.
 
 config ARM_EXYNOS4210_CPUFREQ
-	bool "Samsung EXYNOS4210"
+	def_bool CPU_EXYNOS4210
 	help
 	  This adds the CPUFreq driver for Samsung EXYNOS4210
 	  SoC (S5PV310 or S5PC210).
+
+config ARM_EXYNOS4X12_CPUFREQ
+	def_bool (SOC_EXYNOS4212 || SOC_EXYNOS4412)
+	help
+	  This adds the CPUFreq driver for Samsung EXYNOS4X12
+	  SoC (EXYNOS4212 or EXYNOS4412).
+
+config ARM_EXYNOS5250_CPUFREQ
+	def_bool SOC_EXYNOS5250
+	help
+	  This adds the CPUFreq driver for Samsung EXYNOS5250
+	  SoC.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index ac000fa..9531fc2 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -40,11 +40,14 @@
 ##################################################################################
 # ARM SoC drivers
 obj-$(CONFIG_UX500_SOC_DB8500)		+= db8500-cpufreq.o
+obj-$(CONFIG_ARM_S3C2416_CPUFREQ)	+= s3c2416-cpufreq.o
 obj-$(CONFIG_ARM_S3C64XX_CPUFREQ)	+= s3c64xx-cpufreq.o
 obj-$(CONFIG_ARM_S5PV210_CPUFREQ)	+= s5pv210-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS_CPUFREQ)	+= exynos-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
-obj-$(CONFIG_ARCH_OMAP2PLUS)            += omap-cpufreq.o
+obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
+obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
+obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 622013f..7f2f149 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -126,6 +126,15 @@
 }
 pure_initcall(init_cpufreq_transition_notifier_list);
 
+static int off __read_mostly;
+int cpufreq_disabled(void)
+{
+	return off;
+}
+void disable_cpufreq(void)
+{
+	off = 1;
+}
 static LIST_HEAD(cpufreq_governor_list);
 static DEFINE_MUTEX(cpufreq_governor_mutex);
 
@@ -1441,6 +1450,9 @@
 {
 	int retval = -EINVAL;
 
+	if (cpufreq_disabled())
+		return -ENODEV;
+
 	pr_debug("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
 		target_freq, relation);
 	if (cpu_online(policy->cpu) && cpufreq_driver->target)
@@ -1549,6 +1561,9 @@
 	if (!governor)
 		return -EINVAL;
 
+	if (cpufreq_disabled())
+		return -ENODEV;
+
 	mutex_lock(&cpufreq_governor_mutex);
 
 	err = -EBUSY;
@@ -1572,6 +1587,9 @@
 	if (!governor)
 		return;
 
+	if (cpufreq_disabled())
+		return;
+
 #ifdef CONFIG_HOTPLUG_CPU
 	for_each_present_cpu(cpu) {
 		if (cpu_online(cpu))
@@ -1814,6 +1832,9 @@
 	unsigned long flags;
 	int ret;
 
+	if (cpufreq_disabled())
+		return -ENODEV;
+
 	if (!driver_data || !driver_data->verify || !driver_data->init ||
 	    ((!driver_data->setpolicy) && (!driver_data->target)))
 		return -EINVAL;
@@ -1901,6 +1922,9 @@
 {
 	int cpu;
 
+	if (cpufreq_disabled())
+		return -ENODEV;
+
 	for_each_possible_cpu(cpu) {
 		per_cpu(cpufreq_policy_cpu, cpu) = -1;
 		init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index c3e0652..836e9b0 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -257,6 +257,62 @@
 show_one(ignore_nice_load, ignore_nice);
 show_one(powersave_bias, powersave_bias);
 
+/**
+ * update_sampling_rate - update sampling rate effective immediately if needed.
+ * @new_rate: new sampling rate
+ *
+ * If new rate is smaller than the old, simply updaing
+ * dbs_tuners_int.sampling_rate might not be appropriate. For example,
+ * if the original sampling_rate was 1 second and the requested new sampling
+ * rate is 10 ms because the user needs immediate reaction from ondemand
+ * governor, but not sure if higher frequency will be required or not,
+ * then, the governor may change the sampling rate too late; up to 1 second
+ * later. Thus, if we are reducing the sampling rate, we need to make the
+ * new value effective immediately.
+ */
+static void update_sampling_rate(unsigned int new_rate)
+{
+	int cpu;
+
+	dbs_tuners_ins.sampling_rate = new_rate
+				     = max(new_rate, min_sampling_rate);
+
+	for_each_online_cpu(cpu) {
+		struct cpufreq_policy *policy;
+		struct cpu_dbs_info_s *dbs_info;
+		unsigned long next_sampling, appointed_at;
+
+		policy = cpufreq_cpu_get(cpu);
+		if (!policy)
+			continue;
+		dbs_info = &per_cpu(od_cpu_dbs_info, policy->cpu);
+		cpufreq_cpu_put(policy);
+
+		mutex_lock(&dbs_info->timer_mutex);
+
+		if (!delayed_work_pending(&dbs_info->work)) {
+			mutex_unlock(&dbs_info->timer_mutex);
+			continue;
+		}
+
+		next_sampling  = jiffies + usecs_to_jiffies(new_rate);
+		appointed_at = dbs_info->work.timer.expires;
+
+
+		if (time_before(next_sampling, appointed_at)) {
+
+			mutex_unlock(&dbs_info->timer_mutex);
+			cancel_delayed_work_sync(&dbs_info->work);
+			mutex_lock(&dbs_info->timer_mutex);
+
+			schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work,
+						 usecs_to_jiffies(new_rate));
+
+		}
+		mutex_unlock(&dbs_info->timer_mutex);
+	}
+}
+
 static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
 				   const char *buf, size_t count)
 {
@@ -265,7 +321,7 @@
 	ret = sscanf(buf, "%u", &input);
 	if (ret != 1)
 		return -EINVAL;
-	dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate);
+	update_sampling_rate(input);
 	return count;
 }
 
diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c
index f500201..0bf1b89 100644
--- a/drivers/cpufreq/db8500-cpufreq.c
+++ b/drivers/cpufreq/db8500-cpufreq.c
@@ -22,11 +22,11 @@
 	},
 	[1] = {
 		.index = 1,
-		.frequency = 300000,
+		.frequency = 400000,
 	},
 	[2] = {
 		.index = 2,
-		.frequency = 600000,
+		.frequency = 800000,
 	},
 	[3] = {
 		/* Used for MAX_OPP, if available */
@@ -113,12 +113,9 @@
 
 	BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
 
-	if (!prcmu_is_u8400()) {
-		freq_table[1].frequency = 400000;
-		freq_table[2].frequency = 800000;
-		if (prcmu_has_arm_maxopp())
-			freq_table[3].frequency = 1000000;
-	}
+	if (prcmu_has_arm_maxopp())
+		freq_table[3].frequency = 1000000;
+
 	pr_info("db8500-cpufreq : Available frequencies:\n");
 	for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
 		pr_info("  %d Mhz\n", freq_table[i].frequency/1000);
@@ -145,7 +142,7 @@
 	policy->cpuinfo.transition_latency = 20 * 1000; /* in ns */
 
 	/* policy sharing between dual CPUs */
-	cpumask_copy(policy->cpus, &cpu_present_map);
+	cpumask_copy(policy->cpus, cpu_present_mask);
 
 	policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
 
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 5467879..b243a7e 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -210,6 +210,8 @@
 
 	cpufreq_frequency_table_get_attr(exynos_info->freq_table, policy->cpu);
 
+	locking_frequency = exynos_getspeed(0);
+
 	/* set the transition latency value */
 	policy->cpuinfo.transition_latency = 100000;
 
@@ -252,6 +254,10 @@
 
 	if (soc_is_exynos4210())
 		ret = exynos4210_cpufreq_init(exynos_info);
+	else if (soc_is_exynos4212() || soc_is_exynos4412())
+		ret = exynos4x12_cpufreq_init(exynos_info);
+	else if (soc_is_exynos5250())
+		ret = exynos5250_cpufreq_init(exynos_info);
 	else
 		pr_err("%s: CPU type not found\n", __func__);
 
diff --git a/drivers/cpufreq/exynos4210-cpufreq.c b/drivers/cpufreq/exynos4210-cpufreq.c
index 065da5b..fb148fa 100644
--- a/drivers/cpufreq/exynos4210-cpufreq.c
+++ b/drivers/cpufreq/exynos4210-cpufreq.c
@@ -121,25 +121,25 @@
 
 	tmp = exynos4210_clkdiv_table[div_index].clkdiv;
 
-	__raw_writel(tmp, S5P_CLKDIV_CPU);
+	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
 
 	do {
-		tmp = __raw_readl(S5P_CLKDIV_STATCPU);
+		tmp = __raw_readl(EXYNOS4_CLKDIV_STATCPU);
 	} while (tmp & 0x1111111);
 
 	/* Change Divider - CPU1 */
 
-	tmp = __raw_readl(S5P_CLKDIV_CPU1);
+	tmp = __raw_readl(EXYNOS4_CLKDIV_CPU1);
 
 	tmp &= ~((0x7 << 4) | 0x7);
 
 	tmp |= ((clkdiv_cpu1[div_index][0] << 4) |
 		(clkdiv_cpu1[div_index][1] << 0));
 
-	__raw_writel(tmp, S5P_CLKDIV_CPU1);
+	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
 
 	do {
-		tmp = __raw_readl(S5P_CLKDIV_STATCPU1);
+		tmp = __raw_readl(EXYNOS4_CLKDIV_STATCPU1);
 	} while (tmp & 0x11);
 }
 
@@ -151,32 +151,32 @@
 	clk_set_parent(moutcore, mout_mpll);
 
 	do {
-		tmp = (__raw_readl(S5P_CLKMUX_STATCPU)
-			>> S5P_CLKSRC_CPU_MUXCORE_SHIFT);
+		tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
+			>> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
 		tmp &= 0x7;
 	} while (tmp != 0x2);
 
 	/* 2. Set APLL Lock time */
-	__raw_writel(S5P_APLL_LOCKTIME, S5P_APLL_LOCK);
+	__raw_writel(EXYNOS4_APLL_LOCKTIME, EXYNOS4_APLL_LOCK);
 
 	/* 3. Change PLL PMS values */
-	tmp = __raw_readl(S5P_APLL_CON0);
+	tmp = __raw_readl(EXYNOS4_APLL_CON0);
 	tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
 	tmp |= exynos4210_apll_pms_table[index];
-	__raw_writel(tmp, S5P_APLL_CON0);
+	__raw_writel(tmp, EXYNOS4_APLL_CON0);
 
 	/* 4. wait_lock_time */
 	do {
-		tmp = __raw_readl(S5P_APLL_CON0);
-	} while (!(tmp & (0x1 << S5P_APLLCON0_LOCKED_SHIFT)));
+		tmp = __raw_readl(EXYNOS4_APLL_CON0);
+	} while (!(tmp & (0x1 << EXYNOS4_APLLCON0_LOCKED_SHIFT)));
 
 	/* 5. MUX_CORE_SEL = APLL */
 	clk_set_parent(moutcore, mout_apll);
 
 	do {
-		tmp = __raw_readl(S5P_CLKMUX_STATCPU);
-		tmp &= S5P_CLKMUX_STATCPU_MUXCORE_MASK;
-	} while (tmp != (0x1 << S5P_CLKSRC_CPU_MUXCORE_SHIFT));
+		tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
+		tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
+	} while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
 }
 
 bool exynos4210_pms_change(unsigned int old_index, unsigned int new_index)
@@ -198,10 +198,10 @@
 			exynos4210_set_clkdiv(new_index);
 
 			/* 2. Change just s value in apll m,p,s value */
-			tmp = __raw_readl(S5P_APLL_CON0);
+			tmp = __raw_readl(EXYNOS4_APLL_CON0);
 			tmp &= ~(0x7 << 0);
 			tmp |= (exynos4210_apll_pms_table[new_index] & 0x7);
-			__raw_writel(tmp, S5P_APLL_CON0);
+			__raw_writel(tmp, EXYNOS4_APLL_CON0);
 		} else {
 			/* Clock Configuration Procedure */
 			/* 1. Change the system clock divider values */
@@ -212,10 +212,10 @@
 	} else if (old_index < new_index) {
 		if (!exynos4210_pms_change(old_index, new_index)) {
 			/* 1. Change just s value in apll m,p,s value */
-			tmp = __raw_readl(S5P_APLL_CON0);
+			tmp = __raw_readl(EXYNOS4_APLL_CON0);
 			tmp &= ~(0x7 << 0);
 			tmp |= (exynos4210_apll_pms_table[new_index] & 0x7);
-			__raw_writel(tmp, S5P_APLL_CON0);
+			__raw_writel(tmp, EXYNOS4_APLL_CON0);
 
 			/* 2. Change the system clock divider values */
 			exynos4210_set_clkdiv(new_index);
@@ -253,24 +253,24 @@
 	if (IS_ERR(mout_apll))
 		goto err_mout_apll;
 
-	tmp = __raw_readl(S5P_CLKDIV_CPU);
+	tmp = __raw_readl(EXYNOS4_CLKDIV_CPU);
 
 	for (i = L0; i <  CPUFREQ_LEVEL_END; i++) {
-		tmp &= ~(S5P_CLKDIV_CPU0_CORE_MASK |
-			S5P_CLKDIV_CPU0_COREM0_MASK |
-			S5P_CLKDIV_CPU0_COREM1_MASK |
-			S5P_CLKDIV_CPU0_PERIPH_MASK |
-			S5P_CLKDIV_CPU0_ATB_MASK |
-			S5P_CLKDIV_CPU0_PCLKDBG_MASK |
-			S5P_CLKDIV_CPU0_APLL_MASK);
+		tmp &= ~(EXYNOS4_CLKDIV_CPU0_CORE_MASK |
+			EXYNOS4_CLKDIV_CPU0_COREM0_MASK |
+			EXYNOS4_CLKDIV_CPU0_COREM1_MASK |
+			EXYNOS4_CLKDIV_CPU0_PERIPH_MASK |
+			EXYNOS4_CLKDIV_CPU0_ATB_MASK |
+			EXYNOS4_CLKDIV_CPU0_PCLKDBG_MASK |
+			EXYNOS4_CLKDIV_CPU0_APLL_MASK);
 
-		tmp |= ((clkdiv_cpu0[i][0] << S5P_CLKDIV_CPU0_CORE_SHIFT) |
-			(clkdiv_cpu0[i][1] << S5P_CLKDIV_CPU0_COREM0_SHIFT) |
-			(clkdiv_cpu0[i][2] << S5P_CLKDIV_CPU0_COREM1_SHIFT) |
-			(clkdiv_cpu0[i][3] << S5P_CLKDIV_CPU0_PERIPH_SHIFT) |
-			(clkdiv_cpu0[i][4] << S5P_CLKDIV_CPU0_ATB_SHIFT) |
-			(clkdiv_cpu0[i][5] << S5P_CLKDIV_CPU0_PCLKDBG_SHIFT) |
-			(clkdiv_cpu0[i][6] << S5P_CLKDIV_CPU0_APLL_SHIFT));
+		tmp |= ((clkdiv_cpu0[i][0] << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT) |
+			(clkdiv_cpu0[i][1] << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT) |
+			(clkdiv_cpu0[i][2] << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT) |
+			(clkdiv_cpu0[i][3] << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT) |
+			(clkdiv_cpu0[i][4] << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT) |
+			(clkdiv_cpu0[i][5] << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT) |
+			(clkdiv_cpu0[i][6] << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT));
 
 		exynos4210_clkdiv_table[i].clkdiv = tmp;
 	}
diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c
new file mode 100644
index 0000000..8c5a7af
--- /dev/null
+++ b/drivers/cpufreq/exynos4x12-cpufreq.c
@@ -0,0 +1,536 @@
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * EXYNOS4X12 - CPU frequency scaling support
+ *
+ * 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/kernel.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+
+#include <mach/regs-clock.h>
+#include <mach/cpufreq.h>
+
+#define CPUFREQ_LEVEL_END	(L13 + 1)
+
+static int max_support_idx;
+static int min_support_idx = (CPUFREQ_LEVEL_END - 1);
+
+static struct clk *cpu_clk;
+static struct clk *moutcore;
+static struct clk *mout_mpll;
+static struct clk *mout_apll;
+
+struct cpufreq_clkdiv {
+	unsigned int	index;
+	unsigned int	clkdiv;
+	unsigned int	clkdiv1;
+};
+
+static unsigned int exynos4x12_volt_table[CPUFREQ_LEVEL_END];
+
+static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
+	{L0, 1500 * 1000},
+	{L1, 1400 * 1000},
+	{L2, 1300 * 1000},
+	{L3, 1200 * 1000},
+	{L4, 1100 * 1000},
+	{L5, 1000 * 1000},
+	{L6,  900 * 1000},
+	{L7,  800 * 1000},
+	{L8,  700 * 1000},
+	{L9,  600 * 1000},
+	{L10, 500 * 1000},
+	{L11, 400 * 1000},
+	{L12, 300 * 1000},
+	{L13, 200 * 1000},
+	{0, CPUFREQ_TABLE_END},
+};
+
+static struct cpufreq_clkdiv exynos4x12_clkdiv_table[CPUFREQ_LEVEL_END];
+
+static unsigned int clkdiv_cpu0_4212[CPUFREQ_LEVEL_END][8] = {
+	/*
+	 * Clock divider value for following
+	 * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
+	 *		DIVATB, DIVPCLK_DBG, DIVAPLL, DIVCORE2 }
+	 */
+	/* ARM L0: 1500 MHz */
+	{ 0, 3, 7, 0, 6, 1, 2, 0 },
+
+	/* ARM L1: 1400 MHz */
+	{ 0, 3, 7, 0, 6, 1, 2, 0 },
+
+	/* ARM L2: 1300 MHz */
+	{ 0, 3, 7, 0, 5, 1, 2, 0 },
+
+	/* ARM L3: 1200 MHz */
+	{ 0, 3, 7, 0, 5, 1, 2, 0 },
+
+	/* ARM L4: 1100 MHz */
+	{ 0, 3, 6, 0, 4, 1, 2, 0 },
+
+	/* ARM L5: 1000 MHz */
+	{ 0, 2, 5, 0, 4, 1, 1, 0 },
+
+	/* ARM L6: 900 MHz */
+	{ 0, 2, 5, 0, 3, 1, 1, 0 },
+
+	/* ARM L7: 800 MHz */
+	{ 0, 2, 5, 0, 3, 1, 1, 0 },
+
+	/* ARM L8: 700 MHz */
+	{ 0, 2, 4, 0, 3, 1, 1, 0 },
+
+	/* ARM L9: 600 MHz */
+	{ 0, 2, 4, 0, 3, 1, 1, 0 },
+
+	/* ARM L10: 500 MHz */
+	{ 0, 2, 4, 0, 3, 1, 1, 0 },
+
+	/* ARM L11: 400 MHz */
+	{ 0, 2, 4, 0, 3, 1, 1, 0 },
+
+	/* ARM L12: 300 MHz */
+	{ 0, 2, 4, 0, 2, 1, 1, 0 },
+
+	/* ARM L13: 200 MHz */
+	{ 0, 1, 3, 0, 1, 1, 1, 0 },
+};
+
+static unsigned int clkdiv_cpu0_4412[CPUFREQ_LEVEL_END][8] = {
+	/*
+	 * Clock divider value for following
+	 * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
+	 *		DIVATB, DIVPCLK_DBG, DIVAPLL, DIVCORE2 }
+	 */
+	/* ARM L0: 1500 MHz */
+	{ 0, 3, 7, 0, 6, 1, 2, 0 },
+
+	/* ARM L1: 1400 MHz */
+	{ 0, 3, 7, 0, 6, 1, 2, 0 },
+
+	/* ARM L2: 1300 MHz */
+	{ 0, 3, 7, 0, 5, 1, 2, 0 },
+
+	/* ARM L3: 1200 MHz */
+	{ 0, 3, 7, 0, 5, 1, 2, 0 },
+
+	/* ARM L4: 1100 MHz */
+	{ 0, 3, 6, 0, 4, 1, 2, 0 },
+
+	/* ARM L5: 1000 MHz */
+	{ 0, 2, 5, 0, 4, 1, 1, 0 },
+
+	/* ARM L6: 900 MHz */
+	{ 0, 2, 5, 0, 3, 1, 1, 0 },
+
+	/* ARM L7: 800 MHz */
+	{ 0, 2, 5, 0, 3, 1, 1, 0 },
+
+	/* ARM L8: 700 MHz */
+	{ 0, 2, 4, 0, 3, 1, 1, 0 },
+
+	/* ARM L9: 600 MHz */
+	{ 0, 2, 4, 0, 3, 1, 1, 0 },
+
+	/* ARM L10: 500 MHz */
+	{ 0, 2, 4, 0, 3, 1, 1, 0 },
+
+	/* ARM L11: 400 MHz */
+	{ 0, 2, 4, 0, 3, 1, 1, 0 },
+
+	/* ARM L12: 300 MHz */
+	{ 0, 2, 4, 0, 2, 1, 1, 0 },
+
+	/* ARM L13: 200 MHz */
+	{ 0, 1, 3, 0, 1, 1, 1, 0 },
+};
+
+static unsigned int clkdiv_cpu1_4212[CPUFREQ_LEVEL_END][2] = {
+	/* Clock divider value for following
+	 * { DIVCOPY, DIVHPM }
+	 */
+	/* ARM L0: 1500 MHz */
+	{ 6, 0 },
+
+	/* ARM L1: 1400 MHz */
+	{ 6, 0 },
+
+	/* ARM L2: 1300 MHz */
+	{ 5, 0 },
+
+	/* ARM L3: 1200 MHz */
+	{ 5, 0 },
+
+	/* ARM L4: 1100 MHz */
+	{ 4, 0 },
+
+	/* ARM L5: 1000 MHz */
+	{ 4, 0 },
+
+	/* ARM L6: 900 MHz */
+	{ 3, 0 },
+
+	/* ARM L7: 800 MHz */
+	{ 3, 0 },
+
+	/* ARM L8: 700 MHz */
+	{ 3, 0 },
+
+	/* ARM L9: 600 MHz */
+	{ 3, 0 },
+
+	/* ARM L10: 500 MHz */
+	{ 3, 0 },
+
+	/* ARM L11: 400 MHz */
+	{ 3, 0 },
+
+	/* ARM L12: 300 MHz */
+	{ 3, 0 },
+
+	/* ARM L13: 200 MHz */
+	{ 3, 0 },
+};
+
+static unsigned int clkdiv_cpu1_4412[CPUFREQ_LEVEL_END][3] = {
+	/* Clock divider value for following
+	 * { DIVCOPY, DIVHPM, DIVCORES }
+	 */
+	/* ARM L0: 1500 MHz */
+	{ 6, 0, 7 },
+
+	/* ARM L1: 1400 MHz */
+	{ 6, 0, 6 },
+
+	/* ARM L2: 1300 MHz */
+	{ 5, 0, 6 },
+
+	/* ARM L3: 1200 MHz */
+	{ 5, 0, 5 },
+
+	/* ARM L4: 1100 MHz */
+	{ 4, 0, 5 },
+
+	/* ARM L5: 1000 MHz */
+	{ 4, 0, 4 },
+
+	/* ARM L6: 900 MHz */
+	{ 3, 0, 4 },
+
+	/* ARM L7: 800 MHz */
+	{ 3, 0, 3 },
+
+	/* ARM L8: 700 MHz */
+	{ 3, 0, 3 },
+
+	/* ARM L9: 600 MHz */
+	{ 3, 0, 2 },
+
+	/* ARM L10: 500 MHz */
+	{ 3, 0, 2 },
+
+	/* ARM L11: 400 MHz */
+	{ 3, 0, 1 },
+
+	/* ARM L12: 300 MHz */
+	{ 3, 0, 1 },
+
+	/* ARM L13: 200 MHz */
+	{ 3, 0, 0 },
+};
+
+static unsigned int exynos4x12_apll_pms_table[CPUFREQ_LEVEL_END] = {
+	/* APLL FOUT L0: 1500 MHz */
+	((250 << 16) | (4 << 8) | (0x0)),
+
+	/* APLL FOUT L1: 1400 MHz */
+	((175 << 16) | (3 << 8) | (0x0)),
+
+	/* APLL FOUT L2: 1300 MHz */
+	((325 << 16) | (6 << 8) | (0x0)),
+
+	/* APLL FOUT L3: 1200 MHz */
+	((200 << 16) | (4 << 8) | (0x0)),
+
+	/* APLL FOUT L4: 1100 MHz */
+	((275 << 16) | (6 << 8) | (0x0)),
+
+	/* APLL FOUT L5: 1000 MHz */
+	((125 << 16) | (3 << 8) | (0x0)),
+
+	/* APLL FOUT L6: 900 MHz */
+	((150 << 16) | (4 << 8) | (0x0)),
+
+	/* APLL FOUT L7: 800 MHz */
+	((100 << 16) | (3 << 8) | (0x0)),
+
+	/* APLL FOUT L8: 700 MHz */
+	((175 << 16) | (3 << 8) | (0x1)),
+
+	/* APLL FOUT L9: 600 MHz */
+	((200 << 16) | (4 << 8) | (0x1)),
+
+	/* APLL FOUT L10: 500 MHz */
+	((125 << 16) | (3 << 8) | (0x1)),
+
+	/* APLL FOUT L11 400 MHz */
+	((100 << 16) | (3 << 8) | (0x1)),
+
+	/* APLL FOUT L12: 300 MHz */
+	((200 << 16) | (4 << 8) | (0x2)),
+
+	/* APLL FOUT L13: 200 MHz */
+	((100 << 16) | (3 << 8) | (0x2)),
+};
+
+static const unsigned int asv_voltage_4x12[CPUFREQ_LEVEL_END] = {
+	1350000, 1287500, 1250000, 1187500, 1137500, 1087500, 1037500,
+	1000000,  987500,  975000,  950000,  925000,  900000,  900000
+};
+
+static void exynos4x12_set_clkdiv(unsigned int div_index)
+{
+	unsigned int tmp;
+	unsigned int stat_cpu1;
+
+	/* Change Divider - CPU0 */
+
+	tmp = exynos4x12_clkdiv_table[div_index].clkdiv;
+
+	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
+
+	while (__raw_readl(EXYNOS4_CLKDIV_STATCPU) & 0x11111111)
+		cpu_relax();
+
+	/* Change Divider - CPU1 */
+	tmp = exynos4x12_clkdiv_table[div_index].clkdiv1;
+
+	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
+	if (soc_is_exynos4212())
+		stat_cpu1 = 0x11;
+	else
+		stat_cpu1 = 0x111;
+
+	while (__raw_readl(EXYNOS4_CLKDIV_STATCPU1) & stat_cpu1)
+		cpu_relax();
+}
+
+static void exynos4x12_set_apll(unsigned int index)
+{
+	unsigned int tmp, pdiv;
+
+	/* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
+	clk_set_parent(moutcore, mout_mpll);
+
+	do {
+		cpu_relax();
+		tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
+			>> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
+		tmp &= 0x7;
+	} while (tmp != 0x2);
+
+	/* 2. Set APLL Lock time */
+	pdiv = ((exynos4x12_apll_pms_table[index] >> 8) & 0x3f);
+
+	__raw_writel((pdiv * 250), EXYNOS4_APLL_LOCK);
+
+	/* 3. Change PLL PMS values */
+	tmp = __raw_readl(EXYNOS4_APLL_CON0);
+	tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
+	tmp |= exynos4x12_apll_pms_table[index];
+	__raw_writel(tmp, EXYNOS4_APLL_CON0);
+
+	/* 4. wait_lock_time */
+	do {
+		cpu_relax();
+		tmp = __raw_readl(EXYNOS4_APLL_CON0);
+	} while (!(tmp & (0x1 << EXYNOS4_APLLCON0_LOCKED_SHIFT)));
+
+	/* 5. MUX_CORE_SEL = APLL */
+	clk_set_parent(moutcore, mout_apll);
+
+	do {
+		cpu_relax();
+		tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
+		tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
+	} while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
+}
+
+bool exynos4x12_pms_change(unsigned int old_index, unsigned int new_index)
+{
+	unsigned int old_pm = exynos4x12_apll_pms_table[old_index] >> 8;
+	unsigned int new_pm = exynos4x12_apll_pms_table[new_index] >> 8;
+
+	return (old_pm == new_pm) ? 0 : 1;
+}
+
+static void exynos4x12_set_frequency(unsigned int old_index,
+				  unsigned int new_index)
+{
+	unsigned int tmp;
+
+	if (old_index > new_index) {
+		if (!exynos4x12_pms_change(old_index, new_index)) {
+			/* 1. Change the system clock divider values */
+			exynos4x12_set_clkdiv(new_index);
+			/* 2. Change just s value in apll m,p,s value */
+			tmp = __raw_readl(EXYNOS4_APLL_CON0);
+			tmp &= ~(0x7 << 0);
+			tmp |= (exynos4x12_apll_pms_table[new_index] & 0x7);
+			__raw_writel(tmp, EXYNOS4_APLL_CON0);
+
+		} else {
+			/* Clock Configuration Procedure */
+			/* 1. Change the system clock divider values */
+			exynos4x12_set_clkdiv(new_index);
+			/* 2. Change the apll m,p,s value */
+			exynos4x12_set_apll(new_index);
+		}
+	} else if (old_index < new_index) {
+		if (!exynos4x12_pms_change(old_index, new_index)) {
+			/* 1. Change just s value in apll m,p,s value */
+			tmp = __raw_readl(EXYNOS4_APLL_CON0);
+			tmp &= ~(0x7 << 0);
+			tmp |= (exynos4x12_apll_pms_table[new_index] & 0x7);
+			__raw_writel(tmp, EXYNOS4_APLL_CON0);
+			/* 2. Change the system clock divider values */
+			exynos4x12_set_clkdiv(new_index);
+		} else {
+			/* Clock Configuration Procedure */
+			/* 1. Change the apll m,p,s value */
+			exynos4x12_set_apll(new_index);
+			/* 2. Change the system clock divider values */
+			exynos4x12_set_clkdiv(new_index);
+		}
+	}
+}
+
+static void __init set_volt_table(void)
+{
+	unsigned int i;
+
+	max_support_idx = L1;
+
+	/* Not supported */
+	exynos4x12_freq_table[L0].frequency = CPUFREQ_ENTRY_INVALID;
+
+	for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
+		exynos4x12_volt_table[i] = asv_voltage_4x12[i];
+}
+
+int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
+{
+	int i;
+	unsigned int tmp;
+	unsigned long rate;
+
+	set_volt_table();
+
+	cpu_clk = clk_get(NULL, "armclk");
+	if (IS_ERR(cpu_clk))
+		return PTR_ERR(cpu_clk);
+
+	moutcore = clk_get(NULL, "moutcore");
+	if (IS_ERR(moutcore))
+		goto err_moutcore;
+
+	mout_mpll = clk_get(NULL, "mout_mpll");
+	if (IS_ERR(mout_mpll))
+		goto err_mout_mpll;
+
+	rate = clk_get_rate(mout_mpll) / 1000;
+
+	mout_apll = clk_get(NULL, "mout_apll");
+	if (IS_ERR(mout_apll))
+		goto err_mout_apll;
+
+	for (i = L0; i <  CPUFREQ_LEVEL_END; i++) {
+
+		exynos4x12_clkdiv_table[i].index = i;
+
+		tmp = __raw_readl(EXYNOS4_CLKDIV_CPU);
+
+		tmp &= ~(EXYNOS4_CLKDIV_CPU0_CORE_MASK |
+			EXYNOS4_CLKDIV_CPU0_COREM0_MASK |
+			EXYNOS4_CLKDIV_CPU0_COREM1_MASK |
+			EXYNOS4_CLKDIV_CPU0_PERIPH_MASK |
+			EXYNOS4_CLKDIV_CPU0_ATB_MASK |
+			EXYNOS4_CLKDIV_CPU0_PCLKDBG_MASK |
+			EXYNOS4_CLKDIV_CPU0_APLL_MASK);
+
+		if (soc_is_exynos4212()) {
+			tmp |= ((clkdiv_cpu0_4212[i][0] << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT) |
+				(clkdiv_cpu0_4212[i][1] << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT) |
+				(clkdiv_cpu0_4212[i][2] << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT) |
+				(clkdiv_cpu0_4212[i][3] << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT) |
+				(clkdiv_cpu0_4212[i][4] << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT) |
+				(clkdiv_cpu0_4212[i][5] << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT) |
+				(clkdiv_cpu0_4212[i][6] << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT));
+		} else {
+			tmp &= ~EXYNOS4_CLKDIV_CPU0_CORE2_MASK;
+
+			tmp |= ((clkdiv_cpu0_4412[i][0] << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT) |
+				(clkdiv_cpu0_4412[i][1] << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT) |
+				(clkdiv_cpu0_4412[i][2] << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT) |
+				(clkdiv_cpu0_4412[i][3] << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT) |
+				(clkdiv_cpu0_4412[i][4] << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT) |
+				(clkdiv_cpu0_4412[i][5] << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT) |
+				(clkdiv_cpu0_4412[i][6] << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT) |
+				(clkdiv_cpu0_4412[i][7] << EXYNOS4_CLKDIV_CPU0_CORE2_SHIFT));
+		}
+
+		exynos4x12_clkdiv_table[i].clkdiv = tmp;
+
+		tmp = __raw_readl(EXYNOS4_CLKDIV_CPU1);
+
+		if (soc_is_exynos4212()) {
+			tmp &= ~(EXYNOS4_CLKDIV_CPU1_COPY_MASK |
+				EXYNOS4_CLKDIV_CPU1_HPM_MASK);
+			tmp |= ((clkdiv_cpu1_4212[i][0] << EXYNOS4_CLKDIV_CPU1_COPY_SHIFT) |
+				(clkdiv_cpu1_4212[i][1] << EXYNOS4_CLKDIV_CPU1_HPM_SHIFT));
+		} else {
+			tmp &= ~(EXYNOS4_CLKDIV_CPU1_COPY_MASK |
+				EXYNOS4_CLKDIV_CPU1_HPM_MASK |
+				EXYNOS4_CLKDIV_CPU1_CORES_MASK);
+			tmp |= ((clkdiv_cpu1_4412[i][0] << EXYNOS4_CLKDIV_CPU1_COPY_SHIFT) |
+				(clkdiv_cpu1_4412[i][1] << EXYNOS4_CLKDIV_CPU1_HPM_SHIFT) |
+				(clkdiv_cpu1_4412[i][2] << EXYNOS4_CLKDIV_CPU1_CORES_SHIFT));
+		}
+		exynos4x12_clkdiv_table[i].clkdiv1 = tmp;
+	}
+
+	info->mpll_freq_khz = rate;
+	info->pm_lock_idx = L5;
+	info->pll_safe_idx = L7;
+	info->max_support_idx = max_support_idx;
+	info->min_support_idx = min_support_idx;
+	info->cpu_clk = cpu_clk;
+	info->volt_table = exynos4x12_volt_table;
+	info->freq_table = exynos4x12_freq_table;
+	info->set_freq = exynos4x12_set_frequency;
+	info->need_apll_change = exynos4x12_pms_change;
+
+	return 0;
+
+err_mout_apll:
+	clk_put(mout_mpll);
+err_mout_mpll:
+	clk_put(moutcore);
+err_moutcore:
+	clk_put(cpu_clk);
+
+	pr_debug("%s: failed initialization\n", __func__);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(exynos4x12_cpufreq_init);
diff --git a/drivers/cpufreq/exynos5250-cpufreq.c b/drivers/cpufreq/exynos5250-cpufreq.c
new file mode 100644
index 0000000..a883316
--- /dev/null
+++ b/drivers/cpufreq/exynos5250-cpufreq.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2010-20122Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * EXYNOS5250 - CPU frequency scaling support
+ *
+ * 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/kernel.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/cpufreq.h>
+
+#define CPUFREQ_LEVEL_END	(L15 + 1)
+
+static int max_support_idx;
+static int min_support_idx = (CPUFREQ_LEVEL_END - 1);
+static struct clk *cpu_clk;
+static struct clk *moutcore;
+static struct clk *mout_mpll;
+static struct clk *mout_apll;
+
+struct cpufreq_clkdiv {
+	unsigned int	index;
+	unsigned int	clkdiv;
+	unsigned int	clkdiv1;
+};
+
+static unsigned int exynos5250_volt_table[CPUFREQ_LEVEL_END];
+
+static struct cpufreq_frequency_table exynos5250_freq_table[] = {
+	{L0, 1700 * 1000},
+	{L1, 1600 * 1000},
+	{L2, 1500 * 1000},
+	{L3, 1400 * 1000},
+	{L4, 1300 * 1000},
+	{L5, 1200 * 1000},
+	{L6, 1100 * 1000},
+	{L7, 1000 * 1000},
+	{L8, 900 * 1000},
+	{L9, 800 * 1000},
+	{L10, 700 * 1000},
+	{L11, 600 * 1000},
+	{L12, 500 * 1000},
+	{L13, 400 * 1000},
+	{L14, 300 * 1000},
+	{L15, 200 * 1000},
+	{0, CPUFREQ_TABLE_END},
+};
+
+static struct cpufreq_clkdiv exynos5250_clkdiv_table[CPUFREQ_LEVEL_END];
+
+static unsigned int clkdiv_cpu0_5250[CPUFREQ_LEVEL_END][8] = {
+	/*
+	 * Clock divider value for following
+	 * { ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2 }
+	 */
+	{ 0, 3, 7, 7, 6, 1, 3, 0 },	/* 1700 MHz - N/A */
+	{ 0, 3, 7, 7, 6, 1, 3, 0 },	/* 1600 MHz - N/A */
+	{ 0, 3, 7, 7, 5, 1, 3, 0 },	/* 1500 MHz - N/A */
+	{ 0, 3, 7, 7, 6, 1, 3, 0 },	/* 1400 MHz */
+	{ 0, 3, 7, 7, 6, 1, 3, 0 },	/* 1300 MHz */
+	{ 0, 3, 7, 7, 5, 1, 3, 0 },	/* 1200 MHz */
+	{ 0, 2, 7, 7, 5, 1, 2, 0 },	/* 1100 MHz */
+	{ 0, 2, 7, 7, 4, 1, 2, 0 },	/* 1000 MHz */
+	{ 0, 2, 7, 7, 4, 1, 2, 0 },	/* 900 MHz */
+	{ 0, 2, 7, 7, 3, 1, 1, 0 },	/* 800 MHz */
+	{ 0, 1, 7, 7, 3, 1, 1, 0 },	/* 700 MHz */
+	{ 0, 1, 7, 7, 2, 1, 1, 0 },	/* 600 MHz */
+	{ 0, 1, 7, 7, 2, 1, 1, 0 },	/* 500 MHz */
+	{ 0, 1, 7, 7, 1, 1, 1, 0 },	/* 400 MHz */
+	{ 0, 1, 7, 7, 1, 1, 1, 0 },	/* 300 MHz */
+	{ 0, 1, 7, 7, 1, 1, 1, 0 },	/* 200 MHz */
+};
+
+static unsigned int clkdiv_cpu1_5250[CPUFREQ_LEVEL_END][2] = {
+	/* Clock divider value for following
+	 * { COPY, HPM }
+	 */
+	{ 0, 2 },	/* 1700 MHz - N/A */
+	{ 0, 2 },	/* 1600 MHz - N/A */
+	{ 0, 2 },	/* 1500 MHz - N/A */
+	{ 0, 2 },	/* 1400 MHz */
+	{ 0, 2 },	/* 1300 MHz */
+	{ 0, 2 },	/* 1200 MHz */
+	{ 0, 2 },	/* 1100 MHz */
+	{ 0, 2 },	/* 1000 MHz */
+	{ 0, 2 },	/* 900 MHz */
+	{ 0, 2 },	/* 800 MHz */
+	{ 0, 2 },	/* 700 MHz */
+	{ 0, 2 },	/* 600 MHz */
+	{ 0, 2 },	/* 500 MHz */
+	{ 0, 2 },	/* 400 MHz */
+	{ 0, 2 },	/* 300 MHz */
+	{ 0, 2 },	/* 200 MHz */
+};
+
+static unsigned int exynos5_apll_pms_table[CPUFREQ_LEVEL_END] = {
+	(0),				/* 1700 MHz - N/A */
+	(0),				/* 1600 MHz - N/A */
+	(0),				/* 1500 MHz - N/A */
+	(0),				/* 1400 MHz */
+	((325 << 16) | (6 << 8) | 0),	/* 1300 MHz */
+	((200 << 16) | (4 << 8) | 0),	/* 1200 MHz */
+	((275 << 16) | (6 << 8) | 0),	/* 1100 MHz */
+	((125 << 16) | (3 << 8) | 0),	/* 1000 MHz */
+	((150 << 16) | (4 << 8) | 0),	/* 900 MHz */
+	((100 << 16) | (3 << 8) | 0),	/* 800 MHz */
+	((175 << 16) | (3 << 8) | 1),	/* 700 MHz */
+	((200 << 16) | (4 << 8) | 1),	/* 600 MHz */
+	((125 << 16) | (3 << 8) | 1),	/* 500 MHz */
+	((100 << 16) | (3 << 8) | 1),	/* 400 MHz */
+	((200 << 16) | (4 << 8) | 2),	/* 300 MHz */
+	((100 << 16) | (3 << 8) | 2),	/* 200 MHz */
+};
+
+/* ASV group voltage table */
+static const unsigned int asv_voltage_5250[CPUFREQ_LEVEL_END] = {
+	0, 0, 0, 0, 0, 0, 0,	/* 1700 MHz ~ 1100 MHz Not supported */
+	1175000, 1125000, 1075000, 1050000, 1000000,
+	950000, 925000, 925000, 900000
+};
+
+static void set_clkdiv(unsigned int div_index)
+{
+	unsigned int tmp;
+
+	/* Change Divider - CPU0 */
+
+	tmp = exynos5250_clkdiv_table[div_index].clkdiv;
+
+	__raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
+
+	while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
+		cpu_relax();
+
+	/* Change Divider - CPU1 */
+	tmp = exynos5250_clkdiv_table[div_index].clkdiv1;
+
+	__raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
+
+	while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
+		cpu_relax();
+}
+
+static void set_apll(unsigned int new_index,
+			     unsigned int old_index)
+{
+	unsigned int tmp, pdiv;
+
+	/* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
+	clk_set_parent(moutcore, mout_mpll);
+
+	do {
+		cpu_relax();
+		tmp = (__raw_readl(EXYNOS5_CLKMUX_STATCPU) >> 16);
+		tmp &= 0x7;
+	} while (tmp != 0x2);
+
+	/* 2. Set APLL Lock time */
+	pdiv = ((exynos5_apll_pms_table[new_index] >> 8) & 0x3f);
+
+	__raw_writel((pdiv * 250), EXYNOS5_APLL_LOCK);
+
+	/* 3. Change PLL PMS values */
+	tmp = __raw_readl(EXYNOS5_APLL_CON0);
+	tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
+	tmp |= exynos5_apll_pms_table[new_index];
+	__raw_writel(tmp, EXYNOS5_APLL_CON0);
+
+	/* 4. wait_lock_time */
+	do {
+		cpu_relax();
+		tmp = __raw_readl(EXYNOS5_APLL_CON0);
+	} while (!(tmp & (0x1 << 29)));
+
+	/* 5. MUX_CORE_SEL = APLL */
+	clk_set_parent(moutcore, mout_apll);
+
+	do {
+		cpu_relax();
+		tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
+		tmp &= (0x7 << 16);
+	} while (tmp != (0x1 << 16));
+
+}
+
+bool exynos5250_pms_change(unsigned int old_index, unsigned int new_index)
+{
+	unsigned int old_pm = (exynos5_apll_pms_table[old_index] >> 8);
+	unsigned int new_pm = (exynos5_apll_pms_table[new_index] >> 8);
+
+	return (old_pm == new_pm) ? 0 : 1;
+}
+
+static void exynos5250_set_frequency(unsigned int old_index,
+				  unsigned int new_index)
+{
+	unsigned int tmp;
+
+	if (old_index > new_index) {
+		if (!exynos5250_pms_change(old_index, new_index)) {
+			/* 1. Change the system clock divider values */
+			set_clkdiv(new_index);
+			/* 2. Change just s value in apll m,p,s value */
+			tmp = __raw_readl(EXYNOS5_APLL_CON0);
+			tmp &= ~(0x7 << 0);
+			tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
+			__raw_writel(tmp, EXYNOS5_APLL_CON0);
+
+		} else {
+			/* Clock Configuration Procedure */
+			/* 1. Change the system clock divider values */
+			set_clkdiv(new_index);
+			/* 2. Change the apll m,p,s value */
+			set_apll(new_index, old_index);
+		}
+	} else if (old_index < new_index) {
+		if (!exynos5250_pms_change(old_index, new_index)) {
+			/* 1. Change just s value in apll m,p,s value */
+			tmp = __raw_readl(EXYNOS5_APLL_CON0);
+			tmp &= ~(0x7 << 0);
+			tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
+			__raw_writel(tmp, EXYNOS5_APLL_CON0);
+			/* 2. Change the system clock divider values */
+			set_clkdiv(new_index);
+		} else {
+			/* Clock Configuration Procedure */
+			/* 1. Change the apll m,p,s value */
+			set_apll(new_index, old_index);
+			/* 2. Change the system clock divider values */
+			set_clkdiv(new_index);
+		}
+	}
+}
+
+static void __init set_volt_table(void)
+{
+	unsigned int i;
+
+	exynos5250_freq_table[L0].frequency = CPUFREQ_ENTRY_INVALID;
+	exynos5250_freq_table[L1].frequency = CPUFREQ_ENTRY_INVALID;
+	exynos5250_freq_table[L2].frequency = CPUFREQ_ENTRY_INVALID;
+	exynos5250_freq_table[L3].frequency = CPUFREQ_ENTRY_INVALID;
+	exynos5250_freq_table[L4].frequency = CPUFREQ_ENTRY_INVALID;
+	exynos5250_freq_table[L5].frequency = CPUFREQ_ENTRY_INVALID;
+	exynos5250_freq_table[L6].frequency = CPUFREQ_ENTRY_INVALID;
+
+	max_support_idx = L7;
+
+	for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
+		exynos5250_volt_table[i] = asv_voltage_5250[i];
+}
+
+int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
+{
+	int i;
+	unsigned int tmp;
+	unsigned long rate;
+
+	set_volt_table();
+
+	cpu_clk = clk_get(NULL, "armclk");
+	if (IS_ERR(cpu_clk))
+		return PTR_ERR(cpu_clk);
+
+	moutcore = clk_get(NULL, "mout_cpu");
+	if (IS_ERR(moutcore))
+		goto err_moutcore;
+
+	mout_mpll = clk_get(NULL, "mout_mpll");
+	if (IS_ERR(mout_mpll))
+		goto err_mout_mpll;
+
+	rate = clk_get_rate(mout_mpll) / 1000;
+
+	mout_apll = clk_get(NULL, "mout_apll");
+	if (IS_ERR(mout_apll))
+		goto err_mout_apll;
+
+	for (i = L0; i < CPUFREQ_LEVEL_END; i++) {
+
+		exynos5250_clkdiv_table[i].index = i;
+
+		tmp = __raw_readl(EXYNOS5_CLKDIV_CPU0);
+
+		tmp &= ~((0x7 << 0) | (0x7 << 4) | (0x7 << 8) |
+			(0x7 << 12) | (0x7 << 16) | (0x7 << 20) |
+			(0x7 << 24) | (0x7 << 28));
+
+		tmp |= ((clkdiv_cpu0_5250[i][0] << 0) |
+			(clkdiv_cpu0_5250[i][1] << 4) |
+			(clkdiv_cpu0_5250[i][2] << 8) |
+			(clkdiv_cpu0_5250[i][3] << 12) |
+			(clkdiv_cpu0_5250[i][4] << 16) |
+			(clkdiv_cpu0_5250[i][5] << 20) |
+			(clkdiv_cpu0_5250[i][6] << 24) |
+			(clkdiv_cpu0_5250[i][7] << 28));
+
+		exynos5250_clkdiv_table[i].clkdiv = tmp;
+
+		tmp = __raw_readl(EXYNOS5_CLKDIV_CPU1);
+
+		tmp &= ~((0x7 << 0) | (0x7 << 4));
+
+		tmp |= ((clkdiv_cpu1_5250[i][0] << 0) |
+			(clkdiv_cpu1_5250[i][1] << 4));
+
+		exynos5250_clkdiv_table[i].clkdiv1 = tmp;
+	}
+
+	info->mpll_freq_khz = rate;
+	/* 1000Mhz */
+	info->pm_lock_idx = L7;
+	/* 800Mhz */
+	info->pll_safe_idx = L9;
+	info->max_support_idx = max_support_idx;
+	info->min_support_idx = min_support_idx;
+	info->cpu_clk = cpu_clk;
+	info->volt_table = exynos5250_volt_table;
+	info->freq_table = exynos5250_freq_table;
+	info->set_freq = exynos5250_set_frequency;
+	info->need_apll_change = exynos5250_pms_change;
+
+	return 0;
+
+err_mout_apll:
+	clk_put(mout_mpll);
+err_mout_mpll:
+	clk_put(moutcore);
+err_moutcore:
+	clk_put(cpu_clk);
+
+	pr_err("%s: failed initialization\n", __func__);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(exynos5250_cpufreq_init);
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 5d04c57..17fa04d0 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -25,8 +25,8 @@
 #include <linux/opp.h>
 #include <linux/cpu.h>
 #include <linux/module.h>
+#include <linux/regulator/consumer.h>
 
-#include <asm/system.h>
 #include <asm/smp_plat.h>
 #include <asm/cpu.h>
 
@@ -37,6 +37,9 @@
 
 #include <mach/hardware.h>
 
+/* OPP tolerance in percentage */
+#define	OPP_TOLERANCE	4
+
 #ifdef CONFIG_SMP
 struct lpj_info {
 	unsigned long	ref;
@@ -52,6 +55,7 @@
 static struct clk *mpu_clk;
 static char *mpu_clk_name;
 static struct device *mpu_dev;
+static struct regulator *mpu_reg;
 
 static int omap_verify_speed(struct cpufreq_policy *policy)
 {
@@ -76,8 +80,10 @@
 		       unsigned int relation)
 {
 	unsigned int i;
-	int ret = 0;
+	int r, ret = 0;
 	struct cpufreq_freqs freqs;
+	struct opp *opp;
+	unsigned long freq, volt = 0, volt_old = 0, tol = 0;
 
 	if (!freq_table) {
 		dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__,
@@ -111,13 +117,50 @@
 		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 	}
 
-#ifdef CONFIG_CPU_FREQ_DEBUG
-	pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new);
-#endif
+	freq = freqs.new * 1000;
+
+	if (mpu_reg) {
+		opp = opp_find_freq_ceil(mpu_dev, &freq);
+		if (IS_ERR(opp)) {
+			dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
+				__func__, freqs.new);
+			return -EINVAL;
+		}
+		volt = opp_get_voltage(opp);
+		tol = volt * OPP_TOLERANCE / 100;
+		volt_old = regulator_get_voltage(mpu_reg);
+	}
+
+	dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n", 
+		freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
+		freqs.new / 1000, volt ? volt / 1000 : -1);
+
+	/* scaling up?  scale voltage before frequency */
+	if (mpu_reg && (freqs.new > freqs.old)) {
+		r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
+		if (r < 0) {
+			dev_warn(mpu_dev, "%s: unable to scale voltage up.\n",
+				 __func__);
+			freqs.new = freqs.old;
+			goto done;
+		}
+	}
 
 	ret = clk_set_rate(mpu_clk, freqs.new * 1000);
-	freqs.new = omap_getspeed(policy->cpu);
 
+	/* scaling down?  scale voltage after frequency */
+	if (mpu_reg && (freqs.new < freqs.old)) {
+		r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
+		if (r < 0) {
+			dev_warn(mpu_dev, "%s: unable to scale voltage down.\n",
+				 __func__);
+			ret = clk_set_rate(mpu_clk, freqs.old * 1000);
+			freqs.new = freqs.old;
+			goto done;
+		}
+	}
+
+	freqs.new = omap_getspeed(policy->cpu);
 #ifdef CONFIG_SMP
 	/*
 	 * Note that loops_per_jiffy is not updated on SMP systems in
@@ -144,6 +187,7 @@
 					freqs.new);
 #endif
 
+done:
 	/* notifiers */
 	for_each_cpu(i, policy->cpus) {
 		freqs.cpu = i;
@@ -260,6 +304,23 @@
 		return -EINVAL;
 	}
 
+	mpu_reg = regulator_get(mpu_dev, "vcc");
+	if (IS_ERR(mpu_reg)) {
+		pr_warning("%s: unable to get MPU regulator\n", __func__);
+		mpu_reg = NULL;
+	} else {
+		/* 
+		 * Ensure physical regulator is present.
+		 * (e.g. could be dummy regulator.)
+		 */
+		if (regulator_get_voltage(mpu_reg) < 0) {
+			pr_warn("%s: physical regulator not present for MPU\n",
+				__func__);
+			regulator_put(mpu_reg);
+			mpu_reg = NULL;
+		}
+	}
+
 	return cpufreq_register_driver(&omap_driver);
 }
 
diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c
index cf7e1ee..334cc2f 100644
--- a/drivers/cpufreq/powernow-k7.c
+++ b/drivers/cpufreq/powernow-k7.c
@@ -27,7 +27,6 @@
 
 #include <asm/timer.h>		/* Needed for recalibrate_cpu_khz() */
 #include <asm/msr.h>
-#include <asm/system.h>
 #include <asm/cpu_device_id.h>
 
 #ifdef CONFIG_X86_POWERNOW_K7_ACPI
diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c
new file mode 100644
index 0000000..50d2f15
--- /dev/null
+++ b/drivers/cpufreq/s3c2416-cpufreq.c
@@ -0,0 +1,542 @@
+/*
+ * S3C2416/2450 CPUfreq Support
+ *
+ * Copyright 2011 Heiko Stuebner <heiko@sntech.de>
+ *
+ * based on s3c64xx_cpufreq.c
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ *
+ * 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/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reboot.h>
+#include <linux/module.h>
+
+static DEFINE_MUTEX(cpufreq_lock);
+
+struct s3c2416_data {
+	struct clk *armdiv;
+	struct clk *armclk;
+	struct clk *hclk;
+
+	unsigned long regulator_latency;
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+	struct regulator *vddarm;
+#endif
+
+	struct cpufreq_frequency_table *freq_table;
+
+	bool is_dvs;
+	bool disable_dvs;
+};
+
+static struct s3c2416_data s3c2416_cpufreq;
+
+struct s3c2416_dvfs {
+	unsigned int vddarm_min;
+	unsigned int vddarm_max;
+};
+
+/* pseudo-frequency for dvs mode */
+#define FREQ_DVS	132333
+
+/* frequency to sleep and reboot in
+ * it's essential to leave dvs, as some boards do not reconfigure the
+ * regulator on reboot
+ */
+#define FREQ_SLEEP	133333
+
+/* Sources for the ARMCLK */
+#define SOURCE_HCLK	0
+#define SOURCE_ARMDIV	1
+
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+/* S3C2416 only supports changing the voltage in the dvs-mode.
+ * Voltages down to 1.0V seem to work, so we take what the regulator
+ * can get us.
+ */
+static struct s3c2416_dvfs s3c2416_dvfs_table[] = {
+	[SOURCE_HCLK] = {  950000, 1250000 },
+	[SOURCE_ARMDIV] = { 1250000, 1350000 },
+};
+#endif
+
+static struct cpufreq_frequency_table s3c2416_freq_table[] = {
+	{ SOURCE_HCLK, FREQ_DVS },
+	{ SOURCE_ARMDIV, 133333 },
+	{ SOURCE_ARMDIV, 266666 },
+	{ SOURCE_ARMDIV, 400000 },
+	{ 0, CPUFREQ_TABLE_END },
+};
+
+static struct cpufreq_frequency_table s3c2450_freq_table[] = {
+	{ SOURCE_HCLK, FREQ_DVS },
+	{ SOURCE_ARMDIV, 133500 },
+	{ SOURCE_ARMDIV, 267000 },
+	{ SOURCE_ARMDIV, 534000 },
+	{ 0, CPUFREQ_TABLE_END },
+};
+
+static int s3c2416_cpufreq_verify_speed(struct cpufreq_policy *policy)
+{
+	struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	return cpufreq_frequency_table_verify(policy, s3c_freq->freq_table);
+}
+
+static unsigned int s3c2416_cpufreq_get_speed(unsigned int cpu)
+{
+	struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
+
+	if (cpu != 0)
+		return 0;
+
+	/* return our pseudo-frequency when in dvs mode */
+	if (s3c_freq->is_dvs)
+		return FREQ_DVS;
+
+	return clk_get_rate(s3c_freq->armclk) / 1000;
+}
+
+static int s3c2416_cpufreq_set_armdiv(struct s3c2416_data *s3c_freq,
+				      unsigned int freq)
+{
+	int ret;
+
+	if (clk_get_rate(s3c_freq->armdiv) / 1000 != freq) {
+		ret = clk_set_rate(s3c_freq->armdiv, freq * 1000);
+		if (ret < 0) {
+			pr_err("cpufreq: Failed to set armdiv rate %dkHz: %d\n",
+			       freq, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int s3c2416_cpufreq_enter_dvs(struct s3c2416_data *s3c_freq, int idx)
+{
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+	struct s3c2416_dvfs *dvfs;
+#endif
+	int ret;
+
+	if (s3c_freq->is_dvs) {
+		pr_debug("cpufreq: already in dvs mode, nothing to do\n");
+		return 0;
+	}
+
+	pr_debug("cpufreq: switching armclk to hclk (%lukHz)\n",
+		 clk_get_rate(s3c_freq->hclk) / 1000);
+	ret = clk_set_parent(s3c_freq->armclk, s3c_freq->hclk);
+	if (ret < 0) {
+		pr_err("cpufreq: Failed to switch armclk to hclk: %d\n", ret);
+		return ret;
+	}
+
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+	/* changing the core voltage is only allowed when in dvs mode */
+	if (s3c_freq->vddarm) {
+		dvfs = &s3c2416_dvfs_table[idx];
+
+		pr_debug("cpufreq: setting regultor to %d-%d\n",
+			 dvfs->vddarm_min, dvfs->vddarm_max);
+		ret = regulator_set_voltage(s3c_freq->vddarm,
+					    dvfs->vddarm_min,
+					    dvfs->vddarm_max);
+
+		/* when lowering the voltage failed, there is nothing to do */
+		if (ret != 0)
+			pr_err("cpufreq: Failed to set VDDARM: %d\n", ret);
+	}
+#endif
+
+	s3c_freq->is_dvs = 1;
+
+	return 0;
+}
+
+static int s3c2416_cpufreq_leave_dvs(struct s3c2416_data *s3c_freq, int idx)
+{
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+	struct s3c2416_dvfs *dvfs;
+#endif
+	int ret;
+
+	if (!s3c_freq->is_dvs) {
+		pr_debug("cpufreq: not in dvs mode, so can't leave\n");
+		return 0;
+	}
+
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+	if (s3c_freq->vddarm) {
+		dvfs = &s3c2416_dvfs_table[idx];
+
+		pr_debug("cpufreq: setting regultor to %d-%d\n",
+			 dvfs->vddarm_min, dvfs->vddarm_max);
+		ret = regulator_set_voltage(s3c_freq->vddarm,
+					    dvfs->vddarm_min,
+					    dvfs->vddarm_max);
+		if (ret != 0) {
+			pr_err("cpufreq: Failed to set VDDARM: %d\n", ret);
+			return ret;
+		}
+	}
+#endif
+
+	/* force armdiv to hclk frequency for transition from dvs*/
+	if (clk_get_rate(s3c_freq->armdiv) > clk_get_rate(s3c_freq->hclk)) {
+		pr_debug("cpufreq: force armdiv to hclk frequency (%lukHz)\n",
+			 clk_get_rate(s3c_freq->hclk) / 1000);
+		ret = s3c2416_cpufreq_set_armdiv(s3c_freq,
+					clk_get_rate(s3c_freq->hclk) / 1000);
+		if (ret < 0) {
+			pr_err("cpufreq: Failed to to set the armdiv to %lukHz: %d\n",
+			       clk_get_rate(s3c_freq->hclk) / 1000, ret);
+			return ret;
+		}
+	}
+
+	pr_debug("cpufreq: switching armclk parent to armdiv (%lukHz)\n",
+			clk_get_rate(s3c_freq->armdiv) / 1000);
+
+	ret = clk_set_parent(s3c_freq->armclk, s3c_freq->armdiv);
+	if (ret < 0) {
+		pr_err("cpufreq: Failed to switch armclk clock parent to armdiv: %d\n",
+		       ret);
+		return ret;
+	}
+
+	s3c_freq->is_dvs = 0;
+
+	return 0;
+}
+
+static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
+				      unsigned int target_freq,
+				      unsigned int relation)
+{
+	struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
+	struct cpufreq_freqs freqs;
+	int idx, ret, to_dvs = 0;
+	unsigned int i;
+
+	mutex_lock(&cpufreq_lock);
+
+	pr_debug("cpufreq: to %dKHz, relation %d\n", target_freq, relation);
+
+	ret = cpufreq_frequency_table_target(policy, s3c_freq->freq_table,
+					     target_freq, relation, &i);
+	if (ret != 0)
+		goto out;
+
+	idx = s3c_freq->freq_table[i].index;
+
+	if (idx == SOURCE_HCLK)
+		to_dvs = 1;
+
+	/* switching to dvs when it's not allowed */
+	if (to_dvs && s3c_freq->disable_dvs) {
+		pr_debug("cpufreq: entering dvs mode not allowed\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	freqs.cpu = 0;
+	freqs.flags = 0;
+	freqs.old = s3c_freq->is_dvs ? FREQ_DVS
+				     : clk_get_rate(s3c_freq->armclk) / 1000;
+
+	/* When leavin dvs mode, always switch the armdiv to the hclk rate
+	 * The S3C2416 has stability issues when switching directly to
+	 * higher frequencies.
+	 */
+	freqs.new = (s3c_freq->is_dvs && !to_dvs)
+				? clk_get_rate(s3c_freq->hclk) / 1000
+				: s3c_freq->freq_table[i].frequency;
+
+	pr_debug("cpufreq: Transition %d-%dkHz\n", freqs.old, freqs.new);
+
+	if (!to_dvs && freqs.old == freqs.new)
+		goto out;
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	if (to_dvs) {
+		pr_debug("cpufreq: enter dvs\n");
+		ret = s3c2416_cpufreq_enter_dvs(s3c_freq, idx);
+	} else if (s3c_freq->is_dvs) {
+		pr_debug("cpufreq: leave dvs\n");
+		ret = s3c2416_cpufreq_leave_dvs(s3c_freq, idx);
+	} else {
+		pr_debug("cpufreq: change armdiv to %dkHz\n", freqs.new);
+		ret = s3c2416_cpufreq_set_armdiv(s3c_freq, freqs.new);
+	}
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+out:
+	mutex_unlock(&cpufreq_lock);
+
+	return ret;
+}
+
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
+{
+	int count, v, i, found;
+	struct cpufreq_frequency_table *freq;
+	struct s3c2416_dvfs *dvfs;
+
+	count = regulator_count_voltages(s3c_freq->vddarm);
+	if (count < 0) {
+		pr_err("cpufreq: Unable to check supported voltages\n");
+		return;
+	}
+
+	freq = s3c_freq->freq_table;
+	while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {
+		if (freq->frequency == CPUFREQ_ENTRY_INVALID)
+			continue;
+
+		dvfs = &s3c2416_dvfs_table[freq->index];
+		found = 0;
+
+		/* Check only the min-voltage, more is always ok on S3C2416 */
+		for (i = 0; i < count; i++) {
+			v = regulator_list_voltage(s3c_freq->vddarm, i);
+			if (v >= dvfs->vddarm_min)
+				found = 1;
+		}
+
+		if (!found) {
+			pr_debug("cpufreq: %dkHz unsupported by regulator\n",
+				 freq->frequency);
+			freq->frequency = CPUFREQ_ENTRY_INVALID;
+		}
+
+		freq++;
+	}
+
+	/* Guessed */
+	s3c_freq->regulator_latency = 1 * 1000 * 1000;
+}
+#endif
+
+static int s3c2416_cpufreq_reboot_notifier_evt(struct notifier_block *this,
+					       unsigned long event, void *ptr)
+{
+	struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
+	int ret;
+
+	mutex_lock(&cpufreq_lock);
+
+	/* disable further changes */
+	s3c_freq->disable_dvs = 1;
+
+	mutex_unlock(&cpufreq_lock);
+
+	/* some boards don't reconfigure the regulator on reboot, which
+	 * could lead to undervolting the cpu when the clock is reset.
+	 * Therefore we always leave the DVS mode on reboot.
+	 */
+	if (s3c_freq->is_dvs) {
+		pr_debug("cpufreq: leave dvs on reboot\n");
+		ret = cpufreq_driver_target(cpufreq_cpu_get(0), FREQ_SLEEP, 0);
+		if (ret < 0)
+			return NOTIFY_BAD;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block s3c2416_cpufreq_reboot_notifier = {
+	.notifier_call = s3c2416_cpufreq_reboot_notifier_evt,
+};
+
+static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+	struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
+	struct cpufreq_frequency_table *freq;
+	struct clk *msysclk;
+	unsigned long rate;
+	int ret;
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	msysclk = clk_get(NULL, "msysclk");
+	if (IS_ERR(msysclk)) {
+		ret = PTR_ERR(msysclk);
+		pr_err("cpufreq: Unable to obtain msysclk: %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * S3C2416 and S3C2450 share the same processor-ID and also provide no
+	 * other means to distinguish them other than through the rate of
+	 * msysclk. On S3C2416 msysclk runs at 800MHz and on S3C2450 at 533MHz.
+	 */
+	rate = clk_get_rate(msysclk);
+	if (rate == 800 * 1000 * 1000) {
+		pr_info("cpufreq: msysclk running at %lukHz, using S3C2416 frequency table\n",
+			rate / 1000);
+		s3c_freq->freq_table = s3c2416_freq_table;
+		policy->cpuinfo.max_freq = 400000;
+	} else if (rate / 1000 == 534000) {
+		pr_info("cpufreq: msysclk running at %lukHz, using S3C2450 frequency table\n",
+			rate / 1000);
+		s3c_freq->freq_table = s3c2450_freq_table;
+		policy->cpuinfo.max_freq = 534000;
+	}
+
+	/* not needed anymore */
+	clk_put(msysclk);
+
+	if (s3c_freq->freq_table == NULL) {
+		pr_err("cpufreq: No frequency information for this CPU, msysclk at %lukHz\n",
+		       rate / 1000);
+		return -ENODEV;
+	}
+
+	s3c_freq->is_dvs = 0;
+
+	s3c_freq->armdiv = clk_get(NULL, "armdiv");
+	if (IS_ERR(s3c_freq->armdiv)) {
+		ret = PTR_ERR(s3c_freq->armdiv);
+		pr_err("cpufreq: Unable to obtain ARMDIV: %d\n", ret);
+		return ret;
+	}
+
+	s3c_freq->hclk = clk_get(NULL, "hclk");
+	if (IS_ERR(s3c_freq->hclk)) {
+		ret = PTR_ERR(s3c_freq->hclk);
+		pr_err("cpufreq: Unable to obtain HCLK: %d\n", ret);
+		goto err_hclk;
+	}
+
+	/* chech hclk rate, we only support the common 133MHz for now
+	 * hclk could also run at 66MHz, but this not often used
+	 */
+	rate = clk_get_rate(s3c_freq->hclk);
+	if (rate < 133 * 1000 * 1000) {
+		pr_err("cpufreq: HCLK not at 133MHz\n");
+		clk_put(s3c_freq->hclk);
+		ret = -EINVAL;
+		goto err_armclk;
+	}
+
+	s3c_freq->armclk = clk_get(NULL, "armclk");
+	if (IS_ERR(s3c_freq->armclk)) {
+		ret = PTR_ERR(s3c_freq->armclk);
+		pr_err("cpufreq: Unable to obtain ARMCLK: %d\n", ret);
+		goto err_armclk;
+	}
+
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+	s3c_freq->vddarm = regulator_get(NULL, "vddarm");
+	if (IS_ERR(s3c_freq->vddarm)) {
+		ret = PTR_ERR(s3c_freq->vddarm);
+		pr_err("cpufreq: Failed to obtain VDDARM: %d\n", ret);
+		goto err_vddarm;
+	}
+
+	s3c2416_cpufreq_cfg_regulator(s3c_freq);
+#else
+	s3c_freq->regulator_latency = 0;
+#endif
+
+	freq = s3c_freq->freq_table;
+	while (freq->frequency != CPUFREQ_TABLE_END) {
+		/* special handling for dvs mode */
+		if (freq->index == 0) {
+			if (!s3c_freq->hclk) {
+				pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n",
+					 freq->frequency);
+				freq->frequency = CPUFREQ_ENTRY_INVALID;
+			} else {
+				freq++;
+				continue;
+			}
+		}
+
+		/* Check for frequencies we can generate */
+		rate = clk_round_rate(s3c_freq->armdiv,
+				      freq->frequency * 1000);
+		rate /= 1000;
+		if (rate != freq->frequency) {
+			pr_debug("cpufreq: %dkHz unsupported by clock (clk_round_rate return %lu)\n",
+				 freq->frequency, rate);
+			freq->frequency = CPUFREQ_ENTRY_INVALID;
+		}
+
+		freq++;
+	}
+
+	policy->cur = clk_get_rate(s3c_freq->armclk) / 1000;
+
+	/* Datasheet says PLL stabalisation time must be at least 300us,
+	 * so but add some fudge. (reference in LOCKCON0 register description)
+	 */
+	policy->cpuinfo.transition_latency = (500 * 1000) +
+					     s3c_freq->regulator_latency;
+
+	ret = cpufreq_frequency_table_cpuinfo(policy, s3c_freq->freq_table);
+	if (ret)
+		goto err_freq_table;
+
+	cpufreq_frequency_table_get_attr(s3c_freq->freq_table, 0);
+
+	register_reboot_notifier(&s3c2416_cpufreq_reboot_notifier);
+
+	return 0;
+
+err_freq_table:
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+	regulator_put(s3c_freq->vddarm);
+err_vddarm:
+#endif
+	clk_put(s3c_freq->armclk);
+err_armclk:
+	clk_put(s3c_freq->hclk);
+err_hclk:
+	clk_put(s3c_freq->armdiv);
+
+	return ret;
+}
+
+static struct freq_attr *s3c2416_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver s3c2416_cpufreq_driver = {
+	.owner		= THIS_MODULE,
+	.flags          = 0,
+	.verify		= s3c2416_cpufreq_verify_speed,
+	.target		= s3c2416_cpufreq_set_target,
+	.get		= s3c2416_cpufreq_get_speed,
+	.init		= s3c2416_cpufreq_driver_init,
+	.name		= "s3c2416",
+	.attr		= s3c2416_cpufreq_attr,
+};
+
+static int __init s3c2416_cpufreq_init(void)
+{
+	return cpufreq_register_driver(&s3c2416_cpufreq_driver);
+}
+module_init(s3c2416_cpufreq_init);
diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c
index a5e72cb..6f9490b 100644
--- a/drivers/cpufreq/s3c64xx-cpufreq.c
+++ b/drivers/cpufreq/s3c64xx-cpufreq.c
@@ -217,13 +217,6 @@
 	} else {
 		s3c64xx_cpufreq_config_regulator();
 	}
-
-	vddint = regulator_get(NULL, "vddint");
-	if (IS_ERR(vddint)) {
-		ret = PTR_ERR(vddint);
-		pr_err("Failed to obtain VDDINT: %d\n", ret);
-		vddint = NULL;
-	}
 #endif
 
 	freq = s3c64xx_freq_table;
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 6588f43..87411ce 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -53,6 +53,52 @@
 
 static int __cpuidle_register_device(struct cpuidle_device *dev);
 
+static inline int cpuidle_enter(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv, int index)
+{
+	struct cpuidle_state *target_state = &drv->states[index];
+	return target_state->enter(dev, drv, index);
+}
+
+static inline int cpuidle_enter_tk(struct cpuidle_device *dev,
+			       struct cpuidle_driver *drv, int index)
+{
+	return cpuidle_wrap_enter(dev, drv, index, cpuidle_enter);
+}
+
+typedef int (*cpuidle_enter_t)(struct cpuidle_device *dev,
+			       struct cpuidle_driver *drv, int index);
+
+static cpuidle_enter_t cpuidle_enter_ops;
+
+/**
+ * cpuidle_play_dead - cpu off-lining
+ *
+ * Only returns in case of an error
+ */
+int cpuidle_play_dead(void)
+{
+	struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
+	struct cpuidle_driver *drv = cpuidle_get_driver();
+	int i, dead_state = -1;
+	int power_usage = -1;
+
+	/* Find lowest-power state that supports long-term idle */
+	for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
+		struct cpuidle_state *s = &drv->states[i];
+
+		if (s->power_usage < power_usage && s->enter_dead) {
+			power_usage = s->power_usage;
+			dead_state = i;
+		}
+	}
+
+	if (dead_state != -1)
+		return drv->states[dead_state].enter_dead(dev, dead_state);
+
+	return -ENODEV;
+}
+
 /**
  * cpuidle_idle_call - the main idle loop
  *
@@ -63,7 +109,6 @@
 {
 	struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
 	struct cpuidle_driver *drv = cpuidle_get_driver();
-	struct cpuidle_state *target_state;
 	int next_state, entered_state;
 
 	if (off)
@@ -92,12 +137,10 @@
 		return 0;
 	}
 
-	target_state = &drv->states[next_state];
-
 	trace_power_start_rcuidle(POWER_CSTATE, next_state, dev->cpu);
 	trace_cpu_idle_rcuidle(next_state, dev->cpu);
 
-	entered_state = target_state->enter(dev, drv, next_state);
+	entered_state = cpuidle_enter_ops(dev, drv, next_state);
 
 	trace_power_end_rcuidle(dev->cpu);
 	trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
@@ -110,6 +153,8 @@
 		dev->states_usage[entered_state].time +=
 				(unsigned long long)dev->last_residency;
 		dev->states_usage[entered_state].usage++;
+	} else {
+		dev->last_residency = 0;
 	}
 
 	/* give the governor an opportunity to reflect on the outcome */
@@ -164,6 +209,37 @@
 
 EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
 
+/**
+ * cpuidle_wrap_enter - performs timekeeping and irqen around enter function
+ * @dev: pointer to a valid cpuidle_device object
+ * @drv: pointer to a valid cpuidle_driver object
+ * @index: index of the target cpuidle state.
+ */
+int cpuidle_wrap_enter(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv, int index,
+				int (*enter)(struct cpuidle_device *dev,
+					struct cpuidle_driver *drv, int index))
+{
+	ktime_t time_start, time_end;
+	s64 diff;
+
+	time_start = ktime_get();
+
+	index = enter(dev, drv, index);
+
+	time_end = ktime_get();
+
+	local_irq_enable();
+
+	diff = ktime_to_us(ktime_sub(time_end, time_start));
+	if (diff > INT_MAX)
+		diff = INT_MAX;
+
+	dev->last_residency = (int) diff;
+
+	return index;
+}
+
 #ifdef CONFIG_ARCH_HAS_CPU_RELAX
 static int poll_idle(struct cpuidle_device *dev,
 		struct cpuidle_driver *drv, int index)
@@ -197,6 +273,7 @@
 	state->power_usage = -1;
 	state->flags = 0;
 	state->enter = poll_idle;
+	state->disable = 0;
 }
 #else
 static void poll_idle_init(struct cpuidle_driver *drv) {}
@@ -212,13 +289,14 @@
 int cpuidle_enable_device(struct cpuidle_device *dev)
 {
 	int ret, i;
+	struct cpuidle_driver *drv = cpuidle_get_driver();
 
 	if (dev->enabled)
 		return 0;
-	if (!cpuidle_get_driver() || !cpuidle_curr_governor)
+	if (!drv || !cpuidle_curr_governor)
 		return -EIO;
 	if (!dev->state_count)
-		return -EINVAL;
+		dev->state_count = drv->state_count;
 
 	if (dev->registered == 0) {
 		ret = __cpuidle_register_device(dev);
@@ -226,13 +304,16 @@
 			return ret;
 	}
 
-	poll_idle_init(cpuidle_get_driver());
+	cpuidle_enter_ops = drv->en_core_tk_irqen ?
+		cpuidle_enter_tk : cpuidle_enter;
+
+	poll_idle_init(drv);
 
 	if ((ret = cpuidle_add_state_sysfs(dev)))
 		return ret;
 
 	if (cpuidle_curr_governor->enable &&
-	    (ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev)))
+	    (ret = cpuidle_curr_governor->enable(drv, dev)))
 		goto fail_sysfs;
 
 	for (i = 0; i < dev->state_count; i++) {
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 284d7af..40cd3f3 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -47,7 +47,7 @@
  */
 int cpuidle_register_driver(struct cpuidle_driver *drv)
 {
-	if (!drv)
+	if (!drv || !drv->state_count)
 		return -EINVAL;
 
 	if (cpuidle_disabled())
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index ad09526..0633575 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -236,7 +236,7 @@
 {
 	struct menu_device *data = &__get_cpu_var(menu_devices);
 	int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
-	unsigned int power_usage = -1;
+	int power_usage = -1;
 	int i;
 	int multiplier;
 	struct timespec t;
@@ -280,7 +280,8 @@
 	 * We want to default to C1 (hlt), not to busy polling
 	 * unless the timer is happening really really soon.
 	 */
-	if (data->expected_us > 5)
+	if (data->expected_us > 5 &&
+		drv->states[CPUIDLE_DRIVER_STATE_START].disable == 0)
 		data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
 
 	/*
@@ -290,6 +291,8 @@
 	for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
 		struct cpuidle_state *s = &drv->states[i];
 
+		if (s->disable)
+			continue;
 		if (s->target_residency > data->predicted_us)
 			continue;
 		if (s->exit_latency > latency_req)
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 3fe41fe..88032b4 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -11,6 +11,7 @@
 #include <linux/sysfs.h>
 #include <linux/slab.h>
 #include <linux/cpu.h>
+#include <linux/capability.h>
 
 #include "cpuidle.h"
 
@@ -222,6 +223,9 @@
 #define define_one_state_ro(_name, show) \
 static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
 
+#define define_one_state_rw(_name, show, store) \
+static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0644, show, store)
+
 #define define_show_state_function(_name) \
 static ssize_t show_state_##_name(struct cpuidle_state *state, \
 			 struct cpuidle_state_usage *state_usage, char *buf) \
@@ -229,6 +233,24 @@
 	return sprintf(buf, "%u\n", state->_name);\
 }
 
+#define define_store_state_function(_name) \
+static ssize_t store_state_##_name(struct cpuidle_state *state, \
+		const char *buf, size_t size) \
+{ \
+	long value; \
+	int err; \
+	if (!capable(CAP_SYS_ADMIN)) \
+		return -EPERM; \
+	err = kstrtol(buf, 0, &value); \
+	if (err) \
+		return err; \
+	if (value) \
+		state->disable = 1; \
+	else \
+		state->disable = 0; \
+	return size; \
+}
+
 #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) \
@@ -251,6 +273,8 @@
 define_show_state_ull_function(time)
 define_show_state_str_function(name)
 define_show_state_str_function(desc)
+define_show_state_function(disable)
+define_store_state_function(disable)
 
 define_one_state_ro(name, show_state_name);
 define_one_state_ro(desc, show_state_desc);
@@ -258,6 +282,7 @@
 define_one_state_ro(power, show_state_power_usage);
 define_one_state_ro(usage, show_state_usage);
 define_one_state_ro(time, show_state_time);
+define_one_state_rw(disable, show_state_disable, store_state_disable);
 
 static struct attribute *cpuidle_state_default_attrs[] = {
 	&attr_name.attr,
@@ -266,6 +291,7 @@
 	&attr_power.attr,
 	&attr_usage.attr,
 	&attr_time.attr,
+	&attr_disable.attr,
 	NULL
 };
 
@@ -287,8 +313,22 @@
 	return ret;
 }
 
+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);
+	struct cpuidle_state_attr *cattr = attr_to_stateattr(attr);
+
+	if (cattr->store)
+		ret = cattr->store(state, buf, size);
+
+	return ret;
+}
+
 static const struct sysfs_ops cpuidle_state_sysfs_ops = {
 	.show = cpuidle_state_show,
+	.store = cpuidle_state_store,
 };
 
 static void cpuidle_state_sysfs_release(struct kobject *kobj)
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index e707979..ab9abb4 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -64,7 +64,6 @@
 config ZCRYPT
 	tristate "Support for PCI-attached cryptographic adapters"
 	depends on S390
-	select ZCRYPT_MONOLITHIC if ZCRYPT="y"
 	select HW_RANDOM
 	help
 	  Select this option if you want to use a PCI-attached cryptographic
@@ -77,14 +76,6 @@
 	  + Crypto Express3 Coprocessor (CEX3C)
 	  + Crypto Express3 Accelerator (CEX3A)
 
-config ZCRYPT_MONOLITHIC
-	bool "Monolithic zcrypt module"
-	depends on ZCRYPT
-	help
-	  Select this option if you want to have a single module z90crypt,
-	  that contains all parts of the crypto device driver (ap bus,
-	  request router and all the card drivers).
-
 config CRYPTO_SHA1_S390
 	tristate "SHA1 digest algorithm"
 	depends on S390
diff --git a/drivers/devfreq/exynos4_bus.c b/drivers/devfreq/exynos4_bus.c
index 1a361e9..88ddc77 100644
--- a/drivers/devfreq/exynos4_bus.c
+++ b/drivers/devfreq/exynos4_bus.c
@@ -311,51 +311,51 @@
 	/* Change Divider - DMC0 */
 	tmp = data->dmc_divtable[index];
 
-	__raw_writel(tmp, S5P_CLKDIV_DMC0);
+	__raw_writel(tmp, EXYNOS4_CLKDIV_DMC0);
 
 	do {
-		tmp = __raw_readl(S5P_CLKDIV_STAT_DMC0);
+		tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_DMC0);
 	} while (tmp & 0x11111111);
 
 	/* Change Divider - TOP */
 	tmp = data->top_divtable[index];
 
-	__raw_writel(tmp, S5P_CLKDIV_TOP);
+	__raw_writel(tmp, EXYNOS4_CLKDIV_TOP);
 
 	do {
-		tmp = __raw_readl(S5P_CLKDIV_STAT_TOP);
+		tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_TOP);
 	} while (tmp & 0x11111);
 
 	/* Change Divider - LEFTBUS */
-	tmp = __raw_readl(S5P_CLKDIV_LEFTBUS);
+	tmp = __raw_readl(EXYNOS4_CLKDIV_LEFTBUS);
 
-	tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
+	tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
 
 	tmp |= ((exynos4210_clkdiv_lr_bus[index][0] <<
-				S5P_CLKDIV_BUS_GDLR_SHIFT) |
+				EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
 		(exynos4210_clkdiv_lr_bus[index][1] <<
-				S5P_CLKDIV_BUS_GPLR_SHIFT));
+				EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
 
-	__raw_writel(tmp, S5P_CLKDIV_LEFTBUS);
+	__raw_writel(tmp, EXYNOS4_CLKDIV_LEFTBUS);
 
 	do {
-		tmp = __raw_readl(S5P_CLKDIV_STAT_LEFTBUS);
+		tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_LEFTBUS);
 	} while (tmp & 0x11);
 
 	/* Change Divider - RIGHTBUS */
-	tmp = __raw_readl(S5P_CLKDIV_RIGHTBUS);
+	tmp = __raw_readl(EXYNOS4_CLKDIV_RIGHTBUS);
 
-	tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
+	tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
 
 	tmp |= ((exynos4210_clkdiv_lr_bus[index][0] <<
-				S5P_CLKDIV_BUS_GDLR_SHIFT) |
+				EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
 		(exynos4210_clkdiv_lr_bus[index][1] <<
-				S5P_CLKDIV_BUS_GPLR_SHIFT));
+				EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
 
-	__raw_writel(tmp, S5P_CLKDIV_RIGHTBUS);
+	__raw_writel(tmp, EXYNOS4_CLKDIV_RIGHTBUS);
 
 	do {
-		tmp = __raw_readl(S5P_CLKDIV_STAT_RIGHTBUS);
+		tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_RIGHTBUS);
 	} while (tmp & 0x11);
 
 	return 0;
@@ -376,137 +376,137 @@
 	/* Change Divider - DMC0 */
 	tmp = data->dmc_divtable[index];
 
-	__raw_writel(tmp, S5P_CLKDIV_DMC0);
+	__raw_writel(tmp, EXYNOS4_CLKDIV_DMC0);
 
 	do {
-		tmp = __raw_readl(S5P_CLKDIV_STAT_DMC0);
+		tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_DMC0);
 	} while (tmp & 0x11111111);
 
 	/* Change Divider - DMC1 */
-	tmp = __raw_readl(S5P_CLKDIV_DMC1);
+	tmp = __raw_readl(EXYNOS4_CLKDIV_DMC1);
 
-	tmp &= ~(S5P_CLKDIV_DMC1_G2D_ACP_MASK |
-		S5P_CLKDIV_DMC1_C2C_MASK |
-		S5P_CLKDIV_DMC1_C2CACLK_MASK);
+	tmp &= ~(EXYNOS4_CLKDIV_DMC1_G2D_ACP_MASK |
+		EXYNOS4_CLKDIV_DMC1_C2C_MASK |
+		EXYNOS4_CLKDIV_DMC1_C2CACLK_MASK);
 
 	tmp |= ((exynos4x12_clkdiv_dmc1[index][0] <<
-				S5P_CLKDIV_DMC1_G2D_ACP_SHIFT) |
+				EXYNOS4_CLKDIV_DMC1_G2D_ACP_SHIFT) |
 		(exynos4x12_clkdiv_dmc1[index][1] <<
-				S5P_CLKDIV_DMC1_C2C_SHIFT) |
+				EXYNOS4_CLKDIV_DMC1_C2C_SHIFT) |
 		(exynos4x12_clkdiv_dmc1[index][2] <<
-				S5P_CLKDIV_DMC1_C2CACLK_SHIFT));
+				EXYNOS4_CLKDIV_DMC1_C2CACLK_SHIFT));
 
-	__raw_writel(tmp, S5P_CLKDIV_DMC1);
+	__raw_writel(tmp, EXYNOS4_CLKDIV_DMC1);
 
 	do {
-		tmp = __raw_readl(S5P_CLKDIV_STAT_DMC1);
+		tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_DMC1);
 	} while (tmp & 0x111111);
 
 	/* Change Divider - TOP */
-	tmp = __raw_readl(S5P_CLKDIV_TOP);
+	tmp = __raw_readl(EXYNOS4_CLKDIV_TOP);
 
-	tmp &= ~(S5P_CLKDIV_TOP_ACLK266_GPS_MASK |
-		S5P_CLKDIV_TOP_ACLK100_MASK |
-		S5P_CLKDIV_TOP_ACLK160_MASK |
-		S5P_CLKDIV_TOP_ACLK133_MASK |
-		S5P_CLKDIV_TOP_ONENAND_MASK);
+	tmp &= ~(EXYNOS4_CLKDIV_TOP_ACLK266_GPS_MASK |
+		EXYNOS4_CLKDIV_TOP_ACLK100_MASK |
+		EXYNOS4_CLKDIV_TOP_ACLK160_MASK |
+		EXYNOS4_CLKDIV_TOP_ACLK133_MASK |
+		EXYNOS4_CLKDIV_TOP_ONENAND_MASK);
 
 	tmp |= ((exynos4x12_clkdiv_top[index][0] <<
-				S5P_CLKDIV_TOP_ACLK266_GPS_SHIFT) |
+				EXYNOS4_CLKDIV_TOP_ACLK266_GPS_SHIFT) |
 		(exynos4x12_clkdiv_top[index][1] <<
-				S5P_CLKDIV_TOP_ACLK100_SHIFT) |
+				EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT) |
 		(exynos4x12_clkdiv_top[index][2] <<
-				S5P_CLKDIV_TOP_ACLK160_SHIFT) |
+				EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT) |
 		(exynos4x12_clkdiv_top[index][3] <<
-				S5P_CLKDIV_TOP_ACLK133_SHIFT) |
+				EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT) |
 		(exynos4x12_clkdiv_top[index][4] <<
-				S5P_CLKDIV_TOP_ONENAND_SHIFT));
+				EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT));
 
-	__raw_writel(tmp, S5P_CLKDIV_TOP);
+	__raw_writel(tmp, EXYNOS4_CLKDIV_TOP);
 
 	do {
-		tmp = __raw_readl(S5P_CLKDIV_STAT_TOP);
+		tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_TOP);
 	} while (tmp & 0x11111);
 
 	/* Change Divider - LEFTBUS */
-	tmp = __raw_readl(S5P_CLKDIV_LEFTBUS);
+	tmp = __raw_readl(EXYNOS4_CLKDIV_LEFTBUS);
 
-	tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
+	tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
 
 	tmp |= ((exynos4x12_clkdiv_lr_bus[index][0] <<
-				S5P_CLKDIV_BUS_GDLR_SHIFT) |
+				EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
 		(exynos4x12_clkdiv_lr_bus[index][1] <<
-				S5P_CLKDIV_BUS_GPLR_SHIFT));
+				EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
 
-	__raw_writel(tmp, S5P_CLKDIV_LEFTBUS);
+	__raw_writel(tmp, EXYNOS4_CLKDIV_LEFTBUS);
 
 	do {
-		tmp = __raw_readl(S5P_CLKDIV_STAT_LEFTBUS);
+		tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_LEFTBUS);
 	} while (tmp & 0x11);
 
 	/* Change Divider - RIGHTBUS */
-	tmp = __raw_readl(S5P_CLKDIV_RIGHTBUS);
+	tmp = __raw_readl(EXYNOS4_CLKDIV_RIGHTBUS);
 
-	tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
+	tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
 
 	tmp |= ((exynos4x12_clkdiv_lr_bus[index][0] <<
-				S5P_CLKDIV_BUS_GDLR_SHIFT) |
+				EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
 		(exynos4x12_clkdiv_lr_bus[index][1] <<
-				S5P_CLKDIV_BUS_GPLR_SHIFT));
+				EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
 
-	__raw_writel(tmp, S5P_CLKDIV_RIGHTBUS);
+	__raw_writel(tmp, EXYNOS4_CLKDIV_RIGHTBUS);
 
 	do {
-		tmp = __raw_readl(S5P_CLKDIV_STAT_RIGHTBUS);
+		tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_RIGHTBUS);
 	} while (tmp & 0x11);
 
 	/* Change Divider - MFC */
-	tmp = __raw_readl(S5P_CLKDIV_MFC);
+	tmp = __raw_readl(EXYNOS4_CLKDIV_MFC);
 
-	tmp &= ~(S5P_CLKDIV_MFC_MASK);
+	tmp &= ~(EXYNOS4_CLKDIV_MFC_MASK);
 
 	tmp |= ((exynos4x12_clkdiv_sclkip[index][0] <<
-				S5P_CLKDIV_MFC_SHIFT));
+				EXYNOS4_CLKDIV_MFC_SHIFT));
 
-	__raw_writel(tmp, S5P_CLKDIV_MFC);
+	__raw_writel(tmp, EXYNOS4_CLKDIV_MFC);
 
 	do {
-		tmp = __raw_readl(S5P_CLKDIV_STAT_MFC);
+		tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_MFC);
 	} while (tmp & 0x1);
 
 	/* Change Divider - JPEG */
-	tmp = __raw_readl(S5P_CLKDIV_CAM1);
+	tmp = __raw_readl(EXYNOS4_CLKDIV_CAM1);
 
-	tmp &= ~(S5P_CLKDIV_CAM1_JPEG_MASK);
+	tmp &= ~(EXYNOS4_CLKDIV_CAM1_JPEG_MASK);
 
 	tmp |= ((exynos4x12_clkdiv_sclkip[index][1] <<
-				S5P_CLKDIV_CAM1_JPEG_SHIFT));
+				EXYNOS4_CLKDIV_CAM1_JPEG_SHIFT));
 
-	__raw_writel(tmp, S5P_CLKDIV_CAM1);
+	__raw_writel(tmp, EXYNOS4_CLKDIV_CAM1);
 
 	do {
-		tmp = __raw_readl(S5P_CLKDIV_STAT_CAM1);
+		tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_CAM1);
 	} while (tmp & 0x1);
 
 	/* Change Divider - FIMC0~3 */
-	tmp = __raw_readl(S5P_CLKDIV_CAM);
+	tmp = __raw_readl(EXYNOS4_CLKDIV_CAM);
 
-	tmp &= ~(S5P_CLKDIV_CAM_FIMC0_MASK | S5P_CLKDIV_CAM_FIMC1_MASK |
-		S5P_CLKDIV_CAM_FIMC2_MASK | S5P_CLKDIV_CAM_FIMC3_MASK);
+	tmp &= ~(EXYNOS4_CLKDIV_CAM_FIMC0_MASK | EXYNOS4_CLKDIV_CAM_FIMC1_MASK |
+		EXYNOS4_CLKDIV_CAM_FIMC2_MASK | EXYNOS4_CLKDIV_CAM_FIMC3_MASK);
 
 	tmp |= ((exynos4x12_clkdiv_sclkip[index][2] <<
-				S5P_CLKDIV_CAM_FIMC0_SHIFT) |
+				EXYNOS4_CLKDIV_CAM_FIMC0_SHIFT) |
 		(exynos4x12_clkdiv_sclkip[index][2] <<
-				S5P_CLKDIV_CAM_FIMC1_SHIFT) |
+				EXYNOS4_CLKDIV_CAM_FIMC1_SHIFT) |
 		(exynos4x12_clkdiv_sclkip[index][2] <<
-				S5P_CLKDIV_CAM_FIMC2_SHIFT) |
+				EXYNOS4_CLKDIV_CAM_FIMC2_SHIFT) |
 		(exynos4x12_clkdiv_sclkip[index][2] <<
-				S5P_CLKDIV_CAM_FIMC3_SHIFT));
+				EXYNOS4_CLKDIV_CAM_FIMC3_SHIFT));
 
-	__raw_writel(tmp, S5P_CLKDIV_CAM);
+	__raw_writel(tmp, EXYNOS4_CLKDIV_CAM);
 
 	do {
-		tmp = __raw_readl(S5P_CLKDIV_STAT_CAM1);
+		tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_CAM1);
 	} while (tmp & 0x1111);
 
 	return 0;
@@ -760,55 +760,55 @@
 	int mgrp;
 	int i, err = 0;
 
-	tmp = __raw_readl(S5P_CLKDIV_DMC0);
+	tmp = __raw_readl(EXYNOS4_CLKDIV_DMC0);
 	for (i = LV_0; i < EX4210_LV_NUM; i++) {
-		tmp &= ~(S5P_CLKDIV_DMC0_ACP_MASK |
-			S5P_CLKDIV_DMC0_ACPPCLK_MASK |
-			S5P_CLKDIV_DMC0_DPHY_MASK |
-			S5P_CLKDIV_DMC0_DMC_MASK |
-			S5P_CLKDIV_DMC0_DMCD_MASK |
-			S5P_CLKDIV_DMC0_DMCP_MASK |
-			S5P_CLKDIV_DMC0_COPY2_MASK |
-			S5P_CLKDIV_DMC0_CORETI_MASK);
+		tmp &= ~(EXYNOS4_CLKDIV_DMC0_ACP_MASK |
+			EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK |
+			EXYNOS4_CLKDIV_DMC0_DPHY_MASK |
+			EXYNOS4_CLKDIV_DMC0_DMC_MASK |
+			EXYNOS4_CLKDIV_DMC0_DMCD_MASK |
+			EXYNOS4_CLKDIV_DMC0_DMCP_MASK |
+			EXYNOS4_CLKDIV_DMC0_COPY2_MASK |
+			EXYNOS4_CLKDIV_DMC0_CORETI_MASK);
 
 		tmp |= ((exynos4210_clkdiv_dmc0[i][0] <<
-					S5P_CLKDIV_DMC0_ACP_SHIFT) |
+					EXYNOS4_CLKDIV_DMC0_ACP_SHIFT) |
 			(exynos4210_clkdiv_dmc0[i][1] <<
-					S5P_CLKDIV_DMC0_ACPPCLK_SHIFT) |
+					EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT) |
 			(exynos4210_clkdiv_dmc0[i][2] <<
-					S5P_CLKDIV_DMC0_DPHY_SHIFT) |
+					EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT) |
 			(exynos4210_clkdiv_dmc0[i][3] <<
-					S5P_CLKDIV_DMC0_DMC_SHIFT) |
+					EXYNOS4_CLKDIV_DMC0_DMC_SHIFT) |
 			(exynos4210_clkdiv_dmc0[i][4] <<
-					S5P_CLKDIV_DMC0_DMCD_SHIFT) |
+					EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT) |
 			(exynos4210_clkdiv_dmc0[i][5] <<
-					S5P_CLKDIV_DMC0_DMCP_SHIFT) |
+					EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT) |
 			(exynos4210_clkdiv_dmc0[i][6] <<
-					S5P_CLKDIV_DMC0_COPY2_SHIFT) |
+					EXYNOS4_CLKDIV_DMC0_COPY2_SHIFT) |
 			(exynos4210_clkdiv_dmc0[i][7] <<
-					S5P_CLKDIV_DMC0_CORETI_SHIFT));
+					EXYNOS4_CLKDIV_DMC0_CORETI_SHIFT));
 
 		data->dmc_divtable[i] = tmp;
 	}
 
-	tmp = __raw_readl(S5P_CLKDIV_TOP);
+	tmp = __raw_readl(EXYNOS4_CLKDIV_TOP);
 	for (i = LV_0; i <  EX4210_LV_NUM; i++) {
-		tmp &= ~(S5P_CLKDIV_TOP_ACLK200_MASK |
-			S5P_CLKDIV_TOP_ACLK100_MASK |
-			S5P_CLKDIV_TOP_ACLK160_MASK |
-			S5P_CLKDIV_TOP_ACLK133_MASK |
-			S5P_CLKDIV_TOP_ONENAND_MASK);
+		tmp &= ~(EXYNOS4_CLKDIV_TOP_ACLK200_MASK |
+			EXYNOS4_CLKDIV_TOP_ACLK100_MASK |
+			EXYNOS4_CLKDIV_TOP_ACLK160_MASK |
+			EXYNOS4_CLKDIV_TOP_ACLK133_MASK |
+			EXYNOS4_CLKDIV_TOP_ONENAND_MASK);
 
 		tmp |= ((exynos4210_clkdiv_top[i][0] <<
-					S5P_CLKDIV_TOP_ACLK200_SHIFT) |
+					EXYNOS4_CLKDIV_TOP_ACLK200_SHIFT) |
 			(exynos4210_clkdiv_top[i][1] <<
-					S5P_CLKDIV_TOP_ACLK100_SHIFT) |
+					EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT) |
 			(exynos4210_clkdiv_top[i][2] <<
-					S5P_CLKDIV_TOP_ACLK160_SHIFT) |
+					EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT) |
 			(exynos4210_clkdiv_top[i][3] <<
-					S5P_CLKDIV_TOP_ACLK133_SHIFT) |
+					EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT) |
 			(exynos4210_clkdiv_top[i][4] <<
-					S5P_CLKDIV_TOP_ONENAND_SHIFT));
+					EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT));
 
 		data->top_divtable[i] = tmp;
 	}
@@ -868,32 +868,32 @@
 	int ret;
 
 	/* Enable pause function for DREX2 DVFS */
-	tmp = __raw_readl(S5P_DMC_PAUSE_CTRL);
-	tmp |= DMC_PAUSE_ENABLE;
-	__raw_writel(tmp, S5P_DMC_PAUSE_CTRL);
+	tmp = __raw_readl(EXYNOS4_DMC_PAUSE_CTRL);
+	tmp |= EXYNOS4_DMC_PAUSE_ENABLE;
+	__raw_writel(tmp, EXYNOS4_DMC_PAUSE_CTRL);
 
-	tmp = __raw_readl(S5P_CLKDIV_DMC0);
+	tmp = __raw_readl(EXYNOS4_CLKDIV_DMC0);
 
 	for (i = 0; i <  EX4x12_LV_NUM; i++) {
-		tmp &= ~(S5P_CLKDIV_DMC0_ACP_MASK |
-			S5P_CLKDIV_DMC0_ACPPCLK_MASK |
-			S5P_CLKDIV_DMC0_DPHY_MASK |
-			S5P_CLKDIV_DMC0_DMC_MASK |
-			S5P_CLKDIV_DMC0_DMCD_MASK |
-			S5P_CLKDIV_DMC0_DMCP_MASK);
+		tmp &= ~(EXYNOS4_CLKDIV_DMC0_ACP_MASK |
+			EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK |
+			EXYNOS4_CLKDIV_DMC0_DPHY_MASK |
+			EXYNOS4_CLKDIV_DMC0_DMC_MASK |
+			EXYNOS4_CLKDIV_DMC0_DMCD_MASK |
+			EXYNOS4_CLKDIV_DMC0_DMCP_MASK);
 
 		tmp |= ((exynos4x12_clkdiv_dmc0[i][0] <<
-					S5P_CLKDIV_DMC0_ACP_SHIFT) |
+					EXYNOS4_CLKDIV_DMC0_ACP_SHIFT) |
 			(exynos4x12_clkdiv_dmc0[i][1] <<
-					S5P_CLKDIV_DMC0_ACPPCLK_SHIFT) |
+					EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT) |
 			(exynos4x12_clkdiv_dmc0[i][2] <<
-					S5P_CLKDIV_DMC0_DPHY_SHIFT) |
+					EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT) |
 			(exynos4x12_clkdiv_dmc0[i][3] <<
-					S5P_CLKDIV_DMC0_DMC_SHIFT) |
+					EXYNOS4_CLKDIV_DMC0_DMC_SHIFT) |
 			(exynos4x12_clkdiv_dmc0[i][4] <<
-					S5P_CLKDIV_DMC0_DMCD_SHIFT) |
+					EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT) |
 			(exynos4x12_clkdiv_dmc0[i][5] <<
-					S5P_CLKDIV_DMC0_DMCP_SHIFT));
+					EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT));
 
 		data->dmc_divtable[i] = tmp;
 	}
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index f1a2749..cf9da36 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -201,7 +201,6 @@
 	tristate "DMA API Driver for PL330"
 	select DMA_ENGINE
 	depends on ARM_AMBA
-	select PL330
 	help
 	  Select if your platform has one or more PL330 DMACs.
 	  You need to provide platform specific settings via
@@ -231,7 +230,7 @@
 
 config IMX_DMA
 	tristate "i.MX DMA support"
-	depends on IMX_HAVE_DMA_V1
+	depends on ARCH_MXC
 	select DMA_ENGINE
 	help
 	  Support the i.MX DMA engine. This engine is integrated into
@@ -252,6 +251,15 @@
 	help
 	  Enable support for the Cirrus Logic EP93xx M2P/M2M DMA controller.
 
+config DMA_SA11X0
+	tristate "SA-11x0 DMA support"
+	depends on ARCH_SA1100
+	select DMA_ENGINE
+	help
+	  Support the DMA engine found on Intel StrongARM SA-1100 and
+	  SA-1110 SoCs.  This DMA engine can only be used with on-chip
+	  devices.
+
 config DMA_ENGINE
 	bool
 
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 009a222..86b795b 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -27,3 +27,4 @@
 obj-$(CONFIG_PCH_DMA) += pch_dma.o
 obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o
 obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
+obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 8a28158..c301a8e 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -85,6 +85,8 @@
 #include <linux/slab.h>
 #include <asm/hardware/pl080.h>
 
+#include "dmaengine.h"
+
 #define DRIVER_NAME	"pl08xdmac"
 
 static struct amba_driver pl08x_amba_driver;
@@ -649,7 +651,7 @@
 			}
 
 			if ((bd.srcbus.addr % bd.srcbus.buswidth) ||
-					(bd.srcbus.addr % bd.srcbus.buswidth)) {
+					(bd.dstbus.addr % bd.dstbus.buswidth)) {
 				dev_err(&pl08x->adev->dev,
 					"%s src & dst address must be aligned to src"
 					" & dst width if peripheral is flow controller",
@@ -919,13 +921,10 @@
 	struct pl08x_dma_chan *plchan = to_pl08x_chan(tx->chan);
 	struct pl08x_txd *txd = to_pl08x_txd(tx);
 	unsigned long flags;
+	dma_cookie_t cookie;
 
 	spin_lock_irqsave(&plchan->lock, flags);
-
-	plchan->chan.cookie += 1;
-	if (plchan->chan.cookie < 0)
-		plchan->chan.cookie = 1;
-	tx->cookie = plchan->chan.cookie;
+	cookie = dma_cookie_assign(tx);
 
 	/* Put this onto the pending list */
 	list_add_tail(&txd->node, &plchan->pend_list);
@@ -945,7 +944,7 @@
 
 	spin_unlock_irqrestore(&plchan->lock, flags);
 
-	return tx->cookie;
+	return cookie;
 }
 
 static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt(
@@ -965,31 +964,17 @@
 		dma_cookie_t cookie, struct dma_tx_state *txstate)
 {
 	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
-	dma_cookie_t last_used;
-	dma_cookie_t last_complete;
 	enum dma_status ret;
-	u32 bytesleft = 0;
 
-	last_used = plchan->chan.cookie;
-	last_complete = plchan->lc;
-
-	ret = dma_async_is_complete(cookie, last_complete, last_used);
-	if (ret == DMA_SUCCESS) {
-		dma_set_tx_state(txstate, last_complete, last_used, 0);
+	ret = dma_cookie_status(chan, cookie, txstate);
+	if (ret == DMA_SUCCESS)
 		return ret;
-	}
 
 	/*
 	 * This cookie not complete yet
+	 * Get number of bytes left in the active transactions and queue
 	 */
-	last_used = plchan->chan.cookie;
-	last_complete = plchan->lc;
-
-	/* Get number of bytes left in the active transactions and queue */
-	bytesleft = pl08x_getbytes_chan(plchan);
-
-	dma_set_tx_state(txstate, last_complete, last_used,
-			 bytesleft);
+	dma_set_residue(txstate, pl08x_getbytes_chan(plchan));
 
 	if (plchan->state == PL08X_CHAN_PAUSED)
 		return DMA_PAUSED;
@@ -1139,6 +1124,8 @@
 	cctl |= burst << PL080_CONTROL_SB_SIZE_SHIFT;
 	cctl |= burst << PL080_CONTROL_DB_SIZE_SHIFT;
 
+	plchan->device_fc = config->device_fc;
+
 	if (plchan->runtime_direction == DMA_DEV_TO_MEM) {
 		plchan->src_addr = config->src_addr;
 		plchan->src_cctl = pl08x_cctl(cctl) | PL080_CONTROL_DST_INCR |
@@ -1326,7 +1313,7 @@
 static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 		struct dma_chan *chan, struct scatterlist *sgl,
 		unsigned int sg_len, enum dma_transfer_direction direction,
-		unsigned long flags)
+		unsigned long flags, void *context)
 {
 	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
 	struct pl08x_driver_data *pl08x = plchan->host;
@@ -1370,7 +1357,7 @@
 		return NULL;
 	}
 
-	if (plchan->cd->device_fc)
+	if (plchan->device_fc)
 		tmp = (direction == DMA_MEM_TO_DEV) ? PL080_FLOW_MEM2PER_PER :
 			PL080_FLOW_PER2MEM_PER;
 	else
@@ -1541,7 +1528,7 @@
 
 	if (txd) {
 		/* Update last completed */
-		plchan->lc = txd->tx.cookie;
+		dma_cookie_complete(&txd->tx);
 	}
 
 	/* If a new descriptor is queued, set it up plchan->at is NULL here */
@@ -1722,8 +1709,7 @@
 			 chan->name);
 
 		chan->chan.device = dmadev;
-		chan->chan.cookie = 0;
-		chan->lc = 0;
+		dma_cookie_init(&chan->chan);
 
 		spin_lock_init(&chan->lock);
 		INIT_LIST_HEAD(&chan->pend_list);
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index f4aed5f..7aa58d2 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -27,6 +27,7 @@
 #include <linux/of_device.h>
 
 #include "at_hdmac_regs.h"
+#include "dmaengine.h"
 
 /*
  * Glossary
@@ -192,27 +193,6 @@
 }
 
 /**
- * atc_assign_cookie - compute and assign new cookie
- * @atchan: channel we work on
- * @desc: descriptor to assign cookie for
- *
- * Called with atchan->lock held and bh disabled
- */
-static dma_cookie_t
-atc_assign_cookie(struct at_dma_chan *atchan, struct at_desc *desc)
-{
-	dma_cookie_t cookie = atchan->chan_common.cookie;
-
-	if (++cookie < 0)
-		cookie = 1;
-
-	atchan->chan_common.cookie = cookie;
-	desc->txd.cookie = cookie;
-
-	return cookie;
-}
-
-/**
  * atc_dostart - starts the DMA engine for real
  * @atchan: the channel we want to start
  * @first: first descriptor in the list we want to begin with
@@ -269,7 +249,7 @@
 	dev_vdbg(chan2dev(&atchan->chan_common),
 		"descriptor %u complete\n", txd->cookie);
 
-	atchan->completed_cookie = txd->cookie;
+	dma_cookie_complete(txd);
 
 	/* move children to free_list */
 	list_splice_init(&desc->tx_list, &atchan->free_list);
@@ -547,7 +527,7 @@
 	unsigned long		flags;
 
 	spin_lock_irqsave(&atchan->lock, flags);
-	cookie = atc_assign_cookie(atchan, desc);
+	cookie = dma_cookie_assign(tx);
 
 	if (list_empty(&atchan->active_list)) {
 		dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n",
@@ -659,14 +639,16 @@
  * @sg_len: number of entries in @scatterlist
  * @direction: DMA direction
  * @flags: tx descriptor status flags
+ * @context: transaction context (ignored)
  */
 static struct dma_async_tx_descriptor *
 atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 		unsigned int sg_len, enum dma_transfer_direction direction,
-		unsigned long flags)
+		unsigned long flags, void *context)
 {
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct at_dma_slave	*atslave = chan->private;
+	struct dma_slave_config	*sconfig = &atchan->dma_sconfig;
 	struct at_desc		*first = NULL;
 	struct at_desc		*prev = NULL;
 	u32			ctrla;
@@ -688,19 +670,18 @@
 		return NULL;
 	}
 
-	reg_width = atslave->reg_width;
-
 	ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla;
 	ctrlb = ATC_IEN;
 
 	switch (direction) {
 	case DMA_MEM_TO_DEV:
+		reg_width = convert_buswidth(sconfig->dst_addr_width);
 		ctrla |=  ATC_DST_WIDTH(reg_width);
 		ctrlb |=  ATC_DST_ADDR_MODE_FIXED
 			| ATC_SRC_ADDR_MODE_INCR
 			| ATC_FC_MEM2PER
 			| ATC_SIF(AT_DMA_MEM_IF) | ATC_DIF(AT_DMA_PER_IF);
-		reg = atslave->tx_reg;
+		reg = sconfig->dst_addr;
 		for_each_sg(sgl, sg, sg_len, i) {
 			struct at_desc	*desc;
 			u32		len;
@@ -728,13 +709,14 @@
 		}
 		break;
 	case DMA_DEV_TO_MEM:
+		reg_width = convert_buswidth(sconfig->src_addr_width);
 		ctrla |=  ATC_SRC_WIDTH(reg_width);
 		ctrlb |=  ATC_DST_ADDR_MODE_INCR
 			| ATC_SRC_ADDR_MODE_FIXED
 			| ATC_FC_PER2MEM
 			| ATC_SIF(AT_DMA_PER_IF) | ATC_DIF(AT_DMA_MEM_IF);
 
-		reg = atslave->rx_reg;
+		reg = sconfig->src_addr;
 		for_each_sg(sgl, sg, sg_len, i) {
 			struct at_desc	*desc;
 			u32		len;
@@ -810,12 +792,15 @@
  * atc_dma_cyclic_fill_desc - Fill one period decriptor
  */
 static int
-atc_dma_cyclic_fill_desc(struct at_dma_slave *atslave, struct at_desc *desc,
+atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
 		unsigned int period_index, dma_addr_t buf_addr,
-		size_t period_len, enum dma_transfer_direction direction)
+		unsigned int reg_width, size_t period_len,
+		enum dma_transfer_direction direction)
 {
-	u32		ctrla;
-	unsigned int	reg_width = atslave->reg_width;
+	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
+	struct at_dma_slave	*atslave = chan->private;
+	struct dma_slave_config	*sconfig = &atchan->dma_sconfig;
+	u32			ctrla;
 
 	/* prepare common CRTLA value */
 	ctrla =   ATC_DEFAULT_CTRLA | atslave->ctrla
@@ -826,7 +811,7 @@
 	switch (direction) {
 	case DMA_MEM_TO_DEV:
 		desc->lli.saddr = buf_addr + (period_len * period_index);
-		desc->lli.daddr = atslave->tx_reg;
+		desc->lli.daddr = sconfig->dst_addr;
 		desc->lli.ctrla = ctrla;
 		desc->lli.ctrlb = ATC_DST_ADDR_MODE_FIXED
 				| ATC_SRC_ADDR_MODE_INCR
@@ -836,7 +821,7 @@
 		break;
 
 	case DMA_DEV_TO_MEM:
-		desc->lli.saddr = atslave->rx_reg;
+		desc->lli.saddr = sconfig->src_addr;
 		desc->lli.daddr = buf_addr + (period_len * period_index);
 		desc->lli.ctrla = ctrla;
 		desc->lli.ctrlb = ATC_DST_ADDR_MODE_INCR
@@ -860,16 +845,20 @@
  * @buf_len: total number of bytes for the entire buffer
  * @period_len: number of bytes for each period
  * @direction: transfer direction, to or from device
+ * @context: transfer context (ignored)
  */
 static struct dma_async_tx_descriptor *
 atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
-		size_t period_len, enum dma_transfer_direction direction)
+		size_t period_len, enum dma_transfer_direction direction,
+		void *context)
 {
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct at_dma_slave	*atslave = chan->private;
+	struct dma_slave_config	*sconfig = &atchan->dma_sconfig;
 	struct at_desc		*first = NULL;
 	struct at_desc		*prev = NULL;
 	unsigned long		was_cyclic;
+	unsigned int		reg_width;
 	unsigned int		periods = buf_len / period_len;
 	unsigned int		i;
 
@@ -889,8 +878,13 @@
 		return NULL;
 	}
 
+	if (sconfig->direction == DMA_MEM_TO_DEV)
+		reg_width = convert_buswidth(sconfig->dst_addr_width);
+	else
+		reg_width = convert_buswidth(sconfig->src_addr_width);
+
 	/* Check for too big/unaligned periods and unaligned DMA buffer */
-	if (atc_dma_cyclic_check_values(atslave->reg_width, buf_addr,
+	if (atc_dma_cyclic_check_values(reg_width, buf_addr,
 					period_len, direction))
 		goto err_out;
 
@@ -902,8 +896,8 @@
 		if (!desc)
 			goto err_desc_get;
 
-		if (atc_dma_cyclic_fill_desc(atslave, desc, i, buf_addr,
-						period_len, direction))
+		if (atc_dma_cyclic_fill_desc(chan, desc, i, buf_addr,
+					     reg_width, period_len, direction))
 			goto err_desc_get;
 
 		atc_desc_chain(&first, &prev, desc);
@@ -926,6 +920,23 @@
 	return NULL;
 }
 
+static int set_runtime_config(struct dma_chan *chan,
+			      struct dma_slave_config *sconfig)
+{
+	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
+
+	/* Check if it is chan is configured for slave transfers */
+	if (!chan->private)
+		return -EINVAL;
+
+	memcpy(&atchan->dma_sconfig, sconfig, sizeof(*sconfig));
+
+	convert_burst(&atchan->dma_sconfig.src_maxburst);
+	convert_burst(&atchan->dma_sconfig.dst_maxburst);
+
+	return 0;
+}
+
 
 static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 		       unsigned long arg)
@@ -986,6 +997,8 @@
 		clear_bit(ATC_IS_CYCLIC, &atchan->status);
 
 		spin_unlock_irqrestore(&atchan->lock, flags);
+	} else if (cmd == DMA_SLAVE_CONFIG) {
+		return set_runtime_config(chan, (struct dma_slave_config *)arg);
 	} else {
 		return -ENXIO;
 	}
@@ -1016,26 +1029,20 @@
 
 	spin_lock_irqsave(&atchan->lock, flags);
 
-	last_complete = atchan->completed_cookie;
-	last_used = chan->cookie;
-
-	ret = dma_async_is_complete(cookie, last_complete, last_used);
+	ret = dma_cookie_status(chan, cookie, txstate);
 	if (ret != DMA_SUCCESS) {
 		atc_cleanup_descriptors(atchan);
 
-		last_complete = atchan->completed_cookie;
-		last_used = chan->cookie;
-
-		ret = dma_async_is_complete(cookie, last_complete, last_used);
+		ret = dma_cookie_status(chan, cookie, txstate);
 	}
 
+	last_complete = chan->completed_cookie;
+	last_used = chan->cookie;
+
 	spin_unlock_irqrestore(&atchan->lock, flags);
 
 	if (ret != DMA_SUCCESS)
-		dma_set_tx_state(txstate, last_complete, last_used,
-			atc_first_active(atchan)->len);
-	else
-		dma_set_tx_state(txstate, last_complete, last_used, 0);
+		dma_set_residue(txstate, atc_first_active(atchan)->len);
 
 	if (atc_chan_is_paused(atchan))
 		ret = DMA_PAUSED;
@@ -1129,7 +1136,7 @@
 	spin_lock_irqsave(&atchan->lock, flags);
 	atchan->descs_allocated = i;
 	list_splice(&tmp_list, &atchan->free_list);
-	atchan->completed_cookie = chan->cookie = 1;
+	dma_cookie_init(chan);
 	spin_unlock_irqrestore(&atchan->lock, flags);
 
 	/* channel parameters */
@@ -1329,7 +1336,7 @@
 		struct at_dma_chan	*atchan = &atdma->chan[i];
 
 		atchan->chan_common.device = &atdma->dma_common;
-		atchan->chan_common.cookie = atchan->completed_cookie = 1;
+		dma_cookie_init(&atchan->chan_common);
 		list_add_tail(&atchan->chan_common.device_node,
 				&atdma->dma_common.channels);
 
diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
index a8d3277..897a8bc 100644
--- a/drivers/dma/at_hdmac_regs.h
+++ b/drivers/dma/at_hdmac_regs.h
@@ -207,8 +207,8 @@
  * @save_cfg: configuration register that is saved on suspend/resume cycle
  * @save_dscr: for cyclic operations, preserve next descriptor address in
  *             the cyclic list on suspend/resume cycle
+ * @dma_sconfig: configuration for slave transfers, passed via DMA_SLAVE_CONFIG
  * @lock: serializes enqueue/dequeue operations to descriptors lists
- * @completed_cookie: identifier for the most recently completed operation
  * @active_list: list of descriptors dmaengine is being running on
  * @queue: list of descriptors ready to be submitted to engine
  * @free_list: list of descriptors usable by the channel
@@ -223,11 +223,11 @@
 	struct tasklet_struct	tasklet;
 	u32			save_cfg;
 	u32			save_dscr;
+	struct dma_slave_config dma_sconfig;
 
 	spinlock_t		lock;
 
 	/* these other elements are all protected by lock */
-	dma_cookie_t		completed_cookie;
 	struct list_head	active_list;
 	struct list_head	queue;
 	struct list_head	free_list;
@@ -245,6 +245,36 @@
 	return container_of(dchan, struct at_dma_chan, chan_common);
 }
 
+/*
+ * Fix sconfig's burst size according to at_hdmac. We need to convert them as:
+ * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3, 32 -> 4, 64 -> 5, 128 -> 6, 256 -> 7.
+ *
+ * This can be done by finding most significant bit set.
+ */
+static inline void convert_burst(u32 *maxburst)
+{
+	if (*maxburst > 1)
+		*maxburst = fls(*maxburst) - 2;
+	else
+		*maxburst = 0;
+}
+
+/*
+ * Fix sconfig's bus width according to at_hdmac.
+ * 1 byte -> 0, 2 bytes -> 1, 4 bytes -> 2.
+ */
+static inline u8 convert_buswidth(enum dma_slave_buswidth addr_width)
+{
+	switch (addr_width) {
+	case DMA_SLAVE_BUSWIDTH_2_BYTES:
+		return 1;
+	case DMA_SLAVE_BUSWIDTH_4_BYTES:
+		return 2;
+	default:
+		/* For 1 byte width or fallback */
+		return 0;
+	}
+}
 
 /*--  Controller  ------------------------------------------------------*/
 
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index d65a718..750925f 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -24,6 +24,7 @@
 #include <mach/coh901318.h>
 
 #include "coh901318_lli.h"
+#include "dmaengine.h"
 
 #define COHC_2_DEV(cohc) (&cohc->chan.dev->device)
 
@@ -59,7 +60,6 @@
 struct coh901318_chan {
 	spinlock_t lock;
 	int allocated;
-	int completed;
 	int id;
 	int stopped;
 
@@ -104,13 +104,6 @@
 static struct coh901318_base *debugfs_dma_base;
 static struct dentry *dma_dentry;
 
-static int coh901318_debugfs_open(struct inode *inode, struct file *file)
-{
-
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static int coh901318_debugfs_read(struct file *file, char __user *buf,
 				  size_t count, loff_t *f_pos)
 {
@@ -158,7 +151,7 @@
 
 static const struct file_operations coh901318_debugfs_status_operations = {
 	.owner		= THIS_MODULE,
-	.open		= coh901318_debugfs_open,
+	.open		= simple_open,
 	.read		= coh901318_debugfs_read,
 	.llseek		= default_llseek,
 };
@@ -318,20 +311,6 @@
 
 	return 0;
 }
-static dma_cookie_t
-coh901318_assign_cookie(struct coh901318_chan *cohc,
-			struct coh901318_desc *cohd)
-{
-	dma_cookie_t cookie = cohc->chan.cookie;
-
-	if (++cookie < 0)
-		cookie = 1;
-
-	cohc->chan.cookie = cookie;
-	cohd->desc.cookie = cookie;
-
-	return cookie;
-}
 
 static struct coh901318_desc *
 coh901318_desc_get(struct coh901318_chan *cohc)
@@ -705,7 +684,7 @@
 	callback_param = cohd_fin->desc.callback_param;
 
 	/* sign this job as completed on the channel */
-	cohc->completed = cohd_fin->desc.cookie;
+	dma_cookie_complete(&cohd_fin->desc);
 
 	/* release the lli allocation and remove the descriptor */
 	coh901318_lli_free(&cohc->base->pool, &cohd_fin->lli);
@@ -929,7 +908,7 @@
 	coh901318_config(cohc, NULL);
 
 	cohc->allocated = 1;
-	cohc->completed = chan->cookie = 1;
+	dma_cookie_init(chan);
 
 	spin_unlock_irqrestore(&cohc->lock, flags);
 
@@ -966,16 +945,16 @@
 						   desc);
 	struct coh901318_chan *cohc = to_coh901318_chan(tx->chan);
 	unsigned long flags;
+	dma_cookie_t cookie;
 
 	spin_lock_irqsave(&cohc->lock, flags);
-
-	tx->cookie = coh901318_assign_cookie(cohc, cohd);
+	cookie = dma_cookie_assign(tx);
 
 	coh901318_desc_queue(cohc, cohd);
 
 	spin_unlock_irqrestore(&cohc->lock, flags);
 
-	return tx->cookie;
+	return cookie;
 }
 
 static struct dma_async_tx_descriptor *
@@ -1035,7 +1014,7 @@
 static struct dma_async_tx_descriptor *
 coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 			unsigned int sg_len, enum dma_transfer_direction direction,
-			unsigned long flags)
+			unsigned long flags, void *context)
 {
 	struct coh901318_chan *cohc = to_coh901318_chan(chan);
 	struct coh901318_lli *lli;
@@ -1165,17 +1144,12 @@
 		 struct dma_tx_state *txstate)
 {
 	struct coh901318_chan *cohc = to_coh901318_chan(chan);
-	dma_cookie_t last_used;
-	dma_cookie_t last_complete;
-	int ret;
+	enum dma_status ret;
 
-	last_complete = cohc->completed;
-	last_used = chan->cookie;
+	ret = dma_cookie_status(chan, cookie, txstate);
+	/* FIXME: should be conditional on ret != DMA_SUCCESS? */
+	dma_set_residue(txstate, coh901318_get_bytes_left(chan));
 
-	ret = dma_async_is_complete(cookie, last_complete, last_used);
-
-	dma_set_tx_state(txstate, last_complete, last_used,
-			 coh901318_get_bytes_left(chan));
 	if (ret == DMA_IN_PROGRESS && cohc->stopped)
 		ret = DMA_PAUSED;
 
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index a6c6051..767bcc3 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -510,8 +510,8 @@
 					 dma_chan_name(chan));
 				list_del_rcu(&device->global_node);
 			} else if (err)
-				pr_debug("dmaengine: failed to get %s: (%d)\n",
-					 dma_chan_name(chan), err);
+				pr_debug("%s: failed to get %s: (%d)\n",
+					__func__, dma_chan_name(chan), err);
 			else
 				break;
 			if (--device->privatecnt == 0)
@@ -564,8 +564,8 @@
 				list_del_rcu(&device->global_node);
 				break;
 			} else if (err)
-				pr_err("dmaengine: failed to get %s: (%d)\n",
-				       dma_chan_name(chan), err);
+				pr_err("%s: failed to get %s: (%d)\n",
+					__func__, dma_chan_name(chan), err);
 		}
 	}
 
diff --git a/drivers/dma/dmaengine.h b/drivers/dma/dmaengine.h
new file mode 100644
index 0000000..17f983a
--- /dev/null
+++ b/drivers/dma/dmaengine.h
@@ -0,0 +1,89 @@
+/*
+ * The contents of this file are private to DMA engine drivers, and is not
+ * part of the API to be used by DMA engine users.
+ */
+#ifndef DMAENGINE_H
+#define DMAENGINE_H
+
+#include <linux/bug.h>
+#include <linux/dmaengine.h>
+
+/**
+ * dma_cookie_init - initialize the cookies for a DMA channel
+ * @chan: dma channel to initialize
+ */
+static inline void dma_cookie_init(struct dma_chan *chan)
+{
+	chan->cookie = DMA_MIN_COOKIE;
+	chan->completed_cookie = DMA_MIN_COOKIE;
+}
+
+/**
+ * dma_cookie_assign - assign a DMA engine cookie to the descriptor
+ * @tx: descriptor needing cookie
+ *
+ * Assign a unique non-zero per-channel cookie to the descriptor.
+ * Note: caller is expected to hold a lock to prevent concurrency.
+ */
+static inline dma_cookie_t dma_cookie_assign(struct dma_async_tx_descriptor *tx)
+{
+	struct dma_chan *chan = tx->chan;
+	dma_cookie_t cookie;
+
+	cookie = chan->cookie + 1;
+	if (cookie < DMA_MIN_COOKIE)
+		cookie = DMA_MIN_COOKIE;
+	tx->cookie = chan->cookie = cookie;
+
+	return cookie;
+}
+
+/**
+ * dma_cookie_complete - complete a descriptor
+ * @tx: descriptor to complete
+ *
+ * Mark this descriptor complete by updating the channels completed
+ * cookie marker.  Zero the descriptors cookie to prevent accidental
+ * repeated completions.
+ *
+ * Note: caller is expected to hold a lock to prevent concurrency.
+ */
+static inline void dma_cookie_complete(struct dma_async_tx_descriptor *tx)
+{
+	BUG_ON(tx->cookie < DMA_MIN_COOKIE);
+	tx->chan->completed_cookie = tx->cookie;
+	tx->cookie = 0;
+}
+
+/**
+ * dma_cookie_status - report cookie status
+ * @chan: dma channel
+ * @cookie: cookie we are interested in
+ * @state: dma_tx_state structure to return last/used cookies
+ *
+ * Report the status of the cookie, filling in the state structure if
+ * non-NULL.  No locking is required.
+ */
+static inline enum dma_status dma_cookie_status(struct dma_chan *chan,
+	dma_cookie_t cookie, struct dma_tx_state *state)
+{
+	dma_cookie_t used, complete;
+
+	used = chan->cookie;
+	complete = chan->completed_cookie;
+	barrier();
+	if (state) {
+		state->last = complete;
+		state->used = used;
+		state->residue = 0;
+	}
+	return dma_async_is_complete(cookie, complete, used);
+}
+
+static inline void dma_set_residue(struct dma_tx_state *state, u32 residue)
+{
+	if (state)
+		state->residue = residue;
+}
+
+#endif
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 9b592b0..7439079 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -9,6 +9,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/bitops.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/dmaengine.h>
@@ -22,6 +23,7 @@
 #include <linux/slab.h>
 
 #include "dw_dmac_regs.h"
+#include "dmaengine.h"
 
 /*
  * This supports the Synopsys "DesignWare AHB Central DMA Controller",
@@ -33,19 +35,23 @@
  * which does not support descriptor writeback.
  */
 
-#define DWC_DEFAULT_CTLLO(private) ({				\
-		struct dw_dma_slave *__slave = (private);	\
-		int dms = __slave ? __slave->dst_master : 0;	\
-		int sms = __slave ? __slave->src_master : 1;	\
-		u8 smsize = __slave ? __slave->src_msize : DW_DMA_MSIZE_16; \
-		u8 dmsize = __slave ? __slave->dst_msize : DW_DMA_MSIZE_16; \
+#define DWC_DEFAULT_CTLLO(_chan) ({				\
+		struct dw_dma_slave *__slave = (_chan->private);	\
+		struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan);	\
+		struct dma_slave_config	*_sconfig = &_dwc->dma_sconfig;	\
+		int _dms = __slave ? __slave->dst_master : 0;	\
+		int _sms = __slave ? __slave->src_master : 1;	\
+		u8 _smsize = __slave ? _sconfig->src_maxburst :	\
+			DW_DMA_MSIZE_16;			\
+		u8 _dmsize = __slave ? _sconfig->dst_maxburst :	\
+			DW_DMA_MSIZE_16;			\
 								\
-		(DWC_CTLL_DST_MSIZE(dmsize)			\
-		 | DWC_CTLL_SRC_MSIZE(smsize)			\
+		(DWC_CTLL_DST_MSIZE(_dmsize)			\
+		 | DWC_CTLL_SRC_MSIZE(_smsize)			\
 		 | DWC_CTLL_LLP_D_EN				\
 		 | DWC_CTLL_LLP_S_EN				\
-		 | DWC_CTLL_DMS(dms)				\
-		 | DWC_CTLL_SMS(sms));				\
+		 | DWC_CTLL_DMS(_dms)				\
+		 | DWC_CTLL_SMS(_sms));				\
 	})
 
 /*
@@ -151,21 +157,6 @@
 	}
 }
 
-/* Called with dwc->lock held and bh disabled */
-static dma_cookie_t
-dwc_assign_cookie(struct dw_dma_chan *dwc, struct dw_desc *desc)
-{
-	dma_cookie_t cookie = dwc->chan.cookie;
-
-	if (++cookie < 0)
-		cookie = 1;
-
-	dwc->chan.cookie = cookie;
-	desc->txd.cookie = cookie;
-
-	return cookie;
-}
-
 static void dwc_initialize(struct dw_dma_chan *dwc)
 {
 	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
@@ -192,7 +183,6 @@
 
 	/* Enable interrupts */
 	channel_set_bit(dw, MASK.XFER, dwc->mask);
-	channel_set_bit(dw, MASK.BLOCK, dwc->mask);
 	channel_set_bit(dw, MASK.ERROR, dwc->mask);
 
 	dwc->initialized = true;
@@ -245,7 +235,7 @@
 	dev_vdbg(chan2dev(&dwc->chan), "descriptor %u complete\n", txd->cookie);
 
 	spin_lock_irqsave(&dwc->lock, flags);
-	dwc->completed = txd->cookie;
+	dma_cookie_complete(txd);
 	if (callback_required) {
 		callback = txd->callback;
 		param = txd->callback_param;
@@ -329,12 +319,6 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&dwc->lock, flags);
-	/*
-	 * Clear block interrupt flag before scanning so that we don't
-	 * miss any, and read LLP before RAW_XFER to ensure it is
-	 * valid if we decide to scan the list.
-	 */
-	dma_writel(dw, CLEAR.BLOCK, dwc->mask);
 	llp = channel_readl(dwc, LLP);
 	status_xfer = dma_readl(dw, RAW.XFER);
 
@@ -470,17 +454,16 @@
 
 /* called with dwc->lock held and all DMAC interrupts disabled */
 static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
-		u32 status_block, u32 status_err, u32 status_xfer)
+		u32 status_err, u32 status_xfer)
 {
 	unsigned long flags;
 
-	if (status_block & dwc->mask) {
+	if (dwc->mask) {
 		void (*callback)(void *param);
 		void *callback_param;
 
 		dev_vdbg(chan2dev(&dwc->chan), "new cyclic period llp 0x%08x\n",
 				channel_readl(dwc, LLP));
-		dma_writel(dw, CLEAR.BLOCK, dwc->mask);
 
 		callback = dwc->cdesc->period_callback;
 		callback_param = dwc->cdesc->period_callback_param;
@@ -520,7 +503,6 @@
 		channel_writel(dwc, CTL_LO, 0);
 		channel_writel(dwc, CTL_HI, 0);
 
-		dma_writel(dw, CLEAR.BLOCK, dwc->mask);
 		dma_writel(dw, CLEAR.ERROR, dwc->mask);
 		dma_writel(dw, CLEAR.XFER, dwc->mask);
 
@@ -537,36 +519,29 @@
 {
 	struct dw_dma *dw = (struct dw_dma *)data;
 	struct dw_dma_chan *dwc;
-	u32 status_block;
 	u32 status_xfer;
 	u32 status_err;
 	int i;
 
-	status_block = dma_readl(dw, RAW.BLOCK);
 	status_xfer = dma_readl(dw, RAW.XFER);
 	status_err = dma_readl(dw, RAW.ERROR);
 
-	dev_vdbg(dw->dma.dev, "tasklet: status_block=%x status_err=%x\n",
-			status_block, status_err);
+	dev_vdbg(dw->dma.dev, "tasklet: status_err=%x\n", status_err);
 
 	for (i = 0; i < dw->dma.chancnt; i++) {
 		dwc = &dw->chan[i];
 		if (test_bit(DW_DMA_IS_CYCLIC, &dwc->flags))
-			dwc_handle_cyclic(dw, dwc, status_block, status_err,
-					status_xfer);
+			dwc_handle_cyclic(dw, dwc, status_err, status_xfer);
 		else if (status_err & (1 << i))
 			dwc_handle_error(dw, dwc);
-		else if ((status_block | status_xfer) & (1 << i))
+		else if (status_xfer & (1 << i))
 			dwc_scan_descriptors(dw, dwc);
 	}
 
 	/*
-	 * Re-enable interrupts. Block Complete interrupts are only
-	 * enabled if the INT_EN bit in the descriptor is set. This
-	 * will trigger a scan before the whole list is done.
+	 * Re-enable interrupts.
 	 */
 	channel_set_bit(dw, MASK.XFER, dw->all_chan_mask);
-	channel_set_bit(dw, MASK.BLOCK, dw->all_chan_mask);
 	channel_set_bit(dw, MASK.ERROR, dw->all_chan_mask);
 }
 
@@ -583,7 +558,6 @@
 	 * softirq handler.
 	 */
 	channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
-	channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
 	channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
 
 	status = dma_readl(dw, STATUS_INT);
@@ -594,7 +568,6 @@
 
 		/* Try to recover */
 		channel_clear_bit(dw, MASK.XFER, (1 << 8) - 1);
-		channel_clear_bit(dw, MASK.BLOCK, (1 << 8) - 1);
 		channel_clear_bit(dw, MASK.SRC_TRAN, (1 << 8) - 1);
 		channel_clear_bit(dw, MASK.DST_TRAN, (1 << 8) - 1);
 		channel_clear_bit(dw, MASK.ERROR, (1 << 8) - 1);
@@ -615,7 +588,7 @@
 	unsigned long		flags;
 
 	spin_lock_irqsave(&dwc->lock, flags);
-	cookie = dwc_assign_cookie(dwc, desc);
+	cookie = dma_cookie_assign(tx);
 
 	/*
 	 * REVISIT: We should attempt to chain as many descriptors as
@@ -674,7 +647,7 @@
 	else
 		src_width = dst_width = 0;
 
-	ctllo = DWC_DEFAULT_CTLLO(chan->private)
+	ctllo = DWC_DEFAULT_CTLLO(chan)
 			| DWC_CTLL_DST_WIDTH(dst_width)
 			| DWC_CTLL_SRC_WIDTH(src_width)
 			| DWC_CTLL_DST_INC
@@ -731,10 +704,11 @@
 static struct dma_async_tx_descriptor *
 dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 		unsigned int sg_len, enum dma_transfer_direction direction,
-		unsigned long flags)
+		unsigned long flags, void *context)
 {
 	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
 	struct dw_dma_slave	*dws = chan->private;
+	struct dma_slave_config	*sconfig = &dwc->dma_sconfig;
 	struct dw_desc		*prev;
 	struct dw_desc		*first;
 	u32			ctllo;
@@ -750,25 +724,34 @@
 	if (unlikely(!dws || !sg_len))
 		return NULL;
 
-	reg_width = dws->reg_width;
 	prev = first = NULL;
 
 	switch (direction) {
 	case DMA_MEM_TO_DEV:
-		ctllo = (DWC_DEFAULT_CTLLO(chan->private)
+		reg_width = __fls(sconfig->dst_addr_width);
+		reg = sconfig->dst_addr;
+		ctllo = (DWC_DEFAULT_CTLLO(chan)
 				| DWC_CTLL_DST_WIDTH(reg_width)
 				| DWC_CTLL_DST_FIX
-				| DWC_CTLL_SRC_INC
-				| DWC_CTLL_FC(dws->fc));
-		reg = dws->tx_reg;
+				| DWC_CTLL_SRC_INC);
+
+		ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
+			DWC_CTLL_FC(DW_DMA_FC_D_M2P);
+
 		for_each_sg(sgl, sg, sg_len, i) {
 			struct dw_desc	*desc;
 			u32		len, dlen, mem;
 
 			mem = sg_phys(sg);
 			len = sg_dma_len(sg);
-			mem_width = 2;
-			if (unlikely(mem & 3 || len & 3))
+
+			if (!((mem | len) & 7))
+				mem_width = 3;
+			else if (!((mem | len) & 3))
+				mem_width = 2;
+			else if (!((mem | len) & 1))
+				mem_width = 1;
+			else
 				mem_width = 0;
 
 slave_sg_todev_fill_desc:
@@ -812,21 +795,30 @@
 		}
 		break;
 	case DMA_DEV_TO_MEM:
-		ctllo = (DWC_DEFAULT_CTLLO(chan->private)
+		reg_width = __fls(sconfig->src_addr_width);
+		reg = sconfig->src_addr;
+		ctllo = (DWC_DEFAULT_CTLLO(chan)
 				| DWC_CTLL_SRC_WIDTH(reg_width)
 				| DWC_CTLL_DST_INC
-				| DWC_CTLL_SRC_FIX
-				| DWC_CTLL_FC(dws->fc));
+				| DWC_CTLL_SRC_FIX);
 
-		reg = dws->rx_reg;
+		ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
+			DWC_CTLL_FC(DW_DMA_FC_D_P2M);
+
 		for_each_sg(sgl, sg, sg_len, i) {
 			struct dw_desc	*desc;
 			u32		len, dlen, mem;
 
 			mem = sg_phys(sg);
 			len = sg_dma_len(sg);
-			mem_width = 2;
-			if (unlikely(mem & 3 || len & 3))
+
+			if (!((mem | len) & 7))
+				mem_width = 3;
+			else if (!((mem | len) & 3))
+				mem_width = 2;
+			else if (!((mem | len) & 1))
+				mem_width = 1;
+			else
 				mem_width = 0;
 
 slave_sg_fromdev_fill_desc:
@@ -890,6 +882,39 @@
 	return NULL;
 }
 
+/*
+ * Fix sconfig's burst size according to dw_dmac. We need to convert them as:
+ * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
+ *
+ * NOTE: burst size 2 is not supported by controller.
+ *
+ * This can be done by finding least significant bit set: n & (n - 1)
+ */
+static inline void convert_burst(u32 *maxburst)
+{
+	if (*maxburst > 1)
+		*maxburst = fls(*maxburst) - 2;
+	else
+		*maxburst = 0;
+}
+
+static int
+set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
+{
+	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+
+	/* Check if it is chan is configured for slave transfers */
+	if (!chan->private)
+		return -EINVAL;
+
+	memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
+
+	convert_burst(&dwc->dma_sconfig.src_maxburst);
+	convert_burst(&dwc->dma_sconfig.dst_maxburst);
+
+	return 0;
+}
+
 static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 		       unsigned long arg)
 {
@@ -939,8 +964,11 @@
 		/* Flush all pending and queued descriptors */
 		list_for_each_entry_safe(desc, _desc, &list, desc_node)
 			dwc_descriptor_complete(dwc, desc, false);
-	} else
+	} else if (cmd == DMA_SLAVE_CONFIG) {
+		return set_runtime_config(chan, (struct dma_slave_config *)arg);
+	} else {
 		return -ENXIO;
+	}
 
 	return 0;
 }
@@ -951,28 +979,17 @@
 	      struct dma_tx_state *txstate)
 {
 	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
-	dma_cookie_t		last_used;
-	dma_cookie_t		last_complete;
-	int			ret;
+	enum dma_status		ret;
 
-	last_complete = dwc->completed;
-	last_used = chan->cookie;
-
-	ret = dma_async_is_complete(cookie, last_complete, last_used);
+	ret = dma_cookie_status(chan, cookie, txstate);
 	if (ret != DMA_SUCCESS) {
 		dwc_scan_descriptors(to_dw_dma(chan->device), dwc);
 
-		last_complete = dwc->completed;
-		last_used = chan->cookie;
-
-		ret = dma_async_is_complete(cookie, last_complete, last_used);
+		ret = dma_cookie_status(chan, cookie, txstate);
 	}
 
 	if (ret != DMA_SUCCESS)
-		dma_set_tx_state(txstate, last_complete, last_used,
-				dwc_first_active(dwc)->len);
-	else
-		dma_set_tx_state(txstate, last_complete, last_used, 0);
+		dma_set_residue(txstate, dwc_first_active(dwc)->len);
 
 	if (dwc->paused)
 		return DMA_PAUSED;
@@ -1004,7 +1021,7 @@
 		return -EIO;
 	}
 
-	dwc->completed = chan->cookie = 1;
+	dma_cookie_init(chan);
 
 	/*
 	 * NOTE: some controllers may have additional features that we
@@ -1068,7 +1085,6 @@
 
 	/* Disable interrupts */
 	channel_clear_bit(dw, MASK.XFER, dwc->mask);
-	channel_clear_bit(dw, MASK.BLOCK, dwc->mask);
 	channel_clear_bit(dw, MASK.ERROR, dwc->mask);
 
 	spin_unlock_irqrestore(&dwc->lock, flags);
@@ -1120,7 +1136,6 @@
 		return -EBUSY;
 	}
 
-	dma_writel(dw, CLEAR.BLOCK, dwc->mask);
 	dma_writel(dw, CLEAR.ERROR, dwc->mask);
 	dma_writel(dw, CLEAR.XFER, dwc->mask);
 
@@ -1175,11 +1190,11 @@
 		enum dma_transfer_direction direction)
 {
 	struct dw_dma_chan		*dwc = to_dw_dma_chan(chan);
+	struct dma_slave_config		*sconfig = &dwc->dma_sconfig;
 	struct dw_cyclic_desc		*cdesc;
 	struct dw_cyclic_desc		*retval = NULL;
 	struct dw_desc			*desc;
 	struct dw_desc			*last = NULL;
-	struct dw_dma_slave		*dws = chan->private;
 	unsigned long			was_cyclic;
 	unsigned int			reg_width;
 	unsigned int			periods;
@@ -1203,7 +1218,12 @@
 	}
 
 	retval = ERR_PTR(-EINVAL);
-	reg_width = dws->reg_width;
+
+	if (direction == DMA_MEM_TO_DEV)
+		reg_width = __ffs(sconfig->dst_addr_width);
+	else
+		reg_width = __ffs(sconfig->src_addr_width);
+
 	periods = buf_len / period_len;
 
 	/* Check for too big/unaligned periods and unaligned DMA buffer. */
@@ -1236,26 +1256,34 @@
 
 		switch (direction) {
 		case DMA_MEM_TO_DEV:
-			desc->lli.dar = dws->tx_reg;
+			desc->lli.dar = sconfig->dst_addr;
 			desc->lli.sar = buf_addr + (period_len * i);
-			desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan->private)
+			desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan)
 					| DWC_CTLL_DST_WIDTH(reg_width)
 					| DWC_CTLL_SRC_WIDTH(reg_width)
 					| DWC_CTLL_DST_FIX
 					| DWC_CTLL_SRC_INC
-					| DWC_CTLL_FC(dws->fc)
 					| DWC_CTLL_INT_EN);
+
+			desc->lli.ctllo |= sconfig->device_fc ?
+				DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
+				DWC_CTLL_FC(DW_DMA_FC_D_M2P);
+
 			break;
 		case DMA_DEV_TO_MEM:
 			desc->lli.dar = buf_addr + (period_len * i);
-			desc->lli.sar = dws->rx_reg;
-			desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan->private)
+			desc->lli.sar = sconfig->src_addr;
+			desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan)
 					| DWC_CTLL_SRC_WIDTH(reg_width)
 					| DWC_CTLL_DST_WIDTH(reg_width)
 					| DWC_CTLL_DST_INC
 					| DWC_CTLL_SRC_FIX
-					| DWC_CTLL_FC(dws->fc)
 					| DWC_CTLL_INT_EN);
+
+			desc->lli.ctllo |= sconfig->device_fc ?
+				DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
+				DWC_CTLL_FC(DW_DMA_FC_D_P2M);
+
 			break;
 		default:
 			break;
@@ -1322,7 +1350,6 @@
 	while (dma_readl(dw, CH_EN) & dwc->mask)
 		cpu_relax();
 
-	dma_writel(dw, CLEAR.BLOCK, dwc->mask);
 	dma_writel(dw, CLEAR.ERROR, dwc->mask);
 	dma_writel(dw, CLEAR.XFER, dwc->mask);
 
@@ -1347,7 +1374,6 @@
 	dma_writel(dw, CFG, 0);
 
 	channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
-	channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
 	channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask);
 	channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask);
 	channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
@@ -1369,7 +1395,7 @@
 	int			err;
 	int			i;
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 	if (!pdata || pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS)
 		return -EINVAL;
 
@@ -1423,7 +1449,7 @@
 		struct dw_dma_chan	*dwc = &dw->chan[i];
 
 		dwc->chan.device = &dw->dma;
-		dwc->chan.cookie = dwc->completed = 1;
+		dma_cookie_init(&dwc->chan);
 		if (pdata->chan_allocation_order == CHAN_ALLOCATION_ASCENDING)
 			list_add_tail(&dwc->chan.device_node,
 					&dw->dma.channels);
@@ -1432,7 +1458,7 @@
 
 		/* 7 is highest priority & 0 is lowest. */
 		if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING)
-			dwc->priority = 7 - i;
+			dwc->priority = pdata->nr_channels - i - 1;
 		else
 			dwc->priority = i;
 
@@ -1449,13 +1475,11 @@
 
 	/* Clear/disable all interrupts on all channels. */
 	dma_writel(dw, CLEAR.XFER, dw->all_chan_mask);
-	dma_writel(dw, CLEAR.BLOCK, dw->all_chan_mask);
 	dma_writel(dw, CLEAR.SRC_TRAN, dw->all_chan_mask);
 	dma_writel(dw, CLEAR.DST_TRAN, dw->all_chan_mask);
 	dma_writel(dw, CLEAR.ERROR, dw->all_chan_mask);
 
 	channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
-	channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
 	channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask);
 	channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask);
 	channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
@@ -1562,6 +1586,10 @@
 static const struct dev_pm_ops dw_dev_pm_ops = {
 	.suspend_noirq = dw_suspend_noirq,
 	.resume_noirq = dw_resume_noirq,
+	.freeze_noirq = dw_suspend_noirq,
+	.thaw_noirq = dw_resume_noirq,
+	.restore_noirq = dw_resume_noirq,
+	.poweroff_noirq = dw_suspend_noirq,
 };
 
 static struct platform_driver dw_driver = {
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 5eef694..f298f69 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -13,6 +13,18 @@
 
 #define DW_DMA_MAX_NR_CHANNELS	8
 
+/* flow controller */
+enum dw_dma_fc {
+	DW_DMA_FC_D_M2M,
+	DW_DMA_FC_D_M2P,
+	DW_DMA_FC_D_P2M,
+	DW_DMA_FC_D_P2P,
+	DW_DMA_FC_P_P2M,
+	DW_DMA_FC_SP_P2P,
+	DW_DMA_FC_P_M2P,
+	DW_DMA_FC_DP_P2P,
+};
+
 /*
  * Redefine this macro to handle differences between 32- and 64-bit
  * addressing, big vs. little endian, etc.
@@ -146,13 +158,15 @@
 
 	/* these other elements are all protected by lock */
 	unsigned long		flags;
-	dma_cookie_t		completed;
 	struct list_head	active_list;
 	struct list_head	queue;
 	struct list_head	free_list;
 	struct dw_cyclic_desc	*cdesc;
 
 	unsigned int		descs_allocated;
+
+	/* configuration passed via DMA_SLAVE_CONFIG */
+	struct dma_slave_config dma_sconfig;
 };
 
 static inline struct dw_dma_chan_regs __iomem *
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index 59e7a96..e6f133b 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -28,6 +28,8 @@
 
 #include <mach/dma.h>
 
+#include "dmaengine.h"
+
 /* M2P registers */
 #define M2P_CONTROL			0x0000
 #define M2P_CONTROL_STALLINT		BIT(0)
@@ -122,7 +124,6 @@
  * @lock: lock protecting the fields following
  * @flags: flags for the channel
  * @buffer: which buffer to use next (0/1)
- * @last_completed: last completed cookie value
  * @active: flattened chain of descriptors currently being processed
  * @queue: pending descriptors which are handled next
  * @free_list: list of free descriptors which can be used
@@ -157,7 +158,6 @@
 #define EP93XX_DMA_IS_CYCLIC		0
 
 	int				buffer;
-	dma_cookie_t			last_completed;
 	struct list_head		active;
 	struct list_head		queue;
 	struct list_head		free_list;
@@ -703,7 +703,7 @@
 	desc = ep93xx_dma_get_active(edmac);
 	if (desc) {
 		if (desc->complete) {
-			edmac->last_completed = desc->txd.cookie;
+			dma_cookie_complete(&desc->txd);
 			list_splice_init(&edmac->active, &list);
 		}
 		callback = desc->txd.callback;
@@ -783,17 +783,10 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&edmac->lock, flags);
-
-	cookie = edmac->chan.cookie;
-
-	if (++cookie < 0)
-		cookie = 1;
+	cookie = dma_cookie_assign(tx);
 
 	desc = container_of(tx, struct ep93xx_dma_desc, txd);
 
-	edmac->chan.cookie = cookie;
-	desc->txd.cookie = cookie;
-
 	/*
 	 * If nothing is currently prosessed, we push this descriptor
 	 * directly to the hardware. Otherwise we put the descriptor
@@ -861,8 +854,7 @@
 		goto fail_clk_disable;
 
 	spin_lock_irq(&edmac->lock);
-	edmac->last_completed = 1;
-	edmac->chan.cookie = 1;
+	dma_cookie_init(&edmac->chan);
 	ret = edmac->edma->hw_setup(edmac);
 	spin_unlock_irq(&edmac->lock);
 
@@ -983,13 +975,14 @@
  * @sg_len: number of entries in @sgl
  * @dir: direction of tha DMA transfer
  * @flags: flags for the descriptor
+ * @context: operation context (ignored)
  *
  * Returns a valid DMA descriptor or %NULL in case of failure.
  */
 static struct dma_async_tx_descriptor *
 ep93xx_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 			 unsigned int sg_len, enum dma_transfer_direction dir,
-			 unsigned long flags)
+			 unsigned long flags, void *context)
 {
 	struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
 	struct ep93xx_dma_desc *desc, *first;
@@ -1056,6 +1049,7 @@
  * @buf_len: length of the buffer (in bytes)
  * @period_len: lenght of a single period
  * @dir: direction of the operation
+ * @context: operation context (ignored)
  *
  * Prepares a descriptor for cyclic DMA operation. This means that once the
  * descriptor is submitted, we will be submitting in a @period_len sized
@@ -1068,7 +1062,7 @@
 static struct dma_async_tx_descriptor *
 ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
 			   size_t buf_len, size_t period_len,
-			   enum dma_transfer_direction dir)
+			   enum dma_transfer_direction dir, void *context)
 {
 	struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
 	struct ep93xx_dma_desc *desc, *first;
@@ -1248,18 +1242,13 @@
 					    struct dma_tx_state *state)
 {
 	struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
-	dma_cookie_t last_used, last_completed;
 	enum dma_status ret;
 	unsigned long flags;
 
 	spin_lock_irqsave(&edmac->lock, flags);
-	last_used = chan->cookie;
-	last_completed = edmac->last_completed;
+	ret = dma_cookie_status(chan, cookie, state);
 	spin_unlock_irqrestore(&edmac->lock, flags);
 
-	ret = dma_async_is_complete(cookie, last_completed, last_used);
-	dma_set_tx_state(state, last_completed, last_used, 0);
-
 	return ret;
 }
 
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index b98070c..8f84761 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -35,6 +35,7 @@
 #include <linux/dmapool.h>
 #include <linux/of_platform.h>
 
+#include "dmaengine.h"
 #include "fsldma.h"
 
 #define chan_dbg(chan, fmt, arg...)					\
@@ -413,17 +414,10 @@
 	 * assign cookies to all of the software descriptors
 	 * that make up this transaction
 	 */
-	cookie = chan->common.cookie;
 	list_for_each_entry(child, &desc->tx_list, node) {
-		cookie++;
-		if (cookie < DMA_MIN_COOKIE)
-			cookie = DMA_MIN_COOKIE;
-
-		child->async_tx.cookie = cookie;
+		cookie = dma_cookie_assign(&child->async_tx);
 	}
 
-	chan->common.cookie = cookie;
-
 	/* put this transaction onto the tail of the pending queue */
 	append_ld_queue(chan, desc);
 
@@ -765,6 +759,7 @@
  * @sg_len: number of entries in @scatterlist
  * @direction: DMA direction
  * @flags: DMAEngine flags
+ * @context: transaction context (ignored)
  *
  * Prepare a set of descriptors for a DMA_SLAVE transaction. Following the
  * DMA_SLAVE API, this gets the device-specific information from the
@@ -772,7 +767,8 @@
  */
 static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
 	struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
-	enum dma_transfer_direction direction, unsigned long flags)
+	enum dma_transfer_direction direction, unsigned long flags,
+	void *context)
 {
 	/*
 	 * This operation is not supported on the Freescale DMA controller
@@ -984,19 +980,14 @@
 					struct dma_tx_state *txstate)
 {
 	struct fsldma_chan *chan = to_fsl_chan(dchan);
-	dma_cookie_t last_complete;
-	dma_cookie_t last_used;
+	enum dma_status ret;
 	unsigned long flags;
 
 	spin_lock_irqsave(&chan->desc_lock, flags);
-
-	last_complete = chan->completed_cookie;
-	last_used = dchan->cookie;
-
+	ret = dma_cookie_status(dchan, cookie, txstate);
 	spin_unlock_irqrestore(&chan->desc_lock, flags);
 
-	dma_set_tx_state(txstate, last_complete, last_used, 0);
-	return dma_async_is_complete(cookie, last_complete, last_used);
+	return ret;
 }
 
 /*----------------------------------------------------------------------------*/
@@ -1087,8 +1078,8 @@
 
 		desc = to_fsl_desc(chan->ld_running.prev);
 		cookie = desc->async_tx.cookie;
+		dma_cookie_complete(&desc->async_tx);
 
-		chan->completed_cookie = cookie;
 		chan_dbg(chan, "completed_cookie=%d\n", cookie);
 	}
 
@@ -1303,6 +1294,7 @@
 	chan->idle = true;
 
 	chan->common.device = &fdev->common;
+	dma_cookie_init(&chan->common);
 
 	/* find the IRQ line, if it exists in the device tree */
 	chan->irq = irq_of_parse_and_map(node, 0);
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index 9cb5aa5..f5c3879 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -137,7 +137,6 @@
 struct fsldma_chan {
 	char name[8];			/* Channel name */
 	struct fsldma_chan_regs __iomem *regs;
-	dma_cookie_t completed_cookie;	/* The maximum cookie completed */
 	spinlock_t desc_lock;		/* Descriptor operation lock */
 	struct list_head ld_pending;	/* Link descriptors queue */
 	struct list_head ld_running;	/* Link descriptors queue */
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index e4383ee..a45b5d2 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -5,6 +5,7 @@
  * found on i.MX1/21/27
  *
  * Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright 2012 Javier Martin, Vista Silicon <javier.martin@vista-silicon.com>
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
@@ -14,7 +15,6 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
@@ -23,37 +23,159 @@
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 #include <linux/dmaengine.h>
 #include <linux/module.h>
 
 #include <asm/irq.h>
-#include <mach/dma-v1.h>
+#include <mach/dma.h>
 #include <mach/hardware.h>
 
+#include "dmaengine.h"
+#define IMXDMA_MAX_CHAN_DESCRIPTORS	16
+#define IMX_DMA_CHANNELS  16
+
+#define IMX_DMA_2D_SLOTS	2
+#define IMX_DMA_2D_SLOT_A	0
+#define IMX_DMA_2D_SLOT_B	1
+
+#define IMX_DMA_LENGTH_LOOP	((unsigned int)-1)
+#define IMX_DMA_MEMSIZE_32	(0 << 4)
+#define IMX_DMA_MEMSIZE_8	(1 << 4)
+#define IMX_DMA_MEMSIZE_16	(2 << 4)
+#define IMX_DMA_TYPE_LINEAR	(0 << 10)
+#define IMX_DMA_TYPE_2D		(1 << 10)
+#define IMX_DMA_TYPE_FIFO	(2 << 10)
+
+#define IMX_DMA_ERR_BURST     (1 << 0)
+#define IMX_DMA_ERR_REQUEST   (1 << 1)
+#define IMX_DMA_ERR_TRANSFER  (1 << 2)
+#define IMX_DMA_ERR_BUFFER    (1 << 3)
+#define IMX_DMA_ERR_TIMEOUT   (1 << 4)
+
+#define DMA_DCR     0x00		/* Control Register */
+#define DMA_DISR    0x04		/* Interrupt status Register */
+#define DMA_DIMR    0x08		/* Interrupt mask Register */
+#define DMA_DBTOSR  0x0c		/* Burst timeout status Register */
+#define DMA_DRTOSR  0x10		/* Request timeout Register */
+#define DMA_DSESR   0x14		/* Transfer Error Status Register */
+#define DMA_DBOSR   0x18		/* Buffer overflow status Register */
+#define DMA_DBTOCR  0x1c		/* Burst timeout control Register */
+#define DMA_WSRA    0x40		/* W-Size Register A */
+#define DMA_XSRA    0x44		/* X-Size Register A */
+#define DMA_YSRA    0x48		/* Y-Size Register A */
+#define DMA_WSRB    0x4c		/* W-Size Register B */
+#define DMA_XSRB    0x50		/* X-Size Register B */
+#define DMA_YSRB    0x54		/* Y-Size Register B */
+#define DMA_SAR(x)  (0x80 + ((x) << 6))	/* Source Address Registers */
+#define DMA_DAR(x)  (0x84 + ((x) << 6))	/* Destination Address Registers */
+#define DMA_CNTR(x) (0x88 + ((x) << 6))	/* Count Registers */
+#define DMA_CCR(x)  (0x8c + ((x) << 6))	/* Control Registers */
+#define DMA_RSSR(x) (0x90 + ((x) << 6))	/* Request source select Registers */
+#define DMA_BLR(x)  (0x94 + ((x) << 6))	/* Burst length Registers */
+#define DMA_RTOR(x) (0x98 + ((x) << 6))	/* Request timeout Registers */
+#define DMA_BUCR(x) (0x98 + ((x) << 6))	/* Bus Utilization Registers */
+#define DMA_CCNR(x) (0x9C + ((x) << 6))	/* Channel counter Registers */
+
+#define DCR_DRST           (1<<1)
+#define DCR_DEN            (1<<0)
+#define DBTOCR_EN          (1<<15)
+#define DBTOCR_CNT(x)      ((x) & 0x7fff)
+#define CNTR_CNT(x)        ((x) & 0xffffff)
+#define CCR_ACRPT          (1<<14)
+#define CCR_DMOD_LINEAR    (0x0 << 12)
+#define CCR_DMOD_2D        (0x1 << 12)
+#define CCR_DMOD_FIFO      (0x2 << 12)
+#define CCR_DMOD_EOBFIFO   (0x3 << 12)
+#define CCR_SMOD_LINEAR    (0x0 << 10)
+#define CCR_SMOD_2D        (0x1 << 10)
+#define CCR_SMOD_FIFO      (0x2 << 10)
+#define CCR_SMOD_EOBFIFO   (0x3 << 10)
+#define CCR_MDIR_DEC       (1<<9)
+#define CCR_MSEL_B         (1<<8)
+#define CCR_DSIZ_32        (0x0 << 6)
+#define CCR_DSIZ_8         (0x1 << 6)
+#define CCR_DSIZ_16        (0x2 << 6)
+#define CCR_SSIZ_32        (0x0 << 4)
+#define CCR_SSIZ_8         (0x1 << 4)
+#define CCR_SSIZ_16        (0x2 << 4)
+#define CCR_REN            (1<<3)
+#define CCR_RPT            (1<<2)
+#define CCR_FRC            (1<<1)
+#define CCR_CEN            (1<<0)
+#define RTOR_EN            (1<<15)
+#define RTOR_CLK           (1<<14)
+#define RTOR_PSC           (1<<13)
+
+enum  imxdma_prep_type {
+	IMXDMA_DESC_MEMCPY,
+	IMXDMA_DESC_INTERLEAVED,
+	IMXDMA_DESC_SLAVE_SG,
+	IMXDMA_DESC_CYCLIC,
+};
+
+struct imx_dma_2d_config {
+	u16		xsr;
+	u16		ysr;
+	u16		wsr;
+	int		count;
+};
+
+struct imxdma_desc {
+	struct list_head		node;
+	struct dma_async_tx_descriptor	desc;
+	enum dma_status			status;
+	dma_addr_t			src;
+	dma_addr_t			dest;
+	size_t				len;
+	enum dma_transfer_direction	direction;
+	enum imxdma_prep_type		type;
+	/* For memcpy and interleaved */
+	unsigned int			config_port;
+	unsigned int			config_mem;
+	/* For interleaved transfers */
+	unsigned int			x;
+	unsigned int			y;
+	unsigned int			w;
+	/* For slave sg and cyclic */
+	struct scatterlist		*sg;
+	unsigned int			sgcount;
+};
+
 struct imxdma_channel {
+	int				hw_chaining;
+	struct timer_list		watchdog;
 	struct imxdma_engine		*imxdma;
 	unsigned int			channel;
-	unsigned int			imxdma_channel;
 
+	struct tasklet_struct		dma_tasklet;
+	struct list_head		ld_free;
+	struct list_head		ld_queue;
+	struct list_head		ld_active;
+	int				descs_allocated;
 	enum dma_slave_buswidth		word_size;
 	dma_addr_t			per_address;
 	u32				watermark_level;
 	struct dma_chan			chan;
-	spinlock_t			lock;
 	struct dma_async_tx_descriptor	desc;
-	dma_cookie_t			last_completed;
 	enum dma_status			status;
 	int				dma_request;
 	struct scatterlist		*sg_list;
+	u32				ccr_from_device;
+	u32				ccr_to_device;
+	bool				enabled_2d;
+	int				slot_2d;
 };
 
-#define MAX_DMA_CHANNELS 8
-
 struct imxdma_engine {
 	struct device			*dev;
 	struct device_dma_parameters	dma_parms;
 	struct dma_device		dma_device;
-	struct imxdma_channel		channel[MAX_DMA_CHANNELS];
+	void __iomem			*base;
+	struct clk			*dma_clk;
+	spinlock_t			lock;
+	struct imx_dma_2d_config	slots_2d[IMX_DMA_2D_SLOTS];
+	struct imxdma_channel		channel[IMX_DMA_CHANNELS];
 };
 
 static struct imxdma_channel *to_imxdma_chan(struct dma_chan *chan)
@@ -61,36 +183,418 @@
 	return container_of(chan, struct imxdma_channel, chan);
 }
 
-static void imxdma_handle(struct imxdma_channel *imxdmac)
+static inline bool imxdma_chan_is_doing_cyclic(struct imxdma_channel *imxdmac)
 {
-	if (imxdmac->desc.callback)
-		imxdmac->desc.callback(imxdmac->desc.callback_param);
-	imxdmac->last_completed = imxdmac->desc.cookie;
+	struct imxdma_desc *desc;
+
+	if (!list_empty(&imxdmac->ld_active)) {
+		desc = list_first_entry(&imxdmac->ld_active, struct imxdma_desc,
+					node);
+		if (desc->type == IMXDMA_DESC_CYCLIC)
+			return true;
+	}
+	return false;
 }
 
-static void imxdma_irq_handler(int channel, void *data)
-{
-	struct imxdma_channel *imxdmac = data;
 
-	imxdmac->status = DMA_SUCCESS;
-	imxdma_handle(imxdmac);
+
+static void imx_dmav1_writel(struct imxdma_engine *imxdma, unsigned val,
+			     unsigned offset)
+{
+	__raw_writel(val, imxdma->base + offset);
 }
 
-static void imxdma_err_handler(int channel, void *data, int error)
+static unsigned imx_dmav1_readl(struct imxdma_engine *imxdma, unsigned offset)
 {
-	struct imxdma_channel *imxdmac = data;
-
-	imxdmac->status = DMA_ERROR;
-	imxdma_handle(imxdmac);
+	return __raw_readl(imxdma->base + offset);
 }
 
-static void imxdma_progression(int channel, void *data,
-		struct scatterlist *sg)
+static int imxdma_hw_chain(struct imxdma_channel *imxdmac)
 {
-	struct imxdma_channel *imxdmac = data;
+	if (cpu_is_mx27())
+		return imxdmac->hw_chaining;
+	else
+		return 0;
+}
 
-	imxdmac->status = DMA_SUCCESS;
-	imxdma_handle(imxdmac);
+/*
+ * imxdma_sg_next - prepare next chunk for scatter-gather DMA emulation
+ */
+static inline int imxdma_sg_next(struct imxdma_desc *d)
+{
+	struct imxdma_channel *imxdmac = to_imxdma_chan(d->desc.chan);
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	struct scatterlist *sg = d->sg;
+	unsigned long now;
+
+	now = min(d->len, sg->length);
+	if (d->len != IMX_DMA_LENGTH_LOOP)
+		d->len -= now;
+
+	if (d->direction == DMA_DEV_TO_MEM)
+		imx_dmav1_writel(imxdma, sg->dma_address,
+				 DMA_DAR(imxdmac->channel));
+	else
+		imx_dmav1_writel(imxdma, sg->dma_address,
+				 DMA_SAR(imxdmac->channel));
+
+	imx_dmav1_writel(imxdma, now, DMA_CNTR(imxdmac->channel));
+
+	dev_dbg(imxdma->dev, " %s channel: %d dst 0x%08x, src 0x%08x, "
+		"size 0x%08x\n", __func__, imxdmac->channel,
+		 imx_dmav1_readl(imxdma, DMA_DAR(imxdmac->channel)),
+		 imx_dmav1_readl(imxdma, DMA_SAR(imxdmac->channel)),
+		 imx_dmav1_readl(imxdma, DMA_CNTR(imxdmac->channel)));
+
+	return now;
+}
+
+static void imxdma_enable_hw(struct imxdma_desc *d)
+{
+	struct imxdma_channel *imxdmac = to_imxdma_chan(d->desc.chan);
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	int channel = imxdmac->channel;
+	unsigned long flags;
+
+	dev_dbg(imxdma->dev, "%s channel %d\n", __func__, channel);
+
+	local_irq_save(flags);
+
+	imx_dmav1_writel(imxdma, 1 << channel, DMA_DISR);
+	imx_dmav1_writel(imxdma, imx_dmav1_readl(imxdma, DMA_DIMR) &
+			 ~(1 << channel), DMA_DIMR);
+	imx_dmav1_writel(imxdma, imx_dmav1_readl(imxdma, DMA_CCR(channel)) |
+			 CCR_CEN | CCR_ACRPT, DMA_CCR(channel));
+
+	if ((cpu_is_mx21() || cpu_is_mx27()) &&
+			d->sg && imxdma_hw_chain(imxdmac)) {
+		d->sg = sg_next(d->sg);
+		if (d->sg) {
+			u32 tmp;
+			imxdma_sg_next(d);
+			tmp = imx_dmav1_readl(imxdma, DMA_CCR(channel));
+			imx_dmav1_writel(imxdma, tmp | CCR_RPT | CCR_ACRPT,
+					 DMA_CCR(channel));
+		}
+	}
+
+	local_irq_restore(flags);
+}
+
+static void imxdma_disable_hw(struct imxdma_channel *imxdmac)
+{
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	int channel = imxdmac->channel;
+	unsigned long flags;
+
+	dev_dbg(imxdma->dev, "%s channel %d\n", __func__, channel);
+
+	if (imxdma_hw_chain(imxdmac))
+		del_timer(&imxdmac->watchdog);
+
+	local_irq_save(flags);
+	imx_dmav1_writel(imxdma, imx_dmav1_readl(imxdma, DMA_DIMR) |
+			 (1 << channel), DMA_DIMR);
+	imx_dmav1_writel(imxdma, imx_dmav1_readl(imxdma, DMA_CCR(channel)) &
+			 ~CCR_CEN, DMA_CCR(channel));
+	imx_dmav1_writel(imxdma, 1 << channel, DMA_DISR);
+	local_irq_restore(flags);
+}
+
+static void imxdma_watchdog(unsigned long data)
+{
+	struct imxdma_channel *imxdmac = (struct imxdma_channel *)data;
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	int channel = imxdmac->channel;
+
+	imx_dmav1_writel(imxdma, 0, DMA_CCR(channel));
+
+	/* Tasklet watchdog error handler */
+	tasklet_schedule(&imxdmac->dma_tasklet);
+	dev_dbg(imxdma->dev, "channel %d: watchdog timeout!\n",
+		imxdmac->channel);
+}
+
+static irqreturn_t imxdma_err_handler(int irq, void *dev_id)
+{
+	struct imxdma_engine *imxdma = dev_id;
+	unsigned int err_mask;
+	int i, disr;
+	int errcode;
+
+	disr = imx_dmav1_readl(imxdma, DMA_DISR);
+
+	err_mask = imx_dmav1_readl(imxdma, DMA_DBTOSR) |
+		   imx_dmav1_readl(imxdma, DMA_DRTOSR) |
+		   imx_dmav1_readl(imxdma, DMA_DSESR)  |
+		   imx_dmav1_readl(imxdma, DMA_DBOSR);
+
+	if (!err_mask)
+		return IRQ_HANDLED;
+
+	imx_dmav1_writel(imxdma, disr & err_mask, DMA_DISR);
+
+	for (i = 0; i < IMX_DMA_CHANNELS; i++) {
+		if (!(err_mask & (1 << i)))
+			continue;
+		errcode = 0;
+
+		if (imx_dmav1_readl(imxdma, DMA_DBTOSR) & (1 << i)) {
+			imx_dmav1_writel(imxdma, 1 << i, DMA_DBTOSR);
+			errcode |= IMX_DMA_ERR_BURST;
+		}
+		if (imx_dmav1_readl(imxdma, DMA_DRTOSR) & (1 << i)) {
+			imx_dmav1_writel(imxdma, 1 << i, DMA_DRTOSR);
+			errcode |= IMX_DMA_ERR_REQUEST;
+		}
+		if (imx_dmav1_readl(imxdma, DMA_DSESR) & (1 << i)) {
+			imx_dmav1_writel(imxdma, 1 << i, DMA_DSESR);
+			errcode |= IMX_DMA_ERR_TRANSFER;
+		}
+		if (imx_dmav1_readl(imxdma, DMA_DBOSR) & (1 << i)) {
+			imx_dmav1_writel(imxdma, 1 << i, DMA_DBOSR);
+			errcode |= IMX_DMA_ERR_BUFFER;
+		}
+		/* Tasklet error handler */
+		tasklet_schedule(&imxdma->channel[i].dma_tasklet);
+
+		printk(KERN_WARNING
+		       "DMA timeout on channel %d -%s%s%s%s\n", i,
+		       errcode & IMX_DMA_ERR_BURST ?    " burst" : "",
+		       errcode & IMX_DMA_ERR_REQUEST ?  " request" : "",
+		       errcode & IMX_DMA_ERR_TRANSFER ? " transfer" : "",
+		       errcode & IMX_DMA_ERR_BUFFER ?   " buffer" : "");
+	}
+	return IRQ_HANDLED;
+}
+
+static void dma_irq_handle_channel(struct imxdma_channel *imxdmac)
+{
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	int chno = imxdmac->channel;
+	struct imxdma_desc *desc;
+
+	spin_lock(&imxdma->lock);
+	if (list_empty(&imxdmac->ld_active)) {
+		spin_unlock(&imxdma->lock);
+		goto out;
+	}
+
+	desc = list_first_entry(&imxdmac->ld_active,
+				struct imxdma_desc,
+				node);
+	spin_unlock(&imxdma->lock);
+
+	if (desc->sg) {
+		u32 tmp;
+		desc->sg = sg_next(desc->sg);
+
+		if (desc->sg) {
+			imxdma_sg_next(desc);
+
+			tmp = imx_dmav1_readl(imxdma, DMA_CCR(chno));
+
+			if (imxdma_hw_chain(imxdmac)) {
+				/* FIXME: The timeout should probably be
+				 * configurable
+				 */
+				mod_timer(&imxdmac->watchdog,
+					jiffies + msecs_to_jiffies(500));
+
+				tmp |= CCR_CEN | CCR_RPT | CCR_ACRPT;
+				imx_dmav1_writel(imxdma, tmp, DMA_CCR(chno));
+			} else {
+				imx_dmav1_writel(imxdma, tmp & ~CCR_CEN,
+						 DMA_CCR(chno));
+				tmp |= CCR_CEN;
+			}
+
+			imx_dmav1_writel(imxdma, tmp, DMA_CCR(chno));
+
+			if (imxdma_chan_is_doing_cyclic(imxdmac))
+				/* Tasklet progression */
+				tasklet_schedule(&imxdmac->dma_tasklet);
+
+			return;
+		}
+
+		if (imxdma_hw_chain(imxdmac)) {
+			del_timer(&imxdmac->watchdog);
+			return;
+		}
+	}
+
+out:
+	imx_dmav1_writel(imxdma, 0, DMA_CCR(chno));
+	/* Tasklet irq */
+	tasklet_schedule(&imxdmac->dma_tasklet);
+}
+
+static irqreturn_t dma_irq_handler(int irq, void *dev_id)
+{
+	struct imxdma_engine *imxdma = dev_id;
+	int i, disr;
+
+	if (cpu_is_mx21() || cpu_is_mx27())
+		imxdma_err_handler(irq, dev_id);
+
+	disr = imx_dmav1_readl(imxdma, DMA_DISR);
+
+	dev_dbg(imxdma->dev, "%s called, disr=0x%08x\n", __func__, disr);
+
+	imx_dmav1_writel(imxdma, disr, DMA_DISR);
+	for (i = 0; i < IMX_DMA_CHANNELS; i++) {
+		if (disr & (1 << i))
+			dma_irq_handle_channel(&imxdma->channel[i]);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int imxdma_xfer_desc(struct imxdma_desc *d)
+{
+	struct imxdma_channel *imxdmac = to_imxdma_chan(d->desc.chan);
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	unsigned long flags;
+	int slot = -1;
+	int i;
+
+	/* Configure and enable */
+	switch (d->type) {
+	case IMXDMA_DESC_INTERLEAVED:
+		/* Try to get a free 2D slot */
+		spin_lock_irqsave(&imxdma->lock, flags);
+		for (i = 0; i < IMX_DMA_2D_SLOTS; i++) {
+			if ((imxdma->slots_2d[i].count > 0) &&
+			((imxdma->slots_2d[i].xsr != d->x) ||
+			(imxdma->slots_2d[i].ysr != d->y) ||
+			(imxdma->slots_2d[i].wsr != d->w)))
+				continue;
+			slot = i;
+			break;
+		}
+		if (slot < 0)
+			return -EBUSY;
+
+		imxdma->slots_2d[slot].xsr = d->x;
+		imxdma->slots_2d[slot].ysr = d->y;
+		imxdma->slots_2d[slot].wsr = d->w;
+		imxdma->slots_2d[slot].count++;
+
+		imxdmac->slot_2d = slot;
+		imxdmac->enabled_2d = true;
+		spin_unlock_irqrestore(&imxdma->lock, flags);
+
+		if (slot == IMX_DMA_2D_SLOT_A) {
+			d->config_mem &= ~CCR_MSEL_B;
+			d->config_port &= ~CCR_MSEL_B;
+			imx_dmav1_writel(imxdma, d->x, DMA_XSRA);
+			imx_dmav1_writel(imxdma, d->y, DMA_YSRA);
+			imx_dmav1_writel(imxdma, d->w, DMA_WSRA);
+		} else {
+			d->config_mem |= CCR_MSEL_B;
+			d->config_port |= CCR_MSEL_B;
+			imx_dmav1_writel(imxdma, d->x, DMA_XSRB);
+			imx_dmav1_writel(imxdma, d->y, DMA_YSRB);
+			imx_dmav1_writel(imxdma, d->w, DMA_WSRB);
+		}
+		/*
+		 * We fall-through here intentionally, since a 2D transfer is
+		 * similar to MEMCPY just adding the 2D slot configuration.
+		 */
+	case IMXDMA_DESC_MEMCPY:
+		imx_dmav1_writel(imxdma, d->src, DMA_SAR(imxdmac->channel));
+		imx_dmav1_writel(imxdma, d->dest, DMA_DAR(imxdmac->channel));
+		imx_dmav1_writel(imxdma, d->config_mem | (d->config_port << 2),
+			 DMA_CCR(imxdmac->channel));
+
+		imx_dmav1_writel(imxdma, d->len, DMA_CNTR(imxdmac->channel));
+
+		dev_dbg(imxdma->dev, "%s channel: %d dest=0x%08x src=0x%08x "
+			"dma_length=%d\n", __func__, imxdmac->channel,
+			d->dest, d->src, d->len);
+
+		break;
+	/* Cyclic transfer is the same as slave_sg with special sg configuration. */
+	case IMXDMA_DESC_CYCLIC:
+	case IMXDMA_DESC_SLAVE_SG:
+		if (d->direction == DMA_DEV_TO_MEM) {
+			imx_dmav1_writel(imxdma, imxdmac->per_address,
+					 DMA_SAR(imxdmac->channel));
+			imx_dmav1_writel(imxdma, imxdmac->ccr_from_device,
+					 DMA_CCR(imxdmac->channel));
+
+			dev_dbg(imxdma->dev, "%s channel: %d sg=%p sgcount=%d "
+				"total length=%d dev_addr=0x%08x (dev2mem)\n",
+				__func__, imxdmac->channel, d->sg, d->sgcount,
+				d->len, imxdmac->per_address);
+		} else if (d->direction == DMA_MEM_TO_DEV) {
+			imx_dmav1_writel(imxdma, imxdmac->per_address,
+					 DMA_DAR(imxdmac->channel));
+			imx_dmav1_writel(imxdma, imxdmac->ccr_to_device,
+					 DMA_CCR(imxdmac->channel));
+
+			dev_dbg(imxdma->dev, "%s channel: %d sg=%p sgcount=%d "
+				"total length=%d dev_addr=0x%08x (mem2dev)\n",
+				__func__, imxdmac->channel, d->sg, d->sgcount,
+				d->len, imxdmac->per_address);
+		} else {
+			dev_err(imxdma->dev, "%s channel: %d bad dma mode\n",
+				__func__, imxdmac->channel);
+			return -EINVAL;
+		}
+
+		imxdma_sg_next(d);
+
+		break;
+	default:
+		return -EINVAL;
+	}
+	imxdma_enable_hw(d);
+	return 0;
+}
+
+static void imxdma_tasklet(unsigned long data)
+{
+	struct imxdma_channel *imxdmac = (void *)data;
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	struct imxdma_desc *desc;
+
+	spin_lock(&imxdma->lock);
+
+	if (list_empty(&imxdmac->ld_active)) {
+		/* Someone might have called terminate all */
+		goto out;
+	}
+	desc = list_first_entry(&imxdmac->ld_active, struct imxdma_desc, node);
+
+	if (desc->desc.callback)
+		desc->desc.callback(desc->desc.callback_param);
+
+	dma_cookie_complete(&desc->desc);
+
+	/* If we are dealing with a cyclic descriptor keep it on ld_active */
+	if (imxdma_chan_is_doing_cyclic(imxdmac))
+		goto out;
+
+	/* Free 2D slot if it was an interleaved transfer */
+	if (imxdmac->enabled_2d) {
+		imxdma->slots_2d[imxdmac->slot_2d].count--;
+		imxdmac->enabled_2d = false;
+	}
+
+	list_move_tail(imxdmac->ld_active.next, &imxdmac->ld_free);
+
+	if (!list_empty(&imxdmac->ld_queue)) {
+		desc = list_first_entry(&imxdmac->ld_queue, struct imxdma_desc,
+					node);
+		list_move_tail(imxdmac->ld_queue.next, &imxdmac->ld_active);
+		if (imxdma_xfer_desc(desc) < 0)
+			dev_warn(imxdma->dev, "%s: channel: %d couldn't xfer desc\n",
+				 __func__, imxdmac->channel);
+	}
+out:
+	spin_unlock(&imxdma->lock);
 }
 
 static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
@@ -98,13 +602,18 @@
 {
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
 	struct dma_slave_config *dmaengine_cfg = (void *)arg;
-	int ret;
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	unsigned long flags;
 	unsigned int mode = 0;
 
 	switch (cmd) {
 	case DMA_TERMINATE_ALL:
-		imxdmac->status = DMA_ERROR;
-		imx_dma_disable(imxdmac->imxdma_channel);
+		imxdma_disable_hw(imxdmac);
+
+		spin_lock_irqsave(&imxdma->lock, flags);
+		list_splice_tail_init(&imxdmac->ld_active, &imxdmac->ld_free);
+		list_splice_tail_init(&imxdmac->ld_queue, &imxdmac->ld_free);
+		spin_unlock_irqrestore(&imxdma->lock, flags);
 		return 0;
 	case DMA_SLAVE_CONFIG:
 		if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
@@ -129,16 +638,22 @@
 			mode = IMX_DMA_MEMSIZE_32;
 			break;
 		}
-		ret = imx_dma_config_channel(imxdmac->imxdma_channel,
-				mode | IMX_DMA_TYPE_FIFO,
-				IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
-				imxdmac->dma_request, 1);
 
-		if (ret)
-			return ret;
+		imxdmac->hw_chaining = 1;
+		if (!imxdma_hw_chain(imxdmac))
+			return -EINVAL;
+		imxdmac->ccr_from_device = (mode | IMX_DMA_TYPE_FIFO) |
+			((IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR) << 2) |
+			CCR_REN;
+		imxdmac->ccr_to_device =
+			(IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR) |
+			((mode | IMX_DMA_TYPE_FIFO) << 2) | CCR_REN;
+		imx_dmav1_writel(imxdma, imxdmac->dma_request,
+				 DMA_RSSR(imxdmac->channel));
 
-		imx_dma_config_burstlen(imxdmac->imxdma_channel,
-				imxdmac->watermark_level * imxdmac->word_size);
+		/* Set burst length */
+		imx_dmav1_writel(imxdma, imxdmac->watermark_level *
+				imxdmac->word_size, DMA_BLR(imxdmac->channel));
 
 		return 0;
 	default:
@@ -152,43 +667,20 @@
 					    dma_cookie_t cookie,
 					    struct dma_tx_state *txstate)
 {
-	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
-	dma_cookie_t last_used;
-	enum dma_status ret;
-
-	last_used = chan->cookie;
-
-	ret = dma_async_is_complete(cookie, imxdmac->last_completed, last_used);
-	dma_set_tx_state(txstate, imxdmac->last_completed, last_used, 0);
-
-	return ret;
-}
-
-static dma_cookie_t imxdma_assign_cookie(struct imxdma_channel *imxdma)
-{
-	dma_cookie_t cookie = imxdma->chan.cookie;
-
-	if (++cookie < 0)
-		cookie = 1;
-
-	imxdma->chan.cookie = cookie;
-	imxdma->desc.cookie = cookie;
-
-	return cookie;
+	return dma_cookie_status(chan, cookie, txstate);
 }
 
 static dma_cookie_t imxdma_tx_submit(struct dma_async_tx_descriptor *tx)
 {
 	struct imxdma_channel *imxdmac = to_imxdma_chan(tx->chan);
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
 	dma_cookie_t cookie;
+	unsigned long flags;
 
-	spin_lock_irq(&imxdmac->lock);
-
-	cookie = imxdma_assign_cookie(imxdmac);
-
-	imx_dma_enable(imxdmac->imxdma_channel);
-
-	spin_unlock_irq(&imxdmac->lock);
+	spin_lock_irqsave(&imxdma->lock, flags);
+	list_move_tail(imxdmac->ld_free.next, &imxdmac->ld_queue);
+	cookie = dma_cookie_assign(tx);
+	spin_unlock_irqrestore(&imxdma->lock, flags);
 
 	return cookie;
 }
@@ -198,23 +690,52 @@
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
 	struct imx_dma_data *data = chan->private;
 
-	imxdmac->dma_request = data->dma_request;
+	if (data != NULL)
+		imxdmac->dma_request = data->dma_request;
 
-	dma_async_tx_descriptor_init(&imxdmac->desc, chan);
-	imxdmac->desc.tx_submit = imxdma_tx_submit;
-	/* txd.flags will be overwritten in prep funcs */
-	imxdmac->desc.flags = DMA_CTRL_ACK;
+	while (imxdmac->descs_allocated < IMXDMA_MAX_CHAN_DESCRIPTORS) {
+		struct imxdma_desc *desc;
 
-	imxdmac->status = DMA_SUCCESS;
+		desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+		if (!desc)
+			break;
+		__memzero(&desc->desc, sizeof(struct dma_async_tx_descriptor));
+		dma_async_tx_descriptor_init(&desc->desc, chan);
+		desc->desc.tx_submit = imxdma_tx_submit;
+		/* txd.flags will be overwritten in prep funcs */
+		desc->desc.flags = DMA_CTRL_ACK;
+		desc->status = DMA_SUCCESS;
 
-	return 0;
+		list_add_tail(&desc->node, &imxdmac->ld_free);
+		imxdmac->descs_allocated++;
+	}
+
+	if (!imxdmac->descs_allocated)
+		return -ENOMEM;
+
+	return imxdmac->descs_allocated;
 }
 
 static void imxdma_free_chan_resources(struct dma_chan *chan)
 {
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	struct imxdma_desc *desc, *_desc;
+	unsigned long flags;
 
-	imx_dma_disable(imxdmac->imxdma_channel);
+	spin_lock_irqsave(&imxdma->lock, flags);
+
+	imxdma_disable_hw(imxdmac);
+	list_splice_tail_init(&imxdmac->ld_active, &imxdmac->ld_free);
+	list_splice_tail_init(&imxdmac->ld_queue, &imxdmac->ld_free);
+
+	spin_unlock_irqrestore(&imxdma->lock, flags);
+
+	list_for_each_entry_safe(desc, _desc, &imxdmac->ld_free, node) {
+		kfree(desc);
+		imxdmac->descs_allocated--;
+	}
+	INIT_LIST_HEAD(&imxdmac->ld_free);
 
 	if (imxdmac->sg_list) {
 		kfree(imxdmac->sg_list);
@@ -225,27 +746,23 @@
 static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
 		struct dma_chan *chan, struct scatterlist *sgl,
 		unsigned int sg_len, enum dma_transfer_direction direction,
-		unsigned long flags)
+		unsigned long flags, void *context)
 {
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
 	struct scatterlist *sg;
-	int i, ret, dma_length = 0;
-	unsigned int dmamode;
+	int i, dma_length = 0;
+	struct imxdma_desc *desc;
 
-	if (imxdmac->status == DMA_IN_PROGRESS)
+	if (list_empty(&imxdmac->ld_free) ||
+	    imxdma_chan_is_doing_cyclic(imxdmac))
 		return NULL;
 
-	imxdmac->status = DMA_IN_PROGRESS;
+	desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
 
 	for_each_sg(sgl, sg, sg_len, i) {
 		dma_length += sg->length;
 	}
 
-	if (direction == DMA_DEV_TO_MEM)
-		dmamode = DMA_MODE_READ;
-	else
-		dmamode = DMA_MODE_WRITE;
-
 	switch (imxdmac->word_size) {
 	case DMA_SLAVE_BUSWIDTH_4_BYTES:
 		if (sgl->length & 3 || sgl->dma_address & 3)
@@ -261,37 +778,41 @@
 		return NULL;
 	}
 
-	ret = imx_dma_setup_sg(imxdmac->imxdma_channel, sgl, sg_len,
-		 dma_length, imxdmac->per_address, dmamode);
-	if (ret)
-		return NULL;
+	desc->type = IMXDMA_DESC_SLAVE_SG;
+	desc->sg = sgl;
+	desc->sgcount = sg_len;
+	desc->len = dma_length;
+	desc->direction = direction;
+	if (direction == DMA_DEV_TO_MEM) {
+		desc->src = imxdmac->per_address;
+	} else {
+		desc->dest = imxdmac->per_address;
+	}
+	desc->desc.callback = NULL;
+	desc->desc.callback_param = NULL;
 
-	return &imxdmac->desc;
+	return &desc->desc;
 }
 
 static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
 		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
-		size_t period_len, enum dma_transfer_direction direction)
+		size_t period_len, enum dma_transfer_direction direction,
+		void *context)
 {
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
 	struct imxdma_engine *imxdma = imxdmac->imxdma;
-	int i, ret;
+	struct imxdma_desc *desc;
+	int i;
 	unsigned int periods = buf_len / period_len;
-	unsigned int dmamode;
 
 	dev_dbg(imxdma->dev, "%s channel: %d buf_len=%d period_len=%d\n",
 			__func__, imxdmac->channel, buf_len, period_len);
 
-	if (imxdmac->status == DMA_IN_PROGRESS)
+	if (list_empty(&imxdmac->ld_free) ||
+	    imxdma_chan_is_doing_cyclic(imxdmac))
 		return NULL;
-	imxdmac->status = DMA_IN_PROGRESS;
 
-	ret = imx_dma_setup_progression_handler(imxdmac->imxdma_channel,
-			imxdma_progression);
-	if (ret) {
-		dev_err(imxdma->dev, "Failed to setup the DMA handler\n");
-		return NULL;
-	}
+	desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
 
 	if (imxdmac->sg_list)
 		kfree(imxdmac->sg_list);
@@ -317,62 +838,221 @@
 	imxdmac->sg_list[periods].page_link =
 		((unsigned long)imxdmac->sg_list | 0x01) & ~0x02;
 
-	if (direction == DMA_DEV_TO_MEM)
-		dmamode = DMA_MODE_READ;
-	else
-		dmamode = DMA_MODE_WRITE;
+	desc->type = IMXDMA_DESC_CYCLIC;
+	desc->sg = imxdmac->sg_list;
+	desc->sgcount = periods;
+	desc->len = IMX_DMA_LENGTH_LOOP;
+	desc->direction = direction;
+	if (direction == DMA_DEV_TO_MEM) {
+		desc->src = imxdmac->per_address;
+	} else {
+		desc->dest = imxdmac->per_address;
+	}
+	desc->desc.callback = NULL;
+	desc->desc.callback_param = NULL;
 
-	ret = imx_dma_setup_sg(imxdmac->imxdma_channel, imxdmac->sg_list, periods,
-		 IMX_DMA_LENGTH_LOOP, imxdmac->per_address, dmamode);
-	if (ret)
+	return &desc->desc;
+}
+
+static struct dma_async_tx_descriptor *imxdma_prep_dma_memcpy(
+	struct dma_chan *chan, dma_addr_t dest,
+	dma_addr_t src, size_t len, unsigned long flags)
+{
+	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	struct imxdma_desc *desc;
+
+	dev_dbg(imxdma->dev, "%s channel: %d src=0x%x dst=0x%x len=%d\n",
+			__func__, imxdmac->channel, src, dest, len);
+
+	if (list_empty(&imxdmac->ld_free) ||
+	    imxdma_chan_is_doing_cyclic(imxdmac))
 		return NULL;
 
-	return &imxdmac->desc;
+	desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
+
+	desc->type = IMXDMA_DESC_MEMCPY;
+	desc->src = src;
+	desc->dest = dest;
+	desc->len = len;
+	desc->direction = DMA_MEM_TO_MEM;
+	desc->config_port = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR;
+	desc->config_mem = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR;
+	desc->desc.callback = NULL;
+	desc->desc.callback_param = NULL;
+
+	return &desc->desc;
+}
+
+static struct dma_async_tx_descriptor *imxdma_prep_dma_interleaved(
+	struct dma_chan *chan, struct dma_interleaved_template *xt,
+	unsigned long flags)
+{
+	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	struct imxdma_desc *desc;
+
+	dev_dbg(imxdma->dev, "%s channel: %d src_start=0x%x dst_start=0x%x\n"
+		"   src_sgl=%s dst_sgl=%s numf=%d frame_size=%d\n", __func__,
+		imxdmac->channel, xt->src_start, xt->dst_start,
+		xt->src_sgl ? "true" : "false", xt->dst_sgl ? "true" : "false",
+		xt->numf, xt->frame_size);
+
+	if (list_empty(&imxdmac->ld_free) ||
+	    imxdma_chan_is_doing_cyclic(imxdmac))
+		return NULL;
+
+	if (xt->frame_size != 1 || xt->numf <= 0 || xt->dir != DMA_MEM_TO_MEM)
+		return NULL;
+
+	desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
+
+	desc->type = IMXDMA_DESC_INTERLEAVED;
+	desc->src = xt->src_start;
+	desc->dest = xt->dst_start;
+	desc->x = xt->sgl[0].size;
+	desc->y = xt->numf;
+	desc->w = xt->sgl[0].icg + desc->x;
+	desc->len = desc->x * desc->y;
+	desc->direction = DMA_MEM_TO_MEM;
+	desc->config_port = IMX_DMA_MEMSIZE_32;
+	desc->config_mem = IMX_DMA_MEMSIZE_32;
+	if (xt->src_sgl)
+		desc->config_mem |= IMX_DMA_TYPE_2D;
+	if (xt->dst_sgl)
+		desc->config_port |= IMX_DMA_TYPE_2D;
+	desc->desc.callback = NULL;
+	desc->desc.callback_param = NULL;
+
+	return &desc->desc;
 }
 
 static void imxdma_issue_pending(struct dma_chan *chan)
 {
-	/*
-	 * Nothing to do. We only have a single descriptor
-	 */
+	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	struct imxdma_desc *desc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&imxdma->lock, flags);
+	if (list_empty(&imxdmac->ld_active) &&
+	    !list_empty(&imxdmac->ld_queue)) {
+		desc = list_first_entry(&imxdmac->ld_queue,
+					struct imxdma_desc, node);
+
+		if (imxdma_xfer_desc(desc) < 0) {
+			dev_warn(imxdma->dev,
+				 "%s: channel: %d couldn't issue DMA xfer\n",
+				 __func__, imxdmac->channel);
+		} else {
+			list_move_tail(imxdmac->ld_queue.next,
+				       &imxdmac->ld_active);
+		}
+	}
+	spin_unlock_irqrestore(&imxdma->lock, flags);
 }
 
 static int __init imxdma_probe(struct platform_device *pdev)
-{
+	{
 	struct imxdma_engine *imxdma;
 	int ret, i;
 
+
 	imxdma = kzalloc(sizeof(*imxdma), GFP_KERNEL);
 	if (!imxdma)
 		return -ENOMEM;
 
+	if (cpu_is_mx1()) {
+		imxdma->base = MX1_IO_ADDRESS(MX1_DMA_BASE_ADDR);
+	} else if (cpu_is_mx21()) {
+		imxdma->base = MX21_IO_ADDRESS(MX21_DMA_BASE_ADDR);
+	} else if (cpu_is_mx27()) {
+		imxdma->base = MX27_IO_ADDRESS(MX27_DMA_BASE_ADDR);
+	} else {
+		kfree(imxdma);
+		return 0;
+	}
+
+	imxdma->dma_clk = clk_get(NULL, "dma");
+	if (IS_ERR(imxdma->dma_clk))
+		return PTR_ERR(imxdma->dma_clk);
+	clk_enable(imxdma->dma_clk);
+
+	/* reset DMA module */
+	imx_dmav1_writel(imxdma, DCR_DRST, DMA_DCR);
+
+	if (cpu_is_mx1()) {
+		ret = request_irq(MX1_DMA_INT, dma_irq_handler, 0, "DMA", imxdma);
+		if (ret) {
+			dev_warn(imxdma->dev, "Can't register IRQ for DMA\n");
+			kfree(imxdma);
+			return ret;
+		}
+
+		ret = request_irq(MX1_DMA_ERR, imxdma_err_handler, 0, "DMA", imxdma);
+		if (ret) {
+			dev_warn(imxdma->dev, "Can't register ERRIRQ for DMA\n");
+			free_irq(MX1_DMA_INT, NULL);
+			kfree(imxdma);
+			return ret;
+		}
+	}
+
+	/* enable DMA module */
+	imx_dmav1_writel(imxdma, DCR_DEN, DMA_DCR);
+
+	/* clear all interrupts */
+	imx_dmav1_writel(imxdma, (1 << IMX_DMA_CHANNELS) - 1, DMA_DISR);
+
+	/* disable interrupts */
+	imx_dmav1_writel(imxdma, (1 << IMX_DMA_CHANNELS) - 1, DMA_DIMR);
+
 	INIT_LIST_HEAD(&imxdma->dma_device.channels);
 
 	dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask);
 	dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask);
+	dma_cap_set(DMA_MEMCPY, imxdma->dma_device.cap_mask);
+	dma_cap_set(DMA_INTERLEAVE, imxdma->dma_device.cap_mask);
+
+	/* Initialize 2D global parameters */
+	for (i = 0; i < IMX_DMA_2D_SLOTS; i++)
+		imxdma->slots_2d[i].count = 0;
+
+	spin_lock_init(&imxdma->lock);
 
 	/* Initialize channel parameters */
-	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+	for (i = 0; i < IMX_DMA_CHANNELS; i++) {
 		struct imxdma_channel *imxdmac = &imxdma->channel[i];
 
-		imxdmac->imxdma_channel = imx_dma_request_by_prio("dmaengine",
-				DMA_PRIO_MEDIUM);
-		if ((int)imxdmac->channel < 0) {
-			ret = -ENODEV;
-			goto err_init;
+		if (cpu_is_mx21() || cpu_is_mx27()) {
+			ret = request_irq(MX2x_INT_DMACH0 + i,
+					dma_irq_handler, 0, "DMA", imxdma);
+			if (ret) {
+				dev_warn(imxdma->dev, "Can't register IRQ %d "
+					 "for DMA channel %d\n",
+					 MX2x_INT_DMACH0 + i, i);
+				goto err_init;
+			}
+			init_timer(&imxdmac->watchdog);
+			imxdmac->watchdog.function = &imxdma_watchdog;
+			imxdmac->watchdog.data = (unsigned long)imxdmac;
 		}
 
-		imx_dma_setup_handlers(imxdmac->imxdma_channel,
-		       imxdma_irq_handler, imxdma_err_handler, imxdmac);
-
 		imxdmac->imxdma = imxdma;
-		spin_lock_init(&imxdmac->lock);
 
+		INIT_LIST_HEAD(&imxdmac->ld_queue);
+		INIT_LIST_HEAD(&imxdmac->ld_free);
+		INIT_LIST_HEAD(&imxdmac->ld_active);
+
+		tasklet_init(&imxdmac->dma_tasklet, imxdma_tasklet,
+			     (unsigned long)imxdmac);
 		imxdmac->chan.device = &imxdma->dma_device;
+		dma_cookie_init(&imxdmac->chan);
 		imxdmac->channel = i;
 
 		/* Add the channel to the DMAC list */
-		list_add_tail(&imxdmac->chan.device_node, &imxdma->dma_device.channels);
+		list_add_tail(&imxdmac->chan.device_node,
+			      &imxdma->dma_device.channels);
 	}
 
 	imxdma->dev = &pdev->dev;
@@ -383,11 +1063,14 @@
 	imxdma->dma_device.device_tx_status = imxdma_tx_status;
 	imxdma->dma_device.device_prep_slave_sg = imxdma_prep_slave_sg;
 	imxdma->dma_device.device_prep_dma_cyclic = imxdma_prep_dma_cyclic;
+	imxdma->dma_device.device_prep_dma_memcpy = imxdma_prep_dma_memcpy;
+	imxdma->dma_device.device_prep_interleaved_dma = imxdma_prep_dma_interleaved;
 	imxdma->dma_device.device_control = imxdma_control;
 	imxdma->dma_device.device_issue_pending = imxdma_issue_pending;
 
 	platform_set_drvdata(pdev, imxdma);
 
+	imxdma->dma_device.copy_align = 2; /* 2^2 = 4 bytes alignment */
 	imxdma->dma_device.dev->dma_parms = &imxdma->dma_parms;
 	dma_set_max_seg_size(imxdma->dma_device.dev, 0xffffff);
 
@@ -400,9 +1083,13 @@
 	return 0;
 
 err_init:
-	while (--i >= 0) {
-		struct imxdma_channel *imxdmac = &imxdma->channel[i];
-		imx_dma_free(imxdmac->imxdma_channel);
+
+	if (cpu_is_mx21() || cpu_is_mx27()) {
+		while (--i >= 0)
+			free_irq(MX2x_INT_DMACH0 + i, NULL);
+	} else if cpu_is_mx1() {
+		free_irq(MX1_DMA_INT, NULL);
+		free_irq(MX1_DMA_ERR, NULL);
 	}
 
 	kfree(imxdma);
@@ -416,10 +1103,12 @@
 
         dma_async_device_unregister(&imxdma->dma_device);
 
-	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
-		struct imxdma_channel *imxdmac = &imxdma->channel[i];
-
-		 imx_dma_free(imxdmac->imxdma_channel);
+	if (cpu_is_mx21() || cpu_is_mx27()) {
+		for (i = 0; i < IMX_DMA_CHANNELS; i++)
+			free_irq(MX2x_INT_DMACH0 + i, NULL);
+	} else if cpu_is_mx1() {
+		free_irq(MX1_DMA_INT, NULL);
+		free_irq(MX1_DMA_ERR, NULL);
 	}
 
         kfree(imxdma);
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 8bc5acf..d3e38e2 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/bitops.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/clk.h>
@@ -35,13 +36,14 @@
 #include <linux/dmaengine.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/module.h>
 
 #include <asm/irq.h>
 #include <mach/sdma.h>
 #include <mach/dma.h>
 #include <mach/hardware.h>
 
+#include "dmaengine.h"
+
 /* SDMA registers */
 #define SDMA_H_C0PTR		0x000
 #define SDMA_H_INTR		0x004
@@ -260,19 +262,18 @@
 	unsigned int			pc_from_device, pc_to_device;
 	unsigned long			flags;
 	dma_addr_t			per_address;
-	u32				event_mask0, event_mask1;
-	u32				watermark_level;
+	unsigned long			event_mask[2];
+	unsigned long			watermark_level;
 	u32				shp_addr, per_addr;
 	struct dma_chan			chan;
 	spinlock_t			lock;
 	struct dma_async_tx_descriptor	desc;
-	dma_cookie_t			last_completed;
 	enum dma_status			status;
 	unsigned int			chn_count;
 	unsigned int			chn_real_count;
 };
 
-#define IMX_DMA_SG_LOOP		(1 << 0)
+#define IMX_DMA_SG_LOOP		BIT(0)
 
 #define MAX_DMA_CHANNELS 32
 #define MXC_SDMA_DEFAULT_PRIORITY 1
@@ -346,9 +347,9 @@
 };
 MODULE_DEVICE_TABLE(of, sdma_dt_ids);
 
-#define SDMA_H_CONFIG_DSPDMA	(1 << 12) /* indicates if the DSPDMA is used */
-#define SDMA_H_CONFIG_RTD_PINS	(1 << 11) /* indicates if Real-Time Debug pins are enabled */
-#define SDMA_H_CONFIG_ACR	(1 << 4)  /* indicates if AHB freq /core freq = 2 or 1 */
+#define SDMA_H_CONFIG_DSPDMA	BIT(12) /* indicates if the DSPDMA is used */
+#define SDMA_H_CONFIG_RTD_PINS	BIT(11) /* indicates if Real-Time Debug pins are enabled */
+#define SDMA_H_CONFIG_ACR	BIT(4)  /* indicates if AHB freq /core freq = 2 or 1 */
 #define SDMA_H_CONFIG_CSM	(3)       /* indicates which context switch mode is selected*/
 
 static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event)
@@ -363,37 +364,42 @@
 {
 	struct sdma_engine *sdma = sdmac->sdma;
 	int channel = sdmac->channel;
-	u32 evt, mcu, dsp;
+	unsigned long evt, mcu, dsp;
 
 	if (event_override && mcu_override && dsp_override)
 		return -EINVAL;
 
-	evt = __raw_readl(sdma->regs + SDMA_H_EVTOVR);
-	mcu = __raw_readl(sdma->regs + SDMA_H_HOSTOVR);
-	dsp = __raw_readl(sdma->regs + SDMA_H_DSPOVR);
+	evt = readl_relaxed(sdma->regs + SDMA_H_EVTOVR);
+	mcu = readl_relaxed(sdma->regs + SDMA_H_HOSTOVR);
+	dsp = readl_relaxed(sdma->regs + SDMA_H_DSPOVR);
 
 	if (dsp_override)
-		dsp &= ~(1 << channel);
+		__clear_bit(channel, &dsp);
 	else
-		dsp |= (1 << channel);
+		__set_bit(channel, &dsp);
 
 	if (event_override)
-		evt &= ~(1 << channel);
+		__clear_bit(channel, &evt);
 	else
-		evt |= (1 << channel);
+		__set_bit(channel, &evt);
 
 	if (mcu_override)
-		mcu &= ~(1 << channel);
+		__clear_bit(channel, &mcu);
 	else
-		mcu |= (1 << channel);
+		__set_bit(channel, &mcu);
 
-	__raw_writel(evt, sdma->regs + SDMA_H_EVTOVR);
-	__raw_writel(mcu, sdma->regs + SDMA_H_HOSTOVR);
-	__raw_writel(dsp, sdma->regs + SDMA_H_DSPOVR);
+	writel_relaxed(evt, sdma->regs + SDMA_H_EVTOVR);
+	writel_relaxed(mcu, sdma->regs + SDMA_H_HOSTOVR);
+	writel_relaxed(dsp, sdma->regs + SDMA_H_DSPOVR);
 
 	return 0;
 }
 
+static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
+{
+	writel(BIT(channel), sdma->regs + SDMA_H_START);
+}
+
 /*
  * sdma_run_channel - run a channel and wait till it's done
  */
@@ -405,7 +411,7 @@
 
 	init_completion(&sdmac->done);
 
-	__raw_writel(1 << channel, sdma->regs + SDMA_H_START);
+	sdma_enable_channel(sdma, channel);
 
 	ret = wait_for_completion_timeout(&sdmac->done, HZ);
 
@@ -452,12 +458,12 @@
 {
 	struct sdma_engine *sdma = sdmac->sdma;
 	int channel = sdmac->channel;
-	u32 val;
+	unsigned long val;
 	u32 chnenbl = chnenbl_ofs(sdma, event);
 
-	val = __raw_readl(sdma->regs + chnenbl);
-	val |= (1 << channel);
-	__raw_writel(val, sdma->regs + chnenbl);
+	val = readl_relaxed(sdma->regs + chnenbl);
+	__set_bit(channel, &val);
+	writel_relaxed(val, sdma->regs + chnenbl);
 }
 
 static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
@@ -465,11 +471,11 @@
 	struct sdma_engine *sdma = sdmac->sdma;
 	int channel = sdmac->channel;
 	u32 chnenbl = chnenbl_ofs(sdma, event);
-	u32 val;
+	unsigned long val;
 
-	val = __raw_readl(sdma->regs + chnenbl);
-	val &= ~(1 << channel);
-	__raw_writel(val, sdma->regs + chnenbl);
+	val = readl_relaxed(sdma->regs + chnenbl);
+	__clear_bit(channel, &val);
+	writel_relaxed(val, sdma->regs + chnenbl);
 }
 
 static void sdma_handle_channel_loop(struct sdma_channel *sdmac)
@@ -523,7 +529,7 @@
 	else
 		sdmac->status = DMA_SUCCESS;
 
-	sdmac->last_completed = sdmac->desc.cookie;
+	dma_cookie_complete(&sdmac->desc);
 	if (sdmac->desc.callback)
 		sdmac->desc.callback(sdmac->desc.callback_param);
 }
@@ -545,10 +551,10 @@
 static irqreturn_t sdma_int_handler(int irq, void *dev_id)
 {
 	struct sdma_engine *sdma = dev_id;
-	u32 stat;
+	unsigned long stat;
 
-	stat = __raw_readl(sdma->regs + SDMA_H_INTR);
-	__raw_writel(stat, sdma->regs + SDMA_H_INTR);
+	stat = readl_relaxed(sdma->regs + SDMA_H_INTR);
+	writel_relaxed(stat, sdma->regs + SDMA_H_INTR);
 
 	while (stat) {
 		int channel = fls(stat) - 1;
@@ -556,7 +562,7 @@
 
 		mxc_sdma_handle_channel(sdmac);
 
-		stat &= ~(1 << channel);
+		__clear_bit(channel, &stat);
 	}
 
 	return IRQ_HANDLED;
@@ -664,11 +670,11 @@
 		return load_address;
 
 	dev_dbg(sdma->dev, "load_address = %d\n", load_address);
-	dev_dbg(sdma->dev, "wml = 0x%08x\n", sdmac->watermark_level);
+	dev_dbg(sdma->dev, "wml = 0x%08x\n", (u32)sdmac->watermark_level);
 	dev_dbg(sdma->dev, "shp_addr = 0x%08x\n", sdmac->shp_addr);
 	dev_dbg(sdma->dev, "per_addr = 0x%08x\n", sdmac->per_addr);
-	dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", sdmac->event_mask0);
-	dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", sdmac->event_mask1);
+	dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", (u32)sdmac->event_mask[0]);
+	dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", (u32)sdmac->event_mask[1]);
 
 	mutex_lock(&sdma->channel_0_lock);
 
@@ -678,8 +684,8 @@
 	/* Send by context the event mask,base address for peripheral
 	 * and watermark level
 	 */
-	context->gReg[0] = sdmac->event_mask1;
-	context->gReg[1] = sdmac->event_mask0;
+	context->gReg[0] = sdmac->event_mask[1];
+	context->gReg[1] = sdmac->event_mask[0];
 	context->gReg[2] = sdmac->per_addr;
 	context->gReg[6] = sdmac->shp_addr;
 	context->gReg[7] = sdmac->watermark_level;
@@ -702,7 +708,7 @@
 	struct sdma_engine *sdma = sdmac->sdma;
 	int channel = sdmac->channel;
 
-	__raw_writel(1 << channel, sdma->regs + SDMA_H_STATSTOP);
+	writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP);
 	sdmac->status = DMA_ERROR;
 }
 
@@ -712,13 +718,13 @@
 
 	sdma_disable_channel(sdmac);
 
-	sdmac->event_mask0 = 0;
-	sdmac->event_mask1 = 0;
+	sdmac->event_mask[0] = 0;
+	sdmac->event_mask[1] = 0;
 	sdmac->shp_addr = 0;
 	sdmac->per_addr = 0;
 
 	if (sdmac->event_id0) {
-		if (sdmac->event_id0 > 32)
+		if (sdmac->event_id0 >= sdmac->sdma->num_events)
 			return -EINVAL;
 		sdma_event_enable(sdmac, sdmac->event_id0);
 	}
@@ -741,15 +747,14 @@
 			(sdmac->peripheral_type != IMX_DMATYPE_DSP)) {
 		/* Handle multiple event channels differently */
 		if (sdmac->event_id1) {
-			sdmac->event_mask1 = 1 << (sdmac->event_id1 % 32);
+			sdmac->event_mask[1] = BIT(sdmac->event_id1 % 32);
 			if (sdmac->event_id1 > 31)
-				sdmac->watermark_level |= 1 << 31;
-			sdmac->event_mask0 = 1 << (sdmac->event_id0 % 32);
+				__set_bit(31, &sdmac->watermark_level);
+			sdmac->event_mask[0] = BIT(sdmac->event_id0 % 32);
 			if (sdmac->event_id0 > 31)
-				sdmac->watermark_level |= 1 << 30;
+				__set_bit(30, &sdmac->watermark_level);
 		} else {
-			sdmac->event_mask0 = 1 << sdmac->event_id0;
-			sdmac->event_mask1 = 1 << (sdmac->event_id0 - 32);
+			__set_bit(sdmac->event_id0, sdmac->event_mask);
 		}
 		/* Watermark Level */
 		sdmac->watermark_level |= sdmac->watermark_level;
@@ -775,7 +780,7 @@
 		return -EINVAL;
 	}
 
-	__raw_writel(priority, sdma->regs + SDMA_CHNPRI_0 + 4 * channel);
+	writel_relaxed(priority, sdma->regs + SDMA_CHNPRI_0 + 4 * channel);
 
 	return 0;
 }
@@ -797,8 +802,6 @@
 	sdma->channel_control[channel].base_bd_ptr = sdmac->bd_phys;
 	sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
 
-	clk_enable(sdma->clk);
-
 	sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY);
 
 	init_completion(&sdmac->done);
@@ -811,24 +814,6 @@
 	return ret;
 }
 
-static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
-{
-	__raw_writel(1 << channel, sdma->regs + SDMA_H_START);
-}
-
-static dma_cookie_t sdma_assign_cookie(struct sdma_channel *sdmac)
-{
-	dma_cookie_t cookie = sdmac->chan.cookie;
-
-	if (++cookie < 0)
-		cookie = 1;
-
-	sdmac->chan.cookie = cookie;
-	sdmac->desc.cookie = cookie;
-
-	return cookie;
-}
-
 static struct sdma_channel *to_sdma_chan(struct dma_chan *chan)
 {
 	return container_of(chan, struct sdma_channel, chan);
@@ -838,14 +823,11 @@
 {
 	unsigned long flags;
 	struct sdma_channel *sdmac = to_sdma_chan(tx->chan);
-	struct sdma_engine *sdma = sdmac->sdma;
 	dma_cookie_t cookie;
 
 	spin_lock_irqsave(&sdmac->lock, flags);
 
-	cookie = sdma_assign_cookie(sdmac);
-
-	sdma_enable_channel(sdma, sdmac->channel);
+	cookie = dma_cookie_assign(tx);
 
 	spin_unlock_irqrestore(&sdmac->lock, flags);
 
@@ -876,11 +858,14 @@
 
 	sdmac->peripheral_type = data->peripheral_type;
 	sdmac->event_id0 = data->dma_request;
-	ret = sdma_set_channel_priority(sdmac, prio);
+
+	clk_enable(sdmac->sdma->clk);
+
+	ret = sdma_request_channel(sdmac);
 	if (ret)
 		return ret;
 
-	ret = sdma_request_channel(sdmac);
+	ret = sdma_set_channel_priority(sdmac, prio);
 	if (ret)
 		return ret;
 
@@ -917,7 +902,7 @@
 static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 		struct dma_chan *chan, struct scatterlist *sgl,
 		unsigned int sg_len, enum dma_transfer_direction direction,
-		unsigned long flags)
+		unsigned long flags, void *context)
 {
 	struct sdma_channel *sdmac = to_sdma_chan(chan);
 	struct sdma_engine *sdma = sdmac->sdma;
@@ -1015,7 +1000,8 @@
 
 static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
 		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
-		size_t period_len, enum dma_transfer_direction direction)
+		size_t period_len, enum dma_transfer_direction direction,
+		void *context)
 {
 	struct sdma_channel *sdmac = to_sdma_chan(chan);
 	struct sdma_engine *sdma = sdmac->sdma;
@@ -1129,7 +1115,7 @@
 
 	last_used = chan->cookie;
 
-	dma_set_tx_state(txstate, sdmac->last_completed, last_used,
+	dma_set_tx_state(txstate, chan->completed_cookie, last_used,
 			sdmac->chn_count - sdmac->chn_real_count);
 
 	return sdmac->status;
@@ -1137,9 +1123,11 @@
 
 static void sdma_issue_pending(struct dma_chan *chan)
 {
-	/*
-	 * Nothing to do. We only have a single descriptor
-	 */
+	struct sdma_channel *sdmac = to_sdma_chan(chan);
+	struct sdma_engine *sdma = sdmac->sdma;
+
+	if (sdmac->status == DMA_IN_PROGRESS)
+		sdma_enable_channel(sdma, sdmac->channel);
 }
 
 #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1	34
@@ -1231,7 +1219,7 @@
 	clk_enable(sdma->clk);
 
 	/* Be sure SDMA has not started yet */
-	__raw_writel(0, sdma->regs + SDMA_H_C0PTR);
+	writel_relaxed(0, sdma->regs + SDMA_H_C0PTR);
 
 	sdma->channel_control = dma_alloc_coherent(NULL,
 			MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) +
@@ -1254,11 +1242,11 @@
 
 	/* disable all channels */
 	for (i = 0; i < sdma->num_events; i++)
-		__raw_writel(0, sdma->regs + chnenbl_ofs(sdma, i));
+		writel_relaxed(0, sdma->regs + chnenbl_ofs(sdma, i));
 
 	/* All channels have priority 0 */
 	for (i = 0; i < MAX_DMA_CHANNELS; i++)
-		__raw_writel(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
+		writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
 
 	ret = sdma_request_channel(&sdma->channel[0]);
 	if (ret)
@@ -1267,16 +1255,16 @@
 	sdma_config_ownership(&sdma->channel[0], false, true, false);
 
 	/* Set Command Channel (Channel Zero) */
-	__raw_writel(0x4050, sdma->regs + SDMA_CHN0ADDR);
+	writel_relaxed(0x4050, sdma->regs + SDMA_CHN0ADDR);
 
 	/* Set bits of CONFIG register but with static context switching */
 	/* FIXME: Check whether to set ACR bit depending on clock ratios */
-	__raw_writel(0, sdma->regs + SDMA_H_CONFIG);
+	writel_relaxed(0, sdma->regs + SDMA_H_CONFIG);
 
-	__raw_writel(ccb_phys, sdma->regs + SDMA_H_C0PTR);
+	writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR);
 
 	/* Set bits of CONFIG register with given context switching mode */
-	__raw_writel(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
+	writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
 
 	/* Initializes channel's priorities */
 	sdma_set_channel_priority(&sdma->channel[0], 7);
@@ -1368,6 +1356,7 @@
 		spin_lock_init(&sdmac->lock);
 
 		sdmac->chan.device = &sdma->dma_device;
+		dma_cookie_init(&sdmac->chan);
 		sdmac->channel = i;
 
 		/*
@@ -1388,7 +1377,9 @@
 		sdma_add_scripts(sdma, pdata->script_addrs);
 
 	if (pdata) {
-		sdma_get_firmware(sdma, pdata->fw_name);
+		ret = sdma_get_firmware(sdma, pdata->fw_name);
+		if (ret)
+			dev_warn(&pdev->dev, "failed to get firmware from platform data\n");
 	} else {
 		/*
 		 * Because that device tree does not encode ROM script address,
@@ -1397,15 +1388,12 @@
 		 */
 		ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
 					      &fw_name);
-		if (ret) {
-			dev_err(&pdev->dev, "failed to get firmware name\n");
-			goto err_init;
-		}
-
-		ret = sdma_get_firmware(sdma, fw_name);
-		if (ret) {
-			dev_err(&pdev->dev, "failed to get firmware\n");
-			goto err_init;
+		if (ret)
+			dev_warn(&pdev->dev, "failed to get firmware name\n");
+		else {
+			ret = sdma_get_firmware(sdma, fw_name);
+			if (ret)
+				dev_warn(&pdev->dev, "failed to get firmware from device tree\n");
 		}
 	}
 
diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c
index 74f70aa..c900ca7 100644
--- a/drivers/dma/intel_mid_dma.c
+++ b/drivers/dma/intel_mid_dma.c
@@ -29,6 +29,8 @@
 #include <linux/intel_mid_dma.h>
 #include <linux/module.h>
 
+#include "dmaengine.h"
+
 #define MAX_CHAN	4 /*max ch across controllers*/
 #include "intel_mid_dma_regs.h"
 
@@ -288,7 +290,7 @@
 	struct intel_mid_dma_lli	*llitem;
 	void *param_txd = NULL;
 
-	midc->completed = txd->cookie;
+	dma_cookie_complete(txd);
 	callback_txd = txd->callback;
 	param_txd = txd->callback_param;
 
@@ -434,14 +436,7 @@
 	dma_cookie_t		cookie;
 
 	spin_lock_bh(&midc->lock);
-	cookie = midc->chan.cookie;
-
-	if (++cookie < 0)
-		cookie = 1;
-
-	midc->chan.cookie = cookie;
-	desc->txd.cookie = cookie;
-
+	cookie = dma_cookie_assign(tx);
 
 	if (list_empty(&midc->active_list))
 		list_add_tail(&desc->desc_node, &midc->active_list);
@@ -482,31 +477,18 @@
 						dma_cookie_t cookie,
 						struct dma_tx_state *txstate)
 {
-	struct intel_mid_dma_chan	*midc = to_intel_mid_dma_chan(chan);
-	dma_cookie_t		last_used;
-	dma_cookie_t		last_complete;
-	int				ret;
+	struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
+	enum dma_status ret;
 
-	last_complete = midc->completed;
-	last_used = chan->cookie;
-
-	ret = dma_async_is_complete(cookie, last_complete, last_used);
+	ret = dma_cookie_status(chan, cookie, txstate);
 	if (ret != DMA_SUCCESS) {
 		spin_lock_bh(&midc->lock);
 		midc_scan_descriptors(to_middma_device(chan->device), midc);
 		spin_unlock_bh(&midc->lock);
 
-		last_complete = midc->completed;
-		last_used = chan->cookie;
-
-		ret = dma_async_is_complete(cookie, last_complete, last_used);
+		ret = dma_cookie_status(chan, cookie, txstate);
 	}
 
-	if (txstate) {
-		txstate->last = last_complete;
-		txstate->used = last_used;
-		txstate->residue = 0;
-	}
 	return ret;
 }
 
@@ -732,13 +714,14 @@
  * @sg_len: length of sg txn
  * @direction: DMA transfer dirtn
  * @flags: DMA flags
+ * @context: transfer context (ignored)
  *
  * Prepares LLI based periphral transfer
  */
 static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
 			struct dma_chan *chan, struct scatterlist *sgl,
 			unsigned int sg_len, enum dma_transfer_direction direction,
-			unsigned long flags)
+			unsigned long flags, void *context)
 {
 	struct intel_mid_dma_chan *midc = NULL;
 	struct intel_mid_dma_slave *mids = NULL;
@@ -832,7 +815,6 @@
 		/*trying to free ch in use!!!!!*/
 		pr_err("ERR_MDMA: trying to free ch in use\n");
 	}
-	pm_runtime_put(&mid->pdev->dev);
 	spin_lock_bh(&midc->lock);
 	midc->descs_allocated = 0;
 	list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
@@ -853,6 +835,7 @@
 	/* Disable CH interrupts */
 	iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_BLOCK);
 	iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_ERR);
+	pm_runtime_put(&mid->pdev->dev);
 }
 
 /**
@@ -886,7 +869,7 @@
 		pm_runtime_put(&mid->pdev->dev);
 		return -EIO;
 	}
-	midc->completed = chan->cookie = 1;
+	dma_cookie_init(chan);
 
 	spin_lock_bh(&midc->lock);
 	while (midc->descs_allocated < DESCS_PER_CHANNEL) {
@@ -1056,7 +1039,8 @@
 	}
 	err_status &= mid->intr_mask;
 	if (err_status) {
-		iowrite32(MASK_INTR_REG(err_status), mid->dma_base + MASK_ERR);
+		iowrite32((err_status << INT_MASK_WE),
+			  mid->dma_base + MASK_ERR);
 		call_tasklet = 1;
 	}
 	if (call_tasklet)
@@ -1118,7 +1102,7 @@
 		struct intel_mid_dma_chan *midch = &dma->ch[i];
 
 		midch->chan.device = &dma->common;
-		midch->chan.cookie =  1;
+		dma_cookie_init(&midch->chan);
 		midch->ch_id = dma->chan_base + i;
 		pr_debug("MDMA:Init CH %d, ID %d\n", i, midch->ch_id);
 
diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h
index c83d35b..1bfa926 100644
--- a/drivers/dma/intel_mid_dma_regs.h
+++ b/drivers/dma/intel_mid_dma_regs.h
@@ -165,7 +165,6 @@
  * @dma_base: MMIO register space DMA engine base pointer
  * @ch_id: DMA channel id
  * @lock: channel spinlock
- * @completed: DMA cookie
  * @active_list: current active descriptors
  * @queue: current queued up descriptors
  * @free_list: current free descriptors
@@ -183,7 +182,6 @@
 	void __iomem		*dma_base;
 	int			ch_id;
 	spinlock_t		lock;
-	dma_cookie_t		completed;
 	struct list_head	active_list;
 	struct list_head	queue;
 	struct list_head	free_list;
diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
index a4d6cb0..31493d8 100644
--- a/drivers/dma/ioat/dma.c
+++ b/drivers/dma/ioat/dma.c
@@ -40,6 +40,8 @@
 #include "registers.h"
 #include "hw.h"
 
+#include "../dmaengine.h"
+
 int ioat_pending_level = 4;
 module_param(ioat_pending_level, int, 0644);
 MODULE_PARM_DESC(ioat_pending_level,
@@ -107,6 +109,7 @@
 	chan->reg_base = device->reg_base + (0x80 * (idx + 1));
 	spin_lock_init(&chan->cleanup_lock);
 	chan->common.device = dma;
+	dma_cookie_init(&chan->common);
 	list_add_tail(&chan->common.device_node, &dma->channels);
 	device->idx[idx] = chan;
 	init_timer(&chan->timer);
@@ -235,12 +238,7 @@
 
 	spin_lock_bh(&ioat->desc_lock);
 	/* cookie incr and addition to used_list must be atomic */
-	cookie = c->cookie;
-	cookie++;
-	if (cookie < 0)
-		cookie = 1;
-	c->cookie = cookie;
-	tx->cookie = cookie;
+	cookie = dma_cookie_assign(tx);
 	dev_dbg(to_dev(&ioat->base), "%s: cookie: %d\n", __func__, cookie);
 
 	/* write address into NextDescriptor field of last desc in chain */
@@ -603,8 +601,7 @@
 		 */
 		dump_desc_dbg(ioat, desc);
 		if (tx->cookie) {
-			chan->completed_cookie = tx->cookie;
-			tx->cookie = 0;
+			dma_cookie_complete(tx);
 			ioat_dma_unmap(chan, tx->flags, desc->len, desc->hw);
 			ioat->active -= desc->hw->tx_cnt;
 			if (tx->callback) {
@@ -733,13 +730,15 @@
 {
 	struct ioat_chan_common *chan = to_chan_common(c);
 	struct ioatdma_device *device = chan->device;
+	enum dma_status ret;
 
-	if (ioat_tx_status(c, cookie, txstate) == DMA_SUCCESS)
-		return DMA_SUCCESS;
+	ret = dma_cookie_status(c, cookie, txstate);
+	if (ret == DMA_SUCCESS)
+		return ret;
 
 	device->cleanup_fn((unsigned long) c);
 
-	return ioat_tx_status(c, cookie, txstate);
+	return dma_cookie_status(c, cookie, txstate);
 }
 
 static void ioat1_dma_start_null_desc(struct ioat_dma_chan *ioat)
diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h
index 5216c8a..c7888bc 100644
--- a/drivers/dma/ioat/dma.h
+++ b/drivers/dma/ioat/dma.h
@@ -90,7 +90,6 @@
 	void __iomem *reg_base;
 	unsigned long last_completion;
 	spinlock_t cleanup_lock;
-	dma_cookie_t completed_cookie;
 	unsigned long state;
 	#define IOAT_COMPLETION_PENDING 0
 	#define IOAT_COMPLETION_ACK 1
@@ -143,28 +142,6 @@
 	return container_of(chan, struct ioat_dma_chan, base);
 }
 
-/**
- * ioat_tx_status - poll the status of an ioat transaction
- * @c: channel handle
- * @cookie: transaction identifier
- * @txstate: if set, updated with the transaction state
- */
-static inline enum dma_status
-ioat_tx_status(struct dma_chan *c, dma_cookie_t cookie,
-		 struct dma_tx_state *txstate)
-{
-	struct ioat_chan_common *chan = to_chan_common(c);
-	dma_cookie_t last_used;
-	dma_cookie_t last_complete;
-
-	last_used = c->cookie;
-	last_complete = chan->completed_cookie;
-
-	dma_set_tx_state(txstate, last_complete, last_used, 0);
-
-	return dma_async_is_complete(cookie, last_complete, last_used);
-}
-
 /* wrapper around hardware descriptor format + additional software fields */
 
 /**
diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c
index 5d65f83..e8e110f 100644
--- a/drivers/dma/ioat/dma_v2.c
+++ b/drivers/dma/ioat/dma_v2.c
@@ -41,6 +41,8 @@
 #include "registers.h"
 #include "hw.h"
 
+#include "../dmaengine.h"
+
 int ioat_ring_alloc_order = 8;
 module_param(ioat_ring_alloc_order, int, 0644);
 MODULE_PARM_DESC(ioat_ring_alloc_order,
@@ -147,8 +149,7 @@
 		dump_desc_dbg(ioat, desc);
 		if (tx->cookie) {
 			ioat_dma_unmap(chan, tx->flags, desc->len, desc->hw);
-			chan->completed_cookie = tx->cookie;
-			tx->cookie = 0;
+			dma_cookie_complete(tx);
 			if (tx->callback) {
 				tx->callback(tx->callback_param);
 				tx->callback = NULL;
@@ -398,13 +399,9 @@
 	struct dma_chan *c = tx->chan;
 	struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
 	struct ioat_chan_common *chan = &ioat->base;
-	dma_cookie_t cookie = c->cookie;
+	dma_cookie_t cookie;
 
-	cookie++;
-	if (cookie < 0)
-		cookie = 1;
-	tx->cookie = cookie;
-	c->cookie = cookie;
+	cookie = dma_cookie_assign(tx);
 	dev_dbg(to_dev(&ioat->base), "%s: cookie: %d\n", __func__, cookie);
 
 	if (!test_and_set_bit(IOAT_COMPLETION_PENDING, &chan->state))
diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c
index f519c93..2c4476c 100644
--- a/drivers/dma/ioat/dma_v3.c
+++ b/drivers/dma/ioat/dma_v3.c
@@ -61,6 +61,7 @@
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
 #include <linux/prefetch.h>
+#include "../dmaengine.h"
 #include "registers.h"
 #include "hw.h"
 #include "dma.h"
@@ -277,9 +278,8 @@
 		dump_desc_dbg(ioat, desc);
 		tx = &desc->txd;
 		if (tx->cookie) {
-			chan->completed_cookie = tx->cookie;
+			dma_cookie_complete(tx);
 			ioat3_dma_unmap(ioat, desc, idx + i);
-			tx->cookie = 0;
 			if (tx->callback) {
 				tx->callback(tx->callback_param);
 				tx->callback = NULL;
@@ -411,13 +411,15 @@
 		struct dma_tx_state *txstate)
 {
 	struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
+	enum dma_status ret;
 
-	if (ioat_tx_status(c, cookie, txstate) == DMA_SUCCESS)
-		return DMA_SUCCESS;
+	ret = dma_cookie_status(c, cookie, txstate);
+	if (ret == DMA_SUCCESS)
+		return ret;
 
 	ioat3_cleanup(ioat);
 
-	return ioat_tx_status(c, cookie, txstate);
+	return dma_cookie_status(c, cookie, txstate);
 }
 
 static struct dma_async_tx_descriptor *
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c
index faf88b7..da6c4c2 100644
--- a/drivers/dma/iop-adma.c
+++ b/drivers/dma/iop-adma.c
@@ -36,6 +36,8 @@
 
 #include <mach/adma.h>
 
+#include "dmaengine.h"
+
 #define to_iop_adma_chan(chan) container_of(chan, struct iop_adma_chan, common)
 #define to_iop_adma_device(dev) \
 	container_of(dev, struct iop_adma_device, common)
@@ -317,7 +319,7 @@
 	}
 
 	if (cookie > 0) {
-		iop_chan->completed_cookie = cookie;
+		iop_chan->common.completed_cookie = cookie;
 		pr_debug("\tcompleted cookie %d\n", cookie);
 	}
 }
@@ -438,18 +440,6 @@
 	return NULL;
 }
 
-static dma_cookie_t
-iop_desc_assign_cookie(struct iop_adma_chan *iop_chan,
-	struct iop_adma_desc_slot *desc)
-{
-	dma_cookie_t cookie = iop_chan->common.cookie;
-	cookie++;
-	if (cookie < 0)
-		cookie = 1;
-	iop_chan->common.cookie = desc->async_tx.cookie = cookie;
-	return cookie;
-}
-
 static void iop_adma_check_threshold(struct iop_adma_chan *iop_chan)
 {
 	dev_dbg(iop_chan->device->common.dev, "pending: %d\n",
@@ -477,7 +467,7 @@
 	slots_per_op = grp_start->slots_per_op;
 
 	spin_lock_bh(&iop_chan->lock);
-	cookie = iop_desc_assign_cookie(iop_chan, sw_desc);
+	cookie = dma_cookie_assign(tx);
 
 	old_chain_tail = list_entry(iop_chan->chain.prev,
 		struct iop_adma_desc_slot, chain_node);
@@ -904,24 +894,15 @@
 					struct dma_tx_state *txstate)
 {
 	struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
-	dma_cookie_t last_used;
-	dma_cookie_t last_complete;
-	enum dma_status ret;
+	int ret;
 
-	last_used = chan->cookie;
-	last_complete = iop_chan->completed_cookie;
-	dma_set_tx_state(txstate, last_complete, last_used, 0);
-	ret = dma_async_is_complete(cookie, last_complete, last_used);
+	ret = dma_cookie_status(chan, cookie, txstate);
 	if (ret == DMA_SUCCESS)
 		return ret;
 
 	iop_adma_slot_cleanup(iop_chan);
 
-	last_used = chan->cookie;
-	last_complete = iop_chan->completed_cookie;
-	dma_set_tx_state(txstate, last_complete, last_used, 0);
-
-	return dma_async_is_complete(cookie, last_complete, last_used);
+	return dma_cookie_status(chan, cookie, txstate);
 }
 
 static irqreturn_t iop_adma_eot_handler(int irq, void *data)
@@ -1565,6 +1546,7 @@
 	INIT_LIST_HEAD(&iop_chan->chain);
 	INIT_LIST_HEAD(&iop_chan->all_slots);
 	iop_chan->common.device = dma_dev;
+	dma_cookie_init(&iop_chan->common);
 	list_add_tail(&iop_chan->common.device_node, &dma_dev->channels);
 
 	if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) {
@@ -1642,16 +1624,12 @@
 		iop_desc_set_dest_addr(grp_start, iop_chan, 0);
 		iop_desc_set_memcpy_src_addr(grp_start, 0);
 
-		cookie = iop_chan->common.cookie;
-		cookie++;
-		if (cookie <= 1)
-			cookie = 2;
+		cookie = dma_cookie_assign(&sw_desc->async_tx);
 
 		/* initialize the completed cookie to be less than
 		 * the most recently used cookie
 		 */
-		iop_chan->completed_cookie = cookie - 1;
-		iop_chan->common.cookie = sw_desc->async_tx.cookie = cookie;
+		iop_chan->common.completed_cookie = cookie - 1;
 
 		/* channel should not be busy */
 		BUG_ON(iop_chan_is_busy(iop_chan));
@@ -1699,16 +1677,12 @@
 		iop_desc_set_xor_src_addr(grp_start, 0, 0);
 		iop_desc_set_xor_src_addr(grp_start, 1, 0);
 
-		cookie = iop_chan->common.cookie;
-		cookie++;
-		if (cookie <= 1)
-			cookie = 2;
+		cookie = dma_cookie_assign(&sw_desc->async_tx);
 
 		/* initialize the completed cookie to be less than
 		 * the most recently used cookie
 		 */
-		iop_chan->completed_cookie = cookie - 1;
-		iop_chan->common.cookie = sw_desc->async_tx.cookie = cookie;
+		iop_chan->common.completed_cookie = cookie - 1;
 
 		/* channel should not be busy */
 		BUG_ON(iop_chan_is_busy(iop_chan));
diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c
index 6212b16..62e3f8e 100644
--- a/drivers/dma/ipu/ipu_idmac.c
+++ b/drivers/dma/ipu/ipu_idmac.c
@@ -25,6 +25,7 @@
 
 #include <mach/ipu.h>
 
+#include "../dmaengine.h"
 #include "ipu_intern.h"
 
 #define FS_VF_IN_VALID	0x00000002
@@ -866,14 +867,7 @@
 
 	dev_dbg(dev, "Submitting sg %p\n", &desc->sg[0]);
 
-	cookie = ichan->dma_chan.cookie;
-
-	if (++cookie < 0)
-		cookie = 1;
-
-	/* from dmaengine.h: "last cookie value returned to client" */
-	ichan->dma_chan.cookie = cookie;
-	tx->cookie = cookie;
+	cookie = dma_cookie_assign(tx);
 
 	/* ipu->lock can be taken under ichan->lock, but not v.v. */
 	spin_lock_irqsave(&ichan->lock, flags);
@@ -1295,7 +1289,7 @@
 	/* Flip the active buffer - even if update above failed */
 	ichan->active_buffer = !ichan->active_buffer;
 	if (done)
-		ichan->completed = desc->txd.cookie;
+		dma_cookie_complete(&desc->txd);
 
 	callback = desc->txd.callback;
 	callback_param = desc->txd.callback_param;
@@ -1341,7 +1335,8 @@
 /* Allocate and initialise a transfer descriptor. */
 static struct dma_async_tx_descriptor *idmac_prep_slave_sg(struct dma_chan *chan,
 		struct scatterlist *sgl, unsigned int sg_len,
-		enum dma_transfer_direction direction, unsigned long tx_flags)
+		enum dma_transfer_direction direction, unsigned long tx_flags,
+		void *context)
 {
 	struct idmac_channel *ichan = to_idmac_chan(chan);
 	struct idmac_tx_desc *desc = NULL;
@@ -1510,8 +1505,7 @@
 	BUG_ON(chan->client_count > 1);
 	WARN_ON(ichan->status != IPU_CHANNEL_FREE);
 
-	chan->cookie		= 1;
-	ichan->completed	= -ENXIO;
+	dma_cookie_init(chan);
 
 	ret = ipu_irq_map(chan->chan_id);
 	if (ret < 0)
@@ -1600,9 +1594,7 @@
 static enum dma_status idmac_tx_status(struct dma_chan *chan,
 		       dma_cookie_t cookie, struct dma_tx_state *txstate)
 {
-	struct idmac_channel *ichan = to_idmac_chan(chan);
-
-	dma_set_tx_state(txstate, ichan->completed, chan->cookie, 0);
+	dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie, 0);
 	if (cookie != chan->cookie)
 		return DMA_ERROR;
 	return DMA_SUCCESS;
@@ -1638,11 +1630,10 @@
 
 		ichan->status		= IPU_CHANNEL_FREE;
 		ichan->sec_chan_en	= false;
-		ichan->completed	= -ENXIO;
 		snprintf(ichan->eof_name, sizeof(ichan->eof_name), "IDMAC EOF %d", i);
 
 		dma_chan->device	= &idmac->dma;
-		dma_chan->cookie	= 1;
+		dma_cookie_init(dma_chan);
 		dma_chan->chan_id	= i;
 		list_add_tail(&dma_chan->device_node, &dma->channels);
 	}
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 4d6d4cf..2ab0a3d 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -44,6 +44,8 @@
 
 #include <linux/random.h>
 
+#include "dmaengine.h"
+
 /* Number of DMA Transfer descriptors allocated per channel */
 #define MPC_DMA_DESCRIPTORS	64
 
@@ -188,7 +190,6 @@
 	struct list_head		completed;
 	struct mpc_dma_tcd		*tcd;
 	dma_addr_t			tcd_paddr;
-	dma_cookie_t			completed_cookie;
 
 	/* Lock for this structure */
 	spinlock_t			lock;
@@ -365,7 +366,7 @@
 		/* Free descriptors */
 		spin_lock_irqsave(&mchan->lock, flags);
 		list_splice_tail_init(&list, &mchan->free);
-		mchan->completed_cookie = last_cookie;
+		mchan->chan.completed_cookie = last_cookie;
 		spin_unlock_irqrestore(&mchan->lock, flags);
 	}
 }
@@ -438,13 +439,7 @@
 		mpc_dma_execute(mchan);
 
 	/* Update cookie */
-	cookie = mchan->chan.cookie + 1;
-	if (cookie <= 0)
-		cookie = 1;
-
-	mchan->chan.cookie = cookie;
-	mdesc->desc.cookie = cookie;
-
+	cookie = dma_cookie_assign(txd);
 	spin_unlock_irqrestore(&mchan->lock, flags);
 
 	return cookie;
@@ -562,17 +557,14 @@
 	       struct dma_tx_state *txstate)
 {
 	struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+	enum dma_status ret;
 	unsigned long flags;
-	dma_cookie_t last_used;
-	dma_cookie_t last_complete;
 
 	spin_lock_irqsave(&mchan->lock, flags);
-	last_used = mchan->chan.cookie;
-	last_complete = mchan->completed_cookie;
+	ret = dma_cookie_status(chan, cookie, txstate);
 	spin_unlock_irqrestore(&mchan->lock, flags);
 
-	dma_set_tx_state(txstate, last_complete, last_used, 0);
-	return dma_async_is_complete(cookie, last_complete, last_used);
+	return ret;
 }
 
 /* Prepare descriptor for memory to memory copy */
@@ -741,8 +733,7 @@
 		mchan = &mdma->channels[i];
 
 		mchan->chan.device = dma;
-		mchan->chan.cookie = 1;
-		mchan->completed_cookie = mchan->chan.cookie;
+		dma_cookie_init(&mchan->chan);
 
 		INIT_LIST_HEAD(&mchan->free);
 		INIT_LIST_HEAD(&mchan->prepared);
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index e779b43..fa5d55f 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -26,6 +26,8 @@
 #include <linux/platform_device.h>
 #include <linux/memory.h>
 #include <plat/mv_xor.h>
+
+#include "dmaengine.h"
 #include "mv_xor.h"
 
 static void mv_xor_issue_pending(struct dma_chan *chan);
@@ -435,7 +437,7 @@
 	}
 
 	if (cookie > 0)
-		mv_chan->completed_cookie = cookie;
+		mv_chan->common.completed_cookie = cookie;
 }
 
 static void
@@ -534,18 +536,6 @@
 	return NULL;
 }
 
-static dma_cookie_t
-mv_desc_assign_cookie(struct mv_xor_chan *mv_chan,
-		      struct mv_xor_desc_slot *desc)
-{
-	dma_cookie_t cookie = mv_chan->common.cookie;
-
-	if (++cookie < 0)
-		cookie = 1;
-	mv_chan->common.cookie = desc->async_tx.cookie = cookie;
-	return cookie;
-}
-
 /************************ DMA engine API functions ****************************/
 static dma_cookie_t
 mv_xor_tx_submit(struct dma_async_tx_descriptor *tx)
@@ -563,7 +553,7 @@
 	grp_start = sw_desc->group_head;
 
 	spin_lock_bh(&mv_chan->lock);
-	cookie = mv_desc_assign_cookie(mv_chan, sw_desc);
+	cookie = dma_cookie_assign(tx);
 
 	if (list_empty(&mv_chan->chain))
 		list_splice_init(&sw_desc->tx_list, &mv_chan->chain);
@@ -820,27 +810,16 @@
 					  struct dma_tx_state *txstate)
 {
 	struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan);
-	dma_cookie_t last_used;
-	dma_cookie_t last_complete;
 	enum dma_status ret;
 
-	last_used = chan->cookie;
-	last_complete = mv_chan->completed_cookie;
-	mv_chan->is_complete_cookie = cookie;
-	dma_set_tx_state(txstate, last_complete, last_used, 0);
-
-	ret = dma_async_is_complete(cookie, last_complete, last_used);
+	ret = dma_cookie_status(chan, cookie, txstate);
 	if (ret == DMA_SUCCESS) {
 		mv_xor_clean_completed_slots(mv_chan);
 		return ret;
 	}
 	mv_xor_slot_cleanup(mv_chan);
 
-	last_used = chan->cookie;
-	last_complete = mv_chan->completed_cookie;
-
-	dma_set_tx_state(txstate, last_complete, last_used, 0);
-	return dma_async_is_complete(cookie, last_complete, last_used);
+	return dma_cookie_status(chan, cookie, txstate);
 }
 
 static void mv_dump_xor_regs(struct mv_xor_chan *chan)
@@ -1214,6 +1193,7 @@
 	INIT_LIST_HEAD(&mv_chan->completed_slots);
 	INIT_LIST_HEAD(&mv_chan->all_slots);
 	mv_chan->common.device = dma_dev;
+	dma_cookie_init(&mv_chan->common);
 
 	list_add_tail(&mv_chan->common.device_node, &dma_dev->channels);
 
diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h
index 977b592..654876b 100644
--- a/drivers/dma/mv_xor.h
+++ b/drivers/dma/mv_xor.h
@@ -78,7 +78,6 @@
 /**
  * struct mv_xor_chan - internal representation of a XOR channel
  * @pending: allows batching of hardware operations
- * @completed_cookie: identifier for the most recently completed operation
  * @lock: serializes enqueue/dequeue operations to the descriptors pool
  * @mmr_base: memory mapped register base
  * @idx: the index of the xor channel
@@ -93,7 +92,6 @@
  */
 struct mv_xor_chan {
 	int			pending;
-	dma_cookie_t		completed_cookie;
 	spinlock_t		lock; /* protects the descriptor slot pool */
 	void __iomem		*mmr_base;
 	unsigned int		idx;
@@ -109,7 +107,6 @@
 #ifdef USE_TIMER
 	unsigned long		cleanup_time;
 	u32			current_on_last_cleanup;
-	dma_cookie_t		is_complete_cookie;
 #endif
 };
 
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index b06cd4c..c81ef7e 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -22,12 +22,14 @@
 #include <linux/platform_device.h>
 #include <linux/dmaengine.h>
 #include <linux/delay.h>
+#include <linux/fsl/mxs-dma.h>
 
 #include <asm/irq.h>
 #include <mach/mxs.h>
-#include <mach/dma.h>
 #include <mach/common.h>
 
+#include "dmaengine.h"
+
 /*
  * NOTE: The term "PIO" throughout the mxs-dma implementation means
  * PIO mode of mxs apbh-dma and apbx-dma.  With this working mode,
@@ -111,7 +113,6 @@
 	struct mxs_dma_ccw		*ccw;
 	dma_addr_t			ccw_phys;
 	int				desc_count;
-	dma_cookie_t			last_completed;
 	enum dma_status			status;
 	unsigned int			flags;
 #define MXS_DMA_SG_LOOP			(1 << 0)
@@ -193,19 +194,6 @@
 	mxs_chan->status = DMA_IN_PROGRESS;
 }
 
-static dma_cookie_t mxs_dma_assign_cookie(struct mxs_dma_chan *mxs_chan)
-{
-	dma_cookie_t cookie = mxs_chan->chan.cookie;
-
-	if (++cookie < 0)
-		cookie = 1;
-
-	mxs_chan->chan.cookie = cookie;
-	mxs_chan->desc.cookie = cookie;
-
-	return cookie;
-}
-
 static struct mxs_dma_chan *to_mxs_dma_chan(struct dma_chan *chan)
 {
 	return container_of(chan, struct mxs_dma_chan, chan);
@@ -217,7 +205,7 @@
 
 	mxs_dma_enable_chan(mxs_chan);
 
-	return mxs_dma_assign_cookie(mxs_chan);
+	return dma_cookie_assign(tx);
 }
 
 static void mxs_dma_tasklet(unsigned long data)
@@ -274,7 +262,7 @@
 		stat1 &= ~(1 << channel);
 
 		if (mxs_chan->status == DMA_SUCCESS)
-			mxs_chan->last_completed = mxs_chan->desc.cookie;
+			dma_cookie_complete(&mxs_chan->desc);
 
 		/* schedule tasklet on this channel */
 		tasklet_schedule(&mxs_chan->tasklet);
@@ -349,10 +337,32 @@
 	clk_disable_unprepare(mxs_dma->clk);
 }
 
+/*
+ * How to use the flags for ->device_prep_slave_sg() :
+ *    [1] If there is only one DMA command in the DMA chain, the code should be:
+ *            ......
+ *            ->device_prep_slave_sg(DMA_CTRL_ACK);
+ *            ......
+ *    [2] If there are two DMA commands in the DMA chain, the code should be
+ *            ......
+ *            ->device_prep_slave_sg(0);
+ *            ......
+ *            ->device_prep_slave_sg(DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ *            ......
+ *    [3] If there are more than two DMA commands in the DMA chain, the code
+ *        should be:
+ *            ......
+ *            ->device_prep_slave_sg(0);                                // First
+ *            ......
+ *            ->device_prep_slave_sg(DMA_PREP_INTERRUPT [| DMA_CTRL_ACK]);
+ *            ......
+ *            ->device_prep_slave_sg(DMA_PREP_INTERRUPT | DMA_CTRL_ACK); // Last
+ *            ......
+ */
 static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
 		struct dma_chan *chan, struct scatterlist *sgl,
 		unsigned int sg_len, enum dma_transfer_direction direction,
-		unsigned long append)
+		unsigned long flags, void *context)
 {
 	struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
 	struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
@@ -360,6 +370,7 @@
 	struct scatterlist *sg;
 	int i, j;
 	u32 *pio;
+	bool append = flags & DMA_PREP_INTERRUPT;
 	int idx = append ? mxs_chan->desc_count : 0;
 
 	if (mxs_chan->status == DMA_IN_PROGRESS && !append)
@@ -386,7 +397,6 @@
 		ccw->bits |= CCW_CHAIN;
 		ccw->bits &= ~CCW_IRQ;
 		ccw->bits &= ~CCW_DEC_SEM;
-		ccw->bits &= ~CCW_WAIT4END;
 	} else {
 		idx = 0;
 	}
@@ -401,7 +411,8 @@
 		ccw->bits = 0;
 		ccw->bits |= CCW_IRQ;
 		ccw->bits |= CCW_DEC_SEM;
-		ccw->bits |= CCW_WAIT4END;
+		if (flags & DMA_CTRL_ACK)
+			ccw->bits |= CCW_WAIT4END;
 		ccw->bits |= CCW_HALT_ON_TERM;
 		ccw->bits |= CCW_TERM_FLUSH;
 		ccw->bits |= BF_CCW(sg_len, PIO_NUM);
@@ -432,7 +443,8 @@
 				ccw->bits &= ~CCW_CHAIN;
 				ccw->bits |= CCW_IRQ;
 				ccw->bits |= CCW_DEC_SEM;
-				ccw->bits |= CCW_WAIT4END;
+				if (flags & DMA_CTRL_ACK)
+					ccw->bits |= CCW_WAIT4END;
 			}
 		}
 	}
@@ -447,7 +459,8 @@
 
 static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic(
 		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
-		size_t period_len, enum dma_transfer_direction direction)
+		size_t period_len, enum dma_transfer_direction direction,
+		void *context)
 {
 	struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
 	struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
@@ -538,7 +551,7 @@
 	dma_cookie_t last_used;
 
 	last_used = chan->cookie;
-	dma_set_tx_state(txstate, mxs_chan->last_completed, last_used, 0);
+	dma_set_tx_state(txstate, chan->completed_cookie, last_used, 0);
 
 	return mxs_chan->status;
 }
@@ -630,6 +643,7 @@
 
 		mxs_chan->mxs_dma = mxs_dma;
 		mxs_chan->chan.device = &mxs_dma->dma_device;
+		dma_cookie_init(&mxs_chan->chan);
 
 		tasklet_init(&mxs_chan->tasklet, mxs_dma_tasklet,
 			     (unsigned long) mxs_chan);
diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c
index 823f581..65c0495 100644
--- a/drivers/dma/pch_dma.c
+++ b/drivers/dma/pch_dma.c
@@ -25,6 +25,8 @@
 #include <linux/module.h>
 #include <linux/pch_dma.h>
 
+#include "dmaengine.h"
+
 #define DRV_NAME "pch-dma"
 
 #define DMA_CTL0_DISABLE		0x0
@@ -105,7 +107,6 @@
 
 	spinlock_t		lock;
 
-	dma_cookie_t		completed_cookie;
 	struct list_head	active_list;
 	struct list_head	queue;
 	struct list_head	free_list;
@@ -416,20 +417,6 @@
 	}
 }
 
-static dma_cookie_t pdc_assign_cookie(struct pch_dma_chan *pd_chan,
-				      struct pch_dma_desc *desc)
-{
-	dma_cookie_t cookie = pd_chan->chan.cookie;
-
-	if (++cookie < 0)
-		cookie = 1;
-
-	pd_chan->chan.cookie = cookie;
-	desc->txd.cookie = cookie;
-
-	return cookie;
-}
-
 static dma_cookie_t pd_tx_submit(struct dma_async_tx_descriptor *txd)
 {
 	struct pch_dma_desc *desc = to_pd_desc(txd);
@@ -437,7 +424,7 @@
 	dma_cookie_t cookie;
 
 	spin_lock(&pd_chan->lock);
-	cookie = pdc_assign_cookie(pd_chan, desc);
+	cookie = dma_cookie_assign(txd);
 
 	if (list_empty(&pd_chan->active_list)) {
 		list_add_tail(&desc->desc_node, &pd_chan->active_list);
@@ -544,7 +531,7 @@
 	spin_lock_irq(&pd_chan->lock);
 	list_splice(&tmp_list, &pd_chan->free_list);
 	pd_chan->descs_allocated = i;
-	pd_chan->completed_cookie = chan->cookie = 1;
+	dma_cookie_init(chan);
 	spin_unlock_irq(&pd_chan->lock);
 
 	pdc_enable_irq(chan, 1);
@@ -578,19 +565,12 @@
 				    struct dma_tx_state *txstate)
 {
 	struct pch_dma_chan *pd_chan = to_pd_chan(chan);
-	dma_cookie_t last_used;
-	dma_cookie_t last_completed;
-	int ret;
+	enum dma_status ret;
 
 	spin_lock_irq(&pd_chan->lock);
-	last_completed = pd_chan->completed_cookie;
-	last_used = chan->cookie;
+	ret = dma_cookie_status(chan, cookie, txstate);
 	spin_unlock_irq(&pd_chan->lock);
 
-	ret = dma_async_is_complete(cookie, last_completed, last_used);
-
-	dma_set_tx_state(txstate, last_completed, last_used, 0);
-
 	return ret;
 }
 
@@ -607,7 +587,8 @@
 
 static struct dma_async_tx_descriptor *pd_prep_slave_sg(struct dma_chan *chan,
 			struct scatterlist *sgl, unsigned int sg_len,
-			enum dma_transfer_direction direction, unsigned long flags)
+			enum dma_transfer_direction direction, unsigned long flags,
+			void *context)
 {
 	struct pch_dma_chan *pd_chan = to_pd_chan(chan);
 	struct pch_dma_slave *pd_slave = chan->private;
@@ -932,7 +913,7 @@
 		struct pch_dma_chan *pd_chan = &pd->channels[i];
 
 		pd_chan->chan.device = &pd->dma;
-		pd_chan->chan.cookie = 1;
+		dma_cookie_init(&pd_chan->chan);
 
 		pd_chan->membase = &regs->desc[i];
 
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index b8ec03e..282caf1 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -1,4 +1,6 @@
-/* linux/drivers/dma/pl330.c
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
  *
  * Copyright (C) 2010 Samsung Electronics Co. Ltd.
  *	Jaswinder Singh <jassi.brar@samsung.com>
@@ -9,10 +11,15 @@
  * (at your option) any later version.
  */
 
+#include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
 #include <linux/interrupt.h>
 #include <linux/amba/bus.h>
@@ -21,8 +28,497 @@
 #include <linux/scatterlist.h>
 #include <linux/of.h>
 
+#include "dmaengine.h"
+#define PL330_MAX_CHAN		8
+#define PL330_MAX_IRQS		32
+#define PL330_MAX_PERI		32
+
+enum pl330_srccachectrl {
+	SCCTRL0,	/* Noncacheable and nonbufferable */
+	SCCTRL1,	/* Bufferable only */
+	SCCTRL2,	/* Cacheable, but do not allocate */
+	SCCTRL3,	/* Cacheable and bufferable, but do not allocate */
+	SINVALID1,
+	SINVALID2,
+	SCCTRL6,	/* Cacheable write-through, allocate on reads only */
+	SCCTRL7,	/* Cacheable write-back, allocate on reads only */
+};
+
+enum pl330_dstcachectrl {
+	DCCTRL0,	/* Noncacheable and nonbufferable */
+	DCCTRL1,	/* Bufferable only */
+	DCCTRL2,	/* Cacheable, but do not allocate */
+	DCCTRL3,	/* Cacheable and bufferable, but do not allocate */
+	DINVALID1,	/* AWCACHE = 0x1000 */
+	DINVALID2,
+	DCCTRL6,	/* Cacheable write-through, allocate on writes only */
+	DCCTRL7,	/* Cacheable write-back, allocate on writes only */
+};
+
+enum pl330_byteswap {
+	SWAP_NO,
+	SWAP_2,
+	SWAP_4,
+	SWAP_8,
+	SWAP_16,
+};
+
+enum pl330_reqtype {
+	MEMTOMEM,
+	MEMTODEV,
+	DEVTOMEM,
+	DEVTODEV,
+};
+
+/* Register and Bit field Definitions */
+#define DS			0x0
+#define DS_ST_STOP		0x0
+#define DS_ST_EXEC		0x1
+#define DS_ST_CMISS		0x2
+#define DS_ST_UPDTPC		0x3
+#define DS_ST_WFE		0x4
+#define DS_ST_ATBRR		0x5
+#define DS_ST_QBUSY		0x6
+#define DS_ST_WFP		0x7
+#define DS_ST_KILL		0x8
+#define DS_ST_CMPLT		0x9
+#define DS_ST_FLTCMP		0xe
+#define DS_ST_FAULT		0xf
+
+#define DPC			0x4
+#define INTEN			0x20
+#define ES			0x24
+#define INTSTATUS		0x28
+#define INTCLR			0x2c
+#define FSM			0x30
+#define FSC			0x34
+#define FTM			0x38
+
+#define _FTC			0x40
+#define FTC(n)			(_FTC + (n)*0x4)
+
+#define _CS			0x100
+#define CS(n)			(_CS + (n)*0x8)
+#define CS_CNS			(1 << 21)
+
+#define _CPC			0x104
+#define CPC(n)			(_CPC + (n)*0x8)
+
+#define _SA			0x400
+#define SA(n)			(_SA + (n)*0x20)
+
+#define _DA			0x404
+#define DA(n)			(_DA + (n)*0x20)
+
+#define _CC			0x408
+#define CC(n)			(_CC + (n)*0x20)
+
+#define CC_SRCINC		(1 << 0)
+#define CC_DSTINC		(1 << 14)
+#define CC_SRCPRI		(1 << 8)
+#define CC_DSTPRI		(1 << 22)
+#define CC_SRCNS		(1 << 9)
+#define CC_DSTNS		(1 << 23)
+#define CC_SRCIA		(1 << 10)
+#define CC_DSTIA		(1 << 24)
+#define CC_SRCBRSTLEN_SHFT	4
+#define CC_DSTBRSTLEN_SHFT	18
+#define CC_SRCBRSTSIZE_SHFT	1
+#define CC_DSTBRSTSIZE_SHFT	15
+#define CC_SRCCCTRL_SHFT	11
+#define CC_SRCCCTRL_MASK	0x7
+#define CC_DSTCCTRL_SHFT	25
+#define CC_DRCCCTRL_MASK	0x7
+#define CC_SWAP_SHFT		28
+
+#define _LC0			0x40c
+#define LC0(n)			(_LC0 + (n)*0x20)
+
+#define _LC1			0x410
+#define LC1(n)			(_LC1 + (n)*0x20)
+
+#define DBGSTATUS		0xd00
+#define DBG_BUSY		(1 << 0)
+
+#define DBGCMD			0xd04
+#define DBGINST0		0xd08
+#define DBGINST1		0xd0c
+
+#define CR0			0xe00
+#define CR1			0xe04
+#define CR2			0xe08
+#define CR3			0xe0c
+#define CR4			0xe10
+#define CRD			0xe14
+
+#define PERIPH_ID		0xfe0
+#define PERIPH_REV_SHIFT	20
+#define PERIPH_REV_MASK		0xf
+#define PERIPH_REV_R0P0		0
+#define PERIPH_REV_R1P0		1
+#define PERIPH_REV_R1P1		2
+#define PCELL_ID		0xff0
+
+#define CR0_PERIPH_REQ_SET	(1 << 0)
+#define CR0_BOOT_EN_SET		(1 << 1)
+#define CR0_BOOT_MAN_NS		(1 << 2)
+#define CR0_NUM_CHANS_SHIFT	4
+#define CR0_NUM_CHANS_MASK	0x7
+#define CR0_NUM_PERIPH_SHIFT	12
+#define CR0_NUM_PERIPH_MASK	0x1f
+#define CR0_NUM_EVENTS_SHIFT	17
+#define CR0_NUM_EVENTS_MASK	0x1f
+
+#define CR1_ICACHE_LEN_SHIFT	0
+#define CR1_ICACHE_LEN_MASK	0x7
+#define CR1_NUM_ICACHELINES_SHIFT	4
+#define CR1_NUM_ICACHELINES_MASK	0xf
+
+#define CRD_DATA_WIDTH_SHIFT	0
+#define CRD_DATA_WIDTH_MASK	0x7
+#define CRD_WR_CAP_SHIFT	4
+#define CRD_WR_CAP_MASK		0x7
+#define CRD_WR_Q_DEP_SHIFT	8
+#define CRD_WR_Q_DEP_MASK	0xf
+#define CRD_RD_CAP_SHIFT	12
+#define CRD_RD_CAP_MASK		0x7
+#define CRD_RD_Q_DEP_SHIFT	16
+#define CRD_RD_Q_DEP_MASK	0xf
+#define CRD_DATA_BUFF_SHIFT	20
+#define CRD_DATA_BUFF_MASK	0x3ff
+
+#define PART			0x330
+#define DESIGNER		0x41
+#define REVISION		0x0
+#define INTEG_CFG		0x0
+#define PERIPH_ID_VAL		((PART << 0) | (DESIGNER << 12))
+
+#define PCELL_ID_VAL		0xb105f00d
+
+#define PL330_STATE_STOPPED		(1 << 0)
+#define PL330_STATE_EXECUTING		(1 << 1)
+#define PL330_STATE_WFE			(1 << 2)
+#define PL330_STATE_FAULTING		(1 << 3)
+#define PL330_STATE_COMPLETING		(1 << 4)
+#define PL330_STATE_WFP			(1 << 5)
+#define PL330_STATE_KILLING		(1 << 6)
+#define PL330_STATE_FAULT_COMPLETING	(1 << 7)
+#define PL330_STATE_CACHEMISS		(1 << 8)
+#define PL330_STATE_UPDTPC		(1 << 9)
+#define PL330_STATE_ATBARRIER		(1 << 10)
+#define PL330_STATE_QUEUEBUSY		(1 << 11)
+#define PL330_STATE_INVALID		(1 << 15)
+
+#define PL330_STABLE_STATES (PL330_STATE_STOPPED | PL330_STATE_EXECUTING \
+				| PL330_STATE_WFE | PL330_STATE_FAULTING)
+
+#define CMD_DMAADDH		0x54
+#define CMD_DMAEND		0x00
+#define CMD_DMAFLUSHP		0x35
+#define CMD_DMAGO		0xa0
+#define CMD_DMALD		0x04
+#define CMD_DMALDP		0x25
+#define CMD_DMALP		0x20
+#define CMD_DMALPEND		0x28
+#define CMD_DMAKILL		0x01
+#define CMD_DMAMOV		0xbc
+#define CMD_DMANOP		0x18
+#define CMD_DMARMB		0x12
+#define CMD_DMASEV		0x34
+#define CMD_DMAST		0x08
+#define CMD_DMASTP		0x29
+#define CMD_DMASTZ		0x0c
+#define CMD_DMAWFE		0x36
+#define CMD_DMAWFP		0x30
+#define CMD_DMAWMB		0x13
+
+#define SZ_DMAADDH		3
+#define SZ_DMAEND		1
+#define SZ_DMAFLUSHP		2
+#define SZ_DMALD		1
+#define SZ_DMALDP		2
+#define SZ_DMALP		2
+#define SZ_DMALPEND		2
+#define SZ_DMAKILL		1
+#define SZ_DMAMOV		6
+#define SZ_DMANOP		1
+#define SZ_DMARMB		1
+#define SZ_DMASEV		2
+#define SZ_DMAST		1
+#define SZ_DMASTP		2
+#define SZ_DMASTZ		1
+#define SZ_DMAWFE		2
+#define SZ_DMAWFP		2
+#define SZ_DMAWMB		1
+#define SZ_DMAGO		6
+
+#define BRST_LEN(ccr)		((((ccr) >> CC_SRCBRSTLEN_SHFT) & 0xf) + 1)
+#define BRST_SIZE(ccr)		(1 << (((ccr) >> CC_SRCBRSTSIZE_SHFT) & 0x7))
+
+#define BYTE_TO_BURST(b, ccr)	((b) / BRST_SIZE(ccr) / BRST_LEN(ccr))
+#define BURST_TO_BYTE(c, ccr)	((c) * BRST_SIZE(ccr) * BRST_LEN(ccr))
+
+/*
+ * With 256 bytes, we can do more than 2.5MB and 5MB xfers per req
+ * at 1byte/burst for P<->M and M<->M respectively.
+ * For typical scenario, at 1word/burst, 10MB and 20MB xfers per req
+ * should be enough for P<->M and M<->M respectively.
+ */
+#define MCODE_BUFF_PER_REQ	256
+
+/* If the _pl330_req is available to the client */
+#define IS_FREE(req)	(*((u8 *)((req)->mc_cpu)) == CMD_DMAEND)
+
+/* Use this _only_ to wait on transient states */
+#define UNTIL(t, s)	while (!(_state(t) & (s))) cpu_relax();
+
+#ifdef PL330_DEBUG_MCGEN
+static unsigned cmd_line;
+#define PL330_DBGCMD_DUMP(off, x...)	do { \
+						printk("%x:", cmd_line); \
+						printk(x); \
+						cmd_line += off; \
+					} while (0)
+#define PL330_DBGMC_START(addr)		(cmd_line = addr)
+#else
+#define PL330_DBGCMD_DUMP(off, x...)	do {} while (0)
+#define PL330_DBGMC_START(addr)		do {} while (0)
+#endif
+
+/* The number of default descriptors */
+
 #define NR_DEFAULT_DESC	16
 
+/* Populated by the PL330 core driver for DMA API driver's info */
+struct pl330_config {
+	u32	periph_id;
+	u32	pcell_id;
+#define DMAC_MODE_NS	(1 << 0)
+	unsigned int	mode;
+	unsigned int	data_bus_width:10; /* In number of bits */
+	unsigned int	data_buf_dep:10;
+	unsigned int	num_chan:4;
+	unsigned int	num_peri:6;
+	u32		peri_ns;
+	unsigned int	num_events:6;
+	u32		irq_ns;
+};
+
+/* Handle to the DMAC provided to the PL330 core */
+struct pl330_info {
+	/* Owning device */
+	struct device *dev;
+	/* Size of MicroCode buffers for each channel. */
+	unsigned mcbufsz;
+	/* ioremap'ed address of PL330 registers. */
+	void __iomem	*base;
+	/* Client can freely use it. */
+	void	*client_data;
+	/* PL330 core data, Client must not touch it. */
+	void	*pl330_data;
+	/* Populated by the PL330 core driver during pl330_add */
+	struct pl330_config	pcfg;
+	/*
+	 * If the DMAC has some reset mechanism, then the
+	 * client may want to provide pointer to the method.
+	 */
+	void (*dmac_reset)(struct pl330_info *pi);
+};
+
+/**
+ * Request Configuration.
+ * The PL330 core does not modify this and uses the last
+ * working configuration if the request doesn't provide any.
+ *
+ * The Client may want to provide this info only for the
+ * first request and a request with new settings.
+ */
+struct pl330_reqcfg {
+	/* Address Incrementing */
+	unsigned dst_inc:1;
+	unsigned src_inc:1;
+
+	/*
+	 * For now, the SRC & DST protection levels
+	 * and burst size/length are assumed same.
+	 */
+	bool nonsecure;
+	bool privileged;
+	bool insnaccess;
+	unsigned brst_len:5;
+	unsigned brst_size:3; /* in power of 2 */
+
+	enum pl330_dstcachectrl dcctl;
+	enum pl330_srccachectrl scctl;
+	enum pl330_byteswap swap;
+	struct pl330_config *pcfg;
+};
+
+/*
+ * One cycle of DMAC operation.
+ * There may be more than one xfer in a request.
+ */
+struct pl330_xfer {
+	u32 src_addr;
+	u32 dst_addr;
+	/* Size to xfer */
+	u32 bytes;
+	/*
+	 * Pointer to next xfer in the list.
+	 * The last xfer in the req must point to NULL.
+	 */
+	struct pl330_xfer *next;
+};
+
+/* The xfer callbacks are made with one of these arguments. */
+enum pl330_op_err {
+	/* The all xfers in the request were success. */
+	PL330_ERR_NONE,
+	/* If req aborted due to global error. */
+	PL330_ERR_ABORT,
+	/* If req failed due to problem with Channel. */
+	PL330_ERR_FAIL,
+};
+
+/* A request defining Scatter-Gather List ending with NULL xfer. */
+struct pl330_req {
+	enum pl330_reqtype rqtype;
+	/* Index of peripheral for the xfer. */
+	unsigned peri:5;
+	/* Unique token for this xfer, set by the client. */
+	void *token;
+	/* Callback to be called after xfer. */
+	void (*xfer_cb)(void *token, enum pl330_op_err err);
+	/* If NULL, req will be done at last set parameters. */
+	struct pl330_reqcfg *cfg;
+	/* Pointer to first xfer in the request. */
+	struct pl330_xfer *x;
+};
+
+/*
+ * To know the status of the channel and DMAC, the client
+ * provides a pointer to this structure. The PL330 core
+ * fills it with current information.
+ */
+struct pl330_chanstatus {
+	/*
+	 * If the DMAC engine halted due to some error,
+	 * the client should remove-add DMAC.
+	 */
+	bool dmac_halted;
+	/*
+	 * If channel is halted due to some error,
+	 * the client should ABORT/FLUSH and START the channel.
+	 */
+	bool faulting;
+	/* Location of last load */
+	u32 src_addr;
+	/* Location of last store */
+	u32 dst_addr;
+	/*
+	 * Pointer to the currently active req, NULL if channel is
+	 * inactive, even though the requests may be present.
+	 */
+	struct pl330_req *top_req;
+	/* Pointer to req waiting second in the queue if any. */
+	struct pl330_req *wait_req;
+};
+
+enum pl330_chan_op {
+	/* Start the channel */
+	PL330_OP_START,
+	/* Abort the active xfer */
+	PL330_OP_ABORT,
+	/* Stop xfer and flush queue */
+	PL330_OP_FLUSH,
+};
+
+struct _xfer_spec {
+	u32 ccr;
+	struct pl330_req *r;
+	struct pl330_xfer *x;
+};
+
+enum dmamov_dst {
+	SAR = 0,
+	CCR,
+	DAR,
+};
+
+enum pl330_dst {
+	SRC = 0,
+	DST,
+};
+
+enum pl330_cond {
+	SINGLE,
+	BURST,
+	ALWAYS,
+};
+
+struct _pl330_req {
+	u32 mc_bus;
+	void *mc_cpu;
+	/* Number of bytes taken to setup MC for the req */
+	u32 mc_len;
+	struct pl330_req *r;
+	/* Hook to attach to DMAC's list of reqs with due callback */
+	struct list_head rqd;
+};
+
+/* ToBeDone for tasklet */
+struct _pl330_tbd {
+	bool reset_dmac;
+	bool reset_mngr;
+	u8 reset_chan;
+};
+
+/* A DMAC Thread */
+struct pl330_thread {
+	u8 id;
+	int ev;
+	/* If the channel is not yet acquired by any client */
+	bool free;
+	/* Parent DMAC */
+	struct pl330_dmac *dmac;
+	/* Only two at a time */
+	struct _pl330_req req[2];
+	/* Index of the last enqueued request */
+	unsigned lstenq;
+	/* Index of the last submitted request or -1 if the DMA is stopped */
+	int req_running;
+};
+
+enum pl330_dmac_state {
+	UNINIT,
+	INIT,
+	DYING,
+};
+
+/* A DMAC */
+struct pl330_dmac {
+	spinlock_t		lock;
+	/* Holds list of reqs with due callbacks */
+	struct list_head	req_done;
+	/* Pointer to platform specific stuff */
+	struct pl330_info	*pinfo;
+	/* Maximum possible events/irqs */
+	int			events[32];
+	/* BUS address of MicroCode buffer */
+	u32			mcode_bus;
+	/* CPU address of MicroCode buffer */
+	void			*mcode_cpu;
+	/* List of all Channel threads */
+	struct pl330_thread	*channels;
+	/* Pointer to the MANAGER thread */
+	struct pl330_thread	*manager;
+	/* To handle bad news in interrupt */
+	struct tasklet_struct	tasks;
+	struct _pl330_tbd	dmac_tbd;
+	/* State of DMAC operation */
+	enum pl330_dmac_state	state;
+};
+
 enum desc_status {
 	/* In the DMAC pool */
 	FREE,
@@ -51,9 +547,6 @@
 	/* DMA-Engine Channel */
 	struct dma_chan chan;
 
-	/* Last completed cookie */
-	dma_cookie_t completed;
-
 	/* List of to be xfered descriptors */
 	struct list_head work_list;
 
@@ -117,6 +610,1599 @@
 	struct dma_pl330_chan *pchan;
 };
 
+static inline void _callback(struct pl330_req *r, enum pl330_op_err err)
+{
+	if (r && r->xfer_cb)
+		r->xfer_cb(r->token, err);
+}
+
+static inline bool _queue_empty(struct pl330_thread *thrd)
+{
+	return (IS_FREE(&thrd->req[0]) && IS_FREE(&thrd->req[1]))
+		? true : false;
+}
+
+static inline bool _queue_full(struct pl330_thread *thrd)
+{
+	return (IS_FREE(&thrd->req[0]) || IS_FREE(&thrd->req[1]))
+		? false : true;
+}
+
+static inline bool is_manager(struct pl330_thread *thrd)
+{
+	struct pl330_dmac *pl330 = thrd->dmac;
+
+	/* MANAGER is indexed at the end */
+	if (thrd->id == pl330->pinfo->pcfg.num_chan)
+		return true;
+	else
+		return false;
+}
+
+/* If manager of the thread is in Non-Secure mode */
+static inline bool _manager_ns(struct pl330_thread *thrd)
+{
+	struct pl330_dmac *pl330 = thrd->dmac;
+
+	return (pl330->pinfo->pcfg.mode & DMAC_MODE_NS) ? true : false;
+}
+
+static inline u32 get_id(struct pl330_info *pi, u32 off)
+{
+	void __iomem *regs = pi->base;
+	u32 id = 0;
+
+	id |= (readb(regs + off + 0x0) << 0);
+	id |= (readb(regs + off + 0x4) << 8);
+	id |= (readb(regs + off + 0x8) << 16);
+	id |= (readb(regs + off + 0xc) << 24);
+
+	return id;
+}
+
+static inline u32 get_revision(u32 periph_id)
+{
+	return (periph_id >> PERIPH_REV_SHIFT) & PERIPH_REV_MASK;
+}
+
+static inline u32 _emit_ADDH(unsigned dry_run, u8 buf[],
+		enum pl330_dst da, u16 val)
+{
+	if (dry_run)
+		return SZ_DMAADDH;
+
+	buf[0] = CMD_DMAADDH;
+	buf[0] |= (da << 1);
+	*((u16 *)&buf[1]) = val;
+
+	PL330_DBGCMD_DUMP(SZ_DMAADDH, "\tDMAADDH %s %u\n",
+		da == 1 ? "DA" : "SA", val);
+
+	return SZ_DMAADDH;
+}
+
+static inline u32 _emit_END(unsigned dry_run, u8 buf[])
+{
+	if (dry_run)
+		return SZ_DMAEND;
+
+	buf[0] = CMD_DMAEND;
+
+	PL330_DBGCMD_DUMP(SZ_DMAEND, "\tDMAEND\n");
+
+	return SZ_DMAEND;
+}
+
+static inline u32 _emit_FLUSHP(unsigned dry_run, u8 buf[], u8 peri)
+{
+	if (dry_run)
+		return SZ_DMAFLUSHP;
+
+	buf[0] = CMD_DMAFLUSHP;
+
+	peri &= 0x1f;
+	peri <<= 3;
+	buf[1] = peri;
+
+	PL330_DBGCMD_DUMP(SZ_DMAFLUSHP, "\tDMAFLUSHP %u\n", peri >> 3);
+
+	return SZ_DMAFLUSHP;
+}
+
+static inline u32 _emit_LD(unsigned dry_run, u8 buf[],	enum pl330_cond cond)
+{
+	if (dry_run)
+		return SZ_DMALD;
+
+	buf[0] = CMD_DMALD;
+
+	if (cond == SINGLE)
+		buf[0] |= (0 << 1) | (1 << 0);
+	else if (cond == BURST)
+		buf[0] |= (1 << 1) | (1 << 0);
+
+	PL330_DBGCMD_DUMP(SZ_DMALD, "\tDMALD%c\n",
+		cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'));
+
+	return SZ_DMALD;
+}
+
+static inline u32 _emit_LDP(unsigned dry_run, u8 buf[],
+		enum pl330_cond cond, u8 peri)
+{
+	if (dry_run)
+		return SZ_DMALDP;
+
+	buf[0] = CMD_DMALDP;
+
+	if (cond == BURST)
+		buf[0] |= (1 << 1);
+
+	peri &= 0x1f;
+	peri <<= 3;
+	buf[1] = peri;
+
+	PL330_DBGCMD_DUMP(SZ_DMALDP, "\tDMALDP%c %u\n",
+		cond == SINGLE ? 'S' : 'B', peri >> 3);
+
+	return SZ_DMALDP;
+}
+
+static inline u32 _emit_LP(unsigned dry_run, u8 buf[],
+		unsigned loop, u8 cnt)
+{
+	if (dry_run)
+		return SZ_DMALP;
+
+	buf[0] = CMD_DMALP;
+
+	if (loop)
+		buf[0] |= (1 << 1);
+
+	cnt--; /* DMAC increments by 1 internally */
+	buf[1] = cnt;
+
+	PL330_DBGCMD_DUMP(SZ_DMALP, "\tDMALP_%c %u\n", loop ? '1' : '0', cnt);
+
+	return SZ_DMALP;
+}
+
+struct _arg_LPEND {
+	enum pl330_cond cond;
+	bool forever;
+	unsigned loop;
+	u8 bjump;
+};
+
+static inline u32 _emit_LPEND(unsigned dry_run, u8 buf[],
+		const struct _arg_LPEND *arg)
+{
+	enum pl330_cond cond = arg->cond;
+	bool forever = arg->forever;
+	unsigned loop = arg->loop;
+	u8 bjump = arg->bjump;
+
+	if (dry_run)
+		return SZ_DMALPEND;
+
+	buf[0] = CMD_DMALPEND;
+
+	if (loop)
+		buf[0] |= (1 << 2);
+
+	if (!forever)
+		buf[0] |= (1 << 4);
+
+	if (cond == SINGLE)
+		buf[0] |= (0 << 1) | (1 << 0);
+	else if (cond == BURST)
+		buf[0] |= (1 << 1) | (1 << 0);
+
+	buf[1] = bjump;
+
+	PL330_DBGCMD_DUMP(SZ_DMALPEND, "\tDMALP%s%c_%c bjmpto_%x\n",
+			forever ? "FE" : "END",
+			cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'),
+			loop ? '1' : '0',
+			bjump);
+
+	return SZ_DMALPEND;
+}
+
+static inline u32 _emit_KILL(unsigned dry_run, u8 buf[])
+{
+	if (dry_run)
+		return SZ_DMAKILL;
+
+	buf[0] = CMD_DMAKILL;
+
+	return SZ_DMAKILL;
+}
+
+static inline u32 _emit_MOV(unsigned dry_run, u8 buf[],
+		enum dmamov_dst dst, u32 val)
+{
+	if (dry_run)
+		return SZ_DMAMOV;
+
+	buf[0] = CMD_DMAMOV;
+	buf[1] = dst;
+	*((u32 *)&buf[2]) = val;
+
+	PL330_DBGCMD_DUMP(SZ_DMAMOV, "\tDMAMOV %s 0x%x\n",
+		dst == SAR ? "SAR" : (dst == DAR ? "DAR" : "CCR"), val);
+
+	return SZ_DMAMOV;
+}
+
+static inline u32 _emit_NOP(unsigned dry_run, u8 buf[])
+{
+	if (dry_run)
+		return SZ_DMANOP;
+
+	buf[0] = CMD_DMANOP;
+
+	PL330_DBGCMD_DUMP(SZ_DMANOP, "\tDMANOP\n");
+
+	return SZ_DMANOP;
+}
+
+static inline u32 _emit_RMB(unsigned dry_run, u8 buf[])
+{
+	if (dry_run)
+		return SZ_DMARMB;
+
+	buf[0] = CMD_DMARMB;
+
+	PL330_DBGCMD_DUMP(SZ_DMARMB, "\tDMARMB\n");
+
+	return SZ_DMARMB;
+}
+
+static inline u32 _emit_SEV(unsigned dry_run, u8 buf[], u8 ev)
+{
+	if (dry_run)
+		return SZ_DMASEV;
+
+	buf[0] = CMD_DMASEV;
+
+	ev &= 0x1f;
+	ev <<= 3;
+	buf[1] = ev;
+
+	PL330_DBGCMD_DUMP(SZ_DMASEV, "\tDMASEV %u\n", ev >> 3);
+
+	return SZ_DMASEV;
+}
+
+static inline u32 _emit_ST(unsigned dry_run, u8 buf[], enum pl330_cond cond)
+{
+	if (dry_run)
+		return SZ_DMAST;
+
+	buf[0] = CMD_DMAST;
+
+	if (cond == SINGLE)
+		buf[0] |= (0 << 1) | (1 << 0);
+	else if (cond == BURST)
+		buf[0] |= (1 << 1) | (1 << 0);
+
+	PL330_DBGCMD_DUMP(SZ_DMAST, "\tDMAST%c\n",
+		cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'));
+
+	return SZ_DMAST;
+}
+
+static inline u32 _emit_STP(unsigned dry_run, u8 buf[],
+		enum pl330_cond cond, u8 peri)
+{
+	if (dry_run)
+		return SZ_DMASTP;
+
+	buf[0] = CMD_DMASTP;
+
+	if (cond == BURST)
+		buf[0] |= (1 << 1);
+
+	peri &= 0x1f;
+	peri <<= 3;
+	buf[1] = peri;
+
+	PL330_DBGCMD_DUMP(SZ_DMASTP, "\tDMASTP%c %u\n",
+		cond == SINGLE ? 'S' : 'B', peri >> 3);
+
+	return SZ_DMASTP;
+}
+
+static inline u32 _emit_STZ(unsigned dry_run, u8 buf[])
+{
+	if (dry_run)
+		return SZ_DMASTZ;
+
+	buf[0] = CMD_DMASTZ;
+
+	PL330_DBGCMD_DUMP(SZ_DMASTZ, "\tDMASTZ\n");
+
+	return SZ_DMASTZ;
+}
+
+static inline u32 _emit_WFE(unsigned dry_run, u8 buf[], u8 ev,
+		unsigned invalidate)
+{
+	if (dry_run)
+		return SZ_DMAWFE;
+
+	buf[0] = CMD_DMAWFE;
+
+	ev &= 0x1f;
+	ev <<= 3;
+	buf[1] = ev;
+
+	if (invalidate)
+		buf[1] |= (1 << 1);
+
+	PL330_DBGCMD_DUMP(SZ_DMAWFE, "\tDMAWFE %u%s\n",
+		ev >> 3, invalidate ? ", I" : "");
+
+	return SZ_DMAWFE;
+}
+
+static inline u32 _emit_WFP(unsigned dry_run, u8 buf[],
+		enum pl330_cond cond, u8 peri)
+{
+	if (dry_run)
+		return SZ_DMAWFP;
+
+	buf[0] = CMD_DMAWFP;
+
+	if (cond == SINGLE)
+		buf[0] |= (0 << 1) | (0 << 0);
+	else if (cond == BURST)
+		buf[0] |= (1 << 1) | (0 << 0);
+	else
+		buf[0] |= (0 << 1) | (1 << 0);
+
+	peri &= 0x1f;
+	peri <<= 3;
+	buf[1] = peri;
+
+	PL330_DBGCMD_DUMP(SZ_DMAWFP, "\tDMAWFP%c %u\n",
+		cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'P'), peri >> 3);
+
+	return SZ_DMAWFP;
+}
+
+static inline u32 _emit_WMB(unsigned dry_run, u8 buf[])
+{
+	if (dry_run)
+		return SZ_DMAWMB;
+
+	buf[0] = CMD_DMAWMB;
+
+	PL330_DBGCMD_DUMP(SZ_DMAWMB, "\tDMAWMB\n");
+
+	return SZ_DMAWMB;
+}
+
+struct _arg_GO {
+	u8 chan;
+	u32 addr;
+	unsigned ns;
+};
+
+static inline u32 _emit_GO(unsigned dry_run, u8 buf[],
+		const struct _arg_GO *arg)
+{
+	u8 chan = arg->chan;
+	u32 addr = arg->addr;
+	unsigned ns = arg->ns;
+
+	if (dry_run)
+		return SZ_DMAGO;
+
+	buf[0] = CMD_DMAGO;
+	buf[0] |= (ns << 1);
+
+	buf[1] = chan & 0x7;
+
+	*((u32 *)&buf[2]) = addr;
+
+	return SZ_DMAGO;
+}
+
+#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
+
+/* Returns Time-Out */
+static bool _until_dmac_idle(struct pl330_thread *thrd)
+{
+	void __iomem *regs = thrd->dmac->pinfo->base;
+	unsigned long loops = msecs_to_loops(5);
+
+	do {
+		/* Until Manager is Idle */
+		if (!(readl(regs + DBGSTATUS) & DBG_BUSY))
+			break;
+
+		cpu_relax();
+	} while (--loops);
+
+	if (!loops)
+		return true;
+
+	return false;
+}
+
+static inline void _execute_DBGINSN(struct pl330_thread *thrd,
+		u8 insn[], bool as_manager)
+{
+	void __iomem *regs = thrd->dmac->pinfo->base;
+	u32 val;
+
+	val = (insn[0] << 16) | (insn[1] << 24);
+	if (!as_manager) {
+		val |= (1 << 0);
+		val |= (thrd->id << 8); /* Channel Number */
+	}
+	writel(val, regs + DBGINST0);
+
+	val = *((u32 *)&insn[2]);
+	writel(val, regs + DBGINST1);
+
+	/* If timed out due to halted state-machine */
+	if (_until_dmac_idle(thrd)) {
+		dev_err(thrd->dmac->pinfo->dev, "DMAC halted!\n");
+		return;
+	}
+
+	/* Get going */
+	writel(0, regs + DBGCMD);
+}
+
+/*
+ * Mark a _pl330_req as free.
+ * We do it by writing DMAEND as the first instruction
+ * because no valid request is going to have DMAEND as
+ * its first instruction to execute.
+ */
+static void mark_free(struct pl330_thread *thrd, int idx)
+{
+	struct _pl330_req *req = &thrd->req[idx];
+
+	_emit_END(0, req->mc_cpu);
+	req->mc_len = 0;
+
+	thrd->req_running = -1;
+}
+
+static inline u32 _state(struct pl330_thread *thrd)
+{
+	void __iomem *regs = thrd->dmac->pinfo->base;
+	u32 val;
+
+	if (is_manager(thrd))
+		val = readl(regs + DS) & 0xf;
+	else
+		val = readl(regs + CS(thrd->id)) & 0xf;
+
+	switch (val) {
+	case DS_ST_STOP:
+		return PL330_STATE_STOPPED;
+	case DS_ST_EXEC:
+		return PL330_STATE_EXECUTING;
+	case DS_ST_CMISS:
+		return PL330_STATE_CACHEMISS;
+	case DS_ST_UPDTPC:
+		return PL330_STATE_UPDTPC;
+	case DS_ST_WFE:
+		return PL330_STATE_WFE;
+	case DS_ST_FAULT:
+		return PL330_STATE_FAULTING;
+	case DS_ST_ATBRR:
+		if (is_manager(thrd))
+			return PL330_STATE_INVALID;
+		else
+			return PL330_STATE_ATBARRIER;
+	case DS_ST_QBUSY:
+		if (is_manager(thrd))
+			return PL330_STATE_INVALID;
+		else
+			return PL330_STATE_QUEUEBUSY;
+	case DS_ST_WFP:
+		if (is_manager(thrd))
+			return PL330_STATE_INVALID;
+		else
+			return PL330_STATE_WFP;
+	case DS_ST_KILL:
+		if (is_manager(thrd))
+			return PL330_STATE_INVALID;
+		else
+			return PL330_STATE_KILLING;
+	case DS_ST_CMPLT:
+		if (is_manager(thrd))
+			return PL330_STATE_INVALID;
+		else
+			return PL330_STATE_COMPLETING;
+	case DS_ST_FLTCMP:
+		if (is_manager(thrd))
+			return PL330_STATE_INVALID;
+		else
+			return PL330_STATE_FAULT_COMPLETING;
+	default:
+		return PL330_STATE_INVALID;
+	}
+}
+
+static void _stop(struct pl330_thread *thrd)
+{
+	void __iomem *regs = thrd->dmac->pinfo->base;
+	u8 insn[6] = {0, 0, 0, 0, 0, 0};
+
+	if (_state(thrd) == PL330_STATE_FAULT_COMPLETING)
+		UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING);
+
+	/* Return if nothing needs to be done */
+	if (_state(thrd) == PL330_STATE_COMPLETING
+		  || _state(thrd) == PL330_STATE_KILLING
+		  || _state(thrd) == PL330_STATE_STOPPED)
+		return;
+
+	_emit_KILL(0, insn);
+
+	/* Stop generating interrupts for SEV */
+	writel(readl(regs + INTEN) & ~(1 << thrd->ev), regs + INTEN);
+
+	_execute_DBGINSN(thrd, insn, is_manager(thrd));
+}
+
+/* Start doing req 'idx' of thread 'thrd' */
+static bool _trigger(struct pl330_thread *thrd)
+{
+	void __iomem *regs = thrd->dmac->pinfo->base;
+	struct _pl330_req *req;
+	struct pl330_req *r;
+	struct _arg_GO go;
+	unsigned ns;
+	u8 insn[6] = {0, 0, 0, 0, 0, 0};
+	int idx;
+
+	/* Return if already ACTIVE */
+	if (_state(thrd) != PL330_STATE_STOPPED)
+		return true;
+
+	idx = 1 - thrd->lstenq;
+	if (!IS_FREE(&thrd->req[idx]))
+		req = &thrd->req[idx];
+	else {
+		idx = thrd->lstenq;
+		if (!IS_FREE(&thrd->req[idx]))
+			req = &thrd->req[idx];
+		else
+			req = NULL;
+	}
+
+	/* Return if no request */
+	if (!req || !req->r)
+		return true;
+
+	r = req->r;
+
+	if (r->cfg)
+		ns = r->cfg->nonsecure ? 1 : 0;
+	else if (readl(regs + CS(thrd->id)) & CS_CNS)
+		ns = 1;
+	else
+		ns = 0;
+
+	/* See 'Abort Sources' point-4 at Page 2-25 */
+	if (_manager_ns(thrd) && !ns)
+		dev_info(thrd->dmac->pinfo->dev, "%s:%d Recipe for ABORT!\n",
+			__func__, __LINE__);
+
+	go.chan = thrd->id;
+	go.addr = req->mc_bus;
+	go.ns = ns;
+	_emit_GO(0, insn, &go);
+
+	/* Set to generate interrupts for SEV */
+	writel(readl(regs + INTEN) | (1 << thrd->ev), regs + INTEN);
+
+	/* Only manager can execute GO */
+	_execute_DBGINSN(thrd, insn, true);
+
+	thrd->req_running = idx;
+
+	return true;
+}
+
+static bool _start(struct pl330_thread *thrd)
+{
+	switch (_state(thrd)) {
+	case PL330_STATE_FAULT_COMPLETING:
+		UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING);
+
+		if (_state(thrd) == PL330_STATE_KILLING)
+			UNTIL(thrd, PL330_STATE_STOPPED)
+
+	case PL330_STATE_FAULTING:
+		_stop(thrd);
+
+	case PL330_STATE_KILLING:
+	case PL330_STATE_COMPLETING:
+		UNTIL(thrd, PL330_STATE_STOPPED)
+
+	case PL330_STATE_STOPPED:
+		return _trigger(thrd);
+
+	case PL330_STATE_WFP:
+	case PL330_STATE_QUEUEBUSY:
+	case PL330_STATE_ATBARRIER:
+	case PL330_STATE_UPDTPC:
+	case PL330_STATE_CACHEMISS:
+	case PL330_STATE_EXECUTING:
+		return true;
+
+	case PL330_STATE_WFE: /* For RESUME, nothing yet */
+	default:
+		return false;
+	}
+}
+
+static inline int _ldst_memtomem(unsigned dry_run, u8 buf[],
+		const struct _xfer_spec *pxs, int cyc)
+{
+	int off = 0;
+	struct pl330_config *pcfg = pxs->r->cfg->pcfg;
+
+	/* check lock-up free version */
+	if (get_revision(pcfg->periph_id) >= PERIPH_REV_R1P0) {
+		while (cyc--) {
+			off += _emit_LD(dry_run, &buf[off], ALWAYS);
+			off += _emit_ST(dry_run, &buf[off], ALWAYS);
+		}
+	} else {
+		while (cyc--) {
+			off += _emit_LD(dry_run, &buf[off], ALWAYS);
+			off += _emit_RMB(dry_run, &buf[off]);
+			off += _emit_ST(dry_run, &buf[off], ALWAYS);
+			off += _emit_WMB(dry_run, &buf[off]);
+		}
+	}
+
+	return off;
+}
+
+static inline int _ldst_devtomem(unsigned dry_run, u8 buf[],
+		const struct _xfer_spec *pxs, int cyc)
+{
+	int off = 0;
+
+	while (cyc--) {
+		off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->r->peri);
+		off += _emit_LDP(dry_run, &buf[off], SINGLE, pxs->r->peri);
+		off += _emit_ST(dry_run, &buf[off], ALWAYS);
+		off += _emit_FLUSHP(dry_run, &buf[off], pxs->r->peri);
+	}
+
+	return off;
+}
+
+static inline int _ldst_memtodev(unsigned dry_run, u8 buf[],
+		const struct _xfer_spec *pxs, int cyc)
+{
+	int off = 0;
+
+	while (cyc--) {
+		off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->r->peri);
+		off += _emit_LD(dry_run, &buf[off], ALWAYS);
+		off += _emit_STP(dry_run, &buf[off], SINGLE, pxs->r->peri);
+		off += _emit_FLUSHP(dry_run, &buf[off], pxs->r->peri);
+	}
+
+	return off;
+}
+
+static int _bursts(unsigned dry_run, u8 buf[],
+		const struct _xfer_spec *pxs, int cyc)
+{
+	int off = 0;
+
+	switch (pxs->r->rqtype) {
+	case MEMTODEV:
+		off += _ldst_memtodev(dry_run, &buf[off], pxs, cyc);
+		break;
+	case DEVTOMEM:
+		off += _ldst_devtomem(dry_run, &buf[off], pxs, cyc);
+		break;
+	case MEMTOMEM:
+		off += _ldst_memtomem(dry_run, &buf[off], pxs, cyc);
+		break;
+	default:
+		off += 0x40000000; /* Scare off the Client */
+		break;
+	}
+
+	return off;
+}
+
+/* Returns bytes consumed and updates bursts */
+static inline int _loop(unsigned dry_run, u8 buf[],
+		unsigned long *bursts, const struct _xfer_spec *pxs)
+{
+	int cyc, cycmax, szlp, szlpend, szbrst, off;
+	unsigned lcnt0, lcnt1, ljmp0, ljmp1;
+	struct _arg_LPEND lpend;
+
+	/* Max iterations possible in DMALP is 256 */
+	if (*bursts >= 256*256) {
+		lcnt1 = 256;
+		lcnt0 = 256;
+		cyc = *bursts / lcnt1 / lcnt0;
+	} else if (*bursts > 256) {
+		lcnt1 = 256;
+		lcnt0 = *bursts / lcnt1;
+		cyc = 1;
+	} else {
+		lcnt1 = *bursts;
+		lcnt0 = 0;
+		cyc = 1;
+	}
+
+	szlp = _emit_LP(1, buf, 0, 0);
+	szbrst = _bursts(1, buf, pxs, 1);
+
+	lpend.cond = ALWAYS;
+	lpend.forever = false;
+	lpend.loop = 0;
+	lpend.bjump = 0;
+	szlpend = _emit_LPEND(1, buf, &lpend);
+
+	if (lcnt0) {
+		szlp *= 2;
+		szlpend *= 2;
+	}
+
+	/*
+	 * Max bursts that we can unroll due to limit on the
+	 * size of backward jump that can be encoded in DMALPEND
+	 * which is 8-bits and hence 255
+	 */
+	cycmax = (255 - (szlp + szlpend)) / szbrst;
+
+	cyc = (cycmax < cyc) ? cycmax : cyc;
+
+	off = 0;
+
+	if (lcnt0) {
+		off += _emit_LP(dry_run, &buf[off], 0, lcnt0);
+		ljmp0 = off;
+	}
+
+	off += _emit_LP(dry_run, &buf[off], 1, lcnt1);
+	ljmp1 = off;
+
+	off += _bursts(dry_run, &buf[off], pxs, cyc);
+
+	lpend.cond = ALWAYS;
+	lpend.forever = false;
+	lpend.loop = 1;
+	lpend.bjump = off - ljmp1;
+	off += _emit_LPEND(dry_run, &buf[off], &lpend);
+
+	if (lcnt0) {
+		lpend.cond = ALWAYS;
+		lpend.forever = false;
+		lpend.loop = 0;
+		lpend.bjump = off - ljmp0;
+		off += _emit_LPEND(dry_run, &buf[off], &lpend);
+	}
+
+	*bursts = lcnt1 * cyc;
+	if (lcnt0)
+		*bursts *= lcnt0;
+
+	return off;
+}
+
+static inline int _setup_loops(unsigned dry_run, u8 buf[],
+		const struct _xfer_spec *pxs)
+{
+	struct pl330_xfer *x = pxs->x;
+	u32 ccr = pxs->ccr;
+	unsigned long c, bursts = BYTE_TO_BURST(x->bytes, ccr);
+	int off = 0;
+
+	while (bursts) {
+		c = bursts;
+		off += _loop(dry_run, &buf[off], &c, pxs);
+		bursts -= c;
+	}
+
+	return off;
+}
+
+static inline int _setup_xfer(unsigned dry_run, u8 buf[],
+		const struct _xfer_spec *pxs)
+{
+	struct pl330_xfer *x = pxs->x;
+	int off = 0;
+
+	/* DMAMOV SAR, x->src_addr */
+	off += _emit_MOV(dry_run, &buf[off], SAR, x->src_addr);
+	/* DMAMOV DAR, x->dst_addr */
+	off += _emit_MOV(dry_run, &buf[off], DAR, x->dst_addr);
+
+	/* Setup Loop(s) */
+	off += _setup_loops(dry_run, &buf[off], pxs);
+
+	return off;
+}
+
+/*
+ * A req is a sequence of one or more xfer units.
+ * Returns the number of bytes taken to setup the MC for the req.
+ */
+static int _setup_req(unsigned dry_run, struct pl330_thread *thrd,
+		unsigned index, struct _xfer_spec *pxs)
+{
+	struct _pl330_req *req = &thrd->req[index];
+	struct pl330_xfer *x;
+	u8 *buf = req->mc_cpu;
+	int off = 0;
+
+	PL330_DBGMC_START(req->mc_bus);
+
+	/* DMAMOV CCR, ccr */
+	off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr);
+
+	x = pxs->r->x;
+	do {
+		/* Error if xfer length is not aligned at burst size */
+		if (x->bytes % (BRST_SIZE(pxs->ccr) * BRST_LEN(pxs->ccr)))
+			return -EINVAL;
+
+		pxs->x = x;
+		off += _setup_xfer(dry_run, &buf[off], pxs);
+
+		x = x->next;
+	} while (x);
+
+	/* DMASEV peripheral/event */
+	off += _emit_SEV(dry_run, &buf[off], thrd->ev);
+	/* DMAEND */
+	off += _emit_END(dry_run, &buf[off]);
+
+	return off;
+}
+
+static inline u32 _prepare_ccr(const struct pl330_reqcfg *rqc)
+{
+	u32 ccr = 0;
+
+	if (rqc->src_inc)
+		ccr |= CC_SRCINC;
+
+	if (rqc->dst_inc)
+		ccr |= CC_DSTINC;
+
+	/* We set same protection levels for Src and DST for now */
+	if (rqc->privileged)
+		ccr |= CC_SRCPRI | CC_DSTPRI;
+	if (rqc->nonsecure)
+		ccr |= CC_SRCNS | CC_DSTNS;
+	if (rqc->insnaccess)
+		ccr |= CC_SRCIA | CC_DSTIA;
+
+	ccr |= (((rqc->brst_len - 1) & 0xf) << CC_SRCBRSTLEN_SHFT);
+	ccr |= (((rqc->brst_len - 1) & 0xf) << CC_DSTBRSTLEN_SHFT);
+
+	ccr |= (rqc->brst_size << CC_SRCBRSTSIZE_SHFT);
+	ccr |= (rqc->brst_size << CC_DSTBRSTSIZE_SHFT);
+
+	ccr |= (rqc->scctl << CC_SRCCCTRL_SHFT);
+	ccr |= (rqc->dcctl << CC_DSTCCTRL_SHFT);
+
+	ccr |= (rqc->swap << CC_SWAP_SHFT);
+
+	return ccr;
+}
+
+static inline bool _is_valid(u32 ccr)
+{
+	enum pl330_dstcachectrl dcctl;
+	enum pl330_srccachectrl scctl;
+
+	dcctl = (ccr >> CC_DSTCCTRL_SHFT) & CC_DRCCCTRL_MASK;
+	scctl = (ccr >> CC_SRCCCTRL_SHFT) & CC_SRCCCTRL_MASK;
+
+	if (dcctl == DINVALID1 || dcctl == DINVALID2
+			|| scctl == SINVALID1 || scctl == SINVALID2)
+		return false;
+	else
+		return true;
+}
+
+/*
+ * Submit a list of xfers after which the client wants notification.
+ * Client is not notified after each xfer unit, just once after all
+ * xfer units are done or some error occurs.
+ */
+static int pl330_submit_req(void *ch_id, struct pl330_req *r)
+{
+	struct pl330_thread *thrd = ch_id;
+	struct pl330_dmac *pl330;
+	struct pl330_info *pi;
+	struct _xfer_spec xs;
+	unsigned long flags;
+	void __iomem *regs;
+	unsigned idx;
+	u32 ccr;
+	int ret = 0;
+
+	/* No Req or Unacquired Channel or DMAC */
+	if (!r || !thrd || thrd->free)
+		return -EINVAL;
+
+	pl330 = thrd->dmac;
+	pi = pl330->pinfo;
+	regs = pi->base;
+
+	if (pl330->state == DYING
+		|| pl330->dmac_tbd.reset_chan & (1 << thrd->id)) {
+		dev_info(thrd->dmac->pinfo->dev, "%s:%d\n",
+			__func__, __LINE__);
+		return -EAGAIN;
+	}
+
+	/* If request for non-existing peripheral */
+	if (r->rqtype != MEMTOMEM && r->peri >= pi->pcfg.num_peri) {
+		dev_info(thrd->dmac->pinfo->dev,
+				"%s:%d Invalid peripheral(%u)!\n",
+				__func__, __LINE__, r->peri);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&pl330->lock, flags);
+
+	if (_queue_full(thrd)) {
+		ret = -EAGAIN;
+		goto xfer_exit;
+	}
+
+	/* Prefer Secure Channel */
+	if (!_manager_ns(thrd))
+		r->cfg->nonsecure = 0;
+	else
+		r->cfg->nonsecure = 1;
+
+	/* Use last settings, if not provided */
+	if (r->cfg)
+		ccr = _prepare_ccr(r->cfg);
+	else
+		ccr = readl(regs + CC(thrd->id));
+
+	/* If this req doesn't have valid xfer settings */
+	if (!_is_valid(ccr)) {
+		ret = -EINVAL;
+		dev_info(thrd->dmac->pinfo->dev, "%s:%d Invalid CCR(%x)!\n",
+			__func__, __LINE__, ccr);
+		goto xfer_exit;
+	}
+
+	idx = IS_FREE(&thrd->req[0]) ? 0 : 1;
+
+	xs.ccr = ccr;
+	xs.r = r;
+
+	/* First dry run to check if req is acceptable */
+	ret = _setup_req(1, thrd, idx, &xs);
+	if (ret < 0)
+		goto xfer_exit;
+
+	if (ret > pi->mcbufsz / 2) {
+		dev_info(thrd->dmac->pinfo->dev,
+			"%s:%d Trying increasing mcbufsz\n",
+				__func__, __LINE__);
+		ret = -ENOMEM;
+		goto xfer_exit;
+	}
+
+	/* Hook the request */
+	thrd->lstenq = idx;
+	thrd->req[idx].mc_len = _setup_req(0, thrd, idx, &xs);
+	thrd->req[idx].r = r;
+
+	ret = 0;
+
+xfer_exit:
+	spin_unlock_irqrestore(&pl330->lock, flags);
+
+	return ret;
+}
+
+static void pl330_dotask(unsigned long data)
+{
+	struct pl330_dmac *pl330 = (struct pl330_dmac *) data;
+	struct pl330_info *pi = pl330->pinfo;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&pl330->lock, flags);
+
+	/* The DMAC itself gone nuts */
+	if (pl330->dmac_tbd.reset_dmac) {
+		pl330->state = DYING;
+		/* Reset the manager too */
+		pl330->dmac_tbd.reset_mngr = true;
+		/* Clear the reset flag */
+		pl330->dmac_tbd.reset_dmac = false;
+	}
+
+	if (pl330->dmac_tbd.reset_mngr) {
+		_stop(pl330->manager);
+		/* Reset all channels */
+		pl330->dmac_tbd.reset_chan = (1 << pi->pcfg.num_chan) - 1;
+		/* Clear the reset flag */
+		pl330->dmac_tbd.reset_mngr = false;
+	}
+
+	for (i = 0; i < pi->pcfg.num_chan; i++) {
+
+		if (pl330->dmac_tbd.reset_chan & (1 << i)) {
+			struct pl330_thread *thrd = &pl330->channels[i];
+			void __iomem *regs = pi->base;
+			enum pl330_op_err err;
+
+			_stop(thrd);
+
+			if (readl(regs + FSC) & (1 << thrd->id))
+				err = PL330_ERR_FAIL;
+			else
+				err = PL330_ERR_ABORT;
+
+			spin_unlock_irqrestore(&pl330->lock, flags);
+
+			_callback(thrd->req[1 - thrd->lstenq].r, err);
+			_callback(thrd->req[thrd->lstenq].r, err);
+
+			spin_lock_irqsave(&pl330->lock, flags);
+
+			thrd->req[0].r = NULL;
+			thrd->req[1].r = NULL;
+			mark_free(thrd, 0);
+			mark_free(thrd, 1);
+
+			/* Clear the reset flag */
+			pl330->dmac_tbd.reset_chan &= ~(1 << i);
+		}
+	}
+
+	spin_unlock_irqrestore(&pl330->lock, flags);
+
+	return;
+}
+
+/* Returns 1 if state was updated, 0 otherwise */
+static int pl330_update(const struct pl330_info *pi)
+{
+	struct _pl330_req *rqdone;
+	struct pl330_dmac *pl330;
+	unsigned long flags;
+	void __iomem *regs;
+	u32 val;
+	int id, ev, ret = 0;
+
+	if (!pi || !pi->pl330_data)
+		return 0;
+
+	regs = pi->base;
+	pl330 = pi->pl330_data;
+
+	spin_lock_irqsave(&pl330->lock, flags);
+
+	val = readl(regs + FSM) & 0x1;
+	if (val)
+		pl330->dmac_tbd.reset_mngr = true;
+	else
+		pl330->dmac_tbd.reset_mngr = false;
+
+	val = readl(regs + FSC) & ((1 << pi->pcfg.num_chan) - 1);
+	pl330->dmac_tbd.reset_chan |= val;
+	if (val) {
+		int i = 0;
+		while (i < pi->pcfg.num_chan) {
+			if (val & (1 << i)) {
+				dev_info(pi->dev,
+					"Reset Channel-%d\t CS-%x FTC-%x\n",
+						i, readl(regs + CS(i)),
+						readl(regs + FTC(i)));
+				_stop(&pl330->channels[i]);
+			}
+			i++;
+		}
+	}
+
+	/* Check which event happened i.e, thread notified */
+	val = readl(regs + ES);
+	if (pi->pcfg.num_events < 32
+			&& val & ~((1 << pi->pcfg.num_events) - 1)) {
+		pl330->dmac_tbd.reset_dmac = true;
+		dev_err(pi->dev, "%s:%d Unexpected!\n", __func__, __LINE__);
+		ret = 1;
+		goto updt_exit;
+	}
+
+	for (ev = 0; ev < pi->pcfg.num_events; ev++) {
+		if (val & (1 << ev)) { /* Event occurred */
+			struct pl330_thread *thrd;
+			u32 inten = readl(regs + INTEN);
+			int active;
+
+			/* Clear the event */
+			if (inten & (1 << ev))
+				writel(1 << ev, regs + INTCLR);
+
+			ret = 1;
+
+			id = pl330->events[ev];
+
+			thrd = &pl330->channels[id];
+
+			active = thrd->req_running;
+			if (active == -1) /* Aborted */
+				continue;
+
+			rqdone = &thrd->req[active];
+			mark_free(thrd, active);
+
+			/* Get going again ASAP */
+			_start(thrd);
+
+			/* For now, just make a list of callbacks to be done */
+			list_add_tail(&rqdone->rqd, &pl330->req_done);
+		}
+	}
+
+	/* Now that we are in no hurry, do the callbacks */
+	while (!list_empty(&pl330->req_done)) {
+		struct pl330_req *r;
+
+		rqdone = container_of(pl330->req_done.next,
+					struct _pl330_req, rqd);
+
+		list_del_init(&rqdone->rqd);
+
+		/* Detach the req */
+		r = rqdone->r;
+		rqdone->r = NULL;
+
+		spin_unlock_irqrestore(&pl330->lock, flags);
+		_callback(r, PL330_ERR_NONE);
+		spin_lock_irqsave(&pl330->lock, flags);
+	}
+
+updt_exit:
+	spin_unlock_irqrestore(&pl330->lock, flags);
+
+	if (pl330->dmac_tbd.reset_dmac
+			|| pl330->dmac_tbd.reset_mngr
+			|| pl330->dmac_tbd.reset_chan) {
+		ret = 1;
+		tasklet_schedule(&pl330->tasks);
+	}
+
+	return ret;
+}
+
+static int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op)
+{
+	struct pl330_thread *thrd = ch_id;
+	struct pl330_dmac *pl330;
+	unsigned long flags;
+	int ret = 0, active;
+
+	if (!thrd || thrd->free || thrd->dmac->state == DYING)
+		return -EINVAL;
+
+	pl330 = thrd->dmac;
+	active = thrd->req_running;
+
+	spin_lock_irqsave(&pl330->lock, flags);
+
+	switch (op) {
+	case PL330_OP_FLUSH:
+		/* Make sure the channel is stopped */
+		_stop(thrd);
+
+		thrd->req[0].r = NULL;
+		thrd->req[1].r = NULL;
+		mark_free(thrd, 0);
+		mark_free(thrd, 1);
+		break;
+
+	case PL330_OP_ABORT:
+		/* Make sure the channel is stopped */
+		_stop(thrd);
+
+		/* ABORT is only for the active req */
+		if (active == -1)
+			break;
+
+		thrd->req[active].r = NULL;
+		mark_free(thrd, active);
+
+		/* Start the next */
+	case PL330_OP_START:
+		if ((active == -1) && !_start(thrd))
+			ret = -EIO;
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	spin_unlock_irqrestore(&pl330->lock, flags);
+	return ret;
+}
+
+/* Reserve an event */
+static inline int _alloc_event(struct pl330_thread *thrd)
+{
+	struct pl330_dmac *pl330 = thrd->dmac;
+	struct pl330_info *pi = pl330->pinfo;
+	int ev;
+
+	for (ev = 0; ev < pi->pcfg.num_events; ev++)
+		if (pl330->events[ev] == -1) {
+			pl330->events[ev] = thrd->id;
+			return ev;
+		}
+
+	return -1;
+}
+
+static bool _chan_ns(const struct pl330_info *pi, int i)
+{
+	return pi->pcfg.irq_ns & (1 << i);
+}
+
+/* Upon success, returns IdentityToken for the
+ * allocated channel, NULL otherwise.
+ */
+static void *pl330_request_channel(const struct pl330_info *pi)
+{
+	struct pl330_thread *thrd = NULL;
+	struct pl330_dmac *pl330;
+	unsigned long flags;
+	int chans, i;
+
+	if (!pi || !pi->pl330_data)
+		return NULL;
+
+	pl330 = pi->pl330_data;
+
+	if (pl330->state == DYING)
+		return NULL;
+
+	chans = pi->pcfg.num_chan;
+
+	spin_lock_irqsave(&pl330->lock, flags);
+
+	for (i = 0; i < chans; i++) {
+		thrd = &pl330->channels[i];
+		if ((thrd->free) && (!_manager_ns(thrd) ||
+					_chan_ns(pi, i))) {
+			thrd->ev = _alloc_event(thrd);
+			if (thrd->ev >= 0) {
+				thrd->free = false;
+				thrd->lstenq = 1;
+				thrd->req[0].r = NULL;
+				mark_free(thrd, 0);
+				thrd->req[1].r = NULL;
+				mark_free(thrd, 1);
+				break;
+			}
+		}
+		thrd = NULL;
+	}
+
+	spin_unlock_irqrestore(&pl330->lock, flags);
+
+	return thrd;
+}
+
+/* Release an event */
+static inline void _free_event(struct pl330_thread *thrd, int ev)
+{
+	struct pl330_dmac *pl330 = thrd->dmac;
+	struct pl330_info *pi = pl330->pinfo;
+
+	/* If the event is valid and was held by the thread */
+	if (ev >= 0 && ev < pi->pcfg.num_events
+			&& pl330->events[ev] == thrd->id)
+		pl330->events[ev] = -1;
+}
+
+static void pl330_release_channel(void *ch_id)
+{
+	struct pl330_thread *thrd = ch_id;
+	struct pl330_dmac *pl330;
+	unsigned long flags;
+
+	if (!thrd || thrd->free)
+		return;
+
+	_stop(thrd);
+
+	_callback(thrd->req[1 - thrd->lstenq].r, PL330_ERR_ABORT);
+	_callback(thrd->req[thrd->lstenq].r, PL330_ERR_ABORT);
+
+	pl330 = thrd->dmac;
+
+	spin_lock_irqsave(&pl330->lock, flags);
+	_free_event(thrd, thrd->ev);
+	thrd->free = true;
+	spin_unlock_irqrestore(&pl330->lock, flags);
+}
+
+/* Initialize the structure for PL330 configuration, that can be used
+ * by the client driver the make best use of the DMAC
+ */
+static void read_dmac_config(struct pl330_info *pi)
+{
+	void __iomem *regs = pi->base;
+	u32 val;
+
+	val = readl(regs + CRD) >> CRD_DATA_WIDTH_SHIFT;
+	val &= CRD_DATA_WIDTH_MASK;
+	pi->pcfg.data_bus_width = 8 * (1 << val);
+
+	val = readl(regs + CRD) >> CRD_DATA_BUFF_SHIFT;
+	val &= CRD_DATA_BUFF_MASK;
+	pi->pcfg.data_buf_dep = val + 1;
+
+	val = readl(regs + CR0) >> CR0_NUM_CHANS_SHIFT;
+	val &= CR0_NUM_CHANS_MASK;
+	val += 1;
+	pi->pcfg.num_chan = val;
+
+	val = readl(regs + CR0);
+	if (val & CR0_PERIPH_REQ_SET) {
+		val = (val >> CR0_NUM_PERIPH_SHIFT) & CR0_NUM_PERIPH_MASK;
+		val += 1;
+		pi->pcfg.num_peri = val;
+		pi->pcfg.peri_ns = readl(regs + CR4);
+	} else {
+		pi->pcfg.num_peri = 0;
+	}
+
+	val = readl(regs + CR0);
+	if (val & CR0_BOOT_MAN_NS)
+		pi->pcfg.mode |= DMAC_MODE_NS;
+	else
+		pi->pcfg.mode &= ~DMAC_MODE_NS;
+
+	val = readl(regs + CR0) >> CR0_NUM_EVENTS_SHIFT;
+	val &= CR0_NUM_EVENTS_MASK;
+	val += 1;
+	pi->pcfg.num_events = val;
+
+	pi->pcfg.irq_ns = readl(regs + CR3);
+
+	pi->pcfg.periph_id = get_id(pi, PERIPH_ID);
+	pi->pcfg.pcell_id = get_id(pi, PCELL_ID);
+}
+
+static inline void _reset_thread(struct pl330_thread *thrd)
+{
+	struct pl330_dmac *pl330 = thrd->dmac;
+	struct pl330_info *pi = pl330->pinfo;
+
+	thrd->req[0].mc_cpu = pl330->mcode_cpu
+				+ (thrd->id * pi->mcbufsz);
+	thrd->req[0].mc_bus = pl330->mcode_bus
+				+ (thrd->id * pi->mcbufsz);
+	thrd->req[0].r = NULL;
+	mark_free(thrd, 0);
+
+	thrd->req[1].mc_cpu = thrd->req[0].mc_cpu
+				+ pi->mcbufsz / 2;
+	thrd->req[1].mc_bus = thrd->req[0].mc_bus
+				+ pi->mcbufsz / 2;
+	thrd->req[1].r = NULL;
+	mark_free(thrd, 1);
+}
+
+static int dmac_alloc_threads(struct pl330_dmac *pl330)
+{
+	struct pl330_info *pi = pl330->pinfo;
+	int chans = pi->pcfg.num_chan;
+	struct pl330_thread *thrd;
+	int i;
+
+	/* Allocate 1 Manager and 'chans' Channel threads */
+	pl330->channels = kzalloc((1 + chans) * sizeof(*thrd),
+					GFP_KERNEL);
+	if (!pl330->channels)
+		return -ENOMEM;
+
+	/* Init Channel threads */
+	for (i = 0; i < chans; i++) {
+		thrd = &pl330->channels[i];
+		thrd->id = i;
+		thrd->dmac = pl330;
+		_reset_thread(thrd);
+		thrd->free = true;
+	}
+
+	/* MANAGER is indexed at the end */
+	thrd = &pl330->channels[chans];
+	thrd->id = chans;
+	thrd->dmac = pl330;
+	thrd->free = false;
+	pl330->manager = thrd;
+
+	return 0;
+}
+
+static int dmac_alloc_resources(struct pl330_dmac *pl330)
+{
+	struct pl330_info *pi = pl330->pinfo;
+	int chans = pi->pcfg.num_chan;
+	int ret;
+
+	/*
+	 * Alloc MicroCode buffer for 'chans' Channel threads.
+	 * A channel's buffer offset is (Channel_Id * MCODE_BUFF_PERCHAN)
+	 */
+	pl330->mcode_cpu = dma_alloc_coherent(pi->dev,
+				chans * pi->mcbufsz,
+				&pl330->mcode_bus, GFP_KERNEL);
+	if (!pl330->mcode_cpu) {
+		dev_err(pi->dev, "%s:%d Can't allocate memory!\n",
+			__func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	ret = dmac_alloc_threads(pl330);
+	if (ret) {
+		dev_err(pi->dev, "%s:%d Can't to create channels for DMAC!\n",
+			__func__, __LINE__);
+		dma_free_coherent(pi->dev,
+				chans * pi->mcbufsz,
+				pl330->mcode_cpu, pl330->mcode_bus);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pl330_add(struct pl330_info *pi)
+{
+	struct pl330_dmac *pl330;
+	void __iomem *regs;
+	int i, ret;
+
+	if (!pi || !pi->dev)
+		return -EINVAL;
+
+	/* If already added */
+	if (pi->pl330_data)
+		return -EINVAL;
+
+	/*
+	 * If the SoC can perform reset on the DMAC, then do it
+	 * before reading its configuration.
+	 */
+	if (pi->dmac_reset)
+		pi->dmac_reset(pi);
+
+	regs = pi->base;
+
+	/* Check if we can handle this DMAC */
+	if ((get_id(pi, PERIPH_ID) & 0xfffff) != PERIPH_ID_VAL
+	   || get_id(pi, PCELL_ID) != PCELL_ID_VAL) {
+		dev_err(pi->dev, "PERIPH_ID 0x%x, PCELL_ID 0x%x !\n",
+			get_id(pi, PERIPH_ID), get_id(pi, PCELL_ID));
+		return -EINVAL;
+	}
+
+	/* Read the configuration of the DMAC */
+	read_dmac_config(pi);
+
+	if (pi->pcfg.num_events == 0) {
+		dev_err(pi->dev, "%s:%d Can't work without events!\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	pl330 = kzalloc(sizeof(*pl330), GFP_KERNEL);
+	if (!pl330) {
+		dev_err(pi->dev, "%s:%d Can't allocate memory!\n",
+			__func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	/* Assign the info structure and private data */
+	pl330->pinfo = pi;
+	pi->pl330_data = pl330;
+
+	spin_lock_init(&pl330->lock);
+
+	INIT_LIST_HEAD(&pl330->req_done);
+
+	/* Use default MC buffer size if not provided */
+	if (!pi->mcbufsz)
+		pi->mcbufsz = MCODE_BUFF_PER_REQ * 2;
+
+	/* Mark all events as free */
+	for (i = 0; i < pi->pcfg.num_events; i++)
+		pl330->events[i] = -1;
+
+	/* Allocate resources needed by the DMAC */
+	ret = dmac_alloc_resources(pl330);
+	if (ret) {
+		dev_err(pi->dev, "Unable to create channels for DMAC\n");
+		kfree(pl330);
+		return ret;
+	}
+
+	tasklet_init(&pl330->tasks, pl330_dotask, (unsigned long) pl330);
+
+	pl330->state = INIT;
+
+	return 0;
+}
+
+static int dmac_free_threads(struct pl330_dmac *pl330)
+{
+	struct pl330_info *pi = pl330->pinfo;
+	int chans = pi->pcfg.num_chan;
+	struct pl330_thread *thrd;
+	int i;
+
+	/* Release Channel threads */
+	for (i = 0; i < chans; i++) {
+		thrd = &pl330->channels[i];
+		pl330_release_channel((void *)thrd);
+	}
+
+	/* Free memory */
+	kfree(pl330->channels);
+
+	return 0;
+}
+
+static void dmac_free_resources(struct pl330_dmac *pl330)
+{
+	struct pl330_info *pi = pl330->pinfo;
+	int chans = pi->pcfg.num_chan;
+
+	dmac_free_threads(pl330);
+
+	dma_free_coherent(pi->dev, chans * pi->mcbufsz,
+				pl330->mcode_cpu, pl330->mcode_bus);
+}
+
+static void pl330_del(struct pl330_info *pi)
+{
+	struct pl330_dmac *pl330;
+
+	if (!pi || !pi->pl330_data)
+		return;
+
+	pl330 = pi->pl330_data;
+
+	pl330->state = UNINIT;
+
+	tasklet_kill(&pl330->tasks);
+
+	/* Free DMAC resources */
+	dmac_free_resources(pl330);
+
+	kfree(pl330);
+	pi->pl330_data = NULL;
+}
+
 /* forward declaration */
 static struct amba_driver pl330_driver;
 
@@ -234,7 +2320,7 @@
 	/* Pick up ripe tomatoes */
 	list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
 		if (desc->status == DONE) {
-			pch->completed = desc->txd.cookie;
+			dma_cookie_complete(&desc->txd);
 			list_move_tail(&desc->node, &list);
 		}
 
@@ -305,7 +2391,7 @@
 
 	spin_lock_irqsave(&pch->lock, flags);
 
-	pch->completed = chan->cookie = 1;
+	dma_cookie_init(chan);
 	pch->cyclic = false;
 
 	pch->pl330_chid = pl330_request_channel(&pdmac->pif);
@@ -340,7 +2426,6 @@
 		/* Mark all desc done */
 		list_for_each_entry_safe(desc, _dt, &pch->work_list , node) {
 			desc->status = DONE;
-			pch->completed = desc->txd.cookie;
 			list_move_tail(&desc->node, &list);
 		}
 
@@ -396,18 +2481,7 @@
 pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
 		 struct dma_tx_state *txstate)
 {
-	struct dma_pl330_chan *pch = to_pchan(chan);
-	dma_cookie_t last_done, last_used;
-	int ret;
-
-	last_done = pch->completed;
-	last_used = chan->cookie;
-
-	ret = dma_async_is_complete(cookie, last_done, last_used);
-
-	dma_set_tx_state(txstate, last_done, last_used, 0);
-
-	return ret;
+	return dma_cookie_status(chan, cookie, txstate);
 }
 
 static void pl330_issue_pending(struct dma_chan *chan)
@@ -430,26 +2504,16 @@
 	spin_lock_irqsave(&pch->lock, flags);
 
 	/* Assign cookies to all nodes */
-	cookie = tx->chan->cookie;
-
 	while (!list_empty(&last->node)) {
 		desc = list_entry(last->node.next, struct dma_pl330_desc, node);
 
-		if (++cookie < 0)
-			cookie = 1;
-		desc->txd.cookie = cookie;
+		dma_cookie_assign(&desc->txd);
 
 		list_move_tail(&desc->node, &pch->work_list);
 	}
 
-	if (++cookie < 0)
-		cookie = 1;
-	last->txd.cookie = cookie;
-
+	cookie = dma_cookie_assign(&last->txd);
 	list_add_tail(&last->node, &pch->work_list);
-
-	tx->chan->cookie = cookie;
-
 	spin_unlock_irqrestore(&pch->lock, flags);
 
 	return cookie;
@@ -553,6 +2617,7 @@
 	async_tx_ack(&desc->txd);
 
 	desc->req.peri = peri_id ? pch->chan.chan_id : 0;
+	desc->rqcfg.pcfg = &pch->dmac->pif.pcfg;
 
 	dma_async_tx_descriptor_init(&desc->txd, &pch->chan);
 
@@ -621,7 +2686,8 @@
 
 static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
 		struct dma_chan *chan, dma_addr_t dma_addr, size_t len,
-		size_t period_len, enum dma_transfer_direction direction)
+		size_t period_len, enum dma_transfer_direction direction,
+		void *context)
 {
 	struct dma_pl330_desc *desc;
 	struct dma_pl330_chan *pch = to_pchan(chan);
@@ -711,7 +2777,7 @@
 static struct dma_async_tx_descriptor *
 pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 		unsigned int sg_len, enum dma_transfer_direction direction,
-		unsigned long flg)
+		unsigned long flg, void *context)
 {
 	struct dma_pl330_desc *first, *desc = NULL;
 	struct dma_pl330_chan *pch = to_pchan(chan);
@@ -829,7 +2895,7 @@
 	if (IS_ERR(pdmac->clk)) {
 		dev_err(&adev->dev, "Cannot get operation clock.\n");
 		ret = -EINVAL;
-		goto probe_err1;
+		goto probe_err2;
 	}
 
 	amba_set_drvdata(adev, pdmac);
@@ -843,11 +2909,11 @@
 	ret = request_irq(irq, pl330_irq_handler, 0,
 			dev_name(&adev->dev), pi);
 	if (ret)
-		goto probe_err2;
+		goto probe_err3;
 
 	ret = pl330_add(pi);
 	if (ret)
-		goto probe_err3;
+		goto probe_err4;
 
 	INIT_LIST_HEAD(&pdmac->desc_pool);
 	spin_lock_init(&pdmac->pool_lock);
@@ -904,7 +2970,7 @@
 	ret = dma_async_device_register(pd);
 	if (ret) {
 		dev_err(&adev->dev, "unable to register DMAC\n");
-		goto probe_err4;
+		goto probe_err5;
 	}
 
 	dev_info(&adev->dev,
@@ -917,10 +2983,15 @@
 
 	return 0;
 
-probe_err4:
+probe_err5:
 	pl330_del(pi);
-probe_err3:
+probe_err4:
 	free_irq(irq, pi);
+probe_err3:
+#ifndef CONFIG_PM_RUNTIME
+	clk_disable(pdmac->clk);
+#endif
+	clk_put(pdmac->clk);
 probe_err2:
 	iounmap(pi->base);
 probe_err1:
@@ -1035,18 +3106,7 @@
 	.remove = pl330_remove,
 };
 
-static int __init pl330_init(void)
-{
-	return amba_driver_register(&pl330_driver);
-}
-module_init(pl330_init);
-
-static void __exit pl330_exit(void)
-{
-	amba_driver_unregister(&pl330_driver);
-	return;
-}
-module_exit(pl330_exit);
+module_amba_driver(pl330_driver);
 
 MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>");
 MODULE_DESCRIPTION("API Driver for PL330 DMAC");
diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c
index fc457a7..ced9882 100644
--- a/drivers/dma/ppc4xx/adma.c
+++ b/drivers/dma/ppc4xx/adma.c
@@ -46,6 +46,7 @@
 #include <asm/dcr.h>
 #include <asm/dcr-regs.h>
 #include "adma.h"
+#include "../dmaengine.h"
 
 enum ppc_adma_init_code {
 	PPC_ADMA_INIT_OK = 0,
@@ -1930,7 +1931,7 @@
 				if (end_of_chain && slot_cnt) {
 					/* Should wait for ZeroSum completion */
 					if (cookie > 0)
-						chan->completed_cookie = cookie;
+						chan->common.completed_cookie = cookie;
 					return;
 				}
 
@@ -1960,7 +1961,7 @@
 	BUG_ON(!seen_current);
 
 	if (cookie > 0) {
-		chan->completed_cookie = cookie;
+		chan->common.completed_cookie = cookie;
 		pr_debug("\tcompleted cookie %d\n", cookie);
 	}
 
@@ -2150,22 +2151,6 @@
 }
 
 /**
- * ppc440spe_desc_assign_cookie - assign a cookie
- */
-static dma_cookie_t ppc440spe_desc_assign_cookie(
-		struct ppc440spe_adma_chan *chan,
-		struct ppc440spe_adma_desc_slot *desc)
-{
-	dma_cookie_t cookie = chan->common.cookie;
-
-	cookie++;
-	if (cookie < 0)
-		cookie = 1;
-	chan->common.cookie = desc->async_tx.cookie = cookie;
-	return cookie;
-}
-
-/**
  * ppc440spe_rxor_set_region_data -
  */
 static void ppc440spe_rxor_set_region(struct ppc440spe_adma_desc_slot *desc,
@@ -2235,8 +2220,7 @@
 	slots_per_op = group_start->slots_per_op;
 
 	spin_lock_bh(&chan->lock);
-
-	cookie = ppc440spe_desc_assign_cookie(chan, sw_desc);
+	cookie = dma_cookie_assign(tx);
 
 	if (unlikely(list_empty(&chan->chain))) {
 		/* first peer */
@@ -3944,28 +3928,16 @@
 			dma_cookie_t cookie, struct dma_tx_state *txstate)
 {
 	struct ppc440spe_adma_chan *ppc440spe_chan;
-	dma_cookie_t last_used;
-	dma_cookie_t last_complete;
 	enum dma_status ret;
 
 	ppc440spe_chan = to_ppc440spe_adma_chan(chan);
-	last_used = chan->cookie;
-	last_complete = ppc440spe_chan->completed_cookie;
-
-	dma_set_tx_state(txstate, last_complete, last_used, 0);
-
-	ret = dma_async_is_complete(cookie, last_complete, last_used);
+	ret = dma_cookie_status(chan, cookie, txstate);
 	if (ret == DMA_SUCCESS)
 		return ret;
 
 	ppc440spe_adma_slot_cleanup(ppc440spe_chan);
 
-	last_used = chan->cookie;
-	last_complete = ppc440spe_chan->completed_cookie;
-
-	dma_set_tx_state(txstate, last_complete, last_used, 0);
-
-	return dma_async_is_complete(cookie, last_complete, last_used);
+	return dma_cookie_status(chan, cookie, txstate);
 }
 
 /**
@@ -4050,16 +4022,12 @@
 		async_tx_ack(&sw_desc->async_tx);
 		ppc440spe_desc_init_null_xor(group_start);
 
-		cookie = chan->common.cookie;
-		cookie++;
-		if (cookie <= 1)
-			cookie = 2;
+		cookie = dma_cookie_assign(&sw_desc->async_tx);
 
 		/* initialize the completed cookie to be less than
 		 * the most recently used cookie
 		 */
-		chan->completed_cookie = cookie - 1;
-		chan->common.cookie = sw_desc->async_tx.cookie = cookie;
+		chan->common.completed_cookie = cookie - 1;
 
 		/* channel should not be busy */
 		BUG_ON(ppc440spe_chan_is_busy(chan));
@@ -4529,6 +4497,7 @@
 	INIT_LIST_HEAD(&chan->all_slots);
 	chan->device = adev;
 	chan->common.device = &adev->common;
+	dma_cookie_init(&chan->common);
 	list_add_tail(&chan->common.device_node, &adev->common.channels);
 	tasklet_init(&chan->irq_tasklet, ppc440spe_adma_tasklet,
 		     (unsigned long)chan);
diff --git a/drivers/dma/ppc4xx/adma.h b/drivers/dma/ppc4xx/adma.h
index 8ada5a81..26b7a5e 100644
--- a/drivers/dma/ppc4xx/adma.h
+++ b/drivers/dma/ppc4xx/adma.h
@@ -81,7 +81,6 @@
  * @common: common dmaengine channel object members
  * @all_slots: complete domain of slots usable by the channel
  * @pending: allows batching of hardware operations
- * @completed_cookie: identifier for the most recently completed operation
  * @slots_allocated: records the actual size of the descriptor slot pool
  * @hw_chain_inited: h/w descriptor chain initialization flag
  * @irq_tasklet: bottom half where ppc440spe_adma_slot_cleanup runs
@@ -99,7 +98,6 @@
 	struct list_head all_slots;
 	struct ppc440spe_adma_desc_slot *last_used;
 	int pending;
-	dma_cookie_t completed_cookie;
 	int slots_allocated;
 	int hw_chain_inited;
 	struct tasklet_struct irq_tasklet;
diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c
new file mode 100644
index 0000000..ec78cce
--- /dev/null
+++ b/drivers/dma/sa11x0-dma.c
@@ -0,0 +1,1109 @@
+/*
+ * SA11x0 DMAengine support
+ *
+ * Copyright (C) 2012 Russell King
+ *   Derived in part from arch/arm/mach-sa1100/dma.c,
+ *   Copyright (C) 2000, 2001 by Nicolas Pitre
+ *
+ * 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/sched.h>
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sa11x0-dma.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define NR_PHY_CHAN	6
+#define DMA_ALIGN	3
+#define DMA_MAX_SIZE	0x1fff
+#define DMA_CHUNK_SIZE	0x1000
+
+#define DMA_DDAR	0x00
+#define DMA_DCSR_S	0x04
+#define DMA_DCSR_C	0x08
+#define DMA_DCSR_R	0x0c
+#define DMA_DBSA	0x10
+#define DMA_DBTA	0x14
+#define DMA_DBSB	0x18
+#define DMA_DBTB	0x1c
+#define DMA_SIZE	0x20
+
+#define DCSR_RUN	(1 << 0)
+#define DCSR_IE		(1 << 1)
+#define DCSR_ERROR	(1 << 2)
+#define DCSR_DONEA	(1 << 3)
+#define DCSR_STRTA	(1 << 4)
+#define DCSR_DONEB	(1 << 5)
+#define DCSR_STRTB	(1 << 6)
+#define DCSR_BIU	(1 << 7)
+
+#define DDAR_RW		(1 << 0)	/* 0 = W, 1 = R */
+#define DDAR_E		(1 << 1)	/* 0 = LE, 1 = BE */
+#define DDAR_BS		(1 << 2)	/* 0 = BS4, 1 = BS8 */
+#define DDAR_DW		(1 << 3)	/* 0 = 8b, 1 = 16b */
+#define DDAR_Ser0UDCTr	(0x0 << 4)
+#define DDAR_Ser0UDCRc	(0x1 << 4)
+#define DDAR_Ser1SDLCTr	(0x2 << 4)
+#define DDAR_Ser1SDLCRc	(0x3 << 4)
+#define DDAR_Ser1UARTTr	(0x4 << 4)
+#define DDAR_Ser1UARTRc	(0x5 << 4)
+#define DDAR_Ser2ICPTr	(0x6 << 4)
+#define DDAR_Ser2ICPRc	(0x7 << 4)
+#define DDAR_Ser3UARTTr	(0x8 << 4)
+#define DDAR_Ser3UARTRc	(0x9 << 4)
+#define DDAR_Ser4MCP0Tr	(0xa << 4)
+#define DDAR_Ser4MCP0Rc	(0xb << 4)
+#define DDAR_Ser4MCP1Tr	(0xc << 4)
+#define DDAR_Ser4MCP1Rc	(0xd << 4)
+#define DDAR_Ser4SSPTr	(0xe << 4)
+#define DDAR_Ser4SSPRc	(0xf << 4)
+
+struct sa11x0_dma_sg {
+	u32			addr;
+	u32			len;
+};
+
+struct sa11x0_dma_desc {
+	struct dma_async_tx_descriptor tx;
+	u32			ddar;
+	size_t			size;
+
+	/* maybe protected by c->lock */
+	struct list_head	node;
+	unsigned		sglen;
+	struct sa11x0_dma_sg	sg[0];
+};
+
+struct sa11x0_dma_phy;
+
+struct sa11x0_dma_chan {
+	struct dma_chan		chan;
+	spinlock_t		lock;
+	dma_cookie_t		lc;
+
+	/* protected by c->lock */
+	struct sa11x0_dma_phy	*phy;
+	enum dma_status		status;
+	struct list_head	desc_submitted;
+	struct list_head	desc_issued;
+
+	/* protected by d->lock */
+	struct list_head	node;
+
+	u32			ddar;
+	const char		*name;
+};
+
+struct sa11x0_dma_phy {
+	void __iomem		*base;
+	struct sa11x0_dma_dev	*dev;
+	unsigned		num;
+
+	struct sa11x0_dma_chan	*vchan;
+
+	/* Protected by c->lock */
+	unsigned		sg_load;
+	struct sa11x0_dma_desc	*txd_load;
+	unsigned		sg_done;
+	struct sa11x0_dma_desc	*txd_done;
+#ifdef CONFIG_PM_SLEEP
+	u32			dbs[2];
+	u32			dbt[2];
+	u32			dcsr;
+#endif
+};
+
+struct sa11x0_dma_dev {
+	struct dma_device	slave;
+	void __iomem		*base;
+	spinlock_t		lock;
+	struct tasklet_struct	task;
+	struct list_head	chan_pending;
+	struct list_head	desc_complete;
+	struct sa11x0_dma_phy	phy[NR_PHY_CHAN];
+};
+
+static struct sa11x0_dma_chan *to_sa11x0_dma_chan(struct dma_chan *chan)
+{
+	return container_of(chan, struct sa11x0_dma_chan, chan);
+}
+
+static struct sa11x0_dma_dev *to_sa11x0_dma(struct dma_device *dmadev)
+{
+	return container_of(dmadev, struct sa11x0_dma_dev, slave);
+}
+
+static struct sa11x0_dma_desc *to_sa11x0_dma_tx(struct dma_async_tx_descriptor *tx)
+{
+	return container_of(tx, struct sa11x0_dma_desc, tx);
+}
+
+static struct sa11x0_dma_desc *sa11x0_dma_next_desc(struct sa11x0_dma_chan *c)
+{
+	if (list_empty(&c->desc_issued))
+		return NULL;
+
+	return list_first_entry(&c->desc_issued, struct sa11x0_dma_desc, node);
+}
+
+static void sa11x0_dma_start_desc(struct sa11x0_dma_phy *p, struct sa11x0_dma_desc *txd)
+{
+	list_del(&txd->node);
+	p->txd_load = txd;
+	p->sg_load = 0;
+
+	dev_vdbg(p->dev->slave.dev, "pchan %u: txd %p[%x]: starting: DDAR:%x\n",
+		p->num, txd, txd->tx.cookie, txd->ddar);
+}
+
+static void noinline sa11x0_dma_start_sg(struct sa11x0_dma_phy *p,
+	struct sa11x0_dma_chan *c)
+{
+	struct sa11x0_dma_desc *txd = p->txd_load;
+	struct sa11x0_dma_sg *sg;
+	void __iomem *base = p->base;
+	unsigned dbsx, dbtx;
+	u32 dcsr;
+
+	if (!txd)
+		return;
+
+	dcsr = readl_relaxed(base + DMA_DCSR_R);
+
+	/* Don't try to load the next transfer if both buffers are started */
+	if ((dcsr & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB))
+		return;
+
+	if (p->sg_load == txd->sglen) {
+		struct sa11x0_dma_desc *txn = sa11x0_dma_next_desc(c);
+
+		/*
+		 * We have reached the end of the current descriptor.
+		 * Peek at the next descriptor, and if compatible with
+		 * the current, start processing it.
+		 */
+		if (txn && txn->ddar == txd->ddar) {
+			txd = txn;
+			sa11x0_dma_start_desc(p, txn);
+		} else {
+			p->txd_load = NULL;
+			return;
+		}
+	}
+
+	sg = &txd->sg[p->sg_load++];
+
+	/* Select buffer to load according to channel status */
+	if (((dcsr & (DCSR_BIU | DCSR_STRTB)) == (DCSR_BIU | DCSR_STRTB)) ||
+	    ((dcsr & (DCSR_BIU | DCSR_STRTA)) == 0)) {
+		dbsx = DMA_DBSA;
+		dbtx = DMA_DBTA;
+		dcsr = DCSR_STRTA | DCSR_IE | DCSR_RUN;
+	} else {
+		dbsx = DMA_DBSB;
+		dbtx = DMA_DBTB;
+		dcsr = DCSR_STRTB | DCSR_IE | DCSR_RUN;
+	}
+
+	writel_relaxed(sg->addr, base + dbsx);
+	writel_relaxed(sg->len, base + dbtx);
+	writel(dcsr, base + DMA_DCSR_S);
+
+	dev_dbg(p->dev->slave.dev, "pchan %u: load: DCSR:%02x DBS%c:%08x DBT%c:%08x\n",
+		p->num, dcsr,
+		'A' + (dbsx == DMA_DBSB), sg->addr,
+		'A' + (dbtx == DMA_DBTB), sg->len);
+}
+
+static void noinline sa11x0_dma_complete(struct sa11x0_dma_phy *p,
+	struct sa11x0_dma_chan *c)
+{
+	struct sa11x0_dma_desc *txd = p->txd_done;
+
+	if (++p->sg_done == txd->sglen) {
+		struct sa11x0_dma_dev *d = p->dev;
+
+		dev_vdbg(d->slave.dev, "pchan %u: txd %p[%x]: completed\n",
+			p->num, p->txd_done, p->txd_done->tx.cookie);
+
+		c->lc = txd->tx.cookie;
+
+		spin_lock(&d->lock);
+		list_add_tail(&txd->node, &d->desc_complete);
+		spin_unlock(&d->lock);
+
+		p->sg_done = 0;
+		p->txd_done = p->txd_load;
+
+		tasklet_schedule(&d->task);
+	}
+
+	sa11x0_dma_start_sg(p, c);
+}
+
+static irqreturn_t sa11x0_dma_irq(int irq, void *dev_id)
+{
+	struct sa11x0_dma_phy *p = dev_id;
+	struct sa11x0_dma_dev *d = p->dev;
+	struct sa11x0_dma_chan *c;
+	u32 dcsr;
+
+	dcsr = readl_relaxed(p->base + DMA_DCSR_R);
+	if (!(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB)))
+		return IRQ_NONE;
+
+	/* Clear reported status bits */
+	writel_relaxed(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB),
+		p->base + DMA_DCSR_C);
+
+	dev_dbg(d->slave.dev, "pchan %u: irq: DCSR:%02x\n", p->num, dcsr);
+
+	if (dcsr & DCSR_ERROR) {
+		dev_err(d->slave.dev, "pchan %u: error. DCSR:%02x DDAR:%08x DBSA:%08x DBTA:%08x DBSB:%08x DBTB:%08x\n",
+			p->num, dcsr,
+			readl_relaxed(p->base + DMA_DDAR),
+			readl_relaxed(p->base + DMA_DBSA),
+			readl_relaxed(p->base + DMA_DBTA),
+			readl_relaxed(p->base + DMA_DBSB),
+			readl_relaxed(p->base + DMA_DBTB));
+	}
+
+	c = p->vchan;
+	if (c) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&c->lock, flags);
+		/*
+		 * Now that we're holding the lock, check that the vchan
+		 * really is associated with this pchan before touching the
+		 * hardware.  This should always succeed, because we won't
+		 * change p->vchan or c->phy while the channel is actively
+		 * transferring.
+		 */
+		if (c->phy == p) {
+			if (dcsr & DCSR_DONEA)
+				sa11x0_dma_complete(p, c);
+			if (dcsr & DCSR_DONEB)
+				sa11x0_dma_complete(p, c);
+		}
+		spin_unlock_irqrestore(&c->lock, flags);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void sa11x0_dma_start_txd(struct sa11x0_dma_chan *c)
+{
+	struct sa11x0_dma_desc *txd = sa11x0_dma_next_desc(c);
+
+	/* If the issued list is empty, we have no further txds to process */
+	if (txd) {
+		struct sa11x0_dma_phy *p = c->phy;
+
+		sa11x0_dma_start_desc(p, txd);
+		p->txd_done = txd;
+		p->sg_done = 0;
+
+		/* The channel should not have any transfers started */
+		WARN_ON(readl_relaxed(p->base + DMA_DCSR_R) &
+				      (DCSR_STRTA | DCSR_STRTB));
+
+		/* Clear the run and start bits before changing DDAR */
+		writel_relaxed(DCSR_RUN | DCSR_STRTA | DCSR_STRTB,
+			       p->base + DMA_DCSR_C);
+		writel_relaxed(txd->ddar, p->base + DMA_DDAR);
+
+		/* Try to start both buffers */
+		sa11x0_dma_start_sg(p, c);
+		sa11x0_dma_start_sg(p, c);
+	}
+}
+
+static void sa11x0_dma_tasklet(unsigned long arg)
+{
+	struct sa11x0_dma_dev *d = (struct sa11x0_dma_dev *)arg;
+	struct sa11x0_dma_phy *p;
+	struct sa11x0_dma_chan *c;
+	struct sa11x0_dma_desc *txd, *txn;
+	LIST_HEAD(head);
+	unsigned pch, pch_alloc = 0;
+
+	dev_dbg(d->slave.dev, "tasklet enter\n");
+
+	/* Get the completed tx descriptors */
+	spin_lock_irq(&d->lock);
+	list_splice_init(&d->desc_complete, &head);
+	spin_unlock_irq(&d->lock);
+
+	list_for_each_entry(txd, &head, node) {
+		c = to_sa11x0_dma_chan(txd->tx.chan);
+
+		dev_dbg(d->slave.dev, "vchan %p: txd %p[%x] completed\n",
+			c, txd, txd->tx.cookie);
+
+		spin_lock_irq(&c->lock);
+		p = c->phy;
+		if (p) {
+			if (!p->txd_done)
+				sa11x0_dma_start_txd(c);
+			if (!p->txd_done) {
+				/* No current txd associated with this channel */
+				dev_dbg(d->slave.dev, "pchan %u: free\n", p->num);
+
+				/* Mark this channel free */
+				c->phy = NULL;
+				p->vchan = NULL;
+			}
+		}
+		spin_unlock_irq(&c->lock);
+	}
+
+	spin_lock_irq(&d->lock);
+	for (pch = 0; pch < NR_PHY_CHAN; pch++) {
+		p = &d->phy[pch];
+
+		if (p->vchan == NULL && !list_empty(&d->chan_pending)) {
+			c = list_first_entry(&d->chan_pending,
+				struct sa11x0_dma_chan, node);
+			list_del_init(&c->node);
+
+			pch_alloc |= 1 << pch;
+
+			/* Mark this channel allocated */
+			p->vchan = c;
+
+			dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, c);
+		}
+	}
+	spin_unlock_irq(&d->lock);
+
+	for (pch = 0; pch < NR_PHY_CHAN; pch++) {
+		if (pch_alloc & (1 << pch)) {
+			p = &d->phy[pch];
+			c = p->vchan;
+
+			spin_lock_irq(&c->lock);
+			c->phy = p;
+
+			sa11x0_dma_start_txd(c);
+			spin_unlock_irq(&c->lock);
+		}
+	}
+
+	/* Now free the completed tx descriptor, and call their callbacks */
+	list_for_each_entry_safe(txd, txn, &head, node) {
+		dma_async_tx_callback callback = txd->tx.callback;
+		void *callback_param = txd->tx.callback_param;
+
+		dev_dbg(d->slave.dev, "txd %p[%x]: callback and free\n",
+			txd, txd->tx.cookie);
+
+		kfree(txd);
+
+		if (callback)
+			callback(callback_param);
+	}
+
+	dev_dbg(d->slave.dev, "tasklet exit\n");
+}
+
+
+static void sa11x0_dma_desc_free(struct sa11x0_dma_dev *d, struct list_head *head)
+{
+	struct sa11x0_dma_desc *txd, *txn;
+
+	list_for_each_entry_safe(txd, txn, head, node) {
+		dev_dbg(d->slave.dev, "txd %p: freeing\n", txd);
+		kfree(txd);
+	}
+}
+
+static int sa11x0_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+	return 0;
+}
+
+static void sa11x0_dma_free_chan_resources(struct dma_chan *chan)
+{
+	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
+	unsigned long flags;
+	LIST_HEAD(head);
+
+	spin_lock_irqsave(&c->lock, flags);
+	spin_lock(&d->lock);
+	list_del_init(&c->node);
+	spin_unlock(&d->lock);
+
+	list_splice_tail_init(&c->desc_submitted, &head);
+	list_splice_tail_init(&c->desc_issued, &head);
+	spin_unlock_irqrestore(&c->lock, flags);
+
+	sa11x0_dma_desc_free(d, &head);
+}
+
+static dma_addr_t sa11x0_dma_pos(struct sa11x0_dma_phy *p)
+{
+	unsigned reg;
+	u32 dcsr;
+
+	dcsr = readl_relaxed(p->base + DMA_DCSR_R);
+
+	if ((dcsr & (DCSR_BIU | DCSR_STRTA)) == DCSR_STRTA ||
+	    (dcsr & (DCSR_BIU | DCSR_STRTB)) == DCSR_BIU)
+		reg = DMA_DBSA;
+	else
+		reg = DMA_DBSB;
+
+	return readl_relaxed(p->base + reg);
+}
+
+static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan,
+	dma_cookie_t cookie, struct dma_tx_state *state)
+{
+	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
+	struct sa11x0_dma_phy *p;
+	struct sa11x0_dma_desc *txd;
+	dma_cookie_t last_used, last_complete;
+	unsigned long flags;
+	enum dma_status ret;
+	size_t bytes = 0;
+
+	last_used = c->chan.cookie;
+	last_complete = c->lc;
+
+	ret = dma_async_is_complete(cookie, last_complete, last_used);
+	if (ret == DMA_SUCCESS) {
+		dma_set_tx_state(state, last_complete, last_used, 0);
+		return ret;
+	}
+
+	spin_lock_irqsave(&c->lock, flags);
+	p = c->phy;
+	ret = c->status;
+	if (p) {
+		dma_addr_t addr = sa11x0_dma_pos(p);
+
+		dev_vdbg(d->slave.dev, "tx_status: addr:%x\n", addr);
+
+		txd = p->txd_done;
+		if (txd) {
+			unsigned i;
+
+			for (i = 0; i < txd->sglen; i++) {
+				dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x\n",
+					i, txd->sg[i].addr, txd->sg[i].len);
+				if (addr >= txd->sg[i].addr &&
+				    addr < txd->sg[i].addr + txd->sg[i].len) {
+					unsigned len;
+
+					len = txd->sg[i].len -
+						(addr - txd->sg[i].addr);
+					dev_vdbg(d->slave.dev, "tx_status: [%u] +%x\n",
+						i, len);
+					bytes += len;
+					i++;
+					break;
+				}
+			}
+			for (; i < txd->sglen; i++) {
+				dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x ++\n",
+					i, txd->sg[i].addr, txd->sg[i].len);
+				bytes += txd->sg[i].len;
+			}
+		}
+		if (txd != p->txd_load && p->txd_load)
+			bytes += p->txd_load->size;
+	}
+	list_for_each_entry(txd, &c->desc_issued, node) {
+		bytes += txd->size;
+	}
+	spin_unlock_irqrestore(&c->lock, flags);
+
+	dma_set_tx_state(state, last_complete, last_used, bytes);
+
+	dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", bytes);
+
+	return ret;
+}
+
+/*
+ * Move pending txds to the issued list, and re-init pending list.
+ * If not already pending, add this channel to the list of pending
+ * channels and trigger the tasklet to run.
+ */
+static void sa11x0_dma_issue_pending(struct dma_chan *chan)
+{
+	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
+	unsigned long flags;
+
+	spin_lock_irqsave(&c->lock, flags);
+	list_splice_tail_init(&c->desc_submitted, &c->desc_issued);
+	if (!list_empty(&c->desc_issued)) {
+		spin_lock(&d->lock);
+		if (!c->phy && list_empty(&c->node)) {
+			list_add_tail(&c->node, &d->chan_pending);
+			tasklet_schedule(&d->task);
+			dev_dbg(d->slave.dev, "vchan %p: issued\n", c);
+		}
+		spin_unlock(&d->lock);
+	} else
+		dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", c);
+	spin_unlock_irqrestore(&c->lock, flags);
+}
+
+static dma_cookie_t sa11x0_dma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(tx->chan);
+	struct sa11x0_dma_desc *txd = to_sa11x0_dma_tx(tx);
+	unsigned long flags;
+
+	spin_lock_irqsave(&c->lock, flags);
+	c->chan.cookie += 1;
+	if (c->chan.cookie < 0)
+		c->chan.cookie = 1;
+	txd->tx.cookie = c->chan.cookie;
+
+	list_add_tail(&txd->node, &c->desc_submitted);
+	spin_unlock_irqrestore(&c->lock, flags);
+
+	dev_dbg(tx->chan->device->dev, "vchan %p: txd %p[%x]: submitted\n",
+		c, txd, txd->tx.cookie);
+
+	return txd->tx.cookie;
+}
+
+static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
+	struct dma_chan *chan, struct scatterlist *sg, unsigned int sglen,
+	enum dma_transfer_direction dir, unsigned long flags, void *context)
+{
+	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+	struct sa11x0_dma_desc *txd;
+	struct scatterlist *sgent;
+	unsigned i, j = sglen;
+	size_t size = 0;
+
+	/* SA11x0 channels can only operate in their native direction */
+	if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) {
+		dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n",
+			c, c->ddar, dir);
+		return NULL;
+	}
+
+	/* Do not allow zero-sized txds */
+	if (sglen == 0)
+		return NULL;
+
+	for_each_sg(sg, sgent, sglen, i) {
+		dma_addr_t addr = sg_dma_address(sgent);
+		unsigned int len = sg_dma_len(sgent);
+
+		if (len > DMA_MAX_SIZE)
+			j += DIV_ROUND_UP(len, DMA_MAX_SIZE & ~DMA_ALIGN) - 1;
+		if (addr & DMA_ALIGN) {
+			dev_dbg(chan->device->dev, "vchan %p: bad buffer alignment: %08x\n",
+				c, addr);
+			return NULL;
+		}
+	}
+
+	txd = kzalloc(sizeof(*txd) + j * sizeof(txd->sg[0]), GFP_ATOMIC);
+	if (!txd) {
+		dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", c);
+		return NULL;
+	}
+
+	j = 0;
+	for_each_sg(sg, sgent, sglen, i) {
+		dma_addr_t addr = sg_dma_address(sgent);
+		unsigned len = sg_dma_len(sgent);
+
+		size += len;
+
+		do {
+			unsigned tlen = len;
+
+			/*
+			 * Check whether the transfer will fit.  If not, try
+			 * to split the transfer up such that we end up with
+			 * equal chunks - but make sure that we preserve the
+			 * alignment.  This avoids small segments.
+			 */
+			if (tlen > DMA_MAX_SIZE) {
+				unsigned mult = DIV_ROUND_UP(tlen,
+					DMA_MAX_SIZE & ~DMA_ALIGN);
+
+				tlen = (tlen / mult) & ~DMA_ALIGN;
+			}
+
+			txd->sg[j].addr = addr;
+			txd->sg[j].len = tlen;
+
+			addr += tlen;
+			len -= tlen;
+			j++;
+		} while (len);
+	}
+
+	dma_async_tx_descriptor_init(&txd->tx, &c->chan);
+	txd->tx.flags = flags;
+	txd->tx.tx_submit = sa11x0_dma_tx_submit;
+	txd->ddar = c->ddar;
+	txd->size = size;
+	txd->sglen = j;
+
+	dev_dbg(chan->device->dev, "vchan %p: txd %p: size %u nr %u\n",
+		c, txd, txd->size, txd->sglen);
+
+	return &txd->tx;
+}
+
+static int sa11x0_dma_slave_config(struct sa11x0_dma_chan *c, struct dma_slave_config *cfg)
+{
+	u32 ddar = c->ddar & ((0xf << 4) | DDAR_RW);
+	dma_addr_t addr;
+	enum dma_slave_buswidth width;
+	u32 maxburst;
+
+	if (ddar & DDAR_RW) {
+		addr = cfg->src_addr;
+		width = cfg->src_addr_width;
+		maxburst = cfg->src_maxburst;
+	} else {
+		addr = cfg->dst_addr;
+		width = cfg->dst_addr_width;
+		maxburst = cfg->dst_maxburst;
+	}
+
+	if ((width != DMA_SLAVE_BUSWIDTH_1_BYTE &&
+	     width != DMA_SLAVE_BUSWIDTH_2_BYTES) ||
+	    (maxburst != 4 && maxburst != 8))
+		return -EINVAL;
+
+	if (width == DMA_SLAVE_BUSWIDTH_2_BYTES)
+		ddar |= DDAR_DW;
+	if (maxburst == 8)
+		ddar |= DDAR_BS;
+
+	dev_dbg(c->chan.device->dev, "vchan %p: dma_slave_config addr %x width %u burst %u\n",
+		c, addr, width, maxburst);
+
+	c->ddar = ddar | (addr & 0xf0000000) | (addr & 0x003ffffc) << 6;
+
+	return 0;
+}
+
+static int sa11x0_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+	unsigned long arg)
+{
+	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
+	struct sa11x0_dma_phy *p;
+	LIST_HEAD(head);
+	unsigned long flags;
+	int ret;
+
+	switch (cmd) {
+	case DMA_SLAVE_CONFIG:
+		return sa11x0_dma_slave_config(c, (struct dma_slave_config *)arg);
+
+	case DMA_TERMINATE_ALL:
+		dev_dbg(d->slave.dev, "vchan %p: terminate all\n", c);
+		/* Clear the tx descriptor lists */
+		spin_lock_irqsave(&c->lock, flags);
+		list_splice_tail_init(&c->desc_submitted, &head);
+		list_splice_tail_init(&c->desc_issued, &head);
+
+		p = c->phy;
+		if (p) {
+			struct sa11x0_dma_desc *txd, *txn;
+
+			dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num);
+			/* vchan is assigned to a pchan - stop the channel */
+			writel(DCSR_RUN | DCSR_IE |
+				DCSR_STRTA | DCSR_DONEA |
+				DCSR_STRTB | DCSR_DONEB,
+				p->base + DMA_DCSR_C);
+
+			list_for_each_entry_safe(txd, txn, &d->desc_complete, node)
+				if (txd->tx.chan == &c->chan)
+					list_move(&txd->node, &head);
+
+			if (p->txd_load) {
+				if (p->txd_load != p->txd_done)
+					list_add_tail(&p->txd_load->node, &head);
+				p->txd_load = NULL;
+			}
+			if (p->txd_done) {
+				list_add_tail(&p->txd_done->node, &head);
+				p->txd_done = NULL;
+			}
+			c->phy = NULL;
+			spin_lock(&d->lock);
+			p->vchan = NULL;
+			spin_unlock(&d->lock);
+			tasklet_schedule(&d->task);
+		}
+		spin_unlock_irqrestore(&c->lock, flags);
+		sa11x0_dma_desc_free(d, &head);
+		ret = 0;
+		break;
+
+	case DMA_PAUSE:
+		dev_dbg(d->slave.dev, "vchan %p: pause\n", c);
+		spin_lock_irqsave(&c->lock, flags);
+		if (c->status == DMA_IN_PROGRESS) {
+			c->status = DMA_PAUSED;
+
+			p = c->phy;
+			if (p) {
+				writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C);
+			} else {
+				spin_lock(&d->lock);
+				list_del_init(&c->node);
+				spin_unlock(&d->lock);
+			}
+		}
+		spin_unlock_irqrestore(&c->lock, flags);
+		ret = 0;
+		break;
+
+	case DMA_RESUME:
+		dev_dbg(d->slave.dev, "vchan %p: resume\n", c);
+		spin_lock_irqsave(&c->lock, flags);
+		if (c->status == DMA_PAUSED) {
+			c->status = DMA_IN_PROGRESS;
+
+			p = c->phy;
+			if (p) {
+				writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S);
+			} else if (!list_empty(&c->desc_issued)) {
+				spin_lock(&d->lock);
+				list_add_tail(&c->node, &d->chan_pending);
+				spin_unlock(&d->lock);
+			}
+		}
+		spin_unlock_irqrestore(&c->lock, flags);
+		ret = 0;
+		break;
+
+	default:
+		ret = -ENXIO;
+		break;
+	}
+
+	return ret;
+}
+
+struct sa11x0_dma_channel_desc {
+	u32 ddar;
+	const char *name;
+};
+
+#define CD(d1, d2) { .ddar = DDAR_##d1 | d2, .name = #d1 }
+static const struct sa11x0_dma_channel_desc chan_desc[] = {
+	CD(Ser0UDCTr, 0),
+	CD(Ser0UDCRc, DDAR_RW),
+	CD(Ser1SDLCTr, 0),
+	CD(Ser1SDLCRc, DDAR_RW),
+	CD(Ser1UARTTr, 0),
+	CD(Ser1UARTRc, DDAR_RW),
+	CD(Ser2ICPTr, 0),
+	CD(Ser2ICPRc, DDAR_RW),
+	CD(Ser3UARTTr, 0),
+	CD(Ser3UARTRc, DDAR_RW),
+	CD(Ser4MCP0Tr, 0),
+	CD(Ser4MCP0Rc, DDAR_RW),
+	CD(Ser4MCP1Tr, 0),
+	CD(Ser4MCP1Rc, DDAR_RW),
+	CD(Ser4SSPTr, 0),
+	CD(Ser4SSPRc, DDAR_RW),
+};
+
+static int __devinit sa11x0_dma_init_dmadev(struct dma_device *dmadev,
+	struct device *dev)
+{
+	unsigned i;
+
+	dmadev->chancnt = ARRAY_SIZE(chan_desc);
+	INIT_LIST_HEAD(&dmadev->channels);
+	dmadev->dev = dev;
+	dmadev->device_alloc_chan_resources = sa11x0_dma_alloc_chan_resources;
+	dmadev->device_free_chan_resources = sa11x0_dma_free_chan_resources;
+	dmadev->device_control = sa11x0_dma_control;
+	dmadev->device_tx_status = sa11x0_dma_tx_status;
+	dmadev->device_issue_pending = sa11x0_dma_issue_pending;
+
+	for (i = 0; i < dmadev->chancnt; i++) {
+		struct sa11x0_dma_chan *c;
+
+		c = kzalloc(sizeof(*c), GFP_KERNEL);
+		if (!c) {
+			dev_err(dev, "no memory for channel %u\n", i);
+			return -ENOMEM;
+		}
+
+		c->chan.device = dmadev;
+		c->status = DMA_IN_PROGRESS;
+		c->ddar = chan_desc[i].ddar;
+		c->name = chan_desc[i].name;
+		spin_lock_init(&c->lock);
+		INIT_LIST_HEAD(&c->desc_submitted);
+		INIT_LIST_HEAD(&c->desc_issued);
+		INIT_LIST_HEAD(&c->node);
+		list_add_tail(&c->chan.device_node, &dmadev->channels);
+	}
+
+	return dma_async_device_register(dmadev);
+}
+
+static int sa11x0_dma_request_irq(struct platform_device *pdev, int nr,
+	void *data)
+{
+	int irq = platform_get_irq(pdev, nr);
+
+	if (irq <= 0)
+		return -ENXIO;
+
+	return request_irq(irq, sa11x0_dma_irq, 0, dev_name(&pdev->dev), data);
+}
+
+static void sa11x0_dma_free_irq(struct platform_device *pdev, int nr,
+	void *data)
+{
+	int irq = platform_get_irq(pdev, nr);
+	if (irq > 0)
+		free_irq(irq, data);
+}
+
+static void sa11x0_dma_free_channels(struct dma_device *dmadev)
+{
+	struct sa11x0_dma_chan *c, *cn;
+
+	list_for_each_entry_safe(c, cn, &dmadev->channels, chan.device_node) {
+		list_del(&c->chan.device_node);
+		kfree(c);
+	}
+}
+
+static int __devinit sa11x0_dma_probe(struct platform_device *pdev)
+{
+	struct sa11x0_dma_dev *d;
+	struct resource *res;
+	unsigned i;
+	int ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
+	d = kzalloc(sizeof(*d), GFP_KERNEL);
+	if (!d) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	spin_lock_init(&d->lock);
+	INIT_LIST_HEAD(&d->chan_pending);
+	INIT_LIST_HEAD(&d->desc_complete);
+
+	d->base = ioremap(res->start, resource_size(res));
+	if (!d->base) {
+		ret = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	tasklet_init(&d->task, sa11x0_dma_tasklet, (unsigned long)d);
+
+	for (i = 0; i < NR_PHY_CHAN; i++) {
+		struct sa11x0_dma_phy *p = &d->phy[i];
+
+		p->dev = d;
+		p->num = i;
+		p->base = d->base + i * DMA_SIZE;
+		writel_relaxed(DCSR_RUN | DCSR_IE | DCSR_ERROR |
+			DCSR_DONEA | DCSR_STRTA | DCSR_DONEB | DCSR_STRTB,
+			p->base + DMA_DCSR_C);
+		writel_relaxed(0, p->base + DMA_DDAR);
+
+		ret = sa11x0_dma_request_irq(pdev, i, p);
+		if (ret) {
+			while (i) {
+				i--;
+				sa11x0_dma_free_irq(pdev, i, &d->phy[i]);
+			}
+			goto err_irq;
+		}
+	}
+
+	dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
+	d->slave.device_prep_slave_sg = sa11x0_dma_prep_slave_sg;
+	ret = sa11x0_dma_init_dmadev(&d->slave, &pdev->dev);
+	if (ret) {
+		dev_warn(d->slave.dev, "failed to register slave async device: %d\n",
+			ret);
+		goto err_slave_reg;
+	}
+
+	platform_set_drvdata(pdev, d);
+	return 0;
+
+ err_slave_reg:
+	sa11x0_dma_free_channels(&d->slave);
+	for (i = 0; i < NR_PHY_CHAN; i++)
+		sa11x0_dma_free_irq(pdev, i, &d->phy[i]);
+ err_irq:
+	tasklet_kill(&d->task);
+	iounmap(d->base);
+ err_ioremap:
+	kfree(d);
+ err_alloc:
+	return ret;
+}
+
+static int __devexit sa11x0_dma_remove(struct platform_device *pdev)
+{
+	struct sa11x0_dma_dev *d = platform_get_drvdata(pdev);
+	unsigned pch;
+
+	dma_async_device_unregister(&d->slave);
+
+	sa11x0_dma_free_channels(&d->slave);
+	for (pch = 0; pch < NR_PHY_CHAN; pch++)
+		sa11x0_dma_free_irq(pdev, pch, &d->phy[pch]);
+	tasklet_kill(&d->task);
+	iounmap(d->base);
+	kfree(d);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int sa11x0_dma_suspend(struct device *dev)
+{
+	struct sa11x0_dma_dev *d = dev_get_drvdata(dev);
+	unsigned pch;
+
+	for (pch = 0; pch < NR_PHY_CHAN; pch++) {
+		struct sa11x0_dma_phy *p = &d->phy[pch];
+		u32 dcsr, saved_dcsr;
+
+		dcsr = saved_dcsr = readl_relaxed(p->base + DMA_DCSR_R);
+		if (dcsr & DCSR_RUN) {
+			writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C);
+			dcsr = readl_relaxed(p->base + DMA_DCSR_R);
+		}
+
+		saved_dcsr &= DCSR_RUN | DCSR_IE;
+		if (dcsr & DCSR_BIU) {
+			p->dbs[0] = readl_relaxed(p->base + DMA_DBSB);
+			p->dbt[0] = readl_relaxed(p->base + DMA_DBTB);
+			p->dbs[1] = readl_relaxed(p->base + DMA_DBSA);
+			p->dbt[1] = readl_relaxed(p->base + DMA_DBTA);
+			saved_dcsr |= (dcsr & DCSR_STRTA ? DCSR_STRTB : 0) |
+				      (dcsr & DCSR_STRTB ? DCSR_STRTA : 0);
+		} else {
+			p->dbs[0] = readl_relaxed(p->base + DMA_DBSA);
+			p->dbt[0] = readl_relaxed(p->base + DMA_DBTA);
+			p->dbs[1] = readl_relaxed(p->base + DMA_DBSB);
+			p->dbt[1] = readl_relaxed(p->base + DMA_DBTB);
+			saved_dcsr |= dcsr & (DCSR_STRTA | DCSR_STRTB);
+		}
+		p->dcsr = saved_dcsr;
+
+		writel(DCSR_STRTA | DCSR_STRTB, p->base + DMA_DCSR_C);
+	}
+
+	return 0;
+}
+
+static int sa11x0_dma_resume(struct device *dev)
+{
+	struct sa11x0_dma_dev *d = dev_get_drvdata(dev);
+	unsigned pch;
+
+	for (pch = 0; pch < NR_PHY_CHAN; pch++) {
+		struct sa11x0_dma_phy *p = &d->phy[pch];
+		struct sa11x0_dma_desc *txd = NULL;
+		u32 dcsr = readl_relaxed(p->base + DMA_DCSR_R);
+
+		WARN_ON(dcsr & (DCSR_BIU | DCSR_STRTA | DCSR_STRTB | DCSR_RUN));
+
+		if (p->txd_done)
+			txd = p->txd_done;
+		else if (p->txd_load)
+			txd = p->txd_load;
+
+		if (!txd)
+			continue;
+
+		writel_relaxed(txd->ddar, p->base + DMA_DDAR);
+
+		writel_relaxed(p->dbs[0], p->base + DMA_DBSA);
+		writel_relaxed(p->dbt[0], p->base + DMA_DBTA);
+		writel_relaxed(p->dbs[1], p->base + DMA_DBSB);
+		writel_relaxed(p->dbt[1], p->base + DMA_DBTB);
+		writel_relaxed(p->dcsr, p->base + DMA_DCSR_S);
+	}
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops sa11x0_dma_pm_ops = {
+	.suspend_noirq = sa11x0_dma_suspend,
+	.resume_noirq = sa11x0_dma_resume,
+	.freeze_noirq = sa11x0_dma_suspend,
+	.thaw_noirq = sa11x0_dma_resume,
+	.poweroff_noirq = sa11x0_dma_suspend,
+	.restore_noirq = sa11x0_dma_resume,
+};
+
+static struct platform_driver sa11x0_dma_driver = {
+	.driver = {
+		.name	= "sa11x0-dma",
+		.owner	= THIS_MODULE,
+		.pm	= &sa11x0_dma_pm_ops,
+	},
+	.probe		= sa11x0_dma_probe,
+	.remove		= __devexit_p(sa11x0_dma_remove),
+};
+
+bool sa11x0_dma_filter_fn(struct dma_chan *chan, void *param)
+{
+	if (chan->device->dev->driver == &sa11x0_dma_driver.driver) {
+		struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+		const char *p = param;
+
+		return !strcmp(c->name, p);
+	}
+	return false;
+}
+EXPORT_SYMBOL(sa11x0_dma_filter_fn);
+
+static int __init sa11x0_dma_init(void)
+{
+	return platform_driver_register(&sa11x0_dma_driver);
+}
+subsys_initcall(sa11x0_dma_init);
+
+static void __exit sa11x0_dma_exit(void)
+{
+	platform_driver_unregister(&sa11x0_dma_driver);
+}
+module_exit(sa11x0_dma_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("SA-11x0 DMA driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sa11x0-dma");
diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
index 812fd76..19d7a8d 100644
--- a/drivers/dma/shdma.c
+++ b/drivers/dma/shdma.c
@@ -30,6 +30,8 @@
 #include <linux/kdebug.h>
 #include <linux/spinlock.h>
 #include <linux/rculist.h>
+
+#include "dmaengine.h"
 #include "shdma.h"
 
 /* DMA descriptor control */
@@ -296,13 +298,7 @@
 	else
 		power_up = false;
 
-	cookie = sh_chan->common.cookie;
-	cookie++;
-	if (cookie < 0)
-		cookie = 1;
-
-	sh_chan->common.cookie = cookie;
-	tx->cookie = cookie;
+	cookie = dma_cookie_assign(tx);
 
 	/* Mark all chunks of this descriptor as submitted, move to the queue */
 	list_for_each_entry_safe(chunk, c, desc->node.prev, node) {
@@ -673,7 +669,8 @@
 
 static struct dma_async_tx_descriptor *sh_dmae_prep_slave_sg(
 	struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len,
-	enum dma_transfer_direction direction, unsigned long flags)
+	enum dma_transfer_direction direction, unsigned long flags,
+	void *context)
 {
 	struct sh_dmae_slave *param;
 	struct sh_dmae_chan *sh_chan;
@@ -764,12 +761,12 @@
 			cookie = tx->cookie;
 
 		if (desc->mark == DESC_COMPLETED && desc->chunks == 1) {
-			if (sh_chan->completed_cookie != desc->cookie - 1)
+			if (sh_chan->common.completed_cookie != desc->cookie - 1)
 				dev_dbg(sh_chan->dev,
 					"Completing cookie %d, expected %d\n",
 					desc->cookie,
-					sh_chan->completed_cookie + 1);
-			sh_chan->completed_cookie = desc->cookie;
+					sh_chan->common.completed_cookie + 1);
+			sh_chan->common.completed_cookie = desc->cookie;
 		}
 
 		/* Call callback on the last chunk */
@@ -823,7 +820,7 @@
 		 * Terminating and the loop completed normally: forgive
 		 * uncompleted cookies
 		 */
-		sh_chan->completed_cookie = sh_chan->common.cookie;
+		sh_chan->common.completed_cookie = sh_chan->common.cookie;
 
 	spin_unlock_irqrestore(&sh_chan->desc_lock, flags);
 
@@ -883,23 +880,14 @@
 					struct dma_tx_state *txstate)
 {
 	struct sh_dmae_chan *sh_chan = to_sh_chan(chan);
-	dma_cookie_t last_used;
-	dma_cookie_t last_complete;
 	enum dma_status status;
 	unsigned long flags;
 
 	sh_dmae_chan_ld_cleanup(sh_chan, false);
 
-	/* First read completed cookie to avoid a skew */
-	last_complete = sh_chan->completed_cookie;
-	rmb();
-	last_used = chan->cookie;
-	BUG_ON(last_complete < 0);
-	dma_set_tx_state(txstate, last_complete, last_used, 0);
-
 	spin_lock_irqsave(&sh_chan->desc_lock, flags);
 
-	status = dma_async_is_complete(cookie, last_complete, last_used);
+	status = dma_cookie_status(chan, cookie, txstate);
 
 	/*
 	 * If we don't find cookie on the queue, it has been aborted and we have
@@ -1102,6 +1090,7 @@
 
 	/* reference struct dma_device */
 	new_sh_chan->common.device = &shdev->common;
+	dma_cookie_init(&new_sh_chan->common);
 
 	new_sh_chan->dev = shdev->common.dev;
 	new_sh_chan->id = id;
diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h
index 2b55a27..0b1d2c1 100644
--- a/drivers/dma/shdma.h
+++ b/drivers/dma/shdma.h
@@ -30,7 +30,6 @@
 };
 
 struct sh_dmae_chan {
-	dma_cookie_t completed_cookie;	/* The maximum cookie completed */
 	spinlock_t desc_lock;		/* Descriptor operation lock */
 	struct list_head ld_queue;	/* Link descriptors queue */
 	struct list_head ld_free;	/* Link descriptors free */
diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
index 2333810..434ad31 100644
--- a/drivers/dma/sirf-dma.c
+++ b/drivers/dma/sirf-dma.c
@@ -18,6 +18,8 @@
 #include <linux/of_platform.h>
 #include <linux/sirfsoc_dma.h>
 
+#include "dmaengine.h"
+
 #define SIRFSOC_DMA_DESCRIPTORS                 16
 #define SIRFSOC_DMA_CHANNELS                    16
 
@@ -59,7 +61,6 @@
 	struct list_head		queued;
 	struct list_head		active;
 	struct list_head		completed;
-	dma_cookie_t			completed_cookie;
 	unsigned long			happened_cyclic;
 	unsigned long			completed_cyclic;
 
@@ -208,7 +209,7 @@
 			/* Free descriptors */
 			spin_lock_irqsave(&schan->lock, flags);
 			list_splice_tail_init(&list, &schan->free);
-			schan->completed_cookie = last_cookie;
+			schan->chan.completed_cookie = last_cookie;
 			spin_unlock_irqrestore(&schan->lock, flags);
 		} else {
 			/* for cyclic channel, desc is always in active list */
@@ -258,13 +259,7 @@
 	/* Move descriptor to queue */
 	list_move_tail(&sdesc->node, &schan->queued);
 
-	/* Update cookie */
-	cookie = schan->chan.cookie + 1;
-	if (cookie <= 0)
-		cookie = 1;
-
-	schan->chan.cookie = cookie;
-	sdesc->desc.cookie = cookie;
+	cookie = dma_cookie_assign(txd);
 
 	spin_unlock_irqrestore(&schan->lock, flags);
 
@@ -414,16 +409,13 @@
 {
 	struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
 	unsigned long flags;
-	dma_cookie_t last_used;
-	dma_cookie_t last_complete;
+	enum dma_status ret;
 
 	spin_lock_irqsave(&schan->lock, flags);
-	last_used = schan->chan.cookie;
-	last_complete = schan->completed_cookie;
+	ret = dma_cookie_status(chan, cookie, txstate);
 	spin_unlock_irqrestore(&schan->lock, flags);
 
-	dma_set_tx_state(txstate, last_complete, last_used, 0);
-	return dma_async_is_complete(cookie, last_complete, last_used);
+	return ret;
 }
 
 static struct dma_async_tx_descriptor *sirfsoc_dma_prep_interleaved(
@@ -497,7 +489,7 @@
 static struct dma_async_tx_descriptor *
 sirfsoc_dma_prep_cyclic(struct dma_chan *chan, dma_addr_t addr,
 	size_t buf_len, size_t period_len,
-	enum dma_transfer_direction direction)
+	enum dma_transfer_direction direction, void *context)
 {
 	struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
 	struct sirfsoc_dma_desc *sdesc = NULL;
@@ -635,8 +627,7 @@
 		schan = &sdma->channels[i];
 
 		schan->chan.device = dma;
-		schan->chan.cookie = 1;
-		schan->completed_cookie = schan->chan.cookie;
+		dma_cookie_init(&schan->chan);
 
 		INIT_LIST_HEAD(&schan->free);
 		INIT_LIST_HEAD(&schan->prepared);
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index cc5ecbc..bdd41d4 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -21,6 +21,7 @@
 
 #include <plat/ste_dma40.h>
 
+#include "dmaengine.h"
 #include "ste_dma40_ll.h"
 
 #define D40_NAME "dma40"
@@ -220,8 +221,6 @@
  *
  * @lock: A spinlock to protect this struct.
  * @log_num: The logical number, if any of this channel.
- * @completed: Starts with 1, after first interrupt it is set to dma engine's
- * current cookie.
  * @pending_tx: The number of pending transfers. Used between interrupt handler
  * and tasklet.
  * @busy: Set to true when transfer is ongoing on this channel.
@@ -250,8 +249,6 @@
 struct d40_chan {
 	spinlock_t			 lock;
 	int				 log_num;
-	/* ID of the most recent completed transfer */
-	int				 completed;
 	int				 pending_tx;
 	bool				 busy;
 	struct d40_phy_res		*phy_chan;
@@ -1223,21 +1220,14 @@
 					     chan);
 	struct d40_desc *d40d = container_of(tx, struct d40_desc, txd);
 	unsigned long flags;
+	dma_cookie_t cookie;
 
 	spin_lock_irqsave(&d40c->lock, flags);
-
-	d40c->chan.cookie++;
-
-	if (d40c->chan.cookie < 0)
-		d40c->chan.cookie = 1;
-
-	d40d->txd.cookie = d40c->chan.cookie;
-
+	cookie = dma_cookie_assign(tx);
 	d40_desc_queue(d40c, d40d);
-
 	spin_unlock_irqrestore(&d40c->lock, flags);
 
-	return tx->cookie;
+	return cookie;
 }
 
 static int d40_start(struct d40_chan *d40c)
@@ -1357,7 +1347,7 @@
 		goto err;
 
 	if (!d40d->cyclic)
-		d40c->completed = d40d->txd.cookie;
+		dma_cookie_complete(&d40d->txd);
 
 	/*
 	 * If terminating a channel pending_tx is set to zero.
@@ -2182,7 +2172,7 @@
 	bool is_free_phy;
 	spin_lock_irqsave(&d40c->lock, flags);
 
-	d40c->completed = chan->cookie = 1;
+	dma_cookie_init(chan);
 
 	/* If no dma configuration is set use default configuration (memcpy) */
 	if (!d40c->configured) {
@@ -2299,7 +2289,8 @@
 							 struct scatterlist *sgl,
 							 unsigned int sg_len,
 							 enum dma_transfer_direction direction,
-							 unsigned long dma_flags)
+							 unsigned long dma_flags,
+							 void *context)
 {
 	if (direction != DMA_DEV_TO_MEM && direction != DMA_MEM_TO_DEV)
 		return NULL;
@@ -2310,7 +2301,7 @@
 static struct dma_async_tx_descriptor *
 dma40_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
 		     size_t buf_len, size_t period_len,
-		     enum dma_transfer_direction direction)
+		     enum dma_transfer_direction direction, void *context)
 {
 	unsigned int periods = buf_len / period_len;
 	struct dma_async_tx_descriptor *txd;
@@ -2342,25 +2333,19 @@
 				     struct dma_tx_state *txstate)
 {
 	struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
-	dma_cookie_t last_used;
-	dma_cookie_t last_complete;
-	int ret;
+	enum dma_status ret;
 
 	if (d40c->phy_chan == NULL) {
 		chan_err(d40c, "Cannot read status of unallocated channel\n");
 		return -EINVAL;
 	}
 
-	last_complete = d40c->completed;
-	last_used = chan->cookie;
+	ret = dma_cookie_status(chan, cookie, txstate);
+	if (ret != DMA_SUCCESS)
+		dma_set_residue(txstate, stedma40_residue(chan));
 
 	if (d40_is_paused(d40c))
 		ret = DMA_PAUSED;
-	else
-		ret = dma_async_is_complete(cookie, last_complete, last_used);
-
-	dma_set_tx_state(txstate, last_complete, last_used,
-			 stedma40_residue(chan));
 
 	return ret;
 }
diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c
index a6f9c16..4e0dff5 100644
--- a/drivers/dma/timb_dma.c
+++ b/drivers/dma/timb_dma.c
@@ -31,6 +31,8 @@
 
 #include <linux/timb_dma.h>
 
+#include "dmaengine.h"
+
 #define DRIVER_NAME "timb-dma"
 
 /* Global DMA registers */
@@ -84,7 +86,6 @@
 					especially the lists and descriptors,
 					from races between the tasklet and calls
 					from above */
-	dma_cookie_t		last_completed_cookie;
 	bool			ongoing;
 	struct list_head	active_list;
 	struct list_head	queue;
@@ -284,7 +285,7 @@
 	else
 		iowrite32(0, td_chan->membase + TIMBDMA_OFFS_TX_DLAR);
 */
-	td_chan->last_completed_cookie = txd->cookie;
+	dma_cookie_complete(txd);
 	td_chan->ongoing = false;
 
 	callback = txd->callback;
@@ -349,12 +350,7 @@
 	dma_cookie_t cookie;
 
 	spin_lock_bh(&td_chan->lock);
-
-	cookie = txd->chan->cookie;
-	if (++cookie < 0)
-		cookie = 1;
-	txd->chan->cookie = cookie;
-	txd->cookie = cookie;
+	cookie = dma_cookie_assign(txd);
 
 	if (list_empty(&td_chan->active_list)) {
 		dev_dbg(chan2dev(txd->chan), "%s: started %u\n", __func__,
@@ -481,8 +477,7 @@
 	}
 
 	spin_lock_bh(&td_chan->lock);
-	td_chan->last_completed_cookie = 1;
-	chan->cookie = 1;
+	dma_cookie_init(chan);
 	spin_unlock_bh(&td_chan->lock);
 
 	return 0;
@@ -515,24 +510,13 @@
 static enum dma_status td_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
 				    struct dma_tx_state *txstate)
 {
-	struct timb_dma_chan *td_chan =
-		container_of(chan, struct timb_dma_chan, chan);
-	dma_cookie_t		last_used;
-	dma_cookie_t		last_complete;
-	int			ret;
+	enum dma_status ret;
 
 	dev_dbg(chan2dev(chan), "%s: Entry\n", __func__);
 
-	last_complete = td_chan->last_completed_cookie;
-	last_used = chan->cookie;
+	ret = dma_cookie_status(chan, cookie, txstate);
 
-	ret = dma_async_is_complete(cookie, last_complete, last_used);
-
-	dma_set_tx_state(txstate, last_complete, last_used, 0);
-
-	dev_dbg(chan2dev(chan),
-		"%s: exit, ret: %d, last_complete: %d, last_used: %d\n",
-		__func__, ret, last_complete, last_used);
+	dev_dbg(chan2dev(chan), "%s: exit, ret: %d\n", 	__func__, ret);
 
 	return ret;
 }
@@ -558,7 +542,8 @@
 
 static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan,
 	struct scatterlist *sgl, unsigned int sg_len,
-	enum dma_transfer_direction direction, unsigned long flags)
+	enum dma_transfer_direction direction, unsigned long flags,
+	void *context)
 {
 	struct timb_dma_chan *td_chan =
 		container_of(chan, struct timb_dma_chan, chan);
@@ -766,7 +751,7 @@
 		}
 
 		td_chan->chan.device = &td->dma;
-		td_chan->chan.cookie = 1;
+		dma_cookie_init(&td_chan->chan);
 		spin_lock_init(&td_chan->lock);
 		INIT_LIST_HEAD(&td_chan->active_list);
 		INIT_LIST_HEAD(&td_chan->queue);
diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c
index 6122c36..913f55c 100644
--- a/drivers/dma/txx9dmac.c
+++ b/drivers/dma/txx9dmac.c
@@ -15,6 +15,8 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/scatterlist.h>
+
+#include "dmaengine.h"
 #include "txx9dmac.h"
 
 static struct txx9dmac_chan *to_txx9dmac_chan(struct dma_chan *chan)
@@ -279,21 +281,6 @@
 	}
 }
 
-/* Called with dc->lock held and bh disabled */
-static dma_cookie_t
-txx9dmac_assign_cookie(struct txx9dmac_chan *dc, struct txx9dmac_desc *desc)
-{
-	dma_cookie_t cookie = dc->chan.cookie;
-
-	if (++cookie < 0)
-		cookie = 1;
-
-	dc->chan.cookie = cookie;
-	desc->txd.cookie = cookie;
-
-	return cookie;
-}
-
 /*----------------------------------------------------------------------*/
 
 static void txx9dmac_dump_regs(struct txx9dmac_chan *dc)
@@ -424,7 +411,7 @@
 	dev_vdbg(chan2dev(&dc->chan), "descriptor %u %p complete\n",
 		 txd->cookie, desc);
 
-	dc->completed = txd->cookie;
+	dma_cookie_complete(txd);
 	callback = txd->callback;
 	param = txd->callback_param;
 
@@ -738,7 +725,7 @@
 	dma_cookie_t cookie;
 
 	spin_lock_bh(&dc->lock);
-	cookie = txx9dmac_assign_cookie(dc, desc);
+	cookie = dma_cookie_assign(tx);
 
 	dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u %p\n",
 		 desc->txd.cookie, desc);
@@ -846,7 +833,7 @@
 static struct dma_async_tx_descriptor *
 txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 		unsigned int sg_len, enum dma_transfer_direction direction,
-		unsigned long flags)
+		unsigned long flags, void *context)
 {
 	struct txx9dmac_chan *dc = to_txx9dmac_chan(chan);
 	struct txx9dmac_dev *ddev = dc->ddev;
@@ -972,27 +959,17 @@
 		   struct dma_tx_state *txstate)
 {
 	struct txx9dmac_chan *dc = to_txx9dmac_chan(chan);
-	dma_cookie_t last_used;
-	dma_cookie_t last_complete;
-	int ret;
+	enum dma_status ret;
 
-	last_complete = dc->completed;
-	last_used = chan->cookie;
-
-	ret = dma_async_is_complete(cookie, last_complete, last_used);
+	ret = dma_cookie_status(chan, cookie, txstate);
 	if (ret != DMA_SUCCESS) {
 		spin_lock_bh(&dc->lock);
 		txx9dmac_scan_descriptors(dc);
 		spin_unlock_bh(&dc->lock);
 
-		last_complete = dc->completed;
-		last_used = chan->cookie;
-
-		ret = dma_async_is_complete(cookie, last_complete, last_used);
+		ret = dma_cookie_status(chan, cookie, txstate);
 	}
 
-	dma_set_tx_state(txstate, last_complete, last_used, 0);
-
 	return ret;
 }
 
@@ -1057,7 +1034,7 @@
 		return -EIO;
 	}
 
-	dc->completed = chan->cookie = 1;
+	dma_cookie_init(chan);
 
 	dc->ccr = TXX9_DMA_CCR_IMMCHN | TXX9_DMA_CCR_INTENE | CCR_LE;
 	txx9dmac_chan_set_SMPCHN(dc);
@@ -1186,7 +1163,7 @@
 	dc->ddev->chan[ch] = dc;
 	dc->chan.device = &dc->dma;
 	list_add_tail(&dc->chan.device_node, &dc->chan.device->channels);
-	dc->chan.cookie = dc->completed = 1;
+	dma_cookie_init(&dc->chan);
 
 	if (is_dmac64(dc))
 		dc->ch_regs = &__txx9dmac_regs(dc->ddev)->CHAN[ch];
diff --git a/drivers/dma/txx9dmac.h b/drivers/dma/txx9dmac.h
index 365d423..f5a7605 100644
--- a/drivers/dma/txx9dmac.h
+++ b/drivers/dma/txx9dmac.h
@@ -172,7 +172,6 @@
 	spinlock_t		lock;
 
 	/* these other elements are all protected by lock */
-	dma_cookie_t		completed;
 	struct list_head	active_list;
 	struct list_head	queue;
 	struct list_head	free_list;
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 5948a21..fdffa1b 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -215,7 +215,7 @@
 config EDAC_SBRIDGE
 	tristate "Intel Sandy-Bridge Integrated MC"
 	depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL
-	depends on EXPERIMENTAL
+	depends on PCI_MMCONFIG && EXPERIMENTAL
 	help
 	  Support for error detection and correction the Intel
 	  Sandy Bridge Integrated Memory Controller.
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index c9eee6d..7ef73c9 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -1132,12 +1132,36 @@
 		return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
 	}
 	else if (pvt->ext_model >= K8_REV_D) {
+		unsigned diff;
 		WARN_ON(cs_mode > 10);
 
-		if (cs_mode == 3 || cs_mode == 8)
-			return 32 << (cs_mode - 1);
-		else
-			return 32 << cs_mode;
+		/*
+		 * the below calculation, besides trying to win an obfuscated C
+		 * contest, maps cs_mode values to DIMM chip select sizes. The
+		 * mappings are:
+		 *
+		 * cs_mode	CS size (mb)
+		 * =======	============
+		 * 0		32
+		 * 1		64
+		 * 2		128
+		 * 3		128
+		 * 4		256
+		 * 5		512
+		 * 6		256
+		 * 7		512
+		 * 8		1024
+		 * 9		1024
+		 * 10		2048
+		 *
+		 * Basically, it calculates a value with which to shift the
+		 * smallest CS size of 32MB.
+		 *
+		 * ddr[23]_cs_size have a similar purpose.
+		 */
+		diff = cs_mode/3 + (unsigned)(cs_mode > 5);
+
+		return 32 << (cs_mode - diff);
 	}
 	else {
 		WARN_ON(cs_mode > 6);
@@ -2133,6 +2157,7 @@
 static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
 {
 	u32 cs_mode, nr_pages;
+	u32 dbam = dct ? pvt->dbam1 : pvt->dbam0;
 
 	/*
 	 * The math on this doesn't look right on the surface because x/2*4 can
@@ -2141,16 +2166,10 @@
 	 * number of bits to shift the DBAM register to extract the proper CSROW
 	 * field.
 	 */
-	cs_mode = (pvt->dbam0 >> ((csrow_nr / 2) * 4)) & 0xF;
+	cs_mode =  (dbam >> ((csrow_nr / 2) * 4)) & 0xF;
 
 	nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT);
 
-	/*
-	 * If dual channel then double the memory size of single channel.
-	 * Channel count is 1 or 2
-	 */
-	nr_pages <<= (pvt->channel_count - 1);
-
 	debugf0("  (csrow=%d) DBAM map index= %d\n", csrow_nr, cs_mode);
 	debugf0("    nr_pages= %u  channel-count = %d\n",
 		nr_pages, pvt->channel_count);
@@ -2181,7 +2200,7 @@
 	for_each_chip_select(i, 0, pvt) {
 		csrow = &mci->csrows[i];
 
-		if (!csrow_enabled(i, 0, pvt)) {
+		if (!csrow_enabled(i, 0, pvt) && !csrow_enabled(i, 1, pvt)) {
 			debugf1("----CSROW %d EMPTY for node %d\n", i,
 				pvt->mc_node_id);
 			continue;
@@ -2191,7 +2210,10 @@
 			i, pvt->mc_node_id);
 
 		empty = 0;
-		csrow->nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
+		if (csrow_enabled(i, 0, pvt))
+			csrow->nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
+		if (csrow_enabled(i, 1, pvt))
+			csrow->nr_pages += amd64_csrow_nr_pages(pvt, 1, i);
 		find_csrow_limits(mci, i, &input_addr_min, &input_addr_max);
 		sys_addr = input_addr_to_sys_addr(mci, input_addr_min);
 		csrow->first_page = (u32) (sys_addr >> PAGE_SHIFT);
@@ -2685,7 +2707,7 @@
  * PCI core identifies what devices are on a system during boot, and then
  * inquiry this table to see if this driver is for a given device found.
  */
-static const struct pci_device_id amd64_pci_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(amd64_pci_table) = {
 	{
 		.vendor		= PCI_VENDOR_ID_AMD,
 		.device		= PCI_DEVICE_ID_AMD_K8_NB_MEMCTL,
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c
index e47e73b..f8fd3c8 100644
--- a/drivers/edac/amd76x_edac.c
+++ b/drivers/edac/amd76x_edac.c
@@ -321,7 +321,7 @@
 	edac_mc_free(mci);
 }
 
-static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(amd76x_pci_tbl) = {
 	{
 	 PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	 AMD762},
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 1af531a..4122326 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -1380,7 +1380,7 @@
 	edac_mc_free(mci);
 }
 
-static const struct pci_device_id e752x_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(e752x_pci_tbl) = {
 	{
 	 PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	 E7520},
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c
index 6ffb6d2..68dea87 100644
--- a/drivers/edac/e7xxx_edac.c
+++ b/drivers/edac/e7xxx_edac.c
@@ -525,7 +525,7 @@
 	edac_mc_free(mci);
 }
 
-static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(e7xxx_pci_tbl) = {
 	{
 	 PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	 E7205},
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index da09cd7..feef773 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -39,7 +39,7 @@
 
 #ifdef CONFIG_EDAC_DEBUG
 
-static void edac_mc_dump_channel(struct channel_info *chan)
+static void edac_mc_dump_channel(struct rank_info *chan)
 {
 	debugf4("\tchannel = %p\n", chan);
 	debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx);
@@ -156,7 +156,7 @@
 {
 	struct mem_ctl_info *mci;
 	struct csrow_info *csi, *csrow;
-	struct channel_info *chi, *chp, *chan;
+	struct rank_info *chi, *chp, *chan;
 	void *pvt;
 	unsigned size;
 	int row, chn;
@@ -181,7 +181,7 @@
 	 * rather than an imaginary chunk of memory located at address 0.
 	 */
 	csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi));
-	chi = (struct channel_info *)(((char *)mci) + ((unsigned long)chi));
+	chi = (struct rank_info *)(((char *)mci) + ((unsigned long)chi));
 	pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;
 
 	/* setup index and various internal pointers */
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index d56e634..e9a28f5 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -452,7 +452,7 @@
 	int new_bw = 0;
 
 	if (!mci->set_sdram_scrub_rate)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (strict_strtoul(data, 10, &bandwidth) < 0)
 		return -EINVAL;
@@ -475,7 +475,7 @@
 	int bandwidth = 0;
 
 	if (!mci->get_sdram_scrub_rate)
-		return -EINVAL;
+		return -ENODEV;
 
 	bandwidth = mci->get_sdram_scrub_rate(mci);
 	if (bandwidth < 0) {
diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c
index 670c448..6c86f6e 100644
--- a/drivers/edac/edac_stub.c
+++ b/drivers/edac/edac_stub.c
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/edac.h>
 #include <linux/atomic.h>
+#include <linux/device.h>
 #include <asm/edac.h>
 
 int edac_op_state = EDAC_OPSTATE_INVAL;
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c
index c0510b3..277689a 100644
--- a/drivers/edac/i3000_edac.c
+++ b/drivers/edac/i3000_edac.c
@@ -470,7 +470,7 @@
 	edac_mc_free(mci);
 }
 
-static const struct pci_device_id i3000_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i3000_pci_tbl) = {
 	{
 	 PCI_VEND_DEV(INTEL, 3000_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	 I3000},
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c
index 73f55e200..046808c 100644
--- a/drivers/edac/i3200_edac.c
+++ b/drivers/edac/i3200_edac.c
@@ -445,7 +445,7 @@
 	edac_mc_free(mci);
 }
 
-static const struct pci_device_id i3200_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i3200_pci_tbl) = {
 	{
 		PCI_VEND_DEV(INTEL, 3200_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 		I3200},
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index 4dc3ac2..a2680d8 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
@@ -1516,7 +1516,7 @@
  *
  *	The "E500P" device is the first device supported.
  */
-static const struct pci_device_id i5000_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i5000_pci_tbl) = {
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I5000_DEV16),
 	 .driver_data = I5000P},
 
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index bcbdeec..d500749 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
@@ -49,7 +49,7 @@
 #define		I5100_FERR_NF_MEM_M6ERR_MASK	(1 << 6)
 #define		I5100_FERR_NF_MEM_M5ERR_MASK	(1 << 5)
 #define		I5100_FERR_NF_MEM_M4ERR_MASK	(1 << 4)
-#define		I5100_FERR_NF_MEM_M1ERR_MASK	1
+#define		I5100_FERR_NF_MEM_M1ERR_MASK	(1 << 1)
 #define		I5100_FERR_NF_MEM_ANY_MASK	\
 			(I5100_FERR_NF_MEM_M16ERR_MASK | \
 			I5100_FERR_NF_MEM_M15ERR_MASK | \
@@ -535,23 +535,20 @@
 static void i5100_check_error(struct mem_ctl_info *mci)
 {
 	struct i5100_priv *priv = mci->pvt_info;
-	u32 dw;
-
+	u32 dw, dw2;
 
 	pci_read_config_dword(priv->mc, I5100_FERR_NF_MEM, &dw);
 	if (i5100_ferr_nf_mem_any(dw)) {
-		u32 dw2;
 
 		pci_read_config_dword(priv->mc, I5100_NERR_NF_MEM, &dw2);
-		if (dw2)
-			pci_write_config_dword(priv->mc, I5100_NERR_NF_MEM,
-					       dw2);
-		pci_write_config_dword(priv->mc, I5100_FERR_NF_MEM, dw);
 
 		i5100_read_log(mci, i5100_ferr_nf_mem_chan_indx(dw),
 			       i5100_ferr_nf_mem_any(dw),
 			       i5100_nerr_nf_mem_any(dw2));
+
+		pci_write_config_dword(priv->mc, I5100_NERR_NF_MEM, dw2);
 	}
+	pci_write_config_dword(priv->mc, I5100_FERR_NF_MEM, dw);
 }
 
 /* The i5100 chipset will scrub the entire memory once, then
@@ -1051,7 +1048,7 @@
 	edac_mc_free(mci);
 }
 
-static const struct pci_device_id i5100_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i5100_pci_tbl) = {
 	/* Device 16, Function 0, Channel 0 Memory Map, Error Flag/Mask, ... */
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5100_16) },
 	{ 0, }
diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c
index 74d6ec34..1869a10 100644
--- a/drivers/edac/i5400_edac.c
+++ b/drivers/edac/i5400_edac.c
@@ -735,7 +735,7 @@
 
 	/* Attempt to 'get' the MCH register we want */
 	pdev = NULL;
-	while (!pvt->branchmap_werrors || !pvt->fsb_error_regs) {
+	while (1) {
 		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
 				      PCI_DEVICE_ID_INTEL_5400_ERR, pdev);
 		if (!pdev) {
@@ -743,23 +743,42 @@
 			i5400_printk(KERN_ERR,
 				"'system address,Process Bus' "
 				"device not found:"
-				"vendor 0x%x device 0x%x ERR funcs "
+				"vendor 0x%x device 0x%x ERR func 1 "
 				"(broken BIOS?)\n",
 				PCI_VENDOR_ID_INTEL,
 				PCI_DEVICE_ID_INTEL_5400_ERR);
-			goto error;
+			return -ENODEV;
 		}
 
-		/* Store device 16 funcs 1 and 2 */
-		switch (PCI_FUNC(pdev->devfn)) {
-		case 1:
-			pvt->branchmap_werrors = pdev;
+		/* Store device 16 func 1 */
+		if (PCI_FUNC(pdev->devfn) == 1)
 			break;
-		case 2:
-			pvt->fsb_error_regs = pdev;
-			break;
-		}
 	}
+	pvt->branchmap_werrors = pdev;
+
+	pdev = NULL;
+	while (1) {
+		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+				      PCI_DEVICE_ID_INTEL_5400_ERR, pdev);
+		if (!pdev) {
+			/* End of list, leave */
+			i5400_printk(KERN_ERR,
+				"'system address,Process Bus' "
+				"device not found:"
+				"vendor 0x%x device 0x%x ERR func 2 "
+				"(broken BIOS?)\n",
+				PCI_VENDOR_ID_INTEL,
+				PCI_DEVICE_ID_INTEL_5400_ERR);
+
+			pci_dev_put(pvt->branchmap_werrors);
+			return -ENODEV;
+		}
+
+		/* Store device 16 func 2 */
+		if (PCI_FUNC(pdev->devfn) == 2)
+			break;
+	}
+	pvt->fsb_error_regs = pdev;
 
 	debugf1("System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
 		pci_name(pvt->system_address),
@@ -778,7 +797,10 @@
 			"MC: 'BRANCH 0' device not found:"
 			"vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n",
 			PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_FBD0);
-		goto error;
+
+		pci_dev_put(pvt->fsb_error_regs);
+		pci_dev_put(pvt->branchmap_werrors);
+		return -ENODEV;
 	}
 
 	/* If this device claims to have more than 2 channels then
@@ -796,14 +818,14 @@
 			"(broken BIOS?)\n",
 			PCI_VENDOR_ID_INTEL,
 			PCI_DEVICE_ID_INTEL_5400_FBD1);
-		goto error;
+
+		pci_dev_put(pvt->branch_0);
+		pci_dev_put(pvt->fsb_error_regs);
+		pci_dev_put(pvt->branchmap_werrors);
+		return -ENODEV;
 	}
 
 	return 0;
-
-error:
-	i5400_put_devices(mci);
-	return -ENODEV;
 }
 
 /*
@@ -1383,7 +1405,7 @@
  *
  *	The "E500P" device is the first device supported.
  */
-static const struct pci_device_id i5400_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i5400_pci_tbl) = {
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_ERR)},
 	{0,}			/* 0 terminated list. */
 };
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
index 6104dba..3bafa3b 100644
--- a/drivers/edac/i7300_edac.c
+++ b/drivers/edac/i7300_edac.c
@@ -1192,7 +1192,7 @@
  *
  * Has only 8086:360c PCI ID
  */
-static const struct pci_device_id i7300_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i7300_pci_tbl) = {
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_ERR)},
 	{0,}			/* 0 terminated list. */
 };
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 8568d9b..85226cc 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -391,7 +391,7 @@
 /*
  *	pci_device_id	table for which devices we are looking for
  */
-static const struct pci_device_id i7core_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i7core_pci_tbl) = {
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)},
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0)},
 	{0,}			/* 0 terminated list. */
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c
index 4329d39..3bf2b2f 100644
--- a/drivers/edac/i82443bxgx_edac.c
+++ b/drivers/edac/i82443bxgx_edac.c
@@ -380,7 +380,7 @@
 
 EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_remove_one);
 
-static const struct pci_device_id i82443bxgx_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i82443bxgx_pci_tbl) = {
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0)},
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2)},
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0)},
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c
index 931a057..c779092 100644
--- a/drivers/edac/i82860_edac.c
+++ b/drivers/edac/i82860_edac.c
@@ -270,7 +270,7 @@
 	edac_mc_free(mci);
 }
 
-static const struct pci_device_id i82860_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i82860_pci_tbl) = {
 	{
 	 PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	 I82860},
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index 33864c6..10f15d8 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -511,7 +511,7 @@
 	edac_mc_free(mci);
 }
 
-static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i82875p_pci_tbl) = {
 	{
 	 PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	 I82875P},
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
index 4184e01..0cd8368 100644
--- a/drivers/edac/i82975x_edac.c
+++ b/drivers/edac/i82975x_edac.c
@@ -612,7 +612,7 @@
 	edac_mc_free(mci);
 }
 
-static const struct pci_device_id i82975x_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i82975x_pci_tbl) = {
 	{
 		PCI_VEND_DEV(INTEL, 82975_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 		I82975X
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index bd926ea..d0c372e 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -39,42 +39,31 @@
  */
 
 /* transaction type */
-const char *tt_msgs[] = { "INSN", "DATA", "GEN", "RESV" };
+const char * const tt_msgs[] = { "INSN", "DATA", "GEN", "RESV" };
 EXPORT_SYMBOL_GPL(tt_msgs);
 
 /* cache level */
-const char *ll_msgs[] = { "RESV", "L1", "L2", "L3/GEN" };
+const char * const ll_msgs[] = { "RESV", "L1", "L2", "L3/GEN" };
 EXPORT_SYMBOL_GPL(ll_msgs);
 
 /* memory transaction type */
-const char *rrrr_msgs[] = {
+const char * const rrrr_msgs[] = {
        "GEN", "RD", "WR", "DRD", "DWR", "IRD", "PRF", "EV", "SNP"
 };
 EXPORT_SYMBOL_GPL(rrrr_msgs);
 
 /* participating processor */
-const char *pp_msgs[] = { "SRC", "RES", "OBS", "GEN" };
+const char * const pp_msgs[] = { "SRC", "RES", "OBS", "GEN" };
 EXPORT_SYMBOL_GPL(pp_msgs);
 
 /* request timeout */
-const char *to_msgs[] = { "no timeout",	"timed out" };
+const char * const to_msgs[] = { "no timeout", "timed out" };
 EXPORT_SYMBOL_GPL(to_msgs);
 
 /* memory or i/o */
-const char *ii_msgs[] = { "MEM", "RESV", "IO", "GEN" };
+const char * const ii_msgs[] = { "MEM", "RESV", "IO", "GEN" };
 EXPORT_SYMBOL_GPL(ii_msgs);
 
-static const char *f10h_nb_mce_desc[] = {
-	"HT link data error",
-	"Protocol error (link, L3, probe filter, etc.)",
-	"Parity error in NB-internal arrays",
-	"Link Retry due to IO link transmission error",
-	"L3 ECC data cache error",
-	"ECC error in L3 cache tag",
-	"L3 LRU parity bits error",
-	"ECC Error in the Probe Filter directory"
-};
-
 static const char * const f15h_ic_mce_desc[] = {
 	"UC during a demand linefill from L2",
 	"Parity error during data load from IC",
@@ -88,7 +77,7 @@
 	"Parity error for IC probe tag valid bit",
 	"PFB non-cacheable bit parity error",
 	"PFB valid bit parity error",			/* xec = 0xd */
-	"patch RAM",					/* xec = 010 */
+	"Microcode Patch Buffer",			/* xec = 010 */
 	"uop queue",
 	"insn buffer",
 	"predecode buffer",
@@ -104,7 +93,7 @@
 	"WCC Tag ECC error",
 	"WCC Data ECC error",
 	"WCB Data parity error",
-	"VB Data/ECC error",
+	"VB Data ECC or parity error",
 	"L2 Tag ECC error",				/* xec = 0x10 */
 	"Hard L2 Tag ECC error",
 	"Multiple hits on L2 tag",
@@ -112,6 +101,28 @@
 	"PRB address parity error"
 };
 
+static const char * const nb_mce_desc[] = {
+	"DRAM ECC error detected on the NB",
+	"CRC error detected on HT link",
+	"Link-defined sync error packets detected on HT link",
+	"HT Master abort",
+	"HT Target abort",
+	"Invalid GART PTE entry during GART table walk",
+	"Unsupported atomic RMW received from an IO link",
+	"Watchdog timeout due to lack of progress",
+	"DRAM ECC error detected on the NB",
+	"SVM DMA Exclusion Vector error",
+	"HT data error detected on link",
+	"Protocol error (link, L3, probe filter)",
+	"NB internal arrays parity error",
+	"DRAM addr/ctl signals parity error",
+	"IO link transmission error",
+	"L3 data cache ECC error",			/* xec = 0x1c */
+	"L3 cache tag error",
+	"L3 LRU parity bits error",
+	"ECC Error in the Probe Filter directory"
+};
+
 static const char * const fr_ex_mce_desc[] = {
 	"CPU Watchdog timer expire",
 	"Wakeup array dest tag",
@@ -125,7 +136,7 @@
 	"Physical register file AG0 port",
 	"Physical register file AG1 port",
 	"Flag register file",
-	"DE correctable error could not be corrected"
+	"DE error occurred"
 };
 
 static bool f12h_dc_mce(u16 ec, u8 xec)
@@ -255,10 +266,9 @@
 	} else if (BUS_ERROR(ec)) {
 
 		if (!xec)
-			pr_cont("during system linefill.\n");
+			pr_cont("System Read Data Error.\n");
 		else
-			pr_cont(" Internal %s condition.\n",
-				((xec == 1) ? "livelock" : "deadlock"));
+			pr_cont(" Internal error condition type %d.\n", xec);
 	} else
 		ret = false;
 
@@ -355,7 +365,11 @@
 		pr_cont("%s.\n", f15h_ic_mce_desc[xec-2]);
 		break;
 
-	case 0x10 ... 0x14:
+	case 0x10:
+		pr_cont("%s.\n", f15h_ic_mce_desc[xec-4]);
+		break;
+
+	case 0x11 ... 0x14:
 		pr_cont("Decoder %s parity error.\n", f15h_ic_mce_desc[xec-4]);
 		break;
 
@@ -496,58 +510,31 @@
 	pr_emerg(HW_ERR "Corrupted LS MCE info?\n");
 }
 
-static bool k8_nb_mce(u16 ec, u8 xec)
+void amd_decode_nb_mce(struct mce *m)
 {
-	bool ret = true;
-
-	switch (xec) {
-	case 0x1:
-		pr_cont("CRC error detected on HT link.\n");
-		break;
-
-	case 0x5:
-		pr_cont("Invalid GART PTE entry during GART table walk.\n");
-		break;
-
-	case 0x6:
-		pr_cont("Unsupported atomic RMW received from an IO link.\n");
-		break;
-
-	case 0x0:
-	case 0x8:
-		if (boot_cpu_data.x86 == 0x11)
-			return false;
-
-		pr_cont("DRAM ECC error detected on the NB.\n");
-		break;
-
-	case 0xd:
-		pr_cont("Parity error on the DRAM addr/ctl signals.\n");
-		break;
-
-	default:
-		ret = false;
-		break;
-	}
-
-	return ret;
-}
-
-static bool f10h_nb_mce(u16 ec, u8 xec)
-{
-	bool ret = true;
+	struct cpuinfo_x86 *c = &boot_cpu_data;
+	int node_id = amd_get_nb_id(m->extcpu);
+	u16 ec = EC(m->status);
+	u8 xec = XEC(m->status, 0x1f);
 	u8 offset = 0;
 
-	if (k8_nb_mce(ec, xec))
-		return true;
+	pr_emerg(HW_ERR "Northbridge Error (node %d): ", node_id);
 
-	switch(xec) {
-	case 0xa ... 0xc:
-		offset = 10;
-		break;
+	switch (xec) {
+	case 0x0 ... 0xe:
 
-	case 0xe:
-		offset = 11;
+		/* special handling for DRAM ECCs */
+		if (xec == 0x0 || xec == 0x8) {
+			/* no ECCs on F11h */
+			if (c->x86 == 0x11)
+				goto wrong_nb_mce;
+
+			pr_cont("%s.\n", nb_mce_desc[xec]);
+
+			if (nb_bus_decoder)
+				nb_bus_decoder(node_id, m);
+			return;
+		}
 		break;
 
 	case 0xf:
@@ -556,83 +543,25 @@
 		else if (BUS_ERROR(ec))
 			pr_cont("DMA Exclusion Vector Table Walk error.\n");
 		else
-			ret = false;
-
-		goto out;
-		break;
+			goto wrong_nb_mce;
+		return;
 
 	case 0x19:
 		if (boot_cpu_data.x86 == 0x15)
 			pr_cont("Compute Unit Data Error.\n");
 		else
-			ret = false;
-
-		goto out;
-		break;
+			goto wrong_nb_mce;
+		return;
 
 	case 0x1c ... 0x1f:
-		offset = 24;
+		offset = 13;
 		break;
 
 	default:
-		ret = false;
-
-		goto out;
-		break;
-	}
-
-	pr_cont("%s.\n", f10h_nb_mce_desc[xec - offset]);
-
-out:
-	return ret;
-}
-
-static bool nb_noop_mce(u16 ec, u8 xec)
-{
-	return false;
-}
-
-void amd_decode_nb_mce(struct mce *m)
-{
-	struct cpuinfo_x86 *c = &boot_cpu_data;
-	int node_id = amd_get_nb_id(m->extcpu);
-	u16 ec = EC(m->status);
-	u8 xec = XEC(m->status, 0x1f);
-
-	pr_emerg(HW_ERR "Northbridge Error (node %d): ", node_id);
-
-	switch (xec) {
-	case 0x2:
-		pr_cont("Sync error (sync packets on HT link detected).\n");
-		return;
-
-	case 0x3:
-		pr_cont("HT Master abort.\n");
-		return;
-
-	case 0x4:
-		pr_cont("HT Target abort.\n");
-		return;
-
-	case 0x7:
-		pr_cont("NB Watchdog timeout.\n");
-		return;
-
-	case 0x9:
-		pr_cont("SVM DMA Exclusion Vector error.\n");
-		return;
-
-	default:
-		break;
-	}
-
-	if (!fam_ops->nb_mce(ec, xec))
 		goto wrong_nb_mce;
+	}
 
-	if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x15)
-		if ((xec == 0x8 || xec == 0x0) && nb_bus_decoder)
-			nb_bus_decoder(node_id, m);
-
+	pr_cont("%s.\n", nb_mce_desc[xec - offset]);
 	return;
 
 wrong_nb_mce:
@@ -648,9 +577,6 @@
 	if (c->x86 == 0xf || c->x86 == 0x11)
 		goto wrong_fr_mce;
 
-	if (c->x86 != 0x15 && xec != 0x0)
-		goto wrong_fr_mce;
-
 	pr_emerg(HW_ERR "%s Error: ",
 		 (c->x86 == 0x15 ? "Execution Unit" : "FIROB"));
 
@@ -828,9 +754,7 @@
 	if (c->x86_vendor != X86_VENDOR_AMD)
 		return 0;
 
-	if ((c->x86 < 0xf || c->x86 > 0x12) &&
-	    (c->x86 != 0x14 || c->x86_model > 0xf) &&
-	    (c->x86 != 0x15 || c->x86_model > 0xf))
+	if (c->x86 < 0xf || c->x86 > 0x15)
 		return 0;
 
 	fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL);
@@ -841,43 +765,37 @@
 	case 0xf:
 		fam_ops->dc_mce = k8_dc_mce;
 		fam_ops->ic_mce = k8_ic_mce;
-		fam_ops->nb_mce = k8_nb_mce;
 		break;
 
 	case 0x10:
 		fam_ops->dc_mce = f10h_dc_mce;
 		fam_ops->ic_mce = k8_ic_mce;
-		fam_ops->nb_mce = f10h_nb_mce;
 		break;
 
 	case 0x11:
 		fam_ops->dc_mce = k8_dc_mce;
 		fam_ops->ic_mce = k8_ic_mce;
-		fam_ops->nb_mce = f10h_nb_mce;
 		break;
 
 	case 0x12:
 		fam_ops->dc_mce = f12h_dc_mce;
 		fam_ops->ic_mce = k8_ic_mce;
-		fam_ops->nb_mce = nb_noop_mce;
 		break;
 
 	case 0x14:
 		nb_err_cpumask  = 0x3;
 		fam_ops->dc_mce = f14h_dc_mce;
 		fam_ops->ic_mce = f14h_ic_mce;
-		fam_ops->nb_mce = nb_noop_mce;
 		break;
 
 	case 0x15:
 		xec_mask = 0x1f;
 		fam_ops->dc_mce = f15h_dc_mce;
 		fam_ops->ic_mce = f15h_ic_mce;
-		fam_ops->nb_mce = f10h_nb_mce;
 		break;
 
 	default:
-		printk(KERN_WARNING "Huh? What family is that: %d?!\n", c->x86);
+		printk(KERN_WARNING "Huh? What family is it: 0x%x?!\n", c->x86);
 		kfree(fam_ops);
 		return -EINVAL;
 	}
diff --git a/drivers/edac/mce_amd.h b/drivers/edac/mce_amd.h
index 0106747..c6074c5 100644
--- a/drivers/edac/mce_amd.h
+++ b/drivers/edac/mce_amd.h
@@ -69,12 +69,12 @@
 	R4_SNOOP,
 };
 
-extern const char *tt_msgs[];
-extern const char *ll_msgs[];
-extern const char *rrrr_msgs[];
-extern const char *pp_msgs[];
-extern const char *to_msgs[];
-extern const char *ii_msgs[];
+extern const char * const tt_msgs[];
+extern const char * const ll_msgs[];
+extern const char * const rrrr_msgs[];
+extern const char * const pp_msgs[];
+extern const char * const to_msgs[];
+extern const char * const ii_msgs[];
 
 /*
  * per-family decoder ops
@@ -82,7 +82,6 @@
 struct amd_decoder_ops {
 	bool (*dc_mce)(u16, u8);
 	bool (*ic_mce)(u16, u8);
-	bool (*nb_mce)(u16, u8);
 };
 
 void amd_report_gart_errors(bool);
diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c
index 885e8ad..66b5151 100644
--- a/drivers/edac/mce_amd_inj.c
+++ b/drivers/edac/mce_amd_inj.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/kobject.h>
+#include <linux/device.h>
 #include <linux/edac.h>
 #include <linux/module.h>
 #include <asm/mce.h>
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c
index fc75706..d427c69 100644
--- a/drivers/edac/ppc4xx_edac.c
+++ b/drivers/edac/ppc4xx_edac.c
@@ -184,7 +184,7 @@
 
 /* Function Prototypes */
 
-static int ppc4xx_edac_probe(struct platform_device *device)
+static int ppc4xx_edac_probe(struct platform_device *device);
 static int ppc4xx_edac_remove(struct platform_device *device);
 
 /* Global Variables */
@@ -1068,7 +1068,7 @@
 
 	mci->mod_name		= PPC4XX_EDAC_MODULE_NAME;
 	mci->mod_ver		= PPC4XX_EDAC_MODULE_REVISION;
-	mci->ctl_name		= match->compatible,
+	mci->ctl_name		= ppc4xx_edac_match->compatible,
 	mci->dev_name		= np->full_name;
 
 	/* Initialize callbacks */
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c
index e294e1b..6d908ad 100644
--- a/drivers/edac/r82600_edac.c
+++ b/drivers/edac/r82600_edac.c
@@ -373,7 +373,7 @@
 	edac_mc_free(mci);
 }
 
-static const struct pci_device_id r82600_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(r82600_pci_tbl) = {
 	{
 	 PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
 	 },
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 1dc118d..a203536 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -20,6 +20,7 @@
 #include <linux/mmzone.h>
 #include <linux/smp.h>
 #include <linux/bitmap.h>
+#include <linux/math64.h>
 #include <asm/processor.h>
 #include <asm/mce.h>
 
@@ -367,7 +368,7 @@
 /*
  *	pci_device_id	table for which devices we are looking for
  */
-static const struct pci_device_id sbridge_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(sbridge_pci_tbl) = {
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)},
 	{0,}			/* 0 terminated list. */
 };
@@ -670,6 +671,7 @@
 	u32 reg;
 	u64 limit, prv = 0;
 	u64 tmp_mb;
+	u32 mb, kb;
 	u32 rir_way;
 
 	/*
@@ -682,8 +684,9 @@
 	pvt->tolm = GET_TOLM(reg);
 	tmp_mb = (1 + pvt->tolm) >> 20;
 
-	debugf0("TOLM: %Lu.%03Lu GB (0x%016Lx)\n",
-		tmp_mb / 1000, tmp_mb % 1000, (u64)pvt->tolm);
+	mb = div_u64_rem(tmp_mb, 1000, &kb);
+	debugf0("TOLM: %u.%03u GB (0x%016Lx)\n",
+		mb, kb, (u64)pvt->tolm);
 
 	/* Address range is already 45:25 */
 	pci_read_config_dword(pvt->pci_sad1, TOHM,
@@ -691,8 +694,9 @@
 	pvt->tohm = GET_TOHM(reg);
 	tmp_mb = (1 + pvt->tohm) >> 20;
 
-	debugf0("TOHM: %Lu.%03Lu GB (0x%016Lx)",
-		tmp_mb / 1000, tmp_mb % 1000, (u64)pvt->tohm);
+	mb = div_u64_rem(tmp_mb, 1000, &kb);
+	debugf0("TOHM: %u.%03u GB (0x%016Lx)",
+		mb, kb, (u64)pvt->tohm);
 
 	/*
 	 * Step 2) Get SAD range and SAD Interleave list
@@ -714,10 +718,11 @@
 			break;
 
 		tmp_mb = (limit + 1) >> 20;
-		debugf0("SAD#%d %s up to %Lu.%03Lu GB (0x%016Lx) %s reg=0x%08x\n",
+		mb = div_u64_rem(tmp_mb, 1000, &kb);
+		debugf0("SAD#%d %s up to %u.%03u GB (0x%016Lx) %s reg=0x%08x\n",
 			n_sads,
 			get_dram_attr(reg),
-			tmp_mb / 1000, tmp_mb % 1000,
+			mb, kb,
 			((u64)tmp_mb) << 20L,
 			INTERLEAVE_MODE(reg) ? "Interleave: 8:6" : "Interleave: [8:6]XOR[18:16]",
 			reg);
@@ -747,8 +752,9 @@
 			break;
 		tmp_mb = (limit + 1) >> 20;
 
-		debugf0("TAD#%d: up to %Lu.%03Lu GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n",
-			n_tads, tmp_mb / 1000, tmp_mb % 1000,
+		mb = div_u64_rem(tmp_mb, 1000, &kb);
+		debugf0("TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n",
+			n_tads, mb, kb,
 			((u64)tmp_mb) << 20L,
 			(u32)TAD_SOCK(reg),
 			(u32)TAD_CH(reg),
@@ -757,7 +763,7 @@
 			(u32)TAD_TGT2(reg),
 			(u32)TAD_TGT3(reg),
 			reg);
-		prv = tmp_mb;
+		prv = limit;
 	}
 
 	/*
@@ -771,9 +777,10 @@
 					      tad_ch_nilv_offset[j],
 					      &reg);
 			tmp_mb = TAD_OFFSET(reg) >> 20;
-			debugf0("TAD CH#%d, offset #%d: %Lu.%03Lu GB (0x%016Lx), reg=0x%08x\n",
+			mb = div_u64_rem(tmp_mb, 1000, &kb);
+			debugf0("TAD CH#%d, offset #%d: %u.%03u GB (0x%016Lx), reg=0x%08x\n",
 				i, j,
-				tmp_mb / 1000, tmp_mb % 1000,
+				mb, kb,
 				((u64)tmp_mb) << 20L,
 				reg);
 		}
@@ -795,9 +802,10 @@
 
 			tmp_mb = RIR_LIMIT(reg) >> 20;
 			rir_way = 1 << RIR_WAY(reg);
-			debugf0("CH#%d RIR#%d, limit: %Lu.%03Lu GB (0x%016Lx), way: %d, reg=0x%08x\n",
+			mb = div_u64_rem(tmp_mb, 1000, &kb);
+			debugf0("CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n",
 				i, j,
-				tmp_mb / 1000, tmp_mb % 1000,
+				mb, kb,
 				((u64)tmp_mb) << 20L,
 				rir_way,
 				reg);
@@ -808,9 +816,10 @@
 						      &reg);
 				tmp_mb = RIR_OFFSET(reg) << 6;
 
-				debugf0("CH#%d RIR#%d INTL#%d, offset %Lu.%03Lu GB (0x%016Lx), tgt: %d, reg=0x%08x\n",
+				mb = div_u64_rem(tmp_mb, 1000, &kb);
+				debugf0("CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n",
 					i, j, k,
-					tmp_mb / 1000, tmp_mb % 1000,
+					mb, kb,
 					((u64)tmp_mb) << 20L,
 					(u32)RIR_RNK_TGT(reg),
 					reg);
@@ -848,6 +857,7 @@
 	u8			ch_way,sck_way;
 	u32			tad_offset;
 	u32			rir_way;
+	u32			mb, kb;
 	u64			ch_addr, offset, limit, prv = 0;
 
 
@@ -858,7 +868,7 @@
 	 * range (e. g. VGA addresses). It is unlikely, however, that the
 	 * memory controller would generate an error on that range.
 	 */
-	if ((addr > (u64) pvt->tolm) && (addr < (1L << 32))) {
+	if ((addr > (u64) pvt->tolm) && (addr < (1LL << 32))) {
 		sprintf(msg, "Error at TOLM area, on addr 0x%08Lx", addr);
 		edac_mc_handle_ce_no_info(mci, msg);
 		return -EINVAL;
@@ -913,7 +923,7 @@
 		addr,
 		limit,
 		sad_way + 7,
-		INTERLEAVE_MODE(reg) ? "" : "XOR[18:16]");
+		interleave_mode ? "" : "XOR[18:16]");
 	if (interleave_mode)
 		idx = ((addr >> 6) ^ (addr >> 16)) & 7;
 	else
@@ -1053,7 +1063,7 @@
 	ch_addr = addr & 0x7f;
 	/* Remove socket wayness and remove 6 bits */
 	addr >>= 6;
-	addr /= sck_xch;
+	addr = div_u64(addr, sck_xch);
 #if 0
 	/* Divide by channel way */
 	addr = addr / ch_way;
@@ -1073,10 +1083,10 @@
 			continue;
 
 		limit = RIR_LIMIT(reg);
-
-		debugf0("RIR#%d, limit: %Lu.%03Lu GB (0x%016Lx), way: %d\n",
+		mb = div_u64_rem(limit >> 20, 1000, &kb);
+		debugf0("RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n",
 			n_rir,
-			(limit >> 20) / 1000, (limit >> 20) % 1000,
+			mb, kb,
 			limit,
 			1 << RIR_WAY(reg));
 		if  (ch_addr <= limit)
diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c
index b6f47de..a438297 100644
--- a/drivers/edac/x38_edac.c
+++ b/drivers/edac/x38_edac.c
@@ -440,7 +440,7 @@
 	edac_mc_free(mci);
 }
 
-static const struct pci_device_id x38_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(x38_pci_tbl) = {
 	{
 	 PCI_VEND_DEV(INTEL, X38_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	 X38},
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index 2be6f45..7224533 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -28,11 +28,6 @@
 	  To compile this driver as a module, say M here:  The module will be
 	  called firewire-ohci.
 
-config FIREWIRE_OHCI_DEBUG
-	bool
-	depends on FIREWIRE_OHCI
-	default y
-
 config FIREWIRE_SBP2
 	tristate "Storage devices (SBP-2 protocol)"
 	depends on FIREWIRE && SCSI
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index 85661b0..cc595eb 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -37,6 +37,22 @@
 
 #include "core.h"
 
+#define define_fw_printk_level(func, kern_level)		\
+void func(const struct fw_card *card, const char *fmt, ...)	\
+{								\
+	struct va_format vaf;					\
+	va_list args;						\
+								\
+	va_start(args, fmt);					\
+	vaf.fmt = fmt;						\
+	vaf.va = &args;						\
+	printk(kern_level KBUILD_MODNAME " %s: %pV",		\
+	       dev_name(card->device), &vaf);			\
+	va_end(args);						\
+}
+define_fw_printk_level(fw_err, KERN_ERR);
+define_fw_printk_level(fw_notice, KERN_NOTICE);
+
 int fw_compute_block_crc(__be32 *block)
 {
 	int length;
@@ -260,7 +276,7 @@
 		fw_iso_resource_manage(card, generation, 1ULL << 31,
 				       &channel, &bandwidth, true);
 		if (channel != 31) {
-			fw_notify("failed to allocate broadcast channel\n");
+			fw_notice(card, "failed to allocate broadcast channel\n");
 			return;
 		}
 		card->broadcast_channel_allocated = true;
@@ -343,14 +359,14 @@
 
 		if (!card->irm_node->link_on) {
 			new_root_id = local_id;
-			fw_notify("%s, making local node (%02x) root.\n",
+			fw_notice(card, "%s, making local node (%02x) root\n",
 				  "IRM has link off", new_root_id);
 			goto pick_me;
 		}
 
 		if (irm_is_1394_1995_only && !keep_this_irm) {
 			new_root_id = local_id;
-			fw_notify("%s, making local node (%02x) root.\n",
+			fw_notice(card, "%s, making local node (%02x) root\n",
 				  "IRM is not 1394a compliant", new_root_id);
 			goto pick_me;
 		}
@@ -405,7 +421,7 @@
 			 * root, and thus, IRM.
 			 */
 			new_root_id = local_id;
-			fw_notify("%s, making local node (%02x) root.\n",
+			fw_notice(card, "%s, making local node (%02x) root\n",
 				  "BM lock failed", new_root_id);
 			goto pick_me;
 		}
@@ -478,8 +494,8 @@
 	spin_unlock_irq(&card->lock);
 
 	if (do_reset) {
-		fw_notify("phy config: card %d, new root=%x, gap_count=%d\n",
-			  card->index, new_root_id, gap_count);
+		fw_notice(card, "phy config: new root=%x, gap_count=%d\n",
+			  new_root_id, gap_count);
 		fw_send_phy_config(card, new_root_id, generation, gap_count);
 		reset_bus(card, true);
 		/* Will allocate broadcast channel after the reset. */
@@ -634,6 +650,11 @@
 {
 }
 
+static int dummy_flush_iso_completions(struct fw_iso_context *ctx)
+{
+	return -ENODEV;
+}
+
 static const struct fw_card_driver dummy_driver_template = {
 	.read_phy_reg		= dummy_read_phy_reg,
 	.update_phy_reg		= dummy_update_phy_reg,
@@ -646,6 +667,7 @@
 	.set_iso_channels	= dummy_set_iso_channels,
 	.queue_iso		= dummy_queue_iso,
 	.flush_queue_iso	= dummy_flush_queue_iso,
+	.flush_iso_completions	= dummy_flush_iso_completions,
 };
 
 void fw_card_release(struct kref *kref)
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 4799393..2e6b245 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -44,14 +44,13 @@
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 
-#include <asm/system.h>
 
 #include "core.h"
 
 /*
  * ABI version history is documented in linux/firewire-cdev.h.
  */
-#define FW_CDEV_KERNEL_VERSION			4
+#define FW_CDEV_KERNEL_VERSION			5
 #define FW_CDEV_VERSION_EVENT_REQUEST2		4
 #define FW_CDEV_VERSION_ALLOCATE_REGION_END	4
 
@@ -389,7 +388,7 @@
 
 	e = kzalloc(sizeof(*e), GFP_KERNEL);
 	if (e == NULL) {
-		fw_notify("Out of memory when allocating event\n");
+		fw_notice(client->device->card, "out of memory when allocating event\n");
 		return;
 	}
 
@@ -438,6 +437,7 @@
 	struct fw_cdev_send_phy_packet		send_phy_packet;
 	struct fw_cdev_receive_phy_packets	receive_phy_packets;
 	struct fw_cdev_set_iso_channels		set_iso_channels;
+	struct fw_cdev_flush_iso		flush_iso;
 };
 
 static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
@@ -691,7 +691,7 @@
 	r = kmalloc(sizeof(*r), GFP_ATOMIC);
 	e = kmalloc(sizeof(*e), GFP_ATOMIC);
 	if (r == NULL || e == NULL) {
-		fw_notify("Out of memory when allocating event\n");
+		fw_notice(card, "out of memory when allocating event\n");
 		goto failed;
 	}
 	r->card    = card;
@@ -928,7 +928,7 @@
 
 	e = kmalloc(sizeof(*e) + header_length, GFP_ATOMIC);
 	if (e == NULL) {
-		fw_notify("Out of memory when allocating event\n");
+		fw_notice(context->card, "out of memory when allocating event\n");
 		return;
 	}
 	e->interrupt.type      = FW_CDEV_EVENT_ISO_INTERRUPT;
@@ -948,7 +948,7 @@
 
 	e = kmalloc(sizeof(*e), GFP_ATOMIC);
 	if (e == NULL) {
-		fw_notify("Out of memory when allocating event\n");
+		fw_notice(context->card, "out of memory when allocating event\n");
 		return;
 	}
 	e->interrupt.type      = FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL;
@@ -1168,6 +1168,16 @@
 	return fw_iso_context_stop(client->iso_context);
 }
 
+static int ioctl_flush_iso(struct client *client, union ioctl_arg *arg)
+{
+	struct fw_cdev_flush_iso *a = &arg->flush_iso;
+
+	if (client->iso_context == NULL || a->handle != 0)
+		return -EINVAL;
+
+	return fw_iso_context_flush_completions(client->iso_context);
+}
+
 static int ioctl_get_cycle_timer2(struct client *client, union ioctl_arg *arg)
 {
 	struct fw_cdev_get_cycle_timer2 *a = &arg->get_cycle_timer2;
@@ -1548,7 +1558,7 @@
 	list_for_each_entry(client, &card->phy_receiver_list, phy_receiver_link) {
 		e = kmalloc(sizeof(*e) + 8, GFP_ATOMIC);
 		if (e == NULL) {
-			fw_notify("Out of memory when allocating event\n");
+			fw_notice(card, "out of memory when allocating event\n");
 			break;
 		}
 		e->phy_packet.closure	= client->phy_receiver_closure;
@@ -1589,6 +1599,7 @@
 	[0x15] = ioctl_send_phy_packet,
 	[0x16] = ioctl_receive_phy_packets,
 	[0x17] = ioctl_set_iso_channels,
+	[0x18] = ioctl_flush_iso,
 };
 
 static int dispatch_ioctl(struct client *client,
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index f3b890d..68109e9 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -40,7 +40,6 @@
 
 #include <linux/atomic.h>
 #include <asm/byteorder.h>
-#include <asm/system.h>
 
 #include "core.h"
 
@@ -485,6 +484,7 @@
  */
 static int read_config_rom(struct fw_device *device, int generation)
 {
+	struct fw_card *card = device->card;
 	const u32 *old_rom, *new_rom;
 	u32 *rom, *stack;
 	u32 sp, key;
@@ -529,12 +529,12 @@
 	 */
 	if ((rom[2] & 0x7) < device->max_speed ||
 	    device->max_speed == SCODE_BETA ||
-	    device->card->beta_repeaters_present) {
+	    card->beta_repeaters_present) {
 		u32 dummy;
 
 		/* for S1600 and S3200 */
 		if (device->max_speed == SCODE_BETA)
-			device->max_speed = device->card->link_speed;
+			device->max_speed = card->link_speed;
 
 		while (device->max_speed > SCODE_100) {
 			if (read_rom(device, generation, 0, &dummy) ==
@@ -576,9 +576,9 @@
 			 * a firmware bug.  Ignore this whole block, i.e.
 			 * simply set a fake block length of 0.
 			 */
-			fw_error("skipped invalid ROM block %x at %llx\n",
-				 rom[i],
-				 i * 4 | CSR_REGISTER_BASE | CSR_CONFIG_ROM);
+			fw_err(card, "skipped invalid ROM block %x at %llx\n",
+			       rom[i],
+			       i * 4 | CSR_REGISTER_BASE | CSR_CONFIG_ROM);
 			rom[i] = 0;
 			end = i;
 		}
@@ -604,9 +604,10 @@
 			 * the ROM don't have to check offsets all the time.
 			 */
 			if (i + (rom[i] & 0xffffff) >= MAX_CONFIG_ROM_SIZE) {
-				fw_error("skipped unsupported ROM entry %x at %llx\n",
-					 rom[i],
-					 i * 4 | CSR_REGISTER_BASE | CSR_CONFIG_ROM);
+				fw_err(card,
+				       "skipped unsupported ROM entry %x at %llx\n",
+				       rom[i],
+				       i * 4 | CSR_REGISTER_BASE | CSR_CONFIG_ROM);
 				rom[i] = 0;
 				continue;
 			}
@@ -641,6 +642,7 @@
 {
 	struct fw_unit *unit = fw_unit(dev);
 
+	fw_device_put(fw_parent_device(unit));
 	kfree(unit);
 }
 
@@ -672,7 +674,7 @@
 		 */
 		unit = kzalloc(sizeof(*unit), GFP_KERNEL);
 		if (unit == NULL) {
-			fw_error("failed to allocate memory for unit\n");
+			fw_err(device->card, "out of memory for unit\n");
 			continue;
 		}
 
@@ -692,6 +694,7 @@
 		if (device_register(&unit->device) < 0)
 			goto skip_unit;
 
+		fw_device_get(device);
 		continue;
 
 	skip_unit:
@@ -873,7 +876,7 @@
 		smp_wmb();  /* update node_id before generation */
 		old->generation = card->generation;
 		old->config_rom_retries = 0;
-		fw_notify("rediscovered device %s\n", dev_name(dev));
+		fw_notice(card, "rediscovered device %s\n", dev_name(dev));
 
 		PREPARE_DELAYED_WORK(&old->work, fw_device_update);
 		fw_schedule_device_work(old, 0);
@@ -954,6 +957,7 @@
 {
 	struct fw_device *device =
 		container_of(work, struct fw_device, work.work);
+	struct fw_card *card = device->card;
 	struct device *revived_dev;
 	int minor, ret;
 
@@ -970,16 +974,16 @@
 			fw_schedule_device_work(device, RETRY_DELAY);
 		} else {
 			if (device->node->link_on)
-				fw_notify("giving up on config rom for node id %x\n",
+				fw_notice(card, "giving up on Config ROM for node id %x\n",
 					  device->node_id);
-			if (device->node == device->card->root_node)
-				fw_schedule_bm_work(device->card, 0);
+			if (device->node == card->root_node)
+				fw_schedule_bm_work(card, 0);
 			fw_device_release(&device->device);
 		}
 		return;
 	}
 
-	revived_dev = device_find_child(device->card->device,
+	revived_dev = device_find_child(card->device,
 					device, lookup_existing_device);
 	if (revived_dev) {
 		put_device(revived_dev);
@@ -1002,7 +1006,7 @@
 
 	device->device.bus = &fw_bus_type;
 	device->device.type = &fw_device_type;
-	device->device.parent = device->card->device;
+	device->device.parent = card->device;
 	device->device.devt = MKDEV(fw_cdev_major, minor);
 	dev_set_name(&device->device, "fw%d", minor);
 
@@ -1014,7 +1018,7 @@
 				&device->attribute_group);
 
 	if (device_add(&device->device)) {
-		fw_error("Failed to add device.\n");
+		fw_err(card, "failed to add device\n");
 		goto error_with_cdev;
 	}
 
@@ -1035,18 +1039,10 @@
 		PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
 		fw_schedule_device_work(device, SHUTDOWN_DELAY);
 	} else {
-		if (device->config_rom_retries)
-			fw_notify("created device %s: GUID %08x%08x, S%d00, "
-				  "%d config ROM retries\n",
-				  dev_name(&device->device),
-				  device->config_rom[3], device->config_rom[4],
-				  1 << device->max_speed,
-				  device->config_rom_retries);
-		else
-			fw_notify("created device %s: GUID %08x%08x, S%d00\n",
-				  dev_name(&device->device),
-				  device->config_rom[3], device->config_rom[4],
-				  1 << device->max_speed);
+		fw_notice(card, "created device %s: GUID %08x%08x, S%d00\n",
+			  dev_name(&device->device),
+			  device->config_rom[3], device->config_rom[4],
+			  1 << device->max_speed);
 		device->config_rom_retries = 0;
 
 		set_broadcast_channel(device, device->generation);
@@ -1058,8 +1054,8 @@
 	 * just end up running the IRM work a couple of extra times -
 	 * pretty harmless.
 	 */
-	if (device->node == device->card->root_node)
-		fw_schedule_bm_work(device->card, 0);
+	if (device->node == card->root_node)
+		fw_schedule_bm_work(card, 0);
 
 	return;
 
@@ -1163,12 +1159,13 @@
 			   FW_DEVICE_RUNNING) == FW_DEVICE_GONE)
 		goto gone;
 
-	fw_notify("refreshed device %s\n", dev_name(&device->device));
+	fw_notice(card, "refreshed device %s\n", dev_name(&device->device));
 	device->config_rom_retries = 0;
 	goto out;
 
  give_up:
-	fw_notify("giving up on refresh of device %s\n", dev_name(&device->device));
+	fw_notice(card, "giving up on refresh of device %s\n",
+		  dev_name(&device->device));
  gone:
 	atomic_set(&device->state, FW_DEVICE_GONE);
 	PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c
index 0f90e00..d156582 100644
--- a/drivers/firewire/core-iso.c
+++ b/drivers/firewire/core-iso.c
@@ -192,6 +192,12 @@
 }
 EXPORT_SYMBOL(fw_iso_context_queue_flush);
 
+int fw_iso_context_flush_completions(struct fw_iso_context *ctx)
+{
+	return ctx->card->driver->flush_iso_completions(ctx);
+}
+EXPORT_SYMBOL(fw_iso_context_flush_completions);
+
 int fw_iso_context_stop(struct fw_iso_context *ctx)
 {
 	return ctx->card->driver->stop_iso(ctx);
diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c
index 94d3b49..0de8350 100644
--- a/drivers/firewire/core-topology.c
+++ b/drivers/firewire/core-topology.c
@@ -31,7 +31,6 @@
 
 #include <linux/atomic.h>
 #include <asm/byteorder.h>
-#include <asm/system.h>
 
 #include "core.h"
 
@@ -205,19 +204,19 @@
 		next_sid = count_ports(sid, &port_count, &child_port_count);
 
 		if (next_sid == NULL) {
-			fw_error("Inconsistent extended self IDs.\n");
+			fw_err(card, "inconsistent extended self IDs\n");
 			return NULL;
 		}
 
 		q = *sid;
 		if (phy_id != SELF_ID_PHY_ID(q)) {
-			fw_error("PHY ID mismatch in self ID: %d != %d.\n",
-				 phy_id, SELF_ID_PHY_ID(q));
+			fw_err(card, "PHY ID mismatch in self ID: %d != %d\n",
+			       phy_id, SELF_ID_PHY_ID(q));
 			return NULL;
 		}
 
 		if (child_port_count > stack_depth) {
-			fw_error("Topology stack underflow\n");
+			fw_err(card, "topology stack underflow\n");
 			return NULL;
 		}
 
@@ -235,7 +234,7 @@
 
 		node = fw_node_create(q, port_count, card->color);
 		if (node == NULL) {
-			fw_error("Out of memory while building topology.\n");
+			fw_err(card, "out of memory while building topology\n");
 			return NULL;
 		}
 
@@ -284,8 +283,8 @@
 		 */
 		if ((next_sid == end && parent_count != 0) ||
 		    (next_sid < end && parent_count != 1)) {
-			fw_error("Parent port inconsistency for node %d: "
-				 "parent_count=%d\n", phy_id, parent_count);
+			fw_err(card, "parent port inconsistency for node %d: "
+			       "parent_count=%d\n", phy_id, parent_count);
 			return NULL;
 		}
 
@@ -530,7 +529,6 @@
 	 */
 	if (!is_next_generation(generation, card->generation) &&
 	    card->local_node != NULL) {
-		fw_notify("skipped bus generations, destroying all nodes\n");
 		fw_destroy_nodes(card);
 		card->bm_retries = 0;
 	}
@@ -557,7 +555,7 @@
 	card->color++;
 
 	if (local_node == NULL) {
-		fw_error("topology build failed\n");
+		fw_err(card, "topology build failed\n");
 		/* FIXME: We need to issue a bus reset in this case. */
 	} else if (card->local_node == NULL) {
 		card->local_node = local_node;
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 855ab3f..dea2dcc 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -565,7 +565,6 @@
 				const struct fw_address_region *region)
 {
 	struct fw_address_handler *other;
-	unsigned long flags;
 	int ret = -EBUSY;
 
 	if (region->start & 0xffff000000000003ULL ||
@@ -575,7 +574,7 @@
 	    handler->length == 0)
 		return -EINVAL;
 
-	spin_lock_irqsave(&address_handler_lock, flags);
+	spin_lock_bh(&address_handler_lock);
 
 	handler->offset = region->start;
 	while (handler->offset + handler->length <= region->end) {
@@ -594,7 +593,7 @@
 		}
 	}
 
-	spin_unlock_irqrestore(&address_handler_lock, flags);
+	spin_unlock_bh(&address_handler_lock);
 
 	return ret;
 }
@@ -602,14 +601,15 @@
 
 /**
  * fw_core_remove_address_handler() - unregister an address handler
+ *
+ * When fw_core_remove_address_handler() returns, @handler->callback() is
+ * guaranteed to not run on any CPU anymore.
  */
 void fw_core_remove_address_handler(struct fw_address_handler *handler)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&address_handler_lock, flags);
+	spin_lock_bh(&address_handler_lock);
 	list_del(&handler->link);
-	spin_unlock_irqrestore(&address_handler_lock, flags);
+	spin_unlock_bh(&address_handler_lock);
 }
 EXPORT_SYMBOL(fw_core_remove_address_handler);
 
@@ -770,7 +770,7 @@
 		break;
 
 	default:
-		fw_error("ERROR - corrupt request received - %08x %08x %08x\n",
+		fw_notice(card, "ERROR - corrupt request received - %08x %08x %08x\n",
 			 p->header[0], p->header[1], p->header[2]);
 		return NULL;
 	}
@@ -826,7 +826,6 @@
 					    unsigned long long offset)
 {
 	struct fw_address_handler *handler;
-	unsigned long flags;
 	int tcode, destination, source;
 
 	destination = HEADER_GET_DESTINATION(p->header[0]);
@@ -835,27 +834,19 @@
 	if (tcode == TCODE_LOCK_REQUEST)
 		tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]);
 
-	spin_lock_irqsave(&address_handler_lock, flags);
+	spin_lock_bh(&address_handler_lock);
 	handler = lookup_enclosing_address_handler(&address_handler_list,
 						   offset, request->length);
-	spin_unlock_irqrestore(&address_handler_lock, flags);
-
-	/*
-	 * FIXME: lookup the fw_node corresponding to the sender of
-	 * this request and pass that to the address handler instead
-	 * of the node ID.  We may also want to move the address
-	 * allocations to fw_node so we only do this callback if the
-	 * upper layers registered it for this node.
-	 */
-
-	if (handler == NULL)
-		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
-	else
+	if (handler)
 		handler->address_callback(card, request,
 					  tcode, destination, source,
 					  p->generation, offset,
 					  request->data, request->length,
 					  handler->callback_data);
+	spin_unlock_bh(&address_handler_lock);
+
+	if (!handler)
+		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
 }
 
 static void handle_fcp_region_request(struct fw_card *card,
@@ -864,7 +855,6 @@
 				      unsigned long long offset)
 {
 	struct fw_address_handler *handler;
-	unsigned long flags;
 	int tcode, destination, source;
 
 	if ((offset != (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
@@ -886,7 +876,7 @@
 		return;
 	}
 
-	spin_lock_irqsave(&address_handler_lock, flags);
+	spin_lock_bh(&address_handler_lock);
 	list_for_each_entry(handler, &address_handler_list, link) {
 		if (is_enclosing_handler(handler, offset, request->length))
 			handler->address_callback(card, NULL, tcode,
@@ -896,7 +886,7 @@
 						  request->length,
 						  handler->callback_data);
 	}
-	spin_unlock_irqrestore(&address_handler_lock, flags);
+	spin_unlock_bh(&address_handler_lock);
 
 	fw_send_response(card, request, RCODE_COMPLETE);
 }
@@ -960,7 +950,7 @@
 
 	if (&t->link == &card->transaction_list) {
  timed_out:
-		fw_notify("Unsolicited response (source %x, tlabel %x)\n",
+		fw_notice(card, "unsolicited response (source %x, tlabel %x)\n",
 			  source, tlabel);
 		return;
 	}
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index b45be57..9047f55 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -1,6 +1,8 @@
 #ifndef _FIREWIRE_CORE_H
 #define _FIREWIRE_CORE_H
 
+#include <linux/compiler.h>
+#include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/list.h>
 #include <linux/idr.h>
@@ -23,6 +25,11 @@
 
 /* -card */
 
+extern __printf(2, 3)
+void fw_err(const struct fw_card *card, const char *fmt, ...);
+extern __printf(2, 3)
+void fw_notice(const struct fw_card *card, const char *fmt, ...);
+
 /* bitfields within the PHY registers */
 #define PHY_LINK_ACTIVE		0x80
 #define PHY_CONTENDER		0x40
@@ -99,6 +106,8 @@
 
 	void (*flush_queue_iso)(struct fw_iso_context *ctx);
 
+	int (*flush_iso_completions)(struct fw_iso_context *ctx);
+
 	int (*stop_iso)(struct fw_iso_context *ctx);
 };
 
@@ -141,6 +150,18 @@
 extern struct idr fw_device_idr;
 extern int fw_cdev_major;
 
+static inline struct fw_device *fw_device_get(struct fw_device *device)
+{
+	get_device(&device->device);
+
+	return device;
+}
+
+static inline void fw_device_put(struct fw_device *device)
+{
+	put_device(&device->device);
+}
+
 struct fw_device *fw_device_get_by_devt(dev_t devt);
 int fw_device_set_broadcast_channel(struct device *dev, void *gen);
 void fw_node_event(struct fw_card *card, struct fw_node *node, int event);
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index a20f45b..08c6749 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -256,8 +256,8 @@
 	if (get_unaligned_be16(&h->h_proto) == ETH_P_IP)
 		return arp_find((unsigned char *)&h->h_dest, skb);
 
-	fw_notify("%s: unable to resolve type %04x addresses\n",
-		  skb->dev->name, be16_to_cpu(h->h_proto));
+	dev_notice(&skb->dev->dev, "unable to resolve type %04x addresses\n",
+		   be16_to_cpu(h->h_proto));
 	return 0;
 }
 
@@ -369,7 +369,7 @@
 
 	new = kmalloc(sizeof(*new), GFP_ATOMIC);
 	if (!new) {
-		fw_error("out of memory\n");
+		dev_err(&pd->skb->dev->dev, "out of memory\n");
 		return NULL;
 	}
 
@@ -414,7 +414,7 @@
 fail_w_new:
 	kfree(new);
 fail:
-	fw_error("out of memory\n");
+	dev_err(&net->dev, "out of memory\n");
 
 	return NULL;
 }
@@ -554,7 +554,7 @@
 		sspd = arp1394->sspd;
 		/* Sanity check.  OS X 10.3 PPC reportedly sends 131. */
 		if (sspd > SCODE_3200) {
-			fw_notify("sspd %x out of range\n", sspd);
+			dev_notice(&net->dev, "sspd %x out of range\n", sspd);
 			sspd = SCODE_3200;
 		}
 		max_payload = fwnet_max_payload(arp1394->max_rec, sspd);
@@ -574,8 +574,9 @@
 		spin_unlock_irqrestore(&dev->lock, flags);
 
 		if (!peer) {
-			fw_notify("No peer for ARP packet from %016llx\n",
-				  (unsigned long long)peer_guid);
+			dev_notice(&net->dev,
+				   "no peer for ARP packet from %016llx\n",
+				   (unsigned long long)peer_guid);
 			goto no_peer;
 		}
 
@@ -691,7 +692,7 @@
 
 		skb = dev_alloc_skb(len + net->hard_header_len + 15);
 		if (unlikely(!skb)) {
-			fw_error("out of memory\n");
+			dev_err(&net->dev, "out of memory\n");
 			net->stats.rx_dropped++;
 
 			return -ENOMEM;
@@ -814,7 +815,7 @@
 		rcode = RCODE_TYPE_ERROR;
 	else if (fwnet_incoming_packet(dev, payload, length,
 				       source, generation, false) != 0) {
-		fw_error("Incoming packet failure\n");
+		dev_err(&dev->netdev->dev, "incoming packet failure\n");
 		rcode = RCODE_CONFLICT_ERROR;
 	} else
 		rcode = RCODE_COMPLETE;
@@ -881,7 +882,7 @@
 	if (retval >= 0)
 		fw_iso_context_queue_flush(dev->broadcast_rcv_context);
 	else
-		fw_error("requeue failed\n");
+		dev_err(&dev->netdev->dev, "requeue failed\n");
 }
 
 static struct kmem_cache *fwnet_packet_task_cache;
@@ -936,9 +937,10 @@
 		case RFC2374_HDR_LASTFRAG:
 		case RFC2374_HDR_UNFRAG:
 		default:
-			fw_error("Outstanding packet %x lf %x, header %x,%x\n",
-				 ptask->outstanding_pkts, lf, ptask->hdr.w0,
-				 ptask->hdr.w1);
+			dev_err(&dev->netdev->dev,
+				"outstanding packet %x lf %x, header %x,%x\n",
+				ptask->outstanding_pkts, lf, ptask->hdr.w0,
+				ptask->hdr.w1);
 			BUG();
 
 		case RFC2374_HDR_FIRSTFRAG:
@@ -1010,8 +1012,9 @@
 		fwnet_transmit_packet_failed(ptask);
 
 		if (printk_timed_ratelimit(&j,  1000) || rcode != last_rcode) {
-			fw_error("fwnet_write_complete: "
-				"failed: %x (skipped %d)\n", rcode, errors_skipped);
+			dev_err(&ptask->dev->netdev->dev,
+				"fwnet_write_complete failed: %x (skipped %d)\n",
+				rcode, errors_skipped);
 
 			errors_skipped = 0;
 			last_rcode = rcode;
@@ -1539,14 +1542,12 @@
 	put_unaligned_be64(card->guid, net->dev_addr);
 	put_unaligned_be64(~0ULL, net->broadcast);
 	ret = register_netdev(net);
-	if (ret) {
-		fw_error("Cannot register the driver\n");
+	if (ret)
 		goto out;
-	}
 
 	list_add_tail(&dev->dev_link, &fwnet_device_list);
-	fw_notify("%s: IPv4 over FireWire on device %016llx\n",
-		  net->name, (unsigned long long)card->guid);
+	dev_notice(&net->dev, "IPv4 over IEEE 1394 on card %s\n",
+		   dev_name(card->device));
  have_dev:
 	ret = fwnet_add_peer(dev, unit, device);
 	if (ret && allocated_netdev) {
@@ -1648,7 +1649,7 @@
 static struct fw_driver fwnet_driver = {
 	.driver = {
 		.owner  = THIS_MODULE,
-		.name   = "net",
+		.name   = KBUILD_MODNAME,
 		.bus    = &fw_bus_type,
 		.probe  = fwnet_probe,
 		.remove = fwnet_remove,
diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c
index 763626b..a7c4422 100644
--- a/drivers/firewire/nosy.c
+++ b/drivers/firewire/nosy.c
@@ -36,7 +36,7 @@
 #include <linux/timex.h>
 #include <linux/uaccess.h>
 #include <linux/wait.h>
-
+#include <linux/dma-mapping.h>
 #include <linux/atomic.h>
 #include <asm/byteorder.h>
 
@@ -536,7 +536,7 @@
 	u32 p, end;
 	int ret, i;
 
-	if (pci_set_dma_mask(dev, 0xffffffff)) {
+	if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) {
 		dev_err(&dev->dev,
 		    "DMA address limits not supported for PCILynx hardware\n");
 		return -ENXIO;
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 7f5f0da..2b54600 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -46,7 +46,6 @@
 
 #include <asm/byteorder.h>
 #include <asm/page.h>
-#include <asm/system.h>
 
 #ifdef CONFIG_PPC_PMAC
 #include <asm/pmac_feature.h>
@@ -170,10 +169,12 @@
 struct iso_context {
 	struct fw_iso_context base;
 	struct context context;
-	int excess_bytes;
 	void *header;
 	size_t header_length;
-
+	unsigned long flushing_completions;
+	u32 mc_buffer_bus;
+	u16 mc_completed;
+	u16 last_timestamp;
 	u8 sync;
 	u8 tags;
 };
@@ -338,8 +339,6 @@
 #define OHCI_PARAM_DEBUG_IRQS		4
 #define OHCI_PARAM_DEBUG_BUSRESETS	8 /* only effective before chip init */
 
-#ifdef CONFIG_FIREWIRE_OHCI_DEBUG
-
 static int param_debug;
 module_param_named(debug, param_debug, int, 0644);
 MODULE_PARM_DESC(debug, "Verbose logging (default = 0"
@@ -349,7 +348,7 @@
 	", busReset events = "	__stringify(OHCI_PARAM_DEBUG_BUSRESETS)
 	", or a combination, or all = -1)");
 
-static void log_irqs(u32 evt)
+static void log_irqs(struct fw_ohci *ohci, u32 evt)
 {
 	if (likely(!(param_debug &
 			(OHCI_PARAM_DEBUG_IRQS | OHCI_PARAM_DEBUG_BUSRESETS))))
@@ -359,7 +358,8 @@
 	    !(evt & OHCI1394_busReset))
 		return;
 
-	fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
+	dev_notice(ohci->card.device,
+	    "IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
 	    evt & OHCI1394_selfIDComplete	? " selfID"		: "",
 	    evt & OHCI1394_RQPkt		? " AR_req"		: "",
 	    evt & OHCI1394_RSPkt		? " AR_resp"		: "",
@@ -398,24 +398,29 @@
 	return port[*s >> shift & 3];
 }
 
-static void log_selfids(int node_id, int generation, int self_id_count, u32 *s)
+static void log_selfids(struct fw_ohci *ohci, int generation, int self_id_count)
 {
+	u32 *s;
+
 	if (likely(!(param_debug & OHCI_PARAM_DEBUG_SELFIDS)))
 		return;
 
-	fw_notify("%d selfIDs, generation %d, local node ID %04x\n",
-		  self_id_count, generation, node_id);
+	dev_notice(ohci->card.device,
+		   "%d selfIDs, generation %d, local node ID %04x\n",
+		   self_id_count, generation, ohci->node_id);
 
-	for (; self_id_count--; ++s)
+	for (s = ohci->self_id_buffer; self_id_count--; ++s)
 		if ((*s & 1 << 23) == 0)
-			fw_notify("selfID 0: %08x, phy %d [%c%c%c] "
+			dev_notice(ohci->card.device,
+			    "selfID 0: %08x, phy %d [%c%c%c] "
 			    "%s gc=%d %s %s%s%s\n",
 			    *s, *s >> 24 & 63, _p(s, 6), _p(s, 4), _p(s, 2),
 			    speed[*s >> 14 & 3], *s >> 16 & 63,
 			    power[*s >> 8 & 7], *s >> 22 & 1 ? "L" : "",
 			    *s >> 11 & 1 ? "c" : "", *s & 2 ? "i" : "");
 		else
-			fw_notify("selfID n: %08x, phy %d [%c%c%c%c%c%c%c%c]\n",
+			dev_notice(ohci->card.device,
+			    "selfID n: %08x, phy %d [%c%c%c%c%c%c%c%c]\n",
 			    *s, *s >> 24 & 63,
 			    _p(s, 16), _p(s, 14), _p(s, 12), _p(s, 10),
 			    _p(s,  8), _p(s,  6), _p(s,  4), _p(s,  2));
@@ -451,7 +456,8 @@
 	[0xe] = "link internal",	[0xf] = "-reserved-",
 };
 
-static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
+static void log_ar_at_event(struct fw_ohci *ohci,
+			    char dir, int speed, u32 *header, int evt)
 {
 	int tcode = header[0] >> 4 & 0xf;
 	char specific[12];
@@ -463,8 +469,9 @@
 			evt = 0x1f;
 
 	if (evt == OHCI1394_evt_bus_reset) {
-		fw_notify("A%c evt_bus_reset, generation %d\n",
-		    dir, (header[2] >> 16) & 0xff);
+		dev_notice(ohci->card.device,
+			   "A%c evt_bus_reset, generation %d\n",
+			   dir, (header[2] >> 16) & 0xff);
 		return;
 	}
 
@@ -483,39 +490,35 @@
 
 	switch (tcode) {
 	case 0xa:
-		fw_notify("A%c %s, %s\n", dir, evts[evt], tcodes[tcode]);
+		dev_notice(ohci->card.device,
+			   "A%c %s, %s\n",
+			   dir, evts[evt], tcodes[tcode]);
 		break;
 	case 0xe:
-		fw_notify("A%c %s, PHY %08x %08x\n",
-			  dir, evts[evt], header[1], header[2]);
+		dev_notice(ohci->card.device,
+			   "A%c %s, PHY %08x %08x\n",
+			   dir, evts[evt], header[1], header[2]);
 		break;
 	case 0x0: case 0x1: case 0x4: case 0x5: case 0x9:
-		fw_notify("A%c spd %x tl %02x, "
-		    "%04x -> %04x, %s, "
-		    "%s, %04x%08x%s\n",
-		    dir, speed, header[0] >> 10 & 0x3f,
-		    header[1] >> 16, header[0] >> 16, evts[evt],
-		    tcodes[tcode], header[1] & 0xffff, header[2], specific);
+		dev_notice(ohci->card.device,
+			   "A%c spd %x tl %02x, "
+			   "%04x -> %04x, %s, "
+			   "%s, %04x%08x%s\n",
+			   dir, speed, header[0] >> 10 & 0x3f,
+			   header[1] >> 16, header[0] >> 16, evts[evt],
+			   tcodes[tcode], header[1] & 0xffff, header[2], specific);
 		break;
 	default:
-		fw_notify("A%c spd %x tl %02x, "
-		    "%04x -> %04x, %s, "
-		    "%s%s\n",
-		    dir, speed, header[0] >> 10 & 0x3f,
-		    header[1] >> 16, header[0] >> 16, evts[evt],
-		    tcodes[tcode], specific);
+		dev_notice(ohci->card.device,
+			   "A%c spd %x tl %02x, "
+			   "%04x -> %04x, %s, "
+			   "%s%s\n",
+			   dir, speed, header[0] >> 10 & 0x3f,
+			   header[1] >> 16, header[0] >> 16, evts[evt],
+			   tcodes[tcode], specific);
 	}
 }
 
-#else
-
-#define param_debug 0
-static inline void log_irqs(u32 evt) {}
-static inline void log_selfids(int node_id, int generation, int self_id_count, u32 *s) {}
-static inline void log_ar_at_event(char dir, int speed, u32 *header, int evt) {}
-
-#endif /* CONFIG_FIREWIRE_OHCI_DEBUG */
-
 static inline void reg_write(const struct fw_ohci *ohci, int offset, u32 data)
 {
 	writel(data, ohci->registers + offset);
@@ -559,7 +562,7 @@
 		if (i >= 3)
 			msleep(1);
 	}
-	fw_error("failed to read phy reg\n");
+	dev_err(ohci->card.device, "failed to read phy reg\n");
 
 	return -EBUSY;
 }
@@ -581,7 +584,7 @@
 		if (i >= 3)
 			msleep(1);
 	}
-	fw_error("failed to write phy reg\n");
+	dev_err(ohci->card.device, "failed to write phy reg\n");
 
 	return -EBUSY;
 }
@@ -680,11 +683,14 @@
 
 static void ar_context_abort(struct ar_context *ctx, const char *error_msg)
 {
-	if (reg_read(ctx->ohci, CONTROL_CLEAR(ctx->regs)) & CONTEXT_RUN) {
-		reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN);
-		flush_writes(ctx->ohci);
+	struct fw_ohci *ohci = ctx->ohci;
 
-		fw_error("AR error: %s; DMA stopped\n", error_msg);
+	if (reg_read(ohci, CONTROL_CLEAR(ctx->regs)) & CONTEXT_RUN) {
+		reg_write(ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN);
+		flush_writes(ohci);
+
+		dev_err(ohci->card.device, "AR error: %s; DMA stopped\n",
+			error_msg);
 	}
 	/* FIXME: restart? */
 }
@@ -854,7 +860,7 @@
 	p.timestamp  = status & 0xffff;
 	p.generation = ohci->request_generation;
 
-	log_ar_at_event('R', p.speed, p.header, evt);
+	log_ar_at_event(ohci, 'R', p.speed, p.header, evt);
 
 	/*
 	 * Several controllers, notably from NEC and VIA, forget to
@@ -1226,21 +1232,22 @@
 
 static void context_stop(struct context *ctx)
 {
+	struct fw_ohci *ohci = ctx->ohci;
 	u32 reg;
 	int i;
 
-	reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN);
+	reg_write(ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN);
 	ctx->running = false;
 
 	for (i = 0; i < 1000; i++) {
-		reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs));
+		reg = reg_read(ohci, CONTROL_SET(ctx->regs));
 		if ((reg & CONTEXT_ACTIVE) == 0)
 			return;
 
 		if (i)
 			udelay(10);
 	}
-	fw_error("Error: DMA context still active (0x%08x)\n", reg);
+	dev_err(ohci->card.device, "DMA context still active (0x%08x)\n", reg);
 }
 
 struct driver_data {
@@ -1420,7 +1427,7 @@
 	evt = le16_to_cpu(last->transfer_status) & 0x1f;
 	packet->timestamp = le16_to_cpu(last->res_count);
 
-	log_ar_at_event('T', packet->speed, packet->header, evt);
+	log_ar_at_event(ohci, 'T', packet->speed, packet->header, evt);
 
 	switch (evt) {
 	case OHCI1394_evt_timeout:
@@ -1549,7 +1556,7 @@
 			goto out;
 		}
 
-	fw_error("swap not done (CSR lock timeout)\n");
+	dev_err(ohci->card.device, "swap not done (CSR lock timeout)\n");
 	fw_fill_response(&response, packet->header, RCODE_BUSY, NULL, 0);
 
  out:
@@ -1623,15 +1630,10 @@
 	u32 ctl;
 
 	ctl = reg_read(ohci, CONTROL_SET(regs));
-	if (ctl & CONTEXT_DEAD) {
-#ifdef CONFIG_FIREWIRE_OHCI_DEBUG
-		fw_error("DMA context %s has stopped, error code: %s\n",
-			 name, evts[ctl & 0x1f]);
-#else
-		fw_error("DMA context %s has stopped, error code: %#x\n",
-			 name, ctl & 0x1f);
-#endif
-	}
+	if (ctl & CONTEXT_DEAD)
+		dev_err(ohci->card.device,
+			"DMA context %s has stopped, error code: %s\n",
+			name, evts[ctl & 0x1f]);
 }
 
 static void handle_dead_contexts(struct fw_ohci *ohci)
@@ -1781,7 +1783,8 @@
 
 	reg = reg_read(ohci, OHCI1394_NodeID);
 	if (!(reg & OHCI1394_NodeID_idValid)) {
-		fw_notify("node ID not valid, new bus reset in progress\n");
+		dev_notice(ohci->card.device,
+			   "node ID not valid, new bus reset in progress\n");
 		return -EBUSY;
 	}
 	self_id |= ((reg & 0x3f) << 24); /* phy ID */
@@ -1827,11 +1830,12 @@
 
 	reg = reg_read(ohci, OHCI1394_NodeID);
 	if (!(reg & OHCI1394_NodeID_idValid)) {
-		fw_notify("node ID not valid, new bus reset in progress\n");
+		dev_notice(ohci->card.device,
+			   "node ID not valid, new bus reset in progress\n");
 		return;
 	}
 	if ((reg & OHCI1394_NodeID_nodeNumber) == 63) {
-		fw_notify("malconfigured bus\n");
+		dev_notice(ohci->card.device, "malconfigured bus\n");
 		return;
 	}
 	ohci->node_id = reg & (OHCI1394_NodeID_busNumber |
@@ -1845,7 +1849,7 @@
 
 	reg = reg_read(ohci, OHCI1394_SelfIDCount);
 	if (reg & OHCI1394_SelfIDCount_selfIDError) {
-		fw_notify("inconsistent self IDs\n");
+		dev_notice(ohci->card.device, "inconsistent self IDs\n");
 		return;
 	}
 	/*
@@ -1857,7 +1861,7 @@
 	self_id_count = (reg >> 3) & 0xff;
 
 	if (self_id_count > 252) {
-		fw_notify("inconsistent self IDs\n");
+		dev_notice(ohci->card.device, "inconsistent self IDs\n");
 		return;
 	}
 
@@ -1875,11 +1879,13 @@
 			 */
 			if (cond_le32_to_cpu(ohci->self_id_cpu[i])
 							== 0xffff008f) {
-				fw_notify("ignoring spurious self IDs\n");
+				dev_notice(ohci->card.device,
+					   "ignoring spurious self IDs\n");
 				self_id_count = j;
 				break;
 			} else {
-				fw_notify("inconsistent self IDs\n");
+				dev_notice(ohci->card.device,
+					   "inconsistent self IDs\n");
 				return;
 			}
 		}
@@ -1890,13 +1896,14 @@
 	if (ohci->quirks & QUIRK_TI_SLLZ059) {
 		self_id_count = find_and_insert_self_id(ohci, self_id_count);
 		if (self_id_count < 0) {
-			fw_notify("could not construct local self ID\n");
+			dev_notice(ohci->card.device,
+				   "could not construct local self ID\n");
 			return;
 		}
 	}
 
 	if (self_id_count == 0) {
-		fw_notify("inconsistent self IDs\n");
+		dev_notice(ohci->card.device, "inconsistent self IDs\n");
 		return;
 	}
 	rmb();
@@ -1917,8 +1924,8 @@
 
 	new_generation = (reg_read(ohci, OHCI1394_SelfIDCount) >> 16) & 0xff;
 	if (new_generation != generation) {
-		fw_notify("recursive bus reset detected, "
-			  "discarding self ids\n");
+		dev_notice(ohci->card.device,
+			   "new bus reset, discarding self ids\n");
 		return;
 	}
 
@@ -1989,8 +1996,7 @@
 		dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
 				  free_rom, free_rom_bus);
 
-	log_selfids(ohci->node_id, generation,
-		    self_id_count, ohci->self_id_buffer);
+	log_selfids(ohci, generation, self_id_count);
 
 	fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation,
 				 self_id_count, ohci->self_id_buffer,
@@ -2015,7 +2021,7 @@
 	 */
 	reg_write(ohci, OHCI1394_IntEventClear,
 		  event & ~(OHCI1394_busReset | OHCI1394_postedWriteErr));
-	log_irqs(event);
+	log_irqs(ohci, event);
 
 	if (event & OHCI1394_selfIDComplete)
 		queue_work(fw_workqueue, &ohci->bus_reset_work);
@@ -2057,8 +2063,7 @@
 	}
 
 	if (unlikely(event & OHCI1394_regAccessFail))
-		fw_error("Register access failure - "
-			 "please notify linux1394-devel@lists.sf.net\n");
+		dev_err(ohci->card.device, "register access failure\n");
 
 	if (unlikely(event & OHCI1394_postedWriteErr)) {
 		reg_read(ohci, OHCI1394_PostedWriteAddressHi);
@@ -2066,12 +2071,13 @@
 		reg_write(ohci, OHCI1394_IntEventClear,
 			  OHCI1394_postedWriteErr);
 		if (printk_ratelimit())
-			fw_error("PCI posted write error\n");
+			dev_err(ohci->card.device, "PCI posted write error\n");
 	}
 
 	if (unlikely(event & OHCI1394_cycleTooLong)) {
 		if (printk_ratelimit())
-			fw_notify("isochronous cycle too long\n");
+			dev_notice(ohci->card.device,
+				   "isochronous cycle too long\n");
 		reg_write(ohci, OHCI1394_LinkControlSet,
 			  OHCI1394_LinkControl_cycleMaster);
 	}
@@ -2084,7 +2090,8 @@
 		 * them at least two cycles later.  (FIXME?)
 		 */
 		if (printk_ratelimit())
-			fw_notify("isochronous cycle inconsistent\n");
+			dev_notice(ohci->card.device,
+				   "isochronous cycle inconsistent\n");
 	}
 
 	if (unlikely(event & OHCI1394_unrecoverableError))
@@ -2211,7 +2218,7 @@
 	int i, ret;
 
 	if (software_reset(ohci)) {
-		fw_error("Failed to reset ohci card.\n");
+		dev_err(card->device, "failed to reset ohci card\n");
 		return -EBUSY;
 	}
 
@@ -2235,7 +2242,7 @@
 	}
 
 	if (!lps) {
-		fw_error("Failed to set Link Power Status\n");
+		dev_err(card->device, "failed to set Link Power Status\n");
 		return -EIO;
 	}
 
@@ -2244,7 +2251,7 @@
 		if (ret < 0)
 			return ret;
 		if (ret)
-			fw_notify("local TSB41BA3D phy\n");
+			dev_notice(card->device, "local TSB41BA3D phy\n");
 		else
 			ohci->quirks &= ~QUIRK_TI_SLLZ059;
 	}
@@ -2344,7 +2351,8 @@
 	if (request_irq(dev->irq, irq_handler,
 			pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED,
 			ohci_driver_name, ohci)) {
-		fw_error("Failed to allocate interrupt %d.\n", dev->irq);
+		dev_err(card->device, "failed to allocate interrupt %d\n",
+			dev->irq);
 		pci_disable_msi(dev);
 
 		if (config_rom) {
@@ -2509,7 +2517,7 @@
 		dma_unmap_single(ohci->card.device, packet->payload_bus,
 				 packet->payload_length, DMA_TO_DEVICE);
 
-	log_ar_at_event('T', packet->speed, packet->header, 0x20);
+	log_ar_at_event(ohci, 'T', packet->speed, packet->header, 0x20);
 	driver_data->packet = NULL;
 	packet->ack = RCODE_CANCELLED;
 	packet->callback(packet, &ohci->card, packet->ack);
@@ -2674,25 +2682,35 @@
 	}
 }
 
-static void copy_iso_headers(struct iso_context *ctx, void *p)
+static void flush_iso_completions(struct iso_context *ctx)
 {
-	int i = ctx->header_length;
+	ctx->base.callback.sc(&ctx->base, ctx->last_timestamp,
+			      ctx->header_length, ctx->header,
+			      ctx->base.callback_data);
+	ctx->header_length = 0;
+}
 
-	if (i + ctx->base.header_size > PAGE_SIZE)
-		return;
+static void copy_iso_headers(struct iso_context *ctx, const u32 *dma_hdr)
+{
+	u32 *ctx_hdr;
+
+	if (ctx->header_length + ctx->base.header_size > PAGE_SIZE)
+		flush_iso_completions(ctx);
+
+	ctx_hdr = ctx->header + ctx->header_length;
+	ctx->last_timestamp = (u16)le32_to_cpu((__force __le32)dma_hdr[0]);
 
 	/*
-	 * The iso header is byteswapped to little endian by
-	 * the controller, but the remaining header quadlets
-	 * are big endian.  We want to present all the headers
-	 * as big endian, so we have to swap the first quadlet.
+	 * The two iso header quadlets are byteswapped to little
+	 * endian by the controller, but we want to present them
+	 * as big endian for consistency with the bus endianness.
 	 */
 	if (ctx->base.header_size > 0)
-		*(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4));
+		ctx_hdr[0] = swab32(dma_hdr[1]); /* iso packet header */
 	if (ctx->base.header_size > 4)
-		*(u32 *) (ctx->header + i + 4) = __swab32(*(u32 *) p);
+		ctx_hdr[1] = swab32(dma_hdr[0]); /* timestamp */
 	if (ctx->base.header_size > 8)
-		memcpy(ctx->header + i + 8, p + 8, ctx->base.header_size - 8);
+		memcpy(&ctx_hdr[2], &dma_hdr[2], ctx->base.header_size - 8);
 	ctx->header_length += ctx->base.header_size;
 }
 
@@ -2704,8 +2722,6 @@
 		container_of(context, struct iso_context, context);
 	struct descriptor *pd;
 	u32 buffer_dma;
-	__le32 *ir_header;
-	void *p;
 
 	for (pd = d; pd <= last; pd++)
 		if (pd->transfer_status)
@@ -2724,17 +2740,10 @@
 					      DMA_FROM_DEVICE);
 	}
 
-	p = last + 1;
-	copy_iso_headers(ctx, p);
+	copy_iso_headers(ctx, (u32 *) (last + 1));
 
-	if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) {
-		ir_header = (__le32 *) p;
-		ctx->base.callback.sc(&ctx->base,
-				      le32_to_cpu(ir_header[0]) & 0xffff,
-				      ctx->header_length, ctx->header,
-				      ctx->base.callback_data);
-		ctx->header_length = 0;
-	}
+	if (last->control & cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS))
+		flush_iso_completions(ctx);
 
 	return 1;
 }
@@ -2746,29 +2755,51 @@
 {
 	struct iso_context *ctx =
 		container_of(context, struct iso_context, context);
+	unsigned int req_count, res_count, completed;
 	u32 buffer_dma;
 
-	if (!last->transfer_status)
+	req_count = le16_to_cpu(last->req_count);
+	res_count = le16_to_cpu(ACCESS_ONCE(last->res_count));
+	completed = req_count - res_count;
+	buffer_dma = le32_to_cpu(last->data_address);
+
+	if (completed > 0) {
+		ctx->mc_buffer_bus = buffer_dma;
+		ctx->mc_completed = completed;
+	}
+
+	if (res_count != 0)
 		/* Descriptor(s) not done yet, stop iteration */
 		return 0;
 
-	buffer_dma = le32_to_cpu(last->data_address);
 	dma_sync_single_range_for_cpu(context->ohci->card.device,
 				      buffer_dma & PAGE_MASK,
 				      buffer_dma & ~PAGE_MASK,
-				      le16_to_cpu(last->req_count),
-				      DMA_FROM_DEVICE);
+				      completed, DMA_FROM_DEVICE);
 
-	if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS)
+	if (last->control & cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS)) {
 		ctx->base.callback.mc(&ctx->base,
-				      le32_to_cpu(last->data_address) +
-				      le16_to_cpu(last->req_count) -
-				      le16_to_cpu(last->res_count),
+				      buffer_dma + completed,
 				      ctx->base.callback_data);
+		ctx->mc_completed = 0;
+	}
 
 	return 1;
 }
 
+static void flush_ir_buffer_fill(struct iso_context *ctx)
+{
+	dma_sync_single_range_for_cpu(ctx->context.ohci->card.device,
+				      ctx->mc_buffer_bus & PAGE_MASK,
+				      ctx->mc_buffer_bus & ~PAGE_MASK,
+				      ctx->mc_completed, DMA_FROM_DEVICE);
+
+	ctx->base.callback.mc(&ctx->base,
+			      ctx->mc_buffer_bus + ctx->mc_completed,
+			      ctx->base.callback_data);
+	ctx->mc_completed = 0;
+}
+
 static inline void sync_it_packet_for_cpu(struct context *context,
 					  struct descriptor *pd)
 {
@@ -2812,8 +2843,8 @@
 {
 	struct iso_context *ctx =
 		container_of(context, struct iso_context, context);
-	int i;
 	struct descriptor *pd;
+	__be32 *ctx_hdr;
 
 	for (pd = d; pd <= last; pd++)
 		if (pd->transfer_status)
@@ -2824,20 +2855,19 @@
 
 	sync_it_packet_for_cpu(context, d);
 
-	i = ctx->header_length;
-	if (i + 4 < PAGE_SIZE) {
-		/* Present this value as big-endian to match the receive code */
-		*(__be32 *)(ctx->header + i) = cpu_to_be32(
-				((u32)le16_to_cpu(pd->transfer_status) << 16) |
-				le16_to_cpu(pd->res_count));
-		ctx->header_length += 4;
-	}
-	if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) {
-		ctx->base.callback.sc(&ctx->base, le16_to_cpu(last->res_count),
-				      ctx->header_length, ctx->header,
-				      ctx->base.callback_data);
-		ctx->header_length = 0;
-	}
+	if (ctx->header_length + 4 > PAGE_SIZE)
+		flush_iso_completions(ctx);
+
+	ctx_hdr = ctx->header + ctx->header_length;
+	ctx->last_timestamp = le16_to_cpu(last->res_count);
+	/* Present this value as big-endian to match the receive code */
+	*ctx_hdr = cpu_to_be32((le16_to_cpu(pd->transfer_status) << 16) |
+			       le16_to_cpu(pd->res_count));
+	ctx->header_length += 4;
+
+	if (last->control & cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS))
+		flush_iso_completions(ctx);
+
 	return 1;
 }
 
@@ -2924,8 +2954,10 @@
 	if (ret < 0)
 		goto out_with_header;
 
-	if (type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL)
+	if (type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL) {
 		set_multichannel_mask(ohci, 0);
+		ctx->mc_completed = 0;
+	}
 
 	return &ctx->base;
 
@@ -3387,6 +3419,39 @@
 	reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
 }
 
+static int ohci_flush_iso_completions(struct fw_iso_context *base)
+{
+	struct iso_context *ctx = container_of(base, struct iso_context, base);
+	int ret = 0;
+
+	tasklet_disable(&ctx->context.tasklet);
+
+	if (!test_and_set_bit_lock(0, &ctx->flushing_completions)) {
+		context_tasklet((unsigned long)&ctx->context);
+
+		switch (base->type) {
+		case FW_ISO_CONTEXT_TRANSMIT:
+		case FW_ISO_CONTEXT_RECEIVE:
+			if (ctx->header_length != 0)
+				flush_iso_completions(ctx);
+			break;
+		case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
+			if (ctx->mc_completed != 0)
+				flush_ir_buffer_fill(ctx);
+			break;
+		default:
+			ret = -ENOSYS;
+		}
+
+		clear_bit_unlock(0, &ctx->flushing_completions);
+		smp_mb__after_clear_bit();
+	}
+
+	tasklet_enable(&ctx->context.tasklet);
+
+	return ret;
+}
+
 static const struct fw_card_driver ohci_driver = {
 	.enable			= ohci_enable,
 	.read_phy_reg		= ohci_read_phy_reg,
@@ -3404,6 +3469,7 @@
 	.set_iso_channels	= ohci_set_iso_channels,
 	.queue_iso		= ohci_queue_iso,
 	.flush_queue_iso	= ohci_flush_queue_iso,
+	.flush_iso_completions	= ohci_flush_iso_completions,
 	.start_iso		= ohci_start_iso,
 	.stop_iso		= ohci_stop_iso,
 };
@@ -3463,7 +3529,7 @@
 
 	err = pci_enable_device(dev);
 	if (err) {
-		fw_error("Failed to enable OHCI hardware\n");
+		dev_err(&dev->dev, "failed to enable OHCI hardware\n");
 		goto fail_free;
 	}
 
@@ -3478,13 +3544,13 @@
 
 	err = pci_request_region(dev, 0, ohci_driver_name);
 	if (err) {
-		fw_error("MMIO resource unavailable\n");
+		dev_err(&dev->dev, "MMIO resource unavailable\n");
 		goto fail_disable;
 	}
 
 	ohci->registers = pci_iomap(dev, 0, OHCI1394_REGISTER_SIZE);
 	if (ohci->registers == NULL) {
-		fw_error("Failed to remap registers\n");
+		dev_err(&dev->dev, "failed to remap registers\n");
 		err = -ENXIO;
 		goto fail_iomem;
 	}
@@ -3573,9 +3639,10 @@
 		goto fail_contexts;
 
 	version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
-	fw_notify("Added fw-ohci device %s, OHCI v%x.%x, "
+	dev_notice(&dev->dev,
+		  "added OHCI v%x.%x device as card %d, "
 		  "%d IR + %d IT contexts, quirks 0x%x\n",
-		  dev_name(&dev->dev), version >> 16, version & 0xff,
+		  version >> 16, version & 0xff, ohci->card.index,
 		  ohci->n_ir, ohci->n_it, ohci->quirks);
 
 	return 0;
@@ -3604,7 +3671,7 @@
 	pmac_ohci_off(dev);
  fail:
 	if (err == -ENOMEM)
-		fw_error("Out of memory\n");
+		dev_err(&dev->dev, "out of memory\n");
 
 	return err;
 }
@@ -3648,7 +3715,7 @@
 	kfree(ohci);
 	pmac_ohci_off(dev);
 
-	fw_notify("Removed fw-ohci device.\n");
+	dev_notice(&dev->dev, "removed fw-ohci device\n");
 }
 
 #ifdef CONFIG_PM
@@ -3662,12 +3729,12 @@
 	pci_disable_msi(dev);
 	err = pci_save_state(dev);
 	if (err) {
-		fw_error("pci_save_state failed\n");
+		dev_err(&dev->dev, "pci_save_state failed\n");
 		return err;
 	}
 	err = pci_set_power_state(dev, pci_choose_state(dev, state));
 	if (err)
-		fw_error("pci_set_power_state failed with %d\n", err);
+		dev_err(&dev->dev, "pci_set_power_state failed with %d\n", err);
 	pmac_ohci_off(dev);
 
 	return 0;
@@ -3683,7 +3750,7 @@
 	pci_restore_state(dev);
 	err = pci_enable_device(dev);
 	if (err) {
-		fw_error("pci_enable_device failed\n");
+		dev_err(&dev->dev, "pci_enable_device failed\n");
 		return err;
 	}
 
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index 80e95aa..b7e65d7 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -52,7 +52,6 @@
 #include <linux/workqueue.h>
 
 #include <asm/byteorder.h>
-#include <asm/system.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -125,8 +124,6 @@
 	", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
 	", or a combination)");
 
-static const char sbp2_driver_name[] = "sbp2";
-
 /*
  * We create one struct sbp2_logical_unit per SBP-2 Logical Unit Number Entry
  * and one struct scsi_device per sbp2_logical_unit.
@@ -165,7 +162,6 @@
  */
 struct sbp2_target {
 	struct fw_unit *unit;
-	const char *bus_id;
 	struct list_head lu_list;
 
 	u64 management_agent_address;
@@ -181,11 +177,21 @@
 	int blocked;	/* ditto */
 };
 
-static struct fw_device *target_device(struct sbp2_target *tgt)
+static struct fw_device *target_parent_device(struct sbp2_target *tgt)
 {
 	return fw_parent_device(tgt->unit);
 }
 
+static const struct device *tgt_dev(const struct sbp2_target *tgt)
+{
+	return &tgt->unit->device;
+}
+
+static const struct device *lu_dev(const struct sbp2_logical_unit *lu)
+{
+	return &lu->tgt->unit->device;
+}
+
 /* Impossible login_id, to detect logout attempt before successful login */
 #define INVALID_LOGIN_ID 0x10000
 
@@ -211,6 +217,7 @@
 #define SBP2_CSR_UNIT_CHARACTERISTICS	0x3a
 #define SBP2_CSR_FIRMWARE_REVISION	0x3c
 #define SBP2_CSR_LOGICAL_UNIT_NUMBER	0x14
+#define SBP2_CSR_UNIT_UNIQUE_ID		0x8d
 #define SBP2_CSR_LOGICAL_UNIT_DIRECTORY	0xd4
 
 /* Management orb opcodes */
@@ -430,7 +437,8 @@
 		memcpy(status.data, payload + 8, length - 8);
 
 	if (STATUS_GET_SOURCE(status) == 2 || STATUS_GET_SOURCE(status) == 3) {
-		fw_notify("non-orb related status write, not handled\n");
+		dev_notice(lu_dev(lu),
+			   "non-ORB related status write, not handled\n");
 		fw_send_response(card, request, RCODE_COMPLETE);
 		return;
 	}
@@ -451,7 +459,7 @@
 		orb->callback(orb, &status);
 		kref_put(&orb->kref, free_orb); /* orb callback reference */
 	} else {
-		fw_error("status write for unknown orb\n");
+		dev_err(lu_dev(lu), "status write for unknown ORB\n");
 	}
 
 	fw_send_response(card, request, RCODE_COMPLETE);
@@ -492,7 +500,7 @@
 static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu,
 			  int node_id, int generation, u64 offset)
 {
-	struct fw_device *device = target_device(lu->tgt);
+	struct fw_device *device = target_parent_device(lu->tgt);
 	struct sbp2_pointer orb_pointer;
 	unsigned long flags;
 
@@ -513,7 +521,7 @@
 
 static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu)
 {
-	struct fw_device *device = target_device(lu->tgt);
+	struct fw_device *device = target_parent_device(lu->tgt);
 	struct sbp2_orb *orb, *next;
 	struct list_head list;
 	unsigned long flags;
@@ -552,7 +560,7 @@
 				    int generation, int function,
 				    int lun_or_login_id, void *response)
 {
-	struct fw_device *device = target_device(lu->tgt);
+	struct fw_device *device = target_parent_device(lu->tgt);
 	struct sbp2_management_orb *orb;
 	unsigned int timeout;
 	int retval = -ENOMEM;
@@ -560,7 +568,7 @@
 	if (function == SBP2_LOGOUT_REQUEST && fw_device_is_shutdown(device))
 		return 0;
 
-	orb = kzalloc(sizeof(*orb), GFP_ATOMIC);
+	orb = kzalloc(sizeof(*orb), GFP_NOIO);
 	if (orb == NULL)
 		return -ENOMEM;
 
@@ -612,20 +620,20 @@
 
 	retval = -EIO;
 	if (sbp2_cancel_orbs(lu) == 0) {
-		fw_error("%s: orb reply timed out, rcode=0x%02x\n",
-			 lu->tgt->bus_id, orb->base.rcode);
+		dev_err(lu_dev(lu), "ORB reply timed out, rcode 0x%02x\n",
+			orb->base.rcode);
 		goto out;
 	}
 
 	if (orb->base.rcode != RCODE_COMPLETE) {
-		fw_error("%s: management write failed, rcode 0x%02x\n",
-			 lu->tgt->bus_id, orb->base.rcode);
+		dev_err(lu_dev(lu), "management write failed, rcode 0x%02x\n",
+			orb->base.rcode);
 		goto out;
 	}
 
 	if (STATUS_GET_RESPONSE(orb->status) != 0 ||
 	    STATUS_GET_SBP_STATUS(orb->status) != 0) {
-		fw_error("%s: error status: %d:%d\n", lu->tgt->bus_id,
+		dev_err(lu_dev(lu), "error status: %d:%d\n",
 			 STATUS_GET_RESPONSE(orb->status),
 			 STATUS_GET_SBP_STATUS(orb->status));
 		goto out;
@@ -648,7 +656,7 @@
 
 static void sbp2_agent_reset(struct sbp2_logical_unit *lu)
 {
-	struct fw_device *device = target_device(lu->tgt);
+	struct fw_device *device = target_parent_device(lu->tgt);
 	__be32 d = 0;
 
 	fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST,
@@ -665,7 +673,7 @@
 
 static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu)
 {
-	struct fw_device *device = target_device(lu->tgt);
+	struct fw_device *device = target_parent_device(lu->tgt);
 	struct fw_transaction *t;
 	static __be32 d;
 
@@ -704,7 +712,7 @@
 static void sbp2_conditionally_block(struct sbp2_logical_unit *lu)
 {
 	struct sbp2_target *tgt = lu->tgt;
-	struct fw_card *card = target_device(tgt)->card;
+	struct fw_card *card = target_parent_device(tgt)->card;
 	struct Scsi_Host *shost =
 		container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
 	unsigned long flags;
@@ -728,7 +736,7 @@
 static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu)
 {
 	struct sbp2_target *tgt = lu->tgt;
-	struct fw_card *card = target_device(tgt)->card;
+	struct fw_card *card = target_parent_device(tgt)->card;
 	struct Scsi_Host *shost =
 		container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
 	unsigned long flags;
@@ -753,7 +761,7 @@
  */
 static void sbp2_unblock(struct sbp2_target *tgt)
 {
-	struct fw_card *card = target_device(tgt)->card;
+	struct fw_card *card = target_parent_device(tgt)->card;
 	struct Scsi_Host *shost =
 		container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
 	unsigned long flags;
@@ -794,7 +802,7 @@
  */
 static void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu)
 {
-	struct fw_device *device = target_device(lu->tgt);
+	struct fw_device *device = target_parent_device(lu->tgt);
 	__be32 d = cpu_to_be32(SBP2_CYCLE_LIMIT | SBP2_RETRY_LIMIT);
 
 	fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST,
@@ -809,7 +817,7 @@
 	struct sbp2_logical_unit *lu =
 		container_of(work, struct sbp2_logical_unit, work.work);
 	struct sbp2_target *tgt = lu->tgt;
-	struct fw_device *device = target_device(tgt);
+	struct fw_device *device = target_parent_device(tgt);
 	struct Scsi_Host *shost;
 	struct scsi_device *sdev;
 	struct sbp2_login_response response;
@@ -833,8 +841,8 @@
 		if (lu->retries++ < 5) {
 			sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
 		} else {
-			fw_error("%s: failed to login to LUN %04x\n",
-				 tgt->bus_id, lu->lun);
+			dev_err(tgt_dev(tgt), "failed to login to LUN %04x\n",
+				lu->lun);
 			/* Let any waiting I/O fail from now on. */
 			sbp2_unblock(lu->tgt);
 		}
@@ -851,8 +859,8 @@
 		      << 32) | be32_to_cpu(response.command_block_agent.low);
 	lu->login_id = be32_to_cpu(response.misc) & 0xffff;
 
-	fw_notify("%s: logged in to LUN %04x (%d retries)\n",
-		  tgt->bus_id, lu->lun, lu->retries);
+	dev_notice(tgt_dev(tgt), "logged in to LUN %04x (%d retries)\n",
+		   lu->lun, lu->retries);
 
 	/* set appropriate retry limit(s) in BUSY_TIMEOUT register */
 	sbp2_set_busy_timeout(lu);
@@ -919,7 +927,7 @@
 	struct sbp2_logical_unit *lu =
 		container_of(work, struct sbp2_logical_unit, work.work);
 	struct sbp2_target *tgt = lu->tgt;
-	struct fw_device *device = target_device(tgt);
+	struct fw_device *device = target_parent_device(tgt);
 	int generation, node_id, local_node_id;
 
 	if (fw_device_is_shutdown(device))
@@ -943,7 +951,7 @@
 		smp_rmb(); /* get current card generation */
 		if (generation == device->card->generation ||
 		    lu->retries++ >= 5) {
-			fw_error("%s: failed to reconnect\n", tgt->bus_id);
+			dev_err(tgt_dev(tgt), "failed to reconnect\n");
 			lu->retries = 0;
 			PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
 		}
@@ -957,8 +965,8 @@
 	smp_wmb();	  /* node IDs must not be older than generation */
 	lu->generation	  = generation;
 
-	fw_notify("%s: reconnected to LUN %04x (%d retries)\n",
-		  tgt->bus_id, lu->lun, lu->retries);
+	dev_notice(tgt_dev(tgt), "reconnected to LUN %04x (%d retries)\n",
+		   lu->lun, lu->retries);
 
 	sbp2_agent_reset(lu);
 	sbp2_cancel_orbs(lu);
@@ -997,6 +1005,13 @@
 	return 0;
 }
 
+static void sbp2_get_unit_unique_id(struct sbp2_target *tgt,
+				    const u32 *leaf)
+{
+	if ((leaf[0] & 0xffff0000) == 0x00020000)
+		tgt->guid = (u64)leaf[1] << 32 | leaf[2];
+}
+
 static int sbp2_scan_logical_unit_dir(struct sbp2_target *tgt,
 				      const u32 *directory)
 {
@@ -1048,6 +1063,10 @@
 				return -ENOMEM;
 			break;
 
+		case SBP2_CSR_UNIT_UNIQUE_ID:
+			sbp2_get_unit_unique_id(tgt, ci.p - 1 + value);
+			break;
+
 		case SBP2_CSR_LOGICAL_UNIT_DIRECTORY:
 			/* Adjust for the increment in the iterator */
 			if (sbp2_scan_logical_unit_dir(tgt, ci.p - 1 + value) < 0)
@@ -1068,8 +1087,8 @@
 	unsigned int timeout = tgt->mgt_orb_timeout;
 
 	if (timeout > 40000)
-		fw_notify("%s: %ds mgt_ORB_timeout limited to 40s\n",
-			  tgt->bus_id, timeout / 1000);
+		dev_notice(tgt_dev(tgt), "%ds mgt_ORB_timeout limited to 40s\n",
+			   timeout / 1000);
 
 	tgt->mgt_orb_timeout = clamp_val(timeout, 5000, 40000);
 }
@@ -1081,9 +1100,9 @@
 	unsigned int w = sbp2_param_workarounds;
 
 	if (w)
-		fw_notify("Please notify linux1394-devel@lists.sourceforge.net "
-			  "if you need the workarounds parameter for %s\n",
-			  tgt->bus_id);
+		dev_notice(tgt_dev(tgt),
+			   "Please notify linux1394-devel@lists.sf.net "
+			   "if you need the workarounds parameter\n");
 
 	if (w & SBP2_WORKAROUND_OVERRIDE)
 		goto out;
@@ -1103,9 +1122,9 @@
 	}
  out:
 	if (w)
-		fw_notify("Workarounds for %s: 0x%x "
-			  "(firmware_revision 0x%06x, model_id 0x%06x)\n",
-			  tgt->bus_id, w, firmware_revision, model);
+		dev_notice(tgt_dev(tgt), "workarounds 0x%x "
+			   "(firmware_revision 0x%06x, model_id 0x%06x)\n",
+			   w, firmware_revision, model);
 	tgt->workarounds = w;
 }
 
@@ -1121,6 +1140,10 @@
 	struct Scsi_Host *shost;
 	u32 model, firmware_revision;
 
+	/* cannot (or should not) handle targets on the local node */
+	if (device->is_local)
+		return -ENODEV;
+
 	if (dma_get_max_seg_size(device->card->device) > SBP2_MAX_SEG_SIZE)
 		BUG_ON(dma_set_max_seg_size(device->card->device,
 					    SBP2_MAX_SEG_SIZE));
@@ -1133,7 +1156,6 @@
 	dev_set_drvdata(&unit->device, tgt);
 	tgt->unit = unit;
 	INIT_LIST_HEAD(&tgt->lu_list);
-	tgt->bus_id = dev_name(&unit->device);
 	tgt->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4];
 
 	if (fw_device_enable_phys_dma(device) < 0)
@@ -1239,7 +1261,7 @@
 		kfree(lu);
 	}
 	scsi_remove_host(shost);
-	fw_notify("released %s, target %d:0:0\n", tgt->bus_id, shost->host_no);
+	dev_notice(dev, "released target %d:0:0\n", shost->host_no);
 
 	scsi_host_put(shost);
 	return 0;
@@ -1261,7 +1283,7 @@
 static struct fw_driver sbp2_driver = {
 	.driver   = {
 		.owner  = THIS_MODULE,
-		.name   = sbp2_driver_name,
+		.name   = KBUILD_MODNAME,
 		.bus    = &fw_bus_type,
 		.probe  = sbp2_probe,
 		.remove = sbp2_remove,
@@ -1286,10 +1308,19 @@
 static unsigned int sbp2_status_to_sense_data(u8 *sbp2_status, u8 *sense_data)
 {
 	int sam_status;
+	int sfmt = (sbp2_status[0] >> 6) & 0x03;
 
-	sense_data[0] = 0x70;
+	if (sfmt == 2 || sfmt == 3) {
+		/*
+		 * Reserved for future standardization (2) or
+		 * Status block format vendor-dependent (3)
+		 */
+		return DID_ERROR << 16;
+	}
+
+	sense_data[0] = 0x70 | sfmt | (sbp2_status[1] & 0x80);
 	sense_data[1] = 0x0;
-	sense_data[2] = sbp2_status[1];
+	sense_data[2] = ((sbp2_status[1] << 1) & 0xe0) | (sbp2_status[1] & 0x0f);
 	sense_data[3] = sbp2_status[4];
 	sense_data[4] = sbp2_status[5];
 	sense_data[5] = sbp2_status[6];
@@ -1325,7 +1356,7 @@
 {
 	struct sbp2_command_orb *orb =
 		container_of(base_orb, struct sbp2_command_orb, base);
-	struct fw_device *device = target_device(orb->lu->tgt);
+	struct fw_device *device = target_parent_device(orb->lu->tgt);
 	int result;
 
 	if (status != NULL) {
@@ -1433,7 +1464,7 @@
 				  struct scsi_cmnd *cmd)
 {
 	struct sbp2_logical_unit *lu = cmd->device->hostdata;
-	struct fw_device *device = target_device(lu->tgt);
+	struct fw_device *device = target_parent_device(lu->tgt);
 	struct sbp2_command_orb *orb;
 	int generation, retval = SCSI_MLQUEUE_HOST_BUSY;
 
@@ -1442,7 +1473,7 @@
 	 * transfer direction not handled.
 	 */
 	if (cmd->sc_data_direction == DMA_BIDIRECTIONAL) {
-		fw_error("Can't handle DMA_BIDIRECTIONAL, rejecting command\n");
+		dev_err(lu_dev(lu), "cannot handle bidirectional command\n");
 		cmd->result = DID_ERROR << 16;
 		cmd->scsi_done(cmd);
 		return 0;
@@ -1450,7 +1481,7 @@
 
 	orb = kzalloc(sizeof(*orb), GFP_ATOMIC);
 	if (orb == NULL) {
-		fw_notify("failed to alloc orb\n");
+		dev_notice(lu_dev(lu), "failed to alloc ORB\n");
 		return SCSI_MLQUEUE_HOST_BUSY;
 	}
 
@@ -1550,7 +1581,7 @@
 {
 	struct sbp2_logical_unit *lu = cmd->device->hostdata;
 
-	fw_notify("%s: sbp2_scsi_abort\n", lu->tgt->bus_id);
+	dev_notice(lu_dev(lu), "sbp2_scsi_abort\n");
 	sbp2_agent_reset(lu);
 	sbp2_cancel_orbs(lu);
 
@@ -1590,7 +1621,7 @@
 static struct scsi_host_template scsi_driver_template = {
 	.module			= THIS_MODULE,
 	.name			= "SBP-2 IEEE-1394",
-	.proc_name		= sbp2_driver_name,
+	.proc_name		= "sbp2",
 	.queuecommand		= sbp2_scsi_queuecommand,
 	.slave_alloc		= sbp2_scsi_slave_alloc,
 	.slave_configure	= sbp2_scsi_slave_configure,
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d0c4118..edadbda 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -190,6 +190,17 @@
 	  additional drivers must be enabled in order to use the
 	  functionality of the device.
 
+config GPIO_GE_FPGA
+	bool "GE FPGA based GPIO"
+	depends on GE_FPGA
+	help
+	  Support for common GPIO functionality provided on some GE Single Board
+	  Computers.
+
+	  This driver provides basic support (configure as input or output, read
+	  and write pin state) for GPIO implemented in a number of GE single
+	  board computers.
+
 comment "I2C GPIO expanders:"
 
 config GPIO_MAX7300
@@ -225,6 +236,12 @@
 	  Say yes here to enable the max732x to be used as an interrupt
 	  controller. It requires the driver to be built in the kernel.
 
+config GPIO_MC9S08DZ60
+	bool "MX35 3DS BOARD MC9S08DZ60 GPIO functions"
+	depends on I2C && MACH_MX35_3DS
+	help
+	  Select this to enable the MC9S08DZ60 GPIO driver
+
 config GPIO_PCA953X
 	tristate "PCA953x, PCA955x, TCA64xx, and MAX7310 I/O ports"
 	depends on I2C
@@ -411,6 +428,14 @@
 	  Hub) which is for IVI(In-Vehicle Infotainment) use.
 	  This driver can access the IOH's GPIO device.
 
+config GPIO_SODAVILLE
+	bool "Intel Sodaville GPIO support"
+	depends on X86 && PCI && OF && BROKEN
+	select GPIO_GENERIC
+	select GENERIC_IRQ_CHIP
+	help
+	  Say Y here to support Intel Sodaville GPIO.
+
 config GPIO_TIMBERDALE
 	bool "Support for timberdale GPIO IP"
 	depends on MFD_TIMBERDALE && HAS_IOMEM
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index fa10df6..007f54b 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -16,6 +16,7 @@
 obj-$(CONFIG_GPIO_DA9052)	+= gpio-da9052.o
 obj-$(CONFIG_ARCH_DAVINCI)	+= gpio-davinci.o
 obj-$(CONFIG_GPIO_EP93XX)	+= gpio-ep93xx.o
+obj-$(CONFIG_GPIO_GE_FPGA)	+= gpio-ge.o
 obj-$(CONFIG_GPIO_IT8761E)	+= gpio-it8761e.o
 obj-$(CONFIG_GPIO_JANZ_TTL)	+= gpio-janz-ttl.o
 obj-$(CONFIG_ARCH_KS8695)	+= gpio-ks8695.o
@@ -26,6 +27,7 @@
 obj-$(CONFIG_GPIO_MAX7301)	+= gpio-max7301.o
 obj-$(CONFIG_GPIO_MAX732X)	+= gpio-max732x.o
 obj-$(CONFIG_GPIO_MC33880)	+= gpio-mc33880.o
+obj-$(CONFIG_GPIO_MC9S08DZ60)	+= gpio-mc9s08dz60.o
 obj-$(CONFIG_GPIO_MCP23S08)	+= gpio-mcp23s08.o
 obj-$(CONFIG_GPIO_ML_IOH)	+= gpio-ml-ioh.o
 obj-$(CONFIG_GPIO_MPC5200)	+= gpio-mpc5200.o
@@ -45,6 +47,7 @@
 obj-$(CONFIG_PLAT_SAMSUNG)	+= gpio-samsung.o
 obj-$(CONFIG_ARCH_SA1100)	+= gpio-sa1100.o
 obj-$(CONFIG_GPIO_SCH)		+= gpio-sch.o
+obj-$(CONFIG_GPIO_SODAVILLE)	+= gpio-sodaville.o
 obj-$(CONFIG_GPIO_STMPE)	+= gpio-stmpe.o
 obj-$(CONFIG_GPIO_SX150X)	+= gpio-sx150x.o
 obj-$(CONFIG_GPIO_TC3589X)	+= gpio-tc3589x.o
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index df0d595..3d00016 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -313,10 +313,16 @@
 		return -ENODEV;
 }
 
-static int gpio_irq_type_unbanked(struct irq_data *d, unsigned trigger)
+static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger)
 {
-	struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
-	u32 mask = (u32) irq_data_get_irq_handler_data(d);
+	struct davinci_gpio_controller *d;
+	struct davinci_gpio_regs __iomem *g;
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
+	u32 mask;
+
+	d = (struct davinci_gpio_controller *)data->handler_data;
+	g = (struct davinci_gpio_regs __iomem *)d->regs;
+	mask = __gpio_mask(data->irq - soc_info->gpio_irq);
 
 	if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
 		return -EINVAL;
@@ -380,7 +386,7 @@
 	 * IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs.
 	 */
 	if (soc_info->gpio_unbanked) {
-		static struct irq_chip gpio_irqchip_unbanked;
+		static struct irq_chip_type gpio_unbanked;
 
 		/* pass "bank 0" GPIO IRQs to AINTC */
 		chips[0].chip.to_irq = gpio_to_irq_unbanked;
@@ -388,9 +394,10 @@
 
 		/* AINTC handles mask/unmask; GPIO handles triggering */
 		irq = bank_irq;
-		gpio_irqchip_unbanked = *irq_get_chip(irq);
-		gpio_irqchip_unbanked.name = "GPIO-AINTC";
-		gpio_irqchip_unbanked.irq_set_type = gpio_irq_type_unbanked;
+		gpio_unbanked = *container_of(irq_get_chip(irq),
+					      struct irq_chip_type, chip);
+		gpio_unbanked.chip.name = "GPIO-AINTC";
+		gpio_unbanked.chip.irq_set_type = gpio_irq_type_unbanked;
 
 		/* default trigger: both edges */
 		g = gpio2regs(0);
@@ -399,9 +406,8 @@
 
 		/* set the direct IRQs up to use that irqchip */
 		for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) {
-			irq_set_chip(irq, &gpio_irqchip_unbanked);
-			irq_set_handler_data(irq, (void *)__gpio_mask(gpio));
-			irq_set_chip_data(irq, (__force void *)g);
+			irq_set_chip(irq, &gpio_unbanked.chip);
+			irq_set_handler_data(irq, &chips[gpio / 32]);
 			irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH);
 		}
 
diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c
index 1c0fc37..776b772 100644
--- a/drivers/gpio/gpio-ep93xx.c
+++ b/drivers/gpio/gpio-ep93xx.c
@@ -12,8 +12,6 @@
  *  published by the Free Software Foundation.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -65,11 +63,6 @@
 		EP93XX_GPIO_REG(int_en_register_offset[port]));
 }
 
-static inline void ep93xx_gpio_int_mask(unsigned line)
-{
-	gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7));
-}
-
 static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable)
 {
 	int line = irq_to_gpio(irq);
@@ -212,7 +205,6 @@
 		handler = handle_edge_irq;
 		break;
 	default:
-		pr_err("failed to set irq type %d for gpio %d\n", type, gpio);
 		return -EINVAL;
 	}
 
@@ -378,13 +370,6 @@
 	}
 	ep93xx_gpio->mmio_base = mmio;
 
-	/* Default all ports to GPIO */
-	ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS |
-			       EP93XX_SYSCON_DEVCFG_GONK |
-			       EP93XX_SYSCON_DEVCFG_EONIDE |
-			       EP93XX_SYSCON_DEVCFG_GONIDE |
-			       EP93XX_SYSCON_DEVCFG_HONIDE);
-
 	for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) {
 		struct bgpio_chip *bgc = &ep93xx_gpio->bgc[i];
 		struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i];
diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c
new file mode 100644
index 0000000..7b95a4a
--- /dev/null
+++ b/drivers/gpio/gpio-ge.c
@@ -0,0 +1,199 @@
+/*
+ * Driver for GE FPGA based GPIO
+ *
+ * Author: Martyn Welch <martyn.welch@ge.com>
+ *
+ * 2008 (c) GE Intelligent Platforms Embedded Systems, 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.
+ */
+
+/* TODO
+ *
+ * Configuration of output modes (totem-pole/open-drain)
+ * Interrupt configuration - interrupts are always generated the FPGA relies on
+ * the I/O interrupt controllers mask to stop them propergating
+ */
+
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#define GEF_GPIO_DIRECT		0x00
+#define GEF_GPIO_IN		0x04
+#define GEF_GPIO_OUT		0x08
+#define GEF_GPIO_TRIG		0x0C
+#define GEF_GPIO_POLAR_A	0x10
+#define GEF_GPIO_POLAR_B	0x14
+#define GEF_GPIO_INT_STAT	0x18
+#define GEF_GPIO_OVERRUN	0x1C
+#define GEF_GPIO_MODE		0x20
+
+static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value)
+{
+	unsigned int data;
+
+	data = ioread32be(reg);
+	/* value: 0=low; 1=high */
+	if (value & 0x1)
+		data = data | (0x1 << offset);
+	else
+		data = data & ~(0x1 << offset);
+
+	iowrite32be(data, reg);
+}
+
+
+static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
+{
+	unsigned int data;
+	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
+
+	data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
+	data = data | (0x1 << offset);
+	iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
+
+	return 0;
+}
+
+static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value)
+{
+	unsigned int data;
+	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
+
+	/* Set direction before switching to input */
+	_gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
+
+	data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
+	data = data & ~(0x1 << offset);
+	iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
+
+	return 0;
+}
+
+static int gef_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	unsigned int data;
+	int state = 0;
+	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
+
+	data = ioread32be(mmchip->regs + GEF_GPIO_IN);
+	state = (int)((data >> offset) & 0x1);
+
+	return state;
+}
+
+static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
+
+	_gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
+}
+
+static int __init gef_gpio_init(void)
+{
+	struct device_node *np;
+	int retval;
+	struct of_mm_gpio_chip *gef_gpio_chip;
+
+	for_each_compatible_node(np, NULL, "gef,sbc610-gpio") {
+
+		pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
+
+		/* Allocate chip structure */
+		gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
+		if (!gef_gpio_chip) {
+			pr_err("%s: Unable to allocate structure\n",
+				np->full_name);
+			continue;
+		}
+
+		/* Setup pointers to chip functions */
+		gef_gpio_chip->gc.of_gpio_n_cells = 2;
+		gef_gpio_chip->gc.ngpio = 19;
+		gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
+		gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
+		gef_gpio_chip->gc.get = gef_gpio_get;
+		gef_gpio_chip->gc.set = gef_gpio_set;
+
+		/* This function adds a memory mapped GPIO chip */
+		retval = of_mm_gpiochip_add(np, gef_gpio_chip);
+		if (retval) {
+			kfree(gef_gpio_chip);
+			pr_err("%s: Unable to add GPIO\n", np->full_name);
+		}
+	}
+
+	for_each_compatible_node(np, NULL, "gef,sbc310-gpio") {
+
+		pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
+
+		/* Allocate chip structure */
+		gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
+		if (!gef_gpio_chip) {
+			pr_err("%s: Unable to allocate structure\n",
+				np->full_name);
+			continue;
+		}
+
+		/* Setup pointers to chip functions */
+		gef_gpio_chip->gc.of_gpio_n_cells = 2;
+		gef_gpio_chip->gc.ngpio = 6;
+		gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
+		gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
+		gef_gpio_chip->gc.get = gef_gpio_get;
+		gef_gpio_chip->gc.set = gef_gpio_set;
+
+		/* This function adds a memory mapped GPIO chip */
+		retval = of_mm_gpiochip_add(np, gef_gpio_chip);
+		if (retval) {
+			kfree(gef_gpio_chip);
+			pr_err("%s: Unable to add GPIO\n", np->full_name);
+		}
+	}
+
+	for_each_compatible_node(np, NULL, "ge,imp3a-gpio") {
+
+		pr_debug("%s: Initialising GE GPIO\n", np->full_name);
+
+		/* Allocate chip structure */
+		gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
+		if (!gef_gpio_chip) {
+			pr_err("%s: Unable to allocate structure\n",
+				np->full_name);
+			continue;
+		}
+
+		/* Setup pointers to chip functions */
+		gef_gpio_chip->gc.of_gpio_n_cells = 2;
+		gef_gpio_chip->gc.ngpio = 16;
+		gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
+		gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
+		gef_gpio_chip->gc.get = gef_gpio_get;
+		gef_gpio_chip->gc.set = gef_gpio_set;
+
+		/* This function adds a memory mapped GPIO chip */
+		retval = of_mm_gpiochip_add(np, gef_gpio_chip);
+		if (retval) {
+			kfree(gef_gpio_chip);
+			pr_err("%s: Unable to add GPIO\n", np->full_name);
+		}
+	}
+
+	return 0;
+};
+arch_initcall(gef_gpio_init);
+
+MODULE_DESCRIPTION("GE I/O FPGA GPIO driver");
+MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c
index ddfacc5..61c2d08 100644
--- a/drivers/gpio/gpio-lpc32xx.c
+++ b/drivers/gpio/gpio-lpc32xx.c
@@ -59,12 +59,14 @@
 #define GPO3_PIN_TO_BIT(x)			(1 << (x))
 #define GPIO012_PIN_IN_SEL(x, y)		(((x) >> (y)) & 1)
 #define GPIO3_PIN_IN_SHIFT(x)			((x) == 5 ? 24 : 10 + (x))
-#define GPIO3_PIN_IN_SEL(x, y)			((x) >> GPIO3_PIN_IN_SHIFT(y))
+#define GPIO3_PIN_IN_SEL(x, y)			(((x) >> GPIO3_PIN_IN_SHIFT(y)) & 1)
 #define GPIO3_PIN5_IN_SEL(x)			(((x) >> 24) & 1)
 #define GPI3_PIN_IN_SEL(x, y)			(((x) >> (y)) & 1)
+#define GPO3_PIN_IN_SEL(x, y)			(((x) >> (y)) & 1)
 
 struct gpio_regs {
 	void __iomem *inp_state;
+	void __iomem *outp_state;
 	void __iomem *outp_set;
 	void __iomem *outp_clr;
 	void __iomem *dir_set;
@@ -145,6 +147,7 @@
 
 static struct gpio_regs gpio_grp_regs_p3 = {
 	.inp_state	= LPC32XX_GPIO_P3_INP_STATE,
+	.outp_state	= LPC32XX_GPIO_P3_OUTP_STATE,
 	.outp_set	= LPC32XX_GPIO_P3_OUTP_SET,
 	.outp_clr	= LPC32XX_GPIO_P3_OUTP_CLR,
 	.dir_set	= LPC32XX_GPIO_P2_DIR_SET,
@@ -240,6 +243,12 @@
 	return GPI3_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state), pin);
 }
 
+static int __get_gpo_state_p3(struct lpc32xx_gpio_chip *group,
+	unsigned pin)
+{
+	return GPO3_PIN_IN_SEL(__raw_readl(group->gpio_grp->outp_state), pin);
+}
+
 /*
  * GENERIC_GPIO primitives.
  */
@@ -340,6 +349,13 @@
 	__set_gpo_level_p3(group, pin, value);
 }
 
+static int lpc32xx_gpo_get_value(struct gpio_chip *chip, unsigned pin)
+{
+	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+	return __get_gpo_state_p3(group, pin);
+}
+
 static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin)
 {
 	if (pin < chip->ngpio)
@@ -427,6 +443,7 @@
 			.label			= "gpo_p3",
 			.direction_output	= lpc32xx_gpio_dir_out_always,
 			.set			= lpc32xx_gpo_set_value,
+			.get			= lpc32xx_gpo_get_value,
 			.request		= lpc32xx_gpio_request,
 			.base			= LPC32XX_GPO_P3_GRP,
 			.ngpio			= LPC32XX_GPO_P3_MAX,
diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c
new file mode 100644
index 0000000..2738cc4
--- /dev/null
+++ b/drivers/gpio/gpio-mc9s08dz60.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Author: Wu Guoxing <b39297@freescale.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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+
+#define GPIO_GROUP_NUM 2
+#define GPIO_NUM_PER_GROUP 8
+#define GPIO_NUM (GPIO_GROUP_NUM*GPIO_NUM_PER_GROUP)
+
+struct mc9s08dz60 {
+	struct i2c_client *client;
+	struct gpio_chip chip;
+};
+
+static inline struct mc9s08dz60 *to_mc9s08dz60(struct gpio_chip *gc)
+{
+	return container_of(gc, struct mc9s08dz60, chip);
+}
+
+
+static void mc9s_gpio_to_reg_and_bit(int offset, u8 *reg, u8 *bit)
+{
+	*reg = 0x20 + offset / GPIO_NUM_PER_GROUP;
+	*bit = offset % GPIO_NUM_PER_GROUP;
+}
+
+static int mc9s08dz60_get_value(struct gpio_chip *gc, unsigned offset)
+{
+	u8 reg, bit;
+	s32 value;
+	struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+
+	mc9s_gpio_to_reg_and_bit(offset, &reg, &bit);
+	value = i2c_smbus_read_byte_data(mc9s->client, reg);
+
+	return (value >= 0) ? (value >> bit) & 0x1 : 0;
+}
+
+static int mc9s08dz60_set(struct mc9s08dz60 *mc9s, unsigned offset, int val)
+{
+	u8 reg, bit;
+	s32 value;
+
+	mc9s_gpio_to_reg_and_bit(offset, &reg, &bit);
+	value = i2c_smbus_read_byte_data(mc9s->client, reg);
+	if (value >= 0) {
+		if (val)
+			value |= 1 << bit;
+		else
+			value &= ~(1 << bit);
+
+		return i2c_smbus_write_byte_data(mc9s->client, reg, value);
+	} else
+		return value;
+
+}
+
+
+static void mc9s08dz60_set_value(struct gpio_chip *gc, unsigned offset, int val)
+{
+	struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+
+	mc9s08dz60_set(mc9s, offset, val);
+}
+
+static int mc9s08dz60_direction_output(struct gpio_chip *gc,
+				       unsigned offset, int val)
+{
+	struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+
+	return mc9s08dz60_set(mc9s, offset, val);
+}
+
+static int mc9s08dz60_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	int ret = 0;
+	struct mc9s08dz60 *mc9s;
+
+	mc9s = kzalloc(sizeof(*mc9s), GFP_KERNEL);
+	if (!mc9s)
+		return -ENOMEM;
+
+	mc9s->chip.label = client->name;
+	mc9s->chip.base = -1;
+	mc9s->chip.dev = &client->dev;
+	mc9s->chip.owner = THIS_MODULE;
+	mc9s->chip.ngpio = GPIO_NUM;
+	mc9s->chip.can_sleep = 1;
+	mc9s->chip.get = mc9s08dz60_get_value;
+	mc9s->chip.set = mc9s08dz60_set_value;
+	mc9s->chip.direction_output = mc9s08dz60_direction_output;
+	mc9s->client = client;
+	i2c_set_clientdata(client, mc9s);
+
+	ret = gpiochip_add(&mc9s->chip);
+	if (ret)
+		goto error;
+
+	return 0;
+
+ error:
+	kfree(mc9s);
+	return ret;
+}
+
+static int mc9s08dz60_remove(struct i2c_client *client)
+{
+	struct mc9s08dz60 *mc9s;
+	int ret;
+
+	mc9s = i2c_get_clientdata(client);
+
+	ret = gpiochip_remove(&mc9s->chip);
+	if (!ret)
+		kfree(mc9s);
+
+	return ret;
+
+}
+
+static const struct i2c_device_id mc9s08dz60_id[] = {
+	{"mc9s08dz60", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, mc9s08dz60_id);
+
+static struct i2c_driver mc9s08dz60_i2c_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "mc9s08dz60",
+	},
+	.probe = mc9s08dz60_probe,
+	.remove = mc9s08dz60_remove,
+	.id_table = mc9s08dz60_id,
+};
+
+module_i2c_driver(mc9s08dz60_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc. "
+		"Wu Guoxing <b39297@freescale.com>");
+MODULE_DESCRIPTION("mc9s08dz60 gpio function on mx35 3ds board");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 0b05629..1adc2ec 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -19,8 +19,12 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
-#include <linux/slab.h>
+#include <linux/device.h>
 #include <linux/pm_runtime.h>
+#include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/irqdomain.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
@@ -28,41 +32,11 @@
 #include <asm/gpio.h>
 #include <asm/mach/irq.h>
 
-struct gpio_bank {
-	unsigned long pbase;
-	void __iomem *base;
-	u16 irq;
-	u16 virtual_irq_start;
-	int method;
-	u32 suspend_wakeup;
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
-	u32 saved_wakeup;
-#endif
-	u32 non_wakeup_gpios;
-	u32 enabled_non_wakeup_gpios;
+#define OFF_MODE	1
 
-	u32 saved_datain;
-	u32 saved_fallingdetect;
-	u32 saved_risingdetect;
-	u32 level_mask;
-	u32 toggle_mask;
-	spinlock_t lock;
-	struct gpio_chip chip;
-	struct clk *dbck;
-	u32 mod_usage;
-	u32 dbck_enable_mask;
-	struct device *dev;
-	bool dbck_flag;
-	int stride;
-	u32 width;
+static LIST_HEAD(omap_gpio_list);
 
-	void (*set_dataout)(struct gpio_bank *bank, int gpio, int enable);
-
-	struct omap_gpio_reg_offs *regs;
-};
-
-#ifdef CONFIG_ARCH_OMAP3
-struct omap3_gpio_regs {
+struct gpio_regs {
 	u32 irqenable1;
 	u32 irqenable2;
 	u32 wake_en;
@@ -73,22 +47,56 @@
 	u32 risingdetect;
 	u32 fallingdetect;
 	u32 dataout;
+	u32 debounce;
+	u32 debounce_en;
 };
 
-static struct omap3_gpio_regs gpio_context[OMAP34XX_NR_GPIOS];
-#endif
+struct gpio_bank {
+	struct list_head node;
+	void __iomem *base;
+	u16 irq;
+	int irq_base;
+	struct irq_domain *domain;
+	u32 suspend_wakeup;
+	u32 saved_wakeup;
+	u32 non_wakeup_gpios;
+	u32 enabled_non_wakeup_gpios;
+	struct gpio_regs context;
+	u32 saved_datain;
+	u32 saved_fallingdetect;
+	u32 saved_risingdetect;
+	u32 level_mask;
+	u32 toggle_mask;
+	spinlock_t lock;
+	struct gpio_chip chip;
+	struct clk *dbck;
+	u32 mod_usage;
+	u32 dbck_enable_mask;
+	bool dbck_enabled;
+	struct device *dev;
+	bool is_mpuio;
+	bool dbck_flag;
+	bool loses_context;
+	int stride;
+	u32 width;
+	int context_loss_count;
+	int power_mode;
+	bool workaround_enabled;
 
-/*
- * TODO: Cleanup gpio_bank usage as it is having information
- * related to all instances of the device
- */
-static struct gpio_bank *gpio_bank;
+	void (*set_dataout)(struct gpio_bank *bank, int gpio, int enable);
+	int (*get_context_loss_count)(struct device *dev);
 
-/* TODO: Analyze removing gpio_bank_count usage from driver code */
-int gpio_bank_count;
+	struct omap_gpio_reg_offs *regs;
+};
 
 #define GPIO_INDEX(bank, gpio) (gpio % bank->width)
 #define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio))
+#define GPIO_MOD_CTRL_BIT	BIT(0)
+
+static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
+{
+	return gpio_irq - bank->irq_base + bank->chip.base;
+}
 
 static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
 {
@@ -102,6 +110,7 @@
 	else
 		l &= ~(1 << gpio);
 	__raw_writel(l, reg);
+	bank->context.oe = l;
 }
 
 
@@ -111,10 +120,13 @@
 	void __iomem *reg = bank->base;
 	u32 l = GPIO_BIT(bank, gpio);
 
-	if (enable)
+	if (enable) {
 		reg += bank->regs->set_dataout;
-	else
+		bank->context.dataout |= l;
+	} else {
 		reg += bank->regs->clr_dataout;
+		bank->context.dataout &= ~l;
+	}
 
 	__raw_writel(l, reg);
 }
@@ -132,27 +144,28 @@
 	else
 		l &= ~gpio_bit;
 	__raw_writel(l, reg);
+	bank->context.dataout = l;
 }
 
-static int _get_gpio_datain(struct gpio_bank *bank, int gpio)
+static int _get_gpio_datain(struct gpio_bank *bank, int offset)
 {
 	void __iomem *reg = bank->base + bank->regs->datain;
 
-	return (__raw_readl(reg) & GPIO_BIT(bank, gpio)) != 0;
+	return (__raw_readl(reg) & (1 << offset)) != 0;
 }
 
-static int _get_gpio_dataout(struct gpio_bank *bank, int gpio)
+static int _get_gpio_dataout(struct gpio_bank *bank, int offset)
 {
 	void __iomem *reg = bank->base + bank->regs->dataout;
 
-	return (__raw_readl(reg) & GPIO_BIT(bank, gpio)) != 0;
+	return (__raw_readl(reg) & (1 << offset)) != 0;
 }
 
 static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
 {
 	int l = __raw_readl(base + reg);
 
-	if (set) 
+	if (set)
 		l |= mask;
 	else
 		l &= ~mask;
@@ -160,6 +173,22 @@
 	__raw_writel(l, base + reg);
 }
 
+static inline void _gpio_dbck_enable(struct gpio_bank *bank)
+{
+	if (bank->dbck_enable_mask && !bank->dbck_enabled) {
+		clk_enable(bank->dbck);
+		bank->dbck_enabled = true;
+	}
+}
+
+static inline void _gpio_dbck_disable(struct gpio_bank *bank)
+{
+	if (bank->dbck_enable_mask && bank->dbck_enabled) {
+		clk_disable(bank->dbck);
+		bank->dbck_enabled = false;
+	}
+}
+
 /**
  * _set_gpio_debounce - low level gpio debounce time
  * @bank: the gpio bank we're acting upon
@@ -188,70 +217,74 @@
 
 	l = GPIO_BIT(bank, gpio);
 
+	clk_enable(bank->dbck);
 	reg = bank->base + bank->regs->debounce;
 	__raw_writel(debounce, reg);
 
 	reg = bank->base + bank->regs->debounce_en;
 	val = __raw_readl(reg);
 
-	if (debounce) {
+	if (debounce)
 		val |= l;
-		clk_enable(bank->dbck);
-	} else {
+	else
 		val &= ~l;
-		clk_disable(bank->dbck);
-	}
 	bank->dbck_enable_mask = val;
 
 	__raw_writel(val, reg);
+	clk_disable(bank->dbck);
+	/*
+	 * Enable debounce clock per module.
+	 * This call is mandatory because in omap_gpio_request() when
+	 * *_runtime_get_sync() is called,  _gpio_dbck_enable() within
+	 * runtime callbck fails to turn on dbck because dbck_enable_mask
+	 * used within _gpio_dbck_enable() is still not initialized at
+	 * that point. Therefore we have to enable dbck here.
+	 */
+	_gpio_dbck_enable(bank);
+	if (bank->dbck_enable_mask) {
+		bank->context.debounce = debounce;
+		bank->context.debounce_en = val;
+	}
 }
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
-						int trigger)
+static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
+						unsigned trigger)
 {
 	void __iomem *base = bank->base;
 	u32 gpio_bit = 1 << gpio;
 
-	if (cpu_is_omap44xx()) {
-		_gpio_rmw(base, OMAP4_GPIO_LEVELDETECT0, gpio_bit,
-			  trigger & IRQ_TYPE_LEVEL_LOW);
-		_gpio_rmw(base, OMAP4_GPIO_LEVELDETECT1, gpio_bit,
-			  trigger & IRQ_TYPE_LEVEL_HIGH);
-		_gpio_rmw(base, OMAP4_GPIO_RISINGDETECT, gpio_bit,
-			  trigger & IRQ_TYPE_EDGE_RISING);
-		_gpio_rmw(base, OMAP4_GPIO_FALLINGDETECT, gpio_bit,
-			  trigger & IRQ_TYPE_EDGE_FALLING);
-	} else {
-		_gpio_rmw(base, OMAP24XX_GPIO_LEVELDETECT0, gpio_bit,
-			  trigger & IRQ_TYPE_LEVEL_LOW);
-		_gpio_rmw(base, OMAP24XX_GPIO_LEVELDETECT1, gpio_bit,
-			  trigger & IRQ_TYPE_LEVEL_HIGH);
-		_gpio_rmw(base, OMAP24XX_GPIO_RISINGDETECT, gpio_bit,
-			  trigger & IRQ_TYPE_EDGE_RISING);
-		_gpio_rmw(base, OMAP24XX_GPIO_FALLINGDETECT, gpio_bit,
-			  trigger & IRQ_TYPE_EDGE_FALLING);
-	}
+	_gpio_rmw(base, bank->regs->leveldetect0, gpio_bit,
+		  trigger & IRQ_TYPE_LEVEL_LOW);
+	_gpio_rmw(base, bank->regs->leveldetect1, gpio_bit,
+		  trigger & IRQ_TYPE_LEVEL_HIGH);
+	_gpio_rmw(base, bank->regs->risingdetect, gpio_bit,
+		  trigger & IRQ_TYPE_EDGE_RISING);
+	_gpio_rmw(base, bank->regs->fallingdetect, gpio_bit,
+		  trigger & IRQ_TYPE_EDGE_FALLING);
+
+	bank->context.leveldetect0 =
+			__raw_readl(bank->base + bank->regs->leveldetect0);
+	bank->context.leveldetect1 =
+			__raw_readl(bank->base + bank->regs->leveldetect1);
+	bank->context.risingdetect =
+			__raw_readl(bank->base + bank->regs->risingdetect);
+	bank->context.fallingdetect =
+			__raw_readl(bank->base + bank->regs->fallingdetect);
+
 	if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
-		if (cpu_is_omap44xx()) {
-			_gpio_rmw(base, OMAP4_GPIO_IRQWAKEN0, gpio_bit,
-				  trigger != 0);
-		} else {
-			/*
-			 * GPIO wakeup request can only be generated on edge
-			 * transitions
-			 */
-			if (trigger & IRQ_TYPE_EDGE_BOTH)
-				__raw_writel(1 << gpio, bank->base
-					+ OMAP24XX_GPIO_SETWKUENA);
-			else
-				__raw_writel(1 << gpio, bank->base
-					+ OMAP24XX_GPIO_CLEARWKUENA);
-		}
+		_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0);
+		bank->context.wake_en =
+			__raw_readl(bank->base + bank->regs->wkup_en);
 	}
+
 	/* This part needs to be executed always for OMAP{34xx, 44xx} */
-	if (cpu_is_omap34xx() || cpu_is_omap44xx() ||
-			(bank->non_wakeup_gpios & gpio_bit)) {
+	if (!bank->regs->irqctrl) {
+		/* On omap24xx proceed only when valid GPIO bit is set */
+		if (bank->non_wakeup_gpios) {
+			if (!(bank->non_wakeup_gpios & gpio_bit))
+				goto exit;
+		}
+
 		/*
 		 * Log the edge gpio and manually trigger the IRQ
 		 * after resume if the input level changes
@@ -264,17 +297,11 @@
 			bank->enabled_non_wakeup_gpios &= ~gpio_bit;
 	}
 
-	if (cpu_is_omap44xx()) {
-		bank->level_mask =
-			__raw_readl(bank->base + OMAP4_GPIO_LEVELDETECT0) |
-			__raw_readl(bank->base + OMAP4_GPIO_LEVELDETECT1);
-	} else {
-		bank->level_mask =
-			__raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0) |
-			__raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
-	}
+exit:
+	bank->level_mask =
+		__raw_readl(bank->base + bank->regs->leveldetect0) |
+		__raw_readl(bank->base + bank->regs->leveldetect1);
 }
-#endif
 
 #ifdef CONFIG_ARCH_OMAP1
 /*
@@ -286,23 +313,10 @@
 	void __iomem *reg = bank->base;
 	u32 l = 0;
 
-	switch (bank->method) {
-	case METHOD_MPUIO:
-		reg += OMAP_MPUIO_GPIO_INT_EDGE / bank->stride;
-		break;
-#ifdef CONFIG_ARCH_OMAP15XX
-	case METHOD_GPIO_1510:
-		reg += OMAP1510_GPIO_INT_CONTROL;
-		break;
-#endif
-#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
-	case METHOD_GPIO_7XX:
-		reg += OMAP7XX_GPIO_INT_CONTROL;
-		break;
-#endif
-	default:
+	if (!bank->regs->irqctrl)
 		return;
-	}
+
+	reg += bank->regs->irqctrl;
 
 	l = __raw_readl(reg);
 	if ((l >> gpio) & 1)
@@ -312,17 +326,22 @@
 
 	__raw_writel(l, reg);
 }
+#else
+static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {}
 #endif
 
-static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
+static int _set_gpio_triggering(struct gpio_bank *bank, int gpio,
+							unsigned trigger)
 {
 	void __iomem *reg = bank->base;
+	void __iomem *base = bank->base;
 	u32 l = 0;
 
-	switch (bank->method) {
-#ifdef CONFIG_ARCH_OMAP1
-	case METHOD_MPUIO:
-		reg += OMAP_MPUIO_GPIO_INT_EDGE / bank->stride;
+	if (bank->regs->leveldetect0 && bank->regs->wkup_en) {
+		set_gpio_trigger(bank, gpio, trigger);
+	} else if (bank->regs->irqctrl) {
+		reg += bank->regs->irqctrl;
+
 		l = __raw_readl(reg);
 		if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
 			bank->toggle_mask |= 1 << gpio;
@@ -331,29 +350,15 @@
 		else if (trigger & IRQ_TYPE_EDGE_FALLING)
 			l &= ~(1 << gpio);
 		else
-			goto bad;
-		break;
-#endif
-#ifdef CONFIG_ARCH_OMAP15XX
-	case METHOD_GPIO_1510:
-		reg += OMAP1510_GPIO_INT_CONTROL;
-		l = __raw_readl(reg);
-		if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
-			bank->toggle_mask |= 1 << gpio;
-		if (trigger & IRQ_TYPE_EDGE_RISING)
-			l |= 1 << gpio;
-		else if (trigger & IRQ_TYPE_EDGE_FALLING)
-			l &= ~(1 << gpio);
-		else
-			goto bad;
-		break;
-#endif
-#ifdef CONFIG_ARCH_OMAP16XX
-	case METHOD_GPIO_1610:
+			return -EINVAL;
+
+		__raw_writel(l, reg);
+	} else if (bank->regs->edgectrl1) {
 		if (gpio & 0x08)
-			reg += OMAP1610_GPIO_EDGE_CTRL2;
+			reg += bank->regs->edgectrl2;
 		else
-			reg += OMAP1610_GPIO_EDGE_CTRL1;
+			reg += bank->regs->edgectrl1;
+
 		gpio &= 0x07;
 		l = __raw_readl(reg);
 		l &= ~(3 << (gpio << 1));
@@ -361,45 +366,19 @@
 			l |= 2 << (gpio << 1);
 		if (trigger & IRQ_TYPE_EDGE_FALLING)
 			l |= 1 << (gpio << 1);
-		if (trigger)
-			/* Enable wake-up during idle for dynamic tick */
-			__raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_SET_WAKEUPENA);
-		else
-			__raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA);
-		break;
-#endif
-#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
-	case METHOD_GPIO_7XX:
-		reg += OMAP7XX_GPIO_INT_CONTROL;
-		l = __raw_readl(reg);
-		if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
-			bank->toggle_mask |= 1 << gpio;
-		if (trigger & IRQ_TYPE_EDGE_RISING)
-			l |= 1 << gpio;
-		else if (trigger & IRQ_TYPE_EDGE_FALLING)
-			l &= ~(1 << gpio);
-		else
-			goto bad;
-		break;
-#endif
-#ifdef CONFIG_ARCH_OMAP2PLUS
-	case METHOD_GPIO_24XX:
-	case METHOD_GPIO_44XX:
-		set_24xx_gpio_triggering(bank, gpio, trigger);
-		return 0;
-#endif
-	default:
-		goto bad;
+
+		/* Enable wake-up during idle for dynamic tick */
+		_gpio_rmw(base, bank->regs->wkup_en, 1 << gpio, trigger);
+		bank->context.wake_en =
+			__raw_readl(bank->base + bank->regs->wkup_en);
+		__raw_writel(l, reg);
 	}
-	__raw_writel(l, reg);
 	return 0;
-bad:
-	return -EINVAL;
 }
 
 static int gpio_irq_type(struct irq_data *d, unsigned type)
 {
-	struct gpio_bank *bank;
+	struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
 	unsigned gpio;
 	int retval;
 	unsigned long flags;
@@ -407,17 +386,15 @@
 	if (!cpu_class_is_omap2() && d->irq > IH_MPUIO_BASE)
 		gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE);
 	else
-		gpio = d->irq - IH_GPIO_BASE;
+		gpio = irq_to_gpio(bank, d->irq);
 
 	if (type & ~IRQ_TYPE_SENSE_MASK)
 		return -EINVAL;
 
-	/* OMAP1 allows only only edge triggering */
-	if (!cpu_class_is_omap2()
-			&& (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
+	if (!bank->regs->leveldetect0 &&
+		(type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
 		return -EINVAL;
 
-	bank = irq_data_get_irq_chip_data(d);
 	spin_lock_irqsave(&bank->lock, flags);
 	retval = _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), type);
 	spin_unlock_irqrestore(&bank->lock, flags);
@@ -474,6 +451,7 @@
 	if (bank->regs->set_irqenable) {
 		reg += bank->regs->set_irqenable;
 		l = gpio_mask;
+		bank->context.irqenable1 |= gpio_mask;
 	} else {
 		reg += bank->regs->irqenable;
 		l = __raw_readl(reg);
@@ -481,6 +459,7 @@
 			l &= ~gpio_mask;
 		else
 			l |= gpio_mask;
+		bank->context.irqenable1 = l;
 	}
 
 	__raw_writel(l, reg);
@@ -494,6 +473,7 @@
 	if (bank->regs->clr_irqenable) {
 		reg += bank->regs->clr_irqenable;
 		l = gpio_mask;
+		bank->context.irqenable1 &= ~gpio_mask;
 	} else {
 		reg += bank->regs->irqenable;
 		l = __raw_readl(reg);
@@ -501,6 +481,7 @@
 			l |= gpio_mask;
 		else
 			l &= ~gpio_mask;
+		bank->context.irqenable1 = l;
 	}
 
 	__raw_writel(l, reg);
@@ -508,7 +489,10 @@
 
 static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable)
 {
-	_enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
+	if (enable)
+		_enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
+	else
+		_disable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
 }
 
 /*
@@ -525,7 +509,7 @@
 	unsigned long flags;
 
 	if (bank->non_wakeup_gpios & gpio_bit) {
-		dev_err(bank->dev, 
+		dev_err(bank->dev,
 			"Unable to modify wakeup on non-wakeup GPIO%d\n", gpio);
 		return -EINVAL;
 	}
@@ -536,6 +520,7 @@
 	else
 		bank->suspend_wakeup &= ~gpio_bit;
 
+	__raw_writel(bank->suspend_wakeup, bank->base + bank->regs->wkup_en);
 	spin_unlock_irqrestore(&bank->lock, flags);
 
 	return 0;
@@ -552,14 +537,10 @@
 /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
 static int gpio_wake_enable(struct irq_data *d, unsigned int enable)
 {
-	unsigned int gpio = d->irq - IH_GPIO_BASE;
-	struct gpio_bank *bank;
-	int retval;
+	struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+	unsigned int gpio = irq_to_gpio(bank, d->irq);
 
-	bank = irq_data_get_irq_chip_data(d);
-	retval = _set_gpio_wakeup(bank, gpio, enable);
-
-	return retval;
+	return _set_gpio_wakeup(bank, gpio, enable);
 }
 
 static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -567,38 +548,39 @@
 	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
 	unsigned long flags;
 
-	spin_lock_irqsave(&bank->lock, flags);
+	/*
+	 * If this is the first gpio_request for the bank,
+	 * enable the bank module.
+	 */
+	if (!bank->mod_usage)
+		pm_runtime_get_sync(bank->dev);
 
+	spin_lock_irqsave(&bank->lock, flags);
 	/* Set trigger to none. You need to enable the desired trigger with
 	 * request_irq() or set_irq_type().
 	 */
 	_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
 
-#ifdef CONFIG_ARCH_OMAP15XX
-	if (bank->method == METHOD_GPIO_1510) {
-		void __iomem *reg;
+	if (bank->regs->pinctrl) {
+		void __iomem *reg = bank->base + bank->regs->pinctrl;
 
 		/* Claim the pin for MPU */
-		reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;
 		__raw_writel(__raw_readl(reg) | (1 << offset), reg);
 	}
-#endif
-	if (!cpu_class_is_omap1()) {
-		if (!bank->mod_usage) {
-			void __iomem *reg = bank->base;
-			u32 ctrl;
 
-			if (cpu_is_omap24xx() || cpu_is_omap34xx())
-				reg += OMAP24XX_GPIO_CTRL;
-			else if (cpu_is_omap44xx())
-				reg += OMAP4_GPIO_CTRL;
-			ctrl = __raw_readl(reg);
-			/* Module is enabled, clocks are not gated */
-			ctrl &= 0xFFFFFFFE;
-			__raw_writel(ctrl, reg);
-		}
-		bank->mod_usage |= 1 << offset;
+	if (bank->regs->ctrl && !bank->mod_usage) {
+		void __iomem *reg = bank->base + bank->regs->ctrl;
+		u32 ctrl;
+
+		ctrl = __raw_readl(reg);
+		/* Module is enabled, clocks are not gated */
+		ctrl &= ~GPIO_MOD_CTRL_BIT;
+		__raw_writel(ctrl, reg);
+		bank->context.ctrl = ctrl;
 	}
+
+	bank->mod_usage |= 1 << offset;
+
 	spin_unlock_irqrestore(&bank->lock, flags);
 
 	return 0;
@@ -607,48 +589,40 @@
 static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
 	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+	void __iomem *base = bank->base;
 	unsigned long flags;
 
 	spin_lock_irqsave(&bank->lock, flags);
-#ifdef CONFIG_ARCH_OMAP16XX
-	if (bank->method == METHOD_GPIO_1610) {
-		/* Disable wake-up during idle for dynamic tick */
-		void __iomem *reg = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
-		__raw_writel(1 << offset, reg);
-	}
-#endif
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-	if (bank->method == METHOD_GPIO_24XX) {
-		/* Disable wake-up during idle for dynamic tick */
-		void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
-		__raw_writel(1 << offset, reg);
-	}
-#endif
-#ifdef CONFIG_ARCH_OMAP4
-	if (bank->method == METHOD_GPIO_44XX) {
-		/* Disable wake-up during idle for dynamic tick */
-		void __iomem *reg = bank->base + OMAP4_GPIO_IRQWAKEN0;
-		__raw_writel(1 << offset, reg);
-	}
-#endif
-	if (!cpu_class_is_omap1()) {
-		bank->mod_usage &= ~(1 << offset);
-		if (!bank->mod_usage) {
-			void __iomem *reg = bank->base;
-			u32 ctrl;
 
-			if (cpu_is_omap24xx() || cpu_is_omap34xx())
-				reg += OMAP24XX_GPIO_CTRL;
-			else if (cpu_is_omap44xx())
-				reg += OMAP4_GPIO_CTRL;
-			ctrl = __raw_readl(reg);
-			/* Module is disabled, clocks are gated */
-			ctrl |= 1;
-			__raw_writel(ctrl, reg);
-		}
+	if (bank->regs->wkup_en) {
+		/* Disable wake-up during idle for dynamic tick */
+		_gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0);
+		bank->context.wake_en =
+			__raw_readl(bank->base + bank->regs->wkup_en);
 	}
+
+	bank->mod_usage &= ~(1 << offset);
+
+	if (bank->regs->ctrl && !bank->mod_usage) {
+		void __iomem *reg = bank->base + bank->regs->ctrl;
+		u32 ctrl;
+
+		ctrl = __raw_readl(reg);
+		/* Module is disabled, clocks are gated */
+		ctrl |= GPIO_MOD_CTRL_BIT;
+		__raw_writel(ctrl, reg);
+		bank->context.ctrl = ctrl;
+	}
+
 	_reset_gpio(bank, bank->chip.base + offset);
 	spin_unlock_irqrestore(&bank->lock, flags);
+
+	/*
+	 * If this is the last gpio to be freed in the bank,
+	 * disable the bank module.
+	 */
+	if (!bank->mod_usage)
+		pm_runtime_put(bank->dev);
 }
 
 /*
@@ -674,6 +648,7 @@
 
 	bank = irq_get_handler_data(irq);
 	isr_reg = bank->base + bank->regs->irqstatus;
+	pm_runtime_get_sync(bank->dev);
 
 	if (WARN_ON(!isr_reg))
 		goto exit;
@@ -685,12 +660,8 @@
 		enabled = _get_gpio_irqbank_mask(bank);
 		isr_saved = isr = __raw_readl(isr_reg) & enabled;
 
-		if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO))
-			isr &= 0x0000ffff;
-
-		if (cpu_class_is_omap2()) {
+		if (bank->level_mask)
 			level_mask = bank->level_mask & enabled;
-		}
 
 		/* clear edge sensitive interrupts before handler(s) are
 		called so that we don't miss any interrupt occurred while
@@ -711,14 +682,15 @@
 		if (!isr)
 			break;
 
-		gpio_irq = bank->virtual_irq_start;
+		gpio_irq = bank->irq_base;
 		for (; isr != 0; isr >>= 1, gpio_irq++) {
-			gpio_index = GPIO_INDEX(bank, irq_to_gpio(gpio_irq));
+			int gpio = irq_to_gpio(bank, gpio_irq);
 
 			if (!(isr & 1))
 				continue;
 
-#ifdef CONFIG_ARCH_OMAP1
+			gpio_index = GPIO_INDEX(bank, gpio);
+
 			/*
 			 * Some chips can't respond to both rising and falling
 			 * at the same time.  If this irq was requested with
@@ -728,7 +700,6 @@
 			 */
 			if (bank->toggle_mask & (1 << gpio_index))
 				_toggle_gpio_edge_triggering(bank, gpio_index);
-#endif
 
 			generic_handle_irq(gpio_irq);
 		}
@@ -740,12 +711,13 @@
 exit:
 	if (!unmasked)
 		chained_irq_exit(chip, desc);
+	pm_runtime_put(bank->dev);
 }
 
 static void gpio_irq_shutdown(struct irq_data *d)
 {
-	unsigned int gpio = d->irq - IH_GPIO_BASE;
 	struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+	unsigned int gpio = irq_to_gpio(bank, d->irq);
 	unsigned long flags;
 
 	spin_lock_irqsave(&bank->lock, flags);
@@ -755,16 +727,16 @@
 
 static void gpio_ack_irq(struct irq_data *d)
 {
-	unsigned int gpio = d->irq - IH_GPIO_BASE;
 	struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+	unsigned int gpio = irq_to_gpio(bank, d->irq);
 
 	_clear_gpio_irqstatus(bank, gpio);
 }
 
 static void gpio_mask_irq(struct irq_data *d)
 {
-	unsigned int gpio = d->irq - IH_GPIO_BASE;
 	struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+	unsigned int gpio = irq_to_gpio(bank, d->irq);
 	unsigned long flags;
 
 	spin_lock_irqsave(&bank->lock, flags);
@@ -775,8 +747,8 @@
 
 static void gpio_unmask_irq(struct irq_data *d)
 {
-	unsigned int gpio = d->irq - IH_GPIO_BASE;
 	struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+	unsigned int gpio = irq_to_gpio(bank, d->irq);
 	unsigned int irq_mask = GPIO_BIT(bank, gpio);
 	u32 trigger = irqd_get_trigger_type(d);
 	unsigned long flags;
@@ -808,14 +780,6 @@
 
 /*---------------------------------------------------------------------*/
 
-#ifdef CONFIG_ARCH_OMAP1
-
-#define bank_is_mpuio(bank)	((bank)->method == METHOD_MPUIO)
-
-#ifdef CONFIG_ARCH_OMAP16XX
-
-#include <linux/platform_device.h>
-
 static int omap_mpuio_suspend_noirq(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
@@ -869,32 +833,16 @@
 	/* could list the /proc/iomem resources */
 };
 
-static inline void mpuio_init(void)
+static inline void mpuio_init(struct gpio_bank *bank)
 {
-	struct gpio_bank *bank = &gpio_bank[0];
 	platform_set_drvdata(&omap_mpuio_device, bank);
 
 	if (platform_driver_register(&omap_mpuio_driver) == 0)
 		(void) platform_device_register(&omap_mpuio_device);
 }
 
-#else
-static inline void mpuio_init(void) {}
-#endif	/* 16xx */
-
-#else
-
-#define bank_is_mpuio(bank)	0
-static inline void mpuio_init(void) {}
-
-#endif
-
 /*---------------------------------------------------------------------*/
 
-/* REVISIT these are stupid implementations!  replace by ones that
- * don't switch on METHOD_* and which mostly avoid spinlocks
- */
-
 static int gpio_input(struct gpio_chip *chip, unsigned offset)
 {
 	struct gpio_bank *bank;
@@ -917,19 +865,15 @@
 static int gpio_get(struct gpio_chip *chip, unsigned offset)
 {
 	struct gpio_bank *bank;
-	void __iomem *reg;
-	int gpio;
 	u32 mask;
 
-	gpio = chip->base + offset;
 	bank = container_of(chip, struct gpio_bank, chip);
-	reg = bank->base;
-	mask = GPIO_BIT(bank, gpio);
+	mask = (1 << offset);
 
 	if (gpio_is_input(bank, mask))
-		return _get_gpio_datain(bank, gpio);
+		return _get_gpio_datain(bank, offset);
 	else
-		return _get_gpio_dataout(bank, gpio);
+		return _get_gpio_dataout(bank, offset);
 }
 
 static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
@@ -982,7 +926,7 @@
 	struct gpio_bank *bank;
 
 	bank = container_of(chip, struct gpio_bank, chip);
-	return bank->virtual_irq_start + offset;
+	return bank->irq_base + offset;
 }
 
 /*---------------------------------------------------------------------*/
@@ -1007,81 +951,35 @@
  */
 static struct lock_class_key gpio_lock_class;
 
-static inline int init_gpio_info(struct platform_device *pdev)
+static void omap_gpio_mod_init(struct gpio_bank *bank)
 {
-	/* TODO: Analyze removing gpio_bank_count usage from driver code */
-	gpio_bank = kzalloc(gpio_bank_count * sizeof(struct gpio_bank),
-				GFP_KERNEL);
-	if (!gpio_bank) {
-		dev_err(&pdev->dev, "Memory alloc failed for gpio_bank\n");
-		return -ENOMEM;
+	void __iomem *base = bank->base;
+	u32 l = 0xffffffff;
+
+	if (bank->width == 16)
+		l = 0xffff;
+
+	if (bank->is_mpuio) {
+		__raw_writel(l, bank->base + bank->regs->irqenable);
+		return;
 	}
-	return 0;
+
+	_gpio_rmw(base, bank->regs->irqenable, l, bank->regs->irqenable_inv);
+	_gpio_rmw(base, bank->regs->irqstatus, l,
+					bank->regs->irqenable_inv == false);
+	_gpio_rmw(base, bank->regs->irqenable, l, bank->regs->debounce_en != 0);
+	_gpio_rmw(base, bank->regs->irqenable, l, bank->regs->ctrl != 0);
+	if (bank->regs->debounce_en)
+		_gpio_rmw(base, bank->regs->debounce_en, 0, 1);
+
+	/* Save OE default value (0xffffffff) in the context */
+	bank->context.oe = __raw_readl(bank->base + bank->regs->direction);
+	 /* Initialize interface clk ungated, module enabled */
+	if (bank->regs->ctrl)
+		_gpio_rmw(base, bank->regs->ctrl, 0, 1);
 }
 
-/* TODO: Cleanup cpu_is_* checks */
-static void omap_gpio_mod_init(struct gpio_bank *bank, int id)
-{
-	if (cpu_class_is_omap2()) {
-		if (cpu_is_omap44xx()) {
-			__raw_writel(0xffffffff, bank->base +
-					OMAP4_GPIO_IRQSTATUSCLR0);
-			__raw_writel(0x00000000, bank->base +
-					 OMAP4_GPIO_DEBOUNCENABLE);
-			/* Initialize interface clk ungated, module enabled */
-			__raw_writel(0, bank->base + OMAP4_GPIO_CTRL);
-		} else if (cpu_is_omap34xx()) {
-			__raw_writel(0x00000000, bank->base +
-					OMAP24XX_GPIO_IRQENABLE1);
-			__raw_writel(0xffffffff, bank->base +
-					OMAP24XX_GPIO_IRQSTATUS1);
-			__raw_writel(0x00000000, bank->base +
-					OMAP24XX_GPIO_DEBOUNCE_EN);
-
-			/* Initialize interface clk ungated, module enabled */
-			__raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL);
-		} else if (cpu_is_omap24xx()) {
-			static const u32 non_wakeup_gpios[] = {
-				0xe203ffc0, 0x08700040
-			};
-			if (id < ARRAY_SIZE(non_wakeup_gpios))
-				bank->non_wakeup_gpios = non_wakeup_gpios[id];
-		}
-	} else if (cpu_class_is_omap1()) {
-		if (bank_is_mpuio(bank))
-			__raw_writew(0xffff, bank->base +
-				OMAP_MPUIO_GPIO_MASKIT / bank->stride);
-		if (cpu_is_omap15xx() && bank->method == METHOD_GPIO_1510) {
-			__raw_writew(0xffff, bank->base
-						+ OMAP1510_GPIO_INT_MASK);
-			__raw_writew(0x0000, bank->base
-						+ OMAP1510_GPIO_INT_STATUS);
-		}
-		if (cpu_is_omap16xx() && bank->method == METHOD_GPIO_1610) {
-			__raw_writew(0x0000, bank->base
-						+ OMAP1610_GPIO_IRQENABLE1);
-			__raw_writew(0xffff, bank->base
-						+ OMAP1610_GPIO_IRQSTATUS1);
-			__raw_writew(0x0014, bank->base
-						+ OMAP1610_GPIO_SYSCONFIG);
-
-			/*
-			 * Enable system clock for GPIO module.
-			 * The CAM_CLK_CTRL *is* really the right place.
-			 */
-			omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04,
-						ULPD_CAM_CLK_CTRL);
-		}
-		if (cpu_is_omap7xx() && bank->method == METHOD_GPIO_7XX) {
-			__raw_writel(0xffffffff, bank->base
-						+ OMAP7XX_GPIO_INT_MASK);
-			__raw_writel(0x00000000, bank->base
-						+ OMAP7XX_GPIO_INT_STATUS);
-		}
-	}
-}
-
-static __init void
+static __devinit void
 omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
 		    unsigned int num)
 {
@@ -1101,8 +999,8 @@
 	ct->chip.irq_mask = irq_gc_mask_set_bit;
 	ct->chip.irq_unmask = irq_gc_mask_clr_bit;
 	ct->chip.irq_set_type = gpio_irq_type;
-	/* REVISIT: assuming only 16xx supports MPUIO wake events */
-	if (cpu_is_omap16xx())
+
+	if (bank->regs->wkup_en)
 		ct->chip.irq_set_wake = gpio_wake_enable,
 
 	ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride;
@@ -1115,7 +1013,6 @@
 	int j;
 	static int gpio;
 
-	bank->mod_usage = 0;
 	/*
 	 * REVISIT eventually switch from OMAP-specific gpio structs
 	 * over to the generic ones
@@ -1128,11 +1025,10 @@
 	bank->chip.set_debounce = gpio_debounce;
 	bank->chip.set = gpio_set;
 	bank->chip.to_irq = gpio_2irq;
-	if (bank_is_mpuio(bank)) {
+	if (bank->is_mpuio) {
 		bank->chip.label = "mpuio";
-#ifdef CONFIG_ARCH_OMAP16XX
-		bank->chip.dev = &omap_mpuio_device.dev;
-#endif
+		if (bank->regs->wkup_en)
+			bank->chip.dev = &omap_mpuio_device.dev;
 		bank->chip.base = OMAP_MPUIO(0);
 	} else {
 		bank->chip.label = "gpio";
@@ -1143,11 +1039,10 @@
 
 	gpiochip_add(&bank->chip);
 
-	for (j = bank->virtual_irq_start;
-		     j < bank->virtual_irq_start + bank->width; j++) {
+	for (j = bank->irq_base; j < bank->irq_base + bank->width; j++) {
 		irq_set_lockdep_class(j, &gpio_lock_class);
 		irq_set_chip_data(j, bank);
-		if (bank_is_mpuio(bank)) {
+		if (bank->is_mpuio) {
 			omap_mpuio_alloc_gc(bank, j, bank->width);
 		} else {
 			irq_set_chip(j, &gpio_irq_chip);
@@ -1159,45 +1054,58 @@
 	irq_set_handler_data(bank->irq, bank);
 }
 
+static const struct of_device_id omap_gpio_match[];
+
 static int __devinit omap_gpio_probe(struct platform_device *pdev)
 {
-	static int gpio_init_done;
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	const struct of_device_id *match;
 	struct omap_gpio_platform_data *pdata;
 	struct resource *res;
-	int id;
 	struct gpio_bank *bank;
+	int ret = 0;
 
-	if (!pdev->dev.platform_data)
+	match = of_match_device(of_match_ptr(omap_gpio_match), dev);
+
+	pdata = match ? match->data : dev->platform_data;
+	if (!pdata)
 		return -EINVAL;
 
-	pdata = pdev->dev.platform_data;
-
-	if (!gpio_init_done) {
-		int ret;
-
-		ret = init_gpio_info(pdev);
-		if (ret)
-			return ret;
+	bank = devm_kzalloc(&pdev->dev, sizeof(struct gpio_bank), GFP_KERNEL);
+	if (!bank) {
+		dev_err(dev, "Memory alloc failed\n");
+		return -ENOMEM;
 	}
 
-	id = pdev->id;
-	bank = &gpio_bank[id];
-
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (unlikely(!res)) {
-		dev_err(&pdev->dev, "GPIO Bank %i Invalid IRQ resource\n", id);
+		dev_err(dev, "Invalid IRQ resource\n");
 		return -ENODEV;
 	}
 
 	bank->irq = res->start;
-	bank->virtual_irq_start = pdata->virtual_irq_start;
-	bank->method = pdata->bank_type;
-	bank->dev = &pdev->dev;
+	bank->dev = dev;
 	bank->dbck_flag = pdata->dbck_flag;
 	bank->stride = pdata->bank_stride;
 	bank->width = pdata->bank_width;
-
+	bank->is_mpuio = pdata->is_mpuio;
+	bank->non_wakeup_gpios = pdata->non_wakeup_gpios;
+	bank->loses_context = pdata->loses_context;
+	bank->get_context_loss_count = pdata->get_context_loss_count;
 	bank->regs = pdata->regs;
+#ifdef CONFIG_OF_GPIO
+	bank->chip.of_node = of_node_get(node);
+#endif
+
+	bank->irq_base = irq_alloc_descs(-1, 0, bank->width, 0);
+	if (bank->irq_base < 0) {
+		dev_err(dev, "Couldn't allocate IRQ numbers\n");
+		return -ENODEV;
+	}
+
+	bank->domain = irq_domain_add_legacy(node, bank->width, bank->irq_base,
+					     0, &irq_domain_simple_ops, NULL);
 
 	if (bank->regs->set_dataout && bank->regs->clr_dataout)
 		bank->set_dataout = _set_gpio_dataout_reg;
@@ -1209,369 +1117,422 @@
 	/* Static mapping, never released */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (unlikely(!res)) {
-		dev_err(&pdev->dev, "GPIO Bank %i Invalid mem resource\n", id);
+		dev_err(dev, "Invalid mem resource\n");
 		return -ENODEV;
 	}
 
-	bank->base = ioremap(res->start, resource_size(res));
+	if (!devm_request_mem_region(dev, res->start, resource_size(res),
+				     pdev->name)) {
+		dev_err(dev, "Region already claimed\n");
+		return -EBUSY;
+	}
+
+	bank->base = devm_ioremap(dev, res->start, resource_size(res));
 	if (!bank->base) {
-		dev_err(&pdev->dev, "Could not ioremap gpio bank%i\n", id);
+		dev_err(dev, "Could not ioremap\n");
 		return -ENOMEM;
 	}
 
+	platform_set_drvdata(pdev, bank);
+
 	pm_runtime_enable(bank->dev);
+	pm_runtime_irq_safe(bank->dev);
 	pm_runtime_get_sync(bank->dev);
 
-	omap_gpio_mod_init(bank, id);
+	if (bank->is_mpuio)
+		mpuio_init(bank);
+
+	omap_gpio_mod_init(bank);
 	omap_gpio_chip_init(bank);
 	omap_gpio_show_rev(bank);
 
-	if (!gpio_init_done)
-		gpio_init_done = 1;
+	pm_runtime_put(bank->dev);
 
-	return 0;
+	list_add_tail(&bank->node, &omap_gpio_list);
+
+	return ret;
 }
 
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
-static int omap_gpio_suspend(void)
-{
-	int i;
-
-	if (!cpu_class_is_omap2() && !cpu_is_omap16xx())
-		return 0;
-
-	for (i = 0; i < gpio_bank_count; i++) {
-		struct gpio_bank *bank = &gpio_bank[i];
-		void __iomem *wake_status;
-		void __iomem *wake_clear;
-		void __iomem *wake_set;
-		unsigned long flags;
-
-		switch (bank->method) {
-#ifdef CONFIG_ARCH_OMAP16XX
-		case METHOD_GPIO_1610:
-			wake_status = bank->base + OMAP1610_GPIO_WAKEUPENABLE;
-			wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
-			wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
-			break;
-#endif
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-		case METHOD_GPIO_24XX:
-			wake_status = bank->base + OMAP24XX_GPIO_WAKE_EN;
-			wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
-			wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
-			break;
-#endif
-#ifdef CONFIG_ARCH_OMAP4
-		case METHOD_GPIO_44XX:
-			wake_status = bank->base + OMAP4_GPIO_IRQWAKEN0;
-			wake_clear = bank->base + OMAP4_GPIO_IRQWAKEN0;
-			wake_set = bank->base + OMAP4_GPIO_IRQWAKEN0;
-			break;
-#endif
-		default:
-			continue;
-		}
-
-		spin_lock_irqsave(&bank->lock, flags);
-		bank->saved_wakeup = __raw_readl(wake_status);
-		__raw_writel(0xffffffff, wake_clear);
-		__raw_writel(bank->suspend_wakeup, wake_set);
-		spin_unlock_irqrestore(&bank->lock, flags);
-	}
-
-	return 0;
-}
-
-static void omap_gpio_resume(void)
-{
-	int i;
-
-	if (!cpu_class_is_omap2() && !cpu_is_omap16xx())
-		return;
-
-	for (i = 0; i < gpio_bank_count; i++) {
-		struct gpio_bank *bank = &gpio_bank[i];
-		void __iomem *wake_clear;
-		void __iomem *wake_set;
-		unsigned long flags;
-
-		switch (bank->method) {
-#ifdef CONFIG_ARCH_OMAP16XX
-		case METHOD_GPIO_1610:
-			wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
-			wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
-			break;
-#endif
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-		case METHOD_GPIO_24XX:
-			wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
-			wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
-			break;
-#endif
-#ifdef CONFIG_ARCH_OMAP4
-		case METHOD_GPIO_44XX:
-			wake_clear = bank->base + OMAP4_GPIO_IRQWAKEN0;
-			wake_set = bank->base + OMAP4_GPIO_IRQWAKEN0;
-			break;
-#endif
-		default:
-			continue;
-		}
-
-		spin_lock_irqsave(&bank->lock, flags);
-		__raw_writel(0xffffffff, wake_clear);
-		__raw_writel(bank->saved_wakeup, wake_set);
-		spin_unlock_irqrestore(&bank->lock, flags);
-	}
-}
-
-static struct syscore_ops omap_gpio_syscore_ops = {
-	.suspend	= omap_gpio_suspend,
-	.resume		= omap_gpio_resume,
-};
-
-#endif
-
 #ifdef CONFIG_ARCH_OMAP2PLUS
 
-static int workaround_enabled;
-
-void omap2_gpio_prepare_for_idle(int off_mode)
+#if defined(CONFIG_PM_SLEEP)
+static int omap_gpio_suspend(struct device *dev)
 {
-	int i, c = 0;
-	int min = 0;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct gpio_bank *bank = platform_get_drvdata(pdev);
+	void __iomem *base = bank->base;
+	void __iomem *wakeup_enable;
+	unsigned long flags;
 
-	if (cpu_is_omap34xx())
-		min = 1;
+	if (!bank->mod_usage || !bank->loses_context)
+		return 0;
 
-	for (i = min; i < gpio_bank_count; i++) {
-		struct gpio_bank *bank = &gpio_bank[i];
-		u32 l1 = 0, l2 = 0;
-		int j;
+	if (!bank->regs->wkup_en || !bank->suspend_wakeup)
+		return 0;
 
-		for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
-			clk_disable(bank->dbck);
+	wakeup_enable = bank->base + bank->regs->wkup_en;
 
-		if (!off_mode)
-			continue;
+	spin_lock_irqsave(&bank->lock, flags);
+	bank->saved_wakeup = __raw_readl(wakeup_enable);
+	_gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0);
+	_gpio_rmw(base, bank->regs->wkup_en, bank->suspend_wakeup, 1);
+	spin_unlock_irqrestore(&bank->lock, flags);
 
-		/* If going to OFF, remove triggering for all
-		 * non-wakeup GPIOs.  Otherwise spurious IRQs will be
-		 * generated.  See OMAP2420 Errata item 1.101. */
-		if (!(bank->enabled_non_wakeup_gpios))
-			continue;
+	return 0;
+}
+
+static int omap_gpio_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct gpio_bank *bank = platform_get_drvdata(pdev);
+	void __iomem *base = bank->base;
+	unsigned long flags;
+
+	if (!bank->mod_usage || !bank->loses_context)
+		return 0;
+
+	if (!bank->regs->wkup_en || !bank->saved_wakeup)
+		return 0;
+
+	spin_lock_irqsave(&bank->lock, flags);
+	_gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0);
+	_gpio_rmw(base, bank->regs->wkup_en, bank->saved_wakeup, 1);
+	spin_unlock_irqrestore(&bank->lock, flags);
+
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#if defined(CONFIG_PM_RUNTIME)
+static void omap_gpio_restore_context(struct gpio_bank *bank);
+
+static int omap_gpio_runtime_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct gpio_bank *bank = platform_get_drvdata(pdev);
+	u32 l1 = 0, l2 = 0;
+	unsigned long flags;
+	u32 wake_low, wake_hi;
+
+	spin_lock_irqsave(&bank->lock, flags);
+
+	/*
+	 * Only edges can generate a wakeup event to the PRCM.
+	 *
+	 * Therefore, ensure any wake-up capable GPIOs have
+	 * edge-detection enabled before going idle to ensure a wakeup
+	 * to the PRCM is generated on a GPIO transition. (c.f. 34xx
+	 * NDA TRM 25.5.3.1)
+	 *
+	 * The normal values will be restored upon ->runtime_resume()
+	 * by writing back the values saved in bank->context.
+	 */
+	wake_low = bank->context.leveldetect0 & bank->context.wake_en;
+	if (wake_low)
+		__raw_writel(wake_low | bank->context.fallingdetect,
+			     bank->base + bank->regs->fallingdetect);
+	wake_hi = bank->context.leveldetect1 & bank->context.wake_en;
+	if (wake_hi)
+		__raw_writel(wake_hi | bank->context.risingdetect,
+			     bank->base + bank->regs->risingdetect);
+
+	if (bank->power_mode != OFF_MODE) {
+		bank->power_mode = 0;
+		goto update_gpio_context_count;
+	}
+	/*
+	 * If going to OFF, remove triggering for all
+	 * non-wakeup GPIOs.  Otherwise spurious IRQs will be
+	 * generated.  See OMAP2420 Errata item 1.101.
+	 */
+	bank->saved_datain = __raw_readl(bank->base +
+						bank->regs->datain);
+	l1 = __raw_readl(bank->base + bank->regs->fallingdetect);
+	l2 = __raw_readl(bank->base + bank->regs->risingdetect);
+
+	bank->saved_fallingdetect = l1;
+	bank->saved_risingdetect = l2;
+	l1 &= ~bank->enabled_non_wakeup_gpios;
+	l2 &= ~bank->enabled_non_wakeup_gpios;
+
+	__raw_writel(l1, bank->base + bank->regs->fallingdetect);
+	__raw_writel(l2, bank->base + bank->regs->risingdetect);
+
+	bank->workaround_enabled = true;
+
+update_gpio_context_count:
+	if (bank->get_context_loss_count)
+		bank->context_loss_count =
+				bank->get_context_loss_count(bank->dev);
+
+	_gpio_dbck_disable(bank);
+	spin_unlock_irqrestore(&bank->lock, flags);
+
+	return 0;
+}
+
+static int omap_gpio_runtime_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct gpio_bank *bank = platform_get_drvdata(pdev);
+	int context_lost_cnt_after;
+	u32 l = 0, gen, gen0, gen1;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bank->lock, flags);
+	_gpio_dbck_enable(bank);
+
+	/*
+	 * In ->runtime_suspend(), level-triggered, wakeup-enabled
+	 * GPIOs were set to edge trigger also in order to be able to
+	 * generate a PRCM wakeup.  Here we restore the
+	 * pre-runtime_suspend() values for edge triggering.
+	 */
+	__raw_writel(bank->context.fallingdetect,
+		     bank->base + bank->regs->fallingdetect);
+	__raw_writel(bank->context.risingdetect,
+		     bank->base + bank->regs->risingdetect);
+
+	if (!bank->workaround_enabled) {
+		spin_unlock_irqrestore(&bank->lock, flags);
+		return 0;
+	}
+
+	if (bank->get_context_loss_count) {
+		context_lost_cnt_after =
+			bank->get_context_loss_count(bank->dev);
+		if (context_lost_cnt_after != bank->context_loss_count ||
+						!context_lost_cnt_after) {
+			omap_gpio_restore_context(bank);
+		} else {
+			spin_unlock_irqrestore(&bank->lock, flags);
+			return 0;
+		}
+	}
+
+	__raw_writel(bank->saved_fallingdetect,
+			bank->base + bank->regs->fallingdetect);
+	__raw_writel(bank->saved_risingdetect,
+			bank->base + bank->regs->risingdetect);
+	l = __raw_readl(bank->base + bank->regs->datain);
+
+	/*
+	 * Check if any of the non-wakeup interrupt GPIOs have changed
+	 * state.  If so, generate an IRQ by software.  This is
+	 * horribly racy, but it's the best we can do to work around
+	 * this silicon bug.
+	 */
+	l ^= bank->saved_datain;
+	l &= bank->enabled_non_wakeup_gpios;
+
+	/*
+	 * No need to generate IRQs for the rising edge for gpio IRQs
+	 * configured with falling edge only; and vice versa.
+	 */
+	gen0 = l & bank->saved_fallingdetect;
+	gen0 &= bank->saved_datain;
+
+	gen1 = l & bank->saved_risingdetect;
+	gen1 &= ~(bank->saved_datain);
+
+	/* FIXME: Consider GPIO IRQs with level detections properly! */
+	gen = l & (~(bank->saved_fallingdetect) & ~(bank->saved_risingdetect));
+	/* Consider all GPIO IRQs needed to be updated */
+	gen |= gen0 | gen1;
+
+	if (gen) {
+		u32 old0, old1;
+
+		old0 = __raw_readl(bank->base + bank->regs->leveldetect0);
+		old1 = __raw_readl(bank->base + bank->regs->leveldetect1);
 
 		if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-			bank->saved_datain = __raw_readl(bank->base +
-					OMAP24XX_GPIO_DATAIN);
-			l1 = __raw_readl(bank->base +
-					OMAP24XX_GPIO_FALLINGDETECT);
-			l2 = __raw_readl(bank->base +
-					OMAP24XX_GPIO_RISINGDETECT);
+			__raw_writel(old0 | gen, bank->base +
+						bank->regs->leveldetect0);
+			__raw_writel(old1 | gen, bank->base +
+						bank->regs->leveldetect1);
 		}
 
 		if (cpu_is_omap44xx()) {
-			bank->saved_datain = __raw_readl(bank->base +
-						OMAP4_GPIO_DATAIN);
-			l1 = __raw_readl(bank->base +
-						OMAP4_GPIO_FALLINGDETECT);
-			l2 = __raw_readl(bank->base +
-						OMAP4_GPIO_RISINGDETECT);
+			__raw_writel(old0 | l, bank->base +
+						bank->regs->leveldetect0);
+			__raw_writel(old1 | l, bank->base +
+						bank->regs->leveldetect1);
 		}
-
-		bank->saved_fallingdetect = l1;
-		bank->saved_risingdetect = l2;
-		l1 &= ~bank->enabled_non_wakeup_gpios;
-		l2 &= ~bank->enabled_non_wakeup_gpios;
-
-		if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-			__raw_writel(l1, bank->base +
-					OMAP24XX_GPIO_FALLINGDETECT);
-			__raw_writel(l2, bank->base +
-					OMAP24XX_GPIO_RISINGDETECT);
-		}
-
-		if (cpu_is_omap44xx()) {
-			__raw_writel(l1, bank->base + OMAP4_GPIO_FALLINGDETECT);
-			__raw_writel(l2, bank->base + OMAP4_GPIO_RISINGDETECT);
-		}
-
-		c++;
+		__raw_writel(old0, bank->base + bank->regs->leveldetect0);
+		__raw_writel(old1, bank->base + bank->regs->leveldetect1);
 	}
-	if (!c) {
-		workaround_enabled = 0;
-		return;
+
+	bank->workaround_enabled = false;
+	spin_unlock_irqrestore(&bank->lock, flags);
+
+	return 0;
+}
+#endif /* CONFIG_PM_RUNTIME */
+
+void omap2_gpio_prepare_for_idle(int pwr_mode)
+{
+	struct gpio_bank *bank;
+
+	list_for_each_entry(bank, &omap_gpio_list, node) {
+		if (!bank->mod_usage || !bank->loses_context)
+			continue;
+
+		bank->power_mode = pwr_mode;
+
+		pm_runtime_put_sync_suspend(bank->dev);
 	}
-	workaround_enabled = 1;
 }
 
 void omap2_gpio_resume_after_idle(void)
 {
-	int i;
-	int min = 0;
+	struct gpio_bank *bank;
 
-	if (cpu_is_omap34xx())
-		min = 1;
-	for (i = min; i < gpio_bank_count; i++) {
-		struct gpio_bank *bank = &gpio_bank[i];
-		u32 l = 0, gen, gen0, gen1;
-		int j;
-
-		for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
-			clk_enable(bank->dbck);
-
-		if (!workaround_enabled)
+	list_for_each_entry(bank, &omap_gpio_list, node) {
+		if (!bank->mod_usage || !bank->loses_context)
 			continue;
 
-		if (!(bank->enabled_non_wakeup_gpios))
-			continue;
-
-		if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-			__raw_writel(bank->saved_fallingdetect,
-				 bank->base + OMAP24XX_GPIO_FALLINGDETECT);
-			__raw_writel(bank->saved_risingdetect,
-				 bank->base + OMAP24XX_GPIO_RISINGDETECT);
-			l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
-		}
-
-		if (cpu_is_omap44xx()) {
-			__raw_writel(bank->saved_fallingdetect,
-				 bank->base + OMAP4_GPIO_FALLINGDETECT);
-			__raw_writel(bank->saved_risingdetect,
-				 bank->base + OMAP4_GPIO_RISINGDETECT);
-			l = __raw_readl(bank->base + OMAP4_GPIO_DATAIN);
-		}
-
-		/* Check if any of the non-wakeup interrupt GPIOs have changed
-		 * state.  If so, generate an IRQ by software.  This is
-		 * horribly racy, but it's the best we can do to work around
-		 * this silicon bug. */
-		l ^= bank->saved_datain;
-		l &= bank->enabled_non_wakeup_gpios;
-
-		/*
-		 * No need to generate IRQs for the rising edge for gpio IRQs
-		 * configured with falling edge only; and vice versa.
-		 */
-		gen0 = l & bank->saved_fallingdetect;
-		gen0 &= bank->saved_datain;
-
-		gen1 = l & bank->saved_risingdetect;
-		gen1 &= ~(bank->saved_datain);
-
-		/* FIXME: Consider GPIO IRQs with level detections properly! */
-		gen = l & (~(bank->saved_fallingdetect) &
-				~(bank->saved_risingdetect));
-		/* Consider all GPIO IRQs needed to be updated */
-		gen |= gen0 | gen1;
-
-		if (gen) {
-			u32 old0, old1;
-
-			if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-				old0 = __raw_readl(bank->base +
-					OMAP24XX_GPIO_LEVELDETECT0);
-				old1 = __raw_readl(bank->base +
-					OMAP24XX_GPIO_LEVELDETECT1);
-				__raw_writel(old0 | gen, bank->base +
-					OMAP24XX_GPIO_LEVELDETECT0);
-				__raw_writel(old1 | gen, bank->base +
-					OMAP24XX_GPIO_LEVELDETECT1);
-				__raw_writel(old0, bank->base +
-					OMAP24XX_GPIO_LEVELDETECT0);
-				__raw_writel(old1, bank->base +
-					OMAP24XX_GPIO_LEVELDETECT1);
-			}
-
-			if (cpu_is_omap44xx()) {
-				old0 = __raw_readl(bank->base +
-						OMAP4_GPIO_LEVELDETECT0);
-				old1 = __raw_readl(bank->base +
-						OMAP4_GPIO_LEVELDETECT1);
-				__raw_writel(old0 | l, bank->base +
-						OMAP4_GPIO_LEVELDETECT0);
-				__raw_writel(old1 | l, bank->base +
-						OMAP4_GPIO_LEVELDETECT1);
-				__raw_writel(old0, bank->base +
-						OMAP4_GPIO_LEVELDETECT0);
-				__raw_writel(old1, bank->base +
-						OMAP4_GPIO_LEVELDETECT1);
-			}
-		}
+		pm_runtime_get_sync(bank->dev);
 	}
-
 }
 
+#if defined(CONFIG_PM_RUNTIME)
+static void omap_gpio_restore_context(struct gpio_bank *bank)
+{
+	__raw_writel(bank->context.wake_en,
+				bank->base + bank->regs->wkup_en);
+	__raw_writel(bank->context.ctrl, bank->base + bank->regs->ctrl);
+	__raw_writel(bank->context.leveldetect0,
+				bank->base + bank->regs->leveldetect0);
+	__raw_writel(bank->context.leveldetect1,
+				bank->base + bank->regs->leveldetect1);
+	__raw_writel(bank->context.risingdetect,
+				bank->base + bank->regs->risingdetect);
+	__raw_writel(bank->context.fallingdetect,
+				bank->base + bank->regs->fallingdetect);
+	if (bank->regs->set_dataout && bank->regs->clr_dataout)
+		__raw_writel(bank->context.dataout,
+				bank->base + bank->regs->set_dataout);
+	else
+		__raw_writel(bank->context.dataout,
+				bank->base + bank->regs->dataout);
+	__raw_writel(bank->context.oe, bank->base + bank->regs->direction);
+
+	if (bank->dbck_enable_mask) {
+		__raw_writel(bank->context.debounce, bank->base +
+					bank->regs->debounce);
+		__raw_writel(bank->context.debounce_en,
+					bank->base + bank->regs->debounce_en);
+	}
+
+	__raw_writel(bank->context.irqenable1,
+				bank->base + bank->regs->irqenable);
+	__raw_writel(bank->context.irqenable2,
+				bank->base + bank->regs->irqenable2);
+}
+#endif /* CONFIG_PM_RUNTIME */
+#else
+#define omap_gpio_suspend NULL
+#define omap_gpio_resume NULL
+#define omap_gpio_runtime_suspend NULL
+#define omap_gpio_runtime_resume NULL
 #endif
 
-#ifdef CONFIG_ARCH_OMAP3
-/* save the registers of bank 2-6 */
-void omap_gpio_save_context(void)
-{
-	int i;
+static const struct dev_pm_ops gpio_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume)
+	SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
+									NULL)
+};
 
-	/* saving banks from 2-6 only since GPIO1 is in WKUP */
-	for (i = 1; i < gpio_bank_count; i++) {
-		struct gpio_bank *bank = &gpio_bank[i];
-		gpio_context[i].irqenable1 =
-			__raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE1);
-		gpio_context[i].irqenable2 =
-			__raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE2);
-		gpio_context[i].wake_en =
-			__raw_readl(bank->base + OMAP24XX_GPIO_WAKE_EN);
-		gpio_context[i].ctrl =
-			__raw_readl(bank->base + OMAP24XX_GPIO_CTRL);
-		gpio_context[i].oe =
-			__raw_readl(bank->base + OMAP24XX_GPIO_OE);
-		gpio_context[i].leveldetect0 =
-			__raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0);
-		gpio_context[i].leveldetect1 =
-			__raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
-		gpio_context[i].risingdetect =
-			__raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT);
-		gpio_context[i].fallingdetect =
-			__raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT);
-		gpio_context[i].dataout =
-			__raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT);
-	}
-}
+#if defined(CONFIG_OF)
+static struct omap_gpio_reg_offs omap2_gpio_regs = {
+	.revision =		OMAP24XX_GPIO_REVISION,
+	.direction =		OMAP24XX_GPIO_OE,
+	.datain =		OMAP24XX_GPIO_DATAIN,
+	.dataout =		OMAP24XX_GPIO_DATAOUT,
+	.set_dataout =		OMAP24XX_GPIO_SETDATAOUT,
+	.clr_dataout =		OMAP24XX_GPIO_CLEARDATAOUT,
+	.irqstatus =		OMAP24XX_GPIO_IRQSTATUS1,
+	.irqstatus2 =		OMAP24XX_GPIO_IRQSTATUS2,
+	.irqenable =		OMAP24XX_GPIO_IRQENABLE1,
+	.irqenable2 =		OMAP24XX_GPIO_IRQENABLE2,
+	.set_irqenable =	OMAP24XX_GPIO_SETIRQENABLE1,
+	.clr_irqenable =	OMAP24XX_GPIO_CLEARIRQENABLE1,
+	.debounce =		OMAP24XX_GPIO_DEBOUNCE_VAL,
+	.debounce_en =		OMAP24XX_GPIO_DEBOUNCE_EN,
+	.ctrl =			OMAP24XX_GPIO_CTRL,
+	.wkup_en =		OMAP24XX_GPIO_WAKE_EN,
+	.leveldetect0 =		OMAP24XX_GPIO_LEVELDETECT0,
+	.leveldetect1 =		OMAP24XX_GPIO_LEVELDETECT1,
+	.risingdetect =		OMAP24XX_GPIO_RISINGDETECT,
+	.fallingdetect =	OMAP24XX_GPIO_FALLINGDETECT,
+};
 
-/* restore the required registers of bank 2-6 */
-void omap_gpio_restore_context(void)
-{
-	int i;
+static struct omap_gpio_reg_offs omap4_gpio_regs = {
+	.revision =		OMAP4_GPIO_REVISION,
+	.direction =		OMAP4_GPIO_OE,
+	.datain =		OMAP4_GPIO_DATAIN,
+	.dataout =		OMAP4_GPIO_DATAOUT,
+	.set_dataout =		OMAP4_GPIO_SETDATAOUT,
+	.clr_dataout =		OMAP4_GPIO_CLEARDATAOUT,
+	.irqstatus =		OMAP4_GPIO_IRQSTATUS0,
+	.irqstatus2 =		OMAP4_GPIO_IRQSTATUS1,
+	.irqenable =		OMAP4_GPIO_IRQSTATUSSET0,
+	.irqenable2 =		OMAP4_GPIO_IRQSTATUSSET1,
+	.set_irqenable =	OMAP4_GPIO_IRQSTATUSSET0,
+	.clr_irqenable =	OMAP4_GPIO_IRQSTATUSCLR0,
+	.debounce =		OMAP4_GPIO_DEBOUNCINGTIME,
+	.debounce_en =		OMAP4_GPIO_DEBOUNCENABLE,
+	.ctrl =			OMAP4_GPIO_CTRL,
+	.wkup_en =		OMAP4_GPIO_IRQWAKEN0,
+	.leveldetect0 =		OMAP4_GPIO_LEVELDETECT0,
+	.leveldetect1 =		OMAP4_GPIO_LEVELDETECT1,
+	.risingdetect =		OMAP4_GPIO_RISINGDETECT,
+	.fallingdetect =	OMAP4_GPIO_FALLINGDETECT,
+};
 
-	for (i = 1; i < gpio_bank_count; i++) {
-		struct gpio_bank *bank = &gpio_bank[i];
-		__raw_writel(gpio_context[i].irqenable1,
-				bank->base + OMAP24XX_GPIO_IRQENABLE1);
-		__raw_writel(gpio_context[i].irqenable2,
-				bank->base + OMAP24XX_GPIO_IRQENABLE2);
-		__raw_writel(gpio_context[i].wake_en,
-				bank->base + OMAP24XX_GPIO_WAKE_EN);
-		__raw_writel(gpio_context[i].ctrl,
-				bank->base + OMAP24XX_GPIO_CTRL);
-		__raw_writel(gpio_context[i].oe,
-				bank->base + OMAP24XX_GPIO_OE);
-		__raw_writel(gpio_context[i].leveldetect0,
-				bank->base + OMAP24XX_GPIO_LEVELDETECT0);
-		__raw_writel(gpio_context[i].leveldetect1,
-				bank->base + OMAP24XX_GPIO_LEVELDETECT1);
-		__raw_writel(gpio_context[i].risingdetect,
-				bank->base + OMAP24XX_GPIO_RISINGDETECT);
-		__raw_writel(gpio_context[i].fallingdetect,
-				bank->base + OMAP24XX_GPIO_FALLINGDETECT);
-		__raw_writel(gpio_context[i].dataout,
-				bank->base + OMAP24XX_GPIO_DATAOUT);
-	}
-}
+static struct omap_gpio_platform_data omap2_pdata = {
+	.regs = &omap2_gpio_regs,
+	.bank_width = 32,
+	.dbck_flag = false,
+};
+
+static struct omap_gpio_platform_data omap3_pdata = {
+	.regs = &omap2_gpio_regs,
+	.bank_width = 32,
+	.dbck_flag = true,
+};
+
+static struct omap_gpio_platform_data omap4_pdata = {
+	.regs = &omap4_gpio_regs,
+	.bank_width = 32,
+	.dbck_flag = true,
+};
+
+static const struct of_device_id omap_gpio_match[] = {
+	{
+		.compatible = "ti,omap4-gpio",
+		.data = &omap4_pdata,
+	},
+	{
+		.compatible = "ti,omap3-gpio",
+		.data = &omap3_pdata,
+	},
+	{
+		.compatible = "ti,omap2-gpio",
+		.data = &omap2_pdata,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, omap_gpio_match);
 #endif
 
 static struct platform_driver omap_gpio_driver = {
 	.probe		= omap_gpio_probe,
 	.driver		= {
 		.name	= "omap_gpio",
+		.pm	= &gpio_pm_ops,
+		.of_match_table = of_match_ptr(omap_gpio_match),
 	},
 };
 
@@ -1585,17 +1546,3 @@
 	return platform_driver_register(&omap_gpio_driver);
 }
 postcore_initcall(omap_gpio_drv_reg);
-
-static int __init omap_gpio_sysinit(void)
-{
-	mpuio_init();
-
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
-	if (cpu_is_omap16xx() || cpu_class_is_omap2())
-		register_syscore_ops(&omap_gpio_syscore_ops);
-#endif
-
-	return 0;
-}
-
-arch_initcall(omap_gpio_sysinit);
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 77c9cc7..b4b5da4 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -352,7 +352,12 @@
 	return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_resume);
+static const struct dev_pm_ops pl061_dev_pm_ops = {
+	.suspend = pl061_suspend,
+	.resume = pl061_resume,
+	.freeze = pl061_suspend,
+	.restore = pl061_resume,
+};
 #endif
 
 static struct amba_id pl061_ids[] = {
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index b2d3ee1..5689ce6 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -22,6 +22,8 @@
 #include <linux/syscore_ops.h>
 #include <linux/slab.h>
 
+#include <mach/irqs.h>
+
 /*
  * We handle the GPIOs by banks, each bank covers up to 32 GPIOs with
  * one set of registers. The register offsets are organized below:
diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c
index 7eecf69..8ea3b33 100644
--- a/drivers/gpio/gpio-sa1100.c
+++ b/drivers/gpio/gpio-sa1100.c
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 
 static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c
index 0a79a11..4627787 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -169,7 +169,7 @@
 	return s3c24xx_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN);
 }
 
-static int exynos4_gpio_setpull(struct samsung_gpio_chip *chip,
+static int exynos_gpio_setpull(struct samsung_gpio_chip *chip,
 				unsigned int off, samsung_gpio_pull_t pull)
 {
 	if (pull == S3C_GPIO_PULL_UP)
@@ -178,7 +178,7 @@
 	return samsung_gpio_setpull_updown(chip, off, pull);
 }
 
-static samsung_gpio_pull_t exynos4_gpio_getpull(struct samsung_gpio_chip *chip,
+static samsung_gpio_pull_t exynos_gpio_getpull(struct samsung_gpio_chip *chip,
 						unsigned int off)
 {
 	samsung_gpio_pull_t pull;
@@ -452,9 +452,9 @@
 };
 #endif
 
-static struct samsung_gpio_cfg exynos4_gpio_cfg = {
-	.set_pull	= exynos4_gpio_setpull,
-	.get_pull	= exynos4_gpio_getpull,
+static struct samsung_gpio_cfg exynos_gpio_cfg = {
+	.set_pull	= exynos_gpio_setpull,
+	.get_pull	= exynos_gpio_getpull,
 	.set_config	= samsung_gpio_setcfg_4bit,
 	.get_config	= samsung_gpio_getcfg_4bit,
 };
@@ -502,13 +502,13 @@
 		.get_config	= samsung_gpio_getcfg_2bit,
 	},
 	[8] = {
-		.set_pull	= exynos4_gpio_setpull,
-		.get_pull	= exynos4_gpio_getpull,
+		.set_pull	= exynos_gpio_setpull,
+		.get_pull	= exynos_gpio_getpull,
 	},
 	[9] = {
 		.cfg_eint	= 0x3,
-		.set_pull	= exynos4_gpio_setpull,
-		.get_pull	= exynos4_gpio_getpull,
+		.set_pull	= exynos_gpio_setpull,
+		.get_pull	= exynos_gpio_getpull,
 	}
 };
 
@@ -2113,10 +2113,10 @@
 };
 
 /*
- * Followings are the gpio banks in EXYNOS4210
+ * Followings are the gpio banks in EXYNOS SoCs
  *
  * The 'config' member when left to NULL, is initialized to the default
- * structure samsung_gpio_cfgs[3] in the init function below.
+ * structure exynos_gpio_cfg in the init function below.
  *
  * The 'base' member is also initialized in the init function below.
  * Note: The initialization of 'base' member of samsung_gpio_chip structure
@@ -2331,7 +2331,6 @@
 			.label	= "GPY6",
 		},
 	}, {
-		.base	= (S5P_VA_GPIO2 + 0xC00),
 		.config	= &samsung_gpio_cfgs[9],
 		.irq_base = IRQ_EINT(0),
 		.chip	= {
@@ -2341,7 +2340,6 @@
 			.to_irq	= samsung_gpiolib_to_irq,
 		},
 	}, {
-		.base	= (S5P_VA_GPIO2 + 0xC20),
 		.config	= &samsung_gpio_cfgs[9],
 		.irq_base = IRQ_EINT(8),
 		.chip	= {
@@ -2351,7 +2349,6 @@
 			.to_irq	= samsung_gpiolib_to_irq,
 		},
 	}, {
-		.base	= (S5P_VA_GPIO2 + 0xC40),
 		.config	= &samsung_gpio_cfgs[9],
 		.irq_base = IRQ_EINT(16),
 		.chip	= {
@@ -2361,7 +2358,6 @@
 			.to_irq	= samsung_gpiolib_to_irq,
 		},
 	}, {
-		.base	= (S5P_VA_GPIO2 + 0xC60),
 		.config	= &samsung_gpio_cfgs[9],
 		.irq_base = IRQ_EINT(24),
 		.chip	= {
@@ -2386,8 +2382,280 @@
 #endif
 };
 
-#if defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_OF)
-static int exynos4_gpio_xlate(struct gpio_chip *gc,
+static struct samsung_gpio_chip exynos5_gpios_1[] = {
+#ifdef CONFIG_ARCH_EXYNOS5
+	{
+		.chip	= {
+			.base	= EXYNOS5_GPA0(0),
+			.ngpio	= EXYNOS5_GPIO_A0_NR,
+			.label	= "GPA0",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPA1(0),
+			.ngpio	= EXYNOS5_GPIO_A1_NR,
+			.label	= "GPA1",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPA2(0),
+			.ngpio	= EXYNOS5_GPIO_A2_NR,
+			.label	= "GPA2",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPB0(0),
+			.ngpio	= EXYNOS5_GPIO_B0_NR,
+			.label	= "GPB0",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPB1(0),
+			.ngpio	= EXYNOS5_GPIO_B1_NR,
+			.label	= "GPB1",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPB2(0),
+			.ngpio	= EXYNOS5_GPIO_B2_NR,
+			.label	= "GPB2",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPB3(0),
+			.ngpio	= EXYNOS5_GPIO_B3_NR,
+			.label	= "GPB3",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPC0(0),
+			.ngpio	= EXYNOS5_GPIO_C0_NR,
+			.label	= "GPC0",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPC1(0),
+			.ngpio	= EXYNOS5_GPIO_C1_NR,
+			.label	= "GPC1",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPC2(0),
+			.ngpio	= EXYNOS5_GPIO_C2_NR,
+			.label	= "GPC2",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPC3(0),
+			.ngpio	= EXYNOS5_GPIO_C3_NR,
+			.label	= "GPC3",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPD0(0),
+			.ngpio	= EXYNOS5_GPIO_D0_NR,
+			.label	= "GPD0",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPD1(0),
+			.ngpio	= EXYNOS5_GPIO_D1_NR,
+			.label	= "GPD1",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPY0(0),
+			.ngpio	= EXYNOS5_GPIO_Y0_NR,
+			.label	= "GPY0",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPY1(0),
+			.ngpio	= EXYNOS5_GPIO_Y1_NR,
+			.label	= "GPY1",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPY2(0),
+			.ngpio	= EXYNOS5_GPIO_Y2_NR,
+			.label	= "GPY2",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPY3(0),
+			.ngpio	= EXYNOS5_GPIO_Y3_NR,
+			.label	= "GPY3",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPY4(0),
+			.ngpio	= EXYNOS5_GPIO_Y4_NR,
+			.label	= "GPY4",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPY5(0),
+			.ngpio	= EXYNOS5_GPIO_Y5_NR,
+			.label	= "GPY5",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPY6(0),
+			.ngpio	= EXYNOS5_GPIO_Y6_NR,
+			.label	= "GPY6",
+		},
+	}, {
+		.config	= &samsung_gpio_cfgs[9],
+		.irq_base = IRQ_EINT(0),
+		.chip	= {
+			.base	= EXYNOS5_GPX0(0),
+			.ngpio	= EXYNOS5_GPIO_X0_NR,
+			.label	= "GPX0",
+			.to_irq	= samsung_gpiolib_to_irq,
+		},
+	}, {
+		.config	= &samsung_gpio_cfgs[9],
+		.irq_base = IRQ_EINT(8),
+		.chip	= {
+			.base	= EXYNOS5_GPX1(0),
+			.ngpio	= EXYNOS5_GPIO_X1_NR,
+			.label	= "GPX1",
+			.to_irq	= samsung_gpiolib_to_irq,
+		},
+	}, {
+		.config	= &samsung_gpio_cfgs[9],
+		.irq_base = IRQ_EINT(16),
+		.chip	= {
+			.base	= EXYNOS5_GPX2(0),
+			.ngpio	= EXYNOS5_GPIO_X2_NR,
+			.label	= "GPX2",
+			.to_irq	= samsung_gpiolib_to_irq,
+		},
+	}, {
+		.config	= &samsung_gpio_cfgs[9],
+		.irq_base = IRQ_EINT(24),
+		.chip	= {
+			.base	= EXYNOS5_GPX3(0),
+			.ngpio	= EXYNOS5_GPIO_X3_NR,
+			.label	= "GPX3",
+			.to_irq	= samsung_gpiolib_to_irq,
+		},
+	},
+#endif
+};
+
+static struct samsung_gpio_chip exynos5_gpios_2[] = {
+#ifdef CONFIG_ARCH_EXYNOS5
+	{
+		.chip	= {
+			.base	= EXYNOS5_GPE0(0),
+			.ngpio	= EXYNOS5_GPIO_E0_NR,
+			.label	= "GPE0",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPE1(0),
+			.ngpio	= EXYNOS5_GPIO_E1_NR,
+			.label	= "GPE1",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPF0(0),
+			.ngpio	= EXYNOS5_GPIO_F0_NR,
+			.label	= "GPF0",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPF1(0),
+			.ngpio	= EXYNOS5_GPIO_F1_NR,
+			.label	= "GPF1",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPG0(0),
+			.ngpio	= EXYNOS5_GPIO_G0_NR,
+			.label	= "GPG0",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPG1(0),
+			.ngpio	= EXYNOS5_GPIO_G1_NR,
+			.label	= "GPG1",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPG2(0),
+			.ngpio	= EXYNOS5_GPIO_G2_NR,
+			.label	= "GPG2",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPH0(0),
+			.ngpio	= EXYNOS5_GPIO_H0_NR,
+			.label	= "GPH0",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPH1(0),
+			.ngpio	= EXYNOS5_GPIO_H1_NR,
+			.label	= "GPH1",
+
+		},
+	},
+#endif
+};
+
+static struct samsung_gpio_chip exynos5_gpios_3[] = {
+#ifdef CONFIG_ARCH_EXYNOS5
+	{
+		.chip	= {
+			.base	= EXYNOS5_GPV0(0),
+			.ngpio	= EXYNOS5_GPIO_V0_NR,
+			.label	= "GPV0",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPV1(0),
+			.ngpio	= EXYNOS5_GPIO_V1_NR,
+			.label	= "GPV1",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPV2(0),
+			.ngpio	= EXYNOS5_GPIO_V2_NR,
+			.label	= "GPV2",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPV3(0),
+			.ngpio	= EXYNOS5_GPIO_V3_NR,
+			.label	= "GPV3",
+		},
+	}, {
+		.chip	= {
+			.base	= EXYNOS5_GPV4(0),
+			.ngpio	= EXYNOS5_GPIO_V4_NR,
+			.label	= "GPV4",
+		},
+	},
+#endif
+};
+
+static struct samsung_gpio_chip exynos5_gpios_4[] = {
+#ifdef CONFIG_ARCH_EXYNOS5
+	{
+		.chip	= {
+			.base	= EXYNOS5_GPZ(0),
+			.ngpio	= EXYNOS5_GPIO_Z_NR,
+			.label	= "GPZ",
+		},
+	},
+#endif
+};
+
+
+#if defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF)
+static int exynos_gpio_xlate(struct gpio_chip *gc,
 			const struct of_phandle_args *gpiospec, u32 *flags)
 {
 	unsigned int pin;
@@ -2413,13 +2681,13 @@
 	return gpiospec->args[0];
 }
 
-static const struct of_device_id exynos4_gpio_dt_match[] __initdata = {
+static const struct of_device_id exynos_gpio_dt_match[] __initdata = {
 	{ .compatible = "samsung,exynos4-gpio", },
 	{}
 };
 
-static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
-						 u64 base, u64 offset)
+static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
+						u64 base, u64 offset)
 {
 	struct gpio_chip *gc =  &chip->chip;
 	u64 address;
@@ -2429,28 +2697,29 @@
 
 	address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset;
 	gc->of_node = of_find_matching_node_by_address(NULL,
-			exynos4_gpio_dt_match, address);
+			exynos_gpio_dt_match, address);
 	if (!gc->of_node) {
 		pr_info("gpio: device tree node not found for gpio controller"
 			" with base address %08llx\n", address);
 		return;
 	}
 	gc->of_gpio_n_cells = 4;
-	gc->of_xlate = exynos4_gpio_xlate;
+	gc->of_xlate = exynos_gpio_xlate;
 }
-#elif defined(CONFIG_ARCH_EXYNOS4)
-static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
-						 u64 base, u64 offset)
+#elif defined(CONFIG_ARCH_EXYNOS)
+static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
+						u64 base, u64 offset)
 {
 	return;
 }
-#endif /* defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_OF) */
+#endif /* defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) */
 
 /* TODO: cleanup soc_is_* */
 static __init int samsung_gpiolib_init(void)
 {
 	struct samsung_gpio_chip *chip;
 	int i, nr_chips;
+	void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4;
 	int group = 0;
 
 	samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs));
@@ -2516,66 +2785,200 @@
 		s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
 #endif
 	} else if (soc_is_exynos4210()) {
-		group = 0;
+#ifdef CONFIG_CPU_EXYNOS4210
+		void __iomem *gpx_base;
 
 		/* gpio part1 */
+		gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K);
+		if (gpio_base1 == NULL) {
+			pr_err("unable to ioremap for gpio_base1\n");
+			goto err_ioremap1;
+		}
+
 		chip = exynos4_gpios_1;
 		nr_chips = ARRAY_SIZE(exynos4_gpios_1);
 
 		for (i = 0; i < nr_chips; i++, chip++) {
 			if (!chip->config) {
-				chip->config = &exynos4_gpio_cfg;
+				chip->config = &exynos_gpio_cfg;
 				chip->group = group++;
 			}
-#ifdef CONFIG_CPU_EXYNOS4210
-			exynos4_gpiolib_attach_ofnode(chip,
+			exynos_gpiolib_attach_ofnode(chip,
 					EXYNOS4_PA_GPIO1, i * 0x20);
-#endif
 		}
-		samsung_gpiolib_add_4bit_chips(exynos4_gpios_1, nr_chips, S5P_VA_GPIO1);
+		samsung_gpiolib_add_4bit_chips(exynos4_gpios_1,
+					       nr_chips, gpio_base1);
 
 		/* gpio part2 */
+		gpio_base2 = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
+		if (gpio_base2 == NULL) {
+			pr_err("unable to ioremap for gpio_base2\n");
+			goto err_ioremap2;
+		}
+
+		/* need to set base address for gpx */
+		chip = &exynos4_gpios_2[16];
+		gpx_base = gpio_base2 + 0xC00;
+		for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
+			chip->base = gpx_base;
+
 		chip = exynos4_gpios_2;
 		nr_chips = ARRAY_SIZE(exynos4_gpios_2);
 
 		for (i = 0; i < nr_chips; i++, chip++) {
 			if (!chip->config) {
-				chip->config = &exynos4_gpio_cfg;
+				chip->config = &exynos_gpio_cfg;
 				chip->group = group++;
 			}
-#ifdef CONFIG_CPU_EXYNOS4210
-			exynos4_gpiolib_attach_ofnode(chip,
+			exynos_gpiolib_attach_ofnode(chip,
 					EXYNOS4_PA_GPIO2, i * 0x20);
-#endif
 		}
-		samsung_gpiolib_add_4bit_chips(exynos4_gpios_2, nr_chips, S5P_VA_GPIO2);
+		samsung_gpiolib_add_4bit_chips(exynos4_gpios_2,
+					       nr_chips, gpio_base2);
 
 		/* gpio part3 */
+		gpio_base3 = ioremap(EXYNOS4_PA_GPIO3, SZ_256);
+		if (gpio_base3 == NULL) {
+			pr_err("unable to ioremap for gpio_base3\n");
+			goto err_ioremap3;
+		}
+
 		chip = exynos4_gpios_3;
 		nr_chips = ARRAY_SIZE(exynos4_gpios_3);
 
 		for (i = 0; i < nr_chips; i++, chip++) {
 			if (!chip->config) {
-				chip->config = &exynos4_gpio_cfg;
+				chip->config = &exynos_gpio_cfg;
 				chip->group = group++;
 			}
-#ifdef CONFIG_CPU_EXYNOS4210
-			exynos4_gpiolib_attach_ofnode(chip,
+			exynos_gpiolib_attach_ofnode(chip,
 					EXYNOS4_PA_GPIO3, i * 0x20);
-#endif
 		}
-		samsung_gpiolib_add_4bit_chips(exynos4_gpios_3, nr_chips, S5P_VA_GPIO3);
+		samsung_gpiolib_add_4bit_chips(exynos4_gpios_3,
+					       nr_chips, gpio_base3);
 
 #if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_S5P_GPIO_INT)
 		s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS);
 		s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS);
 #endif
+
+#endif	/* CONFIG_CPU_EXYNOS4210 */
+	} else if (soc_is_exynos5250()) {
+#ifdef CONFIG_SOC_EXYNOS5250
+		void __iomem *gpx_base;
+
+		/* gpio part1 */
+		gpio_base1 = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
+		if (gpio_base1 == NULL) {
+			pr_err("unable to ioremap for gpio_base1\n");
+			goto err_ioremap1;
+		}
+
+		/* need to set base address for gpx */
+		chip = &exynos5_gpios_1[20];
+		gpx_base = gpio_base1 + 0xC00;
+		for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
+			chip->base = gpx_base;
+
+		chip = exynos5_gpios_1;
+		nr_chips = ARRAY_SIZE(exynos5_gpios_1);
+
+		for (i = 0; i < nr_chips; i++, chip++) {
+			if (!chip->config) {
+				chip->config = &exynos_gpio_cfg;
+				chip->group = group++;
+			}
+			exynos_gpiolib_attach_ofnode(chip,
+					EXYNOS5_PA_GPIO1, i * 0x20);
+		}
+		samsung_gpiolib_add_4bit_chips(exynos5_gpios_1,
+					       nr_chips, gpio_base1);
+
+		/* gpio part2 */
+		gpio_base2 = ioremap(EXYNOS5_PA_GPIO2, SZ_4K);
+		if (gpio_base2 == NULL) {
+			pr_err("unable to ioremap for gpio_base2\n");
+			goto err_ioremap2;
+		}
+
+		chip = exynos5_gpios_2;
+		nr_chips = ARRAY_SIZE(exynos5_gpios_2);
+
+		for (i = 0; i < nr_chips; i++, chip++) {
+			if (!chip->config) {
+				chip->config = &exynos_gpio_cfg;
+				chip->group = group++;
+			}
+			exynos_gpiolib_attach_ofnode(chip,
+					EXYNOS5_PA_GPIO2, i * 0x20);
+		}
+		samsung_gpiolib_add_4bit_chips(exynos5_gpios_2,
+					       nr_chips, gpio_base2);
+
+		/* gpio part3 */
+		gpio_base3 = ioremap(EXYNOS5_PA_GPIO3, SZ_4K);
+		if (gpio_base3 == NULL) {
+			pr_err("unable to ioremap for gpio_base3\n");
+			goto err_ioremap3;
+		}
+
+		/* need to set base address for gpv */
+		exynos5_gpios_3[0].base = gpio_base3;
+		exynos5_gpios_3[1].base = gpio_base3 + 0x20;
+		exynos5_gpios_3[2].base = gpio_base3 + 0x60;
+		exynos5_gpios_3[3].base = gpio_base3 + 0x80;
+		exynos5_gpios_3[4].base = gpio_base3 + 0xC0;
+
+		chip = exynos5_gpios_3;
+		nr_chips = ARRAY_SIZE(exynos5_gpios_3);
+
+		for (i = 0; i < nr_chips; i++, chip++) {
+			if (!chip->config) {
+				chip->config = &exynos_gpio_cfg;
+				chip->group = group++;
+			}
+			exynos_gpiolib_attach_ofnode(chip,
+					EXYNOS5_PA_GPIO3, i * 0x20);
+		}
+		samsung_gpiolib_add_4bit_chips(exynos5_gpios_3,
+					       nr_chips, gpio_base3);
+
+		/* gpio part4 */
+		gpio_base4 = ioremap(EXYNOS5_PA_GPIO4, SZ_4K);
+		if (gpio_base4 == NULL) {
+			pr_err("unable to ioremap for gpio_base4\n");
+			goto err_ioremap4;
+		}
+
+		chip = exynos5_gpios_4;
+		nr_chips = ARRAY_SIZE(exynos5_gpios_4);
+
+		for (i = 0; i < nr_chips; i++, chip++) {
+			if (!chip->config) {
+				chip->config = &exynos_gpio_cfg;
+				chip->group = group++;
+			}
+			exynos_gpiolib_attach_ofnode(chip,
+					EXYNOS5_PA_GPIO4, i * 0x20);
+		}
+		samsung_gpiolib_add_4bit_chips(exynos5_gpios_4,
+					       nr_chips, gpio_base4);
+#endif	/* CONFIG_SOC_EXYNOS5250 */
 	} else {
 		WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n");
 		return -ENODEV;
 	}
 
 	return 0;
+
+err_ioremap4:
+	iounmap(gpio_base3);
+err_ioremap3:
+	iounmap(gpio_base2);
+err_ioremap2:
+	iounmap(gpio_base1);
+err_ioremap1:
+	return -ENOMEM;
 }
 core_initcall(samsung_gpiolib_init);
 
diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c
new file mode 100644
index 0000000..9ba15d3
--- /dev/null
+++ b/drivers/gpio/gpio-sodaville.c
@@ -0,0 +1,302 @@
+/*
+ *  GPIO interface for Intel Sodaville SoCs.
+ *
+ *  Copyright (c) 2010, 2011 Intel Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/of_irq.h>
+#include <linux/basic_mmio_gpio.h>
+
+#define DRV_NAME		"sdv_gpio"
+#define SDV_NUM_PUB_GPIOS	12
+#define PCI_DEVICE_ID_SDV_GPIO	0x2e67
+#define GPIO_BAR		0
+
+#define GPOUTR		0x00
+#define GPOER		0x04
+#define GPINR		0x08
+
+#define GPSTR		0x0c
+#define GPIT1R0		0x10
+#define GPIO_INT	0x14
+#define GPIT1R1		0x18
+
+#define GPMUXCTL	0x1c
+
+struct sdv_gpio_chip_data {
+	int irq_base;
+	void __iomem *gpio_pub_base;
+	struct irq_domain id;
+	struct irq_chip_generic *gc;
+	struct bgpio_chip bgpio;
+};
+
+static int sdv_gpio_pub_set_type(struct irq_data *d, unsigned int type)
+{
+	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+	struct sdv_gpio_chip_data *sd = gc->private;
+	void __iomem *type_reg;
+	u32 irq_offs = d->irq - sd->irq_base;
+	u32 reg;
+
+	if (irq_offs < 8)
+		type_reg = sd->gpio_pub_base + GPIT1R0;
+	else
+		type_reg = sd->gpio_pub_base + GPIT1R1;
+
+	reg = readl(type_reg);
+
+	switch (type) {
+	case IRQ_TYPE_LEVEL_HIGH:
+		reg &= ~BIT(4 * (irq_offs % 8));
+		break;
+
+	case IRQ_TYPE_LEVEL_LOW:
+		reg |= BIT(4 * (irq_offs % 8));
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	writel(reg, type_reg);
+	return 0;
+}
+
+static irqreturn_t sdv_gpio_pub_irq_handler(int irq, void *data)
+{
+	struct sdv_gpio_chip_data *sd = data;
+	u32 irq_stat = readl(sd->gpio_pub_base + GPSTR);
+
+	irq_stat &= readl(sd->gpio_pub_base + GPIO_INT);
+	if (!irq_stat)
+		return IRQ_NONE;
+
+	while (irq_stat) {
+		u32 irq_bit = __fls(irq_stat);
+
+		irq_stat &= ~BIT(irq_bit);
+		generic_handle_irq(sd->irq_base + irq_bit);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int sdv_xlate(struct irq_domain *h, struct device_node *node,
+		const u32 *intspec, u32 intsize, irq_hw_number_t *out_hwirq,
+		u32 *out_type)
+{
+	u32 line, type;
+
+	if (node != h->of_node)
+		return -EINVAL;
+
+	if (intsize < 2)
+		return -EINVAL;
+
+	line = *intspec;
+	*out_hwirq = line;
+
+	intspec++;
+	type = *intspec;
+
+	switch (type) {
+	case IRQ_TYPE_LEVEL_LOW:
+	case IRQ_TYPE_LEVEL_HIGH:
+		*out_type = type;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static struct irq_domain_ops irq_domain_sdv_ops = {
+	.dt_translate	= sdv_xlate,
+};
+
+static __devinit int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd,
+		struct pci_dev *pdev)
+{
+	struct irq_chip_type *ct;
+	int ret;
+
+	sd->irq_base = irq_alloc_descs(-1, 0, SDV_NUM_PUB_GPIOS, -1);
+	if (sd->irq_base < 0)
+		return sd->irq_base;
+
+	/* mask + ACK all interrupt sources */
+	writel(0, sd->gpio_pub_base + GPIO_INT);
+	writel((1 << 11) - 1, sd->gpio_pub_base + GPSTR);
+
+	ret = request_irq(pdev->irq, sdv_gpio_pub_irq_handler, IRQF_SHARED,
+			"sdv_gpio", sd);
+	if (ret)
+		goto out_free_desc;
+
+	sd->id.irq_base = sd->irq_base;
+	sd->id.of_node = of_node_get(pdev->dev.of_node);
+	sd->id.ops = &irq_domain_sdv_ops;
+
+	/*
+	 * This gpio irq controller latches level irqs. Testing shows that if
+	 * we unmask & ACK the IRQ before the source of the interrupt is gone
+	 * then the interrupt is active again.
+	 */
+	sd->gc = irq_alloc_generic_chip("sdv-gpio", 1, sd->irq_base,
+			sd->gpio_pub_base, handle_fasteoi_irq);
+	if (!sd->gc) {
+		ret = -ENOMEM;
+		goto out_free_irq;
+	}
+
+	sd->gc->private = sd;
+	ct = sd->gc->chip_types;
+	ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
+	ct->regs.eoi = GPSTR;
+	ct->regs.mask = GPIO_INT;
+	ct->chip.irq_mask = irq_gc_mask_clr_bit;
+	ct->chip.irq_unmask = irq_gc_mask_set_bit;
+	ct->chip.irq_eoi = irq_gc_eoi;
+	ct->chip.irq_set_type = sdv_gpio_pub_set_type;
+
+	irq_setup_generic_chip(sd->gc, IRQ_MSK(SDV_NUM_PUB_GPIOS),
+			IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST,
+			IRQ_LEVEL | IRQ_NOPROBE);
+
+	irq_domain_add(&sd->id);
+	return 0;
+out_free_irq:
+	free_irq(pdev->irq, sd);
+out_free_desc:
+	irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS);
+	return ret;
+}
+
+static int __devinit sdv_gpio_probe(struct pci_dev *pdev,
+					const struct pci_device_id *pci_id)
+{
+	struct sdv_gpio_chip_data *sd;
+	unsigned long addr;
+	const void *prop;
+	int len;
+	int ret;
+	u32 mux_val;
+
+	sd = kzalloc(sizeof(struct sdv_gpio_chip_data), GFP_KERNEL);
+	if (!sd)
+		return -ENOMEM;
+	ret = pci_enable_device(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "can't enable device.\n");
+		goto done;
+	}
+
+	ret = pci_request_region(pdev, GPIO_BAR, DRV_NAME);
+	if (ret) {
+		dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR);
+		goto disable_pci;
+	}
+
+	addr = pci_resource_start(pdev, GPIO_BAR);
+	if (!addr)
+		goto release_reg;
+	sd->gpio_pub_base = ioremap(addr, pci_resource_len(pdev, GPIO_BAR));
+
+	prop = of_get_property(pdev->dev.of_node, "intel,muxctl", &len);
+	if (prop && len == 4) {
+		mux_val = of_read_number(prop, 1);
+		writel(mux_val, sd->gpio_pub_base + GPMUXCTL);
+	}
+
+	ret = bgpio_init(&sd->bgpio, &pdev->dev, 4,
+			sd->gpio_pub_base + GPINR, sd->gpio_pub_base + GPOUTR,
+			NULL, sd->gpio_pub_base + GPOER, NULL, false);
+	if (ret)
+		goto unmap;
+	sd->bgpio.gc.ngpio = SDV_NUM_PUB_GPIOS;
+
+	ret = gpiochip_add(&sd->bgpio.gc);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "gpiochip_add() failed.\n");
+		goto unmap;
+	}
+
+	ret = sdv_register_irqsupport(sd, pdev);
+	if (ret)
+		goto unmap;
+
+	pci_set_drvdata(pdev, sd);
+	dev_info(&pdev->dev, "Sodaville GPIO driver registered.\n");
+	return 0;
+
+unmap:
+	iounmap(sd->gpio_pub_base);
+release_reg:
+	pci_release_region(pdev, GPIO_BAR);
+disable_pci:
+	pci_disable_device(pdev);
+done:
+	kfree(sd);
+	return ret;
+}
+
+static void sdv_gpio_remove(struct pci_dev *pdev)
+{
+	struct sdv_gpio_chip_data *sd = pci_get_drvdata(pdev);
+
+	irq_domain_del(&sd->id);
+	free_irq(pdev->irq, sd);
+	irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS);
+
+	if (gpiochip_remove(&sd->bgpio.gc))
+		dev_err(&pdev->dev, "gpiochip_remove() failed.\n");
+
+	pci_release_region(pdev, GPIO_BAR);
+	iounmap(sd->gpio_pub_base);
+	pci_disable_device(pdev);
+	kfree(sd);
+}
+
+static struct pci_device_id sdv_gpio_pci_ids[] __devinitdata = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDV_GPIO) },
+	{ 0, },
+};
+
+static struct pci_driver sdv_gpio_driver = {
+	.name = DRV_NAME,
+	.id_table = sdv_gpio_pci_ids,
+	.probe = sdv_gpio_probe,
+	.remove = sdv_gpio_remove,
+};
+
+static int __init sdv_gpio_init(void)
+{
+	return pci_register_driver(&sdv_gpio_driver);
+}
+module_init(sdv_gpio_init);
+
+static void __exit sdv_gpio_exit(void)
+{
+	pci_unregister_driver(&sdv_gpio_driver);
+}
+module_exit(sdv_gpio_exit);
+
+MODULE_AUTHOR("Hans J. Koch <hjk@linutronix.de>");
+MODULE_DESCRIPTION("GPIO interface for Intel Sodaville SoCs");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 87a68a8..dce3472 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -54,7 +54,7 @@
 	if (ret < 0)
 		return ret;
 
-	return ret & mask;
+	return !!(ret & mask);
 }
 
 static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
@@ -307,13 +307,11 @@
 	struct stmpe_gpio_platform_data *pdata;
 	struct stmpe_gpio *stmpe_gpio;
 	int ret;
-	int irq;
+	int irq = 0;
 
 	pdata = stmpe->pdata->gpio;
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
 
 	stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL);
 	if (!stmpe_gpio)
@@ -330,21 +328,28 @@
 	stmpe_gpio->chip.dev = &pdev->dev;
 	stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
 
-	stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
+	if (irq >= 0)
+		stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
+	else
+		dev_info(&pdev->dev,
+			"device configured in no-irq mode; "
+			"irqs are not available\n");
 
 	ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
 	if (ret)
 		goto out_free;
 
-	ret = stmpe_gpio_irq_init(stmpe_gpio);
-	if (ret)
-		goto out_disable;
+	if (irq >= 0) {
+		ret = stmpe_gpio_irq_init(stmpe_gpio);
+		if (ret)
+			goto out_disable;
 
-	ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT,
-				   "stmpe-gpio", stmpe_gpio);
-	if (ret) {
-		dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
-		goto out_removeirq;
+		ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq,
+				IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio);
+		if (ret) {
+			dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
+			goto out_removeirq;
+		}
 	}
 
 	ret = gpiochip_add(&stmpe_gpio->chip);
@@ -361,9 +366,11 @@
 	return 0;
 
 out_freeirq:
-	free_irq(irq, stmpe_gpio);
+	if (irq >= 0)
+		free_irq(irq, stmpe_gpio);
 out_removeirq:
-	stmpe_gpio_irq_remove(stmpe_gpio);
+	if (irq >= 0)
+		stmpe_gpio_irq_remove(stmpe_gpio);
 out_disable:
 	stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
 out_free:
@@ -391,8 +398,10 @@
 
 	stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
 
-	free_irq(irq, stmpe_gpio);
-	stmpe_gpio_irq_remove(stmpe_gpio);
+	if (irq >= 0) {
+		free_irq(irq, stmpe_gpio);
+		stmpe_gpio_irq_remove(stmpe_gpio);
+	}
 	platform_set_drvdata(pdev, NULL);
 	kfree(stmpe_gpio);
 
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index bdc2937..12f349b3 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -22,9 +22,10 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
-#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
+#include <linux/irqdomain.h>
 
 #include <asm/mach/irq.h>
 
@@ -36,7 +37,8 @@
 #define GPIO_PORT(x)		(((x) >> 3) & 0x3)
 #define GPIO_BIT(x)		((x) & 0x7)
 
-#define GPIO_REG(x)		(GPIO_BANK(x) * 0x80 + GPIO_PORT(x) * 4)
+#define GPIO_REG(x)		(GPIO_BANK(x) * tegra_gpio_bank_stride + \
+					GPIO_PORT(x) * 4)
 
 #define GPIO_CNF(x)		(GPIO_REG(x) + 0x00)
 #define GPIO_OE(x)		(GPIO_REG(x) + 0x10)
@@ -47,12 +49,12 @@
 #define GPIO_INT_LVL(x)		(GPIO_REG(x) + 0x60)
 #define GPIO_INT_CLR(x)		(GPIO_REG(x) + 0x70)
 
-#define GPIO_MSK_CNF(x)		(GPIO_REG(x) + 0x800)
-#define GPIO_MSK_OE(x)		(GPIO_REG(x) + 0x810)
-#define GPIO_MSK_OUT(x)		(GPIO_REG(x) + 0X820)
-#define GPIO_MSK_INT_STA(x)	(GPIO_REG(x) + 0x840)
-#define GPIO_MSK_INT_ENB(x)	(GPIO_REG(x) + 0x850)
-#define GPIO_MSK_INT_LVL(x)	(GPIO_REG(x) + 0x860)
+#define GPIO_MSK_CNF(x)		(GPIO_REG(x) + tegra_gpio_upper_offset + 0x00)
+#define GPIO_MSK_OE(x)		(GPIO_REG(x) + tegra_gpio_upper_offset + 0x10)
+#define GPIO_MSK_OUT(x)		(GPIO_REG(x) + tegra_gpio_upper_offset + 0X20)
+#define GPIO_MSK_INT_STA(x)	(GPIO_REG(x) + tegra_gpio_upper_offset + 0x40)
+#define GPIO_MSK_INT_ENB(x)	(GPIO_REG(x) + tegra_gpio_upper_offset + 0x50)
+#define GPIO_MSK_INT_LVL(x)	(GPIO_REG(x) + tegra_gpio_upper_offset + 0x60)
 
 #define GPIO_INT_LVL_MASK		0x010101
 #define GPIO_INT_LVL_EDGE_RISING	0x000101
@@ -74,9 +76,12 @@
 #endif
 };
 
-
+static struct irq_domain *irq_domain;
 static void __iomem *regs;
-static struct tegra_gpio_bank tegra_gpio_banks[7];
+static u32 tegra_gpio_bank_count;
+static u32 tegra_gpio_bank_stride;
+static u32 tegra_gpio_upper_offset;
+static struct tegra_gpio_bank *tegra_gpio_banks;
 
 static inline void tegra_gpio_writel(u32 val, u32 reg)
 {
@@ -107,11 +112,13 @@
 {
 	tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1);
 }
+EXPORT_SYMBOL_GPL(tegra_gpio_enable);
 
 void tegra_gpio_disable(int gpio)
 {
 	tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0);
 }
+EXPORT_SYMBOL_GPL(tegra_gpio_disable);
 
 static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
@@ -139,7 +146,7 @@
 
 static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	return TEGRA_GPIO_TO_IRQ(offset);
+	return irq_find_mapping(irq_domain, offset);
 }
 
 static struct gpio_chip tegra_gpio_chip = {
@@ -155,28 +162,28 @@
 
 static void tegra_gpio_irq_ack(struct irq_data *d)
 {
-	int gpio = d->irq - INT_GPIO_BASE;
+	int gpio = d->hwirq;
 
 	tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio));
 }
 
 static void tegra_gpio_irq_mask(struct irq_data *d)
 {
-	int gpio = d->irq - INT_GPIO_BASE;
+	int gpio = d->hwirq;
 
 	tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0);
 }
 
 static void tegra_gpio_irq_unmask(struct irq_data *d)
 {
-	int gpio = d->irq - INT_GPIO_BASE;
+	int gpio = d->hwirq;
 
 	tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1);
 }
 
 static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 {
-	int gpio = d->irq - INT_GPIO_BASE;
+	int gpio = d->hwirq;
 	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
 	int port = GPIO_PORT(gpio);
 	int lvl_type;
@@ -273,7 +280,7 @@
 
 	local_irq_save(flags);
 
-	for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
+	for (b = 0; b < tegra_gpio_bank_count; b++) {
 		struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
 
 		for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
@@ -296,7 +303,7 @@
 	int p;
 
 	local_irq_save(flags);
-	for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
+	for (b = 0; b < tegra_gpio_bank_count; b++) {
 		struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
 
 		for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
@@ -329,6 +336,26 @@
 #endif
 };
 
+struct tegra_gpio_soc_config {
+	u32 bank_stride;
+	u32 upper_offset;
+};
+
+static struct tegra_gpio_soc_config tegra20_gpio_config = {
+	.bank_stride = 0x80,
+	.upper_offset = 0x800,
+};
+
+static struct tegra_gpio_soc_config tegra30_gpio_config = {
+	.bank_stride = 0x100,
+	.upper_offset = 0x80,
+};
+
+static struct of_device_id tegra_gpio_of_match[] __devinitdata = {
+	{ .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config },
+	{ .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config },
+	{ },
+};
 
 /* This lock class tells lockdep that GPIO irqs are in a different
  * category than their parents, so it won't report false recursion.
@@ -337,13 +364,55 @@
 
 static int __devinit tegra_gpio_probe(struct platform_device *pdev)
 {
+	const struct of_device_id *match;
+	struct tegra_gpio_soc_config *config;
+	int irq_base;
 	struct resource *res;
 	struct tegra_gpio_bank *bank;
 	int gpio;
 	int i;
 	int j;
 
-	for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) {
+	match = of_match_device(tegra_gpio_of_match, &pdev->dev);
+	if (match)
+		config = (struct tegra_gpio_soc_config *)match->data;
+	else
+		config = &tegra20_gpio_config;
+
+	tegra_gpio_bank_stride = config->bank_stride;
+	tegra_gpio_upper_offset = config->upper_offset;
+
+	for (;;) {
+		res = platform_get_resource(pdev, IORESOURCE_IRQ, tegra_gpio_bank_count);
+		if (!res)
+			break;
+		tegra_gpio_bank_count++;
+	}
+	if (!tegra_gpio_bank_count) {
+		dev_err(&pdev->dev, "Missing IRQ resource\n");
+		return -ENODEV;
+	}
+
+	tegra_gpio_chip.ngpio = tegra_gpio_bank_count * 32;
+
+	tegra_gpio_banks = devm_kzalloc(&pdev->dev,
+			tegra_gpio_bank_count * sizeof(*tegra_gpio_banks),
+			GFP_KERNEL);
+	if (!tegra_gpio_banks) {
+		dev_err(&pdev->dev, "Couldn't allocate bank structure\n");
+		return -ENODEV;
+	}
+
+	irq_base = irq_alloc_descs(-1, 0, tegra_gpio_chip.ngpio, 0);
+	if (irq_base < 0) {
+		dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n");
+		return -ENODEV;
+	}
+	irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
+					   tegra_gpio_chip.ngpio, irq_base, 0,
+					   &irq_domain_simple_ops, NULL);
+
+	for (i = 0; i < tegra_gpio_bank_count; i++) {
 		res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
 		if (!res) {
 			dev_err(&pdev->dev, "Missing IRQ resource\n");
@@ -367,7 +436,7 @@
 		return -ENODEV;
 	}
 
-	for (i = 0; i < 7; i++) {
+	for (i = 0; i < tegra_gpio_bank_count; i++) {
 		for (j = 0; j < 4; j++) {
 			int gpio = tegra_gpio_compose(i, j, 0);
 			tegra_gpio_writel(0x00, GPIO_INT_ENB(gpio));
@@ -380,8 +449,8 @@
 
 	gpiochip_add(&tegra_gpio_chip);
 
-	for (gpio = 0; gpio < TEGRA_NR_GPIOS; gpio++) {
-		int irq = TEGRA_GPIO_TO_IRQ(gpio);
+	for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) {
+		int irq = irq_find_mapping(irq_domain, gpio);
 		/* No validity check; all Tegra GPIOs are valid IRQs */
 
 		bank = &tegra_gpio_banks[GPIO_BANK(gpio)];
@@ -393,7 +462,7 @@
 		set_irq_flags(irq, IRQF_VALID);
 	}
 
-	for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) {
+	for (i = 0; i < tegra_gpio_bank_count; i++) {
 		bank = &tegra_gpio_banks[i];
 
 		irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler);
@@ -406,11 +475,6 @@
 	return 0;
 }
 
-static struct of_device_id tegra_gpio_of_match[] __devinitdata = {
-	{ .compatible = "nvidia,tegra20-gpio", },
-	{ },
-};
-
 static struct platform_driver tegra_gpio_driver = {
 	.driver		= {
 		.name	= "tegra-gpio",
@@ -426,7 +490,7 @@
 }
 postcore_initcall(tegra_gpio_init);
 
-void __init tegra_gpio_config(struct tegra_gpio_table *table, int num)
+void tegra_gpio_config(struct tegra_gpio_table *table, int num)
 {
 	int i;
 
@@ -450,7 +514,7 @@
 	int i;
 	int j;
 
-	for (i = 0; i < 7; i++) {
+	for (i = 0; i < tegra_gpio_bank_count; i++) {
 		for (j = 0; j < 4; j++) {
 			int gpio = tegra_gpio_compose(i, j, 0);
 			seq_printf(s,
diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c
index 91f45b9..7eef648 100644
--- a/drivers/gpio/gpio-tps65910.c
+++ b/drivers/gpio/gpio-tps65910.c
@@ -69,6 +69,7 @@
 void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
 {
 	int ret;
+	struct tps65910_board *board_data;
 
 	if (!gpio_base)
 		return;
@@ -80,10 +81,10 @@
 
 	switch(tps65910_chip_id(tps65910)) {
 	case TPS65910:
-		tps65910->gpio.ngpio	= 6;
+		tps65910->gpio.ngpio	= TPS65910_NUM_GPIO;
 		break;
 	case TPS65911:
-		tps65910->gpio.ngpio	= 9;
+		tps65910->gpio.ngpio	= TPS65911_NUM_GPIO;
 		break;
 	default:
 		return;
@@ -95,6 +96,21 @@
 	tps65910->gpio.set		= tps65910_gpio_set;
 	tps65910->gpio.get		= tps65910_gpio_get;
 
+	/* Configure sleep control for gpios */
+	board_data = dev_get_platdata(tps65910->dev);
+	if (board_data) {
+		int i;
+		for (i = 0; i < tps65910->gpio.ngpio; ++i) {
+			if (board_data->en_gpio_sleep[i]) {
+				ret = tps65910_set_bits(tps65910,
+					TPS65910_GPIO0 + i, GPIO_SLEEP_MASK);
+				if (ret < 0)
+					dev_warn(tps65910->dev,
+						"GPIO Sleep setting failed\n");
+			}
+		}
+	}
+
 	ret = gpiochip_add(&tps65910->gpio);
 
 	if (ret)
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c
index b8b4f22..94256fe 100644
--- a/drivers/gpio/gpio-twl4030.c
+++ b/drivers/gpio/gpio-twl4030.c
@@ -32,6 +32,8 @@
 #include <linux/irq.h>
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/irqdomain.h>
 
 #include <linux/i2c/twl.h>
 
@@ -256,7 +258,8 @@
 		 * and vMMC2 power supplies based on card presence.
 		 */
 		pdata = chip->dev->platform_data;
-		value |= pdata->mmc_cd & 0x03;
+		if (pdata)
+			value |= pdata->mmc_cd & 0x03;
 
 		status = gpio_twl4030_write(REG_GPIO_CTRL, value);
 	}
@@ -395,59 +398,70 @@
 static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
 {
 	struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
-	int ret;
+	struct device_node *node = pdev->dev.of_node;
+	int ret, irq_base;
 
 	/* maybe setup IRQs */
-	if (pdata->irq_base) {
-		if (is_module()) {
-			dev_err(&pdev->dev,
-				"can't dispatch IRQs from modules\n");
-			goto no_irqs;
-		}
-		ret = twl4030_sih_setup(TWL4030_MODULE_GPIO);
-		if (ret < 0)
-			return ret;
-		WARN_ON(ret != pdata->irq_base);
-		twl4030_gpio_irq_base = ret;
+	if (is_module()) {
+		dev_err(&pdev->dev, "can't dispatch IRQs from modules\n");
+		goto no_irqs;
 	}
 
+	irq_base = irq_alloc_descs(-1, 0, TWL4030_GPIO_MAX, 0);
+	if (irq_base < 0) {
+		dev_err(&pdev->dev, "Failed to alloc irq_descs\n");
+		return irq_base;
+	}
+
+	irq_domain_add_legacy(node, TWL4030_GPIO_MAX, irq_base, 0,
+			      &irq_domain_simple_ops, NULL);
+
+	ret = twl4030_sih_setup(&pdev->dev, TWL4030_MODULE_GPIO, irq_base);
+	if (ret < 0)
+		return ret;
+
+	twl4030_gpio_irq_base = irq_base;
+
 no_irqs:
-	/*
-	 * NOTE:  boards may waste power if they don't set pullups
-	 * and pulldowns correctly ... default for non-ULPI pins is
-	 * pulldown, and some other pins may have external pullups
-	 * or pulldowns.  Careful!
-	 */
-	ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
-	if (ret)
-		dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
-				pdata->pullups, pdata->pulldowns,
-				ret);
-
-	ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd);
-	if (ret)
-		dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n",
-				pdata->debounce, pdata->mmc_cd,
-				ret);
-
-	twl_gpiochip.base = pdata->gpio_base;
+	twl_gpiochip.base = -1;
 	twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
 	twl_gpiochip.dev = &pdev->dev;
 
-	/* NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE,
-	 * is (still) clear if use_leds is set.
-	 */
-	if (pdata->use_leds)
-		twl_gpiochip.ngpio += 2;
+	if (pdata) {
+		twl_gpiochip.base = pdata->gpio_base;
+
+		/*
+		 * NOTE:  boards may waste power if they don't set pullups
+		 * and pulldowns correctly ... default for non-ULPI pins is
+		 * pulldown, and some other pins may have external pullups
+		 * or pulldowns.  Careful!
+		 */
+		ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
+		if (ret)
+			dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
+					pdata->pullups, pdata->pulldowns,
+					ret);
+
+		ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd);
+		if (ret)
+			dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n",
+					pdata->debounce, pdata->mmc_cd,
+					ret);
+
+		/*
+		 * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE,
+		 * is (still) clear if use_leds is set.
+		 */
+		if (pdata->use_leds)
+			twl_gpiochip.ngpio += 2;
+	}
 
 	ret = gpiochip_add(&twl_gpiochip);
 	if (ret < 0) {
-		dev_err(&pdev->dev,
-				"could not register gpiochip, %d\n",
-				ret);
+		dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
 		twl_gpiochip.ngpio = 0;
 		gpio_twl4030_remove(pdev);
-	} else if (pdata->setup) {
+	} else if (pdata && pdata->setup) {
 		int status;
 
 		status = pdata->setup(&pdev->dev,
@@ -465,7 +479,7 @@
 	struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
 	int status;
 
-	if (pdata->teardown) {
+	if (pdata && pdata->teardown) {
 		status = pdata->teardown(&pdev->dev,
 				pdata->gpio_base, TWL4030_GPIO_MAX);
 		if (status) {
@@ -486,12 +500,21 @@
 	return -EIO;
 }
 
+static const struct of_device_id twl_gpio_match[] = {
+	{ .compatible = "ti,twl4030-gpio", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, twl_gpio_match);
+
 /* Note:  this hardware lives inside an I2C-based multi-function device. */
 MODULE_ALIAS("platform:twl4030_gpio");
 
 static struct platform_driver gpio_twl4030_driver = {
-	.driver.name	= "twl4030_gpio",
-	.driver.owner	= THIS_MODULE,
+	.driver = {
+		.name	= "twl4030_gpio",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(twl_gpio_match),
+	},
 	.probe		= gpio_twl4030_probe,
 	.remove		= gpio_twl4030_remove,
 };
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 17fdf4b..5a75510 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -58,6 +58,8 @@
 #define FLAG_TRIG_FALL	5	/* trigger on falling edge */
 #define FLAG_TRIG_RISE	6	/* trigger on rising edge */
 #define FLAG_ACTIVE_LOW	7	/* sysfs value has active low */
+#define FLAG_OPEN_DRAIN	8	/* Gpio is open drain type */
+#define FLAG_OPEN_SOURCE 9	/* Gpio is open source type */
 
 #define ID_SHIFT	16	/* add new flags before this one */
 
@@ -873,6 +875,7 @@
 {
 	struct gpio_desc	*desc;
 	int			status = 0;
+	struct device		*dev = NULL;
 
 	if (!gpio_is_valid(gpio)) {
 		status = -EINVAL;
@@ -884,19 +887,20 @@
 	desc = &gpio_desc[gpio];
 
 	if (test_bit(FLAG_EXPORT, &desc->flags)) {
-		struct device	*dev = NULL;
 
 		dev = class_find_device(&gpio_class, NULL, desc, match_export);
 		if (dev) {
 			gpio_setup_irq(desc, dev, 0);
 			clear_bit(FLAG_EXPORT, &desc->flags);
-			put_device(dev);
-			device_unregister(dev);
 		} else
 			status = -ENODEV;
 	}
 
 	mutex_unlock(&sysfs_lock);
+	if (dev) {
+		device_unregister(dev);
+		put_device(dev);
+	}
 done:
 	if (status)
 		pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
@@ -1150,8 +1154,9 @@
  * non-zero, this function will return to the caller and not iterate over any
  * more gpio_chips.
  */
-struct gpio_chip *gpiochip_find(void *data,
-				int (*match)(struct gpio_chip *chip, void *data))
+struct gpio_chip *gpiochip_find(const void *data,
+				int (*match)(struct gpio_chip *chip,
+					     const void *data))
 {
 	struct gpio_chip *chip = NULL;
 	unsigned long flags;
@@ -1261,6 +1266,8 @@
 		module_put(desc->chip->owner);
 		clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
 		clear_bit(FLAG_REQUESTED, &desc->flags);
+		clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
+		clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
 	} else
 		WARN_ON(extra_checks);
 
@@ -1282,6 +1289,12 @@
 	if (err)
 		return err;
 
+	if (flags & GPIOF_OPEN_DRAIN)
+		set_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags);
+
+	if (flags & GPIOF_OPEN_SOURCE)
+		set_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags);
+
 	if (flags & GPIOF_DIR_IN)
 		err = gpio_direction_input(gpio);
 	else
@@ -1431,6 +1444,14 @@
 	struct gpio_desc	*desc = &gpio_desc[gpio];
 	int			status = -EINVAL;
 
+	/* Open drain pin should not be driven to 1 */
+	if (value && test_bit(FLAG_OPEN_DRAIN,  &desc->flags))
+		return gpio_direction_input(gpio);
+
+	/* Open source pin should not be driven to 0 */
+	if (!value && test_bit(FLAG_OPEN_SOURCE,  &desc->flags))
+		return gpio_direction_input(gpio);
+
 	spin_lock_irqsave(&gpio_lock, flags);
 
 	if (!gpio_is_valid(gpio))
@@ -1560,6 +1581,7 @@
 	int value;
 
 	chip = gpio_to_chip(gpio);
+	/* Should be using gpio_get_value_cansleep() */
 	WARN_ON(chip->can_sleep);
 	value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
 	trace_gpio_value(gpio, 1, value);
@@ -1567,6 +1589,57 @@
 }
 EXPORT_SYMBOL_GPL(__gpio_get_value);
 
+/*
+ *  _gpio_set_open_drain_value() - Set the open drain gpio's value.
+ * @gpio: Gpio whose state need to be set.
+ * @chip: Gpio chip.
+ * @value: Non-zero for setting it HIGH otherise it will set to LOW.
+ */
+static void _gpio_set_open_drain_value(unsigned gpio,
+			struct gpio_chip *chip, int value)
+{
+	int err = 0;
+	if (value) {
+		err = chip->direction_input(chip, gpio - chip->base);
+		if (!err)
+			clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+	} else {
+		err = chip->direction_output(chip, gpio - chip->base, 0);
+		if (!err)
+			set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+	}
+	trace_gpio_direction(gpio, value, err);
+	if (err < 0)
+		pr_err("%s: Error in set_value for open drain gpio%d err %d\n",
+					__func__, gpio, err);
+}
+
+/*
+ *  _gpio_set_open_source() - Set the open source gpio's value.
+ * @gpio: Gpio whose state need to be set.
+ * @chip: Gpio chip.
+ * @value: Non-zero for setting it HIGH otherise it will set to LOW.
+ */
+static void _gpio_set_open_source_value(unsigned gpio,
+			struct gpio_chip *chip, int value)
+{
+	int err = 0;
+	if (value) {
+		err = chip->direction_output(chip, gpio - chip->base, 1);
+		if (!err)
+			set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+	} else {
+		err = chip->direction_input(chip, gpio - chip->base);
+		if (!err)
+			clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+	}
+	trace_gpio_direction(gpio, !value, err);
+	if (err < 0)
+		pr_err("%s: Error in set_value for open source gpio%d err %d\n",
+					__func__, gpio, err);
+}
+
+
 /**
  * __gpio_set_value() - assign a gpio's value
  * @gpio: gpio whose value will be assigned
@@ -1581,9 +1654,15 @@
 	struct gpio_chip	*chip;
 
 	chip = gpio_to_chip(gpio);
+	/* Should be using gpio_set_value_cansleep() */
 	WARN_ON(chip->can_sleep);
 	trace_gpio_value(gpio, 0, value);
-	chip->set(chip, gpio - chip->base, value);
+	if (test_bit(FLAG_OPEN_DRAIN,  &gpio_desc[gpio].flags))
+		_gpio_set_open_drain_value(gpio, chip, value);
+	else if (test_bit(FLAG_OPEN_SOURCE,  &gpio_desc[gpio].flags))
+		_gpio_set_open_source_value(gpio, chip, value);
+	else
+		chip->set(chip, gpio - chip->base, value);
 }
 EXPORT_SYMBOL_GPL(__gpio_set_value);
 
@@ -1650,7 +1729,12 @@
 	might_sleep_if(extra_checks);
 	chip = gpio_to_chip(gpio);
 	trace_gpio_value(gpio, 0, value);
-	chip->set(chip, gpio - chip->base, value);
+	if (test_bit(FLAG_OPEN_DRAIN,  &gpio_desc[gpio].flags))
+		_gpio_set_open_drain_value(gpio, chip, value);
+	else if (test_bit(FLAG_OPEN_SOURCE,  &gpio_desc[gpio].flags))
+		_gpio_set_open_source_value(gpio, chip, value);
+	else
+		chip->set(chip, gpio - chip->base, value);
 }
 EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
 
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 2418429..e354bc0 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -9,6 +9,7 @@
 	depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU
 	select I2C
 	select I2C_ALGOBIT
+	select DMA_SHARED_BUFFER
 	help
 	  Kernel-level support for the Direct Rendering Infrastructure (DRI)
 	  introduced in XFree86 4.0. If you say Y here, you need to select
@@ -18,6 +19,11 @@
 	  details.  You should also select and configure AGP
 	  (/dev/agpgart) support if it is available for your platform.
 
+config DRM_USB
+	tristate
+	depends on DRM
+	select USB
+
 config DRM_KMS_HELPER
 	tristate
 	depends on DRM
@@ -27,6 +33,18 @@
 	help
 	  FB and CRTC helpers for KMS drivers.
 
+config DRM_LOAD_EDID_FIRMWARE
+	bool "Allow to specify an EDID data set instead of probing for it"
+	depends on DRM_KMS_HELPER
+	help
+	  Say Y here, if you want to use EDID data to be loaded from the
+	  /lib/firmware directory or one of the provided built-in
+	  data sets. This may be necessary, if the graphics adapter or
+	  monitor are unable to provide appropriate EDID data. Since this
+	  feature is provided as a workaround for broken hardware, the
+	  default case is N. Details and instructions how to build your own
+	  EDID data are given in Documentation/EDID/HOWTO.txt.
+
 config DRM_TTM
 	tristate
 	depends on DRM
@@ -71,6 +89,8 @@
 
 source "drivers/gpu/drm/radeon/Kconfig"
 
+source "drivers/gpu/drm/nouveau/Kconfig"
+
 config DRM_I810
 	tristate "Intel I810"
 	# !PREEMPT because of missing ioctl locking
@@ -165,3 +185,4 @@
 
 source "drivers/gpu/drm/gma500/Kconfig"
 
+source "drivers/gpu/drm/udl/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 0cde1b8..c20da5b 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -12,17 +12,21 @@
 		drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \
 		drm_crtc.o drm_modes.o drm_edid.o \
 		drm_info.o drm_debugfs.o drm_encoder_slave.o \
-		drm_trace_points.o drm_global.o drm_usb.o
+		drm_trace_points.o drm_global.o drm_prime.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 
+drm-usb-y   := drm_usb.o
+
 drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o drm_dp_i2c_helper.o
+drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
 
 obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
 
 CFLAGS_drm_trace_points.o := -I$(src)
 
 obj-$(CONFIG_DRM)	+= drm.o
+obj-$(CONFIG_DRM_USB)   += drm_usb.o
 obj-$(CONFIG_DRM_TTM)	+= ttm/
 obj-$(CONFIG_DRM_TDFX)	+= tdfx/
 obj-$(CONFIG_DRM_R128)	+= r128/
@@ -37,4 +41,5 @@
 obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
 obj-$(CONFIG_DRM_EXYNOS) +=exynos/
 obj-$(CONFIG_DRM_GMA500) += gma500/
+obj-$(CONFIG_DRM_UDL) += udl/
 obj-y			+= i2c/
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 5e818a8..d3aaeb6 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -38,11 +38,6 @@
 #include "drm_edid.h"
 #include "drm_fourcc.h"
 
-struct drm_prop_enum_list {
-	int type;
-	char *name;
-};
-
 /* Avoid boilerplate.  I'm tired of typing. */
 #define DRM_ENUM_NAME_FN(fnname, list)				\
 	char *fnname(int val)					\
@@ -298,9 +293,8 @@
 	int ret;
 
 	ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
-	if (ret) {
+	if (ret)
 		return ret;
-	}
 
 	fb->dev = dev;
 	fb->funcs = funcs;
@@ -370,19 +364,31 @@
  * Caller must hold mode config lock.
  *
  * Inits a new object created as base part of an driver crtc object.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure.
  */
-void drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 		   const struct drm_crtc_funcs *funcs)
 {
+	int ret;
+
 	crtc->dev = dev;
 	crtc->funcs = funcs;
 
 	mutex_lock(&dev->mode_config.mutex);
-	drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
+
+	ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
+	if (ret)
+		goto out;
 
 	list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
 	dev->mode_config.num_crtc++;
+
+ out:
 	mutex_unlock(&dev->mode_config.mutex);
+
+	return ret;
 }
 EXPORT_SYMBOL(drm_crtc_init);
 
@@ -442,7 +448,7 @@
 		     struct drm_display_mode *mode)
 {
 	list_del(&mode->head);
-	kfree(mode);
+	drm_mode_destroy(connector->dev, mode);
 }
 EXPORT_SYMBOL(drm_mode_remove);
 
@@ -454,21 +460,29 @@
  * @name: user visible name of the connector
  *
  * LOCKING:
- * Caller must hold @dev's mode_config lock.
+ * Takes mode config lock.
  *
  * Initialises a preallocated connector. Connectors should be
  * subclassed as part of driver connector objects.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure.
  */
-void drm_connector_init(struct drm_device *dev,
-		     struct drm_connector *connector,
-		     const struct drm_connector_funcs *funcs,
-		     int connector_type)
+int drm_connector_init(struct drm_device *dev,
+		       struct drm_connector *connector,
+		       const struct drm_connector_funcs *funcs,
+		       int connector_type)
 {
+	int ret;
+
 	mutex_lock(&dev->mode_config.mutex);
 
+	ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
+	if (ret)
+		goto out;
+
 	connector->dev = dev;
 	connector->funcs = funcs;
-	drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
 	connector->connector_type = connector_type;
 	connector->connector_type_id =
 		++drm_connector_enum_list[connector_type].count; /* TODO */
@@ -488,7 +502,10 @@
 	drm_connector_attach_property(connector,
 				      dev->mode_config.dpms_property, 0);
 
+ out:
 	mutex_unlock(&dev->mode_config.mutex);
+
+	return ret;
 }
 EXPORT_SYMBOL(drm_connector_init);
 
@@ -497,7 +514,7 @@
  * @connector: connector to cleanup
  *
  * LOCKING:
- * Caller must hold @dev's mode_config lock.
+ * Takes mode config lock.
  *
  * Cleans up the connector but doesn't free the object.
  */
@@ -523,23 +540,41 @@
 }
 EXPORT_SYMBOL(drm_connector_cleanup);
 
-void drm_encoder_init(struct drm_device *dev,
+void drm_connector_unplug_all(struct drm_device *dev)
+{
+	struct drm_connector *connector;
+
+	/* taking the mode config mutex ends up in a clash with sysfs */
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+		drm_sysfs_connector_remove(connector);
+
+}
+EXPORT_SYMBOL(drm_connector_unplug_all);
+
+int drm_encoder_init(struct drm_device *dev,
 		      struct drm_encoder *encoder,
 		      const struct drm_encoder_funcs *funcs,
 		      int encoder_type)
 {
+	int ret;
+
 	mutex_lock(&dev->mode_config.mutex);
 
-	encoder->dev = dev;
+	ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
+	if (ret)
+		goto out;
 
-	drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
+	encoder->dev = dev;
 	encoder->encoder_type = encoder_type;
 	encoder->funcs = funcs;
 
 	list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
 	dev->mode_config.num_encoder++;
 
+ out:
 	mutex_unlock(&dev->mode_config.mutex);
+
+	return ret;
 }
 EXPORT_SYMBOL(drm_encoder_init);
 
@@ -560,18 +595,23 @@
 		   const uint32_t *formats, uint32_t format_count,
 		   bool priv)
 {
+	int ret;
+
 	mutex_lock(&dev->mode_config.mutex);
 
+	ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
+	if (ret)
+		goto out;
+
 	plane->dev = dev;
-	drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
 	plane->funcs = funcs;
 	plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
 				      GFP_KERNEL);
 	if (!plane->format_types) {
 		DRM_DEBUG_KMS("out of memory when allocating plane\n");
 		drm_mode_object_put(dev, &plane->base);
-		mutex_unlock(&dev->mode_config.mutex);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto out;
 	}
 
 	memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
@@ -589,9 +629,10 @@
 		INIT_LIST_HEAD(&plane->head);
 	}
 
+ out:
 	mutex_unlock(&dev->mode_config.mutex);
 
-	return 0;
+	return ret;
 }
 EXPORT_SYMBOL(drm_plane_init);
 
@@ -631,7 +672,11 @@
 	if (!nmode)
 		return NULL;
 
-	drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE);
+	if (drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) {
+		kfree(nmode);
+		return NULL;
+	}
+
 	return nmode;
 }
 EXPORT_SYMBOL(drm_mode_create);
@@ -648,6 +693,9 @@
  */
 void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
 {
+	if (!mode)
+		return;
+
 	drm_mode_object_put(dev, &mode->base);
 
 	kfree(mode);
@@ -658,7 +706,6 @@
 {
 	struct drm_property *edid;
 	struct drm_property *dpms;
-	int i;
 
 	/*
 	 * Standard properties (apply to all connectors)
@@ -668,11 +715,9 @@
 				   "EDID", 0);
 	dev->mode_config.edid_property = edid;
 
-	dpms = drm_property_create(dev, DRM_MODE_PROP_ENUM,
-				   "DPMS", ARRAY_SIZE(drm_dpms_enum_list));
-	for (i = 0; i < ARRAY_SIZE(drm_dpms_enum_list); i++)
-		drm_property_add_enum(dpms, i, drm_dpms_enum_list[i].type,
-				      drm_dpms_enum_list[i].name);
+	dpms = drm_property_create_enum(dev, 0,
+				   "DPMS", drm_dpms_enum_list,
+				   ARRAY_SIZE(drm_dpms_enum_list));
 	dev->mode_config.dpms_property = dpms;
 
 	return 0;
@@ -688,30 +733,21 @@
 {
 	struct drm_property *dvi_i_selector;
 	struct drm_property *dvi_i_subconnector;
-	int i;
 
 	if (dev->mode_config.dvi_i_select_subconnector_property)
 		return 0;
 
 	dvi_i_selector =
-		drm_property_create(dev, DRM_MODE_PROP_ENUM,
+		drm_property_create_enum(dev, 0,
 				    "select subconnector",
+				    drm_dvi_i_select_enum_list,
 				    ARRAY_SIZE(drm_dvi_i_select_enum_list));
-	for (i = 0; i < ARRAY_SIZE(drm_dvi_i_select_enum_list); i++)
-		drm_property_add_enum(dvi_i_selector, i,
-				      drm_dvi_i_select_enum_list[i].type,
-				      drm_dvi_i_select_enum_list[i].name);
 	dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector;
 
-	dvi_i_subconnector =
-		drm_property_create(dev, DRM_MODE_PROP_ENUM |
-				    DRM_MODE_PROP_IMMUTABLE,
+	dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
 				    "subconnector",
+				    drm_dvi_i_subconnector_enum_list,
 				    ARRAY_SIZE(drm_dvi_i_subconnector_enum_list));
-	for (i = 0; i < ARRAY_SIZE(drm_dvi_i_subconnector_enum_list); i++)
-		drm_property_add_enum(dvi_i_subconnector, i,
-				      drm_dvi_i_subconnector_enum_list[i].type,
-				      drm_dvi_i_subconnector_enum_list[i].name);
 	dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector;
 
 	return 0;
@@ -742,51 +778,33 @@
 	/*
 	 * Basic connector properties
 	 */
-	tv_selector = drm_property_create(dev, DRM_MODE_PROP_ENUM,
+	tv_selector = drm_property_create_enum(dev, 0,
 					  "select subconnector",
+					  drm_tv_select_enum_list,
 					  ARRAY_SIZE(drm_tv_select_enum_list));
-	for (i = 0; i < ARRAY_SIZE(drm_tv_select_enum_list); i++)
-		drm_property_add_enum(tv_selector, i,
-				      drm_tv_select_enum_list[i].type,
-				      drm_tv_select_enum_list[i].name);
 	dev->mode_config.tv_select_subconnector_property = tv_selector;
 
 	tv_subconnector =
-		drm_property_create(dev, DRM_MODE_PROP_ENUM |
-				    DRM_MODE_PROP_IMMUTABLE, "subconnector",
+		drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+				    "subconnector",
+				    drm_tv_subconnector_enum_list,
 				    ARRAY_SIZE(drm_tv_subconnector_enum_list));
-	for (i = 0; i < ARRAY_SIZE(drm_tv_subconnector_enum_list); i++)
-		drm_property_add_enum(tv_subconnector, i,
-				      drm_tv_subconnector_enum_list[i].type,
-				      drm_tv_subconnector_enum_list[i].name);
 	dev->mode_config.tv_subconnector_property = tv_subconnector;
 
 	/*
 	 * Other, TV specific properties: margins & TV modes.
 	 */
 	dev->mode_config.tv_left_margin_property =
-		drm_property_create(dev, DRM_MODE_PROP_RANGE,
-				    "left margin", 2);
-	dev->mode_config.tv_left_margin_property->values[0] = 0;
-	dev->mode_config.tv_left_margin_property->values[1] = 100;
+		drm_property_create_range(dev, 0, "left margin", 0, 100);
 
 	dev->mode_config.tv_right_margin_property =
-		drm_property_create(dev, DRM_MODE_PROP_RANGE,
-				    "right margin", 2);
-	dev->mode_config.tv_right_margin_property->values[0] = 0;
-	dev->mode_config.tv_right_margin_property->values[1] = 100;
+		drm_property_create_range(dev, 0, "right margin", 0, 100);
 
 	dev->mode_config.tv_top_margin_property =
-		drm_property_create(dev, DRM_MODE_PROP_RANGE,
-				    "top margin", 2);
-	dev->mode_config.tv_top_margin_property->values[0] = 0;
-	dev->mode_config.tv_top_margin_property->values[1] = 100;
+		drm_property_create_range(dev, 0, "top margin", 0, 100);
 
 	dev->mode_config.tv_bottom_margin_property =
-		drm_property_create(dev, DRM_MODE_PROP_RANGE,
-				    "bottom margin", 2);
-	dev->mode_config.tv_bottom_margin_property->values[0] = 0;
-	dev->mode_config.tv_bottom_margin_property->values[1] = 100;
+		drm_property_create_range(dev, 0, "bottom margin", 0, 100);
 
 	dev->mode_config.tv_mode_property =
 		drm_property_create(dev, DRM_MODE_PROP_ENUM,
@@ -796,40 +814,22 @@
 				      i, modes[i]);
 
 	dev->mode_config.tv_brightness_property =
-		drm_property_create(dev, DRM_MODE_PROP_RANGE,
-				    "brightness", 2);
-	dev->mode_config.tv_brightness_property->values[0] = 0;
-	dev->mode_config.tv_brightness_property->values[1] = 100;
+		drm_property_create_range(dev, 0, "brightness", 0, 100);
 
 	dev->mode_config.tv_contrast_property =
-		drm_property_create(dev, DRM_MODE_PROP_RANGE,
-				    "contrast", 2);
-	dev->mode_config.tv_contrast_property->values[0] = 0;
-	dev->mode_config.tv_contrast_property->values[1] = 100;
+		drm_property_create_range(dev, 0, "contrast", 0, 100);
 
 	dev->mode_config.tv_flicker_reduction_property =
-		drm_property_create(dev, DRM_MODE_PROP_RANGE,
-				    "flicker reduction", 2);
-	dev->mode_config.tv_flicker_reduction_property->values[0] = 0;
-	dev->mode_config.tv_flicker_reduction_property->values[1] = 100;
+		drm_property_create_range(dev, 0, "flicker reduction", 0, 100);
 
 	dev->mode_config.tv_overscan_property =
-		drm_property_create(dev, DRM_MODE_PROP_RANGE,
-				    "overscan", 2);
-	dev->mode_config.tv_overscan_property->values[0] = 0;
-	dev->mode_config.tv_overscan_property->values[1] = 100;
+		drm_property_create_range(dev, 0, "overscan", 0, 100);
 
 	dev->mode_config.tv_saturation_property =
-		drm_property_create(dev, DRM_MODE_PROP_RANGE,
-				    "saturation", 2);
-	dev->mode_config.tv_saturation_property->values[0] = 0;
-	dev->mode_config.tv_saturation_property->values[1] = 100;
+		drm_property_create_range(dev, 0, "saturation", 0, 100);
 
 	dev->mode_config.tv_hue_property =
-		drm_property_create(dev, DRM_MODE_PROP_RANGE,
-				    "hue", 2);
-	dev->mode_config.tv_hue_property->values[0] = 0;
-	dev->mode_config.tv_hue_property->values[1] = 100;
+		drm_property_create_range(dev, 0, "hue", 0, 100);
 
 	return 0;
 }
@@ -845,18 +845,14 @@
 int drm_mode_create_scaling_mode_property(struct drm_device *dev)
 {
 	struct drm_property *scaling_mode;
-	int i;
 
 	if (dev->mode_config.scaling_mode_property)
 		return 0;
 
 	scaling_mode =
-		drm_property_create(dev, DRM_MODE_PROP_ENUM, "scaling mode",
+		drm_property_create_enum(dev, 0, "scaling mode",
+				drm_scaling_mode_enum_list,
 				    ARRAY_SIZE(drm_scaling_mode_enum_list));
-	for (i = 0; i < ARRAY_SIZE(drm_scaling_mode_enum_list); i++)
-		drm_property_add_enum(scaling_mode, i,
-				      drm_scaling_mode_enum_list[i].type,
-				      drm_scaling_mode_enum_list[i].name);
 
 	dev->mode_config.scaling_mode_property = scaling_mode;
 
@@ -874,18 +870,14 @@
 int drm_mode_create_dithering_property(struct drm_device *dev)
 {
 	struct drm_property *dithering_mode;
-	int i;
 
 	if (dev->mode_config.dithering_mode_property)
 		return 0;
 
 	dithering_mode =
-		drm_property_create(dev, DRM_MODE_PROP_ENUM, "dithering",
+		drm_property_create_enum(dev, 0, "dithering",
+				drm_dithering_mode_enum_list,
 				    ARRAY_SIZE(drm_dithering_mode_enum_list));
-	for (i = 0; i < ARRAY_SIZE(drm_dithering_mode_enum_list); i++)
-		drm_property_add_enum(dithering_mode, i,
-				      drm_dithering_mode_enum_list[i].type,
-				      drm_dithering_mode_enum_list[i].name);
 	dev->mode_config.dithering_mode_property = dithering_mode;
 
 	return 0;
@@ -902,20 +894,15 @@
 int drm_mode_create_dirty_info_property(struct drm_device *dev)
 {
 	struct drm_property *dirty_info;
-	int i;
 
 	if (dev->mode_config.dirty_info_property)
 		return 0;
 
 	dirty_info =
-		drm_property_create(dev, DRM_MODE_PROP_ENUM |
-				    DRM_MODE_PROP_IMMUTABLE,
+		drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
 				    "dirty",
+				    drm_dirty_info_enum_list,
 				    ARRAY_SIZE(drm_dirty_info_enum_list));
-	for (i = 0; i < ARRAY_SIZE(drm_dirty_info_enum_list); i++)
-		drm_property_add_enum(dirty_info, i,
-				      drm_dirty_info_enum_list[i].type,
-				      drm_dirty_info_enum_list[i].name);
 	dev->mode_config.dirty_info_property = dirty_info;
 
 	return 0;
@@ -999,6 +986,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
 
 /**
  * drm_mode_config_cleanup - free up DRM mode_config info
@@ -1048,6 +1036,9 @@
 				 head) {
 		plane->funcs->destroy(plane);
 	}
+
+	idr_remove_all(&dev->mode_config.crtc_idr);
+	idr_destroy(&dev->mode_config.crtc_idr);
 }
 EXPORT_SYMBOL(drm_mode_config_cleanup);
 
@@ -1062,9 +1053,16 @@
  * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
  * the user.
  */
-void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
-			       struct drm_display_mode *in)
+static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
+				      const struct drm_display_mode *in)
 {
+	WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
+	     in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
+	     in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX ||
+	     in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX ||
+	     in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX,
+	     "timing values too large for mode info\n");
+
 	out->clock = in->clock;
 	out->hdisplay = in->hdisplay;
 	out->hsync_start = in->hsync_start;
@@ -1093,10 +1091,16 @@
  *
  * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to
  * the caller.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
  */
-void drm_crtc_convert_umode(struct drm_display_mode *out,
-			    struct drm_mode_modeinfo *in)
+static int drm_crtc_convert_umode(struct drm_display_mode *out,
+				  const struct drm_mode_modeinfo *in)
 {
+	if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
+		return -ERANGE;
+
 	out->clock = in->clock;
 	out->hdisplay = in->hdisplay;
 	out->hsync_start = in->hsync_start;
@@ -1113,6 +1117,8 @@
 	out->type = in->type;
 	strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
 	out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
+
+	return 0;
 }
 
 /**
@@ -1311,7 +1317,7 @@
  * @arg: arg from ioctl
  *
  * LOCKING:
- * Caller? (FIXME)
+ * Takes mode config lock.
  *
  * Construct a CRTC configuration structure to return to the user.
  *
@@ -1371,7 +1377,7 @@
  * @arg: arg from ioctl
  *
  * LOCKING:
- * Caller? (FIXME)
+ * Takes mode config lock.
  *
  * Construct a connector configuration structure to return to the user.
  *
@@ -1553,6 +1559,9 @@
  * @data: ioctl data
  * @file_priv: DRM file info
  *
+ * LOCKING:
+ * Takes mode config lock.
+ *
  * Return an plane count and set of IDs.
  */
 int drm_mode_getplane_res(struct drm_device *dev, void *data,
@@ -1599,6 +1608,9 @@
  * @data: ioctl data
  * @file_priv: DRM file info
  *
+ * LOCKING:
+ * Takes mode config lock.
+ *
  * Return plane info, including formats supported, gamma size, any
  * current fb, etc.
  */
@@ -1664,6 +1676,9 @@
  * @data: ioctl data*
  * @file_prive: DRM file info
  *
+ * LOCKING:
+ * Takes mode config lock.
+ *
  * Set plane info, including placement, fb, scaling, and other factors.
  * Or pass a NULL fb to disable.
  */
@@ -1794,7 +1809,7 @@
  * @arg: arg from ioctl
  *
  * LOCKING:
- * Caller? (FIXME)
+ * Takes mode config lock.
  *
  * Build a new CRTC configuration based on user request.
  *
@@ -1809,7 +1824,7 @@
 	struct drm_mode_config *config = &dev->mode_config;
 	struct drm_mode_crtc *crtc_req = data;
 	struct drm_mode_object *obj;
-	struct drm_crtc *crtc, *crtcfb;
+	struct drm_crtc *crtc;
 	struct drm_connector **connector_set = NULL, *connector;
 	struct drm_framebuffer *fb = NULL;
 	struct drm_display_mode *mode = NULL;
@@ -1821,6 +1836,10 @@
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
+	/* For some reason crtc x/y offsets are signed internally. */
+	if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX)
+		return -ERANGE;
+
 	mutex_lock(&dev->mode_config.mutex);
 	obj = drm_mode_object_find(dev, crtc_req->crtc_id,
 				   DRM_MODE_OBJECT_CRTC);
@@ -1836,14 +1855,12 @@
 		/* If we have a mode we need a framebuffer. */
 		/* If we pass -1, set the mode with the currently bound fb */
 		if (crtc_req->fb_id == -1) {
-			list_for_each_entry(crtcfb,
-					    &dev->mode_config.crtc_list, head) {
-				if (crtcfb == crtc) {
-					DRM_DEBUG_KMS("Using current fb for "
-							"setmode\n");
-					fb = crtc->fb;
-				}
+			if (!crtc->fb) {
+				DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
+				ret = -EINVAL;
+				goto out;
 			}
+			fb = crtc->fb;
 		} else {
 			obj = drm_mode_object_find(dev, crtc_req->fb_id,
 						   DRM_MODE_OBJECT_FB);
@@ -1857,8 +1874,30 @@
 		}
 
 		mode = drm_mode_create(dev);
-		drm_crtc_convert_umode(mode, &crtc_req->mode);
+		if (!mode) {
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		ret = drm_crtc_convert_umode(mode, &crtc_req->mode);
+		if (ret) {
+			DRM_DEBUG_KMS("Invalid mode\n");
+			goto out;
+		}
+
 		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+
+		if (mode->hdisplay > fb->width ||
+		    mode->vdisplay > fb->height ||
+		    crtc_req->x > fb->width - mode->hdisplay ||
+		    crtc_req->y > fb->height - mode->vdisplay) {
+			DRM_DEBUG_KMS("Invalid CRTC viewport %ux%u+%u+%u for fb size %ux%u.\n",
+				      mode->hdisplay, mode->vdisplay,
+				      crtc_req->x, crtc_req->y,
+				      fb->width, fb->height);
+			ret = -ENOSPC;
+			goto out;
+		}
 	}
 
 	if (crtc_req->count_connectors == 0 && mode) {
@@ -1926,6 +1965,7 @@
 
 out:
 	kfree(connector_set);
+	drm_mode_destroy(dev, mode);
 	mutex_unlock(&dev->mode_config.mutex);
 	return ret;
 }
@@ -2275,7 +2315,7 @@
  * @arg: arg from ioctl
  *
  * LOCKING:
- * Caller? (FIXME)
+ * Takes mode config lock.
  *
  * Lookup the FB given its ID and return info about it.
  *
@@ -2424,38 +2464,48 @@
  *
  * Add @mode to @connector's user mode list.
  */
-static int drm_mode_attachmode(struct drm_device *dev,
-			       struct drm_connector *connector,
-			       struct drm_display_mode *mode)
+static void drm_mode_attachmode(struct drm_device *dev,
+				struct drm_connector *connector,
+				struct drm_display_mode *mode)
 {
-	int ret = 0;
-
 	list_add_tail(&mode->head, &connector->user_modes);
-	return ret;
 }
 
 int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc,
-			     struct drm_display_mode *mode)
+			     const struct drm_display_mode *mode)
 {
 	struct drm_connector *connector;
 	int ret = 0;
-	struct drm_display_mode *dup_mode;
-	int need_dup = 0;
+	struct drm_display_mode *dup_mode, *next;
+	LIST_HEAD(list);
+
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		if (!connector->encoder)
-			break;
+			continue;
 		if (connector->encoder->crtc == crtc) {
-			if (need_dup)
-				dup_mode = drm_mode_duplicate(dev, mode);
-			else
-				dup_mode = mode;
-			ret = drm_mode_attachmode(dev, connector, dup_mode);
-			if (ret)
-				return ret;
-			need_dup = 1;
+			dup_mode = drm_mode_duplicate(dev, mode);
+			if (!dup_mode) {
+				ret = -ENOMEM;
+				goto out;
+			}
+			list_add_tail(&dup_mode->head, &list);
 		}
 	}
-	return 0;
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		if (!connector->encoder)
+			continue;
+		if (connector->encoder->crtc == crtc)
+			list_move_tail(list.next, &connector->user_modes);
+	}
+
+	WARN_ON(!list_empty(&list));
+
+ out:
+	list_for_each_entry_safe(dup_mode, next, &list, head)
+		drm_mode_destroy(dev, dup_mode);
+
+	return ret;
 }
 EXPORT_SYMBOL(drm_mode_attachmode_crtc);
 
@@ -2534,9 +2584,14 @@
 		goto out;
 	}
 
-	drm_crtc_convert_umode(mode, umode);
+	ret = drm_crtc_convert_umode(mode, umode);
+	if (ret) {
+		DRM_DEBUG_KMS("Invalid mode\n");
+		drm_mode_destroy(dev, mode);
+		goto out;
+	}
 
-	ret = drm_mode_attachmode(dev, connector, mode);
+	drm_mode_attachmode(dev, connector, mode);
 out:
 	mutex_unlock(&dev->mode_config.mutex);
 	return ret;
@@ -2577,7 +2632,12 @@
 	}
 	connector = obj_to_connector(obj);
 
-	drm_crtc_convert_umode(&mode, umode);
+	ret = drm_crtc_convert_umode(&mode, umode);
+	if (ret) {
+		DRM_DEBUG_KMS("Invalid mode\n");
+		goto out;
+	}
+
 	ret = drm_mode_detachmode(dev, connector, &mode);
 out:
 	mutex_unlock(&dev->mode_config.mutex);
@@ -2588,6 +2648,7 @@
 					 const char *name, int num_values)
 {
 	struct drm_property *property = NULL;
+	int ret;
 
 	property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
 	if (!property)
@@ -2599,7 +2660,10 @@
 			goto fail;
 	}
 
-	drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
+	ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
+	if (ret)
+		goto fail;
+
 	property->flags = flags;
 	property->num_values = num_values;
 	INIT_LIST_HEAD(&property->enum_blob_list);
@@ -2612,11 +2676,59 @@
 	list_add_tail(&property->head, &dev->mode_config.property_list);
 	return property;
 fail:
+	kfree(property->values);
 	kfree(property);
 	return NULL;
 }
 EXPORT_SYMBOL(drm_property_create);
 
+struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
+					 const char *name,
+					 const struct drm_prop_enum_list *props,
+					 int num_values)
+{
+	struct drm_property *property;
+	int i, ret;
+
+	flags |= DRM_MODE_PROP_ENUM;
+
+	property = drm_property_create(dev, flags, name, num_values);
+	if (!property)
+		return NULL;
+
+	for (i = 0; i < num_values; i++) {
+		ret = drm_property_add_enum(property, i,
+				      props[i].type,
+				      props[i].name);
+		if (ret) {
+			drm_property_destroy(dev, property);
+			return NULL;
+		}
+	}
+
+	return property;
+}
+EXPORT_SYMBOL(drm_property_create_enum);
+
+struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
+					 const char *name,
+					 uint64_t min, uint64_t max)
+{
+	struct drm_property *property;
+
+	flags |= DRM_MODE_PROP_RANGE;
+
+	property = drm_property_create(dev, flags, name, 2);
+	if (!property)
+		return NULL;
+
+	property->values[0] = min;
+	property->values[1] = max;
+
+	return property;
+}
+EXPORT_SYMBOL(drm_property_create_range);
+
 int drm_property_add_enum(struct drm_property *property, int index,
 			  uint64_t value, const char *name)
 {
@@ -2828,6 +2940,7 @@
 							  void *data)
 {
 	struct drm_property_blob *blob;
+	int ret;
 
 	if (!length || !data)
 		return NULL;
@@ -2836,13 +2949,16 @@
 	if (!blob)
 		return NULL;
 
-	blob->data = (void *)((char *)blob + sizeof(struct drm_property_blob));
+	ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
+	if (ret) {
+		kfree(blob);
+		return NULL;
+	}
+
 	blob->length = length;
 
 	memcpy(blob->data, data, length);
 
-	drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
-
 	list_add_tail(&blob->head, &dev->mode_config.property_blob_list);
 	return blob;
 }
@@ -3021,7 +3137,7 @@
 }
 EXPORT_SYMBOL(drm_mode_connector_detach_encoder);
 
-bool drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
+int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
 				  int gamma_size)
 {
 	crtc->gamma_size = gamma_size;
@@ -3029,10 +3145,10 @@
 	crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL);
 	if (!crtc->gamma_store) {
 		crtc->gamma_size = 0;
-		return false;
+		return -ENOMEM;
 	}
 
-	return true;
+	return 0;
 }
 EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
 
@@ -3178,6 +3294,18 @@
 		goto out;
 	fb = obj_to_fb(obj);
 
+	if (crtc->mode.hdisplay > fb->width ||
+	    crtc->mode.vdisplay > fb->height ||
+	    crtc->x > fb->width - crtc->mode.hdisplay ||
+	    crtc->y > fb->height - crtc->mode.vdisplay) {
+		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d.\n",
+			      fb->width, fb->height,
+			      crtc->mode.hdisplay, crtc->mode.vdisplay,
+			      crtc->x, crtc->y);
+		ret = -ENOSPC;
+		goto out;
+	}
+
 	if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
 		ret = -ENOMEM;
 		spin_lock_irqsave(&dev->event_lock, flags);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 84a4a80..8111889 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -37,6 +37,7 @@
 #include "drm_fourcc.h"
 #include "drm_crtc_helper.h"
 #include "drm_fb_helper.h"
+#include "drm_edid.h"
 
 static bool drm_kms_helper_poll = true;
 module_param_named(poll, drm_kms_helper_poll, bool, 0600);
@@ -44,12 +45,12 @@
 static void drm_mode_validate_flag(struct drm_connector *connector,
 				   int flags)
 {
-	struct drm_display_mode *mode, *t;
+	struct drm_display_mode *mode;
 
 	if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE))
 		return;
 
-	list_for_each_entry_safe(mode, t, &connector->modes, head) {
+	list_for_each_entry(mode, &connector->modes, head) {
 		if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&
 				!(flags & DRM_MODE_FLAG_INTERLACE))
 			mode->status = MODE_NO_INTERLACE;
@@ -87,7 +88,7 @@
 					    uint32_t maxX, uint32_t maxY)
 {
 	struct drm_device *dev = connector->dev;
-	struct drm_display_mode *mode, *t;
+	struct drm_display_mode *mode;
 	struct drm_connector_helper_funcs *connector_funcs =
 		connector->helper_private;
 	int count = 0;
@@ -96,7 +97,7 @@
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
 			drm_get_connector_name(connector));
 	/* set all modes to the unverified state */
-	list_for_each_entry_safe(mode, t, &connector->modes, head)
+	list_for_each_entry(mode, &connector->modes, head)
 		mode->status = MODE_UNVERIFIED;
 
 	if (connector->force) {
@@ -118,7 +119,12 @@
 		goto prune;
 	}
 
-	count = (*connector_funcs->get_modes)(connector);
+#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
+	count = drm_load_edid_firmware(connector);
+	if (count == 0)
+#endif
+		count = (*connector_funcs->get_modes)(connector);
+
 	if (count == 0 && connector->status == connector_status_connected)
 		count = drm_add_modes_noedid(connector, 1024, 768);
 	if (count == 0)
@@ -136,7 +142,7 @@
 		mode_flags |= DRM_MODE_FLAG_DBLSCAN;
 	drm_mode_validate_flag(connector, mode_flags);
 
-	list_for_each_entry_safe(mode, t, &connector->modes, head) {
+	list_for_each_entry(mode, &connector->modes, head) {
 		if (mode->status == MODE_OK)
 			mode->status = connector_funcs->mode_valid(connector,
 								   mode);
@@ -152,7 +158,7 @@
 
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id,
 			drm_get_connector_name(connector));
-	list_for_each_entry_safe(mode, t, &connector->modes, head) {
+	list_for_each_entry(mode, &connector->modes, head) {
 		mode->vrefresh = drm_mode_vrefresh(mode);
 
 		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
@@ -352,6 +358,8 @@
 		return true;
 
 	adjusted_mode = drm_mode_duplicate(dev, mode);
+	if (!adjusted_mode)
+		return false;
 
 	saved_hwmode = crtc->hwmode;
 	saved_mode = crtc->mode;
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index ebf7d3f..6116e3b 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -135,23 +135,27 @@
 	DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED),
 
-	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+
+	DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_UNLOCKED),
+	DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_UNLOCKED),
+
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER|DRM_UNLOCKED),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED),
-	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
@@ -390,6 +394,10 @@
 	unsigned int usize, asize;
 
 	dev = file_priv->minor->dev;
+
+	if (drm_device_is_unplugged(dev))
+		return -ENODEV;
+
 	atomic_inc(&dev->ioctl_count);
 	atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
 	++file_priv->ioctl_count;
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index ece03fc..5a18b0d 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -149,8 +149,7 @@
  * Sanity check the EDID block (base or extension).  Return 0 if the block
  * doesn't check out, or 1 if it's valid.
  */
-static bool
-drm_edid_block_valid(u8 *raw_edid)
+bool drm_edid_block_valid(u8 *raw_edid)
 {
 	int i;
 	u8 csum = 0;
@@ -203,6 +202,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL(drm_edid_block_valid);
 
 /**
  * drm_edid_is_valid - sanity check EDID data
@@ -226,7 +226,6 @@
 }
 EXPORT_SYMBOL(drm_edid_is_valid);
 
-#define DDC_ADDR 0x50
 #define DDC_SEGMENT_ADDR 0x30
 /**
  * Get EDID information via I2C.
@@ -266,6 +265,11 @@
 			}
 		};
 		ret = i2c_transfer(adapter, msgs, 2);
+		if (ret == -ENXIO) {
+			DRM_DEBUG_KMS("drm: skipping non-existent adapter %s\n",
+					adapter->name);
+			break;
+		}
 	} while (ret != 2 && --retries);
 
 	return ret == 2 ? 0 : -1;
@@ -745,7 +749,7 @@
 		 */
 		mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
 		if (drm_mode_hsync(mode) > drm_gtf2_hbreak(edid)) {
-			kfree(mode);
+			drm_mode_destroy(dev, mode);
 			mode = drm_gtf_mode_complex(dev, hsize, vsize,
 						    vrefresh_rate, 0, 0,
 						    drm_gtf2_m(edid),
diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c
new file mode 100644
index 0000000..da9acba
--- /dev/null
+++ b/drivers/gpu/drm/drm_edid_load.c
@@ -0,0 +1,250 @@
+/*
+   drm_edid_load.c: use a built-in EDID data set or load it via the firmware
+		    interface
+
+   Copyright (C) 2012 Carsten Emde <C.Emde@osadl.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.
+
+   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/module.h>
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "drm_edid.h"
+
+static char edid_firmware[PATH_MAX];
+module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
+MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
+	"from built-in data or /lib/firmware instead. ");
+
+#define GENERIC_EDIDS 4
+static char *generic_edid_name[GENERIC_EDIDS] = {
+	"edid/1024x768.bin",
+	"edid/1280x1024.bin",
+	"edid/1680x1050.bin",
+	"edid/1920x1080.bin",
+};
+
+static u8 generic_edid[GENERIC_EDIDS][128] = {
+	{
+	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
+	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
+	0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
+	0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
+	0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
+	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
+	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
+	0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
+	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
+	0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
+	},
+	{
+	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
+	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
+	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
+	0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
+	0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
+	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
+	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
+	0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
+	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
+	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
+	},
+	{
+	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
+	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
+	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
+	0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
+	0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
+	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
+	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
+	0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
+	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
+	0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
+	},
+	{
+	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
+	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
+	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
+	0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
+	0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
+	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
+	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
+	0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
+	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
+	0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
+	},
+};
+
+static int edid_load(struct drm_connector *connector, char *name,
+		     char *connector_name)
+{
+	const struct firmware *fw;
+	struct platform_device *pdev;
+	u8 *fwdata = NULL, *edid;
+	int fwsize, expected;
+	int builtin = 0, err = 0;
+	int i, valid_extensions = 0;
+
+	pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
+	if (IS_ERR(pdev)) {
+		DRM_ERROR("Failed to register EDID firmware platform device "
+		    "for connector \"%s\"\n", connector_name);
+		err = -EINVAL;
+		goto out;
+	}
+
+	err = request_firmware(&fw, name, &pdev->dev);
+	platform_device_unregister(pdev);
+
+	if (err) {
+		i = 0;
+		while (i < GENERIC_EDIDS && strcmp(name, generic_edid_name[i]))
+			i++;
+		if (i < GENERIC_EDIDS) {
+			err = 0;
+			builtin = 1;
+			fwdata = generic_edid[i];
+			fwsize = sizeof(generic_edid[i]);
+		}
+	}
+
+	if (err) {
+		DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
+		    name, err);
+		goto out;
+	}
+
+	if (fwdata == NULL) {
+		fwdata = (u8 *) fw->data;
+		fwsize = fw->size;
+	}
+
+	expected = (fwdata[0x7e] + 1) * EDID_LENGTH;
+	if (expected != fwsize) {
+		DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
+		    "(expected %d, got %d)\n", name, expected, (int) fwsize);
+		err = -EINVAL;
+		goto relfw_out;
+	}
+
+	edid = kmalloc(fwsize, GFP_KERNEL);
+	if (edid == NULL) {
+		err = -ENOMEM;
+		goto relfw_out;
+	}
+	memcpy(edid, fwdata, fwsize);
+
+	if (!drm_edid_block_valid(edid)) {
+		DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
+		    name);
+		kfree(edid);
+		err = -EINVAL;
+		goto relfw_out;
+	}
+
+	for (i = 1; i <= edid[0x7e]; i++) {
+		if (i != valid_extensions + 1)
+			memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
+			    edid + i * EDID_LENGTH, EDID_LENGTH);
+		if (drm_edid_block_valid(edid + i * EDID_LENGTH))
+			valid_extensions++;
+	}
+
+	if (valid_extensions != edid[0x7e]) {
+		edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
+		DRM_INFO("Found %d valid extensions instead of %d in EDID data "
+		    "\"%s\" for connector \"%s\"\n", valid_extensions,
+		    edid[0x7e], name, connector_name);
+		edid[0x7e] = valid_extensions;
+		edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
+		    GFP_KERNEL);
+		if (edid == NULL) {
+			err = -ENOMEM;
+			goto relfw_out;
+		}
+	}
+
+	connector->display_info.raw_edid = edid;
+	DRM_INFO("Got %s EDID base block and %d extension%s from "
+	    "\"%s\" for connector \"%s\"\n", builtin ? "built-in" :
+	    "external", valid_extensions, valid_extensions == 1 ? "" : "s",
+	    name, connector_name);
+
+relfw_out:
+	release_firmware(fw);
+
+out:
+	return err;
+}
+
+int drm_load_edid_firmware(struct drm_connector *connector)
+{
+	char *connector_name = drm_get_connector_name(connector);
+	char *edidname = edid_firmware, *last, *colon;
+	int ret = 0;
+
+	if (*edidname == '\0')
+		return ret;
+
+	colon = strchr(edidname, ':');
+	if (colon != NULL) {
+		if (strncmp(connector_name, edidname, colon - edidname))
+			return ret;
+		edidname = colon + 1;
+		if (*edidname == '\0')
+			return ret;
+	}
+
+	last = edidname + strlen(edidname) - 1;
+	if (*last == '\n')
+		*last = '\0';
+
+	ret = edid_load(connector, edidname, connector_name);
+	if (ret)
+		return 0;
+
+	drm_mode_connector_update_edid_property(connector,
+	    (struct edid *) connector->display_info.raw_edid);
+
+	return drm_add_edid_modes(connector, (struct edid *)
+	    connector->display_info.raw_edid);
+}
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index aada26f..a0d6e89 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -306,91 +306,31 @@
 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
 #endif
 
-static void drm_fb_helper_on(struct fb_info *info)
+static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 {
 	struct drm_fb_helper *fb_helper = info->par;
 	struct drm_device *dev = fb_helper->dev;
 	struct drm_crtc *crtc;
-	struct drm_crtc_helper_funcs *crtc_funcs;
 	struct drm_connector *connector;
-	struct drm_encoder *encoder;
 	int i, j;
 
 	/*
-	 * For each CRTC in this fb, turn the crtc on then,
-	 * find all associated encoders and turn them on.
+	 * For each CRTC in this fb, turn the connectors on/off.
 	 */
 	mutex_lock(&dev->mode_config.mutex);
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
-		crtc_funcs = crtc->helper_private;
 
 		if (!crtc->enabled)
 			continue;
 
-		crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
-
-		/* Walk the connectors & encoders on this fb turning them on */
+		/* Walk the connectors & encoders on this fb turning them on/off */
 		for (j = 0; j < fb_helper->connector_count; j++) {
 			connector = fb_helper->connector_info[j]->connector;
-			connector->dpms = DRM_MODE_DPMS_ON;
+			drm_helper_connector_dpms(connector, dpms_mode);
 			drm_connector_property_set_value(connector,
-							 dev->mode_config.dpms_property,
-							 DRM_MODE_DPMS_ON);
+				dev->mode_config.dpms_property, dpms_mode);
 		}
-		/* Found a CRTC on this fb, now find encoders */
-		list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-			if (encoder->crtc == crtc) {
-				struct drm_encoder_helper_funcs *encoder_funcs;
-
-				encoder_funcs = encoder->helper_private;
-				encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
-			}
-		}
-	}
-	mutex_unlock(&dev->mode_config.mutex);
-}
-
-static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
-{
-	struct drm_fb_helper *fb_helper = info->par;
-	struct drm_device *dev = fb_helper->dev;
-	struct drm_crtc *crtc;
-	struct drm_crtc_helper_funcs *crtc_funcs;
-	struct drm_connector *connector;
-	struct drm_encoder *encoder;
-	int i, j;
-
-	/*
-	 * For each CRTC in this fb, find all associated encoders
-	 * and turn them off, then turn off the CRTC.
-	 */
-	mutex_lock(&dev->mode_config.mutex);
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		crtc = fb_helper->crtc_info[i].mode_set.crtc;
-		crtc_funcs = crtc->helper_private;
-
-		if (!crtc->enabled)
-			continue;
-
-		/* Walk the connectors on this fb and mark them off */
-		for (j = 0; j < fb_helper->connector_count; j++) {
-			connector = fb_helper->connector_info[j]->connector;
-			connector->dpms = dpms_mode;
-			drm_connector_property_set_value(connector,
-							 dev->mode_config.dpms_property,
-							 dpms_mode);
-		}
-		/* Found a CRTC on this fb, now find encoders */
-		list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-			if (encoder->crtc == crtc) {
-				struct drm_encoder_helper_funcs *encoder_funcs;
-
-				encoder_funcs = encoder->helper_private;
-				encoder_funcs->dpms(encoder, dpms_mode);
-			}
-		}
-		crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
 	}
 	mutex_unlock(&dev->mode_config.mutex);
 }
@@ -400,23 +340,23 @@
 	switch (blank) {
 	/* Display: On; HSync: On, VSync: On */
 	case FB_BLANK_UNBLANK:
-		drm_fb_helper_on(info);
+		drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON);
 		break;
 	/* Display: Off; HSync: On, VSync: On */
 	case FB_BLANK_NORMAL:
-		drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
+		drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
 		break;
 	/* Display: Off; HSync: Off, VSync: On */
 	case FB_BLANK_HSYNC_SUSPEND:
-		drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
+		drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
 		break;
 	/* Display: Off; HSync: On, VSync: Off */
 	case FB_BLANK_VSYNC_SUSPEND:
-		drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND);
+		drm_fb_helper_dpms(info, DRM_MODE_DPMS_SUSPEND);
 		break;
 	/* Display: Off; HSync: Off, VSync: Off */
 	case FB_BLANK_POWERDOWN:
-		drm_fb_helper_off(info, DRM_MODE_DPMS_OFF);
+		drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
 		break;
 	}
 	return 0;
@@ -430,8 +370,11 @@
 	for (i = 0; i < helper->connector_count; i++)
 		kfree(helper->connector_info[i]);
 	kfree(helper->connector_info);
-	for (i = 0; i < helper->crtc_count; i++)
+	for (i = 0; i < helper->crtc_count; i++) {
 		kfree(helper->crtc_info[i].mode_set.connectors);
+		if (helper->crtc_info[i].mode_set.mode)
+			drm_mode_destroy(helper->dev, helper->crtc_info[i].mode_set.mode);
+	}
 	kfree(helper->crtc_info);
 }
 
@@ -474,11 +417,10 @@
 
 	i = 0;
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		fb_helper->crtc_info[i].crtc_id = crtc->base.id;
 		fb_helper->crtc_info[i].mode_set.crtc = crtc;
 		i++;
 	}
-	fb_helper->conn_limit = max_conn_count;
+
 	return 0;
 out_free:
 	drm_fb_helper_crtc_free(fb_helper);
@@ -617,9 +559,13 @@
 		return -EINVAL;
 
 	/* Need to resize the fb object !!! */
-	if (var->bits_per_pixel > fb->bits_per_pixel || var->xres > fb->width || var->yres > fb->height) {
+	if (var->bits_per_pixel > fb->bits_per_pixel ||
+	    var->xres > fb->width || var->yres > fb->height ||
+	    var->xres_virtual > fb->width || var->yres_virtual > fb->height) {
 		DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb "
-			  "object %dx%d-%d > %dx%d-%d\n", var->xres, var->yres, var->bits_per_pixel,
+			  "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n",
+			  var->xres, var->yres, var->bits_per_pixel,
+			  var->xres_virtual, var->yres_virtual,
 			  fb->width, fb->height, fb->bits_per_pixel);
 		return -EINVAL;
 	}
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 6263b01..cdfbf27 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -133,6 +133,9 @@
 	if (!(dev = minor->dev))
 		return -ENODEV;
 
+	if (drm_device_is_unplugged(dev))
+		return -ENODEV;
+
 	retcode = drm_open_helper(inode, filp, dev);
 	if (!retcode) {
 		atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
@@ -181,6 +184,9 @@
 	if (!(dev = minor->dev))
 		goto out;
 
+	if (drm_device_is_unplugged(dev))
+		goto out;
+
 	old_fops = filp->f_op;
 	filp->f_op = fops_get(dev->driver->fops);
 	if (filp->f_op == NULL) {
@@ -265,6 +271,9 @@
 	if (dev->driver->driver_features & DRIVER_GEM)
 		drm_gem_open(dev, priv);
 
+	if (drm_core_check_feature(dev, DRIVER_PRIME))
+		drm_prime_init_file_private(&priv->prime);
+
 	if (dev->driver->open) {
 		ret = dev->driver->open(dev, priv);
 		if (ret < 0)
@@ -565,6 +574,10 @@
 
 	if (dev->driver->postclose)
 		dev->driver->postclose(dev, file_priv);
+
+	if (drm_core_check_feature(dev, DRIVER_PRIME))
+		drm_prime_destroy_file_private(&file_priv->prime);
+
 	kfree(file_priv);
 
 	/* ========================================================
@@ -579,6 +592,8 @@
 			retcode = -EBUSY;
 		} else
 			retcode = drm_lastclose(dev);
+		if (drm_device_is_unplugged(dev))
+			drm_put_dev(dev);
 	}
 	mutex_unlock(&drm_global_mutex);
 
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index f8625e2..83114b5 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -35,6 +35,7 @@
 #include <linux/mman.h>
 #include <linux/pagemap.h>
 #include <linux/shmem_fs.h>
+#include <linux/dma-buf.h>
 #include "drmP.h"
 
 /** @file drm_gem.c
@@ -232,6 +233,10 @@
 	idr_remove(&filp->object_idr, handle);
 	spin_unlock(&filp->table_lock);
 
+	if (obj->import_attach)
+		drm_prime_remove_imported_buf_handle(&filp->prime,
+				obj->import_attach->dmabuf);
+
 	if (dev->driver->gem_close_object)
 		dev->driver->gem_close_object(obj, filp);
 	drm_gem_object_handle_unreference_unlocked(obj);
@@ -527,6 +532,10 @@
 	struct drm_gem_object *obj = ptr;
 	struct drm_device *dev = obj->dev;
 
+	if (obj->import_attach)
+		drm_prime_remove_imported_buf_handle(&file_priv->prime,
+				obj->import_attach->dmabuf);
+
 	if (dev->driver->gem_close_object)
 		dev->driver->gem_close_object(obj, file_priv);
 
@@ -661,6 +670,9 @@
 	struct drm_hash_item *hash;
 	int ret = 0;
 
+	if (drm_device_is_unplugged(dev))
+		return -ENODEV;
+
 	mutex_lock(&dev->struct_mutex);
 
 	if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) {
@@ -700,7 +712,6 @@
 	 */
 	drm_gem_object_reference(obj);
 
-	vma->vm_file = filp;	/* Needed for drm_vm_open() */
 	drm_vm_open_locked(vma);
 
 out_unlock:
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 956fd38..cf85155 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -37,6 +37,7 @@
 #include "drm_core.h"
 
 #include "linux/pci.h"
+#include "linux/export.h"
 
 /**
  * Get the bus id.
@@ -276,6 +277,12 @@
 	case DRM_CAP_VBLANK_HIGH_CRTC:
 		req->value = 1;
 		break;
+	case DRM_CAP_DUMB_PREFERRED_DEPTH:
+		req->value = dev->mode_config.preferred_depth;
+		break;
+	case DRM_CAP_DUMB_PREFER_SHADOW:
+		req->value = dev->mode_config.prefer_shadow;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -346,3 +353,4 @@
 	DRM_DEBUG("\n");
 	return 0;
 }
+EXPORT_SYMBOL(drm_noop);
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 44a5d0a..c869436 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -305,7 +305,7 @@
  * \param dev DRM device.
  *
  * Initializes the IRQ related data. Installs the handler, calling the driver
- * \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions
+ * \c irq_preinstall() and \c irq_postinstall() functions
  * before and after the installation.
  */
 int drm_irq_install(struct drm_device *dev)
@@ -385,7 +385,7 @@
  *
  * \param dev DRM device.
  *
- * Calls the driver's \c drm_driver_irq_uninstall() function, and stops the irq.
+ * Calls the driver's \c irq_uninstall() function, and stops the irq.
  */
 int drm_irq_uninstall(struct drm_device *dev)
 {
diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c
index c8b6b66..c86a0f1 100644
--- a/drivers/gpu/drm/drm_memory.c
+++ b/drivers/gpu/drm/drm_memory.c
@@ -37,25 +37,6 @@
 #include <linux/export.h>
 #include "drmP.h"
 
-/**
- * Called when "/proc/dri/%dev%/mem" is read.
- *
- * \param buf output buffer.
- * \param start start of output data.
- * \param offset requested start offset.
- * \param len requested number of bytes.
- * \param eof whether there is no more data to return.
- * \param data private data.
- * \return number of written bytes.
- *
- * No-op.
- */
-int drm_mem_info(char *buf, char **start, off_t offset,
-		 int len, int *eof, void *data)
-{
-	return 0;
-}
-
 #if __OS_HAS_AGP
 static void *agp_remap(unsigned long offset, unsigned long size,
 		       struct drm_device * dev)
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index fb8e46b..b7adb4a 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -686,8 +686,6 @@
 			p->crtc_vsync_end /= 2;
 			p->crtc_vtotal /= 2;
 		}
-
-		p->crtc_vtotal |= 1;
 	}
 
 	if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
@@ -716,6 +714,27 @@
 
 
 /**
+ * drm_mode_copy - copy the mode
+ * @dst: mode to overwrite
+ * @src: mode to copy
+ *
+ * LOCKING:
+ * None.
+ *
+ * Copy an existing mode into another mode, preserving the object id
+ * of the destination mode.
+ */
+void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
+{
+	int id = dst->base.id;
+
+	*dst = *src;
+	dst->base.id = id;
+	INIT_LIST_HEAD(&dst->head);
+}
+EXPORT_SYMBOL(drm_mode_copy);
+
+/**
  * drm_mode_duplicate - allocate and duplicate an existing mode
  * @m: mode to duplicate
  *
@@ -729,16 +748,13 @@
 					    const struct drm_display_mode *mode)
 {
 	struct drm_display_mode *nmode;
-	int new_id;
 
 	nmode = drm_mode_create(dev);
 	if (!nmode)
 		return NULL;
 
-	new_id = nmode->base.id;
-	*nmode = *mode;
-	nmode->base.id = new_id;
-	INIT_LIST_HEAD(&nmode->head);
+	drm_mode_copy(nmode, mode);
+
 	return nmode;
 }
 EXPORT_SYMBOL(drm_mode_duplicate);
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index d4d10b7..13f3d93 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -324,8 +324,6 @@
 	if (ret)
 		goto err_g1;
 
-	pci_set_master(pdev);
-
 	dev->pdev = pdev;
 	dev->dev = &pdev->dev;
 
diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c
index ae9db5e..82431dc 100644
--- a/drivers/gpu/drm/drm_platform.c
+++ b/drivers/gpu/drm/drm_platform.c
@@ -122,7 +122,7 @@
 
 static int drm_platform_set_busid(struct drm_device *dev, struct drm_master *master)
 {
-	int len, ret;
+	int len, ret, id;
 
 	master->unique_len = 13 + strlen(dev->platformdev->name);
 	master->unique_size = master->unique_len;
@@ -131,8 +131,16 @@
 	if (master->unique == NULL)
 		return -ENOMEM;
 
+	id = dev->platformdev->id;
+
+	/* if only a single instance of the platform device, id will be
+	 * set to -1.. use 0 instead to avoid a funny looking bus-id:
+	 */
+	if (id == -1)
+		id = 0;
+
 	len = snprintf(master->unique, master->unique_len,
-			"platform:%s:%02d", dev->platformdev->name, dev->platformdev->id);
+			"platform:%s:%02d", dev->platformdev->name, id);
 
 	if (len > master->unique_len) {
 		DRM_ERROR("Unique buffer overflowed\n");
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
new file mode 100644
index 0000000..1bdf2b5
--- /dev/null
+++ b/drivers/gpu/drm/drm_prime.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright © 2012 Red Hat
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *      Dave Airlie <airlied@redhat.com>
+ *      Rob Clark <rob.clark@linaro.org>
+ *
+ */
+
+#include <linux/export.h>
+#include <linux/dma-buf.h>
+#include "drmP.h"
+
+/*
+ * DMA-BUF/GEM Object references and lifetime overview:
+ *
+ * On the export the dma_buf holds a reference to the exporting GEM
+ * object. It takes this reference in handle_to_fd_ioctl, when it
+ * first calls .prime_export and stores the exporting GEM object in
+ * the dma_buf priv. This reference is released when the dma_buf
+ * object goes away in the driver .release function.
+ *
+ * On the import the importing GEM object holds a reference to the
+ * dma_buf (which in turn holds a ref to the exporting GEM object).
+ * It takes that reference in the fd_to_handle ioctl.
+ * It calls dma_buf_get, creates an attachment to it and stores the
+ * attachment in the GEM object. When this attachment is destroyed
+ * when the imported object is destroyed, we remove the attachment
+ * and drop the reference to the dma_buf.
+ *
+ * Thus the chain of references always flows in one direction
+ * (avoiding loops): importing_gem -> dmabuf -> exporting_gem
+ *
+ * Self-importing: if userspace is using PRIME as a replacement for flink
+ * then it will get a fd->handle request for a GEM object that it created.
+ * Drivers should detect this situation and return back the gem object
+ * from the dma-buf private.
+ */
+
+struct drm_prime_member {
+	struct list_head entry;
+	struct dma_buf *dma_buf;
+	uint32_t handle;
+};
+
+int drm_gem_prime_handle_to_fd(struct drm_device *dev,
+		struct drm_file *file_priv, uint32_t handle, uint32_t flags,
+		int *prime_fd)
+{
+	struct drm_gem_object *obj;
+	void *buf;
+
+	obj = drm_gem_object_lookup(dev, file_priv, handle);
+	if (!obj)
+		return -ENOENT;
+
+	mutex_lock(&file_priv->prime.lock);
+	/* re-export the original imported object */
+	if (obj->import_attach) {
+		get_dma_buf(obj->import_attach->dmabuf);
+		*prime_fd = dma_buf_fd(obj->import_attach->dmabuf, flags);
+		drm_gem_object_unreference_unlocked(obj);
+		mutex_unlock(&file_priv->prime.lock);
+		return 0;
+	}
+
+	if (obj->export_dma_buf) {
+		get_dma_buf(obj->export_dma_buf);
+		*prime_fd = dma_buf_fd(obj->export_dma_buf, flags);
+		drm_gem_object_unreference_unlocked(obj);
+	} else {
+		buf = dev->driver->gem_prime_export(dev, obj, flags);
+		if (IS_ERR(buf)) {
+			/* normally the created dma-buf takes ownership of the ref,
+			 * but if that fails then drop the ref
+			 */
+			drm_gem_object_unreference_unlocked(obj);
+			mutex_unlock(&file_priv->prime.lock);
+			return PTR_ERR(buf);
+		}
+		obj->export_dma_buf = buf;
+		*prime_fd = dma_buf_fd(buf, flags);
+	}
+	mutex_unlock(&file_priv->prime.lock);
+	return 0;
+}
+EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);
+
+int drm_gem_prime_fd_to_handle(struct drm_device *dev,
+		struct drm_file *file_priv, int prime_fd, uint32_t *handle)
+{
+	struct dma_buf *dma_buf;
+	struct drm_gem_object *obj;
+	int ret;
+
+	dma_buf = dma_buf_get(prime_fd);
+	if (IS_ERR(dma_buf))
+		return PTR_ERR(dma_buf);
+
+	mutex_lock(&file_priv->prime.lock);
+
+	ret = drm_prime_lookup_imported_buf_handle(&file_priv->prime,
+			dma_buf, handle);
+	if (!ret) {
+		ret = 0;
+		goto out_put;
+	}
+
+	/* never seen this one, need to import */
+	obj = dev->driver->gem_prime_import(dev, dma_buf);
+	if (IS_ERR(obj)) {
+		ret = PTR_ERR(obj);
+		goto out_put;
+	}
+
+	ret = drm_gem_handle_create(file_priv, obj, handle);
+	drm_gem_object_unreference_unlocked(obj);
+	if (ret)
+		goto out_put;
+
+	ret = drm_prime_add_imported_buf_handle(&file_priv->prime,
+			dma_buf, *handle);
+	if (ret)
+		goto fail;
+
+	mutex_unlock(&file_priv->prime.lock);
+	return 0;
+
+fail:
+	/* hmm, if driver attached, we are relying on the free-object path
+	 * to detach.. which seems ok..
+	 */
+	drm_gem_object_handle_unreference_unlocked(obj);
+out_put:
+	dma_buf_put(dma_buf);
+	mutex_unlock(&file_priv->prime.lock);
+	return ret;
+}
+EXPORT_SYMBOL(drm_gem_prime_fd_to_handle);
+
+int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
+				 struct drm_file *file_priv)
+{
+	struct drm_prime_handle *args = data;
+	uint32_t flags;
+
+	if (!drm_core_check_feature(dev, DRIVER_PRIME))
+		return -EINVAL;
+
+	if (!dev->driver->prime_handle_to_fd)
+		return -ENOSYS;
+
+	/* check flags are valid */
+	if (args->flags & ~DRM_CLOEXEC)
+		return -EINVAL;
+
+	/* we only want to pass DRM_CLOEXEC which is == O_CLOEXEC */
+	flags = args->flags & DRM_CLOEXEC;
+
+	return dev->driver->prime_handle_to_fd(dev, file_priv,
+			args->handle, flags, &args->fd);
+}
+
+int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
+				 struct drm_file *file_priv)
+{
+	struct drm_prime_handle *args = data;
+
+	if (!drm_core_check_feature(dev, DRIVER_PRIME))
+		return -EINVAL;
+
+	if (!dev->driver->prime_fd_to_handle)
+		return -ENOSYS;
+
+	return dev->driver->prime_fd_to_handle(dev, file_priv,
+			args->fd, &args->handle);
+}
+
+/*
+ * drm_prime_pages_to_sg
+ *
+ * this helper creates an sg table object from a set of pages
+ * the driver is responsible for mapping the pages into the
+ * importers address space
+ */
+struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages)
+{
+	struct sg_table *sg = NULL;
+	struct scatterlist *iter;
+	int i;
+	int ret;
+
+	sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!sg)
+		goto out;
+
+	ret = sg_alloc_table(sg, nr_pages, GFP_KERNEL);
+	if (ret)
+		goto out;
+
+	for_each_sg(sg->sgl, iter, nr_pages, i)
+		sg_set_page(iter, pages[i], PAGE_SIZE, 0);
+
+	return sg;
+out:
+	kfree(sg);
+	return NULL;
+}
+EXPORT_SYMBOL(drm_prime_pages_to_sg);
+
+/* helper function to cleanup a GEM/prime object */
+void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg)
+{
+	struct dma_buf_attachment *attach;
+	struct dma_buf *dma_buf;
+	attach = obj->import_attach;
+	if (sg)
+		dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
+	dma_buf = attach->dmabuf;
+	dma_buf_detach(attach->dmabuf, attach);
+	/* remove the reference */
+	dma_buf_put(dma_buf);
+}
+EXPORT_SYMBOL(drm_prime_gem_destroy);
+
+void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)
+{
+	INIT_LIST_HEAD(&prime_fpriv->head);
+	mutex_init(&prime_fpriv->lock);
+}
+EXPORT_SYMBOL(drm_prime_init_file_private);
+
+void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv)
+{
+	struct drm_prime_member *member, *safe;
+	list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
+		list_del(&member->entry);
+		kfree(member);
+	}
+}
+EXPORT_SYMBOL(drm_prime_destroy_file_private);
+
+int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle)
+{
+	struct drm_prime_member *member;
+
+	member = kmalloc(sizeof(*member), GFP_KERNEL);
+	if (!member)
+		return -ENOMEM;
+
+	member->dma_buf = dma_buf;
+	member->handle = handle;
+	list_add(&member->entry, &prime_fpriv->head);
+	return 0;
+}
+EXPORT_SYMBOL(drm_prime_add_imported_buf_handle);
+
+int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle)
+{
+	struct drm_prime_member *member;
+
+	list_for_each_entry(member, &prime_fpriv->head, entry) {
+		if (member->dma_buf == dma_buf) {
+			*handle = member->handle;
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+EXPORT_SYMBOL(drm_prime_lookup_imported_buf_handle);
+
+void drm_prime_remove_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf)
+{
+	struct drm_prime_member *member, *safe;
+
+	mutex_lock(&prime_fpriv->lock);
+	list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
+		if (member->dma_buf == dma_buf) {
+			list_del(&member->entry);
+			kfree(member);
+		}
+	}
+	mutex_unlock(&prime_fpriv->lock);
+}
+EXPORT_SYMBOL(drm_prime_remove_imported_buf_handle);
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index 6d7b083..aa454f8 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -319,6 +319,7 @@
 	drm_lastclose(dev);
 	return retcode;
 }
+EXPORT_SYMBOL(drm_fill_in_dev);
 
 
 /**
@@ -397,6 +398,7 @@
 	*minor = NULL;
 	return ret;
 }
+EXPORT_SYMBOL(drm_get_minor);
 
 /**
  * Put a secondary minor number.
@@ -428,6 +430,12 @@
 	*minor_p = NULL;
 	return 0;
 }
+EXPORT_SYMBOL(drm_put_minor);
+
+static void drm_unplug_minor(struct drm_minor *minor)
+{
+	drm_sysfs_device_remove(minor);
+}
 
 /**
  * Called via drm_exit() at module unload time or when pci device is
@@ -492,3 +500,21 @@
 	kfree(dev);
 }
 EXPORT_SYMBOL(drm_put_dev);
+
+void drm_unplug_dev(struct drm_device *dev)
+{
+	/* for a USB device */
+	if (drm_core_check_feature(dev, DRIVER_MODESET))
+		drm_unplug_minor(dev->control);
+	drm_unplug_minor(dev->primary);
+
+	mutex_lock(&drm_global_mutex);
+
+	drm_device_set_unplugged(dev);
+
+	if (dev->open_count == 0) {
+		drm_put_dev(dev);
+	}
+	mutex_unlock(&drm_global_mutex);
+}
+EXPORT_SYMBOL(drm_unplug_dev);
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 62c3675..5a7bd51 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -454,6 +454,8 @@
 {
 	int i;
 
+	if (!connector->kdev.parent)
+		return;
 	DRM_DEBUG("removing \"%s\" from sysfs\n",
 		  drm_get_connector_name(connector));
 
@@ -461,6 +463,7 @@
 		device_remove_file(&connector->kdev, &connector_attrs[i]);
 	sysfs_remove_bin_file(&connector->kdev.kobj, &edid_attr);
 	device_unregister(&connector->kdev);
+	connector->kdev.parent = NULL;
 }
 EXPORT_SYMBOL(drm_sysfs_connector_remove);
 
@@ -533,7 +536,9 @@
  */
 void drm_sysfs_device_remove(struct drm_minor *minor)
 {
-	device_unregister(&minor->kdev);
+	if (minor->kdev.parent)
+		device_unregister(&minor->kdev);
+	minor->kdev.parent = NULL;
 }
 
 
diff --git a/drivers/gpu/drm/drm_usb.c b/drivers/gpu/drm/drm_usb.c
index 445003f..c8c83da 100644
--- a/drivers/gpu/drm/drm_usb.c
+++ b/drivers/gpu/drm/drm_usb.c
@@ -2,7 +2,6 @@
 #include <linux/usb.h>
 #include <linux/export.h>
 
-#ifdef CONFIG_USB
 int drm_get_usb_dev(struct usb_interface *interface,
 		    const struct usb_device_id *id,
 		    struct drm_driver *driver)
@@ -115,4 +114,3 @@
 	usb_deregister(udriver);
 }
 EXPORT_SYMBOL(drm_usb_exit);
-#endif
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c
index 8c03eaf..1495618 100644
--- a/drivers/gpu/drm/drm_vm.c
+++ b/drivers/gpu/drm/drm_vm.c
@@ -519,7 +519,6 @@
 	vma->vm_flags |= VM_RESERVED;	/* Don't swap */
 	vma->vm_flags |= VM_DONTEXPAND;
 
-	vma->vm_file = filp;	/* Needed for drm_vm_open() */
 	drm_vm_open_locked(vma);
 	return 0;
 }
@@ -671,7 +670,6 @@
 	vma->vm_flags |= VM_RESERVED;	/* Don't swap */
 	vma->vm_flags |= VM_DONTEXPAND;
 
-	vma->vm_file = filp;	/* Needed for drm_vm_open() */
 	drm_vm_open_locked(vma);
 	return 0;
 }
@@ -682,6 +680,9 @@
 	struct drm_device *dev = priv->minor->dev;
 	int ret;
 
+	if (drm_device_is_unplugged(dev))
+		return -ENODEV;
+
 	mutex_lock(&dev->struct_mutex);
 	ret = drm_mmap_locked(filp, vma);
 	mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index b9e5266c..3343ac4 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -1,7 +1,6 @@
 config DRM_EXYNOS
 	tristate "DRM Support for Samsung SoC EXYNOS Series"
 	depends on DRM && PLAT_SAMSUNG
-	default	n
 	select DRM_KMS_HELPER
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
@@ -12,16 +11,19 @@
 	  If M is selected the module will be called exynosdrm.
 
 config DRM_EXYNOS_FIMD
-	tristate "Exynos DRM FIMD"
+	bool "Exynos DRM FIMD"
 	depends on DRM_EXYNOS && !FB_S3C
-	default n
 	help
 	  Choose this option if you want to use Exynos FIMD for DRM.
-	  If M is selected, the module will be called exynos_drm_fimd
 
 config DRM_EXYNOS_HDMI
-	tristate "Exynos DRM HDMI"
+	bool "Exynos DRM HDMI"
 	depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV
 	help
 	  Choose this option if you want to use Exynos HDMI for DRM.
-	  If M is selected, the module will be called exynos_drm_hdmi
+
+config DRM_EXYNOS_VIDI
+	bool "Exynos DRM Virtual Display"
+	depends on DRM_EXYNOS
+	help
+	  Choose this option if you want to use Exynos VIDI for DRM.
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 395e69c..9e0bff8 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -8,7 +8,10 @@
 		exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \
 		exynos_drm_plane.o
 
-obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o
-obj-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
-obj-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o exynos_ddc.o \
-				 exynos_hdmiphy.o exynos_drm_hdmi.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)	+= exynos_drm_fimd.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)	+= exynos_hdmi.o exynos_mixer.o \
+					   exynos_ddc.o exynos_hdmiphy.o \
+					   exynos_drm_hdmi.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI)	+= exynos_drm_vidi.o
+
+obj-$(CONFIG_DRM_EXYNOS)		+= exynosdrm.o
diff --git a/drivers/gpu/drm/exynos/exynos_ddc.c b/drivers/gpu/drm/exynos/exynos_ddc.c
index 84b614f..7e1051d 100644
--- a/drivers/gpu/drm/exynos/exynos_ddc.c
+++ b/drivers/gpu/drm/exynos/exynos_ddc.c
@@ -55,4 +55,3 @@
 	.remove		= __devexit_p(s5p_ddc_remove),
 	.command		= NULL,
 };
-EXPORT_SYMBOL(ddc_driver);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c
index 3cf785c..4a3a5f7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c
@@ -25,45 +25,161 @@
 
 #include "drmP.h"
 #include "drm.h"
+#include "exynos_drm.h"
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_gem.h"
 #include "exynos_drm_buf.h"
 
 static int lowlevel_buffer_allocate(struct drm_device *dev,
-		struct exynos_drm_gem_buf *buffer)
+		unsigned int flags, struct exynos_drm_gem_buf *buf)
 {
+	dma_addr_t start_addr, end_addr;
+	unsigned int npages, page_size, i = 0;
+	struct scatterlist *sgl;
+	int ret = 0;
+
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	buffer->kvaddr = dma_alloc_writecombine(dev->dev, buffer->size,
-			&buffer->dma_addr, GFP_KERNEL);
-	if (!buffer->kvaddr) {
-		DRM_ERROR("failed to allocate buffer.\n");
+	if (flags & EXYNOS_BO_NONCONTIG) {
+		DRM_DEBUG_KMS("not support allocation type.\n");
+		return -EINVAL;
+	}
+
+	if (buf->dma_addr) {
+		DRM_DEBUG_KMS("already allocated.\n");
+		return 0;
+	}
+
+	if (buf->size >= SZ_1M) {
+		npages = (buf->size >> SECTION_SHIFT) + 1;
+		page_size = SECTION_SIZE;
+	} else if (buf->size >= SZ_64K) {
+		npages = (buf->size >> 16) + 1;
+		page_size = SZ_64K;
+	} else {
+		npages = (buf->size >> PAGE_SHIFT) + 1;
+		page_size = PAGE_SIZE;
+	}
+
+	buf->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!buf->sgt) {
+		DRM_ERROR("failed to allocate sg table.\n");
 		return -ENOMEM;
 	}
 
-	DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
-			(unsigned long)buffer->kvaddr,
-			(unsigned long)buffer->dma_addr,
-			buffer->size);
+	ret = sg_alloc_table(buf->sgt, npages, GFP_KERNEL);
+	if (ret < 0) {
+		DRM_ERROR("failed to initialize sg table.\n");
+		kfree(buf->sgt);
+		buf->sgt = NULL;
+		return -ENOMEM;
+	}
 
-	return 0;
+		buf->kvaddr = dma_alloc_writecombine(dev->dev, buf->size,
+				&buf->dma_addr, GFP_KERNEL);
+		if (!buf->kvaddr) {
+			DRM_ERROR("failed to allocate buffer.\n");
+			ret = -ENOMEM;
+			goto err1;
+		}
+
+		start_addr = buf->dma_addr;
+		end_addr = buf->dma_addr + buf->size;
+
+		buf->pages = kzalloc(sizeof(struct page) * npages, GFP_KERNEL);
+		if (!buf->pages) {
+			DRM_ERROR("failed to allocate pages.\n");
+			ret = -ENOMEM;
+			goto err2;
+		}
+
+	start_addr = buf->dma_addr;
+	end_addr = buf->dma_addr + buf->size;
+
+	buf->pages = kzalloc(sizeof(struct page) * npages, GFP_KERNEL);
+	if (!buf->pages) {
+		DRM_ERROR("failed to allocate pages.\n");
+		ret = -ENOMEM;
+		goto err2;
+	}
+
+	sgl = buf->sgt->sgl;
+
+	while (i < npages) {
+		buf->pages[i] = phys_to_page(start_addr);
+		sg_set_page(sgl, buf->pages[i], page_size, 0);
+		sg_dma_address(sgl) = start_addr;
+		start_addr += page_size;
+		if (end_addr - start_addr < page_size)
+			break;
+		sgl = sg_next(sgl);
+		i++;
+	}
+
+	buf->pages[i] = phys_to_page(start_addr);
+
+	sgl = sg_next(sgl);
+	sg_set_page(sgl, buf->pages[i+1], end_addr - start_addr, 0);
+
+	DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
+			(unsigned long)buf->kvaddr,
+			(unsigned long)buf->dma_addr,
+			buf->size);
+
+	return ret;
+err2:
+	dma_free_writecombine(dev->dev, buf->size, buf->kvaddr,
+			(dma_addr_t)buf->dma_addr);
+	buf->dma_addr = (dma_addr_t)NULL;
+err1:
+	sg_free_table(buf->sgt);
+	kfree(buf->sgt);
+	buf->sgt = NULL;
+
+	return ret;
 }
 
 static void lowlevel_buffer_deallocate(struct drm_device *dev,
-		struct exynos_drm_gem_buf *buffer)
+		unsigned int flags, struct exynos_drm_gem_buf *buf)
 {
 	DRM_DEBUG_KMS("%s.\n", __FILE__);
 
-	if (buffer->dma_addr && buffer->size)
-		dma_free_writecombine(dev->dev, buffer->size, buffer->kvaddr,
-				(dma_addr_t)buffer->dma_addr);
-	else
-		DRM_DEBUG_KMS("buffer data are invalid.\n");
+	/*
+	 * release only physically continuous memory and
+	 * non-continuous memory would be released by exynos
+	 * gem framework.
+	 */
+	if (flags & EXYNOS_BO_NONCONTIG) {
+		DRM_DEBUG_KMS("not support allocation type.\n");
+		return;
+	}
+
+	if (!buf->dma_addr) {
+		DRM_DEBUG_KMS("dma_addr is invalid.\n");
+		return;
+	}
+
+	DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
+			(unsigned long)buf->kvaddr,
+			(unsigned long)buf->dma_addr,
+			buf->size);
+
+	sg_free_table(buf->sgt);
+
+	kfree(buf->sgt);
+	buf->sgt = NULL;
+
+	kfree(buf->pages);
+	buf->pages = NULL;
+
+	dma_free_writecombine(dev->dev, buf->size, buf->kvaddr,
+				(dma_addr_t)buf->dma_addr);
+	buf->dma_addr = (dma_addr_t)NULL;
 }
 
-struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
-		unsigned int size)
+struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
+						unsigned int size)
 {
 	struct exynos_drm_gem_buf *buffer;
 
@@ -77,21 +193,11 @@
 	}
 
 	buffer->size = size;
-
-	/*
-	 * allocate memory region with size and set the memory information
-	 * to vaddr and dma_addr of a buffer object.
-	 */
-	if (lowlevel_buffer_allocate(dev, buffer) < 0) {
-		kfree(buffer);
-		return NULL;
-	}
-
 	return buffer;
 }
 
-void exynos_drm_buf_destroy(struct drm_device *dev,
-		struct exynos_drm_gem_buf *buffer)
+void exynos_drm_fini_buf(struct drm_device *dev,
+				struct exynos_drm_gem_buf *buffer)
 {
 	DRM_DEBUG_KMS("%s.\n", __FILE__);
 
@@ -100,12 +206,27 @@
 		return;
 	}
 
-	lowlevel_buffer_deallocate(dev, buffer);
-
 	kfree(buffer);
 	buffer = NULL;
 }
 
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM Buffer Management Module");
-MODULE_LICENSE("GPL");
+int exynos_drm_alloc_buf(struct drm_device *dev,
+		struct exynos_drm_gem_buf *buf, unsigned int flags)
+{
+
+	/*
+	 * allocate memory region and set the memory information
+	 * to vaddr and dma_addr of a buffer object.
+	 */
+	if (lowlevel_buffer_allocate(dev, flags, buf) < 0)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void exynos_drm_free_buf(struct drm_device *dev,
+		unsigned int flags, struct exynos_drm_gem_buf *buffer)
+{
+
+	lowlevel_buffer_deallocate(dev, flags, buffer);
+}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.h b/drivers/gpu/drm/exynos/exynos_drm_buf.h
index c913f2b..3388e4e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.h
@@ -26,12 +26,22 @@
 #ifndef _EXYNOS_DRM_BUF_H_
 #define _EXYNOS_DRM_BUF_H_
 
-/* allocate physical memory. */
-struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
-		unsigned int size);
+/* create and initialize buffer object. */
+struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
+						unsigned int size);
 
-/* remove allocated physical memory. */
-void exynos_drm_buf_destroy(struct drm_device *dev,
-		struct exynos_drm_gem_buf *buffer);
+/* destroy buffer object. */
+void exynos_drm_fini_buf(struct drm_device *dev,
+				struct exynos_drm_gem_buf *buffer);
+
+/* allocate physical memory region and setup sgt and pages. */
+int exynos_drm_alloc_buf(struct drm_device *dev,
+				struct exynos_drm_gem_buf *buf,
+				unsigned int flags);
+
+/* release physical memory region, sgt and pages. */
+void exynos_drm_free_buf(struct drm_device *dev,
+				unsigned int flags,
+				struct exynos_drm_gem_buf *buffer);
 
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 99d5527..bf791fa 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -225,6 +225,29 @@
 	.best_encoder	= exynos_drm_best_encoder,
 };
 
+static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
+				unsigned int max_width, unsigned int max_height)
+{
+	struct exynos_drm_connector *exynos_connector =
+					to_exynos_connector(connector);
+	struct exynos_drm_manager *manager = exynos_connector->manager;
+	struct exynos_drm_manager_ops *ops = manager->ops;
+	unsigned int width, height;
+
+	width = max_width;
+	height = max_height;
+
+	/*
+	 * if specific driver want to find desired_mode using maxmum
+	 * resolution then get max width and height from that driver.
+	 */
+	if (ops && ops->get_max_resol)
+		ops->get_max_resol(manager->dev, &width, &height);
+
+	return drm_helper_probe_single_connector_modes(connector, width,
+							height);
+}
+
 /* get detection status of display device. */
 static enum drm_connector_status
 exynos_drm_connector_detect(struct drm_connector *connector, bool force)
@@ -262,7 +285,7 @@
 
 static struct drm_connector_funcs exynos_connector_funcs = {
 	.dpms		= drm_helper_connector_dpms,
-	.fill_modes	= drm_helper_probe_single_connector_modes,
+	.fill_modes	= exynos_drm_connector_fill_modes,
 	.detect		= exynos_drm_connector_detect,
 	.destroy	= exynos_drm_connector_destroy,
 };
@@ -292,6 +315,10 @@
 		connector->interlace_allowed = true;
 		connector->polled = DRM_CONNECTOR_POLL_HPD;
 		break;
+	case EXYNOS_DISPLAY_TYPE_VIDI:
+		type = DRM_MODE_CONNECTOR_VIRTUAL;
+		connector->polled = DRM_CONNECTOR_POLL_HPD;
+		break;
 	default:
 		type = DRM_MODE_CONNECTOR_Unknown;
 		break;
@@ -325,9 +352,3 @@
 	kfree(exynos_connector);
 	return NULL;
 }
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM Connector Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c
index d08a558..411832e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_core.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_core.c
@@ -32,7 +32,6 @@
 #include "exynos_drm_connector.h"
 #include "exynos_drm_fbdev.h"
 
-static DEFINE_MUTEX(exynos_drm_mutex);
 static LIST_HEAD(exynos_drm_subdrv_list);
 static struct drm_device *drm_dev;
 
@@ -60,6 +59,9 @@
 			return ret;
 	}
 
+	if (subdrv->is_local)
+		return 0;
+
 	/* create and initialize a encoder for this sub driver. */
 	encoder = exynos_drm_encoder_create(dev, &subdrv->manager,
 			(1 << MAX_CRTC) - 1);
@@ -116,13 +118,10 @@
 	if (!dev)
 		return -EINVAL;
 
-	if (drm_dev) {
-		DRM_ERROR("Already drm device were registered\n");
-		return -EBUSY;
-	}
+	drm_dev = dev;
 
-	mutex_lock(&exynos_drm_mutex);
 	list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
+		subdrv->drm_dev = dev;
 		err = exynos_drm_subdrv_probe(dev, subdrv);
 		if (err) {
 			DRM_DEBUG("exynos drm subdrv probe failed.\n");
@@ -130,9 +129,6 @@
 		}
 	}
 
-	drm_dev = dev;
-	mutex_unlock(&exynos_drm_mutex);
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_device_register);
@@ -143,86 +139,28 @@
 
 	DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
-	if (!dev || dev != drm_dev) {
+	if (!dev) {
 		WARN(1, "Unexpected drm device unregister!\n");
 		return -EINVAL;
 	}
 
-	mutex_lock(&exynos_drm_mutex);
 	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list)
 		exynos_drm_subdrv_remove(dev, subdrv);
 
 	drm_dev = NULL;
-	mutex_unlock(&exynos_drm_mutex);
 
 	return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
 
-static int exynos_drm_mode_group_reinit(struct drm_device *dev)
-{
-	struct drm_mode_group *group = &dev->primary->mode_group;
-	uint32_t *id_list = group->id_list;
-	int ret;
-
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
-	ret = drm_mode_group_init_legacy_group(dev, group);
-	if (ret < 0)
-		return ret;
-
-	kfree(id_list);
-	return 0;
-}
-
 int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
 {
-	int err;
-
 	DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
 	if (!subdrv)
 		return -EINVAL;
 
-	mutex_lock(&exynos_drm_mutex);
-	if (drm_dev) {
-		err = exynos_drm_subdrv_probe(drm_dev, subdrv);
-		if (err) {
-			DRM_ERROR("failed to probe exynos drm subdrv\n");
-			mutex_unlock(&exynos_drm_mutex);
-			return err;
-		}
-
-		/* setup possible_clones. */
-		exynos_drm_encoder_setup(drm_dev);
-
-		/*
-		 * if any specific driver such as fimd or hdmi driver called
-		 * exynos_drm_subdrv_register() later than drm_load(),
-		 * the fb helper should be re-initialized and re-configured.
-		 */
-		err = exynos_drm_fbdev_reinit(drm_dev);
-		if (err) {
-			DRM_ERROR("failed to reinitialize exynos drm fbdev\n");
-			exynos_drm_subdrv_remove(drm_dev, subdrv);
-			mutex_unlock(&exynos_drm_mutex);
-			return err;
-		}
-
-		err = exynos_drm_mode_group_reinit(drm_dev);
-		if (err) {
-			DRM_ERROR("failed to reinitialize mode group\n");
-			exynos_drm_fbdev_fini(drm_dev);
-			exynos_drm_subdrv_remove(drm_dev, subdrv);
-			mutex_unlock(&exynos_drm_mutex);
-			return err;
-		}
-	}
-
-	subdrv->drm_dev = drm_dev;
-
 	list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
-	mutex_unlock(&exynos_drm_mutex);
 
 	return 0;
 }
@@ -230,46 +168,48 @@
 
 int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
 {
-	int ret = -EFAULT;
-
 	DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
-	if (!subdrv) {
-		DRM_DEBUG("Unexpected exynos drm subdrv unregister!\n");
-		return ret;
-	}
+	if (!subdrv)
+		return -EINVAL;
 
-	mutex_lock(&exynos_drm_mutex);
-	if (drm_dev) {
-		exynos_drm_subdrv_remove(drm_dev, subdrv);
-		list_del(&subdrv->list);
+	list_del(&subdrv->list);
 
-		/*
-		 * fb helper should be updated once a sub driver is released
-		 * to re-configure crtc and connector and also to re-setup
-		 * drm framebuffer.
-		 */
-		ret = exynos_drm_fbdev_reinit(drm_dev);
-		if (ret < 0) {
-			DRM_ERROR("failed fb helper reinit.\n");
-			goto fail;
-		}
-
-		ret = exynos_drm_mode_group_reinit(drm_dev);
-		if (ret < 0) {
-			DRM_ERROR("failed drm mode group reinit.\n");
-			goto fail;
-		}
-	}
-
-fail:
-	mutex_unlock(&exynos_drm_mutex);
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
 
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM Core Driver");
-MODULE_LICENSE("GPL");
+int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
+{
+	struct exynos_drm_subdrv *subdrv;
+	int ret;
+
+	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
+		if (subdrv->open) {
+			ret = subdrv->open(dev, subdrv->manager.dev, file);
+			if (ret)
+				goto err;
+		}
+	}
+
+	return 0;
+
+err:
+	list_for_each_entry_reverse(subdrv, &subdrv->list, list) {
+		if (subdrv->close)
+			subdrv->close(dev, subdrv->manager.dev, file);
+	}
+	return ret;
+}
+EXPORT_SYMBOL_GPL(exynos_drm_subdrv_open);
+
+void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file)
+{
+	struct exynos_drm_subdrv *subdrv;
+
+	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
+		if (subdrv->close)
+			subdrv->close(dev, subdrv->manager.dev, file);
+	}
+}
+EXPORT_SYMBOL_GPL(exynos_drm_subdrv_close);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index de81883..3486ffe 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -249,7 +249,11 @@
 {
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	mode = adjusted_mode;
+	/*
+	 * copy the mode data adjusted by mode_fixup() into crtc->mode
+	 * so that hardware can be seet to proper mode.
+	 */
+	memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
 
 	return exynos_drm_crtc_update(crtc);
 }
@@ -426,9 +430,3 @@
 	exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
 			exynos_drm_disable_vblank);
 }
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM CRTC Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 09cc13f..a6819b5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -38,6 +38,7 @@
 #include "exynos_drm_fb.h"
 #include "exynos_drm_gem.h"
 #include "exynos_drm_plane.h"
+#include "exynos_drm_vidi.h"
 
 #define DRIVER_NAME	"exynos"
 #define DRIVER_DESC	"Samsung SoC DRM"
@@ -144,11 +145,34 @@
 	return 0;
 }
 
-static void exynos_drm_preclose(struct drm_device *dev,
-					struct drm_file *file)
+static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
 {
 	DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
+	return exynos_drm_subdrv_open(dev, file);
+}
+
+static void exynos_drm_preclose(struct drm_device *dev,
+					struct drm_file *file)
+{
+	struct exynos_drm_private *private = dev->dev_private;
+	struct drm_pending_vblank_event *e, *t;
+	unsigned long flags;
+
+	DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+	/* release events of current file */
+	spin_lock_irqsave(&dev->event_lock, flags);
+	list_for_each_entry_safe(e, t, &private->pageflip_event_list,
+			base.link) {
+		if (e->base.file_priv == file) {
+			list_del(&e->base.link);
+			e->base.destroy(&e->base);
+		}
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	exynos_drm_subdrv_close(dev, file);
 }
 
 static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
@@ -185,6 +209,8 @@
 			exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
 	DRM_IOCTL_DEF_DRV(EXYNOS_PLANE_SET_ZPOS, exynos_plane_set_zpos_ioctl,
 			DRM_UNLOCKED | DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
+			vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
 };
 
 static const struct file_operations exynos_drm_driver_fops = {
@@ -202,6 +228,7 @@
 				  DRIVER_MODESET | DRIVER_GEM,
 	.load			= exynos_drm_load,
 	.unload			= exynos_drm_unload,
+	.open			= exynos_drm_open,
 	.preclose		= exynos_drm_preclose,
 	.lastclose		= exynos_drm_lastclose,
 	.postclose		= exynos_drm_postclose,
@@ -252,9 +279,60 @@
 
 static int __init exynos_drm_init(void)
 {
+	int ret;
+
 	DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
-	return platform_driver_register(&exynos_drm_platform_driver);
+#ifdef CONFIG_DRM_EXYNOS_FIMD
+	ret = platform_driver_register(&fimd_driver);
+	if (ret < 0)
+		goto out_fimd;
+#endif
+
+#ifdef CONFIG_DRM_EXYNOS_HDMI
+	ret = platform_driver_register(&hdmi_driver);
+	if (ret < 0)
+		goto out_hdmi;
+	ret = platform_driver_register(&mixer_driver);
+	if (ret < 0)
+		goto out_mixer;
+	ret = platform_driver_register(&exynos_drm_common_hdmi_driver);
+	if (ret < 0)
+		goto out_common_hdmi;
+#endif
+
+#ifdef CONFIG_DRM_EXYNOS_VIDI
+	ret = platform_driver_register(&vidi_driver);
+	if (ret < 0)
+		goto out_vidi;
+#endif
+
+	ret = platform_driver_register(&exynos_drm_platform_driver);
+	if (ret < 0)
+		goto out;
+
+	return 0;
+
+out:
+#ifdef CONFIG_DRM_EXYNOS_VIDI
+out_vidi:
+	platform_driver_unregister(&vidi_driver);
+#endif
+
+#ifdef CONFIG_DRM_EXYNOS_HDMI
+	platform_driver_unregister(&exynos_drm_common_hdmi_driver);
+out_common_hdmi:
+	platform_driver_unregister(&mixer_driver);
+out_mixer:
+	platform_driver_unregister(&hdmi_driver);
+out_hdmi:
+#endif
+
+#ifdef CONFIG_DRM_EXYNOS_FIMD
+	platform_driver_unregister(&fimd_driver);
+out_fimd:
+#endif
+	return ret;
 }
 
 static void __exit exynos_drm_exit(void)
@@ -262,6 +340,20 @@
 	DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
 	platform_driver_unregister(&exynos_drm_platform_driver);
+
+#ifdef CONFIG_DRM_EXYNOS_HDMI
+	platform_driver_unregister(&exynos_drm_common_hdmi_driver);
+	platform_driver_unregister(&mixer_driver);
+	platform_driver_unregister(&hdmi_driver);
+#endif
+
+#ifdef CONFIG_DRM_EXYNOS_VIDI
+	platform_driver_unregister(&vidi_driver);
+#endif
+
+#ifdef CONFIG_DRM_EXYNOS_FIMD
+	platform_driver_unregister(&fimd_driver);
+#endif
 }
 
 module_init(exynos_drm_init);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 13540de..fbd0a23 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -32,9 +32,9 @@
 #include <linux/module.h>
 #include "drm.h"
 
-#define MAX_CRTC	2
+#define MAX_CRTC	3
 #define MAX_PLANE	5
-#define MAX_FB_BUFFER	3
+#define MAX_FB_BUFFER	4
 #define DEFAULT_ZPOS	-1
 
 struct drm_device;
@@ -50,6 +50,8 @@
 	EXYNOS_DISPLAY_TYPE_LCD,
 	/* HDMI Interface. */
 	EXYNOS_DISPLAY_TYPE_HDMI,
+	/* Virtual Display Interface. */
+	EXYNOS_DISPLAY_TYPE_VIDI,
 };
 
 /*
@@ -155,8 +157,10 @@
  *
  * @dpms: control device power.
  * @apply: set timing, vblank and overlay data to registers.
+ * @mode_fixup: fix mode data comparing to hw specific display mode.
  * @mode_set: convert drm_display_mode to hw specific display mode and
  *	      would be called by encoder->mode_set().
+ * @get_max_resol: get maximum resolution to specific hardware.
  * @commit: set current hw specific display mode to hw.
  * @enable_vblank: specific driver callback for enabling vblank interrupt.
  * @disable_vblank: specific driver callback for disabling vblank interrupt.
@@ -164,7 +168,13 @@
 struct exynos_drm_manager_ops {
 	void (*dpms)(struct device *subdrv_dev, int mode);
 	void (*apply)(struct device *subdrv_dev);
+	void (*mode_fixup)(struct device *subdrv_dev,
+				struct drm_connector *connector,
+				struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode);
 	void (*mode_set)(struct device *subdrv_dev, void *mode);
+	void (*get_max_resol)(struct device *subdrv_dev, unsigned int *width,
+				unsigned int *height);
 	void (*commit)(struct device *subdrv_dev);
 	int (*enable_vblank)(struct device *subdrv_dev);
 	void (*disable_vblank)(struct device *subdrv_dev);
@@ -217,10 +227,13 @@
  * @list: sub driver has its own list object to register to exynos drm driver.
  * @drm_dev: pointer to drm_device and this pointer would be set
  *	when sub driver calls exynos_drm_subdrv_register().
+ * @is_local: appear encoder and connector disrelated device.
  * @probe: this callback would be called by exynos drm driver after
  *	subdrv is registered to it.
  * @remove: this callback is used to release resources created
  *	by probe callback.
+ * @open: this would be called with drm device file open.
+ * @close: this would be called with drm device file close.
  * @manager: subdrv has its own manager to control a hardware appropriately
  *	and we can access a hardware drawing on this manager.
  * @encoder: encoder object owned by this sub driver.
@@ -229,9 +242,14 @@
 struct exynos_drm_subdrv {
 	struct list_head list;
 	struct drm_device *drm_dev;
+	bool is_local;
 
 	int (*probe)(struct drm_device *drm_dev, struct device *dev);
 	void (*remove)(struct drm_device *dev);
+	int (*open)(struct drm_device *drm_dev, struct device *dev,
+			struct drm_file *file);
+	void (*close)(struct drm_device *drm_dev, struct device *dev,
+			struct drm_file *file);
 
 	struct exynos_drm_manager manager;
 	struct drm_encoder *encoder;
@@ -254,15 +272,19 @@
  * this function would be called by sub drivers such as display controller
  * or hdmi driver to register this sub driver object to exynos drm driver
  * and when a sub driver is registered to exynos drm driver a probe callback
- * of the sub driver is called and creates its own encoder and connector
- * and then fb helper and drm mode group would be re-initialized.
+ * of the sub driver is called and creates its own encoder and connector.
  */
 int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv);
 
-/*
- * this function removes subdrv list from exynos drm driver and fb helper
- * and drm mode group would be re-initialized.
- */
+/* this function removes subdrv list from exynos drm driver */
 int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv);
 
+int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
+void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
+
+extern struct platform_driver fimd_driver;
+extern struct platform_driver hdmi_driver;
+extern struct platform_driver mixer_driver;
+extern struct platform_driver exynos_drm_common_hdmi_driver;
+extern struct platform_driver vidi_driver;
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index ef4754f..6e9ac7b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -111,9 +111,19 @@
 			       struct drm_display_mode *mode,
 			       struct drm_display_mode *adjusted_mode)
 {
+	struct drm_device *dev = encoder->dev;
+	struct drm_connector *connector;
+	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
+	struct exynos_drm_manager_ops *manager_ops = manager->ops;
+
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	/* drm framework doesn't check NULL. */
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		if (connector->encoder == encoder)
+			if (manager_ops && manager_ops->mode_fixup)
+				manager_ops->mode_fixup(manager->dev, connector,
+							mode, adjusted_mode);
+	}
 
 	return true;
 }
@@ -132,12 +142,11 @@
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	mode = adjusted_mode;
-
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		if (connector->encoder == encoder) {
 			if (manager_ops && manager_ops->mode_set)
-				manager_ops->mode_set(manager->dev, mode);
+				manager_ops->mode_set(manager->dev,
+							adjusted_mode);
 
 			if (overlay_ops && overlay_ops->mode_set)
 				overlay_ops->mode_set(manager->dev, overlay);
@@ -209,6 +218,7 @@
 		switch (display_ops->type) {
 		case EXYNOS_DISPLAY_TYPE_LCD:
 		case EXYNOS_DISPLAY_TYPE_HDMI:
+		case EXYNOS_DISPLAY_TYPE_VIDI:
 			clone_mask |= (1 << (cnt++));
 			break;
 		default:
@@ -433,9 +443,3 @@
 	if (overlay_ops && overlay_ops->disable)
 		overlay_ops->disable(manager->dev, zpos);
 }
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM Encoder Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 3733fe6..c38c8f4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -211,9 +211,3 @@
 
 	dev->mode_config.funcs = &exynos_drm_mode_config_funcs;
 }
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM FB Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 54f8f07..d5586cc 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -125,7 +125,9 @@
 	}
 
 	size = mode_cmd.pitches[0] * mode_cmd.height;
-	exynos_gem_obj = exynos_drm_gem_create(dev, size);
+
+	/* 0 means to allocate physically continuous memory */
+	exynos_gem_obj = exynos_drm_gem_create(dev, 0, size);
 	if (IS_ERR(exynos_gem_obj)) {
 		ret = PTR_ERR(exynos_gem_obj);
 		goto out;
@@ -314,89 +316,3 @@
 
 	drm_fb_helper_restore_fbdev_mode(private->fb_helper);
 }
-
-int exynos_drm_fbdev_reinit(struct drm_device *dev)
-{
-	struct exynos_drm_private *private = dev->dev_private;
-	struct drm_fb_helper *fb_helper;
-	int ret;
-
-	if (!private)
-		return -EINVAL;
-
-	/*
-	 * if all sub drivers were unloaded then num_connector is 0
-	 * so at this time, the framebuffers also should be destroyed.
-	 */
-	if (!dev->mode_config.num_connector) {
-		exynos_drm_fbdev_fini(dev);
-		return 0;
-	}
-
-	fb_helper = private->fb_helper;
-
-	if (fb_helper) {
-		struct list_head temp_list;
-
-		INIT_LIST_HEAD(&temp_list);
-
-		/*
-		 * fb_helper is reintialized but kernel fb is reused
-		 * so kernel_fb_list need to be backuped and restored
-		 */
-		if (!list_empty(&fb_helper->kernel_fb_list))
-			list_replace_init(&fb_helper->kernel_fb_list,
-					&temp_list);
-
-		drm_fb_helper_fini(fb_helper);
-
-		ret = drm_fb_helper_init(dev, fb_helper,
-				dev->mode_config.num_crtc, MAX_CONNECTOR);
-		if (ret < 0) {
-			DRM_ERROR("failed to initialize drm fb helper\n");
-			return ret;
-		}
-
-		if (!list_empty(&temp_list))
-			list_replace(&temp_list, &fb_helper->kernel_fb_list);
-
-		ret = drm_fb_helper_single_add_all_connectors(fb_helper);
-		if (ret < 0) {
-			DRM_ERROR("failed to add fb helper to connectors\n");
-			goto err;
-		}
-
-		ret = drm_fb_helper_initial_config(fb_helper, PREFERRED_BPP);
-		if (ret < 0) {
-			DRM_ERROR("failed to set up hw configuration.\n");
-			goto err;
-		}
-	} else {
-		/*
-		 * if drm_load() failed whem drm load() was called prior
-		 * to specific drivers, fb_helper must be NULL and so
-		 * this fuction should be called again to re-initialize and
-		 * re-configure the fb helper. it means that this function
-		 * has been called by the specific drivers.
-		 */
-		ret = exynos_drm_fbdev_init(dev);
-	}
-
-	return ret;
-
-err:
-	/*
-	 * if drm_load() failed when drm load() was called prior
-	 * to specific drivers, the fb_helper must be NULL and so check it.
-	 */
-	if (fb_helper)
-		drm_fb_helper_fini(fb_helper);
-
-	return ret;
-}
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM FBDEV Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 56458ee..ecb6db2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -1007,7 +1007,7 @@
 	SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL)
 };
 
-static struct platform_driver fimd_driver = {
+struct platform_driver fimd_driver = {
 	.probe		= fimd_probe,
 	.remove		= __devexit_p(fimd_remove),
 	.driver		= {
@@ -1016,21 +1016,3 @@
 		.pm	= &fimd_pm_ops,
 	},
 };
-
-static int __init fimd_init(void)
-{
-	return platform_driver_register(&fimd_driver);
-}
-
-static void __exit fimd_exit(void)
-{
-	platform_driver_unregister(&fimd_driver);
-}
-
-module_init(fimd_init);
-module_exit(fimd_exit);
-
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_DESCRIPTION("Samsung DRM FIMD Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 025abb3..fa1aa94 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -26,6 +26,7 @@
 #include "drmP.h"
 #include "drm.h"
 
+#include <linux/shmem_fs.h>
 #include <drm/exynos_drm.h>
 
 #include "exynos_drm_drv.h"
@@ -55,6 +56,178 @@
 	return out_msg;
 }
 
+static unsigned int mask_gem_flags(unsigned int flags)
+{
+	return flags &= EXYNOS_BO_NONCONTIG;
+}
+
+static struct page **exynos_gem_get_pages(struct drm_gem_object *obj,
+						gfp_t gfpmask)
+{
+	struct inode *inode;
+	struct address_space *mapping;
+	struct page *p, **pages;
+	int i, npages;
+
+	/* This is the shared memory object that backs the GEM resource */
+	inode = obj->filp->f_path.dentry->d_inode;
+	mapping = inode->i_mapping;
+
+	npages = obj->size >> PAGE_SHIFT;
+
+	pages = drm_malloc_ab(npages, sizeof(struct page *));
+	if (pages == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	gfpmask |= mapping_gfp_mask(mapping);
+
+	for (i = 0; i < npages; i++) {
+		p = shmem_read_mapping_page_gfp(mapping, i, gfpmask);
+		if (IS_ERR(p))
+			goto fail;
+		pages[i] = p;
+	}
+
+	return pages;
+
+fail:
+	while (i--)
+		page_cache_release(pages[i]);
+
+	drm_free_large(pages);
+	return ERR_PTR(PTR_ERR(p));
+}
+
+static void exynos_gem_put_pages(struct drm_gem_object *obj,
+					struct page **pages,
+					bool dirty, bool accessed)
+{
+	int i, npages;
+
+	npages = obj->size >> PAGE_SHIFT;
+
+	for (i = 0; i < npages; i++) {
+		if (dirty)
+			set_page_dirty(pages[i]);
+
+		if (accessed)
+			mark_page_accessed(pages[i]);
+
+		/* Undo the reference we took when populating the table */
+		page_cache_release(pages[i]);
+	}
+
+	drm_free_large(pages);
+}
+
+static int exynos_drm_gem_map_pages(struct drm_gem_object *obj,
+					struct vm_area_struct *vma,
+					unsigned long f_vaddr,
+					pgoff_t page_offset)
+{
+	struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
+	struct exynos_drm_gem_buf *buf = exynos_gem_obj->buffer;
+	unsigned long pfn;
+
+	if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) {
+		unsigned long usize = buf->size;
+
+		if (!buf->pages)
+			return -EINTR;
+
+		while (usize > 0) {
+			pfn = page_to_pfn(buf->pages[page_offset++]);
+			vm_insert_mixed(vma, f_vaddr, pfn);
+			f_vaddr += PAGE_SIZE;
+			usize -= PAGE_SIZE;
+		}
+
+		return 0;
+	}
+
+	pfn = (buf->dma_addr >> PAGE_SHIFT) + page_offset;
+
+	return vm_insert_mixed(vma, f_vaddr, pfn);
+}
+
+static int exynos_drm_gem_get_pages(struct drm_gem_object *obj)
+{
+	struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
+	struct exynos_drm_gem_buf *buf = exynos_gem_obj->buffer;
+	struct scatterlist *sgl;
+	struct page **pages;
+	unsigned int npages, i = 0;
+	int ret;
+
+	if (buf->pages) {
+		DRM_DEBUG_KMS("already allocated.\n");
+		return -EINVAL;
+	}
+
+	pages = exynos_gem_get_pages(obj, GFP_KERNEL);
+	if (IS_ERR(pages)) {
+		DRM_ERROR("failed to get pages.\n");
+		return PTR_ERR(pages);
+	}
+
+	npages = obj->size >> PAGE_SHIFT;
+
+	buf->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!buf->sgt) {
+		DRM_ERROR("failed to allocate sg table.\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = sg_alloc_table(buf->sgt, npages, GFP_KERNEL);
+	if (ret < 0) {
+		DRM_ERROR("failed to initialize sg table.\n");
+		ret = -EFAULT;
+		goto err1;
+	}
+
+	sgl = buf->sgt->sgl;
+
+	/* set all pages to sg list. */
+	while (i < npages) {
+		sg_set_page(sgl, pages[i], PAGE_SIZE, 0);
+		sg_dma_address(sgl) = page_to_phys(pages[i]);
+		i++;
+		sgl = sg_next(sgl);
+	}
+
+	/* add some codes for UNCACHED type here. TODO */
+
+	buf->pages = pages;
+	return ret;
+err1:
+	kfree(buf->sgt);
+	buf->sgt = NULL;
+err:
+	exynos_gem_put_pages(obj, pages, true, false);
+	return ret;
+
+}
+
+static void exynos_drm_gem_put_pages(struct drm_gem_object *obj)
+{
+	struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
+	struct exynos_drm_gem_buf *buf = exynos_gem_obj->buffer;
+
+	/*
+	 * if buffer typs is EXYNOS_BO_NONCONTIG then release all pages
+	 * allocated at gem fault handler.
+	 */
+	sg_free_table(buf->sgt);
+	kfree(buf->sgt);
+	buf->sgt = NULL;
+
+	exynos_gem_put_pages(obj, buf->pages, true, false);
+	buf->pages = NULL;
+
+	/* add some codes for UNCACHED type here. TODO */
+}
+
 static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
 					struct drm_file *file_priv,
 					unsigned int *handle)
@@ -90,7 +263,15 @@
 
 	DRM_DEBUG_KMS("handle count = %d\n", atomic_read(&obj->handle_count));
 
-	exynos_drm_buf_destroy(obj->dev, exynos_gem_obj->buffer);
+	if ((exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) &&
+			exynos_gem_obj->buffer->pages)
+		exynos_drm_gem_put_pages(obj);
+	else
+		exynos_drm_free_buf(obj->dev, exynos_gem_obj->flags,
+					exynos_gem_obj->buffer);
+
+	exynos_drm_fini_buf(obj->dev, exynos_gem_obj->buffer);
+	exynos_gem_obj->buffer = NULL;
 
 	if (obj->map_list.map)
 		drm_gem_free_mmap_offset(obj);
@@ -99,6 +280,7 @@
 	drm_gem_object_release(obj);
 
 	kfree(exynos_gem_obj);
+	exynos_gem_obj = NULL;
 }
 
 static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
@@ -114,6 +296,7 @@
 		return NULL;
 	}
 
+	exynos_gem_obj->size = size;
 	obj = &exynos_gem_obj->base;
 
 	ret = drm_gem_object_init(dev, obj, size);
@@ -129,27 +312,55 @@
 }
 
 struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
-						 unsigned long size)
+						unsigned int flags,
+						unsigned long size)
 {
-	struct exynos_drm_gem_buf *buffer;
 	struct exynos_drm_gem_obj *exynos_gem_obj;
+	struct exynos_drm_gem_buf *buf;
+	int ret;
 
 	size = roundup(size, PAGE_SIZE);
 	DRM_DEBUG_KMS("%s: size = 0x%lx\n", __FILE__, size);
 
-	buffer = exynos_drm_buf_create(dev, size);
-	if (!buffer)
+	flags = mask_gem_flags(flags);
+
+	buf = exynos_drm_init_buf(dev, size);
+	if (!buf)
 		return ERR_PTR(-ENOMEM);
 
 	exynos_gem_obj = exynos_drm_gem_init(dev, size);
 	if (!exynos_gem_obj) {
-		exynos_drm_buf_destroy(dev, buffer);
-		return ERR_PTR(-ENOMEM);
+		ret = -ENOMEM;
+		goto err;
 	}
 
-	exynos_gem_obj->buffer = buffer;
+	exynos_gem_obj->buffer = buf;
+
+	/* set memory type and cache attribute from user side. */
+	exynos_gem_obj->flags = flags;
+
+	/*
+	 * allocate all pages as desired size if user wants to allocate
+	 * physically non-continuous memory.
+	 */
+	if (flags & EXYNOS_BO_NONCONTIG) {
+		ret = exynos_drm_gem_get_pages(&exynos_gem_obj->base);
+		if (ret < 0) {
+			drm_gem_object_release(&exynos_gem_obj->base);
+			goto err;
+		}
+	} else {
+		ret = exynos_drm_alloc_buf(dev, buf, flags);
+		if (ret < 0) {
+			drm_gem_object_release(&exynos_gem_obj->base);
+			goto err;
+		}
+	}
 
 	return exynos_gem_obj;
+err:
+	exynos_drm_fini_buf(dev, buf);
+	return ERR_PTR(ret);
 }
 
 int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
@@ -161,7 +372,7 @@
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	exynos_gem_obj = exynos_drm_gem_create(dev, args->size);
+	exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
 	if (IS_ERR(exynos_gem_obj))
 		return PTR_ERR(exynos_gem_obj);
 
@@ -175,6 +386,64 @@
 	return 0;
 }
 
+void *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
+					unsigned int gem_handle,
+					struct drm_file *file_priv)
+{
+	struct exynos_drm_gem_obj *exynos_gem_obj;
+	struct drm_gem_object *obj;
+
+	obj = drm_gem_object_lookup(dev, file_priv, gem_handle);
+	if (!obj) {
+		DRM_ERROR("failed to lookup gem object.\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	exynos_gem_obj = to_exynos_gem_obj(obj);
+
+	if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) {
+		DRM_DEBUG_KMS("not support NONCONTIG type.\n");
+		drm_gem_object_unreference_unlocked(obj);
+
+		/* TODO */
+		return ERR_PTR(-EINVAL);
+	}
+
+	return &exynos_gem_obj->buffer->dma_addr;
+}
+
+void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
+					unsigned int gem_handle,
+					struct drm_file *file_priv)
+{
+	struct exynos_drm_gem_obj *exynos_gem_obj;
+	struct drm_gem_object *obj;
+
+	obj = drm_gem_object_lookup(dev, file_priv, gem_handle);
+	if (!obj) {
+		DRM_ERROR("failed to lookup gem object.\n");
+		return;
+	}
+
+	exynos_gem_obj = to_exynos_gem_obj(obj);
+
+	if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) {
+		DRM_DEBUG_KMS("not support NONCONTIG type.\n");
+		drm_gem_object_unreference_unlocked(obj);
+
+		/* TODO */
+		return;
+	}
+
+	drm_gem_object_unreference_unlocked(obj);
+
+	/*
+	 * decrease obj->refcount one more time because we has already
+	 * increased it at exynos_drm_gem_get_dma_addr().
+	 */
+	drm_gem_object_unreference_unlocked(obj);
+}
+
 int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
 				    struct drm_file *file_priv)
 {
@@ -200,7 +469,8 @@
 	struct drm_gem_object *obj = filp->private_data;
 	struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
 	struct exynos_drm_gem_buf *buffer;
-	unsigned long pfn, vm_size;
+	unsigned long pfn, vm_size, usize, uaddr = vma->vm_start;
+	int ret;
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -208,9 +478,9 @@
 
 	/* in case of direct mapping, always having non-cachable attribute */
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-	vma->vm_file = filp;
 
-	vm_size = vma->vm_end - vma->vm_start;
+	vm_size = usize = vma->vm_end - vma->vm_start;
+
 	/*
 	 * a buffer contains information to physically continuous memory
 	 * allocated by user request or at framebuffer creation.
@@ -221,18 +491,37 @@
 	if (vm_size > buffer->size)
 		return -EINVAL;
 
-	/*
-	 * get page frame number to physical memory to be mapped
-	 * to user space.
-	 */
-	pfn = ((unsigned long)exynos_gem_obj->buffer->dma_addr) >> PAGE_SHIFT;
+	if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) {
+		int i = 0;
 
-	DRM_DEBUG_KMS("pfn = 0x%lx\n", pfn);
+		if (!buffer->pages)
+			return -EINVAL;
 
-	if (remap_pfn_range(vma, vma->vm_start, pfn, vm_size,
-				vma->vm_page_prot)) {
-		DRM_ERROR("failed to remap pfn range.\n");
-		return -EAGAIN;
+		do {
+			ret = vm_insert_page(vma, uaddr, buffer->pages[i++]);
+			if (ret) {
+				DRM_ERROR("failed to remap user space.\n");
+				return ret;
+			}
+
+			uaddr += PAGE_SIZE;
+			usize -= PAGE_SIZE;
+		} while (usize > 0);
+	} else {
+		/*
+		 * get page frame number to physical memory to be mapped
+		 * to user space.
+		 */
+		pfn = ((unsigned long)exynos_gem_obj->buffer->dma_addr) >>
+								PAGE_SHIFT;
+
+		DRM_DEBUG_KMS("pfn = 0x%lx\n", pfn);
+
+		if (remap_pfn_range(vma, vma->vm_start, pfn, vm_size,
+					vma->vm_page_prot)) {
+			DRM_ERROR("failed to remap pfn range.\n");
+			return -EAGAIN;
+		}
 	}
 
 	return 0;
@@ -312,9 +601,9 @@
 	 */
 
 	args->pitch = args->width * args->bpp >> 3;
-	args->size = args->pitch * args->height;
+	args->size = PAGE_ALIGN(args->pitch * args->height);
 
-	exynos_gem_obj = exynos_drm_gem_create(dev, args->size);
+	exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
 	if (IS_ERR(exynos_gem_obj))
 		return PTR_ERR(exynos_gem_obj);
 
@@ -398,20 +687,31 @@
 	struct drm_gem_object *obj = vma->vm_private_data;
 	struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
 	struct drm_device *dev = obj->dev;
-	unsigned long pfn;
+	unsigned long f_vaddr;
 	pgoff_t page_offset;
 	int ret;
 
 	page_offset = ((unsigned long)vmf->virtual_address -
 			vma->vm_start) >> PAGE_SHIFT;
+	f_vaddr = (unsigned long)vmf->virtual_address;
 
 	mutex_lock(&dev->struct_mutex);
 
-	pfn = (((unsigned long)exynos_gem_obj->buffer->dma_addr) >>
-			PAGE_SHIFT) + page_offset;
+	/*
+	 * allocate all pages as desired size if user wants to allocate
+	 * physically non-continuous memory.
+	 */
+	if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) {
+		ret = exynos_drm_gem_get_pages(obj);
+		if (ret < 0)
+			goto err;
+	}
 
-	ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
+	ret = exynos_drm_gem_map_pages(obj, vma, f_vaddr, page_offset);
+	if (ret < 0)
+		DRM_ERROR("failed to map pages.\n");
 
+err:
 	mutex_unlock(&dev->struct_mutex);
 
 	return convert_to_vm_err_msg(ret);
@@ -435,7 +735,3 @@
 
 	return ret;
 }
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM GEM Module");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
index 67cdc91..e40fbad 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -36,11 +36,15 @@
  * @dma_addr: bus address(accessed by dma) to allocated memory region.
  *	- this address could be physical address without IOMMU and
  *	device address with IOMMU.
+ * @sgt: sg table to transfer page data.
+ * @pages: contain all pages to allocated memory region.
  * @size: size of allocated memory region.
  */
 struct exynos_drm_gem_buf {
 	void __iomem		*kvaddr;
 	dma_addr_t		dma_addr;
+	struct sg_table		*sgt;
+	struct page		**pages;
 	unsigned long		size;
 };
 
@@ -55,6 +59,8 @@
  *	by user request or at framebuffer creation.
  *	continuous memory region allocated by user request
  *	or at framebuffer creation.
+ * @size: total memory size to physically non-continuous memory region.
+ * @flags: indicate memory type to allocated buffer and cache attruibute.
  *
  * P.S. this object would be transfered to user as kms_bo.handle so
  *	user can access the buffer through kms_bo.handle.
@@ -62,6 +68,8 @@
 struct exynos_drm_gem_obj {
 	struct drm_gem_object		base;
 	struct exynos_drm_gem_buf	*buffer;
+	unsigned long			size;
+	unsigned int			flags;
 };
 
 /* destroy a buffer with gem object */
@@ -69,7 +77,8 @@
 
 /* create a new buffer with gem object */
 struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
-						 unsigned long size);
+						unsigned int flags,
+						unsigned long size);
 
 /*
  * request gem object creation and buffer allocation as the size
@@ -79,6 +88,24 @@
 int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
 				struct drm_file *file_priv);
 
+/*
+ * get dma address from gem handle and this function could be used for
+ * other drivers such as 2d/3d acceleration drivers.
+ * with this function call, gem object reference count would be increased.
+ */
+void *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
+					unsigned int gem_handle,
+					struct drm_file *file_priv);
+
+/*
+ * put dma address from gem handle and this function could be used for
+ * other drivers such as 2d/3d acceleration drivers.
+ * with this function call, gem object reference count would be decreased.
+ */
+void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
+					unsigned int gem_handle,
+					struct drm_file *file_priv);
+
 /* get buffer offset to map to user space. */
 int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
 				    struct drm_file *file_priv);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index ed8a319e..14eb26b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -38,7 +38,6 @@
 	struct exynos_drm_subdrv	subdrv;
 	struct exynos_drm_hdmi_context	*hdmi_ctx;
 	struct exynos_drm_hdmi_context	*mixer_ctx;
-	struct work_struct		work;
 };
 
 void exynos_drm_display_ops_register(struct exynos_hdmi_display_ops
@@ -49,7 +48,6 @@
 	if (display_ops)
 		hdmi_display_ops = display_ops;
 }
-EXPORT_SYMBOL(exynos_drm_display_ops_register);
 
 void exynos_drm_manager_ops_register(struct exynos_hdmi_manager_ops
 					*manager_ops)
@@ -59,7 +57,6 @@
 	if (manager_ops)
 		hdmi_manager_ops = manager_ops;
 }
-EXPORT_SYMBOL(exynos_drm_manager_ops_register);
 
 void exynos_drm_overlay_ops_register(struct exynos_hdmi_overlay_ops
 					*overlay_ops)
@@ -69,7 +66,6 @@
 	if (overlay_ops)
 		hdmi_overlay_ops = overlay_ops;
 }
-EXPORT_SYMBOL(exynos_drm_overlay_ops_register);
 
 static bool drm_hdmi_is_connected(struct device *dev)
 {
@@ -155,6 +151,20 @@
 		return hdmi_overlay_ops->disable_vblank(ctx->mixer_ctx->ctx);
 }
 
+static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
+				struct drm_connector *connector,
+				struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{
+	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (hdmi_manager_ops && hdmi_manager_ops->mode_fixup)
+		hdmi_manager_ops->mode_fixup(ctx->hdmi_ctx->ctx, connector,
+						mode, adjusted_mode);
+}
+
 static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
 {
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
@@ -165,6 +175,18 @@
 		hdmi_manager_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
 }
 
+static void drm_hdmi_get_max_resol(struct device *subdrv_dev,
+				unsigned int *width, unsigned int *height)
+{
+	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (hdmi_manager_ops && hdmi_manager_ops->get_max_resol)
+		hdmi_manager_ops->get_max_resol(ctx->hdmi_ctx->ctx, width,
+							height);
+}
+
 static void drm_hdmi_commit(struct device *subdrv_dev)
 {
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
@@ -200,7 +222,9 @@
 	.dpms = drm_hdmi_dpms,
 	.enable_vblank = drm_hdmi_enable_vblank,
 	.disable_vblank = drm_hdmi_disable_vblank,
+	.mode_fixup = drm_hdmi_mode_fixup,
 	.mode_set = drm_hdmi_mode_set,
+	.get_max_resol = drm_hdmi_get_max_resol,
 	.commit = drm_hdmi_commit,
 };
 
@@ -249,7 +273,6 @@
 	struct drm_hdmi_context *ctx;
 	struct platform_device *pdev = to_platform_device(dev);
 	struct exynos_drm_common_hdmi_pd *pd;
-	int ret;
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -270,26 +293,13 @@
 		return -EFAULT;
 	}
 
-	ret = platform_driver_register(&hdmi_driver);
-	if (ret) {
-		DRM_DEBUG_KMS("failed to register hdmi driver.\n");
-		return ret;
-	}
-
-	ret = platform_driver_register(&mixer_driver);
-	if (ret) {
-		DRM_DEBUG_KMS("failed to register mixer driver.\n");
-		goto err_hdmidrv;
-	}
-
 	ctx = get_ctx_from_subdrv(subdrv);
 
 	ctx->hdmi_ctx = (struct exynos_drm_hdmi_context *)
 				to_context(pd->hdmi_dev);
 	if (!ctx->hdmi_ctx) {
 		DRM_DEBUG_KMS("hdmi context is null.\n");
-		ret = -EFAULT;
-		goto err_mixerdrv;
+		return -EFAULT;
 	}
 
 	ctx->hdmi_ctx->drm_dev = drm_dev;
@@ -298,42 +308,12 @@
 				to_context(pd->mixer_dev);
 	if (!ctx->mixer_ctx) {
 		DRM_DEBUG_KMS("mixer context is null.\n");
-		ret = -EFAULT;
-		goto err_mixerdrv;
+		return -EFAULT;
 	}
 
 	ctx->mixer_ctx->drm_dev = drm_dev;
 
 	return 0;
-
-err_mixerdrv:
-	platform_driver_unregister(&mixer_driver);
-err_hdmidrv:
-	platform_driver_unregister(&hdmi_driver);
-	return ret;
-}
-
-static void hdmi_subdrv_remove(struct drm_device *drm_dev)
-{
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
-	platform_driver_unregister(&hdmi_driver);
-	platform_driver_unregister(&mixer_driver);
-}
-
-static void exynos_drm_hdmi_late_probe(struct work_struct *work)
-{
-	struct drm_hdmi_context *ctx = container_of(work,
-				struct drm_hdmi_context, work);
-
-	/*
-	 * this function calls subdrv->probe() so this must be called
-	 * after probe context.
-	 *
-	 * PS. subdrv->probe() will call platform_driver_register() to probe
-	 * hdmi and mixer driver.
-	 */
-	exynos_drm_subdrv_register(&ctx->subdrv);
 }
 
 static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
@@ -353,7 +333,6 @@
 	subdrv = &ctx->subdrv;
 
 	subdrv->probe = hdmi_subdrv_probe;
-	subdrv->remove = hdmi_subdrv_remove;
 	subdrv->manager.pipe = -1;
 	subdrv->manager.ops = &drm_hdmi_manager_ops;
 	subdrv->manager.overlay_ops = &drm_hdmi_overlay_ops;
@@ -362,9 +341,7 @@
 
 	platform_set_drvdata(pdev, subdrv);
 
-	INIT_WORK(&ctx->work, exynos_drm_hdmi_late_probe);
-
-	schedule_work(&ctx->work);
+	exynos_drm_subdrv_register(subdrv);
 
 	return 0;
 }
@@ -400,7 +377,7 @@
 	return 0;
 }
 
-static struct platform_driver exynos_drm_common_hdmi_driver = {
+struct platform_driver exynos_drm_common_hdmi_driver = {
 	.probe		= exynos_drm_hdmi_probe,
 	.remove		= __devexit_p(exynos_drm_hdmi_remove),
 	.driver		= {
@@ -409,31 +386,3 @@
 		.pm = &hdmi_pm_ops,
 	},
 };
-
-static int __init exynos_drm_hdmi_init(void)
-{
-	int ret;
-
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
-	ret = platform_driver_register(&exynos_drm_common_hdmi_driver);
-	if (ret) {
-		DRM_DEBUG_KMS("failed to register hdmi common driver.\n");
-		return ret;
-	}
-
-	return ret;
-}
-
-static void __exit exynos_drm_hdmi_exit(void)
-{
-	platform_driver_unregister(&exynos_drm_common_hdmi_driver);
-}
-
-module_init(exynos_drm_hdmi_init);
-module_exit(exynos_drm_hdmi_exit);
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM HDMI Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index 3c29f79..44497cf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -47,7 +47,12 @@
 };
 
 struct exynos_hdmi_manager_ops {
+	void (*mode_fixup)(void *ctx, struct drm_connector *connector,
+				struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode);
 	void (*mode_set)(void *ctx, void *mode);
+	void (*get_max_resol)(void *ctx, unsigned int *width,
+				unsigned int *height);
 	void (*commit)(void *ctx);
 	void (*disable)(void *ctx);
 };
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index bdcf770..c277a3a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -22,6 +22,10 @@
 	bool				enabled;
 };
 
+static const uint32_t formats[] = {
+	DRM_FORMAT_XRGB8888,
+};
+
 static int
 exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 		     struct drm_framebuffer *fb, int crtc_x, int crtc_y,
@@ -115,9 +119,9 @@
 
 	exynos_plane->overlay.zpos = DEFAULT_ZPOS;
 
-	/* TODO: format */
 	return drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
-			      &exynos_plane_funcs, NULL, 0, false);
+			      &exynos_plane_funcs, formats, ARRAY_SIZE(formats),
+			      false);
 }
 
 int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
new file mode 100644
index 0000000..8e1339f
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -0,0 +1,676 @@
+/* exynos_drm_vidi.c
+ *
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ * Authors:
+ *	Inki Dae <inki.dae@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 "drmP.h"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <drm/exynos_drm.h>
+
+#include "drm_edid.h"
+#include "drm_crtc_helper.h"
+
+#include "exynos_drm_drv.h"
+#include "exynos_drm_crtc.h"
+#include "exynos_drm_encoder.h"
+
+/* vidi has totally three virtual windows. */
+#define WINDOWS_NR		3
+
+#define get_vidi_context(dev)	platform_get_drvdata(to_platform_device(dev))
+
+struct vidi_win_data {
+	unsigned int		offset_x;
+	unsigned int		offset_y;
+	unsigned int		ovl_width;
+	unsigned int		ovl_height;
+	unsigned int		fb_width;
+	unsigned int		fb_height;
+	unsigned int		bpp;
+	dma_addr_t		dma_addr;
+	void __iomem		*vaddr;
+	unsigned int		buf_offsize;
+	unsigned int		line_size;	/* bytes */
+	bool			enabled;
+};
+
+struct vidi_context {
+	struct exynos_drm_subdrv	subdrv;
+	struct drm_crtc			*crtc;
+	struct vidi_win_data		win_data[WINDOWS_NR];
+	struct edid			*raw_edid;
+	unsigned int			clkdiv;
+	unsigned int			default_win;
+	unsigned long			irq_flags;
+	unsigned int			connected;
+	bool				vblank_on;
+	bool				suspended;
+	struct work_struct		work;
+	struct mutex			lock;
+};
+
+static const char fake_edid_info[] = {
+	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
+	0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
+	0x0a, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0xbd,
+	0xee, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x66, 0x21, 0x50, 0xb0, 0x51, 0x00,
+	0x1b, 0x30, 0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
+	0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
+	0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
+	0x4b, 0x1a, 0x44, 0x17, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47,
+	0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xbc, 0x02, 0x03, 0x1e, 0xf1,
+	0x46, 0x84, 0x05, 0x03, 0x10, 0x20, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83,
+	0x01, 0x00, 0x00, 0xe2, 0x00, 0x0f, 0x67, 0x03, 0x0c, 0x00, 0x10, 0x00,
+	0xb8, 0x2d, 0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c,
+	0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x9e, 0x8c, 0x0a, 0xd0, 0x8a,
+	0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00,
+	0x00, 0x18, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
+	0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x06
+};
+
+static void vidi_fake_vblank_handler(struct work_struct *work);
+
+static bool vidi_display_is_connected(struct device *dev)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/*
+	 * connection request would come from user side
+	 * to do hotplug through specific ioctl.
+	 */
+	return ctx->connected ? true : false;
+}
+
+static int vidi_get_edid(struct device *dev, struct drm_connector *connector,
+				u8 *edid, int len)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+	struct edid *raw_edid;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/*
+	 * the edid data comes from user side and it would be set
+	 * to ctx->raw_edid through specific ioctl.
+	 */
+	if (!ctx->raw_edid) {
+		DRM_DEBUG_KMS("raw_edid is null.\n");
+		return -EFAULT;
+	}
+
+	raw_edid = kzalloc(len, GFP_KERNEL);
+	if (!raw_edid) {
+		DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
+		return -ENOMEM;
+	}
+
+	memcpy(raw_edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions)
+						* EDID_LENGTH, len));
+
+	/* attach the edid data to connector. */
+	connector->display_info.raw_edid = (char *)raw_edid;
+
+	memcpy(edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions)
+					* EDID_LENGTH, len));
+
+	return 0;
+}
+
+static void *vidi_get_panel(struct device *dev)
+{
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/* TODO. */
+
+	return NULL;
+}
+
+static int vidi_check_timing(struct device *dev, void *timing)
+{
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/* TODO. */
+
+	return 0;
+}
+
+static int vidi_display_power_on(struct device *dev, int mode)
+{
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/* TODO */
+
+	return 0;
+}
+
+static struct exynos_drm_display_ops vidi_display_ops = {
+	.type = EXYNOS_DISPLAY_TYPE_VIDI,
+	.is_connected = vidi_display_is_connected,
+	.get_edid = vidi_get_edid,
+	.get_panel = vidi_get_panel,
+	.check_timing = vidi_check_timing,
+	.power_on = vidi_display_power_on,
+};
+
+static void vidi_dpms(struct device *subdrv_dev, int mode)
+{
+	struct vidi_context *ctx = get_vidi_context(subdrv_dev);
+
+	DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
+
+	mutex_lock(&ctx->lock);
+
+	switch (mode) {
+	case DRM_MODE_DPMS_ON:
+		/* TODO. */
+		break;
+	case DRM_MODE_DPMS_STANDBY:
+	case DRM_MODE_DPMS_SUSPEND:
+	case DRM_MODE_DPMS_OFF:
+		/* TODO. */
+		break;
+	default:
+		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+		break;
+	}
+
+	mutex_unlock(&ctx->lock);
+}
+
+static void vidi_apply(struct device *subdrv_dev)
+{
+	struct vidi_context *ctx = get_vidi_context(subdrv_dev);
+	struct exynos_drm_manager *mgr = &ctx->subdrv.manager;
+	struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
+	struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
+	struct vidi_win_data *win_data;
+	int i;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	for (i = 0; i < WINDOWS_NR; i++) {
+		win_data = &ctx->win_data[i];
+		if (win_data->enabled && (ovl_ops && ovl_ops->commit))
+			ovl_ops->commit(subdrv_dev, i);
+	}
+
+	if (mgr_ops && mgr_ops->commit)
+		mgr_ops->commit(subdrv_dev);
+}
+
+static void vidi_commit(struct device *dev)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (ctx->suspended)
+		return;
+}
+
+static int vidi_enable_vblank(struct device *dev)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (ctx->suspended)
+		return -EPERM;
+
+	if (!test_and_set_bit(0, &ctx->irq_flags))
+		ctx->vblank_on = true;
+
+	return 0;
+}
+
+static void vidi_disable_vblank(struct device *dev)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (ctx->suspended)
+		return;
+
+	if (test_and_clear_bit(0, &ctx->irq_flags))
+		ctx->vblank_on = false;
+}
+
+static struct exynos_drm_manager_ops vidi_manager_ops = {
+	.dpms = vidi_dpms,
+	.apply = vidi_apply,
+	.commit = vidi_commit,
+	.enable_vblank = vidi_enable_vblank,
+	.disable_vblank = vidi_disable_vblank,
+};
+
+static void vidi_win_mode_set(struct device *dev,
+			      struct exynos_drm_overlay *overlay)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+	struct vidi_win_data *win_data;
+	int win;
+	unsigned long offset;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (!overlay) {
+		dev_err(dev, "overlay is NULL\n");
+		return;
+	}
+
+	win = overlay->zpos;
+	if (win == DEFAULT_ZPOS)
+		win = ctx->default_win;
+
+	if (win < 0 || win > WINDOWS_NR)
+		return;
+
+	offset = overlay->fb_x * (overlay->bpp >> 3);
+	offset += overlay->fb_y * overlay->pitch;
+
+	DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
+
+	win_data = &ctx->win_data[win];
+
+	win_data->offset_x = overlay->crtc_x;
+	win_data->offset_y = overlay->crtc_y;
+	win_data->ovl_width = overlay->crtc_width;
+	win_data->ovl_height = overlay->crtc_height;
+	win_data->fb_width = overlay->fb_width;
+	win_data->fb_height = overlay->fb_height;
+	win_data->dma_addr = overlay->dma_addr[0] + offset;
+	win_data->vaddr = overlay->vaddr[0] + offset;
+	win_data->bpp = overlay->bpp;
+	win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
+				(overlay->bpp >> 3);
+	win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
+
+	/*
+	 * some parts of win_data should be transferred to user side
+	 * through specific ioctl.
+	 */
+
+	DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
+			win_data->offset_x, win_data->offset_y);
+	DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
+			win_data->ovl_width, win_data->ovl_height);
+	DRM_DEBUG_KMS("paddr = 0x%lx, vaddr = 0x%lx\n",
+			(unsigned long)win_data->dma_addr,
+			(unsigned long)win_data->vaddr);
+	DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
+			overlay->fb_width, overlay->crtc_width);
+}
+
+static void vidi_win_commit(struct device *dev, int zpos)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+	struct vidi_win_data *win_data;
+	int win = zpos;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (ctx->suspended)
+		return;
+
+	if (win == DEFAULT_ZPOS)
+		win = ctx->default_win;
+
+	if (win < 0 || win > WINDOWS_NR)
+		return;
+
+	win_data = &ctx->win_data[win];
+
+	win_data->enabled = true;
+
+	DRM_DEBUG_KMS("dma_addr = 0x%x\n", win_data->dma_addr);
+
+	if (ctx->vblank_on)
+		schedule_work(&ctx->work);
+}
+
+static void vidi_win_disable(struct device *dev, int zpos)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+	struct vidi_win_data *win_data;
+	int win = zpos;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (win == DEFAULT_ZPOS)
+		win = ctx->default_win;
+
+	if (win < 0 || win > WINDOWS_NR)
+		return;
+
+	win_data = &ctx->win_data[win];
+	win_data->enabled = false;
+
+	/* TODO. */
+}
+
+static struct exynos_drm_overlay_ops vidi_overlay_ops = {
+	.mode_set = vidi_win_mode_set,
+	.commit = vidi_win_commit,
+	.disable = vidi_win_disable,
+};
+
+static void vidi_finish_pageflip(struct drm_device *drm_dev, int crtc)
+{
+	struct exynos_drm_private *dev_priv = drm_dev->dev_private;
+	struct drm_pending_vblank_event *e, *t;
+	struct timeval now;
+	unsigned long flags;
+	bool is_checked = false;
+
+	spin_lock_irqsave(&drm_dev->event_lock, flags);
+
+	list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
+			base.link) {
+		/* if event's pipe isn't same as crtc then ignore it. */
+		if (crtc != e->pipe)
+			continue;
+
+		is_checked = true;
+
+		do_gettimeofday(&now);
+		e->event.sequence = 0;
+		e->event.tv_sec = now.tv_sec;
+		e->event.tv_usec = now.tv_usec;
+
+		list_move_tail(&e->base.link, &e->base.file_priv->event_list);
+		wake_up_interruptible(&e->base.file_priv->event_wait);
+	}
+
+	if (is_checked) {
+		/*
+		 * call drm_vblank_put only in case that drm_vblank_get was
+		 * called.
+		 */
+		if (atomic_read(&drm_dev->vblank_refcount[crtc]) > 0)
+			drm_vblank_put(drm_dev, crtc);
+
+		/*
+		 * don't off vblank if vblank_disable_allowed is 1,
+		 * because vblank would be off by timer handler.
+		 */
+		if (!drm_dev->vblank_disable_allowed)
+			drm_vblank_off(drm_dev, crtc);
+	}
+
+	spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+}
+
+static void vidi_fake_vblank_handler(struct work_struct *work)
+{
+	struct vidi_context *ctx = container_of(work, struct vidi_context,
+					work);
+	struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
+	struct exynos_drm_manager *manager = &subdrv->manager;
+
+	if (manager->pipe < 0)
+		return;
+
+	/* refresh rate is about 50Hz. */
+	usleep_range(16000, 20000);
+
+	drm_handle_vblank(subdrv->drm_dev, manager->pipe);
+	vidi_finish_pageflip(subdrv->drm_dev, manager->pipe);
+}
+
+static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
+{
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/*
+	 * enable drm irq mode.
+	 * - with irq_enabled = 1, we can use the vblank feature.
+	 *
+	 * P.S. note that we wouldn't use drm irq handler but
+	 *	just specific driver own one instead because
+	 *	drm framework supports only one irq handler.
+	 */
+	drm_dev->irq_enabled = 1;
+
+	/*
+	 * with vblank_disable_allowed = 1, vblank interrupt will be disabled
+	 * by drm timer once a current process gives up ownership of
+	 * vblank event.(after drm_vblank_put function is called)
+	 */
+	drm_dev->vblank_disable_allowed = 1;
+
+	return 0;
+}
+
+static void vidi_subdrv_remove(struct drm_device *drm_dev)
+{
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/* TODO. */
+}
+
+static int vidi_power_on(struct vidi_context *ctx, bool enable)
+{
+	struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
+	struct device *dev = subdrv->manager.dev;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (enable != false && enable != true)
+		return -EINVAL;
+
+	if (enable) {
+		ctx->suspended = false;
+
+		/* if vblank was enabled status, enable it again. */
+		if (test_and_clear_bit(0, &ctx->irq_flags))
+			vidi_enable_vblank(dev);
+
+		vidi_apply(dev);
+	} else {
+		ctx->suspended = true;
+	}
+
+	return 0;
+}
+
+static int vidi_show_connection(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int rc;
+	struct vidi_context *ctx = get_vidi_context(dev);
+
+	mutex_lock(&ctx->lock);
+
+	rc = sprintf(buf, "%d\n", ctx->connected);
+
+	mutex_unlock(&ctx->lock);
+
+	return rc;
+}
+
+static int vidi_store_connection(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t len)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+	int ret;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	ret = kstrtoint(buf, 0, &ctx->connected);
+	if (ret)
+		return ret;
+
+	if (ctx->connected > 1)
+		return -EINVAL;
+
+	DRM_DEBUG_KMS("requested connection.\n");
+
+	drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
+
+	return len;
+}
+
+static DEVICE_ATTR(connection, 0644, vidi_show_connection,
+			vidi_store_connection);
+
+int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
+				struct drm_file *file_priv)
+{
+	struct vidi_context *ctx = NULL;
+	struct drm_encoder *encoder;
+	struct exynos_drm_manager *manager;
+	struct exynos_drm_display_ops *display_ops;
+	struct drm_exynos_vidi_connection *vidi = data;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (!vidi) {
+		DRM_DEBUG_KMS("user data for vidi is null.\n");
+		return -EINVAL;
+	}
+
+	if (!vidi->edid) {
+		DRM_DEBUG_KMS("edid data is null.\n");
+		return -EINVAL;
+	}
+
+	if (vidi->connection > 1) {
+		DRM_DEBUG_KMS("connection should be 0 or 1.\n");
+		return -EINVAL;
+	}
+
+	list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
+								head) {
+		manager = exynos_drm_get_manager(encoder);
+		display_ops = manager->display_ops;
+
+		if (display_ops->type == EXYNOS_DISPLAY_TYPE_VIDI) {
+			ctx = get_vidi_context(manager->dev);
+			break;
+		}
+	}
+
+	if (!ctx) {
+		DRM_DEBUG_KMS("not found virtual device type encoder.\n");
+		return -EINVAL;
+	}
+
+	if (ctx->connected == vidi->connection) {
+		DRM_DEBUG_KMS("same connection request.\n");
+		return -EINVAL;
+	}
+
+	if (vidi->connection)
+		ctx->raw_edid = (struct edid *)vidi->edid;
+
+	ctx->connected = vidi->connection;
+	drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
+
+	return 0;
+}
+
+static int __devinit vidi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct vidi_context *ctx;
+	struct exynos_drm_subdrv *subdrv;
+	int ret;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->default_win = 0;
+
+	INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
+
+	/* for test */
+	ctx->raw_edid = (struct edid *)fake_edid_info;
+
+	subdrv = &ctx->subdrv;
+	subdrv->probe = vidi_subdrv_probe;
+	subdrv->remove = vidi_subdrv_remove;
+	subdrv->manager.pipe = -1;
+	subdrv->manager.ops = &vidi_manager_ops;
+	subdrv->manager.overlay_ops = &vidi_overlay_ops;
+	subdrv->manager.display_ops = &vidi_display_ops;
+	subdrv->manager.dev = dev;
+
+	mutex_init(&ctx->lock);
+
+	platform_set_drvdata(pdev, ctx);
+
+	ret = device_create_file(&pdev->dev, &dev_attr_connection);
+	if (ret < 0)
+		DRM_INFO("failed to create connection sysfs.\n");
+
+	exynos_drm_subdrv_register(subdrv);
+
+	return 0;
+}
+
+static int __devexit vidi_remove(struct platform_device *pdev)
+{
+	struct vidi_context *ctx = platform_get_drvdata(pdev);
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	exynos_drm_subdrv_unregister(&ctx->subdrv);
+
+	kfree(ctx);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int vidi_suspend(struct device *dev)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+
+	return vidi_power_on(ctx, false);
+}
+
+static int vidi_resume(struct device *dev)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+
+	return vidi_power_on(ctx, true);
+}
+#endif
+
+static const struct dev_pm_ops vidi_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(vidi_suspend, vidi_resume)
+};
+
+struct platform_driver vidi_driver = {
+	.probe		= vidi_probe,
+	.remove		= __devexit_p(vidi_remove),
+	.driver		= {
+		.name	= "exynos-drm-vidi",
+		.owner	= THIS_MODULE,
+		.pm	= &vidi_pm_ops,
+	},
+};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.h b/drivers/gpu/drm/exynos/exynos_drm_vidi.h
new file mode 100644
index 0000000..a4babe4
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.h
@@ -0,0 +1,36 @@
+/* exynos_drm_vidi.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * Author: Inki Dae <inki.dae@samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _EXYNOS_DRM_VIDI_H_
+#define _EXYNOS_DRM_VIDI_H_
+
+#ifdef CONFIG_DRM_EXYNOS_VIDI
+int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
+				struct drm_file *file_priv);
+#else
+#define vidi_connection_ioctl	NULL
+#endif
+
+#endif
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 3429d3f..575a8cb 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -41,44 +41,83 @@
 #include "exynos_hdmi.h"
 
 #define HDMI_OVERLAY_NUMBER	3
+#define MAX_WIDTH		1920
+#define MAX_HEIGHT		1080
 #define get_hdmi_context(dev)	platform_get_drvdata(to_platform_device(dev))
 
-static const u8 hdmiphy_conf27[32] = {
+struct hdmi_resources {
+	struct clk			*hdmi;
+	struct clk			*sclk_hdmi;
+	struct clk			*sclk_pixel;
+	struct clk			*sclk_hdmiphy;
+	struct clk			*hdmiphy;
+	struct regulator_bulk_data	*regul_bulk;
+	int				regul_count;
+};
+
+struct hdmi_context {
+	struct device			*dev;
+	struct drm_device		*drm_dev;
+	struct fb_videomode		*default_timing;
+	unsigned int			is_v13:1;
+	unsigned int			default_win;
+	unsigned int			default_bpp;
+	bool				hpd_handle;
+	bool				enabled;
+
+	struct resource			*regs_res;
+	void __iomem			*regs;
+	unsigned int			irq;
+	struct workqueue_struct		*wq;
+	struct work_struct		hotplug_work;
+
+	struct i2c_client		*ddc_port;
+	struct i2c_client		*hdmiphy_port;
+
+	/* current hdmiphy conf index */
+	int cur_conf;
+
+	struct hdmi_resources		res;
+	void				*parent_ctx;
+};
+
+/* HDMI Version 1.3 */
+static const u8 hdmiphy_v13_conf27[32] = {
 	0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
 	0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
 	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
 	0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
 };
 
-static const u8 hdmiphy_conf27_027[32] = {
+static const u8 hdmiphy_v13_conf27_027[32] = {
 	0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
 	0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
 	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
 	0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
 };
 
-static const u8 hdmiphy_conf74_175[32] = {
+static const u8 hdmiphy_v13_conf74_175[32] = {
 	0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
 	0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
 	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
 	0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
 };
 
-static const u8 hdmiphy_conf74_25[32] = {
+static const u8 hdmiphy_v13_conf74_25[32] = {
 	0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
 	0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
 	0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
 	0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
 };
 
-static const u8 hdmiphy_conf148_5[32] = {
+static const u8 hdmiphy_v13_conf148_5[32] = {
 	0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
 	0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
 	0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
 	0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
 };
 
-struct hdmi_tg_regs {
+struct hdmi_v13_tg_regs {
 	u8 cmd;
 	u8 h_fsz_l;
 	u8 h_fsz_h;
@@ -110,7 +149,7 @@
 	u8 field_bot_hdmi_h;
 };
 
-struct hdmi_core_regs {
+struct hdmi_v13_core_regs {
 	u8 h_blank[2];
 	u8 v_blank[3];
 	u8 h_v_line[3];
@@ -123,12 +162,21 @@
 	u8 v_sync_gen3[3];
 };
 
-struct hdmi_preset_conf {
-	struct hdmi_core_regs core;
-	struct hdmi_tg_regs tg;
+struct hdmi_v13_preset_conf {
+	struct hdmi_v13_core_regs core;
+	struct hdmi_v13_tg_regs tg;
 };
 
-static const struct hdmi_preset_conf hdmi_conf_480p = {
+struct hdmi_v13_conf {
+	int width;
+	int height;
+	int vrefresh;
+	bool interlace;
+	const u8 *hdmiphy_data;
+	const struct hdmi_v13_preset_conf *conf;
+};
+
+static const struct hdmi_v13_preset_conf hdmi_v13_conf_480p = {
 	.core = {
 		.h_blank = {0x8a, 0x00},
 		.v_blank = {0x0d, 0x6a, 0x01},
@@ -154,7 +202,7 @@
 	},
 };
 
-static const struct hdmi_preset_conf hdmi_conf_720p60 = {
+static const struct hdmi_v13_preset_conf hdmi_v13_conf_720p60 = {
 	.core = {
 		.h_blank = {0x72, 0x01},
 		.v_blank = {0xee, 0xf2, 0x00},
@@ -182,7 +230,7 @@
 	},
 };
 
-static const struct hdmi_preset_conf hdmi_conf_1080i50 = {
+static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080i50 = {
 	.core = {
 		.h_blank = {0xd0, 0x02},
 		.v_blank = {0x32, 0xB2, 0x00},
@@ -210,7 +258,7 @@
 	},
 };
 
-static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
+static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080p50 = {
 	.core = {
 		.h_blank = {0xd0, 0x02},
 		.v_blank = {0x65, 0x6c, 0x01},
@@ -238,7 +286,7 @@
 	},
 };
 
-static const struct hdmi_preset_conf hdmi_conf_1080i60 = {
+static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080i60 = {
 	.core = {
 		.h_blank = {0x18, 0x01},
 		.v_blank = {0x32, 0xB2, 0x00},
@@ -266,7 +314,7 @@
 	},
 };
 
-static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
+static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080p60 = {
 	.core = {
 		.h_blank = {0x18, 0x01},
 		.v_blank = {0x65, 0x6c, 0x01},
@@ -294,13 +342,530 @@
 	},
 };
 
+static const struct hdmi_v13_conf hdmi_v13_confs[] = {
+	{ 1280, 720, 60, false, hdmiphy_v13_conf74_25, &hdmi_v13_conf_720p60 },
+	{ 1280, 720, 50, false, hdmiphy_v13_conf74_25, &hdmi_v13_conf_720p60 },
+	{ 720, 480, 60, false, hdmiphy_v13_conf27_027, &hdmi_v13_conf_480p },
+	{ 1920, 1080, 50, true, hdmiphy_v13_conf74_25, &hdmi_v13_conf_1080i50 },
+	{ 1920, 1080, 50, false, hdmiphy_v13_conf148_5,
+				 &hdmi_v13_conf_1080p50 },
+	{ 1920, 1080, 60, true, hdmiphy_v13_conf74_25, &hdmi_v13_conf_1080i60 },
+	{ 1920, 1080, 60, false, hdmiphy_v13_conf148_5,
+				 &hdmi_v13_conf_1080p60 },
+};
+
+/* HDMI Version 1.4 */
+static const u8 hdmiphy_conf27_027[32] = {
+	0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
+	0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
+	0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+	0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
+};
+
+static const u8 hdmiphy_conf74_25[32] = {
+	0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
+	0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
+	0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+	0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
+};
+
+static const u8 hdmiphy_conf148_5[32] = {
+	0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
+	0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
+	0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+	0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
+};
+
+struct hdmi_tg_regs {
+	u8 cmd;
+	u8 h_fsz_l;
+	u8 h_fsz_h;
+	u8 hact_st_l;
+	u8 hact_st_h;
+	u8 hact_sz_l;
+	u8 hact_sz_h;
+	u8 v_fsz_l;
+	u8 v_fsz_h;
+	u8 vsync_l;
+	u8 vsync_h;
+	u8 vsync2_l;
+	u8 vsync2_h;
+	u8 vact_st_l;
+	u8 vact_st_h;
+	u8 vact_sz_l;
+	u8 vact_sz_h;
+	u8 field_chg_l;
+	u8 field_chg_h;
+	u8 vact_st2_l;
+	u8 vact_st2_h;
+	u8 vact_st3_l;
+	u8 vact_st3_h;
+	u8 vact_st4_l;
+	u8 vact_st4_h;
+	u8 vsync_top_hdmi_l;
+	u8 vsync_top_hdmi_h;
+	u8 vsync_bot_hdmi_l;
+	u8 vsync_bot_hdmi_h;
+	u8 field_top_hdmi_l;
+	u8 field_top_hdmi_h;
+	u8 field_bot_hdmi_l;
+	u8 field_bot_hdmi_h;
+	u8 tg_3d;
+};
+
+struct hdmi_core_regs {
+	u8 h_blank[2];
+	u8 v2_blank[2];
+	u8 v1_blank[2];
+	u8 v_line[2];
+	u8 h_line[2];
+	u8 hsync_pol[1];
+	u8 vsync_pol[1];
+	u8 int_pro_mode[1];
+	u8 v_blank_f0[2];
+	u8 v_blank_f1[2];
+	u8 h_sync_start[2];
+	u8 h_sync_end[2];
+	u8 v_sync_line_bef_2[2];
+	u8 v_sync_line_bef_1[2];
+	u8 v_sync_line_aft_2[2];
+	u8 v_sync_line_aft_1[2];
+	u8 v_sync_line_aft_pxl_2[2];
+	u8 v_sync_line_aft_pxl_1[2];
+	u8 v_blank_f2[2]; /* for 3D mode */
+	u8 v_blank_f3[2]; /* for 3D mode */
+	u8 v_blank_f4[2]; /* for 3D mode */
+	u8 v_blank_f5[2]; /* for 3D mode */
+	u8 v_sync_line_aft_3[2];
+	u8 v_sync_line_aft_4[2];
+	u8 v_sync_line_aft_5[2];
+	u8 v_sync_line_aft_6[2];
+	u8 v_sync_line_aft_pxl_3[2];
+	u8 v_sync_line_aft_pxl_4[2];
+	u8 v_sync_line_aft_pxl_5[2];
+	u8 v_sync_line_aft_pxl_6[2];
+	u8 vact_space_1[2];
+	u8 vact_space_2[2];
+	u8 vact_space_3[2];
+	u8 vact_space_4[2];
+	u8 vact_space_5[2];
+	u8 vact_space_6[2];
+};
+
+struct hdmi_preset_conf {
+	struct hdmi_core_regs core;
+	struct hdmi_tg_regs tg;
+};
+
+struct hdmi_conf {
+	int width;
+	int height;
+	int vrefresh;
+	bool interlace;
+	const u8 *hdmiphy_data;
+	const struct hdmi_preset_conf *conf;
+};
+
+static const struct hdmi_preset_conf hdmi_conf_480p60 = {
+	.core = {
+		.h_blank = {0x8a, 0x00},
+		.v2_blank = {0x0d, 0x02},
+		.v1_blank = {0x2d, 0x00},
+		.v_line = {0x0d, 0x02},
+		.h_line = {0x5a, 0x03},
+		.hsync_pol = {0x01},
+		.vsync_pol = {0x01},
+		.int_pro_mode = {0x00},
+		.v_blank_f0 = {0xff, 0xff},
+		.v_blank_f1 = {0xff, 0xff},
+		.h_sync_start = {0x0e, 0x00},
+		.h_sync_end = {0x4c, 0x00},
+		.v_sync_line_bef_2 = {0x0f, 0x00},
+		.v_sync_line_bef_1 = {0x09, 0x00},
+		.v_sync_line_aft_2 = {0xff, 0xff},
+		.v_sync_line_aft_1 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_2 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_1 = {0xff, 0xff},
+		.v_blank_f2 = {0xff, 0xff},
+		.v_blank_f3 = {0xff, 0xff},
+		.v_blank_f4 = {0xff, 0xff},
+		.v_blank_f5 = {0xff, 0xff},
+		.v_sync_line_aft_3 = {0xff, 0xff},
+		.v_sync_line_aft_4 = {0xff, 0xff},
+		.v_sync_line_aft_5 = {0xff, 0xff},
+		.v_sync_line_aft_6 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_3 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_4 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_5 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_6 = {0xff, 0xff},
+		.vact_space_1 = {0xff, 0xff},
+		.vact_space_2 = {0xff, 0xff},
+		.vact_space_3 = {0xff, 0xff},
+		.vact_space_4 = {0xff, 0xff},
+		.vact_space_5 = {0xff, 0xff},
+		.vact_space_6 = {0xff, 0xff},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x5a, 0x03, /* h_fsz */
+		0x8a, 0x00, 0xd0, 0x02, /* hact */
+		0x0d, 0x02, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x2d, 0x00, 0xe0, 0x01, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x48, 0x02, /* vact_st2 */
+		0x00, 0x00, /* vact_st3 */
+		0x00, 0x00, /* vact_st4 */
+		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+		0x00, /* 3d FP */
+	},
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p50 = {
+	.core = {
+		.h_blank = {0xbc, 0x02},
+		.v2_blank = {0xee, 0x02},
+		.v1_blank = {0x1e, 0x00},
+		.v_line = {0xee, 0x02},
+		.h_line = {0xbc, 0x07},
+		.hsync_pol = {0x00},
+		.vsync_pol = {0x00},
+		.int_pro_mode = {0x00},
+		.v_blank_f0 = {0xff, 0xff},
+		.v_blank_f1 = {0xff, 0xff},
+		.h_sync_start = {0xb6, 0x01},
+		.h_sync_end = {0xde, 0x01},
+		.v_sync_line_bef_2 = {0x0a, 0x00},
+		.v_sync_line_bef_1 = {0x05, 0x00},
+		.v_sync_line_aft_2 = {0xff, 0xff},
+		.v_sync_line_aft_1 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_2 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_1 = {0xff, 0xff},
+		.v_blank_f2 = {0xff, 0xff},
+		.v_blank_f3 = {0xff, 0xff},
+		.v_blank_f4 = {0xff, 0xff},
+		.v_blank_f5 = {0xff, 0xff},
+		.v_sync_line_aft_3 = {0xff, 0xff},
+		.v_sync_line_aft_4 = {0xff, 0xff},
+		.v_sync_line_aft_5 = {0xff, 0xff},
+		.v_sync_line_aft_6 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_3 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_4 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_5 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_6 = {0xff, 0xff},
+		.vact_space_1 = {0xff, 0xff},
+		.vact_space_2 = {0xff, 0xff},
+		.vact_space_3 = {0xff, 0xff},
+		.vact_space_4 = {0xff, 0xff},
+		.vact_space_5 = {0xff, 0xff},
+		.vact_space_6 = {0xff, 0xff},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0xbc, 0x07, /* h_fsz */
+		0xbc, 0x02, 0x00, 0x05, /* hact */
+		0xee, 0x02, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x1e, 0x00, 0xd0, 0x02, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x48, 0x02, /* vact_st2 */
+		0x00, 0x00, /* vact_st3 */
+		0x00, 0x00, /* vact_st4 */
+		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+		0x00, /* 3d FP */
+	},
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p60 = {
+	.core = {
+		.h_blank = {0x72, 0x01},
+		.v2_blank = {0xee, 0x02},
+		.v1_blank = {0x1e, 0x00},
+		.v_line = {0xee, 0x02},
+		.h_line = {0x72, 0x06},
+		.hsync_pol = {0x00},
+		.vsync_pol = {0x00},
+		.int_pro_mode = {0x00},
+		.v_blank_f0 = {0xff, 0xff},
+		.v_blank_f1 = {0xff, 0xff},
+		.h_sync_start = {0x6c, 0x00},
+		.h_sync_end = {0x94, 0x00},
+		.v_sync_line_bef_2 = {0x0a, 0x00},
+		.v_sync_line_bef_1 = {0x05, 0x00},
+		.v_sync_line_aft_2 = {0xff, 0xff},
+		.v_sync_line_aft_1 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_2 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_1 = {0xff, 0xff},
+		.v_blank_f2 = {0xff, 0xff},
+		.v_blank_f3 = {0xff, 0xff},
+		.v_blank_f4 = {0xff, 0xff},
+		.v_blank_f5 = {0xff, 0xff},
+		.v_sync_line_aft_3 = {0xff, 0xff},
+		.v_sync_line_aft_4 = {0xff, 0xff},
+		.v_sync_line_aft_5 = {0xff, 0xff},
+		.v_sync_line_aft_6 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_3 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_4 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_5 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_6 = {0xff, 0xff},
+		.vact_space_1 = {0xff, 0xff},
+		.vact_space_2 = {0xff, 0xff},
+		.vact_space_3 = {0xff, 0xff},
+		.vact_space_4 = {0xff, 0xff},
+		.vact_space_5 = {0xff, 0xff},
+		.vact_space_6 = {0xff, 0xff},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x72, 0x06, /* h_fsz */
+		0x72, 0x01, 0x00, 0x05, /* hact */
+		0xee, 0x02, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x1e, 0x00, 0xd0, 0x02, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x48, 0x02, /* vact_st2 */
+		0x00, 0x00, /* vact_st3 */
+		0x00, 0x00, /* vact_st4 */
+		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+		0x00, /* 3d FP */
+	},
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i50 = {
+	.core = {
+		.h_blank = {0xd0, 0x02},
+		.v2_blank = {0x32, 0x02},
+		.v1_blank = {0x16, 0x00},
+		.v_line = {0x65, 0x04},
+		.h_line = {0x50, 0x0a},
+		.hsync_pol = {0x00},
+		.vsync_pol = {0x00},
+		.int_pro_mode = {0x01},
+		.v_blank_f0 = {0x49, 0x02},
+		.v_blank_f1 = {0x65, 0x04},
+		.h_sync_start = {0x0e, 0x02},
+		.h_sync_end = {0x3a, 0x02},
+		.v_sync_line_bef_2 = {0x07, 0x00},
+		.v_sync_line_bef_1 = {0x02, 0x00},
+		.v_sync_line_aft_2 = {0x39, 0x02},
+		.v_sync_line_aft_1 = {0x34, 0x02},
+		.v_sync_line_aft_pxl_2 = {0x38, 0x07},
+		.v_sync_line_aft_pxl_1 = {0x38, 0x07},
+		.v_blank_f2 = {0xff, 0xff},
+		.v_blank_f3 = {0xff, 0xff},
+		.v_blank_f4 = {0xff, 0xff},
+		.v_blank_f5 = {0xff, 0xff},
+		.v_sync_line_aft_3 = {0xff, 0xff},
+		.v_sync_line_aft_4 = {0xff, 0xff},
+		.v_sync_line_aft_5 = {0xff, 0xff},
+		.v_sync_line_aft_6 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_3 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_4 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_5 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_6 = {0xff, 0xff},
+		.vact_space_1 = {0xff, 0xff},
+		.vact_space_2 = {0xff, 0xff},
+		.vact_space_3 = {0xff, 0xff},
+		.vact_space_4 = {0xff, 0xff},
+		.vact_space_5 = {0xff, 0xff},
+		.vact_space_6 = {0xff, 0xff},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x50, 0x0a, /* h_fsz */
+		0xd0, 0x02, 0x80, 0x07, /* hact */
+		0x65, 0x04, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x16, 0x00, 0x1c, 0x02, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x49, 0x02, /* vact_st2 */
+		0x00, 0x00, /* vact_st3 */
+		0x00, 0x00, /* vact_st4 */
+		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+		0x00, /* 3d FP */
+	},
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i60 = {
+	.core = {
+		.h_blank = {0x18, 0x01},
+		.v2_blank = {0x32, 0x02},
+		.v1_blank = {0x16, 0x00},
+		.v_line = {0x65, 0x04},
+		.h_line = {0x98, 0x08},
+		.hsync_pol = {0x00},
+		.vsync_pol = {0x00},
+		.int_pro_mode = {0x01},
+		.v_blank_f0 = {0x49, 0x02},
+		.v_blank_f1 = {0x65, 0x04},
+		.h_sync_start = {0x56, 0x00},
+		.h_sync_end = {0x82, 0x00},
+		.v_sync_line_bef_2 = {0x07, 0x00},
+		.v_sync_line_bef_1 = {0x02, 0x00},
+		.v_sync_line_aft_2 = {0x39, 0x02},
+		.v_sync_line_aft_1 = {0x34, 0x02},
+		.v_sync_line_aft_pxl_2 = {0xa4, 0x04},
+		.v_sync_line_aft_pxl_1 = {0xa4, 0x04},
+		.v_blank_f2 = {0xff, 0xff},
+		.v_blank_f3 = {0xff, 0xff},
+		.v_blank_f4 = {0xff, 0xff},
+		.v_blank_f5 = {0xff, 0xff},
+		.v_sync_line_aft_3 = {0xff, 0xff},
+		.v_sync_line_aft_4 = {0xff, 0xff},
+		.v_sync_line_aft_5 = {0xff, 0xff},
+		.v_sync_line_aft_6 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_3 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_4 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_5 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_6 = {0xff, 0xff},
+		.vact_space_1 = {0xff, 0xff},
+		.vact_space_2 = {0xff, 0xff},
+		.vact_space_3 = {0xff, 0xff},
+		.vact_space_4 = {0xff, 0xff},
+		.vact_space_5 = {0xff, 0xff},
+		.vact_space_6 = {0xff, 0xff},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x98, 0x08, /* h_fsz */
+		0x18, 0x01, 0x80, 0x07, /* hact */
+		0x65, 0x04, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x16, 0x00, 0x1c, 0x02, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x49, 0x02, /* vact_st2 */
+		0x00, 0x00, /* vact_st3 */
+		0x00, 0x00, /* vact_st4 */
+		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+		0x00, /* 3d FP */
+	},
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
+	.core = {
+		.h_blank = {0xd0, 0x02},
+		.v2_blank = {0x65, 0x04},
+		.v1_blank = {0x2d, 0x00},
+		.v_line = {0x65, 0x04},
+		.h_line = {0x50, 0x0a},
+		.hsync_pol = {0x00},
+		.vsync_pol = {0x00},
+		.int_pro_mode = {0x00},
+		.v_blank_f0 = {0xff, 0xff},
+		.v_blank_f1 = {0xff, 0xff},
+		.h_sync_start = {0x0e, 0x02},
+		.h_sync_end = {0x3a, 0x02},
+		.v_sync_line_bef_2 = {0x09, 0x00},
+		.v_sync_line_bef_1 = {0x04, 0x00},
+		.v_sync_line_aft_2 = {0xff, 0xff},
+		.v_sync_line_aft_1 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_2 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_1 = {0xff, 0xff},
+		.v_blank_f2 = {0xff, 0xff},
+		.v_blank_f3 = {0xff, 0xff},
+		.v_blank_f4 = {0xff, 0xff},
+		.v_blank_f5 = {0xff, 0xff},
+		.v_sync_line_aft_3 = {0xff, 0xff},
+		.v_sync_line_aft_4 = {0xff, 0xff},
+		.v_sync_line_aft_5 = {0xff, 0xff},
+		.v_sync_line_aft_6 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_3 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_4 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_5 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_6 = {0xff, 0xff},
+		.vact_space_1 = {0xff, 0xff},
+		.vact_space_2 = {0xff, 0xff},
+		.vact_space_3 = {0xff, 0xff},
+		.vact_space_4 = {0xff, 0xff},
+		.vact_space_5 = {0xff, 0xff},
+		.vact_space_6 = {0xff, 0xff},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x50, 0x0a, /* h_fsz */
+		0xd0, 0x02, 0x80, 0x07, /* hact */
+		0x65, 0x04, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x2d, 0x00, 0x38, 0x04, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x48, 0x02, /* vact_st2 */
+		0x00, 0x00, /* vact_st3 */
+		0x00, 0x00, /* vact_st4 */
+		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+		0x00, /* 3d FP */
+	},
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
+	.core = {
+		.h_blank = {0x18, 0x01},
+		.v2_blank = {0x65, 0x04},
+		.v1_blank = {0x2d, 0x00},
+		.v_line = {0x65, 0x04},
+		.h_line = {0x98, 0x08},
+		.hsync_pol = {0x00},
+		.vsync_pol = {0x00},
+		.int_pro_mode = {0x00},
+		.v_blank_f0 = {0xff, 0xff},
+		.v_blank_f1 = {0xff, 0xff},
+		.h_sync_start = {0x56, 0x00},
+		.h_sync_end = {0x82, 0x00},
+		.v_sync_line_bef_2 = {0x09, 0x00},
+		.v_sync_line_bef_1 = {0x04, 0x00},
+		.v_sync_line_aft_2 = {0xff, 0xff},
+		.v_sync_line_aft_1 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_2 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_1 = {0xff, 0xff},
+		.v_blank_f2 = {0xff, 0xff},
+		.v_blank_f3 = {0xff, 0xff},
+		.v_blank_f4 = {0xff, 0xff},
+		.v_blank_f5 = {0xff, 0xff},
+		.v_sync_line_aft_3 = {0xff, 0xff},
+		.v_sync_line_aft_4 = {0xff, 0xff},
+		.v_sync_line_aft_5 = {0xff, 0xff},
+		.v_sync_line_aft_6 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_3 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_4 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_5 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_6 = {0xff, 0xff},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x98, 0x08, /* h_fsz */
+		0x18, 0x01, 0x80, 0x07, /* hact */
+		0x65, 0x04, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x2d, 0x00, 0x38, 0x04, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x48, 0x02, /* vact_st2 */
+		0x00, 0x00, /* vact_st3 */
+		0x00, 0x00, /* vact_st4 */
+		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+		0x00, /* 3d FP */
+	},
+};
+
 static const struct hdmi_conf hdmi_confs[] = {
+	{ 720, 480, 60, false, hdmiphy_conf27_027, &hdmi_conf_480p60 },
+	{ 1280, 720, 50, false, hdmiphy_conf74_25, &hdmi_conf_720p50 },
 	{ 1280, 720, 60, false, hdmiphy_conf74_25, &hdmi_conf_720p60 },
-	{ 1280, 720, 50, false, hdmiphy_conf74_25, &hdmi_conf_720p60 },
-	{ 720, 480, 60, false, hdmiphy_conf27_027, &hdmi_conf_480p },
 	{ 1920, 1080, 50, true, hdmiphy_conf74_25, &hdmi_conf_1080i50 },
-	{ 1920, 1080, 50, false, hdmiphy_conf148_5, &hdmi_conf_1080p50 },
 	{ 1920, 1080, 60, true, hdmiphy_conf74_25, &hdmi_conf_1080i60 },
+	{ 1920, 1080, 50, false, hdmiphy_conf148_5, &hdmi_conf_1080p50 },
 	{ 1920, 1080, 60, false, hdmiphy_conf148_5, &hdmi_conf_1080p60 },
 };
 
@@ -324,7 +889,7 @@
 	writel(value, hdata->regs + reg_id);
 }
 
-static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
+static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
 {
 #define DUMPREG(reg_id) \
 	DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
@@ -333,50 +898,50 @@
 	DUMPREG(HDMI_INTC_FLAG);
 	DUMPREG(HDMI_INTC_CON);
 	DUMPREG(HDMI_HPD_STATUS);
-	DUMPREG(HDMI_PHY_RSTOUT);
-	DUMPREG(HDMI_PHY_VPLL);
-	DUMPREG(HDMI_PHY_CMU);
-	DUMPREG(HDMI_CORE_RSTOUT);
+	DUMPREG(HDMI_V13_PHY_RSTOUT);
+	DUMPREG(HDMI_V13_PHY_VPLL);
+	DUMPREG(HDMI_V13_PHY_CMU);
+	DUMPREG(HDMI_V13_CORE_RSTOUT);
 
 	DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
 	DUMPREG(HDMI_CON_0);
 	DUMPREG(HDMI_CON_1);
 	DUMPREG(HDMI_CON_2);
 	DUMPREG(HDMI_SYS_STATUS);
-	DUMPREG(HDMI_PHY_STATUS);
+	DUMPREG(HDMI_V13_PHY_STATUS);
 	DUMPREG(HDMI_STATUS_EN);
 	DUMPREG(HDMI_HPD);
 	DUMPREG(HDMI_MODE_SEL);
-	DUMPREG(HDMI_HPD_GEN);
-	DUMPREG(HDMI_DC_CONTROL);
-	DUMPREG(HDMI_VIDEO_PATTERN_GEN);
+	DUMPREG(HDMI_V13_HPD_GEN);
+	DUMPREG(HDMI_V13_DC_CONTROL);
+	DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
 
 	DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
 	DUMPREG(HDMI_H_BLANK_0);
 	DUMPREG(HDMI_H_BLANK_1);
-	DUMPREG(HDMI_V_BLANK_0);
-	DUMPREG(HDMI_V_BLANK_1);
-	DUMPREG(HDMI_V_BLANK_2);
-	DUMPREG(HDMI_H_V_LINE_0);
-	DUMPREG(HDMI_H_V_LINE_1);
-	DUMPREG(HDMI_H_V_LINE_2);
+	DUMPREG(HDMI_V13_V_BLANK_0);
+	DUMPREG(HDMI_V13_V_BLANK_1);
+	DUMPREG(HDMI_V13_V_BLANK_2);
+	DUMPREG(HDMI_V13_H_V_LINE_0);
+	DUMPREG(HDMI_V13_H_V_LINE_1);
+	DUMPREG(HDMI_V13_H_V_LINE_2);
 	DUMPREG(HDMI_VSYNC_POL);
 	DUMPREG(HDMI_INT_PRO_MODE);
-	DUMPREG(HDMI_V_BLANK_F_0);
-	DUMPREG(HDMI_V_BLANK_F_1);
-	DUMPREG(HDMI_V_BLANK_F_2);
-	DUMPREG(HDMI_H_SYNC_GEN_0);
-	DUMPREG(HDMI_H_SYNC_GEN_1);
-	DUMPREG(HDMI_H_SYNC_GEN_2);
-	DUMPREG(HDMI_V_SYNC_GEN_1_0);
-	DUMPREG(HDMI_V_SYNC_GEN_1_1);
-	DUMPREG(HDMI_V_SYNC_GEN_1_2);
-	DUMPREG(HDMI_V_SYNC_GEN_2_0);
-	DUMPREG(HDMI_V_SYNC_GEN_2_1);
-	DUMPREG(HDMI_V_SYNC_GEN_2_2);
-	DUMPREG(HDMI_V_SYNC_GEN_3_0);
-	DUMPREG(HDMI_V_SYNC_GEN_3_1);
-	DUMPREG(HDMI_V_SYNC_GEN_3_2);
+	DUMPREG(HDMI_V13_V_BLANK_F_0);
+	DUMPREG(HDMI_V13_V_BLANK_F_1);
+	DUMPREG(HDMI_V13_V_BLANK_F_2);
+	DUMPREG(HDMI_V13_H_SYNC_GEN_0);
+	DUMPREG(HDMI_V13_H_SYNC_GEN_1);
+	DUMPREG(HDMI_V13_H_SYNC_GEN_2);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
 
 	DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
 	DUMPREG(HDMI_TG_CMD);
@@ -411,7 +976,198 @@
 #undef DUMPREG
 }
 
-static int hdmi_conf_index(struct drm_display_mode *mode)
+static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
+{
+	int i;
+
+#define DUMPREG(reg_id) \
+	DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
+	readl(hdata->regs + reg_id))
+
+	DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_INTC_CON);
+	DUMPREG(HDMI_INTC_FLAG);
+	DUMPREG(HDMI_HPD_STATUS);
+	DUMPREG(HDMI_INTC_CON_1);
+	DUMPREG(HDMI_INTC_FLAG_1);
+	DUMPREG(HDMI_PHY_STATUS_0);
+	DUMPREG(HDMI_PHY_STATUS_PLL);
+	DUMPREG(HDMI_PHY_CON_0);
+	DUMPREG(HDMI_PHY_RSTOUT);
+	DUMPREG(HDMI_PHY_VPLL);
+	DUMPREG(HDMI_PHY_CMU);
+	DUMPREG(HDMI_CORE_RSTOUT);
+
+	DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_CON_0);
+	DUMPREG(HDMI_CON_1);
+	DUMPREG(HDMI_CON_2);
+	DUMPREG(HDMI_SYS_STATUS);
+	DUMPREG(HDMI_PHY_STATUS_0);
+	DUMPREG(HDMI_STATUS_EN);
+	DUMPREG(HDMI_HPD);
+	DUMPREG(HDMI_MODE_SEL);
+	DUMPREG(HDMI_ENC_EN);
+	DUMPREG(HDMI_DC_CONTROL);
+	DUMPREG(HDMI_VIDEO_PATTERN_GEN);
+
+	DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_H_BLANK_0);
+	DUMPREG(HDMI_H_BLANK_1);
+	DUMPREG(HDMI_V2_BLANK_0);
+	DUMPREG(HDMI_V2_BLANK_1);
+	DUMPREG(HDMI_V1_BLANK_0);
+	DUMPREG(HDMI_V1_BLANK_1);
+	DUMPREG(HDMI_V_LINE_0);
+	DUMPREG(HDMI_V_LINE_1);
+	DUMPREG(HDMI_H_LINE_0);
+	DUMPREG(HDMI_H_LINE_1);
+	DUMPREG(HDMI_HSYNC_POL);
+
+	DUMPREG(HDMI_VSYNC_POL);
+	DUMPREG(HDMI_INT_PRO_MODE);
+	DUMPREG(HDMI_V_BLANK_F0_0);
+	DUMPREG(HDMI_V_BLANK_F0_1);
+	DUMPREG(HDMI_V_BLANK_F1_0);
+	DUMPREG(HDMI_V_BLANK_F1_1);
+
+	DUMPREG(HDMI_H_SYNC_START_0);
+	DUMPREG(HDMI_H_SYNC_START_1);
+	DUMPREG(HDMI_H_SYNC_END_0);
+	DUMPREG(HDMI_H_SYNC_END_1);
+
+	DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
+	DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
+	DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
+	DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
+
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
+
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
+
+	DUMPREG(HDMI_V_BLANK_F2_0);
+	DUMPREG(HDMI_V_BLANK_F2_1);
+	DUMPREG(HDMI_V_BLANK_F3_0);
+	DUMPREG(HDMI_V_BLANK_F3_1);
+	DUMPREG(HDMI_V_BLANK_F4_0);
+	DUMPREG(HDMI_V_BLANK_F4_1);
+	DUMPREG(HDMI_V_BLANK_F5_0);
+	DUMPREG(HDMI_V_BLANK_F5_1);
+
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
+
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
+
+	DUMPREG(HDMI_VACT_SPACE_1_0);
+	DUMPREG(HDMI_VACT_SPACE_1_1);
+	DUMPREG(HDMI_VACT_SPACE_2_0);
+	DUMPREG(HDMI_VACT_SPACE_2_1);
+	DUMPREG(HDMI_VACT_SPACE_3_0);
+	DUMPREG(HDMI_VACT_SPACE_3_1);
+	DUMPREG(HDMI_VACT_SPACE_4_0);
+	DUMPREG(HDMI_VACT_SPACE_4_1);
+	DUMPREG(HDMI_VACT_SPACE_5_0);
+	DUMPREG(HDMI_VACT_SPACE_5_1);
+	DUMPREG(HDMI_VACT_SPACE_6_0);
+	DUMPREG(HDMI_VACT_SPACE_6_1);
+
+	DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_TG_CMD);
+	DUMPREG(HDMI_TG_H_FSZ_L);
+	DUMPREG(HDMI_TG_H_FSZ_H);
+	DUMPREG(HDMI_TG_HACT_ST_L);
+	DUMPREG(HDMI_TG_HACT_ST_H);
+	DUMPREG(HDMI_TG_HACT_SZ_L);
+	DUMPREG(HDMI_TG_HACT_SZ_H);
+	DUMPREG(HDMI_TG_V_FSZ_L);
+	DUMPREG(HDMI_TG_V_FSZ_H);
+	DUMPREG(HDMI_TG_VSYNC_L);
+	DUMPREG(HDMI_TG_VSYNC_H);
+	DUMPREG(HDMI_TG_VSYNC2_L);
+	DUMPREG(HDMI_TG_VSYNC2_H);
+	DUMPREG(HDMI_TG_VACT_ST_L);
+	DUMPREG(HDMI_TG_VACT_ST_H);
+	DUMPREG(HDMI_TG_VACT_SZ_L);
+	DUMPREG(HDMI_TG_VACT_SZ_H);
+	DUMPREG(HDMI_TG_FIELD_CHG_L);
+	DUMPREG(HDMI_TG_FIELD_CHG_H);
+	DUMPREG(HDMI_TG_VACT_ST2_L);
+	DUMPREG(HDMI_TG_VACT_ST2_H);
+	DUMPREG(HDMI_TG_VACT_ST3_L);
+	DUMPREG(HDMI_TG_VACT_ST3_H);
+	DUMPREG(HDMI_TG_VACT_ST4_L);
+	DUMPREG(HDMI_TG_VACT_ST4_H);
+	DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
+	DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
+	DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
+	DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
+	DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
+	DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
+	DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
+	DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
+	DUMPREG(HDMI_TG_3D);
+
+	DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_AVI_CON);
+	DUMPREG(HDMI_AVI_HEADER0);
+	DUMPREG(HDMI_AVI_HEADER1);
+	DUMPREG(HDMI_AVI_HEADER2);
+	DUMPREG(HDMI_AVI_CHECK_SUM);
+	DUMPREG(HDMI_VSI_CON);
+	DUMPREG(HDMI_VSI_HEADER0);
+	DUMPREG(HDMI_VSI_HEADER1);
+	DUMPREG(HDMI_VSI_HEADER2);
+	for (i = 0; i < 7; ++i)
+		DUMPREG(HDMI_VSI_DATA(i));
+
+#undef DUMPREG
+}
+
+static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
+{
+	if (hdata->is_v13)
+		hdmi_v13_regs_dump(hdata, prefix);
+	else
+		hdmi_v14_regs_dump(hdata, prefix);
+}
+
+static int hdmi_v13_conf_index(struct drm_display_mode *mode)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hdmi_v13_confs); ++i)
+		if (hdmi_v13_confs[i].width == mode->hdisplay &&
+				hdmi_v13_confs[i].height == mode->vdisplay &&
+				hdmi_v13_confs[i].vrefresh == mode->vrefresh &&
+				hdmi_v13_confs[i].interlace ==
+				((mode->flags & DRM_MODE_FLAG_INTERLACE) ?
+				 true : false))
+			return i;
+
+	return -EINVAL;
+}
+
+static int hdmi_v14_conf_index(struct drm_display_mode *mode)
 {
 	int i;
 
@@ -424,7 +1180,16 @@
 				 true : false))
 			return i;
 
-	return -1;
+	return -EINVAL;
+}
+
+static int hdmi_conf_index(struct hdmi_context *hdata,
+			   struct drm_display_mode *mode)
+{
+	if (hdata->is_v13)
+		return hdmi_v13_conf_index(mode);
+
+	return hdmi_v14_conf_index(mode);
 }
 
 static bool hdmi_is_connected(void *ctx)
@@ -462,10 +1227,56 @@
 	return 0;
 }
 
+static int hdmi_v13_check_timing(struct fb_videomode *check_timing)
+{
+	int i;
+
+	DRM_DEBUG_KMS("valid mode : xres=%d, yres=%d, refresh=%d, intl=%d\n",
+			check_timing->xres, check_timing->yres,
+			check_timing->refresh, (check_timing->vmode &
+			FB_VMODE_INTERLACED) ? true : false);
+
+	for (i = 0; i < ARRAY_SIZE(hdmi_v13_confs); ++i)
+		if (hdmi_v13_confs[i].width == check_timing->xres &&
+			hdmi_v13_confs[i].height == check_timing->yres &&
+			hdmi_v13_confs[i].vrefresh == check_timing->refresh &&
+			hdmi_v13_confs[i].interlace ==
+			((check_timing->vmode & FB_VMODE_INTERLACED) ?
+			 true : false))
+				return 0;
+
+	/* TODO */
+
+	return -EINVAL;
+}
+
+static int hdmi_v14_check_timing(struct fb_videomode *check_timing)
+{
+	int i;
+
+	DRM_DEBUG_KMS("valid mode : xres=%d, yres=%d, refresh=%d, intl=%d\n",
+			check_timing->xres, check_timing->yres,
+			check_timing->refresh, (check_timing->vmode &
+			FB_VMODE_INTERLACED) ? true : false);
+
+	for (i = 0; i < ARRAY_SIZE(hdmi_confs); i++)
+		if (hdmi_confs[i].width == check_timing->xres &&
+			hdmi_confs[i].height == check_timing->yres &&
+			hdmi_confs[i].vrefresh == check_timing->refresh &&
+			hdmi_confs[i].interlace ==
+			((check_timing->vmode & FB_VMODE_INTERLACED) ?
+			 true : false))
+				return 0;
+
+	/* TODO */
+
+	return -EINVAL;
+}
+
 static int hdmi_check_timing(void *ctx, void *timing)
 {
+	struct hdmi_context *hdata = (struct hdmi_context *)ctx;
 	struct fb_videomode *check_timing = timing;
-	int i;
 
 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
@@ -473,16 +1284,10 @@
 			check_timing->yres, check_timing->refresh,
 			check_timing->vmode);
 
-	for (i = 0; i < ARRAY_SIZE(hdmi_confs); ++i)
-		if (hdmi_confs[i].width == check_timing->xres &&
-			hdmi_confs[i].height == check_timing->yres &&
-			hdmi_confs[i].vrefresh == check_timing->refresh &&
-			hdmi_confs[i].interlace ==
-			((check_timing->vmode & FB_VMODE_INTERLACED) ?
-			 true : false))
-			return 0;
-
-	return -EINVAL;
+	if (hdata->is_v13)
+		return hdmi_v13_check_timing(check_timing);
+	else
+		return hdmi_v14_check_timing(check_timing);
 }
 
 static int hdmi_display_power_on(void *ctx, int mode)
@@ -514,15 +1319,185 @@
 	.power_on	= hdmi_display_power_on,
 };
 
+static void hdmi_set_acr(u32 freq, u8 *acr)
+{
+	u32 n, cts;
+
+	switch (freq) {
+	case 32000:
+		n = 4096;
+		cts = 27000;
+		break;
+	case 44100:
+		n = 6272;
+		cts = 30000;
+		break;
+	case 88200:
+		n = 12544;
+		cts = 30000;
+		break;
+	case 176400:
+		n = 25088;
+		cts = 30000;
+		break;
+	case 48000:
+		n = 6144;
+		cts = 27000;
+		break;
+	case 96000:
+		n = 12288;
+		cts = 27000;
+		break;
+	case 192000:
+		n = 24576;
+		cts = 27000;
+		break;
+	default:
+		n = 0;
+		cts = 0;
+		break;
+	}
+
+	acr[1] = cts >> 16;
+	acr[2] = cts >> 8 & 0xff;
+	acr[3] = cts & 0xff;
+
+	acr[4] = n >> 16;
+	acr[5] = n >> 8 & 0xff;
+	acr[6] = n & 0xff;
+}
+
+static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
+{
+	hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
+	hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
+	hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
+	hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
+	hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
+	hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
+	hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
+	hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
+	hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
+
+	if (hdata->is_v13)
+		hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
+	else
+		hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
+}
+
+static void hdmi_audio_init(struct hdmi_context *hdata)
+{
+	u32 sample_rate, bits_per_sample, frame_size_code;
+	u32 data_num, bit_ch, sample_frq;
+	u32 val;
+	u8 acr[7];
+
+	sample_rate = 44100;
+	bits_per_sample = 16;
+	frame_size_code = 0;
+
+	switch (bits_per_sample) {
+	case 20:
+		data_num = 2;
+		bit_ch  = 1;
+		break;
+	case 24:
+		data_num = 3;
+		bit_ch  = 1;
+		break;
+	default:
+		data_num = 1;
+		bit_ch  = 0;
+		break;
+	}
+
+	hdmi_set_acr(sample_rate, acr);
+	hdmi_reg_acr(hdata, acr);
+
+	hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
+				| HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
+				| HDMI_I2S_MUX_ENABLE);
+
+	hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
+			| HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
+
+	hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
+
+	sample_frq = (sample_rate == 44100) ? 0 :
+			(sample_rate == 48000) ? 2 :
+			(sample_rate == 32000) ? 3 :
+			(sample_rate == 96000) ? 0xa : 0x0;
+
+	hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
+	hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
+
+	val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
+	hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
+
+	/* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
+	hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
+			| HDMI_I2S_SEL_LRCK(6));
+	hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
+			| HDMI_I2S_SEL_SDATA2(4));
+	hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
+			| HDMI_I2S_SEL_SDATA2(2));
+	hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
+
+	/* I2S_CON_1 & 2 */
+	hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
+			| HDMI_I2S_L_CH_LOW_POL);
+	hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
+			| HDMI_I2S_SET_BIT_CH(bit_ch)
+			| HDMI_I2S_SET_SDATA_BIT(data_num)
+			| HDMI_I2S_BASIC_FORMAT);
+
+	/* Configure register related to CUV information */
+	hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
+			| HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
+			| HDMI_I2S_COPYRIGHT
+			| HDMI_I2S_LINEAR_PCM
+			| HDMI_I2S_CONSUMER_FORMAT);
+	hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
+	hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
+	hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
+			| HDMI_I2S_SET_SMP_FREQ(sample_frq));
+	hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
+			HDMI_I2S_ORG_SMP_FREQ_44_1
+			| HDMI_I2S_WORD_LEN_MAX24_24BITS
+			| HDMI_I2S_WORD_LEN_MAX_24BITS);
+
+	hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
+}
+
+static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
+{
+	u32 mod;
+
+	mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
+	if (mod & HDMI_DVI_MODE_EN)
+		return;
+
+	hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
+	hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
+			HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
+}
+
 static void hdmi_conf_reset(struct hdmi_context *hdata)
 {
+	u32 reg;
+
 	/* disable hpd handle for drm */
 	hdata->hpd_handle = false;
 
+	if (hdata->is_v13)
+		reg = HDMI_V13_CORE_RSTOUT;
+	else
+		reg = HDMI_CORE_RSTOUT;
+
 	/* resetting HDMI core */
-	hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT,  0, HDMI_CORE_SW_RSTOUT);
+	hdmi_reg_writemask(hdata, reg,  0, HDMI_CORE_SW_RSTOUT);
 	mdelay(10);
-	hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT);
+	hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT);
 	mdelay(10);
 
 	/* enable hpd handle for drm */
@@ -546,57 +1521,67 @@
 		HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
 	/* disable bluescreen */
 	hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
-	/* choose bluescreen (fecal) color */
-	hdmi_reg_writeb(hdata, HDMI_BLUE_SCREEN_0, 0x12);
-	hdmi_reg_writeb(hdata, HDMI_BLUE_SCREEN_1, 0x34);
-	hdmi_reg_writeb(hdata, HDMI_BLUE_SCREEN_2, 0x56);
-	/* enable AVI packet every vsync, fixes purple line problem */
-	hdmi_reg_writeb(hdata, HDMI_AVI_CON, 0x02);
-	/* force RGB, look to CEA-861-D, table 7 for more detail */
-	hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(0), 0 << 5);
-	hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
 
-	hdmi_reg_writeb(hdata, HDMI_SPD_CON, 0x02);
-	hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
-	hdmi_reg_writeb(hdata, HDMI_ACR_CON, 0x04);
+	if (hdata->is_v13) {
+		/* choose bluescreen (fecal) color */
+		hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
+		hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
+		hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
+
+		/* enable AVI packet every vsync, fixes purple line problem */
+		hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
+		/* force RGB, look to CEA-861-D, table 7 for more detail */
+		hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
+		hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
+
+		hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
+		hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
+		hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
+	} else {
+		/* enable AVI packet every vsync, fixes purple line problem */
+		hdmi_reg_writeb(hdata, HDMI_AVI_CON, 0x02);
+		hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 2 << 5);
+		hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
+	}
 
 	/* enable hpd handle for drm */
 	hdata->hpd_handle = true;
 }
 
-static void hdmi_timing_apply(struct hdmi_context *hdata,
-				 const struct hdmi_preset_conf *conf)
+static void hdmi_v13_timing_apply(struct hdmi_context *hdata)
 {
-	const struct hdmi_core_regs *core = &conf->core;
-	const struct hdmi_tg_regs *tg = &conf->tg;
+	const struct hdmi_v13_preset_conf *conf =
+		hdmi_v13_confs[hdata->cur_conf].conf;
+	const struct hdmi_v13_core_regs *core = &conf->core;
+	const struct hdmi_v13_tg_regs *tg = &conf->tg;
 	int tries;
 
 	/* setting core registers */
 	hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
 	hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
-	hdmi_reg_writeb(hdata, HDMI_V_BLANK_0, core->v_blank[0]);
-	hdmi_reg_writeb(hdata, HDMI_V_BLANK_1, core->v_blank[1]);
-	hdmi_reg_writeb(hdata, HDMI_V_BLANK_2, core->v_blank[2]);
-	hdmi_reg_writeb(hdata, HDMI_H_V_LINE_0, core->h_v_line[0]);
-	hdmi_reg_writeb(hdata, HDMI_H_V_LINE_1, core->h_v_line[1]);
-	hdmi_reg_writeb(hdata, HDMI_H_V_LINE_2, core->h_v_line[2]);
+	hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
+	hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
+	hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
+	hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
+	hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
+	hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
 	hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
 	hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
-	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F_0, core->v_blank_f[0]);
-	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F_1, core->v_blank_f[1]);
-	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F_2, core->v_blank_f[2]);
-	hdmi_reg_writeb(hdata, HDMI_H_SYNC_GEN_0, core->h_sync_gen[0]);
-	hdmi_reg_writeb(hdata, HDMI_H_SYNC_GEN_1, core->h_sync_gen[1]);
-	hdmi_reg_writeb(hdata, HDMI_H_SYNC_GEN_2, core->h_sync_gen[2]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
+	hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
+	hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
+	hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
+	hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
+	hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
+	hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
+	hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
+	hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
+	hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
+	hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
+	hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
+	hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
+	hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
+	hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
+	hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
 	/* Timing generator registers */
 	hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
 	hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
@@ -629,7 +1614,7 @@
 
 	/* waiting for HDMIPHY's PLL to get to steady state */
 	for (tries = 100; tries; --tries) {
-		u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
+		u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
 		if (val & HDMI_PHY_STATUS_READY)
 			break;
 		mdelay(1);
@@ -653,9 +1638,185 @@
 		hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
 }
 
+static void hdmi_v14_timing_apply(struct hdmi_context *hdata)
+{
+	const struct hdmi_preset_conf *conf = hdmi_confs[hdata->cur_conf].conf;
+	const struct hdmi_core_regs *core = &conf->core;
+	const struct hdmi_tg_regs *tg = &conf->tg;
+	int tries;
+
+	/* setting core registers */
+	hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
+	hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
+	hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
+	hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
+	hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
+	hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
+	hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
+	hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
+	hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
+	hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
+	hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
+	hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
+	hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
+	hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
+	hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
+			core->v_sync_line_bef_2[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
+			core->v_sync_line_bef_2[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
+			core->v_sync_line_bef_1[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
+			core->v_sync_line_bef_1[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
+			core->v_sync_line_aft_2[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
+			core->v_sync_line_aft_2[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
+			core->v_sync_line_aft_1[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
+			core->v_sync_line_aft_1[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
+			core->v_sync_line_aft_pxl_2[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
+			core->v_sync_line_aft_pxl_2[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
+			core->v_sync_line_aft_pxl_1[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
+			core->v_sync_line_aft_pxl_1[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
+			core->v_sync_line_aft_3[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
+			core->v_sync_line_aft_3[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
+			core->v_sync_line_aft_4[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
+			core->v_sync_line_aft_4[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
+			core->v_sync_line_aft_5[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
+			core->v_sync_line_aft_5[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
+			core->v_sync_line_aft_6[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
+			core->v_sync_line_aft_6[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
+			core->v_sync_line_aft_pxl_3[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
+			core->v_sync_line_aft_pxl_3[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
+			core->v_sync_line_aft_pxl_4[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
+			core->v_sync_line_aft_pxl_4[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
+			core->v_sync_line_aft_pxl_5[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
+			core->v_sync_line_aft_pxl_5[1]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
+			core->v_sync_line_aft_pxl_6[0]);
+	hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
+			core->v_sync_line_aft_pxl_6[1]);
+	hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
+	hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
+	hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
+	hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
+	hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
+	hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
+	hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
+	hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
+	hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
+	hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
+	hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
+	hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
+
+	/* Timing generator registers */
+	hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d);
+
+	/* waiting for HDMIPHY's PLL to get to steady state */
+	for (tries = 100; tries; --tries) {
+		u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
+		if (val & HDMI_PHY_STATUS_READY)
+			break;
+		mdelay(1);
+	}
+	/* steady state not achieved */
+	if (tries == 0) {
+		DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
+		hdmi_regs_dump(hdata, "timing apply");
+	}
+
+	clk_disable(hdata->res.sclk_hdmi);
+	clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_hdmiphy);
+	clk_enable(hdata->res.sclk_hdmi);
+
+	/* enable HDMI and timing generator */
+	hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
+	if (core->int_pro_mode[0])
+		hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
+				HDMI_FIELD_EN);
+	else
+		hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
+}
+
+static void hdmi_timing_apply(struct hdmi_context *hdata)
+{
+	if (hdata->is_v13)
+		hdmi_v13_timing_apply(hdata);
+	else
+		hdmi_v14_timing_apply(hdata);
+}
+
 static void hdmiphy_conf_reset(struct hdmi_context *hdata)
 {
 	u8 buffer[2];
+	u32 reg;
 
 	clk_disable(hdata->res.sclk_hdmi);
 	clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_pixel);
@@ -668,15 +1829,21 @@
 	if (hdata->hdmiphy_port)
 		i2c_master_send(hdata->hdmiphy_port, buffer, 2);
 
+	if (hdata->is_v13)
+		reg = HDMI_V13_PHY_RSTOUT;
+	else
+		reg = HDMI_PHY_RSTOUT;
+
 	/* reset hdmiphy */
-	hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
+	hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
 	mdelay(10);
-	hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT,  0, HDMI_PHY_SW_RSTOUT);
+	hdmi_reg_writemask(hdata, reg,  0, HDMI_PHY_SW_RSTOUT);
 	mdelay(10);
 }
 
 static void hdmiphy_conf_apply(struct hdmi_context *hdata)
 {
+	const u8 *hdmiphy_data;
 	u8 buffer[32];
 	u8 operation[2];
 	u8 read_buffer[32] = {0, };
@@ -689,7 +1856,12 @@
 	}
 
 	/* pixel clock */
-	memcpy(buffer, hdmi_confs[hdata->cur_conf].hdmiphy_data, 32);
+	if (hdata->is_v13)
+		hdmiphy_data = hdmi_v13_confs[hdata->cur_conf].hdmiphy_data;
+	else
+		hdmiphy_data = hdmi_confs[hdata->cur_conf].hdmiphy_data;
+
+	memcpy(buffer, hdmiphy_data, 32);
 	ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
 	if (ret != 32) {
 		DRM_ERROR("failed to configure HDMIPHY via I2C\n");
@@ -721,9 +1893,6 @@
 
 static void hdmi_conf_apply(struct hdmi_context *hdata)
 {
-	const struct hdmi_preset_conf *conf =
-		  hdmi_confs[hdata->cur_conf].conf;
-
 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
 	hdmiphy_conf_reset(hdata);
@@ -731,13 +1900,55 @@
 
 	hdmi_conf_reset(hdata);
 	hdmi_conf_init(hdata);
+	hdmi_audio_init(hdata);
 
 	/* setting core registers */
-	hdmi_timing_apply(hdata, conf);
+	hdmi_timing_apply(hdata);
+	hdmi_audio_control(hdata, true);
 
 	hdmi_regs_dump(hdata, "start");
 }
 
+static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector,
+				struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{
+	struct drm_display_mode *m;
+	struct hdmi_context *hdata = (struct hdmi_context *)ctx;
+	int index;
+
+	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+	drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+	if (hdata->is_v13)
+		index = hdmi_v13_conf_index(adjusted_mode);
+	else
+		index = hdmi_v14_conf_index(adjusted_mode);
+
+	/* just return if user desired mode exists. */
+	if (index >= 0)
+		return;
+
+	/*
+	 * otherwise, find the most suitable mode among modes and change it
+	 * to adjusted_mode.
+	 */
+	list_for_each_entry(m, &connector->modes, head) {
+		if (hdata->is_v13)
+			index = hdmi_v13_conf_index(m);
+		else
+			index = hdmi_v14_conf_index(m);
+
+		if (index >= 0) {
+			DRM_INFO("desired mode doesn't exist so\n");
+			DRM_INFO("use the most suitable mode among modes.\n");
+			memcpy(adjusted_mode, m, sizeof(*m));
+			break;
+		}
+	}
+}
+
 static void hdmi_mode_set(void *ctx, void *mode)
 {
 	struct hdmi_context *hdata = (struct hdmi_context *)ctx;
@@ -745,13 +1956,22 @@
 
 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-	conf_idx = hdmi_conf_index(mode);
-	if (conf_idx >= 0 && conf_idx < ARRAY_SIZE(hdmi_confs))
+	conf_idx = hdmi_conf_index(hdata, mode);
+	if (conf_idx >= 0)
 		hdata->cur_conf = conf_idx;
 	else
 		DRM_DEBUG_KMS("not supported mode\n");
 }
 
+static void hdmi_get_max_resol(void *ctx, unsigned int *width,
+					unsigned int *height)
+{
+	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+	*width = MAX_WIDTH;
+	*height = MAX_HEIGHT;
+}
+
 static void hdmi_commit(void *ctx)
 {
 	struct hdmi_context *hdata = (struct hdmi_context *)ctx;
@@ -770,13 +1990,16 @@
 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
 	if (hdata->enabled) {
+		hdmi_audio_control(hdata, false);
 		hdmiphy_conf_reset(hdata);
 		hdmi_conf_reset(hdata);
 	}
 }
 
 static struct exynos_hdmi_manager_ops manager_ops = {
+	.mode_fixup	= hdmi_mode_fixup,
 	.mode_set	= hdmi_mode_set,
+	.get_max_resol	= hdmi_get_max_resol,
 	.commit		= hdmi_commit,
 	.disable	= hdmi_disable,
 };
@@ -926,7 +2149,7 @@
 	hdmiphy_conf_reset(hdata);
 	hdmi_conf_reset(hdata);
 	hdmi_conf_init(hdata);
-
+	hdmi_audio_init(hdata);
 }
 
 static void hdmi_resource_poweroff(struct hdmi_context *hdata)
@@ -978,14 +2201,12 @@
 	if (ddc)
 		hdmi_ddc = ddc;
 }
-EXPORT_SYMBOL(hdmi_attach_ddc_client);
 
 void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
 {
 	if (hdmiphy)
 		hdmi_hdmiphy = hdmiphy;
 }
-EXPORT_SYMBOL(hdmi_attach_hdmiphy_client);
 
 static int __devinit hdmi_probe(struct platform_device *pdev)
 {
@@ -1022,6 +2243,7 @@
 
 	platform_set_drvdata(pdev, drm_hdmi_ctx);
 
+	hdata->is_v13 = pdata->is_v13;
 	hdata->default_win = pdata->default_win;
 	hdata->default_timing = &pdata->timing;
 	hdata->default_bpp = pdata->bpp;
@@ -1167,10 +2389,3 @@
 		.pm = &hdmi_pm_ops,
 	},
 };
-EXPORT_SYMBOL(hdmi_driver);
-
-MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_DESCRIPTION("Samsung DRM HDMI core Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.h b/drivers/gpu/drm/exynos/exynos_hdmi.h
index 31d6cf8..1c3b6d8 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.h
@@ -28,56 +28,6 @@
 #ifndef _EXYNOS_HDMI_H_
 #define _EXYNOS_HDMI_H_
 
-struct hdmi_conf {
-	int width;
-	int height;
-	int vrefresh;
-	bool interlace;
-	const u8 *hdmiphy_data;
-	const struct hdmi_preset_conf *conf;
-};
-
-struct hdmi_resources {
-	struct clk *hdmi;
-	struct clk *sclk_hdmi;
-	struct clk *sclk_pixel;
-	struct clk *sclk_hdmiphy;
-	struct clk *hdmiphy;
-	struct regulator_bulk_data *regul_bulk;
-	int regul_count;
-};
-
-struct hdmi_context {
-	struct device			*dev;
-	struct drm_device		*drm_dev;
-	struct fb_videomode		*default_timing;
-	unsigned int			default_win;
-	unsigned int			default_bpp;
-	bool				hpd_handle;
-	bool				enabled;
-
-	struct resource			*regs_res;
-	/** base address of HDMI registers */
-	void __iomem *regs;
-	/** HDMI hotplug interrupt */
-	unsigned int irq;
-	/** workqueue for delayed work */
-	struct workqueue_struct *wq;
-	/** hotplug handling work */
-	struct work_struct hotplug_work;
-
-	struct i2c_client *ddc_port;
-	struct i2c_client *hdmiphy_port;
-
-	/** current hdmiphy conf index */
-	int cur_conf;
-	/** other resources */
-	struct hdmi_resources res;
-
-	void *parent_ctx;
-};
-
-
 void hdmi_attach_ddc_client(struct i2c_client *ddc);
 void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy);
 
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 93846e8..4d5f41e 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -36,11 +36,57 @@
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_hdmi.h"
-#include "exynos_hdmi.h"
-#include "exynos_mixer.h"
+
+#define HDMI_OVERLAY_NUMBER	3
 
 #define get_mixer_context(dev)	platform_get_drvdata(to_platform_device(dev))
 
+struct hdmi_win_data {
+	dma_addr_t		dma_addr;
+	void __iomem		*vaddr;
+	dma_addr_t		chroma_dma_addr;
+	void __iomem		*chroma_vaddr;
+	uint32_t		pixel_format;
+	unsigned int		bpp;
+	unsigned int		crtc_x;
+	unsigned int		crtc_y;
+	unsigned int		crtc_width;
+	unsigned int		crtc_height;
+	unsigned int		fb_x;
+	unsigned int		fb_y;
+	unsigned int		fb_width;
+	unsigned int		fb_height;
+	unsigned int		mode_width;
+	unsigned int		mode_height;
+	unsigned int		scan_flags;
+};
+
+struct mixer_resources {
+	struct device		*dev;
+	int			irq;
+	void __iomem		*mixer_regs;
+	void __iomem		*vp_regs;
+	spinlock_t		reg_slock;
+	struct clk		*mixer;
+	struct clk		*vp;
+	struct clk		*sclk_mixer;
+	struct clk		*sclk_hdmi;
+	struct clk		*sclk_dac;
+};
+
+struct mixer_context {
+	struct fb_videomode	*default_timing;
+	unsigned int		default_win;
+	unsigned int		default_bpp;
+	unsigned int		irq;
+	int			pipe;
+	bool			interlace;
+	bool			vp_enabled;
+
+	struct mixer_resources	mixer_res;
+	struct hdmi_win_data	win_data[HDMI_OVERLAY_NUMBER];
+};
+
 static const u8 filter_y_horiz_tap8[] = {
 	0,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
 	-1,	-1,	-1,	-1,	-1,	0,	0,	0,
@@ -1066,10 +1112,3 @@
 	.probe = mixer_probe,
 	.remove = __devexit_p(mixer_remove),
 };
-EXPORT_SYMBOL(mixer_driver);
-
-MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_DESCRIPTION("Samsung DRM HDMI mixer Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.h b/drivers/gpu/drm/exynos/exynos_mixer.h
deleted file mode 100644
index cebacfe..0000000
--- a/drivers/gpu/drm/exynos/exynos_mixer.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authors:
- *	Seung-Woo Kim <sw0312.kim@samsung.com>
- *	Inki Dae <inki.dae@samsung.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _EXYNOS_MIXER_H_
-#define _EXYNOS_MIXER_H_
-
-#define HDMI_OVERLAY_NUMBER	3
-
-struct hdmi_win_data {
-	dma_addr_t		dma_addr;
-	void __iomem		*vaddr;
-	dma_addr_t		chroma_dma_addr;
-	void __iomem		*chroma_vaddr;
-	uint32_t		pixel_format;
-	unsigned int		bpp;
-	unsigned int		crtc_x;
-	unsigned int		crtc_y;
-	unsigned int		crtc_width;
-	unsigned int		crtc_height;
-	unsigned int		fb_x;
-	unsigned int		fb_y;
-	unsigned int		fb_width;
-	unsigned int		fb_height;
-	unsigned int		mode_width;
-	unsigned int		mode_height;
-	unsigned int		scan_flags;
-};
-
-struct mixer_resources {
-	struct device *dev;
-	/** interrupt index */
-	int irq;
-	/** pointer to Mixer registers */
-	void __iomem *mixer_regs;
-	/** pointer to Video Processor registers */
-	void __iomem *vp_regs;
-	/** spinlock for protection of registers */
-	spinlock_t reg_slock;
-	/** other resources */
-	struct clk *mixer;
-	struct clk *vp;
-	struct clk *sclk_mixer;
-	struct clk *sclk_hdmi;
-	struct clk *sclk_dac;
-};
-
-struct mixer_context {
-	unsigned int			default_win;
-	struct fb_videomode		*default_timing;
-	unsigned int			default_bpp;
-
-	/** mixer interrupt */
-	unsigned int irq;
-	/** current crtc pipe for vblank */
-	int pipe;
-	/** interlace scan mode */
-	bool interlace;
-	/** vp enabled status */
-	bool vp_enabled;
-
-	/** mixer and vp resources */
-	struct mixer_resources mixer_res;
-
-	/** overlay window data */
-	struct hdmi_win_data		win_data[HDMI_OVERLAY_NUMBER];
-};
-
-#endif
diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h
index 72e6b52..3c04bea 100644
--- a/drivers/gpu/drm/exynos/regs-hdmi.h
+++ b/drivers/gpu/drm/exynos/regs-hdmi.h
@@ -19,64 +19,67 @@
  * Register part
 */
 
+/* HDMI Version 1.3 & Common */
 #define HDMI_CTRL_BASE(x)		((x) + 0x00000000)
 #define HDMI_CORE_BASE(x)		((x) + 0x00010000)
+#define HDMI_I2S_BASE(x)		((x) + 0x00040000)
 #define HDMI_TG_BASE(x)			((x) + 0x00050000)
 
 /* Control registers */
 #define HDMI_INTC_CON			HDMI_CTRL_BASE(0x0000)
 #define HDMI_INTC_FLAG			HDMI_CTRL_BASE(0x0004)
 #define HDMI_HPD_STATUS			HDMI_CTRL_BASE(0x000C)
-#define HDMI_PHY_RSTOUT			HDMI_CTRL_BASE(0x0014)
-#define HDMI_PHY_VPLL			HDMI_CTRL_BASE(0x0018)
-#define HDMI_PHY_CMU			HDMI_CTRL_BASE(0x001C)
-#define HDMI_CORE_RSTOUT		HDMI_CTRL_BASE(0x0020)
+#define HDMI_V13_PHY_RSTOUT		HDMI_CTRL_BASE(0x0014)
+#define HDMI_V13_PHY_VPLL		HDMI_CTRL_BASE(0x0018)
+#define HDMI_V13_PHY_CMU		HDMI_CTRL_BASE(0x001C)
+#define HDMI_V13_CORE_RSTOUT		HDMI_CTRL_BASE(0x0020)
 
 /* Core registers */
 #define HDMI_CON_0			HDMI_CORE_BASE(0x0000)
 #define HDMI_CON_1			HDMI_CORE_BASE(0x0004)
 #define HDMI_CON_2			HDMI_CORE_BASE(0x0008)
 #define HDMI_SYS_STATUS			HDMI_CORE_BASE(0x0010)
-#define HDMI_PHY_STATUS			HDMI_CORE_BASE(0x0014)
+#define HDMI_V13_PHY_STATUS		HDMI_CORE_BASE(0x0014)
 #define HDMI_STATUS_EN			HDMI_CORE_BASE(0x0020)
 #define HDMI_HPD			HDMI_CORE_BASE(0x0030)
 #define HDMI_MODE_SEL			HDMI_CORE_BASE(0x0040)
-#define HDMI_BLUE_SCREEN_0		HDMI_CORE_BASE(0x0050)
-#define HDMI_BLUE_SCREEN_1		HDMI_CORE_BASE(0x0054)
-#define HDMI_BLUE_SCREEN_2		HDMI_CORE_BASE(0x0058)
+#define HDMI_ENC_EN			HDMI_CORE_BASE(0x0044)
+#define HDMI_V13_BLUE_SCREEN_0		HDMI_CORE_BASE(0x0050)
+#define HDMI_V13_BLUE_SCREEN_1		HDMI_CORE_BASE(0x0054)
+#define HDMI_V13_BLUE_SCREEN_2		HDMI_CORE_BASE(0x0058)
 #define HDMI_H_BLANK_0			HDMI_CORE_BASE(0x00A0)
 #define HDMI_H_BLANK_1			HDMI_CORE_BASE(0x00A4)
-#define HDMI_V_BLANK_0			HDMI_CORE_BASE(0x00B0)
-#define HDMI_V_BLANK_1			HDMI_CORE_BASE(0x00B4)
-#define HDMI_V_BLANK_2			HDMI_CORE_BASE(0x00B8)
-#define HDMI_H_V_LINE_0			HDMI_CORE_BASE(0x00C0)
-#define HDMI_H_V_LINE_1			HDMI_CORE_BASE(0x00C4)
-#define HDMI_H_V_LINE_2			HDMI_CORE_BASE(0x00C8)
+#define HDMI_V13_V_BLANK_0		HDMI_CORE_BASE(0x00B0)
+#define HDMI_V13_V_BLANK_1		HDMI_CORE_BASE(0x00B4)
+#define HDMI_V13_V_BLANK_2		HDMI_CORE_BASE(0x00B8)
+#define HDMI_V13_H_V_LINE_0		HDMI_CORE_BASE(0x00C0)
+#define HDMI_V13_H_V_LINE_1		HDMI_CORE_BASE(0x00C4)
+#define HDMI_V13_H_V_LINE_2		HDMI_CORE_BASE(0x00C8)
 #define HDMI_VSYNC_POL			HDMI_CORE_BASE(0x00E4)
 #define HDMI_INT_PRO_MODE		HDMI_CORE_BASE(0x00E8)
-#define HDMI_V_BLANK_F_0		HDMI_CORE_BASE(0x0110)
-#define HDMI_V_BLANK_F_1		HDMI_CORE_BASE(0x0114)
-#define HDMI_V_BLANK_F_2		HDMI_CORE_BASE(0x0118)
-#define HDMI_H_SYNC_GEN_0		HDMI_CORE_BASE(0x0120)
-#define HDMI_H_SYNC_GEN_1		HDMI_CORE_BASE(0x0124)
-#define HDMI_H_SYNC_GEN_2		HDMI_CORE_BASE(0x0128)
-#define HDMI_V_SYNC_GEN_1_0		HDMI_CORE_BASE(0x0130)
-#define HDMI_V_SYNC_GEN_1_1		HDMI_CORE_BASE(0x0134)
-#define HDMI_V_SYNC_GEN_1_2		HDMI_CORE_BASE(0x0138)
-#define HDMI_V_SYNC_GEN_2_0		HDMI_CORE_BASE(0x0140)
-#define HDMI_V_SYNC_GEN_2_1		HDMI_CORE_BASE(0x0144)
-#define HDMI_V_SYNC_GEN_2_2		HDMI_CORE_BASE(0x0148)
-#define HDMI_V_SYNC_GEN_3_0		HDMI_CORE_BASE(0x0150)
-#define HDMI_V_SYNC_GEN_3_1		HDMI_CORE_BASE(0x0154)
-#define HDMI_V_SYNC_GEN_3_2		HDMI_CORE_BASE(0x0158)
-#define HDMI_ACR_CON			HDMI_CORE_BASE(0x0180)
-#define HDMI_AVI_CON			HDMI_CORE_BASE(0x0300)
-#define HDMI_AVI_BYTE(n)		HDMI_CORE_BASE(0x0320 + 4 * (n))
-#define HDMI_DC_CONTROL			HDMI_CORE_BASE(0x05C0)
-#define HDMI_VIDEO_PATTERN_GEN		HDMI_CORE_BASE(0x05C4)
-#define HDMI_HPD_GEN			HDMI_CORE_BASE(0x05C8)
-#define HDMI_AUI_CON			HDMI_CORE_BASE(0x0360)
-#define HDMI_SPD_CON			HDMI_CORE_BASE(0x0400)
+#define HDMI_V13_V_BLANK_F_0		HDMI_CORE_BASE(0x0110)
+#define HDMI_V13_V_BLANK_F_1		HDMI_CORE_BASE(0x0114)
+#define HDMI_V13_V_BLANK_F_2		HDMI_CORE_BASE(0x0118)
+#define HDMI_V13_H_SYNC_GEN_0		HDMI_CORE_BASE(0x0120)
+#define HDMI_V13_H_SYNC_GEN_1		HDMI_CORE_BASE(0x0124)
+#define HDMI_V13_H_SYNC_GEN_2		HDMI_CORE_BASE(0x0128)
+#define HDMI_V13_V_SYNC_GEN_1_0		HDMI_CORE_BASE(0x0130)
+#define HDMI_V13_V_SYNC_GEN_1_1		HDMI_CORE_BASE(0x0134)
+#define HDMI_V13_V_SYNC_GEN_1_2		HDMI_CORE_BASE(0x0138)
+#define HDMI_V13_V_SYNC_GEN_2_0		HDMI_CORE_BASE(0x0140)
+#define HDMI_V13_V_SYNC_GEN_2_1		HDMI_CORE_BASE(0x0144)
+#define HDMI_V13_V_SYNC_GEN_2_2		HDMI_CORE_BASE(0x0148)
+#define HDMI_V13_V_SYNC_GEN_3_0		HDMI_CORE_BASE(0x0150)
+#define HDMI_V13_V_SYNC_GEN_3_1		HDMI_CORE_BASE(0x0154)
+#define HDMI_V13_V_SYNC_GEN_3_2		HDMI_CORE_BASE(0x0158)
+#define HDMI_V13_ACR_CON		HDMI_CORE_BASE(0x0180)
+#define HDMI_V13_AVI_CON		HDMI_CORE_BASE(0x0300)
+#define HDMI_V13_AVI_BYTE(n)		HDMI_CORE_BASE(0x0320 + 4 * (n))
+#define HDMI_V13_DC_CONTROL		HDMI_CORE_BASE(0x05C0)
+#define HDMI_V13_VIDEO_PATTERN_GEN	HDMI_CORE_BASE(0x05C4)
+#define HDMI_V13_HPD_GEN		HDMI_CORE_BASE(0x05C8)
+#define HDMI_V13_AUI_CON		HDMI_CORE_BASE(0x0360)
+#define HDMI_V13_SPD_CON		HDMI_CORE_BASE(0x0400)
 
 /* Timing generator registers */
 #define HDMI_TG_CMD			HDMI_TG_BASE(0x0000)
@@ -130,6 +133,9 @@
 
 /* HDMI_CON_0 */
 #define HDMI_BLUE_SCR_EN		(1 << 5)
+#define HDMI_ASP_EN			(1 << 2)
+#define HDMI_ASP_DIS			(0 << 2)
+#define HDMI_ASP_MASK			(1 << 2)
 #define HDMI_EN				(1 << 0)
 
 /* HDMI_PHY_STATUS */
@@ -138,10 +144,418 @@
 /* HDMI_MODE_SEL */
 #define HDMI_MODE_HDMI_EN		(1 << 1)
 #define HDMI_MODE_DVI_EN		(1 << 0)
+#define HDMI_DVI_MODE_EN		(1)
+#define HDMI_DVI_MODE_DIS		(0)
 #define HDMI_MODE_MASK			(3 << 0)
 
 /* HDMI_TG_CMD */
 #define HDMI_TG_EN			(1 << 0)
 #define HDMI_FIELD_EN			(1 << 1)
 
+
+/* HDMI Version 1.4 */
+/* Control registers */
+/* #define HDMI_INTC_CON		HDMI_CTRL_BASE(0x0000) */
+/* #define HDMI_INTC_FLAG		HDMI_CTRL_BASE(0x0004) */
+#define HDMI_HDCP_KEY_LOAD		HDMI_CTRL_BASE(0x0008)
+/* #define HDMI_HPD_STATUS		HDMI_CTRL_BASE(0x000C) */
+#define HDMI_INTC_CON_1			HDMI_CTRL_BASE(0x0010)
+#define HDMI_INTC_FLAG_1		HDMI_CTRL_BASE(0x0014)
+#define HDMI_PHY_STATUS_0		HDMI_CTRL_BASE(0x0020)
+#define HDMI_PHY_STATUS_CMU		HDMI_CTRL_BASE(0x0024)
+#define HDMI_PHY_STATUS_PLL		HDMI_CTRL_BASE(0x0028)
+#define HDMI_PHY_CON_0			HDMI_CTRL_BASE(0x0030)
+#define HDMI_HPD_CTRL			HDMI_CTRL_BASE(0x0040)
+#define HDMI_HPD_ST			HDMI_CTRL_BASE(0x0044)
+#define HDMI_HPD_TH_X			HDMI_CTRL_BASE(0x0050)
+#define HDMI_AUDIO_CLKSEL		HDMI_CTRL_BASE(0x0070)
+#define HDMI_PHY_RSTOUT			HDMI_CTRL_BASE(0x0074)
+#define HDMI_PHY_VPLL			HDMI_CTRL_BASE(0x0078)
+#define HDMI_PHY_CMU			HDMI_CTRL_BASE(0x007C)
+#define HDMI_CORE_RSTOUT		HDMI_CTRL_BASE(0x0080)
+
+/* Video related registers */
+#define HDMI_YMAX			HDMI_CORE_BASE(0x0060)
+#define HDMI_YMIN			HDMI_CORE_BASE(0x0064)
+#define HDMI_CMAX			HDMI_CORE_BASE(0x0068)
+#define HDMI_CMIN			HDMI_CORE_BASE(0x006C)
+
+#define HDMI_V2_BLANK_0			HDMI_CORE_BASE(0x00B0)
+#define HDMI_V2_BLANK_1			HDMI_CORE_BASE(0x00B4)
+#define HDMI_V1_BLANK_0			HDMI_CORE_BASE(0x00B8)
+#define HDMI_V1_BLANK_1			HDMI_CORE_BASE(0x00BC)
+
+#define HDMI_V_LINE_0			HDMI_CORE_BASE(0x00C0)
+#define HDMI_V_LINE_1			HDMI_CORE_BASE(0x00C4)
+#define HDMI_H_LINE_0			HDMI_CORE_BASE(0x00C8)
+#define HDMI_H_LINE_1			HDMI_CORE_BASE(0x00CC)
+
+#define HDMI_HSYNC_POL			HDMI_CORE_BASE(0x00E0)
+
+#define HDMI_V_BLANK_F0_0		HDMI_CORE_BASE(0x0110)
+#define HDMI_V_BLANK_F0_1		HDMI_CORE_BASE(0x0114)
+#define HDMI_V_BLANK_F1_0		HDMI_CORE_BASE(0x0118)
+#define HDMI_V_BLANK_F1_1		HDMI_CORE_BASE(0x011C)
+
+#define HDMI_H_SYNC_START_0		HDMI_CORE_BASE(0x0120)
+#define HDMI_H_SYNC_START_1		HDMI_CORE_BASE(0x0124)
+#define HDMI_H_SYNC_END_0		HDMI_CORE_BASE(0x0128)
+#define HDMI_H_SYNC_END_1		HDMI_CORE_BASE(0x012C)
+
+#define HDMI_V_SYNC_LINE_BEF_2_0	HDMI_CORE_BASE(0x0130)
+#define HDMI_V_SYNC_LINE_BEF_2_1	HDMI_CORE_BASE(0x0134)
+#define HDMI_V_SYNC_LINE_BEF_1_0	HDMI_CORE_BASE(0x0138)
+#define HDMI_V_SYNC_LINE_BEF_1_1	HDMI_CORE_BASE(0x013C)
+
+#define HDMI_V_SYNC_LINE_AFT_2_0	HDMI_CORE_BASE(0x0140)
+#define HDMI_V_SYNC_LINE_AFT_2_1	HDMI_CORE_BASE(0x0144)
+#define HDMI_V_SYNC_LINE_AFT_1_0	HDMI_CORE_BASE(0x0148)
+#define HDMI_V_SYNC_LINE_AFT_1_1	HDMI_CORE_BASE(0x014C)
+
+#define HDMI_V_SYNC_LINE_AFT_PXL_2_0	HDMI_CORE_BASE(0x0150)
+#define HDMI_V_SYNC_LINE_AFT_PXL_2_1	HDMI_CORE_BASE(0x0154)
+#define HDMI_V_SYNC_LINE_AFT_PXL_1_0	HDMI_CORE_BASE(0x0158)
+#define HDMI_V_SYNC_LINE_AFT_PXL_1_1	HDMI_CORE_BASE(0x015C)
+
+#define HDMI_V_BLANK_F2_0		HDMI_CORE_BASE(0x0160)
+#define HDMI_V_BLANK_F2_1		HDMI_CORE_BASE(0x0164)
+#define HDMI_V_BLANK_F3_0		HDMI_CORE_BASE(0x0168)
+#define HDMI_V_BLANK_F3_1		HDMI_CORE_BASE(0x016C)
+#define HDMI_V_BLANK_F4_0		HDMI_CORE_BASE(0x0170)
+#define HDMI_V_BLANK_F4_1		HDMI_CORE_BASE(0x0174)
+#define HDMI_V_BLANK_F5_0		HDMI_CORE_BASE(0x0178)
+#define HDMI_V_BLANK_F5_1		HDMI_CORE_BASE(0x017C)
+
+#define HDMI_V_SYNC_LINE_AFT_3_0	HDMI_CORE_BASE(0x0180)
+#define HDMI_V_SYNC_LINE_AFT_3_1	HDMI_CORE_BASE(0x0184)
+#define HDMI_V_SYNC_LINE_AFT_4_0	HDMI_CORE_BASE(0x0188)
+#define HDMI_V_SYNC_LINE_AFT_4_1	HDMI_CORE_BASE(0x018C)
+#define HDMI_V_SYNC_LINE_AFT_5_0	HDMI_CORE_BASE(0x0190)
+#define HDMI_V_SYNC_LINE_AFT_5_1	HDMI_CORE_BASE(0x0194)
+#define HDMI_V_SYNC_LINE_AFT_6_0	HDMI_CORE_BASE(0x0198)
+#define HDMI_V_SYNC_LINE_AFT_6_1	HDMI_CORE_BASE(0x019C)
+
+#define HDMI_V_SYNC_LINE_AFT_PXL_3_0	HDMI_CORE_BASE(0x01A0)
+#define HDMI_V_SYNC_LINE_AFT_PXL_3_1	HDMI_CORE_BASE(0x01A4)
+#define HDMI_V_SYNC_LINE_AFT_PXL_4_0	HDMI_CORE_BASE(0x01A8)
+#define HDMI_V_SYNC_LINE_AFT_PXL_4_1	HDMI_CORE_BASE(0x01AC)
+#define HDMI_V_SYNC_LINE_AFT_PXL_5_0	HDMI_CORE_BASE(0x01B0)
+#define HDMI_V_SYNC_LINE_AFT_PXL_5_1	HDMI_CORE_BASE(0x01B4)
+#define HDMI_V_SYNC_LINE_AFT_PXL_6_0	HDMI_CORE_BASE(0x01B8)
+#define HDMI_V_SYNC_LINE_AFT_PXL_6_1	HDMI_CORE_BASE(0x01BC)
+
+#define HDMI_VACT_SPACE_1_0		HDMI_CORE_BASE(0x01C0)
+#define HDMI_VACT_SPACE_1_1		HDMI_CORE_BASE(0x01C4)
+#define HDMI_VACT_SPACE_2_0		HDMI_CORE_BASE(0x01C8)
+#define HDMI_VACT_SPACE_2_1		HDMI_CORE_BASE(0x01CC)
+#define HDMI_VACT_SPACE_3_0		HDMI_CORE_BASE(0x01D0)
+#define HDMI_VACT_SPACE_3_1		HDMI_CORE_BASE(0x01D4)
+#define HDMI_VACT_SPACE_4_0		HDMI_CORE_BASE(0x01D8)
+#define HDMI_VACT_SPACE_4_1		HDMI_CORE_BASE(0x01DC)
+#define HDMI_VACT_SPACE_5_0		HDMI_CORE_BASE(0x01E0)
+#define HDMI_VACT_SPACE_5_1		HDMI_CORE_BASE(0x01E4)
+#define HDMI_VACT_SPACE_6_0		HDMI_CORE_BASE(0x01E8)
+#define HDMI_VACT_SPACE_6_1		HDMI_CORE_BASE(0x01EC)
+
+#define HDMI_GCP_CON			HDMI_CORE_BASE(0x0200)
+#define HDMI_GCP_BYTE1			HDMI_CORE_BASE(0x0210)
+#define HDMI_GCP_BYTE2			HDMI_CORE_BASE(0x0214)
+#define HDMI_GCP_BYTE3			HDMI_CORE_BASE(0x0218)
+
+/* Audio related registers */
+#define HDMI_ASP_CON			HDMI_CORE_BASE(0x0300)
+#define HDMI_ASP_SP_FLAT		HDMI_CORE_BASE(0x0304)
+#define HDMI_ASP_CHCFG0			HDMI_CORE_BASE(0x0310)
+#define HDMI_ASP_CHCFG1			HDMI_CORE_BASE(0x0314)
+#define HDMI_ASP_CHCFG2			HDMI_CORE_BASE(0x0318)
+#define HDMI_ASP_CHCFG3			HDMI_CORE_BASE(0x031C)
+
+#define HDMI_ACR_CON			HDMI_CORE_BASE(0x0400)
+#define HDMI_ACR_MCTS0			HDMI_CORE_BASE(0x0410)
+#define HDMI_ACR_MCTS1			HDMI_CORE_BASE(0x0414)
+#define HDMI_ACR_MCTS2			HDMI_CORE_BASE(0x0418)
+#define HDMI_ACR_CTS0			HDMI_CORE_BASE(0x0420)
+#define HDMI_ACR_CTS1			HDMI_CORE_BASE(0x0424)
+#define HDMI_ACR_CTS2			HDMI_CORE_BASE(0x0428)
+#define HDMI_ACR_N0			HDMI_CORE_BASE(0x0430)
+#define HDMI_ACR_N1			HDMI_CORE_BASE(0x0434)
+#define HDMI_ACR_N2			HDMI_CORE_BASE(0x0438)
+
+/* Packet related registers */
+#define HDMI_ACP_CON			HDMI_CORE_BASE(0x0500)
+#define HDMI_ACP_TYPE			HDMI_CORE_BASE(0x0514)
+#define HDMI_ACP_DATA(n)		HDMI_CORE_BASE(0x0520 + 4 * (n))
+
+#define HDMI_ISRC_CON			HDMI_CORE_BASE(0x0600)
+#define HDMI_ISRC1_HEADER1		HDMI_CORE_BASE(0x0614)
+#define HDMI_ISRC1_DATA(n)		HDMI_CORE_BASE(0x0620 + 4 * (n))
+#define HDMI_ISRC2_DATA(n)		HDMI_CORE_BASE(0x06A0 + 4 * (n))
+
+#define HDMI_AVI_CON			HDMI_CORE_BASE(0x0700)
+#define HDMI_AVI_HEADER0		HDMI_CORE_BASE(0x0710)
+#define HDMI_AVI_HEADER1		HDMI_CORE_BASE(0x0714)
+#define HDMI_AVI_HEADER2		HDMI_CORE_BASE(0x0718)
+#define HDMI_AVI_CHECK_SUM		HDMI_CORE_BASE(0x071C)
+#define HDMI_AVI_BYTE(n)		HDMI_CORE_BASE(0x0720 + 4 * (n))
+
+#define HDMI_AUI_CON			HDMI_CORE_BASE(0x0800)
+#define HDMI_AUI_HEADER0		HDMI_CORE_BASE(0x0810)
+#define HDMI_AUI_HEADER1		HDMI_CORE_BASE(0x0814)
+#define HDMI_AUI_HEADER2		HDMI_CORE_BASE(0x0818)
+#define HDMI_AUI_CHECK_SUM		HDMI_CORE_BASE(0x081C)
+#define HDMI_AUI_BYTE(n)		HDMI_CORE_BASE(0x0820 + 4 * (n))
+
+#define HDMI_MPG_CON			HDMI_CORE_BASE(0x0900)
+#define HDMI_MPG_CHECK_SUM		HDMI_CORE_BASE(0x091C)
+#define HDMI_MPG_DATA(n)		HDMI_CORE_BASE(0x0920 + 4 * (n))
+
+#define HDMI_SPD_CON			HDMI_CORE_BASE(0x0A00)
+#define HDMI_SPD_HEADER0		HDMI_CORE_BASE(0x0A10)
+#define HDMI_SPD_HEADER1		HDMI_CORE_BASE(0x0A14)
+#define HDMI_SPD_HEADER2		HDMI_CORE_BASE(0x0A18)
+#define HDMI_SPD_DATA(n)		HDMI_CORE_BASE(0x0A20 + 4 * (n))
+
+#define HDMI_GAMUT_CON			HDMI_CORE_BASE(0x0B00)
+#define HDMI_GAMUT_HEADER0		HDMI_CORE_BASE(0x0B10)
+#define HDMI_GAMUT_HEADER1		HDMI_CORE_BASE(0x0B14)
+#define HDMI_GAMUT_HEADER2		HDMI_CORE_BASE(0x0B18)
+#define HDMI_GAMUT_METADATA(n)		HDMI_CORE_BASE(0x0B20 + 4 * (n))
+
+#define HDMI_VSI_CON			HDMI_CORE_BASE(0x0C00)
+#define HDMI_VSI_HEADER0		HDMI_CORE_BASE(0x0C10)
+#define HDMI_VSI_HEADER1		HDMI_CORE_BASE(0x0C14)
+#define HDMI_VSI_HEADER2		HDMI_CORE_BASE(0x0C18)
+#define HDMI_VSI_DATA(n)		HDMI_CORE_BASE(0x0C20 + 4 * (n))
+
+#define HDMI_DC_CONTROL			HDMI_CORE_BASE(0x0D00)
+#define HDMI_VIDEO_PATTERN_GEN		HDMI_CORE_BASE(0x0D04)
+
+#define HDMI_AN_SEED_SEL		HDMI_CORE_BASE(0x0E48)
+#define HDMI_AN_SEED_0			HDMI_CORE_BASE(0x0E58)
+#define HDMI_AN_SEED_1			HDMI_CORE_BASE(0x0E5C)
+#define HDMI_AN_SEED_2			HDMI_CORE_BASE(0x0E60)
+#define HDMI_AN_SEED_3			HDMI_CORE_BASE(0x0E64)
+
+/* HDCP related registers */
+#define HDMI_HDCP_SHA1(n)		HDMI_CORE_BASE(0x7000 + 4 * (n))
+#define HDMI_HDCP_KSV_LIST(n)		HDMI_CORE_BASE(0x7050 + 4 * (n))
+
+#define HDMI_HDCP_KSV_LIST_CON		HDMI_CORE_BASE(0x7064)
+#define HDMI_HDCP_SHA_RESULT		HDMI_CORE_BASE(0x7070)
+#define HDMI_HDCP_CTRL1			HDMI_CORE_BASE(0x7080)
+#define HDMI_HDCP_CTRL2			HDMI_CORE_BASE(0x7084)
+#define HDMI_HDCP_CHECK_RESULT		HDMI_CORE_BASE(0x7090)
+#define HDMI_HDCP_BKSV(n)		HDMI_CORE_BASE(0x70A0 + 4 * (n))
+#define HDMI_HDCP_AKSV(n)		HDMI_CORE_BASE(0x70C0 + 4 * (n))
+#define HDMI_HDCP_AN(n)			HDMI_CORE_BASE(0x70E0 + 4 * (n))
+
+#define HDMI_HDCP_BCAPS			HDMI_CORE_BASE(0x7100)
+#define HDMI_HDCP_BSTATUS_0		HDMI_CORE_BASE(0x7110)
+#define HDMI_HDCP_BSTATUS_1		HDMI_CORE_BASE(0x7114)
+#define HDMI_HDCP_RI_0			HDMI_CORE_BASE(0x7140)
+#define HDMI_HDCP_RI_1			HDMI_CORE_BASE(0x7144)
+#define HDMI_HDCP_I2C_INT		HDMI_CORE_BASE(0x7180)
+#define HDMI_HDCP_AN_INT		HDMI_CORE_BASE(0x7190)
+#define HDMI_HDCP_WDT_INT		HDMI_CORE_BASE(0x71A0)
+#define HDMI_HDCP_RI_INT		HDMI_CORE_BASE(0x71B0)
+#define HDMI_HDCP_RI_COMPARE_0		HDMI_CORE_BASE(0x71D0)
+#define HDMI_HDCP_RI_COMPARE_1		HDMI_CORE_BASE(0x71D4)
+#define HDMI_HDCP_FRAME_COUNT		HDMI_CORE_BASE(0x71E0)
+
+#define HDMI_RGB_ROUND_EN		HDMI_CORE_BASE(0xD500)
+#define HDMI_VACT_SPACE_R_0		HDMI_CORE_BASE(0xD504)
+#define HDMI_VACT_SPACE_R_1		HDMI_CORE_BASE(0xD508)
+#define HDMI_VACT_SPACE_G_0		HDMI_CORE_BASE(0xD50C)
+#define HDMI_VACT_SPACE_G_1		HDMI_CORE_BASE(0xD510)
+#define HDMI_VACT_SPACE_B_0		HDMI_CORE_BASE(0xD514)
+#define HDMI_VACT_SPACE_B_1		HDMI_CORE_BASE(0xD518)
+
+#define HDMI_BLUE_SCREEN_B_0		HDMI_CORE_BASE(0xD520)
+#define HDMI_BLUE_SCREEN_B_1		HDMI_CORE_BASE(0xD524)
+#define HDMI_BLUE_SCREEN_G_0		HDMI_CORE_BASE(0xD528)
+#define HDMI_BLUE_SCREEN_G_1		HDMI_CORE_BASE(0xD52C)
+#define HDMI_BLUE_SCREEN_R_0		HDMI_CORE_BASE(0xD530)
+#define HDMI_BLUE_SCREEN_R_1		HDMI_CORE_BASE(0xD534)
+
+/* HDMI I2S register */
+#define HDMI_I2S_CLK_CON		HDMI_I2S_BASE(0x000)
+#define HDMI_I2S_CON_1			HDMI_I2S_BASE(0x004)
+#define HDMI_I2S_CON_2			HDMI_I2S_BASE(0x008)
+#define HDMI_I2S_PIN_SEL_0		HDMI_I2S_BASE(0x00c)
+#define HDMI_I2S_PIN_SEL_1		HDMI_I2S_BASE(0x010)
+#define HDMI_I2S_PIN_SEL_2		HDMI_I2S_BASE(0x014)
+#define HDMI_I2S_PIN_SEL_3		HDMI_I2S_BASE(0x018)
+#define HDMI_I2S_DSD_CON		HDMI_I2S_BASE(0x01c)
+#define HDMI_I2S_MUX_CON		HDMI_I2S_BASE(0x020)
+#define HDMI_I2S_CH_ST_CON		HDMI_I2S_BASE(0x024)
+#define HDMI_I2S_CH_ST_0		HDMI_I2S_BASE(0x028)
+#define HDMI_I2S_CH_ST_1		HDMI_I2S_BASE(0x02c)
+#define HDMI_I2S_CH_ST_2		HDMI_I2S_BASE(0x030)
+#define HDMI_I2S_CH_ST_3		HDMI_I2S_BASE(0x034)
+#define HDMI_I2S_CH_ST_4		HDMI_I2S_BASE(0x038)
+#define HDMI_I2S_CH_ST_SH_0		HDMI_I2S_BASE(0x03c)
+#define HDMI_I2S_CH_ST_SH_1		HDMI_I2S_BASE(0x040)
+#define HDMI_I2S_CH_ST_SH_2		HDMI_I2S_BASE(0x044)
+#define HDMI_I2S_CH_ST_SH_3		HDMI_I2S_BASE(0x048)
+#define HDMI_I2S_CH_ST_SH_4		HDMI_I2S_BASE(0x04c)
+#define HDMI_I2S_MUX_CH			HDMI_I2S_BASE(0x054)
+#define HDMI_I2S_MUX_CUV		HDMI_I2S_BASE(0x058)
+
+/* I2S bit definition */
+
+/* I2S_CLK_CON */
+#define HDMI_I2S_CLK_DIS		(0)
+#define HDMI_I2S_CLK_EN			(1)
+
+/* I2S_CON_1 */
+#define HDMI_I2S_SCLK_FALLING_EDGE	(0 << 1)
+#define HDMI_I2S_SCLK_RISING_EDGE	(1 << 1)
+#define HDMI_I2S_L_CH_LOW_POL		(0)
+#define HDMI_I2S_L_CH_HIGH_POL		(1)
+
+/* I2S_CON_2 */
+#define HDMI_I2S_MSB_FIRST_MODE		(0 << 6)
+#define HDMI_I2S_LSB_FIRST_MODE		(1 << 6)
+#define HDMI_I2S_BIT_CH_32FS		(0 << 4)
+#define HDMI_I2S_BIT_CH_48FS		(1 << 4)
+#define HDMI_I2S_BIT_CH_RESERVED	(2 << 4)
+#define HDMI_I2S_SDATA_16BIT		(1 << 2)
+#define HDMI_I2S_SDATA_20BIT		(2 << 2)
+#define HDMI_I2S_SDATA_24BIT		(3 << 2)
+#define HDMI_I2S_BASIC_FORMAT		(0)
+#define HDMI_I2S_L_JUST_FORMAT		(2)
+#define HDMI_I2S_R_JUST_FORMAT		(3)
+#define HDMI_I2S_CON_2_CLR		(~(0xFF))
+#define HDMI_I2S_SET_BIT_CH(x)		(((x) & 0x7) << 4)
+#define HDMI_I2S_SET_SDATA_BIT(x)	(((x) & 0x7) << 2)
+
+/* I2S_PIN_SEL_0 */
+#define HDMI_I2S_SEL_SCLK(x)		(((x) & 0x7) << 4)
+#define HDMI_I2S_SEL_LRCK(x)		((x) & 0x7)
+
+/* I2S_PIN_SEL_1 */
+#define HDMI_I2S_SEL_SDATA1(x)		(((x) & 0x7) << 4)
+#define HDMI_I2S_SEL_SDATA2(x)		((x) & 0x7)
+
+/* I2S_PIN_SEL_2 */
+#define HDMI_I2S_SEL_SDATA3(x)		(((x) & 0x7) << 4)
+#define HDMI_I2S_SEL_SDATA2(x)		((x) & 0x7)
+
+/* I2S_PIN_SEL_3 */
+#define HDMI_I2S_SEL_DSD(x)		((x) & 0x7)
+
+/* I2S_DSD_CON */
+#define HDMI_I2S_DSD_CLK_RI_EDGE	(1 << 1)
+#define HDMI_I2S_DSD_CLK_FA_EDGE	(0 << 1)
+#define HDMI_I2S_DSD_ENABLE		(1)
+#define HDMI_I2S_DSD_DISABLE		(0)
+
+/* I2S_MUX_CON */
+#define HDMI_I2S_NOISE_FILTER_ZERO	(0 << 5)
+#define HDMI_I2S_NOISE_FILTER_2_STAGE	(1 << 5)
+#define HDMI_I2S_NOISE_FILTER_3_STAGE	(2 << 5)
+#define HDMI_I2S_NOISE_FILTER_4_STAGE	(3 << 5)
+#define HDMI_I2S_NOISE_FILTER_5_STAGE	(4 << 5)
+#define HDMI_I2S_IN_DISABLE		(1 << 4)
+#define HDMI_I2S_IN_ENABLE		(0 << 4)
+#define HDMI_I2S_AUD_SPDIF		(0 << 2)
+#define HDMI_I2S_AUD_I2S		(1 << 2)
+#define HDMI_I2S_AUD_DSD		(2 << 2)
+#define HDMI_I2S_CUV_SPDIF_ENABLE	(0 << 1)
+#define HDMI_I2S_CUV_I2S_ENABLE		(1 << 1)
+#define HDMI_I2S_MUX_DISABLE		(0)
+#define HDMI_I2S_MUX_ENABLE		(1)
+#define HDMI_I2S_MUX_CON_CLR		(~(0xFF))
+
+/* I2S_CH_ST_CON */
+#define HDMI_I2S_CH_STATUS_RELOAD	(1)
+#define HDMI_I2S_CH_ST_CON_CLR		(~(1))
+
+/* I2S_CH_ST_0 / I2S_CH_ST_SH_0 */
+#define HDMI_I2S_CH_STATUS_MODE_0	(0 << 6)
+#define HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH	(0 << 3)
+#define HDMI_I2S_2AUD_CH_WITH_PREEMPH	(1 << 3)
+#define HDMI_I2S_DEFAULT_EMPHASIS	(0 << 3)
+#define HDMI_I2S_COPYRIGHT		(0 << 2)
+#define HDMI_I2S_NO_COPYRIGHT		(1 << 2)
+#define HDMI_I2S_LINEAR_PCM		(0 << 1)
+#define HDMI_I2S_NO_LINEAR_PCM		(1 << 1)
+#define HDMI_I2S_CONSUMER_FORMAT	(0)
+#define HDMI_I2S_PROF_FORMAT		(1)
+#define HDMI_I2S_CH_ST_0_CLR		(~(0xFF))
+
+/* I2S_CH_ST_1 / I2S_CH_ST_SH_1 */
+#define HDMI_I2S_CD_PLAYER		(0x00)
+#define HDMI_I2S_DAT_PLAYER		(0x03)
+#define HDMI_I2S_DCC_PLAYER		(0x43)
+#define HDMI_I2S_MINI_DISC_PLAYER	(0x49)
+
+/* I2S_CH_ST_2 / I2S_CH_ST_SH_2 */
+#define HDMI_I2S_CHANNEL_NUM_MASK	(0xF << 4)
+#define HDMI_I2S_SOURCE_NUM_MASK	(0xF)
+#define HDMI_I2S_SET_CHANNEL_NUM(x)	(((x) & (0xF)) << 4)
+#define HDMI_I2S_SET_SOURCE_NUM(x)	((x) & (0xF))
+
+/* I2S_CH_ST_3 / I2S_CH_ST_SH_3 */
+#define HDMI_I2S_CLK_ACCUR_LEVEL_1	(1 << 4)
+#define HDMI_I2S_CLK_ACCUR_LEVEL_2	(0 << 4)
+#define HDMI_I2S_CLK_ACCUR_LEVEL_3	(2 << 4)
+#define HDMI_I2S_SMP_FREQ_44_1		(0x0)
+#define HDMI_I2S_SMP_FREQ_48		(0x2)
+#define HDMI_I2S_SMP_FREQ_32		(0x3)
+#define HDMI_I2S_SMP_FREQ_96		(0xA)
+#define HDMI_I2S_SET_SMP_FREQ(x)	((x) & (0xF))
+
+/* I2S_CH_ST_4 / I2S_CH_ST_SH_4 */
+#define HDMI_I2S_ORG_SMP_FREQ_44_1	(0xF << 4)
+#define HDMI_I2S_ORG_SMP_FREQ_88_2	(0x7 << 4)
+#define HDMI_I2S_ORG_SMP_FREQ_22_05	(0xB << 4)
+#define HDMI_I2S_ORG_SMP_FREQ_176_4	(0x3 << 4)
+#define HDMI_I2S_WORD_LEN_NOT_DEFINE	(0x0 << 1)
+#define HDMI_I2S_WORD_LEN_MAX24_20BITS	(0x1 << 1)
+#define HDMI_I2S_WORD_LEN_MAX24_22BITS	(0x2 << 1)
+#define HDMI_I2S_WORD_LEN_MAX24_23BITS	(0x4 << 1)
+#define HDMI_I2S_WORD_LEN_MAX24_24BITS	(0x5 << 1)
+#define HDMI_I2S_WORD_LEN_MAX24_21BITS	(0x6 << 1)
+#define HDMI_I2S_WORD_LEN_MAX20_16BITS	(0x1 << 1)
+#define HDMI_I2S_WORD_LEN_MAX20_18BITS	(0x2 << 1)
+#define HDMI_I2S_WORD_LEN_MAX20_19BITS	(0x4 << 1)
+#define HDMI_I2S_WORD_LEN_MAX20_20BITS	(0x5 << 1)
+#define HDMI_I2S_WORD_LEN_MAX20_17BITS	(0x6 << 1)
+#define HDMI_I2S_WORD_LEN_MAX_24BITS	(1)
+#define HDMI_I2S_WORD_LEN_MAX_20BITS	(0)
+
+/* I2S_MUX_CH */
+#define HDMI_I2S_CH3_R_EN		(1 << 7)
+#define HDMI_I2S_CH3_L_EN		(1 << 6)
+#define HDMI_I2S_CH3_EN			(3 << 6)
+#define HDMI_I2S_CH2_R_EN		(1 << 5)
+#define HDMI_I2S_CH2_L_EN		(1 << 4)
+#define HDMI_I2S_CH2_EN			(3 << 4)
+#define HDMI_I2S_CH1_R_EN		(1 << 3)
+#define HDMI_I2S_CH1_L_EN		(1 << 2)
+#define HDMI_I2S_CH1_EN			(3 << 2)
+#define HDMI_I2S_CH0_R_EN		(1 << 1)
+#define HDMI_I2S_CH0_L_EN		(1)
+#define HDMI_I2S_CH0_EN			(3)
+#define HDMI_I2S_CH_ALL_EN		(0xFF)
+#define HDMI_I2S_MUX_CH_CLR		(~HDMI_I2S_CH_ALL_EN)
+
+/* I2S_MUX_CUV */
+#define HDMI_I2S_CUV_R_EN		(1 << 1)
+#define HDMI_I2S_CUV_L_EN		(1)
+#define HDMI_I2S_CUV_RL_EN		(0x03)
+
+/* I2S_CUV_L_R */
+#define HDMI_I2S_CUV_R_DATA_MASK	(0x7 << 4)
+#define HDMI_I2S_CUV_L_DATA_MASK	(0x7)
+
+/* Timing generator registers */
+/* TG configure/status registers */
+#define HDMI_TG_VACT_ST3_L		HDMI_TG_BASE(0x0068)
+#define HDMI_TG_VACT_ST3_H		HDMI_TG_BASE(0x006c)
+#define HDMI_TG_VACT_ST4_L		HDMI_TG_BASE(0x0070)
+#define HDMI_TG_VACT_ST4_H		HDMI_TG_BASE(0x0074)
+#define HDMI_TG_3D			HDMI_TG_BASE(0x00F0)
+
 #endif /* SAMSUNG_REGS_HDMI_H */
diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig
index 754e14b..42e665c 100644
--- a/drivers/gpu/drm/gma500/Kconfig
+++ b/drivers/gpu/drm/gma500/Kconfig
@@ -16,8 +16,7 @@
 	depends on DRM_GMA500
 	help
 	  Say yes to include support for GMA600 (Intel Moorestown/Oaktrail)
-	  platforms with LVDS ports. HDMI and MIPI are not currently
-	  supported.
+	  platforms with LVDS ports. MIPI is not currently supported.
 
 config DRM_GMA3600
 	bool "Intel GMA3600/3650 support (Experimental)"
@@ -25,3 +24,10 @@
 	help
 	  Say yes to include basic support for Intel GMA3600/3650 (Intel
 	  Cedar Trail) platforms.
+
+config DRM_MEDFIELD
+	bool "Intel Medfield support (Experimental)"
+	depends on DRM_GMA500 && X86_INTEL_MID
+	help
+	  Say yes to include support for the Intel Medfield platform.
+
diff --git a/drivers/gpu/drm/gma500/Makefile b/drivers/gpu/drm/gma500/Makefile
index 81c103b..1583982 100644
--- a/drivers/gpu/drm/gma500/Makefile
+++ b/drivers/gpu/drm/gma500/Makefile
@@ -37,4 +37,14 @@
 	  oaktrail_hdmi.o \
 	  oaktrail_hdmi_i2c.o
 
+gma500_gfx-$(CONFIG_DRM_MEDFIELD) += mdfld_device.o \
+	  mdfld_output.o \
+	  mdfld_intel_display.o \
+	  mdfld_dsi_output.o \
+	  mdfld_dsi_dpi.o \
+	  mdfld_dsi_pkg_sender.o \
+	  mdfld_tpo_vid.o \
+	  mdfld_tmd_vid.o \
+	  tc35876x-dsi-lvds.o
+
 obj-$(CONFIG_DRM_GMA500) += gma500_gfx.o
diff --git a/drivers/gpu/drm/gma500/cdv_device.c b/drivers/gpu/drm/gma500/cdv_device.c
index 53404af..a54cc73 100644
--- a/drivers/gpu/drm/gma500/cdv_device.c
+++ b/drivers/gpu/drm/gma500/cdv_device.c
@@ -202,13 +202,12 @@
 	pci_dev_put(pci_root);
 }
 
-#define PSB_APM_CMD			0x0
-#define PSB_APM_STS			0x04
 #define PSB_PM_SSC			0x20
 #define PSB_PM_SSS			0x30
-#define PSB_PWRGT_GFX_MASK		0x3
-#define CDV_PWRGT_DISPLAY_CNTR		0x000fc00c
-#define CDV_PWRGT_DISPLAY_STS		0x000fc00c
+#define PSB_PWRGT_GFX_ON		0x02
+#define PSB_PWRGT_GFX_OFF		0x01
+#define PSB_PWRGT_GFX_D0		0x00
+#define PSB_PWRGT_GFX_D3		0x03
 
 static void cdv_init_pm(struct drm_device *dev)
 {
@@ -221,26 +220,22 @@
 	dev_priv->ospm_base = CDV_MSG_READ32(PSB_PUNIT_PORT,
 							PSB_OSPMBA) & 0xFFFF;
 
-	/* Force power on for now */
+	/* Power status */
 	pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
-	pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
 
+	/* Enable the GPU */
+	pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
+	pwr_cnt |= PSB_PWRGT_GFX_ON;
 	outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
+
+	/* Wait for the GPU power */
 	for (i = 0; i < 5; i++) {
 		u32 pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
 		if ((pwr_sts & PSB_PWRGT_GFX_MASK) == 0)
-			break;
+			return;
 		udelay(10);
 	}
-	pwr_cnt = inl(dev_priv->ospm_base + PSB_PM_SSC);
-	pwr_cnt &= ~CDV_PWRGT_DISPLAY_CNTR;
-	outl(pwr_cnt, dev_priv->ospm_base + PSB_PM_SSC);
-	for (i = 0; i < 5; i++) {
-		u32 pwr_sts = inl(dev_priv->ospm_base + PSB_PM_SSS);
-		if ((pwr_sts & CDV_PWRGT_DISPLAY_STS) == 0)
-			break;
-		udelay(10);
-	}
+	dev_err(dev->dev, "GPU: power management timed out.\n");
 }
 
 /**
@@ -249,11 +244,50 @@
  *
  *	Save the state we need in order to be able to restore the interface
  *	upon resume from suspend
- *
- *	FIXME: review
  */
 static int cdv_save_display_registers(struct drm_device *dev)
 {
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	struct psb_save_area *regs = &dev_priv->regs;
+	struct drm_connector *connector;
+
+	dev_info(dev->dev, "Saving GPU registers.\n");
+
+	pci_read_config_byte(dev->pdev, 0xF4, &regs->cdv.saveLBB);
+
+	regs->cdv.saveDSPCLK_GATE_D = REG_READ(DSPCLK_GATE_D);
+	regs->cdv.saveRAMCLK_GATE_D = REG_READ(RAMCLK_GATE_D);
+
+	regs->cdv.saveDSPARB = REG_READ(DSPARB);
+	regs->cdv.saveDSPFW[0] = REG_READ(DSPFW1);
+	regs->cdv.saveDSPFW[1] = REG_READ(DSPFW2);
+	regs->cdv.saveDSPFW[2] = REG_READ(DSPFW3);
+	regs->cdv.saveDSPFW[3] = REG_READ(DSPFW4);
+	regs->cdv.saveDSPFW[4] = REG_READ(DSPFW5);
+	regs->cdv.saveDSPFW[5] = REG_READ(DSPFW6);
+
+	regs->cdv.saveADPA = REG_READ(ADPA);
+
+	regs->cdv.savePP_CONTROL = REG_READ(PP_CONTROL);
+	regs->cdv.savePFIT_PGM_RATIOS = REG_READ(PFIT_PGM_RATIOS);
+	regs->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL);
+	regs->saveBLC_PWM_CTL2 = REG_READ(BLC_PWM_CTL2);
+	regs->cdv.saveLVDS = REG_READ(LVDS);
+
+	regs->cdv.savePFIT_CONTROL = REG_READ(PFIT_CONTROL);
+
+	regs->cdv.savePP_ON_DELAYS = REG_READ(PP_ON_DELAYS);
+	regs->cdv.savePP_OFF_DELAYS = REG_READ(PP_OFF_DELAYS);
+	regs->cdv.savePP_CYCLE = REG_READ(PP_CYCLE);
+
+	regs->cdv.saveVGACNTRL = REG_READ(VGACNTRL);
+
+	regs->cdv.saveIER = REG_READ(PSB_INT_ENABLE_R);
+	regs->cdv.saveIMR = REG_READ(PSB_INT_MASK_R);
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+		connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
+
 	return 0;
 }
 
@@ -267,16 +301,113 @@
  */
 static int cdv_restore_display_registers(struct drm_device *dev)
 {
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	struct psb_save_area *regs = &dev_priv->regs;
+	struct drm_connector *connector;
+	u32 temp;
+
+	pci_write_config_byte(dev->pdev, 0xF4, regs->cdv.saveLBB);
+
+	REG_WRITE(DSPCLK_GATE_D, regs->cdv.saveDSPCLK_GATE_D);
+	REG_WRITE(RAMCLK_GATE_D, regs->cdv.saveRAMCLK_GATE_D);
+
+	/* BIOS does below anyway */
+	REG_WRITE(DPIO_CFG, 0);
+	REG_WRITE(DPIO_CFG, DPIO_MODE_SELECT_0 | DPIO_CMN_RESET_N);
+
+	temp = REG_READ(DPLL_A);
+	if ((temp & DPLL_SYNCLOCK_ENABLE) == 0) {
+		REG_WRITE(DPLL_A, temp | DPLL_SYNCLOCK_ENABLE);
+		REG_READ(DPLL_A);
+	}
+
+	temp = REG_READ(DPLL_B);
+	if ((temp & DPLL_SYNCLOCK_ENABLE) == 0) {
+		REG_WRITE(DPLL_B, temp | DPLL_SYNCLOCK_ENABLE);
+		REG_READ(DPLL_B);
+	}
+
+	udelay(500);
+
+	REG_WRITE(DSPFW1, regs->cdv.saveDSPFW[0]);
+	REG_WRITE(DSPFW2, regs->cdv.saveDSPFW[1]);
+	REG_WRITE(DSPFW3, regs->cdv.saveDSPFW[2]);
+	REG_WRITE(DSPFW4, regs->cdv.saveDSPFW[3]);
+	REG_WRITE(DSPFW5, regs->cdv.saveDSPFW[4]);
+	REG_WRITE(DSPFW6, regs->cdv.saveDSPFW[5]);
+
+	REG_WRITE(DSPARB, regs->cdv.saveDSPARB);
+	REG_WRITE(ADPA, regs->cdv.saveADPA);
+
+	REG_WRITE(BLC_PWM_CTL2, regs->saveBLC_PWM_CTL2);
+	REG_WRITE(LVDS, regs->cdv.saveLVDS);
+	REG_WRITE(PFIT_CONTROL, regs->cdv.savePFIT_CONTROL);
+	REG_WRITE(PFIT_PGM_RATIOS, regs->cdv.savePFIT_PGM_RATIOS);
+	REG_WRITE(BLC_PWM_CTL, regs->saveBLC_PWM_CTL);
+	REG_WRITE(PP_ON_DELAYS, regs->cdv.savePP_ON_DELAYS);
+	REG_WRITE(PP_OFF_DELAYS, regs->cdv.savePP_OFF_DELAYS);
+	REG_WRITE(PP_CYCLE, regs->cdv.savePP_CYCLE);
+	REG_WRITE(PP_CONTROL, regs->cdv.savePP_CONTROL);
+
+	REG_WRITE(VGACNTRL, regs->cdv.saveVGACNTRL);
+
+	REG_WRITE(PSB_INT_ENABLE_R, regs->cdv.saveIER);
+	REG_WRITE(PSB_INT_MASK_R, regs->cdv.saveIMR);
+
+	/* Fix arbitration bug */
+	CDV_MSG_WRITE32(3, 0x30, 0x08027108);
+
+	drm_mode_config_reset(dev);
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+		connector->funcs->dpms(connector, DRM_MODE_DPMS_ON);
+
+	/* Resume the modeset for every activated CRTC */
+	drm_helper_resume_force_mode(dev);
 	return 0;
 }
 
 static int cdv_power_down(struct drm_device *dev)
 {
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	u32 pwr_cnt, pwr_mask, pwr_sts;
+	int tries = 5;
+
+	pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
+	pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
+	pwr_cnt |= PSB_PWRGT_GFX_OFF;
+	pwr_mask = PSB_PWRGT_GFX_MASK;
+
+	outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
+
+	while (tries--) {
+		pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
+		if ((pwr_sts & pwr_mask) == PSB_PWRGT_GFX_D3)
+			return 0;
+		udelay(10);
+	}
 	return 0;
 }
 
 static int cdv_power_up(struct drm_device *dev)
 {
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	u32 pwr_cnt, pwr_mask, pwr_sts;
+	int tries = 5;
+
+	pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
+	pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
+	pwr_cnt |= PSB_PWRGT_GFX_ON;
+	pwr_mask = PSB_PWRGT_GFX_MASK;
+
+	outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
+
+	while (tries--) {
+		pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
+		if ((pwr_sts & pwr_mask) == PSB_PWRGT_GFX_D0)
+			return 0;
+		udelay(10);
+	}
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/gma500/cdv_device.h b/drivers/gpu/drm/gma500/cdv_device.h
index 2a88b7b..9561e17 100644
--- a/drivers/gpu/drm/gma500/cdv_device.h
+++ b/drivers/gpu/drm/gma500/cdv_device.h
@@ -26,7 +26,7 @@
 extern struct drm_display_mode *cdv_intel_crtc_mode_get(struct drm_device *dev,
 					     struct drm_crtc *crtc);
 
-extern inline void cdv_intel_wait_for_vblank(struct drm_device *dev)
+static inline void cdv_intel_wait_for_vblank(struct drm_device *dev)
 {
 	/* Wait for 20ms, i.e. one cycle at 50hz. */
         /* FIXME: msleep ?? */
diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c
index c100f3e9..a71a6cd 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_crt.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c
@@ -32,6 +32,7 @@
 #include "psb_intel_drv.h"
 #include "psb_intel_reg.h"
 #include "power.h"
+#include "cdv_device.h"
 #include <linux/pm_runtime.h>
 
 
diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
index 18d1152..be84559 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -344,7 +344,7 @@
 /*
  * Returns whether any encoder on the specified pipe is of the specified type
  */
-bool cdv_intel_pipe_has_type(struct drm_crtc *crtc, int type)
+static bool cdv_intel_pipe_has_type(struct drm_crtc *crtc, int type)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_mode_config *mode_config = &dev->mode_config;
@@ -476,7 +476,7 @@
 	return err != target;
 }
 
-int cdv_intel_pipe_set_base(struct drm_crtc *crtc,
+static int cdv_intel_pipe_set_base(struct drm_crtc *crtc,
 			    int x, int y, struct drm_framebuffer *old_fb)
 {
 	struct drm_device *dev = crtc->dev;
@@ -569,7 +569,6 @@
 	int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE;
 	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
 	u32 temp;
-	bool enabled;
 
 	/* XXX: When our outputs are all unaware of DPMS modes other than off
 	 * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
@@ -663,7 +662,6 @@
 		udelay(150);
 		break;
 	}
-	enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF;
 	/*Set FIFO Watermarks*/
 	REG_WRITE(DSPARB, 0x3F3E);
 }
@@ -680,22 +678,6 @@
 	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
 }
 
-void cdv_intel_encoder_prepare(struct drm_encoder *encoder)
-{
-	struct drm_encoder_helper_funcs *encoder_funcs =
-	    encoder->helper_private;
-	/* lvds has its own version of prepare see cdv_intel_lvds_prepare */
-	encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
-}
-
-void cdv_intel_encoder_commit(struct drm_encoder *encoder)
-{
-	struct drm_encoder_helper_funcs *encoder_funcs =
-	    encoder->helper_private;
-	/* lvds has its own version of commit see cdv_intel_lvds_commit */
-	encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
-}
-
 static bool cdv_intel_crtc_mode_fixup(struct drm_crtc *crtc,
 				  struct drm_display_mode *mode,
 				  struct drm_display_mode *adjusted_mode)
@@ -745,7 +727,7 @@
 	int refclk;
 	struct cdv_intel_clock_t clock;
 	u32 dpll = 0, dspcntr, pipeconf;
-	bool ok, is_sdvo = false, is_dvo = false;
+	bool ok;
 	bool is_crt = false, is_lvds = false, is_tv = false;
 	bool is_hdmi = false;
 	struct drm_mode_config *mode_config = &dev->mode_config;
@@ -763,12 +745,6 @@
 		case INTEL_OUTPUT_LVDS:
 			is_lvds = true;
 			break;
-		case INTEL_OUTPUT_SDVO:
-			is_sdvo = true;
-			break;
-		case INTEL_OUTPUT_DVO:
-			is_dvo = true;
-			break;
 		case INTEL_OUTPUT_TVOUT:
 			is_tv = true;
 			break;
@@ -928,7 +904,7 @@
 }
 
 /** Loads the palette/gamma unit for the CRTC with the prepared values */
-void cdv_intel_crtc_load_lut(struct drm_crtc *crtc)
+static void cdv_intel_crtc_load_lut(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_psb_private *dev_priv =
@@ -968,7 +944,7 @@
 		gma_power_end(dev);
 	} else {
 		for (i = 0; i < 256; i++) {
-			dev_priv->save_palette_a[i] =
+			dev_priv->regs.psb.save_palette_a[i] =
 				  ((psb_intel_crtc->lut_r[i] +
 				  psb_intel_crtc->lut_adj[i]) << 16) |
 				  ((psb_intel_crtc->lut_g[i] +
@@ -1338,18 +1314,20 @@
 		gma_power_end(dev);
 	} else {
 		dpll = (pipe == 0) ?
-			dev_priv->saveDPLL_A : dev_priv->saveDPLL_B;
+			dev_priv->regs.psb.saveDPLL_A :
+			dev_priv->regs.psb.saveDPLL_B;
 
 		if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
 			fp = (pipe == 0) ?
-				dev_priv->saveFPA0 :
-				dev_priv->saveFPB0;
+				dev_priv->regs.psb.saveFPA0 :
+				dev_priv->regs.psb.saveFPB0;
 		else
 			fp = (pipe == 0) ?
-				dev_priv->saveFPA1 :
-				dev_priv->saveFPB1;
+				dev_priv->regs.psb.saveFPA1 :
+				dev_priv->regs.psb.saveFPB1;
 
-		is_lvds = (pipe == 1) && (dev_priv->saveLVDS & LVDS_PORT_EN);
+		is_lvds = (pipe == 1) &&
+				(dev_priv->regs.psb.saveLVDS & LVDS_PORT_EN);
 	}
 
 	clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
@@ -1419,13 +1397,17 @@
 		gma_power_end(dev);
 	} else {
 		htot = (pipe == 0) ?
-			dev_priv->saveHTOTAL_A : dev_priv->saveHTOTAL_B;
+			dev_priv->regs.psb.saveHTOTAL_A :
+			dev_priv->regs.psb.saveHTOTAL_B;
 		hsync = (pipe == 0) ?
-			dev_priv->saveHSYNC_A : dev_priv->saveHSYNC_B;
+			dev_priv->regs.psb.saveHSYNC_A :
+			dev_priv->regs.psb.saveHSYNC_B;
 		vtot = (pipe == 0) ?
-			dev_priv->saveVTOTAL_A : dev_priv->saveVTOTAL_B;
+			dev_priv->regs.psb.saveVTOTAL_A :
+			dev_priv->regs.psb.saveVTOTAL_B;
 		vsync = (pipe == 0) ?
-			dev_priv->saveVSYNC_A : dev_priv->saveVSYNC_B;
+			dev_priv->regs.psb.saveVSYNC_A :
+			dev_priv->regs.psb.saveVSYNC_B;
 	}
 
 	mode = kzalloc(sizeof(*mode), GFP_KERNEL);
@@ -1475,34 +1457,3 @@
 	.set_config = cdv_crtc_set_config,
 	.destroy = cdv_intel_crtc_destroy,
 };
-
-/*
- * Set the default value of cursor control and base register
- * to zero. This is a workaround for h/w defect on oaktrail
- */
-void cdv_intel_cursor_init(struct drm_device *dev, int pipe)
-{
-	uint32_t control;
-	uint32_t base;
-
-	switch (pipe) {
-	case 0:
-		control = CURACNTR;
-		base = CURABASE;
-		break;
-	case 1:
-		control = CURBCNTR;
-		base = CURBBASE;
-		break;
-	case 2:
-		control = CURCCNTR;
-		base = CURCBASE;
-		break;
-	default:
-		return;
-	}
-
-	REG_WRITE(control, 0);
-	REG_WRITE(base, 0);
-}
-
diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
index de25560..8d52695 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
@@ -34,6 +34,7 @@
 #include "psb_intel_drv.h"
 #include "psb_drv.h"
 #include "psb_intel_reg.h"
+#include "cdv_device.h"
 #include <linux/pm_runtime.h>
 
 /* hdmi control bits */
diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
index 50e744b..8359c1a 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
@@ -78,13 +78,14 @@
 
 		gma_power_end(dev);
 	} else
-		retval = ((dev_priv->saveBLC_PWM_CTL &
+		retval = ((dev_priv->regs.saveBLC_PWM_CTL &
 			  BACKLIGHT_MODULATION_FREQ_MASK) >>
 			  BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
 
 	return retval;
 }
 
+#if 0
 /*
  * Set LVDS backlight level by I2C command
  */
@@ -165,6 +166,7 @@
 	else
 		cdv_lvds_pwm_set_brightness(dev, level);
 }
+#endif
 
 /**
  * Sets the backlight level.
@@ -184,9 +186,9 @@
 				(level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
 		gma_power_end(dev);
 	} else {
-		blc_pwm_ctl = dev_priv->saveBLC_PWM_CTL &
+		blc_pwm_ctl = dev_priv->regs.saveBLC_PWM_CTL &
 				~BACKLIGHT_DUTY_CYCLE_MASK;
-		dev_priv->saveBLC_PWM_CTL = (blc_pwm_ctl |
+		dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl |
 					(level << BACKLIGHT_DUTY_CYCLE_SHIFT));
 	}
 }
@@ -242,7 +244,7 @@
 {
 }
 
-int cdv_intel_lvds_mode_valid(struct drm_connector *connector,
+static int cdv_intel_lvds_mode_valid(struct drm_connector *connector,
 			      struct drm_display_mode *mode)
 {
 	struct drm_device *dev = connector->dev;
@@ -267,7 +269,7 @@
 	return MODE_OK;
 }
 
-bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder,
+static bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder,
 				  struct drm_display_mode *mode,
 				  struct drm_display_mode *adjusted_mode)
 {
@@ -436,7 +438,7 @@
  * Unregister the DDC bus for this connector then free the driver private
  * structure.
  */
-void cdv_intel_lvds_destroy(struct drm_connector *connector)
+static void cdv_intel_lvds_destroy(struct drm_connector *connector)
 {
 	struct psb_intel_encoder *psb_intel_encoder =
 					psb_intel_attached_encoder(connector);
@@ -448,7 +450,7 @@
 	kfree(connector);
 }
 
-int cdv_intel_lvds_set_property(struct drm_connector *connector,
+static int cdv_intel_lvds_set_property(struct drm_connector *connector,
 				       struct drm_property *property,
 				       uint64_t value)
 {
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index be61673..8ea202f 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -111,39 +111,6 @@
         return 0;
 }
 
-void psbfb_suspend(struct drm_device *dev)
-{
-	struct drm_framebuffer *fb;
-
-	console_lock();
-	mutex_lock(&dev->mode_config.mutex);
-	list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
-		struct psb_framebuffer *psbfb = to_psb_fb(fb);
-		struct fb_info *info = psbfb->fbdev;
-		fb_set_suspend(info, 1);
-		drm_fb_helper_blank(FB_BLANK_POWERDOWN, info);
-	}
-	mutex_unlock(&dev->mode_config.mutex);
-	console_unlock();
-}
-
-void psbfb_resume(struct drm_device *dev)
-{
-	struct drm_framebuffer *fb;
-
-	console_lock();
-	mutex_lock(&dev->mode_config.mutex);
-	list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
-		struct psb_framebuffer *psbfb = to_psb_fb(fb);
-		struct fb_info *info = psbfb->fbdev;
-		fb_set_suspend(info, 0);
-		drm_fb_helper_blank(FB_BLANK_UNBLANK, info);
-	}
-	mutex_unlock(&dev->mode_config.mutex);
-	console_unlock();
-	drm_helper_disable_unused_functions(dev);
-}
-
 static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
 	struct psb_framebuffer *psbfb = vma->vm_private_data;
@@ -158,7 +125,7 @@
 	unsigned long phys_addr = (unsigned long)dev_priv->stolen_base;
 
 	page_num = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
-	address = (unsigned long)vmf->virtual_address;
+	address = (unsigned long)vmf->virtual_address - (vmf->pgoff << PAGE_SHIFT);
 
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
@@ -390,6 +357,7 @@
 	mode_cmd.width = sizes->surface_width;
 	mode_cmd.height = sizes->surface_height;
 	bpp = sizes->surface_bpp;
+	depth = sizes->surface_depth;
 
 	/* No 24bit packed */
 	if (bpp == 24)
@@ -402,7 +370,6 @@
 		 * is ok with some fonts
 		 */
         	mode_cmd.pitches[0] =  ALIGN(mode_cmd.width * ((bpp + 7) / 8), 4096 >> pitch_lines);
-        	depth = sizes->surface_depth;
 
         	size = mode_cmd.pitches[0] * mode_cmd.height;
         	size = ALIGN(size, PAGE_SIZE);
@@ -462,6 +429,7 @@
 	fbdev->psb_fb_helper.fb = fb;
 	fbdev->psb_fb_helper.fbdev = info;
 
+	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
 	strcpy(info->fix.id, "psbfb");
 
 	info->flags = FBINFO_DEFAULT;
@@ -499,18 +467,13 @@
 		info->apertures->ranges[0].size = dev_priv->gtt.stolen_size;
 	}
 
-	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
 	drm_fb_helper_fill_var(info, &fbdev->psb_fb_helper,
 				sizes->fb_width, sizes->fb_height);
 
 	info->fix.mmio_start = pci_resource_start(dev->pdev, 0);
 	info->fix.mmio_len = pci_resource_len(dev->pdev, 0);
 
-	info->pixmap.size = 64 * 1024;
-	info->pixmap.buf_align = 8;
-	info->pixmap.access_align = 32;
-	info->pixmap.flags = FB_PIXMAP_SYSTEM;
-	info->pixmap.scan_align = 1;
+	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
 
 	dev_info(dev->dev, "allocated %dx%d fb\n",
 					psbfb->base.width, psbfb->base.height);
@@ -559,11 +522,21 @@
 static void psbfb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
 							u16 blue, int regno)
 {
+	struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc);
+
+	intel_crtc->lut_r[regno] = red >> 8;
+	intel_crtc->lut_g[regno] = green >> 8;
+	intel_crtc->lut_b[regno] = blue >> 8;
 }
 
 static void psbfb_gamma_get(struct drm_crtc *crtc, u16 *red,
 					u16 *green, u16 *blue, int regno)
 {
+	struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc);
+
+	*red = intel_crtc->lut_r[regno] << 8;
+	*green = intel_crtc->lut_g[regno] << 8;
+	*blue = intel_crtc->lut_b[regno] << 8;
 }
 
 static int psbfb_probe(struct drm_fb_helper *helper,
@@ -588,7 +561,7 @@
 	.fb_probe = psbfb_probe,
 };
 
-int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev)
+static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev)
 {
 	struct fb_info *info;
 	struct psb_framebuffer *psbfb = &fbdev->pfb;
@@ -630,7 +603,7 @@
 	return 0;
 }
 
-void psb_fbdev_fini(struct drm_device *dev)
+static void psb_fbdev_fini(struct drm_device *dev)
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
 
@@ -724,10 +697,7 @@
 	if (dev_priv->backlight_property)
 		return 0;
 
-	backlight = drm_property_create(dev, DRM_MODE_PROP_RANGE,
-							"backlight", 2);
-	backlight->values[0] = 0;
-	backlight->values[1] = 100;
+	backlight = drm_property_create_range(dev, 0, "backlight", 0, 100);
 
 	dev_priv->backlight_property = backlight;
 
diff --git a/drivers/gpu/drm/gma500/gem_glue.c b/drivers/gpu/drm/gma500/gem_glue.c
index daac121..3c17634 100644
--- a/drivers/gpu/drm/gma500/gem_glue.c
+++ b/drivers/gpu/drm/gma500/gem_glue.c
@@ -19,6 +19,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm.h>
+#include "gem_glue.h"
 
 void drm_gem_object_release_wrap(struct drm_gem_object *obj)
 {
diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c
index aff194f..c6465b4 100644
--- a/drivers/gpu/drm/gma500/gtt.c
+++ b/drivers/gpu/drm/gma500/gtt.c
@@ -57,7 +57,7 @@
  *	Given a gtt_range object return the GTT offset of the page table
  *	entries for this gtt_range
  */
-u32 *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r)
+static u32 *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r)
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	unsigned long offset;
@@ -378,7 +378,7 @@
 	kfree(gt);
 }
 
-void psb_gtt_alloc(struct drm_device *dev)
+static void psb_gtt_alloc(struct drm_device *dev)
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	init_rwsem(&dev_priv->gtt.sem);
diff --git a/drivers/gpu/drm/gma500/intel_gmbus.c b/drivers/gpu/drm/gma500/intel_gmbus.c
index 147584a..9db9052 100644
--- a/drivers/gpu/drm/gma500/intel_gmbus.c
+++ b/drivers/gpu/drm/gma500/intel_gmbus.c
@@ -395,7 +395,7 @@
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	int ret, i;
 
-	dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS,
+	dev_priv->gmbus = kcalloc(GMBUS_NUM_PORTS, sizeof(struct intel_gmbus),
 				  GFP_KERNEL);
 	if (dev_priv->gmbus == NULL)
 		return -ENOMEM;
diff --git a/drivers/gpu/drm/gma500/mdfld_device.c b/drivers/gpu/drm/gma500/mdfld_device.c
new file mode 100644
index 0000000..af65678
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_device.c
@@ -0,0 +1,691 @@
+/**************************************************************************
+ * Copyright (c) 2011, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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 "psb_drv.h"
+#include "mid_bios.h"
+#include "mdfld_output.h"
+#include "mdfld_dsi_output.h"
+#include "tc35876x-dsi-lvds.h"
+
+#include <asm/intel_scu_ipc.h>
+
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+
+#define MRST_BLC_MAX_PWM_REG_FREQ	    0xFFFF
+#define BLC_PWM_PRECISION_FACTOR 100	/* 10000000 */
+#define BLC_PWM_FREQ_CALC_CONSTANT 32
+#define MHz 1000000
+#define BRIGHTNESS_MIN_LEVEL 1
+#define BRIGHTNESS_MAX_LEVEL 100
+#define BRIGHTNESS_MASK	0xFF
+#define BLC_POLARITY_NORMAL 0
+#define BLC_POLARITY_INVERSE 1
+#define BLC_ADJUSTMENT_MAX 100
+
+#define MDFLD_BLC_PWM_PRECISION_FACTOR    10
+#define MDFLD_BLC_MAX_PWM_REG_FREQ        0xFFFE
+#define MDFLD_BLC_MIN_PWM_REG_FREQ        0x2
+
+#define MDFLD_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
+#define MDFLD_BACKLIGHT_PWM_CTL_SHIFT	(16)
+
+static struct backlight_device *mdfld_backlight_device;
+
+int mdfld_set_brightness(struct backlight_device *bd)
+{
+	struct drm_device *dev =
+		(struct drm_device *)bl_get_data(mdfld_backlight_device);
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	int level = bd->props.brightness;
+
+	DRM_DEBUG_DRIVER("backlight level set to %d\n", level);
+
+	/* Perform value bounds checking */
+	if (level < BRIGHTNESS_MIN_LEVEL)
+		level = BRIGHTNESS_MIN_LEVEL;
+
+	if (gma_power_begin(dev, false)) {
+		u32 adjusted_level = 0;
+
+		/*
+		 * Adjust the backlight level with the percent in
+		 * dev_priv->blc_adj2
+		 */
+		adjusted_level = level * dev_priv->blc_adj2;
+		adjusted_level = adjusted_level / BLC_ADJUSTMENT_MAX;
+		dev_priv->brightness_adjusted = adjusted_level;
+
+		if (mdfld_get_panel_type(dev, 0) == TC35876X) {
+			if (dev_priv->dpi_panel_on[0] ||
+					dev_priv->dpi_panel_on[2])
+				tc35876x_brightness_control(dev,
+						dev_priv->brightness_adjusted);
+		} else {
+			if (dev_priv->dpi_panel_on[0])
+				mdfld_dsi_brightness_control(dev, 0,
+						dev_priv->brightness_adjusted);
+		}
+
+		if (dev_priv->dpi_panel_on[2])
+			mdfld_dsi_brightness_control(dev, 2,
+					dev_priv->brightness_adjusted);
+		gma_power_end(dev);
+	}
+
+	/* cache the brightness for later use */
+	dev_priv->brightness = level;
+	return 0;
+}
+
+static int mdfld_get_brightness(struct backlight_device *bd)
+{
+	struct drm_device *dev =
+		(struct drm_device *)bl_get_data(mdfld_backlight_device);
+	struct drm_psb_private *dev_priv = dev->dev_private;
+
+	DRM_DEBUG_DRIVER("brightness = 0x%x \n", dev_priv->brightness);
+
+	/* return locally cached var instead of HW read (due to DPST etc.) */
+	return dev_priv->brightness;
+}
+
+static const struct backlight_ops mdfld_ops = {
+	.get_brightness = mdfld_get_brightness,
+	.update_status  = mdfld_set_brightness,
+};
+
+static int device_backlight_init(struct drm_device *dev)
+{
+	struct drm_psb_private *dev_priv = (struct drm_psb_private *)
+		dev->dev_private;
+
+	dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX;
+	dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX;
+
+	return 0;
+}
+
+static int mdfld_backlight_init(struct drm_device *dev)
+{
+	struct backlight_properties props;
+	int ret = 0;
+
+	memset(&props, 0, sizeof(struct backlight_properties));
+	props.max_brightness = BRIGHTNESS_MAX_LEVEL;
+	props.type = BACKLIGHT_PLATFORM;
+	mdfld_backlight_device = backlight_device_register("mdfld-bl",
+				NULL, (void *)dev, &mdfld_ops, &props);
+
+	if (IS_ERR(mdfld_backlight_device))
+		return PTR_ERR(mdfld_backlight_device);
+
+	ret = device_backlight_init(dev);
+	if (ret)
+		return ret;
+
+	mdfld_backlight_device->props.brightness = BRIGHTNESS_MAX_LEVEL;
+	mdfld_backlight_device->props.max_brightness = BRIGHTNESS_MAX_LEVEL;
+	backlight_update_status(mdfld_backlight_device);
+	return 0;
+}
+#endif
+
+struct backlight_device *mdfld_get_backlight_device(void)
+{
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+	return mdfld_backlight_device;
+#else
+	return NULL;
+#endif
+}
+
+/*
+ * mdfld_save_display_registers
+ *
+ * Description: We are going to suspend so save current display
+ * register state.
+ *
+ * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
+ */
+static int mdfld_save_display_registers(struct drm_device *dev, int pipe)
+{
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	struct medfield_state *regs = &dev_priv->regs.mdfld;
+	int i;
+
+	/* register */
+	u32 dpll_reg = MRST_DPLL_A;
+	u32 fp_reg = MRST_FPA0;
+	u32 pipeconf_reg = PIPEACONF;
+	u32 htot_reg = HTOTAL_A;
+	u32 hblank_reg = HBLANK_A;
+	u32 hsync_reg = HSYNC_A;
+	u32 vtot_reg = VTOTAL_A;
+	u32 vblank_reg = VBLANK_A;
+	u32 vsync_reg = VSYNC_A;
+	u32 pipesrc_reg = PIPEASRC;
+	u32 dspstride_reg = DSPASTRIDE;
+	u32 dsplinoff_reg = DSPALINOFF;
+	u32 dsptileoff_reg = DSPATILEOFF;
+	u32 dspsize_reg = DSPASIZE;
+	u32 dsppos_reg = DSPAPOS;
+	u32 dspsurf_reg = DSPASURF;
+	u32 mipi_reg = MIPI;
+	u32 dspcntr_reg = DSPACNTR;
+	u32 dspstatus_reg = PIPEASTAT;
+	u32 palette_reg = PALETTE_A;
+
+	/* pointer to values */
+	u32 *dpll_val = &regs->saveDPLL_A;
+	u32 *fp_val = &regs->saveFPA0;
+	u32 *pipeconf_val = &regs->savePIPEACONF;
+	u32 *htot_val = &regs->saveHTOTAL_A;
+	u32 *hblank_val = &regs->saveHBLANK_A;
+	u32 *hsync_val = &regs->saveHSYNC_A;
+	u32 *vtot_val = &regs->saveVTOTAL_A;
+	u32 *vblank_val = &regs->saveVBLANK_A;
+	u32 *vsync_val = &regs->saveVSYNC_A;
+	u32 *pipesrc_val = &regs->savePIPEASRC;
+	u32 *dspstride_val = &regs->saveDSPASTRIDE;
+	u32 *dsplinoff_val = &regs->saveDSPALINOFF;
+	u32 *dsptileoff_val = &regs->saveDSPATILEOFF;
+	u32 *dspsize_val = &regs->saveDSPASIZE;
+	u32 *dsppos_val = &regs->saveDSPAPOS;
+	u32 *dspsurf_val = &regs->saveDSPASURF;
+	u32 *mipi_val = &regs->saveMIPI;
+	u32 *dspcntr_val = &regs->saveDSPACNTR;
+	u32 *dspstatus_val = &regs->saveDSPASTATUS;
+	u32 *palette_val = regs->save_palette_a;
+
+	switch (pipe) {
+	case 0:
+		break;
+	case 1:
+		/* regester */
+		dpll_reg = MDFLD_DPLL_B;
+		fp_reg = MDFLD_DPLL_DIV0;
+		pipeconf_reg = PIPEBCONF;
+		htot_reg = HTOTAL_B;
+		hblank_reg = HBLANK_B;
+		hsync_reg = HSYNC_B;
+		vtot_reg = VTOTAL_B;
+		vblank_reg = VBLANK_B;
+		vsync_reg = VSYNC_B;
+		pipesrc_reg = PIPEBSRC;
+		dspstride_reg = DSPBSTRIDE;
+		dsplinoff_reg = DSPBLINOFF;
+		dsptileoff_reg = DSPBTILEOFF;
+		dspsize_reg = DSPBSIZE;
+		dsppos_reg = DSPBPOS;
+		dspsurf_reg = DSPBSURF;
+		dspcntr_reg = DSPBCNTR;
+		dspstatus_reg = PIPEBSTAT;
+		palette_reg = PALETTE_B;
+
+		/* values */
+		dpll_val = &regs->saveDPLL_B;
+		fp_val = &regs->saveFPB0;
+		pipeconf_val = &regs->savePIPEBCONF;
+		htot_val = &regs->saveHTOTAL_B;
+		hblank_val = &regs->saveHBLANK_B;
+		hsync_val = &regs->saveHSYNC_B;
+		vtot_val = &regs->saveVTOTAL_B;
+		vblank_val = &regs->saveVBLANK_B;
+		vsync_val = &regs->saveVSYNC_B;
+		pipesrc_val = &regs->savePIPEBSRC;
+		dspstride_val = &regs->saveDSPBSTRIDE;
+		dsplinoff_val = &regs->saveDSPBLINOFF;
+		dsptileoff_val = &regs->saveDSPBTILEOFF;
+		dspsize_val = &regs->saveDSPBSIZE;
+		dsppos_val = &regs->saveDSPBPOS;
+		dspsurf_val = &regs->saveDSPBSURF;
+		dspcntr_val = &regs->saveDSPBCNTR;
+		dspstatus_val = &regs->saveDSPBSTATUS;
+		palette_val = regs->save_palette_b;
+		break;
+	case 2:
+		/* register */
+		pipeconf_reg = PIPECCONF;
+		htot_reg = HTOTAL_C;
+		hblank_reg = HBLANK_C;
+		hsync_reg = HSYNC_C;
+		vtot_reg = VTOTAL_C;
+		vblank_reg = VBLANK_C;
+		vsync_reg = VSYNC_C;
+		pipesrc_reg = PIPECSRC;
+		dspstride_reg = DSPCSTRIDE;
+		dsplinoff_reg = DSPCLINOFF;
+		dsptileoff_reg = DSPCTILEOFF;
+		dspsize_reg = DSPCSIZE;
+		dsppos_reg = DSPCPOS;
+		dspsurf_reg = DSPCSURF;
+		mipi_reg = MIPI_C;
+		dspcntr_reg = DSPCCNTR;
+		dspstatus_reg = PIPECSTAT;
+		palette_reg = PALETTE_C;
+
+		/* pointer to values */
+		pipeconf_val = &regs->savePIPECCONF;
+		htot_val = &regs->saveHTOTAL_C;
+		hblank_val = &regs->saveHBLANK_C;
+		hsync_val = &regs->saveHSYNC_C;
+		vtot_val = &regs->saveVTOTAL_C;
+		vblank_val = &regs->saveVBLANK_C;
+		vsync_val = &regs->saveVSYNC_C;
+		pipesrc_val = &regs->savePIPECSRC;
+		dspstride_val = &regs->saveDSPCSTRIDE;
+		dsplinoff_val = &regs->saveDSPCLINOFF;
+		dsptileoff_val = &regs->saveDSPCTILEOFF;
+		dspsize_val = &regs->saveDSPCSIZE;
+		dsppos_val = &regs->saveDSPCPOS;
+		dspsurf_val = &regs->saveDSPCSURF;
+		mipi_val = &regs->saveMIPI_C;
+		dspcntr_val = &regs->saveDSPCCNTR;
+		dspstatus_val = &regs->saveDSPCSTATUS;
+		palette_val = regs->save_palette_c;
+		break;
+	default:
+		DRM_ERROR("%s, invalid pipe number.\n", __func__);
+		return -EINVAL;
+	}
+
+	/* Pipe & plane A info */
+	*dpll_val = PSB_RVDC32(dpll_reg);
+	*fp_val = PSB_RVDC32(fp_reg);
+	*pipeconf_val = PSB_RVDC32(pipeconf_reg);
+	*htot_val = PSB_RVDC32(htot_reg);
+	*hblank_val = PSB_RVDC32(hblank_reg);
+	*hsync_val = PSB_RVDC32(hsync_reg);
+	*vtot_val = PSB_RVDC32(vtot_reg);
+	*vblank_val = PSB_RVDC32(vblank_reg);
+	*vsync_val = PSB_RVDC32(vsync_reg);
+	*pipesrc_val = PSB_RVDC32(pipesrc_reg);
+	*dspstride_val = PSB_RVDC32(dspstride_reg);
+	*dsplinoff_val = PSB_RVDC32(dsplinoff_reg);
+	*dsptileoff_val = PSB_RVDC32(dsptileoff_reg);
+	*dspsize_val = PSB_RVDC32(dspsize_reg);
+	*dsppos_val = PSB_RVDC32(dsppos_reg);
+	*dspsurf_val = PSB_RVDC32(dspsurf_reg);
+	*dspcntr_val = PSB_RVDC32(dspcntr_reg);
+	*dspstatus_val = PSB_RVDC32(dspstatus_reg);
+
+	/*save palette (gamma) */
+	for (i = 0; i < 256; i++)
+		palette_val[i] = PSB_RVDC32(palette_reg + (i << 2));
+
+	if (pipe == 1) {
+		regs->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
+		regs->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
+
+		regs->saveHDMIPHYMISCCTL = PSB_RVDC32(HDMIPHYMISCCTL);
+		regs->saveHDMIB_CONTROL = PSB_RVDC32(HDMIB_CONTROL);
+		return 0;
+	}
+
+	*mipi_val = PSB_RVDC32(mipi_reg);
+	return 0;
+}
+
+/*
+ * mdfld_restore_display_registers
+ *
+ * Description: We are going to resume so restore display register state.
+ *
+ * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
+ */
+static int mdfld_restore_display_registers(struct drm_device *dev, int pipe)
+{
+	/* To get  panel out of ULPS mode. */
+	u32 temp = 0;
+	u32 device_ready_reg = DEVICE_READY_REG;
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	struct mdfld_dsi_config *dsi_config = NULL;
+	struct medfield_state *regs = &dev_priv->regs.mdfld;
+	u32 i = 0;
+	u32 dpll = 0;
+	u32 timeout = 0;
+
+	/* regester */
+	u32 dpll_reg = MRST_DPLL_A;
+	u32 fp_reg = MRST_FPA0;
+	u32 pipeconf_reg = PIPEACONF;
+	u32 htot_reg = HTOTAL_A;
+	u32 hblank_reg = HBLANK_A;
+	u32 hsync_reg = HSYNC_A;
+	u32 vtot_reg = VTOTAL_A;
+	u32 vblank_reg = VBLANK_A;
+	u32 vsync_reg = VSYNC_A;
+	u32 pipesrc_reg = PIPEASRC;
+	u32 dspstride_reg = DSPASTRIDE;
+	u32 dsplinoff_reg = DSPALINOFF;
+	u32 dsptileoff_reg = DSPATILEOFF;
+	u32 dspsize_reg = DSPASIZE;
+	u32 dsppos_reg = DSPAPOS;
+	u32 dspsurf_reg = DSPASURF;
+	u32 dspstatus_reg = PIPEASTAT;
+	u32 mipi_reg = MIPI;
+	u32 dspcntr_reg = DSPACNTR;
+	u32 palette_reg = PALETTE_A;
+
+	/* values */
+	u32 dpll_val = regs->saveDPLL_A & ~DPLL_VCO_ENABLE;
+	u32 fp_val = regs->saveFPA0;
+	u32 pipeconf_val = regs->savePIPEACONF;
+	u32 htot_val = regs->saveHTOTAL_A;
+	u32 hblank_val = regs->saveHBLANK_A;
+	u32 hsync_val = regs->saveHSYNC_A;
+	u32 vtot_val = regs->saveVTOTAL_A;
+	u32 vblank_val = regs->saveVBLANK_A;
+	u32 vsync_val = regs->saveVSYNC_A;
+	u32 pipesrc_val = regs->savePIPEASRC;
+	u32 dspstride_val = regs->saveDSPASTRIDE;
+	u32 dsplinoff_val = regs->saveDSPALINOFF;
+	u32 dsptileoff_val = regs->saveDSPATILEOFF;
+	u32 dspsize_val = regs->saveDSPASIZE;
+	u32 dsppos_val = regs->saveDSPAPOS;
+	u32 dspsurf_val = regs->saveDSPASURF;
+	u32 dspstatus_val = regs->saveDSPASTATUS;
+	u32 mipi_val = regs->saveMIPI;
+	u32 dspcntr_val = regs->saveDSPACNTR;
+	u32 *palette_val = regs->save_palette_a;
+
+	switch (pipe) {
+	case 0:
+		dsi_config = dev_priv->dsi_configs[0];
+		break;
+	case 1:
+		/* regester */
+		dpll_reg = MDFLD_DPLL_B;
+		fp_reg = MDFLD_DPLL_DIV0;
+		pipeconf_reg = PIPEBCONF;
+		htot_reg = HTOTAL_B;
+		hblank_reg = HBLANK_B;
+		hsync_reg = HSYNC_B;
+		vtot_reg = VTOTAL_B;
+		vblank_reg = VBLANK_B;
+		vsync_reg = VSYNC_B;
+		pipesrc_reg = PIPEBSRC;
+		dspstride_reg = DSPBSTRIDE;
+		dsplinoff_reg = DSPBLINOFF;
+		dsptileoff_reg = DSPBTILEOFF;
+		dspsize_reg = DSPBSIZE;
+		dsppos_reg = DSPBPOS;
+		dspsurf_reg = DSPBSURF;
+		dspcntr_reg = DSPBCNTR;
+		dspstatus_reg = PIPEBSTAT;
+		palette_reg = PALETTE_B;
+
+		/* values */
+		dpll_val = regs->saveDPLL_B & ~DPLL_VCO_ENABLE;
+		fp_val = regs->saveFPB0;
+		pipeconf_val = regs->savePIPEBCONF;
+		htot_val = regs->saveHTOTAL_B;
+		hblank_val = regs->saveHBLANK_B;
+		hsync_val = regs->saveHSYNC_B;
+		vtot_val = regs->saveVTOTAL_B;
+		vblank_val = regs->saveVBLANK_B;
+		vsync_val = regs->saveVSYNC_B;
+		pipesrc_val = regs->savePIPEBSRC;
+		dspstride_val = regs->saveDSPBSTRIDE;
+		dsplinoff_val = regs->saveDSPBLINOFF;
+		dsptileoff_val = regs->saveDSPBTILEOFF;
+		dspsize_val = regs->saveDSPBSIZE;
+		dsppos_val = regs->saveDSPBPOS;
+		dspsurf_val = regs->saveDSPBSURF;
+		dspcntr_val = regs->saveDSPBCNTR;
+		dspstatus_val = regs->saveDSPBSTATUS;
+		palette_val = regs->save_palette_b;
+		break;
+	case 2:
+		/* regester */
+		pipeconf_reg = PIPECCONF;
+		htot_reg = HTOTAL_C;
+		hblank_reg = HBLANK_C;
+		hsync_reg = HSYNC_C;
+		vtot_reg = VTOTAL_C;
+		vblank_reg = VBLANK_C;
+		vsync_reg = VSYNC_C;
+		pipesrc_reg = PIPECSRC;
+		dspstride_reg = DSPCSTRIDE;
+		dsplinoff_reg = DSPCLINOFF;
+		dsptileoff_reg = DSPCTILEOFF;
+		dspsize_reg = DSPCSIZE;
+		dsppos_reg = DSPCPOS;
+		dspsurf_reg = DSPCSURF;
+		mipi_reg = MIPI_C;
+		dspcntr_reg = DSPCCNTR;
+		dspstatus_reg = PIPECSTAT;
+		palette_reg = PALETTE_C;
+
+		/* values */
+		pipeconf_val = regs->savePIPECCONF;
+		htot_val = regs->saveHTOTAL_C;
+		hblank_val = regs->saveHBLANK_C;
+		hsync_val = regs->saveHSYNC_C;
+		vtot_val = regs->saveVTOTAL_C;
+		vblank_val = regs->saveVBLANK_C;
+		vsync_val = regs->saveVSYNC_C;
+		pipesrc_val = regs->savePIPECSRC;
+		dspstride_val = regs->saveDSPCSTRIDE;
+		dsplinoff_val = regs->saveDSPCLINOFF;
+		dsptileoff_val = regs->saveDSPCTILEOFF;
+		dspsize_val = regs->saveDSPCSIZE;
+		dsppos_val = regs->saveDSPCPOS;
+		dspsurf_val = regs->saveDSPCSURF;
+		mipi_val = regs->saveMIPI_C;
+		dspcntr_val = regs->saveDSPCCNTR;
+		dspstatus_val = regs->saveDSPCSTATUS;
+		palette_val = regs->save_palette_c;
+
+		dsi_config = dev_priv->dsi_configs[1];
+		break;
+	default:
+		DRM_ERROR("%s, invalid pipe number.\n", __func__);
+		return -EINVAL;
+	}
+
+	/*make sure VGA plane is off. it initializes to on after reset!*/
+	PSB_WVDC32(0x80000000, VGACNTRL);
+
+	if (pipe == 1) {
+		PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, dpll_reg);
+		PSB_RVDC32(dpll_reg);
+
+		PSB_WVDC32(fp_val, fp_reg);
+	} else {
+
+		dpll = PSB_RVDC32(dpll_reg);
+
+		if (!(dpll & DPLL_VCO_ENABLE)) {
+
+			/* When ungating power of DPLL, needs to wait 0.5us
+			   before enable the VCO */
+			if (dpll & MDFLD_PWR_GATE_EN) {
+				dpll &= ~MDFLD_PWR_GATE_EN;
+				PSB_WVDC32(dpll, dpll_reg);
+				/* FIXME_MDFLD PO - change 500 to 1 after PO */
+				udelay(500);
+			}
+
+			PSB_WVDC32(fp_val, fp_reg);
+			PSB_WVDC32(dpll_val, dpll_reg);
+			/* FIXME_MDFLD PO - change 500 to 1 after PO */
+			udelay(500);
+
+			dpll_val |= DPLL_VCO_ENABLE;
+			PSB_WVDC32(dpll_val, dpll_reg);
+			PSB_RVDC32(dpll_reg);
+
+			/* wait for DSI PLL to lock */
+			while (timeout < 20000 &&
+			  !(PSB_RVDC32(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) {
+				udelay(150);
+				timeout++;
+			}
+
+			if (timeout == 20000) {
+				DRM_ERROR("%s, can't lock DSIPLL.\n",
+								__func__);
+				return -EINVAL;
+			}
+		}
+	}
+	/* Restore mode */
+	PSB_WVDC32(htot_val, htot_reg);
+	PSB_WVDC32(hblank_val, hblank_reg);
+	PSB_WVDC32(hsync_val, hsync_reg);
+	PSB_WVDC32(vtot_val, vtot_reg);
+	PSB_WVDC32(vblank_val, vblank_reg);
+	PSB_WVDC32(vsync_val, vsync_reg);
+	PSB_WVDC32(pipesrc_val, pipesrc_reg);
+	PSB_WVDC32(dspstatus_val, dspstatus_reg);
+
+	/*set up the plane*/
+	PSB_WVDC32(dspstride_val, dspstride_reg);
+	PSB_WVDC32(dsplinoff_val, dsplinoff_reg);
+	PSB_WVDC32(dsptileoff_val, dsptileoff_reg);
+	PSB_WVDC32(dspsize_val, dspsize_reg);
+	PSB_WVDC32(dsppos_val, dsppos_reg);
+	PSB_WVDC32(dspsurf_val, dspsurf_reg);
+
+	if (pipe == 1) {
+		/* restore palette (gamma) */
+		/*DRM_UDELAY(50000); */
+		for (i = 0; i < 256; i++)
+			PSB_WVDC32(palette_val[i], palette_reg + (i << 2));
+
+		PSB_WVDC32(regs->savePFIT_CONTROL, PFIT_CONTROL);
+		PSB_WVDC32(regs->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
+
+		/*TODO: resume HDMI port */
+
+		/*TODO: resume pipe*/
+
+		/*enable the plane*/
+		PSB_WVDC32(dspcntr_val & ~DISPLAY_PLANE_ENABLE, dspcntr_reg);
+
+		return 0;
+	}
+
+	/*set up pipe related registers*/
+	PSB_WVDC32(mipi_val, mipi_reg);
+
+	/*setup MIPI adapter + MIPI IP registers*/
+	if (dsi_config)
+		mdfld_dsi_controller_init(dsi_config, pipe);
+
+	if (in_atomic() || in_interrupt())
+		mdelay(20);
+	else
+		msleep(20);
+
+	/*enable the plane*/
+	PSB_WVDC32(dspcntr_val, dspcntr_reg);
+
+	if (in_atomic() || in_interrupt())
+		mdelay(20);
+	else
+		msleep(20);
+
+	/* LP Hold Release */
+	temp = REG_READ(mipi_reg);
+	temp |= LP_OUTPUT_HOLD_RELEASE;
+	REG_WRITE(mipi_reg, temp);
+	mdelay(1);
+
+
+	/* Set DSI host to exit from Utra Low Power State */
+	temp = REG_READ(device_ready_reg);
+	temp &= ~ULPS_MASK;
+	temp |= 0x3;
+	temp |= EXIT_ULPS_DEV_READY;
+	REG_WRITE(device_ready_reg, temp);
+	mdelay(1);
+
+	temp = REG_READ(device_ready_reg);
+	temp &= ~ULPS_MASK;
+	temp |= EXITING_ULPS;
+	REG_WRITE(device_ready_reg, temp);
+	mdelay(1);
+
+	/*enable the pipe*/
+	PSB_WVDC32(pipeconf_val, pipeconf_reg);
+
+	/* restore palette (gamma) */
+	/*DRM_UDELAY(50000); */
+	for (i = 0; i < 256; i++)
+		PSB_WVDC32(palette_val[i], palette_reg + (i << 2));
+
+	return 0;
+}
+
+static int mdfld_save_registers(struct drm_device *dev)
+{
+	/* mdfld_save_cursor_overlay_registers(dev); */
+	mdfld_save_display_registers(dev, 0);
+	mdfld_save_display_registers(dev, 2);
+	mdfld_disable_crtc(dev, 0);
+	mdfld_disable_crtc(dev, 2);
+
+	return 0;
+}
+
+static int mdfld_restore_registers(struct drm_device *dev)
+{
+	mdfld_restore_display_registers(dev, 2);
+	mdfld_restore_display_registers(dev, 0);
+	/* mdfld_restore_cursor_overlay_registers(dev); */
+
+	return 0;
+}
+
+static int mdfld_power_down(struct drm_device *dev)
+{
+	/* FIXME */
+	return 0;
+}
+
+static int mdfld_power_up(struct drm_device *dev)
+{
+	/* FIXME */
+	return 0;
+}
+
+const struct psb_ops mdfld_chip_ops = {
+	.name = "mdfld",
+	.accel_2d = 0,
+	.pipes = 3,
+	.crtcs = 3,
+	.sgx_offset = MRST_SGX_OFFSET,
+
+	.chip_setup = mid_chip_setup,
+	.crtc_helper = &mdfld_helper_funcs,
+	.crtc_funcs = &psb_intel_crtc_funcs,
+
+	.output_init = mdfld_output_init,
+
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+	.backlight_init = mdfld_backlight_init,
+#endif
+
+	.save_regs = mdfld_save_registers,
+	.restore_regs = mdfld_restore_registers,
+	.power_down = mdfld_power_down,
+	.power_up = mdfld_power_up,
+};
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
new file mode 100644
index 0000000..d52358b
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
@@ -0,0 +1,1017 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * jim liu <jim.liu@intel.com>
+ * Jackie Li<yaodong.li@intel.com>
+ */
+
+#include "mdfld_dsi_dpi.h"
+#include "mdfld_output.h"
+#include "mdfld_dsi_pkg_sender.h"
+#include "psb_drv.h"
+#include "tc35876x-dsi-lvds.h"
+
+static void mdfld_dsi_dpi_shut_down(struct mdfld_dsi_dpi_output *output,
+								int pipe);
+
+static void mdfld_wait_for_HS_DATA_FIFO(struct drm_device *dev, u32 pipe)
+{
+	u32 gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe);
+	int timeout = 0;
+
+	udelay(500);
+
+	/* This will time out after approximately 2+ seconds */
+	while ((timeout < 20000) &&
+		(REG_READ(gen_fifo_stat_reg) & DSI_FIFO_GEN_HS_DATA_FULL)) {
+		udelay(100);
+		timeout++;
+	}
+
+	if (timeout == 20000)
+		DRM_INFO("MIPI: HS Data FIFO was never cleared!\n");
+}
+
+static void mdfld_wait_for_HS_CTRL_FIFO(struct drm_device *dev, u32 pipe)
+{
+	u32 gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe);
+	int timeout = 0;
+
+	udelay(500);
+
+	/* This will time out after approximately 2+ seconds */
+	while ((timeout < 20000) && (REG_READ(gen_fifo_stat_reg)
+					& DSI_FIFO_GEN_HS_CTRL_FULL)) {
+		udelay(100);
+		timeout++;
+	}
+	if (timeout == 20000)
+		DRM_INFO("MIPI: HS CMD FIFO was never cleared!\n");
+}
+
+static void mdfld_wait_for_DPI_CTRL_FIFO(struct drm_device *dev, u32 pipe)
+{
+	u32 gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe);
+	int timeout = 0;
+
+	udelay(500);
+
+	/* This will time out after approximately 2+ seconds */
+	while ((timeout < 20000) && ((REG_READ(gen_fifo_stat_reg) &
+					DPI_FIFO_EMPTY) != DPI_FIFO_EMPTY)) {
+		udelay(100);
+		timeout++;
+	}
+
+	if (timeout == 20000)
+		DRM_ERROR("MIPI: DPI FIFO was never cleared\n");
+}
+
+static void mdfld_wait_for_SPL_PKG_SENT(struct drm_device *dev, u32 pipe)
+{
+	u32 intr_stat_reg = MIPI_INTR_STAT_REG(pipe);
+	int timeout = 0;
+
+	udelay(500);
+
+	/* This will time out after approximately 2+ seconds */
+	while ((timeout < 20000) && (!(REG_READ(intr_stat_reg)
+					& DSI_INTR_STATE_SPL_PKG_SENT))) {
+		udelay(100);
+		timeout++;
+	}
+
+	if (timeout == 20000)
+                DRM_ERROR("MIPI: SPL_PKT_SENT_INTERRUPT was not sent successfully!\n");
+}
+
+/* For TC35876X */
+
+static void dsi_set_device_ready_state(struct drm_device *dev, int state,
+				int pipe)
+{
+	REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), !!state, 0, 0);
+}
+
+static void dsi_set_pipe_plane_enable_state(struct drm_device *dev,
+							int state, int pipe)
+{
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	u32 pipeconf_reg = PIPEACONF;
+	u32 dspcntr_reg = DSPACNTR;
+
+	u32 dspcntr = dev_priv->dspcntr[pipe];
+	u32 mipi = MIPI_PORT_EN | PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX;
+
+	if (pipe) {
+		pipeconf_reg = PIPECCONF;
+		dspcntr_reg = DSPCCNTR;
+	} else
+		mipi &= (~0x03);
+
+	if (state) {
+		/*Set up pipe */
+		REG_WRITE(pipeconf_reg, BIT(31));
+
+		if (REG_BIT_WAIT(pipeconf_reg, 1, 30))
+			dev_err(&dev->pdev->dev, "%s: Pipe enable timeout\n",
+				__func__);
+
+		/*Set up display plane */
+		REG_WRITE(dspcntr_reg, dspcntr);
+	} else {
+		u32 dspbase_reg = pipe ? MDFLD_DSPCBASE : MRST_DSPABASE;
+
+		/* Put DSI lanes to ULPS to disable pipe */
+		REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), 2, 2, 1);
+		REG_READ(MIPI_DEVICE_READY_REG(pipe)); /* posted write? */
+
+		/* LP Hold */
+		REG_FLD_MOD(MIPI_PORT_CONTROL(pipe), 0, 16, 16);
+		REG_READ(MIPI_PORT_CONTROL(pipe)); /* posted write? */
+
+		/* Disable display plane */
+		REG_FLD_MOD(dspcntr_reg, 0, 31, 31);
+
+		/* Flush the plane changes ??? posted write? */
+		REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+		REG_READ(dspbase_reg);
+
+		/* Disable PIPE */
+		REG_FLD_MOD(pipeconf_reg, 0, 31, 31);
+
+		if (REG_BIT_WAIT(pipeconf_reg, 0, 30))
+			dev_err(&dev->pdev->dev, "%s: Pipe disable timeout\n",
+				__func__);
+
+		if (REG_BIT_WAIT(MIPI_GEN_FIFO_STAT_REG(pipe), 1, 28))
+			dev_err(&dev->pdev->dev, "%s: FIFO not empty\n",
+				__func__);
+	}
+}
+
+static void mdfld_dsi_configure_down(struct mdfld_dsi_encoder *dsi_encoder,
+								int pipe)
+{
+	struct mdfld_dsi_dpi_output *dpi_output =
+				MDFLD_DSI_DPI_OUTPUT(dsi_encoder);
+	struct mdfld_dsi_config *dsi_config =
+				mdfld_dsi_encoder_get_config(dsi_encoder);
+	struct drm_device *dev = dsi_config->dev;
+	struct drm_psb_private *dev_priv = dev->dev_private;
+
+	if (!dev_priv->dpi_panel_on[pipe]) {
+		dev_err(dev->dev, "DPI panel is already off\n");
+		return;
+	}
+	tc35876x_toshiba_bridge_panel_off(dev);
+	tc35876x_set_bridge_reset_state(dev, 1);
+	dsi_set_pipe_plane_enable_state(dev, 0, pipe);
+	mdfld_dsi_dpi_shut_down(dpi_output, pipe);
+	dsi_set_device_ready_state(dev, 0, pipe);
+}
+
+static void mdfld_dsi_configure_up(struct mdfld_dsi_encoder *dsi_encoder,
+								int pipe)
+{
+	struct mdfld_dsi_dpi_output *dpi_output =
+				MDFLD_DSI_DPI_OUTPUT(dsi_encoder);
+	struct mdfld_dsi_config *dsi_config =
+				mdfld_dsi_encoder_get_config(dsi_encoder);
+	struct drm_device *dev = dsi_config->dev;
+	struct drm_psb_private *dev_priv = dev->dev_private;
+
+	if (dev_priv->dpi_panel_on[pipe]) {
+		dev_err(dev->dev, "DPI panel is already on\n");
+		return;
+	}
+
+	/* For resume path sequence */
+	mdfld_dsi_dpi_shut_down(dpi_output, pipe);
+	dsi_set_device_ready_state(dev, 0, pipe);
+
+	dsi_set_device_ready_state(dev, 1, pipe);
+	tc35876x_set_bridge_reset_state(dev, 0);
+	tc35876x_configure_lvds_bridge(dev);
+	mdfld_dsi_dpi_turn_on(dpi_output, pipe);  /* Send turn on command */
+	dsi_set_pipe_plane_enable_state(dev, 1, pipe);
+}
+/* End for TC35876X */
+
+/* ************************************************************************* *\
+ * FUNCTION: mdfld_dsi_tpo_ic_init
+ *
+ * DESCRIPTION:  This function is called only by mrst_dsi_mode_set and
+ *               restore_display_registers.  since this function does not
+ *               acquire the mutex, it is important that the calling function
+ *               does!
+\* ************************************************************************* */
+static void mdfld_dsi_tpo_ic_init(struct mdfld_dsi_config *dsi_config, u32 pipe)
+{
+	struct drm_device *dev = dsi_config->dev;
+	u32 dcsChannelNumber = dsi_config->channel_num;
+	u32 gen_data_reg = MIPI_HS_GEN_DATA_REG(pipe);
+	u32 gen_ctrl_reg = MIPI_HS_GEN_CTRL_REG(pipe);
+	u32 gen_ctrl_val = GEN_LONG_WRITE;
+
+	DRM_INFO("Enter mrst init TPO MIPI display.\n");
+
+	gen_ctrl_val |= dcsChannelNumber << DCS_CHANNEL_NUMBER_POS;
+
+	/* Flip page order */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x00008036);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x02 << WORD_COUNTS_POS));
+
+	/* 0xF0 */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x005a5af0);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS));
+
+	/* Write protection key */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x005a5af1);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS));
+
+	/* 0xFC */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x005a5afc);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS));
+
+	/* 0xB7 */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x770000b7);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x00000044);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x05 << WORD_COUNTS_POS));
+
+	/* 0xB6 */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x000a0ab6);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS));
+
+	/* 0xF2 */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x081010f2);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x4a070708);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x000000c5);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x09 << WORD_COUNTS_POS));
+
+	/* 0xF8 */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x024003f8);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x01030a04);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x0e020220);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x00000004);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x0d << WORD_COUNTS_POS));
+
+	/* 0xE2 */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x398fc3e2);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x0000916f);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x06 << WORD_COUNTS_POS));
+
+	/* 0xB0 */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x000000b0);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x02 << WORD_COUNTS_POS));
+
+	/* 0xF4 */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x240242f4);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x78ee2002);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x2a071050);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x507fee10);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x10300710);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x14 << WORD_COUNTS_POS));
+
+	/* 0xBA */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x19fe07ba);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x101c0a31);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x00000010);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x09 << WORD_COUNTS_POS));
+
+	/* 0xBB */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x28ff07bb);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x24280a31);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x00000034);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x09 << WORD_COUNTS_POS));
+
+	/* 0xFB */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x535d05fb);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x1b1a2130);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x221e180e);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x131d2120);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x535d0508);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x1c1a2131);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x231f160d);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x111b2220);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x535c2008);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x1f1d2433);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x2c251a10);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x2c34372d);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x00000023);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x31 << WORD_COUNTS_POS));
+
+	/* 0xFA */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x525c0bfa);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x1c1c232f);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x2623190e);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x18212625);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x545d0d0e);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x1e1d2333);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x26231a10);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x1a222725);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x545d280f);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x21202635);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x31292013);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x31393d33);
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x00000029);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x31 << WORD_COUNTS_POS));
+
+	/* Set DM */
+	mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+	REG_WRITE(gen_data_reg, 0x000100f7);
+	mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+	REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS));
+}
+
+static u16 mdfld_dsi_dpi_to_byte_clock_count(int pixel_clock_count,
+						int num_lane, int bpp)
+{
+	return (u16)((pixel_clock_count * bpp) / (num_lane * 8));
+}
+
+/*
+ * Calculate the dpi time basing on a given drm mode @mode
+ * return 0 on success.
+ * FIXME: I was using proposed mode value for calculation, may need to
+ * use crtc mode values later
+ */
+int mdfld_dsi_dpi_timing_calculation(struct drm_display_mode *mode,
+				struct mdfld_dsi_dpi_timing *dpi_timing,
+				int num_lane, int bpp)
+{
+	int pclk_hsync, pclk_hfp, pclk_hbp, pclk_hactive;
+	int pclk_vsync, pclk_vfp, pclk_vbp;
+
+	pclk_hactive = mode->hdisplay;
+	pclk_hfp = mode->hsync_start - mode->hdisplay;
+	pclk_hsync = mode->hsync_end - mode->hsync_start;
+	pclk_hbp = mode->htotal - mode->hsync_end;
+
+	pclk_vfp = mode->vsync_start - mode->vdisplay;
+	pclk_vsync = mode->vsync_end - mode->vsync_start;
+	pclk_vbp = mode->vtotal - mode->vsync_end;
+
+	/*
+	 * byte clock counts were calculated by following formula
+	 * bclock_count = pclk_count * bpp / num_lane / 8
+	 */
+	dpi_timing->hsync_count = mdfld_dsi_dpi_to_byte_clock_count(
+						pclk_hsync, num_lane, bpp);
+	dpi_timing->hbp_count = mdfld_dsi_dpi_to_byte_clock_count(
+						pclk_hbp, num_lane, bpp);
+	dpi_timing->hfp_count = mdfld_dsi_dpi_to_byte_clock_count(
+						pclk_hfp, num_lane, bpp);
+	dpi_timing->hactive_count = mdfld_dsi_dpi_to_byte_clock_count(
+						pclk_hactive, num_lane, bpp);
+	dpi_timing->vsync_count = mdfld_dsi_dpi_to_byte_clock_count(
+						pclk_vsync, num_lane, bpp);
+	dpi_timing->vbp_count = mdfld_dsi_dpi_to_byte_clock_count(
+						pclk_vbp, num_lane, bpp);
+	dpi_timing->vfp_count = mdfld_dsi_dpi_to_byte_clock_count(
+						pclk_vfp, num_lane, bpp);
+
+	return 0;
+}
+
+void mdfld_dsi_dpi_controller_init(struct mdfld_dsi_config *dsi_config,
+								int pipe)
+{
+	struct drm_device *dev = dsi_config->dev;
+	int lane_count = dsi_config->lane_count;
+	struct mdfld_dsi_dpi_timing dpi_timing;
+	struct drm_display_mode *mode = dsi_config->mode;
+	u32 val;
+
+	/*un-ready device*/
+	REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), 0, 0, 0);
+
+	/*init dsi adapter before kicking off*/
+	REG_WRITE(MIPI_CTRL_REG(pipe), 0x00000018);
+
+	/*enable all interrupts*/
+	REG_WRITE(MIPI_INTR_EN_REG(pipe), 0xffffffff);
+
+	/*set up func_prg*/
+	val = lane_count;
+	val |= dsi_config->channel_num << DSI_DPI_VIRT_CHANNEL_OFFSET;
+
+	switch (dsi_config->bpp) {
+	case 16:
+		val |= DSI_DPI_COLOR_FORMAT_RGB565;
+		break;
+	case 18:
+		val |= DSI_DPI_COLOR_FORMAT_RGB666;
+		break;
+	case 24:
+		val |= DSI_DPI_COLOR_FORMAT_RGB888;
+		break;
+	default:
+		DRM_ERROR("unsupported color format, bpp = %d\n",
+							dsi_config->bpp);
+	}
+	REG_WRITE(MIPI_DSI_FUNC_PRG_REG(pipe), val);
+
+	REG_WRITE(MIPI_HS_TX_TIMEOUT_REG(pipe),
+			(mode->vtotal * mode->htotal * dsi_config->bpp /
+				(8 * lane_count)) & DSI_HS_TX_TIMEOUT_MASK);
+	REG_WRITE(MIPI_LP_RX_TIMEOUT_REG(pipe),
+				0xffff & DSI_LP_RX_TIMEOUT_MASK);
+
+	/*max value: 20 clock cycles of txclkesc*/
+	REG_WRITE(MIPI_TURN_AROUND_TIMEOUT_REG(pipe),
+				0x14 & DSI_TURN_AROUND_TIMEOUT_MASK);
+
+	/*min 21 txclkesc, max: ffffh*/
+	REG_WRITE(MIPI_DEVICE_RESET_TIMER_REG(pipe),
+				0xffff & DSI_RESET_TIMER_MASK);
+
+	REG_WRITE(MIPI_DPI_RESOLUTION_REG(pipe),
+				mode->vdisplay << 16 | mode->hdisplay);
+
+	/*set DPI timing registers*/
+	mdfld_dsi_dpi_timing_calculation(mode, &dpi_timing,
+				dsi_config->lane_count, dsi_config->bpp);
+
+	REG_WRITE(MIPI_HSYNC_COUNT_REG(pipe),
+			dpi_timing.hsync_count & DSI_DPI_TIMING_MASK);
+	REG_WRITE(MIPI_HBP_COUNT_REG(pipe),
+			dpi_timing.hbp_count & DSI_DPI_TIMING_MASK);
+	REG_WRITE(MIPI_HFP_COUNT_REG(pipe),
+			dpi_timing.hfp_count & DSI_DPI_TIMING_MASK);
+	REG_WRITE(MIPI_HACTIVE_COUNT_REG(pipe),
+			dpi_timing.hactive_count & DSI_DPI_TIMING_MASK);
+	REG_WRITE(MIPI_VSYNC_COUNT_REG(pipe),
+			dpi_timing.vsync_count & DSI_DPI_TIMING_MASK);
+	REG_WRITE(MIPI_VBP_COUNT_REG(pipe),
+			dpi_timing.vbp_count & DSI_DPI_TIMING_MASK);
+	REG_WRITE(MIPI_VFP_COUNT_REG(pipe),
+			dpi_timing.vfp_count & DSI_DPI_TIMING_MASK);
+
+	REG_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe), 0x46);
+
+	/*min: 7d0 max: 4e20*/
+	REG_WRITE(MIPI_INIT_COUNT_REG(pipe), 0x000007d0);
+
+	/*set up video mode*/
+	val = dsi_config->video_mode | DSI_DPI_COMPLETE_LAST_LINE;
+	REG_WRITE(MIPI_VIDEO_MODE_FORMAT_REG(pipe), val);
+
+	REG_WRITE(MIPI_EOT_DISABLE_REG(pipe), 0x00000000);
+
+	REG_WRITE(MIPI_LP_BYTECLK_REG(pipe), 0x00000004);
+
+	/*TODO: figure out how to setup these registers*/
+	if (mdfld_get_panel_type(dev, pipe) == TC35876X)
+		REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x2A0c6008);
+	else
+		REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x150c3408);
+
+	REG_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe), (0xa << 16) | 0x14);
+
+	if (mdfld_get_panel_type(dev, pipe) == TC35876X)
+		tc35876x_set_bridge_reset_state(dev, 0);  /*Pull High Reset */
+
+	/*set device ready*/
+	REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), 1, 0, 0);
+}
+
+void mdfld_dsi_dpi_turn_on(struct mdfld_dsi_dpi_output *output, int pipe)
+{
+	struct drm_device *dev = output->dev;
+
+	/* clear special packet sent bit */
+	if (REG_READ(MIPI_INTR_STAT_REG(pipe)) & DSI_INTR_STATE_SPL_PKG_SENT)
+		REG_WRITE(MIPI_INTR_STAT_REG(pipe),
+					DSI_INTR_STATE_SPL_PKG_SENT);
+
+	/*send turn on package*/
+	REG_WRITE(MIPI_DPI_CONTROL_REG(pipe), DSI_DPI_CTRL_HS_TURN_ON);
+
+	/*wait for SPL_PKG_SENT interrupt*/
+	mdfld_wait_for_SPL_PKG_SENT(dev, pipe);
+
+	if (REG_READ(MIPI_INTR_STAT_REG(pipe)) & DSI_INTR_STATE_SPL_PKG_SENT)
+		REG_WRITE(MIPI_INTR_STAT_REG(pipe),
+					DSI_INTR_STATE_SPL_PKG_SENT);
+
+	output->panel_on = 1;
+
+	/* FIXME the following is disabled to WA the X slow start issue
+	   for TMD panel
+	if (pipe == 2)
+		dev_priv->dpi_panel_on2 = true;
+	else if (pipe == 0)
+		dev_priv->dpi_panel_on = true; */
+}
+
+static void mdfld_dsi_dpi_shut_down(struct mdfld_dsi_dpi_output *output,
+								int pipe)
+{
+	struct drm_device *dev = output->dev;
+
+	/*if output is on, or mode setting didn't happen, ignore this*/
+	if ((!output->panel_on) || output->first_boot) {
+		output->first_boot = 0;
+		return;
+	}
+
+	/* Wait for dpi fifo to empty */
+	mdfld_wait_for_DPI_CTRL_FIFO(dev, pipe);
+
+	/* Clear the special packet interrupt bit if set */
+	if (REG_READ(MIPI_INTR_STAT_REG(pipe)) & DSI_INTR_STATE_SPL_PKG_SENT)
+		REG_WRITE(MIPI_INTR_STAT_REG(pipe),
+					DSI_INTR_STATE_SPL_PKG_SENT);
+
+	if (REG_READ(MIPI_DPI_CONTROL_REG(pipe)) == DSI_DPI_CTRL_HS_SHUTDOWN)
+		goto shutdown_out;
+
+	REG_WRITE(MIPI_DPI_CONTROL_REG(pipe), DSI_DPI_CTRL_HS_SHUTDOWN);
+
+shutdown_out:
+	output->panel_on = 0;
+	output->first_boot = 0;
+
+	/* FIXME the following is disabled to WA the X slow start issue
+	   for TMD panel
+	if (pipe == 2)
+		dev_priv->dpi_panel_on2 = false;
+	else if (pipe == 0)
+		dev_priv->dpi_panel_on = false;	 */
+}
+
+static void mdfld_dsi_dpi_set_power(struct drm_encoder *encoder, bool on)
+{
+	struct mdfld_dsi_encoder *dsi_encoder = mdfld_dsi_encoder(encoder);
+	struct mdfld_dsi_dpi_output *dpi_output =
+				MDFLD_DSI_DPI_OUTPUT(dsi_encoder);
+	struct mdfld_dsi_config *dsi_config =
+				mdfld_dsi_encoder_get_config(dsi_encoder);
+	int pipe = mdfld_dsi_encoder_get_pipe(dsi_encoder);
+	struct drm_device *dev = dsi_config->dev;
+	struct drm_psb_private *dev_priv = dev->dev_private;
+
+	/*start up display island if it was shutdown*/
+	if (!gma_power_begin(dev, true))
+		return;
+
+	if (on) {
+		if (mdfld_get_panel_type(dev, pipe) == TMD_VID)
+			mdfld_dsi_dpi_turn_on(dpi_output, pipe);
+		else if (mdfld_get_panel_type(dev, pipe) == TC35876X)
+			mdfld_dsi_configure_up(dsi_encoder, pipe);
+		else {
+			/*enable mipi port*/
+			REG_WRITE(MIPI_PORT_CONTROL(pipe),
+				REG_READ(MIPI_PORT_CONTROL(pipe)) | BIT(31));
+			REG_READ(MIPI_PORT_CONTROL(pipe));
+
+			mdfld_dsi_dpi_turn_on(dpi_output, pipe);
+			mdfld_dsi_tpo_ic_init(dsi_config, pipe);
+		}
+		dev_priv->dpi_panel_on[pipe] = true;
+	} else {
+		if (mdfld_get_panel_type(dev, pipe) == TMD_VID)
+			mdfld_dsi_dpi_shut_down(dpi_output, pipe);
+		else if (mdfld_get_panel_type(dev, pipe) == TC35876X)
+			mdfld_dsi_configure_down(dsi_encoder, pipe);
+		else {
+			mdfld_dsi_dpi_shut_down(dpi_output, pipe);
+
+			/*disable mipi port*/
+			REG_WRITE(MIPI_PORT_CONTROL(pipe),
+				REG_READ(MIPI_PORT_CONTROL(pipe)) & ~BIT(31));
+			REG_READ(MIPI_PORT_CONTROL(pipe));
+		}
+		dev_priv->dpi_panel_on[pipe] = false;
+	}
+	gma_power_end(dev);
+}
+
+void mdfld_dsi_dpi_dpms(struct drm_encoder *encoder, int mode)
+{
+	mdfld_dsi_dpi_set_power(encoder, mode == DRM_MODE_DPMS_ON);
+}
+
+bool mdfld_dsi_dpi_mode_fixup(struct drm_encoder *encoder,
+				     struct drm_display_mode *mode,
+				     struct drm_display_mode *adjusted_mode)
+{
+	struct mdfld_dsi_encoder *dsi_encoder = mdfld_dsi_encoder(encoder);
+	struct mdfld_dsi_config *dsi_config =
+				mdfld_dsi_encoder_get_config(dsi_encoder);
+	struct drm_display_mode *fixed_mode = dsi_config->fixed_mode;
+
+	if (fixed_mode) {
+		adjusted_mode->hdisplay = fixed_mode->hdisplay;
+		adjusted_mode->hsync_start = fixed_mode->hsync_start;
+		adjusted_mode->hsync_end = fixed_mode->hsync_end;
+		adjusted_mode->htotal = fixed_mode->htotal;
+		adjusted_mode->vdisplay = fixed_mode->vdisplay;
+		adjusted_mode->vsync_start = fixed_mode->vsync_start;
+		adjusted_mode->vsync_end = fixed_mode->vsync_end;
+		adjusted_mode->vtotal = fixed_mode->vtotal;
+		adjusted_mode->clock = fixed_mode->clock;
+		drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+	}
+	return true;
+}
+
+void mdfld_dsi_dpi_prepare(struct drm_encoder *encoder)
+{
+	mdfld_dsi_dpi_set_power(encoder, false);
+}
+
+void mdfld_dsi_dpi_commit(struct drm_encoder *encoder)
+{
+	mdfld_dsi_dpi_set_power(encoder, true);
+}
+
+/* For TC35876X */
+/* This functionality was implemented in FW in iCDK */
+/* But removed in DV0 and later. So need to add here. */
+static void mipi_set_properties(struct mdfld_dsi_config *dsi_config, int pipe)
+{
+	struct drm_device *dev = dsi_config->dev;
+
+	REG_WRITE(MIPI_CTRL_REG(pipe), 0x00000018);
+	REG_WRITE(MIPI_INTR_EN_REG(pipe), 0xffffffff);
+	REG_WRITE(MIPI_HS_TX_TIMEOUT_REG(pipe), 0xffffff);
+	REG_WRITE(MIPI_LP_RX_TIMEOUT_REG(pipe), 0xffffff);
+	REG_WRITE(MIPI_TURN_AROUND_TIMEOUT_REG(pipe), 0x14);
+	REG_WRITE(MIPI_DEVICE_RESET_TIMER_REG(pipe), 0xff);
+	REG_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe), 0x25);
+	REG_WRITE(MIPI_INIT_COUNT_REG(pipe), 0xf0);
+	REG_WRITE(MIPI_EOT_DISABLE_REG(pipe), 0x00000000);
+	REG_WRITE(MIPI_LP_BYTECLK_REG(pipe), 0x00000004);
+	REG_WRITE(MIPI_DBI_BW_CTRL_REG(pipe), 0x00000820);
+	REG_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe), (0xa << 16) | 0x14);
+}
+
+static void mdfld_mipi_set_video_timing(struct mdfld_dsi_config *dsi_config,
+					int pipe)
+{
+	struct drm_device *dev = dsi_config->dev;
+	struct mdfld_dsi_dpi_timing dpi_timing;
+	struct drm_display_mode *mode = dsi_config->mode;
+
+	mdfld_dsi_dpi_timing_calculation(mode, &dpi_timing,
+					dsi_config->lane_count,
+					dsi_config->bpp);
+
+	REG_WRITE(MIPI_DPI_RESOLUTION_REG(pipe),
+		mode->vdisplay << 16 | mode->hdisplay);
+	REG_WRITE(MIPI_HSYNC_COUNT_REG(pipe),
+		dpi_timing.hsync_count & DSI_DPI_TIMING_MASK);
+	REG_WRITE(MIPI_HBP_COUNT_REG(pipe),
+		dpi_timing.hbp_count & DSI_DPI_TIMING_MASK);
+	REG_WRITE(MIPI_HFP_COUNT_REG(pipe),
+		dpi_timing.hfp_count & DSI_DPI_TIMING_MASK);
+	REG_WRITE(MIPI_HACTIVE_COUNT_REG(pipe),
+		dpi_timing.hactive_count & DSI_DPI_TIMING_MASK);
+	REG_WRITE(MIPI_VSYNC_COUNT_REG(pipe),
+		dpi_timing.vsync_count & DSI_DPI_TIMING_MASK);
+	REG_WRITE(MIPI_VBP_COUNT_REG(pipe),
+		dpi_timing.vbp_count & DSI_DPI_TIMING_MASK);
+	REG_WRITE(MIPI_VFP_COUNT_REG(pipe),
+		dpi_timing.vfp_count & DSI_DPI_TIMING_MASK);
+}
+
+static void mdfld_mipi_config(struct mdfld_dsi_config *dsi_config, int pipe)
+{
+	struct drm_device *dev = dsi_config->dev;
+	int lane_count = dsi_config->lane_count;
+
+	if (pipe) {
+		REG_WRITE(MIPI_PORT_CONTROL(0), 0x00000002);
+		REG_WRITE(MIPI_PORT_CONTROL(2), 0x80000000);
+	} else {
+		REG_WRITE(MIPI_PORT_CONTROL(0), 0x80010000);
+		REG_WRITE(MIPI_PORT_CONTROL(2), 0x00);
+	}
+
+	REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x150A600F);
+	REG_WRITE(MIPI_VIDEO_MODE_FORMAT_REG(pipe), 0x0000000F);
+
+	/* lane_count = 3 */
+	REG_WRITE(MIPI_DSI_FUNC_PRG_REG(pipe), 0x00000200 | lane_count);
+
+	mdfld_mipi_set_video_timing(dsi_config, pipe);
+}
+
+static void mdfld_set_pipe_timing(struct mdfld_dsi_config *dsi_config, int pipe)
+{
+	struct drm_device *dev = dsi_config->dev;
+	struct drm_display_mode *mode = dsi_config->mode;
+
+	REG_WRITE(HTOTAL_A, ((mode->htotal - 1) << 16) | (mode->hdisplay - 1));
+	REG_WRITE(HBLANK_A, ((mode->htotal - 1) << 16) | (mode->hdisplay - 1));
+	REG_WRITE(HSYNC_A,
+		((mode->hsync_end - 1) << 16) | (mode->hsync_start - 1));
+
+	REG_WRITE(VTOTAL_A, ((mode->vtotal - 1) << 16) | (mode->vdisplay - 1));
+	REG_WRITE(VBLANK_A, ((mode->vtotal - 1) << 16) | (mode->vdisplay - 1));
+	REG_WRITE(VSYNC_A,
+		((mode->vsync_end - 1) << 16) | (mode->vsync_start - 1));
+
+	REG_WRITE(PIPEASRC,
+		((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+}
+/* End for TC35876X */
+
+void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder,
+				   struct drm_display_mode *mode,
+				   struct drm_display_mode *adjusted_mode)
+{
+	struct mdfld_dsi_encoder *dsi_encoder = mdfld_dsi_encoder(encoder);
+	struct mdfld_dsi_dpi_output *dpi_output =
+					MDFLD_DSI_DPI_OUTPUT(dsi_encoder);
+	struct mdfld_dsi_config *dsi_config =
+				mdfld_dsi_encoder_get_config(dsi_encoder);
+	struct drm_device *dev = dsi_config->dev;
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	int pipe = mdfld_dsi_encoder_get_pipe(dsi_encoder);
+
+	u32 pipeconf_reg = PIPEACONF;
+	u32 dspcntr_reg = DSPACNTR;
+
+	u32 pipeconf = dev_priv->pipeconf[pipe];
+	u32 dspcntr = dev_priv->dspcntr[pipe];
+	u32 mipi = MIPI_PORT_EN | PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX;
+
+	if (pipe) {
+		pipeconf_reg = PIPECCONF;
+		dspcntr_reg = DSPCCNTR;
+	} else {
+		if (mdfld_get_panel_type(dev, pipe) == TC35876X)
+			mipi &= (~0x03); /* Use all four lanes */
+		else
+			mipi |= 2;
+	}
+
+	/*start up display island if it was shutdown*/
+	if (!gma_power_begin(dev, true))
+		return;
+
+	if (mdfld_get_panel_type(dev, pipe) == TC35876X) {
+		/*
+		 * The following logic is required to reset the bridge and
+		 * configure. This also starts the DSI clock at 200MHz.
+		 */
+		tc35876x_set_bridge_reset_state(dev, 0);  /*Pull High Reset */
+		tc35876x_toshiba_bridge_panel_on(dev);
+		udelay(100);
+		/* Now start the DSI clock */
+		REG_WRITE(MRST_DPLL_A, 0x00);
+		REG_WRITE(MRST_FPA0, 0xC1);
+		REG_WRITE(MRST_DPLL_A, 0x00800000);
+		udelay(500);
+		REG_WRITE(MRST_DPLL_A, 0x80800000);
+
+		if (REG_BIT_WAIT(pipeconf_reg, 1, 29))
+			dev_err(&dev->pdev->dev, "%s: DSI PLL lock timeout\n",
+				__func__);
+
+		REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x2A0c6008);
+
+		mipi_set_properties(dsi_config, pipe);
+		mdfld_mipi_config(dsi_config, pipe);
+		mdfld_set_pipe_timing(dsi_config, pipe);
+
+		REG_WRITE(DSPABASE, 0x00);
+		REG_WRITE(DSPASTRIDE, (mode->hdisplay * 4));
+		REG_WRITE(DSPASIZE,
+			((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
+
+		REG_WRITE(DSPACNTR, 0x98000000);
+		REG_WRITE(DSPASURF, 0x00);
+
+		REG_WRITE(VGACNTRL, 0x80000000);
+		REG_WRITE(DEVICE_READY_REG, 0x00000001);
+
+		REG_WRITE(MIPI_PORT_CONTROL(pipe), 0x80810000);
+	} else {
+		/*set up mipi port FIXME: do at init time */
+		REG_WRITE(MIPI_PORT_CONTROL(pipe), mipi);
+	}
+	REG_READ(MIPI_PORT_CONTROL(pipe));
+
+	if (mdfld_get_panel_type(dev, pipe) == TMD_VID) {
+		/* NOP */
+	} else if (mdfld_get_panel_type(dev, pipe) == TC35876X) {
+		/* set up DSI controller DPI interface */
+		mdfld_dsi_dpi_controller_init(dsi_config, pipe);
+
+		/* Configure MIPI Bridge and Panel */
+		tc35876x_configure_lvds_bridge(dev);
+		dev_priv->dpi_panel_on[pipe] = true;
+	} else {
+		/*turn on DPI interface*/
+		mdfld_dsi_dpi_turn_on(dpi_output, pipe);
+	}
+
+	/*set up pipe*/
+	REG_WRITE(pipeconf_reg, pipeconf);
+	REG_READ(pipeconf_reg);
+
+	/*set up display plane*/
+	REG_WRITE(dspcntr_reg, dspcntr);
+	REG_READ(dspcntr_reg);
+
+	msleep(20); /* FIXME: this should wait for vblank */
+
+	if (mdfld_get_panel_type(dev, pipe) == TMD_VID) {
+		/* NOP */
+	} else if (mdfld_get_panel_type(dev, pipe) == TC35876X) {
+		mdfld_dsi_dpi_turn_on(dpi_output, pipe);
+	} else {
+		/* init driver ic */
+		mdfld_dsi_tpo_ic_init(dsi_config, pipe);
+		/*init backlight*/
+		mdfld_dsi_brightness_init(dsi_config, pipe);
+	}
+
+	gma_power_end(dev);
+}
+
+/*
+ * Init DSI DPI encoder.
+ * Allocate an mdfld_dsi_encoder and attach it to given @dsi_connector
+ * return pointer of newly allocated DPI encoder, NULL on error
+ */
+struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev,
+				struct mdfld_dsi_connector *dsi_connector,
+				const struct panel_funcs *p_funcs)
+{
+	struct mdfld_dsi_dpi_output *dpi_output = NULL;
+	struct mdfld_dsi_config *dsi_config;
+	struct drm_connector *connector = NULL;
+	struct drm_encoder *encoder = NULL;
+	int pipe;
+	u32 data;
+	int ret;
+
+	pipe = dsi_connector->pipe;
+
+	if (mdfld_get_panel_type(dev, pipe) != TC35876X) {
+		dsi_config = mdfld_dsi_get_config(dsi_connector);
+
+		/* panel hard-reset */
+		if (p_funcs->reset) {
+			ret = p_funcs->reset(pipe);
+			if (ret) {
+				DRM_ERROR("Panel %d hard-reset failed\n", pipe);
+				return NULL;
+			}
+		}
+
+		/* panel drvIC init */
+		if (p_funcs->drv_ic_init)
+			p_funcs->drv_ic_init(dsi_config, pipe);
+
+		/* panel power mode detect */
+		ret = mdfld_dsi_get_power_mode(dsi_config, &data, false);
+		if (ret) {
+			DRM_ERROR("Panel %d get power mode failed\n", pipe);
+			dsi_connector->status = connector_status_disconnected;
+		} else {
+			DRM_INFO("pipe %d power mode 0x%x\n", pipe, data);
+			dsi_connector->status = connector_status_connected;
+		}
+	}
+
+	dpi_output = kzalloc(sizeof(struct mdfld_dsi_dpi_output), GFP_KERNEL);
+	if (!dpi_output) {
+		DRM_ERROR("No memory\n");
+		return NULL;
+	}
+
+	if (dsi_connector->pipe)
+		dpi_output->panel_on = 0;
+	else
+		dpi_output->panel_on = 0;
+
+	dpi_output->dev = dev;
+	if (mdfld_get_panel_type(dev, pipe) != TC35876X)
+		dpi_output->p_funcs = p_funcs;
+	dpi_output->first_boot = 1;
+
+	/*get fixed mode*/
+	dsi_config = mdfld_dsi_get_config(dsi_connector);
+
+	/*create drm encoder object*/
+	connector = &dsi_connector->base.base;
+	encoder = &dpi_output->base.base.base;
+	drm_encoder_init(dev,
+			encoder,
+			p_funcs->encoder_funcs,
+			DRM_MODE_ENCODER_LVDS);
+	drm_encoder_helper_add(encoder,
+				p_funcs->encoder_helper_funcs);
+
+	/*attach to given connector*/
+	drm_mode_connector_attach_encoder(connector, encoder);
+
+	/*set possible crtcs and clones*/
+	if (dsi_connector->pipe) {
+		encoder->possible_crtcs = (1 << 2);
+		encoder->possible_clones = (1 << 1);
+	} else {
+		encoder->possible_crtcs = (1 << 0);
+		encoder->possible_clones = (1 << 0);
+	}
+
+	dsi_connector->base.encoder = &dpi_output->base.base;
+
+	return &dpi_output->base;
+}
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.h b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.h
new file mode 100644
index 0000000..6f76247
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * jim liu <jim.liu@intel.com>
+ * Jackie Li<yaodong.li@intel.com>
+ */
+
+#ifndef __MDFLD_DSI_DPI_H__
+#define __MDFLD_DSI_DPI_H__
+
+#include "mdfld_dsi_output.h"
+#include "mdfld_output.h"
+
+struct mdfld_dsi_dpi_timing {
+	u16 hsync_count;
+	u16 hbp_count;
+	u16 hfp_count;
+	u16 hactive_count;
+	u16 vsync_count;
+	u16 vbp_count;
+	u16 vfp_count;
+};
+
+struct mdfld_dsi_dpi_output {
+	struct mdfld_dsi_encoder base;
+	struct drm_device *dev;
+
+	int panel_on;
+	int first_boot;
+
+	const struct panel_funcs *p_funcs;
+};
+
+#define MDFLD_DSI_DPI_OUTPUT(dsi_encoder)\
+	container_of(dsi_encoder, struct mdfld_dsi_dpi_output, base)
+
+/* Export functions */
+extern int mdfld_dsi_dpi_timing_calculation(struct drm_display_mode *mode,
+				struct mdfld_dsi_dpi_timing *dpi_timing,
+				int num_lane, int bpp);
+extern struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev,
+				struct mdfld_dsi_connector *dsi_connector,
+				const struct panel_funcs *p_funcs);
+
+/* MDFLD DPI helper functions */
+extern void mdfld_dsi_dpi_dpms(struct drm_encoder *encoder, int mode);
+extern bool mdfld_dsi_dpi_mode_fixup(struct drm_encoder *encoder,
+				struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode);
+extern void mdfld_dsi_dpi_prepare(struct drm_encoder *encoder);
+extern void mdfld_dsi_dpi_commit(struct drm_encoder *encoder);
+extern void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder,
+				struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode);
+extern void mdfld_dsi_dpi_turn_on(struct mdfld_dsi_dpi_output *output,
+				int pipe);
+extern void mdfld_dsi_dpi_controller_init(struct mdfld_dsi_config *dsi_config,
+				int pipe);
+#endif /*__MDFLD_DSI_DPI_H__*/
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
new file mode 100644
index 0000000..5675d93
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
@@ -0,0 +1,621 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * jim liu <jim.liu@intel.com>
+ * Jackie Li<yaodong.li@intel.com>
+ */
+
+#include <linux/module.h>
+
+#include "mdfld_dsi_output.h"
+#include "mdfld_dsi_dpi.h"
+#include "mdfld_output.h"
+#include "mdfld_dsi_pkg_sender.h"
+#include "tc35876x-dsi-lvds.h"
+#include <linux/pm_runtime.h>
+#include <asm/intel_scu_ipc.h>
+
+/* get the LABC from command line. */
+static int LABC_control = 1;
+
+#ifdef MODULE
+module_param(LABC_control, int, 0644);
+#else
+
+static int __init parse_LABC_control(char *arg)
+{
+	/* LABC control can be passed in as a cmdline parameter */
+	/* to enable this feature add LABC=1 to cmdline */
+	/* to disable this feature add LABC=0 to cmdline */
+	if (!arg)
+		return -EINVAL;
+
+	if (!strcasecmp(arg, "0"))
+		LABC_control = 0;
+	else if (!strcasecmp(arg, "1"))
+		LABC_control = 1;
+
+	return 0;
+}
+early_param("LABC", parse_LABC_control);
+#endif
+
+/**
+ * Check and see if the generic control or data buffer is empty and ready.
+ */
+void mdfld_dsi_gen_fifo_ready(struct drm_device *dev, u32 gen_fifo_stat_reg,
+							u32 fifo_stat)
+{
+	u32 GEN_BF_time_out_count;
+
+	/* Check MIPI Adatper command registers */
+	for (GEN_BF_time_out_count = 0;
+			GEN_BF_time_out_count < GEN_FB_TIME_OUT;
+			GEN_BF_time_out_count++) {
+		if ((REG_READ(gen_fifo_stat_reg) & fifo_stat) == fifo_stat)
+			break;
+		udelay(100);
+	}
+
+	if (GEN_BF_time_out_count == GEN_FB_TIME_OUT)
+		DRM_ERROR("mdfld_dsi_gen_fifo_ready, Timeout. gen_fifo_stat_reg = 0x%x.\n",
+					gen_fifo_stat_reg);
+}
+
+/**
+ * Manage the DSI MIPI keyboard and display brightness.
+ * FIXME: this is exported to OSPM code. should work out an specific
+ * display interface to OSPM.
+ */
+
+void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, int pipe)
+{
+	struct mdfld_dsi_pkg_sender *sender =
+				mdfld_dsi_get_pkg_sender(dsi_config);
+	struct drm_device *dev = sender->dev;
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	u32 gen_ctrl_val;
+
+	if (!sender) {
+		DRM_ERROR("No sender found\n");
+		return;
+	}
+
+	/* Set default display backlight value to 85% (0xd8)*/
+	mdfld_dsi_send_mcs_short(sender, write_display_brightness, 0xd8, 1,
+				true);
+
+	/* Set minimum brightness setting of CABC function to 20% (0x33)*/
+	mdfld_dsi_send_mcs_short(sender, write_cabc_min_bright, 0x33, 1, true);
+
+	/* Enable backlight or/and LABC */
+	gen_ctrl_val = BRIGHT_CNTL_BLOCK_ON | DISPLAY_DIMMING_ON |
+								BACKLIGHT_ON;
+	if (LABC_control == 1)
+		gen_ctrl_val |= DISPLAY_DIMMING_ON | DISPLAY_BRIGHTNESS_AUTO
+								| GAMMA_AUTO;
+
+	if (LABC_control == 1)
+		gen_ctrl_val |= AMBIENT_LIGHT_SENSE_ON;
+
+	dev_priv->mipi_ctrl_display = gen_ctrl_val;
+
+	mdfld_dsi_send_mcs_short(sender, write_ctrl_display, (u8)gen_ctrl_val,
+				1, true);
+
+	mdfld_dsi_send_mcs_short(sender, write_ctrl_cabc, UI_IMAGE, 1, true);
+}
+
+void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe, int level)
+{
+	struct mdfld_dsi_pkg_sender *sender;
+	struct drm_psb_private *dev_priv;
+	struct mdfld_dsi_config *dsi_config;
+	u32 gen_ctrl_val = 0;
+	int p_type = TMD_VID;
+
+	if (!dev || (pipe != 0 && pipe != 2)) {
+		DRM_ERROR("Invalid parameter\n");
+		return;
+	}
+
+	p_type = mdfld_get_panel_type(dev, 0);
+
+	dev_priv = dev->dev_private;
+
+	if (pipe)
+		dsi_config = dev_priv->dsi_configs[1];
+	else
+		dsi_config = dev_priv->dsi_configs[0];
+
+	sender = mdfld_dsi_get_pkg_sender(dsi_config);
+
+	if (!sender) {
+		DRM_ERROR("No sender found\n");
+		return;
+	}
+
+	gen_ctrl_val = (level * 0xff / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL) & 0xff;
+
+	dev_dbg(sender->dev->dev, "pipe = %d, gen_ctrl_val = %d.\n",
+							pipe, gen_ctrl_val);
+
+	if (p_type == TMD_VID) {
+		/* Set display backlight value */
+		mdfld_dsi_send_mcs_short(sender, tmd_write_display_brightness,
+					(u8)gen_ctrl_val, 1, true);
+	} else {
+		/* Set display backlight value */
+		mdfld_dsi_send_mcs_short(sender, write_display_brightness,
+					(u8)gen_ctrl_val, 1, true);
+
+		/* Enable backlight control */
+		if (level == 0)
+			gen_ctrl_val = 0;
+		else
+			gen_ctrl_val = dev_priv->mipi_ctrl_display;
+
+		mdfld_dsi_send_mcs_short(sender, write_ctrl_display,
+					(u8)gen_ctrl_val, 1, true);
+	}
+}
+
+static int mdfld_dsi_get_panel_status(struct mdfld_dsi_config *dsi_config,
+				u8 dcs, u32 *data, bool hs)
+{
+	struct mdfld_dsi_pkg_sender *sender
+		= mdfld_dsi_get_pkg_sender(dsi_config);
+
+	if (!sender || !data) {
+		DRM_ERROR("Invalid parameter\n");
+		return -EINVAL;
+	}
+
+	return mdfld_dsi_read_mcs(sender, dcs, data, 1, hs);
+}
+
+int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, u32 *mode,
+			bool hs)
+{
+	if (!dsi_config || !mode) {
+		DRM_ERROR("Invalid parameter\n");
+		return -EINVAL;
+	}
+
+	return mdfld_dsi_get_panel_status(dsi_config, 0x0a, mode, hs);
+}
+
+/*
+ * NOTE: this function was used by OSPM.
+ * TODO: will be removed later, should work out display interfaces for OSPM
+ */
+void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config, int pipe)
+{
+	if (!dsi_config || ((pipe != 0) && (pipe != 2))) {
+		DRM_ERROR("Invalid parameters\n");
+		return;
+	}
+
+	mdfld_dsi_dpi_controller_init(dsi_config, pipe);
+}
+
+static void mdfld_dsi_connector_save(struct drm_connector *connector)
+{
+}
+
+static void mdfld_dsi_connector_restore(struct drm_connector *connector)
+{
+}
+
+/* FIXME: start using the force parameter */
+static enum drm_connector_status
+mdfld_dsi_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct mdfld_dsi_connector *dsi_connector
+		= mdfld_dsi_connector(connector);
+
+	dsi_connector->status = connector_status_connected;
+
+	return dsi_connector->status;
+}
+
+static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
+				struct drm_property *property,
+				uint64_t value)
+{
+	struct drm_encoder *encoder = connector->encoder;
+
+	if (!strcmp(property->name, "scaling mode") && encoder) {
+		struct psb_intel_crtc *psb_crtc =
+					to_psb_intel_crtc(encoder->crtc);
+		bool centerechange;
+		uint64_t val;
+
+		if (!psb_crtc)
+			goto set_prop_error;
+
+		switch (value) {
+		case DRM_MODE_SCALE_FULLSCREEN:
+			break;
+		case DRM_MODE_SCALE_NO_SCALE:
+			break;
+		case DRM_MODE_SCALE_ASPECT:
+			break;
+		default:
+			goto set_prop_error;
+		}
+
+		if (drm_connector_property_get_value(connector, property, &val))
+			goto set_prop_error;
+
+		if (val == value)
+			goto set_prop_done;
+
+		if (drm_connector_property_set_value(connector,
+							property, value))
+			goto set_prop_error;
+
+		centerechange = (val == DRM_MODE_SCALE_NO_SCALE) ||
+			(value == DRM_MODE_SCALE_NO_SCALE);
+
+		if (psb_crtc->saved_mode.hdisplay != 0 &&
+		    psb_crtc->saved_mode.vdisplay != 0) {
+			if (centerechange) {
+				if (!drm_crtc_helper_set_mode(encoder->crtc,
+						&psb_crtc->saved_mode,
+						encoder->crtc->x,
+						encoder->crtc->y,
+						encoder->crtc->fb))
+					goto set_prop_error;
+			} else {
+				struct drm_encoder_helper_funcs *funcs =
+						encoder->helper_private;
+				funcs->mode_set(encoder,
+					&psb_crtc->saved_mode,
+					&psb_crtc->saved_adjusted_mode);
+			}
+		}
+	} else if (!strcmp(property->name, "backlight") && encoder) {
+		if (drm_connector_property_set_value(connector, property,
+									value))
+			goto set_prop_error;
+		else {
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+			struct backlight_device *psb_bd;
+
+			psb_bd = mdfld_get_backlight_device();
+			if (psb_bd) {
+				psb_bd->props.brightness = value;
+				mdfld_set_brightness(psb_bd);
+			}
+#endif
+		}
+	}
+set_prop_done:
+	return 0;
+set_prop_error:
+	return -1;
+}
+
+static void mdfld_dsi_connector_destroy(struct drm_connector *connector)
+{
+	struct mdfld_dsi_connector *dsi_connector =
+					mdfld_dsi_connector(connector);
+	struct mdfld_dsi_pkg_sender *sender;
+
+	if (!dsi_connector)
+		return;
+	drm_sysfs_connector_remove(connector);
+	drm_connector_cleanup(connector);
+	sender = dsi_connector->pkg_sender;
+	mdfld_dsi_pkg_sender_destroy(sender);
+	kfree(dsi_connector);
+}
+
+static int mdfld_dsi_connector_get_modes(struct drm_connector *connector)
+{
+	struct mdfld_dsi_connector *dsi_connector =
+				mdfld_dsi_connector(connector);
+	struct mdfld_dsi_config *dsi_config =
+				mdfld_dsi_get_config(dsi_connector);
+	struct drm_display_mode *fixed_mode = dsi_config->fixed_mode;
+	struct drm_display_mode *dup_mode = NULL;
+	struct drm_device *dev = connector->dev;
+
+	connector->display_info.min_vfreq = 0;
+	connector->display_info.max_vfreq = 200;
+	connector->display_info.min_hfreq = 0;
+	connector->display_info.max_hfreq = 200;
+
+	if (fixed_mode) {
+		dev_dbg(dev->dev, "fixed_mode %dx%d\n",
+				fixed_mode->hdisplay, fixed_mode->vdisplay);
+		dup_mode = drm_mode_duplicate(dev, fixed_mode);
+		drm_mode_probed_add(connector, dup_mode);
+		return 1;
+	}
+	DRM_ERROR("Didn't get any modes!\n");
+	return 0;
+}
+
+static int mdfld_dsi_connector_mode_valid(struct drm_connector *connector,
+						struct drm_display_mode *mode)
+{
+	struct mdfld_dsi_connector *dsi_connector =
+					mdfld_dsi_connector(connector);
+	struct mdfld_dsi_config *dsi_config =
+					mdfld_dsi_get_config(dsi_connector);
+	struct drm_display_mode *fixed_mode = dsi_config->fixed_mode;
+
+	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return MODE_NO_DBLESCAN;
+
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		return MODE_NO_INTERLACE;
+
+	/**
+	 * FIXME: current DC has no fitting unit, reject any mode setting
+	 * request
+	 * Will figure out a way to do up-scaling(pannel fitting) later.
+	 **/
+	if (fixed_mode) {
+		if (mode->hdisplay != fixed_mode->hdisplay)
+			return MODE_PANEL;
+
+		if (mode->vdisplay != fixed_mode->vdisplay)
+			return MODE_PANEL;
+	}
+
+	return MODE_OK;
+}
+
+static void mdfld_dsi_connector_dpms(struct drm_connector *connector, int mode)
+{
+	if (mode == connector->dpms)
+		return;
+
+	/*first, execute dpms*/
+
+	drm_helper_connector_dpms(connector, mode);
+}
+
+static struct drm_encoder *mdfld_dsi_connector_best_encoder(
+				struct drm_connector *connector)
+{
+	struct mdfld_dsi_connector *dsi_connector =
+				mdfld_dsi_connector(connector);
+	struct mdfld_dsi_config *dsi_config =
+				mdfld_dsi_get_config(dsi_connector);
+	return &dsi_config->encoder->base.base;
+}
+
+/*DSI connector funcs*/
+static const struct drm_connector_funcs mdfld_dsi_connector_funcs = {
+	.dpms = /*drm_helper_connector_dpms*/mdfld_dsi_connector_dpms,
+	.save = mdfld_dsi_connector_save,
+	.restore = mdfld_dsi_connector_restore,
+	.detect = mdfld_dsi_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.set_property = mdfld_dsi_connector_set_property,
+	.destroy = mdfld_dsi_connector_destroy,
+};
+
+/*DSI connector helper funcs*/
+static const struct drm_connector_helper_funcs
+	mdfld_dsi_connector_helper_funcs = {
+	.get_modes = mdfld_dsi_connector_get_modes,
+	.mode_valid = mdfld_dsi_connector_mode_valid,
+	.best_encoder = mdfld_dsi_connector_best_encoder,
+};
+
+static int mdfld_dsi_get_default_config(struct drm_device *dev,
+				struct mdfld_dsi_config *config, int pipe)
+{
+	if (!dev || !config) {
+		DRM_ERROR("Invalid parameters");
+		return -EINVAL;
+	}
+
+	config->bpp = 24;
+	if (mdfld_get_panel_type(dev, pipe) == TC35876X)
+		config->lane_count = 4;
+	else
+		config->lane_count = 2;
+	config->channel_num = 0;
+
+	if (mdfld_get_panel_type(dev, pipe) == TMD_VID)
+		config->video_mode = MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE;
+	else if (mdfld_get_panel_type(dev, pipe) == TC35876X)
+		config->video_mode =
+				MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS;
+	else
+		config->video_mode = MDFLD_DSI_VIDEO_BURST_MODE;
+
+	return 0;
+}
+
+int mdfld_dsi_panel_reset(int pipe)
+{
+	unsigned gpio;
+	int ret = 0;
+
+	switch (pipe) {
+	case 0:
+		gpio = 128;
+		break;
+	case 2:
+		gpio = 34;
+		break;
+	default:
+		DRM_ERROR("Invalid output\n");
+		return -EINVAL;
+	}
+
+	ret = gpio_request(gpio, "gfx");
+	if (ret) {
+		DRM_ERROR("gpio_rqueset failed\n");
+		return ret;
+	}
+
+	ret = gpio_direction_output(gpio, 1);
+	if (ret) {
+		DRM_ERROR("gpio_direction_output failed\n");
+		goto gpio_error;
+	}
+
+	gpio_get_value(128);
+
+gpio_error:
+	if (gpio_is_valid(gpio))
+		gpio_free(gpio);
+
+	return ret;
+}
+
+/*
+ * MIPI output init
+ * @dev drm device
+ * @pipe pipe number. 0 or 2
+ * @config
+ *
+ * Do the initialization of a MIPI output, including create DRM mode objects
+ * initialization of DSI output on @pipe
+ */
+void mdfld_dsi_output_init(struct drm_device *dev,
+			   int pipe,
+			   const struct panel_funcs *p_vid_funcs)
+{
+	struct mdfld_dsi_config *dsi_config;
+	struct mdfld_dsi_connector *dsi_connector;
+	struct drm_connector *connector;
+	struct mdfld_dsi_encoder *encoder;
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	struct panel_info dsi_panel_info;
+	u32 width_mm, height_mm;
+
+	dev_dbg(dev->dev, "init DSI output on pipe %d\n", pipe);
+
+	if (!dev || ((pipe != 0) && (pipe != 2))) {
+		DRM_ERROR("Invalid parameter\n");
+		return;
+	}
+
+	/*create a new connetor*/
+	dsi_connector = kzalloc(sizeof(struct mdfld_dsi_connector), GFP_KERNEL);
+	if (!dsi_connector) {
+		DRM_ERROR("No memory");
+		return;
+	}
+
+	dsi_connector->pipe =  pipe;
+
+	dsi_config = kzalloc(sizeof(struct mdfld_dsi_config),
+			GFP_KERNEL);
+	if (!dsi_config) {
+		DRM_ERROR("cannot allocate memory for DSI config\n");
+		goto dsi_init_err0;
+	}
+	mdfld_dsi_get_default_config(dev, dsi_config, pipe);
+
+	dsi_connector->private = dsi_config;
+
+	dsi_config->changed = 1;
+	dsi_config->dev = dev;
+
+	dsi_config->fixed_mode = p_vid_funcs->get_config_mode(dev);
+	if (p_vid_funcs->get_panel_info(dev, pipe, &dsi_panel_info))
+			goto dsi_init_err0;
+
+	width_mm = dsi_panel_info.width_mm;
+	height_mm = dsi_panel_info.height_mm;
+
+	dsi_config->mode = dsi_config->fixed_mode;
+	dsi_config->connector = dsi_connector;
+
+	if (!dsi_config->fixed_mode) {
+		DRM_ERROR("No pannel fixed mode was found\n");
+		goto dsi_init_err0;
+	}
+
+	if (pipe && dev_priv->dsi_configs[0]) {
+		dsi_config->dvr_ic_inited = 0;
+		dev_priv->dsi_configs[1] = dsi_config;
+	} else if (pipe == 0) {
+		dsi_config->dvr_ic_inited = 1;
+		dev_priv->dsi_configs[0] = dsi_config;
+	} else {
+		DRM_ERROR("Trying to init MIPI1 before MIPI0\n");
+		goto dsi_init_err0;
+	}
+
+
+	connector = &dsi_connector->base.base;
+	drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs,
+						DRM_MODE_CONNECTOR_LVDS);
+	drm_connector_helper_add(connector, &mdfld_dsi_connector_helper_funcs);
+
+	connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+	connector->display_info.width_mm = width_mm;
+	connector->display_info.height_mm = height_mm;
+	connector->interlace_allowed = false;
+	connector->doublescan_allowed = false;
+
+	/*attach properties*/
+	drm_connector_attach_property(connector,
+				dev->mode_config.scaling_mode_property,
+				DRM_MODE_SCALE_FULLSCREEN);
+	drm_connector_attach_property(connector,
+				dev_priv->backlight_property,
+				MDFLD_DSI_BRIGHTNESS_MAX_LEVEL);
+
+	/*init DSI package sender on this output*/
+	if (mdfld_dsi_pkg_sender_init(dsi_connector, pipe)) {
+		DRM_ERROR("Package Sender initialization failed on pipe %d\n",
+									pipe);
+		goto dsi_init_err0;
+	}
+
+	encoder = mdfld_dsi_dpi_init(dev, dsi_connector, p_vid_funcs);
+	if (!encoder) {
+		DRM_ERROR("Create DPI encoder failed\n");
+		goto dsi_init_err1;
+	}
+	encoder->private = dsi_config;
+	dsi_config->encoder = encoder;
+	encoder->base.type = (pipe == 0) ? INTEL_OUTPUT_MIPI :
+		INTEL_OUTPUT_MIPI2;
+	drm_sysfs_connector_add(connector);
+	return;
+
+	/*TODO: add code to destroy outputs on error*/
+dsi_init_err1:
+	/*destroy sender*/
+	mdfld_dsi_pkg_sender_destroy(dsi_connector->pkg_sender);
+
+	drm_connector_cleanup(connector);
+
+	kfree(dsi_config->fixed_mode);
+	kfree(dsi_config);
+dsi_init_err0:
+	kfree(dsi_connector);
+}
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.h b/drivers/gpu/drm/gma500/mdfld_dsi_output.h
new file mode 100644
index 0000000..21071ce
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.h
@@ -0,0 +1,378 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * jim liu <jim.liu@intel.com>
+ * Jackie Li<yaodong.li@intel.com>
+ */
+
+#ifndef __MDFLD_DSI_OUTPUT_H__
+#define __MDFLD_DSI_OUTPUT_H__
+
+#include <linux/backlight.h>
+#include <linux/version.h>
+#include <drm/drmP.h>
+#include <drm/drm.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+
+#include "psb_drv.h"
+#include "psb_intel_drv.h"
+#include "psb_intel_reg.h"
+#include "mdfld_output.h"
+
+#include <asm/mrst.h>
+
+#define FLD_MASK(start, end)	(((1 << ((start) - (end) + 1)) - 1) << (end))
+#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
+#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
+#define FLD_MOD(orig, val, start, end) \
+	(((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
+
+#define REG_FLD_MOD(reg, val, start, end) \
+	REG_WRITE(reg, FLD_MOD(REG_READ(reg), val, start, end))
+
+static inline int REGISTER_FLD_WAIT(struct drm_device *dev, u32 reg,
+		u32 val, int start, int end)
+{
+	int t = 100000;
+
+	while (FLD_GET(REG_READ(reg), start, end) != val) {
+		if (--t == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+#define REG_FLD_WAIT(reg, val, start, end) \
+	REGISTER_FLD_WAIT(dev, reg, val, start, end)
+
+#define REG_BIT_WAIT(reg, val, bitnum) \
+	REGISTER_FLD_WAIT(dev, reg, val, bitnum, bitnum)
+
+#define MDFLD_DSI_BRIGHTNESS_MAX_LEVEL 100
+
+#ifdef DEBUG
+#define CHECK_PIPE(pipe) ({			\
+	const typeof(pipe) __pipe = (pipe);	\
+	BUG_ON(__pipe != 0 && __pipe != 2);	\
+	__pipe;	})
+#else
+#define CHECK_PIPE(pipe) (pipe)
+#endif
+
+/*
+ * Actual MIPIA->MIPIC reg offset is 0x800, value 0x400 is valid for 0 and 2
+ */
+#define REG_OFFSET(pipe) (CHECK_PIPE(pipe) * 0x400)
+
+/* mdfld DSI controller registers */
+#define MIPI_DEVICE_READY_REG(pipe)		(0xb000 + REG_OFFSET(pipe))
+#define MIPI_INTR_STAT_REG(pipe)		(0xb004 + REG_OFFSET(pipe))
+#define MIPI_INTR_EN_REG(pipe)			(0xb008 + REG_OFFSET(pipe))
+#define MIPI_DSI_FUNC_PRG_REG(pipe)		(0xb00c + REG_OFFSET(pipe))
+#define MIPI_HS_TX_TIMEOUT_REG(pipe)		(0xb010 + REG_OFFSET(pipe))
+#define MIPI_LP_RX_TIMEOUT_REG(pipe)		(0xb014 + REG_OFFSET(pipe))
+#define MIPI_TURN_AROUND_TIMEOUT_REG(pipe)	(0xb018 + REG_OFFSET(pipe))
+#define MIPI_DEVICE_RESET_TIMER_REG(pipe)	(0xb01c + REG_OFFSET(pipe))
+#define MIPI_DPI_RESOLUTION_REG(pipe)		(0xb020 + REG_OFFSET(pipe))
+#define MIPI_DBI_FIFO_THROTTLE_REG(pipe)	(0xb024 + REG_OFFSET(pipe))
+#define MIPI_HSYNC_COUNT_REG(pipe)		(0xb028 + REG_OFFSET(pipe))
+#define MIPI_HBP_COUNT_REG(pipe)		(0xb02c + REG_OFFSET(pipe))
+#define MIPI_HFP_COUNT_REG(pipe)		(0xb030 + REG_OFFSET(pipe))
+#define MIPI_HACTIVE_COUNT_REG(pipe)		(0xb034 + REG_OFFSET(pipe))
+#define MIPI_VSYNC_COUNT_REG(pipe)		(0xb038 + REG_OFFSET(pipe))
+#define MIPI_VBP_COUNT_REG(pipe)		(0xb03c + REG_OFFSET(pipe))
+#define MIPI_VFP_COUNT_REG(pipe)		(0xb040 + REG_OFFSET(pipe))
+#define MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe)	(0xb044 + REG_OFFSET(pipe))
+#define MIPI_DPI_CONTROL_REG(pipe)		(0xb048 + REG_OFFSET(pipe))
+#define MIPI_DPI_DATA_REG(pipe)			(0xb04c + REG_OFFSET(pipe))
+#define MIPI_INIT_COUNT_REG(pipe)		(0xb050 + REG_OFFSET(pipe))
+#define MIPI_MAX_RETURN_PACK_SIZE_REG(pipe)	(0xb054 + REG_OFFSET(pipe))
+#define MIPI_VIDEO_MODE_FORMAT_REG(pipe)	(0xb058 + REG_OFFSET(pipe))
+#define MIPI_EOT_DISABLE_REG(pipe)		(0xb05c + REG_OFFSET(pipe))
+#define MIPI_LP_BYTECLK_REG(pipe)		(0xb060 + REG_OFFSET(pipe))
+#define MIPI_LP_GEN_DATA_REG(pipe)		(0xb064 + REG_OFFSET(pipe))
+#define MIPI_HS_GEN_DATA_REG(pipe)		(0xb068 + REG_OFFSET(pipe))
+#define MIPI_LP_GEN_CTRL_REG(pipe)		(0xb06c + REG_OFFSET(pipe))
+#define MIPI_HS_GEN_CTRL_REG(pipe)		(0xb070 + REG_OFFSET(pipe))
+#define MIPI_GEN_FIFO_STAT_REG(pipe)		(0xb074 + REG_OFFSET(pipe))
+#define MIPI_HS_LS_DBI_ENABLE_REG(pipe)		(0xb078 + REG_OFFSET(pipe))
+#define MIPI_DPHY_PARAM_REG(pipe)		(0xb080 + REG_OFFSET(pipe))
+#define MIPI_DBI_BW_CTRL_REG(pipe)		(0xb084 + REG_OFFSET(pipe))
+#define MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe)	(0xb088 + REG_OFFSET(pipe))
+
+#define MIPI_CTRL_REG(pipe)			(0xb104 + REG_OFFSET(pipe))
+#define MIPI_DATA_ADD_REG(pipe)			(0xb108 + REG_OFFSET(pipe))
+#define MIPI_DATA_LEN_REG(pipe)			(0xb10c + REG_OFFSET(pipe))
+#define MIPI_CMD_ADD_REG(pipe)			(0xb110 + REG_OFFSET(pipe))
+#define MIPI_CMD_LEN_REG(pipe)			(0xb114 + REG_OFFSET(pipe))
+
+/* non-uniform reg offset */
+#define MIPI_PORT_CONTROL(pipe)		(CHECK_PIPE(pipe) ? MIPI_C : MIPI)
+
+#define DSI_DEVICE_READY				(0x1)
+#define DSI_POWER_STATE_ULPS_ENTER			(0x2 << 1)
+#define DSI_POWER_STATE_ULPS_EXIT			(0x1 << 1)
+#define DSI_POWER_STATE_ULPS_OFFSET			(0x1)
+
+
+#define DSI_ONE_DATA_LANE					(0x1)
+#define DSI_TWO_DATA_LANE					(0x2)
+#define DSI_THREE_DATA_LANE					(0X3)
+#define DSI_FOUR_DATA_LANE					(0x4)
+#define DSI_DPI_VIRT_CHANNEL_OFFSET			(0x3)
+#define DSI_DBI_VIRT_CHANNEL_OFFSET			(0x5)
+#define DSI_DPI_COLOR_FORMAT_RGB565			(0x01 << 7)
+#define DSI_DPI_COLOR_FORMAT_RGB666			(0x02 << 7)
+#define DSI_DPI_COLOR_FORMAT_RGB666_UNPACK		(0x03 << 7)
+#define DSI_DPI_COLOR_FORMAT_RGB888			(0x04 << 7)
+#define DSI_DBI_COLOR_FORMAT_OPTION2			(0x05 << 13)
+
+#define DSI_INTR_STATE_RXSOTERROR			BIT(0)
+
+#define DSI_INTR_STATE_SPL_PKG_SENT			BIT(30)
+#define DSI_INTR_STATE_TE				BIT(31)
+
+#define DSI_HS_TX_TIMEOUT_MASK				(0xffffff)
+
+#define DSI_LP_RX_TIMEOUT_MASK				(0xffffff)
+
+#define DSI_TURN_AROUND_TIMEOUT_MASK		(0x3f)
+
+#define DSI_RESET_TIMER_MASK				(0xffff)
+
+#define DSI_DBI_FIFO_WM_HALF				(0x0)
+#define DSI_DBI_FIFO_WM_QUARTER				(0x1)
+#define DSI_DBI_FIFO_WM_LOW					(0x2)
+
+#define DSI_DPI_TIMING_MASK					(0xffff)
+
+#define DSI_INIT_TIMER_MASK					(0xffff)
+
+#define DSI_DBI_RETURN_PACK_SIZE_MASK		(0x3ff)
+
+#define DSI_LP_BYTECLK_MASK					(0x0ffff)
+
+#define DSI_HS_CTRL_GEN_SHORT_W0			(0x03)
+#define DSI_HS_CTRL_GEN_SHORT_W1			(0x13)
+#define DSI_HS_CTRL_GEN_SHORT_W2			(0x23)
+#define DSI_HS_CTRL_GEN_R0					(0x04)
+#define DSI_HS_CTRL_GEN_R1					(0x14)
+#define DSI_HS_CTRL_GEN_R2					(0x24)
+#define DSI_HS_CTRL_GEN_LONG_W				(0x29)
+#define DSI_HS_CTRL_MCS_SHORT_W0			(0x05)
+#define DSI_HS_CTRL_MCS_SHORT_W1			(0x15)
+#define DSI_HS_CTRL_MCS_R0					(0x06)
+#define DSI_HS_CTRL_MCS_LONG_W				(0x39)
+#define DSI_HS_CTRL_VC_OFFSET				(0x06)
+#define DSI_HS_CTRL_WC_OFFSET				(0x08)
+
+#define	DSI_FIFO_GEN_HS_DATA_FULL			BIT(0)
+#define DSI_FIFO_GEN_HS_DATA_HALF_EMPTY		BIT(1)
+#define DSI_FIFO_GEN_HS_DATA_EMPTY			BIT(2)
+#define DSI_FIFO_GEN_LP_DATA_FULL			BIT(8)
+#define DSI_FIFO_GEN_LP_DATA_HALF_EMPTY		BIT(9)
+#define DSI_FIFO_GEN_LP_DATA_EMPTY			BIT(10)
+#define DSI_FIFO_GEN_HS_CTRL_FULL			BIT(16)
+#define DSI_FIFO_GEN_HS_CTRL_HALF_EMPTY		BIT(17)
+#define DSI_FIFO_GEN_HS_CTRL_EMPTY			BIT(18)
+#define DSI_FIFO_GEN_LP_CTRL_FULL			BIT(24)
+#define DSI_FIFO_GEN_LP_CTRL_HALF_EMPTY		BIT(25)
+#define DSI_FIFO_GEN_LP_CTRL_EMPTY			BIT(26)
+#define DSI_FIFO_DBI_EMPTY					BIT(27)
+#define DSI_FIFO_DPI_EMPTY					BIT(28)
+
+#define DSI_DBI_HS_LP_SWITCH_MASK			(0x1)
+
+#define DSI_HS_LP_SWITCH_COUNTER_OFFSET		(0x0)
+#define DSI_LP_HS_SWITCH_COUNTER_OFFSET		(0x16)
+
+#define DSI_DPI_CTRL_HS_SHUTDOWN			(0x00000001)
+#define DSI_DPI_CTRL_HS_TURN_ON				(0x00000002)
+
+/*dsi power modes*/
+#define DSI_POWER_MODE_DISPLAY_ON	BIT(2)
+#define DSI_POWER_MODE_NORMAL_ON	BIT(3)
+#define DSI_POWER_MODE_SLEEP_OUT	BIT(4)
+#define DSI_POWER_MODE_PARTIAL_ON	BIT(5)
+#define DSI_POWER_MODE_IDLE_ON		BIT(6)
+
+enum {
+	MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE = 1,
+	MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS = 2,
+	MDFLD_DSI_VIDEO_BURST_MODE = 3,
+};
+
+#define DSI_DPI_COMPLETE_LAST_LINE			BIT(2)
+#define DSI_DPI_DISABLE_BTA					BIT(3)
+
+struct mdfld_dsi_connector {
+	struct psb_intel_connector base;
+
+	int pipe;
+	void *private;
+	void *pkg_sender;
+
+	/* Connection status */
+	enum drm_connector_status status;
+};
+
+struct mdfld_dsi_encoder {
+	struct psb_intel_encoder base;
+	void *private;
+};
+
+/*
+ * DSI config, consists of one DSI connector, two DSI encoders.
+ * DRM will pick up on DSI encoder basing on differents configs.
+ */
+struct mdfld_dsi_config {
+	struct drm_device *dev;
+	struct drm_display_mode *fixed_mode;
+	struct drm_display_mode *mode;
+
+	struct mdfld_dsi_connector *connector;
+	struct mdfld_dsi_encoder *encoder;
+
+	int changed;
+
+	int bpp;
+	int lane_count;
+	/*Virtual channel number for this encoder*/
+	int channel_num;
+	/*video mode configure*/
+	int video_mode;
+
+	int dvr_ic_inited;
+};
+
+static inline struct mdfld_dsi_connector *mdfld_dsi_connector(
+		struct drm_connector *connector)
+{
+	struct psb_intel_connector *psb_connector;
+
+	psb_connector = to_psb_intel_connector(connector);
+
+	return container_of(psb_connector, struct mdfld_dsi_connector, base);
+}
+
+static inline struct mdfld_dsi_encoder *mdfld_dsi_encoder(
+		struct drm_encoder *encoder)
+{
+	struct psb_intel_encoder *psb_encoder;
+
+	psb_encoder = to_psb_intel_encoder(encoder);
+
+	return container_of(psb_encoder, struct mdfld_dsi_encoder, base);
+}
+
+static inline struct mdfld_dsi_config *
+	mdfld_dsi_get_config(struct mdfld_dsi_connector *connector)
+{
+	if (!connector)
+		return NULL;
+	return (struct mdfld_dsi_config *)connector->private;
+}
+
+static inline void *mdfld_dsi_get_pkg_sender(struct mdfld_dsi_config *config)
+{
+	struct mdfld_dsi_connector *dsi_connector;
+
+	if (!config)
+		return NULL;
+
+	dsi_connector = config->connector;
+
+	if (!dsi_connector)
+		return NULL;
+
+	return dsi_connector->pkg_sender;
+}
+
+static inline struct mdfld_dsi_config *
+	mdfld_dsi_encoder_get_config(struct mdfld_dsi_encoder *encoder)
+{
+	if (!encoder)
+		return NULL;
+	return (struct mdfld_dsi_config *)encoder->private;
+}
+
+static inline struct mdfld_dsi_connector *
+	mdfld_dsi_encoder_get_connector(struct mdfld_dsi_encoder *encoder)
+{
+	struct mdfld_dsi_config *config;
+
+	if (!encoder)
+		return NULL;
+
+	config = mdfld_dsi_encoder_get_config(encoder);
+	if (!config)
+		return NULL;
+
+	return config->connector;
+}
+
+static inline void *mdfld_dsi_encoder_get_pkg_sender(
+				struct mdfld_dsi_encoder *encoder)
+{
+	struct mdfld_dsi_config *dsi_config;
+
+	dsi_config = mdfld_dsi_encoder_get_config(encoder);
+	if (!dsi_config)
+		return NULL;
+
+	return mdfld_dsi_get_pkg_sender(dsi_config);
+}
+
+static inline int mdfld_dsi_encoder_get_pipe(struct mdfld_dsi_encoder *encoder)
+{
+	struct mdfld_dsi_connector *connector;
+
+	if (!encoder)
+		return -1;
+
+	connector = mdfld_dsi_encoder_get_connector(encoder);
+	if (!connector)
+		return -1;
+	return connector->pipe;
+}
+
+/* Export functions */
+extern void mdfld_dsi_gen_fifo_ready(struct drm_device *dev,
+					u32 gen_fifo_stat_reg, u32 fifo_stat);
+extern void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config,
+					int pipe);
+extern void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe,
+					int level);
+extern void mdfld_dsi_output_init(struct drm_device *dev,
+					int pipe,
+					const struct panel_funcs *p_vid_funcs);
+extern void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config,
+					int pipe);
+
+extern int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config,
+					u32 *mode, bool hs);
+extern int mdfld_dsi_panel_reset(int pipe);
+
+#endif /*__MDFLD_DSI_OUTPUT_H__*/
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c
new file mode 100644
index 0000000..baa0e14
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c
@@ -0,0 +1,694 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Jackie Li<yaodong.li@intel.com>
+ */
+
+#include <linux/freezer.h>
+
+#include "mdfld_dsi_output.h"
+#include "mdfld_dsi_pkg_sender.h"
+#include "mdfld_dsi_dpi.h"
+
+#define MDFLD_DSI_READ_MAX_COUNT		5000
+
+enum data_type {
+	DSI_DT_GENERIC_SHORT_WRITE_0	= 0x03,
+	DSI_DT_GENERIC_SHORT_WRITE_1	= 0x13,
+	DSI_DT_GENERIC_SHORT_WRITE_2	= 0x23,
+	DSI_DT_GENERIC_READ_0		= 0x04,
+	DSI_DT_GENERIC_READ_1		= 0x14,
+	DSI_DT_GENERIC_READ_2		= 0x24,
+	DSI_DT_GENERIC_LONG_WRITE	= 0x29,
+	DSI_DT_DCS_SHORT_WRITE_0	= 0x05,
+	DSI_DT_DCS_SHORT_WRITE_1	= 0x15,
+	DSI_DT_DCS_READ			= 0x06,
+	DSI_DT_DCS_LONG_WRITE		= 0x39,
+};
+
+enum {
+	MDFLD_DSI_PANEL_MODE_SLEEP = 0x1,
+};
+
+enum {
+	MDFLD_DSI_PKG_SENDER_FREE = 0x0,
+	MDFLD_DSI_PKG_SENDER_BUSY = 0x1,
+};
+
+static const char *const dsi_errors[] = {
+	"RX SOT Error",
+	"RX SOT Sync Error",
+	"RX EOT Sync Error",
+	"RX Escape Mode Entry Error",
+	"RX LP TX Sync Error",
+	"RX HS Receive Timeout Error",
+	"RX False Control Error",
+	"RX ECC Single Bit Error",
+	"RX ECC Multibit Error",
+	"RX Checksum Error",
+	"RX DSI Data Type Not Recognised",
+	"RX DSI VC ID Invalid",
+	"TX False Control Error",
+	"TX ECC Single Bit Error",
+	"TX ECC Multibit Error",
+	"TX Checksum Error",
+	"TX DSI Data Type Not Recognised",
+	"TX DSI VC ID invalid",
+	"High Contention",
+	"Low contention",
+	"DPI FIFO Under run",
+	"HS TX Timeout",
+	"LP RX Timeout",
+	"Turn Around ACK Timeout",
+	"ACK With No Error",
+	"RX Invalid TX Length",
+	"RX Prot Violation",
+	"HS Generic Write FIFO Full",
+	"LP Generic Write FIFO Full",
+	"Generic Read Data Avail"
+	"Special Packet Sent",
+	"Tearing Effect",
+};
+
+static inline int wait_for_gen_fifo_empty(struct mdfld_dsi_pkg_sender *sender,
+						u32 mask)
+{
+	struct drm_device *dev = sender->dev;
+	u32 gen_fifo_stat_reg = sender->mipi_gen_fifo_stat_reg;
+	int retry = 0xffff;
+
+	while (retry--) {
+		if ((mask & REG_READ(gen_fifo_stat_reg)) == mask)
+			return 0;
+		udelay(100);
+	}
+	DRM_ERROR("fifo is NOT empty 0x%08x\n", REG_READ(gen_fifo_stat_reg));
+	return -EIO;
+}
+
+static int wait_for_all_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
+{
+	return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(10) | BIT(18) |
+						BIT(26) | BIT(27) | BIT(28)));
+}
+
+static int wait_for_lp_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
+{
+	return wait_for_gen_fifo_empty(sender, (BIT(10) | BIT(26)));
+}
+
+static int wait_for_hs_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
+{
+	return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(18)));
+}
+
+static int handle_dsi_error(struct mdfld_dsi_pkg_sender *sender, u32 mask)
+{
+	u32 intr_stat_reg = sender->mipi_intr_stat_reg;
+	struct drm_device *dev = sender->dev;
+
+	dev_dbg(sender->dev->dev, "Handling error 0x%08x\n", mask);
+
+	switch (mask) {
+	case BIT(0):
+	case BIT(1):
+	case BIT(2):
+	case BIT(3):
+	case BIT(4):
+	case BIT(5):
+	case BIT(6):
+	case BIT(7):
+	case BIT(8):
+	case BIT(9):
+	case BIT(10):
+	case BIT(11):
+	case BIT(12):
+	case BIT(13):
+		dev_dbg(sender->dev->dev, "No Action required\n");
+		break;
+	case BIT(14):
+		/*wait for all fifo empty*/
+		/*wait_for_all_fifos_empty(sender)*/;
+		break;
+	case BIT(15):
+		dev_dbg(sender->dev->dev, "No Action required\n");
+		break;
+	case BIT(16):
+		break;
+	case BIT(17):
+		break;
+	case BIT(18):
+	case BIT(19):
+		dev_dbg(sender->dev->dev, "High/Low contention detected\n");
+		/*wait for contention recovery time*/
+		/*mdelay(10);*/
+		/*wait for all fifo empty*/
+		if (0)
+			wait_for_all_fifos_empty(sender);
+		break;
+	case BIT(20):
+		dev_dbg(sender->dev->dev, "No Action required\n");
+		break;
+	case BIT(21):
+		/*wait for all fifo empty*/
+		/*wait_for_all_fifos_empty(sender);*/
+		break;
+	case BIT(22):
+		break;
+	case BIT(23):
+	case BIT(24):
+	case BIT(25):
+	case BIT(26):
+	case BIT(27):
+		dev_dbg(sender->dev->dev, "HS Gen fifo full\n");
+		REG_WRITE(intr_stat_reg, mask);
+		wait_for_hs_fifos_empty(sender);
+		break;
+	case BIT(28):
+		dev_dbg(sender->dev->dev, "LP Gen fifo full\n");
+		REG_WRITE(intr_stat_reg, mask);
+		wait_for_lp_fifos_empty(sender);
+		break;
+	case BIT(29):
+	case BIT(30):
+	case BIT(31):
+		dev_dbg(sender->dev->dev, "No Action required\n");
+		break;
+	}
+
+	if (mask & REG_READ(intr_stat_reg))
+		dev_dbg(sender->dev->dev,
+				"Cannot clean interrupt 0x%08x\n", mask);
+	return 0;
+}
+
+static int dsi_error_handler(struct mdfld_dsi_pkg_sender *sender)
+{
+	struct drm_device *dev = sender->dev;
+	u32 intr_stat_reg = sender->mipi_intr_stat_reg;
+	u32 mask;
+	u32 intr_stat;
+	int i;
+	int err = 0;
+
+	intr_stat = REG_READ(intr_stat_reg);
+
+	for (i = 0; i < 32; i++) {
+		mask = (0x00000001UL) << i;
+		if (intr_stat & mask) {
+			dev_dbg(sender->dev->dev, "[DSI]: %s\n", dsi_errors[i]);
+			err = handle_dsi_error(sender, mask);
+			if (err)
+				DRM_ERROR("Cannot handle error\n");
+		}
+	}
+	return err;
+}
+
+static int send_short_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
+			u8 cmd, u8 param, bool hs)
+{
+	struct drm_device *dev = sender->dev;
+	u32 ctrl_reg;
+	u32 val;
+	u8 virtual_channel = 0;
+
+	if (hs) {
+		ctrl_reg = sender->mipi_hs_gen_ctrl_reg;
+
+		/* FIXME: wait_for_hs_fifos_empty(sender); */
+	} else {
+		ctrl_reg = sender->mipi_lp_gen_ctrl_reg;
+
+		/* FIXME: wait_for_lp_fifos_empty(sender); */
+	}
+
+	val = FLD_VAL(param, 23, 16) | FLD_VAL(cmd, 15, 8) |
+		FLD_VAL(virtual_channel, 7, 6) | FLD_VAL(data_type, 5, 0);
+
+	REG_WRITE(ctrl_reg, val);
+
+	return 0;
+}
+
+static int send_long_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
+			u8 *data, int len, bool hs)
+{
+	struct drm_device *dev = sender->dev;
+	u32 ctrl_reg;
+	u32 data_reg;
+	u32 val;
+	u8 *p;
+	u8 b1, b2, b3, b4;
+	u8 virtual_channel = 0;
+	int i;
+
+	if (hs) {
+		ctrl_reg = sender->mipi_hs_gen_ctrl_reg;
+		data_reg = sender->mipi_hs_gen_data_reg;
+
+		/* FIXME: wait_for_hs_fifos_empty(sender); */
+	} else {
+		ctrl_reg = sender->mipi_lp_gen_ctrl_reg;
+		data_reg = sender->mipi_lp_gen_data_reg;
+
+		/* FIXME: wait_for_lp_fifos_empty(sender); */
+	}
+
+	p = data;
+	for (i = 0; i < len / 4; i++) {
+		b1 = *p++;
+		b2 = *p++;
+		b3 = *p++;
+		b4 = *p++;
+
+		REG_WRITE(data_reg, b4 << 24 | b3 << 16 | b2 << 8 | b1);
+	}
+
+	i = len % 4;
+	if (i) {
+		b1 = 0; b2 = 0; b3 = 0;
+
+		switch (i) {
+		case 3:
+			b1 = *p++;
+			b2 = *p++;
+			b3 = *p++;
+			break;
+		case 2:
+			b1 = *p++;
+			b2 = *p++;
+			break;
+		case 1:
+			b1 = *p++;
+			break;
+		}
+
+		REG_WRITE(data_reg, b3 << 16 | b2 << 8 | b1);
+	}
+
+	val = FLD_VAL(len, 23, 8) | FLD_VAL(virtual_channel, 7, 6) |
+		FLD_VAL(data_type, 5, 0);
+
+	REG_WRITE(ctrl_reg, val);
+
+	return 0;
+}
+
+static int send_pkg_prepare(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
+			u8 *data, u16 len)
+{
+	u8 cmd;
+
+	switch (data_type) {
+	case DSI_DT_DCS_SHORT_WRITE_0:
+	case DSI_DT_DCS_SHORT_WRITE_1:
+	case DSI_DT_DCS_LONG_WRITE:
+		cmd = *data;
+		break;
+	default:
+		return 0;
+	}
+
+	/*this prevents other package sending while doing msleep*/
+	sender->status = MDFLD_DSI_PKG_SENDER_BUSY;
+
+	/*wait for 120 milliseconds in case exit_sleep_mode just be sent*/
+	if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) {
+		/*TODO: replace it with msleep later*/
+		mdelay(120);
+	}
+
+	if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) {
+		/*TODO: replace it with msleep later*/
+		mdelay(120);
+	}
+	return 0;
+}
+
+static int send_pkg_done(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
+			u8 *data, u16 len)
+{
+	u8 cmd;
+
+	switch (data_type) {
+	case DSI_DT_DCS_SHORT_WRITE_0:
+	case DSI_DT_DCS_SHORT_WRITE_1:
+	case DSI_DT_DCS_LONG_WRITE:
+		cmd = *data;
+		break;
+	default:
+		return 0;
+	}
+
+	/*update panel status*/
+	if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) {
+		sender->panel_mode |= MDFLD_DSI_PANEL_MODE_SLEEP;
+		/*TODO: replace it with msleep later*/
+		mdelay(120);
+	} else if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) {
+		sender->panel_mode &= ~MDFLD_DSI_PANEL_MODE_SLEEP;
+		/*TODO: replace it with msleep later*/
+		mdelay(120);
+	} else if (unlikely(cmd == DCS_SOFT_RESET)) {
+		/*TODO: replace it with msleep later*/
+		mdelay(5);
+	}
+
+	sender->status = MDFLD_DSI_PKG_SENDER_FREE;
+
+	return 0;
+}
+
+static int send_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
+		u8 *data, u16 len, bool hs)
+{
+	int ret;
+
+	/*handle DSI error*/
+	ret = dsi_error_handler(sender);
+	if (ret) {
+		DRM_ERROR("Error handling failed\n");
+		return -EAGAIN;
+	}
+
+	/* send pkg */
+	if (sender->status == MDFLD_DSI_PKG_SENDER_BUSY) {
+		DRM_ERROR("sender is busy\n");
+		return -EAGAIN;
+	}
+
+	ret = send_pkg_prepare(sender, data_type, data, len);
+	if (ret) {
+		DRM_ERROR("send_pkg_prepare error\n");
+		return ret;
+	}
+
+	switch (data_type) {
+	case DSI_DT_GENERIC_SHORT_WRITE_0:
+	case DSI_DT_GENERIC_SHORT_WRITE_1:
+	case DSI_DT_GENERIC_SHORT_WRITE_2:
+	case DSI_DT_GENERIC_READ_0:
+	case DSI_DT_GENERIC_READ_1:
+	case DSI_DT_GENERIC_READ_2:
+	case DSI_DT_DCS_SHORT_WRITE_0:
+	case DSI_DT_DCS_SHORT_WRITE_1:
+	case DSI_DT_DCS_READ:
+		ret = send_short_pkg(sender, data_type, data[0], data[1], hs);
+		break;
+	case DSI_DT_GENERIC_LONG_WRITE:
+	case DSI_DT_DCS_LONG_WRITE:
+		ret = send_long_pkg(sender, data_type, data, len, hs);
+		break;
+	}
+
+	send_pkg_done(sender, data_type, data, len);
+
+	/*FIXME: should I query complete and fifo empty here?*/
+
+	return ret;
+}
+
+int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
+			u32 len, bool hs)
+{
+	unsigned long flags;
+
+	if (!sender || !data || !len) {
+		DRM_ERROR("Invalid parameters\n");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&sender->lock, flags);
+	send_pkg(sender, DSI_DT_DCS_LONG_WRITE, data, len, hs);
+	spin_unlock_irqrestore(&sender->lock, flags);
+
+	return 0;
+}
+
+int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
+			u8 param, u8 param_num, bool hs)
+{
+	u8 data[2];
+	unsigned long flags;
+	u8 data_type;
+
+	if (!sender) {
+		DRM_ERROR("Invalid parameter\n");
+		return -EINVAL;
+	}
+
+	data[0] = cmd;
+
+	if (param_num) {
+		data_type = DSI_DT_DCS_SHORT_WRITE_1;
+		data[1] = param;
+	} else {
+		data_type = DSI_DT_DCS_SHORT_WRITE_0;
+		data[1] = 0;
+	}
+
+	spin_lock_irqsave(&sender->lock, flags);
+	send_pkg(sender, data_type, data, sizeof(data), hs);
+	spin_unlock_irqrestore(&sender->lock, flags);
+
+	return 0;
+}
+
+int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0,
+			u8 param1, u8 param_num, bool hs)
+{
+	u8 data[2];
+	unsigned long flags;
+	u8 data_type;
+
+	if (!sender || param_num > 2) {
+		DRM_ERROR("Invalid parameter\n");
+		return -EINVAL;
+	}
+
+	switch (param_num) {
+	case 0:
+		data_type = DSI_DT_GENERIC_SHORT_WRITE_0;
+		data[0] = 0;
+		data[1] = 0;
+		break;
+	case 1:
+		data_type = DSI_DT_GENERIC_SHORT_WRITE_1;
+		data[0] = param0;
+		data[1] = 0;
+		break;
+	case 2:
+		data_type = DSI_DT_GENERIC_SHORT_WRITE_2;
+		data[0] = param0;
+		data[1] = param1;
+		break;
+	}
+
+	spin_lock_irqsave(&sender->lock, flags);
+	send_pkg(sender, data_type, data, sizeof(data), hs);
+	spin_unlock_irqrestore(&sender->lock, flags);
+
+	return 0;
+}
+
+int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
+			u32 len, bool hs)
+{
+	unsigned long flags;
+
+	if (!sender || !data || !len) {
+		DRM_ERROR("Invalid parameters\n");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&sender->lock, flags);
+	send_pkg(sender, DSI_DT_GENERIC_LONG_WRITE, data, len, hs);
+	spin_unlock_irqrestore(&sender->lock, flags);
+
+	return 0;
+}
+
+static int __read_panel_data(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
+			u8 *data, u16 len, u32 *data_out, u16 len_out, bool hs)
+{
+	unsigned long flags;
+	struct drm_device *dev = sender->dev;
+	int i;
+	u32 gen_data_reg;
+	int retry = MDFLD_DSI_READ_MAX_COUNT;
+
+	if (!sender || !data_out || !len_out) {
+		DRM_ERROR("Invalid parameters\n");
+		return -EINVAL;
+	}
+
+	/**
+	 * do reading.
+	 * 0) send out generic read request
+	 * 1) polling read data avail interrupt
+	 * 2) read data
+	 */
+	spin_lock_irqsave(&sender->lock, flags);
+
+	REG_WRITE(sender->mipi_intr_stat_reg, BIT(29));
+
+	if ((REG_READ(sender->mipi_intr_stat_reg) & BIT(29)))
+		DRM_ERROR("Can NOT clean read data valid interrupt\n");
+
+	/*send out read request*/
+	send_pkg(sender, data_type, data, len, hs);
+
+	/*polling read data avail interrupt*/
+	while (retry && !(REG_READ(sender->mipi_intr_stat_reg) & BIT(29))) {
+		udelay(100);
+		retry--;
+	}
+
+	if (!retry) {
+		spin_unlock_irqrestore(&sender->lock, flags);
+		return -ETIMEDOUT;
+	}
+
+	REG_WRITE(sender->mipi_intr_stat_reg, BIT(29));
+
+	/*read data*/
+	if (hs)
+		gen_data_reg = sender->mipi_hs_gen_data_reg;
+	else
+		gen_data_reg = sender->mipi_lp_gen_data_reg;
+
+	for (i = 0; i < len_out; i++)
+		*(data_out + i) = REG_READ(gen_data_reg);
+
+	spin_unlock_irqrestore(&sender->lock, flags);
+
+	return 0;
+}
+
+int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
+		u32 *data, u16 len, bool hs)
+{
+	if (!sender || !data || !len) {
+		DRM_ERROR("Invalid parameters\n");
+		return -EINVAL;
+	}
+
+	return __read_panel_data(sender, DSI_DT_DCS_READ, &cmd, 1,
+				data, len, hs);
+}
+
+int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector,
+								int pipe)
+{
+	struct mdfld_dsi_pkg_sender *pkg_sender;
+	struct mdfld_dsi_config *dsi_config =
+				mdfld_dsi_get_config(dsi_connector);
+	struct drm_device *dev = dsi_config->dev;
+	u32 mipi_val = 0;
+
+	if (!dsi_connector) {
+		DRM_ERROR("Invalid parameter\n");
+		return -EINVAL;
+	}
+
+	pkg_sender = dsi_connector->pkg_sender;
+
+	if (!pkg_sender || IS_ERR(pkg_sender)) {
+		pkg_sender = kzalloc(sizeof(struct mdfld_dsi_pkg_sender),
+								GFP_KERNEL);
+		if (!pkg_sender) {
+			DRM_ERROR("Create DSI pkg sender failed\n");
+			return -ENOMEM;
+		}
+		dsi_connector->pkg_sender = (void *)pkg_sender;
+	}
+
+	pkg_sender->dev = dev;
+	pkg_sender->dsi_connector = dsi_connector;
+	pkg_sender->pipe = pipe;
+	pkg_sender->pkg_num = 0;
+	pkg_sender->panel_mode = 0;
+	pkg_sender->status = MDFLD_DSI_PKG_SENDER_FREE;
+
+	/*init regs*/
+	if (pipe == 0) {
+		pkg_sender->dpll_reg = MRST_DPLL_A;
+		pkg_sender->dspcntr_reg = DSPACNTR;
+		pkg_sender->pipeconf_reg = PIPEACONF;
+		pkg_sender->dsplinoff_reg = DSPALINOFF;
+		pkg_sender->dspsurf_reg = DSPASURF;
+		pkg_sender->pipestat_reg = PIPEASTAT;
+	} else if (pipe == 2) {
+		pkg_sender->dpll_reg = MRST_DPLL_A;
+		pkg_sender->dspcntr_reg = DSPCCNTR;
+		pkg_sender->pipeconf_reg = PIPECCONF;
+		pkg_sender->dsplinoff_reg = DSPCLINOFF;
+		pkg_sender->dspsurf_reg = DSPCSURF;
+		pkg_sender->pipestat_reg = PIPECSTAT;
+	}
+
+	pkg_sender->mipi_intr_stat_reg = MIPI_INTR_STAT_REG(pipe);
+	pkg_sender->mipi_lp_gen_data_reg = MIPI_LP_GEN_DATA_REG(pipe);
+	pkg_sender->mipi_hs_gen_data_reg = MIPI_HS_GEN_DATA_REG(pipe);
+	pkg_sender->mipi_lp_gen_ctrl_reg = MIPI_LP_GEN_CTRL_REG(pipe);
+	pkg_sender->mipi_hs_gen_ctrl_reg = MIPI_HS_GEN_CTRL_REG(pipe);
+	pkg_sender->mipi_gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe);
+	pkg_sender->mipi_data_addr_reg = MIPI_DATA_ADD_REG(pipe);
+	pkg_sender->mipi_data_len_reg = MIPI_DATA_LEN_REG(pipe);
+	pkg_sender->mipi_cmd_addr_reg = MIPI_CMD_ADD_REG(pipe);
+	pkg_sender->mipi_cmd_len_reg = MIPI_CMD_LEN_REG(pipe);
+
+	/*init lock*/
+	spin_lock_init(&pkg_sender->lock);
+
+	if (mdfld_get_panel_type(dev, pipe) != TC35876X) {
+		/**
+		 * For video mode, don't enable DPI timing output here,
+		 * will init the DPI timing output during mode setting.
+		 */
+		mipi_val = PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX;
+
+		if (pipe == 0)
+			mipi_val |= 0x2;
+
+		REG_WRITE(MIPI_PORT_CONTROL(pipe), mipi_val);
+		REG_READ(MIPI_PORT_CONTROL(pipe));
+
+		/* do dsi controller init */
+		mdfld_dsi_controller_init(dsi_config, pipe);
+	}
+
+	return 0;
+}
+
+void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender)
+{
+	if (!sender || IS_ERR(sender))
+		return;
+
+	/*free*/
+	kfree(sender);
+}
+
+
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.h b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.h
new file mode 100644
index 0000000..459cd7e
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Jackie Li<yaodong.li@intel.com>
+ */
+#ifndef __MDFLD_DSI_PKG_SENDER_H__
+#define __MDFLD_DSI_PKG_SENDER_H__
+
+#include <linux/kthread.h>
+
+#define MDFLD_MAX_DCS_PARAM	8
+
+struct mdfld_dsi_pkg_sender {
+	struct drm_device *dev;
+	struct mdfld_dsi_connector *dsi_connector;
+	u32 status;
+	u32 panel_mode;
+
+	int pipe;
+
+	spinlock_t lock;
+
+	u32 pkg_num;
+
+	/* Registers */
+	u32 dpll_reg;
+	u32 dspcntr_reg;
+	u32 pipeconf_reg;
+	u32 pipestat_reg;
+	u32 dsplinoff_reg;
+	u32 dspsurf_reg;
+
+	u32 mipi_intr_stat_reg;
+	u32 mipi_lp_gen_data_reg;
+	u32 mipi_hs_gen_data_reg;
+	u32 mipi_lp_gen_ctrl_reg;
+	u32 mipi_hs_gen_ctrl_reg;
+	u32 mipi_gen_fifo_stat_reg;
+	u32 mipi_data_addr_reg;
+	u32 mipi_data_len_reg;
+	u32 mipi_cmd_addr_reg;
+	u32 mipi_cmd_len_reg;
+};
+
+/* DCS definitions */
+#define DCS_SOFT_RESET			0x01
+#define DCS_ENTER_SLEEP_MODE		0x10
+#define DCS_EXIT_SLEEP_MODE		0x11
+#define DCS_SET_DISPLAY_OFF		0x28
+#define DCS_SET_DISPLAY_ON		0x29
+#define DCS_SET_COLUMN_ADDRESS		0x2a
+#define DCS_SET_PAGE_ADDRESS		0x2b
+#define DCS_WRITE_MEM_START		0x2c
+#define DCS_SET_TEAR_OFF		0x34
+#define DCS_SET_TEAR_ON			0x35
+
+extern int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector,
+					int pipe);
+extern void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender);
+int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
+					u8 param, u8 param_num, bool hs);
+int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
+					u32 len, bool hs);
+int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0,
+					u8 param1, u8 param_num, bool hs);
+int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
+					u32 len, bool hs);
+/* Read interfaces */
+int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
+		u32 *data, u16 len, bool hs);
+
+#endif
diff --git a/drivers/gpu/drm/gma500/mdfld_intel_display.c b/drivers/gpu/drm/gma500/mdfld_intel_display.c
new file mode 100644
index 0000000..a35a292
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_intel_display.c
@@ -0,0 +1,1180 @@
+/*
+ * Copyright © 2006-2007 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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.
+ *
+ * Authors:
+ *	Eric Anholt <eric@anholt.net>
+ */
+
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+
+#include <drm/drmP.h>
+#include "psb_intel_reg.h"
+#include "psb_intel_display.h"
+#include "framebuffer.h"
+#include "mdfld_output.h"
+#include "mdfld_dsi_output.h"
+
+/* Hardcoded currently */
+static int ksel = KSEL_CRYSTAL_19;
+
+struct psb_intel_range_t {
+	int min, max;
+};
+
+struct mrst_limit_t {
+	struct psb_intel_range_t dot, m, p1;
+};
+
+struct mrst_clock_t {
+	/* derived values */
+	int dot;
+	int m;
+	int p1;
+};
+
+#define COUNT_MAX 0x10000000
+
+void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe)
+{
+	int count, temp;
+	u32 pipeconf_reg = PIPEACONF;
+
+	switch (pipe) {
+	case 0:
+		break;
+	case 1:
+		pipeconf_reg = PIPEBCONF;
+		break;
+	case 2:
+		pipeconf_reg = PIPECCONF;
+		break;
+	default:
+		DRM_ERROR("Illegal Pipe Number.\n");
+		return;
+	}
+
+	/* FIXME JLIU7_PO */
+	psb_intel_wait_for_vblank(dev);
+	return;
+
+	/* Wait for for the pipe disable to take effect. */
+	for (count = 0; count < COUNT_MAX; count++) {
+		temp = REG_READ(pipeconf_reg);
+		if ((temp & PIPEACONF_PIPE_STATE) == 0)
+			break;
+	}
+}
+
+void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe)
+{
+	int count, temp;
+	u32 pipeconf_reg = PIPEACONF;
+
+	switch (pipe) {
+	case 0:
+		break;
+	case 1:
+		pipeconf_reg = PIPEBCONF;
+		break;
+	case 2:
+		pipeconf_reg = PIPECCONF;
+		break;
+	default:
+		DRM_ERROR("Illegal Pipe Number.\n");
+		return;
+	}
+
+	/* FIXME JLIU7_PO */
+	psb_intel_wait_for_vblank(dev);
+	return;
+
+	/* Wait for for the pipe enable to take effect. */
+	for (count = 0; count < COUNT_MAX; count++) {
+		temp = REG_READ(pipeconf_reg);
+		if ((temp & PIPEACONF_PIPE_STATE) == 1)
+			break;
+	}
+}
+
+static void psb_intel_crtc_prepare(struct drm_crtc *crtc)
+{
+	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
+static void psb_intel_crtc_commit(struct drm_crtc *crtc)
+{
+	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+}
+
+static bool psb_intel_crtc_mode_fixup(struct drm_crtc *crtc,
+				  struct drm_display_mode *mode,
+				  struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+/**
+ * Return the pipe currently connected to the panel fitter,
+ * or -1 if the panel fitter is not present or not in use
+ */
+static int psb_intel_panel_fitter_pipe(struct drm_device *dev)
+{
+	u32 pfit_control;
+
+	pfit_control = REG_READ(PFIT_CONTROL);
+
+	/* See if the panel fitter is in use */
+	if ((pfit_control & PFIT_ENABLE) == 0)
+		return -1;
+
+	/* 965 can place panel fitter on either pipe */
+	return (pfit_control >> 29) & 0x3;
+}
+
+static struct drm_device globle_dev;
+
+void mdfld__intel_plane_set_alpha(int enable)
+{
+	struct drm_device *dev = &globle_dev;
+	int dspcntr_reg = DSPACNTR;
+	u32 dspcntr;
+
+	dspcntr = REG_READ(dspcntr_reg);
+
+	if (enable) {
+		dspcntr &= ~DISPPLANE_32BPP_NO_ALPHA;
+		dspcntr |= DISPPLANE_32BPP;
+	} else {
+		dspcntr &= ~DISPPLANE_32BPP;
+		dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
+	}
+
+	REG_WRITE(dspcntr_reg, dspcntr);
+}
+
+static int check_fb(struct drm_framebuffer *fb)
+{
+	if (!fb)
+		return 0;
+
+	switch (fb->bits_per_pixel) {
+	case 8:
+	case 16:
+	case 24:
+	case 32:
+		return 0;
+	default:
+		DRM_ERROR("Unknown color depth\n");
+		return -EINVAL;
+	}
+}
+
+static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
+				struct drm_framebuffer *old_fb)
+{
+	struct drm_device *dev = crtc->dev;
+	/* struct drm_i915_master_private *master_priv; */
+	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
+	struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
+	int pipe = psb_intel_crtc->pipe;
+	unsigned long start, offset;
+	int dsplinoff = DSPALINOFF;
+	int dspsurf = DSPASURF;
+	int dspstride = DSPASTRIDE;
+	int dspcntr_reg = DSPACNTR;
+	u32 dspcntr;
+	int ret;
+
+	memcpy(&globle_dev, dev, sizeof(struct drm_device));
+
+	dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe);
+
+	/* no fb bound */
+	if (!crtc->fb) {
+		dev_dbg(dev->dev, "No FB bound\n");
+		return 0;
+	}
+
+	ret = check_fb(crtc->fb);
+	if (ret)
+		return ret;
+
+	switch (pipe) {
+	case 0:
+		dsplinoff = DSPALINOFF;
+		break;
+	case 1:
+		dsplinoff = DSPBLINOFF;
+		dspsurf = DSPBSURF;
+		dspstride = DSPBSTRIDE;
+		dspcntr_reg = DSPBCNTR;
+		break;
+	case 2:
+		dsplinoff = DSPCLINOFF;
+		dspsurf = DSPCSURF;
+		dspstride = DSPCSTRIDE;
+		dspcntr_reg = DSPCCNTR;
+		break;
+	default:
+		DRM_ERROR("Illegal Pipe Number.\n");
+		return -EINVAL;
+	}
+
+	if (!gma_power_begin(dev, true))
+		return 0;
+
+	start = psbfb->gtt->offset;
+	offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
+
+	REG_WRITE(dspstride, crtc->fb->pitches[0]);
+	dspcntr = REG_READ(dspcntr_reg);
+	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
+
+	switch (crtc->fb->bits_per_pixel) {
+	case 8:
+		dspcntr |= DISPPLANE_8BPP;
+		break;
+	case 16:
+		if (crtc->fb->depth == 15)
+			dspcntr |= DISPPLANE_15_16BPP;
+		else
+			dspcntr |= DISPPLANE_16BPP;
+		break;
+	case 24:
+	case 32:
+		dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
+		break;
+	}
+	REG_WRITE(dspcntr_reg, dspcntr);
+
+	dev_dbg(dev->dev, "Writing base %08lX %08lX %d %d\n",
+						start, offset, x, y);
+	REG_WRITE(dsplinoff, offset);
+	REG_READ(dsplinoff);
+	REG_WRITE(dspsurf, start);
+	REG_READ(dspsurf);
+
+	gma_power_end(dev);
+
+	return 0;
+}
+
+/*
+ * Disable the pipe, plane and pll.
+ *
+ */
+void mdfld_disable_crtc(struct drm_device *dev, int pipe)
+{
+	int dpll_reg = MRST_DPLL_A;
+	int dspcntr_reg = DSPACNTR;
+	int dspbase_reg = MRST_DSPABASE;
+	int pipeconf_reg = PIPEACONF;
+	u32 temp;
+
+	dev_dbg(dev->dev, "pipe = %d\n", pipe);
+
+
+	switch (pipe) {
+	case 0:
+		break;
+	case 1:
+		dpll_reg = MDFLD_DPLL_B;
+		dspcntr_reg = DSPBCNTR;
+		dspbase_reg = DSPBSURF;
+		pipeconf_reg = PIPEBCONF;
+		break;
+	case 2:
+		dpll_reg = MRST_DPLL_A;
+		dspcntr_reg = DSPCCNTR;
+		dspbase_reg = MDFLD_DSPCBASE;
+		pipeconf_reg = PIPECCONF;
+		break;
+	default:
+		DRM_ERROR("Illegal Pipe Number.\n");
+		return;
+	}
+
+	if (pipe != 1)
+		mdfld_dsi_gen_fifo_ready(dev, MIPI_GEN_FIFO_STAT_REG(pipe),
+				HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY);
+
+	/* Disable display plane */
+	temp = REG_READ(dspcntr_reg);
+	if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
+		REG_WRITE(dspcntr_reg,
+			  temp & ~DISPLAY_PLANE_ENABLE);
+		/* Flush the plane changes */
+		REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+		REG_READ(dspbase_reg);
+	}
+
+	/* FIXME_JLIU7 MDFLD_PO revisit */
+
+	/* Next, disable display pipes */
+	temp = REG_READ(pipeconf_reg);
+	if ((temp & PIPEACONF_ENABLE) != 0) {
+		temp &= ~PIPEACONF_ENABLE;
+		temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF;
+		REG_WRITE(pipeconf_reg, temp);
+		REG_READ(pipeconf_reg);
+
+		/* Wait for for the pipe disable to take effect. */
+		mdfldWaitForPipeDisable(dev, pipe);
+	}
+
+	temp = REG_READ(dpll_reg);
+	if (temp & DPLL_VCO_ENABLE) {
+		if ((pipe != 1 &&
+			!((REG_READ(PIPEACONF) | REG_READ(PIPECCONF))
+				& PIPEACONF_ENABLE)) || pipe == 1) {
+			temp &= ~(DPLL_VCO_ENABLE);
+			REG_WRITE(dpll_reg, temp);
+			REG_READ(dpll_reg);
+			/* Wait for the clocks to turn off. */
+			/* FIXME_MDFLD PO may need more delay */
+			udelay(500);
+
+			if (!(temp & MDFLD_PWR_GATE_EN)) {
+				/* gating power of DPLL */
+				REG_WRITE(dpll_reg, temp | MDFLD_PWR_GATE_EN);
+				/* FIXME_MDFLD PO - change 500 to 1 after PO */
+				udelay(5000);
+			}
+		}
+	}
+
+}
+
+/**
+ * Sets the power management mode of the pipe and plane.
+ *
+ * This code should probably grow support for turning the cursor off and back
+ * on appropriately at the same time as we're turning the pipe off/on.
+ */
+static void mdfld_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
+	int pipe = psb_intel_crtc->pipe;
+	int dpll_reg = MRST_DPLL_A;
+	int dspcntr_reg = DSPACNTR;
+	int dspbase_reg = MRST_DSPABASE;
+	int pipeconf_reg = PIPEACONF;
+	u32 pipestat_reg = PIPEASTAT;
+	u32 pipeconf = dev_priv->pipeconf[pipe];
+	u32 temp;
+	int timeout = 0;
+
+	dev_dbg(dev->dev, "mode = %d, pipe = %d\n", mode, pipe);
+
+/* FIXME_JLIU7 MDFLD_PO replaced w/ the following function */
+/* mdfld_dbi_dpms (struct drm_device *dev, int pipe, bool enabled) */
+
+	switch (pipe) {
+	case 0:
+		break;
+	case 1:
+		dpll_reg = DPLL_B;
+		dspcntr_reg = DSPBCNTR;
+		dspbase_reg = MRST_DSPBBASE;
+		pipeconf_reg = PIPEBCONF;
+		dpll_reg = MDFLD_DPLL_B;
+		break;
+	case 2:
+		dpll_reg = MRST_DPLL_A;
+		dspcntr_reg = DSPCCNTR;
+		dspbase_reg = MDFLD_DSPCBASE;
+		pipeconf_reg = PIPECCONF;
+		pipestat_reg = PIPECSTAT;
+		break;
+	default:
+		DRM_ERROR("Illegal Pipe Number.\n");
+		return;
+	}
+
+	if (!gma_power_begin(dev, true))
+		return;
+
+	/* XXX: When our outputs are all unaware of DPMS modes other than off
+	 * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
+	 */
+	switch (mode) {
+	case DRM_MODE_DPMS_ON:
+	case DRM_MODE_DPMS_STANDBY:
+	case DRM_MODE_DPMS_SUSPEND:
+		/* Enable the DPLL */
+		temp = REG_READ(dpll_reg);
+
+		if ((temp & DPLL_VCO_ENABLE) == 0) {
+			/* When ungating power of DPLL, needs to wait 0.5us
+			   before enable the VCO */
+			if (temp & MDFLD_PWR_GATE_EN) {
+				temp &= ~MDFLD_PWR_GATE_EN;
+				REG_WRITE(dpll_reg, temp);
+				/* FIXME_MDFLD PO - change 500 to 1 after PO */
+				udelay(500);
+			}
+
+			REG_WRITE(dpll_reg, temp);
+			REG_READ(dpll_reg);
+			/* FIXME_MDFLD PO - change 500 to 1 after PO */
+			udelay(500);
+
+			REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
+			REG_READ(dpll_reg);
+
+			/**
+			 * wait for DSI PLL to lock
+			 * NOTE: only need to poll status of pipe 0 and pipe 1,
+			 * since both MIPI pipes share the same PLL.
+			 */
+			while ((pipe != 2) && (timeout < 20000) &&
+			  !(REG_READ(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) {
+				udelay(150);
+				timeout++;
+			}
+		}
+
+		/* Enable the plane */
+		temp = REG_READ(dspcntr_reg);
+		if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+			REG_WRITE(dspcntr_reg,
+				temp | DISPLAY_PLANE_ENABLE);
+			/* Flush the plane changes */
+			REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+		}
+
+		/* Enable the pipe */
+		temp = REG_READ(pipeconf_reg);
+		if ((temp & PIPEACONF_ENABLE) == 0) {
+			REG_WRITE(pipeconf_reg, pipeconf);
+
+			/* Wait for for the pipe enable to take effect. */
+			mdfldWaitForPipeEnable(dev, pipe);
+		}
+
+		/*workaround for sighting 3741701 Random X blank display*/
+		/*perform w/a in video mode only on pipe A or C*/
+		if (pipe == 0 || pipe == 2) {
+			REG_WRITE(pipestat_reg, REG_READ(pipestat_reg));
+			msleep(100);
+			if (PIPE_VBLANK_STATUS & REG_READ(pipestat_reg))
+				dev_dbg(dev->dev, "OK");
+			else {
+				dev_dbg(dev->dev, "STUCK!!!!");
+				/*shutdown controller*/
+				temp = REG_READ(dspcntr_reg);
+				REG_WRITE(dspcntr_reg,
+						temp & ~DISPLAY_PLANE_ENABLE);
+				REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+				/*mdfld_dsi_dpi_shut_down(dev, pipe);*/
+				REG_WRITE(0xb048, 1);
+				msleep(100);
+				temp = REG_READ(pipeconf_reg);
+				temp &= ~PIPEACONF_ENABLE;
+				REG_WRITE(pipeconf_reg, temp);
+				msleep(100); /*wait for pipe disable*/
+				REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 0);
+				msleep(100);
+				REG_WRITE(0xb004, REG_READ(0xb004));
+				/* try to bring the controller back up again*/
+				REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 1);
+				temp = REG_READ(dspcntr_reg);
+				REG_WRITE(dspcntr_reg,
+						temp | DISPLAY_PLANE_ENABLE);
+				REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+				/*mdfld_dsi_dpi_turn_on(dev, pipe);*/
+				REG_WRITE(0xb048, 2);
+				msleep(100);
+				temp = REG_READ(pipeconf_reg);
+				temp |= PIPEACONF_ENABLE;
+				REG_WRITE(pipeconf_reg, temp);
+			}
+		}
+
+		psb_intel_crtc_load_lut(crtc);
+
+		/* Give the overlay scaler a chance to enable
+		   if it's on this pipe */
+		/* psb_intel_crtc_dpms_video(crtc, true); TODO */
+
+		break;
+	case DRM_MODE_DPMS_OFF:
+		/* Give the overlay scaler a chance to disable
+		 * if it's on this pipe */
+		/* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */
+		if (pipe != 1)
+			mdfld_dsi_gen_fifo_ready(dev,
+				MIPI_GEN_FIFO_STAT_REG(pipe),
+				HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY);
+
+		/* Disable the VGA plane that we never use */
+		REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
+
+		/* Disable display plane */
+		temp = REG_READ(dspcntr_reg);
+		if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
+			REG_WRITE(dspcntr_reg,
+				  temp & ~DISPLAY_PLANE_ENABLE);
+			/* Flush the plane changes */
+			REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+			REG_READ(dspbase_reg);
+		}
+
+		/* Next, disable display pipes */
+		temp = REG_READ(pipeconf_reg);
+		if ((temp & PIPEACONF_ENABLE) != 0) {
+			temp &= ~PIPEACONF_ENABLE;
+			temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF;
+			REG_WRITE(pipeconf_reg, temp);
+			REG_READ(pipeconf_reg);
+
+			/* Wait for for the pipe disable to take effect. */
+			mdfldWaitForPipeDisable(dev, pipe);
+		}
+
+		temp = REG_READ(dpll_reg);
+		if (temp & DPLL_VCO_ENABLE) {
+			if ((pipe != 1 && !((REG_READ(PIPEACONF)
+				| REG_READ(PIPECCONF)) & PIPEACONF_ENABLE))
+					|| pipe == 1) {
+				temp &= ~(DPLL_VCO_ENABLE);
+				REG_WRITE(dpll_reg, temp);
+				REG_READ(dpll_reg);
+				/* Wait for the clocks to turn off. */
+				/* FIXME_MDFLD PO may need more delay */
+				udelay(500);
+			}
+		}
+		break;
+	}
+	gma_power_end(dev);
+}
+
+
+#define MDFLD_LIMT_DPLL_19	    0
+#define MDFLD_LIMT_DPLL_25	    1
+#define MDFLD_LIMT_DPLL_83	    2
+#define MDFLD_LIMT_DPLL_100	    3
+#define MDFLD_LIMT_DSIPLL_19	    4
+#define MDFLD_LIMT_DSIPLL_25	    5
+#define MDFLD_LIMT_DSIPLL_83	    6
+#define MDFLD_LIMT_DSIPLL_100	    7
+
+#define MDFLD_DOT_MIN		  19750
+#define MDFLD_DOT_MAX		  120000
+#define MDFLD_DPLL_M_MIN_19	    113
+#define MDFLD_DPLL_M_MAX_19	    155
+#define MDFLD_DPLL_P1_MIN_19	    2
+#define MDFLD_DPLL_P1_MAX_19	    10
+#define MDFLD_DPLL_M_MIN_25	    101
+#define MDFLD_DPLL_M_MAX_25	    130
+#define MDFLD_DPLL_P1_MIN_25	    2
+#define MDFLD_DPLL_P1_MAX_25	    10
+#define MDFLD_DPLL_M_MIN_83	    64
+#define MDFLD_DPLL_M_MAX_83	    64
+#define MDFLD_DPLL_P1_MIN_83	    2
+#define MDFLD_DPLL_P1_MAX_83	    2
+#define MDFLD_DPLL_M_MIN_100	    64
+#define MDFLD_DPLL_M_MAX_100	    64
+#define MDFLD_DPLL_P1_MIN_100	    2
+#define MDFLD_DPLL_P1_MAX_100	    2
+#define MDFLD_DSIPLL_M_MIN_19	    131
+#define MDFLD_DSIPLL_M_MAX_19	    175
+#define MDFLD_DSIPLL_P1_MIN_19	    3
+#define MDFLD_DSIPLL_P1_MAX_19	    8
+#define MDFLD_DSIPLL_M_MIN_25	    97
+#define MDFLD_DSIPLL_M_MAX_25	    140
+#define MDFLD_DSIPLL_P1_MIN_25	    3
+#define MDFLD_DSIPLL_P1_MAX_25	    9
+#define MDFLD_DSIPLL_M_MIN_83	    33
+#define MDFLD_DSIPLL_M_MAX_83	    92
+#define MDFLD_DSIPLL_P1_MIN_83	    2
+#define MDFLD_DSIPLL_P1_MAX_83	    3
+#define MDFLD_DSIPLL_M_MIN_100	    97
+#define MDFLD_DSIPLL_M_MAX_100	    140
+#define MDFLD_DSIPLL_P1_MIN_100	    3
+#define MDFLD_DSIPLL_P1_MAX_100	    9
+
+static const struct mrst_limit_t mdfld_limits[] = {
+	{			/* MDFLD_LIMT_DPLL_19 */
+	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+	 .m = {.min = MDFLD_DPLL_M_MIN_19, .max = MDFLD_DPLL_M_MAX_19},
+	 .p1 = {.min = MDFLD_DPLL_P1_MIN_19, .max = MDFLD_DPLL_P1_MAX_19},
+	 },
+	{			/* MDFLD_LIMT_DPLL_25 */
+	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+	 .m = {.min = MDFLD_DPLL_M_MIN_25, .max = MDFLD_DPLL_M_MAX_25},
+	 .p1 = {.min = MDFLD_DPLL_P1_MIN_25, .max = MDFLD_DPLL_P1_MAX_25},
+	 },
+	{			/* MDFLD_LIMT_DPLL_83 */
+	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+	 .m = {.min = MDFLD_DPLL_M_MIN_83, .max = MDFLD_DPLL_M_MAX_83},
+	 .p1 = {.min = MDFLD_DPLL_P1_MIN_83, .max = MDFLD_DPLL_P1_MAX_83},
+	 },
+	{			/* MDFLD_LIMT_DPLL_100 */
+	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+	 .m = {.min = MDFLD_DPLL_M_MIN_100, .max = MDFLD_DPLL_M_MAX_100},
+	 .p1 = {.min = MDFLD_DPLL_P1_MIN_100, .max = MDFLD_DPLL_P1_MAX_100},
+	 },
+	{			/* MDFLD_LIMT_DSIPLL_19 */
+	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+	 .m = {.min = MDFLD_DSIPLL_M_MIN_19, .max = MDFLD_DSIPLL_M_MAX_19},
+	 .p1 = {.min = MDFLD_DSIPLL_P1_MIN_19, .max = MDFLD_DSIPLL_P1_MAX_19},
+	 },
+	{			/* MDFLD_LIMT_DSIPLL_25 */
+	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+	 .m = {.min = MDFLD_DSIPLL_M_MIN_25, .max = MDFLD_DSIPLL_M_MAX_25},
+	 .p1 = {.min = MDFLD_DSIPLL_P1_MIN_25, .max = MDFLD_DSIPLL_P1_MAX_25},
+	 },
+	{			/* MDFLD_LIMT_DSIPLL_83 */
+	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+	 .m = {.min = MDFLD_DSIPLL_M_MIN_83, .max = MDFLD_DSIPLL_M_MAX_83},
+	 .p1 = {.min = MDFLD_DSIPLL_P1_MIN_83, .max = MDFLD_DSIPLL_P1_MAX_83},
+	 },
+	{			/* MDFLD_LIMT_DSIPLL_100 */
+	 .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+	 .m = {.min = MDFLD_DSIPLL_M_MIN_100, .max = MDFLD_DSIPLL_M_MAX_100},
+	 .p1 = {.min = MDFLD_DSIPLL_P1_MIN_100, .max = MDFLD_DSIPLL_P1_MAX_100},
+	 },
+};
+
+#define MDFLD_M_MIN	    21
+#define MDFLD_M_MAX	    180
+static const u32 mdfld_m_converts[] = {
+/* M configuration table from 9-bit LFSR table */
+	224, 368, 440, 220, 366, 439, 219, 365, 182, 347, /* 21 - 30 */
+	173, 342, 171, 85, 298, 149, 74, 37, 18, 265,   /* 31 - 40 */
+	388, 194, 353, 432, 216, 108, 310, 155, 333, 166, /* 41 - 50 */
+	83, 41, 276, 138, 325, 162, 337, 168, 340, 170, /* 51 - 60 */
+	341, 426, 469, 234, 373, 442, 221, 110, 311, 411, /* 61 - 70 */
+	461, 486, 243, 377, 188, 350, 175, 343, 427, 213, /* 71 - 80 */
+	106, 53, 282, 397, 354, 227, 113, 56, 284, 142, /* 81 - 90 */
+	71, 35, 273, 136, 324, 418, 465, 488, 500, 506, /* 91 - 100 */
+	253, 126, 63, 287, 399, 455, 483, 241, 376, 444, /* 101 - 110 */
+	478, 495, 503, 251, 381, 446, 479, 239, 375, 443, /* 111 - 120 */
+	477, 238, 119, 315, 157, 78, 295, 147, 329, 420, /* 121 - 130 */
+	210, 105, 308, 154, 77, 38, 275, 137, 68, 290, /* 131 - 140 */
+	145, 328, 164, 82, 297, 404, 458, 485, 498, 249, /* 141 - 150 */
+	380, 190, 351, 431, 471, 235, 117, 314, 413, 206, /* 151 - 160 */
+	103, 51, 25, 12, 262, 387, 193, 96, 48, 280, /* 161 - 170 */
+	396, 198, 99, 305, 152, 76, 294, 403, 457, 228, /* 171 - 180 */
+};
+
+static const struct mrst_limit_t *mdfld_limit(struct drm_crtc *crtc)
+{
+	const struct mrst_limit_t *limit = NULL;
+	struct drm_device *dev = crtc->dev;
+	struct drm_psb_private *dev_priv = dev->dev_private;
+
+	if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_MIPI)
+	    || psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_MIPI2)) {
+		if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19))
+			limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_19];
+		else if (ksel == KSEL_BYPASS_25)
+			limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_25];
+		else if ((ksel == KSEL_BYPASS_83_100) &&
+				(dev_priv->core_freq == 166))
+			limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_83];
+		else if ((ksel == KSEL_BYPASS_83_100) &&
+			 (dev_priv->core_freq == 100 ||
+				dev_priv->core_freq == 200))
+			limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_100];
+	} else if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) {
+		if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19))
+			limit = &mdfld_limits[MDFLD_LIMT_DPLL_19];
+		else if (ksel == KSEL_BYPASS_25)
+			limit = &mdfld_limits[MDFLD_LIMT_DPLL_25];
+		else if ((ksel == KSEL_BYPASS_83_100) &&
+				(dev_priv->core_freq == 166))
+			limit = &mdfld_limits[MDFLD_LIMT_DPLL_83];
+		else if ((ksel == KSEL_BYPASS_83_100) &&
+				 (dev_priv->core_freq == 100 ||
+				 dev_priv->core_freq == 200))
+			limit = &mdfld_limits[MDFLD_LIMT_DPLL_100];
+	} else {
+		limit = NULL;
+		dev_dbg(dev->dev, "mdfld_limit Wrong display type.\n");
+	}
+
+	return limit;
+}
+
+/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */
+static void mdfld_clock(int refclk, struct mrst_clock_t *clock)
+{
+	clock->dot = (refclk * clock->m) / clock->p1;
+}
+
+/**
+ * Returns a set of divisors for the desired target clock with the given refclk,
+ * or FALSE.  Divisor values are the actual divisors for
+ */
+static bool
+mdfldFindBestPLL(struct drm_crtc *crtc, int target, int refclk,
+		struct mrst_clock_t *best_clock)
+{
+	struct mrst_clock_t clock;
+	const struct mrst_limit_t *limit = mdfld_limit(crtc);
+	int err = target;
+
+	memset(best_clock, 0, sizeof(*best_clock));
+
+	for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) {
+		for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max;
+		     clock.p1++) {
+			int this_err;
+
+			mdfld_clock(refclk, &clock);
+
+			this_err = abs(clock.dot - target);
+			if (this_err < err) {
+				*best_clock = clock;
+				err = this_err;
+			}
+		}
+	}
+	return err != target;
+}
+
+static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
+			      struct drm_display_mode *mode,
+			      struct drm_display_mode *adjusted_mode,
+			      int x, int y,
+			      struct drm_framebuffer *old_fb)
+{
+	struct drm_device *dev = crtc->dev;
+	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	int pipe = psb_intel_crtc->pipe;
+	int fp_reg = MRST_FPA0;
+	int dpll_reg = MRST_DPLL_A;
+	int dspcntr_reg = DSPACNTR;
+	int pipeconf_reg = PIPEACONF;
+	int htot_reg = HTOTAL_A;
+	int hblank_reg = HBLANK_A;
+	int hsync_reg = HSYNC_A;
+	int vtot_reg = VTOTAL_A;
+	int vblank_reg = VBLANK_A;
+	int vsync_reg = VSYNC_A;
+	int dspsize_reg = DSPASIZE;
+	int dsppos_reg = DSPAPOS;
+	int pipesrc_reg = PIPEASRC;
+	u32 *pipeconf = &dev_priv->pipeconf[pipe];
+	u32 *dspcntr = &dev_priv->dspcntr[pipe];
+	int refclk = 0;
+	int clk_n = 0, clk_p2 = 0, clk_byte = 1, clk = 0, m_conv = 0,
+								clk_tmp = 0;
+	struct mrst_clock_t clock;
+	bool ok;
+	u32 dpll = 0, fp = 0;
+	bool is_mipi = false, is_mipi2 = false, is_hdmi = false;
+	struct drm_mode_config *mode_config = &dev->mode_config;
+	struct psb_intel_encoder *psb_intel_encoder = NULL;
+	uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN;
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+	int timeout = 0;
+	int ret;
+
+	dev_dbg(dev->dev, "pipe = 0x%x\n", pipe);
+
+#if 0
+	if (pipe == 1) {
+		if (!gma_power_begin(dev, true))
+			return 0;
+		android_hdmi_crtc_mode_set(crtc, mode, adjusted_mode,
+			x, y, old_fb);
+		goto mrst_crtc_mode_set_exit;
+	}
+#endif
+
+	switch (pipe) {
+	case 0:
+		break;
+	case 1:
+		fp_reg = FPB0;
+		dpll_reg = DPLL_B;
+		dspcntr_reg = DSPBCNTR;
+		pipeconf_reg = PIPEBCONF;
+		htot_reg = HTOTAL_B;
+		hblank_reg = HBLANK_B;
+		hsync_reg = HSYNC_B;
+		vtot_reg = VTOTAL_B;
+		vblank_reg = VBLANK_B;
+		vsync_reg = VSYNC_B;
+		dspsize_reg = DSPBSIZE;
+		dsppos_reg = DSPBPOS;
+		pipesrc_reg = PIPEBSRC;
+		fp_reg = MDFLD_DPLL_DIV0;
+		dpll_reg = MDFLD_DPLL_B;
+		break;
+	case 2:
+		dpll_reg = MRST_DPLL_A;
+		dspcntr_reg = DSPCCNTR;
+		pipeconf_reg = PIPECCONF;
+		htot_reg = HTOTAL_C;
+		hblank_reg = HBLANK_C;
+		hsync_reg = HSYNC_C;
+		vtot_reg = VTOTAL_C;
+		vblank_reg = VBLANK_C;
+		vsync_reg = VSYNC_C;
+		dspsize_reg = DSPCSIZE;
+		dsppos_reg = DSPCPOS;
+		pipesrc_reg = PIPECSRC;
+		break;
+	default:
+		DRM_ERROR("Illegal Pipe Number.\n");
+		return 0;
+	}
+
+	ret = check_fb(crtc->fb);
+	if (ret)
+		return ret;
+
+	dev_dbg(dev->dev, "adjusted_hdisplay = %d\n",
+		 adjusted_mode->hdisplay);
+	dev_dbg(dev->dev, "adjusted_vdisplay = %d\n",
+		 adjusted_mode->vdisplay);
+	dev_dbg(dev->dev, "adjusted_hsync_start = %d\n",
+		 adjusted_mode->hsync_start);
+	dev_dbg(dev->dev, "adjusted_hsync_end = %d\n",
+		 adjusted_mode->hsync_end);
+	dev_dbg(dev->dev, "adjusted_htotal = %d\n",
+		 adjusted_mode->htotal);
+	dev_dbg(dev->dev, "adjusted_vsync_start = %d\n",
+		 adjusted_mode->vsync_start);
+	dev_dbg(dev->dev, "adjusted_vsync_end = %d\n",
+		 adjusted_mode->vsync_end);
+	dev_dbg(dev->dev, "adjusted_vtotal = %d\n",
+		 adjusted_mode->vtotal);
+	dev_dbg(dev->dev, "adjusted_clock = %d\n",
+		 adjusted_mode->clock);
+	dev_dbg(dev->dev, "hdisplay = %d\n",
+		 mode->hdisplay);
+	dev_dbg(dev->dev, "vdisplay = %d\n",
+		 mode->vdisplay);
+
+	if (!gma_power_begin(dev, true))
+		return 0;
+
+	memcpy(&psb_intel_crtc->saved_mode, mode,
+					sizeof(struct drm_display_mode));
+	memcpy(&psb_intel_crtc->saved_adjusted_mode, adjusted_mode,
+					sizeof(struct drm_display_mode));
+
+	list_for_each_entry(connector, &mode_config->connector_list, head) {
+		if (!connector)
+			continue;
+
+		encoder = connector->encoder;
+
+		if (!encoder)
+			continue;
+
+		if (encoder->crtc != crtc)
+			continue;
+
+		psb_intel_encoder = psb_intel_attached_encoder(connector);
+
+		switch (psb_intel_encoder->type) {
+		case INTEL_OUTPUT_MIPI:
+			is_mipi = true;
+			break;
+		case INTEL_OUTPUT_MIPI2:
+			is_mipi2 = true;
+			break;
+		case INTEL_OUTPUT_HDMI:
+			is_hdmi = true;
+			break;
+		}
+	}
+
+	/* Disable the VGA plane that we never use */
+	REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
+
+	/* Disable the panel fitter if it was on our pipe */
+	if (psb_intel_panel_fitter_pipe(dev) == pipe)
+		REG_WRITE(PFIT_CONTROL, 0);
+
+	/* pipesrc and dspsize control the size that is scaled from,
+	 * which should always be the user's requested size.
+	 */
+	if (pipe == 1) {
+		/* FIXME: To make HDMI display with 864x480 (TPO), 480x864
+		 * (PYR) or 480x854 (TMD), set the sprite width/height and
+		 * souce image size registers with the adjusted mode for
+		 * pipe B.
+		 */
+
+		/*
+		 * The defined sprite rectangle must always be completely
+		 * contained within the displayable area of the screen image
+		 * (frame buffer).
+		 */
+		REG_WRITE(dspsize_reg, ((min(mode->crtc_vdisplay, adjusted_mode->crtc_vdisplay) - 1) << 16)
+				| (min(mode->crtc_hdisplay, adjusted_mode->crtc_hdisplay) - 1));
+		/* Set the CRTC with encoder mode. */
+		REG_WRITE(pipesrc_reg, ((mode->crtc_hdisplay - 1) << 16)
+				 | (mode->crtc_vdisplay - 1));
+	} else {
+		REG_WRITE(dspsize_reg,
+				((mode->crtc_vdisplay - 1) << 16) |
+						(mode->crtc_hdisplay - 1));
+		REG_WRITE(pipesrc_reg,
+				((mode->crtc_hdisplay - 1) << 16) |
+						(mode->crtc_vdisplay - 1));
+	}
+
+	REG_WRITE(dsppos_reg, 0);
+
+	if (psb_intel_encoder)
+		drm_connector_property_get_value(connector,
+			dev->mode_config.scaling_mode_property, &scalingType);
+
+	if (scalingType == DRM_MODE_SCALE_NO_SCALE) {
+		/* Medfield doesn't have register support for centering so we
+		 * need to mess with the h/vblank and h/vsync start and ends
+		 * to get centering
+		 */
+		int offsetX = 0, offsetY = 0;
+
+		offsetX = (adjusted_mode->crtc_hdisplay -
+					mode->crtc_hdisplay) / 2;
+		offsetY = (adjusted_mode->crtc_vdisplay -
+					mode->crtc_vdisplay) / 2;
+
+		REG_WRITE(htot_reg, (mode->crtc_hdisplay - 1) |
+			((adjusted_mode->crtc_htotal - 1) << 16));
+		REG_WRITE(vtot_reg, (mode->crtc_vdisplay - 1) |
+			((adjusted_mode->crtc_vtotal - 1) << 16));
+		REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start -
+								offsetX - 1) |
+			((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16));
+		REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start -
+								offsetX - 1) |
+			((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16));
+		REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start -
+								offsetY - 1) |
+			((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16));
+		REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start -
+								offsetY - 1) |
+			((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16));
+	} else {
+		REG_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
+			((adjusted_mode->crtc_htotal - 1) << 16));
+		REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
+			((adjusted_mode->crtc_vtotal - 1) << 16));
+		REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
+			((adjusted_mode->crtc_hblank_end - 1) << 16));
+		REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
+			((adjusted_mode->crtc_hsync_end - 1) << 16));
+		REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
+			((adjusted_mode->crtc_vblank_end - 1) << 16));
+		REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
+			((adjusted_mode->crtc_vsync_end - 1) << 16));
+	}
+
+	/* Flush the plane changes */
+	{
+		struct drm_crtc_helper_funcs *crtc_funcs =
+		    crtc->helper_private;
+		crtc_funcs->mode_set_base(crtc, x, y, old_fb);
+	}
+
+	/* setup pipeconf */
+	*pipeconf = PIPEACONF_ENABLE; /* FIXME_JLIU7 REG_READ(pipeconf_reg); */
+
+	/* Set up the display plane register */
+	*dspcntr = REG_READ(dspcntr_reg);
+	*dspcntr |= pipe << DISPPLANE_SEL_PIPE_POS;
+	*dspcntr |= DISPLAY_PLANE_ENABLE;
+
+	if (is_mipi2)
+		goto mrst_crtc_mode_set_exit;
+	clk = adjusted_mode->clock;
+
+	if (is_hdmi) {
+		if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) {
+			refclk = 19200;
+
+			if (is_mipi || is_mipi2)
+				clk_n = 1, clk_p2 = 8;
+			else if (is_hdmi)
+				clk_n = 1, clk_p2 = 10;
+		} else if (ksel == KSEL_BYPASS_25) {
+			refclk = 25000;
+
+			if (is_mipi || is_mipi2)
+				clk_n = 1, clk_p2 = 8;
+			else if (is_hdmi)
+				clk_n = 1, clk_p2 = 10;
+		} else if ((ksel == KSEL_BYPASS_83_100) &&
+					dev_priv->core_freq == 166) {
+			refclk = 83000;
+
+			if (is_mipi || is_mipi2)
+				clk_n = 4, clk_p2 = 8;
+			else if (is_hdmi)
+				clk_n = 4, clk_p2 = 10;
+		} else if ((ksel == KSEL_BYPASS_83_100) &&
+					(dev_priv->core_freq == 100 ||
+					dev_priv->core_freq == 200)) {
+			refclk = 100000;
+			if (is_mipi || is_mipi2)
+				clk_n = 4, clk_p2 = 8;
+			else if (is_hdmi)
+				clk_n = 4, clk_p2 = 10;
+		}
+
+		if (is_mipi)
+			clk_byte = dev_priv->bpp / 8;
+		else if (is_mipi2)
+			clk_byte = dev_priv->bpp2 / 8;
+
+		clk_tmp = clk * clk_n * clk_p2 * clk_byte;
+
+		dev_dbg(dev->dev, "clk = %d, clk_n = %d, clk_p2 = %d.\n",
+					clk, clk_n, clk_p2);
+		dev_dbg(dev->dev, "adjusted_mode->clock = %d, clk_tmp = %d.\n",
+					adjusted_mode->clock, clk_tmp);
+
+		ok = mdfldFindBestPLL(crtc, clk_tmp, refclk, &clock);
+
+		if (!ok) {
+			DRM_ERROR
+			    ("mdfldFindBestPLL fail in mdfld_crtc_mode_set.\n");
+		} else {
+			m_conv = mdfld_m_converts[(clock.m - MDFLD_M_MIN)];
+
+			dev_dbg(dev->dev, "dot clock = %d,"
+				 "m = %d, p1 = %d, m_conv = %d.\n",
+					clock.dot, clock.m,
+					clock.p1, m_conv);
+		}
+
+		dpll = REG_READ(dpll_reg);
+
+		if (dpll & DPLL_VCO_ENABLE) {
+			dpll &= ~DPLL_VCO_ENABLE;
+			REG_WRITE(dpll_reg, dpll);
+			REG_READ(dpll_reg);
+
+			/* FIXME jliu7 check the DPLL lock bit PIPEACONF[29] */
+			/* FIXME_MDFLD PO - change 500 to 1 after PO */
+			udelay(500);
+
+			/* reset M1, N1 & P1 */
+			REG_WRITE(fp_reg, 0);
+			dpll &= ~MDFLD_P1_MASK;
+			REG_WRITE(dpll_reg, dpll);
+			/* FIXME_MDFLD PO - change 500 to 1 after PO */
+			udelay(500);
+		}
+
+		/* When ungating power of DPLL, needs to wait 0.5us before
+		 * enable the VCO */
+		if (dpll & MDFLD_PWR_GATE_EN) {
+			dpll &= ~MDFLD_PWR_GATE_EN;
+			REG_WRITE(dpll_reg, dpll);
+			/* FIXME_MDFLD PO - change 500 to 1 after PO */
+			udelay(500);
+		}
+		dpll = 0;
+
+#if 0 /* FIXME revisit later */
+		if (ksel == KSEL_CRYSTAL_19 || ksel == KSEL_BYPASS_19 ||
+						ksel == KSEL_BYPASS_25)
+			dpll &= ~MDFLD_INPUT_REF_SEL;
+		else if (ksel == KSEL_BYPASS_83_100)
+			dpll |= MDFLD_INPUT_REF_SEL;
+#endif /* FIXME revisit later */
+
+		if (is_hdmi)
+			dpll |= MDFLD_VCO_SEL;
+
+		fp = (clk_n / 2) << 16;
+		fp |= m_conv;
+
+		/* compute bitmask from p1 value */
+		dpll |= (1 << (clock.p1 - 2)) << 17;
+
+#if 0 /* 1080p30 & 720p */
+		dpll = 0x00050000;
+		fp = 0x000001be;
+#endif
+#if 0 /* 480p */
+		dpll = 0x02010000;
+		fp = 0x000000d2;
+#endif
+	} else {
+#if 0 /*DBI_TPO_480x864*/
+		dpll = 0x00020000;
+		fp = 0x00000156;
+#endif /* DBI_TPO_480x864 */ /* get from spec. */
+
+		dpll = 0x00800000;
+		fp = 0x000000c1;
+	}
+
+	REG_WRITE(fp_reg, fp);
+	REG_WRITE(dpll_reg, dpll);
+	/* FIXME_MDFLD PO - change 500 to 1 after PO */
+	udelay(500);
+
+	dpll |= DPLL_VCO_ENABLE;
+	REG_WRITE(dpll_reg, dpll);
+	REG_READ(dpll_reg);
+
+	/* wait for DSI PLL to lock */
+	while (timeout < 20000 &&
+			!(REG_READ(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) {
+		udelay(150);
+		timeout++;
+	}
+
+	if (is_mipi)
+		goto mrst_crtc_mode_set_exit;
+
+	dev_dbg(dev->dev, "is_mipi = 0x%x\n", is_mipi);
+
+	REG_WRITE(pipeconf_reg, *pipeconf);
+	REG_READ(pipeconf_reg);
+
+	/* Wait for for the pipe enable to take effect. */
+	REG_WRITE(dspcntr_reg, *dspcntr);
+	psb_intel_wait_for_vblank(dev);
+
+mrst_crtc_mode_set_exit:
+
+	gma_power_end(dev);
+
+	return 0;
+}
+
+const struct drm_crtc_helper_funcs mdfld_helper_funcs = {
+	.dpms = mdfld_crtc_dpms,
+	.mode_fixup = psb_intel_crtc_mode_fixup,
+	.mode_set = mdfld_crtc_mode_set,
+	.mode_set_base = mdfld__intel_pipe_set_base,
+	.prepare = psb_intel_crtc_prepare,
+	.commit = psb_intel_crtc_commit,
+};
+
diff --git a/drivers/gpu/drm/gma500/mdfld_output.c b/drivers/gpu/drm/gma500/mdfld_output.c
new file mode 100644
index 0000000..c95966b
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_output.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c)  2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicensen
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Thomas Eaton <thomas.g.eaton@intel.com>
+ * Scott Rowe <scott.m.rowe@intel.com>
+*/
+
+#include "mdfld_output.h"
+#include "mdfld_dsi_dpi.h"
+#include "mdfld_dsi_output.h"
+
+#include "tc35876x-dsi-lvds.h"
+
+int mdfld_get_panel_type(struct drm_device *dev, int pipe)
+{
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	return dev_priv->mdfld_panel_id;
+}
+
+static void mdfld_init_panel(struct drm_device *dev, int mipi_pipe,
+								int p_type)
+{
+	switch (p_type) {
+	case TPO_VID:
+		mdfld_dsi_output_init(dev, mipi_pipe, &mdfld_tpo_vid_funcs);
+		break;
+	case TC35876X:
+		tc35876x_init(dev);
+		mdfld_dsi_output_init(dev, mipi_pipe, &mdfld_tc35876x_funcs);
+		break;
+	case TMD_VID:
+		mdfld_dsi_output_init(dev, mipi_pipe, &mdfld_tmd_vid_funcs);
+		break;
+	case HDMI:
+/*		if (dev_priv->mdfld_hdmi_present)
+			mdfld_hdmi_init(dev, &dev_priv->mode_dev); */
+		break;
+	}
+}
+
+
+int mdfld_output_init(struct drm_device *dev)
+{
+	struct drm_psb_private *dev_priv = dev->dev_private;
+
+	/* FIXME: hardcoded for now */
+	dev_priv->mdfld_panel_id = TC35876X;
+	/* MIPI panel 1 */
+	mdfld_init_panel(dev, 0, dev_priv->mdfld_panel_id);
+	/* HDMI panel */
+	mdfld_init_panel(dev, 1, HDMI);
+	return 0;
+}
+
diff --git a/drivers/gpu/drm/gma500/mdfld_output.h b/drivers/gpu/drm/gma500/mdfld_output.h
new file mode 100644
index 0000000..ab2b27c
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_output.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c)  2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicensen
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Thomas Eaton <thomas.g.eaton@intel.com>
+ * Scott Rowe <scott.m.rowe@intel.com>
+*/
+
+#ifndef MDFLD_OUTPUT_H
+#define MDFLD_OUTPUT_H
+
+#include "psb_drv.h"
+
+#define TPO_PANEL_WIDTH		84
+#define TPO_PANEL_HEIGHT	46
+#define TMD_PANEL_WIDTH		39
+#define TMD_PANEL_HEIGHT	71
+
+struct mdfld_dsi_config;
+
+enum panel_type {
+	TPO_VID,
+	TMD_VID,
+	HDMI,
+	TC35876X,
+};
+
+struct panel_info {
+	u32 width_mm;
+	u32 height_mm;
+	/* Other info */
+};
+
+struct panel_funcs {
+	const struct drm_encoder_funcs *encoder_funcs;
+	const struct drm_encoder_helper_funcs *encoder_helper_funcs;
+	struct drm_display_mode * (*get_config_mode)(struct drm_device *);
+	int (*get_panel_info)(struct drm_device *, int, struct panel_info *);
+	int (*reset)(int pipe);
+	void (*drv_ic_init)(struct mdfld_dsi_config *dsi_config, int pipe);
+};
+
+int mdfld_output_init(struct drm_device *dev);
+
+struct backlight_device *mdfld_get_backlight_device(void);
+int mdfld_set_brightness(struct backlight_device *bd);
+
+int mdfld_get_panel_type(struct drm_device *dev, int pipe);
+
+extern const struct drm_crtc_helper_funcs mdfld_helper_funcs;
+
+extern const struct panel_funcs mdfld_tmd_vid_funcs;
+extern const struct panel_funcs mdfld_tpo_vid_funcs;
+
+extern void mdfld_disable_crtc(struct drm_device *dev, int pipe);
+extern void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe);
+extern void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe);
+#endif
diff --git a/drivers/gpu/drm/gma500/mdfld_tmd_vid.c b/drivers/gpu/drm/gma500/mdfld_tmd_vid.c
new file mode 100644
index 0000000..dc0c6c3
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_tmd_vid.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Jim Liu <jim.liu@intel.com>
+ * Jackie Li<yaodong.li@intel.com>
+ * Gideon Eaton <eaton.
+ * Scott Rowe <scott.m.rowe@intel.com>
+ */
+
+#include "mdfld_dsi_dpi.h"
+#include "mdfld_dsi_pkg_sender.h"
+
+static struct drm_display_mode *tmd_vid_get_config_mode(struct drm_device *dev)
+{
+	struct drm_display_mode *mode;
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD;
+	bool use_gct = false; /*Disable GCT for now*/
+
+	mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+	if (!mode)
+		return NULL;
+
+	if (use_gct) {
+		mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo;
+		mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo;
+		mode->hsync_start = mode->hdisplay + \
+				((ti->hsync_offset_hi << 8) | \
+				ti->hsync_offset_lo);
+		mode->hsync_end = mode->hsync_start + \
+				((ti->hsync_pulse_width_hi << 8) | \
+				ti->hsync_pulse_width_lo);
+		mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | \
+								ti->hblank_lo);
+		mode->vsync_start = \
+			mode->vdisplay + ((ti->vsync_offset_hi << 8) | \
+						ti->vsync_offset_lo);
+		mode->vsync_end = \
+			mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) | \
+						ti->vsync_pulse_width_lo);
+		mode->vtotal = mode->vdisplay + \
+				((ti->vblank_hi << 8) | ti->vblank_lo);
+		mode->clock = ti->pixel_clock * 10;
+
+		dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay);
+		dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay);
+		dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start);
+		dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end);
+		dev_dbg(dev->dev, "htotal is %d\n", mode->htotal);
+		dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start);
+		dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end);
+		dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal);
+		dev_dbg(dev->dev, "clock is %d\n", mode->clock);
+	} else {
+		mode->hdisplay = 480;
+		mode->vdisplay = 854;
+		mode->hsync_start = 487;
+		mode->hsync_end = 490;
+		mode->htotal = 499;
+		mode->vsync_start = 861;
+		mode->vsync_end = 865;
+		mode->vtotal = 873;
+		mode->clock = 33264;
+	}
+
+	drm_mode_set_name(mode);
+	drm_mode_set_crtcinfo(mode, 0);
+
+	mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+	return mode;
+}
+
+static int tmd_vid_get_panel_info(struct drm_device *dev,
+				int pipe,
+				struct panel_info *pi)
+{
+	if (!dev || !pi)
+		return -EINVAL;
+
+	pi->width_mm = TMD_PANEL_WIDTH;
+	pi->height_mm = TMD_PANEL_HEIGHT;
+
+	return 0;
+}
+
+/* ************************************************************************* *\
+ * FUNCTION: mdfld_init_TMD_MIPI
+ *
+ * DESCRIPTION:  This function is called only by mrst_dsi_mode_set and
+ *               restore_display_registers.  since this function does not
+ *               acquire the mutex, it is important that the calling function
+ *               does!
+\* ************************************************************************* */
+
+/* FIXME: make the below data u8 instead of u32; note byte order! */
+static u32 tmd_cmd_mcap_off[] = {0x000000b2};
+static u32 tmd_cmd_enable_lane_switch[] = {0x000101ef};
+static u32 tmd_cmd_set_lane_num[] = {0x006360ef};
+static u32 tmd_cmd_pushing_clock0[] = {0x00cc2fef};
+static u32 tmd_cmd_pushing_clock1[] = {0x00dd6eef};
+static u32 tmd_cmd_set_mode[] = {0x000000b3};
+static u32 tmd_cmd_set_sync_pulse_mode[] = {0x000961ef};
+static u32 tmd_cmd_set_column[] = {0x0100002a, 0x000000df};
+static u32 tmd_cmd_set_page[] = {0x0300002b, 0x00000055};
+static u32 tmd_cmd_set_video_mode[] = {0x00000153};
+/*no auto_bl,need add in furture*/
+static u32 tmd_cmd_enable_backlight[] = {0x00005ab4};
+static u32 tmd_cmd_set_backlight_dimming[] = {0x00000ebd};
+
+static void mdfld_dsi_tmd_drv_ic_init(struct mdfld_dsi_config *dsi_config,
+				      int pipe)
+{
+	struct mdfld_dsi_pkg_sender *sender
+			= mdfld_dsi_get_pkg_sender(dsi_config);
+
+	DRM_INFO("Enter mdfld init TMD MIPI display.\n");
+
+	if (!sender) {
+		DRM_ERROR("Cannot get sender\n");
+		return;
+	}
+
+	if (dsi_config->dvr_ic_inited)
+		return;
+
+	msleep(3);
+
+	/* FIXME: make the below data u8 instead of u32; note byte order! */
+
+	mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_mcap_off,
+				sizeof(tmd_cmd_mcap_off), false);
+	mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_enable_lane_switch,
+				sizeof(tmd_cmd_enable_lane_switch), false);
+	mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_lane_num,
+				sizeof(tmd_cmd_set_lane_num), false);
+	mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_pushing_clock0,
+				sizeof(tmd_cmd_pushing_clock0), false);
+	mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_pushing_clock1,
+				sizeof(tmd_cmd_pushing_clock1), false);
+	mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_mode,
+				sizeof(tmd_cmd_set_mode), false);
+	mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_sync_pulse_mode,
+				sizeof(tmd_cmd_set_sync_pulse_mode), false);
+	mdfld_dsi_send_mcs_long(sender, (u8 *) tmd_cmd_set_column,
+				sizeof(tmd_cmd_set_column), false);
+	mdfld_dsi_send_mcs_long(sender, (u8 *) tmd_cmd_set_page,
+				sizeof(tmd_cmd_set_page), false);
+	mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_video_mode,
+				sizeof(tmd_cmd_set_video_mode), false);
+	mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_enable_backlight,
+				sizeof(tmd_cmd_enable_backlight), false);
+	mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_backlight_dimming,
+				sizeof(tmd_cmd_set_backlight_dimming), false);
+
+	dsi_config->dvr_ic_inited = 1;
+}
+
+/*TPO DPI encoder helper funcs*/
+static const struct drm_encoder_helper_funcs
+				mdfld_tpo_dpi_encoder_helper_funcs = {
+	.dpms = mdfld_dsi_dpi_dpms,
+	.mode_fixup = mdfld_dsi_dpi_mode_fixup,
+	.prepare = mdfld_dsi_dpi_prepare,
+	.mode_set = mdfld_dsi_dpi_mode_set,
+	.commit = mdfld_dsi_dpi_commit,
+};
+
+/*TPO DPI encoder funcs*/
+static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+const struct panel_funcs mdfld_tmd_vid_funcs = {
+	.encoder_funcs = &mdfld_tpo_dpi_encoder_funcs,
+	.encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs,
+	.get_config_mode = &tmd_vid_get_config_mode,
+	.get_panel_info = tmd_vid_get_panel_info,
+	.reset = mdfld_dsi_panel_reset,
+	.drv_ic_init = mdfld_dsi_tmd_drv_ic_init,
+};
diff --git a/drivers/gpu/drm/gma500/mdfld_tpo_vid.c b/drivers/gpu/drm/gma500/mdfld_tpo_vid.c
new file mode 100644
index 0000000..d8d4170
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_tpo_vid.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * jim liu <jim.liu@intel.com>
+ * Jackie Li<yaodong.li@intel.com>
+ */
+
+#include "mdfld_dsi_dpi.h"
+
+static struct drm_display_mode *tpo_vid_get_config_mode(struct drm_device *dev)
+{
+	struct drm_display_mode *mode;
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD;
+	bool use_gct = false;
+
+	mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+	if (!mode)
+		return NULL;
+
+	if (use_gct) {
+		mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo;
+		mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo;
+		mode->hsync_start = mode->hdisplay +
+				((ti->hsync_offset_hi << 8) |
+				ti->hsync_offset_lo);
+		mode->hsync_end = mode->hsync_start +
+				((ti->hsync_pulse_width_hi << 8) |
+				ti->hsync_pulse_width_lo);
+		mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) |
+								ti->hblank_lo);
+		mode->vsync_start =
+			mode->vdisplay + ((ti->vsync_offset_hi << 8) |
+						ti->vsync_offset_lo);
+		mode->vsync_end =
+			mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) |
+						ti->vsync_pulse_width_lo);
+		mode->vtotal = mode->vdisplay +
+				((ti->vblank_hi << 8) | ti->vblank_lo);
+		mode->clock = ti->pixel_clock * 10;
+
+		dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay);
+		dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay);
+		dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start);
+		dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end);
+		dev_dbg(dev->dev, "htotal is %d\n", mode->htotal);
+		dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start);
+		dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end);
+		dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal);
+		dev_dbg(dev->dev, "clock is %d\n", mode->clock);
+	} else {
+		mode->hdisplay = 864;
+		mode->vdisplay = 480;
+		mode->hsync_start = 873;
+		mode->hsync_end = 876;
+		mode->htotal = 887;
+		mode->vsync_start = 487;
+		mode->vsync_end = 490;
+		mode->vtotal = 499;
+		mode->clock = 33264;
+	}
+
+	drm_mode_set_name(mode);
+	drm_mode_set_crtcinfo(mode, 0);
+
+	mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+	return mode;
+}
+
+static int tpo_vid_get_panel_info(struct drm_device *dev,
+				int pipe,
+				struct panel_info *pi)
+{
+	if (!dev || !pi)
+		return -EINVAL;
+
+	pi->width_mm = TPO_PANEL_WIDTH;
+	pi->height_mm = TPO_PANEL_HEIGHT;
+
+	return 0;
+}
+
+/*TPO DPI encoder helper funcs*/
+static const struct drm_encoder_helper_funcs
+				mdfld_tpo_dpi_encoder_helper_funcs = {
+	.dpms = mdfld_dsi_dpi_dpms,
+	.mode_fixup = mdfld_dsi_dpi_mode_fixup,
+	.prepare = mdfld_dsi_dpi_prepare,
+	.mode_set = mdfld_dsi_dpi_mode_set,
+	.commit = mdfld_dsi_dpi_commit,
+};
+
+/*TPO DPI encoder funcs*/
+static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+const struct panel_funcs mdfld_tpo_vid_funcs = {
+	.encoder_funcs = &mdfld_tpo_dpi_encoder_funcs,
+	.encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs,
+	.get_config_mode = &tpo_vid_get_config_mode,
+	.get_panel_info = tpo_vid_get_panel_info,
+};
diff --git a/drivers/gpu/drm/gma500/mmu.c b/drivers/gpu/drm/gma500/mmu.c
index e80ee82..49bac41 100644
--- a/drivers/gpu/drm/gma500/mmu.c
+++ b/drivers/gpu/drm/gma500/mmu.c
@@ -270,7 +270,7 @@
 	return NULL;
 }
 
-void psb_mmu_free_pt(struct psb_mmu_pt *pt)
+static void psb_mmu_free_pt(struct psb_mmu_pt *pt)
 {
 	__free_page(pt->p);
 	kfree(pt);
@@ -351,7 +351,7 @@
 	return pt;
 }
 
-struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd,
+static struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd,
 					     unsigned long addr)
 {
 	uint32_t index = psb_mmu_pd_index(addr);
@@ -488,15 +488,6 @@
 	return pd;
 }
 
-/* Returns the physical address of the PD shared by sgx/msvdx */
-uint32_t psb_get_default_pd_addr(struct psb_mmu_driver *driver)
-{
-	struct psb_mmu_pd *pd;
-
-	pd = psb_mmu_get_default_pd(driver);
-	return page_to_pfn(pd->p) << PAGE_SHIFT;
-}
-
 void psb_mmu_driver_takedown(struct psb_mmu_driver *driver)
 {
 	psb_mmu_free_pagedir(driver->default_pd);
diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c
index 9d12a3e..a39b0d0 100644
--- a/drivers/gpu/drm/gma500/oaktrail_crtc.c
+++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c
@@ -115,7 +115,7 @@
 	clock->dot = (refclk * clock->m) / (14 * clock->p1);
 }
 
-void mrstPrintPll(char *prefix, struct oaktrail_clock_t *clock)
+static void mrstPrintPll(char *prefix, struct oaktrail_clock_t *clock)
 {
 	pr_debug("%s: dotclock = %d,  m = %d, p1 = %d.\n",
 	     prefix, clock->dot, clock->m, clock->p1);
@@ -169,7 +169,6 @@
 	int dspbase_reg = (pipe == 0) ? MRST_DSPABASE : DSPBBASE;
 	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
 	u32 temp;
-	bool enabled;
 
 	if (!gma_power_begin(dev, true))
 		return;
@@ -253,8 +252,6 @@
 		break;
 	}
 
-	enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF;
-
 	/*Set FIFO Watermarks*/
 	REG_WRITE(DSPARB, 0x3FFF);
 	REG_WRITE(DSPFW1, 0x3F88080A);
@@ -310,7 +307,7 @@
 	struct oaktrail_clock_t clock;
 	u32 dpll = 0, fp = 0, dspcntr, pipeconf;
 	bool ok, is_sdvo = false;
-	bool is_crt = false, is_lvds = false, is_tv = false;
+	bool is_lvds = false;
 	bool is_mipi = false;
 	struct drm_mode_config *mode_config = &dev->mode_config;
 	struct psb_intel_encoder *psb_intel_encoder = NULL;
@@ -340,12 +337,6 @@
 		case INTEL_OUTPUT_SDVO:
 			is_sdvo = true;
 			break;
-		case INTEL_OUTPUT_TVOUT:
-			is_tv = true;
-			break;
-		case INTEL_OUTPUT_ANALOG:
-			is_crt = true;
-			break;
 		case INTEL_OUTPUT_MIPI:
 			is_mipi = true;
 			break;
@@ -428,9 +419,6 @@
 	else
 		dspcntr |= DISPPLANE_SEL_PIPE_B;
 
-	dev_priv->dspcntr = dspcntr |= DISPLAY_PLANE_ENABLE;
-	dev_priv->pipeconf = pipeconf |= PIPEACONF_ENABLE;
-
 	if (is_mipi)
 		goto oaktrail_crtc_mode_set_exit;
 
@@ -517,7 +505,7 @@
 	return true;
 }
 
-int oaktrail_pipe_set_base(struct drm_crtc *crtc,
+static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
 			    int x, int y, struct drm_framebuffer *old_fb)
 {
 	struct drm_device *dev = crtc->dev;
diff --git a/drivers/gpu/drm/gma500/oaktrail_device.c b/drivers/gpu/drm/gma500/oaktrail_device.c
index 63aea2f..41d1924 100644
--- a/drivers/gpu/drm/gma500/oaktrail_device.c
+++ b/drivers/gpu/drm/gma500/oaktrail_device.c
@@ -141,7 +141,7 @@
 	.update_status  = oaktrail_set_brightness,
 };
 
-int oaktrail_backlight_init(struct drm_device *dev)
+static int oaktrail_backlight_init(struct drm_device *dev)
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	int ret;
@@ -176,10 +176,6 @@
  *	for power management
  */
 
-static void oaktrail_init_pm(struct drm_device *dev)
-{
-}
-
 /**
  *	oaktrail_save_display_registers	-	save registers lost on suspend
  *	@dev: our DRM device
@@ -190,81 +186,82 @@
 static int oaktrail_save_display_registers(struct drm_device *dev)
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
+	struct psb_save_area *regs = &dev_priv->regs;
 	int i;
 	u32 pp_stat;
 
 	/* Display arbitration control + watermarks */
-	dev_priv->saveDSPARB = PSB_RVDC32(DSPARB);
-	dev_priv->saveDSPFW1 = PSB_RVDC32(DSPFW1);
-	dev_priv->saveDSPFW2 = PSB_RVDC32(DSPFW2);
-	dev_priv->saveDSPFW3 = PSB_RVDC32(DSPFW3);
-	dev_priv->saveDSPFW4 = PSB_RVDC32(DSPFW4);
-	dev_priv->saveDSPFW5 = PSB_RVDC32(DSPFW5);
-	dev_priv->saveDSPFW6 = PSB_RVDC32(DSPFW6);
-	dev_priv->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
+	regs->psb.saveDSPARB = PSB_RVDC32(DSPARB);
+	regs->psb.saveDSPFW1 = PSB_RVDC32(DSPFW1);
+	regs->psb.saveDSPFW2 = PSB_RVDC32(DSPFW2);
+	regs->psb.saveDSPFW3 = PSB_RVDC32(DSPFW3);
+	regs->psb.saveDSPFW4 = PSB_RVDC32(DSPFW4);
+	regs->psb.saveDSPFW5 = PSB_RVDC32(DSPFW5);
+	regs->psb.saveDSPFW6 = PSB_RVDC32(DSPFW6);
+	regs->psb.saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
 
 	/* Pipe & plane A info */
-	dev_priv->savePIPEACONF = PSB_RVDC32(PIPEACONF);
-	dev_priv->savePIPEASRC = PSB_RVDC32(PIPEASRC);
-	dev_priv->saveFPA0 = PSB_RVDC32(MRST_FPA0);
-	dev_priv->saveFPA1 = PSB_RVDC32(MRST_FPA1);
-	dev_priv->saveDPLL_A = PSB_RVDC32(MRST_DPLL_A);
-	dev_priv->saveHTOTAL_A = PSB_RVDC32(HTOTAL_A);
-	dev_priv->saveHBLANK_A = PSB_RVDC32(HBLANK_A);
-	dev_priv->saveHSYNC_A = PSB_RVDC32(HSYNC_A);
-	dev_priv->saveVTOTAL_A = PSB_RVDC32(VTOTAL_A);
-	dev_priv->saveVBLANK_A = PSB_RVDC32(VBLANK_A);
-	dev_priv->saveVSYNC_A = PSB_RVDC32(VSYNC_A);
-	dev_priv->saveBCLRPAT_A = PSB_RVDC32(BCLRPAT_A);
-	dev_priv->saveDSPACNTR = PSB_RVDC32(DSPACNTR);
-	dev_priv->saveDSPASTRIDE = PSB_RVDC32(DSPASTRIDE);
-	dev_priv->saveDSPAADDR = PSB_RVDC32(DSPABASE);
-	dev_priv->saveDSPASURF = PSB_RVDC32(DSPASURF);
-	dev_priv->saveDSPALINOFF = PSB_RVDC32(DSPALINOFF);
-	dev_priv->saveDSPATILEOFF = PSB_RVDC32(DSPATILEOFF);
+	regs->psb.savePIPEACONF = PSB_RVDC32(PIPEACONF);
+	regs->psb.savePIPEASRC = PSB_RVDC32(PIPEASRC);
+	regs->psb.saveFPA0 = PSB_RVDC32(MRST_FPA0);
+	regs->psb.saveFPA1 = PSB_RVDC32(MRST_FPA1);
+	regs->psb.saveDPLL_A = PSB_RVDC32(MRST_DPLL_A);
+	regs->psb.saveHTOTAL_A = PSB_RVDC32(HTOTAL_A);
+	regs->psb.saveHBLANK_A = PSB_RVDC32(HBLANK_A);
+	regs->psb.saveHSYNC_A = PSB_RVDC32(HSYNC_A);
+	regs->psb.saveVTOTAL_A = PSB_RVDC32(VTOTAL_A);
+	regs->psb.saveVBLANK_A = PSB_RVDC32(VBLANK_A);
+	regs->psb.saveVSYNC_A = PSB_RVDC32(VSYNC_A);
+	regs->psb.saveBCLRPAT_A = PSB_RVDC32(BCLRPAT_A);
+	regs->psb.saveDSPACNTR = PSB_RVDC32(DSPACNTR);
+	regs->psb.saveDSPASTRIDE = PSB_RVDC32(DSPASTRIDE);
+	regs->psb.saveDSPAADDR = PSB_RVDC32(DSPABASE);
+	regs->psb.saveDSPASURF = PSB_RVDC32(DSPASURF);
+	regs->psb.saveDSPALINOFF = PSB_RVDC32(DSPALINOFF);
+	regs->psb.saveDSPATILEOFF = PSB_RVDC32(DSPATILEOFF);
 
 	/* Save cursor regs */
-	dev_priv->saveDSPACURSOR_CTRL = PSB_RVDC32(CURACNTR);
-	dev_priv->saveDSPACURSOR_BASE = PSB_RVDC32(CURABASE);
-	dev_priv->saveDSPACURSOR_POS = PSB_RVDC32(CURAPOS);
+	regs->psb.saveDSPACURSOR_CTRL = PSB_RVDC32(CURACNTR);
+	regs->psb.saveDSPACURSOR_BASE = PSB_RVDC32(CURABASE);
+	regs->psb.saveDSPACURSOR_POS = PSB_RVDC32(CURAPOS);
 
 	/* Save palette (gamma) */
 	for (i = 0; i < 256; i++)
-		dev_priv->save_palette_a[i] = PSB_RVDC32(PALETTE_A + (i << 2));
+		regs->psb.save_palette_a[i] = PSB_RVDC32(PALETTE_A + (i << 2));
 
 	if (dev_priv->hdmi_priv)
 		oaktrail_hdmi_save(dev);
 
 	/* Save performance state */
-	dev_priv->savePERF_MODE = PSB_RVDC32(MRST_PERF_MODE);
+	regs->psb.savePERF_MODE = PSB_RVDC32(MRST_PERF_MODE);
 
 	/* LVDS state */
-	dev_priv->savePP_CONTROL = PSB_RVDC32(PP_CONTROL);
-	dev_priv->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
-	dev_priv->savePFIT_AUTO_RATIOS = PSB_RVDC32(PFIT_AUTO_RATIOS);
-	dev_priv->saveBLC_PWM_CTL = PSB_RVDC32(BLC_PWM_CTL);
-	dev_priv->saveBLC_PWM_CTL2 = PSB_RVDC32(BLC_PWM_CTL2);
-	dev_priv->saveLVDS = PSB_RVDC32(LVDS);
-	dev_priv->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
-	dev_priv->savePP_ON_DELAYS = PSB_RVDC32(LVDSPP_ON);
-	dev_priv->savePP_OFF_DELAYS = PSB_RVDC32(LVDSPP_OFF);
-	dev_priv->savePP_DIVISOR = PSB_RVDC32(PP_CYCLE);
+	regs->psb.savePP_CONTROL = PSB_RVDC32(PP_CONTROL);
+	regs->psb.savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
+	regs->psb.savePFIT_AUTO_RATIOS = PSB_RVDC32(PFIT_AUTO_RATIOS);
+	regs->saveBLC_PWM_CTL = PSB_RVDC32(BLC_PWM_CTL);
+	regs->saveBLC_PWM_CTL2 = PSB_RVDC32(BLC_PWM_CTL2);
+	regs->psb.saveLVDS = PSB_RVDC32(LVDS);
+	regs->psb.savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
+	regs->psb.savePP_ON_DELAYS = PSB_RVDC32(LVDSPP_ON);
+	regs->psb.savePP_OFF_DELAYS = PSB_RVDC32(LVDSPP_OFF);
+	regs->psb.savePP_DIVISOR = PSB_RVDC32(PP_CYCLE);
 
 	/* HW overlay */
-	dev_priv->saveOV_OVADD = PSB_RVDC32(OV_OVADD);
-	dev_priv->saveOV_OGAMC0 = PSB_RVDC32(OV_OGAMC0);
-	dev_priv->saveOV_OGAMC1 = PSB_RVDC32(OV_OGAMC1);
-	dev_priv->saveOV_OGAMC2 = PSB_RVDC32(OV_OGAMC2);
-	dev_priv->saveOV_OGAMC3 = PSB_RVDC32(OV_OGAMC3);
-	dev_priv->saveOV_OGAMC4 = PSB_RVDC32(OV_OGAMC4);
-	dev_priv->saveOV_OGAMC5 = PSB_RVDC32(OV_OGAMC5);
+	regs->psb.saveOV_OVADD = PSB_RVDC32(OV_OVADD);
+	regs->psb.saveOV_OGAMC0 = PSB_RVDC32(OV_OGAMC0);
+	regs->psb.saveOV_OGAMC1 = PSB_RVDC32(OV_OGAMC1);
+	regs->psb.saveOV_OGAMC2 = PSB_RVDC32(OV_OGAMC2);
+	regs->psb.saveOV_OGAMC3 = PSB_RVDC32(OV_OGAMC3);
+	regs->psb.saveOV_OGAMC4 = PSB_RVDC32(OV_OGAMC4);
+	regs->psb.saveOV_OGAMC5 = PSB_RVDC32(OV_OGAMC5);
 
 	/* DPST registers */
-	dev_priv->saveHISTOGRAM_INT_CONTROL_REG =
+	regs->psb.saveHISTOGRAM_INT_CONTROL_REG =
 					PSB_RVDC32(HISTOGRAM_INT_CONTROL);
-	dev_priv->saveHISTOGRAM_LOGIC_CONTROL_REG =
+	regs->psb.saveHISTOGRAM_LOGIC_CONTROL_REG =
 					PSB_RVDC32(HISTOGRAM_LOGIC_CONTROL);
-	dev_priv->savePWM_CONTROL_LOGIC = PSB_RVDC32(PWM_CONTROL_LOGIC);
+	regs->psb.savePWM_CONTROL_LOGIC = PSB_RVDC32(PWM_CONTROL_LOGIC);
 
 	if (dev_priv->iLVDS_enable) {
 		/* Shut down the panel */
@@ -302,79 +299,80 @@
 static int oaktrail_restore_display_registers(struct drm_device *dev)
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
+	struct psb_save_area *regs = &dev_priv->regs;
 	u32 pp_stat;
 	int i;
 
 	/* Display arbitration + watermarks */
-	PSB_WVDC32(dev_priv->saveDSPARB, DSPARB);
-	PSB_WVDC32(dev_priv->saveDSPFW1, DSPFW1);
-	PSB_WVDC32(dev_priv->saveDSPFW2, DSPFW2);
-	PSB_WVDC32(dev_priv->saveDSPFW3, DSPFW3);
-	PSB_WVDC32(dev_priv->saveDSPFW4, DSPFW4);
-	PSB_WVDC32(dev_priv->saveDSPFW5, DSPFW5);
-	PSB_WVDC32(dev_priv->saveDSPFW6, DSPFW6);
-	PSB_WVDC32(dev_priv->saveCHICKENBIT, DSPCHICKENBIT);
+	PSB_WVDC32(regs->psb.saveDSPARB, DSPARB);
+	PSB_WVDC32(regs->psb.saveDSPFW1, DSPFW1);
+	PSB_WVDC32(regs->psb.saveDSPFW2, DSPFW2);
+	PSB_WVDC32(regs->psb.saveDSPFW3, DSPFW3);
+	PSB_WVDC32(regs->psb.saveDSPFW4, DSPFW4);
+	PSB_WVDC32(regs->psb.saveDSPFW5, DSPFW5);
+	PSB_WVDC32(regs->psb.saveDSPFW6, DSPFW6);
+	PSB_WVDC32(regs->psb.saveCHICKENBIT, DSPCHICKENBIT);
 
 	/* Make sure VGA plane is off. it initializes to on after reset!*/
 	PSB_WVDC32(0x80000000, VGACNTRL);
 
 	/* set the plls */
-	PSB_WVDC32(dev_priv->saveFPA0, MRST_FPA0);
-	PSB_WVDC32(dev_priv->saveFPA1, MRST_FPA1);
+	PSB_WVDC32(regs->psb.saveFPA0, MRST_FPA0);
+	PSB_WVDC32(regs->psb.saveFPA1, MRST_FPA1);
 
 	/* Actually enable it */
-	PSB_WVDC32(dev_priv->saveDPLL_A, MRST_DPLL_A);
+	PSB_WVDC32(regs->psb.saveDPLL_A, MRST_DPLL_A);
 	DRM_UDELAY(150);
 
 	/* Restore mode */
-	PSB_WVDC32(dev_priv->saveHTOTAL_A, HTOTAL_A);
-	PSB_WVDC32(dev_priv->saveHBLANK_A, HBLANK_A);
-	PSB_WVDC32(dev_priv->saveHSYNC_A, HSYNC_A);
-	PSB_WVDC32(dev_priv->saveVTOTAL_A, VTOTAL_A);
-	PSB_WVDC32(dev_priv->saveVBLANK_A, VBLANK_A);
-	PSB_WVDC32(dev_priv->saveVSYNC_A, VSYNC_A);
-	PSB_WVDC32(dev_priv->savePIPEASRC, PIPEASRC);
-	PSB_WVDC32(dev_priv->saveBCLRPAT_A, BCLRPAT_A);
+	PSB_WVDC32(regs->psb.saveHTOTAL_A, HTOTAL_A);
+	PSB_WVDC32(regs->psb.saveHBLANK_A, HBLANK_A);
+	PSB_WVDC32(regs->psb.saveHSYNC_A, HSYNC_A);
+	PSB_WVDC32(regs->psb.saveVTOTAL_A, VTOTAL_A);
+	PSB_WVDC32(regs->psb.saveVBLANK_A, VBLANK_A);
+	PSB_WVDC32(regs->psb.saveVSYNC_A, VSYNC_A);
+	PSB_WVDC32(regs->psb.savePIPEASRC, PIPEASRC);
+	PSB_WVDC32(regs->psb.saveBCLRPAT_A, BCLRPAT_A);
 
 	/* Restore performance mode*/
-	PSB_WVDC32(dev_priv->savePERF_MODE, MRST_PERF_MODE);
+	PSB_WVDC32(regs->psb.savePERF_MODE, MRST_PERF_MODE);
 
 	/* Enable the pipe*/
 	if (dev_priv->iLVDS_enable)
-		PSB_WVDC32(dev_priv->savePIPEACONF, PIPEACONF);
+		PSB_WVDC32(regs->psb.savePIPEACONF, PIPEACONF);
 
 	/* Set up the plane*/
-	PSB_WVDC32(dev_priv->saveDSPALINOFF, DSPALINOFF);
-	PSB_WVDC32(dev_priv->saveDSPASTRIDE, DSPASTRIDE);
-	PSB_WVDC32(dev_priv->saveDSPATILEOFF, DSPATILEOFF);
+	PSB_WVDC32(regs->psb.saveDSPALINOFF, DSPALINOFF);
+	PSB_WVDC32(regs->psb.saveDSPASTRIDE, DSPASTRIDE);
+	PSB_WVDC32(regs->psb.saveDSPATILEOFF, DSPATILEOFF);
 
 	/* Enable the plane */
-	PSB_WVDC32(dev_priv->saveDSPACNTR, DSPACNTR);
-	PSB_WVDC32(dev_priv->saveDSPASURF, DSPASURF);
+	PSB_WVDC32(regs->psb.saveDSPACNTR, DSPACNTR);
+	PSB_WVDC32(regs->psb.saveDSPASURF, DSPASURF);
 
 	/* Enable Cursor A */
-	PSB_WVDC32(dev_priv->saveDSPACURSOR_CTRL, CURACNTR);
-	PSB_WVDC32(dev_priv->saveDSPACURSOR_POS, CURAPOS);
-	PSB_WVDC32(dev_priv->saveDSPACURSOR_BASE, CURABASE);
+	PSB_WVDC32(regs->psb.saveDSPACURSOR_CTRL, CURACNTR);
+	PSB_WVDC32(regs->psb.saveDSPACURSOR_POS, CURAPOS);
+	PSB_WVDC32(regs->psb.saveDSPACURSOR_BASE, CURABASE);
 
 	/* Restore palette (gamma) */
 	for (i = 0; i < 256; i++)
-		PSB_WVDC32(dev_priv->save_palette_a[i], PALETTE_A + (i << 2));
+		PSB_WVDC32(regs->psb.save_palette_a[i], PALETTE_A + (i << 2));
 
 	if (dev_priv->hdmi_priv)
 		oaktrail_hdmi_restore(dev);
 
 	if (dev_priv->iLVDS_enable) {
-		PSB_WVDC32(dev_priv->saveBLC_PWM_CTL2, BLC_PWM_CTL2);
-		PSB_WVDC32(dev_priv->saveLVDS, LVDS); /*port 61180h*/
-		PSB_WVDC32(dev_priv->savePFIT_CONTROL, PFIT_CONTROL);
-		PSB_WVDC32(dev_priv->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
-		PSB_WVDC32(dev_priv->savePFIT_AUTO_RATIOS, PFIT_AUTO_RATIOS);
-		PSB_WVDC32(dev_priv->saveBLC_PWM_CTL, BLC_PWM_CTL);
-		PSB_WVDC32(dev_priv->savePP_ON_DELAYS, LVDSPP_ON);
-		PSB_WVDC32(dev_priv->savePP_OFF_DELAYS, LVDSPP_OFF);
-		PSB_WVDC32(dev_priv->savePP_DIVISOR, PP_CYCLE);
-		PSB_WVDC32(dev_priv->savePP_CONTROL, PP_CONTROL);
+		PSB_WVDC32(regs->saveBLC_PWM_CTL2, BLC_PWM_CTL2);
+		PSB_WVDC32(regs->psb.saveLVDS, LVDS); /*port 61180h*/
+		PSB_WVDC32(regs->psb.savePFIT_CONTROL, PFIT_CONTROL);
+		PSB_WVDC32(regs->psb.savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
+		PSB_WVDC32(regs->psb.savePFIT_AUTO_RATIOS, PFIT_AUTO_RATIOS);
+		PSB_WVDC32(regs->saveBLC_PWM_CTL, BLC_PWM_CTL);
+		PSB_WVDC32(regs->psb.savePP_ON_DELAYS, LVDSPP_ON);
+		PSB_WVDC32(regs->psb.savePP_OFF_DELAYS, LVDSPP_OFF);
+		PSB_WVDC32(regs->psb.savePP_DIVISOR, PP_CYCLE);
+		PSB_WVDC32(regs->psb.savePP_CONTROL, PP_CONTROL);
 	}
 
 	/* Wait for cycle delay */
@@ -388,20 +386,20 @@
 	} while (pp_stat & 0x10000000);
 
 	/* Restore HW overlay */
-	PSB_WVDC32(dev_priv->saveOV_OVADD, OV_OVADD);
-	PSB_WVDC32(dev_priv->saveOV_OGAMC0, OV_OGAMC0);
-	PSB_WVDC32(dev_priv->saveOV_OGAMC1, OV_OGAMC1);
-	PSB_WVDC32(dev_priv->saveOV_OGAMC2, OV_OGAMC2);
-	PSB_WVDC32(dev_priv->saveOV_OGAMC3, OV_OGAMC3);
-	PSB_WVDC32(dev_priv->saveOV_OGAMC4, OV_OGAMC4);
-	PSB_WVDC32(dev_priv->saveOV_OGAMC5, OV_OGAMC5);
+	PSB_WVDC32(regs->psb.saveOV_OVADD, OV_OVADD);
+	PSB_WVDC32(regs->psb.saveOV_OGAMC0, OV_OGAMC0);
+	PSB_WVDC32(regs->psb.saveOV_OGAMC1, OV_OGAMC1);
+	PSB_WVDC32(regs->psb.saveOV_OGAMC2, OV_OGAMC2);
+	PSB_WVDC32(regs->psb.saveOV_OGAMC3, OV_OGAMC3);
+	PSB_WVDC32(regs->psb.saveOV_OGAMC4, OV_OGAMC4);
+	PSB_WVDC32(regs->psb.saveOV_OGAMC5, OV_OGAMC5);
 
 	/* DPST registers */
-	PSB_WVDC32(dev_priv->saveHISTOGRAM_INT_CONTROL_REG,
+	PSB_WVDC32(regs->psb.saveHISTOGRAM_INT_CONTROL_REG,
 						HISTOGRAM_INT_CONTROL);
-	PSB_WVDC32(dev_priv->saveHISTOGRAM_LOGIC_CONTROL_REG,
+	PSB_WVDC32(regs->psb.saveHISTOGRAM_LOGIC_CONTROL_REG,
 						HISTOGRAM_LOGIC_CONTROL);
-	PSB_WVDC32(dev_priv->savePWM_CONTROL_LOGIC, PWM_CONTROL_LOGIC);
+	PSB_WVDC32(regs->psb.savePWM_CONTROL_LOGIC, PWM_CONTROL_LOGIC);
 
 	return 0;
 }
@@ -502,7 +500,6 @@
 	.backlight_init = oaktrail_backlight_init,
 #endif
 
-	.init_pm = oaktrail_init_pm,
 	.save_regs = oaktrail_save_display_registers,
 	.restore_regs = oaktrail_restore_display_registers,
 	.power_down = oaktrail_power_down,
diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
index 025d309..f8b367b 100644
--- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c
+++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
@@ -125,59 +125,6 @@
 	.nf  = { .min = NF_MIN,			.max = NF_MAX  },
 };
 
-static void wait_for_vblank(struct drm_device *dev)
-{
-	/* FIXME: Can we do this as a sleep ? */
-	/* Wait for 20ms, i.e. one cycle at 50hz. */
-	mdelay(20);
-}
-
-static void scu_busy_loop(void *scu_base)
-{
-	u32 status = 0;
-	u32 loop_count = 0;
-
-	status = readl(scu_base + 0x04);
-	while (status & 1) {
-		udelay(1); /* scu processing time is in few u secods */
-		status = readl(scu_base + 0x04);
-		loop_count++;
-		/* break if scu doesn't reset busy bit after huge retry */
-		if (loop_count > 1000) {
-			DRM_DEBUG_KMS("SCU IPC timed out");
-			return;
-		}
-	}
-}
-
-static void oaktrail_hdmi_reset(struct drm_device *dev)
-{
-	void *base;
-	/* FIXME: at least make these defines */
-	unsigned int scu_ipc_mmio = 0xff11c000;
-	int scu_len = 1024;
-
-	base = ioremap((resource_size_t)scu_ipc_mmio, scu_len);
-	if (base == NULL) {
-		DRM_ERROR("failed to map SCU mmio\n");
-		return;
-	}
-
-	/* scu ipc: assert hdmi controller reset */
-	writel(0xff11d118, base + 0x0c);
-	writel(0x7fffffdf, base + 0x80);
-	writel(0x42005, base + 0x0);
-	scu_busy_loop(base);
-
-	/* scu ipc: de-assert hdmi controller reset */
-	writel(0xff11d118, base + 0x0c);
-	writel(0x7fffffff, base + 0x80);
-	writel(0x42005, base + 0x0);
-	scu_busy_loop(base);
-
-	iounmap(base);
-}
-
 static void oaktrail_hdmi_audio_enable(struct drm_device *dev)
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
@@ -208,104 +155,6 @@
 	HDMI_READ(HDMI_HCR);
 }
 
-void oaktrail_crtc_hdmi_dpms(struct drm_crtc *crtc, int mode)
-{
-	struct drm_device *dev = crtc->dev;
-	u32 temp;
-
-	switch (mode) {
-	case DRM_MODE_DPMS_OFF:
-		/* Disable VGACNTRL */
-		REG_WRITE(VGACNTRL, 0x80000000);
-
-		/* Disable plane */
-		temp = REG_READ(DSPBCNTR);
-		if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
-			REG_WRITE(DSPBCNTR, temp & ~DISPLAY_PLANE_ENABLE);
-			REG_READ(DSPBCNTR);
-			/* Flush the plane changes */
-			REG_WRITE(DSPBSURF, REG_READ(DSPBSURF));
-			REG_READ(DSPBSURF);
-		}
-
-		/* Disable pipe B */
-		temp = REG_READ(PIPEBCONF);
-		if ((temp & PIPEACONF_ENABLE) != 0) {
-			REG_WRITE(PIPEBCONF, temp & ~PIPEACONF_ENABLE);
-			REG_READ(PIPEBCONF);
-		}
-
-		/* Disable LNW Pipes, etc */
-		temp = REG_READ(PCH_PIPEBCONF);
-		if ((temp & PIPEACONF_ENABLE) != 0) {
-			REG_WRITE(PCH_PIPEBCONF, temp & ~PIPEACONF_ENABLE);
-			REG_READ(PCH_PIPEBCONF);
-		}
-		/* wait for pipe off */
-		udelay(150);
-		/* Disable dpll */
-		temp = REG_READ(DPLL_CTRL);
-		if ((temp & DPLL_PWRDN) == 0) {
-			REG_WRITE(DPLL_CTRL, temp | (DPLL_PWRDN | DPLL_RESET));
-			REG_WRITE(DPLL_STATUS, 0x1);
-		}
-		/* wait for dpll off */
-		udelay(150);
-		break;
-	case DRM_MODE_DPMS_ON:
-	case DRM_MODE_DPMS_STANDBY:
-	case DRM_MODE_DPMS_SUSPEND:
-		/* Enable dpll */
-		temp = REG_READ(DPLL_CTRL);
-		if ((temp & DPLL_PWRDN) != 0) {
-			REG_WRITE(DPLL_CTRL, temp & ~(DPLL_PWRDN | DPLL_RESET));
-			temp = REG_READ(DPLL_CLK_ENABLE);
-			REG_WRITE(DPLL_CLK_ENABLE, temp | DPLL_EN_DISP | DPLL_SEL_HDMI | DPLL_EN_HDMI);
-			REG_READ(DPLL_CLK_ENABLE);
-		}
-		/* wait for dpll warm up */
-		udelay(150);
-
-		/* Enable pipe B */
-		temp = REG_READ(PIPEBCONF);
-		if ((temp & PIPEACONF_ENABLE) == 0) {
-			REG_WRITE(PIPEBCONF, temp | PIPEACONF_ENABLE);
-			REG_READ(PIPEBCONF);
-		}
-
-		/* Enable LNW Pipe B */
-		temp = REG_READ(PCH_PIPEBCONF);
-		if ((temp & PIPEACONF_ENABLE) == 0) {
-			REG_WRITE(PCH_PIPEBCONF, temp | PIPEACONF_ENABLE);
-			REG_READ(PCH_PIPEBCONF);
-		}
-		wait_for_vblank(dev);
-
-		/* Enable plane */
-		temp = REG_READ(DSPBCNTR);
-		if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
-			REG_WRITE(DSPBCNTR, temp | DISPLAY_PLANE_ENABLE);
-			/* Flush the plane changes */
-			REG_WRITE(DSPBSURF, REG_READ(DSPBSURF));
-			REG_READ(DSPBSURF);
-		}
-		psb_intel_crtc_load_lut(crtc);
-	}
-	/* DSPARB */
-	REG_WRITE(DSPARB, 0x00003fbf);
-	/* FW1 */
-	REG_WRITE(0x70034, 0x3f880a0a);
-	/* FW2 */
-	REG_WRITE(0x70038, 0x0b060808);
-	/* FW4 */
-	REG_WRITE(0x70050, 0x08030404);
-	/* FW5 */
-	REG_WRITE(0x70054, 0x04040404);
-	/* LNC Chicken Bits */
-	REG_WRITE(0x70400, 0x4000);
-}
-
-
 static void oaktrail_hdmi_dpms(struct drm_encoder *encoder, int mode)
 {
 	static int dpms_mode = -1;
@@ -327,182 +176,6 @@
 	HDMI_WRITE(HDMI_VIDEO_REG, temp);
 }
 
-static unsigned int htotal_calculate(struct drm_display_mode *mode)
-{
-	u32 htotal, new_crtc_htotal;
-
-	htotal = (mode->crtc_hdisplay - 1) | ((mode->crtc_htotal - 1) << 16);
-
-	/*
-	 * 1024 x 768  new_crtc_htotal = 0x1024;
-	 * 1280 x 1024 new_crtc_htotal = 0x0c34;
-	 */
-	new_crtc_htotal = (mode->crtc_htotal - 1) * 200 * 1000 / mode->clock;
-
-	return (mode->crtc_hdisplay - 1) | (new_crtc_htotal << 16);
-}
-
-static void oaktrail_hdmi_find_dpll(struct drm_crtc *crtc, int target,
-				int refclk, struct oaktrail_hdmi_clock *best_clock)
-{
-	int np_min, np_max, nr_min, nr_max;
-	int np, nr, nf;
-
-	np_min = DIV_ROUND_UP(oaktrail_hdmi_limit.vco.min, target * 10);
-	np_max = oaktrail_hdmi_limit.vco.max / (target * 10);
-	if (np_min < oaktrail_hdmi_limit.np.min)
-		np_min = oaktrail_hdmi_limit.np.min;
-	if (np_max > oaktrail_hdmi_limit.np.max)
-		np_max = oaktrail_hdmi_limit.np.max;
-
-	nr_min = DIV_ROUND_UP((refclk * 1000), (target * 10 * np_max));
-	nr_max = DIV_ROUND_UP((refclk * 1000), (target * 10 * np_min));
-	if (nr_min < oaktrail_hdmi_limit.nr.min)
-		nr_min = oaktrail_hdmi_limit.nr.min;
-	if (nr_max > oaktrail_hdmi_limit.nr.max)
-		nr_max = oaktrail_hdmi_limit.nr.max;
-
-	np = DIV_ROUND_UP((refclk * 1000), (target * 10 * nr_max));
-	nr = DIV_ROUND_UP((refclk * 1000), (target * 10 * np));
-	nf = DIV_ROUND_CLOSEST((target * 10 * np * nr), refclk);
-	DRM_DEBUG_KMS("np, nr, nf %d %d %d\n", np, nr, nf);
-
-	/*
-	 * 1024 x 768  np = 1; nr = 0x26; nf = 0x0fd8000;
-	 * 1280 x 1024 np = 1; nr = 0x17; nf = 0x1034000;
-	 */
-	best_clock->np = np;
-	best_clock->nr = nr - 1;
-	best_clock->nf = (nf << 14);
-}
-
-int oaktrail_crtc_hdmi_mode_set(struct drm_crtc *crtc,
-			    struct drm_display_mode *mode,
-			    struct drm_display_mode *adjusted_mode,
-			    int x, int y,
-			    struct drm_framebuffer *old_fb)
-{
-	struct drm_device *dev = crtc->dev;
-	struct drm_psb_private *dev_priv = dev->dev_private;
-	struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
-	int pipe = 1;
-	int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
-	int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
-	int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
-	int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
-	int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
-	int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
-	int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
-	int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
-	int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
-	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-	int refclk;
-	struct oaktrail_hdmi_clock clock;
-	u32 dspcntr, pipeconf, dpll, temp;
-	int dspcntr_reg = DSPBCNTR;
-
-	/* Disable the VGA plane that we never use */
-	REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
-
-	/* XXX: Disable the panel fitter if it was on our pipe */
-
-	/* Disable dpll if necessary */
-	dpll = REG_READ(DPLL_CTRL);
-	if ((dpll & DPLL_PWRDN) == 0) {
-		REG_WRITE(DPLL_CTRL, dpll | (DPLL_PWRDN | DPLL_RESET));
-		REG_WRITE(DPLL_DIV_CTRL, 0x00000000);
-		REG_WRITE(DPLL_STATUS, 0x1);
-	}
-	udelay(150);
-
-	/* reset controller: FIXME - can we sort out the ioremap mess ? */
-	iounmap(hdmi_dev->regs);
-	oaktrail_hdmi_reset(dev);
-
-	/* program and enable dpll */
-	refclk = 25000;
-	oaktrail_hdmi_find_dpll(crtc, adjusted_mode->clock, refclk, &clock);
-
-	/* Setting DPLL */
-	dpll = REG_READ(DPLL_CTRL);
-	dpll &= ~DPLL_PDIV_MASK;
-	dpll &= ~(DPLL_PWRDN | DPLL_RESET);
-	REG_WRITE(DPLL_CTRL, 0x00000008);
-	REG_WRITE(DPLL_DIV_CTRL, ((clock.nf << 6) | clock.nr));
-	REG_WRITE(DPLL_ADJUST, ((clock.nf >> 14) - 1));
-	REG_WRITE(DPLL_CTRL, (dpll | (clock.np << DPLL_PDIV_SHIFT) | DPLL_ENSTAT | DPLL_DITHEN));
-	REG_WRITE(DPLL_UPDATE, 0x80000000);
-	REG_WRITE(DPLL_CLK_ENABLE, 0x80050102);
-	udelay(150);
-
-	hdmi_dev->regs = ioremap(hdmi_dev->mmio, hdmi_dev->mmio_len);
-	if (hdmi_dev->regs == NULL) {
-		DRM_ERROR("failed to do hdmi mmio mapping\n");
-		return -ENOMEM;
-	}
-
-	/* configure HDMI */
-	HDMI_WRITE(0x1004, 0x1fd);
-	HDMI_WRITE(0x2000, 0x1);
-	HDMI_WRITE(0x2008, 0x0);
-	HDMI_WRITE(0x3130, 0x8);
-	HDMI_WRITE(0x101c, 0x1800810);
-
-	temp = htotal_calculate(adjusted_mode);
-	REG_WRITE(htot_reg, temp);
-	REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | ((adjusted_mode->crtc_hblank_end - 1) << 16));
-	REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | ((adjusted_mode->crtc_hsync_end - 1) << 16));
-	REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | ((adjusted_mode->crtc_vtotal - 1) << 16));
-	REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | ((adjusted_mode->crtc_vblank_end - 1) << 16));
-	REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16));
-	REG_WRITE(pipesrc_reg,
-		((mode->crtc_hdisplay - 1) << 16) |  (mode->crtc_vdisplay - 1));
-
-	REG_WRITE(PCH_HTOTAL_B, (adjusted_mode->crtc_hdisplay - 1) | ((adjusted_mode->crtc_htotal - 1) << 16));
-	REG_WRITE(PCH_HBLANK_B, (adjusted_mode->crtc_hblank_start - 1) | ((adjusted_mode->crtc_hblank_end - 1) << 16));
-	REG_WRITE(PCH_HSYNC_B, (adjusted_mode->crtc_hsync_start - 1) | ((adjusted_mode->crtc_hsync_end - 1) << 16));
-	REG_WRITE(PCH_VTOTAL_B, (adjusted_mode->crtc_vdisplay - 1) | ((adjusted_mode->crtc_vtotal - 1) << 16));
-	REG_WRITE(PCH_VBLANK_B, (adjusted_mode->crtc_vblank_start - 1) | ((adjusted_mode->crtc_vblank_end - 1) << 16));
-	REG_WRITE(PCH_VSYNC_B, (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16));
-	REG_WRITE(PCH_PIPEBSRC,
-		((mode->crtc_hdisplay - 1) << 16) |  (mode->crtc_vdisplay - 1));
-
-	temp = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start;
-	HDMI_WRITE(HDMI_HBLANK_A, ((adjusted_mode->crtc_hdisplay - 1) << 16) |  temp);
-
-	REG_WRITE(dspsize_reg,
-			((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
-	REG_WRITE(dsppos_reg, 0);
-
-	/* Flush the plane changes */
-	{
-		struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-		crtc_funcs->mode_set_base(crtc, x, y, old_fb);
-	}
-
-	/* Set up the display plane register */
-	dspcntr = REG_READ(dspcntr_reg);
-	dspcntr |= DISPPLANE_GAMMA_ENABLE;
-	dspcntr |= DISPPLANE_SEL_PIPE_B;
-	dspcntr |= DISPLAY_PLANE_ENABLE;
-
-	/* setup pipeconf */
-	pipeconf = REG_READ(pipeconf_reg);
-	pipeconf |= PIPEACONF_ENABLE;
-
-	REG_WRITE(pipeconf_reg, pipeconf);
-	REG_READ(pipeconf_reg);
-
-	REG_WRITE(PCH_PIPEBCONF, pipeconf);
-	REG_READ(PCH_PIPEBCONF);
-	wait_for_vblank(dev);
-
-	REG_WRITE(dspcntr_reg, dspcntr);
-	wait_for_vblank(dev);
-
-	return 0;
-}
-
 static int oaktrail_hdmi_mode_valid(struct drm_connector *connector,
 				struct drm_display_mode *mode)
 {
@@ -692,7 +365,7 @@
 
 static DEFINE_PCI_DEVICE_TABLE(hdmi_ids) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080d) },
-	{}
+	{ 0 }
 };
 
 void oaktrail_hdmi_setup(struct drm_device *dev)
@@ -766,6 +439,7 @@
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
+	struct psb_state *regs = &dev_priv->regs.psb;
 	int i;
 
 	/* dpll */
@@ -776,14 +450,14 @@
 	hdmi_dev->saveDPLL_CLK_ENABLE = PSB_RVDC32(DPLL_CLK_ENABLE);
 
 	/* pipe B */
-	dev_priv->savePIPEBCONF = PSB_RVDC32(PIPEBCONF);
-	dev_priv->savePIPEBSRC  = PSB_RVDC32(PIPEBSRC);
-	dev_priv->saveHTOTAL_B  = PSB_RVDC32(HTOTAL_B);
-	dev_priv->saveHBLANK_B  = PSB_RVDC32(HBLANK_B);
-	dev_priv->saveHSYNC_B   = PSB_RVDC32(HSYNC_B);
-	dev_priv->saveVTOTAL_B  = PSB_RVDC32(VTOTAL_B);
-	dev_priv->saveVBLANK_B  = PSB_RVDC32(VBLANK_B);
-	dev_priv->saveVSYNC_B   = PSB_RVDC32(VSYNC_B);
+	regs->savePIPEBCONF = PSB_RVDC32(PIPEBCONF);
+	regs->savePIPEBSRC  = PSB_RVDC32(PIPEBSRC);
+	regs->saveHTOTAL_B  = PSB_RVDC32(HTOTAL_B);
+	regs->saveHBLANK_B  = PSB_RVDC32(HBLANK_B);
+	regs->saveHSYNC_B   = PSB_RVDC32(HSYNC_B);
+	regs->saveVTOTAL_B  = PSB_RVDC32(VTOTAL_B);
+	regs->saveVBLANK_B  = PSB_RVDC32(VBLANK_B);
+	regs->saveVSYNC_B   = PSB_RVDC32(VSYNC_B);
 
 	hdmi_dev->savePCH_PIPEBCONF = PSB_RVDC32(PCH_PIPEBCONF);
 	hdmi_dev->savePCH_PIPEBSRC = PSB_RVDC32(PCH_PIPEBSRC);
@@ -795,21 +469,21 @@
 	hdmi_dev->savePCH_VSYNC_B  = PSB_RVDC32(PCH_VSYNC_B);
 
 	/* plane */
-	dev_priv->saveDSPBCNTR = PSB_RVDC32(DSPBCNTR);
-	dev_priv->saveDSPBSTRIDE = PSB_RVDC32(DSPBSTRIDE);
-	dev_priv->saveDSPBADDR = PSB_RVDC32(DSPBBASE);
-	dev_priv->saveDSPBSURF = PSB_RVDC32(DSPBSURF);
-	dev_priv->saveDSPBLINOFF = PSB_RVDC32(DSPBLINOFF);
-	dev_priv->saveDSPBTILEOFF = PSB_RVDC32(DSPBTILEOFF);
+	regs->saveDSPBCNTR = PSB_RVDC32(DSPBCNTR);
+	regs->saveDSPBSTRIDE = PSB_RVDC32(DSPBSTRIDE);
+	regs->saveDSPBADDR = PSB_RVDC32(DSPBBASE);
+	regs->saveDSPBSURF = PSB_RVDC32(DSPBSURF);
+	regs->saveDSPBLINOFF = PSB_RVDC32(DSPBLINOFF);
+	regs->saveDSPBTILEOFF = PSB_RVDC32(DSPBTILEOFF);
 
 	/* cursor B */
-	dev_priv->saveDSPBCURSOR_CTRL = PSB_RVDC32(CURBCNTR);
-	dev_priv->saveDSPBCURSOR_BASE = PSB_RVDC32(CURBBASE);
-	dev_priv->saveDSPBCURSOR_POS = PSB_RVDC32(CURBPOS);
+	regs->saveDSPBCURSOR_CTRL = PSB_RVDC32(CURBCNTR);
+	regs->saveDSPBCURSOR_BASE = PSB_RVDC32(CURBBASE);
+	regs->saveDSPBCURSOR_POS = PSB_RVDC32(CURBPOS);
 
 	/* save palette */
 	for (i = 0; i < 256; i++)
-		dev_priv->save_palette_b[i] = PSB_RVDC32(PALETTE_B + (i << 2));
+		regs->save_palette_b[i] = PSB_RVDC32(PALETTE_B + (i << 2));
 }
 
 /* restore HDMI register state */
@@ -817,6 +491,7 @@
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
+	struct psb_state *regs = &dev_priv->regs.psb;
 	int i;
 
 	/* dpll */
@@ -828,13 +503,13 @@
 	DRM_UDELAY(150);
 
 	/* pipe */
-	PSB_WVDC32(dev_priv->savePIPEBSRC, PIPEBSRC);
-	PSB_WVDC32(dev_priv->saveHTOTAL_B, HTOTAL_B);
-	PSB_WVDC32(dev_priv->saveHBLANK_B, HBLANK_B);
-	PSB_WVDC32(dev_priv->saveHSYNC_B,  HSYNC_B);
-	PSB_WVDC32(dev_priv->saveVTOTAL_B, VTOTAL_B);
-	PSB_WVDC32(dev_priv->saveVBLANK_B, VBLANK_B);
-	PSB_WVDC32(dev_priv->saveVSYNC_B,  VSYNC_B);
+	PSB_WVDC32(regs->savePIPEBSRC, PIPEBSRC);
+	PSB_WVDC32(regs->saveHTOTAL_B, HTOTAL_B);
+	PSB_WVDC32(regs->saveHBLANK_B, HBLANK_B);
+	PSB_WVDC32(regs->saveHSYNC_B,  HSYNC_B);
+	PSB_WVDC32(regs->saveVTOTAL_B, VTOTAL_B);
+	PSB_WVDC32(regs->saveVBLANK_B, VBLANK_B);
+	PSB_WVDC32(regs->saveVSYNC_B,  VSYNC_B);
 
 	PSB_WVDC32(hdmi_dev->savePCH_PIPEBSRC, PCH_PIPEBSRC);
 	PSB_WVDC32(hdmi_dev->savePCH_HTOTAL_B, PCH_HTOTAL_B);
@@ -844,22 +519,22 @@
 	PSB_WVDC32(hdmi_dev->savePCH_VBLANK_B, PCH_VBLANK_B);
 	PSB_WVDC32(hdmi_dev->savePCH_VSYNC_B,  PCH_VSYNC_B);
 
-	PSB_WVDC32(dev_priv->savePIPEBCONF, PIPEBCONF);
+	PSB_WVDC32(regs->savePIPEBCONF, PIPEBCONF);
 	PSB_WVDC32(hdmi_dev->savePCH_PIPEBCONF, PCH_PIPEBCONF);
 
 	/* plane */
-	PSB_WVDC32(dev_priv->saveDSPBLINOFF, DSPBLINOFF);
-	PSB_WVDC32(dev_priv->saveDSPBSTRIDE, DSPBSTRIDE);
-	PSB_WVDC32(dev_priv->saveDSPBTILEOFF, DSPBTILEOFF);
-	PSB_WVDC32(dev_priv->saveDSPBCNTR, DSPBCNTR);
-	PSB_WVDC32(dev_priv->saveDSPBSURF, DSPBSURF);
+	PSB_WVDC32(regs->saveDSPBLINOFF, DSPBLINOFF);
+	PSB_WVDC32(regs->saveDSPBSTRIDE, DSPBSTRIDE);
+	PSB_WVDC32(regs->saveDSPBTILEOFF, DSPBTILEOFF);
+	PSB_WVDC32(regs->saveDSPBCNTR, DSPBCNTR);
+	PSB_WVDC32(regs->saveDSPBSURF, DSPBSURF);
 
 	/* cursor B */
-	PSB_WVDC32(dev_priv->saveDSPBCURSOR_CTRL, CURBCNTR);
-	PSB_WVDC32(dev_priv->saveDSPBCURSOR_POS, CURBPOS);
-	PSB_WVDC32(dev_priv->saveDSPBCURSOR_BASE, CURBBASE);
+	PSB_WVDC32(regs->saveDSPBCURSOR_CTRL, CURBCNTR);
+	PSB_WVDC32(regs->saveDSPBCURSOR_POS, CURBPOS);
+	PSB_WVDC32(regs->saveDSPBCURSOR_BASE, CURBBASE);
 
 	/* restore palette */
 	for (i = 0; i < 256; i++)
-		PSB_WVDC32(dev_priv->save_palette_b[i], PALETTE_B + (i << 2));
+		PSB_WVDC32(regs->save_palette_b[i], PALETTE_B + (i << 2));
 }
diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c
index 7054408..5e84fbd 100644
--- a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c
+++ b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c
@@ -127,7 +127,7 @@
 {
 	struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap);
 	struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
-	int i, err = 0;
+	int i;
 
 	mutex_lock(&i2c_dev->i2c_lock);
 
@@ -139,9 +139,9 @@
 	for (i = 0; i < num; i++) {
 		if (pmsg->len && pmsg->buf) {
 			if (pmsg->flags & I2C_M_RD)
-				err = xfer_read(adap, pmsg);
+				xfer_read(adap, pmsg);
 			else
-				err = xfer_write(adap, pmsg);
+				xfer_write(adap, pmsg);
 		}
 		pmsg++;         /* next message */
 	}
diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c
index 238bbe1..654f32b 100644
--- a/drivers/gpu/drm/gma500/oaktrail_lvds.c
+++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c
@@ -192,7 +192,7 @@
 
 		gma_power_end(dev);
 	} else
-		ret = ((dev_priv->saveBLC_PWM_CTL &
+		ret = ((dev_priv->regs.saveBLC_PWM_CTL &
 			  BACKLIGHT_MODULATION_FREQ_MASK) >>
 			  BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
 
@@ -331,7 +331,6 @@
 	struct drm_encoder *encoder;
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	struct edid *edid;
-	int ret = 0;
 	struct i2c_adapter *i2c_adap;
 	struct drm_display_mode *scan;	/* *modes, *bios_mode; */
 
@@ -400,7 +399,7 @@
 		if (edid) {
 			drm_mode_connector_update_edid_property(connector,
 									edid);
-			ret = drm_add_edid_modes(connector, edid);
+			drm_add_edid_modes(connector, edid);
 			kfree(edid);
 		}
 
diff --git a/drivers/gpu/drm/gma500/power.c b/drivers/gpu/drm/gma500/power.c
index 9402569..889b854 100644
--- a/drivers/gpu/drm/gma500/power.c
+++ b/drivers/gpu/drm/gma500/power.c
@@ -58,7 +58,8 @@
 	spin_lock_init(&power_ctrl_lock);
 	mutex_init(&power_mutex);
 
-	dev_priv->ops->init_pm(dev);
+	if (dev_priv->ops->init_pm)
+		dev_priv->ops->init_pm(dev);
 }
 
 /**
@@ -101,9 +102,6 @@
 	struct drm_device *dev = pci_get_drvdata(pdev);
 	struct drm_psb_private *dev_priv = dev->dev_private;
 
-	if (dev_priv->suspended == false)
-		return;
-
 	/* turn on the display power island */
 	dev_priv->ops->power_up(dev);
 	dev_priv->suspended = false;
@@ -132,9 +130,9 @@
 
 	pci_save_state(pdev);
 	pci_read_config_dword(pdev, 0x5C, &bsm);
-	dev_priv->saveBSM = bsm;
+	dev_priv->regs.saveBSM = bsm;
 	pci_read_config_dword(pdev, 0xFC, &vbt);
-	dev_priv->saveVBT = vbt;
+	dev_priv->regs.saveVBT = vbt;
 	pci_read_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, &dev_priv->msi_addr);
 	pci_read_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, &dev_priv->msi_data);
 
@@ -162,8 +160,8 @@
 
 	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
-	pci_write_config_dword(pdev, 0x5c, dev_priv->saveBSM);
-	pci_write_config_dword(pdev, 0xFC, dev_priv->saveVBT);
+	pci_write_config_dword(pdev, 0x5c, dev_priv->regs.saveBSM);
+	pci_write_config_dword(pdev, 0xFC, dev_priv->regs.saveVBT);
 	/* restoring MSI address and data in PCIx space */
 	pci_write_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, dev_priv->msi_addr);
 	pci_write_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, dev_priv->msi_data);
@@ -195,6 +193,7 @@
 	if (!dev_priv->suspended) {
 		if (dev_priv->display_count) {
 			mutex_unlock(&power_mutex);
+			dev_err(dev->dev, "GPU hardware busy, cannot suspend\n");
 			return -EBUSY;
 		}
 		psb_irq_uninstall(dev);
@@ -302,7 +301,7 @@
 
 int psb_runtime_resume(struct device *dev)
 {
-	return gma_power_resume(dev);;
+	return gma_power_resume(dev);
 }
 
 int psb_runtime_idle(struct device *dev)
diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c
index e5f5906..95d163e 100644
--- a/drivers/gpu/drm/gma500/psb_device.c
+++ b/drivers/gpu/drm/gma500/psb_device.c
@@ -177,16 +177,17 @@
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	struct drm_crtc *crtc;
 	struct drm_connector *connector;
+	struct psb_state *regs = &dev_priv->regs.psb;
 
 	/* Display arbitration control + watermarks */
-	dev_priv->saveDSPARB = PSB_RVDC32(DSPARB);
-	dev_priv->saveDSPFW1 = PSB_RVDC32(DSPFW1);
-	dev_priv->saveDSPFW2 = PSB_RVDC32(DSPFW2);
-	dev_priv->saveDSPFW3 = PSB_RVDC32(DSPFW3);
-	dev_priv->saveDSPFW4 = PSB_RVDC32(DSPFW4);
-	dev_priv->saveDSPFW5 = PSB_RVDC32(DSPFW5);
-	dev_priv->saveDSPFW6 = PSB_RVDC32(DSPFW6);
-	dev_priv->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
+	regs->saveDSPARB = PSB_RVDC32(DSPARB);
+	regs->saveDSPFW1 = PSB_RVDC32(DSPFW1);
+	regs->saveDSPFW2 = PSB_RVDC32(DSPFW2);
+	regs->saveDSPFW3 = PSB_RVDC32(DSPFW3);
+	regs->saveDSPFW4 = PSB_RVDC32(DSPFW4);
+	regs->saveDSPFW5 = PSB_RVDC32(DSPFW5);
+	regs->saveDSPFW6 = PSB_RVDC32(DSPFW6);
+	regs->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
 
 	/* Save crtc and output state */
 	mutex_lock(&dev->mode_config.mutex);
@@ -213,16 +214,17 @@
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	struct drm_crtc *crtc;
 	struct drm_connector *connector;
+	struct psb_state *regs = &dev_priv->regs.psb;
 
 	/* Display arbitration + watermarks */
-	PSB_WVDC32(dev_priv->saveDSPARB, DSPARB);
-	PSB_WVDC32(dev_priv->saveDSPFW1, DSPFW1);
-	PSB_WVDC32(dev_priv->saveDSPFW2, DSPFW2);
-	PSB_WVDC32(dev_priv->saveDSPFW3, DSPFW3);
-	PSB_WVDC32(dev_priv->saveDSPFW4, DSPFW4);
-	PSB_WVDC32(dev_priv->saveDSPFW5, DSPFW5);
-	PSB_WVDC32(dev_priv->saveDSPFW6, DSPFW6);
-	PSB_WVDC32(dev_priv->saveCHICKENBIT, DSPCHICKENBIT);
+	PSB_WVDC32(regs->saveDSPARB, DSPARB);
+	PSB_WVDC32(regs->saveDSPFW1, DSPFW1);
+	PSB_WVDC32(regs->saveDSPFW2, DSPFW2);
+	PSB_WVDC32(regs->saveDSPFW3, DSPFW3);
+	PSB_WVDC32(regs->saveDSPFW4, DSPFW4);
+	PSB_WVDC32(regs->saveDSPFW5, DSPFW5);
+	PSB_WVDC32(regs->saveDSPFW6, DSPFW6);
+	PSB_WVDC32(regs->saveCHICKENBIT, DSPCHICKENBIT);
 
 	/*make sure VGA plane is off. it initializes to on after reset!*/
 	PSB_WVDC32(0x80000000, VGACNTRL);
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index f14768f..c34adf9 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -60,6 +60,16 @@
 	/* Atom E620 */
 	{ 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops},
 #endif
+#if defined(CONFIG_DRM_MEDFIELD)
+	{0x8086, 0x0130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+	{0x8086, 0x0131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+	{0x8086, 0x0132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+	{0x8086, 0x0133, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+	{0x8086, 0x0134, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+	{0x8086, 0x0135, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+	{0x8086, 0x0136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+	{0x8086, 0x0137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+#endif
 #if defined(CONFIG_DRM_GMA3600)
 	{ 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
 	{ 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
@@ -70,7 +80,7 @@
 	{ 0x8086, 0x0be6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
 	{ 0x8086, 0x0be7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
 #endif
-	{ 0, 0, 0}
+	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, pciidlist);
 
@@ -78,27 +88,27 @@
  * Standard IOCTLs.
  */
 
-#define DRM_IOCTL_PSB_ADB	\
+#define DRM_IOCTL_GMA_ADB	\
 		DRM_IOWR(DRM_GMA_ADB + DRM_COMMAND_BASE, uint32_t)
-#define DRM_IOCTL_PSB_MODE_OPERATION	\
+#define DRM_IOCTL_GMA_MODE_OPERATION	\
 		DRM_IOWR(DRM_GMA_MODE_OPERATION + DRM_COMMAND_BASE, \
 			 struct drm_psb_mode_operation_arg)
-#define DRM_IOCTL_PSB_STOLEN_MEMORY	\
+#define DRM_IOCTL_GMA_STOLEN_MEMORY	\
 		DRM_IOWR(DRM_GMA_STOLEN_MEMORY + DRM_COMMAND_BASE, \
 			 struct drm_psb_stolen_memory_arg)
-#define DRM_IOCTL_PSB_GAMMA	\
+#define DRM_IOCTL_GMA_GAMMA	\
 		DRM_IOWR(DRM_GMA_GAMMA + DRM_COMMAND_BASE, \
 			 struct drm_psb_dpst_lut_arg)
-#define DRM_IOCTL_PSB_DPST_BL	\
+#define DRM_IOCTL_GMA_DPST_BL	\
 		DRM_IOWR(DRM_GMA_DPST_BL + DRM_COMMAND_BASE, \
 			 uint32_t)
-#define DRM_IOCTL_PSB_GET_PIPE_FROM_CRTC_ID	\
+#define DRM_IOCTL_GMA_GET_PIPE_FROM_CRTC_ID	\
 		DRM_IOWR(DRM_GMA_GET_PIPE_FROM_CRTC_ID + DRM_COMMAND_BASE, \
 			 struct drm_psb_get_pipe_from_crtc_id_arg)
-#define DRM_IOCTL_PSB_GEM_CREATE	\
+#define DRM_IOCTL_GMA_GEM_CREATE	\
 		DRM_IOWR(DRM_GMA_GEM_CREATE + DRM_COMMAND_BASE, \
 			 struct drm_psb_gem_create)
-#define DRM_IOCTL_PSB_GEM_MMAP	\
+#define DRM_IOCTL_GMA_GEM_MMAP	\
 		DRM_IOWR(DRM_GMA_GEM_MMAP + DRM_COMMAND_BASE, \
 			 struct drm_psb_gem_mmap)
 
@@ -113,22 +123,19 @@
 static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data,
 			     struct drm_file *file_priv);
 
-#define PSB_IOCTL_DEF(ioctl, func, flags) \
-	[DRM_IOCTL_NR(ioctl) - DRM_COMMAND_BASE] = {ioctl, flags, func}
-
 static struct drm_ioctl_desc psb_ioctls[] = {
-	PSB_IOCTL_DEF(DRM_IOCTL_PSB_ADB, psb_adb_ioctl, DRM_AUTH),
-	PSB_IOCTL_DEF(DRM_IOCTL_PSB_MODE_OPERATION, psb_mode_operation_ioctl,
+	DRM_IOCTL_DEF_DRV(GMA_ADB, psb_adb_ioctl, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(GMA_MODE_OPERATION, psb_mode_operation_ioctl,
 		      DRM_AUTH),
-	PSB_IOCTL_DEF(DRM_IOCTL_PSB_STOLEN_MEMORY, psb_stolen_memory_ioctl,
+	DRM_IOCTL_DEF_DRV(GMA_STOLEN_MEMORY, psb_stolen_memory_ioctl,
 		      DRM_AUTH),
-	PSB_IOCTL_DEF(DRM_IOCTL_PSB_GAMMA, psb_gamma_ioctl, DRM_AUTH),
-	PSB_IOCTL_DEF(DRM_IOCTL_PSB_DPST_BL, psb_dpst_bl_ioctl, DRM_AUTH),
-	PSB_IOCTL_DEF(DRM_IOCTL_PSB_GET_PIPE_FROM_CRTC_ID,
+	DRM_IOCTL_DEF_DRV(GMA_GAMMA, psb_gamma_ioctl, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(GMA_DPST_BL, psb_dpst_bl_ioctl, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(GMA_GET_PIPE_FROM_CRTC_ID,
 					psb_intel_get_pipe_from_crtc_id, 0),
-	PSB_IOCTL_DEF(DRM_IOCTL_PSB_GEM_CREATE, psb_gem_create_ioctl,
+	DRM_IOCTL_DEF_DRV(GMA_GEM_CREATE, psb_gem_create_ioctl,
 						DRM_UNLOCKED | DRM_AUTH),
-	PSB_IOCTL_DEF(DRM_IOCTL_PSB_GEM_MMAP, psb_gem_mmap_ioctl,
+	DRM_IOCTL_DEF_DRV(GMA_GEM_MMAP, psb_gem_mmap_ioctl,
 						DRM_UNLOCKED | DRM_AUTH),
 };
 
@@ -268,10 +275,8 @@
 {
 	struct drm_psb_private *dev_priv;
 	unsigned long resource_start;
-	struct psb_gtt *pg;
 	unsigned long irqflags;
 	int ret = -ENOMEM;
-	uint32_t tt_pages;
 	struct drm_connector *connector;
 	struct psb_intel_encoder *psb_intel_encoder;
 
@@ -283,6 +288,8 @@
 	dev_priv->dev = dev;
 	dev->dev_private = (void *) dev_priv;
 
+	pci_set_master(dev->pdev);
+
 	if (!IS_PSB(dev)) {
 		if (pci_enable_msi(dev->pdev))
 			dev_warn(dev->dev, "Enabling MSI failed!\n");
@@ -327,12 +334,6 @@
 	if (!dev_priv->mmu)
 		goto out_err;
 
-	pg = &dev_priv->gtt;
-
-	tt_pages = (pg->gatt_pages < PSB_TT_PRIV0_PLIMIT) ?
-		(pg->gatt_pages) : PSB_TT_PRIV0_PLIMIT;
-
-
 	dev_priv->pf_pd = psb_mmu_alloc_pd(dev_priv->mmu, 1, 0);
 	if (!dev_priv->pf_pd)
 		goto out_err;
@@ -409,7 +410,7 @@
 	return ret;
 }
 
-int psb_driver_device_is_agp(struct drm_device *dev)
+static int psb_driver_device_is_agp(struct drm_device *dev)
 {
 	return 0;
 }
@@ -600,7 +601,7 @@
 /* When a client dies:
  *    - Check for and clean up flipped page state
  */
-void psb_driver_preclose(struct drm_device *dev, struct drm_file *priv)
+static void psb_driver_preclose(struct drm_device *dev, struct drm_file *priv)
 {
 }
 
@@ -677,7 +678,9 @@
 	.id_table = pciidlist,
 	.probe = psb_probe,
 	.remove = psb_remove,
-	.driver.pm = &psb_pm_ops,
+	.driver = {
+		.pm = &psb_pm_ops,
+	}
 };
 
 static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h
index eb1568a..40ce2c9 100644
--- a/drivers/gpu/drm/gma500/psb_drv.h
+++ b/drivers/gpu/drm/gma500/psb_drv.h
@@ -276,6 +276,217 @@
 	u32 reg0;
 };
 
+/*
+ *	Register save state. This is used to hold the context when the
+ *	device is powered off. In the case of Oaktrail this can (but does not
+ *	yet) include screen blank. Operations occuring during the save
+ *	update the register cache instead.
+ */
+struct psb_state {
+	uint32_t saveDSPACNTR;
+	uint32_t saveDSPBCNTR;
+	uint32_t savePIPEACONF;
+	uint32_t savePIPEBCONF;
+	uint32_t savePIPEASRC;
+	uint32_t savePIPEBSRC;
+	uint32_t saveFPA0;
+	uint32_t saveFPA1;
+	uint32_t saveDPLL_A;
+	uint32_t saveDPLL_A_MD;
+	uint32_t saveHTOTAL_A;
+	uint32_t saveHBLANK_A;
+	uint32_t saveHSYNC_A;
+	uint32_t saveVTOTAL_A;
+	uint32_t saveVBLANK_A;
+	uint32_t saveVSYNC_A;
+	uint32_t saveDSPASTRIDE;
+	uint32_t saveDSPASIZE;
+	uint32_t saveDSPAPOS;
+	uint32_t saveDSPABASE;
+	uint32_t saveDSPASURF;
+	uint32_t saveDSPASTATUS;
+	uint32_t saveFPB0;
+	uint32_t saveFPB1;
+	uint32_t saveDPLL_B;
+	uint32_t saveDPLL_B_MD;
+	uint32_t saveHTOTAL_B;
+	uint32_t saveHBLANK_B;
+	uint32_t saveHSYNC_B;
+	uint32_t saveVTOTAL_B;
+	uint32_t saveVBLANK_B;
+	uint32_t saveVSYNC_B;
+	uint32_t saveDSPBSTRIDE;
+	uint32_t saveDSPBSIZE;
+	uint32_t saveDSPBPOS;
+	uint32_t saveDSPBBASE;
+	uint32_t saveDSPBSURF;
+	uint32_t saveDSPBSTATUS;
+	uint32_t saveVCLK_DIVISOR_VGA0;
+	uint32_t saveVCLK_DIVISOR_VGA1;
+	uint32_t saveVCLK_POST_DIV;
+	uint32_t saveVGACNTRL;
+	uint32_t saveADPA;
+	uint32_t saveLVDS;
+	uint32_t saveDVOA;
+	uint32_t saveDVOB;
+	uint32_t saveDVOC;
+	uint32_t savePP_ON;
+	uint32_t savePP_OFF;
+	uint32_t savePP_CONTROL;
+	uint32_t savePP_CYCLE;
+	uint32_t savePFIT_CONTROL;
+	uint32_t savePaletteA[256];
+	uint32_t savePaletteB[256];
+	uint32_t saveCLOCKGATING;
+	uint32_t saveDSPARB;
+	uint32_t saveDSPATILEOFF;
+	uint32_t saveDSPBTILEOFF;
+	uint32_t saveDSPAADDR;
+	uint32_t saveDSPBADDR;
+	uint32_t savePFIT_AUTO_RATIOS;
+	uint32_t savePFIT_PGM_RATIOS;
+	uint32_t savePP_ON_DELAYS;
+	uint32_t savePP_OFF_DELAYS;
+	uint32_t savePP_DIVISOR;
+	uint32_t saveBCLRPAT_A;
+	uint32_t saveBCLRPAT_B;
+	uint32_t saveDSPALINOFF;
+	uint32_t saveDSPBLINOFF;
+	uint32_t savePERF_MODE;
+	uint32_t saveDSPFW1;
+	uint32_t saveDSPFW2;
+	uint32_t saveDSPFW3;
+	uint32_t saveDSPFW4;
+	uint32_t saveDSPFW5;
+	uint32_t saveDSPFW6;
+	uint32_t saveCHICKENBIT;
+	uint32_t saveDSPACURSOR_CTRL;
+	uint32_t saveDSPBCURSOR_CTRL;
+	uint32_t saveDSPACURSOR_BASE;
+	uint32_t saveDSPBCURSOR_BASE;
+	uint32_t saveDSPACURSOR_POS;
+	uint32_t saveDSPBCURSOR_POS;
+	uint32_t save_palette_a[256];
+	uint32_t save_palette_b[256];
+	uint32_t saveOV_OVADD;
+	uint32_t saveOV_OGAMC0;
+	uint32_t saveOV_OGAMC1;
+	uint32_t saveOV_OGAMC2;
+	uint32_t saveOV_OGAMC3;
+	uint32_t saveOV_OGAMC4;
+	uint32_t saveOV_OGAMC5;
+	uint32_t saveOVC_OVADD;
+	uint32_t saveOVC_OGAMC0;
+	uint32_t saveOVC_OGAMC1;
+	uint32_t saveOVC_OGAMC2;
+	uint32_t saveOVC_OGAMC3;
+	uint32_t saveOVC_OGAMC4;
+	uint32_t saveOVC_OGAMC5;
+
+	/* DPST register save */
+	uint32_t saveHISTOGRAM_INT_CONTROL_REG;
+	uint32_t saveHISTOGRAM_LOGIC_CONTROL_REG;
+	uint32_t savePWM_CONTROL_LOGIC;
+};
+
+struct medfield_state {
+	uint32_t saveDPLL_A;
+	uint32_t saveFPA0;
+	uint32_t savePIPEACONF;
+	uint32_t saveHTOTAL_A;
+	uint32_t saveHBLANK_A;
+	uint32_t saveHSYNC_A;
+	uint32_t saveVTOTAL_A;
+	uint32_t saveVBLANK_A;
+	uint32_t saveVSYNC_A;
+	uint32_t savePIPEASRC;
+	uint32_t saveDSPASTRIDE;
+	uint32_t saveDSPALINOFF;
+	uint32_t saveDSPATILEOFF;
+	uint32_t saveDSPASIZE;
+	uint32_t saveDSPAPOS;
+	uint32_t saveDSPASURF;
+	uint32_t saveDSPACNTR;
+	uint32_t saveDSPASTATUS;
+	uint32_t save_palette_a[256];
+	uint32_t saveMIPI;
+
+	uint32_t saveDPLL_B;
+	uint32_t saveFPB0;
+	uint32_t savePIPEBCONF;
+	uint32_t saveHTOTAL_B;
+	uint32_t saveHBLANK_B;
+	uint32_t saveHSYNC_B;
+	uint32_t saveVTOTAL_B;
+	uint32_t saveVBLANK_B;
+	uint32_t saveVSYNC_B;
+	uint32_t savePIPEBSRC;
+	uint32_t saveDSPBSTRIDE;
+	uint32_t saveDSPBLINOFF;
+	uint32_t saveDSPBTILEOFF;
+	uint32_t saveDSPBSIZE;
+	uint32_t saveDSPBPOS;
+	uint32_t saveDSPBSURF;
+	uint32_t saveDSPBCNTR;
+	uint32_t saveDSPBSTATUS;
+	uint32_t save_palette_b[256];
+
+	uint32_t savePIPECCONF;
+	uint32_t saveHTOTAL_C;
+	uint32_t saveHBLANK_C;
+	uint32_t saveHSYNC_C;
+	uint32_t saveVTOTAL_C;
+	uint32_t saveVBLANK_C;
+	uint32_t saveVSYNC_C;
+	uint32_t savePIPECSRC;
+	uint32_t saveDSPCSTRIDE;
+	uint32_t saveDSPCLINOFF;
+	uint32_t saveDSPCTILEOFF;
+	uint32_t saveDSPCSIZE;
+	uint32_t saveDSPCPOS;
+	uint32_t saveDSPCSURF;
+	uint32_t saveDSPCCNTR;
+	uint32_t saveDSPCSTATUS;
+	uint32_t save_palette_c[256];
+	uint32_t saveMIPI_C;
+
+	uint32_t savePFIT_CONTROL;
+	uint32_t savePFIT_PGM_RATIOS;
+	uint32_t saveHDMIPHYMISCCTL;
+	uint32_t saveHDMIB_CONTROL;
+};
+
+struct cdv_state {
+	uint32_t saveDSPCLK_GATE_D;
+	uint32_t saveRAMCLK_GATE_D;
+	uint32_t saveDSPARB;
+	uint32_t saveDSPFW[6];
+	uint32_t saveADPA;
+	uint32_t savePP_CONTROL;
+	uint32_t savePFIT_PGM_RATIOS;
+	uint32_t saveLVDS;
+	uint32_t savePFIT_CONTROL;
+	uint32_t savePP_ON_DELAYS;
+	uint32_t savePP_OFF_DELAYS;
+	uint32_t savePP_CYCLE;
+	uint32_t saveVGACNTRL;
+	uint32_t saveIER;
+	uint32_t saveIMR;
+	u8	 saveLBB;
+};
+
+struct psb_save_area {
+	uint32_t saveBSM;
+	uint32_t saveVBT;
+	union {
+	        struct psb_state psb;
+		struct medfield_state mdfld;
+		struct cdv_state cdv;
+	};
+	uint32_t saveBLC_PWM_CTL2;
+	uint32_t saveBLC_PWM_CTL;
+};
+
 struct psb_ops;
 
 #define PSB_NUM_PIPE		3
@@ -397,215 +608,20 @@
 	struct oaktrail_vbt vbt_data;
 	struct oaktrail_gct_data gct_data;
 
-	/* MIPI Panel type etc */
-	int panel_id;
-	bool dual_mipi;		/* dual display - DPI & DBI */
-	bool dpi_panel_on;	/* The DPI panel power is on */
-	bool dpi_panel_on2;	/* The DPI panel power is on */
-	bool dbi_panel_on;	/* The DBI panel power is on */
-	bool dbi_panel_on2;	/* The DBI panel power is on */
-	u32 dsr_fb_update;	/* DSR FB update counter */
-
-	/* Moorestown HDMI state */
+	/* Oaktrail HDMI state */
 	struct oaktrail_hdmi_dev *hdmi_priv;
-
-	/* Moorestown pipe config register value cache */
-	uint32_t pipeconf;
-	uint32_t pipeconf1;
-	uint32_t pipeconf2;
-
-	/* Moorestown plane control register value cache */
-	uint32_t dspcntr;
-	uint32_t dspcntr1;
-	uint32_t dspcntr2;
-
-	/* Moorestown MM backlight cache */
-	uint8_t saveBKLTCNT;
-	uint8_t saveBKLTREQ;
-	uint8_t saveBKLTBRTL;
-
+	
 	/*
 	 * Register state
 	 */
-	uint32_t saveDSPACNTR;
-	uint32_t saveDSPBCNTR;
-	uint32_t savePIPEACONF;
-	uint32_t savePIPEBCONF;
-	uint32_t savePIPEASRC;
-	uint32_t savePIPEBSRC;
-	uint32_t saveFPA0;
-	uint32_t saveFPA1;
-	uint32_t saveDPLL_A;
-	uint32_t saveDPLL_A_MD;
-	uint32_t saveHTOTAL_A;
-	uint32_t saveHBLANK_A;
-	uint32_t saveHSYNC_A;
-	uint32_t saveVTOTAL_A;
-	uint32_t saveVBLANK_A;
-	uint32_t saveVSYNC_A;
-	uint32_t saveDSPASTRIDE;
-	uint32_t saveDSPASIZE;
-	uint32_t saveDSPAPOS;
-	uint32_t saveDSPABASE;
-	uint32_t saveDSPASURF;
-	uint32_t saveDSPASTATUS;
-	uint32_t saveFPB0;
-	uint32_t saveFPB1;
-	uint32_t saveDPLL_B;
-	uint32_t saveDPLL_B_MD;
-	uint32_t saveHTOTAL_B;
-	uint32_t saveHBLANK_B;
-	uint32_t saveHSYNC_B;
-	uint32_t saveVTOTAL_B;
-	uint32_t saveVBLANK_B;
-	uint32_t saveVSYNC_B;
-	uint32_t saveDSPBSTRIDE;
-	uint32_t saveDSPBSIZE;
-	uint32_t saveDSPBPOS;
-	uint32_t saveDSPBBASE;
-	uint32_t saveDSPBSURF;
-	uint32_t saveDSPBSTATUS;
-	uint32_t saveVCLK_DIVISOR_VGA0;
-	uint32_t saveVCLK_DIVISOR_VGA1;
-	uint32_t saveVCLK_POST_DIV;
-	uint32_t saveVGACNTRL;
-	uint32_t saveADPA;
-	uint32_t saveLVDS;
-	uint32_t saveDVOA;
-	uint32_t saveDVOB;
-	uint32_t saveDVOC;
-	uint32_t savePP_ON;
-	uint32_t savePP_OFF;
-	uint32_t savePP_CONTROL;
-	uint32_t savePP_CYCLE;
-	uint32_t savePFIT_CONTROL;
-	uint32_t savePaletteA[256];
-	uint32_t savePaletteB[256];
-	uint32_t saveBLC_PWM_CTL2;
-	uint32_t saveBLC_PWM_CTL;
-	uint32_t saveCLOCKGATING;
-	uint32_t saveDSPARB;
-	uint32_t saveDSPATILEOFF;
-	uint32_t saveDSPBTILEOFF;
-	uint32_t saveDSPAADDR;
-	uint32_t saveDSPBADDR;
-	uint32_t savePFIT_AUTO_RATIOS;
-	uint32_t savePFIT_PGM_RATIOS;
-	uint32_t savePP_ON_DELAYS;
-	uint32_t savePP_OFF_DELAYS;
-	uint32_t savePP_DIVISOR;
-	uint32_t saveBSM;
-	uint32_t saveVBT;
-	uint32_t saveBCLRPAT_A;
-	uint32_t saveBCLRPAT_B;
-	uint32_t saveDSPALINOFF;
-	uint32_t saveDSPBLINOFF;
-	uint32_t savePERF_MODE;
-	uint32_t saveDSPFW1;
-	uint32_t saveDSPFW2;
-	uint32_t saveDSPFW3;
-	uint32_t saveDSPFW4;
-	uint32_t saveDSPFW5;
-	uint32_t saveDSPFW6;
-	uint32_t saveCHICKENBIT;
-	uint32_t saveDSPACURSOR_CTRL;
-	uint32_t saveDSPBCURSOR_CTRL;
-	uint32_t saveDSPACURSOR_BASE;
-	uint32_t saveDSPBCURSOR_BASE;
-	uint32_t saveDSPACURSOR_POS;
-	uint32_t saveDSPBCURSOR_POS;
-	uint32_t save_palette_a[256];
-	uint32_t save_palette_b[256];
-	uint32_t saveOV_OVADD;
-	uint32_t saveOV_OGAMC0;
-	uint32_t saveOV_OGAMC1;
-	uint32_t saveOV_OGAMC2;
-	uint32_t saveOV_OGAMC3;
-	uint32_t saveOV_OGAMC4;
-	uint32_t saveOV_OGAMC5;
-	uint32_t saveOVC_OVADD;
-	uint32_t saveOVC_OGAMC0;
-	uint32_t saveOVC_OGAMC1;
-	uint32_t saveOVC_OGAMC2;
-	uint32_t saveOVC_OGAMC3;
-	uint32_t saveOVC_OGAMC4;
-	uint32_t saveOVC_OGAMC5;
+
+	struct psb_save_area regs;
 
 	/* MSI reg save */
 	uint32_t msi_addr;
 	uint32_t msi_data;
 
-	/* Medfield specific register save state */
-	uint32_t saveHDMIPHYMISCCTL;
-	uint32_t saveHDMIB_CONTROL;
-	uint32_t saveDSPCCNTR;
-	uint32_t savePIPECCONF;
-	uint32_t savePIPECSRC;
-	uint32_t saveHTOTAL_C;
-	uint32_t saveHBLANK_C;
-	uint32_t saveHSYNC_C;
-	uint32_t saveVTOTAL_C;
-	uint32_t saveVBLANK_C;
-	uint32_t saveVSYNC_C;
-	uint32_t saveDSPCSTRIDE;
-	uint32_t saveDSPCSIZE;
-	uint32_t saveDSPCPOS;
-	uint32_t saveDSPCSURF;
-	uint32_t saveDSPCSTATUS;
-	uint32_t saveDSPCLINOFF;
-	uint32_t saveDSPCTILEOFF;
-	uint32_t saveDSPCCURSOR_CTRL;
-	uint32_t saveDSPCCURSOR_BASE;
-	uint32_t saveDSPCCURSOR_POS;
-	uint32_t save_palette_c[256];
-	uint32_t saveOV_OVADD_C;
-	uint32_t saveOV_OGAMC0_C;
-	uint32_t saveOV_OGAMC1_C;
-	uint32_t saveOV_OGAMC2_C;
-	uint32_t saveOV_OGAMC3_C;
-	uint32_t saveOV_OGAMC4_C;
-	uint32_t saveOV_OGAMC5_C;
 
-	/* DSI register save */
-	uint32_t saveDEVICE_READY_REG;
-	uint32_t saveINTR_EN_REG;
-	uint32_t saveDSI_FUNC_PRG_REG;
-	uint32_t saveHS_TX_TIMEOUT_REG;
-	uint32_t saveLP_RX_TIMEOUT_REG;
-	uint32_t saveTURN_AROUND_TIMEOUT_REG;
-	uint32_t saveDEVICE_RESET_REG;
-	uint32_t saveDPI_RESOLUTION_REG;
-	uint32_t saveHORIZ_SYNC_PAD_COUNT_REG;
-	uint32_t saveHORIZ_BACK_PORCH_COUNT_REG;
-	uint32_t saveHORIZ_FRONT_PORCH_COUNT_REG;
-	uint32_t saveHORIZ_ACTIVE_AREA_COUNT_REG;
-	uint32_t saveVERT_SYNC_PAD_COUNT_REG;
-	uint32_t saveVERT_BACK_PORCH_COUNT_REG;
-	uint32_t saveVERT_FRONT_PORCH_COUNT_REG;
-	uint32_t saveHIGH_LOW_SWITCH_COUNT_REG;
-	uint32_t saveINIT_COUNT_REG;
-	uint32_t saveMAX_RET_PAK_REG;
-	uint32_t saveVIDEO_FMT_REG;
-	uint32_t saveEOT_DISABLE_REG;
-	uint32_t saveLP_BYTECLK_REG;
-	uint32_t saveHS_LS_DBI_ENABLE_REG;
-	uint32_t saveTXCLKESC_REG;
-	uint32_t saveDPHY_PARAM_REG;
-	uint32_t saveMIPI_CONTROL_REG;
-	uint32_t saveMIPI;
-	uint32_t saveMIPI_C;
-
-	/* DPST register save */
-	uint32_t saveHISTOGRAM_INT_CONTROL_REG;
-	uint32_t saveHISTOGRAM_LOGIC_CONTROL_REG;
-	uint32_t savePWM_CONTROL_LOGIC;
-
-	/*
-	 * DSI info. 
-	 */
-	void * dbi_dsr_info;	
-	void * dbi_dpu_info;
-	void * dsi_configs[2];
 	/*
 	 * LID-Switch
 	 */
@@ -635,6 +651,24 @@
 
 	/* 2D acceleration */
 	spinlock_t lock_2d;
+
+	/*
+	 * Panel brightness
+	 */
+	int brightness;
+	int brightness_adjusted;
+
+	bool dsr_enable;
+	u32 dsr_fb_update;
+	bool dpi_panel_on[3];
+	void *dsi_configs[2];
+	u32 bpp;
+	u32 bpp2;
+
+	u32 pipeconf[3];
+	u32 dspcntr[3];
+
+	int mdfld_panel_id;
 };
 
 
@@ -830,6 +864,9 @@
 /* oaktrail_device.c */
 extern const struct psb_ops oaktrail_chip_ops;
 
+/* mdlfd_device.c */
+extern const struct psb_ops mdfld_chip_ops;
+
 /* cdv_device.c */
 extern const struct psb_ops cdv_chip_ops;
 
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
index 49e9835..2616558 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.c
+++ b/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -333,7 +333,7 @@
 	mdelay(20);
 }
 
-int psb_intel_pipe_set_base(struct drm_crtc *crtc,
+static int psb_intel_pipe_set_base(struct drm_crtc *crtc,
 			    int x, int y, struct drm_framebuffer *old_fb)
 {
 	struct drm_device *dev = crtc->dev;
@@ -433,7 +433,6 @@
 	int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE;
 	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
 	u32 temp;
-	bool enabled;
 
 	/* XXX: When our outputs are all unaware of DPMS modes other than off
 	 * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
@@ -518,8 +517,6 @@
 		break;
 	}
 
-	enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF;
-
 	/*Set FIFO Watermarks*/
 	REG_WRITE(DSPARB, 0x3F3E);
 }
@@ -611,8 +608,8 @@
 	int refclk;
 	struct psb_intel_clock_t clock;
 	u32 dpll = 0, fp = 0, dspcntr, pipeconf;
-	bool ok, is_sdvo = false, is_dvo = false;
-	bool is_crt = false, is_lvds = false, is_tv = false;
+	bool ok, is_sdvo = false;
+	bool is_lvds = false, is_tv = false;
 	struct drm_mode_config *mode_config = &dev->mode_config;
 	struct drm_connector *connector;
 
@@ -637,15 +634,9 @@
 		case INTEL_OUTPUT_SDVO:
 			is_sdvo = true;
 			break;
-		case INTEL_OUTPUT_DVO:
-			is_dvo = true;
-			break;
 		case INTEL_OUTPUT_TVOUT:
 			is_tv = true;
 			break;
-		case INTEL_OUTPUT_ANALOG:
-			is_crt = true;
-			break;
 		}
 	}
 
@@ -845,7 +836,7 @@
 		gma_power_end(dev);
 	} else {
 		for (i = 0; i < 256; i++) {
-			dev_priv->save_palette_a[i] =
+			dev_priv->regs.psb.save_palette_a[i] =
 				  ((psb_intel_crtc->lut_r[i] +
 				  psb_intel_crtc->lut_adj[i]) << 16) |
 				  ((psb_intel_crtc->lut_g[i] +
@@ -1141,18 +1132,20 @@
 		gma_power_end(dev);
 	} else {
 		dpll = (pipe == 0) ?
-			dev_priv->saveDPLL_A : dev_priv->saveDPLL_B;
+			dev_priv->regs.psb.saveDPLL_A :
+			dev_priv->regs.psb.saveDPLL_B;
 
 		if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
 			fp = (pipe == 0) ?
-				dev_priv->saveFPA0 :
-				dev_priv->saveFPB0;
+				dev_priv->regs.psb.saveFPA0 :
+				dev_priv->regs.psb.saveFPB0;
 		else
 			fp = (pipe == 0) ?
-				dev_priv->saveFPA1 :
-				dev_priv->saveFPB1;
+				dev_priv->regs.psb.saveFPA1 :
+				dev_priv->regs.psb.saveFPB1;
 
-		is_lvds = (pipe == 1) && (dev_priv->saveLVDS & LVDS_PORT_EN);
+		is_lvds = (pipe == 1) && (dev_priv->regs.psb.saveLVDS &
+								LVDS_PORT_EN);
 	}
 
 	clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
@@ -1218,13 +1211,17 @@
 		gma_power_end(dev);
 	} else {
 		htot = (pipe == 0) ?
-			dev_priv->saveHTOTAL_A : dev_priv->saveHTOTAL_B;
+			dev_priv->regs.psb.saveHTOTAL_A :
+			dev_priv->regs.psb.saveHTOTAL_B;
 		hsync = (pipe == 0) ?
-			dev_priv->saveHSYNC_A : dev_priv->saveHSYNC_B;
+			dev_priv->regs.psb.saveHSYNC_A :
+			dev_priv->regs.psb.saveHSYNC_B;
 		vtot = (pipe == 0) ?
-			dev_priv->saveVTOTAL_A : dev_priv->saveVTOTAL_B;
+			dev_priv->regs.psb.saveVTOTAL_A :
+			dev_priv->regs.psb.saveVTOTAL_B;
 		vsync = (pipe == 0) ?
-			dev_priv->saveVSYNC_A : dev_priv->saveVSYNC_B;
+			dev_priv->regs.psb.saveVSYNC_A :
+			dev_priv->regs.psb.saveVSYNC_B;
 	}
 
 	mode = kzalloc(sizeof(*mode), GFP_KERNEL);
@@ -1419,13 +1416,6 @@
 	return index_mask;
 }
 
-
-void psb_intel_modeset_cleanup(struct drm_device *dev)
-{
-	drm_mode_config_cleanup(dev);
-}
-
-
 /* current intel driver doesn't take advantage of encoders
    always give back the encoder for the connector
 */
diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c
index 0a43758..c83f5b5 100644
--- a/drivers/gpu/drm/gma500/psb_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c
@@ -77,7 +77,7 @@
 		ret = REG_READ(BLC_PWM_CTL);
 		gma_power_end(dev);
 	} else /* Powered off, use the saved value */
-		ret = dev_priv->saveBLC_PWM_CTL;
+		ret = dev_priv->regs.saveBLC_PWM_CTL;
 
 	/* Top 15bits hold the frequency mask */
 	ret = (ret &  BACKLIGHT_MODULATION_FREQ_MASK) >>
@@ -86,7 +86,7 @@
         ret *= 2;	/* Return a 16bit range as needed for setting */
         if (ret == 0)
                 dev_err(dev->dev, "BL bug: Reg %08x save %08X\n",
-                        REG_READ(BLC_PWM_CTL), dev_priv->saveBLC_PWM_CTL);
+                        REG_READ(BLC_PWM_CTL), dev_priv->regs.saveBLC_PWM_CTL);
 	return ret;
 }
 
@@ -203,13 +203,13 @@
 		REG_WRITE(BLC_PWM_CTL,
 				(blc_pwm_ctl |
 				(level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
-		dev_priv->saveBLC_PWM_CTL = (blc_pwm_ctl |
+		dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl |
 					(level << BACKLIGHT_DUTY_CYCLE_SHIFT));
 		gma_power_end(dev);
 	} else {
-		blc_pwm_ctl = dev_priv->saveBLC_PWM_CTL &
+		blc_pwm_ctl = dev_priv->regs.saveBLC_PWM_CTL &
 				~BACKLIGHT_DUTY_CYCLE_MASK;
-		dev_priv->saveBLC_PWM_CTL = (blc_pwm_ctl |
+		dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl |
 					(level << BACKLIGHT_DUTY_CYCLE_SHIFT));
 	}
 }
@@ -283,7 +283,7 @@
 	lvds_priv->savePFIT_PGM_RATIOS = REG_READ(PFIT_PGM_RATIOS);
 
 	/*TODO: move backlight_duty_cycle to psb_intel_lvds_priv*/
-	dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
+	dev_priv->backlight_duty_cycle = (dev_priv->regs.saveBLC_PWM_CTL &
 						BACKLIGHT_DUTY_CYCLE_MASK);
 
 	/*
diff --git a/drivers/gpu/drm/gma500/psb_intel_reg.h b/drivers/gpu/drm/gma500/psb_intel_reg.h
index fcc0af0..e89d3a2 100644
--- a/drivers/gpu/drm/gma500/psb_intel_reg.h
+++ b/drivers/gpu/drm/gma500/psb_intel_reg.h
@@ -177,6 +177,9 @@
 #define LVDSPP_OFF		0x6120c
 #define PP_CYCLE		0x61210
 
+#define PP_ON_DELAYS		0x61208		/* Cedartrail */
+#define PP_OFF_DELAYS		0x6120c		/* Cedartrail */
+
 #define PFIT_CONTROL		0x61230
 #define PFIT_ENABLE			(1 << 31)
 #define PFIT_PIPE_MASK			(3 << 29)
@@ -1252,6 +1255,12 @@
 # define SB_BYTE_ENABLE_SHIFT                   4
 # define SB_BUSY                                (1 << 0)
 
+#define DSPCLK_GATE_D		0x6200
+# define VRHUNIT_CLOCK_GATE_DISABLE		(1 << 28) /* Fixed value on CDV */
+# define DPOUNIT_CLOCK_GATE_DISABLE		(1 << 11)
+# define DPIOUNIT_CLOCK_GATE_DISABLE		(1 << 6)
+
+#define RAMCLK_GATE_D		0x6210
 
 /* 32-bit value read/written from the DPIO reg. */
 #define SB_DATA		0x02104 /* cedarview */
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
index 88b4297..36330ca 100644
--- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
+++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
@@ -1301,7 +1301,7 @@
 	return NULL;
 }
 
-enum drm_connector_status
+static enum drm_connector_status
 psb_intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
 {
 	struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector);
@@ -2312,10 +2312,8 @@
 		psb_intel_sdvo_connector->max_##name = data_value[0]; \
 		psb_intel_sdvo_connector->cur_##name = response; \
 		psb_intel_sdvo_connector->name = \
-			drm_property_create(dev, DRM_MODE_PROP_RANGE, #name, 2); \
+			drm_property_create_range(dev, 0, #name, 0, data_value[0]); \
 		if (!psb_intel_sdvo_connector->name) return false; \
-		psb_intel_sdvo_connector->name->values[0] = 0; \
-		psb_intel_sdvo_connector->name->values[1] = data_value[0]; \
 		drm_connector_attach_property(connector, \
 					      psb_intel_sdvo_connector->name, \
 					      psb_intel_sdvo_connector->cur_##name); \
@@ -2349,25 +2347,19 @@
 		psb_intel_sdvo_connector->left_margin = data_value[0] - response;
 		psb_intel_sdvo_connector->right_margin = psb_intel_sdvo_connector->left_margin;
 		psb_intel_sdvo_connector->left =
-			drm_property_create(dev, DRM_MODE_PROP_RANGE,
-					    "left_margin", 2);
+			drm_property_create_range(dev, 0, "left_margin", 0, data_value[0]);
 		if (!psb_intel_sdvo_connector->left)
 			return false;
 
-		psb_intel_sdvo_connector->left->values[0] = 0;
-		psb_intel_sdvo_connector->left->values[1] = data_value[0];
 		drm_connector_attach_property(connector,
 					      psb_intel_sdvo_connector->left,
 					      psb_intel_sdvo_connector->left_margin);
 
 		psb_intel_sdvo_connector->right =
-			drm_property_create(dev, DRM_MODE_PROP_RANGE,
-					    "right_margin", 2);
+			drm_property_create_range(dev, 0, "right_margin", 0, data_value[0]);
 		if (!psb_intel_sdvo_connector->right)
 			return false;
 
-		psb_intel_sdvo_connector->right->values[0] = 0;
-		psb_intel_sdvo_connector->right->values[1] = data_value[0];
 		drm_connector_attach_property(connector,
 					      psb_intel_sdvo_connector->right,
 					      psb_intel_sdvo_connector->right_margin);
@@ -2391,25 +2383,19 @@
 		psb_intel_sdvo_connector->top_margin = data_value[0] - response;
 		psb_intel_sdvo_connector->bottom_margin = psb_intel_sdvo_connector->top_margin;
 		psb_intel_sdvo_connector->top =
-			drm_property_create(dev, DRM_MODE_PROP_RANGE,
-					    "top_margin", 2);
+			drm_property_create_range(dev, 0, "top_margin", 0, data_value[0]);
 		if (!psb_intel_sdvo_connector->top)
 			return false;
 
-		psb_intel_sdvo_connector->top->values[0] = 0;
-		psb_intel_sdvo_connector->top->values[1] = data_value[0];
 		drm_connector_attach_property(connector,
 					      psb_intel_sdvo_connector->top,
 					      psb_intel_sdvo_connector->top_margin);
 
 		psb_intel_sdvo_connector->bottom =
-			drm_property_create(dev, DRM_MODE_PROP_RANGE,
-					    "bottom_margin", 2);
+			drm_property_create_range(dev, 0, "bottom_margin", 0, data_value[0]);
 		if (!psb_intel_sdvo_connector->bottom)
 			return false;
 
-		psb_intel_sdvo_connector->bottom->values[0] = 0;
-		psb_intel_sdvo_connector->bottom->values[1] = data_value[0];
 		drm_connector_attach_property(connector,
 					      psb_intel_sdvo_connector->bottom,
 					      psb_intel_sdvo_connector->bottom_margin);
@@ -2438,12 +2424,10 @@
 		psb_intel_sdvo_connector->max_dot_crawl = 1;
 		psb_intel_sdvo_connector->cur_dot_crawl = response & 0x1;
 		psb_intel_sdvo_connector->dot_crawl =
-			drm_property_create(dev, DRM_MODE_PROP_RANGE, "dot_crawl", 2);
+			drm_property_create_range(dev, 0, "dot_crawl", 0, 1);
 		if (!psb_intel_sdvo_connector->dot_crawl)
 			return false;
 
-		psb_intel_sdvo_connector->dot_crawl->values[0] = 0;
-		psb_intel_sdvo_connector->dot_crawl->values[1] = 1;
 		drm_connector_attach_property(connector,
 					      psb_intel_sdvo_connector->dot_crawl,
 					      psb_intel_sdvo_connector->cur_dot_crawl);
diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c
index 7be802b..1869586 100644
--- a/drivers/gpu/drm/gma500/psb_irq.c
+++ b/drivers/gpu/drm/gma500/psb_irq.c
@@ -27,6 +27,8 @@
 #include "psb_reg.h"
 #include "psb_intel_reg.h"
 #include "power.h"
+#include "psb_irq.h"
+#include "mdfld_output.h"
 
 /*
  * inline functions
@@ -113,7 +115,7 @@
 	}
 }
 
-void mid_enable_pipe_event(struct drm_psb_private *dev_priv, int pipe)
+static void mid_enable_pipe_event(struct drm_psb_private *dev_priv, int pipe)
 {
 	if (gma_power_begin(dev_priv->dev, false)) {
 		u32 pipe_event = mid_pipe_event(pipe);
@@ -124,7 +126,7 @@
 	}
 }
 
-void mid_disable_pipe_event(struct drm_psb_private *dev_priv, int pipe)
+static void mid_disable_pipe_event(struct drm_psb_private *dev_priv, int pipe)
 {
 	if (dev_priv->pipestat[pipe] == 0) {
 		if (gma_power_begin(dev_priv->dev, false)) {
@@ -453,6 +455,11 @@
 	uint32_t reg_val = 0;
 	uint32_t pipeconf_reg = mid_pipeconf(pipe);
 
+	/* Medfield is different - we should perhaps extract out vblank
+	   and blacklight etc ops */
+	if (IS_MFLD(dev))
+		return mdfld_enable_te(dev, pipe);
+
 	if (gma_power_begin(dev, false)) {
 		reg_val = REG_READ(pipeconf_reg);
 		gma_power_end(dev);
@@ -485,6 +492,8 @@
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	unsigned long irqflags;
 
+	if (IS_MFLD(dev))
+		mdfld_disable_te(dev, pipe);
 	spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
 
 	if (pipe == 0)
@@ -499,6 +508,55 @@
 	spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
 }
 
+/*
+ * It is used to enable TE interrupt
+ */
+int mdfld_enable_te(struct drm_device *dev, int pipe)
+{
+	struct drm_psb_private *dev_priv =
+		(struct drm_psb_private *) dev->dev_private;
+	unsigned long irqflags;
+	uint32_t reg_val = 0;
+	uint32_t pipeconf_reg = mid_pipeconf(pipe);
+
+	if (gma_power_begin(dev, false)) {
+		reg_val = REG_READ(pipeconf_reg);
+		gma_power_end(dev);
+	}
+
+	if (!(reg_val & PIPEACONF_ENABLE))
+		return -EINVAL;
+
+	spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
+
+	mid_enable_pipe_event(dev_priv, pipe);
+	psb_enable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE);
+
+	spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
+
+	return 0;
+}
+
+/*
+ * It is used to disable TE interrupt
+ */
+void mdfld_disable_te(struct drm_device *dev, int pipe)
+{
+	struct drm_psb_private *dev_priv =
+		(struct drm_psb_private *) dev->dev_private;
+	unsigned long irqflags;
+
+	if (!dev_priv->dsr_enable)
+		return;
+
+	spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
+
+	mid_disable_pipe_event(dev_priv, pipe);
+	psb_disable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE);
+
+	spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
+}
+
 /* Called from drm generic code, passed a 'crtc', which
  * we use as a pipe index
  */
diff --git a/drivers/gpu/drm/gma500/psb_irq.h b/drivers/gpu/drm/gma500/psb_irq.h
index 216fda3..603045b 100644
--- a/drivers/gpu/drm/gma500/psb_irq.h
+++ b/drivers/gpu/drm/gma500/psb_irq.h
@@ -42,4 +42,6 @@
 void psb_disable_vblank(struct drm_device *dev, int pipe);
 u32  psb_get_vblank_counter(struct drm_device *dev, int pipe);
 
+int mdfld_enable_te(struct drm_device *dev, int pipe);
+void mdfld_disable_te(struct drm_device *dev, int pipe);
 #endif /* _SYSIRQ_H_ */
diff --git a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c
new file mode 100644
index 0000000..4a07ab5
--- /dev/null
+++ b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c
@@ -0,0 +1,829 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "mdfld_dsi_dpi.h"
+#include "mdfld_output.h"
+#include "mdfld_dsi_pkg_sender.h"
+#include "tc35876x-dsi-lvds.h"
+#include <linux/i2c/tc35876x.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/intel_scu_ipc.h>
+
+static struct i2c_client *tc35876x_client;
+static struct i2c_client *cmi_lcd_i2c_client;
+
+#define FLD_MASK(start, end)	(((1 << ((start) - (end) + 1)) - 1) << (end))
+#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
+
+/* DSI D-PHY Layer Registers */
+#define D0W_DPHYCONTTX		0x0004
+#define CLW_DPHYCONTRX		0x0020
+#define D0W_DPHYCONTRX		0x0024
+#define D1W_DPHYCONTRX		0x0028
+#define D2W_DPHYCONTRX		0x002C
+#define D3W_DPHYCONTRX		0x0030
+#define COM_DPHYCONTRX		0x0038
+#define CLW_CNTRL		0x0040
+#define D0W_CNTRL		0x0044
+#define D1W_CNTRL		0x0048
+#define D2W_CNTRL		0x004C
+#define D3W_CNTRL		0x0050
+#define DFTMODE_CNTRL		0x0054
+
+/* DSI PPI Layer Registers */
+#define PPI_STARTPPI		0x0104
+#define PPI_BUSYPPI		0x0108
+#define PPI_LINEINITCNT		0x0110
+#define PPI_LPTXTIMECNT		0x0114
+#define PPI_LANEENABLE		0x0134
+#define PPI_TX_RX_TA		0x013C
+#define PPI_CLS_ATMR		0x0140
+#define PPI_D0S_ATMR		0x0144
+#define PPI_D1S_ATMR		0x0148
+#define PPI_D2S_ATMR		0x014C
+#define PPI_D3S_ATMR		0x0150
+#define PPI_D0S_CLRSIPOCOUNT	0x0164
+#define PPI_D1S_CLRSIPOCOUNT	0x0168
+#define PPI_D2S_CLRSIPOCOUNT	0x016C
+#define PPI_D3S_CLRSIPOCOUNT	0x0170
+#define CLS_PRE			0x0180
+#define D0S_PRE			0x0184
+#define D1S_PRE			0x0188
+#define D2S_PRE			0x018C
+#define D3S_PRE			0x0190
+#define CLS_PREP		0x01A0
+#define D0S_PREP		0x01A4
+#define D1S_PREP		0x01A8
+#define D2S_PREP		0x01AC
+#define D3S_PREP		0x01B0
+#define CLS_ZERO		0x01C0
+#define D0S_ZERO		0x01C4
+#define D1S_ZERO		0x01C8
+#define D2S_ZERO		0x01CC
+#define D3S_ZERO		0x01D0
+#define PPI_CLRFLG		0x01E0
+#define PPI_CLRSIPO		0x01E4
+#define HSTIMEOUT		0x01F0
+#define HSTIMEOUTENABLE		0x01F4
+
+/* DSI Protocol Layer Registers */
+#define DSI_STARTDSI		0x0204
+#define DSI_BUSYDSI		0x0208
+#define DSI_LANEENABLE		0x0210
+#define DSI_LANESTATUS0		0x0214
+#define DSI_LANESTATUS1		0x0218
+#define DSI_INTSTATUS		0x0220
+#define DSI_INTMASK		0x0224
+#define DSI_INTCLR		0x0228
+#define DSI_LPTXTO		0x0230
+
+/* DSI General Registers */
+#define DSIERRCNT		0x0300
+
+/* DSI Application Layer Registers */
+#define APLCTRL			0x0400
+#define RDPKTLN			0x0404
+
+/* Video Path Registers */
+#define VPCTRL			0x0450
+#define HTIM1			0x0454
+#define HTIM2			0x0458
+#define VTIM1			0x045C
+#define VTIM2			0x0460
+#define VFUEN			0x0464
+
+/* LVDS Registers */
+#define LVMX0003		0x0480
+#define LVMX0407		0x0484
+#define LVMX0811		0x0488
+#define LVMX1215		0x048C
+#define LVMX1619		0x0490
+#define LVMX2023		0x0494
+#define LVMX2427		0x0498
+#define LVCFG			0x049C
+#define LVPHY0			0x04A0
+#define LVPHY1			0x04A4
+
+/* System Registers */
+#define SYSSTAT			0x0500
+#define SYSRST			0x0504
+
+/* GPIO Registers */
+/*#define GPIOC			0x0520*/
+#define GPIOO			0x0524
+#define GPIOI			0x0528
+
+/* I2C Registers */
+#define I2CTIMCTRL		0x0540
+#define I2CMADDR		0x0544
+#define WDATAQ			0x0548
+#define RDATAQ			0x054C
+
+/* Chip/Rev Registers */
+#define IDREG			0x0580
+
+/* Debug Registers */
+#define DEBUG00			0x05A0
+#define DEBUG01			0x05A4
+
+/* Panel CABC registers */
+#define PANEL_PWM_CONTROL	0x90
+#define PANEL_FREQ_DIVIDER_HI	0x91
+#define PANEL_FREQ_DIVIDER_LO	0x92
+#define PANEL_DUTY_CONTROL	0x93
+#define PANEL_MODIFY_RGB	0x94
+#define PANEL_FRAMERATE_CONTROL	0x96
+#define PANEL_PWM_MIN		0x97
+#define PANEL_PWM_REF		0x98
+#define PANEL_PWM_MAX		0x99
+#define PANEL_ALLOW_DISTORT	0x9A
+#define PANEL_BYPASS_PWMI	0x9B
+
+/* Panel color management registers */
+#define PANEL_CM_ENABLE		0x700
+#define PANEL_CM_HUE		0x701
+#define PANEL_CM_SATURATION	0x702
+#define PANEL_CM_INTENSITY	0x703
+#define PANEL_CM_BRIGHTNESS	0x704
+#define PANEL_CM_CE_ENABLE	0x705
+#define PANEL_CM_PEAK_EN	0x710
+#define PANEL_CM_GAIN		0x711
+#define PANEL_CM_HUETABLE_START	0x730
+#define PANEL_CM_HUETABLE_END	0x747 /* inclusive */
+
+/* Input muxing for registers LVMX0003...LVMX2427 */
+enum {
+	INPUT_R0,	/* 0 */
+	INPUT_R1,
+	INPUT_R2,
+	INPUT_R3,
+	INPUT_R4,
+	INPUT_R5,
+	INPUT_R6,
+	INPUT_R7,
+	INPUT_G0,	/* 8 */
+	INPUT_G1,
+	INPUT_G2,
+	INPUT_G3,
+	INPUT_G4,
+	INPUT_G5,
+	INPUT_G6,
+	INPUT_G7,
+	INPUT_B0,	/* 16 */
+	INPUT_B1,
+	INPUT_B2,
+	INPUT_B3,
+	INPUT_B4,
+	INPUT_B5,
+	INPUT_B6,
+	INPUT_B7,
+	INPUT_HSYNC,	/* 24 */
+	INPUT_VSYNC,
+	INPUT_DE,
+	LOGIC_0,
+	/* 28...31 undefined */
+};
+
+#define INPUT_MUX(lvmx03, lvmx02, lvmx01, lvmx00)		\
+	(FLD_VAL(lvmx03, 29, 24) | FLD_VAL(lvmx02, 20, 16) |	\
+	FLD_VAL(lvmx01, 12, 8) | FLD_VAL(lvmx00, 4, 0))
+
+/**
+ * tc35876x_regw - Write DSI-LVDS bridge register using I2C
+ * @client: struct i2c_client to use
+ * @reg: register address
+ * @value: value to write
+ *
+ * Returns 0 on success, or a negative error value.
+ */
+static int tc35876x_regw(struct i2c_client *client, u16 reg, u32 value)
+{
+	int r;
+	u8 tx_data[] = {
+		/* NOTE: Register address big-endian, data little-endian. */
+		(reg >> 8) & 0xff,
+		reg & 0xff,
+		value & 0xff,
+		(value >> 8) & 0xff,
+		(value >> 16) & 0xff,
+		(value >> 24) & 0xff,
+	};
+	struct i2c_msg msgs[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.buf = tx_data,
+			.len = ARRAY_SIZE(tx_data),
+		},
+	};
+
+	r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (r < 0) {
+		dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x error %d\n",
+			__func__, reg, value, r);
+		return r;
+	}
+
+	if (r < ARRAY_SIZE(msgs)) {
+		dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x msgs %d\n",
+			__func__, reg, value, r);
+		return -EAGAIN;
+	}
+
+	dev_dbg(&client->dev, "%s: reg 0x%04x val 0x%08x\n",
+			__func__, reg, value);
+
+	return 0;
+}
+
+/**
+ * tc35876x_regr - Read DSI-LVDS bridge register using I2C
+ * @client: struct i2c_client to use
+ * @reg: register address
+ * @value: pointer for storing the value
+ *
+ * Returns 0 on success, or a negative error value.
+ */
+static int tc35876x_regr(struct i2c_client *client, u16 reg, u32 *value)
+{
+	int r;
+	u8 tx_data[] = {
+		(reg >> 8) & 0xff,
+		reg & 0xff,
+	};
+	u8 rx_data[4];
+	struct i2c_msg msgs[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.buf = tx_data,
+			.len = ARRAY_SIZE(tx_data),
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.buf = rx_data,
+			.len = ARRAY_SIZE(rx_data),
+		 },
+	};
+
+	r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (r < 0) {
+		dev_err(&client->dev, "%s: reg 0x%04x error %d\n", __func__,
+			reg, r);
+		return r;
+	}
+
+	if (r < ARRAY_SIZE(msgs)) {
+		dev_err(&client->dev, "%s: reg 0x%04x msgs %d\n", __func__,
+			reg, r);
+		return -EAGAIN;
+	}
+
+	*value = rx_data[0] << 24 | rx_data[1] << 16 |
+		rx_data[2] << 8 | rx_data[3];
+
+	dev_dbg(&client->dev, "%s: reg 0x%04x value 0x%08x\n", __func__,
+		reg, *value);
+
+	return 0;
+}
+
+void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state)
+{
+	struct tc35876x_platform_data *pdata;
+
+	if (WARN(!tc35876x_client, "%s called before probe", __func__))
+		return;
+
+	dev_dbg(&tc35876x_client->dev, "%s: state %d\n", __func__, state);
+
+	pdata = dev_get_platdata(&tc35876x_client->dev);
+
+	if (pdata->gpio_bridge_reset == -1)
+		return;
+
+	if (state) {
+		gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0);
+		mdelay(10);
+	} else {
+		/* Pull MIPI Bridge reset pin to Low */
+		gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0);
+		mdelay(20);
+		/* Pull MIPI Bridge reset pin to High */
+		gpio_set_value_cansleep(pdata->gpio_bridge_reset, 1);
+		mdelay(40);
+	}
+}
+
+void tc35876x_configure_lvds_bridge(struct drm_device *dev)
+{
+	struct i2c_client *i2c = tc35876x_client;
+	u32 ppi_lptxtimecnt;
+	u32 txtagocnt;
+	u32 txtasurecnt;
+	u32 id;
+
+	if (WARN(!tc35876x_client, "%s called before probe", __func__))
+		return;
+
+	dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
+
+	if (!tc35876x_regr(i2c, IDREG, &id))
+		dev_info(&tc35876x_client->dev, "tc35876x ID 0x%08x\n", id);
+	else
+		dev_err(&tc35876x_client->dev, "Cannot read ID\n");
+
+	ppi_lptxtimecnt = 4;
+	txtagocnt = (5 * ppi_lptxtimecnt - 3) / 4;
+	txtasurecnt = 3 * ppi_lptxtimecnt / 2;
+	tc35876x_regw(i2c, PPI_TX_RX_TA, FLD_VAL(txtagocnt, 26, 16) |
+		FLD_VAL(txtasurecnt, 10, 0));
+	tc35876x_regw(i2c, PPI_LPTXTIMECNT, FLD_VAL(ppi_lptxtimecnt, 10, 0));
+
+	tc35876x_regw(i2c, PPI_D0S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
+	tc35876x_regw(i2c, PPI_D1S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
+	tc35876x_regw(i2c, PPI_D2S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
+	tc35876x_regw(i2c, PPI_D3S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
+
+	/* Enabling MIPI & PPI lanes, Enable 4 lanes */
+	tc35876x_regw(i2c, PPI_LANEENABLE,
+		BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0));
+	tc35876x_regw(i2c, DSI_LANEENABLE,
+		BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0));
+	tc35876x_regw(i2c, PPI_STARTPPI, BIT(0));
+	tc35876x_regw(i2c, DSI_STARTDSI, BIT(0));
+
+	/* Setting LVDS output frequency */
+	tc35876x_regw(i2c, LVPHY0, FLD_VAL(1, 20, 16) |
+		FLD_VAL(2, 15, 14) | FLD_VAL(6, 4, 0)); /* 0x00048006 */
+
+	/* Setting video panel control register,0x00000120 VTGen=ON ?!?!? */
+	tc35876x_regw(i2c, VPCTRL, BIT(8) | BIT(5));
+
+	/* Horizontal back porch and horizontal pulse width. 0x00280028 */
+	tc35876x_regw(i2c, HTIM1, FLD_VAL(40, 24, 16) | FLD_VAL(40, 8, 0));
+
+	/* Horizontal front porch and horizontal active video size. 0x00500500*/
+	tc35876x_regw(i2c, HTIM2, FLD_VAL(80, 24, 16) | FLD_VAL(1280, 10, 0));
+
+	/* Vertical back porch and vertical sync pulse width. 0x000e000a */
+	tc35876x_regw(i2c, VTIM1, FLD_VAL(14, 23, 16) | FLD_VAL(10, 7, 0));
+
+	/* Vertical front porch and vertical display size. 0x000e0320 */
+	tc35876x_regw(i2c, VTIM2, FLD_VAL(14, 23, 16) | FLD_VAL(800, 10, 0));
+
+	/* Set above HTIM1, HTIM2, VTIM1, and VTIM2 at next VSYNC. */
+	tc35876x_regw(i2c, VFUEN, BIT(0));
+
+	/* Soft reset LCD controller. */
+	tc35876x_regw(i2c, SYSRST, BIT(2));
+
+	/* LVDS-TX input muxing */
+	tc35876x_regw(i2c, LVMX0003,
+		INPUT_MUX(INPUT_R5, INPUT_R4, INPUT_R3, INPUT_R2));
+	tc35876x_regw(i2c, LVMX0407,
+		INPUT_MUX(INPUT_G2, INPUT_R7, INPUT_R1, INPUT_R6));
+	tc35876x_regw(i2c, LVMX0811,
+		INPUT_MUX(INPUT_G1, INPUT_G0, INPUT_G4, INPUT_G3));
+	tc35876x_regw(i2c, LVMX1215,
+		INPUT_MUX(INPUT_B2, INPUT_G7, INPUT_G6, INPUT_G5));
+	tc35876x_regw(i2c, LVMX1619,
+		INPUT_MUX(INPUT_B4, INPUT_B3, INPUT_B1, INPUT_B0));
+	tc35876x_regw(i2c, LVMX2023,
+		INPUT_MUX(LOGIC_0,  INPUT_B7, INPUT_B6, INPUT_B5));
+	tc35876x_regw(i2c, LVMX2427,
+		INPUT_MUX(INPUT_R0, INPUT_DE, INPUT_VSYNC, INPUT_HSYNC));
+
+	/* Enable LVDS transmitter. */
+	tc35876x_regw(i2c, LVCFG, BIT(0));
+
+	/* Clear notifications. Don't write reserved bits. Was write 0xffffffff
+	 * to 0x0288, must be in error?! */
+	tc35876x_regw(i2c, DSI_INTCLR, FLD_MASK(31, 30) | FLD_MASK(22, 0));
+}
+
+#define GPIOPWMCTRL	0x38F
+#define PWM0CLKDIV0	0x62 /* low byte */
+#define PWM0CLKDIV1	0x61 /* high byte */
+
+#define SYSTEMCLK	19200000UL /* 19.2 MHz */
+#define PWM_FREQUENCY	9600 /* Hz */
+
+/* f = baseclk / (clkdiv + 1) => clkdiv = (baseclk - f) / f */
+static inline u16 calc_clkdiv(unsigned long baseclk, unsigned int f)
+{
+	return (baseclk - f) / f;
+}
+
+static void tc35876x_brightness_init(struct drm_device *dev)
+{
+	int ret;
+	u8 pwmctrl;
+	u16 clkdiv;
+
+	/* Make sure the PWM reference is the 19.2 MHz system clock. Read first
+	 * instead of setting directly to catch potential conflicts between PWM
+	 * users. */
+	ret = intel_scu_ipc_ioread8(GPIOPWMCTRL, &pwmctrl);
+	if (ret || pwmctrl != 0x01) {
+		if (ret)
+			dev_err(&dev->pdev->dev, "GPIOPWMCTRL read failed\n");
+		else
+			dev_warn(&dev->pdev->dev, "GPIOPWMCTRL was not set to system clock (pwmctrl = 0x%02x)\n", pwmctrl);
+
+		ret = intel_scu_ipc_iowrite8(GPIOPWMCTRL, 0x01);
+		if (ret)
+			dev_err(&dev->pdev->dev, "GPIOPWMCTRL set failed\n");
+	}
+
+	clkdiv = calc_clkdiv(SYSTEMCLK, PWM_FREQUENCY);
+
+	ret = intel_scu_ipc_iowrite8(PWM0CLKDIV1, (clkdiv >> 8) & 0xff);
+	if (!ret)
+		ret = intel_scu_ipc_iowrite8(PWM0CLKDIV0, clkdiv & 0xff);
+
+	if (ret)
+		dev_err(&dev->pdev->dev, "PWM0CLKDIV set failed\n");
+	else
+		dev_dbg(&dev->pdev->dev, "PWM0CLKDIV set to 0x%04x (%d Hz)\n",
+			clkdiv, PWM_FREQUENCY);
+}
+
+#define PWM0DUTYCYCLE			0x67
+
+void tc35876x_brightness_control(struct drm_device *dev, int level)
+{
+	int ret;
+	u8 duty_val;
+	u8 panel_duty_val;
+
+	level = clamp(level, 0, MDFLD_DSI_BRIGHTNESS_MAX_LEVEL);
+
+	/* PWM duty cycle 0x00...0x63 corresponds to 0...99% */
+	duty_val = level * 0x63 / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL;
+
+	/* I won't pretend to understand this formula. The panel spec is quite
+	 * bad engrish.
+	 */
+	panel_duty_val = (2 * level - 100) * 0xA9 /
+			 MDFLD_DSI_BRIGHTNESS_MAX_LEVEL + 0x56;
+
+	ret = intel_scu_ipc_iowrite8(PWM0DUTYCYCLE, duty_val);
+	if (ret)
+		dev_err(&tc35876x_client->dev, "%s: ipc write fail\n",
+			__func__);
+
+	if (cmi_lcd_i2c_client) {
+		ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
+						PANEL_PWM_MAX, panel_duty_val);
+		if (ret < 0)
+			dev_err(&cmi_lcd_i2c_client->dev, "%s: i2c write failed\n",
+				__func__);
+	}
+}
+
+void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev)
+{
+	struct tc35876x_platform_data *pdata;
+
+	if (WARN(!tc35876x_client, "%s called before probe", __func__))
+		return;
+
+	dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
+
+	pdata = dev_get_platdata(&tc35876x_client->dev);
+
+	if (pdata->gpio_panel_bl_en != -1)
+		gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 0);
+
+	if (pdata->gpio_panel_vadd != -1)
+		gpio_set_value_cansleep(pdata->gpio_panel_vadd, 0);
+}
+
+void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev)
+{
+	struct tc35876x_platform_data *pdata;
+	struct drm_psb_private *dev_priv = dev->dev_private;
+
+	if (WARN(!tc35876x_client, "%s called before probe", __func__))
+		return;
+
+	dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
+
+	pdata = dev_get_platdata(&tc35876x_client->dev);
+
+	if (pdata->gpio_panel_vadd != -1) {
+		gpio_set_value_cansleep(pdata->gpio_panel_vadd, 1);
+		msleep(260);
+	}
+
+	if (cmi_lcd_i2c_client) {
+		int ret;
+		dev_dbg(&cmi_lcd_i2c_client->dev, "setting TCON\n");
+		/* Bit 4 is average_saving. Setting it to 1, the brightness is
+		 * referenced to the average of the frame content. 0 means
+		 * reference to the maximum of frame contents. Bits 3:0 are
+		 * allow_distort. When set to a nonzero value, all color values
+		 * between 255-allow_distort*2 and 255 are mapped to the
+		 * 255-allow_distort*2 value.
+		 */
+		ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
+						PANEL_ALLOW_DISTORT, 0x10);
+		if (ret < 0)
+			dev_err(&cmi_lcd_i2c_client->dev,
+				"i2c write failed (%d)\n", ret);
+		ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
+						PANEL_BYPASS_PWMI, 0);
+		if (ret < 0)
+			dev_err(&cmi_lcd_i2c_client->dev,
+				"i2c write failed (%d)\n", ret);
+		/* Set minimum brightness value - this is tunable */
+		ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
+						PANEL_PWM_MIN, 0x35);
+		if (ret < 0)
+			dev_err(&cmi_lcd_i2c_client->dev,
+				"i2c write failed (%d)\n", ret);
+	}
+
+	if (pdata->gpio_panel_bl_en != -1)
+		gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 1);
+
+	tc35876x_brightness_control(dev, dev_priv->brightness_adjusted);
+}
+
+static struct drm_display_mode *tc35876x_get_config_mode(struct drm_device *dev)
+{
+	struct drm_display_mode *mode;
+
+	dev_dbg(&dev->pdev->dev, "%s\n", __func__);
+
+	mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+	if (!mode)
+		return NULL;
+
+	/* FIXME: do this properly. */
+	mode->hdisplay = 1280;
+	mode->vdisplay = 800;
+	mode->hsync_start = 1360;
+	mode->hsync_end = 1400;
+	mode->htotal = 1440;
+	mode->vsync_start = 814;
+	mode->vsync_end = 824;
+	mode->vtotal = 838;
+	mode->clock = 33324 << 1;
+
+	dev_info(&dev->pdev->dev, "hdisplay(w) = %d\n", mode->hdisplay);
+	dev_info(&dev->pdev->dev, "vdisplay(h) = %d\n", mode->vdisplay);
+	dev_info(&dev->pdev->dev, "HSS = %d\n", mode->hsync_start);
+	dev_info(&dev->pdev->dev, "HSE = %d\n", mode->hsync_end);
+	dev_info(&dev->pdev->dev, "htotal = %d\n", mode->htotal);
+	dev_info(&dev->pdev->dev, "VSS = %d\n", mode->vsync_start);
+	dev_info(&dev->pdev->dev, "VSE = %d\n", mode->vsync_end);
+	dev_info(&dev->pdev->dev, "vtotal = %d\n", mode->vtotal);
+	dev_info(&dev->pdev->dev, "clock = %d\n", mode->clock);
+
+	drm_mode_set_name(mode);
+	drm_mode_set_crtcinfo(mode, 0);
+
+	mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+	return mode;
+}
+
+/* DV1 Active area 216.96 x 135.6 mm */
+#define DV1_PANEL_WIDTH 217
+#define DV1_PANEL_HEIGHT 136
+
+static int tc35876x_get_panel_info(struct drm_device *dev, int pipe,
+				struct panel_info *pi)
+{
+	if (!dev || !pi)
+		return -EINVAL;
+
+	pi->width_mm = DV1_PANEL_WIDTH;
+	pi->height_mm = DV1_PANEL_HEIGHT;
+
+	return 0;
+}
+
+static int tc35876x_bridge_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	struct tc35876x_platform_data *pdata;
+
+	dev_info(&client->dev, "%s\n", __func__);
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "%s: i2c_check_functionality() failed\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	pdata = dev_get_platdata(&client->dev);
+	if (!pdata) {
+		dev_err(&client->dev, "%s: no platform data\n", __func__);
+		return -ENODEV;
+	}
+
+	if (pdata->gpio_bridge_reset != -1) {
+		gpio_request(pdata->gpio_bridge_reset, "tc35876x bridge reset");
+		gpio_direction_output(pdata->gpio_bridge_reset, 0);
+	}
+
+	if (pdata->gpio_panel_bl_en != -1) {
+		gpio_request(pdata->gpio_panel_bl_en, "tc35876x panel bl en");
+		gpio_direction_output(pdata->gpio_panel_bl_en, 0);
+	}
+
+	if (pdata->gpio_panel_vadd != -1) {
+		gpio_request(pdata->gpio_panel_vadd, "tc35876x panel vadd");
+		gpio_direction_output(pdata->gpio_panel_vadd, 0);
+	}
+
+	tc35876x_client = client;
+
+	return 0;
+}
+
+static int tc35876x_bridge_remove(struct i2c_client *client)
+{
+	struct tc35876x_platform_data *pdata = dev_get_platdata(&client->dev);
+
+	dev_dbg(&client->dev, "%s\n", __func__);
+
+	if (pdata->gpio_bridge_reset != -1)
+		gpio_free(pdata->gpio_bridge_reset);
+
+	if (pdata->gpio_panel_bl_en != -1)
+		gpio_free(pdata->gpio_panel_bl_en);
+
+	if (pdata->gpio_panel_vadd != -1)
+		gpio_free(pdata->gpio_panel_vadd);
+
+	tc35876x_client = NULL;
+
+	return 0;
+}
+
+static const struct i2c_device_id tc35876x_bridge_id[] = {
+	{ "i2c_disp_brig", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tc35876x_bridge_id);
+
+static struct i2c_driver tc35876x_bridge_i2c_driver = {
+	.driver = {
+		.name = "i2c_disp_brig",
+	},
+	.id_table = tc35876x_bridge_id,
+	.probe = tc35876x_bridge_probe,
+	.remove = __devexit_p(tc35876x_bridge_remove),
+};
+
+/* LCD panel I2C */
+static int cmi_lcd_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	dev_info(&client->dev, "%s\n", __func__);
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "%s: i2c_check_functionality() failed\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	cmi_lcd_i2c_client = client;
+
+	return 0;
+}
+
+static int cmi_lcd_i2c_remove(struct i2c_client *client)
+{
+	dev_dbg(&client->dev, "%s\n", __func__);
+
+	cmi_lcd_i2c_client = NULL;
+
+	return 0;
+}
+
+static const struct i2c_device_id cmi_lcd_i2c_id[] = {
+	{ "cmi-lcd", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cmi_lcd_i2c_id);
+
+static struct i2c_driver cmi_lcd_i2c_driver = {
+	.driver = {
+		.name = "cmi-lcd",
+	},
+	.id_table = cmi_lcd_i2c_id,
+	.probe = cmi_lcd_i2c_probe,
+	.remove = __devexit_p(cmi_lcd_i2c_remove),
+};
+
+/* HACK to create I2C device while it's not created by platform code */
+#define CMI_LCD_I2C_ADAPTER	2
+#define CMI_LCD_I2C_ADDR	0x60
+
+static int cmi_lcd_hack_create_device(void)
+{
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	struct i2c_board_info info = {
+		.type = "cmi-lcd",
+		.addr = CMI_LCD_I2C_ADDR,
+	};
+
+	pr_debug("%s\n", __func__);
+
+	adapter = i2c_get_adapter(CMI_LCD_I2C_ADAPTER);
+	if (!adapter) {
+		pr_err("%s: i2c_get_adapter(%d) failed\n", __func__,
+			CMI_LCD_I2C_ADAPTER);
+		return -EINVAL;
+	}
+
+	client = i2c_new_device(adapter, &info);
+	if (!client) {
+		pr_err("%s: i2c_new_device() failed\n", __func__);
+		i2c_put_adapter(adapter);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct drm_encoder_helper_funcs tc35876x_encoder_helper_funcs = {
+	.dpms = mdfld_dsi_dpi_dpms,
+	.mode_fixup = mdfld_dsi_dpi_mode_fixup,
+	.prepare = mdfld_dsi_dpi_prepare,
+	.mode_set = mdfld_dsi_dpi_mode_set,
+	.commit = mdfld_dsi_dpi_commit,
+};
+
+static const struct drm_encoder_funcs tc35876x_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+const struct panel_funcs mdfld_tc35876x_funcs = {
+	.encoder_funcs = &tc35876x_encoder_funcs,
+	.encoder_helper_funcs = &tc35876x_encoder_helper_funcs,
+	.get_config_mode = tc35876x_get_config_mode,
+	.get_panel_info = tc35876x_get_panel_info,
+};
+
+void tc35876x_init(struct drm_device *dev)
+{
+	int r;
+
+	dev_dbg(&dev->pdev->dev, "%s\n", __func__);
+
+	cmi_lcd_hack_create_device();
+
+	r = i2c_add_driver(&cmi_lcd_i2c_driver);
+	if (r < 0)
+		dev_err(&dev->pdev->dev,
+			"%s: i2c_add_driver() for %s failed (%d)\n",
+			__func__, cmi_lcd_i2c_driver.driver.name, r);
+
+	r = i2c_add_driver(&tc35876x_bridge_i2c_driver);
+	if (r < 0)
+		dev_err(&dev->pdev->dev,
+			"%s: i2c_add_driver() for %s failed (%d)\n",
+			__func__, tc35876x_bridge_i2c_driver.driver.name, r);
+
+	tc35876x_brightness_init(dev);
+}
+
+void tc35876x_exit(void)
+{
+	pr_debug("%s\n", __func__);
+
+	i2c_del_driver(&tc35876x_bridge_i2c_driver);
+
+	if (cmi_lcd_i2c_client)
+		i2c_del_driver(&cmi_lcd_i2c_driver);
+}
diff --git a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.h b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.h
new file mode 100644
index 0000000..b14b7f9
--- /dev/null
+++ b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __MDFLD_DSI_LVDS_BRIDGE_H__
+#define __MDFLD_DSI_LVDS_BRIDGE_H__
+
+void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state);
+void tc35876x_configure_lvds_bridge(struct drm_device *dev);
+void tc35876x_brightness_control(struct drm_device *dev, int level);
+void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev);
+void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev);
+void tc35876x_init(struct drm_device *dev);
+void tc35876x_exit(void);
+
+extern const struct panel_funcs mdfld_tc35876x_funcs;
+
+#endif /*__MDFLD_DSI_LVDS_BRIDGE_H__*/
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
index 07d55df..d3f2e87 100644
--- a/drivers/gpu/drm/i2c/ch7006_drv.c
+++ b/drivers/gpu/drm/i2c/ch7006_drv.c
@@ -252,10 +252,7 @@
 
 	drm_mode_create_tv_properties(dev, NUM_TV_NORMS, ch7006_tv_norm_names);
 
-	priv->scale_property = drm_property_create(dev, DRM_MODE_PROP_RANGE,
-						   "scale", 2);
-	priv->scale_property->values[0] = 0;
-	priv->scale_property->values[1] = 2;
+	priv->scale_property = drm_property_create_range(dev, 0, "scale", 0, 2);
 
 	drm_connector_attach_property(connector, conf->tv_select_subconnector_property,
 				      priv->select_subconnector);
diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c
index 7f4b4e1..2c8a60c 100644
--- a/drivers/gpu/drm/i810/i810_dma.c
+++ b/drivers/gpu/drm/i810/i810_dma.c
@@ -99,7 +99,6 @@
 	buf_priv = buf->dev_private;
 
 	vma->vm_flags |= (VM_IO | VM_DONTCOPY);
-	vma->vm_file = filp;
 
 	buf_priv->currently_mapped = I810_BUF_MAPPED;
 
@@ -1208,6 +1207,8 @@
 	dev->types[8] = _DRM_STAT_SECONDARY;
 	dev->types[9] = _DRM_STAT_DMA;
 
+	pci_set_master(dev->pdev);
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 808b255..ce7fc77 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -3,7 +3,7 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 ccflags-y := -Iinclude/drm
-i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
+i915-y := i915_drv.o i915_dma.o i915_irq.o \
 	  i915_debugfs.o \
           i915_suspend.o \
 	  i915_gem.o \
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index deaa657..b505b70 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -83,6 +83,7 @@
 	B(supports_tv);
 	B(has_bsd_ring);
 	B(has_blt_ring);
+	B(has_llc);
 #undef B
 
 	return 0;
@@ -563,45 +564,6 @@
 	return 0;
 }
 
-static void i915_dump_object(struct seq_file *m,
-			     struct io_mapping *mapping,
-			     struct drm_i915_gem_object *obj)
-{
-	int page, page_count, i;
-
-	page_count = obj->base.size / PAGE_SIZE;
-	for (page = 0; page < page_count; page++) {
-		u32 *mem = io_mapping_map_wc(mapping,
-					     obj->gtt_offset + page * PAGE_SIZE);
-		for (i = 0; i < PAGE_SIZE; i += 4)
-			seq_printf(m, "%08x :  %08x\n", i, mem[i / 4]);
-		io_mapping_unmap(mem);
-	}
-}
-
-static int i915_batchbuffer_info(struct seq_file *m, void *data)
-{
-	struct drm_info_node *node = (struct drm_info_node *) m->private;
-	struct drm_device *dev = node->minor->dev;
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	struct drm_i915_gem_object *obj;
-	int ret;
-
-	ret = mutex_lock_interruptible(&dev->struct_mutex);
-	if (ret)
-		return ret;
-
-	list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
-		if (obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) {
-		    seq_printf(m, "--- gtt_offset = 0x%08x\n", obj->gtt_offset);
-		    i915_dump_object(m, dev_priv->mm.gtt_mapping, obj);
-		}
-	}
-
-	mutex_unlock(&dev->struct_mutex);
-	return 0;
-}
-
 static int i915_ringbuffer_data(struct seq_file *m, void *data)
 {
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -668,9 +630,9 @@
 static const char *ring_str(int ring)
 {
 	switch (ring) {
-	case RING_RENDER: return " render";
-	case RING_BSD: return " bsd";
-	case RING_BLT: return " blt";
+	case RCS: return "render";
+	case VCS: return "bsd";
+	case BCS: return "blt";
 	default: return "";
 	}
 }
@@ -713,7 +675,7 @@
 	seq_printf(m, "%s [%d]:\n", name, count);
 
 	while (count--) {
-		seq_printf(m, "  %08x %8u %04x %04x %08x%s%s%s%s%s%s",
+		seq_printf(m, "  %08x %8u %04x %04x %08x%s%s%s%s%s%s%s",
 			   err->gtt_offset,
 			   err->size,
 			   err->read_domains,
@@ -723,6 +685,7 @@
 			   tiling_flag(err->tiling),
 			   dirty_flag(err->dirty),
 			   purgeable_flag(err->purgeable),
+			   err->ring != -1 ? " " : "",
 			   ring_str(err->ring),
 			   cache_level_str(err->cache_level));
 
@@ -736,6 +699,38 @@
 	}
 }
 
+static void i915_ring_error_state(struct seq_file *m,
+				  struct drm_device *dev,
+				  struct drm_i915_error_state *error,
+				  unsigned ring)
+{
+	seq_printf(m, "%s command stream:\n", ring_str(ring));
+	seq_printf(m, "  HEAD: 0x%08x\n", error->head[ring]);
+	seq_printf(m, "  TAIL: 0x%08x\n", error->tail[ring]);
+	seq_printf(m, "  ACTHD: 0x%08x\n", error->acthd[ring]);
+	seq_printf(m, "  IPEIR: 0x%08x\n", error->ipeir[ring]);
+	seq_printf(m, "  IPEHR: 0x%08x\n", error->ipehr[ring]);
+	seq_printf(m, "  INSTDONE: 0x%08x\n", error->instdone[ring]);
+	if (ring == RCS && INTEL_INFO(dev)->gen >= 4) {
+		seq_printf(m, "  INSTDONE1: 0x%08x\n", error->instdone1);
+		seq_printf(m, "  BBADDR: 0x%08llx\n", error->bbaddr);
+	}
+	if (INTEL_INFO(dev)->gen >= 4)
+		seq_printf(m, "  INSTPS: 0x%08x\n", error->instps[ring]);
+	seq_printf(m, "  INSTPM: 0x%08x\n", error->instpm[ring]);
+	if (INTEL_INFO(dev)->gen >= 6) {
+		seq_printf(m, "  FADDR: 0x%08x\n", error->faddr[ring]);
+		seq_printf(m, "  FAULT_REG: 0x%08x\n", error->fault_reg[ring]);
+		seq_printf(m, "  SYNC_0: 0x%08x\n",
+			   error->semaphore_mboxes[ring][0]);
+		seq_printf(m, "  SYNC_1: 0x%08x\n",
+			   error->semaphore_mboxes[ring][1]);
+	}
+	seq_printf(m, "  seqno: 0x%08x\n", error->seqno[ring]);
+	seq_printf(m, "  ring->head: 0x%08x\n", error->cpu_ring_head[ring]);
+	seq_printf(m, "  ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]);
+}
+
 static int i915_error_state(struct seq_file *m, void *unused)
 {
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -743,7 +738,7 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_error_state *error;
 	unsigned long flags;
-	int i, page, offset, elt;
+	int i, j, page, offset, elt;
 
 	spin_lock_irqsave(&dev_priv->error_lock, flags);
 	if (!dev_priv->first_error) {
@@ -758,36 +753,21 @@
 	seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
 	seq_printf(m, "EIR: 0x%08x\n", error->eir);
 	seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er);
-	if (INTEL_INFO(dev)->gen >= 6) {
-		seq_printf(m, "ERROR: 0x%08x\n", error->error);
-		seq_printf(m, "Blitter command stream:\n");
-		seq_printf(m, "  ACTHD:    0x%08x\n", error->bcs_acthd);
-		seq_printf(m, "  IPEIR:    0x%08x\n", error->bcs_ipeir);
-		seq_printf(m, "  IPEHR:    0x%08x\n", error->bcs_ipehr);
-		seq_printf(m, "  INSTDONE: 0x%08x\n", error->bcs_instdone);
-		seq_printf(m, "  seqno:    0x%08x\n", error->bcs_seqno);
-		seq_printf(m, "Video (BSD) command stream:\n");
-		seq_printf(m, "  ACTHD:    0x%08x\n", error->vcs_acthd);
-		seq_printf(m, "  IPEIR:    0x%08x\n", error->vcs_ipeir);
-		seq_printf(m, "  IPEHR:    0x%08x\n", error->vcs_ipehr);
-		seq_printf(m, "  INSTDONE: 0x%08x\n", error->vcs_instdone);
-		seq_printf(m, "  seqno:    0x%08x\n", error->vcs_seqno);
-	}
-	seq_printf(m, "Render command stream:\n");
-	seq_printf(m, "  ACTHD: 0x%08x\n", error->acthd);
-	seq_printf(m, "  IPEIR: 0x%08x\n", error->ipeir);
-	seq_printf(m, "  IPEHR: 0x%08x\n", error->ipehr);
-	seq_printf(m, "  INSTDONE: 0x%08x\n", error->instdone);
-	if (INTEL_INFO(dev)->gen >= 4) {
-		seq_printf(m, "  INSTDONE1: 0x%08x\n", error->instdone1);
-		seq_printf(m, "  INSTPS: 0x%08x\n", error->instps);
-	}
-	seq_printf(m, "  INSTPM: 0x%08x\n", error->instpm);
-	seq_printf(m, "  seqno: 0x%08x\n", error->seqno);
 
 	for (i = 0; i < dev_priv->num_fence_regs; i++)
 		seq_printf(m, "  fence[%d] = %08llx\n", i, error->fence[i]);
 
+	if (INTEL_INFO(dev)->gen >= 6) {
+		seq_printf(m, "ERROR: 0x%08x\n", error->error);
+		seq_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
+	}
+
+	i915_ring_error_state(m, dev, error, RCS);
+	if (HAS_BLT(dev))
+		i915_ring_error_state(m, dev, error, BCS);
+	if (HAS_BSD(dev))
+		i915_ring_error_state(m, dev, error, VCS);
+
 	if (error->active_bo)
 		print_error_buffers(m, "Active",
 				    error->active_bo,
@@ -798,10 +778,10 @@
 				    error->pinned_bo,
 				    error->pinned_bo_count);
 
-	for (i = 0; i < ARRAY_SIZE(error->batchbuffer); i++) {
-		if (error->batchbuffer[i]) {
-			struct drm_i915_error_object *obj = error->batchbuffer[i];
+	for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
+		struct drm_i915_error_object *obj;
 
+		if ((obj = error->ring[i].batchbuffer)) {
 			seq_printf(m, "%s --- gtt_offset = 0x%08x\n",
 				   dev_priv->ring[i].name,
 				   obj->gtt_offset);
@@ -813,11 +793,20 @@
 				}
 			}
 		}
-	}
 
-	for (i = 0; i < ARRAY_SIZE(error->ringbuffer); i++) {
-		if (error->ringbuffer[i]) {
-			struct drm_i915_error_object *obj = error->ringbuffer[i];
+		if (error->ring[i].num_requests) {
+			seq_printf(m, "%s --- %d requests\n",
+				   dev_priv->ring[i].name,
+				   error->ring[i].num_requests);
+			for (j = 0; j < error->ring[i].num_requests; j++) {
+				seq_printf(m, "  seqno 0x%08x, emitted %ld, tail 0x%08x\n",
+					   error->ring[i].requests[j].seqno,
+					   error->ring[i].requests[j].jiffies,
+					   error->ring[i].requests[j].tail);
+			}
+		}
+
+		if ((obj = error->ring[i].ringbuffer)) {
 			seq_printf(m, "%s --- ringbuffer = 0x%08x\n",
 				   dev_priv->ring[i].name,
 				   obj->gtt_offset);
@@ -1414,11 +1403,102 @@
 	return 0;
 }
 
-static int
-i915_wedged_open(struct inode *inode,
-		 struct file *filp)
+static const char *swizzle_string(unsigned swizzle)
 {
-	filp->private_data = inode->i_private;
+	switch(swizzle) {
+	case I915_BIT_6_SWIZZLE_NONE:
+		return "none";
+	case I915_BIT_6_SWIZZLE_9:
+		return "bit9";
+	case I915_BIT_6_SWIZZLE_9_10:
+		return "bit9/bit10";
+	case I915_BIT_6_SWIZZLE_9_11:
+		return "bit9/bit11";
+	case I915_BIT_6_SWIZZLE_9_10_11:
+		return "bit9/bit10/bit11";
+	case I915_BIT_6_SWIZZLE_9_17:
+		return "bit9/bit17";
+	case I915_BIT_6_SWIZZLE_9_10_17:
+		return "bit9/bit10/bit17";
+	case I915_BIT_6_SWIZZLE_UNKNOWN:
+		return "unkown";
+	}
+
+	return "bug";
+}
+
+static int i915_swizzle_info(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	mutex_lock(&dev->struct_mutex);
+	seq_printf(m, "bit6 swizzle for X-tiling = %s\n",
+		   swizzle_string(dev_priv->mm.bit_6_swizzle_x));
+	seq_printf(m, "bit6 swizzle for Y-tiling = %s\n",
+		   swizzle_string(dev_priv->mm.bit_6_swizzle_y));
+
+	if (IS_GEN3(dev) || IS_GEN4(dev)) {
+		seq_printf(m, "DDC = 0x%08x\n",
+			   I915_READ(DCC));
+		seq_printf(m, "C0DRB3 = 0x%04x\n",
+			   I915_READ16(C0DRB3));
+		seq_printf(m, "C1DRB3 = 0x%04x\n",
+			   I915_READ16(C1DRB3));
+	} else if (IS_GEN6(dev) || IS_GEN7(dev)) {
+		seq_printf(m, "MAD_DIMM_C0 = 0x%08x\n",
+			   I915_READ(MAD_DIMM_C0));
+		seq_printf(m, "MAD_DIMM_C1 = 0x%08x\n",
+			   I915_READ(MAD_DIMM_C1));
+		seq_printf(m, "MAD_DIMM_C2 = 0x%08x\n",
+			   I915_READ(MAD_DIMM_C2));
+		seq_printf(m, "TILECTL = 0x%08x\n",
+			   I915_READ(TILECTL));
+		seq_printf(m, "ARB_MODE = 0x%08x\n",
+			   I915_READ(ARB_MODE));
+		seq_printf(m, "DISP_ARB_CTL = 0x%08x\n",
+			   I915_READ(DISP_ARB_CTL));
+	}
+	mutex_unlock(&dev->struct_mutex);
+
+	return 0;
+}
+
+static int i915_ppgtt_info(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_ring_buffer *ring;
+	int i, ret;
+
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
+	if (INTEL_INFO(dev)->gen == 6)
+		seq_printf(m, "GFX_MODE: 0x%08x\n", I915_READ(GFX_MODE));
+
+	for (i = 0; i < I915_NUM_RINGS; i++) {
+		ring = &dev_priv->ring[i];
+
+		seq_printf(m, "%s\n", ring->name);
+		if (INTEL_INFO(dev)->gen == 7)
+			seq_printf(m, "GFX_MODE: 0x%08x\n", I915_READ(RING_MODE_GEN7(ring)));
+		seq_printf(m, "PP_DIR_BASE: 0x%08x\n", I915_READ(RING_PP_DIR_BASE(ring)));
+		seq_printf(m, "PP_DIR_BASE_READ: 0x%08x\n", I915_READ(RING_PP_DIR_BASE_READ(ring)));
+		seq_printf(m, "PP_DIR_DCLV: 0x%08x\n", I915_READ(RING_PP_DIR_DCLV(ring)));
+	}
+	if (dev_priv->mm.aliasing_ppgtt) {
+		struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+
+		seq_printf(m, "aliasing PPGTT:\n");
+		seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd_offset);
+	}
+	seq_printf(m, "ECOCHK: 0x%08x\n", I915_READ(GAM_ECOCHK));
+	mutex_unlock(&dev->struct_mutex);
+
 	return 0;
 }
 
@@ -1472,20 +1552,12 @@
 
 static const struct file_operations i915_wedged_fops = {
 	.owner = THIS_MODULE,
-	.open = i915_wedged_open,
+	.open = simple_open,
 	.read = i915_wedged_read,
 	.write = i915_wedged_write,
 	.llseek = default_llseek,
 };
 
-static int
-i915_max_freq_open(struct inode *inode,
-		   struct file *filp)
-{
-	filp->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t
 i915_max_freq_read(struct file *filp,
 		   char __user *ubuf,
@@ -1542,20 +1614,12 @@
 
 static const struct file_operations i915_max_freq_fops = {
 	.owner = THIS_MODULE,
-	.open = i915_max_freq_open,
+	.open = simple_open,
 	.read = i915_max_freq_read,
 	.write = i915_max_freq_write,
 	.llseek = default_llseek,
 };
 
-static int
-i915_cache_sharing_open(struct inode *inode,
-		   struct file *filp)
-{
-	filp->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t
 i915_cache_sharing_read(struct file *filp,
 		   char __user *ubuf,
@@ -1621,7 +1685,7 @@
 
 static const struct file_operations i915_cache_sharing_fops = {
 	.owner = THIS_MODULE,
-	.open = i915_cache_sharing_open,
+	.open = simple_open,
 	.read = i915_cache_sharing_read,
 	.write = i915_cache_sharing_write,
 	.llseek = default_llseek,
@@ -1653,21 +1717,6 @@
 	return 0;
 }
 
-static int i915_wedged_create(struct dentry *root, struct drm_minor *minor)
-{
-	struct drm_device *dev = minor->dev;
-	struct dentry *ent;
-
-	ent = debugfs_create_file("i915_wedged",
-				  S_IRUGO | S_IWUSR,
-				  root, dev,
-				  &i915_wedged_fops);
-	if (IS_ERR(ent))
-		return PTR_ERR(ent);
-
-	return drm_add_fake_info_node(minor, ent, &i915_wedged_fops);
-}
-
 static int i915_forcewake_open(struct inode *inode, struct file *file)
 {
 	struct drm_device *dev = inode->i_private;
@@ -1729,34 +1778,22 @@
 	return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops);
 }
 
-static int i915_max_freq_create(struct dentry *root, struct drm_minor *minor)
+static int i915_debugfs_create(struct dentry *root,
+			       struct drm_minor *minor,
+			       const char *name,
+			       const struct file_operations *fops)
 {
 	struct drm_device *dev = minor->dev;
 	struct dentry *ent;
 
-	ent = debugfs_create_file("i915_max_freq",
+	ent = debugfs_create_file(name,
 				  S_IRUGO | S_IWUSR,
 				  root, dev,
-				  &i915_max_freq_fops);
+				  fops);
 	if (IS_ERR(ent))
 		return PTR_ERR(ent);
 
-	return drm_add_fake_info_node(minor, ent, &i915_max_freq_fops);
-}
-
-static int i915_cache_sharing_create(struct dentry *root, struct drm_minor *minor)
-{
-	struct drm_device *dev = minor->dev;
-	struct dentry *ent;
-
-	ent = debugfs_create_file("i915_cache_sharing",
-				  S_IRUGO | S_IWUSR,
-				  root, dev,
-				  &i915_cache_sharing_fops);
-	if (IS_ERR(ent))
-		return PTR_ERR(ent);
-
-	return drm_add_fake_info_node(minor, ent, &i915_cache_sharing_fops);
+	return drm_add_fake_info_node(minor, ent, fops);
 }
 
 static struct drm_info_list i915_debugfs_list[] = {
@@ -1782,7 +1819,6 @@
 	{"i915_bsd_ringbuffer_info", i915_ringbuffer_info, 0, (void *)VCS},
 	{"i915_blt_ringbuffer_data", i915_ringbuffer_data, 0, (void *)BCS},
 	{"i915_blt_ringbuffer_info", i915_ringbuffer_info, 0, (void *)BCS},
-	{"i915_batchbuffers", i915_batchbuffer_info, 0},
 	{"i915_error_state", i915_error_state, 0},
 	{"i915_rstdby_delays", i915_rstdby_delays, 0},
 	{"i915_cur_delayinfo", i915_cur_delayinfo, 0},
@@ -1798,6 +1834,8 @@
 	{"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
 	{"i915_context_status", i915_context_status, 0},
 	{"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0},
+	{"i915_swizzle_info", i915_swizzle_info, 0},
+	{"i915_ppgtt_info", i915_ppgtt_info, 0},
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
@@ -1805,17 +1843,25 @@
 {
 	int ret;
 
-	ret = i915_wedged_create(minor->debugfs_root, minor);
+	ret = i915_debugfs_create(minor->debugfs_root, minor,
+				  "i915_wedged",
+				  &i915_wedged_fops);
 	if (ret)
 		return ret;
 
 	ret = i915_forcewake_create(minor->debugfs_root, minor);
 	if (ret)
 		return ret;
-	ret = i915_max_freq_create(minor->debugfs_root, minor);
+
+	ret = i915_debugfs_create(minor->debugfs_root, minor,
+				  "i915_max_freq",
+				  &i915_max_freq_fops);
 	if (ret)
 		return ret;
-	ret = i915_cache_sharing_create(minor->debugfs_root, minor);
+
+	ret = i915_debugfs_create(minor->debugfs_root, minor,
+				  "i915_cache_sharing",
+				  &i915_cache_sharing_fops);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index ddfe3d9..785f67f 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -784,6 +784,9 @@
 	case I915_PARAM_HAS_GEN7_SOL_RESET:
 		value = 1;
 		break;
+	case I915_PARAM_HAS_LLC:
+		value = HAS_LLC(dev);
+		break;
 	default:
 		DRM_DEBUG_DRIVER("Unknown parameter %d\n",
 				 param->param);
@@ -1180,6 +1183,21 @@
 	return can_switch;
 }
 
+static bool
+intel_enable_ppgtt(struct drm_device *dev)
+{
+	if (i915_enable_ppgtt >= 0)
+		return i915_enable_ppgtt;
+
+#ifdef CONFIG_INTEL_IOMMU
+	/* Disable ppgtt on SNB if VT-d is on. */
+	if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped)
+		return false;
+#endif
+
+	return true;
+}
+
 static int i915_load_gem_init(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1193,22 +1211,41 @@
 	/* Basic memrange allocator for stolen space */
 	drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size);
 
-	/* Let GEM Manage all of the aperture.
-	 *
-	 * However, leave one page at the end still bound to the scratch page.
-	 * There are a number of places where the hardware apparently
-	 * prefetches past the end of the object, and we've seen multiple
-	 * hangs with the GPU head pointer stuck in a batchbuffer bound
-	 * at the last page of the aperture.  One page should be enough to
-	 * keep any prefetching inside of the aperture.
-	 */
-	i915_gem_do_init(dev, 0, mappable_size, gtt_size - PAGE_SIZE);
-
 	mutex_lock(&dev->struct_mutex);
-	ret = i915_gem_init_ringbuffer(dev);
+	if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) {
+		/* PPGTT pdes are stolen from global gtt ptes, so shrink the
+		 * aperture accordingly when using aliasing ppgtt. */
+		gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
+		/* For paranoia keep the guard page in between. */
+		gtt_size -= PAGE_SIZE;
+
+		i915_gem_do_init(dev, 0, mappable_size, gtt_size);
+
+		ret = i915_gem_init_aliasing_ppgtt(dev);
+		if (ret) {
+			mutex_unlock(&dev->struct_mutex);
+			return ret;
+		}
+	} else {
+		/* Let GEM Manage all of the aperture.
+		 *
+		 * However, leave one page at the end still bound to the scratch
+		 * page.  There are a number of places where the hardware
+		 * apparently prefetches past the end of the object, and we've
+		 * seen multiple hangs with the GPU head pointer stuck in a
+		 * batchbuffer bound at the last page of the aperture.  One page
+		 * should be enough to keep any prefetching inside of the
+		 * aperture.
+		 */
+		i915_gem_do_init(dev, 0, mappable_size, gtt_size - PAGE_SIZE);
+	}
+
+	ret = i915_gem_init_hw(dev);
 	mutex_unlock(&dev->struct_mutex);
-	if (ret)
+	if (ret) {
+		i915_gem_cleanup_aliasing_ppgtt(dev);
 		return ret;
+	}
 
 	/* Try to set up FBC with a reasonable compressed buffer size */
 	if (I915_HAS_FBC(dev) && i915_powersave) {
@@ -1295,6 +1332,7 @@
 	mutex_lock(&dev->struct_mutex);
 	i915_gem_cleanup_ringbuffer(dev);
 	mutex_unlock(&dev->struct_mutex);
+	i915_gem_cleanup_aliasing_ppgtt(dev);
 cleanup_vga_switcheroo:
 	vga_switcheroo_unregister_client(dev->pdev);
 cleanup_vga_client:
@@ -1930,6 +1968,8 @@
 		goto free_priv;
 	}
 
+	pci_set_master(dev->pdev);
+
 	/* overlay on gen2 is broken and can't address above 1G */
 	if (IS_GEN2(dev))
 		dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30));
@@ -2129,7 +2169,7 @@
 		unregister_shrinker(&dev_priv->mm.inactive_shrinker);
 
 	mutex_lock(&dev->struct_mutex);
-	ret = i915_gpu_idle(dev);
+	ret = i915_gpu_idle(dev, true);
 	if (ret)
 		DRM_ERROR("failed to idle hardware: %d\n", ret);
 	mutex_unlock(&dev->struct_mutex);
@@ -2182,6 +2222,7 @@
 		i915_gem_free_all_phys_object(dev);
 		i915_gem_cleanup_ringbuffer(dev);
 		mutex_unlock(&dev->struct_mutex);
+		i915_gem_cleanup_aliasing_ppgtt(dev);
 		if (I915_HAS_FBC(dev) && i915_powersave)
 			i915_cleanup_compression(dev);
 		drm_mm_takedown(&dev_priv->mm.stolen);
@@ -2247,18 +2288,12 @@
 
 	i915_gem_lastclose(dev);
 
-	if (dev_priv->agp_heap)
-		i915_mem_takedown(&(dev_priv->agp_heap));
-
 	i915_dma_cleanup(dev);
 }
 
 void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
 {
-	drm_i915_private_t *dev_priv = dev->dev_private;
 	i915_gem_release(dev, file_priv);
-	if (!drm_core_check_feature(dev, DRIVER_MODESET))
-		i915_mem_release(dev, file_priv, dev_priv->agp_heap);
 }
 
 void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
@@ -2277,11 +2312,11 @@
 	DRM_IOCTL_DEF_DRV(I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH),
 	DRM_IOCTL_DEF_DRV(I915_GETPARAM, i915_getparam, DRM_AUTH),
 	DRM_IOCTL_DEF_DRV(I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-	DRM_IOCTL_DEF_DRV(I915_ALLOC, i915_mem_alloc, DRM_AUTH),
-	DRM_IOCTL_DEF_DRV(I915_FREE, i915_mem_free, DRM_AUTH),
-	DRM_IOCTL_DEF_DRV(I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+	DRM_IOCTL_DEF_DRV(I915_ALLOC, drm_noop, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(I915_FREE, drm_noop, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(I915_INIT_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 	DRM_IOCTL_DEF_DRV(I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH),
-	DRM_IOCTL_DEF_DRV(I915_DESTROY_HEAP,  i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+	DRM_IOCTL_DEF_DRV(I915_DESTROY_HEAP,  drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 	DRM_IOCTL_DEF_DRV(I915_SET_VBLANK_PIPE,  i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 	DRM_IOCTL_DEF_DRV(I915_GET_VBLANK_PIPE,  i915_vblank_pipe_get, DRM_AUTH),
 	DRM_IOCTL_DEF_DRV(I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH),
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 308f819..dfa55e7 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -66,7 +66,11 @@
 int i915_enable_rc6 __read_mostly = -1;
 module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600);
 MODULE_PARM_DESC(i915_enable_rc6,
-		"Enable power-saving render C-state 6 (default: -1 (use per-chip default)");
+		"Enable power-saving render C-state 6. "
+		"Different stages can be selected via bitmask values "
+		"(0 = disable; 1 = enable rc6; 2 = enable deep rc6; 4 = enable deepest rc6). "
+		"For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. "
+		"default: -1 (use per-chip default)");
 
 int i915_enable_fbc __read_mostly = -1;
 module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600);
@@ -103,6 +107,11 @@
 		"WARNING: Disabling this can cause system wide hangs. "
 		"(default: true)");
 
+int i915_enable_ppgtt __read_mostly = -1;
+module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0600);
+MODULE_PARM_DESC(i915_enable_ppgtt,
+		"Enable PPGTT (default: true)");
+
 static struct drm_driver driver;
 extern int intel_agp_enabled;
 
@@ -198,7 +207,7 @@
 
 static const struct intel_device_info intel_ironlake_d_info = {
 	.gen = 5,
-	.need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1,
+	.need_gfx_hws = 1, .has_hotplug = 1,
 	.has_bsd_ring = 1,
 };
 
@@ -214,6 +223,7 @@
 	.need_gfx_hws = 1, .has_hotplug = 1,
 	.has_bsd_ring = 1,
 	.has_blt_ring = 1,
+	.has_llc = 1,
 };
 
 static const struct intel_device_info intel_sandybridge_m_info = {
@@ -222,6 +232,7 @@
 	.has_fbc = 1,
 	.has_bsd_ring = 1,
 	.has_blt_ring = 1,
+	.has_llc = 1,
 };
 
 static const struct intel_device_info intel_ivybridge_d_info = {
@@ -229,6 +240,7 @@
 	.need_gfx_hws = 1, .has_hotplug = 1,
 	.has_bsd_ring = 1,
 	.has_blt_ring = 1,
+	.has_llc = 1,
 };
 
 static const struct intel_device_info intel_ivybridge_m_info = {
@@ -237,6 +249,7 @@
 	.has_fbc = 0,	/* FBC is not enabled on Ivybridge mobile yet */
 	.has_bsd_ring = 1,
 	.has_blt_ring = 1,
+	.has_llc = 1,
 };
 
 static const struct pci_device_id pciidlist[] = {		/* aka */
@@ -283,6 +296,7 @@
 	INTEL_VGA_DEVICE(0x0152, &intel_ivybridge_d_info), /* GT1 desktop */
 	INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */
 	INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */
+	INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */
 	{0, 0, 0}
 };
 
@@ -376,16 +390,27 @@
 	spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
 }
 
+static void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv)
+{
+	u32 gtfifodbg;
+	gtfifodbg = I915_READ_NOTRACE(GTFIFODBG);
+	if (WARN(gtfifodbg & GT_FIFO_CPU_ERROR_MASK,
+	     "MMIO read or write has been dropped %x\n", gtfifodbg))
+		I915_WRITE_NOTRACE(GTFIFODBG, GT_FIFO_CPU_ERROR_MASK);
+}
+
 void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
 {
 	I915_WRITE_NOTRACE(FORCEWAKE, 0);
-	POSTING_READ(FORCEWAKE);
+	/* The below doubles as a POSTING_READ */
+	gen6_gt_check_fifodbg(dev_priv);
 }
 
 void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv)
 {
 	I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 0);
-	POSTING_READ(FORCEWAKE_MT);
+	/* The below doubles as a POSTING_READ */
+	gen6_gt_check_fifodbg(dev_priv);
 }
 
 /*
@@ -401,8 +426,10 @@
 	spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
 }
 
-void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
+int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
 {
+	int ret = 0;
+
 	if (dev_priv->gt_fifo_count < GT_FIFO_NUM_RESERVED_ENTRIES) {
 		int loop = 500;
 		u32 fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
@@ -410,10 +437,13 @@
 			udelay(10);
 			fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
 		}
-		WARN_ON(loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES);
+		if (WARN_ON(loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES))
+			++ret;
 		dev_priv->gt_fifo_count = fifo;
 	}
 	dev_priv->gt_fifo_count--;
+
+	return ret;
 }
 
 static int i915_drm_freeze(struct drm_device *dev)
@@ -442,6 +472,10 @@
 	/* Modeset on resume, not lid events */
 	dev_priv->modeset_on_lid = 0;
 
+	console_lock();
+	intel_fbdev_set_suspend(dev, 1);
+	console_unlock();
+
 	return 0;
 }
 
@@ -494,7 +528,7 @@
 		mutex_lock(&dev->struct_mutex);
 		dev_priv->mm.suspended = 0;
 
-		error = i915_gem_init_ringbuffer(dev);
+		error = i915_gem_init_hw(dev);
 		mutex_unlock(&dev->struct_mutex);
 
 		if (HAS_PCH_SPLIT(dev))
@@ -504,7 +538,9 @@
 		drm_irq_install(dev);
 
 		/* Resume the modeset for every activated CRTC */
+		mutex_lock(&dev->mode_config.mutex);
 		drm_helper_resume_force_mode(dev);
+		mutex_unlock(&dev->mode_config.mutex);
 
 		if (IS_IRONLAKE_M(dev))
 			ironlake_enable_rc6(dev);
@@ -514,6 +550,9 @@
 
 	dev_priv->modeset_on_lid = 0;
 
+	console_lock();
+	intel_fbdev_set_suspend(dev, 0);
+	console_unlock();
 	return error;
 }
 
@@ -633,7 +672,7 @@
 }
 
 /**
- * i965_reset - reset chip after a hang
+ * i915_reset - reset chip after a hang
  * @dev: drm device to reset
  * @flags: reset domains
  *
@@ -709,12 +748,16 @@
 			!dev_priv->mm.suspended) {
 		dev_priv->mm.suspended = 0;
 
+		i915_gem_init_swizzling(dev);
+
 		dev_priv->ring[RCS].init(&dev_priv->ring[RCS]);
 		if (HAS_BSD(dev))
 		    dev_priv->ring[VCS].init(&dev_priv->ring[VCS]);
 		if (HAS_BLT(dev))
 		    dev_priv->ring[BCS].init(&dev_priv->ring[BCS]);
 
+		i915_gem_init_ppgtt(dev);
+
 		mutex_unlock(&dev->struct_mutex);
 		drm_irq_uninstall(dev);
 		drm_mode_config_reset(dev);
@@ -977,11 +1020,15 @@
 
 #define __i915_write(x, y) \
 void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
+	u32 __fifo_ret = 0; \
 	trace_i915_reg_rw(true, reg, val, sizeof(val)); \
 	if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
-		__gen6_gt_wait_for_fifo(dev_priv); \
+		__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
 	} \
 	write##y(val, dev_priv->regs + reg); \
+	if (unlikely(__fifo_ret)) { \
+		gen6_gt_check_fifodbg(dev_priv); \
+	} \
 }
 __i915_write(8, b)
 __i915_write(16, w)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 9689ca3..5fabc6c 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -35,6 +35,7 @@
 #include "intel_ringbuffer.h"
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
 #include <drm/intel-gtt.h>
 #include <linux/backlight.h>
 
@@ -135,6 +136,7 @@
 	struct list_head lru_list;
 	struct drm_i915_gem_object *obj;
 	uint32_t setup_seqno;
+	int pin_count;
 };
 
 struct sdvo_device_mapping {
@@ -152,33 +154,40 @@
 	u32 eir;
 	u32 pgtbl_er;
 	u32 pipestat[I915_MAX_PIPES];
-	u32 ipeir;
-	u32 ipehr;
-	u32 instdone;
-	u32 acthd;
+	u32 tail[I915_NUM_RINGS];
+	u32 head[I915_NUM_RINGS];
+	u32 ipeir[I915_NUM_RINGS];
+	u32 ipehr[I915_NUM_RINGS];
+	u32 instdone[I915_NUM_RINGS];
+	u32 acthd[I915_NUM_RINGS];
+	u32 semaphore_mboxes[I915_NUM_RINGS][I915_NUM_RINGS - 1];
+	/* our own tracking of ring head and tail */
+	u32 cpu_ring_head[I915_NUM_RINGS];
+	u32 cpu_ring_tail[I915_NUM_RINGS];
 	u32 error; /* gen6+ */
-	u32 bcs_acthd; /* gen6+ blt engine */
-	u32 bcs_ipehr;
-	u32 bcs_ipeir;
-	u32 bcs_instdone;
-	u32 bcs_seqno;
-	u32 vcs_acthd; /* gen6+ bsd engine */
-	u32 vcs_ipehr;
-	u32 vcs_ipeir;
-	u32 vcs_instdone;
-	u32 vcs_seqno;
-	u32 instpm;
-	u32 instps;
+	u32 instpm[I915_NUM_RINGS];
+	u32 instps[I915_NUM_RINGS];
 	u32 instdone1;
-	u32 seqno;
+	u32 seqno[I915_NUM_RINGS];
 	u64 bbaddr;
+	u32 fault_reg[I915_NUM_RINGS];
+	u32 done_reg;
+	u32 faddr[I915_NUM_RINGS];
 	u64 fence[I915_MAX_NUM_FENCES];
 	struct timeval time;
-	struct drm_i915_error_object {
-		int page_count;
-		u32 gtt_offset;
-		u32 *pages[0];
-	} *ringbuffer[I915_NUM_RINGS], *batchbuffer[I915_NUM_RINGS];
+	struct drm_i915_error_ring {
+		struct drm_i915_error_object {
+			int page_count;
+			u32 gtt_offset;
+			u32 *pages[0];
+		} *ringbuffer, *batchbuffer;
+		struct drm_i915_error_request {
+			long jiffies;
+			u32 seqno;
+			u32 tail;
+		} *requests;
+		int num_requests;
+	} ring[I915_NUM_RINGS];
 	struct drm_i915_error_buffer {
 		u32 size;
 		u32 name;
@@ -191,7 +200,7 @@
 		u32 tiling:2;
 		u32 dirty:1;
 		u32 purgeable:1;
-		u32 ring:4;
+		s32 ring:4;
 		u32 cache_level:2;
 	} *active_bo, *pinned_bo;
 	u32 active_bo_count, pinned_bo_count;
@@ -255,6 +264,17 @@
 	u8 supports_tv:1;
 	u8 has_bsd_ring:1;
 	u8 has_blt_ring:1;
+	u8 has_llc:1;
+};
+
+#define I915_PPGTT_PD_ENTRIES 512
+#define I915_PPGTT_PT_ENTRIES 1024
+struct i915_hw_ppgtt {
+	unsigned num_pd_entries;
+	struct page **pt_pages;
+	uint32_t pd_offset;
+	dma_addr_t *pt_dma_addr;
+	dma_addr_t scratch_page_dma_addr;
 };
 
 enum no_fbc_reason {
@@ -279,6 +299,16 @@
 struct intel_fbdev;
 struct intel_fbc_work;
 
+struct intel_gmbus {
+	struct i2c_adapter adapter;
+	bool force_bit;
+	bool has_gpio;
+	u32 reg0;
+	u32 gpio_reg;
+	struct i2c_algo_bit_data bit_algo;
+	struct drm_i915_private *dev_priv;
+};
+
 typedef struct drm_i915_private {
 	struct drm_device *dev;
 
@@ -296,11 +326,11 @@
 	/** gt_lock is also taken in irq contexts. */
 	struct spinlock gt_lock;
 
-	struct intel_gmbus {
-		struct i2c_adapter adapter;
-		struct i2c_adapter *force_bit;
-		u32 reg0;
-	} *gmbus;
+	struct intel_gmbus *gmbus;
+
+	/** gmbus_mutex protects against concurrent usage of the single hw gmbus
+	 * controller on different i2c buses. */
+	struct mutex gmbus_mutex;
 
 	struct pci_dev *bridge_dev;
 	struct intel_ring_buffer ring[I915_NUM_RINGS];
@@ -335,7 +365,6 @@
 
 	int tex_lru_log_granularity;
 	int allow_batchbuffer;
-	struct mem_block *agp_heap;
 	unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
 	int vblank_pipe;
 	int num_pipe;
@@ -584,6 +613,9 @@
 		struct io_mapping *gtt_mapping;
 		int gtt_mtrr;
 
+		/** PPGTT used for aliasing the PPGTT with the GTT */
+		struct i915_hw_ppgtt *aliasing_ppgtt;
+
 		struct shrinker inactive_shrinker;
 
 		/**
@@ -749,6 +781,13 @@
 	struct drm_property *force_audio_property;
 } drm_i915_private_t;
 
+enum hdmi_force_audio {
+	HDMI_AUDIO_OFF_DVI = -2,	/* no aux data for HDMI-DVI converter */
+	HDMI_AUDIO_OFF,			/* force turn off HDMI audio */
+	HDMI_AUDIO_AUTO,		/* trust EDID */
+	HDMI_AUDIO_ON,			/* force turn on HDMI audio */
+};
+
 enum i915_cache_level {
 	I915_CACHE_NONE,
 	I915_CACHE_LLC,
@@ -841,6 +880,8 @@
 
 	unsigned int cache_level:2;
 
+	unsigned int has_aliasing_ppgtt_mapping:1;
+
 	struct page **pages;
 
 	/**
@@ -918,6 +959,9 @@
 	/** GEM sequence number associated with this request. */
 	uint32_t seqno;
 
+	/** Postion in the ringbuffer of the end of the request */
+	u32 tail;
+
 	/** Time at which this request was emitted, in jiffies. */
 	unsigned long emitted_jiffies;
 
@@ -974,8 +1018,11 @@
 
 #define HAS_BSD(dev)            (INTEL_INFO(dev)->has_bsd_ring)
 #define HAS_BLT(dev)            (INTEL_INFO(dev)->has_blt_ring)
+#define HAS_LLC(dev)            (INTEL_INFO(dev)->has_llc)
 #define I915_NEED_GFX_HWS(dev)	(INTEL_INFO(dev)->need_gfx_hws)
 
+#define HAS_ALIASING_PPGTT(dev)	(INTEL_INFO(dev)->gen >=6)
+
 #define HAS_OVERLAY(dev)		(INTEL_INFO(dev)->has_overlay)
 #define OVERLAY_NEEDS_PHYSICAL(dev)	(INTEL_INFO(dev)->overlay_needs_physical)
 
@@ -1006,6 +1053,27 @@
 
 #include "i915_trace.h"
 
+/**
+ * RC6 is a special power stage which allows the GPU to enter an very
+ * low-voltage mode when idle, using down to 0V while at this stage.  This
+ * stage is entered automatically when the GPU is idle when RC6 support is
+ * enabled, and as soon as new workload arises GPU wakes up automatically as well.
+ *
+ * There are different RC6 modes available in Intel GPU, which differentiate
+ * among each other with the latency required to enter and leave RC6 and
+ * voltage consumed by the GPU in different states.
+ *
+ * The combination of the following flags define which states GPU is allowed
+ * to enter, while RC6 is the normal RC6 state, RC6p is the deep RC6, and
+ * RC6pp is deepest RC6. Their support by hardware varies according to the
+ * GPU, BIOS, chipset and platform. RC6 is usually the safest one and the one
+ * which brings the most power savings; deeper states save more power, but
+ * require higher latency to switch to and wake up.
+ */
+#define INTEL_RC6_ENABLE			(1<<0)
+#define INTEL_RC6p_ENABLE			(1<<1)
+#define INTEL_RC6pp_ENABLE			(1<<2)
+
 extern struct drm_ioctl_desc i915_ioctls[];
 extern int i915_max_ioctl;
 extern unsigned int i915_fbpercrtc __always_unused;
@@ -1018,6 +1086,7 @@
 extern int i915_enable_rc6 __read_mostly;
 extern int i915_enable_fbc __read_mostly;
 extern bool i915_enable_hangcheck __read_mostly;
+extern int i915_enable_ppgtt __read_mostly;
 
 extern int i915_suspend(struct drm_device *dev, pm_message_t state);
 extern int i915_resume(struct drm_device *dev);
@@ -1079,18 +1148,6 @@
 #endif
 
 
-/* i915_mem.c */
-extern int i915_mem_alloc(struct drm_device *dev, void *data,
-			  struct drm_file *file_priv);
-extern int i915_mem_free(struct drm_device *dev, void *data,
-			 struct drm_file *file_priv);
-extern int i915_mem_init_heap(struct drm_device *dev, void *data,
-			      struct drm_file *file_priv);
-extern int i915_mem_destroy_heap(struct drm_device *dev, void *data,
-				 struct drm_file *file_priv);
-extern void i915_mem_takedown(struct mem_block **heap);
-extern void i915_mem_release(struct drm_device * dev,
-			     struct drm_file *file_priv, struct mem_block *heap);
 /* i915_gem.c */
 int i915_gem_init_ioctl(struct drm_device *dev, void *data,
 			struct drm_file *file_priv);
@@ -1170,37 +1227,55 @@
 	return (int32_t)(seq1 - seq2) >= 0;
 }
 
-static inline u32
-i915_gem_next_request_seqno(struct intel_ring_buffer *ring)
-{
-	drm_i915_private_t *dev_priv = ring->dev->dev_private;
-	return ring->outstanding_lazy_request = dev_priv->next_seqno;
-}
+u32 i915_gem_next_request_seqno(struct intel_ring_buffer *ring);
 
 int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj,
 					   struct intel_ring_buffer *pipelined);
 int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj);
 
+static inline void
+i915_gem_object_pin_fence(struct drm_i915_gem_object *obj)
+{
+	if (obj->fence_reg != I915_FENCE_REG_NONE) {
+		struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+		dev_priv->fence_regs[obj->fence_reg].pin_count++;
+	}
+}
+
+static inline void
+i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj)
+{
+	if (obj->fence_reg != I915_FENCE_REG_NONE) {
+		struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+		dev_priv->fence_regs[obj->fence_reg].pin_count--;
+	}
+}
+
 void i915_gem_retire_requests(struct drm_device *dev);
+void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring);
+
 void i915_gem_reset(struct drm_device *dev);
 void i915_gem_clflush_object(struct drm_i915_gem_object *obj);
 int __must_check i915_gem_object_set_domain(struct drm_i915_gem_object *obj,
 					    uint32_t read_domains,
 					    uint32_t write_domain);
 int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
-int __must_check i915_gem_init_ringbuffer(struct drm_device *dev);
+int __must_check i915_gem_init_hw(struct drm_device *dev);
+void i915_gem_init_swizzling(struct drm_device *dev);
+void i915_gem_init_ppgtt(struct drm_device *dev);
 void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
 void i915_gem_do_init(struct drm_device *dev,
 		      unsigned long start,
 		      unsigned long mappable_end,
 		      unsigned long end);
-int __must_check i915_gpu_idle(struct drm_device *dev);
+int __must_check i915_gpu_idle(struct drm_device *dev, bool do_retire);
 int __must_check i915_gem_idle(struct drm_device *dev);
 int __must_check i915_add_request(struct intel_ring_buffer *ring,
 				  struct drm_file *file,
 				  struct drm_i915_gem_request *request);
 int __must_check i915_wait_request(struct intel_ring_buffer *ring,
-				   uint32_t seqno);
+				   uint32_t seqno,
+				   bool do_retire);
 int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
 int __must_check
 i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj,
@@ -1227,6 +1302,14 @@
 				    enum i915_cache_level cache_level);
 
 /* i915_gem_gtt.c */
+int __must_check i915_gem_init_aliasing_ppgtt(struct drm_device *dev);
+void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev);
+void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
+			    struct drm_i915_gem_object *obj,
+			    enum i915_cache_level cache_level);
+void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
+			      struct drm_i915_gem_object *obj);
+
 void i915_gem_restore_gtt_mappings(struct drm_device *dev);
 int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj);
 void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj,
@@ -1365,7 +1448,7 @@
  */
 void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
 void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
-void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
+int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
 
 /* We give fast paths for the really cool registers */
 #define NEEDS_FORCE_WAKE(dev_priv, reg) \
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index e55badb..4c65c63 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -58,6 +58,7 @@
 
 static int i915_gem_inactive_shrink(struct shrinker *shrinker,
 				    struct shrink_control *sc);
+static void i915_gem_object_truncate(struct drm_i915_gem_object *obj);
 
 /* some bookkeeping */
 static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
@@ -258,73 +259,6 @@
 		obj->tiling_mode != I915_TILING_NONE;
 }
 
-static inline void
-slow_shmem_copy(struct page *dst_page,
-		int dst_offset,
-		struct page *src_page,
-		int src_offset,
-		int length)
-{
-	char *dst_vaddr, *src_vaddr;
-
-	dst_vaddr = kmap(dst_page);
-	src_vaddr = kmap(src_page);
-
-	memcpy(dst_vaddr + dst_offset, src_vaddr + src_offset, length);
-
-	kunmap(src_page);
-	kunmap(dst_page);
-}
-
-static inline void
-slow_shmem_bit17_copy(struct page *gpu_page,
-		      int gpu_offset,
-		      struct page *cpu_page,
-		      int cpu_offset,
-		      int length,
-		      int is_read)
-{
-	char *gpu_vaddr, *cpu_vaddr;
-
-	/* Use the unswizzled path if this page isn't affected. */
-	if ((page_to_phys(gpu_page) & (1 << 17)) == 0) {
-		if (is_read)
-			return slow_shmem_copy(cpu_page, cpu_offset,
-					       gpu_page, gpu_offset, length);
-		else
-			return slow_shmem_copy(gpu_page, gpu_offset,
-					       cpu_page, cpu_offset, length);
-	}
-
-	gpu_vaddr = kmap(gpu_page);
-	cpu_vaddr = kmap(cpu_page);
-
-	/* Copy the data, XORing A6 with A17 (1). The user already knows he's
-	 * XORing with the other bits (A9 for Y, A9 and A10 for X)
-	 */
-	while (length > 0) {
-		int cacheline_end = ALIGN(gpu_offset + 1, 64);
-		int this_length = min(cacheline_end - gpu_offset, length);
-		int swizzled_gpu_offset = gpu_offset ^ 64;
-
-		if (is_read) {
-			memcpy(cpu_vaddr + cpu_offset,
-			       gpu_vaddr + swizzled_gpu_offset,
-			       this_length);
-		} else {
-			memcpy(gpu_vaddr + swizzled_gpu_offset,
-			       cpu_vaddr + cpu_offset,
-			       this_length);
-		}
-		cpu_offset += this_length;
-		gpu_offset += this_length;
-		length -= this_length;
-	}
-
-	kunmap(cpu_page);
-	kunmap(gpu_page);
-}
-
 /**
  * This is the fast shmem pread path, which attempts to copy_from_user directly
  * from the backing pages of the object to the user's address space.  On a
@@ -385,6 +319,58 @@
 	return 0;
 }
 
+static inline int
+__copy_to_user_swizzled(char __user *cpu_vaddr,
+			const char *gpu_vaddr, int gpu_offset,
+			int length)
+{
+	int ret, cpu_offset = 0;
+
+	while (length > 0) {
+		int cacheline_end = ALIGN(gpu_offset + 1, 64);
+		int this_length = min(cacheline_end - gpu_offset, length);
+		int swizzled_gpu_offset = gpu_offset ^ 64;
+
+		ret = __copy_to_user(cpu_vaddr + cpu_offset,
+				     gpu_vaddr + swizzled_gpu_offset,
+				     this_length);
+		if (ret)
+			return ret + length;
+
+		cpu_offset += this_length;
+		gpu_offset += this_length;
+		length -= this_length;
+	}
+
+	return 0;
+}
+
+static inline int
+__copy_from_user_swizzled(char __user *gpu_vaddr, int gpu_offset,
+			  const char *cpu_vaddr,
+			  int length)
+{
+	int ret, cpu_offset = 0;
+
+	while (length > 0) {
+		int cacheline_end = ALIGN(gpu_offset + 1, 64);
+		int this_length = min(cacheline_end - gpu_offset, length);
+		int swizzled_gpu_offset = gpu_offset ^ 64;
+
+		ret = __copy_from_user(gpu_vaddr + swizzled_gpu_offset,
+				       cpu_vaddr + cpu_offset,
+				       this_length);
+		if (ret)
+			return ret + length;
+
+		cpu_offset += this_length;
+		gpu_offset += this_length;
+		length -= this_length;
+	}
+
+	return 0;
+}
+
 /**
  * This is the fallback shmem pread path, which allocates temporary storage
  * in kernel space to copy_to_user into outside of the struct_mutex, so we
@@ -398,72 +384,34 @@
 			  struct drm_file *file)
 {
 	struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
-	struct mm_struct *mm = current->mm;
-	struct page **user_pages;
+	char __user *user_data;
 	ssize_t remain;
-	loff_t offset, pinned_pages, i;
-	loff_t first_data_page, last_data_page, num_pages;
-	int shmem_page_offset;
-	int data_page_index, data_page_offset;
-	int page_length;
-	int ret;
-	uint64_t data_ptr = args->data_ptr;
-	int do_bit17_swizzling;
+	loff_t offset;
+	int shmem_page_offset, page_length, ret;
+	int obj_do_bit17_swizzling, page_do_bit17_swizzling;
 
+	user_data = (char __user *) (uintptr_t) args->data_ptr;
 	remain = args->size;
 
-	/* Pin the user pages containing the data.  We can't fault while
-	 * holding the struct mutex, yet we want to hold it while
-	 * dereferencing the user data.
-	 */
-	first_data_page = data_ptr / PAGE_SIZE;
-	last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
-	num_pages = last_data_page - first_data_page + 1;
-
-	user_pages = drm_malloc_ab(num_pages, sizeof(struct page *));
-	if (user_pages == NULL)
-		return -ENOMEM;
-
-	mutex_unlock(&dev->struct_mutex);
-	down_read(&mm->mmap_sem);
-	pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr,
-				      num_pages, 1, 0, user_pages, NULL);
-	up_read(&mm->mmap_sem);
-	mutex_lock(&dev->struct_mutex);
-	if (pinned_pages < num_pages) {
-		ret = -EFAULT;
-		goto out;
-	}
-
-	ret = i915_gem_object_set_cpu_read_domain_range(obj,
-							args->offset,
-							args->size);
-	if (ret)
-		goto out;
-
-	do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
+	obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
 
 	offset = args->offset;
 
+	mutex_unlock(&dev->struct_mutex);
+
 	while (remain > 0) {
 		struct page *page;
+		char *vaddr;
 
 		/* Operation in this page
 		 *
 		 * shmem_page_offset = offset within page in shmem file
-		 * data_page_index = page number in get_user_pages return
-		 * data_page_offset = offset with data_page_index page.
 		 * page_length = bytes to copy for this page
 		 */
 		shmem_page_offset = offset_in_page(offset);
-		data_page_index = data_ptr / PAGE_SIZE - first_data_page;
-		data_page_offset = offset_in_page(data_ptr);
-
 		page_length = remain;
 		if ((shmem_page_offset + page_length) > PAGE_SIZE)
 			page_length = PAGE_SIZE - shmem_page_offset;
-		if ((data_page_offset + page_length) > PAGE_SIZE)
-			page_length = PAGE_SIZE - data_page_offset;
 
 		page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT);
 		if (IS_ERR(page)) {
@@ -471,36 +419,38 @@
 			goto out;
 		}
 
-		if (do_bit17_swizzling) {
-			slow_shmem_bit17_copy(page,
-					      shmem_page_offset,
-					      user_pages[data_page_index],
-					      data_page_offset,
-					      page_length,
-					      1);
-		} else {
-			slow_shmem_copy(user_pages[data_page_index],
-					data_page_offset,
-					page,
-					shmem_page_offset,
-					page_length);
-		}
+		page_do_bit17_swizzling = obj_do_bit17_swizzling &&
+			(page_to_phys(page) & (1 << 17)) != 0;
+
+		vaddr = kmap(page);
+		if (page_do_bit17_swizzling)
+			ret = __copy_to_user_swizzled(user_data,
+						      vaddr, shmem_page_offset,
+						      page_length);
+		else
+			ret = __copy_to_user(user_data,
+					     vaddr + shmem_page_offset,
+					     page_length);
+		kunmap(page);
 
 		mark_page_accessed(page);
 		page_cache_release(page);
 
+		if (ret) {
+			ret = -EFAULT;
+			goto out;
+		}
+
 		remain -= page_length;
-		data_ptr += page_length;
+		user_data += page_length;
 		offset += page_length;
 	}
 
 out:
-	for (i = 0; i < pinned_pages; i++) {
-		SetPageDirty(user_pages[i]);
-		mark_page_accessed(user_pages[i]);
-		page_cache_release(user_pages[i]);
-	}
-	drm_free_large(user_pages);
+	mutex_lock(&dev->struct_mutex);
+	/* Fixup: Kill any reinstated backing storage pages */
+	if (obj->madv == __I915_MADV_PURGED)
+		i915_gem_object_truncate(obj);
 
 	return ret;
 }
@@ -841,71 +791,36 @@
 			   struct drm_file *file)
 {
 	struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
-	struct mm_struct *mm = current->mm;
-	struct page **user_pages;
 	ssize_t remain;
-	loff_t offset, pinned_pages, i;
-	loff_t first_data_page, last_data_page, num_pages;
-	int shmem_page_offset;
-	int data_page_index,  data_page_offset;
-	int page_length;
-	int ret;
-	uint64_t data_ptr = args->data_ptr;
-	int do_bit17_swizzling;
+	loff_t offset;
+	char __user *user_data;
+	int shmem_page_offset, page_length, ret;
+	int obj_do_bit17_swizzling, page_do_bit17_swizzling;
 
+	user_data = (char __user *) (uintptr_t) args->data_ptr;
 	remain = args->size;
 
-	/* Pin the user pages containing the data.  We can't fault while
-	 * holding the struct mutex, and all of the pwrite implementations
-	 * want to hold it while dereferencing the user data.
-	 */
-	first_data_page = data_ptr / PAGE_SIZE;
-	last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
-	num_pages = last_data_page - first_data_page + 1;
-
-	user_pages = drm_malloc_ab(num_pages, sizeof(struct page *));
-	if (user_pages == NULL)
-		return -ENOMEM;
-
-	mutex_unlock(&dev->struct_mutex);
-	down_read(&mm->mmap_sem);
-	pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr,
-				      num_pages, 0, 0, user_pages, NULL);
-	up_read(&mm->mmap_sem);
-	mutex_lock(&dev->struct_mutex);
-	if (pinned_pages < num_pages) {
-		ret = -EFAULT;
-		goto out;
-	}
-
-	ret = i915_gem_object_set_to_cpu_domain(obj, 1);
-	if (ret)
-		goto out;
-
-	do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
+	obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
 
 	offset = args->offset;
 	obj->dirty = 1;
 
+	mutex_unlock(&dev->struct_mutex);
+
 	while (remain > 0) {
 		struct page *page;
+		char *vaddr;
 
 		/* Operation in this page
 		 *
 		 * shmem_page_offset = offset within page in shmem file
-		 * data_page_index = page number in get_user_pages return
-		 * data_page_offset = offset with data_page_index page.
 		 * page_length = bytes to copy for this page
 		 */
 		shmem_page_offset = offset_in_page(offset);
-		data_page_index = data_ptr / PAGE_SIZE - first_data_page;
-		data_page_offset = offset_in_page(data_ptr);
 
 		page_length = remain;
 		if ((shmem_page_offset + page_length) > PAGE_SIZE)
 			page_length = PAGE_SIZE - shmem_page_offset;
-		if ((data_page_offset + page_length) > PAGE_SIZE)
-			page_length = PAGE_SIZE - data_page_offset;
 
 		page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT);
 		if (IS_ERR(page)) {
@@ -913,34 +828,45 @@
 			goto out;
 		}
 
-		if (do_bit17_swizzling) {
-			slow_shmem_bit17_copy(page,
-					      shmem_page_offset,
-					      user_pages[data_page_index],
-					      data_page_offset,
-					      page_length,
-					      0);
-		} else {
-			slow_shmem_copy(page,
-					shmem_page_offset,
-					user_pages[data_page_index],
-					data_page_offset,
-					page_length);
-		}
+		page_do_bit17_swizzling = obj_do_bit17_swizzling &&
+			(page_to_phys(page) & (1 << 17)) != 0;
+
+		vaddr = kmap(page);
+		if (page_do_bit17_swizzling)
+			ret = __copy_from_user_swizzled(vaddr, shmem_page_offset,
+							user_data,
+							page_length);
+		else
+			ret = __copy_from_user(vaddr + shmem_page_offset,
+					       user_data,
+					       page_length);
+		kunmap(page);
 
 		set_page_dirty(page);
 		mark_page_accessed(page);
 		page_cache_release(page);
 
+		if (ret) {
+			ret = -EFAULT;
+			goto out;
+		}
+
 		remain -= page_length;
-		data_ptr += page_length;
+		user_data += page_length;
 		offset += page_length;
 	}
 
 out:
-	for (i = 0; i < pinned_pages; i++)
-		page_cache_release(user_pages[i]);
-	drm_free_large(user_pages);
+	mutex_lock(&dev->struct_mutex);
+	/* Fixup: Kill any reinstated backing storage pages */
+	if (obj->madv == __I915_MADV_PURGED)
+		i915_gem_object_truncate(obj);
+	/* and flush dirty cachelines in case the object isn't in the cpu write
+	 * domain anymore. */
+	if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
+		i915_gem_clflush_object(obj);
+		intel_gtt_chipset_flush();
+	}
 
 	return ret;
 }
@@ -996,10 +922,13 @@
 	 * pread/pwrite currently are reading and writing from the CPU
 	 * perspective, requiring manual detiling by the client.
 	 */
-	if (obj->phys_obj)
+	if (obj->phys_obj) {
 		ret = i915_gem_phys_pwrite(dev, obj, args, file);
-	else if (obj->gtt_space &&
-		 obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
+		goto out;
+	}
+
+	if (obj->gtt_space &&
+	    obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
 		ret = i915_gem_object_pin(obj, 0, true);
 		if (ret)
 			goto out;
@@ -1018,18 +947,24 @@
 
 out_unpin:
 		i915_gem_object_unpin(obj);
-	} else {
-		ret = i915_gem_object_set_to_cpu_domain(obj, 1);
-		if (ret)
-			goto out;
 
-		ret = -EFAULT;
-		if (!i915_gem_object_needs_bit17_swizzle(obj))
-			ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file);
-		if (ret == -EFAULT)
-			ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file);
+		if (ret != -EFAULT)
+			goto out;
+		/* Fall through to the shmfs paths because the gtt paths might
+		 * fail with non-page-backed user pointers (e.g. gtt mappings
+		 * when moving data between textures). */
 	}
 
+	ret = i915_gem_object_set_to_cpu_domain(obj, 1);
+	if (ret)
+		goto out;
+
+	ret = -EFAULT;
+	if (!i915_gem_object_needs_bit17_swizzle(obj))
+		ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file);
+	if (ret == -EFAULT)
+		ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file);
+
 out:
 	drm_gem_object_unreference(&obj->base);
 unlock:
@@ -1141,7 +1076,6 @@
 i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
 		    struct drm_file *file)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_mmap *args = data;
 	struct drm_gem_object *obj;
 	unsigned long addr;
@@ -1153,11 +1087,6 @@
 	if (obj == NULL)
 		return -ENOENT;
 
-	if (obj->size > dev_priv->mm.gtt_mappable_end) {
-		drm_gem_object_unreference_unlocked(obj);
-		return -E2BIG;
-	}
-
 	down_write(&current->mm->mmap_sem);
 	addr = do_mmap(obj->filp, 0, args->size,
 		       PROT_READ | PROT_WRITE, MAP_SHARED,
@@ -1543,16 +1472,19 @@
 	list_move_tail(&obj->ring_list, &ring->active_list);
 
 	obj->last_rendering_seqno = seqno;
+
 	if (obj->fenced_gpu_access) {
-		struct drm_i915_fence_reg *reg;
-
-		BUG_ON(obj->fence_reg == I915_FENCE_REG_NONE);
-
 		obj->last_fenced_seqno = seqno;
 		obj->last_fenced_ring = ring;
 
-		reg = &dev_priv->fence_regs[obj->fence_reg];
-		list_move_tail(&reg->lru_list, &dev_priv->mm.fence_list);
+		/* Bump MRU to take account of the delayed flush */
+		if (obj->fence_reg != I915_FENCE_REG_NONE) {
+			struct drm_i915_fence_reg *reg;
+
+			reg = &dev_priv->fence_regs[obj->fence_reg];
+			list_move_tail(&reg->lru_list,
+				       &dev_priv->mm.fence_list);
+		}
 	}
 }
 
@@ -1647,6 +1579,28 @@
 	}
 }
 
+static u32
+i915_gem_get_seqno(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	u32 seqno = dev_priv->next_seqno;
+
+	/* reserve 0 for non-seqno */
+	if (++dev_priv->next_seqno == 0)
+		dev_priv->next_seqno = 1;
+
+	return seqno;
+}
+
+u32
+i915_gem_next_request_seqno(struct intel_ring_buffer *ring)
+{
+	if (ring->outstanding_lazy_request == 0)
+		ring->outstanding_lazy_request = i915_gem_get_seqno(ring->dev);
+
+	return ring->outstanding_lazy_request;
+}
+
 int
 i915_add_request(struct intel_ring_buffer *ring,
 		 struct drm_file *file,
@@ -1654,10 +1608,19 @@
 {
 	drm_i915_private_t *dev_priv = ring->dev->dev_private;
 	uint32_t seqno;
+	u32 request_ring_position;
 	int was_empty;
 	int ret;
 
 	BUG_ON(request == NULL);
+	seqno = i915_gem_next_request_seqno(ring);
+
+	/* Record the position of the start of the request so that
+	 * should we detect the updated seqno part-way through the
+	 * GPU processing the request, we never over-estimate the
+	 * position of the head.
+	 */
+	request_ring_position = intel_ring_get_tail(ring);
 
 	ret = ring->add_request(ring, &seqno);
 	if (ret)
@@ -1667,6 +1630,7 @@
 
 	request->seqno = seqno;
 	request->ring = ring;
+	request->tail = request_ring_position;
 	request->emitted_jiffies = jiffies;
 	was_empty = list_empty(&ring->request_list);
 	list_add_tail(&request->list, &ring->request_list);
@@ -1681,7 +1645,7 @@
 		spin_unlock(&file_priv->mm.lock);
 	}
 
-	ring->outstanding_lazy_request = false;
+	ring->outstanding_lazy_request = 0;
 
 	if (!dev_priv->mm.suspended) {
 		if (i915_enable_hangcheck) {
@@ -1803,7 +1767,7 @@
 /**
  * This function clears the request list as sequence numbers are passed.
  */
-static void
+void
 i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
 {
 	uint32_t seqno;
@@ -1831,6 +1795,12 @@
 			break;
 
 		trace_i915_gem_request_retire(ring, request->seqno);
+		/* We know the GPU must have read the request to have
+		 * sent us the seqno + interrupt, so use the position
+		 * of tail of the request to update the last known position
+		 * of the GPU head.
+		 */
+		ring->last_retired_head = request->tail;
 
 		list_del(&request->list);
 		i915_gem_request_remove_from_client(request);
@@ -1943,7 +1913,8 @@
  */
 int
 i915_wait_request(struct intel_ring_buffer *ring,
-		  uint32_t seqno)
+		  uint32_t seqno,
+		  bool do_retire)
 {
 	drm_i915_private_t *dev_priv = ring->dev->dev_private;
 	u32 ier;
@@ -2017,17 +1988,12 @@
 	if (atomic_read(&dev_priv->mm.wedged))
 		ret = -EAGAIN;
 
-	if (ret && ret != -ERESTARTSYS)
-		DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n",
-			  __func__, ret, seqno, ring->get_seqno(ring),
-			  dev_priv->next_seqno);
-
 	/* Directly dispatch request retiring.  While we have the work queue
 	 * to handle this, the waiter on a request often wants an associated
 	 * buffer to have made it to the inactive list, and we would need
 	 * a separate wait queue to handle that.
 	 */
-	if (ret == 0)
+	if (ret == 0 && do_retire)
 		i915_gem_retire_requests_ring(ring);
 
 	return ret;
@@ -2051,7 +2017,8 @@
 	 * it.
 	 */
 	if (obj->active) {
-		ret = i915_wait_request(obj->ring, obj->last_rendering_seqno);
+		ret = i915_wait_request(obj->ring, obj->last_rendering_seqno,
+					true);
 		if (ret)
 			return ret;
 	}
@@ -2089,6 +2056,7 @@
 int
 i915_gem_object_unbind(struct drm_i915_gem_object *obj)
 {
+	drm_i915_private_t *dev_priv = obj->base.dev->dev_private;
 	int ret = 0;
 
 	if (obj->gtt_space == NULL)
@@ -2133,6 +2101,11 @@
 	trace_i915_gem_object_unbind(obj);
 
 	i915_gem_gtt_unbind_object(obj);
+	if (obj->has_aliasing_ppgtt_mapping) {
+		i915_ppgtt_unbind_object(dev_priv->mm.aliasing_ppgtt, obj);
+		obj->has_aliasing_ppgtt_mapping = 0;
+	}
+
 	i915_gem_object_put_pages_gtt(obj);
 
 	list_del_init(&obj->gtt_list);
@@ -2172,7 +2145,7 @@
 	return 0;
 }
 
-static int i915_ring_idle(struct intel_ring_buffer *ring)
+static int i915_ring_idle(struct intel_ring_buffer *ring, bool do_retire)
 {
 	int ret;
 
@@ -2186,18 +2159,18 @@
 			return ret;
 	}
 
-	return i915_wait_request(ring, i915_gem_next_request_seqno(ring));
+	return i915_wait_request(ring, i915_gem_next_request_seqno(ring),
+				 do_retire);
 }
 
-int
-i915_gpu_idle(struct drm_device *dev)
+int i915_gpu_idle(struct drm_device *dev, bool do_retire)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	int ret, i;
 
 	/* Flush everything onto the inactive list. */
 	for (i = 0; i < I915_NUM_RINGS; i++) {
-		ret = i915_ring_idle(&dev_priv->ring[i]);
+		ret = i915_ring_idle(&dev_priv->ring[i], do_retire);
 		if (ret)
 			return ret;
 	}
@@ -2400,7 +2373,8 @@
 		if (!ring_passed_seqno(obj->last_fenced_ring,
 				       obj->last_fenced_seqno)) {
 			ret = i915_wait_request(obj->last_fenced_ring,
-						obj->last_fenced_seqno);
+						obj->last_fenced_seqno,
+						true);
 			if (ret)
 				return ret;
 		}
@@ -2432,6 +2406,8 @@
 
 	if (obj->fence_reg != I915_FENCE_REG_NONE) {
 		struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+
+		WARN_ON(dev_priv->fence_regs[obj->fence_reg].pin_count);
 		i915_gem_clear_fence_reg(obj->base.dev,
 					 &dev_priv->fence_regs[obj->fence_reg]);
 
@@ -2456,7 +2432,7 @@
 		if (!reg->obj)
 			return reg;
 
-		if (!reg->obj->pin_count)
+		if (!reg->pin_count)
 			avail = reg;
 	}
 
@@ -2466,7 +2442,7 @@
 	/* None available, try to steal one or wait for a user to finish */
 	avail = first = NULL;
 	list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) {
-		if (reg->obj->pin_count)
+		if (reg->pin_count)
 			continue;
 
 		if (first == NULL)
@@ -2541,7 +2517,8 @@
 				if (!ring_passed_seqno(obj->last_fenced_ring,
 						       reg->setup_seqno)) {
 					ret = i915_wait_request(obj->last_fenced_ring,
-								reg->setup_seqno);
+								reg->setup_seqno,
+								true);
 					if (ret)
 						return ret;
 				}
@@ -2560,7 +2537,7 @@
 
 	reg = i915_find_fence_reg(dev, pipelined);
 	if (reg == NULL)
-		return -ENOSPC;
+		return -EDEADLK;
 
 	ret = i915_gem_object_flush_fence(obj, pipelined);
 	if (ret)
@@ -2660,6 +2637,7 @@
 	list_del_init(&reg->lru_list);
 	reg->obj = NULL;
 	reg->setup_seqno = 0;
+	reg->pin_count = 0;
 }
 
 /**
@@ -2946,6 +2924,8 @@
 int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
 				    enum i915_cache_level cache_level)
 {
+	struct drm_device *dev = obj->base.dev;
+	drm_i915_private_t *dev_priv = dev->dev_private;
 	int ret;
 
 	if (obj->cache_level == cache_level)
@@ -2974,6 +2954,9 @@
 		}
 
 		i915_gem_gtt_rebind_object(obj, cache_level);
+		if (obj->has_aliasing_ppgtt_mapping)
+			i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
+					       obj, cache_level);
 	}
 
 	if (cache_level == I915_CACHE_NONE) {
@@ -3084,10 +3067,13 @@
 			return ret;
 	}
 
+	ret = i915_gem_object_wait_rendering(obj);
+	if (ret)
+		return ret;
+
 	/* Ensure that we invalidate the GPU's caches and TLBs. */
 	obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
-
-	return i915_gem_object_wait_rendering(obj);
+	return 0;
 }
 
 /**
@@ -3619,8 +3605,8 @@
 	obj->base.write_domain = I915_GEM_DOMAIN_CPU;
 	obj->base.read_domains = I915_GEM_DOMAIN_CPU;
 
-	if (IS_GEN6(dev) || IS_GEN7(dev)) {
-		/* On Gen6, we can have the GPU use the LLC (the CPU
+	if (HAS_LLC(dev)) {
+		/* On some devices, we can have the GPU use the LLC (the CPU
 		 * cache) for about a 10% performance improvement
 		 * compared to uncached.  Graphics requests other than
 		 * display scanout are coherent with the CPU in
@@ -3710,7 +3696,7 @@
 		return 0;
 	}
 
-	ret = i915_gpu_idle(dev);
+	ret = i915_gpu_idle(dev, true);
 	if (ret) {
 		mutex_unlock(&dev->struct_mutex);
 		return ret;
@@ -3745,12 +3731,91 @@
 	return 0;
 }
 
+void i915_gem_init_swizzling(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+
+	if (INTEL_INFO(dev)->gen < 5 ||
+	    dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_NONE)
+		return;
+
+	I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) |
+				 DISP_TILE_SURFACE_SWIZZLING);
+
+	if (IS_GEN5(dev))
+		return;
+
+	I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_SWZCTL);
+	if (IS_GEN6(dev))
+		I915_WRITE(ARB_MODE, ARB_MODE_ENABLE(ARB_MODE_SWIZZLE_SNB));
+	else
+		I915_WRITE(ARB_MODE, ARB_MODE_ENABLE(ARB_MODE_SWIZZLE_IVB));
+}
+
+void i915_gem_init_ppgtt(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	uint32_t pd_offset;
+	struct intel_ring_buffer *ring;
+	struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+	uint32_t __iomem *pd_addr;
+	uint32_t pd_entry;
+	int i;
+
+	if (!dev_priv->mm.aliasing_ppgtt)
+		return;
+
+
+	pd_addr = dev_priv->mm.gtt->gtt + ppgtt->pd_offset/sizeof(uint32_t);
+	for (i = 0; i < ppgtt->num_pd_entries; i++) {
+		dma_addr_t pt_addr;
+
+		if (dev_priv->mm.gtt->needs_dmar)
+			pt_addr = ppgtt->pt_dma_addr[i];
+		else
+			pt_addr = page_to_phys(ppgtt->pt_pages[i]);
+
+		pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr);
+		pd_entry |= GEN6_PDE_VALID;
+
+		writel(pd_entry, pd_addr + i);
+	}
+	readl(pd_addr);
+
+	pd_offset = ppgtt->pd_offset;
+	pd_offset /= 64; /* in cachelines, */
+	pd_offset <<= 16;
+
+	if (INTEL_INFO(dev)->gen == 6) {
+		uint32_t ecochk = I915_READ(GAM_ECOCHK);
+		I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT |
+				       ECOCHK_PPGTT_CACHE64B);
+		I915_WRITE(GFX_MODE, GFX_MODE_ENABLE(GFX_PPGTT_ENABLE));
+	} else if (INTEL_INFO(dev)->gen >= 7) {
+		I915_WRITE(GAM_ECOCHK, ECOCHK_PPGTT_CACHE64B);
+		/* GFX_MODE is per-ring on gen7+ */
+	}
+
+	for (i = 0; i < I915_NUM_RINGS; i++) {
+		ring = &dev_priv->ring[i];
+
+		if (INTEL_INFO(dev)->gen >= 7)
+			I915_WRITE(RING_MODE_GEN7(ring),
+				   GFX_MODE_ENABLE(GFX_PPGTT_ENABLE));
+
+		I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
+		I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset);
+	}
+}
+
 int
-i915_gem_init_ringbuffer(struct drm_device *dev)
+i915_gem_init_hw(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	int ret;
 
+	i915_gem_init_swizzling(dev);
+
 	ret = intel_init_render_ring_buffer(dev);
 	if (ret)
 		return ret;
@@ -3769,6 +3834,8 @@
 
 	dev_priv->next_seqno = 1;
 
+	i915_gem_init_ppgtt(dev);
+
 	return 0;
 
 cleanup_bsd_ring:
@@ -3806,7 +3873,7 @@
 	mutex_lock(&dev->struct_mutex);
 	dev_priv->mm.suspended = 0;
 
-	ret = i915_gem_init_ringbuffer(dev);
+	ret = i915_gem_init_hw(dev);
 	if (ret != 0) {
 		mutex_unlock(&dev->struct_mutex);
 		return ret;
@@ -4201,7 +4268,7 @@
 		 * This has a dramatic impact to reduce the number of
 		 * OOM-killer events whilst running the GPU aggressively.
 		 */
-		if (i915_gpu_idle(dev) == 0)
+		if (i915_gpu_idle(dev, true) == 0)
 			goto rescan;
 	}
 	mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index ead5d00..21a8271 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -36,7 +36,6 @@
 mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind)
 {
 	list_add(&obj->exec_list, unwind);
-	drm_gem_object_reference(&obj->base);
 	return drm_mm_scan_add_block(obj->gtt_space);
 }
 
@@ -49,21 +48,6 @@
 	struct drm_i915_gem_object *obj;
 	int ret = 0;
 
-	i915_gem_retire_requests(dev);
-
-	/* Re-check for free space after retiring requests */
-	if (mappable) {
-		if (drm_mm_search_free_in_range(&dev_priv->mm.gtt_space,
-						min_size, alignment, 0,
-						dev_priv->mm.gtt_mappable_end,
-						0))
-			return 0;
-	} else {
-		if (drm_mm_search_free(&dev_priv->mm.gtt_space,
-				       min_size, alignment, 0))
-			return 0;
-	}
-
 	trace_i915_gem_evict(dev, min_size, alignment, mappable);
 
 	/*
@@ -139,7 +123,6 @@
 		BUG_ON(ret);
 
 		list_del_init(&obj->exec_list);
-		drm_gem_object_unreference(&obj->base);
 	}
 
 	/* We expect the caller to unpin, evict all and try again, or give up.
@@ -158,10 +141,10 @@
 				       exec_list);
 		if (drm_mm_scan_remove_block(obj->gtt_space)) {
 			list_move(&obj->exec_list, &eviction_list);
+			drm_gem_object_reference(&obj->base);
 			continue;
 		}
 		list_del_init(&obj->exec_list);
-		drm_gem_object_unreference(&obj->base);
 	}
 
 	/* Unbinding will emit any required flushes */
@@ -195,7 +178,7 @@
 	trace_i915_gem_evict_everything(dev, purgeable_only);
 
 	/* Flush everything (on to the inactive lists) and evict */
-	ret = i915_gpu_idle(dev);
+	ret = i915_gpu_idle(dev, true);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 65e1f00..f51a696 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -203,9 +203,9 @@
 	cd->invalidate_domains |= invalidate_domains;
 	cd->flush_domains |= flush_domains;
 	if (flush_domains & I915_GEM_GPU_DOMAINS)
-		cd->flush_rings |= obj->ring->id;
+		cd->flush_rings |= intel_ring_flag(obj->ring);
 	if (invalidate_domains & I915_GEM_GPU_DOMAINS)
-		cd->flush_rings |= ring->id;
+		cd->flush_rings |= intel_ring_flag(ring);
 }
 
 struct eb_objects {
@@ -287,14 +287,14 @@
 	 * exec_object list, so it should have a GTT space bound by now.
 	 */
 	if (unlikely(target_offset == 0)) {
-		DRM_ERROR("No GTT space found for object %d\n",
+		DRM_DEBUG("No GTT space found for object %d\n",
 			  reloc->target_handle);
 		return ret;
 	}
 
 	/* Validate that the target is in a valid r/w GPU domain */
 	if (unlikely(reloc->write_domain & (reloc->write_domain - 1))) {
-		DRM_ERROR("reloc with multiple write domains: "
+		DRM_DEBUG("reloc with multiple write domains: "
 			  "obj %p target %d offset %d "
 			  "read %08x write %08x",
 			  obj, reloc->target_handle,
@@ -303,8 +303,9 @@
 			  reloc->write_domain);
 		return ret;
 	}
-	if (unlikely((reloc->write_domain | reloc->read_domains) & I915_GEM_DOMAIN_CPU)) {
-		DRM_ERROR("reloc with read/write CPU domains: "
+	if (unlikely((reloc->write_domain | reloc->read_domains)
+		     & ~I915_GEM_GPU_DOMAINS)) {
+		DRM_DEBUG("reloc with read/write non-GPU domains: "
 			  "obj %p target %d offset %d "
 			  "read %08x write %08x",
 			  obj, reloc->target_handle,
@@ -315,7 +316,7 @@
 	}
 	if (unlikely(reloc->write_domain && target_obj->pending_write_domain &&
 		     reloc->write_domain != target_obj->pending_write_domain)) {
-		DRM_ERROR("Write domain conflict: "
+		DRM_DEBUG("Write domain conflict: "
 			  "obj %p target %d offset %d "
 			  "new %08x old %08x\n",
 			  obj, reloc->target_handle,
@@ -336,7 +337,7 @@
 
 	/* Check that the relocation address is valid... */
 	if (unlikely(reloc->offset > obj->base.size - 4)) {
-		DRM_ERROR("Relocation beyond object bounds: "
+		DRM_DEBUG("Relocation beyond object bounds: "
 			  "obj %p target %d offset %d size %d.\n",
 			  obj, reloc->target_handle,
 			  (int) reloc->offset,
@@ -344,7 +345,7 @@
 		return ret;
 	}
 	if (unlikely(reloc->offset & 3)) {
-		DRM_ERROR("Relocation not 4-byte aligned: "
+		DRM_DEBUG("Relocation not 4-byte aligned: "
 			  "obj %p target %d offset %d.\n",
 			  obj, reloc->target_handle,
 			  (int) reloc->offset);
@@ -461,11 +462,60 @@
 	return ret;
 }
 
+#define  __EXEC_OBJECT_HAS_FENCE (1<<31)
+
+static int
+pin_and_fence_object(struct drm_i915_gem_object *obj,
+		     struct intel_ring_buffer *ring)
+{
+	struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
+	bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
+	bool need_fence, need_mappable;
+	int ret;
+
+	need_fence =
+		has_fenced_gpu_access &&
+		entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
+		obj->tiling_mode != I915_TILING_NONE;
+	need_mappable =
+		entry->relocation_count ? true : need_fence;
+
+	ret = i915_gem_object_pin(obj, entry->alignment, need_mappable);
+	if (ret)
+		return ret;
+
+	if (has_fenced_gpu_access) {
+		if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
+			if (obj->tiling_mode) {
+				ret = i915_gem_object_get_fence(obj, ring);
+				if (ret)
+					goto err_unpin;
+
+				entry->flags |= __EXEC_OBJECT_HAS_FENCE;
+				i915_gem_object_pin_fence(obj);
+			} else {
+				ret = i915_gem_object_put_fence(obj);
+				if (ret)
+					goto err_unpin;
+			}
+			obj->pending_fenced_gpu_access = true;
+		}
+	}
+
+	entry->offset = obj->gtt_offset;
+	return 0;
+
+err_unpin:
+	i915_gem_object_unpin(obj);
+	return ret;
+}
+
 static int
 i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
 			    struct drm_file *file,
 			    struct list_head *objects)
 {
+	drm_i915_private_t *dev_priv = ring->dev->dev_private;
 	struct drm_i915_gem_object *obj;
 	int ret, retry;
 	bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
@@ -518,6 +568,7 @@
 		list_for_each_entry(obj, objects, exec_list) {
 			struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
 			bool need_fence, need_mappable;
+
 			if (!obj->gtt_space)
 				continue;
 
@@ -532,58 +583,55 @@
 			    (need_mappable && !obj->map_and_fenceable))
 				ret = i915_gem_object_unbind(obj);
 			else
-				ret = i915_gem_object_pin(obj,
-							  entry->alignment,
-							  need_mappable);
+				ret = pin_and_fence_object(obj, ring);
 			if (ret)
 				goto err;
-
-			entry++;
 		}
 
 		/* Bind fresh objects */
 		list_for_each_entry(obj, objects, exec_list) {
-			struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
-			bool need_fence;
+			if (obj->gtt_space)
+				continue;
 
-			need_fence =
-				has_fenced_gpu_access &&
-				entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
-				obj->tiling_mode != I915_TILING_NONE;
+			ret = pin_and_fence_object(obj, ring);
+			if (ret) {
+				int ret_ignore;
 
-			if (!obj->gtt_space) {
-				bool need_mappable =
-					entry->relocation_count ? true : need_fence;
-
-				ret = i915_gem_object_pin(obj,
-							  entry->alignment,
-							  need_mappable);
-				if (ret)
-					break;
+				/* This can potentially raise a harmless
+				 * -EINVAL if we failed to bind in the above
+				 * call. It cannot raise -EINTR since we know
+				 * that the bo is freshly bound and so will
+				 * not need to be flushed or waited upon.
+				 */
+				ret_ignore = i915_gem_object_unbind(obj);
+				(void)ret_ignore;
+				WARN_ON(obj->gtt_space);
+				break;
 			}
-
-			if (has_fenced_gpu_access) {
-				if (need_fence) {
-					ret = i915_gem_object_get_fence(obj, ring);
-					if (ret)
-						break;
-				} else if (entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
-					   obj->tiling_mode == I915_TILING_NONE) {
-					/* XXX pipelined! */
-					ret = i915_gem_object_put_fence(obj);
-					if (ret)
-						break;
-				}
-				obj->pending_fenced_gpu_access = need_fence;
-			}
-
-			entry->offset = obj->gtt_offset;
 		}
 
 		/* Decrement pin count for bound objects */
 		list_for_each_entry(obj, objects, exec_list) {
-			if (obj->gtt_space)
-				i915_gem_object_unpin(obj);
+			struct drm_i915_gem_exec_object2 *entry;
+
+			if (!obj->gtt_space)
+				continue;
+
+			entry = obj->exec_entry;
+			if (entry->flags & __EXEC_OBJECT_HAS_FENCE) {
+				i915_gem_object_unpin_fence(obj);
+				entry->flags &= ~__EXEC_OBJECT_HAS_FENCE;
+			}
+
+			i915_gem_object_unpin(obj);
+
+			/* ... and ensure ppgtt mapping exist if needed. */
+			if (dev_priv->mm.aliasing_ppgtt && !obj->has_aliasing_ppgtt_mapping) {
+				i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
+						       obj, obj->cache_level);
+
+				obj->has_aliasing_ppgtt_mapping = 1;
+			}
 		}
 
 		if (ret != -ENOSPC || retry > 1)
@@ -600,16 +648,19 @@
 	} while (1);
 
 err:
-	obj = list_entry(obj->exec_list.prev,
-			 struct drm_i915_gem_object,
-			 exec_list);
-	while (objects != &obj->exec_list) {
-		if (obj->gtt_space)
-			i915_gem_object_unpin(obj);
+	list_for_each_entry_continue_reverse(obj, objects, exec_list) {
+		struct drm_i915_gem_exec_object2 *entry;
 
-		obj = list_entry(obj->exec_list.prev,
-				 struct drm_i915_gem_object,
-				 exec_list);
+		if (!obj->gtt_space)
+			continue;
+
+		entry = obj->exec_entry;
+		if (entry->flags & __EXEC_OBJECT_HAS_FENCE) {
+			i915_gem_object_unpin_fence(obj);
+			entry->flags &= ~__EXEC_OBJECT_HAS_FENCE;
+		}
+
+		i915_gem_object_unpin(obj);
 	}
 
 	return ret;
@@ -682,7 +733,7 @@
 		obj = to_intel_bo(drm_gem_object_lookup(dev, file,
 							exec[i].handle));
 		if (&obj->base == NULL) {
-			DRM_ERROR("Invalid object handle %d at index %d\n",
+			DRM_DEBUG("Invalid object handle %d at index %d\n",
 				   exec[i].handle, i);
 			ret = -ENOENT;
 			goto err;
@@ -1013,7 +1064,7 @@
 	int ret, mode, i;
 
 	if (!i915_gem_check_execbuffer(args)) {
-		DRM_ERROR("execbuf with invalid offset/length\n");
+		DRM_DEBUG("execbuf with invalid offset/length\n");
 		return -EINVAL;
 	}
 
@@ -1028,20 +1079,20 @@
 		break;
 	case I915_EXEC_BSD:
 		if (!HAS_BSD(dev)) {
-			DRM_ERROR("execbuf with invalid ring (BSD)\n");
+			DRM_DEBUG("execbuf with invalid ring (BSD)\n");
 			return -EINVAL;
 		}
 		ring = &dev_priv->ring[VCS];
 		break;
 	case I915_EXEC_BLT:
 		if (!HAS_BLT(dev)) {
-			DRM_ERROR("execbuf with invalid ring (BLT)\n");
+			DRM_DEBUG("execbuf with invalid ring (BLT)\n");
 			return -EINVAL;
 		}
 		ring = &dev_priv->ring[BCS];
 		break;
 	default:
-		DRM_ERROR("execbuf with unknown ring: %d\n",
+		DRM_DEBUG("execbuf with unknown ring: %d\n",
 			  (int)(args->flags & I915_EXEC_RING_MASK));
 		return -EINVAL;
 	}
@@ -1067,18 +1118,18 @@
 		}
 		break;
 	default:
-		DRM_ERROR("execbuf with unknown constants: %d\n", mode);
+		DRM_DEBUG("execbuf with unknown constants: %d\n", mode);
 		return -EINVAL;
 	}
 
 	if (args->buffer_count < 1) {
-		DRM_ERROR("execbuf with %d buffers\n", args->buffer_count);
+		DRM_DEBUG("execbuf with %d buffers\n", args->buffer_count);
 		return -EINVAL;
 	}
 
 	if (args->num_cliprects != 0) {
 		if (ring != &dev_priv->ring[RCS]) {
-			DRM_ERROR("clip rectangles are only valid with the render ring\n");
+			DRM_DEBUG("clip rectangles are only valid with the render ring\n");
 			return -EINVAL;
 		}
 
@@ -1123,7 +1174,7 @@
 		obj = to_intel_bo(drm_gem_object_lookup(dev, file,
 							exec[i].handle));
 		if (&obj->base == NULL) {
-			DRM_ERROR("Invalid object handle %d at index %d\n",
+			DRM_DEBUG("Invalid object handle %d at index %d\n",
 				   exec[i].handle, i);
 			/* prevent error path from reading uninitialized data */
 			ret = -ENOENT;
@@ -1131,7 +1182,7 @@
 		}
 
 		if (!list_empty(&obj->exec_list)) {
-			DRM_ERROR("Object %p [handle %d, index %d] appears more than once in object list\n",
+			DRM_DEBUG("Object %p [handle %d, index %d] appears more than once in object list\n",
 				   obj, exec[i].handle, i);
 			ret = -EINVAL;
 			goto err;
@@ -1169,7 +1220,7 @@
 
 	/* Set the pending read domains for the batch buffer to COMMAND */
 	if (batch_obj->base.pending_write_domain) {
-		DRM_ERROR("Attempting to use self-modifying batch buffer\n");
+		DRM_DEBUG("Attempting to use self-modifying batch buffer\n");
 		ret = -EINVAL;
 		goto err;
 	}
@@ -1186,7 +1237,7 @@
 			 * so every billion or so execbuffers, we need to stall
 			 * the GPU in order to reset the counters.
 			 */
-			ret = i915_gpu_idle(dev);
+			ret = i915_gpu_idle(dev, true);
 			if (ret)
 				goto err;
 
@@ -1274,7 +1325,7 @@
 	int ret, i;
 
 	if (args->buffer_count < 1) {
-		DRM_ERROR("execbuf with %d buffers\n", args->buffer_count);
+		DRM_DEBUG("execbuf with %d buffers\n", args->buffer_count);
 		return -EINVAL;
 	}
 
@@ -1282,7 +1333,7 @@
 	exec_list = drm_malloc_ab(sizeof(*exec_list), args->buffer_count);
 	exec2_list = drm_malloc_ab(sizeof(*exec2_list), args->buffer_count);
 	if (exec_list == NULL || exec2_list == NULL) {
-		DRM_ERROR("Failed to allocate exec list for %d buffers\n",
+		DRM_DEBUG("Failed to allocate exec list for %d buffers\n",
 			  args->buffer_count);
 		drm_free_large(exec_list);
 		drm_free_large(exec2_list);
@@ -1293,7 +1344,7 @@
 			     (uintptr_t) args->buffers_ptr,
 			     sizeof(*exec_list) * args->buffer_count);
 	if (ret != 0) {
-		DRM_ERROR("copy %d exec entries failed %d\n",
+		DRM_DEBUG("copy %d exec entries failed %d\n",
 			  args->buffer_count, ret);
 		drm_free_large(exec_list);
 		drm_free_large(exec2_list);
@@ -1334,7 +1385,7 @@
 				   sizeof(*exec_list) * args->buffer_count);
 		if (ret) {
 			ret = -EFAULT;
-			DRM_ERROR("failed to copy %d exec entries "
+			DRM_DEBUG("failed to copy %d exec entries "
 				  "back to user (%d)\n",
 				  args->buffer_count, ret);
 		}
@@ -1354,7 +1405,7 @@
 	int ret;
 
 	if (args->buffer_count < 1) {
-		DRM_ERROR("execbuf2 with %d buffers\n", args->buffer_count);
+		DRM_DEBUG("execbuf2 with %d buffers\n", args->buffer_count);
 		return -EINVAL;
 	}
 
@@ -1364,7 +1415,7 @@
 		exec2_list = drm_malloc_ab(sizeof(*exec2_list),
 					   args->buffer_count);
 	if (exec2_list == NULL) {
-		DRM_ERROR("Failed to allocate exec list for %d buffers\n",
+		DRM_DEBUG("Failed to allocate exec list for %d buffers\n",
 			  args->buffer_count);
 		return -ENOMEM;
 	}
@@ -1373,7 +1424,7 @@
 			     (uintptr_t) args->buffers_ptr,
 			     sizeof(*exec2_list) * args->buffer_count);
 	if (ret != 0) {
-		DRM_ERROR("copy %d exec entries failed %d\n",
+		DRM_DEBUG("copy %d exec entries failed %d\n",
 			  args->buffer_count, ret);
 		drm_free_large(exec2_list);
 		return -EFAULT;
@@ -1388,7 +1439,7 @@
 				   sizeof(*exec2_list) * args->buffer_count);
 		if (ret) {
 			ret = -EFAULT;
-			DRM_ERROR("failed to copy %d exec entries "
+			DRM_DEBUG("failed to copy %d exec entries "
 				  "back to user (%d)\n",
 				  args->buffer_count, ret);
 		}
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 6042c5e..a135c61 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -29,6 +29,270 @@
 #include "i915_trace.h"
 #include "intel_drv.h"
 
+/* PPGTT support for Sandybdrige/Gen6 and later */
+static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
+				   unsigned first_entry,
+				   unsigned num_entries)
+{
+	uint32_t *pt_vaddr;
+	uint32_t scratch_pte;
+	unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
+	unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
+	unsigned last_pte, i;
+
+	scratch_pte = GEN6_PTE_ADDR_ENCODE(ppgtt->scratch_page_dma_addr);
+	scratch_pte |= GEN6_PTE_VALID | GEN6_PTE_CACHE_LLC;
+
+	while (num_entries) {
+		last_pte = first_pte + num_entries;
+		if (last_pte > I915_PPGTT_PT_ENTRIES)
+			last_pte = I915_PPGTT_PT_ENTRIES;
+
+		pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]);
+
+		for (i = first_pte; i < last_pte; i++)
+			pt_vaddr[i] = scratch_pte;
+
+		kunmap_atomic(pt_vaddr);
+
+		num_entries -= last_pte - first_pte;
+		first_pte = 0;
+		act_pd++;
+	}
+}
+
+int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct i915_hw_ppgtt *ppgtt;
+	unsigned first_pd_entry_in_global_pt;
+	int i;
+	int ret = -ENOMEM;
+
+	/* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024
+	 * entries. For aliasing ppgtt support we just steal them at the end for
+	 * now. */
+	first_pd_entry_in_global_pt = 512*1024 - I915_PPGTT_PD_ENTRIES;
+
+	ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
+	if (!ppgtt)
+		return ret;
+
+	ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES;
+	ppgtt->pt_pages = kzalloc(sizeof(struct page *)*ppgtt->num_pd_entries,
+				  GFP_KERNEL);
+	if (!ppgtt->pt_pages)
+		goto err_ppgtt;
+
+	for (i = 0; i < ppgtt->num_pd_entries; i++) {
+		ppgtt->pt_pages[i] = alloc_page(GFP_KERNEL);
+		if (!ppgtt->pt_pages[i])
+			goto err_pt_alloc;
+	}
+
+	if (dev_priv->mm.gtt->needs_dmar) {
+		ppgtt->pt_dma_addr = kzalloc(sizeof(dma_addr_t)
+						*ppgtt->num_pd_entries,
+					     GFP_KERNEL);
+		if (!ppgtt->pt_dma_addr)
+			goto err_pt_alloc;
+	}
+
+	for (i = 0; i < ppgtt->num_pd_entries; i++) {
+		dma_addr_t pt_addr;
+		if (dev_priv->mm.gtt->needs_dmar) {
+			pt_addr = pci_map_page(dev->pdev, ppgtt->pt_pages[i],
+					       0, 4096,
+					       PCI_DMA_BIDIRECTIONAL);
+
+			if (pci_dma_mapping_error(dev->pdev,
+						  pt_addr)) {
+				ret = -EIO;
+				goto err_pd_pin;
+
+			}
+			ppgtt->pt_dma_addr[i] = pt_addr;
+		} else
+			pt_addr = page_to_phys(ppgtt->pt_pages[i]);
+	}
+
+	ppgtt->scratch_page_dma_addr = dev_priv->mm.gtt->scratch_page_dma;
+
+	i915_ppgtt_clear_range(ppgtt, 0,
+			       ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES);
+
+	ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(uint32_t);
+
+	dev_priv->mm.aliasing_ppgtt = ppgtt;
+
+	return 0;
+
+err_pd_pin:
+	if (ppgtt->pt_dma_addr) {
+		for (i--; i >= 0; i--)
+			pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i],
+				       4096, PCI_DMA_BIDIRECTIONAL);
+	}
+err_pt_alloc:
+	kfree(ppgtt->pt_dma_addr);
+	for (i = 0; i < ppgtt->num_pd_entries; i++) {
+		if (ppgtt->pt_pages[i])
+			__free_page(ppgtt->pt_pages[i]);
+	}
+	kfree(ppgtt->pt_pages);
+err_ppgtt:
+	kfree(ppgtt);
+
+	return ret;
+}
+
+void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+	int i;
+
+	if (!ppgtt)
+		return;
+
+	if (ppgtt->pt_dma_addr) {
+		for (i = 0; i < ppgtt->num_pd_entries; i++)
+			pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i],
+				       4096, PCI_DMA_BIDIRECTIONAL);
+	}
+
+	kfree(ppgtt->pt_dma_addr);
+	for (i = 0; i < ppgtt->num_pd_entries; i++)
+		__free_page(ppgtt->pt_pages[i]);
+	kfree(ppgtt->pt_pages);
+	kfree(ppgtt);
+}
+
+static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt,
+					 struct scatterlist *sg_list,
+					 unsigned sg_len,
+					 unsigned first_entry,
+					 uint32_t pte_flags)
+{
+	uint32_t *pt_vaddr, pte;
+	unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
+	unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
+	unsigned i, j, m, segment_len;
+	dma_addr_t page_addr;
+	struct scatterlist *sg;
+
+	/* init sg walking */
+	sg = sg_list;
+	i = 0;
+	segment_len = sg_dma_len(sg) >> PAGE_SHIFT;
+	m = 0;
+
+	while (i < sg_len) {
+		pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]);
+
+		for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) {
+			page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
+			pte = GEN6_PTE_ADDR_ENCODE(page_addr);
+			pt_vaddr[j] = pte | pte_flags;
+
+			/* grab the next page */
+			m++;
+			if (m == segment_len) {
+				sg = sg_next(sg);
+				i++;
+				if (i == sg_len)
+					break;
+
+				segment_len = sg_dma_len(sg) >> PAGE_SHIFT;
+				m = 0;
+			}
+		}
+
+		kunmap_atomic(pt_vaddr);
+
+		first_pte = 0;
+		act_pd++;
+	}
+}
+
+static void i915_ppgtt_insert_pages(struct i915_hw_ppgtt *ppgtt,
+				    unsigned first_entry, unsigned num_entries,
+				    struct page **pages, uint32_t pte_flags)
+{
+	uint32_t *pt_vaddr, pte;
+	unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
+	unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
+	unsigned last_pte, i;
+	dma_addr_t page_addr;
+
+	while (num_entries) {
+		last_pte = first_pte + num_entries;
+		last_pte = min_t(unsigned, last_pte, I915_PPGTT_PT_ENTRIES);
+
+		pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]);
+
+		for (i = first_pte; i < last_pte; i++) {
+			page_addr = page_to_phys(*pages);
+			pte = GEN6_PTE_ADDR_ENCODE(page_addr);
+			pt_vaddr[i] = pte | pte_flags;
+
+			pages++;
+		}
+
+		kunmap_atomic(pt_vaddr);
+
+		num_entries -= last_pte - first_pte;
+		first_pte = 0;
+		act_pd++;
+	}
+}
+
+void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
+			    struct drm_i915_gem_object *obj,
+			    enum i915_cache_level cache_level)
+{
+	struct drm_device *dev = obj->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t pte_flags = GEN6_PTE_VALID;
+
+	switch (cache_level) {
+	case I915_CACHE_LLC_MLC:
+		pte_flags |= GEN6_PTE_CACHE_LLC_MLC;
+		break;
+	case I915_CACHE_LLC:
+		pte_flags |= GEN6_PTE_CACHE_LLC;
+		break;
+	case I915_CACHE_NONE:
+		pte_flags |= GEN6_PTE_UNCACHED;
+		break;
+	default:
+		BUG();
+	}
+
+	if (dev_priv->mm.gtt->needs_dmar) {
+		BUG_ON(!obj->sg_list);
+
+		i915_ppgtt_insert_sg_entries(ppgtt,
+					     obj->sg_list,
+					     obj->num_sg,
+					     obj->gtt_space->start >> PAGE_SHIFT,
+					     pte_flags);
+	} else
+		i915_ppgtt_insert_pages(ppgtt,
+					obj->gtt_space->start >> PAGE_SHIFT,
+					obj->base.size >> PAGE_SHIFT,
+					obj->pages,
+					pte_flags);
+}
+
+void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
+			      struct drm_i915_gem_object *obj)
+{
+	i915_ppgtt_clear_range(ppgtt,
+			       obj->gtt_space->start >> PAGE_SHIFT,
+			       obj->base.size >> PAGE_SHIFT);
+}
+
 /* XXX kill agp_type! */
 static unsigned int cache_level_to_agp_type(struct drm_device *dev,
 					    enum i915_cache_level cache_level)
@@ -55,7 +319,7 @@
 
 	if (unlikely(dev_priv->mm.gtt->do_idle_maps)) {
 		dev_priv->mm.interruptible = false;
-		if (i915_gpu_idle(dev_priv->dev)) {
+		if (i915_gpu_idle(dev_priv->dev, false)) {
 			DRM_ERROR("Couldn't idle GPU\n");
 			/* Wait a bit, in hopes it avoids the hang */
 			udelay(10);
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 31d334d..1a93066 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -93,8 +93,23 @@
 	uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
 
 	if (INTEL_INFO(dev)->gen >= 6) {
-		swizzle_x = I915_BIT_6_SWIZZLE_NONE;
-		swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+		uint32_t dimm_c0, dimm_c1;
+		dimm_c0 = I915_READ(MAD_DIMM_C0);
+		dimm_c1 = I915_READ(MAD_DIMM_C1);
+		dimm_c0 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK;
+		dimm_c1 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK;
+		/* Enable swizzling when the channels are populated with
+		 * identically sized dimms. We don't need to check the 3rd
+		 * channel because no cpu with gpu attached ships in that
+		 * configuration. Also, swizzling only makes sense for 2
+		 * channels anyway. */
+		if (dimm_c0 == dimm_c1) {
+			swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+			swizzle_y = I915_BIT_6_SWIZZLE_9;
+		} else {
+			swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+			swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+		}
 	} else if (IS_GEN5(dev)) {
 		/* On Ironlake whatever DRAM config, GPU always do
 		 * same swizzling setup.
@@ -107,10 +122,10 @@
 		 */
 		swizzle_x = I915_BIT_6_SWIZZLE_NONE;
 		swizzle_y = I915_BIT_6_SWIZZLE_NONE;
-	} else if (IS_MOBILE(dev)) {
+	} else if (IS_MOBILE(dev) || (IS_GEN3(dev) && !IS_G33(dev))) {
 		uint32_t dcc;
 
-		/* On mobile 9xx chipsets, channel interleave by the CPU is
+		/* On 9xx chipsets, channel interleave by the CPU is
 		 * determined by DCC.  For single-channel, neither the CPU
 		 * nor the GPU do swizzling.  For dual channel interleaved,
 		 * the GPU's interleave is bit 9 and 10 for X tiled, and bit
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 5bd4361..afd4e03 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -720,7 +720,6 @@
 	reloc_offset = src->gtt_offset;
 	for (page = 0; page < page_count; page++) {
 		unsigned long flags;
-		void __iomem *s;
 		void *d;
 
 		d = kmalloc(PAGE_SIZE, GFP_ATOMIC);
@@ -728,10 +727,29 @@
 			goto unwind;
 
 		local_irq_save(flags);
-		s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
-					     reloc_offset);
-		memcpy_fromio(d, s, PAGE_SIZE);
-		io_mapping_unmap_atomic(s);
+		if (reloc_offset < dev_priv->mm.gtt_mappable_end) {
+			void __iomem *s;
+
+			/* Simply ignore tiling or any overlapping fence.
+			 * It's part of the error state, and this hopefully
+			 * captures what the GPU read.
+			 */
+
+			s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
+						     reloc_offset);
+			memcpy_fromio(d, s, PAGE_SIZE);
+			io_mapping_unmap_atomic(s);
+		} else {
+			void *s;
+
+			drm_clflush_pages(&src->pages[page], 1);
+
+			s = kmap_atomic(src->pages[page]);
+			memcpy(d, s, PAGE_SIZE);
+			kunmap_atomic(s);
+
+			drm_clflush_pages(&src->pages[page], 1);
+		}
 		local_irq_restore(flags);
 
 		dst->pages[page] = d;
@@ -770,11 +788,11 @@
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(error->batchbuffer); i++)
-		i915_error_object_free(error->batchbuffer[i]);
-
-	for (i = 0; i < ARRAY_SIZE(error->ringbuffer); i++)
-		i915_error_object_free(error->ringbuffer[i]);
+	for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
+		i915_error_object_free(error->ring[i].batchbuffer);
+		i915_error_object_free(error->ring[i].ringbuffer);
+		kfree(error->ring[i].requests);
+	}
 
 	kfree(error->active_bo);
 	kfree(error->overlay);
@@ -804,7 +822,7 @@
 		err->tiling = obj->tiling_mode;
 		err->dirty = obj->dirty;
 		err->purgeable = obj->madv != I915_MADV_WILLNEED;
-		err->ring = obj->ring ? obj->ring->id : 0;
+		err->ring = obj->ring ? obj->ring->id : -1;
 		err->cache_level = obj->cache_level;
 
 		if (++i == count)
@@ -876,6 +894,92 @@
 	return NULL;
 }
 
+static void i915_record_ring_state(struct drm_device *dev,
+				   struct drm_i915_error_state *error,
+				   struct intel_ring_buffer *ring)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (INTEL_INFO(dev)->gen >= 6) {
+		error->faddr[ring->id] = I915_READ(RING_DMA_FADD(ring->mmio_base));
+		error->fault_reg[ring->id] = I915_READ(RING_FAULT_REG(ring));
+		error->semaphore_mboxes[ring->id][0]
+			= I915_READ(RING_SYNC_0(ring->mmio_base));
+		error->semaphore_mboxes[ring->id][1]
+			= I915_READ(RING_SYNC_1(ring->mmio_base));
+	}
+
+	if (INTEL_INFO(dev)->gen >= 4) {
+		error->ipeir[ring->id] = I915_READ(RING_IPEIR(ring->mmio_base));
+		error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base));
+		error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base));
+		error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base));
+		if (ring->id == RCS) {
+			error->instdone1 = I915_READ(INSTDONE1);
+			error->bbaddr = I915_READ64(BB_ADDR);
+		}
+	} else {
+		error->ipeir[ring->id] = I915_READ(IPEIR);
+		error->ipehr[ring->id] = I915_READ(IPEHR);
+		error->instdone[ring->id] = I915_READ(INSTDONE);
+	}
+
+	error->instpm[ring->id] = I915_READ(RING_INSTPM(ring->mmio_base));
+	error->seqno[ring->id] = ring->get_seqno(ring);
+	error->acthd[ring->id] = intel_ring_get_active_head(ring);
+	error->head[ring->id] = I915_READ_HEAD(ring);
+	error->tail[ring->id] = I915_READ_TAIL(ring);
+
+	error->cpu_ring_head[ring->id] = ring->head;
+	error->cpu_ring_tail[ring->id] = ring->tail;
+}
+
+static void i915_gem_record_rings(struct drm_device *dev,
+				  struct drm_i915_error_state *error)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_gem_request *request;
+	int i, count;
+
+	for (i = 0; i < I915_NUM_RINGS; i++) {
+		struct intel_ring_buffer *ring = &dev_priv->ring[i];
+
+		if (ring->obj == NULL)
+			continue;
+
+		i915_record_ring_state(dev, error, ring);
+
+		error->ring[i].batchbuffer =
+			i915_error_first_batchbuffer(dev_priv, ring);
+
+		error->ring[i].ringbuffer =
+			i915_error_object_create(dev_priv, ring->obj);
+
+		count = 0;
+		list_for_each_entry(request, &ring->request_list, list)
+			count++;
+
+		error->ring[i].num_requests = count;
+		error->ring[i].requests =
+			kmalloc(count*sizeof(struct drm_i915_error_request),
+				GFP_ATOMIC);
+		if (error->ring[i].requests == NULL) {
+			error->ring[i].num_requests = 0;
+			continue;
+		}
+
+		count = 0;
+		list_for_each_entry(request, &ring->request_list, list) {
+			struct drm_i915_error_request *erq;
+
+			erq = &error->ring[i].requests[count++];
+			erq->seqno = request->seqno;
+			erq->jiffies = request->emitted_jiffies;
+			erq->tail = request->tail;
+		}
+	}
+}
+
 /**
  * i915_capture_error_state - capture an error record for later analysis
  * @dev: drm device
@@ -900,7 +1004,7 @@
 		return;
 
 	/* Account for pipe specific data like PIPE*STAT */
-	error = kmalloc(sizeof(*error), GFP_ATOMIC);
+	error = kzalloc(sizeof(*error), GFP_ATOMIC);
 	if (!error) {
 		DRM_DEBUG_DRIVER("out of memory, not capturing error state\n");
 		return;
@@ -909,59 +1013,18 @@
 	DRM_INFO("capturing error event; look for more information in /debug/dri/%d/i915_error_state\n",
 		 dev->primary->index);
 
-	error->seqno = dev_priv->ring[RCS].get_seqno(&dev_priv->ring[RCS]);
 	error->eir = I915_READ(EIR);
 	error->pgtbl_er = I915_READ(PGTBL_ER);
 	for_each_pipe(pipe)
 		error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
-	error->instpm = I915_READ(INSTPM);
-	error->error = 0;
+
 	if (INTEL_INFO(dev)->gen >= 6) {
 		error->error = I915_READ(ERROR_GEN6);
-
-		error->bcs_acthd = I915_READ(BCS_ACTHD);
-		error->bcs_ipehr = I915_READ(BCS_IPEHR);
-		error->bcs_ipeir = I915_READ(BCS_IPEIR);
-		error->bcs_instdone = I915_READ(BCS_INSTDONE);
-		error->bcs_seqno = 0;
-		if (dev_priv->ring[BCS].get_seqno)
-			error->bcs_seqno = dev_priv->ring[BCS].get_seqno(&dev_priv->ring[BCS]);
-
-		error->vcs_acthd = I915_READ(VCS_ACTHD);
-		error->vcs_ipehr = I915_READ(VCS_IPEHR);
-		error->vcs_ipeir = I915_READ(VCS_IPEIR);
-		error->vcs_instdone = I915_READ(VCS_INSTDONE);
-		error->vcs_seqno = 0;
-		if (dev_priv->ring[VCS].get_seqno)
-			error->vcs_seqno = dev_priv->ring[VCS].get_seqno(&dev_priv->ring[VCS]);
+		error->done_reg = I915_READ(DONE_REG);
 	}
-	if (INTEL_INFO(dev)->gen >= 4) {
-		error->ipeir = I915_READ(IPEIR_I965);
-		error->ipehr = I915_READ(IPEHR_I965);
-		error->instdone = I915_READ(INSTDONE_I965);
-		error->instps = I915_READ(INSTPS);
-		error->instdone1 = I915_READ(INSTDONE1);
-		error->acthd = I915_READ(ACTHD_I965);
-		error->bbaddr = I915_READ64(BB_ADDR);
-	} else {
-		error->ipeir = I915_READ(IPEIR);
-		error->ipehr = I915_READ(IPEHR);
-		error->instdone = I915_READ(INSTDONE);
-		error->acthd = I915_READ(ACTHD);
-		error->bbaddr = 0;
-	}
+
 	i915_gem_record_fences(dev, error);
-
-	/* Record the active batch and ring buffers */
-	for (i = 0; i < I915_NUM_RINGS; i++) {
-		error->batchbuffer[i] =
-			i915_error_first_batchbuffer(dev_priv,
-						     &dev_priv->ring[i]);
-
-		error->ringbuffer[i] =
-			i915_error_object_create(dev_priv,
-						 dev_priv->ring[i].obj);
-	}
+	i915_gem_record_rings(dev, error);
 
 	/* Record buffers on the active and pinned lists. */
 	error->active_bo = NULL;
@@ -1017,11 +1080,12 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_error_state *error;
+	unsigned long flags;
 
-	spin_lock(&dev_priv->error_lock);
+	spin_lock_irqsave(&dev_priv->error_lock, flags);
 	error = dev_priv->first_error;
 	dev_priv->first_error = NULL;
-	spin_unlock(&dev_priv->error_lock);
+	spin_unlock_irqrestore(&dev_priv->error_lock, flags);
 
 	if (error)
 		i915_error_state_free(dev, error);
@@ -1698,6 +1762,7 @@
 	    dev_priv->last_instdone1 == instdone1) {
 		if (dev_priv->hangcheck_count++ > 1) {
 			DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
+			i915_handle_error(dev, true);
 
 			if (!IS_GEN2(dev)) {
 				/* Is the chip hanging on a WAIT_FOR_EVENT?
@@ -1705,7 +1770,6 @@
 				 * and break the hang. This should work on
 				 * all but the second generation chipsets.
 				 */
-
 				if (kick_ring(&dev_priv->ring[RCS]))
 					goto repeat;
 
@@ -1718,7 +1782,6 @@
 					goto repeat;
 			}
 
-			i915_handle_error(dev, true);
 			return;
 		}
 	} else {
@@ -1752,18 +1815,6 @@
 
 	I915_WRITE(HWSTAM, 0xeffe);
 
-	if (IS_GEN6(dev)) {
-		/* Workaround stalls observed on Sandy Bridge GPUs by
-		 * making the blitter command streamer generate a
-		 * write to the Hardware Status Page for
-		 * MI_USER_INTERRUPT.  This appears to serialize the
-		 * previous seqno write out before the interrupt
-		 * happens.
-		 */
-		I915_WRITE(GEN6_BLITTER_HWSTAM, ~GEN6_BLITTER_USER_INTERRUPT);
-		I915_WRITE(GEN6_BSD_HWSTAM, ~GEN6_BSD_USER_INTERRUPT);
-	}
-
 	/* XXX hotplug from PCH */
 
 	I915_WRITE(DEIMR, 0xffffffff);
diff --git a/drivers/gpu/drm/i915/i915_mem.c b/drivers/gpu/drm/i915/i915_mem.c
deleted file mode 100644
index cc8f6d4..0000000
--- a/drivers/gpu/drm/i915/i915_mem.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/* i915_mem.c -- Simple agp/fb memory manager for i915 -*- linux-c -*-
- */
-/*
- * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "drmP.h"
-#include "drm.h"
-#include "i915_drm.h"
-#include "i915_drv.h"
-
-/* This memory manager is integrated into the global/local lru
- * mechanisms used by the clients.  Specifically, it operates by
- * setting the 'in_use' fields of the global LRU to indicate whether
- * this region is privately allocated to a client.
- *
- * This does require the client to actually respect that field.
- *
- * Currently no effort is made to allocate 'private' memory in any
- * clever way - the LRU information isn't used to determine which
- * block to allocate, and the ring is drained prior to allocations --
- * in other words allocation is expensive.
- */
-static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
-	drm_i915_sarea_t *sarea_priv = master_priv->sarea_priv;
-	struct drm_tex_region *list;
-	unsigned shift, nr;
-	unsigned start;
-	unsigned end;
-	unsigned i;
-	int age;
-
-	shift = dev_priv->tex_lru_log_granularity;
-	nr = I915_NR_TEX_REGIONS;
-
-	start = p->start >> shift;
-	end = (p->start + p->size - 1) >> shift;
-
-	age = ++sarea_priv->texAge;
-	list = sarea_priv->texList;
-
-	/* Mark the regions with the new flag and update their age.  Move
-	 * them to head of list to preserve LRU semantics.
-	 */
-	for (i = start; i <= end; i++) {
-		list[i].in_use = in_use;
-		list[i].age = age;
-
-		/* remove_from_list(i)
-		 */
-		list[(unsigned)list[i].next].prev = list[i].prev;
-		list[(unsigned)list[i].prev].next = list[i].next;
-
-		/* insert_at_head(list, i)
-		 */
-		list[i].prev = nr;
-		list[i].next = list[nr].next;
-		list[(unsigned)list[nr].next].prev = i;
-		list[nr].next = i;
-	}
-}
-
-/* Very simple allocator for agp memory, working on a static range
- * already mapped into each client's address space.
- */
-
-static struct mem_block *split_block(struct mem_block *p, int start, int size,
-				     struct drm_file *file_priv)
-{
-	/* Maybe cut off the start of an existing block */
-	if (start > p->start) {
-		struct mem_block *newblock = kmalloc(sizeof(*newblock),
-						     GFP_KERNEL);
-		if (!newblock)
-			goto out;
-		newblock->start = start;
-		newblock->size = p->size - (start - p->start);
-		newblock->file_priv = NULL;
-		newblock->next = p->next;
-		newblock->prev = p;
-		p->next->prev = newblock;
-		p->next = newblock;
-		p->size -= newblock->size;
-		p = newblock;
-	}
-
-	/* Maybe cut off the end of an existing block */
-	if (size < p->size) {
-		struct mem_block *newblock = kmalloc(sizeof(*newblock),
-						     GFP_KERNEL);
-		if (!newblock)
-			goto out;
-		newblock->start = start + size;
-		newblock->size = p->size - size;
-		newblock->file_priv = NULL;
-		newblock->next = p->next;
-		newblock->prev = p;
-		p->next->prev = newblock;
-		p->next = newblock;
-		p->size = size;
-	}
-
-      out:
-	/* Our block is in the middle */
-	p->file_priv = file_priv;
-	return p;
-}
-
-static struct mem_block *alloc_block(struct mem_block *heap, int size,
-				     int align2, struct drm_file *file_priv)
-{
-	struct mem_block *p;
-	int mask = (1 << align2) - 1;
-
-	for (p = heap->next; p != heap; p = p->next) {
-		int start = (p->start + mask) & ~mask;
-		if (p->file_priv == NULL && start + size <= p->start + p->size)
-			return split_block(p, start, size, file_priv);
-	}
-
-	return NULL;
-}
-
-static struct mem_block *find_block(struct mem_block *heap, int start)
-{
-	struct mem_block *p;
-
-	for (p = heap->next; p != heap; p = p->next)
-		if (p->start == start)
-			return p;
-
-	return NULL;
-}
-
-static void free_block(struct mem_block *p)
-{
-	p->file_priv = NULL;
-
-	/* Assumes a single contiguous range.  Needs a special file_priv in
-	 * 'heap' to stop it being subsumed.
-	 */
-	if (p->next->file_priv == NULL) {
-		struct mem_block *q = p->next;
-		p->size += q->size;
-		p->next = q->next;
-		p->next->prev = p;
-		kfree(q);
-	}
-
-	if (p->prev->file_priv == NULL) {
-		struct mem_block *q = p->prev;
-		q->size += p->size;
-		q->next = p->next;
-		q->next->prev = q;
-		kfree(p);
-	}
-}
-
-/* Initialize.  How to check for an uninitialized heap?
- */
-static int init_heap(struct mem_block **heap, int start, int size)
-{
-	struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL);
-
-	if (!blocks)
-		return -ENOMEM;
-
-	*heap = kmalloc(sizeof(**heap), GFP_KERNEL);
-	if (!*heap) {
-		kfree(blocks);
-		return -ENOMEM;
-	}
-
-	blocks->start = start;
-	blocks->size = size;
-	blocks->file_priv = NULL;
-	blocks->next = blocks->prev = *heap;
-
-	memset(*heap, 0, sizeof(**heap));
-	(*heap)->file_priv = (struct drm_file *) -1;
-	(*heap)->next = (*heap)->prev = blocks;
-	return 0;
-}
-
-/* Free all blocks associated with the releasing file.
- */
-void i915_mem_release(struct drm_device * dev, struct drm_file *file_priv,
-		      struct mem_block *heap)
-{
-	struct mem_block *p;
-
-	if (!heap || !heap->next)
-		return;
-
-	for (p = heap->next; p != heap; p = p->next) {
-		if (p->file_priv == file_priv) {
-			p->file_priv = NULL;
-			mark_block(dev, p, 0);
-		}
-	}
-
-	/* Assumes a single contiguous range.  Needs a special file_priv in
-	 * 'heap' to stop it being subsumed.
-	 */
-	for (p = heap->next; p != heap; p = p->next) {
-		while (p->file_priv == NULL && p->next->file_priv == NULL) {
-			struct mem_block *q = p->next;
-			p->size += q->size;
-			p->next = q->next;
-			p->next->prev = p;
-			kfree(q);
-		}
-	}
-}
-
-/* Shutdown.
- */
-void i915_mem_takedown(struct mem_block **heap)
-{
-	struct mem_block *p;
-
-	if (!*heap)
-		return;
-
-	for (p = (*heap)->next; p != *heap;) {
-		struct mem_block *q = p;
-		p = p->next;
-		kfree(q);
-	}
-
-	kfree(*heap);
-	*heap = NULL;
-}
-
-static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region)
-{
-	switch (region) {
-	case I915_MEM_REGION_AGP:
-		return &dev_priv->agp_heap;
-	default:
-		return NULL;
-	}
-}
-
-/* IOCTL HANDLERS */
-
-int i915_mem_alloc(struct drm_device *dev, void *data,
-		   struct drm_file *file_priv)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	drm_i915_mem_alloc_t *alloc = data;
-	struct mem_block *block, **heap;
-
-	if (!dev_priv) {
-		DRM_ERROR("called with no initialization\n");
-		return -EINVAL;
-	}
-
-	heap = get_heap(dev_priv, alloc->region);
-	if (!heap || !*heap)
-		return -EFAULT;
-
-	/* Make things easier on ourselves: all allocations at least
-	 * 4k aligned.
-	 */
-	if (alloc->alignment < 12)
-		alloc->alignment = 12;
-
-	block = alloc_block(*heap, alloc->size, alloc->alignment, file_priv);
-
-	if (!block)
-		return -ENOMEM;
-
-	mark_block(dev, block, 1);
-
-	if (DRM_COPY_TO_USER(alloc->region_offset, &block->start,
-			     sizeof(int))) {
-		DRM_ERROR("copy_to_user\n");
-		return -EFAULT;
-	}
-
-	return 0;
-}
-
-int i915_mem_free(struct drm_device *dev, void *data,
-		  struct drm_file *file_priv)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	drm_i915_mem_free_t *memfree = data;
-	struct mem_block *block, **heap;
-
-	if (!dev_priv) {
-		DRM_ERROR("called with no initialization\n");
-		return -EINVAL;
-	}
-
-	heap = get_heap(dev_priv, memfree->region);
-	if (!heap || !*heap)
-		return -EFAULT;
-
-	block = find_block(*heap, memfree->region_offset);
-	if (!block)
-		return -EFAULT;
-
-	if (block->file_priv != file_priv)
-		return -EPERM;
-
-	mark_block(dev, block, 0);
-	free_block(block);
-	return 0;
-}
-
-int i915_mem_init_heap(struct drm_device *dev, void *data,
-		       struct drm_file *file_priv)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	drm_i915_mem_init_heap_t *initheap = data;
-	struct mem_block **heap;
-
-	if (!dev_priv) {
-		DRM_ERROR("called with no initialization\n");
-		return -EINVAL;
-	}
-
-	heap = get_heap(dev_priv, initheap->region);
-	if (!heap)
-		return -EFAULT;
-
-	if (*heap) {
-		DRM_ERROR("heap already initialized?");
-		return -EFAULT;
-	}
-
-	return init_heap(heap, initheap->start, initheap->size);
-}
-
-int i915_mem_destroy_heap(struct drm_device *dev, void *data,
-			   struct drm_file *file_priv)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	drm_i915_mem_destroy_heap_t *destroyheap = data;
-	struct mem_block **heap;
-
-	if (!dev_priv) {
-		DRM_ERROR("called with no initialization\n");
-		return -EINVAL;
-	}
-
-	heap = get_heap(dev_priv, destroyheap->region);
-	if (!heap) {
-		DRM_ERROR("get_heap failed");
-		return -EFAULT;
-	}
-
-	if (!*heap) {
-		DRM_ERROR("heap not initialized?");
-		return -EFAULT;
-	}
-
-	i915_mem_takedown(heap);
-	return 0;
-}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 558ac71..2abf4eb 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -86,12 +86,45 @@
 #define   GEN6_MBC_SNPCR_LOW	(2<<21)
 #define   GEN6_MBC_SNPCR_MIN	(3<<21) /* only 1/16th of the cache is shared */
 
+#define GEN6_MBCTL		0x0907c
+#define   GEN6_MBCTL_ENABLE_BOOT_FETCH	(1 << 4)
+#define   GEN6_MBCTL_CTX_FETCH_NEEDED	(1 << 3)
+#define   GEN6_MBCTL_BME_UPDATE_ENABLE	(1 << 2)
+#define   GEN6_MBCTL_MAE_UPDATE_ENABLE	(1 << 1)
+#define   GEN6_MBCTL_BOOT_FETCH_MECH	(1 << 0)
+
 #define GEN6_GDRST	0x941c
 #define  GEN6_GRDOM_FULL		(1 << 0)
 #define  GEN6_GRDOM_RENDER		(1 << 1)
 #define  GEN6_GRDOM_MEDIA		(1 << 2)
 #define  GEN6_GRDOM_BLT			(1 << 3)
 
+/* PPGTT stuff */
+#define GEN6_GTT_ADDR_ENCODE(addr)	((addr) | (((addr) >> 28) & 0xff0))
+
+#define GEN6_PDE_VALID			(1 << 0)
+#define GEN6_PDE_LARGE_PAGE		(2 << 0) /* use 32kb pages */
+/* gen6+ has bit 11-4 for physical addr bit 39-32 */
+#define GEN6_PDE_ADDR_ENCODE(addr)	GEN6_GTT_ADDR_ENCODE(addr)
+
+#define GEN6_PTE_VALID			(1 << 0)
+#define GEN6_PTE_UNCACHED		(1 << 1)
+#define GEN6_PTE_CACHE_LLC		(2 << 1)
+#define GEN6_PTE_CACHE_LLC_MLC		(3 << 1)
+#define GEN6_PTE_CACHE_BITS		(3 << 1)
+#define GEN6_PTE_GFDT			(1 << 3)
+#define GEN6_PTE_ADDR_ENCODE(addr)	GEN6_GTT_ADDR_ENCODE(addr)
+
+#define RING_PP_DIR_BASE(ring)		((ring)->mmio_base+0x228)
+#define RING_PP_DIR_BASE_READ(ring)	((ring)->mmio_base+0x518)
+#define RING_PP_DIR_DCLV(ring)		((ring)->mmio_base+0x220)
+#define   PP_DIR_DCLV_2G		0xffffffff
+
+#define GAM_ECOCHK			0x4090
+#define   ECOCHK_SNB_BIT		(1<<10)
+#define   ECOCHK_PPGTT_CACHE64B		(0x3<<3)
+#define   ECOCHK_PPGTT_CACHE4B		(0x0<<3)
+
 /* VGA stuff */
 
 #define VGA_ST01_MDA 0x3ba
@@ -295,6 +328,12 @@
 #define FENCE_REG_SANDYBRIDGE_0		0x100000
 #define   SANDYBRIDGE_FENCE_PITCH_SHIFT	32
 
+/* control register for cpu gtt access */
+#define TILECTL				0x101000
+#define   TILECTL_SWZCTL			(1 << 0)
+#define   TILECTL_TLB_PREFETCH_DIS	(1 << 2)
+#define   TILECTL_BACKSNOOP_DIS		(1 << 3)
+
 /*
  * Instruction and interrupt control regs
  */
@@ -318,7 +357,14 @@
 #define RING_MAX_IDLE(base)	((base)+0x54)
 #define RING_HWS_PGA(base)	((base)+0x80)
 #define RING_HWS_PGA_GEN6(base)	((base)+0x2080)
+#define ARB_MODE		0x04030
+#define   ARB_MODE_SWIZZLE_SNB	(1<<4)
+#define   ARB_MODE_SWIZZLE_IVB	(1<<5)
+#define   ARB_MODE_ENABLE(x)	GFX_MODE_ENABLE(x)
+#define   ARB_MODE_DISABLE(x)	GFX_MODE_DISABLE(x)
 #define RENDER_HWS_PGA_GEN7	(0x04080)
+#define RING_FAULT_REG(ring)	(0x4094 + 0x100*(ring)->id)
+#define DONE_REG		0x40b0
 #define BSD_HWS_PGA_GEN7	(0x04180)
 #define BLT_HWS_PGA_GEN7	(0x04280)
 #define RING_ACTHD(base)	((base)+0x74)
@@ -352,6 +398,12 @@
 #define IPEIR_I965	0x02064
 #define IPEHR_I965	0x02068
 #define INSTDONE_I965	0x0206c
+#define RING_IPEIR(base)	((base)+0x64)
+#define RING_IPEHR(base)	((base)+0x68)
+#define RING_INSTDONE(base)	((base)+0x6c)
+#define RING_INSTPS(base)	((base)+0x70)
+#define RING_DMA_FADD(base)	((base)+0x78)
+#define RING_INSTPM(base)	((base)+0xc0)
 #define INSTPS		0x02070 /* 965+ only */
 #define INSTDONE1	0x0207c /* 965+ only */
 #define ACTHD_I965	0x02074
@@ -365,14 +417,6 @@
 #define INSTDONE	0x02090
 #define NOPID		0x02094
 #define HWSTAM		0x02098
-#define VCS_INSTDONE	0x1206C
-#define VCS_IPEIR	0x12064
-#define VCS_IPEHR	0x12068
-#define VCS_ACTHD	0x12074
-#define BCS_INSTDONE	0x2206C
-#define BCS_IPEIR	0x22064
-#define BCS_IPEHR	0x22068
-#define BCS_ACTHD	0x22074
 
 #define ERROR_GEN6	0x040a0
 
@@ -391,10 +435,11 @@
 
 #define MI_MODE		0x0209c
 # define VS_TIMER_DISPATCH				(1 << 6)
-# define MI_FLUSH_ENABLE				(1 << 11)
+# define MI_FLUSH_ENABLE				(1 << 12)
 
 #define GFX_MODE	0x02520
 #define GFX_MODE_GEN7	0x0229c
+#define RING_MODE_GEN7(ring)	((ring)->mmio_base+0x29c)
 #define   GFX_RUN_LIST_ENABLE		(1<<15)
 #define   GFX_TLB_INVALIDATE_ALWAYS	(1<<13)
 #define   GFX_SURFACE_FAULT_ENABLE	(1<<12)
@@ -1037,6 +1082,29 @@
 #define C0DRB3			0x10206
 #define C1DRB3			0x10606
 
+/** snb MCH registers for reading the DRAM channel configuration */
+#define MAD_DIMM_C0			(MCHBAR_MIRROR_BASE_SNB + 0x5004)
+#define MAD_DIMM_C1			(MCHBAR_MIRROR_BASE_SNB + 0x5008)
+#define MAD_DIMM_C2			(MCHBAR_MIRROR_BASE_SNB + 0x500C)
+#define   MAD_DIMM_ECC_MASK		(0x3 << 24)
+#define   MAD_DIMM_ECC_OFF		(0x0 << 24)
+#define   MAD_DIMM_ECC_IO_ON_LOGIC_OFF	(0x1 << 24)
+#define   MAD_DIMM_ECC_IO_OFF_LOGIC_ON	(0x2 << 24)
+#define   MAD_DIMM_ECC_ON		(0x3 << 24)
+#define   MAD_DIMM_ENH_INTERLEAVE	(0x1 << 22)
+#define   MAD_DIMM_RANK_INTERLEAVE	(0x1 << 21)
+#define   MAD_DIMM_B_WIDTH_X16		(0x1 << 20) /* X8 chips if unset */
+#define   MAD_DIMM_A_WIDTH_X16		(0x1 << 19) /* X8 chips if unset */
+#define   MAD_DIMM_B_DUAL_RANK		(0x1 << 18)
+#define   MAD_DIMM_A_DUAL_RANK		(0x1 << 17)
+#define   MAD_DIMM_A_SELECT		(0x1 << 16)
+/* DIMM sizes are in multiples of 256mb. */
+#define   MAD_DIMM_B_SIZE_SHIFT		8
+#define   MAD_DIMM_B_SIZE_MASK		(0xff << MAD_DIMM_B_SIZE_SHIFT)
+#define   MAD_DIMM_A_SIZE_SHIFT		0
+#define   MAD_DIMM_A_SIZE_MASK		(0xff << MAD_DIMM_A_SIZE_SHIFT)
+
+
 /* Clocking configuration register */
 #define CLKCFG			0x10c00
 #define CLKCFG_FSB_400					(5 << 0)	/* hrawclk 100 */
@@ -1316,6 +1384,7 @@
 #define _VSYNC_A		0x60014
 #define _PIPEASRC	0x6001c
 #define _BCLRPAT_A	0x60020
+#define _VSYNCSHIFT_A	0x60028
 
 /* Pipe B timing regs */
 #define _HTOTAL_B	0x61000
@@ -1326,6 +1395,8 @@
 #define _VSYNC_B		0x61014
 #define _PIPEBSRC	0x6101c
 #define _BCLRPAT_B	0x61020
+#define _VSYNCSHIFT_B	0x61028
+
 
 #define HTOTAL(pipe) _PIPE(pipe, _HTOTAL_A, _HTOTAL_B)
 #define HBLANK(pipe) _PIPE(pipe, _HBLANK_A, _HBLANK_B)
@@ -1334,6 +1405,7 @@
 #define VBLANK(pipe) _PIPE(pipe, _VBLANK_A, _VBLANK_B)
 #define VSYNC(pipe) _PIPE(pipe, _VSYNC_A, _VSYNC_B)
 #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
+#define VSYNCSHIFT(pipe) _PIPE(pipe, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
 
 /* VGA port control */
 #define ADPA			0x61100
@@ -2313,16 +2385,28 @@
 #define   PIPECONF_DISABLE	0
 #define   PIPECONF_DOUBLE_WIDE	(1<<30)
 #define   I965_PIPECONF_ACTIVE	(1<<30)
+#define   PIPECONF_FRAME_START_DELAY_MASK (3<<27)
 #define   PIPECONF_SINGLE_WIDE	0
 #define   PIPECONF_PIPE_UNLOCKED 0
 #define   PIPECONF_PIPE_LOCKED	(1<<25)
 #define   PIPECONF_PALETTE	0
 #define   PIPECONF_GAMMA		(1<<24)
 #define   PIPECONF_FORCE_BORDER	(1<<25)
-#define   PIPECONF_PROGRESSIVE	(0 << 21)
-#define   PIPECONF_INTERLACE_W_FIELD_INDICATION	(6 << 21)
-#define   PIPECONF_INTERLACE_FIELD_0_ONLY		(7 << 21)
 #define   PIPECONF_INTERLACE_MASK	(7 << 21)
+/* Note that pre-gen3 does not support interlaced display directly. Panel
+ * fitting must be disabled on pre-ilk for interlaced. */
+#define   PIPECONF_PROGRESSIVE			(0 << 21)
+#define   PIPECONF_INTERLACE_W_SYNC_SHIFT_PANEL	(4 << 21) /* gen4 only */
+#define   PIPECONF_INTERLACE_W_SYNC_SHIFT	(5 << 21) /* gen4 only */
+#define   PIPECONF_INTERLACE_W_FIELD_INDICATION	(6 << 21)
+#define   PIPECONF_INTERLACE_FIELD_0_ONLY	(7 << 21) /* gen3 only */
+/* Ironlake and later have a complete new set of values for interlaced. PFIT
+ * means panel fitter required, PF means progressive fetch, DBL means power
+ * saving pixel doubling. */
+#define   PIPECONF_PFIT_PF_INTERLACED_ILK	(1 << 21)
+#define   PIPECONF_INTERLACED_ILK		(3 << 21)
+#define   PIPECONF_INTERLACED_DBL_ILK		(4 << 21) /* ilk/snb only */
+#define   PIPECONF_PFIT_PF_INTERLACED_DBL_ILK	(5 << 21) /* ilk/snb only */
 #define   PIPECONF_CXSR_DOWNCLOCK	(1<<16)
 #define   PIPECONF_BPP_MASK	(0x000000e0)
 #define   PIPECONF_BPP_8	(0<<5)
@@ -3219,6 +3303,7 @@
 #define _TRANS_VSYNC_A           0xe0014
 #define  TRANS_VSYNC_END_SHIFT  16
 #define  TRANS_VSYNC_START_SHIFT 0
+#define _TRANS_VSYNCSHIFT_A	0xe0028
 
 #define _TRANSA_DATA_M1          0xe0030
 #define _TRANSA_DATA_N1          0xe0034
@@ -3249,6 +3334,7 @@
 #define _TRANS_VTOTAL_B          0xe100c
 #define _TRANS_VBLANK_B          0xe1010
 #define _TRANS_VSYNC_B           0xe1014
+#define _TRANS_VSYNCSHIFT_B	 0xe1028
 
 #define TRANS_HTOTAL(pipe) _PIPE(pipe, _TRANS_HTOTAL_A, _TRANS_HTOTAL_B)
 #define TRANS_HBLANK(pipe) _PIPE(pipe, _TRANS_HBLANK_A, _TRANS_HBLANK_B)
@@ -3256,6 +3342,8 @@
 #define TRANS_VTOTAL(pipe) _PIPE(pipe, _TRANS_VTOTAL_A, _TRANS_VTOTAL_B)
 #define TRANS_VBLANK(pipe) _PIPE(pipe, _TRANS_VBLANK_A, _TRANS_VBLANK_B)
 #define TRANS_VSYNC(pipe) _PIPE(pipe, _TRANS_VSYNC_A, _TRANS_VSYNC_B)
+#define TRANS_VSYNCSHIFT(pipe) _PIPE(pipe, _TRANS_VSYNCSHIFT_A, \
+				     _TRANS_VSYNCSHIFT_B)
 
 #define _TRANSB_DATA_M1          0xe1030
 #define _TRANSB_DATA_N1          0xe1034
@@ -3289,7 +3377,10 @@
 #define  TRANS_FSYNC_DELAY_HB4  (3<<27)
 #define  TRANS_DP_AUDIO_ONLY    (1<<26)
 #define  TRANS_DP_VIDEO_AUDIO   (0<<26)
+#define  TRANS_INTERLACE_MASK   (7<<21)
 #define  TRANS_PROGRESSIVE      (0<<21)
+#define  TRANS_INTERLACED       (3<<21)
+#define  TRANS_LEGACY_INTERLACED_ILK (2<<21)
 #define  TRANS_8BPC             (0<<5)
 #define  TRANS_10BPC            (1<<5)
 #define  TRANS_6BPC             (2<<5)
@@ -3628,6 +3719,12 @@
 #define  ECOBUS					0xa180
 #define    FORCEWAKE_MT_ENABLE			(1<<5)
 
+#define  GTFIFODBG				0x120000
+#define    GT_FIFO_CPU_ERROR_MASK		7
+#define    GT_FIFO_OVFERR			(1<<2)
+#define    GT_FIFO_IAWRERR			(1<<1)
+#define    GT_FIFO_IARDERR			(1<<0)
+
 #define  GT_FIFO_FREE_ENTRIES			0x120008
 #define    GT_FIFO_NUM_RESERVED_ENTRIES		20
 
@@ -3757,4 +3854,16 @@
  */
 #define GEN7_SO_WRITE_OFFSET(n)		(0x5280 + (n) * 4)
 
+#define IBX_AUD_CONFIG_A			0xe2000
+#define CPT_AUD_CONFIG_A			0xe5000
+#define   AUD_CONFIG_N_VALUE_INDEX		(1 << 29)
+#define   AUD_CONFIG_N_PROG_ENABLE		(1 << 28)
+#define   AUD_CONFIG_UPPER_N_SHIFT		20
+#define   AUD_CONFIG_UPPER_N_VALUE		(0xff << 20)
+#define   AUD_CONFIG_LOWER_N_SHIFT		4
+#define   AUD_CONFIG_LOWER_N_VALUE		(0xfff << 4)
+#define   AUD_CONFIG_PIXEL_CLOCK_HDMI_SHIFT	16
+#define   AUD_CONFIG_PIXEL_CLOCK_HDMI		(0xf << 16)
+#define   AUD_CONFIG_DISABLE_NCTS		(1 << 3)
+
 #endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c
index cb91210..bae3edf 100644
--- a/drivers/gpu/drm/i915/intel_acpi.c
+++ b/drivers/gpu/drm/i915/intel_acpi.c
@@ -208,7 +208,7 @@
 
 	ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS, 0);
 	if (ret < 0) {
-		DRM_ERROR("failed to get supported _DSM functions\n");
+		DRM_DEBUG_KMS("failed to get supported _DSM functions\n");
 		return false;
 	}
 
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 63880e2..b48fc2a 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -24,6 +24,7 @@
  *    Eric Anholt <eric@anholt.net>
  *
  */
+#include <linux/dmi.h>
 #include <drm/drm_dp_helper.h>
 #include "drmP.h"
 #include "drm.h"
@@ -572,7 +573,7 @@
 		DRM_DEBUG_KMS("no child dev is parsed from VBT\n");
 		return;
 	}
-	dev_priv->child_dev = kzalloc(sizeof(*p_child) * count, GFP_KERNEL);
+	dev_priv->child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL);
 	if (!dev_priv->child_dev) {
 		DRM_DEBUG_KMS("No memory space for child device\n");
 		return;
@@ -621,6 +622,26 @@
 	dev_priv->edp.bpp = 18;
 }
 
+static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
+{
+	DRM_DEBUG_KMS("Falling back to manually reading VBT from "
+		      "VBIOS ROM for %s\n",
+		      id->ident);
+	return 1;
+}
+
+static const struct dmi_system_id intel_no_opregion_vbt[] = {
+	{
+		.callback = intel_no_opregion_vbt_callback,
+		.ident = "ThinkCentre A57",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "97027RG"),
+		},
+	},
+	{ }
+};
+
 /**
  * intel_parse_bios - find VBT and initialize settings from the BIOS
  * @dev: DRM device
@@ -641,7 +662,7 @@
 	init_vbt_defaults(dev_priv);
 
 	/* XXX Should this validation be moved to intel_opregion.c? */
-	if (dev_priv->opregion.vbt) {
+	if (!dmi_check_system(intel_no_opregion_vbt) && dev_priv->opregion.vbt) {
 		struct vbt_header *vbt = dev_priv->opregion.vbt;
 		if (memcmp(vbt->signature, "$VBT", 4) == 0) {
 			DRM_DEBUG_KMS("Using VBT from OpRegion: %20s\n",
@@ -669,7 +690,7 @@
 		}
 
 		if (!vbt) {
-			DRM_ERROR("VBT signature missing\n");
+			DRM_DEBUG_DRIVER("VBT signature missing\n");
 			pci_unmap_rom(pdev, bios);
 			return -1;
 		}
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index dd729d4..4d3d736 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -594,7 +594,10 @@
 				1 << INTEL_ANALOG_CLONE_BIT |
 				1 << INTEL_SDVO_LVDS_CLONE_BIT);
 	crt->base.crtc_mask = (1 << 0) | (1 << 1);
-	connector->interlace_allowed = 1;
+	if (IS_GEN2(dev))
+		connector->interlace_allowed = 0;
+	else
+		connector->interlace_allowed = 1;
 	connector->doublescan_allowed = 0;
 
 	drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 397087c..91b35fd 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -75,7 +75,7 @@
 	intel_range_t   dot, vco, n, m, m1, m2, p, p1;
 	intel_p2_t	    p2;
 	bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
-			int, int, intel_clock_t *);
+			int, int, intel_clock_t *, intel_clock_t *);
 };
 
 /* FDI */
@@ -83,17 +83,21 @@
 
 static bool
 intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
-		    int target, int refclk, intel_clock_t *best_clock);
+		    int target, int refclk, intel_clock_t *match_clock,
+		    intel_clock_t *best_clock);
 static bool
 intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
-			int target, int refclk, intel_clock_t *best_clock);
+			int target, int refclk, intel_clock_t *match_clock,
+			intel_clock_t *best_clock);
 
 static bool
 intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc,
-		      int target, int refclk, intel_clock_t *best_clock);
+		      int target, int refclk, intel_clock_t *match_clock,
+		      intel_clock_t *best_clock);
 static bool
 intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc,
-			   int target, int refclk, intel_clock_t *best_clock);
+			   int target, int refclk, intel_clock_t *match_clock,
+			   intel_clock_t *best_clock);
 
 static inline u32 /* units of 100MHz */
 intel_fdi_link_freq(struct drm_device *dev)
@@ -515,7 +519,8 @@
 
 static bool
 intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
-		    int target, int refclk, intel_clock_t *best_clock)
+		    int target, int refclk, intel_clock_t *match_clock,
+		    intel_clock_t *best_clock)
 
 {
 	struct drm_device *dev = crtc->dev;
@@ -562,6 +567,9 @@
 					if (!intel_PLL_is_valid(dev, limit,
 								&clock))
 						continue;
+					if (match_clock &&
+					    clock.p != match_clock->p)
+						continue;
 
 					this_err = abs(clock.dot - target);
 					if (this_err < err) {
@@ -578,7 +586,8 @@
 
 static bool
 intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
-			int target, int refclk, intel_clock_t *best_clock)
+			int target, int refclk, intel_clock_t *match_clock,
+			intel_clock_t *best_clock)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -625,6 +634,9 @@
 					if (!intel_PLL_is_valid(dev, limit,
 								&clock))
 						continue;
+					if (match_clock &&
+					    clock.p != match_clock->p)
+						continue;
 
 					this_err = abs(clock.dot - target);
 					if (this_err < err_most) {
@@ -642,7 +654,8 @@
 
 static bool
 intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
-			   int target, int refclk, intel_clock_t *best_clock)
+			   int target, int refclk, intel_clock_t *match_clock,
+			   intel_clock_t *best_clock)
 {
 	struct drm_device *dev = crtc->dev;
 	intel_clock_t clock;
@@ -668,7 +681,8 @@
 /* DisplayPort has only two frequencies, 162MHz and 270MHz */
 static bool
 intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
-		      int target, int refclk, intel_clock_t *best_clock)
+		      int target, int refclk, intel_clock_t *match_clock,
+		      intel_clock_t *best_clock)
 {
 	intel_clock_t clock;
 	if (target < 200000) {
@@ -922,6 +936,10 @@
 	u32 val;
 	bool cur_state;
 
+	/* if we need the pipe A quirk it must be always on */
+	if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE)
+		state = true;
+
 	reg = PIPECONF(pipe);
 	val = I915_READ(reg);
 	cur_state = !!(val & PIPECONF_ENABLE);
@@ -930,19 +948,24 @@
 	     pipe_name(pipe), state_string(state), state_string(cur_state));
 }
 
-static void assert_plane_enabled(struct drm_i915_private *dev_priv,
-				 enum plane plane)
+static void assert_plane(struct drm_i915_private *dev_priv,
+			 enum plane plane, bool state)
 {
 	int reg;
 	u32 val;
+	bool cur_state;
 
 	reg = DSPCNTR(plane);
 	val = I915_READ(reg);
-	WARN(!(val & DISPLAY_PLANE_ENABLE),
-	     "plane %c assertion failure, should be active but is disabled\n",
-	     plane_name(plane));
+	cur_state = !!(val & DISPLAY_PLANE_ENABLE);
+	WARN(cur_state != state,
+	     "plane %c assertion failure (expected %s, current %s)\n",
+	     plane_name(plane), state_string(state), state_string(cur_state));
 }
 
+#define assert_plane_enabled(d, p) assert_plane(d, p, true)
+#define assert_plane_disabled(d, p) assert_plane(d, p, false)
+
 static void assert_planes_disabled(struct drm_i915_private *dev_priv,
 				   enum pipe pipe)
 {
@@ -951,8 +974,14 @@
 	int cur_pipe;
 
 	/* Planes are fixed to pipes on ILK+ */
-	if (HAS_PCH_SPLIT(dev_priv->dev))
+	if (HAS_PCH_SPLIT(dev_priv->dev)) {
+		reg = DSPCNTR(pipe);
+		val = I915_READ(reg);
+		WARN((val & DISPLAY_PLANE_ENABLE),
+		     "plane %c assertion failure, should be disabled but not\n",
+		     plane_name(pipe));
 		return;
+	}
 
 	/* Need to check both planes against the pipe */
 	for (i = 0; i < 2; i++) {
@@ -1071,7 +1100,7 @@
 {
 	u32 val = I915_READ(reg);
 	WARN(hdmi_pipe_enabled(dev_priv, val, pipe),
-	     "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
+	     "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n",
 	     reg, pipe_name(pipe));
 }
 
@@ -1237,7 +1266,8 @@
 				    enum pipe pipe)
 {
 	int reg;
-	u32 val;
+	u32 val, pipeconf_val;
+	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
 
 	/* PCH only available on ILK+ */
 	BUG_ON(dev_priv->info->gen < 5);
@@ -1251,6 +1281,7 @@
 
 	reg = TRANSCONF(pipe);
 	val = I915_READ(reg);
+	pipeconf_val = I915_READ(PIPECONF(pipe));
 
 	if (HAS_PCH_IBX(dev_priv->dev)) {
 		/*
@@ -1258,8 +1289,19 @@
 		 * that in pipeconf reg.
 		 */
 		val &= ~PIPE_BPC_MASK;
-		val |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK;
+		val |= pipeconf_val & PIPE_BPC_MASK;
 	}
+
+	val &= ~TRANS_INTERLACE_MASK;
+	if ((pipeconf_val & PIPECONF_INTERLACE_MASK) == PIPECONF_INTERLACED_ILK)
+		if (HAS_PCH_IBX(dev_priv->dev) &&
+		    intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO))
+			val |= TRANS_LEGACY_INTERLACED_ILK;
+		else
+			val |= TRANS_INTERLACED;
+	else
+		val |= TRANS_PROGRESSIVE;
+
 	I915_WRITE(reg, val | TRANS_ENABLE);
 	if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100))
 		DRM_ERROR("failed to enable transcoder %d\n", pipe);
@@ -2012,6 +2054,8 @@
 		ret = i915_gem_object_get_fence(obj, pipelined);
 		if (ret)
 			goto err_unpin;
+
+		i915_gem_object_pin_fence(obj);
 	}
 
 	dev_priv->mm.interruptible = true;
@@ -2024,6 +2068,12 @@
 	return ret;
 }
 
+void intel_unpin_fb_obj(struct drm_i915_gem_object *obj)
+{
+	i915_gem_object_unpin_fence(obj);
+	i915_gem_object_unpin(obj);
+}
+
 static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 			     int x, int y)
 {
@@ -2255,7 +2305,7 @@
 	ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
 					 LEAVE_ATOMIC_MODE_SET);
 	if (ret) {
-		i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+		intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
 		mutex_unlock(&dev->struct_mutex);
 		DRM_ERROR("failed to update base address\n");
 		return ret;
@@ -2263,7 +2313,7 @@
 
 	if (old_fb) {
 		intel_wait_for_vblank(dev, intel_crtc->pipe);
-		i915_gem_object_unpin(to_intel_framebuffer(old_fb)->obj);
+		intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj);
 	}
 
 	mutex_unlock(&dev->struct_mutex);
@@ -2936,6 +2986,7 @@
 	I915_WRITE(TRANS_VTOTAL(pipe), I915_READ(VTOTAL(pipe)));
 	I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe)));
 	I915_WRITE(TRANS_VSYNC(pipe),  I915_READ(VSYNC(pipe)));
+	I915_WRITE(TRANS_VSYNCSHIFT(pipe),  I915_READ(VSYNCSHIFT(pipe)));
 
 	intel_fdi_normal_train(crtc);
 
@@ -3321,10 +3372,12 @@
 	struct drm_device *dev = crtc->dev;
 
 	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+	assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane);
+	assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe);
 
 	if (crtc->fb) {
 		mutex_lock(&dev->struct_mutex);
-		i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+		intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
 		mutex_unlock(&dev->struct_mutex);
 	}
 }
@@ -3398,11 +3451,8 @@
 			return false;
 	}
 
-	/* XXX some encoders set the crtcinfo, others don't.
-	 * Obviously we need some form of conflict resolution here...
-	 */
-	if (adjusted_mode->crtc_htotal == 0)
-		drm_mode_set_crtcinfo(adjusted_mode, 0);
+	/* All interlaced capable intel hw wants timings in frames. */
+	drm_mode_set_crtcinfo(adjusted_mode, 0);
 
 	return true;
 }
@@ -4521,6 +4571,7 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int latency = SNB_READ_WM0_LATENCY() * 100;	/* In unit 0.1us */
+	u32 val;
 	int fbc_wm, plane_wm, cursor_wm;
 	unsigned int enabled;
 
@@ -4529,8 +4580,10 @@
 			    &sandybridge_display_wm_info, latency,
 			    &sandybridge_cursor_wm_info, latency,
 			    &plane_wm, &cursor_wm)) {
-		I915_WRITE(WM0_PIPEA_ILK,
-			   (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+		val = I915_READ(WM0_PIPEA_ILK);
+		val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+		I915_WRITE(WM0_PIPEA_ILK, val |
+			   ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
 		DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
 			      " plane %d, " "cursor: %d\n",
 			      plane_wm, cursor_wm);
@@ -4541,8 +4594,10 @@
 			    &sandybridge_display_wm_info, latency,
 			    &sandybridge_cursor_wm_info, latency,
 			    &plane_wm, &cursor_wm)) {
-		I915_WRITE(WM0_PIPEB_ILK,
-			   (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+		val = I915_READ(WM0_PIPEB_ILK);
+		val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+		I915_WRITE(WM0_PIPEB_ILK, val |
+			   ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
 		DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
 			      " plane %d, cursor: %d\n",
 			      plane_wm, cursor_wm);
@@ -4555,8 +4610,10 @@
 			    &sandybridge_display_wm_info, latency,
 			    &sandybridge_cursor_wm_info, latency,
 			    &plane_wm, &cursor_wm)) {
-		I915_WRITE(WM0_PIPEC_IVB,
-			   (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+		val = I915_READ(WM0_PIPEC_IVB);
+		val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+		I915_WRITE(WM0_PIPEC_IVB, val |
+			   ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
 		DRM_DEBUG_KMS("FIFO watermarks For pipe C -"
 			      " plane %d, cursor: %d\n",
 			      plane_wm, cursor_wm);
@@ -4709,6 +4766,7 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int latency = SNB_READ_WM0_LATENCY() * 100;	/* In unit 0.1us */
+	u32 val;
 	int sprite_wm, reg;
 	int ret;
 
@@ -4735,7 +4793,9 @@
 		return;
 	}
 
-	I915_WRITE(reg, I915_READ(reg) | (sprite_wm << WM0_PIPE_SPRITE_SHIFT));
+	val = I915_READ(reg);
+	val &= ~WM0_PIPE_SPRITE_MASK;
+	I915_WRITE(reg, val | (sprite_wm << WM0_PIPE_SPRITE_SHIFT));
 	DRM_DEBUG_KMS("sprite watermarks For pipe %d - %d\n", pipe, sprite_wm);
 
 
@@ -4977,6 +5037,82 @@
 	return display_bpc != bpc;
 }
 
+static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int refclk;
+
+	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+	    intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
+		refclk = dev_priv->lvds_ssc_freq * 1000;
+		DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
+			      refclk / 1000);
+	} else if (!IS_GEN2(dev)) {
+		refclk = 96000;
+	} else {
+		refclk = 48000;
+	}
+
+	return refclk;
+}
+
+static void i9xx_adjust_sdvo_tv_clock(struct drm_display_mode *adjusted_mode,
+				      intel_clock_t *clock)
+{
+	/* SDVO TV has fixed PLL values depend on its clock range,
+	   this mirrors vbios setting. */
+	if (adjusted_mode->clock >= 100000
+	    && adjusted_mode->clock < 140500) {
+		clock->p1 = 2;
+		clock->p2 = 10;
+		clock->n = 3;
+		clock->m1 = 16;
+		clock->m2 = 8;
+	} else if (adjusted_mode->clock >= 140500
+		   && adjusted_mode->clock <= 200000) {
+		clock->p1 = 1;
+		clock->p2 = 10;
+		clock->n = 6;
+		clock->m1 = 12;
+		clock->m2 = 8;
+	}
+}
+
+static void i9xx_update_pll_dividers(struct drm_crtc *crtc,
+				     intel_clock_t *clock,
+				     intel_clock_t *reduced_clock)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int pipe = intel_crtc->pipe;
+	u32 fp, fp2 = 0;
+
+	if (IS_PINEVIEW(dev)) {
+		fp = (1 << clock->n) << 16 | clock->m1 << 8 | clock->m2;
+		if (reduced_clock)
+			fp2 = (1 << reduced_clock->n) << 16 |
+				reduced_clock->m1 << 8 | reduced_clock->m2;
+	} else {
+		fp = clock->n << 16 | clock->m1 << 8 | clock->m2;
+		if (reduced_clock)
+			fp2 = reduced_clock->n << 16 | reduced_clock->m1 << 8 |
+				reduced_clock->m2;
+	}
+
+	I915_WRITE(FP0(pipe), fp);
+
+	intel_crtc->lowfreq_avail = false;
+	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+	    reduced_clock && i915_powersave) {
+		I915_WRITE(FP1(pipe), fp2);
+		intel_crtc->lowfreq_avail = true;
+	} else {
+		I915_WRITE(FP1(pipe), fp);
+	}
+}
+
 static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
 			      struct drm_display_mode *mode,
 			      struct drm_display_mode *adjusted_mode,
@@ -4990,7 +5126,7 @@
 	int plane = intel_crtc->plane;
 	int refclk, num_connectors = 0;
 	intel_clock_t clock, reduced_clock;
-	u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
+	u32 dpll, dspcntr, pipeconf, vsyncshift;
 	bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
 	bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
 	struct drm_mode_config *mode_config = &dev->mode_config;
@@ -5031,15 +5167,7 @@
 		num_connectors++;
 	}
 
-	if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
-		refclk = dev_priv->lvds_ssc_freq * 1000;
-		DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
-			      refclk / 1000);
-	} else if (!IS_GEN2(dev)) {
-		refclk = 96000;
-	} else {
-		refclk = 48000;
-	}
+	refclk = i9xx_get_refclk(crtc, num_connectors);
 
 	/*
 	 * Returns a set of divisors for the desired target clock with the given
@@ -5047,7 +5175,8 @@
 	 * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
 	 */
 	limit = intel_limit(crtc, refclk);
-	ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
+	ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
+			     &clock);
 	if (!ok) {
 		DRM_ERROR("Couldn't find PLL settings for mode!\n");
 		return -EINVAL;
@@ -5057,53 +5186,24 @@
 	intel_crtc_update_cursor(crtc, true);
 
 	if (is_lvds && dev_priv->lvds_downclock_avail) {
+		/*
+		 * Ensure we match the reduced clock's P to the target clock.
+		 * If the clocks don't match, we can't switch the display clock
+		 * by using the FP0/FP1. In such case we will disable the LVDS
+		 * downclock feature.
+		*/
 		has_reduced_clock = limit->find_pll(limit, crtc,
 						    dev_priv->lvds_downclock,
 						    refclk,
+						    &clock,
 						    &reduced_clock);
-		if (has_reduced_clock && (clock.p != reduced_clock.p)) {
-			/*
-			 * If the different P is found, it means that we can't
-			 * switch the display clock by using the FP0/FP1.
-			 * In such case we will disable the LVDS downclock
-			 * feature.
-			 */
-			DRM_DEBUG_KMS("Different P is found for "
-				      "LVDS clock/downclock\n");
-			has_reduced_clock = 0;
-		}
-	}
-	/* SDVO TV has fixed PLL values depend on its clock range,
-	   this mirrors vbios setting. */
-	if (is_sdvo && is_tv) {
-		if (adjusted_mode->clock >= 100000
-		    && adjusted_mode->clock < 140500) {
-			clock.p1 = 2;
-			clock.p2 = 10;
-			clock.n = 3;
-			clock.m1 = 16;
-			clock.m2 = 8;
-		} else if (adjusted_mode->clock >= 140500
-			   && adjusted_mode->clock <= 200000) {
-			clock.p1 = 1;
-			clock.p2 = 10;
-			clock.n = 6;
-			clock.m1 = 12;
-			clock.m2 = 8;
-		}
 	}
 
-	if (IS_PINEVIEW(dev)) {
-		fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
-		if (has_reduced_clock)
-			fp2 = (1 << reduced_clock.n) << 16 |
-				reduced_clock.m1 << 8 | reduced_clock.m2;
-	} else {
-		fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
-		if (has_reduced_clock)
-			fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
-				reduced_clock.m2;
-	}
+	if (is_sdvo && is_tv)
+		i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock);
+
+	i9xx_update_pll_dividers(crtc, &clock, has_reduced_clock ?
+				 &reduced_clock : NULL);
 
 	dpll = DPLL_VGA_MODE_DIS;
 
@@ -5177,8 +5277,6 @@
 	/* Set up the display plane register */
 	dspcntr = DISPPLANE_GAMMA_ENABLE;
 
-	/* Ironlake's plane is forced to pipe, bit 24 is to
-	   enable color space conversion */
 	if (pipe == 0)
 		dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
 	else
@@ -5213,7 +5311,6 @@
 	DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
 	drm_mode_debug_printmodeline(mode);
 
-	I915_WRITE(FP0(pipe), fp);
 	I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
 
 	POSTING_READ(DPLL(pipe));
@@ -5300,34 +5397,32 @@
 		I915_WRITE(DPLL(pipe), dpll);
 	}
 
-	intel_crtc->lowfreq_avail = false;
-	if (is_lvds && has_reduced_clock && i915_powersave) {
-		I915_WRITE(FP1(pipe), fp2);
-		intel_crtc->lowfreq_avail = true;
-		if (HAS_PIPE_CXSR(dev)) {
+	if (HAS_PIPE_CXSR(dev)) {
+		if (intel_crtc->lowfreq_avail) {
 			DRM_DEBUG_KMS("enabling CxSR downclocking\n");
 			pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
-		}
-	} else {
-		I915_WRITE(FP1(pipe), fp);
-		if (HAS_PIPE_CXSR(dev)) {
+		} else {
 			DRM_DEBUG_KMS("disabling CxSR downclocking\n");
 			pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
 		}
 	}
 
 	pipeconf &= ~PIPECONF_INTERLACE_MASK;
-	if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
+	if (!IS_GEN2(dev) &&
+	    adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
 		pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
 		/* the chip adds 2 halflines automatically */
-		adjusted_mode->crtc_vdisplay -= 1;
 		adjusted_mode->crtc_vtotal -= 1;
-		adjusted_mode->crtc_vblank_start -= 1;
 		adjusted_mode->crtc_vblank_end -= 1;
-		adjusted_mode->crtc_vsync_end -= 1;
-		adjusted_mode->crtc_vsync_start -= 1;
-	} else
+		vsyncshift = adjusted_mode->crtc_hsync_start
+			     - adjusted_mode->crtc_htotal/2;
+	} else {
 		pipeconf |= PIPECONF_PROGRESSIVE;
+		vsyncshift = 0;
+	}
+
+	if (!IS_GEN3(dev))
+		I915_WRITE(VSYNCSHIFT(pipe), vsyncshift);
 
 	I915_WRITE(HTOTAL(pipe),
 		   (adjusted_mode->crtc_hdisplay - 1) |
@@ -5444,7 +5539,8 @@
 		if (intel_panel_use_ssc(dev_priv) && can_ssc) {
 			DRM_DEBUG_KMS("Using SSC on panel\n");
 			temp |= DREF_SSC1_ENABLE;
-		}
+		} else
+			temp &= ~DREF_SSC1_ENABLE;
 
 		/* Get SSC going before enabling the outputs */
 		I915_WRITE(PCH_DREF_CONTROL, temp);
@@ -5593,7 +5689,8 @@
 	 * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
 	 */
 	limit = intel_limit(crtc, refclk);
-	ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
+	ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
+			     &clock);
 	if (!ok) {
 		DRM_ERROR("Couldn't find PLL settings for mode!\n");
 		return -EINVAL;
@@ -5603,21 +5700,17 @@
 	intel_crtc_update_cursor(crtc, true);
 
 	if (is_lvds && dev_priv->lvds_downclock_avail) {
+		/*
+		 * Ensure we match the reduced clock's P to the target clock.
+		 * If the clocks don't match, we can't switch the display clock
+		 * by using the FP0/FP1. In such case we will disable the LVDS
+		 * downclock feature.
+		*/
 		has_reduced_clock = limit->find_pll(limit, crtc,
 						    dev_priv->lvds_downclock,
 						    refclk,
+						    &clock,
 						    &reduced_clock);
-		if (has_reduced_clock && (clock.p != reduced_clock.p)) {
-			/*
-			 * If the different P is found, it means that we can't
-			 * switch the display clock by using the FP0/FP1.
-			 * In such case we will disable the LVDS downclock
-			 * feature.
-			 */
-			DRM_DEBUG_KMS("Different P is found for "
-				      "LVDS clock/downclock\n");
-			has_reduced_clock = 0;
-		}
 	}
 	/* SDVO TV has fixed PLL values depend on its clock range,
 	   this mirrors vbios setting. */
@@ -5914,16 +6007,17 @@
 
 	pipeconf &= ~PIPECONF_INTERLACE_MASK;
 	if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
-		pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
+		pipeconf |= PIPECONF_INTERLACED_ILK;
 		/* the chip adds 2 halflines automatically */
-		adjusted_mode->crtc_vdisplay -= 1;
 		adjusted_mode->crtc_vtotal -= 1;
-		adjusted_mode->crtc_vblank_start -= 1;
 		adjusted_mode->crtc_vblank_end -= 1;
-		adjusted_mode->crtc_vsync_end -= 1;
-		adjusted_mode->crtc_vsync_start -= 1;
-	} else
+		I915_WRITE(VSYNCSHIFT(pipe),
+			   adjusted_mode->crtc_hsync_start
+			   - adjusted_mode->crtc_htotal/2);
+	} else {
 		pipeconf |= PIPECONF_PROGRESSIVE;
+		I915_WRITE(VSYNCSHIFT(pipe), 0);
+	}
 
 	I915_WRITE(HTOTAL(pipe),
 		   (adjusted_mode->crtc_hdisplay - 1) |
@@ -5966,12 +6060,6 @@
 
 	intel_wait_for_vblank(dev, pipe);
 
-	if (IS_GEN5(dev)) {
-		/* enable address swizzle for tiling buffer */
-		temp = I915_READ(DISP_ARB_CTL);
-		I915_WRITE(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING);
-	}
-
 	I915_WRITE(DSPCNTR(plane), dspcntr);
 	POSTING_READ(DSPCNTR(plane));
 
@@ -6086,15 +6174,18 @@
 	uint32_t i;
 	int len;
 	int hdmiw_hdmiedid;
+	int aud_config;
 	int aud_cntl_st;
 	int aud_cntrl_st2;
 
 	if (HAS_PCH_IBX(connector->dev)) {
 		hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID_A;
+		aud_config = IBX_AUD_CONFIG_A;
 		aud_cntl_st = IBX_AUD_CNTL_ST_A;
 		aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
 	} else {
 		hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID_A;
+		aud_config = CPT_AUD_CONFIG_A;
 		aud_cntl_st = CPT_AUD_CNTL_ST_A;
 		aud_cntrl_st2 = CPT_AUD_CNTRL_ST2;
 	}
@@ -6102,6 +6193,7 @@
 	i = to_intel_crtc(crtc)->pipe;
 	hdmiw_hdmiedid += i * 0x100;
 	aud_cntl_st += i * 0x100;
+	aud_config += i * 0x100;
 
 	DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(i));
 
@@ -6121,7 +6213,9 @@
 	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
 		DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n");
 		eld[5] |= (1 << 2);	/* Conn_Type, 0x1 = DisplayPort */
-	}
+		I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */
+	} else
+		I915_WRITE(aud_config, 0);
 
 	if (intel_eld_uptodate(connector,
 			       aud_cntrl_st2, eldv,
@@ -6927,9 +7021,7 @@
 	if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) {
 		DRM_DEBUG_DRIVER("upclocking LVDS\n");
 
-		/* Unlock panel regs */
-		I915_WRITE(PP_CONTROL,
-			   I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
+		assert_panel_unlocked(dev_priv, pipe);
 
 		dpll &= ~DISPLAY_RATE_SELECT_FPA1;
 		I915_WRITE(dpll_reg, dpll);
@@ -6938,9 +7030,6 @@
 		dpll = I915_READ(dpll_reg);
 		if (dpll & DISPLAY_RATE_SELECT_FPA1)
 			DRM_DEBUG_DRIVER("failed to upclock LVDS!\n");
-
-		/* ...and lock them again */
-		I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3);
 	}
 
 	/* Schedule downclock */
@@ -6970,9 +7059,7 @@
 	if (!HAS_PIPE_CXSR(dev) && intel_crtc->lowfreq_avail) {
 		DRM_DEBUG_DRIVER("downclocking LVDS\n");
 
-		/* Unlock panel regs */
-		I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) |
-			   PANEL_UNLOCK_REGS);
+		assert_panel_unlocked(dev_priv, pipe);
 
 		dpll |= DISPLAY_RATE_SELECT_FPA1;
 		I915_WRITE(dpll_reg, dpll);
@@ -6980,9 +7067,6 @@
 		dpll = I915_READ(dpll_reg);
 		if (!(dpll & DISPLAY_RATE_SELECT_FPA1))
 			DRM_DEBUG_DRIVER("failed to downclock LVDS!\n");
-
-		/* ...and lock them again */
-		I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3);
 	}
 
 }
@@ -7097,7 +7181,7 @@
 		container_of(__work, struct intel_unpin_work, work);
 
 	mutex_lock(&work->dev->struct_mutex);
-	i915_gem_object_unpin(work->old_fb_obj);
+	intel_unpin_fb_obj(work->old_fb_obj);
 	drm_gem_object_unreference(&work->pending_flip_obj->base);
 	drm_gem_object_unreference(&work->old_fb_obj->base);
 
@@ -7247,7 +7331,7 @@
 		 MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
 	OUT_RING(fb->pitches[0]);
 	OUT_RING(obj->gtt_offset + offset);
-	OUT_RING(MI_NOOP);
+	OUT_RING(0); /* aux display base address, unused */
 	ADVANCE_LP_RING();
 out:
 	return ret;
@@ -7497,6 +7581,12 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 reg, val;
 
+	/* Clear any frame start delays used for debugging left by the BIOS */
+	for_each_pipe(pipe) {
+		reg = PIPECONF(pipe);
+		I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
+	}
+
 	if (HAS_PCH_SPLIT(dev))
 		return;
 
@@ -7681,10 +7771,9 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *encoder;
 	bool dpd_is_edp = false;
-	bool has_lvds = false;
+	bool has_lvds;
 
-	if (IS_MOBILE(dev) && !IS_I830(dev))
-		has_lvds = intel_lvds_init(dev);
+	has_lvds = intel_lvds_init(dev);
 	if (!has_lvds && !HAS_PCH_SPLIT(dev)) {
 		/* disable the panel fitter on everything but LVDS */
 		I915_WRITE(PFIT_CONTROL, 0);
@@ -7840,7 +7929,8 @@
 	case DRM_FORMAT_VYUY:
 		break;
 	default:
-		DRM_ERROR("unsupported pixel format\n");
+		DRM_DEBUG_KMS("unsupported pixel format %u\n",
+				mode_cmd->pixel_format);
 		return -EINVAL;
 	}
 
@@ -8132,7 +8222,7 @@
 	dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
 }
 
-static bool intel_enable_rc6(struct drm_device *dev)
+static int intel_enable_rc6(struct drm_device *dev)
 {
 	/*
 	 * Respect the kernel parameter if it is set
@@ -8150,11 +8240,11 @@
 	 * Disable rc6 on Sandybridge
 	 */
 	if (INTEL_INFO(dev)->gen == 6) {
-		DRM_DEBUG_DRIVER("Sandybridge: RC6 disabled\n");
-		return 0;
+		DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n");
+		return INTEL_RC6_ENABLE;
 	}
-	DRM_DEBUG_DRIVER("RC6 enabled\n");
-	return 1;
+	DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n");
+	return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE);
 }
 
 void gen6_enable_rps(struct drm_i915_private *dev_priv)
@@ -8162,7 +8252,9 @@
 	u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
 	u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
 	u32 pcu_mbox, rc6_mask = 0;
+	u32 gtfifodbg;
 	int cur_freq, min_freq, max_freq;
+	int rc6_mode;
 	int i;
 
 	/* Here begins a magic sequence of register writes to enable
@@ -8173,6 +8265,13 @@
 	 */
 	I915_WRITE(GEN6_RC_STATE, 0);
 	mutex_lock(&dev_priv->dev->struct_mutex);
+
+	/* Clear the DBG now so we don't confuse earlier errors */
+	if ((gtfifodbg = I915_READ(GTFIFODBG))) {
+		DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg);
+		I915_WRITE(GTFIFODBG, gtfifodbg);
+	}
+
 	gen6_gt_force_wake_get(dev_priv);
 
 	/* disable the counters and set deterministic thresholds */
@@ -8193,9 +8292,20 @@
 	I915_WRITE(GEN6_RC6p_THRESHOLD, 100000);
 	I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */
 
-	if (intel_enable_rc6(dev_priv->dev))
-		rc6_mask = GEN6_RC_CTL_RC6_ENABLE |
-			((IS_GEN7(dev_priv->dev)) ? GEN6_RC_CTL_RC6p_ENABLE : 0);
+	rc6_mode = intel_enable_rc6(dev_priv->dev);
+	if (rc6_mode & INTEL_RC6_ENABLE)
+		rc6_mask |= GEN6_RC_CTL_RC6_ENABLE;
+
+	if (rc6_mode & INTEL_RC6p_ENABLE)
+		rc6_mask |= GEN6_RC_CTL_RC6p_ENABLE;
+
+	if (rc6_mode & INTEL_RC6pp_ENABLE)
+		rc6_mask |= GEN6_RC_CTL_RC6pp_ENABLE;
+
+	DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n",
+			(rc6_mode & INTEL_RC6_ENABLE) ? "on" : "off",
+			(rc6_mode & INTEL_RC6p_ENABLE) ? "on" : "off",
+			(rc6_mode & INTEL_RC6pp_ENABLE) ? "on" : "off");
 
 	I915_WRITE(GEN6_RC_CONTROL,
 		   rc6_mask |
@@ -8959,8 +9069,6 @@
 };
 
 struct intel_quirk intel_quirks[] = {
-	/* HP Compaq 2730p needs pipe A force quirk (LP: #291555) */
-	{ 0x2a42, 0x103c, 0x30eb, quirk_pipea_force },
 	/* HP Mini needs pipe A force quirk (LP: #322104) */
 	{ 0x27ae, 0x103c, 0x361a, quirk_pipea_force },
 
@@ -9037,6 +9145,9 @@
 	dev->mode_config.min_width = 0;
 	dev->mode_config.min_height = 0;
 
+	dev->mode_config.preferred_depth = 24;
+	dev->mode_config.prefer_shadow = 1;
+
 	dev->mode_config.funcs = (void *)&intel_mode_funcs;
 
 	intel_init_quirks(dev);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 94f860c..110552f 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -49,7 +49,7 @@
 	uint32_t DP;
 	uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE];
 	bool has_audio;
-	int force_audio;
+	enum hdmi_force_audio force_audio;
 	uint32_t color_range;
 	int dpms_mode;
 	uint8_t link_bw;
@@ -352,7 +352,7 @@
 	int recv_bytes;
 	uint32_t status;
 	uint32_t aux_clock_divider;
-	int try, precharge;
+	int try, precharge = 5;
 
 	intel_dp_check_edp(intel_dp);
 	/* The clock divider is based off the hrawclk,
@@ -368,15 +368,10 @@
 		else
 			aux_clock_divider = 225; /* eDP input clock at 450Mhz */
 	} else if (HAS_PCH_SPLIT(dev))
-		aux_clock_divider = 62; /* IRL input clock fixed at 125Mhz */
+		aux_clock_divider = 63; /* IRL input clock fixed at 125Mhz */
 	else
 		aux_clock_divider = intel_hrawclk(dev) / 2;
 
-	if (IS_GEN6(dev))
-		precharge = 3;
-	else
-		precharge = 5;
-
 	/* Try to wait for any previous AUX channel activity */
 	for (try = 0; try < 3; try++) {
 		status = I915_READ(ch_ctl);
@@ -421,6 +416,10 @@
 			   DP_AUX_CH_CTL_DONE |
 			   DP_AUX_CH_CTL_TIME_OUT_ERROR |
 			   DP_AUX_CH_CTL_RECEIVE_ERROR);
+
+		if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR |
+			      DP_AUX_CH_CTL_RECEIVE_ERROR))
+			continue;
 		if (status & DP_AUX_CH_CTL_DONE)
 			break;
 	}
@@ -2117,8 +2116,8 @@
 	if (status != connector_status_connected)
 		return status;
 
-	if (intel_dp->force_audio) {
-		intel_dp->has_audio = intel_dp->force_audio > 0;
+	if (intel_dp->force_audio != HDMI_AUDIO_AUTO) {
+		intel_dp->has_audio = (intel_dp->force_audio == HDMI_AUDIO_ON);
 	} else {
 		edid = intel_dp_get_edid(connector, &intel_dp->adapter);
 		if (edid) {
@@ -2218,10 +2217,10 @@
 
 		intel_dp->force_audio = i;
 
-		if (i == 0)
+		if (i == HDMI_AUDIO_AUTO)
 			has_audio = intel_dp_detect_audio(connector);
 		else
-			has_audio = i > 0;
+			has_audio = (i == HDMI_AUDIO_ON);
 
 		if (has_audio == intel_dp->has_audio)
 			return 0;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 1348705..5a14149 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -374,6 +374,7 @@
 extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
 				      struct drm_i915_gem_object *obj,
 				      struct intel_ring_buffer *pipelined);
+extern void intel_unpin_fb_obj(struct drm_i915_gem_object *obj);
 
 extern int intel_framebuffer_init(struct drm_device *dev,
 				  struct intel_framebuffer *ifb,
@@ -381,7 +382,7 @@
 				  struct drm_i915_gem_object *obj);
 extern int intel_fbdev_init(struct drm_device *dev);
 extern void intel_fbdev_fini(struct drm_device *dev);
-
+extern void intel_fbdev_set_suspend(struct drm_device *dev, int state);
 extern void intel_prepare_page_flip(struct drm_device *dev, int plane);
 extern void intel_finish_page_flip(struct drm_device *dev, int pipe);
 extern void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index 6eda1b5..020a7d7 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -157,7 +157,6 @@
 		C(vsync_end);
 		C(vtotal);
 		C(clock);
-		drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
 #undef C
 	}
 
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 571375a..19ecd78 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -152,11 +152,7 @@
 	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
 	drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
 
-	info->pixmap.size = 64*1024;
-	info->pixmap.buf_align = 8;
-	info->pixmap.access_align = 32;
-	info->pixmap.flags = FB_PIXMAP_SYSTEM;
-	info->pixmap.scan_align = 1;
+	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
 
 	DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n",
 		      fb->width, fb->height,
@@ -258,6 +254,16 @@
 	kfree(dev_priv->fbdev);
 	dev_priv->fbdev = NULL;
 }
+
+void intel_fbdev_set_suspend(struct drm_device *dev, int state)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	if (!dev_priv->fbdev)
+		return;
+
+	fb_set_suspend(dev_priv->fbdev->helper.fbdev, state);
+}
+
 MODULE_LICENSE("GPL and additional rights");
 
 void intel_fb_output_poll_changed(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 64541f7..cae3e5f 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -44,7 +44,7 @@
 	uint32_t color_range;
 	bool has_hdmi_sink;
 	bool has_audio;
-	int force_audio;
+	enum hdmi_force_audio force_audio;
 	void (*write_infoframe)(struct drm_encoder *encoder,
 				struct dip_infoframe *frame);
 };
@@ -339,7 +339,9 @@
 	if (edid) {
 		if (edid->input & DRM_EDID_INPUT_DIGITAL) {
 			status = connector_status_connected;
-			intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
+			if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
+				intel_hdmi->has_hdmi_sink =
+						drm_detect_hdmi_monitor(edid);
 			intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
 		}
 		connector->display_info.raw_edid = NULL;
@@ -347,8 +349,9 @@
 	}
 
 	if (status == connector_status_connected) {
-		if (intel_hdmi->force_audio)
-			intel_hdmi->has_audio = intel_hdmi->force_audio > 0;
+		if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO)
+			intel_hdmi->has_audio =
+				(intel_hdmi->force_audio == HDMI_AUDIO_ON);
 	}
 
 	return status;
@@ -402,7 +405,7 @@
 		return ret;
 
 	if (property == dev_priv->force_audio_property) {
-		int i = val;
+		enum hdmi_force_audio i = val;
 		bool has_audio;
 
 		if (i == intel_hdmi->force_audio)
@@ -410,13 +413,13 @@
 
 		intel_hdmi->force_audio = i;
 
-		if (i == 0)
+		if (i == HDMI_AUDIO_AUTO)
 			has_audio = intel_hdmi_detect_audio(connector);
 		else
-			has_audio = i > 0;
+			has_audio = (i == HDMI_AUDIO_ON);
 
-		if (has_audio == intel_hdmi->has_audio)
-			return 0;
+		if (i == HDMI_AUDIO_OFF_DVI)
+			intel_hdmi->has_hdmi_sink = 0;
 
 		intel_hdmi->has_audio = has_audio;
 		goto done;
@@ -514,7 +517,7 @@
 	intel_encoder->type = INTEL_OUTPUT_HDMI;
 
 	connector->polled = DRM_CONNECTOR_POLL_HPD;
-	connector->interlace_allowed = 0;
+	connector->interlace_allowed = 1;
 	connector->doublescan_allowed = 0;
 	intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
 
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index d30cccc..601c86e 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -37,7 +37,7 @@
 
 /* Intel GPIO access functions */
 
-#define I2C_RISEFALL_TIME 20
+#define I2C_RISEFALL_TIME 10
 
 static inline struct intel_gmbus *
 to_intel_gmbus(struct i2c_adapter *i2c)
@@ -45,13 +45,6 @@
 	return container_of(i2c, struct intel_gmbus, adapter);
 }
 
-struct intel_gpio {
-	struct i2c_adapter adapter;
-	struct i2c_algo_bit_data algo;
-	struct drm_i915_private *dev_priv;
-	u32 reg;
-};
-
 void
 intel_i2c_reset(struct drm_device *dev)
 {
@@ -78,15 +71,15 @@
 	I915_WRITE(DSPCLK_GATE_D, val);
 }
 
-static u32 get_reserved(struct intel_gpio *gpio)
+static u32 get_reserved(struct intel_gmbus *bus)
 {
-	struct drm_i915_private *dev_priv = gpio->dev_priv;
+	struct drm_i915_private *dev_priv = bus->dev_priv;
 	struct drm_device *dev = dev_priv->dev;
 	u32 reserved = 0;
 
 	/* On most chips, these bits must be preserved in software. */
 	if (!IS_I830(dev) && !IS_845G(dev))
-		reserved = I915_READ_NOTRACE(gpio->reg) &
+		reserved = I915_READ_NOTRACE(bus->gpio_reg) &
 					     (GPIO_DATA_PULLUP_DISABLE |
 					      GPIO_CLOCK_PULLUP_DISABLE);
 
@@ -95,29 +88,29 @@
 
 static int get_clock(void *data)
 {
-	struct intel_gpio *gpio = data;
-	struct drm_i915_private *dev_priv = gpio->dev_priv;
-	u32 reserved = get_reserved(gpio);
-	I915_WRITE_NOTRACE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK);
-	I915_WRITE_NOTRACE(gpio->reg, reserved);
-	return (I915_READ_NOTRACE(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0;
+	struct intel_gmbus *bus = data;
+	struct drm_i915_private *dev_priv = bus->dev_priv;
+	u32 reserved = get_reserved(bus);
+	I915_WRITE_NOTRACE(bus->gpio_reg, reserved | GPIO_CLOCK_DIR_MASK);
+	I915_WRITE_NOTRACE(bus->gpio_reg, reserved);
+	return (I915_READ_NOTRACE(bus->gpio_reg) & GPIO_CLOCK_VAL_IN) != 0;
 }
 
 static int get_data(void *data)
 {
-	struct intel_gpio *gpio = data;
-	struct drm_i915_private *dev_priv = gpio->dev_priv;
-	u32 reserved = get_reserved(gpio);
-	I915_WRITE_NOTRACE(gpio->reg, reserved | GPIO_DATA_DIR_MASK);
-	I915_WRITE_NOTRACE(gpio->reg, reserved);
-	return (I915_READ_NOTRACE(gpio->reg) & GPIO_DATA_VAL_IN) != 0;
+	struct intel_gmbus *bus = data;
+	struct drm_i915_private *dev_priv = bus->dev_priv;
+	u32 reserved = get_reserved(bus);
+	I915_WRITE_NOTRACE(bus->gpio_reg, reserved | GPIO_DATA_DIR_MASK);
+	I915_WRITE_NOTRACE(bus->gpio_reg, reserved);
+	return (I915_READ_NOTRACE(bus->gpio_reg) & GPIO_DATA_VAL_IN) != 0;
 }
 
 static void set_clock(void *data, int state_high)
 {
-	struct intel_gpio *gpio = data;
-	struct drm_i915_private *dev_priv = gpio->dev_priv;
-	u32 reserved = get_reserved(gpio);
+	struct intel_gmbus *bus = data;
+	struct drm_i915_private *dev_priv = bus->dev_priv;
+	u32 reserved = get_reserved(bus);
 	u32 clock_bits;
 
 	if (state_high)
@@ -126,15 +119,15 @@
 		clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
 			GPIO_CLOCK_VAL_MASK;
 
-	I915_WRITE_NOTRACE(gpio->reg, reserved | clock_bits);
-	POSTING_READ(gpio->reg);
+	I915_WRITE_NOTRACE(bus->gpio_reg, reserved | clock_bits);
+	POSTING_READ(bus->gpio_reg);
 }
 
 static void set_data(void *data, int state_high)
 {
-	struct intel_gpio *gpio = data;
-	struct drm_i915_private *dev_priv = gpio->dev_priv;
-	u32 reserved = get_reserved(gpio);
+	struct intel_gmbus *bus = data;
+	struct drm_i915_private *dev_priv = bus->dev_priv;
+	u32 reserved = get_reserved(bus);
 	u32 data_bits;
 
 	if (state_high)
@@ -143,13 +136,14 @@
 		data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
 			GPIO_DATA_VAL_MASK;
 
-	I915_WRITE_NOTRACE(gpio->reg, reserved | data_bits);
-	POSTING_READ(gpio->reg);
+	I915_WRITE_NOTRACE(bus->gpio_reg, reserved | data_bits);
+	POSTING_READ(bus->gpio_reg);
 }
 
-static struct i2c_adapter *
-intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin)
+static bool
+intel_gpio_setup(struct intel_gmbus *bus, u32 pin)
 {
+	struct drm_i915_private *dev_priv = bus->dev_priv;
 	static const int map_pin_to_reg[] = {
 		0,
 		GPIOB,
@@ -160,65 +154,48 @@
 		0,
 		GPIOF,
 	};
-	struct intel_gpio *gpio;
+	struct i2c_algo_bit_data *algo;
 
 	if (pin >= ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin])
-		return NULL;
+		return false;
 
-	gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL);
-	if (gpio == NULL)
-		return NULL;
+	algo = &bus->bit_algo;
 
-	gpio->reg = map_pin_to_reg[pin];
+	bus->gpio_reg = map_pin_to_reg[pin];
 	if (HAS_PCH_SPLIT(dev_priv->dev))
-		gpio->reg += PCH_GPIOA - GPIOA;
-	gpio->dev_priv = dev_priv;
+		bus->gpio_reg += PCH_GPIOA - GPIOA;
 
-	snprintf(gpio->adapter.name, sizeof(gpio->adapter.name),
-		 "i915 GPIO%c", "?BACDE?F"[pin]);
-	gpio->adapter.owner = THIS_MODULE;
-	gpio->adapter.algo_data	= &gpio->algo;
-	gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev;
-	gpio->algo.setsda = set_data;
-	gpio->algo.setscl = set_clock;
-	gpio->algo.getsda = get_data;
-	gpio->algo.getscl = get_clock;
-	gpio->algo.udelay = I2C_RISEFALL_TIME;
-	gpio->algo.timeout = usecs_to_jiffies(2200);
-	gpio->algo.data = gpio;
+	bus->adapter.algo_data = algo;
+	algo->setsda = set_data;
+	algo->setscl = set_clock;
+	algo->getsda = get_data;
+	algo->getscl = get_clock;
+	algo->udelay = I2C_RISEFALL_TIME;
+	algo->timeout = usecs_to_jiffies(2200);
+	algo->data = bus;
 
-	if (i2c_bit_add_bus(&gpio->adapter))
-		goto out_free;
-
-	return &gpio->adapter;
-
-out_free:
-	kfree(gpio);
-	return NULL;
+	return true;
 }
 
 static int
-intel_i2c_quirk_xfer(struct drm_i915_private *dev_priv,
-		     struct i2c_adapter *adapter,
+intel_i2c_quirk_xfer(struct intel_gmbus *bus,
 		     struct i2c_msg *msgs,
 		     int num)
 {
-	struct intel_gpio *gpio = container_of(adapter,
-					       struct intel_gpio,
-					       adapter);
+	struct drm_i915_private *dev_priv = bus->dev_priv;
 	int ret;
 
 	intel_i2c_reset(dev_priv->dev);
 
 	intel_i2c_quirk_set(dev_priv, true);
-	set_data(gpio, 1);
-	set_clock(gpio, 1);
+	set_data(bus, 1);
+	set_clock(bus, 1);
 	udelay(I2C_RISEFALL_TIME);
 
-	ret = adapter->algo->master_xfer(adapter, msgs, num);
+	ret = i2c_bit_algo.master_xfer(&bus->adapter, msgs, num);
 
-	set_data(gpio, 1);
-	set_clock(gpio, 1);
+	set_data(bus, 1);
+	set_clock(bus, 1);
 	intel_i2c_quirk_set(dev_priv, false);
 
 	return ret;
@@ -232,12 +209,15 @@
 	struct intel_gmbus *bus = container_of(adapter,
 					       struct intel_gmbus,
 					       adapter);
-	struct drm_i915_private *dev_priv = adapter->algo_data;
-	int i, reg_offset;
+	struct drm_i915_private *dev_priv = bus->dev_priv;
+	int i, reg_offset, ret;
 
-	if (bus->force_bit)
-		return intel_i2c_quirk_xfer(dev_priv,
-					    bus->force_bit, msgs, num);
+	mutex_lock(&dev_priv->gmbus_mutex);
+
+	if (bus->force_bit) {
+		ret = intel_i2c_quirk_xfer(bus, msgs, num);
+		goto out;
+	}
 
 	reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0;
 
@@ -249,7 +229,8 @@
 
 		if (msgs[i].flags & I2C_M_RD) {
 			I915_WRITE(GMBUS1 + reg_offset,
-				   GMBUS_CYCLE_WAIT | (i + 1 == num ? GMBUS_CYCLE_STOP : 0) |
+				   GMBUS_CYCLE_WAIT |
+				   (i + 1 == num ? GMBUS_CYCLE_STOP : 0) |
 				   (len << GMBUS_BYTE_COUNT_SHIFT) |
 				   (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
 				   GMBUS_SLAVE_READ | GMBUS_SW_RDY);
@@ -278,7 +259,8 @@
 
 			I915_WRITE(GMBUS3 + reg_offset, val);
 			I915_WRITE(GMBUS1 + reg_offset,
-				   (i + 1 == num ? GMBUS_CYCLE_STOP : GMBUS_CYCLE_WAIT) |
+				   GMBUS_CYCLE_WAIT |
+				   (i + 1 == num ? GMBUS_CYCLE_STOP : 0) |
 				   (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) |
 				   (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
 				   GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
@@ -317,11 +299,15 @@
 	I915_WRITE(GMBUS1 + reg_offset, 0);
 
 done:
-	/* Mark the GMBUS interface as disabled. We will re-enable it at the
-	 * start of the next xfer, till then let it sleep.
+	/* Mark the GMBUS interface as disabled after waiting for idle.
+	 * We will re-enable it at the start of the next xfer,
+	 * till then let it sleep.
 	 */
+	if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, 10))
+		DRM_INFO("GMBUS timed out waiting for idle\n");
 	I915_WRITE(GMBUS0 + reg_offset, 0);
-	return i;
+	ret = i;
+	goto out;
 
 timeout:
 	DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n",
@@ -329,23 +315,21 @@
 	I915_WRITE(GMBUS0 + reg_offset, 0);
 
 	/* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
-	bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff);
-	if (!bus->force_bit)
-		return -ENOMEM;
-
-	return intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num);
+	if (!bus->has_gpio) {
+		ret = -EIO;
+	} else {
+		bus->force_bit = true;
+		ret = intel_i2c_quirk_xfer(bus, msgs, num);
+	}
+out:
+	mutex_unlock(&dev_priv->gmbus_mutex);
+	return ret;
 }
 
 static u32 gmbus_func(struct i2c_adapter *adapter)
 {
-	struct intel_gmbus *bus = container_of(adapter,
-					       struct intel_gmbus,
-					       adapter);
-
-	if (bus->force_bit)
-		bus->force_bit->algo->functionality(bus->force_bit);
-
-	return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+	return i2c_bit_algo.functionality(adapter) &
+		(I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
 		/* I2C_FUNC_10BIT_ADDR | */
 		I2C_FUNC_SMBUS_READ_BLOCK_DATA |
 		I2C_FUNC_SMBUS_BLOCK_PROC_CALL);
@@ -375,11 +359,13 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret, i;
 
-	dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS,
+	dev_priv->gmbus = kcalloc(GMBUS_NUM_PORTS, sizeof(struct intel_gmbus),
 				  GFP_KERNEL);
 	if (dev_priv->gmbus == NULL)
 		return -ENOMEM;
 
+	mutex_init(&dev_priv->gmbus_mutex);
+
 	for (i = 0; i < GMBUS_NUM_PORTS; i++) {
 		struct intel_gmbus *bus = &dev_priv->gmbus[i];
 
@@ -391,7 +377,7 @@
 			 names[i]);
 
 		bus->adapter.dev.parent = &dev->pdev->dev;
-		bus->adapter.algo_data	= dev_priv;
+		bus->dev_priv = dev_priv;
 
 		bus->adapter.algo = &gmbus_algorithm;
 		ret = i2c_add_adapter(&bus->adapter);
@@ -401,8 +387,11 @@
 		/* By default use a conservative clock rate */
 		bus->reg0 = i | GMBUS_RATE_100KHZ;
 
+		bus->has_gpio = intel_gpio_setup(bus, i);
+
 		/* XXX force bit banging until GMBUS is fully debugged */
-		bus->force_bit = intel_gpio_create(dev_priv, i);
+		if (bus->has_gpio && IS_GEN2(dev))
+			bus->force_bit = true;
 	}
 
 	intel_i2c_reset(dev_priv->dev);
@@ -430,19 +419,8 @@
 {
 	struct intel_gmbus *bus = to_intel_gmbus(adapter);
 
-	if (force_bit) {
-		if (bus->force_bit == NULL) {
-			struct drm_i915_private *dev_priv = adapter->algo_data;
-			bus->force_bit = intel_gpio_create(dev_priv,
-							   bus->reg0 & 0xff);
-		}
-	} else {
-		if (bus->force_bit) {
-			i2c_del_adapter(bus->force_bit);
-			kfree(bus->force_bit);
-			bus->force_bit = NULL;
-		}
-	}
+	if (bus->has_gpio)
+		bus->force_bit = force_bit;
 }
 
 void intel_teardown_gmbus(struct drm_device *dev)
@@ -455,10 +433,6 @@
 
 	for (i = 0; i < GMBUS_NUM_PORTS; i++) {
 		struct intel_gmbus *bus = &dev_priv->gmbus[i];
-		if (bus->force_bit) {
-			i2c_del_adapter(bus->force_bit);
-			kfree(bus->force_bit);
-		}
 		i2c_del_adapter(&bus->adapter);
 	}
 
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index aa84832..95db2e9 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -739,6 +739,30 @@
 			DMI_MATCH(DMI_BOARD_NAME, "AT5NM10T-I"),
 		},
 	},
+	{
+		.callback = intel_no_lvds_dmi_callback,
+		.ident = "Hewlett-Packard t5745",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_BOARD_NAME, "hp t5745"),
+		},
+	},
+	{
+		.callback = intel_no_lvds_dmi_callback,
+		.ident = "Hewlett-Packard st5747",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_BOARD_NAME, "hp st5747"),
+		},
+	},
+	{
+		.callback = intel_no_lvds_dmi_callback,
+		.ident = "MSI Wind Box DC500",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
+			DMI_MATCH(DMI_BOARD_NAME, "MS-7469"),
+		},
+	},
 
 	{ }	/* terminating entry */
 };
@@ -844,6 +868,18 @@
 	return false;
 }
 
+static bool intel_lvds_supported(struct drm_device *dev)
+{
+	/* With the introduction of the PCH we gained a dedicated
+	 * LVDS presence pin, use it. */
+	if (HAS_PCH_SPLIT(dev))
+		return true;
+
+	/* Otherwise LVDS was only attached to mobile products,
+	 * except for the inglorious 830gm */
+	return IS_MOBILE(dev) && !IS_I830(dev);
+}
+
 /**
  * intel_lvds_init - setup LVDS connectors on this device
  * @dev: drm device
@@ -865,6 +901,9 @@
 	int pipe;
 	u8 pin;
 
+	if (!intel_lvds_supported(dev))
+		return false;
+
 	/* Skip init on machines we know falsely report LVDS */
 	if (dmi_check_system(intel_no_lvds))
 		return false;
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c
index be2c6fe..d1928e7 100644
--- a/drivers/gpu/drm/i915/intel_modes.c
+++ b/drivers/gpu/drm/i915/intel_modes.c
@@ -28,6 +28,7 @@
 #include <linux/fb.h>
 #include <drm/drm_edid.h>
 #include "drmP.h"
+#include "drm_edid.h"
 #include "intel_drv.h"
 #include "i915_drv.h"
 
@@ -42,13 +43,13 @@
 	u8 buf[2];
 	struct i2c_msg msgs[] = {
 		{
-			.addr = 0x50,
+			.addr = DDC_ADDR,
 			.flags = 0,
 			.len = 1,
 			.buf = out_buf,
 		},
 		{
-			.addr = 0x50,
+			.addr = DDC_ADDR,
 			.flags = I2C_M_RD,
 			.len = 1,
 			.buf = buf,
@@ -83,10 +84,11 @@
 	return ret;
 }
 
-static const char *force_audio_names[] = {
-	"off",
-	"auto",
-	"on",
+static const struct drm_prop_enum_list force_audio_names[] = {
+	{ HDMI_AUDIO_OFF_DVI, "force-dvi" },
+	{ HDMI_AUDIO_OFF, "off" },
+	{ HDMI_AUDIO_AUTO, "auto" },
+	{ HDMI_AUDIO_ON, "on" },
 };
 
 void
@@ -95,27 +97,24 @@
 	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_property *prop;
-	int i;
 
 	prop = dev_priv->force_audio_property;
 	if (prop == NULL) {
-		prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
+		prop = drm_property_create_enum(dev, 0,
 					   "audio",
+					   force_audio_names,
 					   ARRAY_SIZE(force_audio_names));
 		if (prop == NULL)
 			return;
 
-		for (i = 0; i < ARRAY_SIZE(force_audio_names); i++)
-			drm_property_add_enum(prop, i, i-1, force_audio_names[i]);
-
 		dev_priv->force_audio_property = prop;
 	}
 	drm_connector_attach_property(connector, prop, 0);
 }
 
-static const char *broadcast_rgb_names[] = {
-	"Full",
-	"Limited 16:235",
+static const struct drm_prop_enum_list broadcast_rgb_names[] = {
+	{ 0, "Full" },
+	{ 1, "Limited 16:235" },
 };
 
 void
@@ -124,19 +123,16 @@
 	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_property *prop;
-	int i;
 
 	prop = dev_priv->broadcast_rgb_property;
 	if (prop == NULL) {
-		prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
+		prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
 					   "Broadcast RGB",
+					   broadcast_rgb_names,
 					   ARRAY_SIZE(broadcast_rgb_names));
 		if (prop == NULL)
 			return;
 
-		for (i = 0; i < ARRAY_SIZE(broadcast_rgb_names); i++)
-			drm_property_add_enum(prop, i, i, broadcast_rgb_names[i]);
-
 		dev_priv->broadcast_rgb_property = prop;
 	}
 
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index cdf17d4..80b331c 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -25,8 +25,6 @@
  *
  * Derived from Xorg ddx, xf86-video-intel, src/i830_video.c
  */
-
-#include <linux/seq_file.h>
 #include "drmP.h"
 #include "drm.h"
 #include "i915_drm.h"
@@ -227,7 +225,8 @@
 	}
 	overlay->last_flip_req = request->seqno;
 	overlay->flip_tail = tail;
-	ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req);
+	ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req,
+				true);
 	if (ret)
 		return ret;
 
@@ -263,7 +262,7 @@
 	DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n");
 
 	mode = drm_mode_duplicate(dev, &vesa_640x480);
-	drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+	drm_mode_set_crtcinfo(mode, 0);
 	if (!drm_crtc_helper_set_mode(&crtc->base, mode,
 				       crtc->base.x, crtc->base.y,
 				       crtc->base.fb))
@@ -448,7 +447,8 @@
 	if (overlay->last_flip_req == 0)
 		return 0;
 
-	ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req);
+	ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req,
+				true);
 	if (ret)
 		return ret;
 
@@ -935,10 +935,10 @@
 {
 	struct drm_display_mode *mode = &overlay->crtc->base.mode;
 
-	if (rec->dst_x < mode->crtc_hdisplay &&
-	    rec->dst_x + rec->dst_width <= mode->crtc_hdisplay &&
-	    rec->dst_y < mode->crtc_vdisplay &&
-	    rec->dst_y + rec->dst_height <= mode->crtc_vdisplay)
+	if (rec->dst_x < mode->hdisplay &&
+	    rec->dst_x + rec->dst_width <= mode->hdisplay &&
+	    rec->dst_y < mode->vdisplay &&
+	    rec->dst_y + rec->dst_height <= mode->vdisplay)
 		return 0;
 	else
 		return -EINVAL;
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 04d79fd..230a141 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -48,7 +48,7 @@
 
 	adjusted_mode->clock = fixed_mode->clock;
 
-	drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+	drm_mode_set_crtcinfo(adjusted_mode, 0);
 }
 
 /* adjusted_mode has been preset to be the panel's fixed mode */
@@ -141,8 +141,8 @@
 			dev_priv->saveBLC_PWM_CTL2 = val;
 		} else if (val == 0) {
 			I915_WRITE(BLC_PWM_PCH_CTL2,
-				   dev_priv->saveBLC_PWM_CTL);
-			val = dev_priv->saveBLC_PWM_CTL;
+				   dev_priv->saveBLC_PWM_CTL2);
+			val = dev_priv->saveBLC_PWM_CTL2;
 		}
 	} else {
 		val = I915_READ(BLC_PWM_CTL);
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 5361915..e25581a 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -52,20 +52,6 @@
 	return space;
 }
 
-static u32 i915_gem_get_seqno(struct drm_device *dev)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	u32 seqno;
-
-	seqno = dev_priv->next_seqno;
-
-	/* reserve 0 for non-seqno */
-	if (++dev_priv->next_seqno == 0)
-		dev_priv->next_seqno = 1;
-
-	return seqno;
-}
-
 static int
 render_ring_flush(struct intel_ring_buffer *ring,
 		  u32	invalidate_domains,
@@ -399,8 +385,6 @@
 
 	if (INTEL_INFO(dev)->gen > 3) {
 		int mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
-		if (IS_GEN6(dev) || IS_GEN7(dev))
-			mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;
 		I915_WRITE(MI_MODE, mode);
 		if (IS_GEN7(dev))
 			I915_WRITE(GFX_MODE_GEN7,
@@ -467,7 +451,7 @@
 	mbox1_reg = ring->signal_mbox[0];
 	mbox2_reg = ring->signal_mbox[1];
 
-	*seqno = i915_gem_get_seqno(ring->dev);
+	*seqno = i915_gem_next_request_seqno(ring);
 
 	update_mboxes(ring, *seqno, mbox1_reg);
 	update_mboxes(ring, *seqno, mbox2_reg);
@@ -565,8 +549,7 @@
 pc_render_add_request(struct intel_ring_buffer *ring,
 		      u32 *result)
 {
-	struct drm_device *dev = ring->dev;
-	u32 seqno = i915_gem_get_seqno(dev);
+	u32 seqno = i915_gem_next_request_seqno(ring);
 	struct pipe_control *pc = ring->private;
 	u32 scratch_addr = pc->gtt_offset + 128;
 	int ret;
@@ -600,6 +583,7 @@
 	PIPE_CONTROL_FLUSH(ring, scratch_addr);
 	scratch_addr += 128;
 	PIPE_CONTROL_FLUSH(ring, scratch_addr);
+
 	intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE |
 			PIPE_CONTROL_WRITE_FLUSH |
 			PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
@@ -617,8 +601,7 @@
 render_ring_add_request(struct intel_ring_buffer *ring,
 			u32 *result)
 {
-	struct drm_device *dev = ring->dev;
-	u32 seqno = i915_gem_get_seqno(dev);
+	u32 seqno = i915_gem_next_request_seqno(ring);
 	int ret;
 
 	ret = intel_ring_begin(ring, 4);
@@ -643,7 +626,7 @@
 	/* Workaround to force correct ordering between irq and seqno writes on
 	 * ivb (and maybe also on snb) by reading from a CS register (like
 	 * ACTHD) before reading the status page. */
-	if (IS_GEN7(dev))
+	if (IS_GEN6(dev) || IS_GEN7(dev))
 		intel_ring_get_active_head(ring);
 	return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
 }
@@ -744,13 +727,13 @@
 	 */
 	if (IS_GEN7(dev)) {
 		switch (ring->id) {
-		case RING_RENDER:
+		case RCS:
 			mmio = RENDER_HWS_PGA_GEN7;
 			break;
-		case RING_BLT:
+		case BCS:
 			mmio = BLT_HWS_PGA_GEN7;
 			break;
-		case RING_BSD:
+		case VCS:
 			mmio = BSD_HWS_PGA_GEN7;
 			break;
 		}
@@ -792,7 +775,7 @@
 	if (ret)
 		return ret;
 
-	seqno = i915_gem_get_seqno(ring->dev);
+	seqno = i915_gem_next_request_seqno(ring);
 
 	intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
 	intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
@@ -816,8 +799,7 @@
 	/* It looks like we need to prevent the gt from suspending while waiting
 	 * for an notifiy irq, otherwise irqs seem to get lost on at least the
 	 * blt/bsd rings on ivb. */
-	if (IS_GEN7(dev))
-		gen6_gt_force_wake_get(dev_priv);
+	gen6_gt_force_wake_get(dev_priv);
 
 	spin_lock(&ring->irq_lock);
 	if (ring->irq_refcount++ == 0) {
@@ -844,8 +826,7 @@
 	}
 	spin_unlock(&ring->irq_lock);
 
-	if (IS_GEN7(dev))
-		gen6_gt_force_wake_put(dev_priv);
+	gen6_gt_force_wake_put(dev_priv);
 }
 
 static bool
@@ -1127,11 +1108,93 @@
 	return 0;
 }
 
+static int intel_ring_wait_seqno(struct intel_ring_buffer *ring, u32 seqno)
+{
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
+	bool was_interruptible;
+	int ret;
+
+	/* XXX As we have not yet audited all the paths to check that
+	 * they are ready for ERESTARTSYS from intel_ring_begin, do not
+	 * allow us to be interruptible by a signal.
+	 */
+	was_interruptible = dev_priv->mm.interruptible;
+	dev_priv->mm.interruptible = false;
+
+	ret = i915_wait_request(ring, seqno, true);
+
+	dev_priv->mm.interruptible = was_interruptible;
+
+	return ret;
+}
+
+static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n)
+{
+	struct drm_i915_gem_request *request;
+	u32 seqno = 0;
+	int ret;
+
+	i915_gem_retire_requests_ring(ring);
+
+	if (ring->last_retired_head != -1) {
+		ring->head = ring->last_retired_head;
+		ring->last_retired_head = -1;
+		ring->space = ring_space(ring);
+		if (ring->space >= n)
+			return 0;
+	}
+
+	list_for_each_entry(request, &ring->request_list, list) {
+		int space;
+
+		if (request->tail == -1)
+			continue;
+
+		space = request->tail - (ring->tail + 8);
+		if (space < 0)
+			space += ring->size;
+		if (space >= n) {
+			seqno = request->seqno;
+			break;
+		}
+
+		/* Consume this request in case we need more space than
+		 * is available and so need to prevent a race between
+		 * updating last_retired_head and direct reads of
+		 * I915_RING_HEAD. It also provides a nice sanity check.
+		 */
+		request->tail = -1;
+	}
+
+	if (seqno == 0)
+		return -ENOSPC;
+
+	ret = intel_ring_wait_seqno(ring, seqno);
+	if (ret)
+		return ret;
+
+	if (WARN_ON(ring->last_retired_head == -1))
+		return -ENOSPC;
+
+	ring->head = ring->last_retired_head;
+	ring->last_retired_head = -1;
+	ring->space = ring_space(ring);
+	if (WARN_ON(ring->space < n))
+		return -ENOSPC;
+
+	return 0;
+}
+
 int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n)
 {
 	struct drm_device *dev = ring->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	unsigned long end;
+	int ret;
+
+	ret = intel_ring_wait_request(ring, n);
+	if (ret != -ENOSPC)
+		return ret;
 
 	trace_i915_ring_wait_begin(ring);
 	if (drm_core_check_feature(dev, DRIVER_GEM))
@@ -1200,7 +1263,7 @@
 
 static const struct intel_ring_buffer render_ring = {
 	.name			= "render ring",
-	.id			= RING_RENDER,
+	.id			= RCS,
 	.mmio_base		= RENDER_RING_BASE,
 	.size			= 32 * PAGE_SIZE,
 	.init			= init_render_ring,
@@ -1223,7 +1286,7 @@
 
 static const struct intel_ring_buffer bsd_ring = {
 	.name                   = "bsd ring",
-	.id			= RING_BSD,
+	.id			= VCS,
 	.mmio_base		= BSD_RING_BASE,
 	.size			= 32 * PAGE_SIZE,
 	.init			= init_ring_common,
@@ -1333,7 +1396,7 @@
 /* ring buffer for Video Codec for Gen6+ */
 static const struct intel_ring_buffer gen6_bsd_ring = {
 	.name			= "gen6 bsd ring",
-	.id			= RING_BSD,
+	.id			= VCS,
 	.mmio_base		= GEN6_BSD_RING_BASE,
 	.size			= 32 * PAGE_SIZE,
 	.init			= init_ring_common,
@@ -1369,79 +1432,13 @@
 			  GEN6_BLITTER_USER_INTERRUPT);
 }
 
-
-/* Workaround for some stepping of SNB,
- * each time when BLT engine ring tail moved,
- * the first command in the ring to be parsed
- * should be MI_BATCH_BUFFER_START
- */
-#define NEED_BLT_WORKAROUND(dev) \
-	(IS_GEN6(dev) && (dev->pdev->revision < 8))
-
-static inline struct drm_i915_gem_object *
-to_blt_workaround(struct intel_ring_buffer *ring)
-{
-	return ring->private;
-}
-
-static int blt_ring_init(struct intel_ring_buffer *ring)
-{
-	if (NEED_BLT_WORKAROUND(ring->dev)) {
-		struct drm_i915_gem_object *obj;
-		u32 *ptr;
-		int ret;
-
-		obj = i915_gem_alloc_object(ring->dev, 4096);
-		if (obj == NULL)
-			return -ENOMEM;
-
-		ret = i915_gem_object_pin(obj, 4096, true);
-		if (ret) {
-			drm_gem_object_unreference(&obj->base);
-			return ret;
-		}
-
-		ptr = kmap(obj->pages[0]);
-		*ptr++ = MI_BATCH_BUFFER_END;
-		*ptr++ = MI_NOOP;
-		kunmap(obj->pages[0]);
-
-		ret = i915_gem_object_set_to_gtt_domain(obj, false);
-		if (ret) {
-			i915_gem_object_unpin(obj);
-			drm_gem_object_unreference(&obj->base);
-			return ret;
-		}
-
-		ring->private = obj;
-	}
-
-	return init_ring_common(ring);
-}
-
-static int blt_ring_begin(struct intel_ring_buffer *ring,
-			  int num_dwords)
-{
-	if (ring->private) {
-		int ret = intel_ring_begin(ring, num_dwords+2);
-		if (ret)
-			return ret;
-
-		intel_ring_emit(ring, MI_BATCH_BUFFER_START);
-		intel_ring_emit(ring, to_blt_workaround(ring)->gtt_offset);
-
-		return 0;
-	} else
-		return intel_ring_begin(ring, 4);
-}
-
 static int blt_ring_flush(struct intel_ring_buffer *ring,
 			  u32 invalidate, u32 flush)
 {
 	uint32_t cmd;
 	int ret;
 
-	ret = blt_ring_begin(ring, 4);
+	ret = intel_ring_begin(ring, 4);
 	if (ret)
 		return ret;
 
@@ -1456,22 +1453,12 @@
 	return 0;
 }
 
-static void blt_ring_cleanup(struct intel_ring_buffer *ring)
-{
-	if (!ring->private)
-		return;
-
-	i915_gem_object_unpin(ring->private);
-	drm_gem_object_unreference(ring->private);
-	ring->private = NULL;
-}
-
 static const struct intel_ring_buffer gen6_blt_ring = {
 	.name			= "blt ring",
-	.id			= RING_BLT,
+	.id			= BCS,
 	.mmio_base		= BLT_RING_BASE,
 	.size			= 32 * PAGE_SIZE,
-	.init			= blt_ring_init,
+	.init			= init_ring_common,
 	.write_tail		= ring_write_tail,
 	.flush			= blt_ring_flush,
 	.add_request		= gen6_add_request,
@@ -1479,7 +1466,6 @@
 	.irq_get		= blt_ring_get_irq,
 	.irq_put		= blt_ring_put_irq,
 	.dispatch_execbuffer	= gen6_ring_dispatch_execbuffer,
-	.cleanup		= blt_ring_cleanup,
 	.sync_to		= gen6_blt_ring_sync_to,
 	.semaphore_register	= {MI_SEMAPHORE_SYNC_BR,
 				   MI_SEMAPHORE_SYNC_BV,
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 68281c9..bc0365b 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -1,13 +1,6 @@
 #ifndef _INTEL_RINGBUFFER_H_
 #define _INTEL_RINGBUFFER_H_
 
-enum {
-	RCS = 0x0,
-	VCS,
-	BCS,
-	I915_NUM_RINGS,
-};
-
 struct  intel_hw_status_page {
 	u32	__iomem	*page_addr;
 	unsigned int	gfx_addr;
@@ -36,10 +29,11 @@
 struct  intel_ring_buffer {
 	const char	*name;
 	enum intel_ring_id {
-		RING_RENDER = 0x1,
-		RING_BSD = 0x2,
-		RING_BLT = 0x4,
+		RCS = 0x0,
+		VCS,
+		BCS,
 	} id;
+#define I915_NUM_RINGS 3
 	u32		mmio_base;
 	void		__iomem *virtual_start;
 	struct		drm_device *dev;
@@ -52,6 +46,16 @@
 	int		effective_size;
 	struct intel_hw_status_page status_page;
 
+	/** We track the position of the requests in the ring buffer, and
+	 * when each is retired we increment last_retired_head as the GPU
+	 * must have finished processing the request and so we know we
+	 * can advance the ringbuffer up to that position.
+	 *
+	 * last_retired_head is set to -1 after the value is consumed so
+	 * we can detect new retirements.
+	 */
+	u32		last_retired_head;
+
 	spinlock_t	irq_lock;
 	u32		irq_refcount;
 	u32		irq_mask;
@@ -119,6 +123,12 @@
 	void *private;
 };
 
+static inline unsigned
+intel_ring_flag(struct intel_ring_buffer *ring)
+{
+	return 1 << ring->id;
+}
+
 static inline u32
 intel_ring_sync_index(struct intel_ring_buffer *ring,
 		      struct intel_ring_buffer *other)
@@ -193,6 +203,11 @@
 u32 intel_ring_get_active_head(struct intel_ring_buffer *ring);
 void intel_ring_setup_status_page(struct intel_ring_buffer *ring);
 
+static inline u32 intel_ring_get_tail(struct intel_ring_buffer *ring)
+{
+	return ring->tail;
+}
+
 static inline void i915_trace_irq_get(struct intel_ring_buffer *ring, u32 seqno)
 {
 	if (ring->trace_irq_seqno == 0 && ring->irq_get(ring))
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index e334ec3..e36b171 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -148,7 +148,7 @@
 	/* Mark the type of connector */
 	uint16_t output_flag;
 
-	int force_audio;
+	enum hdmi_force_audio force_audio;
 
 	/* This contains all current supported TV format */
 	u8 tv_format_supported[TV_FORMAT_NUM];
@@ -944,7 +944,6 @@
 
 	intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd);
 
-	drm_mode_set_crtcinfo(adjusted_mode, 0);
 	return true;
 }
 
@@ -1310,8 +1309,8 @@
 
 	if (status == connector_status_connected) {
 		struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
-		if (intel_sdvo_connector->force_audio)
-			intel_sdvo->has_hdmi_audio = intel_sdvo_connector->force_audio > 0;
+		if (intel_sdvo_connector->force_audio != HDMI_AUDIO_AUTO)
+			intel_sdvo->has_hdmi_audio = (intel_sdvo_connector->force_audio == HDMI_AUDIO_ON);
 	}
 
 	return status;
@@ -1684,10 +1683,10 @@
 
 		intel_sdvo_connector->force_audio = i;
 
-		if (i == 0)
+		if (i == HDMI_AUDIO_AUTO)
 			has_audio = intel_sdvo_detect_hdmi_audio(connector);
 		else
-			has_audio = i > 0;
+			has_audio = (i == HDMI_AUDIO_ON);
 
 		if (has_audio == intel_sdvo->has_hdmi_audio)
 			return 0;
@@ -1985,7 +1984,7 @@
 	drm_connector_helper_add(&connector->base.base,
 				 &intel_sdvo_connector_helper_funcs);
 
-	connector->base.base.interlace_allowed = 0;
+	connector->base.base.interlace_allowed = 1;
 	connector->base.base.doublescan_allowed = 0;
 	connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
 
@@ -2277,10 +2276,8 @@
 		intel_sdvo_connector->max_##name = data_value[0]; \
 		intel_sdvo_connector->cur_##name = response; \
 		intel_sdvo_connector->name = \
-			drm_property_create(dev, DRM_MODE_PROP_RANGE, #name, 2); \
+			drm_property_create_range(dev, 0, #name, 0, data_value[0]); \
 		if (!intel_sdvo_connector->name) return false; \
-		intel_sdvo_connector->name->values[0] = 0; \
-		intel_sdvo_connector->name->values[1] = data_value[0]; \
 		drm_connector_attach_property(connector, \
 					      intel_sdvo_connector->name, \
 					      intel_sdvo_connector->cur_##name); \
@@ -2314,25 +2311,19 @@
 		intel_sdvo_connector->left_margin = data_value[0] - response;
 		intel_sdvo_connector->right_margin = intel_sdvo_connector->left_margin;
 		intel_sdvo_connector->left =
-			drm_property_create(dev, DRM_MODE_PROP_RANGE,
-					    "left_margin", 2);
+			drm_property_create_range(dev, 0, "left_margin", 0, data_value[0]);
 		if (!intel_sdvo_connector->left)
 			return false;
 
-		intel_sdvo_connector->left->values[0] = 0;
-		intel_sdvo_connector->left->values[1] = data_value[0];
 		drm_connector_attach_property(connector,
 					      intel_sdvo_connector->left,
 					      intel_sdvo_connector->left_margin);
 
 		intel_sdvo_connector->right =
-			drm_property_create(dev, DRM_MODE_PROP_RANGE,
-					    "right_margin", 2);
+			drm_property_create_range(dev, 0, "right_margin", 0, data_value[0]);
 		if (!intel_sdvo_connector->right)
 			return false;
 
-		intel_sdvo_connector->right->values[0] = 0;
-		intel_sdvo_connector->right->values[1] = data_value[0];
 		drm_connector_attach_property(connector,
 					      intel_sdvo_connector->right,
 					      intel_sdvo_connector->right_margin);
@@ -2356,25 +2347,21 @@
 		intel_sdvo_connector->top_margin = data_value[0] - response;
 		intel_sdvo_connector->bottom_margin = intel_sdvo_connector->top_margin;
 		intel_sdvo_connector->top =
-			drm_property_create(dev, DRM_MODE_PROP_RANGE,
-					    "top_margin", 2);
+			drm_property_create_range(dev, 0,
+					    "top_margin", 0, data_value[0]);
 		if (!intel_sdvo_connector->top)
 			return false;
 
-		intel_sdvo_connector->top->values[0] = 0;
-		intel_sdvo_connector->top->values[1] = data_value[0];
 		drm_connector_attach_property(connector,
 					      intel_sdvo_connector->top,
 					      intel_sdvo_connector->top_margin);
 
 		intel_sdvo_connector->bottom =
-			drm_property_create(dev, DRM_MODE_PROP_RANGE,
-					    "bottom_margin", 2);
+			drm_property_create_range(dev, 0,
+					    "bottom_margin", 0, data_value[0]);
 		if (!intel_sdvo_connector->bottom)
 			return false;
 
-		intel_sdvo_connector->bottom->values[0] = 0;
-		intel_sdvo_connector->bottom->values[1] = data_value[0];
 		drm_connector_attach_property(connector,
 					      intel_sdvo_connector->bottom,
 					      intel_sdvo_connector->bottom_margin);
@@ -2403,12 +2390,10 @@
 		intel_sdvo_connector->max_dot_crawl = 1;
 		intel_sdvo_connector->cur_dot_crawl = response & 0x1;
 		intel_sdvo_connector->dot_crawl =
-			drm_property_create(dev, DRM_MODE_PROP_RANGE, "dot_crawl", 2);
+			drm_property_create_range(dev, 0, "dot_crawl", 0, 1);
 		if (!intel_sdvo_connector->dot_crawl)
 			return false;
 
-		intel_sdvo_connector->dot_crawl->values[0] = 0;
-		intel_sdvo_connector->dot_crawl->values[1] = 1;
 		drm_connector_attach_property(connector,
 					      intel_sdvo_connector->dot_crawl,
 					      intel_sdvo_connector->cur_dot_crawl);
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index a083504..a464771 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -411,6 +411,9 @@
 
 	old_obj = intel_plane->obj;
 
+	src_w = src_w >> 16;
+	src_h = src_h >> 16;
+
 	/* Pipe must be running... */
 	if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE))
 		return -EINVAL;
@@ -501,7 +504,7 @@
 			intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe);
 			mutex_lock(&dev->struct_mutex);
 		}
-		i915_gem_object_unpin(old_obj);
+		intel_unpin_fb_obj(old_obj);
 	}
 
 out_unlock:
@@ -528,7 +531,7 @@
 		goto out;
 
 	mutex_lock(&dev->struct_mutex);
-	i915_gem_object_unpin(intel_plane->obj);
+	intel_unpin_fb_obj(intel_plane->obj);
 	intel_plane->obj = NULL;
 	mutex_unlock(&dev->struct_mutex);
 out:
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 1571be3..05f765e 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1240,7 +1240,7 @@
 	int type;
 
 	mode = reported_modes[0];
-	drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
+	drm_mode_set_crtcinfo(&mode, 0);
 
 	if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
 		type = intel_tv_detect_type(intel_tv, connector);
diff --git a/drivers/gpu/drm/mga/mga_dma.c b/drivers/gpu/drm/mga/mga_dma.c
index 5ccb65de..507aa3d 100644
--- a/drivers/gpu/drm/mga/mga_dma.c
+++ b/drivers/gpu/drm/mga/mga_dma.c
@@ -403,6 +403,8 @@
 	dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT;
 	dev_priv->chipset = flags;
 
+	pci_set_master(dev->pdev);
+
 	dev_priv->mmio_base = pci_resource_start(dev->pdev, 1);
 	dev_priv->mmio_size = pci_resource_len(dev->pdev, 1);
 
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index ca16399..97a8126 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -13,6 +13,7 @@
 	select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT
 	select ACPI_WMI if ACPI
 	select MXM_WMI if ACPI
+	select POWER_SUPPLY
 	help
 	  Choose this option for open-source nVidia support.
 
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 9f27e3d..1a2ad7e 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -14,7 +14,8 @@
 	     nouveau_mm.o nouveau_vm.o nouveau_mxm.o nouveau_gpio.o \
              nv04_timer.o \
              nv04_mc.o nv40_mc.o nv50_mc.o \
-             nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \
+             nv04_fb.o nv10_fb.o nv20_fb.o nv30_fb.o nv40_fb.o \
+             nv50_fb.o nvc0_fb.o \
              nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o nvc0_fifo.o \
              nv04_graph.o nv10_graph.o nv20_graph.o \
              nv40_graph.o nv50_graph.o nvc0_graph.o \
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index e5cbead..80963d0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -65,195 +65,233 @@
 }
 
 static int
-score_vbios(struct drm_device *dev, const uint8_t *data, const bool writeable)
+score_vbios(struct nvbios *bios, const bool writeable)
 {
-	if (!(data[0] == 0x55 && data[1] == 0xAA)) {
-		NV_TRACEWARN(dev, "... BIOS signature not found\n");
+	if (!bios->data || bios->data[0] != 0x55 || bios->data[1] != 0xAA) {
+		NV_TRACEWARN(bios->dev, "... BIOS signature not found\n");
 		return 0;
 	}
 
-	if (nv_cksum(data, data[2] * 512)) {
-		NV_TRACEWARN(dev, "... BIOS checksum invalid\n");
+	if (nv_cksum(bios->data, bios->data[2] * 512)) {
+		NV_TRACEWARN(bios->dev, "... BIOS checksum invalid\n");
 		/* if a ro image is somewhat bad, it's probably all rubbish */
 		return writeable ? 2 : 1;
-	} else
-		NV_TRACE(dev, "... appears to be valid\n");
+	}
 
+	NV_TRACE(bios->dev, "... appears to be valid\n");
 	return 3;
 }
 
-static void load_vbios_prom(struct drm_device *dev, uint8_t *data)
+static void
+bios_shadow_prom(struct nvbios *bios)
 {
+	struct drm_device *dev = bios->dev;
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	uint32_t pci_nv_20, save_pci_nv_20;
-	int pcir_ptr;
+	u32 pcireg, access;
+	u16 pcir;
 	int i;
 
+	/* enable access to rom */
 	if (dev_priv->card_type >= NV_50)
-		pci_nv_20 = 0x88050;
+		pcireg = 0x088050;
 	else
-		pci_nv_20 = NV_PBUS_PCI_NV_20;
+		pcireg = NV_PBUS_PCI_NV_20;
+	access = nv_mask(dev, pcireg, 0x00000001, 0x00000000);
 
-	/* enable ROM access */
-	save_pci_nv_20 = nvReadMC(dev, pci_nv_20);
-	nvWriteMC(dev, pci_nv_20,
-		  save_pci_nv_20 & ~NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED);
+	/* bail if no rom signature, with a workaround for a PROM reading
+	 * issue on some chipsets.  the first read after a period of
+	 * inactivity returns the wrong result, so retry the first header
+	 * byte a few times before giving up as a workaround
+	 */
+	i = 16;
+	do {
+		if (nv_rd08(dev, NV_PROM_OFFSET + 0) == 0x55)
+			break;
+	} while (i--);
 
-	/* bail if no rom signature */
-	if (nv_rd08(dev, NV_PROM_OFFSET) != 0x55 ||
-	    nv_rd08(dev, NV_PROM_OFFSET + 1) != 0xaa)
+	if (!i || nv_rd08(dev, NV_PROM_OFFSET + 1) != 0xaa)
 		goto out;
 
 	/* additional check (see note below) - read PCI record header */
-	pcir_ptr = nv_rd08(dev, NV_PROM_OFFSET + 0x18) |
-		   nv_rd08(dev, NV_PROM_OFFSET + 0x19) << 8;
-	if (nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr) != 'P' ||
-	    nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 1) != 'C' ||
-	    nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 2) != 'I' ||
-	    nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 3) != 'R')
+	pcir = nv_rd08(dev, NV_PROM_OFFSET + 0x18) |
+	       nv_rd08(dev, NV_PROM_OFFSET + 0x19) << 8;
+	if (nv_rd08(dev, NV_PROM_OFFSET + pcir + 0) != 'P' ||
+	    nv_rd08(dev, NV_PROM_OFFSET + pcir + 1) != 'C' ||
+	    nv_rd08(dev, NV_PROM_OFFSET + pcir + 2) != 'I' ||
+	    nv_rd08(dev, NV_PROM_OFFSET + pcir + 3) != 'R')
 		goto out;
 
-	/* on some 6600GT/6800LE prom reads are messed up.  nvclock alleges a
-	 * a good read may be obtained by waiting or re-reading (cargocult: 5x)
-	 * each byte.  we'll hope pramin has something usable instead
-	 */
-	for (i = 0; i < NV_PROM_SIZE; i++)
-		data[i] = nv_rd08(dev, NV_PROM_OFFSET + i);
+	/* read entire bios image to system memory */
+	bios->length = nv_rd08(dev, NV_PROM_OFFSET + 2) * 512;
+	bios->data = kmalloc(bios->length, GFP_KERNEL);
+	if (bios->data) {
+		for (i = 0; i < bios->length; i++)
+			bios->data[i] = nv_rd08(dev, NV_PROM_OFFSET + i);
+	}
 
 out:
-	/* disable ROM access */
-	nvWriteMC(dev, pci_nv_20,
-		  save_pci_nv_20 | NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED);
+	/* disable access to rom */
+	nv_wr32(dev, pcireg, access);
 }
 
-static void load_vbios_pramin(struct drm_device *dev, uint8_t *data)
+static void
+bios_shadow_pramin(struct nvbios *bios)
 {
+	struct drm_device *dev = bios->dev;
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	uint32_t old_bar0_pramin = 0;
+	u32 bar0 = 0;
 	int i;
 
 	if (dev_priv->card_type >= NV_50) {
 		u64 addr = (u64)(nv_rd32(dev, 0x619f04) & 0xffffff00) << 8;
 		if (!addr) {
-			addr  = (u64)nv_rd32(dev, 0x1700) << 16;
+			addr  = (u64)nv_rd32(dev, 0x001700) << 16;
 			addr += 0xf0000;
 		}
 
-		old_bar0_pramin = nv_rd32(dev, 0x1700);
-		nv_wr32(dev, 0x1700, addr >> 16);
+		bar0 = nv_mask(dev, 0x001700, 0xffffffff, addr >> 16);
 	}
 
 	/* bail if no rom signature */
-	if (nv_rd08(dev, NV_PRAMIN_OFFSET) != 0x55 ||
+	if (nv_rd08(dev, NV_PRAMIN_OFFSET + 0) != 0x55 ||
 	    nv_rd08(dev, NV_PRAMIN_OFFSET + 1) != 0xaa)
 		goto out;
 
-	for (i = 0; i < NV_PROM_SIZE; i++)
-		data[i] = nv_rd08(dev, NV_PRAMIN_OFFSET + i);
+	bios->length = nv_rd08(dev, NV_PRAMIN_OFFSET + 2) * 512;
+	bios->data = kmalloc(bios->length, GFP_KERNEL);
+	if (bios->data) {
+		for (i = 0; i < bios->length; i++)
+			bios->data[i] = nv_rd08(dev, NV_PRAMIN_OFFSET + i);
+	}
 
 out:
 	if (dev_priv->card_type >= NV_50)
-		nv_wr32(dev, 0x1700, old_bar0_pramin);
+		nv_wr32(dev, 0x001700, bar0);
 }
 
-static void load_vbios_pci(struct drm_device *dev, uint8_t *data)
+static void
+bios_shadow_pci(struct nvbios *bios)
 {
-	void __iomem *rom = NULL;
-	size_t rom_len;
-	int ret;
+	struct pci_dev *pdev = bios->dev->pdev;
+	size_t length;
 
-	ret = pci_enable_rom(dev->pdev);
-	if (ret)
-		return;
+	if (!pci_enable_rom(pdev)) {
+		void __iomem *rom = pci_map_rom(pdev, &length);
+		if (rom && length) {
+			bios->data = kmalloc(length, GFP_KERNEL);
+			if (bios->data) {
+				memcpy_fromio(bios->data, rom, length);
+				bios->length = length;
+			}
+		}
+		if (rom)
+			pci_unmap_rom(pdev, rom);
 
-	rom = pci_map_rom(dev->pdev, &rom_len);
-	if (!rom)
-		goto out;
-	memcpy_fromio(data, rom, rom_len);
-	pci_unmap_rom(dev->pdev, rom);
-
-out:
-	pci_disable_rom(dev->pdev);
-}
-
-static void load_vbios_acpi(struct drm_device *dev, uint8_t *data)
-{
-	int i;
-	int ret;
-	int size = 64 * 1024;
-
-	if (!nouveau_acpi_rom_supported(dev->pdev))
-		return;
-
-	for (i = 0; i < (size / ROM_BIOS_PAGE); i++) {
-		ret = nouveau_acpi_get_bios_chunk(data,
-						  (i * ROM_BIOS_PAGE),
-						  ROM_BIOS_PAGE);
-		if (ret <= 0)
-			break;
+		pci_disable_rom(pdev);
 	}
-	return;
+}
+
+static void
+bios_shadow_acpi(struct nvbios *bios)
+{
+	struct pci_dev *pdev = bios->dev->pdev;
+	int ptr, len, ret;
+	u8 data[3];
+
+	if (!nouveau_acpi_rom_supported(pdev))
+		return;
+
+	ret = nouveau_acpi_get_bios_chunk(data, 0, sizeof(data));
+	if (ret != sizeof(data))
+		return;
+
+	bios->length = min(data[2] * 512, 65536);
+	bios->data = kmalloc(bios->length, GFP_KERNEL);
+	if (!bios->data)
+		return;
+
+	len = bios->length;
+	ptr = 0;
+	while (len) {
+		int size = (len > ROM_BIOS_PAGE) ? ROM_BIOS_PAGE : len;
+
+		ret = nouveau_acpi_get_bios_chunk(bios->data, ptr, size);
+		if (ret != size) {
+			kfree(bios->data);
+			bios->data = NULL;
+			return;
+		}
+
+		len -= size;
+		ptr += size;
+	}
 }
 
 struct methods {
 	const char desc[8];
-	void (*loadbios)(struct drm_device *, uint8_t *);
+	void (*shadow)(struct nvbios *);
 	const bool rw;
+	int score;
+	u32 size;
+	u8 *data;
 };
 
-static struct methods shadow_methods[] = {
-	{ "PRAMIN", load_vbios_pramin, true },
-	{ "PROM", load_vbios_prom, false },
-	{ "PCIROM", load_vbios_pci, true },
-	{ "ACPI", load_vbios_acpi, true },
-};
-#define NUM_SHADOW_METHODS ARRAY_SIZE(shadow_methods)
-
-static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
+static bool
+bios_shadow(struct drm_device *dev)
 {
-	struct methods *methods = shadow_methods;
-	int testscore = 3;
-	int scores[NUM_SHADOW_METHODS], i;
+	struct methods shadow_methods[] = {
+		{ "PRAMIN", bios_shadow_pramin, true, 0, 0, NULL },
+		{ "PROM", bios_shadow_prom, false, 0, 0, NULL },
+		{ "ACPI", bios_shadow_acpi, true, 0, 0, NULL },
+		{ "PCIROM", bios_shadow_pci, true, 0, 0, NULL },
+		{}
+	};
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nvbios *bios = &dev_priv->vbios;
+	struct methods *mthd, *best;
 
 	if (nouveau_vbios) {
-		for (i = 0; i < NUM_SHADOW_METHODS; i++)
-			if (!strcasecmp(nouveau_vbios, methods[i].desc))
-				break;
+		mthd = shadow_methods;
+		do {
+			if (strcasecmp(nouveau_vbios, mthd->desc))
+				continue;
+			NV_INFO(dev, "VBIOS source: %s\n", mthd->desc);
 
-		if (i < NUM_SHADOW_METHODS) {
-			NV_INFO(dev, "Attempting to use BIOS image from %s\n",
-				methods[i].desc);
-
-			methods[i].loadbios(dev, data);
-			if (score_vbios(dev, data, methods[i].rw))
+			mthd->shadow(bios);
+			mthd->score = score_vbios(bios, mthd->rw);
+			if (mthd->score)
 				return true;
-		}
+		} while ((++mthd)->shadow);
 
 		NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios);
 	}
 
-	for (i = 0; i < NUM_SHADOW_METHODS; i++) {
-		NV_TRACE(dev, "Attempting to load BIOS image from %s\n",
-			 methods[i].desc);
-		data[0] = data[1] = 0;	/* avoid reuse of previous image */
-		methods[i].loadbios(dev, data);
-		scores[i] = score_vbios(dev, data, methods[i].rw);
-		if (scores[i] == testscore)
-			return true;
-	}
+	mthd = shadow_methods;
+	do {
+		NV_TRACE(dev, "Checking %s for VBIOS\n", mthd->desc);
+		mthd->shadow(bios);
+		mthd->score = score_vbios(bios, mthd->rw);
+		mthd->size = bios->length;
+		mthd->data = bios->data;
+	} while (mthd->score != 3 && (++mthd)->shadow);
 
-	while (--testscore > 0) {
-		for (i = 0; i < NUM_SHADOW_METHODS; i++) {
-			if (scores[i] == testscore) {
-				NV_TRACE(dev, "Using BIOS image from %s\n",
-					 methods[i].desc);
-				methods[i].loadbios(dev, data);
-				return true;
-			}
+	mthd = shadow_methods;
+	best = mthd;
+	do {
+		if (mthd->score > best->score) {
+			kfree(best->data);
+			best = mthd;
 		}
+	} while ((++mthd)->shadow);
+
+	if (best->score) {
+		NV_TRACE(dev, "Using VBIOS from %s\n", best->desc);
+		bios->length = best->size;
+		bios->data = best->data;
+		return true;
 	}
 
-	NV_ERROR(dev, "No valid BIOS image found\n");
+	NV_ERROR(dev, "No valid VBIOS image found\n");
 	return false;
 }
 
@@ -1107,7 +1145,8 @@
 		break;
 	case 1:
 	case 2:
-		if (!(entry[5] & cond))
+		if ((table[0]  < 0x40 && !(entry[5] & cond)) ||
+		    (table[0] == 0x40 && !(entry[4] & cond)))
 			iexec->execute = false;
 		break;
 	case 5:
@@ -6334,11 +6373,7 @@
 	spin_lock_init(&bios->lock);
 	bios->dev = dev;
 
-	if (!NVShadowVBIOS(dev, bios->data))
-		return false;
-
-	bios->length = NV_PROM_SIZE;
-	return true;
+	return bios_shadow(dev);
 }
 
 static int nouveau_parse_vbios_struct(struct drm_device *dev)
@@ -6498,6 +6533,10 @@
 void
 nouveau_bios_takedown(struct drm_device *dev)
 {
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+
 	nouveau_mxm_fini(dev);
 	nouveau_i2c_fini(dev);
+
+	kfree(dev_priv->vbios.data);
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
index a37c31e..298a3af 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
@@ -69,12 +69,16 @@
 	DCB_CONNECTOR_TV_3 = 0x13,
 	DCB_CONNECTOR_DVI_I = 0x30,
 	DCB_CONNECTOR_DVI_D = 0x31,
+	DCB_CONNECTOR_DMS59_0 = 0x38,
+	DCB_CONNECTOR_DMS59_1 = 0x39,
 	DCB_CONNECTOR_LVDS = 0x40,
 	DCB_CONNECTOR_LVDS_SPWG = 0x41,
 	DCB_CONNECTOR_DP = 0x46,
 	DCB_CONNECTOR_eDP = 0x47,
 	DCB_CONNECTOR_HDMI_0 = 0x60,
 	DCB_CONNECTOR_HDMI_1 = 0x61,
+	DCB_CONNECTOR_DMS59_DP0 = 0x64,
+	DCB_CONNECTOR_DMS59_DP1 = 0x65,
 	DCB_CONNECTOR_NONE = 0xff
 };
 
@@ -209,6 +213,8 @@
 		NVBIOS_BIT
 	} type;
 	uint16_t offset;
+	uint32_t length;
+	uint8_t *data;
 
 	uint8_t chip_version;
 
@@ -219,8 +225,6 @@
 
 	spinlock_t lock;
 
-	uint8_t data[NV_PROM_SIZE];
-	unsigned int length;
 	bool execute;
 
 	uint8_t major_version;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index ec54364..7d15a77 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -693,16 +693,12 @@
 		     struct ttm_mem_reg *new_mem)
 {
 	struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
+	struct nouveau_channel *chan = chan = dev_priv->channel;
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
 	struct ttm_mem_reg *old_mem = &bo->mem;
-	struct nouveau_channel *chan;
 	int ret;
 
-	chan = nvbo->channel;
-	if (!chan) {
-		chan = dev_priv->channel;
-		mutex_lock_nested(&chan->mutex, NOUVEAU_KCHANNEL_MUTEX);
-	}
+	mutex_lock_nested(&chan->mutex, NOUVEAU_KCHANNEL_MUTEX);
 
 	/* create temporary vmas for the transfer and attach them to the
 	 * old nouveau_mem node, these will get cleaned up after ttm has
@@ -734,8 +730,7 @@
 	}
 
 out:
-	if (chan == dev_priv->channel)
-		mutex_unlock(&chan->mutex);
+	mutex_unlock(&chan->mutex);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
index a018def..846afb0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
@@ -122,7 +122,7 @@
 	struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv);
 	struct nouveau_channel *chan;
 	unsigned long flags;
-	int ret;
+	int ret, i;
 
 	/* allocate and lock channel structure */
 	chan = kzalloc(sizeof(*chan), GFP_KERNEL);
@@ -184,7 +184,7 @@
 		return ret;
 	}
 
-	nouveau_dma_pre_init(chan);
+	nouveau_dma_init(chan);
 	chan->user_put = 0x40;
 	chan->user_get = 0x44;
 	if (dev_priv->card_type >= NV_50)
@@ -202,9 +202,18 @@
 
 	pfifo->reassign(dev, true);
 
-	ret = nouveau_dma_init(chan);
-	if (!ret)
-		ret = nouveau_fence_channel_init(chan);
+	/* Insert NOPs for NOUVEAU_DMA_SKIPS */
+	ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
+	if (ret) {
+		nouveau_channel_put(&chan);
+		return ret;
+	}
+
+	for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
+		OUT_RING  (chan, 0x00000000);
+	FIRE_RING(chan);
+
+	ret = nouveau_fence_channel_init(chan);
 	if (ret) {
 		nouveau_channel_put(&chan);
 		return ret;
@@ -427,18 +436,11 @@
 	}
 
 	if (dev_priv->card_type < NV_C0) {
-		init->subchan[0].handle = NvM2MF;
-		if (dev_priv->card_type < NV_50)
-			init->subchan[0].grclass = 0x0039;
-		else
-			init->subchan[0].grclass = 0x5039;
+		init->subchan[0].handle = 0x00000000;
+		init->subchan[0].grclass = 0x0000;
 		init->subchan[1].handle = NvSw;
 		init->subchan[1].grclass = NV_SW;
 		init->nr_subchan = 2;
-	} else {
-		init->subchan[0].handle  = 0x9039;
-		init->subchan[0].grclass = 0x9039;
-		init->nr_subchan = 1;
 	}
 
 	/* Named memory object area */
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index f3ce34b..fa86035 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -519,6 +519,19 @@
 		return nv_crtc->set_dither(nv_crtc, true);
 	}
 
+	if (nv_crtc && nv_crtc->set_color_vibrance) {
+		/* Hue */
+		if (property == disp->vibrant_hue_property) {
+			nv_crtc->vibrant_hue = value - 90;
+			return nv_crtc->set_color_vibrance(nv_crtc, true);
+		}
+		/* Saturation */
+		if (property == disp->color_vibrance_property) {
+			nv_crtc->color_vibrance = value - 100;
+			return nv_crtc->set_color_vibrance(nv_crtc, true);
+		}
+	}
+
 	if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV)
 		return get_slave_funcs(encoder)->set_property(
 			encoder, connector, property, value);
@@ -641,10 +654,13 @@
 	if (nv_connector->edid && connector->display_info.bpc)
 		return;
 
-	/* if not, we're out of options unless we're LVDS, default to 6bpc */
-	connector->display_info.bpc = 6;
-	if (nv_encoder->dcb->type != OUTPUT_LVDS)
+	/* if not, we're out of options unless we're LVDS, default to 8bpc */
+	if (nv_encoder->dcb->type != OUTPUT_LVDS) {
+		connector->display_info.bpc = 8;
 		return;
+	}
+
+	connector->display_info.bpc = 6;
 
 	/* LVDS: panel straps */
 	if (bios->fp_no_ddc) {
@@ -854,10 +870,14 @@
 	case DCB_CONNECTOR_TV_0     :
 	case DCB_CONNECTOR_TV_1     :
 	case DCB_CONNECTOR_TV_3     : return DRM_MODE_CONNECTOR_TV;
+	case DCB_CONNECTOR_DMS59_0  :
+	case DCB_CONNECTOR_DMS59_1  :
 	case DCB_CONNECTOR_DVI_I    : return DRM_MODE_CONNECTOR_DVII;
 	case DCB_CONNECTOR_DVI_D    : return DRM_MODE_CONNECTOR_DVID;
 	case DCB_CONNECTOR_LVDS     :
 	case DCB_CONNECTOR_LVDS_SPWG: return DRM_MODE_CONNECTOR_LVDS;
+	case DCB_CONNECTOR_DMS59_DP0:
+	case DCB_CONNECTOR_DMS59_DP1:
 	case DCB_CONNECTOR_DP       : return DRM_MODE_CONNECTOR_DisplayPort;
 	case DCB_CONNECTOR_eDP      : return DRM_MODE_CONNECTOR_eDP;
 	case DCB_CONNECTOR_HDMI_0   :
@@ -998,11 +1018,10 @@
 
 	/* Add overscan compensation options to digital outputs */
 	if (disp->underscan_property &&
-	    (nv_connector->type == DCB_CONNECTOR_DVI_D ||
-	     nv_connector->type == DCB_CONNECTOR_DVI_I ||
-	     nv_connector->type == DCB_CONNECTOR_HDMI_0 ||
-	     nv_connector->type == DCB_CONNECTOR_HDMI_1 ||
-	     nv_connector->type == DCB_CONNECTOR_DP)) {
+	    (type == DRM_MODE_CONNECTOR_DVID ||
+	     type == DRM_MODE_CONNECTOR_DVII ||
+	     type == DRM_MODE_CONNECTOR_HDMIA ||
+	     type == DRM_MODE_CONNECTOR_DisplayPort)) {
 		drm_connector_attach_property(connector,
 					      disp->underscan_property,
 					      UNDERSCAN_OFF);
@@ -1014,6 +1033,16 @@
 					      0);
 	}
 
+	/* Add hue and saturation options */
+	if (disp->vibrant_hue_property)
+		drm_connector_attach_property(connector,
+					      disp->vibrant_hue_property,
+					      90);
+	if (disp->color_vibrance_property)
+		drm_connector_attach_property(connector,
+					      disp->color_vibrance_property,
+					      150);
+
 	switch (nv_connector->type) {
 	case DCB_CONNECTOR_VGA:
 		if (dev_priv->card_type >= NV_50) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h
index 686f6b4..e6d0d1e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_crtc.h
+++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h
@@ -35,6 +35,8 @@
 	uint32_t dpms_saved_fp_control;
 	uint32_t fp_users;
 	int saturation;
+	int color_vibrance;
+	int vibrant_hue;
 	int sharpness;
 	int last_dpms;
 
@@ -67,6 +69,7 @@
 
 	int (*set_dither)(struct nouveau_crtc *crtc, bool update);
 	int (*set_scale)(struct nouveau_crtc *crtc, bool update);
+	int (*set_color_vibrance)(struct nouveau_crtc *crtc, bool update);
 };
 
 static inline struct nouveau_crtc *nouveau_crtc(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 795a9e3..a85e112 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -155,20 +155,20 @@
 };
 
 
-struct drm_prop_enum_list {
+struct nouveau_drm_prop_enum_list {
 	u8 gen_mask;
 	int type;
 	char *name;
 };
 
-static struct drm_prop_enum_list underscan[] = {
+static struct nouveau_drm_prop_enum_list underscan[] = {
 	{ 6, UNDERSCAN_AUTO, "auto" },
 	{ 6, UNDERSCAN_OFF, "off" },
 	{ 6, UNDERSCAN_ON, "on" },
 	{}
 };
 
-static struct drm_prop_enum_list dither_mode[] = {
+static struct nouveau_drm_prop_enum_list dither_mode[] = {
 	{ 7, DITHERING_MODE_AUTO, "auto" },
 	{ 7, DITHERING_MODE_OFF, "off" },
 	{ 1, DITHERING_MODE_ON, "on" },
@@ -178,7 +178,7 @@
 	{}
 };
 
-static struct drm_prop_enum_list dither_depth[] = {
+static struct nouveau_drm_prop_enum_list dither_depth[] = {
 	{ 6, DITHERING_DEPTH_AUTO, "auto" },
 	{ 6, DITHERING_DEPTH_6BPC, "6 bpc" },
 	{ 6, DITHERING_DEPTH_8BPC, "8 bpc" },
@@ -186,7 +186,7 @@
 };
 
 #define PROP_ENUM(p,gen,n,list) do {                                           \
-	struct drm_prop_enum_list *l = (list);                                 \
+	struct nouveau_drm_prop_enum_list *l = (list);                         \
 	int c = 0;                                                             \
 	while (l->gen_mask) {                                                  \
 		if (l->gen_mask & (1 << (gen)))                                \
@@ -281,16 +281,24 @@
 	PROP_ENUM(disp->underscan_property, gen, "underscan", underscan);
 
 	disp->underscan_hborder_property =
-		drm_property_create(dev, DRM_MODE_PROP_RANGE,
-				    "underscan hborder", 2);
-	disp->underscan_hborder_property->values[0] = 0;
-	disp->underscan_hborder_property->values[1] = 128;
+		drm_property_create_range(dev, 0, "underscan hborder", 0, 128);
 
 	disp->underscan_vborder_property =
-		drm_property_create(dev, DRM_MODE_PROP_RANGE,
-				    "underscan vborder", 2);
-	disp->underscan_vborder_property->values[0] = 0;
-	disp->underscan_vborder_property->values[1] = 128;
+		drm_property_create_range(dev, 0, "underscan vborder", 0, 128);
+
+	if (gen == 1) {
+		disp->vibrant_hue_property =
+			drm_property_create(dev, DRM_MODE_PROP_RANGE,
+					    "vibrant hue", 2);
+		disp->vibrant_hue_property->values[0] = 0;
+		disp->vibrant_hue_property->values[1] = 180; /* -90..+90 */
+
+		disp->color_vibrance_property =
+			drm_property_create(dev, DRM_MODE_PROP_RANGE,
+					    "color vibrance", 2);
+		disp->color_vibrance_property->values[0] = 0;
+		disp->color_vibrance_property->values[1] = 200; /* -100..+100 */
+	}
 
 	dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs;
 	dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1);
@@ -309,6 +317,9 @@
 		dev->mode_config.max_height = 8192;
 	}
 
+	dev->mode_config.preferred_depth = 24;
+	dev->mode_config.prefer_shadow = 1;
+
 	drm_kms_helper_poll_init(dev);
 	drm_kms_helper_poll_disable(dev);
 
@@ -430,15 +441,19 @@
 		goto fail;
 
 	/* Emit the pageflip */
-	ret = RING_SPACE(chan, 2);
+	ret = RING_SPACE(chan, 3);
 	if (ret)
 		goto fail;
 
-	if (dev_priv->card_type < NV_C0)
+	if (dev_priv->card_type < NV_C0) {
 		BEGIN_RING(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
-	else
-		BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0500, 1);
-	OUT_RING  (chan, 0);
+		OUT_RING  (chan, 0x00000000);
+		OUT_RING  (chan, 0x00000000);
+	} else {
+		BEGIN_NVC0(chan, 2, 0, NV10_SUBCHAN_REF_CNT, 1);
+		OUT_RING  (chan, ++chan->fence.sequence);
+		BEGIN_NVC0(chan, 8, 0, NVSW_SUBCHAN_PAGE_FLIP, 0x0000);
+	}
 	FIRE_RING (chan);
 
 	ret = nouveau_fence_new(chan, pfence, true);
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c
index 4c2e4e5..295932e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.c
@@ -31,7 +31,7 @@
 #include "nouveau_ramht.h"
 
 void
-nouveau_dma_pre_init(struct nouveau_channel *chan)
+nouveau_dma_init(struct nouveau_channel *chan)
 {
 	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
 	struct nouveau_bo *pushbuf = chan->pushbuf_bo;
@@ -54,65 +54,6 @@
 	chan->dma.free = chan->dma.max - chan->dma.cur;
 }
 
-int
-nouveau_dma_init(struct nouveau_channel *chan)
-{
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	int ret, i;
-
-	if (dev_priv->card_type >= NV_C0) {
-		ret = nouveau_gpuobj_gr_new(chan, 0x9039, 0x9039);
-		if (ret)
-			return ret;
-
-		ret = RING_SPACE(chan, 2);
-		if (ret)
-			return ret;
-
-		BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0000, 1);
-		OUT_RING  (chan, 0x00009039);
-		FIRE_RING (chan);
-		return 0;
-	}
-
-	/* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */
-	ret = nouveau_gpuobj_gr_new(chan, NvM2MF, dev_priv->card_type < NV_50 ?
-				    0x0039 : 0x5039);
-	if (ret)
-		return ret;
-
-	/* NV_MEMORY_TO_MEMORY_FORMAT requires a notifier object */
-	ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000,
-				     &chan->m2mf_ntfy);
-	if (ret)
-		return ret;
-
-	/* Insert NOPS for NOUVEAU_DMA_SKIPS */
-	ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
-	if (ret)
-		return ret;
-
-	for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
-		OUT_RING(chan, 0);
-
-	/* Initialise NV_MEMORY_TO_MEMORY_FORMAT */
-	ret = RING_SPACE(chan, 6);
-	if (ret)
-		return ret;
-	BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NAME, 1);
-	OUT_RING  (chan, NvM2MF);
-	BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 3);
-	OUT_RING  (chan, NvNotify0);
-	OUT_RING  (chan, chan->vram_handle);
-	OUT_RING  (chan, chan->gart_handle);
-
-	/* Sit back and pray the channel works.. */
-	FIRE_RING(chan);
-
-	return 0;
-}
-
 void
 OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned nr_dwords)
 {
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 9b93b70..d996134 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -161,116 +161,6 @@
 	return ret;
 }
 
-static u32
-dp_link_bw_get(struct drm_device *dev, int or, int link)
-{
-	u32 ctrl = nv_rd32(dev, 0x614300 + (or * 0x800));
-	if (!(ctrl & 0x000c0000))
-		return 162000;
-	return 270000;
-}
-
-static int
-dp_lane_count_get(struct drm_device *dev, int or, int link)
-{
-	u32 ctrl = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
-	switch (ctrl & 0x000f0000) {
-	case 0x00010000: return 1;
-	case 0x00030000: return 2;
-	default:
-		return 4;
-	}
-}
-
-void
-nouveau_dp_tu_update(struct drm_device *dev, int or, int link, u32 clk, u32 bpp)
-{
-	const u32 symbol = 100000;
-	int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
-	int TU, VTUi, VTUf, VTUa;
-	u64 link_data_rate, link_ratio, unk;
-	u32 best_diff = 64 * symbol;
-	u32 link_nr, link_bw, r;
-
-	/* calculate packed data rate for each lane */
-	link_nr = dp_lane_count_get(dev, or, link);
-	link_data_rate = (clk * bpp / 8) / link_nr;
-
-	/* calculate ratio of packed data rate to link symbol rate */
-	link_bw = dp_link_bw_get(dev, or, link);
-	link_ratio = link_data_rate * symbol;
-	r = do_div(link_ratio, link_bw);
-
-	for (TU = 64; TU >= 32; TU--) {
-		/* calculate average number of valid symbols in each TU */
-		u32 tu_valid = link_ratio * TU;
-		u32 calc, diff;
-
-		/* find a hw representation for the fraction.. */
-		VTUi = tu_valid / symbol;
-		calc = VTUi * symbol;
-		diff = tu_valid - calc;
-		if (diff) {
-			if (diff >= (symbol / 2)) {
-				VTUf = symbol / (symbol - diff);
-				if (symbol - (VTUf * diff))
-					VTUf++;
-
-				if (VTUf <= 15) {
-					VTUa  = 1;
-					calc += symbol - (symbol / VTUf);
-				} else {
-					VTUa  = 0;
-					VTUf  = 1;
-					calc += symbol;
-				}
-			} else {
-				VTUa  = 0;
-				VTUf  = min((int)(symbol / diff), 15);
-				calc += symbol / VTUf;
-			}
-
-			diff = calc - tu_valid;
-		} else {
-			/* no remainder, but the hw doesn't like the fractional
-			 * part to be zero.  decrement the integer part and
-			 * have the fraction add a whole symbol back
-			 */
-			VTUa = 0;
-			VTUf = 1;
-			VTUi--;
-		}
-
-		if (diff < best_diff) {
-			best_diff = diff;
-			bestTU = TU;
-			bestVTUa = VTUa;
-			bestVTUf = VTUf;
-			bestVTUi = VTUi;
-			if (diff == 0)
-				break;
-		}
-	}
-
-	if (!bestTU) {
-		NV_ERROR(dev, "DP: unable to find suitable config\n");
-		return;
-	}
-
-	/* XXX close to vbios numbers, but not right */
-	unk  = (symbol - link_ratio) * bestTU;
-	unk *= link_ratio;
-	r = do_div(unk, symbol);
-	r = do_div(unk, symbol);
-	unk += 6;
-
-	nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x000001fc, bestTU << 2);
-	nv_mask(dev, NV50_SOR_DP_SCFG(or, link), 0x010f7f3f, bestVTUa << 24 |
-							     bestVTUf << 16 |
-							     bestVTUi << 8 |
-							     unk);
-}
-
 u8 *
 nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry)
 {
@@ -298,6 +188,7 @@
 	case 0x20:
 	case 0x21:
 	case 0x30:
+	case 0x40:
 		break;
 	default:
 		NV_ERROR(dev, "displayport table 0x%02x unknown\n", table[0]);
@@ -318,13 +209,10 @@
  * link training
  *****************************************************************************/
 struct dp_state {
+	struct dp_train_func *func;
 	struct dcb_entry *dcb;
-	u8 *table;
-	u8 *entry;
 	int auxch;
 	int crtc;
-	int or;
-	int link;
 	u8 *dpcd;
 	int link_nr;
 	u32 link_bw;
@@ -335,142 +223,58 @@
 static void
 dp_set_link_config(struct drm_device *dev, struct dp_state *dp)
 {
-	int or = dp->or, link = dp->link;
-	u8 *entry, sink[2];
-	u32 dp_ctrl;
-	u16 script;
+	u8 sink[2];
 
 	NV_DEBUG_KMS(dev, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
 
-	/* set selected link rate on source */
-	switch (dp->link_bw) {
-	case 270000:
-		nv_mask(dev, 0x614300 + (or * 0x800), 0x000c0000, 0x00040000);
-		sink[0] = DP_LINK_BW_2_7;
-		break;
-	default:
-		nv_mask(dev, 0x614300 + (or * 0x800), 0x000c0000, 0x00000000);
-		sink[0] = DP_LINK_BW_1_62;
-		break;
-	}
-
-	/* offset +0x0a of each dp encoder table entry is a pointer to another
-	 * table, that has (among other things) pointers to more scripts that
-	 * need to be executed, this time depending on link speed.
-	 */
-	entry = ROMPTR(dev, dp->entry[10]);
-	if (entry) {
-		if (dp->table[0] < 0x30) {
-			while (dp->link_bw < (ROM16(entry[0]) * 10))
-				entry += 4;
-			script = ROM16(entry[2]);
-		} else {
-			while (dp->link_bw < (entry[0] * 27000))
-				entry += 3;
-			script = ROM16(entry[1]);
-		}
-
-		nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
-	}
-
-	/* configure lane count on the source */
-	dp_ctrl = ((1 << dp->link_nr) - 1) << 16;
-	sink[1] = dp->link_nr;
-	if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP) {
-		dp_ctrl |= 0x00004000;
-		sink[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
-	}
-
-	nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x001f4000, dp_ctrl);
+	/* set desired link configuration on the source */
+	dp->func->link_set(dev, dp->dcb, dp->crtc, dp->link_nr, dp->link_bw,
+			   dp->dpcd[2] & DP_ENHANCED_FRAME_CAP);
 
 	/* inform the sink of the new configuration */
+	sink[0] = dp->link_bw / 27000;
+	sink[1] = dp->link_nr;
+	if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP)
+		sink[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+
 	auxch_tx(dev, dp->auxch, 8, DP_LINK_BW_SET, sink, 2);
 }
 
 static void
-dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 tp)
+dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 pattern)
 {
 	u8 sink_tp;
 
-	NV_DEBUG_KMS(dev, "training pattern %d\n", tp);
+	NV_DEBUG_KMS(dev, "training pattern %d\n", pattern);
 
-	nv_mask(dev, NV50_SOR_DP_CTRL(dp->or, dp->link), 0x0f000000, tp << 24);
+	dp->func->train_set(dev, dp->dcb, pattern);
 
 	auxch_tx(dev, dp->auxch, 9, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
 	sink_tp &= ~DP_TRAINING_PATTERN_MASK;
-	sink_tp |= tp;
+	sink_tp |= pattern;
 	auxch_tx(dev, dp->auxch, 8, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
 }
 
-static const u8 nv50_lane_map[] = { 16, 8, 0, 24 };
-static const u8 nvaf_lane_map[] = { 24, 16, 8, 0 };
-
 static int
 dp_link_train_commit(struct drm_device *dev, struct dp_state *dp)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	u32 mask = 0, drv = 0, pre = 0, unk = 0;
-	const u8 *shifts;
-	int link = dp->link;
-	int or = dp->or;
 	int i;
 
-	if (dev_priv->chipset != 0xaf)
-		shifts = nv50_lane_map;
-	else
-		shifts = nvaf_lane_map;
-
 	for (i = 0; i < dp->link_nr; i++) {
-		u8 *conf = dp->entry + dp->table[4];
 		u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
 		u8 lpre = (lane & 0x0c) >> 2;
 		u8 lvsw = (lane & 0x03) >> 0;
 
-		mask |= 0xff << shifts[i];
-		unk |= 1 << (shifts[i] >> 3);
-
 		dp->conf[i] = (lpre << 3) | lvsw;
 		if (lvsw == DP_TRAIN_VOLTAGE_SWING_1200)
 			dp->conf[i] |= DP_TRAIN_MAX_SWING_REACHED;
-		if (lpre == DP_TRAIN_PRE_EMPHASIS_9_5)
+		if ((lpre << 3) == DP_TRAIN_PRE_EMPHASIS_9_5)
 			dp->conf[i] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
 
 		NV_DEBUG_KMS(dev, "config lane %d %02x\n", i, dp->conf[i]);
-
-		if (dp->table[0] < 0x30) {
-			u8 *last = conf + (dp->entry[4] * dp->table[5]);
-			while (lvsw != conf[0] || lpre != conf[1]) {
-				conf += dp->table[5];
-				if (conf >= last)
-					return -EINVAL;
-			}
-
-			conf += 2;
-		} else {
-			/* no lookup table anymore, set entries for each
-			 * combination of voltage swing and pre-emphasis
-			 * level allowed by the DP spec.
-			 */
-			switch (lvsw) {
-			case 0: lpre += 0; break;
-			case 1: lpre += 4; break;
-			case 2: lpre += 7; break;
-			case 3: lpre += 9; break;
-			}
-
-			conf = conf + (lpre * dp->table[5]);
-			conf++;
-		}
-
-		drv |= conf[0] << shifts[i];
-		pre |= conf[1] << shifts[i];
-		unk  = (unk & ~0x0000ff00) | (conf[2] << 8);
+		dp->func->train_adj(dev, dp->dcb, i, lvsw, lpre);
 	}
 
-	nv_mask(dev, NV50_SOR_DP_UNK118(or, link), mask, drv);
-	nv_mask(dev, NV50_SOR_DP_UNK120(or, link), mask, pre);
-	nv_mask(dev, NV50_SOR_DP_UNK130(or, link), 0x0000ff0f, unk);
-
 	return auxch_tx(dev, dp->auxch, 8, DP_TRAINING_LANE0_SET, dp->conf, 4);
 }
 
@@ -554,8 +358,60 @@
 	return eq_done ? 0 : -1;
 }
 
+static void
+dp_set_downspread(struct drm_device *dev, struct dp_state *dp, bool enable)
+{
+	u16 script = 0x0000;
+	u8 *entry, *table = nouveau_dp_bios_data(dev, dp->dcb, &entry);
+	if (table) {
+		if (table[0] >= 0x20 && table[0] <= 0x30) {
+			if (enable) script = ROM16(entry[12]);
+			else        script = ROM16(entry[14]);
+		} else
+		if (table[0] == 0x40) {
+			if (enable) script = ROM16(entry[11]);
+			else        script = ROM16(entry[13]);
+		}
+	}
+
+	nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
+}
+
+static void
+dp_link_train_init(struct drm_device *dev, struct dp_state *dp)
+{
+	u16 script = 0x0000;
+	u8 *entry, *table = nouveau_dp_bios_data(dev, dp->dcb, &entry);
+	if (table) {
+		if (table[0] >= 0x20 && table[0] <= 0x30)
+			script = ROM16(entry[6]);
+		else
+		if (table[0] == 0x40)
+			script = ROM16(entry[5]);
+	}
+
+	nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
+}
+
+static void
+dp_link_train_fini(struct drm_device *dev, struct dp_state *dp)
+{
+	u16 script = 0x0000;
+	u8 *entry, *table = nouveau_dp_bios_data(dev, dp->dcb, &entry);
+	if (table) {
+		if (table[0] >= 0x20 && table[0] <= 0x30)
+			script = ROM16(entry[8]);
+		else
+		if (table[0] == 0x40)
+			script = ROM16(entry[7]);
+	}
+
+	nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
+}
+
 bool
-nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate)
+nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate,
+		      struct dp_train_func *func)
 {
 	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
@@ -571,17 +427,15 @@
 	if (!auxch)
 		return false;
 
-	dp.table = nouveau_dp_bios_data(dev, nv_encoder->dcb, &dp.entry);
-	if (!dp.table)
-		return -EINVAL;
-
+	dp.func = func;
 	dp.dcb = nv_encoder->dcb;
 	dp.crtc = nv_crtc->index;
 	dp.auxch = auxch->drive;
-	dp.or = nv_encoder->or;
-	dp.link = !(nv_encoder->dcb->sorconf.link & 1);
 	dp.dpcd = nv_encoder->dp.dpcd;
 
+	/* adjust required bandwidth for 8B/10B coding overhead */
+	datarate = (datarate / 8) * 10;
+
 	/* some sinks toggle hotplug in response to some of the actions
 	 * we take during link training (DP_SET_POWER is one), we need
 	 * to ignore them for the moment to avoid races.
@@ -589,16 +443,10 @@
 	nouveau_gpio_irq(dev, 0, nv_connector->hpd, 0xff, false);
 
 	/* enable down-spreading, if possible */
-	if (dp.table[1] >= 16) {
-		u16 script = ROM16(dp.entry[14]);
-		if (nv_encoder->dp.dpcd[3] & 1)
-			script = ROM16(dp.entry[12]);
-
-		nouveau_bios_run_init_table(dev, script, dp.dcb, dp.crtc);
-	}
+	dp_set_downspread(dev, &dp, nv_encoder->dp.dpcd[3] & 1);
 
 	/* execute pre-train script from vbios */
-	nouveau_bios_run_init_table(dev, ROM16(dp.entry[6]), dp.dcb, dp.crtc);
+	dp_link_train_init(dev, &dp);
 
 	/* start off at highest link rate supported by encoder and display */
 	while (*link_bw > nv_encoder->dp.link_bw)
@@ -632,13 +480,36 @@
 	dp_set_training_pattern(dev, &dp, DP_TRAINING_PATTERN_DISABLE);
 
 	/* execute post-train script from vbios */
-	nouveau_bios_run_init_table(dev, ROM16(dp.entry[8]), dp.dcb, dp.crtc);
+	dp_link_train_fini(dev, &dp);
 
 	/* re-enable hotplug detect */
 	nouveau_gpio_irq(dev, 0, nv_connector->hpd, 0xff, true);
 	return true;
 }
 
+void
+nouveau_dp_dpms(struct drm_encoder *encoder, int mode, u32 datarate,
+		struct dp_train_func *func)
+{
+	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+	struct nouveau_i2c_chan *auxch;
+	u8 status;
+
+	auxch = nouveau_i2c_find(encoder->dev, nv_encoder->dcb->i2c_index);
+	if (!auxch)
+		return;
+
+	if (mode == DRM_MODE_DPMS_ON)
+		status = DP_SET_POWER_D0;
+	else
+		status = DP_SET_POWER_D3;
+
+	nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
+
+	if (mode == DRM_MODE_DPMS_ON)
+		nouveau_dp_link_train(encoder, datarate, func);
+}
+
 bool
 nouveau_dp_detect(struct drm_encoder *encoder)
 {
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 81d7962..4f2030b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -57,6 +57,10 @@
 int nouveau_vram_notify = 0;
 module_param_named(vram_notify, nouveau_vram_notify, int, 0400);
 
+MODULE_PARM_DESC(vram_type, "Override detected VRAM type");
+char *nouveau_vram_type;
+module_param_named(vram_type, nouveau_vram_type, charp, 0400);
+
 MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (>=GeForce 8)");
 int nouveau_duallink = 1;
 module_param_named(duallink, nouveau_duallink, int, 0400);
@@ -89,7 +93,7 @@
 int nouveau_override_conntype = 0;
 module_param_named(override_conntype, nouveau_override_conntype, int, 0400);
 
-MODULE_PARM_DESC(tv_disable, "Disable TV-out detection\n");
+MODULE_PARM_DESC(tv_disable, "Disable TV-out detection");
 int nouveau_tv_disable = 0;
 module_param_named(tv_disable, nouveau_tv_disable, int, 0400);
 
@@ -104,27 +108,27 @@
 MODULE_PARM_DESC(reg_debug, "Register access debug bitmask:\n"
 		"\t\t0x1 mc, 0x2 video, 0x4 fb, 0x8 extdev,\n"
 		"\t\t0x10 crtc, 0x20 ramdac, 0x40 vgacrtc, 0x80 rmvio,\n"
-		"\t\t0x100 vgaattr, 0x200 EVO (G80+). ");
+		"\t\t0x100 vgaattr, 0x200 EVO (G80+)");
 int nouveau_reg_debug;
 module_param_named(reg_debug, nouveau_reg_debug, int, 0600);
 
-MODULE_PARM_DESC(perflvl, "Performance level (default: boot)\n");
+MODULE_PARM_DESC(perflvl, "Performance level (default: boot)");
 char *nouveau_perflvl;
 module_param_named(perflvl, nouveau_perflvl, charp, 0400);
 
-MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)\n");
+MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)");
 int nouveau_perflvl_wr;
 module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400);
 
-MODULE_PARM_DESC(msi, "Enable MSI (default: off)\n");
+MODULE_PARM_DESC(msi, "Enable MSI (default: off)");
 int nouveau_msi;
 module_param_named(msi, nouveau_msi, int, 0400);
 
-MODULE_PARM_DESC(ctxfw, "Use external HUB/GPC ucode (fermi)\n");
+MODULE_PARM_DESC(ctxfw, "Use external HUB/GPC ucode (fermi)");
 int nouveau_ctxfw;
 module_param_named(ctxfw, nouveau_ctxfw, int, 0400);
 
-MODULE_PARM_DESC(mxmdcb, "Santise DCB table according to MXM-SIS\n");
+MODULE_PARM_DESC(mxmdcb, "Santise DCB table according to MXM-SIS");
 int nouveau_mxmdcb = 1;
 module_param_named(mxmdcb, nouveau_mxmdcb, int, 0400);
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index b827098..3aef353 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -26,15 +26,15 @@
 #define __NOUVEAU_DRV_H__
 
 #define DRIVER_AUTHOR		"Stephane Marchesin"
-#define DRIVER_EMAIL		"dri-devel@lists.sourceforge.net"
+#define DRIVER_EMAIL		"nouveau@lists.freedesktop.org"
 
 #define DRIVER_NAME		"nouveau"
 #define DRIVER_DESC		"nVidia Riva/TNT/GeForce"
-#define DRIVER_DATE		"20090420"
+#define DRIVER_DATE		"20120316"
 
-#define DRIVER_MAJOR		0
+#define DRIVER_MAJOR		1
 #define DRIVER_MINOR		0
-#define DRIVER_PATCHLEVEL	16
+#define DRIVER_PATCHLEVEL	0
 
 #define NOUVEAU_FAMILY   0x0000FFFF
 #define NOUVEAU_FLAGS    0xFFFF0000
@@ -113,8 +113,6 @@
 	int pbbo_index;
 	bool validate_mapped;
 
-	struct nouveau_channel *channel;
-
 	struct list_head vma_list;
 	unsigned page_shift;
 
@@ -296,7 +294,7 @@
 
 	uint32_t sw_subchannel[8];
 
-	struct nouveau_vma dispc_vma[2];
+	struct nouveau_vma dispc_vma[4];
 	struct {
 		struct nouveau_gpuobj *vblsem;
 		uint32_t vblsem_head;
@@ -406,6 +404,9 @@
 	struct drm_property *underscan_property;
 	struct drm_property *underscan_hborder_property;
 	struct drm_property *underscan_vborder_property;
+	/* not really hue and saturation: */
+	struct drm_property *vibrant_hue_property;
+	struct drm_property *color_vibrance_property;
 };
 
 struct nouveau_gpio_engine {
@@ -432,58 +433,85 @@
 	int nr_level;
 };
 
+/* Exclusive upper limits */
+#define NV_MEM_CL_DDR2_MAX 8
+#define NV_MEM_WR_DDR2_MAX 9
+#define NV_MEM_CL_DDR3_MAX 17
+#define NV_MEM_WR_DDR3_MAX 17
+#define NV_MEM_CL_GDDR3_MAX 16
+#define NV_MEM_WR_GDDR3_MAX 18
+#define NV_MEM_CL_GDDR5_MAX 21
+#define NV_MEM_WR_GDDR5_MAX 20
+
 struct nouveau_pm_memtiming {
 	int id;
-	u32 reg_0; /* 0x10f290 on Fermi, 0x100220 for older */
-	u32 reg_1;
-	u32 reg_2;
-	u32 reg_3;
-	u32 reg_4;
-	u32 reg_5;
-	u32 reg_6;
-	u32 reg_7;
-	u32 reg_8;
-	/* To be written to 0x1002c0 */
-	u8 CL;
-	u8 WR;
+
+	u32 reg[9];
+	u32 mr[4];
+
+	u8 tCWL;
+
+	u8 odt;
+	u8 drive_strength;
 };
 
-struct nouveau_pm_tbl_header{
+struct nouveau_pm_tbl_header {
 	u8 version;
 	u8 header_len;
 	u8 entry_cnt;
 	u8 entry_len;
 };
 
-struct nouveau_pm_tbl_entry{
+struct nouveau_pm_tbl_entry {
 	u8 tWR;
-	u8 tUNK_1;
+	u8 tWTR;
 	u8 tCL;
-	u8 tRP;		/* Byte 3 */
+	u8 tRC;
 	u8 empty_4;
-	u8 tRAS;	/* Byte 5 */
+	u8 tRFC;	/* Byte 5 */
 	u8 empty_6;
-	u8 tRFC;	/* Byte 7 */
+	u8 tRAS;	/* Byte 7 */
 	u8 empty_8;
-	u8 tRC;		/* Byte 9 */
-	u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14;
-	u8 empty_15,empty_16,empty_17;
-	u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21;
+	u8 tRP;		/* Byte 9 */
+	u8 tRCDRD;
+	u8 tRCDWR;
+	u8 tRRD;
+	u8 tUNK_13;
+	u8 RAM_FT1;		/* 14, a bitmask of random RAM features */
+	u8 empty_15;
+	u8 tUNK_16;
+	u8 empty_17;
+	u8 tUNK_18;
+	u8 tCWL;
+	u8 tUNK_20, tUNK_21;
 };
 
-/* nouveau_mem.c */
-void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
-							struct nouveau_pm_tbl_entry *e, uint8_t magic_number,
-							struct nouveau_pm_memtiming *timing);
+struct nouveau_pm_profile;
+struct nouveau_pm_profile_func {
+	void (*destroy)(struct nouveau_pm_profile *);
+	void (*init)(struct nouveau_pm_profile *);
+	void (*fini)(struct nouveau_pm_profile *);
+	struct nouveau_pm_level *(*select)(struct nouveau_pm_profile *);
+};
+
+struct nouveau_pm_profile {
+	const struct nouveau_pm_profile_func *func;
+	struct list_head head;
+	char name[8];
+};
 
 #define NOUVEAU_PM_MAX_LEVEL 8
 struct nouveau_pm_level {
+	struct nouveau_pm_profile profile;
 	struct device_attribute dev_attr;
 	char name[32];
 	int id;
 
-	u32 core;
+	struct nouveau_pm_memtiming timing;
 	u32 memory;
+	u16 memscript;
+
+	u32 core;
 	u32 shader;
 	u32 rop;
 	u32 copy;
@@ -498,9 +526,6 @@
 	u32 volt_min; /* microvolts */
 	u32 volt_max;
 	u8  fanspeed;
-
-	u16 memscript;
-	struct nouveau_pm_memtiming *timing;
 };
 
 struct nouveau_pm_temp_sensor_constants {
@@ -517,27 +542,26 @@
 	s16 fan_boost;
 };
 
-struct nouveau_pm_memtimings {
-	bool supported;
-	struct nouveau_pm_memtiming *timing;
-	int nr_timing;
-};
-
 struct nouveau_pm_fan {
+	u32 percent;
 	u32 min_duty;
 	u32 max_duty;
 	u32 pwm_freq;
+	u32 pwm_divisor;
 };
 
 struct nouveau_pm_engine {
 	struct nouveau_pm_voltage voltage;
 	struct nouveau_pm_level perflvl[NOUVEAU_PM_MAX_LEVEL];
 	int nr_perflvl;
-	struct nouveau_pm_memtimings memtimings;
 	struct nouveau_pm_temp_sensor_constants sensor_constants;
 	struct nouveau_pm_threshold_temp threshold_temp;
 	struct nouveau_pm_fan fan;
-	u32 pwm_divisor;
+
+	struct nouveau_pm_profile *profile_ac;
+	struct nouveau_pm_profile *profile_dc;
+	struct nouveau_pm_profile *profile;
+	struct list_head profiles;
 
 	struct nouveau_pm_level boot;
 	struct nouveau_pm_level *cur;
@@ -669,14 +693,15 @@
 };
 
 enum nouveau_card_type {
-	NV_04      = 0x00,
+	NV_04      = 0x04,
 	NV_10      = 0x10,
 	NV_20      = 0x20,
 	NV_30      = 0x30,
 	NV_40      = 0x40,
 	NV_50      = 0x50,
 	NV_C0      = 0xc0,
-	NV_D0      = 0xd0
+	NV_D0      = 0xd0,
+	NV_E0      = 0xe0,
 };
 
 struct drm_nouveau_private {
@@ -772,8 +797,22 @@
 	} tile;
 
 	/* VRAM/fb configuration */
+	enum {
+		NV_MEM_TYPE_UNKNOWN = 0,
+		NV_MEM_TYPE_STOLEN,
+		NV_MEM_TYPE_SGRAM,
+		NV_MEM_TYPE_SDRAM,
+		NV_MEM_TYPE_DDR1,
+		NV_MEM_TYPE_DDR2,
+		NV_MEM_TYPE_DDR3,
+		NV_MEM_TYPE_GDDR2,
+		NV_MEM_TYPE_GDDR3,
+		NV_MEM_TYPE_GDDR4,
+		NV_MEM_TYPE_GDDR5
+	} vram_type;
 	uint64_t vram_size;
 	uint64_t vram_sys_base;
+	bool vram_rank_B;
 
 	uint64_t fb_available_size;
 	uint64_t fb_mappable_pages;
@@ -846,6 +885,7 @@
 extern int nouveau_uscript_tmds;
 extern int nouveau_vram_pushbuf;
 extern int nouveau_vram_notify;
+extern char *nouveau_vram_type;
 extern int nouveau_fbpercrtc;
 extern int nouveau_tv_disable;
 extern char *nouveau_tv_norm;
@@ -894,8 +934,12 @@
 extern int  nouveau_mem_init_agp(struct drm_device *);
 extern int  nouveau_mem_reset_agp(struct drm_device *);
 extern void nouveau_mem_close(struct drm_device *);
-extern int  nouveau_mem_detect(struct drm_device *);
 extern bool nouveau_mem_flags_valid(struct drm_device *, u32 tile_flags);
+extern int  nouveau_mem_timing_calc(struct drm_device *, u32 freq,
+				    struct nouveau_pm_memtiming *);
+extern void nouveau_mem_timing_read(struct drm_device *,
+				    struct nouveau_pm_memtiming *);
+extern int nouveau_mem_vbios_type(struct drm_device *);
 extern struct nouveau_tile_reg *nv10_mem_set_tiling(
 	struct drm_device *dev, uint32_t addr, uint32_t size,
 	uint32_t pitch, uint32_t flags);
@@ -1046,8 +1090,7 @@
 #endif
 
 /* nouveau_dma.c */
-extern void nouveau_dma_pre_init(struct nouveau_channel *);
-extern int  nouveau_dma_init(struct nouveau_channel *);
+extern void nouveau_dma_init(struct nouveau_channel *);
 extern int  nouveau_dma_wait(struct nouveau_channel *, int slots, int size);
 
 /* nouveau_acpi.c */
@@ -1117,19 +1160,14 @@
 /* nouveau_hdmi.c */
 void nouveau_hdmi_mode_set(struct drm_encoder *, struct drm_display_mode *);
 
-/* nouveau_dp.c */
-int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
-		     uint8_t *data, int data_nr);
-bool nouveau_dp_detect(struct drm_encoder *);
-bool nouveau_dp_link_train(struct drm_encoder *, u32 datarate);
-void nouveau_dp_tu_update(struct drm_device *, int, int, u32, u32);
-u8 *nouveau_dp_bios_data(struct drm_device *, struct dcb_entry *, u8 **);
-
 /* nv04_fb.c */
+extern int  nv04_fb_vram_init(struct drm_device *);
 extern int  nv04_fb_init(struct drm_device *);
 extern void nv04_fb_takedown(struct drm_device *);
 
 /* nv10_fb.c */
+extern int  nv10_fb_vram_init(struct drm_device *dev);
+extern int  nv1a_fb_vram_init(struct drm_device *dev);
 extern int  nv10_fb_init(struct drm_device *);
 extern void nv10_fb_takedown(struct drm_device *);
 extern void nv10_fb_init_tile_region(struct drm_device *dev, int i,
@@ -1138,6 +1176,16 @@
 extern void nv10_fb_set_tile_region(struct drm_device *dev, int i);
 extern void nv10_fb_free_tile_region(struct drm_device *dev, int i);
 
+/* nv20_fb.c */
+extern int  nv20_fb_vram_init(struct drm_device *dev);
+extern int  nv20_fb_init(struct drm_device *);
+extern void nv20_fb_takedown(struct drm_device *);
+extern void nv20_fb_init_tile_region(struct drm_device *dev, int i,
+				     uint32_t addr, uint32_t size,
+				     uint32_t pitch, uint32_t flags);
+extern void nv20_fb_set_tile_region(struct drm_device *dev, int i);
+extern void nv20_fb_free_tile_region(struct drm_device *dev, int i);
+
 /* nv30_fb.c */
 extern int  nv30_fb_init(struct drm_device *);
 extern void nv30_fb_takedown(struct drm_device *);
@@ -1147,6 +1195,7 @@
 extern void nv30_fb_free_tile_region(struct drm_device *dev, int i);
 
 /* nv40_fb.c */
+extern int  nv40_fb_vram_init(struct drm_device *dev);
 extern int  nv40_fb_init(struct drm_device *);
 extern void nv40_fb_takedown(struct drm_device *);
 extern void nv40_fb_set_tile_region(struct drm_device *dev, int i);
@@ -1703,6 +1752,7 @@
 #define NV_MEM_ACCESS_RW (NV_MEM_ACCESS_RO | NV_MEM_ACCESS_WO)
 #define NV_MEM_ACCESS_SYS 4
 #define NV_MEM_ACCESS_VM  8
+#define NV_MEM_ACCESS_NOSNOOP 16
 
 #define NV_MEM_TARGET_VRAM        0
 #define NV_MEM_TARGET_PCI         1
@@ -1713,13 +1763,27 @@
 #define NV_MEM_TYPE_VM 0x7f
 #define NV_MEM_COMP_VM 0x03
 
+/* FIFO methods */
+#define NV01_SUBCHAN_OBJECT                                          0x00000000
+#define NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH                          0x00000010
+#define NV84_SUBCHAN_SEMAPHORE_ADDRESS_LOW                           0x00000014
+#define NV84_SUBCHAN_SEMAPHORE_SEQUENCE                              0x00000018
+#define NV84_SUBCHAN_SEMAPHORE_TRIGGER                               0x0000001c
+#define NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL                 0x00000001
+#define NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG                    0x00000002
+#define NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL                0x00000004
+#define NV84_SUBCHAN_NOTIFY_INTR                                     0x00000020
+#define NV84_SUBCHAN_WRCACHE_FLUSH                                   0x00000024
+#define NV10_SUBCHAN_REF_CNT                                         0x00000050
+#define NVSW_SUBCHAN_PAGE_FLIP                                       0x00000054
+#define NV11_SUBCHAN_DMA_SEMAPHORE                                   0x00000060
+#define NV11_SUBCHAN_SEMAPHORE_OFFSET                                0x00000064
+#define NV11_SUBCHAN_SEMAPHORE_ACQUIRE                               0x00000068
+#define NV11_SUBCHAN_SEMAPHORE_RELEASE                               0x0000006c
+#define NV40_SUBCHAN_YIELD                                           0x00000080
+
 /* NV_SW object class */
 #define NV_SW                                                        0x0000506e
-#define NV_SW_DMA_SEMAPHORE                                          0x00000060
-#define NV_SW_SEMAPHORE_OFFSET                                       0x00000064
-#define NV_SW_SEMAPHORE_ACQUIRE                                      0x00000068
-#define NV_SW_SEMAPHORE_RELEASE                                      0x0000006c
-#define NV_SW_YIELD                                                  0x00000080
 #define NV_SW_DMA_VBLSEM                                             0x0000018c
 #define NV_SW_VBLSEM_OFFSET                                          0x00000400
 #define NV_SW_VBLSEM_RELEASE_VALUE                                   0x00000404
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
index e5d6e3f..3dc14a3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -32,6 +32,14 @@
 
 #define NV_DPMS_CLEARED 0x80
 
+struct dp_train_func {
+	void (*link_set)(struct drm_device *, struct dcb_entry *, int crtc,
+			 int nr, u32 bw, bool enhframe);
+	void (*train_set)(struct drm_device *, struct dcb_entry *, u8 pattern);
+	void (*train_adj)(struct drm_device *, struct dcb_entry *,
+			  u8 lane, u8 swing, u8 preem);
+};
+
 struct nouveau_encoder {
 	struct drm_encoder_slave base;
 
@@ -78,9 +86,19 @@
 	return to_encoder_slave(enc)->slave_funcs;
 }
 
+/* nouveau_dp.c */
+int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
+		     uint8_t *data, int data_nr);
+bool nouveau_dp_detect(struct drm_encoder *);
+void nouveau_dp_dpms(struct drm_encoder *, int mode, u32 datarate,
+		     struct dp_train_func *);
+u8 *nouveau_dp_bios_data(struct drm_device *, struct dcb_entry *, u8 **);
+
 struct nouveau_connector *
 nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
 int nv50_sor_create(struct drm_connector *, struct dcb_entry *);
+void nv50_sor_dp_calc_tu(struct drm_device *, int, int, u32, u32);
 int nv50_dac_create(struct drm_connector *, struct dcb_entry *);
 
+
 #endif /* __NOUVEAU_ENCODER_H__ */
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 9892218..8113e92 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -381,11 +381,7 @@
 		goto out_unref;
 	}
 
-	info->pixmap.size = 64*1024;
-	info->pixmap.buf_align = 8;
-	info->pixmap.access_align = 32;
-	info->pixmap.flags = FB_PIXMAP_SYSTEM;
-	info->pixmap.scan_align = 1;
+	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
 
 	mutex_unlock(&dev->struct_mutex);
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 2f6daae..c1dc20f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -93,18 +93,17 @@
 	}
 
 	list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
-		sequence = fence->sequence;
+		if (fence->sequence > chan->fence.sequence_ack)
+			break;
+
 		fence->signalled = true;
 		list_del(&fence->entry);
-
-		if (unlikely(fence->work))
+		if (fence->work)
 			fence->work(fence->priv, true);
 
 		kref_put(&fence->refcount, nouveau_fence_del);
-
-		if (sequence == chan->fence.sequence_ack)
-			break;
 	}
+
 out:
 	spin_unlock(&chan->fence.lock);
 }
@@ -165,9 +164,9 @@
 
 	if (USE_REFCNT(dev)) {
 		if (dev_priv->card_type < NV_C0)
-			BEGIN_RING(chan, NvSubSw, 0x0050, 1);
+			BEGIN_RING(chan, 0, NV10_SUBCHAN_REF_CNT, 1);
 		else
-			BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0050, 1);
+			BEGIN_NVC0(chan, 2, 0, NV10_SUBCHAN_REF_CNT, 1);
 	} else {
 		BEGIN_RING(chan, NvSubSw, 0x0150, 1);
 	}
@@ -344,7 +343,7 @@
 		if (ret)
 			return ret;
 
-		BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 3);
+		BEGIN_RING(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 3);
 		OUT_RING  (chan, NvSema);
 		OUT_RING  (chan, offset);
 		OUT_RING  (chan, 1);
@@ -354,9 +353,9 @@
 		if (ret)
 			return ret;
 
-		BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1);
+		BEGIN_RING(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
 		OUT_RING  (chan, chan->vram_handle);
-		BEGIN_RING(chan, NvSubSw, 0x0010, 4);
+		BEGIN_RING(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
 		OUT_RING  (chan, upper_32_bits(offset));
 		OUT_RING  (chan, lower_32_bits(offset));
 		OUT_RING  (chan, 1);
@@ -366,7 +365,7 @@
 		if (ret)
 			return ret;
 
-		BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4);
+		BEGIN_NVC0(chan, 2, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
 		OUT_RING  (chan, upper_32_bits(offset));
 		OUT_RING  (chan, lower_32_bits(offset));
 		OUT_RING  (chan, 1);
@@ -397,10 +396,10 @@
 		if (ret)
 			return ret;
 
-		BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 2);
+		BEGIN_RING(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
 		OUT_RING  (chan, NvSema);
 		OUT_RING  (chan, offset);
-		BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_RELEASE, 1);
+		BEGIN_RING(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
 		OUT_RING  (chan, 1);
 	} else
 	if (dev_priv->chipset < 0xc0) {
@@ -408,9 +407,9 @@
 		if (ret)
 			return ret;
 
-		BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1);
+		BEGIN_RING(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
 		OUT_RING  (chan, chan->vram_handle);
-		BEGIN_RING(chan, NvSubSw, 0x0010, 4);
+		BEGIN_RING(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
 		OUT_RING  (chan, upper_32_bits(offset));
 		OUT_RING  (chan, lower_32_bits(offset));
 		OUT_RING  (chan, 1);
@@ -420,7 +419,7 @@
 		if (ret)
 			return ret;
 
-		BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4);
+		BEGIN_NVC0(chan, 2, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
 		OUT_RING  (chan, upper_32_bits(offset));
 		OUT_RING  (chan, lower_32_bits(offset));
 		OUT_RING  (chan, 1);
@@ -510,7 +509,7 @@
 		if (ret)
 			return ret;
 
-		BEGIN_RING(chan, NvSubSw, 0, 1);
+		BEGIN_RING(chan, NvSubSw, NV01_SUBCHAN_OBJECT, 1);
 		OUT_RING  (chan, NvSw);
 		FIRE_RING (chan);
 	}
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 7ce3fde..ed52a6f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -426,9 +426,7 @@
 			return ret;
 		}
 
-		nvbo->channel = (b->read_domains & (1 << 31)) ? NULL : chan;
 		ret = nouveau_bo_validate(nvbo, true, false, false);
-		nvbo->channel = NULL;
 		if (unlikely(ret)) {
 			if (ret != -ERESTARTSYS)
 				NV_ERROR(dev, "fail ttm_validate\n");
@@ -678,19 +676,13 @@
 		return PTR_ERR(bo);
 	}
 
-	/* Mark push buffers as being used on PFIFO, the validation code
-	 * will then make sure that if the pushbuf bo moves, that they
-	 * happen on the kernel channel, which will in turn cause a sync
-	 * to happen before we try and submit the push buffer.
-	 */
+	/* Ensure all push buffers are on validate list */
 	for (i = 0; i < req->nr_push; i++) {
 		if (push[i].bo_index >= req->nr_buffers) {
 			NV_ERROR(dev, "push %d buffer not in list\n", i);
 			ret = -EINVAL;
 			goto out_prevalid;
 		}
-
-		bo[push[i].bo_index].read_domains |= (1 << 31);
 	}
 
 	/* Validate buffer list */
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c
index 820ae7f..e2be95a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.c
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c
@@ -277,7 +277,7 @@
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
 }
 
-const struct i2c_algorithm i2c_bit_algo = {
+const struct i2c_algorithm nouveau_i2c_bit_algo = {
 	.master_xfer = i2c_bit_xfer,
 	.functionality = i2c_bit_func
 };
@@ -315,8 +315,8 @@
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nvbios *bios = &dev_priv->vbios;
 	struct nouveau_i2c_chan *port;
+	u8 version = 0x00, entries, recordlen;
 	u8 *i2c, *entry, legacy[2][4] = {};
-	u8 version, entries, recordlen;
 	int ret, i;
 
 	INIT_LIST_HEAD(&dev_priv->i2c_ports);
@@ -346,12 +346,12 @@
 		if (i2c[7]) legacy[1][1] = i2c[7];
 	}
 
-	if (i2c && version >= 0x30) {
+	if (version >= 0x30) {
 		entry     = i2c[1] + i2c;
 		entries   = i2c[2];
 		recordlen = i2c[3];
 	} else
-	if (i2c) {
+	if (version) {
 		entry     = i2c;
 		entries   = 16;
 		recordlen = 4;
@@ -384,12 +384,12 @@
 		case 0: /* NV04:NV50 */
 			port->drive = entry[0];
 			port->sense = entry[1];
-			port->adapter.algo = &i2c_bit_algo;
+			port->adapter.algo = &nouveau_i2c_bit_algo;
 			break;
 		case 4: /* NV4E */
 			port->drive = 0x600800 + entry[1];
 			port->sense = port->drive;
-			port->adapter.algo = &i2c_bit_algo;
+			port->adapter.algo = &nouveau_i2c_bit_algo;
 			break;
 		case 5: /* NV50- */
 			port->drive = entry[0] & 0x0f;
@@ -402,7 +402,7 @@
 				port->drive = 0x00d014 + (port->drive * 0x20);
 				port->sense = port->drive;
 			}
-			port->adapter.algo = &i2c_bit_algo;
+			port->adapter.algo = &nouveau_i2c_bit_algo;
 			break;
 		case 6: /* NV50- DP AUX */
 			port->drive = entry[0];
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index c3a5745..b08065f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -26,7 +26,8 @@
  * DEALINGS IN THE SOFTWARE.
  *
  * Authors:
- *    Keith Whitwell <keith@tungstengraphics.com>
+ *    Ben Skeggs <bskeggs@redhat.com>
+ *    Roy Spliet <r.spliet@student.tudelft.nl>
  */
 
 
@@ -192,75 +193,6 @@
 	}
 }
 
-static uint32_t
-nouveau_mem_detect_nv04(struct drm_device *dev)
-{
-	uint32_t boot0 = nv_rd32(dev, NV04_PFB_BOOT_0);
-
-	if (boot0 & 0x00000100)
-		return (((boot0 >> 12) & 0xf) * 2 + 2) * 1024 * 1024;
-
-	switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
-	case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
-		return 32 * 1024 * 1024;
-	case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
-		return 16 * 1024 * 1024;
-	case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
-		return 8 * 1024 * 1024;
-	case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
-		return 4 * 1024 * 1024;
-	}
-
-	return 0;
-}
-
-static uint32_t
-nouveau_mem_detect_nforce(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct pci_dev *bridge;
-	uint32_t mem;
-
-	bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
-	if (!bridge) {
-		NV_ERROR(dev, "no bridge device\n");
-		return 0;
-	}
-
-	if (dev_priv->flags & NV_NFORCE) {
-		pci_read_config_dword(bridge, 0x7C, &mem);
-		return (uint64_t)(((mem >> 6) & 31) + 1)*1024*1024;
-	} else
-	if (dev_priv->flags & NV_NFORCE2) {
-		pci_read_config_dword(bridge, 0x84, &mem);
-		return (uint64_t)(((mem >> 4) & 127) + 1)*1024*1024;
-	}
-
-	NV_ERROR(dev, "impossible!\n");
-	return 0;
-}
-
-int
-nouveau_mem_detect(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-	if (dev_priv->card_type == NV_04) {
-		dev_priv->vram_size = nouveau_mem_detect_nv04(dev);
-	} else
-	if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) {
-		dev_priv->vram_size = nouveau_mem_detect_nforce(dev);
-	} else
-	if (dev_priv->card_type < NV_50) {
-		dev_priv->vram_size  = nv_rd32(dev, NV04_PFB_FIFO_DATA);
-		dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK;
-	}
-
-	if (dev_priv->vram_size)
-		return 0;
-	return -ENOMEM;
-}
-
 bool
 nouveau_mem_flags_valid(struct drm_device *dev, u32 tile_flags)
 {
@@ -385,11 +317,29 @@
 	return 0;
 }
 
+static const struct vram_types {
+	int value;
+	const char *name;
+} vram_type_map[] = {
+	{ NV_MEM_TYPE_STOLEN , "stolen system memory" },
+	{ NV_MEM_TYPE_SGRAM  , "SGRAM" },
+	{ NV_MEM_TYPE_SDRAM  , "SDRAM" },
+	{ NV_MEM_TYPE_DDR1   , "DDR1" },
+	{ NV_MEM_TYPE_DDR2   , "DDR2" },
+	{ NV_MEM_TYPE_DDR3   , "DDR3" },
+	{ NV_MEM_TYPE_GDDR2  , "GDDR2" },
+	{ NV_MEM_TYPE_GDDR3  , "GDDR3" },
+	{ NV_MEM_TYPE_GDDR4  , "GDDR4" },
+	{ NV_MEM_TYPE_GDDR5  , "GDDR5" },
+	{ NV_MEM_TYPE_UNKNOWN, "unknown type" }
+};
+
 int
 nouveau_mem_vram_init(struct drm_device *dev)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
+	const struct vram_types *vram_type;
 	int ret, dma_bits;
 
 	dma_bits = 32;
@@ -427,7 +377,21 @@
 		return ret;
 	}
 
-	NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20));
+	vram_type = vram_type_map;
+	while (vram_type->value != NV_MEM_TYPE_UNKNOWN) {
+		if (nouveau_vram_type) {
+			if (!strcasecmp(nouveau_vram_type, vram_type->name))
+				break;
+			dev_priv->vram_type = vram_type->value;
+		} else {
+			if (vram_type->value == dev_priv->vram_type)
+				break;
+		}
+		vram_type++;
+	}
+
+	NV_INFO(dev, "Detected %dMiB VRAM (%s)\n",
+		(int)(dev_priv->vram_size >> 20), vram_type->name);
 	if (dev_priv->vram_sys_base) {
 		NV_INFO(dev, "Stolen system memory at: 0x%010llx\n",
 			dev_priv->vram_sys_base);
@@ -508,216 +472,617 @@
 	return 0;
 }
 
-/* XXX: For now a dummy. More samples required, possibly even a card
- * Called from nouveau_perf.c */
-void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
-							struct nouveau_pm_tbl_entry *e, uint8_t magic_number,
-							struct nouveau_pm_memtiming *timing) {
-
-	NV_DEBUG(dev,"Timing entry format unknown, please contact nouveau developers");
-}
-
-void nv40_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
-							struct nouveau_pm_tbl_entry *e, uint8_t magic_number,
-							struct nouveau_pm_memtiming *timing) {
-
-	timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP);
+static int
+nv40_mem_timing_calc(struct drm_device *dev, u32 freq,
+		     struct nouveau_pm_tbl_entry *e, u8 len,
+		     struct nouveau_pm_memtiming *boot,
+		     struct nouveau_pm_memtiming *t)
+{
+	t->reg[0] = (e->tRP << 24 | e->tRAS << 16 | e->tRFC << 8 | e->tRC);
 
 	/* XXX: I don't trust the -1's and +1's... they must come
 	 *      from somewhere! */
-	timing->reg_1 = (e->tWR + 2 + magic_number) << 24 |
-				  1 << 16 |
-				  (e->tUNK_1 + 2 + magic_number) << 8 |
-				  (e->tCL + 2 - magic_number);
-	timing->reg_2 = (magic_number << 24 | e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10);
-	timing->reg_2 |= 0x20200000;
+	t->reg[1] = (e->tWR + 2 + (t->tCWL - 1)) << 24 |
+		    1 << 16 |
+		    (e->tWTR + 2 + (t->tCWL - 1)) << 8 |
+		    (e->tCL + 2 - (t->tCWL - 1));
 
-	NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x\n", timing->id,
-		 timing->reg_0, timing->reg_1,timing->reg_2);
+	t->reg[2] = 0x20200000 |
+		    ((t->tCWL - 1) << 24 |
+		     e->tRRD << 16 |
+		     e->tRCDWR << 8 |
+		     e->tRCDRD);
+
+	NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x\n", t->id,
+		 t->reg[0], t->reg[1], t->reg[2]);
+	return 0;
 }
 
-void nv50_mem_timing_entry(struct drm_device *dev, struct bit_entry *P, struct nouveau_pm_tbl_header *hdr,
-							struct nouveau_pm_tbl_entry *e, uint8_t magic_number,struct nouveau_pm_memtiming *timing) {
+static int
+nv50_mem_timing_calc(struct drm_device *dev, u32 freq,
+		     struct nouveau_pm_tbl_entry *e, u8 len,
+		     struct nouveau_pm_memtiming *boot,
+		     struct nouveau_pm_memtiming *t)
+{
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct bit_entry P;
+	uint8_t unk18 = 1, unk20 = 0, unk21 = 0, tmp7_3;
 
-	uint8_t unk18 = 1,
-		unk19 = 1,
-		unk20 = 0,
-		unk21 = 0;
+	if (bit_table(dev, 'P', &P))
+		return -EINVAL;
 
-	switch (min(hdr->entry_len, (u8) 22)) {
+	switch (min(len, (u8) 22)) {
 	case 22:
 		unk21 = e->tUNK_21;
 	case 21:
 		unk20 = e->tUNK_20;
 	case 20:
-		unk19 = e->tUNK_19;
+		if (e->tCWL > 0)
+			t->tCWL = e->tCWL;
 	case 19:
 		unk18 = e->tUNK_18;
 		break;
 	}
 
-	timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP);
+	t->reg[0] = (e->tRP << 24 | e->tRAS << 16 | e->tRFC << 8 | e->tRC);
 
-	/* XXX: I don't trust the -1's and +1's... they must come
-	 *      from somewhere! */
-	timing->reg_1 = (e->tWR + unk19 + 1 + magic_number) << 24 |
-				  max(unk18, (u8) 1) << 16 |
-				  (e->tUNK_1 + unk19 + 1 + magic_number) << 8;
-	if (dev_priv->chipset == 0xa8) {
-		timing->reg_1 |= (e->tCL - 1);
+	t->reg[1] = (e->tWR + 2 + (t->tCWL - 1)) << 24 |
+				max(unk18, (u8) 1) << 16 |
+				(e->tWTR + 2 + (t->tCWL - 1)) << 8;
+
+	t->reg[2] = ((t->tCWL - 1) << 24 |
+		    e->tRRD << 16 |
+		    e->tRCDWR << 8 |
+		    e->tRCDRD);
+
+	t->reg[4] = e->tUNK_13 << 8  | e->tUNK_13;
+
+	t->reg[5] = (e->tRFC << 24 | max(e->tRCDRD, e->tRCDWR) << 16 | e->tRP);
+
+	t->reg[8] = boot->reg[8] & 0xffffff00;
+
+	if (P.version == 1) {
+		t->reg[1] |= (e->tCL + 2 - (t->tCWL - 1));
+
+		t->reg[3] = (0x14 + e->tCL) << 24 |
+			    0x16 << 16 |
+			    (e->tCL - 1) << 8 |
+			    (e->tCL - 1);
+
+		t->reg[4] |= boot->reg[4] & 0xffff0000;
+
+		t->reg[6] = (0x33 - t->tCWL) << 16 |
+			    t->tCWL << 8 |
+			    (0x2e + e->tCL - t->tCWL);
+
+		t->reg[7] = 0x4000202 | (e->tCL - 1) << 16;
+
+		/* XXX: P.version == 1 only has DDR2 and GDDR3? */
+		if (dev_priv->vram_type == NV_MEM_TYPE_DDR2) {
+			t->reg[5] |= (e->tCL + 3) << 8;
+			t->reg[6] |= (t->tCWL - 2) << 8;
+			t->reg[8] |= (e->tCL - 4);
+		} else {
+			t->reg[5] |= (e->tCL + 2) << 8;
+			t->reg[6] |= t->tCWL << 8;
+			t->reg[8] |= (e->tCL - 2);
+		}
 	} else {
-		timing->reg_1 |= (e->tCL + 2 - magic_number);
-	}
-	timing->reg_2 = (e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10);
+		t->reg[1] |= (5 + e->tCL - (t->tCWL));
 
-	timing->reg_5 = (e->tRAS << 24 | e->tRC);
-	timing->reg_5 += max(e->tUNK_10, e->tUNK_11) << 16;
+		/* XXX: 0xb? 0x30? */
+		t->reg[3] = (0x30 + e->tCL) << 24 |
+			    (boot->reg[3] & 0x00ff0000)|
+			    (0xb + e->tCL) << 8 |
+			    (e->tCL - 1);
 
-	if (P->version == 1) {
-		timing->reg_2 |= magic_number << 24;
-		timing->reg_3 = (0x14 + e->tCL) << 24 |
-						0x16 << 16 |
-						(e->tCL - 1) << 8 |
-						(e->tCL - 1);
-		timing->reg_4 = (nv_rd32(dev,0x10022c) & 0xffff0000) | e->tUNK_13 << 8  | e->tUNK_13;
-		timing->reg_5 |= (e->tCL + 2) << 8;
-		timing->reg_7 = 0x4000202 | (e->tCL - 1) << 16;
-	} else {
-		timing->reg_2 |= (unk19 - 1) << 24;
-		/* XXX: reg_10022c for recentish cards pretty much unknown*/
-		timing->reg_3 = e->tCL - 1;
-		timing->reg_4 = (unk20 << 24 | unk21 << 16 |
-							e->tUNK_13 << 8  | e->tUNK_13);
+		t->reg[4] |= (unk20 << 24 | unk21 << 16);
+
 		/* XXX: +6? */
-		timing->reg_5 |= (unk19 + 6) << 8;
+		t->reg[5] |= (t->tCWL + 6) << 8;
 
-		/* XXX: reg_10023c currently unknown
-		 * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */
-		timing->reg_7 = 0x202;
+		t->reg[6] = (0x5a + e->tCL) << 16 |
+			    (6 - e->tCL + t->tCWL) << 8 |
+			    (0x50 + e->tCL - t->tCWL);
+
+		tmp7_3 = (boot->reg[7] & 0xff000000) >> 24;
+		t->reg[7] = (tmp7_3 << 24) |
+			    ((tmp7_3 - 6 + e->tCL) << 16) |
+			    0x202;
 	}
 
-	NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", timing->id,
-		 timing->reg_0, timing->reg_1,
-		 timing->reg_2, timing->reg_3);
+	NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", t->id,
+		 t->reg[0], t->reg[1], t->reg[2], t->reg[3]);
 	NV_DEBUG(dev, "         230: %08x %08x %08x %08x\n",
-		 timing->reg_4, timing->reg_5,
-		 timing->reg_6, timing->reg_7);
-	NV_DEBUG(dev, "         240: %08x\n", timing->reg_8);
+		 t->reg[4], t->reg[5], t->reg[6], t->reg[7]);
+	NV_DEBUG(dev, "         240: %08x\n", t->reg[8]);
+	return 0;
 }
 
-void nvc0_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
-							struct nouveau_pm_tbl_entry *e, struct nouveau_pm_memtiming *timing) {
-	timing->reg_0 = (e->tRC << 24 | (e->tRFC & 0x7f) << 17 | e->tRAS << 8 | e->tRP);
-	timing->reg_1 = (nv_rd32(dev,0x10f294) & 0xff000000) | (e->tUNK_11&0x0f) << 20 | (e->tUNK_19 << 7) | (e->tCL & 0x0f);
-	timing->reg_2 = (nv_rd32(dev,0x10f298) & 0xff0000ff) | e->tWR << 16 | e->tUNK_1 << 8;
-	timing->reg_3 = e->tUNK_20 << 9 | e->tUNK_13;
-	timing->reg_4 = (nv_rd32(dev,0x10f2a0) & 0xfff000ff) | e->tUNK_12 << 15;
-	NV_DEBUG(dev, "Entry %d: 290: %08x %08x %08x %08x\n", timing->id,
-		 timing->reg_0, timing->reg_1,
-		 timing->reg_2, timing->reg_3);
-	NV_DEBUG(dev, "         2a0: %08x %08x %08x %08x\n",
-		 timing->reg_4, timing->reg_5,
-		 timing->reg_6, timing->reg_7);
+static int
+nvc0_mem_timing_calc(struct drm_device *dev, u32 freq,
+		     struct nouveau_pm_tbl_entry *e, u8 len,
+		     struct nouveau_pm_memtiming *boot,
+		     struct nouveau_pm_memtiming *t)
+{
+	if (e->tCWL > 0)
+		t->tCWL = e->tCWL;
+
+	t->reg[0] = (e->tRP << 24 | (e->tRAS & 0x7f) << 17 |
+		     e->tRFC << 8 | e->tRC);
+
+	t->reg[1] = (boot->reg[1] & 0xff000000) |
+		    (e->tRCDWR & 0x0f) << 20 |
+		    (e->tRCDRD & 0x0f) << 14 |
+		    (t->tCWL << 7) |
+		    (e->tCL & 0x0f);
+
+	t->reg[2] = (boot->reg[2] & 0xff0000ff) |
+		    e->tWR << 16 | e->tWTR << 8;
+
+	t->reg[3] = (e->tUNK_20 & 0x1f) << 9 |
+		    (e->tUNK_21 & 0xf) << 5 |
+		    (e->tUNK_13 & 0x1f);
+
+	t->reg[4] = (boot->reg[4] & 0xfff00fff) |
+		    (e->tRRD&0x1f) << 15;
+
+	NV_DEBUG(dev, "Entry %d: 290: %08x %08x %08x %08x\n", t->id,
+		 t->reg[0], t->reg[1], t->reg[2], t->reg[3]);
+	NV_DEBUG(dev, "         2a0: %08x\n", t->reg[4]);
+	return 0;
 }
 
 /**
- * Processes the Memory Timing BIOS table, stores generated
- * register values
- * @pre init scripts were run, memtiming regs are initialized
+ * MR generation methods
  */
-void
-nouveau_mem_timing_init(struct drm_device *dev)
+
+static int
+nouveau_mem_ddr2_mr(struct drm_device *dev, u32 freq,
+		    struct nouveau_pm_tbl_entry *e, u8 len,
+		    struct nouveau_pm_memtiming *boot,
+		    struct nouveau_pm_memtiming *t)
+{
+	t->drive_strength = 0;
+	if (len < 15) {
+		t->odt = boot->odt;
+	} else {
+		t->odt = e->RAM_FT1 & 0x07;
+	}
+
+	if (e->tCL >= NV_MEM_CL_DDR2_MAX) {
+		NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL);
+		return -ERANGE;
+	}
+
+	if (e->tWR >= NV_MEM_WR_DDR2_MAX) {
+		NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR);
+		return -ERANGE;
+	}
+
+	if (t->odt > 3) {
+		NV_WARN(dev, "(%u) Invalid odt value, assuming disabled: %x",
+			t->id, t->odt);
+		t->odt = 0;
+	}
+
+	t->mr[0] = (boot->mr[0] & 0x100f) |
+		   (e->tCL) << 4 |
+		   (e->tWR - 1) << 9;
+	t->mr[1] = (boot->mr[1] & 0x101fbb) |
+		   (t->odt & 0x1) << 2 |
+		   (t->odt & 0x2) << 5;
+
+	NV_DEBUG(dev, "(%u) MR: %08x", t->id, t->mr[0]);
+	return 0;
+}
+
+uint8_t nv_mem_wr_lut_ddr3[NV_MEM_WR_DDR3_MAX] = {
+	0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 0, 0};
+
+static int
+nouveau_mem_ddr3_mr(struct drm_device *dev, u32 freq,
+		    struct nouveau_pm_tbl_entry *e, u8 len,
+		    struct nouveau_pm_memtiming *boot,
+		    struct nouveau_pm_memtiming *t)
+{
+	u8 cl = e->tCL - 4;
+
+	t->drive_strength = 0;
+	if (len < 15) {
+		t->odt = boot->odt;
+	} else {
+		t->odt = e->RAM_FT1 & 0x07;
+	}
+
+	if (e->tCL >= NV_MEM_CL_DDR3_MAX || e->tCL < 4) {
+		NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL);
+		return -ERANGE;
+	}
+
+	if (e->tWR >= NV_MEM_WR_DDR3_MAX || e->tWR < 4) {
+		NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR);
+		return -ERANGE;
+	}
+
+	if (e->tCWL < 5) {
+		NV_WARN(dev, "(%u) Invalid tCWL: %u", t->id, e->tCWL);
+		return -ERANGE;
+	}
+
+	t->mr[0] = (boot->mr[0] & 0x180b) |
+		   /* CAS */
+		   (cl & 0x7) << 4 |
+		   (cl & 0x8) >> 1 |
+		   (nv_mem_wr_lut_ddr3[e->tWR]) << 9;
+	t->mr[1] = (boot->mr[1] & 0x101dbb) |
+		   (t->odt & 0x1) << 2 |
+		   (t->odt & 0x2) << 5 |
+		   (t->odt & 0x4) << 7;
+	t->mr[2] = (boot->mr[2] & 0x20ffb7) | (e->tCWL - 5) << 3;
+
+	NV_DEBUG(dev, "(%u) MR: %08x %08x", t->id, t->mr[0], t->mr[2]);
+	return 0;
+}
+
+uint8_t nv_mem_cl_lut_gddr3[NV_MEM_CL_GDDR3_MAX] = {
+	0, 0, 0, 0, 4, 5, 6, 7, 0, 1, 2, 3, 8, 9, 10, 11};
+uint8_t nv_mem_wr_lut_gddr3[NV_MEM_WR_GDDR3_MAX] = {
+	0, 0, 0, 0, 0, 2, 3, 8, 9, 10, 11, 0, 0, 1, 1, 0, 3};
+
+static int
+nouveau_mem_gddr3_mr(struct drm_device *dev, u32 freq,
+		     struct nouveau_pm_tbl_entry *e, u8 len,
+		     struct nouveau_pm_memtiming *boot,
+		     struct nouveau_pm_memtiming *t)
+{
+	if (len < 15) {
+		t->drive_strength = boot->drive_strength;
+		t->odt = boot->odt;
+	} else {
+		t->drive_strength = (e->RAM_FT1 & 0x30) >> 4;
+		t->odt = e->RAM_FT1 & 0x07;
+	}
+
+	if (e->tCL >= NV_MEM_CL_GDDR3_MAX) {
+		NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL);
+		return -ERANGE;
+	}
+
+	if (e->tWR >= NV_MEM_WR_GDDR3_MAX) {
+		NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR);
+		return -ERANGE;
+	}
+
+	if (t->odt > 3) {
+		NV_WARN(dev, "(%u) Invalid odt value, assuming autocal: %x",
+			t->id, t->odt);
+		t->odt = 0;
+	}
+
+	t->mr[0] = (boot->mr[0] & 0xe0b) |
+		   /* CAS */
+		   ((nv_mem_cl_lut_gddr3[e->tCL] & 0x7) << 4) |
+		   ((nv_mem_cl_lut_gddr3[e->tCL] & 0x8) >> 2);
+	t->mr[1] = (boot->mr[1] & 0x100f40) | t->drive_strength |
+		   (t->odt << 2) |
+		   (nv_mem_wr_lut_gddr3[e->tWR] & 0xf) << 4;
+	t->mr[2] = boot->mr[2];
+
+	NV_DEBUG(dev, "(%u) MR: %08x %08x %08x", t->id,
+		      t->mr[0], t->mr[1], t->mr[2]);
+	return 0;
+}
+
+static int
+nouveau_mem_gddr5_mr(struct drm_device *dev, u32 freq,
+		     struct nouveau_pm_tbl_entry *e, u8 len,
+		     struct nouveau_pm_memtiming *boot,
+		     struct nouveau_pm_memtiming *t)
+{
+	if (len < 15) {
+		t->drive_strength = boot->drive_strength;
+		t->odt = boot->odt;
+	} else {
+		t->drive_strength = (e->RAM_FT1 & 0x30) >> 4;
+		t->odt = e->RAM_FT1 & 0x03;
+	}
+
+	if (e->tCL >= NV_MEM_CL_GDDR5_MAX) {
+		NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL);
+		return -ERANGE;
+	}
+
+	if (e->tWR >= NV_MEM_WR_GDDR5_MAX) {
+		NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR);
+		return -ERANGE;
+	}
+
+	if (t->odt > 3) {
+		NV_WARN(dev, "(%u) Invalid odt value, assuming autocal: %x",
+			t->id, t->odt);
+		t->odt = 0;
+	}
+
+	t->mr[0] = (boot->mr[0] & 0x007) |
+		   ((e->tCL - 5) << 3) |
+		   ((e->tWR - 4) << 8);
+	t->mr[1] = (boot->mr[1] & 0x1007f0) |
+		   t->drive_strength |
+		   (t->odt << 2);
+
+	NV_DEBUG(dev, "(%u) MR: %08x %08x", t->id, t->mr[0], t->mr[1]);
+	return 0;
+}
+
+int
+nouveau_mem_timing_calc(struct drm_device *dev, u32 freq,
+			struct nouveau_pm_memtiming *t)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
-	struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
-	struct nvbios *bios = &dev_priv->vbios;
-	struct bit_entry P;
-	struct nouveau_pm_tbl_header *hdr = NULL;
-	uint8_t magic_number;
-	u8 *entry;
-	int i;
+	struct nouveau_pm_memtiming *boot = &pm->boot.timing;
+	struct nouveau_pm_tbl_entry *e;
+	u8 ver, len, *ptr, *ramcfg;
+	int ret;
 
-	if (bios->type == NVBIOS_BIT) {
-		if (bit_table(dev, 'P', &P))
-			return;
+	ptr = nouveau_perf_timing(dev, freq, &ver, &len);
+	if (!ptr || ptr[0] == 0x00) {
+		*t = *boot;
+		return 0;
+	}
+	e = (struct nouveau_pm_tbl_entry *)ptr;
 
-		if (P.version == 1)
-			hdr = (struct nouveau_pm_tbl_header *) ROMPTR(dev, P.data[4]);
+	t->tCWL = boot->tCWL;
+
+	switch (dev_priv->card_type) {
+	case NV_40:
+		ret = nv40_mem_timing_calc(dev, freq, e, len, boot, t);
+		break;
+	case NV_50:
+		ret = nv50_mem_timing_calc(dev, freq, e, len, boot, t);
+		break;
+	case NV_C0:
+		ret = nvc0_mem_timing_calc(dev, freq, e, len, boot, t);
+		break;
+	default:
+		ret = -ENODEV;
+		break;
+	}
+
+	switch (dev_priv->vram_type * !ret) {
+	case NV_MEM_TYPE_GDDR3:
+		ret = nouveau_mem_gddr3_mr(dev, freq, e, len, boot, t);
+		break;
+	case NV_MEM_TYPE_GDDR5:
+		ret = nouveau_mem_gddr5_mr(dev, freq, e, len, boot, t);
+		break;
+	case NV_MEM_TYPE_DDR2:
+		ret = nouveau_mem_ddr2_mr(dev, freq, e, len, boot, t);
+		break;
+	case NV_MEM_TYPE_DDR3:
+		ret = nouveau_mem_ddr3_mr(dev, freq, e, len, boot, t);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	ramcfg = nouveau_perf_ramcfg(dev, freq, &ver, &len);
+	if (ramcfg) {
+		int dll_off;
+
+		if (ver == 0x00)
+			dll_off = !!(ramcfg[3] & 0x04);
 		else
-		if (P.version == 2)
-			hdr = (struct nouveau_pm_tbl_header *) ROMPTR(dev, P.data[8]);
-		else {
-			NV_WARN(dev, "unknown mem for BIT P %d\n", P.version);
-		}
-	} else {
-		NV_DEBUG(dev, "BMP version too old for memory\n");
-		return;
-	}
+			dll_off = !!(ramcfg[2] & 0x40);
 
-	if (!hdr) {
-		NV_DEBUG(dev, "memory timing table pointer invalid\n");
-		return;
-	}
-
-	if (hdr->version != 0x10) {
-		NV_WARN(dev, "memory timing table 0x%02x unknown\n", hdr->version);
-		return;
-	}
-
-	/* validate record length */
-	if (hdr->entry_len < 15) {
-		NV_ERROR(dev, "mem timing table length unknown: %d\n", hdr->entry_len);
-		return;
-	}
-
-	/* parse vbios entries into common format */
-	memtimings->timing =
-		kcalloc(hdr->entry_cnt, sizeof(*memtimings->timing), GFP_KERNEL);
-	if (!memtimings->timing)
-		return;
-
-	/* Get "some number" from the timing reg for NV_40 and NV_50
-	 * Used in calculations later... source unknown */
-	magic_number = 0;
-	if (P.version == 1) {
-		magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24;
-	}
-
-	entry = (u8*) hdr + hdr->header_len;
-	for (i = 0; i < hdr->entry_cnt; i++, entry += hdr->entry_len) {
-		struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i];
-		if (entry[0] == 0)
-			continue;
-
-		timing->id = i;
-		timing->WR = entry[0];
-		timing->CL = entry[2];
-
-		if(dev_priv->card_type <= NV_40) {
-			nv40_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]);
-		} else if(dev_priv->card_type == NV_50){
-			nv50_mem_timing_entry(dev,&P,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]);
-		} else if(dev_priv->card_type == NV_C0) {
-			nvc0_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,&pm->memtimings.timing[i]);
+		switch (dev_priv->vram_type) {
+		case NV_MEM_TYPE_GDDR3:
+			t->mr[1] &= ~0x00000040;
+			t->mr[1] |=  0x00000040 * dll_off;
+			break;
+		default:
+			t->mr[1] &= ~0x00000001;
+			t->mr[1] |=  0x00000001 * dll_off;
+			break;
 		}
 	}
 
-	memtimings->nr_timing = hdr->entry_cnt;
-	memtimings->supported = P.version == 1;
+	return ret;
 }
 
 void
-nouveau_mem_timing_fini(struct drm_device *dev)
+nouveau_mem_timing_read(struct drm_device *dev, struct nouveau_pm_memtiming *t)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings;
+	u32 timing_base, timing_regs, mr_base;
+	int i;
 
-	if(mem->timing) {
-		kfree(mem->timing);
-		mem->timing = NULL;
+	if (dev_priv->card_type >= 0xC0) {
+		timing_base = 0x10f290;
+		mr_base = 0x10f300;
+	} else {
+		timing_base = 0x100220;
+		mr_base = 0x1002c0;
 	}
+
+	t->id = -1;
+
+	switch (dev_priv->card_type) {
+	case NV_50:
+		timing_regs = 9;
+		break;
+	case NV_C0:
+	case NV_D0:
+		timing_regs = 5;
+		break;
+	case NV_30:
+	case NV_40:
+		timing_regs = 3;
+		break;
+	default:
+		timing_regs = 0;
+		return;
+	}
+	for(i = 0; i < timing_regs; i++)
+		t->reg[i] = nv_rd32(dev, timing_base + (0x04 * i));
+
+	t->tCWL = 0;
+	if (dev_priv->card_type < NV_C0) {
+		t->tCWL = ((nv_rd32(dev, 0x100228) & 0x0f000000) >> 24) + 1;
+	} else if (dev_priv->card_type <= NV_D0) {
+		t->tCWL = ((nv_rd32(dev, 0x10f294) & 0x00000f80) >> 7);
+	}
+
+	t->mr[0] = nv_rd32(dev, mr_base);
+	t->mr[1] = nv_rd32(dev, mr_base + 0x04);
+	t->mr[2] = nv_rd32(dev, mr_base + 0x20);
+	t->mr[3] = nv_rd32(dev, mr_base + 0x24);
+
+	t->odt = 0;
+	t->drive_strength = 0;
+
+	switch (dev_priv->vram_type) {
+	case NV_MEM_TYPE_DDR3:
+		t->odt |= (t->mr[1] & 0x200) >> 7;
+	case NV_MEM_TYPE_DDR2:
+		t->odt |= (t->mr[1] & 0x04) >> 2 |
+			  (t->mr[1] & 0x40) >> 5;
+		break;
+	case NV_MEM_TYPE_GDDR3:
+	case NV_MEM_TYPE_GDDR5:
+		t->drive_strength = t->mr[1] & 0x03;
+		t->odt = (t->mr[1] & 0x0c) >> 2;
+		break;
+	default:
+		break;
+	}
+}
+
+int
+nouveau_mem_exec(struct nouveau_mem_exec_func *exec,
+		 struct nouveau_pm_level *perflvl)
+{
+	struct drm_nouveau_private *dev_priv = exec->dev->dev_private;
+	struct nouveau_pm_memtiming *info = &perflvl->timing;
+	u32 tMRD = 1000, tCKSRE = 0, tCKSRX = 0, tXS = 0, tDLLK = 0;
+	u32 mr[3] = { info->mr[0], info->mr[1], info->mr[2] };
+	u32 mr1_dlloff;
+
+	switch (dev_priv->vram_type) {
+	case NV_MEM_TYPE_DDR2:
+		tDLLK = 2000;
+		mr1_dlloff = 0x00000001;
+		break;
+	case NV_MEM_TYPE_DDR3:
+		tDLLK = 12000;
+		mr1_dlloff = 0x00000001;
+		break;
+	case NV_MEM_TYPE_GDDR3:
+		tDLLK = 40000;
+		mr1_dlloff = 0x00000040;
+		break;
+	default:
+		NV_ERROR(exec->dev, "cannot reclock unsupported memtype\n");
+		return -ENODEV;
+	}
+
+	/* fetch current MRs */
+	switch (dev_priv->vram_type) {
+	case NV_MEM_TYPE_GDDR3:
+	case NV_MEM_TYPE_DDR3:
+		mr[2] = exec->mrg(exec, 2);
+	default:
+		mr[1] = exec->mrg(exec, 1);
+		mr[0] = exec->mrg(exec, 0);
+		break;
+	}
+
+	/* DLL 'on' -> DLL 'off' mode, disable before entering self-refresh  */
+	if (!(mr[1] & mr1_dlloff) && (info->mr[1] & mr1_dlloff)) {
+		exec->precharge(exec);
+		exec->mrs (exec, 1, mr[1] | mr1_dlloff);
+		exec->wait(exec, tMRD);
+	}
+
+	/* enter self-refresh mode */
+	exec->precharge(exec);
+	exec->refresh(exec);
+	exec->refresh(exec);
+	exec->refresh_auto(exec, false);
+	exec->refresh_self(exec, true);
+	exec->wait(exec, tCKSRE);
+
+	/* modify input clock frequency */
+	exec->clock_set(exec);
+
+	/* exit self-refresh mode */
+	exec->wait(exec, tCKSRX);
+	exec->precharge(exec);
+	exec->refresh_self(exec, false);
+	exec->refresh_auto(exec, true);
+	exec->wait(exec, tXS);
+
+	/* update MRs */
+	if (mr[2] != info->mr[2]) {
+		exec->mrs (exec, 2, info->mr[2]);
+		exec->wait(exec, tMRD);
+	}
+
+	if (mr[1] != info->mr[1]) {
+		/* need to keep DLL off until later, at least on GDDR3 */
+		exec->mrs (exec, 1, info->mr[1] | (mr[1] & mr1_dlloff));
+		exec->wait(exec, tMRD);
+	}
+
+	if (mr[0] != info->mr[0]) {
+		exec->mrs (exec, 0, info->mr[0]);
+		exec->wait(exec, tMRD);
+	}
+
+	/* update PFB timing registers */
+	exec->timing_set(exec);
+
+	/* DLL (enable + ) reset */
+	if (!(info->mr[1] & mr1_dlloff)) {
+		if (mr[1] & mr1_dlloff) {
+			exec->mrs (exec, 1, info->mr[1]);
+			exec->wait(exec, tMRD);
+		}
+		exec->mrs (exec, 0, info->mr[0] | 0x00000100);
+		exec->wait(exec, tMRD);
+		exec->mrs (exec, 0, info->mr[0] | 0x00000000);
+		exec->wait(exec, tMRD);
+		exec->wait(exec, tDLLK);
+		if (dev_priv->vram_type == NV_MEM_TYPE_GDDR3)
+			exec->precharge(exec);
+	}
+
+	return 0;
+}
+
+int
+nouveau_mem_vbios_type(struct drm_device *dev)
+{
+	struct bit_entry M;
+	u8 ramcfg = (nv_rd32(dev, 0x101000) & 0x0000003c) >> 2;
+	if (!bit_table(dev, 'M', &M) || M.version != 2 || M.length < 5) {
+		u8 *table = ROMPTR(dev, M.data[3]);
+		if (table && table[0] == 0x10 && ramcfg < table[3]) {
+			u8 *entry = table + table[1] + (ramcfg * table[2]);
+			switch (entry[0] & 0x0f) {
+			case 0: return NV_MEM_TYPE_DDR2;
+			case 1: return NV_MEM_TYPE_DDR3;
+			case 2: return NV_MEM_TYPE_GDDR3;
+			case 3: return NV_MEM_TYPE_GDDR5;
+			default:
+				break;
+			}
+
+		}
+	}
+	return NV_MEM_TYPE_UNKNOWN;
 }
 
 static int
diff --git a/drivers/gpu/drm/nouveau/nouveau_mxm.c b/drivers/gpu/drm/nouveau/nouveau_mxm.c
index e5a64f0..07d0d1e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mxm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mxm.c
@@ -582,6 +582,35 @@
 
 #define WMI_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
 
+static u8
+wmi_wmmx_mxmi(struct drm_device *dev, u8 version)
+{
+	u32 mxmi_args[] = { 0x494D584D /* MXMI */, version, 0 };
+	struct acpi_buffer args = { sizeof(mxmi_args), mxmi_args };
+	struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *obj;
+	acpi_status status;
+
+	status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);
+	if (ACPI_FAILURE(status)) {
+		MXM_DBG(dev, "WMMX MXMI returned %d\n", status);
+		return 0x00;
+	}
+
+	obj = retn.pointer;
+	if (obj->type == ACPI_TYPE_INTEGER) {
+		version = obj->integer.value;
+		MXM_DBG(dev, "WMMX MXMI version %d.%d\n",
+			     (version >> 4), version & 0x0f);
+	} else {
+		version = 0;
+		MXM_DBG(dev, "WMMX MXMI returned non-integer\n");
+	}
+
+	kfree(obj);
+	return version;
+}
+
 static bool
 mxm_shadow_wmi(struct drm_device *dev, u8 version)
 {
@@ -592,7 +621,15 @@
 	union acpi_object *obj;
 	acpi_status status;
 
-	if (!wmi_has_guid(WMI_WMMX_GUID))
+	if (!wmi_has_guid(WMI_WMMX_GUID)) {
+		MXM_DBG(dev, "WMMX GUID not found\n");
+		return false;
+	}
+
+	mxms_args[1] = wmi_wmmx_mxmi(dev, 0x00);
+	if (!mxms_args[1])
+		mxms_args[1] = wmi_wmmx_mxmi(dev, version);
+	if (!mxms_args[1])
 		return false;
 
 	status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c
index 58f4973..69a528d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_perf.c
+++ b/drivers/gpu/drm/nouveau/nouveau_perf.c
@@ -27,6 +27,178 @@
 #include "nouveau_drv.h"
 #include "nouveau_pm.h"
 
+static u8 *
+nouveau_perf_table(struct drm_device *dev, u8 *ver)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nvbios *bios = &dev_priv->vbios;
+	struct bit_entry P;
+
+	if (!bit_table(dev, 'P', &P) && P.version && P.version <= 2) {
+		u8 *perf = ROMPTR(dev, P.data[0]);
+		if (perf) {
+			*ver = perf[0];
+			return perf;
+		}
+	}
+
+	if (bios->type == NVBIOS_BMP) {
+		if (bios->data[bios->offset + 6] >= 0x25) {
+			u8 *perf = ROMPTR(dev, bios->data[bios->offset + 0x94]);
+			if (perf) {
+				*ver = perf[1];
+				return perf;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+static u8 *
+nouveau_perf_entry(struct drm_device *dev, int idx,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	u8 *perf = nouveau_perf_table(dev, ver);
+	if (perf) {
+		if (*ver >= 0x12 && *ver < 0x20 && idx < perf[2]) {
+			*hdr = perf[3];
+			*cnt = 0;
+			*len = 0;
+			return perf + perf[0] + idx * perf[3];
+		} else
+		if (*ver >= 0x20 && *ver < 0x40 && idx < perf[2]) {
+			*hdr = perf[3];
+			*cnt = perf[4];
+			*len = perf[5];
+			return perf + perf[1] + idx * (*hdr + (*cnt * *len));
+		} else
+		if (*ver >= 0x40 && *ver < 0x41 && idx < perf[5]) {
+			*hdr = perf[2];
+			*cnt = perf[4];
+			*len = perf[3];
+			return perf + perf[1] + idx * (*hdr + (*cnt * *len));
+		}
+	}
+	return NULL;
+}
+
+static u8 *
+nouveau_perf_rammap(struct drm_device *dev, u32 freq,
+		    u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct bit_entry P;
+	u8 *perf, i = 0;
+
+	if (!bit_table(dev, 'P', &P) && P.version == 2) {
+		u8 *rammap = ROMPTR(dev, P.data[4]);
+		if (rammap) {
+			u8 *ramcfg = rammap + rammap[1];
+
+			*ver = rammap[0];
+			*hdr = rammap[2];
+			*cnt = rammap[4];
+			*len = rammap[3];
+
+			freq /= 1000;
+			for (i = 0; i < rammap[5]; i++) {
+				if (freq >= ROM16(ramcfg[0]) &&
+				    freq <= ROM16(ramcfg[2]))
+					return ramcfg;
+
+				ramcfg += *hdr + (*cnt * *len);
+			}
+		}
+
+		return NULL;
+	}
+
+	if (dev_priv->chipset == 0x49 ||
+	    dev_priv->chipset == 0x4b)
+		freq /= 2;
+
+	while ((perf = nouveau_perf_entry(dev, i++, ver, hdr, cnt, len))) {
+		if (*ver >= 0x20 && *ver < 0x25) {
+			if (perf[0] != 0xff && freq <= ROM16(perf[11]) * 1000)
+				break;
+		} else
+		if (*ver >= 0x25 && *ver < 0x40) {
+			if (perf[0] != 0xff && freq <= ROM16(perf[12]) * 1000)
+				break;
+		}
+	}
+
+	if (perf) {
+		u8 *ramcfg = perf + *hdr;
+		*ver = 0x00;
+		*hdr = 0;
+		return ramcfg;
+	}
+
+	return NULL;
+}
+
+u8 *
+nouveau_perf_ramcfg(struct drm_device *dev, u32 freq, u8 *ver, u8 *len)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nvbios *bios = &dev_priv->vbios;
+	u8 strap, hdr, cnt;
+	u8 *rammap;
+
+	strap = (nv_rd32(dev, 0x101000) & 0x0000003c) >> 2;
+	if (bios->ram_restrict_tbl_ptr)
+		strap = bios->data[bios->ram_restrict_tbl_ptr + strap];
+
+	rammap = nouveau_perf_rammap(dev, freq, ver, &hdr, &cnt, len);
+	if (rammap && strap < cnt)
+		return rammap + hdr + (strap * *len);
+
+	return NULL;
+}
+
+u8 *
+nouveau_perf_timing(struct drm_device *dev, u32 freq, u8 *ver, u8 *len)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nvbios *bios = &dev_priv->vbios;
+	struct bit_entry P;
+	u8 *perf, *timing = NULL;
+	u8 i = 0, hdr, cnt;
+
+	if (bios->type == NVBIOS_BMP) {
+		while ((perf = nouveau_perf_entry(dev, i++, ver, &hdr, &cnt,
+						  len)) && *ver == 0x15) {
+			if (freq <= ROM32(perf[5]) * 20) {
+				*ver = 0x00;
+				*len = 14;
+				return perf + 41;
+			}
+		}
+		return NULL;
+	}
+
+	if (!bit_table(dev, 'P', &P)) {
+		if (P.version == 1)
+			timing = ROMPTR(dev, P.data[4]);
+		else
+		if (P.version == 2)
+			timing = ROMPTR(dev, P.data[8]);
+	}
+
+	if (timing && timing[0] == 0x10) {
+		u8 *ramcfg = nouveau_perf_ramcfg(dev, freq, ver, len);
+		if (ramcfg && ramcfg[1] < timing[2]) {
+			*ver = timing[0];
+			*len = timing[3];
+			return timing + timing[1] + (ramcfg[1] * timing[3]);
+		}
+	}
+
+	return NULL;
+}
+
 static void
 legacy_perf_init(struct drm_device *dev)
 {
@@ -72,74 +244,11 @@
 	pm->nr_perflvl = 1;
 }
 
-static struct nouveau_pm_memtiming *
-nouveau_perf_timing(struct drm_device *dev, struct bit_entry *P,
-		    u16 memclk, u8 *entry, u8 recordlen, u8 entries)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
-	struct nvbios *bios = &dev_priv->vbios;
-	u8 ramcfg;
-	int i;
-
-	/* perf v2 has a separate "timing map" table, we have to match
-	 * the target memory clock to a specific entry, *then* use
-	 * ramcfg to select the correct subentry
-	 */
-	if (P->version == 2) {
-		u8 *tmap = ROMPTR(dev, P->data[4]);
-		if (!tmap) {
-			NV_DEBUG(dev, "no timing map pointer\n");
-			return NULL;
-		}
-
-		if (tmap[0] != 0x10) {
-			NV_WARN(dev, "timing map 0x%02x unknown\n", tmap[0]);
-			return NULL;
-		}
-
-		entry = tmap + tmap[1];
-		recordlen = tmap[2] + (tmap[4] * tmap[3]);
-		for (i = 0; i < tmap[5]; i++, entry += recordlen) {
-			if (memclk >= ROM16(entry[0]) &&
-			    memclk <= ROM16(entry[2]))
-				break;
-		}
-
-		if (i == tmap[5]) {
-			NV_WARN(dev, "no match in timing map table\n");
-			return NULL;
-		}
-
-		entry += tmap[2];
-		recordlen = tmap[3];
-		entries   = tmap[4];
-	}
-
-	ramcfg = (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x0000003c) >> 2;
-	if (bios->ram_restrict_tbl_ptr)
-		ramcfg = bios->data[bios->ram_restrict_tbl_ptr + ramcfg];
-
-	if (ramcfg >= entries) {
-		NV_WARN(dev, "ramcfg strap out of bounds!\n");
-		return NULL;
-	}
-
-	entry += ramcfg * recordlen;
-	if (entry[1] >= pm->memtimings.nr_timing) {
-		if (entry[1] != 0xff)
-			NV_WARN(dev, "timingset %d does not exist\n", entry[1]);
-		return NULL;
-	}
-
-	return &pm->memtimings.timing[entry[1]];
-}
-
 static void
-nouveau_perf_voltage(struct drm_device *dev, struct bit_entry *P,
-		     struct nouveau_pm_level *perflvl)
+nouveau_perf_voltage(struct drm_device *dev, struct nouveau_pm_level *perflvl)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct bit_entry P;
 	u8 *vmap;
 	int id;
 
@@ -158,13 +267,13 @@
 	/* on newer ones, the perflvl stores an index into yet another
 	 * vbios table containing a min/max voltage value for the perflvl
 	 */
-	if (P->version != 2 || P->length < 34) {
+	if (bit_table(dev, 'P', &P) || P.version != 2 || P.length < 34) {
 		NV_DEBUG(dev, "where's our volt map table ptr? %d %d\n",
-			 P->version, P->length);
+			 P.version, P.length);
 		return;
 	}
 
-	vmap = ROMPTR(dev, P->data[32]);
+	vmap = ROMPTR(dev, P.data[32]);
 	if (!vmap) {
 		NV_DEBUG(dev, "volt map table pointer invalid\n");
 		return;
@@ -183,130 +292,70 @@
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
 	struct nvbios *bios = &dev_priv->vbios;
-	struct bit_entry P;
-	struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
-	struct nouveau_pm_tbl_header mt_hdr;
-	u8 version, headerlen, recordlen, entries;
-	u8 *perf, *entry;
-	int vid, i;
+	u8 *perf, ver, hdr, cnt, len;
+	int ret, vid, i = -1;
 
-	if (bios->type == NVBIOS_BIT) {
-		if (bit_table(dev, 'P', &P))
-			return;
-
-		if (P.version != 1 && P.version != 2) {
-			NV_WARN(dev, "unknown perf for BIT P %d\n", P.version);
-			return;
-		}
-
-		perf = ROMPTR(dev, P.data[0]);
-		version   = perf[0];
-		headerlen = perf[1];
-		if (version < 0x40) {
-			recordlen = perf[3] + (perf[4] * perf[5]);
-			entries   = perf[2];
-
-			pm->pwm_divisor = ROM16(perf[6]);
-		} else {
-			recordlen = perf[2] + (perf[3] * perf[4]);
-			entries   = perf[5];
-		}
-	} else {
-		if (bios->data[bios->offset + 6] < 0x25) {
-			legacy_perf_init(dev);
-			return;
-		}
-
-		perf = ROMPTR(dev, bios->data[bios->offset + 0x94]);
-		if (!perf) {
-			NV_DEBUG(dev, "perf table pointer invalid\n");
-			return;
-		}
-
-		version   = perf[1];
-		headerlen = perf[0];
-		recordlen = perf[3];
-		entries   = perf[2];
+	if (bios->type == NVBIOS_BMP && bios->data[bios->offset + 6] < 0x25) {
+		legacy_perf_init(dev);
+		return;
 	}
 
-	if (entries > NOUVEAU_PM_MAX_LEVEL) {
-		NV_DEBUG(dev, "perf table has too many entries - buggy vbios?\n");
-		entries = NOUVEAU_PM_MAX_LEVEL;
-	}
+	perf = nouveau_perf_table(dev, &ver);
+	if (ver >= 0x20 && ver < 0x40)
+		pm->fan.pwm_divisor = ROM16(perf[6]);
 
-	entry = perf + headerlen;
-
-	/* For version 0x15, initialize memtiming table */
-	if(version == 0x15) {
-		memtimings->timing =
-				kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL);
-		if (!memtimings->timing) {
-			NV_WARN(dev,"Could not allocate memtiming table\n");
-			return;
-		}
-
-		mt_hdr.entry_cnt = entries;
-		mt_hdr.entry_len = 14;
-		mt_hdr.version = version;
-		mt_hdr.header_len = 4;
-	}
-
-	for (i = 0; i < entries; i++) {
+	while ((perf = nouveau_perf_entry(dev, ++i, &ver, &hdr, &cnt, &len))) {
 		struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
 
-		perflvl->timing = NULL;
-
-		if (entry[0] == 0xff) {
-			entry += recordlen;
+		if (perf[0] == 0xff)
 			continue;
-		}
 
-		switch (version) {
+		switch (ver) {
 		case 0x12:
 		case 0x13:
 		case 0x15:
-			perflvl->fanspeed = entry[55];
-			if (recordlen > 56)
-				perflvl->volt_min = entry[56];
-			perflvl->core = ROM32(entry[1]) * 10;
-			perflvl->memory = ROM32(entry[5]) * 20;
+			perflvl->fanspeed = perf[55];
+			if (hdr > 56)
+				perflvl->volt_min = perf[56];
+			perflvl->core = ROM32(perf[1]) * 10;
+			perflvl->memory = ROM32(perf[5]) * 20;
 			break;
 		case 0x21:
 		case 0x23:
 		case 0x24:
-			perflvl->fanspeed = entry[4];
-			perflvl->volt_min = entry[5];
-			perflvl->shader = ROM16(entry[6]) * 1000;
+			perflvl->fanspeed = perf[4];
+			perflvl->volt_min = perf[5];
+			perflvl->shader = ROM16(perf[6]) * 1000;
 			perflvl->core = perflvl->shader;
-			perflvl->core += (signed char)entry[8] * 1000;
+			perflvl->core += (signed char)perf[8] * 1000;
 			if (dev_priv->chipset == 0x49 ||
 			    dev_priv->chipset == 0x4b)
-				perflvl->memory = ROM16(entry[11]) * 1000;
+				perflvl->memory = ROM16(perf[11]) * 1000;
 			else
-				perflvl->memory = ROM16(entry[11]) * 2000;
+				perflvl->memory = ROM16(perf[11]) * 2000;
 			break;
 		case 0x25:
-			perflvl->fanspeed = entry[4];
-			perflvl->volt_min = entry[5];
-			perflvl->core = ROM16(entry[6]) * 1000;
-			perflvl->shader = ROM16(entry[10]) * 1000;
-			perflvl->memory = ROM16(entry[12]) * 1000;
+			perflvl->fanspeed = perf[4];
+			perflvl->volt_min = perf[5];
+			perflvl->core = ROM16(perf[6]) * 1000;
+			perflvl->shader = ROM16(perf[10]) * 1000;
+			perflvl->memory = ROM16(perf[12]) * 1000;
 			break;
 		case 0x30:
-			perflvl->memscript = ROM16(entry[2]);
+			perflvl->memscript = ROM16(perf[2]);
 		case 0x35:
-			perflvl->fanspeed = entry[6];
-			perflvl->volt_min = entry[7];
-			perflvl->core = ROM16(entry[8]) * 1000;
-			perflvl->shader = ROM16(entry[10]) * 1000;
-			perflvl->memory = ROM16(entry[12]) * 1000;
-			perflvl->vdec = ROM16(entry[16]) * 1000;
-			perflvl->dom6 = ROM16(entry[20]) * 1000;
+			perflvl->fanspeed = perf[6];
+			perflvl->volt_min = perf[7];
+			perflvl->core = ROM16(perf[8]) * 1000;
+			perflvl->shader = ROM16(perf[10]) * 1000;
+			perflvl->memory = ROM16(perf[12]) * 1000;
+			perflvl->vdec = ROM16(perf[16]) * 1000;
+			perflvl->dom6 = ROM16(perf[20]) * 1000;
 			break;
 		case 0x40:
-#define subent(n) (ROM16(entry[perf[2] + ((n) * perf[3])]) & 0xfff) * 1000
+#define subent(n) ((ROM16(perf[hdr + (n) * len]) & 0xfff) * 1000)
 			perflvl->fanspeed = 0; /*XXX*/
-			perflvl->volt_min = entry[2];
+			perflvl->volt_min = perf[2];
 			if (dev_priv->card_type == NV_50) {
 				perflvl->core   = subent(0);
 				perflvl->shader = subent(1);
@@ -329,36 +378,34 @@
 		}
 
 		/* make sure vid is valid */
-		nouveau_perf_voltage(dev, &P, perflvl);
+		nouveau_perf_voltage(dev, perflvl);
 		if (pm->voltage.supported && perflvl->volt_min) {
 			vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min);
 			if (vid < 0) {
-				NV_DEBUG(dev, "drop perflvl %d, bad vid\n", i);
-				entry += recordlen;
+				NV_DEBUG(dev, "perflvl %d, bad vid\n", i);
 				continue;
 			}
 		}
 
 		/* get the corresponding memory timings */
-		if (version == 0x15) {
-			memtimings->timing[i].id = i;
-			nv30_mem_timing_entry(dev,&mt_hdr,(struct nouveau_pm_tbl_entry*) &entry[41],0,&memtimings->timing[i]);
-			perflvl->timing = &memtimings->timing[i];
-		} else if (version > 0x15) {
-			/* last 3 args are for < 0x40, ignored for >= 0x40 */
-			perflvl->timing =
-				nouveau_perf_timing(dev, &P,
-						    perflvl->memory / 1000,
-						    entry + perf[3],
-						    perf[5], perf[4]);
+		ret = nouveau_mem_timing_calc(dev, perflvl->memory,
+					          &perflvl->timing);
+		if (ret) {
+			NV_DEBUG(dev, "perflvl %d, bad timing: %d\n", i, ret);
+			continue;
 		}
 
 		snprintf(perflvl->name, sizeof(perflvl->name),
 			 "performance_level_%d", i);
 		perflvl->id = i;
-		pm->nr_perflvl++;
 
-		entry += recordlen;
+		snprintf(perflvl->profile.name, sizeof(perflvl->profile.name),
+			 "%d", perflvl->id);
+		perflvl->profile.func = &nouveau_pm_static_profile_func;
+		list_add_tail(&perflvl->profile.head, &pm->profiles);
+
+
+		pm->nr_perflvl++;
 	}
 }
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index 9064d7f..34d591b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -50,7 +50,7 @@
 	ret = nouveau_gpio_find(dev, 0, DCB_GPIO_PWM_FAN, 0xff, &gpio);
 	if (ret == 0) {
 		ret = pm->pwm_get(dev, gpio.line, &divs, &duty);
-		if (ret == 0) {
+		if (ret == 0 && divs) {
 			divs = max(divs, duty);
 			if (dev_priv->card_type <= NV_40 || (gpio.log[0] & 1))
 				duty = divs - duty;
@@ -77,7 +77,7 @@
 
 	ret = nouveau_gpio_find(dev, 0, DCB_GPIO_PWM_FAN, 0xff, &gpio);
 	if (ret == 0) {
-		divs = pm->pwm_divisor;
+		divs = pm->fan.pwm_divisor;
 		if (pm->fan.pwm_freq) {
 			/*XXX: PNVIO clock more than likely... */
 			divs = 135000 / pm->fan.pwm_freq;
@@ -89,7 +89,10 @@
 		if (dev_priv->card_type <= NV_40 || (gpio.log[0] & 1))
 			duty = divs - duty;
 
-		return pm->pwm_set(dev, gpio.line, divs, duty);
+		ret = pm->pwm_set(dev, gpio.line, divs, duty);
+		if (!ret)
+			pm->fan.percent = percent;
+		return ret;
 	}
 
 	return -ENODEV;
@@ -144,9 +147,13 @@
 		return ret;
 
 	state = pm->clocks_pre(dev, perflvl);
-	if (IS_ERR(state))
-		return PTR_ERR(state);
-	pm->clocks_set(dev, state);
+	if (IS_ERR(state)) {
+		ret = PTR_ERR(state);
+		goto error;
+	}
+	ret = pm->clocks_set(dev, state);
+	if (ret)
+		goto error;
 
 	ret = nouveau_pm_perflvl_aux(dev, perflvl, perflvl, pm->cur);
 	if (ret)
@@ -154,6 +161,65 @@
 
 	pm->cur = perflvl;
 	return 0;
+
+error:
+	/* restore the fan speed and voltage before leaving */
+	nouveau_pm_perflvl_aux(dev, perflvl, perflvl, pm->cur);
+	return ret;
+}
+
+void
+nouveau_pm_trigger(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nouveau_pm_profile *profile = NULL;
+	struct nouveau_pm_level *perflvl = NULL;
+	int ret;
+
+	/* select power profile based on current power source */
+	if (power_supply_is_system_supplied())
+		profile = pm->profile_ac;
+	else
+		profile = pm->profile_dc;
+
+	if (profile != pm->profile) {
+		pm->profile->func->fini(pm->profile);
+		pm->profile = profile;
+		pm->profile->func->init(pm->profile);
+	}
+
+	/* select performance level based on profile */
+	perflvl = profile->func->select(profile);
+
+	/* change perflvl, if necessary */
+	if (perflvl != pm->cur) {
+		struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
+		u64 time0 = ptimer->read(dev);
+
+		NV_INFO(dev, "setting performance level: %d", perflvl->id);
+		ret = nouveau_pm_perflvl_set(dev, perflvl);
+		if (ret)
+			NV_INFO(dev, "> reclocking failed: %d\n\n", ret);
+
+		NV_INFO(dev, "> reclocking took %lluns\n\n",
+			     ptimer->read(dev) - time0);
+	}
+}
+
+static struct nouveau_pm_profile *
+profile_find(struct drm_device *dev, const char *string)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nouveau_pm_profile *profile;
+
+	list_for_each_entry(profile, &pm->profiles, head) {
+		if (!strncmp(profile->name, string, sizeof(profile->name)))
+			return profile;
+	}
+
+	return NULL;
 }
 
 static int
@@ -161,33 +227,54 @@
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
-	struct nouveau_pm_level *perflvl = NULL;
+	struct nouveau_pm_profile *ac = NULL, *dc = NULL;
+	char string[16], *cur = string, *ptr;
 
 	/* safety precaution, for now */
 	if (nouveau_perflvl_wr != 7777)
 		return -EPERM;
 
-	if (!strncmp(profile, "boot", 4))
-		perflvl = &pm->boot;
-	else {
-		int pl = simple_strtol(profile, NULL, 10);
-		int i;
+	strncpy(string, profile, sizeof(string));
+	if ((ptr = strchr(string, '\n')))
+		*ptr = '\0';
 
-		for (i = 0; i < pm->nr_perflvl; i++) {
-			if (pm->perflvl[i].id == pl) {
-				perflvl = &pm->perflvl[i];
-				break;
-			}
-		}
+	ptr = strsep(&cur, ",");
+	if (ptr)
+		ac = profile_find(dev, ptr);
 
-		if (!perflvl)
-			return -EINVAL;
-	}
+	ptr = strsep(&cur, ",");
+	if (ptr)
+		dc = profile_find(dev, ptr);
+	else
+		dc = ac;
 
-	NV_INFO(dev, "setting performance level: %s\n", profile);
-	return nouveau_pm_perflvl_set(dev, perflvl);
+	if (ac == NULL || dc == NULL)
+		return -EINVAL;
+
+	pm->profile_ac = ac;
+	pm->profile_dc = dc;
+	nouveau_pm_trigger(dev);
+	return 0;
 }
 
+static void
+nouveau_pm_static_dummy(struct nouveau_pm_profile *profile)
+{
+}
+
+static struct nouveau_pm_level *
+nouveau_pm_static_select(struct nouveau_pm_profile *profile)
+{
+	return container_of(profile, struct nouveau_pm_level, profile);
+}
+
+const struct nouveau_pm_profile_func nouveau_pm_static_profile_func = {
+	.destroy = nouveau_pm_static_dummy,
+	.init = nouveau_pm_static_dummy,
+	.fini = nouveau_pm_static_dummy,
+	.select = nouveau_pm_static_select,
+};
+
 static int
 nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
 {
@@ -197,9 +284,11 @@
 
 	memset(perflvl, 0, sizeof(*perflvl));
 
-	ret = pm->clocks_get(dev, perflvl);
-	if (ret)
-		return ret;
+	if (pm->clocks_get) {
+		ret = pm->clocks_get(dev, perflvl);
+		if (ret)
+			return ret;
+	}
 
 	if (pm->voltage.supported && pm->voltage_get) {
 		ret = pm->voltage_get(dev);
@@ -213,13 +302,14 @@
 	if (ret > 0)
 		perflvl->fanspeed = ret;
 
+	nouveau_mem_timing_read(dev, &perflvl->timing);
 	return 0;
 }
 
 static void
 nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
 {
-	char c[16], s[16], v[32], f[16], t[16], m[16];
+	char c[16], s[16], v[32], f[16], m[16];
 
 	c[0] = '\0';
 	if (perflvl->core)
@@ -247,18 +337,15 @@
 	if (perflvl->fanspeed)
 		snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed);
 
-	t[0] = '\0';
-	if (perflvl->timing)
-		snprintf(t, sizeof(t), " timing %d", perflvl->timing->id);
-
-	snprintf(ptr, len, "%s%s%s%s%s%s\n", c, s, m, t, v, f);
+	snprintf(ptr, len, "%s%s%s%s%s\n", c, s, m, v, f);
 }
 
 static ssize_t
 nouveau_pm_get_perflvl_info(struct device *d,
 			    struct device_attribute *a, char *buf)
 {
-	struct nouveau_pm_level *perflvl = (struct nouveau_pm_level *)a;
+	struct nouveau_pm_level *perflvl =
+		container_of(a, struct nouveau_pm_level, dev_attr);
 	char *ptr = buf;
 	int len = PAGE_SIZE;
 
@@ -280,12 +367,8 @@
 	int len = PAGE_SIZE, ret;
 	char *ptr = buf;
 
-	if (!pm->cur)
-		snprintf(ptr, len, "setting: boot\n");
-	else if (pm->cur == &pm->boot)
-		snprintf(ptr, len, "setting: boot\nc:");
-	else
-		snprintf(ptr, len, "setting: static %d\nc:", pm->cur->id);
+	snprintf(ptr, len, "profile: %s, %s\nc:",
+		 pm->profile_ac->name, pm->profile_dc->name);
 	ptr += strlen(buf);
 	len -= strlen(buf);
 
@@ -397,7 +480,7 @@
 	struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
 	long value;
 
-	if (strict_strtol(buf, 10, &value) == -EINVAL)
+	if (kstrtol(buf, 10, &value) == -EINVAL)
 		return count;
 
 	temp->down_clock = value/1000;
@@ -432,7 +515,7 @@
 	struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
 	long value;
 
-	if (strict_strtol(buf, 10, &value) == -EINVAL)
+	if (kstrtol(buf, 10, &value) == -EINVAL)
 		return count;
 
 	temp->critical = value/1000;
@@ -529,7 +612,7 @@
 	if (nouveau_perflvl_wr != 7777)
 		return -EPERM;
 
-	if (strict_strtol(buf, 10, &value) == -EINVAL)
+	if (kstrtol(buf, 10, &value) == -EINVAL)
 		return -EINVAL;
 
 	if (value < pm->fan.min_duty)
@@ -568,7 +651,7 @@
 	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
 	long value;
 
-	if (strict_strtol(buf, 10, &value) == -EINVAL)
+	if (kstrtol(buf, 10, &value) == -EINVAL)
 		return -EINVAL;
 
 	if (value < 0)
@@ -609,7 +692,7 @@
 	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
 	long value;
 
-	if (strict_strtol(buf, 10, &value) == -EINVAL)
+	if (kstrtol(buf, 10, &value) == -EINVAL)
 		return -EINVAL;
 
 	if (value < 0)
@@ -731,8 +814,10 @@
 
 	if (pm->hwmon) {
 		sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_attrgroup);
-		sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_pwm_fan_attrgroup);
-		sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_fan_rpm_attrgroup);
+		sysfs_remove_group(&dev->pdev->dev.kobj,
+				   &hwmon_pwm_fan_attrgroup);
+		sysfs_remove_group(&dev->pdev->dev.kobj,
+				   &hwmon_fan_rpm_attrgroup);
 
 		hwmon_device_unregister(pm->hwmon);
 	}
@@ -752,6 +837,7 @@
 		bool ac = power_supply_is_system_supplied();
 
 		NV_DEBUG(dev, "power supply changed: %s\n", ac ? "AC" : "DC");
+		nouveau_pm_trigger(dev);
 	}
 
 	return NOTIFY_OK;
@@ -766,35 +852,48 @@
 	char info[256];
 	int ret, i;
 
-	nouveau_mem_timing_init(dev);
+	/* parse aux tables from vbios */
 	nouveau_volt_init(dev);
-	nouveau_perf_init(dev);
 	nouveau_temp_init(dev);
 
+	/* determine current ("boot") performance level */
+	ret = nouveau_pm_perflvl_get(dev, &pm->boot);
+	if (ret) {
+		NV_ERROR(dev, "failed to determine boot perflvl\n");
+		return ret;
+	}
+
+	strncpy(pm->boot.name, "boot", 4);
+	strncpy(pm->boot.profile.name, "boot", 4);
+	pm->boot.profile.func = &nouveau_pm_static_profile_func;
+
+	INIT_LIST_HEAD(&pm->profiles);
+	list_add(&pm->boot.profile.head, &pm->profiles);
+
+	pm->profile_ac = &pm->boot.profile;
+	pm->profile_dc = &pm->boot.profile;
+	pm->profile = &pm->boot.profile;
+	pm->cur = &pm->boot;
+
+	/* add performance levels from vbios */
+	nouveau_perf_init(dev);
+
+	/* display available performance levels */
 	NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl);
 	for (i = 0; i < pm->nr_perflvl; i++) {
 		nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info));
 		NV_INFO(dev, "%d:%s", pm->perflvl[i].id, info);
 	}
 
-	/* determine current ("boot") performance level */
-	ret = nouveau_pm_perflvl_get(dev, &pm->boot);
-	if (ret == 0) {
-		strncpy(pm->boot.name, "boot", 4);
-		pm->cur = &pm->boot;
-
-		nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
-		NV_INFO(dev, "c:%s", info);
-	}
+	nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
+	NV_INFO(dev, "c:%s", info);
 
 	/* switch performance levels now if requested */
-	if (nouveau_perflvl != NULL) {
-		ret = nouveau_pm_profile_set(dev, nouveau_perflvl);
-		if (ret) {
-			NV_ERROR(dev, "error setting perflvl \"%s\": %d\n",
-				 nouveau_perflvl, ret);
-		}
-	}
+	if (nouveau_perflvl != NULL)
+		nouveau_pm_profile_set(dev, nouveau_perflvl);
+
+	/* determine the current fan speed */
+	pm->fan.percent = nouveau_pwmfan_get(dev);
 
 	nouveau_sysfs_init(dev);
 	nouveau_hwmon_init(dev);
@@ -811,6 +910,12 @@
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nouveau_pm_profile *profile, *tmp;
+
+	list_for_each_entry_safe(profile, tmp, &pm->profiles, head) {
+		list_del(&profile->head);
+		profile->func->destroy(profile);
+	}
 
 	if (pm->cur != &pm->boot)
 		nouveau_pm_perflvl_set(dev, &pm->boot);
@@ -818,7 +923,6 @@
 	nouveau_temp_fini(dev);
 	nouveau_perf_fini(dev);
 	nouveau_volt_fini(dev);
-	nouveau_mem_timing_fini(dev);
 
 #if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
 	unregister_acpi_notifier(&pm->acpi_nb);
@@ -840,4 +944,5 @@
 	perflvl = pm->cur;
 	pm->cur = &pm->boot;
 	nouveau_pm_perflvl_set(dev, perflvl);
+	nouveau_pwmfan_set(dev, pm->fan.percent);
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h
index 2f8e14f..3f82dfe 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.h
@@ -25,10 +25,30 @@
 #ifndef __NOUVEAU_PM_H__
 #define __NOUVEAU_PM_H__
 
+struct nouveau_mem_exec_func {
+	struct drm_device *dev;
+	void (*precharge)(struct nouveau_mem_exec_func *);
+	void (*refresh)(struct nouveau_mem_exec_func *);
+	void (*refresh_auto)(struct nouveau_mem_exec_func *, bool);
+	void (*refresh_self)(struct nouveau_mem_exec_func *, bool);
+	void (*wait)(struct nouveau_mem_exec_func *, u32 nsec);
+	u32  (*mrg)(struct nouveau_mem_exec_func *, int mr);
+	void (*mrs)(struct nouveau_mem_exec_func *, int mr, u32 data);
+	void (*clock_set)(struct nouveau_mem_exec_func *);
+	void (*timing_set)(struct nouveau_mem_exec_func *);
+	void *priv;
+};
+
+/* nouveau_mem.c */
+int  nouveau_mem_exec(struct nouveau_mem_exec_func *,
+		      struct nouveau_pm_level *);
+
 /* nouveau_pm.c */
 int  nouveau_pm_init(struct drm_device *dev);
 void nouveau_pm_fini(struct drm_device *dev);
 void nouveau_pm_resume(struct drm_device *dev);
+extern const struct nouveau_pm_profile_func nouveau_pm_static_profile_func;
+void nouveau_pm_trigger(struct drm_device *dev);
 
 /* nouveau_volt.c */
 void nouveau_volt_init(struct drm_device *);
@@ -41,6 +61,8 @@
 /* nouveau_perf.c */
 void nouveau_perf_init(struct drm_device *);
 void nouveau_perf_fini(struct drm_device *);
+u8 *nouveau_perf_timing(struct drm_device *, u32 freq, u8 *ver, u8 *len);
+u8 *nouveau_perf_ramcfg(struct drm_device *, u32 freq, u8 *ver, u8 *len);
 
 /* nouveau_mem.c */
 void nouveau_mem_timing_init(struct drm_device *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index f80c5e0..c2a8511 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -87,7 +87,7 @@
 		engine->pm.clocks_get		= nv04_pm_clocks_get;
 		engine->pm.clocks_pre		= nv04_pm_clocks_pre;
 		engine->pm.clocks_set		= nv04_pm_clocks_set;
-		engine->vram.init		= nouveau_mem_detect;
+		engine->vram.init		= nv04_fb_vram_init;
 		engine->vram.takedown		= nouveau_stub_takedown;
 		engine->vram.flags_valid	= nouveau_mem_flags_valid;
 		break;
@@ -134,7 +134,11 @@
 		engine->pm.clocks_get		= nv04_pm_clocks_get;
 		engine->pm.clocks_pre		= nv04_pm_clocks_pre;
 		engine->pm.clocks_set		= nv04_pm_clocks_set;
-		engine->vram.init		= nouveau_mem_detect;
+		if (dev_priv->chipset == 0x1a ||
+		    dev_priv->chipset == 0x1f)
+			engine->vram.init	= nv1a_fb_vram_init;
+		else
+			engine->vram.init	= nv10_fb_vram_init;
 		engine->vram.takedown		= nouveau_stub_takedown;
 		engine->vram.flags_valid	= nouveau_mem_flags_valid;
 		break;
@@ -153,11 +157,11 @@
 		engine->timer.init		= nv04_timer_init;
 		engine->timer.read		= nv04_timer_read;
 		engine->timer.takedown		= nv04_timer_takedown;
-		engine->fb.init			= nv10_fb_init;
-		engine->fb.takedown		= nv10_fb_takedown;
-		engine->fb.init_tile_region	= nv10_fb_init_tile_region;
-		engine->fb.set_tile_region	= nv10_fb_set_tile_region;
-		engine->fb.free_tile_region	= nv10_fb_free_tile_region;
+		engine->fb.init			= nv20_fb_init;
+		engine->fb.takedown		= nv20_fb_takedown;
+		engine->fb.init_tile_region	= nv20_fb_init_tile_region;
+		engine->fb.set_tile_region	= nv20_fb_set_tile_region;
+		engine->fb.free_tile_region	= nv20_fb_free_tile_region;
 		engine->fifo.channels		= 32;
 		engine->fifo.init		= nv10_fifo_init;
 		engine->fifo.takedown		= nv04_fifo_fini;
@@ -181,7 +185,7 @@
 		engine->pm.clocks_get		= nv04_pm_clocks_get;
 		engine->pm.clocks_pre		= nv04_pm_clocks_pre;
 		engine->pm.clocks_set		= nv04_pm_clocks_set;
-		engine->vram.init		= nouveau_mem_detect;
+		engine->vram.init		= nv20_fb_vram_init;
 		engine->vram.takedown		= nouveau_stub_takedown;
 		engine->vram.flags_valid	= nouveau_mem_flags_valid;
 		break;
@@ -230,7 +234,7 @@
 		engine->pm.clocks_set		= nv04_pm_clocks_set;
 		engine->pm.voltage_get		= nouveau_voltage_gpio_get;
 		engine->pm.voltage_set		= nouveau_voltage_gpio_set;
-		engine->vram.init		= nouveau_mem_detect;
+		engine->vram.init		= nv20_fb_vram_init;
 		engine->vram.takedown		= nouveau_stub_takedown;
 		engine->vram.flags_valid	= nouveau_mem_flags_valid;
 		break;
@@ -286,7 +290,7 @@
 		engine->pm.temp_get		= nv40_temp_get;
 		engine->pm.pwm_get		= nv40_pm_pwm_get;
 		engine->pm.pwm_set		= nv40_pm_pwm_set;
-		engine->vram.init		= nouveau_mem_detect;
+		engine->vram.init		= nv40_fb_vram_init;
 		engine->vram.takedown		= nouveau_stub_takedown;
 		engine->vram.flags_valid	= nouveau_mem_flags_valid;
 		break;
@@ -475,6 +479,47 @@
 		engine->pm.voltage_get		= nouveau_voltage_gpio_get;
 		engine->pm.voltage_set		= nouveau_voltage_gpio_set;
 		break;
+	case 0xe0:
+		engine->instmem.init		= nvc0_instmem_init;
+		engine->instmem.takedown	= nvc0_instmem_takedown;
+		engine->instmem.suspend		= nvc0_instmem_suspend;
+		engine->instmem.resume		= nvc0_instmem_resume;
+		engine->instmem.get		= nv50_instmem_get;
+		engine->instmem.put		= nv50_instmem_put;
+		engine->instmem.map		= nv50_instmem_map;
+		engine->instmem.unmap		= nv50_instmem_unmap;
+		engine->instmem.flush		= nv84_instmem_flush;
+		engine->mc.init			= nv50_mc_init;
+		engine->mc.takedown		= nv50_mc_takedown;
+		engine->timer.init		= nv04_timer_init;
+		engine->timer.read		= nv04_timer_read;
+		engine->timer.takedown		= nv04_timer_takedown;
+		engine->fb.init			= nvc0_fb_init;
+		engine->fb.takedown		= nvc0_fb_takedown;
+		engine->fifo.channels		= 0;
+		engine->fifo.init		= nouveau_stub_init;
+		engine->fifo.takedown		= nouveau_stub_takedown;
+		engine->fifo.disable		= nvc0_fifo_disable;
+		engine->fifo.enable		= nvc0_fifo_enable;
+		engine->fifo.reassign		= nvc0_fifo_reassign;
+		engine->fifo.unload_context	= nouveau_stub_init;
+		engine->display.early_init	= nouveau_stub_init;
+		engine->display.late_takedown	= nouveau_stub_takedown;
+		engine->display.create		= nvd0_display_create;
+		engine->display.destroy		= nvd0_display_destroy;
+		engine->display.init		= nvd0_display_init;
+		engine->display.fini		= nvd0_display_fini;
+		engine->gpio.init		= nv50_gpio_init;
+		engine->gpio.fini		= nv50_gpio_fini;
+		engine->gpio.drive		= nvd0_gpio_drive;
+		engine->gpio.sense		= nvd0_gpio_sense;
+		engine->gpio.irq_enable		= nv50_gpio_irq_enable;
+		engine->vram.init		= nvc0_vram_init;
+		engine->vram.takedown		= nv50_vram_fini;
+		engine->vram.get		= nvc0_vram_new;
+		engine->vram.put		= nv50_vram_del;
+		engine->vram.flags_valid	= nvc0_vram_flags_valid;
+		break;
 	default:
 		NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset);
 		return 1;
@@ -548,6 +593,75 @@
 	return can_switch;
 }
 
+static void
+nouveau_card_channel_fini(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+	if (dev_priv->channel)
+		nouveau_channel_put_unlocked(&dev_priv->channel);
+}
+
+static int
+nouveau_card_channel_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_channel *chan;
+	int ret, oclass;
+
+	ret = nouveau_channel_alloc(dev, &chan, NULL, NvDmaFB, NvDmaTT);
+	dev_priv->channel = chan;
+	if (ret)
+		return ret;
+
+	mutex_unlock(&dev_priv->channel->mutex);
+
+	if (dev_priv->card_type <= NV_50) {
+		if (dev_priv->card_type < NV_50)
+			oclass = 0x0039;
+		else
+			oclass = 0x5039;
+
+		ret = nouveau_gpuobj_gr_new(chan, NvM2MF, oclass);
+		if (ret)
+			goto error;
+
+		ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000,
+					     &chan->m2mf_ntfy);
+		if (ret)
+			goto error;
+
+		ret = RING_SPACE(chan, 6);
+		if (ret)
+			goto error;
+
+		BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NAME, 1);
+		OUT_RING  (chan, NvM2MF);
+		BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 3);
+		OUT_RING  (chan, NvNotify0);
+		OUT_RING  (chan, chan->vram_handle);
+		OUT_RING  (chan, chan->gart_handle);
+	} else
+	if (dev_priv->card_type <= NV_D0) {
+		ret = nouveau_gpuobj_gr_new(chan, 0x9039, 0x9039);
+		if (ret)
+			goto error;
+
+		ret = RING_SPACE(chan, 2);
+		if (ret)
+			goto error;
+
+		BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0000, 1);
+		OUT_RING  (chan, 0x00009039);
+	}
+
+	FIRE_RING (chan);
+error:
+	if (ret)
+		nouveau_card_channel_fini(dev);
+	return ret;
+}
+
 int
 nouveau_card_init(struct drm_device *dev)
 {
@@ -588,16 +702,34 @@
 		nv_mask(dev, 0x00088080, 0x00000800, 0x00000000);
 	}
 
-	nouveau_pm_init(dev);
-
-	ret = engine->vram.init(dev);
+	/* PMC */
+	ret = engine->mc.init(dev);
 	if (ret)
 		goto out_bios;
 
-	ret = nouveau_gpuobj_init(dev);
+	/* PTIMER */
+	ret = engine->timer.init(dev);
+	if (ret)
+		goto out_mc;
+
+	/* PFB */
+	ret = engine->fb.init(dev);
+	if (ret)
+		goto out_timer;
+
+	ret = engine->vram.init(dev);
+	if (ret)
+		goto out_fb;
+
+	/* PGPIO */
+	ret = nouveau_gpio_create(dev);
 	if (ret)
 		goto out_vram;
 
+	ret = nouveau_gpuobj_init(dev);
+	if (ret)
+		goto out_gpio;
+
 	ret = engine->instmem.init(dev);
 	if (ret)
 		goto out_gpuobj;
@@ -610,26 +742,6 @@
 	if (ret)
 		goto out_ttmvram;
 
-	/* PMC */
-	ret = engine->mc.init(dev);
-	if (ret)
-		goto out_gart;
-
-	/* PGPIO */
-	ret = nouveau_gpio_create(dev);
-	if (ret)
-		goto out_mc;
-
-	/* PTIMER */
-	ret = engine->timer.init(dev);
-	if (ret)
-		goto out_gpio;
-
-	/* PFB */
-	ret = engine->fb.init(dev);
-	if (ret)
-		goto out_timer;
-
 	if (!dev_priv->noaccel) {
 		switch (dev_priv->card_type) {
 		case NV_04:
@@ -734,18 +846,16 @@
 		goto out_irq;
 
 	nouveau_backlight_init(dev);
+	nouveau_pm_init(dev);
+
+	ret = nouveau_fence_init(dev);
+	if (ret)
+		goto out_pm;
 
 	if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
-		ret = nouveau_fence_init(dev);
-		if (ret)
-			goto out_disp;
-
-		ret = nouveau_channel_alloc(dev, &dev_priv->channel, NULL,
-					    NvDmaFB, NvDmaTT);
+		ret = nouveau_card_channel_init(dev);
 		if (ret)
 			goto out_fence;
-
-		mutex_unlock(&dev_priv->channel->mutex);
 	}
 
 	if (dev->mode_config.num_crtc) {
@@ -759,10 +869,11 @@
 	return 0;
 
 out_chan:
-	nouveau_channel_put_unlocked(&dev_priv->channel);
+	nouveau_card_channel_fini(dev);
 out_fence:
 	nouveau_fence_fini(dev);
-out_disp:
+out_pm:
+	nouveau_pm_fini(dev);
 	nouveau_backlight_exit(dev);
 	nouveau_display_destroy(dev);
 out_irq:
@@ -779,15 +890,6 @@
 			dev_priv->eng[e]->destroy(dev,e );
 		}
 	}
-
-	engine->fb.takedown(dev);
-out_timer:
-	engine->timer.takedown(dev);
-out_gpio:
-	nouveau_gpio_destroy(dev);
-out_mc:
-	engine->mc.takedown(dev);
-out_gart:
 	nouveau_mem_gart_fini(dev);
 out_ttmvram:
 	nouveau_mem_vram_fini(dev);
@@ -795,10 +897,17 @@
 	engine->instmem.takedown(dev);
 out_gpuobj:
 	nouveau_gpuobj_takedown(dev);
+out_gpio:
+	nouveau_gpio_destroy(dev);
 out_vram:
 	engine->vram.takedown(dev);
+out_fb:
+	engine->fb.takedown(dev);
+out_timer:
+	engine->timer.takedown(dev);
+out_mc:
+	engine->mc.takedown(dev);
 out_bios:
-	nouveau_pm_fini(dev);
 	nouveau_bios_takedown(dev);
 out_display_early:
 	engine->display.late_takedown(dev);
@@ -818,11 +927,9 @@
 		nouveau_display_fini(dev);
 	}
 
-	if (dev_priv->channel) {
-		nouveau_channel_put_unlocked(&dev_priv->channel);
-		nouveau_fence_fini(dev);
-	}
-
+	nouveau_card_channel_fini(dev);
+	nouveau_fence_fini(dev);
+	nouveau_pm_fini(dev);
 	nouveau_backlight_exit(dev);
 	nouveau_display_destroy(dev);
 
@@ -835,11 +942,6 @@
 			}
 		}
 	}
-	engine->fb.takedown(dev);
-	engine->timer.takedown(dev);
-	nouveau_gpio_destroy(dev);
-	engine->mc.takedown(dev);
-	engine->display.late_takedown(dev);
 
 	if (dev_priv->vga_ram) {
 		nouveau_bo_unpin(dev_priv->vga_ram);
@@ -855,13 +957,18 @@
 
 	engine->instmem.takedown(dev);
 	nouveau_gpuobj_takedown(dev);
+
+	nouveau_gpio_destroy(dev);
 	engine->vram.takedown(dev);
+	engine->fb.takedown(dev);
+	engine->timer.takedown(dev);
+	engine->mc.takedown(dev);
+
+	nouveau_bios_takedown(dev);
+	engine->display.late_takedown(dev);
 
 	nouveau_irq_fini(dev);
 
-	nouveau_pm_fini(dev);
-	nouveau_bios_takedown(dev);
-
 	vga_client_register(dev->pdev, NULL, NULL, NULL);
 }
 
@@ -990,8 +1097,8 @@
 int nouveau_load(struct drm_device *dev, unsigned long flags)
 {
 	struct drm_nouveau_private *dev_priv;
-	uint32_t reg0, strap;
-	resource_size_t mmio_start_offs;
+	unsigned long long offset, length;
+	uint32_t reg0 = ~0, strap;
 	int ret;
 
 	dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
@@ -1002,83 +1109,90 @@
 	dev->dev_private = dev_priv;
 	dev_priv->dev = dev;
 
+	pci_set_master(dev->pdev);
+
 	dev_priv->flags = flags & NOUVEAU_FLAGS;
 
 	NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n",
 		 dev->pci_vendor, dev->pci_device, dev->pdev->class);
 
-	/* resource 0 is mmio regs */
-	/* resource 1 is linear FB */
-	/* resource 2 is RAMIN (mmio regs + 0x1000000) */
-	/* resource 6 is bios */
+	/* first up, map the start of mmio and determine the chipset */
+	dev_priv->mmio = ioremap(pci_resource_start(dev->pdev, 0), PAGE_SIZE);
+	if (dev_priv->mmio) {
+#ifdef __BIG_ENDIAN
+		/* put the card into big-endian mode if it's not */
+		if (nv_rd32(dev, NV03_PMC_BOOT_1) != 0x01000001)
+			nv_wr32(dev, NV03_PMC_BOOT_1, 0x01000001);
+		DRM_MEMORYBARRIER();
+#endif
 
-	/* map the mmio regs */
-	mmio_start_offs = pci_resource_start(dev->pdev, 0);
-	dev_priv->mmio = ioremap(mmio_start_offs, 0x00800000);
+		/* determine chipset and derive architecture from it */
+		reg0 = nv_rd32(dev, NV03_PMC_BOOT_0);
+		if ((reg0 & 0x0f000000) > 0) {
+			dev_priv->chipset = (reg0 & 0xff00000) >> 20;
+			switch (dev_priv->chipset & 0xf0) {
+			case 0x10:
+			case 0x20:
+			case 0x30:
+				dev_priv->card_type = dev_priv->chipset & 0xf0;
+				break;
+			case 0x40:
+			case 0x60:
+				dev_priv->card_type = NV_40;
+				break;
+			case 0x50:
+			case 0x80:
+			case 0x90:
+			case 0xa0:
+				dev_priv->card_type = NV_50;
+				break;
+			case 0xc0:
+				dev_priv->card_type = NV_C0;
+				break;
+			case 0xd0:
+				dev_priv->card_type = NV_D0;
+				break;
+			case 0xe0:
+				dev_priv->card_type = NV_E0;
+				break;
+			default:
+				break;
+			}
+		} else
+		if ((reg0 & 0xff00fff0) == 0x20004000) {
+			if (reg0 & 0x00f00000)
+				dev_priv->chipset = 0x05;
+			else
+				dev_priv->chipset = 0x04;
+			dev_priv->card_type = NV_04;
+		}
+
+		iounmap(dev_priv->mmio);
+	}
+
+	if (!dev_priv->card_type) {
+		NV_ERROR(dev, "unsupported chipset 0x%08x\n", reg0);
+		ret = -EINVAL;
+		goto err_priv;
+	}
+
+	NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
+		     dev_priv->card_type, reg0);
+
+	/* map the mmio regs, limiting the amount to preserve vmap space */
+	offset = pci_resource_start(dev->pdev, 0);
+	length = pci_resource_len(dev->pdev, 0);
+	if (dev_priv->card_type < NV_E0)
+		length = min(length, (unsigned long long)0x00800000);
+
+	dev_priv->mmio = ioremap(offset, length);
 	if (!dev_priv->mmio) {
 		NV_ERROR(dev, "Unable to initialize the mmio mapping. "
 			 "Please report your setup to " DRIVER_EMAIL "\n");
 		ret = -EINVAL;
 		goto err_priv;
 	}
-	NV_DEBUG(dev, "regs mapped ok at 0x%llx\n",
-					(unsigned long long)mmio_start_offs);
-
-#ifdef __BIG_ENDIAN
-	/* Put the card in BE mode if it's not */
-	if (nv_rd32(dev, NV03_PMC_BOOT_1) != 0x01000001)
-		nv_wr32(dev, NV03_PMC_BOOT_1, 0x01000001);
-
-	DRM_MEMORYBARRIER();
-#endif
-
-	/* Time to determine the card architecture */
-	reg0 = nv_rd32(dev, NV03_PMC_BOOT_0);
-
-	/* We're dealing with >=NV10 */
-	if ((reg0 & 0x0f000000) > 0) {
-		/* Bit 27-20 contain the architecture in hex */
-		dev_priv->chipset = (reg0 & 0xff00000) >> 20;
-	/* NV04 or NV05 */
-	} else if ((reg0 & 0xff00fff0) == 0x20004000) {
-		if (reg0 & 0x00f00000)
-			dev_priv->chipset = 0x05;
-		else
-			dev_priv->chipset = 0x04;
-	} else
-		dev_priv->chipset = 0xff;
-
-	switch (dev_priv->chipset & 0xf0) {
-	case 0x00:
-	case 0x10:
-	case 0x20:
-	case 0x30:
-		dev_priv->card_type = dev_priv->chipset & 0xf0;
-		break;
-	case 0x40:
-	case 0x60:
-		dev_priv->card_type = NV_40;
-		break;
-	case 0x50:
-	case 0x80:
-	case 0x90:
-	case 0xa0:
-		dev_priv->card_type = NV_50;
-		break;
-	case 0xc0:
-		dev_priv->card_type = NV_C0;
-		break;
-	case 0xd0:
-		dev_priv->card_type = NV_D0;
-		break;
-	default:
-		NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0);
-		ret = -EINVAL;
-		goto err_mmio;
-	}
-
-	NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
-		dev_priv->card_type, reg0);
+	NV_DEBUG(dev, "regs mapped ok at 0x%llx\n", offset);
 
 	/* determine frequency of timing crystal */
 	strap = nv_rd32(dev, 0x101000);
@@ -1136,7 +1250,7 @@
 		}
 	} else {
 		dev_priv->ramin_size = 1 * 1024 * 1024;
-		dev_priv->ramin = ioremap(mmio_start_offs + NV_RAMIN,
+		dev_priv->ramin = ioremap(offset + NV_RAMIN,
 					  dev_priv->ramin_size);
 		if (!dev_priv->ramin) {
 			NV_ERROR(dev, "Failed to map BAR0 PRAMIN.\n");
diff --git a/drivers/gpu/drm/nouveau/nv04_fb.c b/drivers/gpu/drm/nouveau/nv04_fb.c
index 638cf60..d5eedd6 100644
--- a/drivers/gpu/drm/nouveau/nv04_fb.c
+++ b/drivers/gpu/drm/nouveau/nv04_fb.c
@@ -4,6 +4,40 @@
 #include "nouveau_drm.h"
 
 int
+nv04_fb_vram_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	u32 boot0 = nv_rd32(dev, NV04_PFB_BOOT_0);
+
+	if (boot0 & 0x00000100) {
+		dev_priv->vram_size  = ((boot0 >> 12) & 0xf) * 2 + 2;
+		dev_priv->vram_size *= 1024 * 1024;
+	} else {
+		switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
+		case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
+			dev_priv->vram_size = 32 * 1024 * 1024;
+			break;
+		case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
+			dev_priv->vram_size = 16 * 1024 * 1024;
+			break;
+		case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
+			dev_priv->vram_size = 8 * 1024 * 1024;
+			break;
+		case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
+			dev_priv->vram_size = 4 * 1024 * 1024;
+			break;
+		}
+	}
+
+	if ((boot0 & 0x00000038) <= 0x10)
+		dev_priv->vram_type = NV_MEM_TYPE_SGRAM;
+	else
+		dev_priv->vram_type = NV_MEM_TYPE_SDRAM;
+
+	return 0;
+}
+
+int
 nv04_fb_init(struct drm_device *dev)
 {
 	/* This is what the DDX did for NV_ARCH_04, but a mmio-trace shows
diff --git a/drivers/gpu/drm/nouveau/nv10_fb.c b/drivers/gpu/drm/nouveau/nv10_fb.c
index f78181a..420b1608 100644
--- a/drivers/gpu/drm/nouveau/nv10_fb.c
+++ b/drivers/gpu/drm/nouveau/nv10_fb.c
@@ -3,81 +3,16 @@
 #include "nouveau_drv.h"
 #include "nouveau_drm.h"
 
-static struct drm_mm_node *
-nv20_fb_alloc_tag(struct drm_device *dev, uint32_t size)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
-	struct drm_mm_node *mem;
-	int ret;
-
-	ret = drm_mm_pre_get(&pfb->tag_heap);
-	if (ret)
-		return NULL;
-
-	spin_lock(&dev_priv->tile.lock);
-	mem = drm_mm_search_free(&pfb->tag_heap, size, 0, 0);
-	if (mem)
-		mem = drm_mm_get_block_atomic(mem, size, 0);
-	spin_unlock(&dev_priv->tile.lock);
-
-	return mem;
-}
-
-static void
-nv20_fb_free_tag(struct drm_device *dev, struct drm_mm_node *mem)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-	spin_lock(&dev_priv->tile.lock);
-	drm_mm_put_block(mem);
-	spin_unlock(&dev_priv->tile.lock);
-}
-
 void
 nv10_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr,
 			 uint32_t size, uint32_t pitch, uint32_t flags)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
-	int bpp = (flags & NOUVEAU_GEM_TILE_32BPP ? 32 : 16);
 
-	tile->addr = addr;
+	tile->addr  = 0x80000000 | addr;
 	tile->limit = max(1u, addr + size) - 1;
 	tile->pitch = pitch;
-
-	if (dev_priv->card_type == NV_20) {
-		if (flags & NOUVEAU_GEM_TILE_ZETA) {
-			/*
-			 * Allocate some of the on-die tag memory,
-			 * used to store Z compression meta-data (most
-			 * likely just a bitmap determining if a given
-			 * tile is compressed or not).
-			 */
-			tile->tag_mem = nv20_fb_alloc_tag(dev, size / 256);
-
-			if (tile->tag_mem) {
-				/* Enable Z compression */
-				if (dev_priv->chipset >= 0x25)
-					tile->zcomp = tile->tag_mem->start |
-						(bpp == 16 ?
-						 NV25_PFB_ZCOMP_MODE_16 :
-						 NV25_PFB_ZCOMP_MODE_32);
-				else
-					tile->zcomp = tile->tag_mem->start |
-						NV20_PFB_ZCOMP_EN |
-						(bpp == 16 ? 0 :
-						 NV20_PFB_ZCOMP_MODE_32);
-			}
-
-			tile->addr |= 3;
-		} else {
-			tile->addr |= 1;
-		}
-
-	} else {
-		tile->addr |= 1 << 31;
-	}
 }
 
 void
@@ -86,11 +21,6 @@
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
 
-	if (tile->tag_mem) {
-		nv20_fb_free_tag(dev, tile->tag_mem);
-		tile->tag_mem = NULL;
-	}
-
 	tile->addr = tile->limit = tile->pitch = tile->zcomp = 0;
 }
 
@@ -103,9 +33,48 @@
 	nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit);
 	nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch);
 	nv_wr32(dev, NV10_PFB_TILE(i), tile->addr);
+}
 
-	if (dev_priv->card_type == NV_20)
-		nv_wr32(dev, NV20_PFB_ZCOMP(i), tile->zcomp);
+int
+nv1a_fb_vram_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct pci_dev *bridge;
+	uint32_t mem, mib;
+
+	bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
+	if (!bridge) {
+		NV_ERROR(dev, "no bridge device\n");
+		return 0;
+	}
+
+	if (dev_priv->chipset == 0x1a) {
+		pci_read_config_dword(bridge, 0x7c, &mem);
+		mib = ((mem >> 6) & 31) + 1;
+	} else {
+		pci_read_config_dword(bridge, 0x84, &mem);
+		mib = ((mem >> 4) & 127) + 1;
+	}
+
+	dev_priv->vram_size = mib * 1024 * 1024;
+	return 0;
+}
+
+int
+nv10_fb_vram_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	u32 fifo_data = nv_rd32(dev, NV04_PFB_FIFO_DATA);
+	u32 cfg0 = nv_rd32(dev, 0x100200);
+
+	dev_priv->vram_size = fifo_data & NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK;
+
+	if (cfg0 & 0x00000001)
+		dev_priv->vram_type = NV_MEM_TYPE_DDR1;
+	else
+		dev_priv->vram_type = NV_MEM_TYPE_SDRAM;
+
+	return 0;
 }
 
 int
@@ -115,14 +84,8 @@
 	struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
 	int i;
 
-	pfb->num_tiles = NV10_PFB_TILE__SIZE;
-
-	if (dev_priv->card_type == NV_20)
-		drm_mm_init(&pfb->tag_heap, 0,
-			    (dev_priv->chipset >= 0x25 ?
-			     64 * 1024 : 32 * 1024));
-
 	/* Turn all the tiling regions off. */
+	pfb->num_tiles = NV10_PFB_TILE__SIZE;
 	for (i = 0; i < pfb->num_tiles; i++)
 		pfb->set_tile_region(dev, i);
 
@@ -138,7 +101,4 @@
 
 	for (i = 0; i < pfb->num_tiles; i++)
 		pfb->free_tile_region(dev, i);
-
-	if (dev_priv->card_type == NV_20)
-		drm_mm_takedown(&pfb->tag_heap);
 }
diff --git a/drivers/gpu/drm/nouveau/nv20_fb.c b/drivers/gpu/drm/nouveau/nv20_fb.c
new file mode 100644
index 0000000..19bd640
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv20_fb.c
@@ -0,0 +1,148 @@
+#include "drmP.h"
+#include "drm.h"
+#include "nouveau_drv.h"
+#include "nouveau_drm.h"
+
+static struct drm_mm_node *
+nv20_fb_alloc_tag(struct drm_device *dev, uint32_t size)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+	struct drm_mm_node *mem;
+	int ret;
+
+	ret = drm_mm_pre_get(&pfb->tag_heap);
+	if (ret)
+		return NULL;
+
+	spin_lock(&dev_priv->tile.lock);
+	mem = drm_mm_search_free(&pfb->tag_heap, size, 0, 0);
+	if (mem)
+		mem = drm_mm_get_block_atomic(mem, size, 0);
+	spin_unlock(&dev_priv->tile.lock);
+
+	return mem;
+}
+
+static void
+nv20_fb_free_tag(struct drm_device *dev, struct drm_mm_node **pmem)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct drm_mm_node *mem = *pmem;
+	if (mem) {
+		spin_lock(&dev_priv->tile.lock);
+		drm_mm_put_block(mem);
+		spin_unlock(&dev_priv->tile.lock);
+		*pmem = NULL;
+	}
+}
+
+void
+nv20_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr,
+			 uint32_t size, uint32_t pitch, uint32_t flags)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+	int bpp = (flags & NOUVEAU_GEM_TILE_32BPP ? 32 : 16);
+
+	tile->addr  = 0x00000001 | addr;
+	tile->limit = max(1u, addr + size) - 1;
+	tile->pitch = pitch;
+
+	/* Allocate some of the on-die tag memory, used to store Z
+	 * compression meta-data (most likely just a bitmap determining
+	 * if a given tile is compressed or not).
+	 */
+	if (flags & NOUVEAU_GEM_TILE_ZETA) {
+		tile->tag_mem = nv20_fb_alloc_tag(dev, size / 256);
+		if (tile->tag_mem) {
+			/* Enable Z compression */
+			tile->zcomp = tile->tag_mem->start;
+			if (dev_priv->chipset >= 0x25) {
+				if (bpp == 16)
+					tile->zcomp |= NV25_PFB_ZCOMP_MODE_16;
+				else
+					tile->zcomp |= NV25_PFB_ZCOMP_MODE_32;
+			} else {
+				tile->zcomp |= NV20_PFB_ZCOMP_EN;
+				if (bpp != 16)
+					tile->zcomp |= NV20_PFB_ZCOMP_MODE_32;
+			}
+		}
+
+		tile->addr |= 2;
+	}
+}
+
+void
+nv20_fb_free_tile_region(struct drm_device *dev, int i)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+
+	tile->addr = tile->limit = tile->pitch = tile->zcomp = 0;
+	nv20_fb_free_tag(dev, &tile->tag_mem);
+}
+
+void
+nv20_fb_set_tile_region(struct drm_device *dev, int i)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+
+	nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit);
+	nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch);
+	nv_wr32(dev, NV10_PFB_TILE(i), tile->addr);
+	nv_wr32(dev, NV20_PFB_ZCOMP(i), tile->zcomp);
+}
+
+int
+nv20_fb_vram_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	u32 mem_size = nv_rd32(dev, 0x10020c);
+	u32 pbus1218 = nv_rd32(dev, 0x001218);
+
+	dev_priv->vram_size = mem_size & 0xff000000;
+	switch (pbus1218 & 0x00000300) {
+	case 0x00000000: dev_priv->vram_type = NV_MEM_TYPE_SDRAM; break;
+	case 0x00000100: dev_priv->vram_type = NV_MEM_TYPE_DDR1; break;
+	case 0x00000200: dev_priv->vram_type = NV_MEM_TYPE_GDDR3; break;
+	case 0x00000300: dev_priv->vram_type = NV_MEM_TYPE_GDDR2; break;
+	}
+
+	return 0;
+}
+
+int
+nv20_fb_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+	int i;
+
+	if (dev_priv->chipset >= 0x25)
+		drm_mm_init(&pfb->tag_heap, 0, 64 * 1024);
+	else
+		drm_mm_init(&pfb->tag_heap, 0, 32 * 1024);
+
+	/* Turn all the tiling regions off. */
+	pfb->num_tiles = NV10_PFB_TILE__SIZE;
+	for (i = 0; i < pfb->num_tiles; i++)
+		pfb->set_tile_region(dev, i);
+
+	return 0;
+}
+
+void
+nv20_fb_takedown(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+	int i;
+
+	for (i = 0; i < pfb->num_tiles; i++)
+		pfb->free_tile_region(dev, i);
+
+	drm_mm_takedown(&pfb->tag_heap);
+}
diff --git a/drivers/gpu/drm/nouveau/nv40_fb.c b/drivers/gpu/drm/nouveau/nv40_fb.c
index f0ac2a7..7fbcb33 100644
--- a/drivers/gpu/drm/nouveau/nv40_fb.c
+++ b/drivers/gpu/drm/nouveau/nv40_fb.c
@@ -72,6 +72,51 @@
 }
 
 int
+nv40_fb_vram_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+	/* 0x001218 is actually present on a few other NV4X I looked at,
+	 * and even contains sane values matching 0x100474.  From looking
+	 * at various vbios images however, this isn't the case everywhere.
+	 * So, I chose to use the same regs I've seen NVIDIA reading around
+	 * the memory detection, hopefully that'll get us the right numbers
+	 */
+	if (dev_priv->chipset == 0x40) {
+		u32 pbus1218 = nv_rd32(dev, 0x001218);
+		switch (pbus1218 & 0x00000300) {
+		case 0x00000000: dev_priv->vram_type = NV_MEM_TYPE_SDRAM; break;
+		case 0x00000100: dev_priv->vram_type = NV_MEM_TYPE_DDR1; break;
+		case 0x00000200: dev_priv->vram_type = NV_MEM_TYPE_GDDR3; break;
+		case 0x00000300: dev_priv->vram_type = NV_MEM_TYPE_DDR2; break;
+		}
+	} else
+	if (dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) {
+		u32 pfb914 = nv_rd32(dev, 0x100914);
+		switch (pfb914 & 0x00000003) {
+		case 0x00000000: dev_priv->vram_type = NV_MEM_TYPE_DDR1; break;
+		case 0x00000001: dev_priv->vram_type = NV_MEM_TYPE_DDR2; break;
+		case 0x00000002: dev_priv->vram_type = NV_MEM_TYPE_GDDR3; break;
+		case 0x00000003: break;
+		}
+	} else
+	if (dev_priv->chipset != 0x4e) {
+		u32 pfb474 = nv_rd32(dev, 0x100474);
+		if (pfb474 & 0x00000004)
+			dev_priv->vram_type = NV_MEM_TYPE_GDDR3;
+		if (pfb474 & 0x00000002)
+			dev_priv->vram_type = NV_MEM_TYPE_DDR2;
+		if (pfb474 & 0x00000001)
+			dev_priv->vram_type = NV_MEM_TYPE_DDR1;
+	} else {
+		dev_priv->vram_type = NV_MEM_TYPE_STOLEN;
+	}
+
+	dev_priv->vram_size = nv_rd32(dev, 0x10020c) & 0xff000000;
+	return 0;
+}
+
+int
 nv40_fb_init(struct drm_device *dev)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index 8f6c2ac..701b927 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -170,6 +170,41 @@
 	return ret;
 }
 
+static int
+nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update)
+{
+	struct drm_device *dev = nv_crtc->base.dev;
+	struct nouveau_channel *evo = nv50_display(dev)->master;
+	int ret;
+	int adj;
+	u32 hue, vib;
+
+	NV_DEBUG_KMS(dev, "vibrance = %i, hue = %i\n",
+		     nv_crtc->color_vibrance, nv_crtc->vibrant_hue);
+
+	ret = RING_SPACE(evo, 2 + (update ? 2 : 0));
+	if (ret) {
+		NV_ERROR(dev, "no space while setting color vibrance\n");
+		return ret;
+	}
+
+	adj = (nv_crtc->color_vibrance > 0) ? 50 : 0;
+	vib = ((nv_crtc->color_vibrance * 2047 + adj) / 100) & 0xfff;
+
+	hue = ((nv_crtc->vibrant_hue * 2047) / 100) & 0xfff;
+
+	BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, COLOR_CTRL), 1);
+	OUT_RING  (evo, (hue << 20) | (vib << 8));
+
+	if (update) {
+		BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
+		OUT_RING  (evo, 0);
+		FIRE_RING (evo);
+	}
+
+	return 0;
+}
+
 struct nouveau_connector *
 nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc)
 {
@@ -577,8 +612,6 @@
 	OUT_RING  (evo, fb->base.depth == 8 ?
 		   NV50_EVO_CRTC_CLUT_MODE_OFF : NV50_EVO_CRTC_CLUT_MODE_ON);
 
-	BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, COLOR_CTRL), 1);
-	OUT_RING  (evo, NV50_EVO_CRTC_COLOR_CTRL_COLOR);
 	BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_POS), 1);
 	OUT_RING  (evo, (y << 16) | x);
 
@@ -661,6 +694,7 @@
 
 	nv_crtc->set_dither(nv_crtc, false);
 	nv_crtc->set_scale(nv_crtc, false);
+	nv_crtc->set_color_vibrance(nv_crtc, false);
 
 	return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
 }
@@ -721,6 +755,9 @@
 	if (!nv_crtc)
 		return -ENOMEM;
 
+	nv_crtc->color_vibrance = 50;
+	nv_crtc->vibrant_hue = 0;
+
 	/* Default CLUT parameters, will be activated on the hw upon
 	 * first mode set.
 	 */
@@ -751,6 +788,7 @@
 	/* set function pointers */
 	nv_crtc->set_dither = nv50_crtc_set_dither;
 	nv_crtc->set_scale = nv50_crtc_set_scale;
+	nv_crtc->set_color_vibrance = nv50_crtc_set_color_vibrance;
 
 	drm_crtc_init(dev, &nv_crtc->base, &nv50_crtc_funcs);
 	drm_crtc_helper_add(&nv_crtc->base, &nv50_crtc_helper_funcs);
diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c
index a0f2beb..55c5633 100644
--- a/drivers/gpu/drm/nouveau/nv50_dac.c
+++ b/drivers/gpu/drm/nouveau/nv50_dac.c
@@ -190,11 +190,8 @@
 	}
 
 	if (connector->scaling_mode != DRM_MODE_SCALE_NONE &&
-	     connector->native_mode) {
-		int id = adjusted_mode->base.id;
-		*adjusted_mode = *connector->native_mode;
-		adjusted_mode->base.id = id;
-	}
+	     connector->native_mode)
+		drm_mode_copy(adjusted_mode, connector->native_mode);
 
 	return true;
 }
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 7ba28e0..8b78b9c 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -50,6 +50,29 @@
 	return 4;
 }
 
+u32
+nv50_display_active_crtcs(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	u32 mask = 0;
+	int i;
+
+	if (dev_priv->chipset  < 0x90 ||
+	    dev_priv->chipset == 0x92 ||
+	    dev_priv->chipset == 0xa0) {
+		for (i = 0; i < 2; i++)
+			mask |= nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(i));
+	} else {
+		for (i = 0; i < 4; i++)
+			mask |= nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(i));
+	}
+
+	for (i = 0; i < 3; i++)
+		mask |= nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i));
+
+	return mask & 3;
+}
+
 static int
 evo_icmd(struct drm_device *dev, int ch, u32 mthd, u32 data)
 {
@@ -451,15 +474,15 @@
 		}
 
 		if (dev_priv->chipset < 0xc0) {
-			BEGIN_RING(chan, NvSubSw, 0x0060, 2);
+			BEGIN_RING(chan, 0, 0x0060, 2);
 			OUT_RING  (chan, NvEvoSema0 + nv_crtc->index);
 			OUT_RING  (chan, dispc->sem.offset);
-			BEGIN_RING(chan, NvSubSw, 0x006c, 1);
+			BEGIN_RING(chan, 0, 0x006c, 1);
 			OUT_RING  (chan, 0xf00d0000 | dispc->sem.value);
-			BEGIN_RING(chan, NvSubSw, 0x0064, 2);
+			BEGIN_RING(chan, 0, 0x0064, 2);
 			OUT_RING  (chan, dispc->sem.offset ^ 0x10);
 			OUT_RING  (chan, 0x74b1e000);
-			BEGIN_RING(chan, NvSubSw, 0x0060, 1);
+			BEGIN_RING(chan, 0, 0x0060, 1);
 			if (dev_priv->chipset < 0x84)
 				OUT_RING  (chan, NvSema);
 			else
@@ -467,12 +490,12 @@
 		} else {
 			u64 offset = chan->dispc_vma[nv_crtc->index].offset;
 			offset += dispc->sem.offset;
-			BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4);
+			BEGIN_NVC0(chan, 2, 0, 0x0010, 4);
 			OUT_RING  (chan, upper_32_bits(offset));
 			OUT_RING  (chan, lower_32_bits(offset));
 			OUT_RING  (chan, 0xf00d0000 | dispc->sem.value);
 			OUT_RING  (chan, 0x1002);
-			BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4);
+			BEGIN_NVC0(chan, 2, 0, 0x0010, 4);
 			OUT_RING  (chan, upper_32_bits(offset));
 			OUT_RING  (chan, lower_32_bits(offset ^ 0x10));
 			OUT_RING  (chan, 0x74b1e000);
@@ -840,9 +863,9 @@
 	if (type == OUTPUT_DP) {
 		int link = !(dcb->dpconf.sor.link & 1);
 		if ((mc & 0x000f0000) == 0x00020000)
-			nouveau_dp_tu_update(dev, or, link, pclk, 18);
+			nv50_sor_dp_calc_tu(dev, or, link, pclk, 18);
 		else
-			nouveau_dp_tu_update(dev, or, link, pclk, 24);
+			nv50_sor_dp_calc_tu(dev, or, link, pclk, 24);
 	}
 
 	if (dcb->type != OUTPUT_ANALOG) {
diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h
index 95874f7..5d3dd14 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.h
+++ b/drivers/gpu/drm/nouveau/nv50_display.h
@@ -74,6 +74,8 @@
 int nv50_crtc_blank(struct nouveau_crtc *, bool blank);
 int nv50_crtc_set_clock(struct drm_device *, int head, int pclk);
 
+u32  nv50_display_active_crtcs(struct drm_device *);
+
 int  nv50_display_sync(struct drm_device *);
 int  nv50_display_flip_next(struct drm_crtc *, struct drm_framebuffer *,
 			    struct nouveau_channel *chan);
diff --git a/drivers/gpu/drm/nouveau/nv50_evo.h b/drivers/gpu/drm/nouveau/nv50_evo.h
index 3860ca6..771d879 100644
--- a/drivers/gpu/drm/nouveau/nv50_evo.h
+++ b/drivers/gpu/drm/nouveau/nv50_evo.h
@@ -104,7 +104,8 @@
 #define NV50_EVO_CRTC_SCALE_CTRL_INACTIVE                            0x00000000
 #define NV50_EVO_CRTC_SCALE_CTRL_ACTIVE                              0x00000009
 #define NV50_EVO_CRTC_COLOR_CTRL                                     0x000008a8
-#define NV50_EVO_CRTC_COLOR_CTRL_COLOR                               0x00040000
+#define NV50_EVO_CRTC_COLOR_CTRL_VIBRANCE                            0x000fff00
+#define NV50_EVO_CRTC_COLOR_CTRL_HUE                                 0xfff00000
 #define NV50_EVO_CRTC_FB_POS                                         0x000008c0
 #define NV50_EVO_CRTC_REAL_RES                                       0x000008c8
 #define NV50_EVO_CRTC_SCALE_CENTER_OFFSET                            0x000008d4
diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c
index ec5481d..d020ed4 100644
--- a/drivers/gpu/drm/nouveau/nv50_pm.c
+++ b/drivers/gpu/drm/nouveau/nv50_pm.c
@@ -28,6 +28,7 @@
 #include "nouveau_hw.h"
 #include "nouveau_pm.h"
 #include "nouveau_hwsq.h"
+#include "nv50_display.h"
 
 enum clk_src {
 	clk_src_crystal,
@@ -352,17 +353,13 @@
 }
 
 struct nv50_pm_state {
+	struct nouveau_pm_level *perflvl;
+	struct hwsq_ucode eclk_hwsq;
 	struct hwsq_ucode mclk_hwsq;
 	u32 mscript;
-
-	u32 emast;
-	u32 nctrl;
-	u32 ncoef;
-	u32 sctrl;
-	u32 scoef;
-
-	u32 amast;
-	u32 pdivs;
+	u32 mmast;
+	u32 mctrl;
+	u32 mcoef;
 };
 
 static u32
@@ -415,40 +412,153 @@
 	return ((a / 1000) == (b / 1000));
 }
 
+static void
+mclk_precharge(struct nouveau_mem_exec_func *exec)
+{
+	struct nv50_pm_state *info = exec->priv;
+	struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+
+	hwsq_wr32(hwsq, 0x1002d4, 0x00000001);
+}
+
+static void
+mclk_refresh(struct nouveau_mem_exec_func *exec)
+{
+	struct nv50_pm_state *info = exec->priv;
+	struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+
+	hwsq_wr32(hwsq, 0x1002d0, 0x00000001);
+}
+
+static void
+mclk_refresh_auto(struct nouveau_mem_exec_func *exec, bool enable)
+{
+	struct nv50_pm_state *info = exec->priv;
+	struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+
+	hwsq_wr32(hwsq, 0x100210, enable ? 0x80000000 : 0x00000000);
+}
+
+static void
+mclk_refresh_self(struct nouveau_mem_exec_func *exec, bool enable)
+{
+	struct nv50_pm_state *info = exec->priv;
+	struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+
+	hwsq_wr32(hwsq, 0x1002dc, enable ? 0x00000001 : 0x00000000);
+}
+
+static void
+mclk_wait(struct nouveau_mem_exec_func *exec, u32 nsec)
+{
+	struct nv50_pm_state *info = exec->priv;
+	struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+
+	if (nsec > 1000)
+		hwsq_usec(hwsq, (nsec + 500) / 1000);
+}
+
+static u32
+mclk_mrg(struct nouveau_mem_exec_func *exec, int mr)
+{
+	if (mr <= 1)
+		return nv_rd32(exec->dev, 0x1002c0 + ((mr - 0) * 4));
+	if (mr <= 3)
+		return nv_rd32(exec->dev, 0x1002e0 + ((mr - 2) * 4));
+	return 0;
+}
+
+static void
+mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data)
+{
+	struct drm_nouveau_private *dev_priv = exec->dev->dev_private;
+	struct nv50_pm_state *info = exec->priv;
+	struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+
+	if (mr <= 1) {
+		if (dev_priv->vram_rank_B)
+			hwsq_wr32(hwsq, 0x1002c8 + ((mr - 0) * 4), data);
+		hwsq_wr32(hwsq, 0x1002c0 + ((mr - 0) * 4), data);
+	} else
+	if (mr <= 3) {
+		if (dev_priv->vram_rank_B)
+			hwsq_wr32(hwsq, 0x1002e8 + ((mr - 2) * 4), data);
+		hwsq_wr32(hwsq, 0x1002e0 + ((mr - 2) * 4), data);
+	}
+}
+
+static void
+mclk_clock_set(struct nouveau_mem_exec_func *exec)
+{
+	struct nv50_pm_state *info = exec->priv;
+	struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+	u32 ctrl = nv_rd32(exec->dev, 0x004008);
+
+	info->mmast = nv_rd32(exec->dev, 0x00c040);
+	info->mmast &= ~0xc0000000; /* get MCLK_2 from HREF */
+	info->mmast |=  0x0000c000; /* use MCLK_2 as MPLL_BYPASS clock */
+
+	hwsq_wr32(hwsq, 0xc040, info->mmast);
+	hwsq_wr32(hwsq, 0x4008, ctrl | 0x00000200); /* bypass MPLL */
+	if (info->mctrl & 0x80000000)
+		hwsq_wr32(hwsq, 0x400c, info->mcoef);
+	hwsq_wr32(hwsq, 0x4008, info->mctrl);
+}
+
+static void
+mclk_timing_set(struct nouveau_mem_exec_func *exec)
+{
+	struct drm_device *dev = exec->dev;
+	struct nv50_pm_state *info = exec->priv;
+	struct nouveau_pm_level *perflvl = info->perflvl;
+	struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+	int i;
+
+	for (i = 0; i < 9; i++) {
+		u32 reg = 0x100220 + (i * 4);
+		u32 val = nv_rd32(dev, reg);
+		if (val != perflvl->timing.reg[i])
+			hwsq_wr32(hwsq, reg, perflvl->timing.reg[i]);
+	}
+}
+
 static int
-calc_mclk(struct drm_device *dev, u32 freq, struct hwsq_ucode *hwsq)
+calc_mclk(struct drm_device *dev, struct nouveau_pm_level *perflvl,
+	  struct nv50_pm_state *info)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	u32 crtc_mask = nv50_display_active_crtcs(dev);
+	struct nouveau_mem_exec_func exec = {
+		.dev = dev,
+		.precharge = mclk_precharge,
+		.refresh = mclk_refresh,
+		.refresh_auto = mclk_refresh_auto,
+		.refresh_self = mclk_refresh_self,
+		.wait = mclk_wait,
+		.mrg = mclk_mrg,
+		.mrs = mclk_mrs,
+		.clock_set = mclk_clock_set,
+		.timing_set = mclk_timing_set,
+		.priv = info
+	};
+	struct hwsq_ucode *hwsq = &info->mclk_hwsq;
 	struct pll_lims pll;
-	u32 mast = nv_rd32(dev, 0x00c040);
-	u32 ctrl = nv_rd32(dev, 0x004008);
-	u32 coef = nv_rd32(dev, 0x00400c);
-	u32 orig = ctrl;
-	u32 crtc_mask = 0;
 	int N, M, P;
-	int ret, i;
+	int ret;
 
 	/* use pcie refclock if possible, otherwise use mpll */
-	ctrl &= ~0x81ff0200;
-	if (clk_same(freq, read_clk(dev, clk_src_href))) {
-		ctrl |= 0x00000200 | (pll.log2p_bias << 19);
+	info->mctrl  = nv_rd32(dev, 0x004008);
+	info->mctrl &= ~0x81ff0200;
+	if (clk_same(perflvl->memory, read_clk(dev, clk_src_href))) {
+		info->mctrl |= 0x00000200 | (pll.log2p_bias << 19);
 	} else {
-		ret = calc_pll(dev, 0x4008, &pll, freq, &N, &M, &P);
+		ret = calc_pll(dev, 0x4008, &pll, perflvl->memory, &N, &M, &P);
 		if (ret == 0)
 			return -EINVAL;
 
-		ctrl |= 0x80000000 | (P << 22) | (P << 16);
-		ctrl |= pll.log2p_bias << 19;
-		coef  = (N << 8) | M;
-	}
-
-	mast &= ~0xc0000000; /* get MCLK_2 from HREF */
-	mast |=  0x0000c000; /* use MCLK_2 as MPLL_BYPASS clock */
-
-	/* determine active crtcs */
-	for (i = 0; i < 2; i++) {
-		if (nv_rd32(dev, NV50_PDISPLAY_CRTC_C(i, CLOCK)))
-			crtc_mask |= (1 << i);
+		info->mctrl |= 0x80000000 | (P << 22) | (P << 16);
+		info->mctrl |= pll.log2p_bias << 19;
+		info->mcoef  = (N << 8) | M;
 	}
 
 	/* build the ucode which will reclock the memory for us */
@@ -462,25 +572,10 @@
 	hwsq_setf(hwsq, 0x10, 0); /* disable bus access */
 	hwsq_op5f(hwsq, 0x00, 0x01); /* no idea :s */
 
-	/* prepare memory controller */
-	hwsq_wr32(hwsq, 0x1002d4, 0x00000001); /* precharge banks and idle */
-	hwsq_wr32(hwsq, 0x1002d0, 0x00000001); /* force refresh */
-	hwsq_wr32(hwsq, 0x100210, 0x00000000); /* stop the automatic refresh */
-	hwsq_wr32(hwsq, 0x1002dc, 0x00000001); /* start self refresh mode */
+	ret = nouveau_mem_exec(&exec, perflvl);
+	if (ret)
+		return ret;
 
-	/* reclock memory */
-	hwsq_wr32(hwsq, 0xc040, mast);
-	hwsq_wr32(hwsq, 0x4008, orig | 0x00000200); /* bypass MPLL */
-	hwsq_wr32(hwsq, 0x400c, coef);
-	hwsq_wr32(hwsq, 0x4008, ctrl);
-
-	/* restart memory controller */
-	hwsq_wr32(hwsq, 0x1002d4, 0x00000001); /* precharge banks and idle */
-	hwsq_wr32(hwsq, 0x1002dc, 0x00000000); /* stop self refresh mode */
-	hwsq_wr32(hwsq, 0x100210, 0x80000000); /* restart automatic refresh */
-	hwsq_usec(hwsq, 12); /* wait for the PLL to stabilize */
-
-	hwsq_usec(hwsq, 48); /* may be unnecessary: causes flickering */
 	hwsq_setf(hwsq, 0x10, 1); /* enable bus access */
 	hwsq_op5f(hwsq, 0x00, 0x00); /* no idea, reverse of 0x00, 0x01? */
 	if (dev_priv->chipset >= 0x92)
@@ -494,10 +589,11 @@
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nv50_pm_state *info;
+	struct hwsq_ucode *hwsq;
 	struct pll_lims pll;
+	u32 out, mast, divs, ctrl;
 	int clk, ret = -EINVAL;
 	int N, M, P1, P2;
-	u32 out;
 
 	if (dev_priv->chipset == 0xaa ||
 	    dev_priv->chipset == 0xac)
@@ -506,54 +602,44 @@
 	info = kmalloc(sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return ERR_PTR(-ENOMEM);
+	info->perflvl = perflvl;
 
-	/* core: for the moment at least, always use nvpll */
-	clk = calc_pll(dev, 0x4028, &pll, perflvl->core, &N, &M, &P1);
-	if (clk == 0)
-		goto error;
-
-	info->emast = 0x00000003;
-	info->nctrl = 0x80000000 | (P1 << 19) | (P1 << 16);
-	info->ncoef = (N << 8) | M;
-
-	/* shader: tie to nvclk if possible, otherwise use spll.  have to be
-	 * very careful that the shader clock is at least twice the core, or
-	 * some chipsets will be very unhappy.  i expect most or all of these
-	 * cases will be handled by tying to nvclk, but it's possible there's
-	 * corners
-	 */
-	if (P1-- && perflvl->shader == (perflvl->core << 1)) {
-		info->emast |= 0x00000020;
-		info->sctrl  = 0x00000000 | (P1 << 19) | (P1 << 16);
-		info->scoef  = nv_rd32(dev, 0x004024);
-	} else {
-		clk = calc_pll(dev, 0x4020, &pll, perflvl->shader, &N, &M, &P1);
-		if (clk == 0)
-			goto error;
-
-		info->emast |= 0x00000030;
-		info->sctrl  = 0x80000000 | (P1 << 19) | (P1 << 16);
-		info->scoef  = (N << 8) | M;
-	}
-
-	/* memory: build hwsq ucode which we'll use to reclock memory */
+	/* memory: build hwsq ucode which we'll use to reclock memory.
+	 *         use pcie refclock if possible, otherwise use mpll */
 	info->mclk_hwsq.len = 0;
 	if (perflvl->memory) {
-		clk = calc_mclk(dev, perflvl->memory, &info->mclk_hwsq);
-		if (clk < 0) {
-			ret = clk;
+		ret = calc_mclk(dev, perflvl, info);
+		if (ret)
 			goto error;
-		}
-
 		info->mscript = perflvl->memscript;
 	}
 
+	divs = read_div(dev);
+	mast = info->mmast;
+
+	/* start building HWSQ script for engine reclocking */
+	hwsq = &info->eclk_hwsq;
+	hwsq_init(hwsq);
+	hwsq_setf(hwsq, 0x10, 0); /* disable bus access */
+	hwsq_op5f(hwsq, 0x00, 0x01); /* wait for access disabled? */
+
+	/* vdec/dom6: switch to "safe" clocks temporarily */
+	if (perflvl->vdec) {
+		mast &= ~0x00000c00;
+		divs &= ~0x00000700;
+	}
+
+	if (perflvl->dom6) {
+		mast &= ~0x0c000000;
+		divs &= ~0x00000007;
+	}
+
+	hwsq_wr32(hwsq, 0x00c040, mast);
+
 	/* vdec: avoid modifying xpll until we know exactly how the other
 	 * clock domains work, i suspect at least some of them can also be
 	 * tied to xpll...
 	 */
-	info->amast = nv_rd32(dev, 0x00c040);
-	info->pdivs = read_div(dev);
 	if (perflvl->vdec) {
 		/* see how close we can get using nvclk as a source */
 		clk = calc_div(perflvl->core, perflvl->vdec, &P1);
@@ -566,16 +652,14 @@
 		out = calc_div(out, perflvl->vdec, &P2);
 
 		/* select whichever gets us closest */
-		info->amast &= ~0x00000c00;
-		info->pdivs &= ~0x00000700;
 		if (abs((int)perflvl->vdec - clk) <=
 		    abs((int)perflvl->vdec - out)) {
 			if (dev_priv->chipset != 0x98)
-				info->amast |= 0x00000c00;
-			info->pdivs |= P1 << 8;
+				mast |= 0x00000c00;
+			divs |= P1 << 8;
 		} else {
-			info->amast |= 0x00000800;
-			info->pdivs |= P2 << 8;
+			mast |= 0x00000800;
+			divs |= P2 << 8;
 		}
 	}
 
@@ -583,21 +667,82 @@
 	 * of the host clock frequency
 	 */
 	if (perflvl->dom6) {
-		info->amast &= ~0x0c000000;
 		if (clk_same(perflvl->dom6, read_clk(dev, clk_src_href))) {
-			info->amast |= 0x00000000;
+			mast |= 0x00000000;
 		} else
 		if (clk_same(perflvl->dom6, read_clk(dev, clk_src_hclk))) {
-			info->amast |= 0x08000000;
+			mast |= 0x08000000;
 		} else {
 			clk = read_clk(dev, clk_src_hclk) * 3;
 			clk = calc_div(clk, perflvl->dom6, &P1);
 
-			info->amast |= 0x0c000000;
-			info->pdivs  = (info->pdivs & ~0x00000007) | P1;
+			mast |= 0x0c000000;
+			divs |= P1;
 		}
 	}
 
+	/* vdec/dom6: complete switch to new clocks */
+	switch (dev_priv->chipset) {
+	case 0x92:
+	case 0x94:
+	case 0x96:
+		hwsq_wr32(hwsq, 0x004800, divs);
+		break;
+	default:
+		hwsq_wr32(hwsq, 0x004700, divs);
+		break;
+	}
+
+	hwsq_wr32(hwsq, 0x00c040, mast);
+
+	/* core/shader: make sure sclk/nvclk are disconnected from their
+	 * PLLs (nvclk to dom6, sclk to hclk)
+	 */
+	if (dev_priv->chipset < 0x92)
+		mast = (mast & ~0x001000b0) | 0x00100080;
+	else
+		mast = (mast & ~0x000000b3) | 0x00000081;
+
+	hwsq_wr32(hwsq, 0x00c040, mast);
+
+	/* core: for the moment at least, always use nvpll */
+	clk = calc_pll(dev, 0x4028, &pll, perflvl->core, &N, &M, &P1);
+	if (clk == 0)
+		goto error;
+
+	ctrl  = nv_rd32(dev, 0x004028) & ~0xc03f0100;
+	mast &= ~0x00100000;
+	mast |= 3;
+
+	hwsq_wr32(hwsq, 0x004028, 0x80000000 | (P1 << 19) | (P1 << 16) | ctrl);
+	hwsq_wr32(hwsq, 0x00402c, (N << 8) | M);
+
+	/* shader: tie to nvclk if possible, otherwise use spll.  have to be
+	 * very careful that the shader clock is at least twice the core, or
+	 * some chipsets will be very unhappy.  i expect most or all of these
+	 * cases will be handled by tying to nvclk, but it's possible there's
+	 * corners
+	 */
+	ctrl = nv_rd32(dev, 0x004020) & ~0xc03f0100;
+
+	if (P1-- && perflvl->shader == (perflvl->core << 1)) {
+		hwsq_wr32(hwsq, 0x004020, (P1 << 19) | (P1 << 16) | ctrl);
+		hwsq_wr32(hwsq, 0x00c040, 0x00000020 | mast);
+	} else {
+		clk = calc_pll(dev, 0x4020, &pll, perflvl->shader, &N, &M, &P1);
+		if (clk == 0)
+			goto error;
+		ctrl |= 0x80000000;
+
+		hwsq_wr32(hwsq, 0x004020, (P1 << 19) | (P1 << 16) | ctrl);
+		hwsq_wr32(hwsq, 0x004024, (N << 8) | M);
+		hwsq_wr32(hwsq, 0x00c040, 0x00000030 | mast);
+	}
+
+	hwsq_setf(hwsq, 0x10, 1); /* enable bus access */
+	hwsq_op5f(hwsq, 0x00, 0x00); /* wait for access enabled? */
+	hwsq_fini(hwsq);
+
 	return info;
 error:
 	kfree(info);
@@ -605,23 +750,24 @@
 }
 
 static int
-prog_mclk(struct drm_device *dev, struct hwsq_ucode *hwsq)
+prog_hwsq(struct drm_device *dev, struct hwsq_ucode *hwsq)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	u32 hwsq_data, hwsq_kick;
 	int i;
 
-	if (dev_priv->chipset < 0x90) {
+	if (dev_priv->chipset < 0x94) {
 		hwsq_data = 0x001400;
 		hwsq_kick = 0x00000003;
 	} else {
 		hwsq_data = 0x080000;
 		hwsq_kick = 0x00000001;
 	}
-
 	/* upload hwsq ucode */
 	nv_mask(dev, 0x001098, 0x00000008, 0x00000000);
 	nv_wr32(dev, 0x001304, 0x00000000);
+	if (dev_priv->chipset >= 0x92)
+		nv_wr32(dev, 0x001318, 0x00000000);
 	for (i = 0; i < hwsq->len / 4; i++)
 		nv_wr32(dev, hwsq_data + (i * 4), hwsq->ptr.u32[i]);
 	nv_mask(dev, 0x001098, 0x00000018, 0x00000018);
@@ -645,20 +791,19 @@
 int
 nv50_pm_clocks_set(struct drm_device *dev, void *data)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nv50_pm_state *info = data;
 	struct bit_entry M;
-	int ret = 0;
+	int ret = -EBUSY;
 
 	/* halt and idle execution engines */
 	nv_mask(dev, 0x002504, 0x00000001, 0x00000001);
 	if (!nv_wait(dev, 0x002504, 0x00000010, 0x00000010))
-		goto error;
+		goto resume;
+	if (!nv_wait(dev, 0x00251c, 0x0000003f, 0x0000003f))
+		goto resume;
 
-	/* memory: it is *very* important we change this first, the ucode
-	 * we build in pre() now has hardcoded 0xc040 values, which can't
-	 * change before we execute it or the engine clocks may end up
-	 * messed up.
+	/* program memory clock, if necessary - must come before engine clock
+	 * reprogramming due to how we construct the hwsq scripts in pre()
 	 */
 	if (info->mclk_hwsq.len) {
 		/* execute some scripts that do ??? from the vbios.. */
@@ -672,42 +817,14 @@
 			nouveau_bios_init_exec(dev, info->mscript);
 		}
 
-		ret = prog_mclk(dev, &info->mclk_hwsq);
+		ret = prog_hwsq(dev, &info->mclk_hwsq);
 		if (ret)
 			goto resume;
 	}
 
-	/* reclock vdec/dom6 */
-	nv_mask(dev, 0x00c040, 0x00000c00, 0x00000000);
-	switch (dev_priv->chipset) {
-	case 0x92:
-	case 0x94:
-	case 0x96:
-		nv_mask(dev, 0x004800, 0x00000707, info->pdivs);
-		break;
-	default:
-		nv_mask(dev, 0x004700, 0x00000707, info->pdivs);
-		break;
-	}
-	nv_mask(dev, 0x00c040, 0x0c000c00, info->amast);
+	/* program engine clocks */
+	ret = prog_hwsq(dev, &info->eclk_hwsq);
 
-	/* core/shader: make sure sclk/nvclk are disconnected from their
-	 * plls (nvclk to dom6, sclk to hclk), modify the plls, and
-	 * reconnect sclk/nvclk to their new clock source
-	 */
-	if (dev_priv->chipset < 0x92)
-		nv_mask(dev, 0x00c040, 0x001000b0, 0x00100080); /* grrr! */
-	else
-		nv_mask(dev, 0x00c040, 0x000000b3, 0x00000081);
-	nv_mask(dev, 0x004020, 0xc03f0100, info->sctrl);
-	nv_wr32(dev, 0x004024, info->scoef);
-	nv_mask(dev, 0x004028, 0xc03f0100, info->nctrl);
-	nv_wr32(dev, 0x00402c, info->ncoef);
-	nv_mask(dev, 0x00c040, 0x00100033, info->emast);
-
-	goto resume;
-error:
-	ret = -EBUSY;
 resume:
 	nv_mask(dev, 0x002504, 0x00000001, 0x00000000);
 	kfree(info);
diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
index c4423ba..a7844ab 100644
--- a/drivers/gpu/drm/nouveau/nv50_sor.c
+++ b/drivers/gpu/drm/nouveau/nv50_sor.c
@@ -36,6 +36,193 @@
 #include "nouveau_crtc.h"
 #include "nv50_display.h"
 
+static u32
+nv50_sor_dp_lane_map(struct drm_device *dev, struct dcb_entry *dcb, u8 lane)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	static const u8 nvaf[] = { 24, 16, 8, 0 }; /* thanks, apple.. */
+	static const u8 nv50[] = { 16, 8, 0, 24 };
+	if (dev_priv->card_type == 0xaf)
+		return nvaf[lane];
+	return nv50[lane];
+}
+
+static void
+nv50_sor_dp_train_set(struct drm_device *dev, struct dcb_entry *dcb, u8 pattern)
+{
+	u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+	nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x0f000000, pattern << 24);
+}
+
+static void
+nv50_sor_dp_train_adj(struct drm_device *dev, struct dcb_entry *dcb,
+		      u8 lane, u8 swing, u8 preem)
+{
+	u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+	u32 shift = nv50_sor_dp_lane_map(dev, dcb, lane);
+	u32 mask = 0x000000ff << shift;
+	u8 *table, *entry, *config;
+
+	table = nouveau_dp_bios_data(dev, dcb, &entry);
+	if (!table || (table[0] != 0x20 && table[0] != 0x21)) {
+		NV_ERROR(dev, "PDISP: unsupported DP table for chipset\n");
+		return;
+	}
+
+	config = entry + table[4];
+	while (config[0] != swing || config[1] != preem) {
+		config += table[5];
+		if (config >= entry + table[4] + entry[4] * table[5])
+			return;
+	}
+
+	nv_mask(dev, NV50_SOR_DP_UNK118(or, link), mask, config[2] << shift);
+	nv_mask(dev, NV50_SOR_DP_UNK120(or, link), mask, config[3] << shift);
+	nv_mask(dev, NV50_SOR_DP_UNK130(or, link), 0x0000ff00, config[4] << 8);
+}
+
+static void
+nv50_sor_dp_link_set(struct drm_device *dev, struct dcb_entry *dcb, int crtc,
+		     int link_nr, u32 link_bw, bool enhframe)
+{
+	u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+	u32 dpctrl = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)) & ~0x001f4000;
+	u32 clksor = nv_rd32(dev, 0x614300 + (or * 0x800)) & ~0x000c0000;
+	u8 *table, *entry, mask;
+	int i;
+
+	table = nouveau_dp_bios_data(dev, dcb, &entry);
+	if (!table || (table[0] != 0x20 && table[0] != 0x21)) {
+		NV_ERROR(dev, "PDISP: unsupported DP table for chipset\n");
+		return;
+	}
+
+	entry = ROMPTR(dev, entry[10]);
+	if (entry) {
+		while (link_bw < ROM16(entry[0]) * 10)
+			entry += 4;
+
+		nouveau_bios_run_init_table(dev, ROM16(entry[2]), dcb, crtc);
+	}
+
+	dpctrl |= ((1 << link_nr) - 1) << 16;
+	if (enhframe)
+		dpctrl |= 0x00004000;
+
+	if (link_bw > 162000)
+		clksor |= 0x00040000;
+
+	nv_wr32(dev, 0x614300 + (or * 0x800), clksor);
+	nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), dpctrl);
+
+	mask = 0;
+	for (i = 0; i < link_nr; i++)
+		mask |= 1 << (nv50_sor_dp_lane_map(dev, dcb, i) >> 3);
+	nv_mask(dev, NV50_SOR_DP_UNK130(or, link), 0x0000000f, mask);
+}
+
+static void
+nv50_sor_dp_link_get(struct drm_device *dev, u32 or, u32 link, u32 *nr, u32 *bw)
+{
+	u32 dpctrl = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)) & 0x000f0000;
+	u32 clksor = nv_rd32(dev, 0x614300 + (or * 0x800));
+	if (clksor & 0x000c0000)
+		*bw = 270000;
+	else
+		*bw = 162000;
+
+	if      (dpctrl > 0x00030000) *nr = 4;
+	else if (dpctrl > 0x00010000) *nr = 2;
+	else			      *nr = 1;
+}
+
+void
+nv50_sor_dp_calc_tu(struct drm_device *dev, int or, int link, u32 clk, u32 bpp)
+{
+	const u32 symbol = 100000;
+	int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
+	int TU, VTUi, VTUf, VTUa;
+	u64 link_data_rate, link_ratio, unk;
+	u32 best_diff = 64 * symbol;
+	u32 link_nr, link_bw, r;
+
+	/* calculate packed data rate for each lane */
+	nv50_sor_dp_link_get(dev, or, link, &link_nr, &link_bw);
+	link_data_rate = (clk * bpp / 8) / link_nr;
+
+	/* calculate ratio of packed data rate to link symbol rate */
+	link_ratio = link_data_rate * symbol;
+	r = do_div(link_ratio, link_bw);
+
+	for (TU = 64; TU >= 32; TU--) {
+		/* calculate average number of valid symbols in each TU */
+		u32 tu_valid = link_ratio * TU;
+		u32 calc, diff;
+
+		/* find a hw representation for the fraction.. */
+		VTUi = tu_valid / symbol;
+		calc = VTUi * symbol;
+		diff = tu_valid - calc;
+		if (diff) {
+			if (diff >= (symbol / 2)) {
+				VTUf = symbol / (symbol - diff);
+				if (symbol - (VTUf * diff))
+					VTUf++;
+
+				if (VTUf <= 15) {
+					VTUa  = 1;
+					calc += symbol - (symbol / VTUf);
+				} else {
+					VTUa  = 0;
+					VTUf  = 1;
+					calc += symbol;
+				}
+			} else {
+				VTUa  = 0;
+				VTUf  = min((int)(symbol / diff), 15);
+				calc += symbol / VTUf;
+			}
+
+			diff = calc - tu_valid;
+		} else {
+			/* no remainder, but the hw doesn't like the fractional
+			 * part to be zero.  decrement the integer part and
+			 * have the fraction add a whole symbol back
+			 */
+			VTUa = 0;
+			VTUf = 1;
+			VTUi--;
+		}
+
+		if (diff < best_diff) {
+			best_diff = diff;
+			bestTU = TU;
+			bestVTUa = VTUa;
+			bestVTUf = VTUf;
+			bestVTUi = VTUi;
+			if (diff == 0)
+				break;
+		}
+	}
+
+	if (!bestTU) {
+		NV_ERROR(dev, "DP: unable to find suitable config\n");
+		return;
+	}
+
+	/* XXX close to vbios numbers, but not right */
+	unk  = (symbol - link_ratio) * bestTU;
+	unk *= link_ratio;
+	r = do_div(unk, symbol);
+	r = do_div(unk, symbol);
+	unk += 6;
+
+	nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x000001fc, bestTU << 2);
+	nv_mask(dev, NV50_SOR_DP_SCFG(or, link), 0x010f7f3f, bestVTUa << 24 |
+							     bestVTUf << 16 |
+							     bestVTUi << 8 |
+							     unk);
+}
 static void
 nv50_sor_disconnect(struct drm_encoder *encoder)
 {
@@ -117,20 +304,13 @@
 	}
 
 	if (nv_encoder->dcb->type == OUTPUT_DP) {
-		struct nouveau_i2c_chan *auxch;
+		struct dp_train_func func = {
+			.link_set = nv50_sor_dp_link_set,
+			.train_set = nv50_sor_dp_train_set,
+			.train_adj = nv50_sor_dp_train_adj
+		};
 
-		auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
-		if (!auxch)
-			return;
-
-		if (mode == DRM_MODE_DPMS_ON) {
-			u8 status = DP_SET_POWER_D0;
-			nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
-			nouveau_dp_link_train(encoder, nv_encoder->dp.datarate);
-		} else {
-			u8 status = DP_SET_POWER_D3;
-			nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
-		}
+		nouveau_dp_dpms(encoder, mode, nv_encoder->dp.datarate, &func);
 	}
 }
 
@@ -162,11 +342,8 @@
 	}
 
 	if (connector->scaling_mode != DRM_MODE_SCALE_NONE &&
-	     connector->native_mode) {
-		int id = adjusted_mode->base.id;
-		*adjusted_mode = *connector->native_mode;
-		adjusted_mode->base.id = id;
-	}
+	     connector->native_mode)
+		drm_mode_copy(adjusted_mode, connector->native_mode);
 
 	return true;
 }
diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c
index 6f38cea..44fbac9 100644
--- a/drivers/gpu/drm/nouveau/nv50_vm.c
+++ b/drivers/gpu/drm/nouveau/nv50_vm.c
@@ -57,27 +57,15 @@
 }
 
 static inline u64
-nv50_vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target)
+vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target)
 {
-	struct drm_nouveau_private *dev_priv = vma->vm->dev->dev_private;
-
 	phys |= 1; /* present */
 	phys |= (u64)memtype << 40;
-
-	/* IGPs don't have real VRAM, re-target to stolen system memory */
-	if (target == 0 && dev_priv->vram_sys_base) {
-		phys  += dev_priv->vram_sys_base;
-		target = 3;
-	}
-
 	phys |= target << 4;
-
 	if (vma->access & NV_MEM_ACCESS_SYS)
 		phys |= (1 << 6);
-
 	if (!(vma->access & NV_MEM_ACCESS_WO))
 		phys |= (1 << 3);
-
 	return phys;
 }
 
@@ -85,11 +73,19 @@
 nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
 	    struct nouveau_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta)
 {
+	struct drm_nouveau_private *dev_priv = vma->vm->dev->dev_private;
 	u32 comp = (mem->memtype & 0x180) >> 7;
-	u32 block;
+	u32 block, target;
 	int i;
 
-	phys  = nv50_vm_addr(vma, phys, mem->memtype, 0);
+	/* IGPs don't have real VRAM, re-target to stolen system memory */
+	target = 0;
+	if (dev_priv->vram_sys_base) {
+		phys += dev_priv->vram_sys_base;
+		target = 3;
+	}
+
+	phys  = vm_addr(vma, phys, mem->memtype, target);
 	pte <<= 3;
 	cnt <<= 3;
 
@@ -125,9 +121,10 @@
 nv50_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
 	       struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
 {
+	u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 3 : 2;
 	pte <<= 3;
 	while (cnt--) {
-		u64 phys = nv50_vm_addr(vma, (u64)*list++, mem->memtype, 2);
+		u64 phys = vm_addr(vma, (u64)*list++, mem->memtype, target);
 		nv_wo32(pgt, pte + 0, lower_32_bits(phys));
 		nv_wo32(pgt, pte + 4, upper_32_bits(phys));
 		pte += 8;
diff --git a/drivers/gpu/drm/nouveau/nv50_vram.c b/drivers/gpu/drm/nouveau/nv50_vram.c
index 2e45e57..9ed9ae39 100644
--- a/drivers/gpu/drm/nouveau/nv50_vram.c
+++ b/drivers/gpu/drm/nouveau/nv50_vram.c
@@ -189,8 +189,25 @@
 	struct nouveau_vram_engine *vram = &dev_priv->engine.vram;
 	const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
 	const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+	u32 pfb714 = nv_rd32(dev, 0x100714);
 	u32 rblock, length;
 
+	switch (pfb714 & 0x00000007) {
+	case 0: dev_priv->vram_type = NV_MEM_TYPE_DDR1; break;
+	case 1:
+		if (nouveau_mem_vbios_type(dev) == NV_MEM_TYPE_DDR3)
+			dev_priv->vram_type = NV_MEM_TYPE_DDR3;
+		else
+			dev_priv->vram_type = NV_MEM_TYPE_DDR2;
+		break;
+	case 2: dev_priv->vram_type = NV_MEM_TYPE_GDDR3; break;
+	case 3: dev_priv->vram_type = NV_MEM_TYPE_GDDR4; break;
+	case 4: dev_priv->vram_type = NV_MEM_TYPE_GDDR5; break;
+	default:
+		break;
+	}
+
+	dev_priv->vram_rank_B = !!(nv_rd32(dev, 0x100200) & 0x4);
 	dev_priv->vram_size  = nv_rd32(dev, 0x10020c);
 	dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32;
 	dev_priv->vram_size &= 0xffffffff00ULL;
diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c
index dcbe0d5..50d68a7 100644
--- a/drivers/gpu/drm/nouveau/nvc0_fifo.c
+++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c
@@ -436,6 +436,24 @@
 	printk(" on channel 0x%010llx\n", (u64)inst << 12);
 }
 
+static int
+nvc0_fifo_page_flip(struct drm_device *dev, u32 chid)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_channel *chan = NULL;
+	unsigned long flags;
+	int ret = -EINVAL;
+
+	spin_lock_irqsave(&dev_priv->channels.lock, flags);
+	if (likely(chid >= 0 && chid < dev_priv->engine.fifo.channels)) {
+		chan = dev_priv->channels.ptr[chid];
+		if (likely(chan))
+			ret = nouveau_finish_page_flip(chan, NULL);
+	}
+	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+	return ret;
+}
+
 static void
 nvc0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit)
 {
@@ -445,11 +463,21 @@
 	u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0x7f;
 	u32 subc = (addr & 0x00070000);
 	u32 mthd = (addr & 0x00003ffc);
+	u32 show = stat;
 
-	NV_INFO(dev, "PSUBFIFO %d:", unit);
-	nouveau_bitfield_print(nvc0_fifo_subfifo_intr, stat);
-	NV_INFO(dev, "PSUBFIFO %d: ch %d subc %d mthd 0x%04x data 0x%08x\n",
-		unit, chid, subc, mthd, data);
+	if (stat & 0x00200000) {
+		if (mthd == 0x0054) {
+			if (!nvc0_fifo_page_flip(dev, chid))
+				show &= ~0x00200000;
+		}
+	}
+
+	if (show) {
+		NV_INFO(dev, "PFIFO%d:", unit);
+		nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show);
+		NV_INFO(dev, "PFIFO%d: ch %d subc %d mthd 0x%04x data 0x%08x\n",
+			     unit, chid, subc, mthd, data);
+	}
 
 	nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008);
 	nv_wr32(dev, 0x040108 + (unit * 0x2000), stat);
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c
index 8ee3963..9066102 100644
--- a/drivers/gpu/drm/nouveau/nvc0_graph.c
+++ b/drivers/gpu/drm/nouveau/nvc0_graph.c
@@ -333,14 +333,6 @@
 	return 0;
 }
 
-static int
-nvc0_graph_mthd_page_flip(struct nouveau_channel *chan,
-			  u32 class, u32 mthd, u32 data)
-{
-	nouveau_finish_page_flip(chan, NULL);
-	return 0;
-}
-
 static void
 nvc0_graph_init_obj418880(struct drm_device *dev)
 {
@@ -889,7 +881,6 @@
 
 	NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
 	NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
-	NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip);
 	NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
 	if (fermi >= 0x9197)
 		NVOBJ_CLASS(dev, 0x9197, GR); /* 3D (NVC1-) */
diff --git a/drivers/gpu/drm/nouveau/nvc0_pm.c b/drivers/gpu/drm/nouveau/nvc0_pm.c
index e9992f6..ce65f81 100644
--- a/drivers/gpu/drm/nouveau/nvc0_pm.c
+++ b/drivers/gpu/drm/nouveau/nvc0_pm.c
@@ -269,7 +269,7 @@
 	clk0 = calc_div(dev, clk, clk0, freq, &div1D);
 
 	/* see if we can get any closer using PLLs */
-	if (clk0 != freq) {
+	if (clk0 != freq && (0x00004387 & (1 << clk))) {
 		if (clk < 7)
 			clk1 = calc_pll(dev, clk, freq, &info->coef);
 		else
diff --git a/drivers/gpu/drm/nouveau/nvc0_vm.c b/drivers/gpu/drm/nouveau/nvc0_vm.c
index 9e35294..30d2bd5 100644
--- a/drivers/gpu/drm/nouveau/nvc0_vm.c
+++ b/drivers/gpu/drm/nouveau/nvc0_vm.c
@@ -77,9 +77,11 @@
 nvc0_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
 	       struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
 {
+	u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 7 : 5;
+
 	pte <<= 3;
 	while (cnt--) {
-		u64 phys = nvc0_vm_addr(vma, *list++, mem->memtype, 5);
+		u64 phys = nvc0_vm_addr(vma, *list++, mem->memtype, target);
 		nv_wo32(pgt, pte + 0, lower_32_bits(phys));
 		nv_wo32(pgt, pte + 4, upper_32_bits(phys));
 		pte += 8;
diff --git a/drivers/gpu/drm/nouveau/nvc0_vram.c b/drivers/gpu/drm/nouveau/nvc0_vram.c
index ce984d5..a7eef89 100644
--- a/drivers/gpu/drm/nouveau/nvc0_vram.c
+++ b/drivers/gpu/drm/nouveau/nvc0_vram.c
@@ -106,31 +106,32 @@
 	struct nouveau_vram_engine *vram = &dev_priv->engine.vram;
 	const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
 	const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
-	u32 parts = nv_rd32(dev, 0x121c74);
+	u32 parts = nv_rd32(dev, 0x022438);
+	u32 pmask = nv_rd32(dev, 0x022554);
 	u32 bsize = nv_rd32(dev, 0x10f20c);
 	u32 offset, length;
 	bool uniform = true;
 	int ret, part;
 
 	NV_DEBUG(dev, "0x100800: 0x%08x\n", nv_rd32(dev, 0x100800));
-	NV_DEBUG(dev, "parts 0x%08x bcast_mem_amount 0x%08x\n", parts, bsize);
+	NV_DEBUG(dev, "parts 0x%08x mask 0x%08x\n", parts, pmask);
+
+	dev_priv->vram_type = nouveau_mem_vbios_type(dev);
+	dev_priv->vram_rank_B = !!(nv_rd32(dev, 0x10f200) & 0x00000004);
 
 	/* read amount of vram attached to each memory controller */
-	part = 0;
-	while (parts) {
-		u32 psize = nv_rd32(dev, 0x11020c + (part++ * 0x1000));
-		if (psize == 0)
-			continue;
-		parts--;
+	for (part = 0; part < parts; part++) {
+		if (!(pmask & (1 << part))) {
+			u32 psize = nv_rd32(dev, 0x11020c + (part * 0x1000));
+			if (psize != bsize) {
+				if (psize < bsize)
+					bsize = psize;
+				uniform = false;
+			}
 
-		if (psize != bsize) {
-			if (psize < bsize)
-				bsize = psize;
-			uniform = false;
+			NV_DEBUG(dev, "%d: mem_amount 0x%08x\n", part, psize);
+			dev_priv->vram_size += (u64)psize << 20;
 		}
-
-		NV_DEBUG(dev, "%d: mem_amount 0x%08x\n", part, psize);
-		dev_priv->vram_size += (u64)psize << 20;
 	}
 
 	/* if all controllers have the same amount attached, there's no holes */
diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c
index d2ba2f0..0247250 100644
--- a/drivers/gpu/drm/nouveau/nvd0_display.c
+++ b/drivers/gpu/drm/nouveau/nvd0_display.c
@@ -284,6 +284,8 @@
 	u32 *push;
 	int ret;
 
+	evo_sync(crtc->dev, EVO_MASTER);
+
 	swap_interval <<= 4;
 	if (swap_interval == 0)
 		swap_interval |= 0x100;
@@ -301,12 +303,12 @@
 		offset  = chan->dispc_vma[nv_crtc->index].offset;
 		offset += evo->sem.offset;
 
-		BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4);
+		BEGIN_NVC0(chan, 2, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
 		OUT_RING  (chan, upper_32_bits(offset));
 		OUT_RING  (chan, lower_32_bits(offset));
 		OUT_RING  (chan, 0xf00d0000 | evo->sem.value);
 		OUT_RING  (chan, 0x1002);
-		BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4);
+		BEGIN_NVC0(chan, 2, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
 		OUT_RING  (chan, upper_32_bits(offset));
 		OUT_RING  (chan, lower_32_bits(offset ^ 0x10));
 		OUT_RING  (chan, 0x74b1e000);
@@ -361,10 +363,12 @@
 static int
 nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
 {
+	struct drm_nouveau_private *dev_priv = nv_crtc->base.dev->dev_private;
 	struct drm_device *dev = nv_crtc->base.dev;
 	struct nouveau_connector *nv_connector;
 	struct drm_connector *connector;
 	u32 *push, mode = 0x00;
+	u32 mthd;
 
 	nv_connector = nouveau_crtc_connector_get(nv_crtc);
 	connector = &nv_connector->base;
@@ -382,9 +386,14 @@
 		mode |= nv_connector->dithering_depth;
 	}
 
+	if (dev_priv->card_type < NV_E0)
+		mthd = 0x0490 + (nv_crtc->index * 0x0300);
+	else
+		mthd = 0x04a0 + (nv_crtc->index * 0x0300);
+
 	push = evo_wait(dev, EVO_MASTER, 4);
 	if (push) {
-		evo_mthd(push, 0x0490 + (nv_crtc->index * 0x300), 1);
+		evo_mthd(push, mthd, 1);
 		evo_data(push, mode);
 		if (update) {
 			evo_mthd(push, 0x0080, 1);
@@ -593,7 +602,7 @@
 		evo_kick(push, crtc->dev, EVO_MASTER);
 	}
 
-	nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, false);
+	nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, true);
 	nvd0_display_flip_next(crtc, crtc->fb, NULL, 1);
 }
 
@@ -634,8 +643,7 @@
 	u32 hactive, hsynce, hbackp, hfrontp, hblanke, hblanks;
 	u32 vactive, vsynce, vbackp, vfrontp, vblanke, vblanks;
 	u32 vblan2e = 0, vblan2s = 1;
-	u32 magic = 0x31ec6000;
-	u32 syncs, *push;
+	u32 *push;
 	int ret;
 
 	hactive = mode->htotal;
@@ -655,15 +663,8 @@
 		vblan2e = vactive + vsynce + vbackp;
 		vblan2s = vblan2e + (mode->vdisplay * vscan / ilace);
 		vactive = (vactive * 2) + 1;
-		magic  |= 0x00000001;
 	}
 
-	syncs = 0x00000001;
-	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
-		syncs |= 0x00000008;
-	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
-		syncs |= 0x00000010;
-
 	ret = nvd0_crtc_swap_fbs(crtc, old_fb);
 	if (ret)
 		return ret;
@@ -683,9 +684,6 @@
 		evo_data(push, mode->clock * 1000);
 		evo_data(push, 0x00200000); /* ??? */
 		evo_data(push, mode->clock * 1000);
-		evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
-		evo_data(push, syncs);
-		evo_data(push, magic);
 		evo_mthd(push, 0x04d0 + (nv_crtc->index * 0x300), 2);
 		evo_data(push, 0x00000311);
 		evo_data(push, 0x00000100);
@@ -959,11 +957,6 @@
 }
 
 static void
-nvd0_dac_prepare(struct drm_encoder *encoder)
-{
-}
-
-static void
 nvd0_dac_commit(struct drm_encoder *encoder)
 {
 }
@@ -974,13 +967,26 @@
 {
 	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
-	u32 *push;
+	u32 syncs, magic, *push;
+
+	syncs = 0x00000001;
+	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+		syncs |= 0x00000008;
+	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+		syncs |= 0x00000010;
+
+	magic = 0x31ec6000 | (nv_crtc->index << 25);
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		magic |= 0x00000001;
 
 	nvd0_dac_dpms(encoder, DRM_MODE_DPMS_ON);
 
-	push = evo_wait(encoder->dev, EVO_MASTER, 4);
+	push = evo_wait(encoder->dev, EVO_MASTER, 8);
 	if (push) {
-		evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 2);
+		evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
+		evo_data(push, syncs);
+		evo_data(push, magic);
+		evo_mthd(push, 0x0180 + (nv_encoder->or * 0x020), 2);
 		evo_data(push, 1 << nv_crtc->index);
 		evo_data(push, 0x00ff);
 		evo_kick(push, encoder->dev, EVO_MASTER);
@@ -1043,7 +1049,7 @@
 static const struct drm_encoder_helper_funcs nvd0_dac_hfunc = {
 	.dpms = nvd0_dac_dpms,
 	.mode_fixup = nvd0_dac_mode_fixup,
-	.prepare = nvd0_dac_prepare,
+	.prepare = nvd0_dac_disconnect,
 	.commit = nvd0_dac_commit,
 	.mode_set = nvd0_dac_mode_set,
 	.disable = nvd0_dac_disconnect,
@@ -1183,6 +1189,149 @@
 /******************************************************************************
  * SOR
  *****************************************************************************/
+static inline u32
+nvd0_sor_dp_lane_map(struct drm_device *dev, struct dcb_entry *dcb, u8 lane)
+{
+	static const u8 nvd0[] = { 16, 8, 0, 24 };
+	return nvd0[lane];
+}
+
+static void
+nvd0_sor_dp_train_set(struct drm_device *dev, struct dcb_entry *dcb, u8 pattern)
+{
+	const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+	const u32 loff = (or * 0x800) + (link * 0x80);
+	nv_mask(dev, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
+}
+
+static void
+nvd0_sor_dp_train_adj(struct drm_device *dev, struct dcb_entry *dcb,
+		      u8 lane, u8 swing, u8 preem)
+{
+	const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+	const u32 loff = (or * 0x800) + (link * 0x80);
+	u32 shift = nvd0_sor_dp_lane_map(dev, dcb, lane);
+	u32 mask = 0x000000ff << shift;
+	u8 *table, *entry, *config = NULL;
+
+	switch (swing) {
+	case 0: preem += 0; break;
+	case 1: preem += 4; break;
+	case 2: preem += 7; break;
+	case 3: preem += 9; break;
+	}
+
+	table = nouveau_dp_bios_data(dev, dcb, &entry);
+	if (table) {
+		if (table[0] == 0x30) {
+			config  = entry + table[4];
+			config += table[5] * preem;
+		} else
+		if (table[0] == 0x40) {
+			config  = table + table[1];
+			config += table[2] * table[3];
+			config += table[6] * preem;
+		}
+	}
+
+	if (!config) {
+		NV_ERROR(dev, "PDISP: unsupported DP table for chipset\n");
+		return;
+	}
+
+	nv_mask(dev, 0x61c118 + loff, mask, config[1] << shift);
+	nv_mask(dev, 0x61c120 + loff, mask, config[2] << shift);
+	nv_mask(dev, 0x61c130 + loff, 0x0000ff00, config[3] << 8);
+	nv_mask(dev, 0x61c13c + loff, 0x00000000, 0x00000000);
+}
+
+static void
+nvd0_sor_dp_link_set(struct drm_device *dev, struct dcb_entry *dcb, int crtc,
+		     int link_nr, u32 link_bw, bool enhframe)
+{
+	const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+	const u32 loff = (or * 0x800) + (link * 0x80);
+	const u32 soff = (or * 0x800);
+	u32 dpctrl = nv_rd32(dev, 0x61c10c + loff) & ~0x001f4000;
+	u32 clksor = nv_rd32(dev, 0x612300 + soff) & ~0x007c0000;
+	u32 script = 0x0000, lane_mask = 0;
+	u8 *table, *entry;
+	int i;
+
+	link_bw /= 27000;
+
+	table = nouveau_dp_bios_data(dev, dcb, &entry);
+	if (table) {
+		if      (table[0] == 0x30) entry = ROMPTR(dev, entry[10]);
+		else if (table[0] == 0x40) entry = ROMPTR(dev, entry[9]);
+		else                       entry = NULL;
+
+		while (entry) {
+			if (entry[0] >= link_bw)
+				break;
+			entry += 3;
+		}
+
+		nouveau_bios_run_init_table(dev, script, dcb, crtc);
+	}
+
+	clksor |= link_bw << 18;
+	dpctrl |= ((1 << link_nr) - 1) << 16;
+	if (enhframe)
+		dpctrl |= 0x00004000;
+
+	for (i = 0; i < link_nr; i++)
+		lane_mask |= 1 << (nvd0_sor_dp_lane_map(dev, dcb, i) >> 3);
+
+	nv_wr32(dev, 0x612300 + soff, clksor);
+	nv_wr32(dev, 0x61c10c + loff, dpctrl);
+	nv_mask(dev, 0x61c130 + loff, 0x0000000f, lane_mask);
+}
+
+static void
+nvd0_sor_dp_link_get(struct drm_device *dev, struct dcb_entry *dcb,
+		     u32 *link_nr, u32 *link_bw)
+{
+	const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+	const u32 loff = (or * 0x800) + (link * 0x80);
+	const u32 soff = (or * 0x800);
+	u32 dpctrl = nv_rd32(dev, 0x61c10c + loff) & 0x000f0000;
+	u32 clksor = nv_rd32(dev, 0x612300 + soff);
+
+	if      (dpctrl > 0x00030000) *link_nr = 4;
+	else if (dpctrl > 0x00010000) *link_nr = 2;
+	else			      *link_nr = 1;
+
+	*link_bw  = (clksor & 0x007c0000) >> 18;
+	*link_bw *= 27000;
+}
+
+static void
+nvd0_sor_dp_calc_tu(struct drm_device *dev, struct dcb_entry *dcb,
+		    u32 crtc, u32 datarate)
+{
+	const u32 symbol = 100000;
+	const u32 TU = 64;
+	u32 link_nr, link_bw;
+	u64 ratio, value;
+
+	nvd0_sor_dp_link_get(dev, dcb, &link_nr, &link_bw);
+
+	ratio  = datarate;
+	ratio *= symbol;
+	do_div(ratio, link_nr * link_bw);
+
+	value  = (symbol - ratio) * TU;
+	value *= ratio;
+	do_div(value, symbol);
+	do_div(value, symbol);
+
+	value += 5;
+	value |= 0x08000000;
+
+	nv_wr32(dev, 0x616610 + (crtc * 0x800), value);
+}
+
 static void
 nvd0_sor_dpms(struct drm_encoder *encoder, int mode)
 {
@@ -1215,6 +1364,16 @@
 	nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl);
 	nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
 	nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000);
+
+	if (nv_encoder->dcb->type == OUTPUT_DP) {
+		struct dp_train_func func = {
+			.link_set = nvd0_sor_dp_link_set,
+			.train_set = nvd0_sor_dp_train_set,
+			.train_adj = nvd0_sor_dp_train_adj
+		};
+
+		nouveau_dp_dpms(encoder, mode, nv_encoder->dp.datarate, &func);
+	}
 }
 
 static bool
@@ -1237,8 +1396,37 @@
 }
 
 static void
+nvd0_sor_disconnect(struct drm_encoder *encoder)
+{
+	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+	struct drm_device *dev = encoder->dev;
+	u32 *push;
+
+	if (nv_encoder->crtc) {
+		nvd0_crtc_prepare(nv_encoder->crtc);
+
+		push = evo_wait(dev, EVO_MASTER, 4);
+		if (push) {
+			evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
+			evo_data(push, 0x00000000);
+			evo_mthd(push, 0x0080, 1);
+			evo_data(push, 0x00000000);
+			evo_kick(push, dev, EVO_MASTER);
+		}
+
+		nvd0_hdmi_disconnect(encoder);
+
+		nv_encoder->crtc = NULL;
+		nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
+	}
+}
+
+static void
 nvd0_sor_prepare(struct drm_encoder *encoder)
 {
+	nvd0_sor_disconnect(encoder);
+	if (nouveau_encoder(encoder)->dcb->type == OUTPUT_DP)
+		evo_sync(encoder->dev, EVO_MASTER);
 }
 
 static void
@@ -1257,7 +1445,18 @@
 	struct nouveau_connector *nv_connector;
 	struct nvbios *bios = &dev_priv->vbios;
 	u32 mode_ctrl = (1 << nv_crtc->index);
-	u32 *push, or_config;
+	u32 syncs, magic, *push;
+	u32 or_config;
+
+	syncs = 0x00000001;
+	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+		syncs |= 0x00000008;
+	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+		syncs |= 0x00000010;
+
+	magic = 0x31ec6000 | (nv_crtc->index << 25);
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		magic |= 0x00000001;
 
 	nv_connector = nouveau_encoder_connector_get(nv_encoder);
 	switch (nv_encoder->dcb->type) {
@@ -1306,6 +1505,22 @@
 
 		}
 		break;
+	case OUTPUT_DP:
+		if (nv_connector->base.display_info.bpc == 6) {
+			nv_encoder->dp.datarate = mode->clock * 18 / 8;
+			syncs |= 0x00000140;
+		} else {
+			nv_encoder->dp.datarate = mode->clock * 24 / 8;
+			syncs |= 0x00000180;
+		}
+
+		if (nv_encoder->dcb->sorconf.link & 1)
+			mode_ctrl |= 0x00000800;
+		else
+			mode_ctrl |= 0x00000900;
+
+		or_config = (mode_ctrl & 0x00000f00) >> 8;
+		break;
 	default:
 		BUG_ON(1);
 		break;
@@ -1313,9 +1528,17 @@
 
 	nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON);
 
-	push = evo_wait(dev, EVO_MASTER, 4);
+	if (nv_encoder->dcb->type == OUTPUT_DP) {
+		nvd0_sor_dp_calc_tu(dev, nv_encoder->dcb, nv_crtc->index,
+					 nv_encoder->dp.datarate);
+	}
+
+	push = evo_wait(dev, EVO_MASTER, 8);
 	if (push) {
-		evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2);
+		evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
+		evo_data(push, syncs);
+		evo_data(push, magic);
+		evo_mthd(push, 0x0200 + (nv_encoder->or * 0x020), 2);
 		evo_data(push, mode_ctrl);
 		evo_data(push, or_config);
 		evo_kick(push, dev, EVO_MASTER);
@@ -1325,32 +1548,6 @@
 }
 
 static void
-nvd0_sor_disconnect(struct drm_encoder *encoder)
-{
-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-	struct drm_device *dev = encoder->dev;
-	u32 *push;
-
-	if (nv_encoder->crtc) {
-		nvd0_crtc_prepare(nv_encoder->crtc);
-
-		push = evo_wait(dev, EVO_MASTER, 4);
-		if (push) {
-			evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
-			evo_data(push, 0x00000000);
-			evo_mthd(push, 0x0080, 1);
-			evo_data(push, 0x00000000);
-			evo_kick(push, dev, EVO_MASTER);
-		}
-
-		nvd0_hdmi_disconnect(encoder);
-
-		nv_encoder->crtc = NULL;
-		nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
-	}
-}
-
-static void
 nvd0_sor_destroy(struct drm_encoder *encoder)
 {
 	drm_encoder_cleanup(encoder);
@@ -1402,17 +1599,19 @@
 lookup_dcb(struct drm_device *dev, int id, u32 mc)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	int type, or, i;
+	int type, or, i, link = -1;
 
 	if (id < 4) {
 		type = OUTPUT_ANALOG;
 		or   = id;
 	} else {
 		switch (mc & 0x00000f00) {
-		case 0x00000000: type = OUTPUT_LVDS; break;
-		case 0x00000100: type = OUTPUT_TMDS; break;
-		case 0x00000200: type = OUTPUT_TMDS; break;
-		case 0x00000500: type = OUTPUT_TMDS; break;
+		case 0x00000000: link = 0; type = OUTPUT_LVDS; break;
+		case 0x00000100: link = 0; type = OUTPUT_TMDS; break;
+		case 0x00000200: link = 1; type = OUTPUT_TMDS; break;
+		case 0x00000500: link = 0; type = OUTPUT_TMDS; break;
+		case 0x00000800: link = 0; type = OUTPUT_DP; break;
+		case 0x00000900: link = 1; type = OUTPUT_DP; break;
 		default:
 			NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc);
 			return NULL;
@@ -1423,7 +1622,8 @@
 
 	for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
 		struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
-		if (dcb->type == type && (dcb->or & (1 << or)))
+		if (dcb->type == type && (dcb->or & (1 << or)) &&
+		    (link < 0 || link == !(dcb->sorconf.link & 1)))
 			return dcb;
 	}
 
@@ -1474,7 +1674,9 @@
 	}
 
 	pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
-	if (mask & 0x00010000) {
+	NV_DEBUG_KMS(dev, "PDISP: crtc %d pclk %d mask 0x%08x\n",
+			  crtc, pclk, mask);
+	if (pclk && (mask & 0x00010000)) {
 		nv50_crtc_set_clock(dev, crtc, pclk);
 	}
 
@@ -1498,6 +1700,7 @@
 			break;
 		case OUTPUT_TMDS:
 		case OUTPUT_LVDS:
+		case OUTPUT_DP:
 			if (cfg & 0x00000100)
 				tmp = 0x00000101;
 			else
@@ -1548,7 +1751,7 @@
 {
 	struct drm_device *dev = (struct drm_device *)data;
 	struct nvd0_display *disp = nvd0_display(dev);
-	u32 mask, crtc;
+	u32 mask = 0, crtc = ~0;
 	int i;
 
 	if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) {
@@ -1564,12 +1767,8 @@
 		}
 	}
 
-	mask = nv_rd32(dev, 0x6101d4);
-	crtc = 0;
-	if (!mask) {
-		mask = nv_rd32(dev, 0x6109d4);
-		crtc = 1;
-	}
+	while (!mask && ++crtc < dev->mode_config.num_crtc)
+		mask = nv_rd32(dev, 0x6101d4 + (crtc * 0x800));
 
 	if (disp->modeset & 0x00000001)
 		nvd0_display_unk1_handler(dev, crtc, mask);
@@ -1584,6 +1783,7 @@
 {
 	struct nvd0_display *disp = nvd0_display(dev);
 	u32 intr = nv_rd32(dev, 0x610088);
+	int i;
 
 	if (intr & 0x00000001) {
 		u32 stat = nv_rd32(dev, 0x61008c);
@@ -1628,16 +1828,13 @@
 		intr &= ~0x00100000;
 	}
 
-	if (intr & 0x01000000) {
-		u32 stat = nv_rd32(dev, 0x6100bc);
-		nv_wr32(dev, 0x6100bc, stat);
-		intr &= ~0x01000000;
-	}
-
-	if (intr & 0x02000000) {
-		u32 stat = nv_rd32(dev, 0x6108bc);
-		nv_wr32(dev, 0x6108bc, stat);
-		intr &= ~0x02000000;
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		u32 mask = 0x01000000 << i;
+		if (intr & mask) {
+			u32 stat = nv_rd32(dev, 0x6100bc + (i * 0x800));
+			nv_wr32(dev, 0x6100bc + (i * 0x800), stat);
+			intr &= ~mask;
+		}
 	}
 
 	if (intr)
@@ -1774,7 +1971,7 @@
 	struct pci_dev *pdev = dev->pdev;
 	struct nvd0_display *disp;
 	struct dcb_entry *dcbe;
-	int ret, i;
+	int crtcs, ret, i;
 
 	disp = kzalloc(sizeof(*disp), GFP_KERNEL);
 	if (!disp)
@@ -1782,7 +1979,8 @@
 	dev_priv->engine.display.priv = disp;
 
 	/* create crtc objects to represent the hw heads */
-	for (i = 0; i < 2; i++) {
+	crtcs = nv_rd32(dev, 0x022448);
+	for (i = 0; i < crtcs; i++) {
 		ret = nvd0_crtc_create(dev, i);
 		if (ret)
 			goto out;
@@ -1803,6 +2001,7 @@
 		switch (dcbe->type) {
 		case OUTPUT_TMDS:
 		case OUTPUT_LVDS:
+		case OUTPUT_DP:
 			nvd0_sor_create(connector, dcbe);
 			break;
 		case OUTPUT_ANALOG:
diff --git a/drivers/gpu/drm/r128/r128_drv.c b/drivers/gpu/drm/r128/r128_drv.c
index 6a5f439..88718fa 100644
--- a/drivers/gpu/drm/r128/r128_drv.c
+++ b/drivers/gpu/drm/r128/r128_drv.c
@@ -85,6 +85,7 @@
 
 int r128_driver_load(struct drm_device *dev, unsigned long flags)
 {
+	pci_set_master(dev->pdev);
 	return drm_vblank_init(dev, 1);
 }
 
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 2139fe8..9d83729 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -71,7 +71,7 @@
 	r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \
 	evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \
 	radeon_trace_points.o ni.o cayman_blit_shaders.o atombios_encoders.o \
-	radeon_semaphore.o radeon_sa.o
+	radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o si_blit_shaders.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/ObjectID.h b/drivers/gpu/drm/radeon/ObjectID.h
index c61c3fe..ca4b038 100644
--- a/drivers/gpu/drm/radeon/ObjectID.h
+++ b/drivers/gpu/drm/radeon/ObjectID.h
@@ -85,6 +85,7 @@
 #define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA   0x1F
 #define ENCODER_OBJECT_ID_INTERNAL_UNIPHY1        0x20
 #define ENCODER_OBJECT_ID_INTERNAL_UNIPHY2        0x21
+#define ENCODER_OBJECT_ID_INTERNAL_VCE            0x24
 
 #define ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO    0xFF
 
@@ -387,6 +388,10 @@
                                                   GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
                                                   ENCODER_OBJECT_ID_NUTMEG << OBJECT_ID_SHIFT)
 
+#define ENCODER_VCE_ENUM_ID1                     ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+                                                  GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+                                                  ENCODER_OBJECT_ID_INTERNAL_VCE << OBJECT_ID_SHIFT)
+
 /****************************************************/
 /* Connector Object ID definition - Shared with BIOS */
 /****************************************************/
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
index d1bd239..5ce9bf5 100644
--- a/drivers/gpu/drm/radeon/atom.c
+++ b/drivers/gpu/drm/radeon/atom.c
@@ -1306,8 +1306,11 @@
 
 int atom_asic_init(struct atom_context *ctx)
 {
+	struct radeon_device *rdev = ctx->card->dev->dev_private;
 	int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
 	uint32_t ps[16];
+	int ret;
+
 	memset(ps, 0, 64);
 
 	ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR));
@@ -1317,7 +1320,17 @@
 
 	if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
 		return 1;
-	return atom_execute_table(ctx, ATOM_CMD_INIT, ps);
+	ret = atom_execute_table(ctx, ATOM_CMD_INIT, ps);
+	if (ret)
+		return ret;
+
+	memset(ps, 0, 64);
+
+	if (rdev->family < CHIP_R600) {
+		if (CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_SPDFANCNTL))
+			atom_execute_table(ctx, ATOM_CMD_SPDFANCNTL, ps);
+	}
+	return ret;
 }
 
 void atom_destroy(struct atom_context *ctx)
diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h
index 93cfe20..25fea63 100644
--- a/drivers/gpu/drm/radeon/atom.h
+++ b/drivers/gpu/drm/radeon/atom.h
@@ -44,6 +44,7 @@
 #define ATOM_CMD_SETSCLK	0x0A
 #define ATOM_CMD_SETMCLK	0x0B
 #define ATOM_CMD_SETPCLK	0x0C
+#define ATOM_CMD_SPDFANCNTL	0x39
 
 #define ATOM_DATA_FWI_PTR	0xC
 #define ATOM_DATA_IIO_PTR	0x32
diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h
index 1b50ad8..4b04ba3 100644
--- a/drivers/gpu/drm/radeon/atombios.h
+++ b/drivers/gpu/drm/radeon/atombios.h
@@ -101,6 +101,7 @@
 #define ATOM_LCD_SELFTEST_START									(ATOM_DISABLE+5)
 #define ATOM_LCD_SELFTEST_STOP									(ATOM_ENABLE+5)
 #define ATOM_ENCODER_INIT			                  (ATOM_DISABLE+7)
+#define ATOM_INIT			                          (ATOM_DISABLE+7)
 #define ATOM_GET_STATUS                         (ATOM_DISABLE+8)
 
 #define ATOM_BLANKING         1
@@ -251,25 +252,25 @@
   USHORT SetEngineClock;                         //Function Table,directly used by various SW components,latest version 1.1
   USHORT SetMemoryClock;                         //Function Table,directly used by various SW components,latest version 1.1
   USHORT SetPixelClock;                          //Function Table,directly used by various SW components,latest version 1.2  
-  USHORT DynamicClockGating;                     //Atomic Table,  indirectly used by various SW components,called from ASIC_Init
+  USHORT EnableDispPowerGating;                  //Atomic Table,  indirectly used by various SW components,called from ASIC_Init
   USHORT ResetMemoryDLL;                         //Atomic Table,  indirectly used by various SW components,called from SetMemoryClock
   USHORT ResetMemoryDevice;                      //Atomic Table,  indirectly used by various SW components,called from SetMemoryClock
-  USHORT MemoryPLLInit;
-  USHORT AdjustDisplayPll;												//only used by Bios
+  USHORT MemoryPLLInit;                          //Atomic Table,  used only by Bios
+  USHORT AdjustDisplayPll;											 //Atomic Table,  used by various SW componentes. 
   USHORT AdjustMemoryController;                 //Atomic Table,  indirectly used by various SW components,called from SetMemoryClock                
   USHORT EnableASIC_StaticPwrMgt;                //Atomic Table,  only used by Bios
   USHORT ASIC_StaticPwrMgtStatusChange;          //Obsolete ,     only used by Bios   
   USHORT DAC_LoadDetection;                      //Atomic Table,  directly used by various SW components,latest version 1.2  
   USHORT LVTMAEncoderControl;                    //Atomic Table,directly used by various SW components,latest version 1.3
-  USHORT LCD1OutputControl;                      //Atomic Table,  directly used by various SW components,latest version 1.1 
+  USHORT HW_Misc_Operation;                      //Atomic Table,  directly used by various SW components,latest version 1.1 
   USHORT DAC1EncoderControl;                     //Atomic Table,  directly used by various SW components,latest version 1.1  
   USHORT DAC2EncoderControl;                     //Atomic Table,  directly used by various SW components,latest version 1.1 
   USHORT DVOOutputControl;                       //Atomic Table,  directly used by various SW components,latest version 1.1 
   USHORT CV1OutputControl;                       //Atomic Table,  Atomic Table,  Obsolete from Ry6xx, use DAC2 Output instead 
-  USHORT GetConditionalGoldenSetting;            //only used by Bios
+  USHORT GetConditionalGoldenSetting;            //Only used by Bios
   USHORT TVEncoderControl;                       //Function Table,directly used by various SW components,latest version 1.1
-  USHORT TMDSAEncoderControl;                    //Atomic Table,  directly used by various SW components,latest version 1.3
-  USHORT LVDSEncoderControl;                     //Atomic Table,  directly used by various SW components,latest version 1.3
+  USHORT PatchMCSetting;                         //only used by BIOS
+  USHORT MC_SEQ_Control;                         //only used by BIOS
   USHORT TV1OutputControl;                       //Atomic Table,  Obsolete from Ry6xx, use DAC2 Output instead
   USHORT EnableScaler;                           //Atomic Table,  used only by Bios
   USHORT BlankCRTC;                              //Atomic Table,  directly used by various SW components,latest version 1.1 
@@ -282,7 +283,7 @@
   USHORT SetCRTC_Replication;                    //Atomic Table,  used only by Bios
   USHORT SelectCRTC_Source;                      //Atomic Table,  directly used by various SW components,latest version 1.1 
   USHORT EnableGraphSurfaces;                    //Atomic Table,  used only by Bios
-  USHORT UpdateCRTC_DoubleBufferRegisters;
+  USHORT UpdateCRTC_DoubleBufferRegisters;			 //Atomic Table,  used only by Bios
   USHORT LUT_AutoFill;                           //Atomic Table,  only used by Bios
   USHORT EnableHW_IconCursor;                    //Atomic Table,  only used by Bios
   USHORT GetMemoryClock;                         //Atomic Table,  directly used by various SW components,latest version 1.1 
@@ -308,27 +309,36 @@
   USHORT SetVoltage;                             //Function Table,directly and/or indirectly used by various SW components,latest version 1.1
   USHORT DAC1OutputControl;                      //Atomic Table,  directly used by various SW components,latest version 1.1
   USHORT DAC2OutputControl;                      //Atomic Table,  directly used by various SW components,latest version 1.1
-  USHORT SetupHWAssistedI2CStatus;               //Function Table,only used by Bios, obsolete soon.Switch to use "ReadEDIDFromHWAssistedI2C"
+  USHORT ComputeMemoryClockParam;                //Function Table,only used by Bios, obsolete soon.Switch to use "ReadEDIDFromHWAssistedI2C"
   USHORT ClockSource;                            //Atomic Table,  indirectly used by various SW components,called from ASIC_Init
   USHORT MemoryDeviceInit;                       //Atomic Table,  indirectly used by various SW components,called from SetMemoryClock
-  USHORT EnableYUV;                              //Atomic Table,  indirectly used by various SW components,called from EnableVGARender
+  USHORT GetDispObjectInfo;                      //Atomic Table,  indirectly used by various SW components,called from EnableVGARender
   USHORT DIG1EncoderControl;                     //Atomic Table,directly used by various SW components,latest version 1.1
   USHORT DIG2EncoderControl;                     //Atomic Table,directly used by various SW components,latest version 1.1
   USHORT DIG1TransmitterControl;                 //Atomic Table,directly used by various SW components,latest version 1.1
   USHORT DIG2TransmitterControl;	               //Atomic Table,directly used by various SW components,latest version 1.1 
   USHORT ProcessAuxChannelTransaction;					 //Function Table,only used by Bios
   USHORT DPEncoderService;											 //Function Table,only used by Bios
+  USHORT GetVoltageInfo;                         //Function Table,only used by Bios since SI
 }ATOM_MASTER_LIST_OF_COMMAND_TABLES;   
 
 // For backward compatible 
 #define ReadEDIDFromHWAssistedI2C                ProcessI2cChannelTransaction
-#define UNIPHYTransmitterControl						     DIG1TransmitterControl
-#define LVTMATransmitterControl							     DIG2TransmitterControl
+#define DPTranslatorControl                      DIG2EncoderControl
+#define UNIPHYTransmitterControl			     DIG1TransmitterControl
+#define LVTMATransmitterControl				     DIG2TransmitterControl
 #define SetCRTC_DPM_State                        GetConditionalGoldenSetting
 #define SetUniphyInstance                        ASIC_StaticPwrMgtStatusChange
 #define HPDInterruptService                      ReadHWAssistedI2CStatus
 #define EnableVGA_Access                         GetSCLKOverMCLKRatio
-#define GetDispObjectInfo                        EnableYUV 
+#define EnableYUV                                GetDispObjectInfo                         
+#define DynamicClockGating                       EnableDispPowerGating
+#define SetupHWAssistedI2CStatus                 ComputeMemoryClockParam
+
+#define TMDSAEncoderControl                      PatchMCSetting
+#define LVDSEncoderControl                       MC_SEQ_Control
+#define LCD1OutputControl                        HW_Misc_Operation
+
 
 typedef struct _ATOM_MASTER_COMMAND_TABLE
 {
@@ -495,6 +505,34 @@
 // ucInputFlag
 #define ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN  1   // 1-StrobeMode, 0-PerformanceMode
 
+// use for ComputeMemoryClockParamTable
+typedef struct _COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1
+{
+  union
+  {
+    ULONG  ulClock;         
+    ATOM_S_MPLL_FB_DIVIDER   ulFbDiv;         //Output:UPPER_WORD=FB_DIV_INTEGER,  LOWER_WORD=FB_DIV_FRAC shl (16-FB_FRACTION_BITS)
+  };
+  UCHAR   ucDllSpeed;                         //Output 
+  UCHAR   ucPostDiv;                          //Output
+  union{
+    UCHAR   ucInputFlag;                      //Input : ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN: 1-StrobeMode, 0-PerformanceMode
+    UCHAR   ucPllCntlFlag;                    //Output: 
+  };
+  UCHAR   ucBWCntl;                       
+}COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1;
+
+// definition of ucInputFlag
+#define MPLL_INPUT_FLAG_STROBE_MODE_EN          0x01
+// definition of ucPllCntlFlag
+#define MPLL_CNTL_FLAG_VCO_MODE_MASK            0x03 
+#define MPLL_CNTL_FLAG_BYPASS_DQ_PLL            0x04
+#define MPLL_CNTL_FLAG_QDR_ENABLE               0x08
+#define MPLL_CNTL_FLAG_AD_HALF_RATE             0x10
+
+//MPLL_CNTL_FLAG_BYPASS_AD_PLL has a wrong name, should be BYPASS_DQ_PLL
+#define MPLL_CNTL_FLAG_BYPASS_AD_PLL            0x04
+
 typedef struct _DYNAMICE_MEMORY_SETTINGS_PARAMETER
 {
   ATOM_COMPUTE_CLOCK_FREQ ulClock;
@@ -562,6 +600,16 @@
 #define  DYNAMIC_CLOCK_GATING_PS_ALLOCATION  DYNAMIC_CLOCK_GATING_PARAMETERS
 
 /****************************************************************************/	
+// Structure used by EnableDispPowerGatingTable.ctb
+/****************************************************************************/	
+typedef struct _ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 
+{
+  UCHAR ucDispPipeId;                 // ATOM_CRTC1, ATOM_CRTC2, ...
+  UCHAR ucEnable;                     // ATOM_ENABLE or ATOM_DISABLE
+  UCHAR ucPadding[2];
+}ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1;
+
+/****************************************************************************/	
 // Structure used by EnableASIC_StaticPwrMgtTable.ctb
 /****************************************************************************/	
 typedef struct _ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS
@@ -807,6 +855,7 @@
 #define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ		  0x00
 #define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ		  0x01
 #define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ		  0x02
+#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_3_24GHZ		  0x03
 #define ATOM_ENCODER_CONFIG_V4_ENCODER_SEL					  0x70
 #define ATOM_ENCODER_CONFIG_V4_DIG0_ENCODER					  0x00
 #define ATOM_ENCODER_CONFIG_V4_DIG1_ENCODER					  0x10
@@ -814,6 +863,7 @@
 #define ATOM_ENCODER_CONFIG_V4_DIG3_ENCODER					  0x30
 #define ATOM_ENCODER_CONFIG_V4_DIG4_ENCODER					  0x40
 #define ATOM_ENCODER_CONFIG_V4_DIG5_ENCODER					  0x50
+#define ATOM_ENCODER_CONFIG_V4_DIG6_ENCODER					  0x60
 
 typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V4
 {
@@ -1171,6 +1221,106 @@
 #define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER3           	0x80	//EF
 
 
+typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V5
+{
+#if ATOM_BIG_ENDIAN
+  UCHAR ucReservd1:1;
+  UCHAR ucHPDSel:3;
+  UCHAR ucPhyClkSrcId:2;            
+  UCHAR ucCoherentMode:1;            
+  UCHAR ucReserved:1;
+#else
+  UCHAR ucReserved:1;
+  UCHAR ucCoherentMode:1;            
+  UCHAR ucPhyClkSrcId:2;            
+  UCHAR ucHPDSel:3;
+  UCHAR ucReservd1:1;
+#endif
+}ATOM_DIG_TRANSMITTER_CONFIG_V5;
+
+typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5
+{
+  USHORT usSymClock;		        // Encoder Clock in 10kHz,(DP mode)= linkclock/10, (TMDS/LVDS/HDMI)= pixel clock,  (HDMI deep color), =pixel clock * deep_color_ratio
+  UCHAR  ucPhyId;                   // 0=UNIPHYA, 1=UNIPHYB, 2=UNIPHYC, 3=UNIPHYD, 4= UNIPHYE 5=UNIPHYF
+  UCHAR  ucAction;				    // define as ATOM_TRANSMITER_ACTION_xxx
+  UCHAR  ucLaneNum;                 // indicate lane number 1-8
+  UCHAR  ucConnObjId;               // Connector Object Id defined in ObjectId.h
+  UCHAR  ucDigMode;                 // indicate DIG mode
+  union{
+  ATOM_DIG_TRANSMITTER_CONFIG_V5 asConfig;
+  UCHAR ucConfig;
+  };
+  UCHAR  ucDigEncoderSel;           // indicate DIG front end encoder 
+  UCHAR  ucDPLaneSet;
+  UCHAR  ucReserved;
+  UCHAR  ucReserved1;
+}DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5;
+
+//ucPhyId
+#define ATOM_PHY_ID_UNIPHYA                                 0  
+#define ATOM_PHY_ID_UNIPHYB                                 1
+#define ATOM_PHY_ID_UNIPHYC                                 2
+#define ATOM_PHY_ID_UNIPHYD                                 3
+#define ATOM_PHY_ID_UNIPHYE                                 4
+#define ATOM_PHY_ID_UNIPHYF                                 5
+#define ATOM_PHY_ID_UNIPHYG                                 6
+
+// ucDigEncoderSel
+#define ATOM_TRANMSITTER_V5__DIGA_SEL                       0x01
+#define ATOM_TRANMSITTER_V5__DIGB_SEL                       0x02
+#define ATOM_TRANMSITTER_V5__DIGC_SEL                       0x04
+#define ATOM_TRANMSITTER_V5__DIGD_SEL                       0x08
+#define ATOM_TRANMSITTER_V5__DIGE_SEL                       0x10
+#define ATOM_TRANMSITTER_V5__DIGF_SEL                       0x20
+#define ATOM_TRANMSITTER_V5__DIGG_SEL                       0x40
+
+// ucDigMode
+#define ATOM_TRANSMITTER_DIGMODE_V5_DP                      0
+#define ATOM_TRANSMITTER_DIGMODE_V5_LVDS                    1
+#define ATOM_TRANSMITTER_DIGMODE_V5_DVI                     2
+#define ATOM_TRANSMITTER_DIGMODE_V5_HDMI                    3
+#define ATOM_TRANSMITTER_DIGMODE_V5_SDVO                    4
+#define ATOM_TRANSMITTER_DIGMODE_V5_DP_MST                  5
+
+// ucDPLaneSet
+#define DP_LANE_SET__0DB_0_4V                               0x00
+#define DP_LANE_SET__0DB_0_6V                               0x01
+#define DP_LANE_SET__0DB_0_8V                               0x02
+#define DP_LANE_SET__0DB_1_2V                               0x03
+#define DP_LANE_SET__3_5DB_0_4V                             0x08  
+#define DP_LANE_SET__3_5DB_0_6V                             0x09
+#define DP_LANE_SET__3_5DB_0_8V                             0x0a
+#define DP_LANE_SET__6DB_0_4V                               0x10
+#define DP_LANE_SET__6DB_0_6V                               0x11
+#define DP_LANE_SET__9_5DB_0_4V                             0x18  
+
+// ATOM_DIG_TRANSMITTER_CONFIG_V5 asConfig;
+// Bit1
+#define ATOM_TRANSMITTER_CONFIG_V5_COHERENT				          0x02
+
+// Bit3:2
+#define ATOM_TRANSMITTER_CONFIG_V5_REFCLK_SEL_MASK 	        0x0c
+#define ATOM_TRANSMITTER_CONFIG_V5_REFCLK_SEL_SHIFT		    0x02
+
+#define ATOM_TRANSMITTER_CONFIG_V5_P1PLL         		        0x00
+#define ATOM_TRANSMITTER_CONFIG_V5_P2PLL		                0x04
+#define ATOM_TRANSMITTER_CONFIG_V5_P0PLL		                0x08   
+#define ATOM_TRANSMITTER_CONFIG_V5_REFCLK_SRC_EXT           0x0c
+// Bit6:4
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD_SEL_MASK		          0x70
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD_SEL_SHIFT		      0x04
+
+#define ATOM_TRANSMITTER_CONFIG_V5_NO_HPD_SEL				        0x00
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD1_SEL				          0x10
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD2_SEL				          0x20
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD3_SEL				          0x30
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD4_SEL				          0x40
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD5_SEL				          0x50
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD6_SEL				          0x60
+
+#define DIG_TRANSMITTER_CONTROL_PS_ALLOCATION_V1_5            DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5
+
+
 /****************************************************************************/	
 // Structures used by ExternalEncoderControlTable V1.3
 // ASIC Families: Evergreen, Llano, NI
@@ -1793,6 +1943,7 @@
 #define ATOM_PPLL_SS_TYPE_V3_P1PLL            0x00
 #define ATOM_PPLL_SS_TYPE_V3_P2PLL            0x04
 #define ATOM_PPLL_SS_TYPE_V3_DCPLL            0x08
+#define ATOM_PPLL_SS_TYPE_V3_P0PLL            ATOM_PPLL_SS_TYPE_V3_DCPLL
 #define ATOM_PPLL_SS_AMOUNT_V3_FBDIV_MASK     0x00FF
 #define ATOM_PPLL_SS_AMOUNT_V3_FBDIV_SHIFT    0
 #define ATOM_PPLL_SS_AMOUNT_V3_NFRAC_MASK     0x0F00
@@ -2030,12 +2181,77 @@
   USHORT   usVoltageLevel;              // real voltage level
 }SET_VOLTAGE_PARAMETERS_V2;
 
+
+typedef struct	_SET_VOLTAGE_PARAMETERS_V1_3
+{
+  UCHAR    ucVoltageType;               // To tell which voltage to set up, VDDC/MVDDC/MVDDQ/VDDCI
+  UCHAR    ucVoltageMode;               // Indicate action: Set voltage level
+  USHORT   usVoltageLevel;              // real voltage level in unit of mv or Voltage Phase (0, 1, 2, .. )
+}SET_VOLTAGE_PARAMETERS_V1_3;
+
+//ucVoltageType
+#define VOLTAGE_TYPE_VDDC                    1
+#define VOLTAGE_TYPE_MVDDC                   2
+#define VOLTAGE_TYPE_MVDDQ                   3
+#define VOLTAGE_TYPE_VDDCI                   4
+
+//SET_VOLTAGE_PARAMETERS_V3.ucVoltageMode
+#define ATOM_SET_VOLTAGE                     0        //Set voltage Level
+#define ATOM_INIT_VOLTAGE_REGULATOR          3        //Init Regulator
+#define ATOM_SET_VOLTAGE_PHASE               4        //Set Vregulator Phase
+#define ATOM_GET_MAX_VOLTAGE                 6        //Get Max Voltage, not used in SetVoltageTable v1.3
+#define ATOM_GET_VOLTAGE_LEVEL               6        //Get Voltage level from vitual voltage ID
+
+// define vitual voltage id in usVoltageLevel
+#define ATOM_VIRTUAL_VOLTAGE_ID0             0xff01
+#define ATOM_VIRTUAL_VOLTAGE_ID1             0xff02
+#define ATOM_VIRTUAL_VOLTAGE_ID2             0xff03
+#define ATOM_VIRTUAL_VOLTAGE_ID3             0xff04
+
 typedef struct _SET_VOLTAGE_PS_ALLOCATION
 {
   SET_VOLTAGE_PARAMETERS sASICSetVoltage;
   WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;
 }SET_VOLTAGE_PS_ALLOCATION;
 
+// New Added from SI for GetVoltageInfoTable, input parameter structure
+typedef struct  _GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_1
+{
+  UCHAR    ucVoltageType;               // Input: To tell which voltage to set up, VDDC/MVDDC/MVDDQ/VDDCI
+  UCHAR    ucVoltageMode;               // Input: Indicate action: Get voltage info
+  USHORT   usVoltageLevel;              // Input: real voltage level in unit of mv or Voltage Phase (0, 1, 2, .. ) or Leakage Id 
+  ULONG    ulReserved;
+}GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_1;
+
+// New Added from SI for GetVoltageInfoTable, output parameter structure when ucVotlageMode == ATOM_GET_VOLTAGE_VID
+typedef struct  _GET_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_1
+{
+  ULONG    ulVotlageGpioState;
+  ULONG    ulVoltageGPioMask;
+}GET_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_1;
+
+// New Added from SI for GetVoltageInfoTable, output parameter structure when ucVotlageMode == ATOM_GET_VOLTAGE_STATEx_LEAKAGE_VID
+typedef struct  _GET_LEAKAGE_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_1
+{
+  USHORT   usVoltageLevel;
+  USHORT   usVoltageId;                                  // Voltage Id programmed in Voltage Regulator
+  ULONG    ulReseved;
+}GET_LEAKAGE_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_1;
+
+
+// GetVoltageInfo v1.1 ucVoltageMode
+#define	ATOM_GET_VOLTAGE_VID                0x00
+#define ATOM_GET_VOTLAGE_INIT_SEQ           0x03
+#define ATOM_GET_VOLTTAGE_PHASE_PHASE_VID   0x04
+// for SI, this state map to 0xff02 voltage state in Power Play table, which is power boost state
+#define	ATOM_GET_VOLTAGE_STATE0_LEAKAGE_VID 0x10
+
+// for SI, this state map to 0xff01 voltage state in Power Play table, which is performance state
+#define	ATOM_GET_VOLTAGE_STATE1_LEAKAGE_VID 0x11
+// undefined power state
+#define	ATOM_GET_VOLTAGE_STATE2_LEAKAGE_VID 0x12
+#define	ATOM_GET_VOLTAGE_STATE3_LEAKAGE_VID 0x13
+
 /****************************************************************************/	
 // Structures used by TVEncoderControlTable
 /****************************************************************************/	
@@ -2065,9 +2281,9 @@
   USHORT        MultimediaConfigInfo;     // Only used by MM Lib,latest version 2.1, not configuable from Bios, need to include the table to build Bios
   USHORT        StandardVESA_Timing;      // Only used by Bios
   USHORT        FirmwareInfo;             // Shared by various SW components,latest version 1.4
-  USHORT        DAC_Info;                 // Will be obsolete from R600
+  USHORT        PaletteData;              // Only used by BIOS
   USHORT        LCD_Info;                 // Shared by various SW components,latest version 1.3, was called LVDS_Info 
-  USHORT        TMDS_Info;                // Will be obsolete from R600
+  USHORT        DIGTransmitterInfo;       // Internal used by VBIOS only version 3.1
   USHORT        AnalogTV_Info;            // Shared by various SW components,latest version 1.1 
   USHORT        SupportedDevicesInfo;     // Will be obsolete from R600
   USHORT        GPIO_I2C_Info;            // Shared by various SW components,latest version 1.2 will be used from R600           
@@ -2096,15 +2312,16 @@
 	USHORT				PowerSourceInfo;					// Shared by various SW components, latest versoin 1.1
 }ATOM_MASTER_LIST_OF_DATA_TABLES;
 
-// For backward compatible 
-#define LVDS_Info                LCD_Info
-
 typedef struct _ATOM_MASTER_DATA_TABLE
 { 
   ATOM_COMMON_TABLE_HEADER sHeader;  
   ATOM_MASTER_LIST_OF_DATA_TABLES   ListOfDataTables;
 }ATOM_MASTER_DATA_TABLE;
 
+// For backward compatible 
+#define LVDS_Info                LCD_Info
+#define DAC_Info                 PaletteData
+#define TMDS_Info                DIGTransmitterInfo
 
 /****************************************************************************/	
 // Structure used in MultimediaCapabilityInfoTable
@@ -2171,7 +2388,9 @@
 typedef struct _ATOM_FIRMWARE_CAPABILITY
 {
 #if ATOM_BIG_ENDIAN
-  USHORT Reserved:3;
+  USHORT Reserved:1;
+  USHORT SCL2Redefined:1;
+  USHORT PostWithoutModeSet:1;
   USHORT HyperMemory_Size:4;
   USHORT HyperMemory_Support:1;
   USHORT PPMode_Assigned:1;
@@ -2193,7 +2412,9 @@
   USHORT PPMode_Assigned:1;
   USHORT HyperMemory_Support:1;
   USHORT HyperMemory_Size:4;
-  USHORT Reserved:3;
+  USHORT PostWithoutModeSet:1;
+  USHORT SCL2Redefined:1;
+  USHORT Reserved:1;
 #endif
 }ATOM_FIRMWARE_CAPABILITY;
 
@@ -2418,7 +2639,8 @@
   USHORT                          usLcdMaxPixelClockPLL_Output; // In MHz unit
   ULONG                           ulReserved4;                //Was ulAsicMaximumVoltage
   ULONG                           ulMinPixelClockPLL_Output;  //In 10Khz unit
-  ULONG                           ulReserved5;                //Was usMinEngineClockPLL_Input and usMaxEngineClockPLL_Input
+  UCHAR                           ucRemoteDisplayConfig;
+  UCHAR                           ucReserved5[3];             //Was usMinEngineClockPLL_Input and usMaxEngineClockPLL_Input
   ULONG                           ulReserved6;                //Was usMinEngineClockPLL_Output and usMinMemoryClockPLL_Input
   ULONG                           ulReserved7;                //Was usMaxMemoryClockPLL_Input and usMinMemoryClockPLL_Output
   USHORT                          usReserved11;               //Was usMaxPixelClock;  //In 10Khz unit, Max.  Pclk used only for DAC
@@ -2438,6 +2660,11 @@
 
 #define ATOM_FIRMWARE_INFO_LAST  ATOM_FIRMWARE_INFO_V2_2
 
+
+// definition of ucRemoteDisplayConfig
+#define REMOTE_DISPLAY_DISABLE                   0x00
+#define REMOTE_DISPLAY_ENABLE                    0x01
+
 /****************************************************************************/	
 // Structures used in IntegratedSystemInfoTable
 /****************************************************************************/	
@@ -2660,8 +2887,9 @@
 #define    INTEGRATED_SYSTEM_INFO__AMD_CPU__GREYHOUND      2
 #define    INTEGRATED_SYSTEM_INFO__AMD_CPU__K8             3
 #define    INTEGRATED_SYSTEM_INFO__AMD_CPU__PHARAOH        4
+#define    INTEGRATED_SYSTEM_INFO__AMD_CPU__OROCHI         5
 
-#define    INTEGRATED_SYSTEM_INFO__AMD_CPU__MAX_CODE       INTEGRATED_SYSTEM_INFO__AMD_CPU__PHARAOH    // this deff reflects max defined CPU code
+#define    INTEGRATED_SYSTEM_INFO__AMD_CPU__MAX_CODE       INTEGRATED_SYSTEM_INFO__AMD_CPU__OROCHI    // this deff reflects max defined CPU code
 
 #define SYSTEM_CONFIG_POWEREXPRESS_ENABLE                 0x00000001
 #define SYSTEM_CONFIG_RUN_AT_OVERDRIVE_ENGINE             0x00000002
@@ -2753,6 +2981,7 @@
 #define ASIC_INT_DIG4_ENCODER_ID													0x0b
 #define ASIC_INT_DIG5_ENCODER_ID													0x0c
 #define ASIC_INT_DIG6_ENCODER_ID													0x0d
+#define ASIC_INT_DIG7_ENCODER_ID													0x0e
 
 //define Encoder attribute
 #define ATOM_ANALOG_ENCODER																0
@@ -3226,15 +3455,23 @@
 
   UCHAR               ucPowerSequenceDIGONtoDE_in4Ms;
   UCHAR               ucPowerSequenceDEtoVARY_BL_in4Ms;
-  UCHAR               ucPowerSequenceDEtoDIGON_in4Ms;
   UCHAR               ucPowerSequenceVARY_BLtoDE_in4Ms;
+  UCHAR               ucPowerSequenceDEtoDIGON_in4Ms;
 
   UCHAR               ucOffDelay_in4Ms;
   UCHAR               ucPowerSequenceVARY_BLtoBLON_in4Ms;
   UCHAR               ucPowerSequenceBLONtoVARY_BL_in4Ms;
   UCHAR               ucReserved1;
 
-  ULONG               ulReserved[4];
+  UCHAR               ucDPCD_eDP_CONFIGURATION_CAP;     // dpcd 0dh
+  UCHAR               ucDPCD_MAX_LINK_RATE;             // dpcd 01h
+  UCHAR               ucDPCD_MAX_LANE_COUNT;            // dpcd 02h
+  UCHAR               ucDPCD_MAX_DOWNSPREAD;            // dpcd 03h
+
+  USHORT              usMaxPclkFreqInSingleLink;        // Max PixelClock frequency in single link mode. 
+  UCHAR               uceDPToLVDSRxId;
+  UCHAR               ucLcdReservd;
+  ULONG               ulReserved[2];
 }ATOM_LCD_INFO_V13;  
 
 #define ATOM_LCD_INFO_LAST  ATOM_LCD_INFO_V13    
@@ -3273,6 +3510,11 @@
 //Use this cap bit for a quick reference whether an embadded panel (LCD1 ) is LVDS or eDP.
 #define	LCDPANEL_CAP_V13_eDP                    0x4        // = LCDPANEL_CAP_eDP no change comparing to previous version
 
+//uceDPToLVDSRxId
+#define eDP_TO_LVDS_RX_DISABLE                  0x00       // no eDP->LVDS translator chip 
+#define eDP_TO_LVDS_COMMON_ID                   0x01       // common eDP->LVDS translator chip without AMD SW init
+#define eDP_TO_LVDS_RT_ID                       0x02       // RT tanslator which require AMD SW init
+
 typedef struct  _ATOM_PATCH_RECORD_MODE
 {
   UCHAR     ucRecordType;
@@ -3317,6 +3559,7 @@
 #define LCD_CAP_RECORD_TYPE                   3
 #define LCD_FAKE_EDID_PATCH_RECORD_TYPE       4
 #define LCD_PANEL_RESOLUTION_RECORD_TYPE      5
+#define LCD_EDID_OFFSET_PATCH_RECORD_TYPE     6
 #define ATOM_RECORD_END_TYPE                  0xFF
 
 /****************************Spread Spectrum Info Table Definitions **********************/
@@ -3528,6 +3771,7 @@
 
 CAIL needs to claim an reserved area defined by FBAccessAreaOffset and usFBUsedbyDrvInKB in non VGA case.*/
 
+/***********************************************************************************/	
 #define ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO			1
 
 typedef struct _ATOM_FIRMWARE_VRAM_RESERVE_INFO
@@ -3818,13 +4062,17 @@
     ATOM_DP_CONN_CHANNEL_MAPPING asDPMapping;
     ATOM_DVI_CONN_CHANNEL_MAPPING asDVIMapping;
   };
-  UCHAR   ucReserved;
-  USHORT  usReserved[2]; 
+  UCHAR   ucChPNInvert;                   // bit vector for up to 8 lanes, =0: P and N is not invert, =1 P and N is inverted
+  USHORT  usCaps;
+  USHORT  usReserved; 
 }EXT_DISPLAY_PATH;
    
 #define NUMBER_OF_UCHAR_FOR_GUID          16
 #define MAX_NUMBER_OF_EXT_DISPLAY_PATH    7
 
+//usCaps
+#define  EXT_DISPLAY_PATH_CAPS__HBR2_DISABLE          0x01
+
 typedef  struct _ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO
 {
   ATOM_COMMON_TABLE_HEADER sHeader;
@@ -3832,7 +4080,9 @@
   EXT_DISPLAY_PATH         sPath[MAX_NUMBER_OF_EXT_DISPLAY_PATH]; // total of fixed 7 entries.
   UCHAR                    ucChecksum;                            // a  simple Checksum of the sum of whole structure equal to 0x0. 
   UCHAR                    uc3DStereoPinId;                       // use for eDP panel
-  UCHAR                    Reserved [6];                          // for potential expansion
+  UCHAR                    ucRemoteDisplayConfig;
+  UCHAR                    uceDPToLVDSRxId;
+  UCHAR                    Reserved[4];                           // for potential expansion
 }ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO;
 
 //Related definitions, all records are different but they have a commond header
@@ -3977,6 +4227,7 @@
 #define GPIO_PIN_STATE_ACTIVE_HIGH      0x1
 
 // Indexes to GPIO array in GLSync record 
+// GLSync record is for Frame Lock/Gen Lock feature.
 #define ATOM_GPIO_INDEX_GLSYNC_REFCLK    0
 #define ATOM_GPIO_INDEX_GLSYNC_HSYNC     1
 #define ATOM_GPIO_INDEX_GLSYNC_VSYNC     2
@@ -3984,7 +4235,9 @@
 #define ATOM_GPIO_INDEX_GLSYNC_SWAP_GNT  4
 #define ATOM_GPIO_INDEX_GLSYNC_INTERRUPT 5
 #define ATOM_GPIO_INDEX_GLSYNC_V_RESET   6
-#define ATOM_GPIO_INDEX_GLSYNC_MAX       7
+#define ATOM_GPIO_INDEX_GLSYNC_SWAP_CNTL 7
+#define ATOM_GPIO_INDEX_GLSYNC_SWAP_SEL  8
+#define ATOM_GPIO_INDEX_GLSYNC_MAX       9
 
 typedef struct  _ATOM_ENCODER_DVO_CF_RECORD
 {
@@ -3994,7 +4247,8 @@
 }ATOM_ENCODER_DVO_CF_RECORD;
 
 // Bit maps for ATOM_ENCODER_CAP_RECORD.ucEncoderCap
-#define ATOM_ENCODER_CAP_RECORD_HBR2     0x01         // DP1.2 HBR2 is supported by this path
+#define ATOM_ENCODER_CAP_RECORD_HBR2                  0x01         // DP1.2 HBR2 is supported by HW encoder
+#define ATOM_ENCODER_CAP_RECORD_HBR2_EN               0x02         // DP1.2 HBR2 setting is qualified and HBR2 can be enabled 
 
 typedef struct  _ATOM_ENCODER_CAP_RECORD
 {
@@ -4003,11 +4257,13 @@
     USHORT                    usEncoderCap;         
     struct {
 #if ATOM_BIG_ENDIAN
-      USHORT                  usReserved:15;        // Bit1-15 may be defined for other capability in future
+      USHORT                  usReserved:14;        // Bit1-15 may be defined for other capability in future
+      USHORT                  usHBR2En:1;           // Bit1 is for DP1.2 HBR2 enable
       USHORT                  usHBR2Cap:1;          // Bit0 is for DP1.2 HBR2 capability. 
 #else
       USHORT                  usHBR2Cap:1;          // Bit0 is for DP1.2 HBR2 capability. 
-      USHORT                  usReserved:15;        // Bit1-15 may be defined for other capability in future
+      USHORT                  usHBR2En:1;           // Bit1 is for DP1.2 HBR2 enable
+      USHORT                  usReserved:14;        // Bit1-15 may be defined for other capability in future
 #endif
     };
   }; 
@@ -4157,6 +4413,7 @@
 #define	VOLTAGE_CONTROL_ID_VT1556M						0x07									
 #define	VOLTAGE_CONTROL_ID_CHL822x						0x08									
 #define	VOLTAGE_CONTROL_ID_VT1586M						0x09
+#define VOLTAGE_CONTROL_ID_UP1637 						0x0A
 
 typedef struct  _ATOM_VOLTAGE_OBJECT
 {
@@ -4193,6 +4450,69 @@
 	USHORT	usVoltage;
 }ATOM_LEAKID_VOLTAGE;
 
+typedef struct _ATOM_VOLTAGE_OBJECT_HEADER_V3{
+ 	 UCHAR		ucVoltageType;									//Indicate Voltage Source: VDDC, MVDDC, MVDDQ or MVDDCI	 
+   UCHAR		ucVoltageMode;							    //Indicate voltage control mode: Init/Set/Leakage/Set phase 
+	 USHORT		usSize;													//Size of Object	
+}ATOM_VOLTAGE_OBJECT_HEADER_V3;
+
+typedef struct  _VOLTAGE_LUT_ENTRY_V2
+{
+	 ULONG		ulVoltageId;									  // The Voltage ID which is used to program GPIO register
+	 USHORT		usVoltageValue;									// The corresponding Voltage Value, in mV
+}VOLTAGE_LUT_ENTRY_V2;
+
+typedef struct  _LEAKAGE_VOLTAGE_LUT_ENTRY_V2
+{
+  USHORT	usVoltageLevel; 							  // The Voltage ID which is used to program GPIO register
+  USHORT  usVoltageId;                    
+	USHORT	usLeakageId;									  // The corresponding Voltage Value, in mV
+}LEAKAGE_VOLTAGE_LUT_ENTRY_V2;
+
+typedef struct  _ATOM_I2C_VOLTAGE_OBJECT_V3
+{
+   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;
+   UCHAR	ucVoltageRegulatorId;					  //Indicate Voltage Regulator Id
+   UCHAR    ucVoltageControlI2cLine;
+   UCHAR    ucVoltageControlAddress;
+   UCHAR    ucVoltageControlOffset;	 	
+   ULONG    ulReserved;
+   VOLTAGE_LUT_ENTRY asVolI2cLut[1];        // end with 0xff
+}ATOM_I2C_VOLTAGE_OBJECT_V3;
+
+typedef struct  _ATOM_GPIO_VOLTAGE_OBJECT_V3
+{
+   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;   
+   UCHAR    ucVoltageGpioCntlId;         // default is 0 which indicate control through CG VID mode 
+   UCHAR    ucGpioEntryNum;              // indiate the entry numbers of Votlage/Gpio value Look up table
+   UCHAR    ucPhaseDelay;                // phase delay in unit of micro second
+   UCHAR    ucReserved;   
+   ULONG    ulGpioMaskVal;               // GPIO Mask value
+   VOLTAGE_LUT_ENTRY_V2 asVolGpioLut[1];   
+}ATOM_GPIO_VOLTAGE_OBJECT_V3;
+
+typedef struct  _ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
+{
+   ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;
+   UCHAR    ucLeakageCntlId;             // default is 0
+   UCHAR    ucLeakageEntryNum;           // indicate the entry number of LeakageId/Voltage Lut table
+   UCHAR    ucReserved[2];               
+   ULONG    ulMaxVoltageLevel;
+   LEAKAGE_VOLTAGE_LUT_ENTRY_V2 asLeakageIdLut[1];   
+}ATOM_LEAKAGE_VOLTAGE_OBJECT_V3;
+
+typedef union _ATOM_VOLTAGE_OBJECT_V3{
+  ATOM_GPIO_VOLTAGE_OBJECT_V3 asGpioVoltageObj;
+  ATOM_I2C_VOLTAGE_OBJECT_V3 asI2cVoltageObj;
+  ATOM_LEAKAGE_VOLTAGE_OBJECT_V3 asLeakageObj;
+}ATOM_VOLTAGE_OBJECT_V3;
+
+typedef struct  _ATOM_VOLTAGE_OBJECT_INFO_V3_1
+{
+   ATOM_COMMON_TABLE_HEADER	sHeader; 
+	 ATOM_VOLTAGE_OBJECT_V3			asVoltageObj[3];	//Info for Voltage control	  	 
+}ATOM_VOLTAGE_OBJECT_INFO_V3_1;
+
 typedef struct  _ATOM_ASIC_PROFILE_VOLTAGE
 {
 	UCHAR		ucProfileId;
@@ -4305,7 +4625,18 @@
   USHORT usHDMISSpreadRateIn10Hz;
   USHORT usDVISSPercentage;
   USHORT usDVISSpreadRateIn10Hz;
-  ULONG  ulReserved3[21]; 
+  ULONG  SclkDpmBoostMargin;
+  ULONG  SclkDpmThrottleMargin;
+  USHORT SclkDpmTdpLimitPG; 
+  USHORT SclkDpmTdpLimitBoost;
+  ULONG  ulBoostEngineCLock;
+  UCHAR  ulBoostVid_2bit;  
+  UCHAR  EnableBoost;
+  USHORT GnbTdpLimit;
+  USHORT usMaxLVDSPclkFreqInSingleLink;
+  UCHAR  ucLvdsMisc;
+  UCHAR  ucLVDSReserved;
+  ULONG  ulReserved3[15]; 
   ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO sExtDispConnInfo;   
 }ATOM_INTEGRATED_SYSTEM_INFO_V6;   
 
@@ -4313,9 +4644,16 @@
 #define INTEGRATED_SYSTEM_INFO_V6_GPUCAPINFO__TMDSHDMI_COHERENT_SINGLEPLL_MODE       0x01
 #define INTEGRATED_SYSTEM_INFO_V6_GPUCAPINFO__DISABLE_AUX_HW_MODE_DETECTION          0x08
 
-// ulOtherDisplayMisc
-#define INTEGRATED_SYSTEM_INFO__GET_EDID_CALLBACK_FUNC_SUPPORT                       0x01
+//ucLVDSMisc:                   
+#define SYS_INFO_LVDSMISC__888_FPDI_MODE                                             0x01
+#define SYS_INFO_LVDSMISC__DL_CH_SWAP                                                0x02
+#define SYS_INFO_LVDSMISC__888_BPC                                                   0x04
+#define SYS_INFO_LVDSMISC__OVERRIDE_EN                                               0x08
+#define SYS_INFO_LVDSMISC__BLON_ACTIVE_LOW                                           0x10
 
+// not used any more
+#define SYS_INFO_LVDSMISC__VSYNC_ACTIVE_LOW                                          0x04
+#define SYS_INFO_LVDSMISC__HSYNC_ACTIVE_LOW                                          0x08
 
 /**********************************************************************************************************************
   ATOM_INTEGRATED_SYSTEM_INFO_V6 Description
@@ -4384,7 +4722,208 @@
 ulCSR_M3_ARB_CNTL_DEFAULT[10]:    Arrays with values for CSR M3 arbiter for default
 ulCSR_M3_ARB_CNTL_UVD[10]:        Arrays with values for CSR M3 arbiter for UVD playback.
 ulCSR_M3_ARB_CNTL_FS3D[10]:       Arrays with values for CSR M3 arbiter for Full Screen 3D applications.
-sAvail_SCLK[5]:                   Arrays to provide available list of SLCK and corresponding voltage, order from low to high  
+sAvail_SCLK[5]:                   Arrays to provide availabe list of SLCK and corresponding voltage, order from low to high  
+ulGMCRestoreResetTime:            GMC power restore and GMC reset time to calculate data reconnection latency. Unit in ns. 
+ulMinimumNClk:                    Minimum NCLK speed among all NB-Pstates to calcualte data reconnection latency. Unit in 10kHz. 
+ulIdleNClk:                       NCLK speed while memory runs in self-refresh state. Unit in 10kHz.
+ulDDR_DLL_PowerUpTime:            DDR PHY DLL power up time. Unit in ns.
+ulDDR_PLL_PowerUpTime:            DDR PHY PLL power up time. Unit in ns.
+usPCIEClkSSPercentage:            PCIE Clock Spred Spectrum Percentage in unit 0.01%; 100 mean 1%.
+usPCIEClkSSType:                  PCIE Clock Spred Spectrum Type. 0 for Down spread(default); 1 for Center spread.
+usLvdsSSPercentage:               LVDS panel ( not include eDP ) Spread Spectrum Percentage in unit of 0.01%, =0, use VBIOS default setting. 
+usLvdsSSpreadRateIn10Hz:          LVDS panel ( not include eDP ) Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting. 
+usHDMISSPercentage:               HDMI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%,  =0, use VBIOS default setting. 
+usHDMISSpreadRateIn10Hz:          HDMI Spread Spectrum frequency in unit of 10Hz,  =0, use VBIOS default setting. 
+usDVISSPercentage:                DVI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%,  =0, use VBIOS default setting. 
+usDVISSpreadRateIn10Hz:           DVI Spread Spectrum frequency in unit of 10Hz,  =0, use VBIOS default setting. 
+usMaxLVDSPclkFreqInSingleLink:    Max pixel clock LVDS panel single link, if=0 means VBIOS use default threhold, right now it is 85Mhz
+ucLVDSMisc:                       [bit0] LVDS 888bit panel mode =0: LVDS 888 panel in LDI mode, =1: LVDS 888 panel in FPDI mode
+                                  [bit1] LVDS panel lower and upper link mapping =0: lower link and upper link not swap, =1: lower link and upper link are swapped
+                                  [bit2] LVDS 888bit per color mode  =0: 666 bit per color =1:888 bit per color
+                                  [bit3] LVDS parameter override enable  =0: ucLvdsMisc parameter are not used =1: ucLvdsMisc parameter should be used
+                                  [bit4] Polarity of signal sent to digital BLON output pin. =0: not inverted(active high) =1: inverted ( active low )
+**********************************************************************************************************************/
+
+// this Table is used for Liano/Ontario APU
+typedef struct _ATOM_FUSION_SYSTEM_INFO_V1
+{
+  ATOM_INTEGRATED_SYSTEM_INFO_V6    sIntegratedSysInfo;   
+  ULONG  ulPowerplayTable[128];  
+}ATOM_FUSION_SYSTEM_INFO_V1; 
+/**********************************************************************************************************************
+  ATOM_FUSION_SYSTEM_INFO_V1 Description
+sIntegratedSysInfo:               refer to ATOM_INTEGRATED_SYSTEM_INFO_V6 definition.
+ulPowerplayTable[128]:            This 512 bytes memory is used to save ATOM_PPLIB_POWERPLAYTABLE3, starting form ulPowerplayTable[0]    
+**********************************************************************************************************************/ 
+
+// this IntegrateSystemInfoTable is used for Trinity APU
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
+{
+  ATOM_COMMON_TABLE_HEADER   sHeader;
+  ULONG  ulBootUpEngineClock;
+  ULONG  ulDentistVCOFreq;
+  ULONG  ulBootUpUMAClock;
+  ATOM_CLK_VOLT_CAPABILITY   sDISPCLK_Voltage[4];
+  ULONG  ulBootUpReqDisplayVector;
+  ULONG  ulOtherDisplayMisc;
+  ULONG  ulGPUCapInfo;
+  ULONG  ulSB_MMIO_Base_Addr;
+  USHORT usRequestedPWMFreqInHz;
+  UCHAR  ucHtcTmpLmt;
+  UCHAR  ucHtcHystLmt;
+  ULONG  ulMinEngineClock;
+  ULONG  ulSystemConfig;            
+  ULONG  ulCPUCapInfo;
+  USHORT usNBP0Voltage;               
+  USHORT usNBP1Voltage;
+  USHORT usBootUpNBVoltage;                       
+  USHORT usExtDispConnInfoOffset;
+  USHORT usPanelRefreshRateRange;     
+  UCHAR  ucMemoryType;  
+  UCHAR  ucUMAChannelNumber;
+  UCHAR  strVBIOSMsg[40];
+  ULONG  ulReserved[20];
+  ATOM_AVAILABLE_SCLK_LIST   sAvail_SCLK[5];
+  ULONG  ulGMCRestoreResetTime;
+  ULONG  ulMinimumNClk;
+  ULONG  ulIdleNClk;
+  ULONG  ulDDR_DLL_PowerUpTime;
+  ULONG  ulDDR_PLL_PowerUpTime;
+  USHORT usPCIEClkSSPercentage;
+  USHORT usPCIEClkSSType;
+  USHORT usLvdsSSPercentage;
+  USHORT usLvdsSSpreadRateIn10Hz;
+  USHORT usHDMISSPercentage;
+  USHORT usHDMISSpreadRateIn10Hz;
+  USHORT usDVISSPercentage;
+  USHORT usDVISSpreadRateIn10Hz;
+  ULONG  SclkDpmBoostMargin;
+  ULONG  SclkDpmThrottleMargin;
+  USHORT SclkDpmTdpLimitPG; 
+  USHORT SclkDpmTdpLimitBoost;
+  ULONG  ulBoostEngineCLock;
+  UCHAR  ulBoostVid_2bit;  
+  UCHAR  EnableBoost;
+  USHORT GnbTdpLimit;
+  USHORT usMaxLVDSPclkFreqInSingleLink;
+  UCHAR  ucLvdsMisc;
+  UCHAR  ucLVDSReserved;
+  UCHAR  ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
+  UCHAR  ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
+  UCHAR  ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
+  UCHAR  ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
+  UCHAR  ucLVDSOffToOnDelay_in4Ms;
+  UCHAR  ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
+  UCHAR  ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
+  UCHAR  ucLVDSReserved1;
+  ULONG  ulLCDBitDepthControlVal;
+  ULONG  ulNbpStateMemclkFreq[4];
+  USHORT usNBP2Voltage;               
+  USHORT usNBP3Voltage;
+  ULONG  ulNbpStateNClkFreq[4];
+  UCHAR  ucNBDPMEnable;
+  UCHAR  ucReserved[3];
+  UCHAR  ucDPMState0VclkFid;
+  UCHAR  ucDPMState0DclkFid;
+  UCHAR  ucDPMState1VclkFid;
+  UCHAR  ucDPMState1DclkFid;
+  UCHAR  ucDPMState2VclkFid;
+  UCHAR  ucDPMState2DclkFid;
+  UCHAR  ucDPMState3VclkFid;
+  UCHAR  ucDPMState3DclkFid;
+  ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO sExtDispConnInfo;
+}ATOM_INTEGRATED_SYSTEM_INFO_V1_7;
+
+// ulOtherDisplayMisc
+#define INTEGRATED_SYSTEM_INFO__GET_EDID_CALLBACK_FUNC_SUPPORT            0x01
+#define INTEGRATED_SYSTEM_INFO__GET_BOOTUP_DISPLAY_CALLBACK_FUNC_SUPPORT  0x02
+#define INTEGRATED_SYSTEM_INFO__GET_EXPANSION_CALLBACK_FUNC_SUPPORT       0x04
+#define INTEGRATED_SYSTEM_INFO__FAST_BOOT_SUPPORT                         0x08
+
+// ulGPUCapInfo
+#define SYS_INFO_GPUCAPS__TMDSHDMI_COHERENT_SINGLEPLL_MODE                0x01
+#define SYS_INFO_GPUCAPS__DP_SINGLEPLL_MODE                               0x02
+#define SYS_INFO_GPUCAPS__DISABLE_AUX_MODE_DETECT                         0x08
+
+/**********************************************************************************************************************
+  ATOM_INTEGRATED_SYSTEM_INFO_V1_7 Description
+ulBootUpEngineClock:              VBIOS bootup Engine clock frequency, in 10kHz unit. if it is equal 0, then VBIOS use pre-defined bootup engine clock
+ulDentistVCOFreq:                 Dentist VCO clock in 10kHz unit. 
+ulBootUpUMAClock:                 System memory boot up clock frequency in 10Khz unit. 
+sDISPCLK_Voltage:                 Report Display clock voltage requirement.
+ 
+ulBootUpReqDisplayVector:         VBIOS boot up display IDs, following are supported devices in Trinity projects:
+                                  ATOM_DEVICE_CRT1_SUPPORT                  0x0001
+                                  ATOM_DEVICE_DFP1_SUPPORT                  0x0008 
+                                  ATOM_DEVICE_DFP6_SUPPORT                  0x0040 
+                                  ATOM_DEVICE_DFP2_SUPPORT                  0x0080       
+                                  ATOM_DEVICE_DFP3_SUPPORT                  0x0200       
+                                  ATOM_DEVICE_DFP4_SUPPORT                  0x0400        
+                                  ATOM_DEVICE_DFP5_SUPPORT                  0x0800
+                                  ATOM_DEVICE_LCD1_SUPPORT                  0x0002
+ulOtherDisplayMisc:      	        bit[0]=0: INT15 callback function Get LCD EDID ( ax=4e08, bl=1b ) is not supported by SBIOS. 
+                                        =1: INT15 callback function Get LCD EDID ( ax=4e08, bl=1b ) is supported by SBIOS. 
+                                  bit[1]=0: INT15 callback function Get boot display( ax=4e08, bl=01h) is not supported by SBIOS
+                                        =1: INT15 callback function Get boot display( ax=4e08, bl=01h) is supported by SBIOS
+                                  bit[2]=0: INT15 callback function Get panel Expansion ( ax=4e08, bl=02h) is not supported by SBIOS
+                                        =1: INT15 callback function Get panel Expansion ( ax=4e08, bl=02h) is supported by SBIOS
+                                  bit[3]=0: VBIOS fast boot is disable
+                                        =1: VBIOS fast boot is enable. ( VBIOS skip display device detection in every set mode if LCD panel is connect and LID is open)
+ulGPUCapInfo:                     bit[0]=0: TMDS/HDMI Coherent Mode use cascade PLL mode.
+                                        =1: TMDS/HDMI Coherent Mode use signel PLL mode.
+                                  bit[1]=0: DP mode use cascade PLL mode ( New for Trinity )
+                                        =1: DP mode use single PLL mode
+                                  bit[3]=0: Enable AUX HW mode detection logic
+                                        =1: Disable AUX HW mode detection logic
+                                      
+ulSB_MMIO_Base_Addr:              Physical Base address to SB MMIO space. Driver needs to initialize it for SMU usage.
+
+usRequestedPWMFreqInHz:           When it's set to 0x0 by SBIOS: the LCD BackLight is not controlled by GPU(SW). 
+                                  Any attempt to change BL using VBIOS function or enable VariBri from PP table is not effective since ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==0;
+                                  
+                                  When it's set to a non-zero frequency, the BackLight is controlled by GPU (SW) in one of two ways below:
+                                  1. SW uses the GPU BL PWM output to control the BL, in chis case, this non-zero frequency determines what freq GPU should use;
+                                  VBIOS will set up proper PWM frequency and ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1,as the result,
+                                  Changing BL using VBIOS function is functional in both driver and non-driver present environment; 
+                                  and enabling VariBri under the driver environment from PP table is optional.
+
+                                  2. SW uses other means to control BL (like DPCD),this non-zero frequency serves as a flag only indicating
+                                  that BL control from GPU is expected.
+                                  VBIOS will NOT set up PWM frequency but make ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1
+                                  Changing BL using VBIOS function could be functional in both driver and non-driver present environment,but
+                                  it's per platform 
+                                  and enabling VariBri under the driver environment from PP table is optional.
+
+ucHtcTmpLmt:                      Refer to D18F3x64 bit[22:16], HtcTmpLmt. 
+                                  Threshold on value to enter HTC_active state.
+ucHtcHystLmt:                     Refer to D18F3x64 bit[27:24], HtcHystLmt. 
+                                  To calculate threshold off value to exit HTC_active state, which is Threshold on vlaue minus ucHtcHystLmt.
+ulMinEngineClock:                 Minimum SCLK allowed in 10kHz unit. This is calculated based on WRCK Fuse settings.
+ulSystemConfig:                   Bit[0]=0: PCIE Power Gating Disabled 
+                                        =1: PCIE Power Gating Enabled
+                                  Bit[1]=0: DDR-DLL shut-down feature disabled.
+                                         1: DDR-DLL shut-down feature enabled.
+                                  Bit[2]=0: DDR-PLL Power down feature disabled.
+                                         1: DDR-PLL Power down feature enabled.                                 
+ulCPUCapInfo:                     TBD
+usNBP0Voltage:                    VID for voltage on NB P0 State
+usNBP1Voltage:                    VID for voltage on NB P1 State  
+usNBP2Voltage:                    VID for voltage on NB P2 State
+usNBP3Voltage:                    VID for voltage on NB P3 State  
+usBootUpNBVoltage:                Voltage Index of GNB voltage configured by SBIOS, which is suffcient to support VBIOS DISPCLK requirement.
+usExtDispConnInfoOffset:          Offset to sExtDispConnInfo inside the structure
+usPanelRefreshRateRange:          Bit vector for LCD supported refresh rate range. If DRR is requestd by the platform, at least two bits need to be set
+                                  to indicate a range.
+                                  SUPPORTED_LCD_REFRESHRATE_30Hz          0x0004
+                                  SUPPORTED_LCD_REFRESHRATE_40Hz          0x0008
+                                  SUPPORTED_LCD_REFRESHRATE_50Hz          0x0010
+                                  SUPPORTED_LCD_REFRESHRATE_60Hz          0x0020
+ucMemoryType:                     [3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved.
+ucUMAChannelNumber:      	        System memory channel numbers. 
+ulCSR_M3_ARB_CNTL_DEFAULT[10]:    Arrays with values for CSR M3 arbiter for default
+ulCSR_M3_ARB_CNTL_UVD[10]:        Arrays with values for CSR M3 arbiter for UVD playback.
+ulCSR_M3_ARB_CNTL_FS3D[10]:       Arrays with values for CSR M3 arbiter for Full Screen 3D applications.
+sAvail_SCLK[5]:                   Arrays to provide availabe list of SLCK and corresponding voltage, order from low to high  
 ulGMCRestoreResetTime:            GMC power restore and GMC reset time to calculate data reconnection latency. Unit in ns. 
 ulMinimumNClk:                    Minimum NCLK speed among all NB-Pstates to calcualte data reconnection latency. Unit in 10kHz. 
 ulIdleNClk:                       NCLK speed while memory runs in self-refresh state. Unit in 10kHz.
@@ -4398,6 +4937,41 @@
 usHDMISSpreadRateIn10Hz:          HDMI Spread Spectrum frequency in unit of 10Hz,  =0, use VBIOS default setting. 
 usDVISSPercentage:                DVI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%,  =0, use VBIOS default setting. 
 usDVISSpreadRateIn10Hz:           DVI Spread Spectrum frequency in unit of 10Hz,  =0, use VBIOS default setting. 
+usMaxLVDSPclkFreqInSingleLink:    Max pixel clock LVDS panel single link, if=0 means VBIOS use default threhold, right now it is 85Mhz
+ucLVDSMisc:                       [bit0] LVDS 888bit panel mode =0: LVDS 888 panel in LDI mode, =1: LVDS 888 panel in FPDI mode
+                                  [bit1] LVDS panel lower and upper link mapping =0: lower link and upper link not swap, =1: lower link and upper link are swapped
+                                  [bit2] LVDS 888bit per color mode  =0: 666 bit per color =1:888 bit per color
+                                  [bit3] LVDS parameter override enable  =0: ucLvdsMisc parameter are not used =1: ucLvdsMisc parameter should be used
+                                  [bit4] Polarity of signal sent to digital BLON output pin. =0: not inverted(active high) =1: inverted ( active low )
+ucLVDSPwrOnSeqDIGONtoDE_in4Ms:    LVDS power up sequence time in unit of 4ms, time delay from DIGON signal active to data enable signal active( DE ).
+                                  =0 mean use VBIOS default which is 8 ( 32ms ). The LVDS power up sequence is as following: DIGON->DE->VARY_BL->BLON. 
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSPwrOnDEtoVARY_BL_in4Ms:     LVDS power up sequence time in unit of 4ms., time delay from DE( data enable ) active to Vary Brightness enable signal active( VARY_BL ).  
+                                  =0 mean use VBIOS default which is 90 ( 360ms ). The LVDS power up sequence is as following: DIGON->DE->VARY_BL->BLON. 
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+
+ucLVDSPwrOffVARY_BLtoDE_in4Ms:    LVDS power down sequence time in unit of 4ms, time delay from data enable ( DE ) signal off to LCDVCC (DIGON) off. 
+                                  =0 mean use VBIOS default delay which is 8 ( 32ms ). The LVDS power down sequence is as following: BLON->VARY_BL->DE->DIGON
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+
+ucLVDSPwrOffDEtoDIGON_in4Ms:      LVDS power down sequence time in unit of 4ms, time delay from vary brightness enable signal( VARY_BL) off to data enable ( DE ) signal off. 
+                                  =0 mean use VBIOS default which is 90 ( 360ms ). The LVDS power down sequence is as following: BLON->VARY_BL->DE->DIGON
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+
+ucLVDSOffToOnDelay_in4Ms:         LVDS power down sequence time in unit of 4ms. Time delay from DIGON signal off to DIGON signal active. 
+                                  =0 means to use VBIOS default delay which is 125 ( 500ms ).
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+
+ucLVDSPwrOnVARY_BLtoBLON_in4Ms:   LVDS power up sequence time in unit of 4ms. Time delay from VARY_BL signal on to DLON signal active. 
+                                  =0 means to use VBIOS default delay which is 0 ( 0ms ).
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+
+ucLVDSPwrOffBLONtoVARY_BL_in4Ms:  LVDS power down sequence time in unit of 4ms. Time delay from BLON signal off to VARY_BL signal off. 
+                                  =0 means to use VBIOS default delay which is 0 ( 0ms ).
+                                  This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+
+ulNbpStateMemclkFreq[4]:          system memory clock frequncey in unit of 10Khz in different NB pstate. 
+
 **********************************************************************************************************************/
 
 /**************************************************************************/
@@ -4459,6 +5033,7 @@
 #define ASIC_INTERNAL_SS_ON_DP      7
 #define ASIC_INTERNAL_SS_ON_DCPLL   8
 #define ASIC_EXTERNAL_SS_ON_DP_CLOCK 9
+#define ASIC_INTERNAL_VCE_SS        10
 
 typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V2
 {
@@ -4520,7 +5095,7 @@
 #define ATOM_DOS_MODE_INFO_DEF        7
 #define ATOM_I2C_CHANNEL_STATUS_DEF   8
 #define ATOM_I2C_CHANNEL_STATUS1_DEF  9
-
+#define ATOM_INTERNAL_TIMER_DEF       10
 
 // BIOS_0_SCRATCH Definition 
 #define ATOM_S0_CRT1_MONO               0x00000001L
@@ -4648,6 +5223,7 @@
 #define ATOM_S2_DEVICE_DPMS_MASKw1      0x3FF
 #define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASKb3     0x0C
 #define ATOM_S2_FORCEDLOWPWRMODE_STATE_CHANGEb3   0x10
+#define ATOM_S2_TMDS_COHERENT_MODEb3    0x10          // used by VBIOS code only, use coherent mode for TMDS/HDMI mode
 #define ATOM_S2_VRI_BRIGHT_ENABLEb3     0x20
 #define ATOM_S2_ROTATION_STATE_MASKb3   0xC0
 
@@ -5038,6 +5614,23 @@
   USHORT usDeviceId;                  // Active Device Id for this surface. If no device, set to 0. 
 }ENABLE_GRAPH_SURFACE_PARAMETERS_V1_3;
 
+typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS_V1_4
+{
+  USHORT usHight;                     // Image Hight
+  USHORT usWidth;                     // Image Width
+  USHORT usGraphPitch;
+  UCHAR  ucColorDepth;
+  UCHAR  ucPixelFormat;
+  UCHAR  ucSurface;                   // Surface 1 or 2
+  UCHAR  ucEnable;                    // ATOM_ENABLE or ATOM_DISABLE
+  UCHAR  ucModeType;
+  UCHAR  ucReserved;
+}ENABLE_GRAPH_SURFACE_PARAMETERS_V1_4;
+
+// ucEnable
+#define ATOM_GRAPH_CONTROL_SET_PITCH             0x0f
+#define ATOM_GRAPH_CONTROL_SET_DISP_START        0x10
+
 typedef struct _ENABLE_GRAPH_SURFACE_PS_ALLOCATION
 {
   ENABLE_GRAPH_SURFACE_PARAMETERS sSetSurface;          
@@ -5057,6 +5650,58 @@
   USHORT  usY_Size;
 }GET_DISPLAY_SURFACE_SIZE_PARAMETERS; 
 
+typedef struct  _GET_DISPLAY_SURFACE_SIZE_PARAMETERS_V2
+{
+  union{
+    USHORT  usX_Size;                     //When use as input parameter, usX_Size indicates which CRTC                 
+    USHORT  usSurface; 
+  };
+  USHORT usY_Size;
+  USHORT usDispXStart;               
+  USHORT usDispYStart;
+}GET_DISPLAY_SURFACE_SIZE_PARAMETERS_V2; 
+
+
+typedef struct _PALETTE_DATA_CONTROL_PARAMETERS_V3 
+{
+  UCHAR  ucLutId;
+  UCHAR  ucAction;
+  USHORT usLutStartIndex;
+  USHORT usLutLength;
+  USHORT usLutOffsetInVram;
+}PALETTE_DATA_CONTROL_PARAMETERS_V3;
+
+// ucAction:
+#define PALETTE_DATA_AUTO_FILL            1
+#define PALETTE_DATA_READ                 2
+#define PALETTE_DATA_WRITE                3
+
+
+typedef struct _INTERRUPT_SERVICE_PARAMETERS_V2
+{
+  UCHAR  ucInterruptId;
+  UCHAR  ucServiceId;
+  UCHAR  ucStatus;
+  UCHAR  ucReserved;
+}INTERRUPT_SERVICE_PARAMETER_V2;
+
+// ucInterruptId
+#define HDP1_INTERRUPT_ID                 1
+#define HDP2_INTERRUPT_ID                 2
+#define HDP3_INTERRUPT_ID                 3
+#define HDP4_INTERRUPT_ID                 4
+#define HDP5_INTERRUPT_ID                 5
+#define HDP6_INTERRUPT_ID                 6
+#define SW_INTERRUPT_ID                   11   
+
+// ucAction
+#define INTERRUPT_SERVICE_GEN_SW_INT      1
+#define INTERRUPT_SERVICE_GET_STATUS      2
+
+ // ucStatus
+#define INTERRUPT_STATUS__INT_TRIGGER     1
+#define INTERRUPT_STATUS__HPD_HIGH        2
+
 typedef struct _INDIRECT_IO_ACCESS
 {
   ATOM_COMMON_TABLE_HEADER sHeader;  
@@ -5189,7 +5834,7 @@
 
 #define END_OF_REG_INDEX_BLOCK  0x0ffff
 #define END_OF_REG_DATA_BLOCK   0x00000000
-#define ATOM_INIT_REG_MASK_FLAG 0x80
+#define ATOM_INIT_REG_MASK_FLAG 0x80               //Not used in BIOS
 #define	CLOCK_RANGE_HIGHEST			0x00ffffff
 
 #define VALUE_DWORD             SIZEOF ULONG
@@ -5229,6 +5874,7 @@
 #define _128Mx8             0x51
 #define _128Mx16            0x52
 #define _256Mx8             0x61
+#define _256Mx16            0x62
 
 #define SAMSUNG             0x1
 #define INFINEON            0x2
@@ -5585,7 +6231,7 @@
   ULONG	  ulChannelMapCfg;	                // mmMC_SHARED_CHREMAP
   USHORT  usModuleSize;                     // Size of ATOM_VRAM_MODULE_V7
   USHORT  usPrivateReserved;                // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS)
-  USHORT  usReserved;
+  USHORT  usEnableChannels;                 // bit vector which indicate which channels are enabled
   UCHAR   ucExtMemoryID;                    // Current memory module ID
   UCHAR   ucMemoryType;                     // MEM_TYPE_DDR2/DDR3/GDDR3/GDDR5
   UCHAR   ucChannelNum;                     // Number of mem. channels supported in this module
@@ -5597,7 +6243,8 @@
   UCHAR   ucNPL_RT;                         // Round trip delay (MC_SEQ_CAS_TIMING [28:24]:TCL=CL+NPL_RT-2). Always 2.
   UCHAR	  ucPreamble;                       // [7:4] Write Preamble, [3:0] Read Preamble
   UCHAR   ucMemorySize;                     // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros
-  UCHAR   ucReserved[3];
+  USHORT  usSEQSettingOffset;
+  UCHAR   ucReserved;
 // Memory Module specific values
   USHORT  usEMRS2Value;                     // EMRS2/MR2 Value. 
   USHORT  usEMRS3Value;                     // EMRS3/MR3 Value.
@@ -5633,10 +6280,10 @@
 typedef struct _ATOM_VRAM_INFO_V4
 {
   ATOM_COMMON_TABLE_HEADER   sHeader;
-	USHORT										 usMemAdjustTblOffset;													 // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting
-	USHORT										 usMemClkPatchTblOffset;												 //	offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting
-	USHORT										 usRerseved;
-	UCHAR           	         ucMemDQ7_0ByteRemap;													   // DQ line byte remap, =0: Memory Data line BYTE0, =1: BYTE1, =2: BYTE2, =3: BYTE3
+  USHORT                     usMemAdjustTblOffset;													 // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting
+  USHORT                     usMemClkPatchTblOffset;												 //	offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting
+  USHORT										 usRerseved;
+  UCHAR           	         ucMemDQ7_0ByteRemap;													   // DQ line byte remap, =0: Memory Data line BYTE0, =1: BYTE1, =2: BYTE2, =3: BYTE3
   ULONG                      ulMemDQ7_0BitRemap;                             // each DQ line ( 7~0) use 3bits, like: DQ0=Bit[2:0], DQ1:[5:3], ... DQ7:[23:21]
   UCHAR                      ucReservde[4]; 
   UCHAR                      ucNumOfVRAMModule;
@@ -5648,9 +6295,10 @@
 typedef struct _ATOM_VRAM_INFO_HEADER_V2_1
 {
   ATOM_COMMON_TABLE_HEADER   sHeader;
-	USHORT										 usMemAdjustTblOffset;													 // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting
-	USHORT										 usMemClkPatchTblOffset;												 //	offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting
-	USHORT										 usReserved[4];
+  USHORT                     usMemAdjustTblOffset;													 // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting
+  USHORT                     usMemClkPatchTblOffset;												 //	offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting
+  USHORT                     usPerBytePresetOffset;                          // offset of ATOM_INIT_REG_BLOCK structure for Per Byte Offset Preset Settings
+  USHORT                     usReserved[3];
   UCHAR                      ucNumOfVRAMModule;                              // indicate number of VRAM module
   UCHAR                      ucMemoryClkPatchTblVer;                         // version of memory AC timing register list
   UCHAR                      ucVramModuleVer;                                // indicate ATOM_VRAM_MODUE version
@@ -5935,6 +6583,52 @@
 	ASIC_ENCODER_INFO      asEncoderInfo[1];
 }ATOM_DISP_OUT_INFO_V2;
 
+
+typedef struct _ATOM_DISP_CLOCK_ID {
+  UCHAR ucPpllId; 
+  UCHAR ucPpllAttribute;
+}ATOM_DISP_CLOCK_ID;
+
+// ucPpllAttribute
+#define CLOCK_SOURCE_SHAREABLE            0x01
+#define CLOCK_SOURCE_DP_MODE              0x02
+#define CLOCK_SOURCE_NONE_DP_MODE         0x04
+
+//DispOutInfoTable
+typedef struct _ASIC_TRANSMITTER_INFO_V2
+{
+	USHORT usTransmitterObjId;
+	USHORT usDispClkIdOffset;    // point to clock source id list supported by Encoder Object
+  UCHAR  ucTransmitterCmdTblId;
+	UCHAR  ucConfig;
+	UCHAR  ucEncoderID;					 // available 1st encoder ( default )
+	UCHAR  ucOptionEncoderID;    // available 2nd encoder ( optional )
+	UCHAR  uc2ndEncoderID;
+	UCHAR  ucReserved;
+}ASIC_TRANSMITTER_INFO_V2;
+
+typedef struct _ATOM_DISP_OUT_INFO_V3
+{
+  ATOM_COMMON_TABLE_HEADER sHeader;  
+	USHORT ptrTransmitterInfo;
+	USHORT ptrEncoderInfo;
+  USHORT ptrMainCallParserFar;                  // direct address of main parser call in VBIOS binary. 
+  USHORT usReserved;
+  UCHAR  ucDCERevision;   
+  UCHAR  ucMaxDispEngineNum;
+  UCHAR  ucMaxActiveDispEngineNum;
+  UCHAR  ucMaxPPLLNum;
+  UCHAR  ucCoreRefClkSource;                          // value of CORE_REF_CLK_SOURCE
+  UCHAR  ucReserved[3];
+	ASIC_TRANSMITTER_INFO_V2  asTransmitterInfo[1];     // for alligment only
+}ATOM_DISP_OUT_INFO_V3;
+
+typedef enum CORE_REF_CLK_SOURCE{
+  CLOCK_SRC_XTALIN=0,
+  CLOCK_SRC_XO_IN=1,
+  CLOCK_SRC_XO_IN2=2,
+}CORE_REF_CLK_SOURCE;
+
 // DispDevicePriorityInfo
 typedef struct _ATOM_DISPLAY_DEVICE_PRIORITY_INFO
 {
@@ -6070,6 +6764,39 @@
 #define HW_I2C_READ         0
 #define I2C_2BYTE_ADDR      0x02
 
+/****************************************************************************/	
+// Structures used by HW_Misc_OperationTable
+/****************************************************************************/	
+typedef struct  _ATOM_HW_MISC_OPERATION_INPUT_PARAMETER_V1_1 
+{
+  UCHAR  ucCmd;                //  Input: To tell which action to take
+  UCHAR  ucReserved[3];
+  ULONG  ulReserved;
+}ATOM_HW_MISC_OPERATION_INPUT_PARAMETER_V1_1; 
+
+typedef struct  _ATOM_HW_MISC_OPERATION_OUTPUT_PARAMETER_V1_1 
+{
+  UCHAR  ucReturnCode;        // Output: Return value base on action was taken
+  UCHAR  ucReserved[3];
+  ULONG  ulReserved;
+}ATOM_HW_MISC_OPERATION_OUTPUT_PARAMETER_V1_1;
+
+// Actions code
+#define  ATOM_GET_SDI_SUPPORT              0xF0
+
+// Return code 
+#define  ATOM_UNKNOWN_CMD                   0
+#define  ATOM_FEATURE_NOT_SUPPORTED         1
+#define  ATOM_FEATURE_SUPPORTED             2
+
+typedef struct _ATOM_HW_MISC_OPERATION_PS_ALLOCATION
+{
+	ATOM_HW_MISC_OPERATION_INPUT_PARAMETER_V1_1        sInput_Output;
+	PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS         sReserved; 
+}ATOM_HW_MISC_OPERATION_PS_ALLOCATION;
+
+/****************************************************************************/	
+
 typedef struct _SET_HWBLOCK_INSTANCE_PARAMETER_V2
 {
    UCHAR ucHWBlkInst;                // HW block instance, 0, 1, 2, ...
@@ -6090,6 +6817,52 @@
 #define SELECT_CRTC_PIXEL_RATE        7
 #define SELECT_VGA_BLK                8
 
+// DIGTransmitterInfoTable structure used to program UNIPHY settings 
+typedef struct _DIG_TRANSMITTER_INFO_HEADER_V3_1{  
+  ATOM_COMMON_TABLE_HEADER sHeader;  
+  USHORT usDPVsPreEmphSettingOffset;     // offset of PHY_ANALOG_SETTING_INFO * with DP Voltage Swing and Pre-Emphasis for each Link clock 
+  USHORT usPhyAnalogRegListOffset;       // offset of CLOCK_CONDITION_REGESTER_INFO* with None-DP mode Analog Setting's register Info 
+  USHORT usPhyAnalogSettingOffset;       // offset of CLOCK_CONDITION_SETTING_ENTRY* with None-DP mode Analog Setting for each link clock range
+  USHORT usPhyPllRegListOffset;          // offset of CLOCK_CONDITION_REGESTER_INFO* with Phy Pll register Info 
+  USHORT usPhyPllSettingOffset;          // offset of CLOCK_CONDITION_SETTING_ENTRY* with Phy Pll Settings
+}DIG_TRANSMITTER_INFO_HEADER_V3_1;
+
+typedef struct _CLOCK_CONDITION_REGESTER_INFO{
+  USHORT usRegisterIndex;
+  UCHAR  ucStartBit;
+  UCHAR  ucEndBit;
+}CLOCK_CONDITION_REGESTER_INFO;
+
+typedef struct _CLOCK_CONDITION_SETTING_ENTRY{
+  USHORT usMaxClockFreq;
+  UCHAR  ucEncodeMode;
+  UCHAR  ucPhySel;
+  ULONG  ulAnalogSetting[1];
+}CLOCK_CONDITION_SETTING_ENTRY;
+
+typedef struct _CLOCK_CONDITION_SETTING_INFO{
+  USHORT usEntrySize;
+  CLOCK_CONDITION_SETTING_ENTRY asClkCondSettingEntry[1];
+}CLOCK_CONDITION_SETTING_INFO;
+
+typedef struct _PHY_CONDITION_REG_VAL{
+  ULONG  ulCondition;
+  ULONG  ulRegVal;
+}PHY_CONDITION_REG_VAL;
+
+typedef struct _PHY_CONDITION_REG_INFO{
+  USHORT usRegIndex;
+  USHORT usSize;
+  PHY_CONDITION_REG_VAL asRegVal[1];
+}PHY_CONDITION_REG_INFO;
+
+typedef struct _PHY_ANALOG_SETTING_INFO{
+  UCHAR  ucEncodeMode;
+  UCHAR  ucPhySel;
+  USHORT usSize;
+  PHY_CONDITION_REG_INFO  asAnalogSetting[1];
+}PHY_ANALOG_SETTING_INFO;
+
 /****************************************************************************/	
 //Portion VI: Definitinos for vbios MC scratch registers that driver used
 /****************************************************************************/
@@ -6497,6 +7270,8 @@
 #define ATOM_PP_THERMALCONTROLLER_EMC2103   13  /* 0x0D */ // Only fan control will be implemented, do NOT show this in PPGen.
 #define ATOM_PP_THERMALCONTROLLER_SUMO      14  /* 0x0E */ // Sumo type, used internally
 #define ATOM_PP_THERMALCONTROLLER_NISLANDS  15
+#define ATOM_PP_THERMALCONTROLLER_SISLANDS  16
+#define ATOM_PP_THERMALCONTROLLER_LM96163   17
 
 // Thermal controller 'combo type' to use an external controller for Fan control and an internal controller for thermal.
 // We probably should reserve the bit 0x80 for this use.
@@ -6512,6 +7287,7 @@
     UCHAR ucClockStateIndices[1]; // variable-sized
 } ATOM_PPLIB_STATE;
 
+
 typedef struct _ATOM_PPLIB_FANTABLE
 {
     UCHAR   ucFanTableFormat;                // Change this if the table format changes or version changes so that the other fields are not the same.
@@ -6524,12 +7300,20 @@
     USHORT  usPWMHigh;                       // The PWM value at THigh.
 } ATOM_PPLIB_FANTABLE;
 
+typedef struct _ATOM_PPLIB_FANTABLE2
+{
+    ATOM_PPLIB_FANTABLE basicTable;
+    USHORT  usTMax;                          // The max temperature
+} ATOM_PPLIB_FANTABLE2;
+
 typedef struct _ATOM_PPLIB_EXTENDEDHEADER
 {
     USHORT  usSize;
     ULONG   ulMaxEngineClock;   // For Overdrive.
     ULONG   ulMaxMemoryClock;   // For Overdrive.
     // Add extra system parameters here, always adjust size to include all fields.
+    USHORT  usVCETableOffset; //points to ATOM_PPLIB_VCE_Table
+    USHORT  usUVDTableOffset;   //points to ATOM_PPLIB_UVD_Table
 } ATOM_PPLIB_EXTENDEDHEADER;
 
 //// ATOM_PPLIB_POWERPLAYTABLE::ulPlatformCaps
@@ -6552,6 +7336,7 @@
 #define ATOM_PP_PLATFORM_CAP_REGULATOR_HOT 0x00010000               // Enable the 'regulator hot' feature.
 #define ATOM_PP_PLATFORM_CAP_BACO          0x00020000               // Does the driver supports BACO state.
 
+
 typedef struct _ATOM_PPLIB_POWERPLAYTABLE
 {
       ATOM_COMMON_TABLE_HEADER sHeader;
@@ -6610,7 +7395,8 @@
     USHORT                     usVddciDependencyOnMCLKOffset;
     USHORT                     usVddcDependencyOnMCLKOffset;
     USHORT                     usMaxClockVoltageOnDCOffset;
-    USHORT                     usReserved[2];  
+    USHORT                     usVddcPhaseShedLimitsTableOffset;    // Points to ATOM_PPLIB_PhaseSheddingLimits_Table
+    USHORT                     usReserved;  
 } ATOM_PPLIB_POWERPLAYTABLE4, *LPATOM_PPLIB_POWERPLAYTABLE4;
 
 typedef struct _ATOM_PPLIB_POWERPLAYTABLE5
@@ -6620,8 +7406,9 @@
     ULONG                      ulNearTDPLimit;
     ULONG                      ulSQRampingThreshold;
     USHORT                     usCACLeakageTableOffset;         // Points to ATOM_PPLIB_CAC_Leakage_Table
-    ULONG                      ulCACLeakage;                    // TBD, this parameter is still under discussion.  Change to ulReserved if not needed.
-    ULONG                      ulReserved;
+    ULONG                      ulCACLeakage;                    // The iLeakage for driver calculated CAC leakage table
+    USHORT                     usTDPODLimit;
+    USHORT                     usLoadLineSlope;                 // in milliOhms * 100
 } ATOM_PPLIB_POWERPLAYTABLE5, *LPATOM_PPLIB_POWERPLAYTABLE5;
 
 //// ATOM_PPLIB_NONCLOCK_INFO::usClassification
@@ -6650,6 +7437,7 @@
 //// ATOM_PPLIB_NONCLOCK_INFO::usClassification2
 #define ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2     0x0001
 #define ATOM_PPLIB_CLASSIFICATION2_ULV                      0x0002
+#define ATOM_PPLIB_CLASSIFICATION2_MVC                      0x0004   //Multi-View Codec (BD-3D)
 
 //// ATOM_PPLIB_NONCLOCK_INFO::ulCapsAndSettings
 #define ATOM_PPLIB_SINGLE_DISPLAY_ONLY           0x00000001
@@ -6673,7 +7461,9 @@
 
 #define ATOM_PPLIB_SOFTWARE_DISABLE_LOADBALANCING        0x00001000
 #define ATOM_PPLIB_SOFTWARE_ENABLE_SLEEP_FOR_TIMESTAMPS  0x00002000
-#define ATOM_PPLIB_DISALLOW_ON_DC                        0x00004000
+
+#define ATOM_PPLIB_DISALLOW_ON_DC                       0x00004000
+
 #define ATOM_PPLIB_ENABLE_VARIBRIGHT                     0x00008000
 
 //memory related flags
@@ -6735,7 +7525,7 @@
 #define ATOM_PPLIB_R600_FLAGS_UVDSAFE           2
 #define ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE    4
 #define ATOM_PPLIB_R600_FLAGS_MEMORY_ODT_OFF    8
-#define ATOM_PPLIB_R600_FLAGS_MEMORY_DLL_OFF    16
+#define ATOM_PPLIB_R600_FLAGS_MEMORY_DLL_OFF   16
 #define ATOM_PPLIB_R600_FLAGS_LOWPOWER         32   // On the RV770 use 'low power' setting (sequencer S0).
 
 typedef struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO
@@ -6754,6 +7544,24 @@
 
 } ATOM_PPLIB_EVERGREEN_CLOCK_INFO;
 
+typedef struct _ATOM_PPLIB_SI_CLOCK_INFO
+{
+      USHORT usEngineClockLow;
+      UCHAR  ucEngineClockHigh;
+
+      USHORT usMemoryClockLow;
+      UCHAR  ucMemoryClockHigh;
+
+      USHORT usVDDC;
+      USHORT usVDDCI;
+      UCHAR  ucPCIEGen;
+      UCHAR  ucUnused1;
+
+      ULONG ulFlags; // ATOM_PPLIB_SI_FLAGS_*, no flag is necessary for now
+
+} ATOM_PPLIB_SI_CLOCK_INFO;
+
+
 typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO
 
 {
@@ -6766,7 +7574,7 @@
       UCHAR  ucPadding;                   // For proper alignment and size.
       USHORT usVDDC;                      // For the 780, use: None, Low, High, Variable
       UCHAR  ucMaxHTLinkWidth;            // From SBIOS - {2, 4, 8, 16}
-      UCHAR  ucMinHTLinkWidth;            // From SBIOS - {2, 4, 8, 16}. Effective only if CDLW enabled. Minimum down stream width could be bigger as display BW requirement.
+      UCHAR  ucMinHTLinkWidth;            // From SBIOS - {2, 4, 8, 16}. Effective only if CDLW enabled. Minimum down stream width could be bigger as display BW requriement.
       USHORT usHTLinkFreq;                // See definition ATOM_PPLIB_RS780_HTLINKFREQ_xxx or in MHz(>=200).
       ULONG  ulFlags; 
 } ATOM_PPLIB_RS780_CLOCK_INFO;
@@ -6788,9 +7596,7 @@
       USHORT usEngineClockLow;  //clockfrequency & 0xFFFF. The unit is in 10khz
       UCHAR  ucEngineClockHigh; //clockfrequency >> 16. 
       UCHAR  vddcIndex;         //2-bit vddc index;
-      UCHAR  leakage;          //please use 8-bit absolute value, not the 6-bit % value 
-      //please initalize to 0
-      UCHAR  rsv;
+      USHORT tdpLimit;
       //please initalize to 0
       USHORT rsv1;
       //please initialize to 0s
@@ -6813,7 +7619,7 @@
       UCHAR clockInfoIndex[1];
 } ATOM_PPLIB_STATE_V2;
 
-typedef struct StateArray{
+typedef struct _StateArray{
     //how many states we have 
     UCHAR ucNumEntries;
     
@@ -6821,18 +7627,17 @@
 }StateArray;
 
 
-typedef struct ClockInfoArray{
+typedef struct _ClockInfoArray{
     //how many clock levels we have
     UCHAR ucNumEntries;
     
-    //sizeof(ATOM_PPLIB_SUMO_CLOCK_INFO)
+    //sizeof(ATOM_PPLIB_CLOCK_INFO)
     UCHAR ucEntrySize;
     
-    //this is for Sumo
-    ATOM_PPLIB_SUMO_CLOCK_INFO clockInfo[1];
+    UCHAR clockInfo[1];
 }ClockInfoArray;
 
-typedef struct NonClockInfoArray{
+typedef struct _NonClockInfoArray{
 
     //how many non-clock levels we have. normally should be same as number of states
     UCHAR ucNumEntries;
@@ -6871,6 +7676,124 @@
     ATOM_PPLIB_Clock_Voltage_Limit_Record entries[1];                  // Dynamically allocate entries.
 }ATOM_PPLIB_Clock_Voltage_Limit_Table;
 
+typedef struct _ATOM_PPLIB_CAC_Leakage_Record
+{
+    USHORT usVddc;  // We use this field for the "fake" standardized VDDC for power calculations                                                  
+    ULONG  ulLeakageValue;
+}ATOM_PPLIB_CAC_Leakage_Record;
+
+typedef struct _ATOM_PPLIB_CAC_Leakage_Table
+{
+    UCHAR ucNumEntries;                                                 // Number of entries.
+    ATOM_PPLIB_CAC_Leakage_Record entries[1];                           // Dynamically allocate entries.
+}ATOM_PPLIB_CAC_Leakage_Table;
+
+typedef struct _ATOM_PPLIB_PhaseSheddingLimits_Record
+{
+    USHORT usVoltage;
+    USHORT usSclkLow;
+    UCHAR  ucSclkHigh;
+    USHORT usMclkLow;
+    UCHAR  ucMclkHigh;
+}ATOM_PPLIB_PhaseSheddingLimits_Record;
+
+typedef struct _ATOM_PPLIB_PhaseSheddingLimits_Table
+{
+    UCHAR ucNumEntries;                                                 // Number of entries.
+    ATOM_PPLIB_PhaseSheddingLimits_Record entries[1];                   // Dynamically allocate entries.
+}ATOM_PPLIB_PhaseSheddingLimits_Table;
+
+typedef struct _VCEClockInfo{
+    USHORT usEVClkLow;
+    UCHAR  ucEVClkHigh;
+    USHORT usECClkLow;
+    UCHAR  ucECClkHigh;
+}VCEClockInfo;
+
+typedef struct _VCEClockInfoArray{
+    UCHAR ucNumEntries;
+    VCEClockInfo entries[1];
+}VCEClockInfoArray;
+
+typedef struct _ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record
+{
+    USHORT usVoltage;
+    UCHAR  ucVCEClockInfoIndex;
+}ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record;
+
+typedef struct _ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table
+{
+    UCHAR numEntries;
+    ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record entries[1];
+}ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table;
+
+typedef struct _ATOM_PPLIB_VCE_State_Record
+{
+    UCHAR  ucVCEClockInfoIndex;
+    UCHAR  ucClockInfoIndex; //highest 2 bits indicates memory p-states, lower 6bits indicates index to ClockInfoArrary
+}ATOM_PPLIB_VCE_State_Record;
+
+typedef struct _ATOM_PPLIB_VCE_State_Table
+{
+    UCHAR numEntries;
+    ATOM_PPLIB_VCE_State_Record entries[1];
+}ATOM_PPLIB_VCE_State_Table;
+
+
+typedef struct _ATOM_PPLIB_VCE_Table
+{
+      UCHAR revid;
+//    VCEClockInfoArray array;
+//    ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table limits;
+//    ATOM_PPLIB_VCE_State_Table states;
+}ATOM_PPLIB_VCE_Table;
+
+
+typedef struct _UVDClockInfo{
+    USHORT usVClkLow;
+    UCHAR  ucVClkHigh;
+    USHORT usDClkLow;
+    UCHAR  ucDClkHigh;
+}UVDClockInfo;
+
+typedef struct _UVDClockInfoArray{
+    UCHAR ucNumEntries;
+    UVDClockInfo entries[1];
+}UVDClockInfoArray;
+
+typedef struct _ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record
+{
+    USHORT usVoltage;
+    UCHAR  ucUVDClockInfoIndex;
+}ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record;
+
+typedef struct _ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table
+{
+    UCHAR numEntries;
+    ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record entries[1];
+}ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table;
+
+typedef struct _ATOM_PPLIB_UVD_State_Record
+{
+    UCHAR  ucUVDClockInfoIndex;
+    UCHAR  ucClockInfoIndex; //highest 2 bits indicates memory p-states, lower 6bits indicates index to ClockInfoArrary
+}ATOM_PPLIB_UVD_State_Record;
+
+typedef struct _ATOM_PPLIB_UVD_State_Table
+{
+    UCHAR numEntries;
+    ATOM_PPLIB_UVD_State_Record entries[1];
+}ATOM_PPLIB_UVD_State_Table;
+
+
+typedef struct _ATOM_PPLIB_UVD_Table
+{
+      UCHAR revid;
+//    UVDClockInfoArray array;
+//    ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table limits;
+//    ATOM_PPLIB_UVD_State_Table states;
+}ATOM_PPLIB_UVD_Table;
+
 /**************************************************************************/
 
 
@@ -7020,4 +7943,68 @@
 
 #pragma pack() // BIOS data must use byte aligment
 
+//
+// AMD ACPI Table
+//
+#pragma pack(1)
+
+typedef struct {
+  ULONG Signature;
+  ULONG TableLength;      //Length
+  UCHAR Revision;
+  UCHAR Checksum;
+  UCHAR OemId[6];
+  UCHAR OemTableId[8];    //UINT64  OemTableId;
+  ULONG OemRevision;
+  ULONG CreatorId;
+  ULONG CreatorRevision;
+} AMD_ACPI_DESCRIPTION_HEADER;
+/*
+//EFI_ACPI_DESCRIPTION_HEADER from AcpiCommon.h
+typedef struct {
+  UINT32  Signature;       //0x0
+  UINT32  Length;          //0x4
+  UINT8   Revision;        //0x8
+  UINT8   Checksum;        //0x9
+  UINT8   OemId[6];        //0xA
+  UINT64  OemTableId;      //0x10
+  UINT32  OemRevision;     //0x18
+  UINT32  CreatorId;       //0x1C
+  UINT32  CreatorRevision; //0x20
+}EFI_ACPI_DESCRIPTION_HEADER;
+*/
+typedef struct {
+  AMD_ACPI_DESCRIPTION_HEADER SHeader;
+  UCHAR TableUUID[16];    //0x24
+  ULONG VBIOSImageOffset; //0x34. Offset to the first GOP_VBIOS_CONTENT block from the beginning of the stucture.
+  ULONG Lib1ImageOffset;  //0x38. Offset to the first GOP_LIB1_CONTENT block from the beginning of the stucture.
+  ULONG Reserved[4];      //0x3C
+}UEFI_ACPI_VFCT;
+
+typedef struct {
+  ULONG  PCIBus;          //0x4C
+  ULONG  PCIDevice;       //0x50
+  ULONG  PCIFunction;     //0x54
+  USHORT VendorID;        //0x58
+  USHORT DeviceID;        //0x5A
+  USHORT SSVID;           //0x5C
+  USHORT SSID;            //0x5E
+  ULONG  Revision;        //0x60
+  ULONG  ImageLength;     //0x64
+}VFCT_IMAGE_HEADER;
+
+
+typedef struct {
+  VFCT_IMAGE_HEADER	VbiosHeader;
+  UCHAR	VbiosContent[1];
+}GOP_VBIOS_CONTENT;
+
+typedef struct {
+  VFCT_IMAGE_HEADER	Lib1Header;
+  UCHAR	Lib1Content[1];
+}GOP_LIB1_CONTENT;
+
+#pragma pack()
+
+
 #endif /* _ATOMBIOS_H */
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 742f17f..b5ff1f7 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -231,6 +231,22 @@
 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
+static void atombios_powergate_crtc(struct drm_crtc *crtc, int state)
+{
+	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	struct radeon_device *rdev = dev->dev_private;
+	int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
+	ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 args;
+
+	memset(&args, 0, sizeof(args));
+
+	args.ucDispPipeId = radeon_crtc->crtc_id;
+	args.ucEnable = state;
+
+	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
 void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
 	struct drm_device *dev = crtc->dev;
@@ -242,8 +258,11 @@
 		radeon_crtc->enabled = true;
 		/* adjust pm to dpms changes BEFORE enabling crtcs */
 		radeon_pm_compute_clocks(rdev);
+		/* disable crtc pair power gating before programming */
+		if (ASIC_IS_DCE6(rdev))
+			atombios_powergate_crtc(crtc, ATOM_DISABLE);
 		atombios_enable_crtc(crtc, ATOM_ENABLE);
-		if (ASIC_IS_DCE3(rdev))
+		if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev))
 			atombios_enable_crtc_memreq(crtc, ATOM_ENABLE);
 		atombios_blank_crtc(crtc, ATOM_DISABLE);
 		drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
@@ -255,10 +274,29 @@
 		drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);
 		if (radeon_crtc->enabled)
 			atombios_blank_crtc(crtc, ATOM_ENABLE);
-		if (ASIC_IS_DCE3(rdev))
+		if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev))
 			atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);
 		atombios_enable_crtc(crtc, ATOM_DISABLE);
 		radeon_crtc->enabled = false;
+		/* power gating is per-pair */
+		if (ASIC_IS_DCE6(rdev)) {
+			struct drm_crtc *other_crtc;
+			struct radeon_crtc *other_radeon_crtc;
+			list_for_each_entry(other_crtc, &rdev->ddev->mode_config.crtc_list, head) {
+				other_radeon_crtc = to_radeon_crtc(other_crtc);
+				if (((radeon_crtc->crtc_id == 0) && (other_radeon_crtc->crtc_id == 1)) ||
+				    ((radeon_crtc->crtc_id == 1) && (other_radeon_crtc->crtc_id == 0)) ||
+				    ((radeon_crtc->crtc_id == 2) && (other_radeon_crtc->crtc_id == 3)) ||
+				    ((radeon_crtc->crtc_id == 3) && (other_radeon_crtc->crtc_id == 2)) ||
+				    ((radeon_crtc->crtc_id == 4) && (other_radeon_crtc->crtc_id == 5)) ||
+				    ((radeon_crtc->crtc_id == 5) && (other_radeon_crtc->crtc_id == 4))) {
+					/* if both crtcs in the pair are off, enable power gating */
+					if (other_radeon_crtc->enabled == false)
+						atombios_powergate_crtc(crtc, ATOM_ENABLE);
+					break;
+				}
+			}
+		}
 		/* adjust pm to dpms changes AFTER disabling crtcs */
 		radeon_pm_compute_clocks(rdev);
 		break;
@@ -436,7 +474,7 @@
 			return;
 		}
 		args.v3.ucEnable = enable;
-		if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK))
+		if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK) || ASIC_IS_DCE61(rdev))
 			args.v3.ucEnable = ATOM_DISABLE;
 	} else if (ASIC_IS_DCE4(rdev)) {
 		args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
@@ -550,8 +588,8 @@
 		if (encoder->crtc == crtc) {
 			radeon_encoder = to_radeon_encoder(encoder);
 			connector = radeon_get_connector_for_encoder(encoder);
-			if (connector && connector->display_info.bpc)
-				bpc = connector->display_info.bpc;
+			/* if (connector && connector->display_info.bpc)
+				bpc = connector->display_info.bpc; */
 			encoder_mode = atombios_get_encoder_mode(encoder);
 			is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock);
 			if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
@@ -699,7 +737,7 @@
 /* on DCE5, make sure the voltage is high enough to support the
  * required disp clk.
  */
-static void atombios_crtc_set_dcpll(struct radeon_device *rdev,
+static void atombios_crtc_set_disp_eng_pll(struct radeon_device *rdev,
 				    u32 dispclk)
 {
 	u8 frev, crev;
@@ -729,7 +767,12 @@
 			 * SetPixelClock provides the dividers
 			 */
 			args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk);
-			args.v6.ucPpll = ATOM_DCPLL;
+			if (ASIC_IS_DCE61(rdev))
+				args.v6.ucPpll = ATOM_EXT_PLL1;
+			else if (ASIC_IS_DCE6(rdev))
+				args.v6.ucPpll = ATOM_PPLL0;
+			else
+				args.v6.ucPpll = ATOM_DCPLL;
 			break;
 		default:
 			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
@@ -922,7 +965,9 @@
 		struct radeon_connector_atom_dig *dig_connector =
 			radeon_connector->con_priv;
 		int dp_clock;
-		bpc = connector->display_info.bpc;
+
+		/* if (connector->display_info.bpc)
+			bpc = connector->display_info.bpc; */
 
 		switch (encoder_mode) {
 		case ATOM_ENCODER_MODE_DP_MST:
@@ -1031,6 +1076,7 @@
 	struct radeon_bo *rbo;
 	uint64_t fb_location;
 	uint32_t fb_format, fb_pitch_pixels, tiling_flags;
+	unsigned bankw, bankh, mtaspect, tile_split;
 	u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE);
 	u32 tmp, viewport_w, viewport_h;
 	int r;
@@ -1121,20 +1167,13 @@
 			break;
 		}
 
-		switch ((tmp & 0xf000) >> 12) {
-		case 0: /* 1KB rows */
-		default:
-			fb_format |= EVERGREEN_GRPH_TILE_SPLIT(EVERGREEN_ADDR_SURF_TILE_SPLIT_1KB);
-			break;
-		case 1: /* 2KB rows */
-			fb_format |= EVERGREEN_GRPH_TILE_SPLIT(EVERGREEN_ADDR_SURF_TILE_SPLIT_2KB);
-			break;
-		case 2: /* 4KB rows */
-			fb_format |= EVERGREEN_GRPH_TILE_SPLIT(EVERGREEN_ADDR_SURF_TILE_SPLIT_4KB);
-			break;
-		}
-
 		fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1);
+
+		evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split);
+		fb_format |= EVERGREEN_GRPH_TILE_SPLIT(tile_split);
+		fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw);
+		fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh);
+		fb_format |= EVERGREEN_GRPH_MACRO_TILE_ASPECT(mtaspect);
 	} else if (tiling_flags & RADEON_TILING_MICRO)
 		fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1);
 
@@ -1450,7 +1489,36 @@
 	struct drm_crtc *test_crtc;
 	uint32_t pll_in_use = 0;
 
-	if (ASIC_IS_DCE4(rdev)) {
+	if (ASIC_IS_DCE61(rdev)) {
+		list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
+			if (test_encoder->crtc && (test_encoder->crtc == crtc)) {
+				struct radeon_encoder *test_radeon_encoder =
+					to_radeon_encoder(test_encoder);
+				struct radeon_encoder_atom_dig *dig =
+					test_radeon_encoder->enc_priv;
+
+				if ((test_radeon_encoder->encoder_id ==
+				     ENCODER_OBJECT_ID_INTERNAL_UNIPHY) &&
+				    (dig->linkb == false)) /* UNIPHY A uses PPLL2 */
+					return ATOM_PPLL2;
+			}
+		}
+		/* UNIPHY B/C/D/E/F */
+		list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
+			struct radeon_crtc *radeon_test_crtc;
+
+			if (crtc == test_crtc)
+				continue;
+
+			radeon_test_crtc = to_radeon_crtc(test_crtc);
+			if ((radeon_test_crtc->pll_id == ATOM_PPLL0) ||
+			    (radeon_test_crtc->pll_id == ATOM_PPLL1))
+				pll_in_use |= (1 << radeon_test_crtc->pll_id);
+		}
+		if (!(pll_in_use & 4))
+			return ATOM_PPLL0;
+		return ATOM_PPLL1;
+	} else if (ASIC_IS_DCE4(rdev)) {
 		list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
 			if (test_encoder->crtc && (test_encoder->crtc == crtc)) {
 				/* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock,
@@ -1489,10 +1557,12 @@
 
 }
 
-void radeon_atom_dcpll_init(struct radeon_device *rdev)
+void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev)
 {
 	/* always set DCPLL */
-	if (ASIC_IS_DCE4(rdev)) {
+	if (ASIC_IS_DCE6(rdev))
+		atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk);
+	else if (ASIC_IS_DCE4(rdev)) {
 		struct radeon_atom_ss ss;
 		bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss,
 								   ASIC_INTERNAL_SS_ON_DCPLL,
@@ -1500,7 +1570,7 @@
 		if (ss_enabled)
 			atombios_crtc_program_ss(rdev, ATOM_DISABLE, ATOM_DCPLL, &ss);
 		/* XXX: DCE5, make sure voltage, dispclk is high enough */
-		atombios_crtc_set_dcpll(rdev, rdev->clock.default_dispclk);
+		atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk);
 		if (ss_enabled)
 			atombios_crtc_program_ss(rdev, ATOM_ENABLE, ATOM_DCPLL, &ss);
 	}
@@ -1578,6 +1648,8 @@
 static void atombios_crtc_disable(struct drm_crtc *crtc)
 {
 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	struct radeon_device *rdev = dev->dev_private;
 	struct radeon_atom_ss ss;
 
 	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
@@ -1589,6 +1661,12 @@
 		atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
 					  0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
 		break;
+	case ATOM_PPLL0:
+		/* disable the ppll */
+		if (ASIC_IS_DCE61(rdev))
+			atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
+						  0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
+		break;
 	default:
 		break;
 	}
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index 552b436..c57d856 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -63,12 +63,12 @@
 
 	memset(&args, 0, sizeof(args));
 
-	base = (unsigned char *)rdev->mode_info.atom_context->scratch;
+	base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1);
 
 	memcpy(base, send, send_bytes);
 
-	args.v1.lpAuxRequest = 0;
-	args.v1.lpDataOut = 16;
+	args.v1.lpAuxRequest = 0 + 4;
+	args.v1.lpDataOut = 16 + 4;
 	args.v1.ucDataOutLen = 0;
 	args.v1.ucChannelID = chan->rec.i2c_id;
 	args.v1.ucDelay = delay / 10;
@@ -405,10 +405,13 @@
 /* get bpc from the EDID */
 static int convert_bpc_to_bpp(int bpc)
 {
+#if 0
 	if (bpc == 0)
 		return 24;
 	else
 		return bpc * 3;
+#endif
+	return 24;
 }
 
 /* get the max pix clock supported by the link rate and lane num */
@@ -746,7 +749,8 @@
 
 	/* set the lane count on the sink */
 	tmp = dp_info->dp_lane_count;
-	if (dp_info->dpcd[0] >= 0x11)
+	if (dp_info->dpcd[DP_DPCD_REV] >= 0x11 &&
+	    dp_info->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)
 		tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
 	radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LANE_COUNT_SET, tmp);
 
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index b88c460..e607c4d 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -479,7 +479,7 @@
  * - 2 DIG encoder blocks.
  * DIG1/2 can drive UNIPHY0/1/2 link A or link B
  *
- * DCE 4.0/5.0
+ * DCE 4.0/5.0/6.0
  * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B).
  * Supports up to 6 digital outputs
  * - 6 DIG encoder blocks.
@@ -495,7 +495,11 @@
  * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B).
  * Supports up to 6 digital outputs
  * - 2 DIG encoder blocks.
+ * llano
  * DIG1/2 can drive UNIPHY0/1/2 link A or link B
+ * ontario
+ * DIG1 drives UNIPHY0/1/2 link A
+ * DIG2 drives UNIPHY0/1/2 link B
  *
  * Routing
  * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links)
@@ -537,7 +541,7 @@
 		dp_clock = dig_connector->dp_clock;
 		dp_lane_count = dig_connector->dp_lane_count;
 		hpd_id = radeon_connector->hpd.hpd;
-		bpc = connector->display_info.bpc;
+		/* bpc = connector->display_info.bpc; */
 	}
 
 	/* no dig encoder assigned */
@@ -703,6 +707,7 @@
 	DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
 	DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3;
 	DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 v4;
+	DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5 v5;
 };
 
 void
@@ -723,6 +728,7 @@
 	int connector_object_id = 0;
 	int igp_lane_info = 0;
 	int dig_encoder = dig->dig_encoder;
+	int hpd_id = RADEON_HPD_NONE;
 
 	if (action == ATOM_TRANSMITTER_ACTION_INIT) {
 		connector = radeon_get_connector_for_encoder_init(encoder);
@@ -738,6 +744,7 @@
 		struct radeon_connector_atom_dig *dig_connector =
 			radeon_connector->con_priv;
 
+		hpd_id = radeon_connector->hpd.hpd;
 		dp_clock = dig_connector->dp_clock;
 		dp_lane_count = dig_connector->dp_lane_count;
 		connector_object_id =
@@ -1003,6 +1010,60 @@
 					args.v4.acConfig.fDualLinkConnector = 1;
 			}
 			break;
+		case 5:
+			args.v5.ucAction = action;
+			if (is_dp)
+				args.v5.usSymClock = cpu_to_le16(dp_clock / 10);
+			else
+				args.v5.usSymClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+
+			switch (radeon_encoder->encoder_id) {
+			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+				if (dig->linkb)
+					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYB;
+				else
+					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYA;
+				break;
+			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+				if (dig->linkb)
+					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYD;
+				else
+					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYC;
+				break;
+			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+				if (dig->linkb)
+					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYF;
+				else
+					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYE;
+				break;
+			}
+			if (is_dp)
+				args.v5.ucLaneNum = dp_lane_count;
+			else if (radeon_encoder->pixel_clock > 165000)
+				args.v5.ucLaneNum = 8;
+			else
+				args.v5.ucLaneNum = 4;
+			args.v5.ucConnObjId = connector_object_id;
+			args.v5.ucDigMode = atombios_get_encoder_mode(encoder);
+
+			if (is_dp && rdev->clock.dp_extclk)
+				args.v5.asConfig.ucPhyClkSrcId = ENCODER_REFCLK_SRC_EXTCLK;
+			else
+				args.v5.asConfig.ucPhyClkSrcId = pll_id;
+
+			if (is_dp)
+				args.v5.asConfig.ucCoherentMode = 1; /* DP requires coherent */
+			else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+				if (dig->coherent_mode)
+					args.v5.asConfig.ucCoherentMode = 1;
+			}
+			if (hpd_id == RADEON_HPD_NONE)
+				args.v5.asConfig.ucHPDSel = 0;
+			else
+				args.v5.asConfig.ucHPDSel = hpd_id + 1;
+			args.v5.ucDigEncoderSel = 1 << dig_encoder;
+			args.v5.ucDPLaneSet = lane_set;
+			break;
 		default:
 			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
 			break;
@@ -1098,7 +1159,7 @@
 		dp_lane_count = dig_connector->dp_lane_count;
 		connector_object_id =
 			(radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
-		bpc = connector->display_info.bpc;
+		/* bpc = connector->display_info.bpc; */
 	}
 
 	memset(&args, 0, sizeof(args));
@@ -1377,7 +1438,7 @@
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
 	default:
-		if (ASIC_IS_DCE41(rdev)) {
+		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) {
 			atombios_external_encoder_setup(encoder, ext_encoder,
 							EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT);
 			atombios_external_encoder_setup(encoder, ext_encoder,
@@ -1388,7 +1449,7 @@
 	case DRM_MODE_DPMS_STANDBY:
 	case DRM_MODE_DPMS_SUSPEND:
 	case DRM_MODE_DPMS_OFF:
-		if (ASIC_IS_DCE41(rdev)) {
+		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) {
 			atombios_external_encoder_setup(encoder, ext_encoder,
 							EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING);
 			atombios_external_encoder_setup(encoder, ext_encoder,
@@ -1761,7 +1822,7 @@
 			break;
 		}
 
-		if (ext_encoder && ASIC_IS_DCE41(rdev))
+		if (ext_encoder && (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)))
 			atombios_external_encoder_setup(encoder, ext_encoder,
 							EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
 	}
@@ -1850,7 +1911,7 @@
 	}
 
 	if (ext_encoder) {
-		if (ASIC_IS_DCE41(rdev))
+		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev))
 			atombios_external_encoder_setup(encoder, ext_encoder,
 							EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP);
 		else
diff --git a/drivers/gpu/drm/radeon/atombios_i2c.c b/drivers/gpu/drm/radeon/atombios_i2c.c
new file mode 100644
index 0000000..44d87b6
--- /dev/null
+++ b/drivers/gpu/drm/radeon/atombios_i2c.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ *
+ */
+#include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+#include "atom.h"
+
+#define TARGET_HW_I2C_CLOCK 50
+
+/* these are a limitation of ProcessI2cChannelTransaction not the hw */
+#define ATOM_MAX_HW_I2C_WRITE 2
+#define ATOM_MAX_HW_I2C_READ  255
+
+static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
+				 u8 slave_addr, u8 flags,
+				 u8 *buf, u8 num)
+{
+	struct drm_device *dev = chan->dev;
+	struct radeon_device *rdev = dev->dev_private;
+	PROCESS_I2C_CHANNEL_TRANSACTION_PS_ALLOCATION args;
+	int index = GetIndexIntoMasterTable(COMMAND, ProcessI2cChannelTransaction);
+	unsigned char *base;
+	u16 out;
+
+	memset(&args, 0, sizeof(args));
+
+	base = (unsigned char *)rdev->mode_info.atom_context->scratch;
+
+	if (flags & HW_I2C_WRITE) {
+		if (num > ATOM_MAX_HW_I2C_WRITE) {
+			DRM_ERROR("hw i2c: tried to write too many bytes (%d vs 2)\n", num);
+			return -EINVAL;
+		}
+		memcpy(&out, buf, num);
+		args.lpI2CDataOut = cpu_to_le16(out);
+	} else {
+		if (num > ATOM_MAX_HW_I2C_READ) {
+			DRM_ERROR("hw i2c: tried to read too many bytes (%d vs 255)\n", num);
+			return -EINVAL;
+		}
+	}
+
+	args.ucI2CSpeed = TARGET_HW_I2C_CLOCK;
+	args.ucRegIndex = 0;
+	args.ucTransBytes = num;
+	args.ucSlaveAddr = slave_addr << 1;
+	args.ucLineNumber = chan->rec.i2c_id;
+
+	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+	/* error */
+	if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) {
+		DRM_DEBUG_KMS("hw_i2c error\n");
+		return -EIO;
+	}
+
+	if (!(flags & HW_I2C_WRITE))
+		memcpy(buf, base, num);
+
+	return 0;
+}
+
+int radeon_atom_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
+			    struct i2c_msg *msgs, int num)
+{
+	struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
+	struct i2c_msg *p;
+	int i, remaining, current_count, buffer_offset, max_bytes, ret;
+	u8 buf = 0, flags;
+
+	/* check for bus probe */
+	p = &msgs[0];
+	if ((num == 1) && (p->len == 0)) {
+		ret = radeon_process_i2c_ch(i2c,
+					    p->addr, HW_I2C_WRITE,
+					    &buf, 1);
+		if (ret)
+			return ret;
+		else
+			return num;
+	}
+
+	for (i = 0; i < num; i++) {
+		p = &msgs[i];
+		remaining = p->len;
+		buffer_offset = 0;
+		/* max_bytes are a limitation of ProcessI2cChannelTransaction not the hw */
+		if (p->flags & I2C_M_RD) {
+			max_bytes = ATOM_MAX_HW_I2C_READ;
+			flags = HW_I2C_READ;
+		} else {
+			max_bytes = ATOM_MAX_HW_I2C_WRITE;
+			flags = HW_I2C_WRITE;
+		}
+		while (remaining) {
+			if (remaining > max_bytes)
+				current_count = max_bytes;
+			else
+				current_count = remaining;
+			ret = radeon_process_i2c_ch(i2c,
+						    p->addr, flags,
+						    &p->buf[buffer_offset], current_count);
+			if (ret)
+				return ret;
+			remaining -= current_count;
+			buffer_offset += current_count;
+		}
+	}
+
+	return num;
+}
+
+u32 radeon_atom_hw_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
diff --git a/drivers/gpu/drm/radeon/cayman_blit_shaders.c b/drivers/gpu/drm/radeon/cayman_blit_shaders.c
index 7b4eeb7..19a0114 100644
--- a/drivers/gpu/drm/radeon/cayman_blit_shaders.c
+++ b/drivers/gpu/drm/radeon/cayman_blit_shaders.c
@@ -24,6 +24,7 @@
  *     Alex Deucher <alexander.deucher@amd.com>
  */
 
+#include <linux/bug.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index f58254a..cfa372c 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -43,6 +43,37 @@
 extern void cayman_cp_int_cntl_setup(struct radeon_device *rdev,
 				     int ring, u32 cp_int_cntl);
 
+void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw,
+			     unsigned *bankh, unsigned *mtaspect,
+			     unsigned *tile_split)
+{
+	*bankw = (tiling_flags >> RADEON_TILING_EG_BANKW_SHIFT) & RADEON_TILING_EG_BANKW_MASK;
+	*bankh = (tiling_flags >> RADEON_TILING_EG_BANKH_SHIFT) & RADEON_TILING_EG_BANKH_MASK;
+	*mtaspect = (tiling_flags >> RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT) & RADEON_TILING_EG_MACRO_TILE_ASPECT_MASK;
+	*tile_split = (tiling_flags >> RADEON_TILING_EG_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_TILE_SPLIT_MASK;
+	switch (*bankw) {
+	default:
+	case 1: *bankw = EVERGREEN_ADDR_SURF_BANK_WIDTH_1; break;
+	case 2: *bankw = EVERGREEN_ADDR_SURF_BANK_WIDTH_2; break;
+	case 4: *bankw = EVERGREEN_ADDR_SURF_BANK_WIDTH_4; break;
+	case 8: *bankw = EVERGREEN_ADDR_SURF_BANK_WIDTH_8; break;
+	}
+	switch (*bankh) {
+	default:
+	case 1: *bankh = EVERGREEN_ADDR_SURF_BANK_HEIGHT_1; break;
+	case 2: *bankh = EVERGREEN_ADDR_SURF_BANK_HEIGHT_2; break;
+	case 4: *bankh = EVERGREEN_ADDR_SURF_BANK_HEIGHT_4; break;
+	case 8: *bankh = EVERGREEN_ADDR_SURF_BANK_HEIGHT_8; break;
+	}
+	switch (*mtaspect) {
+	default:
+	case 1: *mtaspect = EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_1; break;
+	case 2: *mtaspect = EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_2; break;
+	case 4: *mtaspect = EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_4; break;
+	case 8: *mtaspect = EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_8; break;
+	}
+}
+
 void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev)
 {
 	u16 ctl, v;
@@ -68,6 +99,25 @@
 	}
 }
 
+void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc)
+{
+	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc];
+	int i;
+
+	if (RREG32(EVERGREEN_CRTC_CONTROL + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_MASTER_EN) {
+		for (i = 0; i < rdev->usec_timeout; i++) {
+			if (!(RREG32(EVERGREEN_CRTC_STATUS + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_V_BLANK))
+				break;
+			udelay(1);
+		}
+		for (i = 0; i < rdev->usec_timeout; i++) {
+			if (RREG32(EVERGREEN_CRTC_STATUS + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_V_BLANK)
+				break;
+			udelay(1);
+		}
+	}
+}
+
 void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc)
 {
 	/* enable the pflip int */
@@ -531,7 +581,7 @@
 	return 0;
 }
 
-static u32 evergreen_get_number_of_dram_channels(struct radeon_device *rdev)
+u32 evergreen_get_number_of_dram_channels(struct radeon_device *rdev)
 {
 	u32 tmp = RREG32(MC_SHARED_CHMAP);
 
@@ -1278,7 +1328,10 @@
 			rdev->mc.vram_end >> 12);
 	}
 	WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, rdev->vram_scratch.gpu_addr >> 12);
-	if (rdev->flags & RADEON_IS_IGP) {
+	/* llano/ontario only */
+	if ((rdev->family == CHIP_PALM) ||
+	    (rdev->family == CHIP_SUMO) ||
+	    (rdev->family == CHIP_SUMO2)) {
 		tmp = RREG32(MC_FUS_VM_FB_OFFSET) & 0x000FFFFF;
 		tmp |= ((rdev->mc.vram_end >> 20) & 0xF) << 24;
 		tmp |= ((rdev->mc.vram_start >> 20) & 0xF) << 20;
@@ -1489,7 +1542,7 @@
 
 	evergreen_cp_start(rdev);
 	ring->ready = true;
-	r = radeon_ring_test(rdev, ring);
+	r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, ring);
 	if (r) {
 		ring->ready = false;
 		return r;
@@ -1922,7 +1975,9 @@
 
 
 	mc_shared_chmap = RREG32(MC_SHARED_CHMAP);
-	if (rdev->flags & RADEON_IS_IGP)
+	if ((rdev->family == CHIP_PALM) ||
+	    (rdev->family == CHIP_SUMO) ||
+	    (rdev->family == CHIP_SUMO2))
 		mc_arb_ramcfg = RREG32(FUS_MC_ARB_RAMCFG);
 	else
 		mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG);
@@ -2312,7 +2367,9 @@
 
 	/* Get VRAM informations */
 	rdev->mc.vram_is_ddr = true;
-	if (rdev->flags & RADEON_IS_IGP)
+	if ((rdev->family == CHIP_PALM) ||
+	    (rdev->family == CHIP_SUMO) ||
+	    (rdev->family == CHIP_SUMO2))
 		tmp = RREG32(FUS_MC_ARB_RAMCFG);
 	else
 		tmp = RREG32(MC_ARB_RAMCFG);
@@ -2344,12 +2401,14 @@
 	rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
 	rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
 	/* Setup GPU memory space */
-	if (rdev->flags & RADEON_IS_IGP) {
+	if ((rdev->family == CHIP_PALM) ||
+	    (rdev->family == CHIP_SUMO) ||
+	    (rdev->family == CHIP_SUMO2)) {
 		/* size in bytes on fusion */
 		rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE);
 		rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE);
 	} else {
-		/* size in MB on evergreen */
+		/* size in MB on evergreen/cayman/tn */
 		rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
 		rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
 	}
@@ -2507,7 +2566,9 @@
 		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
 	}
 
-	WREG32(DACA_AUTODETECT_INT_CONTROL, 0);
+	/* only one DAC on DCE6 */
+	if (!ASIC_IS_DCE6(rdev))
+		WREG32(DACA_AUTODETECT_INT_CONTROL, 0);
 	WREG32(DACB_AUTODETECT_INT_CONTROL, 0);
 
 	tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY;
@@ -3147,7 +3208,7 @@
 	r = evergreen_blit_init(rdev);
 	if (r) {
 		r600_blit_fini(rdev);
-		rdev->asic->copy = NULL;
+		rdev->asic->copy.copy = NULL;
 		dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
 	}
 
@@ -3187,7 +3248,7 @@
 	if (r)
 		return r;
 
-	r = r600_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX);
+	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
 	if (r) {
 		DRM_ERROR("radeon: failed testing IB (%d).\n", r);
 		rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c
index 2379849..222acd2 100644
--- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c
+++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c
@@ -32,17 +32,7 @@
 #include "evergreend.h"
 #include "evergreen_blit_shaders.h"
 #include "cayman_blit_shaders.h"
-
-#define DI_PT_RECTLIST        0x11
-#define DI_INDEX_SIZE_16_BIT  0x0
-#define DI_SRC_SEL_AUTO_INDEX 0x2
-
-#define FMT_8                 0x1
-#define FMT_5_6_5             0x8
-#define FMT_8_8_8_8           0x1a
-#define COLOR_8               0x1
-#define COLOR_5_6_5           0x8
-#define COLOR_8_8_8_8         0x1a
+#include "radeon_blit_common.h"
 
 /* emits 17 */
 static void
@@ -236,7 +226,7 @@
 		x1 = 1;
 	if (y2 == 0)
 		y1 = 1;
-	if (rdev->family == CHIP_CAYMAN) {
+	if (rdev->family >= CHIP_CAYMAN) {
 		if ((x2 == 1) && (y2 == 1))
 			x2 = 2;
 	}
diff --git a/drivers/gpu/drm/radeon/evergreen_blit_shaders.c b/drivers/gpu/drm/radeon/evergreen_blit_shaders.c
index 3a10399..f85c0af 100644
--- a/drivers/gpu/drm/radeon/evergreen_blit_shaders.c
+++ b/drivers/gpu/drm/radeon/evergreen_blit_shaders.c
@@ -24,6 +24,7 @@
  *     Alex Deucher <alexander.deucher@amd.com>
  */
 
+#include <linux/bug.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 
diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c
index 8e8cd85..70089d3 100644
--- a/drivers/gpu/drm/radeon/evergreen_cs.c
+++ b/drivers/gpu/drm/radeon/evergreen_cs.c
@@ -31,6 +31,9 @@
 #include "evergreen_reg_safe.h"
 #include "cayman_reg_safe.h"
 
+#define MAX(a,b)                   (((a)>(b))?(a):(b))
+#define MIN(a,b)                   (((a)<(b))?(a):(b))
+
 static int evergreen_cs_packet_next_reloc(struct radeon_cs_parser *p,
 					  struct radeon_cs_reloc **cs_reloc);
 
@@ -40,42 +43,46 @@
 	u32			npipes;
 	u32			row_size;
 	/* value we track */
-	u32			nsamples;
-	u32			cb_color_base_last[12];
+	u32			nsamples;		/* unused */
 	struct radeon_bo	*cb_color_bo[12];
 	u32			cb_color_bo_offset[12];
-	struct radeon_bo	*cb_color_fmask_bo[8];
-	struct radeon_bo	*cb_color_cmask_bo[8];
+	struct radeon_bo	*cb_color_fmask_bo[8];	/* unused */
+	struct radeon_bo	*cb_color_cmask_bo[8];	/* unused */
 	u32			cb_color_info[12];
 	u32			cb_color_view[12];
-	u32			cb_color_pitch_idx[12];
-	u32			cb_color_slice_idx[12];
-	u32			cb_color_dim_idx[12];
-	u32			cb_color_dim[12];
 	u32			cb_color_pitch[12];
 	u32			cb_color_slice[12];
-	u32			cb_color_cmask_slice[8];
-	u32			cb_color_fmask_slice[8];
+	u32			cb_color_attrib[12];
+	u32			cb_color_cmask_slice[8];/* unused */
+	u32			cb_color_fmask_slice[8];/* unused */
 	u32			cb_target_mask;
-	u32			cb_shader_mask;
+	u32			cb_shader_mask; /* unused */
 	u32			vgt_strmout_config;
 	u32			vgt_strmout_buffer_config;
+	struct radeon_bo	*vgt_strmout_bo[4];
+	u32			vgt_strmout_bo_offset[4];
+	u32			vgt_strmout_size[4];
 	u32			db_depth_control;
 	u32			db_depth_view;
+	u32			db_depth_slice;
 	u32			db_depth_size;
-	u32			db_depth_size_idx;
 	u32			db_z_info;
-	u32			db_z_idx;
 	u32			db_z_read_offset;
 	u32			db_z_write_offset;
 	struct radeon_bo	*db_z_read_bo;
 	struct radeon_bo	*db_z_write_bo;
 	u32			db_s_info;
-	u32			db_s_idx;
 	u32			db_s_read_offset;
 	u32			db_s_write_offset;
 	struct radeon_bo	*db_s_read_bo;
 	struct radeon_bo	*db_s_write_bo;
+	bool			sx_misc_kill_all_prims;
+	bool			cb_dirty;
+	bool			db_dirty;
+	bool			streamout_dirty;
+	u32			htile_offset;
+	u32			htile_surface;
+	struct radeon_bo	*htile_bo;
 };
 
 static u32 evergreen_cs_get_aray_mode(u32 tiling_flags)
@@ -103,19 +110,6 @@
 	}
 }
 
-static u32 evergreen_cs_get_tile_split(u32 row_size)
-{
-	switch (row_size) {
-	case 1:
-	default:
-		return ADDR_SURF_TILE_SPLIT_1KB;
-	case 2:
-		return ADDR_SURF_TILE_SPLIT_2KB;
-	case 4:
-		return ADDR_SURF_TILE_SPLIT_4KB;
-	}
-}
-
 static void evergreen_cs_track_init(struct evergreen_cs_track *track)
 {
 	int i;
@@ -128,50 +122,820 @@
 	}
 
 	for (i = 0; i < 12; i++) {
-		track->cb_color_base_last[i] = 0;
 		track->cb_color_bo[i] = NULL;
 		track->cb_color_bo_offset[i] = 0xFFFFFFFF;
 		track->cb_color_info[i] = 0;
-		track->cb_color_view[i] = 0;
-		track->cb_color_pitch_idx[i] = 0;
-		track->cb_color_slice_idx[i] = 0;
-		track->cb_color_dim[i] = 0;
+		track->cb_color_view[i] = 0xFFFFFFFF;
 		track->cb_color_pitch[i] = 0;
 		track->cb_color_slice[i] = 0;
-		track->cb_color_dim[i] = 0;
 	}
 	track->cb_target_mask = 0xFFFFFFFF;
 	track->cb_shader_mask = 0xFFFFFFFF;
+	track->cb_dirty = true;
 
 	track->db_depth_view = 0xFFFFC000;
 	track->db_depth_size = 0xFFFFFFFF;
-	track->db_depth_size_idx = 0;
 	track->db_depth_control = 0xFFFFFFFF;
 	track->db_z_info = 0xFFFFFFFF;
-	track->db_z_idx = 0xFFFFFFFF;
 	track->db_z_read_offset = 0xFFFFFFFF;
 	track->db_z_write_offset = 0xFFFFFFFF;
 	track->db_z_read_bo = NULL;
 	track->db_z_write_bo = NULL;
 	track->db_s_info = 0xFFFFFFFF;
-	track->db_s_idx = 0xFFFFFFFF;
 	track->db_s_read_offset = 0xFFFFFFFF;
 	track->db_s_write_offset = 0xFFFFFFFF;
 	track->db_s_read_bo = NULL;
 	track->db_s_write_bo = NULL;
+	track->db_dirty = true;
+	track->htile_bo = NULL;
+	track->htile_offset = 0xFFFFFFFF;
+	track->htile_surface = 0;
+
+	for (i = 0; i < 4; i++) {
+		track->vgt_strmout_size[i] = 0;
+		track->vgt_strmout_bo[i] = NULL;
+		track->vgt_strmout_bo_offset[i] = 0xFFFFFFFF;
+	}
+	track->streamout_dirty = true;
+	track->sx_misc_kill_all_prims = false;
+}
+
+struct eg_surface {
+	/* value gathered from cs */
+	unsigned	nbx;
+	unsigned	nby;
+	unsigned	format;
+	unsigned	mode;
+	unsigned	nbanks;
+	unsigned	bankw;
+	unsigned	bankh;
+	unsigned	tsplit;
+	unsigned	mtilea;
+	unsigned	nsamples;
+	/* output value */
+	unsigned	bpe;
+	unsigned	layer_size;
+	unsigned	palign;
+	unsigned	halign;
+	unsigned long	base_align;
+};
+
+static int evergreen_surface_check_linear(struct radeon_cs_parser *p,
+					  struct eg_surface *surf,
+					  const char *prefix)
+{
+	surf->layer_size = surf->nbx * surf->nby * surf->bpe * surf->nsamples;
+	surf->base_align = surf->bpe;
+	surf->palign = 1;
+	surf->halign = 1;
+	return 0;
+}
+
+static int evergreen_surface_check_linear_aligned(struct radeon_cs_parser *p,
+						  struct eg_surface *surf,
+						  const char *prefix)
+{
+	struct evergreen_cs_track *track = p->track;
+	unsigned palign;
+
+	palign = MAX(64, track->group_size / surf->bpe);
+	surf->layer_size = surf->nbx * surf->nby * surf->bpe * surf->nsamples;
+	surf->base_align = track->group_size;
+	surf->palign = palign;
+	surf->halign = 1;
+	if (surf->nbx & (palign - 1)) {
+		if (prefix) {
+			dev_warn(p->dev, "%s:%d %s pitch %d invalid must be aligned with %d\n",
+				 __func__, __LINE__, prefix, surf->nbx, palign);
+		}
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int evergreen_surface_check_1d(struct radeon_cs_parser *p,
+				      struct eg_surface *surf,
+				      const char *prefix)
+{
+	struct evergreen_cs_track *track = p->track;
+	unsigned palign;
+
+	palign = track->group_size / (8 * surf->bpe * surf->nsamples);
+	palign = MAX(8, palign);
+	surf->layer_size = surf->nbx * surf->nby * surf->bpe;
+	surf->base_align = track->group_size;
+	surf->palign = palign;
+	surf->halign = 8;
+	if ((surf->nbx & (palign - 1))) {
+		if (prefix) {
+			dev_warn(p->dev, "%s:%d %s pitch %d invalid must be aligned with %d (%d %d %d)\n",
+				 __func__, __LINE__, prefix, surf->nbx, palign,
+				 track->group_size, surf->bpe, surf->nsamples);
+		}
+		return -EINVAL;
+	}
+	if ((surf->nby & (8 - 1))) {
+		if (prefix) {
+			dev_warn(p->dev, "%s:%d %s height %d invalid must be aligned with 8\n",
+				 __func__, __LINE__, prefix, surf->nby);
+		}
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int evergreen_surface_check_2d(struct radeon_cs_parser *p,
+				      struct eg_surface *surf,
+				      const char *prefix)
+{
+	struct evergreen_cs_track *track = p->track;
+	unsigned palign, halign, tileb, slice_pt;
+
+	tileb = 64 * surf->bpe * surf->nsamples;
+	palign = track->group_size / (8 * surf->bpe * surf->nsamples);
+	palign = MAX(8, palign);
+	slice_pt = 1;
+	if (tileb > surf->tsplit) {
+		slice_pt = tileb / surf->tsplit;
+	}
+	tileb = tileb / slice_pt;
+	/* macro tile width & height */
+	palign = (8 * surf->bankw * track->npipes) * surf->mtilea;
+	halign = (8 * surf->bankh * surf->nbanks) / surf->mtilea;
+	surf->layer_size = surf->nbx * surf->nby * surf->bpe * slice_pt;
+	surf->base_align = (palign / 8) * (halign / 8) * tileb;
+	surf->palign = palign;
+	surf->halign = halign;
+
+	if ((surf->nbx & (palign - 1))) {
+		if (prefix) {
+			dev_warn(p->dev, "%s:%d %s pitch %d invalid must be aligned with %d\n",
+				 __func__, __LINE__, prefix, surf->nbx, palign);
+		}
+		return -EINVAL;
+	}
+	if ((surf->nby & (halign - 1))) {
+		if (prefix) {
+			dev_warn(p->dev, "%s:%d %s height %d invalid must be aligned with %d\n",
+				 __func__, __LINE__, prefix, surf->nby, halign);
+		}
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int evergreen_surface_check(struct radeon_cs_parser *p,
+				   struct eg_surface *surf,
+				   const char *prefix)
+{
+	/* some common value computed here */
+	surf->bpe = r600_fmt_get_blocksize(surf->format);
+
+	switch (surf->mode) {
+	case ARRAY_LINEAR_GENERAL:
+		return evergreen_surface_check_linear(p, surf, prefix);
+	case ARRAY_LINEAR_ALIGNED:
+		return evergreen_surface_check_linear_aligned(p, surf, prefix);
+	case ARRAY_1D_TILED_THIN1:
+		return evergreen_surface_check_1d(p, surf, prefix);
+	case ARRAY_2D_TILED_THIN1:
+		return evergreen_surface_check_2d(p, surf, prefix);
+	default:
+		dev_warn(p->dev, "%s:%d %s invalid array mode %d\n",
+				__func__, __LINE__, prefix, surf->mode);
+		return -EINVAL;
+	}
+	return -EINVAL;
+}
+
+static int evergreen_surface_value_conv_check(struct radeon_cs_parser *p,
+					      struct eg_surface *surf,
+					      const char *prefix)
+{
+	switch (surf->mode) {
+	case ARRAY_2D_TILED_THIN1:
+		break;
+	case ARRAY_LINEAR_GENERAL:
+	case ARRAY_LINEAR_ALIGNED:
+	case ARRAY_1D_TILED_THIN1:
+		return 0;
+	default:
+		dev_warn(p->dev, "%s:%d %s invalid array mode %d\n",
+				__func__, __LINE__, prefix, surf->mode);
+		return -EINVAL;
+	}
+
+	switch (surf->nbanks) {
+	case 0: surf->nbanks = 2; break;
+	case 1: surf->nbanks = 4; break;
+	case 2: surf->nbanks = 8; break;
+	case 3: surf->nbanks = 16; break;
+	default:
+		dev_warn(p->dev, "%s:%d %s invalid number of banks %d\n",
+			 __func__, __LINE__, prefix, surf->nbanks);
+		return -EINVAL;
+	}
+	switch (surf->bankw) {
+	case 0: surf->bankw = 1; break;
+	case 1: surf->bankw = 2; break;
+	case 2: surf->bankw = 4; break;
+	case 3: surf->bankw = 8; break;
+	default:
+		dev_warn(p->dev, "%s:%d %s invalid bankw %d\n",
+			 __func__, __LINE__, prefix, surf->bankw);
+		return -EINVAL;
+	}
+	switch (surf->bankh) {
+	case 0: surf->bankh = 1; break;
+	case 1: surf->bankh = 2; break;
+	case 2: surf->bankh = 4; break;
+	case 3: surf->bankh = 8; break;
+	default:
+		dev_warn(p->dev, "%s:%d %s invalid bankh %d\n",
+			 __func__, __LINE__, prefix, surf->bankh);
+		return -EINVAL;
+	}
+	switch (surf->mtilea) {
+	case 0: surf->mtilea = 1; break;
+	case 1: surf->mtilea = 2; break;
+	case 2: surf->mtilea = 4; break;
+	case 3: surf->mtilea = 8; break;
+	default:
+		dev_warn(p->dev, "%s:%d %s invalid macro tile aspect %d\n",
+			 __func__, __LINE__, prefix, surf->mtilea);
+		return -EINVAL;
+	}
+	switch (surf->tsplit) {
+	case 0: surf->tsplit = 64; break;
+	case 1: surf->tsplit = 128; break;
+	case 2: surf->tsplit = 256; break;
+	case 3: surf->tsplit = 512; break;
+	case 4: surf->tsplit = 1024; break;
+	case 5: surf->tsplit = 2048; break;
+	case 6: surf->tsplit = 4096; break;
+	default:
+		dev_warn(p->dev, "%s:%d %s invalid tile split %d\n",
+			 __func__, __LINE__, prefix, surf->tsplit);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned id)
+{
+	struct evergreen_cs_track *track = p->track;
+	struct eg_surface surf;
+	unsigned pitch, slice, mslice;
+	unsigned long offset;
+	int r;
+
+	mslice = G_028C6C_SLICE_MAX(track->cb_color_view[id]) + 1;
+	pitch = track->cb_color_pitch[id];
+	slice = track->cb_color_slice[id];
+	surf.nbx = (pitch + 1) * 8;
+	surf.nby = ((slice + 1) * 64) / surf.nbx;
+	surf.mode = G_028C70_ARRAY_MODE(track->cb_color_info[id]);
+	surf.format = G_028C70_FORMAT(track->cb_color_info[id]);
+	surf.tsplit = G_028C74_TILE_SPLIT(track->cb_color_attrib[id]);
+	surf.nbanks = G_028C74_NUM_BANKS(track->cb_color_attrib[id]);
+	surf.bankw = G_028C74_BANK_WIDTH(track->cb_color_attrib[id]);
+	surf.bankh = G_028C74_BANK_HEIGHT(track->cb_color_attrib[id]);
+	surf.mtilea = G_028C74_MACRO_TILE_ASPECT(track->cb_color_attrib[id]);
+	surf.nsamples = 1;
+
+	if (!r600_fmt_is_valid_color(surf.format)) {
+		dev_warn(p->dev, "%s:%d cb invalid format %d for %d (0x%08x)\n",
+			 __func__, __LINE__, surf.format,
+			id, track->cb_color_info[id]);
+		return -EINVAL;
+	}
+
+	r = evergreen_surface_value_conv_check(p, &surf, "cb");
+	if (r) {
+		return r;
+	}
+
+	r = evergreen_surface_check(p, &surf, "cb");
+	if (r) {
+		dev_warn(p->dev, "%s:%d cb[%d] invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n",
+			 __func__, __LINE__, id, track->cb_color_pitch[id],
+			 track->cb_color_slice[id], track->cb_color_attrib[id],
+			 track->cb_color_info[id]);
+		return r;
+	}
+
+	offset = track->cb_color_bo_offset[id] << 8;
+	if (offset & (surf.base_align - 1)) {
+		dev_warn(p->dev, "%s:%d cb[%d] bo base %ld not aligned with %ld\n",
+			 __func__, __LINE__, id, offset, surf.base_align);
+		return -EINVAL;
+	}
+
+	offset += surf.layer_size * mslice;
+	if (offset > radeon_bo_size(track->cb_color_bo[id])) {
+		dev_warn(p->dev, "%s:%d cb[%d] bo too small (layer size %d, "
+			 "offset %d, max layer %d, bo size %ld, slice %d)\n",
+			 __func__, __LINE__, id, surf.layer_size,
+			track->cb_color_bo_offset[id] << 8, mslice,
+			radeon_bo_size(track->cb_color_bo[id]), slice);
+		dev_warn(p->dev, "%s:%d problematic surf: (%d %d) (%d %d %d %d %d %d %d)\n",
+			 __func__, __LINE__, surf.nbx, surf.nby,
+			surf.mode, surf.bpe, surf.nsamples,
+			surf.bankw, surf.bankh,
+			surf.tsplit, surf.mtilea);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int evergreen_cs_track_validate_htile(struct radeon_cs_parser *p,
+						unsigned nbx, unsigned nby)
+{
+	struct evergreen_cs_track *track = p->track;
+	unsigned long size;
+
+	if (track->htile_bo == NULL) {
+		dev_warn(p->dev, "%s:%d htile enabled without htile surface 0x%08x\n",
+				__func__, __LINE__, track->db_z_info);
+		return -EINVAL;
+	}
+
+	if (G_028ABC_LINEAR(track->htile_surface)) {
+		/* pitch must be 16 htiles aligned == 16 * 8 pixel aligned */
+		nbx = round_up(nbx, 16 * 8);
+		/* height is npipes htiles aligned == npipes * 8 pixel aligned */
+		nby = round_up(nby, track->npipes * 8);
+	} else {
+		switch (track->npipes) {
+		case 8:
+			nbx = round_up(nbx, 64 * 8);
+			nby = round_up(nby, 64 * 8);
+			break;
+		case 4:
+			nbx = round_up(nbx, 64 * 8);
+			nby = round_up(nby, 32 * 8);
+			break;
+		case 2:
+			nbx = round_up(nbx, 32 * 8);
+			nby = round_up(nby, 32 * 8);
+			break;
+		case 1:
+			nbx = round_up(nbx, 32 * 8);
+			nby = round_up(nby, 16 * 8);
+			break;
+		default:
+			dev_warn(p->dev, "%s:%d invalid num pipes %d\n",
+					__func__, __LINE__, track->npipes);
+			return -EINVAL;
+		}
+	}
+	/* compute number of htile */
+	nbx = nbx / 8;
+	nby = nby / 8;
+	size = nbx * nby * 4;
+	size += track->htile_offset;
+
+	if (size > radeon_bo_size(track->htile_bo)) {
+		dev_warn(p->dev, "%s:%d htile surface too small %ld for %ld (%d %d)\n",
+				__func__, __LINE__, radeon_bo_size(track->htile_bo),
+				size, nbx, nby);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int evergreen_cs_track_validate_stencil(struct radeon_cs_parser *p)
+{
+	struct evergreen_cs_track *track = p->track;
+	struct eg_surface surf;
+	unsigned pitch, slice, mslice;
+	unsigned long offset;
+	int r;
+
+	mslice = G_028008_SLICE_MAX(track->db_depth_view) + 1;
+	pitch = G_028058_PITCH_TILE_MAX(track->db_depth_size);
+	slice = track->db_depth_slice;
+	surf.nbx = (pitch + 1) * 8;
+	surf.nby = ((slice + 1) * 64) / surf.nbx;
+	surf.mode = G_028040_ARRAY_MODE(track->db_z_info);
+	surf.format = G_028044_FORMAT(track->db_s_info);
+	surf.tsplit = G_028044_TILE_SPLIT(track->db_s_info);
+	surf.nbanks = G_028040_NUM_BANKS(track->db_z_info);
+	surf.bankw = G_028040_BANK_WIDTH(track->db_z_info);
+	surf.bankh = G_028040_BANK_HEIGHT(track->db_z_info);
+	surf.mtilea = G_028040_MACRO_TILE_ASPECT(track->db_z_info);
+	surf.nsamples = 1;
+
+	if (surf.format != 1) {
+		dev_warn(p->dev, "%s:%d stencil invalid format %d\n",
+			 __func__, __LINE__, surf.format);
+		return -EINVAL;
+	}
+	/* replace by color format so we can use same code */
+	surf.format = V_028C70_COLOR_8;
+
+	r = evergreen_surface_value_conv_check(p, &surf, "stencil");
+	if (r) {
+		return r;
+	}
+
+	r = evergreen_surface_check(p, &surf, NULL);
+	if (r) {
+		/* old userspace doesn't compute proper depth/stencil alignment
+		 * check that alignment against a bigger byte per elements and
+		 * only report if that alignment is wrong too.
+		 */
+		surf.format = V_028C70_COLOR_8_8_8_8;
+		r = evergreen_surface_check(p, &surf, "stencil");
+		if (r) {
+			dev_warn(p->dev, "%s:%d stencil invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n",
+				 __func__, __LINE__, track->db_depth_size,
+				 track->db_depth_slice, track->db_s_info, track->db_z_info);
+		}
+		return r;
+	}
+
+	offset = track->db_s_read_offset << 8;
+	if (offset & (surf.base_align - 1)) {
+		dev_warn(p->dev, "%s:%d stencil read bo base %ld not aligned with %ld\n",
+			 __func__, __LINE__, offset, surf.base_align);
+		return -EINVAL;
+	}
+	offset += surf.layer_size * mslice;
+	if (offset > radeon_bo_size(track->db_s_read_bo)) {
+		dev_warn(p->dev, "%s:%d stencil read bo too small (layer size %d, "
+			 "offset %ld, max layer %d, bo size %ld)\n",
+			 __func__, __LINE__, surf.layer_size,
+			(unsigned long)track->db_s_read_offset << 8, mslice,
+			radeon_bo_size(track->db_s_read_bo));
+		dev_warn(p->dev, "%s:%d stencil invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n",
+			 __func__, __LINE__, track->db_depth_size,
+			 track->db_depth_slice, track->db_s_info, track->db_z_info);
+		return -EINVAL;
+	}
+
+	offset = track->db_s_write_offset << 8;
+	if (offset & (surf.base_align - 1)) {
+		dev_warn(p->dev, "%s:%d stencil write bo base %ld not aligned with %ld\n",
+			 __func__, __LINE__, offset, surf.base_align);
+		return -EINVAL;
+	}
+	offset += surf.layer_size * mslice;
+	if (offset > radeon_bo_size(track->db_s_write_bo)) {
+		dev_warn(p->dev, "%s:%d stencil write bo too small (layer size %d, "
+			 "offset %ld, max layer %d, bo size %ld)\n",
+			 __func__, __LINE__, surf.layer_size,
+			(unsigned long)track->db_s_write_offset << 8, mslice,
+			radeon_bo_size(track->db_s_write_bo));
+		return -EINVAL;
+	}
+
+	/* hyperz */
+	if (G_028040_TILE_SURFACE_ENABLE(track->db_z_info)) {
+		r = evergreen_cs_track_validate_htile(p, surf.nbx, surf.nby);
+		if (r) {
+			return r;
+		}
+	}
+
+	return 0;
+}
+
+static int evergreen_cs_track_validate_depth(struct radeon_cs_parser *p)
+{
+	struct evergreen_cs_track *track = p->track;
+	struct eg_surface surf;
+	unsigned pitch, slice, mslice;
+	unsigned long offset;
+	int r;
+
+	mslice = G_028008_SLICE_MAX(track->db_depth_view) + 1;
+	pitch = G_028058_PITCH_TILE_MAX(track->db_depth_size);
+	slice = track->db_depth_slice;
+	surf.nbx = (pitch + 1) * 8;
+	surf.nby = ((slice + 1) * 64) / surf.nbx;
+	surf.mode = G_028040_ARRAY_MODE(track->db_z_info);
+	surf.format = G_028040_FORMAT(track->db_z_info);
+	surf.tsplit = G_028040_TILE_SPLIT(track->db_z_info);
+	surf.nbanks = G_028040_NUM_BANKS(track->db_z_info);
+	surf.bankw = G_028040_BANK_WIDTH(track->db_z_info);
+	surf.bankh = G_028040_BANK_HEIGHT(track->db_z_info);
+	surf.mtilea = G_028040_MACRO_TILE_ASPECT(track->db_z_info);
+	surf.nsamples = 1;
+
+	switch (surf.format) {
+	case V_028040_Z_16:
+		surf.format = V_028C70_COLOR_16;
+		break;
+	case V_028040_Z_24:
+	case V_028040_Z_32_FLOAT:
+		surf.format = V_028C70_COLOR_8_8_8_8;
+		break;
+	default:
+		dev_warn(p->dev, "%s:%d depth invalid format %d\n",
+			 __func__, __LINE__, surf.format);
+		return -EINVAL;
+	}
+
+	r = evergreen_surface_value_conv_check(p, &surf, "depth");
+	if (r) {
+		dev_warn(p->dev, "%s:%d depth invalid (0x%08x 0x%08x 0x%08x)\n",
+			 __func__, __LINE__, track->db_depth_size,
+			 track->db_depth_slice, track->db_z_info);
+		return r;
+	}
+
+	r = evergreen_surface_check(p, &surf, "depth");
+	if (r) {
+		dev_warn(p->dev, "%s:%d depth invalid (0x%08x 0x%08x 0x%08x)\n",
+			 __func__, __LINE__, track->db_depth_size,
+			 track->db_depth_slice, track->db_z_info);
+		return r;
+	}
+
+	offset = track->db_z_read_offset << 8;
+	if (offset & (surf.base_align - 1)) {
+		dev_warn(p->dev, "%s:%d stencil read bo base %ld not aligned with %ld\n",
+			 __func__, __LINE__, offset, surf.base_align);
+		return -EINVAL;
+	}
+	offset += surf.layer_size * mslice;
+	if (offset > radeon_bo_size(track->db_z_read_bo)) {
+		dev_warn(p->dev, "%s:%d depth read bo too small (layer size %d, "
+			 "offset %ld, max layer %d, bo size %ld)\n",
+			 __func__, __LINE__, surf.layer_size,
+			(unsigned long)track->db_z_read_offset << 8, mslice,
+			radeon_bo_size(track->db_z_read_bo));
+		return -EINVAL;
+	}
+
+	offset = track->db_z_write_offset << 8;
+	if (offset & (surf.base_align - 1)) {
+		dev_warn(p->dev, "%s:%d stencil write bo base %ld not aligned with %ld\n",
+			 __func__, __LINE__, offset, surf.base_align);
+		return -EINVAL;
+	}
+	offset += surf.layer_size * mslice;
+	if (offset > radeon_bo_size(track->db_z_write_bo)) {
+		dev_warn(p->dev, "%s:%d depth write bo too small (layer size %d, "
+			 "offset %ld, max layer %d, bo size %ld)\n",
+			 __func__, __LINE__, surf.layer_size,
+			(unsigned long)track->db_z_write_offset << 8, mslice,
+			radeon_bo_size(track->db_z_write_bo));
+		return -EINVAL;
+	}
+
+	/* hyperz */
+	if (G_028040_TILE_SURFACE_ENABLE(track->db_z_info)) {
+		r = evergreen_cs_track_validate_htile(p, surf.nbx, surf.nby);
+		if (r) {
+			return r;
+		}
+	}
+
+	return 0;
+}
+
+static int evergreen_cs_track_validate_texture(struct radeon_cs_parser *p,
+					       struct radeon_bo *texture,
+					       struct radeon_bo *mipmap,
+					       unsigned idx)
+{
+	struct eg_surface surf;
+	unsigned long toffset, moffset;
+	unsigned dim, llevel, mslice, width, height, depth, i;
+	u32 texdw[8];
+	int r;
+
+	texdw[0] = radeon_get_ib_value(p, idx + 0);
+	texdw[1] = radeon_get_ib_value(p, idx + 1);
+	texdw[2] = radeon_get_ib_value(p, idx + 2);
+	texdw[3] = radeon_get_ib_value(p, idx + 3);
+	texdw[4] = radeon_get_ib_value(p, idx + 4);
+	texdw[5] = radeon_get_ib_value(p, idx + 5);
+	texdw[6] = radeon_get_ib_value(p, idx + 6);
+	texdw[7] = radeon_get_ib_value(p, idx + 7);
+	dim = G_030000_DIM(texdw[0]);
+	llevel = G_030014_LAST_LEVEL(texdw[5]);
+	mslice = G_030014_LAST_ARRAY(texdw[5]) + 1;
+	width = G_030000_TEX_WIDTH(texdw[0]) + 1;
+	height =  G_030004_TEX_HEIGHT(texdw[1]) + 1;
+	depth = G_030004_TEX_DEPTH(texdw[1]) + 1;
+	surf.format = G_03001C_DATA_FORMAT(texdw[7]);
+	surf.nbx = (G_030000_PITCH(texdw[0]) + 1) * 8;
+	surf.nbx = r600_fmt_get_nblocksx(surf.format, surf.nbx);
+	surf.nby = r600_fmt_get_nblocksy(surf.format, height);
+	surf.mode = G_030004_ARRAY_MODE(texdw[1]);
+	surf.tsplit = G_030018_TILE_SPLIT(texdw[6]);
+	surf.nbanks = G_03001C_NUM_BANKS(texdw[7]);
+	surf.bankw = G_03001C_BANK_WIDTH(texdw[7]);
+	surf.bankh = G_03001C_BANK_HEIGHT(texdw[7]);
+	surf.mtilea = G_03001C_MACRO_TILE_ASPECT(texdw[7]);
+	surf.nsamples = 1;
+	toffset = texdw[2] << 8;
+	moffset = texdw[3] << 8;
+
+	if (!r600_fmt_is_valid_texture(surf.format, p->family)) {
+		dev_warn(p->dev, "%s:%d texture invalid format %d\n",
+			 __func__, __LINE__, surf.format);
+		return -EINVAL;
+	}
+	switch (dim) {
+	case V_030000_SQ_TEX_DIM_1D:
+	case V_030000_SQ_TEX_DIM_2D:
+	case V_030000_SQ_TEX_DIM_CUBEMAP:
+	case V_030000_SQ_TEX_DIM_1D_ARRAY:
+	case V_030000_SQ_TEX_DIM_2D_ARRAY:
+		depth = 1;
+	case V_030000_SQ_TEX_DIM_3D:
+		break;
+	default:
+		dev_warn(p->dev, "%s:%d texture invalid dimension %d\n",
+			 __func__, __LINE__, dim);
+		return -EINVAL;
+	}
+
+	r = evergreen_surface_value_conv_check(p, &surf, "texture");
+	if (r) {
+		return r;
+	}
+
+	/* align height */
+	evergreen_surface_check(p, &surf, NULL);
+	surf.nby = ALIGN(surf.nby, surf.halign);
+
+	r = evergreen_surface_check(p, &surf, "texture");
+	if (r) {
+		dev_warn(p->dev, "%s:%d texture invalid 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+			 __func__, __LINE__, texdw[0], texdw[1], texdw[4],
+			 texdw[5], texdw[6], texdw[7]);
+		return r;
+	}
+
+	/* check texture size */
+	if (toffset & (surf.base_align - 1)) {
+		dev_warn(p->dev, "%s:%d texture bo base %ld not aligned with %ld\n",
+			 __func__, __LINE__, toffset, surf.base_align);
+		return -EINVAL;
+	}
+	if (moffset & (surf.base_align - 1)) {
+		dev_warn(p->dev, "%s:%d mipmap bo base %ld not aligned with %ld\n",
+			 __func__, __LINE__, moffset, surf.base_align);
+		return -EINVAL;
+	}
+	if (dim == SQ_TEX_DIM_3D) {
+		toffset += surf.layer_size * depth;
+	} else {
+		toffset += surf.layer_size * mslice;
+	}
+	if (toffset > radeon_bo_size(texture)) {
+		dev_warn(p->dev, "%s:%d texture bo too small (layer size %d, "
+			 "offset %ld, max layer %d, depth %d, bo size %ld) (%d %d)\n",
+			 __func__, __LINE__, surf.layer_size,
+			(unsigned long)texdw[2] << 8, mslice,
+			depth, radeon_bo_size(texture),
+			surf.nbx, surf.nby);
+		return -EINVAL;
+	}
+
+	/* check mipmap size */
+	for (i = 1; i <= llevel; i++) {
+		unsigned w, h, d;
+
+		w = r600_mip_minify(width, i);
+		h = r600_mip_minify(height, i);
+		d = r600_mip_minify(depth, i);
+		surf.nbx = r600_fmt_get_nblocksx(surf.format, w);
+		surf.nby = r600_fmt_get_nblocksy(surf.format, h);
+
+		switch (surf.mode) {
+		case ARRAY_2D_TILED_THIN1:
+			if (surf.nbx < surf.palign || surf.nby < surf.halign) {
+				surf.mode = ARRAY_1D_TILED_THIN1;
+			}
+			/* recompute alignment */
+			evergreen_surface_check(p, &surf, NULL);
+			break;
+		case ARRAY_LINEAR_GENERAL:
+		case ARRAY_LINEAR_ALIGNED:
+		case ARRAY_1D_TILED_THIN1:
+			break;
+		default:
+			dev_warn(p->dev, "%s:%d invalid array mode %d\n",
+				 __func__, __LINE__, surf.mode);
+			return -EINVAL;
+		}
+		surf.nbx = ALIGN(surf.nbx, surf.palign);
+		surf.nby = ALIGN(surf.nby, surf.halign);
+
+		r = evergreen_surface_check(p, &surf, "mipmap");
+		if (r) {
+			return r;
+		}
+
+		if (dim == SQ_TEX_DIM_3D) {
+			moffset += surf.layer_size * d;
+		} else {
+			moffset += surf.layer_size * mslice;
+		}
+		if (moffset > radeon_bo_size(mipmap)) {
+			dev_warn(p->dev, "%s:%d mipmap [%d] bo too small (layer size %d, "
+					"offset %ld, coffset %ld, max layer %d, depth %d, "
+					"bo size %ld) level0 (%d %d %d)\n",
+					__func__, __LINE__, i, surf.layer_size,
+					(unsigned long)texdw[3] << 8, moffset, mslice,
+					d, radeon_bo_size(mipmap),
+					width, height, depth);
+			dev_warn(p->dev, "%s:%d problematic surf: (%d %d) (%d %d %d %d %d %d %d)\n",
+				 __func__, __LINE__, surf.nbx, surf.nby,
+				surf.mode, surf.bpe, surf.nsamples,
+				surf.bankw, surf.bankh,
+				surf.tsplit, surf.mtilea);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
 }
 
 static int evergreen_cs_track_check(struct radeon_cs_parser *p)
 {
 	struct evergreen_cs_track *track = p->track;
+	unsigned tmp, i;
+	int r;
+	unsigned buffer_mask = 0;
 
-	/* we don't support stream out buffer yet */
-	if (track->vgt_strmout_config || track->vgt_strmout_buffer_config) {
-		dev_warn(p->dev, "this kernel doesn't support SMX output buffer\n");
-		return -EINVAL;
+	/* check streamout */
+	if (track->streamout_dirty && track->vgt_strmout_config) {
+		for (i = 0; i < 4; i++) {
+			if (track->vgt_strmout_config & (1 << i)) {
+				buffer_mask |= (track->vgt_strmout_buffer_config >> (i * 4)) & 0xf;
+			}
+		}
+
+		for (i = 0; i < 4; i++) {
+			if (buffer_mask & (1 << i)) {
+				if (track->vgt_strmout_bo[i]) {
+					u64 offset = (u64)track->vgt_strmout_bo_offset[i] +
+							(u64)track->vgt_strmout_size[i];
+					if (offset > radeon_bo_size(track->vgt_strmout_bo[i])) {
+						DRM_ERROR("streamout %d bo too small: 0x%llx, 0x%lx\n",
+							  i, offset,
+							  radeon_bo_size(track->vgt_strmout_bo[i]));
+						return -EINVAL;
+					}
+				} else {
+					dev_warn(p->dev, "No buffer for streamout %d\n", i);
+					return -EINVAL;
+				}
+			}
+		}
+		track->streamout_dirty = false;
 	}
 
-	/* XXX fill in */
+	if (track->sx_misc_kill_all_prims)
+		return 0;
+
+	/* check that we have a cb for each enabled target
+	 */
+	if (track->cb_dirty) {
+		tmp = track->cb_target_mask;
+		for (i = 0; i < 8; i++) {
+			if ((tmp >> (i * 4)) & 0xF) {
+				/* at least one component is enabled */
+				if (track->cb_color_bo[i] == NULL) {
+					dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n",
+						__func__, __LINE__, track->cb_target_mask, track->cb_shader_mask, i);
+					return -EINVAL;
+				}
+				/* check cb */
+				r = evergreen_cs_track_validate_cb(p, i);
+				if (r) {
+					return r;
+				}
+			}
+		}
+		track->cb_dirty = false;
+	}
+
+	if (track->db_dirty) {
+		/* Check stencil buffer */
+		if (G_028800_STENCIL_ENABLE(track->db_depth_control)) {
+			r = evergreen_cs_track_validate_stencil(p);
+			if (r)
+				return r;
+		}
+		/* Check depth buffer */
+		if (G_028800_Z_ENABLE(track->db_depth_control)) {
+			r = evergreen_cs_track_validate_depth(p);
+			if (r)
+				return r;
+		}
+		track->db_dirty = false;
+	}
+
 	return 0;
 }
 
@@ -503,6 +1267,7 @@
 		break;
 	case DB_DEPTH_CONTROL:
 		track->db_depth_control = radeon_get_ib_value(p, idx);
+		track->db_dirty = true;
 		break;
 	case CAYMAN_DB_EQAA:
 		if (p->rdev->family < CHIP_CAYMAN) {
@@ -532,20 +1297,35 @@
 			ib[idx] |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
 			track->db_z_info |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
 			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+				unsigned bankw, bankh, mtaspect, tile_split;
+
+				evergreen_tiling_fields(reloc->lobj.tiling_flags,
+							&bankw, &bankh, &mtaspect,
+							&tile_split);
 				ib[idx] |= DB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
-				ib[idx] |= DB_TILE_SPLIT(evergreen_cs_get_tile_split(track->row_size));
+				ib[idx] |= DB_TILE_SPLIT(tile_split) |
+						DB_BANK_WIDTH(bankw) |
+						DB_BANK_HEIGHT(bankh) |
+						DB_MACRO_TILE_ASPECT(mtaspect);
 			}
 		}
+		track->db_dirty = true;
 		break;
 	case DB_STENCIL_INFO:
 		track->db_s_info = radeon_get_ib_value(p, idx);
+		track->db_dirty = true;
 		break;
 	case DB_DEPTH_VIEW:
 		track->db_depth_view = radeon_get_ib_value(p, idx);
+		track->db_dirty = true;
 		break;
 	case DB_DEPTH_SIZE:
 		track->db_depth_size = radeon_get_ib_value(p, idx);
-		track->db_depth_size_idx = idx;
+		track->db_dirty = true;
+		break;
+	case R_02805C_DB_DEPTH_SLICE:
+		track->db_depth_slice = radeon_get_ib_value(p, idx);
+		track->db_dirty = true;
 		break;
 	case DB_Z_READ_BASE:
 		r = evergreen_cs_packet_next_reloc(p, &reloc);
@@ -557,6 +1337,7 @@
 		track->db_z_read_offset = radeon_get_ib_value(p, idx);
 		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 		track->db_z_read_bo = reloc->robj;
+		track->db_dirty = true;
 		break;
 	case DB_Z_WRITE_BASE:
 		r = evergreen_cs_packet_next_reloc(p, &reloc);
@@ -568,6 +1349,7 @@
 		track->db_z_write_offset = radeon_get_ib_value(p, idx);
 		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 		track->db_z_write_bo = reloc->robj;
+		track->db_dirty = true;
 		break;
 	case DB_STENCIL_READ_BASE:
 		r = evergreen_cs_packet_next_reloc(p, &reloc);
@@ -579,6 +1361,7 @@
 		track->db_s_read_offset = radeon_get_ib_value(p, idx);
 		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 		track->db_s_read_bo = reloc->robj;
+		track->db_dirty = true;
 		break;
 	case DB_STENCIL_WRITE_BASE:
 		r = evergreen_cs_packet_next_reloc(p, &reloc);
@@ -590,18 +1373,56 @@
 		track->db_s_write_offset = radeon_get_ib_value(p, idx);
 		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 		track->db_s_write_bo = reloc->robj;
+		track->db_dirty = true;
 		break;
 	case VGT_STRMOUT_CONFIG:
 		track->vgt_strmout_config = radeon_get_ib_value(p, idx);
+		track->streamout_dirty = true;
 		break;
 	case VGT_STRMOUT_BUFFER_CONFIG:
 		track->vgt_strmout_buffer_config = radeon_get_ib_value(p, idx);
+		track->streamout_dirty = true;
 		break;
+	case VGT_STRMOUT_BUFFER_BASE_0:
+	case VGT_STRMOUT_BUFFER_BASE_1:
+	case VGT_STRMOUT_BUFFER_BASE_2:
+	case VGT_STRMOUT_BUFFER_BASE_3:
+		r = evergreen_cs_packet_next_reloc(p, &reloc);
+		if (r) {
+			dev_warn(p->dev, "bad SET_CONTEXT_REG "
+					"0x%04X\n", reg);
+			return -EINVAL;
+		}
+		tmp = (reg - VGT_STRMOUT_BUFFER_BASE_0) / 16;
+		track->vgt_strmout_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8;
+		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+		track->vgt_strmout_bo[tmp] = reloc->robj;
+		track->streamout_dirty = true;
+		break;
+	case VGT_STRMOUT_BUFFER_SIZE_0:
+	case VGT_STRMOUT_BUFFER_SIZE_1:
+	case VGT_STRMOUT_BUFFER_SIZE_2:
+	case VGT_STRMOUT_BUFFER_SIZE_3:
+		tmp = (reg - VGT_STRMOUT_BUFFER_SIZE_0) / 16;
+		/* size in register is DWs, convert to bytes */
+		track->vgt_strmout_size[tmp] = radeon_get_ib_value(p, idx) * 4;
+		track->streamout_dirty = true;
+		break;
+	case CP_COHER_BASE:
+		r = evergreen_cs_packet_next_reloc(p, &reloc);
+		if (r) {
+			dev_warn(p->dev, "missing reloc for CP_COHER_BASE "
+					"0x%04X\n", reg);
+			return -EINVAL;
+		}
+		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 	case CB_TARGET_MASK:
 		track->cb_target_mask = radeon_get_ib_value(p, idx);
+		track->cb_dirty = true;
 		break;
 	case CB_SHADER_MASK:
 		track->cb_shader_mask = radeon_get_ib_value(p, idx);
+		track->cb_dirty = true;
 		break;
 	case PA_SC_AA_CONFIG:
 		if (p->rdev->family >= CHIP_CAYMAN) {
@@ -631,6 +1452,7 @@
 	case CB_COLOR7_VIEW:
 		tmp = (reg - CB_COLOR0_VIEW) / 0x3c;
 		track->cb_color_view[tmp] = radeon_get_ib_value(p, idx);
+		track->cb_dirty = true;
 		break;
 	case CB_COLOR8_VIEW:
 	case CB_COLOR9_VIEW:
@@ -638,6 +1460,7 @@
 	case CB_COLOR11_VIEW:
 		tmp = ((reg - CB_COLOR8_VIEW) / 0x1c) + 8;
 		track->cb_color_view[tmp] = radeon_get_ib_value(p, idx);
+		track->cb_dirty = true;
 		break;
 	case CB_COLOR0_INFO:
 	case CB_COLOR1_INFO:
@@ -659,6 +1482,7 @@
 			ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
 			track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
 		}
+		track->cb_dirty = true;
 		break;
 	case CB_COLOR8_INFO:
 	case CB_COLOR9_INFO:
@@ -676,6 +1500,7 @@
 			ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
 			track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
 		}
+		track->cb_dirty = true;
 		break;
 	case CB_COLOR0_PITCH:
 	case CB_COLOR1_PITCH:
@@ -687,7 +1512,7 @@
 	case CB_COLOR7_PITCH:
 		tmp = (reg - CB_COLOR0_PITCH) / 0x3c;
 		track->cb_color_pitch[tmp] = radeon_get_ib_value(p, idx);
-		track->cb_color_pitch_idx[tmp] = idx;
+		track->cb_dirty = true;
 		break;
 	case CB_COLOR8_PITCH:
 	case CB_COLOR9_PITCH:
@@ -695,7 +1520,7 @@
 	case CB_COLOR11_PITCH:
 		tmp = ((reg - CB_COLOR8_PITCH) / 0x1c) + 8;
 		track->cb_color_pitch[tmp] = radeon_get_ib_value(p, idx);
-		track->cb_color_pitch_idx[tmp] = idx;
+		track->cb_dirty = true;
 		break;
 	case CB_COLOR0_SLICE:
 	case CB_COLOR1_SLICE:
@@ -707,7 +1532,7 @@
 	case CB_COLOR7_SLICE:
 		tmp = (reg - CB_COLOR0_SLICE) / 0x3c;
 		track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx);
-		track->cb_color_slice_idx[tmp] = idx;
+		track->cb_dirty = true;
 		break;
 	case CB_COLOR8_SLICE:
 	case CB_COLOR9_SLICE:
@@ -715,7 +1540,7 @@
 	case CB_COLOR11_SLICE:
 		tmp = ((reg - CB_COLOR8_SLICE) / 0x1c) + 8;
 		track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx);
-		track->cb_color_slice_idx[tmp] = idx;
+		track->cb_dirty = true;
 		break;
 	case CB_COLOR0_ATTRIB:
 	case CB_COLOR1_ATTRIB:
@@ -725,6 +1550,30 @@
 	case CB_COLOR5_ATTRIB:
 	case CB_COLOR6_ATTRIB:
 	case CB_COLOR7_ATTRIB:
+		r = evergreen_cs_packet_next_reloc(p, &reloc);
+		if (r) {
+			dev_warn(p->dev, "bad SET_CONTEXT_REG "
+					"0x%04X\n", reg);
+			return -EINVAL;
+		}
+		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
+			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+				unsigned bankw, bankh, mtaspect, tile_split;
+
+				evergreen_tiling_fields(reloc->lobj.tiling_flags,
+							&bankw, &bankh, &mtaspect,
+							&tile_split);
+				ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
+				ib[idx] |= CB_TILE_SPLIT(tile_split) |
+					   CB_BANK_WIDTH(bankw) |
+					   CB_BANK_HEIGHT(bankh) |
+					   CB_MACRO_TILE_ASPECT(mtaspect);
+			}
+		}
+		tmp = ((reg - CB_COLOR0_ATTRIB) / 0x3c);
+		track->cb_color_attrib[tmp] = ib[idx];
+		track->cb_dirty = true;
+		break;
 	case CB_COLOR8_ATTRIB:
 	case CB_COLOR9_ATTRIB:
 	case CB_COLOR10_ATTRIB:
@@ -735,30 +1584,23 @@
 					"0x%04X\n", reg);
 			return -EINVAL;
 		}
-		if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
-			ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
-			ib[idx] |= CB_TILE_SPLIT(evergreen_cs_get_tile_split(track->row_size));
+		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
+			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+				unsigned bankw, bankh, mtaspect, tile_split;
+
+				evergreen_tiling_fields(reloc->lobj.tiling_flags,
+							&bankw, &bankh, &mtaspect,
+							&tile_split);
+				ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
+				ib[idx] |= CB_TILE_SPLIT(tile_split) |
+					   CB_BANK_WIDTH(bankw) |
+					   CB_BANK_HEIGHT(bankh) |
+					   CB_MACRO_TILE_ASPECT(mtaspect);
+			}
 		}
-		break;
-	case CB_COLOR0_DIM:
-	case CB_COLOR1_DIM:
-	case CB_COLOR2_DIM:
-	case CB_COLOR3_DIM:
-	case CB_COLOR4_DIM:
-	case CB_COLOR5_DIM:
-	case CB_COLOR6_DIM:
-	case CB_COLOR7_DIM:
-		tmp = (reg - CB_COLOR0_DIM) / 0x3c;
-		track->cb_color_dim[tmp] = radeon_get_ib_value(p, idx);
-		track->cb_color_dim_idx[tmp] = idx;
-		break;
-	case CB_COLOR8_DIM:
-	case CB_COLOR9_DIM:
-	case CB_COLOR10_DIM:
-	case CB_COLOR11_DIM:
-		tmp = ((reg - CB_COLOR8_DIM) / 0x1c) + 8;
-		track->cb_color_dim[tmp] = radeon_get_ib_value(p, idx);
-		track->cb_color_dim_idx[tmp] = idx;
+		tmp = ((reg - CB_COLOR8_ATTRIB) / 0x1c) + 8;
+		track->cb_color_attrib[tmp] = ib[idx];
+		track->cb_dirty = true;
 		break;
 	case CB_COLOR0_FMASK:
 	case CB_COLOR1_FMASK:
@@ -833,8 +1675,8 @@
 		tmp = (reg - CB_COLOR0_BASE) / 0x3c;
 		track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx);
 		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
-		track->cb_color_base_last[tmp] = ib[idx];
 		track->cb_color_bo[tmp] = reloc->robj;
+		track->cb_dirty = true;
 		break;
 	case CB_COLOR8_BASE:
 	case CB_COLOR9_BASE:
@@ -849,8 +1691,25 @@
 		tmp = ((reg - CB_COLOR8_BASE) / 0x1c) + 8;
 		track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx);
 		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
-		track->cb_color_base_last[tmp] = ib[idx];
 		track->cb_color_bo[tmp] = reloc->robj;
+		track->cb_dirty = true;
+		break;
+	case DB_HTILE_DATA_BASE:
+		r = evergreen_cs_packet_next_reloc(p, &reloc);
+		if (r) {
+			dev_warn(p->dev, "bad SET_CONTEXT_REG "
+					"0x%04X\n", reg);
+			return -EINVAL;
+		}
+		track->htile_offset = radeon_get_ib_value(p, idx);
+		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+		track->htile_bo = reloc->robj;
+		track->db_dirty = true;
+		break;
+	case DB_HTILE_SURFACE:
+		/* 8x8 only */
+		track->htile_surface = radeon_get_ib_value(p, idx);
+		track->db_dirty = true;
 		break;
 	case CB_IMMED0_BASE:
 	case CB_IMMED1_BASE:
@@ -864,7 +1723,6 @@
 	case CB_IMMED9_BASE:
 	case CB_IMMED10_BASE:
 	case CB_IMMED11_BASE:
-	case DB_HTILE_DATA_BASE:
 	case SQ_PGM_START_FS:
 	case SQ_PGM_START_ES:
 	case SQ_PGM_START_VS:
@@ -989,6 +1847,9 @@
 		}
 		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 		break;
+	case SX_MISC:
+		track->sx_misc_kill_all_prims = (radeon_get_ib_value(p, idx) & 0x1) != 0;
+		break;
 	default:
 		dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
 		return -EINVAL;
@@ -996,22 +1857,30 @@
 	return 0;
 }
 
-/**
- * evergreen_check_texture_resource() - check if register is authorized or not
- * @p: parser structure holding parsing context
- * @idx: index into the cs buffer
- * @texture: texture's bo structure
- * @mipmap: mipmap's bo structure
- *
- * This function will check that the resource has valid field and that
- * the texture and mipmap bo object are big enough to cover this resource.
- */
-static int evergreen_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,
-						   struct radeon_bo *texture,
-						   struct radeon_bo *mipmap)
+static bool evergreen_is_safe_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
 {
-	/* XXX fill in */
-	return 0;
+	u32 last_reg, m, i;
+
+	if (p->rdev->family >= CHIP_CAYMAN)
+		last_reg = ARRAY_SIZE(cayman_reg_safe_bm);
+	else
+		last_reg = ARRAY_SIZE(evergreen_reg_safe_bm);
+
+	i = (reg >> 7);
+	if (i >= last_reg) {
+		dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
+		return false;
+	}
+	m = 1 << ((reg >> 2) & 31);
+	if (p->rdev->family >= CHIP_CAYMAN) {
+		if (!(cayman_reg_safe_bm[i] & m))
+			return true;
+	} else {
+		if (!(evergreen_reg_safe_bm[i] & m))
+			return true;
+	}
+	dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
+	return false;
 }
 
 static int evergreen_packet3_check(struct radeon_cs_parser *p,
@@ -1036,6 +1905,8 @@
 	{
 		int pred_op;
 		int tmp;
+		uint64_t offset;
+
 		if (pkt->count != 1) {
 			DRM_ERROR("bad SET PREDICATION\n");
 			return -EINVAL;
@@ -1059,8 +1930,12 @@
 			return -EINVAL;
 		}
 
-		ib[idx + 0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff);
-		ib[idx + 1] = tmp + (upper_32_bits(reloc->lobj.gpu_offset) & 0xff);
+		offset = reloc->lobj.gpu_offset +
+		         (idx_value & 0xfffffff0) +
+		         ((u64)(tmp & 0xff) << 32);
+
+		ib[idx + 0] = offset;
+		ib[idx + 1] = (tmp & 0xffffff00) | (upper_32_bits(offset) & 0xff);
 	}
 	break;
 	case PACKET3_CONTEXT_CONTROL:
@@ -1088,6 +1963,9 @@
 		}
 		break;
 	case PACKET3_INDEX_BASE:
+	{
+		uint64_t offset;
+
 		if (pkt->count != 1) {
 			DRM_ERROR("bad INDEX_BASE\n");
 			return -EINVAL;
@@ -1097,15 +1975,24 @@
 			DRM_ERROR("bad INDEX_BASE\n");
 			return -EINVAL;
 		}
-		ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff);
-		ib[idx+1] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+
+		offset = reloc->lobj.gpu_offset +
+		         idx_value +
+		         ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32);
+
+		ib[idx+0] = offset;
+		ib[idx+1] = upper_32_bits(offset) & 0xff;
+
 		r = evergreen_cs_track_check(p);
 		if (r) {
 			dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
 			return r;
 		}
 		break;
+	}
 	case PACKET3_DRAW_INDEX:
+	{
+		uint64_t offset;
 		if (pkt->count != 3) {
 			DRM_ERROR("bad DRAW_INDEX\n");
 			return -EINVAL;
@@ -1115,15 +2002,25 @@
 			DRM_ERROR("bad DRAW_INDEX\n");
 			return -EINVAL;
 		}
-		ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff);
-		ib[idx+1] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+
+		offset = reloc->lobj.gpu_offset +
+		         idx_value +
+		         ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32);
+
+		ib[idx+0] = offset;
+		ib[idx+1] = upper_32_bits(offset) & 0xff;
+
 		r = evergreen_cs_track_check(p);
 		if (r) {
 			dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
 			return r;
 		}
 		break;
+	}
 	case PACKET3_DRAW_INDEX_2:
+	{
+		uint64_t offset;
+
 		if (pkt->count != 4) {
 			DRM_ERROR("bad DRAW_INDEX_2\n");
 			return -EINVAL;
@@ -1133,14 +2030,21 @@
 			DRM_ERROR("bad DRAW_INDEX_2\n");
 			return -EINVAL;
 		}
-		ib[idx+1] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff);
-		ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+
+		offset = reloc->lobj.gpu_offset +
+		         radeon_get_ib_value(p, idx+1) +
+		         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
+
+		ib[idx+1] = offset;
+		ib[idx+2] = upper_32_bits(offset) & 0xff;
+
 		r = evergreen_cs_track_check(p);
 		if (r) {
 			dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
 			return r;
 		}
 		break;
+	}
 	case PACKET3_DRAW_INDEX_AUTO:
 		if (pkt->count != 1) {
 			DRM_ERROR("bad DRAW_INDEX_AUTO\n");
@@ -1231,13 +2135,20 @@
 		}
 		/* bit 4 is reg (0) or mem (1) */
 		if (idx_value & 0x10) {
+			uint64_t offset;
+
 			r = evergreen_cs_packet_next_reloc(p, &reloc);
 			if (r) {
 				DRM_ERROR("bad WAIT_REG_MEM\n");
 				return -EINVAL;
 			}
-			ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
-			ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+
+			offset = reloc->lobj.gpu_offset +
+			         (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +
+			         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
+
+			ib[idx+1] = (ib[idx+1] & 0x3) | (offset & 0xfffffffc);
+			ib[idx+2] = upper_32_bits(offset) & 0xff;
 		}
 		break;
 	case PACKET3_SURFACE_SYNC:
@@ -1262,16 +2173,25 @@
 			return -EINVAL;
 		}
 		if (pkt->count) {
+			uint64_t offset;
+
 			r = evergreen_cs_packet_next_reloc(p, &reloc);
 			if (r) {
 				DRM_ERROR("bad EVENT_WRITE\n");
 				return -EINVAL;
 			}
-			ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
-			ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+			offset = reloc->lobj.gpu_offset +
+			         (radeon_get_ib_value(p, idx+1) & 0xfffffff8) +
+			         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
+
+			ib[idx+1] = offset & 0xfffffff8;
+			ib[idx+2] = upper_32_bits(offset) & 0xff;
 		}
 		break;
 	case PACKET3_EVENT_WRITE_EOP:
+	{
+		uint64_t offset;
+
 		if (pkt->count != 4) {
 			DRM_ERROR("bad EVENT_WRITE_EOP\n");
 			return -EINVAL;
@@ -1281,10 +2201,19 @@
 			DRM_ERROR("bad EVENT_WRITE_EOP\n");
 			return -EINVAL;
 		}
-		ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
-		ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+
+		offset = reloc->lobj.gpu_offset +
+		         (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +
+		         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
+
+		ib[idx+1] = offset & 0xfffffffc;
+		ib[idx+2] = (ib[idx+2] & 0xffffff00) | (upper_32_bits(offset) & 0xff);
 		break;
+	}
 	case PACKET3_EVENT_WRITE_EOS:
+	{
+		uint64_t offset;
+
 		if (pkt->count != 3) {
 			DRM_ERROR("bad EVENT_WRITE_EOS\n");
 			return -EINVAL;
@@ -1294,9 +2223,15 @@
 			DRM_ERROR("bad EVENT_WRITE_EOS\n");
 			return -EINVAL;
 		}
-		ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
-		ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+
+		offset = reloc->lobj.gpu_offset +
+		         (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +
+		         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
+
+		ib[idx+1] = offset & 0xfffffffc;
+		ib[idx+2] = (ib[idx+2] & 0xffffff00) | (upper_32_bits(offset) & 0xff);
 		break;
+	}
 	case PACKET3_SET_CONFIG_REG:
 		start_reg = (idx_value << 2) + PACKET3_SET_CONFIG_REG_START;
 		end_reg = 4 * pkt->count + start_reg - 4;
@@ -1344,6 +2279,7 @@
 		}
 		for (i = 0; i < (pkt->count / 8); i++) {
 			struct radeon_bo *texture, *mipmap;
+			u32 toffset, moffset;
 			u32 size, offset;
 
 			switch (G__SQ_CONSTANT_TYPE(radeon_get_ib_value(p, idx+1+(i*8)+7))) {
@@ -1354,32 +2290,42 @@
 					DRM_ERROR("bad SET_RESOURCE (tex)\n");
 					return -EINVAL;
 				}
-				ib[idx+1+(i*8)+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 				if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
 					ib[idx+1+(i*8)+1] |=
 						TEX_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
 					if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
-						ib[idx+1+(i*8)+6] |=
-							TEX_TILE_SPLIT(evergreen_cs_get_tile_split(track->row_size));
+						unsigned bankw, bankh, mtaspect, tile_split;
+
+						evergreen_tiling_fields(reloc->lobj.tiling_flags,
+									&bankw, &bankh, &mtaspect,
+									&tile_split);
+						ib[idx+1+(i*8)+6] |= TEX_TILE_SPLIT(tile_split);
 						ib[idx+1+(i*8)+7] |=
+							TEX_BANK_WIDTH(bankw) |
+							TEX_BANK_HEIGHT(bankh) |
+							MACRO_TILE_ASPECT(mtaspect) |
 							TEX_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
 					}
 				}
 				texture = reloc->robj;
+				toffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 				/* tex mip base */
 				r = evergreen_cs_packet_next_reloc(p, &reloc);
 				if (r) {
 					DRM_ERROR("bad SET_RESOURCE (tex)\n");
 					return -EINVAL;
 				}
-				ib[idx+1+(i*8)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+				moffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 				mipmap = reloc->robj;
-				r = evergreen_check_texture_resource(p,  idx+1+(i*8),
-						texture, mipmap);
+				r = evergreen_cs_track_validate_texture(p, texture, mipmap, idx+1+(i*8));
 				if (r)
 					return r;
+				ib[idx+1+(i*8)+2] += toffset;
+				ib[idx+1+(i*8)+3] += moffset;
 				break;
 			case SQ_TEX_VTX_VALID_BUFFER:
+			{
+				uint64_t offset64;
 				/* vtx base */
 				r = evergreen_cs_packet_next_reloc(p, &reloc);
 				if (r) {
@@ -1391,11 +2337,15 @@
 				if (p->rdev && (size + offset) > radeon_bo_size(reloc->robj)) {
 					/* force size to size of the buffer */
 					dev_warn(p->dev, "vbo resource seems too big for the bo\n");
-					ib[idx+1+(i*8)+1] = radeon_bo_size(reloc->robj);
+					ib[idx+1+(i*8)+1] = radeon_bo_size(reloc->robj) - offset;
 				}
-				ib[idx+1+(i*8)+0] += (u32)((reloc->lobj.gpu_offset) & 0xffffffff);
-				ib[idx+1+(i*8)+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+
+				offset64 = reloc->lobj.gpu_offset + offset;
+				ib[idx+1+(i*8)+0] = offset64;
+				ib[idx+1+(i*8)+2] = (ib[idx+1+(i*8)+2] & 0xffffff00) |
+						    (upper_32_bits(offset64) & 0xff);
 				break;
+			}
 			case SQ_TEX_VTX_INVALID_TEXTURE:
 			case SQ_TEX_VTX_INVALID_BUFFER:
 			default:
@@ -1451,6 +2401,104 @@
 			return -EINVAL;
 		}
 		break;
+	case PACKET3_STRMOUT_BUFFER_UPDATE:
+		if (pkt->count != 4) {
+			DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (invalid count)\n");
+			return -EINVAL;
+		}
+		/* Updating memory at DST_ADDRESS. */
+		if (idx_value & 0x1) {
+			u64 offset;
+			r = evergreen_cs_packet_next_reloc(p, &reloc);
+			if (r) {
+				DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing dst reloc)\n");
+				return -EINVAL;
+			}
+			offset = radeon_get_ib_value(p, idx+1);
+			offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
+			if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+				DRM_ERROR("bad STRMOUT_BUFFER_UPDATE dst bo too small: 0x%llx, 0x%lx\n",
+					  offset + 4, radeon_bo_size(reloc->robj));
+				return -EINVAL;
+			}
+			offset += reloc->lobj.gpu_offset;
+			ib[idx+1] = offset;
+			ib[idx+2] = upper_32_bits(offset) & 0xff;
+		}
+		/* Reading data from SRC_ADDRESS. */
+		if (((idx_value >> 1) & 0x3) == 2) {
+			u64 offset;
+			r = evergreen_cs_packet_next_reloc(p, &reloc);
+			if (r) {
+				DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing src reloc)\n");
+				return -EINVAL;
+			}
+			offset = radeon_get_ib_value(p, idx+3);
+			offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+			if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+				DRM_ERROR("bad STRMOUT_BUFFER_UPDATE src bo too small: 0x%llx, 0x%lx\n",
+					  offset + 4, radeon_bo_size(reloc->robj));
+				return -EINVAL;
+			}
+			offset += reloc->lobj.gpu_offset;
+			ib[idx+3] = offset;
+			ib[idx+4] = upper_32_bits(offset) & 0xff;
+		}
+		break;
+	case PACKET3_COPY_DW:
+		if (pkt->count != 4) {
+			DRM_ERROR("bad COPY_DW (invalid count)\n");
+			return -EINVAL;
+		}
+		if (idx_value & 0x1) {
+			u64 offset;
+			/* SRC is memory. */
+			r = evergreen_cs_packet_next_reloc(p, &reloc);
+			if (r) {
+				DRM_ERROR("bad COPY_DW (missing src reloc)\n");
+				return -EINVAL;
+			}
+			offset = radeon_get_ib_value(p, idx+1);
+			offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
+			if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+				DRM_ERROR("bad COPY_DW src bo too small: 0x%llx, 0x%lx\n",
+					  offset + 4, radeon_bo_size(reloc->robj));
+				return -EINVAL;
+			}
+			offset += reloc->lobj.gpu_offset;
+			ib[idx+1] = offset;
+			ib[idx+2] = upper_32_bits(offset) & 0xff;
+		} else {
+			/* SRC is a reg. */
+			reg = radeon_get_ib_value(p, idx+1) << 2;
+			if (!evergreen_is_safe_reg(p, reg, idx+1))
+				return -EINVAL;
+		}
+		if (idx_value & 0x2) {
+			u64 offset;
+			/* DST is memory. */
+			r = evergreen_cs_packet_next_reloc(p, &reloc);
+			if (r) {
+				DRM_ERROR("bad COPY_DW (missing dst reloc)\n");
+				return -EINVAL;
+			}
+			offset = radeon_get_ib_value(p, idx+3);
+			offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+			if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+				DRM_ERROR("bad COPY_DW dst bo too small: 0x%llx, 0x%lx\n",
+					  offset + 4, radeon_bo_size(reloc->robj));
+				return -EINVAL;
+			}
+			offset += reloc->lobj.gpu_offset;
+			ib[idx+3] = offset;
+			ib[idx+4] = upper_32_bits(offset) & 0xff;
+		} else {
+			/* DST is a reg. */
+			reg = radeon_get_ib_value(p, idx+3) << 2;
+			if (!evergreen_is_safe_reg(p, reg, idx+3))
+				return -EINVAL;
+		}
+		break;
 	case PACKET3_NOP:
 		break;
 	default:
diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h
index 4215de9..96c10b3 100644
--- a/drivers/gpu/drm/radeon/evergreen_reg.h
+++ b/drivers/gpu/drm/radeon/evergreen_reg.h
@@ -219,6 +219,7 @@
 #       define EVERGREEN_CRTC_MASTER_EN                 (1 << 0)
 #       define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24)
 #define EVERGREEN_CRTC_STATUS                           0x6e8c
+#       define EVERGREEN_CRTC_V_BLANK                   (1 << 0)
 #define EVERGREEN_CRTC_STATUS_POSITION                  0x6e90
 #define EVERGREEN_MASTER_UPDATE_MODE                    0x6ef8
 #define EVERGREEN_CRTC_UPDATE_LOCK                      0x6ed4
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index 74713d4..b4eefc3 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -77,6 +77,7 @@
 
 #define	CONFIG_MEMSIZE					0x5428
 
+#define	CP_COHER_BASE					0x85F8
 #define CP_ME_CNTL					0x86D8
 #define		CP_ME_HALT					(1 << 28)
 #define		CP_PFP_HALT					(1 << 26)
@@ -925,20 +926,138 @@
 #define DB_DEBUG4					0x983C
 #define DB_WATERMARKS					0x9854
 #define DB_DEPTH_CONTROL				0x28800
+#define R_028800_DB_DEPTH_CONTROL                    0x028800
+#define   S_028800_STENCIL_ENABLE(x)                   (((x) & 0x1) << 0)
+#define   G_028800_STENCIL_ENABLE(x)                   (((x) >> 0) & 0x1)
+#define   C_028800_STENCIL_ENABLE                      0xFFFFFFFE
+#define   S_028800_Z_ENABLE(x)                         (((x) & 0x1) << 1)
+#define   G_028800_Z_ENABLE(x)                         (((x) >> 1) & 0x1)
+#define   C_028800_Z_ENABLE                            0xFFFFFFFD
+#define   S_028800_Z_WRITE_ENABLE(x)                   (((x) & 0x1) << 2)
+#define   G_028800_Z_WRITE_ENABLE(x)                   (((x) >> 2) & 0x1)
+#define   C_028800_Z_WRITE_ENABLE                      0xFFFFFFFB
+#define   S_028800_ZFUNC(x)                            (((x) & 0x7) << 4)
+#define   G_028800_ZFUNC(x)                            (((x) >> 4) & 0x7)
+#define   C_028800_ZFUNC                               0xFFFFFF8F
+#define   S_028800_BACKFACE_ENABLE(x)                  (((x) & 0x1) << 7)
+#define   G_028800_BACKFACE_ENABLE(x)                  (((x) >> 7) & 0x1)
+#define   C_028800_BACKFACE_ENABLE                     0xFFFFFF7F
+#define   S_028800_STENCILFUNC(x)                      (((x) & 0x7) << 8)
+#define   G_028800_STENCILFUNC(x)                      (((x) >> 8) & 0x7)
+#define   C_028800_STENCILFUNC                         0xFFFFF8FF
+#define     V_028800_STENCILFUNC_NEVER                 0x00000000
+#define     V_028800_STENCILFUNC_LESS                  0x00000001
+#define     V_028800_STENCILFUNC_EQUAL                 0x00000002
+#define     V_028800_STENCILFUNC_LEQUAL                0x00000003
+#define     V_028800_STENCILFUNC_GREATER               0x00000004
+#define     V_028800_STENCILFUNC_NOTEQUAL              0x00000005
+#define     V_028800_STENCILFUNC_GEQUAL                0x00000006
+#define     V_028800_STENCILFUNC_ALWAYS                0x00000007
+#define   S_028800_STENCILFAIL(x)                      (((x) & 0x7) << 11)
+#define   G_028800_STENCILFAIL(x)                      (((x) >> 11) & 0x7)
+#define   C_028800_STENCILFAIL                         0xFFFFC7FF
+#define     V_028800_STENCIL_KEEP                      0x00000000
+#define     V_028800_STENCIL_ZERO                      0x00000001
+#define     V_028800_STENCIL_REPLACE                   0x00000002
+#define     V_028800_STENCIL_INCR                      0x00000003
+#define     V_028800_STENCIL_DECR                      0x00000004
+#define     V_028800_STENCIL_INVERT                    0x00000005
+#define     V_028800_STENCIL_INCR_WRAP                 0x00000006
+#define     V_028800_STENCIL_DECR_WRAP                 0x00000007
+#define   S_028800_STENCILZPASS(x)                     (((x) & 0x7) << 14)
+#define   G_028800_STENCILZPASS(x)                     (((x) >> 14) & 0x7)
+#define   C_028800_STENCILZPASS                        0xFFFE3FFF
+#define   S_028800_STENCILZFAIL(x)                     (((x) & 0x7) << 17)
+#define   G_028800_STENCILZFAIL(x)                     (((x) >> 17) & 0x7)
+#define   C_028800_STENCILZFAIL                        0xFFF1FFFF
+#define   S_028800_STENCILFUNC_BF(x)                   (((x) & 0x7) << 20)
+#define   G_028800_STENCILFUNC_BF(x)                   (((x) >> 20) & 0x7)
+#define   C_028800_STENCILFUNC_BF                      0xFF8FFFFF
+#define   S_028800_STENCILFAIL_BF(x)                   (((x) & 0x7) << 23)
+#define   G_028800_STENCILFAIL_BF(x)                   (((x) >> 23) & 0x7)
+#define   C_028800_STENCILFAIL_BF                      0xFC7FFFFF
+#define   S_028800_STENCILZPASS_BF(x)                  (((x) & 0x7) << 26)
+#define   G_028800_STENCILZPASS_BF(x)                  (((x) >> 26) & 0x7)
+#define   C_028800_STENCILZPASS_BF                     0xE3FFFFFF
+#define   S_028800_STENCILZFAIL_BF(x)                  (((x) & 0x7) << 29)
+#define   G_028800_STENCILZFAIL_BF(x)                  (((x) >> 29) & 0x7)
+#define   C_028800_STENCILZFAIL_BF                     0x1FFFFFFF
 #define DB_DEPTH_VIEW					0x28008
+#define R_028008_DB_DEPTH_VIEW                       0x00028008
+#define   S_028008_SLICE_START(x)                      (((x) & 0x7FF) << 0)
+#define   G_028008_SLICE_START(x)                      (((x) >> 0) & 0x7FF)
+#define   C_028008_SLICE_START                         0xFFFFF800
+#define   S_028008_SLICE_MAX(x)                        (((x) & 0x7FF) << 13)
+#define   G_028008_SLICE_MAX(x)                        (((x) >> 13) & 0x7FF)
+#define   C_028008_SLICE_MAX                           0xFF001FFF
 #define DB_HTILE_DATA_BASE				0x28014
+#define DB_HTILE_SURFACE				0x28abc
+#define   S_028ABC_HTILE_WIDTH(x)                      (((x) & 0x1) << 0)
+#define   G_028ABC_HTILE_WIDTH(x)                      (((x) >> 0) & 0x1)
+#define   C_028ABC_HTILE_WIDTH                         0xFFFFFFFE
+#define   S_028ABC_HTILE_HEIGHT(x)                      (((x) & 0x1) << 1)
+#define   G_028ABC_HTILE_HEIGHT(x)                      (((x) >> 1) & 0x1)
+#define   C_028ABC_HTILE_HEIGHT                         0xFFFFFFFD
+#define   G_028ABC_LINEAR(x)                           (((x) >> 2) & 0x1)
 #define DB_Z_INFO					0x28040
 #       define Z_ARRAY_MODE(x)                          ((x) << 4)
 #       define DB_TILE_SPLIT(x)                         (((x) & 0x7) << 8)
 #       define DB_NUM_BANKS(x)                          (((x) & 0x3) << 12)
 #       define DB_BANK_WIDTH(x)                         (((x) & 0x3) << 16)
 #       define DB_BANK_HEIGHT(x)                        (((x) & 0x3) << 20)
+#       define DB_MACRO_TILE_ASPECT(x)                  (((x) & 0x3) << 24)
+#define R_028040_DB_Z_INFO                       0x028040
+#define   S_028040_FORMAT(x)                           (((x) & 0x3) << 0)
+#define   G_028040_FORMAT(x)                           (((x) >> 0) & 0x3)
+#define   C_028040_FORMAT                              0xFFFFFFFC
+#define     V_028040_Z_INVALID                     0x00000000
+#define     V_028040_Z_16                          0x00000001
+#define     V_028040_Z_24                          0x00000002
+#define     V_028040_Z_32_FLOAT                    0x00000003
+#define   S_028040_ARRAY_MODE(x)                       (((x) & 0xF) << 4)
+#define   G_028040_ARRAY_MODE(x)                       (((x) >> 4) & 0xF)
+#define   C_028040_ARRAY_MODE                          0xFFFFFF0F
+#define   S_028040_READ_SIZE(x)                        (((x) & 0x1) << 28)
+#define   G_028040_READ_SIZE(x)                        (((x) >> 28) & 0x1)
+#define   C_028040_READ_SIZE                           0xEFFFFFFF
+#define   S_028040_TILE_SURFACE_ENABLE(x)              (((x) & 0x1) << 29)
+#define   G_028040_TILE_SURFACE_ENABLE(x)              (((x) >> 29) & 0x1)
+#define   C_028040_TILE_SURFACE_ENABLE                 0xDFFFFFFF
+#define   S_028040_ZRANGE_PRECISION(x)                 (((x) & 0x1) << 31)
+#define   G_028040_ZRANGE_PRECISION(x)                 (((x) >> 31) & 0x1)
+#define   C_028040_ZRANGE_PRECISION                    0x7FFFFFFF
+#define   S_028040_TILE_SPLIT(x)                       (((x) & 0x7) << 8)
+#define   G_028040_TILE_SPLIT(x)                       (((x) >> 8) & 0x7)
+#define   S_028040_NUM_BANKS(x)                        (((x) & 0x3) << 12)
+#define   G_028040_NUM_BANKS(x)                        (((x) >> 12) & 0x3)
+#define   S_028040_BANK_WIDTH(x)                       (((x) & 0x3) << 16)
+#define   G_028040_BANK_WIDTH(x)                       (((x) >> 16) & 0x3)
+#define   S_028040_BANK_HEIGHT(x)                      (((x) & 0x3) << 20)
+#define   G_028040_BANK_HEIGHT(x)                      (((x) >> 20) & 0x3)
+#define   S_028040_MACRO_TILE_ASPECT(x)                (((x) & 0x3) << 24)
+#define   G_028040_MACRO_TILE_ASPECT(x)                (((x) >> 24) & 0x3)
 #define DB_STENCIL_INFO					0x28044
+#define R_028044_DB_STENCIL_INFO                     0x028044
+#define   S_028044_FORMAT(x)                           (((x) & 0x1) << 0)
+#define   G_028044_FORMAT(x)                           (((x) >> 0) & 0x1)
+#define   C_028044_FORMAT                              0xFFFFFFFE
+#define   G_028044_TILE_SPLIT(x)                       (((x) >> 8) & 0x7)
 #define DB_Z_READ_BASE					0x28048
 #define DB_STENCIL_READ_BASE				0x2804c
 #define DB_Z_WRITE_BASE					0x28050
 #define DB_STENCIL_WRITE_BASE				0x28054
 #define DB_DEPTH_SIZE					0x28058
+#define R_028058_DB_DEPTH_SIZE                       0x028058
+#define   S_028058_PITCH_TILE_MAX(x)                   (((x) & 0x7FF) << 0)
+#define   G_028058_PITCH_TILE_MAX(x)                   (((x) >> 0) & 0x7FF)
+#define   C_028058_PITCH_TILE_MAX                      0xFFFFF800
+#define   S_028058_HEIGHT_TILE_MAX(x)                   (((x) & 0x7FF) << 11)
+#define   G_028058_HEIGHT_TILE_MAX(x)                   (((x) >> 11) & 0x7FF)
+#define   C_028058_HEIGHT_TILE_MAX                      0xFFC007FF
+#define R_02805C_DB_DEPTH_SLICE                      0x02805C
+#define   S_02805C_SLICE_TILE_MAX(x)                   (((x) & 0x3FFFFF) << 0)
+#define   G_02805C_SLICE_TILE_MAX(x)                   (((x) >> 0) & 0x3FFFFF)
+#define   C_02805C_SLICE_TILE_MAX                      0xFFC00000
 
 #define SQ_PGM_START_PS					0x28840
 #define SQ_PGM_START_VS					0x2885c
@@ -948,6 +1067,14 @@
 #define SQ_PGM_START_HS					0x288b8
 #define SQ_PGM_START_LS					0x288d0
 
+#define	VGT_STRMOUT_BUFFER_BASE_0			0x28AD8
+#define	VGT_STRMOUT_BUFFER_BASE_1			0x28AE8
+#define	VGT_STRMOUT_BUFFER_BASE_2			0x28AF8
+#define	VGT_STRMOUT_BUFFER_BASE_3			0x28B08
+#define VGT_STRMOUT_BUFFER_SIZE_0			0x28AD0
+#define VGT_STRMOUT_BUFFER_SIZE_1			0x28AE0
+#define VGT_STRMOUT_BUFFER_SIZE_2			0x28AF0
+#define VGT_STRMOUT_BUFFER_SIZE_3			0x28B00
 #define VGT_STRMOUT_CONFIG				0x28b94
 #define VGT_STRMOUT_BUFFER_CONFIG			0x28b98
 
@@ -974,6 +1101,114 @@
 #define	CB_COLOR0_PITCH					0x28c64
 #define	CB_COLOR0_SLICE					0x28c68
 #define	CB_COLOR0_VIEW					0x28c6c
+#define R_028C6C_CB_COLOR0_VIEW                      0x00028C6C
+#define   S_028C6C_SLICE_START(x)                      (((x) & 0x7FF) << 0)
+#define   G_028C6C_SLICE_START(x)                      (((x) >> 0) & 0x7FF)
+#define   C_028C6C_SLICE_START                         0xFFFFF800
+#define   S_028C6C_SLICE_MAX(x)                        (((x) & 0x7FF) << 13)
+#define   G_028C6C_SLICE_MAX(x)                        (((x) >> 13) & 0x7FF)
+#define   C_028C6C_SLICE_MAX                           0xFF001FFF
+#define R_028C70_CB_COLOR0_INFO                      0x028C70
+#define   S_028C70_ENDIAN(x)                           (((x) & 0x3) << 0)
+#define   G_028C70_ENDIAN(x)                           (((x) >> 0) & 0x3)
+#define   C_028C70_ENDIAN                              0xFFFFFFFC
+#define   S_028C70_FORMAT(x)                           (((x) & 0x3F) << 2)
+#define   G_028C70_FORMAT(x)                           (((x) >> 2) & 0x3F)
+#define   C_028C70_FORMAT                              0xFFFFFF03
+#define     V_028C70_COLOR_INVALID                     0x00000000
+#define     V_028C70_COLOR_8                           0x00000001
+#define     V_028C70_COLOR_4_4                         0x00000002
+#define     V_028C70_COLOR_3_3_2                       0x00000003
+#define     V_028C70_COLOR_16                          0x00000005
+#define     V_028C70_COLOR_16_FLOAT                    0x00000006
+#define     V_028C70_COLOR_8_8                         0x00000007
+#define     V_028C70_COLOR_5_6_5                       0x00000008
+#define     V_028C70_COLOR_6_5_5                       0x00000009
+#define     V_028C70_COLOR_1_5_5_5                     0x0000000A
+#define     V_028C70_COLOR_4_4_4_4                     0x0000000B
+#define     V_028C70_COLOR_5_5_5_1                     0x0000000C
+#define     V_028C70_COLOR_32                          0x0000000D
+#define     V_028C70_COLOR_32_FLOAT                    0x0000000E
+#define     V_028C70_COLOR_16_16                       0x0000000F
+#define     V_028C70_COLOR_16_16_FLOAT                 0x00000010
+#define     V_028C70_COLOR_8_24                        0x00000011
+#define     V_028C70_COLOR_8_24_FLOAT                  0x00000012
+#define     V_028C70_COLOR_24_8                        0x00000013
+#define     V_028C70_COLOR_24_8_FLOAT                  0x00000014
+#define     V_028C70_COLOR_10_11_11                    0x00000015
+#define     V_028C70_COLOR_10_11_11_FLOAT              0x00000016
+#define     V_028C70_COLOR_11_11_10                    0x00000017
+#define     V_028C70_COLOR_11_11_10_FLOAT              0x00000018
+#define     V_028C70_COLOR_2_10_10_10                  0x00000019
+#define     V_028C70_COLOR_8_8_8_8                     0x0000001A
+#define     V_028C70_COLOR_10_10_10_2                  0x0000001B
+#define     V_028C70_COLOR_X24_8_32_FLOAT              0x0000001C
+#define     V_028C70_COLOR_32_32                       0x0000001D
+#define     V_028C70_COLOR_32_32_FLOAT                 0x0000001E
+#define     V_028C70_COLOR_16_16_16_16                 0x0000001F
+#define     V_028C70_COLOR_16_16_16_16_FLOAT           0x00000020
+#define     V_028C70_COLOR_32_32_32_32                 0x00000022
+#define     V_028C70_COLOR_32_32_32_32_FLOAT           0x00000023
+#define     V_028C70_COLOR_32_32_32_FLOAT              0x00000030
+#define   S_028C70_ARRAY_MODE(x)                       (((x) & 0xF) << 8)
+#define   G_028C70_ARRAY_MODE(x)                       (((x) >> 8) & 0xF)
+#define   C_028C70_ARRAY_MODE                          0xFFFFF0FF
+#define     V_028C70_ARRAY_LINEAR_GENERAL              0x00000000
+#define     V_028C70_ARRAY_LINEAR_ALIGNED              0x00000001
+#define     V_028C70_ARRAY_1D_TILED_THIN1              0x00000002
+#define     V_028C70_ARRAY_2D_TILED_THIN1              0x00000004
+#define   S_028C70_NUMBER_TYPE(x)                      (((x) & 0x7) << 12)
+#define   G_028C70_NUMBER_TYPE(x)                      (((x) >> 12) & 0x7)
+#define   C_028C70_NUMBER_TYPE                         0xFFFF8FFF
+#define     V_028C70_NUMBER_UNORM                      0x00000000
+#define     V_028C70_NUMBER_SNORM                      0x00000001
+#define     V_028C70_NUMBER_USCALED                    0x00000002
+#define     V_028C70_NUMBER_SSCALED                    0x00000003
+#define     V_028C70_NUMBER_UINT                       0x00000004
+#define     V_028C70_NUMBER_SINT                       0x00000005
+#define     V_028C70_NUMBER_SRGB                       0x00000006
+#define     V_028C70_NUMBER_FLOAT                      0x00000007
+#define   S_028C70_COMP_SWAP(x)                        (((x) & 0x3) << 15)
+#define   G_028C70_COMP_SWAP(x)                        (((x) >> 15) & 0x3)
+#define   C_028C70_COMP_SWAP                           0xFFFE7FFF
+#define     V_028C70_SWAP_STD                          0x00000000
+#define     V_028C70_SWAP_ALT                          0x00000001
+#define     V_028C70_SWAP_STD_REV                      0x00000002
+#define     V_028C70_SWAP_ALT_REV                      0x00000003
+#define   S_028C70_FAST_CLEAR(x)                       (((x) & 0x1) << 17)
+#define   G_028C70_FAST_CLEAR(x)                       (((x) >> 17) & 0x1)
+#define   C_028C70_FAST_CLEAR                          0xFFFDFFFF
+#define   S_028C70_COMPRESSION(x)                      (((x) & 0x3) << 18)
+#define   G_028C70_COMPRESSION(x)                      (((x) >> 18) & 0x3)
+#define   C_028C70_COMPRESSION                         0xFFF3FFFF
+#define   S_028C70_BLEND_CLAMP(x)                      (((x) & 0x1) << 19)
+#define   G_028C70_BLEND_CLAMP(x)                      (((x) >> 19) & 0x1)
+#define   C_028C70_BLEND_CLAMP                         0xFFF7FFFF
+#define   S_028C70_BLEND_BYPASS(x)                     (((x) & 0x1) << 20)
+#define   G_028C70_BLEND_BYPASS(x)                     (((x) >> 20) & 0x1)
+#define   C_028C70_BLEND_BYPASS                        0xFFEFFFFF
+#define   S_028C70_SIMPLE_FLOAT(x)                     (((x) & 0x1) << 21)
+#define   G_028C70_SIMPLE_FLOAT(x)                     (((x) >> 21) & 0x1)
+#define   C_028C70_SIMPLE_FLOAT                        0xFFDFFFFF
+#define   S_028C70_ROUND_MODE(x)                       (((x) & 0x1) << 22)
+#define   G_028C70_ROUND_MODE(x)                       (((x) >> 22) & 0x1)
+#define   C_028C70_ROUND_MODE                          0xFFBFFFFF
+#define   S_028C70_TILE_COMPACT(x)                     (((x) & 0x1) << 23)
+#define   G_028C70_TILE_COMPACT(x)                     (((x) >> 23) & 0x1)
+#define   C_028C70_TILE_COMPACT                        0xFF7FFFFF
+#define   S_028C70_SOURCE_FORMAT(x)                    (((x) & 0x3) << 24)
+#define   G_028C70_SOURCE_FORMAT(x)                    (((x) >> 24) & 0x3)
+#define   C_028C70_SOURCE_FORMAT                       0xFCFFFFFF
+#define     V_028C70_EXPORT_4C_32BPC                   0x0
+#define     V_028C70_EXPORT_4C_16BPC                   0x1
+#define     V_028C70_EXPORT_2C_32BPC                   0x2 /* Do not use */
+#define   S_028C70_RAT(x)                              (((x) & 0x1) << 26)
+#define   G_028C70_RAT(x)                              (((x) >> 26) & 0x1)
+#define   C_028C70_RAT                                 0xFBFFFFFF
+#define   S_028C70_RESOURCE_TYPE(x)                    (((x) & 0x7) << 27)
+#define   G_028C70_RESOURCE_TYPE(x)                    (((x) >> 27) & 0x7)
+#define   C_028C70_RESOURCE_TYPE                       0xC7FFFFFF
+
 #define	CB_COLOR0_INFO					0x28c70
 #	define CB_FORMAT(x)				((x) << 2)
 #       define CB_ARRAY_MODE(x)                         ((x) << 8)
@@ -984,6 +1219,20 @@
 #	define CB_SOURCE_FORMAT(x)			((x) << 24)
 #	define CB_SF_EXPORT_FULL			0
 #	define CB_SF_EXPORT_NORM			1
+#define R_028C74_CB_COLOR0_ATTRIB                      0x028C74
+#define   S_028C74_NON_DISP_TILING_ORDER(x)            (((x) & 0x1) << 4)
+#define   G_028C74_NON_DISP_TILING_ORDER(x)            (((x) >> 4) & 0x1)
+#define   C_028C74_NON_DISP_TILING_ORDER               0xFFFFFFEF
+#define   S_028C74_TILE_SPLIT(x)                       (((x) & 0xf) << 5)
+#define   G_028C74_TILE_SPLIT(x)                       (((x) >> 5) & 0xf)
+#define   S_028C74_NUM_BANKS(x)                        (((x) & 0x3) << 10)
+#define   G_028C74_NUM_BANKS(x)                        (((x) >> 10) & 0x3)
+#define   S_028C74_BANK_WIDTH(x)                       (((x) & 0x3) << 13)
+#define   G_028C74_BANK_WIDTH(x)                       (((x) >> 13) & 0x3)
+#define   S_028C74_BANK_HEIGHT(x)                      (((x) & 0x3) << 16)
+#define   G_028C74_BANK_HEIGHT(x)                      (((x) >> 16) & 0x3)
+#define   S_028C74_MACRO_TILE_ASPECT(x)                (((x) & 0x3) << 19)
+#define   G_028C74_MACRO_TILE_ASPECT(x)                (((x) >> 19) & 0x3)
 #define	CB_COLOR0_ATTRIB				0x28c74
 #       define CB_TILE_SPLIT(x)                         (((x) & 0x7) << 5)
 #       define ADDR_SURF_TILE_SPLIT_64B                 0
@@ -1008,6 +1257,7 @@
 #       define ADDR_SURF_BANK_HEIGHT_2                  1
 #       define ADDR_SURF_BANK_HEIGHT_4                  2
 #       define ADDR_SURF_BANK_HEIGHT_8                  3
+#       define CB_MACRO_TILE_ASPECT(x)                  (((x) & 0x3) << 19)
 #define	CB_COLOR0_DIM					0x28c78
 /* only CB0-7 blocks have these regs */
 #define	CB_COLOR0_CMASK					0x28c7c
@@ -1196,9 +1446,144 @@
 #define SQ_TEX_RESOURCE_WORD6_0                         0x30018
 #       define TEX_TILE_SPLIT(x)                        (((x) & 0x7) << 29)
 #define SQ_TEX_RESOURCE_WORD7_0                         0x3001c
+#       define MACRO_TILE_ASPECT(x)                     (((x) & 0x3) << 6)
 #       define TEX_BANK_WIDTH(x)                        (((x) & 0x3) << 8)
 #       define TEX_BANK_HEIGHT(x)                       (((x) & 0x3) << 10)
 #       define TEX_NUM_BANKS(x)                         (((x) & 0x3) << 16)
+#define R_030000_SQ_TEX_RESOURCE_WORD0_0             0x030000
+#define   S_030000_DIM(x)                              (((x) & 0x7) << 0)
+#define   G_030000_DIM(x)                              (((x) >> 0) & 0x7)
+#define   C_030000_DIM                                 0xFFFFFFF8
+#define     V_030000_SQ_TEX_DIM_1D                     0x00000000
+#define     V_030000_SQ_TEX_DIM_2D                     0x00000001
+#define     V_030000_SQ_TEX_DIM_3D                     0x00000002
+#define     V_030000_SQ_TEX_DIM_CUBEMAP                0x00000003
+#define     V_030000_SQ_TEX_DIM_1D_ARRAY               0x00000004
+#define     V_030000_SQ_TEX_DIM_2D_ARRAY               0x00000005
+#define     V_030000_SQ_TEX_DIM_2D_MSAA                0x00000006
+#define     V_030000_SQ_TEX_DIM_2D_ARRAY_MSAA          0x00000007
+#define   S_030000_NON_DISP_TILING_ORDER(x)            (((x) & 0x1) << 5)
+#define   G_030000_NON_DISP_TILING_ORDER(x)            (((x) >> 5) & 0x1)
+#define   C_030000_NON_DISP_TILING_ORDER               0xFFFFFFDF
+#define   S_030000_PITCH(x)                            (((x) & 0xFFF) << 6)
+#define   G_030000_PITCH(x)                            (((x) >> 6) & 0xFFF)
+#define   C_030000_PITCH                               0xFFFC003F
+#define   S_030000_TEX_WIDTH(x)                        (((x) & 0x3FFF) << 18)
+#define   G_030000_TEX_WIDTH(x)                        (((x) >> 18) & 0x3FFF)
+#define   C_030000_TEX_WIDTH                           0x0003FFFF
+#define R_030004_SQ_TEX_RESOURCE_WORD1_0             0x030004
+#define   S_030004_TEX_HEIGHT(x)                       (((x) & 0x3FFF) << 0)
+#define   G_030004_TEX_HEIGHT(x)                       (((x) >> 0) & 0x3FFF)
+#define   C_030004_TEX_HEIGHT                          0xFFFFC000
+#define   S_030004_TEX_DEPTH(x)                        (((x) & 0x1FFF) << 14)
+#define   G_030004_TEX_DEPTH(x)                        (((x) >> 14) & 0x1FFF)
+#define   C_030004_TEX_DEPTH                           0xF8003FFF
+#define   S_030004_ARRAY_MODE(x)                       (((x) & 0xF) << 28)
+#define   G_030004_ARRAY_MODE(x)                       (((x) >> 28) & 0xF)
+#define   C_030004_ARRAY_MODE                          0x0FFFFFFF
+#define R_030008_SQ_TEX_RESOURCE_WORD2_0             0x030008
+#define   S_030008_BASE_ADDRESS(x)                     (((x) & 0xFFFFFFFF) << 0)
+#define   G_030008_BASE_ADDRESS(x)                     (((x) >> 0) & 0xFFFFFFFF)
+#define   C_030008_BASE_ADDRESS                        0x00000000
+#define R_03000C_SQ_TEX_RESOURCE_WORD3_0             0x03000C
+#define   S_03000C_MIP_ADDRESS(x)                      (((x) & 0xFFFFFFFF) << 0)
+#define   G_03000C_MIP_ADDRESS(x)                      (((x) >> 0) & 0xFFFFFFFF)
+#define   C_03000C_MIP_ADDRESS                         0x00000000
+#define R_030010_SQ_TEX_RESOURCE_WORD4_0             0x030010
+#define   S_030010_FORMAT_COMP_X(x)                    (((x) & 0x3) << 0)
+#define   G_030010_FORMAT_COMP_X(x)                    (((x) >> 0) & 0x3)
+#define   C_030010_FORMAT_COMP_X                       0xFFFFFFFC
+#define     V_030010_SQ_FORMAT_COMP_UNSIGNED           0x00000000
+#define     V_030010_SQ_FORMAT_COMP_SIGNED             0x00000001
+#define     V_030010_SQ_FORMAT_COMP_UNSIGNED_BIASED    0x00000002
+#define   S_030010_FORMAT_COMP_Y(x)                    (((x) & 0x3) << 2)
+#define   G_030010_FORMAT_COMP_Y(x)                    (((x) >> 2) & 0x3)
+#define   C_030010_FORMAT_COMP_Y                       0xFFFFFFF3
+#define   S_030010_FORMAT_COMP_Z(x)                    (((x) & 0x3) << 4)
+#define   G_030010_FORMAT_COMP_Z(x)                    (((x) >> 4) & 0x3)
+#define   C_030010_FORMAT_COMP_Z                       0xFFFFFFCF
+#define   S_030010_FORMAT_COMP_W(x)                    (((x) & 0x3) << 6)
+#define   G_030010_FORMAT_COMP_W(x)                    (((x) >> 6) & 0x3)
+#define   C_030010_FORMAT_COMP_W                       0xFFFFFF3F
+#define   S_030010_NUM_FORMAT_ALL(x)                   (((x) & 0x3) << 8)
+#define   G_030010_NUM_FORMAT_ALL(x)                   (((x) >> 8) & 0x3)
+#define   C_030010_NUM_FORMAT_ALL                      0xFFFFFCFF
+#define     V_030010_SQ_NUM_FORMAT_NORM                0x00000000
+#define     V_030010_SQ_NUM_FORMAT_INT                 0x00000001
+#define     V_030010_SQ_NUM_FORMAT_SCALED              0x00000002
+#define   S_030010_SRF_MODE_ALL(x)                     (((x) & 0x1) << 10)
+#define   G_030010_SRF_MODE_ALL(x)                     (((x) >> 10) & 0x1)
+#define   C_030010_SRF_MODE_ALL                        0xFFFFFBFF
+#define     V_030010_SRF_MODE_ZERO_CLAMP_MINUS_ONE     0x00000000
+#define     V_030010_SRF_MODE_NO_ZERO                  0x00000001
+#define   S_030010_FORCE_DEGAMMA(x)                    (((x) & 0x1) << 11)
+#define   G_030010_FORCE_DEGAMMA(x)                    (((x) >> 11) & 0x1)
+#define   C_030010_FORCE_DEGAMMA                       0xFFFFF7FF
+#define   S_030010_ENDIAN_SWAP(x)                      (((x) & 0x3) << 12)
+#define   G_030010_ENDIAN_SWAP(x)                      (((x) >> 12) & 0x3)
+#define   C_030010_ENDIAN_SWAP                         0xFFFFCFFF
+#define   S_030010_DST_SEL_X(x)                        (((x) & 0x7) << 16)
+#define   G_030010_DST_SEL_X(x)                        (((x) >> 16) & 0x7)
+#define   C_030010_DST_SEL_X                           0xFFF8FFFF
+#define     V_030010_SQ_SEL_X                          0x00000000
+#define     V_030010_SQ_SEL_Y                          0x00000001
+#define     V_030010_SQ_SEL_Z                          0x00000002
+#define     V_030010_SQ_SEL_W                          0x00000003
+#define     V_030010_SQ_SEL_0                          0x00000004
+#define     V_030010_SQ_SEL_1                          0x00000005
+#define   S_030010_DST_SEL_Y(x)                        (((x) & 0x7) << 19)
+#define   G_030010_DST_SEL_Y(x)                        (((x) >> 19) & 0x7)
+#define   C_030010_DST_SEL_Y                           0xFFC7FFFF
+#define   S_030010_DST_SEL_Z(x)                        (((x) & 0x7) << 22)
+#define   G_030010_DST_SEL_Z(x)                        (((x) >> 22) & 0x7)
+#define   C_030010_DST_SEL_Z                           0xFE3FFFFF
+#define   S_030010_DST_SEL_W(x)                        (((x) & 0x7) << 25)
+#define   G_030010_DST_SEL_W(x)                        (((x) >> 25) & 0x7)
+#define   C_030010_DST_SEL_W                           0xF1FFFFFF
+#define   S_030010_BASE_LEVEL(x)                       (((x) & 0xF) << 28)
+#define   G_030010_BASE_LEVEL(x)                       (((x) >> 28) & 0xF)
+#define   C_030010_BASE_LEVEL                          0x0FFFFFFF
+#define R_030014_SQ_TEX_RESOURCE_WORD5_0             0x030014
+#define   S_030014_LAST_LEVEL(x)                       (((x) & 0xF) << 0)
+#define   G_030014_LAST_LEVEL(x)                       (((x) >> 0) & 0xF)
+#define   C_030014_LAST_LEVEL                          0xFFFFFFF0
+#define   S_030014_BASE_ARRAY(x)                       (((x) & 0x1FFF) << 4)
+#define   G_030014_BASE_ARRAY(x)                       (((x) >> 4) & 0x1FFF)
+#define   C_030014_BASE_ARRAY                          0xFFFE000F
+#define   S_030014_LAST_ARRAY(x)                       (((x) & 0x1FFF) << 17)
+#define   G_030014_LAST_ARRAY(x)                       (((x) >> 17) & 0x1FFF)
+#define   C_030014_LAST_ARRAY                          0xC001FFFF
+#define R_030018_SQ_TEX_RESOURCE_WORD6_0             0x030018
+#define   S_030018_MAX_ANISO(x)                        (((x) & 0x7) << 0)
+#define   G_030018_MAX_ANISO(x)                        (((x) >> 0) & 0x7)
+#define   C_030018_MAX_ANISO                           0xFFFFFFF8
+#define   S_030018_PERF_MODULATION(x)                  (((x) & 0x7) << 3)
+#define   G_030018_PERF_MODULATION(x)                  (((x) >> 3) & 0x7)
+#define   C_030018_PERF_MODULATION                     0xFFFFFFC7
+#define   S_030018_INTERLACED(x)                       (((x) & 0x1) << 6)
+#define   G_030018_INTERLACED(x)                       (((x) >> 6) & 0x1)
+#define   C_030018_INTERLACED                          0xFFFFFFBF
+#define   S_030018_TILE_SPLIT(x)                       (((x) & 0x7) << 29)
+#define   G_030018_TILE_SPLIT(x)                       (((x) >> 29) & 0x7)
+#define R_03001C_SQ_TEX_RESOURCE_WORD7_0             0x03001C
+#define   S_03001C_MACRO_TILE_ASPECT(x)                (((x) & 0x3) << 6)
+#define   G_03001C_MACRO_TILE_ASPECT(x)                (((x) >> 6) & 0x3)
+#define   S_03001C_BANK_WIDTH(x)                       (((x) & 0x3) << 8)
+#define   G_03001C_BANK_WIDTH(x)                       (((x) >> 8) & 0x3)
+#define   S_03001C_BANK_HEIGHT(x)                      (((x) & 0x3) << 10)
+#define   G_03001C_BANK_HEIGHT(x)                      (((x) >> 10) & 0x3)
+#define   S_03001C_NUM_BANKS(x)                        (((x) & 0x3) << 16)
+#define   G_03001C_NUM_BANKS(x)                        (((x) >> 16) & 0x3)
+#define   S_03001C_TYPE(x)                             (((x) & 0x3) << 30)
+#define   G_03001C_TYPE(x)                             (((x) >> 30) & 0x3)
+#define   C_03001C_TYPE                                0x3FFFFFFF
+#define     V_03001C_SQ_TEX_VTX_INVALID_TEXTURE        0x00000000
+#define     V_03001C_SQ_TEX_VTX_INVALID_BUFFER         0x00000001
+#define     V_03001C_SQ_TEX_VTX_VALID_TEXTURE          0x00000002
+#define     V_03001C_SQ_TEX_VTX_VALID_BUFFER           0x00000003
+#define   S_03001C_DATA_FORMAT(x)                      (((x) & 0x3F) << 0)
+#define   G_03001C_DATA_FORMAT(x)                      (((x) >> 0) & 0x3F)
+#define   C_03001C_DATA_FORMAT                         0xFFFFFFC0
 
 #define SQ_VTX_CONSTANT_WORD0_0				0x30000
 #define SQ_VTX_CONSTANT_WORD1_0				0x30004
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index 2509c50..a48ca53 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -42,6 +42,8 @@
 extern int evergreen_mc_init(struct radeon_device *rdev);
 extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev);
 extern void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
+extern void si_rlc_fini(struct radeon_device *rdev);
+extern int si_rlc_init(struct radeon_device *rdev);
 
 #define EVERGREEN_PFP_UCODE_SIZE 1120
 #define EVERGREEN_PM4_UCODE_SIZE 1376
@@ -53,6 +55,8 @@
 #define CAYMAN_RLC_UCODE_SIZE 1024
 #define CAYMAN_MC_UCODE_SIZE 6037
 
+#define ARUBA_RLC_UCODE_SIZE 1536
+
 /* Firmware Names */
 MODULE_FIRMWARE("radeon/BARTS_pfp.bin");
 MODULE_FIRMWARE("radeon/BARTS_me.bin");
@@ -68,6 +72,9 @@
 MODULE_FIRMWARE("radeon/CAYMAN_me.bin");
 MODULE_FIRMWARE("radeon/CAYMAN_mc.bin");
 MODULE_FIRMWARE("radeon/CAYMAN_rlc.bin");
+MODULE_FIRMWARE("radeon/ARUBA_pfp.bin");
+MODULE_FIRMWARE("radeon/ARUBA_me.bin");
+MODULE_FIRMWARE("radeon/ARUBA_rlc.bin");
 
 #define BTC_IO_MC_REGS_SIZE 29
 
@@ -326,6 +333,15 @@
 		rlc_req_size = CAYMAN_RLC_UCODE_SIZE * 4;
 		mc_req_size = CAYMAN_MC_UCODE_SIZE * 4;
 		break;
+	case CHIP_ARUBA:
+		chip_name = "ARUBA";
+		rlc_chip_name = "ARUBA";
+		/* pfp/me same size as CAYMAN */
+		pfp_req_size = CAYMAN_PFP_UCODE_SIZE * 4;
+		me_req_size = CAYMAN_PM4_UCODE_SIZE * 4;
+		rlc_req_size = ARUBA_RLC_UCODE_SIZE * 4;
+		mc_req_size = 0;
+		break;
 	default: BUG();
 	}
 
@@ -365,15 +381,18 @@
 		err = -EINVAL;
 	}
 
-	snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
-	err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev);
-	if (err)
-		goto out;
-	if (rdev->mc_fw->size != mc_req_size) {
-		printk(KERN_ERR
-		       "ni_mc: Bogus length %zu in firmware \"%s\"\n",
-		       rdev->mc_fw->size, fw_name);
-		err = -EINVAL;
+	/* no MC ucode on TN */
+	if (!(rdev->flags & RADEON_IS_IGP)) {
+		snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
+		err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev);
+		if (err)
+			goto out;
+		if (rdev->mc_fw->size != mc_req_size) {
+			printk(KERN_ERR
+			       "ni_mc: Bogus length %zu in firmware \"%s\"\n",
+			       rdev->mc_fw->size, fw_name);
+			err = -EINVAL;
+		}
 	}
 out:
 	platform_device_unregister(pdev);
@@ -478,6 +497,7 @@
 	memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * CAYMAN_MAX_PIPES);
 	switch (rdev->family) {
 	case CHIP_CAYMAN:
+	case CHIP_ARUBA:
 		force_no_swizzle = true;
 		break;
 	default:
@@ -610,7 +630,6 @@
 
 	switch (rdev->family) {
 	case CHIP_CAYMAN:
-	default:
 		rdev->config.cayman.max_shader_engines = 2;
 		rdev->config.cayman.max_pipes_per_simd = 4;
 		rdev->config.cayman.max_tile_pipes = 8;
@@ -632,6 +651,43 @@
 		rdev->config.cayman.sc_hiz_tile_fifo_size = 0x30;
 		rdev->config.cayman.sc_earlyz_tile_fifo_size = 0x130;
 		break;
+	case CHIP_ARUBA:
+	default:
+		rdev->config.cayman.max_shader_engines = 1;
+		rdev->config.cayman.max_pipes_per_simd = 4;
+		rdev->config.cayman.max_tile_pipes = 2;
+		if ((rdev->pdev->device == 0x9900) ||
+		    (rdev->pdev->device == 0x9901)) {
+			rdev->config.cayman.max_simds_per_se = 6;
+			rdev->config.cayman.max_backends_per_se = 2;
+		} else if ((rdev->pdev->device == 0x9903) ||
+			   (rdev->pdev->device == 0x9904)) {
+			rdev->config.cayman.max_simds_per_se = 4;
+			rdev->config.cayman.max_backends_per_se = 2;
+		} else if ((rdev->pdev->device == 0x9990) ||
+			   (rdev->pdev->device == 0x9991)) {
+			rdev->config.cayman.max_simds_per_se = 3;
+			rdev->config.cayman.max_backends_per_se = 1;
+		} else {
+			rdev->config.cayman.max_simds_per_se = 2;
+			rdev->config.cayman.max_backends_per_se = 1;
+		}
+		rdev->config.cayman.max_texture_channel_caches = 2;
+		rdev->config.cayman.max_gprs = 256;
+		rdev->config.cayman.max_threads = 256;
+		rdev->config.cayman.max_gs_threads = 32;
+		rdev->config.cayman.max_stack_entries = 512;
+		rdev->config.cayman.sx_num_of_sets = 8;
+		rdev->config.cayman.sx_max_export_size = 256;
+		rdev->config.cayman.sx_max_export_pos_size = 64;
+		rdev->config.cayman.sx_max_export_smx_size = 192;
+		rdev->config.cayman.max_hw_contexts = 8;
+		rdev->config.cayman.sq_num_cf_insts = 2;
+
+		rdev->config.cayman.sc_prim_fifo_size = 0x40;
+		rdev->config.cayman.sc_hiz_tile_fifo_size = 0x30;
+		rdev->config.cayman.sc_earlyz_tile_fifo_size = 0x130;
+		break;
 	}
 
 	/* Initialize HDP */
@@ -652,7 +708,9 @@
 
 	cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE);
 	cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG);
-	cgts_tcc_disable = 0xff000000;
+	cgts_tcc_disable = 0xffff0000;
+	for (i = 0; i < rdev->config.cayman.max_texture_channel_caches; i++)
+		cgts_tcc_disable &= ~(1 << (16 + i));
 	gc_user_rb_backend_disable = RREG32(GC_USER_RB_BACKEND_DISABLE);
 	gc_user_shader_pipe_config = RREG32(GC_USER_SHADER_PIPE_CONFIG);
 	cgts_user_tcc_disable = RREG32(CGTS_USER_TCC_DISABLE);
@@ -804,8 +862,13 @@
 		rdev->config.cayman.tile_config |= (3 << 0);
 		break;
 	}
-	rdev->config.cayman.tile_config |=
-		((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
+
+	/* num banks is 8 on all fusion asics. 0 = 4, 1 = 8, 2 = 16 */
+	if (rdev->flags & RADEON_IS_IGP)
+		rdev->config.evergreen.tile_config |= 1 << 4;
+	else
+		rdev->config.cayman.tile_config |=
+			((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
 	rdev->config.cayman.tile_config |=
 		((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8;
 	rdev->config.cayman.tile_config |=
@@ -1318,7 +1381,7 @@
 	rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false;
 	rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false;
 	/* this only test cp0 */
-	r = radeon_ring_test(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
+	r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
 	if (r) {
 		rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
 		rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false;
@@ -1440,18 +1503,29 @@
 	/* enable pcie gen2 link */
 	evergreen_pcie_gen2_enable(rdev);
 
-	if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) {
-		r = ni_init_microcode(rdev);
+	if (rdev->flags & RADEON_IS_IGP) {
+		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
+			r = ni_init_microcode(rdev);
+			if (r) {
+				DRM_ERROR("Failed to load firmware!\n");
+				return r;
+			}
+		}
+	} else {
+		if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) {
+			r = ni_init_microcode(rdev);
+			if (r) {
+				DRM_ERROR("Failed to load firmware!\n");
+				return r;
+			}
+		}
+
+		r = ni_mc_load_microcode(rdev);
 		if (r) {
-			DRM_ERROR("Failed to load firmware!\n");
+			DRM_ERROR("Failed to load MC firmware!\n");
 			return r;
 		}
 	}
-	r = ni_mc_load_microcode(rdev);
-	if (r) {
-		DRM_ERROR("Failed to load MC firmware!\n");
-		return r;
-	}
 
 	r = r600_vram_scratch_init(rdev);
 	if (r)
@@ -1466,10 +1540,19 @@
 	r = evergreen_blit_init(rdev);
 	if (r) {
 		r600_blit_fini(rdev);
-		rdev->asic->copy = NULL;
+		rdev->asic->copy.copy = NULL;
 		dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
 	}
 
+	/* allocate rlc buffers */
+	if (rdev->flags & RADEON_IS_IGP) {
+		r = si_rlc_init(rdev);
+		if (r) {
+			DRM_ERROR("Failed to init rlc BOs!\n");
+			return r;
+		}
+	}
+
 	/* allocate wb buffer */
 	r = radeon_wb_init(rdev);
 	if (r)
@@ -1518,7 +1601,7 @@
 	if (r)
 		return r;
 
-	r = r600_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX);
+	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
 	if (r) {
 		DRM_ERROR("radeon: failed testing IB (%d).\n", r);
 		rdev->accel_working = false;
@@ -1654,6 +1737,8 @@
 		dev_err(rdev->dev, "disabling GPU acceleration\n");
 		cayman_cp_fini(rdev);
 		r600_irq_fini(rdev);
+		if (rdev->flags & RADEON_IS_IGP)
+			si_rlc_fini(rdev);
 		radeon_wb_fini(rdev);
 		r100_ib_fini(rdev);
 		radeon_vm_manager_fini(rdev);
@@ -1665,8 +1750,11 @@
 	/* Don't start up if the MC ucode is missing.
 	 * The default clocks and voltages before the MC ucode
 	 * is loaded are not suffient for advanced operations.
+	 *
+	 * We can skip this check for TN, because there is no MC
+	 * ucode.
 	 */
-	if (!rdev->mc_fw) {
+	if (!rdev->mc_fw && !(rdev->flags & RADEON_IS_IGP)) {
 		DRM_ERROR("radeon: MC ucode required for NI+.\n");
 		return -EINVAL;
 	}
@@ -1679,6 +1767,8 @@
 	r600_blit_fini(rdev);
 	cayman_cp_fini(rdev);
 	r600_irq_fini(rdev);
+	if (rdev->flags & RADEON_IS_IGP)
+		si_rlc_fini(rdev);
 	radeon_wb_fini(rdev);
 	radeon_vm_manager_fini(rdev);
 	r100_ib_fini(rdev);
@@ -1702,7 +1792,12 @@
 	/* number of VMs */
 	rdev->vm_manager.nvm = 8;
 	/* base offset of vram pages */
-	rdev->vm_manager.vram_base_offset = 0;
+	if (rdev->flags & RADEON_IS_IGP) {
+		u64 tmp = RREG32(FUS_MC_VM_FB_OFFSET);
+		tmp <<= 22;
+		rdev->vm_manager.vram_base_offset = tmp;
+	} else
+		rdev->vm_manager.vram_base_offset = 0;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h
index 9a7f3b6..2aa7046 100644
--- a/drivers/gpu/drm/radeon/nid.h
+++ b/drivers/gpu/drm/radeon/nid.h
@@ -106,6 +106,7 @@
 #define		SYSTEM_ACCESS_MODE_NOT_IN_SYS			(3 << 3)
 #define		SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU	(0 << 5)
 #define		ENABLE_ADVANCED_DRIVER_MODEL			(1 << 6)
+#define	FUS_MC_VM_FB_OFFSET				0x2068
 
 #define MC_SHARED_BLACKOUT_CNTL           		0x20ac
 #define	MC_ARB_RAMCFG					0x2760
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 333cde9..81801c1 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -65,6 +65,40 @@
 
 #include "r100_track.h"
 
+void r100_wait_for_vblank(struct radeon_device *rdev, int crtc)
+{
+	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc];
+	int i;
+
+	if (radeon_crtc->crtc_id == 0) {
+		if (RREG32(RADEON_CRTC_GEN_CNTL) & RADEON_CRTC_EN) {
+			for (i = 0; i < rdev->usec_timeout; i++) {
+				if (!(RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR))
+					break;
+				udelay(1);
+			}
+			for (i = 0; i < rdev->usec_timeout; i++) {
+				if (RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR)
+					break;
+				udelay(1);
+			}
+		}
+	} else {
+		if (RREG32(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_EN) {
+			for (i = 0; i < rdev->usec_timeout; i++) {
+				if (!(RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR))
+					break;
+				udelay(1);
+			}
+			for (i = 0; i < rdev->usec_timeout; i++) {
+				if (RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR)
+					break;
+				udelay(1);
+			}
+		}
+	}
+}
+
 /* This files gather functions specifics to:
  * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280
  */
@@ -87,23 +121,27 @@
 		r100_cs_dump_packet(p, pkt);
 		return r;
 	}
+
 	value = radeon_get_ib_value(p, idx);
 	tmp = value & 0x003fffff;
 	tmp += (((u32)reloc->lobj.gpu_offset) >> 10);
 
-	if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
-		tile_flags |= RADEON_DST_TILE_MACRO;
-	if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) {
-		if (reg == RADEON_SRC_PITCH_OFFSET) {
-			DRM_ERROR("Cannot src blit from microtiled surface\n");
-			r100_cs_dump_packet(p, pkt);
-			return -EINVAL;
+	if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
+		if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+			tile_flags |= RADEON_DST_TILE_MACRO;
+		if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) {
+			if (reg == RADEON_SRC_PITCH_OFFSET) {
+				DRM_ERROR("Cannot src blit from microtiled surface\n");
+				r100_cs_dump_packet(p, pkt);
+				return -EINVAL;
+			}
+			tile_flags |= RADEON_DST_TILE_MICRO;
 		}
-		tile_flags |= RADEON_DST_TILE_MICRO;
-	}
 
-	tmp |= tile_flags;
-	p->ib->ptr[idx] = (value & 0x3fc00000) | tmp;
+		tmp |= tile_flags;
+		p->ib->ptr[idx] = (value & 0x3fc00000) | tmp;
+	} else
+		p->ib->ptr[idx] = (value & 0xffc00000) | tmp;
 	return 0;
 }
 
@@ -412,7 +450,7 @@
 	/* set pcie lanes */
 	if ((rdev->flags & RADEON_IS_PCIE) &&
 	    !(rdev->flags & RADEON_IS_IGP) &&
-	    rdev->asic->set_pcie_lanes &&
+	    rdev->asic->pm.set_pcie_lanes &&
 	    (ps->pcie_lanes !=
 	     rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) {
 		radeon_set_pcie_lanes(rdev,
@@ -592,8 +630,8 @@
 	if (r)
 		return r;
 	rdev->gart.table_size = rdev->gart.num_gpu_pages * 4;
-	rdev->asic->gart_tlb_flush = &r100_pci_gart_tlb_flush;
-	rdev->asic->gart_set_page = &r100_pci_gart_set_page;
+	rdev->asic->gart.tlb_flush = &r100_pci_gart_tlb_flush;
+	rdev->asic->gart.set_page = &r100_pci_gart_set_page;
 	return radeon_gart_table_ram_alloc(rdev);
 }
 
@@ -930,9 +968,8 @@
 	return -1;
 }
 
-void r100_ring_start(struct radeon_device *rdev)
+void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring)
 {
-	struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
 	int r;
 
 	r = radeon_ring_lock(rdev, ring, 2);
@@ -1143,8 +1180,8 @@
 	WREG32(RADEON_CP_RB_WPTR_DELAY, 0);
 	WREG32(RADEON_CP_CSQ_MODE, 0x00004D4D);
 	WREG32(RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIBM_INDBM);
-	radeon_ring_start(rdev);
-	r = radeon_ring_test(rdev, ring);
+	radeon_ring_start(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
+	r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, ring);
 	if (r) {
 		DRM_ERROR("radeon: cp isn't working (%d).\n", r);
 		return r;
@@ -1552,7 +1589,17 @@
 			r100_cs_dump_packet(p, pkt);
 			return r;
 		}
-		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
+			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+				tile_flags |= RADEON_TXO_MACRO_TILE;
+			if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+				tile_flags |= RADEON_TXO_MICRO_TILE_X2;
+
+			tmp = idx_value & ~(0x7 << 2);
+			tmp |= tile_flags;
+			ib[idx] = tmp + ((u32)reloc->lobj.gpu_offset);
+		} else
+			ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
 		track->textures[i].robj = reloc->robj;
 		track->tex_dirty = true;
 		break;
@@ -1623,15 +1670,17 @@
 			r100_cs_dump_packet(p, pkt);
 			return r;
 		}
+		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
+			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+				tile_flags |= RADEON_COLOR_TILE_ENABLE;
+			if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+				tile_flags |= RADEON_COLOR_MICROTILE_ENABLE;
 
-		if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
-			tile_flags |= RADEON_COLOR_TILE_ENABLE;
-		if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
-			tile_flags |= RADEON_COLOR_MICROTILE_ENABLE;
-
-		tmp = idx_value & ~(0x7 << 16);
-		tmp |= tile_flags;
-		ib[idx] = tmp;
+			tmp = idx_value & ~(0x7 << 16);
+			tmp |= tile_flags;
+			ib[idx] = tmp;
+		} else
+			ib[idx] = idx_value;
 
 		track->cb[0].pitch = idx_value & RADEON_COLORPITCH_MASK;
 		track->cb_dirty = true;
@@ -3691,7 +3740,7 @@
 	radeon_ring_write(ring, ib->length_dw);
 }
 
-int r100_ib_test(struct radeon_device *rdev)
+int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
 {
 	struct radeon_ib *ib;
 	uint32_t scratch;
@@ -3916,7 +3965,7 @@
 	if (r)
 		return r;
 
-	r = r100_ib_test(rdev);
+	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
 	if (r) {
 		dev_err(rdev->dev, "failed testing IB (%d).\n", r);
 		rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c
index eba4cbf..a59cc47 100644
--- a/drivers/gpu/drm/radeon/r200.c
+++ b/drivers/gpu/drm/radeon/r200.c
@@ -215,7 +215,17 @@
 			r100_cs_dump_packet(p, pkt);
 			return r;
 		}
-		ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
+			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+				tile_flags |= R200_TXO_MACRO_TILE;
+			if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+				tile_flags |= R200_TXO_MICRO_TILE;
+
+			tmp = idx_value & ~(0x7 << 2);
+			tmp |= tile_flags;
+			ib[idx] = tmp + ((u32)reloc->lobj.gpu_offset);
+		} else
+			ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
 		track->textures[i].robj = reloc->robj;
 		track->tex_dirty = true;
 		break;
@@ -277,14 +287,17 @@
 			return r;
 		}
 
-		if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
-			tile_flags |= RADEON_COLOR_TILE_ENABLE;
-		if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
-			tile_flags |= RADEON_COLOR_MICROTILE_ENABLE;
+		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
+			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+				tile_flags |= RADEON_COLOR_TILE_ENABLE;
+			if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+				tile_flags |= RADEON_COLOR_MICROTILE_ENABLE;
 
-		tmp = idx_value & ~(0x7 << 16);
-		tmp |= tile_flags;
-		ib[idx] = tmp;
+			tmp = idx_value & ~(0x7 << 16);
+			tmp |= tile_flags;
+			ib[idx] = tmp;
+		} else
+			ib[idx] = idx_value;
 
 		track->cb[0].pitch = idx_value & RADEON_COLORPITCH_MASK;
 		track->cb_dirty = true;
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 6829638..fa14383 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -105,8 +105,8 @@
 	if (r)
 		DRM_ERROR("Failed to register debugfs file for PCIE gart !\n");
 	rdev->gart.table_size = rdev->gart.num_gpu_pages * 4;
-	rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush;
-	rdev->asic->gart_set_page = &rv370_pcie_gart_set_page;
+	rdev->asic->gart.tlb_flush = &rv370_pcie_gart_tlb_flush;
+	rdev->asic->gart.set_page = &rv370_pcie_gart_set_page;
 	return radeon_gart_table_vram_alloc(rdev);
 }
 
@@ -206,9 +206,8 @@
 	radeon_ring_write(ring, RADEON_SW_INT_FIRE);
 }
 
-void r300_ring_start(struct radeon_device *rdev)
+void r300_ring_start(struct radeon_device *rdev, struct radeon_ring *ring)
 {
-	struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
 	unsigned gb_tile_config;
 	int r;
 
@@ -1419,7 +1418,7 @@
 	if (r)
 		return r;
 
-	r = r100_ib_test(rdev);
+	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
 	if (r) {
 		dev_err(rdev->dev, "failed testing IB (%d).\n", r);
 		rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
index b143230..f3fcaac 100644
--- a/drivers/gpu/drm/radeon/r420.c
+++ b/drivers/gpu/drm/radeon/r420.c
@@ -279,7 +279,7 @@
 	if (r)
 		return r;
 
-	r = r100_ib_test(rdev);
+	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
 	if (r) {
 		dev_err(rdev->dev, "failed testing IB (%d).\n", r);
 		rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h
index 3bd8f1b..ec576aa 100644
--- a/drivers/gpu/drm/radeon/r500_reg.h
+++ b/drivers/gpu/drm/radeon/r500_reg.h
@@ -351,6 +351,8 @@
 #define AVIVO_D1CRTC_BLANK_CONTROL                              0x6084
 #define AVIVO_D1CRTC_INTERLACE_CONTROL                          0x6088
 #define AVIVO_D1CRTC_INTERLACE_STATUS                           0x608c
+#define AVIVO_D1CRTC_STATUS                                     0x609c
+#       define AVIVO_D1CRTC_V_BLANK                             (1 << 0)
 #define AVIVO_D1CRTC_STATUS_POSITION                            0x60a0
 #define AVIVO_D1CRTC_FRAME_COUNT                                0x60a4
 #define AVIVO_D1CRTC_STEREO_CONTROL                             0x60c4
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index 25084e8..ebcc15b 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -33,7 +33,7 @@
 
 /* This files gather functions specifics to: r520,rv530,rv560,rv570,r580 */
 
-static int r520_mc_wait_for_idle(struct radeon_device *rdev)
+int r520_mc_wait_for_idle(struct radeon_device *rdev)
 {
 	unsigned i;
 	uint32_t tmp;
@@ -207,7 +207,7 @@
 	if (r)
 		return r;
 
-	r = r100_ib_test(rdev);
+	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
 	if (r) {
 		dev_err(rdev->dev, "failed testing IB (%d).\n", r);
 		rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 17ca72c..391bd26 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -49,6 +49,7 @@
 #define EVERGREEN_PM4_UCODE_SIZE 1376
 #define EVERGREEN_RLC_UCODE_SIZE 768
 #define CAYMAN_RLC_UCODE_SIZE 1024
+#define ARUBA_RLC_UCODE_SIZE 1536
 
 /* Firmware Names */
 MODULE_FIRMWARE("radeon/R600_pfp.bin");
@@ -2226,7 +2227,7 @@
 
 	r600_cp_start(rdev);
 	ring->ready = true;
-	r = radeon_ring_test(rdev, ring);
+	r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, ring);
 	if (r) {
 		ring->ready = false;
 		return r;
@@ -2452,7 +2453,7 @@
 	r = r600_blit_init(rdev);
 	if (r) {
 		r600_blit_fini(rdev);
-		rdev->asic->copy = NULL;
+		rdev->asic->copy.copy = NULL;
 		dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
 	}
 
@@ -2493,7 +2494,7 @@
 	if (r)
 		return r;
 
-	r = r600_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX);
+	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
 	if (r) {
 		DRM_ERROR("radeon: failed testing IB (%d).\n", r);
 		rdev->accel_working = false;
@@ -2701,13 +2702,14 @@
 	radeon_ring_write(ring, ib->length_dw);
 }
 
-int r600_ib_test(struct radeon_device *rdev, int ring)
+int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
 {
 	struct radeon_ib *ib;
 	uint32_t scratch;
 	uint32_t tmp = 0;
 	unsigned i;
 	int r;
+	int ring_index = radeon_ring_index(rdev, ring);
 
 	r = radeon_scratch_get(rdev, &scratch);
 	if (r) {
@@ -2715,7 +2717,7 @@
 		return r;
 	}
 	WREG32(scratch, 0xCAFEDEAD);
-	r = radeon_ib_get(rdev, ring, &ib, 256);
+	r = radeon_ib_get(rdev, ring_index, &ib, 256);
 	if (r) {
 		DRM_ERROR("radeon: failed to get ib (%d).\n", r);
 		return r;
@@ -2723,20 +2725,7 @@
 	ib->ptr[0] = PACKET3(PACKET3_SET_CONFIG_REG, 1);
 	ib->ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
 	ib->ptr[2] = 0xDEADBEEF;
-	ib->ptr[3] = PACKET2(0);
-	ib->ptr[4] = PACKET2(0);
-	ib->ptr[5] = PACKET2(0);
-	ib->ptr[6] = PACKET2(0);
-	ib->ptr[7] = PACKET2(0);
-	ib->ptr[8] = PACKET2(0);
-	ib->ptr[9] = PACKET2(0);
-	ib->ptr[10] = PACKET2(0);
-	ib->ptr[11] = PACKET2(0);
-	ib->ptr[12] = PACKET2(0);
-	ib->ptr[13] = PACKET2(0);
-	ib->ptr[14] = PACKET2(0);
-	ib->ptr[15] = PACKET2(0);
-	ib->length_dw = 16;
+	ib->length_dw = 3;
 	r = radeon_ib_schedule(rdev, ib);
 	if (r) {
 		radeon_scratch_free(rdev, scratch);
@@ -2790,7 +2779,7 @@
 	rdev->ih.rptr = 0;
 }
 
-static int r600_ih_ring_alloc(struct radeon_device *rdev)
+int r600_ih_ring_alloc(struct radeon_device *rdev)
 {
 	int r;
 
@@ -2826,7 +2815,7 @@
 	return 0;
 }
 
-static void r600_ih_ring_fini(struct radeon_device *rdev)
+void r600_ih_ring_fini(struct radeon_device *rdev)
 {
 	int r;
 	if (rdev->ih.ring_obj) {
@@ -2873,10 +2862,17 @@
 
 	r600_rlc_stop(rdev);
 
-	WREG32(RLC_HB_BASE, 0);
 	WREG32(RLC_HB_CNTL, 0);
-	WREG32(RLC_HB_RPTR, 0);
-	WREG32(RLC_HB_WPTR, 0);
+
+	if (rdev->family == CHIP_ARUBA) {
+		WREG32(TN_RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8);
+		WREG32(TN_RLC_CLEAR_STATE_RESTORE_BASE, rdev->rlc.clear_state_gpu_addr >> 8);
+	}
+	if (rdev->family <= CHIP_CAYMAN) {
+		WREG32(RLC_HB_BASE, 0);
+		WREG32(RLC_HB_RPTR, 0);
+		WREG32(RLC_HB_WPTR, 0);
+	}
 	if (rdev->family <= CHIP_CAICOS) {
 		WREG32(RLC_HB_WPTR_LSB_ADDR, 0);
 		WREG32(RLC_HB_WPTR_MSB_ADDR, 0);
@@ -2885,7 +2881,12 @@
 	WREG32(RLC_UCODE_CNTL, 0);
 
 	fw_data = (const __be32 *)rdev->rlc_fw->data;
-	if (rdev->family >= CHIP_CAYMAN) {
+	if (rdev->family >= CHIP_ARUBA) {
+		for (i = 0; i < ARUBA_RLC_UCODE_SIZE; i++) {
+			WREG32(RLC_UCODE_ADDR, i);
+			WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
+		}
+	} else if (rdev->family >= CHIP_CAYMAN) {
 		for (i = 0; i < CAYMAN_RLC_UCODE_SIZE; i++) {
 			WREG32(RLC_UCODE_ADDR, i);
 			WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c
index accc032..db38f58 100644
--- a/drivers/gpu/drm/radeon/r600_blit_kms.c
+++ b/drivers/gpu/drm/radeon/r600_blit_kms.c
@@ -30,20 +30,7 @@
 
 #include "r600d.h"
 #include "r600_blit_shaders.h"
-
-#define DI_PT_RECTLIST        0x11
-#define DI_INDEX_SIZE_16_BIT  0x0
-#define DI_SRC_SEL_AUTO_INDEX 0x2
-
-#define FMT_8                 0x1
-#define FMT_5_6_5             0x8
-#define FMT_8_8_8_8           0x1a
-#define COLOR_8               0x1
-#define COLOR_5_6_5           0x8
-#define COLOR_8_8_8_8         0x1a
-
-#define RECT_UNIT_H           32
-#define RECT_UNIT_W           (RADEON_GPU_PAGE_SIZE / 4 / RECT_UNIT_H)
+#include "radeon_blit_common.h"
 
 /* emits 21 on rv770+, 23 on r600 */
 static void
diff --git a/drivers/gpu/drm/radeon/r600_blit_shaders.c b/drivers/gpu/drm/radeon/r600_blit_shaders.c
index 73e2c7c..34c8b23 100644
--- a/drivers/gpu/drm/radeon/r600_blit_shaders.c
+++ b/drivers/gpu/drm/radeon/r600_blit_shaders.c
@@ -24,6 +24,7 @@
  *     Alex Deucher <alexander.deucher@amd.com>
  */
 
+#include <linux/bug.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index 387fcc9..b8e12af 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -52,15 +52,20 @@
 	struct radeon_bo	*cb_color_bo[8];
 	u64			cb_color_bo_mc[8];
 	u32			cb_color_bo_offset[8];
-	struct radeon_bo	*cb_color_frag_bo[8];
-	struct radeon_bo	*cb_color_tile_bo[8];
+	struct radeon_bo	*cb_color_frag_bo[8]; /* unused */
+	struct radeon_bo	*cb_color_tile_bo[8]; /* unused */
 	u32			cb_color_info[8];
-	u32			cb_color_size_idx[8];
+	u32			cb_color_view[8];
+	u32			cb_color_size_idx[8]; /* unused */
 	u32			cb_target_mask;
-	u32			cb_shader_mask;
+	u32			cb_shader_mask;  /* unused */
 	u32			cb_color_size[8];
 	u32			vgt_strmout_en;
 	u32			vgt_strmout_buffer_en;
+	struct radeon_bo	*vgt_strmout_bo[4];
+	u64			vgt_strmout_bo_mc[4]; /* unused */
+	u32			vgt_strmout_bo_offset[4];
+	u32			vgt_strmout_size[4];
 	u32			db_depth_control;
 	u32			db_depth_info;
 	u32			db_depth_size_idx;
@@ -69,13 +74,20 @@
 	u32			db_offset;
 	struct radeon_bo	*db_bo;
 	u64			db_bo_mc;
+	bool			sx_misc_kill_all_prims;
+	bool			cb_dirty;
+	bool			db_dirty;
+	bool			streamout_dirty;
+	struct radeon_bo	*htile_bo;
+	u64			htile_offset;
+	u32			htile_surface;
 };
 
 #define FMT_8_BIT(fmt, vc)   [fmt] = { 1, 1, 1, vc, CHIP_R600 }
 #define FMT_16_BIT(fmt, vc)  [fmt] = { 1, 1, 2, vc, CHIP_R600 }
-#define FMT_24_BIT(fmt)      [fmt] = { 1, 1, 3,  0, CHIP_R600 }
+#define FMT_24_BIT(fmt)      [fmt] = { 1, 1, 4,  0, CHIP_R600 }
 #define FMT_32_BIT(fmt, vc)  [fmt] = { 1, 1, 4, vc, CHIP_R600 }
-#define FMT_48_BIT(fmt)      [fmt] = { 1, 1, 6,  0, CHIP_R600 }
+#define FMT_48_BIT(fmt)      [fmt] = { 1, 1, 8,  0, CHIP_R600 }
 #define FMT_64_BIT(fmt, vc)  [fmt] = { 1, 1, 8, vc, CHIP_R600 }
 #define FMT_96_BIT(fmt)      [fmt] = { 1, 1, 12, 0, CHIP_R600 }
 #define FMT_128_BIT(fmt, vc) [fmt] = { 1, 1, 16,vc, CHIP_R600 }
@@ -107,7 +119,7 @@
 
 	/* 24-bit */
 	FMT_24_BIT(V_038004_FMT_8_8_8),
-					       
+
 	/* 32-bit */
 	FMT_32_BIT(V_038004_COLOR_32, 1),
 	FMT_32_BIT(V_038004_COLOR_32_FLOAT, 1),
@@ -162,22 +174,22 @@
 	[V_038004_FMT_32_AS_32_32_32_32] = { 1, 1, 4, 0, CHIP_CEDAR},
 };
 
-static bool fmt_is_valid_color(u32 format)
+bool r600_fmt_is_valid_color(u32 format)
 {
 	if (format >= ARRAY_SIZE(color_formats_table))
 		return false;
-	
+
 	if (color_formats_table[format].valid_color)
 		return true;
 
 	return false;
 }
 
-static bool fmt_is_valid_texture(u32 format, enum radeon_family family)
+bool r600_fmt_is_valid_texture(u32 format, enum radeon_family family)
 {
 	if (format >= ARRAY_SIZE(color_formats_table))
 		return false;
-	
+
 	if (family < color_formats_table[format].min_family)
 		return false;
 
@@ -187,7 +199,7 @@
 	return false;
 }
 
-static int fmt_get_blocksize(u32 format)
+int r600_fmt_get_blocksize(u32 format)
 {
 	if (format >= ARRAY_SIZE(color_formats_table))
 		return 0;
@@ -195,7 +207,7 @@
 	return color_formats_table[format].blocksize;
 }
 
-static int fmt_get_nblocksx(u32 format, u32 w)
+int r600_fmt_get_nblocksx(u32 format, u32 w)
 {
 	unsigned bw;
 
@@ -209,7 +221,7 @@
 	return (w + bw - 1) / bw;
 }
 
-static int fmt_get_nblocksy(u32 format, u32 h)
+int r600_fmt_get_nblocksy(u32 format, u32 h)
 {
 	unsigned bh;
 
@@ -256,7 +268,7 @@
 		break;
 	case ARRAY_LINEAR_ALIGNED:
 		*pitch_align = max((u32)64, (u32)(values->group_size / values->blocksize));
-		*height_align = tile_height;
+		*height_align = 1;
 		*depth_align = 1;
 		*base_align = values->group_size;
 		break;
@@ -269,10 +281,9 @@
 		*base_align = values->group_size;
 		break;
 	case ARRAY_2D_TILED_THIN1:
-		*pitch_align = max((u32)macro_tile_width,
-				  (u32)(((values->group_size / tile_height) /
-					 (values->blocksize * values->nsamples)) *
-					values->nbanks)) * tile_width;
+		*pitch_align = max((u32)macro_tile_width * tile_width,
+				(u32)((values->group_size * values->nbanks) /
+				(values->blocksize * values->nsamples * tile_width)));
 		*height_align = macro_tile_height * tile_height;
 		*depth_align = 1;
 		*base_align = max(macro_tile_bytes,
@@ -296,12 +307,14 @@
 		track->cb_color_size[i] = 0;
 		track->cb_color_size_idx[i] = 0;
 		track->cb_color_info[i] = 0;
+		track->cb_color_view[i] = 0xFFFFFFFF;
 		track->cb_color_bo[i] = NULL;
 		track->cb_color_bo_offset[i] = 0xFFFFFFFF;
 		track->cb_color_bo_mc[i] = 0xFFFFFFFF;
 	}
 	track->cb_target_mask = 0xFFFFFFFF;
 	track->cb_shader_mask = 0xFFFFFFFF;
+	track->cb_dirty = true;
 	track->db_bo = NULL;
 	track->db_bo_mc = 0xFFFFFFFF;
 	/* assume the biggest format and that htile is enabled */
@@ -310,6 +323,19 @@
 	track->db_depth_size = 0xFFFFFFFF;
 	track->db_depth_size_idx = 0;
 	track->db_depth_control = 0xFFFFFFFF;
+	track->db_dirty = true;
+	track->htile_bo = NULL;
+	track->htile_offset = 0xFFFFFFFF;
+	track->htile_surface = 0;
+
+	for (i = 0; i < 4; i++) {
+		track->vgt_strmout_size[i] = 0;
+		track->vgt_strmout_bo[i] = NULL;
+		track->vgt_strmout_bo_offset[i] = 0xFFFFFFFF;
+		track->vgt_strmout_bo_mc[i] = 0xFFFFFFFF;
+	}
+	track->streamout_dirty = true;
+	track->sx_misc_kill_all_prims = false;
 }
 
 static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
@@ -322,13 +348,14 @@
 	volatile u32 *ib = p->ib->ptr;
 	unsigned array_mode;
 	u32 format;
+
 	if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
 		dev_warn(p->dev, "FMASK or CMASK buffer are not supported by this kernel\n");
 		return -EINVAL;
 	}
 	size = radeon_bo_size(track->cb_color_bo[i]) - track->cb_color_bo_offset[i];
 	format = G_0280A0_FORMAT(track->cb_color_info[i]);
-	if (!fmt_is_valid_color(format)) {
+	if (!r600_fmt_is_valid_color(format)) {
 		dev_warn(p->dev, "%s:%d cb invalid format %d for %d (0x%08X)\n",
 			 __func__, __LINE__, format,
 			i, track->cb_color_info[i]);
@@ -349,7 +376,7 @@
 	array_check.nbanks = track->nbanks;
 	array_check.npipes = track->npipes;
 	array_check.nsamples = track->nsamples;
-	array_check.blocksize = fmt_get_blocksize(format);
+	array_check.blocksize = r600_fmt_get_blocksize(format);
 	if (r600_get_array_mode_alignment(&array_check,
 					  &pitch_align, &height_align, &depth_align, &base_align)) {
 		dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
@@ -393,7 +420,18 @@
 	}
 
 	/* check offset */
-	tmp = fmt_get_nblocksy(format, height) * fmt_get_nblocksx(format, pitch) * fmt_get_blocksize(format);
+	tmp = r600_fmt_get_nblocksy(format, height) * r600_fmt_get_nblocksx(format, pitch) * r600_fmt_get_blocksize(format);
+	switch (array_mode) {
+	default:
+	case V_0280A0_ARRAY_LINEAR_GENERAL:
+	case V_0280A0_ARRAY_LINEAR_ALIGNED:
+		tmp += track->cb_color_view[i] & 0xFF;
+		break;
+	case V_0280A0_ARRAY_1D_TILED_THIN1:
+	case V_0280A0_ARRAY_2D_TILED_THIN1:
+		tmp += G_028080_SLICE_MAX(track->cb_color_view[i]) * tmp;
+		break;
+	}
 	if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
 		if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) {
 			/* the initial DDX does bad things with the CB size occasionally */
@@ -403,10 +441,13 @@
 			 * broken userspace.
 			 */
 		} else {
-			dev_warn(p->dev, "%s offset[%d] %d %d %d %lu too big\n", __func__, i,
-				 array_mode,
+			dev_warn(p->dev, "%s offset[%d] %d %d %d %lu too big (%d %d) (%d %d %d)\n",
+				 __func__, i, array_mode,
 				 track->cb_color_bo_offset[i], tmp,
-				 radeon_bo_size(track->cb_color_bo[i]));
+				 radeon_bo_size(track->cb_color_bo[i]),
+				 pitch, height, r600_fmt_get_nblocksx(format, pitch),
+				 r600_fmt_get_nblocksy(format, height),
+				 r600_fmt_get_blocksize(format));
 			return -EINVAL;
 		}
 	}
@@ -420,154 +461,316 @@
 	return 0;
 }
 
+static int r600_cs_track_validate_db(struct radeon_cs_parser *p)
+{
+	struct r600_cs_track *track = p->track;
+	u32 nviews, bpe, ntiles, size, slice_tile_max, tmp;
+	u32 height_align, pitch_align, depth_align;
+	u32 pitch = 8192;
+	u32 height = 8192;
+	u64 base_offset, base_align;
+	struct array_mode_checker array_check;
+	int array_mode;
+	volatile u32 *ib = p->ib->ptr;
+
+
+	if (track->db_bo == NULL) {
+		dev_warn(p->dev, "z/stencil with no depth buffer\n");
+		return -EINVAL;
+	}
+	switch (G_028010_FORMAT(track->db_depth_info)) {
+	case V_028010_DEPTH_16:
+		bpe = 2;
+		break;
+	case V_028010_DEPTH_X8_24:
+	case V_028010_DEPTH_8_24:
+	case V_028010_DEPTH_X8_24_FLOAT:
+	case V_028010_DEPTH_8_24_FLOAT:
+	case V_028010_DEPTH_32_FLOAT:
+		bpe = 4;
+		break;
+	case V_028010_DEPTH_X24_8_32_FLOAT:
+		bpe = 8;
+		break;
+	default:
+		dev_warn(p->dev, "z/stencil with invalid format %d\n", G_028010_FORMAT(track->db_depth_info));
+		return -EINVAL;
+	}
+	if ((track->db_depth_size & 0xFFFFFC00) == 0xFFFFFC00) {
+		if (!track->db_depth_size_idx) {
+			dev_warn(p->dev, "z/stencil buffer size not set\n");
+			return -EINVAL;
+		}
+		tmp = radeon_bo_size(track->db_bo) - track->db_offset;
+		tmp = (tmp / bpe) >> 6;
+		if (!tmp) {
+			dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %ld)\n",
+					track->db_depth_size, bpe, track->db_offset,
+					radeon_bo_size(track->db_bo));
+			return -EINVAL;
+		}
+		ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
+	} else {
+		size = radeon_bo_size(track->db_bo);
+		/* pitch in pixels */
+		pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8;
+		slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
+		slice_tile_max *= 64;
+		height = slice_tile_max / pitch;
+		if (height > 8192)
+			height = 8192;
+		base_offset = track->db_bo_mc + track->db_offset;
+		array_mode = G_028010_ARRAY_MODE(track->db_depth_info);
+		array_check.array_mode = array_mode;
+		array_check.group_size = track->group_size;
+		array_check.nbanks = track->nbanks;
+		array_check.npipes = track->npipes;
+		array_check.nsamples = track->nsamples;
+		array_check.blocksize = bpe;
+		if (r600_get_array_mode_alignment(&array_check,
+					&pitch_align, &height_align, &depth_align, &base_align)) {
+			dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
+					G_028010_ARRAY_MODE(track->db_depth_info),
+					track->db_depth_info);
+			return -EINVAL;
+		}
+		switch (array_mode) {
+		case V_028010_ARRAY_1D_TILED_THIN1:
+			/* don't break userspace */
+			height &= ~0x7;
+			break;
+		case V_028010_ARRAY_2D_TILED_THIN1:
+			break;
+		default:
+			dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
+					G_028010_ARRAY_MODE(track->db_depth_info),
+					track->db_depth_info);
+			return -EINVAL;
+		}
+
+		if (!IS_ALIGNED(pitch, pitch_align)) {
+			dev_warn(p->dev, "%s:%d db pitch (%d, 0x%x, %d) invalid\n",
+					__func__, __LINE__, pitch, pitch_align, array_mode);
+			return -EINVAL;
+		}
+		if (!IS_ALIGNED(height, height_align)) {
+			dev_warn(p->dev, "%s:%d db height (%d, 0x%x, %d) invalid\n",
+					__func__, __LINE__, height, height_align, array_mode);
+			return -EINVAL;
+		}
+		if (!IS_ALIGNED(base_offset, base_align)) {
+			dev_warn(p->dev, "%s offset 0x%llx, 0x%llx, %d not aligned\n", __func__,
+					base_offset, base_align, array_mode);
+			return -EINVAL;
+		}
+
+		ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
+		nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
+		tmp = ntiles * bpe * 64 * nviews;
+		if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
+			dev_warn(p->dev, "z/stencil buffer (%d) too small (0x%08X %d %d %d -> %u have %lu)\n",
+					array_mode,
+					track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
+					radeon_bo_size(track->db_bo));
+			return -EINVAL;
+		}
+	}
+
+	/* hyperz */
+	if (G_028010_TILE_SURFACE_ENABLE(track->db_depth_info)) {
+		unsigned long size;
+		unsigned nbx, nby;
+
+		if (track->htile_bo == NULL) {
+			dev_warn(p->dev, "%s:%d htile enabled without htile surface 0x%08x\n",
+				 __func__, __LINE__, track->db_depth_info);
+			return -EINVAL;
+		}
+		if ((track->db_depth_size & 0xFFFFFC00) == 0xFFFFFC00) {
+			dev_warn(p->dev, "%s:%d htile can't be enabled with bogus db_depth_size 0x%08x\n",
+				 __func__, __LINE__, track->db_depth_size);
+			return -EINVAL;
+		}
+
+		nbx = pitch;
+		nby = height;
+		if (G_028D24_LINEAR(track->htile_surface)) {
+			/* nbx must be 16 htiles aligned == 16 * 8 pixel aligned */
+			nbx = round_up(nbx, 16 * 8);
+			/* nby is npipes htiles aligned == npipes * 8 pixel aligned */
+			nby = round_up(nby, track->npipes * 8);
+		} else {
+			/* htile widht & nby (8 or 4) make 2 bits number */
+			tmp = track->htile_surface & 3;
+			/* align is htile align * 8, htile align vary according to
+			 * number of pipe and tile width and nby
+			 */
+			switch (track->npipes) {
+			case 8:
+				switch (tmp) {
+				case 3:	/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
+					nbx = round_up(nbx, 64 * 8);
+					nby = round_up(nby, 64 * 8);
+					break;
+				case 2:	/* HTILE_WIDTH = 4 & HTILE_HEIGHT = 8*/
+				case 1:	/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 4*/
+					nbx = round_up(nbx, 64 * 8);
+					nby = round_up(nby, 32 * 8);
+					break;
+				case 0:	/* HTILE_WIDTH = 4 & HTILE_HEIGHT = 4*/
+					nbx = round_up(nbx, 32 * 8);
+					nby = round_up(nby, 32 * 8);
+					break;
+				default:
+					return -EINVAL;
+				}
+				break;
+			case 4:
+				switch (tmp) {
+				case 3:	/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
+					nbx = round_up(nbx, 64 * 8);
+					nby = round_up(nby, 32 * 8);
+					break;
+				case 2:	/* HTILE_WIDTH = 4 & HTILE_HEIGHT = 8*/
+				case 1:	/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 4*/
+					nbx = round_up(nbx, 32 * 8);
+					nby = round_up(nby, 32 * 8);
+					break;
+				case 0:	/* HTILE_WIDTH = 4 & HTILE_HEIGHT = 4*/
+					nbx = round_up(nbx, 32 * 8);
+					nby = round_up(nby, 16 * 8);
+					break;
+				default:
+					return -EINVAL;
+				}
+				break;
+			case 2:
+				switch (tmp) {
+				case 3:	/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
+					nbx = round_up(nbx, 32 * 8);
+					nby = round_up(nby, 32 * 8);
+					break;
+				case 2:	/* HTILE_WIDTH = 4 & HTILE_HEIGHT = 8*/
+				case 1:	/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 4*/
+					nbx = round_up(nbx, 32 * 8);
+					nby = round_up(nby, 16 * 8);
+					break;
+				case 0:	/* HTILE_WIDTH = 4 & HTILE_HEIGHT = 4*/
+					nbx = round_up(nbx, 16 * 8);
+					nby = round_up(nby, 16 * 8);
+					break;
+				default:
+					return -EINVAL;
+				}
+				break;
+			case 1:
+				switch (tmp) {
+				case 3:	/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
+					nbx = round_up(nbx, 32 * 8);
+					nby = round_up(nby, 16 * 8);
+					break;
+				case 2:	/* HTILE_WIDTH = 4 & HTILE_HEIGHT = 8*/
+				case 1:	/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 4*/
+					nbx = round_up(nbx, 16 * 8);
+					nby = round_up(nby, 16 * 8);
+					break;
+				case 0:	/* HTILE_WIDTH = 4 & HTILE_HEIGHT = 4*/
+					nbx = round_up(nbx, 16 * 8);
+					nby = round_up(nby, 8 * 8);
+					break;
+				default:
+					return -EINVAL;
+				}
+				break;
+			default:
+				dev_warn(p->dev, "%s:%d invalid num pipes %d\n",
+					 __func__, __LINE__, track->npipes);
+				return -EINVAL;
+			}
+		}
+		/* compute number of htile */
+		nbx = G_028D24_HTILE_WIDTH(track->htile_surface) ? nbx / 8 : nbx / 4;
+		nby = G_028D24_HTILE_HEIGHT(track->htile_surface) ? nby / 8 : nby / 4;
+		size = nbx * nby * 4;
+		size += track->htile_offset;
+
+		if (size > radeon_bo_size(track->htile_bo)) {
+			dev_warn(p->dev, "%s:%d htile surface too small %ld for %ld (%d %d)\n",
+				 __func__, __LINE__, radeon_bo_size(track->htile_bo),
+				 size, nbx, nby);
+			return -EINVAL;
+		}
+	}
+
+	track->db_dirty = false;
+	return 0;
+}
+
 static int r600_cs_track_check(struct radeon_cs_parser *p)
 {
 	struct r600_cs_track *track = p->track;
 	u32 tmp;
 	int r, i;
-	volatile u32 *ib = p->ib->ptr;
 
 	/* on legacy kernel we don't perform advanced check */
 	if (p->rdev == NULL)
 		return 0;
-	/* we don't support out buffer yet */
-	if (track->vgt_strmout_en || track->vgt_strmout_buffer_en) {
-		dev_warn(p->dev, "this kernel doesn't support SMX output buffer\n");
-		return -EINVAL;
+
+	/* check streamout */
+	if (track->streamout_dirty && track->vgt_strmout_en) {
+		for (i = 0; i < 4; i++) {
+			if (track->vgt_strmout_buffer_en & (1 << i)) {
+				if (track->vgt_strmout_bo[i]) {
+					u64 offset = (u64)track->vgt_strmout_bo_offset[i] +
+						(u64)track->vgt_strmout_size[i];
+					if (offset > radeon_bo_size(track->vgt_strmout_bo[i])) {
+						DRM_ERROR("streamout %d bo too small: 0x%llx, 0x%lx\n",
+							  i, offset,
+							  radeon_bo_size(track->vgt_strmout_bo[i]));
+						return -EINVAL;
+					}
+				} else {
+					dev_warn(p->dev, "No buffer for streamout %d\n", i);
+					return -EINVAL;
+				}
+			}
+		}
+		track->streamout_dirty = false;
 	}
+
+	if (track->sx_misc_kill_all_prims)
+		return 0;
+
 	/* check that we have a cb for each enabled target, we don't check
 	 * shader_mask because it seems mesa isn't always setting it :(
 	 */
-	tmp = track->cb_target_mask;
-	for (i = 0; i < 8; i++) {
-		if ((tmp >> (i * 4)) & 0xF) {
-			/* at least one component is enabled */
-			if (track->cb_color_bo[i] == NULL) {
-				dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n",
-					__func__, __LINE__, track->cb_target_mask, track->cb_shader_mask, i);
-				return -EINVAL;
+	if (track->cb_dirty) {
+		tmp = track->cb_target_mask;
+		for (i = 0; i < 8; i++) {
+			if ((tmp >> (i * 4)) & 0xF) {
+				/* at least one component is enabled */
+				if (track->cb_color_bo[i] == NULL) {
+					dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n",
+						__func__, __LINE__, track->cb_target_mask, track->cb_shader_mask, i);
+					return -EINVAL;
+				}
+				/* perform rewrite of CB_COLOR[0-7]_SIZE */
+				r = r600_cs_track_validate_cb(p, i);
+				if (r)
+					return r;
 			}
-			/* perform rewrite of CB_COLOR[0-7]_SIZE */
-			r = r600_cs_track_validate_cb(p, i);
-			if (r)
-				return r;
 		}
+		track->cb_dirty = false;
 	}
+
 	/* Check depth buffer */
-	if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
-		G_028800_Z_ENABLE(track->db_depth_control)) {
-		u32 nviews, bpe, ntiles, size, slice_tile_max;
-		u32 height, height_align, pitch, pitch_align, depth_align;
-		u64 base_offset, base_align;
-		struct array_mode_checker array_check;
-		int array_mode;
-
-		if (track->db_bo == NULL) {
-			dev_warn(p->dev, "z/stencil with no depth buffer\n");
-			return -EINVAL;
-		}
-		if (G_028010_TILE_SURFACE_ENABLE(track->db_depth_info)) {
-			dev_warn(p->dev, "this kernel doesn't support z/stencil htile\n");
-			return -EINVAL;
-		}
-		switch (G_028010_FORMAT(track->db_depth_info)) {
-		case V_028010_DEPTH_16:
-			bpe = 2;
-			break;
-		case V_028010_DEPTH_X8_24:
-		case V_028010_DEPTH_8_24:
-		case V_028010_DEPTH_X8_24_FLOAT:
-		case V_028010_DEPTH_8_24_FLOAT:
-		case V_028010_DEPTH_32_FLOAT:
-			bpe = 4;
-			break;
-		case V_028010_DEPTH_X24_8_32_FLOAT:
-			bpe = 8;
-			break;
-		default:
-			dev_warn(p->dev, "z/stencil with invalid format %d\n", G_028010_FORMAT(track->db_depth_info));
-			return -EINVAL;
-		}
-		if ((track->db_depth_size & 0xFFFFFC00) == 0xFFFFFC00) {
-			if (!track->db_depth_size_idx) {
-				dev_warn(p->dev, "z/stencil buffer size not set\n");
-				return -EINVAL;
-			}
-			tmp = radeon_bo_size(track->db_bo) - track->db_offset;
-			tmp = (tmp / bpe) >> 6;
-			if (!tmp) {
-				dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %ld)\n",
-						track->db_depth_size, bpe, track->db_offset,
-						radeon_bo_size(track->db_bo));
-				return -EINVAL;
-			}
-			ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
-		} else {
-			size = radeon_bo_size(track->db_bo);
-			/* pitch in pixels */
-			pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8;
-			slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
-			slice_tile_max *= 64;
-			height = slice_tile_max / pitch;
-			if (height > 8192)
-				height = 8192;
-			base_offset = track->db_bo_mc + track->db_offset;
-			array_mode = G_028010_ARRAY_MODE(track->db_depth_info);
-			array_check.array_mode = array_mode;
-			array_check.group_size = track->group_size;
-			array_check.nbanks = track->nbanks;
-			array_check.npipes = track->npipes;
-			array_check.nsamples = track->nsamples;
-			array_check.blocksize = bpe;
-			if (r600_get_array_mode_alignment(&array_check,
-							  &pitch_align, &height_align, &depth_align, &base_align)) {
-				dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
-					 G_028010_ARRAY_MODE(track->db_depth_info),
-					 track->db_depth_info);
-				return -EINVAL;
-			}
-			switch (array_mode) {
-			case V_028010_ARRAY_1D_TILED_THIN1:
-				/* don't break userspace */
-				height &= ~0x7;
-				break;
-			case V_028010_ARRAY_2D_TILED_THIN1:
-				break;
-			default:
-				dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
-					 G_028010_ARRAY_MODE(track->db_depth_info),
-					 track->db_depth_info);
-				return -EINVAL;
-			}
-
-			if (!IS_ALIGNED(pitch, pitch_align)) {
-				dev_warn(p->dev, "%s:%d db pitch (%d, 0x%x, %d) invalid\n",
-					 __func__, __LINE__, pitch, pitch_align, array_mode);
-				return -EINVAL;
-			}
-			if (!IS_ALIGNED(height, height_align)) {
-				dev_warn(p->dev, "%s:%d db height (%d, 0x%x, %d) invalid\n",
-					 __func__, __LINE__, height, height_align, array_mode);
-				return -EINVAL;
-			}
-			if (!IS_ALIGNED(base_offset, base_align)) {
-				dev_warn(p->dev, "%s offset[%d] 0x%llx, 0x%llx, %d not aligned\n", __func__, i,
-					 base_offset, base_align, array_mode);
-				return -EINVAL;
-			}
-
-			ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
-			nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
-			tmp = ntiles * bpe * 64 * nviews;
-			if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
-				dev_warn(p->dev, "z/stencil buffer (%d) too small (0x%08X %d %d %d -> %u have %lu)\n",
-					 array_mode,
-					 track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
-					 radeon_bo_size(track->db_bo));
-				return -EINVAL;
-			}
-		}
+	if (track->db_dirty && (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
+		G_028800_Z_ENABLE(track->db_depth_control))) {
+		r = r600_cs_track_validate_db(p);
+		if (r)
+			return r;
 	}
+
 	return 0;
 }
 
@@ -939,6 +1142,7 @@
 		break;
 	case R_028800_DB_DEPTH_CONTROL:
 		track->db_depth_control = radeon_get_ib_value(p, idx);
+		track->db_dirty = true;
 		break;
 	case R_028010_DB_DEPTH_INFO:
 		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS) &&
@@ -959,24 +1163,66 @@
 				ib[idx] |= S_028010_ARRAY_MODE(V_028010_ARRAY_1D_TILED_THIN1);
 				track->db_depth_info |= S_028010_ARRAY_MODE(V_028010_ARRAY_1D_TILED_THIN1);
 			}
-		} else
+		} else {
 			track->db_depth_info = radeon_get_ib_value(p, idx);
+		}
+		track->db_dirty = true;
 		break;
 	case R_028004_DB_DEPTH_VIEW:
 		track->db_depth_view = radeon_get_ib_value(p, idx);
+		track->db_dirty = true;
 		break;
 	case R_028000_DB_DEPTH_SIZE:
 		track->db_depth_size = radeon_get_ib_value(p, idx);
 		track->db_depth_size_idx = idx;
+		track->db_dirty = true;
 		break;
 	case R_028AB0_VGT_STRMOUT_EN:
 		track->vgt_strmout_en = radeon_get_ib_value(p, idx);
+		track->streamout_dirty = true;
 		break;
 	case R_028B20_VGT_STRMOUT_BUFFER_EN:
 		track->vgt_strmout_buffer_en = radeon_get_ib_value(p, idx);
+		track->streamout_dirty = true;
+		break;
+	case VGT_STRMOUT_BUFFER_BASE_0:
+	case VGT_STRMOUT_BUFFER_BASE_1:
+	case VGT_STRMOUT_BUFFER_BASE_2:
+	case VGT_STRMOUT_BUFFER_BASE_3:
+		r = r600_cs_packet_next_reloc(p, &reloc);
+		if (r) {
+			dev_warn(p->dev, "bad SET_CONTEXT_REG "
+					"0x%04X\n", reg);
+			return -EINVAL;
+		}
+		tmp = (reg - VGT_STRMOUT_BUFFER_BASE_0) / 16;
+		track->vgt_strmout_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8;
+		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+		track->vgt_strmout_bo[tmp] = reloc->robj;
+		track->vgt_strmout_bo_mc[tmp] = reloc->lobj.gpu_offset;
+		track->streamout_dirty = true;
+		break;
+	case VGT_STRMOUT_BUFFER_SIZE_0:
+	case VGT_STRMOUT_BUFFER_SIZE_1:
+	case VGT_STRMOUT_BUFFER_SIZE_2:
+	case VGT_STRMOUT_BUFFER_SIZE_3:
+		tmp = (reg - VGT_STRMOUT_BUFFER_SIZE_0) / 16;
+		/* size in register is DWs, convert to bytes */
+		track->vgt_strmout_size[tmp] = radeon_get_ib_value(p, idx) * 4;
+		track->streamout_dirty = true;
+		break;
+	case CP_COHER_BASE:
+		r = r600_cs_packet_next_reloc(p, &reloc);
+		if (r) {
+			dev_warn(p->dev, "missing reloc for CP_COHER_BASE "
+					"0x%04X\n", reg);
+			return -EINVAL;
+		}
+		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 		break;
 	case R_028238_CB_TARGET_MASK:
 		track->cb_target_mask = radeon_get_ib_value(p, idx);
+		track->cb_dirty = true;
 		break;
 	case R_02823C_CB_SHADER_MASK:
 		track->cb_shader_mask = radeon_get_ib_value(p, idx);
@@ -984,6 +1230,7 @@
 	case R_028C04_PA_SC_AA_CONFIG:
 		tmp = G_028C04_MSAA_NUM_SAMPLES(radeon_get_ib_value(p, idx));
 		track->nsamples = 1 << tmp;
+		track->cb_dirty = true;
 		break;
 	case R_0280A0_CB_COLOR0_INFO:
 	case R_0280A4_CB_COLOR1_INFO:
@@ -1013,6 +1260,19 @@
 			tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4;
 			track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
 		}
+		track->cb_dirty = true;
+		break;
+	case R_028080_CB_COLOR0_VIEW:
+	case R_028084_CB_COLOR1_VIEW:
+	case R_028088_CB_COLOR2_VIEW:
+	case R_02808C_CB_COLOR3_VIEW:
+	case R_028090_CB_COLOR4_VIEW:
+	case R_028094_CB_COLOR5_VIEW:
+	case R_028098_CB_COLOR6_VIEW:
+	case R_02809C_CB_COLOR7_VIEW:
+		tmp = (reg - R_028080_CB_COLOR0_VIEW) / 4;
+		track->cb_color_view[tmp] = radeon_get_ib_value(p, idx);
+		track->cb_dirty = true;
 		break;
 	case R_028060_CB_COLOR0_SIZE:
 	case R_028064_CB_COLOR1_SIZE:
@@ -1025,6 +1285,7 @@
 		tmp = (reg - R_028060_CB_COLOR0_SIZE) / 4;
 		track->cb_color_size[tmp] = radeon_get_ib_value(p, idx);
 		track->cb_color_size_idx[tmp] = idx;
+		track->cb_dirty = true;
 		break;
 		/* This register were added late, there is userspace
 		 * which does provide relocation for those but set
@@ -1107,6 +1368,7 @@
 		track->cb_color_base_last[tmp] = ib[idx];
 		track->cb_color_bo[tmp] = reloc->robj;
 		track->cb_color_bo_mc[tmp] = reloc->lobj.gpu_offset;
+		track->cb_dirty = true;
 		break;
 	case DB_DEPTH_BASE:
 		r = r600_cs_packet_next_reloc(p, &reloc);
@@ -1119,8 +1381,24 @@
 		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 		track->db_bo = reloc->robj;
 		track->db_bo_mc = reloc->lobj.gpu_offset;
+		track->db_dirty = true;
 		break;
 	case DB_HTILE_DATA_BASE:
+		r = r600_cs_packet_next_reloc(p, &reloc);
+		if (r) {
+			dev_warn(p->dev, "bad SET_CONTEXT_REG "
+					"0x%04X\n", reg);
+			return -EINVAL;
+		}
+		track->htile_offset = radeon_get_ib_value(p, idx) << 8;
+		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+		track->htile_bo = reloc->robj;
+		track->db_dirty = true;
+		break;
+	case DB_HTILE_SURFACE:
+		track->htile_surface = radeon_get_ib_value(p, idx);
+		track->db_dirty = true;
+		break;
 	case SQ_PGM_START_FS:
 	case SQ_PGM_START_ES:
 	case SQ_PGM_START_VS:
@@ -1191,6 +1469,9 @@
 		}
 		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 		break;
+	case SX_MISC:
+		track->sx_misc_kill_all_prims = (radeon_get_ib_value(p, idx) & 0x1) != 0;
+		break;
 	default:
 		dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
 		return -EINVAL;
@@ -1198,7 +1479,7 @@
 	return 0;
 }
 
-static unsigned mip_minify(unsigned size, unsigned level)
+unsigned r600_mip_minify(unsigned size, unsigned level)
 {
 	unsigned val;
 
@@ -1220,22 +1501,22 @@
 	unsigned nlevels = llevel - blevel + 1;
 
 	*l0_size = -1;
-	blocksize = fmt_get_blocksize(format);
+	blocksize = r600_fmt_get_blocksize(format);
 
-	w0 = mip_minify(w0, 0);
-	h0 = mip_minify(h0, 0);
-	d0 = mip_minify(d0, 0);
+	w0 = r600_mip_minify(w0, 0);
+	h0 = r600_mip_minify(h0, 0);
+	d0 = r600_mip_minify(d0, 0);
 	for(i = 0, offset = 0, level = blevel; i < nlevels; i++, level++) {
-		width = mip_minify(w0, i);
-		nbx = fmt_get_nblocksx(format, width);
+		width = r600_mip_minify(w0, i);
+		nbx = r600_fmt_get_nblocksx(format, width);
 
 		nbx = round_up(nbx, block_align);
 
-		height = mip_minify(h0, i);
-		nby = fmt_get_nblocksy(format, height);
+		height = r600_mip_minify(h0, i);
+		nby = r600_fmt_get_nblocksy(format, height);
 		nby = round_up(nby, height_align);
 
-		depth = mip_minify(d0, i);
+		depth = r600_mip_minify(d0, i);
 
 		size = nbx * nby * blocksize;
 		if (nfaces)
@@ -1327,7 +1608,7 @@
 		return -EINVAL;
 	}
 	format = G_038004_DATA_FORMAT(word1);
-	if (!fmt_is_valid_texture(format, p->family)) {
+	if (!r600_fmt_is_valid_texture(format, p->family)) {
 		dev_warn(p->dev, "%s:%d texture invalid format %d\n",
 			 __func__, __LINE__, format);
 		return -EINVAL;
@@ -1340,7 +1621,7 @@
 	array_check.nbanks = track->nbanks;
 	array_check.npipes = track->npipes;
 	array_check.nsamples = 1;
-	array_check.blocksize = fmt_get_blocksize(format);
+	array_check.blocksize = r600_fmt_get_blocksize(format);
 	if (r600_get_array_mode_alignment(&array_check,
 					  &pitch_align, &height_align, &depth_align, &base_align)) {
 		dev_warn(p->dev, "%s:%d tex array mode (%d) invalid\n",
@@ -1373,6 +1654,10 @@
 	word1 = radeon_get_ib_value(p, idx + 5);
 	blevel = G_038010_BASE_LEVEL(word0);
 	llevel = G_038014_LAST_LEVEL(word1);
+	if (blevel > llevel) {
+		dev_warn(p->dev, "texture blevel %d > llevel %d\n",
+			 blevel, llevel);
+	}
 	if (array == 1) {
 		barray = G_038014_BASE_ARRAY(word1);
 		larray = G_038014_LAST_ARRAY(word1);
@@ -1384,8 +1669,10 @@
 			  &l0_size, &mipmap_size);
 	/* using get ib will give us the offset into the texture bo */
 	if ((l0_size + word2) > radeon_bo_size(texture)) {
-		dev_warn(p->dev, "texture bo too small (%d %d %d %d -> %d have %ld)\n",
-			w0, h0, format, word2, l0_size, radeon_bo_size(texture));
+		dev_warn(p->dev, "texture bo too small ((%d %d) (%d %d) %d %d %d -> %d have %ld)\n",
+			 w0, h0, pitch_align, height_align,
+			 array_check.array_mode, format, word2,
+			 l0_size, radeon_bo_size(texture));
 		dev_warn(p->dev, "alignments %d %d %d %lld\n", pitch, pitch_align, height_align, base_align);
 		return -EINVAL;
 	}
@@ -1398,6 +1685,22 @@
 	return 0;
 }
 
+static bool r600_is_safe_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
+{
+	u32 m, i;
+
+	i = (reg >> 7);
+	if (i >= ARRAY_SIZE(r600_reg_safe_bm)) {
+		dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
+		return false;
+	}
+	m = 1 << ((reg >> 2) & 31);
+	if (!(r600_reg_safe_bm[i] & m))
+		return true;
+	dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
+	return false;
+}
+
 static int r600_packet3_check(struct radeon_cs_parser *p,
 				struct radeon_cs_packet *pkt)
 {
@@ -1420,6 +1723,8 @@
 	{
 		int pred_op;
 		int tmp;
+		uint64_t offset;
+
 		if (pkt->count != 1) {
 			DRM_ERROR("bad SET PREDICATION\n");
 			return -EINVAL;
@@ -1443,8 +1748,12 @@
 			return -EINVAL;
 		}
 
-		ib[idx + 0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff);
-		ib[idx + 1] = tmp + (upper_32_bits(reloc->lobj.gpu_offset) & 0xff);
+		offset = reloc->lobj.gpu_offset +
+		         (idx_value & 0xfffffff0) +
+		         ((u64)(tmp & 0xff) << 32);
+
+		ib[idx + 0] = offset;
+		ib[idx + 1] = (tmp & 0xffffff00) | (upper_32_bits(offset) & 0xff);
 	}
 	break;
 
@@ -1468,6 +1777,8 @@
 		}
 		break;
 	case PACKET3_DRAW_INDEX:
+	{
+		uint64_t offset;
 		if (pkt->count != 3) {
 			DRM_ERROR("bad DRAW_INDEX\n");
 			return -EINVAL;
@@ -1477,14 +1788,21 @@
 			DRM_ERROR("bad DRAW_INDEX\n");
 			return -EINVAL;
 		}
-		ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff);
-		ib[idx+1] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+
+		offset = reloc->lobj.gpu_offset +
+		         idx_value +
+		         ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32);
+
+		ib[idx+0] = offset;
+		ib[idx+1] = upper_32_bits(offset) & 0xff;
+
 		r = r600_cs_track_check(p);
 		if (r) {
 			dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
 			return r;
 		}
 		break;
+	}
 	case PACKET3_DRAW_INDEX_AUTO:
 		if (pkt->count != 1) {
 			DRM_ERROR("bad DRAW_INDEX_AUTO\n");
@@ -1515,13 +1833,20 @@
 		}
 		/* bit 4 is reg (0) or mem (1) */
 		if (idx_value & 0x10) {
+			uint64_t offset;
+
 			r = r600_cs_packet_next_reloc(p, &reloc);
 			if (r) {
 				DRM_ERROR("bad WAIT_REG_MEM\n");
 				return -EINVAL;
 			}
-			ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
-			ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+
+			offset = reloc->lobj.gpu_offset +
+			         (radeon_get_ib_value(p, idx+1) & 0xfffffff0) +
+			         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
+
+			ib[idx+1] = (ib[idx+1] & 0x3) | (offset & 0xfffffff0);
+			ib[idx+2] = upper_32_bits(offset) & 0xff;
 		}
 		break;
 	case PACKET3_SURFACE_SYNC:
@@ -1546,16 +1871,25 @@
 			return -EINVAL;
 		}
 		if (pkt->count) {
+			uint64_t offset;
+
 			r = r600_cs_packet_next_reloc(p, &reloc);
 			if (r) {
 				DRM_ERROR("bad EVENT_WRITE\n");
 				return -EINVAL;
 			}
-			ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
-			ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+			offset = reloc->lobj.gpu_offset +
+			         (radeon_get_ib_value(p, idx+1) & 0xfffffff8) +
+			         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
+
+			ib[idx+1] = offset & 0xfffffff8;
+			ib[idx+2] = upper_32_bits(offset) & 0xff;
 		}
 		break;
 	case PACKET3_EVENT_WRITE_EOP:
+	{
+		uint64_t offset;
+
 		if (pkt->count != 4) {
 			DRM_ERROR("bad EVENT_WRITE_EOP\n");
 			return -EINVAL;
@@ -1565,9 +1899,15 @@
 			DRM_ERROR("bad EVENT_WRITE\n");
 			return -EINVAL;
 		}
-		ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
-		ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+
+		offset = reloc->lobj.gpu_offset +
+		         (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +
+		         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
+
+		ib[idx+1] = offset & 0xfffffffc;
+		ib[idx+2] = (ib[idx+2] & 0xffffff00) | (upper_32_bits(offset) & 0xff);
 		break;
+	}
 	case PACKET3_SET_CONFIG_REG:
 		start_reg = (idx_value << 2) + PACKET3_SET_CONFIG_REG_OFFSET;
 		end_reg = 4 * pkt->count + start_reg - 4;
@@ -1652,6 +1992,8 @@
 				ib[idx+1+(i*7)+3] += mip_offset;
 				break;
 			case SQ_TEX_VTX_VALID_BUFFER:
+			{
+				uint64_t offset64;
 				/* vtx base */
 				r = r600_cs_packet_next_reloc(p, &reloc);
 				if (r) {
@@ -1664,11 +2006,15 @@
 					/* force size to size of the buffer */
 					dev_warn(p->dev, "vbo resource seems too big (%d) for the bo (%ld)\n",
 						 size + offset, radeon_bo_size(reloc->robj));
-					ib[idx+1+(i*7)+1] = radeon_bo_size(reloc->robj);
+					ib[idx+1+(i*7)+1] = radeon_bo_size(reloc->robj) - offset;
 				}
-				ib[idx+1+(i*7)+0] += (u32)((reloc->lobj.gpu_offset) & 0xffffffff);
-				ib[idx+1+(i*7)+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+
+				offset64 = reloc->lobj.gpu_offset + offset;
+				ib[idx+1+(i*8)+0] = offset64;
+				ib[idx+1+(i*8)+2] = (ib[idx+1+(i*8)+2] & 0xffffff00) |
+						    (upper_32_bits(offset64) & 0xff);
 				break;
+			}
 			case SQ_TEX_VTX_INVALID_TEXTURE:
 			case SQ_TEX_VTX_INVALID_BUFFER:
 			default:
@@ -1743,6 +2089,104 @@
 			return -EINVAL;
 		}
 		break;
+	case PACKET3_STRMOUT_BUFFER_UPDATE:
+		if (pkt->count != 4) {
+			DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (invalid count)\n");
+			return -EINVAL;
+		}
+		/* Updating memory at DST_ADDRESS. */
+		if (idx_value & 0x1) {
+			u64 offset;
+			r = r600_cs_packet_next_reloc(p, &reloc);
+			if (r) {
+				DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing dst reloc)\n");
+				return -EINVAL;
+			}
+			offset = radeon_get_ib_value(p, idx+1);
+			offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
+			if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+				DRM_ERROR("bad STRMOUT_BUFFER_UPDATE dst bo too small: 0x%llx, 0x%lx\n",
+					  offset + 4, radeon_bo_size(reloc->robj));
+				return -EINVAL;
+			}
+			offset += reloc->lobj.gpu_offset;
+			ib[idx+1] = offset;
+			ib[idx+2] = upper_32_bits(offset) & 0xff;
+		}
+		/* Reading data from SRC_ADDRESS. */
+		if (((idx_value >> 1) & 0x3) == 2) {
+			u64 offset;
+			r = r600_cs_packet_next_reloc(p, &reloc);
+			if (r) {
+				DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing src reloc)\n");
+				return -EINVAL;
+			}
+			offset = radeon_get_ib_value(p, idx+3);
+			offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+			if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+				DRM_ERROR("bad STRMOUT_BUFFER_UPDATE src bo too small: 0x%llx, 0x%lx\n",
+					  offset + 4, radeon_bo_size(reloc->robj));
+				return -EINVAL;
+			}
+			offset += reloc->lobj.gpu_offset;
+			ib[idx+3] = offset;
+			ib[idx+4] = upper_32_bits(offset) & 0xff;
+		}
+		break;
+	case PACKET3_COPY_DW:
+		if (pkt->count != 4) {
+			DRM_ERROR("bad COPY_DW (invalid count)\n");
+			return -EINVAL;
+		}
+		if (idx_value & 0x1) {
+			u64 offset;
+			/* SRC is memory. */
+			r = r600_cs_packet_next_reloc(p, &reloc);
+			if (r) {
+				DRM_ERROR("bad COPY_DW (missing src reloc)\n");
+				return -EINVAL;
+			}
+			offset = radeon_get_ib_value(p, idx+1);
+			offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
+			if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+				DRM_ERROR("bad COPY_DW src bo too small: 0x%llx, 0x%lx\n",
+					  offset + 4, radeon_bo_size(reloc->robj));
+				return -EINVAL;
+			}
+			offset += reloc->lobj.gpu_offset;
+			ib[idx+1] = offset;
+			ib[idx+2] = upper_32_bits(offset) & 0xff;
+		} else {
+			/* SRC is a reg. */
+			reg = radeon_get_ib_value(p, idx+1) << 2;
+			if (!r600_is_safe_reg(p, reg, idx+1))
+				return -EINVAL;
+		}
+		if (idx_value & 0x2) {
+			u64 offset;
+			/* DST is memory. */
+			r = r600_cs_packet_next_reloc(p, &reloc);
+			if (r) {
+				DRM_ERROR("bad COPY_DW (missing dst reloc)\n");
+				return -EINVAL;
+			}
+			offset = radeon_get_ib_value(p, idx+3);
+			offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+			if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+				DRM_ERROR("bad COPY_DW dst bo too small: 0x%llx, 0x%lx\n",
+					  offset + 4, radeon_bo_size(reloc->robj));
+				return -EINVAL;
+			}
+			offset += reloc->lobj.gpu_offset;
+			ib[idx+3] = offset;
+			ib[idx+4] = upper_32_bits(offset) & 0xff;
+		} else {
+			/* DST is a reg. */
+			reg = radeon_get_ib_value(p, idx+3) << 2;
+			if (!r600_is_safe_reg(p, reg, idx+3))
+				return -EINVAL;
+		}
+		break;
 	case PACKET3_NOP:
 		break;
 	default:
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index 9b23670..59f9c99 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -78,6 +78,20 @@
 
 #define CB_COLOR0_SIZE                                  0x28060
 #define CB_COLOR0_VIEW                                  0x28080
+#define R_028080_CB_COLOR0_VIEW                      0x028080
+#define   S_028080_SLICE_START(x)                      (((x) & 0x7FF) << 0)
+#define   G_028080_SLICE_START(x)                      (((x) >> 0) & 0x7FF)
+#define   C_028080_SLICE_START                         0xFFFFF800
+#define   S_028080_SLICE_MAX(x)                        (((x) & 0x7FF) << 13)
+#define   G_028080_SLICE_MAX(x)                        (((x) >> 13) & 0x7FF)
+#define   C_028080_SLICE_MAX                           0xFF001FFF
+#define R_028084_CB_COLOR1_VIEW                      0x028084
+#define R_028088_CB_COLOR2_VIEW                      0x028088
+#define R_02808C_CB_COLOR3_VIEW                      0x02808C
+#define R_028090_CB_COLOR4_VIEW                      0x028090
+#define R_028094_CB_COLOR5_VIEW                      0x028094
+#define R_028098_CB_COLOR6_VIEW                      0x028098
+#define R_02809C_CB_COLOR7_VIEW                      0x02809C
 #define CB_COLOR0_INFO                                  0x280a0
 #	define CB_FORMAT(x)				((x) << 2)
 #       define CB_ARRAY_MODE(x)                         ((x) << 8)
@@ -181,6 +195,14 @@
 #define		PREZ_MUST_WAIT_FOR_POSTZ_DONE			(1 << 31)
 #define	DB_DEPTH_BASE					0x2800C
 #define	DB_HTILE_DATA_BASE				0x28014
+#define	DB_HTILE_SURFACE				0x28D24
+#define   S_028D24_HTILE_WIDTH(x)                      (((x) & 0x1) << 0)
+#define   G_028D24_HTILE_WIDTH(x)                      (((x) >> 0) & 0x1)
+#define   C_028D24_HTILE_WIDTH                         0xFFFFFFFE
+#define   S_028D24_HTILE_HEIGHT(x)                      (((x) & 0x1) << 1)
+#define   G_028D24_HTILE_HEIGHT(x)                      (((x) >> 1) & 0x1)
+#define   C_028D24_HTILE_HEIGHT                         0xFFFFFFFD
+#define   G_028D24_LINEAR(x)                           (((x) >> 2) & 0x1)
 #define	DB_WATERMARKS					0x9838
 #define		DEPTH_FREE(x)					((x) << 0)
 #define		DEPTH_FLUSH(x)					((x) << 5)
@@ -493,6 +515,11 @@
 #define	VGT_STRMOUT_BUFFER_OFFSET_1			0x28AEC
 #define	VGT_STRMOUT_BUFFER_OFFSET_2			0x28AFC
 #define	VGT_STRMOUT_BUFFER_OFFSET_3			0x28B0C
+#define VGT_STRMOUT_BUFFER_SIZE_0			0x28AD0
+#define VGT_STRMOUT_BUFFER_SIZE_1			0x28AE0
+#define VGT_STRMOUT_BUFFER_SIZE_2			0x28AF0
+#define VGT_STRMOUT_BUFFER_SIZE_3			0x28B00
+
 #define	VGT_STRMOUT_EN					0x28AB0
 #define	VGT_VERTEX_REUSE_BLOCK_CNTL			0x28C58
 #define		VTX_REUSE_DEPTH_MASK				0x000000FF
@@ -574,6 +601,10 @@
 #define RLC_UCODE_ADDR                                    0x3f2c
 #define RLC_UCODE_DATA                                    0x3f30
 
+/* new for TN */
+#define TN_RLC_SAVE_AND_RESTORE_BASE                      0x3f10
+#define TN_RLC_CLEAR_STATE_RESTORE_BASE                   0x3f20
+
 #define SRBM_SOFT_RESET                                   0xe60
 #       define SOFT_RESET_RLC                             (1 << 13)
 
@@ -835,6 +866,7 @@
 #              define PACKET3_SEM_SEL_SIGNAL	    (0x6 << 29)
 #              define PACKET3_SEM_SEL_WAIT	    (0x7 << 29)
 #define	PACKET3_MPEG_INDEX				0x3A
+#define	PACKET3_COPY_DW					0x3B
 #define	PACKET3_WAIT_REG_MEM				0x3C
 #define	PACKET3_MEM_WRITE				0x3D
 #define	PACKET3_INDIRECT_BUFFER				0x32
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 1668ec1..138b952 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -236,12 +236,15 @@
 void radeon_combios_get_power_modes(struct radeon_device *rdev);
 void radeon_atombios_get_power_modes(struct radeon_device *rdev);
 void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type);
-int radeon_atom_get_max_vddc(struct radeon_device *rdev, u16 *voltage);
 void rs690_pm_info(struct radeon_device *rdev);
 extern int rv6xx_get_temp(struct radeon_device *rdev);
 extern int rv770_get_temp(struct radeon_device *rdev);
 extern int evergreen_get_temp(struct radeon_device *rdev);
 extern int sumo_get_temp(struct radeon_device *rdev);
+extern int si_get_temp(struct radeon_device *rdev);
+extern void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw,
+				    unsigned *bankh, unsigned *mtaspect,
+				    unsigned *tile_split);
 
 /*
  * Fences.
@@ -411,9 +414,6 @@
 				int alignment, int initial_domain,
 				bool discardable, bool kernel,
 				struct drm_gem_object **obj);
-int radeon_gem_object_pin(struct drm_gem_object *obj, uint32_t pin_domain,
-			  uint64_t *gpu_addr);
-void radeon_gem_object_unpin(struct drm_gem_object *obj);
 
 int radeon_mode_dumb_create(struct drm_file *file_priv,
 			    struct drm_device *dev,
@@ -632,6 +632,7 @@
 	uint32_t		*ptr;
 	struct radeon_fence	*fence;
 	unsigned		vm_id;
+	bool			is_const_ib;
 };
 
 /*
@@ -771,6 +772,18 @@
 
 void r600_blit_suspend(struct radeon_device *rdev);
 
+/*
+ * SI RLC stuff
+ */
+struct si_rlc {
+	/* for power gating */
+	struct radeon_bo	*save_restore_obj;
+	uint64_t		save_restore_gpu_addr;
+	/* for clear state */
+	struct radeon_bo	*clear_state_obj;
+	uint64_t		clear_state_gpu_addr;
+};
+
 int radeon_ib_get(struct radeon_device *rdev, int ring,
 		  struct radeon_ib **ib, unsigned size);
 void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib);
@@ -780,7 +793,6 @@
 void radeon_ib_pool_fini(struct radeon_device *rdev);
 int radeon_ib_pool_start(struct radeon_device *rdev);
 int radeon_ib_pool_suspend(struct radeon_device *rdev);
-int radeon_ib_test(struct radeon_device *rdev);
 /* Ring access between begin & end cannot sleep */
 int radeon_ring_index(struct radeon_device *rdev, struct radeon_ring *cp);
 void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *cp);
@@ -833,12 +845,13 @@
 	struct radeon_cs_reloc	*relocs;
 	struct radeon_cs_reloc	**relocs_ptr;
 	struct list_head	validated;
-	bool			sync_to_ring[RADEON_NUM_RINGS];
 	/* indices of various chunks */
 	int			chunk_ib_idx;
 	int			chunk_relocs_idx;
 	int			chunk_flags_idx;
+	int			chunk_const_ib_idx;
 	struct radeon_ib	*ib;
+	struct radeon_ib	*const_ib;
 	void			*track;
 	unsigned		family;
 	int			parser_error;
@@ -980,6 +993,7 @@
 	THERMAL_TYPE_EVERGREEN,
 	THERMAL_TYPE_SUMO,
 	THERMAL_TYPE_NI,
+	THERMAL_TYPE_SI,
 };
 
 struct radeon_voltage {
@@ -1132,57 +1146,6 @@
 	void (*vga_set_state)(struct radeon_device *rdev, bool state);
 	bool (*gpu_is_lockup)(struct radeon_device *rdev, struct radeon_ring *cp);
 	int (*asic_reset)(struct radeon_device *rdev);
-	void (*gart_tlb_flush)(struct radeon_device *rdev);
-	int (*gart_set_page)(struct radeon_device *rdev, int i, uint64_t addr);
-	int (*cp_init)(struct radeon_device *rdev, unsigned ring_size);
-	void (*cp_fini)(struct radeon_device *rdev);
-	void (*cp_disable)(struct radeon_device *rdev);
-	void (*ring_start)(struct radeon_device *rdev);
-
-	struct {
-		void (*ib_execute)(struct radeon_device *rdev, struct radeon_ib *ib);
-		int (*ib_parse)(struct radeon_device *rdev, struct radeon_ib *ib);
-		void (*emit_fence)(struct radeon_device *rdev, struct radeon_fence *fence);
-		void (*emit_semaphore)(struct radeon_device *rdev, struct radeon_ring *cp,
-				       struct radeon_semaphore *semaphore, bool emit_wait);
-	} ring[RADEON_NUM_RINGS];
-
-	int (*ring_test)(struct radeon_device *rdev, struct radeon_ring *cp);
-	int (*irq_set)(struct radeon_device *rdev);
-	int (*irq_process)(struct radeon_device *rdev);
-	u32 (*get_vblank_counter)(struct radeon_device *rdev, int crtc);
-	int (*cs_parse)(struct radeon_cs_parser *p);
-	int (*copy_blit)(struct radeon_device *rdev,
-			 uint64_t src_offset,
-			 uint64_t dst_offset,
-			 unsigned num_gpu_pages,
-			 struct radeon_fence *fence);
-	int (*copy_dma)(struct radeon_device *rdev,
-			uint64_t src_offset,
-			uint64_t dst_offset,
-			unsigned num_gpu_pages,
-			struct radeon_fence *fence);
-	int (*copy)(struct radeon_device *rdev,
-		    uint64_t src_offset,
-		    uint64_t dst_offset,
-		    unsigned num_gpu_pages,
-		    struct radeon_fence *fence);
-	uint32_t (*get_engine_clock)(struct radeon_device *rdev);
-	void (*set_engine_clock)(struct radeon_device *rdev, uint32_t eng_clock);
-	uint32_t (*get_memory_clock)(struct radeon_device *rdev);
-	void (*set_memory_clock)(struct radeon_device *rdev, uint32_t mem_clock);
-	int (*get_pcie_lanes)(struct radeon_device *rdev);
-	void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes);
-	void (*set_clock_gating)(struct radeon_device *rdev, int enable);
-	int (*set_surface_reg)(struct radeon_device *rdev, int reg,
-			       uint32_t tiling_flags, uint32_t pitch,
-			       uint32_t offset, uint32_t obj_size);
-	void (*clear_surface_reg)(struct radeon_device *rdev, int reg);
-	void (*bandwidth_update)(struct radeon_device *rdev);
-	void (*hpd_init)(struct radeon_device *rdev);
-	void (*hpd_fini)(struct radeon_device *rdev);
-	bool (*hpd_sense)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
-	void (*hpd_set_polarity)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
 	/* ioctl hw specific callback. Some hw might want to perform special
 	 * operation on specific ioctl. For instance on wait idle some hw
 	 * might want to perform and HDP flush through MMIO as it seems that
@@ -1190,17 +1153,99 @@
 	 * through ring.
 	 */
 	void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo);
+	/* check if 3D engine is idle */
 	bool (*gui_idle)(struct radeon_device *rdev);
+	/* wait for mc_idle */
+	int (*mc_wait_for_idle)(struct radeon_device *rdev);
+	/* gart */
+	struct {
+		void (*tlb_flush)(struct radeon_device *rdev);
+		int (*set_page)(struct radeon_device *rdev, int i, uint64_t addr);
+	} gart;
+	/* ring specific callbacks */
+	struct {
+		void (*ib_execute)(struct radeon_device *rdev, struct radeon_ib *ib);
+		int (*ib_parse)(struct radeon_device *rdev, struct radeon_ib *ib);
+		void (*emit_fence)(struct radeon_device *rdev, struct radeon_fence *fence);
+		void (*emit_semaphore)(struct radeon_device *rdev, struct radeon_ring *cp,
+				       struct radeon_semaphore *semaphore, bool emit_wait);
+		int (*cs_parse)(struct radeon_cs_parser *p);
+		void (*ring_start)(struct radeon_device *rdev, struct radeon_ring *cp);
+		int (*ring_test)(struct radeon_device *rdev, struct radeon_ring *cp);
+		int (*ib_test)(struct radeon_device *rdev, struct radeon_ring *cp);
+	} ring[RADEON_NUM_RINGS];
+	/* irqs */
+	struct {
+		int (*set)(struct radeon_device *rdev);
+		int (*process)(struct radeon_device *rdev);
+	} irq;
+	/* displays */
+	struct {
+		/* display watermarks */
+		void (*bandwidth_update)(struct radeon_device *rdev);
+		/* get frame count */
+		u32 (*get_vblank_counter)(struct radeon_device *rdev, int crtc);
+		/* wait for vblank */
+		void (*wait_for_vblank)(struct radeon_device *rdev, int crtc);
+	} display;
+	/* copy functions for bo handling */
+	struct {
+		int (*blit)(struct radeon_device *rdev,
+			    uint64_t src_offset,
+			    uint64_t dst_offset,
+			    unsigned num_gpu_pages,
+			    struct radeon_fence *fence);
+		u32 blit_ring_index;
+		int (*dma)(struct radeon_device *rdev,
+			   uint64_t src_offset,
+			   uint64_t dst_offset,
+			   unsigned num_gpu_pages,
+			   struct radeon_fence *fence);
+		u32 dma_ring_index;
+		/* method used for bo copy */
+		int (*copy)(struct radeon_device *rdev,
+			    uint64_t src_offset,
+			    uint64_t dst_offset,
+			    unsigned num_gpu_pages,
+			    struct radeon_fence *fence);
+		/* ring used for bo copies */
+		u32 copy_ring_index;
+	} copy;
+	/* surfaces */
+	struct {
+		int (*set_reg)(struct radeon_device *rdev, int reg,
+				       uint32_t tiling_flags, uint32_t pitch,
+				       uint32_t offset, uint32_t obj_size);
+		void (*clear_reg)(struct radeon_device *rdev, int reg);
+	} surface;
+	/* hotplug detect */
+	struct {
+		void (*init)(struct radeon_device *rdev);
+		void (*fini)(struct radeon_device *rdev);
+		bool (*sense)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
+		void (*set_polarity)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
+	} hpd;
 	/* power management */
-	void (*pm_misc)(struct radeon_device *rdev);
-	void (*pm_prepare)(struct radeon_device *rdev);
-	void (*pm_finish)(struct radeon_device *rdev);
-	void (*pm_init_profile)(struct radeon_device *rdev);
-	void (*pm_get_dynpm_state)(struct radeon_device *rdev);
+	struct {
+		void (*misc)(struct radeon_device *rdev);
+		void (*prepare)(struct radeon_device *rdev);
+		void (*finish)(struct radeon_device *rdev);
+		void (*init_profile)(struct radeon_device *rdev);
+		void (*get_dynpm_state)(struct radeon_device *rdev);
+		uint32_t (*get_engine_clock)(struct radeon_device *rdev);
+		void (*set_engine_clock)(struct radeon_device *rdev, uint32_t eng_clock);
+		uint32_t (*get_memory_clock)(struct radeon_device *rdev);
+		void (*set_memory_clock)(struct radeon_device *rdev, uint32_t mem_clock);
+		int (*get_pcie_lanes)(struct radeon_device *rdev);
+		void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes);
+		void (*set_clock_gating)(struct radeon_device *rdev, int enable);
+	} pm;
 	/* pageflipping */
-	void (*pre_page_flip)(struct radeon_device *rdev, int crtc);
-	u32 (*page_flip)(struct radeon_device *rdev, int crtc, u64 crtc_base);
-	void (*post_page_flip)(struct radeon_device *rdev, int crtc);
+	struct {
+		void (*pre_page_flip)(struct radeon_device *rdev, int crtc);
+		u32 (*page_flip)(struct radeon_device *rdev, int crtc, u64 crtc_base);
+		void (*post_page_flip)(struct radeon_device *rdev, int crtc);
+	} pflip;
 };
 
 /*
@@ -1340,6 +1385,37 @@
 	struct r100_gpu_lockup	lockup;
 };
 
+struct si_asic {
+	unsigned max_shader_engines;
+	unsigned max_pipes_per_simd;
+	unsigned max_tile_pipes;
+	unsigned max_simds_per_se;
+	unsigned max_backends_per_se;
+	unsigned max_texture_channel_caches;
+	unsigned max_gprs;
+	unsigned max_gs_threads;
+	unsigned max_hw_contexts;
+	unsigned sc_prim_fifo_size_frontend;
+	unsigned sc_prim_fifo_size_backend;
+	unsigned sc_hiz_tile_fifo_size;
+	unsigned sc_earlyz_tile_fifo_size;
+
+	unsigned num_shader_engines;
+	unsigned num_tile_pipes;
+	unsigned num_backends_per_se;
+	unsigned backend_disable_mask_per_asic;
+	unsigned backend_map;
+	unsigned num_texture_channel_caches;
+	unsigned mem_max_burst_length_bytes;
+	unsigned mem_row_size_in_kb;
+	unsigned shader_engine_tile_size;
+	unsigned num_gpus;
+	unsigned multi_gpu_tile_size;
+
+	unsigned tile_config;
+	struct r100_gpu_lockup	lockup;
+};
+
 union radeon_asic_config {
 	struct r300_asic	r300;
 	struct r100_asic	r100;
@@ -1347,6 +1423,7 @@
 	struct rv770_asic	rv770;
 	struct evergreen_asic	evergreen;
 	struct cayman_asic	cayman;
+	struct si_asic		si;
 };
 
 /*
@@ -1462,10 +1539,12 @@
 	const struct firmware *pfp_fw;	/* r6/700 PFP firmware */
 	const struct firmware *rlc_fw;	/* r6/700 RLC firmware */
 	const struct firmware *mc_fw;	/* NI MC firmware */
+	const struct firmware *ce_fw;	/* SI CE firmware */
 	struct r600_blit r600_blit;
 	struct r600_vram_scratch vram_scratch;
 	int msi_enabled; /* msi enabled */
 	struct r600_ih ih; /* r6/700 interrupt ring */
+	struct si_rlc rlc;
 	struct work_struct hotplug_work;
 	int num_crtc; /* number of crtcs */
 	struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
@@ -1491,8 +1570,6 @@
 	unsigned 		debugfs_count;
 	/* virtual memory */
 	struct radeon_vm_manager	vm_manager;
-	/* ring used for bo copies */
-	u32				copy_ring;
 };
 
 int radeon_device_init(struct radeon_device *rdev,
@@ -1611,6 +1688,9 @@
 #define ASIC_IS_DCE41(rdev) ((rdev->family >= CHIP_PALM) && \
 			     (rdev->flags & RADEON_IS_IGP))
 #define ASIC_IS_DCE5(rdev) ((rdev->family >= CHIP_BARTS))
+#define ASIC_IS_DCE6(rdev) ((rdev->family >= CHIP_ARUBA))
+#define ASIC_IS_DCE61(rdev) ((rdev->family >= CHIP_ARUBA) && \
+			     (rdev->flags & RADEON_IS_IGP))
 
 /*
  * BIOS helpers.
@@ -1648,47 +1728,53 @@
 #define radeon_fini(rdev) (rdev)->asic->fini((rdev))
 #define radeon_resume(rdev) (rdev)->asic->resume((rdev))
 #define radeon_suspend(rdev) (rdev)->asic->suspend((rdev))
-#define radeon_cs_parse(p) rdev->asic->cs_parse((p))
+#define radeon_cs_parse(rdev, r, p) (rdev)->asic->ring[(r)].cs_parse((p))
 #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state))
 #define radeon_gpu_is_lockup(rdev, cp) (rdev)->asic->gpu_is_lockup((rdev), (cp))
 #define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev))
-#define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart_tlb_flush((rdev))
-#define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart_set_page((rdev), (i), (p))
-#define radeon_ring_start(rdev) (rdev)->asic->ring_start((rdev))
-#define radeon_ring_test(rdev, cp) (rdev)->asic->ring_test((rdev), (cp))
+#define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart.tlb_flush((rdev))
+#define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart.set_page((rdev), (i), (p))
+#define radeon_ring_start(rdev, r, cp) (rdev)->asic->ring[(r)].ring_start((rdev), (cp))
+#define radeon_ring_test(rdev, r, cp) (rdev)->asic->ring[(r)].ring_test((rdev), (cp))
+#define radeon_ib_test(rdev, r, cp) (rdev)->asic->ring[(r)].ib_test((rdev), (cp))
 #define radeon_ring_ib_execute(rdev, r, ib) (rdev)->asic->ring[(r)].ib_execute((rdev), (ib))
 #define radeon_ring_ib_parse(rdev, r, ib) (rdev)->asic->ring[(r)].ib_parse((rdev), (ib))
-#define radeon_irq_set(rdev) (rdev)->asic->irq_set((rdev))
-#define radeon_irq_process(rdev) (rdev)->asic->irq_process((rdev))
-#define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->get_vblank_counter((rdev), (crtc))
+#define radeon_irq_set(rdev) (rdev)->asic->irq.set((rdev))
+#define radeon_irq_process(rdev) (rdev)->asic->irq.process((rdev))
+#define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->display.get_vblank_counter((rdev), (crtc))
 #define radeon_fence_ring_emit(rdev, r, fence) (rdev)->asic->ring[(r)].emit_fence((rdev), (fence))
 #define radeon_semaphore_ring_emit(rdev, r, cp, semaphore, emit_wait) (rdev)->asic->ring[(r)].emit_semaphore((rdev), (cp), (semaphore), (emit_wait))
-#define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy_blit((rdev), (s), (d), (np), (f))
-#define radeon_copy_dma(rdev, s, d, np, f) (rdev)->asic->copy_dma((rdev), (s), (d), (np), (f))
-#define radeon_copy(rdev, s, d, np, f) (rdev)->asic->copy((rdev), (s), (d), (np), (f))
-#define radeon_get_engine_clock(rdev) (rdev)->asic->get_engine_clock((rdev))
-#define radeon_set_engine_clock(rdev, e) (rdev)->asic->set_engine_clock((rdev), (e))
-#define radeon_get_memory_clock(rdev) (rdev)->asic->get_memory_clock((rdev))
-#define radeon_set_memory_clock(rdev, e) (rdev)->asic->set_memory_clock((rdev), (e))
-#define radeon_get_pcie_lanes(rdev) (rdev)->asic->get_pcie_lanes((rdev))
-#define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->set_pcie_lanes((rdev), (l))
-#define radeon_set_clock_gating(rdev, e) (rdev)->asic->set_clock_gating((rdev), (e))
-#define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->set_surface_reg((rdev), (r), (f), (p), (o), (s)))
-#define radeon_clear_surface_reg(rdev, r) ((rdev)->asic->clear_surface_reg((rdev), (r)))
-#define radeon_bandwidth_update(rdev) (rdev)->asic->bandwidth_update((rdev))
-#define radeon_hpd_init(rdev) (rdev)->asic->hpd_init((rdev))
-#define radeon_hpd_fini(rdev) (rdev)->asic->hpd_fini((rdev))
-#define radeon_hpd_sense(rdev, hpd) (rdev)->asic->hpd_sense((rdev), (hpd))
-#define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd))
+#define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy.blit((rdev), (s), (d), (np), (f))
+#define radeon_copy_dma(rdev, s, d, np, f) (rdev)->asic->copy.dma((rdev), (s), (d), (np), (f))
+#define radeon_copy(rdev, s, d, np, f) (rdev)->asic->copy.copy((rdev), (s), (d), (np), (f))
+#define radeon_copy_blit_ring_index(rdev) (rdev)->asic->copy.blit_ring_index
+#define radeon_copy_dma_ring_index(rdev) (rdev)->asic->copy.dma_ring_index
+#define radeon_copy_ring_index(rdev) (rdev)->asic->copy.copy_ring_index
+#define radeon_get_engine_clock(rdev) (rdev)->asic->pm.get_engine_clock((rdev))
+#define radeon_set_engine_clock(rdev, e) (rdev)->asic->pm.set_engine_clock((rdev), (e))
+#define radeon_get_memory_clock(rdev) (rdev)->asic->pm.get_memory_clock((rdev))
+#define radeon_set_memory_clock(rdev, e) (rdev)->asic->pm.set_memory_clock((rdev), (e))
+#define radeon_get_pcie_lanes(rdev) (rdev)->asic->pm.get_pcie_lanes((rdev))
+#define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->pm.set_pcie_lanes((rdev), (l))
+#define radeon_set_clock_gating(rdev, e) (rdev)->asic->pm.set_clock_gating((rdev), (e))
+#define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->surface.set_reg((rdev), (r), (f), (p), (o), (s)))
+#define radeon_clear_surface_reg(rdev, r) ((rdev)->asic->surface.clear_reg((rdev), (r)))
+#define radeon_bandwidth_update(rdev) (rdev)->asic->display.bandwidth_update((rdev))
+#define radeon_hpd_init(rdev) (rdev)->asic->hpd.init((rdev))
+#define radeon_hpd_fini(rdev) (rdev)->asic->hpd.fini((rdev))
+#define radeon_hpd_sense(rdev, h) (rdev)->asic->hpd.sense((rdev), (h))
+#define radeon_hpd_set_polarity(rdev, h) (rdev)->asic->hpd.set_polarity((rdev), (h))
 #define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev))
-#define radeon_pm_misc(rdev) (rdev)->asic->pm_misc((rdev))
-#define radeon_pm_prepare(rdev) (rdev)->asic->pm_prepare((rdev))
-#define radeon_pm_finish(rdev) (rdev)->asic->pm_finish((rdev))
-#define radeon_pm_init_profile(rdev) (rdev)->asic->pm_init_profile((rdev))
-#define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm_get_dynpm_state((rdev))
-#define radeon_pre_page_flip(rdev, crtc) rdev->asic->pre_page_flip((rdev), (crtc))
-#define radeon_page_flip(rdev, crtc, base) rdev->asic->page_flip((rdev), (crtc), (base))
-#define radeon_post_page_flip(rdev, crtc) rdev->asic->post_page_flip((rdev), (crtc))
+#define radeon_pm_misc(rdev) (rdev)->asic->pm.misc((rdev))
+#define radeon_pm_prepare(rdev) (rdev)->asic->pm.prepare((rdev))
+#define radeon_pm_finish(rdev) (rdev)->asic->pm.finish((rdev))
+#define radeon_pm_init_profile(rdev) (rdev)->asic->pm.init_profile((rdev))
+#define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm.get_dynpm_state((rdev))
+#define radeon_pre_page_flip(rdev, crtc) rdev->asic->pflip.pre_page_flip((rdev), (crtc))
+#define radeon_page_flip(rdev, crtc, base) rdev->asic->pflip.page_flip((rdev), (crtc), (base))
+#define radeon_post_page_flip(rdev, crtc) rdev->asic->pflip.post_page_flip((rdev), (crtc))
+#define radeon_wait_for_vblank(rdev, crtc) rdev->asic->display.wait_for_vblank((rdev), (crtc))
+#define radeon_mc_wait_for_idle(rdev) rdev->asic->mc_wait_for_idle((rdev))
 
 /* Common functions */
 /* AGP */
@@ -1750,6 +1836,16 @@
 void r600_vram_scratch_fini(struct radeon_device *rdev);
 
 /*
+ * r600 cs checking helper
+ */
+unsigned r600_mip_minify(unsigned size, unsigned level);
+bool r600_fmt_is_valid_color(u32 format);
+bool r600_fmt_is_valid_texture(u32 format, enum radeon_family family);
+int r600_fmt_get_blocksize(u32 format);
+int r600_fmt_get_nblocksx(u32 format, u32 w);
+int r600_fmt_get_nblocksy(u32 format, u32 h);
+
+/*
  * r600 functions used by radeon_encoder.c
  */
 extern void r600_hdmi_enable(struct drm_encoder *encoder);
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 36a6192..be4dc2f 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -114,13 +114,13 @@
 			rdev->family == CHIP_R423) {
 		DRM_INFO("Forcing AGP to PCIE mode\n");
 		rdev->flags |= RADEON_IS_PCIE;
-		rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush;
-		rdev->asic->gart_set_page = &rv370_pcie_gart_set_page;
+		rdev->asic->gart.tlb_flush = &rv370_pcie_gart_tlb_flush;
+		rdev->asic->gart.set_page = &rv370_pcie_gart_set_page;
 	} else {
 		DRM_INFO("Forcing AGP to PCI mode\n");
 		rdev->flags |= RADEON_IS_PCI;
-		rdev->asic->gart_tlb_flush = &r100_pci_gart_tlb_flush;
-		rdev->asic->gart_set_page = &r100_pci_gart_set_page;
+		rdev->asic->gart.tlb_flush = &r100_pci_gart_tlb_flush;
+		rdev->asic->gart.set_page = &r100_pci_gart_set_page;
 	}
 	rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
 }
@@ -136,48 +136,70 @@
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r100_gpu_is_lockup,
 	.asic_reset = &r100_asic_reset,
-	.gart_tlb_flush = &r100_pci_gart_tlb_flush,
-	.gart_set_page = &r100_pci_gart_set_page,
-	.ring_start = &r100_ring_start,
-	.ring_test = &r100_ring_test,
+	.ioctl_wait_idle = NULL,
+	.gui_idle = &r100_gui_idle,
+	.mc_wait_for_idle = &r100_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &r100_pci_gart_tlb_flush,
+		.set_page = &r100_pci_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &r100_ring_ib_execute,
 			.emit_fence = &r100_fence_ring_emit,
 			.emit_semaphore = &r100_semaphore_ring_emit,
+			.cs_parse = &r100_cs_parse,
+			.ring_start = &r100_ring_start,
+			.ring_test = &r100_ring_test,
+			.ib_test = &r100_ib_test,
 		}
 	},
-	.irq_set = &r100_irq_set,
-	.irq_process = &r100_irq_process,
-	.get_vblank_counter = &r100_get_vblank_counter,
-	.cs_parse = &r100_cs_parse,
-	.copy_blit = &r100_copy_blit,
-	.copy_dma = NULL,
-	.copy = &r100_copy_blit,
-	.get_engine_clock = &radeon_legacy_get_engine_clock,
-	.set_engine_clock = &radeon_legacy_set_engine_clock,
-	.get_memory_clock = &radeon_legacy_get_memory_clock,
-	.set_memory_clock = NULL,
-	.get_pcie_lanes = NULL,
-	.set_pcie_lanes = NULL,
-	.set_clock_gating = &radeon_legacy_set_clock_gating,
-	.set_surface_reg = r100_set_surface_reg,
-	.clear_surface_reg = r100_clear_surface_reg,
-	.bandwidth_update = &r100_bandwidth_update,
-	.hpd_init = &r100_hpd_init,
-	.hpd_fini = &r100_hpd_fini,
-	.hpd_sense = &r100_hpd_sense,
-	.hpd_set_polarity = &r100_hpd_set_polarity,
-	.ioctl_wait_idle = NULL,
-	.gui_idle = &r100_gui_idle,
-	.pm_misc = &r100_pm_misc,
-	.pm_prepare = &r100_pm_prepare,
-	.pm_finish = &r100_pm_finish,
-	.pm_init_profile = &r100_pm_init_profile,
-	.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
-	.pre_page_flip = &r100_pre_page_flip,
-	.page_flip = &r100_page_flip,
-	.post_page_flip = &r100_post_page_flip,
+	.irq = {
+		.set = &r100_irq_set,
+		.process = &r100_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &r100_bandwidth_update,
+		.get_vblank_counter = &r100_get_vblank_counter,
+		.wait_for_vblank = &r100_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r100_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = NULL,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r100_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r100_set_surface_reg,
+		.clear_reg = r100_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &r100_hpd_init,
+		.fini = &r100_hpd_fini,
+		.sense = &r100_hpd_sense,
+		.set_polarity = &r100_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &r100_pm_misc,
+		.prepare = &r100_pm_prepare,
+		.finish = &r100_pm_finish,
+		.init_profile = &r100_pm_init_profile,
+		.get_dynpm_state = &r100_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_legacy_get_engine_clock,
+		.set_engine_clock = &radeon_legacy_set_engine_clock,
+		.get_memory_clock = &radeon_legacy_get_memory_clock,
+		.set_memory_clock = NULL,
+		.get_pcie_lanes = NULL,
+		.set_pcie_lanes = NULL,
+		.set_clock_gating = &radeon_legacy_set_clock_gating,
+	},
+	.pflip = {
+		.pre_page_flip = &r100_pre_page_flip,
+		.page_flip = &r100_page_flip,
+		.post_page_flip = &r100_post_page_flip,
+	},
 };
 
 static struct radeon_asic r200_asic = {
@@ -188,47 +210,70 @@
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r100_gpu_is_lockup,
 	.asic_reset = &r100_asic_reset,
-	.gart_tlb_flush = &r100_pci_gart_tlb_flush,
-	.gart_set_page = &r100_pci_gart_set_page,
-	.ring_start = &r100_ring_start,
-	.ring_test = &r100_ring_test,
+	.ioctl_wait_idle = NULL,
+	.gui_idle = &r100_gui_idle,
+	.mc_wait_for_idle = &r100_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &r100_pci_gart_tlb_flush,
+		.set_page = &r100_pci_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &r100_ring_ib_execute,
 			.emit_fence = &r100_fence_ring_emit,
 			.emit_semaphore = &r100_semaphore_ring_emit,
+			.cs_parse = &r100_cs_parse,
+			.ring_start = &r100_ring_start,
+			.ring_test = &r100_ring_test,
+			.ib_test = &r100_ib_test,
 		}
 	},
-	.irq_set = &r100_irq_set,
-	.irq_process = &r100_irq_process,
-	.get_vblank_counter = &r100_get_vblank_counter,
-	.cs_parse = &r100_cs_parse,
-	.copy_blit = &r100_copy_blit,
-	.copy_dma = &r200_copy_dma,
-	.copy = &r100_copy_blit,
-	.get_engine_clock = &radeon_legacy_get_engine_clock,
-	.set_engine_clock = &radeon_legacy_set_engine_clock,
-	.get_memory_clock = &radeon_legacy_get_memory_clock,
-	.set_memory_clock = NULL,
-	.set_pcie_lanes = NULL,
-	.set_clock_gating = &radeon_legacy_set_clock_gating,
-	.set_surface_reg = r100_set_surface_reg,
-	.clear_surface_reg = r100_clear_surface_reg,
-	.bandwidth_update = &r100_bandwidth_update,
-	.hpd_init = &r100_hpd_init,
-	.hpd_fini = &r100_hpd_fini,
-	.hpd_sense = &r100_hpd_sense,
-	.hpd_set_polarity = &r100_hpd_set_polarity,
-	.ioctl_wait_idle = NULL,
-	.gui_idle = &r100_gui_idle,
-	.pm_misc = &r100_pm_misc,
-	.pm_prepare = &r100_pm_prepare,
-	.pm_finish = &r100_pm_finish,
-	.pm_init_profile = &r100_pm_init_profile,
-	.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
-	.pre_page_flip = &r100_pre_page_flip,
-	.page_flip = &r100_page_flip,
-	.post_page_flip = &r100_post_page_flip,
+	.irq = {
+		.set = &r100_irq_set,
+		.process = &r100_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &r100_bandwidth_update,
+		.get_vblank_counter = &r100_get_vblank_counter,
+		.wait_for_vblank = &r100_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r100_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = &r200_copy_dma,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r100_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r100_set_surface_reg,
+		.clear_reg = r100_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &r100_hpd_init,
+		.fini = &r100_hpd_fini,
+		.sense = &r100_hpd_sense,
+		.set_polarity = &r100_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &r100_pm_misc,
+		.prepare = &r100_pm_prepare,
+		.finish = &r100_pm_finish,
+		.init_profile = &r100_pm_init_profile,
+		.get_dynpm_state = &r100_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_legacy_get_engine_clock,
+		.set_engine_clock = &radeon_legacy_set_engine_clock,
+		.get_memory_clock = &radeon_legacy_get_memory_clock,
+		.set_memory_clock = NULL,
+		.get_pcie_lanes = NULL,
+		.set_pcie_lanes = NULL,
+		.set_clock_gating = &radeon_legacy_set_clock_gating,
+	},
+	.pflip = {
+		.pre_page_flip = &r100_pre_page_flip,
+		.page_flip = &r100_page_flip,
+		.post_page_flip = &r100_post_page_flip,
+	},
 };
 
 static struct radeon_asic r300_asic = {
@@ -239,48 +284,70 @@
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.asic_reset = &r300_asic_reset,
-	.gart_tlb_flush = &r100_pci_gart_tlb_flush,
-	.gart_set_page = &r100_pci_gart_set_page,
-	.ring_start = &r300_ring_start,
-	.ring_test = &r100_ring_test,
+	.ioctl_wait_idle = NULL,
+	.gui_idle = &r100_gui_idle,
+	.mc_wait_for_idle = &r300_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &r100_pci_gart_tlb_flush,
+		.set_page = &r100_pci_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &r100_ring_ib_execute,
 			.emit_fence = &r300_fence_ring_emit,
 			.emit_semaphore = &r100_semaphore_ring_emit,
+			.cs_parse = &r300_cs_parse,
+			.ring_start = &r300_ring_start,
+			.ring_test = &r100_ring_test,
+			.ib_test = &r100_ib_test,
 		}
 	},
-	.irq_set = &r100_irq_set,
-	.irq_process = &r100_irq_process,
-	.get_vblank_counter = &r100_get_vblank_counter,
-	.cs_parse = &r300_cs_parse,
-	.copy_blit = &r100_copy_blit,
-	.copy_dma = &r200_copy_dma,
-	.copy = &r100_copy_blit,
-	.get_engine_clock = &radeon_legacy_get_engine_clock,
-	.set_engine_clock = &radeon_legacy_set_engine_clock,
-	.get_memory_clock = &radeon_legacy_get_memory_clock,
-	.set_memory_clock = NULL,
-	.get_pcie_lanes = &rv370_get_pcie_lanes,
-	.set_pcie_lanes = &rv370_set_pcie_lanes,
-	.set_clock_gating = &radeon_legacy_set_clock_gating,
-	.set_surface_reg = r100_set_surface_reg,
-	.clear_surface_reg = r100_clear_surface_reg,
-	.bandwidth_update = &r100_bandwidth_update,
-	.hpd_init = &r100_hpd_init,
-	.hpd_fini = &r100_hpd_fini,
-	.hpd_sense = &r100_hpd_sense,
-	.hpd_set_polarity = &r100_hpd_set_polarity,
-	.ioctl_wait_idle = NULL,
-	.gui_idle = &r100_gui_idle,
-	.pm_misc = &r100_pm_misc,
-	.pm_prepare = &r100_pm_prepare,
-	.pm_finish = &r100_pm_finish,
-	.pm_init_profile = &r100_pm_init_profile,
-	.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
-	.pre_page_flip = &r100_pre_page_flip,
-	.page_flip = &r100_page_flip,
-	.post_page_flip = &r100_post_page_flip,
+	.irq = {
+		.set = &r100_irq_set,
+		.process = &r100_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &r100_bandwidth_update,
+		.get_vblank_counter = &r100_get_vblank_counter,
+		.wait_for_vblank = &r100_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r100_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = &r200_copy_dma,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r100_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r100_set_surface_reg,
+		.clear_reg = r100_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &r100_hpd_init,
+		.fini = &r100_hpd_fini,
+		.sense = &r100_hpd_sense,
+		.set_polarity = &r100_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &r100_pm_misc,
+		.prepare = &r100_pm_prepare,
+		.finish = &r100_pm_finish,
+		.init_profile = &r100_pm_init_profile,
+		.get_dynpm_state = &r100_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_legacy_get_engine_clock,
+		.set_engine_clock = &radeon_legacy_set_engine_clock,
+		.get_memory_clock = &radeon_legacy_get_memory_clock,
+		.set_memory_clock = NULL,
+		.get_pcie_lanes = &rv370_get_pcie_lanes,
+		.set_pcie_lanes = &rv370_set_pcie_lanes,
+		.set_clock_gating = &radeon_legacy_set_clock_gating,
+	},
+	.pflip = {
+		.pre_page_flip = &r100_pre_page_flip,
+		.page_flip = &r100_page_flip,
+		.post_page_flip = &r100_post_page_flip,
+	},
 };
 
 static struct radeon_asic r300_asic_pcie = {
@@ -291,47 +358,70 @@
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.asic_reset = &r300_asic_reset,
-	.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
-	.gart_set_page = &rv370_pcie_gart_set_page,
-	.ring_start = &r300_ring_start,
-	.ring_test = &r100_ring_test,
+	.ioctl_wait_idle = NULL,
+	.gui_idle = &r100_gui_idle,
+	.mc_wait_for_idle = &r300_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &rv370_pcie_gart_tlb_flush,
+		.set_page = &rv370_pcie_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &r100_ring_ib_execute,
 			.emit_fence = &r300_fence_ring_emit,
 			.emit_semaphore = &r100_semaphore_ring_emit,
+			.cs_parse = &r300_cs_parse,
+			.ring_start = &r300_ring_start,
+			.ring_test = &r100_ring_test,
+			.ib_test = &r100_ib_test,
 		}
 	},
-	.irq_set = &r100_irq_set,
-	.irq_process = &r100_irq_process,
-	.get_vblank_counter = &r100_get_vblank_counter,
-	.cs_parse = &r300_cs_parse,
-	.copy_blit = &r100_copy_blit,
-	.copy_dma = &r200_copy_dma,
-	.copy = &r100_copy_blit,
-	.get_engine_clock = &radeon_legacy_get_engine_clock,
-	.set_engine_clock = &radeon_legacy_set_engine_clock,
-	.get_memory_clock = &radeon_legacy_get_memory_clock,
-	.set_memory_clock = NULL,
-	.set_pcie_lanes = &rv370_set_pcie_lanes,
-	.set_clock_gating = &radeon_legacy_set_clock_gating,
-	.set_surface_reg = r100_set_surface_reg,
-	.clear_surface_reg = r100_clear_surface_reg,
-	.bandwidth_update = &r100_bandwidth_update,
-	.hpd_init = &r100_hpd_init,
-	.hpd_fini = &r100_hpd_fini,
-	.hpd_sense = &r100_hpd_sense,
-	.hpd_set_polarity = &r100_hpd_set_polarity,
-	.ioctl_wait_idle = NULL,
-	.gui_idle = &r100_gui_idle,
-	.pm_misc = &r100_pm_misc,
-	.pm_prepare = &r100_pm_prepare,
-	.pm_finish = &r100_pm_finish,
-	.pm_init_profile = &r100_pm_init_profile,
-	.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
-	.pre_page_flip = &r100_pre_page_flip,
-	.page_flip = &r100_page_flip,
-	.post_page_flip = &r100_post_page_flip,
+	.irq = {
+		.set = &r100_irq_set,
+		.process = &r100_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &r100_bandwidth_update,
+		.get_vblank_counter = &r100_get_vblank_counter,
+		.wait_for_vblank = &r100_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r100_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = &r200_copy_dma,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r100_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r100_set_surface_reg,
+		.clear_reg = r100_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &r100_hpd_init,
+		.fini = &r100_hpd_fini,
+		.sense = &r100_hpd_sense,
+		.set_polarity = &r100_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &r100_pm_misc,
+		.prepare = &r100_pm_prepare,
+		.finish = &r100_pm_finish,
+		.init_profile = &r100_pm_init_profile,
+		.get_dynpm_state = &r100_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_legacy_get_engine_clock,
+		.set_engine_clock = &radeon_legacy_set_engine_clock,
+		.get_memory_clock = &radeon_legacy_get_memory_clock,
+		.set_memory_clock = NULL,
+		.get_pcie_lanes = &rv370_get_pcie_lanes,
+		.set_pcie_lanes = &rv370_set_pcie_lanes,
+		.set_clock_gating = &radeon_legacy_set_clock_gating,
+	},
+	.pflip = {
+		.pre_page_flip = &r100_pre_page_flip,
+		.page_flip = &r100_page_flip,
+		.post_page_flip = &r100_post_page_flip,
+	},
 };
 
 static struct radeon_asic r420_asic = {
@@ -342,48 +432,70 @@
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.asic_reset = &r300_asic_reset,
-	.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
-	.gart_set_page = &rv370_pcie_gart_set_page,
-	.ring_start = &r300_ring_start,
-	.ring_test = &r100_ring_test,
+	.ioctl_wait_idle = NULL,
+	.gui_idle = &r100_gui_idle,
+	.mc_wait_for_idle = &r300_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &rv370_pcie_gart_tlb_flush,
+		.set_page = &rv370_pcie_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &r100_ring_ib_execute,
 			.emit_fence = &r300_fence_ring_emit,
 			.emit_semaphore = &r100_semaphore_ring_emit,
+			.cs_parse = &r300_cs_parse,
+			.ring_start = &r300_ring_start,
+			.ring_test = &r100_ring_test,
+			.ib_test = &r100_ib_test,
 		}
 	},
-	.irq_set = &r100_irq_set,
-	.irq_process = &r100_irq_process,
-	.get_vblank_counter = &r100_get_vblank_counter,
-	.cs_parse = &r300_cs_parse,
-	.copy_blit = &r100_copy_blit,
-	.copy_dma = &r200_copy_dma,
-	.copy = &r100_copy_blit,
-	.get_engine_clock = &radeon_atom_get_engine_clock,
-	.set_engine_clock = &radeon_atom_set_engine_clock,
-	.get_memory_clock = &radeon_atom_get_memory_clock,
-	.set_memory_clock = &radeon_atom_set_memory_clock,
-	.get_pcie_lanes = &rv370_get_pcie_lanes,
-	.set_pcie_lanes = &rv370_set_pcie_lanes,
-	.set_clock_gating = &radeon_atom_set_clock_gating,
-	.set_surface_reg = r100_set_surface_reg,
-	.clear_surface_reg = r100_clear_surface_reg,
-	.bandwidth_update = &r100_bandwidth_update,
-	.hpd_init = &r100_hpd_init,
-	.hpd_fini = &r100_hpd_fini,
-	.hpd_sense = &r100_hpd_sense,
-	.hpd_set_polarity = &r100_hpd_set_polarity,
-	.ioctl_wait_idle = NULL,
-	.gui_idle = &r100_gui_idle,
-	.pm_misc = &r100_pm_misc,
-	.pm_prepare = &r100_pm_prepare,
-	.pm_finish = &r100_pm_finish,
-	.pm_init_profile = &r420_pm_init_profile,
-	.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
-	.pre_page_flip = &r100_pre_page_flip,
-	.page_flip = &r100_page_flip,
-	.post_page_flip = &r100_post_page_flip,
+	.irq = {
+		.set = &r100_irq_set,
+		.process = &r100_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &r100_bandwidth_update,
+		.get_vblank_counter = &r100_get_vblank_counter,
+		.wait_for_vblank = &r100_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r100_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = &r200_copy_dma,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r100_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r100_set_surface_reg,
+		.clear_reg = r100_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &r100_hpd_init,
+		.fini = &r100_hpd_fini,
+		.sense = &r100_hpd_sense,
+		.set_polarity = &r100_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &r100_pm_misc,
+		.prepare = &r100_pm_prepare,
+		.finish = &r100_pm_finish,
+		.init_profile = &r420_pm_init_profile,
+		.get_dynpm_state = &r100_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = &rv370_get_pcie_lanes,
+		.set_pcie_lanes = &rv370_set_pcie_lanes,
+		.set_clock_gating = &radeon_atom_set_clock_gating,
+	},
+	.pflip = {
+		.pre_page_flip = &r100_pre_page_flip,
+		.page_flip = &r100_page_flip,
+		.post_page_flip = &r100_post_page_flip,
+	},
 };
 
 static struct radeon_asic rs400_asic = {
@@ -394,48 +506,70 @@
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.asic_reset = &r300_asic_reset,
-	.gart_tlb_flush = &rs400_gart_tlb_flush,
-	.gart_set_page = &rs400_gart_set_page,
-	.ring_start = &r300_ring_start,
-	.ring_test = &r100_ring_test,
+	.ioctl_wait_idle = NULL,
+	.gui_idle = &r100_gui_idle,
+	.mc_wait_for_idle = &rs400_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &rs400_gart_tlb_flush,
+		.set_page = &rs400_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &r100_ring_ib_execute,
 			.emit_fence = &r300_fence_ring_emit,
 			.emit_semaphore = &r100_semaphore_ring_emit,
+			.cs_parse = &r300_cs_parse,
+			.ring_start = &r300_ring_start,
+			.ring_test = &r100_ring_test,
+			.ib_test = &r100_ib_test,
 		}
 	},
-	.irq_set = &r100_irq_set,
-	.irq_process = &r100_irq_process,
-	.get_vblank_counter = &r100_get_vblank_counter,
-	.cs_parse = &r300_cs_parse,
-	.copy_blit = &r100_copy_blit,
-	.copy_dma = &r200_copy_dma,
-	.copy = &r100_copy_blit,
-	.get_engine_clock = &radeon_legacy_get_engine_clock,
-	.set_engine_clock = &radeon_legacy_set_engine_clock,
-	.get_memory_clock = &radeon_legacy_get_memory_clock,
-	.set_memory_clock = NULL,
-	.get_pcie_lanes = NULL,
-	.set_pcie_lanes = NULL,
-	.set_clock_gating = &radeon_legacy_set_clock_gating,
-	.set_surface_reg = r100_set_surface_reg,
-	.clear_surface_reg = r100_clear_surface_reg,
-	.bandwidth_update = &r100_bandwidth_update,
-	.hpd_init = &r100_hpd_init,
-	.hpd_fini = &r100_hpd_fini,
-	.hpd_sense = &r100_hpd_sense,
-	.hpd_set_polarity = &r100_hpd_set_polarity,
-	.ioctl_wait_idle = NULL,
-	.gui_idle = &r100_gui_idle,
-	.pm_misc = &r100_pm_misc,
-	.pm_prepare = &r100_pm_prepare,
-	.pm_finish = &r100_pm_finish,
-	.pm_init_profile = &r100_pm_init_profile,
-	.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
-	.pre_page_flip = &r100_pre_page_flip,
-	.page_flip = &r100_page_flip,
-	.post_page_flip = &r100_post_page_flip,
+	.irq = {
+		.set = &r100_irq_set,
+		.process = &r100_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &r100_bandwidth_update,
+		.get_vblank_counter = &r100_get_vblank_counter,
+		.wait_for_vblank = &r100_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r100_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = &r200_copy_dma,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r100_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r100_set_surface_reg,
+		.clear_reg = r100_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &r100_hpd_init,
+		.fini = &r100_hpd_fini,
+		.sense = &r100_hpd_sense,
+		.set_polarity = &r100_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &r100_pm_misc,
+		.prepare = &r100_pm_prepare,
+		.finish = &r100_pm_finish,
+		.init_profile = &r100_pm_init_profile,
+		.get_dynpm_state = &r100_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_legacy_get_engine_clock,
+		.set_engine_clock = &radeon_legacy_set_engine_clock,
+		.get_memory_clock = &radeon_legacy_get_memory_clock,
+		.set_memory_clock = NULL,
+		.get_pcie_lanes = NULL,
+		.set_pcie_lanes = NULL,
+		.set_clock_gating = &radeon_legacy_set_clock_gating,
+	},
+	.pflip = {
+		.pre_page_flip = &r100_pre_page_flip,
+		.page_flip = &r100_page_flip,
+		.post_page_flip = &r100_post_page_flip,
+	},
 };
 
 static struct radeon_asic rs600_asic = {
@@ -446,48 +580,70 @@
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.asic_reset = &rs600_asic_reset,
-	.gart_tlb_flush = &rs600_gart_tlb_flush,
-	.gart_set_page = &rs600_gart_set_page,
-	.ring_start = &r300_ring_start,
-	.ring_test = &r100_ring_test,
+	.ioctl_wait_idle = NULL,
+	.gui_idle = &r100_gui_idle,
+	.mc_wait_for_idle = &rs600_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &rs600_gart_tlb_flush,
+		.set_page = &rs600_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &r100_ring_ib_execute,
 			.emit_fence = &r300_fence_ring_emit,
 			.emit_semaphore = &r100_semaphore_ring_emit,
+			.cs_parse = &r300_cs_parse,
+			.ring_start = &r300_ring_start,
+			.ring_test = &r100_ring_test,
+			.ib_test = &r100_ib_test,
 		}
 	},
-	.irq_set = &rs600_irq_set,
-	.irq_process = &rs600_irq_process,
-	.get_vblank_counter = &rs600_get_vblank_counter,
-	.cs_parse = &r300_cs_parse,
-	.copy_blit = &r100_copy_blit,
-	.copy_dma = &r200_copy_dma,
-	.copy = &r100_copy_blit,
-	.get_engine_clock = &radeon_atom_get_engine_clock,
-	.set_engine_clock = &radeon_atom_set_engine_clock,
-	.get_memory_clock = &radeon_atom_get_memory_clock,
-	.set_memory_clock = &radeon_atom_set_memory_clock,
-	.get_pcie_lanes = NULL,
-	.set_pcie_lanes = NULL,
-	.set_clock_gating = &radeon_atom_set_clock_gating,
-	.set_surface_reg = r100_set_surface_reg,
-	.clear_surface_reg = r100_clear_surface_reg,
-	.bandwidth_update = &rs600_bandwidth_update,
-	.hpd_init = &rs600_hpd_init,
-	.hpd_fini = &rs600_hpd_fini,
-	.hpd_sense = &rs600_hpd_sense,
-	.hpd_set_polarity = &rs600_hpd_set_polarity,
-	.ioctl_wait_idle = NULL,
-	.gui_idle = &r100_gui_idle,
-	.pm_misc = &rs600_pm_misc,
-	.pm_prepare = &rs600_pm_prepare,
-	.pm_finish = &rs600_pm_finish,
-	.pm_init_profile = &r420_pm_init_profile,
-	.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
-	.pre_page_flip = &rs600_pre_page_flip,
-	.page_flip = &rs600_page_flip,
-	.post_page_flip = &rs600_post_page_flip,
+	.irq = {
+		.set = &rs600_irq_set,
+		.process = &rs600_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &rs600_bandwidth_update,
+		.get_vblank_counter = &rs600_get_vblank_counter,
+		.wait_for_vblank = &avivo_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r100_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = &r200_copy_dma,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r100_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r100_set_surface_reg,
+		.clear_reg = r100_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &rs600_hpd_init,
+		.fini = &rs600_hpd_fini,
+		.sense = &rs600_hpd_sense,
+		.set_polarity = &rs600_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &rs600_pm_misc,
+		.prepare = &rs600_pm_prepare,
+		.finish = &rs600_pm_finish,
+		.init_profile = &r420_pm_init_profile,
+		.get_dynpm_state = &r100_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = NULL,
+		.set_pcie_lanes = NULL,
+		.set_clock_gating = &radeon_atom_set_clock_gating,
+	},
+	.pflip = {
+		.pre_page_flip = &rs600_pre_page_flip,
+		.page_flip = &rs600_page_flip,
+		.post_page_flip = &rs600_post_page_flip,
+	},
 };
 
 static struct radeon_asic rs690_asic = {
@@ -498,48 +654,70 @@
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.asic_reset = &rs600_asic_reset,
-	.gart_tlb_flush = &rs400_gart_tlb_flush,
-	.gart_set_page = &rs400_gart_set_page,
-	.ring_start = &r300_ring_start,
-	.ring_test = &r100_ring_test,
+	.ioctl_wait_idle = NULL,
+	.gui_idle = &r100_gui_idle,
+	.mc_wait_for_idle = &rs690_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &rs400_gart_tlb_flush,
+		.set_page = &rs400_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &r100_ring_ib_execute,
 			.emit_fence = &r300_fence_ring_emit,
 			.emit_semaphore = &r100_semaphore_ring_emit,
+			.cs_parse = &r300_cs_parse,
+			.ring_start = &r300_ring_start,
+			.ring_test = &r100_ring_test,
+			.ib_test = &r100_ib_test,
 		}
 	},
-	.irq_set = &rs600_irq_set,
-	.irq_process = &rs600_irq_process,
-	.get_vblank_counter = &rs600_get_vblank_counter,
-	.cs_parse = &r300_cs_parse,
-	.copy_blit = &r100_copy_blit,
-	.copy_dma = &r200_copy_dma,
-	.copy = &r200_copy_dma,
-	.get_engine_clock = &radeon_atom_get_engine_clock,
-	.set_engine_clock = &radeon_atom_set_engine_clock,
-	.get_memory_clock = &radeon_atom_get_memory_clock,
-	.set_memory_clock = &radeon_atom_set_memory_clock,
-	.get_pcie_lanes = NULL,
-	.set_pcie_lanes = NULL,
-	.set_clock_gating = &radeon_atom_set_clock_gating,
-	.set_surface_reg = r100_set_surface_reg,
-	.clear_surface_reg = r100_clear_surface_reg,
-	.bandwidth_update = &rs690_bandwidth_update,
-	.hpd_init = &rs600_hpd_init,
-	.hpd_fini = &rs600_hpd_fini,
-	.hpd_sense = &rs600_hpd_sense,
-	.hpd_set_polarity = &rs600_hpd_set_polarity,
-	.ioctl_wait_idle = NULL,
-	.gui_idle = &r100_gui_idle,
-	.pm_misc = &rs600_pm_misc,
-	.pm_prepare = &rs600_pm_prepare,
-	.pm_finish = &rs600_pm_finish,
-	.pm_init_profile = &r420_pm_init_profile,
-	.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
-	.pre_page_flip = &rs600_pre_page_flip,
-	.page_flip = &rs600_page_flip,
-	.post_page_flip = &rs600_post_page_flip,
+	.irq = {
+		.set = &rs600_irq_set,
+		.process = &rs600_irq_process,
+	},
+	.display = {
+		.get_vblank_counter = &rs600_get_vblank_counter,
+		.bandwidth_update = &rs690_bandwidth_update,
+		.wait_for_vblank = &avivo_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r100_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = &r200_copy_dma,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r200_copy_dma,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r100_set_surface_reg,
+		.clear_reg = r100_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &rs600_hpd_init,
+		.fini = &rs600_hpd_fini,
+		.sense = &rs600_hpd_sense,
+		.set_polarity = &rs600_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &rs600_pm_misc,
+		.prepare = &rs600_pm_prepare,
+		.finish = &rs600_pm_finish,
+		.init_profile = &r420_pm_init_profile,
+		.get_dynpm_state = &r100_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = NULL,
+		.set_pcie_lanes = NULL,
+		.set_clock_gating = &radeon_atom_set_clock_gating,
+	},
+	.pflip = {
+		.pre_page_flip = &rs600_pre_page_flip,
+		.page_flip = &rs600_page_flip,
+		.post_page_flip = &rs600_post_page_flip,
+	},
 };
 
 static struct radeon_asic rv515_asic = {
@@ -550,48 +728,70 @@
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.asic_reset = &rs600_asic_reset,
-	.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
-	.gart_set_page = &rv370_pcie_gart_set_page,
-	.ring_start = &rv515_ring_start,
-	.ring_test = &r100_ring_test,
+	.ioctl_wait_idle = NULL,
+	.gui_idle = &r100_gui_idle,
+	.mc_wait_for_idle = &rv515_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &rv370_pcie_gart_tlb_flush,
+		.set_page = &rv370_pcie_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &r100_ring_ib_execute,
 			.emit_fence = &r300_fence_ring_emit,
 			.emit_semaphore = &r100_semaphore_ring_emit,
+			.cs_parse = &r300_cs_parse,
+			.ring_start = &rv515_ring_start,
+			.ring_test = &r100_ring_test,
+			.ib_test = &r100_ib_test,
 		}
 	},
-	.irq_set = &rs600_irq_set,
-	.irq_process = &rs600_irq_process,
-	.get_vblank_counter = &rs600_get_vblank_counter,
-	.cs_parse = &r300_cs_parse,
-	.copy_blit = &r100_copy_blit,
-	.copy_dma = &r200_copy_dma,
-	.copy = &r100_copy_blit,
-	.get_engine_clock = &radeon_atom_get_engine_clock,
-	.set_engine_clock = &radeon_atom_set_engine_clock,
-	.get_memory_clock = &radeon_atom_get_memory_clock,
-	.set_memory_clock = &radeon_atom_set_memory_clock,
-	.get_pcie_lanes = &rv370_get_pcie_lanes,
-	.set_pcie_lanes = &rv370_set_pcie_lanes,
-	.set_clock_gating = &radeon_atom_set_clock_gating,
-	.set_surface_reg = r100_set_surface_reg,
-	.clear_surface_reg = r100_clear_surface_reg,
-	.bandwidth_update = &rv515_bandwidth_update,
-	.hpd_init = &rs600_hpd_init,
-	.hpd_fini = &rs600_hpd_fini,
-	.hpd_sense = &rs600_hpd_sense,
-	.hpd_set_polarity = &rs600_hpd_set_polarity,
-	.ioctl_wait_idle = NULL,
-	.gui_idle = &r100_gui_idle,
-	.pm_misc = &rs600_pm_misc,
-	.pm_prepare = &rs600_pm_prepare,
-	.pm_finish = &rs600_pm_finish,
-	.pm_init_profile = &r420_pm_init_profile,
-	.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
-	.pre_page_flip = &rs600_pre_page_flip,
-	.page_flip = &rs600_page_flip,
-	.post_page_flip = &rs600_post_page_flip,
+	.irq = {
+		.set = &rs600_irq_set,
+		.process = &rs600_irq_process,
+	},
+	.display = {
+		.get_vblank_counter = &rs600_get_vblank_counter,
+		.bandwidth_update = &rv515_bandwidth_update,
+		.wait_for_vblank = &avivo_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r100_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = &r200_copy_dma,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r100_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r100_set_surface_reg,
+		.clear_reg = r100_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &rs600_hpd_init,
+		.fini = &rs600_hpd_fini,
+		.sense = &rs600_hpd_sense,
+		.set_polarity = &rs600_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &rs600_pm_misc,
+		.prepare = &rs600_pm_prepare,
+		.finish = &rs600_pm_finish,
+		.init_profile = &r420_pm_init_profile,
+		.get_dynpm_state = &r100_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = &rv370_get_pcie_lanes,
+		.set_pcie_lanes = &rv370_set_pcie_lanes,
+		.set_clock_gating = &radeon_atom_set_clock_gating,
+	},
+	.pflip = {
+		.pre_page_flip = &rs600_pre_page_flip,
+		.page_flip = &rs600_page_flip,
+		.post_page_flip = &rs600_post_page_flip,
+	},
 };
 
 static struct radeon_asic r520_asic = {
@@ -602,48 +802,70 @@
 	.vga_set_state = &r100_vga_set_state,
 	.gpu_is_lockup = &r300_gpu_is_lockup,
 	.asic_reset = &rs600_asic_reset,
-	.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
-	.gart_set_page = &rv370_pcie_gart_set_page,
-	.ring_start = &rv515_ring_start,
-	.ring_test = &r100_ring_test,
+	.ioctl_wait_idle = NULL,
+	.gui_idle = &r100_gui_idle,
+	.mc_wait_for_idle = &r520_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &rv370_pcie_gart_tlb_flush,
+		.set_page = &rv370_pcie_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &r100_ring_ib_execute,
 			.emit_fence = &r300_fence_ring_emit,
 			.emit_semaphore = &r100_semaphore_ring_emit,
+			.cs_parse = &r300_cs_parse,
+			.ring_start = &rv515_ring_start,
+			.ring_test = &r100_ring_test,
+			.ib_test = &r100_ib_test,
 		}
 	},
-	.irq_set = &rs600_irq_set,
-	.irq_process = &rs600_irq_process,
-	.get_vblank_counter = &rs600_get_vblank_counter,
-	.cs_parse = &r300_cs_parse,
-	.copy_blit = &r100_copy_blit,
-	.copy_dma = &r200_copy_dma,
-	.copy = &r100_copy_blit,
-	.get_engine_clock = &radeon_atom_get_engine_clock,
-	.set_engine_clock = &radeon_atom_set_engine_clock,
-	.get_memory_clock = &radeon_atom_get_memory_clock,
-	.set_memory_clock = &radeon_atom_set_memory_clock,
-	.get_pcie_lanes = &rv370_get_pcie_lanes,
-	.set_pcie_lanes = &rv370_set_pcie_lanes,
-	.set_clock_gating = &radeon_atom_set_clock_gating,
-	.set_surface_reg = r100_set_surface_reg,
-	.clear_surface_reg = r100_clear_surface_reg,
-	.bandwidth_update = &rv515_bandwidth_update,
-	.hpd_init = &rs600_hpd_init,
-	.hpd_fini = &rs600_hpd_fini,
-	.hpd_sense = &rs600_hpd_sense,
-	.hpd_set_polarity = &rs600_hpd_set_polarity,
-	.ioctl_wait_idle = NULL,
-	.gui_idle = &r100_gui_idle,
-	.pm_misc = &rs600_pm_misc,
-	.pm_prepare = &rs600_pm_prepare,
-	.pm_finish = &rs600_pm_finish,
-	.pm_init_profile = &r420_pm_init_profile,
-	.pm_get_dynpm_state = &r100_pm_get_dynpm_state,
-	.pre_page_flip = &rs600_pre_page_flip,
-	.page_flip = &rs600_page_flip,
-	.post_page_flip = &rs600_post_page_flip,
+	.irq = {
+		.set = &rs600_irq_set,
+		.process = &rs600_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &rv515_bandwidth_update,
+		.get_vblank_counter = &rs600_get_vblank_counter,
+		.wait_for_vblank = &avivo_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r100_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = &r200_copy_dma,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r100_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r100_set_surface_reg,
+		.clear_reg = r100_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &rs600_hpd_init,
+		.fini = &rs600_hpd_fini,
+		.sense = &rs600_hpd_sense,
+		.set_polarity = &rs600_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &rs600_pm_misc,
+		.prepare = &rs600_pm_prepare,
+		.finish = &rs600_pm_finish,
+		.init_profile = &r420_pm_init_profile,
+		.get_dynpm_state = &r100_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = &rv370_get_pcie_lanes,
+		.set_pcie_lanes = &rv370_set_pcie_lanes,
+		.set_clock_gating = &radeon_atom_set_clock_gating,
+	},
+	.pflip = {
+		.pre_page_flip = &rs600_pre_page_flip,
+		.page_flip = &rs600_page_flip,
+		.post_page_flip = &rs600_post_page_flip,
+	},
 };
 
 static struct radeon_asic r600_asic = {
@@ -654,47 +876,69 @@
 	.vga_set_state = &r600_vga_set_state,
 	.gpu_is_lockup = &r600_gpu_is_lockup,
 	.asic_reset = &r600_asic_reset,
-	.gart_tlb_flush = &r600_pcie_gart_tlb_flush,
-	.gart_set_page = &rs600_gart_set_page,
-	.ring_test = &r600_ring_test,
+	.ioctl_wait_idle = r600_ioctl_wait_idle,
+	.gui_idle = &r600_gui_idle,
+	.mc_wait_for_idle = &r600_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &r600_pcie_gart_tlb_flush,
+		.set_page = &rs600_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &r600_ring_ib_execute,
 			.emit_fence = &r600_fence_ring_emit,
 			.emit_semaphore = &r600_semaphore_ring_emit,
+			.cs_parse = &r600_cs_parse,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
 		}
 	},
-	.irq_set = &r600_irq_set,
-	.irq_process = &r600_irq_process,
-	.get_vblank_counter = &rs600_get_vblank_counter,
-	.cs_parse = &r600_cs_parse,
-	.copy_blit = &r600_copy_blit,
-	.copy_dma = NULL,
-	.copy = &r600_copy_blit,
-	.get_engine_clock = &radeon_atom_get_engine_clock,
-	.set_engine_clock = &radeon_atom_set_engine_clock,
-	.get_memory_clock = &radeon_atom_get_memory_clock,
-	.set_memory_clock = &radeon_atom_set_memory_clock,
-	.get_pcie_lanes = &r600_get_pcie_lanes,
-	.set_pcie_lanes = &r600_set_pcie_lanes,
-	.set_clock_gating = NULL,
-	.set_surface_reg = r600_set_surface_reg,
-	.clear_surface_reg = r600_clear_surface_reg,
-	.bandwidth_update = &rv515_bandwidth_update,
-	.hpd_init = &r600_hpd_init,
-	.hpd_fini = &r600_hpd_fini,
-	.hpd_sense = &r600_hpd_sense,
-	.hpd_set_polarity = &r600_hpd_set_polarity,
-	.ioctl_wait_idle = r600_ioctl_wait_idle,
-	.gui_idle = &r600_gui_idle,
-	.pm_misc = &r600_pm_misc,
-	.pm_prepare = &rs600_pm_prepare,
-	.pm_finish = &rs600_pm_finish,
-	.pm_init_profile = &r600_pm_init_profile,
-	.pm_get_dynpm_state = &r600_pm_get_dynpm_state,
-	.pre_page_flip = &rs600_pre_page_flip,
-	.page_flip = &rs600_page_flip,
-	.post_page_flip = &rs600_post_page_flip,
+	.irq = {
+		.set = &r600_irq_set,
+		.process = &r600_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &rv515_bandwidth_update,
+		.get_vblank_counter = &rs600_get_vblank_counter,
+		.wait_for_vblank = &avivo_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r600_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = NULL,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r600_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r600_set_surface_reg,
+		.clear_reg = r600_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &r600_hpd_init,
+		.fini = &r600_hpd_fini,
+		.sense = &r600_hpd_sense,
+		.set_polarity = &r600_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &r600_pm_misc,
+		.prepare = &rs600_pm_prepare,
+		.finish = &rs600_pm_finish,
+		.init_profile = &r600_pm_init_profile,
+		.get_dynpm_state = &r600_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = &r600_get_pcie_lanes,
+		.set_pcie_lanes = &r600_set_pcie_lanes,
+		.set_clock_gating = NULL,
+	},
+	.pflip = {
+		.pre_page_flip = &rs600_pre_page_flip,
+		.page_flip = &rs600_page_flip,
+		.post_page_flip = &rs600_post_page_flip,
+	},
 };
 
 static struct radeon_asic rs780_asic = {
@@ -705,47 +949,69 @@
 	.gpu_is_lockup = &r600_gpu_is_lockup,
 	.vga_set_state = &r600_vga_set_state,
 	.asic_reset = &r600_asic_reset,
-	.gart_tlb_flush = &r600_pcie_gart_tlb_flush,
-	.gart_set_page = &rs600_gart_set_page,
-	.ring_test = &r600_ring_test,
+	.ioctl_wait_idle = r600_ioctl_wait_idle,
+	.gui_idle = &r600_gui_idle,
+	.mc_wait_for_idle = &r600_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &r600_pcie_gart_tlb_flush,
+		.set_page = &rs600_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &r600_ring_ib_execute,
 			.emit_fence = &r600_fence_ring_emit,
 			.emit_semaphore = &r600_semaphore_ring_emit,
+			.cs_parse = &r600_cs_parse,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
 		}
 	},
-	.irq_set = &r600_irq_set,
-	.irq_process = &r600_irq_process,
-	.get_vblank_counter = &rs600_get_vblank_counter,
-	.cs_parse = &r600_cs_parse,
-	.copy_blit = &r600_copy_blit,
-	.copy_dma = NULL,
-	.copy = &r600_copy_blit,
-	.get_engine_clock = &radeon_atom_get_engine_clock,
-	.set_engine_clock = &radeon_atom_set_engine_clock,
-	.get_memory_clock = NULL,
-	.set_memory_clock = NULL,
-	.get_pcie_lanes = NULL,
-	.set_pcie_lanes = NULL,
-	.set_clock_gating = NULL,
-	.set_surface_reg = r600_set_surface_reg,
-	.clear_surface_reg = r600_clear_surface_reg,
-	.bandwidth_update = &rs690_bandwidth_update,
-	.hpd_init = &r600_hpd_init,
-	.hpd_fini = &r600_hpd_fini,
-	.hpd_sense = &r600_hpd_sense,
-	.hpd_set_polarity = &r600_hpd_set_polarity,
-	.ioctl_wait_idle = r600_ioctl_wait_idle,
-	.gui_idle = &r600_gui_idle,
-	.pm_misc = &r600_pm_misc,
-	.pm_prepare = &rs600_pm_prepare,
-	.pm_finish = &rs600_pm_finish,
-	.pm_init_profile = &rs780_pm_init_profile,
-	.pm_get_dynpm_state = &r600_pm_get_dynpm_state,
-	.pre_page_flip = &rs600_pre_page_flip,
-	.page_flip = &rs600_page_flip,
-	.post_page_flip = &rs600_post_page_flip,
+	.irq = {
+		.set = &r600_irq_set,
+		.process = &r600_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &rs690_bandwidth_update,
+		.get_vblank_counter = &rs600_get_vblank_counter,
+		.wait_for_vblank = &avivo_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r600_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = NULL,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r600_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r600_set_surface_reg,
+		.clear_reg = r600_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &r600_hpd_init,
+		.fini = &r600_hpd_fini,
+		.sense = &r600_hpd_sense,
+		.set_polarity = &r600_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &r600_pm_misc,
+		.prepare = &rs600_pm_prepare,
+		.finish = &rs600_pm_finish,
+		.init_profile = &rs780_pm_init_profile,
+		.get_dynpm_state = &r600_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = NULL,
+		.set_memory_clock = NULL,
+		.get_pcie_lanes = NULL,
+		.set_pcie_lanes = NULL,
+		.set_clock_gating = NULL,
+	},
+	.pflip = {
+		.pre_page_flip = &rs600_pre_page_flip,
+		.page_flip = &rs600_page_flip,
+		.post_page_flip = &rs600_post_page_flip,
+	},
 };
 
 static struct radeon_asic rv770_asic = {
@@ -756,47 +1022,69 @@
 	.asic_reset = &r600_asic_reset,
 	.gpu_is_lockup = &r600_gpu_is_lockup,
 	.vga_set_state = &r600_vga_set_state,
-	.gart_tlb_flush = &r600_pcie_gart_tlb_flush,
-	.gart_set_page = &rs600_gart_set_page,
-	.ring_test = &r600_ring_test,
+	.ioctl_wait_idle = r600_ioctl_wait_idle,
+	.gui_idle = &r600_gui_idle,
+	.mc_wait_for_idle = &r600_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &r600_pcie_gart_tlb_flush,
+		.set_page = &rs600_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &r600_ring_ib_execute,
 			.emit_fence = &r600_fence_ring_emit,
 			.emit_semaphore = &r600_semaphore_ring_emit,
+			.cs_parse = &r600_cs_parse,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
 		}
 	},
-	.irq_set = &r600_irq_set,
-	.irq_process = &r600_irq_process,
-	.get_vblank_counter = &rs600_get_vblank_counter,
-	.cs_parse = &r600_cs_parse,
-	.copy_blit = &r600_copy_blit,
-	.copy_dma = NULL,
-	.copy = &r600_copy_blit,
-	.get_engine_clock = &radeon_atom_get_engine_clock,
-	.set_engine_clock = &radeon_atom_set_engine_clock,
-	.get_memory_clock = &radeon_atom_get_memory_clock,
-	.set_memory_clock = &radeon_atom_set_memory_clock,
-	.get_pcie_lanes = &r600_get_pcie_lanes,
-	.set_pcie_lanes = &r600_set_pcie_lanes,
-	.set_clock_gating = &radeon_atom_set_clock_gating,
-	.set_surface_reg = r600_set_surface_reg,
-	.clear_surface_reg = r600_clear_surface_reg,
-	.bandwidth_update = &rv515_bandwidth_update,
-	.hpd_init = &r600_hpd_init,
-	.hpd_fini = &r600_hpd_fini,
-	.hpd_sense = &r600_hpd_sense,
-	.hpd_set_polarity = &r600_hpd_set_polarity,
-	.ioctl_wait_idle = r600_ioctl_wait_idle,
-	.gui_idle = &r600_gui_idle,
-	.pm_misc = &rv770_pm_misc,
-	.pm_prepare = &rs600_pm_prepare,
-	.pm_finish = &rs600_pm_finish,
-	.pm_init_profile = &r600_pm_init_profile,
-	.pm_get_dynpm_state = &r600_pm_get_dynpm_state,
-	.pre_page_flip = &rs600_pre_page_flip,
-	.page_flip = &rv770_page_flip,
-	.post_page_flip = &rs600_post_page_flip,
+	.irq = {
+		.set = &r600_irq_set,
+		.process = &r600_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &rv515_bandwidth_update,
+		.get_vblank_counter = &rs600_get_vblank_counter,
+		.wait_for_vblank = &avivo_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r600_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = NULL,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r600_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r600_set_surface_reg,
+		.clear_reg = r600_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &r600_hpd_init,
+		.fini = &r600_hpd_fini,
+		.sense = &r600_hpd_sense,
+		.set_polarity = &r600_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &rv770_pm_misc,
+		.prepare = &rs600_pm_prepare,
+		.finish = &rs600_pm_finish,
+		.init_profile = &r600_pm_init_profile,
+		.get_dynpm_state = &r600_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = &r600_get_pcie_lanes,
+		.set_pcie_lanes = &r600_set_pcie_lanes,
+		.set_clock_gating = &radeon_atom_set_clock_gating,
+	},
+	.pflip = {
+		.pre_page_flip = &rs600_pre_page_flip,
+		.page_flip = &rv770_page_flip,
+		.post_page_flip = &rs600_post_page_flip,
+	},
 };
 
 static struct radeon_asic evergreen_asic = {
@@ -807,47 +1095,69 @@
 	.gpu_is_lockup = &evergreen_gpu_is_lockup,
 	.asic_reset = &evergreen_asic_reset,
 	.vga_set_state = &r600_vga_set_state,
-	.gart_tlb_flush = &evergreen_pcie_gart_tlb_flush,
-	.gart_set_page = &rs600_gart_set_page,
-	.ring_test = &r600_ring_test,
+	.ioctl_wait_idle = r600_ioctl_wait_idle,
+	.gui_idle = &r600_gui_idle,
+	.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &evergreen_pcie_gart_tlb_flush,
+		.set_page = &rs600_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &evergreen_ring_ib_execute,
 			.emit_fence = &r600_fence_ring_emit,
 			.emit_semaphore = &r600_semaphore_ring_emit,
+			.cs_parse = &evergreen_cs_parse,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
 		}
 	},
-	.irq_set = &evergreen_irq_set,
-	.irq_process = &evergreen_irq_process,
-	.get_vblank_counter = &evergreen_get_vblank_counter,
-	.cs_parse = &evergreen_cs_parse,
-	.copy_blit = &r600_copy_blit,
-	.copy_dma = NULL,
-	.copy = &r600_copy_blit,
-	.get_engine_clock = &radeon_atom_get_engine_clock,
-	.set_engine_clock = &radeon_atom_set_engine_clock,
-	.get_memory_clock = &radeon_atom_get_memory_clock,
-	.set_memory_clock = &radeon_atom_set_memory_clock,
-	.get_pcie_lanes = &r600_get_pcie_lanes,
-	.set_pcie_lanes = &r600_set_pcie_lanes,
-	.set_clock_gating = NULL,
-	.set_surface_reg = r600_set_surface_reg,
-	.clear_surface_reg = r600_clear_surface_reg,
-	.bandwidth_update = &evergreen_bandwidth_update,
-	.hpd_init = &evergreen_hpd_init,
-	.hpd_fini = &evergreen_hpd_fini,
-	.hpd_sense = &evergreen_hpd_sense,
-	.hpd_set_polarity = &evergreen_hpd_set_polarity,
-	.ioctl_wait_idle = r600_ioctl_wait_idle,
-	.gui_idle = &r600_gui_idle,
-	.pm_misc = &evergreen_pm_misc,
-	.pm_prepare = &evergreen_pm_prepare,
-	.pm_finish = &evergreen_pm_finish,
-	.pm_init_profile = &r600_pm_init_profile,
-	.pm_get_dynpm_state = &r600_pm_get_dynpm_state,
-	.pre_page_flip = &evergreen_pre_page_flip,
-	.page_flip = &evergreen_page_flip,
-	.post_page_flip = &evergreen_post_page_flip,
+	.irq = {
+		.set = &evergreen_irq_set,
+		.process = &evergreen_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &evergreen_bandwidth_update,
+		.get_vblank_counter = &evergreen_get_vblank_counter,
+		.wait_for_vblank = &dce4_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r600_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = NULL,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r600_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r600_set_surface_reg,
+		.clear_reg = r600_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &evergreen_hpd_init,
+		.fini = &evergreen_hpd_fini,
+		.sense = &evergreen_hpd_sense,
+		.set_polarity = &evergreen_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &evergreen_pm_misc,
+		.prepare = &evergreen_pm_prepare,
+		.finish = &evergreen_pm_finish,
+		.init_profile = &r600_pm_init_profile,
+		.get_dynpm_state = &r600_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = &r600_get_pcie_lanes,
+		.set_pcie_lanes = &r600_set_pcie_lanes,
+		.set_clock_gating = NULL,
+	},
+	.pflip = {
+		.pre_page_flip = &evergreen_pre_page_flip,
+		.page_flip = &evergreen_page_flip,
+		.post_page_flip = &evergreen_post_page_flip,
+	},
 };
 
 static struct radeon_asic sumo_asic = {
@@ -858,47 +1168,69 @@
 	.gpu_is_lockup = &evergreen_gpu_is_lockup,
 	.asic_reset = &evergreen_asic_reset,
 	.vga_set_state = &r600_vga_set_state,
-	.gart_tlb_flush = &evergreen_pcie_gart_tlb_flush,
-	.gart_set_page = &rs600_gart_set_page,
-	.ring_test = &r600_ring_test,
+	.ioctl_wait_idle = r600_ioctl_wait_idle,
+	.gui_idle = &r600_gui_idle,
+	.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &evergreen_pcie_gart_tlb_flush,
+		.set_page = &rs600_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &evergreen_ring_ib_execute,
 			.emit_fence = &r600_fence_ring_emit,
 			.emit_semaphore = &r600_semaphore_ring_emit,
-		}
+			.cs_parse = &evergreen_cs_parse,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
+		},
 	},
-	.irq_set = &evergreen_irq_set,
-	.irq_process = &evergreen_irq_process,
-	.get_vblank_counter = &evergreen_get_vblank_counter,
-	.cs_parse = &evergreen_cs_parse,
-	.copy_blit = &r600_copy_blit,
-	.copy_dma = NULL,
-	.copy = &r600_copy_blit,
-	.get_engine_clock = &radeon_atom_get_engine_clock,
-	.set_engine_clock = &radeon_atom_set_engine_clock,
-	.get_memory_clock = NULL,
-	.set_memory_clock = NULL,
-	.get_pcie_lanes = NULL,
-	.set_pcie_lanes = NULL,
-	.set_clock_gating = NULL,
-	.set_surface_reg = r600_set_surface_reg,
-	.clear_surface_reg = r600_clear_surface_reg,
-	.bandwidth_update = &evergreen_bandwidth_update,
-	.hpd_init = &evergreen_hpd_init,
-	.hpd_fini = &evergreen_hpd_fini,
-	.hpd_sense = &evergreen_hpd_sense,
-	.hpd_set_polarity = &evergreen_hpd_set_polarity,
-	.ioctl_wait_idle = r600_ioctl_wait_idle,
-	.gui_idle = &r600_gui_idle,
-	.pm_misc = &evergreen_pm_misc,
-	.pm_prepare = &evergreen_pm_prepare,
-	.pm_finish = &evergreen_pm_finish,
-	.pm_init_profile = &sumo_pm_init_profile,
-	.pm_get_dynpm_state = &r600_pm_get_dynpm_state,
-	.pre_page_flip = &evergreen_pre_page_flip,
-	.page_flip = &evergreen_page_flip,
-	.post_page_flip = &evergreen_post_page_flip,
+	.irq = {
+		.set = &evergreen_irq_set,
+		.process = &evergreen_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &evergreen_bandwidth_update,
+		.get_vblank_counter = &evergreen_get_vblank_counter,
+		.wait_for_vblank = &dce4_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r600_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = NULL,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r600_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r600_set_surface_reg,
+		.clear_reg = r600_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &evergreen_hpd_init,
+		.fini = &evergreen_hpd_fini,
+		.sense = &evergreen_hpd_sense,
+		.set_polarity = &evergreen_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &evergreen_pm_misc,
+		.prepare = &evergreen_pm_prepare,
+		.finish = &evergreen_pm_finish,
+		.init_profile = &sumo_pm_init_profile,
+		.get_dynpm_state = &r600_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = NULL,
+		.set_memory_clock = NULL,
+		.get_pcie_lanes = NULL,
+		.set_pcie_lanes = NULL,
+		.set_clock_gating = NULL,
+	},
+	.pflip = {
+		.pre_page_flip = &evergreen_pre_page_flip,
+		.page_flip = &evergreen_page_flip,
+		.post_page_flip = &evergreen_post_page_flip,
+	},
 };
 
 static struct radeon_asic btc_asic = {
@@ -909,47 +1241,69 @@
 	.gpu_is_lockup = &evergreen_gpu_is_lockup,
 	.asic_reset = &evergreen_asic_reset,
 	.vga_set_state = &r600_vga_set_state,
-	.gart_tlb_flush = &evergreen_pcie_gart_tlb_flush,
-	.gart_set_page = &rs600_gart_set_page,
-	.ring_test = &r600_ring_test,
+	.ioctl_wait_idle = r600_ioctl_wait_idle,
+	.gui_idle = &r600_gui_idle,
+	.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &evergreen_pcie_gart_tlb_flush,
+		.set_page = &rs600_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &evergreen_ring_ib_execute,
 			.emit_fence = &r600_fence_ring_emit,
 			.emit_semaphore = &r600_semaphore_ring_emit,
+			.cs_parse = &evergreen_cs_parse,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
 		}
 	},
-	.irq_set = &evergreen_irq_set,
-	.irq_process = &evergreen_irq_process,
-	.get_vblank_counter = &evergreen_get_vblank_counter,
-	.cs_parse = &evergreen_cs_parse,
-	.copy_blit = &r600_copy_blit,
-	.copy_dma = NULL,
-	.copy = &r600_copy_blit,
-	.get_engine_clock = &radeon_atom_get_engine_clock,
-	.set_engine_clock = &radeon_atom_set_engine_clock,
-	.get_memory_clock = &radeon_atom_get_memory_clock,
-	.set_memory_clock = &radeon_atom_set_memory_clock,
-	.get_pcie_lanes = NULL,
-	.set_pcie_lanes = NULL,
-	.set_clock_gating = NULL,
-	.set_surface_reg = r600_set_surface_reg,
-	.clear_surface_reg = r600_clear_surface_reg,
-	.bandwidth_update = &evergreen_bandwidth_update,
-	.hpd_init = &evergreen_hpd_init,
-	.hpd_fini = &evergreen_hpd_fini,
-	.hpd_sense = &evergreen_hpd_sense,
-	.hpd_set_polarity = &evergreen_hpd_set_polarity,
-	.ioctl_wait_idle = r600_ioctl_wait_idle,
-	.gui_idle = &r600_gui_idle,
-	.pm_misc = &evergreen_pm_misc,
-	.pm_prepare = &evergreen_pm_prepare,
-	.pm_finish = &evergreen_pm_finish,
-	.pm_init_profile = &r600_pm_init_profile,
-	.pm_get_dynpm_state = &r600_pm_get_dynpm_state,
-	.pre_page_flip = &evergreen_pre_page_flip,
-	.page_flip = &evergreen_page_flip,
-	.post_page_flip = &evergreen_post_page_flip,
+	.irq = {
+		.set = &evergreen_irq_set,
+		.process = &evergreen_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &evergreen_bandwidth_update,
+		.get_vblank_counter = &evergreen_get_vblank_counter,
+		.wait_for_vblank = &dce4_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r600_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = NULL,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r600_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r600_set_surface_reg,
+		.clear_reg = r600_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &evergreen_hpd_init,
+		.fini = &evergreen_hpd_fini,
+		.sense = &evergreen_hpd_sense,
+		.set_polarity = &evergreen_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &evergreen_pm_misc,
+		.prepare = &evergreen_pm_prepare,
+		.finish = &evergreen_pm_finish,
+		.init_profile = &r600_pm_init_profile,
+		.get_dynpm_state = &r600_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = NULL,
+		.set_pcie_lanes = NULL,
+		.set_clock_gating = NULL,
+	},
+	.pflip = {
+		.pre_page_flip = &evergreen_pre_page_flip,
+		.page_flip = &evergreen_page_flip,
+		.post_page_flip = &evergreen_post_page_flip,
+	},
 };
 
 static const struct radeon_vm_funcs cayman_vm_funcs = {
@@ -970,60 +1324,282 @@
 	.gpu_is_lockup = &cayman_gpu_is_lockup,
 	.asic_reset = &cayman_asic_reset,
 	.vga_set_state = &r600_vga_set_state,
-	.gart_tlb_flush = &cayman_pcie_gart_tlb_flush,
-	.gart_set_page = &rs600_gart_set_page,
-	.ring_test = &r600_ring_test,
+	.ioctl_wait_idle = r600_ioctl_wait_idle,
+	.gui_idle = &r600_gui_idle,
+	.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &cayman_pcie_gart_tlb_flush,
+		.set_page = &rs600_gart_set_page,
+	},
 	.ring = {
 		[RADEON_RING_TYPE_GFX_INDEX] = {
 			.ib_execute = &cayman_ring_ib_execute,
 			.ib_parse = &evergreen_ib_parse,
 			.emit_fence = &cayman_fence_ring_emit,
 			.emit_semaphore = &r600_semaphore_ring_emit,
+			.cs_parse = &evergreen_cs_parse,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
 		},
 		[CAYMAN_RING_TYPE_CP1_INDEX] = {
 			.ib_execute = &cayman_ring_ib_execute,
 			.ib_parse = &evergreen_ib_parse,
 			.emit_fence = &cayman_fence_ring_emit,
 			.emit_semaphore = &r600_semaphore_ring_emit,
+			.cs_parse = &evergreen_cs_parse,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
 		},
 		[CAYMAN_RING_TYPE_CP2_INDEX] = {
 			.ib_execute = &cayman_ring_ib_execute,
 			.ib_parse = &evergreen_ib_parse,
 			.emit_fence = &cayman_fence_ring_emit,
 			.emit_semaphore = &r600_semaphore_ring_emit,
+			.cs_parse = &evergreen_cs_parse,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
 		}
 	},
-	.irq_set = &evergreen_irq_set,
-	.irq_process = &evergreen_irq_process,
-	.get_vblank_counter = &evergreen_get_vblank_counter,
-	.cs_parse = &evergreen_cs_parse,
-	.copy_blit = &r600_copy_blit,
-	.copy_dma = NULL,
-	.copy = &r600_copy_blit,
-	.get_engine_clock = &radeon_atom_get_engine_clock,
-	.set_engine_clock = &radeon_atom_set_engine_clock,
-	.get_memory_clock = &radeon_atom_get_memory_clock,
-	.set_memory_clock = &radeon_atom_set_memory_clock,
-	.get_pcie_lanes = NULL,
-	.set_pcie_lanes = NULL,
-	.set_clock_gating = NULL,
-	.set_surface_reg = r600_set_surface_reg,
-	.clear_surface_reg = r600_clear_surface_reg,
-	.bandwidth_update = &evergreen_bandwidth_update,
-	.hpd_init = &evergreen_hpd_init,
-	.hpd_fini = &evergreen_hpd_fini,
-	.hpd_sense = &evergreen_hpd_sense,
-	.hpd_set_polarity = &evergreen_hpd_set_polarity,
+	.irq = {
+		.set = &evergreen_irq_set,
+		.process = &evergreen_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &evergreen_bandwidth_update,
+		.get_vblank_counter = &evergreen_get_vblank_counter,
+		.wait_for_vblank = &dce4_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r600_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = NULL,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r600_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r600_set_surface_reg,
+		.clear_reg = r600_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &evergreen_hpd_init,
+		.fini = &evergreen_hpd_fini,
+		.sense = &evergreen_hpd_sense,
+		.set_polarity = &evergreen_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &evergreen_pm_misc,
+		.prepare = &evergreen_pm_prepare,
+		.finish = &evergreen_pm_finish,
+		.init_profile = &r600_pm_init_profile,
+		.get_dynpm_state = &r600_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = NULL,
+		.set_pcie_lanes = NULL,
+		.set_clock_gating = NULL,
+	},
+	.pflip = {
+		.pre_page_flip = &evergreen_pre_page_flip,
+		.page_flip = &evergreen_page_flip,
+		.post_page_flip = &evergreen_post_page_flip,
+	},
+};
+
+static struct radeon_asic trinity_asic = {
+	.init = &cayman_init,
+	.fini = &cayman_fini,
+	.suspend = &cayman_suspend,
+	.resume = &cayman_resume,
+	.gpu_is_lockup = &cayman_gpu_is_lockup,
+	.asic_reset = &cayman_asic_reset,
+	.vga_set_state = &r600_vga_set_state,
 	.ioctl_wait_idle = r600_ioctl_wait_idle,
 	.gui_idle = &r600_gui_idle,
-	.pm_misc = &evergreen_pm_misc,
-	.pm_prepare = &evergreen_pm_prepare,
-	.pm_finish = &evergreen_pm_finish,
-	.pm_init_profile = &r600_pm_init_profile,
-	.pm_get_dynpm_state = &r600_pm_get_dynpm_state,
-	.pre_page_flip = &evergreen_pre_page_flip,
-	.page_flip = &evergreen_page_flip,
-	.post_page_flip = &evergreen_post_page_flip,
+	.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &cayman_pcie_gart_tlb_flush,
+		.set_page = &rs600_gart_set_page,
+	},
+	.ring = {
+		[RADEON_RING_TYPE_GFX_INDEX] = {
+			.ib_execute = &cayman_ring_ib_execute,
+			.ib_parse = &evergreen_ib_parse,
+			.emit_fence = &cayman_fence_ring_emit,
+			.emit_semaphore = &r600_semaphore_ring_emit,
+			.cs_parse = &evergreen_cs_parse,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
+		},
+		[CAYMAN_RING_TYPE_CP1_INDEX] = {
+			.ib_execute = &cayman_ring_ib_execute,
+			.ib_parse = &evergreen_ib_parse,
+			.emit_fence = &cayman_fence_ring_emit,
+			.emit_semaphore = &r600_semaphore_ring_emit,
+			.cs_parse = &evergreen_cs_parse,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
+		},
+		[CAYMAN_RING_TYPE_CP2_INDEX] = {
+			.ib_execute = &cayman_ring_ib_execute,
+			.ib_parse = &evergreen_ib_parse,
+			.emit_fence = &cayman_fence_ring_emit,
+			.emit_semaphore = &r600_semaphore_ring_emit,
+			.cs_parse = &evergreen_cs_parse,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
+		}
+	},
+	.irq = {
+		.set = &evergreen_irq_set,
+		.process = &evergreen_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &dce6_bandwidth_update,
+		.get_vblank_counter = &evergreen_get_vblank_counter,
+		.wait_for_vblank = &dce4_wait_for_vblank,
+	},
+	.copy = {
+		.blit = &r600_copy_blit,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = NULL,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = &r600_copy_blit,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r600_set_surface_reg,
+		.clear_reg = r600_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &evergreen_hpd_init,
+		.fini = &evergreen_hpd_fini,
+		.sense = &evergreen_hpd_sense,
+		.set_polarity = &evergreen_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &evergreen_pm_misc,
+		.prepare = &evergreen_pm_prepare,
+		.finish = &evergreen_pm_finish,
+		.init_profile = &sumo_pm_init_profile,
+		.get_dynpm_state = &r600_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = NULL,
+		.set_memory_clock = NULL,
+		.get_pcie_lanes = NULL,
+		.set_pcie_lanes = NULL,
+		.set_clock_gating = NULL,
+	},
+	.pflip = {
+		.pre_page_flip = &evergreen_pre_page_flip,
+		.page_flip = &evergreen_page_flip,
+		.post_page_flip = &evergreen_post_page_flip,
+	},
+};
+
+static const struct radeon_vm_funcs si_vm_funcs = {
+	.init = &si_vm_init,
+	.fini = &si_vm_fini,
+	.bind = &si_vm_bind,
+	.unbind = &si_vm_unbind,
+	.tlb_flush = &si_vm_tlb_flush,
+	.page_flags = &cayman_vm_page_flags,
+	.set_page = &cayman_vm_set_page,
+};
+
+static struct radeon_asic si_asic = {
+	.init = &si_init,
+	.fini = &si_fini,
+	.suspend = &si_suspend,
+	.resume = &si_resume,
+	.gpu_is_lockup = &si_gpu_is_lockup,
+	.asic_reset = &si_asic_reset,
+	.vga_set_state = &r600_vga_set_state,
+	.ioctl_wait_idle = r600_ioctl_wait_idle,
+	.gui_idle = &r600_gui_idle,
+	.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+	.gart = {
+		.tlb_flush = &si_pcie_gart_tlb_flush,
+		.set_page = &rs600_gart_set_page,
+	},
+	.ring = {
+		[RADEON_RING_TYPE_GFX_INDEX] = {
+			.ib_execute = &si_ring_ib_execute,
+			.ib_parse = &si_ib_parse,
+			.emit_fence = &si_fence_ring_emit,
+			.emit_semaphore = &r600_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
+		},
+		[CAYMAN_RING_TYPE_CP1_INDEX] = {
+			.ib_execute = &si_ring_ib_execute,
+			.ib_parse = &si_ib_parse,
+			.emit_fence = &si_fence_ring_emit,
+			.emit_semaphore = &r600_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
+		},
+		[CAYMAN_RING_TYPE_CP2_INDEX] = {
+			.ib_execute = &si_ring_ib_execute,
+			.ib_parse = &si_ib_parse,
+			.emit_fence = &si_fence_ring_emit,
+			.emit_semaphore = &r600_semaphore_ring_emit,
+			.cs_parse = NULL,
+			.ring_test = &r600_ring_test,
+			.ib_test = &r600_ib_test,
+		}
+	},
+	.irq = {
+		.set = &si_irq_set,
+		.process = &si_irq_process,
+	},
+	.display = {
+		.bandwidth_update = &dce6_bandwidth_update,
+		.get_vblank_counter = &evergreen_get_vblank_counter,
+		.wait_for_vblank = &dce4_wait_for_vblank,
+	},
+	.copy = {
+		.blit = NULL,
+		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.dma = NULL,
+		.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+		.copy = NULL,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+	},
+	.surface = {
+		.set_reg = r600_set_surface_reg,
+		.clear_reg = r600_clear_surface_reg,
+	},
+	.hpd = {
+		.init = &evergreen_hpd_init,
+		.fini = &evergreen_hpd_fini,
+		.sense = &evergreen_hpd_sense,
+		.set_polarity = &evergreen_hpd_set_polarity,
+	},
+	.pm = {
+		.misc = &evergreen_pm_misc,
+		.prepare = &evergreen_pm_prepare,
+		.finish = &evergreen_pm_finish,
+		.init_profile = &sumo_pm_init_profile,
+		.get_dynpm_state = &r600_pm_get_dynpm_state,
+		.get_engine_clock = &radeon_atom_get_engine_clock,
+		.set_engine_clock = &radeon_atom_set_engine_clock,
+		.get_memory_clock = &radeon_atom_get_memory_clock,
+		.set_memory_clock = &radeon_atom_set_memory_clock,
+		.get_pcie_lanes = NULL,
+		.set_pcie_lanes = NULL,
+		.set_clock_gating = NULL,
+	},
+	.pflip = {
+		.pre_page_flip = &evergreen_pre_page_flip,
+		.page_flip = &evergreen_page_flip,
+		.post_page_flip = &evergreen_post_page_flip,
+	},
 };
 
 int radeon_asic_init(struct radeon_device *rdev)
@@ -1036,9 +1612,6 @@
 	else
 		rdev->num_crtc = 2;
 
-	/* set the ring used for bo copies */
-	rdev->copy_ring = RADEON_RING_TYPE_GFX_INDEX;
-
 	switch (rdev->family) {
 	case CHIP_R100:
 	case CHIP_RV100:
@@ -1068,10 +1641,10 @@
 		rdev->asic = &r420_asic;
 		/* handle macs */
 		if (rdev->bios == NULL) {
-			rdev->asic->get_engine_clock = &radeon_legacy_get_engine_clock;
-			rdev->asic->set_engine_clock = &radeon_legacy_set_engine_clock;
-			rdev->asic->get_memory_clock = &radeon_legacy_get_memory_clock;
-			rdev->asic->set_memory_clock = NULL;
+			rdev->asic->pm.get_engine_clock = &radeon_legacy_get_engine_clock;
+			rdev->asic->pm.set_engine_clock = &radeon_legacy_set_engine_clock;
+			rdev->asic->pm.get_memory_clock = &radeon_legacy_get_memory_clock;
+			rdev->asic->pm.set_memory_clock = NULL;
 		}
 		break;
 	case CHIP_RS400:
@@ -1146,14 +1719,28 @@
 		rdev->num_crtc = 6;
 		rdev->vm_manager.funcs = &cayman_vm_funcs;
 		break;
+	case CHIP_ARUBA:
+		rdev->asic = &trinity_asic;
+		/* set num crtcs */
+		rdev->num_crtc = 4;
+		rdev->vm_manager.funcs = &cayman_vm_funcs;
+		break;
+	case CHIP_TAHITI:
+	case CHIP_PITCAIRN:
+	case CHIP_VERDE:
+		rdev->asic = &si_asic;
+		/* set num crtcs */
+		rdev->num_crtc = 6;
+		rdev->vm_manager.funcs = &si_vm_funcs;
+		break;
 	default:
 		/* FIXME: not supported yet */
 		return -EINVAL;
 	}
 
 	if (rdev->flags & RADEON_IS_IGP) {
-		rdev->asic->get_memory_clock = NULL;
-		rdev->asic->set_memory_clock = NULL;
+		rdev->asic->pm.get_memory_clock = NULL;
+		rdev->asic->pm.set_memory_clock = NULL;
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 6304aef..3d9f9f1 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -63,7 +63,7 @@
 u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc);
 void r100_pci_gart_tlb_flush(struct radeon_device *rdev);
 int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
-void r100_ring_start(struct radeon_device *rdev);
+void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring);
 int r100_irq_set(struct radeon_device *rdev);
 int r100_irq_process(struct radeon_device *rdev);
 void r100_fence_ring_emit(struct radeon_device *rdev,
@@ -109,7 +109,7 @@
 			   struct r100_gpu_lockup *lockup,
 			   struct radeon_ring *cp);
 void r100_ib_fini(struct radeon_device *rdev);
-int r100_ib_test(struct radeon_device *rdev);
+int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
 void r100_irq_disable(struct radeon_device *rdev);
 void r100_mc_stop(struct radeon_device *rdev, struct r100_mc_save *save);
 void r100_mc_resume(struct radeon_device *rdev, struct r100_mc_save *save);
@@ -139,6 +139,8 @@
 extern void r100_pre_page_flip(struct radeon_device *rdev, int crtc);
 extern u32 r100_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
 extern void r100_post_page_flip(struct radeon_device *rdev, int crtc);
+extern void r100_wait_for_vblank(struct radeon_device *rdev, int crtc);
+extern int r100_mc_wait_for_idle(struct radeon_device *rdev);
 
 /*
  * r200,rv250,rs300,rv280
@@ -159,7 +161,7 @@
 extern int r300_resume(struct radeon_device *rdev);
 extern bool r300_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp);
 extern int r300_asic_reset(struct radeon_device *rdev);
-extern void r300_ring_start(struct radeon_device *rdev);
+extern void r300_ring_start(struct radeon_device *rdev, struct radeon_ring *ring);
 extern void r300_fence_ring_emit(struct radeon_device *rdev,
 				struct radeon_fence *fence);
 extern int r300_cs_parse(struct radeon_cs_parser *p);
@@ -176,6 +178,7 @@
 extern void rv370_pcie_gart_fini(struct radeon_device *rdev);
 extern int rv370_pcie_gart_enable(struct radeon_device *rdev);
 extern void rv370_pcie_gart_disable(struct radeon_device *rdev);
+extern int r300_mc_wait_for_idle(struct radeon_device *rdev);
 
 /*
  * r420,r423,rv410
@@ -206,6 +209,7 @@
 void rs400_gart_adjust_size(struct radeon_device *rdev);
 void rs400_gart_disable(struct radeon_device *rdev);
 void rs400_gart_fini(struct radeon_device *rdev);
+extern int rs400_mc_wait_for_idle(struct radeon_device *rdev);
 
 /*
  * rs600.
@@ -236,7 +240,8 @@
 extern u32 rs600_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
 extern void rs600_post_page_flip(struct radeon_device *rdev, int crtc);
 void rs600_set_safe_registers(struct radeon_device *rdev);
-
+extern void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc);
+extern int rs600_mc_wait_for_idle(struct radeon_device *rdev);
 
 /*
  * rs690,rs740
@@ -251,6 +256,7 @@
 void rs690_line_buffer_adjust(struct radeon_device *rdev,
 					struct drm_display_mode *mode1,
 					struct drm_display_mode *mode2);
+extern int rs690_mc_wait_for_idle(struct radeon_device *rdev);
 
 /*
  * rv515
@@ -267,7 +273,7 @@
 void rv515_fini(struct radeon_device *rdev);
 uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg);
 void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
-void rv515_ring_start(struct radeon_device *rdev);
+void rv515_ring_start(struct radeon_device *rdev, struct radeon_ring *ring);
 void rv515_bandwidth_update(struct radeon_device *rdev);
 int rv515_resume(struct radeon_device *rdev);
 int rv515_suspend(struct radeon_device *rdev);
@@ -278,13 +284,14 @@
 void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save);
 void rv515_clock_startup(struct radeon_device *rdev);
 void rv515_debugfs(struct radeon_device *rdev);
-
+int rv515_mc_wait_for_idle(struct radeon_device *rdev);
 
 /*
  * r520,rv530,rv560,rv570,r580
  */
 int r520_init(struct radeon_device *rdev);
 int r520_resume(struct radeon_device *rdev);
+int r520_mc_wait_for_idle(struct radeon_device *rdev);
 
 /*
  * r600,rv610,rv630,rv620,rv635,rv670,rs780,rs880
@@ -312,7 +319,7 @@
 			 uint32_t tiling_flags, uint32_t pitch,
 			 uint32_t offset, uint32_t obj_size);
 void r600_clear_surface_reg(struct radeon_device *rdev, int reg);
-int r600_ib_test(struct radeon_device *rdev, int ring);
+int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
 void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
 int r600_ring_test(struct radeon_device *rdev, struct radeon_ring *cp);
 int r600_copy_blit(struct radeon_device *rdev,
@@ -375,6 +382,7 @@
 void r600_kms_blit_copy(struct radeon_device *rdev,
 			u64 src_gpu_addr, u64 dst_gpu_addr,
 			unsigned num_gpu_pages);
+int r600_mc_wait_for_idle(struct radeon_device *rdev);
 
 /*
  * rv770,rv730,rv710,rv740
@@ -423,8 +431,10 @@
 extern void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc);
 extern u32 evergreen_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
 extern void evergreen_post_page_flip(struct radeon_device *rdev, int crtc);
+extern void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc);
 void evergreen_disable_interrupt_state(struct radeon_device *rdev);
 int evergreen_blit_init(struct radeon_device *rdev);
+int evergreen_mc_wait_for_idle(struct radeon_device *rdev);
 
 /*
  * cayman
@@ -451,4 +461,29 @@
 			unsigned pfn, uint64_t addr, uint32_t flags);
 int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
 
+/* DCE6 - SI */
+void dce6_bandwidth_update(struct radeon_device *rdev);
+
+/*
+ * si
+ */
+void si_fence_ring_emit(struct radeon_device *rdev,
+			struct radeon_fence *fence);
+void si_pcie_gart_tlb_flush(struct radeon_device *rdev);
+int si_init(struct radeon_device *rdev);
+void si_fini(struct radeon_device *rdev);
+int si_suspend(struct radeon_device *rdev);
+int si_resume(struct radeon_device *rdev);
+bool si_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp);
+int si_asic_reset(struct radeon_device *rdev);
+void si_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
+int si_irq_set(struct radeon_device *rdev);
+int si_irq_process(struct radeon_device *rdev);
+int si_vm_init(struct radeon_device *rdev);
+void si_vm_fini(struct radeon_device *rdev);
+int si_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id);
+void si_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm);
+void si_vm_tlb_flush(struct radeon_device *rdev, struct radeon_vm *vm);
+int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
+
 #endif
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 1f53ae7..f6e69b8 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -56,6 +56,10 @@
 radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum,
 			  uint32_t supported_device);
 
+/* local */
+static int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
+				    u16 voltage_id, u16 *voltage);
+
 union atom_supported_devices {
 	struct _ATOM_SUPPORTED_DEVICES_INFO info;
 	struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2;
@@ -253,7 +257,9 @@
 
 	memset(&hpd, 0, sizeof(struct radeon_hpd));
 
-	if (ASIC_IS_DCE4(rdev))
+	if (ASIC_IS_DCE6(rdev))
+		reg = SI_DC_GPIO_HPD_A;
+	else if (ASIC_IS_DCE4(rdev))
 		reg = EVERGREEN_DC_GPIO_HPD_A;
 	else
 		reg = AVIVO_DC_GPIO_HPD_A;
@@ -442,6 +448,20 @@
 		struct radeon_device *rdev = dev->dev_private;
 		*i2c_bus = radeon_lookup_i2c_gpio(rdev, 0x93);
 	}
+
+	/* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */
+	if ((dev->pdev->device == 0x9802) &&
+	    (dev->pdev->subsystem_vendor == 0x1734) &&
+	    (dev->pdev->subsystem_device == 0x11bd)) {
+		if (*connector_type == DRM_MODE_CONNECTOR_VGA) {
+			*connector_type = DRM_MODE_CONNECTOR_DVII;
+			*line_mux = 0x3103;
+		} else if (*connector_type == DRM_MODE_CONNECTOR_DVID) {
+			*connector_type = DRM_MODE_CONNECTOR_DVII;
+		}
+	}
+
+
 	return true;
 }
 
@@ -1874,6 +1894,8 @@
 	"emc2103",
 	"Sumo",
 	"Northern Islands",
+	"Southern Islands",
+	"lm96163",
 };
 
 union power_info {
@@ -1890,6 +1912,7 @@
 	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
 	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
 	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
+	struct _ATOM_PPLIB_SI_CLOCK_INFO si;
 };
 
 union pplib_power_state {
@@ -2147,6 +2170,11 @@
 				 (controller->ucFanParameters &
 				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 			rdev->pm.int_thermal_type = THERMAL_TYPE_NI;
+		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SISLANDS) {
+			DRM_INFO("Internal thermal controller %s fan control\n",
+				 (controller->ucFanParameters &
+				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+			rdev->pm.int_thermal_type = THERMAL_TYPE_SI;
 		} else if ((controller->ucType ==
 			    ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) ||
 			   (controller->ucType ==
@@ -2267,6 +2295,7 @@
 						   union pplib_clock_info *clock_info)
 {
 	u32 sclk, mclk;
+	u16 vddc;
 
 	if (rdev->flags & RADEON_IS_IGP) {
 		if (rdev->family >= CHIP_PALM) {
@@ -2278,6 +2307,19 @@
 			sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
 			rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
 		}
+	} else if (ASIC_IS_DCE6(rdev)) {
+		sclk = le16_to_cpu(clock_info->si.usEngineClockLow);
+		sclk |= clock_info->si.ucEngineClockHigh << 16;
+		mclk = le16_to_cpu(clock_info->si.usMemoryClockLow);
+		mclk |= clock_info->si.ucMemoryClockHigh << 16;
+		rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
+		rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
+		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
+			VOLTAGE_SW;
+		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
+			le16_to_cpu(clock_info->si.usVDDC);
+		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci =
+			le16_to_cpu(clock_info->si.usVDDCI);
 	} else if (ASIC_IS_DCE4(rdev)) {
 		sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow);
 		sclk |= clock_info->evergreen.ucEngineClockHigh << 16;
@@ -2305,11 +2347,18 @@
 	}
 
 	/* patch up vddc if necessary */
-	if (rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage == 0xff01) {
-		u16 vddc;
-
-		if (radeon_atom_get_max_vddc(rdev, &vddc) == 0)
+	switch (rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage) {
+	case ATOM_VIRTUAL_VOLTAGE_ID0:
+	case ATOM_VIRTUAL_VOLTAGE_ID1:
+	case ATOM_VIRTUAL_VOLTAGE_ID2:
+	case ATOM_VIRTUAL_VOLTAGE_ID3:
+		if (radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC,
+					     rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage,
+					     &vddc) == 0)
 			rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = vddc;
+		break;
+	default:
+		break;
 	}
 
 	if (rdev->flags & RADEON_IS_IGP) {
@@ -2419,9 +2468,9 @@
 	int i, j, non_clock_array_index, clock_array_index;
 	int state_index = 0, mode_index = 0;
 	union pplib_clock_info *clock_info;
-	struct StateArray *state_array;
-	struct ClockInfoArray *clock_info_array;
-	struct NonClockInfoArray *non_clock_info_array;
+	struct _StateArray *state_array;
+	struct _ClockInfoArray *clock_info_array;
+	struct _NonClockInfoArray *non_clock_info_array;
 	bool valid;
 	union power_info *power_info;
 	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
@@ -2434,13 +2483,13 @@
 	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
 
 	radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
-	state_array = (struct StateArray *)
+	state_array = (struct _StateArray *)
 		(mode_info->atom_context->bios + data_offset +
 		 le16_to_cpu(power_info->pplib.usStateArrayOffset));
-	clock_info_array = (struct ClockInfoArray *)
+	clock_info_array = (struct _ClockInfoArray *)
 		(mode_info->atom_context->bios + data_offset +
 		 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
-	non_clock_info_array = (struct NonClockInfoArray *)
+	non_clock_info_array = (struct _NonClockInfoArray *)
 		(mode_info->atom_context->bios + data_offset +
 		 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
 	rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) *
@@ -2467,7 +2516,7 @@
 				if (clock_array_index >= clock_info_array->ucNumEntries)
 					continue;
 				clock_info = (union pplib_clock_info *)
-					&clock_info_array->clockInfo[clock_array_index];
+					&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
 				valid = radeon_atombios_parse_pplib_clock_info(rdev,
 									       state_index, mode_index,
 									       clock_info);
@@ -2624,6 +2673,7 @@
 	struct _SET_VOLTAGE_PS_ALLOCATION alloc;
 	struct _SET_VOLTAGE_PARAMETERS v1;
 	struct _SET_VOLTAGE_PARAMETERS_V2 v2;
+	struct _SET_VOLTAGE_PARAMETERS_V1_3 v3;
 };
 
 void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type)
@@ -2650,6 +2700,11 @@
 		args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE;
 		args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
 		break;
+	case 3:
+		args.v3.ucVoltageType = voltage_type;
+		args.v3.ucVoltageMode = ATOM_SET_VOLTAGE;
+		args.v3.usVoltageLevel = cpu_to_le16(voltage_level);
+		break;
 	default:
 		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
 		return;
@@ -2658,8 +2713,8 @@
 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
-int radeon_atom_get_max_vddc(struct radeon_device *rdev,
-			     u16 *voltage)
+static int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
+				    u16 voltage_id, u16 *voltage)
 {
 	union set_voltage args;
 	int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
@@ -2680,6 +2735,15 @@
 
 		*voltage = le16_to_cpu(args.v2.usVoltageLevel);
 		break;
+	case 3:
+		args.v3.ucVoltageType = voltage_type;
+		args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL;
+		args.v3.usVoltageLevel = cpu_to_le16(voltage_id);
+
+		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+		*voltage = le16_to_cpu(args.v3.usVoltageLevel);
+		break;
 	default:
 		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
 		return -EINVAL;
diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c
index 815f234..fef7b72 100644
--- a/drivers/gpu/drm/radeon/radeon_benchmark.c
+++ b/drivers/gpu/drm/radeon/radeon_benchmark.c
@@ -43,17 +43,19 @@
 
 	start_jiffies = jiffies;
 	for (i = 0; i < n; i++) {
-		r = radeon_fence_create(rdev, &fence, RADEON_RING_TYPE_GFX_INDEX);
-		if (r)
-			return r;
-
 		switch (flag) {
 		case RADEON_BENCHMARK_COPY_DMA:
+			r = radeon_fence_create(rdev, &fence, radeon_copy_dma_ring_index(rdev));
+			if (r)
+				return r;
 			r = radeon_copy_dma(rdev, saddr, daddr,
 					    size / RADEON_GPU_PAGE_SIZE,
 					    fence);
 			break;
 		case RADEON_BENCHMARK_COPY_BLIT:
+			r = radeon_fence_create(rdev, &fence, radeon_copy_blit_ring_index(rdev));
+			if (r)
+				return r;
 			r = radeon_copy_blit(rdev, saddr, daddr,
 					     size / RADEON_GPU_PAGE_SIZE,
 					     fence);
@@ -129,7 +131,7 @@
 	/* r100 doesn't have dma engine so skip the test */
 	/* also, VRAM-to-VRAM test doesn't make much sense for DMA */
 	/* skip it as well if domains are the same */
-	if ((rdev->asic->copy_dma) && (sdomain != ddomain)) {
+	if ((rdev->asic->copy.dma) && (sdomain != ddomain)) {
 		time = radeon_benchmark_do_move(rdev, size, saddr, daddr,
 						RADEON_BENCHMARK_COPY_DMA, n);
 		if (time < 0)
@@ -208,22 +210,22 @@
 		break;
 	case 3:
 		/* GTT to VRAM, buffer size sweep, powers of 2 */
-		for (i = 1; i <= 65536; i <<= 1)
-			radeon_benchmark_move(rdev, i*1024,
+		for (i = 1; i <= 16384; i <<= 1)
+			radeon_benchmark_move(rdev, i * RADEON_GPU_PAGE_SIZE,
 					      RADEON_GEM_DOMAIN_GTT,
 					      RADEON_GEM_DOMAIN_VRAM);
 		break;
 	case 4:
 		/* VRAM to GTT, buffer size sweep, powers of 2 */
-		for (i = 1; i <= 65536; i <<= 1)
-			radeon_benchmark_move(rdev, i*1024,
+		for (i = 1; i <= 16384; i <<= 1)
+			radeon_benchmark_move(rdev, i * RADEON_GPU_PAGE_SIZE,
 					      RADEON_GEM_DOMAIN_VRAM,
 					      RADEON_GEM_DOMAIN_GTT);
 		break;
 	case 5:
 		/* VRAM to VRAM, buffer size sweep, powers of 2 */
-		for (i = 1; i <= 65536; i <<= 1)
-			radeon_benchmark_move(rdev, i*1024,
+		for (i = 1; i <= 16384; i <<= 1)
+			radeon_benchmark_move(rdev, i * RADEON_GPU_PAGE_SIZE,
 					      RADEON_GEM_DOMAIN_VRAM,
 					      RADEON_GEM_DOMAIN_VRAM);
 		break;
diff --git a/drivers/gpu/drm/radeon/radeon_blit_common.h b/drivers/gpu/drm/radeon/radeon_blit_common.h
new file mode 100644
index 0000000..4ecbe72
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_blit_common.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2009 Advanced Micro Devices, Inc.
+ * Copyright 2009 Red Hat Inc.
+ * Copyright 2012 Alcatel-Lucent, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __RADEON_BLIT_COMMON_H__
+
+#define DI_PT_RECTLIST        0x11
+#define DI_INDEX_SIZE_16_BIT  0x0
+#define DI_SRC_SEL_AUTO_INDEX 0x2
+
+#define FMT_8                 0x1
+#define FMT_5_6_5             0x8
+#define FMT_8_8_8_8           0x1a
+#define COLOR_8               0x1
+#define COLOR_5_6_5           0x8
+#define COLOR_8_8_8_8         0x1a
+
+#define RECT_UNIT_H           32
+#define RECT_UNIT_W           (RADEON_GPU_PAGE_SIZE / 4 / RECT_UNIT_H)
+
+#define __RADEON_BLIT_COMMON_H__
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c
index b6e18c8..6ae0c75 100644
--- a/drivers/gpu/drm/radeon/radeon_clocks.c
+++ b/drivers/gpu/drm/radeon/radeon_clocks.c
@@ -334,7 +334,7 @@
 
 	if (!rdev->clock.default_sclk)
 		rdev->clock.default_sclk = radeon_get_engine_clock(rdev);
-	if ((!rdev->clock.default_mclk) && rdev->asic->get_memory_clock)
+	if ((!rdev->clock.default_mclk) && rdev->asic->pm.get_memory_clock)
 		rdev->clock.default_mclk = radeon_get_memory_clock(rdev);
 
 	rdev->pm.current_sclk = rdev->clock.default_sclk;
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 8c9a811..bd05156 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -827,6 +827,27 @@
 	return ret;
 }
 
+static bool radeon_check_hpd_status_unchanged(struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+	enum drm_connector_status status;
+
+	/* We only trust HPD on R600 and newer ASICS. */
+	if (rdev->family >= CHIP_R600
+	  && radeon_connector->hpd.hpd != RADEON_HPD_NONE) {
+		if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
+			status = connector_status_connected;
+		else
+			status = connector_status_disconnected;
+		if (connector->status == status)
+			return true;
+	}
+
+	return false;
+}
+
 /*
  * DVI is complicated
  * Do a DDC probe, if DDC probe passes, get the full EDID so
@@ -851,6 +872,9 @@
 	enum drm_connector_status ret = connector_status_disconnected;
 	bool dret = false;
 
+	if (!force && radeon_check_hpd_status_unchanged(connector))
+		return connector->status;
+
 	if (radeon_connector->ddc_bus)
 		dret = radeon_ddc_probe(radeon_connector);
 	if (dret) {
@@ -946,6 +970,10 @@
 
 			encoder = obj_to_encoder(obj);
 
+			if (encoder->encoder_type != DRM_MODE_ENCODER_DAC ||
+			    encoder->encoder_type != DRM_MODE_ENCODER_TVDAC)
+				continue;
+
 			encoder_funcs = encoder->helper_private;
 			if (encoder_funcs->detect) {
 				if (ret != connector_status_connected) {
@@ -1057,7 +1085,7 @@
 		    (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B))
 			return MODE_OK;
 		else if (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_A) {
-			if (0) {
+			if (ASIC_IS_DCE6(rdev)) {
 				/* HDMI 1.3+ supports max clock of 340 Mhz */
 				if (mode->clock > 340000)
 					return MODE_CLOCK_HIGH;
@@ -1250,6 +1278,9 @@
 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
 
+	if (!force && radeon_check_hpd_status_unchanged(connector))
+		return connector->status;
+
 	if (radeon_connector->edid) {
 		kfree(radeon_connector->edid);
 		radeon_connector->edid = NULL;
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
index 72ae826..0ebb7d4 100644
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
@@ -2115,6 +2115,8 @@
 		break;
 	}
 
+	pci_set_master(dev->pdev);
+
 	if (drm_pci_device_is_agp(dev))
 		dev_priv->flags |= RADEON_IS_AGP;
 	else if (pci_is_pcie(dev->pdev))
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index e64bec4..5cac832 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -85,12 +85,6 @@
 			radeon_bo_list_add_object(&p->relocs[i].lobj,
 						  &p->validated);
 
-			if (p->relocs[i].robj->tbo.sync_obj && !(r->flags & RADEON_RELOC_DONT_SYNC)) {
-				struct radeon_fence *fence = p->relocs[i].robj->tbo.sync_obj;
-				if (!radeon_fence_signaled(fence)) {
-					p->sync_to_ring[fence->ring] = true;
-				}
-			}
 		} else
 			p->relocs[i].handle = 0;
 	}
@@ -109,8 +103,13 @@
 		p->ring = RADEON_RING_TYPE_GFX_INDEX;
 		break;
 	case RADEON_CS_RING_COMPUTE:
-		/* for now */
-		p->ring = RADEON_RING_TYPE_GFX_INDEX;
+		if (p->rdev->family >= CHIP_TAHITI) {
+			if (p->priority > 0)
+				p->ring = CAYMAN_RING_TYPE_CP1_INDEX;
+			else
+				p->ring = CAYMAN_RING_TYPE_CP2_INDEX;
+		} else
+			p->ring = RADEON_RING_TYPE_GFX_INDEX;
 		break;
 	}
 	return 0;
@@ -118,11 +117,24 @@
 
 static int radeon_cs_sync_rings(struct radeon_cs_parser *p)
 {
+	bool sync_to_ring[RADEON_NUM_RINGS] = { };
 	int i, r;
 
+	for (i = 0; i < p->nrelocs; i++) {
+		if (!p->relocs[i].robj || !p->relocs[i].robj->tbo.sync_obj)
+			continue;
+
+		if (!(p->relocs[i].flags & RADEON_RELOC_DONT_SYNC)) {
+			struct radeon_fence *fence = p->relocs[i].robj->tbo.sync_obj;
+			if (!radeon_fence_signaled(fence)) {
+				sync_to_ring[fence->ring] = true;
+			}
+		}
+	}
+
 	for (i = 0; i < RADEON_NUM_RINGS; ++i) {
 		/* no need to sync to our own or unused rings */
-		if (i == p->ring || !p->sync_to_ring[i] || !p->rdev->ring[i].ready)
+		if (i == p->ring || !sync_to_ring[i] || !p->rdev->ring[i].ready)
 			continue;
 
 		if (!p->ib->fence->semaphore) {
@@ -163,6 +175,7 @@
 	p->chunk_ib_idx = -1;
 	p->chunk_relocs_idx = -1;
 	p->chunk_flags_idx = -1;
+	p->chunk_const_ib_idx = -1;
 	p->chunks_array = kcalloc(cs->num_chunks, sizeof(uint64_t), GFP_KERNEL);
 	if (p->chunks_array == NULL) {
 		return -ENOMEM;
@@ -201,6 +214,12 @@
 			if (p->chunks[i].length_dw == 0)
 				return -EINVAL;
 		}
+		if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_CONST_IB) {
+			p->chunk_const_ib_idx = i;
+			/* zero length CONST IB isn't useful */
+			if (p->chunks[i].length_dw == 0)
+				return -EINVAL;
+		}
 		if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_FLAGS) {
 			p->chunk_flags_idx = i;
 			/* zero length flags aren't useful */
@@ -236,21 +255,19 @@
 	if ((p->cs_flags & RADEON_CS_USE_VM) &&
 	    !p->rdev->vm_manager.enabled) {
 		DRM_ERROR("VM not active on asic!\n");
-		if (p->chunk_relocs_idx != -1)
-			kfree(p->chunks[p->chunk_relocs_idx].kdata);
-		if (p->chunk_flags_idx != -1)
-			kfree(p->chunks[p->chunk_flags_idx].kdata);
 		return -EINVAL;
 	}
 
-	if (radeon_cs_get_ring(p, ring, priority)) {
-		if (p->chunk_relocs_idx != -1)
-			kfree(p->chunks[p->chunk_relocs_idx].kdata);
-		if (p->chunk_flags_idx != -1)
-			kfree(p->chunks[p->chunk_flags_idx].kdata);
+	/* we only support VM on SI+ */
+	if ((p->rdev->family >= CHIP_TAHITI) &&
+	    ((p->cs_flags & RADEON_CS_USE_VM) == 0)) {
+		DRM_ERROR("VM required on SI+!\n");
 		return -EINVAL;
 	}
 
+	if (radeon_cs_get_ring(p, ring, priority))
+		return -EINVAL;
+
 
 	/* deal with non-vm */
 	if ((p->chunk_ib_idx != -1) &&
@@ -264,11 +281,8 @@
 		p->chunks[p->chunk_ib_idx].kpage[0] = kmalloc(PAGE_SIZE, GFP_KERNEL);
 		p->chunks[p->chunk_ib_idx].kpage[1] = kmalloc(PAGE_SIZE, GFP_KERNEL);
 		if (p->chunks[p->chunk_ib_idx].kpage[0] == NULL ||
-		    p->chunks[p->chunk_ib_idx].kpage[1] == NULL) {
-			kfree(p->chunks[p->chunk_ib_idx].kpage[0]);
-			kfree(p->chunks[p->chunk_ib_idx].kpage[1]);
+		    p->chunks[p->chunk_ib_idx].kpage[1] == NULL)
 			return -ENOMEM;
-		}
 		p->chunks[p->chunk_ib_idx].kpage_idx[0] = -1;
 		p->chunks[p->chunk_ib_idx].kpage_idx[1] = -1;
 		p->chunks[p->chunk_ib_idx].last_copied_page = -1;
@@ -341,7 +355,7 @@
 		return r;
 	}
 	parser->ib->length_dw = ib_chunk->length_dw;
-	r = radeon_cs_parse(parser);
+	r = radeon_cs_parse(rdev, parser->ring, parser);
 	if (r || parser->parser_error) {
 		DRM_ERROR("Invalid command stream !\n");
 		return r;
@@ -394,6 +408,32 @@
 	if ((parser->cs_flags & RADEON_CS_USE_VM) == 0)
 		return 0;
 
+	if ((rdev->family >= CHIP_TAHITI) &&
+	    (parser->chunk_const_ib_idx != -1)) {
+		ib_chunk = &parser->chunks[parser->chunk_const_ib_idx];
+		if (ib_chunk->length_dw > RADEON_IB_VM_MAX_SIZE) {
+			DRM_ERROR("cs IB CONST too big: %d\n", ib_chunk->length_dw);
+			return -EINVAL;
+		}
+		r =  radeon_ib_get(rdev, parser->ring, &parser->const_ib,
+				   ib_chunk->length_dw * 4);
+		if (r) {
+			DRM_ERROR("Failed to get const ib !\n");
+			return r;
+		}
+		parser->const_ib->is_const_ib = true;
+		parser->const_ib->length_dw = ib_chunk->length_dw;
+		/* Copy the packet into the IB */
+		if (DRM_COPY_FROM_USER(parser->const_ib->ptr, ib_chunk->user_ptr,
+				       ib_chunk->length_dw * 4)) {
+			return -EFAULT;
+		}
+		r = radeon_ring_ib_parse(rdev, parser->ring, parser->const_ib);
+		if (r) {
+			return r;
+		}
+	}
+
 	ib_chunk = &parser->chunks[parser->chunk_ib_idx];
 	if (ib_chunk->length_dw > RADEON_IB_VM_MAX_SIZE) {
 		DRM_ERROR("cs IB too big: %d\n", ib_chunk->length_dw);
@@ -429,11 +469,25 @@
 	if (r) {
 		DRM_ERROR("Failed to synchronize rings !\n");
 	}
+
+	if ((rdev->family >= CHIP_TAHITI) &&
+	    (parser->chunk_const_ib_idx != -1)) {
+		parser->const_ib->vm_id = vm->id;
+		/* ib pool is bind at 0 in virtual address space to gpu_addr is the
+		 * offset inside the pool bo
+		 */
+		parser->const_ib->gpu_addr = parser->const_ib->sa_bo.offset;
+		r = radeon_ib_schedule(rdev, parser->const_ib);
+		if (r)
+			goto out;
+	}
+
 	parser->ib->vm_id = vm->id;
 	/* ib pool is bind at 0 in virtual address space to gpu_addr is the
 	 * offset inside the pool bo
 	 */
 	parser->ib->gpu_addr = parser->ib->sa_bo.offset;
+	parser->ib->is_const_ib = false;
 	r = radeon_ib_schedule(rdev, parser->ib);
 out:
 	if (!r) {
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index fde25c0..42acc64 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -151,7 +151,9 @@
 			   uint32_t height)
 {
 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+	struct radeon_device *rdev = crtc->dev->dev_private;
 	struct drm_gem_object *obj;
+	struct radeon_bo *robj;
 	uint64_t gpu_addr;
 	int ret;
 
@@ -173,7 +175,15 @@
 		return -ENOENT;
 	}
 
-	ret = radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
+	robj = gem_to_radeon_bo(obj);
+	ret = radeon_bo_reserve(robj, false);
+	if (unlikely(ret != 0))
+		goto fail;
+	/* Only 27 bit offset for legacy cursor */
+	ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM,
+				       ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
+				       &gpu_addr);
+	radeon_bo_unreserve(robj);
 	if (ret)
 		goto fail;
 
@@ -181,14 +191,18 @@
 	radeon_crtc->cursor_height = height;
 
 	radeon_lock_cursor(crtc, true);
-	/* XXX only 27 bit offset for legacy cursor */
 	radeon_set_cursor(crtc, obj, gpu_addr);
 	radeon_show_cursor(crtc);
 	radeon_lock_cursor(crtc, false);
 
 unpin:
 	if (radeon_crtc->cursor_bo) {
-		radeon_gem_object_unpin(radeon_crtc->cursor_bo);
+		robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
+		ret = radeon_bo_reserve(robj, false);
+		if (likely(ret == 0)) {
+			radeon_bo_unpin(robj);
+			radeon_bo_unreserve(robj);
+		}
 		drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo);
 	}
 
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 49f7cb7..ea7df16e2 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -89,6 +89,10 @@
 	"TURKS",
 	"CAICOS",
 	"CAYMAN",
+	"ARUBA",
+	"TAHITI",
+	"PITCAIRN",
+	"VERDE",
 	"LAST",
 };
 
@@ -964,7 +968,7 @@
 	/* init dig PHYs, disp eng pll */
 	if (rdev->is_atom_bios) {
 		radeon_atom_encoder_init(rdev);
-		radeon_atom_dcpll_init(rdev);
+		radeon_atom_disp_eng_pll_init(rdev);
 	}
 	/* reset hpd state */
 	radeon_hpd_init(rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 3d31433..8086c96 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -303,8 +303,17 @@
 	if (update_pending &&
 	    (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id,
 							       &vpos, &hpos)) &&
-	    (vpos >=0) &&
-	    (vpos < (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100)) {
+	    ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) ||
+	     (vpos < 0 && !ASIC_IS_AVIVO(rdev)))) {
+		/* crtc didn't flip in this target vblank interval,
+		 * but flip is pending in crtc. Based on the current
+		 * scanout position we know that the current frame is
+		 * (nearly) complete and the flip will (likely)
+		 * complete before the start of the next frame.
+		 */
+		update_pending = 0;
+	}
+	if (update_pending) {
 		/* crtc didn't flip in this target vblank interval,
 		 * but flip is pending in crtc. It will complete it
 		 * in next vblank interval, so complete the flip at
@@ -393,7 +402,9 @@
 		DRM_ERROR("failed to reserve new rbo buffer before flip\n");
 		goto pflip_cleanup;
 	}
-	r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &base);
+	/* Only 27 bit offset for legacy CRTC */
+	r = radeon_bo_pin_restricted(rbo, RADEON_GEM_DOMAIN_VRAM,
+				     ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, &base);
 	if (unlikely(r != 0)) {
 		radeon_bo_unreserve(rbo);
 		r = -EINVAL;
@@ -1136,11 +1147,6 @@
 	.output_poll_changed = radeon_output_poll_changed
 };
 
-struct drm_prop_enum_list {
-	int type;
-	char *name;
-};
-
 static struct drm_prop_enum_list radeon_tmds_pll_enum_list[] =
 {	{ 0, "driver" },
 	{ 1, "bios" },
@@ -1165,86 +1171,53 @@
 
 static int radeon_modeset_create_props(struct radeon_device *rdev)
 {
-	int i, sz;
+	int sz;
 
 	if (rdev->is_atom_bios) {
 		rdev->mode_info.coherent_mode_property =
-			drm_property_create(rdev->ddev,
-					    DRM_MODE_PROP_RANGE,
-					    "coherent", 2);
+			drm_property_create_range(rdev->ddev, 0 , "coherent", 0, 1);
 		if (!rdev->mode_info.coherent_mode_property)
 			return -ENOMEM;
-
-		rdev->mode_info.coherent_mode_property->values[0] = 0;
-		rdev->mode_info.coherent_mode_property->values[1] = 1;
 	}
 
 	if (!ASIC_IS_AVIVO(rdev)) {
 		sz = ARRAY_SIZE(radeon_tmds_pll_enum_list);
 		rdev->mode_info.tmds_pll_property =
-			drm_property_create(rdev->ddev,
-					    DRM_MODE_PROP_ENUM,
-					    "tmds_pll", sz);
-		for (i = 0; i < sz; i++) {
-			drm_property_add_enum(rdev->mode_info.tmds_pll_property,
-					      i,
-					      radeon_tmds_pll_enum_list[i].type,
-					      radeon_tmds_pll_enum_list[i].name);
-		}
+			drm_property_create_enum(rdev->ddev, 0,
+					    "tmds_pll",
+					    radeon_tmds_pll_enum_list, sz);
 	}
 
 	rdev->mode_info.load_detect_property =
-		drm_property_create(rdev->ddev,
-				    DRM_MODE_PROP_RANGE,
-				    "load detection", 2);
+		drm_property_create_range(rdev->ddev, 0, "load detection", 0, 1);
 	if (!rdev->mode_info.load_detect_property)
 		return -ENOMEM;
-	rdev->mode_info.load_detect_property->values[0] = 0;
-	rdev->mode_info.load_detect_property->values[1] = 1;
 
 	drm_mode_create_scaling_mode_property(rdev->ddev);
 
 	sz = ARRAY_SIZE(radeon_tv_std_enum_list);
 	rdev->mode_info.tv_std_property =
-		drm_property_create(rdev->ddev,
-				    DRM_MODE_PROP_ENUM,
-				    "tv standard", sz);
-	for (i = 0; i < sz; i++) {
-		drm_property_add_enum(rdev->mode_info.tv_std_property,
-				      i,
-				      radeon_tv_std_enum_list[i].type,
-				      radeon_tv_std_enum_list[i].name);
-	}
+		drm_property_create_enum(rdev->ddev, 0,
+				    "tv standard",
+				    radeon_tv_std_enum_list, sz);
 
 	sz = ARRAY_SIZE(radeon_underscan_enum_list);
 	rdev->mode_info.underscan_property =
-		drm_property_create(rdev->ddev,
-				    DRM_MODE_PROP_ENUM,
-				    "underscan", sz);
-	for (i = 0; i < sz; i++) {
-		drm_property_add_enum(rdev->mode_info.underscan_property,
-				      i,
-				      radeon_underscan_enum_list[i].type,
-				      radeon_underscan_enum_list[i].name);
-	}
+		drm_property_create_enum(rdev->ddev, 0,
+				    "underscan",
+				    radeon_underscan_enum_list, sz);
 
 	rdev->mode_info.underscan_hborder_property =
-		drm_property_create(rdev->ddev,
-					DRM_MODE_PROP_RANGE,
-					"underscan hborder", 2);
+		drm_property_create_range(rdev->ddev, 0,
+					"underscan hborder", 0, 128);
 	if (!rdev->mode_info.underscan_hborder_property)
 		return -ENOMEM;
-	rdev->mode_info.underscan_hborder_property->values[0] = 0;
-	rdev->mode_info.underscan_hborder_property->values[1] = 128;
 
 	rdev->mode_info.underscan_vborder_property =
-		drm_property_create(rdev->ddev,
-					DRM_MODE_PROP_RANGE,
-					"underscan vborder", 2);
+		drm_property_create_range(rdev->ddev, 0,
+					"underscan vborder", 0, 128);
 	if (!rdev->mode_info.underscan_vborder_property)
 		return -ENOMEM;
-	rdev->mode_info.underscan_vborder_property->values[0] = 0;
-	rdev->mode_info.underscan_vborder_property->values[1] = 128;
 
 	return 0;
 }
@@ -1290,6 +1263,9 @@
 		rdev->ddev->mode_config.max_height = 4096;
 	}
 
+	rdev->ddev->mode_config.preferred_depth = 24;
+	rdev->ddev->mode_config.prefer_shadow = 1;
+
 	rdev->ddev->mode_config.fb_base = rdev->mc.aper_base;
 
 	ret = radeon_modeset_create_props(rdev);
@@ -1320,7 +1296,7 @@
 	/* init dig PHYs, disp eng pll */
 	if (rdev->is_atom_bios) {
 		radeon_atom_encoder_init(rdev);
-		radeon_atom_dcpll_init(rdev);
+		radeon_atom_disp_eng_pll_init(rdev);
 	}
 
 	/* initialize hpd */
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 8032f1f..ef7bb3f 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -54,10 +54,12 @@
  *   2.10.0 - fusion 2D tiling
  *   2.11.0 - backend map, initial compute support for the CS checker
  *   2.12.0 - RADEON_CS_KEEP_TILING_FLAGS
- *   2.13.0 - virtual memory support
+ *   2.13.0 - virtual memory support, streamout
+ *   2.14.0 - add evergreen tiling informations
+ *   2.15.0 - add max_pipes query
  */
 #define KMS_DRIVER_MAJOR	2
-#define KMS_DRIVER_MINOR	13
+#define KMS_DRIVER_MINOR	15
 #define KMS_DRIVER_PATCHLEVEL	0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index 26e9270..7467069 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -307,6 +307,8 @@
 bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
 				    u32 pixel_clock)
 {
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
 	struct drm_connector *connector;
 	struct radeon_connector *radeon_connector;
 	struct radeon_connector_atom_dig *dig_connector;
@@ -324,7 +326,7 @@
 	case DRM_MODE_CONNECTOR_HDMIB:
 		if (radeon_connector->use_digital) {
 			/* HDMI 1.3 supports up to 340 Mhz over single link */
-			if (0 && drm_detect_hdmi_monitor(radeon_connector->edid)) {
+			if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) {
 				if (pixel_clock > 340000)
 					return true;
 				else
@@ -346,7 +348,7 @@
 			return false;
 		else {
 			/* HDMI 1.3 supports up to 340 Mhz over single link */
-			if (0 && drm_detect_hdmi_monitor(radeon_connector->edid)) {
+			if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) {
 				if (pixel_clock > 340000)
 					return true;
 				else
diff --git a/drivers/gpu/drm/radeon/radeon_family.h b/drivers/gpu/drm/radeon/radeon_family.h
index ec2f1ea..d1fafea 100644
--- a/drivers/gpu/drm/radeon/radeon_family.h
+++ b/drivers/gpu/drm/radeon/radeon_family.h
@@ -87,6 +87,10 @@
 	CHIP_TURKS,
 	CHIP_CAICOS,
 	CHIP_CAYMAN,
+	CHIP_ARUBA,
+	CHIP_TAHITI,
+	CHIP_PITCAIRN,
+	CHIP_VERDE,
 	CHIP_LAST,
 };
 
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index 195471c..5906914 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -164,7 +164,10 @@
 	ret = radeon_bo_reserve(rbo, false);
 	if (unlikely(ret != 0))
 		goto out_unref;
-	ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, NULL);
+	/* Only 27 bit offset for legacy CRTC */
+	ret = radeon_bo_pin_restricted(rbo, RADEON_GEM_DOMAIN_VRAM,
+				       ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
+				       NULL);
 	if (ret) {
 		radeon_bo_unreserve(rbo);
 		goto out_unref;
@@ -263,11 +266,7 @@
 	info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base;
 	info->apertures->ranges[0].size = rdev->mc.aper_size;
 
-	info->pixmap.size = 64*1024;
-	info->pixmap.buf_align = 8;
-	info->pixmap.access_align = 32;
-	info->pixmap.flags = FB_PIXMAP_SYSTEM;
-	info->pixmap.scan_align = 1;
+	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
 
 	if (info->screen_base == NULL) {
 		ret = -ENOSPC;
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
index 7337850..c7008b5 100644
--- a/drivers/gpu/drm/radeon/radeon_gem.c
+++ b/drivers/gpu/drm/radeon/radeon_gem.c
@@ -75,32 +75,6 @@
 	return 0;
 }
 
-int radeon_gem_object_pin(struct drm_gem_object *obj, uint32_t pin_domain,
-			  uint64_t *gpu_addr)
-{
-	struct radeon_bo *robj = gem_to_radeon_bo(obj);
-	int r;
-
-	r = radeon_bo_reserve(robj, false);
-	if (unlikely(r != 0))
-		return r;
-	r = radeon_bo_pin(robj, pin_domain, gpu_addr);
-	radeon_bo_unreserve(robj);
-	return r;
-}
-
-void radeon_gem_object_unpin(struct drm_gem_object *obj)
-{
-	struct radeon_bo *robj = gem_to_radeon_bo(obj);
-	int r;
-
-	r = radeon_bo_reserve(robj, false);
-	if (likely(r == 0)) {
-		radeon_bo_unpin(robj);
-		radeon_bo_unreserve(robj);
-	}
-}
-
 int radeon_gem_set_domain(struct drm_gem_object *gobj,
 			  uint32_t rdomain, uint32_t wdomain)
 {
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c
index 98a8ad6..85bcfc8 100644
--- a/drivers/gpu/drm/radeon/radeon_i2c.c
+++ b/drivers/gpu/drm/radeon/radeon_i2c.c
@@ -26,10 +26,15 @@
 #include <linux/export.h>
 
 #include "drmP.h"
+#include "drm_edid.h"
 #include "radeon_drm.h"
 #include "radeon.h"
 #include "atom.h"
 
+extern int radeon_atom_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
+				   struct i2c_msg *msgs, int num);
+extern u32 radeon_atom_hw_i2c_func(struct i2c_adapter *adap);
+
 /**
  * radeon_ddc_probe
  *
@@ -41,13 +46,13 @@
 	int ret;
 	struct i2c_msg msgs[] = {
 		{
-			.addr = 0x50,
+			.addr = DDC_ADDR,
 			.flags = 0,
 			.len = 1,
 			.buf = &out,
 		},
 		{
-			.addr = 0x50,
+			.addr = DDC_ADDR,
 			.flags = I2C_M_RD,
 			.len = 8,
 			.buf = buf,
@@ -882,6 +887,11 @@
 	.functionality = radeon_hw_i2c_func,
 };
 
+static const struct i2c_algorithm radeon_atom_i2c_algo = {
+	.master_xfer = radeon_atom_hw_i2c_xfer,
+	.functionality = radeon_atom_hw_i2c_func,
+};
+
 struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
 					  struct radeon_i2c_bus_rec *rec,
 					  const char *name)
@@ -914,6 +924,18 @@
 			DRM_ERROR("Failed to register hw i2c %s\n", name);
 			goto out_free;
 		}
+	} else if (rec->hw_capable &&
+		   radeon_hw_i2c &&
+		   ASIC_IS_DCE3(rdev)) {
+		/* hw i2c using atom */
+		snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+			 "Radeon i2c hw bus %s", name);
+		i2c->adapter.algo = &radeon_atom_i2c_algo;
+		ret = i2c_add_adapter(&i2c->adapter);
+		if (ret) {
+			DRM_ERROR("Failed to register hw i2c %s\n", name);
+			goto out_free;
+		}
 	} else {
 		/* set the radeon bit adapter */
 		snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
@@ -925,10 +947,8 @@
 		i2c->algo.bit.setscl = set_clock;
 		i2c->algo.bit.getsda = get_data;
 		i2c->algo.bit.getscl = get_clock;
-		i2c->algo.bit.udelay = 20;
-		/* vesa says 2.2 ms is enough, 1 jiffy doesn't seem to always
-		 * make this, 2 jiffies is a lot more reliable */
-		i2c->algo.bit.timeout = 2;
+		i2c->algo.bit.udelay = 10;
+		i2c->algo.bit.timeout = usecs_to_jiffies(2200);	/* from VESA */
 		i2c->algo.bit.data = i2c;
 		ret = i2c_bit_add_bus(&i2c->adapter);
 		if (ret) {
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index d335288..3c2628b 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -57,6 +57,8 @@
 	}
 	dev->dev_private = (void *)rdev;
 
+	pci_set_master(dev->pdev);
+
 	/* update BUS flag */
 	if (drm_pci_device_is_agp(dev)) {
 		flags |= RADEON_IS_AGP;
@@ -169,7 +171,9 @@
 		value = rdev->accel_working;
 		break;
 	case RADEON_INFO_TILING_CONFIG:
-		if (rdev->family >= CHIP_CAYMAN)
+		if (rdev->family >= CHIP_TAHITI)
+			value = rdev->config.si.tile_config;
+		else if (rdev->family >= CHIP_CAYMAN)
 			value = rdev->config.cayman.tile_config;
 		else if (rdev->family >= CHIP_CEDAR)
 			value = rdev->config.evergreen.tile_config;
@@ -208,7 +212,10 @@
 		value = rdev->clock.spll.reference_freq * 10;
 		break;
 	case RADEON_INFO_NUM_BACKENDS:
-		if (rdev->family >= CHIP_CAYMAN)
+		if (rdev->family >= CHIP_TAHITI)
+			value = rdev->config.si.max_backends_per_se *
+				rdev->config.si.max_shader_engines;
+		else if (rdev->family >= CHIP_CAYMAN)
 			value = rdev->config.cayman.max_backends_per_se *
 				rdev->config.cayman.max_shader_engines;
 		else if (rdev->family >= CHIP_CEDAR)
@@ -222,7 +229,9 @@
 		}
 		break;
 	case RADEON_INFO_NUM_TILE_PIPES:
-		if (rdev->family >= CHIP_CAYMAN)
+		if (rdev->family >= CHIP_TAHITI)
+			value = rdev->config.si.max_tile_pipes;
+		else if (rdev->family >= CHIP_CAYMAN)
 			value = rdev->config.cayman.max_tile_pipes;
 		else if (rdev->family >= CHIP_CEDAR)
 			value = rdev->config.evergreen.max_tile_pipes;
@@ -238,7 +247,9 @@
 		value = 1;
 		break;
 	case RADEON_INFO_BACKEND_MAP:
-		if (rdev->family >= CHIP_CAYMAN)
+		if (rdev->family >= CHIP_TAHITI)
+			value = rdev->config.si.backend_map;
+		else if (rdev->family >= CHIP_CAYMAN)
 			value = rdev->config.cayman.backend_map;
 		else if (rdev->family >= CHIP_CEDAR)
 			value = rdev->config.evergreen.backend_map;
@@ -262,6 +273,21 @@
 			return -EINVAL;
 		value = RADEON_IB_VM_MAX_SIZE;
 		break;
+	case RADEON_INFO_MAX_PIPES:
+		if (rdev->family >= CHIP_TAHITI)
+			value = rdev->config.si.max_pipes_per_simd;
+		else if (rdev->family >= CHIP_CAYMAN)
+			value = rdev->config.cayman.max_pipes_per_simd;
+		else if (rdev->family >= CHIP_CEDAR)
+			value = rdev->config.evergreen.max_pipes;
+		else if (rdev->family >= CHIP_RV770)
+			value = rdev->config.rv770.max_pipes;
+		else if (rdev->family >= CHIP_R600)
+			value = rdev->config.r600.max_pipes;
+		else {
+			return -EINVAL;
+		}
+		break;
 	default:
 		DRM_DEBUG_KMS("Invalid request %d\n", info->request);
 		return -EINVAL;
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index 25a19c4..210317c 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -419,7 +419,9 @@
 	r = radeon_bo_reserve(rbo, false);
 	if (unlikely(r != 0))
 		return r;
-	r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &base);
+	/* Only 27 bit offset for legacy CRTC */
+	r = radeon_bo_pin_restricted(rbo, RADEON_GEM_DOMAIN_VRAM, 1 << 27,
+				     &base);
 	if (unlikely(r != 0)) {
 		radeon_bo_unreserve(rbo);
 		return -EINVAL;
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 8a85598..f7eb5d8 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -491,7 +491,7 @@
 				    struct drm_connector *connector);
 extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode);
 extern void radeon_atom_encoder_init(struct radeon_device *rdev);
-extern void radeon_atom_dcpll_init(struct radeon_device *rdev);
+extern void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev);
 extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder,
 					   int action, uint8_t lane_num,
 					   uint8_t lane_set);
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index d45df17..df6a4db 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -224,7 +224,8 @@
 		*bo = NULL;
 }
 
-int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr)
+int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset,
+			     u64 *gpu_addr)
 {
 	int r, i;
 
@@ -232,6 +233,18 @@
 		bo->pin_count++;
 		if (gpu_addr)
 			*gpu_addr = radeon_bo_gpu_offset(bo);
+
+		if (max_offset != 0) {
+			u64 domain_start;
+
+			if (domain == RADEON_GEM_DOMAIN_VRAM)
+				domain_start = bo->rdev->mc.vram_start;
+			else
+				domain_start = bo->rdev->mc.gtt_start;
+			WARN_ON_ONCE(max_offset <
+				     (radeon_bo_gpu_offset(bo) - domain_start));
+		}
+
 		return 0;
 	}
 	radeon_ttm_placement_from_domain(bo, domain);
@@ -239,6 +252,15 @@
 		/* force to pin into visible video ram */
 		bo->placement.lpfn = bo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
 	}
+	if (max_offset) {
+		u64 lpfn = max_offset >> PAGE_SHIFT;
+
+		if (!bo->placement.lpfn)
+			bo->placement.lpfn = bo->rdev->mc.gtt_size >> PAGE_SHIFT;
+
+		if (lpfn < bo->placement.lpfn)
+			bo->placement.lpfn = lpfn;
+	}
 	for (i = 0; i < bo->placement.num_placement; i++)
 		bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
 	r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false, false);
@@ -252,6 +274,11 @@
 	return r;
 }
 
+int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr)
+{
+	return radeon_bo_pin_restricted(bo, domain, 0, gpu_addr);
+}
+
 int radeon_bo_unpin(struct radeon_bo *bo)
 {
 	int r, i;
@@ -445,8 +472,54 @@
 int radeon_bo_set_tiling_flags(struct radeon_bo *bo,
 				uint32_t tiling_flags, uint32_t pitch)
 {
+	struct radeon_device *rdev = bo->rdev;
 	int r;
 
+	if (rdev->family >= CHIP_CEDAR) {
+		unsigned bankw, bankh, mtaspect, tilesplit, stilesplit;
+
+		bankw = (tiling_flags >> RADEON_TILING_EG_BANKW_SHIFT) & RADEON_TILING_EG_BANKW_MASK;
+		bankh = (tiling_flags >> RADEON_TILING_EG_BANKH_SHIFT) & RADEON_TILING_EG_BANKH_MASK;
+		mtaspect = (tiling_flags >> RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT) & RADEON_TILING_EG_MACRO_TILE_ASPECT_MASK;
+		tilesplit = (tiling_flags >> RADEON_TILING_EG_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_TILE_SPLIT_MASK;
+		stilesplit = (tiling_flags >> RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_STENCIL_TILE_SPLIT_MASK;
+		switch (bankw) {
+		case 0:
+		case 1:
+		case 2:
+		case 4:
+		case 8:
+			break;
+		default:
+			return -EINVAL;
+		}
+		switch (bankh) {
+		case 0:
+		case 1:
+		case 2:
+		case 4:
+		case 8:
+			break;
+		default:
+			return -EINVAL;
+		}
+		switch (mtaspect) {
+		case 0:
+		case 1:
+		case 2:
+		case 4:
+		case 8:
+			break;
+		default:
+			return -EINVAL;
+		}
+		if (tilesplit > 6) {
+			return -EINVAL;
+		}
+		if (stilesplit > 6) {
+			return -EINVAL;
+		}
+	}
 	r = radeon_bo_reserve(bo, false);
 	if (unlikely(r != 0))
 		return r;
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h
index cde4303..f9104be 100644
--- a/drivers/gpu/drm/radeon/radeon_object.h
+++ b/drivers/gpu/drm/radeon/radeon_object.h
@@ -118,6 +118,8 @@
 extern void radeon_bo_kunmap(struct radeon_bo *bo);
 extern void radeon_bo_unref(struct radeon_bo **bo);
 extern int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr);
+extern int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain,
+				    u64 max_offset, u64 *gpu_addr);
 extern int radeon_bo_unpin(struct radeon_bo *bo);
 extern int radeon_bo_evict_vram(struct radeon_device *rdev);
 extern void radeon_bo_force_delete(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 095148e..caa55d6 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -221,7 +221,7 @@
 		}
 
 		/* set memory clock */
-		if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
+		if (rdev->asic->pm.set_memory_clock && (mclk != rdev->pm.current_mclk)) {
 			radeon_pm_debug_check_in_vbl(rdev, false);
 			radeon_set_memory_clock(rdev, mclk);
 			radeon_pm_debug_check_in_vbl(rdev, true);
@@ -474,6 +474,9 @@
 	case THERMAL_TYPE_SUMO:
 		temp = sumo_get_temp(rdev);
 		break;
+	case THERMAL_TYPE_SI:
+		temp = si_get_temp(rdev);
+		break;
 	default:
 		temp = 0;
 		break;
@@ -514,6 +517,10 @@
 	case THERMAL_TYPE_EVERGREEN:
 	case THERMAL_TYPE_NI:
 	case THERMAL_TYPE_SUMO:
+	case THERMAL_TYPE_SI:
+		/* No support for TN yet */
+		if (rdev->family == CHIP_ARUBA)
+			return err;
 		rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev);
 		if (IS_ERR(rdev->pm.int_hwmon_dev)) {
 			err = PTR_ERR(rdev->pm.int_hwmon_dev);
@@ -863,11 +870,11 @@
 	seq_printf(m, "default engine clock: %u0 kHz\n", rdev->pm.default_sclk);
 	seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev));
 	seq_printf(m, "default memory clock: %u0 kHz\n", rdev->pm.default_mclk);
-	if (rdev->asic->get_memory_clock)
+	if (rdev->asic->pm.get_memory_clock)
 		seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev));
 	if (rdev->pm.current_vddc)
 		seq_printf(m, "voltage: %u mV\n", rdev->pm.current_vddc);
-	if (rdev->asic->get_pcie_lanes)
+	if (rdev->asic->pm.get_pcie_lanes)
 		seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev));
 
 	return 0;
diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h
index b4ce864..5d8f735 100644
--- a/drivers/gpu/drm/radeon/radeon_reg.h
+++ b/drivers/gpu/drm/radeon/radeon_reg.h
@@ -56,6 +56,7 @@
 #include "r600_reg.h"
 #include "evergreen_reg.h"
 #include "ni_reg.h"
+#include "si_reg.h"
 
 #define RADEON_MC_AGP_LOCATION		0x014c
 #define		RADEON_MC_AGP_START_MASK	0x0000FFFF
@@ -539,9 +540,11 @@
 
 #define RADEON_CRTC2_PITCH                  0x032c
 #define RADEON_CRTC_STATUS                  0x005c
+#       define RADEON_CRTC_VBLANK_CUR       (1 <<  0)
 #       define RADEON_CRTC_VBLANK_SAVE      (1 <<  1)
 #       define RADEON_CRTC_VBLANK_SAVE_CLEAR  (1 <<  1)
 #define RADEON_CRTC2_STATUS                  0x03fc
+#       define RADEON_CRTC2_VBLANK_CUR       (1 <<  0)
 #       define RADEON_CRTC2_VBLANK_SAVE      (1 <<  1)
 #       define RADEON_CRTC2_VBLANK_SAVE_CLEAR  (1 <<  1)
 #define RADEON_CRTC_V_SYNC_STRT_WID         0x020c
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index 92c9ea4..cc33b3d 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -133,6 +133,7 @@
 				(*ib)->gpu_addr += (*ib)->sa_bo.offset;
 				(*ib)->fence = fence;
 				(*ib)->vm_id = 0;
+				(*ib)->is_const_ib = false;
 				/* ib are most likely to be allocated in a ring fashion
 				 * thus rdev->ib_pool.head_id should be the id of the
 				 * oldest ib
@@ -478,7 +479,9 @@
 static int radeon_debugfs_ib_info(struct seq_file *m, void *data)
 {
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
-	struct radeon_ib *ib = node->info_ent->data;
+	struct drm_device *dev = node->minor->dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct radeon_ib *ib = &rdev->ib_pool.ibs[*((unsigned*)node->info_ent->data)];
 	unsigned i;
 
 	if (ib == NULL) {
@@ -495,6 +498,7 @@
 
 static struct drm_info_list radeon_debugfs_ib_list[RADEON_IB_POOL_SIZE];
 static char radeon_debugfs_ib_names[RADEON_IB_POOL_SIZE][32];
+static unsigned radeon_debugfs_ib_idx[RADEON_IB_POOL_SIZE];
 #endif
 
 int radeon_debugfs_ring_init(struct radeon_device *rdev)
@@ -517,10 +521,11 @@
 
 	for (i = 0; i < RADEON_IB_POOL_SIZE; i++) {
 		sprintf(radeon_debugfs_ib_names[i], "radeon_ib_%04u", i);
+		radeon_debugfs_ib_idx[i] = i;
 		radeon_debugfs_ib_list[i].name = radeon_debugfs_ib_names[i];
 		radeon_debugfs_ib_list[i].show = &radeon_debugfs_ib_info;
 		radeon_debugfs_ib_list[i].driver_features = 0;
-		radeon_debugfs_ib_list[i].data = &rdev->ib_pool.ibs[i];
+		radeon_debugfs_ib_list[i].data = &radeon_debugfs_ib_idx[i];
 	}
 	return radeon_debugfs_add_files(rdev, radeon_debugfs_ib_list,
 					RADEON_IB_POOL_SIZE);
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index c421e77..f493c64 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -226,7 +226,7 @@
 	int r, i;
 
 	rdev = radeon_get_rdev(bo->bdev);
-	r = radeon_fence_create(rdev, &fence, rdev->copy_ring);
+	r = radeon_fence_create(rdev, &fence, radeon_copy_ring_index(rdev));
 	if (unlikely(r)) {
 		return r;
 	}
@@ -255,7 +255,7 @@
 		DRM_ERROR("Unknown placement %d\n", old_mem->mem_type);
 		return -EINVAL;
 	}
-	if (!rdev->ring[rdev->copy_ring].ready) {
+	if (!rdev->ring[radeon_copy_ring_index(rdev)].ready) {
 		DRM_ERROR("Trying to move memory with ring turned off.\n");
 		return -EINVAL;
 	}
@@ -266,7 +266,7 @@
 	if (rdev->family >= CHIP_R600) {
 		for (i = 0; i < RADEON_NUM_RINGS; ++i) {
 			/* no need to sync to our own or unused rings */
-			if (i == rdev->copy_ring || !rdev->ring[i].ready)
+			if (i == radeon_copy_ring_index(rdev) || !rdev->ring[i].ready)
 				continue;
 
 			if (!fence->semaphore) {
@@ -283,12 +283,12 @@
 			radeon_semaphore_emit_signal(rdev, i, fence->semaphore);
 			radeon_ring_unlock_commit(rdev, &rdev->ring[i]);
 
-			r = radeon_ring_lock(rdev, &rdev->ring[rdev->copy_ring], 3);
+			r = radeon_ring_lock(rdev, &rdev->ring[radeon_copy_ring_index(rdev)], 3);
 			/* FIXME: handle ring lock error */
 			if (r)
 				continue;
-			radeon_semaphore_emit_wait(rdev, rdev->copy_ring, fence->semaphore);
-			radeon_ring_unlock_commit(rdev, &rdev->ring[rdev->copy_ring]);
+			radeon_semaphore_emit_wait(rdev, radeon_copy_ring_index(rdev), fence->semaphore);
+			radeon_ring_unlock_commit(rdev, &rdev->ring[radeon_copy_ring_index(rdev)]);
 		}
 	}
 
@@ -410,7 +410,8 @@
 		radeon_move_null(bo, new_mem);
 		return 0;
 	}
-	if (!rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready || rdev->asic->copy == NULL) {
+	if (!rdev->ring[radeon_copy_ring_index(rdev)].ready ||
+	    rdev->asic->copy.copy == NULL) {
 		/* use memcpy */
 		goto memcpy;
 	}
diff --git a/drivers/gpu/drm/radeon/reg_srcs/cayman b/drivers/gpu/drm/radeon/reg_srcs/cayman
index 2316977..0f656b1 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/cayman
+++ b/drivers/gpu/drm/radeon/reg_srcs/cayman
@@ -1,5 +1,8 @@
 cayman 0x9400
 0x0000802C GRBM_GFX_INDEX
+0x000084FC CP_STRMOUT_CNTL
+0x000085F0 CP_COHER_CNTL
+0x000085F4 CP_COHER_SIZE
 0x000088B0 VGT_VTX_VECT_EJECT_REG
 0x000088C4 VGT_CACHE_INVALIDATION
 0x000088D4 VGT_GS_VERTEX_REUSE
@@ -77,7 +80,6 @@
 0x0002802C DB_DEPTH_CLEAR
 0x00028030 PA_SC_SCREEN_SCISSOR_TL
 0x00028034 PA_SC_SCREEN_SCISSOR_BR
-0x0002805C DB_DEPTH_SLICE
 0x00028140 SQ_ALU_CONST_BUFFER_SIZE_PS_0
 0x00028144 SQ_ALU_CONST_BUFFER_SIZE_PS_1
 0x00028148 SQ_ALU_CONST_BUFFER_SIZE_PS_2
@@ -206,7 +208,6 @@
 0x00028344 PA_SC_VPORT_ZMAX_14
 0x00028348 PA_SC_VPORT_ZMIN_15
 0x0002834C PA_SC_VPORT_ZMAX_15
-0x00028350 SX_MISC
 0x00028354 SX_SURFACE_SYNC
 0x0002835C SX_SCATTER_EXPORT_SIZE
 0x00028380 SQ_VTX_SEMANTIC_0
@@ -508,10 +509,16 @@
 0x00028AA8 IA_MULTI_VGT_PARAM
 0x00028AB4 VGT_REUSE_OFF
 0x00028AB8 VGT_VTX_CNT_EN
-0x00028ABC DB_HTILE_SURFACE
 0x00028AC0 DB_SRESULTS_COMPARE_STATE0
 0x00028AC4 DB_SRESULTS_COMPARE_STATE1
 0x00028AC8 DB_PRELOAD_CONTROL
+0x00028AD4 VGT_STRMOUT_VTX_STRIDE_0
+0x00028AE4 VGT_STRMOUT_VTX_STRIDE_1
+0x00028AF4 VGT_STRMOUT_VTX_STRIDE_2
+0x00028B04 VGT_STRMOUT_VTX_STRIDE_3
+0x00028B28 VGT_STRMOUT_DRAW_OPAQUE_OFFSET
+0x00028B2C VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE
+0x00028B30 VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE
 0x00028B38 VGT_GS_MAX_VERT_OUT
 0x00028B54 VGT_SHADER_STAGES_EN
 0x00028B58 VGT_LS_HS_CONFIG
@@ -551,6 +558,18 @@
 0x00028C34 PA_SC_AA_SAMPLE_LOCS_PIXEL_X1_Y1_3
 0x00028C38 PA_SC_AA_MASK_X0_Y0_X1_Y0
 0x00028C3C PA_SC_AA_MASK_X0_Y1_X1_Y1
+0x00028C78 CB_COLOR0_DIM
+0x00028CB4 CB_COLOR1_DIM
+0x00028CF0 CB_COLOR2_DIM
+0x00028D2C CB_COLOR3_DIM
+0x00028D68 CB_COLOR4_DIM
+0x00028DA4 CB_COLOR5_DIM
+0x00028DE0 CB_COLOR6_DIM
+0x00028E1C CB_COLOR7_DIM
+0x00028E58 CB_COLOR8_DIM
+0x00028E74 CB_COLOR9_DIM
+0x00028E90 CB_COLOR10_DIM
+0x00028EAC CB_COLOR11_DIM
 0x00028C8C CB_COLOR0_CLEAR_WORD0
 0x00028C90 CB_COLOR0_CLEAR_WORD1
 0x00028C94 CB_COLOR0_CLEAR_WORD2
diff --git a/drivers/gpu/drm/radeon/reg_srcs/evergreen b/drivers/gpu/drm/radeon/reg_srcs/evergreen
index 161737a2..b912a37 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/evergreen
+++ b/drivers/gpu/drm/radeon/reg_srcs/evergreen
@@ -4,6 +4,9 @@
 0x00008044 WAIT_UNTIL_POLL_CNTL
 0x00008048 WAIT_UNTIL_POLL_MASK
 0x0000804c WAIT_UNTIL_POLL_REFDATA
+0x000084FC CP_STRMOUT_CNTL
+0x000085F0 CP_COHER_CNTL
+0x000085F4 CP_COHER_SIZE
 0x000088B0 VGT_VTX_VECT_EJECT_REG
 0x000088C4 VGT_CACHE_INVALIDATION
 0x000088D4 VGT_GS_VERTEX_REUSE
@@ -93,7 +96,6 @@
 0x0002802C DB_DEPTH_CLEAR
 0x00028030 PA_SC_SCREEN_SCISSOR_TL
 0x00028034 PA_SC_SCREEN_SCISSOR_BR
-0x0002805C DB_DEPTH_SLICE
 0x00028140 SQ_ALU_CONST_BUFFER_SIZE_PS_0
 0x00028144 SQ_ALU_CONST_BUFFER_SIZE_PS_1
 0x00028148 SQ_ALU_CONST_BUFFER_SIZE_PS_2
@@ -222,7 +224,6 @@
 0x00028344 PA_SC_VPORT_ZMAX_14
 0x00028348 PA_SC_VPORT_ZMIN_15
 0x0002834C PA_SC_VPORT_ZMAX_15
-0x00028350 SX_MISC
 0x00028354 SX_SURFACE_SYNC
 0x00028380 SQ_VTX_SEMANTIC_0
 0x00028384 SQ_VTX_SEMANTIC_1
@@ -518,10 +519,16 @@
 0x00028AA4 VGT_INSTANCE_STEP_RATE_1
 0x00028AB4 VGT_REUSE_OFF
 0x00028AB8 VGT_VTX_CNT_EN
-0x00028ABC DB_HTILE_SURFACE
 0x00028AC0 DB_SRESULTS_COMPARE_STATE0
 0x00028AC4 DB_SRESULTS_COMPARE_STATE1
 0x00028AC8 DB_PRELOAD_CONTROL
+0x00028AD4 VGT_STRMOUT_VTX_STRIDE_0
+0x00028AE4 VGT_STRMOUT_VTX_STRIDE_1
+0x00028AF4 VGT_STRMOUT_VTX_STRIDE_2
+0x00028B04 VGT_STRMOUT_VTX_STRIDE_3
+0x00028B28 VGT_STRMOUT_DRAW_OPAQUE_OFFSET
+0x00028B2C VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE
+0x00028B30 VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE
 0x00028B38 VGT_GS_MAX_VERT_OUT
 0x00028B54 VGT_SHADER_STAGES_EN
 0x00028B58 VGT_LS_HS_CONFIG
@@ -554,6 +561,18 @@
 0x00028C34 PA_SC_AA_SAMPLE_LOCS_6
 0x00028C38 PA_SC_AA_SAMPLE_LOCS_7
 0x00028C3C PA_SC_AA_MASK
+0x00028C78 CB_COLOR0_DIM
+0x00028CB4 CB_COLOR1_DIM
+0x00028CF0 CB_COLOR2_DIM
+0x00028D2C CB_COLOR3_DIM
+0x00028D68 CB_COLOR4_DIM
+0x00028DA4 CB_COLOR5_DIM
+0x00028DE0 CB_COLOR6_DIM
+0x00028E1C CB_COLOR7_DIM
+0x00028E58 CB_COLOR8_DIM
+0x00028E74 CB_COLOR9_DIM
+0x00028E90 CB_COLOR10_DIM
+0x00028EAC CB_COLOR11_DIM
 0x00028C8C CB_COLOR0_CLEAR_WORD0
 0x00028C90 CB_COLOR0_CLEAR_WORD1
 0x00028C94 CB_COLOR0_CLEAR_WORD2
diff --git a/drivers/gpu/drm/radeon/reg_srcs/r600 b/drivers/gpu/drm/radeon/reg_srcs/r600
index 0380c5c..5e659b0 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/r600
+++ b/drivers/gpu/drm/radeon/reg_srcs/r600
@@ -3,6 +3,9 @@
 0x00028230 R7xx_PA_SC_EDGERULE
 0x000286C8 R7xx_SPI_THREAD_GROUPING
 0x00008D8C R7xx_SQ_DYN_GPR_CNTL_PS_FLUSH_REQ
+0x00008490 CP_STRMOUT_CNTL
+0x000085F0 CP_COHER_CNTL
+0x000085F4 CP_COHER_SIZE
 0x000088C4 VGT_CACHE_INVALIDATION
 0x00028A50 VGT_ENHANCE
 0x000088CC VGT_ES_PER_GS
@@ -38,6 +41,13 @@
 0x00028AB4 VGT_REUSE_OFF
 0x00028AB8 VGT_VTX_CNT_EN
 0x000088B0 VGT_VTX_VECT_EJECT_REG
+0x00028AD4 VGT_STRMOUT_VTX_STRIDE_0
+0x00028AE4 VGT_STRMOUT_VTX_STRIDE_1
+0x00028AF4 VGT_STRMOUT_VTX_STRIDE_2
+0x00028B04 VGT_STRMOUT_VTX_STRIDE_3
+0x00028B28 VGT_STRMOUT_DRAW_OPAQUE_OFFSET
+0x00028B2C VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE
+0x00028B30 VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE
 0x00028810 PA_CL_CLIP_CNTL
 0x00008A14 PA_CL_ENHANCE
 0x00028C14 PA_CL_GB_HORZ_CLIP_ADJ
@@ -428,7 +438,7 @@
 0x00028638 SPI_VS_OUT_ID_9
 0x00028438 SX_ALPHA_REF
 0x00028410 SX_ALPHA_TEST_CONTROL
-0x00028350 SX_MISC
+0x00028354 SX_SURFACE_SYNC
 0x00009014 SX_MEMORY_EXPORT_SIZE
 0x00009604 TC_INVALIDATE
 0x00009400 TD_FILTER4
@@ -703,7 +713,6 @@
 0x0000A710 TD_VS_SAMPLER17_BORDER_RED
 0x00009508 TA_CNTL_AUX
 0x0002802C DB_DEPTH_CLEAR
-0x00028D24 DB_HTILE_SURFACE
 0x00028D34 DB_PREFETCH_LIMIT
 0x00028D30 DB_PRELOAD_CONTROL
 0x00028D0C DB_RENDER_CONTROL
@@ -743,14 +752,6 @@
 0x00028114 CB_COLOR5_MASK
 0x00028118 CB_COLOR6_MASK
 0x0002811C CB_COLOR7_MASK
-0x00028080 CB_COLOR0_VIEW
-0x00028084 CB_COLOR1_VIEW
-0x00028088 CB_COLOR2_VIEW
-0x0002808C CB_COLOR3_VIEW
-0x00028090 CB_COLOR4_VIEW
-0x00028094 CB_COLOR5_VIEW
-0x00028098 CB_COLOR6_VIEW
-0x0002809C CB_COLOR7_VIEW
 0x00028808 CB_COLOR_CONTROL
 0x0002842C CB_FOG_BLUE
 0x00028428 CB_FOG_GREEN
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index 866a05b..4cf381b 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -430,7 +430,7 @@
 	if (r)
 		return r;
 
-	r = r100_ib_test(rdev);
+	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
 	if (r) {
 		dev_err(rdev->dev, "failed testing IB (%d).\n", r);
 		rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 4fc7006..d25cf86 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -46,6 +46,25 @@
 void rs600_gpu_init(struct radeon_device *rdev);
 int rs600_mc_wait_for_idle(struct radeon_device *rdev);
 
+void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc)
+{
+	struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc];
+	int i;
+
+	if (RREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset) & AVIVO_CRTC_EN) {
+		for (i = 0; i < rdev->usec_timeout; i++) {
+			if (!(RREG32(AVIVO_D1CRTC_STATUS + radeon_crtc->crtc_offset) & AVIVO_D1CRTC_V_BLANK))
+				break;
+			udelay(1);
+		}
+		for (i = 0; i < rdev->usec_timeout; i++) {
+			if (RREG32(AVIVO_D1CRTC_STATUS + radeon_crtc->crtc_offset) & AVIVO_D1CRTC_V_BLANK)
+				break;
+			udelay(1);
+		}
+	}
+}
+
 void rs600_pre_page_flip(struct radeon_device *rdev, int crtc)
 {
 	/* enable the pflip int */
@@ -175,7 +194,7 @@
 	/* set pcie lanes */
 	if ((rdev->flags & RADEON_IS_PCIE) &&
 	    !(rdev->flags & RADEON_IS_IGP) &&
-	    rdev->asic->set_pcie_lanes &&
+	    rdev->asic->pm.set_pcie_lanes &&
 	    (ps->pcie_lanes !=
 	     rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) {
 		radeon_set_pcie_lanes(rdev,
@@ -864,7 +883,7 @@
 	if (r)
 		return r;
 
-	r = r100_ib_test(rdev);
+	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
 	if (r) {
 		dev_err(rdev->dev, "failed testing IB (%d).\n", r);
 		rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index f68dff2..f2c3b9d 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -31,7 +31,7 @@
 #include "atom.h"
 #include "rs690d.h"
 
-static int rs690_mc_wait_for_idle(struct radeon_device *rdev)
+int rs690_mc_wait_for_idle(struct radeon_device *rdev)
 {
 	unsigned i;
 	uint32_t tmp;
@@ -647,7 +647,7 @@
 	if (r)
 		return r;
 
-	r = r100_ib_test(rdev);
+	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
 	if (r) {
 		dev_err(rdev->dev, "failed testing IB (%d).\n", r);
 		rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index c520d06..d8d78fe 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -53,9 +53,8 @@
 	}
 }
 
-void rv515_ring_start(struct radeon_device *rdev)
+void rv515_ring_start(struct radeon_device *rdev, struct radeon_ring *ring)
 {
-	struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
 	int r;
 
 	r = radeon_ring_lock(rdev, ring, 64);
@@ -413,7 +412,7 @@
 	if (r)
 		return r;
 
-	r = r100_ib_test(rdev);
+	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
 	if (r) {
 		dev_err(rdev->dev, "failed testing IB (%d).\n", r);
 		rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index c049c0c..c62ae4b 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -1074,7 +1074,7 @@
 	r = r600_blit_init(rdev);
 	if (r) {
 		r600_blit_fini(rdev);
-		rdev->asic->copy = NULL;
+		rdev->asic->copy.copy = NULL;
 		dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
 	}
 
@@ -1114,7 +1114,7 @@
 	if (r)
 		return r;
 
-	r = r600_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX);
+	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
 	if (r) {
 		dev_err(rdev->dev, "IB test failed (%d).\n", r);
 		rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
new file mode 100644
index 0000000..ac7a199
--- /dev/null
+++ b/drivers/gpu/drm/radeon/si.c
@@ -0,0 +1,4128 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include "drmP.h"
+#include "radeon.h"
+#include "radeon_asic.h"
+#include "radeon_drm.h"
+#include "sid.h"
+#include "atom.h"
+#include "si_blit_shaders.h"
+
+#define SI_PFP_UCODE_SIZE 2144
+#define SI_PM4_UCODE_SIZE 2144
+#define SI_CE_UCODE_SIZE 2144
+#define SI_RLC_UCODE_SIZE 2048
+#define SI_MC_UCODE_SIZE 7769
+
+MODULE_FIRMWARE("radeon/TAHITI_pfp.bin");
+MODULE_FIRMWARE("radeon/TAHITI_me.bin");
+MODULE_FIRMWARE("radeon/TAHITI_ce.bin");
+MODULE_FIRMWARE("radeon/TAHITI_mc.bin");
+MODULE_FIRMWARE("radeon/TAHITI_rlc.bin");
+MODULE_FIRMWARE("radeon/PITCAIRN_pfp.bin");
+MODULE_FIRMWARE("radeon/PITCAIRN_me.bin");
+MODULE_FIRMWARE("radeon/PITCAIRN_ce.bin");
+MODULE_FIRMWARE("radeon/PITCAIRN_mc.bin");
+MODULE_FIRMWARE("radeon/PITCAIRN_rlc.bin");
+MODULE_FIRMWARE("radeon/VERDE_pfp.bin");
+MODULE_FIRMWARE("radeon/VERDE_me.bin");
+MODULE_FIRMWARE("radeon/VERDE_ce.bin");
+MODULE_FIRMWARE("radeon/VERDE_mc.bin");
+MODULE_FIRMWARE("radeon/VERDE_rlc.bin");
+
+extern int r600_ih_ring_alloc(struct radeon_device *rdev);
+extern void r600_ih_ring_fini(struct radeon_device *rdev);
+extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev);
+extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
+extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
+extern u32 evergreen_get_number_of_dram_channels(struct radeon_device *rdev);
+
+/* get temperature in millidegrees */
+int si_get_temp(struct radeon_device *rdev)
+{
+	u32 temp;
+	int actual_temp = 0;
+
+	temp = (RREG32(CG_MULT_THERMAL_STATUS) & CTF_TEMP_MASK) >>
+		CTF_TEMP_SHIFT;
+
+	if (temp & 0x200)
+		actual_temp = 255;
+	else
+		actual_temp = temp & 0x1ff;
+
+	actual_temp = (actual_temp * 1000);
+
+	return actual_temp;
+}
+
+#define TAHITI_IO_MC_REGS_SIZE 36
+
+static const u32 tahiti_io_mc_regs[TAHITI_IO_MC_REGS_SIZE][2] = {
+	{0x0000006f, 0x03044000},
+	{0x00000070, 0x0480c018},
+	{0x00000071, 0x00000040},
+	{0x00000072, 0x01000000},
+	{0x00000074, 0x000000ff},
+	{0x00000075, 0x00143400},
+	{0x00000076, 0x08ec0800},
+	{0x00000077, 0x040000cc},
+	{0x00000079, 0x00000000},
+	{0x0000007a, 0x21000409},
+	{0x0000007c, 0x00000000},
+	{0x0000007d, 0xe8000000},
+	{0x0000007e, 0x044408a8},
+	{0x0000007f, 0x00000003},
+	{0x00000080, 0x00000000},
+	{0x00000081, 0x01000000},
+	{0x00000082, 0x02000000},
+	{0x00000083, 0x00000000},
+	{0x00000084, 0xe3f3e4f4},
+	{0x00000085, 0x00052024},
+	{0x00000087, 0x00000000},
+	{0x00000088, 0x66036603},
+	{0x00000089, 0x01000000},
+	{0x0000008b, 0x1c0a0000},
+	{0x0000008c, 0xff010000},
+	{0x0000008e, 0xffffefff},
+	{0x0000008f, 0xfff3efff},
+	{0x00000090, 0xfff3efbf},
+	{0x00000094, 0x00101101},
+	{0x00000095, 0x00000fff},
+	{0x00000096, 0x00116fff},
+	{0x00000097, 0x60010000},
+	{0x00000098, 0x10010000},
+	{0x00000099, 0x00006000},
+	{0x0000009a, 0x00001000},
+	{0x0000009f, 0x00a77400}
+};
+
+static const u32 pitcairn_io_mc_regs[TAHITI_IO_MC_REGS_SIZE][2] = {
+	{0x0000006f, 0x03044000},
+	{0x00000070, 0x0480c018},
+	{0x00000071, 0x00000040},
+	{0x00000072, 0x01000000},
+	{0x00000074, 0x000000ff},
+	{0x00000075, 0x00143400},
+	{0x00000076, 0x08ec0800},
+	{0x00000077, 0x040000cc},
+	{0x00000079, 0x00000000},
+	{0x0000007a, 0x21000409},
+	{0x0000007c, 0x00000000},
+	{0x0000007d, 0xe8000000},
+	{0x0000007e, 0x044408a8},
+	{0x0000007f, 0x00000003},
+	{0x00000080, 0x00000000},
+	{0x00000081, 0x01000000},
+	{0x00000082, 0x02000000},
+	{0x00000083, 0x00000000},
+	{0x00000084, 0xe3f3e4f4},
+	{0x00000085, 0x00052024},
+	{0x00000087, 0x00000000},
+	{0x00000088, 0x66036603},
+	{0x00000089, 0x01000000},
+	{0x0000008b, 0x1c0a0000},
+	{0x0000008c, 0xff010000},
+	{0x0000008e, 0xffffefff},
+	{0x0000008f, 0xfff3efff},
+	{0x00000090, 0xfff3efbf},
+	{0x00000094, 0x00101101},
+	{0x00000095, 0x00000fff},
+	{0x00000096, 0x00116fff},
+	{0x00000097, 0x60010000},
+	{0x00000098, 0x10010000},
+	{0x00000099, 0x00006000},
+	{0x0000009a, 0x00001000},
+	{0x0000009f, 0x00a47400}
+};
+
+static const u32 verde_io_mc_regs[TAHITI_IO_MC_REGS_SIZE][2] = {
+	{0x0000006f, 0x03044000},
+	{0x00000070, 0x0480c018},
+	{0x00000071, 0x00000040},
+	{0x00000072, 0x01000000},
+	{0x00000074, 0x000000ff},
+	{0x00000075, 0x00143400},
+	{0x00000076, 0x08ec0800},
+	{0x00000077, 0x040000cc},
+	{0x00000079, 0x00000000},
+	{0x0000007a, 0x21000409},
+	{0x0000007c, 0x00000000},
+	{0x0000007d, 0xe8000000},
+	{0x0000007e, 0x044408a8},
+	{0x0000007f, 0x00000003},
+	{0x00000080, 0x00000000},
+	{0x00000081, 0x01000000},
+	{0x00000082, 0x02000000},
+	{0x00000083, 0x00000000},
+	{0x00000084, 0xe3f3e4f4},
+	{0x00000085, 0x00052024},
+	{0x00000087, 0x00000000},
+	{0x00000088, 0x66036603},
+	{0x00000089, 0x01000000},
+	{0x0000008b, 0x1c0a0000},
+	{0x0000008c, 0xff010000},
+	{0x0000008e, 0xffffefff},
+	{0x0000008f, 0xfff3efff},
+	{0x00000090, 0xfff3efbf},
+	{0x00000094, 0x00101101},
+	{0x00000095, 0x00000fff},
+	{0x00000096, 0x00116fff},
+	{0x00000097, 0x60010000},
+	{0x00000098, 0x10010000},
+	{0x00000099, 0x00006000},
+	{0x0000009a, 0x00001000},
+	{0x0000009f, 0x00a37400}
+};
+
+/* ucode loading */
+static int si_mc_load_microcode(struct radeon_device *rdev)
+{
+	const __be32 *fw_data;
+	u32 running, blackout = 0;
+	u32 *io_mc_regs;
+	int i, ucode_size, regs_size;
+
+	if (!rdev->mc_fw)
+		return -EINVAL;
+
+	switch (rdev->family) {
+	case CHIP_TAHITI:
+		io_mc_regs = (u32 *)&tahiti_io_mc_regs;
+		ucode_size = SI_MC_UCODE_SIZE;
+		regs_size = TAHITI_IO_MC_REGS_SIZE;
+		break;
+	case CHIP_PITCAIRN:
+		io_mc_regs = (u32 *)&pitcairn_io_mc_regs;
+		ucode_size = SI_MC_UCODE_SIZE;
+		regs_size = TAHITI_IO_MC_REGS_SIZE;
+		break;
+	case CHIP_VERDE:
+	default:
+		io_mc_regs = (u32 *)&verde_io_mc_regs;
+		ucode_size = SI_MC_UCODE_SIZE;
+		regs_size = TAHITI_IO_MC_REGS_SIZE;
+		break;
+	}
+
+	running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK;
+
+	if (running == 0) {
+		if (running) {
+			blackout = RREG32(MC_SHARED_BLACKOUT_CNTL);
+			WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1);
+		}
+
+		/* reset the engine and set to writable */
+		WREG32(MC_SEQ_SUP_CNTL, 0x00000008);
+		WREG32(MC_SEQ_SUP_CNTL, 0x00000010);
+
+		/* load mc io regs */
+		for (i = 0; i < regs_size; i++) {
+			WREG32(MC_SEQ_IO_DEBUG_INDEX, io_mc_regs[(i << 1)]);
+			WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]);
+		}
+		/* load the MC ucode */
+		fw_data = (const __be32 *)rdev->mc_fw->data;
+		for (i = 0; i < ucode_size; i++)
+			WREG32(MC_SEQ_SUP_PGM, be32_to_cpup(fw_data++));
+
+		/* put the engine back into the active state */
+		WREG32(MC_SEQ_SUP_CNTL, 0x00000008);
+		WREG32(MC_SEQ_SUP_CNTL, 0x00000004);
+		WREG32(MC_SEQ_SUP_CNTL, 0x00000001);
+
+		/* wait for training to complete */
+		for (i = 0; i < rdev->usec_timeout; i++) {
+			if (RREG32(MC_SEQ_TRAIN_WAKEUP_CNTL) & TRAIN_DONE_D0)
+				break;
+			udelay(1);
+		}
+		for (i = 0; i < rdev->usec_timeout; i++) {
+			if (RREG32(MC_SEQ_TRAIN_WAKEUP_CNTL) & TRAIN_DONE_D1)
+				break;
+			udelay(1);
+		}
+
+		if (running)
+			WREG32(MC_SHARED_BLACKOUT_CNTL, blackout);
+	}
+
+	return 0;
+}
+
+static int si_init_microcode(struct radeon_device *rdev)
+{
+	struct platform_device *pdev;
+	const char *chip_name;
+	const char *rlc_chip_name;
+	size_t pfp_req_size, me_req_size, ce_req_size, rlc_req_size, mc_req_size;
+	char fw_name[30];
+	int err;
+
+	DRM_DEBUG("\n");
+
+	pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0);
+	err = IS_ERR(pdev);
+	if (err) {
+		printk(KERN_ERR "radeon_cp: Failed to register firmware\n");
+		return -EINVAL;
+	}
+
+	switch (rdev->family) {
+	case CHIP_TAHITI:
+		chip_name = "TAHITI";
+		rlc_chip_name = "TAHITI";
+		pfp_req_size = SI_PFP_UCODE_SIZE * 4;
+		me_req_size = SI_PM4_UCODE_SIZE * 4;
+		ce_req_size = SI_CE_UCODE_SIZE * 4;
+		rlc_req_size = SI_RLC_UCODE_SIZE * 4;
+		mc_req_size = SI_MC_UCODE_SIZE * 4;
+		break;
+	case CHIP_PITCAIRN:
+		chip_name = "PITCAIRN";
+		rlc_chip_name = "PITCAIRN";
+		pfp_req_size = SI_PFP_UCODE_SIZE * 4;
+		me_req_size = SI_PM4_UCODE_SIZE * 4;
+		ce_req_size = SI_CE_UCODE_SIZE * 4;
+		rlc_req_size = SI_RLC_UCODE_SIZE * 4;
+		mc_req_size = SI_MC_UCODE_SIZE * 4;
+		break;
+	case CHIP_VERDE:
+		chip_name = "VERDE";
+		rlc_chip_name = "VERDE";
+		pfp_req_size = SI_PFP_UCODE_SIZE * 4;
+		me_req_size = SI_PM4_UCODE_SIZE * 4;
+		ce_req_size = SI_CE_UCODE_SIZE * 4;
+		rlc_req_size = SI_RLC_UCODE_SIZE * 4;
+		mc_req_size = SI_MC_UCODE_SIZE * 4;
+		break;
+	default: BUG();
+	}
+
+	DRM_INFO("Loading %s Microcode\n", chip_name);
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name);
+	err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->pfp_fw->size != pfp_req_size) {
+		printk(KERN_ERR
+		       "si_cp: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->pfp_fw->size, fw_name);
+		err = -EINVAL;
+		goto out;
+	}
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name);
+	err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->me_fw->size != me_req_size) {
+		printk(KERN_ERR
+		       "si_cp: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->me_fw->size, fw_name);
+		err = -EINVAL;
+	}
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name);
+	err = request_firmware(&rdev->ce_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->ce_fw->size != ce_req_size) {
+		printk(KERN_ERR
+		       "si_cp: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->ce_fw->size, fw_name);
+		err = -EINVAL;
+	}
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name);
+	err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->rlc_fw->size != rlc_req_size) {
+		printk(KERN_ERR
+		       "si_rlc: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->rlc_fw->size, fw_name);
+		err = -EINVAL;
+	}
+
+	snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
+	err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev);
+	if (err)
+		goto out;
+	if (rdev->mc_fw->size != mc_req_size) {
+		printk(KERN_ERR
+		       "si_mc: Bogus length %zu in firmware \"%s\"\n",
+		       rdev->mc_fw->size, fw_name);
+		err = -EINVAL;
+	}
+
+out:
+	platform_device_unregister(pdev);
+
+	if (err) {
+		if (err != -EINVAL)
+			printk(KERN_ERR
+			       "si_cp: Failed to load firmware \"%s\"\n",
+			       fw_name);
+		release_firmware(rdev->pfp_fw);
+		rdev->pfp_fw = NULL;
+		release_firmware(rdev->me_fw);
+		rdev->me_fw = NULL;
+		release_firmware(rdev->ce_fw);
+		rdev->ce_fw = NULL;
+		release_firmware(rdev->rlc_fw);
+		rdev->rlc_fw = NULL;
+		release_firmware(rdev->mc_fw);
+		rdev->mc_fw = NULL;
+	}
+	return err;
+}
+
+/* watermark setup */
+static u32 dce6_line_buffer_adjust(struct radeon_device *rdev,
+				   struct radeon_crtc *radeon_crtc,
+				   struct drm_display_mode *mode,
+				   struct drm_display_mode *other_mode)
+{
+	u32 tmp;
+	/*
+	 * Line Buffer Setup
+	 * There are 3 line buffers, each one shared by 2 display controllers.
+	 * DC_LB_MEMORY_SPLIT controls how that line buffer is shared between
+	 * the display controllers.  The paritioning is done via one of four
+	 * preset allocations specified in bits 21:20:
+	 *  0 - half lb
+	 *  2 - whole lb, other crtc must be disabled
+	 */
+	/* this can get tricky if we have two large displays on a paired group
+	 * of crtcs.  Ideally for multiple large displays we'd assign them to
+	 * non-linked crtcs for maximum line buffer allocation.
+	 */
+	if (radeon_crtc->base.enabled && mode) {
+		if (other_mode)
+			tmp = 0; /* 1/2 */
+		else
+			tmp = 2; /* whole */
+	} else
+		tmp = 0;
+
+	WREG32(DC_LB_MEMORY_SPLIT + radeon_crtc->crtc_offset,
+	       DC_LB_MEMORY_CONFIG(tmp));
+
+	if (radeon_crtc->base.enabled && mode) {
+		switch (tmp) {
+		case 0:
+		default:
+			return 4096 * 2;
+		case 2:
+			return 8192 * 2;
+		}
+	}
+
+	/* controller not enabled, so no lb used */
+	return 0;
+}
+
+static u32 si_get_number_of_dram_channels(struct radeon_device *rdev)
+{
+	u32 tmp = RREG32(MC_SHARED_CHMAP);
+
+	switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+	case 0:
+	default:
+		return 1;
+	case 1:
+		return 2;
+	case 2:
+		return 4;
+	case 3:
+		return 8;
+	case 4:
+		return 3;
+	case 5:
+		return 6;
+	case 6:
+		return 10;
+	case 7:
+		return 12;
+	case 8:
+		return 16;
+	}
+}
+
+struct dce6_wm_params {
+	u32 dram_channels; /* number of dram channels */
+	u32 yclk;          /* bandwidth per dram data pin in kHz */
+	u32 sclk;          /* engine clock in kHz */
+	u32 disp_clk;      /* display clock in kHz */
+	u32 src_width;     /* viewport width */
+	u32 active_time;   /* active display time in ns */
+	u32 blank_time;    /* blank time in ns */
+	bool interlaced;    /* mode is interlaced */
+	fixed20_12 vsc;    /* vertical scale ratio */
+	u32 num_heads;     /* number of active crtcs */
+	u32 bytes_per_pixel; /* bytes per pixel display + overlay */
+	u32 lb_size;       /* line buffer allocated to pipe */
+	u32 vtaps;         /* vertical scaler taps */
+};
+
+static u32 dce6_dram_bandwidth(struct dce6_wm_params *wm)
+{
+	/* Calculate raw DRAM Bandwidth */
+	fixed20_12 dram_efficiency; /* 0.7 */
+	fixed20_12 yclk, dram_channels, bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	yclk.full = dfixed_const(wm->yclk);
+	yclk.full = dfixed_div(yclk, a);
+	dram_channels.full = dfixed_const(wm->dram_channels * 4);
+	a.full = dfixed_const(10);
+	dram_efficiency.full = dfixed_const(7);
+	dram_efficiency.full = dfixed_div(dram_efficiency, a);
+	bandwidth.full = dfixed_mul(dram_channels, yclk);
+	bandwidth.full = dfixed_mul(bandwidth, dram_efficiency);
+
+	return dfixed_trunc(bandwidth);
+}
+
+static u32 dce6_dram_bandwidth_for_display(struct dce6_wm_params *wm)
+{
+	/* Calculate DRAM Bandwidth and the part allocated to display. */
+	fixed20_12 disp_dram_allocation; /* 0.3 to 0.7 */
+	fixed20_12 yclk, dram_channels, bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	yclk.full = dfixed_const(wm->yclk);
+	yclk.full = dfixed_div(yclk, a);
+	dram_channels.full = dfixed_const(wm->dram_channels * 4);
+	a.full = dfixed_const(10);
+	disp_dram_allocation.full = dfixed_const(3); /* XXX worse case value 0.3 */
+	disp_dram_allocation.full = dfixed_div(disp_dram_allocation, a);
+	bandwidth.full = dfixed_mul(dram_channels, yclk);
+	bandwidth.full = dfixed_mul(bandwidth, disp_dram_allocation);
+
+	return dfixed_trunc(bandwidth);
+}
+
+static u32 dce6_data_return_bandwidth(struct dce6_wm_params *wm)
+{
+	/* Calculate the display Data return Bandwidth */
+	fixed20_12 return_efficiency; /* 0.8 */
+	fixed20_12 sclk, bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	sclk.full = dfixed_const(wm->sclk);
+	sclk.full = dfixed_div(sclk, a);
+	a.full = dfixed_const(10);
+	return_efficiency.full = dfixed_const(8);
+	return_efficiency.full = dfixed_div(return_efficiency, a);
+	a.full = dfixed_const(32);
+	bandwidth.full = dfixed_mul(a, sclk);
+	bandwidth.full = dfixed_mul(bandwidth, return_efficiency);
+
+	return dfixed_trunc(bandwidth);
+}
+
+static u32 dce6_get_dmif_bytes_per_request(struct dce6_wm_params *wm)
+{
+	return 32;
+}
+
+static u32 dce6_dmif_request_bandwidth(struct dce6_wm_params *wm)
+{
+	/* Calculate the DMIF Request Bandwidth */
+	fixed20_12 disp_clk_request_efficiency; /* 0.8 */
+	fixed20_12 disp_clk, sclk, bandwidth;
+	fixed20_12 a, b1, b2;
+	u32 min_bandwidth;
+
+	a.full = dfixed_const(1000);
+	disp_clk.full = dfixed_const(wm->disp_clk);
+	disp_clk.full = dfixed_div(disp_clk, a);
+	a.full = dfixed_const(dce6_get_dmif_bytes_per_request(wm) / 2);
+	b1.full = dfixed_mul(a, disp_clk);
+
+	a.full = dfixed_const(1000);
+	sclk.full = dfixed_const(wm->sclk);
+	sclk.full = dfixed_div(sclk, a);
+	a.full = dfixed_const(dce6_get_dmif_bytes_per_request(wm));
+	b2.full = dfixed_mul(a, sclk);
+
+	a.full = dfixed_const(10);
+	disp_clk_request_efficiency.full = dfixed_const(8);
+	disp_clk_request_efficiency.full = dfixed_div(disp_clk_request_efficiency, a);
+
+	min_bandwidth = min(dfixed_trunc(b1), dfixed_trunc(b2));
+
+	a.full = dfixed_const(min_bandwidth);
+	bandwidth.full = dfixed_mul(a, disp_clk_request_efficiency);
+
+	return dfixed_trunc(bandwidth);
+}
+
+static u32 dce6_available_bandwidth(struct dce6_wm_params *wm)
+{
+	/* Calculate the Available bandwidth. Display can use this temporarily but not in average. */
+	u32 dram_bandwidth = dce6_dram_bandwidth(wm);
+	u32 data_return_bandwidth = dce6_data_return_bandwidth(wm);
+	u32 dmif_req_bandwidth = dce6_dmif_request_bandwidth(wm);
+
+	return min(dram_bandwidth, min(data_return_bandwidth, dmif_req_bandwidth));
+}
+
+static u32 dce6_average_bandwidth(struct dce6_wm_params *wm)
+{
+	/* Calculate the display mode Average Bandwidth
+	 * DisplayMode should contain the source and destination dimensions,
+	 * timing, etc.
+	 */
+	fixed20_12 bpp;
+	fixed20_12 line_time;
+	fixed20_12 src_width;
+	fixed20_12 bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	line_time.full = dfixed_const(wm->active_time + wm->blank_time);
+	line_time.full = dfixed_div(line_time, a);
+	bpp.full = dfixed_const(wm->bytes_per_pixel);
+	src_width.full = dfixed_const(wm->src_width);
+	bandwidth.full = dfixed_mul(src_width, bpp);
+	bandwidth.full = dfixed_mul(bandwidth, wm->vsc);
+	bandwidth.full = dfixed_div(bandwidth, line_time);
+
+	return dfixed_trunc(bandwidth);
+}
+
+static u32 dce6_latency_watermark(struct dce6_wm_params *wm)
+{
+	/* First calcualte the latency in ns */
+	u32 mc_latency = 2000; /* 2000 ns. */
+	u32 available_bandwidth = dce6_available_bandwidth(wm);
+	u32 worst_chunk_return_time = (512 * 8 * 1000) / available_bandwidth;
+	u32 cursor_line_pair_return_time = (128 * 4 * 1000) / available_bandwidth;
+	u32 dc_latency = 40000000 / wm->disp_clk; /* dc pipe latency */
+	u32 other_heads_data_return_time = ((wm->num_heads + 1) * worst_chunk_return_time) +
+		(wm->num_heads * cursor_line_pair_return_time);
+	u32 latency = mc_latency + other_heads_data_return_time + dc_latency;
+	u32 max_src_lines_per_dst_line, lb_fill_bw, line_fill_time;
+	u32 tmp, dmif_size = 12288;
+	fixed20_12 a, b, c;
+
+	if (wm->num_heads == 0)
+		return 0;
+
+	a.full = dfixed_const(2);
+	b.full = dfixed_const(1);
+	if ((wm->vsc.full > a.full) ||
+	    ((wm->vsc.full > b.full) && (wm->vtaps >= 3)) ||
+	    (wm->vtaps >= 5) ||
+	    ((wm->vsc.full >= a.full) && wm->interlaced))
+		max_src_lines_per_dst_line = 4;
+	else
+		max_src_lines_per_dst_line = 2;
+
+	a.full = dfixed_const(available_bandwidth);
+	b.full = dfixed_const(wm->num_heads);
+	a.full = dfixed_div(a, b);
+
+	b.full = dfixed_const(mc_latency + 512);
+	c.full = dfixed_const(wm->disp_clk);
+	b.full = dfixed_div(b, c);
+
+	c.full = dfixed_const(dmif_size);
+	b.full = dfixed_div(c, b);
+
+	tmp = min(dfixed_trunc(a), dfixed_trunc(b));
+
+	b.full = dfixed_const(1000);
+	c.full = dfixed_const(wm->disp_clk);
+	b.full = dfixed_div(c, b);
+	c.full = dfixed_const(wm->bytes_per_pixel);
+	b.full = dfixed_mul(b, c);
+
+	lb_fill_bw = min(tmp, dfixed_trunc(b));
+
+	a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
+	b.full = dfixed_const(1000);
+	c.full = dfixed_const(lb_fill_bw);
+	b.full = dfixed_div(c, b);
+	a.full = dfixed_div(a, b);
+	line_fill_time = dfixed_trunc(a);
+
+	if (line_fill_time < wm->active_time)
+		return latency;
+	else
+		return latency + (line_fill_time - wm->active_time);
+
+}
+
+static bool dce6_average_bandwidth_vs_dram_bandwidth_for_display(struct dce6_wm_params *wm)
+{
+	if (dce6_average_bandwidth(wm) <=
+	    (dce6_dram_bandwidth_for_display(wm) / wm->num_heads))
+		return true;
+	else
+		return false;
+};
+
+static bool dce6_average_bandwidth_vs_available_bandwidth(struct dce6_wm_params *wm)
+{
+	if (dce6_average_bandwidth(wm) <=
+	    (dce6_available_bandwidth(wm) / wm->num_heads))
+		return true;
+	else
+		return false;
+};
+
+static bool dce6_check_latency_hiding(struct dce6_wm_params *wm)
+{
+	u32 lb_partitions = wm->lb_size / wm->src_width;
+	u32 line_time = wm->active_time + wm->blank_time;
+	u32 latency_tolerant_lines;
+	u32 latency_hiding;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1);
+	if (wm->vsc.full > a.full)
+		latency_tolerant_lines = 1;
+	else {
+		if (lb_partitions <= (wm->vtaps + 1))
+			latency_tolerant_lines = 1;
+		else
+			latency_tolerant_lines = 2;
+	}
+
+	latency_hiding = (latency_tolerant_lines * line_time + wm->blank_time);
+
+	if (dce6_latency_watermark(wm) <= latency_hiding)
+		return true;
+	else
+		return false;
+}
+
+static void dce6_program_watermarks(struct radeon_device *rdev,
+					 struct radeon_crtc *radeon_crtc,
+					 u32 lb_size, u32 num_heads)
+{
+	struct drm_display_mode *mode = &radeon_crtc->base.mode;
+	struct dce6_wm_params wm;
+	u32 pixel_period;
+	u32 line_time = 0;
+	u32 latency_watermark_a = 0, latency_watermark_b = 0;
+	u32 priority_a_mark = 0, priority_b_mark = 0;
+	u32 priority_a_cnt = PRIORITY_OFF;
+	u32 priority_b_cnt = PRIORITY_OFF;
+	u32 tmp, arb_control3;
+	fixed20_12 a, b, c;
+
+	if (radeon_crtc->base.enabled && num_heads && mode) {
+		pixel_period = 1000000 / (u32)mode->clock;
+		line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
+		priority_a_cnt = 0;
+		priority_b_cnt = 0;
+
+		wm.yclk = rdev->pm.current_mclk * 10;
+		wm.sclk = rdev->pm.current_sclk * 10;
+		wm.disp_clk = mode->clock;
+		wm.src_width = mode->crtc_hdisplay;
+		wm.active_time = mode->crtc_hdisplay * pixel_period;
+		wm.blank_time = line_time - wm.active_time;
+		wm.interlaced = false;
+		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+			wm.interlaced = true;
+		wm.vsc = radeon_crtc->vsc;
+		wm.vtaps = 1;
+		if (radeon_crtc->rmx_type != RMX_OFF)
+			wm.vtaps = 2;
+		wm.bytes_per_pixel = 4; /* XXX: get this from fb config */
+		wm.lb_size = lb_size;
+		if (rdev->family == CHIP_ARUBA)
+			wm.dram_channels = evergreen_get_number_of_dram_channels(rdev);
+		else
+			wm.dram_channels = si_get_number_of_dram_channels(rdev);
+		wm.num_heads = num_heads;
+
+		/* set for high clocks */
+		latency_watermark_a = min(dce6_latency_watermark(&wm), (u32)65535);
+		/* set for low clocks */
+		/* wm.yclk = low clk; wm.sclk = low clk */
+		latency_watermark_b = min(dce6_latency_watermark(&wm), (u32)65535);
+
+		/* possibly force display priority to high */
+		/* should really do this at mode validation time... */
+		if (!dce6_average_bandwidth_vs_dram_bandwidth_for_display(&wm) ||
+		    !dce6_average_bandwidth_vs_available_bandwidth(&wm) ||
+		    !dce6_check_latency_hiding(&wm) ||
+		    (rdev->disp_priority == 2)) {
+			DRM_DEBUG_KMS("force priority to high\n");
+			priority_a_cnt |= PRIORITY_ALWAYS_ON;
+			priority_b_cnt |= PRIORITY_ALWAYS_ON;
+		}
+
+		a.full = dfixed_const(1000);
+		b.full = dfixed_const(mode->clock);
+		b.full = dfixed_div(b, a);
+		c.full = dfixed_const(latency_watermark_a);
+		c.full = dfixed_mul(c, b);
+		c.full = dfixed_mul(c, radeon_crtc->hsc);
+		c.full = dfixed_div(c, a);
+		a.full = dfixed_const(16);
+		c.full = dfixed_div(c, a);
+		priority_a_mark = dfixed_trunc(c);
+		priority_a_cnt |= priority_a_mark & PRIORITY_MARK_MASK;
+
+		a.full = dfixed_const(1000);
+		b.full = dfixed_const(mode->clock);
+		b.full = dfixed_div(b, a);
+		c.full = dfixed_const(latency_watermark_b);
+		c.full = dfixed_mul(c, b);
+		c.full = dfixed_mul(c, radeon_crtc->hsc);
+		c.full = dfixed_div(c, a);
+		a.full = dfixed_const(16);
+		c.full = dfixed_div(c, a);
+		priority_b_mark = dfixed_trunc(c);
+		priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK;
+	}
+
+	/* select wm A */
+	arb_control3 = RREG32(DPG_PIPE_ARBITRATION_CONTROL3 + radeon_crtc->crtc_offset);
+	tmp = arb_control3;
+	tmp &= ~LATENCY_WATERMARK_MASK(3);
+	tmp |= LATENCY_WATERMARK_MASK(1);
+	WREG32(DPG_PIPE_ARBITRATION_CONTROL3 + radeon_crtc->crtc_offset, tmp);
+	WREG32(DPG_PIPE_LATENCY_CONTROL + radeon_crtc->crtc_offset,
+	       (LATENCY_LOW_WATERMARK(latency_watermark_a) |
+		LATENCY_HIGH_WATERMARK(line_time)));
+	/* select wm B */
+	tmp = RREG32(DPG_PIPE_ARBITRATION_CONTROL3 + radeon_crtc->crtc_offset);
+	tmp &= ~LATENCY_WATERMARK_MASK(3);
+	tmp |= LATENCY_WATERMARK_MASK(2);
+	WREG32(DPG_PIPE_ARBITRATION_CONTROL3 + radeon_crtc->crtc_offset, tmp);
+	WREG32(DPG_PIPE_LATENCY_CONTROL + radeon_crtc->crtc_offset,
+	       (LATENCY_LOW_WATERMARK(latency_watermark_b) |
+		LATENCY_HIGH_WATERMARK(line_time)));
+	/* restore original selection */
+	WREG32(DPG_PIPE_ARBITRATION_CONTROL3 + radeon_crtc->crtc_offset, arb_control3);
+
+	/* write the priority marks */
+	WREG32(PRIORITY_A_CNT + radeon_crtc->crtc_offset, priority_a_cnt);
+	WREG32(PRIORITY_B_CNT + radeon_crtc->crtc_offset, priority_b_cnt);
+
+}
+
+void dce6_bandwidth_update(struct radeon_device *rdev)
+{
+	struct drm_display_mode *mode0 = NULL;
+	struct drm_display_mode *mode1 = NULL;
+	u32 num_heads = 0, lb_size;
+	int i;
+
+	radeon_update_display_priority(rdev);
+
+	for (i = 0; i < rdev->num_crtc; i++) {
+		if (rdev->mode_info.crtcs[i]->base.enabled)
+			num_heads++;
+	}
+	for (i = 0; i < rdev->num_crtc; i += 2) {
+		mode0 = &rdev->mode_info.crtcs[i]->base.mode;
+		mode1 = &rdev->mode_info.crtcs[i+1]->base.mode;
+		lb_size = dce6_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i], mode0, mode1);
+		dce6_program_watermarks(rdev, rdev->mode_info.crtcs[i], lb_size, num_heads);
+		lb_size = dce6_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i+1], mode1, mode0);
+		dce6_program_watermarks(rdev, rdev->mode_info.crtcs[i+1], lb_size, num_heads);
+	}
+}
+
+/*
+ * Core functions
+ */
+static u32 si_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
+					   u32 num_tile_pipes,
+					   u32 num_backends_per_asic,
+					   u32 *backend_disable_mask_per_asic,
+					   u32 num_shader_engines)
+{
+	u32 backend_map = 0;
+	u32 enabled_backends_mask = 0;
+	u32 enabled_backends_count = 0;
+	u32 num_backends_per_se;
+	u32 cur_pipe;
+	u32 swizzle_pipe[SI_MAX_PIPES];
+	u32 cur_backend = 0;
+	u32 i;
+	bool force_no_swizzle;
+
+	/* force legal values */
+	if (num_tile_pipes < 1)
+		num_tile_pipes = 1;
+	if (num_tile_pipes > rdev->config.si.max_tile_pipes)
+		num_tile_pipes = rdev->config.si.max_tile_pipes;
+	if (num_shader_engines < 1)
+		num_shader_engines = 1;
+	if (num_shader_engines > rdev->config.si.max_shader_engines)
+		num_shader_engines = rdev->config.si.max_shader_engines;
+	if (num_backends_per_asic < num_shader_engines)
+		num_backends_per_asic = num_shader_engines;
+	if (num_backends_per_asic > (rdev->config.si.max_backends_per_se * num_shader_engines))
+		num_backends_per_asic = rdev->config.si.max_backends_per_se * num_shader_engines;
+
+	/* make sure we have the same number of backends per se */
+	num_backends_per_asic = ALIGN(num_backends_per_asic, num_shader_engines);
+	/* set up the number of backends per se */
+	num_backends_per_se = num_backends_per_asic / num_shader_engines;
+	if (num_backends_per_se > rdev->config.si.max_backends_per_se) {
+		num_backends_per_se = rdev->config.si.max_backends_per_se;
+		num_backends_per_asic = num_backends_per_se * num_shader_engines;
+	}
+
+	/* create enable mask and count for enabled backends */
+	for (i = 0; i < SI_MAX_BACKENDS; ++i) {
+		if (((*backend_disable_mask_per_asic >> i) & 1) == 0) {
+			enabled_backends_mask |= (1 << i);
+			++enabled_backends_count;
+		}
+		if (enabled_backends_count == num_backends_per_asic)
+			break;
+	}
+
+	/* force the backends mask to match the current number of backends */
+	if (enabled_backends_count != num_backends_per_asic) {
+		u32 this_backend_enabled;
+		u32 shader_engine;
+		u32 backend_per_se;
+
+		enabled_backends_mask = 0;
+		enabled_backends_count = 0;
+		*backend_disable_mask_per_asic = SI_MAX_BACKENDS_MASK;
+		for (i = 0; i < SI_MAX_BACKENDS; ++i) {
+			/* calc the current se */
+			shader_engine = i / rdev->config.si.max_backends_per_se;
+			/* calc the backend per se */
+			backend_per_se = i % rdev->config.si.max_backends_per_se;
+			/* default to not enabled */
+			this_backend_enabled = 0;
+			if ((shader_engine < num_shader_engines) &&
+			    (backend_per_se < num_backends_per_se))
+				this_backend_enabled = 1;
+			if (this_backend_enabled) {
+				enabled_backends_mask |= (1 << i);
+				*backend_disable_mask_per_asic &= ~(1 << i);
+				++enabled_backends_count;
+			}
+		}
+	}
+
+
+	memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * SI_MAX_PIPES);
+	switch (rdev->family) {
+	case CHIP_TAHITI:
+	case CHIP_PITCAIRN:
+	case CHIP_VERDE:
+		force_no_swizzle = true;
+		break;
+	default:
+		force_no_swizzle = false;
+		break;
+	}
+	if (force_no_swizzle) {
+		bool last_backend_enabled = false;
+
+		force_no_swizzle = false;
+		for (i = 0; i < SI_MAX_BACKENDS; ++i) {
+			if (((enabled_backends_mask >> i) & 1) == 1) {
+				if (last_backend_enabled)
+					force_no_swizzle = true;
+				last_backend_enabled = true;
+			} else
+				last_backend_enabled = false;
+		}
+	}
+
+	switch (num_tile_pipes) {
+	case 1:
+	case 3:
+	case 5:
+	case 7:
+		DRM_ERROR("odd number of pipes!\n");
+		break;
+	case 2:
+		swizzle_pipe[0] = 0;
+		swizzle_pipe[1] = 1;
+		break;
+	case 4:
+		if (force_no_swizzle) {
+			swizzle_pipe[0] = 0;
+			swizzle_pipe[1] = 1;
+			swizzle_pipe[2] = 2;
+			swizzle_pipe[3] = 3;
+		} else {
+			swizzle_pipe[0] = 0;
+			swizzle_pipe[1] = 2;
+			swizzle_pipe[2] = 1;
+			swizzle_pipe[3] = 3;
+		}
+		break;
+	case 6:
+		if (force_no_swizzle) {
+			swizzle_pipe[0] = 0;
+			swizzle_pipe[1] = 1;
+			swizzle_pipe[2] = 2;
+			swizzle_pipe[3] = 3;
+			swizzle_pipe[4] = 4;
+			swizzle_pipe[5] = 5;
+		} else {
+			swizzle_pipe[0] = 0;
+			swizzle_pipe[1] = 2;
+			swizzle_pipe[2] = 4;
+			swizzle_pipe[3] = 1;
+			swizzle_pipe[4] = 3;
+			swizzle_pipe[5] = 5;
+		}
+		break;
+	case 8:
+		if (force_no_swizzle) {
+			swizzle_pipe[0] = 0;
+			swizzle_pipe[1] = 1;
+			swizzle_pipe[2] = 2;
+			swizzle_pipe[3] = 3;
+			swizzle_pipe[4] = 4;
+			swizzle_pipe[5] = 5;
+			swizzle_pipe[6] = 6;
+			swizzle_pipe[7] = 7;
+		} else {
+			swizzle_pipe[0] = 0;
+			swizzle_pipe[1] = 2;
+			swizzle_pipe[2] = 4;
+			swizzle_pipe[3] = 6;
+			swizzle_pipe[4] = 1;
+			swizzle_pipe[5] = 3;
+			swizzle_pipe[6] = 5;
+			swizzle_pipe[7] = 7;
+		}
+		break;
+	}
+
+	for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) {
+		while (((1 << cur_backend) & enabled_backends_mask) == 0)
+			cur_backend = (cur_backend + 1) % SI_MAX_BACKENDS;
+
+		backend_map |= (((cur_backend & 0xf) << (swizzle_pipe[cur_pipe] * 4)));
+
+		cur_backend = (cur_backend + 1) % SI_MAX_BACKENDS;
+	}
+
+	return backend_map;
+}
+
+static u32 si_get_disable_mask_per_asic(struct radeon_device *rdev,
+					u32 disable_mask_per_se,
+					u32 max_disable_mask_per_se,
+					u32 num_shader_engines)
+{
+	u32 disable_field_width_per_se = r600_count_pipe_bits(disable_mask_per_se);
+	u32 disable_mask_per_asic = disable_mask_per_se & max_disable_mask_per_se;
+
+	if (num_shader_engines == 1)
+		return disable_mask_per_asic;
+	else if (num_shader_engines == 2)
+		return disable_mask_per_asic | (disable_mask_per_asic << disable_field_width_per_se);
+	else
+		return 0xffffffff;
+}
+
+static void si_tiling_mode_table_init(struct radeon_device *rdev)
+{
+	const u32 num_tile_mode_states = 32;
+	u32 reg_offset, gb_tile_moden, split_equal_to_row_size;
+
+	switch (rdev->config.si.mem_row_size_in_kb) {
+	case 1:
+		split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_1KB;
+		break;
+	case 2:
+	default:
+		split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_2KB;
+		break;
+	case 4:
+		split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_4KB;
+		break;
+	}
+
+	if ((rdev->family == CHIP_TAHITI) ||
+	    (rdev->family == CHIP_PITCAIRN)) {
+		for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
+			switch (reg_offset) {
+			case 0:  /* non-AA compressed depth or any compressed stencil */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 1:  /* 2xAA/4xAA compressed depth only */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 2:  /* 8xAA compressed depth only */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 3:  /* 2xAA/4xAA compressed depth with stencil (for depth buffer) */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 4:  /* Maps w/ a dimension less than the 2D macro-tile dimensions (for mipmapped depth textures) */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 5:  /* Uncompressed 16bpp depth - and stencil buffer allocated with it */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(split_equal_to_row_size) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 6:  /* Uncompressed 32bpp depth - and stencil buffer allocated with it */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(split_equal_to_row_size) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+				break;
+			case 7:  /* Uncompressed 8bpp stencil without depth (drivers typically do not use) */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(split_equal_to_row_size) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 8:  /* 1D and 1D Array Surfaces */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+						 MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 9:  /* Displayable maps. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 10:  /* Display 8bpp. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 11:  /* Display 16bpp. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 12:  /* Display 32bpp. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+				break;
+			case 13:  /* Thin. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 14:  /* Thin 8 bpp. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+				break;
+			case 15:  /* Thin 16 bpp. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+				break;
+			case 16:  /* Thin 32 bpp. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+				break;
+			case 17:  /* Thin 64 bpp. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(split_equal_to_row_size) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+				break;
+			case 21:  /* 8 bpp PRT. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 22:  /* 16 bpp PRT */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+				break;
+			case 23:  /* 32 bpp PRT */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 24:  /* 64 bpp PRT */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 25:  /* 128 bpp PRT */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) |
+						 NUM_BANKS(ADDR_SURF_8_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+				break;
+			default:
+				gb_tile_moden = 0;
+				break;
+			}
+			WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+		}
+	} else if (rdev->family == CHIP_VERDE) {
+		for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
+			switch (reg_offset) {
+			case 0:  /* non-AA compressed depth or any compressed stencil */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+				break;
+			case 1:  /* 2xAA/4xAA compressed depth only */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+				break;
+			case 2:  /* 8xAA compressed depth only */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+				break;
+			case 3:  /* 2xAA/4xAA compressed depth with stencil (for depth buffer) */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+				break;
+			case 4:  /* Maps w/ a dimension less than the 2D macro-tile dimensions (for mipmapped depth textures) */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 5:  /* Uncompressed 16bpp depth - and stencil buffer allocated with it */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(split_equal_to_row_size) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 6:  /* Uncompressed 32bpp depth - and stencil buffer allocated with it */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(split_equal_to_row_size) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 7:  /* Uncompressed 8bpp stencil without depth (drivers typically do not use) */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(split_equal_to_row_size) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+				break;
+			case 8:  /* 1D and 1D Array Surfaces */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+						 MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 9:  /* Displayable maps. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 10:  /* Display 8bpp. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+				break;
+			case 11:  /* Display 16bpp. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 12:  /* Display 32bpp. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 13:  /* Thin. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 14:  /* Thin 8 bpp. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 15:  /* Thin 16 bpp. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 16:  /* Thin 32 bpp. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 17:  /* Thin 64 bpp. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+						 TILE_SPLIT(split_equal_to_row_size) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 21:  /* 8 bpp PRT. */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 22:  /* 16 bpp PRT */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4));
+				break;
+			case 23:  /* 32 bpp PRT */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 24:  /* 64 bpp PRT */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+						 NUM_BANKS(ADDR_SURF_16_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2));
+				break;
+			case 25:  /* 128 bpp PRT */
+				gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+						 MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) |
+						 PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+						 TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) |
+						 NUM_BANKS(ADDR_SURF_8_BANK) |
+						 BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+						 BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+						 MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1));
+				break;
+			default:
+				gb_tile_moden = 0;
+				break;
+			}
+			WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+		}
+	} else
+		DRM_ERROR("unknown asic: 0x%x\n", rdev->family);
+}
+
+static void si_gpu_init(struct radeon_device *rdev)
+{
+	u32 cc_rb_backend_disable = 0;
+	u32 cc_gc_shader_array_config;
+	u32 gb_addr_config = 0;
+	u32 mc_shared_chmap, mc_arb_ramcfg;
+	u32 gb_backend_map;
+	u32 cgts_tcc_disable;
+	u32 sx_debug_1;
+	u32 gc_user_shader_array_config;
+	u32 gc_user_rb_backend_disable;
+	u32 cgts_user_tcc_disable;
+	u32 hdp_host_path_cntl;
+	u32 tmp;
+	int i, j;
+
+	switch (rdev->family) {
+	case CHIP_TAHITI:
+		rdev->config.si.max_shader_engines = 2;
+		rdev->config.si.max_pipes_per_simd = 4;
+		rdev->config.si.max_tile_pipes = 12;
+		rdev->config.si.max_simds_per_se = 8;
+		rdev->config.si.max_backends_per_se = 4;
+		rdev->config.si.max_texture_channel_caches = 12;
+		rdev->config.si.max_gprs = 256;
+		rdev->config.si.max_gs_threads = 32;
+		rdev->config.si.max_hw_contexts = 8;
+
+		rdev->config.si.sc_prim_fifo_size_frontend = 0x20;
+		rdev->config.si.sc_prim_fifo_size_backend = 0x100;
+		rdev->config.si.sc_hiz_tile_fifo_size = 0x30;
+		rdev->config.si.sc_earlyz_tile_fifo_size = 0x130;
+		break;
+	case CHIP_PITCAIRN:
+		rdev->config.si.max_shader_engines = 2;
+		rdev->config.si.max_pipes_per_simd = 4;
+		rdev->config.si.max_tile_pipes = 8;
+		rdev->config.si.max_simds_per_se = 5;
+		rdev->config.si.max_backends_per_se = 4;
+		rdev->config.si.max_texture_channel_caches = 8;
+		rdev->config.si.max_gprs = 256;
+		rdev->config.si.max_gs_threads = 32;
+		rdev->config.si.max_hw_contexts = 8;
+
+		rdev->config.si.sc_prim_fifo_size_frontend = 0x20;
+		rdev->config.si.sc_prim_fifo_size_backend = 0x100;
+		rdev->config.si.sc_hiz_tile_fifo_size = 0x30;
+		rdev->config.si.sc_earlyz_tile_fifo_size = 0x130;
+		break;
+	case CHIP_VERDE:
+	default:
+		rdev->config.si.max_shader_engines = 1;
+		rdev->config.si.max_pipes_per_simd = 4;
+		rdev->config.si.max_tile_pipes = 4;
+		rdev->config.si.max_simds_per_se = 2;
+		rdev->config.si.max_backends_per_se = 4;
+		rdev->config.si.max_texture_channel_caches = 4;
+		rdev->config.si.max_gprs = 256;
+		rdev->config.si.max_gs_threads = 32;
+		rdev->config.si.max_hw_contexts = 8;
+
+		rdev->config.si.sc_prim_fifo_size_frontend = 0x20;
+		rdev->config.si.sc_prim_fifo_size_backend = 0x40;
+		rdev->config.si.sc_hiz_tile_fifo_size = 0x30;
+		rdev->config.si.sc_earlyz_tile_fifo_size = 0x130;
+		break;
+	}
+
+	/* Initialize HDP */
+	for (i = 0, j = 0; i < 32; i++, j += 0x18) {
+		WREG32((0x2c14 + j), 0x00000000);
+		WREG32((0x2c18 + j), 0x00000000);
+		WREG32((0x2c1c + j), 0x00000000);
+		WREG32((0x2c20 + j), 0x00000000);
+		WREG32((0x2c24 + j), 0x00000000);
+	}
+
+	WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+
+	evergreen_fix_pci_max_read_req_size(rdev);
+
+	WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN);
+
+	mc_shared_chmap = RREG32(MC_SHARED_CHMAP);
+	mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG);
+
+	cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE);
+	cc_gc_shader_array_config = RREG32(CC_GC_SHADER_ARRAY_CONFIG);
+	cgts_tcc_disable = 0xffff0000;
+	for (i = 0; i < rdev->config.si.max_texture_channel_caches; i++)
+		cgts_tcc_disable &= ~(1 << (16 + i));
+	gc_user_rb_backend_disable = RREG32(GC_USER_RB_BACKEND_DISABLE);
+	gc_user_shader_array_config = RREG32(GC_USER_SHADER_ARRAY_CONFIG);
+	cgts_user_tcc_disable = RREG32(CGTS_USER_TCC_DISABLE);
+
+	rdev->config.si.num_shader_engines = rdev->config.si.max_shader_engines;
+	rdev->config.si.num_tile_pipes = rdev->config.si.max_tile_pipes;
+	tmp = ((~gc_user_rb_backend_disable) & BACKEND_DISABLE_MASK) >> BACKEND_DISABLE_SHIFT;
+	rdev->config.si.num_backends_per_se = r600_count_pipe_bits(tmp);
+	tmp = (gc_user_rb_backend_disable & BACKEND_DISABLE_MASK) >> BACKEND_DISABLE_SHIFT;
+	rdev->config.si.backend_disable_mask_per_asic =
+		si_get_disable_mask_per_asic(rdev, tmp, SI_MAX_BACKENDS_PER_SE_MASK,
+					     rdev->config.si.num_shader_engines);
+	rdev->config.si.backend_map =
+		si_get_tile_pipe_to_backend_map(rdev, rdev->config.si.num_tile_pipes,
+						rdev->config.si.num_backends_per_se *
+						rdev->config.si.num_shader_engines,
+						&rdev->config.si.backend_disable_mask_per_asic,
+						rdev->config.si.num_shader_engines);
+	tmp = ((~cgts_user_tcc_disable) & TCC_DISABLE_MASK) >> TCC_DISABLE_SHIFT;
+	rdev->config.si.num_texture_channel_caches = r600_count_pipe_bits(tmp);
+	rdev->config.si.mem_max_burst_length_bytes = 256;
+	tmp = (mc_arb_ramcfg & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT;
+	rdev->config.si.mem_row_size_in_kb = (4 * (1 << (8 + tmp))) / 1024;
+	if (rdev->config.si.mem_row_size_in_kb > 4)
+		rdev->config.si.mem_row_size_in_kb = 4;
+	/* XXX use MC settings? */
+	rdev->config.si.shader_engine_tile_size = 32;
+	rdev->config.si.num_gpus = 1;
+	rdev->config.si.multi_gpu_tile_size = 64;
+
+	gb_addr_config = 0;
+	switch (rdev->config.si.num_tile_pipes) {
+	case 1:
+		gb_addr_config |= NUM_PIPES(0);
+		break;
+	case 2:
+		gb_addr_config |= NUM_PIPES(1);
+		break;
+	case 4:
+		gb_addr_config |= NUM_PIPES(2);
+		break;
+	case 8:
+	default:
+		gb_addr_config |= NUM_PIPES(3);
+		break;
+	}
+
+	tmp = (rdev->config.si.mem_max_burst_length_bytes / 256) - 1;
+	gb_addr_config |= PIPE_INTERLEAVE_SIZE(tmp);
+	gb_addr_config |= NUM_SHADER_ENGINES(rdev->config.si.num_shader_engines - 1);
+	tmp = (rdev->config.si.shader_engine_tile_size / 16) - 1;
+	gb_addr_config |= SHADER_ENGINE_TILE_SIZE(tmp);
+	switch (rdev->config.si.num_gpus) {
+	case 1:
+	default:
+		gb_addr_config |= NUM_GPUS(0);
+		break;
+	case 2:
+		gb_addr_config |= NUM_GPUS(1);
+		break;
+	case 4:
+		gb_addr_config |= NUM_GPUS(2);
+		break;
+	}
+	switch (rdev->config.si.multi_gpu_tile_size) {
+	case 16:
+		gb_addr_config |= MULTI_GPU_TILE_SIZE(0);
+		break;
+	case 32:
+	default:
+		gb_addr_config |= MULTI_GPU_TILE_SIZE(1);
+		break;
+	case 64:
+		gb_addr_config |= MULTI_GPU_TILE_SIZE(2);
+		break;
+	case 128:
+		gb_addr_config |= MULTI_GPU_TILE_SIZE(3);
+		break;
+	}
+	switch (rdev->config.si.mem_row_size_in_kb) {
+	case 1:
+	default:
+		gb_addr_config |= ROW_SIZE(0);
+		break;
+	case 2:
+		gb_addr_config |= ROW_SIZE(1);
+		break;
+	case 4:
+		gb_addr_config |= ROW_SIZE(2);
+		break;
+	}
+
+	tmp = (gb_addr_config & NUM_PIPES_MASK) >> NUM_PIPES_SHIFT;
+	rdev->config.si.num_tile_pipes = (1 << tmp);
+	tmp = (gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT;
+	rdev->config.si.mem_max_burst_length_bytes = (tmp + 1) * 256;
+	tmp = (gb_addr_config & NUM_SHADER_ENGINES_MASK) >> NUM_SHADER_ENGINES_SHIFT;
+	rdev->config.si.num_shader_engines = tmp + 1;
+	tmp = (gb_addr_config & NUM_GPUS_MASK) >> NUM_GPUS_SHIFT;
+	rdev->config.si.num_gpus = tmp + 1;
+	tmp = (gb_addr_config & MULTI_GPU_TILE_SIZE_MASK) >> MULTI_GPU_TILE_SIZE_SHIFT;
+	rdev->config.si.multi_gpu_tile_size = 1 << tmp;
+	tmp = (gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT;
+	rdev->config.si.mem_row_size_in_kb = 1 << tmp;
+
+	gb_backend_map =
+		si_get_tile_pipe_to_backend_map(rdev, rdev->config.si.num_tile_pipes,
+						rdev->config.si.num_backends_per_se *
+						rdev->config.si.num_shader_engines,
+						&rdev->config.si.backend_disable_mask_per_asic,
+						rdev->config.si.num_shader_engines);
+
+	/* setup tiling info dword.  gb_addr_config is not adequate since it does
+	 * not have bank info, so create a custom tiling dword.
+	 * bits 3:0   num_pipes
+	 * bits 7:4   num_banks
+	 * bits 11:8  group_size
+	 * bits 15:12 row_size
+	 */
+	rdev->config.si.tile_config = 0;
+	switch (rdev->config.si.num_tile_pipes) {
+	case 1:
+		rdev->config.si.tile_config |= (0 << 0);
+		break;
+	case 2:
+		rdev->config.si.tile_config |= (1 << 0);
+		break;
+	case 4:
+		rdev->config.si.tile_config |= (2 << 0);
+		break;
+	case 8:
+	default:
+		/* XXX what about 12? */
+		rdev->config.si.tile_config |= (3 << 0);
+		break;
+	}
+	rdev->config.si.tile_config |=
+		((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
+	rdev->config.si.tile_config |=
+		((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8;
+	rdev->config.si.tile_config |=
+		((gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT) << 12;
+
+	rdev->config.si.backend_map = gb_backend_map;
+	WREG32(GB_ADDR_CONFIG, gb_addr_config);
+	WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
+	WREG32(HDP_ADDR_CONFIG, gb_addr_config);
+
+	/* primary versions */
+	WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
+	WREG32(CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable);
+	WREG32(CC_GC_SHADER_ARRAY_CONFIG, cc_gc_shader_array_config);
+
+	WREG32(CGTS_TCC_DISABLE, cgts_tcc_disable);
+
+	/* user versions */
+	WREG32(GC_USER_RB_BACKEND_DISABLE, cc_rb_backend_disable);
+	WREG32(GC_USER_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable);
+	WREG32(GC_USER_SHADER_ARRAY_CONFIG, cc_gc_shader_array_config);
+
+	WREG32(CGTS_USER_TCC_DISABLE, cgts_tcc_disable);
+
+	si_tiling_mode_table_init(rdev);
+
+	/* set HW defaults for 3D engine */
+	WREG32(CP_QUEUE_THRESHOLDS, (ROQ_IB1_START(0x16) |
+				     ROQ_IB2_START(0x2b)));
+	WREG32(CP_MEQ_THRESHOLDS, MEQ1_START(0x30) | MEQ2_START(0x60));
+
+	sx_debug_1 = RREG32(SX_DEBUG_1);
+	WREG32(SX_DEBUG_1, sx_debug_1);
+
+	WREG32(SPI_CONFIG_CNTL_1, VTX_DONE_DELAY(4));
+
+	WREG32(PA_SC_FIFO_SIZE, (SC_FRONTEND_PRIM_FIFO_SIZE(rdev->config.si.sc_prim_fifo_size_frontend) |
+				 SC_BACKEND_PRIM_FIFO_SIZE(rdev->config.si.sc_prim_fifo_size_backend) |
+				 SC_HIZ_TILE_FIFO_SIZE(rdev->config.si.sc_hiz_tile_fifo_size) |
+				 SC_EARLYZ_TILE_FIFO_SIZE(rdev->config.si.sc_earlyz_tile_fifo_size)));
+
+	WREG32(VGT_NUM_INSTANCES, 1);
+
+	WREG32(CP_PERFMON_CNTL, 0);
+
+	WREG32(SQ_CONFIG, 0);
+
+	WREG32(PA_SC_FORCE_EOV_MAX_CNTS, (FORCE_EOV_MAX_CLK_CNT(4095) |
+					  FORCE_EOV_MAX_REZ_CNT(255)));
+
+	WREG32(VGT_CACHE_INVALIDATION, CACHE_INVALIDATION(VC_AND_TC) |
+	       AUTO_INVLD_EN(ES_AND_GS_AUTO));
+
+	WREG32(VGT_GS_VERTEX_REUSE, 16);
+	WREG32(PA_SC_LINE_STIPPLE_STATE, 0);
+
+	WREG32(CB_PERFCOUNTER0_SELECT0, 0);
+	WREG32(CB_PERFCOUNTER0_SELECT1, 0);
+	WREG32(CB_PERFCOUNTER1_SELECT0, 0);
+	WREG32(CB_PERFCOUNTER1_SELECT1, 0);
+	WREG32(CB_PERFCOUNTER2_SELECT0, 0);
+	WREG32(CB_PERFCOUNTER2_SELECT1, 0);
+	WREG32(CB_PERFCOUNTER3_SELECT0, 0);
+	WREG32(CB_PERFCOUNTER3_SELECT1, 0);
+
+	tmp = RREG32(HDP_MISC_CNTL);
+	tmp |= HDP_FLUSH_INVALIDATE_CACHE;
+	WREG32(HDP_MISC_CNTL, tmp);
+
+	hdp_host_path_cntl = RREG32(HDP_HOST_PATH_CNTL);
+	WREG32(HDP_HOST_PATH_CNTL, hdp_host_path_cntl);
+
+	WREG32(PA_CL_ENHANCE, CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3));
+
+	udelay(50);
+}
+
+/*
+ * GPU scratch registers helpers function.
+ */
+static void si_scratch_init(struct radeon_device *rdev)
+{
+	int i;
+
+	rdev->scratch.num_reg = 7;
+	rdev->scratch.reg_base = SCRATCH_REG0;
+	for (i = 0; i < rdev->scratch.num_reg; i++) {
+		rdev->scratch.free[i] = true;
+		rdev->scratch.reg[i] = rdev->scratch.reg_base + (i * 4);
+	}
+}
+
+void si_fence_ring_emit(struct radeon_device *rdev,
+			struct radeon_fence *fence)
+{
+	struct radeon_ring *ring = &rdev->ring[fence->ring];
+	u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
+
+	/* flush read cache over gart */
+	radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+	radeon_ring_write(ring, (CP_COHER_CNTL2 - PACKET3_SET_CONFIG_REG_START) >> 2);
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3));
+	radeon_ring_write(ring, PACKET3_TCL1_ACTION_ENA |
+			  PACKET3_TC_ACTION_ENA |
+			  PACKET3_SH_KCACHE_ACTION_ENA |
+			  PACKET3_SH_ICACHE_ACTION_ENA);
+	radeon_ring_write(ring, 0xFFFFFFFF);
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, 10); /* poll interval */
+	/* EVENT_WRITE_EOP - flush caches, send int */
+	radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
+	radeon_ring_write(ring, EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) | EVENT_INDEX(5));
+	radeon_ring_write(ring, addr & 0xffffffff);
+	radeon_ring_write(ring, (upper_32_bits(addr) & 0xff) | DATA_SEL(1) | INT_SEL(2));
+	radeon_ring_write(ring, fence->seq);
+	radeon_ring_write(ring, 0);
+}
+
+/*
+ * IB stuff
+ */
+void si_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
+{
+	struct radeon_ring *ring = &rdev->ring[ib->fence->ring];
+	u32 header;
+
+	if (ib->is_const_ib)
+		header = PACKET3(PACKET3_INDIRECT_BUFFER_CONST, 2);
+	else
+		header = PACKET3(PACKET3_INDIRECT_BUFFER, 2);
+
+	radeon_ring_write(ring, header);
+	radeon_ring_write(ring,
+#ifdef __BIG_ENDIAN
+			  (2 << 0) |
+#endif
+			  (ib->gpu_addr & 0xFFFFFFFC));
+	radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF);
+	radeon_ring_write(ring, ib->length_dw | (ib->vm_id << 24));
+
+	/* flush read cache over gart for this vmid */
+	radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+	radeon_ring_write(ring, (CP_COHER_CNTL2 - PACKET3_SET_CONFIG_REG_START) >> 2);
+	radeon_ring_write(ring, ib->vm_id);
+	radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3));
+	radeon_ring_write(ring, PACKET3_TCL1_ACTION_ENA |
+			  PACKET3_TC_ACTION_ENA |
+			  PACKET3_SH_KCACHE_ACTION_ENA |
+			  PACKET3_SH_ICACHE_ACTION_ENA);
+	radeon_ring_write(ring, 0xFFFFFFFF);
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, 10); /* poll interval */
+}
+
+/*
+ * CP.
+ */
+static void si_cp_enable(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32(CP_ME_CNTL, 0);
+	else {
+		radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+		WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT));
+		WREG32(SCRATCH_UMSK, 0);
+	}
+	udelay(50);
+}
+
+static int si_cp_load_microcode(struct radeon_device *rdev)
+{
+	const __be32 *fw_data;
+	int i;
+
+	if (!rdev->me_fw || !rdev->pfp_fw)
+		return -EINVAL;
+
+	si_cp_enable(rdev, false);
+
+	/* PFP */
+	fw_data = (const __be32 *)rdev->pfp_fw->data;
+	WREG32(CP_PFP_UCODE_ADDR, 0);
+	for (i = 0; i < SI_PFP_UCODE_SIZE; i++)
+		WREG32(CP_PFP_UCODE_DATA, be32_to_cpup(fw_data++));
+	WREG32(CP_PFP_UCODE_ADDR, 0);
+
+	/* CE */
+	fw_data = (const __be32 *)rdev->ce_fw->data;
+	WREG32(CP_CE_UCODE_ADDR, 0);
+	for (i = 0; i < SI_CE_UCODE_SIZE; i++)
+		WREG32(CP_CE_UCODE_DATA, be32_to_cpup(fw_data++));
+	WREG32(CP_CE_UCODE_ADDR, 0);
+
+	/* ME */
+	fw_data = (const __be32 *)rdev->me_fw->data;
+	WREG32(CP_ME_RAM_WADDR, 0);
+	for (i = 0; i < SI_PM4_UCODE_SIZE; i++)
+		WREG32(CP_ME_RAM_DATA, be32_to_cpup(fw_data++));
+	WREG32(CP_ME_RAM_WADDR, 0);
+
+	WREG32(CP_PFP_UCODE_ADDR, 0);
+	WREG32(CP_CE_UCODE_ADDR, 0);
+	WREG32(CP_ME_RAM_WADDR, 0);
+	WREG32(CP_ME_RAM_RADDR, 0);
+	return 0;
+}
+
+static int si_cp_start(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+	int r, i;
+
+	r = radeon_ring_lock(rdev, ring, 7 + 4);
+	if (r) {
+		DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r);
+		return r;
+	}
+	/* init the CP */
+	radeon_ring_write(ring, PACKET3(PACKET3_ME_INITIALIZE, 5));
+	radeon_ring_write(ring, 0x1);
+	radeon_ring_write(ring, 0x0);
+	radeon_ring_write(ring, rdev->config.si.max_hw_contexts - 1);
+	radeon_ring_write(ring, PACKET3_ME_INITIALIZE_DEVICE_ID(1));
+	radeon_ring_write(ring, 0);
+	radeon_ring_write(ring, 0);
+
+	/* init the CE partitions */
+	radeon_ring_write(ring, PACKET3(PACKET3_SET_BASE, 2));
+	radeon_ring_write(ring, PACKET3_BASE_INDEX(CE_PARTITION_BASE));
+	radeon_ring_write(ring, 0xc000);
+	radeon_ring_write(ring, 0xe000);
+	radeon_ring_unlock_commit(rdev, ring);
+
+	si_cp_enable(rdev, true);
+
+	r = radeon_ring_lock(rdev, ring, si_default_size + 10);
+	if (r) {
+		DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r);
+		return r;
+	}
+
+	/* setup clear context state */
+	radeon_ring_write(ring, PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+	radeon_ring_write(ring, PACKET3_PREAMBLE_BEGIN_CLEAR_STATE);
+
+	for (i = 0; i < si_default_size; i++)
+		radeon_ring_write(ring, si_default_state[i]);
+
+	radeon_ring_write(ring, PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+	radeon_ring_write(ring, PACKET3_PREAMBLE_END_CLEAR_STATE);
+
+	/* set clear context state */
+	radeon_ring_write(ring, PACKET3(PACKET3_CLEAR_STATE, 0));
+	radeon_ring_write(ring, 0);
+
+	radeon_ring_write(ring, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
+	radeon_ring_write(ring, 0x00000316);
+	radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */
+	radeon_ring_write(ring, 0x00000010); /* VGT_OUT_DEALLOC_CNTL */
+
+	radeon_ring_unlock_commit(rdev, ring);
+
+	for (i = RADEON_RING_TYPE_GFX_INDEX; i <= CAYMAN_RING_TYPE_CP2_INDEX; ++i) {
+		ring = &rdev->ring[i];
+		r = radeon_ring_lock(rdev, ring, 2);
+
+		/* clear the compute context state */
+		radeon_ring_write(ring, PACKET3_COMPUTE(PACKET3_CLEAR_STATE, 0));
+		radeon_ring_write(ring, 0);
+
+		radeon_ring_unlock_commit(rdev, ring);
+	}
+
+	return 0;
+}
+
+static void si_cp_fini(struct radeon_device *rdev)
+{
+	si_cp_enable(rdev, false);
+	radeon_ring_fini(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
+	radeon_ring_fini(rdev, &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX]);
+	radeon_ring_fini(rdev, &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX]);
+}
+
+static int si_cp_resume(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring;
+	u32 tmp;
+	u32 rb_bufsz;
+	int r;
+
+	/* Reset cp; if cp is reset, then PA, SH, VGT also need to be reset */
+	WREG32(GRBM_SOFT_RESET, (SOFT_RESET_CP |
+				 SOFT_RESET_PA |
+				 SOFT_RESET_VGT |
+				 SOFT_RESET_SPI |
+				 SOFT_RESET_SX));
+	RREG32(GRBM_SOFT_RESET);
+	mdelay(15);
+	WREG32(GRBM_SOFT_RESET, 0);
+	RREG32(GRBM_SOFT_RESET);
+
+	WREG32(CP_SEM_WAIT_TIMER, 0x0);
+	WREG32(CP_SEM_INCOMPLETE_TIMER_CNTL, 0x0);
+
+	/* Set the write pointer delay */
+	WREG32(CP_RB_WPTR_DELAY, 0);
+
+	WREG32(CP_DEBUG, 0);
+	WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF);
+
+	/* ring 0 - compute and gfx */
+	/* Set ring buffer size */
+	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+	rb_bufsz = drm_order(ring->ring_size / 8);
+	tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+#ifdef __BIG_ENDIAN
+	tmp |= BUF_SWAP_32BIT;
+#endif
+	WREG32(CP_RB0_CNTL, tmp);
+
+	/* Initialize the ring buffer's read and write pointers */
+	WREG32(CP_RB0_CNTL, tmp | RB_RPTR_WR_ENA);
+	ring->wptr = 0;
+	WREG32(CP_RB0_WPTR, ring->wptr);
+
+	/* set the wb address wether it's enabled or not */
+	WREG32(CP_RB0_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
+	WREG32(CP_RB0_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF);
+
+	if (rdev->wb.enabled)
+		WREG32(SCRATCH_UMSK, 0xff);
+	else {
+		tmp |= RB_NO_UPDATE;
+		WREG32(SCRATCH_UMSK, 0);
+	}
+
+	mdelay(1);
+	WREG32(CP_RB0_CNTL, tmp);
+
+	WREG32(CP_RB0_BASE, ring->gpu_addr >> 8);
+
+	ring->rptr = RREG32(CP_RB0_RPTR);
+
+	/* ring1  - compute only */
+	/* Set ring buffer size */
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+	rb_bufsz = drm_order(ring->ring_size / 8);
+	tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+#ifdef __BIG_ENDIAN
+	tmp |= BUF_SWAP_32BIT;
+#endif
+	WREG32(CP_RB1_CNTL, tmp);
+
+	/* Initialize the ring buffer's read and write pointers */
+	WREG32(CP_RB1_CNTL, tmp | RB_RPTR_WR_ENA);
+	ring->wptr = 0;
+	WREG32(CP_RB1_WPTR, ring->wptr);
+
+	/* set the wb address wether it's enabled or not */
+	WREG32(CP_RB1_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP1_RPTR_OFFSET) & 0xFFFFFFFC);
+	WREG32(CP_RB1_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP1_RPTR_OFFSET) & 0xFF);
+
+	mdelay(1);
+	WREG32(CP_RB1_CNTL, tmp);
+
+	WREG32(CP_RB1_BASE, ring->gpu_addr >> 8);
+
+	ring->rptr = RREG32(CP_RB1_RPTR);
+
+	/* ring2 - compute only */
+	/* Set ring buffer size */
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
+	rb_bufsz = drm_order(ring->ring_size / 8);
+	tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+#ifdef __BIG_ENDIAN
+	tmp |= BUF_SWAP_32BIT;
+#endif
+	WREG32(CP_RB2_CNTL, tmp);
+
+	/* Initialize the ring buffer's read and write pointers */
+	WREG32(CP_RB2_CNTL, tmp | RB_RPTR_WR_ENA);
+	ring->wptr = 0;
+	WREG32(CP_RB2_WPTR, ring->wptr);
+
+	/* set the wb address wether it's enabled or not */
+	WREG32(CP_RB2_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP2_RPTR_OFFSET) & 0xFFFFFFFC);
+	WREG32(CP_RB2_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP2_RPTR_OFFSET) & 0xFF);
+
+	mdelay(1);
+	WREG32(CP_RB2_CNTL, tmp);
+
+	WREG32(CP_RB2_BASE, ring->gpu_addr >> 8);
+
+	ring->rptr = RREG32(CP_RB2_RPTR);
+
+	/* start the rings */
+	si_cp_start(rdev);
+	rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = true;
+	rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = true;
+	rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = true;
+	r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
+	if (r) {
+		rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
+		rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false;
+		rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false;
+		return r;
+	}
+	r = radeon_ring_test(rdev, CAYMAN_RING_TYPE_CP1_INDEX, &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX]);
+	if (r) {
+		rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false;
+	}
+	r = radeon_ring_test(rdev, CAYMAN_RING_TYPE_CP2_INDEX, &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX]);
+	if (r) {
+		rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false;
+	}
+
+	return 0;
+}
+
+bool si_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+	u32 srbm_status;
+	u32 grbm_status, grbm_status2;
+	u32 grbm_status_se0, grbm_status_se1;
+	struct r100_gpu_lockup *lockup = &rdev->config.si.lockup;
+	int r;
+
+	srbm_status = RREG32(SRBM_STATUS);
+	grbm_status = RREG32(GRBM_STATUS);
+	grbm_status2 = RREG32(GRBM_STATUS2);
+	grbm_status_se0 = RREG32(GRBM_STATUS_SE0);
+	grbm_status_se1 = RREG32(GRBM_STATUS_SE1);
+	if (!(grbm_status & GUI_ACTIVE)) {
+		r100_gpu_lockup_update(lockup, ring);
+		return false;
+	}
+	/* force CP activities */
+	r = radeon_ring_lock(rdev, ring, 2);
+	if (!r) {
+		/* PACKET2 NOP */
+		radeon_ring_write(ring, 0x80000000);
+		radeon_ring_write(ring, 0x80000000);
+		radeon_ring_unlock_commit(rdev, ring);
+	}
+	/* XXX deal with CP0,1,2 */
+	ring->rptr = RREG32(ring->rptr_reg);
+	return r100_gpu_cp_is_lockup(rdev, lockup, ring);
+}
+
+static int si_gpu_soft_reset(struct radeon_device *rdev)
+{
+	struct evergreen_mc_save save;
+	u32 grbm_reset = 0;
+
+	if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
+		return 0;
+
+	dev_info(rdev->dev, "GPU softreset \n");
+	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
+		RREG32(GRBM_STATUS));
+	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
+		RREG32(GRBM_STATUS2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
+		RREG32(GRBM_STATUS_SE0));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
+		RREG32(GRBM_STATUS_SE1));
+	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
+		RREG32(SRBM_STATUS));
+	evergreen_mc_stop(rdev, &save);
+	if (radeon_mc_wait_for_idle(rdev)) {
+		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+	}
+	/* Disable CP parsing/prefetching */
+	WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
+
+	/* reset all the gfx blocks */
+	grbm_reset = (SOFT_RESET_CP |
+		      SOFT_RESET_CB |
+		      SOFT_RESET_DB |
+		      SOFT_RESET_GDS |
+		      SOFT_RESET_PA |
+		      SOFT_RESET_SC |
+		      SOFT_RESET_SPI |
+		      SOFT_RESET_SX |
+		      SOFT_RESET_TC |
+		      SOFT_RESET_TA |
+		      SOFT_RESET_VGT |
+		      SOFT_RESET_IA);
+
+	dev_info(rdev->dev, "  GRBM_SOFT_RESET=0x%08X\n", grbm_reset);
+	WREG32(GRBM_SOFT_RESET, grbm_reset);
+	(void)RREG32(GRBM_SOFT_RESET);
+	udelay(50);
+	WREG32(GRBM_SOFT_RESET, 0);
+	(void)RREG32(GRBM_SOFT_RESET);
+	/* Wait a little for things to settle down */
+	udelay(50);
+	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
+		RREG32(GRBM_STATUS));
+	dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
+		RREG32(GRBM_STATUS2));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
+		RREG32(GRBM_STATUS_SE0));
+	dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
+		RREG32(GRBM_STATUS_SE1));
+	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
+		RREG32(SRBM_STATUS));
+	evergreen_mc_resume(rdev, &save);
+	return 0;
+}
+
+int si_asic_reset(struct radeon_device *rdev)
+{
+	return si_gpu_soft_reset(rdev);
+}
+
+/* MC */
+static void si_mc_program(struct radeon_device *rdev)
+{
+	struct evergreen_mc_save save;
+	u32 tmp;
+	int i, j;
+
+	/* Initialize HDP */
+	for (i = 0, j = 0; i < 32; i++, j += 0x18) {
+		WREG32((0x2c14 + j), 0x00000000);
+		WREG32((0x2c18 + j), 0x00000000);
+		WREG32((0x2c1c + j), 0x00000000);
+		WREG32((0x2c20 + j), 0x00000000);
+		WREG32((0x2c24 + j), 0x00000000);
+	}
+	WREG32(HDP_REG_COHERENCY_FLUSH_CNTL, 0);
+
+	evergreen_mc_stop(rdev, &save);
+	if (radeon_mc_wait_for_idle(rdev)) {
+		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+	}
+	/* Lockout access through VGA aperture*/
+	WREG32(VGA_HDP_CONTROL, VGA_MEMORY_DISABLE);
+	/* Update configuration */
+	WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
+	       rdev->mc.vram_start >> 12);
+	WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
+	       rdev->mc.vram_end >> 12);
+	WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR,
+	       rdev->vram_scratch.gpu_addr >> 12);
+	tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16;
+	tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF);
+	WREG32(MC_VM_FB_LOCATION, tmp);
+	/* XXX double check these! */
+	WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8));
+	WREG32(HDP_NONSURFACE_INFO, (2 << 7) | (1 << 30));
+	WREG32(HDP_NONSURFACE_SIZE, 0x3FFFFFFF);
+	WREG32(MC_VM_AGP_BASE, 0);
+	WREG32(MC_VM_AGP_TOP, 0x0FFFFFFF);
+	WREG32(MC_VM_AGP_BOT, 0x0FFFFFFF);
+	if (radeon_mc_wait_for_idle(rdev)) {
+		dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+	}
+	evergreen_mc_resume(rdev, &save);
+	/* we need to own VRAM, so turn off the VGA renderer here
+	 * to stop it overwriting our objects */
+	rv515_vga_render_disable(rdev);
+}
+
+/* SI MC address space is 40 bits */
+static void si_vram_location(struct radeon_device *rdev,
+			     struct radeon_mc *mc, u64 base)
+{
+	mc->vram_start = base;
+	if (mc->mc_vram_size > (0xFFFFFFFFFFULL - base + 1)) {
+		dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n");
+		mc->real_vram_size = mc->aper_size;
+		mc->mc_vram_size = mc->aper_size;
+	}
+	mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
+	dev_info(rdev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n",
+			mc->mc_vram_size >> 20, mc->vram_start,
+			mc->vram_end, mc->real_vram_size >> 20);
+}
+
+static void si_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc)
+{
+	u64 size_af, size_bf;
+
+	size_af = ((0xFFFFFFFFFFULL - mc->vram_end) + mc->gtt_base_align) & ~mc->gtt_base_align;
+	size_bf = mc->vram_start & ~mc->gtt_base_align;
+	if (size_bf > size_af) {
+		if (mc->gtt_size > size_bf) {
+			dev_warn(rdev->dev, "limiting GTT\n");
+			mc->gtt_size = size_bf;
+		}
+		mc->gtt_start = (mc->vram_start & ~mc->gtt_base_align) - mc->gtt_size;
+	} else {
+		if (mc->gtt_size > size_af) {
+			dev_warn(rdev->dev, "limiting GTT\n");
+			mc->gtt_size = size_af;
+		}
+		mc->gtt_start = (mc->vram_end + 1 + mc->gtt_base_align) & ~mc->gtt_base_align;
+	}
+	mc->gtt_end = mc->gtt_start + mc->gtt_size - 1;
+	dev_info(rdev->dev, "GTT: %lluM 0x%016llX - 0x%016llX\n",
+			mc->gtt_size >> 20, mc->gtt_start, mc->gtt_end);
+}
+
+static void si_vram_gtt_location(struct radeon_device *rdev,
+				 struct radeon_mc *mc)
+{
+	if (mc->mc_vram_size > 0xFFC0000000ULL) {
+		/* leave room for at least 1024M GTT */
+		dev_warn(rdev->dev, "limiting VRAM\n");
+		mc->real_vram_size = 0xFFC0000000ULL;
+		mc->mc_vram_size = 0xFFC0000000ULL;
+	}
+	si_vram_location(rdev, &rdev->mc, 0);
+	rdev->mc.gtt_base_align = 0;
+	si_gtt_location(rdev, mc);
+}
+
+static int si_mc_init(struct radeon_device *rdev)
+{
+	u32 tmp;
+	int chansize, numchan;
+
+	/* Get VRAM informations */
+	rdev->mc.vram_is_ddr = true;
+	tmp = RREG32(MC_ARB_RAMCFG);
+	if (tmp & CHANSIZE_OVERRIDE) {
+		chansize = 16;
+	} else if (tmp & CHANSIZE_MASK) {
+		chansize = 64;
+	} else {
+		chansize = 32;
+	}
+	tmp = RREG32(MC_SHARED_CHMAP);
+	switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+	case 0:
+	default:
+		numchan = 1;
+		break;
+	case 1:
+		numchan = 2;
+		break;
+	case 2:
+		numchan = 4;
+		break;
+	case 3:
+		numchan = 8;
+		break;
+	case 4:
+		numchan = 3;
+		break;
+	case 5:
+		numchan = 6;
+		break;
+	case 6:
+		numchan = 10;
+		break;
+	case 7:
+		numchan = 12;
+		break;
+	case 8:
+		numchan = 16;
+		break;
+	}
+	rdev->mc.vram_width = numchan * chansize;
+	/* Could aper size report 0 ? */
+	rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
+	rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
+	/* size in MB on si */
+	rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+	rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+	rdev->mc.visible_vram_size = rdev->mc.aper_size;
+	si_vram_gtt_location(rdev, &rdev->mc);
+	radeon_update_bandwidth_info(rdev);
+
+	return 0;
+}
+
+/*
+ * GART
+ */
+void si_pcie_gart_tlb_flush(struct radeon_device *rdev)
+{
+	/* flush hdp cache */
+	WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
+
+	/* bits 0-15 are the VM contexts0-15 */
+	WREG32(VM_INVALIDATE_REQUEST, 1);
+}
+
+int si_pcie_gart_enable(struct radeon_device *rdev)
+{
+	int r, i;
+
+	if (rdev->gart.robj == NULL) {
+		dev_err(rdev->dev, "No VRAM object for PCIE GART.\n");
+		return -EINVAL;
+	}
+	r = radeon_gart_table_vram_pin(rdev);
+	if (r)
+		return r;
+	radeon_gart_restore(rdev);
+	/* Setup TLB control */
+	WREG32(MC_VM_MX_L1_TLB_CNTL,
+	       (0xA << 7) |
+	       ENABLE_L1_TLB |
+	       SYSTEM_ACCESS_MODE_NOT_IN_SYS |
+	       ENABLE_ADVANCED_DRIVER_MODEL |
+	       SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU);
+	/* Setup L2 cache */
+	WREG32(VM_L2_CNTL, ENABLE_L2_CACHE |
+	       ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
+	       ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE |
+	       EFFECTIVE_L2_QUEUE_SIZE(7) |
+	       CONTEXT1_IDENTITY_ACCESS_MODE(1));
+	WREG32(VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS | INVALIDATE_L2_CACHE);
+	WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY |
+	       L2_CACHE_BIGK_FRAGMENT_SIZE(0));
+	/* setup context0 */
+	WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12);
+	WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12);
+	WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12);
+	WREG32(VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR,
+			(u32)(rdev->dummy_page.addr >> 12));
+	WREG32(VM_CONTEXT0_CNTL2, 0);
+	WREG32(VM_CONTEXT0_CNTL, (ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) |
+				  RANGE_PROTECTION_FAULT_ENABLE_DEFAULT));
+
+	WREG32(0x15D4, 0);
+	WREG32(0x15D8, 0);
+	WREG32(0x15DC, 0);
+
+	/* empty context1-15 */
+	/* FIXME start with 1G, once using 2 level pt switch to full
+	 * vm size space
+	 */
+	/* set vm size, must be a multiple of 4 */
+	WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0);
+	WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, (1 << 30) / RADEON_GPU_PAGE_SIZE);
+	for (i = 1; i < 16; i++) {
+		if (i < 8)
+			WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2),
+			       rdev->gart.table_addr >> 12);
+		else
+			WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2),
+			       rdev->gart.table_addr >> 12);
+	}
+
+	/* enable context1-15 */
+	WREG32(VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR,
+	       (u32)(rdev->dummy_page.addr >> 12));
+	WREG32(VM_CONTEXT1_CNTL2, 0);
+	WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) |
+				RANGE_PROTECTION_FAULT_ENABLE_DEFAULT);
+
+	si_pcie_gart_tlb_flush(rdev);
+	DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
+		 (unsigned)(rdev->mc.gtt_size >> 20),
+		 (unsigned long long)rdev->gart.table_addr);
+	rdev->gart.ready = true;
+	return 0;
+}
+
+void si_pcie_gart_disable(struct radeon_device *rdev)
+{
+	/* Disable all tables */
+	WREG32(VM_CONTEXT0_CNTL, 0);
+	WREG32(VM_CONTEXT1_CNTL, 0);
+	/* Setup TLB control */
+	WREG32(MC_VM_MX_L1_TLB_CNTL, SYSTEM_ACCESS_MODE_NOT_IN_SYS |
+	       SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU);
+	/* Setup L2 cache */
+	WREG32(VM_L2_CNTL, ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
+	       ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE |
+	       EFFECTIVE_L2_QUEUE_SIZE(7) |
+	       CONTEXT1_IDENTITY_ACCESS_MODE(1));
+	WREG32(VM_L2_CNTL2, 0);
+	WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY |
+	       L2_CACHE_BIGK_FRAGMENT_SIZE(0));
+	radeon_gart_table_vram_unpin(rdev);
+}
+
+void si_pcie_gart_fini(struct radeon_device *rdev)
+{
+	si_pcie_gart_disable(rdev);
+	radeon_gart_table_vram_free(rdev);
+	radeon_gart_fini(rdev);
+}
+
+/* vm parser */
+static bool si_vm_reg_valid(u32 reg)
+{
+	/* context regs are fine */
+	if (reg >= 0x28000)
+		return true;
+
+	/* check config regs */
+	switch (reg) {
+	case GRBM_GFX_INDEX:
+	case VGT_VTX_VECT_EJECT_REG:
+	case VGT_CACHE_INVALIDATION:
+	case VGT_ESGS_RING_SIZE:
+	case VGT_GSVS_RING_SIZE:
+	case VGT_GS_VERTEX_REUSE:
+	case VGT_PRIMITIVE_TYPE:
+	case VGT_INDEX_TYPE:
+	case VGT_NUM_INDICES:
+	case VGT_NUM_INSTANCES:
+	case VGT_TF_RING_SIZE:
+	case VGT_HS_OFFCHIP_PARAM:
+	case VGT_TF_MEMORY_BASE:
+	case PA_CL_ENHANCE:
+	case PA_SU_LINE_STIPPLE_VALUE:
+	case PA_SC_LINE_STIPPLE_STATE:
+	case PA_SC_ENHANCE:
+	case SQC_CACHES:
+	case SPI_STATIC_THREAD_MGMT_1:
+	case SPI_STATIC_THREAD_MGMT_2:
+	case SPI_STATIC_THREAD_MGMT_3:
+	case SPI_PS_MAX_WAVE_ID:
+	case SPI_CONFIG_CNTL:
+	case SPI_CONFIG_CNTL_1:
+	case TA_CNTL_AUX:
+		return true;
+	default:
+		DRM_ERROR("Invalid register 0x%x in CS\n", reg);
+		return false;
+	}
+}
+
+static int si_vm_packet3_ce_check(struct radeon_device *rdev,
+				  u32 *ib, struct radeon_cs_packet *pkt)
+{
+	switch (pkt->opcode) {
+	case PACKET3_NOP:
+	case PACKET3_SET_BASE:
+	case PACKET3_SET_CE_DE_COUNTERS:
+	case PACKET3_LOAD_CONST_RAM:
+	case PACKET3_WRITE_CONST_RAM:
+	case PACKET3_WRITE_CONST_RAM_OFFSET:
+	case PACKET3_DUMP_CONST_RAM:
+	case PACKET3_INCREMENT_CE_COUNTER:
+	case PACKET3_WAIT_ON_DE_COUNTER:
+	case PACKET3_CE_WRITE:
+		break;
+	default:
+		DRM_ERROR("Invalid CE packet3: 0x%x\n", pkt->opcode);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int si_vm_packet3_gfx_check(struct radeon_device *rdev,
+				   u32 *ib, struct radeon_cs_packet *pkt)
+{
+	u32 idx = pkt->idx + 1;
+	u32 idx_value = ib[idx];
+	u32 start_reg, end_reg, reg, i;
+
+	switch (pkt->opcode) {
+	case PACKET3_NOP:
+	case PACKET3_SET_BASE:
+	case PACKET3_CLEAR_STATE:
+	case PACKET3_INDEX_BUFFER_SIZE:
+	case PACKET3_DISPATCH_DIRECT:
+	case PACKET3_DISPATCH_INDIRECT:
+	case PACKET3_ALLOC_GDS:
+	case PACKET3_WRITE_GDS_RAM:
+	case PACKET3_ATOMIC_GDS:
+	case PACKET3_ATOMIC:
+	case PACKET3_OCCLUSION_QUERY:
+	case PACKET3_SET_PREDICATION:
+	case PACKET3_COND_EXEC:
+	case PACKET3_PRED_EXEC:
+	case PACKET3_DRAW_INDIRECT:
+	case PACKET3_DRAW_INDEX_INDIRECT:
+	case PACKET3_INDEX_BASE:
+	case PACKET3_DRAW_INDEX_2:
+	case PACKET3_CONTEXT_CONTROL:
+	case PACKET3_INDEX_TYPE:
+	case PACKET3_DRAW_INDIRECT_MULTI:
+	case PACKET3_DRAW_INDEX_AUTO:
+	case PACKET3_DRAW_INDEX_IMMD:
+	case PACKET3_NUM_INSTANCES:
+	case PACKET3_DRAW_INDEX_MULTI_AUTO:
+	case PACKET3_STRMOUT_BUFFER_UPDATE:
+	case PACKET3_DRAW_INDEX_OFFSET_2:
+	case PACKET3_DRAW_INDEX_MULTI_ELEMENT:
+	case PACKET3_DRAW_INDEX_INDIRECT_MULTI:
+	case PACKET3_MPEG_INDEX:
+	case PACKET3_WAIT_REG_MEM:
+	case PACKET3_MEM_WRITE:
+	case PACKET3_PFP_SYNC_ME:
+	case PACKET3_SURFACE_SYNC:
+	case PACKET3_EVENT_WRITE:
+	case PACKET3_EVENT_WRITE_EOP:
+	case PACKET3_EVENT_WRITE_EOS:
+	case PACKET3_SET_CONTEXT_REG:
+	case PACKET3_SET_CONTEXT_REG_INDIRECT:
+	case PACKET3_SET_SH_REG:
+	case PACKET3_SET_SH_REG_OFFSET:
+	case PACKET3_INCREMENT_DE_COUNTER:
+	case PACKET3_WAIT_ON_CE_COUNTER:
+	case PACKET3_WAIT_ON_AVAIL_BUFFER:
+	case PACKET3_ME_WRITE:
+		break;
+	case PACKET3_COPY_DATA:
+		if ((idx_value & 0xf00) == 0) {
+			reg = ib[idx + 3] * 4;
+			if (!si_vm_reg_valid(reg))
+				return -EINVAL;
+		}
+		break;
+	case PACKET3_WRITE_DATA:
+		if ((idx_value & 0xf00) == 0) {
+			start_reg = ib[idx + 1] * 4;
+			if (idx_value & 0x10000) {
+				if (!si_vm_reg_valid(start_reg))
+					return -EINVAL;
+			} else {
+				for (i = 0; i < (pkt->count - 2); i++) {
+					reg = start_reg + (4 * i);
+					if (!si_vm_reg_valid(reg))
+						return -EINVAL;
+				}
+			}
+		}
+		break;
+	case PACKET3_COND_WRITE:
+		if (idx_value & 0x100) {
+			reg = ib[idx + 5] * 4;
+			if (!si_vm_reg_valid(reg))
+				return -EINVAL;
+		}
+		break;
+	case PACKET3_COPY_DW:
+		if (idx_value & 0x2) {
+			reg = ib[idx + 3] * 4;
+			if (!si_vm_reg_valid(reg))
+				return -EINVAL;
+		}
+		break;
+	case PACKET3_SET_CONFIG_REG:
+		start_reg = (idx_value << 2) + PACKET3_SET_CONFIG_REG_START;
+		end_reg = 4 * pkt->count + start_reg - 4;
+		if ((start_reg < PACKET3_SET_CONFIG_REG_START) ||
+		    (start_reg >= PACKET3_SET_CONFIG_REG_END) ||
+		    (end_reg >= PACKET3_SET_CONFIG_REG_END)) {
+			DRM_ERROR("bad PACKET3_SET_CONFIG_REG\n");
+			return -EINVAL;
+		}
+		for (i = 0; i < pkt->count; i++) {
+			reg = start_reg + (4 * i);
+			if (!si_vm_reg_valid(reg))
+				return -EINVAL;
+		}
+		break;
+	default:
+		DRM_ERROR("Invalid GFX packet3: 0x%x\n", pkt->opcode);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int si_vm_packet3_compute_check(struct radeon_device *rdev,
+				       u32 *ib, struct radeon_cs_packet *pkt)
+{
+	u32 idx = pkt->idx + 1;
+	u32 idx_value = ib[idx];
+	u32 start_reg, reg, i;
+
+	switch (pkt->opcode) {
+	case PACKET3_NOP:
+	case PACKET3_SET_BASE:
+	case PACKET3_CLEAR_STATE:
+	case PACKET3_DISPATCH_DIRECT:
+	case PACKET3_DISPATCH_INDIRECT:
+	case PACKET3_ALLOC_GDS:
+	case PACKET3_WRITE_GDS_RAM:
+	case PACKET3_ATOMIC_GDS:
+	case PACKET3_ATOMIC:
+	case PACKET3_OCCLUSION_QUERY:
+	case PACKET3_SET_PREDICATION:
+	case PACKET3_COND_EXEC:
+	case PACKET3_PRED_EXEC:
+	case PACKET3_CONTEXT_CONTROL:
+	case PACKET3_STRMOUT_BUFFER_UPDATE:
+	case PACKET3_WAIT_REG_MEM:
+	case PACKET3_MEM_WRITE:
+	case PACKET3_PFP_SYNC_ME:
+	case PACKET3_SURFACE_SYNC:
+	case PACKET3_EVENT_WRITE:
+	case PACKET3_EVENT_WRITE_EOP:
+	case PACKET3_EVENT_WRITE_EOS:
+	case PACKET3_SET_CONTEXT_REG:
+	case PACKET3_SET_CONTEXT_REG_INDIRECT:
+	case PACKET3_SET_SH_REG:
+	case PACKET3_SET_SH_REG_OFFSET:
+	case PACKET3_INCREMENT_DE_COUNTER:
+	case PACKET3_WAIT_ON_CE_COUNTER:
+	case PACKET3_WAIT_ON_AVAIL_BUFFER:
+	case PACKET3_ME_WRITE:
+		break;
+	case PACKET3_COPY_DATA:
+		if ((idx_value & 0xf00) == 0) {
+			reg = ib[idx + 3] * 4;
+			if (!si_vm_reg_valid(reg))
+				return -EINVAL;
+		}
+		break;
+	case PACKET3_WRITE_DATA:
+		if ((idx_value & 0xf00) == 0) {
+			start_reg = ib[idx + 1] * 4;
+			if (idx_value & 0x10000) {
+				if (!si_vm_reg_valid(start_reg))
+					return -EINVAL;
+			} else {
+				for (i = 0; i < (pkt->count - 2); i++) {
+					reg = start_reg + (4 * i);
+					if (!si_vm_reg_valid(reg))
+						return -EINVAL;
+				}
+			}
+		}
+		break;
+	case PACKET3_COND_WRITE:
+		if (idx_value & 0x100) {
+			reg = ib[idx + 5] * 4;
+			if (!si_vm_reg_valid(reg))
+				return -EINVAL;
+		}
+		break;
+	case PACKET3_COPY_DW:
+		if (idx_value & 0x2) {
+			reg = ib[idx + 3] * 4;
+			if (!si_vm_reg_valid(reg))
+				return -EINVAL;
+		}
+		break;
+	default:
+		DRM_ERROR("Invalid Compute packet3: 0x%x\n", pkt->opcode);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
+{
+	int ret = 0;
+	u32 idx = 0;
+	struct radeon_cs_packet pkt;
+
+	do {
+		pkt.idx = idx;
+		pkt.type = CP_PACKET_GET_TYPE(ib->ptr[idx]);
+		pkt.count = CP_PACKET_GET_COUNT(ib->ptr[idx]);
+		pkt.one_reg_wr = 0;
+		switch (pkt.type) {
+		case PACKET_TYPE0:
+			dev_err(rdev->dev, "Packet0 not allowed!\n");
+			ret = -EINVAL;
+			break;
+		case PACKET_TYPE2:
+			idx += 1;
+			break;
+		case PACKET_TYPE3:
+			pkt.opcode = CP_PACKET3_GET_OPCODE(ib->ptr[idx]);
+			if (ib->is_const_ib)
+				ret = si_vm_packet3_ce_check(rdev, ib->ptr, &pkt);
+			else {
+				switch (ib->fence->ring) {
+				case RADEON_RING_TYPE_GFX_INDEX:
+					ret = si_vm_packet3_gfx_check(rdev, ib->ptr, &pkt);
+					break;
+				case CAYMAN_RING_TYPE_CP1_INDEX:
+				case CAYMAN_RING_TYPE_CP2_INDEX:
+					ret = si_vm_packet3_compute_check(rdev, ib->ptr, &pkt);
+					break;
+				default:
+					dev_err(rdev->dev, "Non-PM4 ring %d !\n", ib->fence->ring);
+					ret = -EINVAL;
+					break;
+				}
+			}
+			idx += pkt.count + 2;
+			break;
+		default:
+			dev_err(rdev->dev, "Unknown packet type %d !\n", pkt.type);
+			ret = -EINVAL;
+			break;
+		}
+		if (ret)
+			break;
+	} while (idx < ib->length_dw);
+
+	return ret;
+}
+
+/*
+ * vm
+ */
+int si_vm_init(struct radeon_device *rdev)
+{
+	/* number of VMs */
+	rdev->vm_manager.nvm = 16;
+	/* base offset of vram pages */
+	rdev->vm_manager.vram_base_offset = 0;
+
+	return 0;
+}
+
+void si_vm_fini(struct radeon_device *rdev)
+{
+}
+
+int si_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id)
+{
+	if (id < 8)
+		WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (id << 2), vm->pt_gpu_addr >> 12);
+	else
+		WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((id - 8) << 2),
+		       vm->pt_gpu_addr >> 12);
+	/* flush hdp cache */
+	WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
+	/* bits 0-15 are the VM contexts0-15 */
+	WREG32(VM_INVALIDATE_REQUEST, 1 << id);
+	return 0;
+}
+
+void si_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm)
+{
+	if (vm->id < 8)
+		WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2), 0);
+	else
+		WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2), 0);
+	/* flush hdp cache */
+	WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
+	/* bits 0-15 are the VM contexts0-15 */
+	WREG32(VM_INVALIDATE_REQUEST, 1 << vm->id);
+}
+
+void si_vm_tlb_flush(struct radeon_device *rdev, struct radeon_vm *vm)
+{
+	if (vm->id == -1)
+		return;
+
+	/* flush hdp cache */
+	WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
+	/* bits 0-15 are the VM contexts0-15 */
+	WREG32(VM_INVALIDATE_REQUEST, 1 << vm->id);
+}
+
+/*
+ * RLC
+ */
+void si_rlc_fini(struct radeon_device *rdev)
+{
+	int r;
+
+	/* save restore block */
+	if (rdev->rlc.save_restore_obj) {
+		r = radeon_bo_reserve(rdev->rlc.save_restore_obj, false);
+		if (unlikely(r != 0))
+			dev_warn(rdev->dev, "(%d) reserve RLC sr bo failed\n", r);
+		radeon_bo_unpin(rdev->rlc.save_restore_obj);
+		radeon_bo_unreserve(rdev->rlc.save_restore_obj);
+
+		radeon_bo_unref(&rdev->rlc.save_restore_obj);
+		rdev->rlc.save_restore_obj = NULL;
+	}
+
+	/* clear state block */
+	if (rdev->rlc.clear_state_obj) {
+		r = radeon_bo_reserve(rdev->rlc.clear_state_obj, false);
+		if (unlikely(r != 0))
+			dev_warn(rdev->dev, "(%d) reserve RLC c bo failed\n", r);
+		radeon_bo_unpin(rdev->rlc.clear_state_obj);
+		radeon_bo_unreserve(rdev->rlc.clear_state_obj);
+
+		radeon_bo_unref(&rdev->rlc.clear_state_obj);
+		rdev->rlc.clear_state_obj = NULL;
+	}
+}
+
+int si_rlc_init(struct radeon_device *rdev)
+{
+	int r;
+
+	/* save restore block */
+	if (rdev->rlc.save_restore_obj == NULL) {
+		r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true,
+				RADEON_GEM_DOMAIN_VRAM, &rdev->rlc.save_restore_obj);
+		if (r) {
+			dev_warn(rdev->dev, "(%d) create RLC sr bo failed\n", r);
+			return r;
+		}
+	}
+
+	r = radeon_bo_reserve(rdev->rlc.save_restore_obj, false);
+	if (unlikely(r != 0)) {
+		si_rlc_fini(rdev);
+		return r;
+	}
+	r = radeon_bo_pin(rdev->rlc.save_restore_obj, RADEON_GEM_DOMAIN_VRAM,
+			  &rdev->rlc.save_restore_gpu_addr);
+	if (r) {
+		radeon_bo_unreserve(rdev->rlc.save_restore_obj);
+		dev_warn(rdev->dev, "(%d) pin RLC sr bo failed\n", r);
+		si_rlc_fini(rdev);
+		return r;
+	}
+
+	/* clear state block */
+	if (rdev->rlc.clear_state_obj == NULL) {
+		r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true,
+				RADEON_GEM_DOMAIN_VRAM, &rdev->rlc.clear_state_obj);
+		if (r) {
+			dev_warn(rdev->dev, "(%d) create RLC c bo failed\n", r);
+			si_rlc_fini(rdev);
+			return r;
+		}
+	}
+	r = radeon_bo_reserve(rdev->rlc.clear_state_obj, false);
+	if (unlikely(r != 0)) {
+		si_rlc_fini(rdev);
+		return r;
+	}
+	r = radeon_bo_pin(rdev->rlc.clear_state_obj, RADEON_GEM_DOMAIN_VRAM,
+			  &rdev->rlc.clear_state_gpu_addr);
+	if (r) {
+
+		radeon_bo_unreserve(rdev->rlc.clear_state_obj);
+		dev_warn(rdev->dev, "(%d) pin RLC c bo failed\n", r);
+		si_rlc_fini(rdev);
+		return r;
+	}
+
+	return 0;
+}
+
+static void si_rlc_stop(struct radeon_device *rdev)
+{
+	WREG32(RLC_CNTL, 0);
+}
+
+static void si_rlc_start(struct radeon_device *rdev)
+{
+	WREG32(RLC_CNTL, RLC_ENABLE);
+}
+
+static int si_rlc_resume(struct radeon_device *rdev)
+{
+	u32 i;
+	const __be32 *fw_data;
+
+	if (!rdev->rlc_fw)
+		return -EINVAL;
+
+	si_rlc_stop(rdev);
+
+	WREG32(RLC_RL_BASE, 0);
+	WREG32(RLC_RL_SIZE, 0);
+	WREG32(RLC_LB_CNTL, 0);
+	WREG32(RLC_LB_CNTR_MAX, 0xffffffff);
+	WREG32(RLC_LB_CNTR_INIT, 0);
+
+	WREG32(RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8);
+	WREG32(RLC_CLEAR_STATE_RESTORE_BASE, rdev->rlc.clear_state_gpu_addr >> 8);
+
+	WREG32(RLC_MC_CNTL, 0);
+	WREG32(RLC_UCODE_CNTL, 0);
+
+	fw_data = (const __be32 *)rdev->rlc_fw->data;
+	for (i = 0; i < SI_RLC_UCODE_SIZE; i++) {
+		WREG32(RLC_UCODE_ADDR, i);
+		WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
+	}
+	WREG32(RLC_UCODE_ADDR, 0);
+
+	si_rlc_start(rdev);
+
+	return 0;
+}
+
+static void si_enable_interrupts(struct radeon_device *rdev)
+{
+	u32 ih_cntl = RREG32(IH_CNTL);
+	u32 ih_rb_cntl = RREG32(IH_RB_CNTL);
+
+	ih_cntl |= ENABLE_INTR;
+	ih_rb_cntl |= IH_RB_ENABLE;
+	WREG32(IH_CNTL, ih_cntl);
+	WREG32(IH_RB_CNTL, ih_rb_cntl);
+	rdev->ih.enabled = true;
+}
+
+static void si_disable_interrupts(struct radeon_device *rdev)
+{
+	u32 ih_rb_cntl = RREG32(IH_RB_CNTL);
+	u32 ih_cntl = RREG32(IH_CNTL);
+
+	ih_rb_cntl &= ~IH_RB_ENABLE;
+	ih_cntl &= ~ENABLE_INTR;
+	WREG32(IH_RB_CNTL, ih_rb_cntl);
+	WREG32(IH_CNTL, ih_cntl);
+	/* set rptr, wptr to 0 */
+	WREG32(IH_RB_RPTR, 0);
+	WREG32(IH_RB_WPTR, 0);
+	rdev->ih.enabled = false;
+	rdev->ih.wptr = 0;
+	rdev->ih.rptr = 0;
+}
+
+static void si_disable_interrupt_state(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	WREG32(CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+	WREG32(CP_INT_CNTL_RING1, 0);
+	WREG32(CP_INT_CNTL_RING2, 0);
+	WREG32(GRBM_INT_CNTL, 0);
+	WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
+	WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
+	if (rdev->num_crtc >= 4) {
+		WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
+		WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+	}
+	if (rdev->num_crtc >= 6) {
+		WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
+		WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+	}
+
+	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
+	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
+	if (rdev->num_crtc >= 4) {
+		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
+		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+	}
+	if (rdev->num_crtc >= 6) {
+		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
+		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+	}
+
+	WREG32(DACA_AUTODETECT_INT_CONTROL, 0);
+
+	tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD1_INT_CONTROL, tmp);
+	tmp = RREG32(DC_HPD2_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD2_INT_CONTROL, tmp);
+	tmp = RREG32(DC_HPD3_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD3_INT_CONTROL, tmp);
+	tmp = RREG32(DC_HPD4_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD4_INT_CONTROL, tmp);
+	tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD5_INT_CONTROL, tmp);
+	tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+	WREG32(DC_HPD6_INT_CONTROL, tmp);
+
+}
+
+static int si_irq_init(struct radeon_device *rdev)
+{
+	int ret = 0;
+	int rb_bufsz;
+	u32 interrupt_cntl, ih_cntl, ih_rb_cntl;
+
+	/* allocate ring */
+	ret = r600_ih_ring_alloc(rdev);
+	if (ret)
+		return ret;
+
+	/* disable irqs */
+	si_disable_interrupts(rdev);
+
+	/* init rlc */
+	ret = si_rlc_resume(rdev);
+	if (ret) {
+		r600_ih_ring_fini(rdev);
+		return ret;
+	}
+
+	/* setup interrupt control */
+	/* set dummy read address to ring address */
+	WREG32(INTERRUPT_CNTL2, rdev->ih.gpu_addr >> 8);
+	interrupt_cntl = RREG32(INTERRUPT_CNTL);
+	/* IH_DUMMY_RD_OVERRIDE=0 - dummy read disabled with msi, enabled without msi
+	 * IH_DUMMY_RD_OVERRIDE=1 - dummy read controlled by IH_DUMMY_RD_EN
+	 */
+	interrupt_cntl &= ~IH_DUMMY_RD_OVERRIDE;
+	/* IH_REQ_NONSNOOP_EN=1 if ring is in non-cacheable memory, e.g., vram */
+	interrupt_cntl &= ~IH_REQ_NONSNOOP_EN;
+	WREG32(INTERRUPT_CNTL, interrupt_cntl);
+
+	WREG32(IH_RB_BASE, rdev->ih.gpu_addr >> 8);
+	rb_bufsz = drm_order(rdev->ih.ring_size / 4);
+
+	ih_rb_cntl = (IH_WPTR_OVERFLOW_ENABLE |
+		      IH_WPTR_OVERFLOW_CLEAR |
+		      (rb_bufsz << 1));
+
+	if (rdev->wb.enabled)
+		ih_rb_cntl |= IH_WPTR_WRITEBACK_ENABLE;
+
+	/* set the writeback address whether it's enabled or not */
+	WREG32(IH_RB_WPTR_ADDR_LO, (rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFFFFFFFC);
+	WREG32(IH_RB_WPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFF);
+
+	WREG32(IH_RB_CNTL, ih_rb_cntl);
+
+	/* set rptr, wptr to 0 */
+	WREG32(IH_RB_RPTR, 0);
+	WREG32(IH_RB_WPTR, 0);
+
+	/* Default settings for IH_CNTL (disabled at first) */
+	ih_cntl = MC_WRREQ_CREDIT(0x10) | MC_WR_CLEAN_CNT(0x10) | MC_VMID(0);
+	/* RPTR_REARM only works if msi's are enabled */
+	if (rdev->msi_enabled)
+		ih_cntl |= RPTR_REARM;
+	WREG32(IH_CNTL, ih_cntl);
+
+	/* force the active interrupt state to all disabled */
+	si_disable_interrupt_state(rdev);
+
+	/* enable irqs */
+	si_enable_interrupts(rdev);
+
+	return ret;
+}
+
+int si_irq_set(struct radeon_device *rdev)
+{
+	u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE;
+	u32 cp_int_cntl1 = 0, cp_int_cntl2 = 0;
+	u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
+	u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
+	u32 grbm_int_cntl = 0;
+	u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;
+
+	if (!rdev->irq.installed) {
+		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
+		return -EINVAL;
+	}
+	/* don't enable anything if the ih is disabled */
+	if (!rdev->ih.enabled) {
+		si_disable_interrupts(rdev);
+		/* force the active interrupt state to all disabled */
+		si_disable_interrupt_state(rdev);
+		return 0;
+	}
+
+	hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
+	hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+
+	/* enable CP interrupts on all rings */
+	if (rdev->irq.sw_int[RADEON_RING_TYPE_GFX_INDEX]) {
+		DRM_DEBUG("si_irq_set: sw int gfx\n");
+		cp_int_cntl |= TIME_STAMP_INT_ENABLE;
+	}
+	if (rdev->irq.sw_int[CAYMAN_RING_TYPE_CP1_INDEX]) {
+		DRM_DEBUG("si_irq_set: sw int cp1\n");
+		cp_int_cntl1 |= TIME_STAMP_INT_ENABLE;
+	}
+	if (rdev->irq.sw_int[CAYMAN_RING_TYPE_CP2_INDEX]) {
+		DRM_DEBUG("si_irq_set: sw int cp2\n");
+		cp_int_cntl2 |= TIME_STAMP_INT_ENABLE;
+	}
+	if (rdev->irq.crtc_vblank_int[0] ||
+	    rdev->irq.pflip[0]) {
+		DRM_DEBUG("si_irq_set: vblank 0\n");
+		crtc1 |= VBLANK_INT_MASK;
+	}
+	if (rdev->irq.crtc_vblank_int[1] ||
+	    rdev->irq.pflip[1]) {
+		DRM_DEBUG("si_irq_set: vblank 1\n");
+		crtc2 |= VBLANK_INT_MASK;
+	}
+	if (rdev->irq.crtc_vblank_int[2] ||
+	    rdev->irq.pflip[2]) {
+		DRM_DEBUG("si_irq_set: vblank 2\n");
+		crtc3 |= VBLANK_INT_MASK;
+	}
+	if (rdev->irq.crtc_vblank_int[3] ||
+	    rdev->irq.pflip[3]) {
+		DRM_DEBUG("si_irq_set: vblank 3\n");
+		crtc4 |= VBLANK_INT_MASK;
+	}
+	if (rdev->irq.crtc_vblank_int[4] ||
+	    rdev->irq.pflip[4]) {
+		DRM_DEBUG("si_irq_set: vblank 4\n");
+		crtc5 |= VBLANK_INT_MASK;
+	}
+	if (rdev->irq.crtc_vblank_int[5] ||
+	    rdev->irq.pflip[5]) {
+		DRM_DEBUG("si_irq_set: vblank 5\n");
+		crtc6 |= VBLANK_INT_MASK;
+	}
+	if (rdev->irq.hpd[0]) {
+		DRM_DEBUG("si_irq_set: hpd 1\n");
+		hpd1 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.hpd[1]) {
+		DRM_DEBUG("si_irq_set: hpd 2\n");
+		hpd2 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.hpd[2]) {
+		DRM_DEBUG("si_irq_set: hpd 3\n");
+		hpd3 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.hpd[3]) {
+		DRM_DEBUG("si_irq_set: hpd 4\n");
+		hpd4 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.hpd[4]) {
+		DRM_DEBUG("si_irq_set: hpd 5\n");
+		hpd5 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.hpd[5]) {
+		DRM_DEBUG("si_irq_set: hpd 6\n");
+		hpd6 |= DC_HPDx_INT_EN;
+	}
+	if (rdev->irq.gui_idle) {
+		DRM_DEBUG("gui idle\n");
+		grbm_int_cntl |= GUI_IDLE_INT_ENABLE;
+	}
+
+	WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
+	WREG32(CP_INT_CNTL_RING1, cp_int_cntl1);
+	WREG32(CP_INT_CNTL_RING2, cp_int_cntl2);
+
+	WREG32(GRBM_INT_CNTL, grbm_int_cntl);
+
+	WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
+	WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2);
+	if (rdev->num_crtc >= 4) {
+		WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3);
+		WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4);
+	}
+	if (rdev->num_crtc >= 6) {
+		WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5);
+		WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6);
+	}
+
+	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, grph1);
+	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, grph2);
+	if (rdev->num_crtc >= 4) {
+		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, grph3);
+		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, grph4);
+	}
+	if (rdev->num_crtc >= 6) {
+		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, grph5);
+		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, grph6);
+	}
+
+	WREG32(DC_HPD1_INT_CONTROL, hpd1);
+	WREG32(DC_HPD2_INT_CONTROL, hpd2);
+	WREG32(DC_HPD3_INT_CONTROL, hpd3);
+	WREG32(DC_HPD4_INT_CONTROL, hpd4);
+	WREG32(DC_HPD5_INT_CONTROL, hpd5);
+	WREG32(DC_HPD6_INT_CONTROL, hpd6);
+
+	return 0;
+}
+
+static inline void si_irq_ack(struct radeon_device *rdev)
+{
+	u32 tmp;
+
+	rdev->irq.stat_regs.evergreen.disp_int = RREG32(DISP_INTERRUPT_STATUS);
+	rdev->irq.stat_regs.evergreen.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
+	rdev->irq.stat_regs.evergreen.disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2);
+	rdev->irq.stat_regs.evergreen.disp_int_cont3 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE3);
+	rdev->irq.stat_regs.evergreen.disp_int_cont4 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE4);
+	rdev->irq.stat_regs.evergreen.disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5);
+	rdev->irq.stat_regs.evergreen.d1grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET);
+	rdev->irq.stat_regs.evergreen.d2grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET);
+	if (rdev->num_crtc >= 4) {
+		rdev->irq.stat_regs.evergreen.d3grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET);
+		rdev->irq.stat_regs.evergreen.d4grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET);
+	}
+	if (rdev->num_crtc >= 6) {
+		rdev->irq.stat_regs.evergreen.d5grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET);
+		rdev->irq.stat_regs.evergreen.d6grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET);
+	}
+
+	if (rdev->irq.stat_regs.evergreen.d1grph_int & GRPH_PFLIP_INT_OCCURRED)
+		WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+	if (rdev->irq.stat_regs.evergreen.d2grph_int & GRPH_PFLIP_INT_OCCURRED)
+		WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+	if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT)
+		WREG32(VBLANK_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VBLANK_ACK);
+	if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT)
+		WREG32(VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VLINE_ACK);
+	if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT)
+		WREG32(VBLANK_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VBLANK_ACK);
+	if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT)
+		WREG32(VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VLINE_ACK);
+
+	if (rdev->num_crtc >= 4) {
+		if (rdev->irq.stat_regs.evergreen.d3grph_int & GRPH_PFLIP_INT_OCCURRED)
+			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+		if (rdev->irq.stat_regs.evergreen.d4grph_int & GRPH_PFLIP_INT_OCCURRED)
+			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+		if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)
+			WREG32(VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK);
+		if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)
+			WREG32(VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK);
+		if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)
+			WREG32(VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK);
+		if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)
+			WREG32(VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK);
+	}
+
+	if (rdev->num_crtc >= 6) {
+		if (rdev->irq.stat_regs.evergreen.d5grph_int & GRPH_PFLIP_INT_OCCURRED)
+			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+		if (rdev->irq.stat_regs.evergreen.d6grph_int & GRPH_PFLIP_INT_OCCURRED)
+			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
+		if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)
+			WREG32(VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK);
+		if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)
+			WREG32(VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK);
+		if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)
+			WREG32(VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK);
+		if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)
+			WREG32(VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK);
+	}
+
+	if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) {
+		tmp = RREG32(DC_HPD1_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD1_INT_CONTROL, tmp);
+	}
+	if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) {
+		tmp = RREG32(DC_HPD2_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD2_INT_CONTROL, tmp);
+	}
+	if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) {
+		tmp = RREG32(DC_HPD3_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD3_INT_CONTROL, tmp);
+	}
+	if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) {
+		tmp = RREG32(DC_HPD4_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD4_INT_CONTROL, tmp);
+	}
+	if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) {
+		tmp = RREG32(DC_HPD5_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD5_INT_CONTROL, tmp);
+	}
+	if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) {
+		tmp = RREG32(DC_HPD5_INT_CONTROL);
+		tmp |= DC_HPDx_INT_ACK;
+		WREG32(DC_HPD6_INT_CONTROL, tmp);
+	}
+}
+
+static void si_irq_disable(struct radeon_device *rdev)
+{
+	si_disable_interrupts(rdev);
+	/* Wait and acknowledge irq */
+	mdelay(1);
+	si_irq_ack(rdev);
+	si_disable_interrupt_state(rdev);
+}
+
+static void si_irq_suspend(struct radeon_device *rdev)
+{
+	si_irq_disable(rdev);
+	si_rlc_stop(rdev);
+}
+
+static void si_irq_fini(struct radeon_device *rdev)
+{
+	si_irq_suspend(rdev);
+	r600_ih_ring_fini(rdev);
+}
+
+static inline u32 si_get_ih_wptr(struct radeon_device *rdev)
+{
+	u32 wptr, tmp;
+
+	if (rdev->wb.enabled)
+		wptr = le32_to_cpu(rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]);
+	else
+		wptr = RREG32(IH_RB_WPTR);
+
+	if (wptr & RB_OVERFLOW) {
+		/* When a ring buffer overflow happen start parsing interrupt
+		 * from the last not overwritten vector (wptr + 16). Hopefully
+		 * this should allow us to catchup.
+		 */
+		dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n",
+			wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask);
+		rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask;
+		tmp = RREG32(IH_RB_CNTL);
+		tmp |= IH_WPTR_OVERFLOW_CLEAR;
+		WREG32(IH_RB_CNTL, tmp);
+	}
+	return (wptr & rdev->ih.ptr_mask);
+}
+
+/*        SI IV Ring
+ * Each IV ring entry is 128 bits:
+ * [7:0]    - interrupt source id
+ * [31:8]   - reserved
+ * [59:32]  - interrupt source data
+ * [63:60]  - reserved
+ * [71:64]  - RINGID
+ * [79:72]  - VMID
+ * [127:80] - reserved
+ */
+int si_irq_process(struct radeon_device *rdev)
+{
+	u32 wptr;
+	u32 rptr;
+	u32 src_id, src_data, ring_id;
+	u32 ring_index;
+	unsigned long flags;
+	bool queue_hotplug = false;
+
+	if (!rdev->ih.enabled || rdev->shutdown)
+		return IRQ_NONE;
+
+	wptr = si_get_ih_wptr(rdev);
+	rptr = rdev->ih.rptr;
+	DRM_DEBUG("si_irq_process start: rptr %d, wptr %d\n", rptr, wptr);
+
+	spin_lock_irqsave(&rdev->ih.lock, flags);
+	if (rptr == wptr) {
+		spin_unlock_irqrestore(&rdev->ih.lock, flags);
+		return IRQ_NONE;
+	}
+restart_ih:
+	/* Order reading of wptr vs. reading of IH ring data */
+	rmb();
+
+	/* display interrupts */
+	si_irq_ack(rdev);
+
+	rdev->ih.wptr = wptr;
+	while (rptr != wptr) {
+		/* wptr/rptr are in bytes! */
+		ring_index = rptr / 4;
+		src_id =  le32_to_cpu(rdev->ih.ring[ring_index]) & 0xff;
+		src_data = le32_to_cpu(rdev->ih.ring[ring_index + 1]) & 0xfffffff;
+		ring_id = le32_to_cpu(rdev->ih.ring[ring_index + 2]) & 0xff;
+
+		switch (src_id) {
+		case 1: /* D1 vblank/vline */
+			switch (src_data) {
+			case 0: /* D1 vblank */
+				if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[0]) {
+						drm_handle_vblank(rdev->ddev, 0);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (rdev->irq.pflip[0])
+						radeon_crtc_handle_flip(rdev, 0);
+					rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D1 vblank\n");
+				}
+				break;
+			case 1: /* D1 vline */
+				if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D1 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 2: /* D2 vblank/vline */
+			switch (src_data) {
+			case 0: /* D2 vblank */
+				if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[1]) {
+						drm_handle_vblank(rdev->ddev, 1);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (rdev->irq.pflip[1])
+						radeon_crtc_handle_flip(rdev, 1);
+					rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D2 vblank\n");
+				}
+				break;
+			case 1: /* D2 vline */
+				if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D2 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 3: /* D3 vblank/vline */
+			switch (src_data) {
+			case 0: /* D3 vblank */
+				if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[2]) {
+						drm_handle_vblank(rdev->ddev, 2);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (rdev->irq.pflip[2])
+						radeon_crtc_handle_flip(rdev, 2);
+					rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D3 vblank\n");
+				}
+				break;
+			case 1: /* D3 vline */
+				if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D3 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 4: /* D4 vblank/vline */
+			switch (src_data) {
+			case 0: /* D4 vblank */
+				if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[3]) {
+						drm_handle_vblank(rdev->ddev, 3);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (rdev->irq.pflip[3])
+						radeon_crtc_handle_flip(rdev, 3);
+					rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D4 vblank\n");
+				}
+				break;
+			case 1: /* D4 vline */
+				if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D4 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 5: /* D5 vblank/vline */
+			switch (src_data) {
+			case 0: /* D5 vblank */
+				if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[4]) {
+						drm_handle_vblank(rdev->ddev, 4);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (rdev->irq.pflip[4])
+						radeon_crtc_handle_flip(rdev, 4);
+					rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D5 vblank\n");
+				}
+				break;
+			case 1: /* D5 vline */
+				if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D5 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 6: /* D6 vblank/vline */
+			switch (src_data) {
+			case 0: /* D6 vblank */
+				if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) {
+					if (rdev->irq.crtc_vblank_int[5]) {
+						drm_handle_vblank(rdev->ddev, 5);
+						rdev->pm.vblank_sync = true;
+						wake_up(&rdev->irq.vblank_queue);
+					}
+					if (rdev->irq.pflip[5])
+						radeon_crtc_handle_flip(rdev, 5);
+					rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
+					DRM_DEBUG("IH: D6 vblank\n");
+				}
+				break;
+			case 1: /* D6 vline */
+				if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) {
+					rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT;
+					DRM_DEBUG("IH: D6 vline\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 42: /* HPD hotplug */
+			switch (src_data) {
+			case 0:
+				if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) {
+					rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD1\n");
+				}
+				break;
+			case 1:
+				if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) {
+					rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD2\n");
+				}
+				break;
+			case 2:
+				if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) {
+					rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD3\n");
+				}
+				break;
+			case 3:
+				if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) {
+					rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD4\n");
+				}
+				break;
+			case 4:
+				if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) {
+					rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD5\n");
+				}
+				break;
+			case 5:
+				if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) {
+					rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT;
+					queue_hotplug = true;
+					DRM_DEBUG("IH: HPD6\n");
+				}
+				break;
+			default:
+				DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+				break;
+			}
+			break;
+		case 176: /* RINGID0 CP_INT */
+			radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
+			break;
+		case 177: /* RINGID1 CP_INT */
+			radeon_fence_process(rdev, CAYMAN_RING_TYPE_CP1_INDEX);
+			break;
+		case 178: /* RINGID2 CP_INT */
+			radeon_fence_process(rdev, CAYMAN_RING_TYPE_CP2_INDEX);
+			break;
+		case 181: /* CP EOP event */
+			DRM_DEBUG("IH: CP EOP\n");
+			switch (ring_id) {
+			case 0:
+				radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
+				break;
+			case 1:
+				radeon_fence_process(rdev, CAYMAN_RING_TYPE_CP1_INDEX);
+				break;
+			case 2:
+				radeon_fence_process(rdev, CAYMAN_RING_TYPE_CP2_INDEX);
+				break;
+			}
+			break;
+		case 233: /* GUI IDLE */
+			DRM_DEBUG("IH: GUI idle\n");
+			rdev->pm.gui_idle = true;
+			wake_up(&rdev->irq.idle_queue);
+			break;
+		default:
+			DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+			break;
+		}
+
+		/* wptr/rptr are in bytes! */
+		rptr += 16;
+		rptr &= rdev->ih.ptr_mask;
+	}
+	/* make sure wptr hasn't changed while processing */
+	wptr = si_get_ih_wptr(rdev);
+	if (wptr != rdev->ih.wptr)
+		goto restart_ih;
+	if (queue_hotplug)
+		schedule_work(&rdev->hotplug_work);
+	rdev->ih.rptr = rptr;
+	WREG32(IH_RB_RPTR, rdev->ih.rptr);
+	spin_unlock_irqrestore(&rdev->ih.lock, flags);
+	return IRQ_HANDLED;
+}
+
+/*
+ * startup/shutdown callbacks
+ */
+static int si_startup(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring;
+	int r;
+
+	if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
+	    !rdev->rlc_fw || !rdev->mc_fw) {
+		r = si_init_microcode(rdev);
+		if (r) {
+			DRM_ERROR("Failed to load firmware!\n");
+			return r;
+		}
+	}
+
+	r = si_mc_load_microcode(rdev);
+	if (r) {
+		DRM_ERROR("Failed to load MC firmware!\n");
+		return r;
+	}
+
+	r = r600_vram_scratch_init(rdev);
+	if (r)
+		return r;
+
+	si_mc_program(rdev);
+	r = si_pcie_gart_enable(rdev);
+	if (r)
+		return r;
+	si_gpu_init(rdev);
+
+#if 0
+	r = evergreen_blit_init(rdev);
+	if (r) {
+		r600_blit_fini(rdev);
+		rdev->asic->copy = NULL;
+		dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
+	}
+#endif
+	/* allocate rlc buffers */
+	r = si_rlc_init(rdev);
+	if (r) {
+		DRM_ERROR("Failed to init rlc BOs!\n");
+		return r;
+	}
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
+
+	r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP1_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
+		return r;
+	}
+
+	r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP2_INDEX);
+	if (r) {
+		dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
+		return r;
+	}
+
+	/* Enable IRQ */
+	r = si_irq_init(rdev);
+	if (r) {
+		DRM_ERROR("radeon: IH init failed (%d).\n", r);
+		radeon_irq_kms_fini(rdev);
+		return r;
+	}
+	si_irq_set(rdev);
+
+	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
+			     CP_RB0_RPTR, CP_RB0_WPTR,
+			     0, 0xfffff, RADEON_CP_PACKET2);
+	if (r)
+		return r;
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET,
+			     CP_RB1_RPTR, CP_RB1_WPTR,
+			     0, 0xfffff, RADEON_CP_PACKET2);
+	if (r)
+		return r;
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
+	r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET,
+			     CP_RB2_RPTR, CP_RB2_WPTR,
+			     0, 0xfffff, RADEON_CP_PACKET2);
+	if (r)
+		return r;
+
+	r = si_cp_load_microcode(rdev);
+	if (r)
+		return r;
+	r = si_cp_resume(rdev);
+	if (r)
+		return r;
+
+	r = radeon_ib_pool_start(rdev);
+	if (r)
+		return r;
+
+	r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
+	if (r) {
+		DRM_ERROR("radeon: failed testing IB (%d) on CP ring 0\n", r);
+		rdev->accel_working = false;
+		return r;
+	}
+
+	r = radeon_ib_test(rdev, CAYMAN_RING_TYPE_CP1_INDEX, &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX]);
+	if (r) {
+		DRM_ERROR("radeon: failed testing IB (%d) on CP ring 1\n", r);
+		rdev->accel_working = false;
+		return r;
+	}
+
+	r = radeon_ib_test(rdev, CAYMAN_RING_TYPE_CP2_INDEX, &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX]);
+	if (r) {
+		DRM_ERROR("radeon: failed testing IB (%d) on CP ring 2\n", r);
+		rdev->accel_working = false;
+		return r;
+	}
+
+	r = radeon_vm_manager_start(rdev);
+	if (r)
+		return r;
+
+	return 0;
+}
+
+int si_resume(struct radeon_device *rdev)
+{
+	int r;
+
+	/* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
+	 * posting will perform necessary task to bring back GPU into good
+	 * shape.
+	 */
+	/* post card */
+	atom_asic_init(rdev->mode_info.atom_context);
+
+	rdev->accel_working = true;
+	r = si_startup(rdev);
+	if (r) {
+		DRM_ERROR("si startup failed on resume\n");
+		rdev->accel_working = false;
+		return r;
+	}
+
+	return r;
+
+}
+
+int si_suspend(struct radeon_device *rdev)
+{
+	/* FIXME: we should wait for ring to be empty */
+	radeon_ib_pool_suspend(rdev);
+	radeon_vm_manager_suspend(rdev);
+#if 0
+	r600_blit_suspend(rdev);
+#endif
+	si_cp_enable(rdev, false);
+	rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
+	rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false;
+	rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false;
+	si_irq_suspend(rdev);
+	radeon_wb_disable(rdev);
+	si_pcie_gart_disable(rdev);
+	return 0;
+}
+
+/* Plan is to move initialization in that function and use
+ * helper function so that radeon_device_init pretty much
+ * do nothing more than calling asic specific function. This
+ * should also allow to remove a bunch of callback function
+ * like vram_info.
+ */
+int si_init(struct radeon_device *rdev)
+{
+	struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+	int r;
+
+	/* This don't do much */
+	r = radeon_gem_init(rdev);
+	if (r)
+		return r;
+	/* Read BIOS */
+	if (!radeon_get_bios(rdev)) {
+		if (ASIC_IS_AVIVO(rdev))
+			return -EINVAL;
+	}
+	/* Must be an ATOMBIOS */
+	if (!rdev->is_atom_bios) {
+		dev_err(rdev->dev, "Expecting atombios for cayman GPU\n");
+		return -EINVAL;
+	}
+	r = radeon_atombios_init(rdev);
+	if (r)
+		return r;
+
+	/* Post card if necessary */
+	if (!radeon_card_posted(rdev)) {
+		if (!rdev->bios) {
+			dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
+			return -EINVAL;
+		}
+		DRM_INFO("GPU not posted. posting now...\n");
+		atom_asic_init(rdev->mode_info.atom_context);
+	}
+	/* Initialize scratch registers */
+	si_scratch_init(rdev);
+	/* Initialize surface registers */
+	radeon_surface_init(rdev);
+	/* Initialize clocks */
+	radeon_get_clock_info(rdev->ddev);
+
+	/* Fence driver */
+	r = radeon_fence_driver_init(rdev);
+	if (r)
+		return r;
+
+	/* initialize memory controller */
+	r = si_mc_init(rdev);
+	if (r)
+		return r;
+	/* Memory manager */
+	r = radeon_bo_init(rdev);
+	if (r)
+		return r;
+
+	r = radeon_irq_kms_init(rdev);
+	if (r)
+		return r;
+
+	ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 1024 * 1024);
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 1024 * 1024);
+
+	ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
+	ring->ring_obj = NULL;
+	r600_ring_init(rdev, ring, 1024 * 1024);
+
+	rdev->ih.ring_obj = NULL;
+	r600_ih_ring_init(rdev, 64 * 1024);
+
+	r = r600_pcie_gart_init(rdev);
+	if (r)
+		return r;
+
+	r = radeon_ib_pool_init(rdev);
+	rdev->accel_working = true;
+	if (r) {
+		dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
+		rdev->accel_working = false;
+	}
+	r = radeon_vm_manager_init(rdev);
+	if (r) {
+		dev_err(rdev->dev, "vm manager initialization failed (%d).\n", r);
+	}
+
+	r = si_startup(rdev);
+	if (r) {
+		dev_err(rdev->dev, "disabling GPU acceleration\n");
+		si_cp_fini(rdev);
+		si_irq_fini(rdev);
+		si_rlc_fini(rdev);
+		radeon_wb_fini(rdev);
+		r100_ib_fini(rdev);
+		radeon_vm_manager_fini(rdev);
+		radeon_irq_kms_fini(rdev);
+		si_pcie_gart_fini(rdev);
+		rdev->accel_working = false;
+	}
+
+	/* Don't start up if the MC ucode is missing.
+	 * The default clocks and voltages before the MC ucode
+	 * is loaded are not suffient for advanced operations.
+	 */
+	if (!rdev->mc_fw) {
+		DRM_ERROR("radeon: MC ucode required for NI+.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void si_fini(struct radeon_device *rdev)
+{
+#if 0
+	r600_blit_fini(rdev);
+#endif
+	si_cp_fini(rdev);
+	si_irq_fini(rdev);
+	si_rlc_fini(rdev);
+	radeon_wb_fini(rdev);
+	radeon_vm_manager_fini(rdev);
+	r100_ib_fini(rdev);
+	radeon_irq_kms_fini(rdev);
+	si_pcie_gart_fini(rdev);
+	r600_vram_scratch_fini(rdev);
+	radeon_gem_fini(rdev);
+	radeon_semaphore_driver_fini(rdev);
+	radeon_fence_driver_fini(rdev);
+	radeon_bo_fini(rdev);
+	radeon_atombios_fini(rdev);
+	kfree(rdev->bios);
+	rdev->bios = NULL;
+}
+
diff --git a/drivers/gpu/drm/radeon/si_blit_shaders.c b/drivers/gpu/drm/radeon/si_blit_shaders.c
new file mode 100644
index 0000000..ec415e7d
--- /dev/null
+++ b/drivers/gpu/drm/radeon/si_blit_shaders.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Alex Deucher <alexander.deucher@amd.com>
+ */
+
+#include <linux/types.h>
+#include <linux/bug.h>
+#include <linux/kernel.h>
+
+const u32 si_default_state[] =
+{
+	0xc0066900,
+	0x00000000,
+	0x00000060, /* DB_RENDER_CONTROL */
+	0x00000000, /* DB_COUNT_CONTROL */
+	0x00000000, /* DB_DEPTH_VIEW */
+	0x0000002a, /* DB_RENDER_OVERRIDE */
+	0x00000000, /* DB_RENDER_OVERRIDE2 */
+	0x00000000, /* DB_HTILE_DATA_BASE */
+
+	0xc0046900,
+	0x00000008,
+	0x00000000, /* DB_DEPTH_BOUNDS_MIN */
+	0x00000000, /* DB_DEPTH_BOUNDS_MAX */
+	0x00000000, /* DB_STENCIL_CLEAR */
+	0x00000000, /* DB_DEPTH_CLEAR */
+
+	0xc0036900,
+	0x0000000f,
+	0x00000000, /* DB_DEPTH_INFO */
+	0x00000000, /* DB_Z_INFO */
+	0x00000000, /* DB_STENCIL_INFO */
+
+	0xc0016900,
+	0x00000080,
+	0x00000000, /* PA_SC_WINDOW_OFFSET */
+
+	0xc00d6900,
+	0x00000083,
+	0x0000ffff, /* PA_SC_CLIPRECT_RULE */
+	0x00000000, /* PA_SC_CLIPRECT_0_TL */
+	0x20002000, /* PA_SC_CLIPRECT_0_BR */
+	0x00000000,
+	0x20002000,
+	0x00000000,
+	0x20002000,
+	0x00000000,
+	0x20002000,
+	0xaaaaaaaa, /* PA_SC_EDGERULE */
+	0x00000000, /* PA_SU_HARDWARE_SCREEN_OFFSET */
+	0x0000000f, /* CB_TARGET_MASK */
+	0x0000000f, /* CB_SHADER_MASK */
+
+	0xc0226900,
+	0x00000094,
+	0x80000000, /* PA_SC_VPORT_SCISSOR_0_TL */
+	0x20002000, /* PA_SC_VPORT_SCISSOR_0_BR */
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x00000000, /* PA_SC_VPORT_ZMIN_0 */
+	0x3f800000, /* PA_SC_VPORT_ZMAX_0 */
+
+	0xc0026900,
+	0x000000d9,
+	0x00000000, /* CP_RINGID */
+	0x00000000, /* CP_VMID */
+
+	0xc0046900,
+	0x00000100,
+	0xffffffff, /* VGT_MAX_VTX_INDX */
+	0x00000000, /* VGT_MIN_VTX_INDX */
+	0x00000000, /* VGT_INDX_OFFSET */
+	0x00000000, /* VGT_MULTI_PRIM_IB_RESET_INDX */
+
+	0xc0046900,
+	0x00000105,
+	0x00000000, /* CB_BLEND_RED */
+	0x00000000, /* CB_BLEND_GREEN */
+	0x00000000, /* CB_BLEND_BLUE */
+	0x00000000, /* CB_BLEND_ALPHA */
+
+	0xc0016900,
+	0x000001e0,
+	0x00000000, /* CB_BLEND0_CONTROL */
+
+	0xc00e6900,
+	0x00000200,
+	0x00000000, /* DB_DEPTH_CONTROL */
+	0x00000000, /* DB_EQAA */
+	0x00cc0010, /* CB_COLOR_CONTROL */
+	0x00000210, /* DB_SHADER_CONTROL */
+	0x00010000, /* PA_CL_CLIP_CNTL */
+	0x00000004, /* PA_SU_SC_MODE_CNTL */
+	0x00000100, /* PA_CL_VTE_CNTL */
+	0x00000000, /* PA_CL_VS_OUT_CNTL */
+	0x00000000, /* PA_CL_NANINF_CNTL */
+	0x00000000, /* PA_SU_LINE_STIPPLE_CNTL */
+	0x00000000, /* PA_SU_LINE_STIPPLE_SCALE */
+	0x00000000, /* PA_SU_PRIM_FILTER_CNTL */
+	0x00000000, /*  */
+	0x00000000, /*  */
+
+	0xc0116900,
+	0x00000280,
+	0x00000000, /* PA_SU_POINT_SIZE */
+	0x00000000, /* PA_SU_POINT_MINMAX */
+	0x00000008, /* PA_SU_LINE_CNTL */
+	0x00000000, /* PA_SC_LINE_STIPPLE */
+	0x00000000, /* VGT_OUTPUT_PATH_CNTL */
+	0x00000000, /* VGT_HOS_CNTL */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000, /* VGT_GS_MODE */
+
+	0xc0026900,
+	0x00000292,
+	0x00000000, /* PA_SC_MODE_CNTL_0 */
+	0x00000000, /* PA_SC_MODE_CNTL_1 */
+
+	0xc0016900,
+	0x000002a1,
+	0x00000000, /* VGT_PRIMITIVEID_EN */
+
+	0xc0016900,
+	0x000002a5,
+	0x00000000, /* VGT_MULTI_PRIM_IB_RESET_EN */
+
+	0xc0026900,
+	0x000002a8,
+	0x00000000, /* VGT_INSTANCE_STEP_RATE_0 */
+	0x00000000,
+
+	0xc0026900,
+	0x000002ad,
+	0x00000000, /* VGT_REUSE_OFF */
+	0x00000000,
+
+	0xc0016900,
+	0x000002d5,
+	0x00000000, /* VGT_SHADER_STAGES_EN */
+
+	0xc0016900,
+	0x000002dc,
+	0x0000aa00, /* DB_ALPHA_TO_MASK */
+
+	0xc0066900,
+	0x000002de,
+	0x00000000, /* PA_SU_POLY_OFFSET_DB_FMT_CNTL */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+
+	0xc0026900,
+	0x000002e5,
+	0x00000000, /* VGT_STRMOUT_CONFIG */
+	0x00000000,
+
+	0xc01b6900,
+	0x000002f5,
+	0x76543210, /* PA_SC_CENTROID_PRIORITY_0 */
+	0xfedcba98, /* PA_SC_CENTROID_PRIORITY_1 */
+	0x00000000, /* PA_SC_LINE_CNTL */
+	0x00000000, /* PA_SC_AA_CONFIG */
+	0x00000005, /* PA_SU_VTX_CNTL */
+	0x3f800000, /* PA_CL_GB_VERT_CLIP_ADJ */
+	0x3f800000, /* PA_CL_GB_VERT_DISC_ADJ */
+	0x3f800000, /* PA_CL_GB_HORZ_CLIP_ADJ */
+	0x3f800000, /* PA_CL_GB_HORZ_DISC_ADJ */
+	0x00000000, /* PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0 */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0xffffffff, /* PA_SC_AA_MASK_X0Y0_X1Y0 */
+	0xffffffff,
+
+	0xc0026900,
+	0x00000316,
+	0x0000000e, /* VGT_VERTEX_REUSE_BLOCK_CNTL */
+	0x00000010, /*  */
+};
+
+const u32 si_default_size = ARRAY_SIZE(si_default_state);
diff --git a/drivers/gpu/drm/radeon/si_blit_shaders.h b/drivers/gpu/drm/radeon/si_blit_shaders.h
new file mode 100644
index 0000000..c739e51
--- /dev/null
+++ b/drivers/gpu/drm/radeon/si_blit_shaders.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef SI_BLIT_SHADERS_H
+#define SI_BLIT_SHADERS_H
+
+extern const u32 si_default_state[];
+
+extern const u32 si_default_size;
+
+#endif
diff --git a/drivers/gpu/drm/radeon/si_reg.h b/drivers/gpu/drm/radeon/si_reg.h
new file mode 100644
index 0000000..eda938a
--- /dev/null
+++ b/drivers/gpu/drm/radeon/si_reg.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+#ifndef __SI_REG_H__
+#define __SI_REG_H__
+
+/* SI */
+#define SI_DC_GPIO_HPD_MASK                      0x65b0
+#define SI_DC_GPIO_HPD_A                         0x65b4
+#define SI_DC_GPIO_HPD_EN                        0x65b8
+#define SI_DC_GPIO_HPD_Y                         0x65bc
+
+#endif
diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h
new file mode 100644
index 0000000..53ea2c4
--- /dev/null
+++ b/drivers/gpu/drm/radeon/sid.h
@@ -0,0 +1,886 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+#ifndef SI_H
+#define SI_H
+
+#define	CG_MULT_THERMAL_STATUS					0x714
+#define		ASIC_MAX_TEMP(x)				((x) << 0)
+#define		ASIC_MAX_TEMP_MASK				0x000001ff
+#define		ASIC_MAX_TEMP_SHIFT				0
+#define		CTF_TEMP(x)					((x) << 9)
+#define		CTF_TEMP_MASK					0x0003fe00
+#define		CTF_TEMP_SHIFT					9
+
+#define SI_MAX_SH_GPRS           256
+#define SI_MAX_TEMP_GPRS         16
+#define SI_MAX_SH_THREADS        256
+#define SI_MAX_SH_STACK_ENTRIES  4096
+#define SI_MAX_FRC_EOV_CNT       16384
+#define SI_MAX_BACKENDS          8
+#define SI_MAX_BACKENDS_MASK     0xFF
+#define SI_MAX_BACKENDS_PER_SE_MASK     0x0F
+#define SI_MAX_SIMDS             12
+#define SI_MAX_SIMDS_MASK        0x0FFF
+#define SI_MAX_SIMDS_PER_SE_MASK        0x00FF
+#define SI_MAX_PIPES             8
+#define SI_MAX_PIPES_MASK        0xFF
+#define SI_MAX_PIPES_PER_SIMD_MASK      0x3F
+#define SI_MAX_LDS_NUM           0xFFFF
+#define SI_MAX_TCC               16
+#define SI_MAX_TCC_MASK          0xFFFF
+
+#define VGA_HDP_CONTROL  				0x328
+#define		VGA_MEMORY_DISABLE				(1 << 4)
+
+#define DMIF_ADDR_CONFIG  				0xBD4
+
+#define	SRBM_STATUS				        0xE50
+
+#define	CC_SYS_RB_BACKEND_DISABLE			0xe80
+#define	GC_USER_SYS_RB_BACKEND_DISABLE			0xe84
+
+#define VM_L2_CNTL					0x1400
+#define		ENABLE_L2_CACHE					(1 << 0)
+#define		ENABLE_L2_FRAGMENT_PROCESSING			(1 << 1)
+#define		L2_CACHE_PTE_ENDIAN_SWAP_MODE(x)		((x) << 2)
+#define		L2_CACHE_PDE_ENDIAN_SWAP_MODE(x)		((x) << 4)
+#define		ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE		(1 << 9)
+#define		ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE	(1 << 10)
+#define		EFFECTIVE_L2_QUEUE_SIZE(x)			(((x) & 7) << 15)
+#define		CONTEXT1_IDENTITY_ACCESS_MODE(x)		(((x) & 3) << 19)
+#define VM_L2_CNTL2					0x1404
+#define		INVALIDATE_ALL_L1_TLBS				(1 << 0)
+#define		INVALIDATE_L2_CACHE				(1 << 1)
+#define		INVALIDATE_CACHE_MODE(x)			((x) << 26)
+#define			INVALIDATE_PTE_AND_PDE_CACHES		0
+#define			INVALIDATE_ONLY_PTE_CACHES		1
+#define			INVALIDATE_ONLY_PDE_CACHES		2
+#define VM_L2_CNTL3					0x1408
+#define		BANK_SELECT(x)					((x) << 0)
+#define		L2_CACHE_UPDATE_MODE(x)				((x) << 6)
+#define		L2_CACHE_BIGK_FRAGMENT_SIZE(x)			((x) << 15)
+#define		L2_CACHE_BIGK_ASSOCIATIVITY			(1 << 20)
+#define	VM_L2_STATUS					0x140C
+#define		L2_BUSY						(1 << 0)
+#define VM_CONTEXT0_CNTL				0x1410
+#define		ENABLE_CONTEXT					(1 << 0)
+#define		PAGE_TABLE_DEPTH(x)				(((x) & 3) << 1)
+#define		RANGE_PROTECTION_FAULT_ENABLE_DEFAULT		(1 << 4)
+#define VM_CONTEXT1_CNTL				0x1414
+#define VM_CONTEXT0_CNTL2				0x1430
+#define VM_CONTEXT1_CNTL2				0x1434
+#define	VM_CONTEXT8_PAGE_TABLE_BASE_ADDR		0x1438
+#define	VM_CONTEXT9_PAGE_TABLE_BASE_ADDR		0x143c
+#define	VM_CONTEXT10_PAGE_TABLE_BASE_ADDR		0x1440
+#define	VM_CONTEXT11_PAGE_TABLE_BASE_ADDR		0x1444
+#define	VM_CONTEXT12_PAGE_TABLE_BASE_ADDR		0x1448
+#define	VM_CONTEXT13_PAGE_TABLE_BASE_ADDR		0x144c
+#define	VM_CONTEXT14_PAGE_TABLE_BASE_ADDR		0x1450
+#define	VM_CONTEXT15_PAGE_TABLE_BASE_ADDR		0x1454
+
+#define VM_INVALIDATE_REQUEST				0x1478
+#define VM_INVALIDATE_RESPONSE				0x147c
+
+#define VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR	0x1518
+#define VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR	0x151c
+
+#define	VM_CONTEXT0_PAGE_TABLE_BASE_ADDR		0x153c
+#define	VM_CONTEXT1_PAGE_TABLE_BASE_ADDR		0x1540
+#define	VM_CONTEXT2_PAGE_TABLE_BASE_ADDR		0x1544
+#define	VM_CONTEXT3_PAGE_TABLE_BASE_ADDR		0x1548
+#define	VM_CONTEXT4_PAGE_TABLE_BASE_ADDR		0x154c
+#define	VM_CONTEXT5_PAGE_TABLE_BASE_ADDR		0x1550
+#define	VM_CONTEXT6_PAGE_TABLE_BASE_ADDR		0x1554
+#define	VM_CONTEXT7_PAGE_TABLE_BASE_ADDR		0x1558
+#define	VM_CONTEXT0_PAGE_TABLE_START_ADDR		0x155c
+#define	VM_CONTEXT1_PAGE_TABLE_START_ADDR		0x1560
+
+#define	VM_CONTEXT0_PAGE_TABLE_END_ADDR			0x157C
+#define	VM_CONTEXT1_PAGE_TABLE_END_ADDR			0x1580
+
+#define MC_SHARED_CHMAP						0x2004
+#define		NOOFCHAN_SHIFT					12
+#define		NOOFCHAN_MASK					0x0000f000
+#define MC_SHARED_CHREMAP					0x2008
+
+#define	MC_VM_FB_LOCATION				0x2024
+#define	MC_VM_AGP_TOP					0x2028
+#define	MC_VM_AGP_BOT					0x202C
+#define	MC_VM_AGP_BASE					0x2030
+#define	MC_VM_SYSTEM_APERTURE_LOW_ADDR			0x2034
+#define	MC_VM_SYSTEM_APERTURE_HIGH_ADDR			0x2038
+#define	MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR		0x203C
+
+#define	MC_VM_MX_L1_TLB_CNTL				0x2064
+#define		ENABLE_L1_TLB					(1 << 0)
+#define		ENABLE_L1_FRAGMENT_PROCESSING			(1 << 1)
+#define		SYSTEM_ACCESS_MODE_PA_ONLY			(0 << 3)
+#define		SYSTEM_ACCESS_MODE_USE_SYS_MAP			(1 << 3)
+#define		SYSTEM_ACCESS_MODE_IN_SYS			(2 << 3)
+#define		SYSTEM_ACCESS_MODE_NOT_IN_SYS			(3 << 3)
+#define		SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU	(0 << 5)
+#define		ENABLE_ADVANCED_DRIVER_MODEL			(1 << 6)
+
+#define MC_SHARED_BLACKOUT_CNTL           		0x20ac
+
+#define	MC_ARB_RAMCFG					0x2760
+#define		NOOFBANK_SHIFT					0
+#define		NOOFBANK_MASK					0x00000003
+#define		NOOFRANK_SHIFT					2
+#define		NOOFRANK_MASK					0x00000004
+#define		NOOFROWS_SHIFT					3
+#define		NOOFROWS_MASK					0x00000038
+#define		NOOFCOLS_SHIFT					6
+#define		NOOFCOLS_MASK					0x000000C0
+#define		CHANSIZE_SHIFT					8
+#define		CHANSIZE_MASK					0x00000100
+#define		CHANSIZE_OVERRIDE				(1 << 11)
+#define		NOOFGROUPS_SHIFT				12
+#define		NOOFGROUPS_MASK					0x00001000
+
+#define	MC_SEQ_TRAIN_WAKEUP_CNTL			0x2808
+#define		TRAIN_DONE_D0      			(1 << 30)
+#define		TRAIN_DONE_D1      			(1 << 31)
+
+#define MC_SEQ_SUP_CNTL           			0x28c8
+#define		RUN_MASK      				(1 << 0)
+#define MC_SEQ_SUP_PGM           			0x28cc
+
+#define MC_IO_PAD_CNTL_D0           			0x29d0
+#define		MEM_FALL_OUT_CMD      			(1 << 8)
+
+#define MC_SEQ_IO_DEBUG_INDEX           		0x2a44
+#define MC_SEQ_IO_DEBUG_DATA           			0x2a48
+
+#define	HDP_HOST_PATH_CNTL				0x2C00
+#define	HDP_NONSURFACE_BASE				0x2C04
+#define	HDP_NONSURFACE_INFO				0x2C08
+#define	HDP_NONSURFACE_SIZE				0x2C0C
+
+#define HDP_ADDR_CONFIG  				0x2F48
+#define HDP_MISC_CNTL					0x2F4C
+#define 	HDP_FLUSH_INVALIDATE_CACHE			(1 << 0)
+
+#define IH_RB_CNTL                                        0x3e00
+#       define IH_RB_ENABLE                               (1 << 0)
+#       define IH_IB_SIZE(x)                              ((x) << 1) /* log2 */
+#       define IH_RB_FULL_DRAIN_ENABLE                    (1 << 6)
+#       define IH_WPTR_WRITEBACK_ENABLE                   (1 << 8)
+#       define IH_WPTR_WRITEBACK_TIMER(x)                 ((x) << 9) /* log2 */
+#       define IH_WPTR_OVERFLOW_ENABLE                    (1 << 16)
+#       define IH_WPTR_OVERFLOW_CLEAR                     (1 << 31)
+#define IH_RB_BASE                                        0x3e04
+#define IH_RB_RPTR                                        0x3e08
+#define IH_RB_WPTR                                        0x3e0c
+#       define RB_OVERFLOW                                (1 << 0)
+#       define WPTR_OFFSET_MASK                           0x3fffc
+#define IH_RB_WPTR_ADDR_HI                                0x3e10
+#define IH_RB_WPTR_ADDR_LO                                0x3e14
+#define IH_CNTL                                           0x3e18
+#       define ENABLE_INTR                                (1 << 0)
+#       define IH_MC_SWAP(x)                              ((x) << 1)
+#       define IH_MC_SWAP_NONE                            0
+#       define IH_MC_SWAP_16BIT                           1
+#       define IH_MC_SWAP_32BIT                           2
+#       define IH_MC_SWAP_64BIT                           3
+#       define RPTR_REARM                                 (1 << 4)
+#       define MC_WRREQ_CREDIT(x)                         ((x) << 15)
+#       define MC_WR_CLEAN_CNT(x)                         ((x) << 20)
+#       define MC_VMID(x)                                 ((x) << 25)
+
+#define	CONFIG_MEMSIZE					0x5428
+
+#define INTERRUPT_CNTL                                    0x5468
+#       define IH_DUMMY_RD_OVERRIDE                       (1 << 0)
+#       define IH_DUMMY_RD_EN                             (1 << 1)
+#       define IH_REQ_NONSNOOP_EN                         (1 << 3)
+#       define GEN_IH_INT_EN                              (1 << 8)
+#define INTERRUPT_CNTL2                                   0x546c
+
+#define HDP_MEM_COHERENCY_FLUSH_CNTL			0x5480
+
+#define	BIF_FB_EN						0x5490
+#define		FB_READ_EN					(1 << 0)
+#define		FB_WRITE_EN					(1 << 1)
+
+#define HDP_REG_COHERENCY_FLUSH_CNTL			0x54A0
+
+#define	DC_LB_MEMORY_SPLIT					0x6b0c
+#define		DC_LB_MEMORY_CONFIG(x)				((x) << 20)
+
+#define	PRIORITY_A_CNT						0x6b18
+#define		PRIORITY_MARK_MASK				0x7fff
+#define		PRIORITY_OFF					(1 << 16)
+#define		PRIORITY_ALWAYS_ON				(1 << 20)
+#define	PRIORITY_B_CNT						0x6b1c
+
+#define	DPG_PIPE_ARBITRATION_CONTROL3				0x6cc8
+#       define LATENCY_WATERMARK_MASK(x)			((x) << 16)
+#define	DPG_PIPE_LATENCY_CONTROL				0x6ccc
+#       define LATENCY_LOW_WATERMARK(x)				((x) << 0)
+#       define LATENCY_HIGH_WATERMARK(x)			((x) << 16)
+
+/* 0x6bb8, 0x77b8, 0x103b8, 0x10fb8, 0x11bb8, 0x127b8 */
+#define VLINE_STATUS                                    0x6bb8
+#       define VLINE_OCCURRED                           (1 << 0)
+#       define VLINE_ACK                                (1 << 4)
+#       define VLINE_STAT                               (1 << 12)
+#       define VLINE_INTERRUPT                          (1 << 16)
+#       define VLINE_INTERRUPT_TYPE                     (1 << 17)
+/* 0x6bbc, 0x77bc, 0x103bc, 0x10fbc, 0x11bbc, 0x127bc */
+#define VBLANK_STATUS                                   0x6bbc
+#       define VBLANK_OCCURRED                          (1 << 0)
+#       define VBLANK_ACK                               (1 << 4)
+#       define VBLANK_STAT                              (1 << 12)
+#       define VBLANK_INTERRUPT                         (1 << 16)
+#       define VBLANK_INTERRUPT_TYPE                    (1 << 17)
+
+/* 0x6b40, 0x7740, 0x10340, 0x10f40, 0x11b40, 0x12740 */
+#define INT_MASK                                        0x6b40
+#       define VBLANK_INT_MASK                          (1 << 0)
+#       define VLINE_INT_MASK                           (1 << 4)
+
+#define DISP_INTERRUPT_STATUS                           0x60f4
+#       define LB_D1_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D1_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD1_INTERRUPT                        (1 << 17)
+#       define DC_HPD1_RX_INTERRUPT                     (1 << 18)
+#       define DACA_AUTODETECT_INTERRUPT                (1 << 22)
+#       define DACB_AUTODETECT_INTERRUPT                (1 << 23)
+#       define DC_I2C_SW_DONE_INTERRUPT                 (1 << 24)
+#       define DC_I2C_HW_DONE_INTERRUPT                 (1 << 25)
+#define DISP_INTERRUPT_STATUS_CONTINUE                  0x60f8
+#       define LB_D2_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D2_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD2_INTERRUPT                        (1 << 17)
+#       define DC_HPD2_RX_INTERRUPT                     (1 << 18)
+#       define DISP_TIMER_INTERRUPT                     (1 << 24)
+#define DISP_INTERRUPT_STATUS_CONTINUE2                 0x60fc
+#       define LB_D3_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D3_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD3_INTERRUPT                        (1 << 17)
+#       define DC_HPD3_RX_INTERRUPT                     (1 << 18)
+#define DISP_INTERRUPT_STATUS_CONTINUE3                 0x6100
+#       define LB_D4_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D4_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD4_INTERRUPT                        (1 << 17)
+#       define DC_HPD4_RX_INTERRUPT                     (1 << 18)
+#define DISP_INTERRUPT_STATUS_CONTINUE4                 0x614c
+#       define LB_D5_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D5_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD5_INTERRUPT                        (1 << 17)
+#       define DC_HPD5_RX_INTERRUPT                     (1 << 18)
+#define DISP_INTERRUPT_STATUS_CONTINUE5                 0x6150
+#       define LB_D6_VLINE_INTERRUPT                    (1 << 2)
+#       define LB_D6_VBLANK_INTERRUPT                   (1 << 3)
+#       define DC_HPD6_INTERRUPT                        (1 << 17)
+#       define DC_HPD6_RX_INTERRUPT                     (1 << 18)
+
+/* 0x6858, 0x7458, 0x10058, 0x10c58, 0x11858, 0x12458 */
+#define GRPH_INT_STATUS                                 0x6858
+#       define GRPH_PFLIP_INT_OCCURRED                  (1 << 0)
+#       define GRPH_PFLIP_INT_CLEAR                     (1 << 8)
+/* 0x685c, 0x745c, 0x1005c, 0x10c5c, 0x1185c, 0x1245c */
+#define	GRPH_INT_CONTROL			        0x685c
+#       define GRPH_PFLIP_INT_MASK                      (1 << 0)
+#       define GRPH_PFLIP_INT_TYPE                      (1 << 8)
+
+#define	DACA_AUTODETECT_INT_CONTROL			0x66c8
+
+#define DC_HPD1_INT_STATUS                              0x601c
+#define DC_HPD2_INT_STATUS                              0x6028
+#define DC_HPD3_INT_STATUS                              0x6034
+#define DC_HPD4_INT_STATUS                              0x6040
+#define DC_HPD5_INT_STATUS                              0x604c
+#define DC_HPD6_INT_STATUS                              0x6058
+#       define DC_HPDx_INT_STATUS                       (1 << 0)
+#       define DC_HPDx_SENSE                            (1 << 1)
+#       define DC_HPDx_RX_INT_STATUS                    (1 << 8)
+
+#define DC_HPD1_INT_CONTROL                             0x6020
+#define DC_HPD2_INT_CONTROL                             0x602c
+#define DC_HPD3_INT_CONTROL                             0x6038
+#define DC_HPD4_INT_CONTROL                             0x6044
+#define DC_HPD5_INT_CONTROL                             0x6050
+#define DC_HPD6_INT_CONTROL                             0x605c
+#       define DC_HPDx_INT_ACK                          (1 << 0)
+#       define DC_HPDx_INT_POLARITY                     (1 << 8)
+#       define DC_HPDx_INT_EN                           (1 << 16)
+#       define DC_HPDx_RX_INT_ACK                       (1 << 20)
+#       define DC_HPDx_RX_INT_EN                        (1 << 24)
+
+#define DC_HPD1_CONTROL                                   0x6024
+#define DC_HPD2_CONTROL                                   0x6030
+#define DC_HPD3_CONTROL                                   0x603c
+#define DC_HPD4_CONTROL                                   0x6048
+#define DC_HPD5_CONTROL                                   0x6054
+#define DC_HPD6_CONTROL                                   0x6060
+#       define DC_HPDx_CONNECTION_TIMER(x)                ((x) << 0)
+#       define DC_HPDx_RX_INT_TIMER(x)                    ((x) << 16)
+#       define DC_HPDx_EN                                 (1 << 28)
+
+/* 0x6e98, 0x7a98, 0x10698, 0x11298, 0x11e98, 0x12a98 */
+#define CRTC_STATUS_FRAME_COUNT                         0x6e98
+
+#define	GRBM_CNTL					0x8000
+#define		GRBM_READ_TIMEOUT(x)				((x) << 0)
+
+#define	GRBM_STATUS2					0x8008
+#define		RLC_RQ_PENDING 					(1 << 0)
+#define		RLC_BUSY 					(1 << 8)
+#define		TC_BUSY 					(1 << 9)
+
+#define	GRBM_STATUS					0x8010
+#define		CMDFIFO_AVAIL_MASK				0x0000000F
+#define		RING2_RQ_PENDING				(1 << 4)
+#define		SRBM_RQ_PENDING					(1 << 5)
+#define		RING1_RQ_PENDING				(1 << 6)
+#define		CF_RQ_PENDING					(1 << 7)
+#define		PF_RQ_PENDING					(1 << 8)
+#define		GDS_DMA_RQ_PENDING				(1 << 9)
+#define		GRBM_EE_BUSY					(1 << 10)
+#define		DB_CLEAN					(1 << 12)
+#define		CB_CLEAN					(1 << 13)
+#define		TA_BUSY 					(1 << 14)
+#define		GDS_BUSY 					(1 << 15)
+#define		VGT_BUSY					(1 << 17)
+#define		IA_BUSY_NO_DMA					(1 << 18)
+#define		IA_BUSY						(1 << 19)
+#define		SX_BUSY 					(1 << 20)
+#define		SPI_BUSY					(1 << 22)
+#define		BCI_BUSY					(1 << 23)
+#define		SC_BUSY 					(1 << 24)
+#define		PA_BUSY 					(1 << 25)
+#define		DB_BUSY 					(1 << 26)
+#define		CP_COHERENCY_BUSY      				(1 << 28)
+#define		CP_BUSY 					(1 << 29)
+#define		CB_BUSY 					(1 << 30)
+#define		GUI_ACTIVE					(1 << 31)
+#define	GRBM_STATUS_SE0					0x8014
+#define	GRBM_STATUS_SE1					0x8018
+#define		SE_DB_CLEAN					(1 << 1)
+#define		SE_CB_CLEAN					(1 << 2)
+#define		SE_BCI_BUSY					(1 << 22)
+#define		SE_VGT_BUSY					(1 << 23)
+#define		SE_PA_BUSY					(1 << 24)
+#define		SE_TA_BUSY					(1 << 25)
+#define		SE_SX_BUSY					(1 << 26)
+#define		SE_SPI_BUSY					(1 << 27)
+#define		SE_SC_BUSY					(1 << 29)
+#define		SE_DB_BUSY					(1 << 30)
+#define		SE_CB_BUSY					(1 << 31)
+
+#define	GRBM_SOFT_RESET					0x8020
+#define		SOFT_RESET_CP					(1 << 0)
+#define		SOFT_RESET_CB					(1 << 1)
+#define		SOFT_RESET_RLC					(1 << 2)
+#define		SOFT_RESET_DB					(1 << 3)
+#define		SOFT_RESET_GDS					(1 << 4)
+#define		SOFT_RESET_PA					(1 << 5)
+#define		SOFT_RESET_SC					(1 << 6)
+#define		SOFT_RESET_BCI					(1 << 7)
+#define		SOFT_RESET_SPI					(1 << 8)
+#define		SOFT_RESET_SX					(1 << 10)
+#define		SOFT_RESET_TC					(1 << 11)
+#define		SOFT_RESET_TA					(1 << 12)
+#define		SOFT_RESET_VGT					(1 << 14)
+#define		SOFT_RESET_IA					(1 << 15)
+
+#define GRBM_GFX_INDEX          			0x802C
+
+#define GRBM_INT_CNTL                                   0x8060
+#       define RDERR_INT_ENABLE                         (1 << 0)
+#       define GUI_IDLE_INT_ENABLE                      (1 << 19)
+
+#define	SCRATCH_REG0					0x8500
+#define	SCRATCH_REG1					0x8504
+#define	SCRATCH_REG2					0x8508
+#define	SCRATCH_REG3					0x850C
+#define	SCRATCH_REG4					0x8510
+#define	SCRATCH_REG5					0x8514
+#define	SCRATCH_REG6					0x8518
+#define	SCRATCH_REG7					0x851C
+
+#define	SCRATCH_UMSK					0x8540
+#define	SCRATCH_ADDR					0x8544
+
+#define	CP_SEM_WAIT_TIMER				0x85BC
+
+#define	CP_SEM_INCOMPLETE_TIMER_CNTL			0x85C8
+
+#define CP_ME_CNTL					0x86D8
+#define		CP_CE_HALT					(1 << 24)
+#define		CP_PFP_HALT					(1 << 26)
+#define		CP_ME_HALT					(1 << 28)
+
+#define	CP_COHER_CNTL2					0x85E8
+
+#define	CP_RB2_RPTR					0x86f8
+#define	CP_RB1_RPTR					0x86fc
+#define	CP_RB0_RPTR					0x8700
+#define	CP_RB_WPTR_DELAY				0x8704
+
+#define	CP_QUEUE_THRESHOLDS				0x8760
+#define		ROQ_IB1_START(x)				((x) << 0)
+#define		ROQ_IB2_START(x)				((x) << 8)
+#define CP_MEQ_THRESHOLDS				0x8764
+#define		MEQ1_START(x)				((x) << 0)
+#define		MEQ2_START(x)				((x) << 8)
+
+#define	CP_PERFMON_CNTL					0x87FC
+
+#define	VGT_VTX_VECT_EJECT_REG				0x88B0
+
+#define	VGT_CACHE_INVALIDATION				0x88C4
+#define		CACHE_INVALIDATION(x)				((x) << 0)
+#define			VC_ONLY						0
+#define			TC_ONLY						1
+#define			VC_AND_TC					2
+#define		AUTO_INVLD_EN(x)				((x) << 6)
+#define			NO_AUTO						0
+#define			ES_AUTO						1
+#define			GS_AUTO						2
+#define			ES_AND_GS_AUTO					3
+#define	VGT_ESGS_RING_SIZE				0x88C8
+#define	VGT_GSVS_RING_SIZE				0x88CC
+
+#define	VGT_GS_VERTEX_REUSE				0x88D4
+
+#define	VGT_PRIMITIVE_TYPE				0x8958
+#define	VGT_INDEX_TYPE					0x895C
+
+#define	VGT_NUM_INDICES					0x8970
+#define	VGT_NUM_INSTANCES				0x8974
+
+#define	VGT_TF_RING_SIZE				0x8988
+
+#define	VGT_HS_OFFCHIP_PARAM				0x89B0
+
+#define	VGT_TF_MEMORY_BASE				0x89B8
+
+#define CC_GC_SHADER_ARRAY_CONFIG			0x89bc
+#define GC_USER_SHADER_ARRAY_CONFIG			0x89c0
+
+#define	PA_CL_ENHANCE					0x8A14
+#define		CLIP_VTX_REORDER_ENA				(1 << 0)
+#define		NUM_CLIP_SEQ(x)					((x) << 1)
+
+#define	PA_SU_LINE_STIPPLE_VALUE			0x8A60
+
+#define	PA_SC_LINE_STIPPLE_STATE			0x8B10
+
+#define	PA_SC_FORCE_EOV_MAX_CNTS			0x8B24
+#define		FORCE_EOV_MAX_CLK_CNT(x)			((x) << 0)
+#define		FORCE_EOV_MAX_REZ_CNT(x)			((x) << 16)
+
+#define	PA_SC_FIFO_SIZE					0x8BCC
+#define		SC_FRONTEND_PRIM_FIFO_SIZE(x)			((x) << 0)
+#define		SC_BACKEND_PRIM_FIFO_SIZE(x)			((x) << 6)
+#define		SC_HIZ_TILE_FIFO_SIZE(x)			((x) << 15)
+#define		SC_EARLYZ_TILE_FIFO_SIZE(x)			((x) << 23)
+
+#define	PA_SC_ENHANCE					0x8BF0
+
+#define	SQ_CONFIG					0x8C00
+
+#define	SQC_CACHES					0x8C08
+
+#define	SX_DEBUG_1					0x9060
+
+#define	SPI_STATIC_THREAD_MGMT_1			0x90E0
+#define	SPI_STATIC_THREAD_MGMT_2			0x90E4
+#define	SPI_STATIC_THREAD_MGMT_3			0x90E8
+#define	SPI_PS_MAX_WAVE_ID				0x90EC
+
+#define	SPI_CONFIG_CNTL					0x9100
+
+#define	SPI_CONFIG_CNTL_1				0x913C
+#define		VTX_DONE_DELAY(x)				((x) << 0)
+#define		INTERP_ONE_PRIM_PER_ROW				(1 << 4)
+
+#define	CGTS_TCC_DISABLE				0x9148
+#define	CGTS_USER_TCC_DISABLE				0x914C
+#define		TCC_DISABLE_MASK				0xFFFF0000
+#define		TCC_DISABLE_SHIFT				16
+
+#define	TA_CNTL_AUX					0x9508
+
+#define CC_RB_BACKEND_DISABLE				0x98F4
+#define		BACKEND_DISABLE(x)     			((x) << 16)
+#define GB_ADDR_CONFIG  				0x98F8
+#define		NUM_PIPES(x)				((x) << 0)
+#define		NUM_PIPES_MASK				0x00000007
+#define		NUM_PIPES_SHIFT				0
+#define		PIPE_INTERLEAVE_SIZE(x)			((x) << 4)
+#define		PIPE_INTERLEAVE_SIZE_MASK		0x00000070
+#define		PIPE_INTERLEAVE_SIZE_SHIFT		4
+#define		NUM_SHADER_ENGINES(x)			((x) << 12)
+#define		NUM_SHADER_ENGINES_MASK			0x00003000
+#define		NUM_SHADER_ENGINES_SHIFT		12
+#define		SHADER_ENGINE_TILE_SIZE(x)     		((x) << 16)
+#define		SHADER_ENGINE_TILE_SIZE_MASK		0x00070000
+#define		SHADER_ENGINE_TILE_SIZE_SHIFT		16
+#define		NUM_GPUS(x)     			((x) << 20)
+#define		NUM_GPUS_MASK				0x00700000
+#define		NUM_GPUS_SHIFT				20
+#define		MULTI_GPU_TILE_SIZE(x)     		((x) << 24)
+#define		MULTI_GPU_TILE_SIZE_MASK		0x03000000
+#define		MULTI_GPU_TILE_SIZE_SHIFT		24
+#define		ROW_SIZE(x)             		((x) << 28)
+#define		ROW_SIZE_MASK				0x30000000
+#define		ROW_SIZE_SHIFT				28
+
+#define	GB_TILE_MODE0					0x9910
+#       define MICRO_TILE_MODE(x)				((x) << 0)
+#              define	ADDR_SURF_DISPLAY_MICRO_TILING		0
+#              define	ADDR_SURF_THIN_MICRO_TILING		1
+#              define	ADDR_SURF_DEPTH_MICRO_TILING		2
+#       define ARRAY_MODE(x)					((x) << 2)
+#              define	ARRAY_LINEAR_GENERAL			0
+#              define	ARRAY_LINEAR_ALIGNED			1
+#              define	ARRAY_1D_TILED_THIN1			2
+#              define	ARRAY_2D_TILED_THIN1			4
+#       define PIPE_CONFIG(x)					((x) << 6)
+#              define	ADDR_SURF_P2				0
+#              define	ADDR_SURF_P4_8x16			4
+#              define	ADDR_SURF_P4_16x16			5
+#              define	ADDR_SURF_P4_16x32			6
+#              define	ADDR_SURF_P4_32x32			7
+#              define	ADDR_SURF_P8_16x16_8x16			8
+#              define	ADDR_SURF_P8_16x32_8x16			9
+#              define	ADDR_SURF_P8_32x32_8x16			10
+#              define	ADDR_SURF_P8_16x32_16x16		11
+#              define	ADDR_SURF_P8_32x32_16x16		12
+#              define	ADDR_SURF_P8_32x32_16x32		13
+#              define	ADDR_SURF_P8_32x64_32x32		14
+#       define TILE_SPLIT(x)					((x) << 11)
+#              define	ADDR_SURF_TILE_SPLIT_64B		0
+#              define	ADDR_SURF_TILE_SPLIT_128B		1
+#              define	ADDR_SURF_TILE_SPLIT_256B		2
+#              define	ADDR_SURF_TILE_SPLIT_512B		3
+#              define	ADDR_SURF_TILE_SPLIT_1KB		4
+#              define	ADDR_SURF_TILE_SPLIT_2KB		5
+#              define	ADDR_SURF_TILE_SPLIT_4KB		6
+#       define BANK_WIDTH(x)					((x) << 14)
+#              define	ADDR_SURF_BANK_WIDTH_1			0
+#              define	ADDR_SURF_BANK_WIDTH_2			1
+#              define	ADDR_SURF_BANK_WIDTH_4			2
+#              define	ADDR_SURF_BANK_WIDTH_8			3
+#       define BANK_HEIGHT(x)					((x) << 16)
+#              define	ADDR_SURF_BANK_HEIGHT_1			0
+#              define	ADDR_SURF_BANK_HEIGHT_2			1
+#              define	ADDR_SURF_BANK_HEIGHT_4			2
+#              define	ADDR_SURF_BANK_HEIGHT_8			3
+#       define MACRO_TILE_ASPECT(x)				((x) << 18)
+#              define	ADDR_SURF_MACRO_ASPECT_1		0
+#              define	ADDR_SURF_MACRO_ASPECT_2		1
+#              define	ADDR_SURF_MACRO_ASPECT_4		2
+#              define	ADDR_SURF_MACRO_ASPECT_8		3
+#       define NUM_BANKS(x)					((x) << 20)
+#              define	ADDR_SURF_2_BANK			0
+#              define	ADDR_SURF_4_BANK			1
+#              define	ADDR_SURF_8_BANK			2
+#              define	ADDR_SURF_16_BANK			3
+
+#define	CB_PERFCOUNTER0_SELECT0				0x9a20
+#define	CB_PERFCOUNTER0_SELECT1				0x9a24
+#define	CB_PERFCOUNTER1_SELECT0				0x9a28
+#define	CB_PERFCOUNTER1_SELECT1				0x9a2c
+#define	CB_PERFCOUNTER2_SELECT0				0x9a30
+#define	CB_PERFCOUNTER2_SELECT1				0x9a34
+#define	CB_PERFCOUNTER3_SELECT0				0x9a38
+#define	CB_PERFCOUNTER3_SELECT1				0x9a3c
+
+#define	GC_USER_RB_BACKEND_DISABLE			0x9B7C
+#define		BACKEND_DISABLE_MASK			0x00FF0000
+#define		BACKEND_DISABLE_SHIFT			16
+
+#define	TCP_CHAN_STEER_LO				0xac0c
+#define	TCP_CHAN_STEER_HI				0xac10
+
+#define	CP_RB0_BASE					0xC100
+#define	CP_RB0_CNTL					0xC104
+#define		RB_BUFSZ(x)					((x) << 0)
+#define		RB_BLKSZ(x)					((x) << 8)
+#define		BUF_SWAP_32BIT					(2 << 16)
+#define		RB_NO_UPDATE					(1 << 27)
+#define		RB_RPTR_WR_ENA					(1 << 31)
+
+#define	CP_RB0_RPTR_ADDR				0xC10C
+#define	CP_RB0_RPTR_ADDR_HI				0xC110
+#define	CP_RB0_WPTR					0xC114
+
+#define	CP_PFP_UCODE_ADDR				0xC150
+#define	CP_PFP_UCODE_DATA				0xC154
+#define	CP_ME_RAM_RADDR					0xC158
+#define	CP_ME_RAM_WADDR					0xC15C
+#define	CP_ME_RAM_DATA					0xC160
+
+#define	CP_CE_UCODE_ADDR				0xC168
+#define	CP_CE_UCODE_DATA				0xC16C
+
+#define	CP_RB1_BASE					0xC180
+#define	CP_RB1_CNTL					0xC184
+#define	CP_RB1_RPTR_ADDR				0xC188
+#define	CP_RB1_RPTR_ADDR_HI				0xC18C
+#define	CP_RB1_WPTR					0xC190
+#define	CP_RB2_BASE					0xC194
+#define	CP_RB2_CNTL					0xC198
+#define	CP_RB2_RPTR_ADDR				0xC19C
+#define	CP_RB2_RPTR_ADDR_HI				0xC1A0
+#define	CP_RB2_WPTR					0xC1A4
+#define CP_INT_CNTL_RING0                               0xC1A8
+#define CP_INT_CNTL_RING1                               0xC1AC
+#define CP_INT_CNTL_RING2                               0xC1B0
+#       define CNTX_BUSY_INT_ENABLE                     (1 << 19)
+#       define CNTX_EMPTY_INT_ENABLE                    (1 << 20)
+#       define WAIT_MEM_SEM_INT_ENABLE                  (1 << 21)
+#       define TIME_STAMP_INT_ENABLE                    (1 << 26)
+#       define CP_RINGID2_INT_ENABLE                    (1 << 29)
+#       define CP_RINGID1_INT_ENABLE                    (1 << 30)
+#       define CP_RINGID0_INT_ENABLE                    (1 << 31)
+#define CP_INT_STATUS_RING0                             0xC1B4
+#define CP_INT_STATUS_RING1                             0xC1B8
+#define CP_INT_STATUS_RING2                             0xC1BC
+#       define WAIT_MEM_SEM_INT_STAT                    (1 << 21)
+#       define TIME_STAMP_INT_STAT                      (1 << 26)
+#       define CP_RINGID2_INT_STAT                      (1 << 29)
+#       define CP_RINGID1_INT_STAT                      (1 << 30)
+#       define CP_RINGID0_INT_STAT                      (1 << 31)
+
+#define	CP_DEBUG					0xC1FC
+
+#define RLC_CNTL                                          0xC300
+#       define RLC_ENABLE                                 (1 << 0)
+#define RLC_RL_BASE                                       0xC304
+#define RLC_RL_SIZE                                       0xC308
+#define RLC_LB_CNTL                                       0xC30C
+#define RLC_SAVE_AND_RESTORE_BASE                         0xC310
+#define RLC_LB_CNTR_MAX                                   0xC314
+#define RLC_LB_CNTR_INIT                                  0xC318
+
+#define RLC_CLEAR_STATE_RESTORE_BASE                      0xC320
+
+#define RLC_UCODE_ADDR                                    0xC32C
+#define RLC_UCODE_DATA                                    0xC330
+
+#define RLC_MC_CNTL                                       0xC344
+#define RLC_UCODE_CNTL                                    0xC348
+
+#define VGT_EVENT_INITIATOR                             0x28a90
+#       define SAMPLE_STREAMOUTSTATS1                   (1 << 0)
+#       define SAMPLE_STREAMOUTSTATS2                   (2 << 0)
+#       define SAMPLE_STREAMOUTSTATS3                   (3 << 0)
+#       define CACHE_FLUSH_TS                           (4 << 0)
+#       define CACHE_FLUSH                              (6 << 0)
+#       define CS_PARTIAL_FLUSH                         (7 << 0)
+#       define VGT_STREAMOUT_RESET                      (10 << 0)
+#       define END_OF_PIPE_INCR_DE                      (11 << 0)
+#       define END_OF_PIPE_IB_END                       (12 << 0)
+#       define RST_PIX_CNT                              (13 << 0)
+#       define VS_PARTIAL_FLUSH                         (15 << 0)
+#       define PS_PARTIAL_FLUSH                         (16 << 0)
+#       define CACHE_FLUSH_AND_INV_TS_EVENT             (20 << 0)
+#       define ZPASS_DONE                               (21 << 0)
+#       define CACHE_FLUSH_AND_INV_EVENT                (22 << 0)
+#       define PERFCOUNTER_START                        (23 << 0)
+#       define PERFCOUNTER_STOP                         (24 << 0)
+#       define PIPELINESTAT_START                       (25 << 0)
+#       define PIPELINESTAT_STOP                        (26 << 0)
+#       define PERFCOUNTER_SAMPLE                       (27 << 0)
+#       define SAMPLE_PIPELINESTAT                      (30 << 0)
+#       define SAMPLE_STREAMOUTSTATS                    (32 << 0)
+#       define RESET_VTX_CNT                            (33 << 0)
+#       define VGT_FLUSH                                (36 << 0)
+#       define BOTTOM_OF_PIPE_TS                        (40 << 0)
+#       define DB_CACHE_FLUSH_AND_INV                   (42 << 0)
+#       define FLUSH_AND_INV_DB_DATA_TS                 (43 << 0)
+#       define FLUSH_AND_INV_DB_META                    (44 << 0)
+#       define FLUSH_AND_INV_CB_DATA_TS                 (45 << 0)
+#       define FLUSH_AND_INV_CB_META                    (46 << 0)
+#       define CS_DONE                                  (47 << 0)
+#       define PS_DONE                                  (48 << 0)
+#       define FLUSH_AND_INV_CB_PIXEL_DATA              (49 << 0)
+#       define THREAD_TRACE_START                       (51 << 0)
+#       define THREAD_TRACE_STOP                        (52 << 0)
+#       define THREAD_TRACE_FLUSH                       (54 << 0)
+#       define THREAD_TRACE_FINISH                      (55 << 0)
+
+/*
+ * PM4
+ */
+#define	PACKET_TYPE0	0
+#define	PACKET_TYPE1	1
+#define	PACKET_TYPE2	2
+#define	PACKET_TYPE3	3
+
+#define CP_PACKET_GET_TYPE(h) (((h) >> 30) & 3)
+#define CP_PACKET_GET_COUNT(h) (((h) >> 16) & 0x3FFF)
+#define CP_PACKET0_GET_REG(h) (((h) & 0xFFFF) << 2)
+#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF)
+#define PACKET0(reg, n)	((PACKET_TYPE0 << 30) |				\
+			 (((reg) >> 2) & 0xFFFF) |			\
+			 ((n) & 0x3FFF) << 16)
+#define CP_PACKET2			0x80000000
+#define		PACKET2_PAD_SHIFT		0
+#define		PACKET2_PAD_MASK		(0x3fffffff << 0)
+
+#define PACKET2(v)	(CP_PACKET2 | REG_SET(PACKET2_PAD, (v)))
+
+#define PACKET3(op, n)	((PACKET_TYPE3 << 30) |				\
+			 (((op) & 0xFF) << 8) |				\
+			 ((n) & 0x3FFF) << 16)
+
+#define PACKET3_COMPUTE(op, n) (PACKET3(op, n) | 1 << 1)
+
+/* Packet 3 types */
+#define	PACKET3_NOP					0x10
+#define	PACKET3_SET_BASE				0x11
+#define		PACKET3_BASE_INDEX(x)                  ((x) << 0)
+#define			GDS_PARTITION_BASE		2
+#define			CE_PARTITION_BASE		3
+#define	PACKET3_CLEAR_STATE				0x12
+#define	PACKET3_INDEX_BUFFER_SIZE			0x13
+#define	PACKET3_DISPATCH_DIRECT				0x15
+#define	PACKET3_DISPATCH_INDIRECT			0x16
+#define	PACKET3_ALLOC_GDS				0x1B
+#define	PACKET3_WRITE_GDS_RAM				0x1C
+#define	PACKET3_ATOMIC_GDS				0x1D
+#define	PACKET3_ATOMIC					0x1E
+#define	PACKET3_OCCLUSION_QUERY				0x1F
+#define	PACKET3_SET_PREDICATION				0x20
+#define	PACKET3_REG_RMW					0x21
+#define	PACKET3_COND_EXEC				0x22
+#define	PACKET3_PRED_EXEC				0x23
+#define	PACKET3_DRAW_INDIRECT				0x24
+#define	PACKET3_DRAW_INDEX_INDIRECT			0x25
+#define	PACKET3_INDEX_BASE				0x26
+#define	PACKET3_DRAW_INDEX_2				0x27
+#define	PACKET3_CONTEXT_CONTROL				0x28
+#define	PACKET3_INDEX_TYPE				0x2A
+#define	PACKET3_DRAW_INDIRECT_MULTI			0x2C
+#define	PACKET3_DRAW_INDEX_AUTO				0x2D
+#define	PACKET3_DRAW_INDEX_IMMD				0x2E
+#define	PACKET3_NUM_INSTANCES				0x2F
+#define	PACKET3_DRAW_INDEX_MULTI_AUTO			0x30
+#define	PACKET3_INDIRECT_BUFFER_CONST			0x31
+#define	PACKET3_INDIRECT_BUFFER				0x32
+#define	PACKET3_STRMOUT_BUFFER_UPDATE			0x34
+#define	PACKET3_DRAW_INDEX_OFFSET_2			0x35
+#define	PACKET3_DRAW_INDEX_MULTI_ELEMENT		0x36
+#define	PACKET3_WRITE_DATA				0x37
+#define	PACKET3_DRAW_INDEX_INDIRECT_MULTI		0x38
+#define	PACKET3_MEM_SEMAPHORE				0x39
+#define	PACKET3_MPEG_INDEX				0x3A
+#define	PACKET3_COPY_DW					0x3B
+#define	PACKET3_WAIT_REG_MEM				0x3C
+#define	PACKET3_MEM_WRITE				0x3D
+#define	PACKET3_COPY_DATA				0x40
+#define	PACKET3_PFP_SYNC_ME				0x42
+#define	PACKET3_SURFACE_SYNC				0x43
+#              define PACKET3_DEST_BASE_0_ENA      (1 << 0)
+#              define PACKET3_DEST_BASE_1_ENA      (1 << 1)
+#              define PACKET3_CB0_DEST_BASE_ENA    (1 << 6)
+#              define PACKET3_CB1_DEST_BASE_ENA    (1 << 7)
+#              define PACKET3_CB2_DEST_BASE_ENA    (1 << 8)
+#              define PACKET3_CB3_DEST_BASE_ENA    (1 << 9)
+#              define PACKET3_CB4_DEST_BASE_ENA    (1 << 10)
+#              define PACKET3_CB5_DEST_BASE_ENA    (1 << 11)
+#              define PACKET3_CB6_DEST_BASE_ENA    (1 << 12)
+#              define PACKET3_CB7_DEST_BASE_ENA    (1 << 13)
+#              define PACKET3_DB_DEST_BASE_ENA     (1 << 14)
+#              define PACKET3_DEST_BASE_2_ENA      (1 << 19)
+#              define PACKET3_DEST_BASE_3_ENA      (1 << 21)
+#              define PACKET3_TCL1_ACTION_ENA      (1 << 22)
+#              define PACKET3_TC_ACTION_ENA        (1 << 23)
+#              define PACKET3_CB_ACTION_ENA        (1 << 25)
+#              define PACKET3_DB_ACTION_ENA        (1 << 26)
+#              define PACKET3_SH_KCACHE_ACTION_ENA (1 << 27)
+#              define PACKET3_SH_ICACHE_ACTION_ENA (1 << 29)
+#define	PACKET3_ME_INITIALIZE				0x44
+#define		PACKET3_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16)
+#define	PACKET3_COND_WRITE				0x45
+#define	PACKET3_EVENT_WRITE				0x46
+#define		EVENT_TYPE(x)                           ((x) << 0)
+#define		EVENT_INDEX(x)                          ((x) << 8)
+                /* 0 - any non-TS event
+		 * 1 - ZPASS_DONE
+		 * 2 - SAMPLE_PIPELINESTAT
+		 * 3 - SAMPLE_STREAMOUTSTAT*
+		 * 4 - *S_PARTIAL_FLUSH
+		 * 5 - EOP events
+		 * 6 - EOS events
+		 * 7 - CACHE_FLUSH, CACHE_FLUSH_AND_INV_EVENT
+		 */
+#define		INV_L2                                  (1 << 20)
+                /* INV TC L2 cache when EVENT_INDEX = 7 */
+#define	PACKET3_EVENT_WRITE_EOP				0x47
+#define		DATA_SEL(x)                             ((x) << 29)
+                /* 0 - discard
+		 * 1 - send low 32bit data
+		 * 2 - send 64bit data
+		 * 3 - send 64bit counter value
+		 */
+#define		INT_SEL(x)                              ((x) << 24)
+                /* 0 - none
+		 * 1 - interrupt only (DATA_SEL = 0)
+		 * 2 - interrupt when data write is confirmed
+		 */
+#define	PACKET3_EVENT_WRITE_EOS				0x48
+#define	PACKET3_PREAMBLE_CNTL				0x4A
+#              define PACKET3_PREAMBLE_BEGIN_CLEAR_STATE     (2 << 28)
+#              define PACKET3_PREAMBLE_END_CLEAR_STATE       (3 << 28)
+#define	PACKET3_ONE_REG_WRITE				0x57
+#define	PACKET3_LOAD_CONFIG_REG				0x5F
+#define	PACKET3_LOAD_CONTEXT_REG			0x60
+#define	PACKET3_LOAD_SH_REG				0x61
+#define	PACKET3_SET_CONFIG_REG				0x68
+#define		PACKET3_SET_CONFIG_REG_START			0x00008000
+#define		PACKET3_SET_CONFIG_REG_END			0x0000b000
+#define	PACKET3_SET_CONTEXT_REG				0x69
+#define		PACKET3_SET_CONTEXT_REG_START			0x00028000
+#define		PACKET3_SET_CONTEXT_REG_END			0x00029000
+#define	PACKET3_SET_CONTEXT_REG_INDIRECT		0x73
+#define	PACKET3_SET_RESOURCE_INDIRECT			0x74
+#define	PACKET3_SET_SH_REG				0x76
+#define		PACKET3_SET_SH_REG_START			0x0000b000
+#define		PACKET3_SET_SH_REG_END				0x0000c000
+#define	PACKET3_SET_SH_REG_OFFSET			0x77
+#define	PACKET3_ME_WRITE				0x7A
+#define	PACKET3_SCRATCH_RAM_WRITE			0x7D
+#define	PACKET3_SCRATCH_RAM_READ			0x7E
+#define	PACKET3_CE_WRITE				0x7F
+#define	PACKET3_LOAD_CONST_RAM				0x80
+#define	PACKET3_WRITE_CONST_RAM				0x81
+#define	PACKET3_WRITE_CONST_RAM_OFFSET			0x82
+#define	PACKET3_DUMP_CONST_RAM				0x83
+#define	PACKET3_INCREMENT_CE_COUNTER			0x84
+#define	PACKET3_INCREMENT_DE_COUNTER			0x85
+#define	PACKET3_WAIT_ON_CE_COUNTER			0x86
+#define	PACKET3_WAIT_ON_DE_COUNTER			0x87
+#define	PACKET3_WAIT_ON_DE_COUNTER_DIFF			0x88
+#define	PACKET3_SET_CE_DE_COUNTERS			0x89
+#define	PACKET3_WAIT_ON_AVAIL_BUFFER			0x8A
+
+#endif
diff --git a/drivers/gpu/drm/savage/savage_state.c b/drivers/gpu/drm/savage/savage_state.c
index 8a3e315..031aaaf 100644
--- a/drivers/gpu/drm/savage/savage_state.c
+++ b/drivers/gpu/drm/savage/savage_state.c
@@ -1057,7 +1057,8 @@
 				DRM_ERROR("indexed drawing command extends "
 					  "beyond end of command buffer\n");
 				DMA_FLUSH();
-				return -EINVAL;
+				ret = -EINVAL;
+				goto done;
 			}
 			/* fall through */
 		case SAVAGE_CMD_DMA_PRIM:
@@ -1076,7 +1077,7 @@
 				      cmdbuf->vb_stride,
 				      cmdbuf->nbox, cmdbuf->box_addr);
 				if (ret != 0)
-					return ret;
+					goto done;
 				first_draw_cmd = NULL;
 			}
 		}
diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c
index 573220c..30d98d1 100644
--- a/drivers/gpu/drm/sis/sis_drv.c
+++ b/drivers/gpu/drm/sis/sis_drv.c
@@ -41,6 +41,8 @@
 {
 	drm_sis_private_t *dev_priv;
 
+	pci_set_master(dev->pdev);
+
 	dev_priv = kzalloc(sizeof(drm_sis_private_t), GFP_KERNEL);
 	if (dev_priv == NULL)
 		return -ENOMEM;
diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c
index 747c141..4a87282 100644
--- a/drivers/gpu/drm/ttm/ttm_agp_backend.c
+++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c
@@ -29,6 +29,8 @@
  *          Keith Packard.
  */
 
+#define pr_fmt(fmt) "[TTM] " fmt
+
 #include "ttm/ttm_module.h"
 #include "ttm/ttm_bo_driver.h"
 #include "ttm/ttm_page_alloc.h"
@@ -74,7 +76,7 @@
 
 	ret = agp_bind_memory(mem, node->start);
 	if (ret)
-		printk(KERN_ERR TTM_PFX "AGP Bind memory failed.\n");
+		pr_err("AGP Bind memory failed\n");
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 7c3a57d..1f5c67c 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -28,6 +28,8 @@
  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
  */
 
+#define pr_fmt(fmt) "[TTM] " fmt
+
 #include "ttm/ttm_module.h"
 #include "ttm/ttm_bo_driver.h"
 #include "ttm/ttm_placement.h"
@@ -68,15 +70,13 @@
 {
 	struct ttm_mem_type_manager *man = &bdev->man[mem_type];
 
-	printk(KERN_ERR TTM_PFX "    has_type: %d\n", man->has_type);
-	printk(KERN_ERR TTM_PFX "    use_type: %d\n", man->use_type);
-	printk(KERN_ERR TTM_PFX "    flags: 0x%08X\n", man->flags);
-	printk(KERN_ERR TTM_PFX "    gpu_offset: 0x%08lX\n", man->gpu_offset);
-	printk(KERN_ERR TTM_PFX "    size: %llu\n", man->size);
-	printk(KERN_ERR TTM_PFX "    available_caching: 0x%08X\n",
-		man->available_caching);
-	printk(KERN_ERR TTM_PFX "    default_caching: 0x%08X\n",
-		man->default_caching);
+	pr_err("    has_type: %d\n", man->has_type);
+	pr_err("    use_type: %d\n", man->use_type);
+	pr_err("    flags: 0x%08X\n", man->flags);
+	pr_err("    gpu_offset: 0x%08lX\n", man->gpu_offset);
+	pr_err("    size: %llu\n", man->size);
+	pr_err("    available_caching: 0x%08X\n", man->available_caching);
+	pr_err("    default_caching: 0x%08X\n", man->default_caching);
 	if (mem_type != TTM_PL_SYSTEM)
 		(*man->func->debug)(man, TTM_PFX);
 }
@@ -86,16 +86,16 @@
 {
 	int i, ret, mem_type;
 
-	printk(KERN_ERR TTM_PFX "No space for %p (%lu pages, %luK, %luM)\n",
-		bo, bo->mem.num_pages, bo->mem.size >> 10,
-		bo->mem.size >> 20);
+	pr_err("No space for %p (%lu pages, %luK, %luM)\n",
+	       bo, bo->mem.num_pages, bo->mem.size >> 10,
+	       bo->mem.size >> 20);
 	for (i = 0; i < placement->num_placement; i++) {
 		ret = ttm_mem_type_from_flags(placement->placement[i],
 						&mem_type);
 		if (ret)
 			return;
-		printk(KERN_ERR TTM_PFX "  placement[%d]=0x%08X (%d)\n",
-			i, placement->placement[i], mem_type);
+		pr_err("  placement[%d]=0x%08X (%d)\n",
+		       i, placement->placement[i], mem_type);
 		ttm_mem_type_debug(bo->bdev, mem_type);
 	}
 }
@@ -344,7 +344,7 @@
 			ret = -ENOMEM;
 		break;
 	default:
-		printk(KERN_ERR TTM_PFX "Illegal buffer object type\n");
+		pr_err("Illegal buffer object type\n");
 		ret = -EINVAL;
 		break;
 	}
@@ -432,7 +432,7 @@
 	if (bo->evicted) {
 		ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
 		if (ret)
-			printk(KERN_ERR TTM_PFX "Can not flush read caches\n");
+			pr_err("Can not flush read caches\n");
 		bo->evicted = false;
 	}
 
@@ -734,9 +734,7 @@
 
 	if (unlikely(ret != 0)) {
 		if (ret != -ERESTARTSYS) {
-			printk(KERN_ERR TTM_PFX
-			       "Failed to expire sync object before "
-			       "buffer eviction.\n");
+			pr_err("Failed to expire sync object before buffer eviction\n");
 		}
 		goto out;
 	}
@@ -757,9 +755,8 @@
 				no_wait_reserve, no_wait_gpu);
 	if (ret) {
 		if (ret != -ERESTARTSYS) {
-			printk(KERN_ERR TTM_PFX
-			       "Failed to find memory space for "
-			       "buffer 0x%p eviction.\n", bo);
+			pr_err("Failed to find memory space for buffer 0x%p eviction\n",
+			       bo);
 			ttm_bo_mem_space_debug(bo, &placement);
 		}
 		goto out;
@@ -769,7 +766,7 @@
 				     no_wait_reserve, no_wait_gpu);
 	if (ret) {
 		if (ret != -ERESTARTSYS)
-			printk(KERN_ERR TTM_PFX "Buffer eviction failed\n");
+			pr_err("Buffer eviction failed\n");
 		ttm_bo_mem_put(bo, &evict_mem);
 		goto out;
 	}
@@ -1180,7 +1177,7 @@
 
 	ret = ttm_mem_global_alloc(mem_glob, acc_size, false, false);
 	if (ret) {
-		printk(KERN_ERR TTM_PFX "Out of kernel memory.\n");
+		pr_err("Out of kernel memory\n");
 		if (destroy)
 			(*destroy)(bo);
 		else
@@ -1191,7 +1188,7 @@
 	size += buffer_start & ~PAGE_MASK;
 	num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	if (num_pages == 0) {
-		printk(KERN_ERR TTM_PFX "Illegal buffer object size.\n");
+		pr_err("Illegal buffer object size\n");
 		if (destroy)
 			(*destroy)(bo);
 		else
@@ -1342,8 +1339,7 @@
 			if (allow_errors) {
 				return ret;
 			} else {
-				printk(KERN_ERR TTM_PFX
-					"Cleanup eviction failed\n");
+				pr_err("Cleanup eviction failed\n");
 			}
 		}
 		spin_lock(&glob->lru_lock);
@@ -1358,14 +1354,14 @@
 	int ret = -EINVAL;
 
 	if (mem_type >= TTM_NUM_MEM_TYPES) {
-		printk(KERN_ERR TTM_PFX "Illegal memory type %d\n", mem_type);
+		pr_err("Illegal memory type %d\n", mem_type);
 		return ret;
 	}
 	man = &bdev->man[mem_type];
 
 	if (!man->has_type) {
-		printk(KERN_ERR TTM_PFX "Trying to take down uninitialized "
-		       "memory manager type %u\n", mem_type);
+		pr_err("Trying to take down uninitialized memory manager type %u\n",
+		       mem_type);
 		return ret;
 	}
 
@@ -1388,16 +1384,12 @@
 	struct ttm_mem_type_manager *man = &bdev->man[mem_type];
 
 	if (mem_type == 0 || mem_type >= TTM_NUM_MEM_TYPES) {
-		printk(KERN_ERR TTM_PFX
-		       "Illegal memory manager memory type %u.\n",
-		       mem_type);
+		pr_err("Illegal memory manager memory type %u\n", mem_type);
 		return -EINVAL;
 	}
 
 	if (!man->has_type) {
-		printk(KERN_ERR TTM_PFX
-		       "Memory type %u has not been initialized.\n",
-		       mem_type);
+		pr_err("Memory type %u has not been initialized\n", mem_type);
 		return 0;
 	}
 
@@ -1482,8 +1474,7 @@
 	ttm_mem_init_shrink(&glob->shrink, ttm_bo_swapout);
 	ret = ttm_mem_register_shrink(glob->mem_glob, &glob->shrink);
 	if (unlikely(ret != 0)) {
-		printk(KERN_ERR TTM_PFX
-		       "Could not register buffer object swapout.\n");
+		pr_err("Could not register buffer object swapout\n");
 		goto out_no_shrink;
 	}
 
@@ -1516,9 +1507,8 @@
 			man->use_type = false;
 			if ((i != TTM_PL_SYSTEM) && ttm_bo_clean_mm(bdev, i)) {
 				ret = -EBUSY;
-				printk(KERN_ERR TTM_PFX
-				       "DRM memory manager type %d "
-				       "is not clean.\n", i);
+				pr_err("DRM memory manager type %d is not clean\n",
+				       i);
 			}
 			man->has_type = false;
 		}
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index 5441284..a877813 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -28,6 +28,8 @@
  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
  */
 
+#define pr_fmt(fmt) "[TTM] " fmt
+
 #include <ttm/ttm_module.h>
 #include <ttm/ttm_bo_driver.h>
 #include <ttm/ttm_placement.h>
@@ -262,8 +264,7 @@
 	read_unlock(&bdev->vm_lock);
 
 	if (unlikely(bo == NULL)) {
-		printk(KERN_ERR TTM_PFX
-		       "Could not find buffer object to map.\n");
+		pr_err("Could not find buffer object to map\n");
 		return -EINVAL;
 	}
 
diff --git a/drivers/gpu/drm/ttm/ttm_memory.c b/drivers/gpu/drm/ttm/ttm_memory.c
index 9eba8e9..23d2ecb 100644
--- a/drivers/gpu/drm/ttm/ttm_memory.c
+++ b/drivers/gpu/drm/ttm/ttm_memory.c
@@ -25,6 +25,8 @@
  *
  **************************************************************************/
 
+#define pr_fmt(fmt) "[TTM] " fmt
+
 #include "ttm/ttm_memory.h"
 #include "ttm/ttm_module.h"
 #include "ttm/ttm_page_alloc.h"
@@ -74,9 +76,8 @@
 	struct ttm_mem_zone *zone =
 		container_of(kobj, struct ttm_mem_zone, kobj);
 
-	printk(KERN_INFO TTM_PFX
-	       "Zone %7s: Used memory at exit: %llu kiB.\n",
-	       zone->name, (unsigned long long) zone->used_mem >> 10);
+	pr_info("Zone %7s: Used memory at exit: %llu kiB\n",
+		zone->name, (unsigned long long)zone->used_mem >> 10);
 	kfree(zone);
 }
 
@@ -390,9 +391,8 @@
 #endif
 	for (i = 0; i < glob->num_zones; ++i) {
 		zone = glob->zones[i];
-		printk(KERN_INFO TTM_PFX
-		       "Zone %7s: Available graphics memory: %llu kiB.\n",
-		       zone->name, (unsigned long long) zone->max_mem >> 10);
+		pr_info("Zone %7s: Available graphics memory: %llu kiB\n",
+			zone->name, (unsigned long long)zone->max_mem >> 10);
 	}
 	ttm_page_alloc_init(glob, glob->zone_kernel->max_mem/(2*PAGE_SIZE));
 	ttm_dma_page_alloc_init(glob, glob->zone_kernel->max_mem/(2*PAGE_SIZE));
diff --git a/drivers/gpu/drm/ttm/ttm_object.c b/drivers/gpu/drm/ttm/ttm_object.c
index 93577f2..68daca4 100644
--- a/drivers/gpu/drm/ttm/ttm_object.c
+++ b/drivers/gpu/drm/ttm/ttm_object.c
@@ -49,6 +49,8 @@
  * for fast lookup of ref objects given a base object.
  */
 
+#define pr_fmt(fmt) "[TTM] " fmt
+
 #include "ttm/ttm_object.h"
 #include "ttm/ttm_module.h"
 #include <linux/list.h>
@@ -232,8 +234,7 @@
 		return NULL;
 
 	if (tfile != base->tfile && !base->shareable) {
-		printk(KERN_ERR TTM_PFX
-		       "Attempted access of non-shareable object.\n");
+		pr_err("Attempted access of non-shareable object\n");
 		ttm_base_object_unref(&base);
 		return NULL;
 	}
diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c
index 499debd..ebc6fac 100644
--- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
+++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
@@ -30,6 +30,9 @@
  * - Use page->lru to keep a free list
  * - doesn't track currently in use pages
  */
+
+#define pr_fmt(fmt) "[TTM] " fmt
+
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/highmem.h>
@@ -167,18 +170,13 @@
 		m->options.small = val;
 	else if (attr == &ttm_page_pool_alloc_size) {
 		if (val > NUM_PAGES_TO_ALLOC*8) {
-			printk(KERN_ERR TTM_PFX
-			       "Setting allocation size to %lu "
-			       "is not allowed. Recommended size is "
-			       "%lu\n",
+			pr_err("Setting allocation size to %lu is not allowed. Recommended size is %lu\n",
 			       NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 7),
 			       NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10));
 			return size;
 		} else if (val > NUM_PAGES_TO_ALLOC) {
-			printk(KERN_WARNING TTM_PFX
-			       "Setting allocation size to "
-			       "larger than %lu is not recommended.\n",
-			       NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10));
+			pr_warn("Setting allocation size to larger than %lu is not recommended\n",
+				NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10));
 		}
 		m->options.alloc_size = val;
 	}
@@ -279,8 +277,7 @@
 {
 	unsigned i;
 	if (set_pages_array_wb(pages, npages))
-		printk(KERN_ERR TTM_PFX "Failed to set %d pages to wb!\n",
-				npages);
+		pr_err("Failed to set %d pages to wb!\n", npages);
 	for (i = 0; i < npages; ++i)
 		__free_page(pages[i]);
 }
@@ -315,8 +312,7 @@
 	pages_to_free = kmalloc(npages_to_free * sizeof(struct page *),
 			GFP_KERNEL);
 	if (!pages_to_free) {
-		printk(KERN_ERR TTM_PFX
-		       "Failed to allocate memory for pool free operation.\n");
+		pr_err("Failed to allocate memory for pool free operation\n");
 		return 0;
 	}
 
@@ -438,16 +434,12 @@
 	case tt_uncached:
 		r = set_pages_array_uc(pages, cpages);
 		if (r)
-			printk(KERN_ERR TTM_PFX
-			       "Failed to set %d pages to uc!\n",
-			       cpages);
+			pr_err("Failed to set %d pages to uc!\n", cpages);
 		break;
 	case tt_wc:
 		r = set_pages_array_wc(pages, cpages);
 		if (r)
-			printk(KERN_ERR TTM_PFX
-			       "Failed to set %d pages to wc!\n",
-			       cpages);
+			pr_err("Failed to set %d pages to wc!\n", cpages);
 		break;
 	default:
 		break;
@@ -492,8 +484,7 @@
 	caching_array = kmalloc(max_cpages*sizeof(struct page *), GFP_KERNEL);
 
 	if (!caching_array) {
-		printk(KERN_ERR TTM_PFX
-		       "Unable to allocate table for new pages.");
+		pr_err("Unable to allocate table for new pages\n");
 		return -ENOMEM;
 	}
 
@@ -501,7 +492,7 @@
 		p = alloc_page(gfp_flags);
 
 		if (!p) {
-			printk(KERN_ERR TTM_PFX "Unable to get page %u.\n", i);
+			pr_err("Unable to get page %u\n", i);
 
 			/* store already allocated pages in the pool after
 			 * setting the caching state */
@@ -599,8 +590,7 @@
 			++pool->nrefills;
 			pool->npages += alloc_size;
 		} else {
-			printk(KERN_ERR TTM_PFX
-			       "Failed to fill pool (%p).", pool);
+			pr_err("Failed to fill pool (%p)\n", pool);
 			/* If we have any pages left put them to the pool. */
 			list_for_each_entry(p, &pool->list, lru) {
 				++cpages;
@@ -675,9 +665,7 @@
 		for (i = 0; i < npages; i++) {
 			if (pages[i]) {
 				if (page_count(pages[i]) != 1)
-					printk(KERN_ERR TTM_PFX
-					       "Erroneous page count. "
-					       "Leaking pages.\n");
+					pr_err("Erroneous page count. Leaking pages.\n");
 				__free_page(pages[i]);
 				pages[i] = NULL;
 			}
@@ -689,9 +677,7 @@
 	for (i = 0; i < npages; i++) {
 		if (pages[i]) {
 			if (page_count(pages[i]) != 1)
-				printk(KERN_ERR TTM_PFX
-				       "Erroneous page count. "
-				       "Leaking pages.\n");
+				pr_err("Erroneous page count. Leaking pages.\n");
 			list_add_tail(&pages[i]->lru, &pool->list);
 			pages[i] = NULL;
 			pool->npages++;
@@ -740,8 +726,7 @@
 			p = alloc_page(gfp_flags);
 			if (!p) {
 
-				printk(KERN_ERR TTM_PFX
-				       "Unable to allocate page.");
+				pr_err("Unable to allocate page\n");
 				return -ENOMEM;
 			}
 
@@ -781,9 +766,7 @@
 		if (r) {
 			/* If there is any pages in the list put them back to
 			 * the pool. */
-			printk(KERN_ERR TTM_PFX
-			       "Failed to allocate extra pages "
-			       "for large request.");
+			pr_err("Failed to allocate extra pages for large request\n");
 			ttm_put_pages(pages, count, flags, cstate);
 			return r;
 		}
@@ -809,7 +792,7 @@
 
 	WARN_ON(_manager);
 
-	printk(KERN_INFO TTM_PFX "Initializing pool allocator.\n");
+	pr_info("Initializing pool allocator\n");
 
 	_manager = kzalloc(sizeof(*_manager), GFP_KERNEL);
 
@@ -844,7 +827,7 @@
 {
 	int i;
 
-	printk(KERN_INFO TTM_PFX "Finalizing pool allocator.\n");
+	pr_info("Finalizing pool allocator\n");
 	ttm_pool_mm_shrink_fini(_manager);
 
 	for (i = 0; i < NUM_POOLS; ++i)
diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
index 0c46d8c..4f9e548 100644
--- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
+++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
@@ -33,6 +33,8 @@
  *   when freed).
  */
 
+#define pr_fmt(fmt) "[TTM] " fmt
+
 #include <linux/dma-mapping.h>
 #include <linux/list.h>
 #include <linux/seq_file.h> /* for seq_printf */
@@ -221,18 +223,13 @@
 		m->options.small = val;
 	else if (attr == &ttm_page_pool_alloc_size) {
 		if (val > NUM_PAGES_TO_ALLOC*8) {
-			printk(KERN_ERR TTM_PFX
-			       "Setting allocation size to %lu "
-			       "is not allowed. Recommended size is "
-			       "%lu\n",
+			pr_err("Setting allocation size to %lu is not allowed. Recommended size is %lu\n",
 			       NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 7),
 			       NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10));
 			return size;
 		} else if (val > NUM_PAGES_TO_ALLOC) {
-			printk(KERN_WARNING TTM_PFX
-			       "Setting allocation size to "
-			       "larger than %lu is not recommended.\n",
-			       NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10));
+			pr_warn("Setting allocation size to larger than %lu is not recommended\n",
+				NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10));
 		}
 		m->options.alloc_size = val;
 	}
@@ -313,15 +310,13 @@
 	if (pool->type & IS_UC) {
 		r = set_pages_array_uc(pages, cpages);
 		if (r)
-			pr_err(TTM_PFX
-			       "%s: Failed to set %d pages to uc!\n",
+			pr_err("%s: Failed to set %d pages to uc!\n",
 			       pool->dev_name, cpages);
 	}
 	if (pool->type & IS_WC) {
 		r = set_pages_array_wc(pages, cpages);
 		if (r)
-			pr_err(TTM_PFX
-			       "%s: Failed to set %d pages to wc!\n",
+			pr_err("%s: Failed to set %d pages to wc!\n",
 			       pool->dev_name, cpages);
 	}
 	return r;
@@ -387,8 +382,8 @@
 	/* Don't set WB on WB page pool. */
 	if (npages && !(pool->type & IS_CACHED) &&
 	    set_pages_array_wb(pages, npages))
-		pr_err(TTM_PFX "%s: Failed to set %d pages to wb!\n",
-			pool->dev_name, npages);
+		pr_err("%s: Failed to set %d pages to wb!\n",
+		       pool->dev_name, npages);
 
 	list_for_each_entry_safe(d_page, tmp, d_pages, page_list) {
 		list_del(&d_page->page_list);
@@ -400,8 +395,8 @@
 {
 	/* Don't set WB on WB page pool. */
 	if (!(pool->type & IS_CACHED) && set_pages_array_wb(&d_page->p, 1))
-		pr_err(TTM_PFX "%s: Failed to set %d pages to wb!\n",
-			pool->dev_name, 1);
+		pr_err("%s: Failed to set %d pages to wb!\n",
+		       pool->dev_name, 1);
 
 	list_del(&d_page->page_list);
 	__ttm_dma_free_page(pool, d_page);
@@ -430,17 +425,16 @@
 #if 0
 	if (nr_free > 1) {
 		pr_debug("%s: (%s:%d) Attempting to free %d (%d) pages\n",
-			pool->dev_name, pool->name, current->pid,
-			npages_to_free, nr_free);
+			 pool->dev_name, pool->name, current->pid,
+			 npages_to_free, nr_free);
 	}
 #endif
 	pages_to_free = kmalloc(npages_to_free * sizeof(struct page *),
 			GFP_KERNEL);
 
 	if (!pages_to_free) {
-		pr_err(TTM_PFX
-		       "%s: Failed to allocate memory for pool free operation.\n",
-			pool->dev_name);
+		pr_err("%s: Failed to allocate memory for pool free operation\n",
+		       pool->dev_name);
 		return 0;
 	}
 	INIT_LIST_HEAD(&d_pages);
@@ -723,23 +717,21 @@
 	caching_array = kmalloc(max_cpages*sizeof(struct page *), GFP_KERNEL);
 
 	if (!caching_array) {
-		pr_err(TTM_PFX
-		       "%s: Unable to allocate table for new pages.",
-			pool->dev_name);
+		pr_err("%s: Unable to allocate table for new pages\n",
+		       pool->dev_name);
 		return -ENOMEM;
 	}
 
 	if (count > 1) {
 		pr_debug("%s: (%s:%d) Getting %d pages\n",
-			pool->dev_name, pool->name, current->pid,
-			count);
+			 pool->dev_name, pool->name, current->pid, count);
 	}
 
 	for (i = 0, cpages = 0; i < count; ++i) {
 		dma_p = __ttm_dma_alloc_page(pool);
 		if (!dma_p) {
-			pr_err(TTM_PFX "%s: Unable to get page %u.\n",
-				pool->dev_name, i);
+			pr_err("%s: Unable to get page %u\n",
+			       pool->dev_name, i);
 
 			/* store already allocated pages in the pool after
 			 * setting the caching state */
@@ -821,8 +813,8 @@
 			struct dma_page *d_page;
 			unsigned cpages = 0;
 
-			pr_err(TTM_PFX "%s: Failed to fill %s pool (r:%d)!\n",
-				pool->dev_name, pool->name, r);
+			pr_err("%s: Failed to fill %s pool (r:%d)!\n",
+			       pool->dev_name, pool->name, r);
 
 			list_for_each_entry(d_page, &d_pages, page_list) {
 				cpages++;
@@ -1038,8 +1030,8 @@
 		nr_free = shrink_pages;
 		shrink_pages = ttm_dma_page_pool_free(p->pool, nr_free);
 		pr_debug("%s: (%s:%d) Asked to shrink %d, have %d more to go\n",
-			p->pool->dev_name, p->pool->name, current->pid, nr_free,
-			shrink_pages);
+			 p->pool->dev_name, p->pool->name, current->pid,
+			 nr_free, shrink_pages);
 	}
 	mutex_unlock(&_manager->lock);
 	/* return estimated number of unused pages in pool */
@@ -1064,7 +1056,7 @@
 
 	WARN_ON(_manager);
 
-	printk(KERN_INFO TTM_PFX "Initializing DMA pool allocator.\n");
+	pr_info("Initializing DMA pool allocator\n");
 
 	_manager = kzalloc(sizeof(*_manager), GFP_KERNEL);
 	if (!_manager)
@@ -1097,7 +1089,7 @@
 {
 	struct device_pools *p, *t;
 
-	printk(KERN_INFO TTM_PFX "Finalizing DMA pool allocator.\n");
+	pr_info("Finalizing DMA pool allocator\n");
 	ttm_dma_pool_mm_shrink_fini(_manager);
 
 	list_for_each_entry_safe_reverse(p, t, &_manager->pools, pools) {
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index c10cf5e..fa09daf 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -28,6 +28,8 @@
  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
  */
 
+#define pr_fmt(fmt) "[TTM] " fmt
+
 #include <linux/sched.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
@@ -196,7 +198,7 @@
 	ttm_tt_alloc_page_directory(ttm);
 	if (!ttm->pages) {
 		ttm_tt_destroy(ttm);
-		printk(KERN_ERR TTM_PFX "Failed allocating page table\n");
+		pr_err("Failed allocating page table\n");
 		return -ENOMEM;
 	}
 	return 0;
@@ -229,7 +231,7 @@
 	ttm_dma_tt_alloc_page_directory(ttm_dma);
 	if (!ttm->pages || !ttm_dma->dma_address) {
 		ttm_tt_destroy(ttm);
-		printk(KERN_ERR TTM_PFX "Failed allocating page table\n");
+		pr_err("Failed allocating page table\n");
 		return -ENOMEM;
 	}
 	return 0;
@@ -347,7 +349,7 @@
 						ttm->num_pages << PAGE_SHIFT,
 						0);
 		if (unlikely(IS_ERR(swap_storage))) {
-			printk(KERN_ERR "Failed allocating swap storage.\n");
+			pr_err("Failed allocating swap storage\n");
 			return PTR_ERR(swap_storage);
 		}
 	} else
diff --git a/drivers/gpu/drm/udl/Kconfig b/drivers/gpu/drm/udl/Kconfig
new file mode 100644
index 0000000..0b5e096
--- /dev/null
+++ b/drivers/gpu/drm/udl/Kconfig
@@ -0,0 +1,12 @@
+config DRM_UDL
+	tristate "DisplayLink"
+	depends on DRM && EXPERIMENTAL
+	select DRM_USB
+	select FB_SYS_FILLRECT
+	select FB_SYS_COPYAREA
+	select FB_SYS_IMAGEBLIT
+	select FB_DEFERRED_IO
+	select DRM_KMS_HELPER
+	help
+	  This is a KMS driver for the USB displaylink video adapters.
+          Say M/Y to add support for these devices via drm/kms interfaces.
diff --git a/drivers/gpu/drm/udl/Makefile b/drivers/gpu/drm/udl/Makefile
new file mode 100644
index 0000000..05c7481
--- /dev/null
+++ b/drivers/gpu/drm/udl/Makefile
@@ -0,0 +1,6 @@
+
+ccflags-y := -Iinclude/drm
+
+udl-y := udl_drv.o udl_modeset.o udl_connector.o udl_encoder.o udl_main.o udl_fb.o udl_transfer.o udl_gem.o
+
+obj-$(CONFIG_DRM_UDL) := udl.o
diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c
new file mode 100644
index 0000000..ba055e9
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ * based in parts on udlfb.c:
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_edid.h"
+#include "drm_crtc_helper.h"
+#include "udl_drv.h"
+
+/* dummy connector to just get EDID,
+   all UDL appear to have a DVI-D */
+
+static u8 *udl_get_edid(struct udl_device *udl)
+{
+	u8 *block;
+	char rbuf[3];
+	int ret, i;
+
+	block = kmalloc(EDID_LENGTH, GFP_KERNEL);
+	if (block == NULL)
+		return NULL;
+
+	for (i = 0; i < EDID_LENGTH; i++) {
+		ret = usb_control_msg(udl->ddev->usbdev,
+				      usb_rcvctrlpipe(udl->ddev->usbdev, 0), (0x02),
+				      (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
+				      HZ);
+		if (ret < 1) {
+			DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret);
+			i--;
+			goto error;
+		}
+		block[i] = rbuf[1];
+	}
+
+	return block;
+
+error:
+	kfree(block);
+	return NULL;
+}
+
+static int udl_get_modes(struct drm_connector *connector)
+{
+	struct udl_device *udl = connector->dev->dev_private;
+	struct edid *edid;
+	int ret;
+
+	edid = (struct edid *)udl_get_edid(udl);
+
+	connector->display_info.raw_edid = (char *)edid;
+
+	drm_mode_connector_update_edid_property(connector, edid);
+	ret = drm_add_edid_modes(connector, edid);
+	connector->display_info.raw_edid = NULL;
+	kfree(edid);
+	return ret;
+}
+
+static int udl_mode_valid(struct drm_connector *connector,
+			  struct drm_display_mode *mode)
+{
+	return 0;
+}
+
+static enum drm_connector_status
+udl_detect(struct drm_connector *connector, bool force)
+{
+	if (drm_device_is_unplugged(connector->dev))
+		return connector_status_disconnected;
+	return connector_status_connected;
+}
+
+struct drm_encoder *udl_best_single_encoder(struct drm_connector *connector)
+{
+	int enc_id = connector->encoder_ids[0];
+	struct drm_mode_object *obj;
+	struct drm_encoder *encoder;
+
+	obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER);
+	if (!obj)
+		return NULL;
+	encoder = obj_to_encoder(obj);
+	return encoder;
+}
+
+int udl_connector_set_property(struct drm_connector *connector, struct drm_property *property,
+			       uint64_t val)
+{
+	return 0;
+}
+
+static void udl_connector_destroy(struct drm_connector *connector)
+{
+	drm_sysfs_connector_remove(connector);
+	drm_connector_cleanup(connector);
+	kfree(connector);
+}
+
+struct drm_connector_helper_funcs udl_connector_helper_funcs = {
+	.get_modes = udl_get_modes,
+	.mode_valid = udl_mode_valid,
+	.best_encoder = udl_best_single_encoder,
+};
+
+struct drm_connector_funcs udl_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.detect = udl_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = udl_connector_destroy,
+	.set_property = udl_connector_set_property,
+};
+
+int udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder)
+{
+	struct drm_connector *connector;
+
+	connector = kzalloc(sizeof(struct drm_connector), GFP_KERNEL);
+	if (!connector)
+		return -ENOMEM;
+
+	drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_DVII);
+	drm_connector_helper_add(connector, &udl_connector_helper_funcs);
+
+	drm_sysfs_connector_add(connector);
+	drm_mode_connector_attach_encoder(connector, encoder);
+
+	drm_connector_attach_property(connector,
+				      dev->mode_config.dirty_info_property,
+				      1);
+	return 0;
+}
diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c
new file mode 100644
index 0000000..5367390
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_drv.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include "drm_usb.h"
+#include "drm_crtc_helper.h"
+#include "udl_drv.h"
+
+static struct drm_driver driver;
+
+static struct usb_device_id id_table[] = {
+	{.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,},
+	{},
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+MODULE_LICENSE("GPL");
+
+static int udl_usb_probe(struct usb_interface *interface,
+			 const struct usb_device_id *id)
+{
+	return drm_get_usb_dev(interface, id, &driver);
+}
+
+static void udl_usb_disconnect(struct usb_interface *interface)
+{
+	struct drm_device *dev = usb_get_intfdata(interface);
+
+	drm_kms_helper_poll_disable(dev);
+	drm_connector_unplug_all(dev);
+	udl_fbdev_unplug(dev);
+	udl_drop_usb(dev);
+	drm_unplug_dev(dev);
+}
+
+static struct vm_operations_struct udl_gem_vm_ops = {
+	.fault = udl_gem_fault,
+	.open = drm_gem_vm_open,
+	.close = drm_gem_vm_close,
+};
+
+static const struct file_operations udl_driver_fops = {
+	.owner = THIS_MODULE,
+	.open = drm_open,
+	.mmap = udl_drm_gem_mmap,
+	.poll = drm_poll,
+	.read = drm_read,
+	.unlocked_ioctl	= drm_ioctl,
+	.release = drm_release,
+	.fasync = drm_fasync,
+	.llseek = noop_llseek,
+};
+
+static struct drm_driver driver = {
+	.driver_features = DRIVER_MODESET | DRIVER_GEM,
+	.load = udl_driver_load,
+	.unload = udl_driver_unload,
+
+	/* gem hooks */
+	.gem_init_object = udl_gem_init_object,
+	.gem_free_object = udl_gem_free_object,
+	.gem_vm_ops = &udl_gem_vm_ops,
+
+	.dumb_create = udl_dumb_create,
+	.dumb_map_offset = udl_gem_mmap,
+	.dumb_destroy = udl_dumb_destroy,
+	.fops = &udl_driver_fops,
+	.name = DRIVER_NAME,
+	.desc = DRIVER_DESC,
+	.date = DRIVER_DATE,
+	.major = DRIVER_MAJOR,
+	.minor = DRIVER_MINOR,
+	.patchlevel = DRIVER_PATCHLEVEL,
+};
+
+static struct usb_driver udl_driver = {
+	.name = "udl",
+	.probe = udl_usb_probe,
+	.disconnect = udl_usb_disconnect,
+	.id_table = id_table,
+};
+
+static int __init udl_init(void)
+{
+	return drm_usb_init(&driver, &udl_driver);
+}
+
+static void __exit udl_exit(void)
+{
+	drm_usb_exit(&driver, &udl_driver);
+}
+
+module_init(udl_init);
+module_exit(udl_exit);
diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h
new file mode 100644
index 0000000..96820d0
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_drv.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ *
+ * based in parts on udlfb.c:
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#ifndef UDL_DRV_H
+#define UDL_DRV_H
+
+#include <linux/usb.h>
+
+#define DRIVER_NAME		"udl"
+#define DRIVER_DESC		"DisplayLink"
+#define DRIVER_DATE		"20120220"
+
+#define DRIVER_MAJOR		0
+#define DRIVER_MINOR		0
+#define DRIVER_PATCHLEVEL	1
+
+struct udl_device;
+
+struct urb_node {
+	struct list_head entry;
+	struct udl_device *dev;
+	struct delayed_work release_urb_work;
+	struct urb *urb;
+};
+
+struct urb_list {
+	struct list_head list;
+	spinlock_t lock;
+	struct semaphore limit_sem;
+	int available;
+	int count;
+	size_t size;
+};
+
+struct udl_fbdev;
+
+struct udl_device {
+	struct device *dev;
+	struct drm_device *ddev;
+
+	int sku_pixel_limit;
+
+	struct urb_list urbs;
+	atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */
+
+	struct udl_fbdev *fbdev;
+	char mode_buf[1024];
+	uint32_t mode_buf_len;
+	atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */
+	atomic_t bytes_identical; /* saved effort with backbuffer comparison */
+	atomic_t bytes_sent; /* to usb, after compression including overhead */
+	atomic_t cpu_kcycles_used; /* transpired during pixel processing */
+};
+
+struct udl_gem_object {
+	struct drm_gem_object base;
+	struct page **pages;
+	void *vmapping;
+};
+
+#define to_udl_bo(x) container_of(x, struct udl_gem_object, base)
+
+struct udl_framebuffer {
+	struct drm_framebuffer base;
+	struct udl_gem_object *obj;
+	bool active_16; /* active on the 16-bit channel */
+};
+
+#define to_udl_fb(x) container_of(x, struct udl_framebuffer, base)
+
+/* modeset */
+int udl_modeset_init(struct drm_device *dev);
+void udl_modeset_cleanup(struct drm_device *dev);
+int udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder);
+
+struct drm_encoder *udl_encoder_init(struct drm_device *dev);
+
+struct urb *udl_get_urb(struct drm_device *dev);
+
+int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len);
+void udl_urb_completion(struct urb *urb);
+
+int udl_driver_load(struct drm_device *dev, unsigned long flags);
+int udl_driver_unload(struct drm_device *dev);
+
+int udl_fbdev_init(struct drm_device *dev);
+void udl_fbdev_cleanup(struct drm_device *dev);
+void udl_fbdev_unplug(struct drm_device *dev);
+struct drm_framebuffer *
+udl_fb_user_fb_create(struct drm_device *dev,
+		      struct drm_file *file,
+		      struct drm_mode_fb_cmd2 *mode_cmd);
+
+int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr,
+		     const char *front, char **urb_buf_ptr,
+		     u32 byte_offset, u32 byte_width,
+		     int *ident_ptr, int *sent_ptr);
+
+int udl_dumb_create(struct drm_file *file_priv,
+		    struct drm_device *dev,
+		    struct drm_mode_create_dumb *args);
+int udl_gem_mmap(struct drm_file *file_priv, struct drm_device *dev,
+		 uint32_t handle, uint64_t *offset);
+int udl_dumb_destroy(struct drm_file *file_priv, struct drm_device *dev,
+		     uint32_t handle);
+
+int udl_gem_init_object(struct drm_gem_object *obj);
+void udl_gem_free_object(struct drm_gem_object *gem_obj);
+struct udl_gem_object *udl_gem_alloc_object(struct drm_device *dev,
+					    size_t size);
+
+int udl_gem_vmap(struct udl_gem_object *obj);
+void udl_gem_vunmap(struct udl_gem_object *obj);
+int udl_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+int udl_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
+
+int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
+		      int width, int height);
+
+int udl_drop_usb(struct drm_device *dev);
+
+#define CMD_WRITE_RAW8   "\xAF\x60" /**< 8 bit raw write command. */
+#define CMD_WRITE_RL8    "\xAF\x61" /**< 8 bit run length command. */
+#define CMD_WRITE_COPY8  "\xAF\x62" /**< 8 bit copy command. */
+#define CMD_WRITE_RLX8   "\xAF\x63" /**< 8 bit extended run length command. */
+
+#define CMD_WRITE_RAW16  "\xAF\x68" /**< 16 bit raw write command. */
+#define CMD_WRITE_RL16   "\xAF\x69" /**< 16 bit run length command. */
+#define CMD_WRITE_COPY16 "\xAF\x6A" /**< 16 bit copy command. */
+#define CMD_WRITE_RLX16  "\xAF\x6B" /**< 16 bit extended run length command. */
+
+#endif
diff --git a/drivers/gpu/drm/udl/udl_encoder.c b/drivers/gpu/drm/udl/udl_encoder.c
new file mode 100644
index 0000000..56e75f0
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_encoder.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ * based in parts on udlfb.c:
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "udl_drv.h"
+
+/* dummy encoder */
+void udl_enc_destroy(struct drm_encoder *encoder)
+{
+	drm_encoder_cleanup(encoder);
+	kfree(encoder);
+}
+
+static void udl_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static bool udl_mode_fixup(struct drm_encoder *encoder,
+			   struct drm_display_mode *mode,
+			   struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static void udl_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void udl_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static void udl_encoder_mode_set(struct drm_encoder *encoder,
+				 struct drm_display_mode *mode,
+				 struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void
+udl_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static const struct drm_encoder_helper_funcs udl_helper_funcs = {
+	.dpms = udl_encoder_dpms,
+	.mode_fixup = udl_mode_fixup,
+	.prepare = udl_encoder_prepare,
+	.mode_set = udl_encoder_mode_set,
+	.commit = udl_encoder_commit,
+	.disable = udl_encoder_disable,
+};
+
+static const struct drm_encoder_funcs udl_enc_funcs = {
+	.destroy = udl_enc_destroy,
+};
+
+struct drm_encoder *udl_encoder_init(struct drm_device *dev)
+{
+	struct drm_encoder *encoder;
+
+	encoder = kzalloc(sizeof(struct drm_encoder), GFP_KERNEL);
+	if (!encoder)
+		return NULL;
+
+	drm_encoder_init(dev, encoder, &udl_enc_funcs, DRM_MODE_ENCODER_TMDS);
+	drm_encoder_helper_add(encoder, &udl_helper_funcs);
+	encoder->possible_crtcs = 1;
+	return encoder;
+}
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
new file mode 100644
index 0000000..4d9c3a5
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -0,0 +1,611 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ *
+ * based in parts on udlfb.c:
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "udl_drv.h"
+
+#include "drm_fb_helper.h"
+
+#define DL_DEFIO_WRITE_DELAY    5 /* fb_deferred_io.delay in jiffies */
+
+static int fb_defio = 1;  /* Optionally enable experimental fb_defio mmap support */
+static int fb_bpp = 16;
+
+module_param(fb_bpp, int, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
+module_param(fb_defio, int, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
+
+struct udl_fbdev {
+	struct drm_fb_helper helper;
+	struct udl_framebuffer ufb;
+	struct list_head fbdev_list;
+	int fb_count;
+};
+
+#define DL_ALIGN_UP(x, a) ALIGN(x, a)
+#define DL_ALIGN_DOWN(x, a) ALIGN(x-(a-1), a)
+
+/** Read the red component (0..255) of a 32 bpp colour. */
+#define DLO_RGB_GETRED(col) (uint8_t)((col) & 0xFF)
+
+/** Read the green component (0..255) of a 32 bpp colour. */
+#define DLO_RGB_GETGRN(col) (uint8_t)(((col) >> 8) & 0xFF)
+
+/** Read the blue component (0..255) of a 32 bpp colour. */
+#define DLO_RGB_GETBLU(col) (uint8_t)(((col) >> 16) & 0xFF)
+
+/** Return red/green component of a 16 bpp colour number. */
+#define DLO_RG16(red, grn) (uint8_t)((((red) & 0xF8) | ((grn) >> 5)) & 0xFF)
+
+/** Return green/blue component of a 16 bpp colour number. */
+#define DLO_GB16(grn, blu) (uint8_t)(((((grn) & 0x1C) << 3) | ((blu) >> 3)) & 0xFF)
+
+/** Return 8 bpp colour number from red, green and blue components. */
+#define DLO_RGB8(red, grn, blu) ((((red) << 5) | (((grn) & 3) << 3) | ((blu) & 7)) & 0xFF)
+
+#if 0
+static uint8_t rgb8(uint32_t col)
+{
+	uint8_t red = DLO_RGB_GETRED(col);
+	uint8_t grn = DLO_RGB_GETGRN(col);
+	uint8_t blu = DLO_RGB_GETBLU(col);
+
+	return DLO_RGB8(red, grn, blu);
+}
+
+static uint16_t rgb16(uint32_t col)
+{
+	uint8_t red = DLO_RGB_GETRED(col);
+	uint8_t grn = DLO_RGB_GETGRN(col);
+	uint8_t blu = DLO_RGB_GETBLU(col);
+
+	return (DLO_RG16(red, grn) << 8) + DLO_GB16(grn, blu);
+}
+#endif
+
+/*
+ * NOTE: fb_defio.c is holding info->fbdefio.mutex
+ *   Touching ANY framebuffer memory that triggers a page fault
+ *   in fb_defio will cause a deadlock, when it also tries to
+ *   grab the same mutex.
+ */
+static void udlfb_dpy_deferred_io(struct fb_info *info,
+				  struct list_head *pagelist)
+{
+	struct page *cur;
+	struct fb_deferred_io *fbdefio = info->fbdefio;
+	struct udl_fbdev *ufbdev = info->par;
+	struct drm_device *dev = ufbdev->ufb.base.dev;
+	struct udl_device *udl = dev->dev_private;
+	struct urb *urb;
+	char *cmd;
+	cycles_t start_cycles, end_cycles;
+	int bytes_sent = 0;
+	int bytes_identical = 0;
+	int bytes_rendered = 0;
+
+	if (!fb_defio)
+		return;
+
+	start_cycles = get_cycles();
+
+	urb = udl_get_urb(dev);
+	if (!urb)
+		return;
+
+	cmd = urb->transfer_buffer;
+
+	/* walk the written page list and render each to device */
+	list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+
+		if (udl_render_hline(dev, (ufbdev->ufb.base.bits_per_pixel / 8),
+				  &urb, (char *) info->fix.smem_start,
+				  &cmd, cur->index << PAGE_SHIFT,
+				  PAGE_SIZE, &bytes_identical, &bytes_sent))
+			goto error;
+		bytes_rendered += PAGE_SIZE;
+	}
+
+	if (cmd > (char *) urb->transfer_buffer) {
+		/* Send partial buffer remaining before exiting */
+		int len = cmd - (char *) urb->transfer_buffer;
+		udl_submit_urb(dev, urb, len);
+		bytes_sent += len;
+	} else
+		udl_urb_completion(urb);
+
+error:
+	atomic_add(bytes_sent, &udl->bytes_sent);
+	atomic_add(bytes_identical, &udl->bytes_identical);
+	atomic_add(bytes_rendered, &udl->bytes_rendered);
+	end_cycles = get_cycles();
+	atomic_add(((unsigned int) ((end_cycles - start_cycles)
+		    >> 10)), /* Kcycles */
+		   &udl->cpu_kcycles_used);
+}
+
+int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
+		      int width, int height)
+{
+	struct drm_device *dev = fb->base.dev;
+	struct udl_device *udl = dev->dev_private;
+	int i, ret;
+	char *cmd;
+	cycles_t start_cycles, end_cycles;
+	int bytes_sent = 0;
+	int bytes_identical = 0;
+	struct urb *urb;
+	int aligned_x;
+	int bpp = (fb->base.bits_per_pixel / 8);
+
+	if (!fb->active_16)
+		return 0;
+
+	if (!fb->obj->vmapping)
+		udl_gem_vmap(fb->obj);
+
+	start_cycles = get_cycles();
+
+	aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long));
+	width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long));
+	x = aligned_x;
+
+	if ((width <= 0) ||
+	    (x + width > fb->base.width) ||
+	    (y + height > fb->base.height))
+		return -EINVAL;
+
+	urb = udl_get_urb(dev);
+	if (!urb)
+		return 0;
+	cmd = urb->transfer_buffer;
+
+	for (i = y; i < y + height ; i++) {
+		const int line_offset = fb->base.pitches[0] * i;
+		const int byte_offset = line_offset + (x * bpp);
+
+		if (udl_render_hline(dev, bpp, &urb,
+				     (char *) fb->obj->vmapping,
+				     &cmd, byte_offset, width * bpp,
+				     &bytes_identical, &bytes_sent))
+			goto error;
+	}
+
+	if (cmd > (char *) urb->transfer_buffer) {
+		/* Send partial buffer remaining before exiting */
+		int len = cmd - (char *) urb->transfer_buffer;
+		ret = udl_submit_urb(dev, urb, len);
+		bytes_sent += len;
+	} else
+		udl_urb_completion(urb);
+
+error:
+	atomic_add(bytes_sent, &udl->bytes_sent);
+	atomic_add(bytes_identical, &udl->bytes_identical);
+	atomic_add(width*height*bpp, &udl->bytes_rendered);
+	end_cycles = get_cycles();
+	atomic_add(((unsigned int) ((end_cycles - start_cycles)
+		    >> 10)), /* Kcycles */
+		   &udl->cpu_kcycles_used);
+
+	return 0;
+}
+
+static int udl_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	unsigned long start = vma->vm_start;
+	unsigned long size = vma->vm_end - vma->vm_start;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	unsigned long page, pos;
+
+	if (offset + size > info->fix.smem_len)
+		return -EINVAL;
+
+	pos = (unsigned long)info->fix.smem_start + offset;
+
+	pr_notice("mmap() framebuffer addr:%lu size:%lu\n",
+		  pos, size);
+
+	while (size > 0) {
+		page = vmalloc_to_pfn((void *)pos);
+		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+			return -EAGAIN;
+
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+
+	vma->vm_flags |= VM_RESERVED;	/* avoid to swap out this VMA */
+	return 0;
+}
+
+static void udl_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	struct udl_fbdev *ufbdev = info->par;
+
+	sys_fillrect(info, rect);
+
+	udl_handle_damage(&ufbdev->ufb, rect->dx, rect->dy, rect->width,
+			  rect->height);
+}
+
+static void udl_fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
+{
+	struct udl_fbdev *ufbdev = info->par;
+
+	sys_copyarea(info, region);
+
+	udl_handle_damage(&ufbdev->ufb, region->dx, region->dy, region->width,
+			  region->height);
+}
+
+static void udl_fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	struct udl_fbdev *ufbdev = info->par;
+
+	sys_imageblit(info, image);
+
+	udl_handle_damage(&ufbdev->ufb, image->dx, image->dy, image->width,
+			  image->height);
+}
+
+/*
+ * It's common for several clients to have framebuffer open simultaneously.
+ * e.g. both fbcon and X. Makes things interesting.
+ * Assumes caller is holding info->lock (for open and release at least)
+ */
+static int udl_fb_open(struct fb_info *info, int user)
+{
+	struct udl_fbdev *ufbdev = info->par;
+	struct drm_device *dev = ufbdev->ufb.base.dev;
+	struct udl_device *udl = dev->dev_private;
+
+	/* If the USB device is gone, we don't accept new opens */
+	if (drm_device_is_unplugged(udl->ddev))
+		return -ENODEV;
+
+	ufbdev->fb_count++;
+
+	if (fb_defio && (info->fbdefio == NULL)) {
+		/* enable defio at last moment if not disabled by client */
+
+		struct fb_deferred_io *fbdefio;
+
+		fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
+
+		if (fbdefio) {
+			fbdefio->delay = DL_DEFIO_WRITE_DELAY;
+			fbdefio->deferred_io = udlfb_dpy_deferred_io;
+		}
+
+		info->fbdefio = fbdefio;
+		fb_deferred_io_init(info);
+	}
+
+	pr_notice("open /dev/fb%d user=%d fb_info=%p count=%d\n",
+		  info->node, user, info, ufbdev->fb_count);
+
+	return 0;
+}
+
+
+/*
+ * Assumes caller is holding info->lock mutex (for open and release at least)
+ */
+static int udl_fb_release(struct fb_info *info, int user)
+{
+	struct udl_fbdev *ufbdev = info->par;
+
+	ufbdev->fb_count--;
+
+	if ((ufbdev->fb_count == 0) && (info->fbdefio)) {
+		fb_deferred_io_cleanup(info);
+		kfree(info->fbdefio);
+		info->fbdefio = NULL;
+		info->fbops->fb_mmap = udl_fb_mmap;
+	}
+
+	pr_warn("released /dev/fb%d user=%d count=%d\n",
+		info->node, user, ufbdev->fb_count);
+
+	return 0;
+}
+
+static struct fb_ops udlfb_ops = {
+	.owner = THIS_MODULE,
+	.fb_check_var = drm_fb_helper_check_var,
+	.fb_set_par = drm_fb_helper_set_par,
+	.fb_fillrect = udl_fb_fillrect,
+	.fb_copyarea = udl_fb_copyarea,
+	.fb_imageblit = udl_fb_imageblit,
+	.fb_pan_display = drm_fb_helper_pan_display,
+	.fb_blank = drm_fb_helper_blank,
+	.fb_setcmap = drm_fb_helper_setcmap,
+	.fb_debug_enter = drm_fb_helper_debug_enter,
+	.fb_debug_leave = drm_fb_helper_debug_leave,
+	.fb_mmap = udl_fb_mmap,
+	.fb_open = udl_fb_open,
+	.fb_release = udl_fb_release,
+};
+
+void udl_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+			   u16 blue, int regno)
+{
+}
+
+void udl_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+			     u16 *blue, int regno)
+{
+	*red = 0;
+	*green = 0;
+	*blue = 0;
+}
+
+static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb,
+				      struct drm_file *file,
+				      unsigned flags, unsigned color,
+				      struct drm_clip_rect *clips,
+				      unsigned num_clips)
+{
+	struct udl_framebuffer *ufb = to_udl_fb(fb);
+	int i;
+
+	if (!ufb->active_16)
+		return 0;
+
+	for (i = 0; i < num_clips; i++) {
+		udl_handle_damage(ufb, clips[i].x1, clips[i].y1,
+				  clips[i].x2 - clips[i].x1,
+				  clips[i].y2 - clips[i].y1);
+	}
+	return 0;
+}
+
+static void udl_user_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+	struct udl_framebuffer *ufb = to_udl_fb(fb);
+
+	if (ufb->obj)
+		drm_gem_object_unreference_unlocked(&ufb->obj->base);
+
+	drm_framebuffer_cleanup(fb);
+	kfree(ufb);
+}
+
+static const struct drm_framebuffer_funcs udlfb_funcs = {
+	.destroy = udl_user_framebuffer_destroy,
+	.dirty = udl_user_framebuffer_dirty,
+	.create_handle = NULL,
+};
+
+
+static int
+udl_framebuffer_init(struct drm_device *dev,
+		     struct udl_framebuffer *ufb,
+		     struct drm_mode_fb_cmd2 *mode_cmd,
+		     struct udl_gem_object *obj)
+{
+	int ret;
+
+	ufb->obj = obj;
+	ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs);
+	drm_helper_mode_fill_fb_struct(&ufb->base, mode_cmd);
+	return ret;
+}
+
+
+static int udlfb_create(struct udl_fbdev *ufbdev,
+			struct drm_fb_helper_surface_size *sizes)
+{
+	struct drm_device *dev = ufbdev->helper.dev;
+	struct fb_info *info;
+	struct device *device = &dev->usbdev->dev;
+	struct drm_framebuffer *fb;
+	struct drm_mode_fb_cmd2 mode_cmd;
+	struct udl_gem_object *obj;
+	uint32_t size;
+	int ret = 0;
+
+	if (sizes->surface_bpp == 24)
+		sizes->surface_bpp = 32;
+
+	mode_cmd.width = sizes->surface_width;
+	mode_cmd.height = sizes->surface_height;
+	mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8);
+
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+							  sizes->surface_depth);
+
+	size = mode_cmd.pitches[0] * mode_cmd.height;
+	size = ALIGN(size, PAGE_SIZE);
+
+	obj = udl_gem_alloc_object(dev, size);
+	if (!obj)
+		goto out;
+
+	ret = udl_gem_vmap(obj);
+	if (ret) {
+		DRM_ERROR("failed to vmap fb\n");
+		goto out_gfree;
+	}
+
+	info = framebuffer_alloc(0, device);
+	if (!info) {
+		ret = -ENOMEM;
+		goto out_gfree;
+	}
+	info->par = ufbdev;
+
+	ret = udl_framebuffer_init(dev, &ufbdev->ufb, &mode_cmd, obj);
+	if (ret)
+		goto out_gfree;
+
+	fb = &ufbdev->ufb.base;
+
+	ufbdev->helper.fb = fb;
+	ufbdev->helper.fbdev = info;
+
+	strcpy(info->fix.id, "udldrmfb");
+
+	info->screen_base = ufbdev->ufb.obj->vmapping;
+	info->fix.smem_len = size;
+	info->fix.smem_start = (unsigned long)ufbdev->ufb.obj->vmapping;
+
+	info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
+	info->fbops = &udlfb_ops;
+	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+	drm_fb_helper_fill_var(info, &ufbdev->helper, sizes->fb_width, sizes->fb_height);
+
+	ret = fb_alloc_cmap(&info->cmap, 256, 0);
+	if (ret) {
+		ret = -ENOMEM;
+		goto out_gfree;
+	}
+
+
+	DRM_DEBUG_KMS("allocated %dx%d vmal %p\n",
+		      fb->width, fb->height,
+		      ufbdev->ufb.obj->vmapping);
+
+	return ret;
+out_gfree:
+	drm_gem_object_unreference(&ufbdev->ufb.obj->base);
+out:
+	return ret;
+}
+
+static int udl_fb_find_or_create_single(struct drm_fb_helper *helper,
+					struct drm_fb_helper_surface_size *sizes)
+{
+	struct udl_fbdev *ufbdev = (struct udl_fbdev *)helper;
+	int new_fb = 0;
+	int ret;
+
+	if (!helper->fb) {
+		ret = udlfb_create(ufbdev, sizes);
+		if (ret)
+			return ret;
+
+		new_fb = 1;
+	}
+	return new_fb;
+}
+
+static struct drm_fb_helper_funcs udl_fb_helper_funcs = {
+	.gamma_set = udl_crtc_fb_gamma_set,
+	.gamma_get = udl_crtc_fb_gamma_get,
+	.fb_probe = udl_fb_find_or_create_single,
+};
+
+static void udl_fbdev_destroy(struct drm_device *dev,
+			      struct udl_fbdev *ufbdev)
+{
+	struct fb_info *info;
+	if (ufbdev->helper.fbdev) {
+		info = ufbdev->helper.fbdev;
+		unregister_framebuffer(info);
+		if (info->cmap.len)
+			fb_dealloc_cmap(&info->cmap);
+		framebuffer_release(info);
+	}
+	drm_fb_helper_fini(&ufbdev->helper);
+	drm_framebuffer_cleanup(&ufbdev->ufb.base);
+	drm_gem_object_unreference_unlocked(&ufbdev->ufb.obj->base);
+}
+
+int udl_fbdev_init(struct drm_device *dev)
+{
+	struct udl_device *udl = dev->dev_private;
+	int bpp_sel = fb_bpp;
+	struct udl_fbdev *ufbdev;
+	int ret;
+
+	ufbdev = kzalloc(sizeof(struct udl_fbdev), GFP_KERNEL);
+	if (!ufbdev)
+		return -ENOMEM;
+
+	udl->fbdev = ufbdev;
+	ufbdev->helper.funcs = &udl_fb_helper_funcs;
+
+	ret = drm_fb_helper_init(dev, &ufbdev->helper,
+				 1, 1);
+	if (ret) {
+		kfree(ufbdev);
+		return ret;
+
+	}
+
+	drm_fb_helper_single_add_all_connectors(&ufbdev->helper);
+	drm_fb_helper_initial_config(&ufbdev->helper, bpp_sel);
+	return 0;
+}
+
+void udl_fbdev_cleanup(struct drm_device *dev)
+{
+	struct udl_device *udl = dev->dev_private;
+	if (!udl->fbdev)
+		return;
+
+	udl_fbdev_destroy(dev, udl->fbdev);
+	kfree(udl->fbdev);
+	udl->fbdev = NULL;
+}
+
+void udl_fbdev_unplug(struct drm_device *dev)
+{
+	struct udl_device *udl = dev->dev_private;
+	struct udl_fbdev *ufbdev;
+	if (!udl->fbdev)
+		return;
+
+	ufbdev = udl->fbdev;
+	if (ufbdev->helper.fbdev) {
+		struct fb_info *info;
+		info = ufbdev->helper.fbdev;
+		unlink_framebuffer(info);
+	}
+}
+
+struct drm_framebuffer *
+udl_fb_user_fb_create(struct drm_device *dev,
+		   struct drm_file *file,
+		   struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	struct drm_gem_object *obj;
+	struct udl_framebuffer *ufb;
+	int ret;
+
+	obj = drm_gem_object_lookup(dev, file, mode_cmd->handles[0]);
+	if (obj == NULL)
+		return ERR_PTR(-ENOENT);
+
+	ufb = kzalloc(sizeof(*ufb), GFP_KERNEL);
+	if (ufb == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	ret = udl_framebuffer_init(dev, ufb, mode_cmd, to_udl_bo(obj));
+	if (ret) {
+		kfree(ufb);
+		return ERR_PTR(-EINVAL);
+	}
+	return &ufb->base;
+}
diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c
new file mode 100644
index 0000000..92f19ef
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_gem.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include "drmP.h"
+#include "udl_drv.h"
+#include <linux/shmem_fs.h>
+
+struct udl_gem_object *udl_gem_alloc_object(struct drm_device *dev,
+					    size_t size)
+{
+	struct udl_gem_object *obj;
+
+	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+	if (obj == NULL)
+		return NULL;
+
+	if (drm_gem_object_init(dev, &obj->base, size) != 0) {
+		kfree(obj);
+		return NULL;
+	}
+
+	return obj;
+}
+
+static int
+udl_gem_create(struct drm_file *file,
+	       struct drm_device *dev,
+	       uint64_t size,
+	       uint32_t *handle_p)
+{
+	struct udl_gem_object *obj;
+	int ret;
+	u32 handle;
+
+	size = roundup(size, PAGE_SIZE);
+
+	obj = udl_gem_alloc_object(dev, size);
+	if (obj == NULL)
+		return -ENOMEM;
+
+	ret = drm_gem_handle_create(file, &obj->base, &handle);
+	if (ret) {
+		drm_gem_object_release(&obj->base);
+		kfree(obj);
+		return ret;
+	}
+
+	drm_gem_object_unreference(&obj->base);
+	*handle_p = handle;
+	return 0;
+}
+
+int udl_dumb_create(struct drm_file *file,
+		    struct drm_device *dev,
+		    struct drm_mode_create_dumb *args)
+{
+	args->pitch = args->width * ((args->bpp + 1) / 8);
+	args->size = args->pitch * args->height;
+	return udl_gem_create(file, dev,
+			      args->size, &args->handle);
+}
+
+int udl_dumb_destroy(struct drm_file *file, struct drm_device *dev,
+		     uint32_t handle)
+{
+	return drm_gem_handle_delete(file, handle);
+}
+
+int udl_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	int ret;
+
+	ret = drm_gem_mmap(filp, vma);
+	if (ret)
+		return ret;
+
+	vma->vm_flags &= ~VM_PFNMAP;
+	vma->vm_flags |= VM_MIXEDMAP;
+
+	return ret;
+}
+
+int udl_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+	struct udl_gem_object *obj = to_udl_bo(vma->vm_private_data);
+	struct page *page;
+	unsigned int page_offset;
+	int ret = 0;
+
+	page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >>
+		PAGE_SHIFT;
+
+	if (!obj->pages)
+		return VM_FAULT_SIGBUS;
+
+	page = obj->pages[page_offset];
+	ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page);
+	switch (ret) {
+	case -EAGAIN:
+		set_need_resched();
+	case 0:
+	case -ERESTARTSYS:
+		return VM_FAULT_NOPAGE;
+	case -ENOMEM:
+		return VM_FAULT_OOM;
+	default:
+		return VM_FAULT_SIGBUS;
+	}
+}
+
+int udl_gem_init_object(struct drm_gem_object *obj)
+{
+	BUG();
+
+	return 0;
+}
+
+static int udl_gem_get_pages(struct udl_gem_object *obj, gfp_t gfpmask)
+{
+	int page_count, i;
+	struct page *page;
+	struct inode *inode;
+	struct address_space *mapping;
+
+	if (obj->pages)
+		return 0;
+
+	page_count = obj->base.size / PAGE_SIZE;
+	BUG_ON(obj->pages != NULL);
+	obj->pages = drm_malloc_ab(page_count, sizeof(struct page *));
+	if (obj->pages == NULL)
+		return -ENOMEM;
+
+	inode = obj->base.filp->f_path.dentry->d_inode;
+	mapping = inode->i_mapping;
+	gfpmask |= mapping_gfp_mask(mapping);
+
+	for (i = 0; i < page_count; i++) {
+		page = shmem_read_mapping_page_gfp(mapping, i, gfpmask);
+		if (IS_ERR(page))
+			goto err_pages;
+		obj->pages[i] = page;
+	}
+
+	return 0;
+err_pages:
+	while (i--)
+		page_cache_release(obj->pages[i]);
+	drm_free_large(obj->pages);
+	obj->pages = NULL;
+	return PTR_ERR(page);
+}
+
+static void udl_gem_put_pages(struct udl_gem_object *obj)
+{
+	int page_count = obj->base.size / PAGE_SIZE;
+	int i;
+
+	for (i = 0; i < page_count; i++)
+		page_cache_release(obj->pages[i]);
+
+	drm_free_large(obj->pages);
+	obj->pages = NULL;
+}
+
+int udl_gem_vmap(struct udl_gem_object *obj)
+{
+	int page_count = obj->base.size / PAGE_SIZE;
+	int ret;
+
+	ret = udl_gem_get_pages(obj, GFP_KERNEL);
+	if (ret)
+		return ret;
+
+	obj->vmapping = vmap(obj->pages, page_count, 0, PAGE_KERNEL);
+	if (!obj->vmapping)
+		return -ENOMEM;
+	return 0;
+}
+
+void udl_gem_vunmap(struct udl_gem_object *obj)
+{
+	if (obj->vmapping)
+		vunmap(obj->vmapping);
+
+	udl_gem_put_pages(obj);
+}
+
+void udl_gem_free_object(struct drm_gem_object *gem_obj)
+{
+	struct udl_gem_object *obj = to_udl_bo(gem_obj);
+
+	if (obj->vmapping)
+		udl_gem_vunmap(obj);
+
+	if (obj->pages)
+		udl_gem_put_pages(obj);
+
+	if (gem_obj->map_list.map)
+		drm_gem_free_mmap_offset(gem_obj);
+}
+
+/* the dumb interface doesn't work with the GEM straight MMAP
+   interface, it expects to do MMAP on the drm fd, like normal */
+int udl_gem_mmap(struct drm_file *file, struct drm_device *dev,
+		 uint32_t handle, uint64_t *offset)
+{
+	struct udl_gem_object *gobj;
+	struct drm_gem_object *obj;
+	int ret = 0;
+
+	mutex_lock(&dev->struct_mutex);
+	obj = drm_gem_object_lookup(dev, file, handle);
+	if (obj == NULL) {
+		ret = -ENOENT;
+		goto unlock;
+	}
+	gobj = to_udl_bo(obj);
+
+	ret = udl_gem_get_pages(gobj, GFP_KERNEL);
+	if (ret)
+		return ret;
+	if (!gobj->base.map_list.map) {
+		ret = drm_gem_create_mmap_offset(obj);
+		if (ret)
+			goto out;
+	}
+
+	*offset = (u64)gobj->base.map_list.hash.key << PAGE_SHIFT;
+
+out:
+	drm_gem_object_unreference(&gobj->base);
+unlock:
+	mutex_unlock(&dev->struct_mutex);
+	return ret;
+}
diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
new file mode 100644
index 0000000..a8d5f09
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ *
+ * based in parts on udlfb.c:
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+#include "drmP.h"
+#include "udl_drv.h"
+
+/* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */
+#define BULK_SIZE 512
+
+#define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE)
+#define WRITES_IN_FLIGHT (4)
+#define MAX_VENDOR_DESCRIPTOR_SIZE 256
+
+#define GET_URB_TIMEOUT	HZ
+#define FREE_URB_TIMEOUT (HZ*2)
+
+static int udl_parse_vendor_descriptor(struct drm_device *dev,
+				       struct usb_device *usbdev)
+{
+	struct udl_device *udl = dev->dev_private;
+	char *desc;
+	char *buf;
+	char *desc_end;
+
+	u8 total_len = 0;
+
+	buf = kzalloc(MAX_VENDOR_DESCRIPTOR_SIZE, GFP_KERNEL);
+	if (!buf)
+		return false;
+	desc = buf;
+
+	total_len = usb_get_descriptor(usbdev, 0x5f, /* vendor specific */
+				    0, desc, MAX_VENDOR_DESCRIPTOR_SIZE);
+	if (total_len > 5) {
+		DRM_INFO("vendor descriptor length:%x data:%02x %02x %02x %02x" \
+			"%02x %02x %02x %02x %02x %02x %02x\n",
+			total_len, desc[0],
+			desc[1], desc[2], desc[3], desc[4], desc[5], desc[6],
+			desc[7], desc[8], desc[9], desc[10]);
+
+		if ((desc[0] != total_len) || /* descriptor length */
+		    (desc[1] != 0x5f) ||   /* vendor descriptor type */
+		    (desc[2] != 0x01) ||   /* version (2 bytes) */
+		    (desc[3] != 0x00) ||
+		    (desc[4] != total_len - 2)) /* length after type */
+			goto unrecognized;
+
+		desc_end = desc + total_len;
+		desc += 5; /* the fixed header we've already parsed */
+
+		while (desc < desc_end) {
+			u8 length;
+			u16 key;
+
+			key = *((u16 *) desc);
+			desc += sizeof(u16);
+			length = *desc;
+			desc++;
+
+			switch (key) {
+			case 0x0200: { /* max_area */
+				u32 max_area;
+				max_area = le32_to_cpu(*((u32 *)desc));
+				DRM_DEBUG("DL chip limited to %d pixel modes\n",
+					max_area);
+				udl->sku_pixel_limit = max_area;
+				break;
+			}
+			default:
+				break;
+			}
+			desc += length;
+		}
+	}
+
+	goto success;
+
+unrecognized:
+	/* allow udlfb to load for now even if firmware unrecognized */
+	DRM_ERROR("Unrecognized vendor firmware descriptor\n");
+
+success:
+	kfree(buf);
+	return true;
+}
+
+static void udl_release_urb_work(struct work_struct *work)
+{
+	struct urb_node *unode = container_of(work, struct urb_node,
+					      release_urb_work.work);
+
+	up(&unode->dev->urbs.limit_sem);
+}
+
+void udl_urb_completion(struct urb *urb)
+{
+	struct urb_node *unode = urb->context;
+	struct udl_device *udl = unode->dev;
+	unsigned long flags;
+
+	/* sync/async unlink faults aren't errors */
+	if (urb->status) {
+		if (!(urb->status == -ENOENT ||
+		    urb->status == -ECONNRESET ||
+		    urb->status == -ESHUTDOWN)) {
+			DRM_ERROR("%s - nonzero write bulk status received: %d\n",
+				__func__, urb->status);
+			atomic_set(&udl->lost_pixels, 1);
+		}
+	}
+
+	urb->transfer_buffer_length = udl->urbs.size; /* reset to actual */
+
+	spin_lock_irqsave(&udl->urbs.lock, flags);
+	list_add_tail(&unode->entry, &udl->urbs.list);
+	udl->urbs.available++;
+	spin_unlock_irqrestore(&udl->urbs.lock, flags);
+
+#if 0
+	/*
+	 * When using fb_defio, we deadlock if up() is called
+	 * while another is waiting. So queue to another process.
+	 */
+	if (fb_defio)
+		schedule_delayed_work(&unode->release_urb_work, 0);
+	else
+#endif
+		up(&udl->urbs.limit_sem);
+}
+
+static void udl_free_urb_list(struct drm_device *dev)
+{
+	struct udl_device *udl = dev->dev_private;
+	int count = udl->urbs.count;
+	struct list_head *node;
+	struct urb_node *unode;
+	struct urb *urb;
+	int ret;
+	unsigned long flags;
+
+	DRM_DEBUG("Waiting for completes and freeing all render urbs\n");
+
+	/* keep waiting and freeing, until we've got 'em all */
+	while (count--) {
+
+		/* Getting interrupted means a leak, but ok at shutdown*/
+		ret = down_interruptible(&udl->urbs.limit_sem);
+		if (ret)
+			break;
+
+		spin_lock_irqsave(&udl->urbs.lock, flags);
+
+		node = udl->urbs.list.next; /* have reserved one with sem */
+		list_del_init(node);
+
+		spin_unlock_irqrestore(&udl->urbs.lock, flags);
+
+		unode = list_entry(node, struct urb_node, entry);
+		urb = unode->urb;
+
+		/* Free each separately allocated piece */
+		usb_free_coherent(urb->dev, udl->urbs.size,
+				  urb->transfer_buffer, urb->transfer_dma);
+		usb_free_urb(urb);
+		kfree(node);
+	}
+	udl->urbs.count = 0;
+}
+
+static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
+{
+	struct udl_device *udl = dev->dev_private;
+	int i = 0;
+	struct urb *urb;
+	struct urb_node *unode;
+	char *buf;
+
+	spin_lock_init(&udl->urbs.lock);
+
+	udl->urbs.size = size;
+	INIT_LIST_HEAD(&udl->urbs.list);
+
+	while (i < count) {
+		unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL);
+		if (!unode)
+			break;
+		unode->dev = udl;
+
+		INIT_DELAYED_WORK(&unode->release_urb_work,
+			  udl_release_urb_work);
+
+		urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!urb) {
+			kfree(unode);
+			break;
+		}
+		unode->urb = urb;
+
+		buf = usb_alloc_coherent(udl->ddev->usbdev, MAX_TRANSFER, GFP_KERNEL,
+					 &urb->transfer_dma);
+		if (!buf) {
+			kfree(unode);
+			usb_free_urb(urb);
+			break;
+		}
+
+		/* urb->transfer_buffer_length set to actual before submit */
+		usb_fill_bulk_urb(urb, udl->ddev->usbdev, usb_sndbulkpipe(udl->ddev->usbdev, 1),
+			buf, size, udl_urb_completion, unode);
+		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+		list_add_tail(&unode->entry, &udl->urbs.list);
+
+		i++;
+	}
+
+	sema_init(&udl->urbs.limit_sem, i);
+	udl->urbs.count = i;
+	udl->urbs.available = i;
+
+	DRM_DEBUG("allocated %d %d byte urbs\n", i, (int) size);
+
+	return i;
+}
+
+struct urb *udl_get_urb(struct drm_device *dev)
+{
+	struct udl_device *udl = dev->dev_private;
+	int ret = 0;
+	struct list_head *entry;
+	struct urb_node *unode;
+	struct urb *urb = NULL;
+	unsigned long flags;
+
+	/* Wait for an in-flight buffer to complete and get re-queued */
+	ret = down_timeout(&udl->urbs.limit_sem, GET_URB_TIMEOUT);
+	if (ret) {
+		atomic_set(&udl->lost_pixels, 1);
+		DRM_INFO("wait for urb interrupted: %x available: %d\n",
+		       ret, udl->urbs.available);
+		goto error;
+	}
+
+	spin_lock_irqsave(&udl->urbs.lock, flags);
+
+	BUG_ON(list_empty(&udl->urbs.list)); /* reserved one with limit_sem */
+	entry = udl->urbs.list.next;
+	list_del_init(entry);
+	udl->urbs.available--;
+
+	spin_unlock_irqrestore(&udl->urbs.lock, flags);
+
+	unode = list_entry(entry, struct urb_node, entry);
+	urb = unode->urb;
+
+error:
+	return urb;
+}
+
+int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len)
+{
+	struct udl_device *udl = dev->dev_private;
+	int ret;
+
+	BUG_ON(len > udl->urbs.size);
+
+	urb->transfer_buffer_length = len; /* set to actual payload len */
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	if (ret) {
+		udl_urb_completion(urb); /* because no one else will */
+		atomic_set(&udl->lost_pixels, 1);
+		DRM_ERROR("usb_submit_urb error %x\n", ret);
+	}
+	return ret;
+}
+
+int udl_driver_load(struct drm_device *dev, unsigned long flags)
+{
+	struct udl_device *udl;
+	int ret;
+
+	DRM_DEBUG("\n");
+	udl = kzalloc(sizeof(struct udl_device), GFP_KERNEL);
+	if (!udl)
+		return -ENOMEM;
+
+	udl->ddev = dev;
+	dev->dev_private = udl;
+
+	if (!udl_parse_vendor_descriptor(dev, dev->usbdev)) {
+		DRM_ERROR("firmware not recognized. Assume incompatible device\n");
+		goto err;
+	}
+
+	if (!udl_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
+		ret = -ENOMEM;
+		DRM_ERROR("udl_alloc_urb_list failed\n");
+		goto err;
+	}
+
+	DRM_DEBUG("\n");
+	ret = udl_modeset_init(dev);
+
+	ret = udl_fbdev_init(dev);
+	return 0;
+err:
+	kfree(udl);
+	DRM_ERROR("%d\n", ret);
+	return ret;
+}
+
+int udl_drop_usb(struct drm_device *dev)
+{
+	udl_free_urb_list(dev);
+	return 0;
+}
+
+int udl_driver_unload(struct drm_device *dev)
+{
+	struct udl_device *udl = dev->dev_private;
+
+	if (udl->urbs.count)
+		udl_free_urb_list(dev);
+
+	udl_fbdev_cleanup(dev);
+	udl_modeset_cleanup(dev);
+	kfree(udl);
+	return 0;
+}
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
new file mode 100644
index 0000000..b3ecb3d
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ *
+ * based in parts on udlfb.c:
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "udl_drv.h"
+
+/*
+ * All DisplayLink bulk operations start with 0xAF, followed by specific code
+ * All operations are written to buffers which then later get sent to device
+ */
+static char *udl_set_register(char *buf, u8 reg, u8 val)
+{
+	*buf++ = 0xAF;
+	*buf++ = 0x20;
+	*buf++ = reg;
+	*buf++ = val;
+	return buf;
+}
+
+static char *udl_vidreg_lock(char *buf)
+{
+	return udl_set_register(buf, 0xFF, 0x00);
+}
+
+static char *udl_vidreg_unlock(char *buf)
+{
+	return udl_set_register(buf, 0xFF, 0xFF);
+}
+
+/*
+ * On/Off for driving the DisplayLink framebuffer to the display
+ *  0x00 H and V sync on
+ *  0x01 H and V sync off (screen blank but powered)
+ *  0x07 DPMS powerdown (requires modeset to come back)
+ */
+static char *udl_enable_hvsync(char *buf, bool enable)
+{
+	if (enable)
+		return udl_set_register(buf, 0x1F, 0x00);
+	else
+		return udl_set_register(buf, 0x1F, 0x07);
+}
+
+static char *udl_set_color_depth(char *buf, u8 selection)
+{
+	return udl_set_register(buf, 0x00, selection);
+}
+
+static char *udl_set_base16bpp(char *wrptr, u32 base)
+{
+	/* the base pointer is 16 bits wide, 0x20 is hi byte. */
+	wrptr = udl_set_register(wrptr, 0x20, base >> 16);
+	wrptr = udl_set_register(wrptr, 0x21, base >> 8);
+	return udl_set_register(wrptr, 0x22, base);
+}
+
+/*
+ * DisplayLink HW has separate 16bpp and 8bpp framebuffers.
+ * In 24bpp modes, the low 323 RGB bits go in the 8bpp framebuffer
+ */
+static char *udl_set_base8bpp(char *wrptr, u32 base)
+{
+	wrptr = udl_set_register(wrptr, 0x26, base >> 16);
+	wrptr = udl_set_register(wrptr, 0x27, base >> 8);
+	return udl_set_register(wrptr, 0x28, base);
+}
+
+static char *udl_set_register_16(char *wrptr, u8 reg, u16 value)
+{
+	wrptr = udl_set_register(wrptr, reg, value >> 8);
+	return udl_set_register(wrptr, reg+1, value);
+}
+
+/*
+ * This is kind of weird because the controller takes some
+ * register values in a different byte order than other registers.
+ */
+static char *udl_set_register_16be(char *wrptr, u8 reg, u16 value)
+{
+	wrptr = udl_set_register(wrptr, reg, value);
+	return udl_set_register(wrptr, reg+1, value >> 8);
+}
+
+/*
+ * LFSR is linear feedback shift register. The reason we have this is
+ * because the display controller needs to minimize the clock depth of
+ * various counters used in the display path. So this code reverses the
+ * provided value into the lfsr16 value by counting backwards to get
+ * the value that needs to be set in the hardware comparator to get the
+ * same actual count. This makes sense once you read above a couple of
+ * times and think about it from a hardware perspective.
+ */
+static u16 udl_lfsr16(u16 actual_count)
+{
+	u32 lv = 0xFFFF; /* This is the lfsr value that the hw starts with */
+
+	while (actual_count--) {
+		lv =	 ((lv << 1) |
+			(((lv >> 15) ^ (lv >> 4) ^ (lv >> 2) ^ (lv >> 1)) & 1))
+			& 0xFFFF;
+	}
+
+	return (u16) lv;
+}
+
+/*
+ * This does LFSR conversion on the value that is to be written.
+ * See LFSR explanation above for more detail.
+ */
+static char *udl_set_register_lfsr16(char *wrptr, u8 reg, u16 value)
+{
+	return udl_set_register_16(wrptr, reg, udl_lfsr16(value));
+}
+
+/*
+ * This takes a standard fbdev screeninfo struct and all of its monitor mode
+ * details and converts them into the DisplayLink equivalent register commands.
+  ERR(vreg(dev,               0x00, (color_depth == 16) ? 0 : 1));
+  ERR(vreg_lfsr16(dev,        0x01, xDisplayStart));
+  ERR(vreg_lfsr16(dev,        0x03, xDisplayEnd));
+  ERR(vreg_lfsr16(dev,        0x05, yDisplayStart));
+  ERR(vreg_lfsr16(dev,        0x07, yDisplayEnd));
+  ERR(vreg_lfsr16(dev,        0x09, xEndCount));
+  ERR(vreg_lfsr16(dev,        0x0B, hSyncStart));
+  ERR(vreg_lfsr16(dev,        0x0D, hSyncEnd));
+  ERR(vreg_big_endian(dev,    0x0F, hPixels));
+  ERR(vreg_lfsr16(dev,        0x11, yEndCount));
+  ERR(vreg_lfsr16(dev,        0x13, vSyncStart));
+  ERR(vreg_lfsr16(dev,        0x15, vSyncEnd));
+  ERR(vreg_big_endian(dev,    0x17, vPixels));
+  ERR(vreg_little_endian(dev, 0x1B, pixelClock5KHz));
+
+  ERR(vreg(dev,               0x1F, 0));
+
+  ERR(vbuf(dev, WRITE_VIDREG_UNLOCK, DSIZEOF(WRITE_VIDREG_UNLOCK)));
+ */
+static char *udl_set_vid_cmds(char *wrptr, struct drm_display_mode *mode)
+{
+	u16 xds, yds;
+	u16 xde, yde;
+	u16 yec;
+
+	/* x display start */
+	xds = mode->crtc_htotal - mode->crtc_hsync_start;
+	wrptr = udl_set_register_lfsr16(wrptr, 0x01, xds);
+	/* x display end */
+	xde = xds + mode->crtc_hdisplay;
+	wrptr = udl_set_register_lfsr16(wrptr, 0x03, xde);
+
+	/* y display start */
+	yds = mode->crtc_vtotal - mode->crtc_vsync_start;
+	wrptr = udl_set_register_lfsr16(wrptr, 0x05, yds);
+	/* y display end */
+	yde = yds + mode->crtc_vdisplay;
+	wrptr = udl_set_register_lfsr16(wrptr, 0x07, yde);
+
+	/* x end count is active + blanking - 1 */
+	wrptr = udl_set_register_lfsr16(wrptr, 0x09,
+					mode->crtc_htotal - 1);
+
+	/* libdlo hardcodes hsync start to 1 */
+	wrptr = udl_set_register_lfsr16(wrptr, 0x0B, 1);
+
+	/* hsync end is width of sync pulse + 1 */
+	wrptr = udl_set_register_lfsr16(wrptr, 0x0D,
+					mode->crtc_hsync_end - mode->crtc_hsync_start + 1);
+
+	/* hpixels is active pixels */
+	wrptr = udl_set_register_16(wrptr, 0x0F, mode->hdisplay);
+
+	/* yendcount is vertical active + vertical blanking */
+	yec = mode->crtc_vtotal;
+	wrptr = udl_set_register_lfsr16(wrptr, 0x11, yec);
+
+	/* libdlo hardcodes vsync start to 0 */
+	wrptr = udl_set_register_lfsr16(wrptr, 0x13, 0);
+
+	/* vsync end is width of vsync pulse */
+	wrptr = udl_set_register_lfsr16(wrptr, 0x15, mode->crtc_vsync_end - mode->crtc_vsync_start);
+
+	/* vpixels is active pixels */
+	wrptr = udl_set_register_16(wrptr, 0x17, mode->crtc_vdisplay);
+
+	wrptr = udl_set_register_16be(wrptr, 0x1B,
+				      mode->clock / 5);
+
+	return wrptr;
+}
+
+static int udl_crtc_write_mode_to_hw(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct udl_device *udl = dev->dev_private;
+	struct urb *urb;
+	char *buf;
+	int retval;
+
+	urb = udl_get_urb(dev);
+	if (!urb)
+		return -ENOMEM;
+
+	buf = (char *)urb->transfer_buffer;
+
+	memcpy(buf, udl->mode_buf, udl->mode_buf_len);
+	retval = udl_submit_urb(dev, urb, udl->mode_buf_len);
+	DRM_INFO("write mode info %d\n", udl->mode_buf_len);
+	return retval;
+}
+
+
+static void udl_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+	struct drm_device *dev = crtc->dev;
+	struct udl_device *udl = dev->dev_private;
+	int retval;
+
+	if (mode == DRM_MODE_DPMS_OFF) {
+		char *buf;
+		struct urb *urb;
+		urb = udl_get_urb(dev);
+		if (!urb)
+			return;
+
+		buf = (char *)urb->transfer_buffer;
+		buf = udl_vidreg_lock(buf);
+		buf = udl_enable_hvsync(buf, false);
+		buf = udl_vidreg_unlock(buf);
+
+		retval = udl_submit_urb(dev, urb, buf - (char *)
+					urb->transfer_buffer);
+	} else {
+		if (udl->mode_buf_len == 0) {
+			DRM_ERROR("Trying to enable DPMS with no mode\n");
+			return;
+		}
+		udl_crtc_write_mode_to_hw(crtc);
+	}
+
+}
+
+static bool udl_crtc_mode_fixup(struct drm_crtc *crtc,
+				  struct drm_display_mode *mode,
+				  struct drm_display_mode *adjusted_mode)
+
+{
+	return true;
+}
+
+#if 0
+static int
+udl_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+			   int x, int y, enum mode_set_atomic state)
+{
+	return 0;
+}
+
+static int
+udl_pipe_set_base(struct drm_crtc *crtc, int x, int y,
+		    struct drm_framebuffer *old_fb)
+{
+	return 0;
+}
+#endif
+
+static int udl_crtc_mode_set(struct drm_crtc *crtc,
+			       struct drm_display_mode *mode,
+			       struct drm_display_mode *adjusted_mode,
+			       int x, int y,
+			       struct drm_framebuffer *old_fb)
+
+{
+	struct drm_device *dev = crtc->dev;
+	struct udl_framebuffer *ufb = to_udl_fb(crtc->fb);
+	struct udl_device *udl = dev->dev_private;
+	char *buf;
+	char *wrptr;
+	int color_depth = 0;
+
+	buf = (char *)udl->mode_buf;
+
+	/* for now we just clip 24 -> 16 - if we fix that fix this */
+	/*if  (crtc->fb->bits_per_pixel != 16)
+	  color_depth = 1; */
+
+	/* This first section has to do with setting the base address on the
+	* controller * associated with the display. There are 2 base
+	* pointers, currently, we only * use the 16 bpp segment.
+	*/
+	wrptr = udl_vidreg_lock(buf);
+	wrptr = udl_set_color_depth(wrptr, color_depth);
+	/* set base for 16bpp segment to 0 */
+	wrptr = udl_set_base16bpp(wrptr, 0);
+	/* set base for 8bpp segment to end of fb */
+	wrptr = udl_set_base8bpp(wrptr, 2 * mode->vdisplay * mode->hdisplay);
+
+	wrptr = udl_set_vid_cmds(wrptr, adjusted_mode);
+	wrptr = udl_enable_hvsync(wrptr, true);
+	wrptr = udl_vidreg_unlock(wrptr);
+
+	ufb->active_16 = true;
+	if (old_fb) {
+		struct udl_framebuffer *uold_fb = to_udl_fb(old_fb);
+		uold_fb->active_16 = false;
+	}
+	udl->mode_buf_len = wrptr - buf;
+
+	/* damage all of it */
+	udl_handle_damage(ufb, 0, 0, ufb->base.width, ufb->base.height);
+	return 0;
+}
+
+
+static void udl_crtc_disable(struct drm_crtc *crtc)
+{
+
+
+}
+
+static void udl_crtc_destroy(struct drm_crtc *crtc)
+{
+	drm_crtc_cleanup(crtc);
+	kfree(crtc);
+}
+
+static void udl_load_lut(struct drm_crtc *crtc)
+{
+}
+
+static void udl_crtc_prepare(struct drm_crtc *crtc)
+{
+}
+
+static void udl_crtc_commit(struct drm_crtc *crtc)
+{
+	udl_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+}
+
+static struct drm_crtc_helper_funcs udl_helper_funcs = {
+	.dpms = udl_crtc_dpms,
+	.mode_fixup = udl_crtc_mode_fixup,
+	.mode_set = udl_crtc_mode_set,
+	.prepare = udl_crtc_prepare,
+	.commit = udl_crtc_commit,
+	.disable = udl_crtc_disable,
+	.load_lut = udl_load_lut,
+};
+
+static const struct drm_crtc_funcs udl_crtc_funcs = {
+	.set_config = drm_crtc_helper_set_config,
+	.destroy = udl_crtc_destroy,
+};
+
+int udl_crtc_init(struct drm_device *dev)
+{
+	struct drm_crtc *crtc;
+
+	crtc = kzalloc(sizeof(struct drm_crtc) + sizeof(struct drm_connector *), GFP_KERNEL);
+	if (crtc == NULL)
+		return -ENOMEM;
+
+	drm_crtc_init(dev, crtc, &udl_crtc_funcs);
+	drm_crtc_helper_add(crtc, &udl_helper_funcs);
+
+	return 0;
+}
+
+static const struct drm_mode_config_funcs udl_mode_funcs = {
+	.fb_create = udl_fb_user_fb_create,
+	.output_poll_changed = NULL,
+};
+
+int udl_modeset_init(struct drm_device *dev)
+{
+	struct drm_encoder *encoder;
+	drm_mode_config_init(dev);
+
+	dev->mode_config.min_width = 640;
+	dev->mode_config.min_height = 480;
+
+	dev->mode_config.max_width = 2048;
+	dev->mode_config.max_height = 2048;
+
+	dev->mode_config.prefer_shadow = 0;
+	dev->mode_config.preferred_depth = 24;
+
+	dev->mode_config.funcs = (void *)&udl_mode_funcs;
+
+	drm_mode_create_dirty_info_property(dev);
+
+	udl_crtc_init(dev);
+
+	encoder = udl_encoder_init(dev);
+
+	udl_connector_init(dev, encoder);
+
+	return 0;
+}
+
+void udl_modeset_cleanup(struct drm_device *dev)
+{
+	drm_mode_config_cleanup(dev);
+}
diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c
new file mode 100644
index 0000000..b9320e2
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_transfer.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ * based in parts on udlfb.c:
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/prefetch.h>
+
+#include "drmP.h"
+#include "udl_drv.h"
+
+#define MAX_CMD_PIXELS		255
+
+#define RLX_HEADER_BYTES	7
+#define MIN_RLX_PIX_BYTES       4
+#define MIN_RLX_CMD_BYTES	(RLX_HEADER_BYTES + MIN_RLX_PIX_BYTES)
+
+#define RLE_HEADER_BYTES	6
+#define MIN_RLE_PIX_BYTES	3
+#define MIN_RLE_CMD_BYTES	(RLE_HEADER_BYTES + MIN_RLE_PIX_BYTES)
+
+#define RAW_HEADER_BYTES	6
+#define MIN_RAW_PIX_BYTES	2
+#define MIN_RAW_CMD_BYTES	(RAW_HEADER_BYTES + MIN_RAW_PIX_BYTES)
+
+/*
+ * Trims identical data from front and back of line
+ * Sets new front buffer address and width
+ * And returns byte count of identical pixels
+ * Assumes CPU natural alignment (unsigned long)
+ * for back and front buffer ptrs and width
+ */
+#if 0
+static int udl_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes)
+{
+	int j, k;
+	const unsigned long *back = (const unsigned long *) bback;
+	const unsigned long *front = (const unsigned long *) *bfront;
+	const int width = *width_bytes / sizeof(unsigned long);
+	int identical = width;
+	int start = width;
+	int end = width;
+
+	prefetch((void *) front);
+	prefetch((void *) back);
+
+	for (j = 0; j < width; j++) {
+		if (back[j] != front[j]) {
+			start = j;
+			break;
+		}
+	}
+
+	for (k = width - 1; k > j; k--) {
+		if (back[k] != front[k]) {
+			end = k+1;
+			break;
+		}
+	}
+
+	identical = start + (width - end);
+	*bfront = (u8 *) &front[start];
+	*width_bytes = (end - start) * sizeof(unsigned long);
+
+	return identical * sizeof(unsigned long);
+}
+#endif
+
+static inline u16 pixel32_to_be16p(const uint8_t *pixel)
+{
+	uint32_t pix = *(uint32_t *)pixel;
+	u16 retval;
+
+	retval =  (((pix >> 3) & 0x001f) |
+		   ((pix >> 5) & 0x07e0) |
+		   ((pix >> 8) & 0xf800));
+	return retval;
+}
+
+/*
+ * Render a command stream for an encoded horizontal line segment of pixels.
+ *
+ * A command buffer holds several commands.
+ * It always begins with a fresh command header
+ * (the protocol doesn't require this, but we enforce it to allow
+ * multiple buffers to be potentially encoded and sent in parallel).
+ * A single command encodes one contiguous horizontal line of pixels
+ *
+ * The function relies on the client to do all allocation, so that
+ * rendering can be done directly to output buffers (e.g. USB URBs).
+ * The function fills the supplied command buffer, providing information
+ * on where it left off, so the client may call in again with additional
+ * buffers if the line will take several buffers to complete.
+ *
+ * A single command can transmit a maximum of 256 pixels,
+ * regardless of the compression ratio (protocol design limit).
+ * To the hardware, 0 for a size byte means 256
+ *
+ * Rather than 256 pixel commands which are either rl or raw encoded,
+ * the rlx command simply assumes alternating raw and rl spans within one cmd.
+ * This has a slightly larger header overhead, but produces more even results.
+ * It also processes all data (read and write) in a single pass.
+ * Performance benchmarks of common cases show it having just slightly better
+ * compression than 256 pixel raw or rle commands, with similar CPU consumpion.
+ * But for very rl friendly data, will compress not quite as well.
+ */
+static void udl_compress_hline16(
+	const u8 **pixel_start_ptr,
+	const u8 *const pixel_end,
+	uint32_t *device_address_ptr,
+	uint8_t **command_buffer_ptr,
+	const uint8_t *const cmd_buffer_end, int bpp)
+{
+	const u8 *pixel = *pixel_start_ptr;
+	uint32_t dev_addr  = *device_address_ptr;
+	uint8_t *cmd = *command_buffer_ptr;
+
+	while ((pixel_end > pixel) &&
+	       (cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) {
+		uint8_t *raw_pixels_count_byte = 0;
+		uint8_t *cmd_pixels_count_byte = 0;
+		const u8 *raw_pixel_start = 0;
+		const u8 *cmd_pixel_start, *cmd_pixel_end = 0;
+
+		prefetchw((void *) cmd); /* pull in one cache line at least */
+
+		*cmd++ = 0xaf;
+		*cmd++ = 0x6b;
+		*cmd++ = (uint8_t) ((dev_addr >> 16) & 0xFF);
+		*cmd++ = (uint8_t) ((dev_addr >> 8) & 0xFF);
+		*cmd++ = (uint8_t) ((dev_addr) & 0xFF);
+
+		cmd_pixels_count_byte = cmd++; /*  we'll know this later */
+		cmd_pixel_start = pixel;
+
+		raw_pixels_count_byte = cmd++; /*  we'll know this later */
+		raw_pixel_start = pixel;
+
+		cmd_pixel_end = pixel + (min(MAX_CMD_PIXELS + 1,
+			min((int)(pixel_end - pixel) / bpp,
+			    (int)(cmd_buffer_end - cmd) / 2))) * bpp;
+
+		prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * bpp);
+
+		while (pixel < cmd_pixel_end) {
+			const u8 * const repeating_pixel = pixel;
+
+			if (bpp == 2)
+				*(uint16_t *)cmd = cpu_to_be16p((uint16_t *)pixel);
+			else if (bpp == 4)
+				*(uint16_t *)cmd = cpu_to_be16(pixel32_to_be16p(pixel));
+
+			cmd += 2;
+			pixel += bpp;
+
+			if (unlikely((pixel < cmd_pixel_end) &&
+				     (!memcmp(pixel, repeating_pixel, bpp)))) {
+				/* go back and fill in raw pixel count */
+				*raw_pixels_count_byte = (((repeating_pixel -
+						raw_pixel_start) / bpp) + 1) & 0xFF;
+
+				while ((pixel < cmd_pixel_end)
+				       && (!memcmp(pixel, repeating_pixel, bpp))) {
+					pixel += bpp;
+				}
+
+				/* immediately after raw data is repeat byte */
+				*cmd++ = (((pixel - repeating_pixel) / bpp) - 1) & 0xFF;
+
+				/* Then start another raw pixel span */
+				raw_pixel_start = pixel;
+				raw_pixels_count_byte = cmd++;
+			}
+		}
+
+		if (pixel > raw_pixel_start) {
+			/* finalize last RAW span */
+			*raw_pixels_count_byte = ((pixel-raw_pixel_start) / bpp) & 0xFF;
+		}
+
+		*cmd_pixels_count_byte = ((pixel - cmd_pixel_start) / bpp) & 0xFF;
+		dev_addr += ((pixel - cmd_pixel_start) / bpp) * 2;
+	}
+
+	if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) {
+		/* Fill leftover bytes with no-ops */
+		if (cmd_buffer_end > cmd)
+			memset(cmd, 0xAF, cmd_buffer_end - cmd);
+		cmd = (uint8_t *) cmd_buffer_end;
+	}
+
+	*command_buffer_ptr = cmd;
+	*pixel_start_ptr = pixel;
+	*device_address_ptr = dev_addr;
+
+	return;
+}
+
+/*
+ * There are 3 copies of every pixel: The front buffer that the fbdev
+ * client renders to, the actual framebuffer across the USB bus in hardware
+ * (that we can only write to, slowly, and can never read), and (optionally)
+ * our shadow copy that tracks what's been sent to that hardware buffer.
+ */
+int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr,
+		     const char *front, char **urb_buf_ptr,
+		     u32 byte_offset, u32 byte_width,
+		     int *ident_ptr, int *sent_ptr)
+{
+	const u8 *line_start, *line_end, *next_pixel;
+	u32 base16 = 0 + (byte_offset / bpp) * 2;
+	struct urb *urb = *urb_ptr;
+	u8 *cmd = *urb_buf_ptr;
+	u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length;
+
+	line_start = (u8 *) (front + byte_offset);
+	next_pixel = line_start;
+	line_end = next_pixel + byte_width;
+
+	while (next_pixel < line_end) {
+
+		udl_compress_hline16(&next_pixel,
+			     line_end, &base16,
+			     (u8 **) &cmd, (u8 *) cmd_end, bpp);
+
+		if (cmd >= cmd_end) {
+			int len = cmd - (u8 *) urb->transfer_buffer;
+			if (udl_submit_urb(dev, urb, len))
+				return 1; /* lost pixels is set */
+			*sent_ptr += len;
+			urb = udl_get_urb(dev);
+			if (!urb)
+				return 1; /* lost_pixels is set */
+			*urb_ptr = urb;
+			cmd = urb->transfer_buffer;
+			cmd_end = &cmd[urb->transfer_buffer_length];
+		}
+	}
+
+	*urb_buf_ptr = cmd;
+
+	return 0;
+}
+
diff --git a/drivers/gpu/drm/via/via_map.c b/drivers/gpu/drm/via/via_map.c
index a2ab343..1f18225 100644
--- a/drivers/gpu/drm/via/via_map.c
+++ b/drivers/gpu/drm/via/via_map.c
@@ -106,6 +106,8 @@
 
 	idr_init(&dev->object_name_idr);
 
+	pci_set_master(dev->pdev);
+
 	ret = drm_vblank_init(dev, 1);
 	if (ret) {
 		kfree(dev_priv);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 2d6f573..ee24d21 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -38,6 +38,10 @@
 #define VMWGFX_CHIP_SVGAII 0
 #define VMW_FB_RESERVATION 0
 
+#define VMW_MIN_INITIAL_WIDTH 800
+#define VMW_MIN_INITIAL_HEIGHT 600
+
+
 /**
  * Fully encoded drm commands. Might move to vmw_drm.h
  */
@@ -387,6 +391,41 @@
 	BUG_ON(n3d < 0);
 }
 
+/**
+ * Sets the initial_[width|height] fields on the given vmw_private.
+ *
+ * It does so by reading SVGA_REG_[WIDTH|HEIGHT] regs and then
+ * clamping the value to fb_max_[width|height] fields and the
+ * VMW_MIN_INITIAL_[WIDTH|HEIGHT].
+ * If the values appear to be invalid, set them to
+ * VMW_MIN_INITIAL_[WIDTH|HEIGHT].
+ */
+static void vmw_get_initial_size(struct vmw_private *dev_priv)
+{
+	uint32_t width;
+	uint32_t height;
+
+	width = vmw_read(dev_priv, SVGA_REG_WIDTH);
+	height = vmw_read(dev_priv, SVGA_REG_HEIGHT);
+
+	width = max_t(uint32_t, width, VMW_MIN_INITIAL_WIDTH);
+	height = max_t(uint32_t, height, VMW_MIN_INITIAL_HEIGHT);
+
+	if (width > dev_priv->fb_max_width ||
+	    height > dev_priv->fb_max_height) {
+
+		/*
+		 * This is a host error and shouldn't occur.
+		 */
+
+		width = VMW_MIN_INITIAL_WIDTH;
+		height = VMW_MIN_INITIAL_HEIGHT;
+	}
+
+	dev_priv->initial_width = width;
+	dev_priv->initial_height = height;
+}
+
 static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 {
 	struct vmw_private *dev_priv;
@@ -400,6 +439,8 @@
 	}
 	memset(dev_priv, 0, sizeof(*dev_priv));
 
+	pci_set_master(dev->pdev);
+
 	dev_priv->dev = dev;
 	dev_priv->vmw_chipset = chipset;
 	dev_priv->last_read_seqno = (uint32_t) -100;
@@ -441,6 +482,9 @@
 	dev_priv->mmio_size = vmw_read(dev_priv, SVGA_REG_MEM_SIZE);
 	dev_priv->fb_max_width = vmw_read(dev_priv, SVGA_REG_MAX_WIDTH);
 	dev_priv->fb_max_height = vmw_read(dev_priv, SVGA_REG_MAX_HEIGHT);
+
+	vmw_get_initial_size(dev_priv);
+
 	if (dev_priv->capabilities & SVGA_CAP_GMR) {
 		dev_priv->max_gmr_descriptors =
 			vmw_read(dev_priv,
@@ -688,6 +732,15 @@
 	return 0;
 }
 
+static void vmw_preclose(struct drm_device *dev,
+			 struct drm_file *file_priv)
+{
+	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
+	struct vmw_private *dev_priv = vmw_priv(dev);
+
+	vmw_event_fence_fpriv_gone(dev_priv->fman, &vmw_fp->fence_events);
+}
+
 static void vmw_postclose(struct drm_device *dev,
 			 struct drm_file *file_priv)
 {
@@ -710,6 +763,7 @@
 	if (unlikely(vmw_fp == NULL))
 		return ret;
 
+	INIT_LIST_HEAD(&vmw_fp->fence_events);
 	vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev, 10);
 	if (unlikely(vmw_fp->tfile == NULL))
 		goto out_no_tfile;
@@ -1102,6 +1156,7 @@
 	.master_set = vmw_master_set,
 	.master_drop = vmw_master_drop,
 	.open = vmw_driver_open,
+	.preclose = vmw_preclose,
 	.postclose = vmw_postclose,
 	.fops = &vmwgfx_driver_fops,
 	.name = VMWGFX_DRIVER_NAME,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index dc27970..d0f2c07 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -40,9 +40,9 @@
 #include "ttm/ttm_module.h"
 #include "vmwgfx_fence.h"
 
-#define VMWGFX_DRIVER_DATE "20111025"
+#define VMWGFX_DRIVER_DATE "20120209"
 #define VMWGFX_DRIVER_MAJOR 2
-#define VMWGFX_DRIVER_MINOR 3
+#define VMWGFX_DRIVER_MINOR 4
 #define VMWGFX_DRIVER_PATCHLEVEL 0
 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000
 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
@@ -62,6 +62,7 @@
 struct vmw_fpriv {
 	struct drm_master *locked_master;
 	struct ttm_object_file *tfile;
+	struct list_head fence_events;
 };
 
 struct vmw_dma_buffer {
@@ -202,6 +203,8 @@
 	uint32_t mmio_size;
 	uint32_t fb_max_width;
 	uint32_t fb_max_height;
+	uint32_t initial_width;
+	uint32_t initial_height;
 	__le32 __iomem *mmio_virt;
 	int mmio_mtrr;
 	uint32_t capabilities;
@@ -533,7 +536,8 @@
 			       uint32_t command_size,
 			       uint64_t throttle_us,
 			       struct drm_vmw_fence_rep __user
-			       *user_fence_rep);
+			       *user_fence_rep,
+			       struct vmw_fence_obj **out_fence);
 
 extern void
 vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 40932fb..4acced4 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -1109,10 +1109,11 @@
 			void *kernel_commands,
 			uint32_t command_size,
 			uint64_t throttle_us,
-			struct drm_vmw_fence_rep __user *user_fence_rep)
+			struct drm_vmw_fence_rep __user *user_fence_rep,
+			struct vmw_fence_obj **out_fence)
 {
 	struct vmw_sw_context *sw_context = &dev_priv->ctx;
-	struct vmw_fence_obj *fence;
+	struct vmw_fence_obj *fence = NULL;
 	uint32_t handle;
 	void *cmd;
 	int ret;
@@ -1208,8 +1209,13 @@
 	vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
 				    user_fence_rep, fence, handle);
 
-	if (likely(fence != NULL))
+	/* Don't unreference when handing fence out */
+	if (unlikely(out_fence != NULL)) {
+		*out_fence = fence;
+		fence = NULL;
+	} else if (likely(fence != NULL)) {
 		vmw_fence_obj_unreference(&fence);
+	}
 
 	mutex_unlock(&dev_priv->cmdbuf_mutex);
 	return 0;
@@ -1362,7 +1368,8 @@
 	ret = vmw_execbuf_process(file_priv, dev_priv,
 				  (void __user *)(unsigned long)arg->commands,
 				  NULL, arg->command_size, arg->throttle_us,
-				  (void __user *)(unsigned long)arg->fence_rep);
+				  (void __user *)(unsigned long)arg->fence_rep,
+				  NULL);
 
 	if (unlikely(ret != 0))
 		goto out_unlock;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
index 34e51a1..3c447bf 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
@@ -414,10 +414,6 @@
 	unsigned fb_bpp, fb_depth, fb_offset, fb_pitch, fb_size;
 	int ret;
 
-	/* XXX These shouldn't be hardcoded. */
-	initial_width = 800;
-	initial_height = 600;
-
 	fb_bpp = 32;
 	fb_depth = 24;
 
@@ -425,8 +421,8 @@
 	fb_width = min(vmw_priv->fb_max_width, (unsigned)2048);
 	fb_height = min(vmw_priv->fb_max_height, (unsigned)2048);
 
-	initial_width = min(fb_width, initial_width);
-	initial_height = min(fb_height, initial_height);
+	initial_width = min(vmw_priv->initial_width, fb_width);
+	initial_height = min(vmw_priv->initial_height, fb_height);
 
 	fb_pitch = fb_width * fb_bpp / 8;
 	fb_size = fb_pitch * fb_height;
@@ -515,19 +511,7 @@
 	info->var.xres = initial_width;
 	info->var.yres = initial_height;
 
-#if 0
-	info->pixmap.size = 64*1024;
-	info->pixmap.buf_align = 8;
-	info->pixmap.access_align = 32;
-	info->pixmap.flags = FB_PIXMAP_SYSTEM;
-	info->pixmap.scan_align = 1;
-#else
-	info->pixmap.size = 0;
-	info->pixmap.buf_align = 8;
-	info->pixmap.access_align = 32;
-	info->pixmap.flags = FB_PIXMAP_SYSTEM;
-	info->pixmap.scan_align = 1;
-#endif
+	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
 
 	info->apertures = alloc_apertures(1);
 	if (!info->apertures) {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index 15fb260..f2fb8f1 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -69,12 +69,13 @@
  * be assigned the current time tv_usec val when the fence signals.
  */
 struct vmw_event_fence_action {
-	struct drm_pending_event e;
 	struct vmw_fence_action action;
+	struct list_head fpriv_head;
+
+	struct drm_pending_event *event;
 	struct vmw_fence_obj *fence;
 	struct drm_device *dev;
-	struct kref kref;
-	uint32_t size;
+
 	uint32_t *tv_sec;
 	uint32_t *tv_usec;
 };
@@ -784,46 +785,40 @@
 }
 
 /**
- * vmw_event_fence_action_destroy
+ * vmw_event_fence_fpriv_gone - Remove references to struct drm_file objects
  *
- * @kref: The struct kref embedded in a struct vmw_event_fence_action.
+ * @fman: Pointer to a struct vmw_fence_manager
+ * @event_list: Pointer to linked list of struct vmw_event_fence_action objects
+ * with pointers to a struct drm_file object about to be closed.
  *
- * The vmw_event_fence_action destructor that may be called either after
- * the fence action cleanup, or when the event is delivered.
- * It frees both the vmw_event_fence_action struct and the actual
- * event structure copied to user-space.
+ * This function removes all pending fence events with references to a
+ * specific struct drm_file object about to be closed. The caller is required
+ * to pass a list of all struct vmw_event_fence_action objects with such
+ * events attached. This function is typically called before the
+ * struct drm_file object's event management is taken down.
  */
-static void vmw_event_fence_action_destroy(struct kref *kref)
+void vmw_event_fence_fpriv_gone(struct vmw_fence_manager *fman,
+				struct list_head *event_list)
 {
-	struct vmw_event_fence_action *eaction =
-		container_of(kref, struct vmw_event_fence_action, kref);
-	struct ttm_mem_global *mem_glob =
-		vmw_mem_glob(vmw_priv(eaction->dev));
-	uint32_t size = eaction->size;
+	struct vmw_event_fence_action *eaction;
+	struct drm_pending_event *event;
+	unsigned long irq_flags;
 
-	kfree(eaction->e.event);
-	kfree(eaction);
-	ttm_mem_global_free(mem_glob, size);
-}
-
-
-/**
- * vmw_event_fence_action_delivered
- *
- * @e: The struct drm_pending_event embedded in a struct
- * vmw_event_fence_action.
- *
- * The struct drm_pending_event destructor that is called by drm
- * once the event is delivered. Since we don't know whether this function
- * will be called before or after the fence action destructor, we
- * free a refcount and destroy if it becomes zero.
- */
-static void vmw_event_fence_action_delivered(struct drm_pending_event *e)
-{
-	struct vmw_event_fence_action *eaction =
-		container_of(e, struct vmw_event_fence_action, e);
-
-	kref_put(&eaction->kref, vmw_event_fence_action_destroy);
+	while (1) {
+		spin_lock_irqsave(&fman->lock, irq_flags);
+		if (list_empty(event_list))
+			goto out_unlock;
+		eaction = list_first_entry(event_list,
+					   struct vmw_event_fence_action,
+					   fpriv_head);
+		list_del_init(&eaction->fpriv_head);
+		event = eaction->event;
+		eaction->event = NULL;
+		spin_unlock_irqrestore(&fman->lock, irq_flags);
+		event->destroy(event);
+	}
+out_unlock:
+	spin_unlock_irqrestore(&fman->lock, irq_flags);
 }
 
 
@@ -836,18 +831,21 @@
  * This function is called when the seqno of the fence where @action is
  * attached has passed. It queues the event on the submitter's event list.
  * This function is always called from atomic context, and may be called
- * from irq context. It ups a refcount reflecting that we now have two
- * destructors.
+ * from irq context.
  */
 static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
 {
 	struct vmw_event_fence_action *eaction =
 		container_of(action, struct vmw_event_fence_action, action);
 	struct drm_device *dev = eaction->dev;
-	struct drm_file *file_priv = eaction->e.file_priv;
+	struct drm_pending_event *event = eaction->event;
+	struct drm_file *file_priv;
 	unsigned long irq_flags;
 
-	kref_get(&eaction->kref);
+	if (unlikely(event == NULL))
+		return;
+
+	file_priv = event->file_priv;
 	spin_lock_irqsave(&dev->event_lock, irq_flags);
 
 	if (likely(eaction->tv_sec != NULL)) {
@@ -858,7 +856,9 @@
 		*eaction->tv_usec = tv.tv_usec;
 	}
 
-	list_add_tail(&eaction->e.link, &file_priv->event_list);
+	list_del_init(&eaction->fpriv_head);
+	list_add_tail(&eaction->event->link, &file_priv->event_list);
+	eaction->event = NULL;
 	wake_up_all(&file_priv->event_wait);
 	spin_unlock_irqrestore(&dev->event_lock, irq_flags);
 }
@@ -876,9 +876,15 @@
 {
 	struct vmw_event_fence_action *eaction =
 		container_of(action, struct vmw_event_fence_action, action);
+	struct vmw_fence_manager *fman = eaction->fence->fman;
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&fman->lock, irq_flags);
+	list_del(&eaction->fpriv_head);
+	spin_unlock_irqrestore(&fman->lock, irq_flags);
 
 	vmw_fence_obj_unreference(&eaction->fence);
-	kref_put(&eaction->kref, vmw_event_fence_action_destroy);
+	kfree(eaction);
 }
 
 
@@ -946,39 +952,23 @@
  * an error code, the caller needs to free that object.
  */
 
-int vmw_event_fence_action_create(struct drm_file *file_priv,
-				  struct vmw_fence_obj *fence,
-				  struct drm_event *event,
-				  uint32_t *tv_sec,
-				  uint32_t *tv_usec,
-				  bool interruptible)
+int vmw_event_fence_action_queue(struct drm_file *file_priv,
+				 struct vmw_fence_obj *fence,
+				 struct drm_pending_event *event,
+				 uint32_t *tv_sec,
+				 uint32_t *tv_usec,
+				 bool interruptible)
 {
 	struct vmw_event_fence_action *eaction;
-	struct ttm_mem_global *mem_glob =
-		vmw_mem_glob(fence->fman->dev_priv);
 	struct vmw_fence_manager *fman = fence->fman;
-	uint32_t size = fman->event_fence_action_size +
-		ttm_round_pot(event->length);
-	int ret;
-
-	/*
-	 * Account for internal structure size as well as the
-	 * event size itself.
-	 */
-
-	ret = ttm_mem_global_alloc(mem_glob, size, false, interruptible);
-	if (unlikely(ret != 0))
-		return ret;
+	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
+	unsigned long irq_flags;
 
 	eaction = kzalloc(sizeof(*eaction), GFP_KERNEL);
-	if (unlikely(eaction == NULL)) {
-		ttm_mem_global_free(mem_glob, size);
+	if (unlikely(eaction == NULL))
 		return -ENOMEM;
-	}
 
-	eaction->e.event = event;
-	eaction->e.file_priv = file_priv;
-	eaction->e.destroy = vmw_event_fence_action_delivered;
+	eaction->event = event;
 
 	eaction->action.seq_passed = vmw_event_fence_action_seq_passed;
 	eaction->action.cleanup = vmw_event_fence_action_cleanup;
@@ -986,16 +976,89 @@
 
 	eaction->fence = vmw_fence_obj_reference(fence);
 	eaction->dev = fman->dev_priv->dev;
-	eaction->size = size;
 	eaction->tv_sec = tv_sec;
 	eaction->tv_usec = tv_usec;
 
-	kref_init(&eaction->kref);
+	spin_lock_irqsave(&fman->lock, irq_flags);
+	list_add_tail(&eaction->fpriv_head, &vmw_fp->fence_events);
+	spin_unlock_irqrestore(&fman->lock, irq_flags);
+
 	vmw_fence_obj_add_action(fence, &eaction->action);
 
 	return 0;
 }
 
+struct vmw_event_fence_pending {
+	struct drm_pending_event base;
+	struct drm_vmw_event_fence event;
+};
+
+int vmw_event_fence_action_create(struct drm_file *file_priv,
+				  struct vmw_fence_obj *fence,
+				  uint32_t flags,
+				  uint64_t user_data,
+				  bool interruptible)
+{
+	struct vmw_event_fence_pending *event;
+	struct drm_device *dev = fence->fman->dev_priv->dev;
+	unsigned long irq_flags;
+	int ret;
+
+	spin_lock_irqsave(&dev->event_lock, irq_flags);
+
+	ret = (file_priv->event_space < sizeof(event->event)) ? -EBUSY : 0;
+	if (likely(ret == 0))
+		file_priv->event_space -= sizeof(event->event);
+
+	spin_unlock_irqrestore(&dev->event_lock, irq_flags);
+
+	if (unlikely(ret != 0)) {
+		DRM_ERROR("Failed to allocate event space for this file.\n");
+		goto out_no_space;
+	}
+
+
+	event = kzalloc(sizeof(event->event), GFP_KERNEL);
+	if (unlikely(event == NULL)) {
+		DRM_ERROR("Failed to allocate an event.\n");
+		ret = -ENOMEM;
+		goto out_no_event;
+	}
+
+	event->event.base.type = DRM_VMW_EVENT_FENCE_SIGNALED;
+	event->event.base.length = sizeof(*event);
+	event->event.user_data = user_data;
+
+	event->base.event = &event->event.base;
+	event->base.file_priv = file_priv;
+	event->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
+
+
+	if (flags & DRM_VMW_FE_FLAG_REQ_TIME)
+		ret = vmw_event_fence_action_queue(file_priv, fence,
+						   &event->base,
+						   &event->event.tv_sec,
+						   &event->event.tv_usec,
+						   interruptible);
+	else
+		ret = vmw_event_fence_action_queue(file_priv, fence,
+						   &event->base,
+						   NULL,
+						   NULL,
+						   interruptible);
+	if (ret != 0)
+		goto out_no_queue;
+
+out_no_queue:
+	event->base.destroy(&event->base);
+out_no_event:
+	spin_lock_irqsave(&dev->event_lock, irq_flags);
+	file_priv->event_space += sizeof(*event);
+	spin_unlock_irqrestore(&dev->event_lock, irq_flags);
+out_no_space:
+	return ret;
+}
+
 int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
 			  struct drm_file *file_priv)
 {
@@ -1008,8 +1071,6 @@
 		(struct drm_vmw_fence_rep __user *)(unsigned long)
 		arg->fence_rep;
 	uint32_t handle;
-	unsigned long irq_flags;
-	struct drm_vmw_event_fence *event;
 	int ret;
 
 	/*
@@ -1062,59 +1123,28 @@
 
 	BUG_ON(fence == NULL);
 
-	spin_lock_irqsave(&dev->event_lock, irq_flags);
-
-	ret = (file_priv->event_space < sizeof(*event)) ? -EBUSY : 0;
-	if (likely(ret == 0))
-		file_priv->event_space -= sizeof(*event);
-
-	spin_unlock_irqrestore(&dev->event_lock, irq_flags);
-
-	if (unlikely(ret != 0)) {
-		DRM_ERROR("Failed to allocate event space for this file.\n");
-		goto out_no_event_space;
-	}
-
-	event = kzalloc(sizeof(*event), GFP_KERNEL);
-	if (unlikely(event == NULL)) {
-		DRM_ERROR("Failed to allocate an event.\n");
-		goto out_no_event;
-	}
-
-	event->base.type = DRM_VMW_EVENT_FENCE_SIGNALED;
-	event->base.length = sizeof(*event);
-	event->user_data = arg->user_data;
-
 	if (arg->flags & DRM_VMW_FE_FLAG_REQ_TIME)
 		ret = vmw_event_fence_action_create(file_priv, fence,
-						    &event->base,
-						    &event->tv_sec,
-						    &event->tv_usec,
+						    arg->flags,
+						    arg->user_data,
 						    true);
 	else
 		ret = vmw_event_fence_action_create(file_priv, fence,
-						    &event->base,
-						    NULL,
-						    NULL,
+						    arg->flags,
+						    arg->user_data,
 						    true);
 
 	if (unlikely(ret != 0)) {
 		if (ret != -ERESTARTSYS)
 			DRM_ERROR("Failed to attach event to fence.\n");
-		goto out_no_attach;
+		goto out_no_create;
 	}
 
 	vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
 				    handle);
 	vmw_fence_obj_unreference(&fence);
 	return 0;
-out_no_attach:
-	kfree(event);
-out_no_event:
-	spin_lock_irqsave(&dev->event_lock, irq_flags);
-	file_priv->event_space += sizeof(*event);
-	spin_unlock_irqrestore(&dev->event_lock, irq_flags);
-out_no_event_space:
+out_no_create:
 	if (user_fence_rep != NULL)
 		ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
 					  handle, TTM_REF_USAGE);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
index 0854a20..faf2e78 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
@@ -109,5 +109,12 @@
 				     struct drm_file *file_priv);
 extern int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
 				 struct drm_file *file_priv);
-
+extern void vmw_event_fence_fpriv_gone(struct vmw_fence_manager *fman,
+				       struct list_head *event_list);
+extern int vmw_event_fence_action_queue(struct drm_file *filee_priv,
+					struct vmw_fence_obj *fence,
+					struct drm_pending_event *event,
+					uint32_t *tv_sec,
+					uint32_t *tv_usec,
+					bool interruptible);
 #endif /* _VMWGFX_FENCE_H_ */
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index b66ef0e..2286d47 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -422,7 +422,8 @@
 				struct vmw_framebuffer *framebuffer,
 				unsigned flags, unsigned color,
 				struct drm_clip_rect *clips,
-				unsigned num_clips, int inc)
+				unsigned num_clips, int inc,
+				struct vmw_fence_obj **out_fence)
 {
 	struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS];
 	struct drm_clip_rect *clips_ptr;
@@ -542,12 +543,15 @@
 		if (num == 0)
 			continue;
 
+		/* only return the last fence */
+		if (out_fence && *out_fence)
+			vmw_fence_obj_unreference(out_fence);
 
 		/* recalculate package length */
 		fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num;
 		cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
 		ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
-					  fifo_size, 0, NULL);
+					  fifo_size, 0, NULL, out_fence);
 
 		if (unlikely(ret != 0))
 			break;
@@ -598,7 +602,7 @@
 
 	ret = do_surface_dirty_sou(dev_priv, file_priv, &vfbs->base,
 				   flags, color,
-				   clips, num_clips, inc);
+				   clips, num_clips, inc, NULL);
 
 	ttm_read_unlock(&vmaster->lock);
 	return 0;
@@ -809,7 +813,7 @@
 	cmd->body.ptr.offset = 0;
 
 	ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
-				  fifo_size, 0, NULL);
+				  fifo_size, 0, NULL, NULL);
 
 	kfree(cmd);
 
@@ -821,7 +825,8 @@
 			       struct vmw_framebuffer *framebuffer,
 			       unsigned flags, unsigned color,
 			       struct drm_clip_rect *clips,
-			       unsigned num_clips, int increment)
+			       unsigned num_clips, int increment,
+			       struct vmw_fence_obj **out_fence)
 {
 	struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS];
 	struct drm_clip_rect *clips_ptr;
@@ -894,9 +899,13 @@
 		if (hit_num == 0)
 			continue;
 
+		/* only return the last fence */
+		if (out_fence && *out_fence)
+			vmw_fence_obj_unreference(out_fence);
+
 		fifo_size = sizeof(*blits) * hit_num;
 		ret = vmw_execbuf_process(file_priv, dev_priv, NULL, blits,
-					  fifo_size, 0, NULL);
+					  fifo_size, 0, NULL, out_fence);
 
 		if (unlikely(ret != 0))
 			break;
@@ -942,7 +951,7 @@
 	} else {
 		ret = do_dmabuf_dirty_sou(file_priv, dev_priv, &vfbd->base,
 					  flags, color,
-					  clips, num_clips, increment);
+					  clips, num_clips, increment, NULL);
 	}
 
 	ttm_read_unlock(&vmaster->lock);
@@ -1296,7 +1305,7 @@
 		fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num;
 		cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
 		ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
-					  fifo_size, 0, NULL);
+					  fifo_size, 0, NULL, NULL);
 
 		if (unlikely(ret != 0))
 			break;
@@ -1409,7 +1418,7 @@
 	fifo_size = sizeof(*cmd) + sizeof(*blits) * blits_pos;
 
 	ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, fifo_size,
-				  0, user_fence_rep);
+				  0, user_fence_rep, NULL);
 
 	kfree(cmd);
 
@@ -1672,6 +1681,70 @@
 	return 0;
 }
 
+int vmw_du_page_flip(struct drm_crtc *crtc,
+		     struct drm_framebuffer *fb,
+		     struct drm_pending_vblank_event *event)
+{
+	struct vmw_private *dev_priv = vmw_priv(crtc->dev);
+	struct drm_framebuffer *old_fb = crtc->fb;
+	struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb);
+	struct drm_file *file_priv = event->base.file_priv;
+	struct vmw_fence_obj *fence = NULL;
+	struct drm_clip_rect clips;
+	int ret;
+
+	/* require ScreenObject support for page flipping */
+	if (!dev_priv->sou_priv)
+		return -ENOSYS;
+
+	if (!vmw_kms_screen_object_flippable(dev_priv, crtc))
+		return -EINVAL;
+
+	crtc->fb = fb;
+
+	/* do a full screen dirty update */
+	clips.x1 = clips.y1 = 0;
+	clips.x2 = fb->width;
+	clips.y2 = fb->height;
+
+	if (vfb->dmabuf)
+		ret = do_dmabuf_dirty_sou(file_priv, dev_priv, vfb,
+					  0, 0, &clips, 1, 1, &fence);
+	else
+		ret = do_surface_dirty_sou(dev_priv, file_priv, vfb,
+					   0, 0, &clips, 1, 1, &fence);
+
+
+	if (ret != 0)
+		goto out_no_fence;
+	if (!fence) {
+		ret = -EINVAL;
+		goto out_no_fence;
+	}
+
+	ret = vmw_event_fence_action_queue(file_priv, fence,
+					   &event->base,
+					   &event->event.tv_sec,
+					   &event->event.tv_usec,
+					   true);
+
+	/*
+	 * No need to hold on to this now. The only cleanup
+	 * we need to do if we fail is unref the fence.
+	 */
+	vmw_fence_obj_unreference(&fence);
+
+	if (vmw_crtc_to_du(crtc)->is_implicit)
+		vmw_kms_screen_object_update_implicit_fb(dev_priv, crtc);
+
+	return ret;
+
+out_no_fence:
+	crtc->fb = old_fb;
+	return ret;
+}
+
+
 void vmw_du_crtc_save(struct drm_crtc *crtc)
 {
 }
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index a4f7f03..8184bc5 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -121,6 +121,9 @@
  * Shared display unit functions - vmwgfx_kms.c
  */
 void vmw_display_unit_cleanup(struct vmw_display_unit *du);
+int vmw_du_page_flip(struct drm_crtc *crtc,
+		     struct drm_framebuffer *fb,
+		     struct drm_pending_vblank_event *event);
 void vmw_du_crtc_save(struct drm_crtc *crtc);
 void vmw_du_crtc_restore(struct drm_crtc *crtc);
 void vmw_du_crtc_gamma_set(struct drm_crtc *crtc,
@@ -154,5 +157,10 @@
 int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv);
 int vmw_kms_sou_update_layout(struct vmw_private *dev_priv, unsigned num,
 			      struct drm_vmw_rect *rects);
+bool vmw_kms_screen_object_flippable(struct vmw_private *dev_priv,
+				     struct drm_crtc *crtc);
+void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv,
+					      struct drm_crtc *crtc);
+
 
 #endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index f77b184..070fb23 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -354,8 +354,8 @@
 	INIT_LIST_HEAD(&ldu->active);
 
 	ldu->base.pref_active = (unit == 0);
-	ldu->base.pref_width = 800;
-	ldu->base.pref_height = 600;
+	ldu->base.pref_width = dev_priv->initial_width;
+	ldu->base.pref_height = dev_priv->initial_height;
 	ldu->base.pref_mode = NULL;
 	ldu->base.is_implicit = true;
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 4defdcf..6deaf2f 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -394,6 +394,7 @@
 	.gamma_set = vmw_du_crtc_gamma_set,
 	.destroy = vmw_sou_crtc_destroy,
 	.set_config = vmw_sou_crtc_set_config,
+	.page_flip = vmw_du_page_flip,
 };
 
 /*
@@ -448,8 +449,8 @@
 	sou->active_implicit = false;
 
 	sou->base.pref_active = (unit == 0);
-	sou->base.pref_width = 800;
-	sou->base.pref_height = 600;
+	sou->base.pref_width = dev_priv->initial_width;
+	sou->base.pref_height = dev_priv->initial_height;
 	sou->base.pref_mode = NULL;
 	sou->base.is_implicit = true;
 
@@ -535,3 +536,36 @@
 
 	return 0;
 }
+
+/**
+ * Returns if this unit can be page flipped.
+ * Must be called with the mode_config mutex held.
+ */
+bool vmw_kms_screen_object_flippable(struct vmw_private *dev_priv,
+				     struct drm_crtc *crtc)
+{
+	struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
+
+	if (!sou->base.is_implicit)
+		return true;
+
+	if (dev_priv->sou_priv->num_implicit != 1)
+		return false;
+
+	return true;
+}
+
+/**
+ * Update the implicit fb to the current fb of this crtc.
+ * Must be called with the mode_config mutex held.
+ */
+void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv,
+					      struct drm_crtc *crtc)
+{
+	struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
+
+	BUG_ON(!sou->base.is_implicit);
+
+	dev_priv->sou_priv->implicit_fb =
+		vmw_framebuffer_to_vfb(sou->base.crtc.fb);
+}
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 990fe19..4da66b4 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1935,6 +1935,16 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
+#if defined(CONFIG_MOUSE_SYNAPTICS_USB) || defined(CONFIG_MOUSE_SYNAPTICS_USB_MODULE)
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_INT_TP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_CPAD) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_STICK) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_COMP_TP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WTP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DPAD) },
+#endif
 	{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
@@ -2016,6 +2026,16 @@
 		if (hdev->product >= USB_DEVICE_ID_LOGITECH_HARMONY_FIRST &&
 				hdev->product <= USB_DEVICE_ID_LOGITECH_HARMONY_LAST)
 			return true;
+		/*
+		 * The Keene FM transmitter USB device has the same USB ID as
+		 * the Logitech AudioHub Speaker, but it should ignore the hid.
+		 * Check if the name is that of the Keene device.
+		 * For reference: the name of the AudioHub is
+		 * "HOLTEK  AudioHub Speaker".
+		 */
+		if (hdev->product == USB_DEVICE_ID_LOGITECH_AUDIOHUB &&
+			!strcmp(hdev->name, "HOLTEK  B-LINK USB Audio  "))
+				return true;
 		break;
 	case USB_VENDOR_ID_SOUNDGRAPH:
 		if (hdev->product >= USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST &&
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 3eb0090..e39aecb 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -471,6 +471,7 @@
 #define USB_DEVICE_ID_LG_MULTITOUCH	0x0064
 
 #define USB_VENDOR_ID_LOGITECH		0x046d
+#define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
 #define USB_DEVICE_ID_LOGITECH_RECEIVER	0xc101
 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
 #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
@@ -677,6 +678,17 @@
 #define USB_DEVICE_ID_SYMBOL_SCANNER_1	0x0800
 #define USB_DEVICE_ID_SYMBOL_SCANNER_2	0x1300
 
+#define USB_VENDOR_ID_SYNAPTICS		0x06cb
+#define USB_DEVICE_ID_SYNAPTICS_TP	0x0001
+#define USB_DEVICE_ID_SYNAPTICS_INT_TP	0x0002
+#define USB_DEVICE_ID_SYNAPTICS_CPAD	0x0003
+#define USB_DEVICE_ID_SYNAPTICS_TS	0x0006
+#define USB_DEVICE_ID_SYNAPTICS_STICK	0x0007
+#define USB_DEVICE_ID_SYNAPTICS_WP	0x0008
+#define USB_DEVICE_ID_SYNAPTICS_COMP_TP	0x0009
+#define USB_DEVICE_ID_SYNAPTICS_WTP	0x0010
+#define USB_DEVICE_ID_SYNAPTICS_DPAD	0x0013
+
 #define USB_VENDOR_ID_THRUSTMASTER	0x044f
 
 #define USB_VENDOR_ID_TIVO		0x150a
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c
index 12f9777..45c3433 100644
--- a/drivers/hid/hid-picolcd.c
+++ b/drivers/hid/hid-picolcd.c
@@ -1525,12 +1525,6 @@
 /*
  * The "eeprom" file
  */
-static int picolcd_debug_eeprom_open(struct inode *i, struct file *f)
-{
-	f->private_data = i->i_private;
-	return 0;
-}
-
 static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u,
 		size_t s, loff_t *off)
 {
@@ -1618,7 +1612,7 @@
  */
 static const struct file_operations picolcd_debug_eeprom_fops = {
 	.owner    = THIS_MODULE,
-	.open     = picolcd_debug_eeprom_open,
+	.open     = simple_open,
 	.read     = picolcd_debug_eeprom_read,
 	.write    = picolcd_debug_eeprom_write,
 	.llseek   = generic_file_llseek,
@@ -1627,12 +1621,6 @@
 /*
  * The "flash" file
  */
-static int picolcd_debug_flash_open(struct inode *i, struct file *f)
-{
-	f->private_data = i->i_private;
-	return 0;
-}
-
 /* record a flash address to buf (bounds check to be done by caller) */
 static int _picolcd_flash_setaddr(struct picolcd_data *data, u8 *buf, long off)
 {
@@ -1817,7 +1805,7 @@
  */
 static const struct file_operations picolcd_debug_flash_fops = {
 	.owner    = THIS_MODULE,
-	.open     = picolcd_debug_flash_open,
+	.open     = simple_open,
 	.read     = picolcd_debug_flash_read,
 	.write    = picolcd_debug_flash_write,
 	.llseek   = generic_file_llseek,
diff --git a/drivers/hid/hid-wiimote-debug.c b/drivers/hid/hid-wiimote-debug.c
index 17dabc1..eec3291 100644
--- a/drivers/hid/hid-wiimote-debug.c
+++ b/drivers/hid/hid-wiimote-debug.c
@@ -23,12 +23,6 @@
 	struct dentry *drm;
 };
 
-static int wiidebug_eeprom_open(struct inode *i, struct file *f)
-{
-	f->private_data = i->i_private;
-	return 0;
-}
-
 static ssize_t wiidebug_eeprom_read(struct file *f, char __user *u, size_t s,
 								loff_t *off)
 {
@@ -83,7 +77,7 @@
 
 static const struct file_operations wiidebug_eeprom_fops = {
 	.owner = THIS_MODULE,
-	.open = wiidebug_eeprom_open,
+	.open = simple_open,
 	.read = wiidebug_eeprom_read,
 	.llseek = generic_file_llseek,
 };
diff --git a/drivers/hsi/Kconfig b/drivers/hsi/Kconfig
new file mode 100644
index 0000000..d94e38d
--- /dev/null
+++ b/drivers/hsi/Kconfig
@@ -0,0 +1,19 @@
+#
+# HSI driver configuration
+#
+menuconfig HSI
+	tristate "HSI support"
+	---help---
+	  The "High speed synchronous Serial Interface" is
+	  synchronous serial interface used mainly to connect
+	  application engines and cellular modems.
+
+if HSI
+
+config HSI_BOARDINFO
+	bool
+	default y
+
+source "drivers/hsi/clients/Kconfig"
+
+endif # HSI
diff --git a/drivers/hsi/Makefile b/drivers/hsi/Makefile
new file mode 100644
index 0000000..9d5d33f
--- /dev/null
+++ b/drivers/hsi/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for HSI
+#
+obj-$(CONFIG_HSI_BOARDINFO)	+= hsi_boardinfo.o
+obj-$(CONFIG_HSI)		+= hsi.o
+obj-y				+= clients/
diff --git a/drivers/hsi/clients/Kconfig b/drivers/hsi/clients/Kconfig
new file mode 100644
index 0000000..3bacd27
--- /dev/null
+++ b/drivers/hsi/clients/Kconfig
@@ -0,0 +1,13 @@
+#
+# HSI clients configuration
+#
+
+comment "HSI clients"
+
+config HSI_CHAR
+	tristate "HSI/SSI character driver"
+	depends on HSI
+	---help---
+	  If you say Y here, you will enable the HSI/SSI character driver.
+	  This driver provides a simple character device interface for
+	  serial communication with the cellular modem over HSI/SSI bus.
diff --git a/drivers/hsi/clients/Makefile b/drivers/hsi/clients/Makefile
new file mode 100644
index 0000000..327c0e2
--- /dev/null
+++ b/drivers/hsi/clients/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for HSI clients
+#
+
+obj-$(CONFIG_HSI_CHAR)	+= hsi_char.o
diff --git a/drivers/hsi/clients/hsi_char.c b/drivers/hsi/clients/hsi_char.c
new file mode 100644
index 0000000..88a050d
--- /dev/null
+++ b/drivers/hsi/clients/hsi_char.c
@@ -0,0 +1,802 @@
+/*
+ * HSI character device driver, implements the character device
+ * interface.
+ *
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Andras Domokos <andras.domokos@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/errno.h>
+#include <linux/types.h>
+#include <linux/atomic.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/kmemleak.h>
+#include <linux/ioctl.h>
+#include <linux/wait.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/scatterlist.h>
+#include <linux/stat.h>
+#include <linux/hsi/hsi.h>
+#include <linux/hsi/hsi_char.h>
+
+#define HSC_DEVS		16 /* Num of channels */
+#define HSC_MSGS		4
+
+#define HSC_RXBREAK		0
+
+#define HSC_ID_BITS		6
+#define HSC_PORT_ID_BITS	4
+#define HSC_ID_MASK		3
+#define HSC_PORT_ID_MASK	3
+#define HSC_CH_MASK		0xf
+
+/*
+ * We support up to 4 controllers that can have up to 4
+ * ports, which should currently be more than enough.
+ */
+#define HSC_BASEMINOR(id, port_id) \
+		((((id) & HSC_ID_MASK) << HSC_ID_BITS) | \
+		(((port_id) & HSC_PORT_ID_MASK) << HSC_PORT_ID_BITS))
+
+enum {
+	HSC_CH_OPEN,
+	HSC_CH_READ,
+	HSC_CH_WRITE,
+	HSC_CH_WLINE,
+};
+
+enum {
+	HSC_RX,
+	HSC_TX,
+};
+
+struct hsc_client_data;
+/**
+ * struct hsc_channel - hsi_char internal channel data
+ * @ch: channel number
+ * @flags: Keeps state of the channel (open/close, reading, writing)
+ * @free_msgs_list: List of free HSI messages/requests
+ * @rx_msgs_queue: List of pending RX requests
+ * @tx_msgs_queue: List of pending TX requests
+ * @lock: Serialize access to the lists
+ * @cl: reference to the associated hsi_client
+ * @cl_data: reference to the client data that this channels belongs to
+ * @rx_wait: RX requests wait queue
+ * @tx_wait: TX requests wait queue
+ */
+struct hsc_channel {
+	unsigned int		ch;
+	unsigned long		flags;
+	struct list_head	free_msgs_list;
+	struct list_head	rx_msgs_queue;
+	struct list_head	tx_msgs_queue;
+	spinlock_t		lock;
+	struct hsi_client	*cl;
+	struct hsc_client_data *cl_data;
+	wait_queue_head_t	rx_wait;
+	wait_queue_head_t	tx_wait;
+};
+
+/**
+ * struct hsc_client_data - hsi_char internal client data
+ * @cdev: Characther device associated to the hsi_client
+ * @lock: Lock to serialize open/close access
+ * @flags: Keeps track of port state (rx hwbreak armed)
+ * @usecnt: Use count for claiming the HSI port (mutex protected)
+ * @cl: Referece to the HSI client
+ * @channels: Array of channels accessible by the client
+ */
+struct hsc_client_data {
+	struct cdev		cdev;
+	struct mutex		lock;
+	unsigned long		flags;
+	unsigned int		usecnt;
+	struct hsi_client	*cl;
+	struct hsc_channel	channels[HSC_DEVS];
+};
+
+/* Stores the major number dynamically allocated for hsi_char */
+static unsigned int hsc_major;
+/* Maximum buffer size that hsi_char will accept from userspace */
+static unsigned int max_data_size = 0x1000;
+module_param(max_data_size, uint, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(max_data_size, "max read/write data size [4,8..65536] (^2)");
+
+static void hsc_add_tail(struct hsc_channel *channel, struct hsi_msg *msg,
+							struct list_head *queue)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&channel->lock, flags);
+	list_add_tail(&msg->link, queue);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static struct hsi_msg *hsc_get_first_msg(struct hsc_channel *channel,
+							struct list_head *queue)
+{
+	struct hsi_msg *msg = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&channel->lock, flags);
+
+	if (list_empty(queue))
+		goto out;
+
+	msg = list_first_entry(queue, struct hsi_msg, link);
+	list_del(&msg->link);
+out:
+	spin_unlock_irqrestore(&channel->lock, flags);
+
+	return msg;
+}
+
+static inline void hsc_msg_free(struct hsi_msg *msg)
+{
+	kfree(sg_virt(msg->sgt.sgl));
+	hsi_free_msg(msg);
+}
+
+static void hsc_free_list(struct list_head *list)
+{
+	struct hsi_msg *msg, *tmp;
+
+	list_for_each_entry_safe(msg, tmp, list, link) {
+		list_del(&msg->link);
+		hsc_msg_free(msg);
+	}
+}
+
+static void hsc_reset_list(struct hsc_channel *channel, struct list_head *l)
+{
+	unsigned long flags;
+	LIST_HEAD(list);
+
+	spin_lock_irqsave(&channel->lock, flags);
+	list_splice_init(l, &list);
+	spin_unlock_irqrestore(&channel->lock, flags);
+
+	hsc_free_list(&list);
+}
+
+static inline struct hsi_msg *hsc_msg_alloc(unsigned int alloc_size)
+{
+	struct hsi_msg *msg;
+	void *buf;
+
+	msg = hsi_alloc_msg(1, GFP_KERNEL);
+	if (!msg)
+		goto out;
+	buf = kmalloc(alloc_size, GFP_KERNEL);
+	if (!buf) {
+		hsi_free_msg(msg);
+		goto out;
+	}
+	sg_init_one(msg->sgt.sgl, buf, alloc_size);
+	/* Ignore false positive, due to sg pointer handling */
+	kmemleak_ignore(buf);
+
+	return msg;
+out:
+	return NULL;
+}
+
+static inline int hsc_msgs_alloc(struct hsc_channel *channel)
+{
+	struct hsi_msg *msg;
+	int i;
+
+	for (i = 0; i < HSC_MSGS; i++) {
+		msg = hsc_msg_alloc(max_data_size);
+		if (!msg)
+			goto out;
+		msg->channel = channel->ch;
+		list_add_tail(&msg->link, &channel->free_msgs_list);
+	}
+
+	return 0;
+out:
+	hsc_free_list(&channel->free_msgs_list);
+
+	return -ENOMEM;
+}
+
+static inline unsigned int hsc_msg_len_get(struct hsi_msg *msg)
+{
+	return msg->sgt.sgl->length;
+}
+
+static inline void hsc_msg_len_set(struct hsi_msg *msg, unsigned int len)
+{
+	msg->sgt.sgl->length = len;
+}
+
+static void hsc_rx_completed(struct hsi_msg *msg)
+{
+	struct hsc_client_data *cl_data = hsi_client_drvdata(msg->cl);
+	struct hsc_channel *channel = cl_data->channels + msg->channel;
+
+	if (test_bit(HSC_CH_READ, &channel->flags)) {
+		hsc_add_tail(channel, msg, &channel->rx_msgs_queue);
+		wake_up(&channel->rx_wait);
+	} else {
+		hsc_add_tail(channel, msg, &channel->free_msgs_list);
+	}
+}
+
+static void hsc_rx_msg_destructor(struct hsi_msg *msg)
+{
+	msg->status = HSI_STATUS_ERROR;
+	hsc_msg_len_set(msg, 0);
+	hsc_rx_completed(msg);
+}
+
+static void hsc_tx_completed(struct hsi_msg *msg)
+{
+	struct hsc_client_data *cl_data = hsi_client_drvdata(msg->cl);
+	struct hsc_channel *channel = cl_data->channels + msg->channel;
+
+	if (test_bit(HSC_CH_WRITE, &channel->flags)) {
+		hsc_add_tail(channel, msg, &channel->tx_msgs_queue);
+		wake_up(&channel->tx_wait);
+	} else {
+		hsc_add_tail(channel, msg, &channel->free_msgs_list);
+	}
+}
+
+static void hsc_tx_msg_destructor(struct hsi_msg *msg)
+{
+	msg->status = HSI_STATUS_ERROR;
+	hsc_msg_len_set(msg, 0);
+	hsc_tx_completed(msg);
+}
+
+static void hsc_break_req_destructor(struct hsi_msg *msg)
+{
+	struct hsc_client_data *cl_data = hsi_client_drvdata(msg->cl);
+
+	hsi_free_msg(msg);
+	clear_bit(HSC_RXBREAK, &cl_data->flags);
+}
+
+static void hsc_break_received(struct hsi_msg *msg)
+{
+	struct hsc_client_data *cl_data = hsi_client_drvdata(msg->cl);
+	struct hsc_channel *channel = cl_data->channels;
+	int i, ret;
+
+	/* Broadcast HWBREAK on all channels */
+	for (i = 0; i < HSC_DEVS; i++, channel++) {
+		struct hsi_msg *msg2;
+
+		if (!test_bit(HSC_CH_READ, &channel->flags))
+			continue;
+		msg2 = hsc_get_first_msg(channel, &channel->free_msgs_list);
+		if (!msg2)
+			continue;
+		clear_bit(HSC_CH_READ, &channel->flags);
+		hsc_msg_len_set(msg2, 0);
+		msg2->status = HSI_STATUS_COMPLETED;
+		hsc_add_tail(channel, msg2, &channel->rx_msgs_queue);
+		wake_up(&channel->rx_wait);
+	}
+	hsi_flush(msg->cl);
+	ret = hsi_async_read(msg->cl, msg);
+	if (ret < 0)
+		hsc_break_req_destructor(msg);
+}
+
+static int hsc_break_request(struct hsi_client *cl)
+{
+	struct hsc_client_data *cl_data = hsi_client_drvdata(cl);
+	struct hsi_msg *msg;
+	int ret;
+
+	if (test_and_set_bit(HSC_RXBREAK, &cl_data->flags))
+		return -EBUSY;
+
+	msg = hsi_alloc_msg(0, GFP_KERNEL);
+	if (!msg) {
+		clear_bit(HSC_RXBREAK, &cl_data->flags);
+		return -ENOMEM;
+	}
+	msg->break_frame = 1;
+	msg->complete = hsc_break_received;
+	msg->destructor = hsc_break_req_destructor;
+	ret = hsi_async_read(cl, msg);
+	if (ret < 0)
+		hsc_break_req_destructor(msg);
+
+	return ret;
+}
+
+static int hsc_break_send(struct hsi_client *cl)
+{
+	struct hsi_msg *msg;
+	int ret;
+
+	msg = hsi_alloc_msg(0, GFP_ATOMIC);
+	if (!msg)
+		return -ENOMEM;
+	msg->break_frame = 1;
+	msg->complete = hsi_free_msg;
+	msg->destructor = hsi_free_msg;
+	ret = hsi_async_write(cl, msg);
+	if (ret < 0)
+		hsi_free_msg(msg);
+
+	return ret;
+}
+
+static int hsc_rx_set(struct hsi_client *cl, struct hsc_rx_config *rxc)
+{
+	struct hsi_config tmp;
+	int ret;
+
+	if ((rxc->mode != HSI_MODE_STREAM) && (rxc->mode != HSI_MODE_FRAME))
+		return -EINVAL;
+	if ((rxc->channels == 0) || (rxc->channels > HSC_DEVS))
+		return -EINVAL;
+	if (rxc->channels & (rxc->channels - 1))
+		return -EINVAL;
+	if ((rxc->flow != HSI_FLOW_SYNC) && (rxc->flow != HSI_FLOW_PIPE))
+		return -EINVAL;
+	tmp = cl->rx_cfg;
+	cl->rx_cfg.mode = rxc->mode;
+	cl->rx_cfg.channels = rxc->channels;
+	cl->rx_cfg.flow = rxc->flow;
+	ret = hsi_setup(cl);
+	if (ret < 0) {
+		cl->rx_cfg = tmp;
+		return ret;
+	}
+	if (rxc->mode == HSI_MODE_FRAME)
+		hsc_break_request(cl);
+
+	return ret;
+}
+
+static inline void hsc_rx_get(struct hsi_client *cl, struct hsc_rx_config *rxc)
+{
+	rxc->mode = cl->rx_cfg.mode;
+	rxc->channels = cl->rx_cfg.channels;
+	rxc->flow = cl->rx_cfg.flow;
+}
+
+static int hsc_tx_set(struct hsi_client *cl, struct hsc_tx_config *txc)
+{
+	struct hsi_config tmp;
+	int ret;
+
+	if ((txc->mode != HSI_MODE_STREAM) && (txc->mode != HSI_MODE_FRAME))
+		return -EINVAL;
+	if ((txc->channels == 0) || (txc->channels > HSC_DEVS))
+		return -EINVAL;
+	if (txc->channels & (txc->channels - 1))
+		return -EINVAL;
+	if ((txc->arb_mode != HSI_ARB_RR) && (txc->arb_mode != HSI_ARB_PRIO))
+		return -EINVAL;
+	tmp = cl->tx_cfg;
+	cl->tx_cfg.mode = txc->mode;
+	cl->tx_cfg.channels = txc->channels;
+	cl->tx_cfg.speed = txc->speed;
+	cl->tx_cfg.arb_mode = txc->arb_mode;
+	ret = hsi_setup(cl);
+	if (ret < 0) {
+		cl->tx_cfg = tmp;
+		return ret;
+	}
+
+	return ret;
+}
+
+static inline void hsc_tx_get(struct hsi_client *cl, struct hsc_tx_config *txc)
+{
+	txc->mode = cl->tx_cfg.mode;
+	txc->channels = cl->tx_cfg.channels;
+	txc->speed = cl->tx_cfg.speed;
+	txc->arb_mode = cl->tx_cfg.arb_mode;
+}
+
+static ssize_t hsc_read(struct file *file, char __user *buf, size_t len,
+						loff_t *ppos __maybe_unused)
+{
+	struct hsc_channel *channel = file->private_data;
+	struct hsi_msg *msg;
+	ssize_t ret;
+
+	if (len == 0)
+		return 0;
+	if (!IS_ALIGNED(len, sizeof(u32)))
+		return -EINVAL;
+	if (len > max_data_size)
+		len = max_data_size;
+	if (channel->ch >= channel->cl->rx_cfg.channels)
+		return -ECHRNG;
+	if (test_and_set_bit(HSC_CH_READ, &channel->flags))
+		return -EBUSY;
+	msg = hsc_get_first_msg(channel, &channel->free_msgs_list);
+	if (!msg) {
+		ret = -ENOSPC;
+		goto out;
+	}
+	hsc_msg_len_set(msg, len);
+	msg->complete = hsc_rx_completed;
+	msg->destructor = hsc_rx_msg_destructor;
+	ret = hsi_async_read(channel->cl, msg);
+	if (ret < 0) {
+		hsc_add_tail(channel, msg, &channel->free_msgs_list);
+		goto out;
+	}
+
+	ret = wait_event_interruptible(channel->rx_wait,
+					!list_empty(&channel->rx_msgs_queue));
+	if (ret < 0) {
+		clear_bit(HSC_CH_READ, &channel->flags);
+		hsi_flush(channel->cl);
+		return -EINTR;
+	}
+
+	msg = hsc_get_first_msg(channel, &channel->rx_msgs_queue);
+	if (msg) {
+		if (msg->status != HSI_STATUS_ERROR) {
+			ret = copy_to_user((void __user *)buf,
+			sg_virt(msg->sgt.sgl), hsc_msg_len_get(msg));
+			if (ret)
+				ret = -EFAULT;
+			else
+				ret = hsc_msg_len_get(msg);
+		} else {
+			ret = -EIO;
+		}
+		hsc_add_tail(channel, msg, &channel->free_msgs_list);
+	}
+out:
+	clear_bit(HSC_CH_READ, &channel->flags);
+
+	return ret;
+}
+
+static ssize_t hsc_write(struct file *file, const char __user *buf, size_t len,
+						loff_t *ppos __maybe_unused)
+{
+	struct hsc_channel *channel = file->private_data;
+	struct hsi_msg *msg;
+	ssize_t ret;
+
+	if ((len == 0) || !IS_ALIGNED(len, sizeof(u32)))
+		return -EINVAL;
+	if (len > max_data_size)
+		len = max_data_size;
+	if (channel->ch >= channel->cl->tx_cfg.channels)
+		return -ECHRNG;
+	if (test_and_set_bit(HSC_CH_WRITE, &channel->flags))
+		return -EBUSY;
+	msg = hsc_get_first_msg(channel, &channel->free_msgs_list);
+	if (!msg) {
+		clear_bit(HSC_CH_WRITE, &channel->flags);
+		return -ENOSPC;
+	}
+	if (copy_from_user(sg_virt(msg->sgt.sgl), (void __user *)buf, len)) {
+		ret = -EFAULT;
+		goto out;
+	}
+	hsc_msg_len_set(msg, len);
+	msg->complete = hsc_tx_completed;
+	msg->destructor = hsc_tx_msg_destructor;
+	ret = hsi_async_write(channel->cl, msg);
+	if (ret < 0)
+		goto out;
+
+	ret = wait_event_interruptible(channel->tx_wait,
+					!list_empty(&channel->tx_msgs_queue));
+	if (ret < 0) {
+		clear_bit(HSC_CH_WRITE, &channel->flags);
+		hsi_flush(channel->cl);
+		return -EINTR;
+	}
+
+	msg = hsc_get_first_msg(channel, &channel->tx_msgs_queue);
+	if (msg) {
+		if (msg->status == HSI_STATUS_ERROR)
+			ret = -EIO;
+		else
+			ret = hsc_msg_len_get(msg);
+
+		hsc_add_tail(channel, msg, &channel->free_msgs_list);
+	}
+out:
+	clear_bit(HSC_CH_WRITE, &channel->flags);
+
+	return ret;
+}
+
+static long hsc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct hsc_channel *channel = file->private_data;
+	unsigned int state;
+	struct hsc_rx_config rxc;
+	struct hsc_tx_config txc;
+	long ret = 0;
+
+	switch (cmd) {
+	case HSC_RESET:
+		hsi_flush(channel->cl);
+		break;
+	case HSC_SET_PM:
+		if (copy_from_user(&state, (void __user *)arg, sizeof(state)))
+			return -EFAULT;
+		if (state == HSC_PM_DISABLE) {
+			if (test_and_set_bit(HSC_CH_WLINE, &channel->flags))
+				return -EINVAL;
+			ret = hsi_start_tx(channel->cl);
+		} else if (state == HSC_PM_ENABLE) {
+			if (!test_and_clear_bit(HSC_CH_WLINE, &channel->flags))
+				return -EINVAL;
+			ret = hsi_stop_tx(channel->cl);
+		} else {
+			ret = -EINVAL;
+		}
+		break;
+	case HSC_SEND_BREAK:
+		return hsc_break_send(channel->cl);
+	case HSC_SET_RX:
+		if (copy_from_user(&rxc, (void __user *)arg, sizeof(rxc)))
+			return -EFAULT;
+		return hsc_rx_set(channel->cl, &rxc);
+	case HSC_GET_RX:
+		hsc_rx_get(channel->cl, &rxc);
+		if (copy_to_user((void __user *)arg, &rxc, sizeof(rxc)))
+			return -EFAULT;
+		break;
+	case HSC_SET_TX:
+		if (copy_from_user(&txc, (void __user *)arg, sizeof(txc)))
+			return -EFAULT;
+		return hsc_tx_set(channel->cl, &txc);
+	case HSC_GET_TX:
+		hsc_tx_get(channel->cl, &txc);
+		if (copy_to_user((void __user *)arg, &txc, sizeof(txc)))
+			return -EFAULT;
+		break;
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	return ret;
+}
+
+static inline void __hsc_port_release(struct hsc_client_data *cl_data)
+{
+	BUG_ON(cl_data->usecnt == 0);
+
+	if (--cl_data->usecnt == 0) {
+		hsi_flush(cl_data->cl);
+		hsi_release_port(cl_data->cl);
+	}
+}
+
+static int hsc_open(struct inode *inode, struct file *file)
+{
+	struct hsc_client_data *cl_data;
+	struct hsc_channel *channel;
+	int ret = 0;
+
+	pr_debug("open, minor = %d\n", iminor(inode));
+
+	cl_data = container_of(inode->i_cdev, struct hsc_client_data, cdev);
+	mutex_lock(&cl_data->lock);
+	channel = cl_data->channels + (iminor(inode) & HSC_CH_MASK);
+
+	if (test_and_set_bit(HSC_CH_OPEN, &channel->flags)) {
+		ret = -EBUSY;
+		goto out;
+	}
+	/*
+	 * Check if we have already claimed the port associated to the HSI
+	 * client. If not then try to claim it, else increase its refcount
+	 */
+	if (cl_data->usecnt == 0) {
+		ret = hsi_claim_port(cl_data->cl, 0);
+		if (ret < 0)
+			goto out;
+		hsi_setup(cl_data->cl);
+	}
+	cl_data->usecnt++;
+
+	ret = hsc_msgs_alloc(channel);
+	if (ret < 0) {
+		__hsc_port_release(cl_data);
+		goto out;
+	}
+
+	file->private_data = channel;
+	mutex_unlock(&cl_data->lock);
+
+	return ret;
+out:
+	mutex_unlock(&cl_data->lock);
+
+	return ret;
+}
+
+static int hsc_release(struct inode *inode __maybe_unused, struct file *file)
+{
+	struct hsc_channel *channel = file->private_data;
+	struct hsc_client_data *cl_data = channel->cl_data;
+
+	mutex_lock(&cl_data->lock);
+	file->private_data = NULL;
+	if (test_and_clear_bit(HSC_CH_WLINE, &channel->flags))
+		hsi_stop_tx(channel->cl);
+	__hsc_port_release(cl_data);
+	hsc_reset_list(channel, &channel->rx_msgs_queue);
+	hsc_reset_list(channel, &channel->tx_msgs_queue);
+	hsc_reset_list(channel, &channel->free_msgs_list);
+	clear_bit(HSC_CH_READ, &channel->flags);
+	clear_bit(HSC_CH_WRITE, &channel->flags);
+	clear_bit(HSC_CH_OPEN, &channel->flags);
+	wake_up(&channel->rx_wait);
+	wake_up(&channel->tx_wait);
+	mutex_unlock(&cl_data->lock);
+
+	return 0;
+}
+
+static const struct file_operations hsc_fops = {
+	.owner		= THIS_MODULE,
+	.read		= hsc_read,
+	.write		= hsc_write,
+	.unlocked_ioctl	= hsc_ioctl,
+	.open		= hsc_open,
+	.release	= hsc_release,
+};
+
+static void __devinit hsc_channel_init(struct hsc_channel *channel)
+{
+	init_waitqueue_head(&channel->rx_wait);
+	init_waitqueue_head(&channel->tx_wait);
+	spin_lock_init(&channel->lock);
+	INIT_LIST_HEAD(&channel->free_msgs_list);
+	INIT_LIST_HEAD(&channel->rx_msgs_queue);
+	INIT_LIST_HEAD(&channel->tx_msgs_queue);
+}
+
+static int __devinit hsc_probe(struct device *dev)
+{
+	const char devname[] = "hsi_char";
+	struct hsc_client_data *cl_data;
+	struct hsc_channel *channel;
+	struct hsi_client *cl = to_hsi_client(dev);
+	unsigned int hsc_baseminor;
+	dev_t hsc_dev;
+	int ret;
+	int i;
+
+	cl_data = kzalloc(sizeof(*cl_data), GFP_KERNEL);
+	if (!cl_data) {
+		dev_err(dev, "Could not allocate hsc_client_data\n");
+		return -ENOMEM;
+	}
+	hsc_baseminor = HSC_BASEMINOR(hsi_id(cl), hsi_port_id(cl));
+	if (!hsc_major) {
+		ret = alloc_chrdev_region(&hsc_dev, hsc_baseminor,
+						HSC_DEVS, devname);
+		if (ret > 0)
+			hsc_major = MAJOR(hsc_dev);
+	} else {
+		hsc_dev = MKDEV(hsc_major, hsc_baseminor);
+		ret = register_chrdev_region(hsc_dev, HSC_DEVS, devname);
+	}
+	if (ret < 0) {
+		dev_err(dev, "Device %s allocation failed %d\n",
+					hsc_major ? "minor" : "major", ret);
+		goto out1;
+	}
+	mutex_init(&cl_data->lock);
+	hsi_client_set_drvdata(cl, cl_data);
+	cdev_init(&cl_data->cdev, &hsc_fops);
+	cl_data->cdev.owner = THIS_MODULE;
+	cl_data->cl = cl;
+	for (i = 0, channel = cl_data->channels; i < HSC_DEVS; i++, channel++) {
+		hsc_channel_init(channel);
+		channel->ch = i;
+		channel->cl = cl;
+		channel->cl_data = cl_data;
+	}
+
+	/* 1 hsi client -> N char devices (one for each channel) */
+	ret = cdev_add(&cl_data->cdev, hsc_dev, HSC_DEVS);
+	if (ret) {
+		dev_err(dev, "Could not add char device %d\n", ret);
+		goto out2;
+	}
+
+	return 0;
+out2:
+	unregister_chrdev_region(hsc_dev, HSC_DEVS);
+out1:
+	kfree(cl_data);
+
+	return ret;
+}
+
+static int __devexit hsc_remove(struct device *dev)
+{
+	struct hsi_client *cl = to_hsi_client(dev);
+	struct hsc_client_data *cl_data = hsi_client_drvdata(cl);
+	dev_t hsc_dev = cl_data->cdev.dev;
+
+	cdev_del(&cl_data->cdev);
+	unregister_chrdev_region(hsc_dev, HSC_DEVS);
+	hsi_client_set_drvdata(cl, NULL);
+	kfree(cl_data);
+
+	return 0;
+}
+
+static struct hsi_client_driver hsc_driver = {
+	.driver = {
+		.name	= "hsi_char",
+		.owner	= THIS_MODULE,
+		.probe	= hsc_probe,
+		.remove	= __devexit_p(hsc_remove),
+	},
+};
+
+static int __init hsc_init(void)
+{
+	int ret;
+
+	if ((max_data_size < 4) || (max_data_size > 0x10000) ||
+		(max_data_size & (max_data_size - 1))) {
+		pr_err("Invalid max read/write data size");
+		return -EINVAL;
+	}
+
+	ret = hsi_register_client_driver(&hsc_driver);
+	if (ret) {
+		pr_err("Error while registering HSI/SSI driver %d", ret);
+		return ret;
+	}
+
+	pr_info("HSI/SSI char device loaded\n");
+
+	return 0;
+}
+module_init(hsc_init);
+
+static void __exit hsc_exit(void)
+{
+	hsi_unregister_client_driver(&hsc_driver);
+	pr_info("HSI char device removed\n");
+}
+module_exit(hsc_exit);
+
+MODULE_AUTHOR("Andras Domokos <andras.domokos@nokia.com>");
+MODULE_ALIAS("hsi:hsi_char");
+MODULE_DESCRIPTION("HSI character device");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
new file mode 100644
index 0000000..4e2d79b
--- /dev/null
+++ b/drivers/hsi/hsi.c
@@ -0,0 +1,494 @@
+/*
+ * HSI core.
+ *
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Carlos Chinea <carlos.chinea@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/hsi/hsi.h>
+#include <linux/compiler.h>
+#include <linux/rwsem.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/kobject.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include "hsi_core.h"
+
+static struct device_type hsi_ctrl = {
+	.name	= "hsi_controller",
+};
+
+static struct device_type hsi_cl = {
+	.name	= "hsi_client",
+};
+
+static struct device_type hsi_port = {
+	.name	= "hsi_port",
+};
+
+static ssize_t modalias_show(struct device *dev,
+			struct device_attribute *a __maybe_unused, char *buf)
+{
+	return sprintf(buf, "hsi:%s\n", dev_name(dev));
+}
+
+static struct device_attribute hsi_bus_dev_attrs[] = {
+	__ATTR_RO(modalias),
+	__ATTR_NULL,
+};
+
+static int hsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	if (dev->type == &hsi_cl)
+		add_uevent_var(env, "MODALIAS=hsi:%s", dev_name(dev));
+
+	return 0;
+}
+
+static int hsi_bus_match(struct device *dev, struct device_driver *driver)
+{
+	return strcmp(dev_name(dev), driver->name) == 0;
+}
+
+static struct bus_type hsi_bus_type = {
+	.name		= "hsi",
+	.dev_attrs	= hsi_bus_dev_attrs,
+	.match		= hsi_bus_match,
+	.uevent		= hsi_bus_uevent,
+};
+
+static void hsi_client_release(struct device *dev)
+{
+	kfree(to_hsi_client(dev));
+}
+
+static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info)
+{
+	struct hsi_client *cl;
+	unsigned long flags;
+
+	cl = kzalloc(sizeof(*cl), GFP_KERNEL);
+	if (!cl)
+		return;
+	cl->device.type = &hsi_cl;
+	cl->tx_cfg = info->tx_cfg;
+	cl->rx_cfg = info->rx_cfg;
+	cl->device.bus = &hsi_bus_type;
+	cl->device.parent = &port->device;
+	cl->device.release = hsi_client_release;
+	dev_set_name(&cl->device, info->name);
+	cl->device.platform_data = info->platform_data;
+	spin_lock_irqsave(&port->clock, flags);
+	list_add_tail(&cl->link, &port->clients);
+	spin_unlock_irqrestore(&port->clock, flags);
+	if (info->archdata)
+		cl->device.archdata = *info->archdata;
+	if (device_register(&cl->device) < 0) {
+		pr_err("hsi: failed to register client: %s\n", info->name);
+		kfree(cl);
+	}
+}
+
+static void hsi_scan_board_info(struct hsi_controller *hsi)
+{
+	struct hsi_cl_info *cl_info;
+	struct hsi_port	*p;
+
+	list_for_each_entry(cl_info, &hsi_board_list, list)
+		if (cl_info->info.hsi_id == hsi->id) {
+			p = hsi_find_port_num(hsi, cl_info->info.port);
+			if (!p)
+				continue;
+			hsi_new_client(p, &cl_info->info);
+		}
+}
+
+static int hsi_remove_client(struct device *dev, void *data __maybe_unused)
+{
+	struct hsi_client *cl = to_hsi_client(dev);
+	struct hsi_port *port = to_hsi_port(dev->parent);
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->clock, flags);
+	list_del(&cl->link);
+	spin_unlock_irqrestore(&port->clock, flags);
+	device_unregister(dev);
+
+	return 0;
+}
+
+static int hsi_remove_port(struct device *dev, void *data __maybe_unused)
+{
+	device_for_each_child(dev, NULL, hsi_remove_client);
+	device_unregister(dev);
+
+	return 0;
+}
+
+static void hsi_controller_release(struct device *dev __maybe_unused)
+{
+}
+
+static void hsi_port_release(struct device *dev __maybe_unused)
+{
+}
+
+/**
+ * hsi_unregister_controller - Unregister an HSI controller
+ * @hsi: The HSI controller to register
+ */
+void hsi_unregister_controller(struct hsi_controller *hsi)
+{
+	device_for_each_child(&hsi->device, NULL, hsi_remove_port);
+	device_unregister(&hsi->device);
+}
+EXPORT_SYMBOL_GPL(hsi_unregister_controller);
+
+/**
+ * hsi_register_controller - Register an HSI controller and its ports
+ * @hsi: The HSI controller to register
+ *
+ * Returns -errno on failure, 0 on success.
+ */
+int hsi_register_controller(struct hsi_controller *hsi)
+{
+	unsigned int i;
+	int err;
+
+	hsi->device.type = &hsi_ctrl;
+	hsi->device.bus = &hsi_bus_type;
+	hsi->device.release = hsi_controller_release;
+	err = device_register(&hsi->device);
+	if (err < 0)
+		return err;
+	for (i = 0; i < hsi->num_ports; i++) {
+		hsi->port[i].device.parent = &hsi->device;
+		hsi->port[i].device.bus = &hsi_bus_type;
+		hsi->port[i].device.release = hsi_port_release;
+		hsi->port[i].device.type = &hsi_port;
+		INIT_LIST_HEAD(&hsi->port[i].clients);
+		spin_lock_init(&hsi->port[i].clock);
+		err = device_register(&hsi->port[i].device);
+		if (err < 0)
+			goto out;
+	}
+	/* Populate HSI bus with HSI clients */
+	hsi_scan_board_info(hsi);
+
+	return 0;
+out:
+	hsi_unregister_controller(hsi);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(hsi_register_controller);
+
+/**
+ * hsi_register_client_driver - Register an HSI client to the HSI bus
+ * @drv: HSI client driver to register
+ *
+ * Returns -errno on failure, 0 on success.
+ */
+int hsi_register_client_driver(struct hsi_client_driver *drv)
+{
+	drv->driver.bus = &hsi_bus_type;
+
+	return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(hsi_register_client_driver);
+
+static inline int hsi_dummy_msg(struct hsi_msg *msg __maybe_unused)
+{
+	return 0;
+}
+
+static inline int hsi_dummy_cl(struct hsi_client *cl __maybe_unused)
+{
+	return 0;
+}
+
+/**
+ * hsi_alloc_controller - Allocate an HSI controller and its ports
+ * @n_ports: Number of ports on the HSI controller
+ * @flags: Kernel allocation flags
+ *
+ * Return NULL on failure or a pointer to an hsi_controller on success.
+ */
+struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags)
+{
+	struct hsi_controller	*hsi;
+	struct hsi_port		*port;
+	unsigned int		i;
+
+	if (!n_ports)
+		return NULL;
+
+	port = kzalloc(sizeof(*port)*n_ports, flags);
+	if (!port)
+		return NULL;
+	hsi = kzalloc(sizeof(*hsi), flags);
+	if (!hsi)
+		goto out;
+	for (i = 0; i < n_ports; i++) {
+		dev_set_name(&port[i].device, "port%d", i);
+		port[i].num = i;
+		port[i].async = hsi_dummy_msg;
+		port[i].setup = hsi_dummy_cl;
+		port[i].flush = hsi_dummy_cl;
+		port[i].start_tx = hsi_dummy_cl;
+		port[i].stop_tx = hsi_dummy_cl;
+		port[i].release = hsi_dummy_cl;
+		mutex_init(&port[i].lock);
+	}
+	hsi->num_ports = n_ports;
+	hsi->port = port;
+
+	return hsi;
+out:
+	kfree(port);
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(hsi_alloc_controller);
+
+/**
+ * hsi_free_controller - Free an HSI controller
+ * @hsi: Pointer to HSI controller
+ */
+void hsi_free_controller(struct hsi_controller *hsi)
+{
+	if (!hsi)
+		return;
+
+	kfree(hsi->port);
+	kfree(hsi);
+}
+EXPORT_SYMBOL_GPL(hsi_free_controller);
+
+/**
+ * hsi_free_msg - Free an HSI message
+ * @msg: Pointer to the HSI message
+ *
+ * Client is responsible to free the buffers pointed by the scatterlists.
+ */
+void hsi_free_msg(struct hsi_msg *msg)
+{
+	if (!msg)
+		return;
+	sg_free_table(&msg->sgt);
+	kfree(msg);
+}
+EXPORT_SYMBOL_GPL(hsi_free_msg);
+
+/**
+ * hsi_alloc_msg - Allocate an HSI message
+ * @nents: Number of memory entries
+ * @flags: Kernel allocation flags
+ *
+ * nents can be 0. This mainly makes sense for read transfer.
+ * In that case, HSI drivers will call the complete callback when
+ * there is data to be read without consuming it.
+ *
+ * Return NULL on failure or a pointer to an hsi_msg on success.
+ */
+struct hsi_msg *hsi_alloc_msg(unsigned int nents, gfp_t flags)
+{
+	struct hsi_msg *msg;
+	int err;
+
+	msg = kzalloc(sizeof(*msg), flags);
+	if (!msg)
+		return NULL;
+
+	if (!nents)
+		return msg;
+
+	err = sg_alloc_table(&msg->sgt, nents, flags);
+	if (unlikely(err)) {
+		kfree(msg);
+		msg = NULL;
+	}
+
+	return msg;
+}
+EXPORT_SYMBOL_GPL(hsi_alloc_msg);
+
+/**
+ * hsi_async - Submit an HSI transfer to the controller
+ * @cl: HSI client sending the transfer
+ * @msg: The HSI transfer passed to controller
+ *
+ * The HSI message must have the channel, ttype, complete and destructor
+ * fields set beforehand. If nents > 0 then the client has to initialize
+ * also the scatterlists to point to the buffers to write to or read from.
+ *
+ * HSI controllers relay on pre-allocated buffers from their clients and they
+ * do not allocate buffers on their own.
+ *
+ * Once the HSI message transfer finishes, the HSI controller calls the
+ * complete callback with the status and actual_len fields of the HSI message
+ * updated. The complete callback can be called before returning from
+ * hsi_async.
+ *
+ * Returns -errno on failure or 0 on success
+ */
+int hsi_async(struct hsi_client *cl, struct hsi_msg *msg)
+{
+	struct hsi_port *port = hsi_get_port(cl);
+
+	if (!hsi_port_claimed(cl))
+		return -EACCES;
+
+	WARN_ON_ONCE(!msg->destructor || !msg->complete);
+	msg->cl = cl;
+
+	return port->async(msg);
+}
+EXPORT_SYMBOL_GPL(hsi_async);
+
+/**
+ * hsi_claim_port - Claim the HSI client's port
+ * @cl: HSI client that wants to claim its port
+ * @share: Flag to indicate if the client wants to share the port or not.
+ *
+ * Returns -errno on failure, 0 on success.
+ */
+int hsi_claim_port(struct hsi_client *cl, unsigned int share)
+{
+	struct hsi_port *port = hsi_get_port(cl);
+	int err = 0;
+
+	mutex_lock(&port->lock);
+	if ((port->claimed) && (!port->shared || !share)) {
+		err = -EBUSY;
+		goto out;
+	}
+	if (!try_module_get(to_hsi_controller(port->device.parent)->owner)) {
+		err = -ENODEV;
+		goto out;
+	}
+	port->claimed++;
+	port->shared = !!share;
+	cl->pclaimed = 1;
+out:
+	mutex_unlock(&port->lock);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(hsi_claim_port);
+
+/**
+ * hsi_release_port - Release the HSI client's port
+ * @cl: HSI client which previously claimed its port
+ */
+void hsi_release_port(struct hsi_client *cl)
+{
+	struct hsi_port *port = hsi_get_port(cl);
+
+	mutex_lock(&port->lock);
+	/* Allow HW driver to do some cleanup */
+	port->release(cl);
+	if (cl->pclaimed)
+		port->claimed--;
+	BUG_ON(port->claimed < 0);
+	cl->pclaimed = 0;
+	if (!port->claimed)
+		port->shared = 0;
+	module_put(to_hsi_controller(port->device.parent)->owner);
+	mutex_unlock(&port->lock);
+}
+EXPORT_SYMBOL_GPL(hsi_release_port);
+
+static int hsi_start_rx(struct hsi_client *cl, void *data __maybe_unused)
+{
+	if (cl->hsi_start_rx)
+		(*cl->hsi_start_rx)(cl);
+
+	return 0;
+}
+
+static int hsi_stop_rx(struct hsi_client *cl, void *data __maybe_unused)
+{
+	if (cl->hsi_stop_rx)
+		(*cl->hsi_stop_rx)(cl);
+
+	return 0;
+}
+
+static int hsi_port_for_each_client(struct hsi_port *port, void *data,
+				int (*fn)(struct hsi_client *cl, void *data))
+{
+	struct hsi_client *cl;
+
+	spin_lock(&port->clock);
+	list_for_each_entry(cl, &port->clients, link) {
+		spin_unlock(&port->clock);
+		(*fn)(cl, data);
+		spin_lock(&port->clock);
+	}
+	spin_unlock(&port->clock);
+
+	return 0;
+}
+
+/**
+ * hsi_event -Notifies clients about port events
+ * @port: Port where the event occurred
+ * @event: The event type
+ *
+ * Clients should not be concerned about wake line behavior. However, due
+ * to a race condition in HSI HW protocol, clients need to be notified
+ * about wake line changes, so they can implement a workaround for it.
+ *
+ * Events:
+ * HSI_EVENT_START_RX - Incoming wake line high
+ * HSI_EVENT_STOP_RX - Incoming wake line down
+ */
+void hsi_event(struct hsi_port *port, unsigned int event)
+{
+	int (*fn)(struct hsi_client *cl, void *data);
+
+	switch (event) {
+	case HSI_EVENT_START_RX:
+		fn = hsi_start_rx;
+		break;
+	case HSI_EVENT_STOP_RX:
+		fn = hsi_stop_rx;
+		break;
+	default:
+		return;
+	}
+	hsi_port_for_each_client(port, NULL, fn);
+}
+EXPORT_SYMBOL_GPL(hsi_event);
+
+static int __init hsi_init(void)
+{
+	return bus_register(&hsi_bus_type);
+}
+postcore_initcall(hsi_init);
+
+static void __exit hsi_exit(void)
+{
+	bus_unregister(&hsi_bus_type);
+}
+module_exit(hsi_exit);
+
+MODULE_AUTHOR("Carlos Chinea <carlos.chinea@nokia.com>");
+MODULE_DESCRIPTION("High-speed Synchronous Serial Interface (HSI) framework");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hsi/hsi_boardinfo.c b/drivers/hsi/hsi_boardinfo.c
new file mode 100644
index 0000000..e56bc6d
--- /dev/null
+++ b/drivers/hsi/hsi_boardinfo.c
@@ -0,0 +1,62 @@
+/*
+ * HSI clients registration interface
+ *
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Carlos Chinea <carlos.chinea@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/hsi/hsi.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include "hsi_core.h"
+
+/*
+ * hsi_board_list is only used internally by the HSI framework.
+ * No one else is allowed to make use of it.
+ */
+LIST_HEAD(hsi_board_list);
+EXPORT_SYMBOL_GPL(hsi_board_list);
+
+/**
+ * hsi_register_board_info - Register HSI clients information
+ * @info: Array of HSI clients on the board
+ * @len: Length of the array
+ *
+ * HSI clients are statically declared and registered on board files.
+ *
+ * HSI clients will be automatically registered to the HSI bus once the
+ * controller and the port where the clients wishes to attach are registered
+ * to it.
+ *
+ * Return -errno on failure, 0 on success.
+ */
+int __init hsi_register_board_info(struct hsi_board_info const *info,
+							unsigned int len)
+{
+	struct hsi_cl_info *cl_info;
+
+	cl_info = kzalloc(sizeof(*cl_info) * len, GFP_KERNEL);
+	if (!cl_info)
+		return -ENOMEM;
+
+	for (; len; len--, info++, cl_info++) {
+		cl_info->info = *info;
+		list_add_tail(&cl_info->list, &hsi_board_list);
+	}
+
+	return 0;
+}
diff --git a/drivers/hsi/hsi_core.h b/drivers/hsi/hsi_core.h
new file mode 100644
index 0000000..ab5c2fb
--- /dev/null
+++ b/drivers/hsi/hsi_core.h
@@ -0,0 +1,35 @@
+/*
+ * HSI framework internal interfaces,
+ *
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Carlos Chinea <carlos.chinea@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
+ */
+
+#ifndef __LINUX_HSI_CORE_H__
+#define __LINUX_HSI_CORE_H__
+
+#include <linux/hsi/hsi.h>
+
+struct hsi_cl_info {
+	struct list_head	list;
+	struct hsi_board_info	info;
+};
+
+extern struct list_head hsi_board_list;
+
+#endif /* __LINUX_HSI_CORE_H__ */
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 811e6c4..8deedc1 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -253,7 +253,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) microarchitectures.
+	  12h (Llano), 14h (Brazos) and 15h (Bulldozer/Trinity)
+	  microarchitectures.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called k10temp.
@@ -425,7 +426,7 @@
 
 config SENSORS_GPIO_FAN
 	tristate "GPIO fan"
-	depends on GENERIC_GPIO
+	depends on GPIOLIB
 	help
 	  If you say yes here you get support for fans connected to GPIO lines.
 
@@ -648,7 +649,8 @@
 	  LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A,
 	  Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659,
 	  MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008,
-	  Winbond/Nuvoton W83L771W/G/AWG/ASG and Philips SA56004 sensor chips.
+	  Winbond/Nuvoton W83L771W/G/AWG/ASG, Philips SA56004, and GMT G781
+	  sensor chips.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called lm90.
@@ -812,6 +814,16 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called max6650.
 
+config SENSORS_MCP3021
+	tristate "Microchip MCP3021"
+	depends on I2C && EXPERIMENTAL
+	help
+	  If you say yes here you get support for the MCP3021 chip
+	  that is a A/D converter (ADC) with 10-bit resolution.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called mcp3021.
+
 config SENSORS_NTC_THERMISTOR
 	tristate "NTC thermistor support"
 	depends on EXPERIMENTAL
@@ -872,7 +884,7 @@
 
 config SENSORS_SHT15
 	tristate "Sensiron humidity and temperature sensors. SHT15 and compat."
-	depends on GENERIC_GPIO
+	depends on GPIOLIB
 	help
 	  If you say yes here you get support for the Sensiron SHT10, SHT11,
 	  SHT15, SHT71, SHT75 humidity and temperature sensors.
@@ -1229,18 +1241,19 @@
 	depends on I2C && EXPERIMENTAL
 	help
 	  If you say yes here you get support for the Winbond W83795G and
-	  W83795ADG hardware monitoring chip.
+	  W83795ADG hardware monitoring chip, including manual fan speed
+	  control.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called w83795.
 
 config SENSORS_W83795_FANCTRL
-	boolean "Include fan control support (DANGEROUS)"
+	boolean "Include automatic fan control support (DANGEROUS)"
 	depends on SENSORS_W83795 && EXPERIMENTAL
 	default n
 	help
-	  If you say yes here, support for the both manual and automatic
-	  fan control features will be included in the driver.
+	  If you say yes here, support for automatic fan speed control
+	  will be included in the driver.
 
 	  This part of the code wasn't carefully reviewed and tested yet,
 	  so enabling this option is strongly discouraged on production
@@ -1358,10 +1371,10 @@
 	  the awesome power of applesmc.
 
 config SENSORS_MC13783_ADC
-        tristate "Freescale MC13783 ADC"
-        depends on MFD_MC13783
+        tristate "Freescale MC13783/MC13892 ADC"
+        depends on MFD_MC13XXX
         help
-          Support for the A/D converter on MC13783 PMIC.
+          Support for the A/D converter on MC13783 and MC13892 PMIC.
 
 if ACPI
 
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 8251ce8..6d3f11f 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -95,6 +95,7 @@
 obj-$(CONFIG_SENSORS_MAX6642)	+= max6642.o
 obj-$(CONFIG_SENSORS_MAX6650)	+= max6650.o
 obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
+obj-$(CONFIG_SENSORS_MCP3021)	+= mcp3021.o
 obj-$(CONFIG_SENSORS_NTC_THERMISTOR)	+= ntc_thermistor.o
 obj-$(CONFIG_SENSORS_PC87360)	+= pc87360.o
 obj-$(CONFIG_SENSORS_PC87427)	+= pc87427.o
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
index 554f046..145f135 100644
--- a/drivers/hwmon/acpi_power_meter.c
+++ b/drivers/hwmon/acpi_power_meter.c
@@ -632,6 +632,7 @@
 		sensors->dev_attr.show = ro->show;
 		sensors->index = ro->index;
 
+		sysfs_attr_init(&sensors->dev_attr.attr);
 		res = device_create_file(dev, &sensors->dev_attr);
 		if (res) {
 			sensors->dev_attr.attr.name = NULL;
@@ -661,6 +662,7 @@
 		sensors->dev_attr.store = rw->set;
 		sensors->index = rw->index;
 
+		sysfs_attr_init(&sensors->dev_attr.attr);
 		res = device_create_file(dev, &sensors->dev_attr);
 		if (res) {
 			sensors->dev_attr.attr.name = NULL;
diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c
index 0e0cfcc..ce43642 100644
--- a/drivers/hwmon/ad7314.c
+++ b/drivers/hwmon/ad7314.c
@@ -128,6 +128,7 @@
 		ret = PTR_ERR(chip->hwmon_dev);
 		goto error_remove_group;
 	}
+	chip->spi_dev = spi_dev;
 
 	return 0;
 error_remove_group:
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
index ff37363..44e1fd7 100644
--- a/drivers/hwmon/adm1031.c
+++ b/drivers/hwmon/adm1031.c
@@ -233,18 +233,15 @@
  * nearest match if no exact match where found.
  */
 static int
-get_fan_auto_nearest(struct adm1031_data *data,
-		     int chan, u8 val, u8 reg, u8 *new_reg)
+get_fan_auto_nearest(struct adm1031_data *data, int chan, u8 val, u8 reg)
 {
 	int i;
 	int first_match = -1, exact_match = -1;
 	u8 other_reg_val =
 	    (*data->chan_select_table)[FAN_CHAN_FROM_REG(reg)][chan ? 0 : 1];
 
-	if (val == 0) {
-		*new_reg = 0;
+	if (val == 0)
 		return 0;
-	}
 
 	for (i = 0; i < 8; i++) {
 		if ((val == (*data->chan_select_table)[i][chan]) &&
@@ -264,13 +261,11 @@
 	}
 
 	if (exact_match >= 0)
-		*new_reg = exact_match;
+		return exact_match;
 	else if (first_match >= 0)
-		*new_reg = first_match;
-	else
-		return -EINVAL;
+		return first_match;
 
-	return 0;
+	return -EINVAL;
 }
 
 static ssize_t show_fan_auto_channel(struct device *dev,
@@ -301,11 +296,12 @@
 
 	mutex_lock(&data->update_lock);
 
-	ret = get_fan_auto_nearest(data, nr, val, data->conf1, &reg);
-	if (ret) {
+	ret = get_fan_auto_nearest(data, nr, val, data->conf1);
+	if (ret < 0) {
 		mutex_unlock(&data->update_lock);
 		return ret;
 	}
+	reg = ret;
 	data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1);
 	if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^
 	    (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) {
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
index 729499e..ece4159 100644
--- a/drivers/hwmon/f75375s.c
+++ b/drivers/hwmon/f75375s.c
@@ -276,6 +276,7 @@
 		return false;
 	default:
 		BUG();
+		return true;
 	}
 }
 
@@ -291,6 +292,7 @@
 		return true;
 	default:
 		BUG();
+		return false;
 	}
 }
 
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
index 523f8fb..b7494af 100644
--- a/drivers/hwmon/fam15h_power.c
+++ b/drivers/hwmon/fam15h_power.c
@@ -60,15 +60,15 @@
 	pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
 				  REG_TDP_RUNNING_AVERAGE, &val);
 	running_avg_capture = (val >> 4) & 0x3fffff;
-	running_avg_capture = sign_extend32(running_avg_capture, 22);
-	running_avg_range = val & 0xf;
+	running_avg_capture = sign_extend32(running_avg_capture, 21);
+	running_avg_range = (val & 0xf) + 1;
 
 	pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
 				  REG_TDP_LIMIT3, &val);
 
 	tdp_limit = val >> 16;
-	curr_pwr_watts = tdp_limit + data->base_tdp -
-		(s32)(running_avg_capture >> (running_avg_range + 1));
+	curr_pwr_watts = (tdp_limit + data->base_tdp) << running_avg_range;
+	curr_pwr_watts -= running_avg_capture;
 	curr_pwr_watts *= data->tdp_to_watts;
 
 	/*
@@ -78,7 +78,7 @@
 	 * scaling factor 1/(2^16).  For conversion we use
 	 * (10^6)/(2^16) = 15625/(2^10)
 	 */
-	curr_pwr_watts = (curr_pwr_watts * 15625) >> 10;
+	curr_pwr_watts = (curr_pwr_watts * 15625) >> (10 + running_avg_range);
 	return sprintf(buf, "%u\n", (unsigned int) curr_pwr_watts);
 }
 static DEVICE_ATTR(power1_input, S_IRUGO, show_power, NULL);
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
index 8305d29..519ce8b 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -53,8 +53,8 @@
 static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
 
 /* Insmod parameters */
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 	__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index aba29d6..307bb32 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -33,6 +33,9 @@
 module_param(force, bool, 0444);
 MODULE_PARM_DESC(force, "force loading on processors with erratum 319");
 
+/* PCI-IDs for Northbridge devices not used anywhere else */
+#define PCI_DEVICE_ID_AMD_15H_M10H_NB_F3	0x1403
+
 /* CPUID function 0x80000001, ebx */
 #define CPUID_PKGTYPE_MASK	0xf0000000
 #define CPUID_PKGTYPE_F		0x00000000
@@ -210,6 +213,7 @@
 	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) },
 	{ 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_NB_F3) },
 	{}
 };
 MODULE_DEVICE_TABLE(pci, k10temp_id_table);
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index 15c05cc..602a0f0 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -148,46 +148,9 @@
 #define UPDATE_INTERVAL(max, rate) \
 			((1000 << (LM63_MAX_CONVRATE - (rate))) / (max))
 
-/*
- * Functions declaration
- */
-
-static int lm63_probe(struct i2c_client *client,
-		      const struct i2c_device_id *id);
-static int lm63_remove(struct i2c_client *client);
-
-static struct lm63_data *lm63_update_device(struct device *dev);
-
-static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info);
-static void lm63_init_client(struct i2c_client *client);
-
 enum chips { lm63, lm64, lm96163 };
 
 /*
- * Driver data (common to all clients)
- */
-
-static const struct i2c_device_id lm63_id[] = {
-	{ "lm63", lm63 },
-	{ "lm64", lm64 },
-	{ "lm96163", lm96163 },
-	{ }
-};
-MODULE_DEVICE_TABLE(i2c, lm63_id);
-
-static struct i2c_driver lm63_driver = {
-	.class		= I2C_CLASS_HWMON,
-	.driver = {
-		.name	= "lm63",
-	},
-	.probe		= lm63_probe,
-	.remove		= lm63_remove,
-	.id_table	= lm63_id,
-	.detect		= lm63_detect,
-	.address_list	= normal_i2c,
-};
-
-/*
  * Client data (each client gets its own)
  */
 
@@ -242,6 +205,145 @@
 	return data->temp8[nr] * (data->lut_temp_highres ? 500 : 1000);
 }
 
+static inline int lut_temp_to_reg(struct lm63_data *data, long val)
+{
+	val -= data->temp2_offset;
+	if (data->lut_temp_highres)
+		return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127500), 500);
+	else
+		return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127000), 1000);
+}
+
+/*
+ * Update the lookup table register cache.
+ * client->update_lock must be held when calling this function.
+ */
+static void lm63_update_lut(struct i2c_client *client)
+{
+	struct lm63_data *data = i2c_get_clientdata(client);
+	int i;
+
+	if (time_after(jiffies, data->lut_last_updated + 5 * HZ) ||
+	    !data->lut_valid) {
+		for (i = 0; i < data->lut_size; i++) {
+			data->pwm1[1 + i] = i2c_smbus_read_byte_data(client,
+					    LM63_REG_LUT_PWM(i));
+			data->temp8[3 + i] = i2c_smbus_read_byte_data(client,
+					     LM63_REG_LUT_TEMP(i));
+		}
+		data->lut_temp_hyst = i2c_smbus_read_byte_data(client,
+				      LM63_REG_LUT_TEMP_HYST);
+
+		data->lut_last_updated = jiffies;
+		data->lut_valid = 1;
+	}
+}
+
+static struct lm63_data *lm63_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm63_data *data = i2c_get_clientdata(client);
+	unsigned long next_update;
+
+	mutex_lock(&data->update_lock);
+
+	next_update = data->last_updated
+	  + msecs_to_jiffies(data->update_interval) + 1;
+
+	if (time_after(jiffies, next_update) || !data->valid) {
+		if (data->config & 0x04) { /* tachometer enabled  */
+			/* order matters for fan1_input */
+			data->fan[0] = i2c_smbus_read_byte_data(client,
+				       LM63_REG_TACH_COUNT_LSB) & 0xFC;
+			data->fan[0] |= i2c_smbus_read_byte_data(client,
+					LM63_REG_TACH_COUNT_MSB) << 8;
+			data->fan[1] = (i2c_smbus_read_byte_data(client,
+					LM63_REG_TACH_LIMIT_LSB) & 0xFC)
+				     | (i2c_smbus_read_byte_data(client,
+					LM63_REG_TACH_LIMIT_MSB) << 8);
+		}
+
+		data->pwm1_freq = i2c_smbus_read_byte_data(client,
+				  LM63_REG_PWM_FREQ);
+		if (data->pwm1_freq == 0)
+			data->pwm1_freq = 1;
+		data->pwm1[0] = i2c_smbus_read_byte_data(client,
+				LM63_REG_PWM_VALUE);
+
+		data->temp8[0] = i2c_smbus_read_byte_data(client,
+				 LM63_REG_LOCAL_TEMP);
+		data->temp8[1] = i2c_smbus_read_byte_data(client,
+				 LM63_REG_LOCAL_HIGH);
+
+		/* order matters for temp2_input */
+		data->temp11[0] = i2c_smbus_read_byte_data(client,
+				  LM63_REG_REMOTE_TEMP_MSB) << 8;
+		data->temp11[0] |= i2c_smbus_read_byte_data(client,
+				   LM63_REG_REMOTE_TEMP_LSB);
+		data->temp11[1] = (i2c_smbus_read_byte_data(client,
+				  LM63_REG_REMOTE_LOW_MSB) << 8)
+				| i2c_smbus_read_byte_data(client,
+				  LM63_REG_REMOTE_LOW_LSB);
+		data->temp11[2] = (i2c_smbus_read_byte_data(client,
+				  LM63_REG_REMOTE_HIGH_MSB) << 8)
+				| i2c_smbus_read_byte_data(client,
+				  LM63_REG_REMOTE_HIGH_LSB);
+		data->temp11[3] = (i2c_smbus_read_byte_data(client,
+				  LM63_REG_REMOTE_OFFSET_MSB) << 8)
+				| i2c_smbus_read_byte_data(client,
+				  LM63_REG_REMOTE_OFFSET_LSB);
+
+		if (data->kind == lm96163)
+			data->temp11u = (i2c_smbus_read_byte_data(client,
+					LM96163_REG_REMOTE_TEMP_U_MSB) << 8)
+				      | i2c_smbus_read_byte_data(client,
+					LM96163_REG_REMOTE_TEMP_U_LSB);
+
+		data->temp8[2] = i2c_smbus_read_byte_data(client,
+				 LM63_REG_REMOTE_TCRIT);
+		data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
+					LM63_REG_REMOTE_TCRIT_HYST);
+
+		data->alarms = i2c_smbus_read_byte_data(client,
+			       LM63_REG_ALERT_STATUS) & 0x7F;
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	lm63_update_lut(client);
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
+ * Trip points in the lookup table should be in ascending order for both
+ * temperatures and PWM output values.
+ */
+static int lm63_lut_looks_bad(struct i2c_client *client)
+{
+	struct lm63_data *data = i2c_get_clientdata(client);
+	int i;
+
+	mutex_lock(&data->update_lock);
+	lm63_update_lut(client);
+
+	for (i = 1; i < data->lut_size; i++) {
+		if (data->pwm1[1 + i - 1] > data->pwm1[1 + i]
+		 || data->temp8[3 + i - 1] > data->temp8[3 + i]) {
+			dev_warn(&client->dev,
+				 "Lookup table doesn't look sane (check entries %d and %d)\n",
+				 i, i + 1);
+			break;
+		}
+	}
+	mutex_unlock(&data->update_lock);
+
+	return i == data->lut_size ? 0 : 1;
+}
+
 /*
  * Sysfs callback functions and files
  */
@@ -294,13 +396,16 @@
 	return sprintf(buf, "%d\n", pwm);
 }
 
-static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
+static ssize_t set_pwm1(struct device *dev, struct device_attribute *devattr,
 			const char *buf, size_t count)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm63_data *data = i2c_get_clientdata(client);
+	int nr = attr->index;
 	unsigned long val;
 	int err;
+	u8 reg;
 
 	if (!(data->config_fan & 0x20)) /* register is read-only */
 		return -EPERM;
@@ -309,11 +414,13 @@
 	if (err)
 		return err;
 
+	reg = nr ? LM63_REG_LUT_PWM(nr - 1) : LM63_REG_PWM_VALUE;
 	val = SENSORS_LIMIT(val, 0, 255);
+
 	mutex_lock(&data->update_lock);
-	data->pwm1[0] = data->pwm_highres ? val :
+	data->pwm1[nr] = data->pwm_highres ? val :
 			(val * data->pwm1_freq * 2 + 127) / 255;
-	i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1[0]);
+	i2c_smbus_write_byte_data(client, reg, data->pwm1[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -325,6 +432,41 @@
 	return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2);
 }
 
+static ssize_t set_pwm1_enable(struct device *dev,
+			       struct device_attribute *dummy,
+			       const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm63_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	if (val < 1 || val > 2)
+		return -EINVAL;
+
+	/*
+	 * Only let the user switch to automatic mode if the lookup table
+	 * looks sane.
+	 */
+	if (val == 2 && lm63_lut_looks_bad(client))
+		return -EPERM;
+
+	mutex_lock(&data->update_lock);
+	data->config_fan = i2c_smbus_read_byte_data(client,
+						    LM63_REG_CONFIG_FAN);
+	if (val == 1)
+		data->config_fan |= 0x20;
+	else
+		data->config_fan &= ~0x20;
+	i2c_smbus_write_byte_data(client, LM63_REG_CONFIG_FAN,
+	data->config_fan);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
 /*
  * There are 8bit registers for both local(temp1) and remote(temp2) sensor.
  * For remote sensor registers temp2_offset has to be considered,
@@ -367,23 +509,31 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm63_data *data = i2c_get_clientdata(client);
 	int nr = attr->index;
-	int reg = nr == 2 ? LM63_REG_REMOTE_TCRIT : LM63_REG_LOCAL_HIGH;
 	long val;
 	int err;
 	int temp;
+	u8 reg;
 
 	err = kstrtol(buf, 10, &val);
 	if (err)
 		return err;
 
 	mutex_lock(&data->update_lock);
-	if (nr == 2) {
+	switch (nr) {
+	case 2:
+		reg = LM63_REG_REMOTE_TCRIT;
 		if (data->remote_unsigned)
 			temp = TEMP8U_TO_REG(val - data->temp2_offset);
 		else
 			temp = TEMP8_TO_REG(val - data->temp2_offset);
-	} else {
+		break;
+	case 1:
+		reg = LM63_REG_LOCAL_HIGH;
 		temp = TEMP8_TO_REG(val);
+		break;
+	default:	/* lookup table */
+		reg = LM63_REG_LUT_TEMP(nr - 3);
+		temp = lut_temp_to_reg(data, val);
 	}
 	data->temp8[nr] = temp;
 	i2c_smbus_write_byte_data(client, reg, temp);
@@ -613,65 +763,78 @@
 	set_fan, 1);
 
 static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0);
-static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO, show_pwm1, NULL, 1);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IRUGO,
-	show_lut_temp, NULL, 3);
+static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+	show_pwm1_enable, set_pwm1_enable);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 1);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 3);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp_hyst, S_IRUGO,
 	show_lut_temp_hyst, NULL, 3);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO, show_pwm1, NULL, 2);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO,
-	show_lut_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 2);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 4);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp_hyst, S_IRUGO,
 	show_lut_temp_hyst, NULL, 4);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO, show_pwm1, NULL, 3);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IRUGO,
-	show_lut_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 3);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 5);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp_hyst, S_IRUGO,
 	show_lut_temp_hyst, NULL, 5);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO, show_pwm1, NULL, 4);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IRUGO,
-	show_lut_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 4);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 6);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp_hyst, S_IRUGO,
 	show_lut_temp_hyst, NULL, 6);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm1, NULL, 5);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IRUGO,
-	show_lut_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 5);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 7);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp_hyst, S_IRUGO,
 	show_lut_temp_hyst, NULL, 7);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IRUGO, show_pwm1, NULL, 6);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IRUGO,
-	show_lut_temp, NULL, 8);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 6);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 8);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp_hyst, S_IRUGO,
 	show_lut_temp_hyst, NULL, 8);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IRUGO, show_pwm1, NULL, 7);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IRUGO,
-	show_lut_temp, NULL, 9);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 7);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 9);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp_hyst, S_IRUGO,
 	show_lut_temp_hyst, NULL, 9);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IRUGO, show_pwm1, NULL, 8);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IRUGO,
-	show_lut_temp, NULL, 10);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 8);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 10);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp_hyst, S_IRUGO,
 	show_lut_temp_hyst, NULL, 10);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, S_IRUGO, show_pwm1, NULL, 9);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, S_IRUGO,
-	show_lut_temp, NULL, 11);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 9);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 11);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp_hyst, S_IRUGO,
 	show_lut_temp_hyst, NULL, 11);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, S_IRUGO, show_pwm1, NULL, 10);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, S_IRUGO,
-	show_lut_temp, NULL, 12);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 10);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 12);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp_hyst, S_IRUGO,
 	show_lut_temp_hyst, NULL, 12);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point11_pwm, S_IRUGO, show_pwm1, NULL, 11);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp, S_IRUGO,
-	show_lut_temp, NULL, 13);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point11_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 11);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 13);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp_hyst, S_IRUGO,
 	show_lut_temp_hyst, NULL, 13);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point12_pwm, S_IRUGO, show_pwm1, NULL, 12);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp, S_IRUGO,
-	show_lut_temp, NULL, 14);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point12_pwm, S_IWUSR | S_IRUGO,
+	show_pwm1, set_pwm1, 12);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp, S_IWUSR | S_IRUGO,
+	show_lut_temp, set_temp8, 14);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp_hyst, S_IRUGO,
 	show_lut_temp_hyst, NULL, 14);
 
@@ -817,28 +980,25 @@
  */
 
 /* Return 0 if detection is successful, -ENODEV otherwise */
-static int lm63_detect(struct i2c_client *new_client,
+static int lm63_detect(struct i2c_client *client,
 		       struct i2c_board_info *info)
 {
-	struct i2c_adapter *adapter = new_client->adapter;
+	struct i2c_adapter *adapter = client->adapter;
 	u8 man_id, chip_id, reg_config1, reg_config2;
 	u8 reg_alert_status, reg_alert_mask;
-	int address = new_client->addr;
+	int address = client->addr;
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -ENODEV;
 
-	man_id = i2c_smbus_read_byte_data(new_client, LM63_REG_MAN_ID);
-	chip_id = i2c_smbus_read_byte_data(new_client, LM63_REG_CHIP_ID);
+	man_id = i2c_smbus_read_byte_data(client, LM63_REG_MAN_ID);
+	chip_id = i2c_smbus_read_byte_data(client, LM63_REG_CHIP_ID);
 
-	reg_config1 = i2c_smbus_read_byte_data(new_client,
-		      LM63_REG_CONFIG1);
-	reg_config2 = i2c_smbus_read_byte_data(new_client,
-		      LM63_REG_CONFIG2);
-	reg_alert_status = i2c_smbus_read_byte_data(new_client,
+	reg_config1 = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1);
+	reg_config2 = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG2);
+	reg_alert_status = i2c_smbus_read_byte_data(client,
 			   LM63_REG_ALERT_STATUS);
-	reg_alert_mask = i2c_smbus_read_byte_data(new_client,
-			 LM63_REG_ALERT_MASK);
+	reg_alert_mask = i2c_smbus_read_byte_data(client, LM63_REG_ALERT_MASK);
 
 	if (man_id != 0x01 /* National Semiconductor */
 	 || (reg_config1 & 0x18) != 0x00
@@ -863,74 +1023,6 @@
 	return 0;
 }
 
-static int lm63_probe(struct i2c_client *new_client,
-		      const struct i2c_device_id *id)
-{
-	struct lm63_data *data;
-	int err;
-
-	data = kzalloc(sizeof(struct lm63_data), GFP_KERNEL);
-	if (!data) {
-		err = -ENOMEM;
-		goto exit;
-	}
-
-	i2c_set_clientdata(new_client, data);
-	data->valid = 0;
-	mutex_init(&data->update_lock);
-
-	/* Set the device type */
-	data->kind = id->driver_data;
-	if (data->kind == lm64)
-		data->temp2_offset = 16000;
-
-	/* Initialize chip */
-	lm63_init_client(new_client);
-
-	/* Register sysfs hooks */
-	err = sysfs_create_group(&new_client->dev.kobj, &lm63_group);
-	if (err)
-		goto exit_free;
-	if (data->config & 0x04) { /* tachometer enabled */
-		err = sysfs_create_group(&new_client->dev.kobj,
-					 &lm63_group_fan1);
-		if (err)
-			goto exit_remove_files;
-	}
-	if (data->kind == lm96163) {
-		err = device_create_file(&new_client->dev,
-					 &dev_attr_temp2_type);
-		if (err)
-			goto exit_remove_files;
-
-		err = sysfs_create_group(&new_client->dev.kobj,
-					 &lm63_group_extra_lut);
-		if (err)
-			goto exit_remove_files;
-	}
-
-	data->hwmon_dev = hwmon_device_register(&new_client->dev);
-	if (IS_ERR(data->hwmon_dev)) {
-		err = PTR_ERR(data->hwmon_dev);
-		goto exit_remove_files;
-	}
-
-	return 0;
-
-exit_remove_files:
-	sysfs_remove_group(&new_client->dev.kobj, &lm63_group);
-	sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1);
-	if (data->kind == lm96163) {
-		device_remove_file(&new_client->dev, &dev_attr_temp2_type);
-		sysfs_remove_group(&new_client->dev.kobj,
-				   &lm63_group_extra_lut);
-	}
-exit_free:
-	kfree(data);
-exit:
-	return err;
-}
-
 /*
  * Ideally we shouldn't have to initialize anything, since the BIOS
  * should have taken care of everything
@@ -1010,6 +1102,71 @@
 		(data->config_fan & 0x20) ? "manual" : "auto");
 }
 
+static int lm63_probe(struct i2c_client *client,
+		      const struct i2c_device_id *id)
+{
+	struct lm63_data *data;
+	int err;
+
+	data = kzalloc(sizeof(struct lm63_data), GFP_KERNEL);
+	if (!data) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	i2c_set_clientdata(client, data);
+	data->valid = 0;
+	mutex_init(&data->update_lock);
+
+	/* Set the device type */
+	data->kind = id->driver_data;
+	if (data->kind == lm64)
+		data->temp2_offset = 16000;
+
+	/* Initialize chip */
+	lm63_init_client(client);
+
+	/* Register sysfs hooks */
+	err = sysfs_create_group(&client->dev.kobj, &lm63_group);
+	if (err)
+		goto exit_free;
+	if (data->config & 0x04) { /* tachometer enabled */
+		err = sysfs_create_group(&client->dev.kobj, &lm63_group_fan1);
+		if (err)
+			goto exit_remove_files;
+	}
+	if (data->kind == lm96163) {
+		err = device_create_file(&client->dev, &dev_attr_temp2_type);
+		if (err)
+			goto exit_remove_files;
+
+		err = sysfs_create_group(&client->dev.kobj,
+					 &lm63_group_extra_lut);
+		if (err)
+			goto exit_remove_files;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove_files;
+	}
+
+	return 0;
+
+exit_remove_files:
+	sysfs_remove_group(&client->dev.kobj, &lm63_group);
+	sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
+	if (data->kind == lm96163) {
+		device_remove_file(&client->dev, &dev_attr_temp2_type);
+		sysfs_remove_group(&client->dev.kobj, &lm63_group_extra_lut);
+	}
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
 static int lm63_remove(struct i2c_client *client)
 {
 	struct lm63_data *data = i2c_get_clientdata(client);
@@ -1026,98 +1183,29 @@
 	return 0;
 }
 
-static struct lm63_data *lm63_update_device(struct device *dev)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm63_data *data = i2c_get_clientdata(client);
-	unsigned long next_update;
-	int i;
+/*
+ * Driver data (common to all clients)
+ */
 
-	mutex_lock(&data->update_lock);
+static const struct i2c_device_id lm63_id[] = {
+	{ "lm63", lm63 },
+	{ "lm64", lm64 },
+	{ "lm96163", lm96163 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm63_id);
 
-	next_update = data->last_updated
-	  + msecs_to_jiffies(data->update_interval) + 1;
-
-	if (time_after(jiffies, next_update) || !data->valid) {
-		if (data->config & 0x04) { /* tachometer enabled  */
-			/* order matters for fan1_input */
-			data->fan[0] = i2c_smbus_read_byte_data(client,
-				       LM63_REG_TACH_COUNT_LSB) & 0xFC;
-			data->fan[0] |= i2c_smbus_read_byte_data(client,
-					LM63_REG_TACH_COUNT_MSB) << 8;
-			data->fan[1] = (i2c_smbus_read_byte_data(client,
-					LM63_REG_TACH_LIMIT_LSB) & 0xFC)
-				     | (i2c_smbus_read_byte_data(client,
-					LM63_REG_TACH_LIMIT_MSB) << 8);
-		}
-
-		data->pwm1_freq = i2c_smbus_read_byte_data(client,
-				  LM63_REG_PWM_FREQ);
-		if (data->pwm1_freq == 0)
-			data->pwm1_freq = 1;
-		data->pwm1[0] = i2c_smbus_read_byte_data(client,
-				LM63_REG_PWM_VALUE);
-
-		data->temp8[0] = i2c_smbus_read_byte_data(client,
-				 LM63_REG_LOCAL_TEMP);
-		data->temp8[1] = i2c_smbus_read_byte_data(client,
-				 LM63_REG_LOCAL_HIGH);
-
-		/* order matters for temp2_input */
-		data->temp11[0] = i2c_smbus_read_byte_data(client,
-				  LM63_REG_REMOTE_TEMP_MSB) << 8;
-		data->temp11[0] |= i2c_smbus_read_byte_data(client,
-				   LM63_REG_REMOTE_TEMP_LSB);
-		data->temp11[1] = (i2c_smbus_read_byte_data(client,
-				  LM63_REG_REMOTE_LOW_MSB) << 8)
-				| i2c_smbus_read_byte_data(client,
-				  LM63_REG_REMOTE_LOW_LSB);
-		data->temp11[2] = (i2c_smbus_read_byte_data(client,
-				  LM63_REG_REMOTE_HIGH_MSB) << 8)
-				| i2c_smbus_read_byte_data(client,
-				  LM63_REG_REMOTE_HIGH_LSB);
-		data->temp11[3] = (i2c_smbus_read_byte_data(client,
-				  LM63_REG_REMOTE_OFFSET_MSB) << 8)
-				| i2c_smbus_read_byte_data(client,
-				  LM63_REG_REMOTE_OFFSET_LSB);
-
-		if (data->kind == lm96163)
-			data->temp11u = (i2c_smbus_read_byte_data(client,
-					LM96163_REG_REMOTE_TEMP_U_MSB) << 8)
-				      | i2c_smbus_read_byte_data(client,
-					LM96163_REG_REMOTE_TEMP_U_LSB);
-
-		data->temp8[2] = i2c_smbus_read_byte_data(client,
-				 LM63_REG_REMOTE_TCRIT);
-		data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
-					LM63_REG_REMOTE_TCRIT_HYST);
-
-		data->alarms = i2c_smbus_read_byte_data(client,
-			       LM63_REG_ALERT_STATUS) & 0x7F;
-
-		data->last_updated = jiffies;
-		data->valid = 1;
-	}
-
-	if (time_after(jiffies, data->lut_last_updated + 5 * HZ) ||
-	    !data->lut_valid) {
-		for (i = 0; i < data->lut_size; i++) {
-			data->pwm1[1 + i] = i2c_smbus_read_byte_data(client,
-					    LM63_REG_LUT_PWM(i));
-			data->temp8[3 + i] = i2c_smbus_read_byte_data(client,
-					     LM63_REG_LUT_TEMP(i));
-		}
-		data->lut_temp_hyst = i2c_smbus_read_byte_data(client,
-				      LM63_REG_LUT_TEMP_HYST);
-
-		data->lut_last_updated = jiffies;
-		data->lut_valid = 1;
-	}
-
-	mutex_unlock(&data->update_lock);
-
-	return data;
-}
+static struct i2c_driver lm63_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "lm63",
+	},
+	.probe		= lm63_probe,
+	.remove		= lm63_remove,
+	.id_table	= lm63_id,
+	.detect		= lm63_detect,
+	.address_list	= normal_i2c,
+};
 
 module_i2c_driver(lm63_driver);
 
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 248f2b4..22b14a68 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -57,6 +57,9 @@
  * This driver also supports the SA56004 from Philips. This device is
  * pin-compatible with the LM86, the ED/EDP parts are also address-compatible.
  *
+ * This driver also supports the G781 from GMT. This device is compatible
+ * with the ADM1032.
+ *
  * Since the LM90 was the first chipset supported by this driver, most
  * comments will refer to this chipset, but are actually general and
  * concern all supported chipsets, unless mentioned otherwise.
@@ -107,7 +110,7 @@
 	0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
 
 enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
-	max6646, w83l771, max6696, sa56004 };
+	max6646, w83l771, max6696, sa56004, g781 };
 
 /*
  * The LM90 registers
@@ -184,6 +187,7 @@
 	{ "adm1032", adm1032 },
 	{ "adt7461", adt7461 },
 	{ "adt7461a", adt7461 },
+	{ "g781", g781 },
 	{ "lm90", lm90 },
 	{ "lm86", lm86 },
 	{ "lm89", lm86 },
@@ -229,6 +233,12 @@
 		.alert_alarms = 0x7c,
 		.max_convrate = 10,
 	},
+	[g781] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+		  | LM90_HAVE_BROKEN_ALERT,
+		.alert_alarms = 0x7c,
+		.max_convrate = 8,
+	},
 	[lm86] = {
 		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
 		.alert_alarms = 0x7b,
@@ -308,22 +318,24 @@
 
 	/* registers values */
 	s8 temp8[8];	/* 0: local low limit
-			   1: local high limit
-			   2: local critical limit
-			   3: remote critical limit
-			   4: local emergency limit (max6659 and max6695/96)
-			   5: remote emergency limit (max6659 and max6695/96)
-			   6: remote 2 critical limit (max6695/96 only)
-			   7: remote 2 emergency limit (max6695/96 only) */
+			 * 1: local high limit
+			 * 2: local critical limit
+			 * 3: remote critical limit
+			 * 4: local emergency limit (max6659 and max6695/96)
+			 * 5: remote emergency limit (max6659 and max6695/96)
+			 * 6: remote 2 critical limit (max6695/96 only)
+			 * 7: remote 2 emergency limit (max6695/96 only)
+			 */
 	s16 temp11[8];	/* 0: remote input
-			   1: remote low limit
-			   2: remote high limit
-			   3: remote offset (except max6646, max6657/58/59,
-					     and max6695/96)
-			   4: local input
-			   5: remote 2 input (max6695/96 only)
-			   6: remote 2 low limit (max6695/96 only)
-			   7: remote 2 high limit (ma6695/96 only) */
+			 * 1: remote low limit
+			 * 2: remote high limit
+			 * 3: remote offset (except max6646, max6657/58/59,
+			 *		     and max6695/96)
+			 * 4: local input
+			 * 5: remote 2 input (max6695/96 only)
+			 * 6: remote 2 low limit (max6695/96 only)
+			 * 7: remote 2 high limit (max6695/96 only)
+			 */
 	u8 temp_hyst;
 	u16 alarms; /* bitvector (upper 8 bits for max6695/96) */
 };
@@ -533,8 +545,10 @@
 				data->alarms |= alarms << 8;
 		}
 
-		/* Re-enable ALERT# output if it was originally enabled and
-		 * relevant alarms are all clear */
+		/*
+		 * Re-enable ALERT# output if it was originally enabled and
+		 * relevant alarms are all clear
+		 */
 		if ((data->config_orig & 0x80) == 0
 		 && (data->alarms & data->alert_alarms) == 0) {
 			u8 config;
@@ -1162,8 +1176,10 @@
 		 && (config1 & 0x3F) == 0x00
 		 && convrate <= 0x0A) {
 			name = "adm1032";
-			/* The ADM1032 supports PEC, but only if combined
-			   transactions are not used. */
+			/*
+			 * The ADM1032 supports PEC, but only if combined
+			 * transactions are not used.
+			 */
 			if (i2c_check_functionality(adapter,
 						    I2C_FUNC_SMBUS_BYTE))
 				info->flags |= I2C_CLIENT_PEC;
@@ -1283,6 +1299,13 @@
 		 && convrate <= 0x09) {
 			name = "sa56004";
 		}
+	} else
+	if ((address == 0x4C || address == 0x4D)
+	 && man_id == 0x47) { /* GMT */
+		if (chip_id == 0x01 /* G781 */
+		 && (config1 & 0x3F) == 0x00
+		 && convrate <= 0x08)
+			name = "g781";
 	}
 
 	if (!name) { /* identification failed */
@@ -1313,6 +1336,15 @@
 	sysfs_remove_group(&dev->kobj, &lm90_group);
 }
 
+static void lm90_restore_conf(struct i2c_client *client, struct lm90_data *data)
+{
+	/* Restore initial configuration */
+	i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
+				  data->convrate_orig);
+	i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
+				  data->config_orig);
+}
+
 static void lm90_init_client(struct i2c_client *client)
 {
 	u8 config, convrate;
@@ -1382,8 +1414,10 @@
 			client->flags &= ~I2C_CLIENT_PEC;
 	}
 
-	/* Different devices have different alarm bits triggering the
-	 * ALERT# output */
+	/*
+	 * Different devices have different alarm bits triggering the
+	 * ALERT# output
+	 */
 	data->alert_alarms = lm90_params[data->kind].alert_alarms;
 
 	/* Set chip capabilities */
@@ -1399,7 +1433,7 @@
 	/* Register sysfs hooks */
 	err = sysfs_create_group(&dev->kobj, &lm90_group);
 	if (err)
-		goto exit_free;
+		goto exit_restore;
 	if (client->flags & I2C_CLIENT_PEC) {
 		err = device_create_file(dev, &dev_attr_pec);
 		if (err)
@@ -1438,7 +1472,8 @@
 
 exit_remove_files:
 	lm90_remove_files(client, data);
-exit_free:
+exit_restore:
+	lm90_restore_conf(client, data);
 	kfree(data);
 exit:
 	return err;
@@ -1450,12 +1485,7 @@
 
 	hwmon_device_unregister(data->hwmon_dev);
 	lm90_remove_files(client, data);
-
-	/* Restore initial configuration */
-	i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
-				  data->convrate_orig);
-	i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
-				  data->config_orig);
+	lm90_restore_conf(client, data);
 
 	kfree(data);
 	return 0;
@@ -1488,9 +1518,11 @@
 			dev_warn(&client->dev,
 				 "temp%d out of range, please check!\n", 3);
 
-		/* Disable ALERT# output, because these chips don't implement
-		  SMBus alert correctly; they should only hold the alert line
-		  low briefly. */
+		/*
+		 * Disable ALERT# output, because these chips don't implement
+		 * SMBus alert correctly; they should only hold the alert line
+		 * low briefly.
+		 */
 		if ((data->flags & LM90_HAVE_BROKEN_ALERT)
 		 && (alarms & data->alert_alarms)) {
 			dev_dbg(&client->dev, "Disabling ALERT#\n");
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
index 193067e..de8f7ad 100644
--- a/drivers/hwmon/max6639.c
+++ b/drivers/hwmon/max6639.c
@@ -596,8 +596,10 @@
 	return 0;
 }
 
-static int max6639_suspend(struct i2c_client *client, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+static int max6639_suspend(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
 	if (data < 0)
 		return data;
@@ -606,8 +608,9 @@
 			MAX6639_REG_GCONFIG, data | MAX6639_GCONFIG_STANDBY);
 }
 
-static int max6639_resume(struct i2c_client *client)
+static int max6639_resume(struct device *dev)
 {
+	struct i2c_client *client = to_i2c_client(dev);
 	int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
 	if (data < 0)
 		return data;
@@ -615,6 +618,7 @@
 	return i2c_smbus_write_byte_data(client,
 			MAX6639_REG_GCONFIG, data & ~MAX6639_GCONFIG_STANDBY);
 }
+#endif /* CONFIG_PM_SLEEP */
 
 static const struct i2c_device_id max6639_id[] = {
 	{"max6639", 0},
@@ -623,15 +627,18 @@
 
 MODULE_DEVICE_TABLE(i2c, max6639_id);
 
+static const struct dev_pm_ops max6639_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(max6639_suspend, max6639_resume)
+};
+
 static struct i2c_driver max6639_driver = {
 	.class = I2C_CLASS_HWMON,
 	.driver = {
 		   .name = "max6639",
+		   .pm = &max6639_pm_ops,
 		   },
 	.probe = max6639_probe,
 	.remove = max6639_remove,
-	.suspend = max6639_suspend,
-	.resume = max6639_resume,
 	.id_table = max6639_id,
 	.detect = max6639_detect,
 	.address_list = normal_i2c,
diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c
index ef65ab5..ce86c5e 100644
--- a/drivers/hwmon/mc13783-adc.c
+++ b/drivers/hwmon/mc13783-adc.c
@@ -1,5 +1,5 @@
 /*
- * Driver for the Freescale Semiconductor MC13783 adc.
+ * Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs.
  *
  * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
  * Copyright (C) 2009 Sascha Hauer, Pengutronix
@@ -18,7 +18,7 @@
  * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include <linux/mfd/mc13783.h>
+#include <linux/mfd/mc13xxx.h>
 #include <linux/platform_device.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/kernel.h>
@@ -28,24 +28,30 @@
 #include <linux/init.h>
 #include <linux/err.h>
 
-#define MC13783_ADC_NAME	"mc13783-adc"
+#define DRIVER_NAME	"mc13783-adc"
+
+/* platform device id driver data */
+#define MC13783_ADC_16CHANS	1
+#define MC13783_ADC_BPDIV2	2
 
 struct mc13783_adc_priv {
 	struct mc13xxx *mc13xxx;
 	struct device *hwmon_dev;
+	char name[10];
 };
 
 static ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute
 			      *devattr, char *buf)
 {
-	return sprintf(buf, "mc13783_adc\n");
+	struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", priv->name);
 }
 
 static int mc13783_adc_read(struct device *dev,
 		struct device_attribute *devattr, unsigned int *val)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
+	struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 	unsigned int channel = attr->index;
 	unsigned int sample[4];
@@ -53,7 +59,7 @@
 
 	ret = mc13xxx_adc_do_conversion(priv->mc13xxx,
 			MC13XXX_ADC_MODE_MULT_CHAN,
-			channel, sample);
+			channel, 0, 0, sample);
 	if (ret)
 		return ret;
 
@@ -68,16 +74,21 @@
 		struct device_attribute *devattr, char *buf)
 {
 	unsigned val;
+	struct platform_device *pdev = to_platform_device(dev);
+	kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
 	int ret = mc13783_adc_read(dev, devattr, &val);
 
 	if (ret)
 		return ret;
 
-	/*
-	 * BP (channel 2) reports with offset 2.4V to the actual value to fit
-	 * the input range of the ADC.  unit = 2.25mV = 9/4 mV.
-	 */
-	val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400;
+	if (driver_data & MC13783_ADC_BPDIV2)
+		val = DIV_ROUND_CLOSEST(val * 9, 2);
+	else
+		/*
+		 * BP (channel 2) reports with offset 2.4V to the actual value
+		 * to fit the input range of the ADC.  unit = 2.25mV = 9/4 mV.
+		 */
+		val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400;
 
 	return sprintf(buf, "%u\n", val);
 }
@@ -114,12 +125,21 @@
 static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14);
 static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15);
 
-static struct attribute *mc13783_attr[] = {
+static struct attribute *mc13783_attr_base[] = {
 	&dev_attr_name.attr,
 	&sensor_dev_attr_in2_input.dev_attr.attr,
 	&sensor_dev_attr_in5_input.dev_attr.attr,
 	&sensor_dev_attr_in6_input.dev_attr.attr,
 	&sensor_dev_attr_in7_input.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group mc13783_group_base = {
+	.attrs = mc13783_attr_base,
+};
+
+/* these are only used if MC13783_ADC_16CHANS is provided in driver data */
+static struct attribute *mc13783_attr_16chans[] = {
 	&sensor_dev_attr_in8_input.dev_attr.attr,
 	&sensor_dev_attr_in9_input.dev_attr.attr,
 	&sensor_dev_attr_in10_input.dev_attr.attr,
@@ -127,8 +147,8 @@
 	NULL
 };
 
-static const struct attribute_group mc13783_group = {
-	.attrs = mc13783_attr,
+static const struct attribute_group mc13783_group_16chans = {
+	.attrs = mc13783_attr_16chans,
 };
 
 /* last four channels may be occupied by the touchscreen */
@@ -156,24 +176,37 @@
 {
 	struct mc13783_adc_priv *priv;
 	int ret;
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	char *dash;
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
 	priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
+	snprintf(priv->name, ARRAY_SIZE(priv->name), "%s", id->name);
+	dash = strchr(priv->name, '-');
+	if (dash)
+		*dash = '\0';
 
 	platform_set_drvdata(pdev, priv);
 
 	/* Register sysfs hooks */
-	ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group);
+	ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_base);
 	if (ret)
-		goto out_err_create1;
+		goto out_err_create_base;
+
+	if (id->driver_data & MC13783_ADC_16CHANS) {
+		ret = sysfs_create_group(&pdev->dev.kobj,
+				&mc13783_group_16chans);
+		if (ret)
+			goto out_err_create_16chans;
+	}
 
 	if (!mc13783_adc_use_touchscreen(pdev)) {
 		ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts);
 		if (ret)
-			goto out_err_create2;
+			goto out_err_create_ts;
 	}
 
 	priv->hwmon_dev = hwmon_device_register(&pdev->dev);
@@ -184,17 +217,20 @@
 		goto out_err_register;
 	}
 
-
 	return 0;
 
 out_err_register:
 
 	if (!mc13783_adc_use_touchscreen(pdev))
 		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
-out_err_create2:
+out_err_create_ts:
 
-	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group);
-out_err_create1:
+	if (id->driver_data & MC13783_ADC_16CHANS)
+		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
+out_err_create_16chans:
+
+	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
+out_err_create_base:
 
 	platform_set_drvdata(pdev, NULL);
 	kfree(priv);
@@ -205,13 +241,17 @@
 static int __devexit mc13783_adc_remove(struct platform_device *pdev)
 {
 	struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
+	kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
 
 	hwmon_device_unregister(priv->hwmon_dev);
 
 	if (!mc13783_adc_use_touchscreen(pdev))
 		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
 
-	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group);
+	if (driver_data & MC13783_ADC_16CHANS)
+		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
+
+	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
 
 	platform_set_drvdata(pdev, NULL);
 	kfree(priv);
@@ -219,12 +259,26 @@
 	return 0;
 }
 
+static const struct platform_device_id mc13783_adc_idtable[] = {
+	{
+		.name = "mc13783-adc",
+		.driver_data = MC13783_ADC_16CHANS,
+	}, {
+		.name = "mc13892-adc",
+		.driver_data = MC13783_ADC_BPDIV2,
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable);
+
 static struct platform_driver mc13783_adc_driver = {
-	.remove 	= __devexit_p(mc13783_adc_remove),
+	.remove		= __devexit_p(mc13783_adc_remove),
 	.driver		= {
 		.owner	= THIS_MODULE,
-		.name	= MC13783_ADC_NAME,
+		.name	= DRIVER_NAME,
 	},
+	.id_table	= mc13783_adc_idtable,
 };
 
 static int __init mc13783_adc_init(void)
@@ -243,4 +297,3 @@
 MODULE_DESCRIPTION("MC13783 ADC driver");
 MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" MC13783_ADC_NAME);
diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c
new file mode 100644
index 0000000..d0afc0c
--- /dev/null
+++ b/drivers/hwmon/mcp3021.c
@@ -0,0 +1,171 @@
+/*
+ * mcp3021.c - driver for the Microchip MCP3021 chip
+ *
+ * Copyright (C) 2008-2009, 2012 Freescale Semiconductor, Inc.
+ * Author: Mingkai Hu <Mingkai.hu@freescale.com>
+ *
+ * This driver export the value of analog input voltage to sysfs, the
+ * voltage unit is mV. Through the sysfs interface, lm-sensors tool
+ * can also display the input voltage.
+ *
+ * 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/hwmon.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/device.h>
+
+/* Vdd info */
+#define MCP3021_VDD_MAX		5500
+#define MCP3021_VDD_MIN		2700
+#define MCP3021_VDD_REF		3300
+
+/* output format */
+#define MCP3021_SAR_SHIFT	2
+#define MCP3021_SAR_MASK	0x3ff
+
+#define MCP3021_OUTPUT_RES	10	/* 10-bit resolution */
+#define MCP3021_OUTPUT_SCALE	4
+
+/*
+ * Client data (each client gets its own)
+ */
+struct mcp3021_data {
+	struct device *hwmon_dev;
+	u32 vdd;	/* device power supply */
+};
+
+static int mcp3021_read16(struct i2c_client *client)
+{
+	int ret;
+	u16 reg;
+	__be16 buf;
+
+	ret = i2c_master_recv(client, (char *)&buf, 2);
+	if (ret < 0)
+		return ret;
+	if (ret != 2)
+		return -EIO;
+
+	/* The output code of the MCP3021 is transmitted with MSB first. */
+	reg = be16_to_cpu(buf);
+
+	/*
+	 * The ten-bit output code is composed of the lower 4-bit of the
+	 * first byte and the upper 6-bit of the second byte.
+	 */
+	reg = (reg >> MCP3021_SAR_SHIFT) & MCP3021_SAR_MASK;
+
+	return reg;
+}
+
+static inline u16 volts_from_reg(u16 vdd, u16 val)
+{
+	if (val == 0)
+		return 0;
+
+	val = val * MCP3021_OUTPUT_SCALE - MCP3021_OUTPUT_SCALE / 2;
+
+	return val * DIV_ROUND_CLOSEST(vdd,
+			(1 << MCP3021_OUTPUT_RES) * MCP3021_OUTPUT_SCALE);
+}
+
+static ssize_t show_in_input(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct mcp3021_data *data = i2c_get_clientdata(client);
+	int reg, in_input;
+
+	reg = mcp3021_read16(client);
+	if (reg < 0)
+		return reg;
+
+	in_input = volts_from_reg(data->vdd, reg);
+	return sprintf(buf, "%d\n", in_input);
+}
+
+static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL);
+
+static int mcp3021_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	int err;
+	struct mcp3021_data *data = NULL;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+		return -ENODEV;
+
+	data = kzalloc(sizeof(struct mcp3021_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+
+	if (client->dev.platform_data) {
+		data->vdd = *(u32 *)client->dev.platform_data;
+		if (data->vdd > MCP3021_VDD_MAX ||
+				data->vdd < MCP3021_VDD_MIN) {
+			err = -EINVAL;
+			goto exit_free;
+		}
+	} else
+		data->vdd = MCP3021_VDD_REF;
+
+	err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr);
+	if (err)
+		goto exit_free;
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
+exit_free:
+	kfree(data);
+	return err;
+}
+
+static int mcp3021_remove(struct i2c_client *client)
+{
+	struct mcp3021_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
+	kfree(data);
+
+	return 0;
+}
+
+static const struct i2c_device_id mcp3021_id[] = {
+	{ "mcp3021", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mcp3021_id);
+
+static struct i2c_driver mcp3021_driver = {
+	.driver = {
+		.name = "mcp3021",
+	},
+	.probe = mcp3021_probe,
+	.remove = mcp3021_remove,
+	.id_table = mcp3021_id,
+};
+
+module_i2c_driver(mcp3021_driver);
+
+MODULE_AUTHOR("Mingkai Hu <Mingkai.hu@freescale.com>");
+MODULE_DESCRIPTION("Microchip MCP3021 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index a25350c..54922ed 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -2619,15 +2619,15 @@
 static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
 				 struct w83627ehf_sio_data *sio_data)
 {
-	static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
-	static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
-	static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
-	static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
-	static const char __initdata sio_name_W83627UHG[] = "W83627UHG";
-	static const char __initdata sio_name_W83667HG[] = "W83667HG";
-	static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
-	static const char __initdata sio_name_NCT6775[] = "NCT6775F";
-	static const char __initdata sio_name_NCT6776[] = "NCT6776F";
+	static const char sio_name_W83627EHF[] __initconst = "W83627EHF";
+	static const char sio_name_W83627EHG[] __initconst = "W83627EHG";
+	static const char sio_name_W83627DHG[] __initconst = "W83627DHG";
+	static const char sio_name_W83627DHG_P[] __initconst = "W83627DHG-P";
+	static const char sio_name_W83627UHG[] __initconst = "W83627UHG";
+	static const char sio_name_W83667HG[] __initconst = "W83667HG";
+	static const char sio_name_W83667HG_B[] __initconst = "W83667HG-B";
+	static const char sio_name_NCT6775[] __initconst = "NCT6775F";
+	static const char sio_name_NCT6776[] __initconst = "NCT6776F";
 
 	u16 val;
 	const char *sio_name;
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index 834e49d..d6b0bdd 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -71,8 +71,8 @@
 	"Watchdog timeout in minutes. 2<= timeout <=255 (default="
 				__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c
index deb12c9..d887cb3 100644
--- a/drivers/hwmon/w83795.c
+++ b/drivers/hwmon/w83795.c
@@ -72,8 +72,10 @@
 #define TEMP_CRIT_HYST			2
 #define TEMP_WARN			3
 #define TEMP_WARN_HYST			4
-/* only crit and crit_hyst affect real-time alarm status
- * current crit crit_hyst warn warn_hyst */
+/*
+ * only crit and crit_hyst affect real-time alarm status
+ * current crit crit_hyst warn warn_hyst
+ */
 static const u16 W83795_REG_TEMP[][5] = {
 	{0x21, 0x96, 0x97, 0x98, 0x99},	/* TD1/TR1 */
 	{0x22, 0x9a, 0x9b, 0x9c, 0x9d},	/* TD2/TR2 */
@@ -354,26 +356,34 @@
 	u8 temp_mode;		/* Bit vector, 0 = TR, 1 = TD */
 	u8 temp_src[3];		/* Register value */
 
-	u8 enable_dts;		/* Enable PECI and SB-TSI,
+	u8 enable_dts;		/*
+				 * Enable PECI and SB-TSI,
 				 * bit 0: =1 enable, =0 disable,
-				 * bit 1: =1 AMD SB-TSI, =0 Intel PECI */
+				 * bit 1: =1 AMD SB-TSI, =0 Intel PECI
+				 */
 	u8 has_dts;		/* Enable monitor DTS temp */
 	s8 dts[8];		/* Register value */
 	u8 dts_read_vrlsb[8];	/* Register value */
 	s8 dts_ext[4];		/* Register value */
 
-	u8 has_pwm;		/* 795g supports 8 pwm, 795adg only supports 2,
+	u8 has_pwm;		/*
+				 * 795g supports 8 pwm, 795adg only supports 2,
 				 * no config register, only affected by chip
-				 * type */
-	u8 pwm[8][5];		/* Register value, output, freq, start,
-				 *  non stop, stop time */
+				 * type
+				 */
+	u8 pwm[8][5];		/*
+				 * Register value, output, freq, start,
+				 *  non stop, stop time
+				 */
 	u16 clkin;		/* CLKIN frequency in kHz */
 	u8 pwm_fcms[2];		/* Register value */
 	u8 pwm_tfmr[6];		/* Register value */
 	u8 pwm_fomc;		/* Register value */
 
-	u16 target_speed[8];	/* Register value, target speed for speed
-				 * cruise */
+	u16 target_speed[8];	/*
+				 * Register value, target speed for speed
+				 * cruise
+				 */
 	u8 tol_speed;		/* tolerance of target speed */
 	u8 pwm_temp[6][4];	/* TTTI, CTFS, HCT, HOT */
 	u8 sf4_reg[6][2][7];	/* 6 temp, temp/dcpwm, 7 registers */
@@ -482,8 +492,10 @@
 	/* Read the fan limits */
 	lsb = 0; /* Silent false gcc warning */
 	for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
-		/* Each register contains LSB for 2 fans, but we want to
-		 * read it only once to save time */
+		/*
+		 * Each register contains LSB for 2 fans, but we want to
+		 * read it only once to save time
+		 */
 		if ((i & 1) == 0 && (data->has_fan & (3 << i)))
 			lsb = w83795_read(client, W83795_REG_FAN_MIN_LSB(i));
 
@@ -665,9 +677,11 @@
 		    w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT));
 	}
 
-	/* Update intrusion and alarms
+	/*
+	 * Update intrusion and alarms
 	 * It is important to read intrusion first, because reading from
-	 * register SMI STS6 clears the interrupt status temporarily. */
+	 * register SMI STS6 clears the interrupt status temporarily.
+	 */
 	tmp = w83795_read(client, W83795_REG_ALARM_CTRL);
 	/* Switch to interrupt status for intrusion if needed */
 	if (tmp & ALARM_CTRL_RTSACS)
@@ -929,6 +943,14 @@
 	if (val < 1 || val > 2)
 		return -EINVAL;
 
+#ifndef CONFIG_SENSORS_W83795_FANCTRL
+	if (val > 1) {
+		dev_warn(dev, "Automatic fan speed control support disabled\n");
+		dev_warn(dev, "Build with CONFIG_SENSORS_W83795_FANCTRL=y if you want it\n");
+		return -EOPNOTSUPP;
+	}
+#endif
+
 	mutex_lock(&data->update_lock);
 	switch (val) {
 	case 1:
@@ -1595,8 +1617,10 @@
 
 #define NOT_USED			-1
 
-/* Don't change the attribute order, _max, _min and _beep are accessed by index
- * somewhere else in the code */
+/*
+ * Don't change the attribute order, _max, _min and _beep are accessed by index
+ * somewhere else in the code
+ */
 #define SENSOR_ATTR_IN(index) {						\
 	SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL,	\
 		IN_READ, index), \
@@ -1610,8 +1634,10 @@
 		show_alarm_beep, store_beep, BEEP_ENABLE,		\
 		index + ((index > 14) ? 1 : 0)) }
 
-/* Don't change the attribute order, _beep is accessed by index
- * somewhere else in the code */
+/*
+ * Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code
+ */
 #define SENSOR_ATTR_FAN(index) {					\
 	SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan,		\
 		NULL, FAN_INPUT, index - 1), \
@@ -1625,23 +1651,25 @@
 #define SENSOR_ATTR_PWM(index) {					\
 	SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm,		\
 		store_pwm, PWM_OUTPUT, index - 1),			\
+	SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO,		\
+		show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \
+	SENSOR_ATTR_2(pwm##index##_mode, S_IRUGO,			\
+		show_pwm_mode, NULL, NOT_USED, index - 1),		\
+	SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO,		\
+		show_pwm, store_pwm, PWM_FREQ, index - 1),		\
 	SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO,		\
 		show_pwm, store_pwm, PWM_NONSTOP, index - 1),		\
 	SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO,		\
 		show_pwm, store_pwm, PWM_START, index - 1),		\
 	SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO,	\
 		show_pwm, store_pwm, PWM_STOP_TIME, index - 1),	 \
-	SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO,	\
-		show_pwm, store_pwm, PWM_FREQ, index - 1),	 \
-	SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO,		\
-		show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \
-	SENSOR_ATTR_2(pwm##index##_mode, S_IRUGO,			\
-		show_pwm_mode, NULL, NOT_USED, index - 1),		\
 	SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \
 		show_fanin, store_fanin, FANIN_TARGET, index - 1) }
 
-/* Don't change the attribute order, _beep is accessed by index
- * somewhere else in the code */
+/*
+ * Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code
+ */
 #define SENSOR_ATTR_DTS(index) {					\
 	SENSOR_ATTR_2(temp##index##_type, S_IRUGO ,		\
 		show_dts_mode, NULL, NOT_USED, index - 7),	\
@@ -1660,8 +1688,10 @@
 	SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO,		\
 		show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) }
 
-/* Don't change the attribute order, _beep is accessed by index
- * somewhere else in the code */
+/*
+ * Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code
+ */
 #define SENSOR_ATTR_TEMP(index) {					\
 	SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 4 ? S_IWUSR : 0), \
 		show_temp_mode, store_temp_mode, NOT_USED, index - 1),	\
@@ -1867,8 +1897,10 @@
 
 	device_id = i2c_smbus_read_byte_data(client, W83795_REG_DEVICEID);
 
-	/* Special case for rev. A chips; can't be checked first because later
-	   revisions emulate this for compatibility */
+	/*
+	 * Special case for rev. A chips; can't be checked first because later
+	 * revisions emulate this for compatibility
+	 */
 	if (device_id < 0 || (device_id & 0xf0) != 0x50) {
 		int alt_id;
 
@@ -1920,8 +1952,10 @@
 		return -ENODEV;
 	}
 
-	/* If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR
-	   should match */
+	/*
+	 * If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR
+	 * should match
+	 */
 	if ((bank & 0x07) == 0) {
 		i2c_addr = i2c_smbus_read_byte_data(client,
 						    W83795_REG_I2C_ADDR);
@@ -1933,10 +1967,12 @@
 		}
 	}
 
-	/* Check 795 chip type: 795G or 795ADG
-	   Usually we don't write to chips during detection, but here we don't
-	   quite have the choice; hopefully it's OK, we are about to return
-	   success anyway */
+	/*
+	 * Check 795 chip type: 795G or 795ADG
+	 * Usually we don't write to chips during detection, but here we don't
+	 * quite have the choice; hopefully it's OK, we are about to return
+	 * success anyway
+	 */
 	if ((bank & 0x07) != 0)
 		i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL,
 					  bank & ~0x07);
@@ -1953,6 +1989,14 @@
 	return 0;
 }
 
+#ifdef CONFIG_SENSORS_W83795_FANCTRL
+#define NUM_PWM_ATTRIBUTES	ARRAY_SIZE(w83795_pwm[0])
+#define NUM_TEMP_ATTRIBUTES	ARRAY_SIZE(w83795_temp[0])
+#else
+#define NUM_PWM_ATTRIBUTES	4
+#define NUM_TEMP_ATTRIBUTES	8
+#endif
+
 static int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
 			       const struct device_attribute *))
 {
@@ -2006,24 +2050,18 @@
 		}
 	}
 
-#ifdef CONFIG_SENSORS_W83795_FANCTRL
 	for (i = 0; i < data->has_pwm; i++) {
-		for (j = 0; j < ARRAY_SIZE(w83795_pwm[0]); j++) {
+		for (j = 0; j < NUM_PWM_ATTRIBUTES; j++) {
 			err = fn(dev, &w83795_pwm[i][j].dev_attr);
 			if (err)
 				return err;
 		}
 	}
-#endif
 
 	for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) {
 		if (!(data->has_temp & (1 << i)))
 			continue;
-#ifdef CONFIG_SENSORS_W83795_FANCTRL
-		for (j = 0; j < ARRAY_SIZE(w83795_temp[0]); j++) {
-#else
-		for (j = 0; j < 8; j++) {
-#endif
+		for (j = 0; j < NUM_TEMP_ATTRIBUTES; j++) {
 			if (j == 7 && !data->enable_beep)
 				continue;
 			err = fn(dev, &w83795_temp[i][j].dev_attr);
@@ -2183,8 +2221,10 @@
 		/* The W83795G has a dedicated BEEP pin */
 		data->enable_beep = 1;
 	} else {
-		/* The W83795ADG has a shared pin for OVT# and BEEP, so you
-		 * can't have both */
+		/*
+		 * The W83795ADG has a shared pin for OVT# and BEEP, so you
+		 * can't have both
+		 */
 		tmp = w83795_read(client, W83795_REG_OVT_CFG);
 		if ((tmp & OVT_CFG_SEL) == 0)
 			data->enable_beep = 1;
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index 24f94f4..7f0b832 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -15,7 +15,8 @@
 
     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.
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.
  * ------------------------------------------------------------------------- */
 
 /* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
@@ -111,7 +112,7 @@
 				break;
 			return -ETIMEDOUT;
 		}
-		cond_resched();
+		cpu_relax();
 	}
 #ifdef DEBUG
 	if (jiffies != start && i2c_debug >= 3)
@@ -616,10 +617,11 @@
 
 /* -----exported algorithm data: -------------------------------------	*/
 
-static const struct i2c_algorithm i2c_bit_algo = {
+const struct i2c_algorithm i2c_bit_algo = {
 	.master_xfer	= bit_xfer,
 	.functionality	= bit_func,
 };
+EXPORT_SYMBOL(i2c_bit_algo);
 
 /*
  * registering functions to load algorithms at runtime
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
index beb9ffe..73133b1 100644
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -15,7 +15,8 @@
  *
  *  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.
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301 USA.
  */
 
 #include <linux/kernel.h>
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index 5eebf56..5c23795 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -16,7 +16,8 @@
  *
  *  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.
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301 USA.
  *
  * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
  * Frodo Looijaard <frodol@dds.nl>, and also from Martin Bailey
diff --git a/drivers/i2c/algos/i2c-algo-pcf.h b/drivers/i2c/algos/i2c-algo-pcf.h
index 5263a9e..1ec703e 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.h
+++ b/drivers/i2c/algos/i2c-algo-pcf.h
@@ -16,7 +16,8 @@
 
     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.		*/
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.							*/
 /* --------------------------------------------------------------------	*/
 
 /* With some changes from Frodo Looijaard <frodol@dds.nl> */
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 3101dd5..d2c5095 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -103,6 +103,7 @@
 	    Patsburg (PCH)
 	    DH89xxCC (PCH)
 	    Panther Point (PCH)
+	    Lynx Point (PCH)
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-i801.
@@ -369,6 +370,21 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-designware-pci.
 
+config I2C_EG20T
+	tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C"
+	depends on PCI
+	help
+	  This driver is for PCH(Platform controller Hub) I2C of EG20T which
+	  is an IOH(Input/Output Hub) for x86 embedded processor.
+	  This driver can access PCH I2C bus device.
+
+	  This driver also can be used for LAPIS Semiconductor IOH(Input/
+	  Output Hub), ML7213, ML7223 and ML7831.
+	  ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is
+	  for MP(Media Phone) use and ML7831 IOH is for general purpose use.
+	  ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
+	  ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
+
 config I2C_GPIO
 	tristate "GPIO-based bitbanging I2C"
 	depends on GENERIC_GPIO
@@ -630,6 +646,16 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called i2c-simtec.
 
+config I2C_SIRF
+	tristate "CSR SiRFprimaII I2C interface"
+	depends on ARCH_PRIMA2
+	help
+	  If you say yes to this option, support will be included for the
+	  CSR SiRFprimaII I2C interface.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-sirf.
+
 config I2C_STU300
 	tristate "ST Microelectronics DDC I2C interface"
 	depends on MACH_U300
@@ -681,20 +707,15 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called xilinx_i2c.
 
-config I2C_EG20T
-	tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C"
-	depends on PCI
+config I2C_XLR
+	tristate "XLR I2C support"
+	depends on CPU_XLR
 	help
-	  This driver is for PCH(Platform controller Hub) I2C of EG20T which
-	  is an IOH(Input/Output Hub) for x86 embedded processor.
-	  This driver can access PCH I2C bus device.
+	  This driver enables support for the on-chip I2C interface of
+	  the Netlogic XLR/XLS MIPS processors.
 
-	  This driver also can be used for LAPIS Semiconductor IOH(Input/
-	  Output Hub), ML7213, ML7223 and ML7831.
-	  ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is
-	  for MP(Media Phone) use and ML7831 IOH is for general purpose use.
-	  ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
-	  ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-xlr.
 
 comment "External I2C/SMBus adapter drivers"
 
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index fba6da6..569567b 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -37,6 +37,7 @@
 i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-core.o
 obj-$(CONFIG_I2C_DESIGNWARE_PCI)	+= i2c-designware-pci.o
 i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-core.o
+obj-$(CONFIG_I2C_EG20T)		+= i2c-eg20t.o
 obj-$(CONFIG_I2C_GPIO)		+= i2c-gpio.o
 obj-$(CONFIG_I2C_HIGHLANDER)	+= i2c-highlander.o
 obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o
@@ -63,12 +64,13 @@
 obj-$(CONFIG_I2C_SH7760)	+= i2c-sh7760.o
 obj-$(CONFIG_I2C_SH_MOBILE)	+= i2c-sh_mobile.o
 obj-$(CONFIG_I2C_SIMTEC)	+= i2c-simtec.o
+obj-$(CONFIG_I2C_SIRF)		+= i2c-sirf.o
 obj-$(CONFIG_I2C_STU300)	+= i2c-stu300.o
 obj-$(CONFIG_I2C_TEGRA)		+= i2c-tegra.o
 obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
 obj-$(CONFIG_I2C_OCTEON)	+= i2c-octeon.o
 obj-$(CONFIG_I2C_XILINX)	+= i2c-xiic.o
-obj-$(CONFIG_I2C_EG20T)         += i2c-eg20t.o
+obj-$(CONFIG_I2C_XLR)		+= i2c-xlr.o
 
 # External I2C/SMBus adapter drivers
 obj-$(CONFIG_I2C_DIOLAN_U2C)	+= i2c-diolan-u2c.o
diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c
index 8679648..ed9f48d 100644
--- a/drivers/i2c/busses/i2c-acorn.c
+++ b/drivers/i2c/busses/i2c-acorn.c
@@ -19,7 +19,6 @@
 
 #include <mach/hardware.h>
 #include <asm/hardware/ioc.h>
-#include <asm/system.h>
 
 #define FORCE_ONES	0xdc
 #define SCL		0x02
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 5244c47..4ba589a 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -214,7 +214,7 @@
 {
 	return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe);
 }
-module_init(dw_i2c_init_driver);
+subsys_initcall(dw_i2c_init_driver);
 
 static void __exit dw_i2c_exit_driver(void)
 {
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c
index ca88776..f086131 100644
--- a/drivers/i2c/busses/i2c-eg20t.c
+++ b/drivers/i2c/busses/i2c-eg20t.c
@@ -271,30 +271,36 @@
 /**
  * pch_i2c_wait_for_bus_idle() - check the status of bus.
  * @adap:	Pointer to struct i2c_algo_pch_data.
- * @timeout:	waiting time counter (us).
+ * @timeout:	waiting time counter (ms).
  */
 static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap,
 				     s32 timeout)
 {
 	void __iomem *p = adap->pch_base_address;
-	ktime_t ns_val;
+	int schedule = 0;
+	unsigned long end = jiffies + msecs_to_jiffies(timeout);
 
-	if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0)
-		return 0;
+	while (ioread32(p + PCH_I2CSR) & I2CMBB_BIT) {
+		if (time_after(jiffies, end)) {
+			pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR));
+			pch_err(adap, "%s: Timeout Error.return%d\n",
+					__func__, -ETIME);
+			pch_i2c_init(adap);
 
-	/* MAX timeout value is timeout*1000*1000nsec */
-	ns_val = ktime_add_ns(ktime_get(), timeout*1000*1000);
-	do {
-		msleep(20);
-		if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0)
-			return 0;
-	} while (ktime_lt(ktime_get(), ns_val));
+			return -ETIME;
+		}
 
-	pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR));
-	pch_err(adap, "%s: Timeout Error.return%d\n", __func__, -ETIME);
-	pch_i2c_init(adap);
+		if (!schedule)
+			/* Retry after some usecs */
+			udelay(5);
+		else
+			/* Wait a bit more without consuming CPU */
+			usleep_range(20, 1000);
 
-	return -ETIME;
+		schedule = 1;
+	}
+
+	return 0;
 }
 
 /**
@@ -778,8 +784,6 @@
 	struct i2c_msg *pmsg;
 	u32 i = 0;
 	u32 status;
-	u32 msglen;
-	u32 subaddrlen;
 	s32 ret;
 
 	struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
@@ -804,12 +808,6 @@
 		status = pmsg->flags;
 		pch_dbg(adap,
 			"After invoking I2C_MODE_SEL :flag= 0x%x\n", status);
-		/* calculate sub address length and message length */
-		/* these are applicable only for buffer mode */
-		subaddrlen = pmsg->buf[0];
-		/* calculate actual message length excluding
-		 * the sub address fields */
-		msglen = (pmsg->len) - (subaddrlen + 1);
 
 		if ((status & (I2C_M_RD)) != false) {
 			ret = pch_i2c_readbytes(i2c_adap, pmsg, (i + 1 == num),
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index a651779..c0330a4 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -14,8 +14,15 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_i2c.h>
 
-#include <asm/gpio.h>
+struct i2c_gpio_private_data {
+	struct i2c_adapter adap;
+	struct i2c_algo_bit_data bit_data;
+	struct i2c_gpio_platform_data pdata;
+};
 
 /* Toggle SDA by changing the direction of the pin */
 static void i2c_gpio_setsda_dir(void *data, int state)
@@ -78,24 +85,62 @@
 	return gpio_get_value(pdata->scl_pin);
 }
 
+static int __devinit of_i2c_gpio_probe(struct device_node *np,
+			     struct i2c_gpio_platform_data *pdata)
+{
+	u32 reg;
+
+	if (of_gpio_count(np) < 2)
+		return -ENODEV;
+
+	pdata->sda_pin = of_get_gpio(np, 0);
+	pdata->scl_pin = of_get_gpio(np, 1);
+
+	if (!gpio_is_valid(pdata->sda_pin) || !gpio_is_valid(pdata->scl_pin)) {
+		pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n",
+		       np->full_name, pdata->sda_pin, pdata->scl_pin);
+		return -ENODEV;
+	}
+
+	of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay);
+
+	if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", &reg))
+		pdata->timeout = msecs_to_jiffies(reg);
+
+	pdata->sda_is_open_drain =
+		of_property_read_bool(np, "i2c-gpio,sda-open-drain");
+	pdata->scl_is_open_drain =
+		of_property_read_bool(np, "i2c-gpio,scl-open-drain");
+	pdata->scl_is_output_only =
+		of_property_read_bool(np, "i2c-gpio,scl-output-only");
+
+	return 0;
+}
+
 static int __devinit i2c_gpio_probe(struct platform_device *pdev)
 {
+	struct i2c_gpio_private_data *priv;
 	struct i2c_gpio_platform_data *pdata;
 	struct i2c_algo_bit_data *bit_data;
 	struct i2c_adapter *adap;
 	int ret;
 
-	pdata = pdev->dev.platform_data;
-	if (!pdata)
-		return -ENXIO;
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	adap = &priv->adap;
+	bit_data = &priv->bit_data;
+	pdata = &priv->pdata;
 
-	ret = -ENOMEM;
-	adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
-	if (!adap)
-		goto err_alloc_adap;
-	bit_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL);
-	if (!bit_data)
-		goto err_alloc_bit_data;
+	if (pdev->dev.of_node) {
+		ret = of_i2c_gpio_probe(pdev->dev.of_node, pdata);
+		if (ret)
+			return ret;
+	} else {
+		if (!pdev->dev.platform_data)
+			return -ENXIO;
+		memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
+	}
 
 	ret = gpio_request(pdata->sda_pin, "sda");
 	if (ret)
@@ -143,6 +188,7 @@
 	adap->algo_data = bit_data;
 	adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
 	adap->dev.parent = &pdev->dev;
+	adap->dev.of_node = pdev->dev.of_node;
 
 	/*
 	 * If "dev->id" is negative we consider it as zero.
@@ -154,7 +200,9 @@
 	if (ret)
 		goto err_add_bus;
 
-	platform_set_drvdata(pdev, adap);
+	of_i2c_register_devices(adap);
+
+	platform_set_drvdata(pdev, priv);
 
 	dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n",
 		 pdata->sda_pin, pdata->scl_pin,
@@ -168,34 +216,40 @@
 err_request_scl:
 	gpio_free(pdata->sda_pin);
 err_request_sda:
-	kfree(bit_data);
-err_alloc_bit_data:
-	kfree(adap);
-err_alloc_adap:
 	return ret;
 }
 
 static int __devexit i2c_gpio_remove(struct platform_device *pdev)
 {
+	struct i2c_gpio_private_data *priv;
 	struct i2c_gpio_platform_data *pdata;
 	struct i2c_adapter *adap;
 
-	adap = platform_get_drvdata(pdev);
-	pdata = pdev->dev.platform_data;
+	priv = platform_get_drvdata(pdev);
+	adap = &priv->adap;
+	pdata = &priv->pdata;
 
 	i2c_del_adapter(adap);
 	gpio_free(pdata->scl_pin);
 	gpio_free(pdata->sda_pin);
-	kfree(adap->algo_data);
-	kfree(adap);
 
 	return 0;
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id i2c_gpio_dt_ids[] = {
+	{ .compatible = "i2c-gpio", },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids);
+#endif
+
 static struct platform_driver i2c_gpio_driver = {
 	.driver		= {
 		.name	= "i2c-gpio",
 		.owner	= THIS_MODULE,
+		.of_match_table	= of_match_ptr(i2c_gpio_dt_ids),
 	},
 	.probe		= i2c_gpio_probe,
 	.remove		= __devexit_p(i2c_gpio_remove),
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 5d2e281..ae2945a5 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -2,7 +2,7 @@
     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
     Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
     <mdsxyz123@yahoo.com>
-    Copyright (C) 2007, 2008   Jean Delvare <khali@linux-fr.org>
+    Copyright (C) 2007 - 2012  Jean Delvare <khali@linux-fr.org>
     Copyright (C) 2010         Intel Corporation,
                                David Woodhouse <dwmw2@infradead.org>
 
@@ -51,6 +51,7 @@
   Patsburg (PCH) IDF    0x1d72     32     hard     yes     yes     yes
   DH89xxCC (PCH)        0x2330     32     hard     yes     yes     yes
   Panther Point (PCH)   0x1e22     32     hard     yes     yes     yes
+  Lynx Point (PCH)      0x8c22     32     hard     yes     yes     yes
 
   Features supported by this driver:
   Software PEC                     no
@@ -105,7 +106,7 @@
 #define SMBHSTCNT_KILL		2
 
 /* Other settings */
-#define MAX_TIMEOUT		100
+#define MAX_RETRIES		400
 #define ENABLE_INT9		0	/* set to 0x01 to enable - untested */
 
 /* I801 command constants */
@@ -145,6 +146,7 @@
 #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS	0x1e22
 #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS	0x2330
 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS	0x3b30
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS	0x8c22
 
 struct i801_priv {
 	struct i2c_adapter adapter;
@@ -215,7 +217,7 @@
 		dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
 		outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL,
 		       SMBHSTCNT(priv));
-		msleep(1);
+		usleep_range(1000, 2000);
 		outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL),
 		       SMBHSTCNT(priv));
 
@@ -272,11 +274,11 @@
 
 	/* We will always wait for a fraction of a second! */
 	do {
-		msleep(1);
+		usleep_range(250, 500);
 		status = inb_p(SMBHSTSTS(priv));
-	} while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
+	} while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_RETRIES));
 
-	result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);
+	result = i801_check_post(priv, status, timeout > MAX_RETRIES);
 	if (result < 0)
 		return result;
 
@@ -291,12 +293,12 @@
 	int status;
 
 	do {
-		msleep(1);
+		usleep_range(250, 500);
 		status = inb_p(SMBHSTSTS(priv));
 	} while ((!(status & SMBHSTSTS_INTR))
-		 && (timeout++ < MAX_TIMEOUT));
+		 && (timeout++ < MAX_RETRIES));
 
-	if (timeout > MAX_TIMEOUT)
+	if (timeout > MAX_RETRIES)
 		dev_dbg(&priv->pci_dev->dev, "PEC Timeout!\n");
 
 	outb_p(status, SMBHSTSTS(priv));
@@ -380,12 +382,12 @@
 		/* We will always wait for a fraction of a second! */
 		timeout = 0;
 		do {
-			msleep(1);
+			usleep_range(250, 500);
 			status = inb_p(SMBHSTSTS(priv));
 		} while ((!(status & SMBHSTSTS_BYTE_DONE))
-			 && (timeout++ < MAX_TIMEOUT));
+			 && (timeout++ < MAX_RETRIES));
 
-		result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);
+		result = i801_check_post(priv, status, timeout > MAX_RETRIES);
 		if (result < 0)
 			return result;
 
@@ -633,6 +635,7 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) },
 	{ 0, }
 };
 
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 58832e5..dfb84b7 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -149,11 +149,6 @@
 			break;
 		if (!for_busy && !(temp & I2SR_IBB))
 			break;
-		if (signal_pending(current)) {
-			dev_dbg(&i2c_imx->adapter.dev,
-				"<%s> I2C Interrupted\n", __func__);
-			return -EINTR;
-		}
 		if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
 			dev_dbg(&i2c_imx->adapter.dev,
 				"<%s> I2C bus is busy\n", __func__);
@@ -196,7 +191,7 @@
 
 	dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
 
-	clk_enable(i2c_imx->clk);
+	clk_prepare_enable(i2c_imx->clk);
 	writeb(i2c_imx->ifdr, i2c_imx->base + IMX_I2C_IFDR);
 	/* Enable I2C controller */
 	writeb(0, i2c_imx->base + IMX_I2C_I2SR);
@@ -245,7 +240,7 @@
 
 	/* Disable I2C controller */
 	writeb(0, i2c_imx->base + IMX_I2C_I2CR);
-	clk_disable(i2c_imx->clk);
+	clk_disable_unprepare(i2c_imx->clk);
 }
 
 static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c
index 6561d27..f90a605 100644
--- a/drivers/i2c/busses/i2c-isch.c
+++ b/drivers/i2c/busses/i2c-isch.c
@@ -47,7 +47,7 @@
 #define SMBBLKDAT	(0x20 + sch_smba)
 
 /* Other settings */
-#define MAX_TIMEOUT	500
+#define MAX_RETRIES	5000
 
 /* I2C constants */
 #define SCH_QUICK		0x00
@@ -68,7 +68,7 @@
 {
 	int temp;
 	int result = 0;
-	int timeout = 0;
+	int retries = 0;
 
 	dev_dbg(&sch_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
 		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT),
@@ -100,12 +100,12 @@
 	outb(inb(SMBHSTCNT) | 0x10, SMBHSTCNT);
 
 	do {
-		msleep(1);
+		usleep_range(100, 200);
 		temp = inb(SMBHSTSTS) & 0x0f;
-	} while ((temp & 0x08) && (timeout++ < MAX_TIMEOUT));
+	} while ((temp & 0x08) && (retries++ < MAX_RETRIES));
 
 	/* If the SMBus is still busy, we give up */
-	if (timeout > MAX_TIMEOUT) {
+	if (retries > MAX_RETRIES) {
 		dev_err(&sch_adapter.dev, "SMBus Timeout!\n");
 		result = -ETIMEDOUT;
 	}
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index a8ebb84..206caac 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -454,7 +454,7 @@
 }
 
 static int mpc_read(struct mpc_i2c *i2c, int target,
-		    u8 *data, int length, int restart)
+		    u8 *data, int length, int restart, bool recv_len)
 {
 	unsigned timeout = i2c->adap.timeout;
 	int i, result;
@@ -470,7 +470,7 @@
 		return result;
 
 	if (length) {
-		if (length == 1)
+		if (length == 1 && !recv_len)
 			writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
 		else
 			writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
@@ -479,17 +479,46 @@
 	}
 
 	for (i = 0; i < length; i++) {
+		u8 byte;
+
 		result = i2c_wait(i2c, timeout, 0);
 		if (result < 0)
 			return result;
 
-		/* Generate txack on next to last byte */
-		if (i == length - 2)
-			writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
-		/* Do not generate stop on last byte */
-		if (i == length - 1)
-			writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX);
-		data[i] = readb(i2c->base + MPC_I2C_DR);
+		/*
+		 * For block reads, we have to know the total length (1st byte)
+		 * before we can determine if we are done.
+		 */
+		if (i || !recv_len) {
+			/* Generate txack on next to last byte */
+			if (i == length - 2)
+				writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA
+					 | CCR_TXAK);
+			/* Do not generate stop on last byte */
+			if (i == length - 1)
+				writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA
+					 | CCR_MTX);
+		}
+
+		byte = readb(i2c->base + MPC_I2C_DR);
+
+		/*
+		 * Adjust length if first received byte is length.
+		 * The length is 1 length byte plus actually data length
+		 */
+		if (i == 0 && recv_len) {
+			if (byte == 0 || byte > I2C_SMBUS_BLOCK_MAX)
+				return -EPROTO;
+			length += byte;
+			/*
+			 * For block reads, generate txack here if data length
+			 * is 1 byte (total length is 2 bytes).
+			 */
+			if (length == 2)
+				writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA
+					 | CCR_TXAK);
+		}
+		data[i] = byte;
 	}
 
 	return length;
@@ -532,12 +561,17 @@
 			"Doing %s %d bytes to 0x%02x - %d of %d messages\n",
 			pmsg->flags & I2C_M_RD ? "read" : "write",
 			pmsg->len, pmsg->addr, i + 1, num);
-		if (pmsg->flags & I2C_M_RD)
-			ret =
-			    mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
-		else
+		if (pmsg->flags & I2C_M_RD) {
+			bool recv_len = pmsg->flags & I2C_M_RECV_LEN;
+
+			ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i,
+				       recv_len);
+			if (recv_len && ret > 0)
+				pmsg->len = ret;
+		} else {
 			ret =
 			    mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
+		}
 	}
 	mpc_i2c_stop(i2c);
 	return (ret < 0) ? ret : num;
@@ -545,7 +579,8 @@
 
 static u32 mpc_functionality(struct i2c_adapter *adap)
 {
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
+	  | I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL;
 }
 
 static const struct i2c_algorithm mpc_algo = {
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index d603646..f673326 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -29,6 +29,8 @@
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/i2c-pxa.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_i2c.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
@@ -1044,23 +1046,60 @@
 	.functionality	= i2c_pxa_functionality,
 };
 
+static struct of_device_id i2c_pxa_dt_ids[] = {
+	{ .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX },
+	{ .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX },
+	{ .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA2XX },
+	{}
+};
+MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
+
+static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c,
+			    enum pxa_i2c_types *i2c_types)
+{
+	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *of_id =
+			of_match_device(i2c_pxa_dt_ids, &pdev->dev);
+	int ret;
+
+	if (!of_id)
+		return 1;
+	ret = of_alias_get_id(np, "i2c");
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
+		return ret;
+	}
+	pdev->id = ret;
+	if (of_get_property(np, "mrvl,i2c-polling", NULL))
+		i2c->use_pio = 1;
+	if (of_get_property(np, "mrvl,i2c-fast-mode", NULL))
+		i2c->fast_mode = 1;
+	*i2c_types = (u32)(of_id->data);
+	return 0;
+}
+
+static int i2c_pxa_probe_pdata(struct platform_device *pdev,
+			       struct pxa_i2c *i2c,
+			       enum pxa_i2c_types *i2c_types)
+{
+	struct i2c_pxa_platform_data *plat = pdev->dev.platform_data;
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+
+	*i2c_types = id->driver_data;
+	if (plat) {
+		i2c->use_pio = plat->use_pio;
+		i2c->fast_mode = plat->fast_mode;
+	}
+	return 0;
+}
+
 static int i2c_pxa_probe(struct platform_device *dev)
 {
-	struct pxa_i2c *i2c;
-	struct resource *res;
 	struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
-	const struct platform_device_id *id = platform_get_device_id(dev);
-	enum pxa_i2c_types i2c_type = id->driver_data;
-	int ret;
-	int irq;
-
-	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-	irq = platform_get_irq(dev, 0);
-	if (res == NULL || irq < 0)
-		return -ENODEV;
-
-	if (!request_mem_region(res->start, resource_size(res), res->name))
-		return -ENOMEM;
+	enum pxa_i2c_types i2c_type;
+	struct pxa_i2c *i2c;
+	struct resource *res = NULL;
+	int ret, irq;
 
 	i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL);
 	if (!i2c) {
@@ -1068,6 +1107,24 @@
 		goto emalloc;
 	}
 
+	ret = i2c_pxa_probe_dt(dev, i2c, &i2c_type);
+	if (ret > 0)
+		ret = i2c_pxa_probe_pdata(dev, i2c, &i2c_type);
+	if (ret < 0)
+		goto eclk;
+
+	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(dev, 0);
+	if (res == NULL || irq < 0) {
+		ret = -ENODEV;
+		goto eclk;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res), res->name)) {
+		ret = -ENOMEM;
+		goto eclk;
+	}
+
 	i2c->adap.owner   = THIS_MODULE;
 	i2c->adap.retries = 5;
 
@@ -1109,21 +1166,16 @@
 
 	i2c->slave_addr = I2C_PXA_SLAVE_ADDR;
 
-#ifdef CONFIG_I2C_PXA_SLAVE
 	if (plat) {
+#ifdef CONFIG_I2C_PXA_SLAVE
 		i2c->slave_addr = plat->slave_addr;
 		i2c->slave = plat->slave;
-	}
 #endif
+		i2c->adap.class = plat->class;
+	}
 
 	clk_enable(i2c->clk);
 
-	if (plat) {
-		i2c->adap.class = plat->class;
-		i2c->use_pio = plat->use_pio;
-		i2c->fast_mode = plat->fast_mode;
-	}
-
 	if (i2c->use_pio) {
 		i2c->adap.algo = &i2c_pxa_pio_algorithm;
 	} else {
@@ -1234,6 +1286,7 @@
 		.name	= "pxa2xx-i2c",
 		.owner	= THIS_MODULE,
 		.pm	= I2C_PXA_DEV_PM_OPS,
+		.of_match_table = i2c_pxa_dt_ids,
 	},
 	.id_table	= i2c_pxa_id_table,
 };
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 4c17180..737f721 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -31,6 +31,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/clk.h>
 #include <linux/cpufreq.h>
 #include <linux/slab.h>
@@ -564,6 +565,7 @@
 	int retry;
 	int ret;
 
+	pm_runtime_get_sync(&adap->dev);
 	clk_enable(i2c->clk);
 
 	for (retry = 0; retry < adap->retries; retry++) {
@@ -572,6 +574,7 @@
 
 		if (ret != -EAGAIN) {
 			clk_disable(i2c->clk);
+			pm_runtime_put_sync(&adap->dev);
 			return ret;
 		}
 
@@ -581,6 +584,7 @@
 	}
 
 	clk_disable(i2c->clk);
+	pm_runtime_put_sync(&adap->dev);
 	return -EREMOTEIO;
 }
 
@@ -890,7 +894,7 @@
 		}
 	}
 
-	i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);
+	i2c = devm_kzalloc(&pdev->dev, sizeof(struct s3c24xx_i2c), GFP_KERNEL);
 	if (!i2c) {
 		dev_err(&pdev->dev, "no memory for state\n");
 		return -ENOMEM;
@@ -1013,6 +1017,9 @@
 	of_i2c_register_devices(&i2c->adap);
 	platform_set_drvdata(pdev, i2c);
 
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_enable(&i2c->adap.dev);
+
 	dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
 	clk_disable(i2c->clk);
 	return 0;
@@ -1035,7 +1042,6 @@
 	clk_put(i2c->clk);
 
  err_noclk:
-	kfree(i2c);
 	return ret;
 }
 
@@ -1048,6 +1054,9 @@
 {
 	struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
 
+	pm_runtime_disable(&i2c->adap.dev);
+	pm_runtime_disable(&pdev->dev);
+
 	s3c24xx_i2c_deregister_cpufreq(i2c);
 
 	i2c_del_adapter(&i2c->adap);
@@ -1061,7 +1070,6 @@
 	release_resource(i2c->ioarea);
 	s3c24xx_i2c_dt_gpio_free(i2c);
 	kfree(i2c->ioarea);
-	kfree(i2c);
 
 	return 0;
 }
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
new file mode 100644
index 0000000..5574a47
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sirf.c
@@ -0,0 +1,459 @@
+/*
+ * I2C bus driver for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#define SIRFSOC_I2C_CLK_CTRL		0x00
+#define SIRFSOC_I2C_STATUS		0x0C
+#define SIRFSOC_I2C_CTRL		0x10
+#define SIRFSOC_I2C_IO_CTRL		0x14
+#define SIRFSOC_I2C_SDA_DELAY		0x18
+#define SIRFSOC_I2C_CMD_START		0x1C
+#define SIRFSOC_I2C_CMD_BUF		0x30
+#define SIRFSOC_I2C_DATA_BUF		0x80
+
+#define SIRFSOC_I2C_CMD_BUF_MAX		16
+#define SIRFSOC_I2C_DATA_BUF_MAX	16
+
+#define SIRFSOC_I2C_CMD(x)		(SIRFSOC_I2C_CMD_BUF + (x)*0x04)
+#define SIRFSOC_I2C_DATA_MASK(x)        (0xFF<<(((x)&3)*8))
+#define SIRFSOC_I2C_DATA_SHIFT(x)       (((x)&3)*8)
+
+#define SIRFSOC_I2C_DIV_MASK		(0xFFFF)
+
+/* I2C status flags */
+#define SIRFSOC_I2C_STAT_BUSY		BIT(0)
+#define SIRFSOC_I2C_STAT_TIP		BIT(1)
+#define SIRFSOC_I2C_STAT_NACK		BIT(2)
+#define SIRFSOC_I2C_STAT_TR_INT		BIT(4)
+#define SIRFSOC_I2C_STAT_STOP		BIT(6)
+#define SIRFSOC_I2C_STAT_CMD_DONE	BIT(8)
+#define SIRFSOC_I2C_STAT_ERR		BIT(9)
+#define SIRFSOC_I2C_CMD_INDEX		(0x1F<<16)
+
+/* I2C control flags */
+#define SIRFSOC_I2C_RESET		BIT(0)
+#define SIRFSOC_I2C_CORE_EN		BIT(1)
+#define SIRFSOC_I2C_MASTER_MODE		BIT(2)
+#define SIRFSOC_I2C_CMD_DONE_EN		BIT(11)
+#define SIRFSOC_I2C_ERR_INT_EN		BIT(12)
+
+#define SIRFSOC_I2C_SDA_DELAY_MASK	(0xFF)
+#define SIRFSOC_I2C_SCLF_FILTER		(3<<8)
+
+#define SIRFSOC_I2C_START_CMD		BIT(0)
+
+#define SIRFSOC_I2C_CMD_RP(x)		((x)&0x7)
+#define SIRFSOC_I2C_NACK		BIT(3)
+#define SIRFSOC_I2C_WRITE		BIT(4)
+#define SIRFSOC_I2C_READ		BIT(5)
+#define SIRFSOC_I2C_STOP		BIT(6)
+#define SIRFSOC_I2C_START		BIT(7)
+
+#define SIRFSOC_I2C_DEFAULT_SPEED 100000
+
+struct sirfsoc_i2c {
+	void __iomem *base;
+	struct clk *clk;
+	u32 cmd_ptr;		/* Current position in CMD buffer */
+	u8 *buf;		/* Buffer passed by user */
+	u32 msg_len;		/* Message length */
+	u32 finished_len;	/* number of bytes read/written */
+	u32 read_cmd_len;	/* number of read cmd sent */
+	int msg_read;		/* 1 indicates a read message */
+	int err_status;		/* 1 indicates an error on bus */
+
+	u32 sda_delay;		/* For suspend/resume */
+	u32 clk_div;
+	int last;		/* Last message in transfer, STOP cmd can be sent */
+
+	struct completion done;	/* indicates completion of message transfer */
+	struct i2c_adapter adapter;
+};
+
+static void i2c_sirfsoc_read_data(struct sirfsoc_i2c *siic)
+{
+	u32 data = 0;
+	int i;
+
+	for (i = 0; i < siic->read_cmd_len; i++) {
+		if (!(i & 0x3))
+			data = readl(siic->base + SIRFSOC_I2C_DATA_BUF + i);
+		siic->buf[siic->finished_len++] =
+			(u8)((data & SIRFSOC_I2C_DATA_MASK(i)) >>
+				SIRFSOC_I2C_DATA_SHIFT(i));
+	}
+}
+
+static void i2c_sirfsoc_queue_cmd(struct sirfsoc_i2c *siic)
+{
+	u32 regval;
+	int i = 0;
+
+	if (siic->msg_read) {
+		while (((siic->finished_len + i) < siic->msg_len)
+				&& (siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX)) {
+			regval = SIRFSOC_I2C_READ | SIRFSOC_I2C_CMD_RP(0);
+			if (((siic->finished_len + i) ==
+					(siic->msg_len - 1)) && siic->last)
+				regval |= SIRFSOC_I2C_STOP | SIRFSOC_I2C_NACK;
+			writel(regval,
+				siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+			i++;
+		}
+
+		siic->read_cmd_len = i;
+	} else {
+		while ((siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX - 1)
+				&& (siic->finished_len < siic->msg_len)) {
+			regval = SIRFSOC_I2C_WRITE | SIRFSOC_I2C_CMD_RP(0);
+			if ((siic->finished_len == (siic->msg_len - 1))
+				&& siic->last)
+				regval |= SIRFSOC_I2C_STOP;
+			writel(regval,
+				siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+			writel(siic->buf[siic->finished_len++],
+				siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+		}
+	}
+	siic->cmd_ptr = 0;
+
+	/* Trigger the transfer */
+	writel(SIRFSOC_I2C_START_CMD, siic->base + SIRFSOC_I2C_CMD_START);
+}
+
+static irqreturn_t i2c_sirfsoc_irq(int irq, void *dev_id)
+{
+	struct sirfsoc_i2c *siic = (struct sirfsoc_i2c *)dev_id;
+	u32 i2c_stat = readl(siic->base + SIRFSOC_I2C_STATUS);
+
+	if (i2c_stat & SIRFSOC_I2C_STAT_ERR) {
+		/* Error conditions */
+		siic->err_status = 1;
+		writel(SIRFSOC_I2C_STAT_ERR, siic->base + SIRFSOC_I2C_STATUS);
+
+		if (i2c_stat & SIRFSOC_I2C_STAT_NACK)
+			dev_err(&siic->adapter.dev, "ACK not received\n");
+		else
+			dev_err(&siic->adapter.dev, "I2C error\n");
+
+		complete(&siic->done);
+	} else if (i2c_stat & SIRFSOC_I2C_STAT_CMD_DONE) {
+		/* CMD buffer execution complete */
+		if (siic->msg_read)
+			i2c_sirfsoc_read_data(siic);
+		if (siic->finished_len == siic->msg_len)
+			complete(&siic->done);
+		else /* Fill a new CMD buffer for left data */
+			i2c_sirfsoc_queue_cmd(siic);
+
+		writel(SIRFSOC_I2C_STAT_CMD_DONE, siic->base + SIRFSOC_I2C_STATUS);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic,
+	struct i2c_msg *msg)
+{
+	unsigned char addr;
+	u32 regval = SIRFSOC_I2C_START | SIRFSOC_I2C_CMD_RP(0) | SIRFSOC_I2C_WRITE;
+
+	/* no data and last message -> add STOP */
+	if (siic->last && (msg->len == 0))
+		regval |= SIRFSOC_I2C_STOP;
+
+	writel(regval, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+
+	addr = msg->addr << 1;	/* Generate address */
+	if (msg->flags & I2C_M_RD)
+		addr |= 1;
+
+	writel(addr, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+}
+
+static int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg)
+{
+	u32 regval = readl(siic->base + SIRFSOC_I2C_CTRL);
+	/* timeout waiting for the xfer to finish or fail */
+	int timeout = msecs_to_jiffies((msg->len + 1) * 50);
+	int ret = 0;
+
+	i2c_sirfsoc_set_address(siic, msg);
+
+	writel(regval | SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN,
+		siic->base + SIRFSOC_I2C_CTRL);
+	i2c_sirfsoc_queue_cmd(siic);
+
+	if (wait_for_completion_timeout(&siic->done, timeout) == 0) {
+		siic->err_status = 1;
+		dev_err(&siic->adapter.dev, "Transfer timeout\n");
+	}
+
+	writel(regval & ~(SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN),
+		siic->base + SIRFSOC_I2C_CTRL);
+	writel(0, siic->base + SIRFSOC_I2C_CMD_START);
+
+	if (siic->err_status) {
+		writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
+			siic->base + SIRFSOC_I2C_CTRL);
+		while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
+			cpu_relax();
+
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static u32 i2c_sirfsoc_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static int i2c_sirfsoc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+	int num)
+{
+	struct sirfsoc_i2c *siic = adap->algo_data;
+	int i, ret;
+
+	clk_enable(siic->clk);
+
+	for (i = 0; i < num; i++) {
+		siic->buf = msgs[i].buf;
+		siic->msg_len = msgs[i].len;
+		siic->msg_read = !!(msgs[i].flags & I2C_M_RD);
+		siic->err_status = 0;
+		siic->cmd_ptr = 0;
+		siic->finished_len = 0;
+		siic->last = (i == (num - 1));
+
+		ret = i2c_sirfsoc_xfer_msg(siic, &msgs[i]);
+		if (ret) {
+			clk_disable(siic->clk);
+			return ret;
+		}
+	}
+
+	clk_disable(siic->clk);
+	return num;
+}
+
+/* I2C algorithms associated with this master controller driver */
+static const struct i2c_algorithm i2c_sirfsoc_algo = {
+	.master_xfer = i2c_sirfsoc_xfer,
+	.functionality = i2c_sirfsoc_func,
+};
+
+static int __devinit i2c_sirfsoc_probe(struct platform_device *pdev)
+{
+	struct sirfsoc_i2c *siic;
+	struct i2c_adapter *adap;
+	struct resource *mem_res;
+	struct clk *clk;
+	int bitrate;
+	int ctrl_speed;
+	int irq;
+
+	int err;
+	u32 regval;
+
+	clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(clk)) {
+		err = PTR_ERR(clk);
+		dev_err(&pdev->dev, "Clock get failed\n");
+		goto err_get_clk;
+	}
+
+	err = clk_prepare(clk);
+	if (err) {
+		dev_err(&pdev->dev, "Clock prepare failed\n");
+		goto err_clk_prep;
+	}
+
+	err = clk_enable(clk);
+	if (err) {
+		dev_err(&pdev->dev, "Clock enable failed\n");
+		goto err_clk_en;
+	}
+
+	ctrl_speed = clk_get_rate(clk);
+
+	siic = devm_kzalloc(&pdev->dev, sizeof(*siic), GFP_KERNEL);
+	if (!siic) {
+		dev_err(&pdev->dev, "Can't allocate driver data\n");
+		err = -ENOMEM;
+		goto out;
+	}
+	adap = &siic->adapter;
+	adap->class = I2C_CLASS_HWMON;
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (mem_res == NULL) {
+		dev_err(&pdev->dev, "Unable to get MEM resource\n");
+		err = -EINVAL;
+		goto out;
+	}
+
+	siic->base = devm_request_and_ioremap(&pdev->dev, mem_res);
+	if (siic->base == NULL) {
+		dev_err(&pdev->dev, "IO remap failed!\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		err = irq;
+		goto out;
+	}
+	err = devm_request_irq(&pdev->dev, irq, i2c_sirfsoc_irq, 0,
+		dev_name(&pdev->dev), siic);
+	if (err)
+		goto out;
+
+	adap->algo = &i2c_sirfsoc_algo;
+	adap->algo_data = siic;
+
+	adap->dev.parent = &pdev->dev;
+	adap->nr = pdev->id;
+
+	strlcpy(adap->name, "sirfsoc-i2c", sizeof(adap->name));
+
+	platform_set_drvdata(pdev, adap);
+	init_completion(&siic->done);
+
+	/* Controller Initalisation */
+
+	writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
+	while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
+		cpu_relax();
+	writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
+		siic->base + SIRFSOC_I2C_CTRL);
+
+	siic->clk = clk;
+
+	err = of_property_read_u32(pdev->dev.of_node,
+		"clock-frequency", &bitrate);
+	if (err < 0)
+		bitrate = SIRFSOC_I2C_DEFAULT_SPEED;
+
+	if (bitrate < 100000)
+		regval =
+			(2 * ctrl_speed) / (2 * bitrate * 11);
+	else
+		regval = ctrl_speed / (bitrate * 5);
+
+	writel(regval, siic->base + SIRFSOC_I2C_CLK_CTRL);
+	if (regval > 0xFF)
+		writel(0xFF, siic->base + SIRFSOC_I2C_SDA_DELAY);
+	else
+		writel(regval, siic->base + SIRFSOC_I2C_SDA_DELAY);
+
+	err = i2c_add_numbered_adapter(adap);
+	if (err < 0) {
+		dev_err(&pdev->dev, "Can't add new i2c adapter\n");
+		goto out;
+	}
+
+	clk_disable(clk);
+
+	dev_info(&pdev->dev, " I2C adapter ready to operate\n");
+
+	return 0;
+
+out:
+	clk_disable(clk);
+err_clk_en:
+	clk_unprepare(clk);
+err_clk_prep:
+	clk_put(clk);
+err_get_clk:
+	return err;
+}
+
+static int __devexit i2c_sirfsoc_remove(struct platform_device *pdev)
+{
+	struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+	struct sirfsoc_i2c *siic = adapter->algo_data;
+
+	writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
+	i2c_del_adapter(adapter);
+	clk_unprepare(siic->clk);
+	clk_put(siic->clk);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int i2c_sirfsoc_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+	struct sirfsoc_i2c *siic = adapter->algo_data;
+
+	clk_enable(siic->clk);
+	siic->sda_delay = readl(siic->base + SIRFSOC_I2C_SDA_DELAY);
+	siic->clk_div = readl(siic->base + SIRFSOC_I2C_CLK_CTRL);
+	clk_disable(siic->clk);
+	return 0;
+}
+
+static int i2c_sirfsoc_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+	struct sirfsoc_i2c *siic = adapter->algo_data;
+
+	clk_enable(siic->clk);
+	writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
+	writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
+		siic->base + SIRFSOC_I2C_CTRL);
+	writel(siic->clk_div, siic->base + SIRFSOC_I2C_CLK_CTRL);
+	writel(siic->sda_delay, siic->base + SIRFSOC_I2C_SDA_DELAY);
+	clk_disable(siic->clk);
+	return 0;
+}
+
+static const struct dev_pm_ops i2c_sirfsoc_pm_ops = {
+	.suspend = i2c_sirfsoc_suspend,
+	.resume = i2c_sirfsoc_resume,
+};
+#endif
+
+static const struct of_device_id sirfsoc_i2c_of_match[] __devinitconst = {
+	{ .compatible = "sirf,prima2-i2c", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, sirfsoc_i2c_of_match);
+
+static struct platform_driver i2c_sirfsoc_driver = {
+	.driver = {
+		.name = "sirfsoc_i2c",
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &i2c_sirfsoc_pm_ops,
+#endif
+		.of_match_table = sirfsoc_i2c_of_match,
+	},
+	.probe = i2c_sirfsoc_probe,
+	.remove = __devexit_p(i2c_sirfsoc_remove),
+};
+module_platform_driver(i2c_sirfsoc_driver);
+
+MODULE_DESCRIPTION("SiRF SoC I2C master controller driver");
+MODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>, "
+	"Xiangzhen Ye <Xiangzhen.Ye@csr.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 0ab4a95..e978635 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -457,7 +457,6 @@
 	int ret;
 
 	tegra_i2c_flush_fifos(i2c_dev);
-	i2c_writel(i2c_dev, 0xFF, I2C_INT_STATUS);
 
 	if (msg->len == 0)
 		return -EINVAL;
diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c
index 6055601..f585aea 100644
--- a/drivers/i2c/busses/i2c-versatile.c
+++ b/drivers/i2c/busses/i2c-versatile.c
@@ -16,6 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/io.h>
+#include <linux/of_i2c.h>
 
 #define I2C_CONTROL	0x00
 #define I2C_CONTROLS	0x00
@@ -99,6 +100,7 @@
 	strlcpy(i2c->adap.name, "Versatile I2C adapter", sizeof(i2c->adap.name));
 	i2c->adap.algo_data = &i2c->algo;
 	i2c->adap.dev.parent = &dev->dev;
+	i2c->adap.dev.of_node = dev->dev.of_node;
 	i2c->algo = i2c_versatile_algo;
 	i2c->algo.data = i2c;
 
@@ -111,6 +113,7 @@
 		ret = i2c_bit_add_bus(&i2c->adap);
 	if (ret >= 0) {
 		platform_set_drvdata(dev, i2c);
+		of_i2c_register_devices(&i2c->adap);
 		return 0;
 	}
 
@@ -133,12 +136,19 @@
 	return 0;
 }
 
+static const struct of_device_id i2c_versatile_match[] = {
+	{ .compatible = "arm,versatile-i2c", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, i2c_versatile_match);
+
 static struct platform_driver i2c_versatile_driver = {
 	.probe		= i2c_versatile_probe,
 	.remove		= i2c_versatile_remove,
 	.driver		= {
 		.name	= "versatile-i2c",
 		.owner	= THIS_MODULE,
+		.of_match_table = i2c_versatile_match,
 	},
 };
 
diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c
new file mode 100644
index 0000000..96d3fab
--- /dev/null
+++ b/drivers/i2c/busses/i2c-xlr.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2011, Netlogic Microsystems Inc.
+ * Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+/* XLR I2C REGISTERS */
+#define XLR_I2C_CFG		0x00
+#define XLR_I2C_CLKDIV		0x01
+#define XLR_I2C_DEVADDR		0x02
+#define XLR_I2C_ADDR		0x03
+#define XLR_I2C_DATAOUT		0x04
+#define XLR_I2C_DATAIN		0x05
+#define XLR_I2C_STATUS		0x06
+#define XLR_I2C_STARTXFR	0x07
+#define XLR_I2C_BYTECNT		0x08
+#define XLR_I2C_HDSTATIM	0x09
+
+/* XLR I2C REGISTERS FLAGS */
+#define XLR_I2C_BUS_BUSY	0x01
+#define XLR_I2C_SDOEMPTY	0x02
+#define XLR_I2C_RXRDY		0x04
+#define XLR_I2C_ACK_ERR		0x08
+#define XLR_I2C_ARB_STARTERR	0x30
+
+/* Register Values */
+#define XLR_I2C_CFG_ADDR	0xF8
+#define XLR_I2C_CFG_NOADDR	0xFA
+#define XLR_I2C_STARTXFR_ND	0x02    /* No Data */
+#define XLR_I2C_STARTXFR_RD	0x01    /* Read */
+#define XLR_I2C_STARTXFR_WR	0x00    /* Write */
+
+#define XLR_I2C_TIMEOUT		10	/* timeout per byte in msec */
+
+/*
+ * On XLR/XLS, we need to use __raw_ IO to read the I2C registers
+ * because they are in the big-endian MMIO area on the SoC.
+ *
+ * The readl/writel implementation on XLR/XLS byteswaps, because
+ * those are for its little-endian PCI space (see arch/mips/Kconfig).
+ */
+static inline void xlr_i2c_wreg(u32 __iomem *base, unsigned int reg, u32 val)
+{
+	__raw_writel(val, base + reg);
+}
+
+static inline u32 xlr_i2c_rdreg(u32 __iomem *base, unsigned int reg)
+{
+	return __raw_readl(base + reg);
+}
+
+struct xlr_i2c_private {
+	struct i2c_adapter adap;
+	u32 __iomem *iobase;
+};
+
+static int xlr_i2c_tx(struct xlr_i2c_private *priv,  u16 len,
+	u8 *buf, u16 addr)
+{
+	struct i2c_adapter *adap = &priv->adap;
+	unsigned long timeout, stoptime, checktime;
+	u32 i2c_status;
+	int pos, timedout;
+	u8 offset, byte;
+
+	offset = buf[0];
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_ADDR, offset);
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr);
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, XLR_I2C_CFG_ADDR);
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1);
+
+	timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT);
+	stoptime = jiffies + timeout;
+	timedout = 0;
+	pos = 1;
+retry:
+	if (len == 1) {
+		xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR,
+				XLR_I2C_STARTXFR_ND);
+	} else {
+		xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[pos]);
+		xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR,
+				XLR_I2C_STARTXFR_WR);
+	}
+
+	while (!timedout) {
+		checktime = jiffies;
+		i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
+
+		if (i2c_status & XLR_I2C_SDOEMPTY) {
+			pos++;
+			/* need to do a empty dataout after the last byte */
+			byte = (pos < len) ? buf[pos] : 0;
+			xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, byte);
+
+			/* reset timeout on successful xmit */
+			stoptime = jiffies + timeout;
+		}
+		timedout = time_after(checktime, stoptime);
+
+		if (i2c_status & XLR_I2C_ARB_STARTERR) {
+			if (timedout)
+				break;
+			goto retry;
+		}
+
+		if (i2c_status & XLR_I2C_ACK_ERR)
+			return -EIO;
+
+		if ((i2c_status & XLR_I2C_BUS_BUSY) == 0 && pos >= len)
+			return 0;
+	}
+	dev_err(&adap->dev, "I2C transmit timeout\n");
+	return -ETIMEDOUT;
+}
+
+static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr)
+{
+	struct i2c_adapter *adap = &priv->adap;
+	u32 i2c_status;
+	unsigned long timeout, stoptime, checktime;
+	int nbytes, timedout;
+	u8 byte;
+
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, XLR_I2C_CFG_NOADDR);
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len);
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr);
+
+	timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT);
+	stoptime = jiffies + timeout;
+	timedout = 0;
+	nbytes = 0;
+retry:
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_RD);
+
+	while (!timedout) {
+		checktime = jiffies;
+		i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
+		if (i2c_status & XLR_I2C_RXRDY) {
+			if (nbytes > len)
+				return -EIO;	/* should not happen */
+
+			/* we need to do a dummy datain when nbytes == len */
+			byte = xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN);
+			if (nbytes < len)
+				buf[nbytes] = byte;
+			nbytes++;
+
+			/* reset timeout on successful read */
+			stoptime = jiffies + timeout;
+		}
+
+		timedout = time_after(checktime, stoptime);
+		if (i2c_status & XLR_I2C_ARB_STARTERR) {
+			if (timedout)
+				break;
+			goto retry;
+		}
+
+		if (i2c_status & XLR_I2C_ACK_ERR)
+			return -EIO;
+
+		if ((i2c_status & XLR_I2C_BUS_BUSY) == 0)
+			return 0;
+	}
+
+	dev_err(&adap->dev, "I2C receive timeout\n");
+	return -ETIMEDOUT;
+}
+
+static int xlr_i2c_xfer(struct i2c_adapter *adap,
+	struct i2c_msg *msgs, int num)
+{
+	struct i2c_msg *msg;
+	int i;
+	int ret = 0;
+	struct xlr_i2c_private *priv = i2c_get_adapdata(adap);
+
+	for (i = 0; ret == 0 && i < num; i++) {
+		msg = &msgs[i];
+		if (msg->flags & I2C_M_RD)
+			ret = xlr_i2c_rx(priv, msg->len, &msg->buf[0],
+					msg->addr);
+		else
+			ret = xlr_i2c_tx(priv, msg->len, &msg->buf[0],
+					msg->addr);
+	}
+
+	return (ret != 0) ? ret : num;
+}
+
+static u32 xlr_func(struct i2c_adapter *adap)
+{
+	/* Emulate SMBUS over I2C */
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm xlr_i2c_algo = {
+	.master_xfer	= xlr_i2c_xfer,
+	.functionality	= xlr_func,
+};
+
+static int __devinit xlr_i2c_probe(struct platform_device *pdev)
+{
+	struct xlr_i2c_private  *priv;
+	struct resource *res;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->iobase = devm_request_and_ioremap(&pdev->dev, res);
+	if (!priv->iobase) {
+		dev_err(&pdev->dev, "devm_request_and_ioremap failed\n");
+		return -EBUSY;
+	}
+
+	priv->adap.dev.parent = &pdev->dev;
+	priv->adap.owner	= THIS_MODULE;
+	priv->adap.algo_data	= priv;
+	priv->adap.algo		= &xlr_i2c_algo;
+	priv->adap.nr		= pdev->id;
+	priv->adap.class	= I2C_CLASS_HWMON;
+	snprintf(priv->adap.name, sizeof(priv->adap.name), "xlr-i2c");
+
+	i2c_set_adapdata(&priv->adap, priv);
+	ret = i2c_add_numbered_adapter(&priv->adap);
+	if (ret < 0) {
+		dev_err(&priv->adap.dev, "Failed to add i2c bus.\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, priv);
+	dev_info(&priv->adap.dev, "Added I2C Bus.\n");
+	return 0;
+}
+
+static int __devexit xlr_i2c_remove(struct platform_device *pdev)
+{
+	struct xlr_i2c_private *priv;
+
+	priv = platform_get_drvdata(pdev);
+	i2c_del_adapter(&priv->adap);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct platform_driver xlr_i2c_driver = {
+	.probe  = xlr_i2c_probe,
+	.remove = __devexit_p(xlr_i2c_remove),
+	.driver = {
+		.name   = "xlr-i2cbus",
+		.owner  = THIS_MODULE,
+	},
+};
+
+module_platform_driver(xlr_i2c_driver);
+
+MODULE_AUTHOR("Ganesan Ramalingam <ganesanr@netlogicmicro.com>");
+MODULE_DESCRIPTION("XLR/XLS SoC I2C Controller driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:xlr-i2cbus");
diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c
index 10274ff..f24cc64 100644
--- a/drivers/i2c/i2c-boardinfo.c
+++ b/drivers/i2c/i2c-boardinfo.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
  */
 
 #include <linux/kernel.h>
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index e9c1893..feb7dc3 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -14,7 +14,8 @@
 
     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.		     */
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.							     */
 /* ------------------------------------------------------------------------- */
 
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h
index 9f9c57f..18a8fd2 100644
--- a/drivers/i2c/i2c-core.h
+++ b/drivers/i2c/i2c-core.h
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
  */
 
 #include <linux/rwsem.h>
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 10e7f1e..4504832 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -17,7 +17,8 @@
 
     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.
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.
 */
 
 /* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
index f61ccc1..9836d08 100644
--- a/drivers/i2c/i2c-smbus.c
+++ b/drivers/i2c/i2c-smbus.c
@@ -16,7 +16,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
  */
 
 #include <linux/kernel.h>
diff --git a/drivers/i2c/muxes/pca9541.c b/drivers/i2c/muxes/pca9541.c
index ed699c5..e0df9b6 100644
--- a/drivers/i2c/muxes/pca9541.c
+++ b/drivers/i2c/muxes/pca9541.c
@@ -393,18 +393,7 @@
 	.id_table = pca9541_id,
 };
 
-static int __init pca9541_init(void)
-{
-	return i2c_add_driver(&pca9541_driver);
-}
-
-static void __exit pca9541_exit(void)
-{
-	i2c_del_driver(&pca9541_driver);
-}
-
-module_init(pca9541_init);
-module_exit(pca9541_exit);
+module_i2c_driver(pca9541_driver);
 
 MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
 MODULE_DESCRIPTION("PCA9541 I2C master selector driver");
diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c
index 6f89536..0e37ef2 100644
--- a/drivers/i2c/muxes/pca954x.c
+++ b/drivers/i2c/muxes/pca954x.c
@@ -284,18 +284,7 @@
 	.id_table	= pca954x_id,
 };
 
-static int __init pca954x_init(void)
-{
-	return i2c_add_driver(&pca954x_driver);
-}
-
-static void __exit pca954x_exit(void)
-{
-	i2c_del_driver(&pca954x_driver);
-}
-
-module_init(pca954x_init);
-module_exit(pca954x_exit);
+module_i2c_driver(pca954x_driver);
 
 MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
 MODULE_DESCRIPTION("PCA954x I2C mux/switch driver");
diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
index d2f3db3..28e344e 100644
--- a/drivers/ide/ide-cs.c
+++ b/drivers/ide/ide-cs.c
@@ -41,7 +41,6 @@
 #include <linux/major.h>
 #include <linux/delay.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c
index 8bbfe55..e03f4f1 100644
--- a/drivers/ide/qd65xx.c
+++ b/drivers/ide/qd65xx.c
@@ -29,7 +29,6 @@
 #include <linux/blkdev.h>
 #include <linux/ide.h>
 #include <linux/init.h>
-#include <asm/system.h>
 #include <asm/io.h>
 
 #define DRV_NAME "qd65xx"
diff --git a/drivers/idle/i7300_idle.c b/drivers/idle/i7300_idle.c
index c976285..fa080eb 100644
--- a/drivers/idle/i7300_idle.c
+++ b/drivers/idle/i7300_idle.c
@@ -516,12 +516,6 @@
 
 MODULE_DEVICE_TABLE(pci, pci_tbl);
 
-int stats_open_generic(struct inode *inode, struct file *fp)
-{
-	fp->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t stats_read_ul(struct file *fp, char __user *ubuf, size_t count,
 				loff_t *off)
 {
@@ -534,7 +528,7 @@
 }
 
 static const struct file_operations idle_fops = {
-	.open	= stats_open_generic,
+	.open	= simple_open,
 	.read	= stats_read_ul,
 	.llseek = default_llseek,
 };
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 1c15e9b..d0f59c3 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -507,8 +507,7 @@
 		int num_substates;
 
 		if (cstate > max_cstate) {
-			printk(PREFIX "max_cstate %d reached\n",
-			       max_cstate);
+			printk(PREFIX "max_cstate %d reached\n", max_cstate);
 			break;
 		}
 
@@ -524,8 +523,9 @@
 		dev->states_usage[dev->state_count].driver_data =
 			(void *)get_driver_data(cstate);
 
-			dev->state_count += 1;
-		}
+		dev->state_count += 1;
+	}
+
 	dev->cpu = cpu;
 
 	if (cpuidle_register_device(dev)) {
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index 9a3fbfc..fd05f48 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -42,7 +42,6 @@
  */
 
 
-#include <asm/system.h>
 #include "ehca_classes.h"
 #include "ehca_tools.h"
 #include "ehca_qes.h"
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index ebe33d9..69e2ad0 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -1378,7 +1378,9 @@
 		break;
 	case SRPT_STATE_NEED_DATA:
 		/* DMA_TO_DEVICE (write) - RDMA read error. */
-		atomic_set(&ioctx->cmd.transport_lun_stop, 1);
+		spin_lock_irqsave(&ioctx->cmd.t_state_lock, flags);
+		ioctx->cmd.transport_state |= CMD_T_LUN_STOP;
+		spin_unlock_irqrestore(&ioctx->cmd.t_state_lock, flags);
 		transport_generic_handle_data(&ioctx->cmd);
 		break;
 	case SRPT_STATE_CMD_RSP_SENT:
@@ -1387,7 +1389,9 @@
 		 * not been received in time.
 		 */
 		srpt_unmap_sg_to_ib_sge(ioctx->ch, ioctx);
-		atomic_set(&ioctx->cmd.transport_lun_stop, 1);
+		spin_lock_irqsave(&ioctx->cmd.t_state_lock, flags);
+		ioctx->cmd.transport_state |= CMD_T_LUN_STOP;
+		spin_unlock_irqrestore(&ioctx->cmd.t_state_lock, flags);
 		kref_put(&ioctx->kref, srpt_put_send_ioctx_kref);
 		break;
 	case SRPT_STATE_MGMT_RSP_SENT:
@@ -1494,6 +1498,7 @@
 {
 	struct se_cmd *cmd;
 	enum srpt_command_state state;
+	unsigned long flags;
 
 	cmd = &ioctx->cmd;
 	state = srpt_get_cmd_state(ioctx);
@@ -1513,7 +1518,9 @@
 			       __func__, __LINE__, state);
 		break;
 	case SRPT_RDMA_WRITE_LAST:
-		atomic_set(&ioctx->cmd.transport_lun_stop, 1);
+		spin_lock_irqsave(&ioctx->cmd.t_state_lock, flags);
+		ioctx->cmd.transport_state |= CMD_T_LUN_STOP;
+		spin_unlock_irqrestore(&ioctx->cmd.t_state_lock, flags);
 		break;
 	default:
 		printk(KERN_ERR "%s[%d]: opcode = %u\n", __func__,
@@ -1750,6 +1757,7 @@
 		       srp_cmd->tag);
 		cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
 		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+		kref_put(&send_ioctx->kref, srpt_put_send_ioctx_kref);
 		goto send_sense;
 	}
 
@@ -1757,15 +1765,19 @@
 	cmd->data_direction = dir;
 	unpacked_lun = srpt_unpack_lun((uint8_t *)&srp_cmd->lun,
 				       sizeof(srp_cmd->lun));
-	if (transport_lookup_cmd_lun(cmd, unpacked_lun) < 0)
+	if (transport_lookup_cmd_lun(cmd, unpacked_lun) < 0) {
+		kref_put(&send_ioctx->kref, srpt_put_send_ioctx_kref);
 		goto send_sense;
+	}
 	ret = transport_generic_allocate_tasks(cmd, srp_cmd->cdb);
-	if (cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
-		srpt_queue_status(cmd);
-	else if (cmd->se_cmd_flags & SCF_SCSI_CDB_EXCEPTION)
-		goto send_sense;
-	else
-		WARN_ON_ONCE(ret);
+	if (ret < 0) {
+		kref_put(&send_ioctx->kref, srpt_put_send_ioctx_kref);
+		if (cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) {
+			srpt_queue_status(cmd);
+			return 0;
+		} else
+			goto send_sense;
+	}
 
 	transport_handle_cdb_direct(cmd);
 	return 0;
@@ -1871,8 +1883,8 @@
 			TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
 		goto process_tmr;
 	}
-	cmd->se_tmr_req = core_tmr_alloc_req(cmd, NULL, tcm_tmr, GFP_KERNEL);
-	if (!cmd->se_tmr_req) {
+	res = core_tmr_alloc_req(cmd, NULL, tcm_tmr, GFP_KERNEL);
+	if (res < 0) {
 		send_ioctx->cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
 		send_ioctx->cmd.se_tmr_req->response = TMR_FUNCTION_REJECTED;
 		goto process_tmr;
@@ -3514,25 +3526,6 @@
 }
 
 /**
- * To do: Find out whether stop_session() has a meaning for transports
- * other than iSCSI.
- */
-static void srpt_stop_session(struct se_session *se_sess, int sess_sleep,
-			      int conn_sleep)
-{
-}
-
-static void srpt_reset_nexus(struct se_session *sess)
-{
-	printk(KERN_ERR "This is the SRP protocol, not iSCSI\n");
-}
-
-static int srpt_sess_logged_in(struct se_session *se_sess)
-{
-	return true;
-}
-
-/**
  * srpt_sess_get_index() - Return the value of scsiAttIntrPortIndex (SCSI-MIB).
  *
  * A quote from RFC 4455 (SCSI-MIB) about this MIB object:
@@ -3576,11 +3569,6 @@
 	return 0;
 }
 
-static int srpt_is_state_remove(struct se_cmd *se_cmd)
-{
-	return 0;
-}
-
 /**
  * srpt_parse_i_port_id() - Parse an initiator port ID.
  * @name: ASCII representation of a 128-bit initiator port ID.
@@ -3950,9 +3938,6 @@
 	.check_stop_free		= srpt_check_stop_free,
 	.shutdown_session		= srpt_shutdown_session,
 	.close_session			= srpt_close_session,
-	.stop_session			= srpt_stop_session,
-	.fall_back_to_erl0		= srpt_reset_nexus,
-	.sess_logged_in			= srpt_sess_logged_in,
 	.sess_get_index			= srpt_sess_get_index,
 	.sess_get_initiator_sid		= NULL,
 	.write_pending			= srpt_write_pending,
@@ -3965,7 +3950,6 @@
 	.queue_tm_rsp			= srpt_queue_response,
 	.get_fabric_sense_len		= srpt_get_fabric_sense_len,
 	.set_fabric_sense_len		= srpt_set_fabric_sense_len,
-	.is_state_remove		= srpt_is_state_remove,
 	/*
 	 * Setup function pointers for generic logic in
 	 * target_core_fabric_configfs.c
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 001b147..3325979 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -25,6 +25,10 @@
 
 if INPUT
 
+config INPUT_OF_MATRIX_KEYMAP
+	depends on USE_OF
+	bool
+
 config INPUT_FF_MEMLESS
 	tristate "Support for memoryless force-feedback devices"
 	help
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 0c78949..b173a13a 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -24,3 +24,4 @@
 obj-$(CONFIG_INPUT_MISC)	+= misc/
 
 obj-$(CONFIG_INPUT_APMPOWER)	+= apm-power.o
+obj-$(CONFIG_INPUT_OF_MATRIX_KEYMAP) += of_keymap.o
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 7df5bfe..4b2e10d 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -20,7 +20,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/major.h>
 #include <linux/device.h>
 #include "input-compat.h"
@@ -46,6 +46,7 @@
 	struct fasync_struct *fasync;
 	struct evdev *evdev;
 	struct list_head node;
+	int clkid;
 	unsigned int bufsize;
 	struct input_event buffer[];
 };
@@ -54,8 +55,12 @@
 static DEFINE_MUTEX(evdev_table_mutex);
 
 static void evdev_pass_event(struct evdev_client *client,
-			     struct input_event *event)
+			     struct input_event *event,
+			     ktime_t mono, ktime_t real)
 {
+	event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
+					mono : real);
+
 	/* Interrupts are disabled, just acquire the lock. */
 	spin_lock(&client->buffer_lock);
 
@@ -94,8 +99,11 @@
 	struct evdev *evdev = handle->private;
 	struct evdev_client *client;
 	struct input_event event;
+	ktime_t time_mono, time_real;
 
-	do_gettimeofday(&event.time);
+	time_mono = ktime_get();
+	time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());
+
 	event.type = type;
 	event.code = code;
 	event.value = value;
@@ -103,11 +111,12 @@
 	rcu_read_lock();
 
 	client = rcu_dereference(evdev->grab);
+
 	if (client)
-		evdev_pass_event(client, &event);
+		evdev_pass_event(client, &event, time_mono, time_real);
 	else
 		list_for_each_entry_rcu(client, &evdev->client_list, node)
-			evdev_pass_event(client, &event);
+			evdev_pass_event(client, &event, time_mono, time_real);
 
 	rcu_read_unlock();
 
@@ -623,6 +632,28 @@
 	return input_set_keycode(dev, &ke);
 }
 
+static int evdev_handle_mt_request(struct input_dev *dev,
+				   unsigned int size,
+				   int __user *ip)
+{
+	const struct input_mt_slot *mt = dev->mt;
+	unsigned int code;
+	int max_slots;
+	int i;
+
+	if (get_user(code, &ip[0]))
+		return -EFAULT;
+	if (!input_is_mt_value(code))
+		return -EINVAL;
+
+	max_slots = (size - sizeof(__u32)) / sizeof(__s32);
+	for (i = 0; i < dev->mtsize && i < max_slots; i++)
+		if (put_user(input_mt_get_value(&mt[i], code), &ip[1 + i]))
+			return -EFAULT;
+
+	return 0;
+}
+
 static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 			   void __user *p, int compat_mode)
 {
@@ -685,6 +716,14 @@
 		else
 			return evdev_ungrab(evdev, client);
 
+	case EVIOCSCLOCKID:
+		if (copy_from_user(&i, p, sizeof(unsigned int)))
+			return -EFAULT;
+		if (i != CLOCK_MONOTONIC && i != CLOCK_REALTIME)
+			return -EINVAL;
+		client->clkid = i;
+		return 0;
+
 	case EVIOCGKEYCODE:
 		return evdev_handle_get_keycode(dev, p);
 
@@ -708,6 +747,9 @@
 		return bits_to_user(dev->propbit, INPUT_PROP_MAX,
 				    size, p, compat_mode);
 
+	case EVIOCGMTSLOTS(0):
+		return evdev_handle_mt_request(dev, size, ip);
+
 	case EVIOCGKEY(0):
 		return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode);
 
diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c
index e46a867..64ca711 100644
--- a/drivers/input/input-compat.c
+++ b/drivers/input/input-compat.c
@@ -17,7 +17,7 @@
 int input_event_from_user(const char __user *buffer,
 			  struct input_event *event)
 {
-	if (INPUT_COMPAT_TEST) {
+	if (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) {
 		struct input_event_compat compat_event;
 
 		if (copy_from_user(&compat_event, buffer,
@@ -41,7 +41,7 @@
 int input_event_to_user(char __user *buffer,
 			const struct input_event *event)
 {
-	if (INPUT_COMPAT_TEST) {
+	if (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) {
 		struct input_event_compat compat_event;
 
 		compat_event.time.tv_sec = event->time.tv_sec;
diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h
index 22be27b..148f66f 100644
--- a/drivers/input/input-compat.h
+++ b/drivers/input/input-compat.h
@@ -67,7 +67,7 @@
 
 static inline size_t input_event_size(void)
 {
-	return INPUT_COMPAT_TEST ?
+	return (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) ?
 		sizeof(struct input_event_compat) : sizeof(struct input_event);
 }
 
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 1f78c957..8921c61 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -180,7 +180,7 @@
 		return INPUT_IGNORE_EVENT;
 	}
 
-	is_mt_event = code >= ABS_MT_FIRST && code <= ABS_MT_LAST;
+	is_mt_event = input_is_mt_value(code);
 
 	if (!is_mt_event) {
 		pold = &dev->absinfo[code].value;
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index c24ec2d..26043cc 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -13,7 +13,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/joystick.h>
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
index 0bc8620..c65b5fa 100644
--- a/drivers/input/joystick/amijoy.c
+++ b/drivers/input/joystick/amijoy.c
@@ -35,7 +35,6 @@
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
 
-#include <asm/system.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 
@@ -108,6 +107,9 @@
 	int i, j;
 	int err;
 
+	if (!MACH_IS_AMIGA)
+		return -ENODEV;
+
 	for (i = 0; i < 2; i++) {
 		if (!amijoy[i])
 			continue;
diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c
index 6d6e741..3063464 100644
--- a/drivers/input/joystick/as5011.c
+++ b/drivers/input/joystick/as5011.c
@@ -355,14 +355,4 @@
 	.id_table	= as5011_id,
 };
 
-static int __init as5011_init(void)
-{
-	return i2c_add_driver(&as5011_driver);
-}
-module_init(as5011_init);
-
-static void __exit as5011_exit(void)
-{
-	i2c_del_driver(&as5011_driver);
-}
-module_exit(as5011_exit);
+module_i2c_driver(as5011_driver);
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index cdc385b..f354813 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -394,6 +394,7 @@
 config KEYBOARD_TEGRA
 	tristate "NVIDIA Tegra internal matrix keyboard controller support"
 	depends on ARCH_TEGRA
+	select INPUT_OF_MATRIX_KEYMAP if USE_OF
 	help
 	  Say Y here if you want to use a matrix keyboard connected directly
 	  to the internal keyboard controller on Tegra SoCs.
@@ -512,7 +513,6 @@
 
 config KEYBOARD_OMAP4
 	tristate "TI OMAP4 keypad support"
-	depends on ARCH_OMAP4
 	help
 	  Say Y here if you want to use the OMAP4 keypad.
 
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index 4a7f534..39ebffa 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -653,17 +653,7 @@
 	.id_table = adp5588_id,
 };
 
-static int __init adp5588_init(void)
-{
-	return i2c_add_driver(&adp5588_driver);
-}
-module_init(adp5588_init);
-
-static void __exit adp5588_exit(void)
-{
-	i2c_del_driver(&adp5588_driver);
-}
-module_exit(adp5588_exit);
+module_i2c_driver(adp5588_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c
index 02b5d53..74e6032 100644
--- a/drivers/input/keyboard/adp5589-keys.c
+++ b/drivers/input/keyboard/adp5589-keys.c
@@ -1108,17 +1108,7 @@
 	.id_table = adp5589_id,
 };
 
-static int __init adp5589_init(void)
-{
-	return i2c_add_driver(&adp5589_driver);
-}
-module_init(adp5589_init);
-
-static void __exit adp5589_exit(void)
-{
-	i2c_del_driver(&adp5589_driver);
-}
-module_exit(adp5589_exit);
+module_i2c_driver(adp5589_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index ed1ed46..62bfce4 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -28,14 +28,18 @@
 #include <linux/gpio.h>
 #include <linux/of_platform.h>
 #include <linux/of_gpio.h>
+#include <linux/spinlock.h>
 
 struct gpio_button_data {
-	struct gpio_keys_button *button;
+	const struct gpio_keys_button *button;
 	struct input_dev *input;
 	struct timer_list timer;
 	struct work_struct work;
-	int timer_debounce;	/* in msecs */
+	unsigned int timer_debounce;	/* in msecs */
+	unsigned int irq;
+	spinlock_t lock;
 	bool disabled;
+	bool key_pressed;
 };
 
 struct gpio_keys_drvdata {
@@ -114,7 +118,7 @@
 		/*
 		 * Disable IRQ and possible debouncing timer.
 		 */
-		disable_irq(gpio_to_irq(bdata->button->gpio));
+		disable_irq(bdata->irq);
 		if (bdata->timer_debounce)
 			del_timer_sync(&bdata->timer);
 
@@ -135,7 +139,7 @@
 static void gpio_keys_enable_button(struct gpio_button_data *bdata)
 {
 	if (bdata->disabled) {
-		enable_irq(gpio_to_irq(bdata->button->gpio));
+		enable_irq(bdata->irq);
 		bdata->disabled = false;
 	}
 }
@@ -195,7 +199,7 @@
  * @type: button type (%EV_KEY, %EV_SW)
  *
  * This function parses stringified bitmap from @buf and disables/enables
- * GPIO buttons accordinly. Returns 0 on success and negative error
+ * GPIO buttons accordingly. Returns 0 on success and negative error
  * on failure.
  */
 static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
@@ -320,9 +324,9 @@
 	.attrs = gpio_keys_attrs,
 };
 
-static void gpio_keys_report_event(struct gpio_button_data *bdata)
+static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
 {
-	struct gpio_keys_button *button = bdata->button;
+	const struct gpio_keys_button *button = bdata->button;
 	struct input_dev *input = bdata->input;
 	unsigned int type = button->type ?: EV_KEY;
 	int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
@@ -336,27 +340,26 @@
 	input_sync(input);
 }
 
-static void gpio_keys_work_func(struct work_struct *work)
+static void gpio_keys_gpio_work_func(struct work_struct *work)
 {
 	struct gpio_button_data *bdata =
 		container_of(work, struct gpio_button_data, work);
 
-	gpio_keys_report_event(bdata);
+	gpio_keys_gpio_report_event(bdata);
 }
 
-static void gpio_keys_timer(unsigned long _data)
+static void gpio_keys_gpio_timer(unsigned long _data)
 {
-	struct gpio_button_data *data = (struct gpio_button_data *)_data;
+	struct gpio_button_data *bdata = (struct gpio_button_data *)_data;
 
-	schedule_work(&data->work);
+	schedule_work(&bdata->work);
 }
 
-static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
+static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
 {
 	struct gpio_button_data *bdata = dev_id;
-	struct gpio_keys_button *button = bdata->button;
 
-	BUG_ON(irq != gpio_to_irq(button->gpio));
+	BUG_ON(irq != bdata->irq);
 
 	if (bdata->timer_debounce)
 		mod_timer(&bdata->timer,
@@ -367,50 +370,133 @@
 	return IRQ_HANDLED;
 }
 
+static void gpio_keys_irq_timer(unsigned long _data)
+{
+	struct gpio_button_data *bdata = (struct gpio_button_data *)_data;
+	struct input_dev *input = bdata->input;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bdata->lock, flags);
+	if (bdata->key_pressed) {
+		input_event(input, EV_KEY, bdata->button->code, 0);
+		input_sync(input);
+		bdata->key_pressed = false;
+	}
+	spin_unlock_irqrestore(&bdata->lock, flags);
+}
+
+static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
+{
+	struct gpio_button_data *bdata = dev_id;
+	const struct gpio_keys_button *button = bdata->button;
+	struct input_dev *input = bdata->input;
+	unsigned long flags;
+
+	BUG_ON(irq != bdata->irq);
+
+	spin_lock_irqsave(&bdata->lock, flags);
+
+	if (!bdata->key_pressed) {
+		input_event(input, EV_KEY, button->code, 1);
+		input_sync(input);
+
+		if (!bdata->timer_debounce) {
+			input_event(input, EV_KEY, button->code, 0);
+			input_sync(input);
+			goto out;
+		}
+
+		bdata->key_pressed = true;
+	}
+
+	if (bdata->timer_debounce)
+		mod_timer(&bdata->timer,
+			jiffies + msecs_to_jiffies(bdata->timer_debounce));
+out:
+	spin_unlock_irqrestore(&bdata->lock, flags);
+	return IRQ_HANDLED;
+}
+
 static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
+					 struct input_dev *input,
 					 struct gpio_button_data *bdata,
-					 struct gpio_keys_button *button)
+					 const struct gpio_keys_button *button)
 {
 	const char *desc = button->desc ? button->desc : "gpio_keys";
 	struct device *dev = &pdev->dev;
+	irq_handler_t isr;
 	unsigned long irqflags;
 	int irq, error;
 
-	setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);
-	INIT_WORK(&bdata->work, gpio_keys_work_func);
+	bdata->input = input;
+	bdata->button = button;
+	spin_lock_init(&bdata->lock);
 
-	error = gpio_request(button->gpio, desc);
-	if (error < 0) {
-		dev_err(dev, "failed to request GPIO %d, error %d\n",
-			button->gpio, error);
-		goto fail2;
+	if (gpio_is_valid(button->gpio)) {
+
+		error = gpio_request(button->gpio, desc);
+		if (error < 0) {
+			dev_err(dev, "Failed to request GPIO %d, error %d\n",
+				button->gpio, error);
+			return error;
+		}
+
+		error = gpio_direction_input(button->gpio);
+		if (error < 0) {
+			dev_err(dev,
+				"Failed to configure direction for GPIO %d, error %d\n",
+				button->gpio, error);
+			goto fail;
+		}
+
+		if (button->debounce_interval) {
+			error = gpio_set_debounce(button->gpio,
+					button->debounce_interval * 1000);
+			/* use timer if gpiolib doesn't provide debounce */
+			if (error < 0)
+				bdata->timer_debounce =
+						button->debounce_interval;
+		}
+
+		irq = gpio_to_irq(button->gpio);
+		if (irq < 0) {
+			error = irq;
+			dev_err(dev,
+				"Unable to get irq number for GPIO %d, error %d\n",
+				button->gpio, error);
+			goto fail;
+		}
+		bdata->irq = irq;
+
+		INIT_WORK(&bdata->work, gpio_keys_gpio_work_func);
+		setup_timer(&bdata->timer,
+			    gpio_keys_gpio_timer, (unsigned long)bdata);
+
+		isr = gpio_keys_gpio_isr;
+		irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+
+	} else {
+		if (!button->irq) {
+			dev_err(dev, "No IRQ specified\n");
+			return -EINVAL;
+		}
+		bdata->irq = button->irq;
+
+		if (button->type && button->type != EV_KEY) {
+			dev_err(dev, "Only EV_KEY allowed for IRQ buttons.\n");
+			return -EINVAL;
+		}
+
+		bdata->timer_debounce = button->debounce_interval;
+		setup_timer(&bdata->timer,
+			    gpio_keys_irq_timer, (unsigned long)bdata);
+
+		isr = gpio_keys_irq_isr;
+		irqflags = 0;
 	}
 
-	error = gpio_direction_input(button->gpio);
-	if (error < 0) {
-		dev_err(dev, "failed to configure"
-			" direction for GPIO %d, error %d\n",
-			button->gpio, error);
-		goto fail3;
-	}
+	input_set_capability(input, button->type ?: EV_KEY, button->code);
 
-	if (button->debounce_interval) {
-		error = gpio_set_debounce(button->gpio,
-					  button->debounce_interval * 1000);
-		/* use timer if gpiolib doesn't provide debounce */
-		if (error < 0)
-			bdata->timer_debounce = button->debounce_interval;
-	}
-
-	irq = gpio_to_irq(button->gpio);
-	if (irq < 0) {
-		error = irq;
-		dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n",
-			button->gpio, error);
-		goto fail3;
-	}
-
-	irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
 	/*
 	 * If platform has specified that the button can be disabled,
 	 * we don't want it to share the interrupt line.
@@ -418,18 +504,19 @@
 	if (!button->can_disable)
 		irqflags |= IRQF_SHARED;
 
-	error = request_threaded_irq(irq, NULL, gpio_keys_isr, irqflags, desc, bdata);
+	error = request_any_context_irq(bdata->irq, isr, irqflags, desc, bdata);
 	if (error < 0) {
 		dev_err(dev, "Unable to claim irq %d; error %d\n",
-			irq, error);
-		goto fail3;
+			bdata->irq, error);
+		goto fail;
 	}
 
 	return 0;
 
-fail3:
-	gpio_free(button->gpio);
-fail2:
+fail:
+	if (gpio_is_valid(button->gpio))
+		gpio_free(button->gpio);
+
 	return error;
 }
 
@@ -547,9 +634,19 @@
 
 #endif
 
+static void gpio_remove_key(struct gpio_button_data *bdata)
+{
+	free_irq(bdata->irq, bdata);
+	if (bdata->timer_debounce)
+		del_timer_sync(&bdata->timer);
+	cancel_work_sync(&bdata->work);
+	if (gpio_is_valid(bdata->button->gpio))
+		gpio_free(bdata->button->gpio);
+}
+
 static int __devinit gpio_keys_probe(struct platform_device *pdev)
 {
-	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+	const struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
 	struct gpio_keys_drvdata *ddata;
 	struct device *dev = &pdev->dev;
 	struct gpio_keys_platform_data alt_pdata;
@@ -599,21 +696,15 @@
 		__set_bit(EV_REP, input->evbit);
 
 	for (i = 0; i < pdata->nbuttons; i++) {
-		struct gpio_keys_button *button = &pdata->buttons[i];
+		const struct gpio_keys_button *button = &pdata->buttons[i];
 		struct gpio_button_data *bdata = &ddata->data[i];
-		unsigned int type = button->type ?: EV_KEY;
 
-		bdata->input = input;
-		bdata->button = button;
-
-		error = gpio_keys_setup_key(pdev, bdata, button);
+		error = gpio_keys_setup_key(pdev, input, bdata, button);
 		if (error)
 			goto fail2;
 
 		if (button->wakeup)
 			wakeup = 1;
-
-		input_set_capability(input, type, button->code);
 	}
 
 	error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
@@ -630,9 +721,12 @@
 		goto fail3;
 	}
 
-	/* get current state of buttons */
-	for (i = 0; i < pdata->nbuttons; i++)
-		gpio_keys_report_event(&ddata->data[i]);
+	/* get current state of buttons that are connected to GPIOs */
+	for (i = 0; i < pdata->nbuttons; i++) {
+		struct gpio_button_data *bdata = &ddata->data[i];
+		if (gpio_is_valid(bdata->button->gpio))
+			gpio_keys_gpio_report_event(bdata);
+	}
 	input_sync(input);
 
 	device_init_wakeup(&pdev->dev, wakeup);
@@ -642,13 +736,8 @@
  fail3:
 	sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
  fail2:
-	while (--i >= 0) {
-		free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
-		if (ddata->data[i].timer_debounce)
-			del_timer_sync(&ddata->data[i].timer);
-		cancel_work_sync(&ddata->data[i].work);
-		gpio_free(pdata->buttons[i].gpio);
-	}
+	while (--i >= 0)
+		gpio_remove_key(&ddata->data[i]);
 
 	platform_set_drvdata(pdev, NULL);
  fail1:
@@ -671,14 +760,8 @@
 
 	device_init_wakeup(&pdev->dev, 0);
 
-	for (i = 0; i < ddata->n_buttons; i++) {
-		int irq = gpio_to_irq(ddata->data[i].button->gpio);
-		free_irq(irq, &ddata->data[i]);
-		if (ddata->data[i].timer_debounce)
-			del_timer_sync(&ddata->data[i].timer);
-		cancel_work_sync(&ddata->data[i].work);
-		gpio_free(ddata->data[i].button->gpio);
-	}
+	for (i = 0; i < ddata->n_buttons; i++)
+		gpio_remove_key(&ddata->data[i]);
 
 	input_unregister_device(input);
 
@@ -703,11 +786,9 @@
 
 	if (device_may_wakeup(dev)) {
 		for (i = 0; i < ddata->n_buttons; i++) {
-			struct gpio_keys_button *button = ddata->data[i].button;
-			if (button->wakeup) {
-				int irq = gpio_to_irq(button->gpio);
-				enable_irq_wake(irq);
-			}
+			struct gpio_button_data *bdata = &ddata->data[i];
+			if (bdata->button->wakeup)
+				enable_irq_wake(bdata->irq);
 		}
 	}
 
@@ -720,14 +801,12 @@
 	int i;
 
 	for (i = 0; i < ddata->n_buttons; i++) {
+		struct gpio_button_data *bdata = &ddata->data[i];
+		if (bdata->button->wakeup && device_may_wakeup(dev))
+			disable_irq_wake(bdata->irq);
 
-		struct gpio_keys_button *button = ddata->data[i].button;
-		if (button->wakeup && device_may_wakeup(dev)) {
-			int irq = gpio_to_irq(button->gpio);
-			disable_irq_wake(irq);
-		}
-
-		gpio_keys_report_event(&ddata->data[i]);
+		if (gpio_is_valid(bdata->button->gpio))
+			gpio_keys_gpio_report_event(bdata);
 	}
 	input_sync(ddata->input);
 
diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c
index eeafc30..9d639fa 100644
--- a/drivers/input/keyboard/jornada720_kbd.c
+++ b/drivers/input/keyboard/jornada720_kbd.c
@@ -27,6 +27,7 @@
 
 #include <mach/jornada720.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 
 MODULE_AUTHOR("Kristoffer Ericson <Kristoffer.Ericson@gmail.com>");
 MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver");
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c
index 21823bf..39ac278 100644
--- a/drivers/input/keyboard/lm8323.c
+++ b/drivers/input/keyboard/lm8323.c
@@ -851,17 +851,7 @@
 };
 MODULE_DEVICE_TABLE(i2c, lm8323_id);
 
-static int __init lm8323_init(void)
-{
-	return i2c_add_driver(&lm8323_i2c_driver);
-}
-module_init(lm8323_init);
-
-static void __exit lm8323_exit(void)
-{
-	i2c_del_driver(&lm8323_i2c_driver);
-}
-module_exit(lm8323_exit);
+module_i2c_driver(lm8323_i2c_driver);
 
 MODULE_AUTHOR("Timo O. Karjalainen <timo.o.karjalainen@nokia.com>");
 MODULE_AUTHOR("Daniel Stone");
diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c
index 5afe35a..8edada8 100644
--- a/drivers/input/keyboard/max7359_keypad.c
+++ b/drivers/input/keyboard/max7359_keypad.c
@@ -316,17 +316,7 @@
 	.id_table	= max7359_ids,
 };
 
-static int __init max7359_init(void)
-{
-	return i2c_add_driver(&max7359_i2c_driver);
-}
-module_init(max7359_init);
-
-static void __exit max7359_exit(void)
-{
-	i2c_del_driver(&max7359_i2c_driver);
-}
-module_exit(max7359_exit);
+module_i2c_driver(max7359_i2c_driver);
 
 MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
 MODULE_DESCRIPTION("MAX7359 Key Switch Controller Driver");
diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c
index af1aab3..64a0ca4 100644
--- a/drivers/input/keyboard/mcs_touchkey.c
+++ b/drivers/input/keyboard/mcs_touchkey.c
@@ -274,18 +274,7 @@
 	.id_table	= mcs_touchkey_id,
 };
 
-static int __init mcs_touchkey_init(void)
-{
-	return i2c_add_driver(&mcs_touchkey_driver);
-}
-
-static void __exit mcs_touchkey_exit(void)
-{
-	i2c_del_driver(&mcs_touchkey_driver);
-}
-
-module_init(mcs_touchkey_init);
-module_exit(mcs_touchkey_exit);
+module_i2c_driver(mcs_touchkey_driver);
 
 /* Module information */
 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c
index 1c1615d..caa218a 100644
--- a/drivers/input/keyboard/mpr121_touchkey.c
+++ b/drivers/input/keyboard/mpr121_touchkey.c
@@ -330,17 +330,7 @@
 	.remove		= __devexit_p(mpr_touchkey_remove),
 };
 
-static int __init mpr_touchkey_init(void)
-{
-	return i2c_add_driver(&mpr_touchkey_driver);
-}
-module_init(mpr_touchkey_init);
-
-static void __exit mpr_touchkey_exit(void)
-{
-	i2c_del_driver(&mpr_touchkey_driver);
-}
-module_exit(mpr_touchkey_exit);
+module_i2c_driver(mpr_touchkey_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>");
diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c
index e35566a..101e245 100644
--- a/drivers/input/keyboard/nomadik-ske-keypad.c
+++ b/drivers/input/keyboard/nomadik-ske-keypad.c
@@ -88,7 +88,7 @@
  *
  * Enable Multi key press detection, auto scan mode
  */
-static int __devinit ske_keypad_chip_init(struct ske_keypad *keypad)
+static int __init ske_keypad_chip_init(struct ske_keypad *keypad)
 {
 	u32 value;
 	int timeout = 50;
@@ -198,7 +198,7 @@
 	return IRQ_HANDLED;
 }
 
-static int __devinit ske_keypad_probe(struct platform_device *pdev)
+static int __init ske_keypad_probe(struct platform_device *pdev)
 {
 	const struct ske_keypad_platform_data *plat = pdev->dev.platform_data;
 	struct ske_keypad *keypad;
@@ -344,7 +344,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int ske_keypad_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
@@ -372,22 +372,17 @@
 
 	return 0;
 }
-
-static const struct dev_pm_ops ske_keypad_dev_pm_ops = {
-	.suspend = ske_keypad_suspend,
-	.resume = ske_keypad_resume,
-};
 #endif
 
+static SIMPLE_DEV_PM_OPS(ske_keypad_dev_pm_ops,
+			 ske_keypad_suspend, ske_keypad_resume);
+
 static struct platform_driver ske_keypad_driver = {
 	.driver = {
 		.name = "nmk-ske-keypad",
 		.owner  = THIS_MODULE,
-#ifdef CONFIG_PM
 		.pm = &ske_keypad_dev_pm_ops,
-#endif
 	},
-	.probe = ske_keypad_probe,
 	.remove = __devexit_p(ske_keypad_remove),
 };
 
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
index d5c5d77..e809ac0 100644
--- a/drivers/input/keyboard/omap4-keypad.c
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -31,7 +31,7 @@
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
 
-#include <plat/omap4-keypad.h>
+#include <linux/platform_data/omap4-keypad.h>
 
 /* OMAP4 registers */
 #define OMAP4_KBD_REVISION		0x00
diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c
index b21bf5b..0b7b2f8 100644
--- a/drivers/input/keyboard/qt1070.c
+++ b/drivers/input/keyboard/qt1070.c
@@ -258,17 +258,7 @@
 	.remove		= __devexit_p(qt1070_remove),
 };
 
-static int __init qt1070_init(void)
-{
-	return i2c_add_driver(&qt1070_driver);
-}
-module_init(qt1070_init);
-
-static void __exit qt1070_exit(void)
-{
-	i2c_del_driver(&qt1070_driver);
-}
-module_exit(qt1070_exit);
+module_i2c_driver(qt1070_driver);
 
 MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>");
 MODULE_DESCRIPTION("Driver for AT42QT1070 QTouch sensor");
diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c
index fac6951..e7a5e36 100644
--- a/drivers/input/keyboard/qt2160.c
+++ b/drivers/input/keyboard/qt2160.c
@@ -379,17 +379,7 @@
 	.remove		= __devexit_p(qt2160_remove),
 };
 
-static int __init qt2160_init(void)
-{
-	return i2c_add_driver(&qt2160_driver);
-}
-module_init(qt2160_init);
-
-static void __exit qt2160_cleanup(void)
-{
-	i2c_del_driver(&qt2160_driver);
-}
-module_exit(qt2160_cleanup);
+module_i2c_driver(qt2160_driver);
 
 MODULE_AUTHOR("Raphael Derosso Pereira <raphaelpereira@gmail.com>");
 MODULE_DESCRIPTION("Driver for AT42QT2160 Touch Sensor");
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
index 17ba7f9..2391ae8 100644
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -175,7 +175,7 @@
 
 	} while (key_down && !keypad->stopped);
 
-	pm_runtime_put_sync(&keypad->pdev->dev);
+	pm_runtime_put(&keypad->pdev->dev);
 
 	return IRQ_HANDLED;
 }
@@ -199,7 +199,7 @@
 	/* KEYIFCOL reg clear. */
 	writel(0, keypad->base + SAMSUNG_KEYIFCOL);
 
-	pm_runtime_put_sync(&keypad->pdev->dev);
+	pm_runtime_put(&keypad->pdev->dev);
 }
 
 static void samsung_keypad_stop(struct samsung_keypad *keypad)
@@ -229,7 +229,7 @@
 	 */
 	enable_irq(keypad->irq);
 
-	pm_runtime_put_sync(&keypad->pdev->dev);
+	pm_runtime_put(&keypad->pdev->dev);
 }
 
 static int samsung_keypad_open(struct input_dev *input_dev)
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index c88bd63..3b6b528 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -50,6 +50,7 @@
 #define ROW_MASK	0xF0
 #define COLUMN_MASK	0x0F
 #define ROW_SHIFT	4
+#define KEY_MATRIX_SHIFT	6
 
 struct spear_kbd {
 	struct input_dev *input;
@@ -57,6 +58,7 @@
 	void __iomem *io_base;
 	struct clk *clk;
 	unsigned int irq;
+	unsigned int mode;
 	unsigned short last_key;
 	unsigned short keycodes[256];
 };
@@ -106,7 +108,8 @@
 		return error;
 
 	/* program keyboard */
-	val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK;
+	val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK |
+		(kbd->mode << KEY_MATRIX_SHIFT);
 	writew(val, kbd->io_base + MODE_REG);
 	writeb(1, kbd->io_base + STATUS_REG);
 
@@ -176,6 +179,8 @@
 
 	kbd->input = input_dev;
 	kbd->irq = irq;
+	kbd->mode = pdata->mode;
+
 	kbd->res = request_mem_region(res->start, resource_size(res),
 				      pdev->name);
 	if (!kbd->res) {
@@ -308,22 +313,17 @@
 
 	return 0;
 }
-
-static const struct dev_pm_ops spear_kbd_pm_ops = {
-	.suspend	= spear_kbd_suspend,
-	.resume		= spear_kbd_resume,
-};
 #endif
 
+static SIMPLE_DEV_PM_OPS(spear_kbd_pm_ops, spear_kbd_suspend, spear_kbd_resume);
+
 static struct platform_driver spear_kbd_driver = {
 	.probe		= spear_kbd_probe,
 	.remove		= __devexit_p(spear_kbd_remove),
 	.driver		= {
 		.name	= "keyboard",
 		.owner	= THIS_MODULE,
-#ifdef CONFIG_PM
 		.pm	= &spear_kbd_pm_ops,
-#endif
 	},
 };
 module_platform_driver(spear_kbd_driver);
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index a136e2e..fe4ac95 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -48,6 +48,7 @@
 #define KBC_FIFO_TH_CNT_SHIFT(cnt)	(cnt << 14)
 #define KBC_DEBOUNCE_CNT_SHIFT(cnt)	(cnt << 4)
 #define KBC_CONTROL_FIFO_CNT_INT_EN	(1 << 3)
+#define KBC_CONTROL_KEYPRESS_INT_EN	(1 << 1)
 #define KBC_CONTROL_KBC_EN		(1 << 0)
 
 /* KBC Interrupt Register */
@@ -356,6 +357,18 @@
 	writel(val, kbc->mmio + KBC_CONTROL_0);
 }
 
+static void tegra_kbc_set_keypress_interrupt(struct tegra_kbc *kbc, bool enable)
+{
+	u32 val;
+
+	val = readl(kbc->mmio + KBC_CONTROL_0);
+	if (enable)
+		val |= KBC_CONTROL_KEYPRESS_INT_EN;
+	else
+		val &= ~KBC_CONTROL_KEYPRESS_INT_EN;
+	writel(val, kbc->mmio + KBC_CONTROL_0);
+}
+
 static void tegra_kbc_keypress_timer(unsigned long data)
 {
 	struct tegra_kbc *kbc = (struct tegra_kbc *)data;
@@ -455,10 +468,18 @@
 		row_cfg &= ~r_mask;
 		col_cfg &= ~c_mask;
 
-		if (pdata->pin_cfg[i].is_row)
+		switch (pdata->pin_cfg[i].type) {
+		case PIN_CFG_ROW:
 			row_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << r_shft;
-		else
+			break;
+
+		case PIN_CFG_COL:
 			col_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << c_shft;
+			break;
+
+		case PIN_CFG_IGNORE:
+			break;
+		}
 
 		writel(row_cfg, kbc->mmio + r_offs);
 		writel(col_cfg, kbc->mmio + c_offs);
@@ -563,7 +584,8 @@
 	for (i = 0; i < KBC_MAX_GPIO; i++) {
 		const struct tegra_kbc_pin_cfg *pin_cfg = &pdata->pin_cfg[i];
 
-		if (pin_cfg->is_row) {
+		switch (pin_cfg->type) {
+		case PIN_CFG_ROW:
 			if (pin_cfg->num >= KBC_MAX_ROW) {
 				dev_err(dev,
 					"pin_cfg[%d]: invalid row number %d\n",
@@ -571,13 +593,25 @@
 				return false;
 			}
 			(*num_rows)++;
-		} else {
+			break;
+
+		case PIN_CFG_COL:
 			if (pin_cfg->num >= KBC_MAX_COL) {
 				dev_err(dev,
 					"pin_cfg[%d]: invalid column number %d\n",
 					i, pin_cfg->num);
 				return false;
 			}
+			break;
+
+		case PIN_CFG_IGNORE:
+			break;
+
+		default:
+			dev_err(dev,
+				"pin_cfg[%d]: invalid entry type %d\n",
+				pin_cfg->type, pin_cfg->num);
+			return false;
 		}
 	}
 
@@ -590,6 +624,8 @@
 {
 	struct tegra_kbc_platform_data *pdata;
 	struct device_node *np = pdev->dev.of_node;
+	u32 prop;
+	int i;
 
 	if (!np)
 		return NULL;
@@ -598,16 +634,16 @@
 	if (!pdata)
 		return NULL;
 
-	if (!of_property_read_u32(np, "debounce-delay", &prop))
+	if (!of_property_read_u32(np, "nvidia,debounce-delay-ms", &prop))
 		pdata->debounce_cnt = prop;
 
-	if (!of_property_read_u32(np, "repeat-delay", &prop))
+	if (!of_property_read_u32(np, "nvidia,repeat-delay-ms", &prop))
 		pdata->repeat_cnt = prop;
 
-	if (of_find_property(np, "needs-ghost-filter", NULL))
+	if (of_find_property(np, "nvidia,needs-ghost-filter", NULL))
 		pdata->use_ghost_filter = true;
 
-	if (of_find_property(np, "wakeup-source", NULL))
+	if (of_find_property(np, "nvidia,wakeup-source", NULL))
 		pdata->wakeup = true;
 
 	/*
@@ -616,14 +652,18 @@
 	 */
 	for (i = 0; i < KBC_MAX_ROW; i++) {
 		pdata->pin_cfg[i].num = i;
-		pdata->pin_cfg[i].is_row = true;
+		pdata->pin_cfg[i].type = PIN_CFG_ROW;
 	}
 
 	for (i = 0; i < KBC_MAX_COL; i++) {
 		pdata->pin_cfg[KBC_MAX_ROW + i].num = i;
-		pdata->pin_cfg[KBC_MAX_ROW + i].is_row = false;
+		pdata->pin_cfg[KBC_MAX_ROW + i].type = PIN_CFG_COL;
 	}
 
+	pdata->keymap_data = matrix_keyboard_of_fill_keymap(np, "linux,keymap");
+
+	/* FIXME: Add handling of linux,fn-keymap here */
+
 	return pdata;
 }
 #else
@@ -759,6 +799,9 @@
 	platform_set_drvdata(pdev, kbc);
 	device_init_wakeup(&pdev->dev, pdata->wakeup);
 
+	if (!pdev->dev.platform_data)
+		matrix_keyboard_of_free_keymap(pdata->keymap_data);
+
 	return 0;
 
 err_free_irq:
@@ -773,8 +816,10 @@
 	input_free_device(input_dev);
 	kfree(kbc);
 err_free_pdata:
-	if (!pdev->dev.platform_data)
+	if (!pdev->dev.platform_data) {
+		matrix_keyboard_of_free_keymap(pdata->keymap_data);
 		kfree(pdata);
+	}
 
 	return err;
 }
@@ -831,6 +876,8 @@
 		msleep(30);
 
 		kbc->keypress_caused_wake = false;
+		/* Enable keypress interrupt before going into suspend. */
+		tegra_kbc_set_keypress_interrupt(kbc, true);
 		enable_irq(kbc->irq);
 		enable_irq_wake(kbc->irq);
 	} else {
@@ -852,6 +899,8 @@
 	if (device_may_wakeup(&pdev->dev)) {
 		disable_irq_wake(kbc->irq);
 		tegra_kbc_setup_wakekeys(kbc, false);
+		/* We will use fifo interrupts for key detection. */
+		tegra_kbc_set_keypress_interrupt(kbc, false);
 
 		/* Restore the resident time of continuous polling mode. */
 		writel(kbc->cp_to_wkup_dly, kbc->mmio + KBC_TO_CNT_0);
diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c
index f2e0cbc..f9ce183 100644
--- a/drivers/input/misc/88pm860x_onkey.c
+++ b/drivers/input/misc/88pm860x_onkey.c
@@ -105,6 +105,8 @@
 	}
 
 	platform_set_drvdata(pdev, info);
+	device_init_wakeup(&pdev->dev, 1);
+
 	return 0;
 
 out_irq:
@@ -129,10 +131,34 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_onkey_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+	if (device_may_wakeup(dev))
+		chip->wakeup_flag |= 1 << PM8607_IRQ_ONKEY;
+	return 0;
+}
+static int pm860x_onkey_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+	if (device_may_wakeup(dev))
+		chip->wakeup_flag &= ~(1 << PM8607_IRQ_ONKEY);
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_onkey_pm_ops, pm860x_onkey_suspend, pm860x_onkey_resume);
+
 static struct platform_driver pm860x_onkey_driver = {
 	.driver		= {
 		.name	= "88pm860x-onkey",
 		.owner	= THIS_MODULE,
+		.pm	= &pm860x_onkey_pm_ops,
 	},
 	.probe		= pm860x_onkey_probe,
 	.remove		= __devexit_p(pm860x_onkey_remove),
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 7b46781..2d78779 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -134,6 +134,18 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called max8925_onkey.
 
+config INPUT_MAX8997_HAPTIC
+	tristate "MAXIM MAX8997 haptic controller support"
+	depends on HAVE_PWM && MFD_MAX8997
+	select INPUT_FF_MEMLESS
+	help
+	  This option enables device driver support for the haptic controller
+	  on MAXIM MAX8997 chip. This driver supports ff-memless interface
+	  from input framework.
+
+	  To compile this driver as module, choose M here: the
+	  module will be called max8997-haptic.
+
 config INPUT_MC13783_PWRBUTTON
 	tristate "MC13783 ON buttons"
 	depends on MFD_MC13783
@@ -415,7 +427,7 @@
 	tristate "PCF8574 Keypad input device"
 	depends on I2C && EXPERIMENTAL
 	help
-	  Say Y here if you want to support a keypad connetced via I2C
+	  Say Y here if you want to support a keypad connected via I2C
 	  with a PCF8574.
 
 	  To compile this driver as a module, choose M here: the
@@ -455,6 +467,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called rb532_button.
 
+config INPUT_DA9052_ONKEY
+	tristate "Dialog DA9052/DA9053 Onkey"
+	depends on PMIC_DA9052
+	help
+	  Support the ONKEY of Dialog DA9052 PMICs as an input device
+	  reporting power button status.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called da9052_onkey.
+
 config INPUT_DM355EVM
 	tristate "TI DaVinci DM355 EVM Keypad and IR Remote"
 	depends on MFD_DM355EVM_MSP
@@ -558,7 +580,7 @@
 
 config INPUT_XEN_KBDDEV_FRONTEND
 	tristate "Xen virtual keyboard and mouse support"
-	depends on XEN_FBDEV_FRONTEND
+	depends on XEN
 	default y
 	select XEN_XENBUS_FRONTEND
 	help
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 46671a8..f55cdf4 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -21,6 +21,7 @@
 obj-$(CONFIG_INPUT_CMA3000)		+= cma3000_d0x.o
 obj-$(CONFIG_INPUT_CMA3000_I2C)		+= cma3000_d0x_i2c.o
 obj-$(CONFIG_INPUT_COBALT_BTNS)		+= cobalt_btns.o
+obj-$(CONFIG_INPUT_DA9052_ONKEY)	+= da9052_onkey.o
 obj-$(CONFIG_INPUT_DM355EVM)		+= dm355evm_keys.o
 obj-$(CONFIG_INPUT_GP2A)		+= gp2ap002a00f.o
 obj-$(CONFIG_INPUT_GPIO_TILT_POLLED)	+= gpio_tilt_polled.o
@@ -30,6 +31,7 @@
 obj-$(CONFIG_INPUT_KXTJ9)		+= kxtj9.o
 obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
 obj-$(CONFIG_INPUT_MAX8925_ONKEY)	+= max8925_onkey.o
+obj-$(CONFIG_INPUT_MAX8997_HAPTIC)	+= max8997_haptic.o
 obj-$(CONFIG_INPUT_MC13783_PWRBUTTON)	+= mc13783-pwrbutton.o
 obj-$(CONFIG_INPUT_MMA8450)		+= mma8450.o
 obj-$(CONFIG_INPUT_MPU3050)		+= mpu3050.o
diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c
index 56810fb..c8a7901 100644
--- a/drivers/input/misc/ad714x-i2c.c
+++ b/drivers/input/misc/ad714x-i2c.c
@@ -116,17 +116,7 @@
 	.id_table = ad714x_id,
 };
 
-static int __init ad714x_i2c_init(void)
-{
-	return i2c_add_driver(&ad714x_i2c_driver);
-}
-module_init(ad714x_i2c_init);
-
-static void __exit ad714x_i2c_exit(void)
-{
-	i2c_del_driver(&ad714x_i2c_driver);
-}
-module_exit(ad714x_i2c_exit);
+module_i2c_driver(ad714x_i2c_driver);
 
 MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor I2C Bus Driver");
 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c
index 875b508..75f6136 100644
--- a/drivers/input/misc/ad714x-spi.c
+++ b/drivers/input/misc/ad714x-spi.c
@@ -123,17 +123,7 @@
 	.remove		= __devexit_p(ad714x_spi_remove),
 };
 
-static __init int ad714x_spi_init(void)
-{
-	return spi_register_driver(&ad714x_spi_driver);
-}
-module_init(ad714x_spi_init);
-
-static __exit void ad714x_spi_exit(void)
-{
-	spi_unregister_driver(&ad714x_spi_driver);
-}
-module_exit(ad714x_spi_exit);
+module_spi_driver(ad714x_spi_driver);
 
 MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor SPI Bus Driver");
 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c
index ccacf2b..dd1d1c1 100644
--- a/drivers/input/misc/adxl34x-i2c.c
+++ b/drivers/input/misc/adxl34x-i2c.c
@@ -148,17 +148,7 @@
 	.id_table = adxl34x_id,
 };
 
-static int __init adxl34x_i2c_init(void)
-{
-	return i2c_add_driver(&adxl34x_driver);
-}
-module_init(adxl34x_i2c_init);
-
-static void __exit adxl34x_i2c_exit(void)
-{
-	i2c_del_driver(&adxl34x_driver);
-}
-module_exit(adxl34x_i2c_exit);
+module_i2c_driver(adxl34x_driver);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer I2C Bus Driver");
diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c
index 34d401e..820a802 100644
--- a/drivers/input/misc/adxl34x-spi.c
+++ b/drivers/input/misc/adxl34x-spi.c
@@ -129,17 +129,7 @@
 	.remove  = __devexit_p(adxl34x_spi_remove),
 };
 
-static int __init adxl34x_spi_init(void)
-{
-	return spi_register_driver(&adxl34x_driver);
-}
-module_init(adxl34x_spi_init);
-
-static void __exit adxl34x_spi_exit(void)
-{
-	spi_unregister_driver(&adxl34x_driver);
-}
-module_exit(adxl34x_spi_exit);
+module_spi_driver(adxl34x_driver);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer SPI Bus Driver");
diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c
index 8f55b54..e2f1e9f 100644
--- a/drivers/input/misc/bma150.c
+++ b/drivers/input/misc/bma150.c
@@ -673,19 +673,8 @@
 	.remove		= __devexit_p(bma150_remove),
 };
 
-static int __init BMA150_init(void)
-{
-	return i2c_add_driver(&bma150_driver);
-}
-
-static void __exit BMA150_exit(void)
-{
-	i2c_del_driver(&bma150_driver);
-}
+module_i2c_driver(bma150_driver);
 
 MODULE_AUTHOR("Albert Zhang <xu.zhang@bosch-sensortec.com>");
 MODULE_DESCRIPTION("BMA150 driver");
 MODULE_LICENSE("GPL");
-
-module_init(BMA150_init);
-module_exit(BMA150_exit);
diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c
index d100cc5..fe9b85f 100644
--- a/drivers/input/misc/cma3000_d0x_i2c.c
+++ b/drivers/input/misc/cma3000_d0x_i2c.c
@@ -125,18 +125,7 @@
 	},
 };
 
-static int __init cma3000_i2c_init(void)
-{
-	return i2c_add_driver(&cma3000_i2c_driver);
-}
-
-static void __exit cma3000_i2c_exit(void)
-{
-	i2c_del_driver(&cma3000_i2c_driver);
-}
-
-module_init(cma3000_i2c_init);
-module_exit(cma3000_i2c_exit);
+module_i2c_driver(cma3000_i2c_driver);
 
 MODULE_DESCRIPTION("CMA3000-D0x Accelerometer I2C Driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c
new file mode 100644
index 0000000..34aebb8
--- /dev/null
+++ b/drivers/input/misc/da9052_onkey.c
@@ -0,0 +1,169 @@
+/*
+ * ON pin driver for Dialog DA9052 PMICs
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@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/init.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+
+struct da9052_onkey {
+	struct da9052 *da9052;
+	struct input_dev *input;
+	struct delayed_work work;
+	unsigned int irq;
+};
+
+static void da9052_onkey_query(struct da9052_onkey *onkey)
+{
+	int key_stat;
+
+	key_stat = da9052_reg_read(onkey->da9052, DA9052_EVENT_B_REG);
+	if (key_stat < 0) {
+		dev_err(onkey->da9052->dev,
+			"Failed to read onkey event %d\n", key_stat);
+	} else {
+		/*
+		 * Since interrupt for deassertion of ONKEY pin is not
+		 * generated, onkey event state determines the onkey
+		 * button state.
+		 */
+		key_stat &= DA9052_EVENTB_ENONKEY;
+		input_report_key(onkey->input, KEY_POWER, key_stat);
+		input_sync(onkey->input);
+	}
+
+	/*
+	 * Interrupt is generated only when the ONKEY pin is asserted.
+	 * Hence the deassertion of the pin is simulated through work queue.
+	 */
+	if (key_stat)
+		schedule_delayed_work(&onkey->work, msecs_to_jiffies(50));
+}
+
+static void da9052_onkey_work(struct work_struct *work)
+{
+	struct da9052_onkey *onkey = container_of(work, struct da9052_onkey,
+						  work.work);
+
+	da9052_onkey_query(onkey);
+}
+
+static irqreturn_t da9052_onkey_irq(int irq, void *data)
+{
+	struct da9052_onkey *onkey = data;
+
+	da9052_onkey_query(onkey);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit da9052_onkey_probe(struct platform_device *pdev)
+{
+	struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent);
+	struct da9052_onkey *onkey;
+	struct input_dev *input_dev;
+	int irq;
+	int error;
+
+	if (!da9052) {
+		dev_err(&pdev->dev, "Failed to get the driver's data\n");
+		return -EINVAL;
+	}
+
+	irq = platform_get_irq_byname(pdev, "ONKEY");
+	if (irq < 0) {
+		dev_err(&pdev->dev,
+			"Failed to get an IRQ for input device, %d\n", irq);
+		return -EINVAL;
+	}
+
+	onkey = kzalloc(sizeof(*onkey), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!onkey || !input_dev) {
+		dev_err(&pdev->dev, "Failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	onkey->input = input_dev;
+	onkey->da9052 = da9052;
+	onkey->irq = irq;
+	INIT_DELAYED_WORK(&onkey->work, da9052_onkey_work);
+
+	input_dev->name = "da9052-onkey";
+	input_dev->phys = "da9052-onkey/input0";
+	input_dev->dev.parent = &pdev->dev;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY);
+	__set_bit(KEY_POWER, input_dev->keybit);
+
+	error = request_threaded_irq(onkey->irq, NULL, da9052_onkey_irq,
+				     IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				     "ONKEY", onkey);
+	if (error < 0) {
+		dev_err(onkey->da9052->dev,
+			"Failed to register ONKEY IRQ %d, error = %d\n",
+			onkey->irq, error);
+		goto err_free_mem;
+	}
+
+	error = input_register_device(onkey->input);
+	if (error) {
+		dev_err(&pdev->dev, "Unable to register input device, %d\n",
+			error);
+		goto err_free_irq;
+	}
+
+	platform_set_drvdata(pdev, onkey);
+	return 0;
+
+err_free_irq:
+	free_irq(onkey->irq, onkey);
+	cancel_delayed_work_sync(&onkey->work);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(onkey);
+
+	return error;
+}
+
+static int __devexit da9052_onkey_remove(struct platform_device *pdev)
+{
+	struct da9052_onkey *onkey = platform_get_drvdata(pdev);
+
+	free_irq(onkey->irq, onkey);
+	cancel_delayed_work_sync(&onkey->work);
+
+	input_unregister_device(onkey->input);
+	kfree(onkey);
+
+	return 0;
+}
+
+static struct platform_driver da9052_onkey_driver = {
+	.probe	= da9052_onkey_probe,
+	.remove	= __devexit_p(da9052_onkey_remove),
+	.driver = {
+		.name	= "da9052-onkey",
+		.owner	= THIS_MODULE,
+	},
+};
+module_platform_driver(da9052_onkey_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("Onkey driver for DA9052");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9052-onkey");
diff --git a/drivers/input/misc/gp2ap002a00f.c b/drivers/input/misc/gp2ap002a00f.c
index 71fba8c..b6664cf 100644
--- a/drivers/input/misc/gp2ap002a00f.c
+++ b/drivers/input/misc/gp2ap002a00f.c
@@ -281,18 +281,7 @@
 	.id_table	= gp2a_i2c_id,
 };
 
-static int __init gp2a_init(void)
-{
-	return i2c_add_driver(&gp2a_i2c_driver);
-}
-
-static void __exit gp2a_exit(void)
-{
-	i2c_del_driver(&gp2a_i2c_driver);
-}
-
-module_init(gp2a_init);
-module_exit(gp2a_exit);
+module_i2c_driver(gp2a_i2c_driver);
 
 MODULE_AUTHOR("Courtney Cavin <courtney.cavin@sonyericsson.com>");
 MODULE_DESCRIPTION("Sharp GP2AP002A00F I2C Proximity/Opto sensor driver");
diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c
index 783597a..f46139f 100644
--- a/drivers/input/misc/kxtj9.c
+++ b/drivers/input/misc/kxtj9.c
@@ -41,6 +41,14 @@
 #define PC1_ON			(1 << 7)
 /* Data ready funtion enable bit: set during probe if using irq mode */
 #define DRDYE			(1 << 5)
+/* DATA CONTROL REGISTER BITS */
+#define ODR12_5F		0
+#define ODR25F			1
+#define ODR50F			2
+#define ODR100F		3
+#define ODR200F		4
+#define ODR400F		5
+#define ODR800F		6
 /* INTERRUPT CONTROL REGISTER 1 BITS */
 /* Set these during probe if using irq mode */
 #define KXTJ9_IEL		(1 << 3)
@@ -116,9 +124,13 @@
 	if (err < 0)
 		dev_err(&tj9->client->dev, "accelerometer data read failed\n");
 
-	x = le16_to_cpu(acc_data[tj9->pdata.axis_map_x]) >> tj9->shift;
-	y = le16_to_cpu(acc_data[tj9->pdata.axis_map_y]) >> tj9->shift;
-	z = le16_to_cpu(acc_data[tj9->pdata.axis_map_z]) >> tj9->shift;
+	x = le16_to_cpu(acc_data[tj9->pdata.axis_map_x]);
+	y = le16_to_cpu(acc_data[tj9->pdata.axis_map_y]);
+	z = le16_to_cpu(acc_data[tj9->pdata.axis_map_z]);
+
+	x >>= tj9->shift;
+	y >>= tj9->shift;
+	z >>= tj9->shift;
 
 	input_report_abs(tj9->input_dev, ABS_X, tj9->pdata.negate_x ? -x : x);
 	input_report_abs(tj9->input_dev, ABS_Y, tj9->pdata.negate_y ? -y : y);
@@ -487,7 +499,7 @@
 		goto out;
 	}
 
-	retval = retval != 0x06 ? -EIO : 0;
+	retval = (retval != 0x07 && retval != 0x08) ? -EIO : 0;
 
 out:
 	kxtj9_device_power_off(tj9);
@@ -537,7 +549,7 @@
 	i2c_set_clientdata(client, tj9);
 
 	tj9->ctrl_reg1 = tj9->pdata.res_12bit | tj9->pdata.g_range;
-	tj9->data_ctrl = tj9->pdata.data_odr_init;
+	tj9->last_poll_interval = tj9->pdata.init_interval;
 
 	if (client->irq) {
 		/* If in irq mode, populate INT_CTRL_REG1 and enable DRDY. */
@@ -655,17 +667,7 @@
 	.id_table	= kxtj9_id,
 };
 
-static int __init kxtj9_init(void)
-{
-	return i2c_add_driver(&kxtj9_driver);
-}
-module_init(kxtj9_init);
-
-static void __exit kxtj9_exit(void)
-{
-	i2c_del_driver(&kxtj9_driver);
-}
-module_exit(kxtj9_exit);
+module_i2c_driver(kxtj9_driver);
 
 MODULE_DESCRIPTION("KXTJ9 accelerometer driver");
 MODULE_AUTHOR("Chris Hudson <chudson@kionix.com>");
diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c
index 23cf082..0a12b74 100644
--- a/drivers/input/misc/max8925_onkey.c
+++ b/drivers/input/misc/max8925_onkey.c
@@ -1,5 +1,5 @@
 /**
- * max8925_onkey.c - MAX8925 ONKEY driver
+ * MAX8925 ONKEY driver
  *
  * Copyright (C) 2009 Marvell International Ltd.
  *      Haojian Zhuang <haojian.zhuang@marvell.com>
@@ -35,7 +35,7 @@
 	struct input_dev	*idev;
 	struct i2c_client	*i2c;
 	struct device		*dev;
-	int			irq[2];
+	unsigned int		irq[2];
 };
 
 /*
@@ -46,17 +46,14 @@
 static irqreturn_t max8925_onkey_handler(int irq, void *data)
 {
 	struct max8925_onkey_info *info = data;
-	int ret, event;
+	int state;
 
-	ret = max8925_reg_read(info->i2c, MAX8925_ON_OFF_STATUS);
-	if (ret & SW_INPUT)
-		event = 1;
-	else
-		event = 0;
-	input_report_key(info->idev, KEY_POWER, event);
+	state = max8925_reg_read(info->i2c, MAX8925_ON_OFF_STATUS);
+
+	input_report_key(info->idev, KEY_POWER, state & SW_INPUT);
 	input_sync(info->idev);
 
-	dev_dbg(info->dev, "onkey event:%d\n", event);
+	dev_dbg(info->dev, "onkey state:%d\n", state);
 
 	/* Enable hardreset to halt if system isn't shutdown on time */
 	max8925_set_bits(info->i2c, MAX8925_SYSENSEL,
@@ -69,6 +66,7 @@
 {
 	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
 	struct max8925_onkey_info *info;
+	struct input_dev *input;
 	int irq[2], error;
 
 	irq[0] = platform_get_irq(pdev, 0);
@@ -76,6 +74,7 @@
 		dev_err(&pdev->dev, "No IRQ resource!\n");
 		return -EINVAL;
 	}
+
 	irq[1] = platform_get_irq(pdev, 1);
 	if (irq[1] < 0) {
 		dev_err(&pdev->dev, "No IRQ resource!\n");
@@ -83,11 +82,24 @@
 	}
 
 	info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL);
-	if (!info)
-		return -ENOMEM;
+	input = input_allocate_device();
+	if (!info || !input) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
 
+	info->idev = input;
 	info->i2c = chip->i2c;
 	info->dev = &pdev->dev;
+	info->irq[0] = irq[0];
+	info->irq[1] = irq[1];
+
+	input->name = "max8925_on";
+	input->phys = "max8925_on/input0";
+	input->id.bustype = BUS_I2C;
+	input->dev.parent = &pdev->dev;
+	input_set_capability(input, EV_KEY, KEY_POWER);
+
 	irq[0] += chip->irq_base;
 	irq[1] += chip->irq_base;
 
@@ -96,60 +108,46 @@
 	if (error < 0) {
 		dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
 			irq[0], error);
-		goto out;
+		goto err_free_mem;
 	}
+
 	error = request_threaded_irq(irq[1], NULL, max8925_onkey_handler,
 				     IRQF_ONESHOT, "onkey-up", info);
 	if (error < 0) {
 		dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
 			irq[1], error);
-		goto out_irq;
+		goto err_free_irq0;
 	}
 
-	info->idev = input_allocate_device();
-	if (!info->idev) {
-		dev_err(chip->dev, "Failed to allocate input dev\n");
-		error = -ENOMEM;
-		goto out_input;
-	}
-
-	info->idev->name = "max8925_on";
-	info->idev->phys = "max8925_on/input0";
-	info->idev->id.bustype = BUS_I2C;
-	info->idev->dev.parent = &pdev->dev;
-	info->irq[0] = irq[0];
-	info->irq[1] = irq[1];
-	info->idev->evbit[0] = BIT_MASK(EV_KEY);
-	info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
-
-
 	error = input_register_device(info->idev);
 	if (error) {
 		dev_err(chip->dev, "Can't register input device: %d\n", error);
-		goto out_reg;
+		goto err_free_irq1;
 	}
 
 	platform_set_drvdata(pdev, info);
+	device_init_wakeup(&pdev->dev, 1);
 
 	return 0;
 
-out_reg:
-	input_free_device(info->idev);
-out_input:
-	free_irq(info->irq[1], info);
-out_irq:
-	free_irq(info->irq[0], info);
-out:
+err_free_irq1:
+	free_irq(irq[1], info);
+err_free_irq0:
+	free_irq(irq[0], info);
+err_free_mem:
+	input_free_device(input);
 	kfree(info);
+
 	return error;
 }
 
 static int __devexit max8925_onkey_remove(struct platform_device *pdev)
 {
 	struct max8925_onkey_info *info = platform_get_drvdata(pdev);
+	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
 
-	free_irq(info->irq[0], info);
-	free_irq(info->irq[1], info);
+	free_irq(info->irq[0] + chip->irq_base, info);
+	free_irq(info->irq[1] + chip->irq_base, info);
 	input_unregister_device(info->idev);
 	kfree(info);
 
@@ -158,10 +156,43 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int max8925_onkey_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct max8925_onkey_info *info = platform_get_drvdata(pdev);
+	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+	if (device_may_wakeup(dev)) {
+		chip->wakeup_flag |= 1 << info->irq[0];
+		chip->wakeup_flag |= 1 << info->irq[1];
+	}
+
+	return 0;
+}
+
+static int max8925_onkey_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct max8925_onkey_info *info = platform_get_drvdata(pdev);
+	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+	if (device_may_wakeup(dev)) {
+		chip->wakeup_flag &= ~(1 << info->irq[0]);
+		chip->wakeup_flag &= ~(1 << info->irq[1]);
+	}
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max8925_onkey_pm_ops, max8925_onkey_suspend, max8925_onkey_resume);
+
 static struct platform_driver max8925_onkey_driver = {
 	.driver		= {
 		.name	= "max8925-onkey",
 		.owner	= THIS_MODULE,
+		.pm	= &max8925_onkey_pm_ops,
 	},
 	.probe		= max8925_onkey_probe,
 	.remove		= __devexit_p(max8925_onkey_remove),
diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c
new file mode 100644
index 0000000..05b7b8b
--- /dev/null
+++ b/drivers/input/misc/max8997_haptic.c
@@ -0,0 +1,407 @@
+/*
+ * MAX8997-haptic controller driver
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Donggeun Kim <dg77.kim@samsung.com>
+ *
+ * This program is not provided / owned by Maxim Integrated Products.
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/pwm.h>
+#include <linux/input.h>
+#include <linux/mfd/max8997-private.h>
+#include <linux/mfd/max8997.h>
+#include <linux/regulator/consumer.h>
+
+/* Haptic configuration 2 register */
+#define MAX8997_MOTOR_TYPE_SHIFT	7
+#define MAX8997_ENABLE_SHIFT		6
+#define MAX8997_MODE_SHIFT		5
+
+/* Haptic driver configuration register */
+#define MAX8997_CYCLE_SHIFT		6
+#define MAX8997_SIG_PERIOD_SHIFT	4
+#define MAX8997_SIG_DUTY_SHIFT		2
+#define MAX8997_PWM_DUTY_SHIFT		0
+
+struct max8997_haptic {
+	struct device *dev;
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct regulator *regulator;
+
+	struct work_struct work;
+	struct mutex mutex;
+
+	bool enabled;
+	unsigned int level;
+
+	struct pwm_device *pwm;
+	unsigned int pwm_period;
+	enum max8997_haptic_pwm_divisor pwm_divisor;
+
+	enum max8997_haptic_motor_type type;
+	enum max8997_haptic_pulse_mode mode;
+
+	unsigned int internal_mode_pattern;
+	unsigned int pattern_cycle;
+	unsigned int pattern_signal_period;
+};
+
+static int max8997_haptic_set_duty_cycle(struct max8997_haptic *chip)
+{
+	int ret = 0;
+
+	if (chip->mode == MAX8997_EXTERNAL_MODE) {
+		unsigned int duty = chip->pwm_period * chip->level / 100;
+		ret = pwm_config(chip->pwm, duty, chip->pwm_period);
+	} else {
+		int i;
+		u8 duty_index = 0;
+
+		for (i = 0; i <= 64; i++) {
+			if (chip->level <= i * 100 / 64) {
+				duty_index = i;
+				break;
+			}
+		}
+		switch (chip->internal_mode_pattern) {
+		case 0:
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGPWMDC1, duty_index);
+			break;
+		case 1:
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGPWMDC2, duty_index);
+			break;
+		case 2:
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGPWMDC3, duty_index);
+			break;
+		case 3:
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGPWMDC4, duty_index);
+			break;
+		default:
+			break;
+		}
+	}
+	return ret;
+}
+
+static void max8997_haptic_configure(struct max8997_haptic *chip)
+{
+	u8 value;
+
+	value = chip->type << MAX8997_MOTOR_TYPE_SHIFT |
+		chip->enabled << MAX8997_ENABLE_SHIFT |
+		chip->mode << MAX8997_MODE_SHIFT | chip->pwm_divisor;
+	max8997_write_reg(chip->client, MAX8997_HAPTIC_REG_CONF2, value);
+
+	if (chip->mode == MAX8997_INTERNAL_MODE && chip->enabled) {
+		value = chip->internal_mode_pattern << MAX8997_CYCLE_SHIFT |
+			chip->internal_mode_pattern << MAX8997_SIG_PERIOD_SHIFT |
+			chip->internal_mode_pattern << MAX8997_SIG_DUTY_SHIFT |
+			chip->internal_mode_pattern << MAX8997_PWM_DUTY_SHIFT;
+		max8997_write_reg(chip->client,
+			MAX8997_HAPTIC_REG_DRVCONF, value);
+
+		switch (chip->internal_mode_pattern) {
+		case 0:
+			value = chip->pattern_cycle << 4;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_CYCLECONF1, value);
+			value = chip->pattern_signal_period;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGCONF1, value);
+			break;
+
+		case 1:
+			value = chip->pattern_cycle;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_CYCLECONF1, value);
+			value = chip->pattern_signal_period;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGCONF2, value);
+			break;
+
+		case 2:
+			value = chip->pattern_cycle << 4;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_CYCLECONF2, value);
+			value = chip->pattern_signal_period;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGCONF3, value);
+			break;
+
+		case 3:
+			value = chip->pattern_cycle;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_CYCLECONF2, value);
+			value = chip->pattern_signal_period;
+			max8997_write_reg(chip->client,
+				MAX8997_HAPTIC_REG_SIGCONF4, value);
+			break;
+
+		default:
+			break;
+		}
+	}
+}
+
+static void max8997_haptic_enable(struct max8997_haptic *chip)
+{
+	int error;
+
+	mutex_lock(&chip->mutex);
+
+	error = max8997_haptic_set_duty_cycle(chip);
+	if (error) {
+		dev_err(chip->dev, "set_pwm_cycle failed, error: %d\n", error);
+		goto out;
+	}
+
+	if (!chip->enabled) {
+		chip->enabled = true;
+		regulator_enable(chip->regulator);
+		max8997_haptic_configure(chip);
+		if (chip->mode == MAX8997_EXTERNAL_MODE)
+			pwm_enable(chip->pwm);
+	}
+
+out:
+	mutex_unlock(&chip->mutex);
+}
+
+static void max8997_haptic_disable(struct max8997_haptic *chip)
+{
+	mutex_lock(&chip->mutex);
+
+	if (chip->enabled) {
+		chip->enabled = false;
+		max8997_haptic_configure(chip);
+		if (chip->mode == MAX8997_EXTERNAL_MODE)
+			pwm_disable(chip->pwm);
+		regulator_disable(chip->regulator);
+	}
+
+	mutex_unlock(&chip->mutex);
+}
+
+static void max8997_haptic_play_effect_work(struct work_struct *work)
+{
+	struct max8997_haptic *chip =
+			container_of(work, struct max8997_haptic, work);
+
+	if (chip->level)
+		max8997_haptic_enable(chip);
+	else
+		max8997_haptic_disable(chip);
+}
+
+static int max8997_haptic_play_effect(struct input_dev *dev, void *data,
+				  struct ff_effect *effect)
+{
+	struct max8997_haptic *chip = input_get_drvdata(dev);
+
+	chip->level = effect->u.rumble.strong_magnitude;
+	if (!chip->level)
+		chip->level = effect->u.rumble.weak_magnitude;
+
+	schedule_work(&chip->work);
+
+	return 0;
+}
+
+static void max8997_haptic_close(struct input_dev *dev)
+{
+	struct max8997_haptic *chip = input_get_drvdata(dev);
+
+	cancel_work_sync(&chip->work);
+	max8997_haptic_disable(chip);
+}
+
+static int __devinit max8997_haptic_probe(struct platform_device *pdev)
+{
+	struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	const struct max8997_platform_data *pdata =
+					dev_get_platdata(iodev->dev);
+	const struct max8997_haptic_platform_data *haptic_pdata =
+					pdata->haptic_pdata;
+	struct max8997_haptic *chip;
+	struct input_dev *input_dev;
+	int error;
+
+	if (!haptic_pdata) {
+		dev_err(&pdev->dev, "no haptic platform data\n");
+		return -EINVAL;
+	}
+
+	chip = kzalloc(sizeof(struct max8997_haptic), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!chip || !input_dev) {
+		dev_err(&pdev->dev, "unable to allocate memory\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	INIT_WORK(&chip->work, max8997_haptic_play_effect_work);
+	mutex_init(&chip->mutex);
+
+	chip->client = iodev->haptic;
+	chip->dev = &pdev->dev;
+	chip->input_dev = input_dev;
+	chip->pwm_period = haptic_pdata->pwm_period;
+	chip->type = haptic_pdata->type;
+	chip->mode = haptic_pdata->mode;
+	chip->pwm_divisor = haptic_pdata->pwm_divisor;
+
+	switch (chip->mode) {
+	case MAX8997_INTERNAL_MODE:
+		chip->internal_mode_pattern =
+				haptic_pdata->internal_mode_pattern;
+		chip->pattern_cycle = haptic_pdata->pattern_cycle;
+		chip->pattern_signal_period =
+				haptic_pdata->pattern_signal_period;
+		break;
+
+	case MAX8997_EXTERNAL_MODE:
+		chip->pwm = pwm_request(haptic_pdata->pwm_channel_id,
+					"max8997-haptic");
+		if (IS_ERR(chip->pwm)) {
+			error = PTR_ERR(chip->pwm);
+			dev_err(&pdev->dev,
+				"unable to request PWM for haptic, error: %d\n",
+				error);
+			goto err_free_mem;
+		}
+		break;
+
+	default:
+		dev_err(&pdev->dev,
+			"Invalid chip mode specified (%d)\n", chip->mode);
+		error = -EINVAL;
+		goto err_free_mem;
+	}
+
+	chip->regulator = regulator_get(&pdev->dev, "inmotor");
+	if (IS_ERR(chip->regulator)) {
+		error = PTR_ERR(chip->regulator);
+		dev_err(&pdev->dev,
+			"unable to get regulator, error: %d\n",
+			error);
+		goto err_free_pwm;
+	}
+
+	input_dev->name = "max8997-haptic";
+	input_dev->id.version = 1;
+	input_dev->dev.parent = &pdev->dev;
+	input_dev->close = max8997_haptic_close;
+	input_set_drvdata(input_dev, chip);
+	input_set_capability(input_dev, EV_FF, FF_RUMBLE);
+
+	error = input_ff_create_memless(input_dev, NULL,
+				max8997_haptic_play_effect);
+	if (error) {
+		dev_err(&pdev->dev,
+			"unable to create FF device, error: %d\n",
+			error);
+		goto err_put_regulator;
+	}
+
+	error = input_register_device(input_dev);
+	if (error) {
+		dev_err(&pdev->dev,
+			"unable to register input device, error: %d\n",
+			error);
+		goto err_destroy_ff;
+	}
+
+	platform_set_drvdata(pdev, chip);
+	return 0;
+
+err_destroy_ff:
+	input_ff_destroy(input_dev);
+err_put_regulator:
+	regulator_put(chip->regulator);
+err_free_pwm:
+	if (chip->mode == MAX8997_EXTERNAL_MODE)
+		pwm_free(chip->pwm);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(chip);
+
+	return error;
+}
+
+static int __devexit max8997_haptic_remove(struct platform_device *pdev)
+{
+	struct max8997_haptic *chip = platform_get_drvdata(pdev);
+
+	input_unregister_device(chip->input_dev);
+	regulator_put(chip->regulator);
+
+	if (chip->mode == MAX8997_EXTERNAL_MODE)
+		pwm_free(chip->pwm);
+
+	kfree(chip);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max8997_haptic_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct max8997_haptic *chip = platform_get_drvdata(pdev);
+
+	max8997_haptic_disable(chip);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max8997_haptic_pm_ops, max8997_haptic_suspend, NULL);
+
+static const struct platform_device_id max8997_haptic_id[] = {
+	{ "max8997-haptic", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, max8997_haptic_id);
+
+static struct platform_driver max8997_haptic_driver = {
+	.driver	= {
+		.name	= "max8997-haptic",
+		.owner	= THIS_MODULE,
+		.pm	= &max8997_haptic_pm_ops,
+	},
+	.probe		= max8997_haptic_probe,
+	.remove		= __devexit_p(max8997_haptic_remove),
+	.id_table	= max8997_haptic_id,
+};
+module_platform_driver(max8997_haptic_driver);
+
+MODULE_ALIAS("platform:max8997-haptic");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_DESCRIPTION("max8997_haptic driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c
index 4d60080..873ebce 100644
--- a/drivers/input/misc/mma8450.c
+++ b/drivers/input/misc/mma8450.c
@@ -247,17 +247,7 @@
 	.id_table	= mma8450_id,
 };
 
-static int __init mma8450_init(void)
-{
-	return i2c_add_driver(&mma8450_driver);
-}
-module_init(mma8450_init);
-
-static void __exit mma8450_exit(void)
-{
-	i2c_del_driver(&mma8450_driver);
-}
-module_exit(mma8450_exit);
+module_i2c_driver(mma8450_driver);
 
 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
 MODULE_DESCRIPTION("MMA8450 3-Axis Accelerometer Driver");
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 208d1a1..5403c57 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -475,17 +475,7 @@
 	.id_table	= mpu3050_ids,
 };
 
-static int __init mpu3050_init(void)
-{
-	return i2c_add_driver(&mpu3050_i2c_driver);
-}
-module_init(mpu3050_init);
-
-static void __exit mpu3050_exit(void)
-{
-	i2c_del_driver(&mpu3050_i2c_driver);
-}
-module_exit(mpu3050_exit);
+module_i2c_driver(mpu3050_i2c_driver);
 
 MODULE_AUTHOR("Wistron Corp.");
 MODULE_DESCRIPTION("MPU3050 Tri-axis gyroscope driver");
diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c
index 08be1a3..544c663 100644
--- a/drivers/input/misc/pcf8574_keypad.c
+++ b/drivers/input/misc/pcf8574_keypad.c
@@ -216,17 +216,7 @@
 	.id_table = pcf8574_kp_id,
 };
 
-static int __init pcf8574_kp_init(void)
-{
-	return i2c_add_driver(&pcf8574_kp_driver);
-}
-module_init(pcf8574_kp_init);
-
-static void __exit pcf8574_kp_exit(void)
-{
-	i2c_del_driver(&pcf8574_kp_driver);
-}
-module_exit(pcf8574_kp_exit);
+module_i2c_driver(pcf8574_kp_driver);
 
 MODULE_AUTHOR("Michael Hennerich");
 MODULE_DESCRIPTION("Keypad input driver for 16 keys connected to PCF8574");
diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
index f3bc418..fc0ed9b 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -172,7 +172,7 @@
 }
 
 /*** Module ***/
-#if CONFIG_PM_SLEEP
+#ifdef CONFIG_PM_SLEEP
 static int twl4030_vibra_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 9c1e6ee..9b8db82 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -322,4 +322,21 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called synaptics_i2c.
 
+config MOUSE_SYNAPTICS_USB
+	tristate "Synaptics USB device support"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  Say Y here if you want to use a Synaptics USB touchpad or pointing
+	  stick.
+
+	  While these devices emulate an USB mouse by default and can be used
+	  with standard usbhid driver, this driver, together with its X.Org
+	  counterpart, allows you to fully utilize capabilities of the device.
+	  More information can be found at:
+	  <http://jan-steinhoff.de/linux/synaptics-usb.html>
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called synaptics_usb.
+
 endif
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 570c84a4..4718eff 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -18,6 +18,7 @@
 obj-$(CONFIG_MOUSE_RISCPC)		+= rpcmouse.o
 obj-$(CONFIG_MOUSE_SERIAL)		+= sermouse.o
 obj-$(CONFIG_MOUSE_SYNAPTICS_I2C)	+= synaptics_i2c.o
+obj-$(CONFIG_MOUSE_SYNAPTICS_USB)	+= synaptics_usb.o
 obj-$(CONFIG_MOUSE_VSXXXAA)		+= vsxxxaa.o
 
 psmouse-objs := psmouse-base.o synaptics.o
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
index ff5f61a..5fa9934 100644
--- a/drivers/input/mouse/amimouse.c
+++ b/drivers/input/mouse/amimouse.c
@@ -25,7 +25,6 @@
 
 #include <asm/irq.h>
 #include <asm/setup.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c
index 5c4a692..d1c4323 100644
--- a/drivers/input/mouse/atarimouse.c
+++ b/drivers/input/mouse/atarimouse.c
@@ -47,7 +47,6 @@
 
 #include <asm/irq.h>
 #include <asm/setup.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/atarihw.h>
 #include <asm/atarikb.h>
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 927e479..f9e2758 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -433,6 +433,7 @@
 	__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
 	__set_bit(BTN_LEFT, input_dev->keybit);
 
+	__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
 	if (cfg->caps & HAS_INTEGRATED_BUTTON)
 		__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
 
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
index 1c5d521..575f880 100644
--- a/drivers/input/mouse/hgpk.c
+++ b/drivers/input/mouse/hgpk.c
@@ -640,7 +640,6 @@
 
 static int hgpk_force_recalibrate(struct psmouse *psmouse)
 {
-	struct ps2dev *ps2dev = &psmouse->ps2dev;
 	struct hgpk_data *priv = psmouse->private;
 	int err;
 
@@ -669,12 +668,9 @@
 	 * we don't have a good way to deal with it.  The 2s window stuff
 	 * (below) is our best option for now.
 	 */
-
-	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
+	if (psmouse_activate(psmouse))
 		return -1;
 
-	psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
-
 	if (tpdebug)
 		psmouse_dbg(psmouse, "touchpad reactivated\n");
 
@@ -733,8 +729,7 @@
 		}
 
 		/* should be all set, enable the touchpad */
-		ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
-		psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
+		psmouse_activate(psmouse);
 		psmouse_dbg(psmouse, "Touchpad powered up.\n");
 	} else {
 		psmouse_dbg(psmouse, "Powering off touchpad.\n");
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index e6c9931..22fe254 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -1092,28 +1092,33 @@
  * psmouse_activate() enables the mouse so that we get motion reports from it.
  */
 
-static void psmouse_activate(struct psmouse *psmouse)
+int psmouse_activate(struct psmouse *psmouse)
 {
-	if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE))
+	if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
 		psmouse_warn(psmouse, "Failed to enable mouse on %s\n",
 			     psmouse->ps2dev.serio->phys);
+		return -1;
+	}
 
 	psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
+	return 0;
 }
 
-
 /*
  * psmouse_deactivate() puts the mouse into poll mode so that we don't get motion
  * reports from it unless we explicitly request it.
  */
 
-static void psmouse_deactivate(struct psmouse *psmouse)
+int psmouse_deactivate(struct psmouse *psmouse)
 {
-	if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
+	if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) {
 		psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n",
 			     psmouse->ps2dev.serio->phys);
+		return -1;
+	}
 
 	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+	return 0;
 }
 
 
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 6a41709..fe1df23 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -105,6 +105,8 @@
 void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
 void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
 psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse);
+int psmouse_activate(struct psmouse *psmouse);
+int psmouse_deactivate(struct psmouse *psmouse);
 
 struct psmouse_attribute {
 	struct device_attribute dattr;
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index e36847d..a977bfa 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -2,7 +2,7 @@
  * Finger Sensing Pad PS/2 mouse driver.
  *
  * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
- * Copyright (C) 2005-2011 Tai-hwa Liang, Sentelic Corporation.
+ * Copyright (C) 2005-2012 Tai-hwa Liang, Sentelic Corporation.
  *
  *   This program is free software; you can redistribute it and/or
  *   modify it under the terms of the GNU General Public License
@@ -21,6 +21,7 @@
 
 #include <linux/module.h>
 #include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/ctype.h>
 #include <linux/libps2.h>
 #include <linux/serio.h>
@@ -36,6 +37,9 @@
 #define	FSP_CMD_TIMEOUT		200
 #define	FSP_CMD_TIMEOUT2	30
 
+#define	GET_ABS_X(packet)	((packet[1] << 2) | ((packet[3] >> 2) & 0x03))
+#define	GET_ABS_Y(packet)	((packet[2] << 2) | (packet[3] & 0x03))
+
 /** Driver version. */
 static const char fsp_drv_ver[] = "1.0.0-K";
 
@@ -90,8 +94,7 @@
 	 * to do that for writes because sysfs set helper does this for
 	 * us.
 	 */
-	ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
-	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+	psmouse_deactivate(psmouse);
 
 	ps2_begin_command(ps2dev);
 
@@ -128,10 +131,10 @@
 
  out:
 	ps2_end_command(ps2dev);
-	ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
-	psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
-	dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n",
-		reg_addr, *reg_val, rc);
+	psmouse_activate(psmouse);
+	psmouse_dbg(psmouse,
+		    "READ REG: 0x%02x is 0x%02x (rc = %d)\n",
+		    reg_addr, *reg_val, rc);
 	return rc;
 }
 
@@ -181,8 +184,9 @@
 
  out:
 	ps2_end_command(ps2dev);
-	dev_dbg(&ps2dev->serio->dev, "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n",
-		reg_addr, reg_val, rc);
+	psmouse_dbg(psmouse,
+		    "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n",
+		    reg_addr, reg_val, rc);
 	return rc;
 }
 
@@ -213,8 +217,7 @@
 	unsigned char param[3];
 	int rc = -1;
 
-	ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
-	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+	psmouse_deactivate(psmouse);
 
 	ps2_begin_command(ps2dev);
 
@@ -239,10 +242,10 @@
 
  out:
 	ps2_end_command(ps2dev);
-	ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
-	psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
-	dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n",
-		*reg_val, rc);
+	psmouse_activate(psmouse);
+	psmouse_dbg(psmouse,
+		    "READ PAGE REG: 0x%02x (rc = %d)\n",
+		    *reg_val, rc);
 	return rc;
 }
 
@@ -278,8 +281,9 @@
 
  out:
 	ps2_end_command(ps2dev);
-	dev_dbg(&ps2dev->serio->dev, "WRITE PAGE REG: to 0x%02x (rc = %d)\n",
-		reg_val, rc);
+	psmouse_dbg(psmouse,
+		    "WRITE PAGE REG: to 0x%02x (rc = %d)\n",
+		    reg_val, rc);
 	return rc;
 }
 
@@ -323,7 +327,7 @@
 	int res = 0;
 
 	if (fsp_reg_read(psmouse, FSP_REG_OPC_QDOWN, &v) == -1) {
-		dev_err(&psmouse->ps2dev.serio->dev, "Unable get OPC state.\n");
+		psmouse_err(psmouse, "Unable get OPC state.\n");
 		return -EIO;
 	}
 
@@ -340,8 +344,7 @@
 	}
 
 	if (res != 0) {
-		dev_err(&psmouse->ps2dev.serio->dev,
-			"Unable to enable OPC tag.\n");
+		psmouse_err(psmouse, "Unable to enable OPC tag.\n");
 		res = -EIO;
 	}
 
@@ -619,18 +622,40 @@
 	.attrs = fsp_attributes,
 };
 
-#ifdef FSP_DEBUG
-static void fsp_packet_debug(unsigned char packet[])
+#ifdef	FSP_DEBUG
+static void fsp_packet_debug(struct psmouse *psmouse, unsigned char packet[])
 {
 	static unsigned int ps2_packet_cnt;
 	static unsigned int ps2_last_second;
 	unsigned int jiffies_msec;
+	const char *packet_type = "UNKNOWN";
+	unsigned short abs_x = 0, abs_y = 0;
+
+	/* Interpret & dump the packet data. */
+	switch (packet[0] >> FSP_PKT_TYPE_SHIFT) {
+	case FSP_PKT_TYPE_ABS:
+		packet_type = "Absolute";
+		abs_x = GET_ABS_X(packet);
+		abs_y = GET_ABS_Y(packet);
+		break;
+	case FSP_PKT_TYPE_NORMAL:
+		packet_type = "Normal";
+		break;
+	case FSP_PKT_TYPE_NOTIFY:
+		packet_type = "Notify";
+		break;
+	case FSP_PKT_TYPE_NORMAL_OPC:
+		packet_type = "Normal-OPC";
+		break;
+	}
 
 	ps2_packet_cnt++;
 	jiffies_msec = jiffies_to_msecs(jiffies);
 	psmouse_dbg(psmouse,
-		    "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n",
-		    jiffies_msec, packet[0], packet[1], packet[2], packet[3]);
+		    "%08dms %s packets: %02x, %02x, %02x, %02x; "
+		    "abs_x: %d, abs_y: %d\n",
+		    jiffies_msec, packet_type,
+		    packet[0], packet[1], packet[2], packet[3], abs_x, abs_y);
 
 	if (jiffies_msec - ps2_last_second > 1000) {
 		psmouse_dbg(psmouse, "PS/2 packets/sec = %d\n", ps2_packet_cnt);
@@ -639,17 +664,29 @@
 	}
 }
 #else
-static void fsp_packet_debug(unsigned char packet[])
+static void fsp_packet_debug(struct psmouse *psmouse, unsigned char packet[])
 {
 }
 #endif
 
+static void fsp_set_slot(struct input_dev *dev, int slot, bool active,
+			 unsigned int x, unsigned int y)
+{
+	input_mt_slot(dev, slot);
+	input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
+	if (active) {
+		input_report_abs(dev, ABS_MT_POSITION_X, x);
+		input_report_abs(dev, ABS_MT_POSITION_Y, y);
+	}
+}
+
 static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
 {
 	struct input_dev *dev = psmouse->dev;
 	struct fsp_data *ad = psmouse->private;
 	unsigned char *packet = psmouse->packet;
 	unsigned char button_status = 0, lscroll = 0, rscroll = 0;
+	unsigned short abs_x, abs_y, fgrs = 0;
 	int rel_x, rel_y;
 
 	if (psmouse->pktcnt < 4)
@@ -659,16 +696,76 @@
 	 * Full packet accumulated, process it
 	 */
 
+	fsp_packet_debug(psmouse, packet);
+
 	switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) {
 	case FSP_PKT_TYPE_ABS:
-		dev_warn(&psmouse->ps2dev.serio->dev,
-			 "Unexpected absolute mode packet, ignored.\n");
+		abs_x = GET_ABS_X(packet);
+		abs_y = GET_ABS_Y(packet);
+
+		if (packet[0] & FSP_PB0_MFMC) {
+			/*
+			 * MFMC packet: assume that there are two fingers on
+			 * pad
+			 */
+			fgrs = 2;
+
+			/* MFMC packet */
+			if (packet[0] & FSP_PB0_MFMC_FGR2) {
+				/* 2nd finger */
+				if (ad->last_mt_fgr == 2) {
+					/*
+					 * workaround for buggy firmware
+					 * which doesn't clear MFMC bit if
+					 * the 1st finger is up
+					 */
+					fgrs = 1;
+					fsp_set_slot(dev, 0, false, 0, 0);
+				}
+				ad->last_mt_fgr = 2;
+
+				fsp_set_slot(dev, 1, fgrs == 2, abs_x, abs_y);
+			} else {
+				/* 1st finger */
+				if (ad->last_mt_fgr == 1) {
+					/*
+					 * workaround for buggy firmware
+					 * which doesn't clear MFMC bit if
+					 * the 2nd finger is up
+					 */
+					fgrs = 1;
+					fsp_set_slot(dev, 1, false, 0, 0);
+				}
+				ad->last_mt_fgr = 1;
+				fsp_set_slot(dev, 0, fgrs != 0, abs_x, abs_y);
+			}
+		} else {
+			/* SFAC packet */
+
+			/* no multi-finger information */
+			ad->last_mt_fgr = 0;
+
+			if (abs_x != 0 && abs_y != 0)
+				fgrs = 1;
+
+			fsp_set_slot(dev, 0, fgrs > 0, abs_x, abs_y);
+			fsp_set_slot(dev, 1, false, 0, 0);
+		}
+		if (fgrs > 0) {
+			input_report_abs(dev, ABS_X, abs_x);
+			input_report_abs(dev, ABS_Y, abs_y);
+		}
+		input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
+		input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+		input_report_key(dev, BTN_TOUCH, fgrs);
+		input_report_key(dev, BTN_TOOL_FINGER, fgrs == 1);
+		input_report_key(dev, BTN_TOOL_DOUBLETAP, fgrs == 2);
 		break;
 
 	case FSP_PKT_TYPE_NORMAL_OPC:
 		/* on-pad click, filter it if necessary */
 		if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC)
-			packet[0] &= ~BIT(0);
+			packet[0] &= ~FSP_PB0_LBTN;
 		/* fall through */
 
 	case FSP_PKT_TYPE_NORMAL:
@@ -715,8 +812,6 @@
 
 	input_sync(dev);
 
-	fsp_packet_debug(packet);
-
 	return PSMOUSE_FULL_PACKET;
 }
 
@@ -740,43 +835,107 @@
 
 	ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
 	if (param[0] != 0x04) {
-		dev_err(&psmouse->ps2dev.serio->dev,
-			"Unable to enable 4 bytes packet format.\n");
+		psmouse_err(psmouse,
+			    "Unable to enable 4 bytes packet format.\n");
 		return -EIO;
 	}
 
-	if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) {
-		dev_err(&psmouse->ps2dev.serio->dev,
-			"Unable to read SYSCTL5 register.\n");
-		return -EIO;
+	if (pad->ver < FSP_VER_STL3888_C0) {
+		/* Preparing relative coordinates output for older hardware */
+		if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) {
+			psmouse_err(psmouse,
+				    "Unable to read SYSCTL5 register.\n");
+			return -EIO;
+		}
+
+		if (fsp_get_buttons(psmouse, &pad->buttons)) {
+			psmouse_err(psmouse,
+				    "Unable to retrieve number of buttons.\n");
+			return -EIO;
+		}
+
+		val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8);
+		/* Ensure we are not in absolute mode */
+		val &= ~FSP_BIT_EN_PKT_G0;
+		if (pad->buttons == 0x06) {
+			/* Left/Middle/Right & Scroll Up/Down/Right/Left */
+			val |= FSP_BIT_EN_MSID6;
+		}
+
+		if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) {
+			psmouse_err(psmouse,
+				    "Unable to set up required mode bits.\n");
+			return -EIO;
+		}
+
+		/*
+		 * Enable OPC tags such that driver can tell the difference
+		 * between on-pad and real button click
+		 */
+		if (fsp_opc_tag_enable(psmouse, true))
+			psmouse_warn(psmouse,
+				     "Failed to enable OPC tag mode.\n");
+		/* enable on-pad click by default */
+		pad->flags |= FSPDRV_FLAG_EN_OPC;
+
+		/* Enable on-pad vertical and horizontal scrolling */
+		fsp_onpad_vscr(psmouse, true);
+		fsp_onpad_hscr(psmouse, true);
+	} else {
+		/* Enable absolute coordinates output for Cx/Dx hardware */
+		if (fsp_reg_write(psmouse, FSP_REG_SWC1,
+				  FSP_BIT_SWC1_EN_ABS_1F |
+				  FSP_BIT_SWC1_EN_ABS_2F |
+				  FSP_BIT_SWC1_EN_FUP_OUT |
+				  FSP_BIT_SWC1_EN_ABS_CON)) {
+			psmouse_err(psmouse,
+				    "Unable to enable absolute coordinates output.\n");
+			return -EIO;
+		}
 	}
 
-	val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8);
-	/* Ensure we are not in absolute mode */
-	val &= ~FSP_BIT_EN_PKT_G0;
-	if (pad->buttons == 0x06) {
-		/* Left/Middle/Right & Scroll Up/Down/Right/Left */
-		val |= FSP_BIT_EN_MSID6;
+	return 0;
+}
+
+static int fsp_set_input_params(struct psmouse *psmouse)
+{
+	struct input_dev *dev = psmouse->dev;
+	struct fsp_data *pad = psmouse->private;
+
+	if (pad->ver < FSP_VER_STL3888_C0) {
+		__set_bit(BTN_MIDDLE, dev->keybit);
+		__set_bit(BTN_BACK, dev->keybit);
+		__set_bit(BTN_FORWARD, dev->keybit);
+		__set_bit(REL_WHEEL, dev->relbit);
+		__set_bit(REL_HWHEEL, dev->relbit);
+	} else {
+		/*
+		 * Hardware prior to Cx performs much better in relative mode;
+		 * hence, only enable absolute coordinates output as well as
+		 * multi-touch output for the newer hardware.
+		 *
+		 * Maximum coordinates can be computed as:
+		 *
+		 *	number of scanlines * 64 - 57
+		 *
+		 * where number of X/Y scanline lines are 16/12.
+		 */
+		int abs_x = 967, abs_y = 711;
+
+		__set_bit(EV_ABS, dev->evbit);
+		__clear_bit(EV_REL, dev->evbit);
+		__set_bit(BTN_TOUCH, dev->keybit);
+		__set_bit(BTN_TOOL_FINGER, dev->keybit);
+		__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
+		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
+
+		input_set_abs_params(dev, ABS_X, 0, abs_x, 0, 0);
+		input_set_abs_params(dev, ABS_Y, 0, abs_y, 0, 0);
+		input_mt_init_slots(dev, 2);
+		input_set_abs_params(dev, ABS_MT_POSITION_X, 0, abs_x, 0, 0);
+		input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, abs_y, 0, 0);
 	}
 
-	if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) {
-		dev_err(&psmouse->ps2dev.serio->dev,
-			"Unable to set up required mode bits.\n");
-		return -EIO;
-	}
-
-	/*
-	 * Enable OPC tags such that driver can tell the difference between
-	 * on-pad and real button click
-	 */
-	if (fsp_opc_tag_enable(psmouse, true))
-		dev_warn(&psmouse->ps2dev.serio->dev,
-			 "Failed to enable OPC tag mode.\n");
-
-	/* Enable on-pad vertical and horizontal scrolling */
-	fsp_onpad_vscr(psmouse, true);
-	fsp_onpad_hscr(psmouse, true);
-
 	return 0;
 }
 
@@ -833,18 +992,16 @@
 int fsp_init(struct psmouse *psmouse)
 {
 	struct fsp_data *priv;
-	int ver, rev, buttons;
+	int ver, rev;
 	int error;
 
 	if (fsp_get_version(psmouse, &ver) ||
-	    fsp_get_revision(psmouse, &rev) ||
-	    fsp_get_buttons(psmouse, &buttons)) {
+	    fsp_get_revision(psmouse, &rev)) {
 		return -ENODEV;
 	}
 
-	psmouse_info(psmouse,
-		     "Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n",
-		     ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7);
+	psmouse_info(psmouse, "Finger Sensing Pad, hw: %d.%d.%d, sw: %s\n",
+		     ver >> 4, ver & 0x0F, rev, fsp_drv_ver);
 
 	psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL);
 	if (!priv)
@@ -852,17 +1009,6 @@
 
 	priv->ver = ver;
 	priv->rev = rev;
-	priv->buttons = buttons;
-
-	/* enable on-pad click by default */
-	priv->flags |= FSPDRV_FLAG_EN_OPC;
-
-	/* Set up various supported input event bits */
-	__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
-	__set_bit(BTN_BACK, psmouse->dev->keybit);
-	__set_bit(BTN_FORWARD, psmouse->dev->keybit);
-	__set_bit(REL_WHEEL, psmouse->dev->relbit);
-	__set_bit(REL_HWHEEL, psmouse->dev->relbit);
 
 	psmouse->protocol_handler = fsp_process_byte;
 	psmouse->disconnect = fsp_disconnect;
@@ -870,16 +1016,20 @@
 	psmouse->cleanup = fsp_reset;
 	psmouse->pktsize = 4;
 
-	/* set default packet output based on number of buttons we found */
 	error = fsp_activate_protocol(psmouse);
 	if (error)
 		goto err_out;
 
+	/* Set up various supported input event bits */
+	error = fsp_set_input_params(psmouse);
+	if (error)
+		goto err_out;
+
 	error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
 				   &fsp_attribute_group);
 	if (error) {
-		dev_err(&psmouse->ps2dev.serio->dev,
-			"Failed to create sysfs attributes (%d)", error);
+		psmouse_err(psmouse,
+			    "Failed to create sysfs attributes (%d)", error);
 		goto err_out;
 	}
 
diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h
index 2e4af24..334de19 100644
--- a/drivers/input/mouse/sentelic.h
+++ b/drivers/input/mouse/sentelic.h
@@ -2,7 +2,7 @@
  * Finger Sensing Pad PS/2 mouse driver.
  *
  * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
- * Copyright (C) 2005-2011 Tai-hwa Liang, Sentelic Corporation.
+ * Copyright (C) 2005-2012 Tai-hwa Liang, Sentelic Corporation.
  *
  *   This program is free software; you can redistribute it and/or
  *   modify it under the terms of the GNU General Public License
@@ -55,6 +55,16 @@
 #define	FSP_BIT_FIX_HSCR	BIT(5)
 #define	FSP_BIT_DRAG_LOCK	BIT(6)
 
+#define	FSP_REG_SWC1		(0x90)
+#define	FSP_BIT_SWC1_EN_ABS_1F	BIT(0)
+#define	FSP_BIT_SWC1_EN_GID	BIT(1)
+#define	FSP_BIT_SWC1_EN_ABS_2F	BIT(2)
+#define	FSP_BIT_SWC1_EN_FUP_OUT	BIT(3)
+#define	FSP_BIT_SWC1_EN_ABS_CON	BIT(4)
+#define	FSP_BIT_SWC1_GST_GRP0	BIT(5)
+#define	FSP_BIT_SWC1_GST_GRP1	BIT(6)
+#define	FSP_BIT_SWC1_BX_COMPAT	BIT(7)
+
 /* Finger-sensing Pad packet formating related definitions */
 
 /* absolute packet type */
@@ -64,12 +74,32 @@
 #define	FSP_PKT_TYPE_NORMAL_OPC	(0x03)
 #define	FSP_PKT_TYPE_SHIFT	(6)
 
+/* bit definitions for the first byte of report packet */
+#define	FSP_PB0_LBTN		BIT(0)
+#define	FSP_PB0_RBTN		BIT(1)
+#define	FSP_PB0_MBTN		BIT(2)
+#define	FSP_PB0_MFMC_FGR2	FSP_PB0_MBTN
+#define	FSP_PB0_MUST_SET	BIT(3)
+#define	FSP_PB0_PHY_BTN		BIT(4)
+#define	FSP_PB0_MFMC		BIT(5)
+
+/* hardware revisions */
+#define	FSP_VER_STL3888_A4	(0xC1)
+#define	FSP_VER_STL3888_B0	(0xD0)
+#define	FSP_VER_STL3888_B1	(0xD1)
+#define	FSP_VER_STL3888_B2	(0xD2)
+#define	FSP_VER_STL3888_C0	(0xE0)
+#define	FSP_VER_STL3888_C1	(0xE1)
+#define	FSP_VER_STL3888_D0	(0xE2)
+#define	FSP_VER_STL3888_D1	(0xE3)
+#define	FSP_VER_STL3888_E0	(0xE4)
+
 #ifdef __KERNEL__
 
 struct fsp_data {
 	unsigned char	ver;		/* hardware version */
 	unsigned char	rev;		/* hardware revison */
-	unsigned char	buttons;	/* Number of buttons */
+	unsigned int	buttons;	/* Number of buttons */
 	unsigned int	flags;
 #define	FSPDRV_FLAG_EN_OPC	(0x001)	/* enable on-pad clicking */
 
@@ -78,6 +108,7 @@
 
 	unsigned char	last_reg;	/* Last register we requested read from */
 	unsigned char	last_val;
+	unsigned int	last_mt_fgr;	/* Last seen finger(multitouch) */
 };
 
 #ifdef CONFIG_MOUSE_PS2_SENTELIC
diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c
index 1c58aaf..f1467570 100644
--- a/drivers/input/mouse/synaptics_i2c.c
+++ b/drivers/input/mouse/synaptics_i2c.c
@@ -672,18 +672,7 @@
 	.id_table	= synaptics_i2c_id_table,
 };
 
-static int __init synaptics_i2c_init(void)
-{
-	return i2c_add_driver(&synaptics_i2c_driver);
-}
-
-static void __exit synaptics_i2c_exit(void)
-{
-	i2c_del_driver(&synaptics_i2c_driver);
-}
-
-module_init(synaptics_i2c_init);
-module_exit(synaptics_i2c_exit);
+module_i2c_driver(synaptics_i2c_driver);
 
 MODULE_DESCRIPTION("Synaptics I2C touchpad driver");
 MODULE_AUTHOR("Mike Rapoport, Igor Grinberg, Compulab");
diff --git a/drivers/input/mouse/synaptics_usb.c b/drivers/input/mouse/synaptics_usb.c
new file mode 100644
index 0000000..3c5eaaa
--- /dev/null
+++ b/drivers/input/mouse/synaptics_usb.c
@@ -0,0 +1,557 @@
+/*
+ * USB Synaptics device driver
+ *
+ *  Copyright (c) 2002 Rob Miller (rob@inpharmatica . co . uk)
+ *  Copyright (c) 2003 Ron Lee (ron@debian.org)
+ *	cPad driver for kernel 2.4
+ *
+ *  Copyright (c) 2004 Jan Steinhoff (cpad@jan-steinhoff . de)
+ *  Copyright (c) 2004 Ron Lee (ron@debian.org)
+ *	rewritten for kernel 2.6
+ *
+ *  cPad display character device part is not included. It can be found at
+ *  http://jan-steinhoff.de/linux/synaptics-usb.html
+ *
+ * Bases on:	usb_skeleton.c v2.2 by Greg Kroah-Hartman
+ *		drivers/hid/usbhid/usbmouse.c by Vojtech Pavlik
+ *		drivers/input/mouse/synaptics.c by Peter Osterlund
+ *
+ * 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.
+ *
+ * Trademarks are the property of their respective owners.
+ */
+
+/*
+ * There are three different types of Synaptics USB devices: Touchpads,
+ * touchsticks (or trackpoints), and touchscreens. Touchpads are well supported
+ * by this driver, touchstick support has not been tested much yet, and
+ * touchscreens have not been tested at all.
+ *
+ * Up to three alternate settings are possible:
+ *	setting 0: one int endpoint for relative movement (used by usbhid.ko)
+ *	setting 1: one int endpoint for absolute finger position
+ *	setting 2 (cPad only): one int endpoint for absolute finger position and
+ *		   two bulk endpoints for the display (in/out)
+ * This driver uses setting 1.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/usb.h>
+#include <linux/input.h>
+#include <linux/usb/input.h>
+
+#define USB_VENDOR_ID_SYNAPTICS	0x06cb
+#define USB_DEVICE_ID_SYNAPTICS_TP	0x0001	/* Synaptics USB TouchPad */
+#define USB_DEVICE_ID_SYNAPTICS_INT_TP	0x0002	/* Integrated USB TouchPad */
+#define USB_DEVICE_ID_SYNAPTICS_CPAD	0x0003	/* Synaptics cPad */
+#define USB_DEVICE_ID_SYNAPTICS_TS	0x0006	/* Synaptics TouchScreen */
+#define USB_DEVICE_ID_SYNAPTICS_STICK	0x0007	/* Synaptics USB Styk */
+#define USB_DEVICE_ID_SYNAPTICS_WP	0x0008	/* Synaptics USB WheelPad */
+#define USB_DEVICE_ID_SYNAPTICS_COMP_TP	0x0009	/* Composite USB TouchPad */
+#define USB_DEVICE_ID_SYNAPTICS_WTP	0x0010	/* Wireless TouchPad */
+#define USB_DEVICE_ID_SYNAPTICS_DPAD	0x0013	/* DisplayPad */
+
+#define SYNUSB_TOUCHPAD			(1 << 0)
+#define SYNUSB_STICK			(1 << 1)
+#define SYNUSB_TOUCHSCREEN		(1 << 2)
+#define SYNUSB_AUXDISPLAY		(1 << 3) /* For cPad */
+#define SYNUSB_COMBO			(1 << 4) /* Composite device (TP + stick) */
+#define SYNUSB_IO_ALWAYS		(1 << 5)
+
+#define USB_DEVICE_SYNAPTICS(prod, kind)		\
+	USB_DEVICE(USB_VENDOR_ID_SYNAPTICS,		\
+		   USB_DEVICE_ID_SYNAPTICS_##prod),	\
+	.driver_info = (kind),
+
+#define SYNUSB_RECV_SIZE	8
+
+#define XMIN_NOMINAL		1472
+#define XMAX_NOMINAL		5472
+#define YMIN_NOMINAL		1408
+#define YMAX_NOMINAL		4448
+
+struct synusb {
+	struct usb_device *udev;
+	struct usb_interface *intf;
+	struct urb *urb;
+	unsigned char *data;
+
+	/* input device related data structures */
+	struct input_dev *input;
+	char name[128];
+	char phys[64];
+
+	/* characteristics of the device */
+	unsigned long flags;
+};
+
+static void synusb_report_buttons(struct synusb *synusb)
+{
+	struct input_dev *input_dev = synusb->input;
+
+	input_report_key(input_dev, BTN_LEFT, synusb->data[1] & 0x04);
+	input_report_key(input_dev, BTN_RIGHT, synusb->data[1] & 0x01);
+	input_report_key(input_dev, BTN_MIDDLE, synusb->data[1] & 0x02);
+}
+
+static void synusb_report_stick(struct synusb *synusb)
+{
+	struct input_dev *input_dev = synusb->input;
+	int x, y;
+	unsigned int pressure;
+
+	pressure = synusb->data[6];
+	x = (s16)(be16_to_cpup((__be16 *)&synusb->data[2]) << 3) >> 7;
+	y = (s16)(be16_to_cpup((__be16 *)&synusb->data[4]) << 3) >> 7;
+
+	if (pressure > 0) {
+		input_report_rel(input_dev, REL_X, x);
+		input_report_rel(input_dev, REL_Y, -y);
+	}
+
+	input_report_abs(input_dev, ABS_PRESSURE, pressure);
+
+	synusb_report_buttons(synusb);
+
+	input_sync(input_dev);
+}
+
+static void synusb_report_touchpad(struct synusb *synusb)
+{
+	struct input_dev *input_dev = synusb->input;
+	unsigned int num_fingers, tool_width;
+	unsigned int x, y;
+	unsigned int pressure, w;
+
+	pressure = synusb->data[6];
+	x = be16_to_cpup((__be16 *)&synusb->data[2]);
+	y = be16_to_cpup((__be16 *)&synusb->data[4]);
+	w = synusb->data[0] & 0x0f;
+
+	if (pressure > 0) {
+		num_fingers = 1;
+		tool_width = 5;
+		switch (w) {
+		case 0 ... 1:
+			num_fingers = 2 + w;
+			break;
+
+		case 2:	                /* pen, pretend its a finger */
+			break;
+
+		case 4 ... 15:
+			tool_width = w;
+			break;
+		}
+	} else {
+		num_fingers = 0;
+		tool_width = 0;
+	}
+
+	/*
+	 * Post events
+	 * BTN_TOUCH has to be first as mousedev relies on it when doing
+	 * absolute -> relative conversion
+	 */
+
+	if (pressure > 30)
+		input_report_key(input_dev, BTN_TOUCH, 1);
+	if (pressure < 25)
+		input_report_key(input_dev, BTN_TOUCH, 0);
+
+	if (num_fingers > 0) {
+		input_report_abs(input_dev, ABS_X, x);
+		input_report_abs(input_dev, ABS_Y,
+				 YMAX_NOMINAL + YMIN_NOMINAL - y);
+	}
+
+	input_report_abs(input_dev, ABS_PRESSURE, pressure);
+	input_report_abs(input_dev, ABS_TOOL_WIDTH, tool_width);
+
+	input_report_key(input_dev, BTN_TOOL_FINGER, num_fingers == 1);
+	input_report_key(input_dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
+	input_report_key(input_dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
+
+	synusb_report_buttons(synusb);
+	if (synusb->flags & SYNUSB_AUXDISPLAY)
+		input_report_key(input_dev, BTN_MIDDLE, synusb->data[1] & 0x08);
+
+	input_sync(input_dev);
+}
+
+static void synusb_irq(struct urb *urb)
+{
+	struct synusb *synusb = urb->context;
+	int error;
+
+	/* Check our status in case we need to bail out early. */
+	switch (urb->status) {
+	case 0:
+		usb_mark_last_busy(synusb->udev);
+		break;
+
+	/* Device went away so don't keep trying to read from it. */
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+
+	default:
+		goto resubmit;
+		break;
+	}
+
+	if (synusb->flags & SYNUSB_STICK)
+		synusb_report_stick(synusb);
+	else
+		synusb_report_touchpad(synusb);
+
+resubmit:
+	error = usb_submit_urb(urb, GFP_ATOMIC);
+	if (error && error != -EPERM)
+		dev_err(&synusb->intf->dev,
+			"%s - usb_submit_urb failed with result: %d",
+			__func__, error);
+}
+
+static struct usb_endpoint_descriptor *
+synusb_get_in_endpoint(struct usb_host_interface *iface)
+{
+
+	struct usb_endpoint_descriptor *endpoint;
+	int i;
+
+	for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
+		endpoint = &iface->endpoint[i].desc;
+
+		if (usb_endpoint_is_int_in(endpoint)) {
+			/* we found our interrupt in endpoint */
+			return endpoint;
+		}
+	}
+
+	return NULL;
+}
+
+static int synusb_open(struct input_dev *dev)
+{
+	struct synusb *synusb = input_get_drvdata(dev);
+	int retval;
+
+	retval = usb_autopm_get_interface(synusb->intf);
+	if (retval) {
+		dev_err(&synusb->intf->dev,
+			"%s - usb_autopm_get_interface failed, error: %d\n",
+			__func__, retval);
+		return retval;
+	}
+
+	retval = usb_submit_urb(synusb->urb, GFP_KERNEL);
+	if (retval) {
+		dev_err(&synusb->intf->dev,
+			"%s - usb_submit_urb failed, error: %d\n",
+			__func__, retval);
+		retval = -EIO;
+		goto out;
+	}
+
+	synusb->intf->needs_remote_wakeup = 1;
+
+out:
+	usb_autopm_put_interface(synusb->intf);
+	return retval;
+}
+
+static void synusb_close(struct input_dev *dev)
+{
+	struct synusb *synusb = input_get_drvdata(dev);
+	int autopm_error;
+
+	autopm_error = usb_autopm_get_interface(synusb->intf);
+
+	usb_kill_urb(synusb->urb);
+	synusb->intf->needs_remote_wakeup = 0;
+
+	if (!autopm_error)
+		usb_autopm_put_interface(synusb->intf);
+}
+
+static int synusb_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct usb_endpoint_descriptor *ep;
+	struct synusb *synusb;
+	struct input_dev *input_dev;
+	unsigned int intf_num = intf->cur_altsetting->desc.bInterfaceNumber;
+	unsigned int altsetting = min(intf->num_altsetting, 1U);
+	int error;
+
+	error = usb_set_interface(udev, intf_num, altsetting);
+	if (error) {
+		dev_err(&udev->dev,
+			"Can not set alternate setting to %i, error: %i",
+			altsetting, error);
+		return error;
+	}
+
+	ep = synusb_get_in_endpoint(intf->cur_altsetting);
+	if (!ep)
+		return -ENODEV;
+
+	synusb = kzalloc(sizeof(*synusb), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!synusb || !input_dev) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	synusb->udev = udev;
+	synusb->intf = intf;
+	synusb->input = input_dev;
+
+	synusb->flags = id->driver_info;
+	if (synusb->flags & SYNUSB_COMBO) {
+		/*
+		 * This is a combo device, we need to set proper
+		 * capability, depending on the interface.
+		 */
+		synusb->flags |= intf_num == 1 ?
+					SYNUSB_STICK : SYNUSB_TOUCHPAD;
+	}
+
+	synusb->urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!synusb->urb) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	synusb->data = usb_alloc_coherent(udev, SYNUSB_RECV_SIZE, GFP_KERNEL,
+					  &synusb->urb->transfer_dma);
+	if (!synusb->data) {
+		error = -ENOMEM;
+		goto err_free_urb;
+	}
+
+	usb_fill_int_urb(synusb->urb, udev,
+			 usb_rcvintpipe(udev, ep->bEndpointAddress),
+			 synusb->data, SYNUSB_RECV_SIZE,
+			 synusb_irq, synusb,
+			 ep->bInterval);
+	synusb->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	if (udev->manufacturer)
+		strlcpy(synusb->name, udev->manufacturer,
+			sizeof(synusb->name));
+
+	if (udev->product) {
+		if (udev->manufacturer)
+			strlcat(synusb->name, " ", sizeof(synusb->name));
+		strlcat(synusb->name, udev->product, sizeof(synusb->name));
+	}
+
+	if (!strlen(synusb->name))
+		snprintf(synusb->name, sizeof(synusb->name),
+			 "USB Synaptics Device %04x:%04x",
+			 le16_to_cpu(udev->descriptor.idVendor),
+			 le16_to_cpu(udev->descriptor.idProduct));
+
+	if (synusb->flags & SYNUSB_STICK)
+		strlcat(synusb->name, " (Stick) ", sizeof(synusb->name));
+
+	usb_make_path(udev, synusb->phys, sizeof(synusb->phys));
+	strlcat(synusb->phys, "/input0", sizeof(synusb->phys));
+
+	input_dev->name = synusb->name;
+	input_dev->phys = synusb->phys;
+	usb_to_input_id(udev, &input_dev->id);
+	input_dev->dev.parent = &synusb->intf->dev;
+
+	if (!(synusb->flags & SYNUSB_IO_ALWAYS)) {
+		input_dev->open = synusb_open;
+		input_dev->close = synusb_close;
+	}
+
+	input_set_drvdata(input_dev, synusb);
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(EV_KEY, input_dev->evbit);
+
+	if (synusb->flags & SYNUSB_STICK) {
+		__set_bit(EV_REL, input_dev->evbit);
+		__set_bit(REL_X, input_dev->relbit);
+		__set_bit(REL_Y, input_dev->relbit);
+		input_set_abs_params(input_dev, ABS_PRESSURE, 0, 127, 0, 0);
+	} else {
+		input_set_abs_params(input_dev, ABS_X,
+				     XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
+		input_set_abs_params(input_dev, ABS_Y,
+				     YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
+		input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0);
+		input_set_abs_params(input_dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
+		__set_bit(BTN_TOUCH, input_dev->keybit);
+		__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+		__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+		__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
+	}
+
+	__set_bit(BTN_LEFT, input_dev->keybit);
+	__set_bit(BTN_RIGHT, input_dev->keybit);
+	__set_bit(BTN_MIDDLE, input_dev->keybit);
+
+	usb_set_intfdata(intf, synusb);
+
+	if (synusb->flags & SYNUSB_IO_ALWAYS) {
+		error = synusb_open(input_dev);
+		if (error)
+			goto err_free_dma;
+	}
+
+	error = input_register_device(input_dev);
+	if (error) {
+		dev_err(&udev->dev,
+			"Failed to register input device, error %d\n",
+			error);
+		goto err_stop_io;
+	}
+
+	return 0;
+
+err_stop_io:
+	if (synusb->flags & SYNUSB_IO_ALWAYS)
+		synusb_close(synusb->input);
+err_free_dma:
+	usb_free_coherent(udev, SYNUSB_RECV_SIZE, synusb->data,
+			  synusb->urb->transfer_dma);
+err_free_urb:
+	usb_free_urb(synusb->urb);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(synusb);
+	usb_set_intfdata(intf, NULL);
+
+	return error;
+}
+
+static void synusb_disconnect(struct usb_interface *intf)
+{
+	struct synusb *synusb = usb_get_intfdata(intf);
+	struct usb_device *udev = interface_to_usbdev(intf);
+
+	if (synusb->flags & SYNUSB_IO_ALWAYS)
+		synusb_close(synusb->input);
+
+	input_unregister_device(synusb->input);
+
+	usb_free_coherent(udev, SYNUSB_RECV_SIZE, synusb->data,
+			  synusb->urb->transfer_dma);
+	usb_free_urb(synusb->urb);
+	kfree(synusb);
+
+	usb_set_intfdata(intf, NULL);
+}
+
+static int synusb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct synusb *synusb = usb_get_intfdata(intf);
+	struct input_dev *input_dev = synusb->input;
+
+	mutex_lock(&input_dev->mutex);
+	usb_kill_urb(synusb->urb);
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
+
+static int synusb_resume(struct usb_interface *intf)
+{
+	struct synusb *synusb = usb_get_intfdata(intf);
+	struct input_dev *input_dev = synusb->input;
+	int retval = 0;
+
+	mutex_lock(&input_dev->mutex);
+
+	if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
+	    usb_submit_urb(synusb->urb, GFP_NOIO) < 0) {
+		retval = -EIO;
+	}
+
+	mutex_unlock(&input_dev->mutex);
+
+	return retval;
+}
+
+static int synusb_pre_reset(struct usb_interface *intf)
+{
+	struct synusb *synusb = usb_get_intfdata(intf);
+	struct input_dev *input_dev = synusb->input;
+
+	mutex_lock(&input_dev->mutex);
+	usb_kill_urb(synusb->urb);
+
+	return 0;
+}
+
+static int synusb_post_reset(struct usb_interface *intf)
+{
+	struct synusb *synusb = usb_get_intfdata(intf);
+	struct input_dev *input_dev = synusb->input;
+	int retval = 0;
+
+	if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
+	    usb_submit_urb(synusb->urb, GFP_NOIO) < 0) {
+		retval = -EIO;
+	}
+
+	mutex_unlock(&input_dev->mutex);
+
+	return retval;
+}
+
+static int synusb_reset_resume(struct usb_interface *intf)
+{
+	return synusb_resume(intf);
+}
+
+static struct usb_device_id synusb_idtable[] = {
+	{ USB_DEVICE_SYNAPTICS(TP, SYNUSB_TOUCHPAD) },
+	{ USB_DEVICE_SYNAPTICS(INT_TP, SYNUSB_TOUCHPAD) },
+	{ USB_DEVICE_SYNAPTICS(CPAD,
+		SYNUSB_TOUCHPAD | SYNUSB_AUXDISPLAY | SYNUSB_IO_ALWAYS) },
+	{ USB_DEVICE_SYNAPTICS(TS, SYNUSB_TOUCHSCREEN) },
+	{ USB_DEVICE_SYNAPTICS(STICK, SYNUSB_STICK) },
+	{ USB_DEVICE_SYNAPTICS(WP, SYNUSB_TOUCHPAD) },
+	{ USB_DEVICE_SYNAPTICS(COMP_TP, SYNUSB_COMBO) },
+	{ USB_DEVICE_SYNAPTICS(WTP, SYNUSB_TOUCHPAD) },
+	{ USB_DEVICE_SYNAPTICS(DPAD, SYNUSB_TOUCHPAD) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, synusb_idtable);
+
+static struct usb_driver synusb_driver = {
+	.name		= "synaptics_usb",
+	.probe		= synusb_probe,
+	.disconnect	= synusb_disconnect,
+	.id_table	= synusb_idtable,
+	.suspend	= synusb_suspend,
+	.resume		= synusb_resume,
+	.pre_reset	= synusb_pre_reset,
+	.post_reset	= synusb_post_reset,
+	.reset_resume	= synusb_reset_resume,
+	.supports_autosuspend = 1,
+};
+
+module_usb_driver(synusb_driver);
+
+MODULE_AUTHOR("Rob Miller <rob@inpharmatica.co.uk>, "
+              "Ron Lee <ron@debian.org>, "
+              "Jan Steinhoff <cpad@jan-steinhoff.de>");
+MODULE_DESCRIPTION("Synaptics USB device driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/of_keymap.c b/drivers/input/of_keymap.c
new file mode 100644
index 0000000..061493d
--- /dev/null
+++ b/drivers/input/of_keymap.c
@@ -0,0 +1,87 @@
+/*
+ * Helpers for open firmware matrix keyboard bindings
+ *
+ * Copyright (C) 2012 Google, Inc
+ *
+ * Author:
+ *	Olof Johansson <olof@lixom.net>
+ *
+ * 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/kernel.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/of.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/export.h>
+#include <linux/gfp.h>
+#include <linux/slab.h>
+
+struct matrix_keymap_data *
+matrix_keyboard_of_fill_keymap(struct device_node *np,
+			       const char *propname)
+{
+	struct matrix_keymap_data *kd;
+	u32 *keymap;
+	int proplen, i;
+	const __be32 *prop;
+
+	if (!np)
+		return NULL;
+
+	if (!propname)
+		propname = "linux,keymap";
+
+	prop = of_get_property(np, propname, &proplen);
+	if (!prop)
+		return NULL;
+
+	if (proplen % sizeof(u32)) {
+		pr_warn("Malformed keymap property %s in %s\n",
+			propname, np->full_name);
+		return NULL;
+	}
+
+	kd = kzalloc(sizeof(*kd), GFP_KERNEL);
+	if (!kd)
+		return NULL;
+
+	kd->keymap = keymap = kzalloc(proplen, GFP_KERNEL);
+	if (!kd->keymap) {
+		kfree(kd);
+		return NULL;
+	}
+
+	kd->keymap_size = proplen / sizeof(u32);
+
+	for (i = 0; i < kd->keymap_size; i++) {
+		u32 tmp = be32_to_cpup(prop + i);
+		int key_code, row, col;
+
+		row = (tmp >> 24) & 0xff;
+		col = (tmp >> 16) & 0xff;
+		key_code = tmp & 0xffff;
+		keymap[i] = KEY(row, col, key_code);
+	}
+
+	return kd;
+}
+EXPORT_SYMBOL_GPL(matrix_keyboard_of_fill_keymap);
+
+void matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd)
+{
+	if (kd) {
+		kfree(kd->keymap);
+		kfree(kd);
+	}
+}
+EXPORT_SYMBOL_GPL(matrix_keyboard_of_free_keymap);
diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c
index 35864c6..cc11f4e 100644
--- a/drivers/input/serio/altera_ps2.c
+++ b/drivers/input/serio/altera_ps2.c
@@ -180,8 +180,6 @@
 	{},
 };
 MODULE_DEVICE_TABLE(of, altera_ps2_match);
-#else /* CONFIG_OF */
-#define altera_ps2_match NULL
 #endif /* CONFIG_OF */
 
 /*
@@ -193,7 +191,7 @@
 	.driver	= {
 		.name	= DRV_NAME,
 		.owner	= THIS_MODULE,
-		.of_match_table = altera_ps2_match,
+		.of_match_table = of_match_ptr(altera_ps2_match),
 	},
 };
 module_platform_driver(altera_ps2_driver);
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
index 8407d5b..2ffd110 100644
--- a/drivers/input/serio/ambakmi.c
+++ b/drivers/input/serio/ambakmi.c
@@ -208,18 +208,7 @@
 	.resume		= amba_kmi_resume,
 };
 
-static int __init amba_kmi_init(void)
-{
-	return amba_driver_register(&ambakmi_driver);
-}
-
-static void __exit amba_kmi_exit(void)
-{
-	amba_driver_unregister(&ambakmi_driver);
-}
-
-module_init(amba_kmi_init);
-module_exit(amba_kmi_exit);
+module_amba_driver(ambakmi_driver);
 
 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 MODULE_DESCRIPTION("AMBA KMI controller driver");
diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c
index d4d08bd..f5fbdf9 100644
--- a/drivers/input/serio/ams_delta_serio.c
+++ b/drivers/input/serio/ams_delta_serio.c
@@ -92,8 +92,7 @@
 static int ams_delta_serio_open(struct serio *serio)
 {
 	/* enable keyboard */
-	ams_delta_latch2_write(AMD_DELTA_LATCH2_KEYBRD_PWR,
-			AMD_DELTA_LATCH2_KEYBRD_PWR);
+	gpio_set_value(AMS_DELTA_GPIO_PIN_KEYBRD_PWR, 1);
 
 	return 0;
 }
@@ -101,9 +100,32 @@
 static void ams_delta_serio_close(struct serio *serio)
 {
 	/* disable keyboard */
-	ams_delta_latch2_write(AMD_DELTA_LATCH2_KEYBRD_PWR, 0);
+	gpio_set_value(AMS_DELTA_GPIO_PIN_KEYBRD_PWR, 0);
 }
 
+static const struct gpio ams_delta_gpios[] __initconst_or_module = {
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_KEYBRD_DATA,
+		.flags	= GPIOF_DIR_IN,
+		.label	= "serio-data",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_KEYBRD_CLK,
+		.flags	= GPIOF_DIR_IN,
+		.label	= "serio-clock",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_KEYBRD_PWR,
+		.flags	= GPIOF_OUT_INIT_LOW,
+		.label	= "serio-power",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_KEYBRD_DATAOUT,
+		.flags	= GPIOF_OUT_INIT_LOW,
+		.label	= "serio-dataout",
+	},
+};
+
 static int __init ams_delta_serio_init(void)
 {
 	int err;
@@ -123,19 +145,12 @@
 	strlcpy(ams_delta_serio->phys, "GPIO/serio0",
 			sizeof(ams_delta_serio->phys));
 
-	err = gpio_request(AMS_DELTA_GPIO_PIN_KEYBRD_DATA, "serio-data");
+	err = gpio_request_array(ams_delta_gpios,
+				ARRAY_SIZE(ams_delta_gpios));
 	if (err) {
-		pr_err("ams_delta_serio: Couldn't request gpio pin for data\n");
+		pr_err("ams_delta_serio: Couldn't request gpio pins\n");
 		goto serio;
 	}
-	gpio_direction_input(AMS_DELTA_GPIO_PIN_KEYBRD_DATA);
-
-	err = gpio_request(AMS_DELTA_GPIO_PIN_KEYBRD_CLK, "serio-clock");
-	if (err) {
-		pr_err("ams_delta_serio: couldn't request gpio pin for clock\n");
-		goto gpio_data;
-	}
-	gpio_direction_input(AMS_DELTA_GPIO_PIN_KEYBRD_CLK);
 
 	err = request_irq(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK),
 			ams_delta_serio_interrupt, IRQ_TYPE_EDGE_RISING,
@@ -143,7 +158,7 @@
 	if (err < 0) {
 		pr_err("ams_delta_serio: couldn't request gpio interrupt %d\n",
 				gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK));
-		goto gpio_clk;
+		goto gpio;
 	}
 	/*
 	 * Since GPIO register handling for keyboard clock pin is performed
@@ -157,10 +172,9 @@
 	dev_info(&ams_delta_serio->dev, "%s\n", ams_delta_serio->name);
 
 	return 0;
-gpio_clk:
-	gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_CLK);
-gpio_data:
-	gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_DATA);
+gpio:
+	gpio_free_array(ams_delta_gpios,
+			ARRAY_SIZE(ams_delta_gpios));
 serio:
 	kfree(ams_delta_serio);
 	return err;
@@ -170,8 +184,8 @@
 static void __exit ams_delta_serio_exit(void)
 {
 	serio_unregister_port(ams_delta_serio);
-	free_irq(OMAP_GPIO_IRQ(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 0);
-	gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_CLK);
-	gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_DATA);
+	free_irq(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 0);
+	gpio_free_array(ams_delta_gpios,
+			ARRAY_SIZE(ams_delta_gpios));
 }
 module_exit(ams_delta_serio_exit);
diff --git a/drivers/input/serio/at32psif.c b/drivers/input/serio/at32psif.c
index 95280f9..36e799c 100644
--- a/drivers/input/serio/at32psif.c
+++ b/drivers/input/serio/at32psif.c
@@ -98,9 +98,9 @@
 	struct serio		*io;
 	void __iomem		*regs;
 	unsigned int		irq;
-	unsigned int		open;
 	/* Prevent concurrent writes to PSIF THR. */
 	spinlock_t		lock;
+	bool			open;
 };
 
 static irqreturn_t psif_interrupt(int irq, void *_ptr)
@@ -164,7 +164,7 @@
 	psif_writel(psif, CR, PSIF_BIT(CR_TXEN) | PSIF_BIT(CR_RXEN));
 	psif_writel(psif, IER, PSIF_BIT(RXRDY));
 
-	psif->open = 1;
+	psif->open = true;
 out:
 	return retval;
 }
@@ -173,7 +173,7 @@
 {
 	struct psif *psif = io->port_data;
 
-	psif->open = 0;
+	psif->open = false;
 
 	psif_writel(psif, IDR, ~0UL);
 	psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS));
@@ -319,9 +319,10 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int psif_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int psif_suspend(struct device *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
 	struct psif *psif = platform_get_drvdata(pdev);
 
 	if (psif->open) {
@@ -332,8 +333,9 @@
 	return 0;
 }
 
-static int psif_resume(struct platform_device *pdev)
+static int psif_resume(struct device *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
 	struct psif *psif = platform_get_drvdata(pdev);
 
 	if (psif->open) {
@@ -344,19 +346,17 @@
 
 	return 0;
 }
-#else
-#define psif_suspend	NULL
-#define psif_resume	NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(psif_pm_ops, psif_suspend, psif_resume);
+
 static struct platform_driver psif_driver = {
 	.remove		= __exit_p(psif_remove),
 	.driver		= {
 		.name	= "atmel_psif",
 		.owner	= THIS_MODULE,
+		.pm	= &psif_pm_ops,
 	},
-	.suspend	= psif_suspend,
-	.resume		= psif_resume,
 };
 
 static int __init psif_init(void)
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index be33160..09a0899 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -71,7 +71,6 @@
 #include <linux/slab.h>
 #include <linux/hil.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 /* Machine-specific abstraction */
 
diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c
index 558200e..61da763 100644
--- a/drivers/input/serio/maceps2.c
+++ b/drivers/input/serio/maceps2.c
@@ -21,7 +21,6 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/ip32/mace.h>
 #include <asm/ip32/ip32_ints.h>
 
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
index 5eb84b3..0c0df7f 100644
--- a/drivers/input/serio/q40kbd.c
+++ b/drivers/input/serio/q40kbd.c
@@ -44,26 +44,31 @@
 #include <asm/irq.h>
 #include <asm/q40ints.h>
 
+#define DRV_NAME	"q40kbd"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
 
-static DEFINE_SPINLOCK(q40kbd_lock);
-static struct serio *q40kbd_port;
-static struct platform_device *q40kbd_device;
+struct q40kbd {
+	struct serio *port;
+	spinlock_t lock;
+};
 
 static irqreturn_t q40kbd_interrupt(int irq, void *dev_id)
 {
+	struct q40kbd *q40kbd = dev_id;
 	unsigned long flags;
 
-	spin_lock_irqsave(&q40kbd_lock, flags);
+	spin_lock_irqsave(&q40kbd->lock, flags);
 
 	if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))
-		serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0);
+		serio_interrupt(q40kbd->port, master_inb(KEYCODE_REG), 0);
 
 	master_outb(-1, KEYBOARD_UNLOCK_REG);
 
-	spin_unlock_irqrestore(&q40kbd_lock, flags);
+	spin_unlock_irqrestore(&q40kbd->lock, flags);
 
 	return IRQ_HANDLED;
 }
@@ -72,17 +77,23 @@
  * q40kbd_flush() flushes all data that may be in the keyboard buffers
  */
 
-static void q40kbd_flush(void)
+static void q40kbd_flush(struct q40kbd *q40kbd)
 {
 	int maxread = 100;
 	unsigned long flags;
 
-	spin_lock_irqsave(&q40kbd_lock, flags);
+	spin_lock_irqsave(&q40kbd->lock, flags);
 
 	while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)))
 		master_inb(KEYCODE_REG);
 
-	spin_unlock_irqrestore(&q40kbd_lock, flags);
+	spin_unlock_irqrestore(&q40kbd->lock, flags);
+}
+
+static void q40kbd_stop(void)
+{
+	master_outb(0, KEY_IRQ_ENABLE_REG);
+	master_outb(-1, KEYBOARD_UNLOCK_REG);
 }
 
 /*
@@ -92,12 +103,9 @@
 
 static int q40kbd_open(struct serio *port)
 {
-	q40kbd_flush();
+	struct q40kbd *q40kbd = port->port_data;
 
-	if (request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL)) {
-		printk(KERN_ERR "q40kbd.c: Can't get irq %d.\n", Q40_IRQ_KEYBOARD);
-		return -EBUSY;
-	}
+	q40kbd_flush(q40kbd);
 
 	/* off we go */
 	master_outb(-1, KEYBOARD_UNLOCK_REG);
@@ -108,36 +116,72 @@
 
 static void q40kbd_close(struct serio *port)
 {
-	master_outb(0, KEY_IRQ_ENABLE_REG);
-	master_outb(-1, KEYBOARD_UNLOCK_REG);
-	free_irq(Q40_IRQ_KEYBOARD, NULL);
+	struct q40kbd *q40kbd = port->port_data;
 
-	q40kbd_flush();
+	q40kbd_stop();
+	q40kbd_flush(q40kbd);
 }
 
-static int __devinit q40kbd_probe(struct platform_device *dev)
+static int __devinit q40kbd_probe(struct platform_device *pdev)
 {
-	q40kbd_port = kzalloc(sizeof(struct serio), GFP_KERNEL);
-	if (!q40kbd_port)
-		return -ENOMEM;
+	struct q40kbd *q40kbd;
+	struct serio *port;
+	int error;
 
-	q40kbd_port->id.type	= SERIO_8042;
-	q40kbd_port->open	= q40kbd_open;
-	q40kbd_port->close	= q40kbd_close;
-	q40kbd_port->dev.parent	= &dev->dev;
-	strlcpy(q40kbd_port->name, "Q40 Kbd Port", sizeof(q40kbd_port->name));
-	strlcpy(q40kbd_port->phys, "Q40", sizeof(q40kbd_port->phys));
+	q40kbd = kzalloc(sizeof(struct q40kbd), GFP_KERNEL);
+	port = kzalloc(sizeof(struct serio), GFP_KERNEL);
+	if (!q40kbd || !port) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
 
-	serio_register_port(q40kbd_port);
+	q40kbd->port = port;
+	spin_lock_init(&q40kbd->lock);
+
+	port->id.type = SERIO_8042;
+	port->open = q40kbd_open;
+	port->close = q40kbd_close;
+	port->port_data = q40kbd;
+	port->dev.parent = &pdev->dev;
+	strlcpy(port->name, "Q40 Kbd Port", sizeof(port->name));
+	strlcpy(port->phys, "Q40", sizeof(port->phys));
+
+	q40kbd_stop();
+
+	error = request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0,
+			    DRV_NAME, q40kbd);
+	if (error) {
+		dev_err(&pdev->dev, "Can't get irq %d.\n", Q40_IRQ_KEYBOARD);
+		goto err_free_mem;
+	}
+
+	serio_register_port(q40kbd->port);
+
+	platform_set_drvdata(pdev, q40kbd);
 	printk(KERN_INFO "serio: Q40 kbd registered\n");
 
 	return 0;
+
+err_free_mem:
+	kfree(port);
+	kfree(q40kbd);
+	return error;
 }
 
-static int __devexit q40kbd_remove(struct platform_device *dev)
+static int __devexit q40kbd_remove(struct platform_device *pdev)
 {
-	serio_unregister_port(q40kbd_port);
+	struct q40kbd *q40kbd = platform_get_drvdata(pdev);
 
+	/*
+	 * q40kbd_close() will be called as part of unregistering
+	 * and will ensure that IRQ is turned off, so it is safe
+	 * to unregister port first and free IRQ later.
+	 */
+	serio_unregister_port(q40kbd->port);
+	free_irq(Q40_IRQ_KEYBOARD, q40kbd);
+	kfree(q40kbd);
+
+	platform_set_drvdata(pdev, NULL);
 	return 0;
 }
 
@@ -146,41 +190,16 @@
 		.name	= "q40kbd",
 		.owner	= THIS_MODULE,
 	},
-	.probe		= q40kbd_probe,
 	.remove		= __devexit_p(q40kbd_remove),
 };
 
 static int __init q40kbd_init(void)
 {
-	int error;
-
-	if (!MACH_IS_Q40)
-		return -ENODEV;
-
-	error = platform_driver_register(&q40kbd_driver);
-	if (error)
-		return error;
-
-	q40kbd_device = platform_device_alloc("q40kbd", -1);
-	if (!q40kbd_device)
-		goto err_unregister_driver;
-
-	error = platform_device_add(q40kbd_device);
-	if (error)
-		goto err_free_device;
-
-	return 0;
-
- err_free_device:
-	platform_device_put(q40kbd_device);
- err_unregister_driver:
-	platform_driver_unregister(&q40kbd_driver);
-	return error;
+	return platform_driver_probe(&q40kbd_driver, q40kbd_probe);
 }
 
 static void __exit q40kbd_exit(void)
 {
-	platform_device_unregister(q40kbd_device);
 	platform_driver_unregister(&q40kbd_driver);
 }
 
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
index 8b44ddc..2af5df6 100644
--- a/drivers/input/serio/rpckbd.c
+++ b/drivers/input/serio/rpckbd.c
@@ -36,16 +36,19 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 
-#include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/hardware/iomd.h>
-#include <asm/system.h>
 
 MODULE_AUTHOR("Vojtech Pavlik, Russell King");
 MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:kart");
 
+struct rpckbd_data {
+	int tx_irq;
+	int rx_irq;
+};
+
 static int rpckbd_write(struct serio *port, unsigned char val)
 {
 	while (!(iomd_readb(IOMD_KCTRL) & (1 << 7)))
@@ -78,19 +81,21 @@
 
 static int rpckbd_open(struct serio *port)
 {
+	struct rpckbd_data *rpckbd = port->port_data;
+
 	/* Reset the keyboard state machine. */
 	iomd_writeb(0, IOMD_KCTRL);
 	iomd_writeb(8, IOMD_KCTRL);
 	iomd_readb(IOMD_KARTRX);
 
-	if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", port) != 0) {
+	if (request_irq(rpckbd->rx_irq, rpckbd_rx, 0, "rpckbd", port) != 0) {
 		printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ\n");
 		return -EBUSY;
 	}
 
-	if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", port) != 0) {
+	if (request_irq(rpckbd->tx_irq, rpckbd_tx, 0, "rpckbd", port) != 0) {
 		printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ\n");
-		free_irq(IRQ_KEYBOARDRX, port);
+		free_irq(rpckbd->rx_irq, port);
 		return -EBUSY;
 	}
 
@@ -99,8 +104,10 @@
 
 static void rpckbd_close(struct serio *port)
 {
-	free_irq(IRQ_KEYBOARDRX, port);
-	free_irq(IRQ_KEYBOARDTX, port);
+	struct rpckbd_data *rpckbd = port->port_data;
+
+	free_irq(rpckbd->rx_irq, port);
+	free_irq(rpckbd->tx_irq, port);
 }
 
 /*
@@ -109,17 +116,35 @@
  */
 static int __devinit rpckbd_probe(struct platform_device *dev)
 {
+	struct rpckbd_data *rpckbd;
 	struct serio *serio;
+	int tx_irq, rx_irq;
+
+	rx_irq = platform_get_irq(dev, 0);
+	if (rx_irq <= 0)
+		return rx_irq < 0 ? rx_irq : -ENXIO;
+
+	tx_irq = platform_get_irq(dev, 1);
+	if (tx_irq <= 0)
+		return tx_irq < 0 ? tx_irq : -ENXIO;
 
 	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
-	if (!serio)
+	rpckbd = kzalloc(sizeof(*rpckbd), GFP_KERNEL);
+	if (!serio || !rpckbd) {
+		kfree(rpckbd);
+		kfree(serio);
 		return -ENOMEM;
+	}
+
+	rpckbd->rx_irq = rx_irq;
+	rpckbd->tx_irq = tx_irq;
 
 	serio->id.type		= SERIO_8042;
 	serio->write		= rpckbd_write;
 	serio->open		= rpckbd_open;
 	serio->close		= rpckbd_close;
 	serio->dev.parent	= &dev->dev;
+	serio->port_data	= rpckbd;
 	strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name));
 	strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys));
 
@@ -131,7 +156,11 @@
 static int __devexit rpckbd_remove(struct platform_device *dev)
 {
 	struct serio *serio = platform_get_drvdata(dev);
+	struct rpckbd_data *rpckbd = serio->port_data;
+
 	serio_unregister_port(serio);
+	kfree(rpckbd);
+
 	return 0;
 }
 
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
index 44fc8b4..3897667 100644
--- a/drivers/input/serio/sa1111ps2.c
+++ b/drivers/input/serio/sa1111ps2.c
@@ -20,10 +20,29 @@
 #include <linux/spinlock.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <asm/hardware/sa1111.h>
 
+#define PS2CR		0x0000
+#define PS2STAT		0x0004
+#define PS2DATA		0x0008
+#define PS2CLKDIV	0x000c
+#define PS2PRECNT	0x0010
+
+#define PS2CR_ENA	0x08
+#define PS2CR_FKD	0x02
+#define PS2CR_FKC	0x01
+
+#define PS2STAT_STP	0x0100
+#define PS2STAT_TXE	0x0080
+#define PS2STAT_TXB	0x0040
+#define PS2STAT_RXF	0x0020
+#define PS2STAT_RXB	0x0010
+#define PS2STAT_ENA	0x0008
+#define PS2STAT_RXP	0x0004
+#define PS2STAT_KBD	0x0002
+#define PS2STAT_KBC	0x0001
+
 struct ps2if {
 	struct serio		*io;
 	struct sa1111_dev	*dev;
@@ -45,22 +64,22 @@
 	struct ps2if *ps2if = dev_id;
 	unsigned int scancode, flag, status;
 
-	status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+	status = sa1111_readl(ps2if->base + PS2STAT);
 	while (status & PS2STAT_RXF) {
 		if (status & PS2STAT_STP)
-			sa1111_writel(PS2STAT_STP, ps2if->base + SA1111_PS2STAT);
+			sa1111_writel(PS2STAT_STP, ps2if->base + PS2STAT);
 
 		flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) |
 		       (status & PS2STAT_RXP ? 0 : SERIO_PARITY);
 
-		scancode = sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff;
+		scancode = sa1111_readl(ps2if->base + PS2DATA) & 0xff;
 
 		if (hweight8(scancode) & 1)
 			flag ^= SERIO_PARITY;
 
 		serio_interrupt(ps2if->io, scancode, flag);
 
-		status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+		status = sa1111_readl(ps2if->base + PS2STAT);
         }
 
         return IRQ_HANDLED;
@@ -75,12 +94,12 @@
 	unsigned int status;
 
 	spin_lock(&ps2if->lock);
-	status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+	status = sa1111_readl(ps2if->base + PS2STAT);
 	if (ps2if->head == ps2if->tail) {
 		disable_irq_nosync(irq);
 		/* done */
 	} else if (status & PS2STAT_TXE) {
-		sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + SA1111_PS2DATA);
+		sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + PS2DATA);
 		ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1);
 	}
 	spin_unlock(&ps2if->lock);
@@ -103,8 +122,8 @@
 	/*
 	 * If the TX register is empty, we can go straight out.
 	 */
-	if (sa1111_readl(ps2if->base + SA1111_PS2STAT) & PS2STAT_TXE) {
-		sa1111_writel(val, ps2if->base + SA1111_PS2DATA);
+	if (sa1111_readl(ps2if->base + PS2STAT) & PS2STAT_TXE) {
+		sa1111_writel(val, ps2if->base + PS2DATA);
 	} else {
 		if (ps2if->head == ps2if->tail)
 			enable_irq(ps2if->dev->irq[1]);
@@ -124,13 +143,16 @@
 	struct ps2if *ps2if = io->port_data;
 	int ret;
 
-	sa1111_enable_device(ps2if->dev);
+	ret = sa1111_enable_device(ps2if->dev);
+	if (ret)
+		return ret;
 
 	ret = request_irq(ps2if->dev->irq[0], ps2_rxint, 0,
 			  SA1111_DRIVER_NAME(ps2if->dev), ps2if);
 	if (ret) {
 		printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
 			ps2if->dev->irq[0], ret);
+		sa1111_disable_device(ps2if->dev);
 		return ret;
 	}
 
@@ -140,6 +162,7 @@
 		printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
 			ps2if->dev->irq[1], ret);
 		free_irq(ps2if->dev->irq[0], ps2if);
+		sa1111_disable_device(ps2if->dev);
 		return ret;
 	}
 
@@ -147,7 +170,7 @@
 
 	enable_irq_wake(ps2if->dev->irq[0]);
 
-	sa1111_writel(PS2CR_ENA, ps2if->base + SA1111_PS2CR);
+	sa1111_writel(PS2CR_ENA, ps2if->base + PS2CR);
 	return 0;
 }
 
@@ -155,7 +178,7 @@
 {
 	struct ps2if *ps2if = io->port_data;
 
-	sa1111_writel(0, ps2if->base + SA1111_PS2CR);
+	sa1111_writel(0, ps2if->base + PS2CR);
 
 	disable_irq_wake(ps2if->dev->irq[0]);
 
@@ -175,7 +198,7 @@
 	int maxread = 100;
 
 	while (maxread--) {
-		if ((sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff) == 0xff)
+		if ((sa1111_readl(ps2if->base + PS2DATA) & 0xff) == 0xff)
 			break;
 	}
 }
@@ -185,11 +208,11 @@
 {
 	unsigned int val;
 
-	sa1111_writel(PS2CR_ENA | mask, ps2if->base + SA1111_PS2CR);
+	sa1111_writel(PS2CR_ENA | mask, ps2if->base + PS2CR);
 
 	udelay(2);
 
-	val = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+	val = sa1111_readl(ps2if->base + PS2STAT);
 	return val & (PS2STAT_KBC | PS2STAT_KBD);
 }
 
@@ -220,7 +243,7 @@
 		ret = -ENODEV;
 	}
 
-	sa1111_writel(0, ps2if->base + SA1111_PS2CR);
+	sa1111_writel(0, ps2if->base + PS2CR);
 
 	return ret;
 }
@@ -274,8 +297,8 @@
 	sa1111_enable_device(ps2if->dev);
 
 	/* Incoming clock is 8MHz */
-	sa1111_writel(0, ps2if->base + SA1111_PS2CLKDIV);
-	sa1111_writel(127, ps2if->base + SA1111_PS2PRECNT);
+	sa1111_writel(0, ps2if->base + PS2CLKDIV);
+	sa1111_writel(127, ps2if->base + PS2PRECNT);
 
 	/*
 	 * Flush any pending input.
@@ -330,6 +353,7 @@
 static struct sa1111_driver ps2_driver = {
 	.drv = {
 		.name	= "sa1111-ps2",
+		.owner	= THIS_MODULE,
 	},
 	.devid		= SA1111_DEVID_PS2,
 	.probe		= ps2_probe,
diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig
index e53f408..bed7cbf 100644
--- a/drivers/input/tablet/Kconfig
+++ b/drivers/input/tablet/Kconfig
@@ -76,6 +76,7 @@
 config TABLET_USB_WACOM
 	tristate "Wacom Intuos/Graphire tablet support (USB)"
 	depends on USB_ARCH_HAS_HCD
+	select POWER_SUPPLY
 	select USB
 	select NEW_LEDS
 	select LEDS_CLASS
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
index 0783864..b4842d0 100644
--- a/drivers/input/tablet/wacom.h
+++ b/drivers/input/tablet/wacom.h
@@ -88,6 +88,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/init.h>
 #include <linux/usb/input.h>
+#include <linux/power_supply.h>
 #include <asm/unaligned.h>
 
 /*
@@ -112,6 +113,7 @@
 	struct urb *irq;
 	struct wacom_wac wacom_wac;
 	struct mutex lock;
+	struct work_struct work;
 	bool open;
 	char phys[32];
 	struct wacom_led {
@@ -120,8 +122,15 @@
 		u8 hlv;       /* status led brightness button pressed (1..127) */
 		u8 img_lum;   /* OLED matrix display brightness */
 	} led;
+	struct power_supply battery;
 };
 
+static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
+{
+	struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+	schedule_work(&wacom->work);
+}
+
 extern const struct usb_device_id wacom_ids[];
 
 void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 2a97b7e..0d26921 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -167,6 +167,19 @@
 		usb_autopm_put_interface(wacom->intf);
 }
 
+/*
+ * Static values for max X/Y and resolution of Pen interface is stored in
+ * features. This mean physical size of active area can be computed.
+ * This is useful to do when Pen and Touch have same active area of tablet.
+ * This means for Touch device, we only need to find max X/Y value and we
+ * have enough information to compute resolution of touch.
+ */
+static void wacom_set_phy_from_res(struct wacom_features *features)
+{
+	features->x_phy = (features->x_max * 100) / features->x_resolution;
+	features->y_phy = (features->y_max * 100) / features->y_resolution;
+}
+
 static int wacom_parse_logical_collection(unsigned char *report,
 					  struct wacom_features *features)
 {
@@ -176,17 +189,9 @@
 
 		/* Logical collection is only used by 3rd gen Bamboo Touch */
 		features->pktlen = WACOM_PKGLEN_BBTOUCH3;
-		features->device_type = BTN_TOOL_DOUBLETAP;
+		features->device_type = BTN_TOOL_FINGER;
 
-		/*
-		 * Stylus and Touch have same active area
-		 * so compute physical size based on stylus
-		 * data before its overwritten.
-		 */
-		features->x_phy =
-			(features->x_max * features->x_resolution) / 100;
-		features->y_phy =
-			(features->y_max * features->y_resolution) / 100;
+		wacom_set_phy_from_res(features);
 
 		features->x_max = features->y_max =
 			get_unaligned_le16(&report[10]);
@@ -286,12 +291,10 @@
 						if (features->type == TABLETPC2FG) {
 							/* need to reset back */
 							features->pktlen = WACOM_PKGLEN_TPC2FG;
-							features->device_type = BTN_TOOL_DOUBLETAP;
 						}
 						if (features->type == BAMBOO_PT) {
 							/* need to reset back */
 							features->pktlen = WACOM_PKGLEN_BBTOUCH;
-							features->device_type = BTN_TOOL_DOUBLETAP;
 							features->x_phy =
 								get_unaligned_le16(&report[i + 5]);
 							features->x_max =
@@ -325,7 +328,6 @@
 						if (features->type == TABLETPC2FG) {
 							/* need to reset back */
 							features->pktlen = WACOM_PKGLEN_TPC2FG;
-							features->device_type = BTN_TOOL_DOUBLETAP;
 							features->y_max =
 								get_unaligned_le16(&report[i + 3]);
 							features->y_phy =
@@ -334,7 +336,6 @@
 						} else if (features->type == BAMBOO_PT) {
 							/* need to reset back */
 							features->pktlen = WACOM_PKGLEN_BBTOUCH;
-							features->device_type = BTN_TOOL_DOUBLETAP;
 							features->y_phy =
 								get_unaligned_le16(&report[i + 3]);
 							features->y_max =
@@ -426,6 +427,7 @@
 						report_id, rep_data, 4, 1);
 		} while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES);
 	} else if (features->type != TABLETPC &&
+		   features->type != WIRELESS &&
 		   features->device_type == BTN_TOOL_PEN) {
 		do {
 			rep_data[0] = 2;
@@ -458,6 +460,21 @@
 	features->pressure_fuzz = 0;
 	features->distance_fuzz = 0;
 
+	/*
+	 * The wireless device HID is basic and layout conflicts with
+	 * other tablets (monitor and touch interface can look like pen).
+	 * Skip the query for this type and modify defaults based on
+	 * interface number.
+	 */
+	if (features->type == WIRELESS) {
+		if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
+			features->device_type = 0;
+		} else if (intf->cur_altsetting->desc.bInterfaceNumber == 2) {
+			features->device_type = BTN_TOOL_DOUBLETAP;
+			features->pktlen = WACOM_PKGLEN_BBTOUCH3;
+		}
+	}
+
 	/* only Tablet PCs and Bamboo P&T need to retrieve the info */
 	if ((features->type != TABLETPC) && (features->type != TABLETPC2FG) &&
 	    (features->type != BAMBOO_PT))
@@ -826,6 +843,152 @@
 	}
 }
 
+static enum power_supply_property wacom_battery_props[] = {
+	POWER_SUPPLY_PROP_CAPACITY
+};
+
+static int wacom_battery_get_property(struct power_supply *psy,
+				      enum power_supply_property psp,
+				      union power_supply_propval *val)
+{
+	struct wacom *wacom = container_of(psy, struct wacom, battery);
+	int ret = 0;
+
+	switch (psp) {
+		case POWER_SUPPLY_PROP_CAPACITY:
+			val->intval =
+				wacom->wacom_wac.battery_capacity * 100 / 31;
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+	}
+
+	return ret;
+}
+
+static int wacom_initialize_battery(struct wacom *wacom)
+{
+	int error = 0;
+
+	if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_MONITOR) {
+		wacom->battery.properties = wacom_battery_props;
+		wacom->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
+		wacom->battery.get_property = wacom_battery_get_property;
+		wacom->battery.name = "wacom_battery";
+		wacom->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+		wacom->battery.use_for_apm = 0;
+
+		error = power_supply_register(&wacom->usbdev->dev,
+					      &wacom->battery);
+	}
+
+	return error;
+}
+
+static void wacom_destroy_battery(struct wacom *wacom)
+{
+	if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_MONITOR)
+		power_supply_unregister(&wacom->battery);
+}
+
+static int wacom_register_input(struct wacom *wacom)
+{
+	struct input_dev *input_dev;
+	struct usb_interface *intf = wacom->intf;
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+	int error;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		return -ENOMEM;
+
+	input_dev->name = wacom_wac->name;
+	input_dev->dev.parent = &intf->dev;
+	input_dev->open = wacom_open;
+	input_dev->close = wacom_close;
+	usb_to_input_id(dev, &input_dev->id);
+	input_set_drvdata(input_dev, wacom);
+
+	wacom_wac->input = input_dev;
+	wacom_setup_input_capabilities(input_dev, wacom_wac);
+
+	error = input_register_device(input_dev);
+	if (error) {
+		input_free_device(input_dev);
+		wacom_wac->input = NULL;
+	}
+
+	return error;
+}
+
+static void wacom_wireless_work(struct work_struct *work)
+{
+	struct wacom *wacom = container_of(work, struct wacom, work);
+	struct usb_device *usbdev = wacom->usbdev;
+	struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+
+	/*
+	 * Regardless if this is a disconnect or a new tablet,
+	 * remove any existing input devices.
+	 */
+
+	/* Stylus interface */
+	wacom = usb_get_intfdata(usbdev->config->interface[1]);
+	if (wacom->wacom_wac.input)
+		input_unregister_device(wacom->wacom_wac.input);
+	wacom->wacom_wac.input = 0;
+
+	/* Touch interface */
+	wacom = usb_get_intfdata(usbdev->config->interface[2]);
+	if (wacom->wacom_wac.input)
+		input_unregister_device(wacom->wacom_wac.input);
+	wacom->wacom_wac.input = 0;
+
+	if (wacom_wac->pid == 0) {
+		printk(KERN_INFO "wacom: wireless tablet disconnected\n");
+	} else {
+		const struct usb_device_id *id = wacom_ids;
+
+		printk(KERN_INFO
+		       "wacom: wireless tablet connected with PID %x\n",
+		       wacom_wac->pid);
+
+		while (id->match_flags) {
+			if (id->idVendor == USB_VENDOR_ID_WACOM &&
+			    id->idProduct == wacom_wac->pid)
+				break;
+			id++;
+		}
+
+		if (!id->match_flags) {
+			printk(KERN_INFO
+			       "wacom: ignorning unknown PID.\n");
+			return;
+		}
+
+		/* Stylus interface */
+		wacom = usb_get_intfdata(usbdev->config->interface[1]);
+		wacom_wac = &wacom->wacom_wac;
+		wacom_wac->features =
+			*((struct wacom_features *)id->driver_info);
+		wacom_wac->features.device_type = BTN_TOOL_PEN;
+		wacom_register_input(wacom);
+
+		/* Touch interface */
+		wacom = usb_get_intfdata(usbdev->config->interface[2]);
+		wacom_wac = &wacom->wacom_wac;
+		wacom_wac->features =
+			*((struct wacom_features *)id->driver_info);
+		wacom_wac->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
+		wacom_wac->features.device_type = BTN_TOOL_FINGER;
+		wacom_set_phy_from_res(&wacom_wac->features);
+		wacom_wac->features.x_max = wacom_wac->features.y_max = 4096;
+		wacom_register_input(wacom);
+	}
+}
+
 static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
 	struct usb_device *dev = interface_to_usbdev(intf);
@@ -833,18 +996,14 @@
 	struct wacom *wacom;
 	struct wacom_wac *wacom_wac;
 	struct wacom_features *features;
-	struct input_dev *input_dev;
 	int error;
 
 	if (!id->driver_info)
 		return -EINVAL;
 
 	wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!wacom || !input_dev) {
-		error = -ENOMEM;
-		goto fail1;
-	}
+	if (!wacom)
+		return -ENOMEM;
 
 	wacom_wac = &wacom->wacom_wac;
 	wacom_wac->features = *((struct wacom_features *)id->driver_info);
@@ -870,11 +1029,10 @@
 	wacom->usbdev = dev;
 	wacom->intf = intf;
 	mutex_init(&wacom->lock);
+	INIT_WORK(&wacom->work, wacom_wireless_work);
 	usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
 	strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
 
-	wacom_wac->input = input_dev;
-
 	endpoint = &intf->cur_altsetting->endpoint[0].desc;
 
 	/* Retrieve the physical and logical size for OEM devices */
@@ -898,15 +1056,6 @@
 			goto fail3;
 	}
 
-	input_dev->name = wacom_wac->name;
-	input_dev->dev.parent = &intf->dev;
-	input_dev->open = wacom_open;
-	input_dev->close = wacom_close;
-	usb_to_input_id(dev, &input_dev->id);
-	input_set_drvdata(input_dev, wacom);
-
-	wacom_setup_input_capabilities(input_dev, wacom_wac);
-
 	usb_fill_int_urb(wacom->irq, dev,
 			 usb_rcvintpipe(dev, endpoint->bEndpointAddress),
 			 wacom_wac->data, features->pktlen,
@@ -918,22 +1067,34 @@
 	if (error)
 		goto fail4;
 
-	error = input_register_device(input_dev);
+	error = wacom_initialize_battery(wacom);
 	if (error)
 		goto fail5;
 
+	if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
+		error = wacom_register_input(wacom);
+		if (error)
+			goto fail6;
+	}
+
 	/* Note that if query fails it is not a hard failure */
 	wacom_query_tablet_data(intf, features);
 
 	usb_set_intfdata(intf, wacom);
+
+	if (features->quirks & WACOM_QUIRK_MONITOR) {
+		if (usb_submit_urb(wacom->irq, GFP_KERNEL))
+			goto fail5;
+	}
+
 	return 0;
 
+ fail6: wacom_destroy_battery(wacom);
  fail5: wacom_destroy_leds(wacom);
  fail4:	wacom_remove_shared_data(wacom_wac);
  fail3:	usb_free_urb(wacom->irq);
  fail2:	usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
- fail1:	input_free_device(input_dev);
-	kfree(wacom);
+ fail1:	kfree(wacom);
 	return error;
 }
 
@@ -944,7 +1105,10 @@
 	usb_set_intfdata(intf, NULL);
 
 	usb_kill_urb(wacom->irq);
-	input_unregister_device(wacom->wacom_wac.input);
+	cancel_work_sync(&wacom->work);
+	if (wacom->wacom_wac.input)
+		input_unregister_device(wacom->wacom_wac.input);
+	wacom_destroy_battery(wacom);
 	wacom_destroy_leds(wacom);
 	usb_free_urb(wacom->irq);
 	usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
@@ -976,7 +1140,8 @@
 	wacom_query_tablet_data(intf, features);
 	wacom_led_control(wacom);
 
-	if (wacom->open && usb_submit_urb(wacom->irq, GFP_NOIO) < 0)
+	if ((wacom->open || features->quirks & WACOM_QUIRK_MONITOR)
+	     && usb_submit_urb(wacom->irq, GFP_NOIO) < 0)
 		rv = -EIO;
 
 	mutex_unlock(&wacom->lock);
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index cd3ed29..cecd35c 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -832,12 +832,24 @@
 
 	dbg("wacom_tpc_irq: received report #%d", data[0]);
 
-	if (len == WACOM_PKGLEN_TPC1FG || data[0] == WACOM_REPORT_TPC1FG)
-		return wacom_tpc_single_touch(wacom, len);
-	else if (data[0] == WACOM_REPORT_TPC2FG)
-		return wacom_tpc_mt_touch(wacom);
-	else if (data[0] == WACOM_REPORT_PENABLED)
-		return wacom_tpc_pen(wacom);
+	switch (len) {
+	case WACOM_PKGLEN_TPC1FG:
+		 return wacom_tpc_single_touch(wacom, len);
+
+	case WACOM_PKGLEN_TPC2FG:
+ 		return wacom_tpc_mt_touch(wacom);
+
+	default:
+		switch (data[0]) {
+		case WACOM_REPORT_TPC1FG:
+		case WACOM_REPORT_TPCHID:
+		case WACOM_REPORT_TPCST:
+			return wacom_tpc_single_touch(wacom, len);
+
+		case WACOM_REPORT_PENABLED:
+			return wacom_tpc_pen(wacom);
+		}
+	}
 
 	return 0;
 }
@@ -1032,6 +1044,35 @@
 	return 0;
 }
 
+static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
+{
+	unsigned char *data = wacom->data;
+	int connected;
+
+	if (len != WACOM_PKGLEN_WIRELESS || data[0] != 0x80)
+		return 0;
+
+	connected = data[1] & 0x01;
+	if (connected) {
+		int pid, battery;
+
+		pid = get_unaligned_be16(&data[6]);
+		battery = data[5] & 0x3f;
+		if (wacom->pid != pid) {
+			wacom->pid = pid;
+			wacom_schedule_work(wacom);
+		}
+		wacom->battery_capacity = battery;
+	} else if (wacom->pid != 0) {
+		/* disconnected while previously connected */
+		wacom->pid = 0;
+		wacom_schedule_work(wacom);
+		wacom->battery_capacity = 0;
+	}
+
+	return 0;
+}
+
 void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 {
 	bool sync;
@@ -1082,6 +1123,10 @@
 		sync = wacom_bpt_irq(wacom_wac, len);
 		break;
 
+	case WIRELESS:
+		sync = wacom_wireless_irq(wacom_wac, len);
+		break;
+
 	default:
 		sync = false;
 		break;
@@ -1143,7 +1188,7 @@
 
 	/* these device have multiple inputs */
 	if (features->type == TABLETPC || features->type == TABLETPC2FG ||
-	    features->type == BAMBOO_PT)
+	    features->type == BAMBOO_PT || features->type == WIRELESS)
 		features->quirks |= WACOM_QUIRK_MULTI_INPUT;
 
 	/* quirk for bamboo touch with 2 low res touches */
@@ -1155,6 +1200,16 @@
 		features->y_fuzz <<= 5;
 		features->quirks |= WACOM_QUIRK_BBTOUCH_LOWRES;
 	}
+
+	if (features->type == WIRELESS) {
+
+		/* monitor never has input and pen/touch have delayed create */
+		features->quirks |= WACOM_QUIRK_NO_INPUT;
+
+		/* must be monitor interface if no device_type set */
+		if (!features->device_type)
+			features->quirks |= WACOM_QUIRK_MONITOR;
+	}
 }
 
 static unsigned int wacom_calculate_touch_res(unsigned int logical_max,
@@ -1317,7 +1372,7 @@
 		break;
 
 	case TABLETPC2FG:
-		if (features->device_type == BTN_TOOL_DOUBLETAP) {
+		if (features->device_type == BTN_TOOL_FINGER) {
 
 			input_mt_init_slots(input_dev, 2);
 			input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
@@ -1366,7 +1421,7 @@
 
 		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
 
-		if (features->device_type == BTN_TOOL_DOUBLETAP) {
+		if (features->device_type == BTN_TOOL_FINGER) {
 			__set_bit(BTN_LEFT, input_dev->keybit);
 			__set_bit(BTN_FORWARD, input_dev->keybit);
 			__set_bit(BTN_BACK, input_dev->keybit);
@@ -1628,6 +1683,9 @@
 static const struct wacom_features wacom_features_0x47 =
 	{ "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023,
 	  31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x84 =
+	{ "Wacom Wireless Receiver", WACOM_PKGLEN_WIRELESS, 0, 0, 0,
+	  0, WIRELESS, 0, 0 };
 static const struct wacom_features wacom_features_0xD0 =
 	{ "Wacom Bamboo 2FG",     WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
 	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1754,6 +1812,7 @@
 	{ USB_DEVICE_DETAILED(0xCE, USB_CLASS_HID,
 			      USB_INTERFACE_SUBCLASS_BOOT,
 			      USB_INTERFACE_PROTOCOL_MOUSE) },
+	{ USB_DEVICE_WACOM(0x84) },
 	{ USB_DEVICE_WACOM(0xD0) },
 	{ USB_DEVICE_WACOM(0xD1) },
 	{ USB_DEVICE_WACOM(0xD2) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 050acae..ba5a334 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -24,6 +24,7 @@
 #define WACOM_PKGLEN_BBTOUCH	20
 #define WACOM_PKGLEN_BBTOUCH3	64
 #define WACOM_PKGLEN_BBPEN	10
+#define WACOM_PKGLEN_WIRELESS	32
 
 /* device IDs */
 #define STYLUS_DEVICE_ID	0x02
@@ -39,10 +40,14 @@
 #define WACOM_REPORT_INTUOSPAD		12
 #define WACOM_REPORT_TPC1FG		6
 #define WACOM_REPORT_TPC2FG		13
+#define WACOM_REPORT_TPCHID		15
+#define WACOM_REPORT_TPCST		16
 
 /* device quirks */
 #define WACOM_QUIRK_MULTI_INPUT		0x0001
 #define WACOM_QUIRK_BBTOUCH_LOWRES	0x0002
+#define WACOM_QUIRK_NO_INPUT		0x0004
+#define WACOM_QUIRK_MONITOR		0x0008
 
 enum {
 	PENPARTNER = 0,
@@ -52,6 +57,7 @@
 	PL,
 	DTU,
 	BAMBOO_PT,
+	WIRELESS,
 	INTUOS,
 	INTUOS3S,
 	INTUOS3,
@@ -105,6 +111,8 @@
 	struct wacom_features features;
 	struct wacom_shared *shared;
 	struct input_dev *input;
+	int pid;
+	int battery_capacity;
 };
 
 #endif
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 4af2a18..2a21419 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -139,7 +139,6 @@
 	tristate "cy8ctmg110 touchscreen"
 	depends on I2C
 	depends on GPIOLIB
-
 	help
 	  Say Y here if you have a cy8ctmg110 capacitive touchscreen on
 	  an AAVA device.
@@ -149,6 +148,37 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called cy8ctmg110_ts.
 
+config TOUCHSCREEN_CYTTSP_CORE
+	tristate "Cypress TTSP touchscreen"
+	help
+	  Say Y here if you have a touchscreen using controller from
+	  the Cypress TrueTouch(tm) Standard Product family connected
+	  to your system. You will also need to select appropriate
+	  bus connection below.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp_core.
+
+config TOUCHSCREEN_CYTTSP_I2C
+	tristate "support I2C bus connection"
+	depends on TOUCHSCREEN_CYTTSP_CORE && I2C
+	help
+	  Say Y here if the touchscreen is connected via I2C bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp_i2c.
+
+config TOUCHSCREEN_CYTTSP_SPI
+	tristate "support SPI bus connection"
+	depends on TOUCHSCREEN_CYTTSP_CORE && SPI_MASTER
+	help
+	  Say Y here if the touchscreen is connected via SPI bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp_spi.
+
 config TOUCHSCREEN_DA9034
 	tristate "Touchscreen support for Dialog Semiconductor DA9034"
 	depends on PMIC_DA903X
@@ -213,9 +243,24 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called fujitsu-ts.
 
+config TOUCHSCREEN_ILI210X
+	tristate "Ilitek ILI210X based touchscreen"
+	depends on I2C
+	help
+	  Say Y here if you have a ILI210X based touchscreen
+	  controller. This driver supports models ILI2102,
+	  ILI2102s, ILI2103, ILI2103s and ILI2105.
+	  Such kind of chipsets can be found in Amazon Kindle Fire
+	  touchscreens.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ili210x.
+
 config TOUCHSCREEN_S3C2410
 	tristate "Samsung S3C2410/generic touchscreen input driver"
-	depends on ARCH_S3C2410 || SAMSUNG_DEV_TS
+	depends on ARCH_S3C24XX || SAMSUNG_DEV_TS
 	select S3C_ADC
 	help
 	  Say Y here if you have the s3c2410 touchscreen.
@@ -430,6 +475,18 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called touchwin.
 
+config TOUCHSCREEN_TI_TSCADC
+	tristate "TI Touchscreen Interface"
+	depends on ARCH_OMAP2PLUS
+	help
+	  Say Y here if you have 4/5/8 wire touchscreen controller
+	  to be connected to the ADC controller on your TI AM335x SoC.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ti_tscadc.
+
 config TOUCHSCREEN_ATMEL_TSADCC
 	tristate "Atmel Touchscreen Interface"
 	depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
@@ -577,6 +634,7 @@
 	  - JASTEC USB Touch Controller/DigiTech DTR-02U
 	  - Zytronic controllers
 	  - Elo TouchSystems 2700 IntelliTouch
+	  - EasyTouch USB Touch Controller from Data Modul
 
 	  Have a look at <http://linux.chapter7.ch/touchkit/> for
 	  a usage description and the required user-space stuff.
@@ -681,6 +739,14 @@
 	bool "NEXIO/iNexio device support" if EXPERT
 	depends on TOUCHSCREEN_USB_COMPOSITE
 
+config TOUCHSCREEN_USB_EASYTOUCH
+	default y
+	bool "EasyTouch USB Touch controller device support" if EMBEDDED
+	depends on TOUCHSCREEN_USB_COMPOSITE
+	help
+	  Say Y here if you have a EasyTouch USB Touch controller device support.
+	  If unsure, say N.
+
 config TOUCHSCREEN_TOUCHIT213
 	tristate "Sahara TouchIT-213 touchscreen"
 	select SERIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 496091e..3d5cf8c 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -16,8 +16,11 @@
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR)	+= auo-pixcir-ts.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
-obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
+obj-$(CONFIG_TOUCHSCREEN_BU21013)	+= bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)	+= cyttsp_core.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C)	+= cyttsp_i2c.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI)	+= cyttsp_spi.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
@@ -26,6 +29,7 @@
 obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
 obj-$(CONFIG_TOUCHSCREEN_EGALAX)	+= egalax_ts.o
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ILI210X)	+= ili210x.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
 obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)	+= intel-mid-touch.o
 obj-$(CONFIG_TOUCHSCREEN_LPC32XX)	+= lpc32xx_ts.o
@@ -45,6 +49,7 @@
 obj-$(CONFIG_TOUCHSCREEN_S3C2410)	+= s3c2410_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ST1232)	+= st1232.o
 obj-$(CONFIG_TOUCHSCREEN_STMPE)		+= stmpe-ts.o
+obj-$(CONFIG_TOUCHSCREEN_TI_TSCADC)	+= ti_tscadc.o
 obj-$(CONFIG_TOUCHSCREEN_TNETV107X)	+= tnetv107x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)	+= touchit213.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)	+= touchright.o
diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c
index 49a36df..2c76921 100644
--- a/drivers/input/touchscreen/ad7877.c
+++ b/drivers/input/touchscreen/ad7877.c
@@ -860,17 +860,7 @@
 	.remove		= __devexit_p(ad7877_remove),
 };
 
-static int __init ad7877_init(void)
-{
-	return spi_register_driver(&ad7877_driver);
-}
-module_init(ad7877_init);
-
-static void __exit ad7877_exit(void)
-{
-	spi_unregister_driver(&ad7877_driver);
-}
-module_exit(ad7877_exit);
+module_spi_driver(ad7877_driver);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("AD7877 touchscreen Driver");
diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c
index 0dac671..3054354 100644
--- a/drivers/input/touchscreen/ad7879-i2c.c
+++ b/drivers/input/touchscreen/ad7879-i2c.c
@@ -102,17 +102,7 @@
 	.id_table	= ad7879_id,
 };
 
-static int __init ad7879_i2c_init(void)
-{
-	return i2c_add_driver(&ad7879_i2c_driver);
-}
-module_init(ad7879_i2c_init);
-
-static void __exit ad7879_i2c_exit(void)
-{
-	i2c_del_driver(&ad7879_i2c_driver);
-}
-module_exit(ad7879_i2c_exit);
+module_i2c_driver(ad7879_i2c_driver);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("AD7879(-1) touchscreen I2C bus driver");
diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c
index 9b2e1c2..db49abf 100644
--- a/drivers/input/touchscreen/ad7879-spi.c
+++ b/drivers/input/touchscreen/ad7879-spi.c
@@ -157,17 +157,7 @@
 	.remove		= __devexit_p(ad7879_spi_remove),
 };
 
-static int __init ad7879_spi_init(void)
-{
-	return spi_register_driver(&ad7879_spi_driver);
-}
-module_init(ad7879_spi_init);
-
-static void __exit ad7879_spi_exit(void)
-{
-	spi_unregister_driver(&ad7879_spi_driver);
-}
-module_exit(ad7879_spi_exit);
+module_spi_driver(ad7879_spi_driver);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("AD7879(-1) touchscreen SPI bus driver");
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 23fd901..f02028e 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -1433,17 +1433,7 @@
 	.remove		= __devexit_p(ads7846_remove),
 };
 
-static int __init ads7846_init(void)
-{
-	return spi_register_driver(&ads7846_driver);
-}
-module_init(ads7846_init);
-
-static void __exit ads7846_exit(void)
-{
-	spi_unregister_driver(&ads7846_driver);
-}
-module_exit(ads7846_exit);
+module_spi_driver(ads7846_driver);
 
 MODULE_DESCRIPTION("ADS7846 TouchScreen Driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c
index 8034cbb..c5c2dbb 100644
--- a/drivers/input/touchscreen/atmel-wm97xx.c
+++ b/drivers/input/touchscreen/atmel-wm97xx.c
@@ -392,9 +392,10 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int atmel_wm97xx_suspend(struct platform_device *pdev, pm_message_t msg)
+#ifdef CONFIG_PM_SLEEP
+static int atmel_wm97xx_suspend(struct *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
 	struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
 
 	ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
@@ -404,8 +405,9 @@
 	return 0;
 }
 
-static int atmel_wm97xx_resume(struct platform_device *pdev)
+static int atmel_wm97xx_resume(struct device *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
 	struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
 	struct wm97xx *wm = atmel_wm97xx->wm;
 
@@ -416,18 +418,18 @@
 
 	return 0;
 }
-#else
-#define atmel_wm97xx_suspend	NULL
-#define atmel_wm97xx_resume	NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(atmel_wm97xx_pm_ops,
+			 atmel_wm97xx_suspend, atmel_wm97xx_resume);
+
 static struct platform_driver atmel_wm97xx_driver = {
 	.remove		= __exit_p(atmel_wm97xx_remove),
 	.driver		= {
-		.name = "wm97xx-touch",
+		.name	= "wm97xx-touch",
+		.owner	= THIS_MODULE,
+		.pm	= &atmel_wm97xx_pm_ops,
 	},
-	.suspend	= atmel_wm97xx_suspend,
-	.resume		= atmel_wm97xx_resume,
 };
 
 static int __init atmel_wm97xx_init(void)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index a596c27..19d4ea6 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1267,18 +1267,7 @@
 	.id_table	= mxt_id,
 };
 
-static int __init mxt_init(void)
-{
-	return i2c_add_driver(&mxt_driver);
-}
-
-static void __exit mxt_exit(void)
-{
-	i2c_del_driver(&mxt_driver);
-}
-
-module_init(mxt_init);
-module_exit(mxt_exit);
+module_i2c_driver(mxt_driver);
 
 /* Module information */
 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c
index 94fb9fbb..c7047b6 100644
--- a/drivers/input/touchscreen/auo-pixcir-ts.c
+++ b/drivers/input/touchscreen/auo-pixcir-ts.c
@@ -635,17 +635,7 @@
 	.id_table	= auo_pixcir_idtable,
 };
 
-static int __init auo_pixcir_init(void)
-{
-	return i2c_add_driver(&auo_pixcir_driver);
-}
-module_init(auo_pixcir_init);
-
-static void __exit auo_pixcir_exit(void)
-{
-	i2c_del_driver(&auo_pixcir_driver);
-}
-module_exit(auo_pixcir_exit);
+module_i2c_driver(auo_pixcir_driver);
 
 MODULE_DESCRIPTION("AUO-PIXCIR touchscreen driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c
index 902c721..f2d03c0 100644
--- a/drivers/input/touchscreen/bu21013_ts.c
+++ b/drivers/input/touchscreen/bu21013_ts.c
@@ -652,30 +652,7 @@
 	.id_table	=	bu21013_id,
 };
 
-/**
- * bu21013_init() - initializes the bu21013 touchscreen driver
- *
- * This function used to initializes the bu21013
- * touchscreen driver and returns integer.
- */
-static int __init bu21013_init(void)
-{
-	return i2c_add_driver(&bu21013_driver);
-}
-
-/**
- * bu21013_exit() - de-initializes the bu21013 touchscreen driver
- *
- * This function uses to de-initializes the bu21013
- * touchscreen driver and returns none.
- */
-static void __exit bu21013_exit(void)
-{
-	i2c_del_driver(&bu21013_driver);
-}
-
-module_init(bu21013_init);
-module_exit(bu21013_exit);
+module_i2c_driver(bu21013_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Naveen Kumar G <naveen.gaddipati@stericsson.com>");
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c
index d8815c5..237753a 100644
--- a/drivers/input/touchscreen/cy8ctmg110_ts.c
+++ b/drivers/input/touchscreen/cy8ctmg110_ts.c
@@ -350,18 +350,7 @@
 	.remove		= __devexit_p(cy8ctmg110_remove),
 };
 
-static int __init cy8ctmg110_init(void)
-{
-	return i2c_add_driver(&cy8ctmg110_driver);
-}
-
-static void __exit cy8ctmg110_exit(void)
-{
-	i2c_del_driver(&cy8ctmg110_driver);
-}
-
-module_init(cy8ctmg110_init);
-module_exit(cy8ctmg110_exit);
+module_i2c_driver(cy8ctmg110_driver);
 
 MODULE_AUTHOR("Samuli Konttila <samuli.konttila@aavamobile.com>");
 MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver");
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
new file mode 100644
index 0000000..f030d9e
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -0,0 +1,625 @@
+/*
+ * Core Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+#include "cyttsp_core.h"
+
+/* Bootloader number of command keys */
+#define CY_NUM_BL_KEYS		8
+
+/* helpers */
+#define GET_NUM_TOUCHES(x)		((x) & 0x0F)
+#define IS_LARGE_AREA(x)		(((x) & 0x10) >> 4)
+#define IS_BAD_PKT(x)			((x) & 0x20)
+#define IS_VALID_APP(x)			((x) & 0x01)
+#define IS_OPERATIONAL_ERR(x)		((x) & 0x3F)
+#define GET_HSTMODE(reg)		(((reg) & 0x70) >> 4)
+#define GET_BOOTLOADERMODE(reg)		(((reg) & 0x10) >> 4)
+
+#define CY_REG_BASE			0x00
+#define CY_REG_ACT_DIST			0x1E
+#define CY_REG_ACT_INTRVL		0x1D
+#define CY_REG_TCH_TMOUT		(CY_REG_ACT_INTRVL + 1)
+#define CY_REG_LP_INTRVL		(CY_REG_TCH_TMOUT + 1)
+#define CY_MAXZ				255
+#define CY_DELAY_DFLT			20 /* ms */
+#define CY_DELAY_MAX			500
+#define CY_ACT_DIST_DFLT		0xF8
+#define CY_HNDSHK_BIT			0x80
+/* device mode bits */
+#define CY_OPERATE_MODE			0x00
+#define CY_SYSINFO_MODE			0x10
+/* power mode select bits */
+#define CY_SOFT_RESET_MODE		0x01 /* return to Bootloader mode */
+#define CY_DEEP_SLEEP_MODE		0x02
+#define CY_LOW_POWER_MODE		0x04
+
+/* Slots management */
+#define CY_MAX_FINGER			4
+#define CY_MAX_ID			16
+
+static const u8 bl_command[] = {
+	0x00,			/* file offset */
+	0xFF,			/* command */
+	0xA5,			/* exit bootloader command */
+	0, 1, 2, 3, 4, 5, 6, 7	/* default keys */
+};
+
+static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
+				u8 length, void *buf)
+{
+	int error;
+	int tries;
+
+	for (tries = 0; tries < CY_NUM_RETRY; tries++) {
+		error = ts->bus_ops->read(ts, command, length, buf);
+		if (!error)
+			return 0;
+
+		msleep(CY_DELAY_DFLT);
+	}
+
+	return -EIO;
+}
+
+static int ttsp_write_block_data(struct cyttsp *ts, u8 command,
+				 u8 length, void *buf)
+{
+	int error;
+	int tries;
+
+	for (tries = 0; tries < CY_NUM_RETRY; tries++) {
+		error = ts->bus_ops->write(ts, command, length, buf);
+		if (!error)
+			return 0;
+
+		msleep(CY_DELAY_DFLT);
+	}
+
+	return -EIO;
+}
+
+static int ttsp_send_command(struct cyttsp *ts, u8 cmd)
+{
+	return ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+}
+
+static int cyttsp_load_bl_regs(struct cyttsp *ts)
+{
+	memset(&ts->bl_data, 0, sizeof(ts->bl_data));
+	ts->bl_data.bl_status = 0x10;
+
+	return ttsp_read_block_data(ts, CY_REG_BASE,
+				    sizeof(ts->bl_data), &ts->bl_data);
+}
+
+static int cyttsp_exit_bl_mode(struct cyttsp *ts)
+{
+	int error;
+	u8 bl_cmd[sizeof(bl_command)];
+
+	memcpy(bl_cmd, bl_command, sizeof(bl_command));
+	if (ts->pdata->bl_keys)
+		memcpy(&bl_cmd[sizeof(bl_command) - CY_NUM_BL_KEYS],
+			ts->pdata->bl_keys, sizeof(bl_command));
+
+	error = ttsp_write_block_data(ts, CY_REG_BASE,
+				      sizeof(bl_cmd), bl_cmd);
+	if (error)
+		return error;
+
+	/* wait for TTSP Device to complete the operation */
+	msleep(CY_DELAY_DFLT);
+
+	error = cyttsp_load_bl_regs(ts);
+	if (error)
+		return error;
+
+	if (GET_BOOTLOADERMODE(ts->bl_data.bl_status))
+		return -EIO;
+
+	return 0;
+}
+
+static int cyttsp_set_operational_mode(struct cyttsp *ts)
+{
+	int error;
+
+	error = ttsp_send_command(ts, CY_OPERATE_MODE);
+	if (error)
+		return error;
+
+	/* wait for TTSP Device to complete switch to Operational mode */
+	error = ttsp_read_block_data(ts, CY_REG_BASE,
+				     sizeof(ts->xy_data), &ts->xy_data);
+	if (error)
+		return error;
+
+	return ts->xy_data.act_dist == CY_ACT_DIST_DFLT ? -EIO : 0;
+}
+
+static int cyttsp_set_sysinfo_mode(struct cyttsp *ts)
+{
+	int error;
+
+	memset(&ts->sysinfo_data, 0, sizeof(ts->sysinfo_data));
+
+	/* switch to sysinfo mode */
+	error = ttsp_send_command(ts, CY_SYSINFO_MODE);
+	if (error)
+		return error;
+
+	/* read sysinfo registers */
+	msleep(CY_DELAY_DFLT);
+	error = ttsp_read_block_data(ts, CY_REG_BASE, sizeof(ts->sysinfo_data),
+				      &ts->sysinfo_data);
+	if (error)
+		return error;
+
+	if (!ts->sysinfo_data.tts_verh && !ts->sysinfo_data.tts_verl)
+		return -EIO;
+
+	return 0;
+}
+
+static int cyttsp_set_sysinfo_regs(struct cyttsp *ts)
+{
+	int retval = 0;
+
+	if (ts->pdata->act_intrvl != CY_ACT_INTRVL_DFLT ||
+	    ts->pdata->tch_tmout != CY_TCH_TMOUT_DFLT ||
+	    ts->pdata->lp_intrvl != CY_LP_INTRVL_DFLT) {
+
+		u8 intrvl_ray[] = {
+			ts->pdata->act_intrvl,
+			ts->pdata->tch_tmout,
+			ts->pdata->lp_intrvl
+		};
+
+		/* set intrvl registers */
+		retval = ttsp_write_block_data(ts, CY_REG_ACT_INTRVL,
+					sizeof(intrvl_ray), intrvl_ray);
+		msleep(CY_DELAY_DFLT);
+	}
+
+	return retval;
+}
+
+static int cyttsp_soft_reset(struct cyttsp *ts)
+{
+	unsigned long timeout;
+	int retval;
+
+	/* wait for interrupt to set ready completion */
+	INIT_COMPLETION(ts->bl_ready);
+	ts->state = CY_BL_STATE;
+
+	enable_irq(ts->irq);
+
+	retval = ttsp_send_command(ts, CY_SOFT_RESET_MODE);
+	if (retval)
+		goto out;
+
+	timeout = wait_for_completion_timeout(&ts->bl_ready,
+			msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX));
+	retval = timeout ? 0 : -EIO;
+
+out:
+	ts->state = CY_IDLE_STATE;
+	disable_irq(ts->irq);
+	return retval;
+}
+
+static int cyttsp_act_dist_setup(struct cyttsp *ts)
+{
+	u8 act_dist_setup = ts->pdata->act_dist;
+
+	/* Init gesture; active distance setup */
+	return ttsp_write_block_data(ts, CY_REG_ACT_DIST,
+				sizeof(act_dist_setup), &act_dist_setup);
+}
+
+static void cyttsp_extract_track_ids(struct cyttsp_xydata *xy_data, int *ids)
+{
+	ids[0] = xy_data->touch12_id >> 4;
+	ids[1] = xy_data->touch12_id & 0xF;
+	ids[2] = xy_data->touch34_id >> 4;
+	ids[3] = xy_data->touch34_id & 0xF;
+}
+
+static const struct cyttsp_tch *cyttsp_get_tch(struct cyttsp_xydata *xy_data,
+					       int idx)
+{
+	switch (idx) {
+	case 0:
+		return &xy_data->tch1;
+	case 1:
+		return &xy_data->tch2;
+	case 2:
+		return &xy_data->tch3;
+	case 3:
+		return &xy_data->tch4;
+	default:
+		return NULL;
+	}
+}
+
+static void cyttsp_report_tchdata(struct cyttsp *ts)
+{
+	struct cyttsp_xydata *xy_data = &ts->xy_data;
+	struct input_dev *input = ts->input;
+	int num_tch = GET_NUM_TOUCHES(xy_data->tt_stat);
+	const struct cyttsp_tch *tch;
+	int ids[CY_MAX_ID];
+	int i;
+	DECLARE_BITMAP(used, CY_MAX_ID);
+
+	if (IS_LARGE_AREA(xy_data->tt_stat) == 1) {
+		/* terminate all active tracks */
+		num_tch = 0;
+		dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
+	} else if (num_tch > CY_MAX_FINGER) {
+		/* terminate all active tracks */
+		num_tch = 0;
+		dev_dbg(ts->dev, "%s: Num touch error detected\n", __func__);
+	} else if (IS_BAD_PKT(xy_data->tt_mode)) {
+		/* terminate all active tracks */
+		num_tch = 0;
+		dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__);
+	}
+
+	cyttsp_extract_track_ids(xy_data, ids);
+
+	bitmap_zero(used, CY_MAX_ID);
+
+	for (i = 0; i < num_tch; i++) {
+		tch = cyttsp_get_tch(xy_data, i);
+
+		input_mt_slot(input, ids[i]);
+		input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+		input_report_abs(input, ABS_MT_POSITION_X, be16_to_cpu(tch->x));
+		input_report_abs(input, ABS_MT_POSITION_Y, be16_to_cpu(tch->y));
+		input_report_abs(input, ABS_MT_TOUCH_MAJOR, tch->z);
+
+		__set_bit(ids[i], used);
+	}
+
+	for (i = 0; i < CY_MAX_ID; i++) {
+		if (test_bit(i, used))
+			continue;
+
+		input_mt_slot(input, i);
+		input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
+	}
+
+	input_sync(input);
+}
+
+static irqreturn_t cyttsp_irq(int irq, void *handle)
+{
+	struct cyttsp *ts = handle;
+	int error;
+
+	if (unlikely(ts->state == CY_BL_STATE)) {
+		complete(&ts->bl_ready);
+		goto out;
+	}
+
+	/* Get touch data from CYTTSP device */
+	error = ttsp_read_block_data(ts, CY_REG_BASE,
+				 sizeof(struct cyttsp_xydata), &ts->xy_data);
+	if (error)
+		goto out;
+
+	/* provide flow control handshake */
+	if (ts->pdata->use_hndshk) {
+		error = ttsp_send_command(ts,
+				ts->xy_data.hst_mode ^ CY_HNDSHK_BIT);
+		if (error)
+			goto out;
+	}
+
+	if (unlikely(ts->state == CY_IDLE_STATE))
+		goto out;
+
+	if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
+		/*
+		 * TTSP device has reset back to bootloader mode.
+		 * Restore to operational mode.
+		 */
+		error = cyttsp_exit_bl_mode(ts);
+		if (error) {
+			dev_err(ts->dev,
+				"Could not return to operational mode, err: %d\n",
+				error);
+			ts->state = CY_IDLE_STATE;
+		}
+	} else {
+		cyttsp_report_tchdata(ts);
+	}
+
+out:
+	return IRQ_HANDLED;
+}
+
+static int cyttsp_power_on(struct cyttsp *ts)
+{
+	int error;
+
+	error = cyttsp_soft_reset(ts);
+	if (error)
+		return error;
+
+	error = cyttsp_load_bl_regs(ts);
+	if (error)
+		return error;
+
+	if (GET_BOOTLOADERMODE(ts->bl_data.bl_status) &&
+	    IS_VALID_APP(ts->bl_data.bl_status)) {
+		error = cyttsp_exit_bl_mode(ts);
+		if (error)
+			return error;
+	}
+
+	if (GET_HSTMODE(ts->bl_data.bl_file) != CY_OPERATE_MODE ||
+	    IS_OPERATIONAL_ERR(ts->bl_data.bl_status)) {
+		return -ENODEV;
+	}
+
+	error = cyttsp_set_sysinfo_mode(ts);
+	if (error)
+		return error;
+
+	error = cyttsp_set_sysinfo_regs(ts);
+	if (error)
+		return error;
+
+	error = cyttsp_set_operational_mode(ts);
+	if (error)
+		return error;
+
+	/* init active distance */
+	error = cyttsp_act_dist_setup(ts);
+	if (error)
+		return error;
+
+	ts->state = CY_ACTIVE_STATE;
+
+	return 0;
+}
+
+static int cyttsp_enable(struct cyttsp *ts)
+{
+	int error;
+
+	/*
+	 * The device firmware can wake on an I2C or SPI memory slave
+	 * address match. So just reading a register is sufficient to
+	 * wake up the device. The first read attempt will fail but it
+	 * will wake it up making the second read attempt successful.
+	 */
+	error = ttsp_read_block_data(ts, CY_REG_BASE,
+				     sizeof(ts->xy_data), &ts->xy_data);
+	if (error)
+		return error;
+
+	if (GET_HSTMODE(ts->xy_data.hst_mode))
+		return -EIO;
+
+	enable_irq(ts->irq);
+
+	return 0;
+}
+
+static int cyttsp_disable(struct cyttsp *ts)
+{
+	int error;
+
+	error = ttsp_send_command(ts, CY_LOW_POWER_MODE);
+	if (error)
+		return error;
+
+	disable_irq(ts->irq);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int cyttsp_suspend(struct device *dev)
+{
+	struct cyttsp *ts = dev_get_drvdata(dev);
+	int retval = 0;
+
+	mutex_lock(&ts->input->mutex);
+
+	if (ts->input->users) {
+		retval = cyttsp_disable(ts);
+		if (retval == 0)
+			ts->suspended = true;
+	}
+
+	mutex_unlock(&ts->input->mutex);
+
+	return retval;
+}
+
+static int cyttsp_resume(struct device *dev)
+{
+	struct cyttsp *ts = dev_get_drvdata(dev);
+
+	mutex_lock(&ts->input->mutex);
+
+	if (ts->input->users)
+		cyttsp_enable(ts);
+
+	ts->suspended = false;
+
+	mutex_unlock(&ts->input->mutex);
+
+	return 0;
+}
+
+#endif
+
+SIMPLE_DEV_PM_OPS(cyttsp_pm_ops, cyttsp_suspend, cyttsp_resume);
+EXPORT_SYMBOL_GPL(cyttsp_pm_ops);
+
+static int cyttsp_open(struct input_dev *dev)
+{
+	struct cyttsp *ts = input_get_drvdata(dev);
+	int retval = 0;
+
+	if (!ts->suspended)
+		retval = cyttsp_enable(ts);
+
+	return retval;
+}
+
+static void cyttsp_close(struct input_dev *dev)
+{
+	struct cyttsp *ts = input_get_drvdata(dev);
+
+	if (!ts->suspended)
+		cyttsp_disable(ts);
+}
+
+struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
+			    struct device *dev, int irq, size_t xfer_buf_size)
+{
+	const struct cyttsp_platform_data *pdata = dev->platform_data;
+	struct cyttsp *ts;
+	struct input_dev *input_dev;
+	int error;
+
+	if (!pdata || !pdata->name || irq <= 0) {
+		error = -EINVAL;
+		goto err_out;
+	}
+
+	ts = kzalloc(sizeof(*ts) + xfer_buf_size, GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ts || !input_dev) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	ts->dev = dev;
+	ts->input = input_dev;
+	ts->pdata = dev->platform_data;
+	ts->bus_ops = bus_ops;
+	ts->irq = irq;
+
+	init_completion(&ts->bl_ready);
+	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
+
+	if (pdata->init) {
+		error = pdata->init();
+		if (error) {
+			dev_err(ts->dev, "platform init failed, err: %d\n",
+				error);
+			goto err_free_mem;
+		}
+	}
+
+	input_dev->name = pdata->name;
+	input_dev->phys = ts->phys;
+	input_dev->id.bustype = bus_ops->bustype;
+	input_dev->dev.parent = ts->dev;
+
+	input_dev->open = cyttsp_open;
+	input_dev->close = cyttsp_close;
+
+	input_set_drvdata(input_dev, ts);
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+			     0, pdata->maxx, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+			     0, pdata->maxy, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+			     0, CY_MAXZ, 0, 0);
+
+	input_mt_init_slots(input_dev, CY_MAX_ID);
+
+	error = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
+				     IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				     pdata->name, ts);
+	if (error) {
+		dev_err(ts->dev, "failed to request IRQ %d, err: %d\n",
+			ts->irq, error);
+		goto err_platform_exit;
+	}
+
+	disable_irq(ts->irq);
+
+	error = cyttsp_power_on(ts);
+	if (error)
+		goto err_free_irq;
+
+	error = input_register_device(input_dev);
+	if (error) {
+		dev_err(ts->dev, "failed to register input device: %d\n",
+			error);
+		goto err_free_irq;
+	}
+
+	return ts;
+
+err_free_irq:
+	free_irq(ts->irq, ts);
+err_platform_exit:
+	if (pdata->exit)
+		pdata->exit();
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(ts);
+err_out:
+	return ERR_PTR(error);
+}
+EXPORT_SYMBOL_GPL(cyttsp_probe);
+
+void cyttsp_remove(struct cyttsp *ts)
+{
+	free_irq(ts->irq, ts);
+	input_unregister_device(ts->input);
+	if (ts->pdata->exit)
+		ts->pdata->exit();
+	kfree(ts);
+}
+EXPORT_SYMBOL_GPL(cyttsp_remove);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core");
+MODULE_AUTHOR("Cypress");
diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h
new file mode 100644
index 0000000..1aa3c69
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_core.h
@@ -0,0 +1,149 @@
+/*
+ * Header file for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+
+#ifndef __CYTTSP_CORE_H__
+#define __CYTTSP_CORE_H__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/input/cyttsp.h>
+
+#define CY_NUM_RETRY		16 /* max number of retries for read ops */
+
+struct cyttsp_tch {
+	__be16 x, y;
+	u8 z;
+} __packed;
+
+/* TrueTouch Standard Product Gen3 interface definition */
+struct cyttsp_xydata {
+	u8 hst_mode;
+	u8 tt_mode;
+	u8 tt_stat;
+	struct cyttsp_tch tch1;
+	u8 touch12_id;
+	struct cyttsp_tch tch2;
+	u8 gest_cnt;
+	u8 gest_id;
+	struct cyttsp_tch tch3;
+	u8 touch34_id;
+	struct cyttsp_tch tch4;
+	u8 tt_undef[3];
+	u8 act_dist;
+	u8 tt_reserved;
+} __packed;
+
+
+/* TTSP System Information interface definition */
+struct cyttsp_sysinfo_data {
+	u8 hst_mode;
+	u8 mfg_cmd;
+	u8 mfg_stat;
+	u8 cid[3];
+	u8 tt_undef1;
+	u8 uid[8];
+	u8 bl_verh;
+	u8 bl_verl;
+	u8 tts_verh;
+	u8 tts_verl;
+	u8 app_idh;
+	u8 app_idl;
+	u8 app_verh;
+	u8 app_verl;
+	u8 tt_undef[5];
+	u8 scn_typ;
+	u8 act_intrvl;
+	u8 tch_tmout;
+	u8 lp_intrvl;
+};
+
+/* TTSP Bootloader Register Map interface definition */
+#define CY_BL_CHKSUM_OK 0x01
+struct cyttsp_bootloader_data {
+	u8 bl_file;
+	u8 bl_status;
+	u8 bl_error;
+	u8 blver_hi;
+	u8 blver_lo;
+	u8 bld_blver_hi;
+	u8 bld_blver_lo;
+	u8 ttspver_hi;
+	u8 ttspver_lo;
+	u8 appid_hi;
+	u8 appid_lo;
+	u8 appver_hi;
+	u8 appver_lo;
+	u8 cid_0;
+	u8 cid_1;
+	u8 cid_2;
+};
+
+struct cyttsp;
+
+struct cyttsp_bus_ops {
+	u16 bustype;
+	int (*write)(struct cyttsp *ts,
+		     u8 addr, u8 length, const void *values);
+	int (*read)(struct cyttsp *ts, u8 addr, u8 length, void *values);
+};
+
+enum cyttsp_state {
+	CY_IDLE_STATE,
+	CY_ACTIVE_STATE,
+	CY_BL_STATE,
+};
+
+struct cyttsp {
+	struct device *dev;
+	int irq;
+	struct input_dev *input;
+	char phys[32];
+	const struct cyttsp_platform_data *pdata;
+	const struct cyttsp_bus_ops *bus_ops;
+	struct cyttsp_bootloader_data bl_data;
+	struct cyttsp_sysinfo_data sysinfo_data;
+	struct cyttsp_xydata xy_data;
+	struct completion bl_ready;
+	enum cyttsp_state state;
+	bool suspended;
+
+	u8 xfer_buf[] ____cacheline_aligned;
+};
+
+struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
+			    struct device *dev, int irq, size_t xfer_buf_size);
+void cyttsp_remove(struct cyttsp *ts);
+
+extern const struct dev_pm_ops cyttsp_pm_ops;
+
+#endif /* __CYTTSP_CORE_H__ */
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c
new file mode 100644
index 0000000..2af1d0c
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_i2c.c
@@ -0,0 +1,136 @@
+/*
+ * Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/i2c.h>
+#include <linux/input.h>
+
+#define CY_I2C_DATA_SIZE	128
+
+static int cyttsp_i2c_read_block_data(struct cyttsp *ts,
+				      u8 addr, u8 length, void *values)
+{
+	struct i2c_client *client = to_i2c_client(ts->dev);
+	struct i2c_msg msgs[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &addr,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = length,
+			.buf = values,
+		},
+	};
+	int retval;
+
+	retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (retval < 0)
+		return retval;
+
+	return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
+}
+
+static int cyttsp_i2c_write_block_data(struct cyttsp *ts,
+				       u8 addr, u8 length, const void *values)
+{
+	struct i2c_client *client = to_i2c_client(ts->dev);
+	int retval;
+
+	ts->xfer_buf[0] = addr;
+	memcpy(&ts->xfer_buf[1], values, length);
+
+	retval = i2c_master_send(client, ts->xfer_buf, length + 1);
+
+	return retval < 0 ? retval : 0;
+}
+
+static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = {
+	.bustype	= BUS_I2C,
+	.write		= cyttsp_i2c_write_block_data,
+	.read           = cyttsp_i2c_read_block_data,
+};
+
+static int __devinit cyttsp_i2c_probe(struct i2c_client *client,
+				      const struct i2c_device_id *id)
+{
+	struct cyttsp *ts;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "I2C functionality not Supported\n");
+		return -EIO;
+	}
+
+	ts = cyttsp_probe(&cyttsp_i2c_bus_ops, &client->dev, client->irq,
+			  CY_I2C_DATA_SIZE);
+
+	if (IS_ERR(ts))
+		return PTR_ERR(ts);
+
+	i2c_set_clientdata(client, ts);
+
+	return 0;
+}
+
+static int __devexit cyttsp_i2c_remove(struct i2c_client *client)
+{
+	struct cyttsp *ts = i2c_get_clientdata(client);
+
+	cyttsp_remove(ts);
+
+	return 0;
+}
+
+static const struct i2c_device_id cyttsp_i2c_id[] = {
+	{ CY_I2C_NAME, 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
+
+static struct i2c_driver cyttsp_i2c_driver = {
+	.driver = {
+		.name	= CY_I2C_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= &cyttsp_pm_ops,
+	},
+	.probe		= cyttsp_i2c_probe,
+	.remove		= __devexit_p(cyttsp_i2c_remove),
+	.id_table	= cyttsp_i2c_id,
+};
+
+module_i2c_driver(cyttsp_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
+MODULE_AUTHOR("Cypress");
+MODULE_ALIAS("i2c:cyttsp");
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
new file mode 100644
index 0000000..9f26341
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_spi.c
@@ -0,0 +1,200 @@
+/*
+ * Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/spi/spi.h>
+
+#define CY_SPI_WR_OP		0x00 /* r/~w */
+#define CY_SPI_RD_OP		0x01
+#define CY_SPI_CMD_BYTES	4
+#define CY_SPI_SYNC_BYTE	2
+#define CY_SPI_SYNC_ACK1	0x62 /* from protocol v.2 */
+#define CY_SPI_SYNC_ACK2	0x9D /* from protocol v.2 */
+#define CY_SPI_DATA_SIZE	128
+#define CY_SPI_DATA_BUF_SIZE	(CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
+#define CY_SPI_BITS_PER_WORD	8
+
+static int cyttsp_spi_xfer(struct cyttsp *ts,
+			   u8 op, u8 reg, u8 *buf, int length)
+{
+	struct spi_device *spi = to_spi_device(ts->dev);
+	struct spi_message msg;
+	struct spi_transfer xfer[2];
+	u8 *wr_buf = &ts->xfer_buf[0];
+	u8 *rd_buf = &ts->xfer_buf[CY_SPI_DATA_BUF_SIZE];
+	int retval;
+	int i;
+
+	if (length > CY_SPI_DATA_SIZE) {
+		dev_err(ts->dev, "%s: length %d is too big.\n",
+			__func__, length);
+		return -EINVAL;
+	}
+
+	memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE);
+	memset(rd_buf, 0, CY_SPI_DATA_BUF_SIZE);
+
+	wr_buf[0] = 0x00; /* header byte 0 */
+	wr_buf[1] = 0xFF; /* header byte 1 */
+	wr_buf[2] = reg;  /* reg index */
+	wr_buf[3] = op;   /* r/~w */
+	if (op == CY_SPI_WR_OP)
+		memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
+
+	memset(xfer, 0, sizeof(xfer));
+	spi_message_init(&msg);
+
+	/*
+	  We set both TX and RX buffers because Cypress TTSP
+	  requires full duplex operation.
+	*/
+	xfer[0].tx_buf = wr_buf;
+	xfer[0].rx_buf = rd_buf;
+	switch (op) {
+	case CY_SPI_WR_OP:
+		xfer[0].len = length + CY_SPI_CMD_BYTES;
+		spi_message_add_tail(&xfer[0], &msg);
+		break;
+
+	case CY_SPI_RD_OP:
+		xfer[0].len = CY_SPI_CMD_BYTES;
+		spi_message_add_tail(&xfer[0], &msg);
+
+		xfer[1].rx_buf = buf;
+		xfer[1].len = length;
+		spi_message_add_tail(&xfer[1], &msg);
+		break;
+
+	default:
+		dev_err(ts->dev, "%s: bad operation code=%d\n", __func__, op);
+		return -EINVAL;
+	}
+
+	retval = spi_sync(spi, &msg);
+	if (retval < 0) {
+		dev_dbg(ts->dev, "%s: spi_sync() error %d, len=%d, op=%d\n",
+			__func__, retval, xfer[1].len, op);
+
+		/*
+		 * do not return here since was a bad ACK sequence
+		 * let the following ACK check handle any errors and
+		 * allow silent retries
+		 */
+	}
+
+	if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK1 ||
+	    rd_buf[CY_SPI_SYNC_BYTE + 1] != CY_SPI_SYNC_ACK2) {
+
+		dev_dbg(ts->dev, "%s: operation %d failed\n", __func__, op);
+
+		for (i = 0; i < CY_SPI_CMD_BYTES; i++)
+			dev_dbg(ts->dev, "%s: test rd_buf[%d]:0x%02x\n",
+				__func__, i, rd_buf[i]);
+		for (i = 0; i < length; i++)
+			dev_dbg(ts->dev, "%s: test buf[%d]:0x%02x\n",
+				__func__, i, buf[i]);
+
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int cyttsp_spi_read_block_data(struct cyttsp *ts,
+				      u8 addr, u8 length, void *data)
+{
+	return cyttsp_spi_xfer(ts, CY_SPI_RD_OP, addr, data, length);
+}
+
+static int cyttsp_spi_write_block_data(struct cyttsp *ts,
+				       u8 addr, u8 length, const void *data)
+{
+	return cyttsp_spi_xfer(ts, CY_SPI_WR_OP, addr, (void *)data, length);
+}
+
+static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = {
+	.bustype	= BUS_SPI,
+	.write		= cyttsp_spi_write_block_data,
+	.read		= cyttsp_spi_read_block_data,
+};
+
+static int __devinit cyttsp_spi_probe(struct spi_device *spi)
+{
+	struct cyttsp *ts;
+	int error;
+
+	/* Set up SPI*/
+	spi->bits_per_word = CY_SPI_BITS_PER_WORD;
+	spi->mode = SPI_MODE_0;
+	error = spi_setup(spi);
+	if (error < 0) {
+		dev_err(&spi->dev, "%s: SPI setup error %d\n",
+			__func__, error);
+		return error;
+	}
+
+	ts = cyttsp_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq,
+			  CY_SPI_DATA_BUF_SIZE * 2);
+	if (IS_ERR(ts))
+		return PTR_ERR(ts);
+
+	spi_set_drvdata(spi, ts);
+
+	return 0;
+}
+
+static int __devexit cyttsp_spi_remove(struct spi_device *spi)
+{
+	struct cyttsp *ts = spi_get_drvdata(spi);
+
+	cyttsp_remove(ts);
+
+	return 0;
+}
+
+static struct spi_driver cyttsp_spi_driver = {
+	.driver = {
+		.name	= CY_SPI_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= &cyttsp_pm_ops,
+	},
+	.probe  = cyttsp_spi_probe,
+	.remove = __devexit_p(cyttsp_spi_remove),
+};
+
+module_spi_driver(cyttsp_spi_driver);
+
+MODULE_ALIAS("spi:cyttsp");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
+MODULE_AUTHOR("Cypress");
+MODULE_ALIAS("spi:cyttsp");
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index 1df19bb..503c709 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -320,20 +320,8 @@
 	.id_table = eeti_ts_id,
 };
 
-static int __init eeti_ts_init(void)
-{
-	return i2c_add_driver(&eeti_ts_driver);
-}
-
-static void __exit eeti_ts_exit(void)
-{
-	i2c_del_driver(&eeti_ts_driver);
-}
+module_i2c_driver(eeti_ts_driver);
 
 MODULE_DESCRIPTION("EETI Touchscreen driver");
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
 MODULE_LICENSE("GPL");
-
-module_init(eeti_ts_init);
-module_exit(eeti_ts_exit);
-
diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c
index eadcc2e..70524dd 100644
--- a/drivers/input/touchscreen/egalax_ts.c
+++ b/drivers/input/touchscreen/egalax_ts.c
@@ -285,18 +285,7 @@
 	.remove		= __devexit_p(egalax_ts_remove),
 };
 
-static int __init egalax_ts_init(void)
-{
-	return i2c_add_driver(&egalax_ts_driver);
-}
-
-static void __exit egalax_ts_exit(void)
-{
-	i2c_del_driver(&egalax_ts_driver);
-}
-
-module_init(egalax_ts_init);
-module_exit(egalax_ts_exit);
+module_i2c_driver(egalax_ts_driver);
 
 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
 MODULE_DESCRIPTION("Touchscreen driver for EETI eGalax touch controller");
diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c
index 639a604..85cf9be 100644
--- a/drivers/input/touchscreen/hp680_ts_input.c
+++ b/drivers/input/touchscreen/hp680_ts_input.c
@@ -93,7 +93,7 @@
 	hp680_ts_dev->phys = "hp680_ts/input0";
 
 	if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt,
-			0, MODNAME, 0) < 0) {
+			0, MODNAME, NULL) < 0) {
 		printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n",
 		       HP680_TS_IRQ);
 		err = -EBUSY;
diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c
new file mode 100644
index 0000000..c004417
--- /dev/null
+++ b/drivers/input/touchscreen/ili210x.c
@@ -0,0 +1,360 @@
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/input/ili210x.h>
+
+#define MAX_TOUCHES		2
+#define DEFAULT_POLL_PERIOD	20
+
+/* Touchscreen commands */
+#define REG_TOUCHDATA		0x10
+#define REG_PANEL_INFO		0x20
+#define REG_FIRMWARE_VERSION	0x40
+#define REG_CALIBRATE		0xcc
+
+struct finger {
+	u8 x_low;
+	u8 x_high;
+	u8 y_low;
+	u8 y_high;
+} __packed;
+
+struct touchdata {
+	u8 status;
+	struct finger finger[MAX_TOUCHES];
+} __packed;
+
+struct panel_info {
+	struct finger finger_max;
+	u8 xchannel_num;
+	u8 ychannel_num;
+} __packed;
+
+struct firmware_version {
+	u8 id;
+	u8 major;
+	u8 minor;
+} __packed;
+
+struct ili210x {
+	struct i2c_client *client;
+	struct input_dev *input;
+	bool (*get_pendown_state)(void);
+	unsigned int poll_period;
+	struct delayed_work dwork;
+};
+
+static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf,
+			    size_t len)
+{
+	struct i2c_msg msg[2] = {
+		{
+			.addr	= client->addr,
+			.flags	= 0,
+			.len	= 1,
+			.buf	= &reg,
+		},
+		{
+			.addr	= client->addr,
+			.flags	= I2C_M_RD,
+			.len	= len,
+			.buf	= buf,
+		}
+	};
+
+	if (i2c_transfer(client->adapter, msg, 2) != 2) {
+		dev_err(&client->dev, "i2c transfer failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void ili210x_report_events(struct input_dev *input,
+				  const struct touchdata *touchdata)
+{
+	int i;
+	bool touch;
+	unsigned int x, y;
+	const struct finger *finger;
+
+	for (i = 0; i < MAX_TOUCHES; i++) {
+		input_mt_slot(input, i);
+
+		finger = &touchdata->finger[i];
+
+		touch = touchdata->status & (1 << i);
+		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+		if (touch) {
+			x = finger->x_low | (finger->x_high << 8);
+			y = finger->y_low | (finger->y_high << 8);
+
+			input_report_abs(input, ABS_MT_POSITION_X, x);
+			input_report_abs(input, ABS_MT_POSITION_Y, y);
+		}
+	}
+
+	input_mt_report_pointer_emulation(input, false);
+	input_sync(input);
+}
+
+static bool get_pendown_state(const struct ili210x *priv)
+{
+	bool state = false;
+
+	if (priv->get_pendown_state)
+		state = priv->get_pendown_state();
+
+	return state;
+}
+
+static void ili210x_work(struct work_struct *work)
+{
+	struct ili210x *priv = container_of(work, struct ili210x,
+					    dwork.work);
+	struct i2c_client *client = priv->client;
+	struct touchdata touchdata;
+	int error;
+
+	error = ili210x_read_reg(client, REG_TOUCHDATA,
+				 &touchdata, sizeof(touchdata));
+	if (error) {
+		dev_err(&client->dev,
+			"Unable to get touchdata, err = %d\n", error);
+		return;
+	}
+
+	ili210x_report_events(priv->input, &touchdata);
+
+	if ((touchdata.status & 0xf3) || get_pendown_state(priv))
+		schedule_delayed_work(&priv->dwork,
+				      msecs_to_jiffies(priv->poll_period));
+}
+
+static irqreturn_t ili210x_irq(int irq, void *irq_data)
+{
+	struct ili210x *priv = irq_data;
+
+	schedule_delayed_work(&priv->dwork, 0);
+
+	return IRQ_HANDLED;
+}
+
+static ssize_t ili210x_calibrate(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ili210x *priv = i2c_get_clientdata(client);
+	unsigned long calibrate;
+	int rc;
+	u8 cmd = REG_CALIBRATE;
+
+	if (kstrtoul(buf, 10, &calibrate))
+		return -EINVAL;
+
+	if (calibrate > 1)
+		return -EINVAL;
+
+	if (calibrate) {
+		rc = i2c_master_send(priv->client, &cmd, sizeof(cmd));
+		if (rc != sizeof(cmd))
+			return -EIO;
+	}
+
+	return count;
+}
+static DEVICE_ATTR(calibrate, 0644, NULL, ili210x_calibrate);
+
+static struct attribute *ili210x_attributes[] = {
+	&dev_attr_calibrate.attr,
+	NULL,
+};
+
+static const struct attribute_group ili210x_attr_group = {
+	.attrs = ili210x_attributes,
+};
+
+static int __devinit ili210x_i2c_probe(struct i2c_client *client,
+				       const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	const struct ili210x_platform_data *pdata = dev->platform_data;
+	struct ili210x *priv;
+	struct input_dev *input;
+	struct panel_info panel;
+	struct firmware_version firmware;
+	int xmax, ymax;
+	int error;
+
+	dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
+
+	if (!pdata) {
+		dev_err(dev, "No platform data!\n");
+		return -EINVAL;
+	}
+
+	if (client->irq <= 0) {
+		dev_err(dev, "No IRQ!\n");
+		return -EINVAL;
+	}
+
+	/* Get firmware version */
+	error = ili210x_read_reg(client, REG_FIRMWARE_VERSION,
+				 &firmware, sizeof(firmware));
+	if (error) {
+		dev_err(dev, "Failed to get firmware version, err: %d\n",
+			error);
+		return error;
+	}
+
+	/* get panel info */
+	error = ili210x_read_reg(client, REG_PANEL_INFO, &panel, sizeof(panel));
+	if (error) {
+		dev_err(dev, "Failed to get panel informations, err: %d\n",
+			error);
+		return error;
+	}
+
+	xmax = panel.finger_max.x_low | (panel.finger_max.x_high << 8);
+	ymax = panel.finger_max.y_low | (panel.finger_max.y_high << 8);
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	input = input_allocate_device();
+	if (!priv || !input) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	priv->client = client;
+	priv->input = input;
+	priv->get_pendown_state = pdata->get_pendown_state;
+	priv->poll_period = pdata->poll_period ? : DEFAULT_POLL_PERIOD;
+	INIT_DELAYED_WORK(&priv->dwork, ili210x_work);
+
+	/* Setup input device */
+	input->name = "ILI210x Touchscreen";
+	input->id.bustype = BUS_I2C;
+	input->dev.parent = dev;
+
+	__set_bit(EV_SYN, input->evbit);
+	__set_bit(EV_KEY, input->evbit);
+	__set_bit(EV_ABS, input->evbit);
+	__set_bit(BTN_TOUCH, input->keybit);
+
+	/* Single touch */
+	input_set_abs_params(input, ABS_X, 0, xmax, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0);
+
+	/* Multi touch */
+	input_mt_init_slots(input, MAX_TOUCHES);
+	input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0);
+	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0);
+
+	input_set_drvdata(input, priv);
+	i2c_set_clientdata(client, priv);
+
+	error = request_irq(client->irq, ili210x_irq, pdata->irq_flags,
+			    client->name, priv);
+	if (error) {
+		dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n",
+			error);
+		goto err_free_mem;
+	}
+
+	error = sysfs_create_group(&dev->kobj, &ili210x_attr_group);
+	if (error) {
+		dev_err(dev, "Unable to create sysfs attributes, err: %d\n",
+			error);
+		goto err_free_irq;
+	}
+
+	error = input_register_device(priv->input);
+	if (error) {
+		dev_err(dev, "Cannot regiser input device, err: %d\n", error);
+		goto err_remove_sysfs;
+	}
+
+	device_init_wakeup(&client->dev, 1);
+
+	dev_dbg(dev,
+		"ILI210x initialized (IRQ: %d), firmware version %d.%d.%d",
+		client->irq, firmware.id, firmware.major, firmware.minor);
+
+	return 0;
+
+err_remove_sysfs:
+	sysfs_remove_group(&dev->kobj, &ili210x_attr_group);
+err_free_irq:
+	free_irq(client->irq, priv);
+err_free_mem:
+	input_free_device(input);
+	kfree(priv);
+	return error;
+}
+
+static int __devexit ili210x_i2c_remove(struct i2c_client *client)
+{
+	struct ili210x *priv = i2c_get_clientdata(client);
+
+	sysfs_remove_group(&client->dev.kobj, &ili210x_attr_group);
+	free_irq(priv->client->irq, priv);
+	cancel_delayed_work_sync(&priv->dwork);
+	input_unregister_device(priv->input);
+	kfree(priv);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ili210x_i2c_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	if (device_may_wakeup(&client->dev))
+		enable_irq_wake(client->irq);
+
+	return 0;
+}
+
+static int ili210x_i2c_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	if (device_may_wakeup(&client->dev))
+		disable_irq_wake(client->irq);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm,
+			 ili210x_i2c_suspend, ili210x_i2c_resume);
+
+static const struct i2c_device_id ili210x_i2c_id[] = {
+	{ "ili210x", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id);
+
+static struct i2c_driver ili210x_ts_driver = {
+	.driver = {
+		.name = "ili210x_i2c",
+		.owner = THIS_MODULE,
+		.pm = &ili210x_i2c_pm,
+	},
+	.id_table = ili210x_i2c_id,
+	.probe = ili210x_i2c_probe,
+	.remove = __devexit_p(ili210x_i2c_remove),
+};
+
+module_i2c_driver(ili210x_ts_driver);
+
+MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
+MODULE_DESCRIPTION("ILI210X I2C Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c
index c3848ad..d9be6ea 100644
--- a/drivers/input/touchscreen/jornada720_ts.c
+++ b/drivers/input/touchscreen/jornada720_ts.c
@@ -22,6 +22,7 @@
 
 #include <mach/hardware.h>
 #include <mach/jornada720.h>
+#include <mach/irqs.h>
 
 MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
 MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver");
diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c
index 4627fe5..4eab50b 100644
--- a/drivers/input/touchscreen/max11801_ts.c
+++ b/drivers/input/touchscreen/max11801_ts.c
@@ -255,18 +255,7 @@
 	.remove		= __devexit_p(max11801_ts_remove),
 };
 
-static int __init max11801_ts_init(void)
-{
-	return i2c_add_driver(&max11801_ts_driver);
-}
-
-static void __exit max11801_ts_exit(void)
-{
-	i2c_del_driver(&max11801_ts_driver);
-}
-
-module_init(max11801_ts_init);
-module_exit(max11801_ts_exit);
+module_i2c_driver(max11801_ts_driver);
 
 MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>");
 MODULE_DESCRIPTION("Touchscreen driver for MAXI MAX11801 controller");
diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c
index ede0274..48dc5b0 100644
--- a/drivers/input/touchscreen/mc13783_ts.c
+++ b/drivers/input/touchscreen/mc13783_ts.c
@@ -39,6 +39,7 @@
 	struct delayed_work work;
 	struct workqueue_struct *workq;
 	unsigned int sample[4];
+	struct mc13xxx_ts_platform_data *touch;
 };
 
 static irqreturn_t mc13783_ts_handler(int irq, void *data)
@@ -125,7 +126,9 @@
 	unsigned int channel = 12;
 
 	if (mc13xxx_adc_do_conversion(priv->mc13xxx,
-				mode, channel, priv->sample) == 0)
+				mode, channel,
+				priv->touch->ato, priv->touch->atox,
+				priv->sample) == 0)
 		mc13783_ts_report_sample(priv);
 }
 
@@ -179,6 +182,12 @@
 	INIT_DELAYED_WORK(&priv->work, mc13783_ts_work);
 	priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
 	priv->idev = idev;
+	priv->touch = dev_get_platdata(&pdev->dev);
+	if (!priv->touch) {
+		dev_err(&pdev->dev, "missing platform data\n");
+		ret = -ENODEV;
+		goto err_free_mem;
+	}
 
 	/*
 	 * We need separate workqueue because mc13783_adc_do_conversion
diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c
index 2d84c80..b528511 100644
--- a/drivers/input/touchscreen/mcs5000_ts.c
+++ b/drivers/input/touchscreen/mcs5000_ts.c
@@ -302,18 +302,7 @@
 	.id_table	= mcs5000_ts_id,
 };
 
-static int __init mcs5000_ts_init(void)
-{
-	return i2c_add_driver(&mcs5000_ts_driver);
-}
-
-static void __exit mcs5000_ts_exit(void)
-{
-	i2c_del_driver(&mcs5000_ts_driver);
-}
-
-module_init(mcs5000_ts_init);
-module_exit(mcs5000_ts_exit);
+module_i2c_driver(mcs5000_ts_driver);
 
 /* Module information */
 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c
index 5226194..c038db9 100644
--- a/drivers/input/touchscreen/migor_ts.c
+++ b/drivers/input/touchscreen/migor_ts.c
@@ -242,19 +242,8 @@
 	.id_table = migor_ts_id,
 };
 
-static int __init migor_ts_init(void)
-{
-	return i2c_add_driver(&migor_ts_driver);
-}
-
-static void __exit migor_ts_exit(void)
-{
-	i2c_del_driver(&migor_ts_driver);
-}
+module_i2c_driver(migor_ts_driver);
 
 MODULE_DESCRIPTION("MigoR Touchscreen driver");
 MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
 MODULE_LICENSE("GPL");
-
-module_init(migor_ts_init);
-module_exit(migor_ts_exit);
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index d5ac09a..72f6ba3 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -222,17 +222,7 @@
 	.id_table	= pixcir_i2c_ts_id,
 };
 
-static int __init pixcir_i2c_ts_init(void)
-{
-	return i2c_add_driver(&pixcir_i2c_ts_driver);
-}
-module_init(pixcir_i2c_ts_init);
-
-static void __exit pixcir_i2c_ts_exit(void)
-{
-	i2c_del_driver(&pixcir_i2c_ts_driver);
-}
-module_exit(pixcir_i2c_ts_exit);
+module_i2c_driver(pixcir_i2c_ts_driver);
 
 MODULE_AUTHOR("Jianchun Bian <jcbian@pixcir.com.cn>, Dequan Meng <dqmeng@pixcir.com.cn>");
 MODULE_DESCRIPTION("Pixcir I2C Touchscreen Driver");
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
index 8825fe3..cbbf71b 100644
--- a/drivers/input/touchscreen/st1232.c
+++ b/drivers/input/touchscreen/st1232.c
@@ -268,17 +268,7 @@
 	},
 };
 
-static int __init st1232_ts_init(void)
-{
-	return i2c_add_driver(&st1232_ts_driver);
-}
-module_init(st1232_ts_init);
-
-static void __exit st1232_ts_exit(void)
-{
-	i2c_del_driver(&st1232_ts_driver);
-}
-module_exit(st1232_ts_exit);
+module_i2c_driver(st1232_ts_driver);
 
 MODULE_AUTHOR("Tony SIM <chinyeow.sim.xt@renesas.com>");
 MODULE_DESCRIPTION("SITRONIX ST1232 Touchscreen Controller Driver");
diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c
new file mode 100644
index 0000000..d229c74
--- /dev/null
+++ b/drivers/input/touchscreen/ti_tscadc.c
@@ -0,0 +1,486 @@
+/*
+ * TI Touch Screen driver
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.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.
+ */
+
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/input/ti_tscadc.h>
+#include <linux/delay.h>
+
+#define REG_IRQEOI		0x020
+#define REG_RAWIRQSTATUS	0x024
+#define REG_IRQSTATUS		0x028
+#define REG_IRQENABLE		0x02C
+#define REG_IRQWAKEUP		0x034
+#define REG_CTRL		0x040
+#define REG_ADCFSM		0x044
+#define REG_CLKDIV		0x04C
+#define REG_SE			0x054
+#define REG_IDLECONFIG		0x058
+#define REG_CHARGECONFIG	0x05C
+#define REG_CHARGEDELAY		0x060
+#define REG_STEPCONFIG(n)	(0x64 + ((n - 1) * 8))
+#define REG_STEPDELAY(n)	(0x68 + ((n - 1) * 8))
+#define REG_STEPCONFIG13	0x0C4
+#define REG_STEPDELAY13		0x0C8
+#define REG_STEPCONFIG14	0x0CC
+#define REG_STEPDELAY14		0x0D0
+#define REG_FIFO0CNT		0xE4
+#define REG_FIFO1THR		0xF4
+#define REG_FIFO0		0x100
+#define REG_FIFO1		0x200
+
+/*	Register Bitfields	*/
+#define IRQWKUP_ENB		BIT(0)
+#define STPENB_STEPENB		0x7FFF
+#define IRQENB_FIFO1THRES	BIT(5)
+#define IRQENB_PENUP		BIT(9)
+#define STEPCONFIG_MODE_HWSYNC	0x2
+#define STEPCONFIG_SAMPLES_AVG	(1 << 4)
+#define STEPCONFIG_XPP		(1 << 5)
+#define STEPCONFIG_XNN		(1 << 6)
+#define STEPCONFIG_YPP		(1 << 7)
+#define STEPCONFIG_YNN		(1 << 8)
+#define STEPCONFIG_XNP		(1 << 9)
+#define STEPCONFIG_YPN		(1 << 10)
+#define STEPCONFIG_INM		(1 << 18)
+#define STEPCONFIG_INP		(1 << 20)
+#define STEPCONFIG_INP_5	(1 << 21)
+#define STEPCONFIG_FIFO1	(1 << 26)
+#define STEPCONFIG_OPENDLY	0xff
+#define STEPCONFIG_Z1		(3 << 19)
+#define STEPIDLE_INP		(1 << 22)
+#define STEPCHARGE_RFP		(1 << 12)
+#define STEPCHARGE_INM		(1 << 15)
+#define STEPCHARGE_INP		(1 << 19)
+#define STEPCHARGE_RFM		(1 << 23)
+#define STEPCHARGE_DELAY	0x1
+#define CNTRLREG_TSCSSENB	(1 << 0)
+#define CNTRLREG_STEPID		(1 << 1)
+#define CNTRLREG_STEPCONFIGWRT	(1 << 2)
+#define CNTRLREG_4WIRE		(1 << 5)
+#define CNTRLREG_5WIRE		(1 << 6)
+#define CNTRLREG_8WIRE		(3 << 5)
+#define CNTRLREG_TSCENB		(1 << 7)
+#define ADCFSM_STEPID		0x10
+
+#define SEQ_SETTLE		275
+#define ADC_CLK			3000000
+#define MAX_12BIT		((1 << 12) - 1)
+#define TSCADC_DELTA_X		15
+#define TSCADC_DELTA_Y		15
+
+struct tscadc {
+	struct input_dev	*input;
+	struct clk		*tsc_ick;
+	void __iomem		*tsc_base;
+	unsigned int		irq;
+	unsigned int		wires;
+	unsigned int		x_plate_resistance;
+	bool			pen_down;
+};
+
+static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg)
+{
+	return readl(ts->tsc_base + reg);
+}
+
+static void tscadc_writel(struct tscadc *tsc, unsigned int reg,
+					unsigned int val)
+{
+	writel(val, tsc->tsc_base + reg);
+}
+
+static void tscadc_step_config(struct tscadc *ts_dev)
+{
+	unsigned int	config;
+	int i;
+
+	/* Configure the Step registers */
+
+	config = STEPCONFIG_MODE_HWSYNC |
+			STEPCONFIG_SAMPLES_AVG | STEPCONFIG_XPP;
+	switch (ts_dev->wires) {
+	case 4:
+		config |= STEPCONFIG_INP | STEPCONFIG_XNN;
+		break;
+	case 5:
+		config |= STEPCONFIG_YNN |
+				STEPCONFIG_INP_5 | STEPCONFIG_XNN |
+				STEPCONFIG_YPP;
+		break;
+	case 8:
+		config |= STEPCONFIG_INP | STEPCONFIG_XNN;
+		break;
+	}
+
+	for (i = 1; i < 7; i++) {
+		tscadc_writel(ts_dev, REG_STEPCONFIG(i), config);
+		tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
+	}
+
+	config = 0;
+	config = STEPCONFIG_MODE_HWSYNC |
+			STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YNN |
+			STEPCONFIG_INM | STEPCONFIG_FIFO1;
+	switch (ts_dev->wires) {
+	case 4:
+		config |= STEPCONFIG_YPP;
+		break;
+	case 5:
+		config |= STEPCONFIG_XPP | STEPCONFIG_INP_5 |
+				STEPCONFIG_XNP | STEPCONFIG_YPN;
+		break;
+	case 8:
+		config |= STEPCONFIG_YPP;
+		break;
+	}
+
+	for (i = 7; i < 13; i++) {
+		tscadc_writel(ts_dev, REG_STEPCONFIG(i), config);
+		tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
+	}
+
+	config = 0;
+	/* Charge step configuration */
+	config = STEPCONFIG_XPP | STEPCONFIG_YNN |
+			STEPCHARGE_RFP | STEPCHARGE_RFM |
+			STEPCHARGE_INM | STEPCHARGE_INP;
+
+	tscadc_writel(ts_dev, REG_CHARGECONFIG, config);
+	tscadc_writel(ts_dev, REG_CHARGEDELAY, STEPCHARGE_DELAY);
+
+	config = 0;
+	/* Configure to calculate pressure */
+	config = STEPCONFIG_MODE_HWSYNC |
+			STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YPP |
+			STEPCONFIG_XNN | STEPCONFIG_INM;
+	tscadc_writel(ts_dev, REG_STEPCONFIG13, config);
+	tscadc_writel(ts_dev, REG_STEPDELAY13, STEPCONFIG_OPENDLY);
+
+	config |= STEPCONFIG_Z1 | STEPCONFIG_FIFO1;
+	tscadc_writel(ts_dev, REG_STEPCONFIG14, config);
+	tscadc_writel(ts_dev, REG_STEPDELAY14, STEPCONFIG_OPENDLY);
+
+	tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB);
+}
+
+static void tscadc_idle_config(struct tscadc *ts_config)
+{
+	unsigned int idleconfig;
+
+	idleconfig = STEPCONFIG_YNN |
+			STEPCONFIG_INM |
+			STEPCONFIG_YPN | STEPIDLE_INP;
+	tscadc_writel(ts_config, REG_IDLECONFIG, idleconfig);
+}
+
+static void tscadc_read_coordinates(struct tscadc *ts_dev,
+				    unsigned int *x, unsigned int *y)
+{
+	unsigned int fifocount = tscadc_readl(ts_dev, REG_FIFO0CNT);
+	unsigned int prev_val_x = ~0, prev_val_y = ~0;
+	unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
+	unsigned int read, diff;
+	unsigned int i;
+
+	/*
+	 * Delta filter is used to remove large variations in sampled
+	 * values from ADC. The filter tries to predict where the next
+	 * coordinate could be. This is done by taking a previous
+	 * coordinate and subtracting it form current one. Further the
+	 * algorithm compares the difference with that of a present value,
+	 * if true the value is reported to the sub system.
+	 */
+	for (i = 0; i < fifocount - 1; i++) {
+		read = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff;
+		diff = abs(read - prev_val_x);
+		if (diff < prev_diff_x) {
+			prev_diff_x = diff;
+			*x = read;
+		}
+		prev_val_x = read;
+
+		read = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff;
+		diff = abs(read - prev_val_y);
+		if (diff < prev_diff_y) {
+			prev_diff_y = diff;
+			*y = read;
+		}
+		prev_val_y = read;
+	}
+}
+
+static irqreturn_t tscadc_irq(int irq, void *dev)
+{
+	struct tscadc *ts_dev = dev;
+	struct input_dev *input_dev = ts_dev->input;
+	unsigned int status, irqclr = 0;
+	unsigned int x = 0, y = 0;
+	unsigned int z1, z2, z;
+	unsigned int fsm;
+
+	status = tscadc_readl(ts_dev, REG_IRQSTATUS);
+	if (status & IRQENB_FIFO1THRES) {
+		tscadc_read_coordinates(ts_dev, &x, &y);
+
+		z1 = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff;
+		z2 = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff;
+
+		if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
+			/*
+			 * Calculate pressure using formula
+			 * Resistance(touch) = x plate resistance *
+			 * x postion/4096 * ((z2 / z1) - 1)
+			 */
+			z = z2 - z1;
+			z *= x;
+			z *= ts_dev->x_plate_resistance;
+			z /= z1;
+			z = (z + 2047) >> 12;
+
+			if (z <= MAX_12BIT) {
+				input_report_abs(input_dev, ABS_X, x);
+				input_report_abs(input_dev, ABS_Y, y);
+				input_report_abs(input_dev, ABS_PRESSURE, z);
+				input_report_key(input_dev, BTN_TOUCH, 1);
+				input_sync(input_dev);
+			}
+		}
+		irqclr |= IRQENB_FIFO1THRES;
+	}
+
+	/*
+	 * Time for sequencer to settle, to read
+	 * correct state of the sequencer.
+	 */
+	udelay(SEQ_SETTLE);
+
+	status = tscadc_readl(ts_dev, REG_RAWIRQSTATUS);
+	if (status & IRQENB_PENUP) {
+		/* Pen up event */
+		fsm = tscadc_readl(ts_dev, REG_ADCFSM);
+		if (fsm == ADCFSM_STEPID) {
+			ts_dev->pen_down = false;
+			input_report_key(input_dev, BTN_TOUCH, 0);
+			input_report_abs(input_dev, ABS_PRESSURE, 0);
+			input_sync(input_dev);
+		} else {
+			ts_dev->pen_down = true;
+		}
+		irqclr |= IRQENB_PENUP;
+	}
+
+	tscadc_writel(ts_dev, REG_IRQSTATUS, irqclr);
+	/* check pending interrupts */
+	tscadc_writel(ts_dev, REG_IRQEOI, 0x0);
+
+	tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB);
+	return IRQ_HANDLED;
+}
+
+/*
+ * The functions for inserting/removing driver as a module.
+ */
+
+static int __devinit tscadc_probe(struct platform_device *pdev)
+{
+	const struct tsc_data *pdata = pdev->dev.platform_data;
+	struct resource *res;
+	struct tscadc *ts_dev;
+	struct input_dev *input_dev;
+	struct clk *clk;
+	int err;
+	int clk_value, ctrl, irq;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "missing platform data.\n");
+		return -EINVAL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no memory resource defined.\n");
+		return -EINVAL;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "no irq ID is specified.\n");
+		return -EINVAL;
+	}
+
+	/* Allocate memory for device */
+	ts_dev = kzalloc(sizeof(struct tscadc), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ts_dev || !input_dev) {
+		dev_err(&pdev->dev, "failed to allocate memory.\n");
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	ts_dev->input = input_dev;
+	ts_dev->irq = irq;
+	ts_dev->wires = pdata->wires;
+	ts_dev->x_plate_resistance = pdata->x_plate_resistance;
+
+	res = request_mem_region(res->start, resource_size(res), pdev->name);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to reserve registers.\n");
+		err = -EBUSY;
+		goto err_free_mem;
+	}
+
+	ts_dev->tsc_base = ioremap(res->start, resource_size(res));
+	if (!ts_dev->tsc_base) {
+		dev_err(&pdev->dev, "failed to map registers.\n");
+		err = -ENOMEM;
+		goto err_release_mem_region;
+	}
+
+	err = request_irq(ts_dev->irq, tscadc_irq,
+			  0, pdev->dev.driver->name, ts_dev);
+	if (err) {
+		dev_err(&pdev->dev, "failed to allocate irq.\n");
+		goto err_unmap_regs;
+	}
+
+	ts_dev->tsc_ick = clk_get(&pdev->dev, "adc_tsc_ick");
+	if (IS_ERR(ts_dev->tsc_ick)) {
+		dev_err(&pdev->dev, "failed to get TSC ick\n");
+		goto err_free_irq;
+	}
+	clk_enable(ts_dev->tsc_ick);
+
+	clk = clk_get(&pdev->dev, "adc_tsc_fck");
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "failed to get TSC fck\n");
+		err = PTR_ERR(clk);
+		goto err_disable_clk;
+	}
+
+	clk_value = clk_get_rate(clk) / ADC_CLK;
+	clk_put(clk);
+
+	if (clk_value < 7) {
+		dev_err(&pdev->dev, "clock input less than min clock requirement\n");
+		goto err_disable_clk;
+	}
+	/* CLKDIV needs to be configured to the value minus 1 */
+	tscadc_writel(ts_dev, REG_CLKDIV, clk_value - 1);
+
+	 /* Enable wake-up of the SoC using touchscreen */
+	tscadc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB);
+
+	ctrl = CNTRLREG_STEPCONFIGWRT |
+			CNTRLREG_TSCENB |
+			CNTRLREG_STEPID;
+	switch (ts_dev->wires) {
+	case 4:
+		ctrl |= CNTRLREG_4WIRE;
+		break;
+	case 5:
+		ctrl |= CNTRLREG_5WIRE;
+		break;
+	case 8:
+		ctrl |= CNTRLREG_8WIRE;
+		break;
+	}
+	tscadc_writel(ts_dev, REG_CTRL, ctrl);
+
+	tscadc_idle_config(ts_dev);
+	tscadc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO1THRES);
+	tscadc_step_config(ts_dev);
+	tscadc_writel(ts_dev, REG_FIFO1THR, 6);
+
+	ctrl |= CNTRLREG_TSCSSENB;
+	tscadc_writel(ts_dev, REG_CTRL, ctrl);
+
+	input_dev->name = "ti-tsc-adc";
+	input_dev->dev.parent = &pdev->dev;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
+
+	/* register to the input system */
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_disable_clk;
+
+	platform_set_drvdata(pdev, ts_dev);
+	return 0;
+
+err_disable_clk:
+	clk_disable(ts_dev->tsc_ick);
+	clk_put(ts_dev->tsc_ick);
+err_free_irq:
+	free_irq(ts_dev->irq, ts_dev);
+err_unmap_regs:
+	iounmap(ts_dev->tsc_base);
+err_release_mem_region:
+	release_mem_region(res->start, resource_size(res));
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(ts_dev);
+	return err;
+}
+
+static int __devexit tscadc_remove(struct platform_device *pdev)
+{
+	struct tscadc *ts_dev = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	free_irq(ts_dev->irq, ts_dev);
+
+	input_unregister_device(ts_dev->input);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	iounmap(ts_dev->tsc_base);
+	release_mem_region(res->start, resource_size(res));
+
+	clk_disable(ts_dev->tsc_ick);
+	clk_put(ts_dev->tsc_ick);
+
+	kfree(ts_dev);
+
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct platform_driver ti_tsc_driver = {
+	.probe	= tscadc_probe,
+	.remove	= __devexit_p(tscadc_remove),
+	.driver	= {
+		.name   = "tsc",
+		.owner	= THIS_MODULE,
+	},
+};
+module_platform_driver(ti_tsc_driver);
+
+MODULE_DESCRIPTION("TI touchscreen controller driver");
+MODULE_AUTHOR("Rachna Patil <rachna@ti.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c
index 067d956..b6adeae 100644
--- a/drivers/input/touchscreen/tsc2005.c
+++ b/drivers/input/touchscreen/tsc2005.c
@@ -747,17 +747,7 @@
 	.remove	= __devexit_p(tsc2005_remove),
 };
 
-static int __init tsc2005_init(void)
-{
-	return spi_register_driver(&tsc2005_driver);
-}
-module_init(tsc2005_init);
-
-static void __exit tsc2005_exit(void)
-{
-	spi_unregister_driver(&tsc2005_driver);
-}
-module_exit(tsc2005_exit);
+module_spi_driver(tsc2005_driver);
 
 MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>");
 MODULE_DESCRIPTION("TSC2005 Touchscreen Driver");
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index 1f674cb..1473d23 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -399,18 +399,7 @@
 	.remove		= __devexit_p(tsc2007_remove),
 };
 
-static int __init tsc2007_init(void)
-{
-	return i2c_add_driver(&tsc2007_driver);
-}
-
-static void __exit tsc2007_exit(void)
-{
-	i2c_del_driver(&tsc2007_driver);
-}
-
-module_init(tsc2007_init);
-module_exit(tsc2007_exit);
+module_i2c_driver(tsc2007_driver);
 
 MODULE_AUTHOR("Kwangwoo Lee <kwlee@mtekvision.com>");
 MODULE_DESCRIPTION("TSC2007 TouchScreen Driver");
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 3a5ebf4..22cd96f 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -17,6 +17,7 @@
  *  - Zytronic capacitive touchscreen
  *  - NEXIO/iNexio
  *  - Elo TouchSystems 2700 IntelliTouch
+ *  - EasyTouch USB Dual/Multi touch controller from Data Modul
  *
  * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
  * Copyright (C) by Todd E. Johnson (mtouchusb.c)
@@ -140,6 +141,7 @@
 	DEVTYPE_TC45USB,
 	DEVTYPE_NEXIO,
 	DEVTYPE_ELO,
+	DEVTYPE_ETOUCH,
 };
 
 #define USB_DEVICE_HID_CLASS(vend, prod) \
@@ -245,6 +247,10 @@
 	{USB_DEVICE(0x04e7, 0x0020), .driver_info = DEVTYPE_ELO},
 #endif
 
+#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
+	{USB_DEVICE(0x7374, 0x0001), .driver_info = DEVTYPE_ETOUCH},
+#endif
+
 	{}
 };
 
@@ -326,6 +332,51 @@
 }
 #endif
 
+/*****************************************************************************
+ * EasyTouch part
+ */
+
+#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
+
+#ifndef MULTI_PACKET
+#define MULTI_PACKET
+#endif
+
+#define ETOUCH_PKT_TYPE_MASK		0xFE
+#define ETOUCH_PKT_TYPE_REPT		0x80
+#define ETOUCH_PKT_TYPE_REPT2		0xB0
+#define ETOUCH_PKT_TYPE_DIAG		0x0A
+
+static int etouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	if ((pkt[0] & ETOUCH_PKT_TYPE_MASK) != ETOUCH_PKT_TYPE_REPT &&
+		(pkt[0] & ETOUCH_PKT_TYPE_MASK) != ETOUCH_PKT_TYPE_REPT2)
+		return 0;
+
+	dev->x = ((pkt[1] & 0x1F) << 7) | (pkt[2] & 0x7F);
+	dev->y = ((pkt[3] & 0x1F) << 7) | (pkt[4] & 0x7F);
+	dev->touch = pkt[0] & 0x01;
+
+	return 1;
+}
+
+static int etouch_get_pkt_len(unsigned char *buf, int len)
+{
+	switch (buf[0] & ETOUCH_PKT_TYPE_MASK) {
+	case ETOUCH_PKT_TYPE_REPT:
+	case ETOUCH_PKT_TYPE_REPT2:
+		return 5;
+
+	case ETOUCH_PKT_TYPE_DIAG:
+		if (len < 2)
+			return -1;
+
+		return buf[1] + 2;
+	}
+
+	return 0;
+}
+#endif
 
 /*****************************************************************************
  * PanJit Part
@@ -1175,6 +1226,18 @@
 		.exit		= nexio_exit,
 	},
 #endif
+#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
+	[DEVTYPE_ETOUCH] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x07ff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x07ff,
+		.rept_size	= 16,
+		.process_pkt	= usbtouch_process_multi,
+		.get_pkt_len	= etouch_get_pkt_len,
+		.read_data	= etouch_read_data,
+	},
+#endif
 };
 
 
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 6bea696..3bd9fff 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -142,4 +142,24 @@
 
          Say N unless you know you need this.
 
+config TEGRA_IOMMU_GART
+	bool "Tegra GART IOMMU Support"
+	depends on ARCH_TEGRA_2x_SOC
+	select IOMMU_API
+	help
+	  Enables support for remapping discontiguous physical memory
+	  shared with the operating system into contiguous I/O virtual
+	  space through the GART (Graphics Address Relocation Table)
+	  hardware included on Tegra SoCs.
+
+config TEGRA_IOMMU_SMMU
+	bool "Tegra SMMU IOMMU Support"
+	depends on ARCH_TEGRA_3x_SOC
+	select IOMMU_API
+	help
+	  Enables support for remapping discontiguous physical memory
+	  shared with the operating system into contiguous I/O virtual
+	  space through the SMMU (System Memory Management Unit)
+	  hardware included on Tegra SoCs.
+
 endif # IOMMU_SUPPORT
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 0e36b49..7ad7a3b 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -8,3 +8,5 @@
 obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
 obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o
 obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
+obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o
+obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index f75e060..a5bee8e 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -2707,7 +2707,8 @@
  * The exported alloc_coherent function for dma_ops.
  */
 static void *alloc_coherent(struct device *dev, size_t size,
-			    dma_addr_t *dma_addr, gfp_t flag)
+			    dma_addr_t *dma_addr, gfp_t flag,
+			    struct dma_attrs *attrs)
 {
 	unsigned long flags;
 	void *virt_addr;
@@ -2765,7 +2766,8 @@
  * The exported free_coherent function for dma_ops.
  */
 static void free_coherent(struct device *dev, size_t size,
-			  void *virt_addr, dma_addr_t dma_addr)
+			  void *virt_addr, dma_addr_t dma_addr,
+			  struct dma_attrs *attrs)
 {
 	unsigned long flags;
 	struct protection_domain *domain;
@@ -2804,7 +2806,7 @@
  * we don't need to preallocate the protection domains anymore.
  * For now we have to.
  */
-static void prealloc_protection_domains(void)
+static void __init prealloc_protection_domains(void)
 {
 	struct iommu_dev_data *dev_data;
 	struct dma_ops_domain *dma_dom;
@@ -2846,8 +2848,8 @@
 }
 
 static struct dma_map_ops amd_iommu_dma_ops = {
-	.alloc_coherent = alloc_coherent,
-	.free_coherent = free_coherent,
+	.alloc = alloc_coherent,
+	.free = free_coherent,
 	.map_page = map_page,
 	.unmap_page = unmap_page,
 	.map_sg = map_sg,
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index a35e98a..c567903 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -196,6 +196,8 @@
  */
 extern void iommu_flush_all_caches(struct amd_iommu *iommu);
 
+static int amd_iommu_enable_interrupts(void);
+
 static inline void update_last_devid(u16 devid)
 {
 	if (devid > amd_iommu_last_bdf)
@@ -358,8 +360,6 @@
  */
 static u8 * __init iommu_map_mmio_space(u64 address)
 {
-	u8 *ret;
-
 	if (!request_mem_region(address, MMIO_REGION_LENGTH, "amd_iommu")) {
 		pr_err("AMD-Vi: Can not reserve memory region %llx for mmio\n",
 			address);
@@ -367,13 +367,7 @@
 		return NULL;
 	}
 
-	ret = ioremap_nocache(address, MMIO_REGION_LENGTH);
-	if (ret != NULL)
-		return ret;
-
-	release_mem_region(address, MMIO_REGION_LENGTH);
-
-	return NULL;
+	return ioremap_nocache(address, MMIO_REGION_LENGTH);
 }
 
 static void __init iommu_unmap_mmio_space(struct amd_iommu *iommu)
@@ -1131,8 +1125,9 @@
 {
 	int r;
 
-	if (pci_enable_msi(iommu->dev))
-		return 1;
+	r = pci_enable_msi(iommu->dev);
+	if (r)
+		return r;
 
 	r = request_threaded_irq(iommu->dev->irq,
 				 amd_iommu_int_handler,
@@ -1142,27 +1137,36 @@
 
 	if (r) {
 		pci_disable_msi(iommu->dev);
-		return 1;
+		return r;
 	}
 
 	iommu->int_enabled = true;
-	iommu_feature_enable(iommu, CONTROL_EVT_INT_EN);
-
-	if (iommu->ppr_log != NULL)
-		iommu_feature_enable(iommu, CONTROL_PPFINT_EN);
 
 	return 0;
 }
 
 static int iommu_init_msi(struct amd_iommu *iommu)
 {
+	int ret;
+
 	if (iommu->int_enabled)
-		return 0;
+		goto enable_faults;
 
 	if (pci_find_capability(iommu->dev, PCI_CAP_ID_MSI))
-		return iommu_setup_msi(iommu);
+		ret = iommu_setup_msi(iommu);
+	else
+		ret = -ENODEV;
 
-	return 1;
+	if (ret)
+		return ret;
+
+enable_faults:
+	iommu_feature_enable(iommu, CONTROL_EVT_INT_EN);
+
+	if (iommu->ppr_log != NULL)
+		iommu_feature_enable(iommu, CONTROL_PPFINT_EN);
+
+	return 0;
 }
 
 /****************************************************************************
@@ -1381,7 +1385,6 @@
 		iommu_enable_ppr_log(iommu);
 		iommu_enable_gt(iommu);
 		iommu_set_exclusion_range(iommu);
-		iommu_init_msi(iommu);
 		iommu_enable(iommu);
 		iommu_flush_all_caches(iommu);
 	}
@@ -1409,6 +1412,8 @@
 
 	/* re-load the hardware */
 	enable_iommus();
+
+	amd_iommu_enable_interrupts();
 }
 
 static int amd_iommu_suspend(void)
@@ -1424,10 +1429,40 @@
 	.resume = amd_iommu_resume,
 };
 
+static void __init free_on_init_error(void)
+{
+	amd_iommu_uninit_devices();
+
+	free_pages((unsigned long)amd_iommu_pd_alloc_bitmap,
+		   get_order(MAX_DOMAIN_ID/8));
+
+	free_pages((unsigned long)amd_iommu_rlookup_table,
+		   get_order(rlookup_table_size));
+
+	free_pages((unsigned long)amd_iommu_alias_table,
+		   get_order(alias_table_size));
+
+	free_pages((unsigned long)amd_iommu_dev_table,
+		   get_order(dev_table_size));
+
+	free_iommu_all();
+
+	free_unity_maps();
+
+#ifdef CONFIG_GART_IOMMU
+	/*
+	 * We failed to initialize the AMD IOMMU - try fallback to GART
+	 * if possible.
+	 */
+	gart_iommu_init();
+
+#endif
+}
+
 /*
- * This is the core init function for AMD IOMMU hardware in the system.
- * This function is called from the generic x86 DMA layer initialization
- * code.
+ * This is the hardware init function for AMD IOMMU in the system.
+ * This function is called either from amd_iommu_init or from the interrupt
+ * remapping setup code.
  *
  * This function basically parses the ACPI table for AMD IOMMU (IVRS)
  * three times:
@@ -1446,16 +1481,21 @@
  *		remapping requirements parsed out of the ACPI table in
  *		this last pass.
  *
- * After that the hardware is initialized and ready to go. In the last
- * step we do some Linux specific things like registering the driver in
- * the dma_ops interface and initializing the suspend/resume support
- * functions. Finally it prints some information about AMD IOMMUs and
- * the driver state and enables the hardware.
+ * After everything is set up the IOMMUs are enabled and the necessary
+ * hotplug and suspend notifiers are registered.
  */
-static int __init amd_iommu_init(void)
+int __init amd_iommu_init_hardware(void)
 {
 	int i, ret = 0;
 
+	if (!amd_iommu_detected)
+		return -ENODEV;
+
+	if (amd_iommu_dev_table != NULL) {
+		/* Hardware already initialized */
+		return 0;
+	}
+
 	/*
 	 * First parse ACPI tables to find the largest Bus/Dev/Func
 	 * we need to handle. Upon this information the shared data
@@ -1472,9 +1512,8 @@
 	alias_table_size   = tbl_size(ALIAS_TABLE_ENTRY_SIZE);
 	rlookup_table_size = tbl_size(RLOOKUP_TABLE_ENTRY_SIZE);
 
-	ret = -ENOMEM;
-
 	/* Device table - directly used by all IOMMUs */
+	ret = -ENOMEM;
 	amd_iommu_dev_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
 				      get_order(dev_table_size));
 	if (amd_iommu_dev_table == NULL)
@@ -1546,20 +1585,65 @@
 
 	enable_iommus();
 
+	amd_iommu_init_notifier();
+
+	register_syscore_ops(&amd_iommu_syscore_ops);
+
+out:
+	return ret;
+
+free:
+	free_on_init_error();
+
+	return ret;
+}
+
+static int amd_iommu_enable_interrupts(void)
+{
+	struct amd_iommu *iommu;
+	int ret = 0;
+
+	for_each_iommu(iommu) {
+		ret = iommu_init_msi(iommu);
+		if (ret)
+			goto out;
+	}
+
+out:
+	return ret;
+}
+
+/*
+ * This is the core init function for AMD IOMMU hardware in the system.
+ * This function is called from the generic x86 DMA layer initialization
+ * code.
+ *
+ * The function calls amd_iommu_init_hardware() to setup and enable the
+ * IOMMU hardware if this has not happened yet. After that the driver
+ * registers for the DMA-API and for the IOMMU-API as necessary.
+ */
+static int __init amd_iommu_init(void)
+{
+	int ret = 0;
+
+	ret = amd_iommu_init_hardware();
+	if (ret)
+		goto out;
+
+	ret = amd_iommu_enable_interrupts();
+	if (ret)
+		goto free;
+
 	if (iommu_pass_through)
 		ret = amd_iommu_init_passthrough();
 	else
 		ret = amd_iommu_init_dma_ops();
 
 	if (ret)
-		goto free_disable;
+		goto free;
 
 	amd_iommu_init_api();
 
-	amd_iommu_init_notifier();
-
-	register_syscore_ops(&amd_iommu_syscore_ops);
-
 	if (iommu_pass_through)
 		goto out;
 
@@ -1569,39 +1653,14 @@
 		printk(KERN_INFO "AMD-Vi: Lazy IO/TLB flushing enabled\n");
 
 	x86_platform.iommu_shutdown = disable_iommus;
+
 out:
 	return ret;
 
-free_disable:
+free:
 	disable_iommus();
 
-free:
-	amd_iommu_uninit_devices();
-
-	free_pages((unsigned long)amd_iommu_pd_alloc_bitmap,
-		   get_order(MAX_DOMAIN_ID/8));
-
-	free_pages((unsigned long)amd_iommu_rlookup_table,
-		   get_order(rlookup_table_size));
-
-	free_pages((unsigned long)amd_iommu_alias_table,
-		   get_order(alias_table_size));
-
-	free_pages((unsigned long)amd_iommu_dev_table,
-		   get_order(dev_table_size));
-
-	free_iommu_all();
-
-	free_unity_maps();
-
-#ifdef CONFIG_GART_IOMMU
-	/*
-	 * We failed to initialize the AMD IOMMU - try fallback to GART
-	 * if possible.
-	 */
-	gart_iommu_init();
-
-#endif
+	free_on_init_error();
 
 	goto out;
 }
diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c
index 8add9f1..036fe9b 100644
--- a/drivers/iommu/amd_iommu_v2.c
+++ b/drivers/iommu/amd_iommu_v2.c
@@ -921,7 +921,16 @@
 	size_t state_table_size;
 	int ret;
 
-	pr_info("AMD IOMMUv2 driver by Joerg Roedel <joerg.roedel@amd.com>");
+	pr_info("AMD IOMMUv2 driver by Joerg Roedel <joerg.roedel@amd.com>\n");
+
+	if (!amd_iommu_v2_supported()) {
+		pr_info("AMD IOMMUv2 functionality not available on this sytem\n");
+		/*
+		 * Load anyway to provide the symbols to other modules
+		 * which may use AMD IOMMUv2 optionally.
+		 */
+		return 0;
+	}
 
 	spin_lock_init(&state_lock);
 
@@ -961,6 +970,9 @@
 	size_t state_table_size;
 	int i;
 
+	if (!amd_iommu_v2_supported())
+		return;
+
 	profile_event_unregister(PROFILE_TASK_EXIT, &profile_nb);
 	amd_iommu_unregister_ppr_notifier(&ppr_nb);
 
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 132f93b..f93d5ac 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -2949,7 +2949,8 @@
 }
 
 static void *intel_alloc_coherent(struct device *hwdev, size_t size,
-				  dma_addr_t *dma_handle, gfp_t flags)
+				  dma_addr_t *dma_handle, gfp_t flags,
+				  struct dma_attrs *attrs)
 {
 	void *vaddr;
 	int order;
@@ -2981,7 +2982,7 @@
 }
 
 static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
-				dma_addr_t dma_handle)
+				dma_addr_t dma_handle, struct dma_attrs *attrs)
 {
 	int order;
 
@@ -3126,8 +3127,8 @@
 }
 
 struct dma_map_ops intel_dma_ops = {
-	.alloc_coherent = intel_alloc_coherent,
-	.free_coherent = intel_free_coherent,
+	.alloc = intel_alloc_coherent,
+	.free = intel_free_coherent,
 	.map_sg = intel_map_sg,
 	.unmap_sg = intel_unmap_sg,
 	.map_page = intel_map_page,
diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c
index 103dbd9..f55fc5d 100644
--- a/drivers/iommu/omap-iommu-debug.c
+++ b/drivers/iommu/omap-iommu-debug.c
@@ -323,15 +323,9 @@
 	return count;
 }
 
-static int debug_open_generic(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 #define DEBUG_FOPS(name)						\
 	static const struct file_operations debug_##name##_fops = {	\
-		.open = debug_open_generic,				\
+		.open = simple_open,					\
 		.read = debug_read_##name,				\
 		.write = debug_write_##name,				\
 		.llseek = generic_file_llseek,				\
@@ -339,7 +333,7 @@
 
 #define DEBUG_FOPS_RO(name)						\
 	static const struct file_operations debug_##name##_fops = {	\
-		.open = debug_open_generic,				\
+		.open = simple_open,					\
 		.read = debug_read_##name,				\
 		.llseek = generic_file_llseek,				\
 	};
diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c
new file mode 100644
index 0000000..779306e
--- /dev/null
+++ b/drivers/iommu/tegra-gart.c
@@ -0,0 +1,451 @@
+/*
+ * IOMMU API for GART in Tegra20
+ *
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt)	"%s(): " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+
+#include <asm/cacheflush.h>
+
+/* bitmap of the page sizes currently supported */
+#define GART_IOMMU_PGSIZES	(SZ_4K)
+
+#define GART_CONFIG		0x24
+#define GART_ENTRY_ADDR		0x28
+#define GART_ENTRY_DATA		0x2c
+#define GART_ENTRY_PHYS_ADDR_VALID	(1 << 31)
+
+#define GART_PAGE_SHIFT		12
+#define GART_PAGE_SIZE		(1 << GART_PAGE_SHIFT)
+#define GART_PAGE_MASK						\
+	(~(GART_PAGE_SIZE - 1) & ~GART_ENTRY_PHYS_ADDR_VALID)
+
+struct gart_client {
+	struct device		*dev;
+	struct list_head	list;
+};
+
+struct gart_device {
+	void __iomem		*regs;
+	u32			*savedata;
+	u32			page_count;	/* total remappable size */
+	dma_addr_t		iovmm_base;	/* offset to vmm_area */
+	spinlock_t		pte_lock;	/* for pagetable */
+	struct list_head	client;
+	spinlock_t		client_lock;	/* for client list */
+	struct device		*dev;
+};
+
+static struct gart_device *gart_handle; /* unique for a system */
+
+#define GART_PTE(_pfn)						\
+	(GART_ENTRY_PHYS_ADDR_VALID | ((_pfn) << PAGE_SHIFT))
+
+/*
+ * Any interaction between any block on PPSB and a block on APB or AHB
+ * must have these read-back to ensure the APB/AHB bus transaction is
+ * complete before initiating activity on the PPSB block.
+ */
+#define FLUSH_GART_REGS(gart)	((void)readl((gart)->regs + GART_CONFIG))
+
+#define for_each_gart_pte(gart, iova)					\
+	for (iova = gart->iovmm_base;					\
+	     iova < gart->iovmm_base + GART_PAGE_SIZE * gart->page_count; \
+	     iova += GART_PAGE_SIZE)
+
+static inline void gart_set_pte(struct gart_device *gart,
+				unsigned long offs, u32 pte)
+{
+	writel(offs, gart->regs + GART_ENTRY_ADDR);
+	writel(pte, gart->regs + GART_ENTRY_DATA);
+
+	dev_dbg(gart->dev, "%s %08lx:%08x\n",
+		 pte ? "map" : "unmap", offs, pte & GART_PAGE_MASK);
+}
+
+static inline unsigned long gart_read_pte(struct gart_device *gart,
+					  unsigned long offs)
+{
+	unsigned long pte;
+
+	writel(offs, gart->regs + GART_ENTRY_ADDR);
+	pte = readl(gart->regs + GART_ENTRY_DATA);
+
+	return pte;
+}
+
+static void do_gart_setup(struct gart_device *gart, const u32 *data)
+{
+	unsigned long iova;
+
+	for_each_gart_pte(gart, iova)
+		gart_set_pte(gart, iova, data ? *(data++) : 0);
+
+	writel(1, gart->regs + GART_CONFIG);
+	FLUSH_GART_REGS(gart);
+}
+
+#ifdef DEBUG
+static void gart_dump_table(struct gart_device *gart)
+{
+	unsigned long iova;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gart->pte_lock, flags);
+	for_each_gart_pte(gart, iova) {
+		unsigned long pte;
+
+		pte = gart_read_pte(gart, iova);
+
+		dev_dbg(gart->dev, "%s %08lx:%08lx\n",
+			(GART_ENTRY_PHYS_ADDR_VALID & pte) ? "v" : " ",
+			iova, pte & GART_PAGE_MASK);
+	}
+	spin_unlock_irqrestore(&gart->pte_lock, flags);
+}
+#else
+static inline void gart_dump_table(struct gart_device *gart)
+{
+}
+#endif
+
+static inline bool gart_iova_range_valid(struct gart_device *gart,
+					 unsigned long iova, size_t bytes)
+{
+	unsigned long iova_start, iova_end, gart_start, gart_end;
+
+	iova_start = iova;
+	iova_end = iova_start + bytes - 1;
+	gart_start = gart->iovmm_base;
+	gart_end = gart_start + gart->page_count * GART_PAGE_SIZE - 1;
+
+	if (iova_start < gart_start)
+		return false;
+	if (iova_end > gart_end)
+		return false;
+	return true;
+}
+
+static int gart_iommu_attach_dev(struct iommu_domain *domain,
+				 struct device *dev)
+{
+	struct gart_device *gart;
+	struct gart_client *client, *c;
+	int err = 0;
+
+	gart = dev_get_drvdata(dev->parent);
+	if (!gart)
+		return -EINVAL;
+	domain->priv = gart;
+
+	client = devm_kzalloc(gart->dev, sizeof(*c), GFP_KERNEL);
+	if (!client)
+		return -ENOMEM;
+	client->dev = dev;
+
+	spin_lock(&gart->client_lock);
+	list_for_each_entry(c, &gart->client, list) {
+		if (c->dev == dev) {
+			dev_err(gart->dev,
+				"%s is already attached\n", dev_name(dev));
+			err = -EINVAL;
+			goto fail;
+		}
+	}
+	list_add(&client->list, &gart->client);
+	spin_unlock(&gart->client_lock);
+	dev_dbg(gart->dev, "Attached %s\n", dev_name(dev));
+	return 0;
+
+fail:
+	devm_kfree(gart->dev, client);
+	spin_unlock(&gart->client_lock);
+	return err;
+}
+
+static void gart_iommu_detach_dev(struct iommu_domain *domain,
+				  struct device *dev)
+{
+	struct gart_device *gart = domain->priv;
+	struct gart_client *c;
+
+	spin_lock(&gart->client_lock);
+
+	list_for_each_entry(c, &gart->client, list) {
+		if (c->dev == dev) {
+			list_del(&c->list);
+			devm_kfree(gart->dev, c);
+			dev_dbg(gart->dev, "Detached %s\n", dev_name(dev));
+			goto out;
+		}
+	}
+	dev_err(gart->dev, "Couldn't find\n");
+out:
+	spin_unlock(&gart->client_lock);
+}
+
+static int gart_iommu_domain_init(struct iommu_domain *domain)
+{
+	return 0;
+}
+
+static void gart_iommu_domain_destroy(struct iommu_domain *domain)
+{
+	struct gart_device *gart = domain->priv;
+
+	if (!gart)
+		return;
+
+	spin_lock(&gart->client_lock);
+	if (!list_empty(&gart->client)) {
+		struct gart_client *c;
+
+		list_for_each_entry(c, &gart->client, list)
+			gart_iommu_detach_dev(domain, c->dev);
+	}
+	spin_unlock(&gart->client_lock);
+	domain->priv = NULL;
+}
+
+static int gart_iommu_map(struct iommu_domain *domain, unsigned long iova,
+			  phys_addr_t pa, size_t bytes, int prot)
+{
+	struct gart_device *gart = domain->priv;
+	unsigned long flags;
+	unsigned long pfn;
+
+	if (!gart_iova_range_valid(gart, iova, bytes))
+		return -EINVAL;
+
+	spin_lock_irqsave(&gart->pte_lock, flags);
+	pfn = __phys_to_pfn(pa);
+	if (!pfn_valid(pfn)) {
+		dev_err(gart->dev, "Invalid page: %08x\n", pa);
+		spin_unlock_irqrestore(&gart->pte_lock, flags);
+		return -EINVAL;
+	}
+	gart_set_pte(gart, iova, GART_PTE(pfn));
+	FLUSH_GART_REGS(gart);
+	spin_unlock_irqrestore(&gart->pte_lock, flags);
+	return 0;
+}
+
+static size_t gart_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
+			       size_t bytes)
+{
+	struct gart_device *gart = domain->priv;
+	unsigned long flags;
+
+	if (!gart_iova_range_valid(gart, iova, bytes))
+		return 0;
+
+	spin_lock_irqsave(&gart->pte_lock, flags);
+	gart_set_pte(gart, iova, 0);
+	FLUSH_GART_REGS(gart);
+	spin_unlock_irqrestore(&gart->pte_lock, flags);
+	return 0;
+}
+
+static phys_addr_t gart_iommu_iova_to_phys(struct iommu_domain *domain,
+					   unsigned long iova)
+{
+	struct gart_device *gart = domain->priv;
+	unsigned long pte;
+	phys_addr_t pa;
+	unsigned long flags;
+
+	if (!gart_iova_range_valid(gart, iova, 0))
+		return -EINVAL;
+
+	spin_lock_irqsave(&gart->pte_lock, flags);
+	pte = gart_read_pte(gart, iova);
+	spin_unlock_irqrestore(&gart->pte_lock, flags);
+
+	pa = (pte & GART_PAGE_MASK);
+	if (!pfn_valid(__phys_to_pfn(pa))) {
+		dev_err(gart->dev, "No entry for %08lx:%08x\n", iova, pa);
+		gart_dump_table(gart);
+		return -EINVAL;
+	}
+	return pa;
+}
+
+static int gart_iommu_domain_has_cap(struct iommu_domain *domain,
+				     unsigned long cap)
+{
+	return 0;
+}
+
+static struct iommu_ops gart_iommu_ops = {
+	.domain_init	= gart_iommu_domain_init,
+	.domain_destroy	= gart_iommu_domain_destroy,
+	.attach_dev	= gart_iommu_attach_dev,
+	.detach_dev	= gart_iommu_detach_dev,
+	.map		= gart_iommu_map,
+	.unmap		= gart_iommu_unmap,
+	.iova_to_phys	= gart_iommu_iova_to_phys,
+	.domain_has_cap	= gart_iommu_domain_has_cap,
+	.pgsize_bitmap	= GART_IOMMU_PGSIZES,
+};
+
+static int tegra_gart_suspend(struct device *dev)
+{
+	struct gart_device *gart = dev_get_drvdata(dev);
+	unsigned long iova;
+	u32 *data = gart->savedata;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gart->pte_lock, flags);
+	for_each_gart_pte(gart, iova)
+		*(data++) = gart_read_pte(gart, iova);
+	spin_unlock_irqrestore(&gart->pte_lock, flags);
+	return 0;
+}
+
+static int tegra_gart_resume(struct device *dev)
+{
+	struct gart_device *gart = dev_get_drvdata(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&gart->pte_lock, flags);
+	do_gart_setup(gart, gart->savedata);
+	spin_unlock_irqrestore(&gart->pte_lock, flags);
+	return 0;
+}
+
+static int tegra_gart_probe(struct platform_device *pdev)
+{
+	struct gart_device *gart;
+	struct resource *res, *res_remap;
+	void __iomem *gart_regs;
+	int err;
+	struct device *dev = &pdev->dev;
+
+	if (gart_handle)
+		return -EIO;
+
+	BUILD_BUG_ON(PAGE_SHIFT != GART_PAGE_SHIFT);
+
+	/* the GART memory aperture is required */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res_remap = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res || !res_remap) {
+		dev_err(dev, "GART memory aperture expected\n");
+		return -ENXIO;
+	}
+
+	gart = devm_kzalloc(dev, sizeof(*gart), GFP_KERNEL);
+	if (!gart) {
+		dev_err(dev, "failed to allocate gart_device\n");
+		return -ENOMEM;
+	}
+
+	gart_regs = devm_ioremap(dev, res->start, resource_size(res));
+	if (!gart_regs) {
+		dev_err(dev, "failed to remap GART registers\n");
+		err = -ENXIO;
+		goto fail;
+	}
+
+	gart->dev = &pdev->dev;
+	spin_lock_init(&gart->pte_lock);
+	spin_lock_init(&gart->client_lock);
+	INIT_LIST_HEAD(&gart->client);
+	gart->regs = gart_regs;
+	gart->iovmm_base = (dma_addr_t)res_remap->start;
+	gart->page_count = (resource_size(res_remap) >> GART_PAGE_SHIFT);
+
+	gart->savedata = vmalloc(sizeof(u32) * gart->page_count);
+	if (!gart->savedata) {
+		dev_err(dev, "failed to allocate context save area\n");
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	platform_set_drvdata(pdev, gart);
+	do_gart_setup(gart, NULL);
+
+	gart_handle = gart;
+	return 0;
+
+fail:
+	if (gart_regs)
+		devm_iounmap(dev, gart_regs);
+	if (gart && gart->savedata)
+		vfree(gart->savedata);
+	devm_kfree(dev, gart);
+	return err;
+}
+
+static int tegra_gart_remove(struct platform_device *pdev)
+{
+	struct gart_device *gart = platform_get_drvdata(pdev);
+	struct device *dev = gart->dev;
+
+	writel(0, gart->regs + GART_CONFIG);
+	if (gart->savedata)
+		vfree(gart->savedata);
+	if (gart->regs)
+		devm_iounmap(dev, gart->regs);
+	devm_kfree(dev, gart);
+	gart_handle = NULL;
+	return 0;
+}
+
+const struct dev_pm_ops tegra_gart_pm_ops = {
+	.suspend	= tegra_gart_suspend,
+	.resume		= tegra_gart_resume,
+};
+
+static struct platform_driver tegra_gart_driver = {
+	.probe		= tegra_gart_probe,
+	.remove		= tegra_gart_remove,
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "tegra-gart",
+		.pm	= &tegra_gart_pm_ops,
+	},
+};
+
+static int __devinit tegra_gart_init(void)
+{
+	bus_set_iommu(&platform_bus_type, &gart_iommu_ops);
+	return platform_driver_register(&tegra_gart_driver);
+}
+
+static void __exit tegra_gart_exit(void)
+{
+	platform_driver_unregister(&tegra_gart_driver);
+}
+
+subsys_initcall(tegra_gart_init);
+module_exit(tegra_gart_exit);
+
+MODULE_DESCRIPTION("IOMMU API for GART in Tegra20");
+MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
new file mode 100644
index 0000000..eb93c82
--- /dev/null
+++ b/drivers/iommu/tegra-smmu.c
@@ -0,0 +1,1034 @@
+/*
+ * IOMMU API for SMMU in Tegra30
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt)	"%s(): " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/iommu.h>
+#include <linux/io.h>
+
+#include <asm/page.h>
+#include <asm/cacheflush.h>
+
+#include <mach/iomap.h>
+#include <mach/smmu.h>
+
+/* bitmap of the page sizes currently supported */
+#define SMMU_IOMMU_PGSIZES	(SZ_4K)
+
+#define SMMU_CONFIG				0x10
+#define SMMU_CONFIG_DISABLE			0
+#define SMMU_CONFIG_ENABLE			1
+
+#define SMMU_TLB_CONFIG				0x14
+#define SMMU_TLB_CONFIG_STATS__MASK		(1 << 31)
+#define SMMU_TLB_CONFIG_STATS__ENABLE		(1 << 31)
+#define SMMU_TLB_CONFIG_HIT_UNDER_MISS__ENABLE	(1 << 29)
+#define SMMU_TLB_CONFIG_ACTIVE_LINES__VALUE	0x10
+#define SMMU_TLB_CONFIG_RESET_VAL		0x20000010
+
+#define SMMU_PTC_CONFIG				0x18
+#define SMMU_PTC_CONFIG_STATS__MASK		(1 << 31)
+#define SMMU_PTC_CONFIG_STATS__ENABLE		(1 << 31)
+#define SMMU_PTC_CONFIG_CACHE__ENABLE		(1 << 29)
+#define SMMU_PTC_CONFIG_INDEX_MAP__PATTERN	0x3f
+#define SMMU_PTC_CONFIG_RESET_VAL		0x2000003f
+
+#define SMMU_PTB_ASID				0x1c
+#define SMMU_PTB_ASID_CURRENT_SHIFT		0
+
+#define SMMU_PTB_DATA				0x20
+#define SMMU_PTB_DATA_RESET_VAL			0
+#define SMMU_PTB_DATA_ASID_NONSECURE_SHIFT	29
+#define SMMU_PTB_DATA_ASID_WRITABLE_SHIFT	30
+#define SMMU_PTB_DATA_ASID_READABLE_SHIFT	31
+
+#define SMMU_TLB_FLUSH				0x30
+#define SMMU_TLB_FLUSH_VA_MATCH_ALL		0
+#define SMMU_TLB_FLUSH_VA_MATCH_SECTION		2
+#define SMMU_TLB_FLUSH_VA_MATCH_GROUP		3
+#define SMMU_TLB_FLUSH_ASID_SHIFT		29
+#define SMMU_TLB_FLUSH_ASID_MATCH_DISABLE	0
+#define SMMU_TLB_FLUSH_ASID_MATCH_ENABLE	1
+#define SMMU_TLB_FLUSH_ASID_MATCH_SHIFT		31
+
+#define SMMU_PTC_FLUSH				0x34
+#define SMMU_PTC_FLUSH_TYPE_ALL			0
+#define SMMU_PTC_FLUSH_TYPE_ADR			1
+#define SMMU_PTC_FLUSH_ADR_SHIFT		4
+
+#define SMMU_ASID_SECURITY			0x38
+
+#define SMMU_STATS_TLB_HIT_COUNT		0x1f0
+#define SMMU_STATS_TLB_MISS_COUNT		0x1f4
+#define SMMU_STATS_PTC_HIT_COUNT		0x1f8
+#define SMMU_STATS_PTC_MISS_COUNT		0x1fc
+
+#define SMMU_TRANSLATION_ENABLE_0		0x228
+#define SMMU_TRANSLATION_ENABLE_1		0x22c
+#define SMMU_TRANSLATION_ENABLE_2		0x230
+
+#define SMMU_AFI_ASID	0x238   /* PCIE */
+#define SMMU_AVPC_ASID	0x23c   /* AVP */
+#define SMMU_DC_ASID	0x240   /* Display controller */
+#define SMMU_DCB_ASID	0x244   /* Display controller B */
+#define SMMU_EPP_ASID	0x248   /* Encoder pre-processor */
+#define SMMU_G2_ASID	0x24c   /* 2D engine */
+#define SMMU_HC_ASID	0x250   /* Host1x */
+#define SMMU_HDA_ASID	0x254   /* High-def audio */
+#define SMMU_ISP_ASID	0x258   /* Image signal processor */
+#define SMMU_MPE_ASID	0x264   /* MPEG encoder */
+#define SMMU_NV_ASID	0x268   /* (3D) */
+#define SMMU_NV2_ASID	0x26c   /* (3D) */
+#define SMMU_PPCS_ASID	0x270   /* AHB */
+#define SMMU_SATA_ASID	0x278   /* SATA */
+#define SMMU_VDE_ASID	0x27c   /* Video decoder */
+#define SMMU_VI_ASID	0x280   /* Video input */
+
+#define SMMU_PDE_NEXT_SHIFT		28
+
+/* AHB Arbiter Registers */
+#define AHB_XBAR_CTRL				0xe0
+#define AHB_XBAR_CTRL_SMMU_INIT_DONE_DONE	1
+#define AHB_XBAR_CTRL_SMMU_INIT_DONE_SHIFT	17
+
+#define SMMU_NUM_ASIDS				4
+#define SMMU_TLB_FLUSH_VA_SECTION__MASK		0xffc00000
+#define SMMU_TLB_FLUSH_VA_SECTION__SHIFT	12 /* right shift */
+#define SMMU_TLB_FLUSH_VA_GROUP__MASK		0xffffc000
+#define SMMU_TLB_FLUSH_VA_GROUP__SHIFT		12 /* right shift */
+#define SMMU_TLB_FLUSH_VA(iova, which)	\
+	((((iova) & SMMU_TLB_FLUSH_VA_##which##__MASK) >> \
+		SMMU_TLB_FLUSH_VA_##which##__SHIFT) |	\
+	SMMU_TLB_FLUSH_VA_MATCH_##which)
+#define SMMU_PTB_ASID_CUR(n)	\
+		((n) << SMMU_PTB_ASID_CURRENT_SHIFT)
+#define SMMU_TLB_FLUSH_ASID_MATCH_disable		\
+		(SMMU_TLB_FLUSH_ASID_MATCH_DISABLE <<	\
+			SMMU_TLB_FLUSH_ASID_MATCH_SHIFT)
+#define SMMU_TLB_FLUSH_ASID_MATCH__ENABLE		\
+		(SMMU_TLB_FLUSH_ASID_MATCH_ENABLE <<	\
+			SMMU_TLB_FLUSH_ASID_MATCH_SHIFT)
+
+#define SMMU_PAGE_SHIFT 12
+#define SMMU_PAGE_SIZE	(1 << SMMU_PAGE_SHIFT)
+
+#define SMMU_PDIR_COUNT	1024
+#define SMMU_PDIR_SIZE	(sizeof(unsigned long) * SMMU_PDIR_COUNT)
+#define SMMU_PTBL_COUNT	1024
+#define SMMU_PTBL_SIZE	(sizeof(unsigned long) * SMMU_PTBL_COUNT)
+#define SMMU_PDIR_SHIFT	12
+#define SMMU_PDE_SHIFT	12
+#define SMMU_PTE_SHIFT	12
+#define SMMU_PFN_MASK	0x000fffff
+
+#define SMMU_ADDR_TO_PFN(addr)	((addr) >> 12)
+#define SMMU_ADDR_TO_PDN(addr)	((addr) >> 22)
+#define SMMU_PDN_TO_ADDR(addr)	((pdn) << 22)
+
+#define _READABLE	(1 << SMMU_PTB_DATA_ASID_READABLE_SHIFT)
+#define _WRITABLE	(1 << SMMU_PTB_DATA_ASID_WRITABLE_SHIFT)
+#define _NONSECURE	(1 << SMMU_PTB_DATA_ASID_NONSECURE_SHIFT)
+#define _PDE_NEXT	(1 << SMMU_PDE_NEXT_SHIFT)
+#define _MASK_ATTR	(_READABLE | _WRITABLE | _NONSECURE)
+
+#define _PDIR_ATTR	(_READABLE | _WRITABLE | _NONSECURE)
+
+#define _PDE_ATTR	(_READABLE | _WRITABLE | _NONSECURE)
+#define _PDE_ATTR_N	(_PDE_ATTR | _PDE_NEXT)
+#define _PDE_VACANT(pdn)	(((pdn) << 10) | _PDE_ATTR)
+
+#define _PTE_ATTR	(_READABLE | _WRITABLE | _NONSECURE)
+#define _PTE_VACANT(addr)	(((addr) >> SMMU_PAGE_SHIFT) | _PTE_ATTR)
+
+#define SMMU_MK_PDIR(page, attr)	\
+		((page_to_phys(page) >> SMMU_PDIR_SHIFT) | (attr))
+#define SMMU_MK_PDE(page, attr)		\
+		(unsigned long)((page_to_phys(page) >> SMMU_PDE_SHIFT) | (attr))
+#define SMMU_EX_PTBL_PAGE(pde)		\
+		pfn_to_page((unsigned long)(pde) & SMMU_PFN_MASK)
+#define SMMU_PFN_TO_PTE(pfn, attr)	(unsigned long)((pfn) | (attr))
+
+#define SMMU_ASID_ENABLE(asid)	((asid) | (1 << 31))
+#define SMMU_ASID_DISABLE	0
+#define SMMU_ASID_ASID(n)	((n) & ~SMMU_ASID_ENABLE(0))
+
+#define smmu_client_enable_hwgrp(c, m)	smmu_client_set_hwgrp(c, m, 1)
+#define smmu_client_disable_hwgrp(c)	smmu_client_set_hwgrp(c, 0, 0)
+#define __smmu_client_enable_hwgrp(c, m) __smmu_client_set_hwgrp(c, m, 1)
+#define __smmu_client_disable_hwgrp(c)	__smmu_client_set_hwgrp(c, 0, 0)
+
+#define HWGRP_INIT(client) [HWGRP_##client] = SMMU_##client##_ASID
+
+static const u32 smmu_hwgrp_asid_reg[] = {
+	HWGRP_INIT(AFI),
+	HWGRP_INIT(AVPC),
+	HWGRP_INIT(DC),
+	HWGRP_INIT(DCB),
+	HWGRP_INIT(EPP),
+	HWGRP_INIT(G2),
+	HWGRP_INIT(HC),
+	HWGRP_INIT(HDA),
+	HWGRP_INIT(ISP),
+	HWGRP_INIT(MPE),
+	HWGRP_INIT(NV),
+	HWGRP_INIT(NV2),
+	HWGRP_INIT(PPCS),
+	HWGRP_INIT(SATA),
+	HWGRP_INIT(VDE),
+	HWGRP_INIT(VI),
+};
+#define HWGRP_ASID_REG(x) (smmu_hwgrp_asid_reg[x])
+
+/*
+ * Per client for address space
+ */
+struct smmu_client {
+	struct device		*dev;
+	struct list_head	list;
+	struct smmu_as		*as;
+	u32			hwgrp;
+};
+
+/*
+ * Per address space
+ */
+struct smmu_as {
+	struct smmu_device	*smmu;	/* back pointer to container */
+	unsigned int		asid;
+	spinlock_t		lock;	/* for pagetable */
+	struct page		*pdir_page;
+	unsigned long		pdir_attr;
+	unsigned long		pde_attr;
+	unsigned long		pte_attr;
+	unsigned int		*pte_count;
+
+	struct list_head	client;
+	spinlock_t		client_lock; /* for client list */
+};
+
+/*
+ * Per SMMU device - IOMMU device
+ */
+struct smmu_device {
+	void __iomem	*regs, *regs_ahbarb;
+	unsigned long	iovmm_base;	/* remappable base address */
+	unsigned long	page_count;	/* total remappable size */
+	spinlock_t	lock;
+	char		*name;
+	struct device	*dev;
+	int		num_as;
+	struct smmu_as	*as;		/* Run-time allocated array */
+	struct page *avp_vector_page;	/* dummy page shared by all AS's */
+
+	/*
+	 * Register image savers for suspend/resume
+	 */
+	unsigned long translation_enable_0;
+	unsigned long translation_enable_1;
+	unsigned long translation_enable_2;
+	unsigned long asid_security;
+};
+
+static struct smmu_device *smmu_handle; /* unique for a system */
+
+/*
+ *	SMMU/AHB register accessors
+ */
+static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
+{
+	return readl(smmu->regs + offs);
+}
+static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
+{
+	writel(val, smmu->regs + offs);
+}
+
+static inline u32 ahb_read(struct smmu_device *smmu, size_t offs)
+{
+	return readl(smmu->regs_ahbarb + offs);
+}
+static inline void ahb_write(struct smmu_device *smmu, u32 val, size_t offs)
+{
+	writel(val, smmu->regs_ahbarb + offs);
+}
+
+#define VA_PAGE_TO_PA(va, page)	\
+	(page_to_phys(page) + ((unsigned long)(va) & ~PAGE_MASK))
+
+#define FLUSH_CPU_DCACHE(va, page, size)	\
+	do {	\
+		unsigned long _pa_ = VA_PAGE_TO_PA(va, page);		\
+		__cpuc_flush_dcache_area((void *)(va), (size_t)(size));	\
+		outer_flush_range(_pa_, _pa_+(size_t)(size));		\
+	} while (0)
+
+/*
+ * Any interaction between any block on PPSB and a block on APB or AHB
+ * must have these read-back barriers to ensure the APB/AHB bus
+ * transaction is complete before initiating activity on the PPSB
+ * block.
+ */
+#define FLUSH_SMMU_REGS(smmu)	smmu_read(smmu, SMMU_CONFIG)
+
+#define smmu_client_hwgrp(c) (u32)((c)->dev->platform_data)
+
+static int __smmu_client_set_hwgrp(struct smmu_client *c,
+				   unsigned long map, int on)
+{
+	int i;
+	struct smmu_as *as = c->as;
+	u32 val, offs, mask = SMMU_ASID_ENABLE(as->asid);
+	struct smmu_device *smmu = as->smmu;
+
+	WARN_ON(!on && map);
+	if (on && !map)
+		return -EINVAL;
+	if (!on)
+		map = smmu_client_hwgrp(c);
+
+	for_each_set_bit(i, &map, HWGRP_COUNT) {
+		offs = HWGRP_ASID_REG(i);
+		val = smmu_read(smmu, offs);
+		if (on) {
+			if (WARN_ON(val & mask))
+				goto err_hw_busy;
+			val |= mask;
+		} else {
+			WARN_ON((val & mask) == mask);
+			val &= ~mask;
+		}
+		smmu_write(smmu, val, offs);
+	}
+	FLUSH_SMMU_REGS(smmu);
+	c->hwgrp = map;
+	return 0;
+
+err_hw_busy:
+	for_each_set_bit(i, &map, HWGRP_COUNT) {
+		offs = HWGRP_ASID_REG(i);
+		val = smmu_read(smmu, offs);
+		val &= ~mask;
+		smmu_write(smmu, val, offs);
+	}
+	return -EBUSY;
+}
+
+static int smmu_client_set_hwgrp(struct smmu_client *c, u32 map, int on)
+{
+	u32 val;
+	unsigned long flags;
+	struct smmu_as *as = c->as;
+	struct smmu_device *smmu = as->smmu;
+
+	spin_lock_irqsave(&smmu->lock, flags);
+	val = __smmu_client_set_hwgrp(c, map, on);
+	spin_unlock_irqrestore(&smmu->lock, flags);
+	return val;
+}
+
+/*
+ * Flush all TLB entries and all PTC entries
+ * Caller must lock smmu
+ */
+static void smmu_flush_regs(struct smmu_device *smmu, int enable)
+{
+	u32 val;
+
+	smmu_write(smmu, SMMU_PTC_FLUSH_TYPE_ALL, SMMU_PTC_FLUSH);
+	FLUSH_SMMU_REGS(smmu);
+	val = SMMU_TLB_FLUSH_VA_MATCH_ALL |
+		SMMU_TLB_FLUSH_ASID_MATCH_disable;
+	smmu_write(smmu, val, SMMU_TLB_FLUSH);
+
+	if (enable)
+		smmu_write(smmu, SMMU_CONFIG_ENABLE, SMMU_CONFIG);
+	FLUSH_SMMU_REGS(smmu);
+}
+
+static void smmu_setup_regs(struct smmu_device *smmu)
+{
+	int i;
+	u32 val;
+
+	for (i = 0; i < smmu->num_as; i++) {
+		struct smmu_as *as = &smmu->as[i];
+		struct smmu_client *c;
+
+		smmu_write(smmu, SMMU_PTB_ASID_CUR(as->asid), SMMU_PTB_ASID);
+		val = as->pdir_page ?
+			SMMU_MK_PDIR(as->pdir_page, as->pdir_attr) :
+			SMMU_PTB_DATA_RESET_VAL;
+		smmu_write(smmu, val, SMMU_PTB_DATA);
+
+		list_for_each_entry(c, &as->client, list)
+			__smmu_client_set_hwgrp(c, c->hwgrp, 1);
+	}
+
+	smmu_write(smmu, smmu->translation_enable_0, SMMU_TRANSLATION_ENABLE_0);
+	smmu_write(smmu, smmu->translation_enable_1, SMMU_TRANSLATION_ENABLE_1);
+	smmu_write(smmu, smmu->translation_enable_2, SMMU_TRANSLATION_ENABLE_2);
+	smmu_write(smmu, smmu->asid_security, SMMU_ASID_SECURITY);
+	smmu_write(smmu, SMMU_TLB_CONFIG_RESET_VAL, SMMU_TLB_CONFIG);
+	smmu_write(smmu, SMMU_PTC_CONFIG_RESET_VAL, SMMU_PTC_CONFIG);
+
+	smmu_flush_regs(smmu, 1);
+
+	val = ahb_read(smmu, AHB_XBAR_CTRL);
+	val |= AHB_XBAR_CTRL_SMMU_INIT_DONE_DONE <<
+		AHB_XBAR_CTRL_SMMU_INIT_DONE_SHIFT;
+	ahb_write(smmu, val, AHB_XBAR_CTRL);
+}
+
+static void flush_ptc_and_tlb(struct smmu_device *smmu,
+		      struct smmu_as *as, dma_addr_t iova,
+		      unsigned long *pte, struct page *page, int is_pde)
+{
+	u32 val;
+	unsigned long tlb_flush_va = is_pde
+		?  SMMU_TLB_FLUSH_VA(iova, SECTION)
+		:  SMMU_TLB_FLUSH_VA(iova, GROUP);
+
+	val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pte, page);
+	smmu_write(smmu, val, SMMU_PTC_FLUSH);
+	FLUSH_SMMU_REGS(smmu);
+	val = tlb_flush_va |
+		SMMU_TLB_FLUSH_ASID_MATCH__ENABLE |
+		(as->asid << SMMU_TLB_FLUSH_ASID_SHIFT);
+	smmu_write(smmu, val, SMMU_TLB_FLUSH);
+	FLUSH_SMMU_REGS(smmu);
+}
+
+static void free_ptbl(struct smmu_as *as, dma_addr_t iova)
+{
+	unsigned long pdn = SMMU_ADDR_TO_PDN(iova);
+	unsigned long *pdir = (unsigned long *)page_address(as->pdir_page);
+
+	if (pdir[pdn] != _PDE_VACANT(pdn)) {
+		dev_dbg(as->smmu->dev, "pdn: %lx\n", pdn);
+
+		ClearPageReserved(SMMU_EX_PTBL_PAGE(pdir[pdn]));
+		__free_page(SMMU_EX_PTBL_PAGE(pdir[pdn]));
+		pdir[pdn] = _PDE_VACANT(pdn);
+		FLUSH_CPU_DCACHE(&pdir[pdn], as->pdir_page, sizeof pdir[pdn]);
+		flush_ptc_and_tlb(as->smmu, as, iova, &pdir[pdn],
+				  as->pdir_page, 1);
+	}
+}
+
+static void free_pdir(struct smmu_as *as)
+{
+	unsigned addr;
+	int count;
+	struct device *dev = as->smmu->dev;
+
+	if (!as->pdir_page)
+		return;
+
+	addr = as->smmu->iovmm_base;
+	count = as->smmu->page_count;
+	while (count-- > 0) {
+		free_ptbl(as, addr);
+		addr += SMMU_PAGE_SIZE * SMMU_PTBL_COUNT;
+	}
+	ClearPageReserved(as->pdir_page);
+	__free_page(as->pdir_page);
+	as->pdir_page = NULL;
+	devm_kfree(dev, as->pte_count);
+	as->pte_count = NULL;
+}
+
+/*
+ * Maps PTBL for given iova and returns the PTE address
+ * Caller must unmap the mapped PTBL returned in *ptbl_page_p
+ */
+static unsigned long *locate_pte(struct smmu_as *as,
+				 dma_addr_t iova, bool allocate,
+				 struct page **ptbl_page_p,
+				 unsigned int **count)
+{
+	unsigned long ptn = SMMU_ADDR_TO_PFN(iova);
+	unsigned long pdn = SMMU_ADDR_TO_PDN(iova);
+	unsigned long *pdir = page_address(as->pdir_page);
+	unsigned long *ptbl;
+
+	if (pdir[pdn] != _PDE_VACANT(pdn)) {
+		/* Mapped entry table already exists */
+		*ptbl_page_p = SMMU_EX_PTBL_PAGE(pdir[pdn]);
+		ptbl = page_address(*ptbl_page_p);
+	} else if (!allocate) {
+		return NULL;
+	} else {
+		int pn;
+		unsigned long addr = SMMU_PDN_TO_ADDR(pdn);
+
+		/* Vacant - allocate a new page table */
+		dev_dbg(as->smmu->dev, "New PTBL pdn: %lx\n", pdn);
+
+		*ptbl_page_p = alloc_page(GFP_ATOMIC);
+		if (!*ptbl_page_p) {
+			dev_err(as->smmu->dev,
+				"failed to allocate smmu_device page table\n");
+			return NULL;
+		}
+		SetPageReserved(*ptbl_page_p);
+		ptbl = (unsigned long *)page_address(*ptbl_page_p);
+		for (pn = 0; pn < SMMU_PTBL_COUNT;
+		     pn++, addr += SMMU_PAGE_SIZE) {
+			ptbl[pn] = _PTE_VACANT(addr);
+		}
+		FLUSH_CPU_DCACHE(ptbl, *ptbl_page_p, SMMU_PTBL_SIZE);
+		pdir[pdn] = SMMU_MK_PDE(*ptbl_page_p,
+					as->pde_attr | _PDE_NEXT);
+		FLUSH_CPU_DCACHE(&pdir[pdn], as->pdir_page, sizeof pdir[pdn]);
+		flush_ptc_and_tlb(as->smmu, as, iova, &pdir[pdn],
+				  as->pdir_page, 1);
+	}
+	*count = &as->pte_count[pdn];
+
+	return &ptbl[ptn % SMMU_PTBL_COUNT];
+}
+
+#ifdef CONFIG_SMMU_SIG_DEBUG
+static void put_signature(struct smmu_as *as,
+			  dma_addr_t iova, unsigned long pfn)
+{
+	struct page *page;
+	unsigned long *vaddr;
+
+	page = pfn_to_page(pfn);
+	vaddr = page_address(page);
+	if (!vaddr)
+		return;
+
+	vaddr[0] = iova;
+	vaddr[1] = pfn << PAGE_SHIFT;
+	FLUSH_CPU_DCACHE(vaddr, page, sizeof(vaddr[0]) * 2);
+}
+#else
+static inline void put_signature(struct smmu_as *as,
+				 unsigned long addr, unsigned long pfn)
+{
+}
+#endif
+
+/*
+ * Caller must lock/unlock as
+ */
+static int alloc_pdir(struct smmu_as *as)
+{
+	unsigned long *pdir;
+	int pdn;
+	u32 val;
+	struct smmu_device *smmu = as->smmu;
+
+	if (as->pdir_page)
+		return 0;
+
+	as->pte_count = devm_kzalloc(smmu->dev,
+		     sizeof(as->pte_count[0]) * SMMU_PDIR_COUNT, GFP_KERNEL);
+	if (!as->pte_count) {
+		dev_err(smmu->dev,
+			"failed to allocate smmu_device PTE cunters\n");
+		return -ENOMEM;
+	}
+	as->pdir_page = alloc_page(GFP_KERNEL | __GFP_DMA);
+	if (!as->pdir_page) {
+		dev_err(smmu->dev,
+			"failed to allocate smmu_device page directory\n");
+		devm_kfree(smmu->dev, as->pte_count);
+		as->pte_count = NULL;
+		return -ENOMEM;
+	}
+	SetPageReserved(as->pdir_page);
+	pdir = page_address(as->pdir_page);
+
+	for (pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++)
+		pdir[pdn] = _PDE_VACANT(pdn);
+	FLUSH_CPU_DCACHE(pdir, as->pdir_page, SMMU_PDIR_SIZE);
+	val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pdir, as->pdir_page);
+	smmu_write(smmu, val, SMMU_PTC_FLUSH);
+	FLUSH_SMMU_REGS(as->smmu);
+	val = SMMU_TLB_FLUSH_VA_MATCH_ALL |
+		SMMU_TLB_FLUSH_ASID_MATCH__ENABLE |
+		(as->asid << SMMU_TLB_FLUSH_ASID_SHIFT);
+	smmu_write(smmu, val, SMMU_TLB_FLUSH);
+	FLUSH_SMMU_REGS(as->smmu);
+
+	return 0;
+}
+
+static void __smmu_iommu_unmap(struct smmu_as *as, dma_addr_t iova)
+{
+	unsigned long *pte;
+	struct page *page;
+	unsigned int *count;
+
+	pte = locate_pte(as, iova, false, &page, &count);
+	if (WARN_ON(!pte))
+		return;
+
+	if (WARN_ON(*pte == _PTE_VACANT(iova)))
+		return;
+
+	*pte = _PTE_VACANT(iova);
+	FLUSH_CPU_DCACHE(pte, page, sizeof(*pte));
+	flush_ptc_and_tlb(as->smmu, as, iova, pte, page, 0);
+	if (!--(*count)) {
+		free_ptbl(as, iova);
+		smmu_flush_regs(as->smmu, 0);
+	}
+}
+
+static void __smmu_iommu_map_pfn(struct smmu_as *as, dma_addr_t iova,
+				 unsigned long pfn)
+{
+	struct smmu_device *smmu = as->smmu;
+	unsigned long *pte;
+	unsigned int *count;
+	struct page *page;
+
+	pte = locate_pte(as, iova, true, &page, &count);
+	if (WARN_ON(!pte))
+		return;
+
+	if (*pte == _PTE_VACANT(iova))
+		(*count)++;
+	*pte = SMMU_PFN_TO_PTE(pfn, as->pte_attr);
+	if (unlikely((*pte == _PTE_VACANT(iova))))
+		(*count)--;
+	FLUSH_CPU_DCACHE(pte, page, sizeof(*pte));
+	flush_ptc_and_tlb(smmu, as, iova, pte, page, 0);
+	put_signature(as, iova, pfn);
+}
+
+static int smmu_iommu_map(struct iommu_domain *domain, unsigned long iova,
+			  phys_addr_t pa, size_t bytes, int prot)
+{
+	struct smmu_as *as = domain->priv;
+	unsigned long pfn = __phys_to_pfn(pa);
+	unsigned long flags;
+
+	dev_dbg(as->smmu->dev, "[%d] %08lx:%08x\n", as->asid, iova, pa);
+
+	if (!pfn_valid(pfn))
+		return -ENOMEM;
+
+	spin_lock_irqsave(&as->lock, flags);
+	__smmu_iommu_map_pfn(as, iova, pfn);
+	spin_unlock_irqrestore(&as->lock, flags);
+	return 0;
+}
+
+static size_t smmu_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
+			       size_t bytes)
+{
+	struct smmu_as *as = domain->priv;
+	unsigned long flags;
+
+	dev_dbg(as->smmu->dev, "[%d] %08lx\n", as->asid, iova);
+
+	spin_lock_irqsave(&as->lock, flags);
+	__smmu_iommu_unmap(as, iova);
+	spin_unlock_irqrestore(&as->lock, flags);
+	return SMMU_PAGE_SIZE;
+}
+
+static phys_addr_t smmu_iommu_iova_to_phys(struct iommu_domain *domain,
+					   unsigned long iova)
+{
+	struct smmu_as *as = domain->priv;
+	unsigned long *pte;
+	unsigned int *count;
+	struct page *page;
+	unsigned long pfn;
+	unsigned long flags;
+
+	spin_lock_irqsave(&as->lock, flags);
+
+	pte = locate_pte(as, iova, true, &page, &count);
+	pfn = *pte & SMMU_PFN_MASK;
+	WARN_ON(!pfn_valid(pfn));
+	dev_dbg(as->smmu->dev,
+		"iova:%08lx pfn:%08lx asid:%d\n", iova, pfn, as->asid);
+
+	spin_unlock_irqrestore(&as->lock, flags);
+	return PFN_PHYS(pfn);
+}
+
+static int smmu_iommu_domain_has_cap(struct iommu_domain *domain,
+				     unsigned long cap)
+{
+	return 0;
+}
+
+static int smmu_iommu_attach_dev(struct iommu_domain *domain,
+				 struct device *dev)
+{
+	struct smmu_as *as = domain->priv;
+	struct smmu_device *smmu = as->smmu;
+	struct smmu_client *client, *c;
+	u32 map;
+	int err;
+
+	client = devm_kzalloc(smmu->dev, sizeof(*c), GFP_KERNEL);
+	if (!client)
+		return -ENOMEM;
+	client->dev = dev;
+	client->as = as;
+	map = (unsigned long)dev->platform_data;
+	if (!map)
+		return -EINVAL;
+
+	err = smmu_client_enable_hwgrp(client, map);
+	if (err)
+		goto err_hwgrp;
+
+	spin_lock(&as->client_lock);
+	list_for_each_entry(c, &as->client, list) {
+		if (c->dev == dev) {
+			dev_err(smmu->dev,
+				"%s is already attached\n", dev_name(c->dev));
+			err = -EINVAL;
+			goto err_client;
+		}
+	}
+	list_add(&client->list, &as->client);
+	spin_unlock(&as->client_lock);
+
+	/*
+	 * Reserve "page zero" for AVP vectors using a common dummy
+	 * page.
+	 */
+	if (map & HWG_AVPC) {
+		struct page *page;
+
+		page = as->smmu->avp_vector_page;
+		__smmu_iommu_map_pfn(as, 0, page_to_pfn(page));
+
+		pr_info("Reserve \"page zero\" for AVP vectors using a common dummy\n");
+	}
+
+	dev_dbg(smmu->dev, "%s is attached\n", dev_name(c->dev));
+	return 0;
+
+err_client:
+	smmu_client_disable_hwgrp(client);
+	spin_unlock(&as->client_lock);
+err_hwgrp:
+	devm_kfree(smmu->dev, client);
+	return err;
+}
+
+static void smmu_iommu_detach_dev(struct iommu_domain *domain,
+				  struct device *dev)
+{
+	struct smmu_as *as = domain->priv;
+	struct smmu_device *smmu = as->smmu;
+	struct smmu_client *c;
+
+	spin_lock(&as->client_lock);
+
+	list_for_each_entry(c, &as->client, list) {
+		if (c->dev == dev) {
+			smmu_client_disable_hwgrp(c);
+			list_del(&c->list);
+			devm_kfree(smmu->dev, c);
+			c->as = NULL;
+			dev_dbg(smmu->dev,
+				"%s is detached\n", dev_name(c->dev));
+			goto out;
+		}
+	}
+	dev_err(smmu->dev, "Couldn't find %s\n", dev_name(c->dev));
+out:
+	spin_unlock(&as->client_lock);
+}
+
+static int smmu_iommu_domain_init(struct iommu_domain *domain)
+{
+	int i;
+	unsigned long flags;
+	struct smmu_as *as;
+	struct smmu_device *smmu = smmu_handle;
+
+	/* Look for a free AS with lock held */
+	for  (i = 0; i < smmu->num_as; i++) {
+		struct smmu_as *tmp = &smmu->as[i];
+
+		spin_lock_irqsave(&tmp->lock, flags);
+		if (!tmp->pdir_page) {
+			as = tmp;
+			goto found;
+		}
+		spin_unlock_irqrestore(&tmp->lock, flags);
+	}
+	dev_err(smmu->dev, "no free AS\n");
+	return -ENODEV;
+
+found:
+	if (alloc_pdir(as) < 0)
+		goto err_alloc_pdir;
+
+	spin_lock(&smmu->lock);
+
+	/* Update PDIR register */
+	smmu_write(smmu, SMMU_PTB_ASID_CUR(as->asid), SMMU_PTB_ASID);
+	smmu_write(smmu,
+		   SMMU_MK_PDIR(as->pdir_page, as->pdir_attr), SMMU_PTB_DATA);
+	FLUSH_SMMU_REGS(smmu);
+
+	spin_unlock(&smmu->lock);
+
+	spin_unlock_irqrestore(&as->lock, flags);
+	domain->priv = as;
+
+	dev_dbg(smmu->dev, "smmu_as@%p\n", as);
+	return 0;
+
+err_alloc_pdir:
+	spin_unlock_irqrestore(&as->lock, flags);
+	return -ENODEV;
+}
+
+static void smmu_iommu_domain_destroy(struct iommu_domain *domain)
+{
+	struct smmu_as *as = domain->priv;
+	struct smmu_device *smmu = as->smmu;
+	unsigned long flags;
+
+	spin_lock_irqsave(&as->lock, flags);
+
+	if (as->pdir_page) {
+		spin_lock(&smmu->lock);
+		smmu_write(smmu, SMMU_PTB_ASID_CUR(as->asid), SMMU_PTB_ASID);
+		smmu_write(smmu, SMMU_PTB_DATA_RESET_VAL, SMMU_PTB_DATA);
+		FLUSH_SMMU_REGS(smmu);
+		spin_unlock(&smmu->lock);
+
+		free_pdir(as);
+	}
+
+	if (!list_empty(&as->client)) {
+		struct smmu_client *c;
+
+		list_for_each_entry(c, &as->client, list)
+			smmu_iommu_detach_dev(domain, c->dev);
+	}
+
+	spin_unlock_irqrestore(&as->lock, flags);
+
+	domain->priv = NULL;
+	dev_dbg(smmu->dev, "smmu_as@%p\n", as);
+}
+
+static struct iommu_ops smmu_iommu_ops = {
+	.domain_init	= smmu_iommu_domain_init,
+	.domain_destroy	= smmu_iommu_domain_destroy,
+	.attach_dev	= smmu_iommu_attach_dev,
+	.detach_dev	= smmu_iommu_detach_dev,
+	.map		= smmu_iommu_map,
+	.unmap		= smmu_iommu_unmap,
+	.iova_to_phys	= smmu_iommu_iova_to_phys,
+	.domain_has_cap	= smmu_iommu_domain_has_cap,
+	.pgsize_bitmap	= SMMU_IOMMU_PGSIZES,
+};
+
+static int tegra_smmu_suspend(struct device *dev)
+{
+	struct smmu_device *smmu = dev_get_drvdata(dev);
+
+	smmu->translation_enable_0 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_0);
+	smmu->translation_enable_1 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_1);
+	smmu->translation_enable_2 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_2);
+	smmu->asid_security = smmu_read(smmu, SMMU_ASID_SECURITY);
+	return 0;
+}
+
+static int tegra_smmu_resume(struct device *dev)
+{
+	struct smmu_device *smmu = dev_get_drvdata(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&smmu->lock, flags);
+	smmu_setup_regs(smmu);
+	spin_unlock_irqrestore(&smmu->lock, flags);
+	return 0;
+}
+
+static int tegra_smmu_probe(struct platform_device *pdev)
+{
+	struct smmu_device *smmu;
+	struct resource *regs, *regs2, *window;
+	struct device *dev = &pdev->dev;
+	int i, err = 0;
+
+	if (smmu_handle)
+		return -EIO;
+
+	BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT);
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	window = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	if (!regs || !regs2 || !window) {
+		dev_err(dev, "No SMMU resources\n");
+		return -ENODEV;
+	}
+
+	smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
+	if (!smmu) {
+		dev_err(dev, "failed to allocate smmu_device\n");
+		return -ENOMEM;
+	}
+
+	smmu->dev = dev;
+	smmu->num_as = SMMU_NUM_ASIDS;
+	smmu->iovmm_base = (unsigned long)window->start;
+	smmu->page_count = resource_size(window) >> SMMU_PAGE_SHIFT;
+	smmu->regs = devm_ioremap(dev, regs->start, resource_size(regs));
+	smmu->regs_ahbarb = devm_ioremap(dev, regs2->start,
+					 resource_size(regs2));
+	if (!smmu->regs || !smmu->regs_ahbarb) {
+		dev_err(dev, "failed to remap SMMU registers\n");
+		err = -ENXIO;
+		goto fail;
+	}
+
+	smmu->translation_enable_0 = ~0;
+	smmu->translation_enable_1 = ~0;
+	smmu->translation_enable_2 = ~0;
+	smmu->asid_security = 0;
+
+	smmu->as = devm_kzalloc(dev,
+			sizeof(smmu->as[0]) * smmu->num_as, GFP_KERNEL);
+	if (!smmu->as) {
+		dev_err(dev, "failed to allocate smmu_as\n");
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	for (i = 0; i < smmu->num_as; i++) {
+		struct smmu_as *as = &smmu->as[i];
+
+		as->smmu = smmu;
+		as->asid = i;
+		as->pdir_attr = _PDIR_ATTR;
+		as->pde_attr = _PDE_ATTR;
+		as->pte_attr = _PTE_ATTR;
+
+		spin_lock_init(&as->lock);
+		INIT_LIST_HEAD(&as->client);
+	}
+	spin_lock_init(&smmu->lock);
+	smmu_setup_regs(smmu);
+	platform_set_drvdata(pdev, smmu);
+
+	smmu->avp_vector_page = alloc_page(GFP_KERNEL);
+	if (!smmu->avp_vector_page)
+		goto fail;
+
+	smmu_handle = smmu;
+	return 0;
+
+fail:
+	if (smmu->avp_vector_page)
+		__free_page(smmu->avp_vector_page);
+	if (smmu->regs)
+		devm_iounmap(dev, smmu->regs);
+	if (smmu->regs_ahbarb)
+		devm_iounmap(dev, smmu->regs_ahbarb);
+	if (smmu && smmu->as) {
+		for (i = 0; i < smmu->num_as; i++) {
+			if (smmu->as[i].pdir_page) {
+				ClearPageReserved(smmu->as[i].pdir_page);
+				__free_page(smmu->as[i].pdir_page);
+			}
+		}
+		devm_kfree(dev, smmu->as);
+	}
+	devm_kfree(dev, smmu);
+	return err;
+}
+
+static int tegra_smmu_remove(struct platform_device *pdev)
+{
+	struct smmu_device *smmu = platform_get_drvdata(pdev);
+	struct device *dev = smmu->dev;
+
+	smmu_write(smmu, SMMU_CONFIG_DISABLE, SMMU_CONFIG);
+	platform_set_drvdata(pdev, NULL);
+	if (smmu->as) {
+		int i;
+
+		for (i = 0; i < smmu->num_as; i++)
+			free_pdir(&smmu->as[i]);
+		devm_kfree(dev, smmu->as);
+	}
+	if (smmu->avp_vector_page)
+		__free_page(smmu->avp_vector_page);
+	if (smmu->regs)
+		devm_iounmap(dev, smmu->regs);
+	if (smmu->regs_ahbarb)
+		devm_iounmap(dev, smmu->regs_ahbarb);
+	devm_kfree(dev, smmu);
+	smmu_handle = NULL;
+	return 0;
+}
+
+const struct dev_pm_ops tegra_smmu_pm_ops = {
+	.suspend	= tegra_smmu_suspend,
+	.resume		= tegra_smmu_resume,
+};
+
+static struct platform_driver tegra_smmu_driver = {
+	.probe		= tegra_smmu_probe,
+	.remove		= tegra_smmu_remove,
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "tegra-smmu",
+		.pm	= &tegra_smmu_pm_ops,
+	},
+};
+
+static int __devinit tegra_smmu_init(void)
+{
+	bus_set_iommu(&platform_bus_type, &smmu_iommu_ops);
+	return platform_driver_register(&tegra_smmu_driver);
+}
+
+static void __exit tegra_smmu_exit(void)
+{
+	platform_driver_unregister(&tegra_smmu_driver);
+}
+
+subsys_initcall(tegra_smmu_init);
+module_exit(tegra_smmu_exit);
+
+MODULE_DESCRIPTION("IOMMU API for SMMU in Tegra30");
+MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index 44b50cc..c21353d 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -18,7 +18,6 @@
 #include <linux/serial.h>
 #include <linux/major.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index 05ed4d0c..c0b8c96 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -891,7 +891,7 @@
 {
 	struct bchannel		*bch;
 
-	if (rq->adr.channel > 2)
+	if (rq->adr.channel == 0 || rq->adr.channel > 2)
 		return -EINVAL;
 	if (rq->protocol == ISDN_P_NONE)
 		return -EINVAL;
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index d055ae7..e2c83a2 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -1962,7 +1962,7 @@
 {
 	struct bchannel		*bch;
 
-	if (rq->adr.channel > 2)
+	if (rq->adr.channel == 0 || rq->adr.channel > 2)
 		return -EINVAL;
 	if (rq->protocol == ISDN_P_NONE)
 		return -EINVAL;
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 6023387..8cde2a0 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -486,7 +486,7 @@
 {
 	struct bchannel		*bch;
 
-	if (rq->adr.channel > 2)
+	if (rq->adr.channel == 0 || rq->adr.channel > 2)
 		return -EINVAL;
 	if (rq->protocol == ISDN_P_NONE)
 		return -EINVAL;
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c
index b47e9be..884369f 100644
--- a/drivers/isdn/hardware/mISDN/mISDNipac.c
+++ b/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -1506,7 +1506,7 @@
 {
 	struct bchannel		*bch;
 
-	if (rq->adr.channel > 2)
+	if (rq->adr.channel == 0 || rq->adr.channel > 2)
 		return -EINVAL;
 	if (rq->protocol == ISDN_P_NONE)
 		return -EINVAL;
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c
index 10446ab..9a6da6e 100644
--- a/drivers/isdn/hardware/mISDN/mISDNisar.c
+++ b/drivers/isdn/hardware/mISDN/mISDNisar.c
@@ -1670,7 +1670,7 @@
 {
 	struct bchannel		*bch;
 
-	if (rq->adr.channel > 2)
+	if (rq->adr.channel == 0 || rq->adr.channel > 2)
 		return -EINVAL;
 	if (rq->protocol == ISDN_P_NONE)
 		return -EINVAL;
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c
index dd6de9f..c726e09 100644
--- a/drivers/isdn/hardware/mISDN/netjet.c
+++ b/drivers/isdn/hardware/mISDN/netjet.c
@@ -860,7 +860,7 @@
 {
 	struct bchannel *bch;
 
-	if (rq->adr.channel > 2)
+	if (rq->adr.channel == 0 || rq->adr.channel > 2)
 		return -EINVAL;
 	if (rq->protocol == ISDN_P_NONE)
 		return -EINVAL;
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c
index 7f1e7ba..2183357 100644
--- a/drivers/isdn/hardware/mISDN/w6692.c
+++ b/drivers/isdn/hardware/mISDN/w6692.c
@@ -1015,7 +1015,7 @@
 {
 	struct bchannel *bch;
 
-	if (rq->adr.channel > 2)
+	if (rq->adr.channel == 0 || rq->adr.channel > 2)
 		return -EINVAL;
 	if (rq->protocol == ISDN_P_NONE)
 		return -EINVAL;
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index 33e3c94..c644557 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -18,7 +18,6 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index fe254e7..a8c4d3f 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -44,7 +44,6 @@
 #include <linux/timer.h>
 #include <linux/ioport.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 68f5049..f0dfc0c 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -44,7 +44,6 @@
 #include <linux/timer.h>
 #include <linux/ioport.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index bfe9428..4deac45 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -25,7 +25,6 @@
 #include <linux/timer.h>
 #include <linux/ioport.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c
index 7f3c54d..c59e8d2 100644
--- a/drivers/isdn/i4l/isdn_bsdcomp.c
+++ b/drivers/isdn/i4l/isdn_bsdcomp.c
@@ -69,7 +69,6 @@
 #include <linux/signal.h>	/* used in new tty drivers */
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 #include <asm/byteorder.h>
 #include <asm/types.h>
 
diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c
index 682911f..a18e639 100644
--- a/drivers/isdn/pcbit/layer2.c
+++ b/drivers/isdn/pcbit/layer2.c
@@ -36,7 +36,6 @@
 
 #include <linux/isdnif.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 
 
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 9ca28fc..ff4b8cf 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -17,7 +17,7 @@
 if NEW_LEDS
 
 config LEDS_CLASS
-	bool "LED Class Support"
+	tristate "LED Class Support"
 	help
 	  This option enables the led sysfs class in /sys/class/leds.  You'll
 	  need this to do anything useful with LEDs.  If unsure, say N.
@@ -69,18 +69,11 @@
 config LEDS_S3C24XX
 	tristate "LED Support for Samsung S3C24XX GPIO LEDs"
 	depends on LEDS_CLASS
-	depends on ARCH_S3C2410
+	depends on ARCH_S3C24XX
 	help
 	  This option enables support for LEDs connected to GPIO lines
 	  on Samsung S3C24XX series CPUs, such as the S3C2410 and S3C2440.
 
-config LEDS_AMS_DELTA
-	tristate "LED Support for the Amstrad Delta (E3)"
-	depends on LEDS_CLASS
-	depends on MACH_AMS_DELTA
-	help
-	  This option enables support for the LEDs on Amstrad Delta (E3).
-
 config LEDS_NET48XX
 	tristate "LED Support for Soekris net48xx series Error LED"
 	depends on LEDS_CLASS
@@ -89,16 +82,6 @@
 	  This option enables support for the Soekris net4801 and net4826 error
 	  LED.
 
-config LEDS_NET5501
-	tristate "LED Support for Soekris net5501 series Error LED"
-	depends on LEDS_TRIGGERS
-	depends on X86 && GPIO_CS5535
-	select LEDS_TRIGGER_DEFAULT_ON
-	default n
-	help
-	  Add support for the Soekris net5501 board (detection, error led
-	  and GPIO).
-
 config LEDS_FSG
 	tristate "LED Support for the Freecom FSG-3"
 	depends on LEDS_CLASS
@@ -244,6 +227,14 @@
 	  LED driver chips accessed via the I2C bus.  Supported
 	  devices include PCA9550, PCA9551, PCA9552, and PCA9553.
 
+config LEDS_PCA9633
+	tristate "LED support for PCA9633 I2C chip"
+	depends on LEDS_CLASS
+	depends on I2C
+	help
+	  This option enables support for LEDs connected to the PCA9633
+	  LED driver chip accessed via the I2C bus.
+
 config LEDS_WM831X_STATUS
 	tristate "LED support for status LEDs on WM831x PMICs"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 1fc6875..890481c 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -12,9 +12,7 @@
 obj-$(CONFIG_LEDS_LM3530)		+= leds-lm3530.o
 obj-$(CONFIG_LEDS_MIKROTIK_RB532)	+= leds-rb532.o
 obj-$(CONFIG_LEDS_S3C24XX)		+= leds-s3c24xx.o
-obj-$(CONFIG_LEDS_AMS_DELTA)		+= leds-ams-delta.o
 obj-$(CONFIG_LEDS_NET48XX)		+= leds-net48xx.o
-obj-$(CONFIG_LEDS_NET5501)		+= leds-net5501.o
 obj-$(CONFIG_LEDS_WRAP)			+= leds-wrap.o
 obj-$(CONFIG_LEDS_COBALT_QUBE)		+= leds-cobalt-qube.o
 obj-$(CONFIG_LEDS_COBALT_RAQ)		+= leds-cobalt-raq.o
@@ -31,6 +29,7 @@
 obj-$(CONFIG_LEDS_OT200)		+= leds-ot200.o
 obj-$(CONFIG_LEDS_FSG)			+= leds-fsg.o
 obj-$(CONFIG_LEDS_PCA955X)		+= leds-pca955x.o
+obj-$(CONFIG_LEDS_PCA9633)		+= leds-pca9633.o
 obj-$(CONFIG_LEDS_DA903X)		+= leds-da903x.o
 obj-$(CONFIG_LEDS_WM831X_STATUS)	+= leds-wm831x-status.o
 obj-$(CONFIG_LEDS_WM8350)		+= leds-wm8350.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 0c8739c..5bff843 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -110,50 +110,6 @@
 	mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
 }
 
-static void led_stop_software_blink(struct led_classdev *led_cdev)
-{
-	/* deactivate previous settings */
-	del_timer_sync(&led_cdev->blink_timer);
-	led_cdev->blink_delay_on = 0;
-	led_cdev->blink_delay_off = 0;
-}
-
-static void led_set_software_blink(struct led_classdev *led_cdev,
-				   unsigned long delay_on,
-				   unsigned long delay_off)
-{
-	int current_brightness;
-
-	current_brightness = led_get_brightness(led_cdev);
-	if (current_brightness)
-		led_cdev->blink_brightness = current_brightness;
-	if (!led_cdev->blink_brightness)
-		led_cdev->blink_brightness = led_cdev->max_brightness;
-
-	if (led_get_trigger_data(led_cdev) &&
-	    delay_on == led_cdev->blink_delay_on &&
-	    delay_off == led_cdev->blink_delay_off)
-		return;
-
-	led_stop_software_blink(led_cdev);
-
-	led_cdev->blink_delay_on = delay_on;
-	led_cdev->blink_delay_off = delay_off;
-
-	/* never on - don't blink */
-	if (!delay_on)
-		return;
-
-	/* never off - just set to brightness */
-	if (!delay_off) {
-		led_set_brightness(led_cdev, led_cdev->blink_brightness);
-		return;
-	}
-
-	mod_timer(&led_cdev->blink_timer, jiffies + 1);
-}
-
-
 /**
  * led_classdev_suspend - suspend an led_classdev.
  * @led_cdev: the led_classdev to suspend.
@@ -262,32 +218,6 @@
 }
 EXPORT_SYMBOL_GPL(led_classdev_unregister);
 
-void led_blink_set(struct led_classdev *led_cdev,
-		   unsigned long *delay_on,
-		   unsigned long *delay_off)
-{
-	del_timer_sync(&led_cdev->blink_timer);
-
-	if (led_cdev->blink_set &&
-	    !led_cdev->blink_set(led_cdev, delay_on, delay_off))
-		return;
-
-	/* blink with 1 Hz as default if nothing specified */
-	if (!*delay_on && !*delay_off)
-		*delay_on = *delay_off = 500;
-
-	led_set_software_blink(led_cdev, *delay_on, *delay_off);
-}
-EXPORT_SYMBOL(led_blink_set);
-
-void led_brightness_set(struct led_classdev *led_cdev,
-			enum led_brightness brightness)
-{
-	led_stop_software_blink(led_cdev);
-	led_cdev->brightness_set(led_cdev, brightness);
-}
-EXPORT_SYMBOL(led_brightness_set);
-
 static int __init leds_init(void)
 {
 	leds_class = class_create(THIS_MODULE, "leds");
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index 016d19f..d686004 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -23,3 +23,73 @@
 
 LIST_HEAD(leds_list);
 EXPORT_SYMBOL_GPL(leds_list);
+
+static void led_stop_software_blink(struct led_classdev *led_cdev)
+{
+	/* deactivate previous settings */
+	del_timer_sync(&led_cdev->blink_timer);
+	led_cdev->blink_delay_on = 0;
+	led_cdev->blink_delay_off = 0;
+}
+
+static void led_set_software_blink(struct led_classdev *led_cdev,
+				   unsigned long delay_on,
+				   unsigned long delay_off)
+{
+	int current_brightness;
+
+	current_brightness = led_get_brightness(led_cdev);
+	if (current_brightness)
+		led_cdev->blink_brightness = current_brightness;
+	if (!led_cdev->blink_brightness)
+		led_cdev->blink_brightness = led_cdev->max_brightness;
+
+	if (led_get_trigger_data(led_cdev) &&
+	    delay_on == led_cdev->blink_delay_on &&
+	    delay_off == led_cdev->blink_delay_off)
+		return;
+
+	led_stop_software_blink(led_cdev);
+
+	led_cdev->blink_delay_on = delay_on;
+	led_cdev->blink_delay_off = delay_off;
+
+	/* never on - don't blink */
+	if (!delay_on)
+		return;
+
+	/* never off - just set to brightness */
+	if (!delay_off) {
+		led_set_brightness(led_cdev, led_cdev->blink_brightness);
+		return;
+	}
+
+	mod_timer(&led_cdev->blink_timer, jiffies + 1);
+}
+
+
+void led_blink_set(struct led_classdev *led_cdev,
+		   unsigned long *delay_on,
+		   unsigned long *delay_off)
+{
+	del_timer_sync(&led_cdev->blink_timer);
+
+	if (led_cdev->blink_set &&
+	    !led_cdev->blink_set(led_cdev, delay_on, delay_off))
+		return;
+
+	/* blink with 1 Hz as default if nothing specified */
+	if (!*delay_on && !*delay_off)
+		*delay_on = *delay_off = 500;
+
+	led_set_software_blink(led_cdev, *delay_on, *delay_off);
+}
+EXPORT_SYMBOL(led_blink_set);
+
+void led_brightness_set(struct led_classdev *led_cdev,
+			enum led_brightness brightness)
+{
+	led_stop_software_blink(led_cdev);
+	led_cdev->brightness_set(led_cdev, brightness);
+}
+EXPORT_SYMBOL(led_brightness_set);
diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c
index 4ca0062..5b61aaf 100644
--- a/drivers/leds/leds-88pm860x.c
+++ b/drivers/leds/leds-88pm860x.c
@@ -114,6 +114,27 @@
 	return ret;
 }
 
+static int led_power_set(struct pm860x_chip *chip, int port, int on)
+{
+	int ret = -EINVAL;
+
+	switch (port) {
+	case PM8606_LED1_RED:
+	case PM8606_LED1_GREEN:
+	case PM8606_LED1_BLUE:
+		ret = on ? pm8606_osc_enable(chip, RGB1_ENABLE) :
+			pm8606_osc_disable(chip, RGB1_ENABLE);
+		break;
+	case PM8606_LED2_RED:
+	case PM8606_LED2_GREEN:
+	case PM8606_LED2_BLUE:
+		ret = on ? pm8606_osc_enable(chip, RGB2_ENABLE) :
+			pm8606_osc_disable(chip, RGB2_ENABLE);
+		break;
+	}
+	return ret;
+}
+
 static void pm860x_led_work(struct work_struct *work)
 {
 
@@ -126,6 +147,7 @@
 	chip = led->chip;
 	mutex_lock(&led->lock);
 	if ((led->current_brightness == 0) && led->brightness) {
+		led_power_set(chip, led->port, 1);
 		if (led->iset) {
 			pm860x_set_bits(led->i2c, __led_off(led->port),
 					LED_CURRENT_MASK, led->iset);
@@ -149,6 +171,7 @@
 					LED_CURRENT_MASK, 0);
 			mask = __blink_ctl_mask(led->port);
 			pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0);
+			led_power_set(chip, led->port, 0);
 		}
 	}
 	led->current_brightness = led->brightness;
diff --git a/drivers/leds/leds-ams-delta.c b/drivers/leds/leds-ams-delta.c
deleted file mode 100644
index 0742835..0000000
--- a/drivers/leds/leds-ams-delta.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * LEDs driver for Amstrad Delta (E3)
- *
- * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
- *
- * 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/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/leds.h>
-#include <plat/board-ams-delta.h>
-
-/*
- * Our context
- */
-struct ams_delta_led {
-	struct led_classdev	cdev;
-	u8			bitmask;
-};
-
-static void ams_delta_led_set(struct led_classdev *led_cdev,
-		enum led_brightness value)
-{
-	struct ams_delta_led *led_dev =
-		container_of(led_cdev, struct ams_delta_led, cdev);
-
-	if (value)
-		ams_delta_latch1_write(led_dev->bitmask, led_dev->bitmask);
-	else
-		ams_delta_latch1_write(led_dev->bitmask, 0);
-}
-
-static struct ams_delta_led ams_delta_leds[] = {
-	{
-		.cdev		= {
-			.name		= "ams-delta::camera",
-			.brightness_set = ams_delta_led_set,
-		},
-		.bitmask	= AMS_DELTA_LATCH1_LED_CAMERA,
-	},
-	{
-		.cdev		= {
-			.name		= "ams-delta::advert",
-			.brightness_set = ams_delta_led_set,
-		},
-		.bitmask	= AMS_DELTA_LATCH1_LED_ADVERT,
-	},
-	{
-		.cdev		= {
-			.name		= "ams-delta::email",
-			.brightness_set = ams_delta_led_set,
-		},
-		.bitmask	= AMS_DELTA_LATCH1_LED_EMAIL,
-	},
-	{
-		.cdev		= {
-			.name		= "ams-delta::handsfree",
-			.brightness_set = ams_delta_led_set,
-		},
-		.bitmask	= AMS_DELTA_LATCH1_LED_HANDSFREE,
-	},
-	{
-		.cdev		= {
-			.name		= "ams-delta::voicemail",
-			.brightness_set = ams_delta_led_set,
-		},
-		.bitmask	= AMS_DELTA_LATCH1_LED_VOICEMAIL,
-	},
-	{
-		.cdev		= {
-			.name		= "ams-delta::voice",
-			.brightness_set = ams_delta_led_set,
-		},
-		.bitmask	= AMS_DELTA_LATCH1_LED_VOICE,
-	},
-};
-
-static int ams_delta_led_probe(struct platform_device *pdev)
-{
-	int i, ret;
-
-	for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i++) {
-		ams_delta_leds[i].cdev.flags |= LED_CORE_SUSPENDRESUME;
-		ret = led_classdev_register(&pdev->dev,
-				&ams_delta_leds[i].cdev);
-		if (ret < 0)
-			goto fail;
-	}
-
-	return 0;
-fail:
-	while (--i >= 0)
-		led_classdev_unregister(&ams_delta_leds[i].cdev);
-	return ret;	
-}
-
-static int ams_delta_led_remove(struct platform_device *pdev)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i++)
-		led_classdev_unregister(&ams_delta_leds[i].cdev);
-
-	return 0;
-}
-
-static struct platform_driver ams_delta_led_driver = {
-	.probe		= ams_delta_led_probe,
-	.remove		= ams_delta_led_remove,
-	.driver		= {
-		.name = "ams-delta-led",
-		.owner = THIS_MODULE,
-	},
-};
-
-module_platform_driver(ams_delta_led_driver);
-
-MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
-MODULE_DESCRIPTION("Amstrad Delta LED driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:ams-delta-led");
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 7df74cb..f4c470a 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/gpio.h>
 #include <linux/leds.h>
 #include <linux/of_platform.h>
 #include <linux/of_gpio.h>
@@ -20,8 +21,6 @@
 #include <linux/workqueue.h>
 #include <linux/module.h>
 
-#include <asm/gpio.h>
-
 struct gpio_led_data {
 	struct led_classdev cdev;
 	unsigned gpio;
diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c
index e59c166..968fd5f 100644
--- a/drivers/leds/leds-lm3530.c
+++ b/drivers/leds/leds-lm3530.c
@@ -26,7 +26,6 @@
 #define LM3530_GEN_CONFIG		0x10
 #define LM3530_ALS_CONFIG		0x20
 #define LM3530_BRT_RAMP_RATE		0x30
-#define LM3530_ALS_ZONE_REG		0x40
 #define LM3530_ALS_IMP_SELECT		0x41
 #define LM3530_BRT_CTRL_REG		0xA0
 #define LM3530_ALS_ZB0_REG		0x60
@@ -38,7 +37,7 @@
 #define LM3530_ALS_Z2T_REG		0x72
 #define LM3530_ALS_Z3T_REG		0x73
 #define LM3530_ALS_Z4T_REG		0x74
-#define LM3530_REG_MAX			15
+#define LM3530_REG_MAX			14
 
 /* General Control Register */
 #define LM3530_EN_I2C_SHIFT		(0)
@@ -80,6 +79,9 @@
 #define LM3530_DEF_ZT_3			(0x33)
 #define LM3530_DEF_ZT_4			(0x19)
 
+/* 7 bits are used for the brightness : LM3530_BRT_CTRL_REG */
+#define MAX_BRIGHTNESS			(127)
+
 struct lm3530_mode_map {
 	const char *mode;
 	enum lm3530_mode mode_val;
@@ -115,7 +117,6 @@
 	LM3530_GEN_CONFIG,
 	LM3530_ALS_CONFIG,
 	LM3530_BRT_RAMP_RATE,
-	LM3530_ALS_ZONE_REG,
 	LM3530_ALS_IMP_SELECT,
 	LM3530_BRT_CTRL_REG,
 	LM3530_ALS_ZB0_REG,
@@ -152,27 +153,35 @@
 	u8 reg_val[LM3530_REG_MAX];
 	u8 zones[LM3530_ALS_ZB_MAX];
 	u32 als_vmin, als_vmax, als_vstep;
-	struct lm3530_platform_data *pltfm = drvdata->pdata;
+	struct lm3530_platform_data *pdata = drvdata->pdata;
 	struct i2c_client *client = drvdata->client;
+	struct lm3530_pwm_data *pwm = &pdata->pwm_data;
 
-	gen_config = (pltfm->brt_ramp_law << LM3530_RAMP_LAW_SHIFT) |
-			((pltfm->max_current & 7) << LM3530_MAX_CURR_SHIFT);
+	gen_config = (pdata->brt_ramp_law << LM3530_RAMP_LAW_SHIFT) |
+			((pdata->max_current & 7) << LM3530_MAX_CURR_SHIFT);
 
-	if (drvdata->mode == LM3530_BL_MODE_MANUAL ||
-	    drvdata->mode == LM3530_BL_MODE_ALS)
-		gen_config |= (LM3530_ENABLE_I2C);
+	switch (drvdata->mode) {
+	case LM3530_BL_MODE_MANUAL:
+	case LM3530_BL_MODE_ALS:
+		gen_config |= LM3530_ENABLE_I2C;
+		break;
+	case LM3530_BL_MODE_PWM:
+		gen_config |= LM3530_ENABLE_PWM | LM3530_ENABLE_PWM_SIMPLE |
+			      (pdata->pwm_pol_hi << LM3530_PWM_POL_SHIFT);
+		break;
+	}
 
 	if (drvdata->mode == LM3530_BL_MODE_ALS) {
-		if (pltfm->als_vmax == 0) {
-			pltfm->als_vmin = 0;
-			pltfm->als_vmax = LM3530_ALS_WINDOW_mV;
+		if (pdata->als_vmax == 0) {
+			pdata->als_vmin = 0;
+			pdata->als_vmax = LM3530_ALS_WINDOW_mV;
 		}
 
-		als_vmin = pltfm->als_vmin;
-		als_vmax = pltfm->als_vmax;
+		als_vmin = pdata->als_vmin;
+		als_vmax = pdata->als_vmax;
 
 		if ((als_vmax - als_vmin) > LM3530_ALS_WINDOW_mV)
-			pltfm->als_vmax = als_vmax =
+			pdata->als_vmax = als_vmax =
 				als_vmin + LM3530_ALS_WINDOW_mV;
 
 		/* n zone boundary makes n+1 zones */
@@ -184,44 +193,41 @@
 					/ 1000;
 
 		als_config =
-			(pltfm->als_avrg_time << LM3530_ALS_AVG_TIME_SHIFT) |
+			(pdata->als_avrg_time << LM3530_ALS_AVG_TIME_SHIFT) |
 			(LM3530_ENABLE_ALS) |
-			(pltfm->als_input_mode << LM3530_ALS_SEL_SHIFT);
+			(pdata->als_input_mode << LM3530_ALS_SEL_SHIFT);
 
 		als_imp_sel =
-			(pltfm->als1_resistor_sel << LM3530_ALS1_IMP_SHIFT) |
-			(pltfm->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT);
+			(pdata->als1_resistor_sel << LM3530_ALS1_IMP_SHIFT) |
+			(pdata->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT);
 
 	}
 
-	if (drvdata->mode == LM3530_BL_MODE_PWM)
-		gen_config |= (LM3530_ENABLE_PWM) |
-				(pltfm->pwm_pol_hi << LM3530_PWM_POL_SHIFT) |
-				(LM3530_ENABLE_PWM_SIMPLE);
-
-	brt_ramp = (pltfm->brt_ramp_fall << LM3530_BRT_RAMP_FALL_SHIFT) |
-			(pltfm->brt_ramp_rise << LM3530_BRT_RAMP_RISE_SHIFT);
+	brt_ramp = (pdata->brt_ramp_fall << LM3530_BRT_RAMP_FALL_SHIFT) |
+			(pdata->brt_ramp_rise << LM3530_BRT_RAMP_RISE_SHIFT);
 
 	if (drvdata->brightness)
 		brightness = drvdata->brightness;
 	else
-		brightness = drvdata->brightness = pltfm->brt_val;
+		brightness = drvdata->brightness = pdata->brt_val;
+
+	if (brightness > drvdata->led_dev.max_brightness)
+		brightness = drvdata->led_dev.max_brightness;
 
 	reg_val[0] = gen_config;	/* LM3530_GEN_CONFIG */
 	reg_val[1] = als_config;	/* LM3530_ALS_CONFIG */
 	reg_val[2] = brt_ramp;		/* LM3530_BRT_RAMP_RATE */
-	reg_val[3] = 0x00;		/* LM3530_ALS_ZONE_REG */
-	reg_val[4] = als_imp_sel;	/* LM3530_ALS_IMP_SELECT */
-	reg_val[5] = brightness;	/* LM3530_BRT_CTRL_REG */
-	reg_val[6] = zones[0];		/* LM3530_ALS_ZB0_REG */
-	reg_val[7] = zones[1];		/* LM3530_ALS_ZB1_REG */
-	reg_val[8] = zones[2];		/* LM3530_ALS_ZB2_REG */
-	reg_val[9] = zones[3];		/* LM3530_ALS_ZB3_REG */
-	reg_val[10] = LM3530_DEF_ZT_0;	/* LM3530_ALS_Z0T_REG */
-	reg_val[11] = LM3530_DEF_ZT_1;	/* LM3530_ALS_Z1T_REG */
-	reg_val[12] = LM3530_DEF_ZT_2;	/* LM3530_ALS_Z2T_REG */
-	reg_val[13] = LM3530_DEF_ZT_3;	/* LM3530_ALS_Z3T_REG */
-	reg_val[14] = LM3530_DEF_ZT_4;	/* LM3530_ALS_Z4T_REG */
+	reg_val[3] = als_imp_sel;	/* LM3530_ALS_IMP_SELECT */
+	reg_val[4] = brightness;	/* LM3530_BRT_CTRL_REG */
+	reg_val[5] = zones[0];		/* LM3530_ALS_ZB0_REG */
+	reg_val[6] = zones[1];		/* LM3530_ALS_ZB1_REG */
+	reg_val[7] = zones[2];		/* LM3530_ALS_ZB2_REG */
+	reg_val[8] = zones[3];		/* LM3530_ALS_ZB3_REG */
+	reg_val[9] = LM3530_DEF_ZT_0;	/* LM3530_ALS_Z0T_REG */
+	reg_val[10] = LM3530_DEF_ZT_1;	/* LM3530_ALS_Z1T_REG */
+	reg_val[11] = LM3530_DEF_ZT_2;	/* LM3530_ALS_Z2T_REG */
+	reg_val[12] = LM3530_DEF_ZT_3;	/* LM3530_ALS_Z3T_REG */
+	reg_val[13] = LM3530_DEF_ZT_4;	/* LM3530_ALS_Z4T_REG */
 
 	if (!drvdata->enable) {
 		ret = regulator_enable(drvdata->regulator);
@@ -234,6 +240,15 @@
 	}
 
 	for (i = 0; i < LM3530_REG_MAX; i++) {
+		/* do not update brightness register when pwm mode */
+		if (lm3530_reg[i] == LM3530_BRT_CTRL_REG &&
+		    drvdata->mode == LM3530_BL_MODE_PWM) {
+			if (pwm->pwm_set_intensity)
+				pwm->pwm_set_intensity(reg_val[i],
+					drvdata->led_dev.max_brightness);
+			continue;
+		}
+
 		ret = i2c_smbus_write_byte_data(client,
 				lm3530_reg[i], reg_val[i]);
 		if (ret)
@@ -249,6 +264,9 @@
 	int err;
 	struct lm3530_data *drvdata =
 	    container_of(led_cdev, struct lm3530_data, led_dev);
+	struct lm3530_platform_data *pdata = drvdata->pdata;
+	struct lm3530_pwm_data *pwm = &pdata->pwm_data;
+	u8 max_brightness = led_cdev->max_brightness;
 
 	switch (drvdata->mode) {
 	case LM3530_BL_MODE_MANUAL:
@@ -264,12 +282,12 @@
 
 		/* set the brightness in brightness control register*/
 		err = i2c_smbus_write_byte_data(drvdata->client,
-				LM3530_BRT_CTRL_REG, brt_val / 2);
+				LM3530_BRT_CTRL_REG, brt_val);
 		if (err)
 			dev_err(&drvdata->client->dev,
 				"Unable to set brightness: %d\n", err);
 		else
-			drvdata->brightness = brt_val / 2;
+			drvdata->brightness = brt_val;
 
 		if (brt_val == 0) {
 			err = regulator_disable(drvdata->regulator);
@@ -282,6 +300,8 @@
 	case LM3530_BL_MODE_ALS:
 		break;
 	case LM3530_BL_MODE_PWM:
+		if (pwm->pwm_set_intensity)
+			pwm->pwm_set_intensity(brt_val, max_brightness);
 		break;
 	default:
 		break;
@@ -291,11 +311,11 @@
 static ssize_t lm3530_mode_get(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
-	struct i2c_client *client = container_of(
-					dev->parent, struct i2c_client, dev);
-	struct lm3530_data *drvdata = i2c_get_clientdata(client);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct lm3530_data *drvdata;
 	int i, len = 0;
 
+	drvdata = container_of(led_cdev, struct lm3530_data, led_dev);
 	for (i = 0; i < ARRAY_SIZE(mode_map); i++)
 		if (drvdata->mode == mode_map[i].mode_val)
 			len += sprintf(buf + len, "[%s] ", mode_map[i].mode);
@@ -310,26 +330,26 @@
 static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute
 				   *attr, const char *buf, size_t size)
 {
-	int err;
-	struct i2c_client *client = container_of(
-					dev->parent, struct i2c_client, dev);
-	struct lm3530_data *drvdata = i2c_get_clientdata(client);
-	int mode;
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct lm3530_data *drvdata;
+	struct lm3530_pwm_data *pwm;
+	u8 max_brightness;
+	int mode, err;
 
+	drvdata = container_of(led_cdev, struct lm3530_data, led_dev);
+	pwm = &drvdata->pdata->pwm_data;
+	max_brightness = led_cdev->max_brightness;
 	mode = lm3530_get_mode_from_str(buf);
 	if (mode < 0) {
 		dev_err(dev, "Invalid mode\n");
 		return -EINVAL;
 	}
 
-	if (mode == LM3530_BL_MODE_MANUAL)
-		drvdata->mode = LM3530_BL_MODE_MANUAL;
-	else if (mode == LM3530_BL_MODE_ALS)
-		drvdata->mode = LM3530_BL_MODE_ALS;
-	else if (mode == LM3530_BL_MODE_PWM) {
-		dev_err(dev, "PWM mode not supported\n");
-		return -EINVAL;
-	}
+	drvdata->mode = mode;
+
+	/* set pwm to low if unnecessary */
+	if (mode != LM3530_BL_MODE_PWM && pwm->pwm_set_intensity)
+		pwm->pwm_set_intensity(0, max_brightness);
 
 	err = lm3530_init_registers(drvdata);
 	if (err) {
@@ -380,6 +400,7 @@
 	drvdata->enable = false;
 	drvdata->led_dev.name = LM3530_LED_DEV;
 	drvdata->led_dev.brightness_set = lm3530_brightness_set;
+	drvdata->led_dev.max_brightness = MAX_BRIGHTNESS;
 
 	i2c_set_clientdata(client, drvdata);
 
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c
index d62a798..410a723 100644
--- a/drivers/leds/leds-lp5521.c
+++ b/drivers/leds/leds-lp5521.c
@@ -81,18 +81,10 @@
 #define LP5521_MASTER_ENABLE		0x40	/* Chip master enable */
 #define LP5521_LOGARITHMIC_PWM		0x80	/* Logarithmic PWM adjustment */
 #define LP5521_EXEC_RUN			0x2A
-
-/* Bits in CONFIG register */
-#define LP5521_PWM_HF			0x40	/* PWM: 0 = 256Hz, 1 = 558Hz */
-#define LP5521_PWRSAVE_EN		0x20	/* 1 = Power save mode */
-#define LP5521_CP_MODE_OFF		0	/* Charge pump (CP) off */
-#define LP5521_CP_MODE_BYPASS		8	/* CP forced to bypass mode */
-#define LP5521_CP_MODE_1X5		0x10	/* CP forced to 1.5x mode */
-#define LP5521_CP_MODE_AUTO		0x18	/* Automatic mode selection */
-#define LP5521_R_TO_BATT		4	/* R out: 0 = CP, 1 = Vbat */
-#define LP5521_CLK_SRC_EXT		0	/* Ext-clk source (CLK_32K) */
-#define LP5521_CLK_INT			1	/* Internal clock */
-#define LP5521_CLK_AUTO			2	/* Automatic clock selection */
+#define LP5521_ENABLE_DEFAULT	\
+	(LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM)
+#define LP5521_ENABLE_RUN_PROGRAM	\
+	(LP5521_ENABLE_DEFAULT | LP5521_EXEC_RUN)
 
 /* Status */
 #define LP5521_EXT_CLK_USED		0x08
@@ -100,6 +92,9 @@
 /* default R channel current register value */
 #define LP5521_REG_R_CURR_DEFAULT	0xAF
 
+/* Pattern Mode */
+#define PATTERN_OFF	0
+
 struct lp5521_engine {
 	int		id;
 	u8		mode;
@@ -241,15 +236,16 @@
 {
 	struct lp5521_chip *chip = i2c_get_clientdata(client);
 	int ret;
+	u8 cfg;
 
 	lp5521_init_engine(chip);
 
 	/* Set all PWMs to direct control mode */
-	ret = lp5521_write(client, LP5521_REG_OP_MODE, 0x3F);
+	ret = lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
 
-	/* Enable auto-powersave, set charge pump to auto, red to battery */
-	ret |= lp5521_write(client, LP5521_REG_CONFIG,
-		LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT);
+	cfg = chip->pdata->update_config ?
+		: (LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT);
+	ret |= lp5521_write(client, LP5521_REG_CONFIG, cfg);
 
 	/* Initialize all channels PWM to zero -> leds off */
 	ret |= lp5521_write(client, LP5521_REG_R_PWM, 0);
@@ -258,8 +254,7 @@
 
 	/* Set engines are set to run state when OP_MODE enables engines */
 	ret |= lp5521_write(client, LP5521_REG_ENABLE,
-			LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM |
-			LP5521_EXEC_RUN);
+			LP5521_ENABLE_RUN_PROGRAM);
 	/* enable takes 500us. 1 - 2 ms leaves some margin */
 	usleep_range(1000, 2000);
 
@@ -310,8 +305,7 @@
 	int ret;
 	u8 buf;
 
-	ret = lp5521_write(client, LP5521_REG_ENABLE,
-			LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM);
+	ret = lp5521_write(client, LP5521_REG_ENABLE, LP5521_ENABLE_DEFAULT);
 	if (ret)
 		return ret;
 	/* enable takes 500us. 1 - 2 ms leaves some margin */
@@ -319,7 +313,7 @@
 	ret = lp5521_read(client, LP5521_REG_ENABLE, &buf);
 	if (ret)
 		return ret;
-	if (buf != (LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM))
+	if (buf != LP5521_ENABLE_DEFAULT)
 		return -ENODEV;
 
 	return 0;
@@ -504,7 +498,7 @@
 	ssize_t ret;
 	unsigned long curr;
 
-	if (strict_strtoul(buf, 0, &curr))
+	if (kstrtoul(buf, 0, &curr))
 		return -EINVAL;
 
 	if (curr > led->max_current)
@@ -536,6 +530,97 @@
 	return sprintf(buf, "%s\n", ret ? "FAIL" : "OK");
 }
 
+static void lp5521_clear_program_memory(struct i2c_client *cl)
+{
+	int i;
+	u8 rgb_mem[] = {
+		LP5521_REG_R_PROG_MEM,
+		LP5521_REG_G_PROG_MEM,
+		LP5521_REG_B_PROG_MEM,
+	};
+
+	for (i = 0; i < ARRAY_SIZE(rgb_mem); i++) {
+		lp5521_write(cl, rgb_mem[i], 0);
+		lp5521_write(cl, rgb_mem[i] + 1, 0);
+	}
+}
+
+static void lp5521_write_program_memory(struct i2c_client *cl,
+				u8 base, u8 *rgb, int size)
+{
+	int i;
+
+	if (!rgb || size <= 0)
+		return;
+
+	for (i = 0; i < size; i++)
+		lp5521_write(cl, base + i, *(rgb + i));
+
+	lp5521_write(cl, base + i, 0);
+	lp5521_write(cl, base + i + 1, 0);
+}
+
+static inline struct lp5521_led_pattern *lp5521_get_pattern
+					(struct lp5521_chip *chip, u8 offset)
+{
+	struct lp5521_led_pattern *ptn;
+	ptn = chip->pdata->patterns + (offset - 1);
+	return ptn;
+}
+
+static void lp5521_run_led_pattern(int mode, struct lp5521_chip *chip)
+{
+	struct lp5521_led_pattern *ptn;
+	struct i2c_client *cl = chip->client;
+	int num_patterns = chip->pdata->num_patterns;
+
+	if (mode > num_patterns || !(chip->pdata->patterns))
+		return;
+
+	if (mode == PATTERN_OFF) {
+		lp5521_write(cl, LP5521_REG_ENABLE, LP5521_ENABLE_DEFAULT);
+		usleep_range(1000, 2000);
+		lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
+	} else {
+		ptn = lp5521_get_pattern(chip, mode);
+		if (!ptn)
+			return;
+
+		lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_LOAD);
+		usleep_range(1000, 2000);
+
+		lp5521_clear_program_memory(cl);
+
+		lp5521_write_program_memory(cl, LP5521_REG_R_PROG_MEM,
+					ptn->r, ptn->size_r);
+		lp5521_write_program_memory(cl, LP5521_REG_G_PROG_MEM,
+					ptn->g, ptn->size_g);
+		lp5521_write_program_memory(cl, LP5521_REG_B_PROG_MEM,
+					ptn->b, ptn->size_b);
+
+		lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_RUN);
+		usleep_range(1000, 2000);
+		lp5521_write(cl, LP5521_REG_ENABLE, LP5521_ENABLE_RUN_PROGRAM);
+	}
+}
+
+static ssize_t store_led_pattern(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t len)
+{
+	struct lp5521_chip *chip = i2c_get_clientdata(to_i2c_client(dev));
+	unsigned long val;
+	int ret;
+
+	ret = strict_strtoul(buf, 16, &val);
+	if (ret)
+		return ret;
+
+	lp5521_run_led_pattern(val, chip);
+
+	return len;
+}
+
 /* led class device attributes */
 static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, show_current, store_current);
 static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
@@ -561,6 +646,7 @@
 static DEVICE_ATTR(engine2_load, S_IWUSR, NULL, store_engine2_load);
 static DEVICE_ATTR(engine3_load, S_IWUSR, NULL, store_engine3_load);
 static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL);
+static DEVICE_ATTR(led_pattern, S_IWUSR, NULL, store_led_pattern);
 
 static struct attribute *lp5521_attributes[] = {
 	&dev_attr_engine1_mode.attr,
@@ -570,6 +656,7 @@
 	&dev_attr_engine1_load.attr,
 	&dev_attr_engine2_load.attr,
 	&dev_attr_engine3_load.attr,
+	&dev_attr_led_pattern.attr,
 	NULL
 };
 
@@ -620,10 +707,15 @@
 		return -EINVAL;
 	}
 
-	snprintf(name, sizeof(name), "%s:channel%d",
-			pdata->label ?: client->name, chan);
 	led->cdev.brightness_set = lp5521_set_brightness;
-	led->cdev.name = name;
+	if (pdata->led_config[chan].name) {
+		led->cdev.name = pdata->led_config[chan].name;
+	} else {
+		snprintf(name, sizeof(name), "%s:channel%d",
+			pdata->label ?: client->name, chan);
+		led->cdev.name = name;
+	}
+
 	res = led_classdev_register(dev, &led->cdev);
 	if (res < 0) {
 		dev_err(dev, "couldn't register led on channel %d\n", chan);
@@ -692,9 +784,9 @@
 	 * otherwise further access to the R G B channels in the
 	 * LP5521_REG_ENABLE register will not have any effect - strange!
 	 */
-	lp5521_read(client, LP5521_REG_R_CURRENT, &buf);
+	ret = lp5521_read(client, LP5521_REG_R_CURRENT, &buf);
 	if (buf != LP5521_REG_R_CURR_DEFAULT) {
-		dev_err(&client->dev, "error in reseting chip\n");
+		dev_err(&client->dev, "error in resetting chip\n");
 		goto fail2;
 	}
 	usleep_range(10000, 20000);
@@ -767,6 +859,7 @@
 	struct lp5521_chip *chip = i2c_get_clientdata(client);
 	int i;
 
+	lp5521_run_led_pattern(PATTERN_OFF, chip);
 	lp5521_unregister_sysfs(client);
 
 	for (i = 0; i < chip->num_leds; i++) {
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c
index 73e791a..857a3e1 100644
--- a/drivers/leds/leds-lp5523.c
+++ b/drivers/leds/leds-lp5523.c
@@ -152,7 +152,7 @@
 
 static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode);
 static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode);
-static int lp5523_load_program(struct lp5523_engine *engine, u8 *pattern);
+static int lp5523_load_program(struct lp5523_engine *engine, const u8 *pattern);
 
 static void lp5523_led_brightness_work(struct work_struct *work);
 
@@ -196,7 +196,7 @@
 	u8 status;
 
 	/* one pattern per engine setting led mux start and stop addresses */
-	u8 pattern[][LP5523_PROGRAM_LENGTH] =  {
+	static const u8 pattern[][LP5523_PROGRAM_LENGTH] =  {
 		{ 0x9c, 0x30, 0x9c, 0xb0, 0x9d, 0x80, 0xd8, 0x00, 0},
 		{ 0x9c, 0x40, 0x9c, 0xc0, 0x9d, 0x80, 0xd8, 0x00, 0},
 		{ 0x9c, 0x50, 0x9c, 0xd0, 0x9d, 0x80, 0xd8, 0x00, 0},
@@ -301,7 +301,7 @@
 	return ret;
 }
 
-static int lp5523_load_program(struct lp5523_engine *engine, u8 *pattern)
+static int lp5523_load_program(struct lp5523_engine *engine, const u8 *pattern)
 {
 	struct lp5523_chip *chip = engine_to_lp5523(engine);
 	struct i2c_client *client = chip->client;
diff --git a/drivers/leds/leds-net5501.c b/drivers/leds/leds-net5501.c
deleted file mode 100644
index 0555d47..0000000
--- a/drivers/leds/leds-net5501.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Soekris board support code
- *
- * Copyright (C) 2008-2009 Tower Technologies
- * Written by Alessandro Zummo <a.zummo@towertech.it>
- *
- * 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/io.h>
-#include <linux/string.h>
-#include <linux/leds.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/module.h>
-
-#include <asm/geode.h>
-
-static const struct gpio_led net5501_leds[] = {
-	{
-		.name = "error",
-		.gpio = 6,
-		.default_trigger = "default-on",
-	},
-};
-
-static struct gpio_led_platform_data net5501_leds_data = {
-	.num_leds = ARRAY_SIZE(net5501_leds),
-	.leds = net5501_leds,
-};
-
-static struct platform_device net5501_leds_dev = {
-	.name = "leds-gpio",
-	.id = -1,
-	.dev.platform_data = &net5501_leds_data,
-};
-
-static void __init init_net5501(void)
-{
-	platform_device_register(&net5501_leds_dev);
-}
-
-struct soekris_board {
-	u16	offset;
-	char	*sig;
-	u8	len;
-	void	(*init)(void);
-};
-
-static struct soekris_board __initdata boards[] = {
-	{ 0xb7b, "net5501", 7, init_net5501 },	/* net5501 v1.33/1.33c */
-	{ 0xb1f, "net5501", 7, init_net5501 },	/* net5501 v1.32i */
-};
-
-static int __init soekris_init(void)
-{
-	int i;
-	unsigned char *rombase, *bios;
-
-	if (!is_geode())
-		return 0;
-
-	rombase = ioremap(0xffff0000, 0xffff);
-	if (!rombase) {
-		printk(KERN_INFO "Soekris net5501 LED driver failed to get rombase");
-		return 0;
-	}
-
-	bios = rombase + 0x20;	/* null terminated */
-
-	if (strncmp(bios, "comBIOS", 7))
-		goto unmap;
-
-	for (i = 0; i < ARRAY_SIZE(boards); i++) {
-		unsigned char *model = rombase + boards[i].offset;
-
-		if (strncmp(model, boards[i].sig, boards[i].len) == 0) {
-			printk(KERN_INFO "Soekris %s: %s\n", model, bios);
-
-			if (boards[i].init)
-				boards[i].init();
-			break;
-		}
-	}
-
-unmap:
-	iounmap(rombase);
-	return 0;
-}
-
-arch_initcall(soekris_init);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-pca9633.c b/drivers/leds/leds-pca9633.c
new file mode 100644
index 0000000..d8926fd
--- /dev/null
+++ b/drivers/leds/leds-pca9633.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2011 bct electronic GmbH
+ *
+ * Author: Peter Meerwald <p.meerwald@bct-electronic.com>
+ *
+ * Based on leds-pca955x.c
+ *
+ * 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.
+ *
+ * LED driver for the PCA9633 I2C LED driver (7-bit slave address 0x62)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/leds.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+
+/* LED select registers determine the source that drives LED outputs */
+#define PCA9633_LED_OFF		0x0	/* LED driver off */
+#define PCA9633_LED_ON		0x1	/* LED driver on */
+#define PCA9633_LED_PWM		0x2	/* Controlled through PWM */
+#define PCA9633_LED_GRP_PWM	0x3	/* Controlled through PWM/GRPPWM */
+
+#define PCA9633_MODE1		0x00
+#define PCA9633_MODE2		0x01
+#define PCA9633_PWM_BASE	0x02
+#define PCA9633_LEDOUT		0x08
+
+static const struct i2c_device_id pca9633_id[] = {
+	{ "pca9633", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pca9633_id);
+
+struct pca9633_led {
+	struct i2c_client *client;
+	struct work_struct work;
+	enum led_brightness brightness;
+	struct led_classdev led_cdev;
+	int led_num; /* 0 .. 3 potentially */
+	char name[32];
+};
+
+static void pca9633_led_work(struct work_struct *work)
+{
+	struct pca9633_led *pca9633 = container_of(work,
+		struct pca9633_led, work);
+	u8 ledout = i2c_smbus_read_byte_data(pca9633->client, PCA9633_LEDOUT);
+	int shift = 2 * pca9633->led_num;
+	u8 mask = 0x3 << shift;
+
+	switch (pca9633->brightness) {
+	case LED_FULL:
+		i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
+			(ledout & ~mask) | (PCA9633_LED_ON << shift));
+		break;
+	case LED_OFF:
+		i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
+			ledout & ~mask);
+		break;
+	default:
+		i2c_smbus_write_byte_data(pca9633->client,
+			PCA9633_PWM_BASE + pca9633->led_num,
+			pca9633->brightness);
+		i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
+			(ledout & ~mask) | (PCA9633_LED_PWM << shift));
+		break;
+	}
+}
+
+static void pca9633_led_set(struct led_classdev *led_cdev,
+	enum led_brightness value)
+{
+	struct pca9633_led *pca9633;
+
+	pca9633 = container_of(led_cdev, struct pca9633_led, led_cdev);
+
+	pca9633->brightness = value;
+
+	/*
+	 * Must use workqueue for the actual I/O since I2C operations
+	 * can sleep.
+	 */
+	schedule_work(&pca9633->work);
+}
+
+static int __devinit pca9633_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	struct pca9633_led *pca9633;
+	struct led_platform_data *pdata;
+	int i, err;
+
+	pdata = client->dev.platform_data;
+
+	if (pdata) {
+		if (pdata->num_leds <= 0 || pdata->num_leds > 4) {
+			dev_err(&client->dev, "board info must claim at most 4 LEDs");
+			return -EINVAL;
+		}
+	}
+
+	pca9633 = kcalloc(4, sizeof(*pca9633), GFP_KERNEL);
+	if (!pca9633)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, pca9633);
+
+	for (i = 0; i < 4; i++) {
+		pca9633[i].client = client;
+		pca9633[i].led_num = i;
+
+		/* Platform data can specify LED names and default triggers */
+		if (pdata && i < pdata->num_leds) {
+			if (pdata->leds[i].name)
+				snprintf(pca9633[i].name,
+					 sizeof(pca9633[i].name), "pca9633:%s",
+					 pdata->leds[i].name);
+			if (pdata->leds[i].default_trigger)
+				pca9633[i].led_cdev.default_trigger =
+					pdata->leds[i].default_trigger;
+		} else {
+			snprintf(pca9633[i].name, sizeof(pca9633[i].name),
+				 "pca9633:%d", i);
+		}
+
+		pca9633[i].led_cdev.name = pca9633[i].name;
+		pca9633[i].led_cdev.brightness_set = pca9633_led_set;
+
+		INIT_WORK(&pca9633[i].work, pca9633_led_work);
+
+		err = led_classdev_register(&client->dev, &pca9633[i].led_cdev);
+		if (err < 0)
+			goto exit;
+	}
+
+	/* Disable LED all-call address and set normal mode */
+	i2c_smbus_write_byte_data(client, PCA9633_MODE1, 0x00);
+
+	/* Turn off LEDs */
+	i2c_smbus_write_byte_data(client, PCA9633_LEDOUT, 0x00);
+
+	return 0;
+
+exit:
+	while (i--) {
+		led_classdev_unregister(&pca9633[i].led_cdev);
+		cancel_work_sync(&pca9633[i].work);
+	}
+
+	kfree(pca9633);
+
+	return err;
+}
+
+static int __devexit pca9633_remove(struct i2c_client *client)
+{
+	struct pca9633_led *pca9633 = i2c_get_clientdata(client);
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		led_classdev_unregister(&pca9633[i].led_cdev);
+		cancel_work_sync(&pca9633[i].work);
+	}
+
+	kfree(pca9633);
+
+	return 0;
+}
+
+static struct i2c_driver pca9633_driver = {
+	.driver = {
+		.name	= "leds-pca9633",
+		.owner	= THIS_MODULE,
+	},
+	.probe	= pca9633_probe,
+	.remove	= __devexit_p(pca9633_remove),
+	.id_table = pca9633_id,
+};
+
+module_i2c_driver(pca9633_driver);
+
+MODULE_AUTHOR("Peter Meerwald <p.meerwald@bct-electronic.com>");
+MODULE_DESCRIPTION("PCA9633 LED driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c
index 133f89f..6c1c14f 100644
--- a/drivers/leds/leds-tca6507.c
+++ b/drivers/leds/leds-tca6507.c
@@ -687,10 +687,9 @@
 			NUM_LEDS);
 		return -ENODEV;
 	}
-	err = -ENOMEM;
 	tca = kzalloc(sizeof(*tca), GFP_KERNEL);
 	if (!tca)
-		goto exit;
+		return -ENOMEM;
 
 	tca->client = client;
 	INIT_WORK(&tca->work, tca6507_work);
@@ -724,11 +723,10 @@
 
 	return 0;
 exit:
-	while (i--)
+	while (i--) {
 		if (tca->leds[i].led_cdev.name)
 			led_classdev_unregister(&tca->leds[i].led_cdev);
-	cancel_work_sync(&tca->work);
-	i2c_set_clientdata(client, NULL);
+	}
 	kfree(tca);
 	return err;
 }
@@ -745,7 +743,6 @@
 	}
 	tca6507_remove_gpio(tca);
 	cancel_work_sync(&tca->work);
-	i2c_set_clientdata(client, NULL);
 	kfree(tca);
 
 	return 0;
diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c
index b6ef8f5..87de8d9 100644
--- a/drivers/macintosh/macio-adb.c
+++ b/drivers/macintosh/macio-adb.c
@@ -14,7 +14,6 @@
 #include <asm/pgtable.h>
 #include <asm/hydra.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index c60d025..fc71723c 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -29,7 +29,6 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/sections.h>
 
 #undef DEBUG
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index 0ff92c2..97cfc5a 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -127,7 +127,6 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/sections.h>
 #include <asm/macio.h>
 
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index 46c4e95..3b4a157 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -41,7 +41,6 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/sections.h>
 #include <asm/macio.h>
 
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 971bc95..86511c5 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -26,7 +26,6 @@
 #include <asm/mac_via.h>
 #endif
 #include <asm/io.h>
-#include <asm/system.h>
 #include <linux/init.h>
 
 static volatile unsigned char __iomem *via;
diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c
index c9570fc..3725f08 100644
--- a/drivers/macintosh/via-macii.c
+++ b/drivers/macintosh/via-macii.c
@@ -34,7 +34,6 @@
 #include <asm/macintosh.h>
 #include <asm/macints.h>
 #include <asm/mac_via.h>
-#include <asm/system.h>
 
 static volatile unsigned char *via;
 
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 6cccd60..22b8ce4 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -50,7 +50,6 @@
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/sections.h>
 #include <asm/irq.h>
 #include <asm/pmac_feature.h>
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
index aeb30d0..a00ee41 100644
--- a/drivers/macintosh/via-pmu68k.c
+++ b/drivers/macintosh/via-pmu68k.c
@@ -37,7 +37,6 @@
 #include <asm/mac_via.h>
 
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index 647c6ad..4d6a90a 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -18,7 +18,6 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/sections.h>
 #include <asm/pmac_low_i2c.h>
 
diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c
index 30e6195..04067e0 100644
--- a/drivers/macintosh/windfarm_pm121.c
+++ b/drivers/macintosh/windfarm_pm121.c
@@ -215,7 +215,6 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/sections.h>
 #include <asm/smu.h>
 
diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c
index 749d174..fc13d0f 100644
--- a/drivers/macintosh/windfarm_pm81.c
+++ b/drivers/macintosh/windfarm_pm81.c
@@ -107,7 +107,6 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/sections.h>
 #include <asm/smu.h>
 
diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c
index 3442732..a9430ed 100644
--- a/drivers/macintosh/windfarm_pm91.c
+++ b/drivers/macintosh/windfarm_pm91.c
@@ -41,7 +41,6 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/sections.h>
 #include <asm/smu.h>
 
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index 43137b4..3c2be51 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -18,7 +18,6 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/sections.h>
 #include <asm/smu.h>
 
diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c
index 3c19350..1cc4e49 100644
--- a/drivers/macintosh/windfarm_smu_sensors.c
+++ b/drivers/macintosh/windfarm_smu_sensors.c
@@ -18,7 +18,6 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/sections.h>
 #include <asm/smu.h>
 
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index faa4741..10f122a 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -277,8 +277,8 @@
          needed for live data migration tools such as 'pvmove'.
 
 config DM_RAID
-       tristate "RAID 1/4/5/6 target (EXPERIMENTAL)"
-       depends on BLK_DEV_DM && EXPERIMENTAL
+       tristate "RAID 1/4/5/6 target"
+       depends on BLK_DEV_DM
        select MD_RAID1
        select MD_RAID456
        select BLK_DEV_MD
@@ -359,8 +359,8 @@
 	If unsure, say N.
 
 config DM_UEVENT
-	bool "DM uevents (EXPERIMENTAL)"
-	depends on BLK_DEV_DM && EXPERIMENTAL
+	bool "DM uevents"
+	depends on BLK_DEV_DM
 	---help---
 	Generate udev events for DM events.
 
@@ -370,4 +370,24 @@
        ---help---
          A target that intermittently fails I/O for debugging purposes.
 
+config DM_VERITY
+	tristate "Verity target support (EXPERIMENTAL)"
+	depends on BLK_DEV_DM && EXPERIMENTAL
+	select CRYPTO
+	select CRYPTO_HASH
+	select DM_BUFIO
+	---help---
+	  This device-mapper target creates a read-only device that
+	  transparently validates the data on one underlying device against
+	  a pre-generated tree of cryptographic checksums stored on a second
+	  device.
+
+	  You'll need to activate the digests you're going to use in the
+	  cryptoapi configuration.
+
+	  To compile this code as a module, choose M here: the module will
+	  be called dm-verity.
+
+	  If unsure, say N.
+
 endif # MD
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 046860c..8b2e0df 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -42,6 +42,7 @@
 obj-$(CONFIG_DM_ZERO)		+= dm-zero.o
 obj-$(CONFIG_DM_RAID)	+= dm-raid.o
 obj-$(CONFIG_DM_THIN_PROVISIONING)	+= dm-thin-pool.o
+obj-$(CONFIG_DM_VERITY)		+= dm-verity.o
 
 ifeq ($(CONFIG_DM_UEVENT),y)
 dm-mod-objs			+= dm-uevent.o
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 045e086..3d0dfa7 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -26,6 +26,7 @@
 #include <linux/file.h>
 #include <linux/mount.h>
 #include <linux/buffer_head.h>
+#include <linux/seq_file.h>
 #include "md.h"
 #include "bitmap.h"
 
@@ -35,31 +36,6 @@
 }
 
 /*
- * just a placeholder - calls kmalloc for bitmap pages
- */
-static unsigned char *bitmap_alloc_page(struct bitmap *bitmap)
-{
-	unsigned char *page;
-
-	page = kzalloc(PAGE_SIZE, GFP_NOIO);
-	if (!page)
-		printk("%s: bitmap_alloc_page FAILED\n", bmname(bitmap));
-	else
-		pr_debug("%s: bitmap_alloc_page: allocated page at %p\n",
-			 bmname(bitmap), page);
-	return page;
-}
-
-/*
- * for now just a placeholder -- just calls kfree for bitmap pages
- */
-static void bitmap_free_page(struct bitmap *bitmap, unsigned char *page)
-{
-	pr_debug("%s: bitmap_free_page: free page %p\n", bmname(bitmap), page);
-	kfree(page);
-}
-
-/*
  * check a page and, if necessary, allocate it (or hijack it if the alloc fails)
  *
  * 1) check to see if this page is allocated, if it's not then try to alloc
@@ -96,7 +72,7 @@
 	/* this page has not been allocated yet */
 
 	spin_unlock_irq(&bitmap->lock);
-	mappage = bitmap_alloc_page(bitmap);
+	mappage = kzalloc(PAGE_SIZE, GFP_NOIO);
 	spin_lock_irq(&bitmap->lock);
 
 	if (mappage == NULL) {
@@ -109,7 +85,7 @@
 	} else if (bitmap->bp[page].map ||
 		   bitmap->bp[page].hijacked) {
 		/* somebody beat us to getting the page */
-		bitmap_free_page(bitmap, mappage);
+		kfree(mappage);
 		return 0;
 	} else {
 
@@ -141,7 +117,7 @@
 		ptr = bitmap->bp[page].map;
 		bitmap->bp[page].map = NULL;
 		bitmap->missing_pages++;
-		bitmap_free_page(bitmap, ptr);
+		kfree(ptr);
 	}
 }
 
@@ -171,7 +147,7 @@
 		did_alloc = 1;
 	}
 
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		if (! test_bit(In_sync, &rdev->flags)
 		    || test_bit(Faulty, &rdev->flags))
 			continue;
@@ -445,18 +421,13 @@
 void bitmap_update_sb(struct bitmap *bitmap)
 {
 	bitmap_super_t *sb;
-	unsigned long flags;
 
 	if (!bitmap || !bitmap->mddev) /* no bitmap for this array */
 		return;
 	if (bitmap->mddev->bitmap_info.external)
 		return;
-	spin_lock_irqsave(&bitmap->lock, flags);
-	if (!bitmap->sb_page) { /* no superblock */
-		spin_unlock_irqrestore(&bitmap->lock, flags);
+	if (!bitmap->sb_page) /* no superblock */
 		return;
-	}
-	spin_unlock_irqrestore(&bitmap->lock, flags);
 	sb = kmap_atomic(bitmap->sb_page);
 	sb->events = cpu_to_le64(bitmap->mddev->events);
 	if (bitmap->mddev->events < bitmap->events_cleared)
@@ -632,26 +603,28 @@
 	/* keep the array size field of the bitmap superblock up to date */
 	sb->sync_size = cpu_to_le64(bitmap->mddev->resync_max_sectors);
 
-	if (!bitmap->mddev->persistent)
-		goto success;
+	if (bitmap->mddev->persistent) {
+		/*
+		 * We have a persistent array superblock, so compare the
+		 * bitmap's UUID and event counter to the mddev's
+		 */
+		if (memcmp(sb->uuid, bitmap->mddev->uuid, 16)) {
+			printk(KERN_INFO
+			       "%s: bitmap superblock UUID mismatch\n",
+			       bmname(bitmap));
+			goto out;
+		}
+		events = le64_to_cpu(sb->events);
+		if (events < bitmap->mddev->events) {
+			printk(KERN_INFO
+			       "%s: bitmap file is out of date (%llu < %llu) "
+			       "-- forcing full recovery\n",
+			       bmname(bitmap), events,
+			       (unsigned long long) bitmap->mddev->events);
+			sb->state |= cpu_to_le32(BITMAP_STALE);
+		}
+	}
 
-	/*
-	 * if we have a persistent array superblock, compare the
-	 * bitmap's UUID and event counter to the mddev's
-	 */
-	if (memcmp(sb->uuid, bitmap->mddev->uuid, 16)) {
-		printk(KERN_INFO "%s: bitmap superblock UUID mismatch\n",
-			bmname(bitmap));
-		goto out;
-	}
-	events = le64_to_cpu(sb->events);
-	if (events < bitmap->mddev->events) {
-		printk(KERN_INFO "%s: bitmap file is out of date (%llu < %llu) "
-			"-- forcing full recovery\n", bmname(bitmap), events,
-			(unsigned long long) bitmap->mddev->events);
-		sb->state |= cpu_to_le32(BITMAP_STALE);
-	}
-success:
 	/* assign fields using values from superblock */
 	bitmap->mddev->bitmap_info.chunksize = chunksize;
 	bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep;
@@ -680,15 +653,10 @@
 			     enum bitmap_mask_op op)
 {
 	bitmap_super_t *sb;
-	unsigned long flags;
 	int old;
 
-	spin_lock_irqsave(&bitmap->lock, flags);
-	if (!bitmap->sb_page) { /* can't set the state */
-		spin_unlock_irqrestore(&bitmap->lock, flags);
+	if (!bitmap->sb_page) /* can't set the state */
 		return 0;
-	}
-	spin_unlock_irqrestore(&bitmap->lock, flags);
 	sb = kmap_atomic(bitmap->sb_page);
 	old = le32_to_cpu(sb->state) & bits;
 	switch (op) {
@@ -870,7 +838,7 @@
 	unsigned long bit;
 	struct page *page;
 	void *kaddr;
-	unsigned long chunk = block >> CHUNK_BLOCK_SHIFT(bitmap);
+	unsigned long chunk = block >> bitmap->chunkshift;
 
 	if (!bitmap->filemap)
 		return;
@@ -1069,10 +1037,10 @@
 		kunmap_atomic(paddr);
 		if (b) {
 			/* if the disk bit is set, set the memory bit */
-			int needed = ((sector_t)(i+1) << (CHUNK_BLOCK_SHIFT(bitmap))
+			int needed = ((sector_t)(i+1) << bitmap->chunkshift
 				      >= start);
 			bitmap_set_memory_bits(bitmap,
-					       (sector_t)i << CHUNK_BLOCK_SHIFT(bitmap),
+					       (sector_t)i << bitmap->chunkshift,
 					       needed);
 			bit_cnt++;
 		}
@@ -1116,7 +1084,7 @@
 
 static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc)
 {
-	sector_t chunk = offset >> CHUNK_BLOCK_SHIFT(bitmap);
+	sector_t chunk = offset >> bitmap->chunkshift;
 	unsigned long page = chunk >> PAGE_COUNTER_SHIFT;
 	bitmap->bp[page].count += inc;
 	bitmap_checkfree(bitmap, page);
@@ -1222,7 +1190,7 @@
 				bitmap->allclean = 0;
 		}
 		bmc = bitmap_get_counter(bitmap,
-					 (sector_t)j << CHUNK_BLOCK_SHIFT(bitmap),
+					 (sector_t)j << bitmap->chunkshift,
 					 &blocks, 0);
 		if (!bmc)
 			j |= PAGE_COUNTER_MASK;
@@ -1231,7 +1199,7 @@
 				/* we can clear the bit */
 				*bmc = 0;
 				bitmap_count_page(bitmap,
-						  (sector_t)j << CHUNK_BLOCK_SHIFT(bitmap),
+						  (sector_t)j << bitmap->chunkshift,
 						  -1);
 
 				/* clear the bit */
@@ -1285,7 +1253,7 @@
 	 * The lock must have been taken with interrupts enabled.
 	 * If !create, we don't release the lock.
 	 */
-	sector_t chunk = offset >> CHUNK_BLOCK_SHIFT(bitmap);
+	sector_t chunk = offset >> bitmap->chunkshift;
 	unsigned long page = chunk >> PAGE_COUNTER_SHIFT;
 	unsigned long pageoff = (chunk & PAGE_COUNTER_MASK) << COUNTER_BYTE_SHIFT;
 	sector_t csize;
@@ -1295,10 +1263,10 @@
 
 	if (bitmap->bp[page].hijacked ||
 	    bitmap->bp[page].map == NULL)
-		csize = ((sector_t)1) << (CHUNK_BLOCK_SHIFT(bitmap) +
+		csize = ((sector_t)1) << (bitmap->chunkshift +
 					  PAGE_COUNTER_SHIFT - 1);
 	else
-		csize = ((sector_t)1) << (CHUNK_BLOCK_SHIFT(bitmap));
+		csize = ((sector_t)1) << bitmap->chunkshift;
 	*blocks = csize - (offset & (csize - 1));
 
 	if (err < 0)
@@ -1424,7 +1392,7 @@
 			set_page_attr(bitmap,
 				      filemap_get_page(
 					      bitmap,
-					      offset >> CHUNK_BLOCK_SHIFT(bitmap)),
+					      offset >> bitmap->chunkshift),
 				      BITMAP_PAGE_PENDING);
 			bitmap->allclean = 0;
 		}
@@ -1512,7 +1480,7 @@
 		else {
 			if (*bmc <= 2) {
 				set_page_attr(bitmap,
-					      filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap)),
+					      filemap_get_page(bitmap, offset >> bitmap->chunkshift),
 					      BITMAP_PAGE_PENDING);
 				bitmap->allclean = 0;
 			}
@@ -1559,7 +1527,7 @@
 
 	bitmap->mddev->curr_resync_completed = sector;
 	set_bit(MD_CHANGE_CLEAN, &bitmap->mddev->flags);
-	sector &= ~((1ULL << CHUNK_BLOCK_SHIFT(bitmap)) - 1);
+	sector &= ~((1ULL << bitmap->chunkshift) - 1);
 	s = 0;
 	while (s < sector && s < bitmap->mddev->resync_max_sectors) {
 		bitmap_end_sync(bitmap, s, &blocks, 0);
@@ -1589,7 +1557,7 @@
 		struct page *page;
 		*bmc = 2 | (needed ? NEEDED_MASK : 0);
 		bitmap_count_page(bitmap, offset, 1);
-		page = filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap));
+		page = filemap_get_page(bitmap, offset >> bitmap->chunkshift);
 		set_page_attr(bitmap, page, BITMAP_PAGE_PENDING);
 		bitmap->allclean = 0;
 	}
@@ -1602,7 +1570,7 @@
 	unsigned long chunk;
 
 	for (chunk = s; chunk <= e; chunk++) {
-		sector_t sec = (sector_t)chunk << CHUNK_BLOCK_SHIFT(bitmap);
+		sector_t sec = (sector_t)chunk << bitmap->chunkshift;
 		bitmap_set_memory_bits(bitmap, sec, 1);
 		spin_lock_irq(&bitmap->lock);
 		bitmap_file_set_bit(bitmap, sec);
@@ -1759,11 +1727,12 @@
 		goto error;
 
 	bitmap->daemon_lastrun = jiffies;
-	bitmap->chunkshift = ffz(~mddev->bitmap_info.chunksize);
+	bitmap->chunkshift = (ffz(~mddev->bitmap_info.chunksize)
+			      - BITMAP_BLOCK_SHIFT);
 
 	/* now that chunksize and chunkshift are set, we can use these macros */
-	chunks = (blocks + CHUNK_BLOCK_RATIO(bitmap) - 1) >>
-			CHUNK_BLOCK_SHIFT(bitmap);
+	chunks = (blocks + bitmap->chunkshift - 1) >>
+			bitmap->chunkshift;
 	pages = (chunks + PAGE_COUNTER_RATIO - 1) / PAGE_COUNTER_RATIO;
 
 	BUG_ON(!pages);
@@ -1836,6 +1805,33 @@
 }
 EXPORT_SYMBOL_GPL(bitmap_load);
 
+void bitmap_status(struct seq_file *seq, struct bitmap *bitmap)
+{
+	unsigned long chunk_kb;
+	unsigned long flags;
+
+	if (!bitmap)
+		return;
+
+	spin_lock_irqsave(&bitmap->lock, flags);
+	chunk_kb = bitmap->mddev->bitmap_info.chunksize >> 10;
+	seq_printf(seq, "bitmap: %lu/%lu pages [%luKB], "
+		   "%lu%s chunk",
+		   bitmap->pages - bitmap->missing_pages,
+		   bitmap->pages,
+		   (bitmap->pages - bitmap->missing_pages)
+		   << (PAGE_SHIFT - 10),
+		   chunk_kb ? chunk_kb : bitmap->mddev->bitmap_info.chunksize,
+		   chunk_kb ? "KB" : "B");
+	if (bitmap->file) {
+		seq_printf(seq, ", file: ");
+		seq_path(seq, &bitmap->file->f_path, " \t\n");
+	}
+
+	seq_printf(seq, "\n");
+	spin_unlock_irqrestore(&bitmap->lock, flags);
+}
+
 static ssize_t
 location_show(struct mddev *mddev, char *page)
 {
@@ -1904,6 +1900,8 @@
 			if (mddev->pers) {
 				mddev->pers->quiesce(mddev, 1);
 				rv = bitmap_create(mddev);
+				if (!rv)
+					rv = bitmap_load(mddev);
 				if (rv) {
 					bitmap_destroy(mddev);
 					mddev->bitmap_info.offset = 0;
diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h
index a15436d..55ca5ae 100644
--- a/drivers/md/bitmap.h
+++ b/drivers/md/bitmap.h
@@ -13,8 +13,6 @@
 #define BITMAP_MAJOR_HI 4
 #define	BITMAP_MAJOR_HOSTENDIAN 3
 
-#define BITMAP_MINOR 39
-
 /*
  * in-memory bitmap:
  *
@@ -101,21 +99,10 @@
 /* same, except a mask value for more efficient bitops */
 #define PAGE_COUNTER_MASK  (PAGE_COUNTER_RATIO - 1)
 
-#define BITMAP_BLOCK_SIZE 512
 #define BITMAP_BLOCK_SHIFT 9
 
 /* how many blocks per chunk? (this is variable) */
 #define CHUNK_BLOCK_RATIO(bitmap) ((bitmap)->mddev->bitmap_info.chunksize >> BITMAP_BLOCK_SHIFT)
-#define CHUNK_BLOCK_SHIFT(bitmap) ((bitmap)->chunkshift - BITMAP_BLOCK_SHIFT)
-#define CHUNK_BLOCK_MASK(bitmap) (CHUNK_BLOCK_RATIO(bitmap) - 1)
-
-/* when hijacked, the counters and bits represent even larger "chunks" */
-/* there will be 1024 chunks represented by each counter in the page pointers */
-#define PAGEPTR_BLOCK_RATIO(bitmap) \
-			(CHUNK_BLOCK_RATIO(bitmap) << PAGE_COUNTER_SHIFT >> 1)
-#define PAGEPTR_BLOCK_SHIFT(bitmap) \
-			(CHUNK_BLOCK_SHIFT(bitmap) + PAGE_COUNTER_SHIFT - 1)
-#define PAGEPTR_BLOCK_MASK(bitmap) (PAGEPTR_BLOCK_RATIO(bitmap) - 1)
 
 #endif
 
@@ -181,12 +168,6 @@
 	unsigned int  count:31;
 };
 
-/* keep track of bitmap file pages that have pending writes on them */
-struct page_list {
-	struct list_head list;
-	struct page *page;
-};
-
 /* the main bitmap structure - one per mddev */
 struct bitmap {
 	struct bitmap_page *bp;
@@ -196,7 +177,7 @@
 	struct mddev *mddev; /* the md device that the bitmap is for */
 
 	/* bitmap chunksize -- how much data does each bit represent? */
-	unsigned long chunkshift; /* chunksize = 2^chunkshift (for bitops) */
+	unsigned long chunkshift; /* chunksize = 2^(chunkshift+9) (for bitops) */
 	unsigned long chunks; /* total number of data chunks for the array */
 
 	__u64	events_cleared;
@@ -245,6 +226,7 @@
 
 void bitmap_print_sb(struct bitmap *bitmap);
 void bitmap_update_sb(struct bitmap *bitmap);
+void bitmap_status(struct seq_file *seq, struct bitmap *bitmap);
 
 int  bitmap_setallbits(struct bitmap *bitmap);
 void bitmap_write_all(struct bitmap *bitmap);
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index b6e58c7..cc06a1e 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -578,7 +578,7 @@
 	struct dm_buffer *b = container_of(bio, struct dm_buffer, bio);
 
 	b->write_error = error;
-	if (error) {
+	if (unlikely(error)) {
 		struct dm_bufio_client *c = b->c;
 		(void)cmpxchg(&c->async_write_error, 0, error);
 	}
@@ -697,13 +697,20 @@
 	dm_bufio_lock(c);
 }
 
+enum new_flag {
+	NF_FRESH = 0,
+	NF_READ = 1,
+	NF_GET = 2,
+	NF_PREFETCH = 3
+};
+
 /*
  * Allocate a new buffer. If the allocation is not possible, wait until
  * some other thread frees a buffer.
  *
  * May drop the lock and regain it.
  */
-static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c)
+static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c, enum new_flag nf)
 {
 	struct dm_buffer *b;
 
@@ -726,6 +733,9 @@
 				return b;
 		}
 
+		if (nf == NF_PREFETCH)
+			return NULL;
+
 		if (!list_empty(&c->reserved_buffers)) {
 			b = list_entry(c->reserved_buffers.next,
 				       struct dm_buffer, lru_list);
@@ -743,9 +753,12 @@
 	}
 }
 
-static struct dm_buffer *__alloc_buffer_wait(struct dm_bufio_client *c)
+static struct dm_buffer *__alloc_buffer_wait(struct dm_bufio_client *c, enum new_flag nf)
 {
-	struct dm_buffer *b = __alloc_buffer_wait_no_callback(c);
+	struct dm_buffer *b = __alloc_buffer_wait_no_callback(c, nf);
+
+	if (!b)
+		return NULL;
 
 	if (c->alloc_callback)
 		c->alloc_callback(b);
@@ -865,32 +878,23 @@
  * Getting a buffer
  *--------------------------------------------------------------*/
 
-enum new_flag {
-	NF_FRESH = 0,
-	NF_READ = 1,
-	NF_GET = 2
-};
-
 static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
-				     enum new_flag nf, struct dm_buffer **bp,
-				     int *need_submit)
+				     enum new_flag nf, int *need_submit)
 {
 	struct dm_buffer *b, *new_b = NULL;
 
 	*need_submit = 0;
 
 	b = __find(c, block);
-	if (b) {
-		b->hold_count++;
-		__relink_lru(b, test_bit(B_DIRTY, &b->state) ||
-			     test_bit(B_WRITING, &b->state));
-		return b;
-	}
+	if (b)
+		goto found_buffer;
 
 	if (nf == NF_GET)
 		return NULL;
 
-	new_b = __alloc_buffer_wait(c);
+	new_b = __alloc_buffer_wait(c, nf);
+	if (!new_b)
+		return NULL;
 
 	/*
 	 * We've had a period where the mutex was unlocked, so need to
@@ -899,10 +903,7 @@
 	b = __find(c, block);
 	if (b) {
 		__free_buffer_wake(new_b);
-		b->hold_count++;
-		__relink_lru(b, test_bit(B_DIRTY, &b->state) ||
-			     test_bit(B_WRITING, &b->state));
-		return b;
+		goto found_buffer;
 	}
 
 	__check_watermark(c);
@@ -922,6 +923,24 @@
 	*need_submit = 1;
 
 	return b;
+
+found_buffer:
+	if (nf == NF_PREFETCH)
+		return NULL;
+	/*
+	 * Note: it is essential that we don't wait for the buffer to be
+	 * read if dm_bufio_get function is used. Both dm_bufio_get and
+	 * dm_bufio_prefetch can be used in the driver request routine.
+	 * If the user called both dm_bufio_prefetch and dm_bufio_get on
+	 * the same buffer, it would deadlock if we waited.
+	 */
+	if (nf == NF_GET && unlikely(test_bit(B_READING, &b->state)))
+		return NULL;
+
+	b->hold_count++;
+	__relink_lru(b, test_bit(B_DIRTY, &b->state) ||
+		     test_bit(B_WRITING, &b->state));
+	return b;
 }
 
 /*
@@ -956,10 +975,10 @@
 	struct dm_buffer *b;
 
 	dm_bufio_lock(c);
-	b = __bufio_new(c, block, nf, bp, &need_submit);
+	b = __bufio_new(c, block, nf, &need_submit);
 	dm_bufio_unlock(c);
 
-	if (!b || IS_ERR(b))
+	if (!b)
 		return b;
 
 	if (need_submit)
@@ -1005,13 +1024,47 @@
 }
 EXPORT_SYMBOL_GPL(dm_bufio_new);
 
+void dm_bufio_prefetch(struct dm_bufio_client *c,
+		       sector_t block, unsigned n_blocks)
+{
+	struct blk_plug plug;
+
+	blk_start_plug(&plug);
+	dm_bufio_lock(c);
+
+	for (; n_blocks--; block++) {
+		int need_submit;
+		struct dm_buffer *b;
+		b = __bufio_new(c, block, NF_PREFETCH, &need_submit);
+		if (unlikely(b != NULL)) {
+			dm_bufio_unlock(c);
+
+			if (need_submit)
+				submit_io(b, READ, b->block, read_endio);
+			dm_bufio_release(b);
+
+			dm_bufio_cond_resched();
+
+			if (!n_blocks)
+				goto flush_plug;
+			dm_bufio_lock(c);
+		}
+
+	}
+
+	dm_bufio_unlock(c);
+
+flush_plug:
+	blk_finish_plug(&plug);
+}
+EXPORT_SYMBOL_GPL(dm_bufio_prefetch);
+
 void dm_bufio_release(struct dm_buffer *b)
 {
 	struct dm_bufio_client *c = b->c;
 
 	dm_bufio_lock(c);
 
-	BUG_ON(test_bit(B_READING, &b->state));
 	BUG_ON(!b->hold_count);
 
 	b->hold_count--;
@@ -1024,6 +1077,7 @@
 		 * invalid buffer.
 		 */
 		if ((b->read_error || b->write_error) &&
+		    !test_bit(B_READING, &b->state) &&
 		    !test_bit(B_WRITING, &b->state) &&
 		    !test_bit(B_DIRTY, &b->state)) {
 			__unlink_buffer(b);
@@ -1041,6 +1095,8 @@
 
 	dm_bufio_lock(c);
 
+	BUG_ON(test_bit(B_READING, &b->state));
+
 	if (!test_and_set_bit(B_DIRTY, &b->state))
 		__relink_lru(b, LIST_DIRTY);
 
diff --git a/drivers/md/dm-bufio.h b/drivers/md/dm-bufio.h
index 5c4c3a0..b142946 100644
--- a/drivers/md/dm-bufio.h
+++ b/drivers/md/dm-bufio.h
@@ -63,6 +63,14 @@
 		   struct dm_buffer **bp);
 
 /*
+ * Prefetch the specified blocks to the cache.
+ * The function starts to read the blocks and returns without waiting for
+ * I/O to finish.
+ */
+void dm_bufio_prefetch(struct dm_bufio_client *c,
+		       sector_t block, unsigned n_blocks);
+
+/*
  * Release a reference obtained with dm_bufio_{read,get,new}. The data
  * pointer and dm_buffer pointer is no longer valid after this call.
  */
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index db6b516..3f06df5 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -176,7 +176,6 @@
 
 #define MIN_IOS        16
 #define MIN_POOL_PAGES 32
-#define MIN_BIO_PAGES  8
 
 static struct kmem_cache *_crypt_io_pool;
 
@@ -848,12 +847,11 @@
 		}
 
 		/*
-		 * if additional pages cannot be allocated without waiting,
-		 * return a partially allocated bio, the caller will then try
-		 * to allocate additional bios while submitting this partial bio
+		 * If additional pages cannot be allocated without waiting,
+		 * return a partially-allocated bio.  The caller will then try
+		 * to allocate more bios while submitting this partial bio.
 		 */
-		if (i == (MIN_BIO_PAGES - 1))
-			gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
+		gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
 
 		len = (size > PAGE_SIZE) ? PAGE_SIZE : size;
 
@@ -1046,16 +1044,14 @@
 	queue_work(cc->io_queue, &io->work);
 }
 
-static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io,
-					  int error, int async)
+static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async)
 {
 	struct bio *clone = io->ctx.bio_out;
 	struct crypt_config *cc = io->target->private;
 
-	if (unlikely(error < 0)) {
+	if (unlikely(io->error < 0)) {
 		crypt_free_buffer_pages(cc, clone);
 		bio_put(clone);
-		io->error = -EIO;
 		crypt_dec_pending(io);
 		return;
 	}
@@ -1106,12 +1102,16 @@
 		sector += bio_sectors(clone);
 
 		crypt_inc_pending(io);
+
 		r = crypt_convert(cc, &io->ctx);
+		if (r < 0)
+			io->error = -EIO;
+
 		crypt_finished = atomic_dec_and_test(&io->ctx.pending);
 
 		/* Encryption was already finished, submit io now */
 		if (crypt_finished) {
-			kcryptd_crypt_write_io_submit(io, r, 0);
+			kcryptd_crypt_write_io_submit(io, 0);
 
 			/*
 			 * If there was an error, do not try next fragments.
@@ -1162,11 +1162,8 @@
 	crypt_dec_pending(io);
 }
 
-static void kcryptd_crypt_read_done(struct dm_crypt_io *io, int error)
+static void kcryptd_crypt_read_done(struct dm_crypt_io *io)
 {
-	if (unlikely(error < 0))
-		io->error = -EIO;
-
 	crypt_dec_pending(io);
 }
 
@@ -1181,9 +1178,11 @@
 			   io->sector);
 
 	r = crypt_convert(cc, &io->ctx);
+	if (r < 0)
+		io->error = -EIO;
 
 	if (atomic_dec_and_test(&io->ctx.pending))
-		kcryptd_crypt_read_done(io, r);
+		kcryptd_crypt_read_done(io);
 
 	crypt_dec_pending(io);
 }
@@ -1204,15 +1203,18 @@
 	if (!error && cc->iv_gen_ops && cc->iv_gen_ops->post)
 		error = cc->iv_gen_ops->post(cc, iv_of_dmreq(cc, dmreq), dmreq);
 
+	if (error < 0)
+		io->error = -EIO;
+
 	mempool_free(req_of_dmreq(cc, dmreq), cc->req_pool);
 
 	if (!atomic_dec_and_test(&ctx->pending))
 		return;
 
 	if (bio_data_dir(io->base_bio) == READ)
-		kcryptd_crypt_read_done(io, error);
+		kcryptd_crypt_read_done(io);
 	else
-		kcryptd_crypt_write_io_submit(io, error, 1);
+		kcryptd_crypt_write_io_submit(io, 1);
 }
 
 static void kcryptd_crypt(struct work_struct *work)
@@ -1413,6 +1415,7 @@
 	char *tmp, *cipher, *chainmode, *ivmode, *ivopts, *keycount;
 	char *cipher_api = NULL;
 	int cpu, ret = -EINVAL;
+	char dummy;
 
 	/* Convert to crypto api definition? */
 	if (strchr(cipher_in, '(')) {
@@ -1434,7 +1437,7 @@
 
 	if (!keycount)
 		cc->tfms_count = 1;
-	else if (sscanf(keycount, "%u", &cc->tfms_count) != 1 ||
+	else if (sscanf(keycount, "%u%c", &cc->tfms_count, &dummy) != 1 ||
 		 !is_power_of_2(cc->tfms_count)) {
 		ti->error = "Bad cipher key count specification";
 		return -EINVAL;
@@ -1579,6 +1582,7 @@
 	int ret;
 	struct dm_arg_set as;
 	const char *opt_string;
+	char dummy;
 
 	static struct dm_arg _args[] = {
 		{0, 1, "Invalid number of feature args"},
@@ -1636,7 +1640,7 @@
 	}
 
 	ret = -EINVAL;
-	if (sscanf(argv[2], "%llu", &tmpll) != 1) {
+	if (sscanf(argv[2], "%llu%c", &tmpll, &dummy) != 1) {
 		ti->error = "Invalid iv_offset sector";
 		goto bad;
 	}
@@ -1647,7 +1651,7 @@
 		goto bad;
 	}
 
-	if (sscanf(argv[4], "%llu", &tmpll) != 1) {
+	if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
 		ti->error = "Invalid device sector";
 		goto bad;
 	}
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
index f18375d..2dc22dd 100644
--- a/drivers/md/dm-delay.c
+++ b/drivers/md/dm-delay.c
@@ -131,6 +131,7 @@
 {
 	struct delay_c *dc;
 	unsigned long long tmpll;
+	char dummy;
 
 	if (argc != 3 && argc != 6) {
 		ti->error = "requires exactly 3 or 6 arguments";
@@ -145,13 +146,13 @@
 
 	dc->reads = dc->writes = 0;
 
-	if (sscanf(argv[1], "%llu", &tmpll) != 1) {
+	if (sscanf(argv[1], "%llu%c", &tmpll, &dummy) != 1) {
 		ti->error = "Invalid device sector";
 		goto bad;
 	}
 	dc->start_read = tmpll;
 
-	if (sscanf(argv[2], "%u", &dc->read_delay) != 1) {
+	if (sscanf(argv[2], "%u%c", &dc->read_delay, &dummy) != 1) {
 		ti->error = "Invalid delay";
 		goto bad;
 	}
@@ -166,13 +167,13 @@
 	if (argc == 3)
 		goto out;
 
-	if (sscanf(argv[4], "%llu", &tmpll) != 1) {
+	if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
 		ti->error = "Invalid write device sector";
 		goto bad_dev_read;
 	}
 	dc->start_write = tmpll;
 
-	if (sscanf(argv[5], "%u", &dc->write_delay) != 1) {
+	if (sscanf(argv[5], "%u%c", &dc->write_delay, &dummy) != 1) {
 		ti->error = "Invalid write delay";
 		goto bad_dev_read;
 	}
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 042e719..aa70f7d 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -283,7 +283,7 @@
 	return 0;
 
 persistent_fail:
-	dm_persistent_snapshot_exit();
+	dm_transient_snapshot_exit();
 transient_fail:
 	return r;
 }
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
index b280c43..ac49c01 100644
--- a/drivers/md/dm-flakey.c
+++ b/drivers/md/dm-flakey.c
@@ -160,6 +160,7 @@
 	unsigned long long tmpll;
 	struct dm_arg_set as;
 	const char *devname;
+	char dummy;
 
 	as.argc = argc;
 	as.argv = argv;
@@ -178,7 +179,7 @@
 
 	devname = dm_shift_arg(&as);
 
-	if (sscanf(dm_shift_arg(&as), "%llu", &tmpll) != 1) {
+	if (sscanf(dm_shift_arg(&as), "%llu%c", &tmpll, &dummy) != 1) {
 		ti->error = "Invalid device sector";
 		goto bad;
 	}
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 1ce84ed..a1a3e6d 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -880,6 +880,7 @@
 	struct hd_geometry geometry;
 	unsigned long indata[4];
 	char *geostr = (char *) param + param->data_start;
+	char dummy;
 
 	md = find_device(param);
 	if (!md)
@@ -891,8 +892,8 @@
 		goto out;
 	}
 
-	x = sscanf(geostr, "%lu %lu %lu %lu", indata,
-		   indata + 1, indata + 2, indata + 3);
+	x = sscanf(geostr, "%lu %lu %lu %lu%c", indata,
+		   indata + 1, indata + 2, indata + 3, &dummy);
 
 	if (x != 4) {
 		DMWARN("Unable to interpret geometry settings.");
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index 9728839..3639eea 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -29,6 +29,7 @@
 {
 	struct linear_c *lc;
 	unsigned long long tmp;
+	char dummy;
 
 	if (argc != 2) {
 		ti->error = "Invalid argument count";
@@ -41,7 +42,7 @@
 		return -ENOMEM;
 	}
 
-	if (sscanf(argv[1], "%llu", &tmp) != 1) {
+	if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1) {
 		ti->error = "dm-linear: Invalid device sector";
 		goto bad;
 	}
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 3b52bb7..65ebaeb 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -369,6 +369,7 @@
 	unsigned int region_count;
 	size_t bitset_size, buf_size;
 	int r;
+	char dummy;
 
 	if (argc < 1 || argc > 2) {
 		DMWARN("wrong number of arguments to dirty region log");
@@ -387,7 +388,7 @@
 		}
 	}
 
-	if (sscanf(argv[0], "%u", &region_size) != 1 ||
+	if (sscanf(argv[0], "%u%c", &region_size, &dummy) != 1 ||
 	    !_check_region_size(ti, region_size)) {
 		DMWARN("invalid region size %s", argv[0]);
 		return -EINVAL;
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 801d92d..922a338 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -226,6 +226,27 @@
 	kfree(m);
 }
 
+static int set_mapinfo(struct multipath *m, union map_info *info)
+{
+	struct dm_mpath_io *mpio;
+
+	mpio = mempool_alloc(m->mpio_pool, GFP_ATOMIC);
+	if (!mpio)
+		return -ENOMEM;
+
+	memset(mpio, 0, sizeof(*mpio));
+	info->ptr = mpio;
+
+	return 0;
+}
+
+static void clear_mapinfo(struct multipath *m, union map_info *info)
+{
+	struct dm_mpath_io *mpio = info->ptr;
+
+	info->ptr = NULL;
+	mempool_free(mpio, m->mpio_pool);
+}
 
 /*-----------------------------------------------
  * Path selection
@@ -341,13 +362,14 @@
 }
 
 static int map_io(struct multipath *m, struct request *clone,
-		  struct dm_mpath_io *mpio, unsigned was_queued)
+		  union map_info *map_context, unsigned was_queued)
 {
 	int r = DM_MAPIO_REMAPPED;
 	size_t nr_bytes = blk_rq_bytes(clone);
 	unsigned long flags;
 	struct pgpath *pgpath;
 	struct block_device *bdev;
+	struct dm_mpath_io *mpio = map_context->ptr;
 
 	spin_lock_irqsave(&m->lock, flags);
 
@@ -423,7 +445,6 @@
 {
 	int r;
 	unsigned long flags;
-	struct dm_mpath_io *mpio;
 	union map_info *info;
 	struct request *clone, *n;
 	LIST_HEAD(cl);
@@ -436,16 +457,15 @@
 		list_del_init(&clone->queuelist);
 
 		info = dm_get_rq_mapinfo(clone);
-		mpio = info->ptr;
 
-		r = map_io(m, clone, mpio, 1);
+		r = map_io(m, clone, info, 1);
 		if (r < 0) {
-			mempool_free(mpio, m->mpio_pool);
+			clear_mapinfo(m, info);
 			dm_kill_unmapped_request(clone, r);
 		} else if (r == DM_MAPIO_REMAPPED)
 			dm_dispatch_request(clone);
 		else if (r == DM_MAPIO_REQUEUE) {
-			mempool_free(mpio, m->mpio_pool);
+			clear_mapinfo(m, info);
 			dm_requeue_unmapped_request(clone);
 		}
 	}
@@ -908,20 +928,16 @@
 			 union map_info *map_context)
 {
 	int r;
-	struct dm_mpath_io *mpio;
 	struct multipath *m = (struct multipath *) ti->private;
 
-	mpio = mempool_alloc(m->mpio_pool, GFP_ATOMIC);
-	if (!mpio)
+	if (set_mapinfo(m, map_context) < 0)
 		/* ENOMEM, requeue */
 		return DM_MAPIO_REQUEUE;
-	memset(mpio, 0, sizeof(*mpio));
 
-	map_context->ptr = mpio;
 	clone->cmd_flags |= REQ_FAILFAST_TRANSPORT;
-	r = map_io(m, clone, mpio, 0);
+	r = map_io(m, clone, map_context, 0);
 	if (r < 0 || r == DM_MAPIO_REQUEUE)
-		mempool_free(mpio, m->mpio_pool);
+		clear_mapinfo(m, map_context);
 
 	return r;
 }
@@ -1054,8 +1070,9 @@
 	struct priority_group *pg;
 	unsigned pgnum;
 	unsigned long flags;
+	char dummy;
 
-	if (!pgstr || (sscanf(pgstr, "%u", &pgnum) != 1) || !pgnum ||
+	if (!pgstr || (sscanf(pgstr, "%u%c", &pgnum, &dummy) != 1) || !pgnum ||
 	    (pgnum > m->nr_priority_groups)) {
 		DMWARN("invalid PG number supplied to switch_pg_num");
 		return -EINVAL;
@@ -1085,8 +1102,9 @@
 {
 	struct priority_group *pg;
 	unsigned pgnum;
+	char dummy;
 
-	if (!pgstr || (sscanf(pgstr, "%u", &pgnum) != 1) || !pgnum ||
+	if (!pgstr || (sscanf(pgstr, "%u%c", &pgnum, &dummy) != 1) || !pgnum ||
 	    (pgnum > m->nr_priority_groups)) {
 		DMWARN("invalid PG number supplied to bypass_pg");
 		return -EINVAL;
@@ -1261,13 +1279,15 @@
 	struct path_selector *ps;
 	int r;
 
+	BUG_ON(!mpio);
+
 	r  = do_end_io(m, clone, error, mpio);
 	if (pgpath) {
 		ps = &pgpath->pg->ps;
 		if (ps->type->end_io)
 			ps->type->end_io(ps, &pgpath->path, mpio->nr_bytes);
 	}
-	mempool_free(mpio, m->mpio_pool);
+	clear_mapinfo(m, map_context);
 
 	return r;
 }
diff --git a/drivers/md/dm-queue-length.c b/drivers/md/dm-queue-length.c
index 03a837a..3941fae 100644
--- a/drivers/md/dm-queue-length.c
+++ b/drivers/md/dm-queue-length.c
@@ -112,6 +112,7 @@
 	struct selector *s = ps->context;
 	struct path_info *pi;
 	unsigned repeat_count = QL_MIN_IO;
+	char dummy;
 
 	/*
 	 * Arguments: [<repeat_count>]
@@ -123,7 +124,7 @@
 		return -EINVAL;
 	}
 
-	if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
+	if ((argc == 1) && (sscanf(argv[0], "%u%c", &repeat_count, &dummy) != 1)) {
 		*error = "queue-length ps: invalid repeat count";
 		return -EINVAL;
 	}
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 787022c..b0ba524 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -604,7 +604,9 @@
 		return 0;
 
 	if (!sync_page_io(rdev, 0, size, rdev->sb_page, READ, 1)) {
-		DMERR("Failed to read device superblock");
+		DMERR("Failed to read superblock of device at position %d",
+		      rdev->raid_disk);
+		set_bit(Faulty, &rdev->flags);
 		return -EINVAL;
 	}
 
@@ -615,14 +617,14 @@
 
 static void super_sync(struct mddev *mddev, struct md_rdev *rdev)
 {
-	struct md_rdev *r, *t;
+	struct md_rdev *r;
 	uint64_t failed_devices;
 	struct dm_raid_superblock *sb;
 
 	sb = page_address(rdev->sb_page);
 	failed_devices = le64_to_cpu(sb->failed_devices);
 
-	rdev_for_each(r, t, mddev)
+	rdev_for_each(r, mddev)
 		if ((r->raid_disk >= 0) && test_bit(Faulty, &r->flags))
 			failed_devices |= (1ULL << r->raid_disk);
 
@@ -707,7 +709,7 @@
 	struct dm_raid_superblock *sb;
 	uint32_t new_devs = 0;
 	uint32_t rebuilds = 0;
-	struct md_rdev *r, *t;
+	struct md_rdev *r;
 	struct dm_raid_superblock *sb2;
 
 	sb = page_address(rdev->sb_page);
@@ -750,7 +752,7 @@
 	 *    case the In_sync bit will /not/ be set and
 	 *    recovery_cp must be MaxSector.
 	 */
-	rdev_for_each(r, t, mddev) {
+	rdev_for_each(r, mddev) {
 		if (!test_bit(In_sync, &r->flags)) {
 			DMINFO("Device %d specified for rebuild: "
 			       "Clearing superblock", r->raid_disk);
@@ -782,7 +784,7 @@
 	 * Now we set the Faulty bit for those devices that are
 	 * recorded in the superblock as failed.
 	 */
-	rdev_for_each(r, t, mddev) {
+	rdev_for_each(r, mddev) {
 		if (!r->sb_page)
 			continue;
 		sb2 = page_address(r->sb_page);
@@ -855,11 +857,27 @@
 static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
 {
 	int ret;
-	struct md_rdev *rdev, *freshest, *tmp;
+	unsigned redundancy = 0;
+	struct raid_dev *dev;
+	struct md_rdev *rdev, *freshest;
 	struct mddev *mddev = &rs->md;
 
+	switch (rs->raid_type->level) {
+	case 1:
+		redundancy = rs->md.raid_disks - 1;
+		break;
+	case 4:
+	case 5:
+	case 6:
+		redundancy = rs->raid_type->parity_devs;
+		break;
+	default:
+		ti->error = "Unknown RAID type";
+		return -EINVAL;
+	}
+
 	freshest = NULL;
-	rdev_for_each(rdev, tmp, mddev) {
+	rdev_for_each(rdev, mddev) {
 		if (!rdev->meta_bdev)
 			continue;
 
@@ -872,6 +890,37 @@
 		case 0:
 			break;
 		default:
+			dev = container_of(rdev, struct raid_dev, rdev);
+			if (redundancy--) {
+				if (dev->meta_dev)
+					dm_put_device(ti, dev->meta_dev);
+
+				dev->meta_dev = NULL;
+				rdev->meta_bdev = NULL;
+
+				if (rdev->sb_page)
+					put_page(rdev->sb_page);
+
+				rdev->sb_page = NULL;
+
+				rdev->sb_loaded = 0;
+
+				/*
+				 * We might be able to salvage the data device
+				 * even though the meta device has failed.  For
+				 * now, we behave as though '- -' had been
+				 * set for this device in the table.
+				 */
+				if (dev->data_dev)
+					dm_put_device(ti, dev->data_dev);
+
+				dev->data_dev = NULL;
+				rdev->bdev = NULL;
+
+				list_del(&rdev->same_set);
+
+				continue;
+			}
 			ti->error = "Failed to load superblock";
 			return ret;
 		}
@@ -888,7 +937,7 @@
 	if (super_validate(mddev, freshest))
 		return -EINVAL;
 
-	rdev_for_each(rdev, tmp, mddev)
+	rdev_for_each(rdev, mddev)
 		if ((rdev != freshest) && super_validate(mddev, rdev))
 			return -EINVAL;
 
@@ -1214,7 +1263,7 @@
 
 static struct target_type raid_target = {
 	.name = "raid",
-	.version = {1, 1, 0},
+	.version = {1, 2, 0},
 	.module = THIS_MODULE,
 	.ctr = raid_ctr,
 	.dtr = raid_dtr,
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 9bfd057..d039de8 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -924,8 +924,9 @@
 		      unsigned int mirror, char **argv)
 {
 	unsigned long long offset;
+	char dummy;
 
-	if (sscanf(argv[1], "%llu", &offset) != 1) {
+	if (sscanf(argv[1], "%llu%c", &offset, &dummy) != 1) {
 		ti->error = "Invalid offset";
 		return -EINVAL;
 	}
@@ -953,13 +954,14 @@
 {
 	unsigned param_count;
 	struct dm_dirty_log *dl;
+	char dummy;
 
 	if (argc < 2) {
 		ti->error = "Insufficient mirror log arguments";
 		return NULL;
 	}
 
-	if (sscanf(argv[1], "%u", &param_count) != 1) {
+	if (sscanf(argv[1], "%u%c", &param_count, &dummy) != 1) {
 		ti->error = "Invalid mirror log argument count";
 		return NULL;
 	}
@@ -986,13 +988,14 @@
 {
 	unsigned num_features;
 	struct dm_target *ti = ms->ti;
+	char dummy;
 
 	*args_used = 0;
 
 	if (!argc)
 		return 0;
 
-	if (sscanf(argv[0], "%u", &num_features) != 1) {
+	if (sscanf(argv[0], "%u%c", &num_features, &dummy) != 1) {
 		ti->error = "Invalid number of features";
 		return -EINVAL;
 	}
@@ -1036,6 +1039,7 @@
 	unsigned int nr_mirrors, m, args_used;
 	struct mirror_set *ms;
 	struct dm_dirty_log *dl;
+	char dummy;
 
 	dl = create_dirty_log(ti, argc, argv, &args_used);
 	if (!dl)
@@ -1044,7 +1048,7 @@
 	argv += args_used;
 	argc -= args_used;
 
-	if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 ||
+	if (!argc || sscanf(argv[0], "%u%c", &nr_mirrors, &dummy) != 1 ||
 	    nr_mirrors < 2 || nr_mirrors > DM_KCOPYD_MAX_REGIONS + 1) {
 		ti->error = "Invalid number of mirrors";
 		dm_dirty_log_destroy(dl);
diff --git a/drivers/md/dm-round-robin.c b/drivers/md/dm-round-robin.c
index 27f1d42..6ab1192 100644
--- a/drivers/md/dm-round-robin.c
+++ b/drivers/md/dm-round-robin.c
@@ -114,6 +114,7 @@
 	struct selector *s = (struct selector *) ps->context;
 	struct path_info *pi;
 	unsigned repeat_count = RR_MIN_IO;
+	char dummy;
 
 	if (argc > 1) {
 		*error = "round-robin ps: incorrect number of arguments";
@@ -121,7 +122,7 @@
 	}
 
 	/* First path argument is number of I/Os before switching path */
-	if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
+	if ((argc == 1) && (sscanf(argv[0], "%u%c", &repeat_count, &dummy) != 1)) {
 		*error = "round-robin ps: invalid repeat count";
 		return -EINVAL;
 	}
diff --git a/drivers/md/dm-service-time.c b/drivers/md/dm-service-time.c
index 59883bd..9df8f6b 100644
--- a/drivers/md/dm-service-time.c
+++ b/drivers/md/dm-service-time.c
@@ -110,6 +110,7 @@
 	struct path_info *pi;
 	unsigned repeat_count = ST_MIN_IO;
 	unsigned relative_throughput = 1;
+	char dummy;
 
 	/*
 	 * Arguments: [<repeat_count> [<relative_throughput>]]
@@ -128,13 +129,13 @@
 		return -EINVAL;
 	}
 
-	if (argc && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
+	if (argc && (sscanf(argv[0], "%u%c", &repeat_count, &dummy) != 1)) {
 		*error = "service-time ps: invalid repeat count";
 		return -EINVAL;
 	}
 
 	if ((argc == 2) &&
-	    (sscanf(argv[1], "%u", &relative_throughput) != 1 ||
+	    (sscanf(argv[1], "%u%c", &relative_throughput, &dummy) != 1 ||
 	     relative_throughput > ST_MAX_RELATIVE_THROUGHPUT)) {
 		*error = "service-time ps: invalid relative_throughput value";
 		return -EINVAL;
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index 3d80cf0..35c94ff 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -75,8 +75,9 @@
 		      unsigned int stripe, char **argv)
 {
 	unsigned long long start;
+	char dummy;
 
-	if (sscanf(argv[1], "%llu", &start) != 1)
+	if (sscanf(argv[1], "%llu%c", &start, &dummy) != 1)
 		return -EINVAL;
 
 	if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table),
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 63cc542..2e227fb 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -268,8 +268,7 @@
 	vfree(t->highs);
 
 	/* free the device list */
-	if (t->devices.next != &t->devices)
-		free_devices(&t->devices);
+	free_devices(&t->devices);
 
 	dm_free_md_mempools(t->mempools);
 
@@ -464,10 +463,11 @@
 	struct dm_dev_internal *dd;
 	unsigned int major, minor;
 	struct dm_table *t = ti->table;
+	char dummy;
 
 	BUG_ON(!t);
 
-	if (sscanf(path, "%u:%u", &major, &minor) == 2) {
+	if (sscanf(path, "%u:%u%c", &major, &minor, &dummy) == 2) {
 		/* Extract the major/minor numbers */
 		dev = MKDEV(major, minor);
 		if (MAJOR(dev) != major || MINOR(dev) != minor)
@@ -842,9 +842,10 @@
 			     unsigned *value, char **error, unsigned grouped)
 {
 	const char *arg_str = dm_shift_arg(arg_set);
+	char dummy;
 
 	if (!arg_str ||
-	    (sscanf(arg_str, "%u", value) != 1) ||
+	    (sscanf(arg_str, "%u%c", value, &dummy) != 1) ||
 	    (*value < arg->min) ||
 	    (*value > arg->max) ||
 	    (grouped && arg_set->argc < *value)) {
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 237571a..737d388 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -614,7 +614,7 @@
 	if (r < 0)
 		goto out;
 
-	r = dm_sm_root_size(pmd->metadata_sm, &data_len);
+	r = dm_sm_root_size(pmd->data_sm, &data_len);
 	if (r < 0)
 		goto out;
 
@@ -713,6 +713,9 @@
 	if (r)
 		goto bad;
 
+	if (bdev_size > THIN_METADATA_MAX_SECTORS)
+		bdev_size = THIN_METADATA_MAX_SECTORS;
+
 	disk_super = dm_block_data(sblock);
 	disk_super->magic = cpu_to_le64(THIN_SUPERBLOCK_MAGIC);
 	disk_super->version = cpu_to_le32(THIN_VERSION);
diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h
index 859c168..ed4725e 100644
--- a/drivers/md/dm-thin-metadata.h
+++ b/drivers/md/dm-thin-metadata.h
@@ -11,6 +11,19 @@
 
 #define THIN_METADATA_BLOCK_SIZE 4096
 
+/*
+ * The metadata device is currently limited in size.
+ *
+ * We have one block of index, which can hold 255 index entries.  Each
+ * index entry contains allocation info about 16k metadata blocks.
+ */
+#define THIN_METADATA_MAX_SECTORS (255 * (1 << 14) * (THIN_METADATA_BLOCK_SIZE / (1 << SECTOR_SHIFT)))
+
+/*
+ * A metadata device larger than 16GB triggers a warning.
+ */
+#define THIN_METADATA_MAX_SECTORS_WARNING (16 * (1024 * 1024 * 1024 >> SECTOR_SHIFT))
+
 /*----------------------------------------------------------------*/
 
 struct dm_pool_metadata;
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index c308757..213ae32 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -23,6 +23,7 @@
 #define DEFERRED_SET_SIZE 64
 #define MAPPING_POOL_SIZE 1024
 #define PRISON_CELLS 1024
+#define COMMIT_PERIOD HZ
 
 /*
  * The block size of the device holding pool data must be
@@ -32,16 +33,6 @@
 #define DATA_DEV_BLOCK_SIZE_MAX_SECTORS (1024 * 1024 * 1024 >> SECTOR_SHIFT)
 
 /*
- * The metadata device is currently limited in size.  The limitation is
- * checked lower down in dm-space-map-metadata, but we also check it here
- * so we can fail early.
- *
- * We have one block of index, which can hold 255 index entries.  Each
- * index entry contains allocation info about 16k metadata blocks.
- */
-#define METADATA_DEV_MAX_SECTORS (255 * (1 << 14) * (THIN_METADATA_BLOCK_SIZE / (1 << SECTOR_SHIFT)))
-
-/*
  * Device id is restricted to 24 bits.
  */
 #define MAX_DEV_ID ((1 << 24) - 1)
@@ -72,7 +63,7 @@
  * missed out if the io covers the block. (schedule_copy).
  *
  * iv) insert the new mapping into the origin's btree
- * (process_prepared_mappings).  This act of inserting breaks some
+ * (process_prepared_mapping).  This act of inserting breaks some
  * sharing of btree nodes between the two devices.  Breaking sharing only
  * effects the btree of that specific device.  Btrees for the other
  * devices that share the block never change.  The btree for the origin
@@ -124,7 +115,7 @@
 	struct hlist_node list;
 	struct bio_prison *prison;
 	struct cell_key key;
-	unsigned count;
+	struct bio *holder;
 	struct bio_list bios;
 };
 
@@ -220,54 +211,59 @@
  * This may block if a new cell needs allocating.  You must ensure that
  * cells will be unlocked even if the calling thread is blocked.
  *
- * Returns the number of entries in the cell prior to the new addition
- * or < 0 on failure.
+ * Returns 1 if the cell was already held, 0 if @inmate is the new holder.
  */
 static int bio_detain(struct bio_prison *prison, struct cell_key *key,
 		      struct bio *inmate, struct cell **ref)
 {
-	int r;
+	int r = 1;
 	unsigned long flags;
 	uint32_t hash = hash_key(prison, key);
-	struct cell *uninitialized_var(cell), *cell2 = NULL;
+	struct cell *cell, *cell2;
 
 	BUG_ON(hash > prison->nr_buckets);
 
 	spin_lock_irqsave(&prison->lock, flags);
+
 	cell = __search_bucket(prison->cells + hash, key);
-
-	if (!cell) {
-		/*
-		 * Allocate a new cell
-		 */
-		spin_unlock_irqrestore(&prison->lock, flags);
-		cell2 = mempool_alloc(prison->cell_pool, GFP_NOIO);
-		spin_lock_irqsave(&prison->lock, flags);
-
-		/*
-		 * We've been unlocked, so we have to double check that
-		 * nobody else has inserted this cell in the meantime.
-		 */
-		cell = __search_bucket(prison->cells + hash, key);
-
-		if (!cell) {
-			cell = cell2;
-			cell2 = NULL;
-
-			cell->prison = prison;
-			memcpy(&cell->key, key, sizeof(cell->key));
-			cell->count = 0;
-			bio_list_init(&cell->bios);
-			hlist_add_head(&cell->list, prison->cells + hash);
-		}
+	if (cell) {
+		bio_list_add(&cell->bios, inmate);
+		goto out;
 	}
 
-	r = cell->count++;
-	bio_list_add(&cell->bios, inmate);
+	/*
+	 * Allocate a new cell
+	 */
 	spin_unlock_irqrestore(&prison->lock, flags);
+	cell2 = mempool_alloc(prison->cell_pool, GFP_NOIO);
+	spin_lock_irqsave(&prison->lock, flags);
 
-	if (cell2)
+	/*
+	 * We've been unlocked, so we have to double check that
+	 * nobody else has inserted this cell in the meantime.
+	 */
+	cell = __search_bucket(prison->cells + hash, key);
+	if (cell) {
 		mempool_free(cell2, prison->cell_pool);
+		bio_list_add(&cell->bios, inmate);
+		goto out;
+	}
+
+	/*
+	 * Use new cell.
+	 */
+	cell = cell2;
+
+	cell->prison = prison;
+	memcpy(&cell->key, key, sizeof(cell->key));
+	cell->holder = inmate;
+	bio_list_init(&cell->bios);
+	hlist_add_head(&cell->list, prison->cells + hash);
+
+	r = 0;
+
+out:
+	spin_unlock_irqrestore(&prison->lock, flags);
 
 	*ref = cell;
 
@@ -283,8 +279,8 @@
 
 	hlist_del(&cell->list);
 
-	if (inmates)
-		bio_list_merge(inmates, &cell->bios);
+	bio_list_add(inmates, cell->holder);
+	bio_list_merge(inmates, &cell->bios);
 
 	mempool_free(cell, prison->cell_pool);
 }
@@ -305,22 +301,44 @@
  * bio may be in the cell.  This function releases the cell, and also does
  * a sanity check.
  */
+static void __cell_release_singleton(struct cell *cell, struct bio *bio)
+{
+	hlist_del(&cell->list);
+	BUG_ON(cell->holder != bio);
+	BUG_ON(!bio_list_empty(&cell->bios));
+}
+
 static void cell_release_singleton(struct cell *cell, struct bio *bio)
 {
-	struct bio_prison *prison = cell->prison;
-	struct bio_list bios;
-	struct bio *b;
 	unsigned long flags;
-
-	bio_list_init(&bios);
+	struct bio_prison *prison = cell->prison;
 
 	spin_lock_irqsave(&prison->lock, flags);
-	__cell_release(cell, &bios);
+	__cell_release_singleton(cell, bio);
 	spin_unlock_irqrestore(&prison->lock, flags);
+}
 
-	b = bio_list_pop(&bios);
-	BUG_ON(b != bio);
-	BUG_ON(!bio_list_empty(&bios));
+/*
+ * Sometimes we don't want the holder, just the additional bios.
+ */
+static void __cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
+{
+	struct bio_prison *prison = cell->prison;
+
+	hlist_del(&cell->list);
+	bio_list_merge(inmates, &cell->bios);
+
+	mempool_free(cell, prison->cell_pool);
+}
+
+static void cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
+{
+	unsigned long flags;
+	struct bio_prison *prison = cell->prison;
+
+	spin_lock_irqsave(&prison->lock, flags);
+	__cell_release_no_holder(cell, inmates);
+	spin_unlock_irqrestore(&prison->lock, flags);
 }
 
 static void cell_error(struct cell *cell)
@@ -471,6 +489,13 @@
  * devices.
  */
 struct new_mapping;
+
+struct pool_features {
+	unsigned zero_new_blocks:1;
+	unsigned discard_enabled:1;
+	unsigned discard_passdown:1;
+};
+
 struct pool {
 	struct list_head list;
 	struct dm_target *ti;	/* Only set if a pool target is bound */
@@ -484,7 +509,7 @@
 	dm_block_t offset_mask;
 	dm_block_t low_water_blocks;
 
-	unsigned zero_new_blocks:1;
+	struct pool_features pf;
 	unsigned low_water_triggered:1;	/* A dm event has been sent */
 	unsigned no_free_space:1;	/* A -ENOSPC warning has been issued */
 
@@ -493,17 +518,21 @@
 
 	struct workqueue_struct *wq;
 	struct work_struct worker;
+	struct delayed_work waker;
 
 	unsigned ref_count;
+	unsigned long last_commit_jiffies;
 
 	spinlock_t lock;
 	struct bio_list deferred_bios;
 	struct bio_list deferred_flush_bios;
 	struct list_head prepared_mappings;
+	struct list_head prepared_discards;
 
 	struct bio_list retry_on_resume_list;
 
-	struct deferred_set ds;	/* FIXME: move to thin_c */
+	struct deferred_set shared_read_ds;
+	struct deferred_set all_io_ds;
 
 	struct new_mapping *next_mapping;
 	mempool_t *mapping_pool;
@@ -521,7 +550,7 @@
 	struct dm_target_callbacks callbacks;
 
 	dm_block_t low_water_blocks;
-	unsigned zero_new_blocks:1;
+	struct pool_features pf;
 };
 
 /*
@@ -529,6 +558,7 @@
  */
 struct thin_c {
 	struct dm_dev *pool_dev;
+	struct dm_dev *origin_dev;
 	dm_thin_id dev_id;
 
 	struct pool *pool;
@@ -597,6 +627,13 @@
 
 /*----------------------------------------------------------------*/
 
+struct endio_hook {
+	struct thin_c *tc;
+	struct deferred_entry *shared_read_entry;
+	struct deferred_entry *all_io_entry;
+	struct new_mapping *overwrite_mapping;
+};
+
 static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
 {
 	struct bio *bio;
@@ -607,7 +644,8 @@
 	bio_list_init(master);
 
 	while ((bio = bio_list_pop(&bios))) {
-		if (dm_get_mapinfo(bio)->ptr == tc)
+		struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+		if (h->tc == tc)
 			bio_endio(bio, DM_ENDIO_REQUEUE);
 		else
 			bio_list_add(master, bio);
@@ -646,14 +684,16 @@
 		(bio->bi_sector & pool->offset_mask);
 }
 
-static void remap_and_issue(struct thin_c *tc, struct bio *bio,
-			    dm_block_t block)
+static void remap_to_origin(struct thin_c *tc, struct bio *bio)
+{
+	bio->bi_bdev = tc->origin_dev->bdev;
+}
+
+static void issue(struct thin_c *tc, struct bio *bio)
 {
 	struct pool *pool = tc->pool;
 	unsigned long flags;
 
-	remap(tc, bio, block);
-
 	/*
 	 * Batch together any FUA/FLUSH bios we find and then issue
 	 * a single commit for them in process_deferred_bios().
@@ -666,6 +706,19 @@
 		generic_make_request(bio);
 }
 
+static void remap_to_origin_and_issue(struct thin_c *tc, struct bio *bio)
+{
+	remap_to_origin(tc, bio);
+	issue(tc, bio);
+}
+
+static void remap_and_issue(struct thin_c *tc, struct bio *bio,
+			    dm_block_t block)
+{
+	remap(tc, bio, block);
+	issue(tc, bio);
+}
+
 /*
  * wake_worker() is used when new work is queued and when pool_resume is
  * ready to continue deferred IO processing.
@@ -680,21 +733,17 @@
 /*
  * Bio endio functions.
  */
-struct endio_hook {
-	struct thin_c *tc;
-	bio_end_io_t *saved_bi_end_io;
-	struct deferred_entry *entry;
-};
-
 struct new_mapping {
 	struct list_head list;
 
-	int prepared;
+	unsigned quiesced:1;
+	unsigned prepared:1;
+	unsigned pass_discard:1;
 
 	struct thin_c *tc;
 	dm_block_t virt_block;
 	dm_block_t data_block;
-	struct cell *cell;
+	struct cell *cell, *cell2;
 	int err;
 
 	/*
@@ -711,7 +760,7 @@
 {
 	struct pool *pool = m->tc->pool;
 
-	if (list_empty(&m->list) && m->prepared) {
+	if (m->quiesced && m->prepared) {
 		list_add(&m->list, &pool->prepared_mappings);
 		wake_worker(pool);
 	}
@@ -734,7 +783,8 @@
 static void overwrite_endio(struct bio *bio, int err)
 {
 	unsigned long flags;
-	struct new_mapping *m = dm_get_mapinfo(bio)->ptr;
+	struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+	struct new_mapping *m = h->overwrite_mapping;
 	struct pool *pool = m->tc->pool;
 
 	m->err = err;
@@ -745,31 +795,6 @@
 	spin_unlock_irqrestore(&pool->lock, flags);
 }
 
-static void shared_read_endio(struct bio *bio, int err)
-{
-	struct list_head mappings;
-	struct new_mapping *m, *tmp;
-	struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
-	unsigned long flags;
-	struct pool *pool = h->tc->pool;
-
-	bio->bi_end_io = h->saved_bi_end_io;
-	bio_endio(bio, err);
-
-	INIT_LIST_HEAD(&mappings);
-	ds_dec(h->entry, &mappings);
-
-	spin_lock_irqsave(&pool->lock, flags);
-	list_for_each_entry_safe(m, tmp, &mappings, list) {
-		list_del(&m->list);
-		INIT_LIST_HEAD(&m->list);
-		__maybe_add_mapping(m);
-	}
-	spin_unlock_irqrestore(&pool->lock, flags);
-
-	mempool_free(h, pool->endio_hook_pool);
-}
-
 /*----------------------------------------------------------------*/
 
 /*
@@ -800,21 +825,16 @@
  * Same as cell_defer above, except it omits one particular detainee,
  * a write bio that covers the block and has already been processed.
  */
-static void cell_defer_except(struct thin_c *tc, struct cell *cell,
-			      struct bio *exception)
+static void cell_defer_except(struct thin_c *tc, struct cell *cell)
 {
 	struct bio_list bios;
-	struct bio *bio;
 	struct pool *pool = tc->pool;
 	unsigned long flags;
 
 	bio_list_init(&bios);
-	cell_release(cell, &bios);
 
 	spin_lock_irqsave(&pool->lock, flags);
-	while ((bio = bio_list_pop(&bios)))
-		if (bio != exception)
-			bio_list_add(&pool->deferred_bios, bio);
+	cell_release_no_holder(cell, &pool->deferred_bios);
 	spin_unlock_irqrestore(&pool->lock, flags);
 
 	wake_worker(pool);
@@ -854,7 +874,7 @@
 	 * the bios in the cell.
 	 */
 	if (bio) {
-		cell_defer_except(tc, m->cell, bio);
+		cell_defer_except(tc, m->cell);
 		bio_endio(bio, 0);
 	} else
 		cell_defer(tc, m->cell, m->data_block);
@@ -863,7 +883,30 @@
 	mempool_free(m, tc->pool->mapping_pool);
 }
 
-static void process_prepared_mappings(struct pool *pool)
+static void process_prepared_discard(struct new_mapping *m)
+{
+	int r;
+	struct thin_c *tc = m->tc;
+
+	r = dm_thin_remove_block(tc->td, m->virt_block);
+	if (r)
+		DMERR("dm_thin_remove_block() failed");
+
+	/*
+	 * Pass the discard down to the underlying device?
+	 */
+	if (m->pass_discard)
+		remap_and_issue(tc, m->bio, m->data_block);
+	else
+		bio_endio(m->bio, 0);
+
+	cell_defer_except(tc, m->cell);
+	cell_defer_except(tc, m->cell2);
+	mempool_free(m, tc->pool->mapping_pool);
+}
+
+static void process_prepared(struct pool *pool, struct list_head *head,
+			     void (*fn)(struct new_mapping *))
 {
 	unsigned long flags;
 	struct list_head maps;
@@ -871,21 +914,27 @@
 
 	INIT_LIST_HEAD(&maps);
 	spin_lock_irqsave(&pool->lock, flags);
-	list_splice_init(&pool->prepared_mappings, &maps);
+	list_splice_init(head, &maps);
 	spin_unlock_irqrestore(&pool->lock, flags);
 
 	list_for_each_entry_safe(m, tmp, &maps, list)
-		process_prepared_mapping(m);
+		fn(m);
 }
 
 /*
  * Deferred bio jobs.
  */
+static int io_overlaps_block(struct pool *pool, struct bio *bio)
+{
+	return !(bio->bi_sector & pool->offset_mask) &&
+		(bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT));
+
+}
+
 static int io_overwrites_block(struct pool *pool, struct bio *bio)
 {
-	return ((bio_data_dir(bio) == WRITE) &&
-		!(bio->bi_sector & pool->offset_mask)) &&
-		(bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT));
+	return (bio_data_dir(bio) == WRITE) &&
+		io_overlaps_block(pool, bio);
 }
 
 static void save_and_set_endio(struct bio *bio, bio_end_io_t **save,
@@ -917,7 +966,8 @@
 }
 
 static void schedule_copy(struct thin_c *tc, dm_block_t virt_block,
-			  dm_block_t data_origin, dm_block_t data_dest,
+			  struct dm_dev *origin, dm_block_t data_origin,
+			  dm_block_t data_dest,
 			  struct cell *cell, struct bio *bio)
 {
 	int r;
@@ -925,6 +975,7 @@
 	struct new_mapping *m = get_next_mapping(pool);
 
 	INIT_LIST_HEAD(&m->list);
+	m->quiesced = 0;
 	m->prepared = 0;
 	m->tc = tc;
 	m->virt_block = virt_block;
@@ -933,7 +984,8 @@
 	m->err = 0;
 	m->bio = NULL;
 
-	ds_add_work(&pool->ds, &m->list);
+	if (!ds_add_work(&pool->shared_read_ds, &m->list))
+		m->quiesced = 1;
 
 	/*
 	 * IO to pool_dev remaps to the pool target's data_dev.
@@ -942,14 +994,15 @@
 	 * bio immediately. Otherwise we use kcopyd to clone the data first.
 	 */
 	if (io_overwrites_block(pool, bio)) {
+		struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+		h->overwrite_mapping = m;
 		m->bio = bio;
 		save_and_set_endio(bio, &m->saved_bi_end_io, overwrite_endio);
-		dm_get_mapinfo(bio)->ptr = m;
 		remap_and_issue(tc, bio, data_dest);
 	} else {
 		struct dm_io_region from, to;
 
-		from.bdev = tc->pool_dev->bdev;
+		from.bdev = origin->bdev;
 		from.sector = data_origin * pool->sectors_per_block;
 		from.count = pool->sectors_per_block;
 
@@ -967,6 +1020,22 @@
 	}
 }
 
+static void schedule_internal_copy(struct thin_c *tc, dm_block_t virt_block,
+				   dm_block_t data_origin, dm_block_t data_dest,
+				   struct cell *cell, struct bio *bio)
+{
+	schedule_copy(tc, virt_block, tc->pool_dev,
+		      data_origin, data_dest, cell, bio);
+}
+
+static void schedule_external_copy(struct thin_c *tc, dm_block_t virt_block,
+				   dm_block_t data_dest,
+				   struct cell *cell, struct bio *bio)
+{
+	schedule_copy(tc, virt_block, tc->origin_dev,
+		      virt_block, data_dest, cell, bio);
+}
+
 static void schedule_zero(struct thin_c *tc, dm_block_t virt_block,
 			  dm_block_t data_block, struct cell *cell,
 			  struct bio *bio)
@@ -975,6 +1044,7 @@
 	struct new_mapping *m = get_next_mapping(pool);
 
 	INIT_LIST_HEAD(&m->list);
+	m->quiesced = 1;
 	m->prepared = 0;
 	m->tc = tc;
 	m->virt_block = virt_block;
@@ -988,13 +1058,14 @@
 	 * zeroing pre-existing data, we can issue the bio immediately.
 	 * Otherwise we use kcopyd to zero the data first.
 	 */
-	if (!pool->zero_new_blocks)
+	if (!pool->pf.zero_new_blocks)
 		process_prepared_mapping(m);
 
 	else if (io_overwrites_block(pool, bio)) {
+		struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+		h->overwrite_mapping = m;
 		m->bio = bio;
 		save_and_set_endio(bio, &m->saved_bi_end_io, overwrite_endio);
-		dm_get_mapinfo(bio)->ptr = m;
 		remap_and_issue(tc, bio, data_block);
 
 	} else {
@@ -1081,7 +1152,8 @@
  */
 static void retry_on_resume(struct bio *bio)
 {
-	struct thin_c *tc = dm_get_mapinfo(bio)->ptr;
+	struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+	struct thin_c *tc = h->tc;
 	struct pool *pool = tc->pool;
 	unsigned long flags;
 
@@ -1102,6 +1174,86 @@
 		retry_on_resume(bio);
 }
 
+static void process_discard(struct thin_c *tc, struct bio *bio)
+{
+	int r;
+	struct pool *pool = tc->pool;
+	struct cell *cell, *cell2;
+	struct cell_key key, key2;
+	dm_block_t block = get_bio_block(tc, bio);
+	struct dm_thin_lookup_result lookup_result;
+	struct new_mapping *m;
+
+	build_virtual_key(tc->td, block, &key);
+	if (bio_detain(tc->pool->prison, &key, bio, &cell))
+		return;
+
+	r = dm_thin_find_block(tc->td, block, 1, &lookup_result);
+	switch (r) {
+	case 0:
+		/*
+		 * Check nobody is fiddling with this pool block.  This can
+		 * happen if someone's in the process of breaking sharing
+		 * on this block.
+		 */
+		build_data_key(tc->td, lookup_result.block, &key2);
+		if (bio_detain(tc->pool->prison, &key2, bio, &cell2)) {
+			cell_release_singleton(cell, bio);
+			break;
+		}
+
+		if (io_overlaps_block(pool, bio)) {
+			/*
+			 * IO may still be going to the destination block.  We must
+			 * quiesce before we can do the removal.
+			 */
+			m = get_next_mapping(pool);
+			m->tc = tc;
+			m->pass_discard = (!lookup_result.shared) & pool->pf.discard_passdown;
+			m->virt_block = block;
+			m->data_block = lookup_result.block;
+			m->cell = cell;
+			m->cell2 = cell2;
+			m->err = 0;
+			m->bio = bio;
+
+			if (!ds_add_work(&pool->all_io_ds, &m->list)) {
+				list_add(&m->list, &pool->prepared_discards);
+				wake_worker(pool);
+			}
+		} else {
+			/*
+			 * This path is hit if people are ignoring
+			 * limits->discard_granularity.  It ignores any
+			 * part of the discard that is in a subsequent
+			 * block.
+			 */
+			sector_t offset = bio->bi_sector - (block << pool->block_shift);
+			unsigned remaining = (pool->sectors_per_block - offset) << 9;
+			bio->bi_size = min(bio->bi_size, remaining);
+
+			cell_release_singleton(cell, bio);
+			cell_release_singleton(cell2, bio);
+			remap_and_issue(tc, bio, lookup_result.block);
+		}
+		break;
+
+	case -ENODATA:
+		/*
+		 * It isn't provisioned, just forget it.
+		 */
+		cell_release_singleton(cell, bio);
+		bio_endio(bio, 0);
+		break;
+
+	default:
+		DMERR("discard: find block unexpectedly returned %d", r);
+		cell_release_singleton(cell, bio);
+		bio_io_error(bio);
+		break;
+	}
+}
+
 static void break_sharing(struct thin_c *tc, struct bio *bio, dm_block_t block,
 			  struct cell_key *key,
 			  struct dm_thin_lookup_result *lookup_result,
@@ -1113,8 +1265,8 @@
 	r = alloc_data_block(tc, &data_block);
 	switch (r) {
 	case 0:
-		schedule_copy(tc, block, lookup_result->block,
-			      data_block, cell, bio);
+		schedule_internal_copy(tc, block, lookup_result->block,
+				       data_block, cell, bio);
 		break;
 
 	case -ENOSPC:
@@ -1147,13 +1299,9 @@
 	if (bio_data_dir(bio) == WRITE)
 		break_sharing(tc, bio, block, &key, lookup_result, cell);
 	else {
-		struct endio_hook *h;
-		h = mempool_alloc(pool->endio_hook_pool, GFP_NOIO);
+		struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
 
-		h->tc = tc;
-		h->entry = ds_inc(&pool->ds);
-		save_and_set_endio(bio, &h->saved_bi_end_io, shared_read_endio);
-		dm_get_mapinfo(bio)->ptr = h;
+		h->shared_read_entry = ds_inc(&pool->shared_read_ds);
 
 		cell_release_singleton(cell, bio);
 		remap_and_issue(tc, bio, lookup_result->block);
@@ -1188,7 +1336,10 @@
 	r = alloc_data_block(tc, &data_block);
 	switch (r) {
 	case 0:
-		schedule_zero(tc, block, data_block, cell, bio);
+		if (tc->origin_dev)
+			schedule_external_copy(tc, block, data_block, cell, bio);
+		else
+			schedule_zero(tc, block, data_block, cell, bio);
 		break;
 
 	case -ENOSPC:
@@ -1239,16 +1390,27 @@
 		break;
 
 	case -ENODATA:
-		provision_block(tc, bio, block, cell);
+		if (bio_data_dir(bio) == READ && tc->origin_dev) {
+			cell_release_singleton(cell, bio);
+			remap_to_origin_and_issue(tc, bio);
+		} else
+			provision_block(tc, bio, block, cell);
 		break;
 
 	default:
 		DMERR("dm_thin_find_block() failed, error = %d", r);
+		cell_release_singleton(cell, bio);
 		bio_io_error(bio);
 		break;
 	}
 }
 
+static int need_commit_due_to_time(struct pool *pool)
+{
+	return jiffies < pool->last_commit_jiffies ||
+	       jiffies > pool->last_commit_jiffies + COMMIT_PERIOD;
+}
+
 static void process_deferred_bios(struct pool *pool)
 {
 	unsigned long flags;
@@ -1264,7 +1426,9 @@
 	spin_unlock_irqrestore(&pool->lock, flags);
 
 	while ((bio = bio_list_pop(&bios))) {
-		struct thin_c *tc = dm_get_mapinfo(bio)->ptr;
+		struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+		struct thin_c *tc = h->tc;
+
 		/*
 		 * If we've got no free new_mapping structs, and processing
 		 * this bio might require one, we pause until there are some
@@ -1277,7 +1441,11 @@
 
 			break;
 		}
-		process_bio(tc, bio);
+
+		if (bio->bi_rw & REQ_DISCARD)
+			process_discard(tc, bio);
+		else
+			process_bio(tc, bio);
 	}
 
 	/*
@@ -1290,7 +1458,7 @@
 	bio_list_init(&pool->deferred_flush_bios);
 	spin_unlock_irqrestore(&pool->lock, flags);
 
-	if (bio_list_empty(&bios))
+	if (bio_list_empty(&bios) && !need_commit_due_to_time(pool))
 		return;
 
 	r = dm_pool_commit_metadata(pool->pmd);
@@ -1301,6 +1469,7 @@
 			bio_io_error(bio);
 		return;
 	}
+	pool->last_commit_jiffies = jiffies;
 
 	while ((bio = bio_list_pop(&bios)))
 		generic_make_request(bio);
@@ -1310,10 +1479,22 @@
 {
 	struct pool *pool = container_of(ws, struct pool, worker);
 
-	process_prepared_mappings(pool);
+	process_prepared(pool, &pool->prepared_mappings, process_prepared_mapping);
+	process_prepared(pool, &pool->prepared_discards, process_prepared_discard);
 	process_deferred_bios(pool);
 }
 
+/*
+ * We want to commit periodically so that not too much
+ * unwritten data builds up.
+ */
+static void do_waker(struct work_struct *ws)
+{
+	struct pool *pool = container_of(to_delayed_work(ws), struct pool, waker);
+	wake_worker(pool);
+	queue_delayed_work(pool->wq, &pool->waker, COMMIT_PERIOD);
+}
+
 /*----------------------------------------------------------------*/
 
 /*
@@ -1335,6 +1516,19 @@
 	wake_worker(pool);
 }
 
+static struct endio_hook *thin_hook_bio(struct thin_c *tc, struct bio *bio)
+{
+	struct pool *pool = tc->pool;
+	struct endio_hook *h = mempool_alloc(pool->endio_hook_pool, GFP_NOIO);
+
+	h->tc = tc;
+	h->shared_read_entry = NULL;
+	h->all_io_entry = bio->bi_rw & REQ_DISCARD ? NULL : ds_inc(&pool->all_io_ds);
+	h->overwrite_mapping = NULL;
+
+	return h;
+}
+
 /*
  * Non-blocking function called from the thin target's map function.
  */
@@ -1347,12 +1541,8 @@
 	struct dm_thin_device *td = tc->td;
 	struct dm_thin_lookup_result result;
 
-	/*
-	 * Save the thin context for easy access from the deferred bio later.
-	 */
-	map_context->ptr = tc;
-
-	if (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) {
+	map_context->ptr = thin_hook_bio(tc, bio);
+	if (bio->bi_rw & (REQ_DISCARD | REQ_FLUSH | REQ_FUA)) {
 		thin_defer_bio(tc, bio);
 		return DM_MAPIO_SUBMITTED;
 	}
@@ -1434,7 +1624,7 @@
 
 	pool->ti = ti;
 	pool->low_water_blocks = pt->low_water_blocks;
-	pool->zero_new_blocks = pt->zero_new_blocks;
+	pool->pf = pt->pf;
 
 	return 0;
 }
@@ -1448,6 +1638,14 @@
 /*----------------------------------------------------------------
  * Pool creation
  *--------------------------------------------------------------*/
+/* Initialize pool features. */
+static void pool_features_init(struct pool_features *pf)
+{
+	pf->zero_new_blocks = 1;
+	pf->discard_enabled = 1;
+	pf->discard_passdown = 1;
+}
+
 static void __pool_destroy(struct pool *pool)
 {
 	__pool_table_remove(pool);
@@ -1495,7 +1693,7 @@
 	pool->block_shift = ffs(block_size) - 1;
 	pool->offset_mask = block_size - 1;
 	pool->low_water_blocks = 0;
-	pool->zero_new_blocks = 1;
+	pool_features_init(&pool->pf);
 	pool->prison = prison_create(PRISON_CELLS);
 	if (!pool->prison) {
 		*error = "Error creating pool's bio prison";
@@ -1523,14 +1721,17 @@
 	}
 
 	INIT_WORK(&pool->worker, do_worker);
+	INIT_DELAYED_WORK(&pool->waker, do_waker);
 	spin_lock_init(&pool->lock);
 	bio_list_init(&pool->deferred_bios);
 	bio_list_init(&pool->deferred_flush_bios);
 	INIT_LIST_HEAD(&pool->prepared_mappings);
+	INIT_LIST_HEAD(&pool->prepared_discards);
 	pool->low_water_triggered = 0;
 	pool->no_free_space = 0;
 	bio_list_init(&pool->retry_on_resume_list);
-	ds_init(&pool->ds);
+	ds_init(&pool->shared_read_ds);
+	ds_init(&pool->all_io_ds);
 
 	pool->next_mapping = NULL;
 	pool->mapping_pool =
@@ -1549,6 +1750,7 @@
 		goto bad_endio_hook_pool;
 	}
 	pool->ref_count = 1;
+	pool->last_commit_jiffies = jiffies;
 	pool->pool_md = pool_md;
 	pool->md_dev = metadata_dev;
 	__pool_table_insert(pool);
@@ -1588,7 +1790,8 @@
 
 static struct pool *__pool_find(struct mapped_device *pool_md,
 				struct block_device *metadata_dev,
-				unsigned long block_size, char **error)
+				unsigned long block_size, char **error,
+				int *created)
 {
 	struct pool *pool = __pool_table_lookup_metadata_dev(metadata_dev);
 
@@ -1604,8 +1807,10 @@
 				return ERR_PTR(-EINVAL);
 			__pool_inc(pool);
 
-		} else
+		} else {
 			pool = pool_create(pool_md, metadata_dev, block_size, error);
+			*created = 1;
+		}
 	}
 
 	return pool;
@@ -1629,10 +1834,6 @@
 	mutex_unlock(&dm_thin_pool_table.mutex);
 }
 
-struct pool_features {
-	unsigned zero_new_blocks:1;
-};
-
 static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
 			       struct dm_target *ti)
 {
@@ -1641,7 +1842,7 @@
 	const char *arg_name;
 
 	static struct dm_arg _args[] = {
-		{0, 1, "Invalid number of pool feature arguments"},
+		{0, 3, "Invalid number of pool feature arguments"},
 	};
 
 	/*
@@ -1661,6 +1862,12 @@
 		if (!strcasecmp(arg_name, "skip_block_zeroing")) {
 			pf->zero_new_blocks = 0;
 			continue;
+		} else if (!strcasecmp(arg_name, "ignore_discard")) {
+			pf->discard_enabled = 0;
+			continue;
+		} else if (!strcasecmp(arg_name, "no_discard_passdown")) {
+			pf->discard_passdown = 0;
+			continue;
 		}
 
 		ti->error = "Unrecognised pool feature requested";
@@ -1678,10 +1885,12 @@
  *
  * Optional feature arguments are:
  *	     skip_block_zeroing: skips the zeroing of newly-provisioned blocks.
+ *	     ignore_discard: disable discard
+ *	     no_discard_passdown: don't pass discards down to the data device
  */
 static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
 {
-	int r;
+	int r, pool_created = 0;
 	struct pool_c *pt;
 	struct pool *pool;
 	struct pool_features pf;
@@ -1691,6 +1900,7 @@
 	dm_block_t low_water_blocks;
 	struct dm_dev *metadata_dev;
 	sector_t metadata_dev_size;
+	char b[BDEVNAME_SIZE];
 
 	/*
 	 * FIXME Remove validation from scope of lock.
@@ -1712,11 +1922,9 @@
 	}
 
 	metadata_dev_size = i_size_read(metadata_dev->bdev->bd_inode) >> SECTOR_SHIFT;
-	if (metadata_dev_size > METADATA_DEV_MAX_SECTORS) {
-		ti->error = "Metadata device is too large";
-		r = -EINVAL;
-		goto out_metadata;
-	}
+	if (metadata_dev_size > THIN_METADATA_MAX_SECTORS_WARNING)
+		DMWARN("Metadata device %s is larger than %u sectors: excess space will not be used.",
+		       bdevname(metadata_dev->bdev, b), THIN_METADATA_MAX_SECTORS);
 
 	r = dm_get_device(ti, argv[1], FMODE_READ | FMODE_WRITE, &data_dev);
 	if (r) {
@@ -1742,8 +1950,7 @@
 	/*
 	 * Set default pool features.
 	 */
-	memset(&pf, 0, sizeof(pf));
-	pf.zero_new_blocks = 1;
+	pool_features_init(&pf);
 
 	dm_consume_args(&as, 4);
 	r = parse_pool_features(&as, &pf, ti);
@@ -1757,20 +1964,58 @@
 	}
 
 	pool = __pool_find(dm_table_get_md(ti->table), metadata_dev->bdev,
-			   block_size, &ti->error);
+			   block_size, &ti->error, &pool_created);
 	if (IS_ERR(pool)) {
 		r = PTR_ERR(pool);
 		goto out_free_pt;
 	}
 
+	/*
+	 * 'pool_created' reflects whether this is the first table load.
+	 * Top level discard support is not allowed to be changed after
+	 * initial load.  This would require a pool reload to trigger thin
+	 * device changes.
+	 */
+	if (!pool_created && pf.discard_enabled != pool->pf.discard_enabled) {
+		ti->error = "Discard support cannot be disabled once enabled";
+		r = -EINVAL;
+		goto out_flags_changed;
+	}
+
+	/*
+	 * If discard_passdown was enabled verify that the data device
+	 * supports discards.  Disable discard_passdown if not; otherwise
+	 * -EOPNOTSUPP will be returned.
+	 */
+	if (pf.discard_passdown) {
+		struct request_queue *q = bdev_get_queue(data_dev->bdev);
+		if (!q || !blk_queue_discard(q)) {
+			DMWARN("Discard unsupported by data device: Disabling discard passdown.");
+			pf.discard_passdown = 0;
+		}
+	}
+
 	pt->pool = pool;
 	pt->ti = ti;
 	pt->metadata_dev = metadata_dev;
 	pt->data_dev = data_dev;
 	pt->low_water_blocks = low_water_blocks;
-	pt->zero_new_blocks = pf.zero_new_blocks;
+	pt->pf = pf;
 	ti->num_flush_requests = 1;
-	ti->num_discard_requests = 0;
+	/*
+	 * Only need to enable discards if the pool should pass
+	 * them down to the data device.  The thin device's discard
+	 * processing will cause mappings to be removed from the btree.
+	 */
+	if (pf.discard_enabled && pf.discard_passdown) {
+		ti->num_discard_requests = 1;
+		/*
+		 * Setting 'discards_supported' circumvents the normal
+		 * stacking of discard limits (this keeps the pool and
+		 * thin devices' discard limits consistent).
+		 */
+		ti->discards_supported = 1;
+	}
 	ti->private = pt;
 
 	pt->callbacks.congested_fn = pool_is_congested;
@@ -1780,6 +2025,8 @@
 
 	return 0;
 
+out_flags_changed:
+	__pool_dec(pool);
 out_free_pt:
 	kfree(pt);
 out:
@@ -1878,7 +2125,7 @@
 	__requeue_bios(pool);
 	spin_unlock_irqrestore(&pool->lock, flags);
 
-	wake_worker(pool);
+	do_waker(&pool->waker.work);
 }
 
 static void pool_postsuspend(struct dm_target *ti)
@@ -1887,6 +2134,7 @@
 	struct pool_c *pt = ti->private;
 	struct pool *pool = pt->pool;
 
+	cancel_delayed_work(&pool->waker);
 	flush_workqueue(pool->wq);
 
 	r = dm_pool_commit_metadata(pool->pmd);
@@ -2067,7 +2315,7 @@
 static int pool_status(struct dm_target *ti, status_type_t type,
 		       char *result, unsigned maxlen)
 {
-	int r;
+	int r, count;
 	unsigned sz = 0;
 	uint64_t transaction_id;
 	dm_block_t nr_free_blocks_data;
@@ -2130,10 +2378,19 @@
 		       (unsigned long)pool->sectors_per_block,
 		       (unsigned long long)pt->low_water_blocks);
 
-		DMEMIT("%u ", !pool->zero_new_blocks);
+		count = !pool->pf.zero_new_blocks + !pool->pf.discard_enabled +
+			!pool->pf.discard_passdown;
+		DMEMIT("%u ", count);
 
-		if (!pool->zero_new_blocks)
+		if (!pool->pf.zero_new_blocks)
 			DMEMIT("skip_block_zeroing ");
+
+		if (!pool->pf.discard_enabled)
+			DMEMIT("ignore_discard ");
+
+		if (!pool->pf.discard_passdown)
+			DMEMIT("no_discard_passdown ");
+
 		break;
 	}
 
@@ -2162,6 +2419,21 @@
 	return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
 }
 
+static void set_discard_limits(struct pool *pool, struct queue_limits *limits)
+{
+	/*
+	 * FIXME: these limits may be incompatible with the pool's data device
+	 */
+	limits->max_discard_sectors = pool->sectors_per_block;
+
+	/*
+	 * This is just a hint, and not enforced.  We have to cope with
+	 * bios that overlap 2 blocks.
+	 */
+	limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT;
+	limits->discard_zeroes_data = pool->pf.zero_new_blocks;
+}
+
 static void pool_io_hints(struct dm_target *ti, struct queue_limits *limits)
 {
 	struct pool_c *pt = ti->private;
@@ -2169,13 +2441,15 @@
 
 	blk_limits_io_min(limits, 0);
 	blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT);
+	if (pool->pf.discard_enabled)
+		set_discard_limits(pool, limits);
 }
 
 static struct target_type pool_target = {
 	.name = "thin-pool",
 	.features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
 		    DM_TARGET_IMMUTABLE,
-	.version = {1, 0, 0},
+	.version = {1, 1, 0},
 	.module = THIS_MODULE,
 	.ctr = pool_ctr,
 	.dtr = pool_dtr,
@@ -2202,6 +2476,8 @@
 	__pool_dec(tc->pool);
 	dm_pool_close_thin_device(tc->td);
 	dm_put_device(ti, tc->pool_dev);
+	if (tc->origin_dev)
+		dm_put_device(ti, tc->origin_dev);
 	kfree(tc);
 
 	mutex_unlock(&dm_thin_pool_table.mutex);
@@ -2210,21 +2486,25 @@
 /*
  * Thin target parameters:
  *
- * <pool_dev> <dev_id>
+ * <pool_dev> <dev_id> [origin_dev]
  *
  * pool_dev: the path to the pool (eg, /dev/mapper/my_pool)
  * dev_id: the internal device identifier
+ * origin_dev: a device external to the pool that should act as the origin
+ *
+ * If the pool device has discards disabled, they get disabled for the thin
+ * device as well.
  */
 static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
 {
 	int r;
 	struct thin_c *tc;
-	struct dm_dev *pool_dev;
+	struct dm_dev *pool_dev, *origin_dev;
 	struct mapped_device *pool_md;
 
 	mutex_lock(&dm_thin_pool_table.mutex);
 
-	if (argc != 2) {
+	if (argc != 2 && argc != 3) {
 		ti->error = "Invalid argument count";
 		r = -EINVAL;
 		goto out_unlock;
@@ -2237,6 +2517,15 @@
 		goto out_unlock;
 	}
 
+	if (argc == 3) {
+		r = dm_get_device(ti, argv[2], FMODE_READ, &origin_dev);
+		if (r) {
+			ti->error = "Error opening origin device";
+			goto bad_origin_dev;
+		}
+		tc->origin_dev = origin_dev;
+	}
+
 	r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &pool_dev);
 	if (r) {
 		ti->error = "Error opening pool device";
@@ -2273,8 +2562,12 @@
 
 	ti->split_io = tc->pool->sectors_per_block;
 	ti->num_flush_requests = 1;
-	ti->num_discard_requests = 0;
-	ti->discards_supported = 0;
+
+	/* In case the pool supports discards, pass them on. */
+	if (tc->pool->pf.discard_enabled) {
+		ti->discards_supported = 1;
+		ti->num_discard_requests = 1;
+	}
 
 	dm_put(pool_md);
 
@@ -2289,6 +2582,9 @@
 bad_common:
 	dm_put_device(ti, tc->pool_dev);
 bad_pool_dev:
+	if (tc->origin_dev)
+		dm_put_device(ti, tc->origin_dev);
+bad_origin_dev:
 	kfree(tc);
 out_unlock:
 	mutex_unlock(&dm_thin_pool_table.mutex);
@@ -2299,11 +2595,46 @@
 static int thin_map(struct dm_target *ti, struct bio *bio,
 		    union map_info *map_context)
 {
-	bio->bi_sector -= ti->begin;
+	bio->bi_sector = dm_target_offset(ti, bio->bi_sector);
 
 	return thin_bio_map(ti, bio, map_context);
 }
 
+static int thin_endio(struct dm_target *ti,
+		      struct bio *bio, int err,
+		      union map_info *map_context)
+{
+	unsigned long flags;
+	struct endio_hook *h = map_context->ptr;
+	struct list_head work;
+	struct new_mapping *m, *tmp;
+	struct pool *pool = h->tc->pool;
+
+	if (h->shared_read_entry) {
+		INIT_LIST_HEAD(&work);
+		ds_dec(h->shared_read_entry, &work);
+
+		spin_lock_irqsave(&pool->lock, flags);
+		list_for_each_entry_safe(m, tmp, &work, list) {
+			list_del(&m->list);
+			m->quiesced = 1;
+			__maybe_add_mapping(m);
+		}
+		spin_unlock_irqrestore(&pool->lock, flags);
+	}
+
+	if (h->all_io_entry) {
+		INIT_LIST_HEAD(&work);
+		ds_dec(h->all_io_entry, &work);
+		list_for_each_entry_safe(m, tmp, &work, list)
+			list_add(&m->list, &pool->prepared_discards);
+	}
+
+	mempool_free(h, pool->endio_hook_pool);
+
+	return 0;
+}
+
 static void thin_postsuspend(struct dm_target *ti)
 {
 	if (dm_noflush_suspending(ti))
@@ -2347,6 +2678,8 @@
 			DMEMIT("%s %lu",
 			       format_dev_t(buf, tc->pool_dev->bdev->bd_dev),
 			       (unsigned long) tc->dev_id);
+			if (tc->origin_dev)
+				DMEMIT(" %s", format_dev_t(buf, tc->origin_dev->bdev->bd_dev));
 			break;
 		}
 	}
@@ -2377,18 +2710,21 @@
 static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
 {
 	struct thin_c *tc = ti->private;
+	struct pool *pool = tc->pool;
 
 	blk_limits_io_min(limits, 0);
-	blk_limits_io_opt(limits, tc->pool->sectors_per_block << SECTOR_SHIFT);
+	blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT);
+	set_discard_limits(pool, limits);
 }
 
 static struct target_type thin_target = {
 	.name = "thin",
-	.version = {1, 0, 0},
+	.version = {1, 1, 0},
 	.module	= THIS_MODULE,
 	.ctr = thin_ctr,
 	.dtr = thin_dtr,
 	.map = thin_map,
+	.end_io = thin_endio,
 	.postsuspend = thin_postsuspend,
 	.status = thin_status,
 	.iterate_devices = thin_iterate_devices,
diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c
new file mode 100644
index 0000000..fa365d3
--- /dev/null
+++ b/drivers/md/dm-verity.c
@@ -0,0 +1,913 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * Author: Mikulas Patocka <mpatocka@redhat.com>
+ *
+ * Based on Chromium dm-verity driver (C) 2011 The Chromium OS Authors
+ *
+ * This file is released under the GPLv2.
+ *
+ * In the file "/sys/module/dm_verity/parameters/prefetch_cluster" you can set
+ * default prefetch value. Data are read in "prefetch_cluster" chunks from the
+ * hash device. Setting this greatly improves performance when data and hash
+ * are on the same disk on different partitions on devices with poor random
+ * access behavior.
+ */
+
+#include "dm-bufio.h"
+
+#include <linux/module.h>
+#include <linux/device-mapper.h>
+#include <crypto/hash.h>
+
+#define DM_MSG_PREFIX			"verity"
+
+#define DM_VERITY_IO_VEC_INLINE		16
+#define DM_VERITY_MEMPOOL_SIZE		4
+#define DM_VERITY_DEFAULT_PREFETCH_SIZE	262144
+
+#define DM_VERITY_MAX_LEVELS		63
+
+static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
+
+module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, S_IRUGO | S_IWUSR);
+
+struct dm_verity {
+	struct dm_dev *data_dev;
+	struct dm_dev *hash_dev;
+	struct dm_target *ti;
+	struct dm_bufio_client *bufio;
+	char *alg_name;
+	struct crypto_shash *tfm;
+	u8 *root_digest;	/* digest of the root block */
+	u8 *salt;		/* salt: its size is salt_size */
+	unsigned salt_size;
+	sector_t data_start;	/* data offset in 512-byte sectors */
+	sector_t hash_start;	/* hash start in blocks */
+	sector_t data_blocks;	/* the number of data blocks */
+	sector_t hash_blocks;	/* the number of hash blocks */
+	unsigned char data_dev_block_bits;	/* log2(data blocksize) */
+	unsigned char hash_dev_block_bits;	/* log2(hash blocksize) */
+	unsigned char hash_per_block_bits;	/* log2(hashes in hash block) */
+	unsigned char levels;	/* the number of tree levels */
+	unsigned char version;
+	unsigned digest_size;	/* digest size for the current hash algorithm */
+	unsigned shash_descsize;/* the size of temporary space for crypto */
+	int hash_failed;	/* set to 1 if hash of any block failed */
+
+	mempool_t *io_mempool;	/* mempool of struct dm_verity_io */
+	mempool_t *vec_mempool;	/* mempool of bio vector */
+
+	struct workqueue_struct *verify_wq;
+
+	/* starting blocks for each tree level. 0 is the lowest level. */
+	sector_t hash_level_block[DM_VERITY_MAX_LEVELS];
+};
+
+struct dm_verity_io {
+	struct dm_verity *v;
+	struct bio *bio;
+
+	/* original values of bio->bi_end_io and bio->bi_private */
+	bio_end_io_t *orig_bi_end_io;
+	void *orig_bi_private;
+
+	sector_t block;
+	unsigned n_blocks;
+
+	/* saved bio vector */
+	struct bio_vec *io_vec;
+	unsigned io_vec_size;
+
+	struct work_struct work;
+
+	/* A space for short vectors; longer vectors are allocated separately. */
+	struct bio_vec io_vec_inline[DM_VERITY_IO_VEC_INLINE];
+
+	/*
+	 * Three variably-size fields follow this struct:
+	 *
+	 * u8 hash_desc[v->shash_descsize];
+	 * u8 real_digest[v->digest_size];
+	 * u8 want_digest[v->digest_size];
+	 *
+	 * To access them use: io_hash_desc(), io_real_digest() and io_want_digest().
+	 */
+};
+
+static struct shash_desc *io_hash_desc(struct dm_verity *v, struct dm_verity_io *io)
+{
+	return (struct shash_desc *)(io + 1);
+}
+
+static u8 *io_real_digest(struct dm_verity *v, struct dm_verity_io *io)
+{
+	return (u8 *)(io + 1) + v->shash_descsize;
+}
+
+static u8 *io_want_digest(struct dm_verity *v, struct dm_verity_io *io)
+{
+	return (u8 *)(io + 1) + v->shash_descsize + v->digest_size;
+}
+
+/*
+ * Auxiliary structure appended to each dm-bufio buffer. If the value
+ * hash_verified is nonzero, hash of the block has been verified.
+ *
+ * The variable hash_verified is set to 0 when allocating the buffer, then
+ * it can be changed to 1 and it is never reset to 0 again.
+ *
+ * There is no lock around this value, a race condition can at worst cause
+ * that multiple processes verify the hash of the same buffer simultaneously
+ * and write 1 to hash_verified simultaneously.
+ * This condition is harmless, so we don't need locking.
+ */
+struct buffer_aux {
+	int hash_verified;
+};
+
+/*
+ * Initialize struct buffer_aux for a freshly created buffer.
+ */
+static void dm_bufio_alloc_callback(struct dm_buffer *buf)
+{
+	struct buffer_aux *aux = dm_bufio_get_aux_data(buf);
+
+	aux->hash_verified = 0;
+}
+
+/*
+ * Translate input sector number to the sector number on the target device.
+ */
+static sector_t verity_map_sector(struct dm_verity *v, sector_t bi_sector)
+{
+	return v->data_start + dm_target_offset(v->ti, bi_sector);
+}
+
+/*
+ * Return hash position of a specified block at a specified tree level
+ * (0 is the lowest level).
+ * The lowest "hash_per_block_bits"-bits of the result denote hash position
+ * inside a hash block. The remaining bits denote location of the hash block.
+ */
+static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
+					 int level)
+{
+	return block >> (level * v->hash_per_block_bits);
+}
+
+static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level,
+				 sector_t *hash_block, unsigned *offset)
+{
+	sector_t position = verity_position_at_level(v, block, level);
+	unsigned idx;
+
+	*hash_block = v->hash_level_block[level] + (position >> v->hash_per_block_bits);
+
+	if (!offset)
+		return;
+
+	idx = position & ((1 << v->hash_per_block_bits) - 1);
+	if (!v->version)
+		*offset = idx * v->digest_size;
+	else
+		*offset = idx << (v->hash_dev_block_bits - v->hash_per_block_bits);
+}
+
+/*
+ * Verify hash of a metadata block pertaining to the specified data block
+ * ("block" argument) at a specified level ("level" argument).
+ *
+ * On successful return, io_want_digest(v, io) contains the hash value for
+ * a lower tree level or for the data block (if we're at the lowest leve).
+ *
+ * If "skip_unverified" is true, unverified buffer is skipped and 1 is returned.
+ * If "skip_unverified" is false, unverified buffer is hashed and verified
+ * against current value of io_want_digest(v, io).
+ */
+static int verity_verify_level(struct dm_verity_io *io, sector_t block,
+			       int level, bool skip_unverified)
+{
+	struct dm_verity *v = io->v;
+	struct dm_buffer *buf;
+	struct buffer_aux *aux;
+	u8 *data;
+	int r;
+	sector_t hash_block;
+	unsigned offset;
+
+	verity_hash_at_level(v, block, level, &hash_block, &offset);
+
+	data = dm_bufio_read(v->bufio, hash_block, &buf);
+	if (unlikely(IS_ERR(data)))
+		return PTR_ERR(data);
+
+	aux = dm_bufio_get_aux_data(buf);
+
+	if (!aux->hash_verified) {
+		struct shash_desc *desc;
+		u8 *result;
+
+		if (skip_unverified) {
+			r = 1;
+			goto release_ret_r;
+		}
+
+		desc = io_hash_desc(v, io);
+		desc->tfm = v->tfm;
+		desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+		r = crypto_shash_init(desc);
+		if (r < 0) {
+			DMERR("crypto_shash_init failed: %d", r);
+			goto release_ret_r;
+		}
+
+		if (likely(v->version >= 1)) {
+			r = crypto_shash_update(desc, v->salt, v->salt_size);
+			if (r < 0) {
+				DMERR("crypto_shash_update failed: %d", r);
+				goto release_ret_r;
+			}
+		}
+
+		r = crypto_shash_update(desc, data, 1 << v->hash_dev_block_bits);
+		if (r < 0) {
+			DMERR("crypto_shash_update failed: %d", r);
+			goto release_ret_r;
+		}
+
+		if (!v->version) {
+			r = crypto_shash_update(desc, v->salt, v->salt_size);
+			if (r < 0) {
+				DMERR("crypto_shash_update failed: %d", r);
+				goto release_ret_r;
+			}
+		}
+
+		result = io_real_digest(v, io);
+		r = crypto_shash_final(desc, result);
+		if (r < 0) {
+			DMERR("crypto_shash_final failed: %d", r);
+			goto release_ret_r;
+		}
+		if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
+			DMERR_LIMIT("metadata block %llu is corrupted",
+				(unsigned long long)hash_block);
+			v->hash_failed = 1;
+			r = -EIO;
+			goto release_ret_r;
+		} else
+			aux->hash_verified = 1;
+	}
+
+	data += offset;
+
+	memcpy(io_want_digest(v, io), data, v->digest_size);
+
+	dm_bufio_release(buf);
+	return 0;
+
+release_ret_r:
+	dm_bufio_release(buf);
+
+	return r;
+}
+
+/*
+ * Verify one "dm_verity_io" structure.
+ */
+static int verity_verify_io(struct dm_verity_io *io)
+{
+	struct dm_verity *v = io->v;
+	unsigned b;
+	int i;
+	unsigned vector = 0, offset = 0;
+
+	for (b = 0; b < io->n_blocks; b++) {
+		struct shash_desc *desc;
+		u8 *result;
+		int r;
+		unsigned todo;
+
+		if (likely(v->levels)) {
+			/*
+			 * First, we try to get the requested hash for
+			 * the current block. If the hash block itself is
+			 * verified, zero is returned. If it isn't, this
+			 * function returns 0 and we fall back to whole
+			 * chain verification.
+			 */
+			int r = verity_verify_level(io, io->block + b, 0, true);
+			if (likely(!r))
+				goto test_block_hash;
+			if (r < 0)
+				return r;
+		}
+
+		memcpy(io_want_digest(v, io), v->root_digest, v->digest_size);
+
+		for (i = v->levels - 1; i >= 0; i--) {
+			int r = verity_verify_level(io, io->block + b, i, false);
+			if (unlikely(r))
+				return r;
+		}
+
+test_block_hash:
+		desc = io_hash_desc(v, io);
+		desc->tfm = v->tfm;
+		desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+		r = crypto_shash_init(desc);
+		if (r < 0) {
+			DMERR("crypto_shash_init failed: %d", r);
+			return r;
+		}
+
+		if (likely(v->version >= 1)) {
+			r = crypto_shash_update(desc, v->salt, v->salt_size);
+			if (r < 0) {
+				DMERR("crypto_shash_update failed: %d", r);
+				return r;
+			}
+		}
+
+		todo = 1 << v->data_dev_block_bits;
+		do {
+			struct bio_vec *bv;
+			u8 *page;
+			unsigned len;
+
+			BUG_ON(vector >= io->io_vec_size);
+			bv = &io->io_vec[vector];
+			page = kmap_atomic(bv->bv_page);
+			len = bv->bv_len - offset;
+			if (likely(len >= todo))
+				len = todo;
+			r = crypto_shash_update(desc,
+					page + bv->bv_offset + offset, len);
+			kunmap_atomic(page);
+			if (r < 0) {
+				DMERR("crypto_shash_update failed: %d", r);
+				return r;
+			}
+			offset += len;
+			if (likely(offset == bv->bv_len)) {
+				offset = 0;
+				vector++;
+			}
+			todo -= len;
+		} while (todo);
+
+		if (!v->version) {
+			r = crypto_shash_update(desc, v->salt, v->salt_size);
+			if (r < 0) {
+				DMERR("crypto_shash_update failed: %d", r);
+				return r;
+			}
+		}
+
+		result = io_real_digest(v, io);
+		r = crypto_shash_final(desc, result);
+		if (r < 0) {
+			DMERR("crypto_shash_final failed: %d", r);
+			return r;
+		}
+		if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
+			DMERR_LIMIT("data block %llu is corrupted",
+				(unsigned long long)(io->block + b));
+			v->hash_failed = 1;
+			return -EIO;
+		}
+	}
+	BUG_ON(vector != io->io_vec_size);
+	BUG_ON(offset);
+
+	return 0;
+}
+
+/*
+ * End one "io" structure with a given error.
+ */
+static void verity_finish_io(struct dm_verity_io *io, int error)
+{
+	struct bio *bio = io->bio;
+	struct dm_verity *v = io->v;
+
+	bio->bi_end_io = io->orig_bi_end_io;
+	bio->bi_private = io->orig_bi_private;
+
+	if (io->io_vec != io->io_vec_inline)
+		mempool_free(io->io_vec, v->vec_mempool);
+
+	mempool_free(io, v->io_mempool);
+
+	bio_endio(bio, error);
+}
+
+static void verity_work(struct work_struct *w)
+{
+	struct dm_verity_io *io = container_of(w, struct dm_verity_io, work);
+
+	verity_finish_io(io, verity_verify_io(io));
+}
+
+static void verity_end_io(struct bio *bio, int error)
+{
+	struct dm_verity_io *io = bio->bi_private;
+
+	if (error) {
+		verity_finish_io(io, error);
+		return;
+	}
+
+	INIT_WORK(&io->work, verity_work);
+	queue_work(io->v->verify_wq, &io->work);
+}
+
+/*
+ * Prefetch buffers for the specified io.
+ * The root buffer is not prefetched, it is assumed that it will be cached
+ * all the time.
+ */
+static void verity_prefetch_io(struct dm_verity *v, struct dm_verity_io *io)
+{
+	int i;
+
+	for (i = v->levels - 2; i >= 0; i--) {
+		sector_t hash_block_start;
+		sector_t hash_block_end;
+		verity_hash_at_level(v, io->block, i, &hash_block_start, NULL);
+		verity_hash_at_level(v, io->block + io->n_blocks - 1, i, &hash_block_end, NULL);
+		if (!i) {
+			unsigned cluster = *(volatile unsigned *)&dm_verity_prefetch_cluster;
+
+			cluster >>= v->data_dev_block_bits;
+			if (unlikely(!cluster))
+				goto no_prefetch_cluster;
+
+			if (unlikely(cluster & (cluster - 1)))
+				cluster = 1 << (fls(cluster) - 1);
+
+			hash_block_start &= ~(sector_t)(cluster - 1);
+			hash_block_end |= cluster - 1;
+			if (unlikely(hash_block_end >= v->hash_blocks))
+				hash_block_end = v->hash_blocks - 1;
+		}
+no_prefetch_cluster:
+		dm_bufio_prefetch(v->bufio, hash_block_start,
+				  hash_block_end - hash_block_start + 1);
+	}
+}
+
+/*
+ * Bio map function. It allocates dm_verity_io structure and bio vector and
+ * fills them. Then it issues prefetches and the I/O.
+ */
+static int verity_map(struct dm_target *ti, struct bio *bio,
+		      union map_info *map_context)
+{
+	struct dm_verity *v = ti->private;
+	struct dm_verity_io *io;
+
+	bio->bi_bdev = v->data_dev->bdev;
+	bio->bi_sector = verity_map_sector(v, bio->bi_sector);
+
+	if (((unsigned)bio->bi_sector | bio_sectors(bio)) &
+	    ((1 << (v->data_dev_block_bits - SECTOR_SHIFT)) - 1)) {
+		DMERR_LIMIT("unaligned io");
+		return -EIO;
+	}
+
+	if ((bio->bi_sector + bio_sectors(bio)) >>
+	    (v->data_dev_block_bits - SECTOR_SHIFT) > v->data_blocks) {
+		DMERR_LIMIT("io out of range");
+		return -EIO;
+	}
+
+	if (bio_data_dir(bio) == WRITE)
+		return -EIO;
+
+	io = mempool_alloc(v->io_mempool, GFP_NOIO);
+	io->v = v;
+	io->bio = bio;
+	io->orig_bi_end_io = bio->bi_end_io;
+	io->orig_bi_private = bio->bi_private;
+	io->block = bio->bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT);
+	io->n_blocks = bio->bi_size >> v->data_dev_block_bits;
+
+	bio->bi_end_io = verity_end_io;
+	bio->bi_private = io;
+	io->io_vec_size = bio->bi_vcnt - bio->bi_idx;
+	if (io->io_vec_size < DM_VERITY_IO_VEC_INLINE)
+		io->io_vec = io->io_vec_inline;
+	else
+		io->io_vec = mempool_alloc(v->vec_mempool, GFP_NOIO);
+	memcpy(io->io_vec, bio_iovec(bio),
+	       io->io_vec_size * sizeof(struct bio_vec));
+
+	verity_prefetch_io(v, io);
+
+	generic_make_request(bio);
+
+	return DM_MAPIO_SUBMITTED;
+}
+
+/*
+ * Status: V (valid) or C (corruption found)
+ */
+static int verity_status(struct dm_target *ti, status_type_t type,
+			 char *result, unsigned maxlen)
+{
+	struct dm_verity *v = ti->private;
+	unsigned sz = 0;
+	unsigned x;
+
+	switch (type) {
+	case STATUSTYPE_INFO:
+		DMEMIT("%c", v->hash_failed ? 'C' : 'V');
+		break;
+	case STATUSTYPE_TABLE:
+		DMEMIT("%u %s %s %u %u %llu %llu %s ",
+			v->version,
+			v->data_dev->name,
+			v->hash_dev->name,
+			1 << v->data_dev_block_bits,
+			1 << v->hash_dev_block_bits,
+			(unsigned long long)v->data_blocks,
+			(unsigned long long)v->hash_start,
+			v->alg_name
+			);
+		for (x = 0; x < v->digest_size; x++)
+			DMEMIT("%02x", v->root_digest[x]);
+		DMEMIT(" ");
+		if (!v->salt_size)
+			DMEMIT("-");
+		else
+			for (x = 0; x < v->salt_size; x++)
+				DMEMIT("%02x", v->salt[x]);
+		break;
+	}
+
+	return 0;
+}
+
+static int verity_ioctl(struct dm_target *ti, unsigned cmd,
+			unsigned long arg)
+{
+	struct dm_verity *v = ti->private;
+	int r = 0;
+
+	if (v->data_start ||
+	    ti->len != i_size_read(v->data_dev->bdev->bd_inode) >> SECTOR_SHIFT)
+		r = scsi_verify_blk_ioctl(NULL, cmd);
+
+	return r ? : __blkdev_driver_ioctl(v->data_dev->bdev, v->data_dev->mode,
+				     cmd, arg);
+}
+
+static int verity_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
+			struct bio_vec *biovec, int max_size)
+{
+	struct dm_verity *v = ti->private;
+	struct request_queue *q = bdev_get_queue(v->data_dev->bdev);
+
+	if (!q->merge_bvec_fn)
+		return max_size;
+
+	bvm->bi_bdev = v->data_dev->bdev;
+	bvm->bi_sector = verity_map_sector(v, bvm->bi_sector);
+
+	return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
+}
+
+static int verity_iterate_devices(struct dm_target *ti,
+				  iterate_devices_callout_fn fn, void *data)
+{
+	struct dm_verity *v = ti->private;
+
+	return fn(ti, v->data_dev, v->data_start, ti->len, data);
+}
+
+static void verity_io_hints(struct dm_target *ti, struct queue_limits *limits)
+{
+	struct dm_verity *v = ti->private;
+
+	if (limits->logical_block_size < 1 << v->data_dev_block_bits)
+		limits->logical_block_size = 1 << v->data_dev_block_bits;
+
+	if (limits->physical_block_size < 1 << v->data_dev_block_bits)
+		limits->physical_block_size = 1 << v->data_dev_block_bits;
+
+	blk_limits_io_min(limits, limits->logical_block_size);
+}
+
+static void verity_dtr(struct dm_target *ti)
+{
+	struct dm_verity *v = ti->private;
+
+	if (v->verify_wq)
+		destroy_workqueue(v->verify_wq);
+
+	if (v->vec_mempool)
+		mempool_destroy(v->vec_mempool);
+
+	if (v->io_mempool)
+		mempool_destroy(v->io_mempool);
+
+	if (v->bufio)
+		dm_bufio_client_destroy(v->bufio);
+
+	kfree(v->salt);
+	kfree(v->root_digest);
+
+	if (v->tfm)
+		crypto_free_shash(v->tfm);
+
+	kfree(v->alg_name);
+
+	if (v->hash_dev)
+		dm_put_device(ti, v->hash_dev);
+
+	if (v->data_dev)
+		dm_put_device(ti, v->data_dev);
+
+	kfree(v);
+}
+
+/*
+ * Target parameters:
+ *	<version>	The current format is version 1.
+ *			Vsn 0 is compatible with original Chromium OS releases.
+ *	<data device>
+ *	<hash device>
+ *	<data block size>
+ *	<hash block size>
+ *	<the number of data blocks>
+ *	<hash start block>
+ *	<algorithm>
+ *	<digest>
+ *	<salt>		Hex string or "-" if no salt.
+ */
+static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
+{
+	struct dm_verity *v;
+	unsigned num;
+	unsigned long long num_ll;
+	int r;
+	int i;
+	sector_t hash_position;
+	char dummy;
+
+	v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL);
+	if (!v) {
+		ti->error = "Cannot allocate verity structure";
+		return -ENOMEM;
+	}
+	ti->private = v;
+	v->ti = ti;
+
+	if ((dm_table_get_mode(ti->table) & ~FMODE_READ)) {
+		ti->error = "Device must be readonly";
+		r = -EINVAL;
+		goto bad;
+	}
+
+	if (argc != 10) {
+		ti->error = "Invalid argument count: exactly 10 arguments required";
+		r = -EINVAL;
+		goto bad;
+	}
+
+	if (sscanf(argv[0], "%d%c", &num, &dummy) != 1 ||
+	    num < 0 || num > 1) {
+		ti->error = "Invalid version";
+		r = -EINVAL;
+		goto bad;
+	}
+	v->version = num;
+
+	r = dm_get_device(ti, argv[1], FMODE_READ, &v->data_dev);
+	if (r) {
+		ti->error = "Data device lookup failed";
+		goto bad;
+	}
+
+	r = dm_get_device(ti, argv[2], FMODE_READ, &v->hash_dev);
+	if (r) {
+		ti->error = "Data device lookup failed";
+		goto bad;
+	}
+
+	if (sscanf(argv[3], "%u%c", &num, &dummy) != 1 ||
+	    !num || (num & (num - 1)) ||
+	    num < bdev_logical_block_size(v->data_dev->bdev) ||
+	    num > PAGE_SIZE) {
+		ti->error = "Invalid data device block size";
+		r = -EINVAL;
+		goto bad;
+	}
+	v->data_dev_block_bits = ffs(num) - 1;
+
+	if (sscanf(argv[4], "%u%c", &num, &dummy) != 1 ||
+	    !num || (num & (num - 1)) ||
+	    num < bdev_logical_block_size(v->hash_dev->bdev) ||
+	    num > INT_MAX) {
+		ti->error = "Invalid hash device block size";
+		r = -EINVAL;
+		goto bad;
+	}
+	v->hash_dev_block_bits = ffs(num) - 1;
+
+	if (sscanf(argv[5], "%llu%c", &num_ll, &dummy) != 1 ||
+	    num_ll << (v->data_dev_block_bits - SECTOR_SHIFT) !=
+	    (sector_t)num_ll << (v->data_dev_block_bits - SECTOR_SHIFT)) {
+		ti->error = "Invalid data blocks";
+		r = -EINVAL;
+		goto bad;
+	}
+	v->data_blocks = num_ll;
+
+	if (ti->len > (v->data_blocks << (v->data_dev_block_bits - SECTOR_SHIFT))) {
+		ti->error = "Data device is too small";
+		r = -EINVAL;
+		goto bad;
+	}
+
+	if (sscanf(argv[6], "%llu%c", &num_ll, &dummy) != 1 ||
+	    num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT) !=
+	    (sector_t)num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT)) {
+		ti->error = "Invalid hash start";
+		r = -EINVAL;
+		goto bad;
+	}
+	v->hash_start = num_ll;
+
+	v->alg_name = kstrdup(argv[7], GFP_KERNEL);
+	if (!v->alg_name) {
+		ti->error = "Cannot allocate algorithm name";
+		r = -ENOMEM;
+		goto bad;
+	}
+
+	v->tfm = crypto_alloc_shash(v->alg_name, 0, 0);
+	if (IS_ERR(v->tfm)) {
+		ti->error = "Cannot initialize hash function";
+		r = PTR_ERR(v->tfm);
+		v->tfm = NULL;
+		goto bad;
+	}
+	v->digest_size = crypto_shash_digestsize(v->tfm);
+	if ((1 << v->hash_dev_block_bits) < v->digest_size * 2) {
+		ti->error = "Digest size too big";
+		r = -EINVAL;
+		goto bad;
+	}
+	v->shash_descsize =
+		sizeof(struct shash_desc) + crypto_shash_descsize(v->tfm);
+
+	v->root_digest = kmalloc(v->digest_size, GFP_KERNEL);
+	if (!v->root_digest) {
+		ti->error = "Cannot allocate root digest";
+		r = -ENOMEM;
+		goto bad;
+	}
+	if (strlen(argv[8]) != v->digest_size * 2 ||
+	    hex2bin(v->root_digest, argv[8], v->digest_size)) {
+		ti->error = "Invalid root digest";
+		r = -EINVAL;
+		goto bad;
+	}
+
+	if (strcmp(argv[9], "-")) {
+		v->salt_size = strlen(argv[9]) / 2;
+		v->salt = kmalloc(v->salt_size, GFP_KERNEL);
+		if (!v->salt) {
+			ti->error = "Cannot allocate salt";
+			r = -ENOMEM;
+			goto bad;
+		}
+		if (strlen(argv[9]) != v->salt_size * 2 ||
+		    hex2bin(v->salt, argv[9], v->salt_size)) {
+			ti->error = "Invalid salt";
+			r = -EINVAL;
+			goto bad;
+		}
+	}
+
+	v->hash_per_block_bits =
+		fls((1 << v->hash_dev_block_bits) / v->digest_size) - 1;
+
+	v->levels = 0;
+	if (v->data_blocks)
+		while (v->hash_per_block_bits * v->levels < 64 &&
+		       (unsigned long long)(v->data_blocks - 1) >>
+		       (v->hash_per_block_bits * v->levels))
+			v->levels++;
+
+	if (v->levels > DM_VERITY_MAX_LEVELS) {
+		ti->error = "Too many tree levels";
+		r = -E2BIG;
+		goto bad;
+	}
+
+	hash_position = v->hash_start;
+	for (i = v->levels - 1; i >= 0; i--) {
+		sector_t s;
+		v->hash_level_block[i] = hash_position;
+		s = verity_position_at_level(v, v->data_blocks, i);
+		s = (s >> v->hash_per_block_bits) +
+		    !!(s & ((1 << v->hash_per_block_bits) - 1));
+		if (hash_position + s < hash_position) {
+			ti->error = "Hash device offset overflow";
+			r = -E2BIG;
+			goto bad;
+		}
+		hash_position += s;
+	}
+	v->hash_blocks = hash_position;
+
+	v->bufio = dm_bufio_client_create(v->hash_dev->bdev,
+		1 << v->hash_dev_block_bits, 1, sizeof(struct buffer_aux),
+		dm_bufio_alloc_callback, NULL);
+	if (IS_ERR(v->bufio)) {
+		ti->error = "Cannot initialize dm-bufio";
+		r = PTR_ERR(v->bufio);
+		v->bufio = NULL;
+		goto bad;
+	}
+
+	if (dm_bufio_get_device_size(v->bufio) < v->hash_blocks) {
+		ti->error = "Hash device is too small";
+		r = -E2BIG;
+		goto bad;
+	}
+
+	v->io_mempool = mempool_create_kmalloc_pool(DM_VERITY_MEMPOOL_SIZE,
+	  sizeof(struct dm_verity_io) + v->shash_descsize + v->digest_size * 2);
+	if (!v->io_mempool) {
+		ti->error = "Cannot allocate io mempool";
+		r = -ENOMEM;
+		goto bad;
+	}
+
+	v->vec_mempool = mempool_create_kmalloc_pool(DM_VERITY_MEMPOOL_SIZE,
+					BIO_MAX_PAGES * sizeof(struct bio_vec));
+	if (!v->vec_mempool) {
+		ti->error = "Cannot allocate vector mempool";
+		r = -ENOMEM;
+		goto bad;
+	}
+
+	/* WQ_UNBOUND greatly improves performance when running on ramdisk */
+	v->verify_wq = alloc_workqueue("kverityd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND, num_online_cpus());
+	if (!v->verify_wq) {
+		ti->error = "Cannot allocate workqueue";
+		r = -ENOMEM;
+		goto bad;
+	}
+
+	return 0;
+
+bad:
+	verity_dtr(ti);
+
+	return r;
+}
+
+static struct target_type verity_target = {
+	.name		= "verity",
+	.version	= {1, 0, 0},
+	.module		= THIS_MODULE,
+	.ctr		= verity_ctr,
+	.dtr		= verity_dtr,
+	.map		= verity_map,
+	.status		= verity_status,
+	.ioctl		= verity_ioctl,
+	.merge		= verity_merge,
+	.iterate_devices = verity_iterate_devices,
+	.io_hints	= verity_io_hints,
+};
+
+static int __init dm_verity_init(void)
+{
+	int r;
+
+	r = dm_register_target(&verity_target);
+	if (r < 0)
+		DMERR("register failed %d", r);
+
+	return r;
+}
+
+static void __exit dm_verity_exit(void)
+{
+	dm_unregister_target(&verity_target);
+}
+
+module_init(dm_verity_init);
+module_exit(dm_verity_exit);
+
+MODULE_AUTHOR("Mikulas Patocka <mpatocka@redhat.com>");
+MODULE_AUTHOR("Mandeep Baines <msb@chromium.org>");
+MODULE_AUTHOR("Will Drewry <wad@chromium.org>");
+MODULE_DESCRIPTION(DM_NAME " target for transparent disk integrity checking");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index b89c548..e24143c 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1016,6 +1016,7 @@
 		/*
 		 * Store bio_set for cleanup.
 		 */
+		clone->bi_end_io = NULL;
 		clone->bi_private = md->bs;
 		bio_put(clone);
 		free_tio(md, tio);
diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c
index feb2c3c..45135f6 100644
--- a/drivers/md/faulty.c
+++ b/drivers/md/faulty.c
@@ -315,7 +315,7 @@
 	}
 	conf->nfaults = 0;
 
-	list_for_each_entry(rdev, &mddev->disks, same_set)
+	rdev_for_each(rdev, mddev)
 		conf->rdev = rdev;
 
 	md_set_array_sectors(mddev, faulty_size(mddev, 0, 0));
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 6274565..fa211d8 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -68,10 +68,19 @@
 	struct dev_info *dev0;
 	unsigned long maxsectors, bio_sectors = bvm->bi_size >> 9;
 	sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
+	int maxbytes = biovec->bv_len;
+	struct request_queue *subq;
 
 	rcu_read_lock();
 	dev0 = which_dev(mddev, sector);
 	maxsectors = dev0->end_sector - sector;
+	subq = bdev_get_queue(dev0->rdev->bdev);
+	if (subq->merge_bvec_fn) {
+		bvm->bi_bdev = dev0->rdev->bdev;
+		bvm->bi_sector -= dev0->end_sector - dev0->rdev->sectors;
+		maxbytes = min(maxbytes, subq->merge_bvec_fn(subq, bvm,
+							     biovec));
+	}
 	rcu_read_unlock();
 
 	if (maxsectors < bio_sectors)
@@ -80,12 +89,12 @@
 		maxsectors -= bio_sectors;
 
 	if (maxsectors <= (PAGE_SIZE >> 9 ) && bio_sectors == 0)
-		return biovec->bv_len;
-	/* The bytes available at this offset could be really big,
-	 * so we cap at 2^31 to avoid overflow */
-	if (maxsectors > (1 << (31-9)))
-		return 1<<31;
-	return maxsectors << 9;
+		return maxbytes;
+
+	if (maxsectors > (maxbytes >> 9))
+		return maxbytes;
+	else
+		return maxsectors << 9;
 }
 
 static int linear_congested(void *data, int bits)
@@ -138,7 +147,7 @@
 	cnt = 0;
 	conf->array_sectors = 0;
 
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		int j = rdev->raid_disk;
 		struct dev_info *disk = conf->disks + j;
 		sector_t sectors;
@@ -158,15 +167,6 @@
 
 		disk_stack_limits(mddev->gendisk, rdev->bdev,
 				  rdev->data_offset << 9);
-		/* as we don't honour merge_bvec_fn, we must never risk
-		 * violating it, so limit max_segments to 1 lying within
-		 * a single page.
-		 */
-		if (rdev->bdev->bd_disk->queue->merge_bvec_fn) {
-			blk_queue_max_segments(mddev->queue, 1);
-			blk_queue_segment_boundary(mddev->queue,
-						   PAGE_CACHE_SIZE - 1);
-		}
 
 		conf->array_sectors += rdev->sectors;
 		cnt++;
@@ -198,6 +198,7 @@
 static int linear_run (struct mddev *mddev)
 {
 	struct linear_conf *conf;
+	int ret;
 
 	if (md_check_no_bitmap(mddev))
 		return -EINVAL;
@@ -211,7 +212,13 @@
 	blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec);
 	mddev->queue->backing_dev_info.congested_fn = linear_congested;
 	mddev->queue->backing_dev_info.congested_data = mddev;
-	return md_integrity_register(mddev);
+
+	ret =  md_integrity_register(mddev);
+	if (ret) {
+		kfree(conf);
+		mddev->private = NULL;
+	}
+	return ret;
 }
 
 static int linear_add(struct mddev *mddev, struct md_rdev *rdev)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index ce88755..b572e1e 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -439,7 +439,7 @@
 	INIT_WORK(&mddev->flush_work, md_submit_flush_data);
 	atomic_set(&mddev->flush_pending, 1);
 	rcu_read_lock();
-	list_for_each_entry_rcu(rdev, &mddev->disks, same_set)
+	rdev_for_each_rcu(rdev, mddev)
 		if (rdev->raid_disk >= 0 &&
 		    !test_bit(Faulty, &rdev->flags)) {
 			/* Take two references, one is dropped
@@ -749,7 +749,7 @@
 {
 	struct md_rdev *rdev;
 
-	list_for_each_entry(rdev, &mddev->disks, same_set)
+	rdev_for_each(rdev, mddev)
 		if (rdev->desc_nr == nr)
 			return rdev;
 
@@ -760,7 +760,7 @@
 {
 	struct md_rdev *rdev;
 
-	list_for_each_entry(rdev, &mddev->disks, same_set)
+	rdev_for_each(rdev, mddev)
 		if (rdev->bdev->bd_dev == dev)
 			return rdev;
 
@@ -1342,7 +1342,7 @@
 		sb->state |= (1<<MD_SB_BITMAP_PRESENT);
 
 	sb->disks[0].state = (1<<MD_DISK_REMOVED);
-	list_for_each_entry(rdev2, &mddev->disks, same_set) {
+	rdev_for_each(rdev2, mddev) {
 		mdp_disk_t *d;
 		int desc_nr;
 		int is_active = test_bit(In_sync, &rdev2->flags);
@@ -1805,18 +1805,18 @@
 						| BB_LEN(internal_bb));
 				*bbp++ = cpu_to_le64(store_bb);
 			}
+			bb->changed = 0;
 			if (read_seqretry(&bb->lock, seq))
 				goto retry;
 
 			bb->sector = (rdev->sb_start +
 				      (int)le32_to_cpu(sb->bblog_offset));
 			bb->size = le16_to_cpu(sb->bblog_size);
-			bb->changed = 0;
 		}
 	}
 
 	max_dev = 0;
-	list_for_each_entry(rdev2, &mddev->disks, same_set)
+	rdev_for_each(rdev2, mddev)
 		if (rdev2->desc_nr+1 > max_dev)
 			max_dev = rdev2->desc_nr+1;
 
@@ -1833,7 +1833,7 @@
 	for (i=0; i<max_dev;i++)
 		sb->dev_roles[i] = cpu_to_le16(0xfffe);
 	
-	list_for_each_entry(rdev2, &mddev->disks, same_set) {
+	rdev_for_each(rdev2, mddev) {
 		i = rdev2->desc_nr;
 		if (test_bit(Faulty, &rdev2->flags))
 			sb->dev_roles[i] = cpu_to_le16(0xfffe);
@@ -1948,7 +1948,7 @@
 		return 0; /* nothing to do */
 	if (!mddev->gendisk || blk_get_integrity(mddev->gendisk))
 		return 0; /* shouldn't register, or already is */
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		/* skip spares and non-functional disks */
 		if (test_bit(Faulty, &rdev->flags))
 			continue;
@@ -2175,7 +2175,7 @@
 {
 	struct md_rdev *rdev, *tmp;
 
-	rdev_for_each(rdev, tmp, mddev) {
+	rdev_for_each_safe(rdev, tmp, mddev) {
 		if (!rdev->mddev) {
 			MD_BUG();
 			continue;
@@ -2307,11 +2307,11 @@
 			bitmap_print_sb(mddev->bitmap);
 		else
 			printk("%s: ", mdname(mddev));
-		list_for_each_entry(rdev, &mddev->disks, same_set)
+		rdev_for_each(rdev, mddev)
 			printk("<%s>", bdevname(rdev->bdev,b));
 		printk("\n");
 
-		list_for_each_entry(rdev, &mddev->disks, same_set)
+		rdev_for_each(rdev, mddev)
 			print_rdev(rdev, mddev->major_version);
 	}
 	printk("md:	**********************************\n");
@@ -2328,7 +2328,7 @@
 	 * with the rest of the array)
 	 */
 	struct md_rdev *rdev;
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		if (rdev->sb_events == mddev->events ||
 		    (nospares &&
 		     rdev->raid_disk < 0 &&
@@ -2351,7 +2351,7 @@
 
 repeat:
 	/* First make sure individual recovery_offsets are correct */
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		if (rdev->raid_disk >= 0 &&
 		    mddev->delta_disks >= 0 &&
 		    !test_bit(In_sync, &rdev->flags) &&
@@ -2364,8 +2364,9 @@
 		clear_bit(MD_CHANGE_DEVS, &mddev->flags);
 		if (!mddev->external) {
 			clear_bit(MD_CHANGE_PENDING, &mddev->flags);
-			list_for_each_entry(rdev, &mddev->disks, same_set) {
+			rdev_for_each(rdev, mddev) {
 				if (rdev->badblocks.changed) {
+					rdev->badblocks.changed = 0;
 					md_ack_all_badblocks(&rdev->badblocks);
 					md_error(mddev, rdev);
 				}
@@ -2430,7 +2431,7 @@
 		mddev->events --;
 	}
 
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		if (rdev->badblocks.changed)
 			any_badblocks_changed++;
 		if (test_bit(Faulty, &rdev->flags))
@@ -2444,7 +2445,7 @@
 		 mdname(mddev), mddev->in_sync);
 
 	bitmap_update_sb(mddev->bitmap);
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		char b[BDEVNAME_SIZE];
 
 		if (rdev->sb_loaded != 1)
@@ -2493,7 +2494,7 @@
 	if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
 		sysfs_notify(&mddev->kobj, NULL, "sync_completed");
 
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		if (test_and_clear_bit(FaultRecorded, &rdev->flags))
 			clear_bit(Blocked, &rdev->flags);
 
@@ -2896,7 +2897,7 @@
 			struct md_rdev *rdev2;
 
 			mddev_lock(mddev);
-			list_for_each_entry(rdev2, &mddev->disks, same_set)
+			rdev_for_each(rdev2, mddev)
 				if (rdev->bdev == rdev2->bdev &&
 				    rdev != rdev2 &&
 				    overlaps(rdev->data_offset, rdev->sectors,
@@ -3193,7 +3194,7 @@
 	char b[BDEVNAME_SIZE];
 
 	freshest = NULL;
-	rdev_for_each(rdev, tmp, mddev)
+	rdev_for_each_safe(rdev, tmp, mddev)
 		switch (super_types[mddev->major_version].
 			load_super(rdev, freshest, mddev->minor_version)) {
 		case 1:
@@ -3214,7 +3215,7 @@
 		validate_super(mddev, freshest);
 
 	i = 0;
-	rdev_for_each(rdev, tmp, mddev) {
+	rdev_for_each_safe(rdev, tmp, mddev) {
 		if (mddev->max_disks &&
 		    (rdev->desc_nr >= mddev->max_disks ||
 		     i > mddev->max_disks)) {
@@ -3403,7 +3404,7 @@
 		return -EINVAL;
 	}
 
-	list_for_each_entry(rdev, &mddev->disks, same_set)
+	rdev_for_each(rdev, mddev)
 		rdev->new_raid_disk = rdev->raid_disk;
 
 	/* ->takeover must set new_* and/or delta_disks
@@ -3456,7 +3457,7 @@
 		mddev->safemode = 0;
 	}
 
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		if (rdev->raid_disk < 0)
 			continue;
 		if (rdev->new_raid_disk >= mddev->raid_disks)
@@ -3465,7 +3466,7 @@
 			continue;
 		sysfs_unlink_rdev(mddev, rdev);
 	}
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		if (rdev->raid_disk < 0)
 			continue;
 		if (rdev->new_raid_disk == rdev->raid_disk)
@@ -4796,7 +4797,7 @@
 	 * the only valid external interface is through the md
 	 * device.
 	 */
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		if (test_bit(Faulty, &rdev->flags))
 			continue;
 		sync_blockdev(rdev->bdev);
@@ -4867,8 +4868,8 @@
 		struct md_rdev *rdev2;
 		int warned = 0;
 
-		list_for_each_entry(rdev, &mddev->disks, same_set)
-			list_for_each_entry(rdev2, &mddev->disks, same_set) {
+		rdev_for_each(rdev, mddev)
+			rdev_for_each(rdev2, mddev) {
 				if (rdev < rdev2 &&
 				    rdev->bdev->bd_contains ==
 				    rdev2->bdev->bd_contains) {
@@ -4945,7 +4946,7 @@
 	mddev->in_sync = 1;
 	smp_wmb();
 	mddev->ready = 1;
-	list_for_each_entry(rdev, &mddev->disks, same_set)
+	rdev_for_each(rdev, mddev)
 		if (rdev->raid_disk >= 0)
 			if (sysfs_link_rdev(mddev, rdev))
 				/* failure here is OK */;
@@ -5073,6 +5074,7 @@
 	mddev->changed = 0;
 	mddev->degraded = 0;
 	mddev->safemode = 0;
+	mddev->merge_check_needed = 0;
 	mddev->bitmap_info.offset = 0;
 	mddev->bitmap_info.default_offset = 0;
 	mddev->bitmap_info.chunksize = 0;
@@ -5175,7 +5177,7 @@
 		/* tell userspace to handle 'inactive' */
 		sysfs_notify_dirent_safe(mddev->sysfs_state);
 
-		list_for_each_entry(rdev, &mddev->disks, same_set)
+		rdev_for_each(rdev, mddev)
 			if (rdev->raid_disk >= 0)
 				sysfs_unlink_rdev(mddev, rdev);
 
@@ -5226,7 +5228,7 @@
 
 	printk(KERN_INFO "md: running: ");
 
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		char b[BDEVNAME_SIZE];
 		printk("<%s>", bdevname(rdev->bdev,b));
 	}
@@ -5356,7 +5358,7 @@
 	struct md_rdev *rdev;
 
 	nr=working=insync=failed=spare=0;
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		nr++;
 		if (test_bit(Faulty, &rdev->flags))
 			failed++;
@@ -5923,7 +5925,7 @@
 		 * grow, and re-add.
 		 */
 		return -EBUSY;
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		sector_t avail = rdev->sectors;
 
 		if (fit && (num_sectors == 0 || num_sectors > avail))
@@ -6724,7 +6726,6 @@
 	struct mddev *mddev = v;
 	sector_t sectors;
 	struct md_rdev *rdev;
-	struct bitmap *bitmap;
 
 	if (v == (void*)1) {
 		struct md_personality *pers;
@@ -6758,7 +6759,7 @@
 		}
 
 		sectors = 0;
-		list_for_each_entry(rdev, &mddev->disks, same_set) {
+		rdev_for_each(rdev, mddev) {
 			char b[BDEVNAME_SIZE];
 			seq_printf(seq, " %s[%d]",
 				bdevname(rdev->bdev,b), rdev->desc_nr);
@@ -6812,27 +6813,7 @@
 		} else
 			seq_printf(seq, "\n       ");
 
-		if ((bitmap = mddev->bitmap)) {
-			unsigned long chunk_kb;
-			unsigned long flags;
-			spin_lock_irqsave(&bitmap->lock, flags);
-			chunk_kb = mddev->bitmap_info.chunksize >> 10;
-			seq_printf(seq, "bitmap: %lu/%lu pages [%luKB], "
-				"%lu%s chunk",
-				bitmap->pages - bitmap->missing_pages,
-				bitmap->pages,
-				(bitmap->pages - bitmap->missing_pages)
-					<< (PAGE_SHIFT - 10),
-				chunk_kb ? chunk_kb : mddev->bitmap_info.chunksize,
-				chunk_kb ? "KB" : "B");
-			if (bitmap->file) {
-				seq_printf(seq, ", file: ");
-				seq_path(seq, &bitmap->file->f_path, " \t\n");
-			}
-
-			seq_printf(seq, "\n");
-			spin_unlock_irqrestore(&bitmap->lock, flags);
-		}
+		bitmap_status(seq, mddev->bitmap);
 
 		seq_printf(seq, "\n");
 	}
@@ -7170,7 +7151,7 @@
 		max_sectors = mddev->dev_sectors;
 		j = MaxSector;
 		rcu_read_lock();
-		list_for_each_entry_rcu(rdev, &mddev->disks, same_set)
+		rdev_for_each_rcu(rdev, mddev)
 			if (rdev->raid_disk >= 0 &&
 			    !test_bit(Faulty, &rdev->flags) &&
 			    !test_bit(In_sync, &rdev->flags) &&
@@ -7342,7 +7323,7 @@
 			if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
 				mddev->curr_resync = MaxSector;
 			rcu_read_lock();
-			list_for_each_entry_rcu(rdev, &mddev->disks, same_set)
+			rdev_for_each_rcu(rdev, mddev)
 				if (rdev->raid_disk >= 0 &&
 				    mddev->delta_disks >= 0 &&
 				    !test_bit(Faulty, &rdev->flags) &&
@@ -7388,7 +7369,7 @@
 
 	mddev->curr_resync_completed = 0;
 
-	list_for_each_entry(rdev, &mddev->disks, same_set)
+	rdev_for_each(rdev, mddev)
 		if (rdev->raid_disk >= 0 &&
 		    !test_bit(Blocked, &rdev->flags) &&
 		    (test_bit(Faulty, &rdev->flags) ||
@@ -7406,7 +7387,7 @@
 			     "degraded");
 
 
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		if (rdev->raid_disk >= 0 &&
 		    !test_bit(In_sync, &rdev->flags) &&
 		    !test_bit(Faulty, &rdev->flags))
@@ -7451,7 +7432,7 @@
 	 * do the superblock for an incrementally recovered device
 	 * written out.
 	 */
-	list_for_each_entry(rdev, &mddev->disks, same_set)
+	rdev_for_each(rdev, mddev)
 		if (!mddev->degraded ||
 		    test_bit(In_sync, &rdev->flags))
 			rdev->saved_raid_disk = -1;
@@ -7529,7 +7510,7 @@
 			 * failed devices.
 			 */
 			struct md_rdev *rdev;
-			list_for_each_entry(rdev, &mddev->disks, same_set)
+			rdev_for_each(rdev, mddev)
 				if (rdev->raid_disk >= 0 &&
 				    !test_bit(Blocked, &rdev->flags) &&
 				    test_bit(Faulty, &rdev->flags) &&
@@ -8040,7 +8021,7 @@
 		return;
 	write_seqlock_irq(&bb->lock);
 
-	if (bb->changed == 0) {
+	if (bb->changed == 0 && bb->unacked_exist) {
 		u64 *p = bb->page;
 		int i;
 		for (i = 0; i < bb->count ; i++) {
@@ -8157,30 +8138,23 @@
 	struct mddev *mddev;
 	int need_delay = 0;
 
-	if ((code == SYS_DOWN) || (code == SYS_HALT) || (code == SYS_POWER_OFF)) {
-
-		printk(KERN_INFO "md: stopping all md devices.\n");
-
-		for_each_mddev(mddev, tmp) {
-			if (mddev_trylock(mddev)) {
-				/* Force a switch to readonly even array
-				 * appears to still be in use.  Hence
-				 * the '100'.
-				 */
-				md_set_readonly(mddev, 100);
-				mddev_unlock(mddev);
-			}
-			need_delay = 1;
+	for_each_mddev(mddev, tmp) {
+		if (mddev_trylock(mddev)) {
+			__md_stop_writes(mddev);
+			mddev->safemode = 2;
+			mddev_unlock(mddev);
 		}
-		/*
-		 * certain more exotic SCSI devices are known to be
-		 * volatile wrt too early system reboots. While the
-		 * right place to handle this issue is the given
-		 * driver, we do want to have a safe RAID driver ...
-		 */
-		if (need_delay)
-			mdelay(1000*1);
+		need_delay = 1;
 	}
+	/*
+	 * certain more exotic SCSI devices are known to be
+	 * volatile wrt too early system reboots. While the
+	 * right place to handle this issue is the given
+	 * driver, we do want to have a safe RAID driver ...
+	 */
+	if (need_delay)
+		mdelay(1000*1);
+
 	return NOTIFY_DONE;
 }
 
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 44c63df..1c2063c 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -128,6 +128,10 @@
 enum flag_bits {
 	Faulty,			/* device is known to have a fault */
 	In_sync,		/* device is in_sync with rest of array */
+	Unmerged,		/* device is being added to array and should
+				 * be considerred for bvec_merge_fn but not
+				 * yet for actual IO
+				 */
 	WriteMostly,		/* Avoid reading if at all possible */
 	AutoDetected,		/* added by auto-detect */
 	Blocked,		/* An error occurred but has not yet
@@ -345,6 +349,10 @@
 	int				degraded;	/* whether md should consider
 							 * adding a spare
 							 */
+	int				merge_check_needed; /* at least one
+							     * member device
+							     * has a
+							     * merge_bvec_fn */
 
 	atomic_t			recovery_active; /* blocks scheduled, but not written */
 	wait_queue_head_t		recovery_wait;
@@ -519,7 +527,10 @@
 /*
  * iterates through the 'same array disks' ringlist
  */
-#define rdev_for_each(rdev, tmp, mddev)				\
+#define rdev_for_each(rdev, mddev)				\
+	list_for_each_entry(rdev, &((mddev)->disks), same_set)
+
+#define rdev_for_each_safe(rdev, tmp, mddev)				\
 	list_for_each_entry_safe(rdev, tmp, &((mddev)->disks), same_set)
 
 #define rdev_for_each_rcu(rdev, mddev)				\
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index a222f51..9339e67 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -428,7 +428,7 @@
 	}
 
 	working_disks = 0;
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		disk_idx = rdev->raid_disk;
 		if (disk_idx < 0 ||
 		    disk_idx >= mddev->raid_disks)
diff --git a/drivers/md/persistent-data/dm-btree-internal.h b/drivers/md/persistent-data/dm-btree-internal.h
index d279c76..5709bfe 100644
--- a/drivers/md/persistent-data/dm-btree-internal.h
+++ b/drivers/md/persistent-data/dm-btree-internal.h
@@ -108,12 +108,9 @@
 	return &n->keys[le32_to_cpu(n->header.max_entries)];
 }
 
-/*
- * FIXME: Now that value size is stored in node we don't need the third parm.
- */
-static inline void *value_ptr(struct node *n, uint32_t index, size_t value_size)
+static inline void *value_ptr(struct node *n, uint32_t index)
 {
-	BUG_ON(value_size != le32_to_cpu(n->header.value_size));
+	uint32_t value_size = le32_to_cpu(n->header.value_size);
 	return value_base(n) + (value_size * index);
 }
 
diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c
index 023fbc2..aa71e23 100644
--- a/drivers/md/persistent-data/dm-btree-remove.c
+++ b/drivers/md/persistent-data/dm-btree-remove.c
@@ -61,20 +61,20 @@
 	if (shift < 0) {
 		shift = -shift;
 		BUG_ON(shift > nr_entries);
-		BUG_ON((void *) key_ptr(n, shift) >= value_ptr(n, shift, value_size));
+		BUG_ON((void *) key_ptr(n, shift) >= value_ptr(n, shift));
 		memmove(key_ptr(n, 0),
 			key_ptr(n, shift),
 			(nr_entries - shift) * sizeof(__le64));
-		memmove(value_ptr(n, 0, value_size),
-			value_ptr(n, shift, value_size),
+		memmove(value_ptr(n, 0),
+			value_ptr(n, shift),
 			(nr_entries - shift) * value_size);
 	} else {
 		BUG_ON(nr_entries + shift > le32_to_cpu(n->header.max_entries));
 		memmove(key_ptr(n, shift),
 			key_ptr(n, 0),
 			nr_entries * sizeof(__le64));
-		memmove(value_ptr(n, shift, value_size),
-			value_ptr(n, 0, value_size),
+		memmove(value_ptr(n, shift),
+			value_ptr(n, 0),
 			nr_entries * value_size);
 	}
 }
@@ -91,16 +91,16 @@
 		memcpy(key_ptr(left, nr_left),
 		       key_ptr(right, 0),
 		       shift * sizeof(__le64));
-		memcpy(value_ptr(left, nr_left, value_size),
-		       value_ptr(right, 0, value_size),
+		memcpy(value_ptr(left, nr_left),
+		       value_ptr(right, 0),
 		       shift * value_size);
 	} else {
 		BUG_ON(shift > le32_to_cpu(right->header.max_entries));
 		memcpy(key_ptr(right, 0),
 		       key_ptr(left, nr_left - shift),
 		       shift * sizeof(__le64));
-		memcpy(value_ptr(right, 0, value_size),
-		       value_ptr(left, nr_left - shift, value_size),
+		memcpy(value_ptr(right, 0),
+		       value_ptr(left, nr_left - shift),
 		       shift * value_size);
 	}
 }
@@ -120,26 +120,17 @@
 			key_ptr(n, index + 1),
 			nr_to_copy * sizeof(__le64));
 
-		memmove(value_ptr(n, index, value_size),
-			value_ptr(n, index + 1, value_size),
+		memmove(value_ptr(n, index),
+			value_ptr(n, index + 1),
 			nr_to_copy * value_size);
 	}
 
 	n->header.nr_entries = cpu_to_le32(nr_entries - 1);
 }
 
-static unsigned del_threshold(struct node *n)
-{
-	return le32_to_cpu(n->header.max_entries) / 3;
-}
-
 static unsigned merge_threshold(struct node *n)
 {
-	/*
-	 * The extra one is because we know we're potentially going to
-	 * delete an entry.
-	 */
-	return 2 * (le32_to_cpu(n->header.max_entries) / 3) + 1;
+	return le32_to_cpu(n->header.max_entries) / 3;
 }
 
 struct child {
@@ -175,7 +166,7 @@
 	if (inc)
 		inc_children(info->tm, result->n, &le64_type);
 
-	*((__le64 *) value_ptr(parent, index, sizeof(__le64))) =
+	*((__le64 *) value_ptr(parent, index)) =
 		cpu_to_le64(dm_block_location(result->block));
 
 	return 0;
@@ -188,6 +179,15 @@
 
 static void shift(struct node *left, struct node *right, int count)
 {
+	uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
+	uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
+	uint32_t max_entries = le32_to_cpu(left->header.max_entries);
+	uint32_t r_max_entries = le32_to_cpu(right->header.max_entries);
+
+	BUG_ON(max_entries != r_max_entries);
+	BUG_ON(nr_left - count > max_entries);
+	BUG_ON(nr_right + count > max_entries);
+
 	if (!count)
 		return;
 
@@ -199,13 +199,8 @@
 		node_shift(right, count);
 	}
 
-	left->header.nr_entries =
-		cpu_to_le32(le32_to_cpu(left->header.nr_entries) - count);
-	BUG_ON(le32_to_cpu(left->header.nr_entries) > le32_to_cpu(left->header.max_entries));
-
-	right->header.nr_entries =
-		cpu_to_le32(le32_to_cpu(right->header.nr_entries) + count);
-	BUG_ON(le32_to_cpu(right->header.nr_entries) > le32_to_cpu(right->header.max_entries));
+	left->header.nr_entries = cpu_to_le32(nr_left - count);
+	right->header.nr_entries = cpu_to_le32(nr_right + count);
 }
 
 static void __rebalance2(struct dm_btree_info *info, struct node *parent,
@@ -215,8 +210,9 @@
 	struct node *right = r->n;
 	uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
 	uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
+	unsigned threshold = 2 * merge_threshold(left) + 1;
 
-	if (nr_left + nr_right <= merge_threshold(left)) {
+	if (nr_left + nr_right < threshold) {
 		/*
 		 * Merge
 		 */
@@ -234,9 +230,6 @@
 		 * Rebalance.
 		 */
 		unsigned target_left = (nr_left + nr_right) / 2;
-		unsigned shift_ = nr_left - target_left;
-		BUG_ON(le32_to_cpu(left->header.max_entries) <= nr_left - shift_);
-		BUG_ON(le32_to_cpu(right->header.max_entries) <= nr_right + shift_);
 		shift(left, right, nr_left - target_left);
 		*key_ptr(parent, r->index) = right->keys[0];
 	}
@@ -272,6 +265,84 @@
 	return exit_child(info, &right);
 }
 
+/*
+ * We dump as many entries from center as possible into left, then the rest
+ * in right, then rebalance2.  This wastes some cpu, but I want something
+ * simple atm.
+ */
+static void delete_center_node(struct dm_btree_info *info, struct node *parent,
+			       struct child *l, struct child *c, struct child *r,
+			       struct node *left, struct node *center, struct node *right,
+			       uint32_t nr_left, uint32_t nr_center, uint32_t nr_right)
+{
+	uint32_t max_entries = le32_to_cpu(left->header.max_entries);
+	unsigned shift = min(max_entries - nr_left, nr_center);
+
+	BUG_ON(nr_left + shift > max_entries);
+	node_copy(left, center, -shift);
+	left->header.nr_entries = cpu_to_le32(nr_left + shift);
+
+	if (shift != nr_center) {
+		shift = nr_center - shift;
+		BUG_ON((nr_right + shift) > max_entries);
+		node_shift(right, shift);
+		node_copy(center, right, shift);
+		right->header.nr_entries = cpu_to_le32(nr_right + shift);
+	}
+	*key_ptr(parent, r->index) = right->keys[0];
+
+	delete_at(parent, c->index);
+	r->index--;
+
+	dm_tm_dec(info->tm, dm_block_location(c->block));
+	__rebalance2(info, parent, l, r);
+}
+
+/*
+ * Redistributes entries among 3 sibling nodes.
+ */
+static void redistribute3(struct dm_btree_info *info, struct node *parent,
+			  struct child *l, struct child *c, struct child *r,
+			  struct node *left, struct node *center, struct node *right,
+			  uint32_t nr_left, uint32_t nr_center, uint32_t nr_right)
+{
+	int s;
+	uint32_t max_entries = le32_to_cpu(left->header.max_entries);
+	unsigned target = (nr_left + nr_center + nr_right) / 3;
+	BUG_ON(target > max_entries);
+
+	if (nr_left < nr_right) {
+		s = nr_left - target;
+
+		if (s < 0 && nr_center < -s) {
+			/* not enough in central node */
+			shift(left, center, nr_center);
+			s = nr_center - target;
+			shift(left, right, s);
+			nr_right += s;
+		} else
+			shift(left, center, s);
+
+		shift(center, right, target - nr_right);
+
+	} else {
+		s = target - nr_right;
+		if (s > 0 && nr_center < s) {
+			/* not enough in central node */
+			shift(center, right, nr_center);
+			s = target - nr_center;
+			shift(left, right, s);
+			nr_left -= s;
+		} else
+			shift(center, right, s);
+
+		shift(left, center, nr_left - target);
+	}
+
+	*key_ptr(parent, c->index) = center->keys[0];
+	*key_ptr(parent, r->index) = right->keys[0];
+}
+
 static void __rebalance3(struct dm_btree_info *info, struct node *parent,
 			 struct child *l, struct child *c, struct child *r)
 {
@@ -282,62 +353,18 @@
 	uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
 	uint32_t nr_center = le32_to_cpu(center->header.nr_entries);
 	uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
-	uint32_t max_entries = le32_to_cpu(left->header.max_entries);
 
-	unsigned target;
+	unsigned threshold = merge_threshold(left) * 4 + 1;
 
 	BUG_ON(left->header.max_entries != center->header.max_entries);
 	BUG_ON(center->header.max_entries != right->header.max_entries);
 
-	if (((nr_left + nr_center + nr_right) / 2) < merge_threshold(center)) {
-		/*
-		 * Delete center node:
-		 *
-		 * We dump as many entries from center as possible into
-		 * left, then the rest in right, then rebalance2.  This
-		 * wastes some cpu, but I want something simple atm.
-		 */
-		unsigned shift = min(max_entries - nr_left, nr_center);
-
-		BUG_ON(nr_left + shift > max_entries);
-		node_copy(left, center, -shift);
-		left->header.nr_entries = cpu_to_le32(nr_left + shift);
-
-		if (shift != nr_center) {
-			shift = nr_center - shift;
-			BUG_ON((nr_right + shift) >= max_entries);
-			node_shift(right, shift);
-			node_copy(center, right, shift);
-			right->header.nr_entries = cpu_to_le32(nr_right + shift);
-		}
-		*key_ptr(parent, r->index) = right->keys[0];
-
-		delete_at(parent, c->index);
-		r->index--;
-
-		dm_tm_dec(info->tm, dm_block_location(c->block));
-		__rebalance2(info, parent, l, r);
-
-		return;
-	}
-
-	/*
-	 * Rebalance
-	 */
-	target = (nr_left + nr_center + nr_right) / 3;
-	BUG_ON(target > max_entries);
-
-	/*
-	 * Adjust the left node
-	 */
-	shift(left, center, nr_left - target);
-
-	/*
-	 * Adjust the right node
-	 */
-	shift(center, right, target - nr_right);
-	*key_ptr(parent, c->index) = center->keys[0];
-	*key_ptr(parent, r->index) = right->keys[0];
+	if ((nr_left + nr_center + nr_right) < threshold)
+		delete_center_node(info, parent, l, c, r, left, center, right,
+				   nr_left, nr_center, nr_right);
+	else
+		redistribute3(info, parent, l, c, r, left, center, right,
+			      nr_left, nr_center, nr_right);
 }
 
 static int rebalance3(struct shadow_spine *s, struct dm_btree_info *info,
@@ -441,9 +468,6 @@
 	if (r)
 		return r;
 
-	if (child_entries > del_threshold(n))
-		return 0;
-
 	has_left_sibling = i > 0;
 	has_right_sibling = i < (le32_to_cpu(n->header.nr_entries) - 1);
 
@@ -496,7 +520,7 @@
 		 */
 		if (shadow_has_parent(s)) {
 			__le64 location = cpu_to_le64(dm_block_location(shadow_current(s)));
-			memcpy(value_ptr(dm_block_data(shadow_parent(s)), i, sizeof(__le64)),
+			memcpy(value_ptr(dm_block_data(shadow_parent(s)), i),
 			       &location, sizeof(__le64));
 		}
 
@@ -553,7 +577,7 @@
 
 		if (info->value_type.dec)
 			info->value_type.dec(info->value_type.context,
-					     value_ptr(n, index, info->value_type.size));
+					     value_ptr(n, index));
 
 		delete_at(n, index);
 	}
diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c
index bd1e7ff..d12b2cc 100644
--- a/drivers/md/persistent-data/dm-btree.c
+++ b/drivers/md/persistent-data/dm-btree.c
@@ -74,8 +74,7 @@
 			dm_tm_inc(tm, value64(n, i));
 	else if (vt->inc)
 		for (i = 0; i < nr_entries; i++)
-			vt->inc(vt->context,
-				value_ptr(n, i, vt->size));
+			vt->inc(vt->context, value_ptr(n, i));
 }
 
 static int insert_at(size_t value_size, struct node *node, unsigned index,
@@ -281,7 +280,7 @@
 
 				for (i = 0; i < f->nr_children; i++)
 					info->value_type.dec(info->value_type.context,
-							     value_ptr(f->n, i, info->value_type.size));
+							     value_ptr(f->n, i));
 			}
 			f->current_child = f->nr_children;
 		}
@@ -320,7 +319,7 @@
 	} while (!(flags & LEAF_NODE));
 
 	*result_key = le64_to_cpu(ro_node(s)->keys[i]);
-	memcpy(v, value_ptr(ro_node(s), i, value_size), value_size);
+	memcpy(v, value_ptr(ro_node(s), i), value_size);
 
 	return 0;
 }
@@ -432,7 +431,7 @@
 
 	size = le32_to_cpu(ln->header.flags) & INTERNAL_NODE ?
 		sizeof(uint64_t) : s->info->value_type.size;
-	memcpy(value_ptr(rn, 0, size), value_ptr(ln, nr_left, size),
+	memcpy(value_ptr(rn, 0), value_ptr(ln, nr_left),
 	       size * nr_right);
 
 	/*
@@ -443,7 +442,7 @@
 	pn = dm_block_data(parent);
 	location = cpu_to_le64(dm_block_location(left));
 	__dm_bless_for_disk(&location);
-	memcpy_disk(value_ptr(pn, parent_index, sizeof(__le64)),
+	memcpy_disk(value_ptr(pn, parent_index),
 		    &location, sizeof(__le64));
 
 	location = cpu_to_le64(dm_block_location(right));
@@ -529,8 +528,8 @@
 
 	size = le32_to_cpu(pn->header.flags) & INTERNAL_NODE ?
 		sizeof(__le64) : s->info->value_type.size;
-	memcpy(value_ptr(ln, 0, size), value_ptr(pn, 0, size), nr_left * size);
-	memcpy(value_ptr(rn, 0, size), value_ptr(pn, nr_left, size),
+	memcpy(value_ptr(ln, 0), value_ptr(pn, 0), nr_left * size);
+	memcpy(value_ptr(rn, 0), value_ptr(pn, nr_left),
 	       nr_right * size);
 
 	/* new_parent should just point to l and r now */
@@ -545,12 +544,12 @@
 	val = cpu_to_le64(dm_block_location(left));
 	__dm_bless_for_disk(&val);
 	pn->keys[0] = ln->keys[0];
-	memcpy_disk(value_ptr(pn, 0, sizeof(__le64)), &val, sizeof(__le64));
+	memcpy_disk(value_ptr(pn, 0), &val, sizeof(__le64));
 
 	val = cpu_to_le64(dm_block_location(right));
 	__dm_bless_for_disk(&val);
 	pn->keys[1] = rn->keys[0];
-	memcpy_disk(value_ptr(pn, 1, sizeof(__le64)), &val, sizeof(__le64));
+	memcpy_disk(value_ptr(pn, 1), &val, sizeof(__le64));
 
 	/*
 	 * rejig the spine.  This is ugly, since it knows too
@@ -595,7 +594,7 @@
 			__le64 location = cpu_to_le64(dm_block_location(shadow_current(s)));
 
 			__dm_bless_for_disk(&location);
-			memcpy_disk(value_ptr(dm_block_data(shadow_parent(s)), i, sizeof(uint64_t)),
+			memcpy_disk(value_ptr(dm_block_data(shadow_parent(s)), i),
 				    &location, sizeof(__le64));
 		}
 
@@ -710,12 +709,12 @@
 		    (!info->value_type.equal ||
 		     !info->value_type.equal(
 			     info->value_type.context,
-			     value_ptr(n, index, info->value_type.size),
+			     value_ptr(n, index),
 			     value))) {
 			info->value_type.dec(info->value_type.context,
-					     value_ptr(n, index, info->value_type.size));
+					     value_ptr(n, index));
 		}
-		memcpy_disk(value_ptr(n, index, info->value_type.size),
+		memcpy_disk(value_ptr(n, index),
 			    value, info->value_type.size);
 	}
 
diff --git a/drivers/md/persistent-data/dm-space-map-common.c b/drivers/md/persistent-data/dm-space-map-common.c
index df2494c..ff3beed 100644
--- a/drivers/md/persistent-data/dm-space-map-common.c
+++ b/drivers/md/persistent-data/dm-space-map-common.c
@@ -405,8 +405,6 @@
 		if (r < 0)
 			return r;
 
-#if 0
-		/* FIXME: dm_btree_remove doesn't handle this yet */
 		if (old > 2) {
 			r = dm_btree_remove(&ll->ref_count_info,
 					    ll->ref_count_root,
@@ -414,7 +412,6 @@
 			if (r)
 				return r;
 		}
-#endif
 
 	} else {
 		__le32 le_rc = cpu_to_le32(ref_count);
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 7294bd1..de63a1f 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -91,7 +91,7 @@
 
 	if (!conf)
 		return -ENOMEM;
-	list_for_each_entry(rdev1, &mddev->disks, same_set) {
+	rdev_for_each(rdev1, mddev) {
 		pr_debug("md/raid0:%s: looking at %s\n",
 			 mdname(mddev),
 			 bdevname(rdev1->bdev, b));
@@ -102,7 +102,7 @@
 		sector_div(sectors, mddev->chunk_sectors);
 		rdev1->sectors = sectors * mddev->chunk_sectors;
 
-		list_for_each_entry(rdev2, &mddev->disks, same_set) {
+		rdev_for_each(rdev2, mddev) {
 			pr_debug("md/raid0:%s:   comparing %s(%llu)"
 				 " with %s(%llu)\n",
 				 mdname(mddev),
@@ -157,7 +157,7 @@
 	smallest = NULL;
 	dev = conf->devlist;
 	err = -EINVAL;
-	list_for_each_entry(rdev1, &mddev->disks, same_set) {
+	rdev_for_each(rdev1, mddev) {
 		int j = rdev1->raid_disk;
 
 		if (mddev->level == 10) {
@@ -188,16 +188,10 @@
 
 		disk_stack_limits(mddev->gendisk, rdev1->bdev,
 				  rdev1->data_offset << 9);
-		/* as we don't honour merge_bvec_fn, we must never risk
-		 * violating it, so limit ->max_segments to 1, lying within
-		 * a single page.
-		 */
 
-		if (rdev1->bdev->bd_disk->queue->merge_bvec_fn) {
-			blk_queue_max_segments(mddev->queue, 1);
-			blk_queue_segment_boundary(mddev->queue,
-						   PAGE_CACHE_SIZE - 1);
-		}
+		if (rdev1->bdev->bd_disk->queue->merge_bvec_fn)
+			conf->has_merge_bvec = 1;
+
 		if (!smallest || (rdev1->sectors < smallest->sectors))
 			smallest = rdev1;
 		cnt++;
@@ -290,113 +284,6 @@
 	return err;
 }
 
-/**
- *	raid0_mergeable_bvec -- tell bio layer if a two requests can be merged
- *	@q: request queue
- *	@bvm: properties of new bio
- *	@biovec: the request that could be merged to it.
- *
- *	Return amount of bytes we can accept at this offset
- */
-static int raid0_mergeable_bvec(struct request_queue *q,
-				struct bvec_merge_data *bvm,
-				struct bio_vec *biovec)
-{
-	struct mddev *mddev = q->queuedata;
-	sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
-	int max;
-	unsigned int chunk_sectors = mddev->chunk_sectors;
-	unsigned int bio_sectors = bvm->bi_size >> 9;
-
-	if (is_power_of_2(chunk_sectors))
-		max =  (chunk_sectors - ((sector & (chunk_sectors-1))
-						+ bio_sectors)) << 9;
-	else
-		max =  (chunk_sectors - (sector_div(sector, chunk_sectors)
-						+ bio_sectors)) << 9;
-	if (max < 0) max = 0; /* bio_add cannot handle a negative return */
-	if (max <= biovec->bv_len && bio_sectors == 0)
-		return biovec->bv_len;
-	else 
-		return max;
-}
-
-static sector_t raid0_size(struct mddev *mddev, sector_t sectors, int raid_disks)
-{
-	sector_t array_sectors = 0;
-	struct md_rdev *rdev;
-
-	WARN_ONCE(sectors || raid_disks,
-		  "%s does not support generic reshape\n", __func__);
-
-	list_for_each_entry(rdev, &mddev->disks, same_set)
-		array_sectors += rdev->sectors;
-
-	return array_sectors;
-}
-
-static int raid0_run(struct mddev *mddev)
-{
-	struct r0conf *conf;
-	int ret;
-
-	if (mddev->chunk_sectors == 0) {
-		printk(KERN_ERR "md/raid0:%s: chunk size must be set.\n",
-		       mdname(mddev));
-		return -EINVAL;
-	}
-	if (md_check_no_bitmap(mddev))
-		return -EINVAL;
-	blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors);
-
-	/* if private is not null, we are here after takeover */
-	if (mddev->private == NULL) {
-		ret = create_strip_zones(mddev, &conf);
-		if (ret < 0)
-			return ret;
-		mddev->private = conf;
-	}
-	conf = mddev->private;
-
-	/* calculate array device size */
-	md_set_array_sectors(mddev, raid0_size(mddev, 0, 0));
-
-	printk(KERN_INFO "md/raid0:%s: md_size is %llu sectors.\n",
-	       mdname(mddev),
-	       (unsigned long long)mddev->array_sectors);
-	/* calculate the max read-ahead size.
-	 * For read-ahead of large files to be effective, we need to
-	 * readahead at least twice a whole stripe. i.e. number of devices
-	 * multiplied by chunk size times 2.
-	 * If an individual device has an ra_pages greater than the
-	 * chunk size, then we will not drive that device as hard as it
-	 * wants.  We consider this a configuration error: a larger
-	 * chunksize should be used in that case.
-	 */
-	{
-		int stripe = mddev->raid_disks *
-			(mddev->chunk_sectors << 9) / PAGE_SIZE;
-		if (mddev->queue->backing_dev_info.ra_pages < 2* stripe)
-			mddev->queue->backing_dev_info.ra_pages = 2* stripe;
-	}
-
-	blk_queue_merge_bvec(mddev->queue, raid0_mergeable_bvec);
-	dump_zones(mddev);
-	return md_integrity_register(mddev);
-}
-
-static int raid0_stop(struct mddev *mddev)
-{
-	struct r0conf *conf = mddev->private;
-
-	blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
-	kfree(conf->strip_zone);
-	kfree(conf->devlist);
-	kfree(conf);
-	mddev->private = NULL;
-	return 0;
-}
-
 /* Find the zone which holds a particular offset
  * Update *sectorp to be an offset in that zone
  */
@@ -453,6 +340,142 @@
 			     + sector_div(sector, zone->nb_dev)];
 }
 
+/**
+ *	raid0_mergeable_bvec -- tell bio layer if two requests can be merged
+ *	@q: request queue
+ *	@bvm: properties of new bio
+ *	@biovec: the request that could be merged to it.
+ *
+ *	Return amount of bytes we can accept at this offset
+ */
+static int raid0_mergeable_bvec(struct request_queue *q,
+				struct bvec_merge_data *bvm,
+				struct bio_vec *biovec)
+{
+	struct mddev *mddev = q->queuedata;
+	struct r0conf *conf = mddev->private;
+	sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
+	sector_t sector_offset = sector;
+	int max;
+	unsigned int chunk_sectors = mddev->chunk_sectors;
+	unsigned int bio_sectors = bvm->bi_size >> 9;
+	struct strip_zone *zone;
+	struct md_rdev *rdev;
+	struct request_queue *subq;
+
+	if (is_power_of_2(chunk_sectors))
+		max =  (chunk_sectors - ((sector & (chunk_sectors-1))
+						+ bio_sectors)) << 9;
+	else
+		max =  (chunk_sectors - (sector_div(sector, chunk_sectors)
+						+ bio_sectors)) << 9;
+	if (max < 0)
+		max = 0; /* bio_add cannot handle a negative return */
+	if (max <= biovec->bv_len && bio_sectors == 0)
+		return biovec->bv_len;
+	if (max < biovec->bv_len)
+		/* too small already, no need to check further */
+		return max;
+	if (!conf->has_merge_bvec)
+		return max;
+
+	/* May need to check subordinate device */
+	sector = sector_offset;
+	zone = find_zone(mddev->private, &sector_offset);
+	rdev = map_sector(mddev, zone, sector, &sector_offset);
+	subq = bdev_get_queue(rdev->bdev);
+	if (subq->merge_bvec_fn) {
+		bvm->bi_bdev = rdev->bdev;
+		bvm->bi_sector = sector_offset + zone->dev_start +
+			rdev->data_offset;
+		return min(max, subq->merge_bvec_fn(subq, bvm, biovec));
+	} else
+		return max;
+}
+
+static sector_t raid0_size(struct mddev *mddev, sector_t sectors, int raid_disks)
+{
+	sector_t array_sectors = 0;
+	struct md_rdev *rdev;
+
+	WARN_ONCE(sectors || raid_disks,
+		  "%s does not support generic reshape\n", __func__);
+
+	rdev_for_each(rdev, mddev)
+		array_sectors += rdev->sectors;
+
+	return array_sectors;
+}
+
+static int raid0_stop(struct mddev *mddev);
+
+static int raid0_run(struct mddev *mddev)
+{
+	struct r0conf *conf;
+	int ret;
+
+	if (mddev->chunk_sectors == 0) {
+		printk(KERN_ERR "md/raid0:%s: chunk size must be set.\n",
+		       mdname(mddev));
+		return -EINVAL;
+	}
+	if (md_check_no_bitmap(mddev))
+		return -EINVAL;
+	blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors);
+
+	/* if private is not null, we are here after takeover */
+	if (mddev->private == NULL) {
+		ret = create_strip_zones(mddev, &conf);
+		if (ret < 0)
+			return ret;
+		mddev->private = conf;
+	}
+	conf = mddev->private;
+
+	/* calculate array device size */
+	md_set_array_sectors(mddev, raid0_size(mddev, 0, 0));
+
+	printk(KERN_INFO "md/raid0:%s: md_size is %llu sectors.\n",
+	       mdname(mddev),
+	       (unsigned long long)mddev->array_sectors);
+	/* calculate the max read-ahead size.
+	 * For read-ahead of large files to be effective, we need to
+	 * readahead at least twice a whole stripe. i.e. number of devices
+	 * multiplied by chunk size times 2.
+	 * If an individual device has an ra_pages greater than the
+	 * chunk size, then we will not drive that device as hard as it
+	 * wants.  We consider this a configuration error: a larger
+	 * chunksize should be used in that case.
+	 */
+	{
+		int stripe = mddev->raid_disks *
+			(mddev->chunk_sectors << 9) / PAGE_SIZE;
+		if (mddev->queue->backing_dev_info.ra_pages < 2* stripe)
+			mddev->queue->backing_dev_info.ra_pages = 2* stripe;
+	}
+
+	blk_queue_merge_bvec(mddev->queue, raid0_mergeable_bvec);
+	dump_zones(mddev);
+
+	ret = md_integrity_register(mddev);
+	if (ret)
+		raid0_stop(mddev);
+
+	return ret;
+}
+
+static int raid0_stop(struct mddev *mddev)
+{
+	struct r0conf *conf = mddev->private;
+
+	blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
+	kfree(conf->strip_zone);
+	kfree(conf->devlist);
+	kfree(conf);
+	mddev->private = NULL;
+	return 0;
+}
+
 /*
  * Is io distribute over 1 or more chunks ?
 */
@@ -505,7 +528,7 @@
 	}
 
 	sector_offset = bio->bi_sector;
-	zone =  find_zone(mddev->private, &sector_offset);
+	zone = find_zone(mddev->private, &sector_offset);
 	tmp_dev = map_sector(mddev, zone, bio->bi_sector,
 			     &sector_offset);
 	bio->bi_bdev = tmp_dev->bdev;
@@ -543,7 +566,7 @@
 		return ERR_PTR(-EINVAL);
 	}
 
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		/* check slot number for a disk */
 		if (rdev->raid_disk == mddev->raid_disks-1) {
 			printk(KERN_ERR "md/raid0:%s: raid5 must have missing parity disk!\n",
@@ -609,6 +632,7 @@
 static void *raid0_takeover_raid1(struct mddev *mddev)
 {
 	struct r0conf *priv_conf;
+	int chunksect;
 
 	/* Check layout:
 	 *  - (N - 1) mirror drives must be already faulty
@@ -619,10 +643,25 @@
 		return ERR_PTR(-EINVAL);
 	}
 
+	/*
+	 * a raid1 doesn't have the notion of chunk size, so
+	 * figure out the largest suitable size we can use.
+	 */
+	chunksect = 64 * 2; /* 64K by default */
+
+	/* The array must be an exact multiple of chunksize */
+	while (chunksect && (mddev->array_sectors & (chunksect - 1)))
+		chunksect >>= 1;
+
+	if ((chunksect << 9) < PAGE_SIZE)
+		/* array size does not allow a suitable chunk size */
+		return ERR_PTR(-EINVAL);
+
 	/* Set new parameters */
 	mddev->new_level = 0;
 	mddev->new_layout = 0;
-	mddev->new_chunk_sectors = 128; /* by default set chunk size to 64k */
+	mddev->new_chunk_sectors = chunksect;
+	mddev->chunk_sectors = chunksect;
 	mddev->delta_disks = 1 - mddev->raid_disks;
 	mddev->raid_disks = 1;
 	/* make sure it will be not marked as dirty */
diff --git a/drivers/md/raid0.h b/drivers/md/raid0.h
index 0884bba..05539d9 100644
--- a/drivers/md/raid0.h
+++ b/drivers/md/raid0.h
@@ -4,13 +4,16 @@
 struct strip_zone {
 	sector_t zone_end;	/* Start of the next zone (in sectors) */
 	sector_t dev_start;	/* Zone offset in real dev (in sectors) */
-	int nb_dev;		/* # of devices attached to the zone */
+	int	 nb_dev;	/* # of devices attached to the zone */
 };
 
 struct r0conf {
-	struct strip_zone *strip_zone;
-	struct md_rdev **devlist; /* lists of rdevs, pointed to by strip_zone->dev */
-	int nr_strip_zones;
+	struct strip_zone	*strip_zone;
+	struct md_rdev		**devlist; /* lists of rdevs, pointed to
+					    * by strip_zone->dev */
+	int			nr_strip_zones;
+	int			has_merge_bvec;	/* at least one member has
+						 * a merge_bvec_fn */
 };
 
 #endif
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index a0b225e..d35e4c9 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -523,6 +523,7 @@
 		rdev = rcu_dereference(conf->mirrors[disk].rdev);
 		if (r1_bio->bios[disk] == IO_BLOCKED
 		    || rdev == NULL
+		    || test_bit(Unmerged, &rdev->flags)
 		    || test_bit(Faulty, &rdev->flags))
 			continue;
 		if (!test_bit(In_sync, &rdev->flags) &&
@@ -614,6 +615,39 @@
 	return best_disk;
 }
 
+static int raid1_mergeable_bvec(struct request_queue *q,
+				struct bvec_merge_data *bvm,
+				struct bio_vec *biovec)
+{
+	struct mddev *mddev = q->queuedata;
+	struct r1conf *conf = mddev->private;
+	sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
+	int max = biovec->bv_len;
+
+	if (mddev->merge_check_needed) {
+		int disk;
+		rcu_read_lock();
+		for (disk = 0; disk < conf->raid_disks * 2; disk++) {
+			struct md_rdev *rdev = rcu_dereference(
+				conf->mirrors[disk].rdev);
+			if (rdev && !test_bit(Faulty, &rdev->flags)) {
+				struct request_queue *q =
+					bdev_get_queue(rdev->bdev);
+				if (q->merge_bvec_fn) {
+					bvm->bi_sector = sector +
+						rdev->data_offset;
+					bvm->bi_bdev = rdev->bdev;
+					max = min(max, q->merge_bvec_fn(
+							  q, bvm, biovec));
+				}
+			}
+		}
+		rcu_read_unlock();
+	}
+	return max;
+
+}
+
 int md_raid1_congested(struct mddev *mddev, int bits)
 {
 	struct r1conf *conf = mddev->private;
@@ -737,9 +771,22 @@
 	spin_lock_irq(&conf->resync_lock);
 	if (conf->barrier) {
 		conf->nr_waiting++;
-		wait_event_lock_irq(conf->wait_barrier, !conf->barrier,
+		/* Wait for the barrier to drop.
+		 * However if there are already pending
+		 * requests (preventing the barrier from
+		 * rising completely), and the
+		 * pre-process bio queue isn't empty,
+		 * then don't wait, as we need to empty
+		 * that queue to get the nr_pending
+		 * count down.
+		 */
+		wait_event_lock_irq(conf->wait_barrier,
+				    !conf->barrier ||
+				    (conf->nr_pending &&
+				     current->bio_list &&
+				     !bio_list_empty(current->bio_list)),
 				    conf->resync_lock,
-				    );
+			);
 		conf->nr_waiting--;
 	}
 	conf->nr_pending++;
@@ -1002,7 +1049,8 @@
 			break;
 		}
 		r1_bio->bios[i] = NULL;
-		if (!rdev || test_bit(Faulty, &rdev->flags)) {
+		if (!rdev || test_bit(Faulty, &rdev->flags)
+		    || test_bit(Unmerged, &rdev->flags)) {
 			if (i < conf->raid_disks)
 				set_bit(R1BIO_Degraded, &r1_bio->state);
 			continue;
@@ -1322,6 +1370,7 @@
 	struct mirror_info *p;
 	int first = 0;
 	int last = conf->raid_disks - 1;
+	struct request_queue *q = bdev_get_queue(rdev->bdev);
 
 	if (mddev->recovery_disabled == conf->recovery_disabled)
 		return -EBUSY;
@@ -1329,23 +1378,17 @@
 	if (rdev->raid_disk >= 0)
 		first = last = rdev->raid_disk;
 
+	if (q->merge_bvec_fn) {
+		set_bit(Unmerged, &rdev->flags);
+		mddev->merge_check_needed = 1;
+	}
+
 	for (mirror = first; mirror <= last; mirror++) {
 		p = conf->mirrors+mirror;
 		if (!p->rdev) {
 
 			disk_stack_limits(mddev->gendisk, rdev->bdev,
 					  rdev->data_offset << 9);
-			/* as we don't honour merge_bvec_fn, we must
-			 * never risk violating it, so limit
-			 * ->max_segments to one lying with a single
-			 * page, as a one page request is never in
-			 * violation.
-			 */
-			if (rdev->bdev->bd_disk->queue->merge_bvec_fn) {
-				blk_queue_max_segments(mddev->queue, 1);
-				blk_queue_segment_boundary(mddev->queue,
-							   PAGE_CACHE_SIZE - 1);
-			}
 
 			p->head_position = 0;
 			rdev->raid_disk = mirror;
@@ -1370,6 +1413,19 @@
 			break;
 		}
 	}
+	if (err == 0 && test_bit(Unmerged, &rdev->flags)) {
+		/* Some requests might not have seen this new
+		 * merge_bvec_fn.  We must wait for them to complete
+		 * before merging the device fully.
+		 * First we make sure any code which has tested
+		 * our function has submitted the request, then
+		 * we wait for all outstanding requests to complete.
+		 */
+		synchronize_sched();
+		raise_barrier(conf);
+		lower_barrier(conf);
+		clear_bit(Unmerged, &rdev->flags);
+	}
 	md_integrity_add_rdev(rdev, mddev);
 	print_conf(conf);
 	return err;
@@ -1682,7 +1738,7 @@
 				s = sbio->bi_io_vec[j].bv_page;
 				if (memcmp(page_address(p),
 					   page_address(s),
-					   PAGE_SIZE))
+					   sbio->bi_io_vec[j].bv_len))
 					break;
 			}
 		} else
@@ -2330,8 +2386,7 @@
 		int ok = 1;
 		for (i = 0 ; i < conf->raid_disks * 2 ; i++)
 			if (r1_bio->bios[i]->bi_end_io == end_sync_write) {
-				struct md_rdev *rdev =
-					rcu_dereference(conf->mirrors[i].rdev);
+				struct md_rdev *rdev = conf->mirrors[i].rdev;
 				ok = rdev_set_badblocks(rdev, sector_nr,
 							min_bad, 0
 					) && ok;
@@ -2491,7 +2546,7 @@
 
 	err = -EINVAL;
 	spin_lock_init(&conf->device_lock);
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		int disk_idx = rdev->raid_disk;
 		if (disk_idx >= mddev->raid_disks
 		    || disk_idx < 0)
@@ -2580,11 +2635,13 @@
 	return ERR_PTR(err);
 }
 
+static int stop(struct mddev *mddev);
 static int run(struct mddev *mddev)
 {
 	struct r1conf *conf;
 	int i;
 	struct md_rdev *rdev;
+	int ret;
 
 	if (mddev->level != 1) {
 		printk(KERN_ERR "md/raid1:%s: raid level not set to mirroring (%d)\n",
@@ -2609,20 +2666,11 @@
 	if (IS_ERR(conf))
 		return PTR_ERR(conf);
 
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		if (!mddev->gendisk)
 			continue;
 		disk_stack_limits(mddev->gendisk, rdev->bdev,
 				  rdev->data_offset << 9);
-		/* as we don't honour merge_bvec_fn, we must never risk
-		 * violating it, so limit ->max_segments to 1 lying within
-		 * a single page, as a one page request is never in violation.
-		 */
-		if (rdev->bdev->bd_disk->queue->merge_bvec_fn) {
-			blk_queue_max_segments(mddev->queue, 1);
-			blk_queue_segment_boundary(mddev->queue,
-						   PAGE_CACHE_SIZE - 1);
-		}
 	}
 
 	mddev->degraded = 0;
@@ -2656,8 +2704,13 @@
 	if (mddev->queue) {
 		mddev->queue->backing_dev_info.congested_fn = raid1_congested;
 		mddev->queue->backing_dev_info.congested_data = mddev;
+		blk_queue_merge_bvec(mddev->queue, raid1_mergeable_bvec);
 	}
-	return md_integrity_register(mddev);
+
+	ret =  md_integrity_register(mddev);
+	if (ret)
+		stop(mddev);
+	return ret;
 }
 
 static int stop(struct mddev *mddev)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 58c44d6..fff7821 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -586,25 +586,68 @@
  *	@biovec: the request that could be merged to it.
  *
  *	Return amount of bytes we can accept at this offset
- *      If near_copies == raid_disk, there are no striping issues,
- *      but in that case, the function isn't called at all.
+ *	This requires checking for end-of-chunk if near_copies != raid_disks,
+ *	and for subordinate merge_bvec_fns if merge_check_needed.
  */
 static int raid10_mergeable_bvec(struct request_queue *q,
 				 struct bvec_merge_data *bvm,
 				 struct bio_vec *biovec)
 {
 	struct mddev *mddev = q->queuedata;
+	struct r10conf *conf = mddev->private;
 	sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
 	int max;
 	unsigned int chunk_sectors = mddev->chunk_sectors;
 	unsigned int bio_sectors = bvm->bi_size >> 9;
 
-	max =  (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9;
-	if (max < 0) max = 0; /* bio_add cannot handle a negative return */
-	if (max <= biovec->bv_len && bio_sectors == 0)
-		return biovec->bv_len;
-	else
-		return max;
+	if (conf->near_copies < conf->raid_disks) {
+		max = (chunk_sectors - ((sector & (chunk_sectors - 1))
+					+ bio_sectors)) << 9;
+		if (max < 0)
+			/* bio_add cannot handle a negative return */
+			max = 0;
+		if (max <= biovec->bv_len && bio_sectors == 0)
+			return biovec->bv_len;
+	} else
+		max = biovec->bv_len;
+
+	if (mddev->merge_check_needed) {
+		struct r10bio r10_bio;
+		int s;
+		r10_bio.sector = sector;
+		raid10_find_phys(conf, &r10_bio);
+		rcu_read_lock();
+		for (s = 0; s < conf->copies; s++) {
+			int disk = r10_bio.devs[s].devnum;
+			struct md_rdev *rdev = rcu_dereference(
+				conf->mirrors[disk].rdev);
+			if (rdev && !test_bit(Faulty, &rdev->flags)) {
+				struct request_queue *q =
+					bdev_get_queue(rdev->bdev);
+				if (q->merge_bvec_fn) {
+					bvm->bi_sector = r10_bio.devs[s].addr
+						+ rdev->data_offset;
+					bvm->bi_bdev = rdev->bdev;
+					max = min(max, q->merge_bvec_fn(
+							  q, bvm, biovec));
+				}
+			}
+			rdev = rcu_dereference(conf->mirrors[disk].replacement);
+			if (rdev && !test_bit(Faulty, &rdev->flags)) {
+				struct request_queue *q =
+					bdev_get_queue(rdev->bdev);
+				if (q->merge_bvec_fn) {
+					bvm->bi_sector = r10_bio.devs[s].addr
+						+ rdev->data_offset;
+					bvm->bi_bdev = rdev->bdev;
+					max = min(max, q->merge_bvec_fn(
+							  q, bvm, biovec));
+				}
+			}
+		}
+		rcu_read_unlock();
+	}
+	return max;
 }
 
 /*
@@ -668,11 +711,12 @@
 		disk = r10_bio->devs[slot].devnum;
 		rdev = rcu_dereference(conf->mirrors[disk].replacement);
 		if (rdev == NULL || test_bit(Faulty, &rdev->flags) ||
+		    test_bit(Unmerged, &rdev->flags) ||
 		    r10_bio->devs[slot].addr + sectors > rdev->recovery_offset)
 			rdev = rcu_dereference(conf->mirrors[disk].rdev);
-		if (rdev == NULL)
-			continue;
-		if (test_bit(Faulty, &rdev->flags))
+		if (rdev == NULL ||
+		    test_bit(Faulty, &rdev->flags) ||
+		    test_bit(Unmerged, &rdev->flags))
 			continue;
 		if (!test_bit(In_sync, &rdev->flags) &&
 		    r10_bio->devs[slot].addr + sectors > rdev->recovery_offset)
@@ -863,9 +907,22 @@
 	spin_lock_irq(&conf->resync_lock);
 	if (conf->barrier) {
 		conf->nr_waiting++;
-		wait_event_lock_irq(conf->wait_barrier, !conf->barrier,
+		/* Wait for the barrier to drop.
+		 * However if there are already pending
+		 * requests (preventing the barrier from
+		 * rising completely), and the
+		 * pre-process bio queue isn't empty,
+		 * then don't wait, as we need to empty
+		 * that queue to get the nr_pending
+		 * count down.
+		 */
+		wait_event_lock_irq(conf->wait_barrier,
+				    !conf->barrier ||
+				    (conf->nr_pending &&
+				     current->bio_list &&
+				     !bio_list_empty(current->bio_list)),
 				    conf->resync_lock,
-				    );
+			);
 		conf->nr_waiting--;
 	}
 	conf->nr_pending++;
@@ -1121,12 +1178,14 @@
 			blocked_rdev = rrdev;
 			break;
 		}
-		if (rrdev && test_bit(Faulty, &rrdev->flags))
+		if (rrdev && (test_bit(Faulty, &rrdev->flags)
+			      || test_bit(Unmerged, &rrdev->flags)))
 			rrdev = NULL;
 
 		r10_bio->devs[i].bio = NULL;
 		r10_bio->devs[i].repl_bio = NULL;
-		if (!rdev || test_bit(Faulty, &rdev->flags)) {
+		if (!rdev || test_bit(Faulty, &rdev->flags) ||
+		    test_bit(Unmerged, &rdev->flags)) {
 			set_bit(R10BIO_Degraded, &r10_bio->state);
 			continue;
 		}
@@ -1477,18 +1536,24 @@
 	int mirror;
 	int first = 0;
 	int last = conf->raid_disks - 1;
+	struct request_queue *q = bdev_get_queue(rdev->bdev);
 
 	if (mddev->recovery_cp < MaxSector)
 		/* only hot-add to in-sync arrays, as recovery is
 		 * very different from resync
 		 */
 		return -EBUSY;
-	if (!enough(conf, -1))
+	if (rdev->saved_raid_disk < 0 && !enough(conf, -1))
 		return -EINVAL;
 
 	if (rdev->raid_disk >= 0)
 		first = last = rdev->raid_disk;
 
+	if (q->merge_bvec_fn) {
+		set_bit(Unmerged, &rdev->flags);
+		mddev->merge_check_needed = 1;
+	}
+
 	if (rdev->saved_raid_disk >= first &&
 	    conf->mirrors[rdev->saved_raid_disk].rdev == NULL)
 		mirror = rdev->saved_raid_disk;
@@ -1508,11 +1573,6 @@
 			err = 0;
 			disk_stack_limits(mddev->gendisk, rdev->bdev,
 					  rdev->data_offset << 9);
-			if (rdev->bdev->bd_disk->queue->merge_bvec_fn) {
-				blk_queue_max_segments(mddev->queue, 1);
-				blk_queue_segment_boundary(mddev->queue,
-							   PAGE_CACHE_SIZE - 1);
-			}
 			conf->fullsync = 1;
 			rcu_assign_pointer(p->replacement, rdev);
 			break;
@@ -1520,17 +1580,6 @@
 
 		disk_stack_limits(mddev->gendisk, rdev->bdev,
 				  rdev->data_offset << 9);
-		/* as we don't honour merge_bvec_fn, we must
-		 * never risk violating it, so limit
-		 * ->max_segments to one lying with a single
-		 * page, as a one page request is never in
-		 * violation.
-		 */
-		if (rdev->bdev->bd_disk->queue->merge_bvec_fn) {
-			blk_queue_max_segments(mddev->queue, 1);
-			blk_queue_segment_boundary(mddev->queue,
-						   PAGE_CACHE_SIZE - 1);
-		}
 
 		p->head_position = 0;
 		p->recovery_disabled = mddev->recovery_disabled - 1;
@@ -1541,7 +1590,19 @@
 		rcu_assign_pointer(p->rdev, rdev);
 		break;
 	}
-
+	if (err == 0 && test_bit(Unmerged, &rdev->flags)) {
+		/* Some requests might not have seen this new
+		 * merge_bvec_fn.  We must wait for them to complete
+		 * before merging the device fully.
+		 * First we make sure any code which has tested
+		 * our function has submitted the request, then
+		 * we wait for all outstanding requests to complete.
+		 */
+		synchronize_sched();
+		raise_barrier(conf, 0);
+		lower_barrier(conf);
+		clear_bit(Unmerged, &rdev->flags);
+	}
 	md_integrity_add_rdev(rdev, mddev);
 	print_conf(conf);
 	return err;
@@ -1682,10 +1743,8 @@
 	d = find_bio_disk(conf, r10_bio, bio, &slot, &repl);
 	if (repl)
 		rdev = conf->mirrors[d].replacement;
-	if (!rdev) {
-		smp_mb();
+	else
 		rdev = conf->mirrors[d].rdev;
-	}
 
 	if (!uptodate) {
 		if (repl)
@@ -1762,7 +1821,7 @@
 			for (j = 0; j < vcnt; j++)
 				if (memcmp(page_address(fbio->bi_io_vec[j].bv_page),
 					   page_address(tbio->bi_io_vec[j].bv_page),
-					   PAGE_SIZE))
+					   fbio->bi_io_vec[j].bv_len))
 					break;
 			if (j == vcnt)
 				continue;
@@ -2087,6 +2146,7 @@
 			d = r10_bio->devs[sl].devnum;
 			rdev = rcu_dereference(conf->mirrors[d].rdev);
 			if (rdev &&
+			    !test_bit(Unmerged, &rdev->flags) &&
 			    test_bit(In_sync, &rdev->flags) &&
 			    is_badblock(rdev, r10_bio->devs[sl].addr + sect, s,
 					&first_bad, &bad_sectors) == 0) {
@@ -2140,6 +2200,7 @@
 			d = r10_bio->devs[sl].devnum;
 			rdev = rcu_dereference(conf->mirrors[d].rdev);
 			if (!rdev ||
+			    test_bit(Unmerged, &rdev->flags) ||
 			    !test_bit(In_sync, &rdev->flags))
 				continue;
 
@@ -3242,7 +3303,7 @@
 		blk_queue_io_opt(mddev->queue, chunk_size *
 				 (conf->raid_disks / conf->near_copies));
 
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 
 		disk_idx = rdev->raid_disk;
 		if (disk_idx >= conf->raid_disks
@@ -3262,15 +3323,6 @@
 
 		disk_stack_limits(mddev->gendisk, rdev->bdev,
 				  rdev->data_offset << 9);
-		/* as we don't honour merge_bvec_fn, we must never risk
-		 * violating it, so limit max_segments to 1 lying
-		 * within a single page.
-		 */
-		if (rdev->bdev->bd_disk->queue->merge_bvec_fn) {
-			blk_queue_max_segments(mddev->queue, 1);
-			blk_queue_segment_boundary(mddev->queue,
-						   PAGE_CACHE_SIZE - 1);
-		}
 
 		disk->head_position = 0;
 	}
@@ -3334,8 +3386,7 @@
 			mddev->queue->backing_dev_info.ra_pages = 2* stripe;
 	}
 
-	if (conf->near_copies < conf->raid_disks)
-		blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec);
+	blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec);
 
 	if (md_integrity_register(mddev))
 		goto out_free_conf;
@@ -3385,6 +3436,43 @@
 	}
 }
 
+static int raid10_resize(struct mddev *mddev, sector_t sectors)
+{
+	/* Resize of 'far' arrays is not supported.
+	 * For 'near' and 'offset' arrays we can set the
+	 * number of sectors used to be an appropriate multiple
+	 * of the chunk size.
+	 * For 'offset', this is far_copies*chunksize.
+	 * For 'near' the multiplier is the LCM of
+	 * near_copies and raid_disks.
+	 * So if far_copies > 1 && !far_offset, fail.
+	 * Else find LCM(raid_disks, near_copy)*far_copies and
+	 * multiply by chunk_size.  Then round to this number.
+	 * This is mostly done by raid10_size()
+	 */
+	struct r10conf *conf = mddev->private;
+	sector_t oldsize, size;
+
+	if (conf->far_copies > 1 && !conf->far_offset)
+		return -EINVAL;
+
+	oldsize = raid10_size(mddev, 0, 0);
+	size = raid10_size(mddev, sectors, 0);
+	md_set_array_sectors(mddev, size);
+	if (mddev->array_sectors > size)
+		return -EINVAL;
+	set_capacity(mddev->gendisk, mddev->array_sectors);
+	revalidate_disk(mddev->gendisk);
+	if (sectors > mddev->dev_sectors &&
+	    mddev->recovery_cp > oldsize) {
+		mddev->recovery_cp = oldsize;
+		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+	}
+	mddev->dev_sectors = sectors;
+	mddev->resync_max_sectors = size;
+	return 0;
+}
+
 static void *raid10_takeover_raid0(struct mddev *mddev)
 {
 	struct md_rdev *rdev;
@@ -3408,7 +3496,7 @@
 
 	conf = setup_conf(mddev);
 	if (!IS_ERR(conf)) {
-		list_for_each_entry(rdev, &mddev->disks, same_set)
+		rdev_for_each(rdev, mddev)
 			if (rdev->raid_disk >= 0)
 				rdev->new_raid_disk = rdev->raid_disk * 2;
 		conf->barrier = 1;
@@ -3454,6 +3542,7 @@
 	.sync_request	= sync_request,
 	.quiesce	= raid10_quiesce,
 	.size		= raid10_size,
+	.resize		= raid10_resize,
 	.takeover	= raid10_takeover,
 };
 
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 360f2b9..f351422 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -208,11 +208,10 @@
 			md_wakeup_thread(conf->mddev->thread);
 		} else {
 			BUG_ON(stripe_operations_active(sh));
-			if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
-				atomic_dec(&conf->preread_active_stripes);
-				if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD)
+			if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
+				if (atomic_dec_return(&conf->preread_active_stripes)
+				    < IO_THRESHOLD)
 					md_wakeup_thread(conf->mddev->thread);
-			}
 			atomic_dec(&conf->active_stripes);
 			if (!test_bit(STRIPE_EXPANDING, &sh->state)) {
 				list_add_tail(&sh->lru, &conf->inactive_list);
@@ -2472,39 +2471,41 @@
 	int abort = 0;
 	int i;
 
-	md_done_sync(conf->mddev, STRIPE_SECTORS, 0);
 	clear_bit(STRIPE_SYNCING, &sh->state);
 	s->syncing = 0;
 	s->replacing = 0;
 	/* There is nothing more to do for sync/check/repair.
+	 * Don't even need to abort as that is handled elsewhere
+	 * if needed, and not always wanted e.g. if there is a known
+	 * bad block here.
 	 * For recover/replace we need to record a bad block on all
 	 * non-sync devices, or abort the recovery
 	 */
-	if (!test_bit(MD_RECOVERY_RECOVER, &conf->mddev->recovery))
-		return;
-	/* During recovery devices cannot be removed, so locking and
-	 * refcounting of rdevs is not needed
-	 */
-	for (i = 0; i < conf->raid_disks; i++) {
-		struct md_rdev *rdev = conf->disks[i].rdev;
-		if (rdev
-		    && !test_bit(Faulty, &rdev->flags)
-		    && !test_bit(In_sync, &rdev->flags)
-		    && !rdev_set_badblocks(rdev, sh->sector,
-					   STRIPE_SECTORS, 0))
-			abort = 1;
-		rdev = conf->disks[i].replacement;
-		if (rdev
-		    && !test_bit(Faulty, &rdev->flags)
-		    && !test_bit(In_sync, &rdev->flags)
-		    && !rdev_set_badblocks(rdev, sh->sector,
-					   STRIPE_SECTORS, 0))
-			abort = 1;
+	if (test_bit(MD_RECOVERY_RECOVER, &conf->mddev->recovery)) {
+		/* During recovery devices cannot be removed, so
+		 * locking and refcounting of rdevs is not needed
+		 */
+		for (i = 0; i < conf->raid_disks; i++) {
+			struct md_rdev *rdev = conf->disks[i].rdev;
+			if (rdev
+			    && !test_bit(Faulty, &rdev->flags)
+			    && !test_bit(In_sync, &rdev->flags)
+			    && !rdev_set_badblocks(rdev, sh->sector,
+						   STRIPE_SECTORS, 0))
+				abort = 1;
+			rdev = conf->disks[i].replacement;
+			if (rdev
+			    && !test_bit(Faulty, &rdev->flags)
+			    && !test_bit(In_sync, &rdev->flags)
+			    && !rdev_set_badblocks(rdev, sh->sector,
+						   STRIPE_SECTORS, 0))
+				abort = 1;
+		}
+		if (abort)
+			conf->recovery_disabled =
+				conf->mddev->recovery_disabled;
 	}
-	if (abort) {
-		conf->recovery_disabled = conf->mddev->recovery_disabled;
-		set_bit(MD_RECOVERY_INTR, &conf->mddev->recovery);
-	}
+	md_done_sync(conf->mddev, STRIPE_SECTORS, !abort);
 }
 
 static int want_replace(struct stripe_head *sh, int disk_idx)
@@ -3204,7 +3205,8 @@
 			/* Not in-sync */;
 		else if (is_bad) {
 			/* also not in-sync */
-			if (!test_bit(WriteErrorSeen, &rdev->flags)) {
+			if (!test_bit(WriteErrorSeen, &rdev->flags) &&
+			    test_bit(R5_UPTODATE, &dev->flags)) {
 				/* treat as in-sync, but with a read error
 				 * which we can now try to correct
 				 */
@@ -3277,12 +3279,14 @@
 		/* If there is a failed device being replaced,
 		 *     we must be recovering.
 		 * else if we are after recovery_cp, we must be syncing
+		 * else if MD_RECOVERY_REQUESTED is set, we also are syncing.
 		 * else we can only be replacing
 		 * sync and recovery both need to read all devices, and so
 		 * use the same flag.
 		 */
 		if (do_recovery ||
-		    sh->sector >= conf->mddev->recovery_cp)
+		    sh->sector >= conf->mddev->recovery_cp ||
+		    test_bit(MD_RECOVERY_REQUESTED, &(conf->mddev->recovery)))
 			s->syncing = 1;
 		else
 			s->replacing = 1;
@@ -4843,7 +4847,7 @@
 
 	pr_debug("raid456: run(%s) called.\n", mdname(mddev));
 
-	list_for_each_entry(rdev, &mddev->disks, same_set) {
+	rdev_for_each(rdev, mddev) {
 		raid_disk = rdev->raid_disk;
 		if (raid_disk >= max_disks
 		    || raid_disk < 0)
@@ -5178,7 +5182,7 @@
 		blk_queue_io_opt(mddev->queue, chunk_size *
 				 (conf->raid_disks - conf->max_degraded));
 
-		list_for_each_entry(rdev, &mddev->disks, same_set)
+		rdev_for_each(rdev, mddev)
 			disk_stack_limits(mddev->gendisk, rdev->bdev,
 					  rdev->data_offset << 9);
 	}
@@ -5362,7 +5366,7 @@
 	if (mddev->recovery_disabled == conf->recovery_disabled)
 		return -EBUSY;
 
-	if (has_failed(conf))
+	if (rdev->saved_raid_disk < 0 && has_failed(conf))
 		/* no point adding a device */
 		return -EINVAL;
 
@@ -5501,7 +5505,7 @@
 	if (!check_stripe_cache(mddev))
 		return -ENOSPC;
 
-	list_for_each_entry(rdev, &mddev->disks, same_set)
+	rdev_for_each(rdev, mddev)
 		if (!test_bit(In_sync, &rdev->flags)
 		    && !test_bit(Faulty, &rdev->flags))
 			spares++;
@@ -5547,16 +5551,14 @@
 	 * such devices during the reshape and confusion could result.
 	 */
 	if (mddev->delta_disks >= 0) {
-		int added_devices = 0;
-		list_for_each_entry(rdev, &mddev->disks, same_set)
+		rdev_for_each(rdev, mddev)
 			if (rdev->raid_disk < 0 &&
 			    !test_bit(Faulty, &rdev->flags)) {
 				if (raid5_add_disk(mddev, rdev) == 0) {
 					if (rdev->raid_disk
-					    >= conf->previous_raid_disks) {
+					    >= conf->previous_raid_disks)
 						set_bit(In_sync, &rdev->flags);
-						added_devices++;
-					} else
+					else
 						rdev->recovery_offset = 0;
 
 					if (sysfs_link_rdev(mddev, rdev))
@@ -5566,7 +5568,6 @@
 				   && !test_bit(Faulty, &rdev->flags)) {
 				/* This is a spare that was manually added */
 				set_bit(In_sync, &rdev->flags);
-				added_devices++;
 			}
 
 		/* When a reshape changes the number of devices,
@@ -5592,6 +5593,7 @@
 		spin_lock_irq(&conf->device_lock);
 		mddev->raid_disks = conf->raid_disks = conf->previous_raid_disks;
 		conf->reshape_progress = MaxSector;
+		mddev->reshape_position = MaxSector;
 		spin_unlock_irq(&conf->device_lock);
 		return -EAGAIN;
 	}
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
index 8295854..f80407e 100644
--- a/drivers/media/common/tuners/Makefile
+++ b/drivers/media/common/tuners/Makefile
@@ -29,5 +29,5 @@
 obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
 obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/max2165.c b/drivers/media/common/tuners/max2165.c
index cb2c98f..ba84936 100644
--- a/drivers/media/common/tuners/max2165.c
+++ b/drivers/media/common/tuners/max2165.c
@@ -168,7 +168,7 @@
 	int i;
 
 	if (0 == divisor)
-		return -1;
+		return -EINVAL;
 
 	q = dividend / divisor;
 	remainder = dividend - q * divisor;
@@ -194,10 +194,13 @@
 	u8 tf_ntch;
 	u32 t;
 	u32 quotient, fraction;
+	int ret;
 
 	/* Set PLL divider according to RF frequency */
-	fixpt_div32(freq / 1000, priv->config->osc_clk * 1000,
-		&quotient, &fraction);
+	ret = fixpt_div32(freq / 1000, priv->config->osc_clk * 1000,
+			 &quotient, &fraction);
+	if (ret != 0)
+		return ret;
 
 	/* 20-bit fraction */
 	fraction >>= 12;
diff --git a/drivers/media/common/tuners/mt2063.c b/drivers/media/common/tuners/mt2063.c
index c89af3c..0ed9091 100644
--- a/drivers/media/common/tuners/mt2063.c
+++ b/drivers/media/common/tuners/mt2063.c
@@ -350,7 +350,7 @@
 	/*
 	 *  ToDo:  Add code here to implement a OS blocking
 	 */
-	msleep(10);
+	msleep(100);
 
 	return 0;
 }
@@ -2226,7 +2226,7 @@
 	.info = {
 		 .name = "MT2063 Silicon Tuner",
 		 .frequency_min = 45000000,
-		 .frequency_max = 850000000,
+		 .frequency_max = 865000000,
 		 .frequency_step = 0,
 		 },
 
diff --git a/drivers/media/common/tuners/mt2063.h b/drivers/media/common/tuners/mt2063.h
index 62d0e8e..3f5cfd9 100644
--- a/drivers/media/common/tuners/mt2063.h
+++ b/drivers/media/common/tuners/mt2063.h
@@ -23,10 +23,6 @@
 	return NULL;
 }
 
-int mt2063_setTune(struct dvb_frontend *fe, u32 f_in,
-				   u32 bw_in,
-				   enum MTTune_atv_standard tv_type);
-
 /* FIXME: Should use the standard DVB attachment interfaces */
 unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe);
 unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe);
diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c
index e13683b..2da4440 100644
--- a/drivers/media/common/tuners/tuner-types.c
+++ b/drivers/media/common/tuners/tuner-types.c
@@ -1868,6 +1868,10 @@
 		.params = tuner_tena_tnf_5337_params,
 		.count  = ARRAY_SIZE(tuner_tena_tnf_5337_params),
 	},
+	[TUNER_XC5000C] = { /* Xceive 5000C */
+		.name   = "Xceive 5000C tuner",
+		/* see xc5000.c for details */
+	},
 };
 EXPORT_SYMBOL(tuners);
 
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index 296df05..7f98984 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -49,9 +49,6 @@
 #define dprintk(level, fmt, arg...) if (debug >= level) \
 	printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
 
-#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw"
-#define XC5000_DEFAULT_FIRMWARE_SIZE 12401
-
 struct xc5000_priv {
 	struct tuner_i2c_props i2c_props;
 	struct list_head hybrid_tuner_instance_list;
@@ -62,6 +59,8 @@
 	u8  video_standard;
 	u8  rf_mode;
 	u8  radio_input;
+
+	int chip_id;
 };
 
 /* Misc Defines */
@@ -204,6 +203,33 @@
 	{"FM Radio-INPUT1_MONO", 0x0278, 0x9002}
 };
 
+
+struct xc5000_fw_cfg {
+	char *name;
+	u16 size;
+};
+
+static const struct xc5000_fw_cfg xc5000a_1_6_114 = {
+	.name = "dvb-fe-xc5000-1.6.114.fw",
+	.size = 12401,
+};
+
+static const struct xc5000_fw_cfg xc5000c_41_024_5_31875 = {
+	.name = "dvb-fe-xc5000c-41.024.5-31875.fw",
+	.size = 16503,
+};
+
+static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id)
+{
+	switch (chip_id) {
+	default:
+	case XC5000A:
+		return &xc5000a_1_6_114;
+	case XC5000C:
+		return &xc5000c_41_024_5_31875;
+	}
+}
+
 static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
 static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
 static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val);
@@ -552,12 +578,14 @@
 	struct xc5000_priv *priv = fe->tuner_priv;
 	const struct firmware *fw;
 	int ret;
+	const struct xc5000_fw_cfg *desired_fw =
+		xc5000_assign_firmware(priv->chip_id);
 
 	/* request the firmware, this will block and timeout */
 	printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
-		XC5000_DEFAULT_FIRMWARE);
+		desired_fw->name);
 
-	ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE,
+	ret = request_firmware(&fw, desired_fw->name,
 		priv->i2c_props.adap->dev.parent);
 	if (ret) {
 		printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
@@ -569,7 +597,7 @@
 		ret = XC_RESULT_SUCCESS;
 	}
 
-	if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) {
+	if (fw->size != desired_fw->size) {
 		printk(KERN_ERR "xc5000: firmware incorrect size\n");
 		ret = XC_RESULT_RESET_FAILURE;
 	} else {
@@ -1139,6 +1167,13 @@
 	if (priv->radio_input == 0)
 		priv->radio_input = cfg->radio_input;
 
+	/* don't override chip id if it's already been set
+	   unless explicitly specified */
+	if ((priv->chip_id == 0) || (cfg->chip_id))
+		/* use default chip id if none specified, set to 0 so
+		   it can be overridden if this is a hybrid driver */
+		priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0;
+
 	/* Check if firmware has been loaded. It is possible that another
 	   instance of the driver has loaded the firmware.
 	 */
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h
index e295745..3396f8e 100644
--- a/drivers/media/common/tuners/xc5000.h
+++ b/drivers/media/common/tuners/xc5000.h
@@ -27,10 +27,15 @@
 struct dvb_frontend;
 struct i2c_adapter;
 
+#define XC5000A 1
+#define XC5000C 2
+
 struct xc5000_config {
 	u8   i2c_address;
 	u32  if_khz;
 	u8   radio_input;
+
+	int chip_id;
 };
 
 /* xc5000 callback command */
diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c
index ce4f858..d88c4aa 100644
--- a/drivers/media/dvb/ddbridge/ddbridge-core.c
+++ b/drivers/media/dvb/ddbridge/ddbridge-core.c
@@ -578,6 +578,7 @@
 	struct drxk_config config;
 
 	memset(&config, 0, sizeof(config));
+	config.microcode_name = "drxk_a3.mc";
 	config.adr = 0x29 + (input->nr & 1);
 
 	fe = input->fe = dvb_attach(drxk_attach, &config, i2c);
diff --git a/drivers/media/dvb/ddbridge/ddbridge.h b/drivers/media/dvb/ddbridge/ddbridge.h
index 6d14893..8b1b41d 100644
--- a/drivers/media/dvb/ddbridge/ddbridge.h
+++ b/drivers/media/dvb/ddbridge/ddbridge.h
@@ -32,8 +32,6 @@
 #include <asm/dma.h>
 #include <linux/dvb/frontend.h>
 #include <linux/dvb/ca.h>
-#include <linux/dvb/video.h>
-#include <linux/dvb/audio.h>
 #include <linux/socket.h>
 
 #include "dmxdev.h"
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index e4b5c03..73970cd 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -29,7 +29,6 @@
 #include <linux/ioctl.h>
 #include <linux/wait.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include "dmxdev.h"
 
 static int debug;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index fbbe545..4555baa 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -655,6 +655,8 @@
 					dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
 					re_tune = true;
 					fepriv->state = FESTATE_TUNED;
+				} else {
+					re_tune = false;
 				}
 
 				if (fe->ops.tune)
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 9f203c6..63bf456 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -361,6 +361,14 @@
 	help
 	  Say Y here to support the E3C EC168 DVB-T USB2.0 receiver.
 
+config DVB_USB_AZ6007
+	tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support"
+	depends on DVB_USB
+	select DVB_DRXK if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2063 if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support theAfatech AF9005 based DVB-T/DVB-C receivers.
+
 config DVB_USB_AZ6027
 	tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support"
 	depends on DVB_USB
@@ -378,6 +386,7 @@
 	select DVB_IX2505V if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select DVB_M88RS2000 if !DVB_FE_CUSTOMISE
 	help
 	  Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 .
 
@@ -403,3 +412,13 @@
 	select VIDEO_TVEEPROM
 	help
 	  Say Y here to support the MxL111SF USB2.0 DTV receiver.
+
+config DVB_USB_RTL28XXU
+	tristate "Realtek RTL28xxU DVB USB support"
+	depends on DVB_USB && EXPERIMENTAL
+	select DVB_RTL2830
+	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+	help
+	  Say Y here to support the Realtek RTL28xxU DVB USB receiver.
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 26c8b9e..b76acb5 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -54,7 +54,6 @@
 dvb-usb-opera-objs = opera1.o
 obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
 
-
 dvb-usb-af9005-objs = af9005.o af9005-fe.o
 obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
 
@@ -88,6 +87,9 @@
 dvb-usb-ec168-objs = ec168.o
 obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
 
+dvb-usb-az6007-objs = az6007.o
+obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o
+
 dvb-usb-az6027-objs = az6027.o
 obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
 
@@ -105,8 +107,12 @@
 obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o
 obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+dvb-usb-rtl28xxu-objs = rtl28xxu.o
+obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
+
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/
 # due to tuner-xc3028
-ccflags-y += -Idrivers/media/common/tuners
-EXTRA_CFLAGS += -Idrivers/media/dvb/ttpci
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb/ttpci
 
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 282a43d..7e70ea5 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -1164,6 +1164,41 @@
 	return ret;
 }
 
+/* override tuner callbacks for resource locking */
+static int af9015_tuner_init(struct dvb_frontend *fe)
+{
+	int ret;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct af9015_state *priv = adap->dev->priv;
+
+	if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+		return -EAGAIN;
+
+	ret = priv->tuner_init[adap->id](fe);
+
+	mutex_unlock(&adap->dev->usb_mutex);
+
+	return ret;
+}
+
+/* override tuner callbacks for resource locking */
+static int af9015_tuner_sleep(struct dvb_frontend *fe)
+{
+	int ret;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct af9015_state *priv = adap->dev->priv;
+
+	if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+		return -EAGAIN;
+
+	ret = priv->tuner_sleep[adap->id](fe);
+
+	mutex_unlock(&adap->dev->usb_mutex);
+
+	return ret;
+}
+
+
 static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	int ret;
@@ -1283,6 +1318,7 @@
 static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
 {
 	int ret;
+	struct af9015_state *state = adap->dev->priv;
 	deb_info("%s:\n", __func__);
 
 	switch (af9015_af9013_config[adap->id].tuner) {
@@ -1340,6 +1376,19 @@
 		err("Unknown tuner id:%d",
 			af9015_af9013_config[adap->id].tuner);
 	}
+
+	if (adap->fe_adap[0].fe->ops.tuner_ops.init) {
+		state->tuner_init[adap->id] =
+			adap->fe_adap[0].fe->ops.tuner_ops.init;
+		adap->fe_adap[0].fe->ops.tuner_ops.init = af9015_tuner_init;
+	}
+
+	if (adap->fe_adap[0].fe->ops.tuner_ops.sleep) {
+		state->tuner_sleep[adap->id] =
+			adap->fe_adap[0].fe->ops.tuner_ops.sleep;
+		adap->fe_adap[0].fe->ops.tuner_ops.sleep = af9015_tuner_sleep;
+	}
+
 	return ret;
 }
 
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
index f619063..2f68419 100644
--- a/drivers/media/dvb/dvb-usb/af9015.h
+++ b/drivers/media/dvb/dvb-usb/af9015.h
@@ -108,6 +108,8 @@
 	int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status);
 	int (*init[2]) (struct dvb_frontend *fe);
 	int (*sleep[2]) (struct dvb_frontend *fe);
+	int (*tuner_init[2]) (struct dvb_frontend *fe);
+	int (*tuner_sleep[2]) (struct dvb_frontend *fe);
 };
 
 struct af9015_config {
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
index cf0c318..03c2865 100644
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -58,7 +58,7 @@
 	u8 *rbuf, u8 rlen)
 {
 	struct anysee_state *state = d->priv;
-	int act_len, ret;
+	int act_len, ret, i;
 	u8 buf[64];
 
 	memcpy(&buf[0], sbuf, slen);
@@ -73,26 +73,52 @@
 	/* We need receive one message more after dvb_usb_generic_rw due
 	   to weird transaction flow, which is 1 x send + 2 x receive. */
 	ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0);
-	if (!ret) {
+	if (ret)
+		goto error_unlock;
+
+	/* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32
+	 * (EPIPE, Broken pipe). Function supports currently msleep() as a
+	 * parameter but I would not like to use it, since according to
+	 * Documentation/timers/timers-howto.txt it should not be used such
+	 * short, under < 20ms, sleeps. Repeating failed message would be
+	 * better choice as not to add unwanted delays...
+	 * Fixing that correctly is one of those or both;
+	 * 1) use repeat if possible
+	 * 2) add suitable delay
+	 */
+
+	/* get answer, retry few times if error returned */
+	for (i = 0; i < 3; i++) {
 		/* receive 2nd answer */
 		ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
 			d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf),
 			&act_len, 2000);
-		if (ret)
-			err("%s: recv bulk message failed: %d", __func__, ret);
-		else {
+
+		if (ret) {
+			deb_info("%s: recv bulk message failed: %d",
+					__func__, ret);
+		} else {
 			deb_xfer("<<< ");
 			debug_dump(buf, rlen, deb_xfer);
 
 			if (buf[63] != 0x4f)
 				deb_info("%s: cmd failed\n", __func__);
+
+			break;
 		}
 	}
 
+	if (ret) {
+		/* all retries failed, it is fatal */
+		err("%s: recv bulk message failed: %d", __func__, ret);
+		goto error_unlock;
+	}
+
 	/* read request, copy returned data to return buf */
-	if (!ret && rbuf && rlen)
+	if (rbuf && rlen)
 		memcpy(rbuf, buf, rlen);
 
+error_unlock:
 	mutex_unlock(&anysee_usb_mutex);
 
 	return ret;
diff --git a/drivers/media/dvb/dvb-usb/az6007.c b/drivers/media/dvb/dvb-usb/az6007.c
new file mode 100644
index 0000000..4008b9c
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/az6007.c
@@ -0,0 +1,957 @@
+/*
+ * Driver for AzureWave 6007 DVB-C/T USB2.0 and clones
+ *
+ * Copyright (c) Henry Wang <Henry.wang@AzureWave.com>
+ *
+ * This driver was made publicly available by Terratec, at:
+ *	http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
+ * The original driver's license is GPL, as declared with MODULE_LICENSE()
+ *
+ * Copyright (c) 2010-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *	Driver modified by in order to work with upstream drxk driver, and
+ *	tons of bugs got fixed.
+ *
+ * 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 under 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.
+ */
+
+#include "drxk.h"
+#include "mt2063.h"
+#include "dvb_ca_en50221.h"
+
+#define DVB_USB_LOG_PREFIX "az6007"
+#include "dvb-usb.h"
+
+/* debug */
+int dvb_usb_az6007_debug;
+module_param_named(debug, dvb_usb_az6007_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))."
+		 DVB_USB_DEBUG_STATUS);
+
+#define deb_info(args...) dprintk(dvb_usb_az6007_debug, 0x01, args)
+#define deb_xfer(args...) dprintk(dvb_usb_az6007_debug, 0x02, args)
+#define deb_rc(args...)   dprintk(dvb_usb_az6007_debug, 0x04, args)
+#define deb_fe(args...)   dprintk(dvb_usb_az6007_debug, 0x08, args)
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* Known requests (Cypress FX2 firmware + az6007 "private" ones*/
+
+#define FX2_OED			0xb5
+#define AZ6007_READ_DATA	0xb7
+#define AZ6007_I2C_RD		0xb9
+#define AZ6007_POWER		0xbc
+#define AZ6007_I2C_WR		0xbd
+#define FX2_SCON1		0xc0
+#define AZ6007_TS_THROUGH	0xc7
+#define AZ6007_READ_IR		0xb4
+
+struct az6007_device_state {
+	struct mutex		mutex;
+	struct mutex		ca_mutex;
+	struct dvb_ca_en50221	ca;
+	unsigned		warm:1;
+	int			(*gate_ctrl) (struct dvb_frontend *, int);
+	unsigned char		data[4096];
+};
+
+static struct drxk_config terratec_h7_drxk = {
+	.adr = 0x29,
+	.parallel_ts = true,
+	.dynamic_clk = true,
+	.single_master = true,
+	.enable_merr_cfg = true,
+	.no_i2c_bridge = false,
+	.chunk_size = 64,
+	.mpeg_out_clk_strength = 0x02,
+	.microcode_name = "dvb-usb-terratec-h7-drxk.fw",
+};
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct dvb_usb_adapter *adap = fe->sec_priv;
+	struct az6007_device_state *st;
+	int status = 0;
+
+	deb_info("%s: %s\n", __func__, enable ? "enable" : "disable");
+
+	if (!adap)
+		return -EINVAL;
+
+	st = adap->dev->priv;
+
+	if (!st)
+		return -EINVAL;
+
+	if (enable)
+		status = st->gate_ctrl(fe, 1);
+	else
+		status = st->gate_ctrl(fe, 0);
+
+	return status;
+}
+
+static struct mt2063_config az6007_mt2063_config = {
+	.tuner_address = 0x60,
+	.refclock = 36125000,
+};
+
+static int __az6007_read(struct usb_device *udev, u8 req, u16 value,
+			    u16 index, u8 *b, int blen)
+{
+	int ret;
+
+	ret = usb_control_msg(udev,
+			      usb_rcvctrlpipe(udev, 0),
+			      req,
+			      USB_TYPE_VENDOR | USB_DIR_IN,
+			      value, index, b, blen, 5000);
+	if (ret < 0) {
+		warn("usb read operation failed. (%d)", ret);
+		return -EIO;
+	}
+
+	deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value,
+		 index);
+	debug_dump(b, blen, deb_xfer);
+
+	return ret;
+}
+
+static int az6007_read(struct dvb_usb_device *d, u8 req, u16 value,
+			    u16 index, u8 *b, int blen)
+{
+	struct az6007_device_state *st = d->priv;
+	int ret;
+
+	if (mutex_lock_interruptible(&st->mutex) < 0)
+		return -EAGAIN;
+
+	ret = __az6007_read(d->udev, req, value, index, b, blen);
+
+	mutex_unlock(&st->mutex);
+
+	return ret;
+}
+
+static int __az6007_write(struct usb_device *udev, u8 req, u16 value,
+			     u16 index, u8 *b, int blen)
+{
+	int ret;
+
+	deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value,
+		 index);
+	debug_dump(b, blen, deb_xfer);
+
+	if (blen > 64) {
+		err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n",
+		    blen);
+		return -EOPNOTSUPP;
+	}
+
+	ret = usb_control_msg(udev,
+			      usb_sndctrlpipe(udev, 0),
+			      req,
+			      USB_TYPE_VENDOR | USB_DIR_OUT,
+			      value, index, b, blen, 5000);
+	if (ret != blen) {
+		err("usb write operation failed. (%d)", ret);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int az6007_write(struct dvb_usb_device *d, u8 req, u16 value,
+			    u16 index, u8 *b, int blen)
+{
+	struct az6007_device_state *st = d->priv;
+	int ret;
+
+	if (mutex_lock_interruptible(&st->mutex) < 0)
+		return -EAGAIN;
+
+	ret = __az6007_write(d->udev, req, value, index, b, blen);
+
+	mutex_unlock(&st->mutex);
+
+	return ret;
+}
+
+static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	struct dvb_usb_device *d = adap->dev;
+
+	deb_info("%s: %s", __func__, onoff ? "enable" : "disable");
+
+	return az6007_write(d, 0xbc, onoff, 0, NULL, 0);
+}
+
+/* remote control stuff (does not work with my box) */
+static int az6007_rc_query(struct dvb_usb_device *d)
+{
+	struct az6007_device_state *st = d->priv;
+	unsigned code = 0;
+
+	az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10);
+
+	if (st->data[1] == 0x44)
+		return 0;
+
+	if ((st->data[1] ^ st->data[2]) == 0xff)
+		code = st->data[1];
+	else
+		code = st->data[1] << 8 | st->data[2];
+
+	if ((st->data[3] ^ st->data[4]) == 0xff)
+		code = code << 8 | st->data[3];
+	else
+		code = code << 16 | st->data[3] << 8 | st->data[4];
+
+	rc_keydown(d->rc_dev, code, st->data[5]);
+
+	return 0;
+}
+
+static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
+					int slot,
+					int address)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 *b;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC1;
+	value = address;
+	index = 0;
+	blen = 1;
+
+	ret = az6007_read(d, req, value, index, b, blen);
+	if (ret < 0) {
+		warn("usb in operation failed. (%d)", ret);
+		ret = -EINVAL;
+	} else {
+		ret = b[0];
+	}
+
+	mutex_unlock(&state->ca_mutex);
+	kfree(b);
+	return ret;
+}
+
+static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
+					 int slot,
+					 int address,
+					 u8 value)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+	int ret;
+	u8 req;
+	u16 value1;
+	u16 index;
+	int blen;
+
+	deb_info("%s %d", __func__, slot);
+	if (slot != 0)
+		return -EINVAL;
+
+	mutex_lock(&state->ca_mutex);
+	req = 0xC2;
+	value1 = address;
+	index = value;
+	blen = 0;
+
+	ret = az6007_write(d, req, value1, index, NULL, blen);
+	if (ret != 0)
+		warn("usb out operation failed. (%d)", ret);
+
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca,
+				      int slot,
+				      u8 address)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 *b;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC3;
+	value = address;
+	index = 0;
+	blen = 2;
+
+	ret = az6007_read(d, req, value, index, b, blen);
+	if (ret < 0) {
+		warn("usb in operation failed. (%d)", ret);
+		ret = -EINVAL;
+	} else {
+		if (b[0] == 0)
+			warn("Read CI IO error");
+
+		ret = b[1];
+		deb_info("read cam data = %x from 0x%x", b[1], value);
+	}
+
+	mutex_unlock(&state->ca_mutex);
+	kfree(b);
+	return ret;
+}
+
+static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca,
+				       int slot,
+				       u8 address,
+				       u8 value)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+	int ret;
+	u8 req;
+	u16 value1;
+	u16 index;
+	int blen;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	mutex_lock(&state->ca_mutex);
+	req = 0xC4;
+	value1 = address;
+	index = value;
+	blen = 0;
+
+	ret = az6007_write(d, req, value1, index, NULL, blen);
+	if (ret != 0) {
+		warn("usb out operation failed. (%d)", ret);
+		goto failed;
+	}
+
+failed:
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 *b;
+
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+
+	req = 0xC8;
+	value = 0;
+	index = 0;
+	blen = 1;
+
+	ret = az6007_read(d, req, value, index, b, blen);
+	if (ret < 0) {
+		warn("usb in operation failed. (%d)", ret);
+		ret = -EIO;
+	} else{
+		ret = b[0];
+	}
+	kfree(b);
+	return ret;
+}
+
+static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+	int ret, i;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC6;
+	value = 1;
+	index = 0;
+	blen = 0;
+
+	ret = az6007_write(d, req, value, index, NULL, blen);
+	if (ret != 0) {
+		warn("usb out operation failed. (%d)", ret);
+		goto failed;
+	}
+
+	msleep(500);
+	req = 0xC6;
+	value = 0;
+	index = 0;
+	blen = 0;
+
+	ret = az6007_write(d, req, value, index, NULL, blen);
+	if (ret != 0) {
+		warn("usb out operation failed. (%d)", ret);
+		goto failed;
+	}
+
+	for (i = 0; i < 15; i++) {
+		msleep(100);
+
+		if (CI_CamReady(ca, slot)) {
+			deb_info("CAM Ready");
+			break;
+		}
+	}
+	msleep(5000);
+
+failed:
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+	return 0;
+}
+
+static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	deb_info("%s", __func__);
+	mutex_lock(&state->ca_mutex);
+	req = 0xC7;
+	value = 1;
+	index = 0;
+	blen = 0;
+
+	ret = az6007_write(d, req, value, index, NULL, blen);
+	if (ret != 0) {
+		warn("usb out operation failed. (%d)", ret);
+		goto failed;
+	}
+
+failed:
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 *b;
+
+	b = kmalloc(12, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC5;
+	value = 0;
+	index = 0;
+	blen = 1;
+
+	ret = az6007_read(d, req, value, index, b, blen);
+	if (ret < 0) {
+		warn("usb in operation failed. (%d)", ret);
+		ret = -EIO;
+	} else
+		ret = 0;
+
+	if (!ret && b[0] == 1) {
+		ret = DVB_CA_EN50221_POLL_CAM_PRESENT |
+		      DVB_CA_EN50221_POLL_CAM_READY;
+	}
+
+	mutex_unlock(&state->ca_mutex);
+	kfree(b);
+	return ret;
+}
+
+
+static void az6007_ci_uninit(struct dvb_usb_device *d)
+{
+	struct az6007_device_state *state;
+
+	deb_info("%s", __func__);
+
+	if (NULL == d)
+		return;
+
+	state = (struct az6007_device_state *)d->priv;
+	if (NULL == state)
+		return;
+
+	if (NULL == state->ca.data)
+		return;
+
+	dvb_ca_en50221_release(&state->ca);
+
+	memset(&state->ca, 0, sizeof(state->ca));
+}
+
+
+static int az6007_ci_init(struct dvb_usb_adapter *a)
+{
+	struct dvb_usb_device *d = a->dev;
+	struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+	int ret;
+
+	deb_info("%s", __func__);
+
+	mutex_init(&state->ca_mutex);
+
+	state->ca.owner			= THIS_MODULE;
+	state->ca.read_attribute_mem	= az6007_ci_read_attribute_mem;
+	state->ca.write_attribute_mem	= az6007_ci_write_attribute_mem;
+	state->ca.read_cam_control	= az6007_ci_read_cam_control;
+	state->ca.write_cam_control	= az6007_ci_write_cam_control;
+	state->ca.slot_reset		= az6007_ci_slot_reset;
+	state->ca.slot_shutdown		= az6007_ci_slot_shutdown;
+	state->ca.slot_ts_enable	= az6007_ci_slot_ts_enable;
+	state->ca.poll_slot_status	= az6007_ci_poll_slot_status;
+	state->ca.data			= d;
+
+	ret = dvb_ca_en50221_init(&a->dvb_adap,
+				  &state->ca,
+				  0, /* flags */
+				  1);/* n_slots */
+	if (ret != 0) {
+		err("Cannot initialize CI: Error %d.", ret);
+		memset(&state->ca, 0, sizeof(state->ca));
+		return ret;
+	}
+
+	deb_info("CI initialized.");
+
+	return 0;
+}
+
+static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6])
+{
+	struct az6007_device_state *st = d->priv;
+	int ret;
+
+	ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6);
+	memcpy(mac, st->data, sizeof(mac));
+
+	if (ret > 0)
+		deb_info("%s: mac is %02x:%02x:%02x:%02x:%02x:%02x\n",
+			 __func__, mac[0], mac[1], mac[2],
+			 mac[3], mac[4], mac[5]);
+
+	return ret;
+}
+
+static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct az6007_device_state *st = adap->dev->priv;
+
+	deb_info("attaching demod drxk");
+
+	adap->fe_adap[0].fe = dvb_attach(drxk_attach, &terratec_h7_drxk,
+					 &adap->dev->i2c_adap);
+	if (!adap->fe_adap[0].fe)
+		return -EINVAL;
+
+	adap->fe_adap[0].fe->sec_priv = adap;
+	st->gate_ctrl = adap->fe_adap[0].fe->ops.i2c_gate_ctrl;
+	adap->fe_adap[0].fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+
+	az6007_ci_init(adap);
+
+	return 0;
+}
+
+static int az6007_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	deb_info("attaching tuner mt2063");
+
+	/* Attach mt2063 to DVB-C frontend */
+	if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
+		adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1);
+	if (!dvb_attach(mt2063_attach, adap->fe_adap[0].fe,
+			&az6007_mt2063_config,
+			&adap->dev->i2c_adap))
+		return -EINVAL;
+
+	if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
+		adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0);
+
+	return 0;
+}
+
+int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	struct az6007_device_state *st = d->priv;
+	int ret;
+
+	deb_info("%s()\n", __func__);
+
+	if (!st->warm) {
+		mutex_init(&st->mutex);
+
+		ret = az6007_write(d, AZ6007_POWER, 0, 2, NULL, 0);
+		if (ret < 0)
+			return ret;
+		msleep(60);
+		ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);
+		if (ret < 0)
+			return ret;
+		msleep(100);
+		ret = az6007_write(d, AZ6007_POWER, 1, 3, NULL, 0);
+		if (ret < 0)
+			return ret;
+		msleep(20);
+		ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);
+		if (ret < 0)
+			return ret;
+
+		msleep(400);
+		ret = az6007_write(d, FX2_SCON1, 0, 3, NULL, 0);
+		if (ret < 0)
+			return ret;
+		msleep(150);
+		ret = az6007_write(d, FX2_SCON1, 1, 3, NULL, 0);
+		if (ret < 0)
+			return ret;
+		msleep(430);
+		ret = az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);
+		if (ret < 0)
+			return ret;
+
+		st->warm = true;
+
+		return 0;
+	}
+
+	if (!onoff)
+		return 0;
+
+	az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);
+	az6007_write(d, AZ6007_TS_THROUGH, 0, 0, NULL, 0);
+
+	return 0;
+}
+
+/* I2C */
+static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+			   int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct az6007_device_state *st = d->priv;
+	int i, j, len;
+	int ret = 0;
+	u16 index;
+	u16 value;
+	int length;
+	u8 req, addr;
+
+	if (mutex_lock_interruptible(&st->mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		addr = msgs[i].addr << 1;
+		if (((i + 1) < num)
+		    && (msgs[i].len == 1)
+		    && (!msgs[i].flags & I2C_M_RD)
+		    && (msgs[i + 1].flags & I2C_M_RD)
+		    && (msgs[i].addr == msgs[i + 1].addr)) {
+			/*
+			 * A write + read xfer for the same address, where
+			 * the first xfer has just 1 byte length.
+			 * Need to join both into one operation
+			 */
+			if (dvb_usb_az6007_debug & 2)
+				printk(KERN_DEBUG
+				       "az6007 I2C xfer write+read addr=0x%x len=%d/%d: ",
+				       addr, msgs[i].len, msgs[i + 1].len);
+			req = AZ6007_I2C_RD;
+			index = msgs[i].buf[0];
+			value = addr | (1 << 8);
+			length = 6 + msgs[i + 1].len;
+			len = msgs[i + 1].len;
+			ret = __az6007_read(d->udev, req, value, index,
+					    st->data, length);
+			if (ret >= len) {
+				for (j = 0; j < len; j++) {
+					msgs[i + 1].buf[j] = st->data[j + 5];
+					if (dvb_usb_az6007_debug & 2)
+						printk(KERN_CONT
+						       "0x%02x ",
+						       msgs[i + 1].buf[j]);
+				}
+			} else
+				ret = -EIO;
+			i++;
+		} else if (!(msgs[i].flags & I2C_M_RD)) {
+			/* write bytes */
+			if (dvb_usb_az6007_debug & 2)
+				printk(KERN_DEBUG
+				       "az6007 I2C xfer write addr=0x%x len=%d: ",
+				       addr, msgs[i].len);
+			req = AZ6007_I2C_WR;
+			index = msgs[i].buf[0];
+			value = addr | (1 << 8);
+			length = msgs[i].len - 1;
+			len = msgs[i].len - 1;
+			if (dvb_usb_az6007_debug & 2)
+				printk(KERN_CONT "(0x%02x) ", msgs[i].buf[0]);
+			for (j = 0; j < len; j++) {
+				st->data[j] = msgs[i].buf[j + 1];
+				if (dvb_usb_az6007_debug & 2)
+					printk(KERN_CONT "0x%02x ",
+					       st->data[j]);
+			}
+			ret =  __az6007_write(d->udev, req, value, index,
+					      st->data, length);
+		} else {
+			/* read bytes */
+			if (dvb_usb_az6007_debug & 2)
+				printk(KERN_DEBUG
+				       "az6007 I2C xfer read addr=0x%x len=%d: ",
+				       addr, msgs[i].len);
+			req = AZ6007_I2C_RD;
+			index = msgs[i].buf[0];
+			value = addr;
+			length = msgs[i].len + 6;
+			len = msgs[i].len;
+			ret = __az6007_read(d->udev, req, value, index,
+					    st->data, length);
+			for (j = 0; j < len; j++) {
+				msgs[i].buf[j] = st->data[j + 5];
+				if (dvb_usb_az6007_debug & 2)
+					printk(KERN_CONT
+					       "0x%02x ", st->data[j + 5]);
+			}
+		}
+		if (dvb_usb_az6007_debug & 2)
+			printk(KERN_CONT "\n");
+		if (ret < 0)
+			goto err;
+	}
+err:
+	mutex_unlock(&st->mutex);
+
+	if (ret < 0) {
+		info("%s ERROR: %i", __func__, ret);
+		return ret;
+	}
+	return num;
+}
+
+static u32 az6007_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm az6007_i2c_algo = {
+	.master_xfer = az6007_i2c_xfer,
+	.functionality = az6007_i2c_func,
+};
+
+int az6007_identify_state(struct usb_device *udev,
+			  struct dvb_usb_device_properties *props,
+			  struct dvb_usb_device_description **desc, int *cold)
+{
+	int ret;
+	u8 *mac;
+
+	mac = kmalloc(6, GFP_ATOMIC);
+	if (!mac)
+		return -ENOMEM;
+
+	/* Try to read the mac address */
+	ret = __az6007_read(udev, AZ6007_READ_DATA, 6, 0, mac, 6);
+	if (ret == 6)
+		*cold = 0;
+	else
+		*cold = 1;
+
+	kfree(mac);
+
+	if (*cold) {
+		__az6007_write(udev, 0x09, 1, 0, NULL, 0);
+		__az6007_write(udev, 0x00, 0, 0, NULL, 0);
+		__az6007_write(udev, 0x00, 0, 0, NULL, 0);
+	}
+
+	deb_info("Device is on %s state\n", *cold ? "warm" : "cold");
+	return 0;
+}
+
+static struct dvb_usb_device_properties az6007_properties;
+
+static void az6007_usb_disconnect(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+	az6007_ci_uninit(d);
+	dvb_usb_device_exit(intf);
+}
+
+static int az6007_usb_probe(struct usb_interface *intf,
+			    const struct usb_device_id *id)
+{
+	return dvb_usb_device_init(intf, &az6007_properties,
+				   THIS_MODULE, NULL, adapter_nr);
+}
+
+static struct usb_device_id az6007_usb_table[] = {
+	{USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007)},
+	{USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7)},
+	{USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2)},
+	{0},
+};
+
+MODULE_DEVICE_TABLE(usb, az6007_usb_table);
+
+static struct dvb_usb_device_properties az6007_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware            = "dvb-usb-terratec-h7-az6007.fw",
+	.no_reconnect        = 1,
+	.size_of_priv        = sizeof(struct az6007_device_state),
+	.identify_state	     = az6007_identify_state,
+	.num_adapters = 1,
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = az6007_streaming_ctrl,
+			.tuner_attach     = az6007_tuner_attach,
+			.frontend_attach  = az6007_frontend_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 10,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		} }
+	} },
+	.power_ctrl       = az6007_power_ctrl,
+	.read_mac_address = az6007_read_mac_addr,
+
+	.rc.core = {
+		.rc_interval      = 400,
+		.rc_codes         = RC_MAP_NEC_TERRATEC_CINERGY_XS,
+		.module_name	  = "az6007",
+		.rc_query         = az6007_rc_query,
+		.allowed_protos   = RC_TYPE_NEC,
+	},
+	.i2c_algo         = &az6007_i2c_algo,
+
+	.num_device_descs = 2,
+	.devices = {
+		{ .name = "AzureWave DTV StarBox DVB-T/C USB2.0 (az6007)",
+		  .cold_ids = { &az6007_usb_table[0], NULL },
+		  .warm_ids = { NULL },
+		},
+		{ .name = "TerraTec DTV StarBox DVB-T/C USB2.0 (az6007)",
+		  .cold_ids = { &az6007_usb_table[1], &az6007_usb_table[2], NULL },
+		  .warm_ids = { NULL },
+		},
+		{ NULL },
+	}
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver az6007_usb_driver = {
+	.name		= "dvb_usb_az6007",
+	.probe		= az6007_usb_probe,
+	.disconnect	= az6007_usb_disconnect,
+	.id_table	= az6007_usb_table,
+};
+
+/* module stuff */
+static int __init az6007_usb_module_init(void)
+{
+	int result;
+	deb_info("az6007 usb module init\n");
+
+	result = usb_register(&az6007_usb_driver);
+	if (result) {
+		err("usb_register failed. (%d)", result);
+		return result;
+	}
+
+	return 0;
+}
+
+static void __exit az6007_usb_module_exit(void)
+{
+	/* deregister this driver from the USB subsystem */
+	deb_info("az6007 usb module exit\n");
+	usb_deregister(&az6007_usb_driver);
+}
+
+module_init(az6007_usb_module_init);
+module_exit(az6007_usb_module_exit);
+
+MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");
+MODULE_VERSION("1.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 070e82aa..02290c6 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -677,11 +677,9 @@
 	u8 toggle;
 
 	deb_info("%s()\n", __func__);
-	if (d == NULL)
-		return;
-
 	if (d->rc_dev == NULL) {
 		/* This will occur if disable_rc_polling=1 */
+		kfree(purb->transfer_buffer);
 		usb_free_urb(purb);
 		return;
 	}
@@ -690,6 +688,7 @@
 
 	if (purb->status < 0) {
 		deb_info("discontinuing polling\n");
+		kfree(purb->transfer_buffer);
 		usb_free_urb(purb);
 		return;
 	}
@@ -784,8 +783,11 @@
 			  dib0700_rc_urb_completion, d);
 
 	ret = usb_submit_urb(purb, GFP_ATOMIC);
-	if (ret)
+	if (ret) {
 		err("rc submit urb failed\n");
+		kfree(purb->transfer_buffer);
+		usb_free_urb(purb);
+	}
 
 	return ret;
 }
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index d390dda..397d8f2 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -51,6 +51,7 @@
 #define USB_VID_PINNACLE			0x2304
 #define USB_VID_PCTV				0x2013
 #define USB_VID_PIXELVIEW			0x1554
+#define USB_VID_REALTEK				0x0bda
 #define USB_VID_TECHNOTREND			0x0b48
 #define USB_VID_TERRATEC			0x0ccd
 #define USB_VID_TELESTAR			0x10b9
@@ -80,6 +81,7 @@
 #define USB_PID_ANSONIC_DVBT_USB			0x6000
 #define USB_PID_ANYSEE					0x861f
 #define USB_PID_AZUREWAVE_AD_TU700			0x3237
+#define USB_PID_AZUREWAVE_6007				0x0ccd
 #define USB_PID_AVERMEDIA_DVBT_USB_COLD			0x0001
 #define USB_PID_AVERMEDIA_DVBT_USB_WARM			0x0002
 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD		0xa800
@@ -125,6 +127,8 @@
 #define USB_PID_E3C_EC168_3				0xfffb
 #define USB_PID_E3C_EC168_4				0x1001
 #define USB_PID_E3C_EC168_5				0x1002
+#define USB_PID_FREECOM_DVBT				0x0160
+#define USB_PID_FREECOM_DVBT_2				0x0161
 #define USB_PID_UNIWILL_STK7700P			0x6003
 #define USB_PID_GENIUS_TVGO_DVB_T03			0x4012
 #define USB_PID_GRANDTEC_DVBT_USB_COLD			0x0fa0
@@ -226,6 +230,8 @@
 #define USB_PID_TERRATEC_CINERGY_T_EXPRESS		0x0062
 #define USB_PID_TERRATEC_CINERGY_T_XXS			0x0078
 #define USB_PID_TERRATEC_CINERGY_T_XXS_2		0x00ab
+#define USB_PID_TERRATEC_H7				0x10b4
+#define USB_PID_TERRATEC_H7_2				0x10a3
 #define USB_PID_TERRATEC_T3				0x10a0
 #define USB_PID_TERRATEC_T5				0x10a1
 #define USB_PID_PINNACLE_EXPRESSCARD_320CX		0x022e
@@ -249,6 +255,8 @@
 #define USB_PID_PCTV_400E				0x020f
 #define USB_PID_PCTV_450E				0x0222
 #define USB_PID_PCTV_452E				0x021f
+#define USB_PID_REALTEK_RTL2831U			0x2831
+#define USB_PID_REALTEK_RTL2832U			0x2832
 #define USB_PID_TECHNOTREND_CONNECT_S2_3600		0x3007
 #define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI		0x300a
 #define USB_PID_NEBULA_DIGITV				0x0201
diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c
index 9f01cd7..3b7b102 100644
--- a/drivers/media/dvb/dvb-usb/it913x.c
+++ b/drivers/media/dvb/dvb-usb/it913x.c
@@ -64,6 +64,7 @@
 struct it913x_state {
 	u8 id;
 	struct ite_config it913x_config;
+	u8 pid_filter_onoff;
 };
 
 struct ite_config it913x_config;
@@ -259,15 +260,16 @@
 
 static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
+	struct it913x_state *st = adap->dev->priv;
 	struct usb_device *udev = adap->dev->udev;
 	int ret;
 	u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
 
-	if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
-			return -EAGAIN;
+	mutex_lock(&adap->dev->i2c_mutex);
+
 	deb_info(1, "PID_C  (%02x)", onoff);
 
-	ret = it913x_wr_reg(udev, pro, PID_EN, onoff);
+	ret = it913x_wr_reg(udev, pro, PID_EN, st->pid_filter_onoff);
 
 	mutex_unlock(&adap->dev->i2c_mutex);
 	return ret;
@@ -276,12 +278,13 @@
 static int it913x_pid_filter(struct dvb_usb_adapter *adap,
 		int index, u16 pid, int onoff)
 {
+	struct it913x_state *st = adap->dev->priv;
 	struct usb_device *udev = adap->dev->udev;
 	int ret;
 	u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
 
-	if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
-			return -EAGAIN;
+	mutex_lock(&adap->dev->i2c_mutex);
+
 	deb_info(1, "PID_F  (%02x)", onoff);
 
 	ret = it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff));
@@ -292,6 +295,13 @@
 
 	ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f));
 
+	if (udev->speed == USB_SPEED_HIGH && pid == 0x2000) {
+			ret |= it913x_wr_reg(udev, pro, PID_EN, !onoff);
+			st->pid_filter_onoff = !onoff;
+	} else
+		st->pid_filter_onoff =
+			adap->fe_adap[adap->active_fe].pid_filtering;
+
 	mutex_unlock(&adap->dev->i2c_mutex);
 	return 0;
 }
@@ -316,8 +326,8 @@
 	int ret;
 	u32 reg;
 	u8 pro;
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-			return -EAGAIN;
+
+	mutex_lock(&d->i2c_mutex);
 
 	debug_data_snipet(1, "Message out", msg[0].buf);
 	deb_info(2, "num of messages %d address %02x", num, msg[0].addr);
@@ -358,8 +368,7 @@
 	int ret;
 	u32 key;
 	/* Avoid conflict with frontends*/
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-			return -EAGAIN;
+	mutex_lock(&d->i2c_mutex);
 
 	ret = it913x_io(d->udev, READ_LONG, PRO_LINK, CMD_IR_GET,
 		0, 0, &ibuf[0], sizeof(ibuf));
@@ -388,19 +397,12 @@
 {
 	int sw;
 	/* auto switch */
-	if (le16_to_cpu(udev->descriptor.idProduct) ==
-			USB_PID_ITETECH_IT9135)
-		sw = IT9135_V1_FW;
-	else if (le16_to_cpu(udev->descriptor.idProduct) ==
-			USB_PID_ITETECH_IT9135_9005)
-		sw = IT9135_V1_FW;
-	else if (le16_to_cpu(udev->descriptor.idProduct) ==
-			USB_PID_ITETECH_IT9135_9006) {
-		sw = IT9135_V2_FW;
-		if (it913x_config.tuner_id_0 == 0)
-			it913x_config.tuner_id_0 = IT9135_60;
-	} else
+	if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_KWORLD_2)
 		sw = IT9137_FW;
+	else if (it913x_config.chip_ver == 1)
+		sw = IT9135_V1_FW;
+	else
+		sw = IT9135_V2_FW;
 
 	/* force switch */
 	if (dvb_usb_it913x_firmware != IT9135_AUTO)
@@ -410,41 +412,103 @@
 	case IT9135_V1_FW:
 		it913x_config.firmware_ver = 1;
 		it913x_config.adc_x2 = 1;
+		it913x_config.read_slevel = false;
 		props->firmware = fw_it9135_v1;
 		break;
 	case IT9135_V2_FW:
 		it913x_config.firmware_ver = 1;
 		it913x_config.adc_x2 = 1;
+		it913x_config.read_slevel = false;
 		props->firmware = fw_it9135_v2;
+		switch (it913x_config.tuner_id_0) {
+		case IT9135_61:
+		case IT9135_62:
+			break;
+		default:
+			info("Unknown tuner ID applying default 0x60");
+		case IT9135_60:
+			it913x_config.tuner_id_0 = IT9135_60;
+		}
 		break;
 	case IT9137_FW:
 	default:
 		it913x_config.firmware_ver = 0;
 		it913x_config.adc_x2 = 0;
+		it913x_config.read_slevel = true;
 		props->firmware = fw_it9137;
 	}
 
 	return 0;
 }
 
+static void it913x_select_remote(struct usb_device *udev,
+	struct dvb_usb_device_properties *props)
+{
+	switch (le16_to_cpu(udev->descriptor.idProduct)) {
+	case USB_PID_ITETECH_IT9135_9005:
+		props->rc.core.rc_codes = RC_MAP_IT913X_V2;
+		return;
+	default:
+		props->rc.core.rc_codes = RC_MAP_IT913X_V1;
+	}
+	return;
+}
+
 #define TS_MPEG_PKT_SIZE	188
 #define EP_LOW			21
 #define TS_BUFFER_SIZE_PID	(EP_LOW*TS_MPEG_PKT_SIZE)
 #define EP_HIGH			348
 #define TS_BUFFER_SIZE_MAX	(EP_HIGH*TS_MPEG_PKT_SIZE)
 
-static int it913x_identify_state(struct usb_device *udev,
-		struct dvb_usb_device_properties *props,
-		struct dvb_usb_device_description **desc,
-		int *cold)
+static int it913x_select_config(struct usb_device *udev,
+	struct dvb_usb_device_properties *props)
 {
-	int ret = 0, firm_no;
-	u8 reg, remote;
+	int ret = 0, reg;
+	bool proprietary_ir = false;
 
-	firm_no = it913x_return_status(udev);
+	if (it913x_config.chip_ver == 0x02
+			&& it913x_config.chip_type == 0x9135)
+		reg = it913x_read_reg(udev, 0x461d);
+	else
+		reg = it913x_read_reg(udev, 0x461b);
 
-	/* checnk for dual mode */
-	it913x_config.dual_mode =  it913x_read_reg(udev, 0x49c5);
+	if (reg < 0)
+		return reg;
+
+	if (reg == 0) {
+		it913x_config.dual_mode = 0;
+		it913x_config.tuner_id_0 = IT9135_38;
+		proprietary_ir = true;
+	} else {
+		/* TS mode */
+		reg =  it913x_read_reg(udev, 0x49c5);
+		if (reg < 0)
+			return reg;
+		it913x_config.dual_mode = reg;
+
+		/* IR mode type */
+		reg = it913x_read_reg(udev, 0x49ac);
+		if (reg < 0)
+			return reg;
+		if (reg == 5) {
+			info("Remote propriety (raw) mode");
+			proprietary_ir = true;
+		} else if (reg == 1) {
+			info("Remote HID mode NOT SUPPORTED");
+			proprietary_ir = false;
+			props->rc.core.rc_codes = NULL;
+		} else
+			props->rc.core.rc_codes = NULL;
+
+		/* Tuner_id */
+		reg = it913x_read_reg(udev, 0x49d0);
+		if (reg < 0)
+			return reg;
+		it913x_config.tuner_id_0 = reg;
+	}
+
+	if (proprietary_ir)
+		it913x_select_remote(udev, props);
 
 	if (udev->speed != USB_SPEED_HIGH) {
 		props->adapter[0].fe[0].pid_filter_count = 5;
@@ -459,17 +523,6 @@
 		if(props->adapter[0].fe[0].pid_filter_count == 5)
 			props->adapter[0].fe[0].pid_filter_count = 31;
 
-	/* TODO different remotes */
-	remote = it913x_read_reg(udev, 0x49ac); /* Remote */
-	if (remote == 0)
-		props->rc.core.rc_codes = NULL;
-
-	/* TODO at the moment tuner_id is always assigned to 0x38 */
-	it913x_config.tuner_id_0 = it913x_read_reg(udev, 0x49d0);
-
-	info("Dual mode=%x Remote=%x Tuner Type=%x", it913x_config.dual_mode
-		, remote, it913x_config.tuner_id_0);
-
 	/* Select Stream Buffer Size and pid filter option*/
 	if (pid_filter) {
 		props->adapter[0].fe[0].stream.u.bulk.buffersize =
@@ -490,8 +543,29 @@
 	} else
 		props->num_adapters = 1;
 
+	info("Dual mode=%x Tuner Type=%x", it913x_config.dual_mode,
+		it913x_config.tuner_id_0);
+
 	ret = ite_firmware_select(udev, props);
 
+	return ret;
+}
+
+static int it913x_identify_state(struct usb_device *udev,
+		struct dvb_usb_device_properties *props,
+		struct dvb_usb_device_description **desc,
+		int *cold)
+{
+	int ret = 0, firm_no;
+	u8 reg;
+
+	firm_no = it913x_return_status(udev);
+
+	/* Read and select config */
+	ret = it913x_select_config(udev, props);
+	if (ret < 0)
+		return ret;
+
 	if (firm_no > 0) {
 		*cold = 0;
 		return 0;
@@ -538,18 +612,22 @@
 
 static int it913x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
+	struct it913x_state *st = adap->dev->priv;
 	int ret = 0;
 	u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
 
-	if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
-			return -EAGAIN;
 	deb_info(1, "STM  (%02x)", onoff);
 
-	if (!onoff)
+	if (!onoff) {
+		mutex_lock(&adap->dev->i2c_mutex);
+
 		ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1);
 
+		mutex_unlock(&adap->dev->i2c_mutex);
+		st->pid_filter_onoff =
+			adap->fe_adap[adap->active_fe].pid_filtering;
 
-	mutex_unlock(&adap->dev->i2c_mutex);
+	}
 
 	return ret;
 }
@@ -789,7 +867,7 @@
 		.rc_query	= it913x_rc_query,
 		.rc_interval	= IT913X_POLL,
 		.allowed_protos	= RC_TYPE_NEC,
-		.rc_codes	= RC_MAP_MSI_DIGIVOX_III,
+		.rc_codes	= RC_MAP_IT913X_V1,
 	},
 	.i2c_algo         = &it913x_i2c_algo,
 	.num_device_descs = 5,
@@ -823,5 +901,5 @@
 
 MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
 MODULE_DESCRIPTION("it913x USB 2 Driver");
-MODULE_VERSION("1.22");
+MODULE_VERSION("1.27");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c
index 291f6b1..5dde06d 100644
--- a/drivers/media/dvb/dvb-usb/lmedm04.c
+++ b/drivers/media/dvb/dvb-usb/lmedm04.c
@@ -77,6 +77,7 @@
 #include "stv0299.h"
 #include "dvb-pll.h"
 #include "z0194a.h"
+#include "m88rs2000.h"
 
 
 
@@ -104,7 +105,7 @@
 
 static int pid_filter;
 module_param_named(pid, pid_filter, int, 0644);
-MODULE_PARM_DESC(pid, "set default 0=on 1=off");
+MODULE_PARM_DESC(pid, "set default 0=default 1=off 2=on");
 
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@@ -113,6 +114,7 @@
 #define TUNER_LG	0x1
 #define TUNER_S7395	0x2
 #define TUNER_S0194	0x3
+#define TUNER_RS2000	0x4
 
 struct lme2510_state {
 	u8 id;
@@ -121,6 +123,8 @@
 	u8 signal_level;
 	u8 signal_sn;
 	u8 time_key;
+	u8 last_key;
+	u8 key_timeout;
 	u8 i2c_talk_onoff;
 	u8 i2c_gate;
 	u8 i2c_tuner_gate_w;
@@ -128,6 +132,7 @@
 	u8 i2c_tuner_addr;
 	u8 stream_on;
 	u8 pid_size;
+	u8 pid_off;
 	void *buffer;
 	struct urb *lme_urb;
 	void *usb_buffer;
@@ -178,14 +183,8 @@
 	/* the read/write capped at 64 */
 	memcpy(buff, wbuf, (wlen < 64) ? wlen : 64);
 
-	ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01));
-
 	ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01);
 
-	msleep(10);
-
-	ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01));
-
 	ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ?
 			rlen : 64 , 0x01);
 
@@ -199,9 +198,14 @@
 
 static int lme2510_stream_restart(struct dvb_usb_device *d)
 {
-	static u8 stream_on[] = LME_ST_ON_W;
+	struct lme2510_state *st = d->priv;
+	u8 all_pids[] = LME_ALL_PIDS;
+	u8 stream_on[] = LME_ST_ON_W;
 	int ret;
-	u8 rbuff[10];
+	u8 rbuff[1];
+	if (st->pid_off)
+		ret = lme2510_usb_talk(d, all_pids, sizeof(all_pids),
+			rbuff, sizeof(rbuff));
 	/*Restart Stream Command*/
 	ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on),
 			rbuff, sizeof(rbuff));
@@ -308,6 +312,14 @@
 						((ibuf[2] & 0x01) << 0x03);
 				}
 				break;
+			case TUNER_RS2000:
+				if (ibuf[2] > 0)
+					st->signal_lock = 0xff;
+				else
+					st->signal_lock = 0xf0;
+				st->signal_level = ibuf[4];
+				st->signal_sn = ibuf[5];
+				st->time_key = ibuf[7];
 			default:
 				break;
 			}
@@ -359,19 +371,20 @@
 static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
 	struct lme2510_state *st = adap->dev->priv;
-	static u8 clear_pid_reg[] = LME_CLEAR_PID;
+	static u8 clear_pid_reg[] = LME_ALL_PIDS;
 	static u8 rbuf[1];
 	int ret;
 
 	deb_info(1, "PID Clearing Filter");
 
-	ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
-	if (ret < 0)
-		return -EAGAIN;
+	mutex_lock(&adap->dev->i2c_mutex);
 
-	if (!onoff)
+	if (!onoff) {
 		ret |= lme2510_usb_talk(adap->dev, clear_pid_reg,
 			sizeof(clear_pid_reg), rbuf, sizeof(rbuf));
+		st->pid_off = true;
+	} else
+		st->pid_off = false;
 
 	st->pid_size = 0;
 
@@ -389,11 +402,9 @@
 		pid, index, onoff);
 
 	if (onoff) {
-			ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
-			if (ret < 0)
-				return -EAGAIN;
-			ret |= lme2510_enable_pid(adap->dev, index, pid);
-			mutex_unlock(&adap->dev->i2c_mutex);
+		mutex_lock(&adap->dev->i2c_mutex);
+		ret |= lme2510_enable_pid(adap->dev, index, pid);
+		mutex_unlock(&adap->dev->i2c_mutex);
 	}
 
 
@@ -425,9 +436,6 @@
 	int ret = 0;
 	struct lme2510_state *st = d->priv;
 
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-			return -EAGAIN;
-
 	if (st->i2c_talk_onoff == 1) {
 
 		ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
@@ -456,8 +464,6 @@
 						st->i2c_talk_onoff = 0;
 					}
 				}
-				if ((wbuf[3] != 0x6) & (wbuf[3] != 0x5))
-					msleep(5);
 			}
 			break;
 		case TUNER_S0194:
@@ -472,10 +478,12 @@
 				}
 			}
 			break;
+		case TUNER_RS2000:
 		default:
 			break;
 		}
 	} else {
+		/* TODO rewrite this section */
 		switch (st->tuner_config) {
 		case TUNER_LG:
 			switch (wbuf[3]) {
@@ -559,6 +567,24 @@
 				break;
 			}
 			break;
+		case TUNER_RS2000:
+			switch (wbuf[3]) {
+			case 0x8c:
+				rbuf[0] = 0x55;
+				rbuf[1] = 0xff;
+				if (st->last_key == st->time_key) {
+					st->key_timeout++;
+					if (st->key_timeout > 5)
+						rbuf[1] = 0;
+				} else
+					st->key_timeout = 0;
+				st->last_key = st->time_key;
+				break;
+			default:
+				lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+				st->i2c_talk_onoff = 1;
+				break;
+			}
 		default:
 			break;
 		}
@@ -568,8 +594,6 @@
 
 	}
 
-	mutex_unlock(&d->i2c_mutex);
-
 	return ret;
 }
 
@@ -584,6 +608,8 @@
 	u16 len;
 	u8 gate = st->i2c_gate;
 
+	mutex_lock(&d->i2c_mutex);
+
 	if (gate == 0)
 		gate = 5;
 
@@ -622,6 +648,7 @@
 
 		if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) {
 			deb_info(1, "i2c transfer failed.");
+			mutex_unlock(&d->i2c_mutex);
 			return -EAGAIN;
 		}
 
@@ -634,6 +661,8 @@
 			}
 		}
 	}
+
+	mutex_unlock(&d->i2c_mutex);
 	return i;
 }
 
@@ -653,7 +682,7 @@
 		struct dvb_usb_device_description **desc,
 		int *cold)
 {
-	if (pid_filter > 0)
+	if (pid_filter != 2)
 		props->adapter[0].fe[0].caps &=
 			~DVB_USB_ADAP_NEED_PID_FILTERING;
 	*cold = 0;
@@ -663,7 +692,7 @@
 static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
 	struct lme2510_state *st = adap->dev->priv;
-	static u8 clear_reg_3[] = LME_CLEAR_PID;
+	static u8 clear_reg_3[] = LME_ALL_PIDS;
 	static u8 rbuf[1];
 	int ret = 0, rlen = sizeof(rbuf);
 
@@ -675,8 +704,7 @@
 	else {
 		deb_info(1, "STM Steam Off");
 		/* mutex is here only to avoid collision with I2C */
-		if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
-			return -EAGAIN;
+		mutex_lock(&adap->dev->i2c_mutex);
 
 		ret = lme2510_usb_talk(adap->dev, clear_reg_3,
 				sizeof(clear_reg_3), rbuf, rlen);
@@ -781,16 +809,18 @@
 	const char fw_c_s7395[] = "dvb-usb-lme2510c-s7395.fw";
 	const char fw_c_lg[] = "dvb-usb-lme2510c-lg.fw";
 	const char fw_c_s0194[] = "dvb-usb-lme2510c-s0194.fw";
+	const char fw_c_rs2000[] = "dvb-usb-lme2510c-rs2000.fw";
 	const char fw_lg[] = "dvb-usb-lme2510-lg.fw";
 	const char fw_s0194[] = "dvb-usb-lme2510-s0194.fw";
 	const char *fw_lme;
-	int ret, cold_fw;
+	int ret = 0, cold_fw;
 
 	cold = (cold > 0) ? (cold & 1) : 0;
 
 	cold_fw = !cold;
 
-	if (le16_to_cpu(udev->descriptor.idProduct) == 0x1122) {
+	switch (le16_to_cpu(udev->descriptor.idProduct)) {
+	case 0x1122:
 		switch (dvb_usb_lme2510_firmware) {
 		default:
 			dvb_usb_lme2510_firmware = TUNER_S0194;
@@ -813,7 +843,8 @@
 			cold_fw = 0;
 			break;
 		}
-	} else {
+		break;
+	case 0x1120:
 		switch (dvb_usb_lme2510_firmware) {
 		default:
 			dvb_usb_lme2510_firmware = TUNER_S7395;
@@ -842,8 +873,17 @@
 			cold_fw = 0;
 			break;
 		}
+		break;
+	case 0x22f0:
+		fw_lme = fw_c_rs2000;
+		ret = request_firmware(&fw, fw_lme, &udev->dev);
+		dvb_usb_lme2510_firmware = TUNER_RS2000;
+		break;
+	default:
+		fw_lme = fw_c_s7395;
 	}
 
+
 	if (cold_fw) {
 		info("FRM Loading %s file", fw_lme);
 		ret = lme2510_download_firmware(udev, fw);
@@ -906,6 +946,29 @@
 	.set_symbol_rate = sharp_z0194a_set_symbol_rate,
 };
 
+static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe,
+	int caller)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dvb_usb_device *d = adap->dev;
+	struct lme2510_state *st = d->priv;
+
+	mutex_lock(&d->i2c_mutex);
+	if ((st->i2c_talk_onoff == 1) && (st->stream_on & 1)) {
+		st->i2c_talk_onoff = 0;
+		lme2510_stream_restart(d);
+	}
+	mutex_unlock(&d->i2c_mutex);
+
+	return 0;
+}
+
+static struct m88rs2000_config m88rs2000_config = {
+	.demod_addr = 0xd0,
+	.tuner_addr = 0xc0,
+	.set_ts_params = dm04_rs2000_set_ts_param,
+};
+
 static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
 					fe_sec_voltage_t voltage)
 {
@@ -915,8 +978,7 @@
 	static u8 rbuf[1];
 	int ret = 0, len = 3, rlen = 1;
 
-	if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
-			return -EAGAIN;
+	mutex_lock(&adap->dev->i2c_mutex);
 
 	switch (voltage) {
 	case SEC_VOLTAGE_18:
@@ -937,12 +999,31 @@
 	return (ret < 0) ? -ENODEV : 0;
 }
 
+static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe,
+	u16 *strength)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct lme2510_state *st = adap->dev->priv;
+
+	*strength = (u16)((u32)st->signal_level * 0xffff / 0x7f);
+	return 0;
+}
+
+static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct lme2510_state *st = adap->dev->priv;
+
+	*snr = (u16)((u32)st->signal_sn * 0xffff / 0xff);
+	return 0;
+}
+
 static int lme_name(struct dvb_usb_adapter *adap)
 {
 	struct lme2510_state *st = adap->dev->priv;
 	const char *desc = adap->dev->desc->name;
 	char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395",
-				" SHARP:BS2F7HZ0194"};
+				" SHARP:BS2F7HZ0194", " RS2000"};
 	char *name = adap->fe_adap[0].fe->ops.info.name;
 
 	strlcpy(name, desc, 128);
@@ -958,60 +1039,82 @@
 	int ret = 0;
 
 	st->i2c_talk_onoff = 1;
-
-	st->i2c_gate = 4;
-	adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config,
-		&adap->dev->i2c_adap);
-
-	if (adap->fe_adap[0].fe) {
-		info("TUN Found Frontend TDA10086");
-		st->i2c_tuner_gate_w = 4;
-		st->i2c_tuner_gate_r = 4;
-		st->i2c_tuner_addr = 0xc0;
-		st->tuner_config = TUNER_LG;
-		if (dvb_usb_lme2510_firmware != TUNER_LG) {
-			dvb_usb_lme2510_firmware = TUNER_LG;
-			ret = lme_firmware_switch(adap->dev->udev, 1);
+	switch (le16_to_cpu(adap->dev->udev->descriptor.idProduct)) {
+	case 0x1122:
+	case 0x1120:
+		st->i2c_gate = 4;
+		adap->fe_adap[0].fe = dvb_attach(tda10086_attach,
+			&tda10086_config, &adap->dev->i2c_adap);
+		if (adap->fe_adap[0].fe) {
+			info("TUN Found Frontend TDA10086");
+			st->i2c_tuner_gate_w = 4;
+			st->i2c_tuner_gate_r = 4;
+			st->i2c_tuner_addr = 0xc0;
+			st->tuner_config = TUNER_LG;
+			if (dvb_usb_lme2510_firmware != TUNER_LG) {
+				dvb_usb_lme2510_firmware = TUNER_LG;
+				ret = lme_firmware_switch(adap->dev->udev, 1);
+			}
+			break;
 		}
-		goto end;
-	}
 
-	st->i2c_gate = 4;
-	adap->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194_config,
+		st->i2c_gate = 4;
+		adap->fe_adap[0].fe = dvb_attach(stv0299_attach,
+				&sharp_z0194_config, &adap->dev->i2c_adap);
+		if (adap->fe_adap[0].fe) {
+			info("FE Found Stv0299");
+			st->i2c_tuner_gate_w = 4;
+			st->i2c_tuner_gate_r = 5;
+			st->i2c_tuner_addr = 0xc0;
+			st->tuner_config = TUNER_S0194;
+			if (dvb_usb_lme2510_firmware != TUNER_S0194) {
+				dvb_usb_lme2510_firmware = TUNER_S0194;
+				ret = lme_firmware_switch(adap->dev->udev, 1);
+			}
+			break;
+		}
+
+		st->i2c_gate = 5;
+		adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config,
 			&adap->dev->i2c_adap);
-	if (adap->fe_adap[0].fe) {
-		info("FE Found Stv0299");
-		st->i2c_tuner_gate_w = 4;
-		st->i2c_tuner_gate_r = 5;
-		st->i2c_tuner_addr = 0xc0;
-		st->tuner_config = TUNER_S0194;
-		if (dvb_usb_lme2510_firmware != TUNER_S0194) {
-			dvb_usb_lme2510_firmware = TUNER_S0194;
-			ret = lme_firmware_switch(adap->dev->udev, 1);
+
+		if (adap->fe_adap[0].fe) {
+			info("FE Found Stv0288");
+			st->i2c_tuner_gate_w = 4;
+			st->i2c_tuner_gate_r = 5;
+			st->i2c_tuner_addr = 0xc0;
+			st->tuner_config = TUNER_S7395;
+			if (dvb_usb_lme2510_firmware != TUNER_S7395) {
+				dvb_usb_lme2510_firmware = TUNER_S7395;
+				ret = lme_firmware_switch(adap->dev->udev, 1);
+			}
+			break;
 		}
-		goto end;
+	case 0x22f0:
+		st->i2c_gate = 5;
+		adap->fe_adap[0].fe = dvb_attach(m88rs2000_attach,
+			&m88rs2000_config, &adap->dev->i2c_adap);
+
+		if (adap->fe_adap[0].fe) {
+			info("FE Found M88RS2000");
+			st->i2c_tuner_gate_w = 5;
+			st->i2c_tuner_gate_r = 5;
+			st->i2c_tuner_addr = 0xc0;
+			st->tuner_config = TUNER_RS2000;
+			adap->fe_adap[0].fe->ops.read_signal_strength =
+				dm04_rs2000_read_signal_strength;
+			adap->fe_adap[0].fe->ops.read_snr =
+				dm04_rs2000_read_snr;
+		}
+		break;
 	}
 
-	st->i2c_gate = 5;
-	adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config,
-			&adap->dev->i2c_adap);
-	if (adap->fe_adap[0].fe) {
-		info("FE Found Stv0288");
-		st->i2c_tuner_gate_w = 4;
-		st->i2c_tuner_gate_r = 5;
-		st->i2c_tuner_addr = 0xc0;
-		st->tuner_config = TUNER_S7395;
-		if (dvb_usb_lme2510_firmware != TUNER_S7395) {
-			dvb_usb_lme2510_firmware = TUNER_S7395;
-			ret = lme_firmware_switch(adap->dev->udev, 1);
-		}
-	} else {
-		info("DM04 Not Supported");
-		return -ENODEV;
+	if (adap->fe_adap[0].fe == NULL) {
+			info("DM04/QQBOX Not Powered up or not Supported");
+			return -ENODEV;
 	}
 
-
-end:	if (ret) {
+	if (ret) {
 		if (adap->fe_adap[0].fe) {
 			dvb_frontend_detach(adap->fe_adap[0].fe);
 			adap->fe_adap[0].fe = NULL;
@@ -1028,7 +1131,7 @@
 static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
 {
 	struct lme2510_state *st = adap->dev->priv;
-	char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA"};
+	char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"};
 	int ret = 0;
 
 	switch (st->tuner_config) {
@@ -1047,6 +1150,9 @@
 			&adap->dev->i2c_adap, DVB_PLL_OPERA1))
 			ret = st->tuner_config;
 		break;
+	case TUNER_RS2000:
+		ret = st->tuner_config;
+		break;
 	default:
 		break;
 	}
@@ -1075,10 +1181,9 @@
 	static u8 lnb_on[] = LNB_ON;
 	static u8 lnb_off[] = LNB_OFF;
 	static u8 rbuf[1];
-	int ret, len = 3, rlen = 1;
+	int ret = 0, len = 3, rlen = 1;
 
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
+	mutex_lock(&d->i2c_mutex);
 
 	if (onoff)
 		ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
@@ -1136,6 +1241,7 @@
 static struct usb_device_id lme2510_table[] = {
 	{ USB_DEVICE(0x3344, 0x1122) },  /* LME2510 */
 	{ USB_DEVICE(0x3344, 0x1120) },  /* LME2510C */
+	{ USB_DEVICE(0x3344, 0x22f0) },  /* LME2510C RS2000 */
 	{}		/* Terminating entry */
 };
 
@@ -1153,7 +1259,7 @@
 				DVB_USB_ADAP_NEED_PID_FILTERING|
 				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
 			.streaming_ctrl   = lme2510_streaming_ctrl,
-			.pid_filter_count = 15,
+			.pid_filter_count = 32,
 			.pid_filter = lme2510_pid_filter,
 			.pid_filter_ctrl  = lme2510_pid_filter_ctrl,
 			.frontend_attach  = dm04_lme2510_frontend_attach,
@@ -1204,7 +1310,7 @@
 				DVB_USB_ADAP_NEED_PID_FILTERING|
 				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
 			.streaming_ctrl   = lme2510_streaming_ctrl,
-			.pid_filter_count = 15,
+			.pid_filter_count = 32,
 			.pid_filter = lme2510_pid_filter,
 			.pid_filter_ctrl  = lme2510_pid_filter_ctrl,
 			.frontend_attach  = dm04_lme2510_frontend_attach,
@@ -1234,11 +1340,14 @@
 	.identify_state   = lme2510_identify_state,
 	.i2c_algo         = &lme2510_i2c_algo,
 	.generic_bulk_ctrl_endpoint = 0,
-	.num_device_descs = 1,
+	.num_device_descs = 2,
 	.devices = {
 		{   "DM04_LME2510C_DVB-S",
 			{ &lme2510_table[1], NULL },
 			},
+		{   "DM04_LME2510C_DVB-S RS2000",
+			{ &lme2510_table[2], NULL },
+			},
 	}
 };
 
@@ -1295,5 +1404,5 @@
 
 MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
 MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
-MODULE_VERSION("1.91");
+MODULE_VERSION("1.99");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.h b/drivers/media/dvb/dvb-usb/lmedm04.h
index ab21e2e..e9c2072 100644
--- a/drivers/media/dvb/dvb-usb/lmedm04.h
+++ b/drivers/media/dvb/dvb-usb/lmedm04.h
@@ -41,6 +41,7 @@
 #define LME_ST_ON_W	{0x06, 0x00}
 #define LME_CLEAR_PID   {0x03, 0x02, 0x20, 0xa0}
 #define LME_ZERO_PID	{0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c}
+#define LME_ALL_PIDS	{0x03, 0x06, 0x00, 0xff, 0x01, 0x1f, 0x20, 0x81}
 
 /*  LNB Voltage
  *  07 XX XX
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c
index 38ef025..81305de 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf.c
+++ b/drivers/media/dvb/dvb-usb/mxl111sf.c
@@ -351,15 +351,13 @@
 					      adap_state->ep6_clockphase,
 					      0, 0);
 		mxl_fail(ret);
+#if 0
 	} else {
 		ret = mxl111sf_disable_656_port(state);
 		mxl_fail(ret);
+#endif
 	}
 
-	mxl111sf_read_reg(state, 0x12, &tmp);
-	tmp &= ~0x04;
-	mxl111sf_write_reg(state, 0x12, tmp);
-
 	return ret;
 }
 
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c
new file mode 100644
index 0000000..8f4736a
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c
@@ -0,0 +1,982 @@
+/*
+ * Realtek RTL28xxU DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.
+ */
+
+#include "rtl28xxu.h"
+
+#include "rtl2830.h"
+
+#include "qt1010.h"
+#include "mt2060.h"
+#include "mxl5005s.h"
+
+/* debug */
+static int dvb_usb_rtl28xxu_debug;
+module_param_named(debug, dvb_usb_rtl28xxu_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req)
+{
+	int ret;
+	unsigned int pipe;
+	u8 requesttype;
+	u8 *buf;
+
+	buf = kmalloc(req->size, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	if (req->index & CMD_WR_FLAG) {
+		/* write */
+		memcpy(buf, req->data, req->size);
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+		pipe = usb_sndctrlpipe(d->udev, 0);
+	} else {
+		/* read */
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+		pipe = usb_rcvctrlpipe(d->udev, 0);
+	}
+
+	ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value,
+			req->index, buf, req->size, 1000);
+	if (ret > 0)
+		ret = 0;
+
+	deb_dump(0, requesttype, req->value, req->index, buf, req->size,
+			deb_xfer);
+
+	/* read request, copy returned data to return buf */
+	if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
+		memcpy(req->data, buf, req->size);
+
+	kfree(buf);
+
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	deb_info("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int rtl2831_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
+{
+	struct rtl28xxu_req req;
+
+	if (reg < 0x3000)
+		req.index = CMD_USB_WR;
+	else if (reg < 0x4000)
+		req.index = CMD_SYS_WR;
+	else
+		req.index = CMD_IR_WR;
+
+	req.value = reg;
+	req.size = len;
+	req.data = val;
+
+	return rtl28xxu_ctrl_msg(d, &req);
+}
+
+static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
+{
+	struct rtl28xxu_req req;
+
+	if (reg < 0x3000)
+		req.index = CMD_USB_RD;
+	else if (reg < 0x4000)
+		req.index = CMD_SYS_RD;
+	else
+		req.index = CMD_IR_RD;
+
+	req.value = reg;
+	req.size = len;
+	req.data = val;
+
+	return rtl28xxu_ctrl_msg(d, &req);
+}
+
+static int rtl2831_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val)
+{
+	return rtl2831_wr_regs(d, reg, &val, 1);
+}
+
+static int rtl2831_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
+{
+	return rtl2831_rd_regs(d, reg, val, 1);
+}
+
+/* I2C */
+static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+	int num)
+{
+	int ret;
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct rtl28xxu_priv *priv = d->priv;
+	struct rtl28xxu_req req;
+
+	/*
+	 * It is not known which are real I2C bus xfer limits, but testing
+	 * with RTL2831U + MT2060 gives max RD 24 and max WR 22 bytes.
+	 * TODO: find out RTL2832U lens
+	 */
+
+	/*
+	 * I2C adapter logic looks rather complicated due to fact it handles
+	 * three different access methods. Those methods are;
+	 * 1) integrated demod access
+	 * 2) old I2C access
+	 * 3) new I2C access
+	 *
+	 * Used method is selected in order 1, 2, 3. Method 3 can handle all
+	 * requests but there is two reasons why not use it always;
+	 * 1) It is most expensive, usually two USB messages are needed
+	 * 2) At least RTL2831U does not support it
+	 *
+	 * Method 3 is needed in case of I2C write+read (typical register read)
+	 * where write is more than one byte.
+	 */
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
+		(msg[1].flags & I2C_M_RD)) {
+		if (msg[0].len > 24 || msg[1].len > 24) {
+			/* TODO: check msg[0].len max */
+			ret = -EOPNOTSUPP;
+			goto err_mutex_unlock;
+		} else if (msg[0].addr == 0x10) {
+			/* method 1 - integrated demod */
+			req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
+			req.index = CMD_DEMOD_RD | priv->page;
+			req.size = msg[1].len;
+			req.data = &msg[1].buf[0];
+			ret = rtl28xxu_ctrl_msg(d, &req);
+		} else if (msg[0].len < 2) {
+			/* method 2 - old I2C */
+			req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
+			req.index = CMD_I2C_RD;
+			req.size = msg[1].len;
+			req.data = &msg[1].buf[0];
+			ret = rtl28xxu_ctrl_msg(d, &req);
+		} else {
+			/* method 3 - new I2C */
+			req.value = (msg[0].addr << 1);
+			req.index = CMD_I2C_DA_WR;
+			req.size = msg[0].len;
+			req.data = msg[0].buf;
+			ret = rtl28xxu_ctrl_msg(d, &req);
+			if (ret)
+				goto err_mutex_unlock;
+
+			req.value = (msg[0].addr << 1);
+			req.index = CMD_I2C_DA_RD;
+			req.size = msg[1].len;
+			req.data = msg[1].buf;
+			ret = rtl28xxu_ctrl_msg(d, &req);
+		}
+	} else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
+		if (msg[0].len > 22) {
+			/* TODO: check msg[0].len max */
+			ret = -EOPNOTSUPP;
+			goto err_mutex_unlock;
+		} else if (msg[0].addr == 0x10) {
+			/* method 1 - integrated demod */
+			if (msg[0].buf[0] == 0x00) {
+				/* save demod page for later demod access */
+				priv->page = msg[0].buf[1];
+				ret = 0;
+			} else {
+				req.value = (msg[0].buf[0] << 8) |
+					(msg[0].addr << 1);
+				req.index = CMD_DEMOD_WR | priv->page;
+				req.size = msg[0].len-1;
+				req.data = &msg[0].buf[1];
+				ret = rtl28xxu_ctrl_msg(d, &req);
+			}
+		} else if (msg[0].len < 23) {
+			/* method 2 - old I2C */
+			req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
+			req.index = CMD_I2C_WR;
+			req.size = msg[0].len-1;
+			req.data = &msg[0].buf[1];
+			ret = rtl28xxu_ctrl_msg(d, &req);
+		} else {
+			/* method 3 - new I2C */
+			req.value = (msg[0].addr << 1);
+			req.index = CMD_I2C_DA_WR;
+			req.size = msg[0].len;
+			req.data = msg[0].buf;
+			ret = rtl28xxu_ctrl_msg(d, &req);
+		}
+	} else {
+		ret = -EINVAL;
+	}
+
+err_mutex_unlock:
+	mutex_unlock(&d->i2c_mutex);
+
+	return ret ? ret : num;
+}
+
+static u32 rtl28xxu_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm rtl28xxu_i2c_algo = {
+	.master_xfer   = rtl28xxu_i2c_xfer,
+	.functionality = rtl28xxu_i2c_func,
+};
+
+static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
+	.i2c_addr = 0x10, /* 0x20 */
+	.xtal = 28800000,
+	.ts_mode = 0,
+	.spec_inv = 1,
+	.if_dvbt = 36150000,
+	.vtop = 0x20,
+	.krf = 0x04,
+	.agc_targ_val = 0x2d,
+
+};
+
+static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
+	.i2c_addr = 0x10, /* 0x20 */
+	.xtal = 28800000,
+	.ts_mode = 0,
+	.spec_inv = 1,
+	.if_dvbt = 36125000,
+	.vtop = 0x20,
+	.krf = 0x04,
+	.agc_targ_val = 0x2d,
+};
+
+static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
+	.i2c_addr = 0x10, /* 0x20 */
+	.xtal = 28800000,
+	.ts_mode = 0,
+	.spec_inv = 0,
+	.if_dvbt = 4570000,
+	.vtop = 0x3f,
+	.krf = 0x04,
+	.agc_targ_val = 0x3e,
+};
+
+static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	struct rtl28xxu_priv *priv = adap->dev->priv;
+	u8 buf[1];
+	struct rtl2830_config *rtl2830_config;
+	/* open RTL2831U/RTL2830 I2C gate */
+	struct rtl28xxu_req req_gate = { 0x0120, 0x0011, 0x0001, "\x08" };
+	/* for MT2060 tuner probe */
+	struct rtl28xxu_req req_mt2060 = { 0x00c0, CMD_I2C_RD, 1, buf };
+	/* for QT1010 tuner probe */
+	struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf };
+
+	deb_info("%s:\n", __func__);
+
+	/*
+	 * RTL2831U GPIOs
+	 * =========================================================
+	 * GPIO0 | tuner#0 | 0 off | 1 on  | MXL5005S (?)
+	 * GPIO2 | LED     | 0 off | 1 on  |
+	 * GPIO4 | tuner#1 | 0 on  | 1 off | MT2060
+	 */
+
+	/* GPIO direction */
+	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
+	if (ret)
+		goto err;
+
+	/* enable as output GPIO0, GPIO2, GPIO4 */
+	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
+	if (ret)
+		goto err;
+
+	/*
+	 * Probe used tuner. We need to know used tuner before demod attach
+	 * since there is some demod params needed to set according to tuner.
+	 */
+
+	/* open demod I2C gate */
+	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
+	if (ret)
+		goto err;
+
+	/* check QT1010 ID(?) register; reg=0f val=2c */
+	ret = rtl28xxu_ctrl_msg(adap->dev, &req_qt1010);
+	if (ret == 0 && buf[0] == 0x2c) {
+		priv->tuner = TUNER_RTL2830_QT1010;
+		rtl2830_config = &rtl28xxu_rtl2830_qt1010_config;
+		deb_info("%s: QT1010\n", __func__);
+		goto found;
+	} else {
+		deb_info("%s: QT1010 probe failed=%d - %02x\n",
+			__func__, ret, buf[0]);
+	}
+
+	/* open demod I2C gate */
+	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
+	if (ret)
+		goto err;
+
+	/* check MT2060 ID register; reg=00 val=63 */
+	ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2060);
+	if (ret == 0 && buf[0] == 0x63) {
+		priv->tuner = TUNER_RTL2830_MT2060;
+		rtl2830_config = &rtl28xxu_rtl2830_mt2060_config;
+		deb_info("%s: MT2060\n", __func__);
+		goto found;
+	} else {
+		deb_info("%s: MT2060 probe failed=%d - %02x\n",
+			__func__, ret, buf[0]);
+	}
+
+	/* assume MXL5005S */
+	ret = 0;
+	priv->tuner = TUNER_RTL2830_MXL5005S;
+	rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config;
+	deb_info("%s: MXL5005S\n", __func__);
+	goto found;
+
+found:
+	/* attach demodulator */
+	adap->fe_adap[0].fe = dvb_attach(rtl2830_attach, rtl2830_config,
+		&adap->dev->i2c_adap);
+	if (adap->fe_adap[0].fe == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	return ret;
+err:
+	deb_info("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	struct rtl28xxu_priv *priv = adap->dev->priv;
+	u8 buf[1];
+	/* open RTL2832U/RTL2832 I2C gate */
+	struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"};
+	/* close RTL2832U/RTL2832 I2C gate */
+	struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"};
+	/* for FC2580 tuner probe */
+	struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
+
+	deb_info("%s:\n", __func__);
+
+	/* GPIO direction */
+	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
+	if (ret)
+		goto err;
+
+	/* enable as output GPIO0, GPIO2, GPIO4 */
+	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
+	if (ret)
+		goto err;
+
+	ret = rtl2831_wr_reg(adap->dev, SYS_DEMOD_CTL, 0xe8);
+	if (ret)
+		goto err;
+
+	/*
+	 * Probe used tuner. We need to know used tuner before demod attach
+	 * since there is some demod params needed to set according to tuner.
+	 */
+
+	/* open demod I2C gate */
+	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_open);
+	if (ret)
+		goto err;
+
+	/* check FC2580 ID register; reg=01 val=56 */
+	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc2580);
+	if (ret == 0 && buf[0] == 0x56) {
+		priv->tuner = TUNER_RTL2832_FC2580;
+		deb_info("%s: FC2580\n", __func__);
+		goto found;
+	} else {
+		deb_info("%s: FC2580 probe failed=%d - %02x\n",
+			__func__, ret, buf[0]);
+	}
+
+	/* close demod I2C gate */
+	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
+	if (ret)
+		goto err;
+
+	/* tuner not found */
+	ret = -ENODEV;
+	goto err;
+
+found:
+	/* close demod I2C gate */
+	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
+	if (ret)
+		goto err;
+
+	/* attach demodulator */
+	/* TODO: */
+
+	return ret;
+err:
+	deb_info("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static struct qt1010_config rtl28xxu_qt1010_config = {
+	.i2c_address = 0x62, /* 0xc4 */
+};
+
+static struct mt2060_config rtl28xxu_mt2060_config = {
+	.i2c_address = 0x60, /* 0xc0 */
+	.clock_out = 0,
+};
+
+static struct mxl5005s_config rtl28xxu_mxl5005s_config = {
+	.i2c_address     = 0x63, /* 0xc6 */
+	.if_freq         = IF_FREQ_4570000HZ,
+	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+	.agc_mode        = MXL_SINGLE_AGC,
+	.tracking_filter = MXL_TF_C_H,
+	.rssi_enable     = MXL_RSSI_ENABLE,
+	.cap_select      = MXL_CAP_SEL_ENABLE,
+	.div_out         = MXL_DIV_OUT_4,
+	.clock_out       = MXL_CLOCK_OUT_DISABLE,
+	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+	.top		 = MXL5005S_TOP_25P2,
+	.mod_mode        = MXL_DIGITAL_MODE,
+	.if_mode         = MXL_ZERO_IF,
+	.AgcMasterByte   = 0x00,
+};
+
+static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	struct rtl28xxu_priv *priv = adap->dev->priv;
+	struct i2c_adapter *rtl2830_tuner_i2c;
+	struct dvb_frontend *fe;
+
+	deb_info("%s:\n", __func__);
+
+	/* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */
+	rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe_adap[0].fe);
+
+	switch (priv->tuner) {
+	case TUNER_RTL2830_QT1010:
+		fe = dvb_attach(qt1010_attach, adap->fe_adap[0].fe,
+				rtl2830_tuner_i2c, &rtl28xxu_qt1010_config);
+		break;
+	case TUNER_RTL2830_MT2060:
+		fe = dvb_attach(mt2060_attach, adap->fe_adap[0].fe,
+				rtl2830_tuner_i2c, &rtl28xxu_mt2060_config,
+				1220);
+		break;
+	case TUNER_RTL2830_MXL5005S:
+		fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
+				rtl2830_tuner_i2c, &rtl28xxu_mxl5005s_config);
+		break;
+	default:
+		fe = NULL;
+		err("unknown tuner=%d", priv->tuner);
+	}
+
+	if (fe == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	return 0;
+err:
+	deb_info("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	struct rtl28xxu_priv *priv = adap->dev->priv;
+	struct dvb_frontend *fe;
+
+	deb_info("%s:\n", __func__);
+
+	switch (priv->tuner) {
+	case TUNER_RTL2832_FC2580:
+		/* TODO: */
+		fe = NULL;
+		break;
+	default:
+		fe = NULL;
+		err("unknown tuner=%d", priv->tuner);
+	}
+
+	if (fe == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	return 0;
+err:
+	deb_info("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
+{
+	int ret;
+	u8 buf[2], gpio;
+
+	deb_info("%s: onoff=%d\n", __func__, onoff);
+
+	ret = rtl2831_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio);
+	if (ret)
+		goto err;
+
+	if (onoff) {
+		buf[0] = 0x00;
+		buf[1] = 0x00;
+		gpio |= 0x04; /* LED on */
+	} else {
+		buf[0] = 0x10; /* stall EPA */
+		buf[1] = 0x02; /* reset EPA */
+		gpio &= (~0x04); /* LED off */
+	}
+
+	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_VAL, gpio);
+	if (ret)
+		goto err;
+
+	ret = rtl2831_wr_regs(adap->dev, USB_EPA_CTL, buf, 2);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	deb_info("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int ret;
+	u8 gpio, sys0;
+
+	deb_info("%s: onoff=%d\n", __func__, onoff);
+
+	/* demod adc */
+	ret = rtl2831_rd_reg(d, SYS_SYS0, &sys0);
+	if (ret)
+		goto err;
+
+	/* tuner power, read GPIOs */
+	ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio);
+	if (ret)
+		goto err;
+
+	deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
+
+	if (onoff) {
+		gpio |= 0x01; /* GPIO0 = 1 */
+		gpio &= (~0x10); /* GPIO4 = 0 */
+		sys0 = sys0 & 0x0f;
+		sys0 |= 0xe0;
+	} else {
+		gpio &= (~0x01); /* GPIO0 = 0 */
+		gpio |= 0x10; /* GPIO4 = 1 */
+		sys0 = sys0 & (~0xc0);
+	}
+
+	deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
+
+	/* demod adc */
+	ret = rtl2831_wr_reg(d, SYS_SYS0, sys0);
+	if (ret)
+		goto err;
+
+	/* tuner power, write GPIOs */
+	ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, gpio);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	deb_info("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int rtl2831u_rc_query(struct dvb_usb_device *d)
+{
+	int ret, i;
+	struct rtl28xxu_priv *priv = d->priv;
+	u8 buf[5];
+	u32 rc_code;
+	struct rtl28xxu_reg_val rc_nec_tab[] = {
+		{ 0x3033, 0x80 },
+		{ 0x3020, 0x43 },
+		{ 0x3021, 0x16 },
+		{ 0x3022, 0x16 },
+		{ 0x3023, 0x5a },
+		{ 0x3024, 0x2d },
+		{ 0x3025, 0x16 },
+		{ 0x3026, 0x01 },
+		{ 0x3028, 0xb0 },
+		{ 0x3029, 0x04 },
+		{ 0x302c, 0x88 },
+		{ 0x302e, 0x13 },
+		{ 0x3030, 0xdf },
+		{ 0x3031, 0x05 },
+	};
+
+	/* init remote controller */
+	if (!priv->rc_active) {
+		for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) {
+			ret = rtl2831_wr_reg(d, rc_nec_tab[i].reg,
+					rc_nec_tab[i].val);
+			if (ret)
+				goto err;
+		}
+		priv->rc_active = true;
+	}
+
+	ret = rtl2831_rd_regs(d, SYS_IRRC_RP, buf, 5);
+	if (ret)
+		goto err;
+
+	if (buf[4] & 0x01) {
+		if (buf[2] == (u8) ~buf[3]) {
+			if (buf[0] == (u8) ~buf[1]) {
+				/* NEC standard (16 bit) */
+				rc_code = buf[0] << 8 | buf[2];
+			} else {
+				/* NEC extended (24 bit) */
+				rc_code = buf[0] << 16 |
+						buf[1] << 8 | buf[2];
+			}
+		} else {
+			/* NEC full (32 bit) */
+			rc_code = buf[0] << 24 | buf[1] << 16 |
+					buf[2] << 8 | buf[3];
+		}
+
+		rc_keydown(d->rc_dev, rc_code, 0);
+
+		ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1);
+		if (ret)
+			goto err;
+
+		/* repeated intentionally to avoid extra keypress */
+		ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1);
+		if (ret)
+			goto err;
+	}
+
+	return ret;
+err:
+	deb_info("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static int rtl2832u_rc_query(struct dvb_usb_device *d)
+{
+	int ret, i;
+	struct rtl28xxu_priv *priv = d->priv;
+	u8 buf[128];
+	int len;
+	struct rtl28xxu_reg_val rc_nec_tab[] = {
+		{ IR_RX_CTRL,             0x20 },
+		{ IR_RX_BUF_CTRL,         0x80 },
+		{ IR_RX_IF,               0xff },
+		{ IR_RX_IE,               0xff },
+		{ IR_MAX_DURATION0,       0xd0 },
+		{ IR_MAX_DURATION1,       0x07 },
+		{ IR_IDLE_LEN0,           0xc0 },
+		{ IR_IDLE_LEN1,           0x00 },
+		{ IR_GLITCH_LEN,          0x03 },
+		{ IR_RX_CLK,              0x09 },
+		{ IR_RX_CFG,              0x1c },
+		{ IR_MAX_H_TOL_LEN,       0x1e },
+		{ IR_MAX_L_TOL_LEN,       0x1e },
+		{ IR_RX_CTRL,             0x80 },
+	};
+
+	/* init remote controller */
+	if (!priv->rc_active) {
+		for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) {
+			ret = rtl2831_wr_reg(d, rc_nec_tab[i].reg,
+					rc_nec_tab[i].val);
+			if (ret)
+				goto err;
+		}
+		priv->rc_active = true;
+	}
+
+	ret = rtl2831_rd_reg(d, IR_RX_IF, &buf[0]);
+	if (ret)
+		goto err;
+
+	if (buf[0] != 0x83)
+		goto exit;
+
+	ret = rtl2831_rd_reg(d, IR_RX_BC, &buf[0]);
+	if (ret)
+		goto err;
+
+	len = buf[0];
+	ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len);
+
+	/* TODO: pass raw IR to Kernel IR decoder */
+
+	ret = rtl2831_wr_reg(d, IR_RX_IF, 0x03);
+	ret = rtl2831_wr_reg(d, IR_RX_BUF_CTRL, 0x80);
+	ret = rtl2831_wr_reg(d, IR_RX_CTRL, 0x80);
+
+exit:
+	return ret;
+err:
+	deb_info("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+enum rtl28xxu_usb_table_entry {
+	RTL2831U_0BDA_2831,
+	RTL2831U_14AA_0160,
+	RTL2831U_14AA_0161,
+};
+
+static struct usb_device_id rtl28xxu_table[] = {
+	/* RTL2831U */
+	[RTL2831U_0BDA_2831] = {
+		USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U)},
+	[RTL2831U_14AA_0160] = {
+		USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT)},
+	[RTL2831U_14AA_0161] = {
+		USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2)},
+
+	/* RTL2832U */
+	{} /* terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, rtl28xxu_table);
+
+static struct dvb_usb_device_properties rtl28xxu_properties[] = {
+	{
+		.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+		.usb_ctrl = DEVICE_SPECIFIC,
+		.no_reconnect = 1,
+
+		.size_of_priv = sizeof(struct rtl28xxu_priv),
+
+		.num_adapters = 1,
+		.adapter = {
+			{
+				.num_frontends = 1,
+				.fe = {
+					{
+						.frontend_attach = rtl2831u_frontend_attach,
+						.tuner_attach    = rtl2831u_tuner_attach,
+						.streaming_ctrl  = rtl28xxu_streaming_ctrl,
+						.stream = {
+							.type = USB_BULK,
+							.count = 6,
+							.endpoint = 0x81,
+							.u = {
+								.bulk = {
+									.buffersize = 8*512,
+								}
+							}
+						}
+					}
+				}
+			}
+		},
+
+		.power_ctrl = rtl28xxu_power_ctrl,
+
+		.rc.core = {
+			.protocol       = RC_TYPE_NEC,
+			.module_name    = "rtl28xxu",
+			.rc_query       = rtl2831u_rc_query,
+			.rc_interval    = 400,
+			.allowed_protos = RC_TYPE_NEC,
+			.rc_codes       = RC_MAP_EMPTY,
+		},
+
+		.i2c_algo = &rtl28xxu_i2c_algo,
+
+		.num_device_descs = 2,
+		.devices = {
+			{
+				.name = "Realtek RTL2831U reference design",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2831U_0BDA_2831],
+				},
+			},
+			{
+				.name = "Freecom USB2.0 DVB-T",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2831U_14AA_0160],
+					&rtl28xxu_table[RTL2831U_14AA_0161],
+				},
+			},
+		}
+	},
+	{
+		.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+		.usb_ctrl = DEVICE_SPECIFIC,
+		.no_reconnect = 1,
+
+		.size_of_priv = sizeof(struct rtl28xxu_priv),
+
+		.num_adapters = 1,
+		.adapter = {
+			{
+				.num_frontends = 1,
+				.fe = {
+					{
+						.frontend_attach = rtl2832u_frontend_attach,
+						.tuner_attach    = rtl2832u_tuner_attach,
+						.streaming_ctrl  = rtl28xxu_streaming_ctrl,
+						.stream = {
+							.type = USB_BULK,
+							.count = 6,
+							.endpoint = 0x81,
+							.u = {
+								.bulk = {
+									.buffersize = 8*512,
+								}
+							}
+						}
+					}
+				}
+			}
+		},
+
+		.power_ctrl = rtl28xxu_power_ctrl,
+
+		.rc.core = {
+			.protocol       = RC_TYPE_NEC,
+			.module_name    = "rtl28xxu",
+			.rc_query       = rtl2832u_rc_query,
+			.rc_interval    = 400,
+			.allowed_protos = RC_TYPE_NEC,
+			.rc_codes       = RC_MAP_EMPTY,
+		},
+
+		.i2c_algo = &rtl28xxu_i2c_algo,
+
+		.num_device_descs = 0, /* disabled as no support for RTL2832 */
+		.devices = {
+			{
+				.name = "Realtek RTL2832U reference design",
+			},
+		}
+	},
+
+};
+
+static int rtl28xxu_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	int ret, i;
+	int properties_count = ARRAY_SIZE(rtl28xxu_properties);
+	struct dvb_usb_device *d;
+
+	deb_info("%s: interface=%d\n", __func__,
+		intf->cur_altsetting->desc.bInterfaceNumber);
+
+	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+		return 0;
+
+	for (i = 0; i < properties_count; i++) {
+		ret = dvb_usb_device_init(intf, &rtl28xxu_properties[i],
+				THIS_MODULE, &d, adapter_nr);
+		if (ret == 0 || ret != -ENODEV)
+			break;
+	}
+
+	if (ret)
+		goto err;
+
+	/* init USB endpoints */
+	ret = rtl2831_wr_reg(d, USB_SYSCTL_0, 0x09);
+	if (ret)
+		goto err;
+
+	ret = rtl2831_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
+	if (ret)
+		goto err;
+
+	ret = rtl2831_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	deb_info("%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static struct usb_driver rtl28xxu_driver = {
+	.name       = "dvb_usb_rtl28xxu",
+	.probe      = rtl28xxu_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table   = rtl28xxu_table,
+};
+
+/* module stuff */
+static int __init rtl28xxu_module_init(void)
+{
+	int ret;
+
+	deb_info("%s:\n", __func__);
+
+	ret = usb_register(&rtl28xxu_driver);
+	if (ret)
+		err("usb_register failed=%d", ret);
+
+	return ret;
+}
+
+static void __exit rtl28xxu_module_exit(void)
+{
+	deb_info("%s:\n", __func__);
+
+	/* deregister this driver from the USB subsystem */
+	usb_deregister(&rtl28xxu_driver);
+}
+
+module_init(rtl28xxu_module_init);
+module_exit(rtl28xxu_module_exit);
+
+MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.h b/drivers/media/dvb/dvb-usb/rtl28xxu.h
new file mode 100644
index 0000000..90f3bb4
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.h
@@ -0,0 +1,264 @@
+/*
+ * Realtek RTL28xxU DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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 RTL28XXU_H
+#define RTL28XXU_H
+
+#define DVB_USB_LOG_PREFIX "rtl28xxu"
+#include "dvb-usb.h"
+
+#define deb_info(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x01, args)
+#define deb_rc(args...)   dprintk(dvb_usb_rtl28xxu_debug, 0x02, args)
+#define deb_xfer(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x04, args)
+#define deb_reg(args...)  dprintk(dvb_usb_rtl28xxu_debug, 0x08, args)
+#define deb_i2c(args...)  dprintk(dvb_usb_rtl28xxu_debug, 0x10, args)
+#define deb_fw(args...)   dprintk(dvb_usb_rtl28xxu_debug, 0x20, args)
+
+#define deb_dump(r, t, v, i, b, l, func) { \
+	int loop_; \
+	func("%02x %02x %02x %02x %02x %02x %02x %02x", \
+		t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \
+	if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
+		func(" >>> "); \
+	else \
+		func(" <<< "); \
+	for (loop_ = 0; loop_ < l; loop_++) \
+		func("%02x ", b[loop_]); \
+	func("\n");\
+}
+
+/*
+ * USB commands
+ * (usb_control_msg() index parameter)
+ */
+
+#define DEMOD            0x0000
+#define USB              0x0100
+#define SYS              0x0200
+#define I2C              0x0300
+#define I2C_DA           0x0600
+
+#define CMD_WR_FLAG      0x0010
+#define CMD_DEMOD_RD     0x0000
+#define CMD_DEMOD_WR     0x0010
+#define CMD_USB_RD       0x0100
+#define CMD_USB_WR       0x0110
+#define CMD_SYS_RD       0x0200
+#define CMD_IR_RD        0x0201
+#define CMD_IR_WR        0x0211
+#define CMD_SYS_WR       0x0210
+#define CMD_I2C_RD       0x0300
+#define CMD_I2C_WR       0x0310
+#define CMD_I2C_DA_RD    0x0600
+#define CMD_I2C_DA_WR    0x0610
+
+
+struct rtl28xxu_priv {
+	u8 chip_id;
+	u8 tuner;
+	u8 page; /* integrated demod active register page */
+	bool rc_active;
+};
+
+enum rtl28xxu_chip_id {
+	CHIP_ID_NONE,
+	CHIP_ID_RTL2831U,
+	CHIP_ID_RTL2832U,
+};
+
+enum rtl28xxu_tuner {
+	TUNER_NONE,
+
+	TUNER_RTL2830_QT1010,
+	TUNER_RTL2830_MT2060,
+	TUNER_RTL2830_MXL5005S,
+
+	TUNER_RTL2832_MT2266,
+	TUNER_RTL2832_FC2580,
+	TUNER_RTL2832_MT2063,
+	TUNER_RTL2832_MAX3543,
+	TUNER_RTL2832_TUA9001,
+	TUNER_RTL2832_MXL5007T,
+	TUNER_RTL2832_FC0012,
+	TUNER_RTL2832_E4000,
+	TUNER_RTL2832_TDA18272,
+	TUNER_RTL2832_FC0013,
+};
+
+struct rtl28xxu_req {
+	u16 value;
+	u16 index;
+	u16 size;
+	u8 *data;
+};
+
+struct rtl28xxu_reg_val {
+	u16 reg;
+	u8 val;
+};
+
+/*
+ * memory map
+ *
+ * 0x0000 DEMOD : demodulator
+ * 0x2000 USB   : SIE, USB endpoint, debug, DMA
+ * 0x3000 SYS   : system
+ * 0xfc00 RC    : remote controller (not RTL2831U)
+ */
+
+/*
+ * USB registers
+ */
+/* SIE Control Registers */
+#define USB_SYSCTL         0x2000 /* USB system control */
+#define USB_SYSCTL_0       0x2000 /* USB system control */
+#define USB_SYSCTL_1       0x2001 /* USB system control */
+#define USB_SYSCTL_2       0x2002 /* USB system control */
+#define USB_SYSCTL_3       0x2003 /* USB system control */
+#define USB_IRQSTAT        0x2008 /* SIE interrupt status */
+#define USB_IRQEN          0x200C /* SIE interrupt enable */
+#define USB_CTRL           0x2010 /* USB control */
+#define USB_STAT           0x2014 /* USB status */
+#define USB_DEVADDR        0x2018 /* USB device address */
+#define USB_TEST           0x201C /* USB test mode */
+#define USB_FRAME_NUMBER   0x2020 /* frame number */
+#define USB_FIFO_ADDR      0x2028 /* address of SIE FIFO RAM */
+#define USB_FIFO_CMD       0x202A /* SIE FIFO RAM access command */
+#define USB_FIFO_DATA      0x2030 /* SIE FIFO RAM data */
+/* Endpoint Registers */
+#define EP0_SETUPA         0x20F8 /* EP 0 setup packet lower byte */
+#define EP0_SETUPB         0x20FC /* EP 0 setup packet higher byte */
+#define USB_EP0_CFG        0x2104 /* EP 0 configure */
+#define USB_EP0_CTL        0x2108 /* EP 0 control */
+#define USB_EP0_STAT       0x210C /* EP 0 status */
+#define USB_EP0_IRQSTAT    0x2110 /* EP 0 interrupt status */
+#define USB_EP0_IRQEN      0x2114 /* EP 0 interrupt enable */
+#define USB_EP0_MAXPKT     0x2118 /* EP 0 max packet size */
+#define USB_EP0_BC         0x2120 /* EP 0 FIFO byte counter */
+#define USB_EPA_CFG        0x2144 /* EP A configure */
+#define USB_EPA_CFG_0      0x2144 /* EP A configure */
+#define USB_EPA_CFG_1      0x2145 /* EP A configure */
+#define USB_EPA_CFG_2      0x2146 /* EP A configure */
+#define USB_EPA_CFG_3      0x2147 /* EP A configure */
+#define USB_EPA_CTL        0x2148 /* EP A control */
+#define USB_EPA_CTL_0      0x2148 /* EP A control */
+#define USB_EPA_CTL_1      0x2149 /* EP A control */
+#define USB_EPA_CTL_2      0x214A /* EP A control */
+#define USB_EPA_CTL_3      0x214B /* EP A control */
+#define USB_EPA_STAT       0x214C /* EP A status */
+#define USB_EPA_IRQSTAT    0x2150 /* EP A interrupt status */
+#define USB_EPA_IRQEN      0x2154 /* EP A interrupt enable */
+#define USB_EPA_MAXPKT     0x2158 /* EP A max packet size */
+#define USB_EPA_MAXPKT_0   0x2158 /* EP A max packet size */
+#define USB_EPA_MAXPKT_1   0x2159 /* EP A max packet size */
+#define USB_EPA_MAXPKT_2   0x215A /* EP A max packet size */
+#define USB_EPA_MAXPKT_3   0x215B /* EP A max packet size */
+#define USB_EPA_FIFO_CFG   0x2160 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_0 0x2160 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_1 0x2161 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_2 0x2162 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_3 0x2163 /* EP A FIFO configure */
+/* Debug Registers */
+#define USB_PHYTSTDIS      0x2F04 /* PHY test disable */
+#define USB_TOUT_VAL       0x2F08 /* USB time-out time */
+#define USB_VDRCTRL        0x2F10 /* UTMI vendor signal control */
+#define USB_VSTAIN         0x2F14 /* UTMI vendor signal status in */
+#define USB_VLOADM         0x2F18 /* UTMI load vendor signal status in */
+#define USB_VSTAOUT        0x2F1C /* UTMI vendor signal status out */
+#define USB_UTMI_TST       0x2F80 /* UTMI test */
+#define USB_UTMI_STATUS    0x2F84 /* UTMI status */
+#define USB_TSTCTL         0x2F88 /* test control */
+#define USB_TSTCTL2        0x2F8C /* test control 2 */
+#define USB_PID_FORCE      0x2F90 /* force PID */
+#define USB_PKTERR_CNT     0x2F94 /* packet error counter */
+#define USB_RXERR_CNT      0x2F98 /* RX error counter */
+#define USB_MEM_BIST       0x2F9C /* MEM BIST test */
+#define USB_SLBBIST        0x2FA0 /* self-loop-back BIST */
+#define USB_CNTTEST        0x2FA4 /* counter test */
+#define USB_PHYTST         0x2FC0 /* USB PHY test */
+#define USB_DBGIDX         0x2FF0 /* select individual block debug signal */
+#define USB_DBGMUX         0x2FF4 /* debug signal module mux */
+
+/*
+ * SYS registers
+ */
+/* demod control registers */
+#define SYS_SYS0           0x3000 /* include DEMOD_CTL, GPO, GPI, GPOE */
+#define SYS_DEMOD_CTL      0x3000 /* control register for DVB-T demodulator */
+/* GPIO registers */
+#define SYS_GPIO_OUT_VAL   0x3001 /* output value of GPIO */
+#define SYS_GPIO_IN_VAL    0x3002 /* input value of GPIO */
+#define SYS_GPIO_OUT_EN    0x3003 /* output enable of GPIO */
+#define SYS_SYS1           0x3004 /* include GPD, SYSINTE, SYSINTS, GP_CFG0 */
+#define SYS_GPIO_DIR       0x3004 /* direction control for GPIO */
+#define SYS_SYSINTE        0x3005 /* system interrupt enable */
+#define SYS_SYSINTS        0x3006 /* system interrupt status */
+#define SYS_GPIO_CFG0      0x3007 /* PAD configuration for GPIO0-GPIO3 */
+#define SYS_SYS2           0x3008 /* include GP_CFG1 and 3 reserved bytes */
+#define SYS_GPIO_CFG1      0x3008 /* PAD configuration for GPIO4 */
+#define SYS_DEMOD_CTL1     0x300B
+
+/* IrDA registers */
+#define SYS_IRRC_PSR       0x3020 /* IR protocol selection */
+#define SYS_IRRC_PER       0x3024 /* IR protocol extension */
+#define SYS_IRRC_SF        0x3028 /* IR sampling frequency */
+#define SYS_IRRC_DPIR      0x302C /* IR data package interval */
+#define SYS_IRRC_CR        0x3030 /* IR control */
+#define SYS_IRRC_RP        0x3034 /* IR read port */
+#define SYS_IRRC_SR        0x3038 /* IR status */
+/* I2C master registers */
+#define SYS_I2CCR          0x3040 /* I2C clock */
+#define SYS_I2CMCR         0x3044 /* I2C master control */
+#define SYS_I2CMSTR        0x3048 /* I2C master SCL timing */
+#define SYS_I2CMSR         0x304C /* I2C master status */
+#define SYS_I2CMFR         0x3050 /* I2C master FIFO */
+
+/*
+ * IR registers
+ */
+#define IR_RX_BUF          0xFC00
+#define IR_RX_IE           0xFD00
+#define IR_RX_IF           0xFD01
+#define IR_RX_CTRL         0xFD02
+#define IR_RX_CFG          0xFD03
+#define IR_MAX_DURATION0   0xFD04
+#define IR_MAX_DURATION1   0xFD05
+#define IR_IDLE_LEN0       0xFD06
+#define IR_IDLE_LEN1       0xFD07
+#define IR_GLITCH_LEN      0xFD08
+#define IR_RX_BUF_CTRL     0xFD09
+#define IR_RX_BUF_DATA     0xFD0A
+#define IR_RX_BC           0xFD0B
+#define IR_RX_CLK          0xFD0C
+#define IR_RX_C_COUNT_L    0xFD0D
+#define IR_RX_C_COUNT_H    0xFD0E
+#define IR_SUSPEND_CTRL    0xFD10
+#define IR_ERR_TOL_CTRL    0xFD11
+#define IR_UNIT_LEN        0xFD12
+#define IR_ERR_TOL_LEN     0xFD13
+#define IR_MAX_H_TOL_LEN   0xFD14
+#define IR_MAX_L_TOL_LEN   0xFD15
+#define IR_MASK_CTRL       0xFD16
+#define IR_MASK_DATA       0xFD17
+#define IR_RES_MASK_ADDR   0xFD18
+#define IR_RES_MASK_T_LEN  0xFD19
+
+#endif
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c
index 864b627..e24ec53 100644
--- a/drivers/media/dvb/firewire/firedtv-fw.c
+++ b/drivers/media/dvb/firewire/firedtv-fw.c
@@ -20,7 +20,6 @@
 #include <linux/workqueue.h>
 
 #include <asm/page.h>
-#include <asm/system.h>
 
 #include <dvb_demux.h>
 
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index ebb5ed7..2124670 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -425,6 +425,13 @@
 	help
 	  Say Y when you want to support this frontend.
 
+config DVB_RTL2830
+	tristate "Realtek RTL2830 DVB-T"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  Say Y when you want to support this frontend.
+
 comment "DVB-C (cable) frontends"
 	depends on DVB_CORE
 
@@ -698,6 +705,14 @@
 	  A DVB-T tuner module.
 	  Say Y when you want to support this frontend.
 
+config DVB_M88RS2000
+	tristate "M88RS2000 DVB-S demodulator and tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module.
+	  Say Y when you want to support this frontend.
+
 comment "Tools to develop new frontends"
 
 config DVB_DUMMY_FE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 00a2063..86fa808 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -2,8 +2,8 @@
 # Makefile for the kernel DVB frontend device drivers.
 #
 
-ccflags-y += -Idrivers/media/dvb/dvb-core/
-ccflags-y += -Idrivers/media/common/tuners/
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core/
+ccflags-y += -I$(srctree)/drivers/media/common/tuners/
 
 stb0899-objs = stb0899_drv.o stb0899_algo.o
 stv0900-objs = stv0900_core.o stv0900_sw.o
@@ -96,4 +96,6 @@
 obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o
 obj-$(CONFIG_DVB_A8293) += a8293.o
 obj-$(CONFIG_DVB_TDA10071) += tda10071.o
+obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
+obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
 
diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c
index 2b248c1..55b6390 100644
--- a/drivers/media/dvb/frontends/au8522_decoder.c
+++ b/drivers/media/dvb/frontends/au8522_decoder.c
@@ -839,15 +839,4 @@
 	.id_table	= au8522_id,
 };
 
-static __init int init_au8522(void)
-{
-	return i2c_add_driver(&au8522_driver);
-}
-
-static __exit void exit_au8522(void)
-{
-	i2c_del_driver(&au8522_driver);
-}
-
-module_init(init_au8522);
-module_exit(exit_au8522);
+module_i2c_driver(au8522_driver);
diff --git a/drivers/media/dvb/frontends/au8522_dig.c b/drivers/media/dvb/frontends/au8522_dig.c
index c688b95d..25f6509 100644
--- a/drivers/media/dvb/frontends/au8522_dig.c
+++ b/drivers/media/dvb/frontends/au8522_dig.c
@@ -588,11 +588,6 @@
 	    (state->current_modulation == c->modulation))
 		return 0;
 
-	au8522_enable_modulation(fe, c->modulation);
-
-	/* Allow the demod to settle */
-	msleep(100);
-
 	if (fe->ops.tuner_ops.set_params) {
 		if (fe->ops.i2c_gate_ctrl)
 			fe->ops.i2c_gate_ctrl(fe, 1);
@@ -604,6 +599,11 @@
 	if (ret < 0)
 		return ret;
 
+	/* Allow the tuner to settle */
+	msleep(100);
+
+	au8522_enable_modulation(fe, c->modulation);
+
 	state->current_frequency = c->frequency;
 
 	return 0;
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index faba824..edc8eaf 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -502,10 +502,26 @@
 	u16 *signal_strength)
 {
 	struct cx22702_state *state = fe->demodulator_priv;
+	u8 reg23;
 
-	u16 rs_ber;
-	rs_ber = cx22702_readreg(state, 0x23);
-	*signal_strength = (rs_ber << 8) | rs_ber;
+	/*
+	 * Experience suggests that the strength signal register works as
+	 * follows:
+	 * - In the absence of signal, value is 0xff.
+	 * - In the presence of a weak signal, bit 7 is set, not sure what
+	 *   the lower 7 bits mean.
+	 * - In the presence of a strong signal, the register holds a 7-bit
+	 *   value (bit 7 is cleared), with greater values standing for
+	 *   weaker signals.
+	 */
+	reg23 = cx22702_readreg(state, 0x23);
+	if (reg23 & 0x80) {
+		*signal_strength = 0;
+	} else {
+		reg23 = ~reg23 & 0x7f;
+		/* Scale to 16 bit */
+		*signal_strength = (reg23 << 9) | (reg23 << 2) | (reg23 >> 5);
+	}
 
 	return 0;
 }
diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c
index 224d81e..d9fe60b 100644
--- a/drivers/media/dvb/frontends/dib0090.c
+++ b/drivers/media/dvb/frontends/dib0090.c
@@ -519,7 +519,7 @@
 	return 0;
 
 identification_error:
-	return -EIO;;
+	return -EIO;
 }
 
 static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c
index 863ef3c..80848b4 100644
--- a/drivers/media/dvb/frontends/dib9000.c
+++ b/drivers/media/dvb/frontends/dib9000.c
@@ -33,7 +33,7 @@
 
 /* lock */
 #define DIB_LOCK struct mutex
-#define DibAcquireLock(lock) do { if (mutex_lock_interruptible(lock) < 0) dprintk("could not get the lock"); } while (0)
+#define DibAcquireLock(lock) mutex_lock_interruptible(lock)
 #define DibReleaseLock(lock) mutex_unlock(lock)
 #define DibInitLock(lock) mutex_init(lock)
 #define DibFreeLock(lock)
@@ -446,7 +446,10 @@
 	if (!state->platform.risc.fw_is_running)
 		return -EIO;
 
-	DibAcquireLock(&state->platform.risc.mem_lock);
+	if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
 	dib9000_risc_mem_setup(state, cmd | 0x80);
 	dib9000_risc_mem_read_chunks(state, b, len);
 	DibReleaseLock(&state->platform.risc.mem_lock);
@@ -459,7 +462,10 @@
 	if (!state->platform.risc.fw_is_running)
 		return -EIO;
 
-	DibAcquireLock(&state->platform.risc.mem_lock);
+	if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
 	dib9000_risc_mem_setup(state, cmd);
 	dib9000_risc_mem_write_chunks(state, b, m->size);
 	DibReleaseLock(&state->platform.risc.mem_lock);
@@ -531,7 +537,10 @@
 	if (!state->platform.risc.fw_is_running)
 		return -EINVAL;
 
-	DibAcquireLock(&state->platform.risc.mbx_if_lock);
+	if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
 	tmp = MAX_MAILBOX_TRY;
 	do {
 		size = dib9000_read_word_attr(state, 1043, attr) & 0xff;
@@ -593,7 +602,10 @@
 	if (!state->platform.risc.fw_is_running)
 		return 0;
 
-	DibAcquireLock(&state->platform.risc.mbx_if_lock);
+	if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) {
+		dprintk("could not get the lock");
+		return 0;
+	}
 	if (risc_id == 1)
 		mc_base = 16;
 	else
@@ -701,7 +713,10 @@
 	if (!state->platform.risc.fw_is_running)
 		return -1;
 
-	DibAcquireLock(&state->platform.risc.mbx_lock);
+	if (DibAcquireLock(&state->platform.risc.mbx_lock) < 0) {
+		dprintk("could not get the lock");
+		return -1;
+	}
 
 	if (dib9000_mbx_count(state, 1, attr))	/* 1=RiscB */
 		ret = dib9000_mbx_fetch_to_cache(state, attr);
@@ -1178,7 +1193,10 @@
 	struct dibDVBTChannel *ch;
 	int ret = 0;
 
-	DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+	if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
 	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
 		ret = -EIO;
 		goto error;
@@ -1660,7 +1678,10 @@
 		p[12] = 0;
 	}
 
-	DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+	if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+		dprintk("could not get the lock");
+		return 0;
+	}
 
 	dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p);
 
@@ -1768,7 +1789,10 @@
 		return 0;
 	}
 
-	DibAcquireLock(&state->demod_lock);
+	if (DibAcquireLock(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
 
 	val = dib9000_read_word(state, 294 + 1) & 0xffef;
 	val |= (onoff & 0x1) << 4;
@@ -1800,7 +1824,10 @@
 		return 0;
 	}
 
-	DibAcquireLock(&state->demod_lock);
+	if (DibAcquireLock(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
 	dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
 	ret = dib9000_write_word(state, 300 + 1 + id,
 			onoff ? (1 << 13) | pid : 0);
@@ -1848,7 +1875,10 @@
 	u8 index_frontend;
 	int ret = 0;
 
-	DibAcquireLock(&state->demod_lock);
+	if (DibAcquireLock(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
 		ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
 		if (ret < 0)
@@ -1874,8 +1904,12 @@
 	fe_status_t stat;
 	int ret = 0;
 
-	if (state->get_frontend_internal == 0)
-		DibAcquireLock(&state->demod_lock);
+	if (state->get_frontend_internal == 0) {
+		if (DibAcquireLock(&state->demod_lock) < 0) {
+			dprintk("could not get the lock");
+			return -EINTR;
+		}
+	}
 
 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
 		state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
@@ -1978,7 +2012,10 @@
 	}
 
 	state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */
-	DibAcquireLock(&state->demod_lock);
+	if (DibAcquireLock(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return 0;
+	}
 
 	fe->dtv_property_cache.delivery_system = SYS_DVBT;
 
@@ -2138,7 +2175,10 @@
 	u8 index_frontend;
 	u16 lock = 0, lock_slave = 0;
 
-	DibAcquireLock(&state->demod_lock);
+	if (DibAcquireLock(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
 		lock_slave |= dib9000_read_lock(state->fe[index_frontend]);
 
@@ -2168,8 +2208,15 @@
 	u16 *c;
 	int ret = 0;
 
-	DibAcquireLock(&state->demod_lock);
-	DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+	if (DibAcquireLock(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
+	if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+		dprintk("could not get the lock");
+		ret = -EINTR;
+		goto error;
+	}
 	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
 		DibReleaseLock(&state->platform.risc.mem_mbx_lock);
 		ret = -EIO;
@@ -2196,7 +2243,10 @@
 	u16 val;
 	int ret = 0;
 
-	DibAcquireLock(&state->demod_lock);
+	if (DibAcquireLock(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
 	*strength = 0;
 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
 		state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
@@ -2206,8 +2256,13 @@
 			*strength += val;
 	}
 
-	DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+	if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+		dprintk("could not get the lock");
+		ret = -EINTR;
+		goto error;
+	}
 	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+		DibReleaseLock(&state->platform.risc.mem_mbx_lock);
 		ret = -EIO;
 		goto error;
 	}
@@ -2232,9 +2287,14 @@
 	u32 n, s, exp;
 	u16 val;
 
-	DibAcquireLock(&state->platform.risc.mem_mbx_lock);
-	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
-		return -EIO;
+	if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+		dprintk("could not get the lock");
+		return 0;
+	}
+	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+		DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+		return 0;
+	}
 	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
 	DibReleaseLock(&state->platform.risc.mem_mbx_lock);
 
@@ -2266,7 +2326,10 @@
 	u8 index_frontend;
 	u32 snr_master;
 
-	DibAcquireLock(&state->demod_lock);
+	if (DibAcquireLock(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
 	snr_master = dib9000_get_snr(fe);
 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
 		snr_master += dib9000_get_snr(state->fe[index_frontend]);
@@ -2288,9 +2351,17 @@
 	u16 *c = (u16 *)state->i2c_read_buffer;
 	int ret = 0;
 
-	DibAcquireLock(&state->demod_lock);
-	DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+	if (DibAcquireLock(&state->demod_lock) < 0) {
+		dprintk("could not get the lock");
+		return -EINTR;
+	}
+	if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+		dprintk("could not get the lock");
+		ret = -EINTR;
+		goto error;
+	}
 	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+		DibReleaseLock(&state->platform.risc.mem_mbx_lock);
 		ret = -EIO;
 		goto error;
 	}
diff --git a/drivers/media/dvb/frontends/drxd_hard.c b/drivers/media/dvb/frontends/drxd_hard.c
index 7bf39cd..f380eb4 100644
--- a/drivers/media/dvb/frontends/drxd_hard.c
+++ b/drivers/media/dvb/frontends/drxd_hard.c
@@ -101,9 +101,9 @@
 
 struct SNoiseCal {
 	int cpOpt;
-	u16 cpNexpOfs;
-	u16 tdCal2k;
-	u16 tdCal8k;
+	short cpNexpOfs;
+	short tdCal2k;
+	short tdCal8k;
 };
 
 enum app_env {
diff --git a/drivers/media/dvb/frontends/drxk.h b/drivers/media/dvb/frontends/drxk.h
index 0209818..9d64e4f 100644
--- a/drivers/media/dvb/frontends/drxk.h
+++ b/drivers/media/dvb/frontends/drxk.h
@@ -7,15 +7,19 @@
 /**
  * struct drxk_config - Configure the initial parameters for DRX-K
  *
- * adr:			I2C Address of the DRX-K
- * parallel_ts:		true means that the device uses parallel TS,
+ * @adr:		I2C Address of the DRX-K
+ * @parallel_ts:	True means that the device uses parallel TS,
  * 			Serial otherwise.
- * single_master:	Device is on the single master mode
- * no_i2c_bridge:	Don't switch the I2C bridge to talk with tuner
- * antenna_gpio:	GPIO bit used to control the antenna
- * antenna_dvbt:	GPIO bit for changing antenna to DVB-C. A value of 1
+ * @dynamic_clk:	True means that the clock will be dynamically
+ *			adjusted. Static clock otherwise.
+ * @enable_merr_cfg:	Enable SIO_PDR_PERR_CFG/SIO_PDR_MVAL_CFG.
+ * @single_master:	Device is on the single master mode
+ * @no_i2c_bridge:	Don't switch the I2C bridge to talk with tuner
+ * @antenna_gpio:	GPIO bit used to control the antenna
+ * @antenna_dvbt:	GPIO bit for changing antenna to DVB-C. A value of 1
  *			means that 1=DVBC, 0 = DVBT. Zero means the opposite.
- * microcode_name:	Name of the firmware file with the microcode
+ * @mpeg_out_clk_strength: DRXK Mpeg output clock drive strength.
+ * @microcode_name:	Name of the firmware file with the microcode
  *
  * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is
  * UIO-3.
@@ -25,11 +29,14 @@
 	bool	single_master;
 	bool	no_i2c_bridge;
 	bool	parallel_ts;
+	bool	dynamic_clk;
+	bool	enable_merr_cfg;
 
 	bool	antenna_dvbt;
 	u16	antenna_gpio;
 
-	int    chunk_size;
+	u8	mpeg_out_clk_strength;
+	int	chunk_size;
 
 	const char *microcode_name;
 };
diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c
index 5ab5379..36d1175 100644
--- a/drivers/media/dvb/frontends/drxk_hard.c
+++ b/drivers/media/dvb/frontends/drxk_hard.c
@@ -90,10 +90,6 @@
 #define DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH (0x03)
 #endif
 
-#ifndef DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH
-#define DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH (0x06)
-#endif
-
 #define DEFAULT_DRXK_MPEG_LOCK_TIMEOUT 700
 #define DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT 500
 
@@ -649,9 +645,6 @@
 	u32 ulQual83 = DEFAULT_MER_83;
 	u32 ulQual93 = DEFAULT_MER_93;
 
-	u32 ulDVBTStaticTSClock = 1;
-	u32 ulDVBCStaticTSClock = 1;
-
 	u32 ulMpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
 	u32 ulDemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
 
@@ -661,7 +654,6 @@
 	u32 ulGPIOCfg = 0x0113;
 	u32 ulInvertTSClock = 0;
 	u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH;
-	u32 ulTSClockkStrength = DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH;
 	u32 ulDVBTBitrate = 50000000;
 	u32 ulDVBCBitrate = DRXK_QAM_SYMBOLRATE_MAX * 8;
 
@@ -814,8 +806,7 @@
 	state->m_invertSTR = false;	/* If TRUE; invert STR signals */
 	state->m_invertVAL = false;	/* If TRUE; invert VAL signals */
 	state->m_invertCLK = (ulInvertTSClock != 0);	/* If TRUE; invert CLK signals */
-	state->m_DVBTStaticCLK = (ulDVBTStaticTSClock != 0);
-	state->m_DVBCStaticCLK = (ulDVBCStaticTSClock != 0);
+
 	/* If TRUE; static MPEG clockrate will be used;
 	   otherwise clockrate will adapt to the bitrate of the TS */
 
@@ -823,7 +814,6 @@
 	state->m_DVBCBitrate = ulDVBCBitrate;
 
 	state->m_TSDataStrength = (ulTSDataStrength & 0x07);
-	state->m_TSClockkStrength = (ulTSClockkStrength & 0x07);
 
 	/* Maximum bitrate in b/s in case static clockrate is selected */
 	state->m_mpegTsStaticBitrate = 19392658;
@@ -1188,6 +1178,7 @@
 	int status = -1;
 	u16 sioPdrMclkCfg = 0;
 	u16 sioPdrMdxCfg = 0;
+	u16 err_cfg = 0;
 
 	dprintk(1, ": mpeg %s, %s mode\n",
 		mpegEnable ? "enable" : "disable",
@@ -1253,12 +1244,17 @@
 		status = write16(state, SIO_PDR_MSTRT_CFG__A, sioPdrMdxCfg);
 		if (status < 0)
 			goto error;
-		status = write16(state, SIO_PDR_MERR_CFG__A, 0x0000);	/* Disable */
+
+		if (state->enable_merr_cfg)
+			err_cfg = sioPdrMdxCfg;
+
+		status = write16(state, SIO_PDR_MERR_CFG__A, err_cfg);
 		if (status < 0)
 			goto error;
-		status = write16(state, SIO_PDR_MVAL_CFG__A, 0x0000);	/* Disable */
+		status = write16(state, SIO_PDR_MVAL_CFG__A, err_cfg);
 		if (status < 0)
 			goto error;
+
 		if (state->m_enableParallel == true) {
 			/* paralel -> enable MD1 to MD7 */
 			status = write16(state, SIO_PDR_MD1_CFG__A, sioPdrMdxCfg);
@@ -6069,9 +6065,7 @@
 		if (status < 0)
 			goto error;
 
-		if (!state->microcode_name)
-			load_microcode(state, "drxk_a3.mc");
-		else
+		if (state->microcode_name)
 			load_microcode(state, state->microcode_name);
 
 		/* disable token-ring bus through OFDM block for possible ucode upload */
@@ -6322,15 +6316,12 @@
 	switch (p->delivery_system) {
 	case SYS_DVBC_ANNEX_A:
 	case SYS_DVBC_ANNEX_C:
+	case SYS_DVBT:
 		sets->min_delay_ms = 3000;
 		sets->max_drift = 0;
 		sets->step_size = 0;
 		return 0;
 	default:
-		/*
-		 * For DVB-T, let it use the default DVB core way, that is:
-		 *	fepriv->step_size = fe->ops.info.frequency_stepsize * 2
-		 */
 		return -EINVAL;
 	}
 }
@@ -6390,6 +6381,21 @@
 	state->antenna_gpio = config->antenna_gpio;
 	state->antenna_dvbt = config->antenna_dvbt;
 	state->m_ChunkSize = config->chunk_size;
+	state->enable_merr_cfg = config->enable_merr_cfg;
+
+	if (config->dynamic_clk) {
+		state->m_DVBTStaticCLK = 0;
+		state->m_DVBCStaticCLK = 0;
+	} else {
+		state->m_DVBTStaticCLK = 1;
+		state->m_DVBCStaticCLK = 1;
+	}
+
+
+	if (config->mpeg_out_clk_strength)
+		state->m_TSClockkStrength = config->mpeg_out_clk_strength & 0x07;
+	else
+		state->m_TSClockkStrength = 0x06;
 
 	if (config->parallel_ts)
 		state->m_enableParallel = true;
diff --git a/drivers/media/dvb/frontends/drxk_hard.h b/drivers/media/dvb/frontends/drxk_hard.h
index 3a58b73..4bbf841 100644
--- a/drivers/media/dvb/frontends/drxk_hard.h
+++ b/drivers/media/dvb/frontends/drxk_hard.h
@@ -332,6 +332,7 @@
 
 	u16	UIO_mask;	/* Bits used by UIO */
 
+	bool	enable_merr_cfg;
 	bool	single_master;
 	bool	no_i2c_bridge;
 	bool	antenna_dvbt;
diff --git a/drivers/media/dvb/frontends/it913x-fe-priv.h b/drivers/media/dvb/frontends/it913x-fe-priv.h
index 93b086e..eb6fd8a 100644
--- a/drivers/media/dvb/frontends/it913x-fe-priv.h
+++ b/drivers/media/dvb/frontends/it913x-fe-priv.h
@@ -201,6 +201,11 @@
 	QAM_64,
 };
 
+enum {
+	PRIORITY_HIGH = 0,	/* High-priority stream */
+	PRIORITY_LOW,	/* Low-priority stream */
+};
+
 /* Standard demodulator functions */
 static struct it913xset set_solo_fe[] = {
 	{PRO_LINK, GPIOH5_EN, {0x01}, 0x01},
diff --git a/drivers/media/dvb/frontends/it913x-fe.c b/drivers/media/dvb/frontends/it913x-fe.c
index ccc36bf..84df03c 100644
--- a/drivers/media/dvb/frontends/it913x-fe.c
+++ b/drivers/media/dvb/frontends/it913x-fe.c
@@ -57,6 +57,7 @@
 	u32 frequency;
 	fe_modulation_t constellation;
 	fe_transmit_mode_t transmission_mode;
+	u8 priority;
 	u32 crystalFrequency;
 	u32 adcFrequency;
 	u8 tuner_type;
@@ -500,19 +501,87 @@
 	return 0;
 }
 
+/* FEC values based on fe_code_rate_t non supported values 0*/
+int it913x_qpsk_pval[] = {0, -93, -91, -90, 0, -89, -88};
+int it913x_16qam_pval[] = {0, -87, -85, -84, 0, -83, -82};
+int it913x_64qam_pval[] = {0, -82, -80, -78, 0, -77, -76};
+
+static int it913x_get_signal_strength(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	struct it913x_fe_state *state = fe->demodulator_priv;
+	u8 code_rate;
+	int ret, temp;
+	u8 lna_gain_os;
+
+	ret = it913x_read_reg_u8(state, VAR_P_INBAND);
+	if (ret < 0)
+		return ret;
+
+	/* VHF/UHF gain offset */
+	if (state->frequency < 300000000)
+		lna_gain_os = 7;
+	else
+		lna_gain_os = 14;
+
+	temp = (ret - 100) - lna_gain_os;
+
+	if (state->priority == PRIORITY_HIGH)
+		code_rate = p->code_rate_HP;
+	else
+		code_rate = p->code_rate_LP;
+
+	if (code_rate >= ARRAY_SIZE(it913x_qpsk_pval))
+		return -EINVAL;
+
+	deb_info("Reg VAR_P_INBAND:%d Calc Offset Value:%d", ret, temp);
+
+	/* Apply FEC offset values*/
+	switch (p->modulation) {
+	case QPSK:
+		temp -= it913x_qpsk_pval[code_rate];
+		break;
+	case QAM_16:
+		temp -= it913x_16qam_pval[code_rate];
+		break;
+	case QAM_64:
+		temp -= it913x_64qam_pval[code_rate];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (temp < -15)
+		ret = 0;
+	else if ((-15 <= temp) && (temp < 0))
+		ret = (2 * (temp + 15)) / 3;
+	else if ((0 <= temp) && (temp < 20))
+		ret = 4 * temp + 10;
+	else if ((20 <= temp) && (temp < 35))
+		ret = (2 * (temp - 20)) / 3 + 90;
+	else if (temp >= 35)
+		ret = 100;
+
+	deb_info("Signal Strength :%d", ret);
+
+	return ret;
+}
+
 static int it913x_fe_read_signal_strength(struct dvb_frontend *fe,
 		u16 *strength)
 {
 	struct it913x_fe_state *state = fe->demodulator_priv;
-	int ret = it913x_read_reg_u8(state, SIGNAL_LEVEL);
-	/*SIGNAL_LEVEL always returns 100%! so using FE_HAS_SIGNAL as switch*/
-	if (state->it913x_status & FE_HAS_SIGNAL)
-		ret = (ret * 0xff) / 0x64;
-	else
-		ret = 0x0;
-	ret |= ret << 0x8;
-	*strength = ret;
-	return 0;
+	int ret = 0;
+	if (state->config->read_slevel) {
+		if (state->it913x_status & FE_HAS_SIGNAL)
+			ret = it913x_read_reg_u8(state, SIGNAL_LEVEL);
+	} else
+		ret = it913x_get_signal_strength(fe);
+
+	if (ret >= 0)
+		*strength = (u16)((u32)ret * 0xffff / 0x64);
+
+	return (ret < 0) ? -ENODEV : 0;
 }
 
 static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
@@ -606,6 +675,8 @@
 	if (reg[2] < 4)
 		p->hierarchy = fe_hi[reg[2]];
 
+	state->priority = reg[5];
+
 	p->code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE;
 	p->code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE;
 
@@ -972,5 +1043,5 @@
 
 MODULE_DESCRIPTION("it913x Frontend and it9137 tuner");
 MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
-MODULE_VERSION("1.13");
+MODULE_VERSION("1.15");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/it913x-fe.h b/drivers/media/dvb/frontends/it913x-fe.h
index c4a908e..07fa459 100644
--- a/drivers/media/dvb/frontends/it913x-fe.h
+++ b/drivers/media/dvb/frontends/it913x-fe.h
@@ -34,6 +34,8 @@
 	u8 tuner_id_1;
 	u8 dual_mode;
 	u8 adf;
+	/* option to read SIGNAL_LEVEL */
+	u8 read_slevel;
 };
 
 #if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \
@@ -168,6 +170,8 @@
 #define EST_SIGNAL_LEVEL	0x004a
 #define FREE_BAND		0x004b
 #define SUSPEND_FLAG		0x004c
+#define VAR_P_INBAND		0x00f7
+
 /* Build in tuner types */
 #define IT9137 0x38
 #define IT9135_38 0x38
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index c990d35..e046622 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -104,8 +104,8 @@
  * then reads the data returned for (len) bytes.
  */
 
-static u8 i2c_read_demod_bytes (struct lgdt330x_state* state,
-			       enum I2C_REG reg, u8* buf, int len)
+static int i2c_read_demod_bytes(struct lgdt330x_state *state,
+				enum I2C_REG reg, u8 *buf, int len)
 {
 	u8 wr [] = { reg };
 	struct i2c_msg msg [] = {
@@ -118,6 +118,8 @@
 	ret = i2c_transfer(state->i2c, msg, 2);
 	if (ret != 2) {
 		printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __func__, state->config->demod_address, reg, ret);
+		if (ret >= 0)
+			ret = -EIO;
 	} else {
 		ret = 0;
 	}
diff --git a/drivers/media/dvb/frontends/m88rs2000.c b/drivers/media/dvb/frontends/m88rs2000.c
new file mode 100644
index 0000000..045ee5a
--- /dev/null
+++ b/drivers/media/dvb/frontends/m88rs2000.c
@@ -0,0 +1,904 @@
+/*
+	Driver for M88RS2000 demodulator and tuner
+
+	Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com)
+	Beta Driver
+
+	Include various calculation code from DS3000 driver.
+	Copyright (C) 2009 Konstantin Dimitrov.
+
+	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/jiffies.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+
+#include "dvb_frontend.h"
+#include "m88rs2000.h"
+
+struct m88rs2000_state {
+	struct i2c_adapter *i2c;
+	const struct m88rs2000_config *config;
+	struct dvb_frontend frontend;
+	u8 no_lock_count;
+	u32 tuner_frequency;
+	u32 symbol_rate;
+	fe_code_rate_t fec_inner;
+	u8 tuner_level;
+	int errmode;
+};
+
+static int m88rs2000_debug;
+
+module_param_named(debug, m88rs2000_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
+
+#define dprintk(level, args...) do { \
+	if (level & m88rs2000_debug) \
+		printk(KERN_DEBUG "m88rs2000-fe: " args); \
+} while (0)
+
+#define deb_info(args...)  dprintk(0x01, args)
+#define info(format, arg...) \
+	printk(KERN_INFO "m88rs2000-fe: " format "\n" , ## arg)
+
+static int m88rs2000_writereg(struct m88rs2000_state *state, u8 tuner,
+	u8 reg, u8 data)
+{
+	int ret;
+	u8 addr = (tuner == 0) ? state->config->tuner_addr :
+		state->config->demod_addr;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {
+		.addr = addr,
+		.flags = 0,
+		.buf = buf,
+		.len = 2
+	};
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		deb_info("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
+			"ret == %i)\n", __func__, reg, data, ret);
+
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int m88rs2000_demod_write(struct m88rs2000_state *state, u8 reg, u8 data)
+{
+	return m88rs2000_writereg(state, 1, reg, data);
+}
+
+static int m88rs2000_tuner_write(struct m88rs2000_state *state, u8 reg, u8 data)
+{
+	m88rs2000_demod_write(state, 0x81, 0x84);
+	udelay(10);
+	return m88rs2000_writereg(state, 0, reg, data);
+
+}
+
+static int m88rs2000_write(struct dvb_frontend *fe, const u8 buf[], int len)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+
+	if (len != 2)
+		return -EINVAL;
+
+	return m88rs2000_writereg(state, 1, buf[0], buf[1]);
+}
+
+static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 tuner, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	u8 addr = (tuner == 0) ? state->config->tuner_addr :
+		state->config->demod_addr;
+	struct i2c_msg msg[] = {
+		{
+			.addr = addr,
+			.flags = 0,
+			.buf = b0,
+			.len = 1
+		}, {
+			.addr = addr,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 1
+		}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		deb_info("%s: readreg error (reg == 0x%02x, ret == %i)\n",
+				__func__, reg, ret);
+
+	return b1[0];
+}
+
+static u8 m88rs2000_demod_read(struct m88rs2000_state *state, u8 reg)
+{
+	return m88rs2000_readreg(state, 1, reg);
+}
+
+static u8 m88rs2000_tuner_read(struct m88rs2000_state *state, u8 reg)
+{
+	m88rs2000_demod_write(state, 0x81, 0x85);
+	udelay(10);
+	return m88rs2000_readreg(state, 0, reg);
+}
+
+static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	int ret;
+	u32 temp;
+	u8 b[3];
+
+	if ((srate < 1000000) || (srate > 45000000))
+		return -EINVAL;
+
+	temp = srate / 1000;
+	temp *= 11831;
+	temp /= 68;
+	temp -= 3;
+
+	b[0] = (u8) (temp >> 16) & 0xff;
+	b[1] = (u8) (temp >> 8) & 0xff;
+	b[2] = (u8) temp & 0xff;
+	ret = m88rs2000_demod_write(state, 0x93, b[2]);
+	ret |= m88rs2000_demod_write(state, 0x94, b[1]);
+	ret |= m88rs2000_demod_write(state, 0x95, b[0]);
+
+	deb_info("m88rs2000: m88rs2000_set_symbolrate\n");
+	return ret;
+}
+
+static int m88rs2000_send_diseqc_msg(struct dvb_frontend *fe,
+				    struct dvb_diseqc_master_cmd *m)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+
+	int i;
+	u8 reg;
+	deb_info("%s\n", __func__);
+	m88rs2000_demod_write(state, 0x9a, 0x30);
+	reg = m88rs2000_demod_read(state, 0xb2);
+	reg &= 0x3f;
+	m88rs2000_demod_write(state, 0xb2, reg);
+	for (i = 0; i <  m->msg_len; i++)
+		m88rs2000_demod_write(state, 0xb3 + i, m->msg[i]);
+
+	reg = m88rs2000_demod_read(state, 0xb1);
+	reg &= 0x87;
+	reg |= ((m->msg_len - 1) << 3) | 0x07;
+	reg &= 0x7f;
+	m88rs2000_demod_write(state, 0xb1, reg);
+
+	for (i = 0; i < 15; i++) {
+		if ((m88rs2000_demod_read(state, 0xb1) & 0x40) == 0x0)
+			break;
+		msleep(20);
+	}
+
+	reg = m88rs2000_demod_read(state, 0xb1);
+	if ((reg & 0x40) > 0x0) {
+		reg &= 0x7f;
+		reg |= 0x40;
+		m88rs2000_demod_write(state, 0xb1, reg);
+	}
+
+	reg = m88rs2000_demod_read(state, 0xb2);
+	reg &= 0x3f;
+	reg |= 0x80;
+	m88rs2000_demod_write(state, 0xb2, reg);
+	m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+
+	return 0;
+}
+
+static int m88rs2000_send_diseqc_burst(struct dvb_frontend *fe,
+						fe_sec_mini_cmd_t burst)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	u8 reg0, reg1;
+	deb_info("%s\n", __func__);
+	m88rs2000_demod_write(state, 0x9a, 0x30);
+	msleep(50);
+	reg0 = m88rs2000_demod_read(state, 0xb1);
+	reg1 = m88rs2000_demod_read(state, 0xb2);
+	/* TODO complete this section */
+	m88rs2000_demod_write(state, 0xb2, reg1);
+	m88rs2000_demod_write(state, 0xb1, reg0);
+	m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+	return 0;
+}
+
+static int m88rs2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	u8 reg0, reg1;
+	m88rs2000_demod_write(state, 0x9a, 0x30);
+	reg0 = m88rs2000_demod_read(state, 0xb1);
+	reg1 = m88rs2000_demod_read(state, 0xb2);
+
+	reg1 &= 0x3f;
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		reg0 |= 0x4;
+		reg0 &= 0xbc;
+		break;
+	case SEC_TONE_OFF:
+		reg1 |= 0x80;
+		break;
+	default:
+		break;
+	}
+	m88rs2000_demod_write(state, 0xb2, reg1);
+	m88rs2000_demod_write(state, 0xb1, reg0);
+	m88rs2000_demod_write(state, 0x9a, 0xb0);
+	return 0;
+}
+
+struct inittab {
+	u8 cmd;
+	u8 reg;
+	u8 val;
+};
+
+struct inittab m88rs2000_setup[] = {
+	{DEMOD_WRITE, 0x9a, 0x30},
+	{DEMOD_WRITE, 0x00, 0x01},
+	{WRITE_DELAY, 0x19, 0x00},
+	{DEMOD_WRITE, 0x00, 0x00},
+	{DEMOD_WRITE, 0x9a, 0xb0},
+	{DEMOD_WRITE, 0x81, 0xc1},
+	{TUNER_WRITE, 0x42, 0x73},
+	{TUNER_WRITE, 0x05, 0x07},
+	{TUNER_WRITE, 0x20, 0x27},
+	{TUNER_WRITE, 0x07, 0x02},
+	{TUNER_WRITE, 0x11, 0xff},
+	{TUNER_WRITE, 0x60, 0xf9},
+	{TUNER_WRITE, 0x08, 0x01},
+	{TUNER_WRITE, 0x00, 0x41},
+	{DEMOD_WRITE, 0x81, 0x81},
+	{DEMOD_WRITE, 0x86, 0xc6},
+	{DEMOD_WRITE, 0x9a, 0x30},
+	{DEMOD_WRITE, 0xf0, 0x22},
+	{DEMOD_WRITE, 0xf1, 0xbf},
+	{DEMOD_WRITE, 0xb0, 0x45},
+	{DEMOD_WRITE, 0xb2, 0x01}, /* set voltage pin always set 1*/
+	{DEMOD_WRITE, 0x9a, 0xb0},
+	{0xff, 0xaa, 0xff}
+};
+
+struct inittab m88rs2000_shutdown[] = {
+	{DEMOD_WRITE, 0x9a, 0x30},
+	{DEMOD_WRITE, 0xb0, 0x00},
+	{DEMOD_WRITE, 0xf1, 0x89},
+	{DEMOD_WRITE, 0x00, 0x01},
+	{DEMOD_WRITE, 0x9a, 0xb0},
+	{TUNER_WRITE, 0x00, 0x40},
+	{DEMOD_WRITE, 0x81, 0x81},
+	{0xff, 0xaa, 0xff}
+};
+
+struct inittab tuner_reset[] = {
+	{TUNER_WRITE, 0x42, 0x73},
+	{TUNER_WRITE, 0x05, 0x07},
+	{TUNER_WRITE, 0x20, 0x27},
+	{TUNER_WRITE, 0x07, 0x02},
+	{TUNER_WRITE, 0x11, 0xff},
+	{TUNER_WRITE, 0x60, 0xf9},
+	{TUNER_WRITE, 0x08, 0x01},
+	{TUNER_WRITE, 0x00, 0x41},
+	{0xff, 0xaa, 0xff}
+};
+
+struct inittab fe_reset[] = {
+	{DEMOD_WRITE, 0x00, 0x01},
+	{DEMOD_WRITE, 0xf1, 0xbf},
+	{DEMOD_WRITE, 0x00, 0x01},
+	{DEMOD_WRITE, 0x20, 0x81},
+	{DEMOD_WRITE, 0x21, 0x80},
+	{DEMOD_WRITE, 0x10, 0x33},
+	{DEMOD_WRITE, 0x11, 0x44},
+	{DEMOD_WRITE, 0x12, 0x07},
+	{DEMOD_WRITE, 0x18, 0x20},
+	{DEMOD_WRITE, 0x28, 0x04},
+	{DEMOD_WRITE, 0x29, 0x8e},
+	{DEMOD_WRITE, 0x3b, 0xff},
+	{DEMOD_WRITE, 0x32, 0x10},
+	{DEMOD_WRITE, 0x33, 0x02},
+	{DEMOD_WRITE, 0x34, 0x30},
+	{DEMOD_WRITE, 0x35, 0xff},
+	{DEMOD_WRITE, 0x38, 0x50},
+	{DEMOD_WRITE, 0x39, 0x68},
+	{DEMOD_WRITE, 0x3c, 0x7f},
+	{DEMOD_WRITE, 0x3d, 0x0f},
+	{DEMOD_WRITE, 0x45, 0x20},
+	{DEMOD_WRITE, 0x46, 0x24},
+	{DEMOD_WRITE, 0x47, 0x7c},
+	{DEMOD_WRITE, 0x48, 0x16},
+	{DEMOD_WRITE, 0x49, 0x04},
+	{DEMOD_WRITE, 0x4a, 0x01},
+	{DEMOD_WRITE, 0x4b, 0x78},
+	{DEMOD_WRITE, 0X4d, 0xd2},
+	{DEMOD_WRITE, 0x4e, 0x6d},
+	{DEMOD_WRITE, 0x50, 0x30},
+	{DEMOD_WRITE, 0x51, 0x30},
+	{DEMOD_WRITE, 0x54, 0x7b},
+	{DEMOD_WRITE, 0x56, 0x09},
+	{DEMOD_WRITE, 0x58, 0x59},
+	{DEMOD_WRITE, 0x59, 0x37},
+	{DEMOD_WRITE, 0x63, 0xfa},
+	{0xff, 0xaa, 0xff}
+};
+
+struct inittab fe_trigger[] = {
+	{DEMOD_WRITE, 0x97, 0x04},
+	{DEMOD_WRITE, 0x99, 0x77},
+	{DEMOD_WRITE, 0x9b, 0x64},
+	{DEMOD_WRITE, 0x9e, 0x00},
+	{DEMOD_WRITE, 0x9f, 0xf8},
+	{DEMOD_WRITE, 0xa0, 0x20},
+	{DEMOD_WRITE, 0xa1, 0xe0},
+	{DEMOD_WRITE, 0xa3, 0x38},
+	{DEMOD_WRITE, 0x98, 0xff},
+	{DEMOD_WRITE, 0xc0, 0x0f},
+	{DEMOD_WRITE, 0x89, 0x01},
+	{DEMOD_WRITE, 0x00, 0x00},
+	{WRITE_DELAY, 0x0a, 0x00},
+	{DEMOD_WRITE, 0x00, 0x01},
+	{DEMOD_WRITE, 0x00, 0x00},
+	{DEMOD_WRITE, 0x9a, 0xb0},
+	{0xff, 0xaa, 0xff}
+};
+
+static int m88rs2000_tab_set(struct m88rs2000_state *state,
+		struct inittab *tab)
+{
+	int ret = 0;
+	u8 i;
+	if (tab == NULL)
+		return -EINVAL;
+
+	for (i = 0; i < 255; i++) {
+		switch (tab[i].cmd) {
+		case 0x01:
+			ret = m88rs2000_demod_write(state, tab[i].reg,
+				tab[i].val);
+			break;
+		case 0x02:
+			ret = m88rs2000_tuner_write(state, tab[i].reg,
+				tab[i].val);
+			break;
+		case 0x10:
+			if (tab[i].reg > 0)
+				mdelay(tab[i].reg);
+			break;
+		case 0xff:
+			if (tab[i].reg == 0xaa && tab[i].val == 0xff)
+				return 0;
+		case 0x00:
+			break;
+		default:
+			return -EINVAL;
+		}
+		if (ret < 0)
+			return -ENODEV;
+	}
+	return 0;
+}
+
+static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
+{
+	deb_info("%s: %s\n", __func__,
+		volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+		volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+
+	return 0;
+}
+
+static int m88rs2000_startup(struct m88rs2000_state *state)
+{
+	int ret = 0;
+	u8 reg;
+
+	reg = m88rs2000_tuner_read(state, 0x00);
+	if ((reg & 0x40) == 0)
+		ret = -ENODEV;
+
+	return ret;
+}
+
+static int m88rs2000_init(struct dvb_frontend *fe)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	int ret;
+
+	deb_info("m88rs2000: init chip\n");
+	/* Setup frontend from shutdown/cold */
+	ret = m88rs2000_tab_set(state, m88rs2000_setup);
+
+	return ret;
+}
+
+static int m88rs2000_sleep(struct dvb_frontend *fe)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	int ret;
+	/* Shutdown the frondend */
+	ret = m88rs2000_tab_set(state, m88rs2000_shutdown);
+	return ret;
+}
+
+static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	u8 reg = m88rs2000_demod_read(state, 0x8c);
+
+	*status = 0;
+
+	if ((reg & 0x7) == 0x7) {
+		*status = FE_HAS_CARRIER | FE_HAS_SIGNAL | FE_HAS_VITERBI
+			| FE_HAS_LOCK;
+		if (state->config->set_ts_params)
+			state->config->set_ts_params(fe, CALL_IS_READ);
+	}
+	return 0;
+}
+
+/* Extact code for these unknown but lmedm04 driver uses interupt callbacks */
+
+static int m88rs2000_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	deb_info("m88rs2000_read_ber %d\n", *ber);
+	*ber = 0;
+	return 0;
+}
+
+static int m88rs2000_read_signal_strength(struct dvb_frontend *fe,
+	u16 *strength)
+{
+	*strength = 0;
+	return 0;
+}
+
+static int m88rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	deb_info("m88rs2000_read_snr %d\n", *snr);
+	*snr = 0;
+	return 0;
+}
+
+static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	deb_info("m88rs2000_read_ber %d\n", *ucblocks);
+	*ucblocks = 0;
+	return 0;
+}
+
+static int m88rs2000_tuner_gate_ctrl(struct m88rs2000_state *state, u8 offset)
+{
+	int ret;
+	ret = m88rs2000_tuner_write(state, 0x51, 0x1f - offset);
+	ret |= m88rs2000_tuner_write(state, 0x51, 0x1f);
+	ret |= m88rs2000_tuner_write(state, 0x50, offset);
+	ret |= m88rs2000_tuner_write(state, 0x50, 0x00);
+	msleep(20);
+	return ret;
+}
+
+static int m88rs2000_set_tuner_rf(struct dvb_frontend *fe)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	int reg;
+	reg = m88rs2000_tuner_read(state, 0x3d);
+	reg &= 0x7f;
+	if (reg < 0x16)
+		reg = 0xa1;
+	else if (reg == 0x16)
+		reg = 0x99;
+	else
+		reg = 0xf9;
+
+	m88rs2000_tuner_write(state, 0x60, reg);
+	reg = m88rs2000_tuner_gate_ctrl(state, 0x08);
+
+	if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	return reg;
+}
+
+static int m88rs2000_set_tuner(struct dvb_frontend *fe, u16 *offset)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	int ret;
+	u32 frequency = c->frequency;
+	s32 offset_khz;
+	s32 tmp;
+	u32 symbol_rate = (c->symbol_rate / 1000);
+	u32 f3db, gdiv28;
+	u16 value, ndiv, lpf_coeff;
+	u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf;
+	u8 lo = 0x01, div4 = 0x0;
+
+	/* Reset Tuner */
+	ret = m88rs2000_tab_set(state, tuner_reset);
+
+	/* Calculate frequency divider */
+	if (frequency < 1060000) {
+		lo |= 0x10;
+		div4 = 0x1;
+		ndiv = (frequency * 14 * 4) / FE_CRYSTAL_KHZ;
+	} else
+		ndiv = (frequency * 14 * 2) / FE_CRYSTAL_KHZ;
+	ndiv = ndiv + ndiv % 2;
+	ndiv = ndiv - 1024;
+
+	ret = m88rs2000_tuner_write(state, 0x10, 0x80 | lo);
+
+	/* Set frequency divider */
+	ret |= m88rs2000_tuner_write(state, 0x01, (ndiv >> 8) & 0xf);
+	ret |= m88rs2000_tuner_write(state, 0x02, ndiv & 0xff);
+
+	ret |= m88rs2000_tuner_write(state, 0x03, 0x06);
+	ret |= m88rs2000_tuner_gate_ctrl(state, 0x10);
+	if (ret < 0)
+		return -ENODEV;
+
+	/* Tuner Frequency Range */
+	ret = m88rs2000_tuner_write(state, 0x10, lo);
+
+	ret |= m88rs2000_tuner_gate_ctrl(state, 0x08);
+
+	/* Tuner RF */
+	ret |= m88rs2000_set_tuner_rf(fe);
+
+	gdiv28 = (FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
+	ret |= m88rs2000_tuner_write(state, 0x04, gdiv28 & 0xff);
+	ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
+	if (ret < 0)
+		return -ENODEV;
+
+	value = m88rs2000_tuner_read(state, 0x26);
+
+	f3db = (symbol_rate * 135) / 200 + 2000;
+	f3db += FREQ_OFFSET_LOW_SYM_RATE;
+	if (f3db < 7000)
+		f3db = 7000;
+	if (f3db > 40000)
+		f3db = 40000;
+
+	gdiv28 = gdiv28 * 207 / (value * 2 + 151);
+	mlpf_max = gdiv28 * 135 / 100;
+	mlpf_min = gdiv28 * 78 / 100;
+	if (mlpf_max > 63)
+		mlpf_max = 63;
+
+	lpf_coeff = 2766;
+
+	nlpf = (f3db * gdiv28 * 2 / lpf_coeff /
+		(FE_CRYSTAL_KHZ / 1000)  + 1) / 2;
+	if (nlpf > 23)
+		nlpf = 23;
+	if (nlpf < 1)
+		nlpf = 1;
+
+	lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
+		* lpf_coeff * 2  / f3db + 1) / 2;
+
+	if (lpf_mxdiv < mlpf_min) {
+		nlpf++;
+		lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
+			* lpf_coeff * 2  / f3db + 1) / 2;
+	}
+
+	if (lpf_mxdiv > mlpf_max)
+		lpf_mxdiv = mlpf_max;
+
+	ret = m88rs2000_tuner_write(state, 0x04, lpf_mxdiv);
+	ret |= m88rs2000_tuner_write(state, 0x06, nlpf);
+
+	ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
+
+	ret |= m88rs2000_tuner_gate_ctrl(state, 0x01);
+
+	msleep(80);
+	/* calculate offset assuming 96000kHz*/
+	offset_khz = (ndiv - ndiv % 2 + 1024) * FE_CRYSTAL_KHZ
+		/ 14 / (div4 + 1) / 2;
+
+	offset_khz -= frequency;
+
+	tmp = offset_khz;
+	tmp *= 65536;
+
+	tmp = (2 * tmp + 96000) / (2 * 96000);
+	if (tmp < 0)
+		tmp += 65536;
+
+	*offset = tmp & 0xffff;
+
+	if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return (ret < 0) ? -EINVAL : 0;
+}
+
+static int m88rs2000_set_fec(struct m88rs2000_state *state,
+		fe_code_rate_t fec)
+{
+	int ret;
+	u16 fec_set;
+	switch (fec) {
+	/* This is not confirmed kept for reference */
+/*	case FEC_1_2:
+		fec_set = 0x88;
+		break;
+	case FEC_2_3:
+		fec_set = 0x68;
+		break;
+	case FEC_3_4:
+		fec_set = 0x48;
+		break;
+	case FEC_5_6:
+		fec_set = 0x28;
+		break;
+	case FEC_7_8:
+		fec_set = 0x18;
+		break; */
+	case FEC_AUTO:
+	default:
+		fec_set = 0x08;
+	}
+	ret = m88rs2000_demod_write(state, 0x76, fec_set);
+
+	return 0;
+}
+
+
+static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state)
+{
+	u8 reg;
+	m88rs2000_demod_write(state, 0x9a, 0x30);
+	reg = m88rs2000_demod_read(state, 0x76);
+	m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+	switch (reg) {
+	case 0x88:
+		return FEC_1_2;
+	case 0x68:
+		return FEC_2_3;
+	case 0x48:
+		return FEC_3_4;
+	case 0x28:
+		return FEC_5_6;
+	case 0x18:
+		return FEC_7_8;
+	case 0x08:
+	default:
+		break;
+	}
+
+	return FEC_AUTO;
+}
+
+static int m88rs2000_set_frontend(struct dvb_frontend *fe)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	fe_status_t status;
+	int i, ret;
+	u16 offset = 0;
+	u8 reg;
+
+	state->no_lock_count = 0;
+
+	if (c->delivery_system != SYS_DVBS) {
+			deb_info("%s: unsupported delivery "
+				"system selected (%d)\n",
+				__func__, c->delivery_system);
+			return -EOPNOTSUPP;
+	}
+
+	/* Set Tuner */
+	ret = m88rs2000_set_tuner(fe, &offset);
+	if (ret < 0)
+		return -ENODEV;
+
+	ret = m88rs2000_demod_write(state, 0x9a, 0x30);
+	/* Unknown usually 0xc6 sometimes 0xc1 */
+	reg = m88rs2000_demod_read(state, 0x86);
+	ret |= m88rs2000_demod_write(state, 0x86, reg);
+	/* Offset lower nibble always 0 */
+	ret |= m88rs2000_demod_write(state, 0x9c, (offset >> 8));
+	ret |= m88rs2000_demod_write(state, 0x9d, offset & 0xf0);
+
+
+	/* Reset Demod */
+	ret = m88rs2000_tab_set(state, fe_reset);
+	if (ret < 0)
+		return -ENODEV;
+
+	/* Unknown */
+	reg = m88rs2000_demod_read(state, 0x70);
+	ret = m88rs2000_demod_write(state, 0x70, reg);
+
+	/* Set FEC */
+	ret |= m88rs2000_set_fec(state, c->fec_inner);
+	ret |= m88rs2000_demod_write(state, 0x85, 0x1);
+	ret |= m88rs2000_demod_write(state, 0x8a, 0xbf);
+	ret |= m88rs2000_demod_write(state, 0x8d, 0x1e);
+	ret |= m88rs2000_demod_write(state, 0x90, 0xf1);
+	ret |= m88rs2000_demod_write(state, 0x91, 0x08);
+
+	if (ret < 0)
+		return -ENODEV;
+
+	/* Set Symbol Rate */
+	ret = m88rs2000_set_symbolrate(fe, c->symbol_rate);
+	if (ret < 0)
+		return -ENODEV;
+
+	/* Set up Demod */
+	ret = m88rs2000_tab_set(state, fe_trigger);
+	if (ret < 0)
+		return -ENODEV;
+
+	for (i = 0; i < 25; i++) {
+		u8 reg = m88rs2000_demod_read(state, 0x8c);
+		if ((reg & 0x7) == 0x7) {
+			status = FE_HAS_LOCK;
+			break;
+		}
+		state->no_lock_count++;
+		if (state->no_lock_count > 15) {
+			reg = m88rs2000_demod_read(state, 0x70);
+			reg ^= 0x4;
+			m88rs2000_demod_write(state, 0x70, reg);
+			state->no_lock_count = 0;
+		}
+		if (state->no_lock_count == 20)
+			m88rs2000_set_tuner_rf(fe);
+		msleep(20);
+	}
+
+	if (status & FE_HAS_LOCK) {
+		state->fec_inner = m88rs2000_get_fec(state);
+		/* Uknown suspect SNR level */
+		reg = m88rs2000_demod_read(state, 0x65);
+	}
+
+	state->tuner_frequency = c->frequency;
+	state->symbol_rate = c->symbol_rate;
+	return 0;
+}
+
+static int m88rs2000_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	c->fec_inner = state->fec_inner;
+	c->frequency = state->tuner_frequency;
+	c->symbol_rate = state->symbol_rate;
+	return 0;
+}
+
+static int m88rs2000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+
+	if (enable)
+		m88rs2000_demod_write(state, 0x81, 0x84);
+	else
+		m88rs2000_demod_write(state, 0x81, 0x81);
+	udelay(10);
+	return 0;
+}
+
+static void m88rs2000_release(struct dvb_frontend *fe)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops m88rs2000_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name			= "M88RS2000 DVB-S",
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 1000,	 /* kHz for QPSK frontends */
+		.frequency_tolerance	= 5000,
+		.symbol_rate_min	= 1000000,
+		.symbol_rate_max	= 45000000,
+		.symbol_rate_tolerance	= 500,	/* ppm */
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+		      FE_CAN_QPSK |
+		      FE_CAN_FEC_AUTO
+	},
+
+	.release = m88rs2000_release,
+	.init = m88rs2000_init,
+	.sleep = m88rs2000_sleep,
+	.write = m88rs2000_write,
+	.i2c_gate_ctrl = m88rs2000_i2c_gate_ctrl,
+	.read_status = m88rs2000_read_status,
+	.read_ber = m88rs2000_read_ber,
+	.read_signal_strength = m88rs2000_read_signal_strength,
+	.read_snr = m88rs2000_read_snr,
+	.read_ucblocks = m88rs2000_read_ucblocks,
+	.diseqc_send_master_cmd = m88rs2000_send_diseqc_msg,
+	.diseqc_send_burst = m88rs2000_send_diseqc_burst,
+	.set_tone = m88rs2000_set_tone,
+	.set_voltage = m88rs2000_set_voltage,
+
+	.set_frontend = m88rs2000_set_frontend,
+	.get_frontend = m88rs2000_get_frontend,
+};
+
+struct dvb_frontend *m88rs2000_attach(const struct m88rs2000_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct m88rs2000_state *state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct m88rs2000_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->tuner_frequency = 0;
+	state->symbol_rate = 0;
+	state->fec_inner = 0;
+
+	if (m88rs2000_startup(state) < 0)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &m88rs2000_ops,
+			sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+
+	return NULL;
+}
+EXPORT_SYMBOL(m88rs2000_attach);
+
+MODULE_DESCRIPTION("M88RS2000 DVB-S Demodulator driver");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.13");
+
diff --git a/drivers/media/dvb/frontends/m88rs2000.h b/drivers/media/dvb/frontends/m88rs2000.h
new file mode 100644
index 0000000..59acdb6
--- /dev/null
+++ b/drivers/media/dvb/frontends/m88rs2000.h
@@ -0,0 +1,66 @@
+/*
+	Driver for M88RS2000 demodulator
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef M88RS2000_H
+#define M88RS2000_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct m88rs2000_config {
+	/* Demodulator i2c address */
+	u8 demod_addr;
+	/* Tuner address */
+	u8 tuner_addr;
+
+	u8 *inittab;
+
+	/* minimum delay before retuning */
+	int min_delay_ms;
+
+	int (*set_ts_params)(struct dvb_frontend *, int);
+};
+
+enum {
+	CALL_IS_SET_FRONTEND = 0x0,
+	CALL_IS_READ,
+};
+
+#if defined(CONFIG_DVB_M88RS2000) || (defined(CONFIG_DVB_M88RS2000_MODULE) && \
+							defined(MODULE))
+extern struct dvb_frontend *m88rs2000_attach(
+	const struct m88rs2000_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *m88rs2000_attach(
+	const struct m88rs2000_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_M88RS2000 */
+
+#define FE_CRYSTAL_KHZ 27000
+#define FREQ_OFFSET_LOW_SYM_RATE 3000
+
+enum {
+	DEMOD_WRITE = 0x1,
+	TUNER_WRITE,
+	WRITE_DELAY = 0x10,
+};
+#endif /* M88RS2000_H */
diff --git a/drivers/media/dvb/frontends/rtl2830.c b/drivers/media/dvb/frontends/rtl2830.c
new file mode 100644
index 0000000..45196c5
--- /dev/null
+++ b/drivers/media/dvb/frontends/rtl2830.c
@@ -0,0 +1,562 @@
+/*
+ * Realtek RTL2830 DVB-T demodulator driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.
+ */
+
+
+/*
+ * Driver implements own I2C-adapter for tuner I2C access. That's since chip
+ * have unusual I2C-gate control which closes gate automatically after each
+ * I2C transfer. Using own I2C adapter we can workaround that.
+ */
+
+#include "rtl2830_priv.h"
+
+int rtl2830_debug;
+module_param_named(debug, rtl2830_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+/* write multiple hardware registers */
+static int rtl2830_wr(struct rtl2830_priv *priv, u8 reg, u8 *val, int len)
+{
+	int ret;
+	u8 buf[1+len];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = priv->cfg.i2c_addr,
+			.flags = 0,
+			.len = 1+len,
+			.buf = buf,
+		}
+	};
+
+	buf[0] = reg;
+	memcpy(&buf[1], val, len);
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* read multiple hardware registers */
+static int rtl2830_rd(struct rtl2830_priv *priv, u8 reg, u8 *val, int len)
+{
+	int ret;
+	struct i2c_msg msg[2] = {
+		{
+			.addr = priv->cfg.i2c_addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg,
+		}, {
+			.addr = priv->cfg.i2c_addr,
+			.flags = I2C_M_RD,
+			.len = len,
+			.buf = val,
+		}
+	};
+
+	ret = i2c_transfer(priv->i2c, msg, 2);
+	if (ret == 2) {
+		ret = 0;
+	} else {
+		warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* write multiple registers */
+static int rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len)
+{
+	int ret;
+	u8 reg2 = (reg >> 0) & 0xff;
+	u8 page = (reg >> 8) & 0xff;
+
+	/* switch bank if needed */
+	if (page != priv->page) {
+		ret = rtl2830_wr(priv, 0x00, &page, 1);
+		if (ret)
+			return ret;
+
+		priv->page = page;
+	}
+
+	return rtl2830_wr(priv, reg2, val, len);
+}
+
+/* read multiple registers */
+static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len)
+{
+	int ret;
+	u8 reg2 = (reg >> 0) & 0xff;
+	u8 page = (reg >> 8) & 0xff;
+
+	/* switch bank if needed */
+	if (page != priv->page) {
+		ret = rtl2830_wr(priv, 0x00, &page, 1);
+		if (ret)
+			return ret;
+
+		priv->page = page;
+	}
+
+	return rtl2830_rd(priv, reg2, val, len);
+}
+
+#if 0 /* currently not used */
+/* write single register */
+static int rtl2830_wr_reg(struct rtl2830_priv *priv, u16 reg, u8 val)
+{
+	return rtl2830_wr_regs(priv, reg, &val, 1);
+}
+#endif
+
+/* read single register */
+static int rtl2830_rd_reg(struct rtl2830_priv *priv, u16 reg, u8 *val)
+{
+	return rtl2830_rd_regs(priv, reg, val, 1);
+}
+
+/* write single register with mask */
+int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask)
+{
+	int ret;
+	u8 tmp;
+
+	/* no need for read if whole reg is written */
+	if (mask != 0xff) {
+		ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
+		if (ret)
+			return ret;
+
+		val &= mask;
+		tmp &= ~mask;
+		val |= tmp;
+	}
+
+	return rtl2830_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register with mask */
+int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask)
+{
+	int ret, i;
+	u8 tmp;
+
+	ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
+	if (ret)
+		return ret;
+
+	tmp &= mask;
+
+	/* find position of the first bit */
+	for (i = 0; i < 8; i++) {
+		if ((mask >> i) & 0x01)
+			break;
+	}
+	*val = tmp >> i;
+
+	return 0;
+}
+
+static int rtl2830_init(struct dvb_frontend *fe)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	int ret, i;
+	u64 num;
+	u8 buf[3], tmp;
+	u32 if_ctl;
+	struct rtl2830_reg_val_mask tab[] = {
+		{ 0x00d, 0x01, 0x03 },
+		{ 0x00d, 0x10, 0x10 },
+		{ 0x104, 0x00, 0x1e },
+		{ 0x105, 0x80, 0x80 },
+		{ 0x110, 0x02, 0x03 },
+		{ 0x110, 0x08, 0x0c },
+		{ 0x17b, 0x00, 0x40 },
+		{ 0x17d, 0x05, 0x0f },
+		{ 0x17d, 0x50, 0xf0 },
+		{ 0x18c, 0x08, 0x0f },
+		{ 0x18d, 0x00, 0xc0 },
+		{ 0x188, 0x05, 0x0f },
+		{ 0x189, 0x00, 0xfc },
+		{ 0x2d5, 0x02, 0x02 },
+		{ 0x2f1, 0x02, 0x06 },
+		{ 0x2f1, 0x20, 0xf8 },
+		{ 0x16d, 0x00, 0x01 },
+		{ 0x1a6, 0x00, 0x80 },
+		{ 0x106, priv->cfg.vtop, 0x3f },
+		{ 0x107, priv->cfg.krf, 0x3f },
+		{ 0x112, 0x28, 0xff },
+		{ 0x103, priv->cfg.agc_targ_val, 0xff },
+		{ 0x00a, 0x02, 0x07 },
+		{ 0x140, 0x0c, 0x3c },
+		{ 0x140, 0x40, 0xc0 },
+		{ 0x15b, 0x05, 0x07 },
+		{ 0x15b, 0x28, 0x38 },
+		{ 0x15c, 0x05, 0x07 },
+		{ 0x15c, 0x28, 0x38 },
+		{ 0x115, priv->cfg.spec_inv, 0x01 },
+		{ 0x16f, 0x01, 0x07 },
+		{ 0x170, 0x18, 0x38 },
+		{ 0x172, 0x0f, 0x0f },
+		{ 0x173, 0x08, 0x38 },
+		{ 0x175, 0x01, 0x07 },
+		{ 0x176, 0x00, 0xc0 },
+	};
+
+	for (i = 0; i < ARRAY_SIZE(tab); i++) {
+		ret = rtl2830_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+			tab[i].mask);
+		if (ret)
+			goto err;
+	}
+
+	ret = rtl2830_wr_regs(priv, 0x18f, "\x28\x00", 2);
+	if (ret)
+		goto err;
+
+	ret = rtl2830_wr_regs(priv, 0x195,
+		"\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8);
+	if (ret)
+		goto err;
+
+	num = priv->cfg.if_dvbt % priv->cfg.xtal;
+	num *= 0x400000;
+	num = div_u64(num, priv->cfg.xtal);
+	num = -num;
+	if_ctl = num & 0x3fffff;
+	dbg("%s: if_ctl=%08x", __func__, if_ctl);
+
+	ret = rtl2830_rd_reg_mask(priv, 0x119, &tmp, 0xc0); /* b[7:6] */
+	if (ret)
+		goto err;
+
+	buf[0] = tmp << 6;
+	buf[0] = (if_ctl >> 16) & 0x3f;
+	buf[1] = (if_ctl >>  8) & 0xff;
+	buf[2] = (if_ctl >>  0) & 0xff;
+
+	ret = rtl2830_wr_regs(priv, 0x119, buf, 3);
+	if (ret)
+		goto err;
+
+	/* TODO: spec init */
+
+	/* soft reset */
+	ret = rtl2830_wr_reg_mask(priv, 0x101, 0x04, 0x04);
+	if (ret)
+		goto err;
+
+	ret = rtl2830_wr_reg_mask(priv, 0x101, 0x00, 0x04);
+	if (ret)
+		goto err;
+
+	priv->sleeping = false;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2830_sleep(struct dvb_frontend *fe)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	priv->sleeping = true;
+	return 0;
+}
+
+int rtl2830_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *s)
+{
+	s->min_delay_ms = 500;
+	s->step_size = fe->ops.info.frequency_stepsize * 2;
+	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+
+	return 0;
+}
+
+static int rtl2830_set_frontend(struct dvb_frontend *fe)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i;
+	static u8 bw_params1[3][34] = {
+		{
+		0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xfa, 0x00, 0x17, 0x00, 0x41,
+		0x00, 0x64, 0x00, 0x67, 0x00, 0x38, 0x1f, 0xde, 0x1f, 0x7a,
+		0x1f, 0x47, 0x1f, 0x7c, 0x00, 0x30, 0x01, 0x4b, 0x02, 0x82,
+		0x03, 0x73, 0x03, 0xcf, /* 6 MHz */
+		}, {
+		0x1f, 0xfa, 0x1f, 0xda, 0x1f, 0xc1, 0x1f, 0xb3, 0x1f, 0xca,
+		0x00, 0x07, 0x00, 0x4d, 0x00, 0x6d, 0x00, 0x40, 0x1f, 0xca,
+		0x1f, 0x4d, 0x1f, 0x2a, 0x1f, 0xb2, 0x00, 0xec, 0x02, 0x7e,
+		0x03, 0xd0, 0x04, 0x53, /* 7 MHz */
+		}, {
+		0x00, 0x10, 0x00, 0x0e, 0x1f, 0xf7, 0x1f, 0xc9, 0x1f, 0xa0,
+		0x1f, 0xa6, 0x1f, 0xec, 0x00, 0x4e, 0x00, 0x7d, 0x00, 0x3a,
+		0x1f, 0x98, 0x1f, 0x10, 0x1f, 0x40, 0x00, 0x75, 0x02, 0x5f,
+		0x04, 0x24, 0x04, 0xdb, /* 8 MHz */
+		},
+	};
+	static u8 bw_params2[3][6] = {
+		{0xc3, 0x0c, 0x44, 0x33, 0x33, 0x30,}, /* 6 MHz */
+		{0xb8, 0xe3, 0x93, 0x99, 0x99, 0x98,}, /* 7 MHz */
+		{0xae, 0xba, 0xf3, 0x26, 0x66, 0x64,}, /* 8 MHz */
+	};
+
+
+	dbg("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__,
+		c->frequency, c->bandwidth_hz, c->inversion);
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+	switch (c->bandwidth_hz) {
+	case 6000000:
+		i = 0;
+		break;
+	case 7000000:
+		i = 1;
+		break;
+	case 8000000:
+		i = 2;
+		break;
+	default:
+		dbg("invalid bandwidth");
+		return -EINVAL;
+	}
+
+	ret = rtl2830_wr_reg_mask(priv, 0x008, i << 1, 0x06);
+	if (ret)
+		goto err;
+
+	/* 1/2 split I2C write */
+	ret = rtl2830_wr_regs(priv, 0x11c, &bw_params1[i][0], 17);
+	if (ret)
+		goto err;
+
+	/* 2/2 split I2C write */
+	ret = rtl2830_wr_regs(priv, 0x12d, &bw_params1[i][17], 17);
+	if (ret)
+		goto err;
+
+	ret = rtl2830_wr_regs(priv, 0x19d, bw_params2[i], 6);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 tmp;
+	*status = 0;
+
+	if (priv->sleeping)
+		return 0;
+
+	ret = rtl2830_rd_reg_mask(priv, 0x351, &tmp, 0x78); /* [6:3] */
+	if (ret)
+		goto err;
+
+	if (tmp == 11) {
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+			FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+	} else if (tmp == 10) {
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+			FE_HAS_VITERBI;
+	}
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	*snr = 0;
+	return 0;
+}
+
+static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	*ber = 0;
+	return 0;
+}
+
+static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	*ucblocks = 0;
+	return 0;
+}
+
+static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	*strength = 0;
+	return 0;
+}
+
+static struct dvb_frontend_ops rtl2830_ops;
+
+static u32 rtl2830_tuner_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static int rtl2830_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
+	struct i2c_msg msg[], int num)
+{
+	struct rtl2830_priv *priv = i2c_get_adapdata(i2c_adap);
+	int ret;
+
+	/* open i2c-gate */
+	ret = rtl2830_wr_reg_mask(priv, 0x101, 0x08, 0x08);
+	if (ret)
+		goto err;
+
+	ret = i2c_transfer(priv->i2c, msg, num);
+	if (ret < 0)
+		warn("tuner i2c failed=%d", ret);
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static struct i2c_algorithm rtl2830_tuner_i2c_algo = {
+	.master_xfer   = rtl2830_tuner_i2c_xfer,
+	.functionality = rtl2830_tuner_i2c_func,
+};
+
+struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+	return &priv->tuner_i2c_adapter;
+}
+EXPORT_SYMBOL(rtl2830_get_tuner_i2c_adapter);
+
+static void rtl2830_release(struct dvb_frontend *fe)
+{
+	struct rtl2830_priv *priv = fe->demodulator_priv;
+
+	i2c_del_adapter(&priv->tuner_i2c_adapter);
+	kfree(priv);
+}
+
+struct dvb_frontend *rtl2830_attach(const struct rtl2830_config *cfg,
+	struct i2c_adapter *i2c)
+{
+	struct rtl2830_priv *priv = NULL;
+	int ret = 0;
+	u8 tmp;
+
+	/* allocate memory for the internal state */
+	priv = kzalloc(sizeof(struct rtl2830_priv), GFP_KERNEL);
+	if (priv == NULL)
+		goto err;
+
+	/* setup the priv */
+	priv->i2c = i2c;
+	memcpy(&priv->cfg, cfg, sizeof(struct rtl2830_config));
+
+	/* check if the demod is there */
+	ret = rtl2830_rd_reg(priv, 0x000, &tmp);
+	if (ret)
+		goto err;
+
+	/* create dvb_frontend */
+	memcpy(&priv->fe.ops, &rtl2830_ops, sizeof(struct dvb_frontend_ops));
+	priv->fe.demodulator_priv = priv;
+
+	/* create tuner i2c adapter */
+	strlcpy(priv->tuner_i2c_adapter.name, "RTL2830 tuner I2C adapter",
+		sizeof(priv->tuner_i2c_adapter.name));
+	priv->tuner_i2c_adapter.algo = &rtl2830_tuner_i2c_algo;
+	priv->tuner_i2c_adapter.algo_data = NULL;
+	i2c_set_adapdata(&priv->tuner_i2c_adapter, priv);
+	if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) {
+		err("tuner I2C bus could not be initialized");
+		goto err;
+	}
+
+	priv->sleeping = true;
+
+	return &priv->fe;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	kfree(priv);
+	return NULL;
+}
+EXPORT_SYMBOL(rtl2830_attach);
+
+static struct dvb_frontend_ops rtl2830_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "Realtek RTL2830 (DVB-T)",
+		.caps = FE_CAN_FEC_1_2 |
+			FE_CAN_FEC_2_3 |
+			FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 |
+			FE_CAN_FEC_7_8 |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK |
+			FE_CAN_QAM_16 |
+			FE_CAN_QAM_64 |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_MUTE_TS
+	},
+
+	.release = rtl2830_release,
+
+	.init = rtl2830_init,
+	.sleep = rtl2830_sleep,
+
+	.get_tune_settings = rtl2830_get_tune_settings,
+
+	.set_frontend = rtl2830_set_frontend,
+
+	.read_status = rtl2830_read_status,
+	.read_snr = rtl2830_read_snr,
+	.read_ber = rtl2830_read_ber,
+	.read_ucblocks = rtl2830_read_ucblocks,
+	.read_signal_strength = rtl2830_read_signal_strength,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/rtl2830.h b/drivers/media/dvb/frontends/rtl2830.h
new file mode 100644
index 0000000..1c6ee91
--- /dev/null
+++ b/drivers/media/dvb/frontends/rtl2830.h
@@ -0,0 +1,97 @@
+/*
+ * Realtek RTL2830 DVB-T demodulator driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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 RTL2830_H
+#define RTL2830_H
+
+#include <linux/dvb/frontend.h>
+
+struct rtl2830_config {
+	/*
+	 * Demodulator I2C address.
+	 */
+	u8 i2c_addr;
+
+	/*
+	 * Xtal frequency.
+	 * Hz
+	 * 4000000, 16000000, 25000000, 28800000
+	 */
+	u32 xtal;
+
+	/*
+	 * TS output mode.
+	 */
+	u8 ts_mode;
+
+	/*
+	 * Spectrum inversion.
+	 */
+	bool spec_inv;
+
+	/*
+	 * IFs for all used modes.
+	 * Hz
+	 * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
+	 */
+	u32 if_dvbt;
+
+	/*
+	 */
+	u8 vtop;
+
+	/*
+	 */
+	u8 krf;
+
+	/*
+	 */
+	u8 agc_targ_val;
+};
+
+#if defined(CONFIG_DVB_RTL2830) || \
+	(defined(CONFIG_DVB_RTL2830_MODULE) && defined(MODULE))
+extern struct dvb_frontend *rtl2830_attach(
+	const struct rtl2830_config *config,
+	struct i2c_adapter *i2c
+);
+
+extern struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(
+	struct dvb_frontend *fe
+);
+#else
+static inline struct dvb_frontend *rtl2830_attach(
+	const struct rtl2830_config *config,
+	struct i2c_adapter *i2c
+)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(
+	struct dvb_frontend *fe
+)
+{
+	return NULL;
+}
+#endif
+
+#endif /* RTL2830_H */
diff --git a/drivers/media/dvb/frontends/rtl2830_priv.h b/drivers/media/dvb/frontends/rtl2830_priv.h
new file mode 100644
index 0000000..4a46476
--- /dev/null
+++ b/drivers/media/dvb/frontends/rtl2830_priv.h
@@ -0,0 +1,57 @@
+/*
+ * Realtek RTL2830 DVB-T demodulator driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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 RTL2830_PRIV_H
+#define RTL2830_PRIV_H
+
+#include "dvb_frontend.h"
+#include "rtl2830.h"
+
+#define LOG_PREFIX "rtl2830"
+
+#undef dbg
+#define dbg(f, arg...) \
+	if (rtl2830_debug) \
+		printk(KERN_INFO            LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct rtl2830_priv {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend fe;
+	struct rtl2830_config cfg;
+	struct i2c_adapter tuner_i2c_adapter;
+
+	bool sleeping;
+
+	u8 page; /* active register page */
+};
+
+struct rtl2830_reg_val_mask {
+	u16 reg;
+	u8  val;
+	u8  mask;
+};
+
+#endif /* RTL2830_PRIV_H */
diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c
index 38565be..dd08f4a 100644
--- a/drivers/media/dvb/frontends/stb0899_drv.c
+++ b/drivers/media/dvb/frontends/stb0899_drv.c
@@ -67,7 +67,7 @@
  * Crude linear extrapolation below -84.8dBm and above -8.0dBm.
  */
 static const struct stb0899_tab stb0899_dvbsrf_tab[] = {
-	{ -950,	-128 },
+	{ -750,	-128 },
 	{ -748,	 -94 },
 	{ -745,	 -92 },
 	{ -735,	 -90 },
@@ -131,7 +131,7 @@
 	{ -730,	13645 },
 	{ -750,	13909 },
 	{ -766,	14153 },
-	{ -999,	16383 }
+	{ -950,	16383 }
 };
 
 /* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/
@@ -964,6 +964,7 @@
 
 	int val;
 	u32 reg;
+	*strength = 0;
 	switch (state->delsys) {
 	case SYS_DVBS:
 	case SYS_DSS:
@@ -983,11 +984,11 @@
 		break;
 	case SYS_DVBS2:
 		if (internal->lock) {
-			reg = STB0899_READ_S2REG(STB0899_DEMOD, IF_AGC_GAIN);
+			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_GAIN);
 			val = STB0899_GETFIELD(IF_AGC_GAIN, reg);
 
 			*strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val);
-			*strength += 750;
+			*strength += 950;
 			dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm",
 				val & 0x3fff, *strength);
 		}
@@ -1009,6 +1010,7 @@
 	u8 buf[2];
 	u32 reg;
 
+	*snr = 0;
 	reg  = stb0899_read_reg(state, STB0899_VSTATUS);
 	switch (state->delsys) {
 	case SYS_DVBS:
@@ -1071,7 +1073,7 @@
 			reg  = stb0899_read_reg(state, STB0899_VSTATUS);
 			if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) {
 				dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_CARRIER | FE_HAS_LOCK");
-				*status |= FE_HAS_CARRIER | FE_HAS_LOCK;
+				*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
 
 				reg = stb0899_read_reg(state, STB0899_PLPARM);
 				if (STB0899_GETFIELD(VITCURPUN, reg)) {
diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c
index fb5548a..632b251 100644
--- a/drivers/media/dvb/frontends/stv0288.c
+++ b/drivers/media/dvb/frontends/stv0288.c
@@ -506,7 +506,7 @@
 		tda[1] = (unsigned char)tm;
 		stv0288_writeregI(state, 0x2b, tda[1]);
 		stv0288_writeregI(state, 0x2c, tda[2]);
-		udelay(30);
+		msleep(30);
 	}
 	state->tuner_frequency = c->frequency;
 	state->fec_inner = FEC_AUTO;
diff --git a/drivers/media/dvb/frontends/tda10071.c b/drivers/media/dvb/frontends/tda10071.c
index a992050..c21bc92 100644
--- a/drivers/media/dvb/frontends/tda10071.c
+++ b/drivers/media/dvb/frontends/tda10071.c
@@ -1215,7 +1215,7 @@
 EXPORT_SYMBOL(tda10071_attach);
 
 static struct dvb_frontend_ops tda10071_ops = {
-	.delsys = { SYS_DVBT, SYS_DVBT2 },
+	.delsys = { SYS_DVBS, SYS_DVBS2 },
 	.info = {
 		.name = "NXP TDA10071",
 		.frequency_min = 950000,
diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c
index 8418c02..7539a5d 100644
--- a/drivers/media/dvb/ngene/ngene-cards.c
+++ b/drivers/media/dvb/ngene/ngene-cards.c
@@ -216,6 +216,7 @@
 	struct drxk_config config;
 
 	memset(&config, 0, sizeof(config));
+	config.microcode_name = "drxk_a3.mc";
 	config.adr = 0x29 + (chan->number ^ 2);
 
 	chan->fe = dvb_attach(drxk_attach, &config, i2c);
diff --git a/drivers/media/dvb/pt1/pt1.c b/drivers/media/dvb/pt1/pt1.c
index b81df5f..15b35c4 100644
--- a/drivers/media/dvb/pt1/pt1.c
+++ b/drivers/media/dvb/pt1/pt1.c
@@ -28,6 +28,7 @@
 #include <linux/pci.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
+#include <linux/ratelimit.h>
 
 #include "dvbdev.h"
 #include "dvb_demux.h"
@@ -77,6 +78,8 @@
 	struct pt1_adapter *adaps[PT1_NR_ADAPS];
 	struct pt1_table *tables;
 	struct task_struct *kthread;
+	int table_index;
+	int buf_index;
 
 	struct mutex lock;
 	int power;
@@ -90,12 +93,12 @@
 	u8 *buf;
 	int upacket_count;
 	int packet_count;
+	int st_count;
 
 	struct dvb_adapter adap;
 	struct dvb_demux demux;
 	int users;
 	struct dmxdev dmxdev;
-	struct dvb_net net;
 	struct dvb_frontend *fe;
 	int (*orig_set_voltage)(struct dvb_frontend *fe,
 				fe_sec_voltage_t voltage);
@@ -119,7 +122,7 @@
 	return readl(pt1->regs + reg * 4);
 }
 
-static int pt1_nr_tables = 64;
+static int pt1_nr_tables = 8;
 module_param_named(nr_tables, pt1_nr_tables, int, 0);
 
 static void pt1_increment_table_count(struct pt1 *pt1)
@@ -264,6 +267,7 @@
 	struct pt1_adapter *adap;
 	int offset;
 	u8 *buf;
+	int sc;
 
 	if (!page->upackets[PT1_NR_UPACKETS - 1])
 		return 0;
@@ -280,6 +284,16 @@
 		else if (!adap->upacket_count)
 			continue;
 
+		if (upacket >> 24 & 1)
+			printk_ratelimited(KERN_INFO "earth-pt1: device "
+				"buffer overflowing. table[%d] buf[%d]\n",
+				pt1->table_index, pt1->buf_index);
+		sc = upacket >> 26 & 0x7;
+		if (adap->st_count != -1 && sc != ((adap->st_count + 1) & 0x7))
+			printk_ratelimited(KERN_INFO "earth-pt1: data loss"
+				" in streamID(adapter)[%d]\n", index);
+		adap->st_count = sc;
+
 		buf = adap->buf;
 		offset = adap->packet_count * 188 + adap->upacket_count * 3;
 		buf[offset] = upacket >> 16;
@@ -303,30 +317,25 @@
 static int pt1_thread(void *data)
 {
 	struct pt1 *pt1;
-	int table_index;
-	int buf_index;
 	struct pt1_buffer_page *page;
 
 	pt1 = data;
 	set_freezable();
 
-	table_index = 0;
-	buf_index = 0;
-
 	while (!kthread_should_stop()) {
 		try_to_freeze();
 
-		page = pt1->tables[table_index].bufs[buf_index].page;
+		page = pt1->tables[pt1->table_index].bufs[pt1->buf_index].page;
 		if (!pt1_filter(pt1, page)) {
 			schedule_timeout_interruptible((HZ + 999) / 1000);
 			continue;
 		}
 
-		if (++buf_index >= PT1_NR_BUFS) {
+		if (++pt1->buf_index >= PT1_NR_BUFS) {
 			pt1_increment_table_count(pt1);
-			buf_index = 0;
-			if (++table_index >= pt1_nr_tables)
-				table_index = 0;
+			pt1->buf_index = 0;
+			if (++pt1->table_index >= pt1_nr_tables)
+				pt1->table_index = 0;
 		}
 	}
 
@@ -477,21 +486,60 @@
 	return ret;
 }
 
+static int pt1_start_polling(struct pt1 *pt1)
+{
+	int ret = 0;
+
+	mutex_lock(&pt1->lock);
+	if (!pt1->kthread) {
+		pt1->kthread = kthread_run(pt1_thread, pt1, "earth-pt1");
+		if (IS_ERR(pt1->kthread)) {
+			ret = PTR_ERR(pt1->kthread);
+			pt1->kthread = NULL;
+		}
+	}
+	mutex_unlock(&pt1->lock);
+	return ret;
+}
+
 static int pt1_start_feed(struct dvb_demux_feed *feed)
 {
 	struct pt1_adapter *adap;
 	adap = container_of(feed->demux, struct pt1_adapter, demux);
-	if (!adap->users++)
+	if (!adap->users++) {
+		int ret;
+
+		ret = pt1_start_polling(adap->pt1);
+		if (ret)
+			return ret;
 		pt1_set_stream(adap->pt1, adap->index, 1);
+	}
 	return 0;
 }
 
+static void pt1_stop_polling(struct pt1 *pt1)
+{
+	int i, count;
+
+	mutex_lock(&pt1->lock);
+	for (i = 0, count = 0; i < PT1_NR_ADAPS; i++)
+		count += pt1->adaps[i]->users;
+
+	if (count == 0 && pt1->kthread) {
+		kthread_stop(pt1->kthread);
+		pt1->kthread = NULL;
+	}
+	mutex_unlock(&pt1->lock);
+}
+
 static int pt1_stop_feed(struct dvb_demux_feed *feed)
 {
 	struct pt1_adapter *adap;
 	adap = container_of(feed->demux, struct pt1_adapter, demux);
-	if (!--adap->users)
+	if (!--adap->users) {
 		pt1_set_stream(adap->pt1, adap->index, 0);
+		pt1_stop_polling(adap->pt1);
+	}
 	return 0;
 }
 
@@ -575,7 +623,6 @@
 
 static void pt1_free_adapter(struct pt1_adapter *adap)
 {
-	dvb_net_release(&adap->net);
 	adap->demux.dmx.close(&adap->demux.dmx);
 	dvb_dmxdev_release(&adap->dmxdev);
 	dvb_dmx_release(&adap->demux);
@@ -616,6 +663,7 @@
 	adap->buf = buf;
 	adap->upacket_count = 0;
 	adap->packet_count = 0;
+	adap->st_count = -1;
 
 	dvb_adap = &adap->adap;
 	dvb_adap->priv = adap;
@@ -644,8 +692,6 @@
 	if (ret < 0)
 		goto err_dmx_release;
 
-	dvb_net_init(dvb_adap, &adap->net, &demux->dmx);
-
 	return adap;
 
 err_dmx_release:
@@ -1020,7 +1066,8 @@
 	pt1 = pci_get_drvdata(pdev);
 	regs = pt1->regs;
 
-	kthread_stop(pt1->kthread);
+	if (pt1->kthread)
+		kthread_stop(pt1->kthread);
 	pt1_cleanup_tables(pt1);
 	pt1_cleanup_frontends(pt1);
 	pt1_disable_ram(pt1);
@@ -1043,7 +1090,6 @@
 	void __iomem *regs;
 	struct pt1 *pt1;
 	struct i2c_adapter *i2c_adap;
-	struct task_struct *kthread;
 
 	ret = pci_enable_device(pdev);
 	if (ret < 0)
@@ -1139,17 +1185,8 @@
 	if (ret < 0)
 		goto err_pt1_cleanup_frontends;
 
-	kthread = kthread_run(pt1_thread, pt1, "pt1");
-	if (IS_ERR(kthread)) {
-		ret = PTR_ERR(kthread);
-		goto err_pt1_cleanup_tables;
-	}
-
-	pt1->kthread = kthread;
 	return 0;
 
-err_pt1_cleanup_tables:
-	pt1_cleanup_tables(pt1);
 err_pt1_cleanup_frontends:
 	pt1_cleanup_frontends(pt1);
 err_pt1_disable_ram:
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 6ecbcf6..4bd8bd5 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -53,7 +53,6 @@
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 
-#include <asm/system.h>
 
 #include <linux/dvb/frontend.h>
 
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
index 7b42ace..f6b52d5 100644
--- a/drivers/media/media-devnode.c
+++ b/drivers/media/media-devnode.c
@@ -40,7 +40,6 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/uaccess.h>
-#include <asm/system.h>
 
 #include <media/media-devnode.h>
 
@@ -312,7 +311,7 @@
 	unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
 }
 
-module_init(media_devnode_init)
+subsys_initcall(media_devnode_init);
 module_exit(media_devnode_exit)
 
 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index e954781..8db2d7f 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -43,7 +43,7 @@
 
 config RADIO_MAXIRADIO
 	tristate "Guillemot MAXI Radio FM 2000 radio"
-	depends on VIDEO_V4L2 && PCI
+	depends on VIDEO_V4L2 && PCI && SND
 	---help---
 	  Choose Y here if you have this radio card.  This card may also be
 	  found as Gemtek PCI FM.
@@ -80,6 +80,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-si4713.
 
+config USB_KEENE
+	tristate "Keene FM Transmitter USB support"
+	depends on USB && VIDEO_V4L2
+	---help---
+	  Say Y here if you want to connect this type of FM transmitter
+	  to your computer's USB port.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called radio-keene.
+
 config RADIO_TEA5764
 	tristate "TEA5764 I2C FM radio support"
 	depends on I2C && VIDEO_V4L2
@@ -167,6 +177,10 @@
 
 if V4L_RADIO_ISA_DRIVERS
 
+config RADIO_ISA
+	depends on ISA
+	tristate
+
 config RADIO_CADET
 	tristate "ADS Cadet AM/FM Tuner"
 	depends on ISA && VIDEO_V4L2
@@ -174,20 +188,13 @@
 	  Choose Y here if you have one of these AM/FM radio cards, and then
 	  fill in the port address below.
 
-	  In order to control your radio card, you will need to use programs
-	  that are compatible with the Video For Linux API.  Information on
-	  this API and pointers to "v4l" programs may be found at
-	  <file:Documentation/video4linux/API.html>.
-
-	  Further documentation on this driver can be found on the WWW at
-	  <http://linux.blackhawke.net/cadet/>.
-
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-cadet.
 
 config RADIO_RTRACK
 	tristate "AIMSlab RadioTrack (aka RadioReveal) support"
 	depends on ISA && VIDEO_V4L2
+	select RADIO_ISA
 	---help---
 	  Choose Y here if you have one of these FM radio cards, and then fill
 	  in the port address below.
@@ -201,11 +208,7 @@
 	  You must also pass the module a suitable io parameter, 0x248 has
 	  been reported to be used by these cards.
 
-	  In order to control your radio card, you will need to use programs
-	  that are compatible with the Video For Linux API.  Information on
-	  this API and pointers to "v4l" programs may be found at
-	  <file:Documentation/video4linux/API.html>. More information is
-	  contained in the file
+	  More information is contained in the file
 	  <file:Documentation/video4linux/radiotrack.txt>.
 
 	  To compile this driver as a module, choose M here: the
@@ -214,7 +217,7 @@
 config RADIO_RTRACK_PORT
 	hex "RadioTrack i/o port (0x20f or 0x30f)"
 	depends on RADIO_RTRACK=y
-	default "20f"
+	default "30f"
 	help
 	  Enter either 0x30f or 0x20f here.  The card default is 0x30f, if you
 	  haven't changed the jumper setting on the card.
@@ -222,14 +225,14 @@
 config RADIO_RTRACK2
 	tristate "AIMSlab RadioTrack II support"
 	depends on ISA && VIDEO_V4L2
+	select RADIO_ISA
 	---help---
 	  Choose Y here if you have this FM radio card, and then fill in the
 	  port address below.
 
-	  In order to control your radio card, you will need to use programs
-	  that are compatible with the Video For Linux API.  Information on
-	  this API and pointers to "v4l" programs may be found at
-	  <file:Documentation/video4linux/API.html>.
+	  Note: this driver hasn't been tested since a long time due to lack
+	  of hardware. If you have this hardware, then please contact the
+	  linux-media mailinglist.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-rtrack2.
@@ -245,15 +248,11 @@
 config RADIO_AZTECH
 	tristate "Aztech/Packard Bell Radio"
 	depends on ISA && VIDEO_V4L2
+	select RADIO_ISA
 	---help---
 	  Choose Y here if you have one of these FM radio cards, and then fill
 	  in the port address below.
 
-	  In order to control your radio card, you will need to use programs
-	  that are compatible with the Video For Linux API.  Information on
-	  this API and pointers to "v4l" programs may be found at
-	  <file:Documentation/video4linux/API.html>.
-
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-aztech.
 
@@ -269,6 +268,7 @@
 config RADIO_GEMTEK
 	tristate "GemTek Radio card (or compatible) support"
 	depends on ISA && VIDEO_V4L2
+	select RADIO_ISA
 	---help---
 	  Choose Y here if you have this FM radio card, and then fill in the
 	  I/O port address and settings below. The following cards either have
@@ -278,23 +278,21 @@
 	  - Typhoon Radio card (some models)
 	  - Hama Radio card
 
-	  In order to control your radio card, you will need to use programs
-	  that are compatible with the Video For Linux API.  Information on
-	  this API and pointers to "v4l" programs may be found at
-	  <file:Documentation/video4linux/API.html>.
-
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-gemtek.
 
 config RADIO_GEMTEK_PORT
-	hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0c24c or 0x28c)"
+	hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0x248 or 0x28c)"
 	depends on RADIO_GEMTEK=y
 	default "34c"
 	help
-	  Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is
-	  0x34c, if you haven't changed the jumper setting on the card. On
-	  Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O
+	  Enter either 0x20c, 0x30c, 0x24c, 0x34c, 0x248 or 0x28c here. The
+	  card default is 0x34c, if you haven't changed the jumper setting
+	  on the card.
+
+	  On Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O
 	  port is 0x20c, 0x248 or 0x28c.
+
 	  If automatic I/O port probing is enabled this port will be used only
 	  in case of automatic probing failure, ie. as a fallback.
 
@@ -318,11 +316,6 @@
 	  sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this
 	  is required for the radio-miropcm20.
 
-	  In order to control your radio card, you will need to use programs
-	  that are compatible with the Video For Linux API.  Information on
-	  this API and pointers to "v4l" programs may be found at
-	  <file:Documentation/video4linux/API.html>.
-
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-miropcm20.
 
@@ -332,11 +325,6 @@
 	---help---
 	  Choose Y here if you have one of these FM radio cards.
 
-	  In order to control your radio card, you will need to use programs
-	  that are compatible with the Video For Linux API.  Information on
-	  this API and pointers to "v4l" programs may be found at
-	  <file:Documentation/video4linux/API.html>.
-
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-sf16fmi.
 
@@ -346,50 +334,35 @@
 	---help---
 	  Choose Y here if you have one of these FM radio cards.
 
-	  In order to control your radio card, you will need to use programs
-	  that are compatible with the Video For Linux API.  Information on
-	  this API and pointers to "v4l" programs may be found on the WWW at
-	  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-sf16fmr2.
 
 config RADIO_TERRATEC
 	tristate "TerraTec ActiveRadio ISA Standalone"
 	depends on ISA && VIDEO_V4L2
+	select RADIO_ISA
 	---help---
-	  Choose Y here if you have this FM radio card, and then fill in the
-	  port address below. (TODO)
+	  Choose Y here if you have this FM radio card.
 
-	  Note: This driver is in its early stages.  Right now volume and
-	  frequency control and muting works at least for me, but
-	  unfortunately I have not found anybody who wants to use this card
-	  with Linux.  So if it is this what YOU are trying to do right now,
-	  PLEASE DROP ME A NOTE!!  Rolf Offermanns <rolf@offermanns.de>.
-
-	  In order to control your radio card, you will need to use programs
-	  that are compatible with the Video For Linux API.  Information on
-	  this API and pointers to "v4l" programs may be found at
-	  <file:Documentation/video4linux/API.html>.
+	  Note: this driver hasn't been tested since a long time due to lack
+	  of hardware. If you have this hardware, then please contact the
+	  linux-media mailinglist.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-terratec.
 
-config RADIO_TERRATEC_PORT
-	hex "Terratec i/o port (normally 0x590)"
-	depends on RADIO_TERRATEC=y
-	default "590"
-	help
-	  Fill in the I/O port of your TerraTec FM radio card. If unsure, go
-	  with the default.
-
 config RADIO_TRUST
 	tristate "Trust FM radio card"
 	depends on ISA && VIDEO_V4L2
+	select RADIO_ISA
 	help
 	  This is a driver for the Trust FM radio cards. Say Y if you have
 	  such a card and want to use it under Linux.
 
+	  Note: this driver hasn't been tested since a long time due to lack
+	  of hardware. If you have this hardware, then please contact the
+	  linux-media mailinglist.
+
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-trust.
 
@@ -404,14 +377,14 @@
 config RADIO_TYPHOON
 	tristate "Typhoon Radio (a.k.a. EcoRadio)"
 	depends on ISA && VIDEO_V4L2
+	select RADIO_ISA
 	---help---
 	  Choose Y here if you have one of these FM radio cards, and then fill
 	  in the port address and the frequency used for muting below.
 
-	  In order to control your radio card, you will need to use programs
-	  that are compatible with the Video For Linux API.  Information on
-	  this API and pointers to "v4l" programs may be found at
-	  <file:Documentation/video4linux/API.html>.
+	  Note: this driver hasn't been tested since a long time due to lack
+	  of hardware. If you have this hardware, then please contact the
+	  linux-media mailinglist.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-typhoon.
@@ -438,14 +411,14 @@
 config RADIO_ZOLTRIX
 	tristate "Zoltrix Radio"
 	depends on ISA && VIDEO_V4L2
+	select RADIO_ISA
 	---help---
 	  Choose Y here if you have one of these FM radio cards, and then fill
 	  in the port address below.
 
-	  In order to control your radio card, you will need to use programs
-	  that are compatible with the Video For Linux API.  Information on
-	  this API and pointers to "v4l" programs may be found at
-	  <file:Documentation/video4linux/API.html>.
+	  Note: this driver hasn't been tested since a long time due to lack
+	  of hardware. If you have this hardware, then please contact the
+	  linux-media mailinglist.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-zoltrix.
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index 390daf9..ca8c7d1 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -2,6 +2,7 @@
 # Makefile for the kernel character device drivers.
 #
 
+obj-$(CONFIG_RADIO_ISA) += radio-isa.o
 obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
 obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
 obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o
@@ -20,6 +21,7 @@
 obj-$(CONFIG_USB_DSBR) += dsbr100.o
 obj-$(CONFIG_RADIO_SI470X) += si470x/
 obj-$(CONFIG_USB_MR800) += radio-mr800.o
+obj-$(CONFIG_USB_KEENE) += radio-keene.o
 obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
 obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o
 obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 1c3f844..98e0c8c 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -1,16 +1,13 @@
-/* radiotrack (radioreveal) driver for Linux radio support
- * (c) 1997 M. Kirkwood
+/*
+ * AimsLab RadioTrack (aka RadioVeveal) driver
+ *
+ * Copyright 1997 M. Kirkwood
+ *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
  * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
  *
- * History:
- * 1999-02-24	Russell Kroll <rkroll@exploits.org>
- * 		Fine tuning/VIDEO_TUNER_LOW
- *		Frequency range expanded to start at 87 MHz
- *
- * TODO: Allow for more than one of these foolish entities :-)
- *
  * Notes on the hardware (reverse engineered from other peoples'
  * reverse engineering of AIMS' code :-)
  *
@@ -26,6 +23,7 @@
  *   wait(a_wee_while);
  *   out(port, stop_changing_the_volume);
  *
+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
  */
 
 #include <linux/module.h>	/* Modules 			*/
@@ -34,401 +32,179 @@
 #include <linux/delay.h>	/* msleep			*/
 #include <linux/videodev2.h>	/* kernel radio structs		*/
 #include <linux/io.h>		/* outb, outb_p			*/
+#include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include "radio-isa.h"
 
-MODULE_AUTHOR("M.Kirkwood");
+MODULE_AUTHOR("M. Kirkwood");
 MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("1.0.0");
 
 #ifndef CONFIG_RADIO_RTRACK_PORT
 #define CONFIG_RADIO_RTRACK_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_RTRACK_PORT;
-static int radio_nr = -1;
+#define RTRACK_MAX 2
 
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)");
-module_param(radio_nr, int, 0);
+static int io[RTRACK_MAX] = { [0] = CONFIG_RADIO_RTRACK_PORT,
+			      [1 ... (RTRACK_MAX - 1)] = -1 };
+static int radio_nr[RTRACK_MAX]	= { [0 ... (RTRACK_MAX - 1)] = -1 };
 
-struct rtrack
-{
-	struct v4l2_device v4l2_dev;
-	struct video_device vdev;
-	int port;
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the RadioTrack card (0x20f or 0x30f)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
+
+struct rtrack {
+	struct radio_isa_card isa;
 	int curvol;
-	unsigned long curfreq;
-	int muted;
-	int io;
-	struct mutex lock;
 };
 
-static struct rtrack rtrack_card;
-
-/* local things */
-
-static void rt_decvol(struct rtrack *rt)
+static struct radio_isa_card *rtrack_alloc(void)
 {
-	outb(0x58, rt->io);		/* volume down + sigstr + on	*/
-	msleep(100);
-	outb(0xd8, rt->io);		/* volume steady + sigstr + on	*/
+	struct rtrack *rt = kzalloc(sizeof(struct rtrack), GFP_KERNEL);
+
+	if (rt)
+		rt->curvol = 0xff;
+	return rt ? &rt->isa : NULL;
 }
 
-static void rt_incvol(struct rtrack *rt)
-{
-	outb(0x98, rt->io);		/* volume up + sigstr + on	*/
-	msleep(100);
-	outb(0xd8, rt->io);		/* volume steady + sigstr + on	*/
-}
-
-static void rt_mute(struct rtrack *rt)
-{
-	rt->muted = 1;
-	mutex_lock(&rt->lock);
-	outb(0xd0, rt->io);		/* volume steady, off		*/
-	mutex_unlock(&rt->lock);
-}
-
-static int rt_setvol(struct rtrack *rt, int vol)
-{
-	int i;
-
-	mutex_lock(&rt->lock);
-
-	if (vol == rt->curvol) {	/* requested volume = current */
-		if (rt->muted) {	/* user is unmuting the card  */
-			rt->muted = 0;
-			outb(0xd8, rt->io);	/* enable card */
-		}
-		mutex_unlock(&rt->lock);
-		return 0;
-	}
-
-	if (vol == 0) {			/* volume = 0 means mute the card */
-		outb(0x48, rt->io);	/* volume down but still "on"	*/
-		msleep(2000);	/* make sure it's totally down	*/
-		outb(0xd0, rt->io);	/* volume steady, off		*/
-		rt->curvol = 0;		/* track the volume state!	*/
-		mutex_unlock(&rt->lock);
-		return 0;
-	}
-
-	rt->muted = 0;
-	if (vol > rt->curvol)
-		for (i = rt->curvol; i < vol; i++)
-			rt_incvol(rt);
-	else
-		for (i = rt->curvol; i > vol; i--)
-			rt_decvol(rt);
-
-	rt->curvol = vol;
-	mutex_unlock(&rt->lock);
-	return 0;
-}
-
-/* the 128+64 on these outb's is to keep the volume stable while tuning
- * without them, the volume _will_ creep up with each frequency change
- * and bit 4 (+16) is to keep the signal strength meter enabled
+/* The 128+64 on these outb's is to keep the volume stable while tuning.
+ * Without them, the volume _will_ creep up with each frequency change
+ * and bit 4 (+16) is to keep the signal strength meter enabled.
  */
 
-static void send_0_byte(struct rtrack *rt)
+static void send_0_byte(struct radio_isa_card *isa, int on)
 {
-	if (rt->curvol == 0 || rt->muted) {
-		outb_p(128+64+16+  1, rt->io);   /* wr-enable + data low */
-		outb_p(128+64+16+2+1, rt->io);   /* clock */
-	}
-	else {
-		outb_p(128+64+16+8+  1, rt->io);  /* on + wr-enable + data low */
-		outb_p(128+64+16+8+2+1, rt->io);  /* clock */
-	}
+	outb_p(128+64+16+on+1, isa->io);	/* wr-enable + data low */
+	outb_p(128+64+16+on+2+1, isa->io);	/* clock */
 	msleep(1);
 }
 
-static void send_1_byte(struct rtrack *rt)
+static void send_1_byte(struct radio_isa_card *isa, int on)
 {
-	if (rt->curvol == 0 || rt->muted) {
-		outb_p(128+64+16+4  +1, rt->io);   /* wr-enable+data high */
-		outb_p(128+64+16+4+2+1, rt->io);   /* clock */
-	}
-	else {
-		outb_p(128+64+16+8+4  +1, rt->io); /* on+wr-enable+data high */
-		outb_p(128+64+16+8+4+2+1, rt->io); /* clock */
-	}
-
+	outb_p(128+64+16+on+4+1, isa->io);	/* wr-enable+data high */
+	outb_p(128+64+16+on+4+2+1, isa->io);	/* clock */
 	msleep(1);
 }
 
-static int rt_setfreq(struct rtrack *rt, unsigned long freq)
+static int rtrack_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
+	int on = v4l2_ctrl_g_ctrl(isa->mute) ? 0 : 8;
 	int i;
 
-	mutex_lock(&rt->lock);			/* Stop other ops interfering */
-
-	rt->curfreq = freq;
-
-	/* now uses VIDEO_TUNER_LOW for fine tuning */
-
 	freq += 171200;			/* Add 10.7 MHz IF 		*/
 	freq /= 800;			/* Convert to 50 kHz units	*/
 
-	send_0_byte(rt);		/*  0: LSB of frequency		*/
+	send_0_byte(isa, on);		/*  0: LSB of frequency		*/
 
 	for (i = 0; i < 13; i++)	/*   : frequency bits (1-13)	*/
 		if (freq & (1 << i))
-			send_1_byte(rt);
+			send_1_byte(isa, on);
 		else
-			send_0_byte(rt);
+			send_0_byte(isa, on);
 
-	send_0_byte(rt);		/* 14: test bit - always 0    */
-	send_0_byte(rt);		/* 15: test bit - always 0    */
+	send_0_byte(isa, on);		/* 14: test bit - always 0    */
+	send_0_byte(isa, on);		/* 15: test bit - always 0    */
 
-	send_0_byte(rt);		/* 16: band data 0 - always 0 */
-	send_0_byte(rt);		/* 17: band data 1 - always 0 */
-	send_0_byte(rt);		/* 18: band data 2 - always 0 */
-	send_0_byte(rt);		/* 19: time base - always 0   */
+	send_0_byte(isa, on);		/* 16: band data 0 - always 0 */
+	send_0_byte(isa, on);		/* 17: band data 1 - always 0 */
+	send_0_byte(isa, on);		/* 18: band data 2 - always 0 */
+	send_0_byte(isa, on);		/* 19: time base - always 0   */
 
-	send_0_byte(rt);		/* 20: spacing (0 = 25 kHz)   */
-	send_1_byte(rt);		/* 21: spacing (1 = 25 kHz)   */
-	send_0_byte(rt);		/* 22: spacing (0 = 25 kHz)   */
-	send_1_byte(rt);		/* 23: AM/FM (FM = 1, always) */
+	send_0_byte(isa, on);		/* 20: spacing (0 = 25 kHz)   */
+	send_1_byte(isa, on);		/* 21: spacing (1 = 25 kHz)   */
+	send_0_byte(isa, on);		/* 22: spacing (0 = 25 kHz)   */
+	send_1_byte(isa, on);		/* 23: AM/FM (FM = 1, always) */
 
-	if (rt->curvol == 0 || rt->muted)
-		outb(0xd0, rt->io);	/* volume steady + sigstr */
-	else
-		outb(0xd8, rt->io);	/* volume steady + sigstr + on */
-
-	mutex_unlock(&rt->lock);
-
+	outb(0xd0 + on, isa->io);	/* volume steady + sigstr */
 	return 0;
 }
 
-static int rt_getsigstr(struct rtrack *rt)
+static u32 rtrack_g_signal(struct radio_isa_card *isa)
 {
-	int sig = 1;
-
-	mutex_lock(&rt->lock);
-	if (inb(rt->io) & 2)	/* bit set = no signal present	*/
-		sig = 0;
-	mutex_unlock(&rt->lock);
-	return sig;
+	/* bit set = no signal present */
+	return 0xffff * !(inb(isa->io) & 2);
 }
 
-static int vidioc_querycap(struct file *file, void  *priv,
-					struct v4l2_capability *v)
+static int rtrack_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
 {
-	strlcpy(v->driver, "radio-aimslab", sizeof(v->driver));
-	strlcpy(v->card, "RadioTrack", sizeof(v->card));
-	strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-	return 0;
-}
+	struct rtrack *rt = container_of(isa, struct rtrack, isa);
+	int curvol = rt->curvol;
 
-static int vidioc_g_tuner(struct file *file, void *priv,
-					struct v4l2_tuner *v)
-{
-	struct rtrack *rt = video_drvdata(file);
-
-	if (v->index > 0)
-		return -EINVAL;
-
-	strlcpy(v->name, "FM", sizeof(v->name));
-	v->type = V4L2_TUNER_RADIO;
-	v->rangelow = 87 * 16000;
-	v->rangehigh = 108 * 16000;
-	v->rxsubchans = V4L2_TUNER_SUB_MONO;
-	v->capability = V4L2_TUNER_CAP_LOW;
-	v->audmode = V4L2_TUNER_MODE_MONO;
-	v->signal = 0xffff * rt_getsigstr(rt);
-	return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-					struct v4l2_tuner *v)
-{
-	return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-					struct v4l2_frequency *f)
-{
-	struct rtrack *rt = video_drvdata(file);
-
-	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-		return -EINVAL;
-	rt_setfreq(rt, f->frequency);
-	return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-					struct v4l2_frequency *f)
-{
-	struct rtrack *rt = video_drvdata(file);
-
-	if (f->tuner != 0)
-		return -EINVAL;
-	f->type = V4L2_TUNER_RADIO;
-	f->frequency = rt->curfreq;
-	return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-					struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-	case V4L2_CID_AUDIO_VOLUME:
-		return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff);
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct rtrack *rt = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = rt->muted;
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		ctrl->value = rt->curvol;
+	if (mute) {
+		outb(0xd0, isa->io);	/* volume steady + sigstr + off	*/
 		return 0;
 	}
-	return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct rtrack *rt = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		if (ctrl->value)
-			rt_mute(rt);
-		else
-			rt_setvol(rt, rt->curvol);
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		rt_setvol(rt, ctrl->value);
-		return 0;
+	if (vol == 0) {			/* volume = 0 means mute the card */
+		outb(0x48, isa->io);	/* volume down but still "on"	*/
+		msleep(curvol * 3);	/* make sure it's totally down	*/
+	} else if (curvol < vol) {
+		outb(0x98, isa->io);	/* volume up + sigstr + on	*/
+		for (; curvol < vol; curvol++)
+			udelay(3000);
+	} else if (curvol > vol) {
+		outb(0x58, isa->io);	/* volume down + sigstr + on	*/
+		for (; curvol > vol; curvol--)
+			udelay(3000);
 	}
-	return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-	*i = 0;
+	outb(0xd8, isa->io);		/* volume steady + sigstr + on	*/
+	rt->curvol = vol;
 	return 0;
 }
 
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+/* Mute card - prevents noisy bootups */
+static int rtrack_initialize(struct radio_isa_card *isa)
 {
-	return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
-{
-	a->index = 0;
-	strlcpy(a->name, "Radio", sizeof(a->name));
-	a->capability = V4L2_AUDCAP_STEREO;
+	/* this ensures that the volume is all the way up  */
+	outb(0x90, isa->io);	/* volume up but still "on"	*/
+	msleep(3000);		/* make sure it's totally up	*/
+	outb(0xc0, isa->io);	/* steady volume, mute card	*/
 	return 0;
 }
 
-static int vidioc_s_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
-{
-	return a->index ? -EINVAL : 0;
-}
-
-static const struct v4l2_file_operations rtrack_fops = {
-	.owner		= THIS_MODULE,
-	.unlocked_ioctl	= video_ioctl2,
+static const struct radio_isa_ops rtrack_ops = {
+	.alloc = rtrack_alloc,
+	.init = rtrack_initialize,
+	.s_mute_volume = rtrack_s_mute_volume,
+	.s_frequency = rtrack_s_frequency,
+	.g_signal = rtrack_g_signal,
 };
 
-static const struct v4l2_ioctl_ops rtrack_ioctl_ops = {
-	.vidioc_querycap    = vidioc_querycap,
-	.vidioc_g_tuner     = vidioc_g_tuner,
-	.vidioc_s_tuner     = vidioc_s_tuner,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
-	.vidioc_g_input     = vidioc_g_input,
-	.vidioc_s_input     = vidioc_s_input,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
-	.vidioc_queryctrl   = vidioc_queryctrl,
-	.vidioc_g_ctrl      = vidioc_g_ctrl,
-	.vidioc_s_ctrl      = vidioc_s_ctrl,
+static const int rtrack_ioports[] = { 0x20f, 0x30f };
+
+static struct radio_isa_driver rtrack_driver = {
+	.driver = {
+		.match		= radio_isa_match,
+		.probe		= radio_isa_probe,
+		.remove		= radio_isa_remove,
+		.driver		= {
+			.name	= "radio-aimslab",
+		},
+	},
+	.io_params = io,
+	.radio_nr_params = radio_nr,
+	.io_ports = rtrack_ioports,
+	.num_of_io_ports = ARRAY_SIZE(rtrack_ioports),
+	.region_size = 2,
+	.card = "AIMSlab RadioTrack/RadioReveal",
+	.ops = &rtrack_ops,
+	.has_stereo = true,
+	.max_volume = 0xff,
 };
 
 static int __init rtrack_init(void)
 {
-	struct rtrack *rt = &rtrack_card;
-	struct v4l2_device *v4l2_dev = &rt->v4l2_dev;
-	int res;
-
-	strlcpy(v4l2_dev->name, "rtrack", sizeof(v4l2_dev->name));
-	rt->io = io;
-
-	if (rt->io == -1) {
-		v4l2_err(v4l2_dev, "you must set an I/O address with io=0x20f or 0x30f\n");
-		return -EINVAL;
-	}
-
-	if (!request_region(rt->io, 2, "rtrack")) {
-		v4l2_err(v4l2_dev, "port 0x%x already in use\n", rt->io);
-		return -EBUSY;
-	}
-
-	res = v4l2_device_register(NULL, v4l2_dev);
-	if (res < 0) {
-		release_region(rt->io, 2);
-		v4l2_err(v4l2_dev, "could not register v4l2_device\n");
-		return res;
-	}
-
-	strlcpy(rt->vdev.name, v4l2_dev->name, sizeof(rt->vdev.name));
-	rt->vdev.v4l2_dev = v4l2_dev;
-	rt->vdev.fops = &rtrack_fops;
-	rt->vdev.ioctl_ops = &rtrack_ioctl_ops;
-	rt->vdev.release = video_device_release_empty;
-	video_set_drvdata(&rt->vdev, rt);
-
-	/* Set up the I/O locking */
-
-	mutex_init(&rt->lock);
-
-	/* mute card - prevents noisy bootups */
-
-	/* this ensures that the volume is all the way down  */
-	outb(0x48, rt->io);		/* volume down but still "on"	*/
-	msleep(2000);	/* make sure it's totally down	*/
-	outb(0xc0, rt->io);		/* steady volume, mute card	*/
-
-	if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-		v4l2_device_unregister(&rt->v4l2_dev);
-		release_region(rt->io, 2);
-		return -EINVAL;
-	}
-	v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n");
-
-	return 0;
+	return isa_register_driver(&rtrack_driver.driver, RTRACK_MAX);
 }
 
 static void __exit rtrack_exit(void)
 {
-	struct rtrack *rt = &rtrack_card;
-
-	video_unregister_device(&rt->vdev);
-	v4l2_device_unregister(&rt->v4l2_dev);
-	release_region(rt->io, 2);
+	isa_unregister_driver(&rtrack_driver.driver);
 }
 
 module_init(rtrack_init);
 module_exit(rtrack_exit);
-
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index eed7b08..177bcbd 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -1,5 +1,7 @@
-/* radio-aztech.c - Aztech radio card driver for Linux 2.2
+/*
+ * radio-aztech.c - Aztech radio card driver
  *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@xs4all.nl>
  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  * Adapted to support the Video for Linux API by
  * Russell Kroll <rkroll@exploits.org>.  Based on original tuner code by:
@@ -10,19 +12,7 @@
  * Scott McGrath    (smcgrath@twilight.vtc.vsc.edu)
  * William McGrath  (wmcgrath@twilight.vtc.vsc.edu)
  *
- * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/
- * along with more information on the card itself.
- *
- * History:
- * 1999-02-24	Russell Kroll <rkroll@exploits.org>
- *		Fine tuning/VIDEO_TUNER_LOW
- * 		Range expanded to 87-108 MHz (from 87.9-107.8)
- *
- * Notable changes from the original source:
- * - includes stripped down to the essentials
- * - for loops used as delays replaced with udelay()
- * - #defines removed, changed to static values
- * - tuning structure changed - no more character arrays, other changes
+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
 */
 
 #include <linux/module.h>	/* Modules 			*/
@@ -31,126 +21,72 @@
 #include <linux/delay.h>	/* udelay			*/
 #include <linux/videodev2.h>	/* kernel radio structs		*/
 #include <linux/io.h>		/* outb, outb_p			*/
+#include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include "radio-isa.h"
 
 MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
 MODULE_DESCRIPTION("A driver for the Aztech radio card.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("1.0.0");
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
-
 #ifndef CONFIG_RADIO_AZTECH_PORT
 #define CONFIG_RADIO_AZTECH_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_AZTECH_PORT;
-static int radio_nr = -1;
-static int radio_wait_time = 1000;
+#define AZTECH_MAX 2
 
-module_param(io, int, 0);
-module_param(radio_nr, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)");
+static int io[AZTECH_MAX] = { [0] = CONFIG_RADIO_AZTECH_PORT,
+			      [1 ... (AZTECH_MAX - 1)] = -1 };
+static int radio_nr[AZTECH_MAX]	= { [0 ... (AZTECH_MAX - 1)] = -1 };
+static const int radio_wait_time = 1000;
 
-struct aztech
-{
-	struct v4l2_device v4l2_dev;
-	struct video_device vdev;
-	int io;
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the Aztech card (0x350 or 0x358)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
+
+struct aztech {
+	struct radio_isa_card isa;
 	int curvol;
-	unsigned long curfreq;
-	int stereo;
-	struct mutex lock;
 };
 
-static struct aztech aztech_card;
-
-static int volconvert(int level)
-{
-	level >>= 14;		/* Map 16bits down to 2 bit */
-	level &= 3;
-
-	/* convert to card-friendly values */
-	switch (level) {
-	case 0:
-		return 0;
-	case 1:
-		return 1;
-	case 2:
-		return 4;
-	case 3:
-		return 5;
-	}
-	return 0;	/* Quieten gcc */
-}
-
 static void send_0_byte(struct aztech *az)
 {
 	udelay(radio_wait_time);
-	outb_p(2 + volconvert(az->curvol), az->io);
-	outb_p(64 + 2 + volconvert(az->curvol), az->io);
+	outb_p(2 + az->curvol, az->isa.io);
+	outb_p(64 + 2 + az->curvol, az->isa.io);
 }
 
 static void send_1_byte(struct aztech *az)
 {
-	udelay (radio_wait_time);
-	outb_p(128 + 2 + volconvert(az->curvol), az->io);
-	outb_p(128 + 64 + 2 + volconvert(az->curvol), az->io);
+	udelay(radio_wait_time);
+	outb_p(128 + 2 + az->curvol, az->isa.io);
+	outb_p(128 + 64 + 2 + az->curvol, az->isa.io);
 }
 
-static int az_setvol(struct aztech *az, int vol)
+static struct radio_isa_card *aztech_alloc(void)
 {
-	mutex_lock(&az->lock);
-	outb(volconvert(vol), az->io);
-	mutex_unlock(&az->lock);
-	return 0;
+	struct aztech *az = kzalloc(sizeof(*az), GFP_KERNEL);
+
+	return az ? &az->isa : NULL;
 }
 
-/* thanks to Michael Dwyer for giving me a dose of clues in
- * the signal strength department..
- *
- * This card has a stereo bit - bit 0 set = mono, not set = stereo
- * It also has a "signal" bit - bit 1 set = bad signal, not set = good
- *
- */
-
-static int az_getsigstr(struct aztech *az)
+static int aztech_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
-	int sig = 1;
-
-	mutex_lock(&az->lock);
-	if (inb(az->io) & 2)	/* bit set = no signal present */
-		sig = 0;
-	mutex_unlock(&az->lock);
-	return sig;
-}
-
-static int az_getstereo(struct aztech *az)
-{
-	int stereo = 1;
-
-	mutex_lock(&az->lock);
-	if (inb(az->io) & 1) 	/* bit set = mono */
-		stereo = 0;
-	mutex_unlock(&az->lock);
-	return stereo;
-}
-
-static int az_setfreq(struct aztech *az, unsigned long frequency)
-{
+	struct aztech *az = container_of(isa, struct aztech, isa);
 	int  i;
 
-	mutex_lock(&az->lock);
-
-	az->curfreq = frequency;
-	frequency += 171200;		/* Add 10.7 MHz IF		*/
-	frequency /= 800;		/* Convert to 50 kHz units	*/
+	freq += 171200;			/* Add 10.7 MHz IF		*/
+	freq /= 800;			/* Convert to 50 kHz units	*/
 
 	send_0_byte(az);		/*  0: LSB of frequency       */
 
 	for (i = 0; i < 13; i++)	/*   : frequency bits (1-13)  */
-		if (frequency & (1 << i))
+		if (freq & (1 << i))
 			send_1_byte(az);
 		else
 			send_0_byte(az);
@@ -158,7 +94,7 @@
 	send_0_byte(az);		/* 14: test bit - always 0    */
 	send_0_byte(az);		/* 15: test bit - always 0    */
 	send_0_byte(az);		/* 16: band data 0 - always 0 */
-	if (az->stereo)		/* 17: stereo (1 to enable)   */
+	if (isa->stereo)		/* 17: stereo (1 to enable)   */
 		send_1_byte(az);
 	else
 		send_0_byte(az);
@@ -173,225 +109,77 @@
 	/* latch frequency */
 
 	udelay(radio_wait_time);
-	outb_p(128 + 64 + volconvert(az->curvol), az->io);
-
-	mutex_unlock(&az->lock);
+	outb_p(128 + 64 + az->curvol, az->isa.io);
 
 	return 0;
 }
 
-static int vidioc_querycap(struct file *file, void  *priv,
-					struct v4l2_capability *v)
+/* thanks to Michael Dwyer for giving me a dose of clues in
+ * the signal strength department..
+ *
+ * This card has a stereo bit - bit 0 set = mono, not set = stereo
+ */
+static u32 aztech_g_rxsubchans(struct radio_isa_card *isa)
 {
-	strlcpy(v->driver, "radio-aztech", sizeof(v->driver));
-	strlcpy(v->card, "Aztech Radio", sizeof(v->card));
-	strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	if (inb(isa->io) & 1)
+		return V4L2_TUNER_SUB_MONO;
+	return V4L2_TUNER_SUB_STEREO;
+}
+
+static int aztech_s_stereo(struct radio_isa_card *isa, bool stereo)
+{
+	return aztech_s_frequency(isa, isa->freq);
+}
+
+static int aztech_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
+{
+	struct aztech *az = container_of(isa, struct aztech, isa);
+
+	if (mute)
+		vol = 0;
+	az->curvol = (vol & 1) + ((vol & 2) << 1);
+	outb(az->curvol, isa->io);
 	return 0;
 }
 
-static int vidioc_g_tuner(struct file *file, void *priv,
-				struct v4l2_tuner *v)
-{
-	struct aztech *az = video_drvdata(file);
-
-	if (v->index > 0)
-		return -EINVAL;
-
-	strlcpy(v->name, "FM", sizeof(v->name));
-	v->type = V4L2_TUNER_RADIO;
-
-	v->rangelow = 87 * 16000;
-	v->rangehigh = 108 * 16000;
-	v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-	v->capability = V4L2_TUNER_CAP_LOW;
-	if (az_getstereo(az))
-		v->audmode = V4L2_TUNER_MODE_STEREO;
-	else
-		v->audmode = V4L2_TUNER_MODE_MONO;
-	v->signal = 0xFFFF * az_getsigstr(az);
-
-	return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-				struct v4l2_tuner *v)
-{
-	return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-	*i = 0;
-	return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-	return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-			   struct v4l2_audio *a)
-{
-	a->index = 0;
-	strlcpy(a->name, "Radio", sizeof(a->name));
-	a->capability = V4L2_AUDCAP_STEREO;
-	return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-			   struct v4l2_audio *a)
-{
-	return a->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-				struct v4l2_frequency *f)
-{
-	struct aztech *az = video_drvdata(file);
-
-	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-		return -EINVAL;
-	az_setfreq(az, f->frequency);
-	return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-				struct v4l2_frequency *f)
-{
-	struct aztech *az = video_drvdata(file);
-
-	if (f->tuner != 0)
-		return -EINVAL;
-	f->type = V4L2_TUNER_RADIO;
-	f->frequency = az->curfreq;
-	return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-			    struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-	case V4L2_CID_AUDIO_VOLUME:
-		return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff);
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-			    struct v4l2_control *ctrl)
-{
-	struct aztech *az = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		if (az->curvol == 0)
-			ctrl->value = 1;
-		else
-			ctrl->value = 0;
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		ctrl->value = az->curvol * 6554;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-			    struct v4l2_control *ctrl)
-{
-	struct aztech *az = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		if (ctrl->value)
-			az_setvol(az, 0);
-		else
-			az_setvol(az, az->curvol);
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		az_setvol(az, ctrl->value);
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static const struct v4l2_file_operations aztech_fops = {
-	.owner		= THIS_MODULE,
-	.unlocked_ioctl	= video_ioctl2,
+static const struct radio_isa_ops aztech_ops = {
+	.alloc = aztech_alloc,
+	.s_mute_volume = aztech_s_mute_volume,
+	.s_frequency = aztech_s_frequency,
+	.s_stereo = aztech_s_stereo,
+	.g_rxsubchans = aztech_g_rxsubchans,
 };
 
-static const struct v4l2_ioctl_ops aztech_ioctl_ops = {
-	.vidioc_querycap    = vidioc_querycap,
-	.vidioc_g_tuner     = vidioc_g_tuner,
-	.vidioc_s_tuner     = vidioc_s_tuner,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
-	.vidioc_g_input     = vidioc_g_input,
-	.vidioc_s_input     = vidioc_s_input,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
-	.vidioc_queryctrl   = vidioc_queryctrl,
-	.vidioc_g_ctrl      = vidioc_g_ctrl,
-	.vidioc_s_ctrl      = vidioc_s_ctrl,
+static const int aztech_ioports[] = { 0x350, 0x358 };
+
+static struct radio_isa_driver aztech_driver = {
+	.driver = {
+		.match		= radio_isa_match,
+		.probe		= radio_isa_probe,
+		.remove		= radio_isa_remove,
+		.driver		= {
+			.name	= "radio-aztech",
+		},
+	},
+	.io_params = io,
+	.radio_nr_params = radio_nr,
+	.io_ports = aztech_ioports,
+	.num_of_io_ports = ARRAY_SIZE(aztech_ioports),
+	.region_size = 2,
+	.card = "Aztech Radio",
+	.ops = &aztech_ops,
+	.has_stereo = true,
+	.max_volume = 3,
 };
 
 static int __init aztech_init(void)
 {
-	struct aztech *az = &aztech_card;
-	struct v4l2_device *v4l2_dev = &az->v4l2_dev;
-	int res;
-
-	strlcpy(v4l2_dev->name, "aztech", sizeof(v4l2_dev->name));
-	az->io = io;
-
-	if (az->io == -1) {
-		v4l2_err(v4l2_dev, "you must set an I/O address with io=0x350 or 0x358\n");
-		return -EINVAL;
-	}
-
-	if (!request_region(az->io, 2, "aztech")) {
-		v4l2_err(v4l2_dev, "port 0x%x already in use\n", az->io);
-		return -EBUSY;
-	}
-
-	res = v4l2_device_register(NULL, v4l2_dev);
-	if (res < 0) {
-		release_region(az->io, 2);
-		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-		return res;
-	}
-
-	mutex_init(&az->lock);
-	strlcpy(az->vdev.name, v4l2_dev->name, sizeof(az->vdev.name));
-	az->vdev.v4l2_dev = v4l2_dev;
-	az->vdev.fops = &aztech_fops;
-	az->vdev.ioctl_ops = &aztech_ioctl_ops;
-	az->vdev.release = video_device_release_empty;
-	video_set_drvdata(&az->vdev, az);
-	/* mute card - prevents noisy bootups */
-	outb(0, az->io);
-
-	if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-		v4l2_device_unregister(v4l2_dev);
-		release_region(az->io, 2);
-		return -EINVAL;
-	}
-
-	v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
-	return 0;
+	return isa_register_driver(&aztech_driver.driver, AZTECH_MAX);
 }
 
 static void __exit aztech_exit(void)
 {
-	struct aztech *az = &aztech_card;
-
-	video_unregister_device(&az->vdev);
-	v4l2_device_unregister(&az->v4l2_dev);
-	release_region(az->io, 2);
+	isa_unregister_driver(&aztech_driver.driver);
 }
 
 module_init(aztech_init);
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 36ce061..2e639ce 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -1,4 +1,7 @@
-/* GemTek radio card driver for Linux (C) 1998 Jonas Munsin <jmunsin@iki.fi>
+/*
+ * GemTek radio card driver
+ *
+ * Copyright 1998 Jonas Munsin <jmunsin@iki.fi>
  *
  * GemTek hasn't released any specs on the card, so the protocol had to
  * be reverse engineered with dosemu.
@@ -11,9 +14,12 @@
  *    Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
  *    Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
  *
- * TODO: Allow for more than one of these foolish entities :-)
- *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Note: this card seems to swap the left and right audio channels!
+ *
+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
  */
 
 #include <linux/module.h>	/* Modules 			*/
@@ -23,8 +29,10 @@
 #include <linux/videodev2.h>	/* kernel radio structs		*/
 #include <linux/mutex.h>
 #include <linux/io.h>		/* outb, outb_p			*/
+#include <linux/slab.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
+#include "radio-isa.h"
 
 /*
  * Module info.
@@ -33,7 +41,7 @@
 MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen <pexu@kapsi.fi>");
 MODULE_DESCRIPTION("A driver for the GemTek Radio card.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.4");
+MODULE_VERSION("1.0.0");
 
 /*
  * Module params.
@@ -46,45 +54,29 @@
 #define CONFIG_RADIO_GEMTEK_PROBE 1
 #endif
 
-static int io		= CONFIG_RADIO_GEMTEK_PORT;
-static bool probe	= CONFIG_RADIO_GEMTEK_PROBE;
-static bool hardmute;
-static bool shutdown	= 1;
-static bool keepmuted	= 1;
-static bool initmute	= 1;
-static int radio_nr	= -1;
+#define GEMTEK_MAX 4
 
-module_param(io, int, 0444);
-MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic "
+static bool probe = CONFIG_RADIO_GEMTEK_PROBE;
+static bool hardmute;
+static int io[GEMTEK_MAX] = { [0] = CONFIG_RADIO_GEMTEK_PORT,
+			      [1 ... (GEMTEK_MAX - 1)] = -1 };
+static int radio_nr[GEMTEK_MAX]	= { [0 ... (GEMTEK_MAX - 1)] = -1 };
+
+module_param(probe, bool, 0444);
+MODULE_PARM_DESC(probe, "Enable automatic device probing.");
+
+module_param(hardmute, bool, 0644);
+MODULE_PARM_DESC(hardmute, "Enable 'hard muting' by shutting down PLL, may "
+	 "reduce static noise.");
+
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "Force I/O ports for the GemTek Radio card if automatic "
 	 "probing is disabled or fails. The most common I/O ports are: 0x20c "
 	 "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to "
 	 "work for the combined sound/radiocard).");
 
-module_param(probe, bool, 0444);
-MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most "
-	"common I/O ports used by the card are probed.");
-
-module_param(hardmute, bool, 0644);
-MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may "
-	 "reduce static noise.");
-
-module_param(shutdown, bool, 0644);
-MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when "
-	 "module is unloaded.");
-
-module_param(keepmuted, bool, 0644);
-MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed.");
-
-module_param(initmute, bool, 0444);
-MODULE_PARM_DESC(initmute, "Mute card when module is loaded.");
-
-module_param(radio_nr, int, 0444);
-
-/*
- * Functions for controlling the card.
- */
-#define GEMTEK_LOWFREQ	(87*16000)
-#define GEMTEK_HIGHFREQ	(108*16000)
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
 
 /*
  * Frequency calculation constants.  Intermediate frequency 10.52 MHz (nominal
@@ -108,18 +100,11 @@
 #define LONG_DELAY 75		/* usec */
 
 struct gemtek {
-	struct v4l2_device v4l2_dev;
-	struct video_device vdev;
-	struct mutex lock;
-	unsigned long lastfreq;
-	int muted;
-	int verified;
-	int io;
+	struct radio_isa_card isa;
+	bool muted;
 	u32 bu2614data;
 };
 
-static struct gemtek gemtek_card;
-
 #define BU2614_FREQ_BITS 	16 /* D0..D15, Frequency data		*/
 #define BU2614_PORT_BITS	3 /* P0..P2, Output port control data	*/
 #define BU2614_VOID_BITS	4 /* unused 				*/
@@ -166,31 +151,24 @@
  */
 static void gemtek_bu2614_transmit(struct gemtek *gt)
 {
+	struct radio_isa_card *isa = &gt->isa;
 	int i, bit, q, mute;
 
-	mutex_lock(&gt->lock);
-
 	mute = gt->muted ? GEMTEK_MT : 0x00;
 
-	outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io);
-	udelay(SHORT_DELAY);
-	outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io);
+	outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, isa->io);
 	udelay(LONG_DELAY);
 
 	for (i = 0, q = gt->bu2614data; i < 32; i++, q >>= 1) {
 		bit = (q & 1) ? GEMTEK_DA : 0;
-		outb_p(mute | GEMTEK_CE | bit, gt->io);
+		outb_p(mute | GEMTEK_CE | bit, isa->io);
 		udelay(SHORT_DELAY);
-		outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, gt->io);
+		outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, isa->io);
 		udelay(SHORT_DELAY);
 	}
 
-	outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io);
+	outb_p(mute | GEMTEK_DA | GEMTEK_CK, isa->io);
 	udelay(SHORT_DELAY);
-	outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io);
-	udelay(LONG_DELAY);
-
-	mutex_unlock(&gt->lock);
 }
 
 /*
@@ -198,21 +176,27 @@
  */
 static unsigned long gemtek_convfreq(unsigned long freq)
 {
-	return ((freq<<FSCALE) + IF_OFFSET + REF_FREQ/2) / REF_FREQ;
+	return ((freq << FSCALE) + IF_OFFSET + REF_FREQ / 2) / REF_FREQ;
+}
+
+static struct radio_isa_card *gemtek_alloc(void)
+{
+	struct gemtek *gt = kzalloc(sizeof(*gt), GFP_KERNEL);
+
+	if (gt)
+		gt->muted = true;
+	return gt ? &gt->isa : NULL;
 }
 
 /*
  * Set FM-frequency.
  */
-static void gemtek_setfreq(struct gemtek *gt, unsigned long freq)
+static int gemtek_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
-	if (keepmuted && hardmute && gt->muted)
-		return;
+	struct gemtek *gt = container_of(isa, struct gemtek, isa);
 
-	freq = clamp_val(freq, GEMTEK_LOWFREQ, GEMTEK_HIGHFREQ);
-
-	gt->lastfreq = freq;
-	gt->muted = 0;
+	if (hardmute && gt->muted)
+		return 0;
 
 	gemtek_bu2614_set(gt, BU2614_PORT, 0);
 	gemtek_bu2614_set(gt, BU2614_FMES, 0);
@@ -220,23 +204,25 @@
 	gemtek_bu2614_set(gt, BU2614_SWAL, 0);
 	gemtek_bu2614_set(gt, BU2614_FMUN, 1);	/* GT bit set	*/
 	gemtek_bu2614_set(gt, BU2614_TEST, 0);
-
 	gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_STDF_3_125_KHZ);
 	gemtek_bu2614_set(gt, BU2614_FREQ, gemtek_convfreq(freq));
-
 	gemtek_bu2614_transmit(gt);
+	return 0;
 }
 
 /*
  * Set mute flag.
  */
-static void gemtek_mute(struct gemtek *gt)
+static int gemtek_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
 {
+	struct gemtek *gt = container_of(isa, struct gemtek, isa);
 	int i;
 
-	gt->muted = 1;
-
+	gt->muted = mute;
 	if (hardmute) {
+		if (!mute)
+			return gemtek_s_frequency(isa, isa->freq);
+
 		/* Turn off PLL, disable data output */
 		gemtek_bu2614_set(gt, BU2614_PORT, 0);
 		gemtek_bu2614_set(gt, BU2614_FMES, 0);	/* CT bit off	*/
@@ -247,367 +233,85 @@
 		gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_PLL_OFF);
 		gemtek_bu2614_set(gt, BU2614_FREQ, 0);
 		gemtek_bu2614_transmit(gt);
-		return;
+		return 0;
 	}
 
-	mutex_lock(&gt->lock);
-
 	/* Read bus contents (CE, CK and DA). */
-	i = inb_p(gt->io);
+	i = inb_p(isa->io);
 	/* Write it back with mute flag set. */
-	outb_p((i >> 5) | GEMTEK_MT, gt->io);
+	outb_p((i >> 5) | (mute ? GEMTEK_MT : 0), isa->io);
 	udelay(SHORT_DELAY);
-
-	mutex_unlock(&gt->lock);
+	return 0;
 }
 
-/*
- * Unset mute flag.
- */
-static void gemtek_unmute(struct gemtek *gt)
+static u32 gemtek_g_rxsubchans(struct radio_isa_card *isa)
 {
-	int i;
-
-	gt->muted = 0;
-	if (hardmute) {
-		/* Turn PLL back on. */
-		gemtek_setfreq(gt, gt->lastfreq);
-		return;
-	}
-	mutex_lock(&gt->lock);
-
-	i = inb_p(gt->io);
-	outb_p(i >> 5, gt->io);
-	udelay(SHORT_DELAY);
-
-	mutex_unlock(&gt->lock);
-}
-
-/*
- * Get signal strength (= stereo status).
- */
-static inline int gemtek_getsigstr(struct gemtek *gt)
-{
-	int sig;
-
-	mutex_lock(&gt->lock);
-	sig = inb_p(gt->io) & GEMTEK_NS ? 0 : 1;
-	mutex_unlock(&gt->lock);
-	return sig;
+	if (inb_p(isa->io) & GEMTEK_NS)
+		return V4L2_TUNER_SUB_MONO;
+	return V4L2_TUNER_SUB_STEREO;
 }
 
 /*
  * Check if requested card acts like GemTek Radio card.
  */
-static int gemtek_verify(struct gemtek *gt, int port)
+static bool gemtek_probe(struct radio_isa_card *isa, int io)
 {
 	int i, q;
 
-	if (gt->verified == port)
-		return 1;
-
-	mutex_lock(&gt->lock);
-
-	q = inb_p(port);	/* Read bus contents before probing. */
+	q = inb_p(io);	/* Read bus contents before probing. */
 	/* Try to turn on CE, CK and DA respectively and check if card responds
 	   properly. */
 	for (i = 0; i < 3; ++i) {
-		outb_p(1 << i, port);
+		outb_p(1 << i, io);
 		udelay(SHORT_DELAY);
 
-		if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) {
-			mutex_unlock(&gt->lock);
-			return 0;
-		}
+		if ((inb_p(io) & ~GEMTEK_NS) != (0x17 | (1 << (i + 5))))
+			return false;
 	}
-	outb_p(q >> 5, port);	/* Write bus contents back. */
+	outb_p(q >> 5, io);	/* Write bus contents back. */
 	udelay(SHORT_DELAY);
-
-	mutex_unlock(&gt->lock);
-	gt->verified = port;
-
-	return 1;
+	return true;
 }
 
-/*
- * Automatic probing for card.
- */
-static int gemtek_probe(struct gemtek *gt)
-{
-	struct v4l2_device *v4l2_dev = &gt->v4l2_dev;
-	int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c };
-	int i;
-
-	if (!probe) {
-		v4l2_info(v4l2_dev, "Automatic device probing disabled.\n");
-		return -1;
-	}
-
-	v4l2_info(v4l2_dev, "Automatic device probing enabled.\n");
-
-	for (i = 0; i < ARRAY_SIZE(ioports); ++i) {
-		v4l2_info(v4l2_dev, "Trying I/O port 0x%x...\n", ioports[i]);
-
-		if (!request_region(ioports[i], 1, "gemtek-probe")) {
-			v4l2_warn(v4l2_dev, "I/O port 0x%x busy!\n",
-			       ioports[i]);
-			continue;
-		}
-
-		if (gemtek_verify(gt, ioports[i])) {
-			v4l2_info(v4l2_dev, "Card found from I/O port "
-			       "0x%x!\n", ioports[i]);
-
-			release_region(ioports[i], 1);
-			gt->io = ioports[i];
-			return gt->io;
-		}
-
-		release_region(ioports[i], 1);
-	}
-
-	v4l2_err(v4l2_dev, "Automatic probing failed!\n");
-	return -1;
-}
-
-/*
- * Video 4 Linux stuff.
- */
-
-static const struct v4l2_file_operations gemtek_fops = {
-	.owner		= THIS_MODULE,
-	.unlocked_ioctl	= video_ioctl2,
+static const struct radio_isa_ops gemtek_ops = {
+	.alloc = gemtek_alloc,
+	.probe = gemtek_probe,
+	.s_mute_volume = gemtek_s_mute_volume,
+	.s_frequency = gemtek_s_frequency,
+	.g_rxsubchans = gemtek_g_rxsubchans,
 };
 
-static int vidioc_querycap(struct file *file, void *priv,
-			   struct v4l2_capability *v)
-{
-	strlcpy(v->driver, "radio-gemtek", sizeof(v->driver));
-	strlcpy(v->card, "GemTek", sizeof(v->card));
-	strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-	return 0;
-}
+static const int gemtek_ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c };
 
-static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
-{
-	struct gemtek *gt = video_drvdata(file);
-
-	if (v->index > 0)
-		return -EINVAL;
-
-	strlcpy(v->name, "FM", sizeof(v->name));
-	v->type = V4L2_TUNER_RADIO;
-	v->rangelow = GEMTEK_LOWFREQ;
-	v->rangehigh = GEMTEK_HIGHFREQ;
-	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
-	v->signal = 0xffff * gemtek_getsigstr(gt);
-	if (v->signal) {
-		v->audmode = V4L2_TUNER_MODE_STEREO;
-		v->rxsubchans = V4L2_TUNER_SUB_STEREO;
-	} else {
-		v->audmode = V4L2_TUNER_MODE_MONO;
-		v->rxsubchans = V4L2_TUNER_SUB_MONO;
-	}
-	return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
-{
-	return (v->index != 0) ? -EINVAL : 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-			      struct v4l2_frequency *f)
-{
-	struct gemtek *gt = video_drvdata(file);
-
-	if (f->tuner != 0)
-		return -EINVAL;
-	f->type = V4L2_TUNER_RADIO;
-	f->frequency = gt->lastfreq;
-	return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-			      struct v4l2_frequency *f)
-{
-	struct gemtek *gt = video_drvdata(file);
-
-	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-		return -EINVAL;
-	gemtek_setfreq(gt, f->frequency);
-	return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-			    struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
-	default:
-		return -EINVAL;
-	}
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-			 struct v4l2_control *ctrl)
-{
-	struct gemtek *gt = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = gt->muted;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-			 struct v4l2_control *ctrl)
-{
-	struct gemtek *gt = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		if (ctrl->value)
-			gemtek_mute(gt);
-		else
-			gemtek_unmute(gt);
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-	*i = 0;
-	return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-	return (i != 0) ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
-	a->index = 0;
-	strlcpy(a->name, "Radio", sizeof(a->name));
-	a->capability = V4L2_AUDCAP_STEREO;
-	return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
-	return (a->index != 0) ? -EINVAL : 0;
-}
-
-static const struct v4l2_ioctl_ops gemtek_ioctl_ops = {
-	.vidioc_querycap	= vidioc_querycap,
-	.vidioc_g_tuner		= vidioc_g_tuner,
-	.vidioc_s_tuner		= vidioc_s_tuner,
-	.vidioc_g_audio		= vidioc_g_audio,
-	.vidioc_s_audio		= vidioc_s_audio,
-	.vidioc_g_input		= vidioc_g_input,
-	.vidioc_s_input		= vidioc_s_input,
-	.vidioc_g_frequency	= vidioc_g_frequency,
-	.vidioc_s_frequency	= vidioc_s_frequency,
-	.vidioc_queryctrl	= vidioc_queryctrl,
-	.vidioc_g_ctrl		= vidioc_g_ctrl,
-	.vidioc_s_ctrl		= vidioc_s_ctrl
+static struct radio_isa_driver gemtek_driver = {
+	.driver = {
+		.match		= radio_isa_match,
+		.probe		= radio_isa_probe,
+		.remove		= radio_isa_remove,
+		.driver		= {
+			.name	= "radio-gemtek",
+		},
+	},
+	.io_params = io,
+	.radio_nr_params = radio_nr,
+	.io_ports = gemtek_ioports,
+	.num_of_io_ports = ARRAY_SIZE(gemtek_ioports),
+	.region_size = 1,
+	.card = "GemTek Radio",
+	.ops = &gemtek_ops,
+	.has_stereo = true,
 };
 
-/*
- * Initialization / cleanup related stuff.
- */
-
 static int __init gemtek_init(void)
 {
-	struct gemtek *gt = &gemtek_card;
-	struct v4l2_device *v4l2_dev = &gt->v4l2_dev;
-	int res;
-
-	strlcpy(v4l2_dev->name, "gemtek", sizeof(v4l2_dev->name));
-
-	v4l2_info(v4l2_dev, "GemTek Radio card driver: v0.0.3\n");
-
-	mutex_init(&gt->lock);
-
-	gt->verified = -1;
-	gt->io = io;
-	gemtek_probe(gt);
-	if (gt->io) {
-		if (!request_region(gt->io, 1, "gemtek")) {
-			v4l2_err(v4l2_dev, "I/O port 0x%x already in use.\n", gt->io);
-			return -EBUSY;
-		}
-
-		if (!gemtek_verify(gt, gt->io))
-			v4l2_warn(v4l2_dev, "Card at I/O port 0x%x does not "
-			       "respond properly, check your "
-			       "configuration.\n", gt->io);
-		else
-			v4l2_info(v4l2_dev, "Using I/O port 0x%x.\n", gt->io);
-	} else if (probe) {
-		v4l2_err(v4l2_dev, "Automatic probing failed and no "
-		       "fixed I/O port defined.\n");
-		return -ENODEV;
-	} else {
-		v4l2_err(v4l2_dev, "Automatic probing disabled but no fixed "
-		       "I/O port defined.");
-		return -EINVAL;
-	}
-
-	res = v4l2_device_register(NULL, v4l2_dev);
-	if (res < 0) {
-		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-		release_region(gt->io, 1);
-		return res;
-	}
-
-	strlcpy(gt->vdev.name, v4l2_dev->name, sizeof(gt->vdev.name));
-	gt->vdev.v4l2_dev = v4l2_dev;
-	gt->vdev.fops = &gemtek_fops;
-	gt->vdev.ioctl_ops = &gemtek_ioctl_ops;
-	gt->vdev.release = video_device_release_empty;
-	video_set_drvdata(&gt->vdev, gt);
-
-	/* Set defaults */
-	gt->lastfreq = GEMTEK_LOWFREQ;
-	gt->bu2614data = 0;
-
-	if (initmute)
-		gemtek_mute(gt);
-
-	if (video_register_device(&gt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-		v4l2_device_unregister(v4l2_dev);
-		release_region(gt->io, 1);
-		return -EBUSY;
-	}
-
-	return 0;
+	gemtek_driver.probe = probe;
+	return isa_register_driver(&gemtek_driver.driver, GEMTEK_MAX);
 }
 
-/*
- * Module cleanup
- */
 static void __exit gemtek_exit(void)
 {
-	struct gemtek *gt = &gemtek_card;
-	struct v4l2_device *v4l2_dev = &gt->v4l2_dev;
-
-	if (shutdown) {
-		hardmute = 1;	/* Turn off PLL */
-		gemtek_mute(gt);
-	} else {
-		v4l2_info(v4l2_dev, "Module unloaded but card not muted!\n");
-	}
-
-	video_unregister_device(&gt->vdev);
-	v4l2_device_unregister(&gt->v4l2_dev);
-	release_region(gt->io, 1);
+	hardmute = 1;	/* Turn off PLL */
+	isa_unregister_driver(&gemtek_driver.driver);
 }
 
 module_init(gemtek_init);
diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c
new file mode 100644
index 0000000..06f9063
--- /dev/null
+++ b/drivers/media/radio/radio-isa.c
@@ -0,0 +1,340 @@
+/*
+ * Framework for ISA radio drivers.
+ * This takes care of all the V4L2 scaffolding, allowing the ISA drivers
+ * to concentrate on the actual hardware operation.
+ *
+ * Copyright (C) 2012 Hans Verkuil <hans.verkuil@cisco.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/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+
+#include "radio-isa.h"
+
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_DESCRIPTION("A framework for ISA radio drivers.");
+MODULE_LICENSE("GPL");
+
+#define FREQ_LOW  (87U * 16000U)
+#define FREQ_HIGH (108U * 16000U)
+
+static int radio_isa_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *v)
+{
+	struct radio_isa_card *isa = video_drvdata(file);
+
+	strlcpy(v->driver, isa->drv->driver.driver.name, sizeof(v->driver));
+	strlcpy(v->card, isa->drv->card, sizeof(v->card));
+	snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name);
+
+	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	v->device_caps = v->capabilities | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int radio_isa_g_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *v)
+{
+	struct radio_isa_card *isa = video_drvdata(file);
+	const struct radio_isa_ops *ops = isa->drv->ops;
+
+	if (v->index > 0)
+		return -EINVAL;
+
+	strlcpy(v->name, "FM", sizeof(v->name));
+	v->type = V4L2_TUNER_RADIO;
+	v->rangelow = FREQ_LOW;
+	v->rangehigh = FREQ_HIGH;
+	v->capability = V4L2_TUNER_CAP_LOW;
+	if (isa->drv->has_stereo)
+		v->capability |= V4L2_TUNER_CAP_STEREO;
+
+	if (ops->g_rxsubchans)
+		v->rxsubchans = ops->g_rxsubchans(isa);
+	else
+		v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+	v->audmode = isa->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
+	if (ops->g_signal)
+		v->signal = ops->g_signal(isa);
+	else
+		v->signal = (v->rxsubchans & V4L2_TUNER_SUB_STEREO) ?
+								0xffff : 0;
+	return 0;
+}
+
+static int radio_isa_s_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *v)
+{
+	struct radio_isa_card *isa = video_drvdata(file);
+	const struct radio_isa_ops *ops = isa->drv->ops;
+
+	if (v->index)
+		return -EINVAL;
+	if (ops->s_stereo) {
+		isa->stereo = (v->audmode == V4L2_TUNER_MODE_STEREO);
+		return ops->s_stereo(isa, isa->stereo);
+	}
+	return 0;
+}
+
+static int radio_isa_s_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct radio_isa_card *isa = video_drvdata(file);
+	int res;
+
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
+	f->frequency = clamp(f->frequency, FREQ_LOW, FREQ_HIGH);
+	res = isa->drv->ops->s_frequency(isa, f->frequency);
+	if (res == 0)
+		isa->freq = f->frequency;
+	return res;
+}
+
+static int radio_isa_g_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct radio_isa_card *isa = video_drvdata(file);
+
+	if (f->tuner != 0)
+		return -EINVAL;
+	f->type = V4L2_TUNER_RADIO;
+	f->frequency = isa->freq;
+	return 0;
+}
+
+static int radio_isa_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct radio_isa_card *isa =
+		container_of(ctrl->handler, struct radio_isa_card, hdl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		return isa->drv->ops->s_mute_volume(isa, ctrl->val,
+				isa->volume ? isa->volume->val : 0);
+	}
+	return -EINVAL;
+}
+
+static int radio_isa_log_status(struct file *file, void *priv)
+{
+	struct radio_isa_card *isa = video_drvdata(file);
+
+	v4l2_info(&isa->v4l2_dev, "I/O Port = 0x%03x\n", isa->io);
+	v4l2_ctrl_handler_log_status(&isa->hdl, isa->v4l2_dev.name);
+	return 0;
+}
+
+static int radio_isa_subscribe_event(struct v4l2_fh *fh,
+				struct v4l2_event_subscription *sub)
+{
+	if (sub->type == V4L2_EVENT_CTRL)
+		return v4l2_event_subscribe(fh, sub, 0);
+	return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops radio_isa_ctrl_ops = {
+	.s_ctrl = radio_isa_s_ctrl,
+};
+
+static const struct v4l2_file_operations radio_isa_fops = {
+	.owner		= THIS_MODULE,
+	.open		= v4l2_fh_open,
+	.release	= v4l2_fh_release,
+	.poll		= v4l2_ctrl_poll,
+	.unlocked_ioctl	= video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops radio_isa_ioctl_ops = {
+	.vidioc_querycap    = radio_isa_querycap,
+	.vidioc_g_tuner     = radio_isa_g_tuner,
+	.vidioc_s_tuner     = radio_isa_s_tuner,
+	.vidioc_g_frequency = radio_isa_g_frequency,
+	.vidioc_s_frequency = radio_isa_s_frequency,
+	.vidioc_log_status  = radio_isa_log_status,
+	.vidioc_subscribe_event   = radio_isa_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+int radio_isa_match(struct device *pdev, unsigned int dev)
+{
+	struct radio_isa_driver *drv = pdev->platform_data;
+
+	return drv->probe || drv->io_params[dev] >= 0;
+}
+EXPORT_SYMBOL_GPL(radio_isa_match);
+
+static bool radio_isa_valid_io(const struct radio_isa_driver *drv, int io)
+{
+	int i;
+
+	for (i = 0; i < drv->num_of_io_ports; i++)
+		if (drv->io_ports[i] == io)
+			return true;
+	return false;
+}
+
+int radio_isa_probe(struct device *pdev, unsigned int dev)
+{
+	struct radio_isa_driver *drv = pdev->platform_data;
+	const struct radio_isa_ops *ops = drv->ops;
+	struct v4l2_device *v4l2_dev;
+	struct radio_isa_card *isa;
+	int res;
+
+	isa = drv->ops->alloc();
+	if (isa == NULL)
+		return -ENOMEM;
+	dev_set_drvdata(pdev, isa);
+	isa->drv = drv;
+	isa->io = drv->io_params[dev];
+	v4l2_dev = &isa->v4l2_dev;
+	strlcpy(v4l2_dev->name, dev_name(pdev), sizeof(v4l2_dev->name));
+
+	if (drv->probe && ops->probe) {
+		int i;
+
+		for (i = 0; i < drv->num_of_io_ports; ++i) {
+			int io = drv->io_ports[i];
+
+			if (request_region(io, drv->region_size, v4l2_dev->name)) {
+				bool found = ops->probe(isa, io);
+
+				release_region(io, drv->region_size);
+				if (found) {
+					isa->io = io;
+					break;
+				}
+			}
+		}
+	}
+
+	if (!radio_isa_valid_io(drv, isa->io)) {
+		int i;
+
+		if (isa->io < 0)
+			return -ENODEV;
+		v4l2_err(v4l2_dev, "you must set an I/O address with io=0x%03x",
+				drv->io_ports[0]);
+		for (i = 1; i < drv->num_of_io_ports; i++)
+			printk(KERN_CONT "/0x%03x", drv->io_ports[i]);
+		printk(KERN_CONT ".\n");
+		kfree(isa);
+		return -EINVAL;
+	}
+
+	if (!request_region(isa->io, drv->region_size, v4l2_dev->name)) {
+		v4l2_err(v4l2_dev, "port 0x%x already in use\n", isa->io);
+		kfree(isa);
+		return -EBUSY;
+	}
+
+	res = v4l2_device_register(pdev, v4l2_dev);
+	if (res < 0) {
+		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+		goto err_dev_reg;
+	}
+
+	v4l2_ctrl_handler_init(&isa->hdl, 1);
+	isa->mute = v4l2_ctrl_new_std(&isa->hdl, &radio_isa_ctrl_ops,
+				V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+	if (drv->max_volume)
+		isa->volume = v4l2_ctrl_new_std(&isa->hdl, &radio_isa_ctrl_ops,
+			V4L2_CID_AUDIO_VOLUME, 0, drv->max_volume, 1,
+			drv->max_volume);
+	v4l2_dev->ctrl_handler = &isa->hdl;
+	if (isa->hdl.error) {
+		res = isa->hdl.error;
+		v4l2_err(v4l2_dev, "Could not register controls\n");
+		goto err_hdl;
+	}
+	if (drv->max_volume)
+		v4l2_ctrl_cluster(2, &isa->mute);
+	v4l2_dev->ctrl_handler = &isa->hdl;
+
+	mutex_init(&isa->lock);
+	isa->vdev.lock = &isa->lock;
+	strlcpy(isa->vdev.name, v4l2_dev->name, sizeof(isa->vdev.name));
+	isa->vdev.v4l2_dev = v4l2_dev;
+	isa->vdev.fops = &radio_isa_fops;
+	isa->vdev.ioctl_ops = &radio_isa_ioctl_ops;
+	isa->vdev.release = video_device_release_empty;
+	set_bit(V4L2_FL_USE_FH_PRIO, &isa->vdev.flags);
+	video_set_drvdata(&isa->vdev, isa);
+	isa->freq = FREQ_LOW;
+	isa->stereo = drv->has_stereo;
+
+	if (ops->init)
+		res = ops->init(isa);
+	if (!res)
+		res = v4l2_ctrl_handler_setup(&isa->hdl);
+	if (!res)
+		res = ops->s_frequency(isa, isa->freq);
+	if (!res && ops->s_stereo)
+		res = ops->s_stereo(isa, isa->stereo);
+	if (res < 0) {
+		v4l2_err(v4l2_dev, "Could not setup card\n");
+		goto err_node_reg;
+	}
+	res = video_register_device(&isa->vdev, VFL_TYPE_RADIO,
+					drv->radio_nr_params[dev]);
+	if (res < 0) {
+		v4l2_err(v4l2_dev, "Could not register device node\n");
+		goto err_node_reg;
+	}
+
+	v4l2_info(v4l2_dev, "Initialized radio card %s on port 0x%03x\n",
+			drv->card, isa->io);
+	return 0;
+
+err_node_reg:
+	v4l2_ctrl_handler_free(&isa->hdl);
+err_hdl:
+	v4l2_device_unregister(&isa->v4l2_dev);
+err_dev_reg:
+	release_region(isa->io, drv->region_size);
+	kfree(isa);
+	return res;
+}
+EXPORT_SYMBOL_GPL(radio_isa_probe);
+
+int radio_isa_remove(struct device *pdev, unsigned int dev)
+{
+	struct radio_isa_card *isa = dev_get_drvdata(pdev);
+	const struct radio_isa_ops *ops = isa->drv->ops;
+
+	ops->s_mute_volume(isa, true, isa->volume ? isa->volume->cur.val : 0);
+	video_unregister_device(&isa->vdev);
+	v4l2_ctrl_handler_free(&isa->hdl);
+	v4l2_device_unregister(&isa->v4l2_dev);
+	release_region(isa->io, isa->drv->region_size);
+	v4l2_info(&isa->v4l2_dev, "Removed radio card %s\n", isa->drv->card);
+	kfree(isa);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(radio_isa_remove);
diff --git a/drivers/media/radio/radio-isa.h b/drivers/media/radio/radio-isa.h
new file mode 100644
index 0000000..8a0ea84
--- /dev/null
+++ b/drivers/media/radio/radio-isa.h
@@ -0,0 +1,105 @@
+/*
+ * Framework for ISA radio drivers.
+ * This takes care of all the V4L2 scaffolding, allowing the ISA drivers
+ * to concentrate on the actual hardware operation.
+ *
+ * Copyright (C) 2012 Hans Verkuil <hans.verkuil@cisco.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 _RADIO_ISA_H_
+#define _RADIO_ISA_H_
+
+#include <linux/isa.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+struct radio_isa_driver;
+struct radio_isa_ops;
+
+/* Core structure for radio ISA cards */
+struct radio_isa_card {
+	const struct radio_isa_driver *drv;
+	struct v4l2_device v4l2_dev;
+	struct v4l2_ctrl_handler hdl;
+	struct video_device vdev;
+	struct mutex lock;
+	const struct radio_isa_ops *ops;
+	struct {	/* mute/volume cluster */
+		struct v4l2_ctrl *mute;
+		struct v4l2_ctrl *volume;
+	};
+	/* I/O port */
+	int io;
+
+	/* Card is in stereo audio mode */
+	bool stereo;
+	/* Current frequency */
+	u32 freq;
+};
+
+struct radio_isa_ops {
+	/* Allocate and initialize a radio_isa_card struct */
+	struct radio_isa_card *(*alloc)(void);
+	/* Probe whether a card is present at the given port */
+	bool (*probe)(struct radio_isa_card *isa, int io);
+	/* Special card initialization can be done here, this is called after
+	 * the standard controls are registered, but before they are setup,
+	 * thus allowing drivers to add their own controls here. */
+	int (*init)(struct radio_isa_card *isa);
+	/* Set mute and volume. */
+	int (*s_mute_volume)(struct radio_isa_card *isa, bool mute, int volume);
+	/* Set frequency */
+	int (*s_frequency)(struct radio_isa_card *isa, u32 freq);
+	/* Set stereo/mono audio mode */
+	int (*s_stereo)(struct radio_isa_card *isa, bool stereo);
+	/* Get rxsubchans value for VIDIOC_G_TUNER */
+	u32 (*g_rxsubchans)(struct radio_isa_card *isa);
+	/* Get the signal strength for VIDIOC_G_TUNER */
+	u32 (*g_signal)(struct radio_isa_card *isa);
+};
+
+/* Top level structure needed to instantiate the cards */
+struct radio_isa_driver {
+	struct isa_driver driver;
+	const struct radio_isa_ops *ops;
+	/* The module_param_array with the specified I/O ports */
+	int *io_params;
+	/* The module_param_array with the radio_nr values */
+	int *radio_nr_params;
+	/* Whether we should probe for possible cards */
+	bool probe;
+	/* The list of possible I/O ports */
+	const int *io_ports;
+	/* The size of that list */
+	int num_of_io_ports;
+	/* The region size to request */
+	unsigned region_size;
+	/* The name of the card */
+	const char *card;
+	/* Card can capture stereo audio */
+	bool has_stereo;
+	/* The maximum volume for the volume control. If 0, then there
+	   is no volume control possible. */
+	int max_volume;
+};
+
+int radio_isa_match(struct device *pdev, unsigned int dev);
+int radio_isa_probe(struct device *pdev, unsigned int dev);
+int radio_isa_remove(struct device *pdev, unsigned int dev);
+
+#endif
diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c
new file mode 100644
index 0000000..55bd1d2
--- /dev/null
+++ b/drivers/media/radio/radio-keene.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2012 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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
+ */
+
+/* kernel includes */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <linux/usb.h>
+#include <linux/version.h>
+#include <linux/mutex.h>
+
+/* driver and module definitions */
+MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>");
+MODULE_DESCRIPTION("Keene FM Transmitter driver");
+MODULE_LICENSE("GPL");
+
+/* Actually, it advertises itself as a Logitech */
+#define USB_KEENE_VENDOR 0x046d
+#define USB_KEENE_PRODUCT 0x0a0e
+
+/* Probably USB_TIMEOUT should be modified in module parameter */
+#define BUFFER_LENGTH 8
+#define USB_TIMEOUT 500
+
+/* Frequency limits in MHz */
+#define FREQ_MIN  76U
+#define FREQ_MAX 108U
+#define FREQ_MUL 16000U
+
+/* USB Device ID List */
+static struct usb_device_id usb_keene_device_table[] = {
+	{USB_DEVICE_AND_INTERFACE_INFO(USB_KEENE_VENDOR, USB_KEENE_PRODUCT,
+							USB_CLASS_HID, 0, 0) },
+	{ }						/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, usb_keene_device_table);
+
+struct keene_device {
+	struct usb_device *usbdev;
+	struct usb_interface *intf;
+	struct video_device vdev;
+	struct v4l2_device v4l2_dev;
+	struct v4l2_ctrl_handler hdl;
+	struct mutex lock;
+
+	u8 *buffer;
+	unsigned curfreq;
+	u8 tx;
+	u8 pa;
+	bool stereo;
+	bool muted;
+	bool preemph_75_us;
+};
+
+static inline struct keene_device *to_keene_dev(struct v4l2_device *v4l2_dev)
+{
+	return container_of(v4l2_dev, struct keene_device, v4l2_dev);
+}
+
+/* Set frequency (if non-0), PA, mute and turn on/off the FM transmitter. */
+static int keene_cmd_main(struct keene_device *radio, unsigned freq, bool play)
+{
+	unsigned short freq_send = freq ? (freq - 76 * 16000) / 800 : 0;
+	int ret;
+
+	radio->buffer[0] = 0x00;
+	radio->buffer[1] = 0x50;
+	radio->buffer[2] = (freq_send >> 8) & 0xff;
+	radio->buffer[3] = freq_send & 0xff;
+	radio->buffer[4] = radio->pa;
+	/* If bit 4 is set, then tune to the frequency.
+	   If bit 3 is set, then unmute; if bit 2 is set, then mute.
+	   If bit 1 is set, then enter idle mode; if bit 0 is set,
+	   then enter transit mode.
+	 */
+	radio->buffer[5] = (radio->muted ? 4 : 8) | (play ? 1 : 2) |
+							(freq ? 0x10 : 0);
+	radio->buffer[6] = 0x00;
+	radio->buffer[7] = 0x00;
+
+	ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
+		9, 0x21, 0x200, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT);
+
+	if (ret < 0) {
+		dev_warn(&radio->vdev.dev, "%s failed (%d)\n", __func__, ret);
+		return ret;
+	}
+	if (freq)
+		radio->curfreq = freq;
+	return 0;
+}
+
+/* Set TX, stereo and preemphasis mode (50 us vs 75 us). */
+static int keene_cmd_set(struct keene_device *radio)
+{
+	int ret;
+
+	radio->buffer[0] = 0x00;
+	radio->buffer[1] = 0x51;
+	radio->buffer[2] = radio->tx;
+	/* If bit 0 is set, then transmit mono, otherwise stereo.
+	   If bit 2 is set, then enable 75 us preemphasis, otherwise
+	   it is 50 us. */
+	radio->buffer[3] = (!radio->stereo) | (radio->preemph_75_us ? 4 : 0);
+	radio->buffer[4] = 0x00;
+	radio->buffer[5] = 0x00;
+	radio->buffer[6] = 0x00;
+	radio->buffer[7] = 0x00;
+
+	ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
+		9, 0x21, 0x200, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT);
+
+	if (ret < 0) {
+		dev_warn(&radio->vdev.dev, "%s failed (%d)\n", __func__, ret);
+		return ret;
+	}
+	return 0;
+}
+
+/* Handle unplugging the device.
+ * We call video_unregister_device in any case.
+ * The last function called in this procedure is
+ * usb_keene_device_release.
+ */
+static void usb_keene_disconnect(struct usb_interface *intf)
+{
+	struct keene_device *radio = to_keene_dev(usb_get_intfdata(intf));
+
+	v4l2_device_get(&radio->v4l2_dev);
+	mutex_lock(&radio->lock);
+	usb_set_intfdata(intf, NULL);
+	video_unregister_device(&radio->vdev);
+	v4l2_device_disconnect(&radio->v4l2_dev);
+	mutex_unlock(&radio->lock);
+	v4l2_device_put(&radio->v4l2_dev);
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+					struct v4l2_capability *v)
+{
+	struct keene_device *radio = video_drvdata(file);
+
+	strlcpy(v->driver, "radio-keene", sizeof(v->driver));
+	strlcpy(v->card, "Keene FM Transmitter", sizeof(v->card));
+	usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
+	v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_MODULATOR;
+	v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int vidioc_g_modulator(struct file *file, void *priv,
+				struct v4l2_modulator *v)
+{
+	struct keene_device *radio = video_drvdata(file);
+
+	if (v->index > 0)
+		return -EINVAL;
+
+	strlcpy(v->name, "FM", sizeof(v->name));
+	v->rangelow = FREQ_MIN * FREQ_MUL;
+	v->rangehigh = FREQ_MAX * FREQ_MUL;
+	v->txsubchans = radio->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+	return 0;
+}
+
+static int vidioc_s_modulator(struct file *file, void *priv,
+				struct v4l2_modulator *v)
+{
+	struct keene_device *radio = video_drvdata(file);
+
+	if (v->index > 0)
+		return -EINVAL;
+
+	radio->stereo = (v->txsubchans == V4L2_TUNER_SUB_STEREO);
+	return keene_cmd_set(radio);
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct keene_device *radio = video_drvdata(file);
+
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
+	f->frequency = clamp(f->frequency,
+			FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL);
+	return keene_cmd_main(radio, f->frequency, true);
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct keene_device *radio = video_drvdata(file);
+
+	if (f->tuner != 0)
+		return -EINVAL;
+	f->type = V4L2_TUNER_RADIO;
+	f->frequency = radio->curfreq;
+	return 0;
+}
+
+static int keene_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	static const u8 db2tx[] = {
+	     /*	 -15,  -12,   -9,   -6,   -3,    0 dB */
+		0x03, 0x13, 0x02, 0x12, 0x22, 0x32,
+	     /*	   3,    6,    9,   12,   15,   18 dB */
+		0x21, 0x31, 0x20, 0x30, 0x40, 0x50
+	};
+	struct keene_device *radio =
+		container_of(ctrl->handler, struct keene_device, hdl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		radio->muted = ctrl->val;
+		return keene_cmd_main(radio, 0, true);
+
+	case V4L2_CID_TUNE_POWER_LEVEL:
+		/* To go from dBuV to the register value we apply the
+		   following formula: */
+		radio->pa = (ctrl->val - 71) * 100 / 62;
+		return keene_cmd_main(radio, 0, true);
+
+	case V4L2_CID_TUNE_PREEMPHASIS:
+		radio->preemph_75_us = ctrl->val == V4L2_PREEMPHASIS_75_uS;
+		return keene_cmd_set(radio);
+
+	case V4L2_CID_AUDIO_COMPRESSION_GAIN:
+		radio->tx = db2tx[(ctrl->val - ctrl->minimum) / ctrl->step];
+		return keene_cmd_set(radio);
+	}
+	return -EINVAL;
+}
+
+static int vidioc_subscribe_event(struct v4l2_fh *fh,
+				struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_CTRL:
+		return v4l2_event_subscribe(fh, sub, 0);
+	default:
+		return -EINVAL;
+	}
+}
+
+
+/* File system interface */
+static const struct v4l2_file_operations usb_keene_fops = {
+	.owner		= THIS_MODULE,
+	.open           = v4l2_fh_open,
+	.release        = v4l2_fh_release,
+	.poll		= v4l2_ctrl_poll,
+	.unlocked_ioctl	= video_ioctl2,
+};
+
+static const struct v4l2_ctrl_ops keene_ctrl_ops = {
+	.s_ctrl = keene_s_ctrl,
+};
+
+static const struct v4l2_ioctl_ops usb_keene_ioctl_ops = {
+	.vidioc_querycap    = vidioc_querycap,
+	.vidioc_g_modulator = vidioc_g_modulator,
+	.vidioc_s_modulator = vidioc_s_modulator,
+	.vidioc_g_frequency = vidioc_g_frequency,
+	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_log_status = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event = vidioc_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static void usb_keene_video_device_release(struct v4l2_device *v4l2_dev)
+{
+	struct keene_device *radio = to_keene_dev(v4l2_dev);
+
+	/* free rest memory */
+	v4l2_ctrl_handler_free(&radio->hdl);
+	kfree(radio->buffer);
+	kfree(radio);
+}
+
+/* check if the device is present and register with v4l and usb if it is */
+static int usb_keene_probe(struct usb_interface *intf,
+				const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct keene_device *radio;
+	struct v4l2_ctrl_handler *hdl;
+	int retval = 0;
+
+	/*
+	 * The Keene FM transmitter USB device has the same USB ID as
+	 * the Logitech AudioHub Speaker, but it should ignore the hid.
+	 * Check if the name is that of the Keene device.
+	 * If not, then someone connected the AudioHub and we shouldn't
+	 * attempt to handle this driver.
+	 * For reference: the product name of the AudioHub is
+	 * "AudioHub Speaker".
+	 */
+	if (dev->product && strcmp(dev->product, "B-LINK USB Audio  "))
+		return -ENODEV;
+
+	radio = kzalloc(sizeof(struct keene_device), GFP_KERNEL);
+	if (radio)
+		radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
+
+	if (!radio || !radio->buffer) {
+		dev_err(&intf->dev, "kmalloc for keene_device failed\n");
+		kfree(radio);
+		retval = -ENOMEM;
+		goto err;
+	}
+
+	hdl = &radio->hdl;
+	v4l2_ctrl_handler_init(hdl, 4);
+	v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_AUDIO_MUTE,
+			0, 1, 1, 0);
+	v4l2_ctrl_new_std_menu(hdl, &keene_ctrl_ops, V4L2_CID_TUNE_PREEMPHASIS,
+			V4L2_PREEMPHASIS_75_uS, 1, V4L2_PREEMPHASIS_50_uS);
+	v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_TUNE_POWER_LEVEL,
+			84, 118, 1, 118);
+	v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_AUDIO_COMPRESSION_GAIN,
+			-15, 18, 3, 0);
+	radio->pa = 118;
+	radio->tx = 0x32;
+	radio->stereo = true;
+	radio->curfreq = 95.16 * FREQ_MUL;
+	if (hdl->error) {
+		retval = hdl->error;
+
+		v4l2_ctrl_handler_free(hdl);
+		goto err_v4l2;
+	}
+	retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
+	if (retval < 0) {
+		dev_err(&intf->dev, "couldn't register v4l2_device\n");
+		goto err_v4l2;
+	}
+
+	mutex_init(&radio->lock);
+
+	radio->v4l2_dev.ctrl_handler = hdl;
+	radio->v4l2_dev.release = usb_keene_video_device_release;
+	strlcpy(radio->vdev.name, radio->v4l2_dev.name,
+		sizeof(radio->vdev.name));
+	radio->vdev.v4l2_dev = &radio->v4l2_dev;
+	radio->vdev.fops = &usb_keene_fops;
+	radio->vdev.ioctl_ops = &usb_keene_ioctl_ops;
+	radio->vdev.lock = &radio->lock;
+	radio->vdev.release = video_device_release_empty;
+
+	radio->usbdev = interface_to_usbdev(intf);
+	radio->intf = intf;
+	usb_set_intfdata(intf, &radio->v4l2_dev);
+
+	video_set_drvdata(&radio->vdev, radio);
+	set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
+
+	retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1);
+	if (retval < 0) {
+		dev_err(&intf->dev, "could not register video device\n");
+		goto err_vdev;
+	}
+	v4l2_ctrl_handler_setup(hdl);
+	dev_info(&intf->dev, "V4L2 device registered as %s\n",
+			video_device_node_name(&radio->vdev));
+	return 0;
+
+err_vdev:
+	v4l2_device_unregister(&radio->v4l2_dev);
+err_v4l2:
+	kfree(radio->buffer);
+	kfree(radio);
+err:
+	return retval;
+}
+
+/* USB subsystem interface */
+static struct usb_driver usb_keene_driver = {
+	.name			= "radio-keene",
+	.probe			= usb_keene_probe,
+	.disconnect		= usb_keene_disconnect,
+	.id_table		= usb_keene_device_table,
+};
+
+static int __init keene_init(void)
+{
+	int retval = usb_register(&usb_keene_driver);
+
+	if (retval)
+		pr_err(KBUILD_MODNAME
+			": usb_register failed. Error number %d\n", retval);
+
+	return retval;
+}
+
+static void __exit keene_exit(void)
+{
+	usb_deregister(&usb_keene_driver);
+}
+
+module_init(keene_init);
+module_exit(keene_exit);
+
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index f872a54..740a3d5 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -42,67 +42,37 @@
 #include <linux/videodev2.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <sound/tea575x-tuner.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
-
-#define DRIVER_VERSION	"0.7.8"
-
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 
 MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
-MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
+MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
+MODULE_VERSION("1.0.0");
 
 static int radio_nr = -1;
-module_param(radio_nr, int, 0);
-
-static int debug;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "activates debug info");
-
-#define dprintk(dev, num, fmt, arg...) \
-	v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg)
-
-#ifndef PCI_VENDOR_ID_GUILLEMOT
-#define PCI_VENDOR_ID_GUILLEMOT 0x5046
-#endif
-
-#ifndef PCI_DEVICE_ID_GUILLEMOT
-#define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001
-#endif
-
+module_param(radio_nr, int, 0644);
+MODULE_PARM_DESC(radio_nr, "Radio device number");
 
 /* TEA5757 pin mappings */
 static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16;
 
-#define FREQ_LO		(87 * 16000)
-#define FREQ_HI		(108 * 16000)
+static atomic_t maxiradio_instance = ATOMIC_INIT(0);
 
-#define FREQ_IF         171200 /* 10.7*16000   */
-#define FREQ_STEP       200    /* 12.5*16      */
-
-/* (x==fmhz*16*1000) -> bits */
-#define FREQ2BITS(x) \
-  ((((unsigned int)(x) + FREQ_IF + (FREQ_STEP << 1)) / (FREQ_STEP << 2)) << 2)
-
-#define BITS2FREQ(x)	((x) * FREQ_STEP - FREQ_IF)
-
+#define PCI_VENDOR_ID_GUILLEMOT 0x5046
+#define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001
 
 struct maxiradio
 {
+	struct snd_tea575x tea;
 	struct v4l2_device v4l2_dev;
-	struct video_device vdev;
 	struct pci_dev *pdev;
 
 	u16	io;	/* base of radio io */
-	u16	muted;	/* VIDEO_AUDIO_MUTE */
-	u16	stereo;	/* VIDEO_TUNER_STEREO_ON */
-	u16	tuned;	/* signal strength (0 or 0xffff) */
-
-	unsigned long freq;
-
-	struct mutex lock;
 };
 
 static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev)
@@ -110,259 +80,41 @@
 	return container_of(v4l2_dev, struct maxiradio, v4l2_dev);
 }
 
-static void outbit(unsigned long bit, u16 io)
+static void maxiradio_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
 {
-	int val = power | wren | (bit ? data : 0);
+	struct maxiradio *dev = tea->private_data;
+	u8 bits = 0;
 
-	outb(val, io);
-	udelay(4);
-	outb(val | clk, io);
-	udelay(4);
-	outb(val, io);
-	udelay(4);
+	bits |= (pins & TEA575X_DATA) ? data : 0;
+	bits |= (pins & TEA575X_CLK)  ? clk  : 0;
+	bits |= (pins & TEA575X_WREN) ? wren : 0;
+	bits |= power;
+
+	outb(bits, dev->io);
 }
 
-static void turn_power(struct maxiradio *dev, int p)
+/* Note: this card cannot read out the data of the shift registers,
+   only the mono/stereo pin works. */
+static u8 maxiradio_tea575x_get_pins(struct snd_tea575x *tea)
 {
-	if (p != 0) {
-		dprintk(dev, 1, "Radio powered on\n");
-		outb(power, dev->io);
-	} else {
-		dprintk(dev, 1, "Radio powered off\n");
-		outb(0, dev->io);
-	}
+	struct maxiradio *dev = tea->private_data;
+	u8 bits = inb(dev->io);
+
+	return  ((bits & data) ? TEA575X_DATA : 0) |
+		((bits & mo_st) ? TEA575X_MOST : 0);
 }
 
-static void set_freq(struct maxiradio *dev, u32 freq)
+static void maxiradio_tea575x_set_direction(struct snd_tea575x *tea, bool output)
 {
-	unsigned long int si;
-	int bl;
-	int io = dev->io;
-	int val = FREQ2BITS(freq);
-
-	/* TEA5757 shift register bits (see pdf) */
-
-	outbit(0, io); /* 24  search */
-	outbit(1, io); /* 23  search up/down */
-
-	outbit(0, io); /* 22  stereo/mono */
-
-	outbit(0, io); /* 21  band */
-	outbit(0, io); /* 20  band (only 00=FM works I think) */
-
-	outbit(0, io); /* 19  port ? */
-	outbit(0, io); /* 18  port ? */
-
-	outbit(0, io); /* 17  search level */
-	outbit(0, io); /* 16  search level */
-
-	si = 0x8000;
-	for (bl = 1; bl <= 16; bl++) {
-		outbit(val & si, io);
-		si >>= 1;
-	}
-
-	dprintk(dev, 1, "Radio freq set to %d.%02d MHz\n",
-				freq / 16000,
-				freq % 16000 * 100 / 16000);
-
-	turn_power(dev, 1);
 }
 
-static int get_stereo(u16 io)
-{
-	outb(power,io);
-	udelay(4);
-
-	return !(inb(io) & mo_st);
-}
-
-static int get_tune(u16 io)
-{
-	outb(power+clk,io);
-	udelay(4);
-
-	return !(inb(io) & mo_st);
-}
-
-
-static int vidioc_querycap(struct file *file, void  *priv,
-			    struct v4l2_capability *v)
-{
-	struct maxiradio *dev = video_drvdata(file);
-
-	strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver));
-	strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card));
-	snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev));
-	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-	return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-			   struct v4l2_tuner *v)
-{
-	struct maxiradio *dev = video_drvdata(file);
-
-	if (v->index > 0)
-		return -EINVAL;
-
-	mutex_lock(&dev->lock);
-	strlcpy(v->name, "FM", sizeof(v->name));
-	v->type = V4L2_TUNER_RADIO;
-	v->rangelow = FREQ_LO;
-	v->rangehigh = FREQ_HI;
-	v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-	v->capability = V4L2_TUNER_CAP_LOW;
-	if (get_stereo(dev->io))
-		v->audmode = V4L2_TUNER_MODE_STEREO;
-	else
-		v->audmode = V4L2_TUNER_MODE_MONO;
-	v->signal = 0xffff * get_tune(dev->io);
-	mutex_unlock(&dev->lock);
-
-	return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-			   struct v4l2_tuner *v)
-{
-	return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-	*i = 0;
-	return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-	return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-			   struct v4l2_audio *a)
-{
-	a->index = 0;
-	strlcpy(a->name, "Radio", sizeof(a->name));
-	a->capability = V4L2_AUDCAP_STEREO;
-	return 0;
-}
-
-
-static int vidioc_s_audio(struct file *file, void *priv,
-			   struct v4l2_audio *a)
-{
-	return a->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-			       struct v4l2_frequency *f)
-{
-	struct maxiradio *dev = video_drvdata(file);
-
-	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-		return -EINVAL;
-	if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) {
-		dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
-					f->frequency / 16000,
-					f->frequency % 16000 * 100 / 16000,
-					FREQ_LO / 16000, FREQ_HI / 16000);
-
-		return -EINVAL;
-	}
-
-	mutex_lock(&dev->lock);
-	dev->freq = f->frequency;
-	set_freq(dev, dev->freq);
-	msleep(125);
-	mutex_unlock(&dev->lock);
-
-	return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-			       struct v4l2_frequency *f)
-{
-	struct maxiradio *dev = video_drvdata(file);
-
-	if (f->tuner != 0)
-		return -EINVAL;
-	f->type = V4L2_TUNER_RADIO;
-	f->frequency = dev->freq;
-
-	dprintk(dev, 4, "radio freq is %d.%02d MHz",
-				f->frequency / 16000,
-				f->frequency % 16000 * 100 / 16000);
-
-	return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-			     struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-		struct v4l2_control *ctrl)
-{
-	struct maxiradio *dev = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = dev->muted;
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-		struct v4l2_control *ctrl)
-{
-	struct maxiradio *dev = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		mutex_lock(&dev->lock);
-		dev->muted = ctrl->value;
-		if (dev->muted)
-			turn_power(dev, 0);
-		else
-			set_freq(dev, dev->freq);
-		mutex_unlock(&dev->lock);
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-static const struct v4l2_file_operations maxiradio_fops = {
-	.owner		= THIS_MODULE,
-	.unlocked_ioctl = video_ioctl2,
+static struct snd_tea575x_ops maxiradio_tea_ops = {
+	.set_pins = maxiradio_tea575x_set_pins,
+	.get_pins = maxiradio_tea575x_get_pins,
+	.set_direction = maxiradio_tea575x_set_direction,
 };
 
-static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
-	.vidioc_querycap    = vidioc_querycap,
-	.vidioc_g_tuner     = vidioc_g_tuner,
-	.vidioc_s_tuner     = vidioc_s_tuner,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
-	.vidioc_g_input     = vidioc_g_input,
-	.vidioc_s_input     = vidioc_s_input,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
-	.vidioc_queryctrl   = vidioc_queryctrl,
-	.vidioc_g_ctrl      = vidioc_g_ctrl,
-	.vidioc_s_ctrl      = vidioc_s_ctrl,
-};
-
-static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit maxiradio_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct maxiradio *dev;
 	struct v4l2_device *v4l2_dev;
@@ -375,63 +127,60 @@
 	}
 
 	v4l2_dev = &dev->v4l2_dev;
-	mutex_init(&dev->lock);
-	dev->pdev = pdev;
-	dev->muted = 1;
-	dev->freq = FREQ_LO;
-
-	strlcpy(v4l2_dev->name, "maxiradio", sizeof(v4l2_dev->name));
+	v4l2_device_set_name(v4l2_dev, "maxiradio", &maxiradio_instance);
 
 	retval = v4l2_device_register(&pdev->dev, v4l2_dev);
 	if (retval < 0) {
 		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
 		goto errfr;
 	}
+	dev->tea.private_data = dev;
+	dev->tea.ops = &maxiradio_tea_ops;
+	/* The data pin cannot be read. This may be a hardware limitation, or
+	   we just don't know how to read it. */
+	dev->tea.cannot_read_data = true;
+	dev->tea.v4l2_dev = v4l2_dev;
+	dev->tea.radio_nr = radio_nr;
+	strlcpy(dev->tea.card, "Maxi Radio FM2000", sizeof(dev->tea.card));
+	snprintf(dev->tea.bus_info, sizeof(dev->tea.bus_info),
+			"PCI:%s", pci_name(pdev));
+
+	retval = -ENODEV;
 
 	if (!request_region(pci_resource_start(pdev, 0),
-			   pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
-		v4l2_err(v4l2_dev, "can't reserve I/O ports\n");
-		goto err_out;
+			   pci_resource_len(pdev, 0), v4l2_dev->name)) {
+		dev_err(&pdev->dev, "can't reserve I/O ports\n");
+		goto err_hdl;
 	}
 
 	if (pci_enable_device(pdev))
 		goto err_out_free_region;
 
 	dev->io = pci_resource_start(pdev, 0);
-	strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
-	dev->vdev.v4l2_dev = v4l2_dev;
-	dev->vdev.fops = &maxiradio_fops;
-	dev->vdev.ioctl_ops = &maxiradio_ioctl_ops;
-	dev->vdev.release = video_device_release_empty;
-	video_set_drvdata(&dev->vdev, dev);
-
-	if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-		v4l2_err(v4l2_dev, "can't register device!");
+	if (snd_tea575x_init(&dev->tea)) {
+		printk(KERN_ERR "radio-maxiradio: Unable to detect TEA575x tuner\n");
 		goto err_out_free_region;
 	}
-
-	v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
-
-	v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n",
-	       dev->io);
 	return 0;
 
 err_out_free_region:
 	release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
-err_out:
+err_hdl:
 	v4l2_device_unregister(v4l2_dev);
 errfr:
 	kfree(dev);
-	return -ENODEV;
+	return retval;
 }
 
-static void __devexit maxiradio_remove_one(struct pci_dev *pdev)
+static void __devexit maxiradio_remove(struct pci_dev *pdev)
 {
 	struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
 	struct maxiradio *dev = to_maxiradio(v4l2_dev);
 
-	video_unregister_device(&dev->vdev);
-	v4l2_device_unregister(&dev->v4l2_dev);
+	snd_tea575x_exit(&dev->tea);
+	/* Turn off power */
+	outb(0, dev->io);
+	v4l2_device_unregister(v4l2_dev);
 	release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
 }
 
@@ -446,19 +195,19 @@
 static struct pci_driver maxiradio_driver = {
 	.name		= "radio-maxiradio",
 	.id_table	= maxiradio_pci_tbl,
-	.probe		= maxiradio_init_one,
-	.remove		= __devexit_p(maxiradio_remove_one),
+	.probe		= maxiradio_probe,
+	.remove		= __devexit_p(maxiradio_remove),
 };
 
-static int __init maxiradio_radio_init(void)
+static int __init maxiradio_init(void)
 {
 	return pci_register_driver(&maxiradio_driver);
 }
 
-static void __exit maxiradio_radio_exit(void)
+static void __exit maxiradio_exit(void)
 {
 	pci_unregister_driver(&maxiradio_driver);
 }
 
-module_init(maxiradio_radio_init);
-module_exit(maxiradio_radio_exit);
+module_init(maxiradio_init);
+module_exit(maxiradio_exit);
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 3628be6..b275c5d 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -1,11 +1,12 @@
-/* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
+/*
+ * RadioTrack II driver
+ * Copyright 1998 Ben Pfaff
  *
  * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
  * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
  * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
  *
- * TODO: Allow for more than one of these foolish entities :-)
- *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
@@ -18,323 +19,120 @@
 #include <linux/io.h>		/* outb, outb_p			*/
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include "radio-isa.h"
 
 MODULE_AUTHOR("Ben Pfaff");
 MODULE_DESCRIPTION("A driver for the RadioTrack II radio card.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("0.1.99");
 
 #ifndef CONFIG_RADIO_RTRACK2_PORT
 #define CONFIG_RADIO_RTRACK2_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_RTRACK2_PORT;
-static int radio_nr = -1;
+#define RTRACK2_MAX 2
 
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)");
-module_param(radio_nr, int, 0);
+static int io[RTRACK2_MAX] = { [0] = CONFIG_RADIO_RTRACK2_PORT,
+			      [1 ... (RTRACK2_MAX - 1)] = -1 };
+static int radio_nr[RTRACK2_MAX] = { [0 ... (RTRACK2_MAX - 1)] = -1 };
 
-struct rtrack2
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the RadioTrack card (0x20f or 0x30f)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
+
+static struct radio_isa_card *rtrack2_alloc(void)
 {
-	struct v4l2_device v4l2_dev;
-	struct video_device vdev;
-	int io;
-	unsigned long curfreq;
-	int muted;
-	struct mutex lock;
-};
-
-static struct rtrack2 rtrack2_card;
-
-
-/* local things */
-
-static void rt_mute(struct rtrack2 *dev)
-{
-	if (dev->muted)
-		return;
-	mutex_lock(&dev->lock);
-	outb(1, dev->io);
-	mutex_unlock(&dev->lock);
-	dev->muted = 1;
+	return kzalloc(sizeof(struct radio_isa_card), GFP_KERNEL);
 }
 
-static void rt_unmute(struct rtrack2 *dev)
+static void zero(struct radio_isa_card *isa)
 {
-	if(dev->muted == 0)
-		return;
-	mutex_lock(&dev->lock);
-	outb(0, dev->io);
-	mutex_unlock(&dev->lock);
-	dev->muted = 0;
+	outb_p(1, isa->io);
+	outb_p(3, isa->io);
+	outb_p(1, isa->io);
 }
 
-static void zero(struct rtrack2 *dev)
+static void one(struct radio_isa_card *isa)
 {
-	outb_p(1, dev->io);
-	outb_p(3, dev->io);
-	outb_p(1, dev->io);
+	outb_p(5, isa->io);
+	outb_p(7, isa->io);
+	outb_p(5, isa->io);
 }
 
-static void one(struct rtrack2 *dev)
-{
-	outb_p(5, dev->io);
-	outb_p(7, dev->io);
-	outb_p(5, dev->io);
-}
-
-static int rt_setfreq(struct rtrack2 *dev, unsigned long freq)
+static int rtrack2_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
 	int i;
 
-	mutex_lock(&dev->lock);
-	dev->curfreq = freq;
 	freq = freq / 200 + 856;
 
-	outb_p(0xc8, dev->io);
-	outb_p(0xc9, dev->io);
-	outb_p(0xc9, dev->io);
+	outb_p(0xc8, isa->io);
+	outb_p(0xc9, isa->io);
+	outb_p(0xc9, isa->io);
 
 	for (i = 0; i < 10; i++)
-		zero(dev);
+		zero(isa);
 
 	for (i = 14; i >= 0; i--)
 		if (freq & (1 << i))
-			one(dev);
+			one(isa);
 		else
-			zero(dev);
+			zero(isa);
 
-	outb_p(0xc8, dev->io);
-	if (!dev->muted)
-		outb_p(0, dev->io);
-
-	mutex_unlock(&dev->lock);
+	outb_p(0xc8, isa->io);
+	if (!v4l2_ctrl_g_ctrl(isa->mute))
+		outb_p(0, isa->io);
 	return 0;
 }
 
-static int vidioc_querycap(struct file *file, void *priv,
-				struct v4l2_capability *v)
+static u32 rtrack2_g_signal(struct radio_isa_card *isa)
 {
-	strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver));
-	strlcpy(v->card, "RadioTrack II", sizeof(v->card));
-	strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	/* bit set = no signal present	*/
+	return (inb(isa->io) & 2) ? 0 : 0xffff;
+}
+
+static int rtrack2_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
+{
+	outb(mute, isa->io);
 	return 0;
 }
 
-static int vidioc_s_tuner(struct file *file, void *priv,
-				struct v4l2_tuner *v)
-{
-	return v->index ? -EINVAL : 0;
-}
-
-static int rt_getsigstr(struct rtrack2 *dev)
-{
-	int sig = 1;
-
-	mutex_lock(&dev->lock);
-	if (inb(dev->io) & 2)	/* bit set = no signal present	*/
-		sig = 0;
-	mutex_unlock(&dev->lock);
-	return sig;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-				struct v4l2_tuner *v)
-{
-	struct rtrack2 *rt = video_drvdata(file);
-
-	if (v->index > 0)
-		return -EINVAL;
-
-	strlcpy(v->name, "FM", sizeof(v->name));
-	v->type = V4L2_TUNER_RADIO;
-	v->rangelow = 88 * 16000;
-	v->rangehigh = 108 * 16000;
-	v->rxsubchans = V4L2_TUNER_SUB_MONO;
-	v->capability = V4L2_TUNER_CAP_LOW;
-	v->audmode = V4L2_TUNER_MODE_MONO;
-	v->signal = 0xFFFF * rt_getsigstr(rt);
-	return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-				struct v4l2_frequency *f)
-{
-	struct rtrack2 *rt = video_drvdata(file);
-
-	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-		return -EINVAL;
-	rt_setfreq(rt, f->frequency);
-	return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-				struct v4l2_frequency *f)
-{
-	struct rtrack2 *rt = video_drvdata(file);
-
-	if (f->tuner != 0)
-		return -EINVAL;
-	f->type = V4L2_TUNER_RADIO;
-	f->frequency = rt->curfreq;
-	return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-				struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-	case V4L2_CID_AUDIO_VOLUME:
-		return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535);
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctrl)
-{
-	struct rtrack2 *rt = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = rt->muted;
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		if (rt->muted)
-			ctrl->value = 0;
-		else
-			ctrl->value = 65535;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctrl)
-{
-	struct rtrack2 *rt = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		if (ctrl->value)
-			rt_mute(rt);
-		else
-			rt_unmute(rt);
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		if (ctrl->value)
-			rt_unmute(rt);
-		else
-			rt_mute(rt);
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-	*i = 0;
-	return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-	return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-				struct v4l2_audio *a)
-{
-	a->index = 0;
-	strlcpy(a->name, "Radio", sizeof(a->name));
-	a->capability = V4L2_AUDCAP_STEREO;
-	return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-				struct v4l2_audio *a)
-{
-	return a->index ? -EINVAL : 0;
-}
-
-static const struct v4l2_file_operations rtrack2_fops = {
-	.owner		= THIS_MODULE,
-	.unlocked_ioctl	= video_ioctl2,
+static const struct radio_isa_ops rtrack2_ops = {
+	.alloc = rtrack2_alloc,
+	.s_mute_volume = rtrack2_s_mute_volume,
+	.s_frequency = rtrack2_s_frequency,
+	.g_signal = rtrack2_g_signal,
 };
 
-static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = {
-	.vidioc_querycap    = vidioc_querycap,
-	.vidioc_g_tuner     = vidioc_g_tuner,
-	.vidioc_s_tuner     = vidioc_s_tuner,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
-	.vidioc_queryctrl   = vidioc_queryctrl,
-	.vidioc_g_ctrl      = vidioc_g_ctrl,
-	.vidioc_s_ctrl      = vidioc_s_ctrl,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
-	.vidioc_g_input     = vidioc_g_input,
-	.vidioc_s_input     = vidioc_s_input,
+static const int rtrack2_ioports[] = { 0x20f, 0x30f };
+
+static struct radio_isa_driver rtrack2_driver = {
+	.driver = {
+		.match		= radio_isa_match,
+		.probe		= radio_isa_probe,
+		.remove		= radio_isa_remove,
+		.driver		= {
+			.name	= "radio-rtrack2",
+		},
+	},
+	.io_params = io,
+	.radio_nr_params = radio_nr,
+	.io_ports = rtrack2_ioports,
+	.num_of_io_ports = ARRAY_SIZE(rtrack2_ioports),
+	.region_size = 4,
+	.card = "AIMSlab RadioTrack II",
+	.ops = &rtrack2_ops,
+	.has_stereo = true,
 };
 
 static int __init rtrack2_init(void)
 {
-	struct rtrack2 *dev = &rtrack2_card;
-	struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
-	int res;
-
-	strlcpy(v4l2_dev->name, "rtrack2", sizeof(v4l2_dev->name));
-	dev->io = io;
-	if (dev->io == -1) {
-		v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or io=0x30c\n");
-		return -EINVAL;
-	}
-	if (!request_region(dev->io, 4, "rtrack2")) {
-		v4l2_err(v4l2_dev, "port 0x%x already in use\n", dev->io);
-		return -EBUSY;
-	}
-
-	res = v4l2_device_register(NULL, v4l2_dev);
-	if (res < 0) {
-		release_region(dev->io, 4);
-		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-		return res;
-	}
-
-	strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
-	dev->vdev.v4l2_dev = v4l2_dev;
-	dev->vdev.fops = &rtrack2_fops;
-	dev->vdev.ioctl_ops = &rtrack2_ioctl_ops;
-	dev->vdev.release = video_device_release_empty;
-	video_set_drvdata(&dev->vdev, dev);
-
-	/* mute card - prevents noisy bootups */
-	outb(1, dev->io);
-	dev->muted = 1;
-
-	mutex_init(&dev->lock);
-	if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-		v4l2_device_unregister(v4l2_dev);
-		release_region(dev->io, 4);
-		return -EINVAL;
-	}
-
-	v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n");
-
-	return 0;
+	return isa_register_driver(&rtrack2_driver.driver, RTRACK2_MAX);
 }
 
 static void __exit rtrack2_exit(void)
 {
-	struct rtrack2 *dev = &rtrack2_card;
-
-	video_unregister_device(&dev->vdev);
-	v4l2_device_unregister(&dev->v4l2_dev);
-	release_region(dev->io, 4);
+	isa_unregister_driver(&rtrack2_driver.driver);
 }
 
 module_init(rtrack2_init);
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 7ab9afa..7c69214 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -9,16 +9,23 @@
 #include <linux/delay.h>
 #include <linux/module.h>	/* Modules 			*/
 #include <linux/init.h>		/* Initdata			*/
+#include <linux/slab.h>
 #include <linux/ioport.h>	/* request_region		*/
 #include <linux/io.h>		/* outb, outb_p			*/
+#include <linux/isa.h>
 #include <sound/tea575x-tuner.h>
 
 MODULE_AUTHOR("Ondrej Zary");
 MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver");
 MODULE_LICENSE("GPL");
 
+static int radio_nr = -1;
+module_param(radio_nr, int, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device number");
+
 struct fmr2 {
 	int io;
+	struct v4l2_device v4l2_dev;
 	struct snd_tea575x tea;
 	struct v4l2_ctrl *volume;
 	struct v4l2_ctrl *balance;
@@ -26,7 +33,6 @@
 
 /* the port is hardwired so no need to support multiple cards */
 #define FMR2_PORT	0x384
-static struct fmr2 fmr2_card;
 
 /* TEA575x tuner pins */
 #define STR_DATA	(1 << 0)
@@ -180,26 +186,46 @@
 	return 0;
 }
 
-static int __init fmr2_init(void)
+static int __devinit fmr2_probe(struct device *pdev, unsigned int dev)
 {
-	struct fmr2 *fmr2 = &fmr2_card;
+	struct fmr2 *fmr2;
+	int err;
 
+	fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL);
+	if (fmr2 == NULL)
+		return -ENOMEM;
+
+	strlcpy(fmr2->v4l2_dev.name, dev_name(pdev),
+			sizeof(fmr2->v4l2_dev.name));
 	fmr2->io = FMR2_PORT;
 
-	if (!request_region(fmr2->io, 2, "SF16-FMR2")) {
+	if (!request_region(fmr2->io, 2, fmr2->v4l2_dev.name)) {
 		printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io);
+		kfree(fmr2);
 		return -EBUSY;
 	}
 
+	dev_set_drvdata(pdev, fmr2);
+	err = v4l2_device_register(pdev, &fmr2->v4l2_dev);
+	if (err < 0) {
+		v4l2_err(&fmr2->v4l2_dev, "Could not register v4l2_device\n");
+		release_region(fmr2->io, 2);
+		kfree(fmr2);
+		return err;
+	}
+	fmr2->tea.v4l2_dev = &fmr2->v4l2_dev;
 	fmr2->tea.private_data = fmr2;
+	fmr2->tea.radio_nr = radio_nr;
 	fmr2->tea.ops = &fmr2_tea_ops;
 	fmr2->tea.ext_init = fmr2_tea_ext_init;
 	strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card));
-	strcpy(fmr2->tea.bus_info, "ISA");
+	snprintf(fmr2->tea.bus_info, sizeof(fmr2->tea.bus_info), "ISA:%s",
+			fmr2->v4l2_dev.name);
 
 	if (snd_tea575x_init(&fmr2->tea)) {
 		printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n");
 		release_region(fmr2->io, 2);
+		kfree(fmr2);
 		return -ENODEV;
 	}
 
@@ -207,12 +233,33 @@
 	return 0;
 }
 
-static void __exit fmr2_exit(void)
+static int __exit fmr2_remove(struct device *pdev, unsigned int dev)
 {
-	struct fmr2 *fmr2 = &fmr2_card;
+	struct fmr2 *fmr2 = dev_get_drvdata(pdev);
 
 	snd_tea575x_exit(&fmr2->tea);
 	release_region(fmr2->io, 2);
+	v4l2_device_unregister(&fmr2->v4l2_dev);
+	kfree(fmr2);
+	return 0;
+}
+
+struct isa_driver fmr2_driver = {
+	.probe		= fmr2_probe,
+	.remove		= fmr2_remove,
+	.driver		= {
+		.name	= "radio-sf16fmr2",
+	},
+};
+
+static int __init fmr2_init(void)
+{
+	return isa_register_driver(&fmr2_driver, 1);
+}
+
+static void __exit fmr2_exit(void)
+{
+	isa_unregister_driver(&fmr2_driver);
 }
 
 module_init(fmr2_init);
diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index db20904..6b1fae3 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -575,21 +575,7 @@
 	.id_table = tea5764_id,
 };
 
-/* init the driver */
-static int __init tea5764_init(void)
-{
-	int ret = i2c_add_driver(&tea5764_i2c_driver);
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ": "
-		DRIVER_DESC "\n");
-	return ret;
-}
-
-/* cleanup the driver */
-static void __exit tea5764_exit(void)
-{
-	i2c_del_driver(&tea5764_i2c_driver);
-}
+module_i2c_driver(tea5764_i2c_driver);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -600,6 +586,3 @@
 MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board");
 module_param(radio_nr, int, 0);
 MODULE_PARM_DESC(radio_nr, "video4linux device number to use");
-
-module_init(tea5764_init);
-module_exit(tea5764_exit);
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index f2ed9cc..be10a80 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -16,11 +16,7 @@
  *  Frequency control is done digitally -- ie out(port,encodefreq(95.8));
  *  Volume Control is done digitally
  *
- *  there is a I2C controlled RDS decoder (SAA6588)  onboard, which i would like to support someday
- *  (as soon i have understand how to get started :)
- *  If you can help me out with that, please contact me!!
- *
- *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
@@ -30,43 +26,24 @@
 #include <linux/videodev2.h>	/* kernel radio structs		*/
 #include <linux/mutex.h>
 #include <linux/io.h>		/* outb, outb_p			*/
+#include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include "radio-isa.h"
 
-MODULE_AUTHOR("R.OFFERMANNS & others");
+MODULE_AUTHOR("R. Offermans & others");
 MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("0.1.99");
 
-#ifndef CONFIG_RADIO_TERRATEC_PORT
-#define CONFIG_RADIO_TERRATEC_PORT 0x590
-#endif
-
-static int io = CONFIG_RADIO_TERRATEC_PORT;
+/* Note: there seems to be only one possible port (0x590), but without
+   hardware this is hard to verify. For now, this is the only one we will
+   support. */
+static int io = 0x590;
 static int radio_nr = -1;
 
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)");
-module_param(radio_nr, int, 0);
-
-static struct v4l2_queryctrl radio_qctrl[] = {
-	{
-		.id            = V4L2_CID_AUDIO_MUTE,
-		.name          = "Mute",
-		.minimum       = 0,
-		.maximum       = 1,
-		.default_value = 1,
-		.type          = V4L2_CTRL_TYPE_BOOLEAN,
-	},{
-		.id            = V4L2_CID_AUDIO_VOLUME,
-		.name          = "Volume",
-		.minimum       = 0,
-		.maximum       = 0xff,
-		.step          = 1,
-		.default_value = 0xff,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-	}
-};
+module_param(radio_nr, int, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device number");
 
 #define WRT_DIS 	0x00
 #define CLK_OFF		0x00
@@ -76,63 +53,24 @@
 #define CLK_ON 		0x08
 #define WRT_EN		0x10
 
-struct terratec
+static struct radio_isa_card *terratec_alloc(void)
 {
-	struct v4l2_device v4l2_dev;
-	struct video_device vdev;
-	int io;
-	int curvol;
-	unsigned long curfreq;
-	int muted;
-	struct mutex lock;
-};
+	return kzalloc(sizeof(struct radio_isa_card), GFP_KERNEL);
+}
 
-static struct terratec terratec_card;
-
-/* local things */
-
-static void tt_write_vol(struct terratec *tt, int volume)
+static int terratec_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
 {
 	int i;
 
-	volume = volume + (volume * 32); /* change both channels */
-	mutex_lock(&tt->lock);
+	if (mute)
+		vol = 0;
+	vol = vol + (vol * 32); /* change both channels */
 	for (i = 0; i < 8; i++) {
-		if (volume & (0x80 >> i))
-			outb(0x80, tt->io + 1);
+		if (vol & (0x80 >> i))
+			outb(0x80, isa->io + 1);
 		else
-			outb(0x00, tt->io + 1);
+			outb(0x00, isa->io + 1);
 	}
-	mutex_unlock(&tt->lock);
-}
-
-
-
-static void tt_mute(struct terratec *tt)
-{
-	tt->muted = 1;
-	tt_write_vol(tt, 0);
-}
-
-static int tt_setvol(struct terratec *tt, int vol)
-{
-	if (vol == tt->curvol) {	/* requested volume = current */
-		if (tt->muted) {	/* user is unmuting the card  */
-			tt->muted = 0;
-			tt_write_vol(tt, vol);	/* enable card */
-		}
-		return 0;
-	}
-
-	if (vol == 0) {			/* volume = 0 means mute the card */
-		tt_write_vol(tt, 0);	/* "turn off card" by setting vol to 0 */
-		tt->curvol = vol;	/* track the volume state!	*/
-		return 0;
-	}
-
-	tt->muted = 0;
-	tt_write_vol(tt, vol);
-	tt->curvol = vol;
 	return 0;
 }
 
@@ -140,20 +78,15 @@
 /* this is the worst part in this driver */
 /* many more or less strange things are going on here, but hey, it works :) */
 
-static int tt_setfreq(struct terratec *tt, unsigned long freq1)
+static int terratec_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
-	int freq;
 	int i;
 	int p;
-	int  temp;
+	int temp;
 	long rest;
 	unsigned char buffer[25];		/* we have to bit shift 25 registers */
 
-	mutex_lock(&tt->lock);
-
-	tt->curfreq = freq1;
-
-	freq = freq1 / 160;			/* convert the freq. to a nice to handle value */
+	freq = freq / 160;			/* convert the freq. to a nice to handle value */
 	memset(buffer, 0, sizeof(buffer));
 
 	rest = freq * 10 + 10700;	/* I once had understood what is going on here */
@@ -175,239 +108,61 @@
 
 	for (i = 24; i > -1; i--) {	/* bit shift the values to the radiocard */
 		if (buffer[i] == 1) {
-			outb(WRT_EN | DATA, tt->io);
-			outb(WRT_EN | DATA | CLK_ON, tt->io);
-			outb(WRT_EN | DATA, tt->io);
+			outb(WRT_EN | DATA, isa->io);
+			outb(WRT_EN | DATA | CLK_ON, isa->io);
+			outb(WRT_EN | DATA, isa->io);
 		} else {
-			outb(WRT_EN | 0x00, tt->io);
-			outb(WRT_EN | 0x00 | CLK_ON, tt->io);
+			outb(WRT_EN | 0x00, isa->io);
+			outb(WRT_EN | 0x00 | CLK_ON, isa->io);
 		}
 	}
-	outb(0x00, tt->io);
-
-	mutex_unlock(&tt->lock);
-
+	outb(0x00, isa->io);
 	return 0;
 }
 
-static int tt_getsigstr(struct terratec *tt)
+static u32 terratec_g_signal(struct radio_isa_card *isa)
 {
-	if (inb(tt->io) & 2)	/* bit set = no signal present	*/
-		return 0;
-	return 1;		/* signal present		*/
+	/* bit set = no signal present	*/
+	return (inb(isa->io) & 2) ? 0 : 0xffff;
 }
 
-static int vidioc_querycap(struct file *file, void *priv,
-					struct v4l2_capability *v)
-{
-	strlcpy(v->driver, "radio-terratec", sizeof(v->driver));
-	strlcpy(v->card, "ActiveRadio", sizeof(v->card));
-	strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-	return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-					struct v4l2_tuner *v)
-{
-	struct terratec *tt = video_drvdata(file);
-
-	if (v->index > 0)
-		return -EINVAL;
-
-	strlcpy(v->name, "FM", sizeof(v->name));
-	v->type = V4L2_TUNER_RADIO;
-	v->rangelow = 87 * 16000;
-	v->rangehigh = 108 * 16000;
-	v->rxsubchans = V4L2_TUNER_SUB_MONO;
-	v->capability = V4L2_TUNER_CAP_LOW;
-	v->audmode = V4L2_TUNER_MODE_MONO;
-	v->signal = 0xFFFF * tt_getsigstr(tt);
-	return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-					struct v4l2_tuner *v)
-{
-	return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-					struct v4l2_frequency *f)
-{
-	struct terratec *tt = video_drvdata(file);
-
-	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-		return -EINVAL;
-	tt_setfreq(tt, f->frequency);
-	return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-					struct v4l2_frequency *f)
-{
-	struct terratec *tt = video_drvdata(file);
-
-	if (f->tuner != 0)
-		return -EINVAL;
-	f->type = V4L2_TUNER_RADIO;
-	f->frequency = tt->curfreq;
-	return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-					struct v4l2_queryctrl *qc)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-		if (qc->id && qc->id == radio_qctrl[i].id) {
-			memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
-			return 0;
-		}
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct terratec *tt = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		if (tt->muted)
-			ctrl->value = 1;
-		else
-			ctrl->value = 0;
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		ctrl->value = tt->curvol * 6554;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct terratec *tt = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		if (ctrl->value)
-			tt_mute(tt);
-		else
-			tt_setvol(tt,tt->curvol);
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		tt_setvol(tt,ctrl->value);
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-	*i = 0;
-	return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-	return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
-{
-	a->index = 0;
-	strlcpy(a->name, "Radio", sizeof(a->name));
-	a->capability = V4L2_AUDCAP_STEREO;
-	return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
-{
-	return a->index ? -EINVAL : 0;
-}
-
-static const struct v4l2_file_operations terratec_fops = {
-	.owner		= THIS_MODULE,
-	.unlocked_ioctl	= video_ioctl2,
+static const struct radio_isa_ops terratec_ops = {
+	.alloc = terratec_alloc,
+	.s_mute_volume = terratec_s_mute_volume,
+	.s_frequency = terratec_s_frequency,
+	.g_signal = terratec_g_signal,
 };
 
-static const struct v4l2_ioctl_ops terratec_ioctl_ops = {
-	.vidioc_querycap    = vidioc_querycap,
-	.vidioc_g_tuner     = vidioc_g_tuner,
-	.vidioc_s_tuner     = vidioc_s_tuner,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
-	.vidioc_queryctrl   = vidioc_queryctrl,
-	.vidioc_g_ctrl      = vidioc_g_ctrl,
-	.vidioc_s_ctrl      = vidioc_s_ctrl,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
-	.vidioc_g_input     = vidioc_g_input,
-	.vidioc_s_input     = vidioc_s_input,
+static const int terratec_ioports[] = { 0x590 };
+
+static struct radio_isa_driver terratec_driver = {
+	.driver = {
+		.match		= radio_isa_match,
+		.probe		= radio_isa_probe,
+		.remove		= radio_isa_remove,
+		.driver		= {
+			.name	= "radio-terratec",
+		},
+	},
+	.io_params = &io,
+	.radio_nr_params = &radio_nr,
+	.io_ports = terratec_ioports,
+	.num_of_io_ports = ARRAY_SIZE(terratec_ioports),
+	.region_size = 2,
+	.card = "TerraTec ActiveRadio",
+	.ops = &terratec_ops,
+	.has_stereo = true,
+	.max_volume = 10,
 };
 
 static int __init terratec_init(void)
 {
-	struct terratec *tt = &terratec_card;
-	struct v4l2_device *v4l2_dev = &tt->v4l2_dev;
-	int res;
-
-	strlcpy(v4l2_dev->name, "terratec", sizeof(v4l2_dev->name));
-	tt->io = io;
-	if (tt->io == -1) {
-		v4l2_err(v4l2_dev, "you must set an I/O address with io=0x590 or 0x591\n");
-		return -EINVAL;
-	}
-	if (!request_region(tt->io, 2, "terratec")) {
-		v4l2_err(v4l2_dev, "port 0x%x already in use\n", io);
-		return -EBUSY;
-	}
-
-	res = v4l2_device_register(NULL, v4l2_dev);
-	if (res < 0) {
-		release_region(tt->io, 2);
-		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-		return res;
-	}
-
-	strlcpy(tt->vdev.name, v4l2_dev->name, sizeof(tt->vdev.name));
-	tt->vdev.v4l2_dev = v4l2_dev;
-	tt->vdev.fops = &terratec_fops;
-	tt->vdev.ioctl_ops = &terratec_ioctl_ops;
-	tt->vdev.release = video_device_release_empty;
-	video_set_drvdata(&tt->vdev, tt);
-
-	mutex_init(&tt->lock);
-
-	/* mute card - prevents noisy bootups */
-	tt_write_vol(tt, 0);
-
-	if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-		v4l2_device_unregister(&tt->v4l2_dev);
-		release_region(tt->io, 2);
-		return -EINVAL;
-	}
-
-	v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n");
-	return 0;
+	return isa_register_driver(&terratec_driver.driver, 1);
 }
 
 static void __exit terratec_exit(void)
 {
-	struct terratec *tt = &terratec_card;
-	struct v4l2_device *v4l2_dev = &tt->v4l2_dev;
-
-	video_unregister_device(&tt->vdev);
-	v4l2_device_unregister(&tt->v4l2_dev);
-	release_region(tt->io, 2);
-	v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver unloaded.\n");
+	isa_unregister_driver(&terratec_driver.driver);
 }
 
 module_init(terratec_init);
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index b3f45a0..26a8c60 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -21,13 +21,15 @@
 #include <linux/ioport.h>
 #include <linux/videodev2.h>
 #include <linux/io.h>
+#include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include "radio-isa.h"
 
 MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
 MODULE_DESCRIPTION("A driver for the Trust FM Radio card.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("0.1.99");
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
 
@@ -35,39 +37,38 @@
 #define CONFIG_RADIO_TRUST_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_TRUST_PORT;
-static int radio_nr = -1;
+#define TRUST_MAX 2
 
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)");
-module_param(radio_nr, int, 0);
+static int io[TRUST_MAX] = { [0] = CONFIG_RADIO_TRUST_PORT,
+			      [1 ... (TRUST_MAX - 1)] = -1 };
+static int radio_nr[TRUST_MAX] = { [0 ... (TRUST_MAX - 1)] = -1 };
+
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the Trust FM Radio card (0x350 or 0x358)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
 
 struct trust {
-	struct v4l2_device v4l2_dev;
-	struct video_device vdev;
-	int io;
+	struct radio_isa_card isa;
 	int ioval;
-	__u16 curvol;
-	__u16 curbass;
-	__u16 curtreble;
-	int muted;
-	unsigned long curfreq;
-	int curstereo;
-	int curmute;
-	struct mutex lock;
 };
 
-static struct trust trust_card;
+static struct radio_isa_card *trust_alloc(void)
+{
+	struct trust *tr = kzalloc(sizeof(*tr), GFP_KERNEL);
+
+	return tr ? &tr->isa : NULL;
+}
 
 /* i2c addresses */
 #define TDA7318_ADDR 0x88
 #define TSA6060T_ADDR 0xc4
 
-#define TR_DELAY do { inb(tr->io); inb(tr->io); inb(tr->io); } while (0)
-#define TR_SET_SCL outb(tr->ioval |= 2, tr->io)
-#define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->io)
-#define TR_SET_SDA outb(tr->ioval |= 1, tr->io)
-#define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->io)
+#define TR_DELAY do { inb(tr->isa.io); inb(tr->isa.io); inb(tr->isa.io); } while (0)
+#define TR_SET_SCL outb(tr->ioval |= 2, tr->isa.io)
+#define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->isa.io)
+#define TR_SET_SDA outb(tr->ioval |= 1, tr->isa.io)
+#define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->isa.io)
 
 static void write_i2c(struct trust *tr, int n, ...)
 {
@@ -84,10 +85,10 @@
 	TR_CLR_SCL;
 	TR_DELAY;
 
-	for(; n; n--) {
+	for (; n; n--) {
 		val = va_arg(args, unsigned);
-		for(mask = 0x80; mask; mask >>= 1) {
-			if(val & mask)
+		for (mask = 0x80; mask; mask >>= 1) {
+			if (val & mask)
 				TR_SET_SDA;
 			else
 				TR_CLR_SDA;
@@ -115,317 +116,128 @@
 	va_end(args);
 }
 
-static void tr_setvol(struct trust *tr, __u16 vol)
+static int trust_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
 {
-	mutex_lock(&tr->lock);
-	tr->curvol = vol / 2048;
-	write_i2c(tr, 2, TDA7318_ADDR, tr->curvol ^ 0x1f);
-	mutex_unlock(&tr->lock);
+	struct trust *tr = container_of(isa, struct trust, isa);
+
+	tr->ioval = (tr->ioval & 0xf7) | (mute << 3);
+	outb(tr->ioval, isa->io);
+	write_i2c(tr, 2, TDA7318_ADDR, vol ^ 0x1f);
+	return 0;
+}
+
+static int trust_s_stereo(struct radio_isa_card *isa, bool stereo)
+{
+	struct trust *tr = container_of(isa, struct trust, isa);
+
+	tr->ioval = (tr->ioval & 0xfb) | (!stereo << 2);
+	outb(tr->ioval, isa->io);
+	return 0;
+}
+
+static u32 trust_g_signal(struct radio_isa_card *isa)
+{
+	int i, v;
+
+	for (i = 0, v = 0; i < 100; i++)
+		v |= inb(isa->io);
+	return (v & 1) ? 0 : 0xffff;
+}
+
+static int trust_s_frequency(struct radio_isa_card *isa, u32 freq)
+{
+	struct trust *tr = container_of(isa, struct trust, isa);
+
+	freq /= 160;	/* Convert to 10 kHz units	*/
+	freq += 1070;	/* Add 10.7 MHz IF		*/
+	write_i2c(tr, 5, TSA6060T_ADDR, (freq << 1) | 1,
+			freq >> 7, 0x60 | ((freq >> 15) & 1), 0);
+	return 0;
 }
 
 static int basstreble2chip[15] = {
 	0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8
 };
 
-static void tr_setbass(struct trust *tr, __u16 bass)
+static int trust_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	mutex_lock(&tr->lock);
-	tr->curbass = bass / 4370;
-	write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[tr->curbass]);
-	mutex_unlock(&tr->lock);
-}
-
-static void tr_settreble(struct trust *tr, __u16 treble)
-{
-	mutex_lock(&tr->lock);
-	tr->curtreble = treble / 4370;
-	write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[tr->curtreble]);
-	mutex_unlock(&tr->lock);
-}
-
-static void tr_setstereo(struct trust *tr, int stereo)
-{
-	mutex_lock(&tr->lock);
-	tr->curstereo = !!stereo;
-	tr->ioval = (tr->ioval & 0xfb) | (!tr->curstereo << 2);
-	outb(tr->ioval, tr->io);
-	mutex_unlock(&tr->lock);
-}
-
-static void tr_setmute(struct trust *tr, int mute)
-{
-	mutex_lock(&tr->lock);
-	tr->curmute = !!mute;
-	tr->ioval = (tr->ioval & 0xf7) | (tr->curmute << 3);
-	outb(tr->ioval, tr->io);
-	mutex_unlock(&tr->lock);
-}
-
-static int tr_getsigstr(struct trust *tr)
-{
-	int i, v;
-
-	mutex_lock(&tr->lock);
-	for (i = 0, v = 0; i < 100; i++)
-		v |= inb(tr->io);
-	mutex_unlock(&tr->lock);
-	return (v & 1) ? 0 : 0xffff;
-}
-
-static int tr_getstereo(struct trust *tr)
-{
-	/* don't know how to determine it, just return the setting */
-	return tr->curstereo;
-}
-
-static void tr_setfreq(struct trust *tr, unsigned long f)
-{
-	mutex_lock(&tr->lock);
-	tr->curfreq = f;
-	f /= 160;	/* Convert to 10 kHz units	*/
-	f += 1070;	/* Add 10.7 MHz IF		*/
-	write_i2c(tr, 5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0);
-	mutex_unlock(&tr->lock);
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
-				struct v4l2_capability *v)
-{
-	strlcpy(v->driver, "radio-trust", sizeof(v->driver));
-	strlcpy(v->card, "Trust FM Radio", sizeof(v->card));
-	strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-	return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-				struct v4l2_tuner *v)
-{
-	struct trust *tr = video_drvdata(file);
-
-	if (v->index > 0)
-		return -EINVAL;
-
-	strlcpy(v->name, "FM", sizeof(v->name));
-	v->type = V4L2_TUNER_RADIO;
-	v->rangelow = 87.5 * 16000;
-	v->rangehigh = 108 * 16000;
-	v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-	v->capability = V4L2_TUNER_CAP_LOW;
-	if (tr_getstereo(tr))
-		v->audmode = V4L2_TUNER_MODE_STEREO;
-	else
-		v->audmode = V4L2_TUNER_MODE_MONO;
-	v->signal = tr_getsigstr(tr);
-	return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-				struct v4l2_tuner *v)
-{
-	struct trust *tr = video_drvdata(file);
-
-	if (v->index)
-		return -EINVAL;
-	tr_setstereo(tr, v->audmode == V4L2_TUNER_MODE_STEREO);
-	return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-				struct v4l2_frequency *f)
-{
-	struct trust *tr = video_drvdata(file);
-
-	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-		return -EINVAL;
-	tr_setfreq(tr, f->frequency);
-	return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-				struct v4l2_frequency *f)
-{
-	struct trust *tr = video_drvdata(file);
-
-	if (f->tuner != 0)
-		return -EINVAL;
-	f->type = V4L2_TUNER_RADIO;
-	f->frequency = tr->curfreq;
-	return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-				struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-	case V4L2_CID_AUDIO_VOLUME:
-		return v4l2_ctrl_query_fill(qc, 0, 65535, 2048, 65535);
-	case V4L2_CID_AUDIO_BASS:
-	case V4L2_CID_AUDIO_TREBLE:
-		return v4l2_ctrl_query_fill(qc, 0, 65535, 4370, 32768);
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctrl)
-{
-	struct trust *tr = video_drvdata(file);
+	struct radio_isa_card *isa =
+		container_of(ctrl->handler, struct radio_isa_card, hdl);
+	struct trust *tr = container_of(isa, struct trust, isa);
 
 	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = tr->curmute;
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		ctrl->value = tr->curvol * 2048;
-		return 0;
 	case V4L2_CID_AUDIO_BASS:
-		ctrl->value = tr->curbass * 4370;
+		write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[ctrl->val]);
 		return 0;
 	case V4L2_CID_AUDIO_TREBLE:
-		ctrl->value = tr->curtreble * 4370;
+		write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[ctrl->val]);
 		return 0;
 	}
 	return -EINVAL;
 }
 
-static int vidioc_s_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctrl)
-{
-	struct trust *tr = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		tr_setmute(tr, ctrl->value);
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		tr_setvol(tr, ctrl->value);
-		return 0;
-	case V4L2_CID_AUDIO_BASS:
-		tr_setbass(tr, ctrl->value);
-		return 0;
-	case V4L2_CID_AUDIO_TREBLE:
-		tr_settreble(tr, ctrl->value);
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-	*i = 0;
-	return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-	return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-				struct v4l2_audio *a)
-{
-	a->index = 0;
-	strlcpy(a->name, "Radio", sizeof(a->name));
-	a->capability = V4L2_AUDCAP_STEREO;
-	return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-				struct v4l2_audio *a)
-{
-	return a->index ? -EINVAL : 0;
-}
-
-static const struct v4l2_file_operations trust_fops = {
-	.owner		= THIS_MODULE,
-	.unlocked_ioctl	= video_ioctl2,
+static const struct v4l2_ctrl_ops trust_ctrl_ops = {
+	.s_ctrl = trust_s_ctrl,
 };
 
-static const struct v4l2_ioctl_ops trust_ioctl_ops = {
-	.vidioc_querycap    = vidioc_querycap,
-	.vidioc_g_tuner     = vidioc_g_tuner,
-	.vidioc_s_tuner     = vidioc_s_tuner,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
-	.vidioc_queryctrl   = vidioc_queryctrl,
-	.vidioc_g_ctrl      = vidioc_g_ctrl,
-	.vidioc_s_ctrl      = vidioc_s_ctrl,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
-	.vidioc_g_input     = vidioc_g_input,
-	.vidioc_s_input     = vidioc_s_input,
-};
-
-static int __init trust_init(void)
+static int trust_initialize(struct radio_isa_card *isa)
 {
-	struct trust *tr = &trust_card;
-	struct v4l2_device *v4l2_dev = &tr->v4l2_dev;
-	int res;
+	struct trust *tr = container_of(isa, struct trust, isa);
 
-	strlcpy(v4l2_dev->name, "trust", sizeof(v4l2_dev->name));
-	tr->io = io;
 	tr->ioval = 0xf;
-	mutex_init(&tr->lock);
-
-	if (tr->io == -1) {
-		v4l2_err(v4l2_dev, "You must set an I/O address with io=0x0x350 or 0x358\n");
-		return -EINVAL;
-	}
-	if (!request_region(tr->io, 2, "Trust FM Radio")) {
-		v4l2_err(v4l2_dev, "port 0x%x already in use\n", tr->io);
-		return -EBUSY;
-	}
-
-	res = v4l2_device_register(NULL, v4l2_dev);
-	if (res < 0) {
-		release_region(tr->io, 2);
-		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-		return res;
-	}
-
-	strlcpy(tr->vdev.name, v4l2_dev->name, sizeof(tr->vdev.name));
-	tr->vdev.v4l2_dev = v4l2_dev;
-	tr->vdev.fops = &trust_fops;
-	tr->vdev.ioctl_ops = &trust_ioctl_ops;
-	tr->vdev.release = video_device_release_empty;
-	video_set_drvdata(&tr->vdev, tr);
-
 	write_i2c(tr, 2, TDA7318_ADDR, 0x80);	/* speaker att. LF = 0 dB */
 	write_i2c(tr, 2, TDA7318_ADDR, 0xa0);	/* speaker att. RF = 0 dB */
 	write_i2c(tr, 2, TDA7318_ADDR, 0xc0);	/* speaker att. LR = 0 dB */
 	write_i2c(tr, 2, TDA7318_ADDR, 0xe0);	/* speaker att. RR = 0 dB */
 	write_i2c(tr, 2, TDA7318_ADDR, 0x40);	/* stereo 1 input, gain = 18.75 dB */
 
-	tr_setvol(tr, 0xffff);
-	tr_setbass(tr, 0x8000);
-	tr_settreble(tr, 0x8000);
-	tr_setstereo(tr, 1);
-
-	/* mute card - prevents noisy bootups */
-	tr_setmute(tr, 1);
-
-	if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-		v4l2_device_unregister(v4l2_dev);
-		release_region(tr->io, 2);
-		return -EINVAL;
-	}
-
-	v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n");
-
-	return 0;
+	v4l2_ctrl_new_std(&isa->hdl, &trust_ctrl_ops,
+				V4L2_CID_AUDIO_BASS, 0, 15, 1, 8);
+	v4l2_ctrl_new_std(&isa->hdl, &trust_ctrl_ops,
+				V4L2_CID_AUDIO_TREBLE, 0, 15, 1, 8);
+	return isa->hdl.error;
 }
 
-static void __exit cleanup_trust_module(void)
-{
-	struct trust *tr = &trust_card;
+static const struct radio_isa_ops trust_ops = {
+	.init = trust_initialize,
+	.alloc = trust_alloc,
+	.s_mute_volume = trust_s_mute_volume,
+	.s_frequency = trust_s_frequency,
+	.s_stereo = trust_s_stereo,
+	.g_signal = trust_g_signal,
+};
 
-	video_unregister_device(&tr->vdev);
-	v4l2_device_unregister(&tr->v4l2_dev);
-	release_region(tr->io, 2);
+static const int trust_ioports[] = { 0x350, 0x358 };
+
+static struct radio_isa_driver trust_driver = {
+	.driver = {
+		.match		= radio_isa_match,
+		.probe		= radio_isa_probe,
+		.remove		= radio_isa_remove,
+		.driver		= {
+			.name	= "radio-trust",
+		},
+	},
+	.io_params = io,
+	.radio_nr_params = radio_nr,
+	.io_ports = trust_ioports,
+	.num_of_io_ports = ARRAY_SIZE(trust_ioports),
+	.region_size = 2,
+	.card = "Trust FM Radio",
+	.ops = &trust_ops,
+	.has_stereo = true,
+	.max_volume = 31,
+};
+
+static int __init trust_init(void)
+{
+	return isa_register_driver(&trust_driver.driver, TRUST_MAX);
+}
+
+static void __exit trust_exit(void)
+{
+	isa_unregister_driver(&trust_driver.driver);
 }
 
 module_init(trust_init);
-module_exit(cleanup_trust_module);
+module_exit(trust_exit);
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index 398726a..eb72a4d 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -33,63 +33,53 @@
 #include <linux/ioport.h>	/* request_region		  */
 #include <linux/videodev2.h>	/* kernel radio structs           */
 #include <linux/io.h>		/* outb, outb_p                   */
+#include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include "radio-isa.h"
 
 #define DRIVER_VERSION "0.1.2"
 
 MODULE_AUTHOR("Dr. Henrik Seidel");
 MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio).");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
+MODULE_VERSION("0.1.99");
 
 #ifndef CONFIG_RADIO_TYPHOON_PORT
 #define CONFIG_RADIO_TYPHOON_PORT -1
 #endif
 
 #ifndef CONFIG_RADIO_TYPHOON_MUTEFREQ
-#define CONFIG_RADIO_TYPHOON_MUTEFREQ 0
+#define CONFIG_RADIO_TYPHOON_MUTEFREQ 87000
 #endif
 
-static int io = CONFIG_RADIO_TYPHOON_PORT;
-static int radio_nr = -1;
+#define TYPHOON_MAX 2
 
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)");
-
-module_param(radio_nr, int, 0);
-
+static int io[TYPHOON_MAX] = { [0] = CONFIG_RADIO_TYPHOON_PORT,
+			      [1 ... (TYPHOON_MAX - 1)] = -1 };
+static int radio_nr[TYPHOON_MAX]	= { [0 ... (TYPHOON_MAX - 1)] = -1 };
 static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ;
+
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the Typhoon card (0x316 or 0x336)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
 module_param(mutefreq, ulong, 0);
 MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)");
 
-#define BANNER "Typhoon Radio Card driver v" DRIVER_VERSION "\n"
-
 struct typhoon {
-	struct v4l2_device v4l2_dev;
-	struct video_device vdev;
-	int io;
-	int curvol;
+	struct radio_isa_card isa;
 	int muted;
-	unsigned long curfreq;
-	unsigned long mutefreq;
-	struct mutex lock;
 };
 
-static struct typhoon typhoon_card;
-
-static void typhoon_setvol_generic(struct typhoon *dev, int vol)
+static struct radio_isa_card *typhoon_alloc(void)
 {
-	mutex_lock(&dev->lock);
-	vol >>= 14;				/* Map 16 bit to 2 bit */
-	vol &= 3;
-	outb_p(vol / 2, dev->io);		/* Set the volume, high bit. */
-	outb_p(vol % 2, dev->io + 2);	/* Set the volume, low bit. */
-	mutex_unlock(&dev->lock);
+	struct typhoon *ty = kzalloc(sizeof(*ty), GFP_KERNEL);
+
+	return ty ? &ty->isa : NULL;
 }
 
-static int typhoon_setfreq_generic(struct typhoon *dev,
-				   unsigned long frequency)
+static int typhoon_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
 	unsigned long outval;
 	unsigned long x;
@@ -105,302 +95,86 @@
 	 *
 	 */
 
-	mutex_lock(&dev->lock);
-	x = frequency / 160;
+	x = freq / 160;
 	outval = (x * x + 2500) / 5000;
 	outval = (outval * x + 5000) / 10000;
 	outval -= (10 * x * x + 10433) / 20866;
 	outval += 4 * x - 11505;
 
-	outb_p((outval >> 8) & 0x01, dev->io + 4);
-	outb_p(outval >> 9, dev->io + 6);
-	outb_p(outval & 0xff, dev->io + 8);
-	mutex_unlock(&dev->lock);
-
+	outb_p((outval >> 8) & 0x01, isa->io + 4);
+	outb_p(outval >> 9, isa->io + 6);
+	outb_p(outval & 0xff, isa->io + 8);
 	return 0;
 }
 
-static int typhoon_setfreq(struct typhoon *dev, unsigned long frequency)
+static int typhoon_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
 {
-	typhoon_setfreq_generic(dev, frequency);
-	dev->curfreq = frequency;
-	return 0;
-}
+	struct typhoon *ty = container_of(isa, struct typhoon, isa);
 
-static void typhoon_mute(struct typhoon *dev)
-{
-	if (dev->muted == 1)
-		return;
-	typhoon_setvol_generic(dev, 0);
-	typhoon_setfreq_generic(dev, dev->mutefreq);
-	dev->muted = 1;
-}
+	if (mute)
+		vol = 0;
+	vol >>= 14;			/* Map 16 bit to 2 bit */
+	vol &= 3;
+	outb_p(vol / 2, isa->io);	/* Set the volume, high bit. */
+	outb_p(vol % 2, isa->io + 2);	/* Set the volume, low bit. */
 
-static void typhoon_unmute(struct typhoon *dev)
-{
-	if (dev->muted == 0)
-		return;
-	typhoon_setfreq_generic(dev, dev->curfreq);
-	typhoon_setvol_generic(dev, dev->curvol);
-	dev->muted = 0;
-}
-
-static int typhoon_setvol(struct typhoon *dev, int vol)
-{
-	if (dev->muted && vol != 0) {	/* user is unmuting the card */
-		dev->curvol = vol;
-		typhoon_unmute(dev);
-		return 0;
+	if (vol == 0 && !ty->muted) {
+		ty->muted = true;
+		return typhoon_s_frequency(isa, mutefreq << 4);
 	}
-	if (vol == dev->curvol)		/* requested volume == current */
-		return 0;
-
-	if (vol == 0) {			/* volume == 0 means mute the card */
-		typhoon_mute(dev);
-		dev->curvol = vol;
-		return 0;
+	if (vol && ty->muted) {
+		ty->muted = false;
+		return typhoon_s_frequency(isa, isa->freq);
 	}
-	typhoon_setvol_generic(dev, vol);
-	dev->curvol = vol;
 	return 0;
 }
 
-static int vidioc_querycap(struct file *file, void  *priv,
-					struct v4l2_capability *v)
-{
-	strlcpy(v->driver, "radio-typhoon", sizeof(v->driver));
-	strlcpy(v->card, "Typhoon Radio", sizeof(v->card));
-	strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-	return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-					struct v4l2_tuner *v)
-{
-	if (v->index > 0)
-		return -EINVAL;
-
-	strlcpy(v->name, "FM", sizeof(v->name));
-	v->type = V4L2_TUNER_RADIO;
-	v->rangelow = 87.5 * 16000;
-	v->rangehigh = 108 * 16000;
-	v->rxsubchans = V4L2_TUNER_SUB_MONO;
-	v->capability = V4L2_TUNER_CAP_LOW;
-	v->audmode = V4L2_TUNER_MODE_MONO;
-	v->signal = 0xFFFF;     /* We can't get the signal strength */
-	return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-					struct v4l2_tuner *v)
-{
-	return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-					struct v4l2_frequency *f)
-{
-	struct typhoon *dev = video_drvdata(file);
-
-	if (f->tuner != 0)
-		return -EINVAL;
-	f->type = V4L2_TUNER_RADIO;
-	f->frequency = dev->curfreq;
-	return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-					struct v4l2_frequency *f)
-{
-	struct typhoon *dev = video_drvdata(file);
-
-	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-		return -EINVAL;
-	dev->curfreq = f->frequency;
-	typhoon_setfreq(dev, dev->curfreq);
-	return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-					struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-	case V4L2_CID_AUDIO_VOLUME:
-		return v4l2_ctrl_query_fill(qc, 0, 65535, 16384, 65535);
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct typhoon *dev = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = dev->muted;
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		ctrl->value = dev->curvol;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_s_ctrl (struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct typhoon *dev = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		if (ctrl->value)
-			typhoon_mute(dev);
-		else
-			typhoon_unmute(dev);
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		typhoon_setvol(dev, ctrl->value);
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-	*i = 0;
-	return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-	return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
-{
-	a->index = 0;
-	strlcpy(a->name, "Radio", sizeof(a->name));
-	a->capability = V4L2_AUDCAP_STEREO;
-	return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
-{
-	return a->index ? -EINVAL : 0;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	struct typhoon *dev = video_drvdata(file);
-	struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
-
-	v4l2_info(v4l2_dev, BANNER);
-#ifdef MODULE
-	v4l2_info(v4l2_dev, "Load type: Driver loaded as a module\n\n");
-#else
-	v4l2_info(v4l2_dev, "Load type: Driver compiled into kernel\n\n");
-#endif
-	v4l2_info(v4l2_dev, "frequency = %lu kHz\n", dev->curfreq >> 4);
-	v4l2_info(v4l2_dev, "volume = %d\n", dev->curvol);
-	v4l2_info(v4l2_dev, "mute = %s\n", dev->muted ?  "on" : "off");
-	v4l2_info(v4l2_dev, "io = 0x%x\n", dev->io);
-	v4l2_info(v4l2_dev, "mute frequency = %lu kHz\n", dev->mutefreq >> 4);
-	return 0;
-}
-
-static const struct v4l2_file_operations typhoon_fops = {
-	.owner		= THIS_MODULE,
-	.unlocked_ioctl	= video_ioctl2,
+static const struct radio_isa_ops typhoon_ops = {
+	.alloc = typhoon_alloc,
+	.s_mute_volume = typhoon_s_mute_volume,
+	.s_frequency = typhoon_s_frequency,
 };
 
-static const struct v4l2_ioctl_ops typhoon_ioctl_ops = {
-	.vidioc_log_status  = vidioc_log_status,
-	.vidioc_querycap    = vidioc_querycap,
-	.vidioc_g_tuner     = vidioc_g_tuner,
-	.vidioc_s_tuner     = vidioc_s_tuner,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
-	.vidioc_g_input     = vidioc_g_input,
-	.vidioc_s_input     = vidioc_s_input,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
-	.vidioc_queryctrl   = vidioc_queryctrl,
-	.vidioc_g_ctrl      = vidioc_g_ctrl,
-	.vidioc_s_ctrl      = vidioc_s_ctrl,
+static const int typhoon_ioports[] = { 0x316, 0x336 };
+
+static struct radio_isa_driver typhoon_driver = {
+	.driver = {
+		.match		= radio_isa_match,
+		.probe		= radio_isa_probe,
+		.remove		= radio_isa_remove,
+		.driver		= {
+			.name	= "radio-typhoon",
+		},
+	},
+	.io_params = io,
+	.radio_nr_params = radio_nr,
+	.io_ports = typhoon_ioports,
+	.num_of_io_ports = ARRAY_SIZE(typhoon_ioports),
+	.region_size = 8,
+	.card = "Typhoon Radio",
+	.ops = &typhoon_ops,
+	.has_stereo = true,
+	.max_volume = 3,
 };
 
 static int __init typhoon_init(void)
 {
-	struct typhoon *dev = &typhoon_card;
-	struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
-	int res;
-
-	strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name));
-	dev->io = io;
-
-	if (dev->io == -1) {
-		v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n");
-		return -EINVAL;
+	if (mutefreq < 87000 || mutefreq > 108000) {
+		printk(KERN_ERR "%s: You must set a frequency (in kHz) used when muting the card,\n",
+				typhoon_driver.driver.driver.name);
+		printk(KERN_ERR "%s: e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108000)\n",
+				typhoon_driver.driver.driver.name);
+		return -ENODEV;
 	}
-
-	if (mutefreq < 87000 || mutefreq > 108500) {
-		v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n");
-		v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n");
-		return -EINVAL;
-	}
-	dev->curfreq = dev->mutefreq = mutefreq << 4;
-
-	mutex_init(&dev->lock);
-	if (!request_region(dev->io, 8, "typhoon")) {
-		v4l2_err(v4l2_dev, "port 0x%x already in use\n",
-		       dev->io);
-		return -EBUSY;
-	}
-
-	res = v4l2_device_register(NULL, v4l2_dev);
-	if (res < 0) {
-		release_region(dev->io, 8);
-		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-		return res;
-	}
-	v4l2_info(v4l2_dev, BANNER);
-
-	strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
-	dev->vdev.v4l2_dev = v4l2_dev;
-	dev->vdev.fops = &typhoon_fops;
-	dev->vdev.ioctl_ops = &typhoon_ioctl_ops;
-	dev->vdev.release = video_device_release_empty;
-	video_set_drvdata(&dev->vdev, dev);
-
-	/* mute card - prevents noisy bootups */
-	typhoon_mute(dev);
-
-	if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-		v4l2_device_unregister(&dev->v4l2_dev);
-		release_region(dev->io, 8);
-		return -EINVAL;
-	}
-	v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io);
-	v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", mutefreq);
-
-	return 0;
+	return isa_register_driver(&typhoon_driver.driver, TYPHOON_MAX);
 }
 
 static void __exit typhoon_exit(void)
 {
-	struct typhoon *dev = &typhoon_card;
-
-	video_unregister_device(&dev->vdev);
-	v4l2_device_unregister(&dev->v4l2_dev);
-	release_region(dev->io, 8);
+	isa_unregister_driver(&typhoon_driver.driver);
 }
 
+
 module_init(typhoon_init);
 module_exit(typhoon_exit);
 
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index f5613b9..026e88e 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -1,5 +1,6 @@
-/* zoltrix radio plus driver for Linux radio support
- * (c) 1998 C. van Schaik <carl@leg.uct.ac.za>
+/*
+ * Zoltrix Radio Plus driver
+ * Copyright 1998 C. van Schaik <carl@leg.uct.ac.za>
  *
  * BUGS
  *  Due to the inconsistency in reading from the signal flags
@@ -27,6 +28,14 @@
  *
  * 2006-07-24 - Converted to V4L2 API
  *		by Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
+ *
+ * Note that this is the driver for the Zoltrix Radio Plus.
+ * This driver does not work for the Zoltrix Radio Plus 108 or the
+ * Zoltrix Radio Plus for Windows.
+ *
+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
  */
 
 #include <linux/module.h>	/* Modules                        */
@@ -36,82 +45,70 @@
 #include <linux/videodev2.h>	/* kernel radio structs           */
 #include <linux/mutex.h>
 #include <linux/io.h>		/* outb, outb_p                   */
+#include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include "radio-isa.h"
 
-MODULE_AUTHOR("C.van Schaik");
+MODULE_AUTHOR("C. van Schaik");
 MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("0.1.99");
 
 #ifndef CONFIG_RADIO_ZOLTRIX_PORT
 #define CONFIG_RADIO_ZOLTRIX_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_ZOLTRIX_PORT;
-static int radio_nr = -1;
+#define ZOLTRIX_MAX 2
 
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)");
-module_param(radio_nr, int, 0);
+static int io[ZOLTRIX_MAX] = { [0] = CONFIG_RADIO_ZOLTRIX_PORT,
+			       [1 ... (ZOLTRIX_MAX - 1)] = -1 };
+static int radio_nr[ZOLTRIX_MAX] = { [0 ... (ZOLTRIX_MAX - 1)] = -1 };
+
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the Zoltrix Radio Plus card (0x20c or 0x30c)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
 
 struct zoltrix {
-	struct v4l2_device v4l2_dev;
-	struct video_device vdev;
-	int io;
+	struct radio_isa_card isa;
 	int curvol;
-	unsigned long curfreq;
-	int muted;
-	unsigned int stereo;
-	struct mutex lock;
+	bool muted;
 };
 
-static struct zoltrix zoltrix_card;
-
-static int zol_setvol(struct zoltrix *zol, int vol)
+static struct radio_isa_card *zoltrix_alloc(void)
 {
-	zol->curvol = vol;
-	if (zol->muted)
-		return 0;
+	struct zoltrix *zol = kzalloc(sizeof(*zol), GFP_KERNEL);
 
-	mutex_lock(&zol->lock);
-	if (vol == 0) {
-		outb(0, zol->io);
-		outb(0, zol->io);
-		inb(zol->io + 3);    /* Zoltrix needs to be read to confirm */
-		mutex_unlock(&zol->lock);
+	return zol ? &zol->isa : NULL;
+}
+
+static int zoltrix_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
+{
+	struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
+
+	zol->curvol = vol;
+	zol->muted = mute;
+	if (mute || vol == 0) {
+		outb(0, isa->io);
+		outb(0, isa->io);
+		inb(isa->io + 3);            /* Zoltrix needs to be read to confirm */
 		return 0;
 	}
 
-	outb(zol->curvol-1, zol->io);
+	outb(vol - 1, isa->io);
 	msleep(10);
-	inb(zol->io + 2);
-	mutex_unlock(&zol->lock);
+	inb(isa->io + 2);
 	return 0;
 }
 
-static void zol_mute(struct zoltrix *zol)
+/* tunes the radio to the desired frequency */
+static int zoltrix_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
-	zol->muted = 1;
-	mutex_lock(&zol->lock);
-	outb(0, zol->io);
-	outb(0, zol->io);
-	inb(zol->io + 3);            /* Zoltrix needs to be read to confirm */
-	mutex_unlock(&zol->lock);
-}
-
-static void zol_unmute(struct zoltrix *zol)
-{
-	zol->muted = 0;
-	zol_setvol(zol, zol->curvol);
-}
-
-static int zol_setfreq(struct zoltrix *zol, unsigned long freq)
-{
-	/* tunes the radio to the desired frequency */
-	struct v4l2_device *v4l2_dev = &zol->v4l2_dev;
+	struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
+	struct v4l2_device *v4l2_dev = &isa->v4l2_dev;
 	unsigned long long bitmask, f, m;
-	unsigned int stereo = zol->stereo;
+	bool stereo = isa->stereo;
 	int i;
 
 	if (freq == 0) {
@@ -125,340 +122,125 @@
 	bitmask = 0xc480402c10080000ull;
 	i = 45;
 
-	mutex_lock(&zol->lock);
+	outb(0, isa->io);
+	outb(0, isa->io);
+	inb(isa->io + 3);            /* Zoltrix needs to be read to confirm */
 
-	zol->curfreq = freq;
-
-	outb(0, zol->io);
-	outb(0, zol->io);
-	inb(zol->io + 3);            /* Zoltrix needs to be read to confirm */
-
-	outb(0x40, zol->io);
-	outb(0xc0, zol->io);
+	outb(0x40, isa->io);
+	outb(0xc0, isa->io);
 
 	bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ (stereo << 31));
 	while (i--) {
 		if ((bitmask & 0x8000000000000000ull) != 0) {
-			outb(0x80, zol->io);
+			outb(0x80, isa->io);
 			udelay(50);
-			outb(0x00, zol->io);
+			outb(0x00, isa->io);
 			udelay(50);
-			outb(0x80, zol->io);
+			outb(0x80, isa->io);
 			udelay(50);
 		} else {
-			outb(0xc0, zol->io);
+			outb(0xc0, isa->io);
 			udelay(50);
-			outb(0x40, zol->io);
+			outb(0x40, isa->io);
 			udelay(50);
-			outb(0xc0, zol->io);
+			outb(0xc0, isa->io);
 			udelay(50);
 		}
 		bitmask *= 2;
 	}
 	/* termination sequence */
-	outb(0x80, zol->io);
-	outb(0xc0, zol->io);
-	outb(0x40, zol->io);
+	outb(0x80, isa->io);
+	outb(0xc0, isa->io);
+	outb(0x40, isa->io);
 	udelay(1000);
-	inb(zol->io + 2);
-
+	inb(isa->io + 2);
 	udelay(1000);
 
-	if (zol->muted) {
-		outb(0, zol->io);
-		outb(0, zol->io);
-		inb(zol->io + 3);
-		udelay(1000);
-	}
-
-	mutex_unlock(&zol->lock);
-
-	if (!zol->muted)
-		zol_setvol(zol, zol->curvol);
-	return 0;
+	return zoltrix_s_mute_volume(isa, zol->muted, zol->curvol);
 }
 
 /* Get signal strength */
-static int zol_getsigstr(struct zoltrix *zol)
+static u32 zoltrix_g_rxsubchans(struct radio_isa_card *isa)
 {
+	struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
 	int a, b;
 
-	mutex_lock(&zol->lock);
-	outb(0x00, zol->io);         /* This stuff I found to do nothing */
-	outb(zol->curvol, zol->io);
+	outb(0x00, isa->io);         /* This stuff I found to do nothing */
+	outb(zol->curvol, isa->io);
 	msleep(20);
 
-	a = inb(zol->io);
+	a = inb(isa->io);
 	msleep(10);
-	b = inb(zol->io);
+	b = inb(isa->io);
 
-	mutex_unlock(&zol->lock);
+	return (a == b && a == 0xcf) ?
+		V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+}
+
+static u32 zoltrix_g_signal(struct radio_isa_card *isa)
+{
+	struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
+	int a, b;
+
+	outb(0x00, isa->io);         /* This stuff I found to do nothing */
+	outb(zol->curvol, isa->io);
+	msleep(20);
+
+	a = inb(isa->io);
+	msleep(10);
+	b = inb(isa->io);
 
 	if (a != b)
 		return 0;
 
 	/* I found this out by playing with a binary scanner on the card io */
-	return a == 0xcf || a == 0xdf || a == 0xef;
+	return (a == 0xcf || a == 0xdf || a == 0xef) ? 0xffff : 0;
 }
 
-static int zol_is_stereo(struct zoltrix *zol)
+static int zoltrix_s_stereo(struct radio_isa_card *isa, bool stereo)
 {
-	int x1, x2;
-
-	mutex_lock(&zol->lock);
-
-	outb(0x00, zol->io);
-	outb(zol->curvol, zol->io);
-	msleep(20);
-
-	x1 = inb(zol->io);
-	msleep(10);
-	x2 = inb(zol->io);
-
-	mutex_unlock(&zol->lock);
-
-	return x1 == x2 && x1 == 0xcf;
+	return zoltrix_s_frequency(isa, isa->freq);
 }
 
-static int vidioc_querycap(struct file *file, void  *priv,
-					struct v4l2_capability *v)
-{
-	strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver));
-	strlcpy(v->card, "Zoltrix Radio", sizeof(v->card));
-	strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-	return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-					struct v4l2_tuner *v)
-{
-	struct zoltrix *zol = video_drvdata(file);
-
-	if (v->index > 0)
-		return -EINVAL;
-
-	strlcpy(v->name, "FM", sizeof(v->name));
-	v->type = V4L2_TUNER_RADIO;
-	v->rangelow = 88 * 16000;
-	v->rangehigh = 108 * 16000;
-	v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-	v->capability = V4L2_TUNER_CAP_LOW;
-	if (zol_is_stereo(zol))
-		v->audmode = V4L2_TUNER_MODE_STEREO;
-	else
-		v->audmode = V4L2_TUNER_MODE_MONO;
-	v->signal = 0xFFFF * zol_getsigstr(zol);
-	return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-					struct v4l2_tuner *v)
-{
-	return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-					struct v4l2_frequency *f)
-{
-	struct zoltrix *zol = video_drvdata(file);
-
-	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-		return -EINVAL;
-	if (zol_setfreq(zol, f->frequency) != 0)
-		return -EINVAL;
-	return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-					struct v4l2_frequency *f)
-{
-	struct zoltrix *zol = video_drvdata(file);
-
-	if (f->tuner != 0)
-		return -EINVAL;
-	f->type = V4L2_TUNER_RADIO;
-	f->frequency = zol->curfreq;
-	return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-					struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-	case V4L2_CID_AUDIO_VOLUME:
-		return v4l2_ctrl_query_fill(qc, 0, 65535, 4096, 65535);
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctrl)
-{
-	struct zoltrix *zol = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = zol->muted;
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		ctrl->value = zol->curvol * 4096;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctrl)
-{
-	struct zoltrix *zol = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		if (ctrl->value)
-			zol_mute(zol);
-		else {
-			zol_unmute(zol);
-			zol_setvol(zol, zol->curvol);
-		}
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		zol_setvol(zol, ctrl->value / 4096);
-		return 0;
-	}
-	zol->stereo = 1;
-	if (zol_setfreq(zol, zol->curfreq) != 0)
-		return -EINVAL;
-#if 0
-/* FIXME: Implement stereo/mono switch on V4L2 */
-	if (v->mode & VIDEO_SOUND_STEREO) {
-		zol->stereo = 1;
-		zol_setfreq(zol, zol->curfreq);
-	}
-	if (v->mode & VIDEO_SOUND_MONO) {
-		zol->stereo = 0;
-		zol_setfreq(zol, zol->curfreq);
-	}
-#endif
-	return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-	*i = 0;
-	return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-	return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
-{
-	a->index = 0;
-	strlcpy(a->name, "Radio", sizeof(a->name));
-	a->capability = V4L2_AUDCAP_STEREO;
-	return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
-{
-	return a->index ? -EINVAL : 0;
-}
-
-static const struct v4l2_file_operations zoltrix_fops =
-{
-	.owner		= THIS_MODULE,
-	.unlocked_ioctl	= video_ioctl2,
+static const struct radio_isa_ops zoltrix_ops = {
+	.alloc = zoltrix_alloc,
+	.s_mute_volume = zoltrix_s_mute_volume,
+	.s_frequency = zoltrix_s_frequency,
+	.s_stereo = zoltrix_s_stereo,
+	.g_rxsubchans = zoltrix_g_rxsubchans,
+	.g_signal = zoltrix_g_signal,
 };
 
-static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = {
-	.vidioc_querycap    = vidioc_querycap,
-	.vidioc_g_tuner     = vidioc_g_tuner,
-	.vidioc_s_tuner     = vidioc_s_tuner,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
-	.vidioc_g_input     = vidioc_g_input,
-	.vidioc_s_input     = vidioc_s_input,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
-	.vidioc_queryctrl   = vidioc_queryctrl,
-	.vidioc_g_ctrl      = vidioc_g_ctrl,
-	.vidioc_s_ctrl      = vidioc_s_ctrl,
+static const int zoltrix_ioports[] = { 0x20c, 0x30c };
+
+static struct radio_isa_driver zoltrix_driver = {
+	.driver = {
+		.match		= radio_isa_match,
+		.probe		= radio_isa_probe,
+		.remove		= radio_isa_remove,
+		.driver		= {
+			.name	= "radio-zoltrix",
+		},
+	},
+	.io_params = io,
+	.radio_nr_params = radio_nr,
+	.io_ports = zoltrix_ioports,
+	.num_of_io_ports = ARRAY_SIZE(zoltrix_ioports),
+	.region_size = 2,
+	.card = "Zoltrix Radio Plus",
+	.ops = &zoltrix_ops,
+	.has_stereo = true,
+	.max_volume = 15,
 };
 
 static int __init zoltrix_init(void)
 {
-	struct zoltrix *zol = &zoltrix_card;
-	struct v4l2_device *v4l2_dev = &zol->v4l2_dev;
-	int res;
-
-	strlcpy(v4l2_dev->name, "zoltrix", sizeof(v4l2_dev->name));
-	zol->io = io;
-	if (zol->io == -1) {
-		v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or 0x30c\n");
-		return -EINVAL;
-	}
-	if (zol->io != 0x20c && zol->io != 0x30c) {
-		v4l2_err(v4l2_dev, "invalid port, try 0x20c or 0x30c\n");
-		return -ENXIO;
-	}
-
-	if (!request_region(zol->io, 2, "zoltrix")) {
-		v4l2_err(v4l2_dev, "port 0x%x already in use\n", zol->io);
-		return -EBUSY;
-	}
-
-	res = v4l2_device_register(NULL, v4l2_dev);
-	if (res < 0) {
-		release_region(zol->io, 2);
-		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-		return res;
-	}
-
-	mutex_init(&zol->lock);
-
-	/* mute card - prevents noisy bootups */
-
-	/* this ensures that the volume is all the way down  */
-
-	outb(0, zol->io);
-	outb(0, zol->io);
-	msleep(20);
-	inb(zol->io + 3);
-
-	zol->curvol = 0;
-	zol->stereo = 1;
-
-	strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name));
-	zol->vdev.v4l2_dev = v4l2_dev;
-	zol->vdev.fops = &zoltrix_fops;
-	zol->vdev.ioctl_ops = &zoltrix_ioctl_ops;
-	zol->vdev.release = video_device_release_empty;
-	video_set_drvdata(&zol->vdev, zol);
-
-	if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-		v4l2_device_unregister(v4l2_dev);
-		release_region(zol->io, 2);
-		return -EINVAL;
-	}
-	v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n");
-
-	return 0;
+	return isa_register_driver(&zoltrix_driver.driver, ZOLTRIX_MAX);
 }
 
 static void __exit zoltrix_exit(void)
 {
-	struct zoltrix *zol = &zoltrix_card;
-
-	video_unregister_device(&zol->vdev);
-	v4l2_device_unregister(&zol->v4l2_dev);
-	release_region(zol->io, 2);
+	isa_unregister_driver(&zoltrix_driver.driver);
 }
 
 module_init(zoltrix_init);
diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c
index b1193df..9474706 100644
--- a/drivers/media/radio/saa7706h.c
+++ b/drivers/media/radio/saa7706h.c
@@ -434,18 +434,7 @@
 	.id_table	= saa7706h_id,
 };
 
-static __init int saa7706h_init(void)
-{
-	return i2c_add_driver(&saa7706h_driver);
-}
-
-static __exit void saa7706h_exit(void)
-{
-	i2c_del_driver(&saa7706h_driver);
-}
-
-module_init(saa7706h_init);
-module_exit(saa7706h_exit);
+module_i2c_driver(saa7706h_driver);
 
 MODULE_DESCRIPTION("SAA7706H Car Radio DSP driver");
 MODULE_AUTHOR("Mocean Laboratories");
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c
index fd3541b..9b546a5 100644
--- a/drivers/media/radio/si470x/radio-si470x-i2c.c
+++ b/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -539,33 +539,7 @@
 	.id_table		= si470x_i2c_id,
 };
 
-
-
-/**************************************************************************
- * Module Interface
- **************************************************************************/
-
-/*
- * si470x_i2c_init - module init
- */
-static int __init si470x_i2c_init(void)
-{
-	printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n");
-	return i2c_add_driver(&si470x_i2c_driver);
-}
-
-
-/*
- * si470x_i2c_exit - module exit
- */
-static void __exit si470x_i2c_exit(void)
-{
-	i2c_del_driver(&si470x_i2c_driver);
-}
-
-
-module_init(si470x_i2c_init);
-module_exit(si470x_i2c_exit);
+module_i2c_driver(si470x_i2c_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c
index 27aba93..b898c89 100644
--- a/drivers/media/radio/si4713-i2c.c
+++ b/drivers/media/radio/si4713-i2c.c
@@ -2106,17 +2106,4 @@
 	.id_table       = si4713_id,
 };
 
-/* Module Interface */
-static int __init si4713_module_init(void)
-{
-	return i2c_add_driver(&si4713_i2c_driver);
-}
-
-static void __exit si4713_module_exit(void)
-{
-	i2c_del_driver(&si4713_i2c_driver);
-}
-
-module_init(si4713_module_init);
-module_exit(si4713_module_exit);
-
+module_i2c_driver(si4713_i2c_driver);
diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c
index 3408685..6418c4c 100644
--- a/drivers/media/radio/tef6862.c
+++ b/drivers/media/radio/tef6862.c
@@ -215,20 +215,8 @@
 	.id_table	= tef6862_id,
 };
 
-static __init int tef6862_init(void)
-{
-	return i2c_add_driver(&tef6862_driver);
-}
-
-static __exit void tef6862_exit(void)
-{
-	i2c_del_driver(&tef6862_driver);
-}
-
-module_init(tef6862_init);
-module_exit(tef6862_exit);
+module_i2c_driver(tef6862_driver);
 
 MODULE_DESCRIPTION("TEF6862 Car Radio Enhanced Selectivity Tuner");
 MODULE_AUTHOR("Mocean Laboratories");
 MODULE_LICENSE("GPL v2");
-
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 4df4aff..a3fbb21 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -266,4 +266,13 @@
 	   To compile this driver as a module, choose M here: the module will
 	   be called rc_loopback.
 
+config IR_GPIO_CIR
+	tristate "GPIO IR remote control"
+	depends on RC_CORE
+	---help---
+	   Say Y if you want to use GPIO based IR Receiver.
+
+	   To compile this driver as a module, choose M here: the module will
+	   be called gpio-ir-recv.
+
 endif #RC_CORE
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index fb3dee2..29f364f 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -26,3 +26,4 @@
 obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
 obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o
 obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o
+obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index 7f7079b..392d4be 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -117,7 +117,7 @@
 static void cir_dump_regs(struct fintek_dev *fintek)
 {
 	fintek_config_mode_enable(fintek);
-	fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+	fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
 
 	pr_reg("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME);
 	pr_reg(" * CR CIR BASE ADDR: 0x%x\n",
@@ -143,7 +143,7 @@
 	u8 chip_major, chip_minor;
 	u8 vendor_major, vendor_minor;
 	u8 portsel, ir_class;
-	u16 vendor;
+	u16 vendor, chip;
 	int ret = 0;
 
 	fintek_config_mode_enable(fintek);
@@ -176,6 +176,7 @@
 
 	chip_major = fintek_cr_read(fintek, GCR_CHIP_ID_HI);
 	chip_minor = fintek_cr_read(fintek, GCR_CHIP_ID_LO);
+	chip  = chip_major << 8 | chip_minor;
 
 	vendor_major = fintek_cr_read(fintek, GCR_VENDOR_ID_HI);
 	vendor_minor = fintek_cr_read(fintek, GCR_VENDOR_ID_LO);
@@ -192,6 +193,15 @@
 	fintek->chip_major  = chip_major;
 	fintek->chip_minor  = chip_minor;
 	fintek->chip_vendor = vendor;
+
+	/*
+	 * Newer reviews of this chipset uses port 8 instead of 5
+	 */
+	if ((chip != 0x0408) || (chip != 0x0804))
+		fintek->logical_dev_cir = LOGICAL_DEV_CIR_REV2;
+	else
+		fintek->logical_dev_cir = LOGICAL_DEV_CIR_REV1;
+
 	spin_unlock_irqrestore(&fintek->fintek_lock, flags);
 
 	return ret;
@@ -200,7 +210,7 @@
 static void fintek_cir_ldev_init(struct fintek_dev *fintek)
 {
 	/* Select CIR logical device and enable */
-	fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+	fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
 	fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
 
 	/* Write allocated CIR address and IRQ information to hardware */
@@ -381,7 +391,7 @@
 	fit_dbg_verbose("%s firing", __func__);
 
 	fintek_config_mode_enable(fintek);
-	fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+	fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
 	fintek_config_mode_disable(fintek);
 
 	/*
@@ -422,7 +432,7 @@
 	fintek_config_mode_enable(fintek);
 
 	/* enable the CIR logical device */
-	fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+	fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
 	fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
 
 	fintek_config_mode_disable(fintek);
@@ -439,7 +449,7 @@
 	fintek_config_mode_enable(fintek);
 
 	/* disable the CIR logical device */
-	fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+	fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
 	fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN);
 
 	fintek_config_mode_disable(fintek);
@@ -611,7 +621,7 @@
 	fintek_config_mode_enable(fintek);
 
 	/* disable cir logical dev */
-	fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+	fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
 	fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN);
 
 	fintek_config_mode_disable(fintek);
@@ -634,7 +644,7 @@
 
 	/* Enable CIR logical device */
 	fintek_config_mode_enable(fintek);
-	fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+	fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
 	fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
 
 	fintek_config_mode_disable(fintek);
diff --git a/drivers/media/rc/fintek-cir.h b/drivers/media/rc/fintek-cir.h
index 1b10b20..82516a1 100644
--- a/drivers/media/rc/fintek-cir.h
+++ b/drivers/media/rc/fintek-cir.h
@@ -88,6 +88,7 @@
 	u8 chip_major;
 	u8 chip_minor;
 	u16 chip_vendor;
+	u8 logical_dev_cir;
 
 	/* hardware features */
 	bool hw_learning_capable;
@@ -172,7 +173,8 @@
 #define LOGICAL_DEV_ENABLE	0x01
 
 /* Logical device number of the CIR function */
-#define LOGICAL_DEV_CIR		0x05
+#define LOGICAL_DEV_CIR_REV1	0x05
+#define LOGICAL_DEV_CIR_REV2	0x08
 
 /* CIR Logical Device (LDN 0x08) config registers */
 #define CIR_CR_COMMAND_INDEX	0x04
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
new file mode 100644
index 0000000..0d87545
--- /dev/null
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -0,0 +1,205 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <media/rc-core.h>
+#include <media/gpio-ir-recv.h>
+
+#define GPIO_IR_DRIVER_NAME	"gpio-rc-recv"
+#define GPIO_IR_DEVICE_NAME	"gpio_ir_recv"
+
+struct gpio_rc_dev {
+	struct rc_dev *rcdev;
+	int gpio_nr;
+	bool active_low;
+};
+
+static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
+{
+	struct gpio_rc_dev *gpio_dev = dev_id;
+	int gval;
+	int rc = 0;
+	enum raw_event_type type = IR_SPACE;
+
+	gval = gpio_get_value_cansleep(gpio_dev->gpio_nr);
+
+	if (gval < 0)
+		goto err_get_value;
+
+	if (gpio_dev->active_low)
+		gval = !gval;
+
+	if (gval == 1)
+		type = IR_PULSE;
+
+	rc = ir_raw_event_store_edge(gpio_dev->rcdev, type);
+	if (rc < 0)
+		goto err_get_value;
+
+	ir_raw_event_handle(gpio_dev->rcdev);
+
+err_get_value:
+	return IRQ_HANDLED;
+}
+
+static int __devinit gpio_ir_recv_probe(struct platform_device *pdev)
+{
+	struct gpio_rc_dev *gpio_dev;
+	struct rc_dev *rcdev;
+	const struct gpio_ir_recv_platform_data *pdata =
+					pdev->dev.platform_data;
+	int rc;
+
+	if (!pdata)
+		return -EINVAL;
+
+	if (pdata->gpio_nr < 0)
+		return -EINVAL;
+
+	gpio_dev = kzalloc(sizeof(struct gpio_rc_dev), GFP_KERNEL);
+	if (!gpio_dev)
+		return -ENOMEM;
+
+	rcdev = rc_allocate_device();
+	if (!rcdev) {
+		rc = -ENOMEM;
+		goto err_allocate_device;
+	}
+
+	rcdev->driver_type = RC_DRIVER_IR_RAW;
+	rcdev->allowed_protos = RC_TYPE_ALL;
+	rcdev->input_name = GPIO_IR_DEVICE_NAME;
+	rcdev->input_id.bustype = BUS_HOST;
+	rcdev->driver_name = GPIO_IR_DRIVER_NAME;
+	rcdev->map_name = RC_MAP_EMPTY;
+
+	gpio_dev->rcdev = rcdev;
+	gpio_dev->gpio_nr = pdata->gpio_nr;
+	gpio_dev->active_low = pdata->active_low;
+
+	rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv");
+	if (rc < 0)
+		goto err_gpio_request;
+	rc  = gpio_direction_input(pdata->gpio_nr);
+	if (rc < 0)
+		goto err_gpio_direction_input;
+
+	rc = rc_register_device(rcdev);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "failed to register rc device\n");
+		goto err_register_rc_device;
+	}
+
+	platform_set_drvdata(pdev, gpio_dev);
+
+	rc = request_any_context_irq(gpio_to_irq(pdata->gpio_nr),
+				gpio_ir_recv_irq,
+			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+					"gpio-ir-recv-irq", gpio_dev);
+	if (rc < 0)
+		goto err_request_irq;
+
+	return 0;
+
+err_request_irq:
+	platform_set_drvdata(pdev, NULL);
+	rc_unregister_device(rcdev);
+err_register_rc_device:
+err_gpio_direction_input:
+	gpio_free(pdata->gpio_nr);
+err_gpio_request:
+	rc_free_device(rcdev);
+	rcdev = NULL;
+err_allocate_device:
+	kfree(gpio_dev);
+	return rc;
+}
+
+static int __devexit gpio_ir_recv_remove(struct platform_device *pdev)
+{
+	struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+
+	free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
+	platform_set_drvdata(pdev, NULL);
+	rc_unregister_device(gpio_dev->rcdev);
+	gpio_free(gpio_dev->gpio_nr);
+	rc_free_device(gpio_dev->rcdev);
+	kfree(gpio_dev);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int gpio_ir_recv_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
+	else
+		disable_irq(gpio_to_irq(gpio_dev->gpio_nr));
+
+	return 0;
+}
+
+static int gpio_ir_recv_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(dev))
+		disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
+	else
+		enable_irq(gpio_to_irq(gpio_dev->gpio_nr));
+
+	return 0;
+}
+
+static const struct dev_pm_ops gpio_ir_recv_pm_ops = {
+	.suspend        = gpio_ir_recv_suspend,
+	.resume         = gpio_ir_recv_resume,
+};
+#endif
+
+static struct platform_driver gpio_ir_recv_driver = {
+	.probe  = gpio_ir_recv_probe,
+	.remove = __devexit_p(gpio_ir_recv_remove),
+	.driver = {
+		.name   = GPIO_IR_DRIVER_NAME,
+		.owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	= &gpio_ir_recv_pm_ops,
+#endif
+	},
+};
+
+static int __init gpio_ir_recv_init(void)
+{
+	return platform_driver_register(&gpio_ir_recv_driver);
+}
+module_init(gpio_ir_recv_init);
+
+static void __exit gpio_ir_recv_exit(void)
+{
+	platform_driver_unregister(&gpio_ir_recv_driver);
+}
+module_exit(gpio_ir_recv_exit);
+
+MODULE_DESCRIPTION("GPIO IR Receiver driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index d5e2b50..dab98b37 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -130,7 +130,7 @@
 		case 15:
 			device    = bitrev8((data->bits >>  0) & 0xFF);
 			subdevice = 0;
-			function  = bitrev8((data->bits >>  7) & 0xFD);
+			function  = bitrev8((data->bits >>  7) & 0xFE);
 			break;
 		case 20:
 			device    = bitrev8((data->bits >>  5) & 0xF8);
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 36e4d5e..49ce266 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -41,8 +41,11 @@
 			rc-imon-mce.o \
 			rc-imon-pad.o \
 			rc-iodata-bctv7e.o \
+			rc-it913x-v1.o \
+			rc-it913x-v2.o \
 			rc-kaiomy.o \
 			rc-kworld-315u.o \
+			rc-kworld-pc150u.o \
 			rc-kworld-plus-tv-analog.o \
 			rc-leadtek-y04g0051.o \
 			rc-lirc.o \
diff --git a/drivers/media/rc/keymaps/rc-it913x-v1.c b/drivers/media/rc/keymaps/rc-it913x-v1.c
new file mode 100644
index 0000000..0ac775f
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-it913x-v1.c
@@ -0,0 +1,95 @@
+/* ITE Generic remotes Version 1
+ *
+ * Copyright (C) 2012 Malcolm Priestley (tvboxspy@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 <media/rc-map.h>
+#include <linux/module.h>
+
+
+static struct rc_map_table it913x_v1_rc[] = {
+	/* Type 1 */
+	{ 0x61d601, KEY_VIDEO },           /* Source */
+	{ 0x61d602, KEY_3 },
+	{ 0x61d603, KEY_POWER },           /* ShutDown */
+	{ 0x61d604, KEY_1 },
+	{ 0x61d605, KEY_5 },
+	{ 0x61d606, KEY_6 },
+	{ 0x61d607, KEY_CHANNELDOWN },     /* CH- */
+	{ 0x61d608, KEY_2 },
+	{ 0x61d609, KEY_CHANNELUP },       /* CH+ */
+	{ 0x61d60a, KEY_9 },
+	{ 0x61d60b, KEY_ZOOM },            /* Zoom */
+	{ 0x61d60c, KEY_7 },
+	{ 0x61d60d, KEY_8 },
+	{ 0x61d60e, KEY_VOLUMEUP },        /* Vol+ */
+	{ 0x61d60f, KEY_4 },
+	{ 0x61d610, KEY_ESC },             /* [back up arrow] */
+	{ 0x61d611, KEY_0 },
+	{ 0x61d612, KEY_OK },              /* [enter arrow] */
+	{ 0x61d613, KEY_VOLUMEDOWN },      /* Vol- */
+	{ 0x61d614, KEY_RECORD },          /* Rec */
+	{ 0x61d615, KEY_STOP },            /* Stop */
+	{ 0x61d616, KEY_PLAY },            /* Play */
+	{ 0x61d617, KEY_MUTE },            /* Mute */
+	{ 0x61d618, KEY_UP },
+	{ 0x61d619, KEY_DOWN },
+	{ 0x61d61a, KEY_LEFT },
+	{ 0x61d61b, KEY_RIGHT },
+	{ 0x61d61c, KEY_RED },
+	{ 0x61d61d, KEY_GREEN },
+	{ 0x61d61e, KEY_YELLOW },
+	{ 0x61d61f, KEY_BLUE },
+	{ 0x61d643, KEY_POWER2 },          /* [red power button] */
+	/* Type 2 - 20 buttons */
+	{ 0x807f0d, KEY_0 },
+	{ 0x807f04, KEY_1 },
+	{ 0x807f05, KEY_2 },
+	{ 0x807f06, KEY_3 },
+	{ 0x807f07, KEY_4 },
+	{ 0x807f08, KEY_5 },
+	{ 0x807f09, KEY_6 },
+	{ 0x807f0a, KEY_7 },
+	{ 0x807f1b, KEY_8 },
+	{ 0x807f1f, KEY_9 },
+	{ 0x807f12, KEY_POWER },
+	{ 0x807f01, KEY_MEDIA_REPEAT}, /* Recall */
+	{ 0x807f19, KEY_PAUSE }, /* Timeshift */
+	{ 0x807f1e, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
+	{ 0x807f03, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
+	{ 0x807f1a, KEY_CHANNELUP },
+	{ 0x807f02, KEY_CHANNELDOWN },
+	{ 0x807f0c, KEY_ZOOM },
+	{ 0x807f00, KEY_RECORD },
+	{ 0x807f0e, KEY_STOP },
+};
+
+static struct rc_map_list it913x_v1_map = {
+	.map = {
+		.scan    = it913x_v1_rc,
+		.size    = ARRAY_SIZE(it913x_v1_rc),
+		.rc_type = RC_TYPE_NEC,
+		.name    = RC_MAP_IT913X_V1,
+	}
+};
+
+static int __init init_rc_it913x_v1_map(void)
+{
+	return rc_map_register(&it913x_v1_map);
+}
+
+static void __exit exit_rc_it913x_v1_map(void)
+{
+	rc_map_unregister(&it913x_v1_map);
+}
+
+module_init(init_rc_it913x_v1_map)
+module_exit(exit_rc_it913x_v1_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
diff --git a/drivers/media/rc/keymaps/rc-it913x-v2.c b/drivers/media/rc/keymaps/rc-it913x-v2.c
new file mode 100644
index 0000000..28e376e
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-it913x-v2.c
@@ -0,0 +1,94 @@
+/* ITE Generic remotes Version 2
+ *
+ * Copyright (C) 2012 Malcolm Priestley (tvboxspy@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 <media/rc-map.h>
+#include <linux/module.h>
+
+
+static struct rc_map_table it913x_v2_rc[] = {
+	/* Type 1 */
+	/* 9005 remote */
+	{ 0x807f12, KEY_POWER2 },	/* Power (RED POWER BUTTON)*/
+	{ 0x807f1a, KEY_VIDEO },	/* Source */
+	{ 0x807f1e, KEY_MUTE },		/* Mute */
+	{ 0x807f01, KEY_RECORD },	/* Record */
+	{ 0x807f02, KEY_CHANNELUP },	/* Channel+ */
+	{ 0x807f03, KEY_TIME },		/* TimeShift */
+	{ 0x807f04, KEY_VOLUMEUP },	/* Volume- */
+	{ 0x807f05, KEY_SCREEN },	/* FullScreen */
+	{ 0x807f06, KEY_VOLUMEDOWN },	/* Volume- */
+	{ 0x807f07, KEY_0 },		/* 0 */
+	{ 0x807f08, KEY_CHANNELDOWN },	/* Channel- */
+	{ 0x807f09, KEY_PREVIOUS },	/* Recall */
+	{ 0x807f0a, KEY_1 },		/* 1 */
+	{ 0x807f1b, KEY_2 },		/* 2 */
+	{ 0x807f1f, KEY_3 },		/* 3 */
+	{ 0x807f0c, KEY_4 },		/* 4 */
+	{ 0x807f0d, KEY_5 },		/* 5 */
+	{ 0x807f0e, KEY_6 },		/* 6 */
+	{ 0x807f00, KEY_7 },		/* 7 */
+	{ 0x807f0f, KEY_8 },		/* 8 */
+	{ 0x807f19, KEY_9 },		/* 9 */
+
+	/* Type 2 */
+	/* keys stereo, snapshot unassigned */
+	{ 0x866b00, KEY_0 },
+	{ 0x866b1b, KEY_1 },
+	{ 0x866b02, KEY_2 },
+	{ 0x866b03, KEY_3 },
+	{ 0x866b04, KEY_4 },
+	{ 0x866b05, KEY_5 },
+	{ 0x866b06, KEY_6 },
+	{ 0x866b07, KEY_7 },
+	{ 0x866b08, KEY_8 },
+	{ 0x866b09, KEY_9 },
+	{ 0x866b12, KEY_POWER },
+	{ 0x866b13, KEY_MUTE },
+	{ 0x866b0a, KEY_PREVIOUS }, /* Recall */
+	{ 0x866b1e, KEY_PAUSE },
+	{ 0x866b0c, KEY_VOLUMEUP },
+	{ 0x866b18, KEY_VOLUMEDOWN },
+	{ 0x866b0b, KEY_CHANNELUP },
+	{ 0x866b18, KEY_CHANNELDOWN },
+	{ 0x866b10, KEY_ZOOM },
+	{ 0x866b1d, KEY_RECORD },
+	{ 0x866b0e, KEY_STOP },
+	{ 0x866b11, KEY_EPG},
+	{ 0x866b1a, KEY_FASTFORWARD },
+	{ 0x866b0f, KEY_REWIND },
+	{ 0x866b1c, KEY_TV },
+	{ 0x866b1b, KEY_TEXT },
+
+};
+
+static struct rc_map_list it913x_v2_map = {
+	.map = {
+		.scan    = it913x_v2_rc,
+		.size    = ARRAY_SIZE(it913x_v2_rc),
+		.rc_type = RC_TYPE_NEC,
+		.name    = RC_MAP_IT913X_V2,
+	}
+};
+
+static int __init init_rc_it913x_v2_map(void)
+{
+	return rc_map_register(&it913x_v2_map);
+}
+
+static void __exit exit_rc_it913x_v2_map(void)
+{
+	rc_map_unregister(&it913x_v2_map);
+}
+
+module_init(init_rc_it913x_v2_map)
+module_exit(exit_rc_it913x_v2_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
diff --git a/drivers/media/rc/keymaps/rc-kworld-pc150u.c b/drivers/media/rc/keymaps/rc-kworld-pc150u.c
new file mode 100644
index 0000000..233bb5e
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-kworld-pc150u.c
@@ -0,0 +1,102 @@
+/* kworld-pc150u.c - Keytable for kworld_pc150u Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Kyle Strickland
+ *   (based on kworld-plus-tv-analog.c by
+ *    Mauro Carvalho Chehab <mchehab@redhat.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 <media/rc-map.h>
+#include <linux/module.h>
+
+/* Kworld PC150-U
+   Kyle Strickland <kyle@kyle.strickland.name>
+ */
+
+static struct rc_map_table kworld_pc150u[] = {
+	{ 0x0c, KEY_MEDIA },		/* Kworld key */
+	{ 0x16, KEY_EJECTCLOSECD },	/* -> ) */
+	{ 0x1d, KEY_POWER2 },
+
+	{ 0x00, KEY_1 },
+	{ 0x01, KEY_2 },
+	{ 0x02, KEY_3 },
+	{ 0x03, KEY_4 },
+	{ 0x04, KEY_5 },
+	{ 0x05, KEY_6 },
+	{ 0x06, KEY_7 },
+	{ 0x07, KEY_8 },
+	{ 0x08, KEY_9 },
+	{ 0x0a, KEY_0 },
+
+	{ 0x09, KEY_AGAIN },
+	{ 0x14, KEY_MUTE },
+
+	{ 0x1e, KEY_LAST },
+	{ 0x17, KEY_ZOOM },
+	{ 0x1f, KEY_HOMEPAGE },
+	{ 0x0e, KEY_ESC },
+
+	{ 0x20, KEY_UP },
+	{ 0x21, KEY_DOWN },
+	{ 0x42, KEY_LEFT },
+	{ 0x43, KEY_RIGHT },
+	{ 0x0b, KEY_ENTER },
+
+	{ 0x10, KEY_CHANNELUP },
+	{ 0x11, KEY_CHANNELDOWN },
+
+	{ 0x13, KEY_VOLUMEUP },
+	{ 0x12, KEY_VOLUMEDOWN },
+
+	{ 0x19, KEY_TIME},		/* Timeshift */
+	{ 0x1a, KEY_STOP},
+	{ 0x1b, KEY_RECORD},
+	{ 0x4b, KEY_EMAIL},
+
+	{ 0x40, KEY_REWIND},
+	{ 0x44, KEY_PLAYPAUSE},
+	{ 0x41, KEY_FORWARD},
+	{ 0x22, KEY_TEXT},
+
+	{ 0x15, KEY_AUDIO},		/* ((*)) */
+	{ 0x0f, KEY_MODE},		/* display ratio */
+	{ 0x1c, KEY_SYSRQ},		/* snapshot */
+	{ 0x4a, KEY_SLEEP},		/* sleep timer */
+
+	{ 0x48, KEY_SOUND},		/* switch theater mode */
+	{ 0x49, KEY_BLUE},		/* A */
+	{ 0x18, KEY_RED},		/* B */
+	{ 0x23, KEY_GREEN},		/* C */
+};
+
+static struct rc_map_list kworld_pc150u_map = {
+	.map = {
+		.scan    = kworld_pc150u,
+		.size    = ARRAY_SIZE(kworld_pc150u),
+		.rc_type = RC_TYPE_UNKNOWN,	/* Legacy IR type */
+		.name    = RC_MAP_KWORLD_PC150U,
+	}
+};
+
+static int __init init_rc_map_kworld_pc150u(void)
+{
+	return rc_map_register(&kworld_pc150u_map);
+}
+
+static void __exit exit_rc_map_kworld_pc150u(void)
+{
+	rc_map_unregister(&kworld_pc150u_map);
+}
+
+module_init(init_rc_map_kworld_pc150u)
+module_exit(exit_rc_map_kworld_pc150u)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kyle Strickland <kyle@kyle.strickland.name>");
diff --git a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
index f3b86c8..8d4dae2 100644
--- a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
+++ b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
@@ -18,6 +18,8 @@
  */
 
 static struct rc_map_table nec_terratec_cinergy_xs[] = {
+
+	/* Terratec Grey IR, with most keys in orange */
 	{ 0x1441, KEY_HOME},
 	{ 0x1401, KEY_POWER2},
 
@@ -78,6 +80,56 @@
 	{ 0x144e, KEY_REWIND},
 	{ 0x144f, KEY_FASTFORWARD},
 	{ 0x145c, KEY_NEXT},
+
+	/* Terratec Black IR, with most keys in black */
+	{ 0x04eb01, KEY_POWER2},
+
+	{ 0x04eb02, KEY_1},
+	{ 0x04eb03, KEY_2},
+	{ 0x04eb04, KEY_3},
+	{ 0x04eb05, KEY_4},
+	{ 0x04eb06, KEY_5},
+	{ 0x04eb07, KEY_6},
+	{ 0x04eb08, KEY_7},
+	{ 0x04eb09, KEY_8},
+	{ 0x04eb0a, KEY_9},
+	{ 0x04eb0c, KEY_0},
+
+	{ 0x04eb0b, KEY_TEXT},		/* TXT */
+	{ 0x04eb0d, KEY_REFRESH},	/* Refresh */
+
+	{ 0x04eb0e, KEY_HOME},
+	{ 0x04eb0f, KEY_EPG},
+
+	{ 0x04eb10, KEY_UP},
+	{ 0x04eb11, KEY_LEFT},
+	{ 0x04eb12, KEY_OK},
+	{ 0x04eb13, KEY_RIGHT},
+	{ 0x04eb14, KEY_DOWN},
+
+	{ 0x04eb15, KEY_BACKSPACE},
+	{ 0x04eb16, KEY_INFO},
+
+	{ 0x04eb17, KEY_RED},
+	{ 0x04eb18, KEY_GREEN},
+	{ 0x04eb19, KEY_YELLOW},
+	{ 0x04eb1a, KEY_BLUE},
+
+	{ 0x04eb1c, KEY_VOLUMEUP},
+	{ 0x04eb1e, KEY_VOLUMEDOWN},
+
+	{ 0x04eb1d, KEY_MUTE},
+
+	{ 0x04eb1b, KEY_CHANNELUP},
+	{ 0x04eb1f, KEY_CHANNELDOWN},
+
+	{ 0x04eb40, KEY_RECORD},
+	{ 0x04eb4c, KEY_PLAY},
+	{ 0x04eb58, KEY_PAUSE},
+
+	{ 0x04eb54, KEY_REWIND},
+	{ 0x04eb48, KEY_STOP},
+	{ 0x04eb5c, KEY_NEXT},
 };
 
 static struct rc_map_list nec_terratec_cinergy_xs_map = {
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 21105bf..e150a2e 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -361,6 +361,8 @@
 	{ USB_DEVICE(VENDOR_FORMOSA, 0xe03c) },
 	/* Formosa Industrial Computing */
 	{ USB_DEVICE(VENDOR_FORMOSA, 0xe03e) },
+	/* Formosa Industrial Computing */
+	{ USB_DEVICE(VENDOR_FORMOSA, 0xe042) },
 	/* Fintek eHome Infrared Transceiver (HP branded) */
 	{ USB_DEVICE(VENDOR_FINTEK, 0x5168) },
 	/* Fintek eHome Infrared Transceiver */
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index b72f858..96f0a8b 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -35,7 +35,7 @@
 	struct list_head		list;		/* to keep track of raw clients */
 	struct task_struct		*thread;
 	spinlock_t			lock;
-	struct kfifo			kfifo;		/* fifo for the pulse/space durations */
+	struct kfifo_rec_ptr_1		kfifo;		/* fifo for the pulse/space durations */
 	ktime_t				last_event;	/* when last event occurred */
 	enum raw_event_type		last_type;	/* last event type */
 	struct rc_dev			*dev;		/* pointer to the parent rc_dev */
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index f6a930b..6e16b09 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1029,6 +1029,7 @@
 
 int rc_register_device(struct rc_dev *dev)
 {
+	static bool raw_init = false; /* raw decoders loaded? */
 	static atomic_t devno = ATOMIC_INIT(0);
 	struct rc_map *rc_map;
 	const char *path;
@@ -1103,6 +1104,12 @@
 	kfree(path);
 
 	if (dev->driver_type == RC_DRIVER_IR_RAW) {
+		/* Load raw decoders, if they aren't already */
+		if (!raw_init) {
+			IR_dprintk(1, "Loading raw decoders\n");
+			ir_raw_init();
+			raw_init = true;
+		}
 		rc = ir_raw_event_register(dev);
 		if (rc < 0)
 			goto out_input;
@@ -1176,8 +1183,6 @@
 		return rc;
 	}
 
-	/* Initialize/load the decoders/keymap code that will be used */
-	ir_raw_init();
 	rc_map_register(&empty_map);
 
 	return 0;
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 9adada0..f2479c5 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -273,6 +273,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called adv7180.
 
+config VIDEO_ADV7183
+	tristate "Analog Devices ADV7183 decoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  V4l2 subdevice driver for the Analog Devices
+	  ADV7183 video decoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adv7183.
+
 config VIDEO_BT819
 	tristate "BT819A VideoStream decoder"
 	depends on VIDEO_V4L2 && I2C
@@ -459,6 +469,9 @@
 
 comment "Camera sensor devices"
 
+config VIDEO_APTINA_PLL
+	tristate
+
 config VIDEO_OV7670
 	tristate "OmniVision OV7670 sensor support"
 	depends on I2C && VIDEO_V4L2
@@ -467,9 +480,28 @@
 	  OV7670 VGA camera.  It currently only works with the M88ALP01
 	  controller.
 
+config VIDEO_VS6624
+	tristate "ST VS6624 sensor support"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  This is a Video4Linux2 sensor-level driver for the ST VS6624
+	  camera.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vs6624.
+
+config VIDEO_MT9M032
+	tristate "MT9M032 camera sensor support"
+	depends on I2C && VIDEO_V4L2
+	select VIDEO_APTINA_PLL
+	---help---
+	  This driver supports MT9M032 camera sensors from Aptina, monochrome
+	  models only.
+
 config VIDEO_MT9P031
 	tristate "Aptina MT9P031 support"
 	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+	select VIDEO_APTINA_PLL
 	---help---
 	  This is a Video4Linux2 sensor-level driver for the Aptina
 	  (Micron) mt9p031 5 Mpixel camera.
@@ -851,6 +883,8 @@
 
 source "drivers/media/video/omap/Kconfig"
 
+source "drivers/media/video/blackfin/Kconfig"
+
 config VIDEO_SH_VOU
 	tristate "SuperH VOU video output driver"
 	depends on VIDEO_DEV && ARCH_SHMOBILE
@@ -1087,7 +1121,7 @@
 config VIDEO_MX2
 	tristate "i.MX27/i.MX25 Camera Sensor Interface driver"
 	depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || ARCH_MX25)
-	select VIDEOBUF_DMA_CONTIG
+	select VIDEOBUF2_DMA_CONTIG
 	select VIDEO_MX2_HOSTSUPPORT
 	---help---
 	  This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor
@@ -1116,7 +1150,8 @@
 
 config VIDEO_S5P_MIPI_CSIS
 	tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver"
-	depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P && VIDEO_V4L2_SUBDEV_API
+	depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P
+	depends on VIDEO_V4L2_SUBDEV_API && REGULATOR
 	---help---
 	  This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver.
 
@@ -1176,4 +1211,14 @@
 	help
 	    MFC 5.1 driver for V4L2.
 
+config VIDEO_MX2_EMMAPRP
+	tristate "MX2 eMMa-PrP support"
+	depends on VIDEO_DEV && VIDEO_V4L2 && SOC_IMX27
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_MEM2MEM_DEV
+	help
+	    MX2X chips have a PrP that can be used to process buffers from
+	    memory to memory. Operations include resizing and format
+	    conversion.
+
 endif # V4L_MEM2MEM_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 3541388..a6282a3 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -12,16 +12,19 @@
 
 videodev-objs	:=	v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
 			v4l2-event.o v4l2-ctrls.o v4l2-subdev.o
+ifeq ($(CONFIG_COMPAT),y)
+  videodev-objs += v4l2-compat-ioctl32.o
+endif
 
 # V4L2 core modules
 
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
-ifeq ($(CONFIG_COMPAT),y)
-  obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o
-endif
-
 obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o
 
+# Helper modules
+
+obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o
+
 # All i2c modules must come first:
 
 obj-$(CONFIG_VIDEO_TUNER) += tuner.o
@@ -40,8 +43,10 @@
 obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
 obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
 obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o
+obj-$(CONFIG_VIDEO_ADV7183) += adv7183.o
 obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o
 obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
+obj-$(CONFIG_VIDEO_VS6624)  += vs6624.o
 obj-$(CONFIG_VIDEO_BT819) += bt819.o
 obj-$(CONFIG_VIDEO_BT856) += bt856.o
 obj-$(CONFIG_VIDEO_BT866) += bt866.o
@@ -65,6 +70,7 @@
 obj-$(CONFIG_VIDEO_OV7670) 	+= ov7670.o
 obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
+obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
 obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
 obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o
 obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
@@ -177,6 +183,8 @@
 obj-$(CONFIG_VIDEO_OMAP1)		+= omap1_camera.o
 obj-$(CONFIG_VIDEO_ATMEL_ISI)		+= atmel-isi.o
 
+obj-$(CONFIG_VIDEO_MX2_EMMAPRP)		+= mx2_emmaprp.o
+
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) 	+= s5p-fimc/
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG)	+= s5p-jpeg/
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC)	+= s5p-mfc/
@@ -184,6 +192,8 @@
 
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D)	+= s5p-g2d/
 
+obj-$(CONFIG_BLACKFIN)                  += blackfin/
+
 obj-$(CONFIG_ARCH_DAVINCI)		+= davinci/
 
 obj-$(CONFIG_VIDEO_SH_VOU)		+= sh_vou.o
@@ -199,6 +209,6 @@
 
 obj-$(CONFIG_ARCH_OMAP)	+= omap/
 
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
-ccflags-y += -Idrivers/media/common/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c
index 12eedf4..5b045b4 100644
--- a/drivers/media/video/adp1653.c
+++ b/drivers/media/video/adp1653.c
@@ -33,7 +33,6 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/version.h>
 #include <media/adp1653.h>
@@ -482,24 +481,7 @@
 	.id_table	= adp1653_id_table,
 };
 
-static int __init adp1653_init(void)
-{
-	int rval;
-
-	rval = i2c_add_driver(&adp1653_i2c_driver);
-	if (rval)
-		printk(KERN_ALERT "%s: failed at i2c_add_driver\n", __func__);
-
-	return rval;
-}
-
-static void __exit adp1653_exit(void)
-{
-	i2c_del_driver(&adp1653_i2c_driver);
-}
-
-module_init(adp1653_init);
-module_exit(adp1653_exit);
+module_i2c_driver(adp1653_i2c_driver);
 
 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
 MODULE_DESCRIPTION("Analog Devices ADP1653 LED flash driver");
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index 879f1d8..6bc01fb 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -407,15 +407,4 @@
 	.id_table	= adv7170_id,
 };
 
-static __init int init_adv7170(void)
-{
-	return i2c_add_driver(&adv7170_driver);
-}
-
-static __exit void exit_adv7170(void)
-{
-	i2c_del_driver(&adv7170_driver);
-}
-
-module_init(init_adv7170);
-module_exit(exit_adv7170);
+module_i2c_driver(adv7170_driver);
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index 206078e..c7640fa 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -457,15 +457,4 @@
 	.id_table	= adv7175_id,
 };
 
-static __init int init_adv7175(void)
-{
-	return i2c_add_driver(&adv7175_driver);
-}
-
-static __exit void exit_adv7175(void)
-{
-	i2c_del_driver(&adv7175_driver);
-}
-
-module_init(init_adv7175);
-module_exit(exit_adv7175);
+module_i2c_driver(adv7175_driver);
diff --git a/drivers/media/video/adv7180.c b/drivers/media/video/adv7180.c
index d2138d0..b8b6c4b 100644
--- a/drivers/media/video/adv7180.c
+++ b/drivers/media/video/adv7180.c
@@ -444,20 +444,8 @@
 	.id_table	= adv7180_id,
 };
 
-static __init int adv7180_init(void)
-{
-	return i2c_add_driver(&adv7180_driver);
-}
-
-static __exit void adv7180_exit(void)
-{
-	i2c_del_driver(&adv7180_driver);
-}
-
-module_init(adv7180_init);
-module_exit(adv7180_exit);
+module_i2c_driver(adv7180_driver);
 
 MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver");
 MODULE_AUTHOR("Mocean Laboratories");
 MODULE_LICENSE("GPL v2");
-
diff --git a/drivers/media/video/adv7183.c b/drivers/media/video/adv7183.c
new file mode 100644
index 0000000..e1d4c89
--- /dev/null
+++ b/drivers/media/video/adv7183.c
@@ -0,0 +1,699 @@
+/*
+ * adv7183.c Analog Devices ADV7183 video decoder driver
+ *
+ * Copyright (c) 2011 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.
+ *
+ * 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/delay.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/adv7183.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+#include "adv7183_regs.h"
+
+struct adv7183 {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+
+	v4l2_std_id std; /* Current set standard */
+	u32 input;
+	u32 output;
+	unsigned reset_pin;
+	unsigned oe_pin;
+	struct v4l2_mbus_framefmt fmt;
+};
+
+/* EXAMPLES USING 27 MHz CLOCK
+ * Mode 1 CVBS Input (Composite Video on AIN5)
+ * All standards are supported through autodetect, 8-bit, 4:2:2, ITU-R BT.656 output on P15 to P8.
+ */
+static const unsigned char adv7183_init_regs[] = {
+	ADV7183_IN_CTRL, 0x04,           /* CVBS input on AIN5 */
+	ADV7183_DIGI_CLAMP_CTRL_1, 0x00, /* Slow down digital clamps */
+	ADV7183_SHAP_FILT_CTRL, 0x41,    /* Set CSFM to SH1 */
+	ADV7183_ADC_CTRL, 0x16,          /* Power down ADC 1 and ADC 2 */
+	ADV7183_CTI_DNR_CTRL_4, 0x04,    /* Set DNR threshold to 4 for flat response */
+	/* ADI recommended programming sequence */
+	ADV7183_ADI_CTRL, 0x80,
+	ADV7183_CTI_DNR_CTRL_4, 0x20,
+	0x52, 0x18,
+	0x58, 0xED,
+	0x77, 0xC5,
+	0x7C, 0x93,
+	0x7D, 0x00,
+	0xD0, 0x48,
+	0xD5, 0xA0,
+	0xD7, 0xEA,
+	ADV7183_SD_SATURATION_CR, 0x3E,
+	ADV7183_PAL_V_END, 0x3E,
+	ADV7183_PAL_F_TOGGLE, 0x0F,
+	ADV7183_ADI_CTRL, 0x00,
+};
+
+static inline struct adv7183 *to_adv7183(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct adv7183, sd);
+}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct adv7183, hdl)->sd;
+}
+
+static inline int adv7183_read(struct v4l2_subdev *sd, unsigned char reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static inline int adv7183_write(struct v4l2_subdev *sd, unsigned char reg,
+				unsigned char value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int adv7183_writeregs(struct v4l2_subdev *sd,
+		const unsigned char *regs, unsigned int num)
+{
+	unsigned char reg, data;
+	unsigned int cnt = 0;
+
+	if (num & 0x1) {
+		v4l2_err(sd, "invalid regs array\n");
+		return -1;
+	}
+
+	while (cnt < num) {
+		reg = *regs++;
+		data = *regs++;
+		cnt += 2;
+
+		adv7183_write(sd, reg, data);
+	}
+	return 0;
+}
+
+static int adv7183_log_status(struct v4l2_subdev *sd)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+
+	v4l2_info(sd, "adv7183: Input control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_IN_CTRL));
+	v4l2_info(sd, "adv7183: Video selection = 0x%02x\n",
+			adv7183_read(sd, ADV7183_VD_SEL));
+	v4l2_info(sd, "adv7183: Output control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_OUT_CTRL));
+	v4l2_info(sd, "adv7183: Extended output control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_EXT_OUT_CTRL));
+	v4l2_info(sd, "adv7183: Autodetect enable = 0x%02x\n",
+			adv7183_read(sd, ADV7183_AUTO_DET_EN));
+	v4l2_info(sd, "adv7183: Contrast = 0x%02x\n",
+			adv7183_read(sd, ADV7183_CONTRAST));
+	v4l2_info(sd, "adv7183: Brightness = 0x%02x\n",
+			adv7183_read(sd, ADV7183_BRIGHTNESS));
+	v4l2_info(sd, "adv7183: Hue = 0x%02x\n",
+			adv7183_read(sd, ADV7183_HUE));
+	v4l2_info(sd, "adv7183: Default value Y = 0x%02x\n",
+			adv7183_read(sd, ADV7183_DEF_Y));
+	v4l2_info(sd, "adv7183: Default value C = 0x%02x\n",
+			adv7183_read(sd, ADV7183_DEF_C));
+	v4l2_info(sd, "adv7183: ADI control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_ADI_CTRL));
+	v4l2_info(sd, "adv7183: Power Management = 0x%02x\n",
+			adv7183_read(sd, ADV7183_POW_MANAGE));
+	v4l2_info(sd, "adv7183: Status 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_STATUS_1),
+			adv7183_read(sd, ADV7183_STATUS_2),
+			adv7183_read(sd, ADV7183_STATUS_3));
+	v4l2_info(sd, "adv7183: Ident = 0x%02x\n",
+			adv7183_read(sd, ADV7183_IDENT));
+	v4l2_info(sd, "adv7183: Analog clamp control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_ANAL_CLAMP_CTRL));
+	v4l2_info(sd, "adv7183: Digital clamp control 1 = 0x%02x\n",
+			adv7183_read(sd, ADV7183_DIGI_CLAMP_CTRL_1));
+	v4l2_info(sd, "adv7183: Shaping filter control 1 and 2 = 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_SHAP_FILT_CTRL),
+			adv7183_read(sd, ADV7183_SHAP_FILT_CTRL_2));
+	v4l2_info(sd, "adv7183: Comb filter control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_COMB_FILT_CTRL));
+	v4l2_info(sd, "adv7183: ADI control 2 = 0x%02x\n",
+			adv7183_read(sd, ADV7183_ADI_CTRL_2));
+	v4l2_info(sd, "adv7183: Pixel delay control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_PIX_DELAY_CTRL));
+	v4l2_info(sd, "adv7183: Misc gain control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_MISC_GAIN_CTRL));
+	v4l2_info(sd, "adv7183: AGC mode control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_AGC_MODE_CTRL));
+	v4l2_info(sd, "adv7183: Chroma gain control 1 and 2 = 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_1),
+			adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_2));
+	v4l2_info(sd, "adv7183: Luma gain control 1 and 2 = 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_1),
+			adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_2));
+	v4l2_info(sd, "adv7183: Vsync field control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_VS_FIELD_CTRL_1),
+			adv7183_read(sd, ADV7183_VS_FIELD_CTRL_2),
+			adv7183_read(sd, ADV7183_VS_FIELD_CTRL_3));
+	v4l2_info(sd, "adv7183: Hsync positon control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_HS_POS_CTRL_1),
+			adv7183_read(sd, ADV7183_HS_POS_CTRL_2),
+			adv7183_read(sd, ADV7183_HS_POS_CTRL_3));
+	v4l2_info(sd, "adv7183: Polarity = 0x%02x\n",
+			adv7183_read(sd, ADV7183_POLARITY));
+	v4l2_info(sd, "adv7183: ADC control = 0x%02x\n",
+			adv7183_read(sd, ADV7183_ADC_CTRL));
+	v4l2_info(sd, "adv7183: SD offset Cb and Cr = 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_SD_OFFSET_CB),
+			adv7183_read(sd, ADV7183_SD_OFFSET_CR));
+	v4l2_info(sd, "adv7183: SD saturation Cb and Cr = 0x%02x 0x%02x\n",
+			adv7183_read(sd, ADV7183_SD_SATURATION_CB),
+			adv7183_read(sd, ADV7183_SD_SATURATION_CR));
+	v4l2_info(sd, "adv7183: Drive strength = 0x%02x\n",
+			adv7183_read(sd, ADV7183_DRIVE_STR));
+	v4l2_ctrl_handler_log_status(&decoder->hdl, sd->name);
+	return 0;
+}
+
+static int adv7183_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+
+	*std = decoder->std;
+	return 0;
+}
+
+static int adv7183_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+	int reg;
+
+	reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
+	if (std == V4L2_STD_PAL_60)
+		reg |= 0x60;
+	else if (std == V4L2_STD_NTSC_443)
+		reg |= 0x70;
+	else if (std == V4L2_STD_PAL_N)
+		reg |= 0x90;
+	else if (std == V4L2_STD_PAL_M)
+		reg |= 0xA0;
+	else if (std == V4L2_STD_PAL_Nc)
+		reg |= 0xC0;
+	else if (std & V4L2_STD_PAL)
+		reg |= 0x80;
+	else if (std & V4L2_STD_NTSC)
+		reg |= 0x50;
+	else if (std & V4L2_STD_SECAM)
+		reg |= 0xE0;
+	else
+		return -EINVAL;
+	adv7183_write(sd, ADV7183_IN_CTRL, reg);
+
+	decoder->std = std;
+
+	return 0;
+}
+
+static int adv7183_reset(struct v4l2_subdev *sd, u32 val)
+{
+	int reg;
+
+	reg = adv7183_read(sd, ADV7183_POW_MANAGE) | 0x80;
+	adv7183_write(sd, ADV7183_POW_MANAGE, reg);
+	/* wait 5ms before any further i2c writes are performed */
+	usleep_range(5000, 10000);
+	return 0;
+}
+
+static int adv7183_s_routing(struct v4l2_subdev *sd,
+				u32 input, u32 output, u32 config)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+	int reg;
+
+	if ((input > ADV7183_COMPONENT1) || (output > ADV7183_16BIT_OUT))
+		return -EINVAL;
+
+	if (input != decoder->input) {
+		decoder->input = input;
+		reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF0;
+		switch (input) {
+		case ADV7183_COMPOSITE1:
+			reg |= 0x1;
+			break;
+		case ADV7183_COMPOSITE2:
+			reg |= 0x2;
+			break;
+		case ADV7183_COMPOSITE3:
+			reg |= 0x3;
+			break;
+		case ADV7183_COMPOSITE4:
+			reg |= 0x4;
+			break;
+		case ADV7183_COMPOSITE5:
+			reg |= 0x5;
+			break;
+		case ADV7183_COMPOSITE6:
+			reg |= 0xB;
+			break;
+		case ADV7183_COMPOSITE7:
+			reg |= 0xC;
+			break;
+		case ADV7183_COMPOSITE8:
+			reg |= 0xD;
+			break;
+		case ADV7183_COMPOSITE9:
+			reg |= 0xE;
+			break;
+		case ADV7183_COMPOSITE10:
+			reg |= 0xF;
+			break;
+		case ADV7183_SVIDEO0:
+			reg |= 0x6;
+			break;
+		case ADV7183_SVIDEO1:
+			reg |= 0x7;
+			break;
+		case ADV7183_SVIDEO2:
+			reg |= 0x8;
+			break;
+		case ADV7183_COMPONENT0:
+			reg |= 0x9;
+			break;
+		case ADV7183_COMPONENT1:
+			reg |= 0xA;
+			break;
+		default:
+			break;
+		}
+		adv7183_write(sd, ADV7183_IN_CTRL, reg);
+	}
+
+	if (output != decoder->output) {
+		decoder->output = output;
+		reg = adv7183_read(sd, ADV7183_OUT_CTRL) & 0xC0;
+		switch (output) {
+		case ADV7183_16BIT_OUT:
+			reg |= 0x9;
+			break;
+		default:
+			reg |= 0xC;
+			break;
+		}
+		adv7183_write(sd, ADV7183_OUT_CTRL, reg);
+	}
+
+	return 0;
+}
+
+static int adv7183_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	int val = ctrl->val;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		if (val < 0)
+			val = 127 - val;
+		adv7183_write(sd, ADV7183_BRIGHTNESS, val);
+		break;
+	case V4L2_CID_CONTRAST:
+		adv7183_write(sd, ADV7183_CONTRAST, val);
+		break;
+	case V4L2_CID_SATURATION:
+		adv7183_write(sd, ADV7183_SD_SATURATION_CB, val >> 8);
+		adv7183_write(sd, ADV7183_SD_SATURATION_CR, (val & 0xFF));
+		break;
+	case V4L2_CID_HUE:
+		adv7183_write(sd, ADV7183_SD_OFFSET_CB, val >> 8);
+		adv7183_write(sd, ADV7183_SD_OFFSET_CR, (val & 0xFF));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int adv7183_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+	int reg;
+
+	/* enable autodetection block */
+	reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
+	adv7183_write(sd, ADV7183_IN_CTRL, reg);
+
+	/* wait autodetection switch */
+	mdelay(10);
+
+	/* get autodetection result */
+	reg = adv7183_read(sd, ADV7183_STATUS_1);
+	switch ((reg >> 0x4) & 0x7) {
+	case 0:
+		*std = V4L2_STD_NTSC;
+		break;
+	case 1:
+		*std = V4L2_STD_NTSC_443;
+		break;
+	case 2:
+		*std = V4L2_STD_PAL_M;
+		break;
+	case 3:
+		*std = V4L2_STD_PAL_60;
+		break;
+	case 4:
+		*std = V4L2_STD_PAL;
+		break;
+	case 5:
+		*std = V4L2_STD_SECAM;
+		break;
+	case 6:
+		*std = V4L2_STD_PAL_Nc;
+		break;
+	case 7:
+		*std = V4L2_STD_SECAM;
+		break;
+	default:
+		*std = V4L2_STD_UNKNOWN;
+		break;
+	}
+
+	/* after std detection, write back user set std */
+	adv7183_s_std(sd, decoder->std);
+	return 0;
+}
+
+static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	int reg;
+
+	*status = V4L2_IN_ST_NO_SIGNAL;
+	reg = adv7183_read(sd, ADV7183_STATUS_1);
+	if (reg < 0)
+		return reg;
+	if (reg & 0x1)
+		*status = 0;
+	return 0;
+}
+
+static int adv7183_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+				enum v4l2_mbus_pixelcode *code)
+{
+	if (index > 0)
+		return -EINVAL;
+
+	*code = V4L2_MBUS_FMT_UYVY8_2X8;
+	return 0;
+}
+
+static int adv7183_try_mbus_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *fmt)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+
+	fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	if (decoder->std & V4L2_STD_525_60) {
+		fmt->field = V4L2_FIELD_SEQ_TB;
+		fmt->width = 720;
+		fmt->height = 480;
+	} else {
+		fmt->field = V4L2_FIELD_SEQ_BT;
+		fmt->width = 720;
+		fmt->height = 576;
+	}
+	return 0;
+}
+
+static int adv7183_s_mbus_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *fmt)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+
+	adv7183_try_mbus_fmt(sd, fmt);
+	decoder->fmt = *fmt;
+	return 0;
+}
+
+static int adv7183_g_mbus_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *fmt)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+
+	*fmt = decoder->fmt;
+	return 0;
+}
+
+static int adv7183_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct adv7183 *decoder = to_adv7183(sd);
+
+	if (enable)
+		gpio_direction_output(decoder->oe_pin, 0);
+	else
+		gpio_direction_output(decoder->oe_pin, 1);
+	udelay(1);
+	return 0;
+}
+
+static int adv7183_g_chip_ident(struct v4l2_subdev *sd,
+		struct v4l2_dbg_chip_ident *chip)
+{
+	int rev;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	/* 0x11 for adv7183, 0x13 for adv7183b */
+	rev = adv7183_read(sd, ADV7183_IDENT);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7183, rev);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	reg->val = adv7183_read(sd, reg->reg & 0xff);
+	reg->size = 1;
+	return 0;
+}
+
+static int adv7183_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	adv7183_write(sd, reg->reg & 0xff, reg->val & 0xff);
+	return 0;
+}
+#endif
+
+static const struct v4l2_ctrl_ops adv7183_ctrl_ops = {
+	.s_ctrl = adv7183_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops adv7183_core_ops = {
+	.log_status = adv7183_log_status,
+	.g_std = adv7183_g_std,
+	.s_std = adv7183_s_std,
+	.reset = adv7183_reset,
+	.g_chip_ident = adv7183_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = adv7183_g_register,
+	.s_register = adv7183_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops adv7183_video_ops = {
+	.s_routing = adv7183_s_routing,
+	.querystd = adv7183_querystd,
+	.g_input_status = adv7183_g_input_status,
+	.enum_mbus_fmt = adv7183_enum_mbus_fmt,
+	.try_mbus_fmt = adv7183_try_mbus_fmt,
+	.s_mbus_fmt = adv7183_s_mbus_fmt,
+	.g_mbus_fmt = adv7183_g_mbus_fmt,
+	.s_stream = adv7183_s_stream,
+};
+
+static const struct v4l2_subdev_ops adv7183_ops = {
+	.core = &adv7183_core_ops,
+	.video = &adv7183_video_ops,
+};
+
+static int adv7183_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct adv7183 *decoder;
+	struct v4l2_subdev *sd;
+	struct v4l2_ctrl_handler *hdl;
+	int ret;
+	struct v4l2_mbus_framefmt fmt;
+	const unsigned *pin_array;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%02x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	pin_array = client->dev.platform_data;
+	if (pin_array == NULL)
+		return -EINVAL;
+
+	decoder = kzalloc(sizeof(struct adv7183), GFP_KERNEL);
+	if (decoder == NULL)
+		return -ENOMEM;
+
+	decoder->reset_pin = pin_array[0];
+	decoder->oe_pin = pin_array[1];
+
+	if (gpio_request(decoder->reset_pin, "ADV7183 Reset")) {
+		v4l_err(client, "failed to request GPIO %d\n", decoder->reset_pin);
+		ret = -EBUSY;
+		goto err_free_decoder;
+	}
+
+	if (gpio_request(decoder->oe_pin, "ADV7183 Output Enable")) {
+		v4l_err(client, "failed to request GPIO %d\n", decoder->oe_pin);
+		ret = -EBUSY;
+		goto err_free_reset;
+	}
+
+	sd = &decoder->sd;
+	v4l2_i2c_subdev_init(sd, client, &adv7183_ops);
+
+	hdl = &decoder->hdl;
+	v4l2_ctrl_handler_init(hdl, 4);
+	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
+	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x80);
+	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 0xFFFF, 1, 0x8080);
+	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+			V4L2_CID_HUE, 0, 0xFFFF, 1, 0x8080);
+	/* hook the control handler into the driver */
+	sd->ctrl_handler = hdl;
+	if (hdl->error) {
+		ret = hdl->error;
+
+		v4l2_ctrl_handler_free(hdl);
+		goto err_free_oe;
+	}
+
+	/* v4l2 doesn't support an autodetect standard, pick PAL as default */
+	decoder->std = V4L2_STD_PAL;
+	decoder->input = ADV7183_COMPOSITE4;
+	decoder->output = ADV7183_8BIT_OUT;
+
+	gpio_direction_output(decoder->oe_pin, 1);
+	/* reset chip */
+	gpio_direction_output(decoder->reset_pin, 0);
+	/* reset pulse width at least 5ms */
+	mdelay(10);
+	gpio_direction_output(decoder->reset_pin, 1);
+	/* wait 5ms before any further i2c writes are performed */
+	mdelay(5);
+
+	adv7183_writeregs(sd, adv7183_init_regs, ARRAY_SIZE(adv7183_init_regs));
+	adv7183_s_std(sd, decoder->std);
+	fmt.width = 720;
+	fmt.height = 576;
+	adv7183_s_mbus_fmt(sd, &fmt);
+
+	/* initialize the hardware to the default control values */
+	ret = v4l2_ctrl_handler_setup(hdl);
+	if (ret) {
+		v4l2_ctrl_handler_free(hdl);
+		goto err_free_oe;
+	}
+
+	return 0;
+err_free_oe:
+	gpio_free(decoder->oe_pin);
+err_free_reset:
+	gpio_free(decoder->reset_pin);
+err_free_decoder:
+	kfree(decoder);
+	return ret;
+}
+
+static int adv7183_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct adv7183 *decoder = to_adv7183(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(sd->ctrl_handler);
+	gpio_free(decoder->oe_pin);
+	gpio_free(decoder->reset_pin);
+	kfree(decoder);
+	return 0;
+}
+
+static const struct i2c_device_id adv7183_id[] = {
+	{"adv7183", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, adv7183_id);
+
+static struct i2c_driver adv7183_driver = {
+	.driver = {
+		.owner  = THIS_MODULE,
+		.name   = "adv7183",
+	},
+	.probe          = adv7183_probe,
+	.remove         = __devexit_p(adv7183_remove),
+	.id_table       = adv7183_id,
+};
+
+static __init int adv7183_init(void)
+{
+	return i2c_add_driver(&adv7183_driver);
+}
+
+static __exit void adv7183_exit(void)
+{
+	i2c_del_driver(&adv7183_driver);
+}
+
+module_init(adv7183_init);
+module_exit(adv7183_exit);
+
+MODULE_DESCRIPTION("Analog Devices ADV7183 video decoder driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/adv7183_regs.h b/drivers/media/video/adv7183_regs.h
new file mode 100644
index 0000000..4a5b7d2
--- /dev/null
+++ b/drivers/media/video/adv7183_regs.h
@@ -0,0 +1,107 @@
+/*
+ * adv7183 - Analog Devices ADV7183 video decoder registers
+ *
+ * Copyright (c) 2011 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _ADV7183_REGS_H_
+#define _ADV7183_REGS_H_
+
+#define ADV7183_IN_CTRL            0x00 /* Input control */
+#define ADV7183_VD_SEL             0x01 /* Video selection */
+#define ADV7183_OUT_CTRL           0x03 /* Output control */
+#define ADV7183_EXT_OUT_CTRL       0x04 /* Extended output control */
+#define ADV7183_AUTO_DET_EN        0x07 /* Autodetect enable */
+#define ADV7183_CONTRAST           0x08 /* Contrast */
+#define ADV7183_BRIGHTNESS         0x0A /* Brightness */
+#define ADV7183_HUE                0x0B /* Hue */
+#define ADV7183_DEF_Y              0x0C /* Default value Y */
+#define ADV7183_DEF_C              0x0D /* Default value C */
+#define ADV7183_ADI_CTRL           0x0E /* ADI control */
+#define ADV7183_POW_MANAGE         0x0F /* Power Management */
+#define ADV7183_STATUS_1           0x10 /* Status 1 */
+#define ADV7183_IDENT              0x11 /* Ident */
+#define ADV7183_STATUS_2           0x12 /* Status 2 */
+#define ADV7183_STATUS_3           0x13 /* Status 3 */
+#define ADV7183_ANAL_CLAMP_CTRL    0x14 /* Analog clamp control */
+#define ADV7183_DIGI_CLAMP_CTRL_1  0x15 /* Digital clamp control 1 */
+#define ADV7183_SHAP_FILT_CTRL     0x17 /* Shaping filter control */
+#define ADV7183_SHAP_FILT_CTRL_2   0x18 /* Shaping filter control 2 */
+#define ADV7183_COMB_FILT_CTRL     0x19 /* Comb filter control */
+#define ADV7183_ADI_CTRL_2         0x1D /* ADI control 2 */
+#define ADV7183_PIX_DELAY_CTRL     0x27 /* Pixel delay control */
+#define ADV7183_MISC_GAIN_CTRL     0x2B /* Misc gain control */
+#define ADV7183_AGC_MODE_CTRL      0x2C /* AGC mode control */
+#define ADV7183_CHRO_GAIN_CTRL_1   0x2D /* Chroma gain control 1 */
+#define ADV7183_CHRO_GAIN_CTRL_2   0x2E /* Chroma gain control 2 */
+#define ADV7183_LUMA_GAIN_CTRL_1   0x2F /* Luma gain control 1 */
+#define ADV7183_LUMA_GAIN_CTRL_2   0x30 /* Luma gain control 2 */
+#define ADV7183_VS_FIELD_CTRL_1    0x31 /* Vsync field control 1 */
+#define ADV7183_VS_FIELD_CTRL_2    0x32 /* Vsync field control 2 */
+#define ADV7183_VS_FIELD_CTRL_3    0x33 /* Vsync field control 3 */
+#define ADV7183_HS_POS_CTRL_1      0x34 /* Hsync positon control 1 */
+#define ADV7183_HS_POS_CTRL_2      0x35 /* Hsync positon control 2 */
+#define ADV7183_HS_POS_CTRL_3      0x36 /* Hsync positon control 3 */
+#define ADV7183_POLARITY           0x37 /* Polarity */
+#define ADV7183_NTSC_COMB_CTRL     0x38 /* NTSC comb control */
+#define ADV7183_PAL_COMB_CTRL      0x39 /* PAL comb control */
+#define ADV7183_ADC_CTRL           0x3A /* ADC control */
+#define ADV7183_MAN_WIN_CTRL       0x3D /* Manual window control */
+#define ADV7183_RESAMPLE_CTRL      0x41 /* Resample control */
+#define ADV7183_GEMSTAR_CTRL_1     0x48 /* Gemstar ctrl 1 */
+#define ADV7183_GEMSTAR_CTRL_2     0x49 /* Gemstar ctrl 2 */
+#define ADV7183_GEMSTAR_CTRL_3     0x4A /* Gemstar ctrl 3 */
+#define ADV7183_GEMSTAR_CTRL_4     0x4B /* Gemstar ctrl 4 */
+#define ADV7183_GEMSTAR_CTRL_5     0x4C /* Gemstar ctrl 5 */
+#define ADV7183_CTI_DNR_CTRL_1     0x4D /* CTI DNR ctrl 1 */
+#define ADV7183_CTI_DNR_CTRL_2     0x4E /* CTI DNR ctrl 2 */
+#define ADV7183_CTI_DNR_CTRL_4     0x50 /* CTI DNR ctrl 4 */
+#define ADV7183_LOCK_CNT           0x51 /* Lock count */
+#define ADV7183_FREE_LINE_LEN      0x8F /* Free-Run line length 1 */
+#define ADV7183_VBI_INFO           0x90 /* VBI info */
+#define ADV7183_WSS_1              0x91 /* WSS 1 */
+#define ADV7183_WSS_2              0x92 /* WSS 2 */
+#define ADV7183_EDTV_1             0x93 /* EDTV 1 */
+#define ADV7183_EDTV_2             0x94 /* EDTV 2 */
+#define ADV7183_EDTV_3             0x95 /* EDTV 3 */
+#define ADV7183_CGMS_1             0x96 /* CGMS 1 */
+#define ADV7183_CGMS_2             0x97 /* CGMS 2 */
+#define ADV7183_CGMS_3             0x98 /* CGMS 3 */
+#define ADV7183_CCAP_1             0x99 /* CCAP 1 */
+#define ADV7183_CCAP_2             0x9A /* CCAP 2 */
+#define ADV7183_LETTERBOX_1        0x9B /* Letterbox 1 */
+#define ADV7183_LETTERBOX_2        0x9C /* Letterbox 2 */
+#define ADV7183_LETTERBOX_3        0x9D /* Letterbox 3 */
+#define ADV7183_CRC_EN             0xB2 /* CRC enable */
+#define ADV7183_ADC_SWITCH_1       0xC3 /* ADC switch 1 */
+#define ADV7183_ADC_SWITCH_2       0xC4 /* ADC swithc 2 */
+#define ADV7183_LETTERBOX_CTRL_1   0xDC /* Letterbox control 1 */
+#define ADV7183_LETTERBOX_CTRL_2   0xDD /* Letterbox control 2 */
+#define ADV7183_SD_OFFSET_CB       0xE1 /* SD offset Cb */
+#define ADV7183_SD_OFFSET_CR       0xE2 /* SD offset Cr */
+#define ADV7183_SD_SATURATION_CB   0xE3 /* SD saturation Cb */
+#define ADV7183_SD_SATURATION_CR   0xE4 /* SD saturation Cr */
+#define ADV7183_NTSC_V_BEGIN       0xE5 /* NTSC V bit begin */
+#define ADV7183_NTSC_V_END         0xE6 /* NTSC V bit end */
+#define ADV7183_NTSC_F_TOGGLE      0xE7 /* NTSC F bit toggle */
+#define ADV7183_PAL_V_BEGIN        0xE8 /* PAL V bit begin */
+#define ADV7183_PAL_V_END          0xE9 /* PAL V bit end */
+#define ADV7183_PAL_F_TOGGLE       0xEA /* PAL F bit toggle */
+#define ADV7183_DRIVE_STR          0xF4 /* Drive strength */
+#define ADV7183_IF_COMP_CTRL       0xF8 /* IF comp control */
+#define ADV7183_VS_MODE_CTRL       0xF9 /* VS mode control */
+
+#endif
diff --git a/drivers/media/video/adv7343.c b/drivers/media/video/adv7343.c
index 021fab2..119b604 100644
--- a/drivers/media/video/adv7343.c
+++ b/drivers/media/video/adv7343.c
@@ -475,15 +475,4 @@
 	.id_table	= adv7343_id,
 };
 
-static __init int init_adv7343(void)
-{
-	return i2c_add_driver(&adv7343_driver);
-}
-
-static __exit void exit_adv7343(void)
-{
-	i2c_del_driver(&adv7343_driver);
-}
-
-module_init(init_adv7343);
-module_exit(exit_adv7343);
+module_i2c_driver(adv7343_driver);
diff --git a/drivers/media/video/ak881x.c b/drivers/media/video/ak881x.c
index 53c496c..ba67465 100644
--- a/drivers/media/video/ak881x.c
+++ b/drivers/media/video/ak881x.c
@@ -352,18 +352,7 @@
 	.id_table	= ak881x_id,
 };
 
-static int __init ak881x_module_init(void)
-{
-	return i2c_add_driver(&ak881x_i2c_driver);
-}
-
-static void __exit ak881x_module_exit(void)
-{
-	i2c_del_driver(&ak881x_i2c_driver);
-}
-
-module_init(ak881x_module_init);
-module_exit(ak881x_module_exit);
+module_i2c_driver(ak881x_i2c_driver);
 
 MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814");
 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
diff --git a/drivers/media/video/aptina-pll.c b/drivers/media/video/aptina-pll.c
new file mode 100644
index 0000000..0bd3813
--- /dev/null
+++ b/drivers/media/video/aptina-pll.c
@@ -0,0 +1,174 @@
+/*
+ * Aptina Sensor PLL Configuration
+ *
+ * Copyright (C) 2012 Laurent Pinchart <laurent.pinchart@ideasonboard.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/device.h>
+#include <linux/gcd.h>
+#include <linux/kernel.h>
+#include <linux/lcm.h>
+#include <linux/module.h>
+
+#include "aptina-pll.h"
+
+int aptina_pll_calculate(struct device *dev,
+			 const struct aptina_pll_limits *limits,
+			 struct aptina_pll *pll)
+{
+	unsigned int mf_min;
+	unsigned int mf_max;
+	unsigned int p1_min;
+	unsigned int p1_max;
+	unsigned int p1;
+	unsigned int div;
+
+	dev_dbg(dev, "PLL: ext clock %u pix clock %u\n",
+		pll->ext_clock, pll->pix_clock);
+
+	if (pll->ext_clock < limits->ext_clock_min ||
+	    pll->ext_clock > limits->ext_clock_max) {
+		dev_err(dev, "pll: invalid external clock frequency.\n");
+		return -EINVAL;
+	}
+
+	if (pll->pix_clock == 0 || pll->pix_clock > limits->pix_clock_max) {
+		dev_err(dev, "pll: invalid pixel clock frequency.\n");
+		return -EINVAL;
+	}
+
+	/* Compute the multiplier M and combined N*P1 divisor. */
+	div = gcd(pll->pix_clock, pll->ext_clock);
+	pll->m = pll->pix_clock / div;
+	div = pll->ext_clock / div;
+
+	/* We now have the smallest M and N*P1 values that will result in the
+	 * desired pixel clock frequency, but they might be out of the valid
+	 * range. Compute the factor by which we should multiply them given the
+	 * following constraints:
+	 *
+	 * - minimum/maximum multiplier
+	 * - minimum/maximum multiplier output clock frequency assuming the
+	 *   minimum/maximum N value
+	 * - minimum/maximum combined N*P1 divisor
+	 */
+	mf_min = DIV_ROUND_UP(limits->m_min, pll->m);
+	mf_min = max(mf_min, limits->out_clock_min /
+		     (pll->ext_clock / limits->n_min * pll->m));
+	mf_min = max(mf_min, limits->n_min * limits->p1_min / div);
+	mf_max = limits->m_max / pll->m;
+	mf_max = min(mf_max, limits->out_clock_max /
+		    (pll->ext_clock / limits->n_max * pll->m));
+	mf_max = min(mf_max, DIV_ROUND_UP(limits->n_max * limits->p1_max, div));
+
+	dev_dbg(dev, "pll: mf min %u max %u\n", mf_min, mf_max);
+	if (mf_min > mf_max) {
+		dev_err(dev, "pll: no valid combined N*P1 divisor.\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * We're looking for the highest acceptable P1 value for which a
+	 * multiplier factor MF exists that fulfills the following conditions:
+	 *
+	 * 1. p1 is in the [p1_min, p1_max] range given by the limits and is
+	 *    even
+	 * 2. mf is in the [mf_min, mf_max] range computed above
+	 * 3. div * mf is a multiple of p1, in order to compute
+	 *	n = div * mf / p1
+	 *	m = pll->m * mf
+	 * 4. the internal clock frequency, given by ext_clock / n, is in the
+	 *    [int_clock_min, int_clock_max] range given by the limits
+	 * 5. the output clock frequency, given by ext_clock / n * m, is in the
+	 *    [out_clock_min, out_clock_max] range given by the limits
+	 *
+	 * The first naive approach is to iterate over all p1 values acceptable
+	 * according to (1) and all mf values acceptable according to (2), and
+	 * stop at the first combination that fulfills (3), (4) and (5). This
+	 * has a O(n^2) complexity.
+	 *
+	 * Instead of iterating over all mf values in the [mf_min, mf_max] range
+	 * we can compute the mf increment between two acceptable values
+	 * according to (3) with
+	 *
+	 *	mf_inc = p1 / gcd(div, p1)			(6)
+	 *
+	 * and round the minimum up to the nearest multiple of mf_inc. This will
+	 * restrict the number of mf values to be checked.
+	 *
+	 * Furthermore, conditions (4) and (5) only restrict the range of
+	 * acceptable p1 and mf values by modifying the minimum and maximum
+	 * limits. (5) can be expressed as
+	 *
+	 *	ext_clock / (div * mf / p1) * m * mf >= out_clock_min
+	 *	ext_clock / (div * mf / p1) * m * mf <= out_clock_max
+	 *
+	 * or
+	 *
+	 *	p1 >= out_clock_min * div / (ext_clock * m)	(7)
+	 *	p1 <= out_clock_max * div / (ext_clock * m)
+	 *
+	 * Similarly, (4) can be expressed as
+	 *
+	 *	mf >= ext_clock * p1 / (int_clock_max * div)	(8)
+	 *	mf <= ext_clock * p1 / (int_clock_min * div)
+	 *
+	 * We can thus iterate over the restricted p1 range defined by the
+	 * combination of (1) and (7), and then compute the restricted mf range
+	 * defined by the combination of (2), (6) and (8). If the resulting mf
+	 * range is not empty, any value in the mf range is acceptable. We thus
+	 * select the mf lwoer bound and the corresponding p1 value.
+	 */
+	if (limits->p1_min == 0) {
+		dev_err(dev, "pll: P1 minimum value must be >0.\n");
+		return -EINVAL;
+	}
+
+	p1_min = max(limits->p1_min, DIV_ROUND_UP(limits->out_clock_min * div,
+		     pll->ext_clock * pll->m));
+	p1_max = min(limits->p1_max, limits->out_clock_max * div /
+		     (pll->ext_clock * pll->m));
+
+	for (p1 = p1_max & ~1; p1 >= p1_min; p1 -= 2) {
+		unsigned int mf_inc = p1 / gcd(div, p1);
+		unsigned int mf_high;
+		unsigned int mf_low;
+
+		mf_low = max(roundup(mf_min, mf_inc),
+			     DIV_ROUND_UP(pll->ext_clock * p1,
+			       limits->int_clock_max * div));
+		mf_high = min(mf_max, pll->ext_clock * p1 /
+			      (limits->int_clock_min * div));
+
+		if (mf_low > mf_high)
+			continue;
+
+		pll->n = div * mf_low / p1;
+		pll->m *= mf_low;
+		pll->p1 = p1;
+		dev_dbg(dev, "PLL: N %u M %u P1 %u\n", pll->n, pll->m, pll->p1);
+		return 0;
+	}
+
+	dev_err(dev, "pll: no valid N and P1 divisors found.\n");
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(aptina_pll_calculate);
+
+MODULE_DESCRIPTION("Aptina PLL Helpers");
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/aptina-pll.h b/drivers/media/video/aptina-pll.h
new file mode 100644
index 0000000..b370e34
--- /dev/null
+++ b/drivers/media/video/aptina-pll.h
@@ -0,0 +1,56 @@
+/*
+ * Aptina Sensor PLL Configuration
+ *
+ * Copyright (C) 2012 Laurent Pinchart <laurent.pinchart@ideasonboard.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 __APTINA_PLL_H
+#define __APTINA_PLL_H
+
+struct aptina_pll {
+	unsigned int ext_clock;
+	unsigned int pix_clock;
+
+	unsigned int n;
+	unsigned int m;
+	unsigned int p1;
+};
+
+struct aptina_pll_limits {
+	unsigned int ext_clock_min;
+	unsigned int ext_clock_max;
+	unsigned int int_clock_min;
+	unsigned int int_clock_max;
+	unsigned int out_clock_min;
+	unsigned int out_clock_max;
+	unsigned int pix_clock_max;
+
+	unsigned int n_min;
+	unsigned int n_max;
+	unsigned int m_min;
+	unsigned int m_max;
+	unsigned int p1_min;
+	unsigned int p1_max;
+};
+
+struct device;
+
+int aptina_pll_calculate(struct device *dev,
+			 const struct aptina_pll_limits *limits,
+			 struct aptina_pll *pll);
+
+#endif /* __APTINA_PLL_H */
diff --git a/drivers/media/video/as3645a.c b/drivers/media/video/as3645a.c
index f241702..7a3371f 100644
--- a/drivers/media/video/as3645a.c
+++ b/drivers/media/video/as3645a.c
@@ -881,24 +881,7 @@
 	.id_table = as3645a_id_table,
 };
 
-static int __init as3645a_init(void)
-{
-	int rval;
-
-	rval = i2c_add_driver(&as3645a_i2c_driver);
-	if (rval)
-		pr_err("%s: Failed to register the driver\n", AS3645A_NAME);
-
-	return rval;
-}
-
-static void __exit as3645a_exit(void)
-{
-	i2c_del_driver(&as3645a_i2c_driver);
-}
-
-module_init(as3645a_init);
-module_exit(as3645a_exit);
+module_i2c_driver(as3645a_i2c_driver);
 
 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
 MODULE_DESCRIPTION("LED flash driver for AS3645A, LM3555 and their clones");
diff --git a/drivers/media/video/blackfin/Kconfig b/drivers/media/video/blackfin/Kconfig
new file mode 100644
index 0000000..ecd5323
--- /dev/null
+++ b/drivers/media/video/blackfin/Kconfig
@@ -0,0 +1,10 @@
+config VIDEO_BLACKFIN_CAPTURE
+	tristate "Blackfin Video Capture Driver"
+	depends on VIDEO_V4L2 && BLACKFIN && I2C
+	select VIDEOBUF2_DMA_CONTIG
+	help
+	  V4L2 bridge driver for Blackfin video capture device.
+	  Choose PPI or EPPI as its interface.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bfin_video_capture.
diff --git a/drivers/media/video/blackfin/Makefile b/drivers/media/video/blackfin/Makefile
new file mode 100644
index 0000000..aa3a0a2
--- /dev/null
+++ b/drivers/media/video/blackfin/Makefile
@@ -0,0 +1,2 @@
+bfin_video_capture-objs := bfin_capture.o ppi.o
+obj-$(CONFIG_VIDEO_BLACKFIN_CAPTURE) += bfin_video_capture.o
diff --git a/drivers/media/video/blackfin/bfin_capture.c b/drivers/media/video/blackfin/bfin_capture.c
new file mode 100644
index 0000000..514fcf7
--- /dev/null
+++ b/drivers/media/video/blackfin/bfin_capture.c
@@ -0,0 +1,1059 @@
+/*
+ * Analog Devices video capture driver
+ *
+ * Copyright (c) 2011 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.
+ *
+ * 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/completion.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include <asm/dma.h>
+
+#include <media/blackfin/bfin_capture.h>
+#include <media/blackfin/ppi.h>
+
+#define CAPTURE_DRV_NAME        "bfin_capture"
+#define BCAP_MIN_NUM_BUF        2
+
+struct bcap_format {
+	char *desc;
+	u32 pixelformat;
+	enum v4l2_mbus_pixelcode mbus_code;
+	int bpp; /* bits per pixel */
+};
+
+struct bcap_buffer {
+	struct vb2_buffer vb;
+	struct list_head list;
+};
+
+struct bcap_device {
+	/* capture device instance */
+	struct v4l2_device v4l2_dev;
+	/* v4l2 control handler */
+	struct v4l2_ctrl_handler ctrl_handler;
+	/* device node data */
+	struct video_device *video_dev;
+	/* sub device instance */
+	struct v4l2_subdev *sd;
+	/* capture config */
+	struct bfin_capture_config *cfg;
+	/* ppi interface */
+	struct ppi_if *ppi;
+	/* current input */
+	unsigned int cur_input;
+	/* current selected standard */
+	v4l2_std_id std;
+	/* used to store pixel format */
+	struct v4l2_pix_format fmt;
+	/* bits per pixel*/
+	int bpp;
+	/* used to store sensor supported format */
+	struct bcap_format *sensor_formats;
+	/* number of sensor formats array */
+	int num_sensor_formats;
+	/* pointing to current video buffer */
+	struct bcap_buffer *cur_frm;
+	/* pointing to next video buffer */
+	struct bcap_buffer *next_frm;
+	/* buffer queue used in videobuf2 */
+	struct vb2_queue buffer_queue;
+	/* allocator-specific contexts for each plane */
+	struct vb2_alloc_ctx *alloc_ctx;
+	/* queue of filled frames */
+	struct list_head dma_queue;
+	/* used in videobuf2 callback */
+	spinlock_t lock;
+	/* used to access capture device */
+	struct mutex mutex;
+	/* used to wait ppi to complete one transfer */
+	struct completion comp;
+	/* prepare to stop */
+	bool stop;
+};
+
+struct bcap_fh {
+	struct v4l2_fh fh;
+	/* indicates whether this file handle is doing IO */
+	bool io_allowed;
+};
+
+static const struct bcap_format bcap_formats[] = {
+	{
+		.desc        = "YCbCr 4:2:2 Interleaved UYVY",
+		.pixelformat = V4L2_PIX_FMT_UYVY,
+		.mbus_code   = V4L2_MBUS_FMT_UYVY8_2X8,
+		.bpp         = 16,
+	},
+	{
+		.desc        = "YCbCr 4:2:2 Interleaved YUYV",
+		.pixelformat = V4L2_PIX_FMT_YUYV,
+		.mbus_code   = V4L2_MBUS_FMT_YUYV8_2X8,
+		.bpp         = 16,
+	},
+	{
+		.desc        = "RGB 565",
+		.pixelformat = V4L2_PIX_FMT_RGB565,
+		.mbus_code   = V4L2_MBUS_FMT_RGB565_2X8_LE,
+		.bpp         = 16,
+	},
+	{
+		.desc        = "RGB 444",
+		.pixelformat = V4L2_PIX_FMT_RGB444,
+		.mbus_code   = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+		.bpp         = 16,
+	},
+
+};
+#define BCAP_MAX_FMTS ARRAY_SIZE(bcap_formats)
+
+static irqreturn_t bcap_isr(int irq, void *dev_id);
+
+static struct bcap_buffer *to_bcap_vb(struct vb2_buffer *vb)
+{
+	return container_of(vb, struct bcap_buffer, vb);
+}
+
+static int bcap_init_sensor_formats(struct bcap_device *bcap_dev)
+{
+	enum v4l2_mbus_pixelcode code;
+	struct bcap_format *sf;
+	unsigned int num_formats = 0;
+	int i, j;
+
+	while (!v4l2_subdev_call(bcap_dev->sd, video,
+				enum_mbus_fmt, num_formats, &code))
+		num_formats++;
+	if (!num_formats)
+		return -ENXIO;
+
+	sf = kzalloc(num_formats * sizeof(*sf), GFP_KERNEL);
+	if (!sf)
+		return -ENOMEM;
+
+	for (i = 0; i < num_formats; i++) {
+		v4l2_subdev_call(bcap_dev->sd, video,
+				enum_mbus_fmt, i, &code);
+		for (j = 0; j < BCAP_MAX_FMTS; j++)
+			if (code == bcap_formats[j].mbus_code)
+				break;
+		if (j == BCAP_MAX_FMTS) {
+			/* we don't allow this sensor working with our bridge */
+			kfree(sf);
+			return -EINVAL;
+		}
+		sf[i] = bcap_formats[j];
+	}
+	bcap_dev->sensor_formats = sf;
+	bcap_dev->num_sensor_formats = num_formats;
+	return 0;
+}
+
+static void bcap_free_sensor_formats(struct bcap_device *bcap_dev)
+{
+	bcap_dev->num_sensor_formats = 0;
+	kfree(bcap_dev->sensor_formats);
+	bcap_dev->sensor_formats = NULL;
+}
+
+static int bcap_open(struct file *file)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct video_device *vfd = bcap_dev->video_dev;
+	struct bcap_fh *bcap_fh;
+
+	if (!bcap_dev->sd) {
+		v4l2_err(&bcap_dev->v4l2_dev, "No sub device registered\n");
+		return -ENODEV;
+	}
+
+	bcap_fh = kzalloc(sizeof(*bcap_fh), GFP_KERNEL);
+	if (!bcap_fh) {
+		v4l2_err(&bcap_dev->v4l2_dev,
+			 "unable to allocate memory for file handle object\n");
+		return -ENOMEM;
+	}
+
+	v4l2_fh_init(&bcap_fh->fh, vfd);
+
+	/* store pointer to v4l2_fh in private_data member of file */
+	file->private_data = &bcap_fh->fh;
+	v4l2_fh_add(&bcap_fh->fh);
+	bcap_fh->io_allowed = false;
+	return 0;
+}
+
+static int bcap_release(struct file *file)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct v4l2_fh *fh = file->private_data;
+	struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+	/* if this instance is doing IO */
+	if (bcap_fh->io_allowed)
+		vb2_queue_release(&bcap_dev->buffer_queue);
+
+	file->private_data = NULL;
+	v4l2_fh_del(&bcap_fh->fh);
+	v4l2_fh_exit(&bcap_fh->fh);
+	kfree(bcap_fh);
+	return 0;
+}
+
+static int bcap_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	return vb2_mmap(&bcap_dev->buffer_queue, vma);
+}
+
+#ifndef CONFIG_MMU
+static unsigned long bcap_get_unmapped_area(struct file *file,
+					    unsigned long addr,
+					    unsigned long len,
+					    unsigned long pgoff,
+					    unsigned long flags)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	return vb2_get_unmapped_area(&bcap_dev->buffer_queue,
+				     addr,
+				     len,
+				     pgoff,
+				     flags);
+}
+#endif
+
+static unsigned int bcap_poll(struct file *file, poll_table *wait)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	return vb2_poll(&bcap_dev->buffer_queue, file, wait);
+}
+
+static int bcap_queue_setup(struct vb2_queue *vq,
+				const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+
+	if (*nbuffers < BCAP_MIN_NUM_BUF)
+		*nbuffers = BCAP_MIN_NUM_BUF;
+
+	*nplanes = 1;
+	sizes[0] = bcap_dev->fmt.sizeimage;
+	alloc_ctxs[0] = bcap_dev->alloc_ctx;
+
+	return 0;
+}
+
+static int bcap_buffer_init(struct vb2_buffer *vb)
+{
+	struct bcap_buffer *buf = to_bcap_vb(vb);
+
+	INIT_LIST_HEAD(&buf->list);
+	return 0;
+}
+
+static int bcap_buffer_prepare(struct vb2_buffer *vb)
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct bcap_buffer *buf = to_bcap_vb(vb);
+	unsigned long size;
+
+	size = bcap_dev->fmt.sizeimage;
+	if (vb2_plane_size(vb, 0) < size) {
+		v4l2_err(&bcap_dev->v4l2_dev, "buffer too small (%lu < %lu)\n",
+				vb2_plane_size(vb, 0), size);
+		return -EINVAL;
+	}
+	vb2_set_plane_payload(&buf->vb, 0, size);
+
+	return 0;
+}
+
+static void bcap_buffer_queue(struct vb2_buffer *vb)
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct bcap_buffer *buf = to_bcap_vb(vb);
+	unsigned long flags;
+
+	spin_lock_irqsave(&bcap_dev->lock, flags);
+	list_add_tail(&buf->list, &bcap_dev->dma_queue);
+	spin_unlock_irqrestore(&bcap_dev->lock, flags);
+}
+
+static void bcap_buffer_cleanup(struct vb2_buffer *vb)
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct bcap_buffer *buf = to_bcap_vb(vb);
+	unsigned long flags;
+
+	spin_lock_irqsave(&bcap_dev->lock, flags);
+	list_del_init(&buf->list);
+	spin_unlock_irqrestore(&bcap_dev->lock, flags);
+}
+
+static void bcap_lock(struct vb2_queue *vq)
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+	mutex_lock(&bcap_dev->mutex);
+}
+
+static void bcap_unlock(struct vb2_queue *vq)
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+	mutex_unlock(&bcap_dev->mutex);
+}
+
+static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+	struct ppi_if *ppi = bcap_dev->ppi;
+	struct ppi_params params;
+	int ret;
+
+	/* enable streamon on the sub device */
+	ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 1);
+	if (ret && (ret != -ENOIOCTLCMD)) {
+		v4l2_err(&bcap_dev->v4l2_dev, "stream on failed in subdev\n");
+		return ret;
+	}
+
+	/* set ppi params */
+	params.width = bcap_dev->fmt.width;
+	params.height = bcap_dev->fmt.height;
+	params.bpp = bcap_dev->bpp;
+	params.ppi_control = bcap_dev->cfg->ppi_control;
+	params.int_mask = bcap_dev->cfg->int_mask;
+	params.blank_clocks = bcap_dev->cfg->blank_clocks;
+	ret = ppi->ops->set_params(ppi, &params);
+	if (ret < 0) {
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"Error in setting ppi params\n");
+		return ret;
+	}
+
+	/* attach ppi DMA irq handler */
+	ret = ppi->ops->attach_irq(ppi, bcap_isr);
+	if (ret < 0) {
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"Error in attaching interrupt handler\n");
+		return ret;
+	}
+
+	INIT_COMPLETION(bcap_dev->comp);
+	bcap_dev->stop = false;
+	return 0;
+}
+
+static int bcap_stop_streaming(struct vb2_queue *vq)
+{
+	struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+	struct ppi_if *ppi = bcap_dev->ppi;
+	int ret;
+
+	if (!vb2_is_streaming(vq))
+		return 0;
+
+	bcap_dev->stop = true;
+	wait_for_completion(&bcap_dev->comp);
+	ppi->ops->stop(ppi);
+	ppi->ops->detach_irq(ppi);
+	ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 0);
+	if (ret && (ret != -ENOIOCTLCMD))
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"stream off failed in subdev\n");
+
+	/* release all active buffers */
+	while (!list_empty(&bcap_dev->dma_queue)) {
+		bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next,
+						struct bcap_buffer, list);
+		list_del(&bcap_dev->next_frm->list);
+		vb2_buffer_done(&bcap_dev->next_frm->vb, VB2_BUF_STATE_ERROR);
+	}
+	return 0;
+}
+
+static struct vb2_ops bcap_video_qops = {
+	.queue_setup            = bcap_queue_setup,
+	.buf_init               = bcap_buffer_init,
+	.buf_prepare            = bcap_buffer_prepare,
+	.buf_cleanup            = bcap_buffer_cleanup,
+	.buf_queue              = bcap_buffer_queue,
+	.wait_prepare           = bcap_unlock,
+	.wait_finish            = bcap_lock,
+	.start_streaming        = bcap_start_streaming,
+	.stop_streaming         = bcap_stop_streaming,
+};
+
+static int bcap_reqbufs(struct file *file, void *priv,
+			struct v4l2_requestbuffers *req_buf)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct vb2_queue *vq = &bcap_dev->buffer_queue;
+	struct v4l2_fh *fh = file->private_data;
+	struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+	if (vb2_is_busy(vq))
+		return -EBUSY;
+
+	bcap_fh->io_allowed = true;
+
+	return vb2_reqbufs(vq, req_buf);
+}
+
+static int bcap_querybuf(struct file *file, void *priv,
+				struct v4l2_buffer *buf)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	return vb2_querybuf(&bcap_dev->buffer_queue, buf);
+}
+
+static int bcap_qbuf(struct file *file, void *priv,
+			struct v4l2_buffer *buf)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct v4l2_fh *fh = file->private_data;
+	struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+	if (!bcap_fh->io_allowed)
+		return -EBUSY;
+
+	return vb2_qbuf(&bcap_dev->buffer_queue, buf);
+}
+
+static int bcap_dqbuf(struct file *file, void *priv,
+			struct v4l2_buffer *buf)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct v4l2_fh *fh = file->private_data;
+	struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+	if (!bcap_fh->io_allowed)
+		return -EBUSY;
+
+	return vb2_dqbuf(&bcap_dev->buffer_queue,
+				buf, file->f_flags & O_NONBLOCK);
+}
+
+static irqreturn_t bcap_isr(int irq, void *dev_id)
+{
+	struct ppi_if *ppi = dev_id;
+	struct bcap_device *bcap_dev = ppi->priv;
+	struct timeval timevalue;
+	struct vb2_buffer *vb = &bcap_dev->cur_frm->vb;
+	dma_addr_t addr;
+
+	spin_lock(&bcap_dev->lock);
+
+	if (bcap_dev->cur_frm != bcap_dev->next_frm) {
+		do_gettimeofday(&timevalue);
+		vb->v4l2_buf.timestamp = timevalue;
+		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+		bcap_dev->cur_frm = bcap_dev->next_frm;
+	}
+
+	ppi->ops->stop(ppi);
+
+	if (bcap_dev->stop) {
+		complete(&bcap_dev->comp);
+	} else {
+		if (!list_empty(&bcap_dev->dma_queue)) {
+			bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next,
+						struct bcap_buffer, list);
+			list_del(&bcap_dev->next_frm->list);
+			addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->next_frm->vb, 0);
+			ppi->ops->update_addr(ppi, (unsigned long)addr);
+		}
+		ppi->ops->start(ppi);
+	}
+
+	spin_unlock(&bcap_dev->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int bcap_streamon(struct file *file, void *priv,
+				enum v4l2_buf_type buf_type)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct bcap_fh *fh = file->private_data;
+	struct ppi_if *ppi = bcap_dev->ppi;
+	dma_addr_t addr;
+	int ret;
+
+	if (!fh->io_allowed)
+		return -EBUSY;
+
+	/* call streamon to start streaming in videobuf */
+	ret = vb2_streamon(&bcap_dev->buffer_queue, buf_type);
+	if (ret)
+		return ret;
+
+	/* if dma queue is empty, return error */
+	if (list_empty(&bcap_dev->dma_queue)) {
+		v4l2_err(&bcap_dev->v4l2_dev, "dma queue is empty\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* get the next frame from the dma queue */
+	bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next,
+					struct bcap_buffer, list);
+	bcap_dev->cur_frm = bcap_dev->next_frm;
+	/* remove buffer from the dma queue */
+	list_del(&bcap_dev->cur_frm->list);
+	addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0);
+	/* update DMA address */
+	ppi->ops->update_addr(ppi, (unsigned long)addr);
+	/* enable ppi */
+	ppi->ops->start(ppi);
+
+	return 0;
+err:
+	vb2_streamoff(&bcap_dev->buffer_queue, buf_type);
+	return ret;
+}
+
+static int bcap_streamoff(struct file *file, void *priv,
+				enum v4l2_buf_type buf_type)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct bcap_fh *fh = file->private_data;
+
+	if (!fh->io_allowed)
+		return -EBUSY;
+
+	return vb2_streamoff(&bcap_dev->buffer_queue, buf_type);
+}
+
+static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	return v4l2_subdev_call(bcap_dev->sd, video, querystd, std);
+}
+
+static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	*std = bcap_dev->std;
+	return 0;
+}
+
+static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	int ret;
+
+	if (vb2_is_busy(&bcap_dev->buffer_queue))
+		return -EBUSY;
+
+	ret = v4l2_subdev_call(bcap_dev->sd, core, s_std, *std);
+	if (ret < 0)
+		return ret;
+
+	bcap_dev->std = *std;
+	return 0;
+}
+
+static int bcap_enum_input(struct file *file, void *priv,
+				struct v4l2_input *input)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct bfin_capture_config *config = bcap_dev->cfg;
+	int ret;
+	u32 status;
+
+	if (input->index >= config->num_inputs)
+		return -EINVAL;
+
+	*input = config->inputs[input->index];
+	/* get input status */
+	ret = v4l2_subdev_call(bcap_dev->sd, video, g_input_status, &status);
+	if (!ret)
+		input->status = status;
+	return 0;
+}
+
+static int bcap_g_input(struct file *file, void *priv, unsigned int *index)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	*index = bcap_dev->cur_input;
+	return 0;
+}
+
+static int bcap_s_input(struct file *file, void *priv, unsigned int index)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct bfin_capture_config *config = bcap_dev->cfg;
+	struct bcap_route *route;
+	int ret;
+
+	if (vb2_is_busy(&bcap_dev->buffer_queue))
+		return -EBUSY;
+
+	if (index >= config->num_inputs)
+		return -EINVAL;
+
+	route = &config->routes[index];
+	ret = v4l2_subdev_call(bcap_dev->sd, video, s_routing,
+				route->input, route->output, 0);
+	if ((ret < 0) && (ret != -ENOIOCTLCMD)) {
+		v4l2_err(&bcap_dev->v4l2_dev, "Failed to set input\n");
+		return ret;
+	}
+	bcap_dev->cur_input = index;
+	return 0;
+}
+
+static int bcap_try_format(struct bcap_device *bcap,
+				struct v4l2_pix_format *pixfmt,
+				enum v4l2_mbus_pixelcode *mbus_code,
+				int *bpp)
+{
+	struct bcap_format *sf = bcap->sensor_formats;
+	struct bcap_format *fmt = NULL;
+	struct v4l2_mbus_framefmt mbus_fmt;
+	int ret, i;
+
+	for (i = 0; i < bcap->num_sensor_formats; i++) {
+		fmt = &sf[i];
+		if (pixfmt->pixelformat == fmt->pixelformat)
+			break;
+	}
+	if (i == bcap->num_sensor_formats)
+		fmt = &sf[0];
+
+	if (mbus_code)
+		*mbus_code = fmt->mbus_code;
+	if (bpp)
+		*bpp = fmt->bpp;
+	v4l2_fill_mbus_format(&mbus_fmt, pixfmt, fmt->mbus_code);
+	ret = v4l2_subdev_call(bcap->sd, video,
+				try_mbus_fmt, &mbus_fmt);
+	if (ret < 0)
+		return ret;
+	v4l2_fill_pix_format(pixfmt, &mbus_fmt);
+	pixfmt->bytesperline = pixfmt->width * fmt->bpp / 8;
+	pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
+	return 0;
+}
+
+static int bcap_enum_fmt_vid_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *fmt)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct bcap_format *sf = bcap_dev->sensor_formats;
+
+	if (fmt->index >= bcap_dev->num_sensor_formats)
+		return -EINVAL;
+
+	fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	strlcpy(fmt->description,
+		sf[fmt->index].desc,
+		sizeof(fmt->description));
+	fmt->pixelformat = sf[fmt->index].pixelformat;
+	return 0;
+}
+
+static int bcap_try_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *fmt)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+	return bcap_try_format(bcap_dev, pixfmt, NULL, NULL);
+}
+
+static int bcap_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	fmt->fmt.pix = bcap_dev->fmt;
+	return 0;
+}
+
+static int bcap_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *fmt)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	struct v4l2_mbus_framefmt mbus_fmt;
+	enum v4l2_mbus_pixelcode mbus_code;
+	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+	int ret, bpp;
+
+	if (vb2_is_busy(&bcap_dev->buffer_queue))
+		return -EBUSY;
+
+	/* see if format works */
+	ret = bcap_try_format(bcap_dev, pixfmt, &mbus_code, &bpp);
+	if (ret < 0)
+		return ret;
+
+	v4l2_fill_mbus_format(&mbus_fmt, pixfmt, mbus_code);
+	ret = v4l2_subdev_call(bcap_dev->sd, video, s_mbus_fmt, &mbus_fmt);
+	if (ret < 0)
+		return ret;
+	bcap_dev->fmt = *pixfmt;
+	bcap_dev->bpp = bpp;
+	return 0;
+}
+
+static int bcap_querycap(struct file *file, void  *priv,
+				struct v4l2_capability *cap)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
+	strlcpy(cap->bus_info, "Blackfin Platform", sizeof(cap->bus_info));
+	strlcpy(cap->card, bcap_dev->cfg->card_name, sizeof(cap->card));
+	return 0;
+}
+
+static int bcap_g_parm(struct file *file, void *fh,
+				struct v4l2_streamparm *a)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	return v4l2_subdev_call(bcap_dev->sd, video, g_parm, a);
+}
+
+static int bcap_s_parm(struct file *file, void *fh,
+				struct v4l2_streamparm *a)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	return v4l2_subdev_call(bcap_dev->sd, video, s_parm, a);
+}
+
+static int bcap_g_chip_ident(struct file *file, void *priv,
+		struct v4l2_dbg_chip_ident *chip)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	chip->ident = V4L2_IDENT_NONE;
+	chip->revision = 0;
+	if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+			chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+
+	return v4l2_subdev_call(bcap_dev->sd, core,
+			g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int bcap_dbg_g_register(struct file *file, void *priv,
+		struct v4l2_dbg_register *reg)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	return v4l2_subdev_call(bcap_dev->sd, core,
+			g_register, reg);
+}
+
+static int bcap_dbg_s_register(struct file *file, void *priv,
+		struct v4l2_dbg_register *reg)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+
+	return v4l2_subdev_call(bcap_dev->sd, core,
+			s_register, reg);
+}
+#endif
+
+static int bcap_log_status(struct file *file, void *priv)
+{
+	struct bcap_device *bcap_dev = video_drvdata(file);
+	/* status for sub devices */
+	v4l2_device_call_all(&bcap_dev->v4l2_dev, 0, core, log_status);
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops bcap_ioctl_ops = {
+	.vidioc_querycap         = bcap_querycap,
+	.vidioc_g_fmt_vid_cap    = bcap_g_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_cap = bcap_enum_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap    = bcap_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap  = bcap_try_fmt_vid_cap,
+	.vidioc_enum_input       = bcap_enum_input,
+	.vidioc_g_input          = bcap_g_input,
+	.vidioc_s_input          = bcap_s_input,
+	.vidioc_querystd         = bcap_querystd,
+	.vidioc_s_std            = bcap_s_std,
+	.vidioc_g_std            = bcap_g_std,
+	.vidioc_reqbufs          = bcap_reqbufs,
+	.vidioc_querybuf         = bcap_querybuf,
+	.vidioc_qbuf             = bcap_qbuf,
+	.vidioc_dqbuf            = bcap_dqbuf,
+	.vidioc_streamon         = bcap_streamon,
+	.vidioc_streamoff        = bcap_streamoff,
+	.vidioc_g_parm           = bcap_g_parm,
+	.vidioc_s_parm           = bcap_s_parm,
+	.vidioc_g_chip_ident     = bcap_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register       = bcap_dbg_g_register,
+	.vidioc_s_register       = bcap_dbg_s_register,
+#endif
+	.vidioc_log_status       = bcap_log_status,
+};
+
+static struct v4l2_file_operations bcap_fops = {
+	.owner = THIS_MODULE,
+	.open = bcap_open,
+	.release = bcap_release,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = bcap_mmap,
+#ifndef CONFIG_MMU
+	.get_unmapped_area = bcap_get_unmapped_area,
+#endif
+	.poll = bcap_poll
+};
+
+static int __devinit bcap_probe(struct platform_device *pdev)
+{
+	struct bcap_device *bcap_dev;
+	struct video_device *vfd;
+	struct i2c_adapter *i2c_adap;
+	struct bfin_capture_config *config;
+	struct vb2_queue *q;
+	int ret;
+
+	config = pdev->dev.platform_data;
+	if (!config) {
+		v4l2_err(pdev->dev.driver, "Unable to get board config\n");
+		return -ENODEV;
+	}
+
+	bcap_dev = kzalloc(sizeof(*bcap_dev), GFP_KERNEL);
+	if (!bcap_dev) {
+		v4l2_err(pdev->dev.driver, "Unable to alloc bcap_dev\n");
+		return -ENOMEM;
+	}
+
+	bcap_dev->cfg = config;
+
+	bcap_dev->ppi = ppi_create_instance(config->ppi_info);
+	if (!bcap_dev->ppi) {
+		v4l2_err(pdev->dev.driver, "Unable to create ppi\n");
+		ret = -ENODEV;
+		goto err_free_dev;
+	}
+	bcap_dev->ppi->priv = bcap_dev;
+
+	bcap_dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(bcap_dev->alloc_ctx)) {
+		ret = PTR_ERR(bcap_dev->alloc_ctx);
+		goto err_free_ppi;
+	}
+
+	vfd = video_device_alloc();
+	if (!vfd) {
+		ret = -ENOMEM;
+		v4l2_err(pdev->dev.driver, "Unable to alloc video device\n");
+		goto err_cleanup_ctx;
+	}
+
+	/* initialize field of video device */
+	vfd->release            = video_device_release;
+	vfd->fops               = &bcap_fops;
+	vfd->ioctl_ops          = &bcap_ioctl_ops;
+	vfd->tvnorms            = 0;
+	vfd->v4l2_dev           = &bcap_dev->v4l2_dev;
+	set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+	strncpy(vfd->name, CAPTURE_DRV_NAME, sizeof(vfd->name));
+	bcap_dev->video_dev     = vfd;
+
+	ret = v4l2_device_register(&pdev->dev, &bcap_dev->v4l2_dev);
+	if (ret) {
+		v4l2_err(pdev->dev.driver,
+				"Unable to register v4l2 device\n");
+		goto err_release_vdev;
+	}
+	v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n");
+
+	bcap_dev->v4l2_dev.ctrl_handler = &bcap_dev->ctrl_handler;
+	ret = v4l2_ctrl_handler_init(&bcap_dev->ctrl_handler, 0);
+	if (ret) {
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"Unable to init control handler\n");
+		goto err_unreg_v4l2;
+	}
+
+	spin_lock_init(&bcap_dev->lock);
+	/* initialize queue */
+	q = &bcap_dev->buffer_queue;
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_MMAP;
+	q->drv_priv = bcap_dev;
+	q->buf_struct_size = sizeof(struct bcap_buffer);
+	q->ops = &bcap_video_qops;
+	q->mem_ops = &vb2_dma_contig_memops;
+
+	vb2_queue_init(q);
+
+	mutex_init(&bcap_dev->mutex);
+	init_completion(&bcap_dev->comp);
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&bcap_dev->dma_queue);
+
+	vfd->lock = &bcap_dev->mutex;
+
+	/* register video device */
+	ret = video_register_device(bcap_dev->video_dev, VFL_TYPE_GRABBER, -1);
+	if (ret) {
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"Unable to register video device\n");
+		goto err_free_handler;
+	}
+	video_set_drvdata(bcap_dev->video_dev, bcap_dev);
+	v4l2_info(&bcap_dev->v4l2_dev, "video device registered as: %s\n",
+			video_device_node_name(vfd));
+
+	/* load up the subdevice */
+	i2c_adap = i2c_get_adapter(config->i2c_adapter_id);
+	if (!i2c_adap) {
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"Unable to find i2c adapter\n");
+		goto err_unreg_vdev;
+
+	}
+	bcap_dev->sd = v4l2_i2c_new_subdev_board(&bcap_dev->v4l2_dev,
+						 i2c_adap,
+						 &config->board_info,
+						 NULL);
+	if (bcap_dev->sd) {
+		int i;
+		/* update tvnorms from the sub devices */
+		for (i = 0; i < config->num_inputs; i++)
+			vfd->tvnorms |= config->inputs[i].std;
+	} else {
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"Unable to register sub device\n");
+		goto err_unreg_vdev;
+	}
+
+	v4l2_info(&bcap_dev->v4l2_dev, "v4l2 sub device registered\n");
+
+	/* now we can probe the default state */
+	if (vfd->tvnorms) {
+		v4l2_std_id std;
+		ret = v4l2_subdev_call(bcap_dev->sd, core, g_std, &std);
+		if (ret) {
+			v4l2_err(&bcap_dev->v4l2_dev,
+					"Unable to get std\n");
+			goto err_unreg_vdev;
+		}
+		bcap_dev->std = std;
+	}
+	ret = bcap_init_sensor_formats(bcap_dev);
+	if (ret) {
+		v4l2_err(&bcap_dev->v4l2_dev,
+				"Unable to create sensor formats table\n");
+		goto err_unreg_vdev;
+	}
+	return 0;
+err_unreg_vdev:
+	video_unregister_device(bcap_dev->video_dev);
+	bcap_dev->video_dev = NULL;
+err_free_handler:
+	v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler);
+err_unreg_v4l2:
+	v4l2_device_unregister(&bcap_dev->v4l2_dev);
+err_release_vdev:
+	if (bcap_dev->video_dev)
+		video_device_release(bcap_dev->video_dev);
+err_cleanup_ctx:
+	vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx);
+err_free_ppi:
+	ppi_delete_instance(bcap_dev->ppi);
+err_free_dev:
+	kfree(bcap_dev);
+	return ret;
+}
+
+static int __devexit bcap_remove(struct platform_device *pdev)
+{
+	struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+	struct bcap_device *bcap_dev = container_of(v4l2_dev,
+						struct bcap_device, v4l2_dev);
+
+	bcap_free_sensor_formats(bcap_dev);
+	video_unregister_device(bcap_dev->video_dev);
+	v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler);
+	v4l2_device_unregister(v4l2_dev);
+	vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx);
+	ppi_delete_instance(bcap_dev->ppi);
+	kfree(bcap_dev);
+	return 0;
+}
+
+static struct platform_driver bcap_driver = {
+	.driver = {
+		.name  = CAPTURE_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = bcap_probe,
+	.remove = __devexit_p(bcap_remove),
+};
+
+static __init int bcap_init(void)
+{
+	return platform_driver_register(&bcap_driver);
+}
+
+static __exit void bcap_exit(void)
+{
+	platform_driver_unregister(&bcap_driver);
+}
+
+module_init(bcap_init);
+module_exit(bcap_exit);
+
+MODULE_DESCRIPTION("Analog Devices blackfin video capture driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/blackfin/ppi.c b/drivers/media/video/blackfin/ppi.c
new file mode 100644
index 0000000..d295921
--- /dev/null
+++ b/drivers/media/video/blackfin/ppi.c
@@ -0,0 +1,271 @@
+/*
+ * ppi.c Analog Devices Parallel Peripheral Interface driver
+ *
+ * Copyright (c) 2011 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.
+ *
+ * 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/slab.h>
+
+#include <asm/bfin_ppi.h>
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#include <media/blackfin/ppi.h>
+
+static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler);
+static void ppi_detach_irq(struct ppi_if *ppi);
+static int ppi_start(struct ppi_if *ppi);
+static int ppi_stop(struct ppi_if *ppi);
+static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params);
+static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr);
+
+static const struct ppi_ops ppi_ops = {
+	.attach_irq = ppi_attach_irq,
+	.detach_irq = ppi_detach_irq,
+	.start = ppi_start,
+	.stop = ppi_stop,
+	.set_params = ppi_set_params,
+	.update_addr = ppi_update_addr,
+};
+
+static irqreturn_t ppi_irq_err(int irq, void *dev_id)
+{
+	struct ppi_if *ppi = dev_id;
+	const struct ppi_info *info = ppi->info;
+
+	switch (info->type) {
+	case PPI_TYPE_PPI:
+	{
+		struct bfin_ppi_regs *reg = info->base;
+		unsigned short status;
+
+		/* register on bf561 is cleared when read 
+		 * others are W1C
+		 */
+		status = bfin_read16(&reg->status);
+		bfin_write16(&reg->status, 0xff00);
+		break;
+	}
+	case PPI_TYPE_EPPI:
+	{
+		struct bfin_eppi_regs *reg = info->base;
+		bfin_write16(&reg->status, 0xffff);
+		break;
+	}
+	default:
+		break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler)
+{
+	const struct ppi_info *info = ppi->info;
+	int ret;
+
+	ret = request_dma(info->dma_ch, "PPI_DMA");
+
+	if (ret) {
+		pr_err("Unable to allocate DMA channel for PPI\n");
+		return ret;
+	}
+	set_dma_callback(info->dma_ch, handler, ppi);
+
+	if (ppi->err_int) {
+		ret = request_irq(info->irq_err, ppi_irq_err, 0, "PPI ERROR", ppi);
+		if (ret) {
+			pr_err("Unable to allocate IRQ for PPI\n");
+			free_dma(info->dma_ch);
+		}
+	}
+	return ret;
+}
+
+static void ppi_detach_irq(struct ppi_if *ppi)
+{
+	const struct ppi_info *info = ppi->info;
+
+	if (ppi->err_int)
+		free_irq(info->irq_err, ppi);
+	free_dma(info->dma_ch);
+}
+
+static int ppi_start(struct ppi_if *ppi)
+{
+	const struct ppi_info *info = ppi->info;
+
+	/* enable DMA */
+	enable_dma(info->dma_ch);
+
+	/* enable PPI */
+	ppi->ppi_control |= PORT_EN;
+	switch (info->type) {
+	case PPI_TYPE_PPI:
+	{
+		struct bfin_ppi_regs *reg = info->base;
+		bfin_write16(&reg->control, ppi->ppi_control);
+		break;
+	}
+	case PPI_TYPE_EPPI:
+	{
+		struct bfin_eppi_regs *reg = info->base;
+		bfin_write32(&reg->control, ppi->ppi_control);
+		break;
+	}
+	default:
+		return -EINVAL;
+	}
+
+	SSYNC();
+	return 0;
+}
+
+static int ppi_stop(struct ppi_if *ppi)
+{
+	const struct ppi_info *info = ppi->info;
+
+	/* disable PPI */
+	ppi->ppi_control &= ~PORT_EN;
+	switch (info->type) {
+	case PPI_TYPE_PPI:
+	{
+		struct bfin_ppi_regs *reg = info->base;
+		bfin_write16(&reg->control, ppi->ppi_control);
+		break;
+	}
+	case PPI_TYPE_EPPI:
+	{
+		struct bfin_eppi_regs *reg = info->base;
+		bfin_write32(&reg->control, ppi->ppi_control);
+		break;
+	}
+	default:
+		return -EINVAL;
+	}
+
+	/* disable DMA */
+	clear_dma_irqstat(info->dma_ch);
+	disable_dma(info->dma_ch);
+
+	SSYNC();
+	return 0;
+}
+
+static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params)
+{
+	const struct ppi_info *info = ppi->info;
+	int dma32 = 0;
+	int dma_config, bytes_per_line, lines_per_frame;
+
+	bytes_per_line = params->width * params->bpp / 8;
+	lines_per_frame = params->height;
+	if (params->int_mask == 0xFFFFFFFF)
+		ppi->err_int = false;
+	else
+		ppi->err_int = true;
+
+	dma_config = (DMA_FLOW_STOP | WNR | RESTART | DMA2D | DI_EN);
+	ppi->ppi_control = params->ppi_control & ~PORT_EN;
+	switch (info->type) {
+	case PPI_TYPE_PPI:
+	{
+		struct bfin_ppi_regs *reg = info->base;
+
+		if (params->ppi_control & DMA32)
+			dma32 = 1;
+
+		bfin_write16(&reg->control, ppi->ppi_control);
+		bfin_write16(&reg->count, bytes_per_line - 1);
+		bfin_write16(&reg->frame, lines_per_frame);
+		break;
+	}
+	case PPI_TYPE_EPPI:
+	{
+		struct bfin_eppi_regs *reg = info->base;
+
+		if ((params->ppi_control & PACK_EN)
+			|| (params->ppi_control & 0x38000) > DLEN_16)
+			dma32 = 1;
+
+		bfin_write32(&reg->control, ppi->ppi_control);
+		bfin_write16(&reg->line, bytes_per_line + params->blank_clocks);
+		bfin_write16(&reg->frame, lines_per_frame);
+		bfin_write16(&reg->hdelay, 0);
+		bfin_write16(&reg->vdelay, 0);
+		bfin_write16(&reg->hcount, bytes_per_line);
+		bfin_write16(&reg->vcount, lines_per_frame);
+		break;
+	}
+	default:
+		return -EINVAL;
+	}
+
+	if (dma32) {
+		dma_config |= WDSIZE_32;
+		set_dma_x_count(info->dma_ch, bytes_per_line >> 2);
+		set_dma_x_modify(info->dma_ch, 4);
+		set_dma_y_modify(info->dma_ch, 4);
+	} else {
+		dma_config |= WDSIZE_16;
+		set_dma_x_count(info->dma_ch, bytes_per_line >> 1);
+		set_dma_x_modify(info->dma_ch, 2);
+		set_dma_y_modify(info->dma_ch, 2);
+	}
+	set_dma_y_count(info->dma_ch, lines_per_frame);
+	set_dma_config(info->dma_ch, dma_config);
+
+	SSYNC();
+	return 0;
+}
+
+static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr)
+{
+	set_dma_start_addr(ppi->info->dma_ch, addr);
+}
+
+struct ppi_if *ppi_create_instance(const struct ppi_info *info)
+{
+	struct ppi_if *ppi;
+
+	if (!info || !info->pin_req)
+		return NULL;
+
+	if (peripheral_request_list(info->pin_req, KBUILD_MODNAME)) {
+		pr_err("request peripheral failed\n");
+		return NULL;
+	}
+
+	ppi = kzalloc(sizeof(*ppi), GFP_KERNEL);
+	if (!ppi) {
+		peripheral_free_list(info->pin_req);
+		pr_err("unable to allocate memory for ppi handle\n");
+		return NULL;
+	}
+	ppi->ops = &ppi_ops;
+	ppi->info = info;
+
+	pr_info("ppi probe success\n");
+	return ppi;
+}
+
+void ppi_delete_instance(struct ppi_if *ppi)
+{
+	peripheral_free_list(ppi->info->pin_req);
+	kfree(ppi);
+}
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index 859eabf..377bf05 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -514,15 +514,4 @@
 	.id_table	= bt819_id,
 };
 
-static __init int init_bt819(void)
-{
-	return i2c_add_driver(&bt819_driver);
-}
-
-static __exit void exit_bt819(void)
-{
-	i2c_del_driver(&bt819_driver);
-}
-
-module_init(init_bt819);
-module_exit(exit_bt819);
+module_i2c_driver(bt819_driver);
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index a43059d..7e5bd36 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -270,15 +270,4 @@
 	.id_table	= bt856_id,
 };
 
-static __init int init_bt856(void)
-{
-	return i2c_add_driver(&bt856_driver);
-}
-
-static __exit void exit_bt856(void)
-{
-	i2c_del_driver(&bt856_driver);
-}
-
-module_init(init_bt856);
-module_exit(exit_bt856);
+module_i2c_driver(bt856_driver);
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
index 4e5dcea..905320b 100644
--- a/drivers/media/video/bt866.c
+++ b/drivers/media/video/bt866.c
@@ -240,15 +240,4 @@
 	.id_table	= bt866_id,
 };
 
-static __init int init_bt866(void)
-{
-	return i2c_add_driver(&bt866_driver);
-}
-
-static __exit void exit_bt866(void)
-{
-	i2c_del_driver(&bt866_driver);
-}
-
-module_init(init_bt866);
-module_exit(exit_bt866);
+module_i2c_driver(bt866_driver);
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 76c301f..e581b37 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -2035,11 +2035,7 @@
 	struct bttv_fh *fh  = f;
 	struct bttv *btv = fh->btv;
 
-	pr_info("%d: ========  START STATUS CARD #%d  ========\n",
-		btv->c.nr, btv->c.nr);
 	bttv_call_all(btv, core, log_status);
-	pr_info("%d: ========  END STATUS CARD   #%d  ========\n",
-		btv->c.nr, btv->c.nr);
 	return 0;
 }
 
diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c
index 1d64af9..c8581e2 100644
--- a/drivers/media/video/cs5345.c
+++ b/drivers/media/video/cs5345.c
@@ -249,15 +249,4 @@
 	.id_table	= cs5345_id,
 };
 
-static __init int init_cs5345(void)
-{
-	return i2c_add_driver(&cs5345_driver);
-}
-
-static __exit void exit_cs5345(void)
-{
-	i2c_del_driver(&cs5345_driver);
-}
-
-module_init(init_cs5345);
-module_exit(exit_cs5345);
+module_i2c_driver(cs5345_driver);
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
index 51c5b9a..b293912 100644
--- a/drivers/media/video/cs53l32a.c
+++ b/drivers/media/video/cs53l32a.c
@@ -248,15 +248,4 @@
 	.id_table	= cs53l32a_id,
 };
 
-static __init int init_cs53l32a(void)
-{
-	return i2c_add_driver(&cs53l32a_driver);
-}
-
-static __exit void exit_cs53l32a(void)
-{
-	i2c_del_driver(&cs53l32a_driver);
-}
-
-module_init(init_cs53l32a);
-module_exit(exit_cs53l32a);
+module_i2c_driver(cs53l32a_driver);
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 349bd9c..b55d57c 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -38,7 +38,7 @@
 #include "cx18-ioctl.h"
 #include "cx18-controls.h"
 #include "tuner-xc2028.h"
-
+#include <linux/dma-mapping.h>
 #include <media/tveeprom.h>
 
 /* If you have already X v4l cards, then set this to X. This way
@@ -75,7 +75,7 @@
 				     -1, -1, -1, -1, -1, -1, -1, -1 };
 static unsigned cardtype_c = 1;
 static unsigned tuner_c = 1;
-static bool radio_c = 1;
+static unsigned radio_c = 1;
 static char pal[] = "--";
 static char secam[] = "--";
 static char ntsc[] = "-";
@@ -110,7 +110,7 @@
 int cx18_debug;
 
 module_param_array(tuner, int, &tuner_c, 0644);
-module_param_array(radio, bool, &radio_c, 0644);
+module_param_array(radio, int, &radio_c, 0644);
 module_param_array(cardtype, int, &cardtype_c, 0644);
 module_param_string(pal, pal, sizeof(pal), 0644);
 module_param_string(secam, secam, sizeof(secam), 0644);
@@ -812,7 +812,7 @@
 		CX18_ERR("Can't enable device %d!\n", cx->instance);
 		return -EIO;
 	}
-	if (pci_set_dma_mask(pci_dev, 0xffffffff)) {
+	if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) {
 		CX18_ERR("No suitable DMA available, card %d\n", cx->instance);
 		return -EIO;
 	}
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index b9a94fc..7a37e0e 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -44,8 +44,6 @@
 #include <linux/slab.h>
 #include <asm/byteorder.h>
 
-#include <linux/dvb/video.h>
-#include <linux/dvb/audio.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 66b1c15..be49f68 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -1085,8 +1085,6 @@
 	struct v4l2_audio audin;
 	int i;
 
-	CX18_INFO("=================  START STATUS CARD #%d  "
-		  "=================\n", cx->instance);
 	CX18_INFO("Version: %s  Card: %s\n", CX18_VERSION, cx->card_name);
 	if (cx->hw_flags & CX18_HW_TVEEPROM) {
 		struct tveeprom tv;
@@ -1120,8 +1118,6 @@
 	CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
 			(long long)cx->mpg_data_received,
 			(long long)cx->vbi_data_inserted);
-	CX18_INFO("==================  END STATUS CARD #%d  "
-		  "==================\n", cx->instance);
 	return 0;
 }
 
diff --git a/drivers/media/video/cx231xx/cx231xx-417.c b/drivers/media/video/cx231xx/cx231xx-417.c
index f8f0e59..d4327da 100644
--- a/drivers/media/video/cx231xx/cx231xx-417.c
+++ b/drivers/media/video/cx231xx/cx231xx-417.c
@@ -1686,7 +1686,6 @@
 	.capabilities   = (V4L2_CAP_VIDEO_CAPTURE |
 			   V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
 			 V4L2_CAP_STREAMING | V4L2_CAP_READWRITE),
-	.reserved       = {0, 0, 0, 0}
 };
 static int vidioc_querycap(struct file *file, void  *priv,
 				struct v4l2_capability *cap)
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c
index 875a7ce..8ed460d 100644
--- a/drivers/media/video/cx231xx/cx231xx-cards.c
+++ b/drivers/media/video/cx231xx/cx231xx-cards.c
@@ -861,7 +861,6 @@
 	kfree(dev->sliced_cc_mode.alt_max_pkt_size);
 	kfree(dev->ts1_mode.alt_max_pkt_size);
 	kfree(dev);
-	dev = NULL;
 }
 
 /*
diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c
index 829a41b..7f916f0 100644
--- a/drivers/media/video/cx231xx/cx231xx-video.c
+++ b/drivers/media/video/cx231xx/cx231xx-video.c
@@ -2319,8 +2319,7 @@
 			if (dev->state & DEV_DISCONNECTED) {
 				if (atomic_read(&dev->devlist_count) > 0) {
 					cx231xx_release_resources(dev);
-					kfree(dev);
-					dev = NULL;
+					fh->dev = NULL;
 					return 0;
 				}
 				return 0;
@@ -2350,8 +2349,7 @@
 		   free the remaining resources */
 		if (dev->state & DEV_DISCONNECTED) {
 			cx231xx_release_resources(dev);
-			kfree(dev);
-			dev = NULL;
+			fh->dev = NULL;
 			return 0;
 		}
 
diff --git a/drivers/media/video/cx25821/cx25821-core.c b/drivers/media/video/cx25821/cx25821-core.c
index f617474..7930ca5 100644
--- a/drivers/media/video/cx25821/cx25821-core.c
+++ b/drivers/media/video/cx25821/cx25821-core.c
@@ -1474,8 +1474,13 @@
 		.device = 0x8210,
 		.subvendor = 0x14f1,
 		.subdevice = 0x0920,
-	},
-	{
+	}, {
+		/* CX25821 No Brand */
+		.vendor = 0x14f1,
+		.device = 0x8210,
+		.subvendor = 0x0000,
+		.subdevice = 0x0000,
+	}, {
 		/* --- end of list --- */
 	}
 };
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 05247d4..fc1ff69 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -5301,15 +5301,4 @@
 	.id_table	= cx25840_id,
 };
 
-static __init int init_cx25840(void)
-{
-	return i2c_add_driver(&cx25840_driver);
-}
-
-static __exit void exit_cx25840(void)
-{
-	i2c_del_driver(&cx25840_driver);
-}
-
-module_init(init_cx25840);
-module_exit(exit_cx25840);
+module_i2c_driver(cx25840_driver);
diff --git a/drivers/media/video/davinci/vpbe_osd.c b/drivers/media/video/davinci/vpbe_osd.c
index d6488b7..bba299d 100644
--- a/drivers/media/video/davinci/vpbe_osd.c
+++ b/drivers/media/video/davinci/vpbe_osd.c
@@ -28,7 +28,6 @@
 #include <linux/clk.h>
 #include <linux/slab.h>
 
-#include <mach/io.h>
 #include <mach/cputype.h>
 #include <mach/hardware.h>
 
diff --git a/drivers/media/video/davinci/vpbe_venc.c b/drivers/media/video/davinci/vpbe_venc.c
index 00e80f5..b21ecc8 100644
--- a/drivers/media/video/davinci/vpbe_venc.c
+++ b/drivers/media/video/davinci/vpbe_venc.c
@@ -27,7 +27,6 @@
 
 #include <mach/hardware.h>
 #include <mach/mux.h>
-#include <mach/io.h>
 #include <mach/i2c.h>
 
 #include <linux/io.h>
diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h
index 25036cb..8bcac65 100644
--- a/drivers/media/video/davinci/vpif.h
+++ b/drivers/media/video/davinci/vpif.h
@@ -18,8 +18,6 @@
 
 #include <linux/io.h>
 #include <linux/videodev2.h>
-#include <mach/hardware.h>
-#include <mach/dm646x.h>
 #include <media/davinci/vpif_types.h>
 
 /* Maximum channel allowed */
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
index 286f029..7fa34b4 100644
--- a/drivers/media/video/davinci/vpif_display.c
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -39,8 +39,6 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-chip-ident.h>
 
-#include <mach/dm646x.h>
-
 #include "vpif_display.h"
 #include "vpif.h"
 
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 4561cd8..9fd8cc7 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -353,6 +353,44 @@
 };
 #endif
 
+/* 1b80:e425 MaxMedia UB425-TC
+ * GPIO_6 - demod reset, 0=active
+ * GPIO_7 - LED, 0=active
+ */
+static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
+	{EM2874_R80_GPIO,  0x83,  0xff,  100},
+	{EM2874_R80_GPIO,  0xc3,  0xff,  100}, /* GPIO_6 = 1 */
+	{EM2874_R80_GPIO,  0x43,  0xff,  000}, /* GPIO_7 = 0 */
+	{-1,                 -1,    -1,   -1},
+};
+
+/* 2304:0242 PCTV QuatroStick (510e)
+ * GPIO_2: decoder reset, 0=active
+ * GPIO_4: decoder suspend, 0=active
+ * GPIO_6: demod reset, 0=active
+ * GPIO_7: LED, 1=active
+ */
+static struct em28xx_reg_seq pctv_510e[] = {
+	{EM2874_R80_GPIO, 0x10, 0xff, 100},
+	{EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+	{EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+	{             -1,   -1,   -1,  -1},
+};
+
+/* 2013:0251 PCTV QuatroStick nano (520e)
+ * GPIO_2: decoder reset, 0=active
+ * GPIO_4: decoder suspend, 0=active
+ * GPIO_6: demod reset, 0=active
+ * GPIO_7: LED, 1=active
+ */
+static struct em28xx_reg_seq pctv_520e[] = {
+	{EM2874_R80_GPIO, 0x10, 0xff, 100},
+	{EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+	{EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+	{EM2874_R80_GPIO, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */
+	{             -1,   -1,   -1,  -1},
+};
+
 /*
  *  Board definitions
  */
@@ -1908,6 +1946,41 @@
 			.amux     = EM28XX_AMUX_LINE_IN,
 		} },
 	},
+	/* 1b80:e425 MaxMedia UB425-TC
+	 * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 */
+	[EM2874_BOARD_MAXMEDIA_UB425_TC] = {
+		.name          = "MaxMedia UB425-TC",
+		.tuner_type    = TUNER_ABSENT,
+		.tuner_gpio    = maxmedia_ub425_tc,
+		.has_dvb       = 1,
+		.i2c_speed     = EM2874_I2C_SECONDARY_BUS_SELECT |
+				EM28XX_I2C_CLK_WAIT_ENABLE |
+				EM28XX_I2C_FREQ_400_KHZ,
+	},
+	/* 2304:0242 PCTV QuatroStick (510e)
+	 * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */
+	[EM2884_BOARD_PCTV_510E] = {
+		.name          = "PCTV QuatroStick (510e)",
+		.tuner_type    = TUNER_ABSENT,
+		.tuner_gpio    = pctv_510e,
+		.has_dvb       = 1,
+		.ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
+		.i2c_speed     = EM2874_I2C_SECONDARY_BUS_SELECT |
+				EM28XX_I2C_CLK_WAIT_ENABLE |
+				EM28XX_I2C_FREQ_400_KHZ,
+	},
+	/* 2013:0251 PCTV QuatroStick nano (520e)
+	 * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */
+	[EM2884_BOARD_PCTV_520E] = {
+		.name          = "PCTV QuatroStick nano (520e)",
+		.tuner_type    = TUNER_ABSENT,
+		.tuner_gpio    = pctv_520e,
+		.has_dvb       = 1,
+		.ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
+		.i2c_speed     = EM2874_I2C_SECONDARY_BUS_SELECT |
+				EM28XX_I2C_CLK_WAIT_ENABLE |
+				EM28XX_I2C_FREQ_400_KHZ,
+	},
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
@@ -2059,6 +2132,12 @@
 			.driver_info = EM2860_BOARD_HT_VIDBOX_NW03 },
 	{ USB_DEVICE(0x1b80, 0xe309), /* Sveon STV40 */
 			.driver_info = EM2860_BOARD_EASYCAP },
+	{ USB_DEVICE(0x1b80, 0xe425),
+			.driver_info = EM2874_BOARD_MAXMEDIA_UB425_TC },
+	{ USB_DEVICE(0x2304, 0x0242),
+			.driver_info = EM2884_BOARD_PCTV_510E },
+	{ USB_DEVICE(0x2013, 0x0251),
+			.driver_info = EM2884_BOARD_PCTV_520E },
 	{ },
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -3122,7 +3201,6 @@
 	int i, nr;
 	const int ifnum = interface->altsetting[0].desc.bInterfaceNumber;
 	char *speed;
-	char descr[255] = "";
 
 	udev = usb_get_dev(interface_to_usbdev(interface));
 
@@ -3227,21 +3305,11 @@
 		speed = "unknown";
 	}
 
-	if (udev->manufacturer)
-		strlcpy(descr, udev->manufacturer, sizeof(descr));
-
-	if (udev->product) {
-		if (*descr)
-			strlcat(descr, " ", sizeof(descr));
-		strlcat(descr, udev->product, sizeof(descr));
-	}
-
-	if (*descr)
-		strlcat(descr, " ", sizeof(descr));
-
 	printk(KERN_INFO DRIVER_NAME
-		": New device %s@ %s Mbps (%04x:%04x, interface %d, class %d)\n",
-		descr,
+		": New device %s %s @ %s Mbps "
+		"(%04x:%04x, interface %d, class %d)\n",
+		udev->manufacturer ? udev->manufacturer : "",
+		udev->product ? udev->product : "",
 		speed,
 		le16_to_cpu(udev->descriptor.idVendor),
 		le16_to_cpu(udev->descriptor.idProduct),
@@ -3307,6 +3375,17 @@
 		goto unlock_and_free;
 	}
 
+	if (has_dvb) {
+		/* pre-allocate DVB isoc transfer buffers */
+		retval = em28xx_alloc_isoc(dev, EM28XX_DIGITAL_MODE,
+					   EM28XX_DVB_MAX_PACKETS,
+					   EM28XX_DVB_NUM_BUFS,
+					   dev->dvb_max_pkt_size);
+		if (retval) {
+			goto unlock_and_free;
+		}
+	}
+
 	request_modules(dev);
 
 	/* Should be the last thing to do, to avoid newer udev's to
@@ -3379,7 +3458,7 @@
 		     video_device_node_name(dev->vdev));
 
 		dev->state |= DEV_MISCONFIGURED;
-		em28xx_uninit_isoc(dev);
+		em28xx_uninit_isoc(dev, dev->mode);
 		dev->state |= DEV_DISCONNECTED;
 		wake_up_interruptible(&dev->wait_frame);
 		wake_up_interruptible(&dev->wait_stream);
@@ -3388,6 +3467,9 @@
 		em28xx_release_resources(dev);
 	}
 
+	/* free DVB isoc buffers */
+	em28xx_uninit_isoc(dev, EM28XX_DIGITAL_MODE);
+
 	mutex_unlock(&dev->lock);
 
 	em28xx_close_extension(dev);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 0aacc96..53a9fb9 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -666,6 +666,7 @@
 
 	return rc;
 }
+EXPORT_SYMBOL_GPL(em28xx_capture_start);
 
 int em28xx_vbi_supported(struct em28xx *dev)
 {
@@ -961,146 +962,192 @@
 /*
  * Stop and Deallocate URBs
  */
-void em28xx_uninit_isoc(struct em28xx *dev)
+void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode)
 {
 	struct urb *urb;
+	struct em28xx_usb_isoc_bufs *isoc_bufs;
 	int i;
 
-	em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n");
+	em28xx_isocdbg("em28xx: called em28xx_uninit_isoc in mode %d\n", mode);
+
+	if (mode == EM28XX_DIGITAL_MODE)
+		isoc_bufs = &dev->isoc_ctl.digital_bufs;
+	else
+		isoc_bufs = &dev->isoc_ctl.analog_bufs;
 
 	dev->isoc_ctl.nfields = -1;
-	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
-		urb = dev->isoc_ctl.urb[i];
+	for (i = 0; i < isoc_bufs->num_bufs; i++) {
+		urb = isoc_bufs->urb[i];
 		if (urb) {
 			if (!irqs_disabled())
 				usb_kill_urb(urb);
 			else
 				usb_unlink_urb(urb);
 
-			if (dev->isoc_ctl.transfer_buffer[i]) {
+			if (isoc_bufs->transfer_buffer[i]) {
 				usb_free_coherent(dev->udev,
 					urb->transfer_buffer_length,
-					dev->isoc_ctl.transfer_buffer[i],
+					isoc_bufs->transfer_buffer[i],
 					urb->transfer_dma);
 			}
 			usb_free_urb(urb);
-			dev->isoc_ctl.urb[i] = NULL;
+			isoc_bufs->urb[i] = NULL;
 		}
-		dev->isoc_ctl.transfer_buffer[i] = NULL;
+		isoc_bufs->transfer_buffer[i] = NULL;
 	}
 
-	kfree(dev->isoc_ctl.urb);
-	kfree(dev->isoc_ctl.transfer_buffer);
+	kfree(isoc_bufs->urb);
+	kfree(isoc_bufs->transfer_buffer);
 
-	dev->isoc_ctl.urb = NULL;
-	dev->isoc_ctl.transfer_buffer = NULL;
-	dev->isoc_ctl.num_bufs = 0;
+	isoc_bufs->urb = NULL;
+	isoc_bufs->transfer_buffer = NULL;
+	isoc_bufs->num_bufs = 0;
 
 	em28xx_capture_start(dev, 0);
 }
 EXPORT_SYMBOL_GPL(em28xx_uninit_isoc);
 
 /*
- * Allocate URBs and start IRQ
+ * Allocate URBs
  */
-int em28xx_init_isoc(struct em28xx *dev, int max_packets,
-		     int num_bufs, int max_pkt_size,
-		     int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
+int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
+		      int max_packets, int num_bufs, int max_pkt_size)
 {
-	struct em28xx_dmaqueue *dma_q = &dev->vidq;
-	struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
+	struct em28xx_usb_isoc_bufs *isoc_bufs;
 	int i;
 	int sb_size, pipe;
 	struct urb *urb;
 	int j, k;
-	int rc;
 
-	em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n");
+	em28xx_isocdbg("em28xx: called em28xx_alloc_isoc in mode %d\n", mode);
+
+	if (mode == EM28XX_DIGITAL_MODE)
+		isoc_bufs = &dev->isoc_ctl.digital_bufs;
+	else
+		isoc_bufs = &dev->isoc_ctl.analog_bufs;
 
 	/* De-allocates all pending stuff */
-	em28xx_uninit_isoc(dev);
+	em28xx_uninit_isoc(dev, mode);
 
-	dev->isoc_ctl.isoc_copy = isoc_copy;
-	dev->isoc_ctl.num_bufs = num_bufs;
+	isoc_bufs->num_bufs = num_bufs;
 
-	dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs,  GFP_KERNEL);
-	if (!dev->isoc_ctl.urb) {
+	isoc_bufs->urb = kzalloc(sizeof(void *)*num_bufs,  GFP_KERNEL);
+	if (!isoc_bufs->urb) {
 		em28xx_errdev("cannot alloc memory for usb buffers\n");
 		return -ENOMEM;
 	}
 
-	dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
-					      GFP_KERNEL);
-	if (!dev->isoc_ctl.transfer_buffer) {
+	isoc_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
+					     GFP_KERNEL);
+	if (!isoc_bufs->transfer_buffer) {
 		em28xx_errdev("cannot allocate memory for usb transfer\n");
-		kfree(dev->isoc_ctl.urb);
+		kfree(isoc_bufs->urb);
 		return -ENOMEM;
 	}
 
-	dev->isoc_ctl.max_pkt_size = max_pkt_size;
+	isoc_bufs->max_pkt_size = max_pkt_size;
+	isoc_bufs->num_packets = max_packets;
 	dev->isoc_ctl.vid_buf = NULL;
 	dev->isoc_ctl.vbi_buf = NULL;
 
-	sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
+	sb_size = isoc_bufs->num_packets * isoc_bufs->max_pkt_size;
 
 	/* allocate urbs and transfer buffers */
-	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
-		urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+	for (i = 0; i < isoc_bufs->num_bufs; i++) {
+		urb = usb_alloc_urb(isoc_bufs->num_packets, GFP_KERNEL);
 		if (!urb) {
 			em28xx_err("cannot alloc isoc_ctl.urb %i\n", i);
-			em28xx_uninit_isoc(dev);
+			em28xx_uninit_isoc(dev, mode);
 			return -ENOMEM;
 		}
-		dev->isoc_ctl.urb[i] = urb;
+		isoc_bufs->urb[i] = urb;
 
-		dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
+		isoc_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev,
 			sb_size, GFP_KERNEL, &urb->transfer_dma);
-		if (!dev->isoc_ctl.transfer_buffer[i]) {
+		if (!isoc_bufs->transfer_buffer[i]) {
 			em28xx_err("unable to allocate %i bytes for transfer"
 					" buffer %i%s\n",
 					sb_size, i,
 					in_interrupt() ? " while in int" : "");
-			em28xx_uninit_isoc(dev);
+			em28xx_uninit_isoc(dev, mode);
 			return -ENOMEM;
 		}
-		memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+		memset(isoc_bufs->transfer_buffer[i], 0, sb_size);
 
 		/* FIXME: this is a hack - should be
 			'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK'
 			should also be using 'desc.bInterval'
 		 */
 		pipe = usb_rcvisocpipe(dev->udev,
-				       dev->mode == EM28XX_ANALOG_MODE ?
+				       mode == EM28XX_ANALOG_MODE ?
 				       EM28XX_EP_ANALOG : EM28XX_EP_DIGITAL);
 
 		usb_fill_int_urb(urb, dev->udev, pipe,
-				 dev->isoc_ctl.transfer_buffer[i], sb_size,
+				 isoc_bufs->transfer_buffer[i], sb_size,
 				 em28xx_irq_callback, dev, 1);
 
-		urb->number_of_packets = max_packets;
+		urb->number_of_packets = isoc_bufs->num_packets;
 		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
 
 		k = 0;
-		for (j = 0; j < max_packets; j++) {
+		for (j = 0; j < isoc_bufs->num_packets; j++) {
 			urb->iso_frame_desc[j].offset = k;
 			urb->iso_frame_desc[j].length =
-						dev->isoc_ctl.max_pkt_size;
-			k += dev->isoc_ctl.max_pkt_size;
+						isoc_bufs->max_pkt_size;
+			k += isoc_bufs->max_pkt_size;
 		}
 	}
 
+	return 0;
+}
+EXPORT_SYMBOL_GPL(em28xx_alloc_isoc);
+
+/*
+ * Allocate URBs and start IRQ
+ */
+int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode,
+		     int max_packets, int num_bufs, int max_pkt_size,
+		     int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
+{
+	struct em28xx_dmaqueue *dma_q = &dev->vidq;
+	struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
+	struct em28xx_usb_isoc_bufs *isoc_bufs;
+	int i;
+	int rc;
+	int alloc;
+
+	em28xx_isocdbg("em28xx: called em28xx_init_isoc in mode %d\n", mode);
+
+	dev->isoc_ctl.isoc_copy = isoc_copy;
+
+	if (mode == EM28XX_DIGITAL_MODE) {
+		isoc_bufs = &dev->isoc_ctl.digital_bufs;
+		/* no need to free/alloc isoc buffers in digital mode */
+		alloc = 0;
+	} else {
+		isoc_bufs = &dev->isoc_ctl.analog_bufs;
+		alloc = 1;
+	}
+
+	if (alloc) {
+		rc = em28xx_alloc_isoc(dev, mode, max_packets,
+				       num_bufs, max_pkt_size);
+		if (rc)
+			return rc;
+	}
+
 	init_waitqueue_head(&dma_q->wq);
 	init_waitqueue_head(&vbi_dma_q->wq);
 
 	em28xx_capture_start(dev, 1);
 
 	/* submit urbs and enables IRQ */
-	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
-		rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+	for (i = 0; i < isoc_bufs->num_bufs; i++) {
+		rc = usb_submit_urb(isoc_bufs->urb[i], GFP_ATOMIC);
 		if (rc) {
 			em28xx_err("submit of urb %i failed (error=%i)\n", i,
 				   rc);
-			em28xx_uninit_isoc(dev);
+			em28xx_uninit_isoc(dev, mode);
 			return rc;
 		}
 	}
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index aabbf48..503a8d5 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -61,9 +61,6 @@
 	printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg);	\
 } while (0)
 
-#define EM28XX_DVB_NUM_BUFS 5
-#define EM28XX_DVB_MAX_PACKETS 64
-
 struct em28xx_dvb {
 	struct dvb_frontend        *fe[2];
 
@@ -172,20 +169,21 @@
 	max_dvb_packet_size = dev->dvb_max_pkt_size;
 	if (max_dvb_packet_size < 0)
 		return max_dvb_packet_size;
-	dprintk(1, "Using %d buffers each with %d bytes\n",
+	dprintk(1, "Using %d buffers each with %d x %d bytes\n",
 		EM28XX_DVB_NUM_BUFS,
+		EM28XX_DVB_MAX_PACKETS,
 		max_dvb_packet_size);
 
-	return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
-				EM28XX_DVB_NUM_BUFS, max_dvb_packet_size,
-				em28xx_dvb_isoc_copy);
+	return em28xx_init_isoc(dev, EM28XX_DIGITAL_MODE,
+				EM28XX_DVB_MAX_PACKETS, EM28XX_DVB_NUM_BUFS,
+				max_dvb_packet_size, em28xx_dvb_isoc_copy);
 }
 
 static int em28xx_stop_streaming(struct em28xx_dvb *dvb)
 {
 	struct em28xx *dev = dvb->adapter.priv;
 
-	em28xx_uninit_isoc(dev);
+	em28xx_capture_start(dev, 0);
 
 	em28xx_set_mode(dev, EM28XX_SUSPEND);
 
@@ -327,6 +325,19 @@
 	.chunk_size = 56,
 };
 
+struct drxk_config maxmedia_ub425_tc_drxk = {
+	.adr = 0x29,
+	.single_master = 1,
+	.no_i2c_bridge = 1,
+};
+
+struct drxk_config pctv_520e_drxk = {
+	.adr = 0x29,
+	.single_master = 1,
+	.microcode_name = "dvb-demod-drxk-pctv.fw",
+	.chunk_size = 58,
+};
+
 static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
 	struct em28xx_dvb *dvb = fe->sec_priv;
@@ -460,6 +471,33 @@
 	em28xx_gpio_set(dev, terratec_h5_end);
 };
 
+static void pctv_520e_init(struct em28xx *dev)
+{
+	/*
+	 * Init TDA8295(?) analog demodulator. Looks like I2C traffic to
+	 * digital demodulator and tuner are routed via TDA8295.
+	 */
+	int i;
+	struct {
+		unsigned char r[4];
+		int len;
+	} regs[] = {
+		{{ 0x06, 0x02, 0x00, 0x31 }, 4},
+		{{ 0x01, 0x02 }, 2},
+		{{ 0x01, 0x02, 0x00, 0xc6 }, 4},
+		{{ 0x01, 0x00 }, 2},
+		{{ 0x01, 0x00, 0xff, 0xaf }, 4},
+		{{ 0x01, 0x00, 0x03, 0xa0 }, 4},
+		{{ 0x01, 0x00 }, 2},
+		{{ 0x01, 0x00, 0x73, 0xaf }, 4},
+	};
+
+	dev->i2c_client.addr = 0x82 >> 1; /* 0x41 */
+
+	for (i = 0; i < ARRAY_SIZE(regs); i++)
+		i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+};
+
 static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe)
 {
 	/* Values extracted from a USB trace of the Terratec Windows driver */
@@ -938,6 +976,48 @@
 			dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap,
 				&em28xx_a8293_config);
 		break;
+	case EM2874_BOARD_MAXMEDIA_UB425_TC:
+		/* attach demodulator */
+		dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk,
+				&dev->i2c_adap);
+
+		if (dvb->fe[0]) {
+			/* disable I2C-gate */
+			dvb->fe[0]->ops.i2c_gate_ctrl = NULL;
+
+			/* attach tuner */
+			if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0],
+					&dev->i2c_adap, 0x60)) {
+				dvb_frontend_detach(dvb->fe[0]);
+				result = -EINVAL;
+				goto out_free;
+			}
+		}
+
+		/* TODO: we need drx-3913k firmware in order to support DVB-T */
+		em28xx_info("MaxMedia UB425-TC: only DVB-C supported by that " \
+				"driver version\n");
+
+		break;
+	case EM2884_BOARD_PCTV_510E:
+	case EM2884_BOARD_PCTV_520E:
+		pctv_520e_init(dev);
+
+		/* attach demodulator */
+		dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk,
+				&dev->i2c_adap);
+
+		if (dvb->fe[0]) {
+			/* attach tuner */
+			if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+					&dev->i2c_adap,
+					&em28xx_cxd2820r_tda18271_config)) {
+				dvb_frontend_detach(dvb->fe[0]);
+				result = -EINVAL;
+				goto out_free;
+			}
+		}
+		break;
 	default:
 		em28xx_errdev("/2: The frontend of your DVB/ATSC card"
 				" isn't supported yet\n");
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 36f5a9b..a88e169 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -41,14 +41,6 @@
 module_param(i2c_debug, int, 0644);
 MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
 
-
-#define dprintk1(lvl, fmt, args...)			\
-do {							\
-	if (i2c_debug >= lvl) {				\
-	printk(fmt, ##args);				\
-      }							\
-} while (0)
-
 #define dprintk2(lvl, fmt, args...)			\
 do {							\
 	if (i2c_debug >= lvl) {				\
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 613300b..324b695 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -760,17 +760,19 @@
 			goto fail;
 	}
 
-	if (!dev->isoc_ctl.num_bufs)
+	if (!dev->isoc_ctl.analog_bufs.num_bufs)
 		urb_init = 1;
 
 	if (urb_init) {
 		if (em28xx_vbi_supported(dev) == 1)
-			rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+			rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE,
+					      EM28XX_NUM_PACKETS,
 					      EM28XX_NUM_BUFS,
 					      dev->max_pkt_size,
 					      em28xx_isoc_copy_vbi);
 		else
-			rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+			rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE,
+					      EM28XX_NUM_PACKETS,
 					      EM28XX_NUM_BUFS,
 					      dev->max_pkt_size,
 					      em28xx_isoc_copy);
@@ -2267,7 +2269,7 @@
 		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
 
 		/* do this before setting alternate! */
-		em28xx_uninit_isoc(dev);
+		em28xx_uninit_isoc(dev, EM28XX_ANALOG_MODE);
 		em28xx_set_mode(dev, EM28XX_SUSPEND);
 
 		/* set alternate 0 */
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 22e252b..2868b19 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -125,6 +125,9 @@
 #define EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C	  81
 #define EM2884_BOARD_CINERGY_HTC_STICK		  82
 #define EM2860_BOARD_HT_VIDBOX_NW03 		  83
+#define EM2874_BOARD_MAXMEDIA_UB425_TC            84
+#define EM2884_BOARD_PCTV_510E                    85
+#define EM2884_BOARD_PCTV_520E                    86
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
@@ -151,12 +154,14 @@
 
 /* number of buffers for isoc transfers */
 #define EM28XX_NUM_BUFS 5
+#define EM28XX_DVB_NUM_BUFS 5
 
 /* number of packets for each buffer
    windows requests only 64 packets .. so we better do the same
    this is what I found out for all alternate numbers there!
  */
 #define EM28XX_NUM_PACKETS 64
+#define EM28XX_DVB_MAX_PACKETS 64
 
 #define EM28XX_INTERLACED_DEFAULT 1
 
@@ -197,10 +202,13 @@
 
 struct em28xx;
 
-struct em28xx_usb_isoc_ctl {
+struct em28xx_usb_isoc_bufs {
 		/* max packet size of isoc transaction */
 	int				max_pkt_size;
 
+		/* number of packets in each buffer */
+	int				num_packets;
+
 		/* number of allocated urbs */
 	int				num_bufs;
 
@@ -209,6 +217,14 @@
 
 		/* transfer buffers for isoc transfer */
 	char				**transfer_buffer;
+};
+
+struct em28xx_usb_isoc_ctl {
+		/* isoc transfer buffers for analog mode */
+	struct em28xx_usb_isoc_bufs	analog_bufs;
+
+		/* isoc transfer buffers for digital mode */
+	struct em28xx_usb_isoc_bufs	digital_bufs;
 
 		/* Last buffer command and region */
 	u8				cmd;
@@ -600,9 +616,6 @@
 	unsigned int *alt_max_pkt_size;	/* array of wMaxPacketSize */
 	int dvb_alt;				/* alternate for DVB */
 	unsigned int dvb_max_pkt_size;		/* wMaxPacketSize for DVB */
-	struct urb *urb[EM28XX_NUM_BUFS];	/* urb for isoc transfers */
-	char *transfer_buffer[EM28XX_NUM_BUFS];	/* transfer buffers for isoc
-						   transfer */
 	char urb_buf[URB_MAX_CTRL_SIZE];	/* urb control msg buffer */
 
 	/* helper funcs that call usb_control_msg */
@@ -676,10 +689,12 @@
 int em28xx_set_outfmt(struct em28xx *dev);
 int em28xx_resolution_set(struct em28xx *dev);
 int em28xx_set_alternate(struct em28xx *dev);
-int em28xx_init_isoc(struct em28xx *dev, int max_packets,
-		     int num_bufs, int max_pkt_size,
+int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
+		      int max_packets, int num_bufs, int max_pkt_size);
+int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode,
+		     int max_packets, int num_bufs, int max_pkt_size,
 		     int (*isoc_copy) (struct em28xx *dev, struct urb *urb));
-void em28xx_uninit_isoc(struct em28xx *dev);
+void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode);
 int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev);
 int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
 int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
diff --git a/drivers/media/video/gspca/gl860/Makefile b/drivers/media/video/gspca/gl860/Makefile
index f511ecc..773ea342 100644
--- a/drivers/media/video/gspca/gl860/Makefile
+++ b/drivers/media/video/gspca/gl860/Makefile
@@ -6,5 +6,5 @@
 		    gl860-ov9655.o \
 		    gl860-mi2020.o
 
-ccflags-y += -Idrivers/media/video/gspca
+ccflags-y += -I$(srctree)/drivers/media/video/gspca
 
diff --git a/drivers/media/video/gspca/m5602/Makefile b/drivers/media/video/gspca/m5602/Makefile
index 7f52961..575b75b 100644
--- a/drivers/media/video/gspca/m5602/Makefile
+++ b/drivers/media/video/gspca/m5602/Makefile
@@ -8,4 +8,4 @@
 		    m5602_s5k83a.o \
 		    m5602_s5k4aa.o
 
-ccflags-y += -Idrivers/media/video/gspca
+ccflags-y += -I$(srctree)/drivers/media/video/gspca
diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c
index fbfa02a..e6601b8 100644
--- a/drivers/media/video/gspca/ov534_9.c
+++ b/drivers/media/video/gspca/ov534_9.c
@@ -1107,16 +1107,34 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 val;
+	s8 sval;
 
 	if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS))
 		return;
-	val = sd->ctrls[BRIGHTNESS].val;
-	if (val < 8)
-		val = 15 - val;		/* f .. 8 */
-	else
-		val = val - 8;		/* 0 .. 7 */
-	sccb_write(gspca_dev, 0x55,	/* brtn - brightness adjustment */
-			0x0f | (val << 4));
+	if (sd->sensor == SENSOR_OV562x) {
+		sval = sd->ctrls[BRIGHTNESS].val;
+		val = 0x76;
+		val += sval;
+		sccb_write(gspca_dev, 0x24, val);
+		val = 0x6a;
+		val += sval;
+		sccb_write(gspca_dev, 0x25, val);
+		if (sval < -40)
+			val = 0x71;
+		else if (sval < 20)
+			val = 0x94;
+		else
+			val = 0xe6;
+		sccb_write(gspca_dev, 0x26, val);
+	} else {
+		val = sd->ctrls[BRIGHTNESS].val;
+		if (val < 8)
+			val = 15 - val;		/* f .. 8 */
+		else
+			val = val - 8;		/* 0 .. 7 */
+		sccb_write(gspca_dev, 0x55,	/* brtn - brightness adjustment */
+				0x0f | (val << 4));
+	}
 }
 
 static void setcontrast(struct gspca_dev *gspca_dev)
@@ -1339,7 +1357,16 @@
 			reg_w(gspca_dev, 0x56, 0x17);
 	} else if ((sensor_id & 0xfff0) == 0x5620) {
 		sd->sensor = SENSOR_OV562x;
+		gspca_dev->ctrl_dis = (1 << CONTRAST) |
+					(1 << AUTOGAIN) |
+					(1 << EXPOSURE) |
+					(1 << SHARPNESS) |
+					(1 << SATUR) |
+					(1 << LIGHTFREQ);
 
+		sd->ctrls[BRIGHTNESS].min = -90;
+		sd->ctrls[BRIGHTNESS].max = 90;
+		sd->ctrls[BRIGHTNESS].def = 0;
 		gspca_dev->cam.cam_mode = ov562x_mode;
 		gspca_dev->cam.nmodes = ARRAY_SIZE(ov562x_mode);
 
@@ -1360,8 +1387,12 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	if (sd->sensor == SENSOR_OV971x || sd->sensor == SENSOR_OV562x)
+	if (sd->sensor == SENSOR_OV971x)
 		return gspca_dev->usb_err;
+	else if (sd->sensor == SENSOR_OV562x) {
+		setbrightness(gspca_dev);
+		return gspca_dev->usb_err;
+	}
 	switch (gspca_dev->curr_mode) {
 	case QVGA_MODE:			/* 320x240 */
 		sccb_w_array(gspca_dev, ov965x_start_1_vga,
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c
index 9db2b34..30662fc 100644
--- a/drivers/media/video/gspca/pac7302.c
+++ b/drivers/media/video/gspca/pac7302.c
@@ -1,8 +1,8 @@
 /*
- *		Pixart PAC7302 library
- *		Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
+ * Pixart PAC7302 driver
  *
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2008-2012 Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
  *
  * Separated from Pixart PAC7311 library by Márton Németh
  * Camera button input handling by Márton Németh <nm127@freemail.hu>
@@ -63,67 +63,61 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#define MODULE_NAME "pac7302"
-
 #include <linux/input.h>
 #include <media/v4l2-chip-ident.h>
 #include "gspca.h"
+/* Include pac common sof detection functions */
+#include "pac_common.h"
 
-MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, "
+		"Thomas Kaiser thomas@kaiser-linux.li");
 MODULE_DESCRIPTION("Pixart PAC7302");
 MODULE_LICENSE("GPL");
 
+enum e_ctrl {
+	BRIGHTNESS,
+	CONTRAST,
+	COLORS,
+	WHITE_BALANCE,
+	RED_BALANCE,
+	BLUE_BALANCE,
+	GAIN,
+	AUTOGAIN,
+	EXPOSURE,
+	VFLIP,
+	HFLIP,
+	NCTRLS		/* number of controls */
+};
+
 /* specific webcam descriptor for pac7302 */
 struct sd {
 	struct gspca_dev gspca_dev;		/* !! must be the first item */
 
-	unsigned char brightness;
-	unsigned char contrast;
-	unsigned char colors;
-	unsigned char white_balance;
-	unsigned char red_balance;
-	unsigned char blue_balance;
-	unsigned char gain;
-	unsigned char autogain;
-	unsigned short exposure;
-	__u8 hflip;
-	__u8 vflip;
+	struct gspca_ctrl ctrls[NCTRLS];
+
 	u8 flags;
 #define FL_HFLIP 0x01		/* mirrored by default */
 #define FL_VFLIP 0x02		/* vertical flipped by default */
 
 	u8 sof_read;
-	u8 autogain_ignore_frames;
+	s8 autogain_ignore_frames;
 
 	atomic_t avg_lum;
 };
 
 /* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static void setbrightcont(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
+static void setwhitebalance(struct gspca_dev *gspca_dev);
+static void setredbalance(struct gspca_dev *gspca_dev);
+static void setbluebalance(struct gspca_dev *gspca_dev);
+static void setgain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
+static void setautogain(struct gspca_dev *gspca_dev);
+static void sethvflip(struct gspca_dev *gspca_dev);
 
 static const struct ctrl sd_ctrls[] = {
-	{
+[BRIGHTNESS] = {
 	    {
 		.id      = V4L2_CID_BRIGHTNESS,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
@@ -132,13 +126,11 @@
 #define BRIGHTNESS_MAX 0x20
 		.maximum = BRIGHTNESS_MAX,
 		.step    = 1,
-#define BRIGHTNESS_DEF 0x10
-		.default_value = BRIGHTNESS_DEF,
+		.default_value = 0x10,
 	    },
-	    .set = sd_setbrightness,
-	    .get = sd_getbrightness,
+	    .set_control = setbrightcont
 	},
-	{
+[CONTRAST] = {
 	    {
 		.id      = V4L2_CID_CONTRAST,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
@@ -147,13 +139,11 @@
 #define CONTRAST_MAX 255
 		.maximum = CONTRAST_MAX,
 		.step    = 1,
-#define CONTRAST_DEF 127
-		.default_value = CONTRAST_DEF,
+		.default_value = 127,
 	    },
-	    .set = sd_setcontrast,
-	    .get = sd_getcontrast,
+	    .set_control = setbrightcont
 	},
-	{
+[COLORS] = {
 	    {
 		.id      = V4L2_CID_SATURATION,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
@@ -162,13 +152,11 @@
 #define COLOR_MAX 255
 		.maximum = COLOR_MAX,
 		.step    = 1,
-#define COLOR_DEF 127
-		.default_value = COLOR_DEF,
+		.default_value = 127
 	    },
-	    .set = sd_setcolors,
-	    .get = sd_getcolors,
+	    .set_control = setcolors
 	},
-	{
+[WHITE_BALANCE] = {
 	    {
 		.id      = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
@@ -176,13 +164,11 @@
 		.minimum = 0,
 		.maximum = 255,
 		.step    = 1,
-#define WHITEBALANCE_DEF 4
-		.default_value = WHITEBALANCE_DEF,
+		.default_value = 4,
 	    },
-	    .set = sd_setwhitebalance,
-	    .get = sd_getwhitebalance,
+	    .set_control = setwhitebalance
 	},
-	{
+[RED_BALANCE] = {
 	    {
 		.id      = V4L2_CID_RED_BALANCE,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
@@ -190,13 +176,11 @@
 		.minimum = 0,
 		.maximum = 3,
 		.step    = 1,
-#define REDBALANCE_DEF 1
-		.default_value = REDBALANCE_DEF,
+		.default_value = 1,
 	    },
-	    .set = sd_setredbalance,
-	    .get = sd_getredbalance,
+	    .set_control = setredbalance
 	},
-	{
+[BLUE_BALANCE] = {
 	    {
 		.id      = V4L2_CID_BLUE_BALANCE,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
@@ -204,29 +188,25 @@
 		.minimum = 0,
 		.maximum = 3,
 		.step    = 1,
-#define BLUEBALANCE_DEF 1
-		.default_value = BLUEBALANCE_DEF,
+		.default_value = 1,
 	    },
-	    .set = sd_setbluebalance,
-	    .get = sd_getbluebalance,
+	    .set_control = setbluebalance
 	},
-	{
+[GAIN] = {
 	    {
 		.id      = V4L2_CID_GAIN,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
 		.name    = "Gain",
 		.minimum = 0,
-#define GAIN_MAX 255
-		.maximum = GAIN_MAX,
+		.maximum = 255,
 		.step    = 1,
 #define GAIN_DEF 127
 #define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
 		.default_value = GAIN_DEF,
 	    },
-	    .set = sd_setgain,
-	    .get = sd_getgain,
+	    .set_control = setgain
 	},
-	{
+[EXPOSURE] = {
 	    {
 		.id      = V4L2_CID_EXPOSURE,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
@@ -238,10 +218,9 @@
 #define EXPOSURE_KNEE 133 /*  66 ms / 15 fps */
 		.default_value = EXPOSURE_DEF,
 	    },
-	    .set = sd_setexposure,
-	    .get = sd_getexposure,
+	    .set_control = setexposure
 	},
-	{
+[AUTOGAIN] = {
 	    {
 		.id      = V4L2_CID_AUTOGAIN,
 		.type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -252,10 +231,9 @@
 #define AUTOGAIN_DEF 1
 		.default_value = AUTOGAIN_DEF,
 	    },
-	    .set = sd_setautogain,
-	    .get = sd_getautogain,
+	    .set_control = setautogain,
 	},
-	{
+[HFLIP] = {
 	    {
 		.id      = V4L2_CID_HFLIP,
 		.type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -263,13 +241,11 @@
 		.minimum = 0,
 		.maximum = 1,
 		.step    = 1,
-#define HFLIP_DEF 0
-		.default_value = HFLIP_DEF,
+		.default_value = 0,
 	    },
-	    .set = sd_sethflip,
-	    .get = sd_gethflip,
+	    .set_control = sethvflip,
 	},
-	{
+[VFLIP] = {
 	    {
 		.id      = V4L2_CID_VFLIP,
 		.type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -277,11 +253,9 @@
 		.minimum = 0,
 		.maximum = 1,
 		.step    = 1,
-#define VFLIP_DEF 0
-		.default_value = VFLIP_DEF,
+		.default_value = 0,
 	    },
-	    .set = sd_setvflip,
-	    .get = sd_getvflip,
+	    .set_control = sethvflip
 	},
 };
 
@@ -290,21 +264,21 @@
 		.bytesperline = 640,
 		.sizeimage = 640 * 480 * 3 / 8 + 590,
 		.colorspace = V4L2_COLORSPACE_JPEG,
-		.priv = 0},
+	},
 };
 
 #define LOAD_PAGE3		255
 #define END_OF_SEQUENCE		0
 
 /* pac 7302 */
-static const __u8 init_7302[] = {
+static const u8 init_7302[] = {
 /*	index,value */
 	0xff, 0x01,		/* page 1 */
 	0x78, 0x00,		/* deactivate */
 	0xff, 0x01,
 	0x78, 0x40,		/* led off */
 };
-static const __u8 start_7302[] = {
+static const u8 start_7302[] = {
 /*	index, len, [value]* */
 	0xff, 1,	0x00,		/* page 0 */
 	0x00, 12,	0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
@@ -319,7 +293,7 @@
 	0x43, 11,	0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
 			0x00, 0x54, 0x11,
 	0x55, 1,	0x00,
-	0x62, 4, 	0x10, 0x1e, 0x1e, 0x18,
+	0x62, 4,	0x10, 0x1e, 0x1e, 0x18,
 	0x6b, 1,	0x00,
 	0x6e, 3,	0x08, 0x06, 0x00,
 	0x72, 3,	0x00, 0xff, 0x00,
@@ -370,7 +344,7 @@
 
 #define SKIP		0xaa
 /* page 3 - the value SKIP says skip the index - see reg_w_page() */
-static const __u8 page3_7302[] = {
+static const u8 page3_7302[] = {
 	0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
 	0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
 	0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -394,7 +368,7 @@
 };
 
 static void reg_w_buf(struct gspca_dev *gspca_dev,
-		  __u8 index,
+		u8 index,
 		  const u8 *buffer, int len)
 {
 	int ret;
@@ -410,7 +384,7 @@
 			index, gspca_dev->usb_buf, len,
 			500);
 	if (ret < 0) {
-		pr_err("reg_w_buf failed index 0x%02x, error %d\n",
+		pr_err("reg_w_buf failed i: %02x error %d\n",
 		       index, ret);
 		gspca_dev->usb_err = ret;
 	}
@@ -418,8 +392,8 @@
 
 
 static void reg_w(struct gspca_dev *gspca_dev,
-		  __u8 index,
-		  __u8 value)
+		u8 index,
+		u8 value)
 {
 	int ret;
 
@@ -433,14 +407,14 @@
 			0, index, gspca_dev->usb_buf, 1,
 			500);
 	if (ret < 0) {
-		pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n",
+		pr_err("reg_w() failed i: %02x v: %02x error %d\n",
 		       index, value, ret);
 		gspca_dev->usb_err = ret;
 	}
 }
 
 static void reg_w_seq(struct gspca_dev *gspca_dev,
-		const __u8 *seq, int len)
+		const u8 *seq, int len)
 {
 	while (--len >= 0) {
 		reg_w(gspca_dev, seq[0], seq[1]);
@@ -450,7 +424,7 @@
 
 /* load the beginning of a page */
 static void reg_w_page(struct gspca_dev *gspca_dev,
-			const __u8 *page, int len)
+			const u8 *page, int len)
 {
 	int index;
 	int ret = 0;
@@ -468,7 +442,7 @@
 				0, index, gspca_dev->usb_buf, 1,
 				500);
 		if (ret < 0) {
-			pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n",
+			pr_err("reg_w_page() failed i: %02x v: %02x error %d\n",
 			       index, page[index], ret);
 			gspca_dev->usb_err = ret;
 			break;
@@ -478,8 +452,8 @@
 
 /* output a variable sequence */
 static void reg_w_var(struct gspca_dev *gspca_dev,
-			const __u8 *seq,
-			const __u8 *page3, unsigned int page3_len)
+			const u8 *seq,
+			const u8 *page3, unsigned int page3_len)
 {
 	int index, len;
 
@@ -493,11 +467,13 @@
 			reg_w_page(gspca_dev, page3, page3_len);
 			break;
 		default:
+#ifdef GSPCA_DEBUG
 			if (len > USB_BUF_SZ) {
 				PDEBUG(D_ERR|D_STREAM,
 					"Incorrect variable sequence");
 				return;
 			}
+#endif
 			while (len > 0) {
 				if (len < 8) {
 					reg_w_buf(gspca_dev,
@@ -524,21 +500,11 @@
 
 	cam = &gspca_dev->cam;
 
-	PDEBUG(D_CONF, "Find Sensor PAC7302");
 	cam->cam_mode = vga_mode;	/* only 640x480 */
 	cam->nmodes = ARRAY_SIZE(vga_mode);
 
-	sd->brightness = BRIGHTNESS_DEF;
-	sd->contrast = CONTRAST_DEF;
-	sd->colors = COLOR_DEF;
-	sd->white_balance = WHITEBALANCE_DEF;
-	sd->red_balance = REDBALANCE_DEF;
-	sd->blue_balance = BLUEBALANCE_DEF;
-	sd->gain = GAIN_DEF;
-	sd->exposure = EXPOSURE_DEF;
-	sd->autogain = AUTOGAIN_DEF;
-	sd->hflip = HFLIP_DEF;
-	sd->vflip = VFLIP_DEF;
+	gspca_dev->cam.ctrls = sd->ctrls;
+
 	sd->flags = id->driver_info;
 	return 0;
 }
@@ -548,19 +514,19 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int i, v;
-	static const __u8 max[10] =
+	static const u8 max[10] =
 		{0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
 		 0xd4, 0xec};
-	static const __u8 delta[10] =
+	static const u8 delta[10] =
 		{0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
 		 0x11, 0x0b};
 
 	reg_w(gspca_dev, 0xff, 0x00);		/* page 0 */
 	for (i = 0; i < 10; i++) {
 		v = max[i];
-		v += (sd->brightness - BRIGHTNESS_MAX)
+		v += (sd->ctrls[BRIGHTNESS].val - BRIGHTNESS_MAX)
 			* 150 / BRIGHTNESS_MAX;		/* 200 ? */
-		v -= delta[i] * sd->contrast / CONTRAST_MAX;
+		v -= delta[i] * sd->ctrls[CONTRAST].val / CONTRAST_MAX;
 		if (v < 0)
 			v = 0;
 		else if (v > 0xff)
@@ -584,12 +550,11 @@
 	reg_w(gspca_dev, 0x11, 0x01);
 	reg_w(gspca_dev, 0xff, 0x00);			/* page 0 */
 	for (i = 0; i < 9; i++) {
-		v = a[i] * sd->colors / COLOR_MAX + b[i];
+		v = a[i] * sd->ctrls[COLORS].val / COLOR_MAX + b[i];
 		reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
 		reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
 	}
 	reg_w(gspca_dev, 0xdc, 0x01);
-	PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
 }
 
 static void setwhitebalance(struct gspca_dev *gspca_dev)
@@ -597,10 +562,9 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	reg_w(gspca_dev, 0xff, 0x00);		/* page 0 */
-	reg_w(gspca_dev, 0xc6, sd->white_balance);
+	reg_w(gspca_dev, 0xc6, sd->ctrls[WHITE_BALANCE].val);
 
 	reg_w(gspca_dev, 0xdc, 0x01);
-	PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance);
 }
 
 static void setredbalance(struct gspca_dev *gspca_dev)
@@ -608,10 +572,9 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	reg_w(gspca_dev, 0xff, 0x00);		/* page 0 */
-	reg_w(gspca_dev, 0xc5, sd->red_balance);
+	reg_w(gspca_dev, 0xc5, sd->ctrls[RED_BALANCE].val);
 
 	reg_w(gspca_dev, 0xdc, 0x01);
-	PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance);
 }
 
 static void setbluebalance(struct gspca_dev *gspca_dev)
@@ -619,10 +582,9 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	reg_w(gspca_dev, 0xff, 0x00);			/* page 0 */
-	reg_w(gspca_dev, 0xc7, sd->blue_balance);
+	reg_w(gspca_dev, 0xc7, sd->ctrls[BLUE_BALANCE].val);
 
 	reg_w(gspca_dev, 0xdc, 0x01);
-	PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance);
 }
 
 static void setgain(struct gspca_dev *gspca_dev)
@@ -630,7 +592,7 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	reg_w(gspca_dev, 0xff, 0x03);			/* page 3 */
-	reg_w(gspca_dev, 0x10, sd->gain >> 3);
+	reg_w(gspca_dev, 0x10, sd->ctrls[GAIN].val >> 3);
 
 	/* load registers to sensor (Bit 0, auto clear) */
 	reg_w(gspca_dev, 0x11, 0x01);
@@ -639,13 +601,13 @@
 static void setexposure(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	__u8 clockdiv;
-	__u16 exposure;
+	u8 clockdiv;
+	u16 exposure;
 
 	/* register 2 of frame 3 contains the clock divider configuring the
 	   no fps according to the formula: 90 / reg. sd->exposure is the
 	   desired exposure time in 0.5 ms. */
-	clockdiv = (90 * sd->exposure + 1999) / 2000;
+	clockdiv = (90 * sd->ctrls[EXPOSURE].val + 1999) / 2000;
 
 	/* Note clockdiv = 3 also works, but when running at 30 fps, depending
 	   on the scene being recorded, the camera switches to another
@@ -664,7 +626,7 @@
 
 	/* frame exposure time in ms = 1000 * clockdiv / 90    ->
 	exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */
-	exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv);
+	exposure = (sd->ctrls[EXPOSURE].val * 45 * 448) / (1000 * clockdiv);
 	/* 0 = use full frametime, 448 = no exposure, reverse it */
 	exposure = 448 - exposure;
 
@@ -677,15 +639,35 @@
 	reg_w(gspca_dev, 0x11, 0x01);
 }
 
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* when switching to autogain set defaults to make sure
+	   we are on a valid point of the autogain gain /
+	   exposure knee graph, and give this change time to
+	   take effect before doing autogain. */
+	if (sd->ctrls[AUTOGAIN].val) {
+		sd->ctrls[EXPOSURE].val = EXPOSURE_DEF;
+		sd->ctrls[GAIN].val = GAIN_DEF;
+		sd->autogain_ignore_frames =
+				PAC_AUTOGAIN_IGNORE_FRAMES;
+	} else {
+		sd->autogain_ignore_frames = -1;
+	}
+	setexposure(gspca_dev);
+	setgain(gspca_dev);
+}
+
 static void sethvflip(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 data, hflip, vflip;
 
-	hflip = sd->hflip;
+	hflip = sd->ctrls[HFLIP].val;
 	if (sd->flags & FL_HFLIP)
 		hflip = !hflip;
-	vflip = sd->vflip;
+	vflip = sd->ctrls[VFLIP].val;
 	if (sd->flags & FL_VFLIP)
 		vflip = !vflip;
 
@@ -708,8 +690,6 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	sd->sof_read = 0;
-
 	reg_w_var(gspca_dev, start_7302,
 		page3_7302, sizeof(page3_7302));
 	setbrightcont(gspca_dev);
@@ -717,15 +697,13 @@
 	setwhitebalance(gspca_dev);
 	setredbalance(gspca_dev);
 	setbluebalance(gspca_dev);
-	setgain(gspca_dev);
-	setexposure(gspca_dev);
+	setautogain(gspca_dev);
 	sethvflip(gspca_dev);
 
 	/* only resolution 640x480 is supported for pac7302 */
 
 	sd->sof_read = 0;
-	sd->autogain_ignore_frames = 0;
-	atomic_set(&sd->avg_lum, -1);
+	atomic_set(&sd->avg_lum, 270 + sd->ctrls[BRIGHTNESS].val);
 
 	/* start stream */
 	reg_w(gspca_dev, 0xff, 0x01);
@@ -751,8 +729,10 @@
 	reg_w(gspca_dev, 0x78, 0x40);
 }
 
-/* Include pac common sof detection functions */
-#include "pac_common.h"
+/* !! coarse_grained_expo_autogain is not used !! */
+#define exp_too_low_cnt flags
+#define exp_too_high_cnt sof_read
+#include "autogain_functions.h"
 
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
@@ -761,65 +741,44 @@
 	int desired_lum;
 	const int deadzone = 30;
 
-	if (avg_lum == -1)
+	if (sd->autogain_ignore_frames < 0)
 		return;
 
-	desired_lum = 270 + sd->brightness;
-
-	if (sd->autogain_ignore_frames > 0)
+	if (sd->autogain_ignore_frames > 0) {
 		sd->autogain_ignore_frames--;
-	else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
-			deadzone, GAIN_KNEE, EXPOSURE_KNEE))
+	} else {
+		desired_lum = 270 + sd->ctrls[BRIGHTNESS].val;
+
+		auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
+				deadzone, GAIN_KNEE, EXPOSURE_KNEE);
 		sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
+	}
 }
 
-/* JPEG header, part 1 */
-static const unsigned char pac_jpeg_header1[] = {
-  0xff, 0xd8,		/* SOI: Start of Image */
+/* JPEG header */
+static const u8 jpeg_header[] = {
+	0xff, 0xd8,	/* SOI: Start of Image */
 
-  0xff, 0xc0,		/* SOF0: Start of Frame (Baseline DCT) */
-  0x00, 0x11,		/* length = 17 bytes (including this length field) */
-  0x08			/* Precision: 8 */
-  /* 2 bytes is placed here: number of image lines */
-  /* 2 bytes is placed here: samples per line */
+	0xff, 0xc0,	/* SOF0: Start of Frame (Baseline DCT) */
+	0x00, 0x11,	/* length = 17 bytes (including this length field) */
+	0x08,		/* Precision: 8 */
+	0x02, 0x80,	/* height = 640 (image rotated) */
+	0x01, 0xe0,	/* width = 480 */
+	0x03,		/* Number of image components: 3 */
+	0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
+	0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
+	0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
+
+	0xff, 0xda,	/* SOS: Start Of Scan */
+	0x00, 0x0c,	/* length = 12 bytes (including this length field) */
+	0x03,		/* number of components: 3 */
+	0x01, 0x00,	/* selector 1, table 0x00 */
+	0x02, 0x11,	/* selector 2, table 0x11 */
+	0x03, 0x11,	/* selector 3, table 0x11 */
+	0x00, 0x3f,	/* Spectral selection: 0 .. 63 */
+	0x00		/* Successive approximation: 0 */
 };
 
-/* JPEG header, continued */
-static const unsigned char pac_jpeg_header2[] = {
-  0x03,			/* Number of image components: 3 */
-  0x01, 0x21, 0x00,	/* ID=1, Subsampling 1x1, Quantization table: 0 */
-  0x02, 0x11, 0x01,	/* ID=2, Subsampling 2x1, Quantization table: 1 */
-  0x03, 0x11, 0x01,	/* ID=3, Subsampling 2x1, Quantization table: 1 */
-
-  0xff, 0xda,		/* SOS: Start Of Scan */
-  0x00, 0x0c,		/* length = 12 bytes (including this length field) */
-  0x03,			/* number of components: 3 */
-  0x01, 0x00,		/* selector 1, table 0x00 */
-  0x02, 0x11,		/* selector 2, table 0x11 */
-  0x03, 0x11,		/* selector 3, table 0x11 */
-  0x00, 0x3f,		/* Spectral selection: 0 .. 63 */
-  0x00			/* Successive approximation: 0 */
-};
-
-static void pac_start_frame(struct gspca_dev *gspca_dev,
-		__u16 lines, __u16 samples_per_line)
-{
-	unsigned char tmpbuf[4];
-
-	gspca_frame_add(gspca_dev, FIRST_PACKET,
-		pac_jpeg_header1, sizeof(pac_jpeg_header1));
-
-	tmpbuf[0] = lines >> 8;
-	tmpbuf[1] = lines & 0xff;
-	tmpbuf[2] = samples_per_line >> 8;
-	tmpbuf[3] = samples_per_line & 0xff;
-
-	gspca_frame_add(gspca_dev, INTER_PACKET,
-		tmpbuf, sizeof(tmpbuf));
-	gspca_frame_add(gspca_dev, INTER_PACKET,
-		pac_jpeg_header2, sizeof(pac_jpeg_header2));
-}
-
 /* this function is run at interrupt level */
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			u8 *data,			/* isoc packet */
@@ -827,7 +786,7 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 *image;
-	unsigned char *sof;
+	u8 *sof;
 
 	sof = pac_find_sof(&sd->sof_read, data, len);
 	if (sof) {
@@ -864,234 +823,21 @@
 				n >= lum_offset)
 			atomic_set(&sd->avg_lum, data[-lum_offset] +
 						data[-lum_offset + 1]);
-		else
-			atomic_set(&sd->avg_lum, -1);
 
 		/* Start the new frame with the jpeg header */
 		/* The PAC7302 has the image rotated 90 degrees */
-		pac_start_frame(gspca_dev,
-			gspca_dev->width, gspca_dev->height);
+		gspca_frame_add(gspca_dev, FIRST_PACKET,
+				jpeg_header, sizeof jpeg_header);
 	}
 	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->brightness = val;
-	if (gspca_dev->streaming)
-		setbrightcont(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->brightness;
-	return 0;
-}
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->contrast = val;
-	if (gspca_dev->streaming)
-		setbrightcont(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->contrast;
-	return 0;
-}
-
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->colors = val;
-	if (gspca_dev->streaming)
-		setcolors(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->colors;
-	return 0;
-}
-
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->white_balance = val;
-	if (gspca_dev->streaming)
-		setwhitebalance(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->white_balance;
-	return 0;
-}
-
-static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->red_balance = val;
-	if (gspca_dev->streaming)
-		setredbalance(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->red_balance;
-	return 0;
-}
-
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->blue_balance = val;
-	if (gspca_dev->streaming)
-		setbluebalance(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->blue_balance;
-	return 0;
-}
-
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->gain = val;
-	if (gspca_dev->streaming)
-		setgain(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->gain;
-	return 0;
-}
-
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->exposure = val;
-	if (gspca_dev->streaming)
-		setexposure(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->exposure;
-	return 0;
-}
-
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->autogain = val;
-	/* when switching to autogain set defaults to make sure
-	   we are on a valid point of the autogain gain /
-	   exposure knee graph, and give this change time to
-	   take effect before doing autogain. */
-	if (sd->autogain) {
-		sd->exposure = EXPOSURE_DEF;
-		sd->gain = GAIN_DEF;
-		if (gspca_dev->streaming) {
-			sd->autogain_ignore_frames =
-				PAC_AUTOGAIN_IGNORE_FRAMES;
-			setexposure(gspca_dev);
-			setgain(gspca_dev);
-		}
-	}
-
-	return gspca_dev->usb_err;
-}
-
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->autogain;
-	return 0;
-}
-
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->hflip = val;
-	if (gspca_dev->streaming)
-		sethvflip(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->hflip;
-	return 0;
-}
-
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->vflip = val;
-	if (gspca_dev->streaming)
-		sethvflip(gspca_dev);
-	return gspca_dev->usb_err;
-}
-
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	*val = sd->vflip;
-	return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
 			struct v4l2_dbg_register *reg)
 {
-	__u8 index;
-	__u8 value;
+	u8 index;
+	u8 value;
 
 	/* reg->reg: bit0..15: reserved for register index (wIndex is 16bit
 			       long on the USB bus)
@@ -1103,8 +849,8 @@
 	) {
 		/* Currently writing to page 0 is only supported. */
 		/* reg_w() only supports 8bit index */
-		index = reg->reg & 0x000000ff;
-		value = reg->val & 0x000000ff;
+		index = reg->reg;
+		value = reg->val;
 
 		/* Note that there shall be no access to other page
 		   by any other function between the page swith and
@@ -1165,7 +911,7 @@
 
 /* sub-driver description for pac7302 */
 static const struct sd_desc sd_desc = {
-	.name = MODULE_NAME,
+	.name = KBUILD_MODNAME,
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
@@ -1187,6 +933,7 @@
 /* -- module initialisation -- */
 static const struct usb_device_id device_table[] = {
 	{USB_DEVICE(0x06f8, 0x3009)},
+	{USB_DEVICE(0x06f8, 0x301b)},
 	{USB_DEVICE(0x093a, 0x2620)},
 	{USB_DEVICE(0x093a, 0x2621)},
 	{USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
@@ -1211,7 +958,7 @@
 }
 
 static struct usb_driver sd_driver = {
-	.name = MODULE_NAME,
+	.name = KBUILD_MODNAME,
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 9e198b4..7e71aa2 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -1,5 +1,7 @@
 /*
  *	Sonix sn9c201 sn9c202 library
+ *
+ * Copyright (C) 2012 Jean-Francois Moine <http://moinejf.free.fr>
  *	Copyright (C) 2008-2009 microdia project <microdia@googlegroups.com>
  *	Copyright (C) 2009 Brian Johnson <brijohn@gmail.com>
  *
@@ -33,8 +35,6 @@
 MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-#define MODULE_NAME "sn9c20x"
-
 /*
  * Pixel format private data
  */
@@ -66,10 +66,37 @@
 #define LED_REVERSE	0x2 /* some cameras unset gpio to turn on leds */
 #define FLIP_DETECT	0x4
 
+enum e_ctrl {
+	BRIGHTNESS,
+	CONTRAST,
+	SATURATION,
+	HUE,
+	GAMMA,
+	BLUE,
+	RED,
+	VFLIP,
+	HFLIP,
+	EXPOSURE,
+	GAIN,
+	AUTOGAIN,
+	QUALITY,
+	NCTRLS		/* number of controls */
+};
+
 /* specific webcam descriptor */
 struct sd {
 	struct gspca_dev gspca_dev;
 
+	struct gspca_ctrl ctrls[NCTRLS];
+
+	struct work_struct work;
+	struct workqueue_struct *work_thread;
+
+	u32 pktsz;			/* (used by pkt_scan) */
+	u16 npkt;
+	s8 nchg;
+	u8 fmt;				/* (used for JPEG QTAB update */
+
 #define MIN_AVG_LUM 80
 #define MAX_AVG_LUM 130
 	atomic_t avg_lum;
@@ -77,31 +104,18 @@
 	u8 older_step;
 	u8 exposure_step;
 
-	u8 brightness;
-	u8 contrast;
-	u8 saturation;
-	s16 hue;
-	u8 gamma;
-	u8 red;
-	u8 blue;
-
-	u8 hflip;
-	u8 vflip;
-	u8 gain;
-	u16 exposure;
-	u8 auto_exposure;
-
 	u8 i2c_addr;
 	u8 sensor;
 	u8 hstart;
 	u8 vstart;
 
 	u8 jpeg_hdr[JPEG_HDR_SZ];
-	u8 quality;
 
 	u8 flags;
 };
 
+static void qual_upd(struct work_struct *work);
+
 struct i2c_reg_u8 {
 	u8 reg;
 	u8 val;
@@ -112,31 +126,6 @@
 	u16 val;
 };
 
-static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_sethue(struct gspca_dev *gspca_dev, s32 val);
-static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val);
-static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setgain(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val);
-
 static const struct dmi_system_id flip_dmi_table[] = {
 	{
 		.ident = "MSI MS-1034",
@@ -177,9 +166,16 @@
 	{}
 };
 
-static const struct ctrl sd_ctrls[] = {
-	{
-#define BRIGHTNESS_IDX 0
+static void set_cmatrix(struct gspca_dev *gspca_dev);
+static void set_gamma(struct gspca_dev *gspca_dev);
+static void set_redblue(struct gspca_dev *gspca_dev);
+static void set_hvflip(struct gspca_dev *gspca_dev);
+static void set_exposure(struct gspca_dev *gspca_dev);
+static void set_gain(struct gspca_dev *gspca_dev);
+static void set_quality(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] = {
 	    {
 		.id      = V4L2_CID_BRIGHTNESS,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
@@ -187,14 +183,11 @@
 		.minimum = 0,
 		.maximum = 0xff,
 		.step    = 1,
-#define BRIGHTNESS_DEFAULT 0x7f
-		.default_value = BRIGHTNESS_DEFAULT,
+		.default_value = 0x7f
 	    },
-	    .set = sd_setbrightness,
-	    .get = sd_getbrightness,
+	    .set_control = set_cmatrix
 	},
-	{
-#define CONTRAST_IDX 1
+[CONTRAST] = {
 	    {
 		.id      = V4L2_CID_CONTRAST,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
@@ -202,14 +195,11 @@
 		.minimum = 0,
 		.maximum = 0xff,
 		.step    = 1,
-#define CONTRAST_DEFAULT 0x7f
-		.default_value = CONTRAST_DEFAULT,
+		.default_value = 0x7f
 	    },
-	    .set = sd_setcontrast,
-	    .get = sd_getcontrast,
+	    .set_control = set_cmatrix
 	},
-	{
-#define SATURATION_IDX 2
+[SATURATION] = {
 	    {
 		.id      = V4L2_CID_SATURATION,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
@@ -217,14 +207,11 @@
 		.minimum = 0,
 		.maximum = 0xff,
 		.step    = 1,
-#define SATURATION_DEFAULT 0x7f
-		.default_value = SATURATION_DEFAULT,
+		.default_value = 0x7f
 	    },
-	    .set = sd_setsaturation,
-	    .get = sd_getsaturation,
+	    .set_control = set_cmatrix
 	},
-	{
-#define HUE_IDX 3
+[HUE] = {
 	    {
 		.id      = V4L2_CID_HUE,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
@@ -232,14 +219,11 @@
 		.minimum = -180,
 		.maximum = 180,
 		.step    = 1,
-#define HUE_DEFAULT 0
-		.default_value = HUE_DEFAULT,
+		.default_value = 0
 	    },
-	    .set = sd_sethue,
-	    .get = sd_gethue,
+	    .set_control = set_cmatrix
 	},
-	{
-#define GAMMA_IDX 4
+[GAMMA] = {
 	    {
 		.id      = V4L2_CID_GAMMA,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
@@ -247,14 +231,11 @@
 		.minimum = 0,
 		.maximum = 0xff,
 		.step    = 1,
-#define GAMMA_DEFAULT 0x10
-		.default_value = GAMMA_DEFAULT,
+		.default_value = 0x10
 	    },
-	    .set = sd_setgamma,
-	    .get = sd_getgamma,
+	    .set_control = set_gamma
 	},
-	{
-#define BLUE_IDX 5
+[BLUE] = {
 	    {
 		.id	 = V4L2_CID_BLUE_BALANCE,
 		.type	 = V4L2_CTRL_TYPE_INTEGER,
@@ -262,14 +243,11 @@
 		.minimum = 0,
 		.maximum = 0x7f,
 		.step	 = 1,
-#define BLUE_DEFAULT 0x28
-		.default_value = BLUE_DEFAULT,
+		.default_value = 0x28
 	    },
-	    .set = sd_setbluebalance,
-	    .get = sd_getbluebalance,
+	    .set_control = set_redblue
 	},
-	{
-#define RED_IDX 6
+[RED] = {
 	    {
 		.id	 = V4L2_CID_RED_BALANCE,
 		.type	 = V4L2_CTRL_TYPE_INTEGER,
@@ -277,14 +255,11 @@
 		.minimum = 0,
 		.maximum = 0x7f,
 		.step	 = 1,
-#define RED_DEFAULT 0x28
-		.default_value = RED_DEFAULT,
+		.default_value = 0x28
 	    },
-	    .set = sd_setredbalance,
-	    .get = sd_getredbalance,
+	    .set_control = set_redblue
 	},
-	{
-#define HFLIP_IDX 7
+[HFLIP] = {
 	    {
 		.id      = V4L2_CID_HFLIP,
 		.type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -292,14 +267,11 @@
 		.minimum = 0,
 		.maximum = 1,
 		.step    = 1,
-#define HFLIP_DEFAULT 0
-		.default_value = HFLIP_DEFAULT,
+		.default_value = 0,
 	    },
-	    .set = sd_sethflip,
-	    .get = sd_gethflip,
+	    .set_control = set_hvflip
 	},
-	{
-#define VFLIP_IDX 8
+[VFLIP] = {
 	    {
 		.id      = V4L2_CID_VFLIP,
 		.type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -307,14 +279,11 @@
 		.minimum = 0,
 		.maximum = 1,
 		.step    = 1,
-#define VFLIP_DEFAULT 0
-		.default_value = VFLIP_DEFAULT,
+		.default_value = 0,
 	    },
-	    .set = sd_setvflip,
-	    .get = sd_getvflip,
+	    .set_control = set_hvflip
 	},
-	{
-#define EXPOSURE_IDX 9
+[EXPOSURE] = {
 	    {
 		.id      = V4L2_CID_EXPOSURE,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
@@ -322,14 +291,11 @@
 		.minimum = 0,
 		.maximum = 0x1780,
 		.step    = 1,
-#define EXPOSURE_DEFAULT 0x33
-		.default_value = EXPOSURE_DEFAULT,
+		.default_value = 0x33,
 	    },
-	    .set = sd_setexposure,
-	    .get = sd_getexposure,
+	    .set_control = set_exposure
 	},
-	{
-#define GAIN_IDX 10
+[GAIN] = {
 	    {
 		.id      = V4L2_CID_GAIN,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
@@ -337,14 +303,11 @@
 		.minimum = 0,
 		.maximum = 28,
 		.step    = 1,
-#define GAIN_DEFAULT 0x00
-		.default_value = GAIN_DEFAULT,
+		.default_value = 0,
 	    },
-	    .set = sd_setgain,
-	    .get = sd_getgain,
+	    .set_control = set_gain
 	},
-	{
-#define AUTOGAIN_IDX 11
+[AUTOGAIN] = {
 	    {
 		.id      = V4L2_CID_AUTOGAIN,
 		.type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -352,11 +315,23 @@
 		.minimum = 0,
 		.maximum = 1,
 		.step    = 1,
-#define AUTO_EXPOSURE_DEFAULT 1
-		.default_value = AUTO_EXPOSURE_DEFAULT,
+		.default_value = 1,
 	    },
-	    .set = sd_setautoexposure,
-	    .get = sd_getautoexposure,
+	},
+[QUALITY] = {
+	    {
+		.id      = V4L2_CID_JPEG_COMPRESSION_QUALITY,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Compression Quality",
+#define QUALITY_MIN 50
+#define QUALITY_MAX 90
+#define QUALITY_DEF 80
+		.minimum = QUALITY_MIN,
+		.maximum = QUALITY_MAX,
+		.step    = 1,
+		.default_value = QUALITY_DEF,
+	    },
+	    .set_control = set_quality
 	},
 };
 
@@ -876,7 +851,7 @@
 };
 
 static struct i2c_reg_u8 soi968_init[] = {
-	{0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f},
+	{0x0c, 0x00}, {0x0f, 0x1f},
 	{0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
 	{0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
 	{0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
@@ -902,7 +877,7 @@
 };
 
 static struct i2c_reg_u8 ov7670_init[] = {
-	{0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
+	{0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
 	{0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
 	{0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
 	{0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
@@ -959,7 +934,7 @@
 };
 
 static struct i2c_reg_u8 ov9650_init[] = {
-	{0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78},
+	{0x00, 0x00}, {0x01, 0x78},
 	{0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
 	{0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
 	{0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
@@ -989,7 +964,7 @@
 };
 
 static struct i2c_reg_u8 ov9655_init[] = {
-	{0x12, 0x80}, {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
+	{0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
 	{0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
 	{0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
 	{0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57},
@@ -1112,10 +1087,13 @@
 	{0x23, 0x09}, {0x01, 0x08},
 };
 
-static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
+static void reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
 {
 	struct usb_device *dev = gspca_dev->dev;
 	int result;
+
+	if (gspca_dev->usb_err < 0)
+		return;
 	result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
 			0x00,
 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -1125,17 +1103,19 @@
 			length,
 			500);
 	if (unlikely(result < 0 || result != length)) {
-		pr_err("Read register failed 0x%02X\n", reg);
-		return -EIO;
+		pr_err("Read register %02x failed %d\n", reg, result);
+		gspca_dev->usb_err = result;
 	}
-	return 0;
 }
 
-static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
+static void reg_w(struct gspca_dev *gspca_dev, u16 reg,
 		 const u8 *buffer, int length)
 {
 	struct usb_device *dev = gspca_dev->dev;
 	int result;
+
+	if (gspca_dev->usb_err < 0)
+		return;
 	memcpy(gspca_dev->usb_buf, buffer, length);
 	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 			0x08,
@@ -1146,38 +1126,41 @@
 			length,
 			500);
 	if (unlikely(result < 0 || result != length)) {
-		pr_err("Write register failed index 0x%02X\n", reg);
-		return -EIO;
+		pr_err("Write register %02x failed %d\n", reg, result);
+		gspca_dev->usb_err = result;
 	}
-	return 0;
 }
 
-static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
+static void reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
 {
-	u8 data[1] = {value};
-	return reg_w(gspca_dev, reg, data, 1);
+	reg_w(gspca_dev, reg, &value, 1);
 }
 
-static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
+static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
 {
 	int i;
+
 	reg_w(gspca_dev, 0x10c0, buffer, 8);
 	for (i = 0; i < 5; i++) {
 		reg_r(gspca_dev, 0x10c0, 1);
+		if (gspca_dev->usb_err < 0)
+			return;
 		if (gspca_dev->usb_buf[0] & 0x04) {
-			if (gspca_dev->usb_buf[0] & 0x08)
-				return -EIO;
-			return 0;
+			if (gspca_dev->usb_buf[0] & 0x08) {
+				pr_err("i2c_w error\n");
+				gspca_dev->usb_err = -EIO;
+			}
+			return;
 		}
-		msleep(1);
+		msleep(10);
 	}
-	return -EIO;
+	pr_err("i2c_w reg %02x no response\n", buffer[2]);
+/*	gspca_dev->usb_err = -EIO;	fixme: may occur */
 }
 
-static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
+static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-
 	u8 row[8];
 
 	/*
@@ -1193,10 +1176,19 @@
 	row[6] = 0x00;
 	row[7] = 0x10;
 
-	return i2c_w(gspca_dev, row);
+	i2c_w(gspca_dev, row);
 }
 
-static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
+static void i2c_w1_buf(struct gspca_dev *gspca_dev,
+			struct i2c_reg_u8 *buf, int sz)
+{
+	while (--sz >= 0) {
+		i2c_w1(gspca_dev, buf->reg, buf->val);
+		buf++;
+	}
+}
+
+static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 row[8];
@@ -1208,16 +1200,25 @@
 	row[0] = 0x81 | (3 << 4);
 	row[1] = sd->i2c_addr;
 	row[2] = reg;
-	row[3] = (val >> 8) & 0xff;
-	row[4] = val & 0xff;
+	row[3] = val >> 8;
+	row[4] = val;
 	row[5] = 0x00;
 	row[6] = 0x00;
 	row[7] = 0x10;
 
-	return i2c_w(gspca_dev, row);
+	i2c_w(gspca_dev, row);
 }
 
-static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
+static void i2c_w2_buf(struct gspca_dev *gspca_dev,
+			struct i2c_reg_u16 *buf, int sz)
+{
+	while (--sz >= 0) {
+		i2c_w2(gspca_dev, buf->reg, buf->val);
+		buf++;
+	}
+}
+
+static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 row[8];
@@ -1230,19 +1231,15 @@
 	row[5] = 0;
 	row[6] = 0;
 	row[7] = 0x10;
-	if (i2c_w(gspca_dev, row) < 0)
-		return -EIO;
+	i2c_w(gspca_dev, row);
 	row[0] = 0x81 | (1 << 4) | 0x02;
 	row[2] = 0;
-	if (i2c_w(gspca_dev, row) < 0)
-		return -EIO;
-	if (reg_r(gspca_dev, 0x10c2, 5) < 0)
-		return -EIO;
+	i2c_w(gspca_dev, row);
+	reg_r(gspca_dev, 0x10c2, 5);
 	*val = gspca_dev->usb_buf[4];
-	return 0;
 }
 
-static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
+static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 row[8];
@@ -1255,233 +1252,204 @@
 	row[5] = 0;
 	row[6] = 0;
 	row[7] = 0x10;
-	if (i2c_w(gspca_dev, row) < 0)
-		return -EIO;
+	i2c_w(gspca_dev, row);
 	row[0] = 0x81 | (2 << 4) | 0x02;
 	row[2] = 0;
-	if (i2c_w(gspca_dev, row) < 0)
-		return -EIO;
-	if (reg_r(gspca_dev, 0x10c2, 5) < 0)
-		return -EIO;
+	i2c_w(gspca_dev, row);
+	reg_r(gspca_dev, 0x10c2, 5);
 	*val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
-	return 0;
 }
 
-static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
+static void ov9650_init_sensor(struct gspca_dev *gspca_dev)
 {
-	int i;
 	u16 id;
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	if (i2c_r2(gspca_dev, 0x1c, &id) < 0)
-		return -EINVAL;
+	i2c_r2(gspca_dev, 0x1c, &id);
+	if (gspca_dev->usb_err < 0)
+		return;
 
 	if (id != 0x7fa2) {
 		pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id);
-		return -ENODEV;
+		gspca_dev->usb_err = -ENODEV;
+		return;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
-		if (i2c_w1(gspca_dev, ov9650_init[i].reg,
-				ov9650_init[i].val) < 0) {
-			pr_err("OV9650 sensor initialization failed\n");
-			return -ENODEV;
-		}
-	}
+	i2c_w1(gspca_dev, 0x12, 0x80);		/* sensor reset */
+	msleep(200);
+	i2c_w1_buf(gspca_dev, ov9650_init, ARRAY_SIZE(ov9650_init));
+	if (gspca_dev->usb_err < 0)
+		pr_err("OV9650 sensor initialization failed\n");
 	sd->hstart = 1;
 	sd->vstart = 7;
-	return 0;
 }
 
-static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
+static void ov9655_init_sensor(struct gspca_dev *gspca_dev)
 {
-	int i;
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
-		if (i2c_w1(gspca_dev, ov9655_init[i].reg,
-				ov9655_init[i].val) < 0) {
-			pr_err("OV9655 sensor initialization failed\n");
-			return -ENODEV;
-		}
-	}
+	i2c_w1(gspca_dev, 0x12, 0x80);		/* sensor reset */
+	msleep(200);
+	i2c_w1_buf(gspca_dev, ov9655_init, ARRAY_SIZE(ov9655_init));
+	if (gspca_dev->usb_err < 0)
+		pr_err("OV9655 sensor initialization failed\n");
+
 	/* disable hflip and vflip */
-	gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+	gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
 	sd->hstart = 1;
 	sd->vstart = 2;
-	return 0;
 }
 
-static int soi968_init_sensor(struct gspca_dev *gspca_dev)
+static void soi968_init_sensor(struct gspca_dev *gspca_dev)
 {
-	int i;
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
-		if (i2c_w1(gspca_dev, soi968_init[i].reg,
-				soi968_init[i].val) < 0) {
-			pr_err("SOI968 sensor initialization failed\n");
-			return -ENODEV;
-		}
-	}
+	i2c_w1(gspca_dev, 0x12, 0x80);		/* sensor reset */
+	msleep(200);
+	i2c_w1_buf(gspca_dev, soi968_init, ARRAY_SIZE(soi968_init));
+	if (gspca_dev->usb_err < 0)
+		pr_err("SOI968 sensor initialization failed\n");
+
 	/* disable hflip and vflip */
-	gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX)
-				| (1 << EXPOSURE_IDX);
+	gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP)
+				| (1 << EXPOSURE);
 	sd->hstart = 60;
 	sd->vstart = 11;
-	return 0;
 }
 
-static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
+static void ov7660_init_sensor(struct gspca_dev *gspca_dev)
 {
-	int i;
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
-		if (i2c_w1(gspca_dev, ov7660_init[i].reg,
-				ov7660_init[i].val) < 0) {
-			pr_err("OV7660 sensor initialization failed\n");
-			return -ENODEV;
-		}
-	}
+	i2c_w1(gspca_dev, 0x12, 0x80);		/* sensor reset */
+	msleep(200);
+	i2c_w1_buf(gspca_dev, ov7660_init, ARRAY_SIZE(ov7660_init));
+	if (gspca_dev->usb_err < 0)
+		pr_err("OV7660 sensor initialization failed\n");
 	sd->hstart = 3;
 	sd->vstart = 3;
-	return 0;
 }
 
-static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
+static void ov7670_init_sensor(struct gspca_dev *gspca_dev)
 {
-	int i;
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
-		if (i2c_w1(gspca_dev, ov7670_init[i].reg,
-				ov7670_init[i].val) < 0) {
-			pr_err("OV7670 sensor initialization failed\n");
-			return -ENODEV;
-		}
-	}
+	i2c_w1(gspca_dev, 0x12, 0x80);		/* sensor reset */
+	msleep(200);
+	i2c_w1_buf(gspca_dev, ov7670_init, ARRAY_SIZE(ov7670_init));
+	if (gspca_dev->usb_err < 0)
+		pr_err("OV7670 sensor initialization failed\n");
+
 	/* disable hflip and vflip */
-	gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+	gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
 	sd->hstart = 0;
 	sd->vstart = 1;
-	return 0;
 }
 
-static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9v_init_sensor(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	int i;
 	u16 value;
-	int ret;
 
 	sd->i2c_addr = 0x5d;
-	ret = i2c_r2(gspca_dev, 0xff, &value);
-	if ((ret == 0) && (value == 0x8243)) {
-		for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
-			if (i2c_w2(gspca_dev, mt9v011_init[i].reg,
-					mt9v011_init[i].val) < 0) {
-				pr_err("MT9V011 sensor initialization failed\n");
-				return -ENODEV;
-			}
+	i2c_r2(gspca_dev, 0xff, &value);
+	if (gspca_dev->usb_err >= 0
+	 && value == 0x8243) {
+		i2c_w2_buf(gspca_dev, mt9v011_init, ARRAY_SIZE(mt9v011_init));
+		if (gspca_dev->usb_err < 0) {
+			pr_err("MT9V011 sensor initialization failed\n");
+			return;
 		}
 		sd->hstart = 2;
 		sd->vstart = 2;
 		sd->sensor = SENSOR_MT9V011;
 		pr_info("MT9V011 sensor detected\n");
-		return 0;
+		return;
 	}
 
+	gspca_dev->usb_err = 0;
 	sd->i2c_addr = 0x5c;
 	i2c_w2(gspca_dev, 0x01, 0x0004);
-	ret = i2c_r2(gspca_dev, 0xff, &value);
-	if ((ret == 0) && (value == 0x823a)) {
-		for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
-			if (i2c_w2(gspca_dev, mt9v111_init[i].reg,
-					mt9v111_init[i].val) < 0) {
-				pr_err("MT9V111 sensor initialization failed\n");
-				return -ENODEV;
-			}
+	i2c_r2(gspca_dev, 0xff, &value);
+	if (gspca_dev->usb_err >= 0
+	 && value == 0x823a) {
+		i2c_w2_buf(gspca_dev, mt9v111_init, ARRAY_SIZE(mt9v111_init));
+		if (gspca_dev->usb_err < 0) {
+			pr_err("MT9V111 sensor initialization failed\n");
+			return;
 		}
-		gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX)
-					| (1 << AUTOGAIN_IDX)
-					| (1 << GAIN_IDX);
+		gspca_dev->ctrl_dis = (1 << EXPOSURE)
+					| (1 << AUTOGAIN)
+					| (1 << GAIN);
 		sd->hstart = 2;
 		sd->vstart = 2;
 		sd->sensor = SENSOR_MT9V111;
 		pr_info("MT9V111 sensor detected\n");
-		return 0;
+		return;
 	}
 
+	gspca_dev->usb_err = 0;
 	sd->i2c_addr = 0x5d;
-	ret = i2c_w2(gspca_dev, 0xf0, 0x0000);
-	if (ret < 0) {
+	i2c_w2(gspca_dev, 0xf0, 0x0000);
+	if (gspca_dev->usb_err < 0) {
+		gspca_dev->usb_err = 0;
 		sd->i2c_addr = 0x48;
 		i2c_w2(gspca_dev, 0xf0, 0x0000);
 	}
-	ret = i2c_r2(gspca_dev, 0x00, &value);
-	if ((ret == 0) && (value == 0x1229)) {
-		for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
-			if (i2c_w2(gspca_dev, mt9v112_init[i].reg,
-					mt9v112_init[i].val) < 0) {
-				pr_err("MT9V112 sensor initialization failed\n");
-				return -ENODEV;
-			}
+	i2c_r2(gspca_dev, 0x00, &value);
+	if (gspca_dev->usb_err >= 0
+	 && value == 0x1229) {
+		i2c_w2_buf(gspca_dev, mt9v112_init, ARRAY_SIZE(mt9v112_init));
+		if (gspca_dev->usb_err < 0) {
+			pr_err("MT9V112 sensor initialization failed\n");
+			return;
 		}
 		sd->hstart = 6;
 		sd->vstart = 2;
 		sd->sensor = SENSOR_MT9V112;
 		pr_info("MT9V112 sensor detected\n");
-		return 0;
+		return;
 	}
 
-	return -ENODEV;
+	gspca_dev->usb_err = -ENODEV;
 }
 
-static int mt9m112_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9m112_init_sensor(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	int i;
-	for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) {
-		if (i2c_w2(gspca_dev, mt9m112_init[i].reg,
-				mt9m112_init[i].val) < 0) {
-			pr_err("MT9M112 sensor initialization failed\n");
-			return -ENODEV;
-		}
-	}
-	gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
-				| (1 << GAIN_IDX);
+
+	i2c_w2_buf(gspca_dev, mt9m112_init, ARRAY_SIZE(mt9m112_init));
+	if (gspca_dev->usb_err < 0)
+		pr_err("MT9M112 sensor initialization failed\n");
+
+	gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
+				| (1 << GAIN);
 	sd->hstart = 0;
 	sd->vstart = 2;
-	return 0;
 }
 
-static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9m111_init_sensor(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	int i;
-	for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
-		if (i2c_w2(gspca_dev, mt9m111_init[i].reg,
-				mt9m111_init[i].val) < 0) {
-			pr_err("MT9M111 sensor initialization failed\n");
-			return -ENODEV;
-		}
-	}
-	gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
-				| (1 << GAIN_IDX);
+
+	i2c_w2_buf(gspca_dev, mt9m111_init, ARRAY_SIZE(mt9m111_init));
+	if (gspca_dev->usb_err < 0)
+		pr_err("MT9M111 sensor initialization failed\n");
+
+	gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
+				| (1 << GAIN);
 	sd->hstart = 0;
 	sd->vstart = 2;
-	return 0;
 }
 
-static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9m001_init_sensor(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	int i;
 	u16 id;
 
-	if (i2c_r2(gspca_dev, 0x00, &id) < 0)
-		return -EINVAL;
+	i2c_r2(gspca_dev, 0x00, &id);
+	if (gspca_dev->usb_err < 0)
+		return;
 
 	/* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
 	switch (id) {
@@ -1494,85 +1462,78 @@
 		break;
 	default:
 		pr_err("No MT9M001 chip detected, ID = %x\n\n", id);
-		return -ENODEV;
+		gspca_dev->usb_err = -ENODEV;
+		return;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
-		if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
-				mt9m001_init[i].val) < 0) {
-			pr_err("MT9M001 sensor initialization failed\n");
-			return -ENODEV;
-		}
-	}
+	i2c_w2_buf(gspca_dev, mt9m001_init, ARRAY_SIZE(mt9m001_init));
+	if (gspca_dev->usb_err < 0)
+		pr_err("MT9M001 sensor initialization failed\n");
+
 	/* disable hflip and vflip */
-	gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+	gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
 	sd->hstart = 1;
 	sd->vstart = 1;
-	return 0;
 }
 
-static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
+static void hv7131r_init_sensor(struct gspca_dev *gspca_dev)
 {
-	int i;
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
-		if (i2c_w1(gspca_dev, hv7131r_init[i].reg,
-				hv7131r_init[i].val) < 0) {
-			pr_err("HV7131R Sensor initialization failed\n");
-			return -ENODEV;
-		}
-	}
+	i2c_w1_buf(gspca_dev, hv7131r_init, ARRAY_SIZE(hv7131r_init));
+	if (gspca_dev->usb_err < 0)
+		pr_err("HV7131R Sensor initialization failed\n");
+
 	sd->hstart = 0;
 	sd->vstart = 1;
-	return 0;
 }
 
-static int set_cmatrix(struct gspca_dev *gspca_dev)
+static void set_cmatrix(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	s32 hue_coord, hue_index = 180 + sd->hue;
+	int satur;
+	s32 hue_coord, hue_index = 180 + sd->ctrls[HUE].val;
 	u8 cmatrix[21];
 
 	memset(cmatrix, 0, sizeof cmatrix);
-	cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26;
+	cmatrix[2] = (sd->ctrls[CONTRAST].val * 0x25 / 0x100) + 0x26;
 	cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
 	cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
-	cmatrix[18] = sd->brightness - 0x80;
+	cmatrix[18] = sd->ctrls[BRIGHTNESS].val - 0x80;
 
-	hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8;
+	satur = sd->ctrls[SATURATION].val;
+	hue_coord = (hsv_red_x[hue_index] * satur) >> 8;
 	cmatrix[6] = hue_coord;
 	cmatrix[7] = (hue_coord >> 8) & 0x0f;
 
-	hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8;
+	hue_coord = (hsv_red_y[hue_index] * satur) >> 8;
 	cmatrix[8] = hue_coord;
 	cmatrix[9] = (hue_coord >> 8) & 0x0f;
 
-	hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8;
+	hue_coord = (hsv_green_x[hue_index] * satur) >> 8;
 	cmatrix[10] = hue_coord;
 	cmatrix[11] = (hue_coord >> 8) & 0x0f;
 
-	hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8;
+	hue_coord = (hsv_green_y[hue_index] * satur) >> 8;
 	cmatrix[12] = hue_coord;
 	cmatrix[13] = (hue_coord >> 8) & 0x0f;
 
-	hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8;
+	hue_coord = (hsv_blue_x[hue_index] * satur) >> 8;
 	cmatrix[14] = hue_coord;
 	cmatrix[15] = (hue_coord >> 8) & 0x0f;
 
-	hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8;
+	hue_coord = (hsv_blue_y[hue_index] * satur) >> 8;
 	cmatrix[16] = hue_coord;
 	cmatrix[17] = (hue_coord >> 8) & 0x0f;
 
-	return reg_w(gspca_dev, 0x10e1, cmatrix, 21);
+	reg_w(gspca_dev, 0x10e1, cmatrix, 21);
 }
 
-static int set_gamma(struct gspca_dev *gspca_dev)
+static void set_gamma(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 gamma[17];
-	u8 gval = sd->gamma * 0xb8 / 0x100;
-
+	u8 gval = sd->ctrls[GAMMA].val * 0xb8 / 0x100;
 
 	gamma[0] = 0x0a;
 	gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
@@ -1592,29 +1553,29 @@
 	gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
 	gamma[16] = 0xf5;
 
-	return reg_w(gspca_dev, 0x1190, gamma, 17);
+	reg_w(gspca_dev, 0x1190, gamma, 17);
 }
 
-static int set_redblue(struct gspca_dev *gspca_dev)
+static void set_redblue(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	reg_w1(gspca_dev, 0x118c, sd->red);
-	reg_w1(gspca_dev, 0x118f, sd->blue);
-	return 0;
+
+	reg_w1(gspca_dev, 0x118c, sd->ctrls[RED].val);
+	reg_w1(gspca_dev, 0x118f, sd->ctrls[BLUE].val);
 }
 
-static int set_hvflip(struct gspca_dev *gspca_dev)
+static void set_hvflip(struct gspca_dev *gspca_dev)
 {
 	u8 value, tslb, hflip, vflip;
 	u16 value2;
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
-		hflip = !sd->hflip;
-		vflip = !sd->vflip;
+		hflip = !sd->ctrls[HFLIP].val;
+		vflip = !sd->ctrls[VFLIP].val;
 	} else {
-		hflip = sd->hflip;
-		vflip = sd->vflip;
+		hflip = sd->ctrls[HFLIP].val;
+		vflip = sd->ctrls[VFLIP].val;
 	}
 
 	switch (sd->sensor) {
@@ -1625,8 +1586,9 @@
 		if (vflip) {
 			value |= 0x10;
 			sd->vstart = 2;
-		} else
+		} else {
 			sd->vstart = 3;
+		}
 		reg_w1(gspca_dev, 0x1182, sd->vstart);
 		i2c_w1(gspca_dev, 0x1e, value);
 		break;
@@ -1674,13 +1636,15 @@
 		i2c_w1(gspca_dev, 0x01, value);
 		break;
 	}
-	return 0;
 }
 
-static int set_exposure(struct gspca_dev *gspca_dev)
+static void set_exposure(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
+	int expo;
+
+	expo = sd->ctrls[EXPOSURE].val;
 	switch (sd->sensor) {
 	case SENSOR_OV7660:
 	case SENSOR_OV7670:
@@ -1688,35 +1652,37 @@
 	case SENSOR_OV9650:
 		exp[0] |= (3 << 4);
 		exp[2] = 0x2d;
-		exp[3] = sd->exposure & 0xff;
-		exp[4] = sd->exposure >> 8;
+		exp[3] = expo;
+		exp[4] = expo >> 8;
 		break;
 	case SENSOR_MT9M001:
 	case SENSOR_MT9V112:
 	case SENSOR_MT9V011:
 		exp[0] |= (3 << 4);
 		exp[2] = 0x09;
-		exp[3] = sd->exposure >> 8;
-		exp[4] = sd->exposure & 0xff;
+		exp[3] = expo >> 8;
+		exp[4] = expo;
 		break;
 	case SENSOR_HV7131R:
 		exp[0] |= (4 << 4);
 		exp[2] = 0x25;
-		exp[3] = (sd->exposure >> 5) & 0xff;
-		exp[4] = (sd->exposure << 3) & 0xff;
+		exp[3] = expo >> 5;
+		exp[4] = expo << 3;
 		exp[5] = 0;
 		break;
 	default:
-		return 0;
+		return;
 	}
 	i2c_w(gspca_dev, exp);
-	return 0;
 }
 
-static int set_gain(struct gspca_dev *gspca_dev)
+static void set_gain(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
+	int g;
+
+	g = sd->ctrls[GAIN].val;
 	switch (sd->sensor) {
 	case SENSOR_OV7660:
 	case SENSOR_OV7670:
@@ -1724,238 +1690,50 @@
 	case SENSOR_OV9655:
 	case SENSOR_OV9650:
 		gain[0] |= (2 << 4);
-		gain[3] = ov_gain[sd->gain];
+		gain[3] = ov_gain[g];
 		break;
 	case SENSOR_MT9V011:
 		gain[0] |= (3 << 4);
 		gain[2] = 0x35;
-		gain[3] = micron1_gain[sd->gain] >> 8;
-		gain[4] = micron1_gain[sd->gain] & 0xff;
+		gain[3] = micron1_gain[g] >> 8;
+		gain[4] = micron1_gain[g];
 		break;
 	case SENSOR_MT9V112:
 		gain[0] |= (3 << 4);
 		gain[2] = 0x2f;
-		gain[3] = micron1_gain[sd->gain] >> 8;
-		gain[4] = micron1_gain[sd->gain] & 0xff;
+		gain[3] = micron1_gain[g] >> 8;
+		gain[4] = micron1_gain[g];
 		break;
 	case SENSOR_MT9M001:
 		gain[0] |= (3 << 4);
 		gain[2] = 0x2f;
-		gain[3] = micron2_gain[sd->gain] >> 8;
-		gain[4] = micron2_gain[sd->gain] & 0xff;
+		gain[3] = micron2_gain[g] >> 8;
+		gain[4] = micron2_gain[g];
 		break;
 	case SENSOR_HV7131R:
 		gain[0] |= (2 << 4);
 		gain[2] = 0x30;
-		gain[3] = hv7131r_gain[sd->gain];
+		gain[3] = hv7131r_gain[g];
 		break;
 	default:
-		return 0;
+		return;
 	}
 	i2c_w(gspca_dev, gain);
-	return 0;
 }
 
-static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val)
+static void set_quality(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	sd->brightness = val;
-	if (gspca_dev->streaming)
-		return set_cmatrix(gspca_dev);
-	return 0;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	*val = sd->brightness;
-	return 0;
-}
-
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->contrast = val;
-	if (gspca_dev->streaming)
-		return set_cmatrix(gspca_dev);
-	return 0;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	*val = sd->contrast;
-	return 0;
-}
-
-static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->saturation = val;
-	if (gspca_dev->streaming)
-		return set_cmatrix(gspca_dev);
-	return 0;
-}
-
-static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	*val = sd->saturation;
-	return 0;
-}
-
-static int sd_sethue(struct gspca_dev *gspca_dev, s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->hue = val;
-	if (gspca_dev->streaming)
-		return set_cmatrix(gspca_dev);
-	return 0;
-}
-
-static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	*val = sd->hue;
-	return 0;
-}
-
-static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->gamma = val;
-	if (gspca_dev->streaming)
-		return set_gamma(gspca_dev);
-	return 0;
-}
-
-static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	*val = sd->gamma;
-	return 0;
-}
-
-static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->red = val;
-	if (gspca_dev->streaming)
-		return set_redblue(gspca_dev);
-	return 0;
-}
-
-static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	*val = sd->red;
-	return 0;
-}
-
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->blue = val;
-	if (gspca_dev->streaming)
-		return set_redblue(gspca_dev);
-	return 0;
-}
-
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	*val = sd->blue;
-	return 0;
-}
-
-static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->hflip = val;
-	if (gspca_dev->streaming)
-		return set_hvflip(gspca_dev);
-	return 0;
-}
-
-static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	*val = sd->hflip;
-	return 0;
-}
-
-static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->vflip = val;
-	if (gspca_dev->streaming)
-		return set_hvflip(gspca_dev);
-	return 0;
-}
-
-static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	*val = sd->vflip;
-	return 0;
-}
-
-static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->exposure = val;
-	if (gspca_dev->streaming)
-		return set_exposure(gspca_dev);
-	return 0;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	*val = sd->exposure;
-	return 0;
-}
-
-static int sd_setgain(struct gspca_dev *gspca_dev, s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->gain = val;
-	if (gspca_dev->streaming)
-		return set_gain(gspca_dev);
-	return 0;
-}
-
-static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	*val = sd->gain;
-	return 0;
-}
-
-static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	sd->auto_exposure = val;
-	return 0;
-}
-
-static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	*val = sd->auto_exposure;
-	return 0;
+	jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
+	reg_w1(gspca_dev, 0x1061, 0x01);	/* stop transfer */
+	reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */
+	reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
+	reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
+	reg_w1(gspca_dev, 0x1061, 0x03);	/* restart transfer */
+	reg_w1(gspca_dev, 0x10e0, sd->fmt);
+	sd->fmt ^= 0x0c;			/* invert QTAB use + write */
+	reg_w1(gspca_dev, 0x10e0, sd->fmt);
 }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -1963,28 +1741,26 @@
 			struct v4l2_dbg_register *reg)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+
 	switch (reg->match.type) {
 	case V4L2_CHIP_MATCH_HOST:
 		if (reg->match.addr != 0)
 			return -EINVAL;
 		if (reg->reg < 0x1000 || reg->reg > 0x11ff)
 			return -EINVAL;
-		if (reg_r(gspca_dev, reg->reg, 1) < 0)
-			return -EINVAL;
+		reg_r(gspca_dev, reg->reg, 1);
 		reg->val = gspca_dev->usb_buf[0];
-		return 0;
+		return gspca_dev->usb_err;
 	case V4L2_CHIP_MATCH_I2C_ADDR:
 		if (reg->match.addr != sd->i2c_addr)
 			return -EINVAL;
 		if (sd->sensor >= SENSOR_MT9V011 &&
 		    sd->sensor <= SENSOR_MT9M112) {
-			if (i2c_r2(gspca_dev, reg->reg, (u16 *)&reg->val) < 0)
-				return -EINVAL;
+			i2c_r2(gspca_dev, reg->reg, (u16 *) &reg->val);
 		} else {
-			if (i2c_r1(gspca_dev, reg->reg, (u8 *)&reg->val) < 0)
-				return -EINVAL;
+			i2c_r1(gspca_dev, reg->reg, (u8 *) &reg->val);
 		}
-		return 0;
+		return gspca_dev->usb_err;
 	}
 	return -EINVAL;
 }
@@ -1993,27 +1769,25 @@
 			struct v4l2_dbg_register *reg)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+
 	switch (reg->match.type) {
 	case V4L2_CHIP_MATCH_HOST:
 		if (reg->match.addr != 0)
 			return -EINVAL;
 		if (reg->reg < 0x1000 || reg->reg > 0x11ff)
 			return -EINVAL;
-		if (reg_w1(gspca_dev, reg->reg, reg->val) < 0)
-			return -EINVAL;
-		return 0;
+		reg_w1(gspca_dev, reg->reg, reg->val);
+		return gspca_dev->usb_err;
 	case V4L2_CHIP_MATCH_I2C_ADDR:
 		if (reg->match.addr != sd->i2c_addr)
 			return -EINVAL;
 		if (sd->sensor >= SENSOR_MT9V011 &&
 		    sd->sensor <= SENSOR_MT9M112) {
-			if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0)
-				return -EINVAL;
+			i2c_w2(gspca_dev, reg->reg, reg->val);
 		} else {
-			if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0)
-				return -EINVAL;
+			i2c_w1(gspca_dev, reg->reg, reg->val);
 		}
-		return 0;
+		return gspca_dev->usb_err;
 	}
 	return -EINVAL;
 }
@@ -2050,9 +1824,9 @@
 	cam = &gspca_dev->cam;
 	cam->needs_full_bandwidth = 1;
 
-	sd->sensor = (id->driver_info >> 8) & 0xff;
-	sd->i2c_addr = id->driver_info & 0xff;
-	sd->flags = (id->driver_info >> 16) & 0xff;
+	sd->sensor = id->driver_info >> 8;
+	sd->i2c_addr = id->driver_info;
+	sd->flags = id->driver_info >> 16;
 
 	switch (sd->sensor) {
 	case SENSOR_MT9M112:
@@ -2076,21 +1850,9 @@
 	sd->older_step = 0;
 	sd->exposure_step = 16;
 
-	sd->brightness = BRIGHTNESS_DEFAULT;
-	sd->contrast = CONTRAST_DEFAULT;
-	sd->saturation = SATURATION_DEFAULT;
-	sd->hue = HUE_DEFAULT;
-	sd->gamma = GAMMA_DEFAULT;
-	sd->red = RED_DEFAULT;
-	sd->blue = BLUE_DEFAULT;
+	gspca_dev->cam.ctrls = sd->ctrls;
 
-	sd->hflip = HFLIP_DEFAULT;
-	sd->vflip = VFLIP_DEFAULT;
-	sd->exposure = EXPOSURE_DEFAULT;
-	sd->gain = GAIN_DEFAULT;
-	sd->auto_exposure = AUTO_EXPOSURE_DEFAULT;
-
-	sd->quality = 95;
+	INIT_WORK(&sd->work, qual_upd);
 
 	return 0;
 }
@@ -2105,9 +1867,10 @@
 
 	for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
 		value = bridge_init[i][1];
-		if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) {
+		reg_w(gspca_dev, bridge_init[i][0], &value, 1);
+		if (gspca_dev->usb_err < 0) {
 			pr_err("Device initialization failed\n");
-			return -ENODEV;
+			return gspca_dev->usb_err;
 		}
 	}
 
@@ -2116,72 +1879,85 @@
 	else
 		reg_w1(gspca_dev, 0x1006, 0x20);
 
-	if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
+	reg_w(gspca_dev, 0x10c0, i2c_init, 9);
+	if (gspca_dev->usb_err < 0) {
 		pr_err("Device initialization failed\n");
-		return -ENODEV;
+		return gspca_dev->usb_err;
 	}
 
 	switch (sd->sensor) {
 	case SENSOR_OV9650:
-		if (ov9650_init_sensor(gspca_dev) < 0)
-			return -ENODEV;
+		ov9650_init_sensor(gspca_dev);
+		if (gspca_dev->usb_err < 0)
+			break;
 		pr_info("OV9650 sensor detected\n");
 		break;
 	case SENSOR_OV9655:
-		if (ov9655_init_sensor(gspca_dev) < 0)
-			return -ENODEV;
+		ov9655_init_sensor(gspca_dev);
+		if (gspca_dev->usb_err < 0)
+			break;
 		pr_info("OV9655 sensor detected\n");
 		break;
 	case SENSOR_SOI968:
-		if (soi968_init_sensor(gspca_dev) < 0)
-			return -ENODEV;
+		soi968_init_sensor(gspca_dev);
+		if (gspca_dev->usb_err < 0)
+			break;
 		pr_info("SOI968 sensor detected\n");
 		break;
 	case SENSOR_OV7660:
-		if (ov7660_init_sensor(gspca_dev) < 0)
-			return -ENODEV;
+		ov7660_init_sensor(gspca_dev);
+		if (gspca_dev->usb_err < 0)
+			break;
 		pr_info("OV7660 sensor detected\n");
 		break;
 	case SENSOR_OV7670:
-		if (ov7670_init_sensor(gspca_dev) < 0)
-			return -ENODEV;
+		ov7670_init_sensor(gspca_dev);
+		if (gspca_dev->usb_err < 0)
+			break;
 		pr_info("OV7670 sensor detected\n");
 		break;
 	case SENSOR_MT9VPRB:
-		if (mt9v_init_sensor(gspca_dev) < 0)
-			return -ENODEV;
+		mt9v_init_sensor(gspca_dev);
+		if (gspca_dev->usb_err < 0)
+			break;
+		pr_info("MT9VPRB sensor detected\n");
 		break;
 	case SENSOR_MT9M111:
-		if (mt9m111_init_sensor(gspca_dev) < 0)
-			return -ENODEV;
+		mt9m111_init_sensor(gspca_dev);
+		if (gspca_dev->usb_err < 0)
+			break;
 		pr_info("MT9M111 sensor detected\n");
 		break;
 	case SENSOR_MT9M112:
-		if (mt9m112_init_sensor(gspca_dev) < 0)
-			return -ENODEV;
+		mt9m112_init_sensor(gspca_dev);
+		if (gspca_dev->usb_err < 0)
+			break;
 		pr_info("MT9M112 sensor detected\n");
 		break;
 	case SENSOR_MT9M001:
-		if (mt9m001_init_sensor(gspca_dev) < 0)
-			return -ENODEV;
+		mt9m001_init_sensor(gspca_dev);
+		if (gspca_dev->usb_err < 0)
+			break;
 		break;
 	case SENSOR_HV7131R:
-		if (hv7131r_init_sensor(gspca_dev) < 0)
-			return -ENODEV;
+		hv7131r_init_sensor(gspca_dev);
+		if (gspca_dev->usb_err < 0)
+			break;
 		pr_info("HV7131R sensor detected\n");
 		break;
 	default:
-		pr_info("Unsupported Sensor\n");
-		return -ENODEV;
+		pr_err("Unsupported sensor\n");
+		gspca_dev->usb_err = -ENODEV;
 	}
 
-	return 0;
+	return gspca_dev->usb_err;
 }
 
 static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	u8 value;
+
 	switch (sd->sensor) {
 	case SENSOR_SOI968:
 		if (mode & MODE_SXGA) {
@@ -2264,6 +2040,7 @@
 			break;
 		default:  /* >= 640x480 */
 			gspca_dev->alt = 9;
+			break;
 		}
 	}
 
@@ -2290,14 +2067,15 @@
 
 	jpeg_define(sd->jpeg_hdr, height, width,
 			0x21);
-	jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+	jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
 
 	if (mode & MODE_RAW)
 		fmt = 0x2d;
 	else if (mode & MODE_JPEG)
-		fmt = 0x2c;
+		fmt = 0x24;
 	else
 		fmt = 0x2f;	/* YUV 420 */
+	sd->fmt = fmt;
 
 	switch (mode & SCALE_MASK) {
 	case SCALE_1280x1024:
@@ -2334,18 +2112,37 @@
 	set_hvflip(gspca_dev);
 
 	reg_w1(gspca_dev, 0x1007, 0x20);
+	reg_w1(gspca_dev, 0x1061, 0x03);
 
-	reg_r(gspca_dev, 0x1061, 1);
-	reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02);
-	return 0;
+	/* if JPEG, prepare the compression quality update */
+	if (mode & MODE_JPEG) {
+		sd->pktsz = sd->npkt = 0;
+		sd->nchg = 0;
+		sd->work_thread =
+			create_singlethread_workqueue(KBUILD_MODNAME);
+	}
+
+	return gspca_dev->usb_err;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
 	reg_w1(gspca_dev, 0x1007, 0x00);
+	reg_w1(gspca_dev, 0x1061, 0x01);
+}
 
-	reg_r(gspca_dev, 0x1061, 1);
-	reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
+/* called on streamoff with alt==0 and on disconnect */
+/* the usb_lock is held at entry - restore on exit */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->work_thread != NULL) {
+		mutex_unlock(&gspca_dev->usb_lock);
+		destroy_workqueue(sd->work_thread);
+		mutex_lock(&gspca_dev->usb_lock);
+		sd->work_thread = NULL;
+	}
 }
 
 static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
@@ -2359,15 +2156,15 @@
 	 * and exposure steps
 	 */
 	if (avg_lum < MIN_AVG_LUM) {
-		if (sd->exposure > 0x1770)
+		if (sd->ctrls[EXPOSURE].val > 0x1770)
 			return;
 
-		new_exp = sd->exposure + sd->exposure_step;
+		new_exp = sd->ctrls[EXPOSURE].val + sd->exposure_step;
 		if (new_exp > 0x1770)
 			new_exp = 0x1770;
 		if (new_exp < 0x10)
 			new_exp = 0x10;
-		sd->exposure = new_exp;
+		sd->ctrls[EXPOSURE].val = new_exp;
 		set_exposure(gspca_dev);
 
 		sd->older_step = sd->old_step;
@@ -2379,14 +2176,14 @@
 			sd->exposure_step += 2;
 	}
 	if (avg_lum > MAX_AVG_LUM) {
-		if (sd->exposure < 0x10)
+		if (sd->ctrls[EXPOSURE].val < 0x10)
 			return;
-		new_exp = sd->exposure - sd->exposure_step;
+		new_exp = sd->ctrls[EXPOSURE].val - sd->exposure_step;
 		if (new_exp > 0x1700)
 			new_exp = 0x1770;
 		if (new_exp < 0x10)
 			new_exp = 0x10;
-		sd->exposure = new_exp;
+		sd->ctrls[EXPOSURE].val = new_exp;
 		set_exposure(gspca_dev);
 		sd->older_step = sd->old_step;
 		sd->old_step = 0;
@@ -2403,14 +2200,14 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	if (avg_lum < MIN_AVG_LUM) {
-		if (sd->gain + 1 <= 28) {
-			sd->gain++;
+		if (sd->ctrls[GAIN].val + 1 <= 28) {
+			sd->ctrls[GAIN].val++;
 			set_gain(gspca_dev);
 		}
 	}
 	if (avg_lum > MAX_AVG_LUM) {
-		if (sd->gain > 0) {
-			sd->gain--;
+		if (sd->ctrls[GAIN].val > 0) {
+			sd->ctrls[GAIN].val--;
 			set_gain(gspca_dev);
 		}
 	}
@@ -2421,7 +2218,7 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	int avg_lum;
 
-	if (!sd->auto_exposure)
+	if (!sd->ctrls[AUTOGAIN].val)
 		return;
 
 	avg_lum = atomic_read(&sd->avg_lum);
@@ -2431,33 +2228,92 @@
 		do_autoexposure(gspca_dev, avg_lum);
 }
 
+/* JPEG quality update */
+/* This function is executed from a work queue. */
+static void qual_upd(struct work_struct *work)
+{
+	struct sd *sd = container_of(work, struct sd, work);
+	struct gspca_dev *gspca_dev = &sd->gspca_dev;
+
+	mutex_lock(&gspca_dev->usb_lock);
+	PDEBUG(D_STREAM, "qual_upd %d%%", sd->ctrls[QUALITY].val);
+	set_quality(gspca_dev);
+	mutex_unlock(&gspca_dev->usb_lock);
+}
+
 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
 			u8 *data,		/* interrupt packet */
 			int len)		/* interrupt packet length */
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	int ret = -EINVAL;
+
 	if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
-			input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
-			input_sync(gspca_dev->input_dev);
-			input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
-			input_sync(gspca_dev->input_dev);
-			ret = 0;
+		input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
+		input_sync(gspca_dev->input_dev);
+		input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+		input_sync(gspca_dev->input_dev);
+		return 0;
 	}
-	return ret;
+	return -EINVAL;
 }
 #endif
 
+/* check the JPEG compression */
+static void transfer_check(struct gspca_dev *gspca_dev,
+			u8 *data)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int new_qual, r;
+
+	new_qual = 0;
+
+	/* if USB error, discard the frame and decrease the quality */
+	if (data[6] & 0x08) {				/* USB FIFO full */
+		gspca_dev->last_packet_type = DISCARD_PACKET;
+		new_qual = -5;
+	} else {
+
+		/* else, compute the filling rate and a new JPEG quality */
+		r = (sd->pktsz * 100) /
+			(sd->npkt *
+				gspca_dev->urb[0]->iso_frame_desc[0].length);
+		if (r >= 85)
+			new_qual = -3;
+		else if (r < 75)
+			new_qual = 2;
+	}
+	if (new_qual != 0) {
+		sd->nchg += new_qual;
+		if (sd->nchg < -6 || sd->nchg >= 12) {
+			sd->nchg = 0;
+			new_qual += sd->ctrls[QUALITY].val;
+			if (new_qual < QUALITY_MIN)
+				new_qual = QUALITY_MIN;
+			else if (new_qual > QUALITY_MAX)
+				new_qual = QUALITY_MAX;
+			if (new_qual != sd->ctrls[QUALITY].val) {
+				sd->ctrls[QUALITY].val = new_qual;
+				queue_work(sd->work_thread, &sd->work);
+			}
+		}
+	} else {
+		sd->nchg = 0;
+	}
+	sd->pktsz = sd->npkt = 0;
+}
+
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	int avg_lum;
+	int avg_lum, is_jpeg;
 	static u8 frame_header[] =
 		{0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
-	if (len == 64 && memcmp(data, frame_header, 6) == 0) {
+
+	is_jpeg = (sd->fmt & 0x03) == 0;
+	if (len >= 64 && memcmp(data, frame_header, 6) == 0) {
 		avg_lum = ((data[35] >> 2) & 3) |
 			   (data[20] << 2) |
 			   (data[19] << 10);
@@ -2484,12 +2340,18 @@
 			    (data[33] << 10);
 		avg_lum >>= 9;
 		atomic_set(&sd->avg_lum, avg_lum);
+
+		if (is_jpeg)
+			transfer_check(gspca_dev, data);
+
 		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
-		return;
+		len -= 64;
+		if (len == 0)
+			return;
+		data += 64;
 	}
 	if (gspca_dev->last_packet_type == LAST_PACKET) {
-		if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv
-				& MODE_JPEG) {
+		if (is_jpeg) {
 			gspca_frame_add(gspca_dev, FIRST_PACKET,
 				sd->jpeg_hdr, JPEG_HDR_SZ);
 			gspca_frame_add(gspca_dev, INTER_PACKET,
@@ -2499,13 +2361,18 @@
 				data, len);
 		}
 	} else {
+		/* if JPEG, count the packets and their size */
+		if (is_jpeg) {
+			sd->npkt++;
+			sd->pktsz += len;
+		}
 		gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 	}
 }
 
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
-	.name = MODULE_NAME,
+	.name = KBUILD_MODNAME,
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
@@ -2513,6 +2380,7 @@
 	.isoc_init = sd_isoc_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
 	.pkt_scan = sd_pkt_scan,
 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 	.int_pkt_scan = sd_int_pkt_scan,
@@ -2581,7 +2449,7 @@
 }
 
 static struct usb_driver sd_driver = {
-	.name = MODULE_NAME,
+	.name = KBUILD_MODNAME,
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 0c9e6dd..db8e508 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -39,7 +39,9 @@
 	BLUE,
 	RED,
 	GAMMA,
+	EXPOSURE,
 	AUTOGAIN,
+	GAIN,
 	HFLIP,
 	VFLIP,
 	SHARPNESS,
@@ -131,7 +133,9 @@
 static void setcolors(struct gspca_dev *gspca_dev);
 static void setredblue(struct gspca_dev *gspca_dev);
 static void setgamma(struct gspca_dev *gspca_dev);
-static void setautogain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static void setgain(struct gspca_dev *gspca_dev);
 static void sethvflip(struct gspca_dev *gspca_dev);
 static void setsharpness(struct gspca_dev *gspca_dev);
 static void setillum(struct gspca_dev *gspca_dev);
@@ -213,6 +217,18 @@
 	    },
 	    .set_control = setgamma
 	},
+[EXPOSURE] = {
+	    {
+		.id      = V4L2_CID_EXPOSURE,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Exposure",
+		.minimum = 500,
+		.maximum = 1500,
+		.step    = 1,
+		.default_value = 1024
+	    },
+	    .set_control = setexposure
+	},
 [AUTOGAIN] = {
 	    {
 		.id      = V4L2_CID_AUTOGAIN,
@@ -223,7 +239,19 @@
 		.step    = 1,
 		.default_value = 1
 	    },
-	    .set_control = setautogain
+	    .set = sd_setautogain,
+	},
+[GAIN] = {
+	    {
+		.id      = V4L2_CID_GAIN,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Gain",
+		.minimum = 4,
+		.maximum = 49,
+		.step    = 1,
+		.default_value = 15
+	    },
+	    .set_control = setgain
 	},
 [HFLIP] = {
 	    {
@@ -290,60 +318,87 @@
 
 /* table of the disabled controls */
 static const __u32 ctrl_dis[] = {
-[SENSOR_ADCM1700] =	(1 << AUTOGAIN) |
+[SENSOR_ADCM1700] =	(1 << EXPOSURE) |
+			(1 << AUTOGAIN) |
+			(1 << GAIN) |
 			(1 << HFLIP) |
 			(1 << VFLIP) |
 			(1 << FREQ),
 
-[SENSOR_GC0307] =	(1 << HFLIP) |
+[SENSOR_GC0307] =	(1 << EXPOSURE) |
+			(1 << GAIN) |
+			(1 << HFLIP) |
 			(1 << VFLIP) |
 			(1 << FREQ),
 
-[SENSOR_HV7131R] =	(1 << HFLIP) |
+[SENSOR_HV7131R] =	(1 << EXPOSURE) |
+			(1 << GAIN) |
+			(1 << HFLIP) |
 			(1 << FREQ),
 
-[SENSOR_MI0360] =	(1 << HFLIP) |
+[SENSOR_MI0360] =	(1 << EXPOSURE) |
+			(1 << GAIN) |
+			(1 << HFLIP) |
 			(1 << VFLIP) |
 			(1 << FREQ),
 
-[SENSOR_MI0360B] =	(1 << HFLIP) |
+[SENSOR_MI0360B] =	(1 << EXPOSURE) |
+			(1 << GAIN) |
+			(1 << HFLIP) |
 			(1 << VFLIP) |
 			(1 << FREQ),
 
-[SENSOR_MO4000] =	(1 << HFLIP) |
+[SENSOR_MO4000] =	(1 << EXPOSURE) |
+			(1 << GAIN) |
+			(1 << HFLIP) |
 			(1 << VFLIP) |
 			(1 << FREQ),
 
-[SENSOR_MT9V111] =	(1 << HFLIP) |
+[SENSOR_MT9V111] =	(1 << EXPOSURE) |
+			(1 << GAIN) |
+			(1 << HFLIP) |
 			(1 << VFLIP) |
 			(1 << FREQ),
 
-[SENSOR_OM6802] =	(1 << HFLIP) |
+[SENSOR_OM6802] =	(1 << EXPOSURE) |
+			(1 << GAIN) |
+			(1 << HFLIP) |
 			(1 << VFLIP) |
 			(1 << FREQ),
 
-[SENSOR_OV7630] =	(1 << HFLIP),
+[SENSOR_OV7630] =	(1 << EXPOSURE) |
+			(1 << GAIN) |
+			(1 << HFLIP),
 
-[SENSOR_OV7648] =	(1 << HFLIP),
+[SENSOR_OV7648] =	(1 << EXPOSURE) |
+			(1 << GAIN) |
+			(1 << HFLIP),
 
-[SENSOR_OV7660] =	(1 << AUTOGAIN) |
+[SENSOR_OV7660] =	(1 << EXPOSURE) |
+			(1 << AUTOGAIN) |
+			(1 << GAIN) |
 			(1 << HFLIP) |
 			(1 << VFLIP),
 
-[SENSOR_PO1030] =	(1 << AUTOGAIN) |
+[SENSOR_PO1030] =	(1 << EXPOSURE) |
+			(1 << AUTOGAIN) |
+			(1 << GAIN) |
 			(1 << HFLIP) |
 			(1 << VFLIP) |
 			(1 << FREQ),
 
-[SENSOR_PO2030N] =	(1 << AUTOGAIN) |
-			(1 << FREQ),
+[SENSOR_PO2030N] =	(1 << FREQ),
 
-[SENSOR_SOI768] =	(1 << AUTOGAIN) |
+[SENSOR_SOI768] =	(1 << EXPOSURE) |
+			(1 << AUTOGAIN) |
+			(1 << GAIN) |
 			(1 << HFLIP) |
 			(1 << VFLIP) |
 			(1 << FREQ),
 
-[SENSOR_SP80708] =	(1 << AUTOGAIN) |
+[SENSOR_SP80708] =	(1 << EXPOSURE) |
+			(1 << AUTOGAIN) |
+			(1 << GAIN) |
 			(1 << HFLIP) |
 			(1 << VFLIP) |
 			(1 << FREQ),
@@ -1242,14 +1297,6 @@
 	{0xa1, 0x6e, 0x05, 0x6f, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x6e, 0x07, 0x25, 0x00, 0x00, 0x00, 0x10},
-	{0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10},
-	{0xc1, 0x6e, 0x16, 0x52, 0x40, 0x48, 0x00, 0x10},
-/*after start*/
-	{0xa1, 0x6e, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x10},
-	{DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
-	{0xa1, 0x6e, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x10},
-	{DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
-	{0xa1, 0x6e, 0x1b, 0x53, 0x00, 0x00, 0x00, 0x10},
 	{}
 };
 
@@ -1858,7 +1905,7 @@
 	return gspca_dev->usb_err;
 }
 
-static u32 setexposure(struct gspca_dev *gspca_dev,
+static u32 expo_adjust(struct gspca_dev *gspca_dev,
 			u32 expo)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -1982,28 +2029,28 @@
 			expo = 0x002dc6c0;
 		else if (expo < 0x02a0)
 			expo = 0x02a0;
-		sd->exposure = setexposure(gspca_dev, expo);
+		sd->exposure = expo_adjust(gspca_dev, expo);
 		break;
 	case SENSOR_MI0360:
 	case SENSOR_MO4000:
 		expo = brightness << 4;
-		sd->exposure = setexposure(gspca_dev, expo);
+		sd->exposure = expo_adjust(gspca_dev, expo);
 		break;
 	case SENSOR_MI0360B:
 		expo = brightness << 2;
-		sd->exposure = setexposure(gspca_dev, expo);
+		sd->exposure = expo_adjust(gspca_dev, expo);
 		break;
 	case SENSOR_GC0307:
 		expo = brightness;
-		sd->exposure = setexposure(gspca_dev, expo);
+		sd->exposure = expo_adjust(gspca_dev, expo);
 		return;			/* don't set the Y offset */
 	case SENSOR_MT9V111:
 		expo = brightness << 2;
-		sd->exposure = setexposure(gspca_dev, expo);
+		sd->exposure = expo_adjust(gspca_dev, expo);
 		return;			/* don't set the Y offset */
 	case SENSOR_OM6802:
 		expo = brightness << 2;
-		sd->exposure = setexposure(gspca_dev, expo);
+		sd->exposure = expo_adjust(gspca_dev, expo);
 		return;			/* Y offset already set */
 	}
 
@@ -2112,6 +2159,23 @@
 	reg_w(gspca_dev, 0x20, gamma, sizeof gamma);
 }
 
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_PO2030N) {
+		u8 rexpo[] =		/* 1a: expo H, 1b: expo M */
+			{0xa1, 0x6e, 0x1a, 0x00, 0x40, 0x00, 0x00, 0x10};
+
+		rexpo[3] = sd->ctrls[EXPOSURE].val >> 8;
+		i2c_w8(gspca_dev, rexpo);
+		msleep(6);
+		rexpo[2] = 0x1b;
+		rexpo[3] = sd->ctrls[EXPOSURE].val;
+		i2c_w8(gspca_dev, rexpo);
+	}
+}
+
 static void setautogain(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -2139,6 +2203,19 @@
 		sd->ag_cnt = -1;
 }
 
+static void setgain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_PO2030N) {
+		u8 rgain[] =		/* 15: gain */
+			{0xa1, 0x6e, 0x15, 0x00, 0x40, 0x00, 0x00, 0x15};
+
+		rgain[3] = sd->ctrls[GAIN].val;
+		i2c_w8(gspca_dev, rgain);
+	}
+}
+
 static void sethvflip(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -2623,6 +2700,10 @@
 	setcontrast(gspca_dev);
 	setcolors(gspca_dev);
 	setautogain(gspca_dev);
+	if (!(gspca_dev->ctrl_inac & ((1 << EXPOSURE) | (1 << GAIN)))) {
+		setexposure(gspca_dev);
+		setgain(gspca_dev);
+	}
 	setfreq(gspca_dev);
 
 	sd->pktsz = sd->npkt = 0;
@@ -2719,6 +2800,12 @@
 	}
 }
 
+/* !! coarse_grained_expo_autogain is not used !! */
+#define exp_too_low_cnt bridge
+#define exp_too_high_cnt sensor
+
+#include "autogain_functions.h"
+
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -2736,6 +2823,13 @@
 
 	delta = atomic_read(&sd->avg_lum);
 	PDEBUG(D_FRAM, "mean lum %d", delta);
+
+	if (sd->sensor == SENSOR_PO2030N) {
+		auto_gain_n_exposure(gspca_dev, delta, luma_mean, luma_delta,
+					15, 1024);
+		return;
+	}
+
 	if (delta < luma_mean - luma_delta ||
 	    delta > luma_mean + luma_delta) {
 		switch (sd->sensor) {
@@ -2744,7 +2838,7 @@
 			expotimes += (luma_mean - delta) >> 6;
 			if (expotimes < 0)
 				expotimes = 0;
-			sd->exposure = setexposure(gspca_dev,
+			sd->exposure = expo_adjust(gspca_dev,
 						   (unsigned int) expotimes);
 			break;
 		case SENSOR_HV7131R:
@@ -2752,7 +2846,7 @@
 			expotimes += (luma_mean - delta) >> 4;
 			if (expotimes < 0)
 				expotimes = 0;
-			sd->exposure = setexposure(gspca_dev,
+			sd->exposure = expo_adjust(gspca_dev,
 					(unsigned int) (expotimes << 8));
 			break;
 		case SENSOR_OM6802:
@@ -2761,7 +2855,7 @@
 			expotimes += (luma_mean - delta) >> 2;
 			if (expotimes < 0)
 				expotimes = 0;
-			sd->exposure = setexposure(gspca_dev,
+			sd->exposure = expo_adjust(gspca_dev,
 						   (unsigned int) expotimes);
 			setredblue(gspca_dev);
 			break;
@@ -2773,7 +2867,7 @@
 			expotimes += (luma_mean - delta) >> 6;
 			if (expotimes < 0)
 				expotimes = 0;
-			sd->exposure = setexposure(gspca_dev,
+			sd->exposure = expo_adjust(gspca_dev,
 						   (unsigned int) expotimes);
 			setredblue(gspca_dev);
 			break;
@@ -2948,16 +3042,18 @@
 	}
 }
 
-static int sd_get_jcomp(struct gspca_dev *gspca_dev,
-			struct v4l2_jpegcompression *jcomp)
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	memset(jcomp, 0, sizeof *jcomp);
-	jcomp->quality = sd->quality;
-	jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
-			| V4L2_JPEG_MARKER_DQT;
-	return 0;
+	sd->ctrls[AUTOGAIN].val = val;
+	if (val)
+		gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN);
+	else
+		gspca_dev->ctrl_inac &= ~(1 << EXPOSURE) & ~(1 << GAIN);
+	if (gspca_dev->streaming)
+		setautogain(gspca_dev);
+	return gspca_dev->usb_err;
 }
 
 static int sd_querymenu(struct gspca_dev *gspca_dev,
@@ -3012,7 +3108,6 @@
 	.stop0 = sd_stop0,
 	.pkt_scan = sd_pkt_scan,
 	.dq_callback = do_autogain,
-	.get_jcomp = sd_get_jcomp,
 	.querymenu = sd_querymenu,
 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 	.int_pkt_scan = sd_int_pkt_scan,
diff --git a/drivers/media/video/gspca/stv06xx/Makefile b/drivers/media/video/gspca/stv06xx/Makefile
index 5b318fa..38bc410 100644
--- a/drivers/media/video/gspca/stv06xx/Makefile
+++ b/drivers/media/video/gspca/stv06xx/Makefile
@@ -6,5 +6,5 @@
 		      stv06xx_pb0100.o \
 		      stv06xx_st6422.o
 
-ccflags-y += -Idrivers/media/video/gspca
+ccflags-y += -I$(srctree)/drivers/media/video/gspca
 
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index b9e15bb..7d9a4f1 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -1,7 +1,7 @@
 /*
- * Z-Star/Vimicro zc301/zc302p/vc30x library
+ * Z-Star/Vimicro zc301/zc302p/vc30x driver
  *
- * Copyright (C) 2009-2011 Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009-2012 Jean-Francois Moine <http://moinejf.free.fr>
  * Copyright (C) 2004 2005 2006 Michel Xhaard mxhaard@magic.fr
  *
  * This program is free software; you can redistribute it and/or modify
@@ -21,8 +21,6 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#define MODULE_NAME "zc3xx"
-
 #include <linux/input.h>
 #include "gspca.h"
 #include "jpeg.h"
@@ -34,7 +32,7 @@
 
 static int force_sensor = -1;
 
-#define QUANT_VAL 1		/* quantization table */
+#define REG08_DEF 3		/* default JPEG compression (70%) */
 #include "zc3xx-reg.h"
 
 /* controls */
@@ -46,6 +44,7 @@
 	AUTOGAIN,
 	LIGHTFREQ,
 	SHARPNESS,
+	QUALITY,
 	NCTRLS		/* number of controls */
 };
 
@@ -57,10 +56,10 @@
 
 	struct gspca_ctrl ctrls[NCTRLS];
 
-	u8 quality;			/* image quality */
-#define QUALITY_MIN 50
-#define QUALITY_MAX 80
-#define QUALITY_DEF 70
+	struct work_struct work;
+	struct workqueue_struct *work_thread;
+
+	u8 reg08;		/* webcam compression quality */
 
 	u8 bridge;
 	u8 sensor;		/* Type of image sensor chip */
@@ -101,6 +100,7 @@
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
 static void setlightfreq(struct gspca_dev *gspca_dev);
 static void setsharpness(struct gspca_dev *gspca_dev);
+static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val);
 
 static const struct ctrl sd_ctrls[NCTRLS] = {
 [BRIGHTNESS] = {
@@ -188,6 +188,18 @@
 	    },
 	    .set_control = setsharpness
 	},
+[QUALITY] = {
+	    {
+		.id	 = V4L2_CID_JPEG_COMPRESSION_QUALITY,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Compression Quality",
+		.minimum = 40,
+		.maximum = 70,
+		.step    = 1,
+		.default_value = 70	/* updated in sd_init() */
+	    },
+	    .set = sd_setquality
+	},
 };
 
 static const struct v4l2_pix_format vga_mode[] = {
@@ -229,6 +241,9 @@
 		.priv = 0},
 };
 
+/* bridge reg08 -> JPEG quality conversion table */
+static u8 jpeg_qual[] = {40, 50, 60, 70, /*80*/};
+
 /* usb exchanges */
 struct usb_action {
 	u8	req;
@@ -3894,7 +3909,6 @@
 /* Gains */
 	{0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF},
 	{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP},
-	{0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN},
 	{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
 /* Auto correction */
 	{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
@@ -5640,7 +5654,7 @@
 	{}
 };
 
-static u8 reg_r_i(struct gspca_dev *gspca_dev,
+static u8 reg_r(struct gspca_dev *gspca_dev,
 		u16 index)
 {
 	int ret;
@@ -5655,24 +5669,14 @@
 			index, gspca_dev->usb_buf, 1,
 			500);
 	if (ret < 0) {
-		pr_err("reg_r_i err %d\n", ret);
+		pr_err("reg_r err %d\n", ret);
 		gspca_dev->usb_err = ret;
 		return 0;
 	}
 	return gspca_dev->usb_buf[0];
 }
 
-static u8 reg_r(struct gspca_dev *gspca_dev,
-		u16 index)
-{
-	u8 ret;
-
-	ret = reg_r_i(gspca_dev, index);
-	PDEBUG(D_USBI, "reg r [%04x] -> %02x", index, ret);
-	return ret;
-}
-
-static void reg_w_i(struct gspca_dev *gspca_dev,
+static void reg_w(struct gspca_dev *gspca_dev,
 			u8 value,
 			u16 index)
 {
@@ -5692,14 +5696,6 @@
 	}
 }
 
-static void reg_w(struct gspca_dev *gspca_dev,
-			u8 value,
-			u16 index)
-{
-	PDEBUG(D_USBO, "reg w [%04x] = %02x", index, value);
-	reg_w_i(gspca_dev, value, index);
-}
-
 static u16 i2c_read(struct gspca_dev *gspca_dev,
 			u8 reg)
 {
@@ -5708,16 +5704,14 @@
 
 	if (gspca_dev->usb_err < 0)
 		return 0;
-	reg_w_i(gspca_dev, reg, 0x0092);
-	reg_w_i(gspca_dev, 0x02, 0x0090);		/* <- read command */
+	reg_w(gspca_dev, reg, 0x0092);
+	reg_w(gspca_dev, 0x02, 0x0090);			/* <- read command */
 	msleep(20);
-	retbyte = reg_r_i(gspca_dev, 0x0091);		/* read status */
+	retbyte = reg_r(gspca_dev, 0x0091);		/* read status */
 	if (retbyte != 0x00)
 		pr_err("i2c_r status error %02x\n", retbyte);
-	retval = reg_r_i(gspca_dev, 0x0095);		/* read Lowbyte */
-	retval |= reg_r_i(gspca_dev, 0x0096) << 8;	/* read Hightbyte */
-	PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)",
-			reg, retval, retbyte);
+	retval = reg_r(gspca_dev, 0x0095);		/* read Lowbyte */
+	retval |= reg_r(gspca_dev, 0x0096) << 8;	/* read Hightbyte */
 	return retval;
 }
 
@@ -5730,16 +5724,14 @@
 
 	if (gspca_dev->usb_err < 0)
 		return 0;
-	reg_w_i(gspca_dev, reg, 0x92);
-	reg_w_i(gspca_dev, valL, 0x93);
-	reg_w_i(gspca_dev, valH, 0x94);
-	reg_w_i(gspca_dev, 0x01, 0x90);		/* <- write command */
+	reg_w(gspca_dev, reg, 0x92);
+	reg_w(gspca_dev, valL, 0x93);
+	reg_w(gspca_dev, valH, 0x94);
+	reg_w(gspca_dev, 0x01, 0x90);		/* <- write command */
 	msleep(1);
-	retbyte = reg_r_i(gspca_dev, 0x0091);		/* read status */
+	retbyte = reg_r(gspca_dev, 0x0091);		/* read status */
 	if (retbyte != 0x00)
 		pr_err("i2c_w status error %02x\n", retbyte);
-	PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)",
-			reg, valH, valL, retbyte);
 	return retbyte;
 }
 
@@ -5906,6 +5898,8 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
+	if (sd->sensor != SENSOR_HV7131R)
+		return;
 	sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9)
 		| (i2c_read(gspca_dev, 0x26) << 1)
 		| (i2c_read(gspca_dev, 0x27) >> 7);
@@ -5916,6 +5910,8 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	int val;
 
+	if (sd->sensor != SENSOR_HV7131R)
+		return;
 	val = sd->ctrls[EXPOSURE].val;
 	i2c_write(gspca_dev, 0x25, val >> 9, 0x00);
 	i2c_write(gspca_dev, 0x26, val >> 1, 0x00);
@@ -5925,32 +5921,20 @@
 static void setquality(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	u8 frxt;
+	s8 reg07;
 
+	reg07 = 0;
 	switch (sd->sensor) {
-	case SENSOR_ADCM2700:
-	case SENSOR_GC0305:
-	case SENSOR_HV7131B:
-	case SENSOR_HV7131R:
 	case SENSOR_OV7620:
+		reg07 = 0x30;
+		break;
+	case SENSOR_HV7131R:
 	case SENSOR_PAS202B:
-	case SENSOR_PO2030:
-		return;
+		return;			/* done by work queue */
 	}
-/*fixme: is it really 0008 0007 0018 for all other sensors? */
-	reg_w(gspca_dev, QUANT_VAL, 0x0008);
-	frxt = 0x30;
-	reg_w(gspca_dev, frxt, 0x0007);
-#if QUANT_VAL == 0 || QUANT_VAL == 1 || QUANT_VAL == 2
-	frxt = 0xff;
-#elif QUANT_VAL == 3
-	frxt = 0xf0;
-#elif QUANT_VAL == 4
-	frxt = 0xe0;
-#else
-	frxt = 0x20;
-#endif
-	reg_w(gspca_dev, frxt, 0x0018);
+	reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
+	if (reg07 != 0)
+		reg_w(gspca_dev, reg07, 0x0007);
 }
 
 /* Matches the sensor's internal frame rate to the lighting frequency.
@@ -6084,6 +6068,115 @@
 	reg_w(gspca_dev, autoval, 0x0180);
 }
 
+/* update the transfer parameters */
+/* This function is executed from a work queue. */
+/* The exact use of the bridge registers 07 and 08 is not known.
+ * The following algorithm has been adapted from ms-win traces */
+static void transfer_update(struct work_struct *work)
+{
+	struct sd *sd = container_of(work, struct sd, work);
+	struct gspca_dev *gspca_dev = &sd->gspca_dev;
+	int change, good;
+	u8 reg07, reg11;
+
+	/* synchronize with the main driver and initialize the registers */
+	mutex_lock(&gspca_dev->usb_lock);
+	reg07 = 0;					/* max */
+	reg_w(gspca_dev, reg07, 0x0007);
+	reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
+	mutex_unlock(&gspca_dev->usb_lock);
+
+	good = 0;
+	for (;;) {
+		msleep(100);
+
+		/* get the transfer status */
+		/* the bit 0 of the bridge register 11 indicates overflow */
+		mutex_lock(&gspca_dev->usb_lock);
+		if (!gspca_dev->present || !gspca_dev->streaming)
+			goto err;
+		reg11 = reg_r(gspca_dev, 0x0011);
+		if (gspca_dev->usb_err < 0
+		 || !gspca_dev->present || !gspca_dev->streaming)
+			goto err;
+
+		change = reg11 & 0x01;
+		if (change) {				/* overflow */
+			switch (reg07) {
+			case 0:				/* max */
+				reg07 = sd->sensor == SENSOR_HV7131R
+						? 0x30 : 0x32;
+				if (sd->reg08 != 0) {
+					change = 3;
+					sd->reg08--;
+				}
+				break;
+			case 0x32:
+				reg07 -= 4;
+				break;
+			default:
+				reg07 -= 2;
+				break;
+			case 2:
+				change = 0;		/* already min */
+				break;
+			}
+			good = 0;
+		} else {				/* no overflow */
+			if (reg07 != 0) {		/* if not max */
+				good++;
+				if (good >= 10) {
+					good = 0;
+					change = 1;
+					reg07 += 2;
+					switch (reg07) {
+					case 0x30:
+						if (sd->sensor == SENSOR_PAS202B)
+							reg07 += 2;
+						break;
+					case 0x32:
+					case 0x34:
+						reg07 = 0;
+						break;
+					}
+				}
+			} else {			/* reg07 max */
+				if (sd->reg08 < sizeof jpeg_qual - 1) {
+					good++;
+					if (good > 10) {
+						sd->reg08++;
+						change = 2;
+					}
+				}
+			}
+		}
+		if (change) {
+			if (change & 1) {
+				reg_w(gspca_dev, reg07, 0x0007);
+				if (gspca_dev->usb_err < 0
+				 || !gspca_dev->present
+				 || !gspca_dev->streaming)
+					goto err;
+			}
+			if (change & 2) {
+				reg_w(gspca_dev, sd->reg08,
+						ZC3XX_R008_CLOCKSETTING);
+				if (gspca_dev->usb_err < 0
+				 || !gspca_dev->present
+				 || !gspca_dev->streaming)
+					goto err;
+				sd->ctrls[QUALITY].val = jpeg_qual[sd->reg08];
+				jpeg_set_qual(sd->jpeg_hdr,
+						jpeg_qual[sd->reg08]);
+			}
+		}
+		mutex_unlock(&gspca_dev->usb_lock);
+	}
+	return;
+err:
+	mutex_unlock(&gspca_dev->usb_lock);
+}
+
 static void send_unknown(struct gspca_dev *gspca_dev, int sensor)
 {
 	reg_w(gspca_dev, 0x01, 0x0000);		/* bridge reset */
@@ -6411,7 +6504,9 @@
 	sd->sensor = id->driver_info;
 
 	gspca_dev->cam.ctrls = sd->ctrls;
-	sd->quality = QUALITY_DEF;
+	sd->reg08 = REG08_DEF;
+
+	INIT_WORK(&sd->work, transfer_update);
 
 	return 0;
 }
@@ -6464,6 +6559,27 @@
 		[SENSOR_PO2030] =	1,
 		[SENSOR_TAS5130C] =	1,
 	};
+	static const u8 reg08_tb[SENSOR_MAX] = {
+		[SENSOR_ADCM2700] =	1,
+		[SENSOR_CS2102] =	3,
+		[SENSOR_CS2102K] =	3,
+		[SENSOR_GC0303] =	2,
+		[SENSOR_GC0305] =	3,
+		[SENSOR_HDCS2020] =	1,
+		[SENSOR_HV7131B] =	3,
+		[SENSOR_HV7131R] =	3,
+		[SENSOR_ICM105A] =	3,
+		[SENSOR_MC501CB] =	3,
+		[SENSOR_MT9V111_1] =	3,
+		[SENSOR_MT9V111_3] =	3,
+		[SENSOR_OV7620] =	1,
+		[SENSOR_OV7630C] =	3,
+		[SENSOR_PAS106] =	3,
+		[SENSOR_PAS202B] =	3,
+		[SENSOR_PB0330] =	3,
+		[SENSOR_PO2030] =	2,
+		[SENSOR_TAS5130C] =	3,
+	};
 
 	sensor = zcxx_probeSensor(gspca_dev);
 	if (sensor >= 0)
@@ -6528,7 +6644,6 @@
 		case 0x0e:
 			PDEBUG(D_PROBE, "Find Sensor PAS202B");
 			sd->sensor = SENSOR_PAS202B;
-/*			sd->sharpness = 1; */
 			break;
 		case 0x0f:
 			PDEBUG(D_PROBE, "Find Sensor PAS106");
@@ -6616,13 +6731,21 @@
 	}
 
 	sd->ctrls[GAMMA].def = gamma[sd->sensor];
+	sd->reg08 = reg08_tb[sd->sensor];
+	sd->ctrls[QUALITY].def = jpeg_qual[sd->reg08];
+	sd->ctrls[QUALITY].min = jpeg_qual[0];
+	sd->ctrls[QUALITY].max = jpeg_qual[ARRAY_SIZE(jpeg_qual) - 1];
 
 	switch (sd->sensor) {
 	case SENSOR_HV7131R:
+		gspca_dev->ctrl_dis = (1 << QUALITY);
 		break;
 	case SENSOR_OV7630C:
 		gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE);
 		break;
+	case SENSOR_PAS202B:
+		gspca_dev->ctrl_dis = (1 << QUALITY) | (1 << EXPOSURE);
+		break;
 	default:
 		gspca_dev->ctrl_dis = (1 << EXPOSURE);
 		break;
@@ -6685,7 +6808,6 @@
 	/* create the JPEG header */
 	jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
 			0x21);		/* JPEG 422 */
-	jpeg_set_qual(sd->jpeg_hdr, sd->quality);
 
 	mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
 	switch (sd->sensor) {
@@ -6761,10 +6883,9 @@
 		reg_r(gspca_dev, 0x0180);	/* from win */
 		reg_w(gspca_dev, 0x00, 0x0180);
 		break;
-	default:
-		setquality(gspca_dev);
-		break;
 	}
+	setquality(gspca_dev);
+	jpeg_set_qual(sd->jpeg_hdr, jpeg_qual[sd->reg08]);
 	setlightfreq(gspca_dev);
 
 	switch (sd->sensor) {
@@ -6776,8 +6897,7 @@
 		reg_w(gspca_dev, 0x40, 0x0117);
 		break;
 	case SENSOR_HV7131R:
-		if (!sd->ctrls[AUTOGAIN].val)
-			setexposure(gspca_dev);
+		setexposure(gspca_dev);
 		reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN);
 		break;
 	case SENSOR_GC0305:
@@ -6802,13 +6922,19 @@
 	}
 
 	setautogain(gspca_dev);
-	switch (sd->sensor) {
-	case SENSOR_PO2030:
-		msleep(50);
-		reg_w(gspca_dev, 0x00, 0x0007);	/* (from win traces) */
-		reg_w(gspca_dev, 0x02, ZC3XX_R008_CLOCKSETTING);
-		break;
+
+	/* start the transfer update thread if needed */
+	if (gspca_dev->usb_err >= 0) {
+		switch (sd->sensor) {
+		case SENSOR_HV7131R:
+		case SENSOR_PAS202B:
+			sd->work_thread =
+				create_singlethread_workqueue(KBUILD_MODNAME);
+			queue_work(sd->work_thread, &sd->work);
+			break;
+		}
 	}
+
 	return gspca_dev->usb_err;
 }
 
@@ -6817,6 +6943,12 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
+	if (sd->work_thread != NULL) {
+		mutex_unlock(&gspca_dev->usb_lock);
+		destroy_workqueue(sd->work_thread);
+		mutex_lock(&gspca_dev->usb_lock);
+		sd->work_thread = NULL;
+	}
 	if (!gspca_dev->present)
 		return;
 	send_unknown(gspca_dev, sd->sensor);
@@ -6893,19 +7025,33 @@
 	return -EINVAL;
 }
 
+static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(jpeg_qual) - 1; i++) {
+		if (val <= jpeg_qual[i])
+			break;
+	}
+	if (i > 0
+	 && i == sd->reg08
+	 && val < jpeg_qual[sd->reg08])
+		i--;
+	sd->reg08 = i;
+	sd->ctrls[QUALITY].val = jpeg_qual[i];
+	if (gspca_dev->streaming)
+		jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
+	return gspca_dev->usb_err;
+}
+
 static int sd_set_jcomp(struct gspca_dev *gspca_dev,
 			struct v4l2_jpegcompression *jcomp)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	if (jcomp->quality < QUALITY_MIN)
-		sd->quality = QUALITY_MIN;
-	else if (jcomp->quality > QUALITY_MAX)
-		sd->quality = QUALITY_MAX;
-	else
-		sd->quality = jcomp->quality;
-	if (gspca_dev->streaming)
-		jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+	sd_setquality(gspca_dev, jcomp->quality);
+	jcomp->quality = sd->ctrls[QUALITY].val;
 	return gspca_dev->usb_err;
 }
 
@@ -6915,7 +7061,7 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	memset(jcomp, 0, sizeof *jcomp);
-	jcomp->quality = sd->quality;
+	jcomp->quality = sd->ctrls[QUALITY].val;
 	jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
 			| V4L2_JPEG_MARKER_DQT;
 	return 0;
@@ -6938,7 +7084,7 @@
 #endif
 
 static const struct sd_desc sd_desc = {
-	.name = MODULE_NAME,
+	.name = KBUILD_MODNAME,
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
@@ -7023,7 +7169,7 @@
 
 /* USB driver */
 static struct usb_driver sd_driver = {
-	.name = MODULE_NAME,
+	.name = KBUILD_MODNAME,
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c
index eec75bb..351e9ba 100644
--- a/drivers/media/video/imx074.c
+++ b/drivers/media/video/imx074.c
@@ -468,18 +468,7 @@
 	.id_table	= imx074_id,
 };
 
-static int __init imx074_mod_init(void)
-{
-	return i2c_add_driver(&imx074_i2c_driver);
-}
-
-static void __exit imx074_mod_exit(void)
-{
-	i2c_del_driver(&imx074_i2c_driver);
-}
-
-module_init(imx074_mod_init);
-module_exit(imx074_mod_exit);
+module_i2c_driver(imx074_i2c_driver);
 
 MODULE_DESCRIPTION("Sony IMX074 Camera driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c
index e5ed4db..5482363 100644
--- a/drivers/media/video/indycam.c
+++ b/drivers/media/video/indycam.c
@@ -387,15 +387,4 @@
 	.id_table	= indycam_id,
 };
 
-static __init int init_indycam(void)
-{
-	return i2c_add_driver(&indycam_driver);
-}
-
-static __exit void exit_indycam(void)
-{
-	i2c_del_driver(&indycam_driver);
-}
-
-module_init(init_indycam);
-module_exit(exit_indycam);
+module_i2c_driver(indycam_driver);
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index a7c41d3..04f192a 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -471,7 +471,7 @@
 	{ }
 };
 
-static struct i2c_driver driver = {
+static struct i2c_driver ir_kbd_driver = {
 	.driver = {
 		.name   = "ir-kbd-i2c",
 	},
@@ -480,21 +480,10 @@
 	.id_table       = ir_kbd_id,
 };
 
+module_i2c_driver(ir_kbd_driver);
+
 /* ----------------------------------------------------------------------- */
 
 MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller");
 MODULE_DESCRIPTION("input driver for i2c IR remote controls");
 MODULE_LICENSE("GPL");
-
-static int __init ir_init(void)
-{
-	return i2c_add_driver(&driver);
-}
-
-static void __exit ir_fini(void)
-{
-	i2c_del_driver(&driver);
-}
-
-module_init(ir_init);
-module_exit(ir_fini);
diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile
index 71ab76a..77de8a4 100644
--- a/drivers/media/video/ivtv/Makefile
+++ b/drivers/media/video/ivtv/Makefile
@@ -7,8 +7,8 @@
 obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
 obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
 
-ccflags-y += -Idrivers/media/video
-ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -I$(srctree)/drivers/media/video
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
 
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c
index b31ee1bc..c604246 100644
--- a/drivers/media/video/ivtv/ivtv-controls.c
+++ b/drivers/media/video/ivtv/ivtv-controls.c
@@ -21,6 +21,7 @@
 #include "ivtv-driver.h"
 #include "ivtv-ioctl.h"
 #include "ivtv-controls.h"
+#include "ivtv-mailbox.h"
 
 static int ivtv_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt)
 {
@@ -99,3 +100,64 @@
 	.s_video_encoding = ivtv_s_video_encoding,
 	.s_stream_vbi_fmt = ivtv_s_stream_vbi_fmt,
 };
+
+int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+
+	if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) {
+		*pts = (s64)((u64)itv->last_dec_timing[2] << 32) |
+			(u64)itv->last_dec_timing[1];
+		*frame = itv->last_dec_timing[0];
+		return 0;
+	}
+	*pts = 0;
+	*frame = 0;
+	if (atomic_read(&itv->decoding)) {
+		if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) {
+			IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n");
+			return -EIO;
+		}
+		memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing));
+		set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
+		*pts = (s64)((u64) data[2] << 32) | (u64) data[1];
+		*frame = data[0];
+		/*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/
+	}
+	return 0;
+}
+
+static int ivtv_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ivtv *itv = container_of(ctrl->handler, struct ivtv, cxhdl.hdl);
+
+	switch (ctrl->id) {
+	/* V4L2_CID_MPEG_VIDEO_DEC_PTS and V4L2_CID_MPEG_VIDEO_DEC_FRAME
+	   control cluster */
+	case V4L2_CID_MPEG_VIDEO_DEC_PTS:
+		return ivtv_g_pts_frame(itv, &itv->ctrl_pts->val64,
+					     &itv->ctrl_frame->val64);
+	}
+	return 0;
+}
+
+static int ivtv_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ivtv *itv = container_of(ctrl->handler, struct ivtv, cxhdl.hdl);
+
+	switch (ctrl->id) {
+	/* V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK and MULTILINGUAL_PLAYBACK
+	   control cluster */
+	case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
+		itv->audio_stereo_mode = itv->ctrl_audio_playback->val - 1;
+		itv->audio_bilingual_mode = itv->ctrl_audio_multilingual_playback->val - 1;
+		ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
+		break;
+	}
+	return 0;
+}
+
+const struct v4l2_ctrl_ops ivtv_hdl_out_ops = {
+	.s_ctrl = ivtv_s_ctrl,
+	.g_volatile_ctrl = ivtv_g_volatile_ctrl,
+};
diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/video/ivtv/ivtv-controls.h
index d12893d..3999e63 100644
--- a/drivers/media/video/ivtv/ivtv-controls.h
+++ b/drivers/media/video/ivtv/ivtv-controls.h
@@ -22,5 +22,7 @@
 #define IVTV_CONTROLS_H
 
 extern struct cx2341x_handler_ops ivtv_cxhdl_ops;
+extern const struct v4l2_ctrl_ops ivtv_hdl_out_ops;
+int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame);
 
 #endif
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 3949b7d..679262e 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -55,7 +55,7 @@
 #include "ivtv-routing.h"
 #include "ivtv-controls.h"
 #include "ivtv-gpio.h"
-
+#include <linux/dma-mapping.h>
 #include <media/tveeprom.h>
 #include <media/saa7115.h>
 #include <media/v4l2-chip-ident.h>
@@ -99,7 +99,7 @@
 
 static unsigned int cardtype_c = 1;
 static unsigned int tuner_c = 1;
-static bool radio_c = 1;
+static int radio_c = 1;
 static unsigned int i2c_clock_period_c = 1;
 static char pal[] = "---";
 static char secam[] = "--";
@@ -139,7 +139,7 @@
 static int newi2c = -1;
 
 module_param_array(tuner, int, &tuner_c, 0644);
-module_param_array(radio, bool, &radio_c, 0644);
+module_param_array(radio, int, &radio_c, 0644);
 module_param_array(cardtype, int, &cardtype_c, 0644);
 module_param_string(pal, pal, sizeof(pal), 0644);
 module_param_string(secam, secam, sizeof(secam), 0644);
@@ -744,8 +744,6 @@
 
 	itv->cur_dma_stream = -1;
 	itv->cur_pio_stream = -1;
-	itv->audio_stereo_mode = AUDIO_STEREO;
-	itv->audio_bilingual_mode = AUDIO_MONO_LEFT;
 
 	/* Ctrls */
 	itv->speed = 1000;
@@ -815,7 +813,7 @@
 		IVTV_ERR("Can't enable device!\n");
 		return -EIO;
 	}
-	if (pci_set_dma_mask(pdev, 0xffffffff)) {
+	if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
 		IVTV_ERR("No suitable DMA available.\n");
 		return -EIO;
 	}
@@ -1200,6 +1198,32 @@
 	itv->tuner_std = itv->std;
 
 	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+		struct v4l2_ctrl_handler *hdl = itv->v4l2_dev.ctrl_handler;
+
+		itv->ctrl_pts = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops,
+				V4L2_CID_MPEG_VIDEO_DEC_PTS, 0, 0, 1, 0);
+		itv->ctrl_frame = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops,
+				V4L2_CID_MPEG_VIDEO_DEC_FRAME, 0, 0x7fffffff, 1, 0);
+		/* Note: V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO is not supported,
+		   mask that menu item. */
+		itv->ctrl_audio_playback =
+			v4l2_ctrl_new_std_menu(hdl, &ivtv_hdl_out_ops,
+				V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK,
+				V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO,
+				1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO,
+				V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO);
+		itv->ctrl_audio_multilingual_playback =
+			v4l2_ctrl_new_std_menu(hdl, &ivtv_hdl_out_ops,
+				V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK,
+				V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO,
+				1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO,
+				V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT);
+		if (hdl->error) {
+			retval = hdl->error;
+			goto free_i2c;
+		}
+		v4l2_ctrl_cluster(2, &itv->ctrl_pts);
+		v4l2_ctrl_cluster(2, &itv->ctrl_audio_playback);
 		ivtv_call_all(itv, video, s_std_output, itv->std);
 		/* Turn off the output signal. The mpeg decoder is not yet
 		   active so without this you would get a green image until the
@@ -1236,6 +1260,7 @@
 free_irq:
 	free_irq(itv->pdev->irq, (void *)itv);
 free_i2c:
+	v4l2_ctrl_handler_free(&itv->cxhdl.hdl);
 	exit_ivtv_i2c(itv);
 free_io:
 	ivtv_iounmap(itv);
@@ -1375,7 +1400,7 @@
 			else
 				type = IVTV_DEC_STREAM_TYPE_MPG;
 			ivtv_stop_v4l2_decode_stream(&itv->streams[type],
-				VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+				V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0);
 		}
 		ivtv_halt_firmware(itv);
 	}
@@ -1391,6 +1416,8 @@
 	ivtv_streams_cleanup(itv, 1);
 	ivtv_udma_free(itv);
 
+	v4l2_ctrl_handler_free(&itv->cxhdl.hdl);
+
 	exit_ivtv_i2c(itv);
 
 	free_irq(itv->pdev->irq, (void *)itv);
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 06f3d78..2e22002 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -54,7 +54,6 @@
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/byteorder.h>
 
 #include <linux/dvb/video.h>
@@ -331,6 +330,7 @@
 	struct ivtv *itv; 		/* for ease of use */
 	const char *name;		/* name of the stream */
 	int type;			/* stream type */
+	u32 caps;			/* V4L2 capabilities */
 
 	struct v4l2_fh *fh;		/* pointer to the streaming filehandle */
 	spinlock_t qlock; 		/* locks access to the queues */
@@ -630,6 +630,16 @@
 
 	struct v4l2_device v4l2_dev;
 	struct cx2341x_handler cxhdl;
+	struct {
+		/* PTS/Frame count control cluster */
+		struct v4l2_ctrl *ctrl_pts;
+		struct v4l2_ctrl *ctrl_frame;
+	};
+	struct {
+		/* Audio Playback control cluster */
+		struct v4l2_ctrl *ctrl_audio_playback;
+		struct v4l2_ctrl *ctrl_audio_multilingual_playback;
+	};
 	struct v4l2_ctrl_handler hdl_gpio;
 	struct v4l2_subdev sd_gpio;	/* GPIO sub-device */
 	u16 instance;
@@ -649,7 +659,6 @@
 	u8 audio_stereo_mode;           /* decoder setting how to handle stereo MPEG audio */
 	u8 audio_bilingual_mode;        /* decoder setting how to handle bilingual MPEG audio */
 
-
 	/* Locking */
 	spinlock_t lock;                /* lock access to this struct */
 	struct mutex serialize_lock;    /* mutex used to serialize open/close/start/stop/ioctl operations */
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 2cd6c89..c9663e8 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -900,7 +900,7 @@
 	if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
 		struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT];
 
-		ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+		ivtv_stop_decoding(id, V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0);
 
 		/* If all output streams are closed, and if the user doesn't have
 		   IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index c4bc481..5452bee 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -246,34 +246,40 @@
 }
 
 static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
-		struct video_command *vc, int try)
+		struct v4l2_decoder_cmd *dc, int try)
 {
 	struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
 
 	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
 		return -EINVAL;
 
-	switch (vc->cmd) {
-	case VIDEO_CMD_PLAY: {
-		vc->flags = 0;
-		vc->play.speed = ivtv_validate_speed(itv->speed, vc->play.speed);
-		if (vc->play.speed < 0)
-			vc->play.format = VIDEO_PLAY_FMT_GOP;
+	switch (dc->cmd) {
+	case V4L2_DEC_CMD_START: {
+		dc->flags &= V4L2_DEC_CMD_START_MUTE_AUDIO;
+		dc->start.speed = ivtv_validate_speed(itv->speed, dc->start.speed);
+		if (dc->start.speed < 0)
+			dc->start.format = V4L2_DEC_START_FMT_GOP;
+		else
+			dc->start.format = V4L2_DEC_START_FMT_NONE;
+		if (dc->start.speed != 500 && dc->start.speed != 1500)
+			dc->flags = dc->start.speed == 1000 ? 0 :
+					V4L2_DEC_CMD_START_MUTE_AUDIO;
 		if (try) break;
 
+		itv->speed_mute_audio = dc->flags & V4L2_DEC_CMD_START_MUTE_AUDIO;
 		if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG)
 			return -EBUSY;
 		if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) {
 			/* forces ivtv_set_speed to be called */
 			itv->speed = 0;
 		}
-		return ivtv_start_decoding(id, vc->play.speed);
+		return ivtv_start_decoding(id, dc->start.speed);
 	}
 
-	case VIDEO_CMD_STOP:
-		vc->flags &= VIDEO_CMD_STOP_IMMEDIATELY|VIDEO_CMD_STOP_TO_BLACK;
-		if (vc->flags & VIDEO_CMD_STOP_IMMEDIATELY)
-			vc->stop.pts = 0;
+	case V4L2_DEC_CMD_STOP:
+		dc->flags &= V4L2_DEC_CMD_STOP_IMMEDIATELY | V4L2_DEC_CMD_STOP_TO_BLACK;
+		if (dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY)
+			dc->stop.pts = 0;
 		if (try) break;
 		if (atomic_read(&itv->decoding) == 0)
 			return 0;
@@ -281,22 +287,22 @@
 			return -EBUSY;
 
 		itv->output_mode = OUT_NONE;
-		return ivtv_stop_v4l2_decode_stream(s, vc->flags, vc->stop.pts);
+		return ivtv_stop_v4l2_decode_stream(s, dc->flags, dc->stop.pts);
 
-	case VIDEO_CMD_FREEZE:
-		vc->flags &= VIDEO_CMD_FREEZE_TO_BLACK;
+	case V4L2_DEC_CMD_PAUSE:
+		dc->flags &= V4L2_DEC_CMD_PAUSE_TO_BLACK;
 		if (try) break;
 		if (itv->output_mode != OUT_MPG)
 			return -EBUSY;
 		if (atomic_read(&itv->decoding) > 0) {
 			ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1,
-				(vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0);
+				(dc->flags & V4L2_DEC_CMD_PAUSE_TO_BLACK) ? 1 : 0);
 			set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);
 		}
 		break;
 
-	case VIDEO_CMD_CONTINUE:
-		vc->flags = 0;
+	case V4L2_DEC_CMD_RESUME:
+		dc->flags = 0;
 		if (try) break;
 		if (itv->output_mode != OUT_MPG)
 			return -EBUSY;
@@ -754,12 +760,15 @@
 
 static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap)
 {
-	struct ivtv *itv = fh2id(fh)->itv;
+	struct ivtv_open_id *id = fh2id(file->private_data);
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
 
 	strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
 	strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
 	snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev));
-	vcap->capabilities = itv->v4l2_cap; 	    /* capabilities */
+	vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS;
+	vcap->device_caps = s->caps;
 	return 0;
 }
 
@@ -1476,8 +1485,6 @@
 	struct v4l2_audio audin;
 	int i;
 
-	IVTV_INFO("=================  START STATUS CARD #%d  =================\n",
-		       itv->instance);
 	IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
 	if (itv->hw_flags & IVTV_HW_TVEEPROM) {
 		struct tveeprom tv;
@@ -1501,13 +1508,6 @@
 			"YUV Frames",
 			"Passthrough",
 		};
-		static const char * const audio_modes[5] = {
-			"Stereo",
-			"Left",
-			"Right",
-			"Mono",
-			"Swapped"
-		};
 		static const char * const alpha_mode[4] = {
 			"None",
 			"Global",
@@ -1536,9 +1536,6 @@
 		ivtv_get_output(itv, itv->active_output, &vidout);
 		ivtv_get_audio_output(itv, 0, &audout);
 		IVTV_INFO("Video Output: %s\n", vidout.name);
-		IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name,
-			audio_modes[itv->audio_stereo_mode],
-			audio_modes[itv->audio_bilingual_mode]);
 		if (mode < 0 || mode > OUT_PASSTHROUGH)
 			mode = OUT_NONE;
 		IVTV_INFO("Output Mode:  %s\n", output_modes[mode]);
@@ -1566,12 +1563,27 @@
 	IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n",
 			(long long)itv->mpg_data_received,
 			(long long)itv->vbi_data_inserted);
-	IVTV_INFO("==================  END STATUS CARD #%d  ==================\n",
-			itv->instance);
-
 	return 0;
 }
 
+static int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec)
+{
+	struct ivtv_open_id *id = fh2id(file->private_data);
+	struct ivtv *itv = id->itv;
+
+	IVTV_DEBUG_IOCTL("VIDIOC_DECODER_CMD %d\n", dec->cmd);
+	return ivtv_video_command(itv, id, dec, false);
+}
+
+static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec)
+{
+	struct ivtv_open_id *id = fh2id(file->private_data);
+	struct ivtv *itv = id->itv;
+
+	IVTV_DEBUG_IOCTL("VIDIOC_TRY_DECODER_CMD %d\n", dec->cmd);
+	return ivtv_video_command(itv, id, dec, true);
+}
+
 static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
 {
 	struct ivtv_open_id *id = fh2id(filp->private_data);
@@ -1605,9 +1617,15 @@
 		return ivtv_yuv_prep_frame(itv, args);
 	}
 
+	case IVTV_IOC_PASSTHROUGH_MODE:
+		IVTV_DEBUG_IOCTL("IVTV_IOC_PASSTHROUGH_MODE\n");
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		return ivtv_passthrough_mode(itv, *(int *)arg != 0);
+
 	case VIDEO_GET_PTS: {
-		u32 data[CX2341X_MBOX_MAX_DATA];
-		u64 *pts = arg;
+		s64 *pts = arg;
+		s64 frame;
 
 		IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n");
 		if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
@@ -1616,29 +1634,12 @@
 		}
 		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
 			return -EINVAL;
-
-		if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) {
-			*pts = (u64) ((u64)itv->last_dec_timing[2] << 32) |
-					(u64)itv->last_dec_timing[1];
-			break;
-		}
-		*pts = 0;
-		if (atomic_read(&itv->decoding)) {
-			if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) {
-				IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n");
-				return -EIO;
-			}
-			memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing));
-			set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
-			*pts = (u64) ((u64) data[2] << 32) | (u64) data[1];
-			/*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/
-		}
-		break;
+		return ivtv_g_pts_frame(itv, pts, &frame);
 	}
 
 	case VIDEO_GET_FRAME_COUNT: {
-		u32 data[CX2341X_MBOX_MAX_DATA];
-		u64 *frame = arg;
+		s64 *frame = arg;
+		s64 pts;
 
 		IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n");
 		if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
@@ -1647,71 +1648,58 @@
 		}
 		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
 			return -EINVAL;
-
-		if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) {
-			*frame = itv->last_dec_timing[0];
-			break;
-		}
-		*frame = 0;
-		if (atomic_read(&itv->decoding)) {
-			if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) {
-				IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n");
-				return -EIO;
-			}
-			memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing));
-			set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
-			*frame = data[0];
-		}
-		break;
+		return ivtv_g_pts_frame(itv, &pts, frame);
 	}
 
 	case VIDEO_PLAY: {
-		struct video_command vc;
+		struct v4l2_decoder_cmd dc;
 
 		IVTV_DEBUG_IOCTL("VIDEO_PLAY\n");
-		memset(&vc, 0, sizeof(vc));
-		vc.cmd = VIDEO_CMD_PLAY;
-		return ivtv_video_command(itv, id, &vc, 0);
+		memset(&dc, 0, sizeof(dc));
+		dc.cmd = V4L2_DEC_CMD_START;
+		return ivtv_video_command(itv, id, &dc, 0);
 	}
 
 	case VIDEO_STOP: {
-		struct video_command vc;
+		struct v4l2_decoder_cmd dc;
 
 		IVTV_DEBUG_IOCTL("VIDEO_STOP\n");
-		memset(&vc, 0, sizeof(vc));
-		vc.cmd = VIDEO_CMD_STOP;
-		vc.flags = VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY;
-		return ivtv_video_command(itv, id, &vc, 0);
+		memset(&dc, 0, sizeof(dc));
+		dc.cmd = V4L2_DEC_CMD_STOP;
+		dc.flags = V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY;
+		return ivtv_video_command(itv, id, &dc, 0);
 	}
 
 	case VIDEO_FREEZE: {
-		struct video_command vc;
+		struct v4l2_decoder_cmd dc;
 
 		IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n");
-		memset(&vc, 0, sizeof(vc));
-		vc.cmd = VIDEO_CMD_FREEZE;
-		return ivtv_video_command(itv, id, &vc, 0);
+		memset(&dc, 0, sizeof(dc));
+		dc.cmd = V4L2_DEC_CMD_PAUSE;
+		return ivtv_video_command(itv, id, &dc, 0);
 	}
 
 	case VIDEO_CONTINUE: {
-		struct video_command vc;
+		struct v4l2_decoder_cmd dc;
 
 		IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n");
-		memset(&vc, 0, sizeof(vc));
-		vc.cmd = VIDEO_CMD_CONTINUE;
-		return ivtv_video_command(itv, id, &vc, 0);
+		memset(&dc, 0, sizeof(dc));
+		dc.cmd = V4L2_DEC_CMD_RESUME;
+		return ivtv_video_command(itv, id, &dc, 0);
 	}
 
 	case VIDEO_COMMAND:
 	case VIDEO_TRY_COMMAND: {
-		struct video_command *vc = arg;
+		/* Note: struct v4l2_decoder_cmd has the same layout as
+		   struct video_command */
+		struct v4l2_decoder_cmd *dc = arg;
 		int try = (cmd == VIDEO_TRY_COMMAND);
 
 		if (try)
-			IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd);
+			IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", dc->cmd);
 		else
-			IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd);
-		return ivtv_video_command(itv, id, vc, try);
+			IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", dc->cmd);
+		return ivtv_video_command(itv, id, dc, try);
 	}
 
 	case VIDEO_GET_EVENT: {
@@ -1775,17 +1763,13 @@
 		IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n");
 		if (iarg > AUDIO_STEREO_SWAPPED)
 			return -EINVAL;
-		itv->audio_stereo_mode = iarg;
-		ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
-		return 0;
+		return v4l2_ctrl_s_ctrl(itv->ctrl_audio_playback, iarg);
 
 	case AUDIO_BILINGUAL_CHANNEL_SELECT:
 		IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n");
 		if (iarg > AUDIO_STEREO_SWAPPED)
 			return -EINVAL;
-		itv->audio_bilingual_mode = iarg;
-		ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
-		return 0;
+		return v4l2_ctrl_s_ctrl(itv->ctrl_audio_multilingual_playback, iarg);
 
 	default:
 		return -EINVAL;
@@ -1800,6 +1784,7 @@
 
 	if (!valid_prio) {
 		switch (cmd) {
+		case IVTV_IOC_PASSTHROUGH_MODE:
 		case VIDEO_PLAY:
 		case VIDEO_STOP:
 		case VIDEO_FREEZE:
@@ -1825,6 +1810,7 @@
 	}
 
 	case IVTV_IOC_DMA_FRAME:
+	case IVTV_IOC_PASSTHROUGH_MODE:
 	case VIDEO_GET_PTS:
 	case VIDEO_GET_FRAME_COUNT:
 	case VIDEO_GET_EVENT:
@@ -1889,6 +1875,8 @@
 	.vidioc_enum_fmt_vid_cap 	    = ivtv_enum_fmt_vid_cap,
 	.vidioc_encoder_cmd  		    = ivtv_encoder_cmd,
 	.vidioc_try_encoder_cmd 	    = ivtv_try_encoder_cmd,
+	.vidioc_decoder_cmd		    = ivtv_decoder_cmd,
+	.vidioc_try_decoder_cmd		    = ivtv_try_decoder_cmd,
 	.vidioc_enum_fmt_vid_out 	    = ivtv_enum_fmt_vid_out,
 	.vidioc_g_fmt_vid_cap 		    = ivtv_g_fmt_vid_cap,
 	.vidioc_g_fmt_vbi_cap		    = ivtv_g_fmt_vbi_cap,
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index c6e28b4..7ea5ca7 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -78,60 +78,73 @@
 	int num_offset;
 	int dma, pio;
 	enum v4l2_buf_type buf_type;
+	u32 v4l2_caps;
 	const struct v4l2_file_operations *fops;
 } ivtv_stream_info[] = {
 	{	/* IVTV_ENC_STREAM_TYPE_MPG */
 		"encoder MPG",
 		VFL_TYPE_GRABBER, 0,
 		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+		V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
+			V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
 		&ivtv_v4l2_enc_fops
 	},
 	{	/* IVTV_ENC_STREAM_TYPE_YUV */
 		"encoder YUV",
 		VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET,
 		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+		V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
+			V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
 		&ivtv_v4l2_enc_fops
 	},
 	{	/* IVTV_ENC_STREAM_TYPE_VBI */
 		"encoder VBI",
 		VFL_TYPE_VBI, 0,
 		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE,
+		V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_TUNER |
+			V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
 		&ivtv_v4l2_enc_fops
 	},
 	{	/* IVTV_ENC_STREAM_TYPE_PCM */
 		"encoder PCM",
 		VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET,
 		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE,
+		V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
 		&ivtv_v4l2_enc_fops
 	},
 	{	/* IVTV_ENC_STREAM_TYPE_RAD */
 		"encoder radio",
 		VFL_TYPE_RADIO, 0,
 		PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE,
+		V4L2_CAP_RADIO | V4L2_CAP_TUNER,
 		&ivtv_v4l2_enc_fops
 	},
 	{	/* IVTV_DEC_STREAM_TYPE_MPG */
 		"decoder MPG",
 		VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET,
 		PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+		V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
 		&ivtv_v4l2_dec_fops
 	},
 	{	/* IVTV_DEC_STREAM_TYPE_VBI */
 		"decoder VBI",
 		VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET,
 		PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE,
+		V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_READWRITE,
 		&ivtv_v4l2_enc_fops
 	},
 	{	/* IVTV_DEC_STREAM_TYPE_VOUT */
 		"decoder VOUT",
 		VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET,
 		PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT,
+		V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
 		&ivtv_v4l2_dec_fops
 	},
 	{	/* IVTV_DEC_STREAM_TYPE_YUV */
 		"decoder YUV",
 		VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET,
 		PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+		V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
 		&ivtv_v4l2_dec_fops
 	}
 };
@@ -149,6 +162,7 @@
 	s->itv = itv;
 	s->type = type;
 	s->name = ivtv_stream_info[type].name;
+	s->caps = ivtv_stream_info[type].v4l2_caps;
 
 	if (ivtv_stream_info[type].pio)
 		s->dma = PCI_DMA_NONE;
@@ -209,8 +223,8 @@
 
 	s->vdev->num = num;
 	s->vdev->v4l2_dev = &itv->v4l2_dev;
-	s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler;
 	s->vdev->fops = ivtv_stream_info[type].fops;
+	s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler;
 	s->vdev->release = video_device_release;
 	s->vdev->tvnorms = V4L2_STD_ALL;
 	s->vdev->lock = &itv->serialize_lock;
@@ -891,7 +905,7 @@
 	IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", (unsigned long long)pts, flags);
 
 	/* Stop Decoder */
-	if (!(flags & VIDEO_CMD_STOP_IMMEDIATELY) || pts) {
+	if (!(flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) || pts) {
 		u32 tmp = 0;
 
 		/* Wait until the decoder is no longer running */
@@ -911,7 +925,7 @@
 				break;
 		}
 	}
-	ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & VIDEO_CMD_STOP_TO_BLACK, 0, 0);
+	ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & V4L2_DEC_CMD_STOP_TO_BLACK, 0, 0);
 
 	/* turn off notification of dual/stereo mode change */
 	ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
index afa9118..ee7ca2d 100644
--- a/drivers/media/video/ks0127.c
+++ b/drivers/media/video/ks0127.c
@@ -721,15 +721,4 @@
 	.id_table	= ks0127_id,
 };
 
-static __init int init_ks0127(void)
-{
-	return i2c_add_driver(&ks0127_driver);
-}
-
-static __exit void exit_ks0127(void)
-{
-	i2c_del_driver(&ks0127_driver);
-}
-
-module_init(init_ks0127);
-module_exit(exit_ks0127);
+module_i2c_driver(ks0127_driver);
diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c
index 303ffa7..0991576 100644
--- a/drivers/media/video/m52790.c
+++ b/drivers/media/video/m52790.c
@@ -213,15 +213,4 @@
 	.id_table	= m52790_id,
 };
 
-static __init int init_m52790(void)
-{
-	return i2c_add_driver(&m52790_driver);
-}
-
-static __exit void exit_m52790(void)
-{
-	i2c_del_driver(&m52790_driver);
-}
-
-module_init(init_m52790);
-module_exit(exit_m52790);
+module_i2c_driver(m52790_driver);
diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c
index 93d768d..d718aee 100644
--- a/drivers/media/video/m5mols/m5mols_core.c
+++ b/drivers/media/video/m5mols/m5mols_core.c
@@ -982,8 +982,8 @@
 	}
 
 	sd = &info->sd;
-	strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
 	v4l2_i2c_subdev_init(sd, client, &m5mols_ops);
+	strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
 	sd->internal_ops = &m5mols_subdev_internal_ops;
@@ -1057,18 +1057,7 @@
 	.id_table	= m5mols_id,
 };
 
-static int __init m5mols_mod_init(void)
-{
-	return i2c_add_driver(&m5mols_i2c_driver);
-}
-
-static void __exit m5mols_mod_exit(void)
-{
-	i2c_del_driver(&m5mols_i2c_driver);
-}
-
-module_init(m5mols_mod_init);
-module_exit(m5mols_mod_exit);
+module_i2c_driver(m5mols_i2c_driver);
 
 MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
 MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>");
diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c
index 37d20e7..996ac34 100644
--- a/drivers/media/video/marvell-ccic/mcam-core.c
+++ b/drivers/media/video/marvell-ccic/mcam-core.c
@@ -509,11 +509,17 @@
 
 	buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
 	list_del_init(&buf->queue);
+	/*
+	 * Very Bad Not Good Things happen if you don't clear
+	 * C1_DESC_ENA before making any descriptor changes.
+	 */
+	mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA);
 	mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa);
 	mcam_reg_write(cam, REG_DESC_LEN_Y,
 			buf->dma_desc_nent*sizeof(struct mcam_dma_desc));
 	mcam_reg_write(cam, REG_DESC_LEN_U, 0);
 	mcam_reg_write(cam, REG_DESC_LEN_V, 0);
+	mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
 	cam->vb_bufs[0] = buf;
 }
 
@@ -533,7 +539,6 @@
 
 	mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD);
 	mcam_sg_next_buffer(cam);
-	mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
 	cam->nbufs = 3;
 }
 
@@ -556,17 +561,16 @@
 	struct mcam_vb_buffer *buf = cam->vb_bufs[0];
 
 	/*
-	 * Very Bad Not Good Things happen if you don't clear
-	 * C1_DESC_ENA before making any descriptor changes.
+	 * If we're no longer supposed to be streaming, don't do anything.
 	 */
-	mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA);
+	if (cam->state != S_STREAMING)
+		return;
 	/*
 	 * If we have another buffer available, put it in and
 	 * restart the engine.
 	 */
 	if (!list_empty(&cam->buffers)) {
 		mcam_sg_next_buffer(cam);
-		mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
 		mcam_ctlr_start(cam);
 	/*
 	 * Otherwise set CF_SG_RESTART and the controller will
@@ -737,7 +741,14 @@
 	mcam_ctlr_stop(cam);
 	cam->state = S_IDLE;
 	spin_unlock_irqrestore(&cam->dev_lock, flags);
-	msleep(40);
+	/*
+	 * This is a brutally long sleep, but experience shows that
+	 * it can take the controller a while to get the message that
+	 * it needs to stop grabbing frames.  In particular, we can
+	 * sometimes (on mmp) get a frame at the end WITHOUT the
+	 * start-of-frame indication.
+	 */
+	msleep(150);
 	if (test_bit(CF_DMA_ACTIVE, &cam->flags))
 		cam_err(cam, "Timeout waiting for DMA to end\n");
 		/* This would be bad news - what now? */
@@ -880,6 +891,7 @@
 	 * Turn it loose.
 	 */
 	spin_lock_irqsave(&cam->dev_lock, flags);
+	clear_bit(CF_DMA_ACTIVE, &cam->flags);
 	mcam_reset_buffers(cam);
 	mcam_ctlr_irq_enable(cam);
 	cam->state = S_STREAMING;
@@ -922,7 +934,7 @@
 	spin_lock_irqsave(&cam->dev_lock, flags);
 	start = (cam->state == S_BUFWAIT) && !list_empty(&cam->buffers);
 	list_add(&mvb->queue, &cam->buffers);
-	if (test_bit(CF_SG_RESTART, &cam->flags))
+	if (cam->state == S_STREAMING && test_bit(CF_SG_RESTART, &cam->flags))
 		mcam_sg_restart(cam);
 	spin_unlock_irqrestore(&cam->dev_lock, flags);
 	if (start)
@@ -1555,15 +1567,12 @@
 {
 	struct mcam_camera *cam = filp->private_data;
 
-	cam_err(cam, "Release, %d frames, %d singles, %d delivered\n", frames,
+	cam_dbg(cam, "Release, %d frames, %d singles, %d delivered\n", frames,
 			singles, delivered);
 	mutex_lock(&cam->s_mutex);
 	(cam->users)--;
-	if (filp == cam->owner) {
-		mcam_ctlr_stop_dma(cam);
-		cam->owner = NULL;
-	}
 	if (cam->users == 0) {
+		mcam_ctlr_stop_dma(cam);
 		mcam_cleanup_vb2(cam);
 		mcam_ctlr_power_down(cam);
 		if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read)
@@ -1688,6 +1697,8 @@
 		if (irqs & (IRQ_EOF0 << frame)) {
 			mcam_frame_complete(cam, frame);
 			handled = 1;
+			if (cam->buffer_mode == B_DMA_sg)
+				break;
 		}
 	/*
 	 * If a frame starts, note that we have DMA active.  This
diff --git a/drivers/media/video/marvell-ccic/mcam-core.h b/drivers/media/video/marvell-ccic/mcam-core.h
index 917200e..bd6acba 100644
--- a/drivers/media/video/marvell-ccic/mcam-core.h
+++ b/drivers/media/video/marvell-ccic/mcam-core.h
@@ -107,7 +107,6 @@
 	enum mcam_state state;
 	unsigned long flags;		/* Buffer status, mainly (dev_lock) */
 	int users;			/* How many open FDs */
-	struct file *owner;		/* Who has data access (v4l2) */
 
 	/*
 	 * Subsystem structures.
diff --git a/drivers/media/video/marvell-ccic/mmp-driver.c b/drivers/media/video/marvell-ccic/mmp-driver.c
index 0d64e2d..d235523 100644
--- a/drivers/media/video/marvell-ccic/mmp-driver.c
+++ b/drivers/media/video/marvell-ccic/mmp-driver.c
@@ -106,6 +106,13 @@
 /*
  * Power control.
  */
+static void mmpcam_power_up_ctlr(struct mmp_camera *cam)
+{
+	iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR);
+	iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR);
+	mdelay(1);
+}
+
 static void mmpcam_power_up(struct mcam_camera *mcam)
 {
 	struct mmp_camera *cam = mcam_to_cam(mcam);
@@ -113,9 +120,7 @@
 /*
  * Turn on power and clocks to the controller.
  */
-	iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR);
-	iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR);
-	mdelay(1);
+	mmpcam_power_up_ctlr(cam);
 /*
  * Provide power to the sensor.
  */
@@ -335,7 +340,7 @@
 	 * touch a register even if nothing was active before; trust
 	 * me, it's better this way.
 	 */
-	mmpcam_power_up(&cam->mcam);
+	mmpcam_power_up_ctlr(cam);
 	return mccic_resume(&cam->mcam);
 }
 
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index d7cd0f6..82ce507 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -881,18 +881,7 @@
 	.id_table	= msp_id,
 };
 
-static __init int init_msp(void)
-{
-	return i2c_add_driver(&msp_driver);
-}
-
-static __exit void exit_msp(void)
-{
-	i2c_del_driver(&msp_driver);
-}
-
-module_init(init_msp);
-module_exit(exit_msp);
+module_i2c_driver(msp_driver);
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index 097c9d3..7e64818 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -730,18 +730,7 @@
 	.id_table	= mt9m001_id,
 };
 
-static int __init mt9m001_mod_init(void)
-{
-	return i2c_add_driver(&mt9m001_i2c_driver);
-}
-
-static void __exit mt9m001_mod_exit(void)
-{
-	i2c_del_driver(&mt9m001_i2c_driver);
-}
-
-module_init(mt9m001_mod_init);
-module_exit(mt9m001_mod_exit);
+module_i2c_driver(mt9m001_i2c_driver);
 
 MODULE_DESCRIPTION("Micron MT9M001 Camera driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
diff --git a/drivers/media/video/mt9m032.c b/drivers/media/video/mt9m032.c
new file mode 100644
index 0000000..7636672
--- /dev/null
+++ b/drivers/media/video/mt9m032.c
@@ -0,0 +1,868 @@
+/*
+ * Driver for MT9M032 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2010-2011 Lund Engineering
+ * Contact: Gil Lund <gwlund@lundeng.com>
+ * Author: Martin Hostettler <martin@neutronstar.dyndns.org>
+ *
+ * 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/media-entity.h>
+#include <media/mt9m032.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "aptina-pll.h"
+
+/*
+ * width and height include active boundary and black parts
+ *
+ * column    0-  15 active boundary
+ * column   16-1455 image
+ * column 1456-1471 active boundary
+ * column 1472-1599 black
+ *
+ * row       0-  51 black
+ * row      53-  59 active boundary
+ * row      60-1139 image
+ * row    1140-1147 active boundary
+ * row    1148-1151 black
+ */
+
+#define MT9M032_PIXEL_ARRAY_WIDTH			1600
+#define MT9M032_PIXEL_ARRAY_HEIGHT			1152
+
+#define MT9M032_CHIP_VERSION				0x00
+#define		MT9M032_CHIP_VERSION_VALUE		0x1402
+#define MT9M032_ROW_START				0x01
+#define		MT9M032_ROW_START_MIN			0
+#define		MT9M032_ROW_START_MAX			1152
+#define		MT9M032_ROW_START_DEF			60
+#define MT9M032_COLUMN_START				0x02
+#define		MT9M032_COLUMN_START_MIN		0
+#define		MT9M032_COLUMN_START_MAX		1600
+#define		MT9M032_COLUMN_START_DEF		16
+#define MT9M032_ROW_SIZE				0x03
+#define		MT9M032_ROW_SIZE_MIN			32
+#define		MT9M032_ROW_SIZE_MAX			1152
+#define		MT9M032_ROW_SIZE_DEF			1080
+#define MT9M032_COLUMN_SIZE				0x04
+#define		MT9M032_COLUMN_SIZE_MIN			32
+#define		MT9M032_COLUMN_SIZE_MAX			1600
+#define		MT9M032_COLUMN_SIZE_DEF			1440
+#define MT9M032_HBLANK					0x05
+#define MT9M032_VBLANK					0x06
+#define		MT9M032_VBLANK_MAX			0x7ff
+#define MT9M032_SHUTTER_WIDTH_HIGH			0x08
+#define MT9M032_SHUTTER_WIDTH_LOW			0x09
+#define		MT9M032_SHUTTER_WIDTH_MIN		1
+#define		MT9M032_SHUTTER_WIDTH_MAX		1048575
+#define		MT9M032_SHUTTER_WIDTH_DEF		1943
+#define MT9M032_PIX_CLK_CTRL				0x0a
+#define		MT9M032_PIX_CLK_CTRL_INV_PIXCLK		0x8000
+#define MT9M032_RESTART					0x0b
+#define MT9M032_RESET					0x0d
+#define MT9M032_PLL_CONFIG1				0x11
+#define		MT9M032_PLL_CONFIG1_OUTDIV_MASK		0x3f
+#define		MT9M032_PLL_CONFIG1_MUL_SHIFT		8
+#define MT9M032_READ_MODE1				0x1e
+#define MT9M032_READ_MODE2				0x20
+#define		MT9M032_READ_MODE2_VFLIP_SHIFT		15
+#define		MT9M032_READ_MODE2_HFLIP_SHIFT		14
+#define		MT9M032_READ_MODE2_ROW_BLC		0x40
+#define MT9M032_GAIN_GREEN1				0x2b
+#define MT9M032_GAIN_BLUE				0x2c
+#define MT9M032_GAIN_RED				0x2d
+#define MT9M032_GAIN_GREEN2				0x2e
+
+/* write only */
+#define MT9M032_GAIN_ALL				0x35
+#define		MT9M032_GAIN_DIGITAL_MASK		0x7f
+#define		MT9M032_GAIN_DIGITAL_SHIFT		8
+#define		MT9M032_GAIN_AMUL_SHIFT			6
+#define		MT9M032_GAIN_ANALOG_MASK		0x3f
+#define MT9M032_FORMATTER1				0x9e
+#define MT9M032_FORMATTER2				0x9f
+#define		MT9M032_FORMATTER2_DOUT_EN		0x1000
+#define		MT9M032_FORMATTER2_PIXCLK_EN		0x2000
+
+/*
+ * The available MT9M032 datasheet is missing documentation for register 0x10
+ * MT9P031 seems to be close enough, so use constants from that datasheet for
+ * now.
+ * But keep the name MT9P031 to remind us, that this isn't really confirmed
+ * for this sensor.
+ */
+#define MT9P031_PLL_CONTROL				0x10
+#define		MT9P031_PLL_CONTROL_PWROFF		0x0050
+#define		MT9P031_PLL_CONTROL_PWRON		0x0051
+#define		MT9P031_PLL_CONTROL_USEPLL		0x0052
+#define MT9P031_PLL_CONFIG2				0x11
+#define		MT9P031_PLL_CONFIG2_P1_DIV_MASK		0x1f
+
+struct mt9m032 {
+	struct v4l2_subdev subdev;
+	struct media_pad pad;
+	struct mt9m032_platform_data *pdata;
+
+	unsigned int pix_clock;
+
+	struct v4l2_ctrl_handler ctrls;
+	struct {
+		struct v4l2_ctrl *hflip;
+		struct v4l2_ctrl *vflip;
+	};
+
+	struct mutex lock; /* Protects streaming, format, interval and crop */
+
+	bool streaming;
+
+	struct v4l2_mbus_framefmt format;
+	struct v4l2_rect crop;
+	struct v4l2_fract frame_interval;
+};
+
+#define to_mt9m032(sd)	container_of(sd, struct mt9m032, subdev)
+#define to_dev(sensor) \
+	(&((struct i2c_client *)v4l2_get_subdevdata(&(sensor)->subdev))->dev)
+
+static int mt9m032_read(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_word_swapped(client, reg);
+}
+
+static int mt9m032_write(struct i2c_client *client, u8 reg, const u16 data)
+{
+	return i2c_smbus_write_word_swapped(client, reg, data);
+}
+
+static u32 mt9m032_row_time(struct mt9m032 *sensor, unsigned int width)
+{
+	unsigned int effective_width;
+	u32 ns;
+
+	effective_width = width + 716; /* empirical value */
+	ns = div_u64(1000000000ULL * effective_width, sensor->pix_clock);
+	dev_dbg(to_dev(sensor),	"MT9M032 line time: %u ns\n", ns);
+	return ns;
+}
+
+static int mt9m032_update_timing(struct mt9m032 *sensor,
+				 struct v4l2_fract *interval)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	struct v4l2_rect *crop = &sensor->crop;
+	unsigned int min_vblank;
+	unsigned int vblank;
+	u32 row_time;
+
+	if (!interval)
+		interval = &sensor->frame_interval;
+
+	row_time = mt9m032_row_time(sensor, crop->width);
+
+	vblank = div_u64(1000000000ULL * interval->numerator,
+			 (u64)row_time * interval->denominator)
+	       - crop->height;
+
+	if (vblank > MT9M032_VBLANK_MAX) {
+		/* hardware limits to 11 bit values */
+		interval->denominator = 1000;
+		interval->numerator =
+			div_u64((crop->height + MT9M032_VBLANK_MAX) *
+				(u64)row_time * interval->denominator,
+				1000000000ULL);
+		vblank = div_u64(1000000000ULL * interval->numerator,
+				 (u64)row_time * interval->denominator)
+		       - crop->height;
+	}
+	/* enforce minimal 1.6ms blanking time. */
+	min_vblank = 1600000 / row_time;
+	vblank = clamp_t(unsigned int, vblank, min_vblank, MT9M032_VBLANK_MAX);
+
+	return mt9m032_write(client, MT9M032_VBLANK, vblank);
+}
+
+static int mt9m032_update_geom_timing(struct mt9m032 *sensor)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	int ret;
+
+	ret = mt9m032_write(client, MT9M032_COLUMN_SIZE,
+			    sensor->crop.width - 1);
+	if (!ret)
+		ret = mt9m032_write(client, MT9M032_ROW_SIZE,
+				    sensor->crop.height - 1);
+	if (!ret)
+		ret = mt9m032_write(client, MT9M032_COLUMN_START,
+				    sensor->crop.left);
+	if (!ret)
+		ret = mt9m032_write(client, MT9M032_ROW_START,
+				    sensor->crop.top);
+	if (!ret)
+		ret = mt9m032_update_timing(sensor, NULL);
+	return ret;
+}
+
+static int update_formatter2(struct mt9m032 *sensor, bool streaming)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	u16 reg_val =   MT9M032_FORMATTER2_DOUT_EN
+		      | 0x0070;  /* parts reserved! */
+				 /* possibly for changing to 14-bit mode */
+
+	if (streaming)
+		reg_val |= MT9M032_FORMATTER2_PIXCLK_EN;   /* pixclock enable */
+
+	return mt9m032_write(client, MT9M032_FORMATTER2, reg_val);
+}
+
+static int mt9m032_setup_pll(struct mt9m032 *sensor)
+{
+	static const struct aptina_pll_limits limits = {
+		.ext_clock_min = 8000000,
+		.ext_clock_max = 16500000,
+		.int_clock_min = 2000000,
+		.int_clock_max = 24000000,
+		.out_clock_min = 322000000,
+		.out_clock_max = 693000000,
+		.pix_clock_max = 99000000,
+		.n_min = 1,
+		.n_max = 64,
+		.m_min = 16,
+		.m_max = 255,
+		.p1_min = 1,
+		.p1_max = 128,
+	};
+
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	struct mt9m032_platform_data *pdata = sensor->pdata;
+	struct aptina_pll pll;
+	int ret;
+
+	pll.ext_clock = pdata->ext_clock;
+	pll.pix_clock = pdata->pix_clock;
+
+	ret = aptina_pll_calculate(&client->dev, &limits, &pll);
+	if (ret < 0)
+		return ret;
+
+	sensor->pix_clock = pdata->pix_clock;
+
+	ret = mt9m032_write(client, MT9M032_PLL_CONFIG1,
+			    (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT)
+			    | (pll.p1 - 1));
+	if (!ret)
+		ret = mt9m032_write(client, MT9P031_PLL_CONFIG2, pll.n - 1);
+	if (!ret)
+		ret = mt9m032_write(client, MT9P031_PLL_CONTROL,
+				    MT9P031_PLL_CONTROL_PWRON |
+				    MT9P031_PLL_CONTROL_USEPLL);
+	if (!ret)		/* more reserved, Continuous, Master Mode */
+		ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8006);
+	if (!ret)		/* Set 14-bit mode, select 7 divider */
+		ret = mt9m032_write(client, MT9M032_FORMATTER1, 0x111e);
+
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Subdev pad operations
+ */
+
+static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index != 0)
+		return -EINVAL;
+
+	code->code = V4L2_MBUS_FMT_Y8_1X8;
+	return 0;
+}
+
+static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev,
+				   struct v4l2_subdev_fh *fh,
+				   struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->index != 0 || fse->code != V4L2_MBUS_FMT_Y8_1X8)
+		return -EINVAL;
+
+	fse->min_width = MT9M032_COLUMN_SIZE_DEF;
+	fse->max_width = MT9M032_COLUMN_SIZE_DEF;
+	fse->min_height = MT9M032_ROW_SIZE_DEF;
+	fse->max_height = MT9M032_ROW_SIZE_DEF;
+
+	return 0;
+}
+
+/**
+ * __mt9m032_get_pad_crop() - get crop rect
+ * @sensor: pointer to the sensor struct
+ * @fh: file handle for getting the try crop rect from
+ * @which: select try or active crop rect
+ *
+ * Returns a pointer the current active or fh relative try crop rect
+ */
+static struct v4l2_rect *
+__mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh,
+		       enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_crop(fh, 0);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &sensor->crop;
+	default:
+		return NULL;
+	}
+}
+
+/**
+ * __mt9m032_get_pad_format() - get format
+ * @sensor: pointer to the sensor struct
+ * @fh: file handle for getting the try format from
+ * @which: select try or active format
+ *
+ * Returns a pointer the current active or fh relative try format
+ */
+static struct v4l2_mbus_framefmt *
+__mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh,
+			 enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_format(fh, 0);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &sensor->format;
+	default:
+		return NULL;
+	}
+}
+
+static int mt9m032_get_pad_format(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_format *fmt)
+{
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+
+	mutex_lock(&sensor->lock);
+	fmt->format = *__mt9m032_get_pad_format(sensor, fh, fmt->which);
+	mutex_unlock(&sensor->lock);
+
+	return 0;
+}
+
+static int mt9m032_set_pad_format(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_format *fmt)
+{
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+	int ret;
+
+	mutex_lock(&sensor->lock);
+
+	if (sensor->streaming && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		ret = -EBUSY;
+		goto done;
+	}
+
+	/* Scaling is not supported, the format is thus fixed. */
+	ret = mt9m032_get_pad_format(subdev, fh, fmt);
+
+done:
+	mutex_lock(&sensor->lock);
+	return ret;
+}
+
+static int mt9m032_get_pad_crop(struct v4l2_subdev *subdev,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_crop *crop)
+{
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+
+	mutex_lock(&sensor->lock);
+	crop->rect = *__mt9m032_get_pad_crop(sensor, fh, crop->which);
+	mutex_unlock(&sensor->lock);
+
+	return 0;
+}
+
+static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_crop *crop)
+{
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+	struct v4l2_mbus_framefmt *format;
+	struct v4l2_rect *__crop;
+	struct v4l2_rect rect;
+	int ret = 0;
+
+	mutex_lock(&sensor->lock);
+
+	if (sensor->streaming && crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		ret = -EBUSY;
+		goto done;
+	}
+
+	/* Clamp the crop rectangle boundaries and align them to a multiple of 2
+	 * pixels to ensure a GRBG Bayer pattern.
+	 */
+	rect.left = clamp(ALIGN(crop->rect.left, 2), MT9M032_COLUMN_START_MIN,
+			  MT9M032_COLUMN_START_MAX);
+	rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN,
+			 MT9M032_ROW_START_MAX);
+	rect.width = clamp(ALIGN(crop->rect.width, 2), MT9M032_COLUMN_SIZE_MIN,
+			   MT9M032_COLUMN_SIZE_MAX);
+	rect.height = clamp(ALIGN(crop->rect.height, 2), MT9M032_ROW_SIZE_MIN,
+			    MT9M032_ROW_SIZE_MAX);
+
+	rect.width = min(rect.width, MT9M032_PIXEL_ARRAY_WIDTH - rect.left);
+	rect.height = min(rect.height, MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
+
+	__crop = __mt9m032_get_pad_crop(sensor, fh, crop->which);
+
+	if (rect.width != __crop->width || rect.height != __crop->height) {
+		/* Reset the output image size if the crop rectangle size has
+		 * been modified.
+		 */
+		format = __mt9m032_get_pad_format(sensor, fh, crop->which);
+		format->width = rect.width;
+		format->height = rect.height;
+	}
+
+	*__crop = rect;
+	crop->rect = rect;
+
+	if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		ret = mt9m032_update_geom_timing(sensor);
+
+done:
+	mutex_unlock(&sensor->lock);
+	return ret;
+}
+
+static int mt9m032_get_frame_interval(struct v4l2_subdev *subdev,
+				      struct v4l2_subdev_frame_interval *fi)
+{
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+
+	mutex_lock(&sensor->lock);
+	memset(fi, 0, sizeof(*fi));
+	fi->interval = sensor->frame_interval;
+	mutex_unlock(&sensor->lock);
+
+	return 0;
+}
+
+static int mt9m032_set_frame_interval(struct v4l2_subdev *subdev,
+				      struct v4l2_subdev_frame_interval *fi)
+{
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+	int ret;
+
+	mutex_lock(&sensor->lock);
+
+	if (sensor->streaming) {
+		ret = -EBUSY;
+		goto done;
+	}
+
+	/* Avoid divisions by 0. */
+	if (fi->interval.denominator == 0)
+		fi->interval.denominator = 1;
+
+	ret = mt9m032_update_timing(sensor, &fi->interval);
+	if (!ret)
+		sensor->frame_interval = fi->interval;
+
+done:
+	mutex_unlock(&sensor->lock);
+	return ret;
+}
+
+static int mt9m032_s_stream(struct v4l2_subdev *subdev, int streaming)
+{
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+	int ret;
+
+	mutex_lock(&sensor->lock);
+	ret = update_formatter2(sensor, streaming);
+	if (!ret)
+		sensor->streaming = streaming;
+	mutex_unlock(&sensor->lock);
+
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9m032_g_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct mt9m032 *sensor = to_mt9m032(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	int val;
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+		return -EINVAL;
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	val = mt9m032_read(client, reg->reg);
+	if (val < 0)
+		return -EIO;
+
+	reg->size = 2;
+	reg->val = val;
+
+	return 0;
+}
+
+static int mt9m032_s_register(struct v4l2_subdev *sd,
+			      struct v4l2_dbg_register *reg)
+{
+	struct mt9m032 *sensor = to_mt9m032(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+
+	if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+		return -EINVAL;
+
+	if (reg->match.addr != client->addr)
+		return -ENODEV;
+
+	return mt9m032_write(client, reg->reg, reg->val);
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev control operations
+ */
+
+static int update_read_mode2(struct mt9m032 *sensor, bool vflip, bool hflip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	int reg_val = (vflip << MT9M032_READ_MODE2_VFLIP_SHIFT)
+		    | (hflip << MT9M032_READ_MODE2_HFLIP_SHIFT)
+		    | MT9M032_READ_MODE2_ROW_BLC
+		    | 0x0007;
+
+	return mt9m032_write(client, MT9M032_READ_MODE2, reg_val);
+}
+
+static int mt9m032_set_gain(struct mt9m032 *sensor, s32 val)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	int digital_gain_val;	/* in 1/8th (0..127) */
+	int analog_mul;		/* 0 or 1 */
+	int analog_gain_val;	/* in 1/16th. (0..63) */
+	u16 reg_val;
+
+	digital_gain_val = 51; /* from setup example */
+
+	if (val < 63) {
+		analog_mul = 0;
+		analog_gain_val = val;
+	} else {
+		analog_mul = 1;
+		analog_gain_val = val / 2;
+	}
+
+	/* a_gain = (1 + analog_mul) + (analog_gain_val + 1) / 16 */
+	/* overall_gain = a_gain * (1 + digital_gain_val / 8) */
+
+	reg_val = ((digital_gain_val & MT9M032_GAIN_DIGITAL_MASK)
+		   << MT9M032_GAIN_DIGITAL_SHIFT)
+		| ((analog_mul & 1) << MT9M032_GAIN_AMUL_SHIFT)
+		| (analog_gain_val & MT9M032_GAIN_ANALOG_MASK);
+
+	return mt9m032_write(client, MT9M032_GAIN_ALL, reg_val);
+}
+
+static int mt9m032_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+	if (ctrl->id == V4L2_CID_GAIN && ctrl->val >= 63) {
+		/* round because of multiplier used for values >= 63 */
+		ctrl->val &= ~1;
+	}
+
+	return 0;
+}
+
+static int mt9m032_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mt9m032 *sensor =
+		container_of(ctrl->handler, struct mt9m032, ctrls);
+	struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+	int ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_GAIN:
+		return mt9m032_set_gain(sensor, ctrl->val);
+
+	case V4L2_CID_HFLIP:
+	/* case V4L2_CID_VFLIP: -- In the same cluster */
+		return update_read_mode2(sensor, sensor->vflip->val,
+					 sensor->hflip->val);
+
+	case V4L2_CID_EXPOSURE:
+		ret = mt9m032_write(client, MT9M032_SHUTTER_WIDTH_HIGH,
+				    (ctrl->val >> 16) & 0xffff);
+		if (ret < 0)
+			return ret;
+
+		return mt9m032_write(client, MT9M032_SHUTTER_WIDTH_LOW,
+				     ctrl->val & 0xffff);
+	}
+
+	return 0;
+}
+
+static struct v4l2_ctrl_ops mt9m032_ctrl_ops = {
+	.s_ctrl = mt9m032_set_ctrl,
+	.try_ctrl = mt9m032_try_ctrl,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops mt9m032_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = mt9m032_g_register,
+	.s_register = mt9m032_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops mt9m032_video_ops = {
+	.s_stream = mt9m032_s_stream,
+	.g_frame_interval = mt9m032_get_frame_interval,
+	.s_frame_interval = mt9m032_set_frame_interval,
+};
+
+static const struct v4l2_subdev_pad_ops mt9m032_pad_ops = {
+	.enum_mbus_code = mt9m032_enum_mbus_code,
+	.enum_frame_size = mt9m032_enum_frame_size,
+	.get_fmt = mt9m032_get_pad_format,
+	.set_fmt = mt9m032_set_pad_format,
+	.set_crop = mt9m032_set_pad_crop,
+	.get_crop = mt9m032_get_pad_crop,
+};
+
+static const struct v4l2_subdev_ops mt9m032_ops = {
+	.core = &mt9m032_core_ops,
+	.video = &mt9m032_video_ops,
+	.pad = &mt9m032_pad_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * Driver initialization and probing
+ */
+
+static int mt9m032_probe(struct i2c_client *client,
+			 const struct i2c_device_id *devid)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct mt9m032 *sensor;
+	int chip_version;
+	int ret;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_warn(&client->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+		return -EIO;
+	}
+
+	if (!client->dev.platform_data)
+		return -ENODEV;
+
+	sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+	if (sensor == NULL)
+		return -ENOMEM;
+
+	mutex_init(&sensor->lock);
+
+	sensor->pdata = client->dev.platform_data;
+
+	v4l2_i2c_subdev_init(&sensor->subdev, client, &mt9m032_ops);
+	sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	chip_version = mt9m032_read(client, MT9M032_CHIP_VERSION);
+	if (chip_version != MT9M032_CHIP_VERSION_VALUE) {
+		dev_err(&client->dev, "MT9M032 not detected, wrong version "
+			"0x%04x\n", chip_version);
+		ret = -ENODEV;
+		goto error_sensor;
+	}
+
+	dev_info(&client->dev, "MT9M032 detected at address 0x%02x\n",
+		 client->addr);
+
+	sensor->frame_interval.numerator = 1;
+	sensor->frame_interval.denominator = 30;
+
+	sensor->crop.left = MT9M032_COLUMN_START_DEF;
+	sensor->crop.top = MT9M032_ROW_START_DEF;
+	sensor->crop.width = MT9M032_COLUMN_SIZE_DEF;
+	sensor->crop.height = MT9M032_ROW_SIZE_DEF;
+
+	sensor->format.width = sensor->crop.width;
+	sensor->format.height = sensor->crop.height;
+	sensor->format.code = V4L2_MBUS_FMT_Y8_1X8;
+	sensor->format.field = V4L2_FIELD_NONE;
+	sensor->format.colorspace = V4L2_COLORSPACE_SRGB;
+
+	v4l2_ctrl_handler_init(&sensor->ctrls, 4);
+
+	v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
+			  V4L2_CID_GAIN, 0, 127, 1, 64);
+
+	sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls,
+					  &mt9m032_ctrl_ops,
+					  V4L2_CID_HFLIP, 0, 1, 1, 0);
+	sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls,
+					  &mt9m032_ctrl_ops,
+					  V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+	v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
+			  V4L2_CID_EXPOSURE, MT9M032_SHUTTER_WIDTH_MIN,
+			  MT9M032_SHUTTER_WIDTH_MAX, 1,
+			  MT9M032_SHUTTER_WIDTH_DEF);
+
+	if (sensor->ctrls.error) {
+		ret = sensor->ctrls.error;
+		dev_err(&client->dev, "control initialization error %d\n", ret);
+		goto error_ctrl;
+	}
+
+	v4l2_ctrl_cluster(2, &sensor->hflip);
+
+	sensor->subdev.ctrl_handler = &sensor->ctrls;
+	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_init(&sensor->subdev.entity, 1, &sensor->pad, 0);
+	if (ret < 0)
+		goto error_ctrl;
+
+	ret = mt9m032_write(client, MT9M032_RESET, 1);	/* reset on */
+	if (ret < 0)
+		goto error_entity;
+	mt9m032_write(client, MT9M032_RESET, 0);	/* reset off */
+	if (ret < 0)
+		goto error_entity;
+
+	ret = mt9m032_setup_pll(sensor);
+	if (ret < 0)
+		goto error_entity;
+	usleep_range(10000, 11000);
+
+	ret = v4l2_ctrl_handler_setup(&sensor->ctrls);
+	if (ret < 0)
+		goto error_entity;
+
+	/* SIZE */
+	ret = mt9m032_update_geom_timing(sensor);
+	if (ret < 0)
+		goto error_entity;
+
+	ret = mt9m032_write(client, 0x41, 0x0000);	/* reserved !!! */
+	if (ret < 0)
+		goto error_entity;
+	ret = mt9m032_write(client, 0x42, 0x0003);	/* reserved !!! */
+	if (ret < 0)
+		goto error_entity;
+	ret = mt9m032_write(client, 0x43, 0x0003);	/* reserved !!! */
+	if (ret < 0)
+		goto error_entity;
+	ret = mt9m032_write(client, 0x7f, 0x0000);	/* reserved !!! */
+	if (ret < 0)
+		goto error_entity;
+	if (sensor->pdata->invert_pixclock) {
+		ret = mt9m032_write(client, MT9M032_PIX_CLK_CTRL,
+				    MT9M032_PIX_CLK_CTRL_INV_PIXCLK);
+		if (ret < 0)
+			goto error_entity;
+	}
+
+	ret = mt9m032_write(client, MT9M032_RESTART, 1); /* Restart on */
+	if (ret < 0)
+		goto error_entity;
+	msleep(100);
+	ret = mt9m032_write(client, MT9M032_RESTART, 0); /* Restart off */
+	if (ret < 0)
+		goto error_entity;
+	msleep(100);
+	ret = update_formatter2(sensor, false);
+	if (ret < 0)
+		goto error_entity;
+
+	return ret;
+
+error_entity:
+	media_entity_cleanup(&sensor->subdev.entity);
+error_ctrl:
+	v4l2_ctrl_handler_free(&sensor->ctrls);
+error_sensor:
+	mutex_destroy(&sensor->lock);
+	kfree(sensor);
+	return ret;
+}
+
+static int mt9m032_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+	struct mt9m032 *sensor = to_mt9m032(subdev);
+
+	v4l2_device_unregister_subdev(&sensor->subdev);
+	v4l2_ctrl_handler_free(&sensor->ctrls);
+	media_entity_cleanup(&sensor->subdev.entity);
+	mutex_destroy(&sensor->lock);
+	kfree(sensor);
+	return 0;
+}
+
+static const struct i2c_device_id mt9m032_id_table[] = {
+	{ MT9M032_NAME, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, mt9m032_id_table);
+
+static struct i2c_driver mt9m032_i2c_driver = {
+	.driver = {
+		.name = MT9M032_NAME,
+	},
+	.probe = mt9m032_probe,
+	.remove = mt9m032_remove,
+	.id_table = mt9m032_id_table,
+};
+
+module_i2c_driver(mt9m032_i2c_driver);
+
+MODULE_AUTHOR("Martin Hostettler <martin@neutronstar.dyndns.org>");
+MODULE_DESCRIPTION("MT9M032 camera sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index bee65bf..b0c5299 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -1008,18 +1008,7 @@
 	.id_table	= mt9m111_id,
 };
 
-static int __init mt9m111_mod_init(void)
-{
-	return i2c_add_driver(&mt9m111_i2c_driver);
-}
-
-static void __exit mt9m111_mod_exit(void)
-{
-	i2c_del_driver(&mt9m111_i2c_driver);
-}
-
-module_init(mt9m111_mod_init);
-module_exit(mt9m111_mod_exit);
+module_i2c_driver(mt9m111_i2c_driver);
 
 MODULE_DESCRIPTION("Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver");
 MODULE_AUTHOR("Robert Jarzmik");
diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c
index 93c3ec7..c81eaf4f 100644
--- a/drivers/media/video/mt9p031.c
+++ b/drivers/media/video/mt9p031.c
@@ -19,7 +19,6 @@
 #include <linux/log2.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
-#include <media/v4l2-subdev.h>
 #include <linux/videodev2.h>
 
 #include <media/mt9p031.h>
@@ -28,6 +27,8 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
 
+#include "aptina-pll.h"
+
 #define MT9P031_PIXEL_ARRAY_WIDTH			2752
 #define MT9P031_PIXEL_ARRAY_HEIGHT			2004
 
@@ -98,14 +99,6 @@
 #define MT9P031_TEST_PATTERN_RED			0xa2
 #define MT9P031_TEST_PATTERN_BLUE			0xa3
 
-struct mt9p031_pll_divs {
-	u32 ext_freq;
-	u32 target_freq;
-	u8 m;
-	u8 n;
-	u8 p1;
-};
-
 struct mt9p031 {
 	struct v4l2_subdev subdev;
 	struct media_pad pad;
@@ -115,10 +108,8 @@
 	struct mt9p031_platform_data *pdata;
 	struct mutex power_lock; /* lock to protect power_count */
 	int power_count;
-	u16 xskip;
-	u16 yskip;
 
-	const struct mt9p031_pll_divs *pll;
+	struct aptina_pll pll;
 
 	/* Registers cache */
 	u16 output_control;
@@ -186,33 +177,31 @@
 					  0);
 }
 
-/*
- * This static table uses ext_freq and vdd_io values to select suitable
- * PLL dividers m, n and p1 which have been calculated as specifiec in p36
- * of Aptina's mt9p031 datasheet. New values should be added here.
- */
-static const struct mt9p031_pll_divs mt9p031_divs[] = {
-	/* ext_freq	target_freq	m	n	p1 */
-	{21000000,	48000000,	26,	2,	6}
-};
-
-static int mt9p031_pll_get_divs(struct mt9p031 *mt9p031)
+static int mt9p031_pll_setup(struct mt9p031 *mt9p031)
 {
+	static const struct aptina_pll_limits limits = {
+		.ext_clock_min = 6000000,
+		.ext_clock_max = 27000000,
+		.int_clock_min = 2000000,
+		.int_clock_max = 13500000,
+		.out_clock_min = 180000000,
+		.out_clock_max = 360000000,
+		.pix_clock_max = 96000000,
+		.n_min = 1,
+		.n_max = 64,
+		.m_min = 16,
+		.m_max = 255,
+		.p1_min = 1,
+		.p1_max = 128,
+	};
+
 	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
-	int i;
+	struct mt9p031_platform_data *pdata = mt9p031->pdata;
 
-	for (i = 0; i < ARRAY_SIZE(mt9p031_divs); i++) {
-		if (mt9p031_divs[i].ext_freq == mt9p031->pdata->ext_freq &&
-		  mt9p031_divs[i].target_freq == mt9p031->pdata->target_freq) {
-			mt9p031->pll = &mt9p031_divs[i];
-			return 0;
-		}
-	}
+	mt9p031->pll.ext_clock = pdata->ext_freq;
+	mt9p031->pll.pix_clock = pdata->target_freq;
 
-	dev_err(&client->dev, "Couldn't find PLL dividers for ext_freq = %d, "
-		"target_freq = %d\n", mt9p031->pdata->ext_freq,
-		mt9p031->pdata->target_freq);
-	return -EINVAL;
+	return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll);
 }
 
 static int mt9p031_pll_enable(struct mt9p031 *mt9p031)
@@ -226,11 +215,11 @@
 		return ret;
 
 	ret = mt9p031_write(client, MT9P031_PLL_CONFIG_1,
-			    (mt9p031->pll->m << 8) | (mt9p031->pll->n - 1));
+			    (mt9p031->pll.m << 8) | (mt9p031->pll.n - 1));
 	if (ret < 0)
 		return ret;
 
-	ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll->p1 - 1);
+	ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll.p1 - 1);
 	if (ret < 0)
 		return ret;
 
@@ -785,8 +774,6 @@
 	format->field = V4L2_FIELD_NONE;
 	format->colorspace = V4L2_COLORSPACE_SRGB;
 
-	mt9p031->xskip = 1;
-	mt9p031->yskip = 1;
 	return mt9p031_set_power(subdev, 1);
 }
 
@@ -905,7 +892,7 @@
 	mt9p031->format.field = V4L2_FIELD_NONE;
 	mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
 
-	ret = mt9p031_pll_get_divs(mt9p031);
+	ret = mt9p031_pll_setup(mt9p031);
 
 done:
 	if (ret < 0) {
@@ -945,18 +932,7 @@
 	.id_table       = mt9p031_id,
 };
 
-static int __init mt9p031_mod_init(void)
-{
-	return i2c_add_driver(&mt9p031_i2c_driver);
-}
-
-static void __exit mt9p031_mod_exit(void)
-{
-	i2c_del_driver(&mt9p031_i2c_driver);
-}
-
-module_init(mt9p031_mod_init);
-module_exit(mt9p031_mod_exit);
+module_i2c_driver(mt9p031_i2c_driver);
 
 MODULE_DESCRIPTION("Aptina MT9P031 Camera driver");
 MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
diff --git a/drivers/media/video/mt9t001.c b/drivers/media/video/mt9t001.c
index cd81d04a..49ca3cb 100644
--- a/drivers/media/video/mt9t001.c
+++ b/drivers/media/video/mt9t001.c
@@ -817,18 +817,7 @@
 	.id_table	= mt9t001_id,
 };
 
-static int __init mt9t001_init(void)
-{
-	return i2c_add_driver(&mt9t001_driver);
-}
-
-static void __exit mt9t001_exit(void)
-{
-	i2c_del_driver(&mt9t001_driver);
-}
-
-module_init(mt9t001_init);
-module_exit(mt9t001_exit);
+module_i2c_driver(mt9t001_driver);
 
 MODULE_DESCRIPTION("Aptina (Micron) MT9T001 Camera driver");
 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
index 84add1a..1415074 100644
--- a/drivers/media/video/mt9t031.c
+++ b/drivers/media/video/mt9t031.c
@@ -850,18 +850,7 @@
 	.id_table	= mt9t031_id,
 };
 
-static int __init mt9t031_mod_init(void)
-{
-	return i2c_add_driver(&mt9t031_i2c_driver);
-}
-
-static void __exit mt9t031_mod_exit(void)
-{
-	i2c_del_driver(&mt9t031_i2c_driver);
-}
-
-module_init(mt9t031_mod_init);
-module_exit(mt9t031_mod_exit);
+module_i2c_driver(mt9t031_i2c_driver);
 
 MODULE_DESCRIPTION("Micron MT9T031 Camera driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c
index 7b34b11..8d1445f 100644
--- a/drivers/media/video/mt9t112.c
+++ b/drivers/media/video/mt9t112.c
@@ -1117,21 +1117,7 @@
 	.id_table = mt9t112_id,
 };
 
-/************************************************************************
-			module function
-************************************************************************/
-static int __init mt9t112_module_init(void)
-{
-	return i2c_add_driver(&mt9t112_i2c_driver);
-}
-
-static void __exit mt9t112_module_exit(void)
-{
-	i2c_del_driver(&mt9t112_i2c_driver);
-}
-
-module_init(mt9t112_module_init);
-module_exit(mt9t112_module_exit);
+module_i2c_driver(mt9t112_i2c_driver);
 
 MODULE_DESCRIPTION("SoC Camera driver for mt9t112");
 MODULE_AUTHOR("Kuninori Morimoto");
diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c
index db74dd2..6bf01ad 100644
--- a/drivers/media/video/mt9v011.c
+++ b/drivers/media/video/mt9v011.c
@@ -709,15 +709,4 @@
 	.id_table	= mt9v011_id,
 };
 
-static __init int init_mt9v011(void)
-{
-	return i2c_add_driver(&mt9v011_driver);
-}
-
-static __exit void exit_mt9v011(void)
-{
-	i2c_del_driver(&mt9v011_driver);
-}
-
-module_init(init_mt9v011);
-module_exit(exit_mt9v011);
+module_i2c_driver(mt9v011_driver);
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index 9449407..bf63417 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -872,18 +872,7 @@
 	.id_table	= mt9v022_id,
 };
 
-static int __init mt9v022_mod_init(void)
-{
-	return i2c_add_driver(&mt9v022_i2c_driver);
-}
-
-static void __exit mt9v022_mod_exit(void)
-{
-	i2c_del_driver(&mt9v022_i2c_driver);
-}
-
-module_init(mt9v022_mod_init);
-module_exit(mt9v022_mod_exit);
+module_i2c_driver(mt9v022_i2c_driver);
 
 MODULE_DESCRIPTION("Micron MT9V022 Camera driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
diff --git a/drivers/media/video/mt9v032.c b/drivers/media/video/mt9v032.c
index d90b982..75e253a 100644
--- a/drivers/media/video/mt9v032.c
+++ b/drivers/media/video/mt9v032.c
@@ -756,18 +756,7 @@
 	.id_table	= mt9v032_id,
 };
 
-static int __init mt9v032_init(void)
-{
-	return i2c_add_driver(&mt9v032_driver);
-}
-
-static void __exit mt9v032_exit(void)
-{
-	i2c_del_driver(&mt9v032_driver);
-}
-
-module_init(mt9v032_init);
-module_exit(mt9v032_exit);
+module_i2c_driver(mt9v032_driver);
 
 MODULE_DESCRIPTION("Aptina MT9V032 Camera driver");
 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c
index 04aab0c..18afaee 100644
--- a/drivers/media/video/mx2_camera.c
+++ b/drivers/media/video/mx2_camera.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2008, Sascha Hauer, Pengutronix
  * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography
+ * Copyright (C) 2012, Javier Martin, Vista Silicon S.L.
  *
  * 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
@@ -18,6 +19,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
+#include <linux/gcd.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -30,17 +32,14 @@
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
-#include <media/videobuf-core.h>
-#include <media/videobuf-dma-contig.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
 #include <media/soc_camera.h>
 #include <media/soc_mediabus.h>
 
 #include <linux/videodev2.h>
 
 #include <mach/mx2_cam.h>
-#ifdef CONFIG_MACH_MX27
-#include <mach/dma-mx1-mx2.h>
-#endif
 #include <mach/hardware.h>
 
 #include <asm/dma.h>
@@ -206,10 +205,23 @@
 #define PRP_INTR_LBOVF		(1 << 7)
 #define PRP_INTR_CH2OVF		(1 << 8)
 
-#define mx27_camera_emma(pcdev)	(cpu_is_mx27() && pcdev->use_emma)
+/* Resizing registers */
+#define PRP_RZ_VALID_TBL_LEN(x)	((x) << 24)
+#define PRP_RZ_VALID_BILINEAR	(1 << 31)
 
 #define MAX_VIDEO_MEM	16
 
+#define RESIZE_NUM_MIN	1
+#define RESIZE_NUM_MAX	20
+#define BC_COEF		3
+#define SZ_COEF		(1 << BC_COEF)
+
+#define RESIZE_DIR_H	0
+#define RESIZE_DIR_V	1
+
+#define RESIZE_ALGO_BILINEAR 0
+#define RESIZE_ALGO_AVERAGING 1
+
 struct mx2_prp_cfg {
 	int channel;
 	u32 in_fmt;
@@ -219,6 +231,13 @@
 	u32 irq_flags;
 };
 
+/* prp resizing parameters */
+struct emma_prp_resize {
+	int		algo; /* type of algorithm used */
+	int		len; /* number of coefficients */
+	unsigned char	s[RESIZE_NUM_MAX]; /* table of coefficients */
+};
+
 /* prp configuration for a client-host fmt pair */
 struct mx2_fmt_cfg {
 	enum v4l2_mbus_pixelcode	in_fmt;
@@ -226,6 +245,26 @@
 	struct mx2_prp_cfg		cfg;
 };
 
+enum mx2_buffer_state {
+	MX2_STATE_QUEUED,
+	MX2_STATE_ACTIVE,
+	MX2_STATE_DONE,
+};
+
+struct mx2_buf_internal {
+	struct list_head	queue;
+	int			bufnum;
+	bool			discard;
+};
+
+/* buffer for one video frame */
+struct mx2_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct vb2_buffer		vb;
+	enum mx2_buffer_state		state;
+	struct mx2_buf_internal		internal;
+};
+
 struct mx2_camera_dev {
 	struct device		*dev;
 	struct soc_camera_host	soc_host;
@@ -242,6 +281,7 @@
 
 	struct list_head	capture;
 	struct list_head	active_bufs;
+	struct list_head	discard;
 
 	spinlock_t		lock;
 
@@ -250,26 +290,23 @@
 	struct mx2_buffer	*fb1_active;
 	struct mx2_buffer	*fb2_active;
 
-	int			use_emma;
-
 	u32			csicr1;
 
+	struct mx2_buf_internal buf_discard[2];
 	void			*discard_buffer;
 	dma_addr_t		discard_buffer_dma;
 	size_t			discard_size;
 	struct mx2_fmt_cfg	*emma_prp;
+	struct emma_prp_resize	resizing[2];
+	unsigned int		s_width, s_height;
 	u32			frame_count;
+	struct vb2_alloc_ctx	*alloc_ctx;
 };
 
-/* buffer for one video frame */
-struct mx2_buffer {
-	/* common v4l buffer stuff -- must be first */
-	struct videobuf_buffer		vb;
-
-	enum v4l2_mbus_pixelcode	code;
-
-	int bufnum;
-};
+static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf)
+{
+	return container_of(int_buf, struct mx2_buffer, internal);
+}
 
 static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
 	/*
@@ -324,13 +361,36 @@
 	return &mx27_emma_prp_table[0];
 };
 
+static void mx27_update_emma_buf(struct mx2_camera_dev *pcdev,
+				 unsigned long phys, int bufnum)
+{
+	struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+
+	if (prp->cfg.channel == 1) {
+		writel(phys, pcdev->base_emma +
+				PRP_DEST_RGB1_PTR + 4 * bufnum);
+	} else {
+		writel(phys, pcdev->base_emma +
+			PRP_DEST_Y_PTR - 0x14 * bufnum);
+		if (prp->out_fmt == V4L2_PIX_FMT_YUV420) {
+			u32 imgsize = pcdev->icd->user_height *
+					pcdev->icd->user_width;
+
+			writel(phys + imgsize, pcdev->base_emma +
+				PRP_DEST_CB_PTR - 0x14 * bufnum);
+			writel(phys + ((5 * imgsize) / 4), pcdev->base_emma +
+				PRP_DEST_CR_PTR - 0x14 * bufnum);
+		}
+	}
+}
+
 static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
 {
 	unsigned long flags;
 
 	clk_disable(pcdev->clk_csi);
 	writel(0, pcdev->base_csi + CSICR1);
-	if (mx27_camera_emma(pcdev)) {
+	if (cpu_is_mx27()) {
 		writel(0, pcdev->base_emma + PRP_CNTL);
 	} else if (cpu_is_mx25()) {
 		spin_lock_irqsave(&pcdev->lock, flags);
@@ -362,7 +422,7 @@
 
 	csicr1 = CSICR1_MCLKEN;
 
-	if (mx27_camera_emma(pcdev)) {
+	if (cpu_is_mx27()) {
 		csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC |
 			CSICR1_RXFF_LEVEL(0);
 	} else if (cpu_is_mx27())
@@ -392,56 +452,13 @@
 
 	mx2_camera_deactivate(pcdev);
 
-	if (pcdev->discard_buffer) {
-		dma_free_coherent(ici->v4l2_dev.dev, pcdev->discard_size,
-				pcdev->discard_buffer,
-				pcdev->discard_buffer_dma);
-		pcdev->discard_buffer = NULL;
-	}
-
 	pcdev->icd = NULL;
 }
 
-#ifdef CONFIG_MACH_MX27
-static void mx27_camera_dma_enable(struct mx2_camera_dev *pcdev)
-{
-	u32 tmp;
-
-	imx_dma_enable(pcdev->dma);
-
-	tmp = readl(pcdev->base_csi + CSICR1);
-	tmp |= CSICR1_RF_OR_INTEN;
-	writel(tmp, pcdev->base_csi + CSICR1);
-}
-
-static irqreturn_t mx27_camera_irq(int irq_csi, void *data)
-{
-	struct mx2_camera_dev *pcdev = data;
-	u32 status = readl(pcdev->base_csi + CSISR);
-
-	if (status & CSISR_SOF_INT && pcdev->active) {
-		u32 tmp;
-
-		tmp = readl(pcdev->base_csi + CSICR1);
-		writel(tmp | CSICR1_CLR_RXFIFO, pcdev->base_csi + CSICR1);
-		mx27_camera_dma_enable(pcdev);
-	}
-
-	writel(CSISR_SOF_INT | CSISR_RFF_OR_INT, pcdev->base_csi + CSISR);
-
-	return IRQ_HANDLED;
-}
-#else
-static irqreturn_t mx27_camera_irq(int irq_csi, void *data)
-{
-	return IRQ_NONE;
-}
-#endif /* CONFIG_MACH_MX27 */
-
 static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb,
 		int state)
 {
-	struct videobuf_buffer *vb;
+	struct vb2_buffer *vb;
 	struct mx2_buffer *buf;
 	struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active :
 		&pcdev->fb2_active;
@@ -454,25 +471,24 @@
 		goto out;
 
 	vb = &(*fb_active)->vb;
-	dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
-		vb, vb->baddr, vb->bsize);
+	dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+		vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
-	vb->state = state;
-	do_gettimeofday(&vb->ts);
-	vb->field_count++;
-
-	wake_up(&vb->done);
+	do_gettimeofday(&vb->v4l2_buf.timestamp);
+	vb->v4l2_buf.sequence++;
+	vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
 
 	if (list_empty(&pcdev->capture)) {
 		buf = NULL;
 		writel(0, pcdev->base_csi + fb_reg);
 	} else {
-		buf = list_entry(pcdev->capture.next, struct mx2_buffer,
-				vb.queue);
+		buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+				internal.queue);
 		vb = &buf->vb;
-		list_del(&vb->queue);
-		vb->state = VIDEOBUF_ACTIVE;
-		writel(videobuf_to_dma_contig(vb), pcdev->base_csi + fb_reg);
+		list_del(&buf->internal.queue);
+		buf->state = MX2_STATE_ACTIVE;
+		writel(vb2_dma_contig_plane_dma_addr(vb, 0),
+		       pcdev->base_csi + fb_reg);
 	}
 
 	*fb_active = buf;
@@ -487,9 +503,9 @@
 	u32 status = readl(pcdev->base_csi + CSISR);
 
 	if (status & CSISR_DMA_TSF_FB1_INT)
-		mx25_camera_frame_done(pcdev, 1, VIDEOBUF_DONE);
+		mx25_camera_frame_done(pcdev, 1, MX2_STATE_DONE);
 	else if (status & CSISR_DMA_TSF_FB2_INT)
-		mx25_camera_frame_done(pcdev, 2, VIDEOBUF_DONE);
+		mx25_camera_frame_done(pcdev, 2, MX2_STATE_DONE);
 
 	/* FIXME: handle CSISR_RFF_OR_INT */
 
@@ -501,59 +517,50 @@
 /*
  *  Videobuf operations
  */
-static int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
-			      unsigned int *size)
+static int mx2_videobuf_setup(struct vb2_queue *vq,
+			const struct v4l2_format *fmt,
+			unsigned int *count, unsigned int *num_planes,
+			unsigned int sizes[], void *alloc_ctxs[])
 {
-	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
 	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
 			icd->current_fmt->host_fmt);
 
-	dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
+	dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]);
+
+	/* TODO: support for VIDIOC_CREATE_BUFS not ready */
+	if (fmt != NULL)
+		return -ENOTTY;
 
 	if (bytes_per_line < 0)
 		return bytes_per_line;
 
-	*size = bytes_per_line * icd->user_height;
+	alloc_ctxs[0] = pcdev->alloc_ctx;
+
+	sizes[0] = bytes_per_line * icd->user_height;
 
 	if (0 == *count)
 		*count = 32;
-	if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
-		*count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
+	if (!*num_planes &&
+	    sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024)
+		*count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0];
+
+	*num_planes = 1;
 
 	return 0;
 }
 
-static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf)
+static int mx2_videobuf_prepare(struct vb2_buffer *vb)
 {
-	struct soc_camera_device *icd = vq->priv_data;
-	struct videobuf_buffer *vb = &buf->vb;
-
-	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
-		vb, vb->baddr, vb->bsize);
-
-	/*
-	 * This waits until this buffer is out of danger, i.e., until it is no
-	 * longer in state VIDEOBUF_QUEUED or VIDEOBUF_ACTIVE
-	 */
-	videobuf_waiton(vq, vb, 0, 0);
-
-	videobuf_dma_contig_free(vq, vb);
-	dev_dbg(icd->parent, "%s freed\n", __func__);
-
-	vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int mx2_videobuf_prepare(struct videobuf_queue *vq,
-		struct videobuf_buffer *vb, enum v4l2_field field)
-{
-	struct soc_camera_device *icd = vq->priv_data;
-	struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
 	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
 			icd->current_fmt->host_fmt);
 	int ret = 0;
 
-	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
-		vb, vb->baddr, vb->bsize);
+	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+		vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
 	if (bytes_per_line < 0)
 		return bytes_per_line;
@@ -563,99 +570,58 @@
 	 * This can be useful if you want to see if we actually fill
 	 * the buffer with something
 	 */
-	memset((void *)vb->baddr, 0xaa, vb->bsize);
+	memset((void *)vb2_plane_vaddr(vb, 0),
+	       0xaa, vb2_get_plane_payload(vb, 0));
 #endif
 
-	if (buf->code	!= icd->current_fmt->code ||
-	    vb->width	!= icd->user_width ||
-	    vb->height	!= icd->user_height ||
-	    vb->field	!= field) {
-		buf->code	= icd->current_fmt->code;
-		vb->width	= icd->user_width;
-		vb->height	= icd->user_height;
-		vb->field	= field;
-		vb->state	= VIDEOBUF_NEEDS_INIT;
-	}
-
-	vb->size = bytes_per_line * vb->height;
-	if (vb->baddr && vb->bsize < vb->size) {
+	vb2_set_plane_payload(vb, 0, bytes_per_line * icd->user_height);
+	if (vb2_plane_vaddr(vb, 0) &&
+	    vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
 		ret = -EINVAL;
 		goto out;
 	}
 
-	if (vb->state == VIDEOBUF_NEEDS_INIT) {
-		ret = videobuf_iolock(vq, vb, NULL);
-		if (ret)
-			goto fail;
-
-		vb->state = VIDEOBUF_PREPARED;
-	}
-
 	return 0;
 
-fail:
-	free_buffer(vq, buf);
 out:
 	return ret;
 }
 
-static void mx2_videobuf_queue(struct videobuf_queue *vq,
-			       struct videobuf_buffer *vb)
+static void mx2_videobuf_queue(struct vb2_buffer *vb)
 {
-	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
 	struct soc_camera_host *ici =
 		to_soc_camera_host(icd->parent);
 	struct mx2_camera_dev *pcdev = ici->priv;
 	struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
 	unsigned long flags;
 
-	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
-		vb, vb->baddr, vb->bsize);
+	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+		vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
 	spin_lock_irqsave(&pcdev->lock, flags);
 
-	vb->state = VIDEOBUF_QUEUED;
-	list_add_tail(&vb->queue, &pcdev->capture);
+	buf->state = MX2_STATE_QUEUED;
+	list_add_tail(&buf->internal.queue, &pcdev->capture);
 
-	if (mx27_camera_emma(pcdev)) {
-		goto out;
-#ifdef CONFIG_MACH_MX27
-	} else if (cpu_is_mx27()) {
-		int ret;
-
-		if (pcdev->active == NULL) {
-			ret = imx_dma_setup_single(pcdev->dma,
-					videobuf_to_dma_contig(vb), vb->size,
-					(u32)pcdev->base_dma + 0x10,
-					DMA_MODE_READ);
-			if (ret) {
-				vb->state = VIDEOBUF_ERROR;
-				wake_up(&vb->done);
-				goto out;
-			}
-
-			vb->state = VIDEOBUF_ACTIVE;
-			pcdev->active = buf;
-		}
-#endif
-	} else { /* cpu_is_mx25() */
+	if (cpu_is_mx25()) {
 		u32 csicr3, dma_inten = 0;
 
 		if (pcdev->fb1_active == NULL) {
-			writel(videobuf_to_dma_contig(vb),
+			writel(vb2_dma_contig_plane_dma_addr(vb, 0),
 					pcdev->base_csi + CSIDMASA_FB1);
 			pcdev->fb1_active = buf;
 			dma_inten = CSICR1_FB1_DMA_INTEN;
 		} else if (pcdev->fb2_active == NULL) {
-			writel(videobuf_to_dma_contig(vb),
+			writel(vb2_dma_contig_plane_dma_addr(vb, 0),
 					pcdev->base_csi + CSIDMASA_FB2);
 			pcdev->fb2_active = buf;
 			dma_inten = CSICR1_FB2_DMA_INTEN;
 		}
 
 		if (dma_inten) {
-			list_del(&vb->queue);
-			vb->state = VIDEOBUF_ACTIVE;
+			list_del(&buf->internal.queue);
+			buf->state = MX2_STATE_ACTIVE;
 
 			csicr3 = readl(pcdev->base_csi + CSICR3);
 
@@ -674,36 +640,31 @@
 		}
 	}
 
-out:
 	spin_unlock_irqrestore(&pcdev->lock, flags);
 }
 
-static void mx2_videobuf_release(struct videobuf_queue *vq,
-				 struct videobuf_buffer *vb)
+static void mx2_videobuf_release(struct vb2_buffer *vb)
 {
-	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 	struct mx2_camera_dev *pcdev = ici->priv;
 	struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
 	unsigned long flags;
 
 #ifdef DEBUG
-	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
-		vb, vb->baddr, vb->bsize);
+	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+		vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
-	switch (vb->state) {
-	case VIDEOBUF_ACTIVE:
+	switch (buf->state) {
+	case MX2_STATE_ACTIVE:
 		dev_info(icd->parent, "%s (active)\n", __func__);
 		break;
-	case VIDEOBUF_QUEUED:
+	case MX2_STATE_QUEUED:
 		dev_info(icd->parent, "%s (queued)\n", __func__);
 		break;
-	case VIDEOBUF_PREPARED:
-		dev_info(icd->parent, "%s (prepared)\n", __func__);
-		break;
 	default:
 		dev_info(icd->parent, "%s (unknown) %d\n", __func__,
-				vb->state);
+				buf->state);
 		break;
 	}
 #endif
@@ -717,11 +678,9 @@
 	 * state. This requires a specific handling for each of the these DMA
 	 * types.
 	 */
+
 	spin_lock_irqsave(&pcdev->lock, flags);
-	if (vb->state == VIDEOBUF_QUEUED) {
-		list_del(&vb->queue);
-		vb->state = VIDEOBUF_ERROR;
-	} else if (cpu_is_mx25() && vb->state == VIDEOBUF_ACTIVE) {
+	if (cpu_is_mx25() && buf->state == MX2_STATE_ACTIVE) {
 		if (pcdev->fb1_active == buf) {
 			pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN;
 			writel(0, pcdev->base_csi + CSIDMASA_FB1);
@@ -732,30 +691,260 @@
 			pcdev->fb2_active = NULL;
 		}
 		writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
-		vb->state = VIDEOBUF_ERROR;
 	}
 	spin_unlock_irqrestore(&pcdev->lock, flags);
-
-	free_buffer(vq, buf);
 }
 
-static struct videobuf_queue_ops mx2_videobuf_ops = {
-	.buf_setup      = mx2_videobuf_setup,
-	.buf_prepare    = mx2_videobuf_prepare,
-	.buf_queue      = mx2_videobuf_queue,
-	.buf_release    = mx2_videobuf_release,
+static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
+		int bytesperline)
+{
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
+	struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+
+	writel((pcdev->s_width << 16) | pcdev->s_height,
+	       pcdev->base_emma + PRP_SRC_FRAME_SIZE);
+	writel(prp->cfg.src_pixel,
+	       pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
+	if (prp->cfg.channel == 1) {
+		writel((icd->user_width << 16) | icd->user_height,
+			pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE);
+		writel(bytesperline,
+			pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE);
+		writel(prp->cfg.ch1_pixel,
+			pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL);
+	} else { /* channel 2 */
+		writel((icd->user_width << 16) | icd->user_height,
+			pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE);
+	}
+
+	/* Enable interrupts */
+	writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL);
+}
+
+static void mx2_prp_resize_commit(struct mx2_camera_dev *pcdev)
+{
+	int dir;
+
+	for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) {
+		unsigned char *s = pcdev->resizing[dir].s;
+		int len = pcdev->resizing[dir].len;
+		unsigned int coeff[2] = {0, 0};
+		unsigned int valid  = 0;
+		int i;
+
+		if (len == 0)
+			continue;
+
+		for (i = RESIZE_NUM_MAX - 1; i >= 0; i--) {
+			int j;
+
+			j = i > 9 ? 1 : 0;
+			coeff[j] = (coeff[j] << BC_COEF) |
+					(s[i] & (SZ_COEF - 1));
+
+			if (i == 5 || i == 15)
+				coeff[j] <<= 1;
+
+			valid = (valid << 1) | (s[i] >> BC_COEF);
+		}
+
+		valid |= PRP_RZ_VALID_TBL_LEN(len);
+
+		if (pcdev->resizing[dir].algo == RESIZE_ALGO_BILINEAR)
+			valid |= PRP_RZ_VALID_BILINEAR;
+
+		if (pcdev->emma_prp->cfg.channel == 1) {
+			if (dir == RESIZE_DIR_H) {
+				writel(coeff[0], pcdev->base_emma +
+							PRP_CH1_RZ_HORI_COEF1);
+				writel(coeff[1], pcdev->base_emma +
+							PRP_CH1_RZ_HORI_COEF2);
+				writel(valid, pcdev->base_emma +
+							PRP_CH1_RZ_HORI_VALID);
+			} else {
+				writel(coeff[0], pcdev->base_emma +
+							PRP_CH1_RZ_VERT_COEF1);
+				writel(coeff[1], pcdev->base_emma +
+							PRP_CH1_RZ_VERT_COEF2);
+				writel(valid, pcdev->base_emma +
+							PRP_CH1_RZ_VERT_VALID);
+			}
+		} else {
+			if (dir == RESIZE_DIR_H) {
+				writel(coeff[0], pcdev->base_emma +
+							PRP_CH2_RZ_HORI_COEF1);
+				writel(coeff[1], pcdev->base_emma +
+							PRP_CH2_RZ_HORI_COEF2);
+				writel(valid, pcdev->base_emma +
+							PRP_CH2_RZ_HORI_VALID);
+			} else {
+				writel(coeff[0], pcdev->base_emma +
+							PRP_CH2_RZ_VERT_COEF1);
+				writel(coeff[1], pcdev->base_emma +
+							PRP_CH2_RZ_VERT_COEF2);
+				writel(valid, pcdev->base_emma +
+							PRP_CH2_RZ_VERT_VALID);
+			}
+		}
+	}
+}
+
+static int mx2_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(q);
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
+	struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+	struct vb2_buffer *vb;
+	struct mx2_buffer *buf;
+	unsigned long phys;
+	int bytesperline;
+
+	if (cpu_is_mx27()) {
+		unsigned long flags;
+		if (count < 2)
+			return -EINVAL;
+
+		spin_lock_irqsave(&pcdev->lock, flags);
+
+		buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+				       internal.queue);
+		buf->internal.bufnum = 0;
+		vb = &buf->vb;
+		buf->state = MX2_STATE_ACTIVE;
+
+		phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+		mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum);
+		list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
+
+		buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+				       internal.queue);
+		buf->internal.bufnum = 1;
+		vb = &buf->vb;
+		buf->state = MX2_STATE_ACTIVE;
+
+		phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+		mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum);
+		list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
+
+		bytesperline = soc_mbus_bytes_per_line(icd->user_width,
+				icd->current_fmt->host_fmt);
+		if (bytesperline < 0)
+			return bytesperline;
+
+		/*
+		 * I didn't manage to properly enable/disable the prp
+		 * on a per frame basis during running transfers,
+		 * thus we allocate a buffer here and use it to
+		 * discard frames when no buffer is available.
+		 * Feel free to work on this ;)
+		 */
+		pcdev->discard_size = icd->user_height * bytesperline;
+		pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev,
+				pcdev->discard_size, &pcdev->discard_buffer_dma,
+				GFP_KERNEL);
+		if (!pcdev->discard_buffer)
+			return -ENOMEM;
+
+		pcdev->buf_discard[0].discard = true;
+		list_add_tail(&pcdev->buf_discard[0].queue,
+				      &pcdev->discard);
+
+		pcdev->buf_discard[1].discard = true;
+		list_add_tail(&pcdev->buf_discard[1].queue,
+				      &pcdev->discard);
+
+		mx2_prp_resize_commit(pcdev);
+
+		mx27_camera_emma_buf_init(icd, bytesperline);
+
+		if (prp->cfg.channel == 1) {
+			writel(PRP_CNTL_CH1EN |
+				PRP_CNTL_CSIEN |
+				prp->cfg.in_fmt |
+				prp->cfg.out_fmt |
+				PRP_CNTL_CH1_LEN |
+				PRP_CNTL_CH1BYP |
+				PRP_CNTL_CH1_TSKIP(0) |
+				PRP_CNTL_IN_TSKIP(0),
+				pcdev->base_emma + PRP_CNTL);
+		} else {
+			writel(PRP_CNTL_CH2EN |
+				PRP_CNTL_CSIEN |
+				prp->cfg.in_fmt |
+				prp->cfg.out_fmt |
+				PRP_CNTL_CH2_LEN |
+				PRP_CNTL_CH2_TSKIP(0) |
+				PRP_CNTL_IN_TSKIP(0),
+				pcdev->base_emma + PRP_CNTL);
+		}
+		spin_unlock_irqrestore(&pcdev->lock, flags);
+	}
+
+	return 0;
+}
+
+static int mx2_stop_streaming(struct vb2_queue *q)
+{
+	struct soc_camera_device *icd = soc_camera_from_vb2q(q);
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
+	struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+	unsigned long flags;
+	void *b;
+	u32 cntl;
+
+	if (cpu_is_mx27()) {
+		spin_lock_irqsave(&pcdev->lock, flags);
+
+		cntl = readl(pcdev->base_emma + PRP_CNTL);
+		if (prp->cfg.channel == 1) {
+			writel(cntl & ~PRP_CNTL_CH1EN,
+			       pcdev->base_emma + PRP_CNTL);
+		} else {
+			writel(cntl & ~PRP_CNTL_CH2EN,
+			       pcdev->base_emma + PRP_CNTL);
+		}
+		INIT_LIST_HEAD(&pcdev->capture);
+		INIT_LIST_HEAD(&pcdev->active_bufs);
+		INIT_LIST_HEAD(&pcdev->discard);
+
+		b = pcdev->discard_buffer;
+		pcdev->discard_buffer = NULL;
+
+		spin_unlock_irqrestore(&pcdev->lock, flags);
+
+		dma_free_coherent(ici->v4l2_dev.dev,
+			pcdev->discard_size, b, pcdev->discard_buffer_dma);
+	}
+
+	return 0;
+}
+
+static struct vb2_ops mx2_videobuf_ops = {
+	.queue_setup	 = mx2_videobuf_setup,
+	.buf_prepare	 = mx2_videobuf_prepare,
+	.buf_queue	 = mx2_videobuf_queue,
+	.buf_cleanup	 = mx2_videobuf_release,
+	.start_streaming = mx2_start_streaming,
+	.stop_streaming	 = mx2_stop_streaming,
 };
 
-static void mx2_camera_init_videobuf(struct videobuf_queue *q,
+static int mx2_camera_init_videobuf(struct vb2_queue *q,
 			      struct soc_camera_device *icd)
 {
-	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
-	struct mx2_camera_dev *pcdev = ici->priv;
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_MMAP | VB2_USERPTR;
+	q->drv_priv = icd;
+	q->ops = &mx2_videobuf_ops;
+	q->mem_ops = &vb2_dma_contig_memops;
+	q->buf_struct_size = sizeof(struct mx2_buffer);
 
-	videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev,
-			&pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			V4L2_FIELD_NONE, sizeof(struct mx2_buffer),
-			icd, &icd->video_lock);
+	return vb2_queue_init(q);
 }
 
 #define MX2_BUS_FLAGS	(V4L2_MBUS_MASTER | \
@@ -785,82 +974,6 @@
 	return -ETIMEDOUT;
 }
 
-static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
-		int bytesperline)
-{
-	struct soc_camera_host *ici =
-		to_soc_camera_host(icd->parent);
-	struct mx2_camera_dev *pcdev = ici->priv;
-	struct mx2_fmt_cfg *prp = pcdev->emma_prp;
-	u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width;
-
-	if (prp->cfg.channel == 1) {
-		writel(pcdev->discard_buffer_dma,
-				pcdev->base_emma + PRP_DEST_RGB1_PTR);
-		writel(pcdev->discard_buffer_dma,
-				pcdev->base_emma + PRP_DEST_RGB2_PTR);
-
-		writel(PRP_CNTL_CH1EN |
-				PRP_CNTL_CSIEN |
-				prp->cfg.in_fmt |
-				prp->cfg.out_fmt |
-				PRP_CNTL_CH1_LEN |
-				PRP_CNTL_CH1BYP |
-				PRP_CNTL_CH1_TSKIP(0) |
-				PRP_CNTL_IN_TSKIP(0),
-				pcdev->base_emma + PRP_CNTL);
-
-		writel((icd->user_width << 16) | icd->user_height,
-			pcdev->base_emma + PRP_SRC_FRAME_SIZE);
-		writel((icd->user_width << 16) | icd->user_height,
-			pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE);
-		writel(bytesperline,
-			pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE);
-		writel(prp->cfg.src_pixel,
-			pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
-		writel(prp->cfg.ch1_pixel,
-			pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL);
-	} else { /* channel 2 */
-		writel(pcdev->discard_buffer_dma,
-			pcdev->base_emma + PRP_DEST_Y_PTR);
-		writel(pcdev->discard_buffer_dma,
-			pcdev->base_emma + PRP_SOURCE_Y_PTR);
-
-		if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) {
-			writel(pcdev->discard_buffer_dma + imgsize,
-				pcdev->base_emma + PRP_DEST_CB_PTR);
-			writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4),
-				pcdev->base_emma + PRP_DEST_CR_PTR);
-			writel(pcdev->discard_buffer_dma + imgsize,
-				pcdev->base_emma + PRP_SOURCE_CB_PTR);
-			writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4),
-				pcdev->base_emma + PRP_SOURCE_CR_PTR);
-		}
-
-		writel(PRP_CNTL_CH2EN |
-			PRP_CNTL_CSIEN |
-			prp->cfg.in_fmt |
-			prp->cfg.out_fmt |
-			PRP_CNTL_CH2_LEN |
-			PRP_CNTL_CH2_TSKIP(0) |
-			PRP_CNTL_IN_TSKIP(0),
-			pcdev->base_emma + PRP_CNTL);
-
-		writel((icd->user_width << 16) | icd->user_height,
-			pcdev->base_emma + PRP_SRC_FRAME_SIZE);
-
-		writel((icd->user_width << 16) | icd->user_height,
-			pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE);
-
-		writel(prp->cfg.src_pixel,
-			pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
-
-	}
-
-	/* Enable interrupts */
-	writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL);
-}
-
 static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
 {
 	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -939,31 +1052,10 @@
 	if (bytesperline < 0)
 		return bytesperline;
 
-	if (mx27_camera_emma(pcdev)) {
+	if (cpu_is_mx27()) {
 		ret = mx27_camera_emma_prp_reset(pcdev);
 		if (ret)
 			return ret;
-
-		if (pcdev->discard_buffer)
-			dma_free_coherent(ici->v4l2_dev.dev,
-				pcdev->discard_size, pcdev->discard_buffer,
-				pcdev->discard_buffer_dma);
-
-		/*
-		 * I didn't manage to properly enable/disable the prp
-		 * on a per frame basis during running transfers,
-		 * thus we allocate a buffer here and use it to
-		 * discard frames when no buffer is available.
-		 * Feel free to work on this ;)
-		 */
-		pcdev->discard_size = icd->user_height * bytesperline;
-		pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev,
-				pcdev->discard_size, &pcdev->discard_buffer_dma,
-				GFP_KERNEL);
-		if (!pcdev->discard_buffer)
-			return -ENOMEM;
-
-		mx27_camera_emma_buf_init(icd, bytesperline);
 	} else if (cpu_is_mx25()) {
 		writel((bytesperline * icd->user_height) >> 2,
 				pcdev->base_csi + CSIRXCNT);
@@ -1052,6 +1144,123 @@
 	return formats;
 }
 
+static int mx2_emmaprp_resize(struct mx2_camera_dev *pcdev,
+			      struct v4l2_mbus_framefmt *mf_in,
+			      struct v4l2_pix_format *pix_out, bool apply)
+{
+	int num, den;
+	unsigned long m;
+	int i, dir;
+
+	for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) {
+		struct emma_prp_resize tmprsz;
+		unsigned char *s = tmprsz.s;
+		int len = 0;
+		int in, out;
+
+		if (dir == RESIZE_DIR_H) {
+			in = mf_in->width;
+			out = pix_out->width;
+		} else {
+			in = mf_in->height;
+			out = pix_out->height;
+		}
+
+		if (in < out)
+			return -EINVAL;
+		else if (in == out)
+			continue;
+
+		/* Calculate ratio */
+		m = gcd(in, out);
+		num = in / m;
+		den = out / m;
+		if (num > RESIZE_NUM_MAX)
+			return -EINVAL;
+
+		if ((num >= 2 * den) && (den == 1) &&
+		    (num < 9) && (!(num & 0x01))) {
+			int sum = 0;
+			int j;
+
+			/* Average scaling for >= 2:1 ratios */
+			/* Support can be added for num >=9 and odd values */
+
+			tmprsz.algo = RESIZE_ALGO_AVERAGING;
+			len = num;
+
+			for (i = 0; i < (len / 2); i++)
+				s[i] = 8;
+
+			do {
+				for (i = 0; i < (len / 2); i++) {
+					s[i] = s[i] >> 1;
+					sum = 0;
+					for (j = 0; j < (len / 2); j++)
+						sum += s[j];
+					if (sum == 4)
+						break;
+				}
+			} while (sum != 4);
+
+			for (i = (len / 2); i < len; i++)
+				s[i] = s[len - i - 1];
+
+			s[len - 1] |= SZ_COEF;
+		} else {
+			/* bilinear scaling for < 2:1 ratios */
+			int v; /* overflow counter */
+			int coeff, nxt; /* table output */
+			int in_pos_inc = 2 * den;
+			int out_pos = num;
+			int out_pos_inc = 2 * num;
+			int init_carry = num - den;
+			int carry = init_carry;
+
+			tmprsz.algo = RESIZE_ALGO_BILINEAR;
+			v = den + in_pos_inc;
+			do {
+				coeff = v - out_pos;
+				out_pos += out_pos_inc;
+				carry += out_pos_inc;
+				for (nxt = 0; v < out_pos; nxt++) {
+					v += in_pos_inc;
+					carry -= in_pos_inc;
+				}
+
+				if (len > RESIZE_NUM_MAX)
+					return -EINVAL;
+
+				coeff = ((coeff << BC_COEF) +
+					(in_pos_inc >> 1)) / in_pos_inc;
+
+				if (coeff >= (SZ_COEF - 1))
+					coeff--;
+
+				coeff |= SZ_COEF;
+				s[len] = (unsigned char)coeff;
+				len++;
+
+				for (i = 1; i < nxt; i++) {
+					if (len >= RESIZE_NUM_MAX)
+						return -EINVAL;
+					s[len] = 0;
+					len++;
+				}
+			} while (carry != init_carry);
+		}
+		tmprsz.len = len;
+		if (dir == RESIZE_DIR_H)
+			mf_in->width = pix_out->width;
+		else
+			mf_in->height = pix_out->height;
+
+		if (apply)
+			memcpy(&pcdev->resizing[dir], &tmprsz, sizeof(tmprsz));
+	}
+	return 0;
+}
+
 static int mx2_camera_set_fmt(struct soc_camera_device *icd,
 			       struct v4l2_format *f)
 {
@@ -1063,6 +1272,9 @@
 	struct v4l2_mbus_framefmt mf;
 	int ret;
 
+	dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n",
+		__func__, pix->width, pix->height);
+
 	xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
 	if (!xlate) {
 		dev_warn(icd->parent, "Format %x not found\n",
@@ -1080,6 +1292,22 @@
 	if (ret < 0 && ret != -ENOIOCTLCMD)
 		return ret;
 
+	/* Store width and height returned by the sensor for resizing */
+	pcdev->s_width = mf.width;
+	pcdev->s_height = mf.height;
+	dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n",
+		__func__, pcdev->s_width, pcdev->s_height);
+
+	pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
+						   xlate->host_fmt->fourcc);
+
+	memset(pcdev->resizing, 0, sizeof(pcdev->resizing));
+	if ((mf.width != pix->width || mf.height != pix->height) &&
+		pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) {
+		if (mx2_emmaprp_resize(pcdev, &mf, pix, true) < 0)
+			dev_dbg(icd->parent, "%s: can't resize\n", __func__);
+	}
+
 	if (mf.code != xlate->code)
 		return -EINVAL;
 
@@ -1089,9 +1317,8 @@
 	pix->colorspace		= mf.colorspace;
 	icd->current_fmt	= xlate;
 
-	if (mx27_camera_emma(pcdev))
-		pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
-						xlate->host_fmt->fourcc);
+	dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n",
+		__func__, pix->width, pix->height);
 
 	return 0;
 }
@@ -1104,9 +1331,14 @@
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 	struct v4l2_mbus_framefmt mf;
 	__u32 pixfmt = pix->pixelformat;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct mx2_camera_dev *pcdev = ici->priv;
 	unsigned int width_limit;
 	int ret;
 
+	dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n",
+		__func__, pix->width, pix->height);
+
 	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
 	if (pixfmt && !xlate) {
 		dev_warn(icd->parent, "Format %x not found\n", pixfmt);
@@ -1156,6 +1388,20 @@
 	if (ret < 0)
 		return ret;
 
+	dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n",
+		__func__, pcdev->s_width, pcdev->s_height);
+
+	/* If the sensor does not support image size try PrP resizing */
+	pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
+						   xlate->host_fmt->fourcc);
+
+	memset(pcdev->resizing, 0, sizeof(pcdev->resizing));
+	if ((mf.width != pix->width || mf.height != pix->height) &&
+		pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) {
+		if (mx2_emmaprp_resize(pcdev, &mf, pix, false) < 0)
+			dev_dbg(icd->parent, "%s: can't resize\n", __func__);
+	}
+
 	if (mf.field == V4L2_FIELD_ANY)
 		mf.field = V4L2_FIELD_NONE;
 	/*
@@ -1174,6 +1420,9 @@
 	pix->field	= mf.field;
 	pix->colorspace	= mf.colorspace;
 
+	dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n",
+		__func__, pix->width, pix->height);
+
 	return 0;
 }
 
@@ -1187,136 +1436,11 @@
 	return 0;
 }
 
-static int mx2_camera_reqbufs(struct soc_camera_device *icd,
-			      struct v4l2_requestbuffers *p)
-{
-	int i;
-
-	for (i = 0; i < p->count; i++) {
-		struct mx2_buffer *buf = container_of(icd->vb_vidq.bufs[i],
-						      struct mx2_buffer, vb);
-		INIT_LIST_HEAD(&buf->vb.queue);
-	}
-
-	return 0;
-}
-
-#ifdef CONFIG_MACH_MX27
-static void mx27_camera_frame_done(struct mx2_camera_dev *pcdev, int state)
-{
-	struct videobuf_buffer *vb;
-	struct mx2_buffer *buf;
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&pcdev->lock, flags);
-
-	if (!pcdev->active) {
-		dev_err(pcdev->dev, "%s called with no active buffer!\n",
-				__func__);
-		goto out;
-	}
-
-	vb = &pcdev->active->vb;
-	buf = container_of(vb, struct mx2_buffer, vb);
-	WARN_ON(list_empty(&vb->queue));
-	dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
-		vb, vb->baddr, vb->bsize);
-
-	/* _init is used to debug races, see comment in pxa_camera_reqbufs() */
-	list_del_init(&vb->queue);
-	vb->state = state;
-	do_gettimeofday(&vb->ts);
-	vb->field_count++;
-
-	wake_up(&vb->done);
-
-	if (list_empty(&pcdev->capture)) {
-		pcdev->active = NULL;
-		goto out;
-	}
-
-	pcdev->active = list_entry(pcdev->capture.next,
-			struct mx2_buffer, vb.queue);
-
-	vb = &pcdev->active->vb;
-	vb->state = VIDEOBUF_ACTIVE;
-
-	ret = imx_dma_setup_single(pcdev->dma, videobuf_to_dma_contig(vb),
-			vb->size, (u32)pcdev->base_dma + 0x10, DMA_MODE_READ);
-
-	if (ret) {
-		vb->state = VIDEOBUF_ERROR;
-		pcdev->active = NULL;
-		wake_up(&vb->done);
-	}
-
-out:
-	spin_unlock_irqrestore(&pcdev->lock, flags);
-}
-
-static void mx27_camera_dma_err_callback(int channel, void *data, int err)
-{
-	struct mx2_camera_dev *pcdev = data;
-
-	mx27_camera_frame_done(pcdev, VIDEOBUF_ERROR);
-}
-
-static void mx27_camera_dma_callback(int channel, void *data)
-{
-	struct mx2_camera_dev *pcdev = data;
-
-	mx27_camera_frame_done(pcdev, VIDEOBUF_DONE);
-}
-
-#define DMA_REQ_CSI_RX          31 /* FIXME: Add this to a resource */
-
-static int __devinit mx27_camera_dma_init(struct platform_device *pdev,
-		struct mx2_camera_dev *pcdev)
-{
-	int err;
-
-	pcdev->dma = imx_dma_request_by_prio("CSI RX DMA", DMA_PRIO_HIGH);
-	if (pcdev->dma < 0) {
-		dev_err(&pdev->dev, "%s failed to request DMA channel\n",
-				__func__);
-		return pcdev->dma;
-	}
-
-	err = imx_dma_setup_handlers(pcdev->dma, mx27_camera_dma_callback,
-					mx27_camera_dma_err_callback, pcdev);
-	if (err) {
-		dev_err(&pdev->dev, "%s failed to set DMA callback\n",
-				__func__);
-		goto err_out;
-	}
-
-	err = imx_dma_config_channel(pcdev->dma,
-			IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO,
-			IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
-			DMA_REQ_CSI_RX, 1);
-	if (err) {
-		dev_err(&pdev->dev, "%s failed to config DMA channel\n",
-				__func__);
-		goto err_out;
-	}
-
-	imx_dma_config_burstlen(pcdev->dma, 64);
-
-	return 0;
-
-err_out:
-	imx_dma_free(pcdev->dma);
-
-	return err;
-}
-#endif /* CONFIG_MACH_MX27 */
-
 static unsigned int mx2_camera_poll(struct file *file, poll_table *pt)
 {
 	struct soc_camera_device *icd = file->private_data;
 
-	return videobuf_poll_stream(file, &icd->vb_vidq, pt);
+	return vb2_poll(&icd->vb2_vidq, file, pt);
 }
 
 static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
@@ -1327,144 +1451,148 @@
 	.set_crop	= mx2_camera_set_crop,
 	.get_formats	= mx2_camera_get_formats,
 	.try_fmt	= mx2_camera_try_fmt,
-	.init_videobuf	= mx2_camera_init_videobuf,
-	.reqbufs	= mx2_camera_reqbufs,
+	.init_videobuf2	= mx2_camera_init_videobuf,
 	.poll		= mx2_camera_poll,
 	.querycap	= mx2_camera_querycap,
 	.set_bus_param	= mx2_camera_set_bus_param,
 };
 
 static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
-		int bufnum, int state)
+		int bufnum, bool err)
 {
-	u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width;
+#ifdef DEBUG
 	struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+#endif
+	struct mx2_buf_internal *ibuf;
 	struct mx2_buffer *buf;
-	struct videobuf_buffer *vb;
+	struct vb2_buffer *vb;
 	unsigned long phys;
 
-	if (!list_empty(&pcdev->active_bufs)) {
-		buf = list_entry(pcdev->active_bufs.next,
-			struct mx2_buffer, vb.queue);
+	ibuf = list_first_entry(&pcdev->active_bufs, struct mx2_buf_internal,
+			       queue);
 
-		BUG_ON(buf->bufnum != bufnum);
+	BUG_ON(ibuf->bufnum != bufnum);
+
+	if (ibuf->discard) {
+		/*
+		 * Discard buffer must not be returned to user space.
+		 * Just return it to the discard queue.
+		 */
+		list_move_tail(pcdev->active_bufs.next, &pcdev->discard);
+	} else {
+		buf = mx2_ibuf_to_buf(ibuf);
 
 		vb = &buf->vb;
 #ifdef DEBUG
-		phys = videobuf_to_dma_contig(vb);
+		phys = vb2_dma_contig_plane_dma_addr(vb, 0);
 		if (prp->cfg.channel == 1) {
 			if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR +
 				4 * bufnum) != phys) {
-				dev_err(pcdev->dev, "%p != %p\n", phys,
-						readl(pcdev->base_emma +
-							PRP_DEST_RGB1_PTR +
-							4 * bufnum));
+				dev_err(pcdev->dev, "%lx != %x\n", phys,
+					readl(pcdev->base_emma +
+					PRP_DEST_RGB1_PTR + 4 * bufnum));
 			}
 		} else {
 			if (readl(pcdev->base_emma + PRP_DEST_Y_PTR -
 				0x14 * bufnum) != phys) {
-				dev_err(pcdev->dev, "%p != %p\n", phys,
-						readl(pcdev->base_emma +
-							PRP_DEST_Y_PTR -
-							0x14 * bufnum));
+				dev_err(pcdev->dev, "%lx != %x\n", phys,
+					readl(pcdev->base_emma +
+					PRP_DEST_Y_PTR - 0x14 * bufnum));
 			}
 		}
 #endif
-		dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb,
-				vb->baddr, vb->bsize);
+		dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb,
+				vb2_plane_vaddr(vb, 0),
+				vb2_get_plane_payload(vb, 0));
 
-		list_del(&vb->queue);
-		vb->state = state;
-		do_gettimeofday(&vb->ts);
-		vb->field_count = pcdev->frame_count * 2;
-		pcdev->frame_count++;
-
-		wake_up(&vb->done);
+		list_del_init(&buf->internal.queue);
+		do_gettimeofday(&vb->v4l2_buf.timestamp);
+		vb->v4l2_buf.sequence = pcdev->frame_count;
+		if (err)
+			vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+		else
+			vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
 	}
 
+	pcdev->frame_count++;
+
 	if (list_empty(&pcdev->capture)) {
-		if (prp->cfg.channel == 1) {
-			writel(pcdev->discard_buffer_dma, pcdev->base_emma +
-					PRP_DEST_RGB1_PTR + 4 * bufnum);
-		} else {
-			writel(pcdev->discard_buffer_dma, pcdev->base_emma +
-						PRP_DEST_Y_PTR -
-						0x14 * bufnum);
-			if (prp->out_fmt == V4L2_PIX_FMT_YUV420) {
-				writel(pcdev->discard_buffer_dma + imgsize,
-				       pcdev->base_emma + PRP_DEST_CB_PTR -
-				       0x14 * bufnum);
-				writel(pcdev->discard_buffer_dma +
-				       ((5 * imgsize) / 4), pcdev->base_emma +
-				       PRP_DEST_CR_PTR - 0x14 * bufnum);
-			}
+		if (list_empty(&pcdev->discard)) {
+			dev_warn(pcdev->dev, "%s: trying to access empty discard list\n",
+				 __func__);
+			return;
 		}
+
+		ibuf = list_first_entry(&pcdev->discard,
+					struct mx2_buf_internal, queue);
+		ibuf->bufnum = bufnum;
+
+		list_move_tail(pcdev->discard.next, &pcdev->active_bufs);
+		mx27_update_emma_buf(pcdev, pcdev->discard_buffer_dma, bufnum);
 		return;
 	}
 
-	buf = list_entry(pcdev->capture.next,
-			struct mx2_buffer, vb.queue);
+	buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+			       internal.queue);
 
-	buf->bufnum = !bufnum;
+	buf->internal.bufnum = bufnum;
 
 	list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
 
 	vb = &buf->vb;
-	vb->state = VIDEOBUF_ACTIVE;
+	buf->state = MX2_STATE_ACTIVE;
 
-	phys = videobuf_to_dma_contig(vb);
-	if (prp->cfg.channel == 1) {
-		writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum);
-	} else {
-		writel(phys, pcdev->base_emma +
-				PRP_DEST_Y_PTR - 0x14 * bufnum);
-		if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) {
-			writel(phys + imgsize, pcdev->base_emma +
-					PRP_DEST_CB_PTR - 0x14 * bufnum);
-			writel(phys + ((5 * imgsize) / 4), pcdev->base_emma +
-					PRP_DEST_CR_PTR - 0x14 * bufnum);
-		}
-	}
+	phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+	mx27_update_emma_buf(pcdev, phys, bufnum);
 }
 
 static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
 {
 	struct mx2_camera_dev *pcdev = data;
 	unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS);
-	struct mx2_buffer *buf;
+	struct mx2_buf_internal *ibuf;
+
+	spin_lock(&pcdev->lock);
+
+	if (list_empty(&pcdev->active_bufs)) {
+		dev_warn(pcdev->dev, "%s: called while active list is empty\n",
+			__func__);
+
+		if (!status) {
+			spin_unlock(&pcdev->lock);
+			return IRQ_NONE;
+		}
+	}
 
 	if (status & (1 << 7)) { /* overflow */
-		u32 cntl;
-		/*
-		 * We only disable channel 1 here since this is the only
-		 * enabled channel
-		 *
-		 * FIXME: the correct DMA overflow handling should be resetting
-		 * the buffer, returning an error frame, and continuing with
-		 * the next one.
-		 */
-		cntl = readl(pcdev->base_emma + PRP_CNTL);
+		u32 cntl = readl(pcdev->base_emma + PRP_CNTL);
 		writel(cntl & ~(PRP_CNTL_CH1EN | PRP_CNTL_CH2EN),
 		       pcdev->base_emma + PRP_CNTL);
 		writel(cntl, pcdev->base_emma + PRP_CNTL);
-	}
-	if ((((status & (3 << 5)) == (3 << 5)) ||
-		((status & (3 << 3)) == (3 << 3)))
-			&& !list_empty(&pcdev->active_bufs)) {
+
+		ibuf = list_first_entry(&pcdev->active_bufs,
+					struct mx2_buf_internal, queue);
+		mx27_camera_frame_done_emma(pcdev,
+					ibuf->bufnum, true);
+
+		status &= ~(1 << 7);
+	} else if (((status & (3 << 5)) == (3 << 5)) ||
+		((status & (3 << 3)) == (3 << 3))) {
 		/*
 		 * Both buffers have triggered, process the one we're expecting
 		 * to first
 		 */
-		buf = list_entry(pcdev->active_bufs.next,
-			struct mx2_buffer, vb.queue);
-		mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE);
-		status &= ~(1 << (6 - buf->bufnum)); /* mark processed */
+		ibuf = list_first_entry(&pcdev->active_bufs,
+					struct mx2_buf_internal, queue);
+		mx27_camera_frame_done_emma(pcdev, ibuf->bufnum, false);
+		status &= ~(1 << (6 - ibuf->bufnum)); /* mark processed */
+	} else if ((status & (1 << 6)) || (status & (1 << 4))) {
+		mx27_camera_frame_done_emma(pcdev, 0, false);
+	} else if ((status & (1 << 5)) || (status & (1 << 3))) {
+		mx27_camera_frame_done_emma(pcdev, 1, false);
 	}
-	if ((status & (1 << 6)) || (status & (1 << 4)))
-		mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE);
-	if ((status & (1 << 5)) || (status & (1 << 3)))
-		mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE);
 
+	spin_unlock(&pcdev->lock);
 	writel(status, pcdev->base_emma + PRP_INTRSTATUS);
 
 	return IRQ_HANDLED;
@@ -1527,8 +1655,6 @@
 	struct resource *res_csi, *res_emma;
 	void __iomem *base_csi;
 	int irq_csi, irq_emma;
-	irq_handler_t mx2_cam_irq_handler = cpu_is_mx25() ? mx25_camera_irq
-		: mx27_camera_irq;
 	int err = 0;
 
 	dev_dbg(&pdev->dev, "initialising\n");
@@ -1550,22 +1676,11 @@
 
 	pcdev->clk_csi = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(pcdev->clk_csi)) {
+		dev_err(&pdev->dev, "Could not get csi clock\n");
 		err = PTR_ERR(pcdev->clk_csi);
 		goto exit_kfree;
 	}
 
-	dev_dbg(&pdev->dev, "Camera clock frequency: %ld\n",
-			clk_get_rate(pcdev->clk_csi));
-
-	/* Initialize DMA */
-#ifdef CONFIG_MACH_MX27
-	if (cpu_is_mx27()) {
-		err = mx27_camera_dma_init(pdev, pcdev);
-		if (err)
-			goto exit_clk_put;
-	}
-#endif /* CONFIG_MACH_MX27 */
-
 	pcdev->res_csi = res_csi;
 	pcdev->pdata = pdev->dev.platform_data;
 	if (pcdev->pdata) {
@@ -1585,6 +1700,7 @@
 
 	INIT_LIST_HEAD(&pcdev->capture);
 	INIT_LIST_HEAD(&pcdev->active_bufs);
+	INIT_LIST_HEAD(&pcdev->discard);
 	spin_lock_init(&pcdev->lock);
 
 	/*
@@ -1606,11 +1722,13 @@
 	pcdev->base_dma = res_csi->start;
 	pcdev->dev = &pdev->dev;
 
-	err = request_irq(pcdev->irq_csi, mx2_cam_irq_handler, 0,
-			MX2_CAM_DRV_NAME, pcdev);
-	if (err) {
-		dev_err(pcdev->dev, "Camera interrupt register failed \n");
-		goto exit_iounmap;
+	if (cpu_is_mx25()) {
+		err = request_irq(pcdev->irq_csi, mx25_camera_irq, 0,
+				MX2_CAM_DRV_NAME, pcdev);
+		if (err) {
+			dev_err(pcdev->dev, "Camera interrupt register failed \n");
+			goto exit_iounmap;
+		}
 	}
 
 	if (cpu_is_mx27()) {
@@ -1618,14 +1736,15 @@
 		res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 		irq_emma = platform_get_irq(pdev, 1);
 
-		if (res_emma && irq_emma >= 0) {
-			dev_info(&pdev->dev, "Using EMMA\n");
-			pcdev->use_emma = 1;
-			pcdev->res_emma = res_emma;
-			pcdev->irq_emma = irq_emma;
-			if (mx27_camera_emma_init(pcdev))
-				goto exit_free_irq;
+		if (!res_emma || !irq_emma) {
+			dev_err(&pdev->dev, "no EMMA resources\n");
+			goto exit_free_irq;
 		}
+
+		pcdev->res_emma = res_emma;
+		pcdev->irq_emma = irq_emma;
+		if (mx27_camera_emma_init(pcdev))
+			goto exit_free_irq;
 	}
 
 	pcdev->soc_host.drv_name	= MX2_CAM_DRV_NAME,
@@ -1633,6 +1752,12 @@
 	pcdev->soc_host.priv		= pcdev;
 	pcdev->soc_host.v4l2_dev.dev	= &pdev->dev;
 	pcdev->soc_host.nr		= pdev->id;
+
+	pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(pcdev->alloc_ctx)) {
+		err = PTR_ERR(pcdev->alloc_ctx);
+		goto eallocctx;
+	}
 	err = soc_camera_host_register(&pcdev->soc_host);
 	if (err)
 		goto exit_free_emma;
@@ -1643,26 +1768,24 @@
 	return 0;
 
 exit_free_emma:
-	if (mx27_camera_emma(pcdev)) {
+	vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+eallocctx:
+	if (cpu_is_mx27()) {
 		free_irq(pcdev->irq_emma, pcdev);
 		clk_disable(pcdev->clk_emma);
 		clk_put(pcdev->clk_emma);
 		iounmap(pcdev->base_emma);
-		release_mem_region(res_emma->start, resource_size(res_emma));
+		release_mem_region(pcdev->res_emma->start, resource_size(pcdev->res_emma));
 	}
 exit_free_irq:
-	free_irq(pcdev->irq_csi, pcdev);
+	if (cpu_is_mx25())
+		free_irq(pcdev->irq_csi, pcdev);
 exit_iounmap:
 	iounmap(base_csi);
 exit_release:
 	release_mem_region(res_csi->start, resource_size(res_csi));
 exit_dma_free:
-#ifdef CONFIG_MACH_MX27
-	if (cpu_is_mx27())
-		imx_dma_free(pcdev->dma);
-exit_clk_put:
 	clk_put(pcdev->clk_csi);
-#endif /* CONFIG_MACH_MX27 */
 exit_kfree:
 	kfree(pcdev);
 exit:
@@ -1677,19 +1800,18 @@
 	struct resource *res;
 
 	clk_put(pcdev->clk_csi);
-#ifdef CONFIG_MACH_MX27
+	if (cpu_is_mx25())
+		free_irq(pcdev->irq_csi, pcdev);
 	if (cpu_is_mx27())
-		imx_dma_free(pcdev->dma);
-#endif /* CONFIG_MACH_MX27 */
-	free_irq(pcdev->irq_csi, pcdev);
-	if (mx27_camera_emma(pcdev))
 		free_irq(pcdev->irq_emma, pcdev);
 
 	soc_camera_host_unregister(&pcdev->soc_host);
 
+	vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+
 	iounmap(pcdev->base_csi);
 
-	if (mx27_camera_emma(pcdev)) {
+	if (cpu_is_mx27()) {
 		clk_disable(pcdev->clk_emma);
 		clk_put(pcdev->clk_emma);
 		iounmap(pcdev->base_emma);
diff --git a/drivers/media/video/mx2_emmaprp.c b/drivers/media/video/mx2_emmaprp.c
new file mode 100644
index 0000000..ba89a74
--- /dev/null
+++ b/drivers/media/video/mx2_emmaprp.c
@@ -0,0 +1,1008 @@
+/*
+ * Support eMMa-PrP through mem2mem framework.
+ *
+ * eMMa-PrP is a piece of HW that allows fetching buffers
+ * from one memory location and do several operations on
+ * them such as scaling or format conversion giving, as a result
+ * a new processed buffer in another memory location.
+ *
+ * Based on mem2mem_testdev.c by Pawel Osciak.
+ *
+ * Copyright (c) 2011 Vista Silicon S.L.
+ * Javier Martin <javier.martin@vista-silicon.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/clk.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <linux/platform_device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+#include <asm/sizes.h>
+
+#define EMMAPRP_MODULE_NAME "mem2mem-emmaprp"
+
+MODULE_DESCRIPTION("Mem-to-mem device which supports eMMa-PrP present in mx2 SoCs");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.1");
+
+static bool debug;
+module_param(debug, bool, 0644);
+
+#define MIN_W 32
+#define MIN_H 32
+#define MAX_W 2040
+#define MAX_H 2046
+
+#define S_ALIGN		1 /* multiple of 2 */
+#define W_ALIGN_YUV420	3 /* multiple of 8 */
+#define W_ALIGN_OTHERS	2 /* multiple of 4 */
+#define H_ALIGN		1 /* multiple of 2 */
+
+/* Flags that indicate a format can be used for capture/output */
+#define MEM2MEM_CAPTURE	(1 << 0)
+#define MEM2MEM_OUTPUT	(1 << 1)
+
+#define MEM2MEM_NAME		"m2m-emmaprp"
+
+/* In bytes, per queue */
+#define MEM2MEM_VID_MEM_LIMIT	SZ_16M
+
+#define dprintk(dev, fmt, arg...) \
+	v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+
+/* EMMA PrP */
+#define PRP_CNTL                        0x00
+#define PRP_INTR_CNTL                   0x04
+#define PRP_INTRSTATUS                  0x08
+#define PRP_SOURCE_Y_PTR                0x0c
+#define PRP_SOURCE_CB_PTR               0x10
+#define PRP_SOURCE_CR_PTR               0x14
+#define PRP_DEST_RGB1_PTR               0x18
+#define PRP_DEST_RGB2_PTR               0x1c
+#define PRP_DEST_Y_PTR                  0x20
+#define PRP_DEST_CB_PTR                 0x24
+#define PRP_DEST_CR_PTR                 0x28
+#define PRP_SRC_FRAME_SIZE              0x2c
+#define PRP_DEST_CH1_LINE_STRIDE        0x30
+#define PRP_SRC_PIXEL_FORMAT_CNTL       0x34
+#define PRP_CH1_PIXEL_FORMAT_CNTL       0x38
+#define PRP_CH1_OUT_IMAGE_SIZE          0x3c
+#define PRP_CH2_OUT_IMAGE_SIZE          0x40
+#define PRP_SRC_LINE_STRIDE             0x44
+#define PRP_CSC_COEF_012                0x48
+#define PRP_CSC_COEF_345                0x4c
+#define PRP_CSC_COEF_678                0x50
+#define PRP_CH1_RZ_HORI_COEF1           0x54
+#define PRP_CH1_RZ_HORI_COEF2           0x58
+#define PRP_CH1_RZ_HORI_VALID           0x5c
+#define PRP_CH1_RZ_VERT_COEF1           0x60
+#define PRP_CH1_RZ_VERT_COEF2           0x64
+#define PRP_CH1_RZ_VERT_VALID           0x68
+#define PRP_CH2_RZ_HORI_COEF1           0x6c
+#define PRP_CH2_RZ_HORI_COEF2           0x70
+#define PRP_CH2_RZ_HORI_VALID           0x74
+#define PRP_CH2_RZ_VERT_COEF1           0x78
+#define PRP_CH2_RZ_VERT_COEF2           0x7c
+#define PRP_CH2_RZ_VERT_VALID           0x80
+
+#define PRP_CNTL_CH1EN          (1 << 0)
+#define PRP_CNTL_CH2EN          (1 << 1)
+#define PRP_CNTL_CSIEN          (1 << 2)
+#define PRP_CNTL_DATA_IN_YUV420 (0 << 3)
+#define PRP_CNTL_DATA_IN_YUV422 (1 << 3)
+#define PRP_CNTL_DATA_IN_RGB16  (2 << 3)
+#define PRP_CNTL_DATA_IN_RGB32  (3 << 3)
+#define PRP_CNTL_CH1_OUT_RGB8   (0 << 5)
+#define PRP_CNTL_CH1_OUT_RGB16  (1 << 5)
+#define PRP_CNTL_CH1_OUT_RGB32  (2 << 5)
+#define PRP_CNTL_CH1_OUT_YUV422 (3 << 5)
+#define PRP_CNTL_CH2_OUT_YUV420 (0 << 7)
+#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7)
+#define PRP_CNTL_CH2_OUT_YUV444 (2 << 7)
+#define PRP_CNTL_CH1_LEN        (1 << 9)
+#define PRP_CNTL_CH2_LEN        (1 << 10)
+#define PRP_CNTL_SKIP_FRAME     (1 << 11)
+#define PRP_CNTL_SWRST          (1 << 12)
+#define PRP_CNTL_CLKEN          (1 << 13)
+#define PRP_CNTL_WEN            (1 << 14)
+#define PRP_CNTL_CH1BYP         (1 << 15)
+#define PRP_CNTL_IN_TSKIP(x)    ((x) << 16)
+#define PRP_CNTL_CH1_TSKIP(x)   ((x) << 19)
+#define PRP_CNTL_CH2_TSKIP(x)   ((x) << 22)
+#define PRP_CNTL_INPUT_FIFO_LEVEL(x)    ((x) << 25)
+#define PRP_CNTL_RZ_FIFO_LEVEL(x)       ((x) << 27)
+#define PRP_CNTL_CH2B1EN        (1 << 29)
+#define PRP_CNTL_CH2B2EN        (1 << 30)
+#define PRP_CNTL_CH2FEN         (1 << 31)
+
+#define PRP_SIZE_HEIGHT(x)	(x)
+#define PRP_SIZE_WIDTH(x)	((x) << 16)
+
+/* IRQ Enable and status register */
+#define PRP_INTR_RDERR          (1 << 0)
+#define PRP_INTR_CH1WERR        (1 << 1)
+#define PRP_INTR_CH2WERR        (1 << 2)
+#define PRP_INTR_CH1FC          (1 << 3)
+#define PRP_INTR_CH2FC          (1 << 5)
+#define PRP_INTR_LBOVF          (1 << 7)
+#define PRP_INTR_CH2OVF         (1 << 8)
+
+#define PRP_INTR_ST_RDERR	(1 << 0)
+#define PRP_INTR_ST_CH1WERR	(1 << 1)
+#define PRP_INTR_ST_CH2WERR	(1 << 2)
+#define PRP_INTR_ST_CH2B2CI	(1 << 3)
+#define PRP_INTR_ST_CH2B1CI	(1 << 4)
+#define PRP_INTR_ST_CH1B2CI	(1 << 5)
+#define PRP_INTR_ST_CH1B1CI	(1 << 6)
+#define PRP_INTR_ST_LBOVF	(1 << 7)
+#define PRP_INTR_ST_CH2OVF	(1 << 8)
+
+struct emmaprp_fmt {
+	char	*name;
+	u32	fourcc;
+	/* Types the format can be used for */
+	u32	types;
+};
+
+static struct emmaprp_fmt formats[] = {
+	{
+		.name	= "YUV 4:2:0 Planar",
+		.fourcc	= V4L2_PIX_FMT_YUV420,
+		.types	= MEM2MEM_CAPTURE,
+	},
+	{
+		.name	= "4:2:2, packed, YUYV",
+		.fourcc	= V4L2_PIX_FMT_YUYV,
+		.types	= MEM2MEM_OUTPUT,
+	},
+};
+
+/* Per-queue, driver-specific private data */
+struct emmaprp_q_data {
+	unsigned int		width;
+	unsigned int		height;
+	unsigned int		sizeimage;
+	struct emmaprp_fmt	*fmt;
+};
+
+enum {
+	V4L2_M2M_SRC = 0,
+	V4L2_M2M_DST = 1,
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+static struct emmaprp_fmt *find_format(struct v4l2_format *f)
+{
+	struct emmaprp_fmt *fmt;
+	unsigned int k;
+
+	for (k = 0; k < NUM_FORMATS; k++) {
+		fmt = &formats[k];
+		if (fmt->fourcc == f->fmt.pix.pixelformat)
+			break;
+	}
+
+	if (k == NUM_FORMATS)
+		return NULL;
+
+	return &formats[k];
+}
+
+struct emmaprp_dev {
+	struct v4l2_device	v4l2_dev;
+	struct video_device	*vfd;
+
+	struct mutex		dev_mutex;
+	spinlock_t		irqlock;
+
+	int			irq_emma;
+	void __iomem		*base_emma;
+	struct clk		*clk_emma;
+	struct resource		*res_emma;
+
+	struct v4l2_m2m_dev	*m2m_dev;
+	struct vb2_alloc_ctx	*alloc_ctx;
+};
+
+struct emmaprp_ctx {
+	struct emmaprp_dev	*dev;
+	/* Abort requested by m2m */
+	int			aborting;
+	struct emmaprp_q_data	q_data[2];
+	struct v4l2_m2m_ctx	*m2m_ctx;
+};
+
+static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx,
+					 enum v4l2_buf_type type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		return &(ctx->q_data[V4L2_M2M_SRC]);
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &(ctx->q_data[V4L2_M2M_DST]);
+	default:
+		BUG();
+	}
+	return NULL;
+}
+
+/*
+ * mem2mem callbacks
+ */
+static void emmaprp_job_abort(void *priv)
+{
+	struct emmaprp_ctx *ctx = priv;
+	struct emmaprp_dev *pcdev = ctx->dev;
+
+	ctx->aborting = 1;
+
+	dprintk(pcdev, "Aborting task\n");
+
+	v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx);
+}
+
+static void emmaprp_lock(void *priv)
+{
+	struct emmaprp_ctx *ctx = priv;
+	struct emmaprp_dev *pcdev = ctx->dev;
+	mutex_lock(&pcdev->dev_mutex);
+}
+
+static void emmaprp_unlock(void *priv)
+{
+	struct emmaprp_ctx *ctx = priv;
+	struct emmaprp_dev *pcdev = ctx->dev;
+	mutex_unlock(&pcdev->dev_mutex);
+}
+
+static inline void emmaprp_dump_regs(struct emmaprp_dev *pcdev)
+{
+	dprintk(pcdev,
+		"eMMa-PrP Registers:\n"
+		"  SOURCE_Y_PTR = 0x%08X\n"
+		"  SRC_FRAME_SIZE = 0x%08X\n"
+		"  DEST_Y_PTR = 0x%08X\n"
+		"  DEST_CR_PTR = 0x%08X\n"
+		"  DEST_CB_PTR = 0x%08X\n"
+		"  CH2_OUT_IMAGE_SIZE = 0x%08X\n"
+		"  CNTL = 0x%08X\n",
+		readl(pcdev->base_emma + PRP_SOURCE_Y_PTR),
+		readl(pcdev->base_emma + PRP_SRC_FRAME_SIZE),
+		readl(pcdev->base_emma + PRP_DEST_Y_PTR),
+		readl(pcdev->base_emma + PRP_DEST_CR_PTR),
+		readl(pcdev->base_emma + PRP_DEST_CB_PTR),
+		readl(pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE),
+		readl(pcdev->base_emma + PRP_CNTL));
+}
+
+static void emmaprp_device_run(void *priv)
+{
+	struct emmaprp_ctx *ctx = priv;
+	struct emmaprp_q_data *s_q_data, *d_q_data;
+	struct vb2_buffer *src_buf, *dst_buf;
+	struct emmaprp_dev *pcdev = ctx->dev;
+	unsigned int s_width, s_height;
+	unsigned int d_width, d_height;
+	unsigned int d_size;
+	dma_addr_t p_in, p_out;
+	u32 tmp;
+
+	src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+
+	s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	s_width	= s_q_data->width;
+	s_height = s_q_data->height;
+
+	d_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	d_width = d_q_data->width;
+	d_height = d_q_data->height;
+	d_size = d_width * d_height;
+
+	p_in = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+	p_out = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+	if (!p_in || !p_out) {
+		v4l2_err(&pcdev->v4l2_dev,
+			 "Acquiring kernel pointers to buffers failed\n");
+		return;
+	}
+
+	/* Input frame parameters */
+	writel(p_in, pcdev->base_emma + PRP_SOURCE_Y_PTR);
+	writel(PRP_SIZE_WIDTH(s_width) | PRP_SIZE_HEIGHT(s_height),
+	       pcdev->base_emma + PRP_SRC_FRAME_SIZE);
+
+	/* Output frame parameters */
+	writel(p_out, pcdev->base_emma + PRP_DEST_Y_PTR);
+	writel(p_out + d_size, pcdev->base_emma + PRP_DEST_CB_PTR);
+	writel(p_out + d_size + (d_size >> 2),
+	       pcdev->base_emma + PRP_DEST_CR_PTR);
+	writel(PRP_SIZE_WIDTH(d_width) | PRP_SIZE_HEIGHT(d_height),
+	       pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE);
+
+	/* IRQ configuration */
+	tmp = readl(pcdev->base_emma + PRP_INTR_CNTL);
+	writel(tmp | PRP_INTR_RDERR |
+		PRP_INTR_CH2WERR |
+		PRP_INTR_CH2FC,
+		pcdev->base_emma + PRP_INTR_CNTL);
+
+	emmaprp_dump_regs(pcdev);
+
+	/* Enable transfer */
+	tmp = readl(pcdev->base_emma + PRP_CNTL);
+	writel(tmp | PRP_CNTL_CH2_OUT_YUV420 |
+		PRP_CNTL_DATA_IN_YUV422 |
+		PRP_CNTL_CH2EN,
+		pcdev->base_emma + PRP_CNTL);
+}
+
+static irqreturn_t emmaprp_irq(int irq_emma, void *data)
+{
+	struct emmaprp_dev *pcdev = data;
+	struct emmaprp_ctx *curr_ctx;
+	struct vb2_buffer *src_vb, *dst_vb;
+	unsigned long flags;
+	u32 irqst;
+
+	/* Check irq flags and clear irq */
+	irqst = readl(pcdev->base_emma + PRP_INTRSTATUS);
+	writel(irqst, pcdev->base_emma + PRP_INTRSTATUS);
+	dprintk(pcdev, "irqst = 0x%08x\n", irqst);
+
+	curr_ctx = v4l2_m2m_get_curr_priv(pcdev->m2m_dev);
+	if (curr_ctx == NULL) {
+		pr_err("Instance released before the end of transaction\n");
+		return IRQ_HANDLED;
+	}
+
+	if (!curr_ctx->aborting) {
+		if ((irqst & PRP_INTR_ST_RDERR) ||
+		(irqst & PRP_INTR_ST_CH2WERR)) {
+			pr_err("PrP bus error ocurred, this transfer is probably corrupted\n");
+			writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
+		} else if (irqst & PRP_INTR_ST_CH2B1CI) { /* buffer ready */
+			src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
+			dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+
+			spin_lock_irqsave(&pcdev->irqlock, flags);
+			v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+			v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+			spin_unlock_irqrestore(&pcdev->irqlock, flags);
+		}
+	}
+
+	v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx);
+	return IRQ_HANDLED;
+}
+
+/*
+ * video ioctls
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
+	strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+			  | V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
+{
+	int i, num;
+	struct emmaprp_fmt *fmt;
+
+	num = 0;
+
+	for (i = 0; i < NUM_FORMATS; ++i) {
+		if (formats[i].types & type) {
+			/* index-th format of type type found ? */
+			if (num == f->index)
+				break;
+			/* Correct type but haven't reached our index yet,
+			 * just increment per-type index */
+			++num;
+		}
+	}
+
+	if (i < NUM_FORMATS) {
+		/* Format found */
+		fmt = &formats[i];
+		strlcpy(f->description, fmt->name, sizeof(f->description) - 1);
+		f->pixelformat = fmt->fourcc;
+		return 0;
+	}
+
+	/* Format not found */
+	return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return enum_fmt(f, MEM2MEM_CAPTURE);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return enum_fmt(f, MEM2MEM_OUTPUT);
+}
+
+static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f)
+{
+	struct vb2_queue *vq;
+	struct emmaprp_q_data *q_data;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, f->type);
+
+	f->fmt.pix.width	= q_data->width;
+	f->fmt.pix.height	= q_data->height;
+	f->fmt.pix.field	= V4L2_FIELD_NONE;
+	f->fmt.pix.pixelformat	= q_data->fmt->fourcc;
+	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+		f->fmt.pix.bytesperline = q_data->width * 3 / 2;
+	else /* YUYV */
+		f->fmt.pix.bytesperline = q_data->width * 2;
+	f->fmt.pix.sizeimage	= q_data->sizeimage;
+
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	return vidioc_g_fmt(priv, f);
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	return vidioc_g_fmt(priv, f);
+}
+
+static int vidioc_try_fmt(struct v4l2_format *f)
+{
+	enum v4l2_field field;
+
+
+	if (!find_format(f))
+		return -EINVAL;
+
+	field = f->fmt.pix.field;
+	if (field == V4L2_FIELD_ANY)
+		field = V4L2_FIELD_NONE;
+	else if (V4L2_FIELD_NONE != field)
+		return -EINVAL;
+
+	/* V4L2 specification suggests the driver corrects the format struct
+	 * if any of the dimensions is unsupported */
+	f->fmt.pix.field = field;
+
+	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
+		v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
+				      W_ALIGN_YUV420, &f->fmt.pix.height,
+				      MIN_H, MAX_H, H_ALIGN, S_ALIGN);
+		f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2;
+	} else {
+		v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
+				      W_ALIGN_OTHERS, &f->fmt.pix.height,
+				      MIN_H, MAX_H, H_ALIGN, S_ALIGN);
+		f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+	}
+	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct emmaprp_fmt *fmt;
+	struct emmaprp_ctx *ctx = priv;
+
+	fmt = find_format(f);
+	if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
+		v4l2_err(&ctx->dev->v4l2_dev,
+			 "Fourcc format (0x%08x) invalid.\n",
+			 f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	return vidioc_try_fmt(f);
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct emmaprp_fmt *fmt;
+	struct emmaprp_ctx *ctx = priv;
+
+	fmt = find_format(f);
+	if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
+		v4l2_err(&ctx->dev->v4l2_dev,
+			 "Fourcc format (0x%08x) invalid.\n",
+			 f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	return vidioc_try_fmt(f);
+}
+
+static int vidioc_s_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f)
+{
+	struct emmaprp_q_data *q_data;
+	struct vb2_queue *vq;
+	int ret;
+
+	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, f->type);
+	if (!q_data)
+		return -EINVAL;
+
+	if (vb2_is_busy(vq)) {
+		v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
+		return -EBUSY;
+	}
+
+	ret = vidioc_try_fmt(f);
+	if (ret)
+		return ret;
+
+	q_data->fmt		= find_format(f);
+	q_data->width		= f->fmt.pix.width;
+	q_data->height		= f->fmt.pix.height;
+	if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420)
+		q_data->sizeimage = q_data->width * q_data->height * 3 / 2;
+	else /* YUYV */
+		q_data->sizeimage = q_data->width * q_data->height * 2;
+
+	dprintk(ctx->dev,
+		"Setting format for type %d, wxh: %dx%d, fmt: %d\n",
+		f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
+
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	int ret;
+
+	ret = vidioc_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	return vidioc_s_fmt(priv, f);
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	int ret;
+
+	ret = vidioc_try_fmt_vid_out(file, priv, f);
+	if (ret)
+		return ret;
+
+	return vidioc_s_fmt(priv, f);
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *reqbufs)
+{
+	struct emmaprp_ctx *ctx = priv;
+
+	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *buf)
+{
+	struct emmaprp_ctx *ctx = priv;
+
+	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct emmaprp_ctx *ctx = priv;
+
+	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct emmaprp_ctx *ctx = priv;
+
+	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct emmaprp_ctx *ctx = priv;
+
+	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type type)
+{
+	struct emmaprp_ctx *ctx = priv;
+
+	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = {
+	.vidioc_querycap	= vidioc_querycap,
+
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
+
+	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out	= vidioc_g_fmt_vid_out,
+	.vidioc_try_fmt_vid_out	= vidioc_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out	= vidioc_s_fmt_vid_out,
+
+	.vidioc_reqbufs		= vidioc_reqbufs,
+	.vidioc_querybuf	= vidioc_querybuf,
+
+	.vidioc_qbuf		= vidioc_qbuf,
+	.vidioc_dqbuf		= vidioc_dqbuf,
+
+	.vidioc_streamon	= vidioc_streamon,
+	.vidioc_streamoff	= vidioc_streamoff,
+};
+
+
+/*
+ * Queue operations
+ */
+static int emmaprp_queue_setup(struct vb2_queue *vq,
+				const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct emmaprp_ctx *ctx = vb2_get_drv_priv(vq);
+	struct emmaprp_q_data *q_data;
+	unsigned int size, count = *nbuffers;
+
+	q_data = get_q_data(ctx, vq->type);
+
+	if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420)
+		size = q_data->width * q_data->height * 3 / 2;
+	else
+		size = q_data->width * q_data->height * 2;
+
+	while (size * count > MEM2MEM_VID_MEM_LIMIT)
+		(count)--;
+
+	*nplanes = 1;
+	*nbuffers = count;
+	sizes[0] = size;
+
+	alloc_ctxs[0] = ctx->dev->alloc_ctx;
+
+	dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
+
+	return 0;
+}
+
+static int emmaprp_buf_prepare(struct vb2_buffer *vb)
+{
+	struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct emmaprp_q_data *q_data;
+
+	dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
+
+	q_data = get_q_data(ctx, vb->vb2_queue->type);
+
+	if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+		dprintk(ctx->dev, "%s data will not fit into plane"
+				  "(%lu < %lu)\n", __func__,
+				  vb2_plane_size(vb, 0),
+				  (long)q_data->sizeimage);
+		return -EINVAL;
+	}
+
+	vb2_set_plane_payload(vb, 0, q_data->sizeimage);
+
+	return 0;
+}
+
+static void emmaprp_buf_queue(struct vb2_buffer *vb)
+{
+	struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static struct vb2_ops emmaprp_qops = {
+	.queue_setup	 = emmaprp_queue_setup,
+	.buf_prepare	 = emmaprp_buf_prepare,
+	.buf_queue	 = emmaprp_buf_queue,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+		      struct vb2_queue *dst_vq)
+{
+	struct emmaprp_ctx *ctx = priv;
+	int ret;
+
+	memset(src_vq, 0, sizeof(*src_vq));
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_MMAP;
+	src_vq->drv_priv = ctx;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->ops = &emmaprp_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	memset(dst_vq, 0, sizeof(*dst_vq));
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_MMAP;
+	dst_vq->drv_priv = ctx;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->ops = &emmaprp_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+	return vb2_queue_init(dst_vq);
+}
+
+/*
+ * File operations
+ */
+static int emmaprp_open(struct file *file)
+{
+	struct emmaprp_dev *pcdev = video_drvdata(file);
+	struct emmaprp_ctx *ctx;
+
+	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	file->private_data = ctx;
+	ctx->dev = pcdev;
+
+	ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init);
+
+	if (IS_ERR(ctx->m2m_ctx)) {
+		int ret = PTR_ERR(ctx->m2m_ctx);
+
+		kfree(ctx);
+		return ret;
+	}
+
+	clk_enable(pcdev->clk_emma);
+	ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1];
+	ctx->q_data[V4L2_M2M_DST].fmt = &formats[0];
+
+	dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
+
+	return 0;
+}
+
+static int emmaprp_release(struct file *file)
+{
+	struct emmaprp_dev *pcdev = video_drvdata(file);
+	struct emmaprp_ctx *ctx = file->private_data;
+
+	dprintk(pcdev, "Releasing instance %p\n", ctx);
+
+	clk_disable(pcdev->clk_emma);
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+	kfree(ctx);
+
+	return 0;
+}
+
+static unsigned int emmaprp_poll(struct file *file,
+				 struct poll_table_struct *wait)
+{
+	struct emmaprp_ctx *ctx = file->private_data;
+
+	return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+static int emmaprp_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct emmaprp_ctx *ctx = file->private_data;
+
+	return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations emmaprp_fops = {
+	.owner		= THIS_MODULE,
+	.open		= emmaprp_open,
+	.release	= emmaprp_release,
+	.poll		= emmaprp_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= emmaprp_mmap,
+};
+
+static struct video_device emmaprp_videodev = {
+	.name		= MEM2MEM_NAME,
+	.fops		= &emmaprp_fops,
+	.ioctl_ops	= &emmaprp_ioctl_ops,
+	.minor		= -1,
+	.release	= video_device_release,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+	.device_run	= emmaprp_device_run,
+	.job_abort	= emmaprp_job_abort,
+	.lock		= emmaprp_lock,
+	.unlock		= emmaprp_unlock,
+};
+
+static int emmaprp_probe(struct platform_device *pdev)
+{
+	struct emmaprp_dev *pcdev;
+	struct video_device *vfd;
+	struct resource *res_emma;
+	int irq_emma;
+	int ret;
+
+	pcdev = kzalloc(sizeof *pcdev, GFP_KERNEL);
+	if (!pcdev)
+		return -ENOMEM;
+
+	spin_lock_init(&pcdev->irqlock);
+
+	pcdev->clk_emma = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(pcdev->clk_emma)) {
+		ret = PTR_ERR(pcdev->clk_emma);
+		goto free_dev;
+	}
+
+	irq_emma = platform_get_irq(pdev, 0);
+	res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (irq_emma < 0 || res_emma == NULL) {
+		dev_err(&pdev->dev, "Missing platform resources data\n");
+		ret = -ENODEV;
+		goto free_clk;
+	}
+
+	ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
+	if (ret)
+		goto free_clk;
+
+	mutex_init(&pcdev->dev_mutex);
+
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(&pcdev->v4l2_dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto unreg_dev;
+	}
+
+	*vfd = emmaprp_videodev;
+	vfd->lock = &pcdev->dev_mutex;
+
+	video_set_drvdata(vfd, pcdev);
+	snprintf(vfd->name, sizeof(vfd->name), "%s", emmaprp_videodev.name);
+	pcdev->vfd = vfd;
+	v4l2_info(&pcdev->v4l2_dev, EMMAPRP_MODULE_NAME
+			" Device registered as /dev/video%d\n", vfd->num);
+
+	platform_set_drvdata(pdev, pcdev);
+
+	if (devm_request_mem_region(&pdev->dev, res_emma->start,
+	    resource_size(res_emma), MEM2MEM_NAME) == NULL)
+		goto rel_vdev;
+
+	pcdev->base_emma = devm_ioremap(&pdev->dev, res_emma->start,
+					resource_size(res_emma));
+	if (!pcdev->base_emma)
+		goto rel_vdev;
+
+	pcdev->irq_emma = irq_emma;
+	pcdev->res_emma = res_emma;
+
+	if (devm_request_irq(&pdev->dev, pcdev->irq_emma, emmaprp_irq,
+			     0, MEM2MEM_NAME, pcdev) < 0)
+		goto rel_vdev;
+
+	pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(pcdev->alloc_ctx)) {
+		v4l2_err(&pcdev->v4l2_dev, "Failed to alloc vb2 context\n");
+		ret = PTR_ERR(pcdev->alloc_ctx);
+		goto rel_vdev;
+	}
+
+	pcdev->m2m_dev = v4l2_m2m_init(&m2m_ops);
+	if (IS_ERR(pcdev->m2m_dev)) {
+		v4l2_err(&pcdev->v4l2_dev, "Failed to init mem2mem device\n");
+		ret = PTR_ERR(pcdev->m2m_dev);
+		goto rel_ctx;
+	}
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+	if (ret) {
+		v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n");
+		goto rel_m2m;
+	}
+
+	return 0;
+
+
+rel_m2m:
+	v4l2_m2m_release(pcdev->m2m_dev);
+rel_ctx:
+	vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+rel_vdev:
+	video_device_release(vfd);
+unreg_dev:
+	v4l2_device_unregister(&pcdev->v4l2_dev);
+free_clk:
+	clk_put(pcdev->clk_emma);
+free_dev:
+	kfree(pcdev);
+
+	return ret;
+}
+
+static int emmaprp_remove(struct platform_device *pdev)
+{
+	struct emmaprp_dev *pcdev = platform_get_drvdata(pdev);
+
+	v4l2_info(&pcdev->v4l2_dev, "Removing " EMMAPRP_MODULE_NAME);
+
+	video_unregister_device(pcdev->vfd);
+	v4l2_m2m_release(pcdev->m2m_dev);
+	vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+	v4l2_device_unregister(&pcdev->v4l2_dev);
+	clk_put(pcdev->clk_emma);
+	kfree(pcdev);
+
+	return 0;
+}
+
+static struct platform_driver emmaprp_pdrv = {
+	.probe		= emmaprp_probe,
+	.remove		= emmaprp_remove,
+	.driver		= {
+		.name	= MEM2MEM_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static void __exit emmaprp_exit(void)
+{
+	platform_driver_unregister(&emmaprp_pdrv);
+}
+
+static int __init emmaprp_init(void)
+{
+	return platform_driver_register(&emmaprp_pdrv);
+}
+
+module_init(emmaprp_init);
+module_exit(emmaprp_exit);
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index 7452277..93c35ef 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -286,7 +286,7 @@
 		sg_dma_address(sg)	= vb2_dma_contig_plane_dma_addr(vb, 0);
 		sg_dma_len(sg)		= new_size;
 
-		txd = ichan->dma_chan.device->device_prep_slave_sg(
+		txd = dmaengine_prep_slave_sg(
 			&ichan->dma_chan, sg, 1, DMA_DEV_TO_MEM,
 			DMA_PREP_INTERRUPT);
 		if (!txd)
diff --git a/drivers/media/video/noon010pc30.c b/drivers/media/video/noon010pc30.c
index 50838bf..440c129 100644
--- a/drivers/media/video/noon010pc30.c
+++ b/drivers/media/video/noon010pc30.c
@@ -725,8 +725,8 @@
 
 	mutex_init(&info->lock);
 	sd = &info->sd;
-	strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
 	v4l2_i2c_subdev_init(sd, client, &noon010_ops);
+	strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
 
 	sd->internal_ops = &noon010_subdev_internal_ops;
 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -844,18 +844,7 @@
 	.id_table	= noon010_id,
 };
 
-static int __init noon010_init(void)
-{
-	return i2c_add_driver(&noon010_i2c_driver);
-}
-
-static void __exit noon010_exit(void)
-{
-	i2c_del_driver(&noon010_i2c_driver);
-}
-
-module_init(noon010_init);
-module_exit(noon010_exit);
+module_i2c_driver(noon010_i2c_driver);
 
 MODULE_DESCRIPTION("Siliconfile NOON010PC30 camera driver");
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
index 1fb7d5b..88cf9d9 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/video/omap/omap_vout.c
@@ -2268,13 +2268,12 @@
 	.driver = {
 		.name = VOUT_NAME,
 	},
-	.probe = omap_vout_probe,
 	.remove = omap_vout_remove,
 };
 
 static int __init omap_vout_init(void)
 {
-	if (platform_driver_register(&omap_vout_driver) != 0) {
+	if (platform_driver_probe(&omap_vout_driver, omap_vout_probe) != 0) {
 		printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n");
 		return -EINVAL;
 	}
diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c
index b5247cb..3c2c5d3 100644
--- a/drivers/media/video/ov2640.c
+++ b/drivers/media/video/ov2640.c
@@ -1103,21 +1103,7 @@
 	.id_table = ov2640_id,
 };
 
-/*
- * Module functions
- */
-static int __init ov2640_module_init(void)
-{
-	return i2c_add_driver(&ov2640_i2c_driver);
-}
-
-static void __exit ov2640_module_exit(void)
-{
-	i2c_del_driver(&ov2640_i2c_driver);
-}
-
-module_init(ov2640_module_init);
-module_exit(ov2640_module_exit);
+module_i2c_driver(ov2640_i2c_driver);
 
 MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor");
 MODULE_AUTHOR("Alberto Panizzo");
diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c
index bb37ec8..80e0779 100644
--- a/drivers/media/video/ov5642.c
+++ b/drivers/media/video/ov5642.c
@@ -1068,18 +1068,7 @@
 	.id_table	= ov5642_id,
 };
 
-static int __init ov5642_mod_init(void)
-{
-	return i2c_add_driver(&ov5642_i2c_driver);
-}
-
-static void __exit ov5642_mod_exit(void)
-{
-	i2c_del_driver(&ov5642_i2c_driver);
-}
-
-module_init(ov5642_mod_init);
-module_exit(ov5642_mod_exit);
+module_i2c_driver(ov5642_i2c_driver);
 
 MODULE_DESCRIPTION("Omnivision OV5642 Camera driver");
 MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c
index 3627f32..3e028b1 100644
--- a/drivers/media/video/ov6650.c
+++ b/drivers/media/video/ov6650.c
@@ -1046,18 +1046,7 @@
 	.id_table = ov6650_id,
 };
 
-static int __init ov6650_module_init(void)
-{
-	return i2c_add_driver(&ov6650_i2c_driver);
-}
-
-static void __exit ov6650_module_exit(void)
-{
-	i2c_del_driver(&ov6650_i2c_driver);
-}
-
-module_init(ov6650_module_init);
-module_exit(ov6650_module_exit);
+module_i2c_driver(ov6650_i2c_driver);
 
 MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650");
 MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index 6a56496..e7c82b2 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -1583,15 +1583,4 @@
 	.id_table	= ov7670_id,
 };
 
-static __init int init_ov7670(void)
-{
-	return i2c_add_driver(&ov7670_driver);
-}
-
-static __exit void exit_ov7670(void)
-{
-	i2c_del_driver(&ov7670_driver);
-}
-
-module_init(init_ov7670);
-module_exit(exit_ov7670);
+module_i2c_driver(ov7670_driver);
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index 9f6ce3d..74e77d3 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -1123,22 +1123,7 @@
 	.id_table = ov772x_id,
 };
 
-/*
- * module function
- */
-
-static int __init ov772x_module_init(void)
-{
-	return i2c_add_driver(&ov772x_i2c_driver);
-}
-
-static void __exit ov772x_module_exit(void)
-{
-	i2c_del_driver(&ov772x_i2c_driver);
-}
-
-module_init(ov772x_module_init);
-module_exit(ov772x_module_exit);
+module_i2c_driver(ov772x_i2c_driver);
 
 MODULE_DESCRIPTION("SoC Camera driver for ov772x");
 MODULE_AUTHOR("Kuninori Morimoto");
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
index a4f9979..23412de 100644
--- a/drivers/media/video/ov9640.c
+++ b/drivers/media/video/ov9640.c
@@ -738,18 +738,7 @@
 	.id_table = ov9640_id,
 };
 
-static int __init ov9640_module_init(void)
-{
-	return i2c_add_driver(&ov9640_i2c_driver);
-}
-
-static void __exit ov9640_module_exit(void)
-{
-	i2c_del_driver(&ov9640_i2c_driver);
-}
-
-module_init(ov9640_module_init);
-module_exit(ov9640_module_exit);
+module_i2c_driver(ov9640_i2c_driver);
 
 MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx");
 MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c
index d9a9f71..3eb07c2 100644
--- a/drivers/media/video/ov9740.c
+++ b/drivers/media/video/ov9740.c
@@ -998,18 +998,7 @@
 	.id_table = ov9740_id,
 };
 
-static int __init ov9740_module_init(void)
-{
-	return i2c_add_driver(&ov9740_i2c_driver);
-}
-
-static void __exit ov9740_module_exit(void)
-{
-	i2c_del_driver(&ov9740_i2c_driver);
-}
-
-module_init(ov9740_module_init);
-module_exit(ov9740_module_exit);
+module_i2c_driver(ov9740_i2c_driver);
 
 MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740");
 MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>");
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index c6da8f7..d8c8982 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -320,7 +320,17 @@
 	.probe_tuner = TDA829X_DONT_PROBE,
 };
 
+static struct tda18271_std_map hauppauge_tda18271_dvbt_std_map = {
+        .dvbt_6   = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+                      .if_lvl = 1, .rfagc_top = 0x37, },
+        .dvbt_7   = { .if_freq = 3800, .agc_mode = 3, .std = 5,
+                      .if_lvl = 1, .rfagc_top = 0x37, },
+        .dvbt_8   = { .if_freq = 4300, .agc_mode = 3, .std = 6,
+                      .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
 static struct tda18271_config hauppauge_tda18271_dvb_config = {
+	.std_map = &hauppauge_tda18271_dvbt_std_map,
 	.gate    = TDA18271_GATE_ANALOG,
 	.output_opt = TDA18271_OUTPUT_LT_OFF,
 };
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 6d66617..e1111d9 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -96,7 +96,6 @@
 	.capabilities   = (V4L2_CAP_VIDEO_CAPTURE |
 			   V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
 			   V4L2_CAP_READWRITE),
-	.reserved       = {0,0,0,0}
 };
 
 static struct v4l2_fmtdesc pvr_fmtdesc [] = {
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index f495eeb..2834e3e 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -1146,14 +1146,6 @@
 	return ret;
 }
 
-static int pwc_log_status(struct file *file, void *priv)
-{
-	struct pwc_device *pdev = video_drvdata(file);
-
-	v4l2_ctrl_handler_log_status(&pdev->ctrl_handler, PWC_NAME);
-	return 0;
-}
-
 const struct v4l2_ioctl_ops pwc_ioctl_ops = {
 	.vidioc_querycap		    = pwc_querycap,
 	.vidioc_enum_input		    = pwc_enum_input,
@@ -1169,7 +1161,7 @@
 	.vidioc_dqbuf			    = pwc_dqbuf,
 	.vidioc_streamon		    = pwc_streamon,
 	.vidioc_streamoff		    = pwc_streamoff,
-	.vidioc_log_status		    = pwc_log_status,
+	.vidioc_log_status		    = v4l2_ctrl_log_status,
 	.vidioc_enum_framesizes		    = pwc_enum_framesizes,
 	.vidioc_enum_frameintervals	    = pwc_enum_frameintervals,
 	.vidioc_g_parm			    = pwc_g_parm,
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 0bd7da2..5a413f4 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -921,12 +921,12 @@
 		/* "Safe default" - 13MHz */
 		recalculate_fifo_timeout(pcdev, 13000000);
 
-	clk_enable(pcdev->clk);
+	clk_prepare_enable(pcdev->clk);
 }
 
 static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
 {
-	clk_disable(pcdev->clk);
+	clk_disable_unprepare(pcdev->clk);
 }
 
 static irqreturn_t pxa_camera_irq(int irq, void *data)
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c
index 9937386..f6419b2 100644
--- a/drivers/media/video/rj54n1cb0c.c
+++ b/drivers/media/video/rj54n1cb0c.c
@@ -1407,18 +1407,7 @@
 	.id_table	= rj54n1_id,
 };
 
-static int __init rj54n1_mod_init(void)
-{
-	return i2c_add_driver(&rj54n1_i2c_driver);
-}
-
-static void __exit rj54n1_mod_exit(void)
-{
-	i2c_del_driver(&rj54n1_i2c_driver);
-}
-
-module_init(rj54n1_mod_init);
-module_exit(rj54n1_mod_exit);
+module_i2c_driver(rj54n1_i2c_driver);
 
 MODULE_DESCRIPTION("Sharp RJ54N1CB0C Camera driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
index c1bef61..4894cbb 100644
--- a/drivers/media/video/s2255drv.c
+++ b/drivers/media/video/s2255drv.c
@@ -134,7 +134,7 @@
 
 /* usb config commands */
 #define IN_DATA_TOKEN	cpu_to_le32(0x2255c0de)
-#define CMD_2255	cpu_to_le32(0xc2255000)
+#define CMD_2255	0xc2255000
 #define CMD_SET_MODE	cpu_to_le32((CMD_2255 | 0x10))
 #define CMD_START	cpu_to_le32((CMD_2255 | 0x20))
 #define CMD_STOP	cpu_to_le32((CMD_2255 | 0x30))
@@ -852,15 +852,13 @@
 static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
 			       struct v4l2_fmtdesc *f)
 {
-	int index = 0;
-	if (f)
-		index = f->index;
+	int index = f->index;
 
 	if (index >= ARRAY_SIZE(formats))
 		return -EINVAL;
-    if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) ||
-			 (formats[index].fourcc == V4L2_PIX_FMT_MJPEG)))
-	return -EINVAL;
+	if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) ||
+			(formats[index].fourcc == V4L2_PIX_FMT_MJPEG)))
+		return -EINVAL;
 	dprintk(4, "name %s\n", formats[index].name);
 	strlcpy(f->description, formats[index].name, sizeof(f->description));
 	f->pixelformat = formats[index].fourcc;
@@ -2027,7 +2025,7 @@
 					pdata[1]);
 				offset = jj + PREFIX_SIZE;
 				bframe = 1;
-				cc = pdword[1];
+				cc = le32_to_cpu(pdword[1]);
 				if (cc >= MAX_CHANNELS) {
 					printk(KERN_ERR
 					       "bad channel\n");
@@ -2036,22 +2034,22 @@
 				/* reverse it */
 				dev->cc = G_chnmap[cc];
 				channel = &dev->channel[dev->cc];
-				payload =  pdword[3];
+				payload =  le32_to_cpu(pdword[3]);
 				if (payload > channel->req_image_size) {
 					channel->bad_payload++;
 					/* discard the bad frame */
 					return -EINVAL;
 				}
 				channel->pkt_size = payload;
-				channel->jpg_size = pdword[4];
+				channel->jpg_size = le32_to_cpu(pdword[4]);
 				break;
 			case S2255_MARKER_RESPONSE:
 
 				pdata += DEF_USB_BLOCK;
 				jj += DEF_USB_BLOCK;
-				if (pdword[1] >= MAX_CHANNELS)
+				if (le32_to_cpu(pdword[1]) >= MAX_CHANNELS)
 					break;
-				cc = G_chnmap[pdword[1]];
+				cc = G_chnmap[le32_to_cpu(pdword[1])];
 				if (cc >= MAX_CHANNELS)
 					break;
 				channel = &dev->channel[cc];
@@ -2074,11 +2072,11 @@
 					wake_up(&dev->fw_data->wait_fw);
 					break;
 				case S2255_RESPONSE_STATUS:
-					channel->vidstatus = pdword[3];
+					channel->vidstatus = le32_to_cpu(pdword[3]);
 					channel->vidstatus_ready = 1;
 					wake_up(&channel->wait_vidstatus);
 					dprintk(5, "got vidstatus %x chan %d\n",
-						pdword[3], cc);
+						le32_to_cpu(pdword[3]), cc);
 					break;
 				default:
 					printk(KERN_INFO "s2255 unknown resp\n");
@@ -2605,10 +2603,11 @@
 		__le32 *pRel;
 		pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4];
 		printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel);
-		dev->dsp_fw_ver = *pRel;
-		if (*pRel < S2255_CUR_DSP_FWVER)
+		dev->dsp_fw_ver = le32_to_cpu(*pRel);
+		if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER)
 			printk(KERN_INFO "s2255: f2255usb.bin out of date.\n");
-		if (dev->pid == 0x2257 && *pRel < S2255_MIN_DSP_COLORFILTER)
+		if (dev->pid == 0x2257 &&
+				dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
 			printk(KERN_WARNING "s2255: 2257 requires firmware %d"
 			       " or above.\n", S2255_MIN_DSP_COLORFILTER);
 	}
diff --git a/drivers/media/video/s5k6aa.c b/drivers/media/video/s5k6aa.c
index 0df7f2a..6625e46 100644
--- a/drivers/media/video/s5k6aa.c
+++ b/drivers/media/video/s5k6aa.c
@@ -1582,8 +1582,8 @@
 	s5k6aa->inv_vflip = pdata->vert_flip;
 
 	sd = &s5k6aa->sd;
-	strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name));
 	v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops);
+	strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name));
 
 	sd->internal_ops = &s5k6aa_subdev_internal_ops;
 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -1663,18 +1663,7 @@
 	.id_table	= s5k6aa_id,
 };
 
-static int __init s5k6aa_init(void)
-{
-	return i2c_add_driver(&s5k6aa_i2c_driver);
-}
-
-static void __exit s5k6aa_exit(void)
-{
-	i2c_del_driver(&s5k6aa_i2c_driver);
-}
-
-module_init(s5k6aa_init);
-module_exit(s5k6aa_exit);
+module_i2c_driver(s5k6aa_i2c_driver);
 
 MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver");
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index a9e9653..b06efd2 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -1019,52 +1019,117 @@
 	return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK);
 }
 
-static int fimc_cap_cropcap(struct file *file, void *fh,
-			    struct v4l2_cropcap *cr)
+static int fimc_cap_create_bufs(struct file *file, void *priv,
+				struct v4l2_create_buffers *create)
 {
 	struct fimc_dev *fimc = video_drvdata(file);
-	struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
 
-	if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-		return -EINVAL;
-
-	cr->bounds.left		= 0;
-	cr->bounds.top		= 0;
-	cr->bounds.width	= f->o_width;
-	cr->bounds.height	= f->o_height;
-	cr->defrect		= cr->bounds;
-
-	return 0;
+	return vb2_create_bufs(&fimc->vid_cap.vbq, create);
 }
 
-static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+static int fimc_cap_prepare_buf(struct file *file, void *priv,
+				struct v4l2_buffer *b)
 {
 	struct fimc_dev *fimc = video_drvdata(file);
-	struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
 
-	cr->c.left	= f->offs_h;
-	cr->c.top	= f->offs_v;
-	cr->c.width	= f->width;
-	cr->c.height	= f->height;
-
-	return 0;
+	return vb2_prepare_buf(&fimc->vid_cap.vbq, b);
 }
 
-static int fimc_cap_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+static int fimc_cap_g_selection(struct file *file, void *fh,
+				struct v4l2_selection *s)
 {
 	struct fimc_dev *fimc = video_drvdata(file);
 	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
-	struct fimc_frame *ff;
+	struct fimc_frame *f = &ctx->s_frame;
+
+	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		f = &ctx->d_frame;
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = f->o_width;
+		s->r.height = f->o_height;
+		return 0;
+
+	case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+		f = &ctx->d_frame;
+	case V4L2_SEL_TGT_CROP_ACTIVE:
+		s->r.left = f->offs_h;
+		s->r.top = f->offs_v;
+		s->r.width = f->width;
+		s->r.height = f->height;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
+int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
+{
+	if (a->left < b->left || a->top < b->top)
+		return 0;
+	if (a->left + a->width > b->left + b->width)
+		return 0;
+	if (a->top + a->height > b->top + b->height)
+		return 0;
+
+	return 1;
+}
+
+static int fimc_cap_s_selection(struct file *file, void *fh,
+				struct v4l2_selection *s)
+{
+	struct fimc_dev *fimc = video_drvdata(file);
+	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+	struct v4l2_rect rect = s->r;
+	struct fimc_frame *f;
 	unsigned long flags;
+	unsigned int pad;
 
-	fimc_capture_try_crop(ctx, &cr->c, FIMC_SD_PAD_SINK);
-	ff = &ctx->s_frame;
+	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return -EINVAL;
 
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+		f = &ctx->d_frame;
+		pad = FIMC_SD_PAD_SOURCE;
+		break;
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_ACTIVE:
+		f = &ctx->s_frame;
+		pad = FIMC_SD_PAD_SINK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	fimc_capture_try_crop(ctx, &rect, pad);
+
+	if (s->flags & V4L2_SEL_FLAG_LE &&
+	    !enclosed_rectangle(&rect, &s->r))
+		return -ERANGE;
+
+	if (s->flags & V4L2_SEL_FLAG_GE &&
+	    !enclosed_rectangle(&s->r, &rect))
+		return -ERANGE;
+
+	s->r = rect;
 	spin_lock_irqsave(&fimc->slock, flags);
-	set_frame_crop(ff, cr->c.left, cr->c.top, cr->c.width, cr->c.height);
-	set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
+	set_frame_crop(f, s->r.left, s->r.top, s->r.width,
+		       s->r.height);
 	spin_unlock_irqrestore(&fimc->slock, flags);
 
+	set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
 	return 0;
 }
 
@@ -1082,12 +1147,14 @@
 	.vidioc_qbuf			= fimc_cap_qbuf,
 	.vidioc_dqbuf			= fimc_cap_dqbuf,
 
+	.vidioc_prepare_buf		= fimc_cap_prepare_buf,
+	.vidioc_create_bufs		= fimc_cap_create_bufs,
+
 	.vidioc_streamon		= fimc_cap_streamon,
 	.vidioc_streamoff		= fimc_cap_streamoff,
 
-	.vidioc_g_crop			= fimc_cap_g_crop,
-	.vidioc_s_crop			= fimc_cap_s_crop,
-	.vidioc_cropcap			= fimc_cap_cropcap,
+	.vidioc_g_selection		= fimc_cap_g_selection,
+	.vidioc_s_selection		= fimc_cap_s_selection,
 
 	.vidioc_enum_input		= fimc_cap_enum_input,
 	.vidioc_s_input			= fimc_cap_s_input,
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index 81bcbb9..e184e65 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -1602,24 +1602,35 @@
 {
 	int i;
 	for (i = 0; i < fimc->num_clocks; i++) {
-		if (fimc->clock[i])
-			clk_put(fimc->clock[i]);
+		if (IS_ERR_OR_NULL(fimc->clock[i]))
+			continue;
+		clk_unprepare(fimc->clock[i]);
+		clk_put(fimc->clock[i]);
+		fimc->clock[i] = NULL;
 	}
 }
 
 static int fimc_clk_get(struct fimc_dev *fimc)
 {
-	int i;
+	int i, ret;
+
 	for (i = 0; i < fimc->num_clocks; i++) {
 		fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]);
-		if (!IS_ERR_OR_NULL(fimc->clock[i]))
-			continue;
-		dev_err(&fimc->pdev->dev, "failed to get fimc clock: %s\n",
-			fimc_clocks[i]);
-		return -ENXIO;
+		if (IS_ERR(fimc->clock[i]))
+			goto err;
+		ret = clk_prepare(fimc->clock[i]);
+		if (ret < 0) {
+			clk_put(fimc->clock[i]);
+			fimc->clock[i] = NULL;
+			goto err;
+		}
 	}
-
 	return 0;
+err:
+	fimc_clk_put(fimc);
+	dev_err(&fimc->pdev->dev, "failed to get clock: %s\n",
+		fimc_clocks[i]);
+	return -ENXIO;
 }
 
 static int fimc_m2m_suspend(struct fimc_dev *fimc)
@@ -1667,8 +1678,6 @@
 	struct s5p_platform_fimc *pdata;
 	int ret = 0;
 
-	dev_dbg(&pdev->dev, "%s():\n", __func__);
-
 	drv_data = (struct samsung_fimc_driverdata *)
 		platform_get_device_id(pdev)->driver_data;
 
@@ -1678,7 +1687,7 @@
 		return -EINVAL;
 	}
 
-	fimc = kzalloc(sizeof(struct fimc_dev), GFP_KERNEL);
+	fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL);
 	if (!fimc)
 		return -ENOMEM;
 
@@ -1689,51 +1698,35 @@
 	pdata = pdev->dev.platform_data;
 	fimc->pdata = pdata;
 
-
 	init_waitqueue_head(&fimc->irq_queue);
 	spin_lock_init(&fimc->slock);
 	mutex_init(&fimc->lock);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "failed to find the registers\n");
-		ret = -ENOENT;
-		goto err_info;
-	}
-
-	fimc->regs_res = request_mem_region(res->start, resource_size(res),
-			dev_name(&pdev->dev));
-	if (!fimc->regs_res) {
-		dev_err(&pdev->dev, "failed to obtain register region\n");
-		ret = -ENOENT;
-		goto err_info;
-	}
-
-	fimc->regs = ioremap(res->start, resource_size(res));
-	if (!fimc->regs) {
-		dev_err(&pdev->dev, "failed to map registers\n");
-		ret = -ENXIO;
-		goto err_req_region;
+	fimc->regs = devm_request_and_ioremap(&pdev->dev, res);
+	if (fimc->regs == NULL) {
+		dev_err(&pdev->dev, "Failed to obtain io memory\n");
+		return -ENOENT;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "failed to get IRQ resource\n");
-		ret = -ENXIO;
-		goto err_regs_unmap;
+	if (res == NULL) {
+		dev_err(&pdev->dev, "Failed to get IRQ resource\n");
+		return -ENXIO;
 	}
 	fimc->irq = res->start;
 
 	fimc->num_clocks = MAX_FIMC_CLOCKS;
 	ret = fimc_clk_get(fimc);
 	if (ret)
-		goto err_regs_unmap;
+		return ret;
 	clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency);
 	clk_enable(fimc->clock[CLK_BUS]);
 
 	platform_set_drvdata(pdev, fimc);
 
-	ret = request_irq(fimc->irq, fimc_irq_handler, 0, pdev->name, fimc);
+	ret = devm_request_irq(&pdev->dev, fimc->irq, fimc_irq_handler,
+			       0, pdev->name, fimc);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
 		goto err_clk;
@@ -1742,7 +1735,7 @@
 	pm_runtime_enable(&pdev->dev);
 	ret = pm_runtime_get_sync(&pdev->dev);
 	if (ret < 0)
-		goto err_irq;
+		goto err_clk;
 	/* Initialize contiguous memory allocator */
 	fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
 	if (IS_ERR(fimc->alloc_ctx)) {
@@ -1757,17 +1750,8 @@
 
 err_pm:
 	pm_runtime_put(&pdev->dev);
-err_irq:
-	free_irq(fimc->irq, fimc);
 err_clk:
 	fimc_clk_put(fimc);
-err_regs_unmap:
-	iounmap(fimc->regs);
-err_req_region:
-	release_resource(fimc->regs_res);
-	kfree(fimc->regs_res);
-err_info:
-	kfree(fimc);
 	return ret;
 }
 
@@ -1854,11 +1838,6 @@
 
 	clk_disable(fimc->clock[CLK_BUS]);
 	fimc_clk_put(fimc);
-	free_irq(fimc->irq, fimc);
-	iounmap(fimc->regs);
-	release_resource(fimc->regs_res);
-	kfree(fimc->regs_res);
-	kfree(fimc);
 
 	dev_info(&pdev->dev, "driver unloaded\n");
 	return 0;
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h
index 4e20560..a18291e 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.h
+++ b/drivers/media/video/s5p-fimc/fimc-core.h
@@ -434,7 +434,6 @@
  * @num_clocks: the number of clocks managed by this device instance
  * @clock:	clocks required for FIMC operation
  * @regs:	the mapped hardware registers
- * @regs_res:	the resource claimed for IO registers
  * @irq:	FIMC interrupt number
  * @irq_queue:	interrupt handler waitqueue
  * @v4l2_dev:	root v4l2_device
@@ -454,7 +453,6 @@
 	u16				num_clocks;
 	struct clk			*clock[MAX_FIMC_CLOCKS];
 	void __iomem			*regs;
-	struct resource			*regs_res;
 	int				irq;
 	wait_queue_head_t		irq_queue;
 	struct v4l2_device		*v4l2_dev;
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c
index 63eccb5..62ed37e 100644
--- a/drivers/media/video/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c
@@ -750,7 +750,7 @@
 	struct fimc_md *fmd;
 	int ret;
 
-	fmd = kzalloc(sizeof(struct fimc_md), GFP_KERNEL);
+	fmd = devm_kzalloc(&pdev->dev, sizeof(*fmd), GFP_KERNEL);
 	if (!fmd)
 		return -ENOMEM;
 
@@ -771,7 +771,7 @@
 	ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev);
 	if (ret < 0) {
 		v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
-		goto err1;
+		return ret;
 	}
 	ret = media_device_register(&fmd->media_dev);
 	if (ret < 0) {
@@ -813,8 +813,6 @@
 	fimc_md_unregister_entities(fmd);
 err2:
 	v4l2_device_unregister(&fmd->v4l2_dev);
-err1:
-	kfree(fmd);
 	return ret;
 }
 
@@ -828,7 +826,6 @@
 	fimc_md_unregister_entities(fmd);
 	media_device_unregister(&fmd->media_dev);
 	fimc_md_put_clocks(fmd);
-	kfree(fmd);
 	return 0;
 }
 
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c
index 130335c..f44f690 100644
--- a/drivers/media/video/s5p-fimc/mipi-csis.c
+++ b/drivers/media/video/s5p-fimc/mipi-csis.c
@@ -1,8 +1,8 @@
 /*
  * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
  *
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki, <s.nawrocki@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
@@ -100,7 +100,6 @@
  * @pads: CSIS pads array
  * @sd: v4l2_subdev associated with CSIS device instance
  * @pdev: CSIS platform device
- * @regs_res: requested I/O register memory resource
  * @regs: mmaped I/O registers memory
  * @clock: CSIS clocks
  * @irq: requested s5p-mipi-csis irq number
@@ -113,7 +112,6 @@
 	struct media_pad pads[CSIS_PADS_NUM];
 	struct v4l2_subdev sd;
 	struct platform_device *pdev;
-	struct resource *regs_res;
 	void __iomem *regs;
 	struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES];
 	struct clk *clock[NUM_CSIS_CLOCKS];
@@ -258,26 +256,36 @@
 {
 	int i;
 
-	for (i = 0; i < NUM_CSIS_CLOCKS; i++)
-		if (!IS_ERR_OR_NULL(state->clock[i]))
-			clk_put(state->clock[i]);
+	for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
+		if (IS_ERR_OR_NULL(state->clock[i]))
+			continue;
+		clk_unprepare(state->clock[i]);
+		clk_put(state->clock[i]);
+		state->clock[i] = NULL;
+	}
 }
 
 static int s5pcsis_clk_get(struct csis_state *state)
 {
 	struct device *dev = &state->pdev->dev;
-	int i;
+	int i, ret;
 
 	for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
 		state->clock[i] = clk_get(dev, csi_clock_name[i]);
-		if (IS_ERR(state->clock[i])) {
-			s5pcsis_clk_put(state);
-			dev_err(dev, "failed to get clock: %s\n",
-				csi_clock_name[i]);
-			return -ENXIO;
+		if (IS_ERR(state->clock[i]))
+			goto err;
+		ret = clk_prepare(state->clock[i]);
+		if (ret < 0) {
+			clk_put(state->clock[i]);
+			state->clock[i] = NULL;
+			goto err;
 		}
 	}
 	return 0;
+err:
+	s5pcsis_clk_put(state);
+	dev_err(dev, "failed to get clock: %s\n", csi_clock_name[i]);
+	return -ENXIO;
 }
 
 static int s5pcsis_s_power(struct v4l2_subdev *sd, int on)
@@ -480,12 +488,11 @@
 {
 	struct s5p_platform_mipi_csis *pdata;
 	struct resource *mem_res;
-	struct resource *regs_res;
 	struct csis_state *state;
 	int ret = -ENOMEM;
 	int i;
 
-	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
 	if (!state)
 		return -ENOMEM;
 
@@ -495,52 +502,27 @@
 	pdata = pdev->dev.platform_data;
 	if (pdata == NULL || pdata->phy_enable == NULL) {
 		dev_err(&pdev->dev, "Platform data not fully specified\n");
-		goto e_free;
+		return -EINVAL;
 	}
 
 	if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) ||
 	    pdata->lanes > CSIS0_MAX_LANES) {
-		ret = -EINVAL;
 		dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n",
 			pdata->lanes);
-		goto e_free;
+		return -EINVAL;
 	}
 
 	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem_res) {
-		dev_err(&pdev->dev, "Failed to get IO memory region\n");
-		goto e_free;
+	state->regs = devm_request_and_ioremap(&pdev->dev, mem_res);
+	if (state->regs == NULL) {
+		dev_err(&pdev->dev, "Failed to request and remap io memory\n");
+		return -ENXIO;
 	}
 
-	regs_res = request_mem_region(mem_res->start, resource_size(mem_res),
-				      pdev->name);
-	if (!regs_res) {
-		dev_err(&pdev->dev, "Failed to request IO memory region\n");
-		goto e_free;
-	}
-	state->regs_res = regs_res;
-
-	state->regs = ioremap(mem_res->start, resource_size(mem_res));
-	if (!state->regs) {
-		dev_err(&pdev->dev, "Failed to remap IO region\n");
-		goto e_reqmem;
-	}
-
-	ret = s5pcsis_clk_get(state);
-	if (ret)
-		goto e_unmap;
-
-	clk_enable(state->clock[CSIS_CLK_MUX]);
-	if (pdata->clk_rate)
-		clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate);
-	else
-		dev_WARN(&pdev->dev, "No clock frequency specified!\n");
-
 	state->irq = platform_get_irq(pdev, 0);
 	if (state->irq < 0) {
-		ret = state->irq;
 		dev_err(&pdev->dev, "Failed to get irq\n");
-		goto e_clkput;
+		return state->irq;
 	}
 
 	for (i = 0; i < CSIS_NUM_SUPPLIES; i++)
@@ -549,12 +531,22 @@
 	ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES,
 				 state->supplies);
 	if (ret)
+		return ret;
+
+	ret = s5pcsis_clk_get(state);
+	if (ret)
 		goto e_clkput;
 
-	ret = request_irq(state->irq, s5pcsis_irq_handler, 0,
-			  dev_name(&pdev->dev), state);
+	clk_enable(state->clock[CSIS_CLK_MUX]);
+	if (pdata->clk_rate)
+		clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate);
+	else
+		dev_WARN(&pdev->dev, "No clock frequency specified!\n");
+
+	ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler,
+			       0, dev_name(&pdev->dev), state);
 	if (ret) {
-		dev_err(&pdev->dev, "request_irq failed\n");
+		dev_err(&pdev->dev, "Interrupt request failed\n");
 		goto e_regput;
 	}
 
@@ -573,7 +565,7 @@
 	ret = media_entity_init(&state->sd.entity,
 				CSIS_PADS_NUM, state->pads, 0);
 	if (ret < 0)
-		goto e_irqfree;
+		goto e_clkput;
 
 	/* This allows to retrieve the platform device id by the host driver */
 	v4l2_set_subdevdata(&state->sd, pdev);
@@ -582,22 +574,13 @@
 	platform_set_drvdata(pdev, &state->sd);
 
 	pm_runtime_enable(&pdev->dev);
-
 	return 0;
 
-e_irqfree:
-	free_irq(state->irq, state);
 e_regput:
 	regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
 e_clkput:
 	clk_disable(state->clock[CSIS_CLK_MUX]);
 	s5pcsis_clk_put(state);
-e_unmap:
-	iounmap(state->regs);
-e_reqmem:
-	release_mem_region(regs_res->start, resource_size(regs_res));
-e_free:
-	kfree(state);
 	return ret;
 }
 
@@ -699,21 +682,15 @@
 {
 	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
 	struct csis_state *state = sd_to_csis_state(sd);
-	struct resource *res = state->regs_res;
 
 	pm_runtime_disable(&pdev->dev);
-	s5pcsis_suspend(&pdev->dev);
+	s5pcsis_pm_suspend(&pdev->dev, false);
 	clk_disable(state->clock[CSIS_CLK_MUX]);
 	pm_runtime_set_suspended(&pdev->dev);
-
 	s5pcsis_clk_put(state);
 	regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
 
 	media_entity_cleanup(&state->sd.entity);
-	free_irq(state->irq, state);
-	iounmap(state->regs);
-	release_mem_region(res->start, resource_size(res));
-	kfree(state);
 
 	return 0;
 }
diff --git a/drivers/media/video/s5p-g2d/g2d-hw.c b/drivers/media/video/s5p-g2d/g2d-hw.c
index 39937cf..5b86cbe 100644
--- a/drivers/media/video/s5p-g2d/g2d-hw.c
+++ b/drivers/media/video/s5p-g2d/g2d-hw.c
@@ -77,6 +77,11 @@
 	w(r, ROP4_REG);
 }
 
+void g2d_set_flip(struct g2d_dev *d, u32 r)
+{
+	w(r, SRC_MSK_DIRECT_REG);
+}
+
 u32 g2d_cmd_stretch(u32 e)
 {
 	e &= 1;
diff --git a/drivers/media/video/s5p-g2d/g2d.c b/drivers/media/video/s5p-g2d/g2d.c
index febaa67..789de74 100644
--- a/drivers/media/video/s5p-g2d/g2d.c
+++ b/drivers/media/video/s5p-g2d/g2d.c
@@ -178,6 +178,9 @@
 {
 	struct g2d_ctx *ctx = container_of(ctrl->handler, struct g2d_ctx,
 								ctrl_handler);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->dev->ctrl_lock, flags);
 	switch (ctrl->id) {
 	case V4L2_CID_COLORFX:
 		if (ctrl->val == V4L2_COLORFX_NEGATIVE)
@@ -185,10 +188,13 @@
 		else
 			ctx->rop = ROP4_COPY;
 		break;
-	default:
-		v4l2_err(&ctx->dev->v4l2_dev, "unknown control\n");
-		return -EINVAL;
+
+	case V4L2_CID_HFLIP:
+		ctx->flip = ctx->ctrl_hflip->val | (ctx->ctrl_vflip->val << 1);
+		break;
+
 	}
+	spin_unlock_irqrestore(&ctx->dev->ctrl_lock, flags);
 	return 0;
 }
 
@@ -200,11 +206,13 @@
 {
 	struct g2d_dev *dev = ctx->dev;
 
-	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1);
-	if (ctx->ctrl_handler.error) {
-		v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n");
-		return ctx->ctrl_handler.error;
-	}
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
+
+	ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops,
+						V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+	ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops,
+						V4L2_CID_VFLIP, 0, 1, 1, 0);
 
 	v4l2_ctrl_new_std_menu(
 		&ctx->ctrl_handler,
@@ -215,10 +223,14 @@
 		V4L2_COLORFX_NONE);
 
 	if (ctx->ctrl_handler.error) {
-		v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n");
-		return ctx->ctrl_handler.error;
+		int err = ctx->ctrl_handler.error;
+		v4l2_err(&dev->v4l2_dev, "g2d_setup_ctrls failed\n");
+		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+		return err;
 	}
 
+	v4l2_ctrl_cluster(2, &ctx->ctrl_hflip);
+
 	return 0;
 }
 
@@ -547,6 +559,7 @@
 	struct g2d_ctx *ctx = prv;
 	struct g2d_dev *dev = ctx->dev;
 	struct vb2_buffer *src, *dst;
+	unsigned long flags;
 	u32 cmd = 0;
 
 	dev->curr = ctx;
@@ -557,6 +570,8 @@
 	clk_enable(dev->gate);
 	g2d_reset(dev);
 
+	spin_lock_irqsave(&dev->ctrl_lock, flags);
+
 	g2d_set_src_size(dev, &ctx->in);
 	g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(src, 0));
 
@@ -564,11 +579,15 @@
 	g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(dst, 0));
 
 	g2d_set_rop4(dev, ctx->rop);
+	g2d_set_flip(dev, ctx->flip);
+
 	if (ctx->in.c_width != ctx->out.c_width ||
 		ctx->in.c_height != ctx->out.c_height)
 		cmd |= g2d_cmd_stretch(1);
 	g2d_set_cmd(dev, cmd);
 	g2d_start(dev);
+
+	spin_unlock_irqrestore(&dev->ctrl_lock, flags);
 }
 
 static irqreturn_t g2d_isr(int irq, void *prv)
@@ -658,7 +677,7 @@
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev)
 		return -ENOMEM;
-	spin_lock_init(&dev->irqlock);
+	spin_lock_init(&dev->ctrl_lock);
 	mutex_init(&dev->mutex);
 	atomic_set(&dev->num_inst, 0);
 	init_waitqueue_head(&dev->irq_queue);
@@ -693,18 +712,30 @@
 		goto unmap_regs;
 	}
 
+	ret = clk_prepare(dev->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to prepare g2d clock\n");
+		goto put_clk;
+	}
+
 	dev->gate = clk_get(&pdev->dev, "fimg2d");
 	if (IS_ERR_OR_NULL(dev->gate)) {
 		dev_err(&pdev->dev, "failed to get g2d clock gate\n");
 		ret = -ENXIO;
-		goto put_clk;
+		goto unprep_clk;
+	}
+
+	ret = clk_prepare(dev->gate);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to prepare g2d clock gate\n");
+		goto put_clk_gate;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "failed to find IRQ\n");
 		ret = -ENXIO;
-		goto put_clk_gate;
+		goto unprep_clk_gate;
 	}
 
 	dev->irq = res->start;
@@ -764,8 +795,12 @@
 	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
 rel_irq:
 	free_irq(dev->irq, dev);
+unprep_clk_gate:
+	clk_unprepare(dev->gate);
 put_clk_gate:
 	clk_put(dev->gate);
+unprep_clk:
+	clk_unprepare(dev->clk);
 put_clk:
 	clk_put(dev->clk);
 unmap_regs:
@@ -787,7 +822,9 @@
 	v4l2_device_unregister(&dev->v4l2_dev);
 	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
 	free_irq(dev->irq, dev);
+	clk_unprepare(dev->gate);
 	clk_put(dev->gate);
+	clk_unprepare(dev->clk);
 	clk_put(dev->clk);
 	iounmap(dev->regs);
 	release_resource(dev->res_regs);
diff --git a/drivers/media/video/s5p-g2d/g2d.h b/drivers/media/video/s5p-g2d/g2d.h
index 5eae901..1b82065 100644
--- a/drivers/media/video/s5p-g2d/g2d.h
+++ b/drivers/media/video/s5p-g2d/g2d.h
@@ -20,7 +20,7 @@
 	struct v4l2_m2m_dev	*m2m_dev;
 	struct video_device	*vfd;
 	struct mutex		mutex;
-	spinlock_t		irqlock;
+	spinlock_t		ctrl_lock;
 	atomic_t		num_inst;
 	struct vb2_alloc_ctx	*alloc_ctx;
 	struct resource		*res_regs;
@@ -57,8 +57,11 @@
 	struct v4l2_m2m_ctx     *m2m_ctx;
 	struct g2d_frame	in;
 	struct g2d_frame	out;
+	struct v4l2_ctrl	*ctrl_hflip;
+	struct v4l2_ctrl	*ctrl_vflip;
 	struct v4l2_ctrl_handler ctrl_handler;
 	u32 rop;
+	u32 flip;
 };
 
 struct g2d_fmt {
@@ -77,6 +80,7 @@
 void g2d_start(struct g2d_dev *d);
 void g2d_clear_int(struct g2d_dev *d);
 void g2d_set_rop4(struct g2d_dev *d, u32 r);
+void g2d_set_flip(struct g2d_dev *d, u32 r);
 u32 g2d_cmd_stretch(u32 e);
 void g2d_set_cmd(struct g2d_dev *d, u32 c);
 
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.c b/drivers/media/video/s5p-jpeg/jpeg-core.c
index 1105a87..5a49c30 100644
--- a/drivers/media/video/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/video/s5p-jpeg/jpeg-core.c
@@ -32,10 +32,9 @@
 
 static struct s5p_jpeg_fmt formats_enc[] = {
 	{
-		.name		= "YUV 4:2:0 planar, YCbCr",
-		.fourcc		= V4L2_PIX_FMT_YUV420,
-		.depth		= 12,
-		.colplanes	= 3,
+		.name		= "JPEG JFIF",
+		.fourcc		= V4L2_PIX_FMT_JPEG,
+		.colplanes	= 1,
 		.types		= MEM2MEM_CAPTURE,
 	},
 	{
@@ -43,7 +42,7 @@
 		.fourcc		= V4L2_PIX_FMT_YUYV,
 		.depth		= 16,
 		.colplanes	= 1,
-		.types		= MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+		.types		= MEM2MEM_OUTPUT,
 	},
 	{
 		.name		= "RGB565",
@@ -203,6 +202,16 @@
 	0xf9, 0xfa
 };
 
+static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
+{
+	return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
+}
+
+static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
+{
+	return container_of(fh, struct s5p_jpeg_ctx, fh);
+}
+
 static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl,
 		   unsigned long tab, int len)
 {
@@ -269,6 +278,7 @@
 		      struct vb2_queue *dst_vq);
 static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
 						 __u32 pixelformat);
+static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
 
 static int s5p_jpeg_open(struct file *file)
 {
@@ -276,12 +286,18 @@
 	struct video_device *vfd = video_devdata(file);
 	struct s5p_jpeg_ctx *ctx;
 	struct s5p_jpeg_fmt *out_fmt;
+	int ret = 0;
 
 	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
-	file->private_data = ctx;
+	v4l2_fh_init(&ctx->fh, vfd);
+	/* Use separate control handler per file handle */
+	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+
 	ctx->jpeg = jpeg;
 	if (vfd == jpeg->vfd_encoder) {
 		ctx->mode = S5P_JPEG_ENCODE;
@@ -291,24 +307,35 @@
 		out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG);
 	}
 
+	ret = s5p_jpeg_controls_create(ctx);
+	if (ret < 0)
+		goto error;
+
 	ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
 	if (IS_ERR(ctx->m2m_ctx)) {
-		int err = PTR_ERR(ctx->m2m_ctx);
-		kfree(ctx);
-		return err;
+		ret = PTR_ERR(ctx->m2m_ctx);
+		goto error;
 	}
 
 	ctx->out_q.fmt = out_fmt;
 	ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV);
-
 	return 0;
+
+error:
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+	return ret;
 }
 
 static int s5p_jpeg_release(struct file *file)
 {
-	struct s5p_jpeg_ctx *ctx = file->private_data;
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
 
 	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
 	kfree(ctx);
 
 	return 0;
@@ -317,14 +344,14 @@
 static unsigned int s5p_jpeg_poll(struct file *file,
 				 struct poll_table_struct *wait)
 {
-	struct s5p_jpeg_ctx *ctx = file->private_data;
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
 
 	return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
 }
 
 static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct s5p_jpeg_ctx *ctx = file->private_data;
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
 
 	return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
 }
@@ -448,7 +475,7 @@
 static int s5p_jpeg_querycap(struct file *file, void *priv,
 			   struct v4l2_capability *cap)
 {
-	struct s5p_jpeg_ctx *ctx = priv;
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
 	if (ctx->mode == S5P_JPEG_ENCODE) {
 		strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
@@ -497,9 +524,7 @@
 static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
 				   struct v4l2_fmtdesc *f)
 {
-	struct s5p_jpeg_ctx *ctx;
-
-	ctx = priv;
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
 	if (ctx->mode == S5P_JPEG_ENCODE)
 		return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
@@ -511,9 +536,7 @@
 static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
 				   struct v4l2_fmtdesc *f)
 {
-	struct s5p_jpeg_ctx *ctx;
-
-	ctx = priv;
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
 	if (ctx->mode == S5P_JPEG_ENCODE)
 		return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
@@ -538,7 +561,7 @@
 	struct vb2_queue *vq;
 	struct s5p_jpeg_q_data *q_data = NULL;
 	struct v4l2_pix_format *pix = &f->fmt.pix;
-	struct s5p_jpeg_ctx *ct = priv;
+	struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
 
 	vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type);
 	if (!vq)
@@ -659,8 +682,8 @@
 static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
 				  struct v4l2_format *f)
 {
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 	struct s5p_jpeg_fmt *fmt;
-	struct s5p_jpeg_ctx *ctx = priv;
 
 	fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
 	if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
@@ -676,8 +699,8 @@
 static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
 				  struct v4l2_format *f)
 {
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 	struct s5p_jpeg_fmt *fmt;
-	struct s5p_jpeg_ctx *ctx = priv;
 
 	fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
 	if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
@@ -728,7 +751,7 @@
 	if (ret)
 		return ret;
 
-	return s5p_jpeg_s_fmt(priv, f);
+	return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
 }
 
 static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
@@ -740,13 +763,13 @@
 	if (ret)
 		return ret;
 
-	return s5p_jpeg_s_fmt(priv, f);
+	return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
 }
 
 static int s5p_jpeg_reqbufs(struct file *file, void *priv,
 			  struct v4l2_requestbuffers *reqbufs)
 {
-	struct s5p_jpeg_ctx *ctx = priv;
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
 	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
 }
@@ -754,14 +777,14 @@
 static int s5p_jpeg_querybuf(struct file *file, void *priv,
 			   struct v4l2_buffer *buf)
 {
-	struct s5p_jpeg_ctx *ctx = priv;
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
 	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
 }
 
 static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 {
-	struct s5p_jpeg_ctx *ctx = priv;
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
 	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
 }
@@ -769,7 +792,7 @@
 static int s5p_jpeg_dqbuf(struct file *file, void *priv,
 			  struct v4l2_buffer *buf)
 {
-	struct s5p_jpeg_ctx *ctx = priv;
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
 	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
 }
@@ -777,7 +800,7 @@
 static int s5p_jpeg_streamon(struct file *file, void *priv,
 			   enum v4l2_buf_type type)
 {
-	struct s5p_jpeg_ctx *ctx = priv;
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
 	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
 }
@@ -785,7 +808,7 @@
 static int s5p_jpeg_streamoff(struct file *file, void *priv,
 			    enum v4l2_buf_type type)
 {
-	struct s5p_jpeg_ctx *ctx = priv;
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
 	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
 }
@@ -793,7 +816,7 @@
 int s5p_jpeg_g_selection(struct file *file, void *priv,
 			 struct v4l2_selection *s)
 {
-	struct s5p_jpeg_ctx *ctx = priv;
+	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
 	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
 	    s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -822,33 +845,89 @@
 	return 0;
 }
 
-static int s5p_jpeg_g_jpegcomp(struct file *file, void *priv,
-			       struct v4l2_jpegcompression *compr)
+/*
+ * V4L2 controls
+ */
+
+static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct s5p_jpeg_ctx *ctx = priv;
+	struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
+	struct s5p_jpeg *jpeg = ctx->jpeg;
+	unsigned long flags;
 
-	if (ctx->mode == S5P_JPEG_DECODE)
-		return -ENOTTY;
+	switch (ctrl->id) {
+	case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+		spin_lock_irqsave(&jpeg->slock, flags);
 
-	memset(compr, 0, sizeof(*compr));
-	compr->quality = ctx->compr_quality;
+		WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY);
+		if (ctx->subsampling > 2)
+			ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
+		else
+			ctrl->val = ctx->subsampling;
+		spin_unlock_irqrestore(&jpeg->slock, flags);
+		break;
+	}
 
 	return 0;
 }
 
-static int s5p_jpeg_s_jpegcomp(struct file *file, void *priv,
-			       struct v4l2_jpegcompression *compr)
+static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct s5p_jpeg_ctx *ctx = priv;
+	struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->jpeg->slock, flags);
+
+	switch (ctrl->id) {
+	case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+		ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - ctrl->val;
+		break;
+	case V4L2_CID_JPEG_RESTART_INTERVAL:
+		ctx->restart_interval = ctrl->val;
+		break;
+	case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+		ctx->subsampling = ctrl->val;
+		break;
+	}
+
+	spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
+	.g_volatile_ctrl	= s5p_jpeg_g_volatile_ctrl,
+	.s_ctrl			= s5p_jpeg_s_ctrl,
+};
+
+static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
+{
+	unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
+	struct v4l2_ctrl *ctrl;
+
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
+
+	if (ctx->mode == S5P_JPEG_ENCODE) {
+		v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
+				  V4L2_CID_JPEG_COMPRESSION_QUALITY,
+				  0, 3, 1, 3);
+
+		v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
+				  V4L2_CID_JPEG_RESTART_INTERVAL,
+				  0, 3, 0xffff, 0);
+		mask = ~0x06; /* 422, 420 */
+	}
+
+	ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
+				      V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
+				      V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
+				      V4L2_JPEG_CHROMA_SUBSAMPLING_422);
+
+	if (ctx->ctrl_handler.error)
+		return ctx->ctrl_handler.error;
 
 	if (ctx->mode == S5P_JPEG_DECODE)
-		return -ENOTTY;
-
-	compr->quality = clamp(compr->quality, S5P_JPEG_COMPR_QUAL_BEST,
-			       S5P_JPEG_COMPR_QUAL_WORST);
-
-	ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - compr->quality;
-
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
+			V4L2_CTRL_FLAG_READ_ONLY;
 	return 0;
 }
 
@@ -877,9 +956,6 @@
 	.vidioc_streamoff		= s5p_jpeg_streamoff,
 
 	.vidioc_g_selection		= s5p_jpeg_g_selection,
-
-	.vidioc_g_jpegcomp		= s5p_jpeg_g_jpegcomp,
-	.vidioc_s_jpegcomp		= s5p_jpeg_s_jpegcomp,
 };
 
 /*
@@ -908,13 +984,8 @@
 			jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565);
 		else
 			jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422);
-		if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
-			jpeg_subsampling_mode(jpeg->regs,
-					      S5P_JPEG_SUBSAMPLING_422);
-		else
-			jpeg_subsampling_mode(jpeg->regs,
-					      S5P_JPEG_SUBSAMPLING_420);
-		jpeg_dri(jpeg->regs, 0);
+		jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
+		jpeg_dri(jpeg->regs, ctx->restart_interval);
 		jpeg_x(jpeg->regs, ctx->out_q.w);
 		jpeg_y(jpeg->regs, ctx->out_q.h);
 		jpeg_imgadr(jpeg->regs, src_addr);
@@ -953,14 +1024,18 @@
 		jpeg_htbl_dc(jpeg->regs, 2);
 		jpeg_htbl_ac(jpeg->regs, 3);
 		jpeg_htbl_dc(jpeg->regs, 3);
-	} else {
+	} else { /* S5P_JPEG_DECODE */
 		jpeg_rst_int_enable(jpeg->regs, true);
 		jpeg_data_num_int_enable(jpeg->regs, true);
 		jpeg_final_mcu_num_int_enable(jpeg->regs, true);
-		jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
+		if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
+			jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
+		else
+			jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
 		jpeg_jpgadr(jpeg->regs, src_addr);
 		jpeg_imgadr(jpeg->regs, dst_addr);
 	}
+
 	jpeg_start(jpeg->regs);
 }
 
@@ -1162,6 +1237,8 @@
 	bool timer_elapsed = false;
 	bool op_completed = false;
 
+	spin_lock(&jpeg->slock);
+
 	curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
 
 	src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
@@ -1192,6 +1269,9 @@
 	v4l2_m2m_buf_done(dst_buf, state);
 	v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx);
 
+	curr_ctx->subsampling = jpeg_get_subsampling_mode(jpeg->regs);
+	spin_unlock(&jpeg->slock);
+
 	jpeg_clear_int(jpeg->regs);
 
 	return IRQ_HANDLED;
@@ -1215,6 +1295,7 @@
 		return -ENOMEM;
 
 	mutex_init(&jpeg->lock);
+	spin_lock_init(&jpeg->slock);
 	jpeg->dev = &pdev->dev;
 
 	/* memory-mapped registers */
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.h b/drivers/media/video/s5p-jpeg/jpeg-core.h
index facad61..38d7367 100644
--- a/drivers/media/video/s5p-jpeg/jpeg-core.h
+++ b/drivers/media/video/s5p-jpeg/jpeg-core.h
@@ -14,6 +14,8 @@
 #define JPEG_CORE_H_
 
 #include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
 
 #define S5P_JPEG_M2M_NAME		"s5p-jpeg"
 
@@ -47,6 +49,7 @@
 /**
  * struct s5p_jpeg - JPEG IP abstraction
  * @lock:		the mutex protecting this structure
+ * @slock:		spinlock protecting the device contexts
  * @v4l2_dev:		v4l2 device for mem2mem mode
  * @vfd_encoder:	video device node for encoder mem2mem mode
  * @vfd_decoder:	video device node for decoder mem2mem mode
@@ -60,6 +63,7 @@
  */
 struct s5p_jpeg {
 	struct mutex		lock;
+	struct spinlock		slock;
 
 	struct v4l2_device	v4l2_dev;
 	struct video_device	*vfd_encoder;
@@ -117,15 +121,20 @@
  * @out_q:		source (output) queue information
  * @cap_fmt:		destination (capture) queue queue information
  * @hdr_parsed:		set if header has been parsed during decompression
+ * @ctrl_handler:	controls handler
  */
 struct s5p_jpeg_ctx {
 	struct s5p_jpeg		*jpeg;
 	unsigned int		mode;
-	unsigned int		compr_quality;
+	unsigned short		compr_quality;
+	unsigned short		restart_interval;
+	unsigned short		subsampling;
 	struct v4l2_m2m_ctx	*m2m_ctx;
 	struct s5p_jpeg_q_data	out_q;
 	struct s5p_jpeg_q_data	cap_q;
+	struct v4l2_fh		fh;
 	bool			hdr_parsed;
+	struct v4l2_ctrl_handler ctrl_handler;
 };
 
 /**
diff --git a/drivers/media/video/s5p-jpeg/jpeg-hw.h b/drivers/media/video/s5p-jpeg/jpeg-hw.h
index e10c744..f12f0fd 100644
--- a/drivers/media/video/s5p-jpeg/jpeg-hw.h
+++ b/drivers/media/video/s5p-jpeg/jpeg-hw.h
@@ -13,6 +13,7 @@
 #define JPEG_HW_H_
 
 #include <linux/io.h>
+#include <linux/videodev2.h>
 
 #include "jpeg-hw.h"
 #include "jpeg-regs.h"
@@ -25,8 +26,6 @@
 #define S5P_JPEG_DECODE			1
 #define S5P_JPEG_RAW_IN_565		0
 #define S5P_JPEG_RAW_IN_422		1
-#define S5P_JPEG_SUBSAMPLING_422	0
-#define S5P_JPEG_SUBSAMPLING_420	1
 #define S5P_JPEG_RAW_OUT_422		0
 #define S5P_JPEG_RAW_OUT_420		1
 
@@ -91,21 +90,26 @@
 	writel(reg, regs + S5P_JPGMOD);
 }
 
-static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned long mode)
+static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode)
 {
 	unsigned long reg, m;
 
-	m = S5P_SUBSAMPLING_MODE_422;
-	if (mode == S5P_JPEG_SUBSAMPLING_422)
-		m = S5P_SUBSAMPLING_MODE_422;
-	else if (mode == S5P_JPEG_SUBSAMPLING_420)
+	if (mode == V4L2_JPEG_CHROMA_SUBSAMPLING_420)
 		m = S5P_SUBSAMPLING_MODE_420;
+	else
+		m = S5P_SUBSAMPLING_MODE_422;
+
 	reg = readl(regs + S5P_JPGMOD);
 	reg &= ~S5P_SUBSAMPLING_MODE_MASK;
 	reg |= m;
 	writel(reg, regs + S5P_JPGMOD);
 }
 
+static inline unsigned int jpeg_get_subsampling_mode(void __iomem *regs)
+{
+	return readl(regs + S5P_JPGMOD) & S5P_SUBSAMPLING_MODE_MASK;
+}
+
 static inline void jpeg_dri(void __iomem *regs, unsigned int dri)
 {
 	unsigned long reg;
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_pm.c b/drivers/media/video/s5p-mfc/s5p_mfc_pm.c
index f6a3035..738a607 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_pm.c
+++ b/drivers/media/video/s5p-mfc/s5p_mfc_pm.c
@@ -41,15 +41,29 @@
 	pm->clock_gate = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME);
 	if (IS_ERR(pm->clock_gate)) {
 		mfc_err("Failed to get clock-gating control\n");
-		ret = -ENOENT;
+		ret = PTR_ERR(pm->clock_gate);
 		goto err_g_ip_clk;
 	}
+
+	ret = clk_prepare(pm->clock_gate);
+	if (ret) {
+		mfc_err("Failed to preapre clock-gating control\n");
+		goto err_p_ip_clk;
+	}
+
 	pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME);
 	if (IS_ERR(pm->clock)) {
 		mfc_err("Failed to get MFC clock\n");
-		ret = -ENOENT;
+		ret = PTR_ERR(pm->clock);
 		goto err_g_ip_clk_2;
 	}
+
+	ret = clk_prepare(pm->clock);
+	if (ret) {
+		mfc_err("Failed to prepare MFC clock\n");
+		goto err_p_ip_clk_2;
+	}
+
 	atomic_set(&pm->power, 0);
 #ifdef CONFIG_PM_RUNTIME
 	pm->device = &dev->plat_dev->dev;
@@ -59,7 +73,11 @@
 	atomic_set(&clk_ref, 0);
 #endif
 	return 0;
+err_p_ip_clk_2:
+	clk_put(pm->clock);
 err_g_ip_clk_2:
+	clk_unprepare(pm->clock_gate);
+err_p_ip_clk:
 	clk_put(pm->clock_gate);
 err_g_ip_clk:
 	return ret;
@@ -67,7 +85,9 @@
 
 void s5p_mfc_final_pm(struct s5p_mfc_dev *dev)
 {
+	clk_unprepare(pm->clock_gate);
 	clk_put(pm->clock_gate);
+	clk_unprepare(pm->clock);
 	clk_put(pm->clock);
 #ifdef CONFIG_PM_RUNTIME
 	pm_runtime_disable(pm->device);
diff --git a/drivers/media/video/s5p-tv/Kconfig b/drivers/media/video/s5p-tv/Kconfig
index f2a0977..f248b28 100644
--- a/drivers/media/video/s5p-tv/Kconfig
+++ b/drivers/media/video/s5p-tv/Kconfig
@@ -46,6 +46,16 @@
 	  as module. It is an I2C driver, that exposes a V4L2
 	  subdev for use by other drivers.
 
+config VIDEO_SAMSUNG_S5P_SII9234
+	tristate "Samsung SII9234 Driver"
+	depends on VIDEO_DEV && VIDEO_V4L2 && I2C
+	depends on VIDEO_SAMSUNG_S5P_TV
+	help
+	  Say Y here if you want support for the MHL interface
+	  in S5P Samsung SoC. The driver can be compiled
+	  as module. It is an I2C driver, that exposes a V4L2
+	  subdev for use by other drivers.
+
 config VIDEO_SAMSUNG_S5P_SDO
 	tristate "Samsung Analog TV Driver"
 	depends on VIDEO_DEV && VIDEO_V4L2
diff --git a/drivers/media/video/s5p-tv/Makefile b/drivers/media/video/s5p-tv/Makefile
index 37e4c17..f49e756 100644
--- a/drivers/media/video/s5p-tv/Makefile
+++ b/drivers/media/video/s5p-tv/Makefile
@@ -8,6 +8,8 @@
 
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY) += s5p-hdmiphy.o
 s5p-hdmiphy-y += hdmiphy_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SII9234) += s5p-sii9234.o
+s5p-sii9234-y += sii9234_drv.o
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o
 s5p-hdmi-y += hdmi_drv.o
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o
diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c
index 8b41a04..4865d25 100644
--- a/drivers/media/video/s5p-tv/hdmi_drv.c
+++ b/drivers/media/video/s5p-tv/hdmi_drv.c
@@ -30,6 +30,7 @@
 #include <linux/clk.h>
 #include <linux/regulator/consumer.h>
 
+#include <media/s5p_hdmi.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-device.h>
@@ -66,6 +67,8 @@
 	struct v4l2_device v4l2_dev;
 	/** subdev of HDMIPHY interface */
 	struct v4l2_subdev *phy_sd;
+	/** subdev of MHL interface */
+	struct v4l2_subdev *mhl_sd;
 	/** configuration of current graphic mode */
 	const struct hdmi_preset_conf *cur_conf;
 	/** current preset */
@@ -74,10 +77,6 @@
 	struct hdmi_resources res;
 };
 
-struct hdmi_driver_data {
-	int hdmiphy_bus;
-};
-
 struct hdmi_tg_regs {
 	u8 cmd;
 	u8 h_fsz_l;
@@ -129,23 +128,11 @@
 	struct v4l2_mbus_framefmt mbus_fmt;
 };
 
-/* I2C module and id for HDMIPHY */
-static struct i2c_board_info hdmiphy_info = {
-	I2C_BOARD_INFO("hdmiphy", 0x38),
-};
-
-static struct hdmi_driver_data hdmi_driver_data[] = {
-	{ .hdmiphy_bus = 3 },
-	{ .hdmiphy_bus = 8 },
-};
-
 static struct platform_device_id hdmi_driver_types[] = {
 	{
 		.name		= "s5pv210-hdmi",
-		.driver_data	= (unsigned long)&hdmi_driver_data[0],
 	}, {
 		.name		= "exynos4-hdmi",
-		.driver_data	= (unsigned long)&hdmi_driver_data[1],
 	}, {
 		/* end node */
 	}
@@ -587,7 +574,15 @@
 	if (tries == 0) {
 		dev_err(dev, "hdmiphy's pll could not reach steady state.\n");
 		v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
-		hdmi_dumpregs(hdev, "s_stream");
+		hdmi_dumpregs(hdev, "hdmiphy - s_stream");
+		return -EIO;
+	}
+
+	/* starting MHL */
+	ret = v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 1);
+	if (hdev->mhl_sd && ret) {
+		v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+		hdmi_dumpregs(hdev, "mhl - s_stream");
 		return -EIO;
 	}
 
@@ -618,6 +613,7 @@
 	clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
 	clk_enable(res->sclk_hdmi);
 
+	v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 0);
 	v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
 
 	hdmi_dumpregs(hdev, "streamoff");
@@ -739,6 +735,7 @@
 	struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
 
 	dev_dbg(dev, "%s\n", __func__);
+	v4l2_subdev_call(hdev->mhl_sd, core, s_power, 0);
 	hdmi_resource_poweroff(&hdev->res);
 	return 0;
 }
@@ -757,6 +754,11 @@
 	if (ret)
 		goto fail;
 
+	/* starting MHL */
+	ret = v4l2_subdev_call(hdev->mhl_sd, core, s_power, 1);
+	if (hdev->mhl_sd && ret)
+		goto fail;
+
 	dev_dbg(dev, "poweron succeed\n");
 
 	return 0;
@@ -867,15 +869,21 @@
 {
 	struct device *dev = &pdev->dev;
 	struct resource *res;
-	struct i2c_adapter *phy_adapter;
+	struct i2c_adapter *adapter;
 	struct v4l2_subdev *sd;
 	struct hdmi_device *hdmi_dev = NULL;
-	struct hdmi_driver_data *drv_data;
+	struct s5p_hdmi_platform_data *pdata = dev->platform_data;
 	int ret;
 
 	dev_dbg(dev, "probe start\n");
 
-	hdmi_dev = kzalloc(sizeof(*hdmi_dev), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(dev, "platform data is missing\n");
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	hdmi_dev = devm_kzalloc(&pdev->dev, sizeof(*hdmi_dev), GFP_KERNEL);
 	if (!hdmi_dev) {
 		dev_err(dev, "out of memory\n");
 		ret = -ENOMEM;
@@ -886,7 +894,7 @@
 
 	ret = hdmi_resources_init(hdmi_dev);
 	if (ret)
-		goto fail_hdev;
+		goto fail;
 
 	/* mapping HDMI registers */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -896,24 +904,26 @@
 		goto fail_init;
 	}
 
-	hdmi_dev->regs = ioremap(res->start, resource_size(res));
+	hdmi_dev->regs = devm_ioremap(&pdev->dev, res->start,
+				      resource_size(res));
 	if (hdmi_dev->regs == NULL) {
 		dev_err(dev, "register mapping failed.\n");
 		ret = -ENXIO;
-		goto fail_hdev;
+		goto fail_init;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (res == NULL) {
 		dev_err(dev, "get interrupt resource failed.\n");
 		ret = -ENXIO;
-		goto fail_regs;
+		goto fail_init;
 	}
 
-	ret = request_irq(res->start, hdmi_irq_handler, 0, "hdmi", hdmi_dev);
+	ret = devm_request_irq(&pdev->dev, res->start, hdmi_irq_handler, 0,
+			       "hdmi", hdmi_dev);
 	if (ret) {
 		dev_err(dev, "request interrupt failed.\n");
-		goto fail_regs;
+		goto fail_init;
 	}
 	hdmi_dev->irq = res->start;
 
@@ -924,28 +934,54 @@
 	ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev);
 	if (ret) {
 		dev_err(dev, "could not register v4l2 device.\n");
-		goto fail_irq;
+		goto fail_init;
 	}
 
-	drv_data = (struct hdmi_driver_data *)
-		platform_get_device_id(pdev)->driver_data;
-	phy_adapter = i2c_get_adapter(drv_data->hdmiphy_bus);
-	if (phy_adapter == NULL) {
-		dev_err(dev, "adapter request failed\n");
+	/* testing if hdmiphy info is present */
+	if (!pdata->hdmiphy_info) {
+		dev_err(dev, "hdmiphy info is missing in platform data\n");
+		ret = -ENXIO;
+		goto fail_vdev;
+	}
+
+	adapter = i2c_get_adapter(pdata->hdmiphy_bus);
+	if (adapter == NULL) {
+		dev_err(dev, "hdmiphy adapter request failed\n");
 		ret = -ENXIO;
 		goto fail_vdev;
 	}
 
 	hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev,
-		phy_adapter, &hdmiphy_info, NULL);
+		adapter, pdata->hdmiphy_info, NULL);
 	/* on failure or not adapter is no longer useful */
-	i2c_put_adapter(phy_adapter);
+	i2c_put_adapter(adapter);
 	if (hdmi_dev->phy_sd == NULL) {
 		dev_err(dev, "missing subdev for hdmiphy\n");
 		ret = -ENODEV;
 		goto fail_vdev;
 	}
 
+	/* initialization of MHL interface if present */
+	if (pdata->mhl_info) {
+		adapter = i2c_get_adapter(pdata->mhl_bus);
+		if (adapter == NULL) {
+			dev_err(dev, "MHL adapter request failed\n");
+			ret = -ENXIO;
+			goto fail_vdev;
+		}
+
+		hdmi_dev->mhl_sd = v4l2_i2c_new_subdev_board(
+			&hdmi_dev->v4l2_dev, adapter,
+			pdata->mhl_info, NULL);
+		/* on failure or not adapter is no longer useful */
+		i2c_put_adapter(adapter);
+		if (hdmi_dev->mhl_sd == NULL) {
+			dev_err(dev, "missing subdev for MHL\n");
+			ret = -ENODEV;
+			goto fail_vdev;
+		}
+	}
+
 	clk_enable(hdmi_dev->res.hdmi);
 
 	pm_runtime_enable(dev);
@@ -962,25 +998,16 @@
 	/* storing subdev for call that have only access to struct device */
 	dev_set_drvdata(dev, sd);
 
-	dev_info(dev, "probe sucessful\n");
+	dev_info(dev, "probe successful\n");
 
 	return 0;
 
 fail_vdev:
 	v4l2_device_unregister(&hdmi_dev->v4l2_dev);
 
-fail_irq:
-	free_irq(hdmi_dev->irq, hdmi_dev);
-
-fail_regs:
-	iounmap(hdmi_dev->regs);
-
 fail_init:
 	hdmi_resources_cleanup(hdmi_dev);
 
-fail_hdev:
-	kfree(hdmi_dev);
-
 fail:
 	dev_err(dev, "probe failed\n");
 	return ret;
@@ -996,11 +1023,8 @@
 	clk_disable(hdmi_dev->res.hdmi);
 	v4l2_device_unregister(&hdmi_dev->v4l2_dev);
 	disable_irq(hdmi_dev->irq);
-	free_irq(hdmi_dev->irq, hdmi_dev);
-	iounmap(hdmi_dev->regs);
 	hdmi_resources_cleanup(hdmi_dev);
-	kfree(hdmi_dev);
-	dev_info(dev, "remove sucessful\n");
+	dev_info(dev, "remove successful\n");
 
 	return 0;
 }
diff --git a/drivers/media/video/s5p-tv/hdmiphy_drv.c b/drivers/media/video/s5p-tv/hdmiphy_drv.c
index 6693f4a..0afef77 100644
--- a/drivers/media/video/s5p-tv/hdmiphy_drv.c
+++ b/drivers/media/video/s5p-tv/hdmiphy_drv.c
@@ -175,14 +175,4 @@
 	.id_table = hdmiphy_id,
 };
 
-static int __init hdmiphy_init(void)
-{
-	return i2c_add_driver(&hdmiphy_driver);
-}
-module_init(hdmiphy_init);
-
-static void __exit hdmiphy_exit(void)
-{
-	i2c_del_driver(&hdmiphy_driver);
-}
-module_exit(hdmiphy_exit);
+module_i2c_driver(hdmiphy_driver);
diff --git a/drivers/media/video/s5p-tv/mixer_drv.c b/drivers/media/video/s5p-tv/mixer_drv.c
index 0064309..a2c0c25 100644
--- a/drivers/media/video/s5p-tv/mixer_drv.c
+++ b/drivers/media/video/s5p-tv/mixer_drv.c
@@ -444,7 +444,7 @@
 
 	kfree(mdev);
 
-	dev_info(dev, "remove sucessful\n");
+	dev_info(dev, "remove successful\n");
 	return 0;
 }
 
diff --git a/drivers/media/video/s5p-tv/sdo_drv.c b/drivers/media/video/s5p-tv/sdo_drv.c
index 059e774..f6bca2c 100644
--- a/drivers/media/video/s5p-tv/sdo_drv.c
+++ b/drivers/media/video/s5p-tv/sdo_drv.c
@@ -301,7 +301,7 @@
 	struct clk *sclk_vpll;
 
 	dev_info(dev, "probe start\n");
-	sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
+	sdev = devm_kzalloc(&pdev->dev, sizeof *sdev, GFP_KERNEL);
 	if (!sdev) {
 		dev_err(dev, "not enough memory.\n");
 		ret = -ENOMEM;
@@ -314,14 +314,14 @@
 	if (res == NULL) {
 		dev_err(dev, "get memory resource failed.\n");
 		ret = -ENXIO;
-		goto fail_sdev;
+		goto fail;
 	}
 
-	sdev->regs = ioremap(res->start, resource_size(res));
+	sdev->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
 	if (sdev->regs == NULL) {
 		dev_err(dev, "register mapping failed.\n");
 		ret = -ENXIO;
-		goto fail_sdev;
+		goto fail;
 	}
 
 	/* acquiring interrupt */
@@ -329,12 +329,13 @@
 	if (res == NULL) {
 		dev_err(dev, "get interrupt resource failed.\n");
 		ret = -ENXIO;
-		goto fail_regs;
+		goto fail;
 	}
-	ret = request_irq(res->start, sdo_irq_handler, 0, "s5p-sdo", sdev);
+	ret = devm_request_irq(&pdev->dev, res->start, sdo_irq_handler, 0,
+			       "s5p-sdo", sdev);
 	if (ret) {
 		dev_err(dev, "request interrupt failed.\n");
-		goto fail_regs;
+		goto fail;
 	}
 	sdev->irq = res->start;
 
@@ -343,7 +344,7 @@
 	if (IS_ERR_OR_NULL(sdev->sclk_dac)) {
 		dev_err(dev, "failed to get clock 'sclk_dac'\n");
 		ret = -ENXIO;
-		goto fail_irq;
+		goto fail;
 	}
 	sdev->dac = clk_get(dev, "dac");
 	if (IS_ERR_OR_NULL(sdev->dac)) {
@@ -415,12 +416,6 @@
 	clk_put(sdev->dac);
 fail_sclk_dac:
 	clk_put(sdev->sclk_dac);
-fail_irq:
-	free_irq(sdev->irq, sdev);
-fail_regs:
-	iounmap(sdev->regs);
-fail_sdev:
-	kfree(sdev);
 fail:
 	dev_info(dev, "probe failed\n");
 	return ret;
@@ -439,9 +434,6 @@
 	clk_put(sdev->dacphy);
 	clk_put(sdev->dac);
 	clk_put(sdev->sclk_dac);
-	free_irq(sdev->irq, sdev);
-	iounmap(sdev->regs);
-	kfree(sdev);
 
 	dev_info(&pdev->dev, "remove successful\n");
 	return 0;
diff --git a/drivers/media/video/s5p-tv/sii9234_drv.c b/drivers/media/video/s5p-tv/sii9234_drv.c
new file mode 100644
index 0000000..0f31ecc
--- /dev/null
+++ b/drivers/media/video/s5p-tv/sii9234_drv.c
@@ -0,0 +1,432 @@
+/*
+ * Samsung MHL interface driver
+ *
+ * Copyright (C) 2011 Samsung Electronics Co.Ltd
+ * Author: Tomasz Stanislawski <t.stanislaws@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/delay.h>
+#include <linux/err.h>
+#include <linux/freezer.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/machine.h>
+#include <linux/slab.h>
+
+#include <mach/gpio.h>
+#include <plat/gpio-cfg.h>
+
+#include <media/sii9234.h>
+#include <media/v4l2-subdev.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung MHL interface driver");
+MODULE_LICENSE("GPL");
+
+struct sii9234_context {
+	struct i2c_client *client;
+	struct regulator *power;
+	int gpio_n_reset;
+	struct v4l2_subdev sd;
+};
+
+static inline struct sii9234_context *sd_to_context(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct sii9234_context, sd);
+}
+
+static inline int sii9234_readb(struct i2c_client *client, int addr)
+{
+	return i2c_smbus_read_byte_data(client, addr);
+}
+
+static inline int sii9234_writeb(struct i2c_client *client, int addr, int value)
+{
+	return i2c_smbus_write_byte_data(client, addr, value);
+}
+
+static inline int sii9234_writeb_mask(struct i2c_client *client, int addr,
+	int value, int mask)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, addr);
+	if (ret < 0)
+		return ret;
+	ret = (ret & ~mask) | (value & mask);
+	return i2c_smbus_write_byte_data(client, addr, ret);
+}
+
+static inline int sii9234_readb_idx(struct i2c_client *client, int addr)
+{
+	int ret;
+	ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8);
+	if (ret < 0)
+		return ret;
+	ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff);
+	if (ret < 0)
+		return ret;
+	return i2c_smbus_read_byte_data(client, 0xbe);
+}
+
+static inline int sii9234_writeb_idx(struct i2c_client *client, int addr,
+	int value)
+{
+	int ret;
+	ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8);
+	if (ret < 0)
+		return ret;
+	ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff);
+	if (ret < 0)
+		return ret;
+	ret = i2c_smbus_write_byte_data(client, 0xbe, value);
+	return ret;
+}
+
+static inline int sii9234_writeb_idx_mask(struct i2c_client *client, int addr,
+	int value, int mask)
+{
+	int ret;
+
+	ret = sii9234_readb_idx(client, addr);
+	if (ret < 0)
+		return ret;
+	ret = (ret & ~mask) | (value & mask);
+	return sii9234_writeb_idx(client, addr, ret);
+}
+
+static int sii9234_reset(struct sii9234_context *ctx)
+{
+	struct i2c_client *client = ctx->client;
+	struct device *dev = &client->dev;
+	int ret, tries;
+
+	gpio_direction_output(ctx->gpio_n_reset, 1);
+	mdelay(1);
+	gpio_direction_output(ctx->gpio_n_reset, 0);
+	mdelay(1);
+	gpio_direction_output(ctx->gpio_n_reset, 1);
+	mdelay(1);
+
+	/* going to TTPI mode */
+	ret = sii9234_writeb(client, 0xc7, 0);
+	if (ret < 0) {
+		dev_err(dev, "failed to set TTPI mode\n");
+		return ret;
+	}
+	for (tries = 0; tries < 100 ; ++tries) {
+		ret = sii9234_readb(client, 0x1b);
+		if (ret > 0)
+			break;
+		if (ret < 0) {
+			dev_err(dev, "failed to reset device\n");
+			return -EIO;
+		}
+		mdelay(1);
+	}
+	if (tries == 100) {
+		dev_err(dev, "maximal number of tries reached\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int sii9234_verify_version(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	int family, rev, tpi_rev, dev_id, sub_id, hdcp, id;
+
+	family = sii9234_readb(client, 0x1b);
+	rev = sii9234_readb(client, 0x1c) & 0x0f;
+	tpi_rev = sii9234_readb(client, 0x1d) & 0x7f;
+	dev_id = sii9234_readb_idx(client, 0x0103);
+	sub_id = sii9234_readb_idx(client, 0x0102);
+	hdcp = sii9234_readb(client, 0x30);
+
+	if (family < 0 || rev < 0 || tpi_rev < 0 || dev_id < 0 ||
+		sub_id < 0 || hdcp < 0) {
+		dev_err(dev, "failed to read chip's version\n");
+		return -EIO;
+	}
+
+	id = (dev_id << 8) | sub_id;
+
+	dev_info(dev, "chip: SiL%02x family: %02x, rev: %02x\n",
+		id, family, rev);
+	dev_info(dev, "tpi_rev:%02x, hdcp: %02x\n", tpi_rev, hdcp);
+	if (id != 0x9234) {
+		dev_err(dev, "not supported chip\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static u8 data[][3] = {
+/* setup from driver created by doonsoo45.kim */
+	{ 0x01, 0x05, 0x04 }, /* Enable Auto soft reset on SCDT = 0 */
+	{ 0x01, 0x08, 0x35 }, /* Power Up TMDS Tx Core */
+	{ 0x01, 0x0d, 0x1c }, /* HDMI Transcode mode enable */
+	{ 0x01, 0x2b, 0x01 }, /* Enable HDCP Compliance workaround */
+	{ 0x01, 0x79, 0x40 }, /* daniel test...MHL_INT */
+	{ 0x01, 0x80, 0x34 }, /* Enable Rx PLL Clock Value */
+	{ 0x01, 0x90, 0x27 }, /* Enable CBUS discovery */
+	{ 0x01, 0x91, 0xe5 }, /* Skip RGND detection */
+	{ 0x01, 0x92, 0x46 }, /* Force MHD mode */
+	{ 0x01, 0x93, 0xdc }, /* Disable CBUS pull-up during RGND measurement */
+	{ 0x01, 0x94, 0x66 }, /* 1.8V CBUS VTH & GND threshold */
+	{ 0x01, 0x95, 0x31 }, /* RGND block & single discovery attempt */
+	{ 0x01, 0x96, 0x22 }, /* use 1K and 2K setting */
+	{ 0x01, 0xa0, 0x10 }, /* SIMG: Term mode */
+	{ 0x01, 0xa1, 0xfc }, /* Disable internal Mobile HD driver */
+	{ 0x01, 0xa3, 0xfa }, /* SIMG: Output Swing  default EB, 3x Clk Mult */
+	{ 0x01, 0xa5, 0x80 }, /* SIMG: RGND Hysterisis, 3x mode for Beast */
+	{ 0x01, 0xa6, 0x0c }, /* SIMG: Swing Offset */
+	{ 0x02, 0x3d, 0x3f }, /* Power up CVCC 1.2V core */
+	{ 0x03, 0x00, 0x00 }, /* SIMG: correcting HW default */
+	{ 0x03, 0x11, 0x01 }, /* Enable TxPLL Clock */
+	{ 0x03, 0x12, 0x15 }, /* Enable Tx Clock Path & Equalizer */
+	{ 0x03, 0x13, 0x60 }, /* SIMG: Set termination value */
+	{ 0x03, 0x14, 0xf0 }, /* SIMG: Change CKDT level */
+	{ 0x03, 0x17, 0x07 }, /* SIMG: PLL Calrefsel */
+	{ 0x03, 0x1a, 0x20 }, /* VCO Cal */
+	{ 0x03, 0x22, 0xe0 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x23, 0xc0 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x24, 0xa0 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x25, 0x80 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x26, 0x60 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x27, 0x40 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x28, 0x20 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x29, 0x00 }, /* SIMG: Auto EQ */
+	{ 0x03, 0x31, 0x0b }, /* SIMG: Rx PLL BW value from I2C BW ~ 4MHz */
+	{ 0x03, 0x45, 0x06 }, /* SIMG: DPLL Mode */
+	{ 0x03, 0x4b, 0x06 }, /* SIMG: Correcting HW default */
+	{ 0x03, 0x4c, 0xa0 }, /* Manual zone control */
+	{ 0x03, 0x4d, 0x02 }, /* SIMG: PLL Mode Value (order is important) */
+};
+
+static int sii9234_set_internal(struct sii9234_context *ctx)
+{
+	struct i2c_client *client = ctx->client;
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(data); ++i) {
+		int addr = (data[i][0] << 8) | data[i][1];
+		ret = sii9234_writeb_idx(client, addr, data[i][2]);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+static int sii9234_runtime_suspend(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct sii9234_context *ctx = sd_to_context(sd);
+	struct i2c_client *client = ctx->client;
+
+	dev_info(dev, "suspend start\n");
+
+	sii9234_writeb_mask(client, 0x1e, 3, 3);
+	regulator_disable(ctx->power);
+
+	return 0;
+}
+
+static int sii9234_runtime_resume(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct sii9234_context *ctx = sd_to_context(sd);
+	struct i2c_client *client = ctx->client;
+	int ret;
+
+	dev_info(dev, "resume start\n");
+	regulator_enable(ctx->power);
+
+	ret = sii9234_reset(ctx);
+	if (ret)
+		goto fail;
+
+	/* enable tpi */
+	ret = sii9234_writeb_mask(client, 0x1e, 1, 0);
+	if (ret < 0)
+		goto fail;
+	ret = sii9234_set_internal(ctx);
+	if (ret < 0)
+		goto fail;
+
+	return 0;
+
+fail:
+	dev_err(dev, "failed to resume\n");
+	regulator_disable(ctx->power);
+
+	return ret;
+}
+
+static const struct dev_pm_ops sii9234_pm_ops = {
+	.runtime_suspend = sii9234_runtime_suspend,
+	.runtime_resume	 = sii9234_runtime_resume,
+};
+
+static int sii9234_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct sii9234_context *ctx = sd_to_context(sd);
+	int ret;
+
+	if (on)
+		ret = pm_runtime_get_sync(&ctx->client->dev);
+	else
+		ret = pm_runtime_put(&ctx->client->dev);
+	/* only values < 0 indicate errors */
+	return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int sii9234_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct sii9234_context *ctx = sd_to_context(sd);
+
+	/* (dis/en)able TDMS output */
+	sii9234_writeb_mask(ctx->client, 0x1a, enable ? 0 : ~0 , 1 << 4);
+	return 0;
+}
+
+static const struct v4l2_subdev_core_ops sii9234_core_ops = {
+	.s_power =  sii9234_s_power,
+};
+
+static const struct v4l2_subdev_video_ops sii9234_video_ops = {
+	.s_stream =  sii9234_s_stream,
+};
+
+static const struct v4l2_subdev_ops sii9234_ops = {
+	.core = &sii9234_core_ops,
+	.video = &sii9234_video_ops,
+};
+
+static int __devinit sii9234_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct sii9234_platform_data *pdata = dev->platform_data;
+	struct sii9234_context *ctx;
+	int ret;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		dev_err(dev, "out of memory\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+	ctx->client = client;
+
+	ctx->power = regulator_get(dev, "hdmi-en");
+	if (IS_ERR(ctx->power)) {
+		dev_err(dev, "failed to acquire regulator hdmi-en\n");
+		ret = PTR_ERR(ctx->power);
+		goto fail_ctx;
+	}
+
+	ctx->gpio_n_reset = pdata->gpio_n_reset;
+	ret = gpio_request(ctx->gpio_n_reset, "MHL_RST");
+	if (ret) {
+		dev_err(dev, "failed to acquire MHL_RST gpio\n");
+		goto fail_power;
+	}
+
+	v4l2_i2c_subdev_init(&ctx->sd, client, &sii9234_ops);
+
+	pm_runtime_enable(dev);
+
+	/* enable device */
+	ret = pm_runtime_get_sync(dev);
+	if (ret)
+		goto fail_pm;
+
+	/* verify chip version */
+	ret = sii9234_verify_version(client);
+	if (ret)
+		goto fail_pm_get;
+
+	/* stop processing */
+	pm_runtime_put(dev);
+
+	dev_info(dev, "probe successful\n");
+
+	return 0;
+
+fail_pm_get:
+	pm_runtime_put_sync(dev);
+
+fail_pm:
+	pm_runtime_disable(dev);
+	gpio_free(ctx->gpio_n_reset);
+
+fail_power:
+	regulator_put(ctx->power);
+
+fail_ctx:
+	kfree(ctx);
+
+fail:
+	dev_err(dev, "probe failed\n");
+
+	return ret;
+}
+
+static int __devexit sii9234_remove(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct sii9234_context *ctx = sd_to_context(sd);
+
+	pm_runtime_disable(dev);
+	gpio_free(ctx->gpio_n_reset);
+	regulator_put(ctx->power);
+	kfree(ctx);
+
+	dev_info(dev, "remove successful\n");
+
+	return 0;
+}
+
+
+static const struct i2c_device_id sii9234_id[] = {
+	{ "SII9234", 0 },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(i2c, sii9234_id);
+static struct i2c_driver sii9234_driver = {
+	.driver = {
+		.name	= "sii9234",
+		.owner	= THIS_MODULE,
+		.pm = &sii9234_pm_ops,
+	},
+	.probe		= sii9234_probe,
+	.remove		= __devexit_p(sii9234_remove),
+	.id_table = sii9234_id,
+};
+
+static int __init sii9234_init(void)
+{
+	return i2c_add_driver(&sii9234_driver);
+}
+module_init(sii9234_init);
+
+static void __exit sii9234_exit(void)
+{
+	i2c_del_driver(&sii9234_driver);
+}
+module_exit(sii9234_exit);
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index 99a2ac1..0caac50 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -539,15 +539,4 @@
 	.id_table	= saa6588_id,
 };
 
-static __init int init_saa6588(void)
-{
-	return i2c_add_driver(&saa6588_driver);
-}
-
-static __exit void exit_saa6588(void)
-{
-	i2c_del_driver(&saa6588_driver);
-}
-
-module_init(init_saa6588);
-module_exit(exit_saa6588);
+module_i2c_driver(saa6588_driver);
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 9966420..51cd4c8 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -491,15 +491,4 @@
 	.id_table	= saa7110_id,
 };
 
-static __init int init_saa7110(void)
-{
-	return i2c_add_driver(&saa7110_driver);
-}
-
-static __exit void exit_saa7110(void)
-{
-	i2c_del_driver(&saa7110_driver);
-}
-
-module_init(init_saa7110);
-module_exit(exit_saa7110);
+module_i2c_driver(saa7110_driver);
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 0ef5484..2107336 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -1724,15 +1724,4 @@
 	.id_table	= saa711x_id,
 };
 
-static __init int init_saa711x(void)
-{
-	return i2c_add_driver(&saa711x_driver);
-}
-
-static __exit void exit_saa711x(void)
-{
-	i2c_del_driver(&saa711x_driver);
-}
-
-module_init(init_saa711x);
-module_exit(exit_saa711x);
+module_i2c_driver(saa711x_driver);
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index ad96461..39c90b0 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -852,15 +852,4 @@
 	.id_table	= saa7127_id,
 };
 
-static __init int init_saa7127(void)
-{
-	return i2c_add_driver(&saa7127_driver);
-}
-
-static __exit void exit_saa7127(void)
-{
-	i2c_del_driver(&saa7127_driver);
-}
-
-module_init(init_saa7127);
-module_exit(exit_saa7127);
+module_i2c_driver(saa7127_driver);
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index a646ccf..da38993 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -10,7 +10,7 @@
 
 obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
 
-ccflags-y += -Idrivers/media/video
-ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -I$(srctree)/drivers/media/video
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index f9f29cc..f147b05 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -1001,18 +1001,7 @@
 	.id_table	= saa6752hs_id,
 };
 
-static __init int init_saa6752hs(void)
-{
-	return i2c_add_driver(&saa6752hs_driver);
-}
-
-static __exit void exit_saa6752hs(void)
-{
-	i2c_del_driver(&saa6752hs_driver);
-}
-
-module_init(init_saa6752hs);
-module_exit(exit_saa6752hs);
+module_i2c_driver(saa6752hs_driver);
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 065d0f6..53aae59 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -33,6 +33,7 @@
 #include "tea5767.h"
 #include "tda18271.h"
 #include "xc5000.h"
+#include "s5h1411.h"
 
 /* commly used strings */
 static char name_mute[]    = "mute";
@@ -5712,6 +5713,36 @@
 			.amux   = LINE1,
 		} },
 	},
+	[SAA7134_BOARD_KWORLD_PC150U] = {
+		.name           = "Kworld PC150-U",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 1 << 21,
+		.ts_type	= SAA7134_MPEG_TS_PARALLEL,
+		.inputs = { {
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		}, {
+			.name   = name_comp,
+			.vmux   = 3,
+			.amux   = LINE1,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		} },
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio	= 0x0000000,
+		},
+	},
 
 };
 
@@ -6306,6 +6337,12 @@
 		.driver_data  = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+		.subvendor    = 0x17de,
+		.subdevice    = 0xa134,
+		.driver_data  = SAA7134_BOARD_KWORLD_PC150U,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
 		.subvendor    = 0x1461,
 		.subdevice    = 0x7360,
@@ -7134,6 +7171,23 @@
 	return 0;
 }
 
+static int saa7134_kworld_pc150u_toggle_agc(struct saa7134_dev *dev,
+					    enum tda18271_mode mode)
+{
+	switch (mode) {
+	case TDA18271_ANALOG:
+		saa7134_set_gpio(dev, 18, 0);
+		break;
+	case TDA18271_DIGITAL:
+		saa7134_set_gpio(dev, 18, 1);
+		msleep(30);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
 					  int command, int arg)
 {
@@ -7150,6 +7204,9 @@
 		case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
 			ret = saa7134_kworld_sbtvd_toggle_agc(dev, arg);
 			break;
+		case SAA7134_BOARD_KWORLD_PC150U:
+			ret = saa7134_kworld_pc150u_toggle_agc(dev, arg);
+			break;
 		default:
 			break;
 		}
@@ -7171,6 +7228,7 @@
 	case SAA7134_BOARD_HAUPPAUGE_HVR1120:
 	case SAA7134_BOARD_AVERMEDIA_M733A:
 	case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+	case SAA7134_BOARD_KWORLD_PC150U:
 	case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
 		/* tda8290 + tda18271 */
 		ret = saa7134_tda8290_18271_callback(dev, command, arg);
@@ -7452,6 +7510,7 @@
 	case SAA7134_BOARD_BEHOLD_X7:
 	case SAA7134_BOARD_BEHOLD_H7:
 	case SAA7134_BOARD_BEHOLD_A7:
+	case SAA7134_BOARD_KWORLD_PC150U:
 		dev->has_remote = SAA7134_REMOTE_I2C;
 		break;
 	case SAA7134_BOARD_AVERMEDIA_A169_B:
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 089fa0f..aaa5c97 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -61,6 +61,7 @@
 #include "zl10036.h"
 #include "zl10039.h"
 #include "mt312.h"
+#include "s5h1411.h"
 
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
@@ -1158,6 +1159,33 @@
 	.output_opt = TDA18271_OUTPUT_LT_OFF,
 };
 
+static struct tda18271_std_map kworld_tda18271_std_map = {
+	.atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 3,
+		      .if_lvl = 6, .rfagc_top = 0x37 },
+	.qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 0,
+		      .if_lvl = 6, .rfagc_top = 0x37 },
+};
+
+static struct tda18271_config kworld_pc150u_tda18271_config = {
+	.std_map = &kworld_tda18271_std_map,
+	.gate    = TDA18271_GATE_ANALOG,
+	.output_opt = TDA18271_OUTPUT_LT_OFF,
+	.config  = 3,	/* Use tuner callback for AGC */
+	.rf_cal_on_startup = 1
+};
+
+static struct s5h1411_config kworld_s5h1411_config = {
+	.output_mode   = S5H1411_PARALLEL_OUTPUT,
+	.gpio          = S5H1411_GPIO_OFF,
+	.qam_if        = S5H1411_IF_4000,
+	.vsb_if        = S5H1411_IF_3250,
+	.inversion     = S5H1411_INVERSION_ON,
+	.status_mode   = S5H1411_DEMODLOCKING,
+	.mpeg_timing   =
+		S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+
 /* ==================================================================
  * Core code
  */
@@ -1438,6 +1466,22 @@
 				   &dev->i2c_adap, 0x61,
 				   TUNER_PHILIPS_TUV1236D);
 		break;
+	case SAA7134_BOARD_KWORLD_PC150U:
+		saa7134_set_gpio(dev, 18, 1); /* Switch to digital mode */
+		saa7134_tuner_callback(dev, 0,
+				       TDA18271_CALLBACK_CMD_AGC_ENABLE, 1);
+		fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+					       &kworld_s5h1411_config,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend != NULL) {
+			dvb_attach(tda829x_attach, fe0->dvb.frontend,
+				   &dev->i2c_adap, 0x4b,
+				   &tda829x_no_probe);
+			dvb_attach(tda18271_attach, fe0->dvb.frontend,
+				   0x60, &dev->i2c_adap,
+				   &kworld_pc150u_tda18271_config);
+		}
+		break;
 	case SAA7134_BOARD_FLYDVBS_LR300:
 		fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
 					       &dev->i2c_adap);
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 2d3f6d2..a176ec3 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -254,7 +254,9 @@
 			addr  = msgs[i].addr << 1;
 			if (msgs[i].flags & I2C_M_RD)
 				addr |= 1;
-			if (i > 0 && msgs[i].flags & I2C_M_RD && msgs[i].addr != 0x40) {
+			if (i > 0 && msgs[i].flags &
+			    I2C_M_RD && msgs[i].addr != 0x40 &&
+			    msgs[i].addr != 0x19) {
 				/* workaround for a saa7134 i2c bug
 				 * needed to talk to the mt352 demux
 				 * thanks to pinnacle for the hint */
@@ -279,6 +281,16 @@
 				d1printk("%02x", rc);
 				msgs[i].buf[byte] = rc;
 			}
+			/* discard mysterious extra byte when reading
+			   from Samsung S5H1411.  i2c bus gets error
+			   if we do not. */
+			if (0x19 == msgs[i].addr) {
+				d1printk(" ?");
+				rc = i2c_recv_byte(dev);
+				if (rc < 0)
+					goto err;
+				d1printk("%02x", rc);
+			}
 		} else {
 			/* write bytes */
 			d2printk("write bytes\n");
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 22ecd72..48d2878 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -210,6 +210,54 @@
 	return 1;
 }
 
+/* copied and modified from get_key_msi_tvanywhere_plus() */
+static int get_key_kworld_pc150u(struct IR_i2c *ir, u32 *ir_key,
+					u32 *ir_raw)
+{
+	unsigned char b;
+	unsigned int gpio;
+
+	/* <dev> is needed to access GPIO. Used by the saa_readl macro. */
+	struct saa7134_dev *dev = ir->c->adapter->algo_data;
+	if (dev == NULL) {
+		i2cdprintk("get_key_kworld_pc150u: "
+			   "ir->c->adapter->algo_data is NULL!\n");
+		return -EIO;
+	}
+
+	/* rising SAA7134_GPIO_GPRESCAN reads the status */
+
+	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+	gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+	/* GPIO&0x100 is pulsed low when a button is pressed. Don't do
+	   I2C receive if gpio&0x100 is not low. */
+
+	if (gpio & 0x100)
+		return 0;       /* No button press */
+
+	/* GPIO says there is a button press. Get it. */
+
+	if (1 != i2c_master_recv(ir->c, &b, 1)) {
+		i2cdprintk("read error\n");
+		return -EIO;
+	}
+
+	/* No button press */
+
+	if (b == 0xff)
+		return 0;
+
+	/* Button pressed */
+
+	dprintk("get_key_kworld_pc150u: Key = 0x%02X\n", b);
+	*ir_key = b;
+	*ir_raw = b;
+	return 1;
+}
+
 static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
 	unsigned char b;
@@ -901,6 +949,21 @@
 			msg_msi.addr, dev->i2c_adap.name,
 			(1 == rc) ? "yes" : "no");
 		break;
+	case SAA7134_BOARD_KWORLD_PC150U:
+		/* copied and modified from MSI TV@nywhere Plus */
+		dev->init_data.name = "Kworld PC150-U";
+		dev->init_data.get_key = get_key_kworld_pc150u;
+		dev->init_data.ir_codes = RC_MAP_KWORLD_PC150U;
+		info.addr = 0x30;
+		/* MSI TV@nywhere Plus controller doesn't seem to
+		   respond to probes unless we read something from
+		   an existing device. Weird...
+		   REVISIT: might no longer be needed */
+		rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1);
+		dprintk("probe 0x%02x @ %s: %s\n",
+			msg_msi.addr, dev->i2c_adap.name,
+			(1 == rc) ? "yes" : "no");
+		break;
 	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
 		dev->init_data.name = "HVR 1110";
 		dev->init_data.get_key = get_key_hvr1110;
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 42fba4f..f625060 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -126,8 +126,8 @@
 	unsigned                users;
 
 	u32			polling;
-        u32			last_gpio;
-        u32			mask_keycode, mask_keydown, mask_keyup;
+	u32			last_gpio;
+	u32			mask_keycode, mask_keydown, mask_keyup;
 
 	bool                    running;
 	bool			active;
@@ -331,6 +331,7 @@
 #define SAA7134_BOARD_BEHOLD_501            186
 #define SAA7134_BOARD_BEHOLD_503FM          187
 #define SAA7134_BOARD_SENSORAY811_911       188
+#define SAA7134_BOARD_KWORLD_PC150U         189
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
diff --git a/drivers/media/video/saa7164/Makefile b/drivers/media/video/saa7164/Makefile
index ecd5811..068443a 100644
--- a/drivers/media/video/saa7164/Makefile
+++ b/drivers/media/video/saa7164/Makefile
@@ -4,9 +4,9 @@
 
 obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o
 
-ccflags-y += -Idrivers/media/video
-ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -I$(srctree)/drivers/media/video
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
 
 ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/saa7164/saa7164-encoder.c b/drivers/media/video/saa7164/saa7164-encoder.c
index 2fd38a0..a9ed686 100644
--- a/drivers/media/video/saa7164/saa7164-encoder.c
+++ b/drivers/media/video/saa7164/saa7164-encoder.c
@@ -791,11 +791,6 @@
 	return 0;
 }
 
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	return 0;
-}
-
 static int fill_queryctrl(struct saa7164_encoder_params *params,
 	struct v4l2_queryctrl *c)
 {
@@ -1347,7 +1342,6 @@
 	.vidioc_g_ext_ctrls	 = vidioc_g_ext_ctrls,
 	.vidioc_s_ext_ctrls	 = vidioc_s_ext_ctrls,
 	.vidioc_try_ext_ctrls	 = vidioc_try_ext_ctrls,
-	.vidioc_log_status	 = vidioc_log_status,
 	.vidioc_queryctrl	 = vidioc_queryctrl,
 	.vidioc_g_chip_ident	 = saa7164_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
diff --git a/drivers/media/video/saa7164/saa7164-vbi.c b/drivers/media/video/saa7164/saa7164-vbi.c
index e2e0341..273cf80 100644
--- a/drivers/media/video/saa7164/saa7164-vbi.c
+++ b/drivers/media/video/saa7164/saa7164-vbi.c
@@ -730,11 +730,6 @@
 	return 0;
 }
 
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	return 0;
-}
-
 static int fill_queryctrl(struct saa7164_vbi_params *params,
 	struct v4l2_queryctrl *c)
 {
@@ -1256,7 +1251,6 @@
 	.vidioc_g_ext_ctrls	 = vidioc_g_ext_ctrls,
 	.vidioc_s_ext_ctrls	 = vidioc_s_ext_ctrls,
 	.vidioc_try_ext_ctrls	 = vidioc_try_ext_ctrls,
-	.vidioc_log_status	 = vidioc_log_status,
 	.vidioc_queryctrl	 = vidioc_queryctrl,
 #if 0
 	.vidioc_g_chip_ident	 = saa7164_g_chip_ident,
diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c
index b6172c2..1e84466 100644
--- a/drivers/media/video/saa717x.c
+++ b/drivers/media/video/saa717x.c
@@ -1375,15 +1375,4 @@
 	.id_table	= saa717x_id,
 };
 
-static __init int init_saa717x(void)
-{
-	return i2c_add_driver(&saa717x_driver);
-}
-
-static __exit void exit_saa717x(void)
-{
-	i2c_del_driver(&saa717x_driver);
-}
-
-module_init(init_saa717x);
-module_exit(exit_saa717x);
+module_i2c_driver(saa717x_driver);
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index 96f56c2..2c6b65c 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -374,15 +374,4 @@
 	.id_table	= saa7185_id,
 };
 
-static __init int init_saa7185(void)
-{
-	return i2c_add_driver(&saa7185_driver);
-}
-
-static __exit void exit_saa7185(void)
-{
-	i2c_del_driver(&saa7185_driver);
-}
-
-module_init(init_saa7185);
-module_exit(exit_saa7185);
+module_i2c_driver(saa7185_driver);
diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c
index 211fa25..d7d1670 100644
--- a/drivers/media/video/saa7191.c
+++ b/drivers/media/video/saa7191.c
@@ -656,15 +656,4 @@
 	.id_table	= saa7191_id,
 };
 
-static __init int init_saa7191(void)
-{
-	return i2c_add_driver(&saa7191_driver);
-}
-
-static __exit void exit_saa7191(void)
-{
-	i2c_del_driver(&saa7191_driver);
-}
-
-module_init(init_saa7191);
-module_exit(exit_saa7191);
+module_i2c_driver(saa7191_driver);
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index f854d85..424dfac 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -112,6 +112,10 @@
 
 	u32 cflcr;
 
+	/* static max sizes either from platform data or default */
+	int max_width;
+	int max_height;
+
 	enum v4l2_field field;
 	int sequence;
 
@@ -1081,7 +1085,15 @@
 		if (ret < 0)
 			return ret;
 
-		while ((mf.width > 2560 || mf.height > 1920) && shift < 4) {
+		/*
+		 * All currently existing CEU implementations support 2560x1920
+		 * or larger frames. If the sensor is proposing too big a frame,
+		 * don't bother with possibly supportred by the CEU larger
+		 * sizes, just try VGA multiples. If needed, this can be
+		 * adjusted in the future.
+		 */
+		while ((mf.width > pcdev->max_width ||
+			mf.height > pcdev->max_height) && shift < 4) {
 			/* Try 2560x1920, 1280x960, 640x480, 320x240 */
 			mf.width	= 2560 >> shift;
 			mf.height	= 1920 >> shift;
@@ -1377,6 +1389,8 @@
 static int client_s_fmt(struct soc_camera_device *icd,
 			struct v4l2_mbus_framefmt *mf, bool ceu_can_scale)
 {
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
 	struct sh_mobile_ceu_cam *cam = icd->host_priv;
 	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
 	struct device *dev = icd->parent;
@@ -1410,8 +1424,8 @@
 	if (ret < 0)
 		return ret;
 
-	max_width = min(cap.bounds.width, 2560);
-	max_height = min(cap.bounds.height, 1920);
+	max_width = min(cap.bounds.width, pcdev->max_width);
+	max_height = min(cap.bounds.height, pcdev->max_height);
 
 	/* Camera set a format, but geometry is not precise, try to improve */
 	tmp_w = mf->width;
@@ -1551,7 +1565,7 @@
 	if (ret < 0)
 		return ret;
 
-	if (mf.width > 2560 || mf.height > 1920)
+	if (mf.width > pcdev->max_width || mf.height > pcdev->max_height)
 		return -EINVAL;
 
 	/* 4. Calculate camera scales */
@@ -1834,6 +1848,8 @@
 static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
 				 struct v4l2_format *f)
 {
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
 	const struct soc_camera_format_xlate *xlate;
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -1854,8 +1870,8 @@
 	/* FIXME: calculate using depth and bus width */
 
 	/* CFSZR requires height and width to be 4-pixel aligned */
-	v4l_bound_align_image(&pix->width, 2, 2560, 2,
-			      &pix->height, 4, 1920, 2, 0);
+	v4l_bound_align_image(&pix->width, 2, pcdev->max_width, 2,
+			      &pix->height, 4, pcdev->max_height, 2, 0);
 
 	width = pix->width;
 	height = pix->height;
@@ -1890,8 +1906,8 @@
 			 * requested a bigger rectangle, it will not return a
 			 * smaller one.
 			 */
-			mf.width = 2560;
-			mf.height = 1920;
+			mf.width = pcdev->max_width;
+			mf.height = pcdev->max_height;
 			ret = v4l2_device_call_until_err(sd->v4l2_dev,
 					soc_camera_grp_id(icd), video,
 					try_mbus_fmt, &mf);
@@ -2082,6 +2098,9 @@
 		goto exit_kfree;
 	}
 
+	pcdev->max_width = pcdev->pdata->max_width ? : 2560;
+	pcdev->max_height = pcdev->pdata->max_height ? : 1920;
+
 	base = ioremap_nocache(res->start, resource_size(res));
 	if (!base) {
 		err = -ENXIO;
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index b827107..eb25756 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -526,10 +526,6 @@
 			},
 		};
 
-		ret = soc_camera_power_on(icd, icl);
-		if (ret < 0)
-			goto epower;
-
 		/* The camera could have been already on, try to reset */
 		if (icl->reset)
 			icl->reset(icd->pdev);
@@ -540,6 +536,10 @@
 			goto eiciadd;
 		}
 
+		ret = soc_camera_power_on(icd, icl);
+		if (ret < 0)
+			goto epower;
+
 		pm_runtime_enable(&icd->vdev->dev);
 		ret = pm_runtime_resume(&icd->vdev->dev);
 		if (ret < 0 && ret != -ENOSYS)
@@ -578,10 +578,10 @@
 esfmt:
 	pm_runtime_disable(&icd->vdev->dev);
 eresume:
-	ici->ops->remove(icd);
-eiciadd:
 	soc_camera_power_off(icd, icl);
 epower:
+	ici->ops->remove(icd);
+eiciadd:
 	icd->use_count--;
 	module_put(ici->ops->owner);
 
@@ -1050,6 +1050,14 @@
 	if (ret < 0)
 		goto ereg;
 
+	/* The camera could have been already on, try to reset */
+	if (icl->reset)
+		icl->reset(icd->pdev);
+
+	ret = ici->ops->add(icd);
+	if (ret < 0)
+		goto eadd;
+
 	/*
 	 * This will not yet call v4l2_subdev_core_ops::s_power(1), because the
 	 * subdevice has not been initialised yet. We'll have to call it once
@@ -1060,14 +1068,6 @@
 	if (ret < 0)
 		goto epower;
 
-	/* The camera could have been already on, try to reset */
-	if (icl->reset)
-		icl->reset(icd->pdev);
-
-	ret = ici->ops->add(icd);
-	if (ret < 0)
-		goto eadd;
-
 	/* Must have icd->vdev before registering the device */
 	ret = video_dev_create(icd);
 	if (ret < 0)
@@ -1165,10 +1165,10 @@
 	video_device_release(icd->vdev);
 	icd->vdev = NULL;
 evdc:
-	ici->ops->remove(icd);
-eadd:
 	soc_camera_power_off(icd, icl);
 epower:
+	ici->ops->remove(icd);
+eadd:
 	regulator_bulk_free(icl->num_regulators, icl->regulators);
 ereg:
 	v4l2_ctrl_handler_free(&icd->ctrl_handler);
diff --git a/drivers/media/video/sr030pc30.c b/drivers/media/video/sr030pc30.c
index d1b07ac..e9d95bd 100644
--- a/drivers/media/video/sr030pc30.c
+++ b/drivers/media/video/sr030pc30.c
@@ -864,18 +864,7 @@
 	.id_table	= sr030pc30_id,
 };
 
-static int __init sr030pc30_init(void)
-{
-	return i2c_add_driver(&sr030pc30_i2c_driver);
-}
-
-static void __exit sr030pc30_exit(void)
-{
-	i2c_del_driver(&sr030pc30_i2c_driver);
-}
-
-module_init(sr030pc30_init);
-module_exit(sr030pc30_exit);
+module_i2c_driver(sr030pc30_i2c_driver);
 
 MODULE_DESCRIPTION("Siliconfile SR030PC30 camera driver");
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
index bd21854..f7707e6 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -482,15 +482,4 @@
 	.id_table	= tda7432_id,
 };
 
-static __init int init_tda7432(void)
-{
-	return i2c_add_driver(&tda7432_driver);
-}
-
-static __exit void exit_tda7432(void)
-{
-	i2c_del_driver(&tda7432_driver);
-}
-
-module_init(init_tda7432);
-module_exit(exit_tda7432);
+module_i2c_driver(tda7432_driver);
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
index 22fa820..465d708 100644
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/video/tda9840.c
@@ -208,15 +208,4 @@
 	.id_table	= tda9840_id,
 };
 
-static __init int init_tda9840(void)
-{
-	return i2c_add_driver(&tda9840_driver);
-}
-
-static __exit void exit_tda9840(void)
-{
-	i2c_del_driver(&tda9840_driver);
-}
-
-module_init(init_tda9840);
-module_exit(exit_tda9840);
+module_i2c_driver(tda9840_driver);
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c
index 827425c..d1d6ea1 100644
--- a/drivers/media/video/tea6415c.c
+++ b/drivers/media/video/tea6415c.c
@@ -184,15 +184,4 @@
 	.id_table	= tea6415c_id,
 };
 
-static __init int init_tea6415c(void)
-{
-	return i2c_add_driver(&tea6415c_driver);
-}
-
-static __exit void exit_tea6415c(void)
-{
-	i2c_del_driver(&tea6415c_driver);
-}
-
-module_init(init_tea6415c);
-module_exit(exit_tea6415c);
+module_i2c_driver(tea6415c_driver);
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
index f350b6c..3875721 100644
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/video/tea6420.c
@@ -166,15 +166,4 @@
 	.id_table	= tea6420_id,
 };
 
-static __init int init_tea6420(void)
-{
-	return i2c_add_driver(&tea6420_driver);
-}
-
-static __exit void exit_tea6420(void)
-{
-	i2c_del_driver(&tea6420_driver);
-}
-
-module_init(init_tea6420);
-module_exit(exit_tea6420);
+module_i2c_driver(tea6420_driver);
diff --git a/drivers/media/video/ths7303.c b/drivers/media/video/ths7303.c
index 61b1dd1..e5c0eed 100644
--- a/drivers/media/video/ths7303.c
+++ b/drivers/media/video/ths7303.c
@@ -137,16 +137,4 @@
 	.id_table	= ths7303_id,
 };
 
-static int __init ths7303_init(void)
-{
-	return i2c_add_driver(&ths7303_driver);
-}
-
-static void __exit ths7303_exit(void)
-{
-	i2c_del_driver(&ths7303_driver);
-}
-
-module_init(ths7303_init);
-module_exit(ths7303_exit);
-
+module_i2c_driver(ths7303_driver);
diff --git a/drivers/media/video/timblogiw.c b/drivers/media/video/timblogiw.c
index 4ed1c7c2..02194c0 100644
--- a/drivers/media/video/timblogiw.c
+++ b/drivers/media/video/timblogiw.c
@@ -564,7 +564,7 @@
 
 	spin_unlock_irq(&fh->queue_lock);
 
-	desc = fh->chan->device->device_prep_slave_sg(fh->chan,
+	desc = dmaengine_prep_slave_sg(fh->chan,
 		buf->sg, sg_elems, DMA_DEV_TO_MEM,
 		DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
 	if (!desc) {
diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c
index 286ec7e..809a75a 100644
--- a/drivers/media/video/tlv320aic23b.c
+++ b/drivers/media/video/tlv320aic23b.c
@@ -227,15 +227,4 @@
 	.id_table	= tlv320aic23b_id,
 };
 
-static __init int init_tlv320aic23b(void)
-{
-	return i2c_add_driver(&tlv320aic23b_driver);
-}
-
-static __exit void exit_tlv320aic23b(void)
-{
-	i2c_del_driver(&tlv320aic23b_driver);
-}
-
-module_init(init_tlv320aic23b);
-module_exit(exit_tlv320aic23b);
+module_i2c_driver(tlv320aic23b_driver);
diff --git a/drivers/media/video/tm6000/tm6000-input.c b/drivers/media/video/tm6000/tm6000-input.c
index 7844607..859eb90 100644
--- a/drivers/media/video/tm6000/tm6000-input.c
+++ b/drivers/media/video/tm6000/tm6000-input.c
@@ -481,8 +481,6 @@
 
 	dprintk(2, "%s\n",__func__);
 
-	rc_unregister_device(ir->rc);
-
 	if (!ir->polling)
 		__tm6000_ir_int_stop(ir->rc);
 
@@ -492,6 +490,7 @@
 	tm6000_flash_led(dev, 0);
 	ir->pwled = 0;
 
+	rc_unregister_device(ir->rc);
 
 	kfree(ir);
 	dev->ir = NULL;
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 4059ea17..a5c6397 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -380,6 +380,21 @@
 		tune_now = 0;
 		break;
 	}
+	case TUNER_XC5000C:
+	{
+		struct xc5000_config xc5000c_cfg = {
+			.i2c_address = t->i2c->addr,
+			/* if_khz will be set at dvb_attach() */
+			.if_khz	  = 0,
+			.chip_id  = XC5000C,
+		};
+
+		if (!dvb_attach(xc5000_attach,
+				&t->fe, t->i2c->adapter, &xc5000c_cfg))
+			goto attach_failed;
+		tune_now = 0;
+		break;
+	}
 	case TUNER_NXP_TDA18271:
 	{
 		struct tda18271_config cfg = {
@@ -1314,18 +1329,7 @@
 	.id_table	= tuner_id,
 };
 
-static __init int init_tuner(void)
-{
-	return i2c_add_driver(&tuner_driver);
-}
-
-static __exit void exit_tuner(void)
-{
-	i2c_del_driver(&tuner_driver);
-}
-
-module_init(init_tuner);
-module_exit(exit_tuner);
+module_i2c_driver(tuner_driver);
 
 MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
 MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index f22dbef..c5b1a73 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -2078,15 +2078,4 @@
 	.id_table	= tvaudio_id,
 };
 
-static __init int init_tvaudio(void)
-{
-	return i2c_add_driver(&tvaudio_driver);
-}
-
-static __exit void exit_tvaudio(void)
-{
-	i2c_del_driver(&tvaudio_driver);
-}
-
-module_init(init_tvaudio);
-module_exit(exit_tvaudio);
+module_i2c_driver(tvaudio_driver);
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 6103d1b..3b6cf03 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -286,8 +286,16 @@
 	{ TUNER_ABSENT,                 "MaxLinear 301"},
 	{ TUNER_ABSENT,                 "Mirics MSi001"},
 	{ TUNER_ABSENT,                 "MaxLinear MxL241SF"},
-	{ TUNER_ABSENT,                 "Xceive XC5000C"},
+	{ TUNER_XC5000C,                "Xceive XC5000C"},
 	{ TUNER_ABSENT,                 "Montage M68TS2020"},
+	{ TUNER_ABSENT,                 "Siano SMS1530"},
+	{ TUNER_ABSENT,                 "Dibcom 7090"},
+	{ TUNER_ABSENT,                 "Xceive XC5200C"},
+	{ TUNER_ABSENT,                 "NXP 18273"},
+	{ TUNER_ABSENT,                 "Montage M88TS2022"},
+	/* 180-189 */
+	{ TUNER_ABSENT,                 "NXP 18272M"},
+	{ TUNER_ABSENT,                 "NXP 18272S"},
 };
 
 /* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are
diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c
index dd26cac..cd615c1 100644
--- a/drivers/media/video/tvp514x.c
+++ b/drivers/media/video/tvp514x.c
@@ -1163,15 +1163,4 @@
 	.id_table = tvp514x_id,
 };
 
-static int __init tvp514x_init(void)
-{
-	return i2c_add_driver(&tvp514x_driver);
-}
-
-static void __exit tvp514x_exit(void)
-{
-	i2c_del_driver(&tvp514x_driver);
-}
-
-module_init(tvp514x_init);
-module_exit(tvp514x_exit);
+module_i2c_driver(tvp514x_driver);
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index 6be9910..1326e11 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -17,6 +17,13 @@
 
 #include "tvp5150_reg.h"
 
+#define TVP5150_H_MAX		720
+#define TVP5150_V_MAX_525_60	480
+#define TVP5150_V_MAX_OTHERS	576
+#define TVP5150_MAX_CROP_LEFT	511
+#define TVP5150_MAX_CROP_TOP	127
+#define TVP5150_CROP_SHIFT	2
+
 MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver");
 MODULE_AUTHOR("Mauro Carvalho Chehab");
 MODULE_LICENSE("GPL");
@@ -29,6 +36,7 @@
 struct tvp5150 {
 	struct v4l2_subdev sd;
 	struct v4l2_ctrl_handler hdl;
+	struct v4l2_rect rect;
 
 	v4l2_std_id norm;	/* Current set standard */
 	u32 input;
@@ -732,6 +740,13 @@
 	if (decoder->norm == std)
 		return 0;
 
+	/* Change cropping height limits */
+	if (std & V4L2_STD_525_60)
+		decoder->rect.height = TVP5150_V_MAX_525_60;
+	else
+		decoder->rect.height = TVP5150_V_MAX_OTHERS;
+
+
 	return tvp5150_set_std(sd, std);
 }
 
@@ -828,11 +843,8 @@
 	else
 		std = decoder->norm;
 
-	f->width = 720;
-	if (std & V4L2_STD_525_60)
-		f->height = 480;
-	else
-		f->height = 576;
+	f->width = decoder->rect.width;
+	f->height = decoder->rect.height;
 
 	f->code = V4L2_MBUS_FMT_YUYV8_2X8;
 	f->field = V4L2_FIELD_SEQ_TB;
@@ -843,6 +855,99 @@
 	return 0;
 }
 
+static int tvp5150_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct v4l2_rect rect = a->c;
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	v4l2_std_id std;
+	int hmax;
+
+	v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n",
+		__func__, rect.left, rect.top, rect.width, rect.height);
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	/* tvp5150 has some special limits */
+	rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
+	rect.width = clamp(rect.width,
+			   TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
+			   TVP5150_H_MAX - rect.left);
+	rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
+
+	/* Calculate height based on current standard */
+	if (decoder->norm == V4L2_STD_ALL)
+		std = tvp5150_read_std(sd);
+	else
+		std = decoder->norm;
+
+	if (std & V4L2_STD_525_60)
+		hmax = TVP5150_V_MAX_525_60;
+	else
+		hmax = TVP5150_V_MAX_OTHERS;
+
+	rect.height = clamp(rect.height,
+			    hmax - TVP5150_MAX_CROP_TOP - rect.top,
+			    hmax - rect.top);
+
+	tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top);
+	tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP,
+		      rect.top + rect.height - hmax);
+	tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_MSB,
+		      rect.left >> TVP5150_CROP_SHIFT);
+	tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_LSB,
+		      rect.left | (1 << TVP5150_CROP_SHIFT));
+	tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_MSB,
+		      (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
+		      TVP5150_CROP_SHIFT);
+	tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_LSB,
+		      rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
+
+	decoder->rect = rect;
+
+	return 0;
+}
+
+static int tvp5150_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
+
+	a->c	= decoder->rect;
+	a->type	= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int tvp5150_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
+	v4l2_std_id std;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	a->bounds.width			= TVP5150_H_MAX;
+
+	/* Calculate height based on current standard */
+	if (decoder->norm == V4L2_STD_ALL)
+		std = tvp5150_read_std(sd);
+	else
+		std = decoder->norm;
+
+	if (std & V4L2_STD_525_60)
+		a->bounds.height = TVP5150_V_MAX_525_60;
+	else
+		a->bounds.height = TVP5150_V_MAX_OTHERS;
+
+	a->defrect			= a->bounds;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
 /****************************************************************************
 			I2C Command
  ****************************************************************************/
@@ -998,6 +1103,10 @@
 	.enum_mbus_fmt = tvp5150_enum_mbus_fmt,
 	.s_mbus_fmt = tvp5150_mbus_fmt,
 	.try_mbus_fmt = tvp5150_mbus_fmt,
+	.g_mbus_fmt = tvp5150_mbus_fmt,
+	.s_crop = tvp5150_s_crop,
+	.g_crop = tvp5150_g_crop,
+	.cropcap = tvp5150_cropcap,
 };
 
 static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
@@ -1083,6 +1192,15 @@
 	}
 	v4l2_ctrl_handler_setup(&core->hdl);
 
+	/* Default is no cropping */
+	core->rect.top = 0;
+	if (tvp5150_read_std(sd) & V4L2_STD_525_60)
+		core->rect.height = TVP5150_V_MAX_525_60;
+	else
+		core->rect.height = TVP5150_V_MAX_OTHERS;
+	core->rect.left = 0;
+	core->rect.width = TVP5150_H_MAX;
+
 	if (debug > 1)
 		tvp5150_log_status(sd);
 	return 0;
@@ -1121,15 +1239,4 @@
 	.id_table	= tvp5150_id,
 };
 
-static __init int init_tvp5150(void)
-{
-	return i2c_add_driver(&tvp5150_driver);
-}
-
-static __exit void exit_tvp5150(void)
-{
-	i2c_del_driver(&tvp5150_driver);
-}
-
-module_init(init_tvp5150);
-module_exit(exit_tvp5150);
+module_i2c_driver(tvp5150_driver);
diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c
index 236c559..d7676d8 100644
--- a/drivers/media/video/tvp7002.c
+++ b/drivers/media/video/tvp7002.c
@@ -1069,27 +1069,4 @@
 	.id_table = tvp7002_id,
 };
 
-/*
- * tvp7002_init - Initialize driver via I2C interface
- *
- * Register the TVP7002 driver.
- * Return 0 on success or error code on failure.
- */
-static int __init tvp7002_init(void)
-{
-	return i2c_add_driver(&tvp7002_driver);
-}
-
-/*
- * tvp7002_exit - Remove driver via I2C interface
- *
- * Unregister the TVP7002 driver.
- * Returns nothing.
- */
-static void __exit tvp7002_exit(void)
-{
-	i2c_del_driver(&tvp7002_driver);
-}
-
-module_init(tvp7002_init);
-module_exit(tvp7002_exit);
+module_i2c_driver(tvp7002_driver);
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
index a514fa6..8768efb 100644
--- a/drivers/media/video/tw9910.c
+++ b/drivers/media/video/tw9910.c
@@ -951,21 +951,7 @@
 	.id_table = tw9910_id,
 };
 
-/*
- * module function
- */
-static int __init tw9910_module_init(void)
-{
-	return i2c_add_driver(&tw9910_i2c_driver);
-}
-
-static void __exit tw9910_module_exit(void)
-{
-	i2c_del_driver(&tw9910_i2c_driver);
-}
-
-module_init(tw9910_module_init);
-module_exit(tw9910_module_exit);
+module_i2c_driver(tw9910_i2c_driver);
 
 MODULE_DESCRIPTION("SoC Camera driver for tw9910");
 MODULE_AUTHOR("Kuninori Morimoto");
diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c
index 1aab96a..1e74465 100644
--- a/drivers/media/video/upd64031a.c
+++ b/drivers/media/video/upd64031a.c
@@ -271,15 +271,4 @@
 	.id_table	= upd64031a_id,
 };
 
-static __init int init_upd64031a(void)
-{
-	return i2c_add_driver(&upd64031a_driver);
-}
-
-static __exit void exit_upd64031a(void)
-{
-	i2c_del_driver(&upd64031a_driver);
-}
-
-module_init(init_upd64031a);
-module_exit(exit_upd64031a);
+module_i2c_driver(upd64031a_driver);
diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c
index 65d065a..75d6acc 100644
--- a/drivers/media/video/upd64083.c
+++ b/drivers/media/video/upd64083.c
@@ -243,15 +243,4 @@
 	.id_table	= upd64083_id,
 };
 
-static __init int init_upd64083(void)
-{
-	return i2c_add_driver(&upd64083_driver);
-}
-
-static __exit void exit_upd64083(void)
-{
-	i2c_del_driver(&upd64083_driver);
-}
-
-module_init(init_upd64083);
-module_exit(exit_upd64083);
+module_i2c_driver(upd64083_driver);
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index a240d43..1d13172 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -23,6 +23,7 @@
  * codec can't handle MJPEG data.
  */
 
+#include <linux/atomic.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/module.h>
@@ -32,7 +33,6 @@
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
 #include <linux/version.h>
-#include <asm/atomic.h>
 #include <asm/unaligned.h>
 
 #include <media/v4l2-common.h>
@@ -2139,6 +2139,15 @@
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Dell XPS m1530 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x05a9,
+	  .idProduct		= 0x2640,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info 		= UVC_QUIRK_PROBE_DEF },
 	/* Apple Built-In iSight */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index 518f77d..8f54e24 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -126,7 +126,7 @@
 		    int drop_corrupted)
 {
 	queue->queue.type = type;
-	queue->queue.io_modes = VB2_MMAP;
+	queue->queue.io_modes = VB2_MMAP | VB2_USERPTR;
 	queue->queue.drv_priv = queue;
 	queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
 	queue->queue.ops = &uvc_queue_qops;
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 2ae4f88..ff2cddd 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -11,6 +11,7 @@
  *
  */
 
+#include <linux/compat.h>
 #include <linux/kernel.h>
 #include <linux/version.h>
 #include <linux/list.h>
@@ -1012,7 +1013,7 @@
 
 	default:
 		uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd);
-		return -EINVAL;
+		return -ENOTTY;
 	}
 
 	return ret;
@@ -1030,6 +1031,207 @@
 	return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl);
 }
 
+#ifdef CONFIG_COMPAT
+struct uvc_xu_control_mapping32 {
+	__u32 id;
+	__u8 name[32];
+	__u8 entity[16];
+	__u8 selector;
+
+	__u8 size;
+	__u8 offset;
+	__u32 v4l2_type;
+	__u32 data_type;
+
+	compat_caddr_t menu_info;
+	__u32 menu_count;
+
+	__u32 reserved[4];
+};
+
+static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp,
+			const struct uvc_xu_control_mapping32 __user *up)
+{
+	struct uvc_menu_info __user *umenus;
+	struct uvc_menu_info __user *kmenus;
+	compat_caddr_t p;
+
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    __copy_from_user(kp, up, offsetof(typeof(*up), menu_info)) ||
+	    __get_user(kp->menu_count, &up->menu_count))
+		return -EFAULT;
+
+	memset(kp->reserved, 0, sizeof(kp->reserved));
+
+	if (kp->menu_count == 0) {
+		kp->menu_info = NULL;
+		return 0;
+	}
+
+	if (__get_user(p, &up->menu_info))
+		return -EFAULT;
+	umenus = compat_ptr(p);
+	if (!access_ok(VERIFY_READ, umenus, kp->menu_count * sizeof(*umenus)))
+		return -EFAULT;
+
+	kmenus = compat_alloc_user_space(kp->menu_count * sizeof(*kmenus));
+	if (kmenus == NULL)
+		return -EFAULT;
+	kp->menu_info = kmenus;
+
+	if (copy_in_user(kmenus, umenus, kp->menu_count * sizeof(*umenus)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp,
+			struct uvc_xu_control_mapping32 __user *up)
+{
+	struct uvc_menu_info __user *umenus;
+	struct uvc_menu_info __user *kmenus = kp->menu_info;
+	compat_caddr_t p;
+
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    __copy_to_user(up, kp, offsetof(typeof(*up), menu_info)) ||
+	    __put_user(kp->menu_count, &up->menu_count))
+		return -EFAULT;
+
+	__clear_user(up->reserved, sizeof(up->reserved));
+
+	if (kp->menu_count == 0)
+		return 0;
+
+	if (get_user(p, &up->menu_info))
+		return -EFAULT;
+	umenus = compat_ptr(p);
+	if (!access_ok(VERIFY_WRITE, umenus, kp->menu_count * sizeof(*umenus)))
+		return -EFAULT;
+
+	if (copy_in_user(umenus, kmenus, kp->menu_count * sizeof(*umenus)))
+		return -EFAULT;
+
+	return 0;
+}
+
+struct uvc_xu_control_query32 {
+	__u8 unit;
+	__u8 selector;
+	__u8 query;
+	__u16 size;
+	compat_caddr_t data;
+};
+
+static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp,
+			const struct uvc_xu_control_query32 __user *up)
+{
+	u8 __user *udata;
+	u8 __user *kdata;
+	compat_caddr_t p;
+
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+	    __copy_from_user(kp, up, offsetof(typeof(*up), data)))
+		return -EFAULT;
+
+	if (kp->size == 0) {
+		kp->data = NULL;
+		return 0;
+	}
+
+	if (__get_user(p, &up->data))
+		return -EFAULT;
+	udata = compat_ptr(p);
+	if (!access_ok(VERIFY_READ, udata, kp->size))
+		return -EFAULT;
+
+	kdata = compat_alloc_user_space(kp->size);
+	if (kdata == NULL)
+		return -EFAULT;
+	kp->data = kdata;
+
+	if (copy_in_user(kdata, udata, kp->size))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp,
+			struct uvc_xu_control_query32 __user *up)
+{
+	u8 __user *udata;
+	u8 __user *kdata = kp->data;
+	compat_caddr_t p;
+
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+	    __copy_to_user(up, kp, offsetof(typeof(*up), data)))
+		return -EFAULT;
+
+	if (kp->size == 0)
+		return 0;
+
+	if (get_user(p, &up->data))
+		return -EFAULT;
+	udata = compat_ptr(p);
+	if (!access_ok(VERIFY_READ, udata, kp->size))
+		return -EFAULT;
+
+	if (copy_in_user(udata, kdata, kp->size))
+		return -EFAULT;
+
+	return 0;
+}
+
+#define UVCIOC_CTRL_MAP32	_IOWR('u', 0x20, struct uvc_xu_control_mapping32)
+#define UVCIOC_CTRL_QUERY32	_IOWR('u', 0x21, struct uvc_xu_control_query32)
+
+static long uvc_v4l2_compat_ioctl32(struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	union {
+		struct uvc_xu_control_mapping xmap;
+		struct uvc_xu_control_query xqry;
+	} karg;
+	void __user *up = compat_ptr(arg);
+	mm_segment_t old_fs;
+	long ret;
+
+	switch (cmd) {
+	case UVCIOC_CTRL_MAP32:
+		cmd = UVCIOC_CTRL_MAP;
+		ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up);
+		break;
+
+	case UVCIOC_CTRL_QUERY32:
+		cmd = UVCIOC_CTRL_QUERY;
+		ret = uvc_v4l2_get_xu_query(&karg.xqry, up);
+		break;
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = uvc_v4l2_ioctl(file, cmd, (unsigned long)&karg);
+	set_fs(old_fs);
+
+	if (ret < 0)
+		return ret;
+
+	switch (cmd) {
+	case UVCIOC_CTRL_MAP:
+		ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up);
+		break;
+
+	case UVCIOC_CTRL_QUERY:
+		ret = uvc_v4l2_put_xu_query(&karg.xqry, up);
+		break;
+	}
+
+	return ret;
+}
+#endif
+
 static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
 		    size_t count, loff_t *ppos)
 {
@@ -1076,6 +1278,9 @@
 	.open		= uvc_v4l2_open,
 	.release	= uvc_v4l2_release,
 	.unlocked_ioctl	= uvc_v4l2_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32	= uvc_v4l2_compat_ioctl32,
+#endif
 	.read		= uvc_v4l2_read,
 	.mmap		= uvc_v4l2_mmap,
 	.poll		= uvc_v4l2_poll,
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 5c6100f..1baec83 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -55,7 +55,6 @@
 #include <linux/spi/spi.h>
 #endif
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
 #include <asm/div64.h>
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index af4419e..2829d25 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -14,12 +14,11 @@
  */
 
 #include <linux/compat.h>
-#include <linux/videodev2.h>
 #include <linux/module.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
 #include <media/v4l2-ioctl.h>
 
-#ifdef CONFIG_COMPAT
-
 static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	long ret = -ENOIOCTLCMD;
@@ -937,6 +936,7 @@
 
 long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
 {
+	struct video_device *vdev = video_devdata(file);
 	long ret = -ENOIOCTLCMD;
 
 	if (!file->f_op->unlocked_ioctl)
@@ -1005,6 +1005,8 @@
 	case VIDIOC_G_ENC_INDEX:
 	case VIDIOC_ENCODER_CMD:
 	case VIDIOC_TRY_ENCODER_CMD:
+	case VIDIOC_DECODER_CMD:
+	case VIDIOC_TRY_DECODER_CMD:
 	case VIDIOC_DBG_S_REGISTER:
 	case VIDIOC_DBG_G_REGISTER:
 	case VIDIOC_DBG_G_CHIP_IDENT:
@@ -1025,14 +1027,16 @@
 		break;
 
 	default:
-		printk(KERN_WARNING "compat_ioctl32: "
-			"unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
-			_IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
+		if (vdev->fops->compat_ioctl32)
+			ret = vdev->fops->compat_ioctl32(file, cmd, arg);
+
+		if (ret == -ENOIOCTLCMD)
+			printk(KERN_WARNING "compat_ioctl32: "
+				"unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
+				_IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd),
+				cmd);
 		break;
 	}
 	return ret;
 }
 EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);
-#endif
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index cccd42b..18015c0 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -175,6 +175,15 @@
 		"16-bit CRC",
 		NULL
 	};
+	static const char * const mpeg_audio_dec_playback[] = {
+		"Auto",
+		"Stereo",
+		"Left",
+		"Right",
+		"Mono",
+		"Swapped Stereo",
+		NULL
+	};
 	static const char * const mpeg_video_encoding[] = {
 		"MPEG-1",
 		"MPEG-2",
@@ -236,8 +245,8 @@
 	};
 	static const char * const tune_preemphasis[] = {
 		"No Preemphasis",
-		"50 useconds",
-		"75 useconds",
+		"50 Microseconds",
+		"75 Microseconds",
 		NULL,
 	};
 	static const char * const header_mode[] = {
@@ -334,7 +343,7 @@
 	};
 	static const char * const mpeg4_profile[] = {
 		"Simple",
-		"Adcanved Simple",
+		"Advanced Simple",
 		"Core",
 		"Simple Scalable",
 		"Advanced Coding Efficency",
@@ -353,6 +362,16 @@
 		NULL,
 	};
 
+	static const char * const jpeg_chroma_subsampling[] = {
+		"4:4:4",
+		"4:2:2",
+		"4:2:0",
+		"4:1:1",
+		"4:1:0",
+		"Gray",
+		NULL,
+	};
+
 	switch (id) {
 	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
 		return mpeg_audio_sampling_freq;
@@ -374,6 +393,9 @@
 		return mpeg_audio_emphasis;
 	case V4L2_CID_MPEG_AUDIO_CRC:
 		return mpeg_audio_crc;
+	case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
+	case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK:
+		return mpeg_audio_dec_playback;
 	case V4L2_CID_MPEG_VIDEO_ENCODING:
 		return mpeg_video_encoding;
 	case V4L2_CID_MPEG_VIDEO_ASPECT:
@@ -414,6 +436,9 @@
 		return mpeg_mpeg4_level;
 	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
 		return mpeg4_profile;
+	case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+		return jpeg_chroma_subsampling;
+
 	default:
 		return NULL;
 	}
@@ -492,6 +517,8 @@
 	case V4L2_CID_MPEG_AUDIO_MUTE:		return "Audio Mute";
 	case V4L2_CID_MPEG_AUDIO_AAC_BITRATE:	return "Audio AAC Bitrate";
 	case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:	return "Audio AC-3 Bitrate";
+	case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:	return "Audio Playback";
+	case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: return "Audio Multilingual Playback";
 	case V4L2_CID_MPEG_VIDEO_ENCODING:	return "Video Encoding";
 	case V4L2_CID_MPEG_VIDEO_ASPECT:	return "Video Aspect";
 	case V4L2_CID_MPEG_VIDEO_B_FRAMES:	return "Video B Frames";
@@ -546,6 +573,8 @@
 	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:		return "Number of MBs in a Slice";
 	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:		return "Slice Partitioning Method";
 	case V4L2_CID_MPEG_VIDEO_VBV_SIZE:			return "VBV Buffer Size";
+	case V4L2_CID_MPEG_VIDEO_DEC_PTS:			return "Video Decoder PTS";
+	case V4L2_CID_MPEG_VIDEO_DEC_FRAME:			return "Video Decoder Frame Count";
 
 	/* CAMERA controls */
 	/* Keep the order of the 'case's the same as in videodev2.h! */
@@ -607,6 +636,14 @@
 	case V4L2_CID_FLASH_CHARGE:		return "Charge";
 	case V4L2_CID_FLASH_READY:		return "Ready to Strobe";
 
+	/* JPEG encoder controls */
+	/* Keep the order of the 'case's the same as in videodev2.h! */
+	case V4L2_CID_JPEG_CLASS:		return "JPEG Compression Controls";
+	case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:	return "Chroma Subsampling";
+	case V4L2_CID_JPEG_RESTART_INTERVAL:	return "Restart Interval";
+	case V4L2_CID_JPEG_COMPRESSION_QUALITY:	return "Compression Quality";
+	case V4L2_CID_JPEG_ACTIVE_MARKER:	return "Active Markers";
+
 	default:
 		return NULL;
 	}
@@ -674,6 +711,8 @@
 	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
 	case V4L2_CID_MPEG_AUDIO_EMPHASIS:
 	case V4L2_CID_MPEG_AUDIO_CRC:
+	case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
+	case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK:
 	case V4L2_CID_MPEG_VIDEO_ENCODING:
 	case V4L2_CID_MPEG_VIDEO_ASPECT:
 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
@@ -693,6 +732,7 @@
 	case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
 	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
 	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+	case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
 		*type = V4L2_CTRL_TYPE_MENU;
 		break;
 	case V4L2_CID_RDS_TX_PS_NAME:
@@ -704,6 +744,7 @@
 	case V4L2_CID_MPEG_CLASS:
 	case V4L2_CID_FM_TX_CLASS:
 	case V4L2_CID_FLASH_CLASS:
+	case V4L2_CID_JPEG_CLASS:
 		*type = V4L2_CTRL_TYPE_CTRL_CLASS;
 		/* You can neither read not write these */
 		*flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
@@ -717,6 +758,7 @@
 		*max = 0xFFFFFF;
 		break;
 	case V4L2_CID_FLASH_FAULT:
+	case V4L2_CID_JPEG_ACTIVE_MARKER:
 		*type = V4L2_CTRL_TYPE_BITMASK;
 		break;
 	case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
@@ -724,6 +766,11 @@
 		*type = V4L2_CTRL_TYPE_INTEGER;
 		*flags |= V4L2_CTRL_FLAG_READ_ONLY;
 		break;
+	case V4L2_CID_MPEG_VIDEO_DEC_FRAME:
+	case V4L2_CID_MPEG_VIDEO_DEC_PTS:
+		*type = V4L2_CTRL_TYPE_INTEGER64;
+		*flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE;
+		break;
 	default:
 		*type = V4L2_CTRL_TYPE_INTEGER;
 		break;
@@ -1470,7 +1517,7 @@
 int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
 			  struct v4l2_ctrl_handler *add)
 {
-	struct v4l2_ctrl *ctrl;
+	struct v4l2_ctrl_ref *ref;
 	int ret = 0;
 
 	/* Do nothing if either handler is NULL or if they are the same */
@@ -1479,7 +1526,9 @@
 	if (hdl->error)
 		return hdl->error;
 	mutex_lock(&add->lock);
-	list_for_each_entry(ctrl, &add->ctrls, node) {
+	list_for_each_entry(ref, &add->ctrl_refs, node) {
+		struct v4l2_ctrl *ctrl = ref->ctrl;
+
 		/* Skip handler-private controls. */
 		if (ctrl->is_private)
 			continue;
@@ -2359,3 +2408,35 @@
 	v4l2_ctrl_unlock(ctrl);
 }
 EXPORT_SYMBOL(v4l2_ctrl_del_event);
+
+int v4l2_ctrl_log_status(struct file *file, void *fh)
+{
+	struct video_device *vfd = video_devdata(file);
+	struct v4l2_fh *vfh = file->private_data;
+
+	if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev)
+		v4l2_ctrl_handler_log_status(vfh->ctrl_handler,
+			vfd->v4l2_dev->name);
+	return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_log_status);
+
+int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
+				struct v4l2_event_subscription *sub)
+{
+	if (sub->type == V4L2_EVENT_CTRL)
+		return v4l2_event_subscribe(fh, sub, 0);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(v4l2_ctrl_subscribe_event);
+
+unsigned int v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct v4l2_fh *fh = file->private_data;
+
+	if (v4l2_event_pending(fh))
+		return POLLPRI;
+	poll_wait(file, &fh->wait, wait);
+	return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_poll);
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 96e9615..70bec54 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -26,7 +26,6 @@
 #include <linux/kmod.h>
 #include <linux/slab.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
@@ -788,7 +787,7 @@
 	unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
 }
 
-module_init(videodev_init)
+subsys_initcall(videodev_init);
 module_exit(videodev_exit)
 
 MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 3f62385..5b2ec1f 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -260,6 +260,8 @@
 	[_IOC_NR(VIDIOC_ENCODER_CMD)] 	   = "VIDIOC_ENCODER_CMD",
 	[_IOC_NR(VIDIOC_TRY_ENCODER_CMD)]  = "VIDIOC_TRY_ENCODER_CMD",
 
+	[_IOC_NR(VIDIOC_DECODER_CMD)]	   = "VIDIOC_DECODER_CMD",
+	[_IOC_NR(VIDIOC_TRY_DECODER_CMD)]  = "VIDIOC_TRY_DECODER_CMD",
 	[_IOC_NR(VIDIOC_DBG_S_REGISTER)]   = "VIDIOC_DBG_S_REGISTER",
 	[_IOC_NR(VIDIOC_DBG_G_REGISTER)]   = "VIDIOC_DBG_G_REGISTER",
 
@@ -540,10 +542,12 @@
 		if (!ret)
 			dbgarg(cmd, "driver=%s, card=%s, bus=%s, "
 					"version=0x%08x, "
-					"capabilities=0x%08x\n",
+					"capabilities=0x%08x, "
+					"device_caps=0x%08x\n",
 					cap->driver, cap->card, cap->bus_info,
 					cap->version,
-					cap->capabilities);
+					cap->capabilities,
+					cap->device_caps);
 		break;
 	}
 
@@ -1762,6 +1766,32 @@
 			dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
 		break;
 	}
+	case VIDIOC_DECODER_CMD:
+	{
+		struct v4l2_decoder_cmd *p = arg;
+
+		if (!ops->vidioc_decoder_cmd)
+			break;
+		if (ret_prio) {
+			ret = ret_prio;
+			break;
+		}
+		ret = ops->vidioc_decoder_cmd(file, fh, p);
+		if (!ret)
+			dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
+		break;
+	}
+	case VIDIOC_TRY_DECODER_CMD:
+	{
+		struct v4l2_decoder_cmd *p = arg;
+
+		if (!ops->vidioc_try_decoder_cmd)
+			break;
+		ret = ops->vidioc_try_decoder_cmd(file, fh, p);
+		if (!ret)
+			dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
+		break;
+	}
 	case VIDIOC_G_PARM:
 	{
 		struct v4l2_streamparm *p = arg;
@@ -1909,7 +1939,13 @@
 	{
 		if (!ops->vidioc_log_status)
 			break;
+		if (vfd->v4l2_dev)
+			pr_info("%s: =================  START STATUS  =================\n",
+				vfd->v4l2_dev->name);
 		ret = ops->vidioc_log_status(file, fh);
+		if (vfd->v4l2_dev)
+			pr_info("%s: ==================  END STATUS  ==================\n",
+				vfd->v4l2_dev->name);
 		break;
 	}
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -2419,7 +2455,7 @@
 	/* Handles IOCTL */
 	err = func(file, cmd, parg);
 	if (err == -ENOIOCTLCMD)
-		err = -EINVAL;
+		err = -ENOTTY;
 
 	if (has_array_args) {
 		*kernel_ptr = user_ptr;
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 41d118e..6fe88e9 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -194,8 +194,16 @@
 	}
 #endif
 
-	case VIDIOC_LOG_STATUS:
-		return v4l2_subdev_call(sd, core, log_status);
+	case VIDIOC_LOG_STATUS: {
+		int ret;
+
+		pr_info("%s: =================  START STATUS  =================\n",
+			sd->name);
+		ret = v4l2_subdev_call(sd, core, log_status);
+		pr_info("%s: ==================  END STATUS  ==================\n",
+			sd->name);
+		return ret;
+	}
 
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
 	case VIDIOC_SUBDEV_G_FMT: {
diff --git a/drivers/media/video/videobuf2-vmalloc.c b/drivers/media/video/videobuf2-vmalloc.c
index 4e789a1..6b5ca6c 100644
--- a/drivers/media/video/videobuf2-vmalloc.c
+++ b/drivers/media/video/videobuf2-vmalloc.c
@@ -10,6 +10,7 @@
  * the Free Software Foundation.
  */
 
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
@@ -22,6 +23,7 @@
 struct vb2_vmalloc_buf {
 	void				*vaddr;
 	struct page			**pages;
+	struct vm_area_struct		*vma;
 	int				write;
 	unsigned long			size;
 	unsigned int			n_pages;
@@ -71,6 +73,8 @@
 	struct vb2_vmalloc_buf *buf;
 	unsigned long first, last;
 	int n_pages, offset;
+	struct vm_area_struct *vma;
+	dma_addr_t physp;
 
 	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
 	if (!buf)
@@ -80,23 +84,37 @@
 	offset = vaddr & ~PAGE_MASK;
 	buf->size = size;
 
-	first = vaddr >> PAGE_SHIFT;
-	last  = (vaddr + size - 1) >> PAGE_SHIFT;
-	buf->n_pages = last - first + 1;
-	buf->pages = kzalloc(buf->n_pages * sizeof(struct page *), GFP_KERNEL);
-	if (!buf->pages)
-		goto fail_pages_array_alloc;
 
-	/* current->mm->mmap_sem is taken by videobuf2 core */
-	n_pages = get_user_pages(current, current->mm, vaddr & PAGE_MASK,
-				 buf->n_pages, write, 1, /* force */
-				 buf->pages, NULL);
-	if (n_pages != buf->n_pages)
-		goto fail_get_user_pages;
+	vma = find_vma(current->mm, vaddr);
+	if (vma && (vma->vm_flags & VM_PFNMAP) && (vma->vm_pgoff)) {
+		if (vb2_get_contig_userptr(vaddr, size, &vma, &physp))
+			goto fail_pages_array_alloc;
+		buf->vma = vma;
+		buf->vaddr = ioremap_nocache(physp, size);
+		if (!buf->vaddr)
+			goto fail_pages_array_alloc;
+	} else {
+		first = vaddr >> PAGE_SHIFT;
+		last  = (vaddr + size - 1) >> PAGE_SHIFT;
+		buf->n_pages = last - first + 1;
+		buf->pages = kzalloc(buf->n_pages * sizeof(struct page *),
+				     GFP_KERNEL);
+		if (!buf->pages)
+			goto fail_pages_array_alloc;
 
-	buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1, PAGE_KERNEL);
-	if (!buf->vaddr)
-		goto fail_get_user_pages;
+		/* current->mm->mmap_sem is taken by videobuf2 core */
+		n_pages = get_user_pages(current, current->mm,
+					 vaddr & PAGE_MASK, buf->n_pages,
+					 write, 1, /* force */
+					 buf->pages, NULL);
+		if (n_pages != buf->n_pages)
+			goto fail_get_user_pages;
+
+		buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1,
+					PAGE_KERNEL);
+		if (!buf->vaddr)
+			goto fail_get_user_pages;
+	}
 
 	buf->vaddr += offset;
 	return buf;
@@ -120,14 +138,20 @@
 	unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK;
 	unsigned int i;
 
-	if (vaddr)
-		vm_unmap_ram((void *)vaddr, buf->n_pages);
-	for (i = 0; i < buf->n_pages; ++i) {
-		if (buf->write)
-			set_page_dirty_lock(buf->pages[i]);
-		put_page(buf->pages[i]);
+	if (buf->pages) {
+		if (vaddr)
+			vm_unmap_ram((void *)vaddr, buf->n_pages);
+		for (i = 0; i < buf->n_pages; ++i) {
+			if (buf->write)
+				set_page_dirty_lock(buf->pages[i]);
+			put_page(buf->pages[i]);
+		}
+		kfree(buf->pages);
+	} else {
+		if (buf->vma)
+			vb2_put_vma(buf->vma);
+		iounmap(buf->vaddr);
 	}
-	kfree(buf->pages);
 	kfree(buf);
 }
 
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 7d754fb..5e8b071 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -819,8 +819,9 @@
 	strcpy(cap->driver, "vivi");
 	strcpy(cap->card, "vivi");
 	strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
-	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
+	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
 			    V4L2_CAP_READWRITE;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
@@ -958,14 +959,6 @@
 	return vb2_streamoff(&dev->vb_vidq, i);
 }
 
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	struct vivi_dev *dev = video_drvdata(file);
-
-	v4l2_ctrl_handler_log_status(&dev->ctrl_handler, dev->v4l2_dev.name);
-	return 0;
-}
-
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
 {
 	return 0;
@@ -1008,17 +1001,6 @@
 	return 0;
 }
 
-static int vidioc_subscribe_event(struct v4l2_fh *fh,
-				struct v4l2_event_subscription *sub)
-{
-	switch (sub->type) {
-	case V4L2_EVENT_CTRL:
-		return v4l2_event_subscribe(fh, sub, 0);
-	default:
-		return -EINVAL;
-	}
-}
-
 /* --- controls ---------------------------------------------- */
 
 static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
@@ -1209,8 +1191,8 @@
 	.vidioc_s_input       = vidioc_s_input,
 	.vidioc_streamon      = vidioc_streamon,
 	.vidioc_streamoff     = vidioc_streamoff,
-	.vidioc_log_status    = vidioc_log_status,
-	.vidioc_subscribe_event = vidioc_subscribe_event,
+	.vidioc_log_status    = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c
index c15efb6..7cfbc9d 100644
--- a/drivers/media/video/vp27smpx.c
+++ b/drivers/media/video/vp27smpx.c
@@ -208,15 +208,4 @@
 	.id_table	= vp27smpx_id,
 };
 
-static __init int init_vp27smpx(void)
-{
-	return i2c_add_driver(&vp27smpx_driver);
-}
-
-static __exit void exit_vp27smpx(void)
-{
-	i2c_del_driver(&vp27smpx_driver);
-}
-
-module_init(init_vp27smpx);
-module_exit(exit_vp27smpx);
+module_i2c_driver(vp27smpx_driver);
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index e5cad6f..2f67b4c 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -588,15 +588,4 @@
 	.id_table	= vpx3220_id,
 };
 
-static __init int init_vpx3220(void)
-{
-	return i2c_add_driver(&vpx3220_driver);
-}
-
-static __exit void exit_vpx3220(void)
-{
-	i2c_del_driver(&vpx3220_driver);
-}
-
-module_init(init_vpx3220);
-module_exit(exit_vpx3220);
+module_i2c_driver(vpx3220_driver);
diff --git a/drivers/media/video/vs6624.c b/drivers/media/video/vs6624.c
new file mode 100644
index 0000000..42ae9dc
--- /dev/null
+++ b/drivers/media/video/vs6624.c
@@ -0,0 +1,928 @@
+/*
+ * vs6624.c ST VS6624 CMOS image sensor driver
+ *
+ * Copyright (c) 2011 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.
+ *
+ * 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/delay.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+
+#include "vs6624_regs.h"
+
+#define VGA_WIDTH       640
+#define VGA_HEIGHT      480
+#define QVGA_WIDTH      320
+#define QVGA_HEIGHT     240
+#define QQVGA_WIDTH     160
+#define QQVGA_HEIGHT    120
+#define CIF_WIDTH       352
+#define CIF_HEIGHT      288
+#define QCIF_WIDTH      176
+#define QCIF_HEIGHT     144
+#define QQCIF_WIDTH     88
+#define QQCIF_HEIGHT    72
+
+#define MAX_FRAME_RATE  30
+
+struct vs6624 {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	struct v4l2_fract frame_rate;
+	struct v4l2_mbus_framefmt fmt;
+	unsigned ce_pin;
+};
+
+static const struct vs6624_format {
+	enum v4l2_mbus_pixelcode mbus_code;
+	enum v4l2_colorspace colorspace;
+} vs6624_formats[] = {
+	{
+		.mbus_code      = V4L2_MBUS_FMT_UYVY8_2X8,
+		.colorspace     = V4L2_COLORSPACE_JPEG,
+	},
+	{
+		.mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
+		.colorspace     = V4L2_COLORSPACE_JPEG,
+	},
+	{
+		.mbus_code      = V4L2_MBUS_FMT_RGB565_2X8_LE,
+		.colorspace     = V4L2_COLORSPACE_SRGB,
+	},
+};
+
+static struct v4l2_mbus_framefmt vs6624_default_fmt = {
+	.width = VGA_WIDTH,
+	.height = VGA_HEIGHT,
+	.code = V4L2_MBUS_FMT_UYVY8_2X8,
+	.field = V4L2_FIELD_NONE,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+};
+
+static const u16 vs6624_p1[] = {
+	0x8104, 0x03,
+	0x8105, 0x01,
+	0xc900, 0x03,
+	0xc904, 0x47,
+	0xc905, 0x10,
+	0xc906, 0x80,
+	0xc907, 0x3a,
+	0x903a, 0x02,
+	0x903b, 0x47,
+	0x903c, 0x15,
+	0xc908, 0x31,
+	0xc909, 0xdc,
+	0xc90a, 0x80,
+	0xc90b, 0x44,
+	0x9044, 0x02,
+	0x9045, 0x31,
+	0x9046, 0xe2,
+	0xc90c, 0x07,
+	0xc90d, 0xe0,
+	0xc90e, 0x80,
+	0xc90f, 0x47,
+	0x9047, 0x90,
+	0x9048, 0x83,
+	0x9049, 0x81,
+	0x904a, 0xe0,
+	0x904b, 0x60,
+	0x904c, 0x08,
+	0x904d, 0x90,
+	0x904e, 0xc0,
+	0x904f, 0x43,
+	0x9050, 0x74,
+	0x9051, 0x01,
+	0x9052, 0xf0,
+	0x9053, 0x80,
+	0x9054, 0x05,
+	0x9055, 0xE4,
+	0x9056, 0x90,
+	0x9057, 0xc0,
+	0x9058, 0x43,
+	0x9059, 0xf0,
+	0x905a, 0x02,
+	0x905b, 0x07,
+	0x905c, 0xec,
+	0xc910, 0x5d,
+	0xc911, 0xca,
+	0xc912, 0x80,
+	0xc913, 0x5d,
+	0x905d, 0xa3,
+	0x905e, 0x04,
+	0x905f, 0xf0,
+	0x9060, 0xa3,
+	0x9061, 0x04,
+	0x9062, 0xf0,
+	0x9063, 0x22,
+	0xc914, 0x72,
+	0xc915, 0x92,
+	0xc916, 0x80,
+	0xc917, 0x64,
+	0x9064, 0x74,
+	0x9065, 0x01,
+	0x9066, 0x02,
+	0x9067, 0x72,
+	0x9068, 0x95,
+	0xc918, 0x47,
+	0xc919, 0xf2,
+	0xc91a, 0x81,
+	0xc91b, 0x69,
+	0x9169, 0x74,
+	0x916a, 0x02,
+	0x916b, 0xf0,
+	0x916c, 0xec,
+	0x916d, 0xb4,
+	0x916e, 0x10,
+	0x916f, 0x0a,
+	0x9170, 0x90,
+	0x9171, 0x80,
+	0x9172, 0x16,
+	0x9173, 0xe0,
+	0x9174, 0x70,
+	0x9175, 0x04,
+	0x9176, 0x90,
+	0x9177, 0xd3,
+	0x9178, 0xc4,
+	0x9179, 0xf0,
+	0x917a, 0x22,
+	0xc91c, 0x0a,
+	0xc91d, 0xbe,
+	0xc91e, 0x80,
+	0xc91f, 0x73,
+	0x9073, 0xfc,
+	0x9074, 0xa3,
+	0x9075, 0xe0,
+	0x9076, 0xf5,
+	0x9077, 0x82,
+	0x9078, 0x8c,
+	0x9079, 0x83,
+	0x907a, 0xa3,
+	0x907b, 0xa3,
+	0x907c, 0xe0,
+	0x907d, 0xfc,
+	0x907e, 0xa3,
+	0x907f, 0xe0,
+	0x9080, 0xc3,
+	0x9081, 0x9f,
+	0x9082, 0xff,
+	0x9083, 0xec,
+	0x9084, 0x9e,
+	0x9085, 0xfe,
+	0x9086, 0x02,
+	0x9087, 0x0a,
+	0x9088, 0xea,
+	0xc920, 0x47,
+	0xc921, 0x38,
+	0xc922, 0x80,
+	0xc923, 0x89,
+	0x9089, 0xec,
+	0x908a, 0xd3,
+	0x908b, 0x94,
+	0x908c, 0x20,
+	0x908d, 0x40,
+	0x908e, 0x01,
+	0x908f, 0x1c,
+	0x9090, 0x90,
+	0x9091, 0xd3,
+	0x9092, 0xd4,
+	0x9093, 0xec,
+	0x9094, 0xf0,
+	0x9095, 0x02,
+	0x9096, 0x47,
+	0x9097, 0x3d,
+	0xc924, 0x45,
+	0xc925, 0xca,
+	0xc926, 0x80,
+	0xc927, 0x98,
+	0x9098, 0x12,
+	0x9099, 0x77,
+	0x909a, 0xd6,
+	0x909b, 0x02,
+	0x909c, 0x45,
+	0x909d, 0xcd,
+	0xc928, 0x20,
+	0xc929, 0xd5,
+	0xc92a, 0x80,
+	0xc92b, 0x9e,
+	0x909e, 0x90,
+	0x909f, 0x82,
+	0x90a0, 0x18,
+	0x90a1, 0xe0,
+	0x90a2, 0xb4,
+	0x90a3, 0x03,
+	0x90a4, 0x0e,
+	0x90a5, 0x90,
+	0x90a6, 0x83,
+	0x90a7, 0xbf,
+	0x90a8, 0xe0,
+	0x90a9, 0x60,
+	0x90aa, 0x08,
+	0x90ab, 0x90,
+	0x90ac, 0x81,
+	0x90ad, 0xfc,
+	0x90ae, 0xe0,
+	0x90af, 0xff,
+	0x90b0, 0xc3,
+	0x90b1, 0x13,
+	0x90b2, 0xf0,
+	0x90b3, 0x90,
+	0x90b4, 0x81,
+	0x90b5, 0xfc,
+	0x90b6, 0xe0,
+	0x90b7, 0xff,
+	0x90b8, 0x02,
+	0x90b9, 0x20,
+	0x90ba, 0xda,
+	0xc92c, 0x70,
+	0xc92d, 0xbc,
+	0xc92e, 0x80,
+	0xc92f, 0xbb,
+	0x90bb, 0x90,
+	0x90bc, 0x82,
+	0x90bd, 0x18,
+	0x90be, 0xe0,
+	0x90bf, 0xb4,
+	0x90c0, 0x03,
+	0x90c1, 0x06,
+	0x90c2, 0x90,
+	0x90c3, 0xc1,
+	0x90c4, 0x06,
+	0x90c5, 0x74,
+	0x90c6, 0x05,
+	0x90c7, 0xf0,
+	0x90c8, 0x90,
+	0x90c9, 0xd3,
+	0x90ca, 0xa0,
+	0x90cb, 0x02,
+	0x90cc, 0x70,
+	0x90cd, 0xbf,
+	0xc930, 0x72,
+	0xc931, 0x21,
+	0xc932, 0x81,
+	0xc933, 0x3b,
+	0x913b, 0x7d,
+	0x913c, 0x02,
+	0x913d, 0x7f,
+	0x913e, 0x7b,
+	0x913f, 0x02,
+	0x9140, 0x72,
+	0x9141, 0x25,
+	0xc934, 0x28,
+	0xc935, 0xae,
+	0xc936, 0x80,
+	0xc937, 0xd2,
+	0x90d2, 0xf0,
+	0x90d3, 0x90,
+	0x90d4, 0xd2,
+	0x90d5, 0x0a,
+	0x90d6, 0x02,
+	0x90d7, 0x28,
+	0x90d8, 0xb4,
+	0xc938, 0x28,
+	0xc939, 0xb1,
+	0xc93a, 0x80,
+	0xc93b, 0xd9,
+	0x90d9, 0x90,
+	0x90da, 0x83,
+	0x90db, 0xba,
+	0x90dc, 0xe0,
+	0x90dd, 0xff,
+	0x90de, 0x90,
+	0x90df, 0xd2,
+	0x90e0, 0x08,
+	0x90e1, 0xe0,
+	0x90e2, 0xe4,
+	0x90e3, 0xef,
+	0x90e4, 0xf0,
+	0x90e5, 0xa3,
+	0x90e6, 0xe0,
+	0x90e7, 0x74,
+	0x90e8, 0xff,
+	0x90e9, 0xf0,
+	0x90ea, 0x90,
+	0x90eb, 0xd2,
+	0x90ec, 0x0a,
+	0x90ed, 0x02,
+	0x90ee, 0x28,
+	0x90ef, 0xb4,
+	0xc93c, 0x29,
+	0xc93d, 0x79,
+	0xc93e, 0x80,
+	0xc93f, 0xf0,
+	0x90f0, 0xf0,
+	0x90f1, 0x90,
+	0x90f2, 0xd2,
+	0x90f3, 0x0e,
+	0x90f4, 0x02,
+	0x90f5, 0x29,
+	0x90f6, 0x7f,
+	0xc940, 0x29,
+	0xc941, 0x7c,
+	0xc942, 0x80,
+	0xc943, 0xf7,
+	0x90f7, 0x90,
+	0x90f8, 0x83,
+	0x90f9, 0xba,
+	0x90fa, 0xe0,
+	0x90fb, 0xff,
+	0x90fc, 0x90,
+	0x90fd, 0xd2,
+	0x90fe, 0x0c,
+	0x90ff, 0xe0,
+	0x9100, 0xe4,
+	0x9101, 0xef,
+	0x9102, 0xf0,
+	0x9103, 0xa3,
+	0x9104, 0xe0,
+	0x9105, 0x74,
+	0x9106, 0xff,
+	0x9107, 0xf0,
+	0x9108, 0x90,
+	0x9109, 0xd2,
+	0x910a, 0x0e,
+	0x910b, 0x02,
+	0x910c, 0x29,
+	0x910d, 0x7f,
+	0xc944, 0x2a,
+	0xc945, 0x42,
+	0xc946, 0x81,
+	0xc947, 0x0e,
+	0x910e, 0xf0,
+	0x910f, 0x90,
+	0x9110, 0xd2,
+	0x9111, 0x12,
+	0x9112, 0x02,
+	0x9113, 0x2a,
+	0x9114, 0x48,
+	0xc948, 0x2a,
+	0xc949, 0x45,
+	0xc94a, 0x81,
+	0xc94b, 0x15,
+	0x9115, 0x90,
+	0x9116, 0x83,
+	0x9117, 0xba,
+	0x9118, 0xe0,
+	0x9119, 0xff,
+	0x911a, 0x90,
+	0x911b, 0xd2,
+	0x911c, 0x10,
+	0x911d, 0xe0,
+	0x911e, 0xe4,
+	0x911f, 0xef,
+	0x9120, 0xf0,
+	0x9121, 0xa3,
+	0x9122, 0xe0,
+	0x9123, 0x74,
+	0x9124, 0xff,
+	0x9125, 0xf0,
+	0x9126, 0x90,
+	0x9127, 0xd2,
+	0x9128, 0x12,
+	0x9129, 0x02,
+	0x912a, 0x2a,
+	0x912b, 0x48,
+	0xc900, 0x01,
+	0x0000, 0x00,
+};
+
+static const u16 vs6624_p2[] = {
+	0x806f, 0x01,
+	0x058c, 0x01,
+	0x0000, 0x00,
+};
+
+static const u16 vs6624_run_setup[] = {
+	0x1d18, 0x00,				/* Enableconstrainedwhitebalance */
+	VS6624_PEAK_MIN_OUT_G_MSB, 0x3c,	/* Damper PeakGain Output MSB */
+	VS6624_PEAK_MIN_OUT_G_LSB, 0x66,	/* Damper PeakGain Output LSB */
+	VS6624_CM_LOW_THR_MSB, 0x65,		/* Damper Low MSB */
+	VS6624_CM_LOW_THR_LSB, 0xd1,		/* Damper Low LSB */
+	VS6624_CM_HIGH_THR_MSB, 0x66,		/* Damper High MSB */
+	VS6624_CM_HIGH_THR_LSB, 0x62,		/* Damper High LSB */
+	VS6624_CM_MIN_OUT_MSB, 0x00,		/* Damper Min output MSB */
+	VS6624_CM_MIN_OUT_LSB, 0x00,		/* Damper Min output LSB */
+	VS6624_NORA_DISABLE, 0x00,		/* Nora fDisable */
+	VS6624_NORA_USAGE, 0x04,		/* Nora usage */
+	VS6624_NORA_LOW_THR_MSB, 0x63,		/* Damper Low MSB Changed 0x63 to 0x65 */
+	VS6624_NORA_LOW_THR_LSB, 0xd1,		/* Damper Low LSB */
+	VS6624_NORA_HIGH_THR_MSB, 0x68,		/* Damper High MSB */
+	VS6624_NORA_HIGH_THR_LSB, 0xdd,		/* Damper High LSB */
+	VS6624_NORA_MIN_OUT_MSB, 0x3a,		/* Damper Min output MSB */
+	VS6624_NORA_MIN_OUT_LSB, 0x00,		/* Damper Min output LSB */
+	VS6624_F2B_DISABLE, 0x00,		/* Disable */
+	0x1d8a, 0x30,				/* MAXWeightHigh */
+	0x1d91, 0x62,				/* fpDamperLowThresholdHigh MSB */
+	0x1d92, 0x4a,				/* fpDamperLowThresholdHigh LSB */
+	0x1d95, 0x65,				/* fpDamperHighThresholdHigh MSB */
+	0x1d96, 0x0e,				/* fpDamperHighThresholdHigh LSB */
+	0x1da1, 0x3a,				/* fpMinimumDamperOutputLow MSB */
+	0x1da2, 0xb8,				/* fpMinimumDamperOutputLow LSB */
+	0x1e08, 0x06,				/* MAXWeightLow */
+	0x1e0a, 0x0a,				/* MAXWeightHigh */
+	0x1601, 0x3a,				/* Red A MSB */
+	0x1602, 0x14,				/* Red A LSB */
+	0x1605, 0x3b,				/* Blue A MSB */
+	0x1606, 0x85,				/* BLue A LSB */
+	0x1609, 0x3b,				/* RED B MSB */
+	0x160a, 0x85,				/* RED B LSB */
+	0x160d, 0x3a,				/* Blue B MSB */
+	0x160e, 0x14,				/* Blue B LSB */
+	0x1611, 0x30,				/* Max Distance from Locus MSB */
+	0x1612, 0x8f,				/* Max Distance from Locus MSB */
+	0x1614, 0x01,				/* Enable constrainer */
+	0x0000, 0x00,
+};
+
+static const u16 vs6624_default[] = {
+	VS6624_CONTRAST0, 0x84,
+	VS6624_SATURATION0, 0x75,
+	VS6624_GAMMA0, 0x11,
+	VS6624_CONTRAST1, 0x84,
+	VS6624_SATURATION1, 0x75,
+	VS6624_GAMMA1, 0x11,
+	VS6624_MAN_RG, 0x80,
+	VS6624_MAN_GG, 0x80,
+	VS6624_MAN_BG, 0x80,
+	VS6624_WB_MODE, 0x1,
+	VS6624_EXPO_COMPENSATION, 0xfe,
+	VS6624_EXPO_METER, 0x0,
+	VS6624_LIGHT_FREQ, 0x64,
+	VS6624_PEAK_GAIN, 0xe,
+	VS6624_PEAK_LOW_THR, 0x28,
+	VS6624_HMIRROR0, 0x0,
+	VS6624_VFLIP0, 0x0,
+	VS6624_ZOOM_HSTEP0_MSB, 0x0,
+	VS6624_ZOOM_HSTEP0_LSB, 0x1,
+	VS6624_ZOOM_VSTEP0_MSB, 0x0,
+	VS6624_ZOOM_VSTEP0_LSB, 0x1,
+	VS6624_PAN_HSTEP0_MSB, 0x0,
+	VS6624_PAN_HSTEP0_LSB, 0xf,
+	VS6624_PAN_VSTEP0_MSB, 0x0,
+	VS6624_PAN_VSTEP0_LSB, 0xf,
+	VS6624_SENSOR_MODE, 0x1,
+	VS6624_SYNC_CODE_SETUP, 0x21,
+	VS6624_DISABLE_FR_DAMPER, 0x0,
+	VS6624_FR_DEN, 0x1,
+	VS6624_FR_NUM_LSB, 0xf,
+	VS6624_INIT_PIPE_SETUP, 0x0,
+	VS6624_IMG_FMT0, 0x0,
+	VS6624_YUV_SETUP, 0x1,
+	VS6624_IMAGE_SIZE0, 0x2,
+	0x0000, 0x00,
+};
+
+static inline struct vs6624 *to_vs6624(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct vs6624, sd);
+}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct vs6624, hdl)->sd;
+}
+
+static int vs6624_read(struct v4l2_subdev *sd, u16 index)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 buf[2];
+
+	buf[0] = index >> 8;
+	buf[1] = index;
+	i2c_master_send(client, buf, 2);
+	i2c_master_recv(client, buf, 1);
+
+	return buf[0];
+}
+
+static int vs6624_write(struct v4l2_subdev *sd, u16 index,
+				u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 buf[3];
+
+	buf[0] = index >> 8;
+	buf[1] = index;
+	buf[2] = value;
+
+	return i2c_master_send(client, buf, 3);
+}
+
+static int vs6624_writeregs(struct v4l2_subdev *sd, const u16 *regs)
+{
+	u16 reg;
+	u8 data;
+
+	while (*regs != 0x00) {
+		reg = *regs++;
+		data = *regs++;
+
+		vs6624_write(sd, reg, data);
+	}
+	return 0;
+}
+
+static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_sd(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_CONTRAST:
+		vs6624_write(sd, VS6624_CONTRAST0, ctrl->val);
+		break;
+	case V4L2_CID_SATURATION:
+		vs6624_write(sd, VS6624_SATURATION0, ctrl->val);
+		break;
+	case V4L2_CID_HFLIP:
+		vs6624_write(sd, VS6624_HMIRROR0, ctrl->val);
+		break;
+	case V4L2_CID_VFLIP:
+		vs6624_write(sd, VS6624_VFLIP0, ctrl->val);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vs6624_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+				enum v4l2_mbus_pixelcode *code)
+{
+	if (index >= ARRAY_SIZE(vs6624_formats))
+		return -EINVAL;
+
+	*code = vs6624_formats[index].mbus_code;
+	return 0;
+}
+
+static int vs6624_try_mbus_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *fmt)
+{
+	int index;
+
+	for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++)
+		if (vs6624_formats[index].mbus_code == fmt->code)
+			break;
+	if (index >= ARRAY_SIZE(vs6624_formats)) {
+		/* default to first format */
+		index = 0;
+		fmt->code = vs6624_formats[0].mbus_code;
+	}
+
+	/* sensor mode is VGA */
+	if (fmt->width > VGA_WIDTH)
+		fmt->width = VGA_WIDTH;
+	if (fmt->height > VGA_HEIGHT)
+		fmt->height = VGA_HEIGHT;
+	fmt->width = fmt->width & (~3);
+	fmt->height = fmt->height & (~3);
+	fmt->field = V4L2_FIELD_NONE;
+	fmt->colorspace = vs6624_formats[index].colorspace;
+	return 0;
+}
+
+static int vs6624_s_mbus_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *fmt)
+{
+	struct vs6624 *sensor = to_vs6624(sd);
+	int ret;
+
+	ret = vs6624_try_mbus_fmt(sd, fmt);
+	if (ret)
+		return ret;
+
+	/* set image format */
+	switch (fmt->code) {
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
+		vs6624_write(sd, VS6624_YUV_SETUP, 0x1);
+		break;
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+		vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
+		vs6624_write(sd, VS6624_YUV_SETUP, 0x3);
+		break;
+	case V4L2_MBUS_FMT_RGB565_2X8_LE:
+		vs6624_write(sd, VS6624_IMG_FMT0, 0x4);
+		vs6624_write(sd, VS6624_RGB_SETUP, 0x0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set image size */
+	if ((fmt->width == VGA_WIDTH) && (fmt->height == VGA_HEIGHT))
+		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x2);
+	else if ((fmt->width == QVGA_WIDTH) && (fmt->height == QVGA_HEIGHT))
+		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x4);
+	else if ((fmt->width == QQVGA_WIDTH) && (fmt->height == QQVGA_HEIGHT))
+		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x6);
+	else if ((fmt->width == CIF_WIDTH) && (fmt->height == CIF_HEIGHT))
+		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x3);
+	else if ((fmt->width == QCIF_WIDTH) && (fmt->height == QCIF_HEIGHT))
+		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x5);
+	else if ((fmt->width == QQCIF_WIDTH) && (fmt->height == QQCIF_HEIGHT))
+		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x7);
+	else {
+		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x8);
+		vs6624_write(sd, VS6624_MAN_HSIZE0_MSB, fmt->width >> 8);
+		vs6624_write(sd, VS6624_MAN_HSIZE0_LSB, fmt->width & 0xFF);
+		vs6624_write(sd, VS6624_MAN_VSIZE0_MSB, fmt->height >> 8);
+		vs6624_write(sd, VS6624_MAN_VSIZE0_LSB, fmt->height & 0xFF);
+		vs6624_write(sd, VS6624_CROP_CTRL0, 0x1);
+	}
+
+	sensor->fmt = *fmt;
+
+	return 0;
+}
+
+static int vs6624_g_mbus_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *fmt)
+{
+	struct vs6624 *sensor = to_vs6624(sd);
+
+	*fmt = sensor->fmt;
+	return 0;
+}
+
+static int vs6624_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+	struct vs6624 *sensor = to_vs6624(sd);
+	struct v4l2_captureparm *cp = &parms->parm.capture;
+
+	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	memset(cp, 0, sizeof(*cp));
+	cp->capability = V4L2_CAP_TIMEPERFRAME;
+	cp->timeperframe.numerator = sensor->frame_rate.denominator;
+	cp->timeperframe.denominator = sensor->frame_rate.numerator;
+	return 0;
+}
+
+static int vs6624_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+	struct vs6624 *sensor = to_vs6624(sd);
+	struct v4l2_captureparm *cp = &parms->parm.capture;
+	struct v4l2_fract *tpf = &cp->timeperframe;
+
+	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (cp->extendedmode != 0)
+		return -EINVAL;
+
+	if (tpf->numerator == 0 || tpf->denominator == 0
+		|| (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) {
+		/* reset to max frame rate */
+		tpf->numerator = 1;
+		tpf->denominator = MAX_FRAME_RATE;
+	}
+	sensor->frame_rate.numerator = tpf->denominator;
+	sensor->frame_rate.denominator = tpf->numerator;
+	vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
+	vs6624_write(sd, VS6624_FR_NUM_MSB,
+			sensor->frame_rate.numerator >> 8);
+	vs6624_write(sd, VS6624_FR_NUM_LSB,
+			sensor->frame_rate.numerator & 0xFF);
+	vs6624_write(sd, VS6624_FR_DEN,
+			sensor->frame_rate.denominator & 0xFF);
+	return 0;
+}
+
+static int vs6624_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	if (enable)
+		vs6624_write(sd, VS6624_USER_CMD, 0x2);
+	else
+		vs6624_write(sd, VS6624_USER_CMD, 0x4);
+	udelay(100);
+	return 0;
+}
+
+static int vs6624_g_chip_ident(struct v4l2_subdev *sd,
+		struct v4l2_dbg_chip_ident *chip)
+{
+	int rev;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	rev = (vs6624_read(sd, VS6624_FW_VSN_MAJOR) << 8)
+		| vs6624_read(sd, VS6624_FW_VSN_MINOR);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VS6624, rev);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	reg->val = vs6624_read(sd, reg->reg & 0xffff);
+	reg->size = 1;
+	return 0;
+}
+
+static int vs6624_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (!v4l2_chip_match_i2c_client(client, &reg->match))
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff);
+	return 0;
+}
+#endif
+
+static const struct v4l2_ctrl_ops vs6624_ctrl_ops = {
+	.s_ctrl = vs6624_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops vs6624_core_ops = {
+	.g_chip_ident = vs6624_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = vs6624_g_register,
+	.s_register = vs6624_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops vs6624_video_ops = {
+	.enum_mbus_fmt = vs6624_enum_mbus_fmt,
+	.try_mbus_fmt = vs6624_try_mbus_fmt,
+	.s_mbus_fmt = vs6624_s_mbus_fmt,
+	.g_mbus_fmt = vs6624_g_mbus_fmt,
+	.s_parm = vs6624_s_parm,
+	.g_parm = vs6624_g_parm,
+	.s_stream = vs6624_s_stream,
+};
+
+static const struct v4l2_subdev_ops vs6624_ops = {
+	.core = &vs6624_core_ops,
+	.video = &vs6624_video_ops,
+};
+
+static int __devinit vs6624_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct vs6624 *sensor;
+	struct v4l2_subdev *sd;
+	struct v4l2_ctrl_handler *hdl;
+	const unsigned *ce;
+	int ret;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+		return -EIO;
+
+	ce = client->dev.platform_data;
+	if (ce == NULL)
+		return -EINVAL;
+
+	ret = gpio_request(*ce, "VS6624 Chip Enable");
+	if (ret) {
+		v4l_err(client, "failed to request GPIO %d\n", *ce);
+		return ret;
+	}
+	gpio_direction_output(*ce, 1);
+	/* wait 100ms before any further i2c writes are performed */
+	mdelay(100);
+
+	sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+	if (sensor == NULL) {
+		gpio_free(*ce);
+		return -ENOMEM;
+	}
+
+	sd = &sensor->sd;
+	v4l2_i2c_subdev_init(sd, client, &vs6624_ops);
+
+	vs6624_writeregs(sd, vs6624_p1);
+	vs6624_write(sd, VS6624_MICRO_EN, 0x2);
+	vs6624_write(sd, VS6624_DIO_EN, 0x1);
+	mdelay(10);
+	vs6624_writeregs(sd, vs6624_p2);
+
+	vs6624_writeregs(sd, vs6624_default);
+	vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF);
+	vs6624_writeregs(sd, vs6624_run_setup);
+
+	/* set frame rate */
+	sensor->frame_rate.numerator = MAX_FRAME_RATE;
+	sensor->frame_rate.denominator = 1;
+	vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
+	vs6624_write(sd, VS6624_FR_NUM_MSB,
+			sensor->frame_rate.numerator >> 8);
+	vs6624_write(sd, VS6624_FR_NUM_LSB,
+			sensor->frame_rate.numerator & 0xFF);
+	vs6624_write(sd, VS6624_FR_DEN,
+			sensor->frame_rate.denominator & 0xFF);
+
+	sensor->fmt = vs6624_default_fmt;
+	sensor->ce_pin = *ce;
+
+	v4l_info(client, "chip found @ 0x%02x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	hdl = &sensor->hdl;
+	v4l2_ctrl_handler_init(hdl, 4);
+	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x87);
+	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 0xFF, 1, 0x78);
+	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	/* hook the control handler into the driver */
+	sd->ctrl_handler = hdl;
+	if (hdl->error) {
+		int err = hdl->error;
+
+		v4l2_ctrl_handler_free(hdl);
+		kfree(sensor);
+		gpio_free(*ce);
+		return err;
+	}
+
+	/* initialize the hardware to the default control values */
+	ret = v4l2_ctrl_handler_setup(hdl);
+	if (ret) {
+		v4l2_ctrl_handler_free(hdl);
+		kfree(sensor);
+		gpio_free(*ce);
+	}
+	return ret;
+}
+
+static int __devexit vs6624_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct vs6624 *sensor = to_vs6624(sd);
+
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(sd->ctrl_handler);
+	gpio_free(sensor->ce_pin);
+	kfree(sensor);
+	return 0;
+}
+
+static const struct i2c_device_id vs6624_id[] = {
+	{"vs6624", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, vs6624_id);
+
+static struct i2c_driver vs6624_driver = {
+	.driver = {
+		.owner  = THIS_MODULE,
+		.name   = "vs6624",
+	},
+	.probe          = vs6624_probe,
+	.remove         = __devexit_p(vs6624_remove),
+	.id_table       = vs6624_id,
+};
+
+static __init int vs6624_init(void)
+{
+	return i2c_add_driver(&vs6624_driver);
+}
+
+static __exit void vs6624_exit(void)
+{
+	i2c_del_driver(&vs6624_driver);
+}
+
+module_init(vs6624_init);
+module_exit(vs6624_exit);
+
+MODULE_DESCRIPTION("VS6624 sensor driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/vs6624_regs.h b/drivers/media/video/vs6624_regs.h
new file mode 100644
index 0000000..6ba2ee2
--- /dev/null
+++ b/drivers/media/video/vs6624_regs.h
@@ -0,0 +1,337 @@
+/*
+ * vs6624 - ST VS6624 CMOS image sensor registers
+ *
+ * Copyright (c) 2011 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _VS6624_REGS_H_
+#define _VS6624_REGS_H_
+
+/* low level control registers */
+#define VS6624_MICRO_EN               0xC003 /* power enable for all MCU clock */
+#define VS6624_DIO_EN                 0xC044 /* enable digital I/O */
+/* device parameters */
+#define VS6624_DEV_ID_MSB             0x0001 /* device id MSB */
+#define VS6624_DEV_ID_LSB             0x0002 /* device id LSB */
+#define VS6624_FW_VSN_MAJOR           0x0004 /* firmware version major */
+#define VS6624_FW_VSN_MINOR           0x0006 /* firmware version minor */
+#define VS6624_PATCH_VSN_MAJOR        0x0008 /* patch version major */
+#define VS6624_PATCH_VSN_MINOR        0x000A /* patch version minor */
+/* host interface manager control */
+#define VS6624_USER_CMD               0x0180 /* user level control of operating states */
+/* host interface manager status */
+#define VS6624_STATE                  0x0202 /* current state of the mode manager */
+/* run mode control */
+#define VS6624_METER_ON               0x0280 /* if false AE and AWB are disabled */
+/* mode setup */
+#define VS6624_ACTIVE_PIPE_SETUP      0x0302 /* select the active bank for non view live mode */
+#define VS6624_SENSOR_MODE            0x0308 /* select the different sensor mode */
+/* pipe setup bank0 */
+#define VS6624_IMAGE_SIZE0            0x0380 /* required output dimension */
+#define VS6624_MAN_HSIZE0_MSB         0x0383 /* input required manual H size MSB */
+#define VS6624_MAN_HSIZE0_LSB         0x0384 /* input required manual H size LSB */
+#define VS6624_MAN_VSIZE0_MSB         0x0387 /* input required manual V size MSB */
+#define VS6624_MAN_VSIZE0_LSB         0x0388 /* input required manual V size LSB */
+#define VS6624_ZOOM_HSTEP0_MSB        0x038B /* set the zoom H step MSB */
+#define VS6624_ZOOM_HSTEP0_LSB        0x038C /* set the zoom H step LSB */
+#define VS6624_ZOOM_VSTEP0_MSB        0x038F /* set the zoom V step MSB */
+#define VS6624_ZOOM_VSTEP0_LSB        0x0390 /* set the zoom V step LSB */
+#define VS6624_ZOOM_CTRL0             0x0392 /* control zoon in, out and stop */
+#define VS6624_PAN_HSTEP0_MSB         0x0395 /* set the pan H step MSB */
+#define VS6624_PAN_HSTEP0_LSB         0x0396 /* set the pan H step LSB */
+#define VS6624_PAN_VSTEP0_MSB         0x0399 /* set the pan V step MSB */
+#define VS6624_PAN_VSTEP0_LSB         0x039A /* set the pan V step LSB */
+#define VS6624_PAN_CTRL0              0x039C /* control pan operation */
+#define VS6624_CROP_CTRL0             0x039E /* select cropping mode */
+#define VS6624_CROP_HSTART0_MSB       0x03A1 /* set the cropping H start address MSB */
+#define VS6624_CROP_HSTART0_LSB       0x03A2 /* set the cropping H start address LSB */
+#define VS6624_CROP_HSIZE0_MSB        0x03A5 /* set the cropping H size MSB */
+#define VS6624_CROP_HSIZE0_LSB        0x03A6 /* set the cropping H size LSB */
+#define VS6624_CROP_VSTART0_MSB       0x03A9 /* set the cropping V start address MSB */
+#define VS6624_CROP_VSTART0_LSB       0x03AA /* set the cropping V start address LSB */
+#define VS6624_CROP_VSIZE0_MSB        0x03AD /* set the cropping V size MSB */
+#define VS6624_CROP_VSIZE0_LSB        0x03AE /* set the cropping V size LSB */
+#define VS6624_IMG_FMT0               0x03B0 /* select required output image format */
+#define VS6624_BAYER_OUT_ALIGN0       0x03B2 /* set bayer output alignment */
+#define VS6624_CONTRAST0              0x03B4 /* contrast control for output */
+#define VS6624_SATURATION0            0x03B6 /* saturation control for output */
+#define VS6624_GAMMA0                 0x03B8 /* gamma settings */
+#define VS6624_HMIRROR0               0x03BA /* horizontal image orientation flip */
+#define VS6624_VFLIP0                 0x03BC /* vertical image orientation flip */
+#define VS6624_CHANNEL_ID0            0x03BE /* logical DMA channel number */
+/* pipe setup bank1 */
+#define VS6624_IMAGE_SIZE1            0x0400 /* required output dimension */
+#define VS6624_MAN_HSIZE1_MSB         0x0403 /* input required manual H size MSB */
+#define VS6624_MAN_HSIZE1_LSB         0x0404 /* input required manual H size LSB */
+#define VS6624_MAN_VSIZE1_MSB         0x0407 /* input required manual V size MSB */
+#define VS6624_MAN_VSIZE1_LSB         0x0408 /* input required manual V size LSB */
+#define VS6624_ZOOM_HSTEP1_MSB        0x040B /* set the zoom H step MSB */
+#define VS6624_ZOOM_HSTEP1_LSB        0x040C /* set the zoom H step LSB */
+#define VS6624_ZOOM_VSTEP1_MSB        0x040F /* set the zoom V step MSB */
+#define VS6624_ZOOM_VSTEP1_LSB        0x0410 /* set the zoom V step LSB */
+#define VS6624_ZOOM_CTRL1             0x0412 /* control zoon in, out and stop */
+#define VS6624_PAN_HSTEP1_MSB         0x0415 /* set the pan H step MSB */
+#define VS6624_PAN_HSTEP1_LSB         0x0416 /* set the pan H step LSB */
+#define VS6624_PAN_VSTEP1_MSB         0x0419 /* set the pan V step MSB */
+#define VS6624_PAN_VSTEP1_LSB         0x041A /* set the pan V step LSB */
+#define VS6624_PAN_CTRL1              0x041C /* control pan operation */
+#define VS6624_CROP_CTRL1             0x041E /* select cropping mode */
+#define VS6624_CROP_HSTART1_MSB       0x0421 /* set the cropping H start address MSB */
+#define VS6624_CROP_HSTART1_LSB       0x0422 /* set the cropping H start address LSB */
+#define VS6624_CROP_HSIZE1_MSB        0x0425 /* set the cropping H size MSB */
+#define VS6624_CROP_HSIZE1_LSB        0x0426 /* set the cropping H size LSB */
+#define VS6624_CROP_VSTART1_MSB       0x0429 /* set the cropping V start address MSB */
+#define VS6624_CROP_VSTART1_LSB       0x042A /* set the cropping V start address LSB */
+#define VS6624_CROP_VSIZE1_MSB        0x042D /* set the cropping V size MSB */
+#define VS6624_CROP_VSIZE1_LSB        0x042E /* set the cropping V size LSB */
+#define VS6624_IMG_FMT1               0x0430 /* select required output image format */
+#define VS6624_BAYER_OUT_ALIGN1       0x0432 /* set bayer output alignment */
+#define VS6624_CONTRAST1              0x0434 /* contrast control for output */
+#define VS6624_SATURATION1            0x0436 /* saturation control for output */
+#define VS6624_GAMMA1                 0x0438 /* gamma settings */
+#define VS6624_HMIRROR1               0x043A /* horizontal image orientation flip */
+#define VS6624_VFLIP1                 0x043C /* vertical image orientation flip */
+#define VS6624_CHANNEL_ID1            0x043E /* logical DMA channel number */
+/* view live control */
+#define VS6624_VIEW_LIVE_EN           0x0480 /* enable view live mode */
+#define VS6624_INIT_PIPE_SETUP        0x0482 /* select initial pipe setup bank */
+/* view live status */
+#define VS6624_CUR_PIPE_SETUP         0x0500 /* indicates most recently applied setup bank */
+/* power management */
+#define VS6624_TIME_TO_POWER_DOWN     0x0580 /* automatically transition time to stop mode */
+/* video timing parameter host inputs */
+#define VS6624_EXT_CLK_FREQ_NUM_MSB   0x0605 /* external clock frequency numerator MSB */
+#define VS6624_EXT_CLK_FREQ_NUM_LSB   0x0606 /* external clock frequency numerator LSB */
+#define VS6624_EXT_CLK_FREQ_DEN       0x0608 /* external clock frequency denominator */
+/* video timing control */
+#define VS6624_SYS_CLK_MODE           0x0880 /* decides system clock frequency */
+/* frame dimension parameter host inputs */
+#define VS6624_LIGHT_FREQ             0x0C80 /* AC frequency used for flicker free time */
+#define VS6624_FLICKER_COMPAT         0x0C82 /* flicker compatible frame length */
+/* static frame rate control */
+#define VS6624_FR_NUM_MSB             0x0D81 /* desired frame rate numerator MSB */
+#define VS6624_FR_NUM_LSB             0x0D82 /* desired frame rate numerator LSB */
+#define VS6624_FR_DEN                 0x0D84 /* desired frame rate denominator */
+/* automatic frame rate control */
+#define VS6624_DISABLE_FR_DAMPER      0x0E80 /* defines frame rate mode */
+#define VS6624_MIN_DAMPER_OUT_MSB     0x0E8C /* minimum frame rate MSB */
+#define VS6624_MIN_DAMPER_OUT_LSB     0x0E8A /* minimum frame rate LSB */
+/* exposure controls */
+#define VS6624_EXPO_MODE              0x1180 /* exposure mode */
+#define VS6624_EXPO_METER             0x1182 /* weights to be associated with the zones */
+#define VS6624_EXPO_TIME_NUM          0x1184 /* exposure time numerator */
+#define VS6624_EXPO_TIME_DEN          0x1186 /* exposure time denominator */
+#define VS6624_EXPO_TIME_MSB          0x1189 /* exposure time for the Manual Mode MSB */
+#define VS6624_EXPO_TIME_LSB          0x118A /* exposure time for the Manual Mode LSB */
+#define VS6624_EXPO_COMPENSATION      0x1190 /* exposure compensation */
+#define VS6624_DIRECT_COARSE_MSB      0x1195 /* coarse integration lines for Direct Mode MSB */
+#define VS6624_DIRECT_COARSE_LSB      0x1196 /* coarse integration lines for Direct Mode LSB */
+#define VS6624_DIRECT_FINE_MSB        0x1199 /* fine integration pixels for Direct Mode MSB */
+#define VS6624_DIRECT_FINE_LSB        0x119A /* fine integration pixels for Direct Mode LSB */
+#define VS6624_DIRECT_ANAL_GAIN_MSB   0x119D /* analog gain for Direct Mode MSB */
+#define VS6624_DIRECT_ANAL_GAIN_LSB   0x119E /* analog gain for Direct Mode LSB */
+#define VS6624_DIRECT_DIGI_GAIN_MSB   0x11A1 /* digital gain for Direct Mode MSB */
+#define VS6624_DIRECT_DIGI_GAIN_LSB   0x11A2 /* digital gain for Direct Mode LSB */
+#define VS6624_FLASH_COARSE_MSB       0x11A5 /* coarse integration lines for Flash Gun Mode MSB */
+#define VS6624_FLASH_COARSE_LSB       0x11A6 /* coarse integration lines for Flash Gun Mode LSB */
+#define VS6624_FLASH_FINE_MSB         0x11A9 /* fine integration pixels for Flash Gun Mode MSB */
+#define VS6624_FLASH_FINE_LSB         0x11AA /* fine integration pixels for Flash Gun Mode LSB */
+#define VS6624_FLASH_ANAL_GAIN_MSB    0x11AD /* analog gain for Flash Gun Mode MSB */
+#define VS6624_FLASH_ANAL_GAIN_LSB    0x11AE /* analog gain for Flash Gun Mode LSB */
+#define VS6624_FLASH_DIGI_GAIN_MSB    0x11B1 /* digital gain for Flash Gun Mode MSB */
+#define VS6624_FLASH_DIGI_GAIN_LSB    0x11B2 /* digital gain for Flash Gun Mode LSB */
+#define VS6624_FREEZE_AE              0x11B4 /* freeze auto exposure */
+#define VS6624_MAX_INT_TIME_MSB       0x11B7 /* user maximum integration time MSB */
+#define VS6624_MAX_INT_TIME_LSB       0x11B8 /* user maximum integration time LSB */
+#define VS6624_FLASH_AG_THR_MSB       0x11BB /* recommend flash gun analog gain threshold MSB */
+#define VS6624_FLASH_AG_THR_LSB       0x11BC /* recommend flash gun analog gain threshold LSB */
+#define VS6624_ANTI_FLICKER_MODE      0x11C0 /* anti flicker mode */
+/* white balance control */
+#define VS6624_WB_MODE                0x1480 /* set white balance mode */
+#define VS6624_MAN_RG                 0x1482 /* user setting for red channel gain */
+#define VS6624_MAN_GG                 0x1484 /* user setting for green channel gain */
+#define VS6624_MAN_BG                 0x1486 /* user setting for blue channel gain */
+#define VS6624_FLASH_RG_MSB           0x148B /* red gain for Flash Gun MSB */
+#define VS6624_FLASH_RG_LSB           0x148C /* red gain for Flash Gun LSB */
+#define VS6624_FLASH_GG_MSB           0x148F /* green gain for Flash Gun MSB */
+#define VS6624_FLASH_GG_LSB           0x1490 /* green gain for Flash Gun LSB */
+#define VS6624_FLASH_BG_MSB           0x1493 /* blue gain for Flash Gun MSB */
+#define VS6624_FLASH_BG_LSB           0x1494 /* blue gain for Flash Gun LSB */
+/* sensor setup */
+#define VS6624_BC_OFFSET              0x1990 /* Black Correction Offset */
+/* image stability */
+#define VS6624_STABLE_WB              0x1900 /* white balance stable */
+#define VS6624_STABLE_EXPO            0x1902 /* exposure stable */
+#define VS6624_STABLE                 0x1906 /* system stable */
+/* flash control */
+#define VS6624_FLASH_MODE             0x1A80 /* flash mode */
+#define VS6624_FLASH_OFF_LINE_MSB     0x1A83 /* off line at flash pulse mode MSB */
+#define VS6624_FLASH_OFF_LINE_LSB     0x1A84 /* off line at flash pulse mode LSB */
+/* flash status */
+#define VS6624_FLASH_RECOM            0x1B00 /* flash gun is recommended */
+#define VS6624_FLASH_GRAB_COMPLETE    0x1B02 /* flash gun image has been grabbed */
+/* scythe filter controls */
+#define VS6624_SCYTHE_FILTER          0x1D80 /* disable scythe defect correction */
+/* jack filter controls */
+#define VS6624_JACK_FILTER            0x1E00 /* disable jack defect correction */
+/* demosaic control */
+#define VS6624_ANTI_ALIAS_FILTER      0x1E80 /* anti alias filter suppress */
+/* color matrix dampers */
+#define VS6624_CM_DISABLE             0x1F00 /* disable color matrix damper */
+#define VS6624_CM_LOW_THR_MSB         0x1F03 /* low threshold for exposure MSB */
+#define VS6624_CM_LOW_THR_LSB         0x1F04 /* low threshold for exposure LSB */
+#define VS6624_CM_HIGH_THR_MSB        0x1F07 /* high threshold for exposure MSB */
+#define VS6624_CM_HIGH_THR_LSB        0x1F08 /* high threshold for exposure LSB */
+#define VS6624_CM_MIN_OUT_MSB         0x1F0B /* minimum possible damper output MSB */
+#define VS6624_CM_MIN_OUT_LSB         0x1F0C /* minimum possible damper output LSB */
+/* peaking control */
+#define VS6624_PEAK_GAIN              0x2000 /* controls peaking gain */
+#define VS6624_PEAK_G_DISABLE         0x2002 /* disable peak gain damping */
+#define VS6624_PEAK_LOW_THR_G_MSB     0x2005 /* low threshold for exposure for gain MSB */
+#define VS6624_PEAK_LOW_THR_G_LSB     0x2006 /* low threshold for exposure for gain LSB */
+#define VS6624_PEAK_HIGH_THR_G_MSB    0x2009 /* high threshold for exposure for gain MSB */
+#define VS6624_PEAK_HIGH_THR_G_LSB    0x200A /* high threshold for exposure for gain LSB */
+#define VS6624_PEAK_MIN_OUT_G_MSB     0x200D /* minimum damper output for gain MSB */
+#define VS6624_PEAK_MIN_OUT_G_LSB     0x200E /* minimum damper output for gain LSB */
+#define VS6624_PEAK_LOW_THR           0x2010 /* adjust degree of coring */
+#define VS6624_PEAK_C_DISABLE         0x2012 /* disable coring damping */
+#define VS6624_PEAK_HIGH_THR          0x2014 /* adjust maximum gain */
+#define VS6624_PEAK_LOW_THR_C_MSB     0x2017 /* low threshold for exposure for coring MSB */
+#define VS6624_PEAK_LOW_THR_C_LSB     0x2018 /* low threshold for exposure for coring LSB */
+#define VS6624_PEAK_HIGH_THR_C_MSB    0x201B /* high threshold for exposure for coring MSB */
+#define VS6624_PEAK_HIGH_THR_C_LSB    0x201C /* high threshold for exposure for coring LSB */
+#define VS6624_PEAK_MIN_OUT_C_MSB     0x201F /* minimum damper output for coring MSB */
+#define VS6624_PEAK_MIN_OUT_C_LSB     0x2020 /* minimum damper output for coring LSB */
+/* pipe 0 RGB to YUV matrix manual control */
+#define VS6624_RYM0_MAN_CTRL          0x2180 /* enable manual RGB to YUV matrix */
+#define VS6624_RYM0_W00_MSB           0x2183 /* row 0 column 0 of YUV matrix MSB */
+#define VS6624_RYM0_W00_LSB           0x2184 /* row 0 column 0 of YUV matrix LSB */
+#define VS6624_RYM0_W01_MSB           0x2187 /* row 0 column 1 of YUV matrix MSB */
+#define VS6624_RYM0_W01_LSB           0x2188 /* row 0 column 1 of YUV matrix LSB */
+#define VS6624_RYM0_W02_MSB           0x218C /* row 0 column 2 of YUV matrix MSB */
+#define VS6624_RYM0_W02_LSB           0x218D /* row 0 column 2 of YUV matrix LSB */
+#define VS6624_RYM0_W10_MSB           0x2190 /* row 1 column 0 of YUV matrix MSB */
+#define VS6624_RYM0_W10_LSB           0x218F /* row 1 column 0 of YUV matrix LSB */
+#define VS6624_RYM0_W11_MSB           0x2193 /* row 1 column 1 of YUV matrix MSB */
+#define VS6624_RYM0_W11_LSB           0x2194 /* row 1 column 1 of YUV matrix LSB */
+#define VS6624_RYM0_W12_MSB           0x2197 /* row 1 column 2 of YUV matrix MSB */
+#define VS6624_RYM0_W12_LSB           0x2198 /* row 1 column 2 of YUV matrix LSB */
+#define VS6624_RYM0_W20_MSB           0x219B /* row 2 column 0 of YUV matrix MSB */
+#define VS6624_RYM0_W20_LSB           0x219C /* row 2 column 0 of YUV matrix LSB */
+#define VS6624_RYM0_W21_MSB           0x21A0 /* row 2 column 1 of YUV matrix MSB */
+#define VS6624_RYM0_W21_LSB           0x219F /* row 2 column 1 of YUV matrix LSB */
+#define VS6624_RYM0_W22_MSB           0x21A3 /* row 2 column 2 of YUV matrix MSB */
+#define VS6624_RYM0_W22_LSB           0x21A4 /* row 2 column 2 of YUV matrix LSB */
+#define VS6624_RYM0_YINY_MSB          0x21A7 /* Y in Y MSB */
+#define VS6624_RYM0_YINY_LSB          0x21A8 /* Y in Y LSB */
+#define VS6624_RYM0_YINCB_MSB         0x21AB /* Y in Cb MSB */
+#define VS6624_RYM0_YINCB_LSB         0x21AC /* Y in Cb LSB */
+#define VS6624_RYM0_YINCR_MSB         0x21B0 /* Y in Cr MSB */
+#define VS6624_RYM0_YINCR_LSB         0x21AF /* Y in Cr LSB */
+/* pipe 1 RGB to YUV matrix manual control */
+#define VS6624_RYM1_MAN_CTRL          0x2200 /* enable manual RGB to YUV matrix */
+#define VS6624_RYM1_W00_MSB           0x2203 /* row 0 column 0 of YUV matrix MSB */
+#define VS6624_RYM1_W00_LSB           0x2204 /* row 0 column 0 of YUV matrix LSB */
+#define VS6624_RYM1_W01_MSB           0x2207 /* row 0 column 1 of YUV matrix MSB */
+#define VS6624_RYM1_W01_LSB           0x2208 /* row 0 column 1 of YUV matrix LSB */
+#define VS6624_RYM1_W02_MSB           0x220C /* row 0 column 2 of YUV matrix MSB */
+#define VS6624_RYM1_W02_LSB           0x220D /* row 0 column 2 of YUV matrix LSB */
+#define VS6624_RYM1_W10_MSB           0x2210 /* row 1 column 0 of YUV matrix MSB */
+#define VS6624_RYM1_W10_LSB           0x220F /* row 1 column 0 of YUV matrix LSB */
+#define VS6624_RYM1_W11_MSB           0x2213 /* row 1 column 1 of YUV matrix MSB */
+#define VS6624_RYM1_W11_LSB           0x2214 /* row 1 column 1 of YUV matrix LSB */
+#define VS6624_RYM1_W12_MSB           0x2217 /* row 1 column 2 of YUV matrix MSB */
+#define VS6624_RYM1_W12_LSB           0x2218 /* row 1 column 2 of YUV matrix LSB */
+#define VS6624_RYM1_W20_MSB           0x221B /* row 2 column 0 of YUV matrix MSB */
+#define VS6624_RYM1_W20_LSB           0x221C /* row 2 column 0 of YUV matrix LSB */
+#define VS6624_RYM1_W21_MSB           0x2220 /* row 2 column 1 of YUV matrix MSB */
+#define VS6624_RYM1_W21_LSB           0x221F /* row 2 column 1 of YUV matrix LSB */
+#define VS6624_RYM1_W22_MSB           0x2223 /* row 2 column 2 of YUV matrix MSB */
+#define VS6624_RYM1_W22_LSB           0x2224 /* row 2 column 2 of YUV matrix LSB */
+#define VS6624_RYM1_YINY_MSB          0x2227 /* Y in Y MSB */
+#define VS6624_RYM1_YINY_LSB          0x2228 /* Y in Y LSB */
+#define VS6624_RYM1_YINCB_MSB         0x222B /* Y in Cb MSB */
+#define VS6624_RYM1_YINCB_LSB         0x222C /* Y in Cb LSB */
+#define VS6624_RYM1_YINCR_MSB         0x2220 /* Y in Cr MSB */
+#define VS6624_RYM1_YINCR_LSB         0x222F /* Y in Cr LSB */
+/* pipe 0 gamma manual control */
+#define VS6624_GAMMA_MAN_CTRL0        0x2280 /* enable manual gamma setup */
+#define VS6624_GAMMA_PEAK_R0          0x2282 /* peaked red channel gamma value */
+#define VS6624_GAMMA_PEAK_G0          0x2284 /* peaked green channel gamma value */
+#define VS6624_GAMMA_PEAK_B0          0x2286 /* peaked blue channel gamma value */
+#define VS6624_GAMMA_UNPEAK_R0        0x2288 /* unpeaked red channel gamma value */
+#define VS6624_GAMMA_UNPEAK_G0        0x228A /* unpeaked green channel gamma value */
+#define VS6624_GAMMA_UNPEAK_B0        0x228C /* unpeaked blue channel gamma value */
+/* pipe 1 gamma manual control */
+#define VS6624_GAMMA_MAN_CTRL1        0x2300 /* enable manual gamma setup */
+#define VS6624_GAMMA_PEAK_R1          0x2302 /* peaked red channel gamma value */
+#define VS6624_GAMMA_PEAK_G1          0x2304 /* peaked green channel gamma value */
+#define VS6624_GAMMA_PEAK_B1          0x2306 /* peaked blue channel gamma value */
+#define VS6624_GAMMA_UNPEAK_R1        0x2308 /* unpeaked red channel gamma value */
+#define VS6624_GAMMA_UNPEAK_G1        0x230A /* unpeaked green channel gamma value */
+#define VS6624_GAMMA_UNPEAK_B1        0x230C /* unpeaked blue channel gamma value */
+/* fade to black */
+#define VS6624_F2B_DISABLE            0x2480 /* disable fade to black */
+#define VS6624_F2B_BLACK_VAL_MSB      0x2483 /* black value MSB */
+#define VS6624_F2B_BLACK_VAL_LSB      0x2484 /* black value LSB */
+#define VS6624_F2B_LOW_THR_MSB        0x2487 /* low threshold for exposure MSB */
+#define VS6624_F2B_LOW_THR_LSB        0x2488 /* low threshold for exposure LSB */
+#define VS6624_F2B_HIGH_THR_MSB       0x248B /* high threshold for exposure MSB */
+#define VS6624_F2B_HIGH_THR_LSB       0x248C /* high threshold for exposure LSB */
+#define VS6624_F2B_MIN_OUT_MSB        0x248F /* minimum damper output MSB */
+#define VS6624_F2B_MIN_OUT_LSB        0x2490 /* minimum damper output LSB */
+/* output formatter control */
+#define VS6624_CODE_CK_EN             0x2580 /* code check enable */
+#define VS6624_BLANK_FMT              0x2582 /* blank format */
+#define VS6624_SYNC_CODE_SETUP        0x2584 /* sync code setup */
+#define VS6624_HSYNC_SETUP            0x2586 /* H sync setup */
+#define VS6624_VSYNC_SETUP            0x2588 /* V sync setup */
+#define VS6624_PCLK_SETUP             0x258A /* PCLK setup */
+#define VS6624_PCLK_EN                0x258C /* PCLK enable */
+#define VS6624_OPF_SP_SETUP           0x258E /* output formatter sp setup */
+#define VS6624_BLANK_DATA_MSB         0x2590 /* blank data MSB */
+#define VS6624_BLANK_DATA_LSB         0x2592 /* blank data LSB */
+#define VS6624_RGB_SETUP              0x2594 /* RGB setup */
+#define VS6624_YUV_SETUP              0x2596 /* YUV setup */
+#define VS6624_VSYNC_RIS_COARSE_H     0x2598 /* V sync rising coarse high */
+#define VS6624_VSYNC_RIS_COARSE_L     0x259A /* V sync rising coarse low */
+#define VS6624_VSYNC_RIS_FINE_H       0x259C /* V sync rising fine high */
+#define VS6624_VSYNC_RIS_FINE_L       0x259E /* V sync rising fine low */
+#define VS6624_VSYNC_FALL_COARSE_H    0x25A0 /* V sync falling coarse high */
+#define VS6624_VSYNC_FALL_COARSE_L    0x25A2 /* V sync falling coarse low */
+#define VS6624_VSYNC_FALL_FINE_H      0x25A4 /* V sync falling fine high */
+#define VS6624_VSYNC_FALL_FINE_L      0x25A6 /* V sync falling fine low */
+#define VS6624_HSYNC_RIS_H            0x25A8 /* H sync rising high */
+#define VS6624_HSYNC_RIS_L            0x25AA /* H sync rising low */
+#define VS6624_HSYNC_FALL_H           0x25AC /* H sync falling high */
+#define VS6624_HSYNC_FALL_L           0x25AE /* H sync falling low */
+#define VS6624_OUT_IF                 0x25B0 /* output interface */
+#define VS6624_CCP_EXT_DATA           0x25B2 /* CCP extra data */
+/* NoRA controls */
+#define VS6624_NORA_DISABLE           0x2600 /* NoRA control mode */
+#define VS6624_NORA_USAGE             0x2602 /* usage */
+#define VS6624_NORA_SPLIT_KN          0x2604 /* split kn */
+#define VS6624_NORA_SPLIT_NI          0x2606 /* split ni */
+#define VS6624_NORA_TIGHT_G           0x2608 /* tight green */
+#define VS6624_NORA_DISABLE_NP        0x260A /* disable noro promoting */
+#define VS6624_NORA_LOW_THR_MSB       0x260D /* low threshold for exposure MSB */
+#define VS6624_NORA_LOW_THR_LSB       0x260E /* low threshold for exposure LSB */
+#define VS6624_NORA_HIGH_THR_MSB      0x2611 /* high threshold for exposure MSB */
+#define VS6624_NORA_HIGH_THR_LSB      0x2612 /* high threshold for exposure LSB */
+#define VS6624_NORA_MIN_OUT_MSB       0x2615 /* minimum damper output MSB */
+#define VS6624_NORA_MIN_OUT_LSB       0x2616 /* minimum damper output LSB */
+
+#endif
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 453dbbd..7fd7ac5 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -129,9 +129,9 @@
 MODULE_VERSION("0.33.1");
 
 #ifdef MODULE
-static const char *pardev[] = {[0 ... W9966_MAXCAMS] = ""};
+static char *pardev[] = {[0 ... W9966_MAXCAMS] = ""};
 #else
-static const char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
+static char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
 #endif
 module_param_array(pardev, charp, NULL, 0);
 MODULE_PARM_DESC(pardev, "pardev: where to search for\n"
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index a22f765..3bb99e9 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -291,15 +291,4 @@
 	.id_table	= wm8739_id,
 };
 
-static __init int init_wm8739(void)
-{
-	return i2c_add_driver(&wm8739_driver);
-}
-
-static __exit void exit_wm8739(void)
-{
-	i2c_del_driver(&wm8739_driver);
-}
-
-module_init(init_wm8739);
-module_exit(exit_wm8739);
+module_i2c_driver(wm8739_driver);
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 9cedb1e..bee77ea 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -339,15 +339,4 @@
 	.id_table	= wm8775_id,
 };
 
-static __init int init_wm8775(void)
-{
-	return i2c_add_driver(&wm8775_driver);
-}
-
-static __exit void exit_wm8775(void)
-{
-	i2c_del_driver(&wm8775_driver);
-}
-
-module_init(init_wm8775);
-module_exit(exit_wm8775);
+module_i2c_driver(wm8775_driver);
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index a7dc467..a5c591f 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -346,7 +346,7 @@
 	if ((pdev == NULL))
 		return -1;
 
-	pci_remove_bus_device(pdev);
+	pci_stop_and_remove_bus_device(pdev);
 	return 0;
 }
 
diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
index c8ed7b6..1d31d72 100644
--- a/drivers/message/i2o/i2o_scsi.c
+++ b/drivers/message/i2o/i2o_scsi.c
@@ -57,7 +57,6 @@
 #include <linux/scatterlist.h>
 
 #include <asm/dma.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <linux/atomic.h>
 
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 17dfe9b..87bd5ba 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -503,6 +503,101 @@
 		free_irq(chip->core_irq, chip);
 }
 
+int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client)
+{
+	int ret = -EIO;
+	struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
+		chip->client : chip->companion;
+
+	dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
+	dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
+			__func__, chip->osc_vote,
+			chip->osc_status);
+
+	mutex_lock(&chip->osc_lock);
+	/* Update voting status */
+	chip->osc_vote |= client;
+	/* If reference group is off - turn on*/
+	if (chip->osc_status != PM8606_REF_GP_OSC_ON) {
+		chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
+		/* Enable Reference group Vsys */
+		if (pm860x_set_bits(i2c, PM8606_VSYS,
+				PM8606_VSYS_EN, PM8606_VSYS_EN))
+			goto out;
+
+		/*Enable Internal Oscillator */
+		if (pm860x_set_bits(i2c, PM8606_MISC,
+				PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN))
+			goto out;
+		/* Update status (only if writes succeed) */
+		chip->osc_status = PM8606_REF_GP_OSC_ON;
+	}
+	mutex_unlock(&chip->osc_lock);
+
+	dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
+			__func__, chip->osc_vote,
+			chip->osc_status, ret);
+	return 0;
+out:
+	mutex_unlock(&chip->osc_lock);
+	return ret;
+}
+EXPORT_SYMBOL(pm8606_osc_enable);
+
+int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client)
+{
+	int ret = -EIO;
+	struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
+		chip->client : chip->companion;
+
+	dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
+	dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
+			__func__, chip->osc_vote,
+			chip->osc_status);
+
+	mutex_lock(&chip->osc_lock);
+	/*Update voting status */
+	chip->osc_vote &= ~(client);
+	/* If reference group is off and this is the last client to release
+	 * - turn off */
+	if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) &&
+			(chip->osc_vote == REF_GP_NO_CLIENTS)) {
+		chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
+		/* Disable Reference group Vsys */
+		if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0))
+			goto out;
+		/* Disable Internal Oscillator */
+		if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0))
+			goto out;
+		chip->osc_status = PM8606_REF_GP_OSC_OFF;
+	}
+	mutex_unlock(&chip->osc_lock);
+
+	dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
+			__func__, chip->osc_vote,
+			chip->osc_status, ret);
+	return 0;
+out:
+	mutex_unlock(&chip->osc_lock);
+	return ret;
+}
+EXPORT_SYMBOL(pm8606_osc_disable);
+
+static void __devinit device_osc_init(struct i2c_client *i2c)
+{
+	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+
+	mutex_init(&chip->osc_lock);
+	/* init portofino reference group voting and status */
+	/* Disable Reference group Vsys */
+	pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0);
+	/* Disable Internal Oscillator */
+	pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0);
+
+	chip->osc_vote = REF_GP_NO_CLIENTS;
+	chip->osc_status = PM8606_REF_GP_OSC_OFF;
+}
+
 static void __devinit device_bk_init(struct pm860x_chip *chip,
 				     struct pm860x_platform_data *pdata)
 {
@@ -767,6 +862,15 @@
 	return;
 }
 
+static void __devinit device_8606_init(struct pm860x_chip *chip,
+				       struct i2c_client *i2c,
+				       struct pm860x_platform_data *pdata)
+{
+	device_osc_init(i2c);
+	device_bk_init(chip, pdata);
+	device_led_init(chip, pdata);
+}
+
 int __devinit pm860x_device_init(struct pm860x_chip *chip,
 		       struct pm860x_platform_data *pdata)
 {
@@ -774,8 +878,7 @@
 
 	switch (chip->id) {
 	case CHIP_PM8606:
-		device_bk_init(chip, pdata);
-		device_led_init(chip, pdata);
+		device_8606_init(chip, chip->client, pdata);
 		break;
 	case CHIP_PM8607:
 		device_8607_init(chip, chip->client, pdata);
@@ -785,8 +888,7 @@
 	if (chip->companion) {
 		switch (chip->id) {
 		case CHIP_PM8607:
-			device_bk_init(chip, pdata);
-			device_led_init(chip, pdata);
+			device_8606_init(chip, chip->companion, pdata);
 			break;
 		case CHIP_PM8606:
 			device_8607_init(chip, chip->companion, pdata);
diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c
index f93dd95..b2cfdc4 100644
--- a/drivers/mfd/88pm860x-i2c.c
+++ b/drivers/mfd/88pm860x-i2c.c
@@ -334,10 +334,35 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_suspend(struct device *dev)
+{
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+	struct pm860x_chip *chip = i2c_get_clientdata(client);
+
+	if (device_may_wakeup(dev) && chip->wakeup_flag)
+		enable_irq_wake(chip->core_irq);
+	return 0;
+}
+
+static int pm860x_resume(struct device *dev)
+{
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+	struct pm860x_chip *chip = i2c_get_clientdata(client);
+
+	if (device_may_wakeup(dev) && chip->wakeup_flag)
+		disable_irq_wake(chip->core_irq);
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume);
+
 static struct i2c_driver pm860x_driver = {
 	.driver	= {
 		.name	= "88PM860x",
 		.owner	= THIS_MODULE,
+		.pm     = &pm860x_pm_ops,
 	},
 	.probe		= pm860x_probe,
 	.remove		= __devexit_p(pm860x_remove),
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 1489c35..29f463c 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -143,6 +143,21 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called tps6507x.
 
+config MFD_TPS65217
+	tristate "TPS65217 Power Management / White LED chips"
+	depends on I2C
+	select MFD_CORE
+	select REGMAP_I2C
+	help
+	  If you say yes here you get support for the TPS65217 series of
+	  Power Management / White LED chips.
+	  These include voltage regulators, lithium ion/polymer battery
+	  charger, wled and other features that are often used in portable
+	  devices.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called tps65217.
+
 config MFD_TPS6586X
 	bool "TPS6586x Power Management chips"
 	depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
@@ -162,6 +177,7 @@
 	depends on I2C=y && GPIOLIB
 	select MFD_CORE
 	select GPIO_TPS65910
+	select REGMAP_I2C
 	help
 	  if you say yes here you get support for the TPS65910 series of
 	  Power Management chips.
@@ -171,7 +187,7 @@
 	depends on GPIOLIB
 
 config MFD_TPS65912_I2C
-	bool "TPS95612 Power Management chip with I2C"
+	bool "TPS65912 Power Management chip with I2C"
 	select MFD_CORE
 	select MFD_TPS65912
 	depends on I2C=y && GPIOLIB
@@ -400,7 +416,7 @@
 	depends on I2C=y && GENERIC_HARDIRQS
 	select MFD_CORE
 	help
-	  Say yes here to support for Maxim Semiconductor MAX8998/8966.
+	  Say yes here to support for Maxim Semiconductor MAX8997/8966.
 	  This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic,
 	  MUIC controls on chip.
 	  This driver provides common support for accessing the device;
@@ -812,6 +828,18 @@
 config TPS65911_COMPARATOR
 	tristate
 
+config MFD_TPS65090
+	bool "TPS65090 Power Management chips"
+	depends on I2C=y && GENERIC_HARDIRQS
+	select MFD_CORE
+	select REGMAP_I2C
+	help
+	  If you say yes here you get support for the TPS65090 series of
+	  Power Management chips.
+	  This driver provides common support for accessing the device,
+	  additional drivers must be enabled in order to use the
+	  functionality of the device.
+
 config MFD_AAT2870_CORE
 	bool "Support for the AnalogicTech AAT2870"
 	select MFD_CORE
@@ -831,6 +859,28 @@
 	  Passage) chip. This chip embeds audio, battery, GPIO, etc.
 	  devices used in Intel Medfield platforms.
 
+config MFD_RC5T583
+	bool "Ricoh RC5T583 Power Management system device"
+	depends on I2C=y && GENERIC_HARDIRQS
+	select MFD_CORE
+	select REGMAP_I2C
+	help
+	  Select this option to get support for the RICOH583 Power
+	  Management system device.
+	  This driver provides common support for accessing the device
+	  through i2c interface. The device supports multiple sub-devices
+	  like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey.
+	  Additional drivers must be enabled in order to use the
+	  different functionality of the device.
+
+config MFD_ANATOP
+	bool "Support for Freescale i.MX on-chip ANATOP controller"
+	depends on SOC_IMX6Q
+	help
+	  Select this option to enable Freescale i.MX on-chip ANATOP
+	  MFD controller. This controller embeds regulator and
+	  thermal devices for Freescale i.MX platforms.
+
 endmenu
 endif
 
@@ -848,8 +898,9 @@
 
 # Chip drivers
 config MCP_UCB1200
-	tristate "Support for UCB1200 / UCB1300"
-	depends on MCP
+	bool "Support for UCB1200 / UCB1300"
+	depends on MCP_SA11X0
+	select MCP
 
 config MCP_UCB1200_TS
 	tristate "Touchscreen interface support"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index b953bab..05fa538 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -38,6 +38,7 @@
 obj-$(CONFIG_TPS6105X)		+= tps6105x.o
 obj-$(CONFIG_TPS65010)		+= tps65010.o
 obj-$(CONFIG_TPS6507X)		+= tps6507x.o
+obj-$(CONFIG_MFD_TPS65217)	+= tps65217.o
 obj-$(CONFIG_MFD_TPS65910)	+= tps65910.o tps65910-irq.o
 tps65912-objs                   := tps65912-core.o tps65912-irq.o
 obj-$(CONFIG_MFD_TPS65912)	+= tps65912.o
@@ -109,6 +110,9 @@
 obj-$(CONFIG_MFD_PM8921_CORE) 	+= pm8921-core.o
 obj-$(CONFIG_MFD_PM8XXX_IRQ) 	+= pm8xxx-irq.o
 obj-$(CONFIG_TPS65911_COMPARATOR)	+= tps65911-comparator.o
+obj-$(CONFIG_MFD_TPS65090)	+= tps65090.o
 obj-$(CONFIG_MFD_AAT2870_CORE)	+= aat2870-core.o
 obj-$(CONFIG_MFD_INTEL_MSIC)	+= intel_msic.o
+obj-$(CONFIG_MFD_RC5T583)	+= rc5t583.o rc5t583-irq.o
 obj-$(CONFIG_MFD_S5M_CORE)	+= s5m-core.o s5m-irq.o
+obj-$(CONFIG_MFD_ANATOP)	+= anatop-mfd.o
diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c
index 3aa36eb..44a3fdb 100644
--- a/drivers/mfd/aat2870-core.c
+++ b/drivers/mfd/aat2870-core.c
@@ -262,13 +262,6 @@
 	return count;
 }
 
-static int aat2870_reg_open_file(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-
-	return 0;
-}
-
 static ssize_t aat2870_reg_read_file(struct file *file, char __user *user_buf,
 				     size_t count, loff_t *ppos)
 {
@@ -330,7 +323,7 @@
 }
 
 static const struct file_operations aat2870_reg_fops = {
-	.open = aat2870_reg_open_file,
+	.open = simple_open,
 	.read = aat2870_reg_read_file,
 	.write = aat2870_reg_write_file,
 };
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c
index 60107ee..1efad20 100644
--- a/drivers/mfd/ab3100-core.c
+++ b/drivers/mfd/ab3100-core.c
@@ -483,12 +483,6 @@
 	bool mode;
 };
 
-static int ab3100_get_set_reg_open_file(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t ab3100_get_set_reg(struct file *file,
 				  const char __user *user_buf,
 				  size_t count, loff_t *ppos)
@@ -583,7 +577,7 @@
 }
 
 static const struct file_operations ab3100_get_set_reg_fops = {
-	.open = ab3100_get_set_reg_open_file,
+	.open = simple_open,
 	.write = ab3100_get_set_reg,
 	.llseek = noop_llseek,
 };
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index d295941..1f08704 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -32,6 +32,7 @@
 #define AB8500_IT_SOURCE6_REG		0x05
 #define AB8500_IT_SOURCE7_REG		0x06
 #define AB8500_IT_SOURCE8_REG		0x07
+#define AB9540_IT_SOURCE13_REG		0x0C
 #define AB8500_IT_SOURCE19_REG		0x12
 #define AB8500_IT_SOURCE20_REG		0x13
 #define AB8500_IT_SOURCE21_REG		0x14
@@ -53,6 +54,7 @@
 #define AB8500_IT_LATCH9_REG		0x28
 #define AB8500_IT_LATCH10_REG		0x29
 #define AB8500_IT_LATCH12_REG		0x2B
+#define AB9540_IT_LATCH13_REG		0x2C
 #define AB8500_IT_LATCH19_REG		0x32
 #define AB8500_IT_LATCH20_REG		0x33
 #define AB8500_IT_LATCH21_REG		0x34
@@ -90,21 +92,39 @@
 #define AB8500_IT_MASK24_REG		0x57
 
 #define AB8500_REV_REG			0x80
+#define AB8500_IC_NAME_REG		0x82
 #define AB8500_SWITCH_OFF_STATUS	0x00
 
 #define AB8500_TURN_ON_STATUS		0x00
 
+#define AB9540_MODEM_CTRL2_REG			0x23
+#define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT	BIT(2)
+
 /*
  * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
- * numbers are indexed into this array with (num / 8).
+ * numbers are indexed into this array with (num / 8). The interupts are
+ * defined in linux/mfd/ab8500.h
  *
  * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
  * offset 0.
  */
+/* AB8500 support */
 static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
 };
 
+/* AB9540 support */
+static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
+	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24,
+};
+
+static const char ab8500_version_str[][7] = {
+	[AB8500_VERSION_AB8500] = "AB8500",
+	[AB8500_VERSION_AB8505] = "AB8505",
+	[AB8500_VERSION_AB9540] = "AB9540",
+	[AB8500_VERSION_AB8540] = "AB8540",
+};
+
 static int ab8500_get_chip_id(struct device *dev)
 {
 	struct ab8500 *ab8500;
@@ -127,9 +147,7 @@
 
 	dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
 
-	ret = mutex_lock_interruptible(&ab8500->lock);
-	if (ret)
-		return ret;
+	mutex_lock(&ab8500->lock);
 
 	ret = ab8500->write(ab8500, addr, data);
 	if (ret < 0)
@@ -156,9 +174,7 @@
 	 * bank on higher 8 bits and reg in lower */
 	u16 addr = ((u16)bank) << 8 | reg;
 
-	ret = mutex_lock_interruptible(&ab8500->lock);
-	if (ret)
-		return ret;
+	mutex_lock(&ab8500->lock);
 
 	ret = ab8500->read(ab8500, addr);
 	if (ret < 0)
@@ -185,31 +201,38 @@
 	u8 reg, u8 bitmask, u8 bitvalues)
 {
 	int ret;
-	u8 data;
 	/* put the u8 bank and u8 reg together into a an u16.
 	 * bank on higher 8 bits and reg in lower */
 	u16 addr = ((u16)bank) << 8 | reg;
 
-	ret = mutex_lock_interruptible(&ab8500->lock);
-	if (ret)
-		return ret;
+	mutex_lock(&ab8500->lock);
 
-	ret = ab8500->read(ab8500, addr);
-	if (ret < 0) {
-		dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
-			addr, ret);
+	if (ab8500->write_masked == NULL) {
+		u8 data;
+
+		ret = ab8500->read(ab8500, addr);
+		if (ret < 0) {
+			dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
+				addr, ret);
+			goto out;
+		}
+
+		data = (u8)ret;
+		data = (~bitmask & data) | (bitmask & bitvalues);
+
+		ret = ab8500->write(ab8500, addr, data);
+		if (ret < 0)
+			dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
+				addr, ret);
+
+		dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr,
+			data);
 		goto out;
 	}
-
-	data = (u8)ret;
-	data = (~bitmask & data) | (bitmask & bitvalues);
-
-	ret = ab8500->write(ab8500, addr, data);
+	ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues);
 	if (ret < 0)
-		dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
-			addr, ret);
-
-	dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, data);
+		dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr,
+			ret);
 out:
 	mutex_unlock(&ab8500->lock);
 	return ret;
@@ -248,7 +271,7 @@
 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
 	int i;
 
-	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
+	for (i = 0; i < ab8500->mask_size; i++) {
 		u8 old = ab8500->oldmask[i];
 		u8 new = ab8500->mask[i];
 		int reg;
@@ -256,14 +279,17 @@
 		if (new == old)
 			continue;
 
-		/* Interrupt register 12 doesn't exist prior to version 2.0 */
-		if (ab8500_irq_regoffset[i] == 11 &&
-			ab8500->chip_id < AB8500_CUT2P0)
+		/*
+		 * Interrupt register 12 doesn't exist prior to AB8500 version
+		 * 2.0
+		 */
+		if (ab8500->irq_reg_offset[i] == 11 &&
+			is_ab8500_1p1_or_earlier(ab8500))
 			continue;
 
 		ab8500->oldmask[i] = new;
 
-		reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
+		reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
 		set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
 	}
 
@@ -306,13 +332,16 @@
 
 	dev_vdbg(ab8500->dev, "interrupt\n");
 
-	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
-		int regoffset = ab8500_irq_regoffset[i];
+	for (i = 0; i < ab8500->mask_size; i++) {
+		int regoffset = ab8500->irq_reg_offset[i];
 		int status;
 		u8 value;
 
-		/* Interrupt register 12 doesn't exist prior to version 2.0 */
-		if (regoffset == 11 && ab8500->chip_id < AB8500_CUT2P0)
+		/*
+		 * Interrupt register 12 doesn't exist prior to AB8500 version
+		 * 2.0
+		 */
+		if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500))
 			continue;
 
 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
@@ -336,8 +365,16 @@
 {
 	int base = ab8500->irq_base;
 	int irq;
+	int num_irqs;
 
-	for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
+	if (is_ab9540(ab8500))
+		num_irqs = AB9540_NR_IRQS;
+	else if (is_ab8505(ab8500))
+		num_irqs = AB8505_NR_IRQS;
+	else
+		num_irqs = AB8500_NR_IRQS;
+
+	for (irq = base; irq < base + num_irqs; irq++) {
 		irq_set_chip_data(irq, ab8500);
 		irq_set_chip_and_handler(irq, &ab8500_irq_chip,
 					 handle_simple_irq);
@@ -356,8 +393,16 @@
 {
 	int base = ab8500->irq_base;
 	int irq;
+	int num_irqs;
 
-	for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
+	if (is_ab9540(ab8500))
+		num_irqs = AB9540_NR_IRQS;
+	else if (is_ab8505(ab8500))
+		num_irqs = AB8505_NR_IRQS;
+	else
+		num_irqs = AB8500_NR_IRQS;
+
+	for (irq = base; irq < base + num_irqs; irq++) {
 #ifdef CONFIG_ARM
 		set_irq_flags(irq, 0);
 #endif
@@ -366,6 +411,7 @@
 	}
 }
 
+/* AB8500 GPIO Resources */
 static struct resource __devinitdata ab8500_gpio_resources[] = {
 	{
 		.name	= "GPIO_INT6",
@@ -375,6 +421,28 @@
 	}
 };
 
+/* AB9540 GPIO Resources */
+static struct resource __devinitdata ab9540_gpio_resources[] = {
+	{
+		.name	= "GPIO_INT6",
+		.start	= AB8500_INT_GPIO6R,
+		.end	= AB8500_INT_GPIO41F,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "GPIO_INT14",
+		.start	= AB9540_INT_GPIO50R,
+		.end	= AB9540_INT_GPIO54R,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "GPIO_INT15",
+		.start	= AB9540_INT_GPIO50F,
+		.end	= AB9540_INT_GPIO54F,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
 static struct resource __devinitdata ab8500_gpadc_resources[] = {
 	{
 		.name	= "HW_CONV_END",
@@ -491,12 +559,6 @@
 		.flags = IORESOURCE_IRQ,
 	},
 	{
-		.name = "USB_CHARGE_DET_DONE",
-		.start = AB8500_INT_USB_CHG_DET_DONE,
-		.end = AB8500_INT_USB_CHG_DET_DONE,
-		.flags = IORESOURCE_IRQ,
-	},
-	{
 		.name = "VBUS_OVV",
 		.start = AB8500_INT_VBUS_OVV,
 		.end = AB8500_INT_VBUS_OVV,
@@ -534,14 +596,8 @@
 	},
 	{
 		.name = "USB_CHARGER_NOT_OKR",
-		.start = AB8500_INT_USB_CHARGER_NOT_OK,
-		.end = AB8500_INT_USB_CHARGER_NOT_OK,
-		.flags = IORESOURCE_IRQ,
-	},
-	{
-		.name = "USB_CHARGER_NOT_OKF",
-		.start = AB8500_INT_USB_CHARGER_NOT_OKF,
-		.end = AB8500_INT_USB_CHARGER_NOT_OKF,
+		.start = AB8500_INT_USB_CHARGER_NOT_OKR,
+		.end = AB8500_INT_USB_CHARGER_NOT_OKR,
 		.flags = IORESOURCE_IRQ,
 	},
 	{
@@ -616,6 +672,12 @@
 		.end = AB8500_INT_CC_INT_CALIB,
 		.flags = IORESOURCE_IRQ,
 	},
+	{
+		.name = "CCEOC",
+		.start = AB8500_INT_CCEOC,
+		.end = AB8500_INT_CCEOC,
+		.flags = IORESOURCE_IRQ,
+	},
 };
 
 static struct resource __devinitdata ab8500_chargalg_resources[] = {};
@@ -630,8 +692,8 @@
 	},
 	{
 		.name	= "IRQ_LAST",
-		.start	= AB8500_INT_USB_CHARGER_NOT_OKF,
-		.end	= AB8500_INT_USB_CHARGER_NOT_OKF,
+		.start	= AB8500_INT_XTAL32K_KO,
+		.end	= AB8500_INT_XTAL32K_KO,
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -691,7 +753,7 @@
 	},
 };
 
-static struct mfd_cell __devinitdata ab8500_devs[] = {
+static struct mfd_cell __devinitdata abx500_common_devs[] = {
 #ifdef CONFIG_DEBUG_FS
 	{
 		.name = "ab8500-debug",
@@ -706,11 +768,6 @@
 		.name = "ab8500-regulator",
 	},
 	{
-		.name = "ab8500-gpio",
-		.num_resources = ARRAY_SIZE(ab8500_gpio_resources),
-		.resources = ab8500_gpio_resources,
-	},
-	{
 		.name = "ab8500-gpadc",
 		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
 		.resources = ab8500_gpadc_resources,
@@ -748,11 +805,7 @@
 	{
 		.name = "ab8500-codec",
 	},
-	{
-		.name = "ab8500-usb",
-		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
-		.resources = ab8500_usb_resources,
-	},
+
 	{
 		.name = "ab8500-poweron-key",
 		.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
@@ -781,6 +834,32 @@
 	},
 };
 
+static struct mfd_cell __devinitdata ab8500_devs[] = {
+	{
+		.name = "ab8500-gpio",
+		.num_resources = ARRAY_SIZE(ab8500_gpio_resources),
+		.resources = ab8500_gpio_resources,
+	},
+	{
+		.name = "ab8500-usb",
+		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
+		.resources = ab8500_usb_resources,
+	},
+};
+
+static struct mfd_cell __devinitdata ab9540_devs[] = {
+	{
+		.name = "ab8500-gpio",
+		.num_resources = ARRAY_SIZE(ab9540_gpio_resources),
+		.resources = ab9540_gpio_resources,
+	},
+	{
+		.name = "ab9540-usb",
+		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
+		.resources = ab8500_usb_resources,
+	},
+};
+
 static ssize_t show_chip_id(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
@@ -842,9 +921,64 @@
 	return sprintf(buf, "%#x\n", value);
 }
 
+static ssize_t show_ab9540_dbbrstn(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct ab8500 *ab8500;
+	int ret;
+	u8 value;
+
+	ab8500 = dev_get_drvdata(dev);
+
+	ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2,
+		AB9540_MODEM_CTRL2_REG, &value);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n",
+			(value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
+}
+
+static ssize_t store_ab9540_dbbrstn(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct ab8500 *ab8500;
+	int ret = count;
+	int err;
+	u8 bitvalues;
+
+	ab8500 = dev_get_drvdata(dev);
+
+	if (count > 0) {
+		switch (buf[0]) {
+		case '0':
+			bitvalues = 0;
+			break;
+		case '1':
+			bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT;
+			break;
+		default:
+			goto exit;
+		}
+
+		err = mask_and_set_register_interruptible(ab8500,
+			AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG,
+			AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues);
+		if (err)
+			dev_info(ab8500->dev,
+				"Failed to set DBBRSTN %c, err %#x\n",
+				buf[0], err);
+	}
+
+exit:
+	return ret;
+}
+
 static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
 static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
 static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
+static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
+			show_ab9540_dbbrstn, store_ab9540_dbbrstn);
 
 static struct attribute *ab8500_sysfs_entries[] = {
 	&dev_attr_chip_id.attr,
@@ -853,11 +987,23 @@
 	NULL,
 };
 
+static struct attribute *ab9540_sysfs_entries[] = {
+	&dev_attr_chip_id.attr,
+	&dev_attr_switch_off_status.attr,
+	&dev_attr_turn_on_status.attr,
+	&dev_attr_dbbrstn.attr,
+	NULL,
+};
+
 static struct attribute_group ab8500_attr_group = {
 	.attrs	= ab8500_sysfs_entries,
 };
 
-int __devinit ab8500_init(struct ab8500 *ab8500)
+static struct attribute_group ab9540_attr_group = {
+	.attrs	= ab9540_sysfs_entries,
+};
+
+int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
 {
 	struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
 	int ret;
@@ -870,25 +1016,45 @@
 	mutex_init(&ab8500->lock);
 	mutex_init(&ab8500->irq_lock);
 
+	if (version != AB8500_VERSION_UNDEFINED)
+		ab8500->version = version;
+	else {
+		ret = get_register_interruptible(ab8500, AB8500_MISC,
+			AB8500_IC_NAME_REG, &value);
+		if (ret < 0)
+			return ret;
+
+		ab8500->version = value;
+	}
+
 	ret = get_register_interruptible(ab8500, AB8500_MISC,
 		AB8500_REV_REG, &value);
 	if (ret < 0)
 		return ret;
 
-	switch (value) {
-	case AB8500_CUT1P0:
-	case AB8500_CUT1P1:
-	case AB8500_CUT2P0:
-	case AB8500_CUT3P0:
-	case AB8500_CUT3P3:
-		dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
-		break;
-	default:
-		dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
-		return -EINVAL;
-	}
 	ab8500->chip_id = value;
 
+	dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n",
+			ab8500_version_str[ab8500->version],
+			ab8500->chip_id >> 4,
+			ab8500->chip_id & 0x0F);
+
+	/* Configure AB8500 or AB9540 IRQ */
+	if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
+		ab8500->mask_size = AB9540_NUM_IRQ_REGS;
+		ab8500->irq_reg_offset = ab9540_irq_regoffset;
+	} else {
+		ab8500->mask_size = AB8500_NUM_IRQ_REGS;
+		ab8500->irq_reg_offset = ab8500_irq_regoffset;
+	}
+	ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL);
+	if (!ab8500->mask)
+		return -ENOMEM;
+	ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL);
+	if (!ab8500->oldmask) {
+		ret = -ENOMEM;
+		goto out_freemask;
+	}
 	/*
 	 * ab8500 has switched off due to (SWITCH_OFF_STATUS):
 	 * 0x01 Swoff bit programming
@@ -911,30 +1077,33 @@
 		plat->init(ab8500);
 
 	/* Clear and mask all interrupts */
-	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
-		/* Interrupt register 12 doesn't exist prior to version 2.0 */
-		if (ab8500_irq_regoffset[i] == 11 &&
-			ab8500->chip_id < AB8500_CUT2P0)
+	for (i = 0; i < ab8500->mask_size; i++) {
+		/*
+		 * Interrupt register 12 doesn't exist prior to AB8500 version
+		 * 2.0
+		 */
+		if (ab8500->irq_reg_offset[i] == 11 &&
+				is_ab8500_1p1_or_earlier(ab8500))
 			continue;
 
 		get_register_interruptible(ab8500, AB8500_INTERRUPT,
-			AB8500_IT_LATCH1_REG + ab8500_irq_regoffset[i],
+			AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
 			&value);
 		set_register_interruptible(ab8500, AB8500_INTERRUPT,
-			AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i], 0xff);
+			AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
 	}
 
 	ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
 	if (ret)
-		return ret;
+		goto out_freeoldmask;
 
-	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++)
+	for (i = 0; i < ab8500->mask_size; i++)
 		ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
 
 	if (ab8500->irq_base) {
 		ret = ab8500_irq_init(ab8500);
 		if (ret)
-			return ret;
+			goto out_freeoldmask;
 
 		ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
 					   IRQF_ONESHOT | IRQF_NO_SUSPEND,
@@ -943,17 +1112,34 @@
 			goto out_removeirq;
 	}
 
-	ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
-			      ARRAY_SIZE(ab8500_devs), NULL,
+	ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
+			      ARRAY_SIZE(abx500_common_devs), NULL,
+			      ab8500->irq_base);
+
+	if (ret)
+		goto out_freeirq;
+
+	if (is_ab9540(ab8500))
+		ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
+			      ARRAY_SIZE(ab9540_devs), NULL,
+			      ab8500->irq_base);
+	else
+		ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
+			      ARRAY_SIZE(ab9540_devs), NULL,
 			      ab8500->irq_base);
 	if (ret)
 		goto out_freeirq;
 
-	ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group);
+	if (is_ab9540(ab8500))
+		ret = sysfs_create_group(&ab8500->dev->kobj,
+					&ab9540_attr_group);
+	else
+		ret = sysfs_create_group(&ab8500->dev->kobj,
+					&ab8500_attr_group);
 	if (ret)
 		dev_err(ab8500->dev, "error creating sysfs entries\n");
-
-	return ret;
+	else
+		return ret;
 
 out_freeirq:
 	if (ab8500->irq_base)
@@ -961,18 +1147,27 @@
 out_removeirq:
 	if (ab8500->irq_base)
 		ab8500_irq_remove(ab8500);
+out_freeoldmask:
+	kfree(ab8500->oldmask);
+out_freemask:
+	kfree(ab8500->mask);
 
 	return ret;
 }
 
 int __devexit ab8500_exit(struct ab8500 *ab8500)
 {
-	sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
+	if (is_ab9540(ab8500))
+		sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
+	else
+		sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
 	mfd_remove_devices(ab8500->dev);
 	if (ab8500->irq_base) {
 		free_irq(ab8500->irq, ab8500);
 		ab8500_irq_remove(ab8500);
 	}
+	kfree(ab8500->oldmask);
+	kfree(ab8500->mask);
 
 	return 0;
 }
diff --git a/drivers/mfd/ab8500-i2c.c b/drivers/mfd/ab8500-i2c.c
index 087fecd..b83045f 100644
--- a/drivers/mfd/ab8500-i2c.c
+++ b/drivers/mfd/ab8500-i2c.c
@@ -11,7 +11,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/db8500-prcmu.h>
+#include <linux/mfd/dbx500-prcmu.h>
 
 static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
 {
@@ -23,6 +23,18 @@
 	return ret;
 }
 
+static int ab8500_i2c_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
+	u8 data)
+{
+	int ret;
+
+	ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
+		&mask, 1);
+	if (ret < 0)
+		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
+	return ret;
+}
+
 static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
 {
 	int ret;
@@ -38,6 +50,7 @@
 
 static int __devinit ab8500_i2c_probe(struct platform_device *plf)
 {
+	const struct platform_device_id *platid = platform_get_device_id(plf);
 	struct ab8500 *ab8500;
 	struct resource *resource;
 	int ret;
@@ -58,13 +71,15 @@
 
 	ab8500->read = ab8500_i2c_read;
 	ab8500->write = ab8500_i2c_write;
+	ab8500->write_masked = ab8500_i2c_write_masked;
 
 	platform_set_drvdata(plf, ab8500);
 
-	ret = ab8500_init(ab8500);
+	ret = ab8500_init(ab8500, platid->driver_data);
 	if (ret)
 		kfree(ab8500);
 
+
 	return ret;
 }
 
@@ -78,13 +93,22 @@
 	return 0;
 }
 
+static const struct platform_device_id ab8500_id[] = {
+	{ "ab8500-i2c", AB8500_VERSION_AB8500 },
+	{ "ab8505-i2c", AB8500_VERSION_AB8505 },
+	{ "ab9540-i2c", AB8500_VERSION_AB9540 },
+	{ "ab8540-i2c", AB8500_VERSION_AB8540 },
+	{ }
+};
+
 static struct platform_driver ab8500_i2c_driver = {
 	.driver = {
 		.name = "ab8500-i2c",
 		.owner = THIS_MODULE,
 	},
 	.probe	= ab8500_i2c_probe,
-	.remove	= __devexit_p(ab8500_i2c_remove)
+	.remove	= __devexit_p(ab8500_i2c_remove),
+	.id_table = ab8500_id,
 };
 
 static int __init ab8500_i2c_init(void)
diff --git a/drivers/mfd/anatop-mfd.c b/drivers/mfd/anatop-mfd.c
new file mode 100644
index 0000000..2af4248
--- /dev/null
+++ b/drivers/mfd/anatop-mfd.c
@@ -0,0 +1,137 @@
+/*
+ * Anatop MFD driver
+ *
+ * Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ * Copyright (C) 2012 Linaro
+ *
+ *  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 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.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/mfd/anatop.h>
+
+u32 anatop_get_bits(struct anatop *adata, u32 addr, int bit_shift,
+		    int bit_width)
+{
+	u32 val, mask;
+
+	if (bit_width == 32)
+		mask = ~0;
+	else
+		mask = (1 << bit_width) - 1;
+
+	val = readl(adata->ioreg + addr);
+	val = (val >> bit_shift) & mask;
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(anatop_get_bits);
+
+void anatop_set_bits(struct anatop *adata, u32 addr, int bit_shift,
+		     int bit_width, u32 data)
+{
+	u32 val, mask;
+
+	if (bit_width == 32)
+		mask = ~0;
+	else
+		mask = (1 << bit_width) - 1;
+
+	spin_lock(&adata->reglock);
+	val = readl(adata->ioreg + addr) & ~(mask << bit_shift);
+	writel((data << bit_shift) | val, adata->ioreg + addr);
+	spin_unlock(&adata->reglock);
+}
+EXPORT_SYMBOL_GPL(anatop_set_bits);
+
+static const struct of_device_id of_anatop_match[] = {
+	{ .compatible = "fsl,imx6q-anatop", },
+	{ },
+};
+
+static int __devinit of_anatop_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	void *ioreg;
+	struct anatop *drvdata;
+
+	ioreg = of_iomap(np, 0);
+	if (!ioreg)
+		return -EADDRNOTAVAIL;
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->ioreg = ioreg;
+	spin_lock_init(&drvdata->reglock);
+	platform_set_drvdata(pdev, drvdata);
+	of_platform_populate(np, of_anatop_match, NULL, dev);
+
+	return 0;
+}
+
+static int __devexit of_anatop_remove(struct platform_device *pdev)
+{
+	struct anatop *drvdata;
+	drvdata = platform_get_drvdata(pdev);
+	iounmap(drvdata->ioreg);
+
+	return 0;
+}
+
+static struct platform_driver anatop_of_driver = {
+	.driver = {
+		.name = "anatop-mfd",
+		.owner = THIS_MODULE,
+		.of_match_table = of_anatop_match,
+	},
+	.probe		= of_anatop_probe,
+	.remove		= of_anatop_remove,
+};
+
+static int __init anatop_init(void)
+{
+	return platform_driver_register(&anatop_of_driver);
+}
+postcore_initcall(anatop_init);
+
+static void __exit anatop_exit(void)
+{
+	platform_driver_unregister(&anatop_of_driver);
+}
+module_exit(anatop_exit);
+
+MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>");
+MODULE_DESCRIPTION("ANATOP MFD driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index b85bbd7..1895cf9 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -525,6 +525,11 @@
 	return;
 }
 
+static int asic3_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	return (offset < ASIC3_NUM_GPIOS) ? IRQ_BOARD_START + offset : -ENXIO;
+}
+
 static __init int asic3_gpio_probe(struct platform_device *pdev,
 				   u16 *gpio_config, int num)
 {
@@ -976,6 +981,7 @@
 	asic->gpio.set = asic3_gpio_set;
 	asic->gpio.direction_input = asic3_gpio_direction_input;
 	asic->gpio.direction_output = asic3_gpio_direction_output;
+	asic->gpio.to_irq = asic3_gpio_to_irq;
 
 	ret = asic3_gpio_probe(pdev,
 			       pdata->gpio_config,
diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c
index 5ddde2a..7ff313f 100644
--- a/drivers/mfd/da9052-core.c
+++ b/drivers/mfd/da9052-core.c
@@ -16,7 +16,6 @@
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
-#include <linux/mutex.h>
 #include <linux/mfd/core.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -647,8 +646,6 @@
 	struct irq_desc *desc;
 	int ret;
 
-	mutex_init(&da9052->io_lock);
-
 	if (pdata && pdata->init != NULL)
 		pdata->init(da9052);
 
diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c
index 44b97c7..36b88e3 100644
--- a/drivers/mfd/da9052-i2c.c
+++ b/drivers/mfd/da9052-i2c.c
@@ -74,24 +74,27 @@
 
 	ret = da9052_i2c_enable_multiwrite(da9052);
 	if (ret < 0)
-		goto err;
+		goto err_regmap;
 
 	ret = da9052_device_init(da9052, id->driver_data);
 	if (ret != 0)
-		goto err;
+		goto err_regmap;
 
 	return 0;
 
+err_regmap:
+	regmap_exit(da9052->regmap);
 err:
 	kfree(da9052);
 	return ret;
 }
 
-static int da9052_i2c_remove(struct i2c_client *client)
+static int __devexit da9052_i2c_remove(struct i2c_client *client)
 {
 	struct da9052 *da9052 = i2c_get_clientdata(client);
 
 	da9052_device_exit(da9052);
+	regmap_exit(da9052->regmap);
 	kfree(da9052);
 
 	return 0;
@@ -107,7 +110,7 @@
 
 static struct i2c_driver da9052_i2c_driver = {
 	.probe = da9052_i2c_probe,
-	.remove = da9052_i2c_remove,
+	.remove = __devexit_p(da9052_i2c_remove),
 	.id_table = da9052_i2c_id,
 	.driver = {
 		.name = "da9052",
diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c
index cdbc7ca..6faf149 100644
--- a/drivers/mfd/da9052-spi.c
+++ b/drivers/mfd/da9052-spi.c
@@ -21,7 +21,7 @@
 
 #include <linux/mfd/da9052/da9052.h>
 
-static int da9052_spi_probe(struct spi_device *spi)
+static int __devinit da9052_spi_probe(struct spi_device *spi)
 {
 	int ret;
 	const struct spi_device_id *id = spi_get_device_id(spi);
@@ -52,20 +52,23 @@
 
 	ret = da9052_device_init(da9052, id->driver_data);
 	if (ret != 0)
-		goto err;
+		goto err_regmap;
 
 	return 0;
 
+err_regmap:
+	regmap_exit(da9052->regmap);
 err:
 	kfree(da9052);
 	return ret;
 }
 
-static int da9052_spi_remove(struct spi_device *spi)
+static int __devexit da9052_spi_remove(struct spi_device *spi)
 {
 	struct da9052 *da9052 = dev_get_drvdata(&spi->dev);
 
 	da9052_device_exit(da9052);
+	regmap_exit(da9052->regmap);
 	kfree(da9052);
 
 	return 0;
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index af8e0ef..ebc1e86 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -30,6 +30,7 @@
 #include <linux/mfd/dbx500-prcmu.h>
 #include <linux/regulator/db8500-prcmu.h>
 #include <linux/regulator/machine.h>
+#include <asm/hardware/gic.h>
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/db8500-regs.h>
@@ -39,11 +40,6 @@
 /* Offset for the firmware version within the TCPM */
 #define PRCMU_FW_VERSION_OFFSET 0xA4
 
-/* PRCMU project numbers, defined by PRCMU FW */
-#define PRCMU_PROJECT_ID_8500V1_0 1
-#define PRCMU_PROJECT_ID_8500V2_0 2
-#define PRCMU_PROJECT_ID_8400V2_0 3
-
 /* Index of different voltages to be used when accessing AVSData */
 #define PRCM_AVS_BASE		0x2FC
 #define PRCM_AVS_VBB_RET	(PRCM_AVS_BASE + 0x0)
@@ -137,6 +133,8 @@
 #define PRCM_REQ_MB1_ARM_OPP			(PRCM_REQ_MB1 + 0x0)
 #define PRCM_REQ_MB1_APE_OPP			(PRCM_REQ_MB1 + 0x1)
 #define PRCM_REQ_MB1_PLL_ON_OFF			(PRCM_REQ_MB1 + 0x4)
+#define PLL_SOC0_OFF	0x1
+#define PLL_SOC0_ON	0x2
 #define PLL_SOC1_OFF	0x4
 #define PLL_SOC1_ON	0x8
 
@@ -266,6 +264,11 @@
 #define WAKEUP_BIT_GPIO7 BIT(30)
 #define WAKEUP_BIT_GPIO8 BIT(31)
 
+static struct {
+	bool valid;
+	struct prcmu_fw_version version;
+} fw_info;
+
 /*
  * This vector maps irq numbers to the bits in the bit field used in
  * communication with the PRCMU firmware.
@@ -341,11 +344,13 @@
  * mb1_transfer - state needed for mailbox 1 communication.
  * @lock:	The transaction lock.
  * @work:	The transaction completion structure.
+ * @ape_opp:	The current APE OPP.
  * @ack:	Reply ("acknowledge") data.
  */
 static struct {
 	struct mutex lock;
 	struct completion work;
+	u8 ape_opp;
 	struct {
 		u8 header;
 		u8 arm_opp;
@@ -413,79 +418,102 @@
 static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
 
 /* Spinlocks */
+static DEFINE_SPINLOCK(prcmu_lock);
 static DEFINE_SPINLOCK(clkout_lock);
-static DEFINE_SPINLOCK(gpiocr_lock);
 
 /* Global var to runtime determine TCDM base for v2 or v1 */
 static __iomem void *tcdm_base;
 
 struct clk_mgt {
-	unsigned int offset;
+	void __iomem *reg;
 	u32 pllsw;
+	int branch;
+	bool clk38div;
+};
+
+enum {
+	PLL_RAW,
+	PLL_FIX,
+	PLL_DIV
 };
 
 static DEFINE_SPINLOCK(clk_mgt_lock);
 
-#define CLK_MGT_ENTRY(_name)[PRCMU_##_name] = { (PRCM_##_name##_MGT_OFF), 0 }
+#define CLK_MGT_ENTRY(_name, _branch, _clk38div)[PRCMU_##_name] = \
+	{ (PRCM_##_name##_MGT), 0 , _branch, _clk38div}
 struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
-	CLK_MGT_ENTRY(SGACLK),
-	CLK_MGT_ENTRY(UARTCLK),
-	CLK_MGT_ENTRY(MSP02CLK),
-	CLK_MGT_ENTRY(MSP1CLK),
-	CLK_MGT_ENTRY(I2CCLK),
-	CLK_MGT_ENTRY(SDMMCCLK),
-	CLK_MGT_ENTRY(SLIMCLK),
-	CLK_MGT_ENTRY(PER1CLK),
-	CLK_MGT_ENTRY(PER2CLK),
-	CLK_MGT_ENTRY(PER3CLK),
-	CLK_MGT_ENTRY(PER5CLK),
-	CLK_MGT_ENTRY(PER6CLK),
-	CLK_MGT_ENTRY(PER7CLK),
-	CLK_MGT_ENTRY(LCDCLK),
-	CLK_MGT_ENTRY(BMLCLK),
-	CLK_MGT_ENTRY(HSITXCLK),
-	CLK_MGT_ENTRY(HSIRXCLK),
-	CLK_MGT_ENTRY(HDMICLK),
-	CLK_MGT_ENTRY(APEATCLK),
-	CLK_MGT_ENTRY(APETRACECLK),
-	CLK_MGT_ENTRY(MCDECLK),
-	CLK_MGT_ENTRY(IPI2CCLK),
-	CLK_MGT_ENTRY(DSIALTCLK),
-	CLK_MGT_ENTRY(DMACLK),
-	CLK_MGT_ENTRY(B2R2CLK),
-	CLK_MGT_ENTRY(TVCLK),
-	CLK_MGT_ENTRY(SSPCLK),
-	CLK_MGT_ENTRY(RNGCLK),
-	CLK_MGT_ENTRY(UICCCLK),
+	CLK_MGT_ENTRY(SGACLK, PLL_DIV, false),
+	CLK_MGT_ENTRY(UARTCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(MSP02CLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(MSP1CLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(I2CCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(SDMMCCLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(SLIMCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(PER1CLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(PER2CLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(PER3CLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(PER5CLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(PER6CLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(PER7CLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(LCDCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(BMLCLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(HSITXCLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(HSIRXCLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(HDMICLK, PLL_FIX, false),
+	CLK_MGT_ENTRY(APEATCLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(APETRACECLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(MCDECLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(IPI2CCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(DSIALTCLK, PLL_FIX, false),
+	CLK_MGT_ENTRY(DMACLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(B2R2CLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(TVCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(SSPCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(RNGCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(UICCCLK, PLL_FIX, false),
 };
 
-static struct regulator *hwacc_regulator[NUM_HW_ACC];
-static struct regulator *hwacc_ret_regulator[NUM_HW_ACC];
-
-static bool hwacc_enabled[NUM_HW_ACC];
-static bool hwacc_ret_enabled[NUM_HW_ACC];
-
-static const char *hwacc_regulator_name[NUM_HW_ACC] = {
-	[HW_ACC_SVAMMDSP]	= "hwacc-sva-mmdsp",
-	[HW_ACC_SVAPIPE]	= "hwacc-sva-pipe",
-	[HW_ACC_SIAMMDSP]	= "hwacc-sia-mmdsp",
-	[HW_ACC_SIAPIPE]	= "hwacc-sia-pipe",
-	[HW_ACC_SGA]		= "hwacc-sga",
-	[HW_ACC_B2R2]		= "hwacc-b2r2",
-	[HW_ACC_MCDE]		= "hwacc-mcde",
-	[HW_ACC_ESRAM1]		= "hwacc-esram1",
-	[HW_ACC_ESRAM2]		= "hwacc-esram2",
-	[HW_ACC_ESRAM3]		= "hwacc-esram3",
-	[HW_ACC_ESRAM4]		= "hwacc-esram4",
+struct dsiclk {
+	u32 divsel_mask;
+	u32 divsel_shift;
+	u32 divsel;
 };
 
-static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
-	[HW_ACC_SVAMMDSP]	= "hwacc-sva-mmdsp-ret",
-	[HW_ACC_SIAMMDSP]	= "hwacc-sia-mmdsp-ret",
-	[HW_ACC_ESRAM1]		= "hwacc-esram1-ret",
-	[HW_ACC_ESRAM2]		= "hwacc-esram2-ret",
-	[HW_ACC_ESRAM3]		= "hwacc-esram3-ret",
-	[HW_ACC_ESRAM4]		= "hwacc-esram4-ret",
+static struct dsiclk dsiclk[2] = {
+	{
+		.divsel_mask = PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_MASK,
+		.divsel_shift = PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_SHIFT,
+		.divsel = PRCM_DSI_PLLOUT_SEL_PHI,
+	},
+	{
+		.divsel_mask = PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_MASK,
+		.divsel_shift = PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_SHIFT,
+		.divsel = PRCM_DSI_PLLOUT_SEL_PHI,
+	}
+};
+
+struct dsiescclk {
+	u32 en;
+	u32 div_mask;
+	u32 div_shift;
+};
+
+static struct dsiescclk dsiescclk[3] = {
+	{
+		.en = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_EN,
+		.div_mask = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_MASK,
+		.div_shift = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_SHIFT,
+	},
+	{
+		.en = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_EN,
+		.div_mask = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_MASK,
+		.div_shift = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_SHIFT,
+	},
+	{
+		.en = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_EN,
+		.div_mask = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_MASK,
+		.div_shift = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_SHIFT,
+	}
 };
 
 /*
@@ -503,9 +531,6 @@
 /* PLLDIV=12, PLLSW=4 (PLLDDR) */
 #define PRCMU_DSI_CLOCK_SETTING		0x0000008C
 
-/* PLLDIV=8, PLLSW=4 (PLLDDR) */
-#define PRCMU_DSI_CLOCK_SETTING_U8400	0x00000088
-
 /* DPI 50000000 Hz */
 #define PRCMU_DPI_CLOCK_SETTING		((1 << PRCMU_CLK_PLL_SW_SHIFT) | \
 					  (16 << PRCMU_CLK_PLL_DIV_SHIFT))
@@ -514,9 +539,6 @@
 /* D=101, N=1, R=4, SELDIV2=0 */
 #define PRCMU_PLLDSI_FREQ_SETTING	0x00040165
 
-/* D=70, N=1, R=3, SELDIV2=0 */
-#define PRCMU_PLLDSI_FREQ_SETTING_U8400	0x00030146
-
 #define PRCMU_ENABLE_PLLDSI		0x00000001
 #define PRCMU_DISABLE_PLLDSI		0x00000000
 #define PRCMU_RELEASE_RESET_DSS		0x0000400C
@@ -528,30 +550,17 @@
 
 #define PRCMU_PLLDSI_LOCKP_LOCKED	0x3
 
-static struct {
-	u8 project_number;
-	u8 api_version;
-	u8 func_version;
-	u8 errata;
-} prcmu_version;
-
-
 int db8500_prcmu_enable_dsipll(void)
 {
 	int i;
-	unsigned int plldsifreq;
 
 	/* Clear DSIPLL_RESETN */
 	writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR);
 	/* Unclamp DSIPLL in/out */
 	writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
 
-	if (prcmu_is_u8400())
-		plldsifreq = PRCMU_PLLDSI_FREQ_SETTING_U8400;
-	else
-		plldsifreq = PRCMU_PLLDSI_FREQ_SETTING;
 	/* Set DSI PLL FREQ */
-	writel(plldsifreq, PRCM_PLLDSI_FREQ);
+	writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ);
 	writel(PRCMU_DSI_PLLOUT_SEL_SETTING, PRCM_DSI_PLLOUT_SEL);
 	/* Enable Escape clocks */
 	writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
@@ -583,12 +592,6 @@
 int db8500_prcmu_set_display_clocks(void)
 {
 	unsigned long flags;
-	unsigned int dsiclk;
-
-	if (prcmu_is_u8400())
-		dsiclk = PRCMU_DSI_CLOCK_SETTING_U8400;
-	else
-		dsiclk = PRCMU_DSI_CLOCK_SETTING;
 
 	spin_lock_irqsave(&clk_mgt_lock, flags);
 
@@ -596,7 +599,7 @@
 	while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
 		cpu_relax();
 
-	writel(dsiclk, PRCM_HDMICLK_MGT);
+	writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT);
 	writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT);
 	writel(PRCMU_DPI_CLOCK_SETTING, PRCM_LCDCLK_MGT);
 
@@ -608,32 +611,35 @@
 	return 0;
 }
 
-/**
- * prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1.
- */
-void prcmu_enable_spi2(void)
+u32 db8500_prcmu_read(unsigned int reg)
 {
-	u32 reg;
-	unsigned long flags;
-
-	spin_lock_irqsave(&gpiocr_lock, flags);
-	reg = readl(PRCM_GPIOCR);
-	writel(reg | PRCM_GPIOCR_SPI2_SELECT, PRCM_GPIOCR);
-	spin_unlock_irqrestore(&gpiocr_lock, flags);
+	return readl(_PRCMU_BASE + reg);
 }
 
-/**
- * prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1.
- */
-void prcmu_disable_spi2(void)
+void db8500_prcmu_write(unsigned int reg, u32 value)
 {
-	u32 reg;
 	unsigned long flags;
 
-	spin_lock_irqsave(&gpiocr_lock, flags);
-	reg = readl(PRCM_GPIOCR);
-	writel(reg & ~PRCM_GPIOCR_SPI2_SELECT, PRCM_GPIOCR);
-	spin_unlock_irqrestore(&gpiocr_lock, flags);
+	spin_lock_irqsave(&prcmu_lock, flags);
+	writel(value, (_PRCMU_BASE + reg));
+	spin_unlock_irqrestore(&prcmu_lock, flags);
+}
+
+void db8500_prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
+{
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&prcmu_lock, flags);
+	val = readl(_PRCMU_BASE + reg);
+	val = ((val & ~mask) | (value & mask));
+	writel(val, (_PRCMU_BASE + reg));
+	spin_unlock_irqrestore(&prcmu_lock, flags);
+}
+
+struct prcmu_fw_version *prcmu_get_fw_version(void)
+{
+	return fw_info.valid ? &fw_info.version : NULL;
 }
 
 bool prcmu_has_arm_maxopp(void)
@@ -642,11 +648,6 @@
 		PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK;
 }
 
-bool prcmu_is_u8400(void)
-{
-	return prcmu_version.project_number == PRCMU_PROJECT_ID_8400V2_0;
-}
-
 /**
  * prcmu_get_boot_status - PRCMU boot status checking
  * Returns: the current PRCMU boot status
@@ -787,6 +788,124 @@
 	return 0;
 }
 
+u8 db8500_prcmu_get_power_state_result(void)
+{
+	return readb(tcdm_base + PRCM_ACK_MB0_AP_PWRSTTR_STATUS);
+}
+
+/* This function decouple the gic from the prcmu */
+int db8500_prcmu_gic_decouple(void)
+{
+	u32 val = readl(PRCM_A9_MASK_REQ);
+
+	/* Set bit 0 register value to 1 */
+	writel(val | PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ,
+	       PRCM_A9_MASK_REQ);
+
+	/* Make sure the register is updated */
+	readl(PRCM_A9_MASK_REQ);
+
+	/* Wait a few cycles for the gic mask completion */
+	udelay(1);
+
+	return 0;
+}
+
+/* This function recouple the gic with the prcmu */
+int db8500_prcmu_gic_recouple(void)
+{
+	u32 val = readl(PRCM_A9_MASK_REQ);
+
+	/* Set bit 0 register value to 0 */
+	writel(val & ~PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ, PRCM_A9_MASK_REQ);
+
+	return 0;
+}
+
+#define PRCMU_GIC_NUMBER_REGS 5
+
+/*
+ * This function checks if there are pending irq on the gic. It only
+ * makes sense if the gic has been decoupled before with the
+ * db8500_prcmu_gic_decouple function. Disabling an interrupt only
+ * disables the forwarding of the interrupt to any CPU interface. It
+ * does not prevent the interrupt from changing state, for example
+ * becoming pending, or active and pending if it is already
+ * active. Hence, we have to check the interrupt is pending *and* is
+ * active.
+ */
+bool db8500_prcmu_gic_pending_irq(void)
+{
+	u32 pr; /* Pending register */
+	u32 er; /* Enable register */
+	void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
+	int i;
+
+        /* 5 registers. STI & PPI not skipped */
+	for (i = 0; i < PRCMU_GIC_NUMBER_REGS; i++) {
+
+		pr = readl_relaxed(dist_base + GIC_DIST_PENDING_SET + i * 4);
+		er = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+		if (pr & er)
+			return true; /* There is a pending interrupt */
+	}
+
+	return false;
+}
+
+/*
+ * This function checks if there are pending interrupt on the
+ * prcmu which has been delegated to monitor the irqs with the
+ * db8500_prcmu_copy_gic_settings function.
+ */
+bool db8500_prcmu_pending_irq(void)
+{
+	u32 it, im;
+	int i;
+
+	for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) {
+		it = readl(PRCM_ARMITVAL31TO0 + i * 4);
+		im = readl(PRCM_ARMITMSK31TO0 + i * 4);
+		if (it & im)
+			return true; /* There is a pending interrupt */
+	}
+
+	return false;
+}
+
+/*
+ * This function checks if the specified cpu is in in WFI. It's usage
+ * makes sense only if the gic is decoupled with the db8500_prcmu_gic_decouple
+ * function. Of course passing smp_processor_id() to this function will
+ * always return false...
+ */
+bool db8500_prcmu_is_cpu_in_wfi(int cpu)
+{
+	return readl(PRCM_ARM_WFI_STANDBY) & cpu ? PRCM_ARM_WFI_STANDBY_WFI1 :
+		     PRCM_ARM_WFI_STANDBY_WFI0;
+}
+
+/*
+ * This function copies the gic SPI settings to the prcmu in order to
+ * monitor them and abort/finish the retention/off sequence or state.
+ */
+int db8500_prcmu_copy_gic_settings(void)
+{
+	u32 er; /* Enable register */
+	void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
+	int i;
+
+        /* We skip the STI and PPI */
+	for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) {
+		er = readl_relaxed(dist_base +
+				   GIC_DIST_ENABLE_SET + (i + 1) * 4);
+		writel(er, PRCM_ARMITMSK31TO0 + i * 4);
+	}
+
+	return 0;
+}
+
 /* This function should only be called while mb0_transfer.lock is held. */
 static void config_wakeups(void)
 {
@@ -909,23 +1028,23 @@
 }
 
 /**
- * prcmu_get_ddr_opp - get the current DDR OPP
+ * db8500_prcmu_get_ddr_opp - get the current DDR OPP
  *
  * Returns: the current DDR OPP
  */
-int prcmu_get_ddr_opp(void)
+int db8500_prcmu_get_ddr_opp(void)
 {
 	return readb(PRCM_DDR_SUBSYS_APE_MINBW);
 }
 
 /**
- * set_ddr_opp - set the appropriate DDR OPP
+ * db8500_set_ddr_opp - set the appropriate DDR OPP
  * @opp: The new DDR operating point to which transition is to be made
  * Returns: 0 on success, non-zero on failure
  *
  * This function sets the operating point of the DDR.
  */
-int prcmu_set_ddr_opp(u8 opp)
+int db8500_prcmu_set_ddr_opp(u8 opp)
 {
 	if (opp < DDR_100_OPP || opp > DDR_25_OPP)
 		return -EINVAL;
@@ -935,25 +1054,82 @@
 
 	return 0;
 }
+
+/* Divide the frequency of certain clocks by 2 for APE_50_PARTLY_25_OPP. */
+static void request_even_slower_clocks(bool enable)
+{
+	void __iomem *clock_reg[] = {
+		PRCM_ACLK_MGT,
+		PRCM_DMACLK_MGT
+	};
+	unsigned long flags;
+	unsigned int i;
+
+	spin_lock_irqsave(&clk_mgt_lock, flags);
+
+	/* Grab the HW semaphore. */
+	while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+		cpu_relax();
+
+	for (i = 0; i < ARRAY_SIZE(clock_reg); i++) {
+		u32 val;
+		u32 div;
+
+		val = readl(clock_reg[i]);
+		div = (val & PRCM_CLK_MGT_CLKPLLDIV_MASK);
+		if (enable) {
+			if ((div <= 1) || (div > 15)) {
+				pr_err("prcmu: Bad clock divider %d in %s\n",
+					div, __func__);
+				goto unlock_and_return;
+			}
+			div <<= 1;
+		} else {
+			if (div <= 2)
+				goto unlock_and_return;
+			div >>= 1;
+		}
+		val = ((val & ~PRCM_CLK_MGT_CLKPLLDIV_MASK) |
+			(div & PRCM_CLK_MGT_CLKPLLDIV_MASK));
+		writel(val, clock_reg[i]);
+	}
+
+unlock_and_return:
+	/* Release the HW semaphore. */
+	writel(0, PRCM_SEM);
+
+	spin_unlock_irqrestore(&clk_mgt_lock, flags);
+}
+
 /**
- * set_ape_opp - set the appropriate APE OPP
+ * db8500_set_ape_opp - set the appropriate APE OPP
  * @opp: The new APE operating point to which transition is to be made
  * Returns: 0 on success, non-zero on failure
  *
  * This function sets the operating point of the APE.
  */
-int prcmu_set_ape_opp(u8 opp)
+int db8500_prcmu_set_ape_opp(u8 opp)
 {
 	int r = 0;
 
+	if (opp == mb1_transfer.ape_opp)
+		return 0;
+
 	mutex_lock(&mb1_transfer.lock);
 
+	if (mb1_transfer.ape_opp == APE_50_PARTLY_25_OPP)
+		request_even_slower_clocks(false);
+
+	if ((opp != APE_100_OPP) && (mb1_transfer.ape_opp != APE_100_OPP))
+		goto skip_message;
+
 	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
 		cpu_relax();
 
 	writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
 	writeb(ARM_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_ARM_OPP));
-	writeb(opp, (tcdm_base + PRCM_REQ_MB1_APE_OPP));
+	writeb(((opp == APE_50_PARTLY_25_OPP) ? APE_50_OPP : opp),
+		(tcdm_base + PRCM_REQ_MB1_APE_OPP));
 
 	writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
 	wait_for_completion(&mb1_transfer.work);
@@ -962,17 +1138,24 @@
 		(mb1_transfer.ack.ape_opp != opp))
 		r = -EIO;
 
+skip_message:
+	if ((!r && (opp == APE_50_PARTLY_25_OPP)) ||
+		(r && (mb1_transfer.ape_opp == APE_50_PARTLY_25_OPP)))
+		request_even_slower_clocks(true);
+	if (!r)
+		mb1_transfer.ape_opp = opp;
+
 	mutex_unlock(&mb1_transfer.lock);
 
 	return r;
 }
 
 /**
- * prcmu_get_ape_opp - get the current APE OPP
+ * db8500_prcmu_get_ape_opp - get the current APE OPP
  *
  * Returns: the current APE OPP
  */
-int prcmu_get_ape_opp(void)
+int db8500_prcmu_get_ape_opp(void)
 {
 	return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_APE_OPP);
 }
@@ -1056,7 +1239,9 @@
 {
 	int r = 0;
 
-	if (clock == PRCMU_PLLSOC1)
+	if (clock == PRCMU_PLLSOC0)
+		clock = (enable ? PLL_SOC0_ON : PLL_SOC0_OFF);
+	else if (clock == PRCMU_PLLSOC1)
 		clock = (enable ? PLL_SOC1_ON : PLL_SOC1_OFF);
 	else
 		return -EINVAL;
@@ -1081,132 +1266,6 @@
 }
 
 /**
- * prcmu_set_hwacc - set the power state of a h/w accelerator
- * @hwacc_dev: The hardware accelerator (enum hw_acc_dev).
- * @state: The new power state (enum hw_acc_state).
- *
- * This function sets the power state of a hardware accelerator.
- * This function should not be called from interrupt context.
- *
- * NOTE! Deprecated, to be removed when all users switched over to use the
- * regulator framework API.
- */
-int prcmu_set_hwacc(u16 hwacc_dev, u8 state)
-{
-	int r = 0;
-	bool ram_retention = false;
-	bool enable, enable_ret;
-
-	/* check argument */
-	BUG_ON(hwacc_dev >= NUM_HW_ACC);
-
-	/* get state of switches */
-	enable = hwacc_enabled[hwacc_dev];
-	enable_ret = hwacc_ret_enabled[hwacc_dev];
-
-	/* set flag if retention is possible */
-	switch (hwacc_dev) {
-	case HW_ACC_SVAMMDSP:
-	case HW_ACC_SIAMMDSP:
-	case HW_ACC_ESRAM1:
-	case HW_ACC_ESRAM2:
-	case HW_ACC_ESRAM3:
-	case HW_ACC_ESRAM4:
-		ram_retention = true;
-		break;
-	}
-
-	/* check argument */
-	BUG_ON(state > HW_ON);
-	BUG_ON(state == HW_OFF_RAMRET && !ram_retention);
-
-	/* modify enable flags */
-	switch (state) {
-	case HW_OFF:
-		enable_ret = false;
-		enable = false;
-		break;
-	case HW_ON:
-		enable = true;
-		break;
-	case HW_OFF_RAMRET:
-		enable_ret = true;
-		enable = false;
-		break;
-	}
-
-	/* get regulator (lazy) */
-	if (hwacc_regulator[hwacc_dev] == NULL) {
-		hwacc_regulator[hwacc_dev] = regulator_get(NULL,
-			hwacc_regulator_name[hwacc_dev]);
-		if (IS_ERR(hwacc_regulator[hwacc_dev])) {
-			pr_err("prcmu: failed to get supply %s\n",
-				hwacc_regulator_name[hwacc_dev]);
-			r = PTR_ERR(hwacc_regulator[hwacc_dev]);
-			goto out;
-		}
-	}
-
-	if (ram_retention) {
-		if (hwacc_ret_regulator[hwacc_dev] == NULL) {
-			hwacc_ret_regulator[hwacc_dev] = regulator_get(NULL,
-				hwacc_ret_regulator_name[hwacc_dev]);
-			if (IS_ERR(hwacc_ret_regulator[hwacc_dev])) {
-				pr_err("prcmu: failed to get supply %s\n",
-					hwacc_ret_regulator_name[hwacc_dev]);
-				r = PTR_ERR(hwacc_ret_regulator[hwacc_dev]);
-				goto out;
-			}
-		}
-	}
-
-	/* set regulators */
-	if (ram_retention) {
-		if (enable_ret && !hwacc_ret_enabled[hwacc_dev]) {
-			r = regulator_enable(hwacc_ret_regulator[hwacc_dev]);
-			if (r < 0) {
-				pr_err("prcmu_set_hwacc: ret enable failed\n");
-				goto out;
-			}
-			hwacc_ret_enabled[hwacc_dev] = true;
-		}
-	}
-
-	if (enable && !hwacc_enabled[hwacc_dev]) {
-		r = regulator_enable(hwacc_regulator[hwacc_dev]);
-		if (r < 0) {
-			pr_err("prcmu_set_hwacc: enable failed\n");
-			goto out;
-		}
-		hwacc_enabled[hwacc_dev] = true;
-	}
-
-	if (!enable && hwacc_enabled[hwacc_dev]) {
-		r = regulator_disable(hwacc_regulator[hwacc_dev]);
-		if (r < 0) {
-			pr_err("prcmu_set_hwacc: disable failed\n");
-			goto out;
-		}
-		hwacc_enabled[hwacc_dev] = false;
-	}
-
-	if (ram_retention) {
-		if (!enable_ret && hwacc_ret_enabled[hwacc_dev]) {
-			r = regulator_disable(hwacc_ret_regulator[hwacc_dev]);
-			if (r < 0) {
-				pr_err("prcmu_set_hwacc: ret disable failed\n");
-				goto out;
-			}
-			hwacc_ret_enabled[hwacc_dev] = false;
-		}
-	}
-
-out:
-	return r;
-}
-EXPORT_SYMBOL(prcmu_set_hwacc);
-
-/**
  * db8500_prcmu_set_epod - set the state of a EPOD (power domain)
  * @epod_id: The EPOD to set
  * @epod_state: The new EPOD state
@@ -1375,7 +1434,7 @@
 	return 0;
 }
 
-static int request_reg_clock(u8 clock, bool enable)
+static int request_clock(u8 clock, bool enable)
 {
 	u32 val;
 	unsigned long flags;
@@ -1386,14 +1445,14 @@
 	while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
 		cpu_relax();
 
-	val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
+	val = readl(clk_mgt[clock].reg);
 	if (enable) {
 		val |= (PRCM_CLK_MGT_CLKEN | clk_mgt[clock].pllsw);
 	} else {
 		clk_mgt[clock].pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
 		val &= ~(PRCM_CLK_MGT_CLKEN | PRCM_CLK_MGT_CLKPLLSW_MASK);
 	}
-	writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
+	writel(val, clk_mgt[clock].reg);
 
 	/* Release the HW semaphore. */
 	writel(0, PRCM_SEM);
@@ -1413,7 +1472,7 @@
 		writel(val | PRCM_CGATING_BYPASS_ICN2, PRCM_CGATING_BYPASS);
 	}
 
-	ret = request_reg_clock(clock, enable);
+	ret = request_clock(clock, enable);
 
 	if (!ret && !enable) {
 		val = readl(PRCM_CGATING_BYPASS);
@@ -1423,6 +1482,78 @@
 	return ret;
 }
 
+static inline bool plldsi_locked(void)
+{
+	return (readl(PRCM_PLLDSI_LOCKP) &
+		(PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 |
+		 PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3)) ==
+		(PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 |
+		 PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3);
+}
+
+static int request_plldsi(bool enable)
+{
+	int r = 0;
+	u32 val;
+
+	writel((PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP |
+		PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI), (enable ?
+		PRCM_MMIP_LS_CLAMP_CLR : PRCM_MMIP_LS_CLAMP_SET));
+
+	val = readl(PRCM_PLLDSI_ENABLE);
+	if (enable)
+		val |= PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
+	else
+		val &= ~PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
+	writel(val, PRCM_PLLDSI_ENABLE);
+
+	if (enable) {
+		unsigned int i;
+		bool locked = plldsi_locked();
+
+		for (i = 10; !locked && (i > 0); --i) {
+			udelay(100);
+			locked = plldsi_locked();
+		}
+		if (locked) {
+			writel(PRCM_APE_RESETN_DSIPLL_RESETN,
+				PRCM_APE_RESETN_SET);
+		} else {
+			writel((PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP |
+				PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI),
+				PRCM_MMIP_LS_CLAMP_SET);
+			val &= ~PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
+			writel(val, PRCM_PLLDSI_ENABLE);
+			r = -EAGAIN;
+		}
+	} else {
+		writel(PRCM_APE_RESETN_DSIPLL_RESETN, PRCM_APE_RESETN_CLR);
+	}
+	return r;
+}
+
+static int request_dsiclk(u8 n, bool enable)
+{
+	u32 val;
+
+	val = readl(PRCM_DSI_PLLOUT_SEL);
+	val &= ~dsiclk[n].divsel_mask;
+	val |= ((enable ? dsiclk[n].divsel : PRCM_DSI_PLLOUT_SEL_OFF) <<
+		dsiclk[n].divsel_shift);
+	writel(val, PRCM_DSI_PLLOUT_SEL);
+	return 0;
+}
+
+static int request_dsiescclk(u8 n, bool enable)
+{
+	u32 val;
+
+	val = readl(PRCM_DSITVCLK_DIV);
+	enable ? (val |= dsiescclk[n].en) : (val &= ~dsiescclk[n].en);
+	writel(val, PRCM_DSITVCLK_DIV);
+	return 0;
+}
+
 /**
  * db8500_prcmu_request_clock() - Request for a clock to be enabled or disabled.
  * @clock:      The clock for which the request is made.
@@ -1433,21 +1564,435 @@
  */
 int db8500_prcmu_request_clock(u8 clock, bool enable)
 {
-	switch(clock) {
-	case PRCMU_SGACLK:
+	if (clock == PRCMU_SGACLK)
 		return request_sga_clock(clock, enable);
-	case PRCMU_TIMCLK:
+	else if (clock < PRCMU_NUM_REG_CLOCKS)
+		return request_clock(clock, enable);
+	else if (clock == PRCMU_TIMCLK)
 		return request_timclk(enable);
-	case PRCMU_SYSCLK:
+	else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+		return request_dsiclk((clock - PRCMU_DSI0CLK), enable);
+	else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+		return request_dsiescclk((clock - PRCMU_DSI0ESCCLK), enable);
+	else if (clock == PRCMU_PLLDSI)
+		return request_plldsi(enable);
+	else if (clock == PRCMU_SYSCLK)
 		return request_sysclk(enable);
-	case PRCMU_PLLSOC1:
+	else if ((clock == PRCMU_PLLSOC0) || (clock == PRCMU_PLLSOC1))
 		return request_pll(clock, enable);
-	default:
-		break;
+	else
+		return -EINVAL;
+}
+
+static unsigned long pll_rate(void __iomem *reg, unsigned long src_rate,
+	int branch)
+{
+	u64 rate;
+	u32 val;
+	u32 d;
+	u32 div = 1;
+
+	val = readl(reg);
+
+	rate = src_rate;
+	rate *= ((val & PRCM_PLL_FREQ_D_MASK) >> PRCM_PLL_FREQ_D_SHIFT);
+
+	d = ((val & PRCM_PLL_FREQ_N_MASK) >> PRCM_PLL_FREQ_N_SHIFT);
+	if (d > 1)
+		div *= d;
+
+	d = ((val & PRCM_PLL_FREQ_R_MASK) >> PRCM_PLL_FREQ_R_SHIFT);
+	if (d > 1)
+		div *= d;
+
+	if (val & PRCM_PLL_FREQ_SELDIV2)
+		div *= 2;
+
+	if ((branch == PLL_FIX) || ((branch == PLL_DIV) &&
+		(val & PRCM_PLL_FREQ_DIV2EN) &&
+		((reg == PRCM_PLLSOC0_FREQ) ||
+		 (reg == PRCM_PLLDDR_FREQ))))
+		div *= 2;
+
+	(void)do_div(rate, div);
+
+	return (unsigned long)rate;
+}
+
+#define ROOT_CLOCK_RATE 38400000
+
+static unsigned long clock_rate(u8 clock)
+{
+	u32 val;
+	u32 pllsw;
+	unsigned long rate = ROOT_CLOCK_RATE;
+
+	val = readl(clk_mgt[clock].reg);
+
+	if (val & PRCM_CLK_MGT_CLK38) {
+		if (clk_mgt[clock].clk38div && (val & PRCM_CLK_MGT_CLK38DIV))
+			rate /= 2;
+		return rate;
 	}
+
+	val |= clk_mgt[clock].pllsw;
+	pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
+
+	if (pllsw == PRCM_CLK_MGT_CLKPLLSW_SOC0)
+		rate = pll_rate(PRCM_PLLSOC0_FREQ, rate, clk_mgt[clock].branch);
+	else if (pllsw == PRCM_CLK_MGT_CLKPLLSW_SOC1)
+		rate = pll_rate(PRCM_PLLSOC1_FREQ, rate, clk_mgt[clock].branch);
+	else if (pllsw == PRCM_CLK_MGT_CLKPLLSW_DDR)
+		rate = pll_rate(PRCM_PLLDDR_FREQ, rate, clk_mgt[clock].branch);
+	else
+		return 0;
+
+	if ((clock == PRCMU_SGACLK) &&
+		(val & PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN)) {
+		u64 r = (rate * 10);
+
+		(void)do_div(r, 25);
+		return (unsigned long)r;
+	}
+	val &= PRCM_CLK_MGT_CLKPLLDIV_MASK;
+	if (val)
+		return rate / val;
+	else
+		return 0;
+}
+
+static unsigned long dsiclk_rate(u8 n)
+{
+	u32 divsel;
+	u32 div = 1;
+
+	divsel = readl(PRCM_DSI_PLLOUT_SEL);
+	divsel = ((divsel & dsiclk[n].divsel_mask) >> dsiclk[n].divsel_shift);
+
+	if (divsel == PRCM_DSI_PLLOUT_SEL_OFF)
+		divsel = dsiclk[n].divsel;
+
+	switch (divsel) {
+	case PRCM_DSI_PLLOUT_SEL_PHI_4:
+		div *= 2;
+	case PRCM_DSI_PLLOUT_SEL_PHI_2:
+		div *= 2;
+	case PRCM_DSI_PLLOUT_SEL_PHI:
+		return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
+			PLL_RAW) / div;
+	default:
+		return 0;
+	}
+}
+
+static unsigned long dsiescclk_rate(u8 n)
+{
+	u32 div;
+
+	div = readl(PRCM_DSITVCLK_DIV);
+	div = ((div & dsiescclk[n].div_mask) >> (dsiescclk[n].div_shift));
+	return clock_rate(PRCMU_TVCLK) / max((u32)1, div);
+}
+
+unsigned long prcmu_clock_rate(u8 clock)
+{
 	if (clock < PRCMU_NUM_REG_CLOCKS)
-		return request_reg_clock(clock, enable);
-	return -EINVAL;
+		return clock_rate(clock);
+	else if (clock == PRCMU_TIMCLK)
+		return ROOT_CLOCK_RATE / 16;
+	else if (clock == PRCMU_SYSCLK)
+		return ROOT_CLOCK_RATE;
+	else if (clock == PRCMU_PLLSOC0)
+		return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+	else if (clock == PRCMU_PLLSOC1)
+		return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+	else if (clock == PRCMU_PLLDDR)
+		return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+	else if (clock == PRCMU_PLLDSI)
+		return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
+			PLL_RAW);
+	else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+		return dsiclk_rate(clock - PRCMU_DSI0CLK);
+	else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+		return dsiescclk_rate(clock - PRCMU_DSI0ESCCLK);
+	else
+		return 0;
+}
+
+static unsigned long clock_source_rate(u32 clk_mgt_val, int branch)
+{
+	if (clk_mgt_val & PRCM_CLK_MGT_CLK38)
+		return ROOT_CLOCK_RATE;
+	clk_mgt_val &= PRCM_CLK_MGT_CLKPLLSW_MASK;
+	if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_SOC0)
+		return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, branch);
+	else if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_SOC1)
+		return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, branch);
+	else if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_DDR)
+		return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, branch);
+	else
+		return 0;
+}
+
+static u32 clock_divider(unsigned long src_rate, unsigned long rate)
+{
+	u32 div;
+
+	div = (src_rate / rate);
+	if (div == 0)
+		return 1;
+	if (rate < (src_rate / div))
+		div++;
+	return div;
+}
+
+static long round_clock_rate(u8 clock, unsigned long rate)
+{
+	u32 val;
+	u32 div;
+	unsigned long src_rate;
+	long rounded_rate;
+
+	val = readl(clk_mgt[clock].reg);
+	src_rate = clock_source_rate((val | clk_mgt[clock].pllsw),
+		clk_mgt[clock].branch);
+	div = clock_divider(src_rate, rate);
+	if (val & PRCM_CLK_MGT_CLK38) {
+		if (clk_mgt[clock].clk38div) {
+			if (div > 2)
+				div = 2;
+		} else {
+			div = 1;
+		}
+	} else if ((clock == PRCMU_SGACLK) && (div == 3)) {
+		u64 r = (src_rate * 10);
+
+		(void)do_div(r, 25);
+		if (r <= rate)
+			return (unsigned long)r;
+	}
+	rounded_rate = (src_rate / min(div, (u32)31));
+
+	return rounded_rate;
+}
+
+#define MIN_PLL_VCO_RATE 600000000ULL
+#define MAX_PLL_VCO_RATE 1680640000ULL
+
+static long round_plldsi_rate(unsigned long rate)
+{
+	long rounded_rate = 0;
+	unsigned long src_rate;
+	unsigned long rem;
+	u32 r;
+
+	src_rate = clock_rate(PRCMU_HDMICLK);
+	rem = rate;
+
+	for (r = 7; (rem > 0) && (r > 0); r--) {
+		u64 d;
+
+		d = (r * rate);
+		(void)do_div(d, src_rate);
+		if (d < 6)
+			d = 6;
+		else if (d > 255)
+			d = 255;
+		d *= src_rate;
+		if (((2 * d) < (r * MIN_PLL_VCO_RATE)) ||
+			((r * MAX_PLL_VCO_RATE) < (2 * d)))
+			continue;
+		(void)do_div(d, r);
+		if (rate < d) {
+			if (rounded_rate == 0)
+				rounded_rate = (long)d;
+			break;
+		}
+		if ((rate - d) < rem) {
+			rem = (rate - d);
+			rounded_rate = (long)d;
+		}
+	}
+	return rounded_rate;
+}
+
+static long round_dsiclk_rate(unsigned long rate)
+{
+	u32 div;
+	unsigned long src_rate;
+	long rounded_rate;
+
+	src_rate = pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
+		PLL_RAW);
+	div = clock_divider(src_rate, rate);
+	rounded_rate = (src_rate / ((div > 2) ? 4 : div));
+
+	return rounded_rate;
+}
+
+static long round_dsiescclk_rate(unsigned long rate)
+{
+	u32 div;
+	unsigned long src_rate;
+	long rounded_rate;
+
+	src_rate = clock_rate(PRCMU_TVCLK);
+	div = clock_divider(src_rate, rate);
+	rounded_rate = (src_rate / min(div, (u32)255));
+
+	return rounded_rate;
+}
+
+long prcmu_round_clock_rate(u8 clock, unsigned long rate)
+{
+	if (clock < PRCMU_NUM_REG_CLOCKS)
+		return round_clock_rate(clock, rate);
+	else if (clock == PRCMU_PLLDSI)
+		return round_plldsi_rate(rate);
+	else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+		return round_dsiclk_rate(rate);
+	else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+		return round_dsiescclk_rate(rate);
+	else
+		return (long)prcmu_clock_rate(clock);
+}
+
+static void set_clock_rate(u8 clock, unsigned long rate)
+{
+	u32 val;
+	u32 div;
+	unsigned long src_rate;
+	unsigned long flags;
+
+	spin_lock_irqsave(&clk_mgt_lock, flags);
+
+	/* Grab the HW semaphore. */
+	while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+		cpu_relax();
+
+	val = readl(clk_mgt[clock].reg);
+	src_rate = clock_source_rate((val | clk_mgt[clock].pllsw),
+		clk_mgt[clock].branch);
+	div = clock_divider(src_rate, rate);
+	if (val & PRCM_CLK_MGT_CLK38) {
+		if (clk_mgt[clock].clk38div) {
+			if (div > 1)
+				val |= PRCM_CLK_MGT_CLK38DIV;
+			else
+				val &= ~PRCM_CLK_MGT_CLK38DIV;
+		}
+	} else if (clock == PRCMU_SGACLK) {
+		val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK |
+			PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN);
+		if (div == 3) {
+			u64 r = (src_rate * 10);
+
+			(void)do_div(r, 25);
+			if (r <= rate) {
+				val |= PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN;
+				div = 0;
+			}
+		}
+		val |= min(div, (u32)31);
+	} else {
+		val &= ~PRCM_CLK_MGT_CLKPLLDIV_MASK;
+		val |= min(div, (u32)31);
+	}
+	writel(val, clk_mgt[clock].reg);
+
+	/* Release the HW semaphore. */
+	writel(0, PRCM_SEM);
+
+	spin_unlock_irqrestore(&clk_mgt_lock, flags);
+}
+
+static int set_plldsi_rate(unsigned long rate)
+{
+	unsigned long src_rate;
+	unsigned long rem;
+	u32 pll_freq = 0;
+	u32 r;
+
+	src_rate = clock_rate(PRCMU_HDMICLK);
+	rem = rate;
+
+	for (r = 7; (rem > 0) && (r > 0); r--) {
+		u64 d;
+		u64 hwrate;
+
+		d = (r * rate);
+		(void)do_div(d, src_rate);
+		if (d < 6)
+			d = 6;
+		else if (d > 255)
+			d = 255;
+		hwrate = (d * src_rate);
+		if (((2 * hwrate) < (r * MIN_PLL_VCO_RATE)) ||
+			((r * MAX_PLL_VCO_RATE) < (2 * hwrate)))
+			continue;
+		(void)do_div(hwrate, r);
+		if (rate < hwrate) {
+			if (pll_freq == 0)
+				pll_freq = (((u32)d << PRCM_PLL_FREQ_D_SHIFT) |
+					(r << PRCM_PLL_FREQ_R_SHIFT));
+			break;
+		}
+		if ((rate - hwrate) < rem) {
+			rem = (rate - hwrate);
+			pll_freq = (((u32)d << PRCM_PLL_FREQ_D_SHIFT) |
+				(r << PRCM_PLL_FREQ_R_SHIFT));
+		}
+	}
+	if (pll_freq == 0)
+		return -EINVAL;
+
+	pll_freq |= (1 << PRCM_PLL_FREQ_N_SHIFT);
+	writel(pll_freq, PRCM_PLLDSI_FREQ);
+
+	return 0;
+}
+
+static void set_dsiclk_rate(u8 n, unsigned long rate)
+{
+	u32 val;
+	u32 div;
+
+	div = clock_divider(pll_rate(PRCM_PLLDSI_FREQ,
+			clock_rate(PRCMU_HDMICLK), PLL_RAW), rate);
+
+	dsiclk[n].divsel = (div == 1) ? PRCM_DSI_PLLOUT_SEL_PHI :
+			   (div == 2) ? PRCM_DSI_PLLOUT_SEL_PHI_2 :
+			   /* else */	PRCM_DSI_PLLOUT_SEL_PHI_4;
+
+	val = readl(PRCM_DSI_PLLOUT_SEL);
+	val &= ~dsiclk[n].divsel_mask;
+	val |= (dsiclk[n].divsel << dsiclk[n].divsel_shift);
+	writel(val, PRCM_DSI_PLLOUT_SEL);
+}
+
+static void set_dsiescclk_rate(u8 n, unsigned long rate)
+{
+	u32 val;
+	u32 div;
+
+	div = clock_divider(clock_rate(PRCMU_TVCLK), rate);
+	val = readl(PRCM_DSITVCLK_DIV);
+	val &= ~dsiescclk[n].div_mask;
+	val |= (min(div, (u32)255) << dsiescclk[n].div_shift);
+	writel(val, PRCM_DSITVCLK_DIV);
+}
+
+int prcmu_set_clock_rate(u8 clock, unsigned long rate)
+{
+	if (clock < PRCMU_NUM_REG_CLOCKS)
+		set_clock_rate(clock, rate);
+	else if (clock == PRCMU_PLLDSI)
+		return set_plldsi_rate(rate);
+	else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+		set_dsiclk_rate((clock - PRCMU_DSI0CLK), rate);
+	else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+		set_dsiescclk_rate((clock - PRCMU_DSI0ESCCLK), rate);
+	return 0;
 }
 
 int db8500_prcmu_config_esram0_deep_sleep(u8 state)
@@ -1476,7 +2021,7 @@
 	return 0;
 }
 
-int prcmu_config_hotdog(u8 threshold)
+int db8500_prcmu_config_hotdog(u8 threshold)
 {
 	mutex_lock(&mb4_transfer.lock);
 
@@ -1494,7 +2039,7 @@
 	return 0;
 }
 
-int prcmu_config_hotmon(u8 low, u8 high)
+int db8500_prcmu_config_hotmon(u8 low, u8 high)
 {
 	mutex_lock(&mb4_transfer.lock);
 
@@ -1533,7 +2078,7 @@
 	return 0;
 }
 
-int prcmu_start_temp_sense(u16 cycles32k)
+int db8500_prcmu_start_temp_sense(u16 cycles32k)
 {
 	if (cycles32k == 0xFFFF)
 		return -EINVAL;
@@ -1541,7 +2086,7 @@
 	return config_hot_period(cycles32k);
 }
 
-int prcmu_stop_temp_sense(void)
+int db8500_prcmu_stop_temp_sense(void)
 {
 	return config_hot_period(0xFFFF);
 }
@@ -1570,7 +2115,7 @@
 
 }
 
-int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
+int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
 {
 	BUG_ON(num == 0 || num > 0xf);
 	return prcmu_a9wdog(MB4H_A9WDOG_CONF, num, 0, 0,
@@ -1578,17 +2123,17 @@
 			    A9WDOG_AUTO_OFF_DIS);
 }
 
-int prcmu_enable_a9wdog(u8 id)
+int db8500_prcmu_enable_a9wdog(u8 id)
 {
 	return prcmu_a9wdog(MB4H_A9WDOG_EN, id, 0, 0, 0);
 }
 
-int prcmu_disable_a9wdog(u8 id)
+int db8500_prcmu_disable_a9wdog(u8 id)
 {
 	return prcmu_a9wdog(MB4H_A9WDOG_DIS, id, 0, 0, 0);
 }
 
-int prcmu_kick_a9wdog(u8 id)
+int db8500_prcmu_kick_a9wdog(u8 id)
 {
 	return prcmu_a9wdog(MB4H_A9WDOG_KICK, id, 0, 0, 0);
 }
@@ -1596,16 +2141,8 @@
 /*
  * timeout is 28 bit, in ms.
  */
-#define MAX_WATCHDOG_TIMEOUT 131000
-int prcmu_load_a9wdog(u8 id, u32 timeout)
+int db8500_prcmu_load_a9wdog(u8 id, u32 timeout)
 {
-	if (timeout > MAX_WATCHDOG_TIMEOUT)
-		/*
-		 * Due to calculation bug in prcmu fw, timeouts
-		 * can't be bigger than 131 seconds.
-		 */
-		return -EINVAL;
-
 	return prcmu_a9wdog(MB4H_A9WDOG_LOAD,
 			    (id & A9WDOG_ID_MASK) |
 			    /*
@@ -1619,41 +2156,6 @@
 }
 
 /**
- * prcmu_set_clock_divider() - Configure the clock divider.
- * @clock:	The clock for which the request is made.
- * @divider:	The clock divider. (< 32)
- *
- * This function should only be used by the clock implementation.
- * Do not use it from any other place!
- */
-int prcmu_set_clock_divider(u8 clock, u8 divider)
-{
-	u32 val;
-	unsigned long flags;
-
-	if ((clock >= PRCMU_NUM_REG_CLOCKS) || (divider < 1) || (31 < divider))
-		return -EINVAL;
-
-	spin_lock_irqsave(&clk_mgt_lock, flags);
-
-	/* Grab the HW semaphore. */
-	while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
-		cpu_relax();
-
-	val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
-	val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK);
-	val |= (u32)divider;
-	writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
-
-	/* Release the HW semaphore. */
-	writel(0, PRCM_SEM);
-
-	spin_unlock_irqrestore(&clk_mgt_lock, flags);
-
-	return 0;
-}
-
-/**
  * prcmu_abb_read() - Read register value(s) from the ABB.
  * @slave:	The I2C slave address.
  * @reg:	The (start) register address.
@@ -1675,6 +2177,7 @@
 	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
 		cpu_relax();
 
+	writeb(0, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB5));
 	writeb(PRCMU_I2C_READ(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
 	writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
 	writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
@@ -1700,16 +2203,19 @@
 }
 
 /**
- * prcmu_abb_write() - Write register value(s) to the ABB.
+ * prcmu_abb_write_masked() - Write masked register value(s) to the ABB.
  * @slave:	The I2C slave address.
  * @reg:	The (start) register address.
  * @value:	The value(s) to write.
+ * @mask:	The mask(s) to use.
  * @size:	The number of registers to write.
  *
- * Reads register value(s) from the ABB.
+ * Writes masked register value(s) to the ABB.
+ * For each @value, only the bits set to 1 in the corresponding @mask
+ * will be written. The other bits are not changed.
  * @size has to be 1 for the current firmware version.
  */
-int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask, u8 size)
 {
 	int r;
 
@@ -1721,6 +2227,7 @@
 	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
 		cpu_relax();
 
+	writeb(~*mask, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB5));
 	writeb(PRCMU_I2C_WRITE(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
 	writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
 	writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
@@ -1743,6 +2250,23 @@
 }
 
 /**
+ * prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave:	The I2C slave address.
+ * @reg:	The (start) register address.
+ * @value:	The value(s) to write.
+ * @size:	The number of registers to write.
+ *
+ * Writes register value(s) to the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+	u8 mask = ~0;
+
+	return prcmu_abb_write_masked(slave, reg, value, &mask, size);
+}
+
+/**
  * prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem
  */
 void prcmu_ac_wake_req(void)
@@ -1850,9 +2374,9 @@
 }
 
 /**
- * prcmu_reset_modem - ask the PRCMU to reset modem
+ * db8500_prcmu_reset_modem - ask the PRCMU to reset modem
  */
-void prcmu_modem_reset(void)
+void db8500_prcmu_modem_reset(void)
 {
 	mutex_lock(&mb1_transfer.lock);
 
@@ -2099,6 +2623,26 @@
 	.irq_unmask	= prcmu_irq_unmask,
 };
 
+static char *fw_project_name(u8 project)
+{
+	switch (project) {
+	case PRCMU_FW_PROJECT_U8500:
+		return "U8500";
+	case PRCMU_FW_PROJECT_U8500_C2:
+		return "U8500 C2";
+	case PRCMU_FW_PROJECT_U9500:
+		return "U9500";
+	case PRCMU_FW_PROJECT_U9500_C2:
+		return "U9500 C2";
+	case PRCMU_FW_PROJECT_U8520:
+		return "U8520";
+	case PRCMU_FW_PROJECT_U8420:
+		return "U8420";
+	default:
+		return "Unknown";
+	}
+}
+
 void __init db8500_prcmu_early_init(void)
 {
 	unsigned int i;
@@ -2108,11 +2652,13 @@
 		if (tcpm_base != NULL) {
 			u32 version;
 			version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET);
-			prcmu_version.project_number = version & 0xFF;
-			prcmu_version.api_version = (version >> 8) & 0xFF;
-			prcmu_version.func_version = (version >> 16) & 0xFF;
-			prcmu_version.errata = (version >> 24) & 0xFF;
-			pr_info("PRCMU firmware version %d.%d.%d\n",
+			fw_info.version.project = version & 0xFF;
+			fw_info.version.api_version = (version >> 8) & 0xFF;
+			fw_info.version.func_version = (version >> 16) & 0xFF;
+			fw_info.version.errata = (version >> 24) & 0xFF;
+			fw_info.valid = true;
+			pr_info("PRCMU firmware: %s, version %d.%d.%d\n",
+				fw_project_name(fw_info.version.project),
 				(version >> 8) & 0xFF, (version >> 16) & 0xFF,
 				(version >> 24) & 0xFF);
 			iounmap(tcpm_base);
@@ -2130,6 +2676,7 @@
 	init_completion(&mb0_transfer.ac_wake_work);
 	mutex_init(&mb1_transfer.lock);
 	init_completion(&mb1_transfer.work);
+	mb1_transfer.ape_opp = APE_NO_CHANGE;
 	mutex_init(&mb2_transfer.lock);
 	init_completion(&mb2_transfer.work);
 	spin_lock_init(&mb2_transfer.auto_pm_lock);
@@ -2154,7 +2701,7 @@
 	}
 }
 
-static void __init db8500_prcmu_init_clkforce(void)
+static void __init init_prcm_registers(void)
 {
 	u32 val;
 
@@ -2186,19 +2733,17 @@
 	REGULATOR_SUPPLY("vcore", "uart1"),
 	REGULATOR_SUPPLY("vcore", "uart2"),
 	REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"),
+	REGULATOR_SUPPLY("v-hsi", "ste_hsi.0"),
 };
 
 static struct regulator_consumer_supply db8500_vsmps2_consumers[] = {
-	/* CG2900 and CW1200 power to off-chip peripherals */
-	REGULATOR_SUPPLY("gbf_1v8", "cg2900-uart.0"),
-	REGULATOR_SUPPLY("wlan_1v8", "cw1200.0"),
 	REGULATOR_SUPPLY("musb_1v8", "ab8500-usb.0"),
 	/* AV8100 regulator */
 	REGULATOR_SUPPLY("hdmi_1v8", "0-0070"),
 };
 
 static struct regulator_consumer_supply db8500_b2r2_mcde_consumers[] = {
-	REGULATOR_SUPPLY("vsupply", "b2r2.0"),
+	REGULATOR_SUPPLY("vsupply", "b2r2_bus"),
 	REGULATOR_SUPPLY("vsupply", "mcde"),
 };
 
@@ -2235,6 +2780,7 @@
 static struct regulator_consumer_supply db8500_esram34_consumers[] = {
 	REGULATOR_SUPPLY("v-esram34", "mcde"),
 	REGULATOR_SUPPLY("esram34", "cm_control"),
+	REGULATOR_SUPPLY("lcla_esram", "dma40.0"),
 };
 
 static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
@@ -2291,7 +2837,7 @@
 		},
 	},
 	[DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
-		.supply_regulator = "db8500-vape",
+		/* dependency to u8500-vape is handled outside regulator framework */
 		.constraints = {
 			.name = "db8500-sva-mmdsp",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2307,7 +2853,7 @@
 		},
 	},
 	[DB8500_REGULATOR_SWITCH_SVAPIPE] = {
-		.supply_regulator = "db8500-vape",
+		/* dependency to u8500-vape is handled outside regulator framework */
 		.constraints = {
 			.name = "db8500-sva-pipe",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2316,7 +2862,7 @@
 		.num_consumer_supplies = ARRAY_SIZE(db8500_svapipe_consumers),
 	},
 	[DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
-		.supply_regulator = "db8500-vape",
+		/* dependency to u8500-vape is handled outside regulator framework */
 		.constraints = {
 			.name = "db8500-sia-mmdsp",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2331,7 +2877,7 @@
 		},
 	},
 	[DB8500_REGULATOR_SWITCH_SIAPIPE] = {
-		.supply_regulator = "db8500-vape",
+		/* dependency to u8500-vape is handled outside regulator framework */
 		.constraints = {
 			.name = "db8500-sia-pipe",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2359,7 +2905,10 @@
 		.num_consumer_supplies = ARRAY_SIZE(db8500_b2r2_mcde_consumers),
 	},
 	[DB8500_REGULATOR_SWITCH_ESRAM12] = {
-		.supply_regulator = "db8500-vape",
+		/*
+		 * esram12 is set in retention and supplied by Vsafe when Vape is off,
+		 * no need to hold Vape
+		 */
 		.constraints = {
 			.name = "db8500-esram12",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2374,7 +2923,10 @@
 		},
 	},
 	[DB8500_REGULATOR_SWITCH_ESRAM34] = {
-		.supply_regulator = "db8500-vape",
+		/*
+		 * esram34 is set in retention and supplied by Vsafe when Vape is off,
+		 * no need to hold Vape
+		 */
 		.constraints = {
 			.name = "db8500-esram34",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2412,7 +2964,7 @@
 	if (ux500_is_svp())
 		return -ENODEV;
 
-	db8500_prcmu_init_clkforce();
+	init_prcm_registers();
 
 	/* Clean up the mailbox interrupts after pre-kernel code. */
 	writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
diff --git a/drivers/mfd/dbx500-prcmu-regs.h b/drivers/mfd/dbx500-prcmu-regs.h
index ec22e9f..3a0bf91 100644
--- a/drivers/mfd/dbx500-prcmu-regs.h
+++ b/drivers/mfd/dbx500-prcmu-regs.h
@@ -17,41 +17,41 @@
 
 #define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end))
 
-#define PRCM_SVACLK_MGT_OFF		0x008
-#define PRCM_SIACLK_MGT_OFF		0x00C
-#define PRCM_SGACLK_MGT_OFF		0x014
-#define PRCM_UARTCLK_MGT_OFF		0x018
-#define PRCM_MSP02CLK_MGT_OFF		0x01C
-#define PRCM_I2CCLK_MGT_OFF		0x020
-#define PRCM_SDMMCCLK_MGT_OFF		0x024
-#define PRCM_SLIMCLK_MGT_OFF		0x028
-#define PRCM_PER1CLK_MGT_OFF		0x02C
-#define PRCM_PER2CLK_MGT_OFF		0x030
-#define PRCM_PER3CLK_MGT_OFF		0x034
-#define PRCM_PER5CLK_MGT_OFF		0x038
-#define PRCM_PER6CLK_MGT_OFF		0x03C
-#define PRCM_PER7CLK_MGT_OFF		0x040
-#define PRCM_PWMCLK_MGT_OFF		0x044 /* for DB5500 */
-#define PRCM_IRDACLK_MGT_OFF		0x048 /* for DB5500 */
-#define PRCM_IRRCCLK_MGT_OFF		0x04C /* for DB5500 */
-#define PRCM_LCDCLK_MGT_OFF		0x044
-#define PRCM_BMLCLK_MGT_OFF		0x04C
-#define PRCM_HSITXCLK_MGT_OFF		0x050
-#define PRCM_HSIRXCLK_MGT_OFF		0x054
-#define PRCM_HDMICLK_MGT_OFF		0x058
-#define PRCM_APEATCLK_MGT_OFF		0x05C
-#define PRCM_APETRACECLK_MGT_OFF	0x060
-#define PRCM_MCDECLK_MGT_OFF		0x064
-#define PRCM_IPI2CCLK_MGT_OFF		0x068
-#define PRCM_DSIALTCLK_MGT_OFF		0x06C
-#define PRCM_DMACLK_MGT_OFF		0x074
-#define PRCM_B2R2CLK_MGT_OFF		0x078
-#define PRCM_TVCLK_MGT_OFF		0x07C
-#define PRCM_UNIPROCLK_MGT_OFF		0x278
-#define PRCM_SSPCLK_MGT_OFF		0x280
-#define PRCM_RNGCLK_MGT_OFF		0x284
-#define PRCM_UICCCLK_MGT_OFF		0x27C
-#define PRCM_MSP1CLK_MGT_OFF		0x288
+#define PRCM_CLK_MGT(_offset) (void __iomem *)(IO_ADDRESS(U8500_PRCMU_BASE) \
+	+ _offset)
+#define PRCM_ACLK_MGT		PRCM_CLK_MGT(0x004)
+#define PRCM_SVACLK_MGT		PRCM_CLK_MGT(0x008)
+#define PRCM_SIACLK_MGT		PRCM_CLK_MGT(0x00C)
+#define PRCM_SGACLK_MGT		PRCM_CLK_MGT(0x014)
+#define PRCM_UARTCLK_MGT	PRCM_CLK_MGT(0x018)
+#define PRCM_MSP02CLK_MGT	PRCM_CLK_MGT(0x01C)
+#define PRCM_I2CCLK_MGT		PRCM_CLK_MGT(0x020)
+#define PRCM_SDMMCCLK_MGT	PRCM_CLK_MGT(0x024)
+#define PRCM_SLIMCLK_MGT	PRCM_CLK_MGT(0x028)
+#define PRCM_PER1CLK_MGT	PRCM_CLK_MGT(0x02C)
+#define PRCM_PER2CLK_MGT	PRCM_CLK_MGT(0x030)
+#define PRCM_PER3CLK_MGT	PRCM_CLK_MGT(0x034)
+#define PRCM_PER5CLK_MGT	PRCM_CLK_MGT(0x038)
+#define PRCM_PER6CLK_MGT	PRCM_CLK_MGT(0x03C)
+#define PRCM_PER7CLK_MGT	PRCM_CLK_MGT(0x040)
+#define PRCM_LCDCLK_MGT		PRCM_CLK_MGT(0x044)
+#define PRCM_BMLCLK_MGT		PRCM_CLK_MGT(0x04C)
+#define PRCM_HSITXCLK_MGT	PRCM_CLK_MGT(0x050)
+#define PRCM_HSIRXCLK_MGT	PRCM_CLK_MGT(0x054)
+#define PRCM_HDMICLK_MGT	PRCM_CLK_MGT(0x058)
+#define PRCM_APEATCLK_MGT	PRCM_CLK_MGT(0x05C)
+#define PRCM_APETRACECLK_MGT	PRCM_CLK_MGT(0x060)
+#define PRCM_MCDECLK_MGT	PRCM_CLK_MGT(0x064)
+#define PRCM_IPI2CCLK_MGT	PRCM_CLK_MGT(0x068)
+#define PRCM_DSIALTCLK_MGT	PRCM_CLK_MGT(0x06C)
+#define PRCM_DMACLK_MGT		PRCM_CLK_MGT(0x074)
+#define PRCM_B2R2CLK_MGT	PRCM_CLK_MGT(0x078)
+#define PRCM_TVCLK_MGT		PRCM_CLK_MGT(0x07C)
+#define PRCM_UNIPROCLK_MGT	PRCM_CLK_MGT(0x278)
+#define PRCM_SSPCLK_MGT		PRCM_CLK_MGT(0x280)
+#define PRCM_RNGCLK_MGT		PRCM_CLK_MGT(0x284)
+#define PRCM_UICCCLK_MGT	PRCM_CLK_MGT(0x27C)
+#define PRCM_MSP1CLK_MGT	PRCM_CLK_MGT(0x288)
 
 #define PRCM_ARM_PLLDIVPS	(_PRCMU_BASE + 0x118)
 #define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE		0x3f
@@ -79,6 +79,8 @@
 
 /* ARM WFI Standby signal register */
 #define PRCM_ARM_WFI_STANDBY    (_PRCMU_BASE + 0x130)
+#define PRCM_ARM_WFI_STANDBY_WFI0               0x08
+#define PRCM_ARM_WFI_STANDBY_WFI1               0x10
 #define PRCM_IOCR		(_PRCMU_BASE + 0x310)
 #define PRCM_IOCR_IOFORCE			0x1
 
@@ -131,20 +133,58 @@
 #define PRCM_MMIP_LS_CLAMP_SET     (_PRCMU_BASE + 0x420)
 #define PRCM_MMIP_LS_CLAMP_CLR     (_PRCMU_BASE + 0x424)
 
+#define PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP		BIT(11)
+#define PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI	BIT(22)
+
 /* PRCMU clock/PLL/reset registers */
+#define PRCM_PLLSOC0_FREQ	   (_PRCMU_BASE + 0x080)
+#define PRCM_PLLSOC1_FREQ	   (_PRCMU_BASE + 0x084)
+#define PRCM_PLLDDR_FREQ	   (_PRCMU_BASE + 0x08C)
+#define PRCM_PLL_FREQ_D_SHIFT	0
+#define PRCM_PLL_FREQ_D_MASK	BITS(0, 7)
+#define PRCM_PLL_FREQ_N_SHIFT	8
+#define PRCM_PLL_FREQ_N_MASK	BITS(8, 13)
+#define PRCM_PLL_FREQ_R_SHIFT	16
+#define PRCM_PLL_FREQ_R_MASK	BITS(16, 18)
+#define PRCM_PLL_FREQ_SELDIV2	BIT(24)
+#define PRCM_PLL_FREQ_DIV2EN	BIT(25)
+
 #define PRCM_PLLDSI_FREQ           (_PRCMU_BASE + 0x500)
 #define PRCM_PLLDSI_ENABLE         (_PRCMU_BASE + 0x504)
 #define PRCM_PLLDSI_LOCKP          (_PRCMU_BASE + 0x508)
-#define PRCM_LCDCLK_MGT            (_PRCMU_BASE + PRCM_LCDCLK_MGT_OFF)
-#define PRCM_MCDECLK_MGT           (_PRCMU_BASE + PRCM_MCDECLK_MGT_OFF)
-#define PRCM_HDMICLK_MGT           (_PRCMU_BASE + PRCM_HDMICLK_MGT_OFF)
-#define PRCM_TVCLK_MGT             (_PRCMU_BASE + PRCM_TVCLK_MGT_OFF)
 #define PRCM_DSI_PLLOUT_SEL        (_PRCMU_BASE + 0x530)
 #define PRCM_DSITVCLK_DIV          (_PRCMU_BASE + 0x52C)
 #define PRCM_PLLDSI_LOCKP          (_PRCMU_BASE + 0x508)
 #define PRCM_APE_RESETN_SET        (_PRCMU_BASE + 0x1E4)
 #define PRCM_APE_RESETN_CLR        (_PRCMU_BASE + 0x1E8)
 
+#define PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE BIT(0)
+
+#define PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10	BIT(0)
+#define PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3	BIT(1)
+
+#define PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_SHIFT	0
+#define PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_MASK	BITS(0, 2)
+#define PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_SHIFT	8
+#define PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_MASK	BITS(8, 10)
+
+#define PRCM_DSI_PLLOUT_SEL_OFF		0
+#define PRCM_DSI_PLLOUT_SEL_PHI		1
+#define PRCM_DSI_PLLOUT_SEL_PHI_2	2
+#define PRCM_DSI_PLLOUT_SEL_PHI_4	3
+
+#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_SHIFT	0
+#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_MASK		BITS(0, 7)
+#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_SHIFT	8
+#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_MASK		BITS(8, 15)
+#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_SHIFT	16
+#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_MASK		BITS(16, 23)
+#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_EN		BIT(24)
+#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_EN		BIT(25)
+#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_EN		BIT(26)
+
+#define PRCM_APE_RESETN_DSIPLL_RESETN BIT(14)
+
 #define PRCM_CLKOCR		   (_PRCMU_BASE + 0x1CC)
 #define PRCM_CLKOCR_CLKOUT0_REF_CLK	(1 << 0)
 #define PRCM_CLKOCR_CLKOUT0_MASK	BITS(0, 13)
@@ -183,9 +223,15 @@
 #define PRCM_CLKOCR_CLKOSEL1_MASK	BITS(22, 24)
 #define PRCM_CLKOCR_CLK1TYPE		BIT(28)
 
-#define PRCM_CLK_MGT_CLKPLLDIV_MASK	BITS(0, 4)
-#define PRCM_CLK_MGT_CLKPLLSW_MASK	BITS(5, 7)
-#define PRCM_CLK_MGT_CLKEN		BIT(8)
+#define PRCM_CLK_MGT_CLKPLLDIV_MASK		BITS(0, 4)
+#define PRCM_CLK_MGT_CLKPLLSW_SOC0		BIT(5)
+#define PRCM_CLK_MGT_CLKPLLSW_SOC1		BIT(6)
+#define PRCM_CLK_MGT_CLKPLLSW_DDR		BIT(7)
+#define PRCM_CLK_MGT_CLKPLLSW_MASK		BITS(5, 7)
+#define PRCM_CLK_MGT_CLKEN			BIT(8)
+#define PRCM_CLK_MGT_CLK38			BIT(9)
+#define PRCM_CLK_MGT_CLK38DIV			BIT(11)
+#define PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN	BIT(12)
 
 /* GPIOCR register */
 #define PRCM_GPIOCR_SPI2_SELECT BIT(23)
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index 7122386..9fd4f63 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -560,6 +560,8 @@
 
 #define MC13XXX_ADC1_CHAN0_SHIFT	5
 #define MC13XXX_ADC1_CHAN1_SHIFT	8
+#define MC13783_ADC1_ATO_SHIFT		11
+#define MC13783_ADC1_ATOX		(1 << 19)
 
 struct mc13xxx_adcdone_data {
 	struct mc13xxx *mc13xxx;
@@ -580,7 +582,8 @@
 #define MC13XXX_ADC_WORKING (1 << 0)
 
 int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
-		unsigned int channel, unsigned int *sample)
+		unsigned int channel, u8 ato, bool atox,
+		unsigned int *sample)
 {
 	u32 adc0, adc1, old_adc0;
 	int i, ret;
@@ -631,6 +634,9 @@
 		return -EINVAL;
 	}
 
+	adc1 |= ato << MC13783_ADC1_ATO_SHIFT;
+	if (atox)
+		adc1 |= MC13783_ADC1_ATOX;
 	dev_dbg(&mc13xxx->spidev->dev, "%s: request irq\n", __func__);
 	mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE,
 			mc13xxx_handler_adcdone, __func__, &adcdone_data);
@@ -813,7 +819,8 @@
 		mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
 
 	if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
-		mc13xxx_add_subdevice(mc13xxx, "%s-ts");
+		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts",
+				&pdata->touch, sizeof(pdata->touch));
 
 	if (pdata) {
 		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index 86cc3f7..62e5e36 100644
--- a/drivers/mfd/mcp-core.c
+++ b/drivers/mfd/mcp-core.c
@@ -19,9 +19,6 @@
 #include <linux/string.h>
 #include <linux/mfd/mcp.h>
 
-#include <mach/dma.h>
-#include <asm/system.h>
-
 
 #define to_mcp(d)		container_of(d, struct mcp, attached_device)
 #define to_mcp_driver(d)	container_of(d, struct mcp_driver, drv)
@@ -48,39 +45,11 @@
 	return 0;
 }
 
-static int mcp_bus_suspend(struct device *dev, pm_message_t state)
-{
-	struct mcp *mcp = to_mcp(dev);
-	int ret = 0;
-
-	if (dev->driver) {
-		struct mcp_driver *drv = to_mcp_driver(dev->driver);
-
-		ret = drv->suspend(mcp, state);
-	}
-	return ret;
-}
-
-static int mcp_bus_resume(struct device *dev)
-{
-	struct mcp *mcp = to_mcp(dev);
-	int ret = 0;
-
-	if (dev->driver) {
-		struct mcp_driver *drv = to_mcp_driver(dev->driver);
-
-		ret = drv->resume(mcp);
-	}
-	return ret;
-}
-
 static struct bus_type mcp_bus_type = {
 	.name		= "mcp",
 	.match		= mcp_bus_match,
 	.probe		= mcp_bus_probe,
 	.remove		= mcp_bus_remove,
-	.suspend	= mcp_bus_suspend,
-	.resume		= mcp_bus_resume,
 };
 
 /**
@@ -208,6 +177,7 @@
 	mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL);
 	if (mcp) {
 		spin_lock_init(&mcp->lock);
+		device_initialize(&mcp->attached_device);
 		mcp->attached_device.parent = parent;
 		mcp->attached_device.bus = &mcp_bus_type;
 		mcp->attached_device.dma_mask = parent->dma_mask;
@@ -217,18 +187,25 @@
 }
 EXPORT_SYMBOL(mcp_host_alloc);
 
-int mcp_host_register(struct mcp *mcp)
+int mcp_host_add(struct mcp *mcp, void *pdata)
 {
+	mcp->attached_device.platform_data = pdata;
 	dev_set_name(&mcp->attached_device, "mcp0");
-	return device_register(&mcp->attached_device);
+	return device_add(&mcp->attached_device);
 }
-EXPORT_SYMBOL(mcp_host_register);
+EXPORT_SYMBOL(mcp_host_add);
 
-void mcp_host_unregister(struct mcp *mcp)
+void mcp_host_del(struct mcp *mcp)
 {
-	device_unregister(&mcp->attached_device);
+	device_del(&mcp->attached_device);
 }
-EXPORT_SYMBOL(mcp_host_unregister);
+EXPORT_SYMBOL(mcp_host_del);
+
+void mcp_host_free(struct mcp *mcp)
+{
+	put_device(&mcp->attached_device);
+}
+EXPORT_SYMBOL(mcp_host_free);
 
 int mcp_driver_register(struct mcp_driver *mcpdrv)
 {
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 02c53a0..c54e244 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -13,51 +13,60 @@
  */
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
 #include <linux/mfd/mcp.h>
 
-#include <mach/dma.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/system.h>
 #include <mach/mcp.h>
 
-#include <mach/assabet.h>
-
+#define DRIVER_NAME "sa11x0-mcp"
 
 struct mcp_sa11x0 {
-	u32	mccr0;
-	u32	mccr1;
+	void __iomem	*base0;
+	void __iomem	*base1;
+	u32		mccr0;
+	u32		mccr1;
 };
 
+/* Register offsets */
+#define MCCR0(m)	((m)->base0 + 0x00)
+#define MCDR0(m)	((m)->base0 + 0x08)
+#define MCDR1(m)	((m)->base0 + 0x0c)
+#define MCDR2(m)	((m)->base0 + 0x10)
+#define MCSR(m)		((m)->base0 + 0x18)
+#define MCCR1(m)	((m)->base1 + 0x00)
+
 #define priv(mcp)	((struct mcp_sa11x0 *)mcp_priv(mcp))
 
 static void
 mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
 {
-	unsigned int mccr0;
+	struct mcp_sa11x0 *m = priv(mcp);
 
 	divisor /= 32;
 
-	mccr0 = Ser4MCCR0 & ~0x00007f00;
-	mccr0 |= divisor << 8;
-	Ser4MCCR0 = mccr0;
+	m->mccr0 &= ~0x00007f00;
+	m->mccr0 |= divisor << 8;
+	writel_relaxed(m->mccr0, MCCR0(m));
 }
 
 static void
 mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
 {
-	unsigned int mccr0;
+	struct mcp_sa11x0 *m = priv(mcp);
 
 	divisor /= 32;
 
-	mccr0 = Ser4MCCR0 & ~0x0000007f;
-	mccr0 |= divisor;
-	Ser4MCCR0 = mccr0;
+	m->mccr0 &= ~0x0000007f;
+	m->mccr0 |= divisor;
+	writel_relaxed(m->mccr0, MCCR0(m));
 }
 
 /*
@@ -69,14 +78,15 @@
 static void
 mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
 {
+	struct mcp_sa11x0 *m = priv(mcp);
 	int ret = -ETIME;
 	int i;
 
-	Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
+	writel_relaxed(reg << 17 | MCDR2_Wr | (val & 0xffff), MCDR2(m));
 
 	for (i = 0; i < 2; i++) {
 		udelay(mcp->rw_timeout);
-		if (Ser4MCSR & MCSR_CWC) {
+		if (readl_relaxed(MCSR(m)) & MCSR_CWC) {
 			ret = 0;
 			break;
 		}
@@ -95,15 +105,16 @@
 static unsigned int
 mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
 {
+	struct mcp_sa11x0 *m = priv(mcp);
 	int ret = -ETIME;
 	int i;
 
-	Ser4MCDR2 = reg << 17 | MCDR2_Rd;
+	writel_relaxed(reg << 17 | MCDR2_Rd, MCDR2(m));
 
 	for (i = 0; i < 2; i++) {
 		udelay(mcp->rw_timeout);
-		if (Ser4MCSR & MCSR_CRC) {
-			ret = Ser4MCDR2 & 0xffff;
+		if (readl_relaxed(MCSR(m)) & MCSR_CRC) {
+			ret = readl_relaxed(MCDR2(m)) & 0xffff;
 			break;
 		}
 	}
@@ -116,13 +127,19 @@
 
 static void mcp_sa11x0_enable(struct mcp *mcp)
 {
-	Ser4MCSR = -1;
-	Ser4MCCR0 |= MCCR0_MCE;
+	struct mcp_sa11x0 *m = priv(mcp);
+
+	writel(-1, MCSR(m));
+	m->mccr0 |= MCCR0_MCE;
+	writel_relaxed(m->mccr0, MCCR0(m));
 }
 
 static void mcp_sa11x0_disable(struct mcp *mcp)
 {
-	Ser4MCCR0 &= ~MCCR0_MCE;
+	struct mcp_sa11x0 *m = priv(mcp);
+
+	m->mccr0 &= ~MCCR0_MCE;
+	writel_relaxed(m->mccr0, MCCR0(m));
 }
 
 /*
@@ -137,55 +154,64 @@
 	.disable		= mcp_sa11x0_disable,
 };
 
-static int mcp_sa11x0_probe(struct platform_device *pdev)
+static int mcp_sa11x0_probe(struct platform_device *dev)
 {
-	struct mcp_plat_data *data = pdev->dev.platform_data;
+	struct mcp_plat_data *data = dev->dev.platform_data;
+	struct resource *mem0, *mem1;
+	struct mcp_sa11x0 *m;
 	struct mcp *mcp;
 	int ret;
 
 	if (!data)
 		return -ENODEV;
 
-	if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
-		return -EBUSY;
+	mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
+	if (!mem0 || !mem1)
+		return -ENXIO;
 
-	mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
+	if (!request_mem_region(mem0->start, resource_size(mem0),
+				DRIVER_NAME)) {
+		ret = -EBUSY;
+		goto err_mem0;
+	}
+
+	if (!request_mem_region(mem1->start, resource_size(mem1),
+				DRIVER_NAME)) {
+		ret = -EBUSY;
+		goto err_mem1;
+	}
+
+	mcp = mcp_host_alloc(&dev->dev, sizeof(struct mcp_sa11x0));
 	if (!mcp) {
 		ret = -ENOMEM;
-		goto release;
+		goto err_alloc;
 	}
 
 	mcp->owner		= THIS_MODULE;
 	mcp->ops		= &mcp_sa11x0;
 	mcp->sclk_rate		= data->sclk_rate;
-	mcp->dma_audio_rd	= DMA_Ser4MCP0Rd;
-	mcp->dma_audio_wr	= DMA_Ser4MCP0Wr;
-	mcp->dma_telco_rd	= DMA_Ser4MCP1Rd;
-	mcp->dma_telco_wr	= DMA_Ser4MCP1Wr;
-	mcp->gpio_base		= data->gpio_base;
 
-	platform_set_drvdata(pdev, mcp);
+	m = priv(mcp);
+	m->mccr0 = data->mccr0 | 0x7f7f;
+	m->mccr1 = data->mccr1;
 
-	if (machine_is_assabet()) {
-		ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
+	m->base0 = ioremap(mem0->start, resource_size(mem0));
+	m->base1 = ioremap(mem1->start, resource_size(mem1));
+	if (!m->base0 || !m->base1) {
+		ret = -ENOMEM;
+		goto err_ioremap;
 	}
 
-	/*
-	 * Setup the PPC unit correctly.
-	 */
-	PPDR &= ~PPC_RXD4;
-	PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
-	PSDR |= PPC_RXD4;
-	PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
-	PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+	platform_set_drvdata(dev, mcp);
 
 	/*
 	 * Initialise device.  Note that we initially
 	 * set the sampling rate to minimum.
 	 */
-	Ser4MCSR = -1;
-	Ser4MCCR1 = data->mccr1;
-	Ser4MCCR0 = data->mccr0 | 0x7f7f;
+	writel_relaxed(-1, MCSR(m));
+	writel_relaxed(m->mccr1, MCCR1(m));
+	writel_relaxed(m->mccr0, MCCR0(m));
 
 	/*
 	 * Calculate the read/write timeout (us) from the bit clock
@@ -195,62 +221,90 @@
 	mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
 			  mcp->sclk_rate;
 
-	ret = mcp_host_register(mcp);
+	ret = mcp_host_add(mcp, data->codec_pdata);
 	if (ret == 0)
-		goto out;
+		return 0;
 
- release:
-	release_mem_region(0x80060000, 0x60);
-	platform_set_drvdata(pdev, NULL);
+	platform_set_drvdata(dev, NULL);
 
- out:
+ err_ioremap:
+	iounmap(m->base1);
+	iounmap(m->base0);
+	mcp_host_free(mcp);
+ err_alloc:
+	release_mem_region(mem1->start, resource_size(mem1));
+ err_mem1:
+	release_mem_region(mem0->start, resource_size(mem0));
+ err_mem0:
 	return ret;
 }
 
 static int mcp_sa11x0_remove(struct platform_device *dev)
 {
 	struct mcp *mcp = platform_get_drvdata(dev);
+	struct mcp_sa11x0 *m = priv(mcp);
+	struct resource *mem0, *mem1;
+
+	if (m->mccr0 & MCCR0_MCE)
+		dev_warn(&dev->dev,
+			 "device left active (missing disable call?)\n");
+
+	mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
 
 	platform_set_drvdata(dev, NULL);
-	mcp_host_unregister(mcp);
-	release_mem_region(0x80060000, 0x60);
+	mcp_host_del(mcp);
+	iounmap(m->base1);
+	iounmap(m->base0);
+	mcp_host_free(mcp);
+	release_mem_region(mem1->start, resource_size(mem1));
+	release_mem_region(mem0->start, resource_size(mem0));
 
 	return 0;
 }
 
-static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int mcp_sa11x0_suspend(struct device *dev)
 {
-	struct mcp *mcp = platform_get_drvdata(dev);
+	struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
 
-	priv(mcp)->mccr0 = Ser4MCCR0;
-	priv(mcp)->mccr1 = Ser4MCCR1;
-	Ser4MCCR0 &= ~MCCR0_MCE;
+	if (m->mccr0 & MCCR0_MCE)
+		dev_warn(dev, "device left active (missing disable call?)\n");
+
+	writel(m->mccr0 & ~MCCR0_MCE, MCCR0(m));
 
 	return 0;
 }
 
-static int mcp_sa11x0_resume(struct platform_device *dev)
+static int mcp_sa11x0_resume(struct device *dev)
 {
-	struct mcp *mcp = platform_get_drvdata(dev);
+	struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
 
-	Ser4MCCR1 = priv(mcp)->mccr1;
-	Ser4MCCR0 = priv(mcp)->mccr0;
+	writel_relaxed(m->mccr1, MCCR1(m));
+	writel_relaxed(m->mccr0, MCCR0(m));
 
 	return 0;
 }
+#endif
 
-/*
- * The driver for the SA11x0 MCP port.
- */
-MODULE_ALIAS("platform:sa11x0-mcp");
+static const struct dev_pm_ops mcp_sa11x0_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+	.suspend = mcp_sa11x0_suspend,
+	.freeze = mcp_sa11x0_suspend,
+	.poweroff = mcp_sa11x0_suspend,
+	.resume_noirq = mcp_sa11x0_resume,
+	.thaw_noirq = mcp_sa11x0_resume,
+	.restore_noirq = mcp_sa11x0_resume,
+#endif
+};
 
 static struct platform_driver mcp_sa11x0_driver = {
 	.probe		= mcp_sa11x0_probe,
 	.remove		= mcp_sa11x0_remove,
-	.suspend	= mcp_sa11x0_suspend,
-	.resume		= mcp_sa11x0_resume,
 	.driver		= {
-		.name	= "sa11x0-mcp",
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= &mcp_sa11x0_pm_ops,
 	},
 };
 
@@ -259,6 +313,7 @@
  */
 module_platform_driver(mcp_sa11x0_driver);
 
+MODULE_ALIAS("platform:" DRIVER_NAME);
 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 411f523..ffc3d48 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -162,7 +162,7 @@
 	atomic_t *cnts;
 
 	/* initialize reference counting for all cells */
-	cnts = kcalloc(sizeof(*cnts), n_devs, GFP_KERNEL);
+	cnts = kcalloc(n_devs, sizeof(*cnts), GFP_KERNEL);
 	if (!cnts)
 		return -ENOMEM;
 
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 68ac2c5..95a2e54 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -170,7 +170,7 @@
 /*-------------------------------------------------------------------------*/
 
 const char usbhs_driver_name[] = USBHS_DRIVER_NAME;
-static u64 usbhs_dmamask = ~(u32)0;
+static u64 usbhs_dmamask = DMA_BIT_MASK(32);
 
 /*-------------------------------------------------------------------------*/
 
@@ -223,7 +223,7 @@
 	}
 
 	child->dev.dma_mask		= &usbhs_dmamask;
-	child->dev.coherent_dma_mask	= 0xffffffff;
+	dma_set_coherent_mask(&child->dev, DMA_BIT_MASK(32));
 	child->dev.parent		= dev;
 
 	ret = platform_device_add(child);
@@ -799,14 +799,13 @@
 
 	platform_set_drvdata(pdev, omap);
 
+	omap_usbhs_init(dev);
 	ret = omap_usbhs_alloc_children(pdev);
 	if (ret) {
 		dev_err(dev, "omap_usbhs_alloc_children failed\n");
 		goto err_alloc;
 	}
 
-	omap_usbhs_init(dev);
-
 	goto end_probe;
 
 err_alloc:
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c
index ff1a7e7..189c2f0 100644
--- a/drivers/mfd/pcf50633-core.c
+++ b/drivers/mfd/pcf50633-core.c
@@ -46,13 +46,7 @@
 int pcf50633_write_block(struct pcf50633 *pcf , u8 reg,
 					int nr_regs, u8 *data)
 {
-	int ret;
-
-	ret = regmap_raw_write(pcf->regmap, reg, data, nr_regs);
-	if (ret != 0)
-		return ret;
-
-	return nr_regs;
+	return regmap_raw_write(pcf->regmap, reg, data, nr_regs);
 }
 EXPORT_SYMBOL_GPL(pcf50633_write_block);
 
diff --git a/drivers/mfd/pcf50633-gpio.c b/drivers/mfd/pcf50633-gpio.c
index 9ab19a8..d02ddf2 100644
--- a/drivers/mfd/pcf50633-gpio.c
+++ b/drivers/mfd/pcf50633-gpio.c
@@ -19,32 +19,7 @@
 
 #include <linux/mfd/pcf50633/core.h>
 #include <linux/mfd/pcf50633/gpio.h>
-
-enum pcf50633_regulator_id {
-	PCF50633_REGULATOR_AUTO,
-	PCF50633_REGULATOR_DOWN1,
-	PCF50633_REGULATOR_DOWN2,
-	PCF50633_REGULATOR_LDO1,
-	PCF50633_REGULATOR_LDO2,
-	PCF50633_REGULATOR_LDO3,
-	PCF50633_REGULATOR_LDO4,
-	PCF50633_REGULATOR_LDO5,
-	PCF50633_REGULATOR_LDO6,
-	PCF50633_REGULATOR_HCLDO,
-	PCF50633_REGULATOR_MEMLDO,
-};
-
-#define PCF50633_REG_AUTOOUT	0x1a
-#define PCF50633_REG_DOWN1OUT	0x1e
-#define PCF50633_REG_DOWN2OUT	0x22
-#define PCF50633_REG_MEMLDOOUT	0x26
-#define PCF50633_REG_LDO1OUT	0x2d
-#define PCF50633_REG_LDO2OUT	0x2f
-#define PCF50633_REG_LDO3OUT	0x31
-#define PCF50633_REG_LDO4OUT	0x33
-#define PCF50633_REG_LDO5OUT	0x35
-#define PCF50633_REG_LDO6OUT	0x37
-#define PCF50633_REG_HCLDOOUT	0x39
+#include <linux/mfd/pcf50633/pmic.h>
 
 static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = {
 	[PCF50633_REGULATOR_AUTO]	= PCF50633_REG_AUTOOUT,
diff --git a/drivers/mfd/pcf50633-irq.c b/drivers/mfd/pcf50633-irq.c
index 048a3b9..498286c 100644
--- a/drivers/mfd/pcf50633-irq.c
+++ b/drivers/mfd/pcf50633-irq.c
@@ -19,12 +19,7 @@
 #include <linux/slab.h>
 
 #include <linux/mfd/pcf50633/core.h>
-
-/* Two MBCS registers used during cold start */
-#define PCF50633_REG_MBCS1		0x4b
-#define PCF50633_REG_MBCS2		0x4c
-#define PCF50633_MBCS1_USBPRES 		0x01
-#define PCF50633_MBCS1_ADAPTPRES	0x01
+#include <linux/mfd/pcf50633/mbc.h>
 
 int pcf50633_register_irq(struct pcf50633 *pcf, int irq,
 			void (*handler) (int, void *), void *data)
diff --git a/drivers/mfd/rc5t583-irq.c b/drivers/mfd/rc5t583-irq.c
new file mode 100644
index 0000000..fa6f80f
--- /dev/null
+++ b/drivers/mfd/rc5t583-irq.c
@@ -0,0 +1,408 @@
+/*
+ * Interrupt driver for RICOH583 power management chip.
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * based on code
+ *      Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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/interrupt.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mfd/rc5t583.h>
+
+enum int_type {
+	SYS_INT  = 0x1,
+	DCDC_INT = 0x2,
+	RTC_INT  = 0x4,
+	ADC_INT  = 0x8,
+	GPIO_INT = 0x10,
+};
+
+static int gpedge_add[] = {
+	RC5T583_GPIO_GPEDGE2,
+	RC5T583_GPIO_GPEDGE2
+};
+
+static int irq_en_add[] = {
+	RC5T583_INT_EN_SYS1,
+	RC5T583_INT_EN_SYS2,
+	RC5T583_INT_EN_DCDC,
+	RC5T583_INT_EN_RTC,
+	RC5T583_INT_EN_ADC1,
+	RC5T583_INT_EN_ADC2,
+	RC5T583_INT_EN_ADC3,
+	RC5T583_GPIO_EN_INT
+};
+
+static int irq_mon_add[] = {
+	RC5T583_INT_MON_SYS1,
+	RC5T583_INT_MON_SYS2,
+	RC5T583_INT_MON_DCDC,
+	RC5T583_INT_MON_RTC,
+	RC5T583_INT_IR_ADCL,
+	RC5T583_INT_IR_ADCH,
+	RC5T583_INT_IR_ADCEND,
+	RC5T583_INT_IR_GPIOF,
+	RC5T583_INT_IR_GPIOR
+};
+
+static int irq_clr_add[] = {
+	RC5T583_INT_IR_SYS1,
+	RC5T583_INT_IR_SYS2,
+	RC5T583_INT_IR_DCDC,
+	RC5T583_INT_IR_RTC,
+	RC5T583_INT_IR_ADCL,
+	RC5T583_INT_IR_ADCH,
+	RC5T583_INT_IR_ADCEND,
+	RC5T583_INT_IR_GPIOF,
+	RC5T583_INT_IR_GPIOR
+};
+
+static int main_int_type[] = {
+	SYS_INT,
+	SYS_INT,
+	DCDC_INT,
+	RTC_INT,
+	ADC_INT,
+	ADC_INT,
+	ADC_INT,
+	GPIO_INT,
+	GPIO_INT,
+};
+
+struct rc5t583_irq_data {
+	u8	int_type;
+	u8	master_bit;
+	u8	int_en_bit;
+	u8	mask_reg_index;
+	int	grp_index;
+};
+
+#define RC5T583_IRQ(_int_type, _master_bit, _grp_index, \
+			_int_bit, _mask_ind)		\
+	{						\
+		.int_type	= _int_type,		\
+		.master_bit	= _master_bit,		\
+		.grp_index	= _grp_index,		\
+		.int_en_bit	= _int_bit,		\
+		.mask_reg_index	= _mask_ind,		\
+	}
+
+static const struct rc5t583_irq_data rc5t583_irqs[RC5T583_MAX_IRQS] = {
+	[RC5T583_IRQ_ONKEY]		= RC5T583_IRQ(SYS_INT,  0, 0, 0, 0),
+	[RC5T583_IRQ_ACOK]		= RC5T583_IRQ(SYS_INT,  0, 1, 1, 0),
+	[RC5T583_IRQ_LIDOPEN]		= RC5T583_IRQ(SYS_INT,  0, 2, 2, 0),
+	[RC5T583_IRQ_PREOT]		= RC5T583_IRQ(SYS_INT,  0, 3, 3, 0),
+	[RC5T583_IRQ_CLKSTP]		= RC5T583_IRQ(SYS_INT,  0, 4, 4, 0),
+	[RC5T583_IRQ_ONKEY_OFF]		= RC5T583_IRQ(SYS_INT,  0, 5, 5, 0),
+	[RC5T583_IRQ_WD]		= RC5T583_IRQ(SYS_INT,  0, 7, 7, 0),
+	[RC5T583_IRQ_EN_PWRREQ1]	= RC5T583_IRQ(SYS_INT,  0, 8, 0, 1),
+	[RC5T583_IRQ_EN_PWRREQ2]	= RC5T583_IRQ(SYS_INT,  0, 9, 1, 1),
+	[RC5T583_IRQ_PRE_VINDET]	= RC5T583_IRQ(SYS_INT,  0, 10, 2, 1),
+
+	[RC5T583_IRQ_DC0LIM]		= RC5T583_IRQ(DCDC_INT, 1, 0, 0, 2),
+	[RC5T583_IRQ_DC1LIM]		= RC5T583_IRQ(DCDC_INT, 1, 1, 1, 2),
+	[RC5T583_IRQ_DC2LIM]		= RC5T583_IRQ(DCDC_INT, 1, 2, 2, 2),
+	[RC5T583_IRQ_DC3LIM]		= RC5T583_IRQ(DCDC_INT, 1, 3, 3, 2),
+
+	[RC5T583_IRQ_CTC]		= RC5T583_IRQ(RTC_INT,  2, 0, 0, 3),
+	[RC5T583_IRQ_YALE]		= RC5T583_IRQ(RTC_INT,  2, 5, 5, 3),
+	[RC5T583_IRQ_DALE]		= RC5T583_IRQ(RTC_INT,  2, 6, 6, 3),
+	[RC5T583_IRQ_WALE]		= RC5T583_IRQ(RTC_INT,  2, 7, 7, 3),
+
+	[RC5T583_IRQ_AIN1L]		= RC5T583_IRQ(ADC_INT,  3, 0, 0, 4),
+	[RC5T583_IRQ_AIN2L]		= RC5T583_IRQ(ADC_INT,  3, 1, 1, 4),
+	[RC5T583_IRQ_AIN3L]		= RC5T583_IRQ(ADC_INT,  3, 2, 2, 4),
+	[RC5T583_IRQ_VBATL]		= RC5T583_IRQ(ADC_INT,  3, 3, 3, 4),
+	[RC5T583_IRQ_VIN3L]		= RC5T583_IRQ(ADC_INT,  3, 4, 4, 4),
+	[RC5T583_IRQ_VIN8L]		= RC5T583_IRQ(ADC_INT,  3, 5, 5, 4),
+	[RC5T583_IRQ_AIN1H]		= RC5T583_IRQ(ADC_INT,  3, 6, 0, 5),
+	[RC5T583_IRQ_AIN2H]		= RC5T583_IRQ(ADC_INT,  3, 7, 1, 5),
+	[RC5T583_IRQ_AIN3H]		= RC5T583_IRQ(ADC_INT,  3, 8, 2, 5),
+	[RC5T583_IRQ_VBATH]		= RC5T583_IRQ(ADC_INT,  3, 9, 3, 5),
+	[RC5T583_IRQ_VIN3H]		= RC5T583_IRQ(ADC_INT,  3, 10, 4, 5),
+	[RC5T583_IRQ_VIN8H]		= RC5T583_IRQ(ADC_INT,  3, 11, 5, 5),
+	[RC5T583_IRQ_ADCEND]		= RC5T583_IRQ(ADC_INT,  3, 12, 0, 6),
+
+	[RC5T583_IRQ_GPIO0]		= RC5T583_IRQ(GPIO_INT, 4, 0, 0, 7),
+	[RC5T583_IRQ_GPIO1]		= RC5T583_IRQ(GPIO_INT, 4, 1, 1, 7),
+	[RC5T583_IRQ_GPIO2]		= RC5T583_IRQ(GPIO_INT, 4, 2, 2, 7),
+	[RC5T583_IRQ_GPIO3]		= RC5T583_IRQ(GPIO_INT, 4, 3, 3, 7),
+	[RC5T583_IRQ_GPIO4]		= RC5T583_IRQ(GPIO_INT, 4, 4, 4, 7),
+	[RC5T583_IRQ_GPIO5]		= RC5T583_IRQ(GPIO_INT, 4, 5, 5, 7),
+	[RC5T583_IRQ_GPIO6]		= RC5T583_IRQ(GPIO_INT, 4, 6, 6, 7),
+	[RC5T583_IRQ_GPIO7]		= RC5T583_IRQ(GPIO_INT, 4, 7, 7, 7),
+};
+
+static void rc5t583_irq_lock(struct irq_data *irq_data)
+{
+	struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+	mutex_lock(&rc5t583->irq_lock);
+}
+
+static void rc5t583_irq_unmask(struct irq_data *irq_data)
+{
+	struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+	unsigned int __irq = irq_data->irq - rc5t583->irq_base;
+	const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
+
+	rc5t583->group_irq_en[data->grp_index] |= 1 << data->grp_index;
+	rc5t583->intc_inten_reg |= 1 << data->master_bit;
+	rc5t583->irq_en_reg[data->mask_reg_index] |= 1 << data->int_en_bit;
+}
+
+static void rc5t583_irq_mask(struct irq_data *irq_data)
+{
+	struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+	unsigned int __irq = irq_data->irq - rc5t583->irq_base;
+	const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
+
+	rc5t583->group_irq_en[data->grp_index] &= ~(1 << data->grp_index);
+	if (!rc5t583->group_irq_en[data->grp_index])
+		rc5t583->intc_inten_reg &= ~(1 << data->master_bit);
+
+	rc5t583->irq_en_reg[data->mask_reg_index] &= ~(1 << data->int_en_bit);
+}
+
+static int rc5t583_irq_set_type(struct irq_data *irq_data, unsigned int type)
+{
+	struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+	unsigned int __irq = irq_data->irq - rc5t583->irq_base;
+	const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
+	int val = 0;
+	int gpedge_index;
+	int gpedge_bit_pos;
+
+	/* Supporting only trigger level inetrrupt */
+	if ((data->int_type & GPIO_INT) && (type & IRQ_TYPE_EDGE_BOTH)) {
+		gpedge_index = data->int_en_bit / 4;
+		gpedge_bit_pos = data->int_en_bit % 4;
+
+		if (type & IRQ_TYPE_EDGE_FALLING)
+			val |= 0x2;
+
+		if (type & IRQ_TYPE_EDGE_RISING)
+			val |= 0x1;
+
+		rc5t583->gpedge_reg[gpedge_index] &= ~(3 << gpedge_bit_pos);
+		rc5t583->gpedge_reg[gpedge_index] |= (val << gpedge_bit_pos);
+		rc5t583_irq_unmask(irq_data);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static void rc5t583_irq_sync_unlock(struct irq_data *irq_data)
+{
+	struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+	int i;
+	int ret;
+
+	for (i = 0; i < ARRAY_SIZE(rc5t583->gpedge_reg); i++) {
+		ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
+				rc5t583->gpedge_reg[i]);
+		if (ret < 0)
+			dev_warn(rc5t583->dev,
+				"Error in writing reg 0x%02x error: %d\n",
+				gpedge_add[i], ret);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(rc5t583->irq_en_reg); i++) {
+		ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
+					rc5t583->irq_en_reg[i]);
+		if (ret < 0)
+			dev_warn(rc5t583->dev,
+				"Error in writing reg 0x%02x error: %d\n",
+				irq_en_add[i], ret);
+	}
+
+	ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN,
+				rc5t583->intc_inten_reg);
+	if (ret < 0)
+		dev_warn(rc5t583->dev,
+			"Error in writing reg 0x%02x error: %d\n",
+			RC5T583_INTC_INTEN, ret);
+
+	mutex_unlock(&rc5t583->irq_lock);
+}
+#ifdef CONFIG_PM_SLEEP
+static int rc5t583_irq_set_wake(struct irq_data *irq_data, unsigned int on)
+{
+	struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+	return irq_set_irq_wake(rc5t583->chip_irq, on);
+}
+#else
+#define rc5t583_irq_set_wake NULL
+#endif
+
+static irqreturn_t rc5t583_irq(int irq, void *data)
+{
+	struct rc5t583 *rc5t583 = data;
+	uint8_t int_sts[RC5T583_MAX_INTERRUPT_MASK_REGS];
+	uint8_t master_int;
+	int i;
+	int ret;
+	unsigned int rtc_int_sts = 0;
+
+	/* Clear the status */
+	for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)
+		int_sts[i] = 0;
+
+	ret  = rc5t583_read(rc5t583->dev, RC5T583_INTC_INTMON, &master_int);
+	if (ret < 0) {
+		dev_err(rc5t583->dev,
+			"Error in reading reg 0x%02x error: %d\n",
+			RC5T583_INTC_INTMON, ret);
+		return IRQ_HANDLED;
+	}
+
+	for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; ++i) {
+		if (!(master_int & main_int_type[i]))
+			continue;
+
+		ret = rc5t583_read(rc5t583->dev, irq_mon_add[i], &int_sts[i]);
+		if (ret < 0) {
+			dev_warn(rc5t583->dev,
+				"Error in reading reg 0x%02x error: %d\n",
+				irq_mon_add[i], ret);
+			int_sts[i] = 0;
+			continue;
+		}
+
+		if (main_int_type[i] & RTC_INT) {
+			rtc_int_sts = 0;
+			if (int_sts[i] & 0x1)
+				rtc_int_sts |= BIT(6);
+			if (int_sts[i] & 0x2)
+				rtc_int_sts |= BIT(7);
+			if (int_sts[i] & 0x4)
+				rtc_int_sts |= BIT(0);
+			if (int_sts[i] & 0x8)
+				rtc_int_sts |= BIT(5);
+		}
+
+		ret = rc5t583_write(rc5t583->dev, irq_clr_add[i],
+				~int_sts[i]);
+		if (ret < 0)
+			dev_warn(rc5t583->dev,
+				"Error in reading reg 0x%02x error: %d\n",
+				irq_clr_add[i], ret);
+
+		if (main_int_type[i] & RTC_INT)
+			int_sts[i] = rtc_int_sts;
+	}
+
+	/* Merge gpio interrupts for rising and falling case*/
+	int_sts[7] |= int_sts[8];
+
+	/* Call interrupt handler if enabled */
+	for (i = 0; i < RC5T583_MAX_IRQS; ++i) {
+		const struct rc5t583_irq_data *data = &rc5t583_irqs[i];
+		if ((int_sts[data->mask_reg_index] & (1 << data->int_en_bit)) &&
+			(rc5t583->group_irq_en[data->master_bit] &
+					(1 << data->grp_index)))
+			handle_nested_irq(rc5t583->irq_base + i);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct irq_chip rc5t583_irq_chip = {
+	.name = "rc5t583-irq",
+	.irq_mask = rc5t583_irq_mask,
+	.irq_unmask = rc5t583_irq_unmask,
+	.irq_bus_lock = rc5t583_irq_lock,
+	.irq_bus_sync_unlock = rc5t583_irq_sync_unlock,
+	.irq_set_type = rc5t583_irq_set_type,
+	.irq_set_wake = rc5t583_irq_set_wake,
+};
+
+int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base)
+{
+	int i, ret;
+
+	if (!irq_base) {
+		dev_warn(rc5t583->dev, "No interrupt support on IRQ base\n");
+		return -EINVAL;
+	}
+
+	mutex_init(&rc5t583->irq_lock);
+
+	/* Initailize all int register to 0 */
+	for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)  {
+		ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
+				rc5t583->irq_en_reg[i]);
+		if (ret < 0)
+			dev_warn(rc5t583->dev,
+				"Error in writing reg 0x%02x error: %d\n",
+				irq_en_add[i], ret);
+	}
+
+	for (i = 0; i < RC5T583_MAX_GPEDGE_REG; i++)  {
+		ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
+				rc5t583->gpedge_reg[i]);
+		if (ret < 0)
+			dev_warn(rc5t583->dev,
+				"Error in writing reg 0x%02x error: %d\n",
+				gpedge_add[i], ret);
+	}
+
+	ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN, 0x0);
+	if (ret < 0)
+		dev_warn(rc5t583->dev,
+			"Error in writing reg 0x%02x error: %d\n",
+			RC5T583_INTC_INTEN, ret);
+
+	/* Clear all interrupts in case they woke up active. */
+	for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)  {
+		ret = rc5t583_write(rc5t583->dev, irq_clr_add[i], 0);
+		if (ret < 0)
+			dev_warn(rc5t583->dev,
+				"Error in writing reg 0x%02x error: %d\n",
+				irq_clr_add[i], ret);
+	}
+
+	rc5t583->irq_base = irq_base;
+	rc5t583->chip_irq = irq;
+
+	for (i = 0; i < RC5T583_MAX_IRQS; i++) {
+		int __irq = i + rc5t583->irq_base;
+		irq_set_chip_data(__irq, rc5t583);
+		irq_set_chip_and_handler(__irq, &rc5t583_irq_chip,
+					 handle_simple_irq);
+		irq_set_nested_thread(__irq, 1);
+#ifdef CONFIG_ARM
+		set_irq_flags(__irq, IRQF_VALID);
+#endif
+	}
+
+	ret = request_threaded_irq(irq, NULL, rc5t583_irq, IRQF_ONESHOT,
+				"rc5t583", rc5t583);
+	if (ret < 0)
+		dev_err(rc5t583->dev,
+			"Error in registering interrupt error: %d\n", ret);
+	return ret;
+}
+
+int rc5t583_irq_exit(struct rc5t583 *rc5t583)
+{
+	if (rc5t583->chip_irq)
+		free_irq(rc5t583->chip_irq, rc5t583);
+	return 0;
+}
diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c
new file mode 100644
index 0000000..99ef944
--- /dev/null
+++ b/drivers/mfd/rc5t583.c
@@ -0,0 +1,386 @@
+/*
+ * Core driver access RC5T583 power management chip.
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * Based on code
+ *	Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/rc5t583.h>
+#include <linux/regmap.h>
+
+#define RICOH_ONOFFSEL_REG	0x10
+#define RICOH_SWCTL_REG		0x5E
+
+struct deepsleep_control_data {
+	u8 reg_add;
+	u8 ds_pos_bit;
+};
+
+#define DEEPSLEEP_INIT(_id, _reg, _pos)		\
+	{					\
+		.reg_add = RC5T583_##_reg,	\
+		.ds_pos_bit = _pos,		\
+	}
+
+static struct deepsleep_control_data deepsleep_data[] = {
+	DEEPSLEEP_INIT(DC0, SLPSEQ1, 0),
+	DEEPSLEEP_INIT(DC1, SLPSEQ1, 4),
+	DEEPSLEEP_INIT(DC2, SLPSEQ2, 0),
+	DEEPSLEEP_INIT(DC3, SLPSEQ2, 4),
+	DEEPSLEEP_INIT(LDO0, SLPSEQ3, 0),
+	DEEPSLEEP_INIT(LDO1, SLPSEQ3, 4),
+	DEEPSLEEP_INIT(LDO2, SLPSEQ4, 0),
+	DEEPSLEEP_INIT(LDO3, SLPSEQ4, 4),
+	DEEPSLEEP_INIT(LDO4, SLPSEQ5, 0),
+	DEEPSLEEP_INIT(LDO5, SLPSEQ5, 4),
+	DEEPSLEEP_INIT(LDO6, SLPSEQ6, 0),
+	DEEPSLEEP_INIT(LDO7, SLPSEQ6, 4),
+	DEEPSLEEP_INIT(LDO8, SLPSEQ7, 0),
+	DEEPSLEEP_INIT(LDO9, SLPSEQ7, 4),
+	DEEPSLEEP_INIT(PSO0, SLPSEQ8, 0),
+	DEEPSLEEP_INIT(PSO1, SLPSEQ8, 4),
+	DEEPSLEEP_INIT(PSO2, SLPSEQ9, 0),
+	DEEPSLEEP_INIT(PSO3, SLPSEQ9, 4),
+	DEEPSLEEP_INIT(PSO4, SLPSEQ10, 0),
+	DEEPSLEEP_INIT(PSO5, SLPSEQ10, 4),
+	DEEPSLEEP_INIT(PSO6, SLPSEQ11, 0),
+	DEEPSLEEP_INIT(PSO7, SLPSEQ11, 4),
+};
+
+#define EXT_PWR_REQ		\
+	(RC5T583_EXT_PWRREQ1_CONTROL | RC5T583_EXT_PWRREQ2_CONTROL)
+
+static struct mfd_cell rc5t583_subdevs[] = {
+	{.name = "rc5t583-regulator",},
+	{.name = "rc5t583-rtc",      },
+	{.name = "rc5t583-key",      }
+};
+
+int rc5t583_write(struct device *dev, uint8_t reg, uint8_t val)
+{
+	struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+	return regmap_write(rc5t583->regmap, reg, val);
+}
+
+int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val)
+{
+	struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+	unsigned int ival;
+	int ret;
+	ret = regmap_read(rc5t583->regmap, reg, &ival);
+	if (!ret)
+		*val = (uint8_t)ival;
+	return ret;
+}
+
+int rc5t583_set_bits(struct device *dev, unsigned int reg,
+			unsigned int bit_mask)
+{
+	struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+	return regmap_update_bits(rc5t583->regmap, reg, bit_mask, bit_mask);
+}
+
+int rc5t583_clear_bits(struct device *dev, unsigned int reg,
+			unsigned int bit_mask)
+{
+	struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+	return regmap_update_bits(rc5t583->regmap, reg, bit_mask, 0);
+}
+
+int rc5t583_update(struct device *dev, unsigned int reg,
+		unsigned int val, unsigned int mask)
+{
+	struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+	return regmap_update_bits(rc5t583->regmap, reg, mask, val);
+}
+
+static int __rc5t583_set_ext_pwrreq1_control(struct device *dev,
+	int id, int ext_pwr, int slots)
+{
+	int ret;
+	uint8_t sleepseq_val;
+	unsigned int en_bit;
+	unsigned int slot_bit;
+
+	if (id == RC5T583_DS_DC0) {
+		dev_err(dev, "PWRREQ1 is invalid control for rail %d\n", id);
+		return -EINVAL;
+	}
+
+	en_bit = deepsleep_data[id].ds_pos_bit;
+	slot_bit = en_bit + 1;
+	ret = rc5t583_read(dev, deepsleep_data[id].reg_add, &sleepseq_val);
+	if (ret < 0) {
+		dev_err(dev, "Error in reading reg 0x%x\n",
+				deepsleep_data[id].reg_add);
+		return ret;
+	}
+
+	sleepseq_val &= ~(0xF << en_bit);
+	sleepseq_val |= BIT(en_bit);
+	sleepseq_val |= ((slots & 0x7) << slot_bit);
+	ret = rc5t583_set_bits(dev, RICOH_ONOFFSEL_REG, BIT(1));
+	if (ret < 0) {
+		dev_err(dev, "Error in updating the 0x%02x register\n",
+				RICOH_ONOFFSEL_REG);
+		return ret;
+	}
+
+	ret = rc5t583_write(dev, deepsleep_data[id].reg_add, sleepseq_val);
+	if (ret < 0) {
+		dev_err(dev, "Error in writing reg 0x%x\n",
+				deepsleep_data[id].reg_add);
+		return ret;
+	}
+
+	if (id == RC5T583_DS_LDO4) {
+		ret = rc5t583_write(dev, RICOH_SWCTL_REG, 0x1);
+		if (ret < 0)
+			dev_err(dev, "Error in writing reg 0x%x\n",
+				RICOH_SWCTL_REG);
+	}
+	return ret;
+}
+
+static int __rc5t583_set_ext_pwrreq2_control(struct device *dev,
+	int id, int ext_pwr)
+{
+	int ret;
+
+	if (id != RC5T583_DS_DC0) {
+		dev_err(dev, "PWRREQ2 is invalid control for rail %d\n", id);
+		return -EINVAL;
+	}
+
+	ret = rc5t583_set_bits(dev, RICOH_ONOFFSEL_REG, BIT(2));
+	if (ret < 0)
+		dev_err(dev, "Error in updating the ONOFFSEL 0x10 register\n");
+	return ret;
+}
+
+int rc5t583_ext_power_req_config(struct device *dev, int ds_id,
+	int ext_pwr_req, int deepsleep_slot_nr)
+{
+	if ((ext_pwr_req & EXT_PWR_REQ) == EXT_PWR_REQ)
+		return -EINVAL;
+
+	if (ext_pwr_req & RC5T583_EXT_PWRREQ1_CONTROL)
+		return __rc5t583_set_ext_pwrreq1_control(dev, ds_id,
+				ext_pwr_req, deepsleep_slot_nr);
+
+	if (ext_pwr_req & RC5T583_EXT_PWRREQ2_CONTROL)
+		return __rc5t583_set_ext_pwrreq2_control(dev,
+			ds_id, ext_pwr_req);
+	return 0;
+}
+
+static int rc5t583_clear_ext_power_req(struct rc5t583 *rc5t583,
+	struct rc5t583_platform_data *pdata)
+{
+	int ret;
+	int i;
+	uint8_t on_off_val = 0;
+
+	/*  Clear ONOFFSEL register */
+	if (pdata->enable_shutdown)
+		on_off_val = 0x1;
+
+	ret = rc5t583_write(rc5t583->dev, RICOH_ONOFFSEL_REG, on_off_val);
+	if (ret < 0)
+		dev_warn(rc5t583->dev, "Error in writing reg %d error: %d\n",
+					RICOH_ONOFFSEL_REG, ret);
+
+	ret = rc5t583_write(rc5t583->dev, RICOH_SWCTL_REG, 0x0);
+	if (ret < 0)
+		dev_warn(rc5t583->dev, "Error in writing reg %d error: %d\n",
+					RICOH_SWCTL_REG, ret);
+
+	/* Clear sleep sequence register */
+	for (i = RC5T583_SLPSEQ1; i <= RC5T583_SLPSEQ11; ++i) {
+		ret = rc5t583_write(rc5t583->dev, i, 0x0);
+		if (ret < 0)
+			dev_warn(rc5t583->dev,
+				"Error in writing reg 0x%02x error: %d\n",
+				i, ret);
+	}
+	return 0;
+}
+
+static bool volatile_reg(struct device *dev, unsigned int reg)
+{
+	/* Enable caching in interrupt registers */
+	switch (reg) {
+	case RC5T583_INT_EN_SYS1:
+	case RC5T583_INT_EN_SYS2:
+	case RC5T583_INT_EN_DCDC:
+	case RC5T583_INT_EN_RTC:
+	case RC5T583_INT_EN_ADC1:
+	case RC5T583_INT_EN_ADC2:
+	case RC5T583_INT_EN_ADC3:
+	case RC5T583_GPIO_GPEDGE1:
+	case RC5T583_GPIO_GPEDGE2:
+	case RC5T583_GPIO_EN_INT:
+		return false;
+
+	case RC5T583_GPIO_MON_IOIN:
+		/* This is gpio input register */
+		return true;
+
+	default:
+		/* Enable caching in gpio registers */
+		if ((reg >= RC5T583_GPIO_IOSEL) &&
+				(reg <= RC5T583_GPIO_GPOFUNC))
+			return false;
+
+		/* Enable caching in sleep seq registers */
+		if ((reg >= RC5T583_SLPSEQ1) && (reg <= RC5T583_SLPSEQ11))
+			return false;
+
+		/* Enable caching of regulator registers */
+		if ((reg >= RC5T583_REG_DC0CTL) && (reg <= RC5T583_REG_SR3CTL))
+			return false;
+		if ((reg >= RC5T583_REG_LDOEN1) &&
+					(reg <= RC5T583_REG_LDO9DAC_DS))
+			return false;
+
+		break;
+	}
+
+	return true;
+}
+
+static const struct regmap_config rc5t583_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.volatile_reg = volatile_reg,
+	.max_register = RC5T583_MAX_REGS,
+	.num_reg_defaults_raw = RC5T583_MAX_REGS,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c,
+			      const struct i2c_device_id *id)
+{
+	struct rc5t583 *rc5t583;
+	struct rc5t583_platform_data *pdata = i2c->dev.platform_data;
+	int ret;
+	bool irq_init_success = false;
+
+	if (!pdata) {
+		dev_err(&i2c->dev, "Err: Platform data not found\n");
+		return -EINVAL;
+	}
+
+	rc5t583 = devm_kzalloc(&i2c->dev, sizeof(struct rc5t583), GFP_KERNEL);
+	if (!rc5t583) {
+		dev_err(&i2c->dev, "Memory allocation failed\n");
+		return -ENOMEM;
+	}
+
+	rc5t583->dev = &i2c->dev;
+	i2c_set_clientdata(i2c, rc5t583);
+
+	rc5t583->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config);
+	if (IS_ERR(rc5t583->regmap)) {
+		ret = PTR_ERR(rc5t583->regmap);
+		dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = rc5t583_clear_ext_power_req(rc5t583, pdata);
+	if (ret < 0)
+		goto err_irq_init;
+
+	if (i2c->irq) {
+		ret = rc5t583_irq_init(rc5t583, i2c->irq, pdata->irq_base);
+		/* Still continue with waring if irq init fails */
+		if (ret)
+			dev_warn(&i2c->dev, "IRQ init failed: %d\n", ret);
+		else
+			irq_init_success = true;
+	}
+
+	ret = mfd_add_devices(rc5t583->dev, -1, rc5t583_subdevs,
+			ARRAY_SIZE(rc5t583_subdevs), NULL, 0);
+	if (ret) {
+		dev_err(&i2c->dev, "add mfd devices failed: %d\n", ret);
+		goto err_add_devs;
+	}
+
+	return 0;
+
+err_add_devs:
+	if (irq_init_success)
+		rc5t583_irq_exit(rc5t583);
+err_irq_init:
+	regmap_exit(rc5t583->regmap);
+	return ret;
+}
+
+static int  __devexit rc5t583_i2c_remove(struct i2c_client *i2c)
+{
+	struct rc5t583 *rc5t583 = i2c_get_clientdata(i2c);
+
+	mfd_remove_devices(rc5t583->dev);
+	rc5t583_irq_exit(rc5t583);
+	regmap_exit(rc5t583->regmap);
+	return 0;
+}
+
+static const struct i2c_device_id rc5t583_i2c_id[] = {
+	{.name = "rc5t583", .driver_data = 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, rc5t583_i2c_id);
+
+static struct i2c_driver rc5t583_i2c_driver = {
+	.driver = {
+		   .name = "rc5t583",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = rc5t583_i2c_probe,
+	.remove = __devexit_p(rc5t583_i2c_remove),
+	.id_table = rc5t583_i2c_id,
+};
+
+static int __init rc5t583_i2c_init(void)
+{
+	return i2c_add_driver(&rc5t583_i2c_driver);
+}
+subsys_initcall(rc5t583_i2c_init);
+
+static void __exit rc5t583_i2c_exit(void)
+{
+	i2c_del_driver(&rc5t583_i2c_driver);
+}
+
+module_exit(rc5t583_i2c_exit);
+
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("RICOH RC5T583 power management system device driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/s5m-core.c b/drivers/mfd/s5m-core.c
index caadabe..48949d9 100644
--- a/drivers/mfd/s5m-core.c
+++ b/drivers/mfd/s5m-core.c
@@ -26,7 +26,27 @@
 #include <linux/mfd/s5m87xx/s5m-rtc.h>
 #include <linux/regmap.h>
 
-static struct mfd_cell s5m87xx_devs[] = {
+static struct mfd_cell s5m8751_devs[] = {
+	{
+		.name = "s5m8751-pmic",
+	}, {
+		.name = "s5m-charger",
+	}, {
+		.name = "s5m8751-codec",
+	},
+};
+
+static struct mfd_cell s5m8763_devs[] = {
+	{
+		.name = "s5m8763-pmic",
+	}, {
+		.name = "s5m-rtc",
+	}, {
+		.name = "s5m-charger",
+	},
+};
+
+static struct mfd_cell s5m8767_devs[] = {
 	{
 		.name = "s5m8767-pmic",
 	}, {
@@ -42,7 +62,7 @@
 
 int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
 {
-	return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);;
+	return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);
 }
 EXPORT_SYMBOL_GPL(s5m_bulk_read);
 
@@ -54,7 +74,7 @@
 
 int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
 {
-	return regmap_raw_write(s5m87xx->regmap, reg, buf, count * sizeof(u16));
+	return regmap_raw_write(s5m87xx->regmap, reg, buf, count);
 }
 EXPORT_SYMBOL_GPL(s5m_bulk_write);
 
@@ -74,10 +94,10 @@
 {
 	struct s5m_platform_data *pdata = i2c->dev.platform_data;
 	struct s5m87xx_dev *s5m87xx;
-	int ret = 0;
-	int error;
+	int ret;
 
-	s5m87xx = kzalloc(sizeof(struct s5m87xx_dev), GFP_KERNEL);
+	s5m87xx = devm_kzalloc(&i2c->dev, sizeof(struct s5m87xx_dev),
+				GFP_KERNEL);
 	if (s5m87xx == NULL)
 		return -ENOMEM;
 
@@ -96,9 +116,9 @@
 
 	s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config);
 	if (IS_ERR(s5m87xx->regmap)) {
-		error = PTR_ERR(s5m87xx->regmap);
+		ret = PTR_ERR(s5m87xx->regmap);
 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
-			error);
+			ret);
 		goto err;
 	}
 
@@ -112,9 +132,23 @@
 
 	pm_runtime_set_active(s5m87xx->dev);
 
-	ret = mfd_add_devices(s5m87xx->dev, -1,
-				s5m87xx_devs, ARRAY_SIZE(s5m87xx_devs),
-				NULL, 0);
+	switch (s5m87xx->device_type) {
+	case S5M8751X:
+		ret = mfd_add_devices(s5m87xx->dev, -1, s5m8751_devs,
+					ARRAY_SIZE(s5m8751_devs), NULL, 0);
+		break;
+	case S5M8763X:
+		ret = mfd_add_devices(s5m87xx->dev, -1, s5m8763_devs,
+					ARRAY_SIZE(s5m8763_devs), NULL, 0);
+		break;
+	case S5M8767X:
+		ret = mfd_add_devices(s5m87xx->dev, -1, s5m8767_devs,
+					ARRAY_SIZE(s5m8767_devs), NULL, 0);
+		break;
+	default:
+		/* If this happens the probe function is problem */
+		BUG();
+	}
 
 	if (ret < 0)
 		goto err;
@@ -126,7 +160,6 @@
 	s5m_irq_exit(s5m87xx);
 	i2c_unregister_device(s5m87xx->rtc);
 	regmap_exit(s5m87xx->regmap);
-	kfree(s5m87xx);
 	return ret;
 }
 
@@ -138,7 +171,6 @@
 	s5m_irq_exit(s5m87xx);
 	i2c_unregister_device(s5m87xx->rtc);
 	regmap_exit(s5m87xx->regmap);
-	kfree(s5m87xx);
 	return 0;
 }
 
diff --git a/drivers/mfd/s5m-irq.c b/drivers/mfd/s5m-irq.c
index de76dfb..0236676 100644
--- a/drivers/mfd/s5m-irq.c
+++ b/drivers/mfd/s5m-irq.c
@@ -342,7 +342,10 @@
 			s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx);
 			break;
 		default:
-			break;
+			dev_err(s5m87xx->dev,
+				"Unknown device type %d\n",
+				s5m87xx->device_type);
+			return -EINVAL;
 
 		}
 	}
@@ -444,7 +447,9 @@
 		}
 		break;
 	default:
-		break;
+		dev_err(s5m87xx->dev,
+			"Unknown device type %d\n", s5m87xx->device_type);
+		return -EINVAL;
 	}
 
 	if (!s5m87xx->ono)
@@ -467,12 +472,15 @@
 					IRQF_ONESHOT, "s5m87xx-ono", s5m87xx);
 		break;
 	default:
+		ret = -EINVAL;
 		break;
 	}
 
-	if (ret)
+	if (ret) {
 		dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
 			s5m87xx->ono, ret);
+		return ret;
+	}
 
 	return 0;
 }
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index f4d8611..d927dd4 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -387,14 +387,6 @@
 
 EXPORT_SYMBOL_GPL(sm501_unit_power);
 
-
-/* Perform a rounded division. */
-static long sm501fb_round_div(long num, long denom)
-{
-        /* n / d + 1 / 2 = (2n + d) / 2d */
-        return (2 * num + denom) / (2 * denom);
-}
-
 /* clock value structure. */
 struct sm501_clock {
 	unsigned long mclk;
@@ -428,7 +420,7 @@
 		/* try all 8 shift values.*/
 		for (shift = 0; shift < 8; shift++) {
 			/* Calculate difference to requested clock */
-			diff = sm501fb_round_div(mclk, divider << shift) - freq;
+			diff = DIV_ROUND_CLOSEST(mclk, divider << shift) - freq;
 			if (diff < 0)
 				diff = -diff;
 
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
index e07947e..2dd8d49 100644
--- a/drivers/mfd/stmpe.c
+++ b/drivers/mfd/stmpe.c
@@ -298,6 +298,11 @@
 	.num_resources	= ARRAY_SIZE(stmpe_gpio_resources),
 };
 
+static struct mfd_cell stmpe_gpio_cell_noirq = {
+	.name		= "stmpe-gpio",
+	/* gpio cell resources consist of an irq only so no resources here */
+};
+
 /*
  * Keypad (1601, 2401, 2403)
  */
@@ -346,6 +351,13 @@
 	},
 };
 
+static struct stmpe_variant_block stmpe801_blocks_noirq[] = {
+	{
+		.cell	= &stmpe_gpio_cell_noirq,
+		.block	= STMPE_BLOCK_GPIO,
+	},
+};
+
 static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks,
 			   bool enable)
 {
@@ -367,6 +379,17 @@
 	.enable		= stmpe801_enable,
 };
 
+static struct stmpe_variant_info stmpe801_noirq = {
+	.name		= "stmpe801",
+	.id_val		= STMPE801_ID,
+	.id_mask	= 0xffff,
+	.num_gpios	= 8,
+	.regs		= stmpe801_regs,
+	.blocks		= stmpe801_blocks_noirq,
+	.num_blocks	= ARRAY_SIZE(stmpe801_blocks_noirq),
+	.enable		= stmpe801_enable,
+};
+
 /*
  * Touchscreen (STMPE811 or STMPE610)
  */
@@ -712,7 +735,7 @@
 	.enable_autosleep	= stmpe1601_autosleep, /* same as stmpe1601 */
 };
 
-static struct stmpe_variant_info *stmpe_variant_info[] = {
+static struct stmpe_variant_info *stmpe_variant_info[STMPE_NBR_PARTS] = {
 	[STMPE610]	= &stmpe610,
 	[STMPE801]	= &stmpe801,
 	[STMPE811]	= &stmpe811,
@@ -721,6 +744,16 @@
 	[STMPE2403]	= &stmpe2403,
 };
 
+/*
+ * These devices can be connected in a 'no-irq' configuration - the irq pin
+ * is not used and the device cannot interrupt the CPU. Here we only list
+ * devices which support this configuration - the driver will fail probing
+ * for any devices not listed here which are configured in this way.
+ */
+static struct stmpe_variant_info *stmpe_noirq_variant_info[STMPE_NBR_PARTS] = {
+	[STMPE801]	= &stmpe801_noirq,
+};
+
 static irqreturn_t stmpe_irq(int irq, void *data)
 {
 	struct stmpe *stmpe = data;
@@ -864,7 +897,7 @@
 	unsigned int irq_trigger = stmpe->pdata->irq_trigger;
 	int autosleep_timeout = stmpe->pdata->autosleep_timeout;
 	struct stmpe_variant_info *variant = stmpe->variant;
-	u8 icr;
+	u8 icr = 0;
 	unsigned int id;
 	u8 data[2];
 	int ret;
@@ -887,31 +920,33 @@
 	if (ret)
 		return ret;
 
-	if (id == STMPE801_ID)
-		icr = STMPE801_REG_SYS_CTRL_INT_EN;
-	else
-		icr = STMPE_ICR_LSB_GIM;
-
-	/* STMPE801 doesn't support Edge interrupts */
-	if (id != STMPE801_ID) {
-		if (irq_trigger == IRQF_TRIGGER_FALLING ||
-				irq_trigger == IRQF_TRIGGER_RISING)
-			icr |= STMPE_ICR_LSB_EDGE;
-	}
-
-	if (irq_trigger == IRQF_TRIGGER_RISING ||
-			irq_trigger == IRQF_TRIGGER_HIGH) {
+	if (stmpe->irq >= 0) {
 		if (id == STMPE801_ID)
-			icr |= STMPE801_REG_SYS_CTRL_INT_HI;
+			icr = STMPE801_REG_SYS_CTRL_INT_EN;
 		else
-			icr |= STMPE_ICR_LSB_HIGH;
-	}
+			icr = STMPE_ICR_LSB_GIM;
 
-	if (stmpe->pdata->irq_invert_polarity) {
-		if (id == STMPE801_ID)
-			icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
-		else
-			icr ^= STMPE_ICR_LSB_HIGH;
+		/* STMPE801 doesn't support Edge interrupts */
+		if (id != STMPE801_ID) {
+			if (irq_trigger == IRQF_TRIGGER_FALLING ||
+					irq_trigger == IRQF_TRIGGER_RISING)
+				icr |= STMPE_ICR_LSB_EDGE;
+		}
+
+		if (irq_trigger == IRQF_TRIGGER_RISING ||
+				irq_trigger == IRQF_TRIGGER_HIGH) {
+			if (id == STMPE801_ID)
+				icr |= STMPE801_REG_SYS_CTRL_INT_HI;
+			else
+				icr |= STMPE_ICR_LSB_HIGH;
+		}
+
+		if (stmpe->pdata->irq_invert_polarity) {
+			if (id == STMPE801_ID)
+				icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
+			else
+				icr ^= STMPE_ICR_LSB_HIGH;
+		}
 	}
 
 	if (stmpe->pdata->autosleep) {
@@ -1001,19 +1036,38 @@
 		stmpe->irq = ci->irq;
 	}
 
+	if (stmpe->irq < 0) {
+		/* use alternate variant info for no-irq mode, if supported */
+		dev_info(stmpe->dev,
+			"%s configured in no-irq mode by platform data\n",
+			stmpe->variant->name);
+		if (!stmpe_noirq_variant_info[stmpe->partnum]) {
+			dev_err(stmpe->dev,
+				"%s does not support no-irq mode!\n",
+				stmpe->variant->name);
+			ret = -ENODEV;
+			goto free_gpio;
+		}
+		stmpe->variant = stmpe_noirq_variant_info[stmpe->partnum];
+	}
+
 	ret = stmpe_chip_init(stmpe);
 	if (ret)
 		goto free_gpio;
 
-	ret = stmpe_irq_init(stmpe);
-	if (ret)
-		goto free_gpio;
+	if (stmpe->irq >= 0) {
+		ret = stmpe_irq_init(stmpe);
+		if (ret)
+			goto free_gpio;
 
-	ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
-			pdata->irq_trigger | IRQF_ONESHOT, "stmpe", stmpe);
-	if (ret) {
-		dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret);
-		goto out_removeirq;
+		ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
+				pdata->irq_trigger | IRQF_ONESHOT,
+				"stmpe", stmpe);
+		if (ret) {
+			dev_err(stmpe->dev, "failed to request IRQ: %d\n",
+					ret);
+			goto out_removeirq;
+		}
 	}
 
 	ret = stmpe_devices_init(stmpe);
@@ -1026,9 +1080,11 @@
 
 out_removedevs:
 	mfd_remove_devices(stmpe->dev);
-	free_irq(stmpe->irq, stmpe);
+	if (stmpe->irq >= 0)
+		free_irq(stmpe->irq, stmpe);
 out_removeirq:
-	stmpe_irq_remove(stmpe);
+	if (stmpe->irq >= 0)
+		stmpe_irq_remove(stmpe);
 free_gpio:
 	if (pdata->irq_over_gpio)
 		gpio_free(pdata->irq_gpio);
@@ -1041,8 +1097,10 @@
 {
 	mfd_remove_devices(stmpe->dev);
 
-	free_irq(stmpe->irq, stmpe);
-	stmpe_irq_remove(stmpe);
+	if (stmpe->irq >= 0) {
+		free_irq(stmpe->irq, stmpe);
+		stmpe_irq_remove(stmpe);
+	}
 
 	if (stmpe->pdata->irq_over_gpio)
 		gpio_free(stmpe->pdata->irq_gpio);
@@ -1057,7 +1115,7 @@
 {
 	struct stmpe *stmpe = dev_get_drvdata(dev);
 
-	if (device_may_wakeup(dev))
+	if (stmpe->irq >= 0 && device_may_wakeup(dev))
 		enable_irq_wake(stmpe->irq);
 
 	return 0;
@@ -1067,7 +1125,7 @@
 {
 	struct stmpe *stmpe = dev_get_drvdata(dev);
 
-	if (device_may_wakeup(dev))
+	if (stmpe->irq >= 0 && device_may_wakeup(dev))
 		disable_irq_wake(stmpe->irq);
 
 	return 0;
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c
new file mode 100644
index 0000000..a66d4df
--- /dev/null
+++ b/drivers/mfd/tps65090.c
@@ -0,0 +1,387 @@
+/*
+ * Core driver for TI TPS65090 PMIC family
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+
+ * 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/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65090.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+
+#define NUM_INT_REG 2
+#define TOTAL_NUM_REG 0x18
+
+/* interrupt status registers */
+#define TPS65090_INT_STS	0x0
+#define TPS65090_INT_STS2	0x1
+
+/* interrupt mask registers */
+#define TPS65090_INT_MSK	0x2
+#define TPS65090_INT_MSK2	0x3
+
+struct tps65090_irq_data {
+	u8		mask_reg;
+	u8		mask_pos;
+};
+
+#define TPS65090_IRQ(_reg, _mask_pos)		\
+	{					\
+		.mask_reg	= (_reg),	\
+		.mask_pos	= (_mask_pos),	\
+	}
+
+static const struct tps65090_irq_data tps65090_irqs[] = {
+	[0]		= TPS65090_IRQ(0, 0),
+	[1]		= TPS65090_IRQ(0, 1),
+	[2]		= TPS65090_IRQ(0, 2),
+	[3]		= TPS65090_IRQ(0, 3),
+	[4]		= TPS65090_IRQ(0, 4),
+	[5]		= TPS65090_IRQ(0, 5),
+	[6]		= TPS65090_IRQ(0, 6),
+	[7]		= TPS65090_IRQ(0, 7),
+	[8]		= TPS65090_IRQ(1, 0),
+	[9]		= TPS65090_IRQ(1, 1),
+	[10]		= TPS65090_IRQ(1, 2),
+	[11]		= TPS65090_IRQ(1, 3),
+	[12]		= TPS65090_IRQ(1, 4),
+	[13]		= TPS65090_IRQ(1, 5),
+	[14]		= TPS65090_IRQ(1, 6),
+	[15]		= TPS65090_IRQ(1, 7),
+};
+
+static struct mfd_cell tps65090s[] = {
+	{
+		.name = "tps65910-pmic",
+	},
+	{
+		.name = "tps65910-regulator",
+	},
+};
+
+struct tps65090 {
+	struct mutex		lock;
+	struct device		*dev;
+	struct i2c_client	*client;
+	struct regmap		*rmap;
+	struct irq_chip		irq_chip;
+	struct mutex		irq_lock;
+	int			irq_base;
+	unsigned int		id;
+};
+
+int tps65090_write(struct device *dev, int reg, uint8_t val)
+{
+	struct tps65090 *tps = dev_get_drvdata(dev);
+	return regmap_write(tps->rmap, reg, val);
+}
+EXPORT_SYMBOL_GPL(tps65090_write);
+
+int tps65090_read(struct device *dev, int reg, uint8_t *val)
+{
+	struct tps65090 *tps = dev_get_drvdata(dev);
+	unsigned int temp_val;
+	int ret;
+	ret = regmap_read(tps->rmap, reg, &temp_val);
+	if (!ret)
+		*val = temp_val;
+	return ret;
+}
+EXPORT_SYMBOL_GPL(tps65090_read);
+
+int tps65090_set_bits(struct device *dev, int reg, uint8_t bit_num)
+{
+	struct tps65090 *tps = dev_get_drvdata(dev);
+	return regmap_update_bits(tps->rmap, reg, BIT(bit_num), ~0u);
+}
+EXPORT_SYMBOL_GPL(tps65090_set_bits);
+
+int tps65090_clr_bits(struct device *dev, int reg, uint8_t bit_num)
+{
+	struct tps65090 *tps = dev_get_drvdata(dev);
+	return regmap_update_bits(tps->rmap, reg, BIT(bit_num), 0u);
+}
+EXPORT_SYMBOL_GPL(tps65090_clr_bits);
+
+static void tps65090_irq_lock(struct irq_data *data)
+{
+	struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data);
+
+	mutex_lock(&tps65090->irq_lock);
+}
+
+static void tps65090_irq_mask(struct irq_data *irq_data)
+{
+	struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data);
+	unsigned int __irq = irq_data->hwirq;
+	const struct tps65090_irq_data *data = &tps65090_irqs[__irq];
+
+	tps65090_set_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg),
+		data->mask_pos);
+}
+
+static void tps65090_irq_unmask(struct irq_data *irq_data)
+{
+	struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data);
+	unsigned int __irq = irq_data->irq - tps65090->irq_base;
+	const struct tps65090_irq_data *data = &tps65090_irqs[__irq];
+
+	tps65090_clr_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg),
+		data->mask_pos);
+}
+
+static void tps65090_irq_sync_unlock(struct irq_data *data)
+{
+	struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data);
+
+	mutex_unlock(&tps65090->irq_lock);
+}
+
+static irqreturn_t tps65090_irq(int irq, void *data)
+{
+	struct tps65090 *tps65090 = data;
+	int ret = 0;
+	u8 status, mask;
+	unsigned long int acks = 0;
+	int i;
+
+	for (i = 0; i < NUM_INT_REG; i++) {
+		ret = tps65090_read(tps65090->dev, TPS65090_INT_MSK + i, &mask);
+		if (ret < 0) {
+			dev_err(tps65090->dev,
+				"failed to read mask reg [addr:%d]\n",
+				TPS65090_INT_MSK + i);
+			return IRQ_NONE;
+		}
+		ret = tps65090_read(tps65090->dev, TPS65090_INT_STS + i,
+			&status);
+		if (ret < 0) {
+			dev_err(tps65090->dev,
+				"failed to read status reg [addr:%d]\n",
+				 TPS65090_INT_STS + i);
+			return IRQ_NONE;
+		}
+		if (status) {
+			/* Ack only those interrupts which are not masked */
+			status &= (~mask);
+			ret = tps65090_write(tps65090->dev,
+					TPS65090_INT_STS + i, status);
+			if (ret < 0) {
+				dev_err(tps65090->dev,
+					"failed to write interrupt status\n");
+				return IRQ_NONE;
+			}
+			acks |= (status << (i * 8));
+		}
+	}
+
+	for_each_set_bit(i, &acks, ARRAY_SIZE(tps65090_irqs))
+		handle_nested_irq(tps65090->irq_base + i);
+	return acks ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int __devinit tps65090_irq_init(struct tps65090 *tps65090, int irq,
+	int irq_base)
+{
+	int i, ret;
+
+	if (!irq_base) {
+		dev_err(tps65090->dev, "IRQ base not set\n");
+		return -EINVAL;
+	}
+
+	mutex_init(&tps65090->irq_lock);
+
+	for (i = 0; i < NUM_INT_REG; i++)
+		tps65090_write(tps65090->dev, TPS65090_INT_MSK + i, 0xFF);
+
+	for (i = 0; i < NUM_INT_REG; i++)
+		tps65090_write(tps65090->dev, TPS65090_INT_STS + i, 0xff);
+
+	tps65090->irq_base = irq_base;
+	tps65090->irq_chip.name = "tps65090";
+	tps65090->irq_chip.irq_mask = tps65090_irq_mask;
+	tps65090->irq_chip.irq_unmask = tps65090_irq_unmask;
+	tps65090->irq_chip.irq_bus_lock = tps65090_irq_lock;
+	tps65090->irq_chip.irq_bus_sync_unlock = tps65090_irq_sync_unlock;
+
+	for (i = 0; i < ARRAY_SIZE(tps65090_irqs); i++) {
+		int __irq = i + tps65090->irq_base;
+		irq_set_chip_data(__irq, tps65090);
+		irq_set_chip_and_handler(__irq, &tps65090->irq_chip,
+					 handle_simple_irq);
+		irq_set_nested_thread(__irq, 1);
+#ifdef CONFIG_ARM
+		set_irq_flags(__irq, IRQF_VALID);
+#endif
+	}
+
+	ret = request_threaded_irq(irq, NULL, tps65090_irq, IRQF_ONESHOT,
+				"tps65090", tps65090);
+	if (!ret) {
+		device_init_wakeup(tps65090->dev, 1);
+		enable_irq_wake(irq);
+	}
+
+	return ret;
+}
+
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS))
+		return true;
+	else
+		return false;
+}
+
+static const struct regmap_config tps65090_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = TOTAL_NUM_REG,
+	.num_reg_defaults_raw = TOTAL_NUM_REG,
+	.cache_type = REGCACHE_RBTREE,
+	.volatile_reg = is_volatile_reg,
+};
+
+static int __devinit tps65090_i2c_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	struct tps65090_platform_data *pdata = client->dev.platform_data;
+	struct tps65090 *tps65090;
+	int ret;
+
+	if (!pdata) {
+		dev_err(&client->dev, "tps65090 requires platform data\n");
+		return -EINVAL;
+	}
+
+	tps65090 = devm_kzalloc(&client->dev, sizeof(struct tps65090),
+		GFP_KERNEL);
+	if (tps65090 == NULL)
+		return -ENOMEM;
+
+	tps65090->client = client;
+	tps65090->dev = &client->dev;
+	i2c_set_clientdata(client, tps65090);
+
+	mutex_init(&tps65090->lock);
+
+	if (client->irq) {
+		ret = tps65090_irq_init(tps65090, client->irq, pdata->irq_base);
+		if (ret) {
+			dev_err(&client->dev, "IRQ init failed with err: %d\n",
+				ret);
+			goto err_exit;
+		}
+	}
+
+	tps65090->rmap = regmap_init_i2c(tps65090->client,
+		&tps65090_regmap_config);
+	if (IS_ERR(tps65090->rmap)) {
+		dev_err(&client->dev, "regmap_init failed with err: %ld\n",
+			PTR_ERR(tps65090->rmap));
+		goto err_irq_exit;
+	};
+
+	ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
+		ARRAY_SIZE(tps65090s), NULL, 0);
+	if (ret) {
+		dev_err(&client->dev, "add mfd devices failed with err: %d\n",
+			ret);
+		goto err_regmap_exit;
+	}
+
+	return 0;
+
+err_regmap_exit:
+	regmap_exit(tps65090->rmap);
+
+err_irq_exit:
+	if (client->irq)
+		free_irq(client->irq, tps65090);
+err_exit:
+	return ret;
+}
+
+static int __devexit tps65090_i2c_remove(struct i2c_client *client)
+{
+	struct tps65090 *tps65090 = i2c_get_clientdata(client);
+
+	mfd_remove_devices(tps65090->dev);
+	regmap_exit(tps65090->rmap);
+	if (client->irq)
+		free_irq(client->irq, tps65090);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int tps65090_i2c_suspend(struct i2c_client *client, pm_message_t state)
+{
+	if (client->irq)
+		disable_irq(client->irq);
+	return 0;
+}
+
+static int tps65090_i2c_resume(struct i2c_client *client)
+{
+	if (client->irq)
+		enable_irq(client->irq);
+	return 0;
+}
+#endif
+
+static const struct i2c_device_id tps65090_id_table[] = {
+	{ "tps65090", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, tps65090_id_table);
+
+static struct i2c_driver tps65090_driver = {
+	.driver	= {
+		.name	= "tps65090",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= tps65090_i2c_probe,
+	.remove		= __devexit_p(tps65090_i2c_remove),
+#ifdef CONFIG_PM
+	.suspend	= tps65090_i2c_suspend,
+	.resume		= tps65090_i2c_resume,
+#endif
+	.id_table	= tps65090_id_table,
+};
+
+static int __init tps65090_init(void)
+{
+	return i2c_add_driver(&tps65090_driver);
+}
+subsys_initcall(tps65090_init);
+
+static void __exit tps65090_exit(void)
+{
+	i2c_del_driver(&tps65090_driver);
+}
+module_exit(tps65090_exit);
+
+MODULE_DESCRIPTION("TPS65090 core driver");
+MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c
new file mode 100644
index 0000000..f7d854e
--- /dev/null
+++ b/drivers/mfd/tps65217.c
@@ -0,0 +1,242 @@
+/*
+ * tps65217.c
+ *
+ * TPS65217 chip family multi-function driver
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65217.h>
+
+/**
+ * tps65217_reg_read: Read a single tps65217 register.
+ *
+ * @tps: Device to read from.
+ * @reg: Register to read.
+ * @val: Contians the value
+ */
+int tps65217_reg_read(struct tps65217 *tps, unsigned int reg,
+			unsigned int *val)
+{
+	return regmap_read(tps->regmap, reg, val);
+}
+EXPORT_SYMBOL_GPL(tps65217_reg_read);
+
+/**
+ * tps65217_reg_write: Write a single tps65217 register.
+ *
+ * @tps65217: Device to write to.
+ * @reg: Register to write to.
+ * @val: Value to write.
+ * @level: Password protected level
+ */
+int tps65217_reg_write(struct tps65217 *tps, unsigned int reg,
+			unsigned int val, unsigned int level)
+{
+	int ret;
+	unsigned int xor_reg_val;
+
+	switch (level) {
+	case TPS65217_PROTECT_NONE:
+		return regmap_write(tps->regmap, reg, val);
+	case TPS65217_PROTECT_L1:
+		xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
+		ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
+							xor_reg_val);
+		if (ret < 0)
+			return ret;
+
+		return regmap_write(tps->regmap, reg, val);
+	case TPS65217_PROTECT_L2:
+		xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
+		ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
+							xor_reg_val);
+		if (ret < 0)
+			return ret;
+		ret = regmap_write(tps->regmap, reg, val);
+		if (ret < 0)
+			return ret;
+		ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
+							xor_reg_val);
+		if (ret < 0)
+			return ret;
+		return regmap_write(tps->regmap, reg, val);
+	default:
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL_GPL(tps65217_reg_write);
+
+/**
+ * tps65217_update_bits: Modify bits w.r.t mask, val and level.
+ *
+ * @tps65217: Device to write to.
+ * @reg: Register to read-write to.
+ * @mask: Mask.
+ * @val: Value to write.
+ * @level: Password protected level
+ */
+int tps65217_update_bits(struct tps65217 *tps, unsigned int reg,
+		unsigned int mask, unsigned int val, unsigned int level)
+{
+	int ret;
+	unsigned int data;
+
+	ret = tps65217_reg_read(tps, reg, &data);
+	if (ret) {
+		dev_err(tps->dev, "Read from reg 0x%x failed\n", reg);
+		return ret;
+	}
+
+	data &= ~mask;
+	data |= val & mask;
+
+	ret = tps65217_reg_write(tps, reg, data, level);
+	if (ret)
+		dev_err(tps->dev, "Write for reg 0x%x failed\n", reg);
+
+	return ret;
+}
+
+int tps65217_set_bits(struct tps65217 *tps, unsigned int reg,
+		unsigned int mask, unsigned int val, unsigned int level)
+{
+	return tps65217_update_bits(tps, reg, mask, val, level);
+}
+EXPORT_SYMBOL_GPL(tps65217_set_bits);
+
+int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
+		unsigned int mask, unsigned int level)
+{
+	return tps65217_update_bits(tps, reg, mask, 0, level);
+}
+EXPORT_SYMBOL_GPL(tps65217_clear_bits);
+
+static struct regmap_config tps65217_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static int __devinit tps65217_probe(struct i2c_client *client,
+				const struct i2c_device_id *ids)
+{
+	struct tps65217 *tps;
+	struct tps65217_board *pdata = client->dev.platform_data;
+	int i, ret;
+	unsigned int version;
+
+	tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
+	if (!tps)
+		return -ENOMEM;
+
+	tps->pdata = pdata;
+	tps->regmap = regmap_init_i2c(client, &tps65217_regmap_config);
+	if (IS_ERR(tps->regmap)) {
+		ret = PTR_ERR(tps->regmap);
+		dev_err(tps->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(client, tps);
+	tps->dev = &client->dev;
+
+	ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version);
+	if (ret < 0) {
+		dev_err(tps->dev, "Failed to read revision"
+					" register: %d\n", ret);
+		goto err_regmap;
+	}
+
+	dev_info(tps->dev, "TPS65217 ID %#x version 1.%d\n",
+			(version & TPS65217_CHIPID_CHIP_MASK) >> 4,
+			version & TPS65217_CHIPID_REV_MASK);
+
+	for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
+		struct platform_device *pdev;
+
+		pdev = platform_device_alloc("tps65217-pmic", i);
+		if (!pdev) {
+			dev_err(tps->dev, "Cannot create regulator %d\n", i);
+			continue;
+		}
+
+		pdev->dev.parent = tps->dev;
+		platform_device_add_data(pdev, &pdata->tps65217_init_data[i],
+					sizeof(pdata->tps65217_init_data[i]));
+		tps->regulator_pdev[i] = pdev;
+
+		platform_device_add(pdev);
+	}
+
+	return 0;
+
+err_regmap:
+	regmap_exit(tps->regmap);
+
+	return ret;
+}
+
+static int __devexit tps65217_remove(struct i2c_client *client)
+{
+	struct tps65217 *tps = i2c_get_clientdata(client);
+	int i;
+
+	for (i = 0; i < TPS65217_NUM_REGULATOR; i++)
+		platform_device_unregister(tps->regulator_pdev[i]);
+
+	regmap_exit(tps->regmap);
+
+	return 0;
+}
+
+static const struct i2c_device_id tps65217_id_table[] = {
+	{"tps65217", 0xF0},
+	{/* end of list */}
+};
+MODULE_DEVICE_TABLE(i2c, tps65217_id_table);
+
+static struct i2c_driver tps65217_driver = {
+	.driver		= {
+		.name	= "tps65217",
+	},
+	.id_table	= tps65217_id_table,
+	.probe		= tps65217_probe,
+	.remove		= __devexit_p(tps65217_remove),
+};
+
+static int __init tps65217_init(void)
+{
+	return i2c_add_driver(&tps65217_driver);
+}
+subsys_initcall(tps65217_init);
+
+static void __exit tps65217_exit(void)
+{
+	i2c_del_driver(&tps65217_driver);
+}
+module_exit(tps65217_exit);
+
+MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>");
+MODULE_DESCRIPTION("TPS65217 chip family multi-function driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c
index 95c0d79..c9ed5c0 100644
--- a/drivers/mfd/tps65910-irq.c
+++ b/drivers/mfd/tps65910-irq.c
@@ -145,12 +145,23 @@
 	tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq));
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tps65910_irq_set_wake(struct irq_data *data, unsigned int enable)
+{
+	struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
+	return irq_set_irq_wake(tps65910->chip_irq, enable);
+}
+#else
+#define tps65910_irq_set_wake NULL
+#endif
+
 static struct irq_chip tps65910_irq_chip = {
 	.name = "tps65910",
 	.irq_bus_lock = tps65910_irq_lock,
 	.irq_bus_sync_unlock = tps65910_irq_sync_unlock,
 	.irq_disable = tps65910_irq_disable,
 	.irq_enable = tps65910_irq_enable,
+	.irq_set_wake = tps65910_irq_set_wake,
 };
 
 int tps65910_irq_init(struct tps65910 *tps65910, int irq,
diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c
index 4392f6b..bf2b25e 100644
--- a/drivers/mfd/tps65910.c
+++ b/drivers/mfd/tps65910.c
@@ -16,10 +16,12 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
+#include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/mfd/core.h>
+#include <linux/regmap.h>
 #include <linux/mfd/tps65910.h>
 
 static struct mfd_cell tps65910s[] = {
@@ -38,99 +40,56 @@
 static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
 				  int bytes, void *dest)
 {
-	struct i2c_client *i2c = tps65910->i2c_client;
-	struct i2c_msg xfer[2];
-	int ret;
-
-	/* Write register */
-	xfer[0].addr = i2c->addr;
-	xfer[0].flags = 0;
-	xfer[0].len = 1;
-	xfer[0].buf = &reg;
-
-	/* Read data */
-	xfer[1].addr = i2c->addr;
-	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = bytes;
-	xfer[1].buf = dest;
-
-	ret = i2c_transfer(i2c->adapter, xfer, 2);
-	if (ret == 2)
-		ret = 0;
-	else if (ret >= 0)
-		ret = -EIO;
-
-	return ret;
+	return regmap_bulk_read(tps65910->regmap, reg, dest, bytes);
 }
 
 static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
-				   int bytes, void *src)
+				  int bytes, void *src)
 {
-	struct i2c_client *i2c = tps65910->i2c_client;
-	/* we add 1 byte for device register */
-	u8 msg[TPS65910_MAX_REGISTER + 1];
-	int ret;
-
-	if (bytes > TPS65910_MAX_REGISTER)
-		return -EINVAL;
-
-	msg[0] = reg;
-	memcpy(&msg[1], src, bytes);
-
-	ret = i2c_master_send(i2c, msg, bytes + 1);
-	if (ret < 0)
-		return ret;
-	if (ret != bytes + 1)
-		return -EIO;
-	return 0;
+	return regmap_bulk_write(tps65910->regmap, reg, src, bytes);
 }
 
 int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
 {
-	u8 data;
-	int err;
-
-	mutex_lock(&tps65910->io_mutex);
-	err = tps65910_i2c_read(tps65910, reg, 1, &data);
-	if (err) {
-		dev_err(tps65910->dev, "read from reg %x failed\n", reg);
-		goto out;
-	}
-
-	data |= mask;
-	err = tps65910_i2c_write(tps65910, reg, 1, &data);
-	if (err)
-		dev_err(tps65910->dev, "write to reg %x failed\n", reg);
-
-out:
-	mutex_unlock(&tps65910->io_mutex);
-	return err;
+	return regmap_update_bits(tps65910->regmap, reg, mask, mask);
 }
 EXPORT_SYMBOL_GPL(tps65910_set_bits);
 
 int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
 {
-	u8 data;
-	int err;
-
-	mutex_lock(&tps65910->io_mutex);
-	err = tps65910_i2c_read(tps65910, reg, 1, &data);
-	if (err) {
-		dev_err(tps65910->dev, "read from reg %x failed\n", reg);
-		goto out;
-	}
-
-	data &= ~mask;
-	err = tps65910_i2c_write(tps65910, reg, 1, &data);
-	if (err)
-		dev_err(tps65910->dev, "write to reg %x failed\n", reg);
-
-out:
-	mutex_unlock(&tps65910->io_mutex);
-	return err;
+	return regmap_update_bits(tps65910->regmap, reg, mask, 0);
 }
 EXPORT_SYMBOL_GPL(tps65910_clear_bits);
 
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	struct tps65910 *tps65910 = dev_get_drvdata(dev);
+
+	/*
+	 * Caching all regulator registers.
+	 * All regualator register address range is same for
+	 * TPS65910 and TPS65911
+	 */
+	if ((reg >= TPS65910_VIO) && (reg <= TPS65910_VDAC)) {
+		/* Check for non-existing register */
+		if (tps65910_chip_id(tps65910) == TPS65910)
+			if ((reg == TPS65911_VDDCTRL_OP) ||
+				(reg == TPS65911_VDDCTRL_SR))
+				return true;
+		return false;
+	}
+	return true;
+}
+
+static const struct regmap_config tps65910_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.volatile_reg = is_volatile_reg,
+	.max_register = TPS65910_MAX_REGISTER,
+	.num_reg_defaults_raw = TPS65910_MAX_REGISTER,
+	.cache_type = REGCACHE_RBTREE,
+};
+
 static int tps65910_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -161,6 +120,13 @@
 	tps65910->write = tps65910_i2c_write;
 	mutex_init(&tps65910->io_mutex);
 
+	tps65910->regmap = regmap_init_i2c(i2c, &tps65910_regmap_config);
+	if (IS_ERR(tps65910->regmap)) {
+		ret = PTR_ERR(tps65910->regmap);
+		dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
+		goto regmap_err;
+	}
+
 	ret = mfd_add_devices(tps65910->dev, -1,
 			      tps65910s, ARRAY_SIZE(tps65910s),
 			      NULL, 0);
@@ -178,6 +144,8 @@
 	return ret;
 
 err:
+	regmap_exit(tps65910->regmap);
+regmap_err:
 	kfree(tps65910);
 	kfree(init_data);
 	return ret;
@@ -189,6 +157,7 @@
 
 	tps65910_irq_exit(tps65910);
 	mfd_remove_devices(tps65910->dev);
+	regmap_exit(tps65910->regmap);
 	kfree(tps65910);
 
 	return 0;
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 806680d..7c2267e 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -46,9 +46,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c/twl.h>
 
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-#include <plat/cpu.h>
-#endif
+#include "twl-core.h"
 
 /*
  * The TWL4030 "Triton 2" is one of a family of a multi-function "Power
@@ -116,8 +114,8 @@
 #define twl_has_watchdog()        false
 #endif
 
-#if defined(CONFIG_MFD_TWL4030_AUDIO) || defined(CONFIG_MFD_TWL4030_AUDIO_MODULE) ||\
-	defined(CONFIG_TWL6040_CORE) || defined(CONFIG_TWL6040_CORE_MODULE)
+#if defined(CONFIG_MFD_TWL4030_AUDIO) || \
+	defined(CONFIG_MFD_TWL4030_AUDIO_MODULE)
 #define twl_has_codec()	true
 #else
 #define twl_has_codec()	false
@@ -147,12 +145,10 @@
 #define SUB_CHIP_ID1 1
 #define SUB_CHIP_ID2 2
 #define SUB_CHIP_ID3 3
+#define SUB_CHIP_ID_INVAL 0xff
 
 #define TWL_MODULE_LAST TWL4030_MODULE_LAST
 
-#define TWL4030_NR_IRQS    34 /* core:8, power:8, gpio: 18 */
-#define TWL6030_NR_IRQS    20
-
 /* Base Address defns for twl4030_map[] */
 
 /* subchip/slave 0 - USB ID */
@@ -314,7 +310,7 @@
 	 * so they continue to match the order in this table.
 	 */
 	{ SUB_CHIP_ID1, TWL6030_BASEADD_USB },
-	{ SUB_CHIP_ID3, TWL6030_BASEADD_AUDIO },
+	{ SUB_CHIP_ID_INVAL, TWL6030_BASEADD_AUDIO },
 	{ SUB_CHIP_ID2, TWL6030_BASEADD_DIEID },
 	{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
 	{ SUB_CHIP_ID1, TWL6030_BASEADD_PIH },
@@ -376,6 +372,11 @@
 		return -EPERM;
 	}
 	sid = twl_map[mod_no].sid;
+	if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
+		pr_err("%s: module %d is not part of the pmic\n",
+		       DRIVER_NAME, mod_no);
+		return -EINVAL;
+	}
 	twl = &twl_modules[sid];
 
 	mutex_lock(&twl->xfer_lock);
@@ -433,6 +434,11 @@
 		return -EPERM;
 	}
 	sid = twl_map[mod_no].sid;
+	if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
+		pr_err("%s: module %d is not part of the pmic\n",
+		       DRIVER_NAME, mod_no);
+		return -EINVAL;
+	}
 	twl = &twl_modules[sid];
 
 	mutex_lock(&twl->xfer_lock);
@@ -663,7 +669,8 @@
  */
 
 static int
-add_children(struct twl4030_platform_data *pdata, unsigned long features)
+add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
+		unsigned long features)
 {
 	struct device	*child;
 	unsigned sub_chip_id;
@@ -671,7 +678,7 @@
 	if (twl_has_gpio() && pdata->gpio) {
 		child = add_child(SUB_CHIP_ID1, "twl4030_gpio",
 				pdata->gpio, sizeof(*pdata->gpio),
-				false, pdata->irq_base + GPIO_INTR_OFFSET, 0);
+				false, irq_base + GPIO_INTR_OFFSET, 0);
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 	}
@@ -679,7 +686,7 @@
 	if (twl_has_keypad() && pdata->keypad) {
 		child = add_child(SUB_CHIP_ID2, "twl4030_keypad",
 				pdata->keypad, sizeof(*pdata->keypad),
-				true, pdata->irq_base + KEYPAD_INTR_OFFSET, 0);
+				true, irq_base + KEYPAD_INTR_OFFSET, 0);
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 	}
@@ -687,7 +694,7 @@
 	if (twl_has_madc() && pdata->madc) {
 		child = add_child(2, "twl4030_madc",
 				pdata->madc, sizeof(*pdata->madc),
-				true, pdata->irq_base + MADC_INTR_OFFSET, 0);
+				true, irq_base + MADC_INTR_OFFSET, 0);
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 	}
@@ -703,7 +710,7 @@
 		sub_chip_id = twl_map[TWL_MODULE_RTC].sid;
 		child = add_child(sub_chip_id, "twl_rtc",
 				NULL, 0,
-				true, pdata->irq_base + RTC_INTR_OFFSET, 0);
+				true, irq_base + RTC_INTR_OFFSET, 0);
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 	}
@@ -756,8 +763,8 @@
 				pdata->usb, sizeof(*pdata->usb),
 				true,
 				/* irq0 = USB_PRES, irq1 = USB */
-				pdata->irq_base + USB_PRES_INTR_OFFSET,
-				pdata->irq_base + USB_INTR_OFFSET);
+				irq_base + USB_PRES_INTR_OFFSET,
+				irq_base + USB_INTR_OFFSET);
 
 		if (IS_ERR(child))
 			return PTR_ERR(child);
@@ -805,8 +812,8 @@
 			pdata->usb, sizeof(*pdata->usb),
 			true,
 			/* irq1 = VBUS_PRES, irq0 = USB ID */
-			pdata->irq_base + USBOTG_INTR_OFFSET,
-			pdata->irq_base + USB_PRES_INTR_OFFSET);
+			irq_base + USBOTG_INTR_OFFSET,
+			irq_base + USB_PRES_INTR_OFFSET);
 
 		if (IS_ERR(child))
 			return PTR_ERR(child);
@@ -833,7 +840,7 @@
 
 	if (twl_has_pwrbutton() && twl_class_is_4030()) {
 		child = add_child(1, "twl4030_pwrbutton",
-				NULL, 0, true, pdata->irq_base + 8 + 0, 0);
+				NULL, 0, true, irq_base + 8 + 0, 0);
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 	}
@@ -847,15 +854,6 @@
 			return PTR_ERR(child);
 	}
 
-	if (twl_has_codec() && pdata->audio && twl_class_is_6030()) {
-		sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
-		child = add_child(sub_chip_id, "twl6040",
-				pdata->audio, sizeof(*pdata->audio),
-				false, 0, 0);
-		if (IS_ERR(child))
-			return PTR_ERR(child);
-	}
-
 	/* twl4030 regulators */
 	if (twl_has_regulator() && twl_class_is_4030()) {
 		child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1,
@@ -1092,8 +1090,8 @@
 		child = add_child(3, "twl4030_bci",
 				pdata->bci, sizeof(*pdata->bci), false,
 				/* irq0 = CHG_PRES, irq1 = BCI */
-				pdata->irq_base + BCI_PRES_INTR_OFFSET,
-				pdata->irq_base + BCI_INTR_OFFSET);
+				irq_base + BCI_PRES_INTR_OFFSET,
+				irq_base + BCI_INTR_OFFSET);
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 	}
@@ -1193,26 +1191,24 @@
 
 /*----------------------------------------------------------------------*/
 
-int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
-int twl4030_exit_irq(void);
-int twl4030_init_chip_irq(const char *chip);
-int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
-int twl6030_exit_irq(void);
 
 static int twl_remove(struct i2c_client *client)
 {
-	unsigned i;
+	unsigned i, num_slaves;
 	int status;
 
-	if (twl_class_is_4030())
+	if (twl_class_is_4030()) {
 		status = twl4030_exit_irq();
-	else
+		num_slaves = TWL_NUM_SLAVES;
+	} else {
 		status = twl6030_exit_irq();
+		num_slaves = TWL_NUM_SLAVES - 1;
+	}
 
 	if (status < 0)
 		return status;
 
-	for (i = 0; i < TWL_NUM_SLAVES; i++) {
+	for (i = 0; i < num_slaves; i++) {
 		struct twl_client	*twl = &twl_modules[i];
 
 		if (twl->client && twl->client != client)
@@ -1223,20 +1219,15 @@
 	return 0;
 }
 
-/* NOTE:  this driver only handles a single twl4030/tps659x0 chip */
+/* NOTE: This driver only handles a single twl4030/tps659x0 chip */
 static int __devinit
 twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
-	int				status;
-	unsigned			i;
 	struct twl4030_platform_data	*pdata = client->dev.platform_data;
 	struct device_node		*node = client->dev.of_node;
-	u8 temp;
-	int ret = 0;
-	int nr_irqs = TWL4030_NR_IRQS;
-
-	if ((id->driver_data) & TWL6030_CLASS)
-		nr_irqs = TWL6030_NR_IRQS;
+	int				irq_base = 0;
+	int				status;
+	unsigned			i, num_slaves;
 
 	if (node && !pdata) {
 		/*
@@ -1255,17 +1246,6 @@
 		return -EINVAL;
 	}
 
-	status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0);
-	if (IS_ERR_VALUE(status)) {
-		dev_err(&client->dev, "Fail to allocate IRQ descs\n");
-		return status;
-	}
-
-	pdata->irq_base = status;
-	pdata->irq_end = pdata->irq_base + nr_irqs;
-	irq_domain_add_legacy(node, nr_irqs, pdata->irq_base, 0,
-			      &irq_domain_simple_ops, NULL);
-
 	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
 		dev_dbg(&client->dev, "can't talk I2C?\n");
 		return -EIO;
@@ -1276,13 +1256,23 @@
 		return -EBUSY;
 	}
 
-	for (i = 0; i < TWL_NUM_SLAVES; i++) {
-		struct twl_client	*twl = &twl_modules[i];
+	if ((id->driver_data) & TWL6030_CLASS) {
+		twl_id = TWL6030_CLASS_ID;
+		twl_map = &twl6030_map[0];
+		num_slaves = TWL_NUM_SLAVES - 1;
+	} else {
+		twl_id = TWL4030_CLASS_ID;
+		twl_map = &twl4030_map[0];
+		num_slaves = TWL_NUM_SLAVES;
+	}
+
+	for (i = 0; i < num_slaves; i++) {
+		struct twl_client *twl = &twl_modules[i];
 
 		twl->address = client->addr + i;
-		if (i == 0)
+		if (i == 0) {
 			twl->client = client;
-		else {
+		} else {
 			twl->client = i2c_new_dummy(client->adapter,
 					twl->address);
 			if (!twl->client) {
@@ -1294,22 +1284,16 @@
 		}
 		mutex_init(&twl->xfer_lock);
 	}
+
 	inuse = true;
-	if ((id->driver_data) & TWL6030_CLASS) {
-		twl_id = TWL6030_CLASS_ID;
-		twl_map = &twl6030_map[0];
-	} else {
-		twl_id = TWL4030_CLASS_ID;
-		twl_map = &twl4030_map[0];
-	}
 
 	/* setup clock framework */
 	clocks_init(&client->dev, pdata->clock);
 
 	/* read TWL IDCODE Register */
 	if (twl_id == TWL4030_CLASS_ID) {
-		ret = twl_read_idcode_register();
-		WARN(ret < 0, "Error: reading twl_idcode register value\n");
+		status = twl_read_idcode_register();
+		WARN(status < 0, "Error: reading twl_idcode register value\n");
 	}
 
 	/* load power event scripts */
@@ -1317,31 +1301,31 @@
 		twl4030_power_init(pdata->power);
 
 	/* Maybe init the T2 Interrupt subsystem */
-	if (client->irq
-			&& pdata->irq_base
-			&& pdata->irq_end > pdata->irq_base) {
+	if (client->irq) {
 		if (twl_class_is_4030()) {
 			twl4030_init_chip_irq(id->name);
-			status = twl4030_init_irq(client->irq, pdata->irq_base,
-			pdata->irq_end);
+			irq_base = twl4030_init_irq(&client->dev, client->irq);
 		} else {
-			status = twl6030_init_irq(client->irq, pdata->irq_base,
-			pdata->irq_end);
+			irq_base = twl6030_init_irq(&client->dev, client->irq);
 		}
 
-		if (status < 0)
+		if (irq_base < 0) {
+			status = irq_base;
 			goto fail;
+		}
 	}
 
-	/* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
+	/*
+	 * Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
 	 * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
 	 * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
 	 */
-
 	if (twl_class_is_4030()) {
+		u8 temp;
+
 		twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1);
 		temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
-		I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
+			I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
 		twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
 	}
 
@@ -1349,11 +1333,12 @@
 	if (node)
 		status = of_platform_populate(node, NULL, NULL, &client->dev);
 	if (status)
-		status = add_children(pdata, id->driver_data);
+		status = add_children(pdata, irq_base, id->driver_data);
 
 fail:
 	if (status < 0)
 		twl_remove(client);
+
 	return status;
 }
 
diff --git a/drivers/mfd/twl-core.h b/drivers/mfd/twl-core.h
index 8c50a55..6ff99dc 100644
--- a/drivers/mfd/twl-core.h
+++ b/drivers/mfd/twl-core.h
@@ -1,9 +1,9 @@
 #ifndef __TWL_CORE_H__
 #define __TWL_CORE_H__
 
-extern int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
+extern int twl6030_init_irq(struct device *dev, int irq_num);
 extern int twl6030_exit_irq(void);
-extern int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
+extern int twl4030_init_irq(struct device *dev, int irq_num);
 extern int twl4030_exit_irq(void);
 extern int twl4030_init_chip_irq(const char *chip);
 
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index b69bb51..5d656e8 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -28,10 +28,12 @@
  */
 
 #include <linux/init.h>
+#include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
-
+#include <linux/of.h>
+#include <linux/irqdomain.h>
 #include <linux/i2c/twl.h>
 
 #include "twl-core.h"
@@ -53,13 +55,14 @@
  *	base + 8  .. base + 15	SIH for PWR_INT
  *	base + 16 .. base + 33	SIH for GPIO
  */
+#define TWL4030_CORE_NR_IRQS	8
+#define TWL4030_PWR_NR_IRQS	8
 
 /* PIH register offsets */
 #define REG_PIH_ISR_P1			0x01
 #define REG_PIH_ISR_P2			0x02
 #define REG_PIH_SIR			0x03	/* for testing */
 
-
 /* Linux could (eventually) use either IRQ line */
 static int irq_line;
 
@@ -111,7 +114,8 @@
 #define TWL4030_MODULE_INT_PWR		TWL4030_MODULE_INT
 
 
-/* Order in this table matches order in PIH_ISR.  That is,
+/*
+ * Order in this table matches order in PIH_ISR.  That is,
  * BIT(n) in PIH_ISR is sih_modules[n].
  */
 /* sih_modules_twl4030 is used both in twl4030 and twl5030 */
@@ -288,7 +292,6 @@
  */
 static irqreturn_t handle_twl4030_pih(int irq, void *devid)
 {
-	int		module_irq;
 	irqreturn_t	ret;
 	u8		pih_isr;
 
@@ -299,16 +302,18 @@
 		return IRQ_NONE;
 	}
 
-	/* these handlers deal with the relevant SIH irq status */
-	for (module_irq = twl4030_irq_base;
-			pih_isr;
-			pih_isr >>= 1, module_irq++) {
-		if (pih_isr & 0x1)
-			handle_nested_irq(module_irq);
+	while (pih_isr) {
+		unsigned long	pending = __ffs(pih_isr);
+		unsigned int	irq;
+
+		pih_isr &= ~BIT(pending);
+		irq = pending + twl4030_irq_base;
+		handle_nested_irq(irq);
 	}
 
 	return IRQ_HANDLED;
 }
+
 /*----------------------------------------------------------------------*/
 
 /*
@@ -337,7 +342,6 @@
 	memset(buf, 0xff, sizeof buf);
 	sih = sih_modules;
 	for (i = 0; i < nr_sih_modules; i++, sih++) {
-
 		/* skip USB -- it's funky */
 		if (!sih->bytes_ixr)
 			continue;
@@ -352,7 +356,8 @@
 			pr_err("twl4030: err %d initializing %s %s\n",
 					status, sih->name, "IMR");
 
-		/* Maybe disable "exclusive" mode; buffer second pending irq;
+		/*
+		 * Maybe disable "exclusive" mode; buffer second pending irq;
 		 * set Clear-On-Read (COR) bit.
 		 *
 		 * NOTE that sometimes COR polarity is documented as being
@@ -382,7 +387,8 @@
 		if (sih->irq_lines <= line)
 			continue;
 
-		/* Clear pending interrupt status.  Either the read was
+		/*
+		 * Clear pending interrupt status.  Either the read was
 		 * enough, or we need to write those bits.  Repeat, in
 		 * case an IRQ is pending (PENDDIS=0) ... that's not
 		 * uncommon with PWR_INT.PWRON.
@@ -398,7 +404,8 @@
 				status = twl_i2c_write(sih->module, buf,
 					sih->mask[line].isr_offset,
 					sih->bytes_ixr);
-			/* else COR=1 means read sufficed.
+			/*
+			 * else COR=1 means read sufficed.
 			 * (for most SIH modules...)
 			 */
 		}
@@ -410,7 +417,8 @@
 static inline void activate_irq(int irq)
 {
 #ifdef CONFIG_ARM
-	/* ARM requires an extra step to clear IRQ_NOREQUEST, which it
+	/*
+	 * ARM requires an extra step to clear IRQ_NOREQUEST, which it
 	 * sets on behalf of every irq_chip.  Also sets IRQ_NOPROBE.
 	 */
 	set_irq_flags(irq, IRQF_VALID);
@@ -620,33 +628,24 @@
 	return IRQ_HANDLED;
 }
 
-static unsigned twl4030_irq_next;
-
-/* returns the first IRQ used by this SIH bank,
- * or negative errno
- */
-int twl4030_sih_setup(int module)
+/* returns the first IRQ used by this SIH bank, or negative errno */
+int twl4030_sih_setup(struct device *dev, int module, int irq_base)
 {
 	int			sih_mod;
 	const struct sih	*sih = NULL;
 	struct sih_agent	*agent;
 	int			i, irq;
 	int			status = -EINVAL;
-	unsigned		irq_base = twl4030_irq_next;
 
 	/* only support modules with standard clear-on-read for now */
-	for (sih_mod = 0, sih = sih_modules;
-			sih_mod < nr_sih_modules;
+	for (sih_mod = 0, sih = sih_modules; sih_mod < nr_sih_modules;
 			sih_mod++, sih++) {
 		if (sih->module == module && sih->set_cor) {
-			if (!WARN((irq_base + sih->bits) > NR_IRQS,
-					"irq %d for %s too big\n",
-					irq_base + sih->bits,
-					sih->name))
-				status = 0;
+			status = 0;
 			break;
 		}
 	}
+
 	if (status < 0)
 		return status;
 
@@ -654,8 +653,6 @@
 	if (!agent)
 		return -ENOMEM;
 
-	status = 0;
-
 	agent->irq_base = irq_base;
 	agent->sih = sih;
 	agent->imr = ~0;
@@ -671,8 +668,6 @@
 		activate_irq(irq);
 	}
 
-	twl4030_irq_next += i;
-
 	/* replace generic PIH handler (handle_simple_irq) */
 	irq = sih_mod + twl4030_irq_base;
 	irq_set_handler_data(irq, agent);
@@ -680,26 +675,43 @@
 	status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0,
 				      agent->irq_name ?: sih->name, NULL);
 
-	pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name,
-			irq, irq_base, twl4030_irq_next - 1);
+	dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", sih->name,
+			irq, irq_base, irq_base + i - 1);
 
 	return status < 0 ? status : irq_base;
 }
 
 /* FIXME need a call to reverse twl4030_sih_setup() ... */
 
-
 /*----------------------------------------------------------------------*/
 
 /* FIXME pass in which interrupt line we'll use ... */
 #define twl_irq_line	0
 
-int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
+int twl4030_init_irq(struct device *dev, int irq_num)
 {
 	static struct irq_chip	twl4030_irq_chip;
+	int			status, i;
+	int			irq_base, irq_end, nr_irqs;
+	struct			device_node *node = dev->of_node;
 
-	int			status;
-	int			i;
+	/*
+	 * TWL core and pwr interrupts must be contiguous because
+	 * the hwirqs numbers are defined contiguously from 1 to 15.
+	 * Create only one domain for both.
+	 */
+	nr_irqs = TWL4030_PWR_NR_IRQS + TWL4030_CORE_NR_IRQS;
+
+	irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+	if (IS_ERR_VALUE(irq_base)) {
+		dev_err(dev, "Fail to allocate IRQ descs\n");
+		return irq_base;
+	}
+
+	irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
+			      &irq_domain_simple_ops, NULL);
+
+	irq_end = irq_base + TWL4030_CORE_NR_IRQS;
 
 	/*
 	 * Mask and clear all TWL4030 interrupts since initially we do
@@ -711,7 +723,8 @@
 
 	twl4030_irq_base = irq_base;
 
-	/* install an irq handler for each of the SIH modules;
+	/*
+	 * Install an irq handler for each of the SIH modules;
 	 * clone dummy irq_chip since PIH can't *do* anything
 	 */
 	twl4030_irq_chip = dummy_irq_chip;
@@ -725,14 +738,14 @@
 		irq_set_nested_thread(i, 1);
 		activate_irq(i);
 	}
-	twl4030_irq_next = i;
-	pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
-			irq_num, irq_base, twl4030_irq_next - 1);
+
+	dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", "PIH",
+			irq_num, irq_base, irq_end);
 
 	/* ... and the PWR_INT module ... */
-	status = twl4030_sih_setup(TWL4030_MODULE_INT);
+	status = twl4030_sih_setup(dev, TWL4030_MODULE_INT, irq_end);
 	if (status < 0) {
-		pr_err("twl4030: sih_setup PWR INT --> %d\n", status);
+		dev_err(dev, "sih_setup PWR INT --> %d\n", status);
 		goto fail;
 	}
 
@@ -741,11 +754,11 @@
 				      IRQF_ONESHOT,
 				      "TWL4030-PIH", NULL);
 	if (status < 0) {
-		pr_err("twl4030: could not claim irq%d: %d\n", irq_num, status);
+		dev_err(dev, "could not claim irq%d: %d\n", irq_num, status);
 		goto fail_rqirq;
 	}
 
-	return status;
+	return irq_base;
 fail_rqirq:
 	/* clean up twl4030_sih_setup */
 fail:
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index c6b456a..b76902f 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -39,6 +39,8 @@
 #include <linux/i2c/twl.h>
 #include <linux/platform_device.h>
 #include <linux/suspend.h>
+#include <linux/of.h>
+#include <linux/irqdomain.h>
 
 #include "twl-core.h"
 
@@ -51,8 +53,8 @@
  *
  * We set up IRQs starting at a platform-specified base. An interrupt map table,
  * specifies mapping between interrupt number and the associated module.
- *
  */
+#define TWL6030_NR_IRQS    20
 
 static int twl6030_interrupt_mapping[24] = {
 	PWR_INTR_OFFSET,	/* Bit 0	PWRON			*/
@@ -185,8 +187,17 @@
 			}
 		local_irq_enable();
 		}
-		ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes,
-				REG_INT_STS_A, 3); /* clear INT_STS_A */
+
+		/*
+		 * NOTE:
+		 * Simulation confirms that documentation is wrong w.r.t the
+		 * interrupt status clear operation. A single *byte* write to
+		 * any one of STS_A to STS_C register results in all three
+		 * STS registers being reset. Since it does not matter which
+		 * value is written, all three registers are cleared on a
+		 * single byte write, so we just use 0x0 to clear.
+		 */
+		ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A);
 		if (ret)
 			pr_warning("twl6030: I2C error in clearing PIH ISR\n");
 
@@ -227,7 +238,7 @@
 #endif
 }
 
-int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
+static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
 {
 	if (on)
 		atomic_inc(&twl6030_wakeirqs);
@@ -237,11 +248,6 @@
 	return 0;
 }
 
-/*----------------------------------------------------------------------*/
-
-static unsigned twl6030_irq_next;
-
-/*----------------------------------------------------------------------*/
 int twl6030_interrupt_unmask(u8 bit_mask, u8 offset)
 {
 	int ret;
@@ -311,7 +317,8 @@
 									ret);
 		return ret;
 	}
-	return 0;
+
+	return twl6030_irq_base + MMCDETECT_INTR_OFFSET;
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
 
@@ -340,29 +347,44 @@
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect);
 
-int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
+int twl6030_init_irq(struct device *dev, int irq_num)
 {
-
-	int	status = 0;
-	int	i;
+	struct			device_node *node = dev->of_node;
+	int			nr_irqs, irq_base, irq_end;
 	struct task_struct	*task;
-	int ret;
-	u8 mask[4];
+	static struct irq_chip  twl6030_irq_chip;
+	int			status = 0;
+	int			i;
+	u8			mask[4];
 
-	static struct irq_chip	twl6030_irq_chip;
+	nr_irqs = TWL6030_NR_IRQS;
+
+	irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+	if (IS_ERR_VALUE(irq_base)) {
+		dev_err(dev, "Fail to allocate IRQ descs\n");
+		return irq_base;
+	}
+
+	irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
+			      &irq_domain_simple_ops, NULL);
+
+	irq_end = irq_base + nr_irqs;
+
 	mask[1] = 0xFF;
 	mask[2] = 0xFF;
 	mask[3] = 0xFF;
-	ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
-			REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */
-	ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
-			REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */
-	ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
-			REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */
+
+	/* mask all int lines */
+	twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3);
+	/* mask all int sts */
+	twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3);
+	/* clear INT_STS_A,B,C */
+	twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3);
 
 	twl6030_irq_base = irq_base;
 
-	/* install an irq handler for each of the modules;
+	/*
+	 * install an irq handler for each of the modules;
 	 * clone dummy irq_chip since PIH can't *do* anything
 	 */
 	twl6030_irq_chip = dummy_irq_chip;
@@ -377,30 +399,29 @@
 		activate_irq(i);
 	}
 
-	twl6030_irq_next = i;
-	pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
-			irq_num, irq_base, twl6030_irq_next - 1);
+	dev_info(dev, "PIH (irq %d) chaining IRQs %d..%d\n",
+			irq_num, irq_base, irq_end);
 
 	/* install an irq handler to demultiplex the TWL6030 interrupt */
 	init_completion(&irq_event);
 
-	status = request_irq(irq_num, handle_twl6030_pih, 0,
-				"TWL6030-PIH", &irq_event);
+	status = request_irq(irq_num, handle_twl6030_pih, 0, "TWL6030-PIH",
+			     &irq_event);
 	if (status < 0) {
-		pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status);
+		dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
 		goto fail_irq;
 	}
 
 	task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
 	if (IS_ERR(task)) {
-		pr_err("twl6030: could not create irq %d thread!\n", irq_num);
+		dev_err(dev, "could not create irq %d thread!\n", irq_num);
 		status = PTR_ERR(task);
 		goto fail_kthread;
 	}
 
 	twl_irq = irq_num;
 	register_pm_notifier(&twl6030_irq_pm_notifier_block);
-	return status;
+	return irq_base;
 
 fail_kthread:
 	free_irq(irq_num, &irq_event);
@@ -408,6 +429,7 @@
 fail_irq:
 	for (i = irq_base; i < irq_end; i++)
 		irq_set_chip_and_handler(i, NULL, NULL);
+
 	return status;
 }
 
diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c
index cea9da6..b63c075 100644
--- a/drivers/mfd/ucb1x00-assabet.c
+++ b/drivers/mfd/ucb1x00-assabet.c
@@ -11,14 +11,15 @@
  */
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/proc_fs.h>
 #include <linux/device.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
 #include <linux/mfd/ucb1x00.h>
 
-#include <mach/dma.h>
-
-
 #define UCB1X00_ATTR(name,input)\
 static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
 			   char *buf)	\
@@ -38,14 +39,45 @@
 
 static int ucb1x00_assabet_add(struct ucb1x00_dev *dev)
 {
-	device_create_file(&dev->ucb->dev, &dev_attr_vbatt);
-	device_create_file(&dev->ucb->dev, &dev_attr_vcharger);
-	device_create_file(&dev->ucb->dev, &dev_attr_batt_temp);
+	struct ucb1x00 *ucb = dev->ucb;
+	struct platform_device *pdev;
+	struct gpio_keys_platform_data keys;
+	static struct gpio_keys_button buttons[6];
+	unsigned i;
+
+	memset(buttons, 0, sizeof(buttons));
+	memset(&keys, 0, sizeof(keys));
+
+	for (i = 0; i < ARRAY_SIZE(buttons); i++) {
+		buttons[i].code = BTN_0 + i;
+		buttons[i].gpio = ucb->gpio.base + i;
+		buttons[i].type = EV_KEY;
+		buttons[i].can_disable = true;
+	}
+
+	keys.buttons = buttons;
+	keys.nbuttons = ARRAY_SIZE(buttons);
+	keys.poll_interval = 50;
+	keys.name = "ucb1x00";
+
+	pdev = platform_device_register_data(&ucb->dev, "gpio-keys", -1,
+		&keys, sizeof(keys));
+
+	device_create_file(&ucb->dev, &dev_attr_vbatt);
+	device_create_file(&ucb->dev, &dev_attr_vcharger);
+	device_create_file(&ucb->dev, &dev_attr_batt_temp);
+
+	dev->priv = pdev;
 	return 0;
 }
 
 static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev)
 {
+	struct platform_device *pdev = dev->priv;
+
+	if (!IS_ERR(pdev))
+		platform_device_unregister(pdev);
+
 	device_remove_file(&dev->ucb->dev, &dev_attr_batt_temp);
 	device_remove_file(&dev->ucb->dev, &dev_attr_vcharger);
 	device_remove_file(&dev->ucb->dev, &dev_attr_vbatt);
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index febc90c..70f02da 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -23,14 +23,12 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/mfd/ucb1x00.h>
+#include <linux/pm.h>
 #include <linux/gpio.h>
-#include <linux/semaphore.h>
-
-#include <mach/dma.h>
-#include <mach/hardware.h>
 
 static DEFINE_MUTEX(ucb1x00_mutex);
 static LIST_HEAD(ucb1x00_drivers);
@@ -102,7 +100,7 @@
  *	ucb1x00_enable must have been called to enable the comms
  *	before using this function.
  *
- *	This function does not take any semaphores or spinlocks.
+ *	This function does not take any mutexes or spinlocks.
  */
 unsigned int ucb1x00_io_read(struct ucb1x00 *ucb)
 {
@@ -120,14 +118,22 @@
 	else
 		ucb->io_out &= ~(1 << offset);
 
+	ucb1x00_enable(ucb);
 	ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
+	ucb1x00_disable(ucb);
 	spin_unlock_irqrestore(&ucb->io_lock, flags);
 }
 
 static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
 	struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
-	return ucb1x00_reg_read(ucb, UCB_IO_DATA) & (1 << offset);
+	unsigned val;
+
+	ucb1x00_enable(ucb);
+	val = ucb1x00_reg_read(ucb, UCB_IO_DATA);
+	ucb1x00_disable(ucb);
+
+	return val & (1 << offset);
 }
 
 static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
@@ -137,7 +143,9 @@
 
 	spin_lock_irqsave(&ucb->io_lock, flags);
 	ucb->io_dir &= ~(1 << offset);
+	ucb1x00_enable(ucb);
 	ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
+	ucb1x00_disable(ucb);
 	spin_unlock_irqrestore(&ucb->io_lock, flags);
 
 	return 0;
@@ -157,6 +165,7 @@
 	else
 		ucb->io_out &= ~mask;
 
+	ucb1x00_enable(ucb);
 	if (old != ucb->io_out)
 		ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
 
@@ -164,11 +173,19 @@
 		ucb->io_dir |= mask;
 		ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
 	}
+	ucb1x00_disable(ucb);
 	spin_unlock_irqrestore(&ucb->io_lock, flags);
 
 	return 0;
 }
 
+static int ucb1x00_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
+
+	return ucb->irq_base > 0 ? ucb->irq_base + offset : -ENXIO;
+}
+
 /*
  * UCB1300 data sheet says we must:
  *  1. enable ADC	=> 5us (including reference startup time)
@@ -186,7 +203,7 @@
  *	Any code wishing to use the ADC converter must call this
  *	function prior to using it.
  *
- *	This function takes the ADC semaphore to prevent two or more
+ *	This function takes the ADC mutex to prevent two or more
  *	concurrent uses, and therefore may sleep.  As a result, it
  *	can only be called from process context, not interrupt
  *	context.
@@ -196,7 +213,7 @@
  */
 void ucb1x00_adc_enable(struct ucb1x00 *ucb)
 {
-	down(&ucb->adc_sem);
+	mutex_lock(&ucb->adc_mutex);
 
 	ucb->adc_cr |= UCB_ADC_ENA;
 
@@ -218,7 +235,7 @@
  *	complete (2 frames max without sync).
  *
  *	If called for a synchronised ADC conversion, it may sleep
- *	with the ADC semaphore held.
+ *	with the ADC mutex held.
  */
 unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
 {
@@ -246,7 +263,7 @@
  *	ucb1x00_adc_disable - disable the ADC converter
  *	@ucb: UCB1x00 structure describing chip
  *
- *	Disable the ADC converter and release the ADC semaphore.
+ *	Disable the ADC converter and release the ADC mutex.
  */
 void ucb1x00_adc_disable(struct ucb1x00 *ucb)
 {
@@ -254,7 +271,7 @@
 	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr);
 	ucb1x00_disable(ucb);
 
-	up(&ucb->adc_sem);
+	mutex_unlock(&ucb->adc_mutex);
 }
 
 /*
@@ -265,10 +282,9 @@
  * SIBCLK to talk to the chip.  We leave the clock running until
  * we have finished processing all interrupts from the chip.
  */
-static irqreturn_t ucb1x00_irq(int irqnr, void *devid)
+static void ucb1x00_irq(unsigned int irq, struct irq_desc *desc)
 {
-	struct ucb1x00 *ucb = devid;
-	struct ucb1x00_irq *irq;
+	struct ucb1x00 *ucb = irq_desc_get_handler_data(desc);
 	unsigned int isr, i;
 
 	ucb1x00_enable(ucb);
@@ -276,157 +292,104 @@
 	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
 	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
 
-	for (i = 0, irq = ucb->irq_handler; i < 16 && isr; i++, isr >>= 1, irq++)
-		if (isr & 1 && irq->fn)
-			irq->fn(i, irq->devid);
+	for (i = 0; i < 16 && isr; i++, isr >>= 1, irq++)
+		if (isr & 1)
+			generic_handle_irq(ucb->irq_base + i);
 	ucb1x00_disable(ucb);
-
-	return IRQ_HANDLED;
 }
 
-/**
- *	ucb1x00_hook_irq - hook a UCB1x00 interrupt
- *	@ucb:   UCB1x00 structure describing chip
- *	@idx:   interrupt index
- *	@fn:    function to call when interrupt is triggered
- *	@devid: device id to pass to interrupt handler
- *
- *	Hook the specified interrupt.  You can only register one handler
- *	for each interrupt source.  The interrupt source is not enabled
- *	by this function; use ucb1x00_enable_irq instead.
- *
- *	Interrupt handlers will be called with other interrupts enabled.
- *
- *	Returns zero on success, or one of the following errors:
- *	 -EINVAL if the interrupt index is invalid
- *	 -EBUSY if the interrupt has already been hooked
- */
-int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid)
+static void ucb1x00_irq_update(struct ucb1x00 *ucb, unsigned mask)
 {
-	struct ucb1x00_irq *irq;
-	int ret = -EINVAL;
-
-	if (idx < 16) {
-		irq = ucb->irq_handler + idx;
-		ret = -EBUSY;
-
-		spin_lock_irq(&ucb->lock);
-		if (irq->fn == NULL) {
-			irq->devid = devid;
-			irq->fn = fn;
-			ret = 0;
-		}
-		spin_unlock_irq(&ucb->lock);
-	}
-	return ret;
+	ucb1x00_enable(ucb);
+	if (ucb->irq_ris_enbl & mask)
+		ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
+				  ucb->irq_mask);
+	if (ucb->irq_fal_enbl & mask)
+		ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
+				  ucb->irq_mask);
+	ucb1x00_disable(ucb);
 }
 
-/**
- *	ucb1x00_enable_irq - enable an UCB1x00 interrupt source
- *	@ucb: UCB1x00 structure describing chip
- *	@idx: interrupt index
- *	@edges: interrupt edges to enable
- *
- *	Enable the specified interrupt to trigger on %UCB_RISING,
- *	%UCB_FALLING or both edges.  The interrupt should have been
- *	hooked by ucb1x00_hook_irq.
- */
-void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
+static void ucb1x00_irq_noop(struct irq_data *data)
 {
-	unsigned long flags;
-
-	if (idx < 16) {
-		spin_lock_irqsave(&ucb->lock, flags);
-
-		ucb1x00_enable(ucb);
-		if (edges & UCB_RISING) {
-			ucb->irq_ris_enbl |= 1 << idx;
-			ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
-		}
-		if (edges & UCB_FALLING) {
-			ucb->irq_fal_enbl |= 1 << idx;
-			ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
-		}
-		ucb1x00_disable(ucb);
-		spin_unlock_irqrestore(&ucb->lock, flags);
-	}
 }
 
-/**
- *	ucb1x00_disable_irq - disable an UCB1x00 interrupt source
- *	@ucb: UCB1x00 structure describing chip
- *	@edges: interrupt edges to disable
- *
- *	Disable the specified interrupt triggering on the specified
- *	(%UCB_RISING, %UCB_FALLING or both) edges.
- */
-void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
+static void ucb1x00_irq_mask(struct irq_data *data)
 {
-	unsigned long flags;
+	struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
+	unsigned mask = 1 << (data->irq - ucb->irq_base);
 
-	if (idx < 16) {
-		spin_lock_irqsave(&ucb->lock, flags);
-
-		ucb1x00_enable(ucb);
-		if (edges & UCB_RISING) {
-			ucb->irq_ris_enbl &= ~(1 << idx);
-			ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
-		}
-		if (edges & UCB_FALLING) {
-			ucb->irq_fal_enbl &= ~(1 << idx);
-			ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
-		}
-		ucb1x00_disable(ucb);
-		spin_unlock_irqrestore(&ucb->lock, flags);
-	}
+	raw_spin_lock(&ucb->irq_lock);
+	ucb->irq_mask &= ~mask;
+	ucb1x00_irq_update(ucb, mask);
+	raw_spin_unlock(&ucb->irq_lock);
 }
 
-/**
- *	ucb1x00_free_irq - disable and free the specified UCB1x00 interrupt
- *	@ucb: UCB1x00 structure describing chip
- *	@idx: interrupt index
- *	@devid: device id.
- *
- *	Disable the interrupt source and remove the handler.  devid must
- *	match the devid passed when hooking the interrupt.
- *
- *	Returns zero on success, or one of the following errors:
- *	 -EINVAL if the interrupt index is invalid
- *	 -ENOENT if devid does not match
- */
-int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid)
+static void ucb1x00_irq_unmask(struct irq_data *data)
 {
-	struct ucb1x00_irq *irq;
-	int ret;
+	struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
+	unsigned mask = 1 << (data->irq - ucb->irq_base);
 
-	if (idx >= 16)
-		goto bad;
-
-	irq = ucb->irq_handler + idx;
-	ret = -ENOENT;
-
-	spin_lock_irq(&ucb->lock);
-	if (irq->devid == devid) {
-		ucb->irq_ris_enbl &= ~(1 << idx);
-		ucb->irq_fal_enbl &= ~(1 << idx);
-
-		ucb1x00_enable(ucb);
-		ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
-		ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
-		ucb1x00_disable(ucb);
-
-		irq->fn = NULL;
-		irq->devid = NULL;
-		ret = 0;
-	}
-	spin_unlock_irq(&ucb->lock);
-	return ret;
-
-bad:
-	printk(KERN_ERR "Freeing bad UCB1x00 irq %d\n", idx);
-	return -EINVAL;
+	raw_spin_lock(&ucb->irq_lock);
+	ucb->irq_mask |= mask;
+	ucb1x00_irq_update(ucb, mask);
+	raw_spin_unlock(&ucb->irq_lock);
 }
 
+static int ucb1x00_irq_set_type(struct irq_data *data, unsigned int type)
+{
+	struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
+	unsigned mask = 1 << (data->irq - ucb->irq_base);
+
+	raw_spin_lock(&ucb->irq_lock);
+	if (type & IRQ_TYPE_EDGE_RISING)
+		ucb->irq_ris_enbl |= mask;
+	else
+		ucb->irq_ris_enbl &= ~mask;
+
+	if (type & IRQ_TYPE_EDGE_FALLING)
+		ucb->irq_fal_enbl |= mask;
+	else
+		ucb->irq_fal_enbl &= ~mask;
+	if (ucb->irq_mask & mask) {
+		ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
+				  ucb->irq_mask);
+		ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
+				  ucb->irq_mask);
+	}
+	raw_spin_unlock(&ucb->irq_lock);
+
+	return 0;
+}
+
+static int ucb1x00_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+	struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
+	struct ucb1x00_plat_data *pdata = ucb->mcp->attached_device.platform_data;
+	unsigned mask = 1 << (data->irq - ucb->irq_base);
+
+	if (!pdata || !pdata->can_wakeup)
+		return -EINVAL;
+
+	raw_spin_lock(&ucb->irq_lock);
+	if (on)
+		ucb->irq_wake |= mask;
+	else
+		ucb->irq_wake &= ~mask;
+	raw_spin_unlock(&ucb->irq_lock);
+
+	return 0;
+}
+
+static struct irq_chip ucb1x00_irqchip = {
+	.name = "ucb1x00",
+	.irq_ack = ucb1x00_irq_noop,
+	.irq_mask = ucb1x00_irq_mask,
+	.irq_unmask = ucb1x00_irq_unmask,
+	.irq_set_type = ucb1x00_irq_set_type,
+	.irq_set_wake = ucb1x00_irq_set_wake,
+};
+
 static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv)
 {
 	struct ucb1x00_dev *dev;
@@ -440,8 +403,8 @@
 		ret = drv->add(dev);
 
 		if (ret == 0) {
-			list_add(&dev->dev_node, &ucb->devs);
-			list_add(&dev->drv_node, &drv->devs);
+			list_add_tail(&dev->dev_node, &ucb->devs);
+			list_add_tail(&dev->drv_node, &drv->devs);
 		} else {
 			kfree(dev);
 		}
@@ -533,98 +496,126 @@
 
 static int ucb1x00_probe(struct mcp *mcp)
 {
-	struct ucb1x00 *ucb;
+	struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
 	struct ucb1x00_driver *drv;
-	unsigned int id;
+	struct ucb1x00 *ucb;
+	unsigned id, i, irq_base;
 	int ret = -ENODEV;
-	int temp;
+
+	/* Tell the platform to deassert the UCB1x00 reset */
+	if (pdata && pdata->reset)
+		pdata->reset(UCB_RST_PROBE);
 
 	mcp_enable(mcp);
 	id = mcp_reg_read(mcp, UCB_ID);
+	mcp_disable(mcp);
 
 	if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) {
 		printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
-		goto err_disable;
+		goto out;
 	}
 
 	ucb = kzalloc(sizeof(struct ucb1x00), GFP_KERNEL);
 	ret = -ENOMEM;
 	if (!ucb)
-		goto err_disable;
+		goto out;
 
-
+	device_initialize(&ucb->dev);
 	ucb->dev.class = &ucb1x00_class;
 	ucb->dev.parent = &mcp->attached_device;
 	dev_set_name(&ucb->dev, "ucb1x00");
 
-	spin_lock_init(&ucb->lock);
+	raw_spin_lock_init(&ucb->irq_lock);
 	spin_lock_init(&ucb->io_lock);
-	sema_init(&ucb->adc_sem, 1);
+	mutex_init(&ucb->adc_mutex);
 
 	ucb->id  = id;
 	ucb->mcp = mcp;
+
+	ret = device_add(&ucb->dev);
+	if (ret)
+		goto err_dev_add;
+
+	ucb1x00_enable(ucb);
 	ucb->irq = ucb1x00_detect_irq(ucb);
+	ucb1x00_disable(ucb);
 	if (ucb->irq == NO_IRQ) {
-		printk(KERN_ERR "UCB1x00: IRQ probe failed\n");
+		dev_err(&ucb->dev, "IRQ probe failed\n");
 		ret = -ENODEV;
-		goto err_free;
+		goto err_no_irq;
 	}
 
 	ucb->gpio.base = -1;
-	if (mcp->gpio_base != 0) {
+	irq_base = pdata ? pdata->irq_base : 0;
+	ucb->irq_base = irq_alloc_descs(-1, irq_base, 16, -1);
+	if (ucb->irq_base < 0) {
+		dev_err(&ucb->dev, "unable to allocate 16 irqs: %d\n",
+			ucb->irq_base);
+		goto err_irq_alloc;
+	}
+
+	for (i = 0; i < 16; i++) {
+		unsigned irq = ucb->irq_base + i;
+
+		irq_set_chip_and_handler(irq, &ucb1x00_irqchip, handle_edge_irq);
+		irq_set_chip_data(irq, ucb);
+		set_irq_flags(irq, IRQF_VALID | IRQ_NOREQUEST);
+	}
+
+	irq_set_irq_type(ucb->irq, IRQ_TYPE_EDGE_RISING);
+	irq_set_handler_data(ucb->irq, ucb);
+	irq_set_chained_handler(ucb->irq, ucb1x00_irq);
+
+	if (pdata && pdata->gpio_base) {
 		ucb->gpio.label = dev_name(&ucb->dev);
-		ucb->gpio.base = mcp->gpio_base;
+		ucb->gpio.dev = &ucb->dev;
+		ucb->gpio.owner = THIS_MODULE;
+		ucb->gpio.base = pdata->gpio_base;
 		ucb->gpio.ngpio = 10;
 		ucb->gpio.set = ucb1x00_gpio_set;
 		ucb->gpio.get = ucb1x00_gpio_get;
 		ucb->gpio.direction_input = ucb1x00_gpio_direction_input;
 		ucb->gpio.direction_output = ucb1x00_gpio_direction_output;
+		ucb->gpio.to_irq = ucb1x00_to_irq;
 		ret = gpiochip_add(&ucb->gpio);
 		if (ret)
-			goto err_free;
+			goto err_gpio_add;
 	} else
 		dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
 
-	ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
-			  "UCB1x00", ucb);
-	if (ret) {
-		printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
-			ucb->irq, ret);
-		goto err_gpio;
-	}
-
 	mcp_set_drvdata(mcp, ucb);
 
-	ret = device_register(&ucb->dev);
-	if (ret)
-		goto err_irq;
-
+	if (pdata)
+		device_set_wakeup_capable(&ucb->dev, pdata->can_wakeup);
 
 	INIT_LIST_HEAD(&ucb->devs);
 	mutex_lock(&ucb1x00_mutex);
-	list_add(&ucb->node, &ucb1x00_devices);
+	list_add_tail(&ucb->node, &ucb1x00_devices);
 	list_for_each_entry(drv, &ucb1x00_drivers, node) {
 		ucb1x00_add_dev(ucb, drv);
 	}
 	mutex_unlock(&ucb1x00_mutex);
 
-	goto out;
+	return ret;
 
- err_irq:
-	free_irq(ucb->irq, ucb);
- err_gpio:
-	if (ucb->gpio.base != -1)
-		temp = gpiochip_remove(&ucb->gpio);
- err_free:
-	kfree(ucb);
- err_disable:
-	mcp_disable(mcp);
+ err_gpio_add:
+	irq_set_chained_handler(ucb->irq, NULL);
+ err_irq_alloc:
+	if (ucb->irq_base > 0)
+		irq_free_descs(ucb->irq_base, 16);
+ err_no_irq:
+	device_del(&ucb->dev);
+ err_dev_add:
+	put_device(&ucb->dev);
  out:
+	if (pdata && pdata->reset)
+		pdata->reset(UCB_RST_PROBE_FAIL);
 	return ret;
 }
 
 static void ucb1x00_remove(struct mcp *mcp)
 {
+	struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
 	struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
 	struct list_head *l, *n;
 	int ret;
@@ -643,8 +634,12 @@
 			dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret);
 	}
 
-	free_irq(ucb->irq, ucb);
+	irq_set_chained_handler(ucb->irq, NULL);
+	irq_free_descs(ucb->irq_base, 16);
 	device_unregister(&ucb->dev);
+
+	if (pdata && pdata->reset)
+		pdata->reset(UCB_RST_REMOVE);
 }
 
 int ucb1x00_register_driver(struct ucb1x00_driver *drv)
@@ -653,7 +648,7 @@
 
 	INIT_LIST_HEAD(&drv->devs);
 	mutex_lock(&ucb1x00_mutex);
-	list_add(&drv->node, &ucb1x00_drivers);
+	list_add_tail(&drv->node, &ucb1x00_drivers);
 	list_for_each_entry(ucb, &ucb1x00_devices, node) {
 		ucb1x00_add_dev(ucb, drv);
 	}
@@ -674,44 +669,86 @@
 	mutex_unlock(&ucb1x00_mutex);
 }
 
-static int ucb1x00_suspend(struct mcp *mcp, pm_message_t state)
+static int ucb1x00_suspend(struct device *dev)
 {
-	struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
-	struct ucb1x00_dev *dev;
+	struct ucb1x00_plat_data *pdata = dev->platform_data;
+	struct ucb1x00 *ucb = dev_get_drvdata(dev);
+	struct ucb1x00_dev *udev;
 
 	mutex_lock(&ucb1x00_mutex);
-	list_for_each_entry(dev, &ucb->devs, dev_node) {
-		if (dev->drv->suspend)
-			dev->drv->suspend(dev, state);
+	list_for_each_entry(udev, &ucb->devs, dev_node) {
+		if (udev->drv->suspend)
+			udev->drv->suspend(udev);
 	}
 	mutex_unlock(&ucb1x00_mutex);
+
+	if (ucb->irq_wake) {
+		unsigned long flags;
+
+		raw_spin_lock_irqsave(&ucb->irq_lock, flags);
+		ucb1x00_enable(ucb);
+		ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
+				  ucb->irq_wake);
+		ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
+				  ucb->irq_wake);
+		ucb1x00_disable(ucb);
+		raw_spin_unlock_irqrestore(&ucb->irq_lock, flags);
+
+		enable_irq_wake(ucb->irq);
+	} else if (pdata && pdata->reset)
+		pdata->reset(UCB_RST_SUSPEND);
+
 	return 0;
 }
 
-static int ucb1x00_resume(struct mcp *mcp)
+static int ucb1x00_resume(struct device *dev)
 {
-	struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
-	struct ucb1x00_dev *dev;
+	struct ucb1x00_plat_data *pdata = dev->platform_data;
+	struct ucb1x00 *ucb = dev_get_drvdata(dev);
+	struct ucb1x00_dev *udev;
 
+	if (!ucb->irq_wake && pdata && pdata->reset)
+		pdata->reset(UCB_RST_RESUME);
+
+	ucb1x00_enable(ucb);
 	ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
 	ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
+
+	if (ucb->irq_wake) {
+		unsigned long flags;
+
+		raw_spin_lock_irqsave(&ucb->irq_lock, flags);
+		ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
+				  ucb->irq_mask);
+		ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
+				  ucb->irq_mask);
+		raw_spin_unlock_irqrestore(&ucb->irq_lock, flags);
+
+		disable_irq_wake(ucb->irq);
+	}
+	ucb1x00_disable(ucb);
+
 	mutex_lock(&ucb1x00_mutex);
-	list_for_each_entry(dev, &ucb->devs, dev_node) {
-		if (dev->drv->resume)
-			dev->drv->resume(dev);
+	list_for_each_entry(udev, &ucb->devs, dev_node) {
+		if (udev->drv->resume)
+			udev->drv->resume(udev);
 	}
 	mutex_unlock(&ucb1x00_mutex);
 	return 0;
 }
 
+static const struct dev_pm_ops ucb1x00_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(ucb1x00_suspend, ucb1x00_resume)
+};
+
 static struct mcp_driver ucb1x00_driver = {
 	.drv		= {
 		.name	= "ucb1x00",
+		.owner	= THIS_MODULE,
+		.pm	= &ucb1x00_pm_ops,
 	},
 	.probe		= ucb1x00_probe,
 	.remove		= ucb1x00_remove,
-	.suspend	= ucb1x00_suspend,
-	.resume		= ucb1x00_resume,
 };
 
 static int __init ucb1x00_init(void)
@@ -742,14 +779,10 @@
 EXPORT_SYMBOL(ucb1x00_adc_read);
 EXPORT_SYMBOL(ucb1x00_adc_disable);
 
-EXPORT_SYMBOL(ucb1x00_hook_irq);
-EXPORT_SYMBOL(ucb1x00_free_irq);
-EXPORT_SYMBOL(ucb1x00_enable_irq);
-EXPORT_SYMBOL(ucb1x00_disable_irq);
-
 EXPORT_SYMBOL(ucb1x00_register_driver);
 EXPORT_SYMBOL(ucb1x00_unregister_driver);
 
+MODULE_ALIAS("mcp:ucb1x00");
 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 MODULE_DESCRIPTION("UCB1x00 core driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index 63a3cbd..1e0e20c 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -20,8 +20,9 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
-#include <linux/smp.h>
+#include <linux/interrupt.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/string.h>
@@ -32,7 +33,6 @@
 #include <linux/kthread.h>
 #include <linux/mfd/ucb1x00.h>
 
-#include <mach/dma.h>
 #include <mach/collie.h>
 #include <asm/mach-types.h>
 
@@ -42,6 +42,8 @@
 	struct input_dev	*idev;
 	struct ucb1x00		*ucb;
 
+	spinlock_t		irq_lock;
+	unsigned		irq_disabled;
 	wait_queue_head_t	irq_wait;
 	struct task_struct	*rtask;
 	u16			x_res;
@@ -238,7 +240,12 @@
 		if (ucb1x00_ts_pen_down(ts)) {
 			set_current_state(TASK_INTERRUPTIBLE);
 
-			ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING);
+			spin_lock_irq(&ts->irq_lock);
+			if (ts->irq_disabled) {
+				ts->irq_disabled = 0;
+				enable_irq(ts->ucb->irq_base + UCB_IRQ_TSPX);
+			}
+			spin_unlock_irq(&ts->irq_lock);
 			ucb1x00_disable(ts->ucb);
 
 			/*
@@ -281,23 +288,37 @@
  * We only detect touch screen _touches_ with this interrupt
  * handler, and even then we just schedule our task.
  */
-static void ucb1x00_ts_irq(int idx, void *id)
+static irqreturn_t ucb1x00_ts_irq(int irq, void *id)
 {
 	struct ucb1x00_ts *ts = id;
 
-	ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
+	spin_lock(&ts->irq_lock);
+	ts->irq_disabled = 1;
+	disable_irq_nosync(ts->ucb->irq_base + UCB_IRQ_TSPX);
+	spin_unlock(&ts->irq_lock);
 	wake_up(&ts->irq_wait);
+
+	return IRQ_HANDLED;
 }
 
 static int ucb1x00_ts_open(struct input_dev *idev)
 {
 	struct ucb1x00_ts *ts = input_get_drvdata(idev);
+	unsigned long flags = 0;
 	int ret = 0;
 
 	BUG_ON(ts->rtask);
 
+	if (machine_is_collie())
+		flags = IRQF_TRIGGER_RISING;
+	else
+		flags = IRQF_TRIGGER_FALLING;
+
+	ts->irq_disabled = 0;
+
 	init_waitqueue_head(&ts->irq_wait);
-	ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
+	ret = request_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ucb1x00_ts_irq,
+			  flags, "ucb1x00-ts", ts);
 	if (ret < 0)
 		goto out;
 
@@ -314,7 +335,7 @@
 	if (!IS_ERR(ts->rtask)) {
 		ret = 0;
 	} else {
-		ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
+		free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts);
 		ts->rtask = NULL;
 		ret = -EFAULT;
 	}
@@ -334,7 +355,7 @@
 		kthread_stop(ts->rtask);
 
 	ucb1x00_enable(ts->ucb);
-	ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
+	free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts);
 	ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
 	ucb1x00_disable(ts->ucb);
 }
@@ -359,11 +380,13 @@
 	ts->ucb = dev->ucb;
 	ts->idev = idev;
 	ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
+	spin_lock_init(&ts->irq_lock);
 
 	idev->name       = "Touchscreen panel";
 	idev->id.product = ts->ucb->id;
 	idev->open       = ucb1x00_ts_open;
 	idev->close      = ucb1x00_ts_close;
+	idev->dev.parent = &ts->ucb->dev;
 
 	idev->evbit[0]   = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
 	idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index f5e54fa..838056c 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -1631,7 +1631,7 @@
 	ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
 	if (ret < 0) {
 		dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret);
-		goto err_regmap;
+		goto err;
 	}
 	switch (ret) {
 	case 0x6204:
@@ -1640,20 +1640,20 @@
 	default:
 		dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret);
 		ret = -EINVAL;
-		goto err_regmap;
+		goto err;
 	}
 
 	ret = wm831x_reg_read(wm831x, WM831X_REVISION);
 	if (ret < 0) {
 		dev_err(wm831x->dev, "Failed to read revision: %d\n", ret);
-		goto err_regmap;
+		goto err;
 	}
 	rev = (ret & WM831X_PARENT_REV_MASK) >> WM831X_PARENT_REV_SHIFT;
 
 	ret = wm831x_reg_read(wm831x, WM831X_RESET_ID);
 	if (ret < 0) {
 		dev_err(wm831x->dev, "Failed to read device ID: %d\n", ret);
-		goto err_regmap;
+		goto err;
 	}
 
 	/* Some engineering samples do not have the ID set, rely on
@@ -1728,7 +1728,7 @@
 	default:
 		dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
 		ret = -EINVAL;
-		goto err_regmap;
+		goto err;
 	}
 
 	/* This will need revisiting in future but is OK for all
@@ -1742,7 +1742,7 @@
 	ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY);
 	if (ret < 0) {
 		dev_err(wm831x->dev, "Failed to read security key: %d\n", ret);
-		goto err_regmap;
+		goto err;
 	}
 	if (ret != 0) {
 		dev_warn(wm831x->dev, "Security key had non-zero value %x\n",
@@ -1755,7 +1755,7 @@
 		ret = pdata->pre_init(wm831x);
 		if (ret != 0) {
 			dev_err(wm831x->dev, "pre_init() failed: %d\n", ret);
-			goto err_regmap;
+			goto err;
 		}
 	}
 
@@ -1778,7 +1778,7 @@
 
 	ret = wm831x_irq_init(wm831x, irq);
 	if (ret != 0)
-		goto err_regmap;
+		goto err;
 
 	wm831x_auxadc_init(wm831x);
 
@@ -1874,9 +1874,8 @@
 
 err_irq:
 	wm831x_irq_exit(wm831x);
-err_regmap:
+err:
 	mfd_remove_devices(wm831x->dev);
-	regmap_exit(wm831x->regmap);
 	return ret;
 }
 
@@ -1887,7 +1886,6 @@
 	if (wm831x->irq_base)
 		free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x);
 	wm831x_irq_exit(wm831x);
-	regmap_exit(wm831x->regmap);
 }
 
 int wm831x_device_suspend(struct wm831x *wm831x)
diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c
index cb15609..2b29cae 100644
--- a/drivers/mfd/wm831x-i2c.c
+++ b/drivers/mfd/wm831x-i2c.c
@@ -37,7 +37,7 @@
 	i2c_set_clientdata(i2c, wm831x);
 	wm831x->dev = &i2c->dev;
 
-	wm831x->regmap = regmap_init_i2c(i2c, &wm831x_regmap_config);
+	wm831x->regmap = devm_regmap_init_i2c(i2c, &wm831x_regmap_config);
 	if (IS_ERR(wm831x->regmap)) {
 		ret = PTR_ERR(wm831x->regmap);
 		dev_err(wm831x->dev, "Failed to allocate register map: %d\n",
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c
index 62ef325..4bceee9 100644
--- a/drivers/mfd/wm831x-spi.c
+++ b/drivers/mfd/wm831x-spi.c
@@ -40,7 +40,7 @@
 	dev_set_drvdata(&spi->dev, wm831x);
 	wm831x->dev = &spi->dev;
 
-	wm831x->regmap = regmap_init_spi(spi, &wm831x_regmap_config);
+	wm831x->regmap = devm_regmap_init_spi(spi, &wm831x_regmap_config);
 	if (IS_ERR(wm831x->regmap)) {
 		ret = PTR_ERR(wm831x->regmap);
 		dev_err(wm831x->dev, "Failed to allocate register map: %d\n",
@@ -89,7 +89,7 @@
 	{ "wm8326", WM8326 },
 	{ },
 };
-MODULE_DEVICE_TABLE(spi, wm831x_spi_id);
+MODULE_DEVICE_TABLE(spi, wm831x_spi_ids);
 
 static struct spi_driver wm831x_spi_driver = {
 	.driver = {
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c
index 2204893..1189a17 100644
--- a/drivers/mfd/wm8400-core.c
+++ b/drivers/mfd/wm8400-core.c
@@ -271,8 +271,7 @@
 		return -EIO;
 	}
 	if (i != reg_data[WM8400_RESET_ID].default_val) {
-		dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n",
-			reg);
+		dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n", i);
 		return -ENODEV;
 	}
 
@@ -350,7 +349,7 @@
 		goto err;
 	}
 
-	wm8400->regmap = regmap_init_i2c(i2c, &wm8400_regmap_config);
+	wm8400->regmap = devm_regmap_init_i2c(i2c, &wm8400_regmap_config);
 	if (IS_ERR(wm8400->regmap)) {
 		ret = PTR_ERR(wm8400->regmap);
 		goto err;
@@ -361,12 +360,10 @@
 
 	ret = wm8400_init(wm8400, i2c->dev.platform_data);
 	if (ret != 0)
-		goto map_err;
+		goto err;
 
 	return 0;
 
-map_err:
-	regmap_exit(wm8400->regmap);
 err:
 	return ret;
 }
@@ -376,7 +373,6 @@
 	struct wm8400 *wm8400 = i2c_get_clientdata(i2c);
 
 	wm8400_release(wm8400);
-	regmap_exit(wm8400->regmap);
 
 	return 0;
 }
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index a04b3c1..9d7ca1e 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -359,15 +359,38 @@
 }
 #endif
 
+static const __devinitdata struct reg_default wm8994_revc_patch[] = {
+	{ 0x102, 0x3 },
+	{ 0x56, 0x3 },
+	{ 0x817, 0x0 },
+	{ 0x102, 0x0 },
+};
+
+static const __devinitdata struct reg_default wm8958_reva_patch[] = {
+	{ 0x102, 0x3 },
+	{ 0xcb, 0x81 },
+	{ 0x817, 0x0 },
+	{ 0x102, 0x0 },
+};
+
+static const __devinitdata struct reg_default wm1811_reva_patch[] = {
+	{ 0x102, 0x3 },
+	{ 0x56, 0x7 },
+	{ 0x5d, 0x7e },
+	{ 0x5e, 0x0 },
+	{ 0x102, 0x0 },
+};
+
 /*
  * Instantiate the generic non-control parts of the device.
  */
-static int wm8994_device_init(struct wm8994 *wm8994, int irq)
+static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
 {
 	struct wm8994_pdata *pdata = wm8994->dev->platform_data;
 	struct regmap_config *regmap_config;
+	const struct reg_default *regmap_patch = NULL;
 	const char *devname;
-	int ret, i;
+	int ret, i, patch_regs;
 	int pulls = 0;
 
 	dev_set_drvdata(wm8994->dev, wm8994);
@@ -379,7 +402,7 @@
 			      NULL, 0);
 	if (ret != 0) {
 		dev_err(wm8994->dev, "Failed to add children: %d\n", ret);
-		goto err_regmap;
+		goto err;
 	}
 
 	switch (wm8994->type) {
@@ -394,7 +417,7 @@
 		break;
 	default:
 		BUG();
-		goto err_regmap;
+		goto err;
 	}
 
 	wm8994->supplies = devm_kzalloc(wm8994->dev,
@@ -402,7 +425,7 @@
 					wm8994->num_supplies, GFP_KERNEL);
 	if (!wm8994->supplies) {
 		ret = -ENOMEM;
-		goto err_regmap;
+		goto err;
 	}
 
 	switch (wm8994->type) {
@@ -420,14 +443,14 @@
 		break;
 	default:
 		BUG();
-		goto err_regmap;
+		goto err;
 	}
 		
 	ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
 				 wm8994->supplies);
 	if (ret != 0) {
 		dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret);
-		goto err_regmap;
+		goto err;
 	}
 
 	ret = regulator_bulk_enable(wm8994->num_supplies,
@@ -488,15 +511,44 @@
 				 "revision %c not fully supported\n",
 				 'A' + wm8994->revision);
 			break;
+		case 2:
+		case 3:
+			regmap_patch = wm8994_revc_patch;
+			patch_regs = ARRAY_SIZE(wm8994_revc_patch);
+			break;
 		default:
 			break;
 		}
 		break;
+
+	case WM8958:
+		switch (wm8994->revision) {
+		case 0:
+			regmap_patch = wm8958_reva_patch;
+			patch_regs = ARRAY_SIZE(wm8958_reva_patch);
+			break;
+		default:
+			break;
+		}
+		break;
+
 	case WM1811:
 		/* Revision C did not change the relevant layer */
 		if (wm8994->revision > 1)
 			wm8994->revision++;
+		switch (wm8994->revision) {
+		case 0:
+		case 1:
+		case 2:
+		case 3:
+			regmap_patch = wm1811_reva_patch;
+			patch_regs = ARRAY_SIZE(wm1811_reva_patch);
+			break;
+		default:
+			break;
+		}
 		break;
+
 	default:
 		break;
 	}
@@ -526,6 +578,16 @@
 		return ret;
 	}
 
+	if (regmap_patch) {
+		ret = regmap_register_patch(wm8994->regmap, regmap_patch,
+					    patch_regs);
+		if (ret != 0) {
+			dev_err(wm8994->dev, "Failed to register patch: %d\n",
+				ret);
+			goto err;
+		}
+	}
+
 	if (pdata) {
 		wm8994->irq_base = pdata->irq_base;
 		wm8994->gpio_base = pdata->gpio_base;
@@ -577,7 +639,7 @@
 	}
 
 	pm_runtime_enable(wm8994->dev);
-	pm_runtime_resume(wm8994->dev);
+	pm_runtime_idle(wm8994->dev);
 
 	return 0;
 
@@ -588,13 +650,12 @@
 			       wm8994->supplies);
 err_get:
 	regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
-err_regmap:
-	regmap_exit(wm8994->regmap);
+err:
 	mfd_remove_devices(wm8994->dev);
 	return ret;
 }
 
-static void wm8994_device_exit(struct wm8994 *wm8994)
+static __devexit void wm8994_device_exit(struct wm8994 *wm8994)
 {
 	pm_runtime_disable(wm8994->dev);
 	mfd_remove_devices(wm8994->dev);
@@ -602,7 +663,6 @@
 	regulator_bulk_disable(wm8994->num_supplies,
 			       wm8994->supplies);
 	regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
-	regmap_exit(wm8994->regmap);
 }
 
 static const struct of_device_id wm8994_of_match[] = {
@@ -613,8 +673,8 @@
 };
 MODULE_DEVICE_TABLE(of, wm8994_of_match);
 
-static int wm8994_i2c_probe(struct i2c_client *i2c,
-			    const struct i2c_device_id *id)
+static __devinit int wm8994_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
 {
 	struct wm8994 *wm8994;
 	int ret;
@@ -628,7 +688,7 @@
 	wm8994->irq = i2c->irq;
 	wm8994->type = id->driver_data;
 
-	wm8994->regmap = regmap_init_i2c(i2c, &wm8994_base_regmap_config);
+	wm8994->regmap = devm_regmap_init_i2c(i2c, &wm8994_base_regmap_config);
 	if (IS_ERR(wm8994->regmap)) {
 		ret = PTR_ERR(wm8994->regmap);
 		dev_err(wm8994->dev, "Failed to allocate register map: %d\n",
@@ -639,7 +699,7 @@
 	return wm8994_device_init(wm8994, i2c->irq);
 }
 
-static int wm8994_i2c_remove(struct i2c_client *i2c)
+static __devexit int wm8994_i2c_remove(struct i2c_client *i2c)
 {
 	struct wm8994 *wm8994 = i2c_get_clientdata(i2c);
 
@@ -668,7 +728,7 @@
 		.of_match_table = wm8994_of_match,
 	},
 	.probe = wm8994_i2c_probe,
-	.remove = wm8994_i2c_remove,
+	.remove = __devexit_p(wm8994_i2c_remove),
 	.id_table = wm8994_i2c_id,
 };
 
diff --git a/drivers/mfd/wm8994-regmap.c b/drivers/mfd/wm8994-regmap.c
index bc0c509..bfd25af 100644
--- a/drivers/mfd/wm8994-regmap.c
+++ b/drivers/mfd/wm8994-regmap.c
@@ -15,11 +15,11 @@
 #include <linux/mfd/wm8994/core.h>
 #include <linux/mfd/wm8994/registers.h>
 #include <linux/regmap.h>
+#include <linux/device.h>
 
 #include "wm8994.h"
 
 static struct reg_default wm1811_defaults[] = {
-	{ 0x0000, 0x1811 },    /* R0    - Software Reset */
 	{ 0x0001, 0x0000 },    /* R1    - Power Management (1) */
 	{ 0x0002, 0x6000 },    /* R2    - Power Management (2) */
 	{ 0x0003, 0x0000 },    /* R3    - Power Management (3) */
@@ -60,7 +60,7 @@
 	{ 0x0036, 0x0000 },    /* R54   - Speaker Mixer */
 	{ 0x0037, 0x0000 },    /* R55   - Additional Control */
 	{ 0x0038, 0x0000 },    /* R56   - AntiPOP (1) */
-	{ 0x0039, 0x0180 },    /* R57   - AntiPOP (2) */
+	{ 0x0039, 0x0000 },    /* R57   - AntiPOP (2) */
 	{ 0x003B, 0x000D },    /* R59   - LDO 1 */
 	{ 0x003C, 0x0003 },    /* R60   - LDO 2 */
 	{ 0x003D, 0x0039 },    /* R61   - MICBIAS1 */
@@ -68,16 +68,12 @@
 	{ 0x004C, 0x1F25 },    /* R76   - Charge Pump (1) */
 	{ 0x004D, 0xAB19 },    /* R77   - Charge Pump (2) */
 	{ 0x0051, 0x0004 },    /* R81   - Class W (1) */
-	{ 0x0054, 0x0000 },    /* R84   - DC Servo (1) */
 	{ 0x0055, 0x054A },    /* R85   - DC Servo (2) */
-	{ 0x0058, 0x0000 },    /* R88   - DC Servo Readback */
 	{ 0x0059, 0x0000 },    /* R89   - DC Servo (4) */
 	{ 0x0060, 0x0000 },    /* R96   - Analogue HP (1) */
 	{ 0x00C5, 0x0000 },    /* R197  - Class D Test (5) */
 	{ 0x00D0, 0x7600 },    /* R208  - Mic Detect 1 */
 	{ 0x00D1, 0x007F },    /* R209  - Mic Detect 2 */
-	{ 0x00D2, 0x0000 },    /* R210  - Mic Detect 3 */
-	{ 0x0100, 0x0100 },    /* R256  - Chip Revision */
 	{ 0x0101, 0x8004 },    /* R257  - Control Interface */
 	{ 0x0200, 0x0000 },    /* R512  - AIF1 Clocking (1) */
 	{ 0x0201, 0x0000 },    /* R513  - AIF1 Clocking (2) */
@@ -87,7 +83,6 @@
 	{ 0x0209, 0x0000 },    /* R521  - Clocking (2) */
 	{ 0x0210, 0x0083 },    /* R528  - AIF1 Rate */
 	{ 0x0211, 0x0083 },    /* R529  - AIF2 Rate */
-	{ 0x0212, 0x0000 },    /* R530  - Rate Status */
 	{ 0x0220, 0x0000 },    /* R544  - FLL1 Control (1) */
 	{ 0x0221, 0x0000 },    /* R545  - FLL1 Control (2) */
 	{ 0x0222, 0x0000 },    /* R546  - FLL1 Control (3) */
@@ -217,8 +212,6 @@
 	{ 0x070A, 0xA101 },    /* R1802 - GPIO 11 */
 	{ 0x0720, 0x0000 },    /* R1824 - Pull Control (1) */
 	{ 0x0721, 0x0156 },    /* R1825 - Pull Control (2) */
-	{ 0x0730, 0x0000 },    /* R1840 - Interrupt Status 1 */
-	{ 0x0731, 0x0000 },    /* R1841 - Interrupt Status 2 */
 	{ 0x0732, 0x0000 },    /* R1842 - Interrupt Raw Status 2 */
 	{ 0x0738, 0x07FF },    /* R1848 - Interrupt Status 1 Mask */
 	{ 0x0739, 0xDFEF },    /* R1849 - Interrupt Status 2 Mask */
@@ -227,7 +220,6 @@
 };
 
 static struct reg_default wm8994_defaults[] = {
-	{ 0x0000, 0x8994 },    /* R0     - Software Reset */ 
 	{ 0x0001, 0x0000 },    /* R1     - Power Management (1) */ 
 	{ 0x0002, 0x6000 },    /* R2     - Power Management (2) */ 
 	{ 0x0003, 0x0000 },    /* R3     - Power Management (3) */ 
@@ -274,12 +266,9 @@
 	{ 0x003C, 0x0003 },    /* R60    - LDO 2 */ 
 	{ 0x004C, 0x1F25 },    /* R76    - Charge Pump (1) */ 
 	{ 0x0051, 0x0004 },    /* R81    - Class W (1) */ 
-	{ 0x0054, 0x0000 },    /* R84    - DC Servo (1) */ 
 	{ 0x0055, 0x054A },    /* R85    - DC Servo (2) */ 
 	{ 0x0057, 0x0000 },    /* R87    - DC Servo (4) */ 
-	{ 0x0058, 0x0000 },    /* R88    - DC Servo Readback */ 
 	{ 0x0060, 0x0000 },    /* R96    - Analogue HP (1) */ 
-	{ 0x0100, 0x0003 },    /* R256   - Chip Revision */ 
 	{ 0x0101, 0x8004 },    /* R257   - Control Interface */ 
 	{ 0x0110, 0x0000 },    /* R272   - Write Sequencer Ctrl (1) */ 
 	{ 0x0111, 0x0000 },    /* R273   - Write Sequencer Ctrl (2) */ 
@@ -291,7 +280,6 @@
 	{ 0x0209, 0x0000 },    /* R521   - Clocking (2) */ 
 	{ 0x0210, 0x0083 },    /* R528   - AIF1 Rate */ 
 	{ 0x0211, 0x0083 },    /* R529   - AIF2 Rate */ 
-	{ 0x0212, 0x0000 },    /* R530   - Rate Status */ 
 	{ 0x0220, 0x0000 },    /* R544   - FLL1 Control (1) */ 
 	{ 0x0221, 0x0000 },    /* R545   - FLL1 Control (2) */ 
 	{ 0x0222, 0x0000 },    /* R546   - FLL1 Control (3) */ 
@@ -444,9 +432,6 @@
 	{ 0x070A, 0xA101 },    /* R1802  - GPIO 11 */ 
 	{ 0x0720, 0x0000 },    /* R1824  - Pull Control (1) */ 
 	{ 0x0721, 0x0156 },    /* R1825  - Pull Control (2) */ 
-	{ 0x0730, 0x0000 },    /* R1840  - Interrupt Status 1 */ 
-	{ 0x0731, 0x0000 },    /* R1841  - Interrupt Status 2 */ 
-	{ 0x0732, 0x0000 },    /* R1842  - Interrupt Raw Status 2 */ 
 	{ 0x0738, 0x07FF },    /* R1848  - Interrupt Status 1 Mask */ 
 	{ 0x0739, 0xFFFF },    /* R1849  - Interrupt Status 2 Mask */ 
 	{ 0x0740, 0x0000 },    /* R1856  - Interrupt Control */ 
@@ -454,7 +439,6 @@
 };
 
 static struct reg_default wm8958_defaults[] = {
-	{ 0x0000, 0x8958 },    /* R0     - Software Reset */ 
 	{ 0x0001, 0x0000 },    /* R1     - Power Management (1) */
 	{ 0x0002, 0x6000 },    /* R2     - Power Management (2) */
 	{ 0x0003, 0x0000 },    /* R3     - Power Management (3) */
@@ -969,6 +953,7 @@
 {
 	switch (reg) {
 	case WM8994_DC_SERVO_READBACK:
+	case WM8994_MICBIAS:
 	case WM8994_WRITE_SEQUENCER_CTRL_1:
 	case WM8994_WRITE_SEQUENCER_CTRL_2:
 	case WM8994_AIF1_ADC2_LEFT_VOLUME:
diff --git a/drivers/misc/atmel_tclib.c b/drivers/misc/atmel_tclib.c
index 4bcfc37..c8d8e38 100644
--- a/drivers/misc/atmel_tclib.c
+++ b/drivers/misc/atmel_tclib.c
@@ -6,12 +6,10 @@
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/export.h>
-
-/* Number of bytes to reserve for the iomem resource */
-#define ATMEL_TC_IOMEM_SIZE	256
-
+#include <linux/of.h>
 
 /*
  * This is a thin library to solve the problem of how to portably allocate
@@ -48,10 +46,17 @@
 	struct atmel_tc		*tc;
 	struct platform_device	*pdev = NULL;
 	struct resource		*r;
+	size_t			size;
 
 	spin_lock(&tc_list_lock);
 	list_for_each_entry(tc, &tc_list, node) {
-		if (tc->pdev->id == block) {
+		if (tc->pdev->dev.of_node) {
+			if (of_alias_get_id(tc->pdev->dev.of_node, "tcb")
+					== block) {
+				pdev = tc->pdev;
+				break;
+			}
+		} else if (tc->pdev->id == block) {
 			pdev = tc->pdev;
 			break;
 		}
@@ -61,11 +66,15 @@
 		goto fail;
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	r = request_mem_region(r->start, ATMEL_TC_IOMEM_SIZE, name);
 	if (!r)
 		goto fail;
 
-	tc->regs = ioremap(r->start, ATMEL_TC_IOMEM_SIZE);
+	size = resource_size(r);
+	r = request_mem_region(r->start, size, name);
+	if (!r)
+		goto fail;
+
+	tc->regs = ioremap(r->start, size);
 	if (!tc->regs)
 		goto fail_ioremap;
 
@@ -76,7 +85,7 @@
 	return tc;
 
 fail_ioremap:
-	release_mem_region(r->start, ATMEL_TC_IOMEM_SIZE);
+	release_mem_region(r->start, size);
 fail:
 	tc = NULL;
 	goto out;
@@ -96,7 +105,7 @@
 	spin_lock(&tc_list_lock);
 	if (tc->regs) {
 		iounmap(tc->regs);
-		release_mem_region(tc->iomem->start, ATMEL_TC_IOMEM_SIZE);
+		release_mem_region(tc->iomem->start, resource_size(tc->iomem));
 		tc->regs = NULL;
 		tc->iomem = NULL;
 	}
@@ -104,6 +113,30 @@
 }
 EXPORT_SYMBOL_GPL(atmel_tc_free);
 
+#if defined(CONFIG_OF)
+static struct atmel_tcb_config tcb_rm9200_config = {
+	.counter_width = 16,
+};
+
+static struct atmel_tcb_config tcb_sam9x5_config = {
+	.counter_width = 32,
+};
+
+static const struct of_device_id atmel_tcb_dt_ids[] = {
+	{
+		.compatible = "atmel,at91rm9200-tcb",
+		.data = &tcb_rm9200_config,
+	}, {
+		.compatible = "atmel,at91sam9x5-tcb",
+		.data = &tcb_sam9x5_config,
+	}, {
+		/* sentinel */
+	}
+};
+
+MODULE_DEVICE_TABLE(of, atmel_tcb_dt_ids);
+#endif
+
 static int __init tc_probe(struct platform_device *pdev)
 {
 	struct atmel_tc *tc;
@@ -129,6 +162,14 @@
 		return -EINVAL;
 	}
 
+	/* Now take SoC information if available */
+	if (pdev->dev.of_node) {
+		const struct of_device_id *match;
+		match = of_match_node(atmel_tcb_dt_ids, pdev->dev.of_node);
+		if (match)
+			tc->tcb_config = match->data;
+	}
+
 	tc->clk[0] = clk;
 	tc->clk[1] = clk_get(&pdev->dev, "t1_clk");
 	if (IS_ERR(tc->clk[1]))
@@ -153,7 +194,10 @@
 }
 
 static struct platform_driver tc_driver = {
-	.driver.name	= "atmel_tcb",
+	.driver = {
+		.name	= "atmel_tcb",
+		.of_match_table	= of_match_ptr(atmel_tcb_dt_ids),
+	},
 };
 
 static int __init tc_init(void)
diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c
index 366bc15..8c279da 100644
--- a/drivers/misc/carma/carma-fpga.c
+++ b/drivers/misc/carma/carma-fpga.c
@@ -560,6 +560,9 @@
 
 	/* flush the writes */
 	fpga_read_reg(priv, 0, MMAP_REG_STATUS);
+	fpga_read_reg(priv, 1, MMAP_REG_STATUS);
+	fpga_read_reg(priv, 2, MMAP_REG_STATUS);
+	fpga_read_reg(priv, 3, MMAP_REG_STATUS);
 
 	/* switch back to the external interrupt source */
 	iowrite32be(0x3F, priv->regs + SYS_IRQ_SOURCE_CTL);
@@ -591,8 +594,12 @@
 	list_move_tail(&priv->inflight->entry, &priv->used);
 	priv->inflight = NULL;
 
-	/* clear the FPGA status and re-enable interrupts */
-	data_enable_interrupts(priv);
+	/*
+	 * If data dumping is still enabled, then clear the FPGA
+	 * status registers and re-enable FPGA interrupts
+	 */
+	if (priv->enabled)
+		data_enable_interrupts(priv);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -708,6 +715,15 @@
 
 	spin_lock(&priv->lock);
 
+	/*
+	 * This is an error case that should never happen.
+	 *
+	 * If this driver has a bug and manages to re-enable interrupts while
+	 * a DMA is in progress, then we will hit this statement and should
+	 * start paying attention immediately.
+	 */
+	BUG_ON(priv->inflight != NULL);
+
 	/* hide the interrupt by switching the IRQ driver to GPIO */
 	data_disable_interrupts(priv);
 
@@ -762,11 +778,15 @@
  */
 static int data_device_enable(struct fpga_device *priv)
 {
+	bool enabled;
 	u32 val;
 	int ret;
 
 	/* multiple enables are safe: they do nothing */
-	if (priv->enabled)
+	spin_lock_irq(&priv->lock);
+	enabled = priv->enabled;
+	spin_unlock_irq(&priv->lock);
+	if (enabled)
 		return 0;
 
 	/* check that the FPGAs are programmed */
@@ -797,6 +817,9 @@
 		goto out_error;
 	}
 
+	/* prevent the FPGAs from generating interrupts */
+	data_disable_interrupts(priv);
+
 	/* hookup the irq handler */
 	ret = request_irq(priv->irq, data_irq, IRQF_SHARED, drv_name, priv);
 	if (ret) {
@@ -804,11 +827,13 @@
 		goto out_error;
 	}
 
-	/* switch to the external FPGA IRQ line */
-	data_enable_interrupts(priv);
-
-	/* success, we're enabled */
+	/* allow the DMA callback to re-enable FPGA interrupts */
+	spin_lock_irq(&priv->lock);
 	priv->enabled = true;
+	spin_unlock_irq(&priv->lock);
+
+	/* allow the FPGAs to generate interrupts */
+	data_enable_interrupts(priv);
 	return 0;
 
 out_error:
@@ -834,41 +859,40 @@
  */
 static int data_device_disable(struct fpga_device *priv)
 {
-	int ret;
+	spin_lock_irq(&priv->lock);
 
 	/* allow multiple disable */
-	if (!priv->enabled)
+	if (!priv->enabled) {
+		spin_unlock_irq(&priv->lock);
 		return 0;
+	}
 
-	/* switch to the internal GPIO IRQ line */
+	/*
+	 * Mark the device disabled
+	 *
+	 * This stops DMA callbacks from re-enabling interrupts
+	 */
+	priv->enabled = false;
+
+	/* prevent the FPGAs from generating interrupts */
 	data_disable_interrupts(priv);
 
+	/* wait until all ongoing DMA has finished */
+	while (priv->inflight != NULL) {
+		spin_unlock_irq(&priv->lock);
+		wait_event(priv->wait, priv->inflight == NULL);
+		spin_lock_irq(&priv->lock);
+	}
+
+	spin_unlock_irq(&priv->lock);
+
 	/* unhook the irq handler */
 	free_irq(priv->irq, priv);
 
-	/*
-	 * wait for all outstanding DMA to complete
-	 *
-	 * Device interrupts are disabled, therefore another buffer cannot
-	 * be marked inflight.
-	 */
-	ret = wait_event_interruptible(priv->wait, priv->inflight == NULL);
-	if (ret)
-		return ret;
-
 	/* free the correlation table */
 	sg_free_table(&priv->corl_table);
 	priv->corl_nents = 0;
 
-	/*
-	 * We are taking the spinlock not to protect priv->enabled, but instead
-	 * to make sure that there are no readers in the process of altering
-	 * the free or used lists while we are setting this flag.
-	 */
-	spin_lock_irq(&priv->lock);
-	priv->enabled = false;
-	spin_unlock_irq(&priv->lock);
-
 	/* free all buffers: the free and used lists are not being changed */
 	data_free_buffers(priv);
 	return 0;
@@ -896,15 +920,6 @@
 static int data_debug_show(struct seq_file *f, void *offset)
 {
 	struct fpga_device *priv = f->private;
-	int ret;
-
-	/*
-	 * Lock the mutex first, so that we get an accurate value for enable
-	 * Lock the spinlock next, to get accurate list counts
-	 */
-	ret = mutex_lock_interruptible(&priv->mutex);
-	if (ret)
-		return ret;
 
 	spin_lock_irq(&priv->lock);
 
@@ -917,7 +932,6 @@
 	seq_printf(f, "num_dropped: %d\n", priv->num_dropped);
 
 	spin_unlock_irq(&priv->lock);
-	mutex_unlock(&priv->mutex);
 	return 0;
 }
 
@@ -970,7 +984,13 @@
 			    char *buf)
 {
 	struct fpga_device *priv = dev_get_drvdata(dev);
-	return snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled);
+	int ret;
+
+	spin_lock_irq(&priv->lock);
+	ret = snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled);
+	spin_unlock_irq(&priv->lock);
+
+	return ret;
 }
 
 static ssize_t data_en_set(struct device *dev, struct device_attribute *attr,
@@ -986,6 +1006,7 @@
 		return -EINVAL;
 	}
 
+	/* protect against concurrent enable/disable */
 	ret = mutex_lock_interruptible(&priv->mutex);
 	if (ret)
 		return ret;
@@ -1079,6 +1100,7 @@
 	struct fpga_reader *reader = filp->private_data;
 	struct fpga_device *priv = reader->priv;
 	struct list_head *used = &priv->used;
+	bool drop_buffer = false;
 	struct data_buf *dbuf;
 	size_t avail;
 	void *data;
@@ -1166,10 +1188,12 @@
 	 * One of two things has happened, the device is disabled, or the
 	 * device has been reconfigured underneath us. In either case, we
 	 * should just throw away the buffer.
+	 *
+	 * Lockdep complains if this is done under the spinlock, so we
+	 * handle it during the unlock path.
 	 */
 	if (!priv->enabled || dbuf->size != priv->bufsize) {
-		videobuf_dma_unmap(priv->dev, &dbuf->vb);
-		data_free_buffer(dbuf);
+		drop_buffer = true;
 		goto out_unlock;
 	}
 
@@ -1178,6 +1202,12 @@
 
 out_unlock:
 	spin_unlock_irq(&priv->lock);
+
+	if (drop_buffer) {
+		videobuf_dma_unmap(priv->dev, &dbuf->vb);
+		data_free_buffer(dbuf);
+	}
+
 	return count;
 }
 
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index 3536175..6673e57 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -87,7 +87,7 @@
 static LIST_HEAD(service_processors);
 
 static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode);
-static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root);
+static void ibmasmfs_create_files (struct super_block *sb);
 static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent);
 
 
@@ -114,7 +114,6 @@
 static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent)
 {
 	struct inode *root;
-	struct dentry *root_dentry;
 
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -129,14 +128,11 @@
 	root->i_op = &simple_dir_inode_operations;
 	root->i_fop = ibmasmfs_dir_ops;
 
-	root_dentry = d_alloc_root(root);
-	if (!root_dentry) {
-		iput(root);
+	sb->s_root = d_make_root(root);
+	if (!sb->s_root)
 		return -ENOMEM;
-	}
-	sb->s_root = root_dentry;
 
-	ibmasmfs_create_files(sb, root_dentry);
+	ibmasmfs_create_files(sb);
 	return 0;
 }
 
@@ -504,12 +500,6 @@
 	return 1;
 }
 
-static int remote_settings_file_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static int remote_settings_file_close(struct inode *inode, struct file *file)
 {
 	return 0;
@@ -604,7 +594,7 @@
 };
 
 static const struct file_operations remote_settings_fops = {
-	.open =		remote_settings_file_open,
+	.open =		simple_open,
 	.release =	remote_settings_file_close,
 	.read =		remote_settings_file_read,
 	.write =	remote_settings_file_write,
@@ -612,7 +602,7 @@
 };
 
 
-static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root)
+static void ibmasmfs_create_files (struct super_block *sb)
 {
 	struct list_head *entry;
 	struct service_processor *sp;
@@ -621,7 +611,7 @@
 		struct dentry *dir;
 		struct dentry *remote_dir;
 		sp = list_entry(entry, struct service_processor, node);
-		dir = ibmasmfs_create_dir(sb, root, sp->dirname);
+		dir = ibmasmfs_create_dir(sb, sb->s_root, sp->dirname);
 		if (!dir)
 			continue;
 
diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c
index 1ccedb71..168d800 100644
--- a/drivers/misc/ibmasm/module.c
+++ b/drivers/misc/ibmasm/module.c
@@ -211,18 +211,17 @@
 
 static int __init ibmasm_init(void)
 {
-	int result;
+	int result = pci_register_driver(&ibmasm_driver);
+	if (result)
+		return result;
 
 	result = ibmasmfs_register();
 	if (result) {
+		pci_unregister_driver(&ibmasm_driver);
 		err("Failed to register ibmasmfs file system");
 		return result;
 	}
-	result = pci_register_driver(&ibmasm_driver);
-	if (result) {
-		ibmasmfs_unregister();
-		return result;
-	}
+
 	ibmasm_register_panic_notifier();
 	info(DRIVER_DESC " version " DRIVER_VERSION " loaded");
 	return 0;
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
index 3f7ad83..3aa9a96 100644
--- a/drivers/misc/kgdbts.c
+++ b/drivers/misc/kgdbts.c
@@ -134,12 +134,17 @@
 static int hwbreaks_ok;
 static int hw_break_val;
 static int hw_break_val2;
+static int cont_instead_of_sstep;
+static unsigned long cont_thread_id;
+static unsigned long sstep_thread_id;
 #if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC)
 static int arch_needs_sstep_emulation = 1;
 #else
 static int arch_needs_sstep_emulation;
 #endif
+static unsigned long cont_addr;
 static unsigned long sstep_addr;
+static int restart_from_top_after_write;
 static int sstep_state;
 
 /* Storage for the registers, in GDB format. */
@@ -187,7 +192,8 @@
 	 */
 	while (!final_ack)
 		msleep_interruptible(1500);
-
+	/* Pause for any other threads to exit after final ack. */
+	msleep_interruptible(1000);
 	if (configured)
 		kgdb_unregister_io_module(&kgdbts_io_ops);
 	configured = 0;
@@ -211,7 +217,7 @@
 	if (!strcmp(arg, "kgdbts_break_test"))
 		addr = (unsigned long)kgdbts_break_test;
 	else if (!strcmp(arg, "sys_open"))
-		addr = (unsigned long)sys_open;
+		addr = (unsigned long)do_sys_open;
 	else if (!strcmp(arg, "do_fork"))
 		addr = (unsigned long)do_fork;
 	else if (!strcmp(arg, "hw_break_val"))
@@ -283,6 +289,16 @@
 	hw_break_val++;
 }
 
+static int get_thread_id_continue(char *put_str, char *arg)
+{
+	char *ptr = &put_str[11];
+
+	if (put_str[1] != 'T' || put_str[2] != '0')
+		return 1;
+	kgdb_hex2long(&ptr, &cont_thread_id);
+	return 0;
+}
+
 static int check_and_rewind_pc(char *put_str, char *arg)
 {
 	unsigned long addr = lookup_addr(arg);
@@ -299,13 +315,21 @@
 	if (addr + BREAK_INSTR_SIZE == ip)
 		offset = -BREAK_INSTR_SIZE;
 #endif
-	if (strcmp(arg, "silent") && ip + offset != addr) {
+
+	if (arch_needs_sstep_emulation && sstep_addr &&
+	    ip + offset == sstep_addr &&
+	    ((!strcmp(arg, "sys_open") || !strcmp(arg, "do_fork")))) {
+		/* This is special case for emulated single step */
+		v2printk("Emul: rewind hit single step bp\n");
+		restart_from_top_after_write = 1;
+	} else if (strcmp(arg, "silent") && ip + offset != addr) {
 		eprintk("kgdbts: BP mismatch %lx expected %lx\n",
 			   ip + offset, addr);
 		return 1;
 	}
 	/* Readjust the instruction pointer if needed */
 	ip += offset;
+	cont_addr = ip;
 #ifdef GDB_ADJUSTS_BREAK_OFFSET
 	instruction_pointer_set(&kgdbts_regs, ip);
 #endif
@@ -315,6 +339,8 @@
 static int check_single_step(char *put_str, char *arg)
 {
 	unsigned long addr = lookup_addr(arg);
+	static int matched_id;
+
 	/*
 	 * From an arch indepent point of view the instruction pointer
 	 * should be on a different instruction
@@ -324,6 +350,29 @@
 	gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs);
 	v2printk("Singlestep stopped at IP: %lx\n",
 		   instruction_pointer(&kgdbts_regs));
+
+	if (sstep_thread_id != cont_thread_id) {
+		/*
+		 * Ensure we stopped in the same thread id as before, else the
+		 * debugger should continue until the original thread that was
+		 * single stepped is scheduled again, emulating gdb's behavior.
+		 */
+		v2printk("ThrID does not match: %lx\n", cont_thread_id);
+		if (arch_needs_sstep_emulation) {
+			if (matched_id &&
+			    instruction_pointer(&kgdbts_regs) != addr)
+				goto continue_test;
+			matched_id++;
+			ts.idx -= 2;
+			sstep_state = 0;
+			return 0;
+		}
+		cont_instead_of_sstep = 1;
+		ts.idx -= 4;
+		return 0;
+	}
+continue_test:
+	matched_id = 0;
 	if (instruction_pointer(&kgdbts_regs) == addr) {
 		eprintk("kgdbts: SingleStep failed at %lx\n",
 			   instruction_pointer(&kgdbts_regs));
@@ -365,10 +414,40 @@
 	return 1;
 }
 
+static void get_cont_catch(char *arg)
+{
+	/* Always send detach because the test is completed at this point */
+	fill_get_buf("D");
+}
+
+static int put_cont_catch(char *put_str, char *arg)
+{
+	/* This is at the end of the test and we catch any and all input */
+	v2printk("kgdbts: cleanup task: %lx\n", sstep_thread_id);
+	ts.idx--;
+	return 0;
+}
+
+static int emul_reset(char *put_str, char *arg)
+{
+	if (strncmp(put_str, "$OK", 3))
+		return 1;
+	if (restart_from_top_after_write) {
+		restart_from_top_after_write = 0;
+		ts.idx = -1;
+	}
+	return 0;
+}
+
 static void emul_sstep_get(char *arg)
 {
 	if (!arch_needs_sstep_emulation) {
-		fill_get_buf(arg);
+		if (cont_instead_of_sstep) {
+			cont_instead_of_sstep = 0;
+			fill_get_buf("c");
+		} else {
+			fill_get_buf(arg);
+		}
 		return;
 	}
 	switch (sstep_state) {
@@ -398,9 +477,11 @@
 static int emul_sstep_put(char *put_str, char *arg)
 {
 	if (!arch_needs_sstep_emulation) {
-		if (!strncmp(put_str+1, arg, 2))
-			return 0;
-		return 1;
+		char *ptr = &put_str[11];
+		if (put_str[1] != 'T' || put_str[2] != '0')
+			return 1;
+		kgdb_hex2long(&ptr, &sstep_thread_id);
+		return 0;
 	}
 	switch (sstep_state) {
 	case 1:
@@ -411,8 +492,7 @@
 		v2printk("Stopped at IP: %lx\n",
 			 instruction_pointer(&kgdbts_regs));
 		/* Want to stop at IP + break instruction size by default */
-		sstep_addr = instruction_pointer(&kgdbts_regs) +
-			BREAK_INSTR_SIZE;
+		sstep_addr = cont_addr + BREAK_INSTR_SIZE;
 		break;
 	case 2:
 		if (strncmp(put_str, "$OK", 3)) {
@@ -424,6 +504,9 @@
 		if (strncmp(put_str, "$T0", 3)) {
 			eprintk("kgdbts: failed continue sstep\n");
 			return 1;
+		} else {
+			char *ptr = &put_str[11];
+			kgdb_hex2long(&ptr, &sstep_thread_id);
 		}
 		break;
 	case 4:
@@ -502,10 +585,10 @@
 static struct test_struct singlestep_break_test[] = {
 	{ "?", "S0*" }, /* Clear break points */
 	{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
-	{ "c", "T0*", }, /* Continue */
+	{ "c", "T0*", NULL, get_thread_id_continue }, /* Continue */
+	{ "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
 	{ "g", "kgdbts_break_test", NULL, check_and_rewind_pc },
 	{ "write", "OK", write_regs }, /* Write registers */
-	{ "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
 	{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
 	{ "g", "kgdbts_break_test", NULL, check_single_step },
 	{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
@@ -523,16 +606,16 @@
 static struct test_struct do_fork_test[] = {
 	{ "?", "S0*" }, /* Clear break points */
 	{ "do_fork", "OK", sw_break, }, /* set sw breakpoint */
-	{ "c", "T0*", }, /* Continue */
-	{ "g", "do_fork", NULL, check_and_rewind_pc }, /* check location */
-	{ "write", "OK", write_regs }, /* Write registers */
+	{ "c", "T0*", NULL, get_thread_id_continue }, /* Continue */
 	{ "do_fork", "OK", sw_rem_break }, /*remove breakpoint */
+	{ "g", "do_fork", NULL, check_and_rewind_pc }, /* check location */
+	{ "write", "OK", write_regs, emul_reset }, /* Write registers */
 	{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
 	{ "g", "do_fork", NULL, check_single_step },
 	{ "do_fork", "OK", sw_break, }, /* set sw breakpoint */
 	{ "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */
 	{ "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */
-	{ "", "" },
+	{ "", "", get_cont_catch, put_cont_catch },
 };
 
 /* Test for hitting a breakpoint at sys_open for what ever the number
@@ -541,16 +624,16 @@
 static struct test_struct sys_open_test[] = {
 	{ "?", "S0*" }, /* Clear break points */
 	{ "sys_open", "OK", sw_break, }, /* set sw breakpoint */
-	{ "c", "T0*", }, /* Continue */
-	{ "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */
-	{ "write", "OK", write_regs }, /* Write registers */
+	{ "c", "T0*", NULL, get_thread_id_continue }, /* Continue */
 	{ "sys_open", "OK", sw_rem_break }, /*remove breakpoint */
+	{ "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */
+	{ "write", "OK", write_regs, emul_reset }, /* Write registers */
 	{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
 	{ "g", "sys_open", NULL, check_single_step },
 	{ "sys_open", "OK", sw_break, }, /* set sw breakpoint */
 	{ "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */
 	{ "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */
-	{ "", "" },
+	{ "", "", get_cont_catch, put_cont_catch },
 };
 
 /*
@@ -693,8 +776,8 @@
 	/* This callback is a put char which is when kgdb sends data to
 	 * this I/O module.
 	 */
-	if (ts.tst[ts.idx].get[0] == '\0' &&
-		ts.tst[ts.idx].put[0] == '\0') {
+	if (ts.tst[ts.idx].get[0] == '\0' && ts.tst[ts.idx].put[0] == '\0' &&
+	    !ts.tst[ts.idx].get_handler) {
 		eprintk("kgdbts: ERROR: beyond end of test on"
 			   " '%s' line %i\n", ts.name, ts.idx);
 		return 0;
@@ -907,6 +990,17 @@
 	if (ptr)
 		sstep_test = simple_strtol(ptr+1, NULL, 10);
 
+	/* All HW break point tests */
+	if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) {
+		hwbreaks_ok = 1;
+		v1printk("kgdbts:RUN hw breakpoint test\n");
+		run_breakpoint_test(1);
+		v1printk("kgdbts:RUN hw write breakpoint test\n");
+		run_hw_break_test(1);
+		v1printk("kgdbts:RUN access write breakpoint test\n");
+		run_hw_break_test(0);
+	}
+
 	/* required internal KGDB tests */
 	v1printk("kgdbts:RUN plant and detach test\n");
 	run_plant_and_detach_test(0);
@@ -924,35 +1018,11 @@
 
 	/* ===Optional tests=== */
 
-	/* All HW break point tests */
-	if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) {
-		hwbreaks_ok = 1;
-		v1printk("kgdbts:RUN hw breakpoint test\n");
-		run_breakpoint_test(1);
-		v1printk("kgdbts:RUN hw write breakpoint test\n");
-		run_hw_break_test(1);
-		v1printk("kgdbts:RUN access write breakpoint test\n");
-		run_hw_break_test(0);
-	}
-
 	if (nmi_sleep) {
 		v1printk("kgdbts:RUN NMI sleep %i seconds test\n", nmi_sleep);
 		run_nmi_sleep_test(nmi_sleep);
 	}
 
-#ifdef CONFIG_DEBUG_RODATA
-	/* Until there is an api to write to read-only text segments, use
-	 * HW breakpoints for the remainder of any tests, else print a
-	 * failure message if hw breakpoints do not work.
-	 */
-	if (!(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT && hwbreaks_ok)) {
-		eprintk("kgdbts: HW breakpoints do not work,"
-			"skipping remaining tests\n");
-		return;
-	}
-	force_hwbrks = 1;
-#endif /* CONFIG_DEBUG_RODATA */
-
 	/* If the do_fork test is run it will be the last test that is
 	 * executed because a kernel thread will be spawned at the very
 	 * end to unregister the debug hooks.
diff --git a/drivers/misc/sgi-gru/gru_instructions.h b/drivers/misc/sgi-gru/gru_instructions.h
index d95587c..04d5170 100644
--- a/drivers/misc/sgi-gru/gru_instructions.h
+++ b/drivers/misc/sgi-gru/gru_instructions.h
@@ -40,6 +40,7 @@
 			*((volatile unsigned long *)(p)) = v; /* force st.rel */	\
 		} while (0)
 #elif defined(CONFIG_X86_64)
+#include <asm/cacheflush.h>
 #define __flush_cache(p)		clflush(p)
 #define gru_ordered_store_ulong(p, v)					\
 		do {							\
diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h
index 851b2f2..c862cd4 100644
--- a/drivers/misc/sgi-xp/xp.h
+++ b/drivers/misc/sgi-xp/xp.h
@@ -25,7 +25,6 @@
 #endif
 
 #if defined CONFIG_IA64
-#include <asm/system.h>
 #include <asm/sn/arch.h>	/* defines is_shub1() and is_shub2() */
 #define is_shub()	ia64_platform_is("sn2")
 #endif
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index c6a383d..eed213a 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -41,7 +41,6 @@
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/sd.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 #include "queue.h"
@@ -1080,6 +1079,7 @@
 	struct mmc_blk_request *brq = &mqrq->brq;
 	struct request *req = mqrq->req;
 	struct mmc_blk_data *md = mq->data;
+	bool do_data_tag;
 
 	/*
 	 * Reliable writes are used to implement Forced Unit Access and
@@ -1156,6 +1156,16 @@
 		mmc_apply_rel_rw(brq, card, req);
 
 	/*
+	 * Data tag is used only during writing meta data to speed
+	 * up write and any subsequent read of this meta data
+	 */
+	do_data_tag = (card->ext_csd.data_tag_unit_size) &&
+		(req->cmd_flags & REQ_META) &&
+		(rq_data_dir(req) == WRITE) &&
+		((brq->data.blocks * brq->data.blksz) >=
+		 card->ext_csd.data_tag_unit_size);
+
+	/*
 	 * Pre-defined multi-block transfers are preferable to
 	 * open ended-ones (and necessary for reliable writes).
 	 * However, it is not sufficient to just send CMD23,
@@ -1173,13 +1183,13 @@
 	 * We'll avoid using CMD23-bounded multiblock writes for
 	 * these, while retaining features like reliable writes.
 	 */
-
-	if ((md->flags & MMC_BLK_CMD23) &&
-	    mmc_op_multi(brq->cmd.opcode) &&
-	    (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
+	if ((md->flags & MMC_BLK_CMD23) && mmc_op_multi(brq->cmd.opcode) &&
+	    (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23) ||
+	     do_data_tag)) {
 		brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
 		brq->sbc.arg = brq->data.blocks |
-			(do_rel_wr ? (1 << 31) : 0);
+			(do_rel_wr ? (1 << 31) : 0) |
+			(do_data_tag ? (1 << 29) : 0);
 		brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
 		brq->mrq.sbc = &brq->sbc;
 	}
@@ -1685,7 +1695,7 @@
 
 	if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
 	     card->ext_csd.boot_ro_lockable) {
-		mode_t mode;
+		umode_t mode;
 
 		if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
 			mode = S_IRUGO;
diff --git a/drivers/mmc/core/cd-gpio.c b/drivers/mmc/core/cd-gpio.c
index 082202a..29de31e 100644
--- a/drivers/mmc/core/cd-gpio.c
+++ b/drivers/mmc/core/cd-gpio.c
@@ -28,13 +28,17 @@
 	return IRQ_HANDLED;
 }
 
-int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio,
-			unsigned int irq, unsigned long flags)
+int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio)
 {
 	size_t len = strlen(dev_name(host->parent)) + 4;
-	struct mmc_cd_gpio *cd = kmalloc(sizeof(*cd) + len, GFP_KERNEL);
+	struct mmc_cd_gpio *cd;
+	int irq = gpio_to_irq(gpio);
 	int ret;
 
+	if (irq < 0)
+		return irq;
+
+	cd = kmalloc(sizeof(*cd) + len, GFP_KERNEL);
 	if (!cd)
 		return -ENOMEM;
 
@@ -45,7 +49,8 @@
 		goto egpioreq;
 
 	ret = request_threaded_irq(irq, NULL, mmc_cd_gpio_irqt,
-				   flags, cd->label, host);
+				   IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				   cd->label, host);
 	if (ret < 0)
 		goto eirqreq;
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 132378b..14f262e 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -188,6 +188,12 @@
 	struct scatterlist *sg;
 #endif
 
+	if (mrq->sbc) {
+		pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",
+			 mmc_hostname(host), mrq->sbc->opcode,
+			 mrq->sbc->arg, mrq->sbc->flags);
+	}
+
 	pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
 		 mmc_hostname(host), mrq->cmd->opcode,
 		 mrq->cmd->arg, mrq->cmd->flags);
@@ -243,16 +249,17 @@
 	complete(&mrq->completion);
 }
 
-static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
+static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
 {
 	init_completion(&mrq->completion);
 	mrq->done = mmc_wait_done;
 	if (mmc_card_removed(host->card)) {
 		mrq->cmd->error = -ENOMEDIUM;
 		complete(&mrq->completion);
-		return;
+		return -ENOMEDIUM;
 	}
 	mmc_start_request(host, mrq);
+	return 0;
 }
 
 static void mmc_wait_for_req_done(struct mmc_host *host,
@@ -336,6 +343,7 @@
 				    struct mmc_async_req *areq, int *error)
 {
 	int err = 0;
+	int start_err = 0;
 	struct mmc_async_req *data = host->areq;
 
 	/* Prepare a new request */
@@ -345,30 +353,23 @@
 	if (host->areq) {
 		mmc_wait_for_req_done(host, host->areq->mrq);
 		err = host->areq->err_check(host->card, host->areq);
-		if (err) {
-			/* post process the completed failed request */
-			mmc_post_req(host, host->areq->mrq, 0);
-			if (areq)
-				/*
-				 * Cancel the new prepared request, because
-				 * it can't run until the failed
-				 * request has been properly handled.
-				 */
-				mmc_post_req(host, areq->mrq, -EINVAL);
-
-			host->areq = NULL;
-			goto out;
-		}
 	}
 
-	if (areq)
-		__mmc_start_req(host, areq->mrq);
+	if (!err && areq)
+		start_err = __mmc_start_req(host, areq->mrq);
 
 	if (host->areq)
 		mmc_post_req(host, host->areq->mrq, 0);
 
-	host->areq = areq;
- out:
+	 /* Cancel a prepared request if it was not started. */
+	if ((err || start_err) && areq)
+			mmc_post_req(host, areq->mrq, -EINVAL);
+
+	if (err)
+		host->areq = NULL;
+	else
+		host->areq = areq;
+
 	if (error)
 		*error = err;
 	return data;
@@ -599,105 +600,6 @@
 EXPORT_SYMBOL(mmc_align_data_size);
 
 /**
- *	mmc_host_enable - enable a host.
- *	@host: mmc host to enable
- *
- *	Hosts that support power saving can use the 'enable' and 'disable'
- *	methods to exit and enter power saving states. For more information
- *	see comments for struct mmc_host_ops.
- */
-int mmc_host_enable(struct mmc_host *host)
-{
-	if (!(host->caps & MMC_CAP_DISABLE))
-		return 0;
-
-	if (host->en_dis_recurs)
-		return 0;
-
-	if (host->nesting_cnt++)
-		return 0;
-
-	cancel_delayed_work_sync(&host->disable);
-
-	if (host->enabled)
-		return 0;
-
-	if (host->ops->enable) {
-		int err;
-
-		host->en_dis_recurs = 1;
-		mmc_host_clk_hold(host);
-		err = host->ops->enable(host);
-		mmc_host_clk_release(host);
-		host->en_dis_recurs = 0;
-
-		if (err) {
-			pr_debug("%s: enable error %d\n",
-				 mmc_hostname(host), err);
-			return err;
-		}
-	}
-	host->enabled = 1;
-	return 0;
-}
-EXPORT_SYMBOL(mmc_host_enable);
-
-static int mmc_host_do_disable(struct mmc_host *host, int lazy)
-{
-	if (host->ops->disable) {
-		int err;
-
-		host->en_dis_recurs = 1;
-		mmc_host_clk_hold(host);
-		err = host->ops->disable(host, lazy);
-		mmc_host_clk_release(host);
-		host->en_dis_recurs = 0;
-
-		if (err < 0) {
-			pr_debug("%s: disable error %d\n",
-				 mmc_hostname(host), err);
-			return err;
-		}
-		if (err > 0) {
-			unsigned long delay = msecs_to_jiffies(err);
-
-			mmc_schedule_delayed_work(&host->disable, delay);
-		}
-	}
-	host->enabled = 0;
-	return 0;
-}
-
-/**
- *	mmc_host_disable - disable a host.
- *	@host: mmc host to disable
- *
- *	Hosts that support power saving can use the 'enable' and 'disable'
- *	methods to exit and enter power saving states. For more information
- *	see comments for struct mmc_host_ops.
- */
-int mmc_host_disable(struct mmc_host *host)
-{
-	int err;
-
-	if (!(host->caps & MMC_CAP_DISABLE))
-		return 0;
-
-	if (host->en_dis_recurs)
-		return 0;
-
-	if (--host->nesting_cnt)
-		return 0;
-
-	if (!host->enabled)
-		return 0;
-
-	err = mmc_host_do_disable(host, 0);
-	return err;
-}
-EXPORT_SYMBOL(mmc_host_disable);
-
-/**
  *	__mmc_claim_host - exclusively claim a host
  *	@host: mmc host to claim
  *	@abort: whether or not the operation should be aborted
@@ -735,8 +637,8 @@
 		wake_up(&host->wq);
 	spin_unlock_irqrestore(&host->lock, flags);
 	remove_wait_queue(&host->wq, &wait);
-	if (!stop)
-		mmc_host_enable(host);
+	if (host->ops->enable && !stop && host->claim_cnt == 1)
+		host->ops->enable(host);
 	return stop;
 }
 
@@ -761,21 +663,28 @@
 		claimed_host = 1;
 	}
 	spin_unlock_irqrestore(&host->lock, flags);
+	if (host->ops->enable && claimed_host && host->claim_cnt == 1)
+		host->ops->enable(host);
 	return claimed_host;
 }
 EXPORT_SYMBOL(mmc_try_claim_host);
 
 /**
- *	mmc_do_release_host - release a claimed host
+ *	mmc_release_host - release a host
  *	@host: mmc host to release
  *
- *	If you successfully claimed a host, this function will
- *	release it again.
+ *	Release a MMC host, allowing others to claim the host
+ *	for their operations.
  */
-void mmc_do_release_host(struct mmc_host *host)
+void mmc_release_host(struct mmc_host *host)
 {
 	unsigned long flags;
 
+	WARN_ON(!host->claimed);
+
+	if (host->ops->disable && host->claim_cnt == 1)
+		host->ops->disable(host);
+
 	spin_lock_irqsave(&host->lock, flags);
 	if (--host->claim_cnt) {
 		/* Release for nested claim */
@@ -787,67 +696,6 @@
 		wake_up(&host->wq);
 	}
 }
-EXPORT_SYMBOL(mmc_do_release_host);
-
-void mmc_host_deeper_disable(struct work_struct *work)
-{
-	struct mmc_host *host =
-		container_of(work, struct mmc_host, disable.work);
-
-	/* If the host is claimed then we do not want to disable it anymore */
-	if (!mmc_try_claim_host(host))
-		return;
-	mmc_host_do_disable(host, 1);
-	mmc_do_release_host(host);
-}
-
-/**
- *	mmc_host_lazy_disable - lazily disable a host.
- *	@host: mmc host to disable
- *
- *	Hosts that support power saving can use the 'enable' and 'disable'
- *	methods to exit and enter power saving states. For more information
- *	see comments for struct mmc_host_ops.
- */
-int mmc_host_lazy_disable(struct mmc_host *host)
-{
-	if (!(host->caps & MMC_CAP_DISABLE))
-		return 0;
-
-	if (host->en_dis_recurs)
-		return 0;
-
-	if (--host->nesting_cnt)
-		return 0;
-
-	if (!host->enabled)
-		return 0;
-
-	if (host->disable_delay) {
-		mmc_schedule_delayed_work(&host->disable,
-				msecs_to_jiffies(host->disable_delay));
-		return 0;
-	} else
-		return mmc_host_do_disable(host, 1);
-}
-EXPORT_SYMBOL(mmc_host_lazy_disable);
-
-/**
- *	mmc_release_host - release a host
- *	@host: mmc host to release
- *
- *	Release a MMC host, allowing others to claim the host
- *	for their operations.
- */
-void mmc_release_host(struct mmc_host *host)
-{
-	WARN_ON(!host->claimed);
-
-	mmc_host_lazy_disable(host);
-
-	mmc_do_release_host(host);
-}
-
 EXPORT_SYMBOL(mmc_release_host);
 
 /*
@@ -2115,18 +1963,36 @@
 int mmc_detect_card_removed(struct mmc_host *host)
 {
 	struct mmc_card *card = host->card;
+	int ret;
 
 	WARN_ON(!host->claimed);
+
+	if (!card)
+		return 1;
+
+	ret = mmc_card_removed(card);
 	/*
 	 * The card will be considered unchanged unless we have been asked to
 	 * detect a change or host requires polling to provide card detection.
 	 */
-	if (card && !host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL))
-		return mmc_card_removed(card);
+	if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL) &&
+	    !(host->caps2 & MMC_CAP2_DETECT_ON_ERR))
+		return ret;
 
 	host->detect_change = 0;
+	if (!ret) {
+		ret = _mmc_detect_card_removed(host);
+		if (ret && (host->caps2 & MMC_CAP2_DETECT_ON_ERR)) {
+			/*
+			 * Schedule a detect work as soon as possible to let a
+			 * rescan handle the card removal.
+			 */
+			cancel_delayed_work(&host->detect);
+			mmc_detect_change(host, 0);
+		}
+	}
 
-	return _mmc_detect_card_removed(host);
+	return ret;
 }
 EXPORT_SYMBOL(mmc_detect_card_removed);
 
@@ -2203,8 +2069,6 @@
 	spin_unlock_irqrestore(&host->lock, flags);
 #endif
 
-	if (host->caps & MMC_CAP_DISABLE)
-		cancel_delayed_work(&host->disable);
 	cancel_delayed_work_sync(&host->detect);
 	mmc_flush_scheduled_work();
 
@@ -2399,13 +2263,11 @@
 {
 	int err = 0;
 
-	if (host->caps & MMC_CAP_DISABLE)
-		cancel_delayed_work(&host->disable);
 	cancel_delayed_work(&host->detect);
 	mmc_flush_scheduled_work();
 	if (mmc_try_claim_host(host)) {
 		err = mmc_cache_ctrl(host, 0);
-		mmc_do_release_host(host);
+		mmc_release_host(host);
 	} else {
 		err = -EBUSY;
 	}
@@ -2426,7 +2288,7 @@
 			if (host->bus_ops->suspend) {
 				err = host->bus_ops->suspend(host);
 			}
-			mmc_do_release_host(host);
+			mmc_release_host(host);
 
 			if (err == -ENOSYS || !host->bus_ops->resume) {
 				/*
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index c3704e2..91c84c7 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -330,7 +330,6 @@
 	spin_lock_init(&host->lock);
 	init_waitqueue_head(&host->wq);
 	INIT_DELAYED_WORK(&host->detect, mmc_rescan);
-	INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);
 #ifdef CONFIG_PM
 	host->pm_notify.notifier_call = mmc_pm_notify;
 #endif
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index 08a7852..f2ab9e5 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -14,7 +14,6 @@
 
 int mmc_register_host_class(void);
 void mmc_unregister_host_class(void);
-void mmc_host_deeper_disable(struct work_struct *work);
 
 #endif
 
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 2b9ed14..02914d6 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -519,6 +519,20 @@
 			ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
 			ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
 			ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
+
+		if (ext_csd[EXT_CSD_DATA_SECTOR_SIZE] == 1)
+			card->ext_csd.data_sector_size = 4096;
+		else
+			card->ext_csd.data_sector_size = 512;
+
+		if ((ext_csd[EXT_CSD_DATA_TAG_SUPPORT] & 1) &&
+		    (ext_csd[EXT_CSD_TAG_UNIT_SIZE] <= 8)) {
+			card->ext_csd.data_tag_unit_size =
+			((unsigned int) 1 << ext_csd[EXT_CSD_TAG_UNIT_SIZE]) *
+			(card->ext_csd.data_sector_size);
+		} else {
+			card->ext_csd.data_tag_unit_size = 0;
+		}
 	}
 
 out:
@@ -938,7 +952,8 @@
 	 * If enhanced_area_en is TRUE, host needs to enable ERASE_GRP_DEF
 	 * bit.  This bit will be lost every time after a reset or power off.
 	 */
-	if (card->ext_csd.enhanced_area_en) {
+	if (card->ext_csd.enhanced_area_en ||
+	    (card->ext_csd.rev >= 3 && (host->caps2 & MMC_CAP2_HC_ERASE_SZ))) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				 EXT_CSD_ERASE_GROUP_DEF, 1,
 				 card->ext_csd.generic_cmd6_time);
@@ -1033,22 +1048,6 @@
 	}
 
 	/*
-	 * Enable HPI feature (if supported)
-	 */
-	if (card->ext_csd.hpi) {
-		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-			EXT_CSD_HPI_MGMT, 1, 0);
-		if (err && err != -EBADMSG)
-			goto free_card;
-		if (err) {
-			pr_warning("%s: Enabling HPI failed\n",
-				   mmc_hostname(card->host));
-			err = 0;
-		} else
-			card->ext_csd.hpi_en = 1;
-	}
-
-	/*
 	 * Compute bus speed.
 	 */
 	max_dtr = (unsigned int)-1;
@@ -1097,9 +1096,12 @@
 		 * 4. execute tuning for HS200
 		 */
 		if ((host->caps2 & MMC_CAP2_HS200) &&
-		    card->host->ops->execute_tuning)
+		    card->host->ops->execute_tuning) {
+			mmc_host_clk_hold(card->host);
 			err = card->host->ops->execute_tuning(card->host,
 				MMC_SEND_TUNING_BLOCK_HS200);
+			mmc_host_clk_release(card->host);
+		}
 		if (err) {
 			pr_warning("%s: tuning execution failed\n",
 				   mmc_hostname(card->host));
@@ -1219,6 +1221,23 @@
 	}
 
 	/*
+	 * Enable HPI feature (if supported)
+	 */
+	if (card->ext_csd.hpi) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_HPI_MGMT, 1,
+				card->ext_csd.generic_cmd6_time);
+		if (err && err != -EBADMSG)
+			goto free_card;
+		if (err) {
+			pr_warning("%s: Enabling HPI failed\n",
+				   mmc_hostname(card->host));
+			err = 0;
+		} else
+			card->ext_csd.hpi_en = 1;
+	}
+
+	/*
 	 * If cache size is higher than 0, this indicates
 	 * the existence of cache and it can be turned on.
 	 */
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 4d41fa9..69370f4 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -553,18 +553,22 @@
 {
 	struct mmc_command cmd = {0};
 	unsigned int opcode;
-	unsigned int flags;
 	int err;
 
+	if (!card->ext_csd.hpi) {
+		pr_warning("%s: Card didn't support HPI command\n",
+			   mmc_hostname(card->host));
+		return -EINVAL;
+	}
+
 	opcode = card->ext_csd.hpi_cmd;
 	if (opcode == MMC_STOP_TRANSMISSION)
-		flags = MMC_RSP_R1 | MMC_CMD_AC;
+		cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
 	else if (opcode == MMC_SEND_STATUS)
-		flags = MMC_RSP_R1 | MMC_CMD_AC;
+		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 
 	cmd.opcode = opcode;
 	cmd.arg = card->rca << 16 | 1;
-	cmd.flags = flags;
 	cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, 0);
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 00fcbed..2bc06e7 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -395,7 +395,7 @@
 
 config MMC_S3C
 	tristate "Samsung S3C SD/MMC Card Interface support"
-	depends on ARCH_S3C2410
+	depends on ARCH_S3C24XX
 	help
 	  This selects a driver for the MCI interface found in
           Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
@@ -533,6 +533,31 @@
 	  Designware Mobile Storage IP block. This disables the external DMA
 	  interface.
 
+config MMC_DW_PLTFM
+	tristate "Synopsys Designware MCI Support as platform device"
+	depends on MMC_DW
+	default y
+	help
+	  This selects the common helper functions support for Host Controller
+	  Interface based platform driver. Please select this option if the IP
+	  is present as a platform device. This is the common interface for the
+	  Synopsys Designware IP.
+
+	  If you have a controller with this interface, say Y or M here.
+
+	  If unsure, say Y.
+
+config MMC_DW_PCI
+	tristate "Synopsys Designware MCI support on PCI bus"
+	depends on MMC_DW && PCI
+	help
+	  This selects the PCI bus for the Synopsys Designware Mobile Storage IP.
+	  Select this option if the IP is present on PCI platform.
+
+	  If you have a controller with this interface, say Y or M here.
+
+	  If unsure, say N.
+
 config MMC_SH_MMCIF
 	tristate "SuperH Internal MMCIF support"
 	depends on MMC_BLOCK && (SUPERH || ARCH_SHMOBILE)
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 745f8fc..3e7e26d 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -39,6 +39,8 @@
 obj-$(CONFIG_MMC_VIA_SDMMC)	+= via-sdmmc.o
 obj-$(CONFIG_SDH_BFIN)		+= bfin_sdh.o
 obj-$(CONFIG_MMC_DW)		+= dw_mmc.o
+obj-$(CONFIG_MMC_DW_PLTFM)	+= dw_mmc-pltfm.o
+obj-$(CONFIG_MMC_DW_PCI)	+= dw_mmc-pci.o
 obj-$(CONFIG_MMC_SH_MMCIF)	+= sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)	+= jz4740_mmc.o
 obj-$(CONFIG_MMC_VUB300)	+= vub300.o
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index 947faa5..efdb81d 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -86,7 +86,6 @@
 {
 	return (   cpu_is_at91sam9260()
 		|| cpu_is_at91sam9263()
-		|| cpu_is_at91cap9()
 		|| cpu_is_at91sam9rl()
 		|| cpu_is_at91sam9g10()
 		|| cpu_is_at91sam9g20()
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index e4449a5..9819dc0 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -24,6 +24,7 @@
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/stat.h>
+#include <linux/types.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/sdio.h>
@@ -173,6 +174,7 @@
 
 	struct atmel_mci_dma	dma;
 	struct dma_chan		*data_chan;
+	struct dma_slave_config	dma_conf;
 
 	u32			cmd_status;
 	u32			data_status;
@@ -863,16 +865,17 @@
 
 	if (data->flags & MMC_DATA_READ) {
 		direction = DMA_FROM_DEVICE;
-		slave_dirn = DMA_DEV_TO_MEM;
+		host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM;
 	} else {
 		direction = DMA_TO_DEVICE;
-		slave_dirn = DMA_MEM_TO_DEV;
+		host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV;
 	}
 
 	sglen = dma_map_sg(chan->device->dev, data->sg,
 			data->sg_len, direction);
 
-	desc = chan->device->device_prep_slave_sg(chan,
+	dmaengine_slave_config(chan, &host->dma_conf);
+	desc = dmaengine_prep_slave_sg(chan,
 			data->sg, sglen, slave_dirn,
 			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc)
@@ -1960,10 +1963,6 @@
 	if (pdata && find_slave_dev(pdata->dma_slave)) {
 		dma_cap_mask_t mask;
 
-		setup_dma_addr(pdata->dma_slave,
-			       host->mapbase + ATMCI_TDR,
-			       host->mapbase + ATMCI_RDR);
-
 		/* Try to grab a DMA channel */
 		dma_cap_zero(mask);
 		dma_cap_set(DMA_SLAVE, mask);
@@ -1975,8 +1974,16 @@
 		return false;
 	} else {
 		dev_info(&host->pdev->dev,
-					"Using %s for DMA transfers\n",
+					"using %s for DMA transfers\n",
 					dma_chan_name(host->dma.chan));
+
+		host->dma_conf.src_addr = host->mapbase + ATMCI_RDR;
+		host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		host->dma_conf.src_maxburst = 1;
+		host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR;
+		host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		host->dma_conf.dst_maxburst = 1;
+		host->dma_conf.device_fc = false;
 		return true;
 	}
 }
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 64a8325..c1f3673 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -160,6 +160,16 @@
 MODULE_PARM_DESC(rw_threshold,
 		"Read/Write threshold. Default = 32");
 
+static unsigned poll_threshold = 128;
+module_param(poll_threshold, uint, S_IRUGO);
+MODULE_PARM_DESC(poll_threshold,
+		 "Polling transaction size threshold. Default = 128");
+
+static unsigned poll_loopcount = 32;
+module_param(poll_loopcount, uint, S_IRUGO);
+MODULE_PARM_DESC(poll_loopcount,
+		 "Maximum polling loop count. Default = 32");
+
 static unsigned __initdata use_dma = 1;
 module_param(use_dma, uint, 0);
 MODULE_PARM_DESC(use_dma, "Whether to use DMA or not. Default = 1");
@@ -193,6 +203,7 @@
 	bool use_dma;
 	bool do_dma;
 	bool sdio_int;
+	bool active_request;
 
 	/* Scatterlist DMA uses one or more parameter RAM entries:
 	 * the main one (associated with rxdma or txdma) plus zero or
@@ -219,6 +230,7 @@
 #endif
 };
 
+static irqreturn_t mmc_davinci_irq(int irq, void *dev_id);
 
 /* PIO only */
 static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host)
@@ -376,7 +388,20 @@
 
 	writel(cmd->arg, host->base + DAVINCI_MMCARGHL);
 	writel(cmd_reg,  host->base + DAVINCI_MMCCMD);
-	writel(im_val, host->base + DAVINCI_MMCIM);
+
+	host->active_request = true;
+
+	if (!host->do_dma && host->bytes_left <= poll_threshold) {
+		u32 count = poll_loopcount;
+
+		while (host->active_request && count--) {
+			mmc_davinci_irq(0, host);
+			cpu_relax();
+		}
+	}
+
+	if (host->active_request)
+		writel(im_val, host->base + DAVINCI_MMCIM);
 }
 
 /*----------------------------------------------------------------------*/
@@ -915,6 +940,7 @@
 	if (!data->stop || (host->cmd && host->cmd->error)) {
 		mmc_request_done(host->mmc, data->mrq);
 		writel(0, host->base + DAVINCI_MMCIM);
+		host->active_request = false;
 	} else
 		mmc_davinci_start_command(host, data->stop);
 }
@@ -942,6 +968,7 @@
 			cmd->mrq->cmd->retries = 0;
 		mmc_request_done(host->mmc, cmd->mrq);
 		writel(0, host->base + DAVINCI_MMCIM);
+		host->active_request = false;
 	}
 }
 
@@ -1009,12 +1036,33 @@
 	 * by read. So, it is not unbouned loop even in the case of
 	 * non-dma.
 	 */
-	while (host->bytes_left && (status & (MMCST0_DXRDY | MMCST0_DRRDY))) {
-		davinci_fifo_data_trans(host, rw_threshold);
-		status = readl(host->base + DAVINCI_MMCST0);
-		if (!status)
-			break;
-		qstatus |= status;
+	if (host->bytes_left && (status & (MMCST0_DXRDY | MMCST0_DRRDY))) {
+		unsigned long im_val;
+
+		/*
+		 * If interrupts fire during the following loop, they will be
+		 * handled by the handler, but the PIC will still buffer these.
+		 * As a result, the handler will be called again to serve these
+		 * needlessly. In order to avoid these spurious interrupts,
+		 * keep interrupts masked during the loop.
+		 */
+		im_val = readl(host->base + DAVINCI_MMCIM);
+		writel(0, host->base + DAVINCI_MMCIM);
+
+		do {
+			davinci_fifo_data_trans(host, rw_threshold);
+			status = readl(host->base + DAVINCI_MMCST0);
+			qstatus |= status;
+		} while (host->bytes_left &&
+			 (status & (MMCST0_DXRDY | MMCST0_DRRDY)));
+
+		/*
+		 * If an interrupt is pending, it is assumed it will fire when
+		 * it is unmasked. This assumption is also taken when the MMCIM
+		 * is first set. Otherwise, writing to MMCIM after reading the
+		 * status is race-prone.
+		 */
+		writel(im_val, host->base + DAVINCI_MMCIM);
 	}
 
 	if (qstatus & MMCST0_DATDNE) {
@@ -1418,17 +1466,14 @@
 	struct mmc_davinci_host *host = platform_get_drvdata(pdev);
 	int ret;
 
-	mmc_host_enable(host->mmc);
 	ret = mmc_suspend_host(host->mmc);
 	if (!ret) {
 		writel(0, host->base + DAVINCI_MMCIM);
 		mmc_davinci_reset_ctrl(host, 1);
-		mmc_host_disable(host->mmc);
 		clk_disable(host->clk);
 		host->suspended = 1;
 	} else {
 		host->suspended = 0;
-		mmc_host_disable(host->mmc);
 	}
 
 	return ret;
@@ -1444,7 +1489,6 @@
 		return 0;
 
 	clk_enable(host->clk);
-	mmc_host_enable(host->mmc);
 
 	mmc_davinci_reset_ctrl(host, 0);
 	ret = mmc_resume_host(host->mmc);
diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c
new file mode 100644
index 0000000..dc0d25a
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-pci.c
@@ -0,0 +1,158 @@
+/*
+ * Synopsys DesignWare Multimedia Card PCI Interface driver
+ *
+ * Copyright (C) 2012 Vayavya Labs Pvt. 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/interrupt.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/dw_mmc.h>
+#include "dw_mmc.h"
+
+#define PCI_BAR_NO 2
+#define COMPLETE_BAR 0
+#define SYNOPSYS_DW_MCI_VENDOR_ID 0x700
+#define SYNOPSYS_DW_MCI_DEVICE_ID 0x1107
+/* Defining the Capabilities */
+#define DW_MCI_CAPABILITIES (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED |\
+				MMC_CAP_SD_HIGHSPEED | MMC_CAP_8_BIT_DATA |\
+				MMC_CAP_SDIO_IRQ)
+
+static struct dw_mci_board pci_board_data = {
+	.num_slots			= 1,
+	.caps				= DW_MCI_CAPABILITIES,
+	.bus_hz				= 33 * 1000 * 1000,
+	.detect_delay_ms		= 200,
+	.fifo_depth			= 32,
+};
+
+static int __devinit dw_mci_pci_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *entries)
+{
+	struct dw_mci *host;
+	int ret;
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		return ret;
+	if (pci_request_regions(pdev, "dw_mmc_pci")) {
+		ret = -ENODEV;
+		goto err_disable_dev;
+	}
+
+	host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
+	if (!host) {
+		ret = -ENOMEM;
+		goto err_release;
+	}
+
+	host->irq = pdev->irq;
+	host->irq_flags = IRQF_SHARED;
+	host->dev = pdev->dev;
+	host->pdata = &pci_board_data;
+
+	host->regs = pci_iomap(pdev, PCI_BAR_NO, COMPLETE_BAR);
+	if (!host->regs) {
+		ret = -EIO;
+		goto err_unmap;
+	}
+
+	pci_set_drvdata(pdev, host);
+	ret = dw_mci_probe(host);
+	if (ret)
+		goto err_probe_failed;
+	return ret;
+
+err_probe_failed:
+	pci_iounmap(pdev, host->regs);
+err_unmap:
+	kfree(host);
+err_release:
+	pci_release_regions(pdev);
+err_disable_dev:
+	pci_disable_device(pdev);
+	return ret;
+}
+
+static void __devexit dw_mci_pci_remove(struct pci_dev *pdev)
+{
+	struct dw_mci *host = pci_get_drvdata(pdev);
+
+	dw_mci_remove(host);
+	pci_set_drvdata(pdev, NULL);
+	pci_release_regions(pdev);
+	pci_iounmap(pdev, host->regs);
+	kfree(host);
+	pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dw_mci_pci_suspend(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct dw_mci *host = pci_get_drvdata(pdev);
+
+	ret = dw_mci_suspend(host);
+	return ret;
+}
+
+static int dw_mci_pci_resume(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct dw_mci *host = pci_get_drvdata(pdev);
+
+	ret = dw_mci_resume(host);
+	return ret;
+}
+#else
+#define dw_mci_pci_suspend	NULL
+#define dw_mci_pci_resume	NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(dw_mci_pci_pmops, dw_mci_pci_suspend, dw_mci_pci_resume);
+
+static DEFINE_PCI_DEVICE_TABLE(dw_mci_pci_id) = {
+	{ PCI_DEVICE(SYNOPSYS_DW_MCI_VENDOR_ID, SYNOPSYS_DW_MCI_DEVICE_ID) },
+	{}
+};
+MODULE_DEVICE_TABLE(pci, dw_mci_pci_id);
+
+static struct pci_driver dw_mci_pci_driver = {
+	.name		= "dw_mmc_pci",
+	.id_table	= dw_mci_pci_id,
+	.probe		= dw_mci_pci_probe,
+	.remove		= dw_mci_pci_remove,
+	.driver		=	{
+		.pm =   &dw_mci_pci_pmops
+	},
+};
+
+static int __init dw_mci_init(void)
+{
+	return pci_register_driver(&dw_mci_pci_driver);
+}
+
+static void __exit dw_mci_exit(void)
+{
+	pci_unregister_driver(&dw_mci_pci_driver);
+}
+
+module_init(dw_mci_init);
+module_exit(dw_mci_exit);
+
+MODULE_DESCRIPTION("DW Multimedia Card PCI Interface driver");
+MODULE_AUTHOR("Shashidhar Hiremath <shashidharh@vayavyalabs.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
new file mode 100644
index 0000000..92ec3eb
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -0,0 +1,134 @@
+/*
+ * Synopsys DesignWare Multimedia Card Interface driver
+ *
+ * Copyright (C) 2009 NXP Semiconductors
+ * Copyright (C) 2009, 2010 Imagination Technologies 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/interrupt.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/dw_mmc.h>
+#include "dw_mmc.h"
+
+static int dw_mci_pltfm_probe(struct platform_device *pdev)
+{
+	struct dw_mci *host;
+	struct resource	*regs;
+	int ret;
+
+	host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
+	if (!host)
+		return -ENOMEM;
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs) {
+		ret = -ENXIO;
+		goto err_free;
+	}
+
+	host->irq = platform_get_irq(pdev, 0);
+	if (host->irq < 0) {
+		ret = host->irq;
+		goto err_free;
+	}
+
+	host->dev = pdev->dev;
+	host->irq_flags = 0;
+	host->pdata = pdev->dev.platform_data;
+	ret = -ENOMEM;
+	host->regs = ioremap(regs->start, resource_size(regs));
+	if (!host->regs)
+		goto err_free;
+	platform_set_drvdata(pdev, host);
+	ret = dw_mci_probe(host);
+	if (ret)
+		goto err_out;
+	return ret;
+err_out:
+	iounmap(host->regs);
+err_free:
+	kfree(host);
+	return ret;
+}
+
+static int __exit dw_mci_pltfm_remove(struct platform_device *pdev)
+{
+	struct dw_mci *host = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	dw_mci_remove(host);
+	iounmap(host->regs);
+	kfree(host);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+/*
+ * TODO: we should probably disable the clock to the card in the suspend path.
+ */
+static int dw_mci_pltfm_suspend(struct device *dev)
+{
+	int ret;
+	struct dw_mci *host = dev_get_drvdata(dev);
+
+	ret = dw_mci_suspend(host);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int dw_mci_pltfm_resume(struct device *dev)
+{
+	int ret;
+	struct dw_mci *host = dev_get_drvdata(dev);
+
+	ret = dw_mci_resume(host);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+#else
+#define dw_mci_pltfm_suspend	NULL
+#define dw_mci_pltfm_resume	NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(dw_mci_pltfm_pmops, dw_mci_pltfm_suspend, dw_mci_pltfm_resume);
+
+static struct platform_driver dw_mci_pltfm_driver = {
+	.remove		= __exit_p(dw_mci_pltfm_remove),
+	.driver		= {
+		.name		= "dw_mmc",
+		.pm		= &dw_mci_pltfm_pmops,
+	},
+};
+
+static int __init dw_mci_init(void)
+{
+	return platform_driver_probe(&dw_mci_pltfm_driver, dw_mci_pltfm_probe);
+}
+
+static void __exit dw_mci_exit(void)
+{
+	platform_driver_unregister(&dw_mci_pltfm_driver);
+}
+
+module_init(dw_mci_init);
+module_exit(dw_mci_exit);
+
+MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
+MODULE_AUTHOR("NXP Semiconductor VietNam");
+MODULE_AUTHOR("Imagination Technologies Ltd");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 8bec1c3..bf3c9b4 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -268,7 +268,7 @@
 				 struct mmc_command *cmd, u32 cmd_flags)
 {
 	host->cmd = cmd;
-	dev_vdbg(&host->pdev->dev,
+	dev_vdbg(&host->dev,
 		 "start command: ARGR=0x%08x CMDR=0x%08x\n",
 		 cmd->arg, cmd_flags);
 
@@ -295,15 +295,25 @@
 	}
 }
 
+static int dw_mci_get_dma_dir(struct mmc_data *data)
+{
+	if (data->flags & MMC_DATA_WRITE)
+		return DMA_TO_DEVICE;
+	else
+		return DMA_FROM_DEVICE;
+}
+
 #ifdef CONFIG_MMC_DW_IDMAC
 static void dw_mci_dma_cleanup(struct dw_mci *host)
 {
 	struct mmc_data *data = host->data;
 
 	if (data)
-		dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
-			     ((data->flags & MMC_DATA_WRITE)
-			      ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+		if (!data->host_cookie)
+			dma_unmap_sg(&host->dev,
+				     data->sg,
+				     data->sg_len,
+				     dw_mci_get_dma_dir(data));
 }
 
 static void dw_mci_idmac_stop_dma(struct dw_mci *host)
@@ -326,7 +336,7 @@
 {
 	struct mmc_data *data = host->data;
 
-	dev_vdbg(&host->pdev->dev, "DMA complete\n");
+	dev_vdbg(&host->dev, "DMA complete\n");
 
 	host->dma_ops->cleanup(host);
 
@@ -428,17 +438,15 @@
 };
 #endif /* CONFIG_MMC_DW_IDMAC */
 
-static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
+static int dw_mci_pre_dma_transfer(struct dw_mci *host,
+				   struct mmc_data *data,
+				   bool next)
 {
 	struct scatterlist *sg;
-	unsigned int i, direction, sg_len;
-	u32 temp;
+	unsigned int i, sg_len;
 
-	host->using_dma = 0;
-
-	/* If we don't have a channel, we can't do DMA */
-	if (!host->use_dma)
-		return -ENODEV;
+	if (!next && data->host_cookie)
+		return data->host_cookie;
 
 	/*
 	 * We don't do DMA on "complex" transfers, i.e. with
@@ -447,6 +455,7 @@
 	 */
 	if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD)
 		return -EINVAL;
+
 	if (data->blksz & 3)
 		return -EINVAL;
 
@@ -455,17 +464,74 @@
 			return -EINVAL;
 	}
 
+	sg_len = dma_map_sg(&host->dev,
+			    data->sg,
+			    data->sg_len,
+			    dw_mci_get_dma_dir(data));
+	if (sg_len == 0)
+		return -EINVAL;
+
+	if (next)
+		data->host_cookie = sg_len;
+
+	return sg_len;
+}
+
+static void dw_mci_pre_req(struct mmc_host *mmc,
+			   struct mmc_request *mrq,
+			   bool is_first_req)
+{
+	struct dw_mci_slot *slot = mmc_priv(mmc);
+	struct mmc_data *data = mrq->data;
+
+	if (!slot->host->use_dma || !data)
+		return;
+
+	if (data->host_cookie) {
+		data->host_cookie = 0;
+		return;
+	}
+
+	if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0)
+		data->host_cookie = 0;
+}
+
+static void dw_mci_post_req(struct mmc_host *mmc,
+			    struct mmc_request *mrq,
+			    int err)
+{
+	struct dw_mci_slot *slot = mmc_priv(mmc);
+	struct mmc_data *data = mrq->data;
+
+	if (!slot->host->use_dma || !data)
+		return;
+
+	if (data->host_cookie)
+		dma_unmap_sg(&slot->host->dev,
+			     data->sg,
+			     data->sg_len,
+			     dw_mci_get_dma_dir(data));
+	data->host_cookie = 0;
+}
+
+static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
+{
+	int sg_len;
+	u32 temp;
+
+	host->using_dma = 0;
+
+	/* If we don't have a channel, we can't do DMA */
+	if (!host->use_dma)
+		return -ENODEV;
+
+	sg_len = dw_mci_pre_dma_transfer(host, data, 0);
+	if (sg_len < 0)
+		return sg_len;
+
 	host->using_dma = 1;
 
-	if (data->flags & MMC_DATA_READ)
-		direction = DMA_FROM_DEVICE;
-	else
-		direction = DMA_TO_DEVICE;
-
-	sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len,
-			    direction);
-
-	dev_vdbg(&host->pdev->dev,
+	dev_vdbg(&host->dev,
 		 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
 		 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
 		 sg_len);
@@ -579,8 +645,8 @@
 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
 
 		/* enable clock */
-		mci_writel(host, CLKENA, SDMMC_CLKEN_ENABLE |
-			   SDMMC_CLKEN_LOW_PWR);
+		mci_writel(host, CLKENA, ((SDMMC_CLKEN_ENABLE |
+			   SDMMC_CLKEN_LOW_PWR) << slot->id));
 
 		/* inform CIU */
 		mci_send_cmd(slot,
@@ -800,6 +866,8 @@
 
 static const struct mmc_host_ops dw_mci_ops = {
 	.request		= dw_mci_request,
+	.pre_req		= dw_mci_pre_req,
+	.post_req		= dw_mci_post_req,
 	.set_ios		= dw_mci_set_ios,
 	.get_ro			= dw_mci_get_ro,
 	.get_cd			= dw_mci_get_cd,
@@ -821,12 +889,12 @@
 		slot = list_entry(host->queue.next,
 				  struct dw_mci_slot, queue_node);
 		list_del(&slot->queue_node);
-		dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n",
+		dev_vdbg(&host->dev, "list not empty: %s is next\n",
 			 mmc_hostname(slot->mmc));
 		host->state = STATE_SENDING_CMD;
 		dw_mci_start_request(host, slot);
 	} else {
-		dev_vdbg(&host->pdev->dev, "list empty\n");
+		dev_vdbg(&host->dev, "list empty\n");
 		host->state = STATE_IDLE;
 	}
 
@@ -965,7 +1033,7 @@
 					data->bytes_xfered = 0;
 					data->error = -ETIMEDOUT;
 				} else {
-					dev_err(&host->pdev->dev,
+					dev_err(&host->dev,
 						"data FIFO error "
 						"(status=%08x)\n",
 						status);
@@ -1682,7 +1750,7 @@
 	struct mmc_host *mmc;
 	struct dw_mci_slot *slot;
 
-	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->pdev->dev);
+	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->dev);
 	if (!mmc)
 		return -ENOMEM;
 
@@ -1720,13 +1788,11 @@
 	if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
 		mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
-#ifdef CONFIG_MMC_DW_IDMAC
-	mmc->max_segs = host->ring_size;
-	mmc->max_blk_size = 65536;
-	mmc->max_blk_count = host->ring_size;
-	mmc->max_seg_size = 0x1000;
-	mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
-#else
+	if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY)
+		mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
+	else
+		mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE;
+
 	if (host->pdata->blk_settings) {
 		mmc->max_segs = host->pdata->blk_settings->max_segs;
 		mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
@@ -1735,13 +1801,20 @@
 		mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
 	} else {
 		/* Useful defaults if platform data is unset. */
+#ifdef CONFIG_MMC_DW_IDMAC
+		mmc->max_segs = host->ring_size;
+		mmc->max_blk_size = 65536;
+		mmc->max_blk_count = host->ring_size;
+		mmc->max_seg_size = 0x1000;
+		mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
+#else
 		mmc->max_segs = 64;
 		mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
 		mmc->max_blk_count = 512;
 		mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 		mmc->max_seg_size = mmc->max_req_size;
-	}
 #endif /* CONFIG_MMC_DW_IDMAC */
+	}
 
 	host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
 	if (IS_ERR(host->vmmc)) {
@@ -1789,10 +1862,10 @@
 static void dw_mci_init_dma(struct dw_mci *host)
 {
 	/* Alloc memory for sg translation */
-	host->sg_cpu = dma_alloc_coherent(&host->pdev->dev, PAGE_SIZE,
+	host->sg_cpu = dma_alloc_coherent(&host->dev, PAGE_SIZE,
 					  &host->sg_dma, GFP_KERNEL);
 	if (!host->sg_cpu) {
-		dev_err(&host->pdev->dev, "%s: could not alloc DMA memory\n",
+		dev_err(&host->dev, "%s: could not alloc DMA memory\n",
 			__func__);
 		goto no_dma;
 	}
@@ -1800,7 +1873,7 @@
 	/* Determine which DMA interface to use */
 #ifdef CONFIG_MMC_DW_IDMAC
 	host->dma_ops = &dw_mci_idmac_ops;
-	dev_info(&host->pdev->dev, "Using internal DMA controller.\n");
+	dev_info(&host->dev, "Using internal DMA controller.\n");
 #endif
 
 	if (!host->dma_ops)
@@ -1808,12 +1881,12 @@
 
 	if (host->dma_ops->init) {
 		if (host->dma_ops->init(host)) {
-			dev_err(&host->pdev->dev, "%s: Unable to initialize "
+			dev_err(&host->dev, "%s: Unable to initialize "
 				"DMA Controller.\n", __func__);
 			goto no_dma;
 		}
 	} else {
-		dev_err(&host->pdev->dev, "DMA initialization not found.\n");
+		dev_err(&host->dev, "DMA initialization not found.\n");
 		goto no_dma;
 	}
 
@@ -1821,7 +1894,7 @@
 	return;
 
 no_dma:
-	dev_info(&host->pdev->dev, "Using PIO mode.\n");
+	dev_info(&host->dev, "Using PIO mode.\n");
 	host->use_dma = 0;
 	return;
 }
@@ -1847,61 +1920,37 @@
 	return false;
 }
 
-static int dw_mci_probe(struct platform_device *pdev)
+int dw_mci_probe(struct dw_mci *host)
 {
-	struct dw_mci *host;
-	struct resource	*regs;
-	struct dw_mci_board *pdata;
-	int irq, ret, i, width;
+	int width, i, ret = 0;
 	u32 fifo_size;
 
-	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!regs)
-		return -ENXIO;
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
-
-	host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
-	if (!host)
-		return -ENOMEM;
-
-	host->pdev = pdev;
-	host->pdata = pdata = pdev->dev.platform_data;
-	if (!pdata || !pdata->init) {
-		dev_err(&pdev->dev,
+	if (!host->pdata || !host->pdata->init) {
+		dev_err(&host->dev,
 			"Platform data must supply init function\n");
-		ret = -ENODEV;
-		goto err_freehost;
+		return -ENODEV;
 	}
 
-	if (!pdata->select_slot && pdata->num_slots > 1) {
-		dev_err(&pdev->dev,
+	if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
+		dev_err(&host->dev,
 			"Platform data must supply select_slot function\n");
-		ret = -ENODEV;
-		goto err_freehost;
+		return -ENODEV;
 	}
 
-	if (!pdata->bus_hz) {
-		dev_err(&pdev->dev,
+	if (!host->pdata->bus_hz) {
+		dev_err(&host->dev,
 			"Platform data must supply bus speed\n");
-		ret = -ENODEV;
-		goto err_freehost;
+		return -ENODEV;
 	}
 
-	host->bus_hz = pdata->bus_hz;
-	host->quirks = pdata->quirks;
+	host->bus_hz = host->pdata->bus_hz;
+	host->quirks = host->pdata->quirks;
 
 	spin_lock_init(&host->lock);
 	INIT_LIST_HEAD(&host->queue);
 
-	ret = -ENOMEM;
-	host->regs = ioremap(regs->start, resource_size(regs));
-	if (!host->regs)
-		goto err_freehost;
 
-	host->dma_ops = pdata->dma_ops;
+	host->dma_ops = host->pdata->dma_ops;
 	dw_mci_init_dma(host);
 
 	/*
@@ -1931,7 +1980,7 @@
 	}
 
 	/* Reset all blocks */
-	if (!mci_wait_reset(&pdev->dev, host)) {
+	if (!mci_wait_reset(&host->dev, host)) {
 		ret = -ENODEV;
 		goto err_dmaunmap;
 	}
@@ -1974,13 +2023,10 @@
 	if (!dw_mci_card_workqueue)
 		goto err_dmaunmap;
 	INIT_WORK(&host->card_work, dw_mci_work_routine_card);
-
-	ret = request_irq(irq, dw_mci_interrupt, 0, "dw-mci", host);
+	ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host);
 	if (ret)
 		goto err_workqueue;
 
-	platform_set_drvdata(pdev, host);
-
 	if (host->pdata->num_slots)
 		host->num_slots = host->pdata->num_slots;
 	else
@@ -2000,7 +2046,7 @@
 	 * Need to check the version-id and set data-offset for DATA register.
 	 */
 	host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
-	dev_info(&pdev->dev, "Version ID is %04x\n", host->verid);
+	dev_info(&host->dev, "Version ID is %04x\n", host->verid);
 
 	if (host->verid < DW_MMC_240A)
 		host->data_offset = DATA_OFFSET;
@@ -2017,12 +2063,12 @@
 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
 
-	dev_info(&pdev->dev, "DW MMC controller at irq %d, "
+	dev_info(&host->dev, "DW MMC controller at irq %d, "
 		 "%d bit host data width, "
 		 "%u deep fifo\n",
-		 irq, width, fifo_size);
+		 host->irq, width, fifo_size);
 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
-		dev_info(&pdev->dev, "Internal DMAC interrupt fix enabled.\n");
+		dev_info(&host->dev, "Internal DMAC interrupt fix enabled.\n");
 
 	return 0;
 
@@ -2033,7 +2079,7 @@
 			dw_mci_cleanup_slot(host->slot[i], i);
 		i--;
 	}
-	free_irq(irq, host);
+	free_irq(host->irq, host);
 
 err_workqueue:
 	destroy_workqueue(dw_mci_card_workqueue);
@@ -2041,33 +2087,26 @@
 err_dmaunmap:
 	if (host->use_dma && host->dma_ops->exit)
 		host->dma_ops->exit(host);
-	dma_free_coherent(&host->pdev->dev, PAGE_SIZE,
+	dma_free_coherent(&host->dev, PAGE_SIZE,
 			  host->sg_cpu, host->sg_dma);
-	iounmap(host->regs);
 
 	if (host->vmmc) {
 		regulator_disable(host->vmmc);
 		regulator_put(host->vmmc);
 	}
-
-
-err_freehost:
-	kfree(host);
 	return ret;
 }
+EXPORT_SYMBOL(dw_mci_probe);
 
-static int __exit dw_mci_remove(struct platform_device *pdev)
+void dw_mci_remove(struct dw_mci *host)
 {
-	struct dw_mci *host = platform_get_drvdata(pdev);
 	int i;
 
 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
 
-	platform_set_drvdata(pdev, NULL);
-
 	for (i = 0; i < host->num_slots; i++) {
-		dev_dbg(&pdev->dev, "remove slot %d\n", i);
+		dev_dbg(&host->dev, "remove slot %d\n", i);
 		if (host->slot[i])
 			dw_mci_cleanup_slot(host->slot[i], i);
 	}
@@ -2076,9 +2115,9 @@
 	mci_writel(host, CLKENA, 0);
 	mci_writel(host, CLKSRC, 0);
 
-	free_irq(platform_get_irq(pdev, 0), host);
+	free_irq(host->irq, host);
 	destroy_workqueue(dw_mci_card_workqueue);
-	dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+	dma_free_coherent(&host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
 
 	if (host->use_dma && host->dma_ops->exit)
 		host->dma_ops->exit(host);
@@ -2088,20 +2127,18 @@
 		regulator_put(host->vmmc);
 	}
 
-	iounmap(host->regs);
-
-	kfree(host);
-	return 0;
 }
+EXPORT_SYMBOL(dw_mci_remove);
+
+
 
 #ifdef CONFIG_PM_SLEEP
 /*
  * TODO: we should probably disable the clock to the card in the suspend path.
  */
-static int dw_mci_suspend(struct device *dev)
+int dw_mci_suspend(struct dw_mci *host)
 {
-	int i, ret;
-	struct dw_mci *host = dev_get_drvdata(dev);
+	int i, ret = 0;
 
 	for (i = 0; i < host->num_slots; i++) {
 		struct dw_mci_slot *slot = host->slot[i];
@@ -2123,11 +2160,11 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(dw_mci_suspend);
 
-static int dw_mci_resume(struct device *dev)
+int dw_mci_resume(struct dw_mci *host)
 {
 	int i, ret;
-	struct dw_mci *host = dev_get_drvdata(dev);
 
 	if (host->vmmc)
 		regulator_enable(host->vmmc);
@@ -2135,7 +2172,7 @@
 	if (host->dma_ops->init)
 		host->dma_ops->init(host);
 
-	if (!mci_wait_reset(dev, host)) {
+	if (!mci_wait_reset(&host->dev, host)) {
 		ret = -ENODEV;
 		return ret;
 	}
@@ -2157,32 +2194,19 @@
 		if (ret < 0)
 			return ret;
 	}
-
 	return 0;
 }
-#else
-#define dw_mci_suspend	NULL
-#define dw_mci_resume	NULL
+EXPORT_SYMBOL(dw_mci_resume);
 #endif /* CONFIG_PM_SLEEP */
 
-static SIMPLE_DEV_PM_OPS(dw_mci_pmops, dw_mci_suspend, dw_mci_resume);
-
-static struct platform_driver dw_mci_driver = {
-	.remove		= __exit_p(dw_mci_remove),
-	.driver		= {
-		.name		= "dw_mmc",
-		.pm		= &dw_mci_pmops,
-	},
-};
-
 static int __init dw_mci_init(void)
 {
-	return platform_driver_probe(&dw_mci_driver, dw_mci_probe);
+	printk(KERN_INFO "Synopsys Designware Multimedia Card Interface Driver");
+	return 0;
 }
 
 static void __exit dw_mci_exit(void)
 {
-	platform_driver_unregister(&dw_mci_driver);
 }
 
 module_init(dw_mci_init);
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index df392a1..15c27e1 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -175,4 +175,11 @@
 	(*(volatile u64 __force *)((dev)->regs + SDMMC_##reg) = (value))
 #endif
 
+extern int dw_mci_probe(struct dw_mci *host);
+extern void dw_mci_remove(struct dw_mci *host);
+#ifdef CONFIG_PM
+extern int dw_mci_suspend(struct dw_mci *host);
+extern int dw_mci_resume(struct dw_mci *host);
+#endif
+
 #endif /* _DW_MMC_H_ */
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 11e589c..032b847 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -30,6 +30,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/amba/mmci.h>
 #include <linux/pm_runtime.h>
+#include <linux/types.h>
 
 #include <asm/div64.h>
 #include <asm/io.h>
@@ -53,6 +54,8 @@
  * @sdio: variant supports SDIO
  * @st_clkdiv: true if using a ST-specific clock divider algorithm
  * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
+ * @pwrreg_powerup: power up value for MMCIPOWER register
+ * @signal_direction: input/out direction of bus signals can be indicated
  */
 struct variant_data {
 	unsigned int		clkreg;
@@ -63,18 +66,22 @@
 	bool			sdio;
 	bool			st_clkdiv;
 	bool			blksz_datactrl16;
+	u32			pwrreg_powerup;
+	bool			signal_direction;
 };
 
 static struct variant_data variant_arm = {
 	.fifosize		= 16 * 4,
 	.fifohalfsize		= 8 * 4,
 	.datalength_bits	= 16,
+	.pwrreg_powerup		= MCI_PWR_UP,
 };
 
 static struct variant_data variant_arm_extended_fifo = {
 	.fifosize		= 128 * 4,
 	.fifohalfsize		= 64 * 4,
 	.datalength_bits	= 16,
+	.pwrreg_powerup		= MCI_PWR_UP,
 };
 
 static struct variant_data variant_u300 = {
@@ -83,6 +90,8 @@
 	.clkreg_enable		= MCI_ST_U300_HWFCEN,
 	.datalength_bits	= 16,
 	.sdio			= true,
+	.pwrreg_powerup		= MCI_PWR_ON,
+	.signal_direction	= true,
 };
 
 static struct variant_data variant_ux500 = {
@@ -93,6 +102,8 @@
 	.datalength_bits	= 24,
 	.sdio			= true,
 	.st_clkdiv		= true,
+	.pwrreg_powerup		= MCI_PWR_ON,
+	.signal_direction	= true,
 };
 
 static struct variant_data variant_ux500v2 = {
@@ -104,11 +115,35 @@
 	.sdio			= true,
 	.st_clkdiv		= true,
 	.blksz_datactrl16	= true,
+	.pwrreg_powerup		= MCI_PWR_ON,
+	.signal_direction	= true,
 };
 
 /*
  * This must be called with host->lock held
  */
+static void mmci_write_clkreg(struct mmci_host *host, u32 clk)
+{
+	if (host->clk_reg != clk) {
+		host->clk_reg = clk;
+		writel(clk, host->base + MMCICLOCK);
+	}
+}
+
+/*
+ * This must be called with host->lock held
+ */
+static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
+{
+	if (host->pwr_reg != pwr) {
+		host->pwr_reg = pwr;
+		writel(pwr, host->base + MMCIPOWER);
+	}
+}
+
+/*
+ * This must be called with host->lock held
+ */
 static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
 {
 	struct variant_data *variant = host->variant;
@@ -153,7 +188,7 @@
 	if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
 		clk |= MCI_ST_8BIT_BUS;
 
-	writel(clk, host->base + MMCICLOCK);
+	mmci_write_clkreg(host, clk);
 }
 
 static void
@@ -166,14 +201,10 @@
 	host->mrq = NULL;
 	host->cmd = NULL;
 
-	/*
-	 * Need to drop the host lock here; mmc_request_done may call
-	 * back into the driver...
-	 */
-	spin_unlock(&host->lock);
-	pm_runtime_put(mmc_dev(host->mmc));
 	mmc_request_done(host->mmc, mrq);
-	spin_lock(&host->lock);
+
+	pm_runtime_mark_last_busy(mmc_dev(host->mmc));
+	pm_runtime_put_autosuspend(mmc_dev(host->mmc));
 }
 
 static void mmci_set_mask1(struct mmci_host *host, unsigned int mask)
@@ -370,6 +401,7 @@
 		.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
 		.src_maxburst = variant->fifohalfsize >> 2, /* # of words */
 		.dst_maxburst = variant->fifohalfsize >> 2, /* # of words */
+		.device_fc = false,
 	};
 	struct dma_chan *chan;
 	struct dma_device *device;
@@ -411,7 +443,7 @@
 		return -EINVAL;
 
 	dmaengine_slave_config(chan, &conf);
-	desc = device->device_prep_slave_sg(chan, data->sg, nr_sg,
+	desc = dmaengine_prep_slave_sg(chan, data->sg, nr_sg,
 					    conf.direction, DMA_CTRL_ACK);
 	if (!desc)
 		goto unmap_exit;
@@ -607,6 +639,11 @@
 	if (data->flags & MMC_DATA_READ)
 		datactrl |= MCI_DPSM_DIRECTION;
 
+	/* The ST Micro variants has a special bit to enable SDIO */
+	if (variant->sdio && host->mmc->card)
+		if (mmc_card_sdio(host->mmc->card))
+			datactrl |= MCI_ST_DPSM_SDIOEN;
+
 	/*
 	 * Attempt to use DMA operation mode, if this
 	 * should fail, fall back to PIO mode
@@ -635,11 +672,6 @@
 		irqmask = MCI_TXFIFOHALFEMPTYMASK;
 	}
 
-	/* The ST Micro variants has a special bit to enable SDIO */
-	if (variant->sdio && host->mmc->card)
-		if (mmc_card_sdio(host->mmc->card))
-			datactrl |= MCI_ST_DPSM_SDIOEN;
-
 	writel(datactrl, base + MMCIDATACTRL);
 	writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
 	mmci_set_mask1(host, irqmask);
@@ -786,7 +818,24 @@
 		if (count <= 0)
 			break;
 
-		readsl(base + MMCIFIFO, ptr, count >> 2);
+		/*
+		 * SDIO especially may want to send something that is
+		 * not divisible by 4 (as opposed to card sectors
+		 * etc). Therefore make sure to always read the last bytes
+		 * while only doing full 32-bit reads towards the FIFO.
+		 */
+		if (unlikely(count & 0x3)) {
+			if (count < 4) {
+				unsigned char buf[4];
+				readsl(base + MMCIFIFO, buf, 1);
+				memcpy(ptr, buf, count);
+			} else {
+				readsl(base + MMCIFIFO, ptr, count >> 2);
+				count &= ~0x3;
+			}
+		} else {
+			readsl(base + MMCIFIFO, ptr, count >> 2);
+		}
 
 		ptr += count;
 		remain -= count;
@@ -821,14 +870,13 @@
 		 */
 		if (variant->sdio &&
 		    mmc_card_sdio(host->mmc->card)) {
+			u32 clk;
 			if (count < 8)
-				writel(readl(host->base + MMCICLOCK) &
-					~variant->clkreg_enable,
-					host->base + MMCICLOCK);
+				clk = host->clk_reg & ~variant->clkreg_enable;
 			else
-				writel(readl(host->base + MMCICLOCK) |
-					variant->clkreg_enable,
-					host->base + MMCICLOCK);
+				clk = host->clk_reg | variant->clkreg_enable;
+
+			mmci_write_clkreg(host, clk);
 		}
 
 		/*
@@ -1015,10 +1063,17 @@
 static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct mmci_host *host = mmc_priv(mmc);
+	struct variant_data *variant = host->variant;
 	u32 pwr = 0;
 	unsigned long flags;
 	int ret;
 
+	pm_runtime_get_sync(mmc_dev(mmc));
+
+	if (host->plat->ios_handler &&
+		host->plat->ios_handler(mmc_dev(mmc), ios))
+			dev_err(mmc_dev(mmc), "platform ios_handler failed\n");
+
 	switch (ios->power_mode) {
 	case MMC_POWER_OFF:
 		if (host->vcc)
@@ -1035,22 +1090,38 @@
 				 * power should be rare so we print an error
 				 * and return here.
 				 */
-				return;
+				goto out;
 			}
 		}
-		if (host->plat->vdd_handler)
-			pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd,
-						       ios->power_mode);
-		/* The ST version does not have this, fall through to POWER_ON */
-		if (host->hw_designer != AMBA_VENDOR_ST) {
-			pwr |= MCI_PWR_UP;
-			break;
-		}
+		/*
+		 * The ST Micro variant doesn't have the PL180s MCI_PWR_UP
+		 * and instead uses MCI_PWR_ON so apply whatever value is
+		 * configured in the variant data.
+		 */
+		pwr |= variant->pwrreg_powerup;
+
+		break;
 	case MMC_POWER_ON:
 		pwr |= MCI_PWR_ON;
 		break;
 	}
 
+	if (variant->signal_direction && ios->power_mode != MMC_POWER_OFF) {
+		/*
+		 * The ST Micro variant has some additional bits
+		 * indicating signal direction for the signals in
+		 * the SD/MMC bus and feedback-clock usage.
+		 */
+		pwr |= host->plat->sigdir;
+
+		if (ios->bus_width == MMC_BUS_WIDTH_4)
+			pwr &= ~MCI_ST_DATA74DIREN;
+		else if (ios->bus_width == MMC_BUS_WIDTH_1)
+			pwr &= (~MCI_ST_DATA74DIREN &
+				~MCI_ST_DATA31DIREN &
+				~MCI_ST_DATA2DIREN);
+	}
+
 	if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) {
 		if (host->hw_designer != AMBA_VENDOR_ST)
 			pwr |= MCI_ROD;
@@ -1066,13 +1137,13 @@
 	spin_lock_irqsave(&host->lock, flags);
 
 	mmci_set_clkreg(host, ios->clock);
-
-	if (host->pwr != pwr) {
-		host->pwr = pwr;
-		writel(pwr, host->base + MMCIPOWER);
-	}
+	mmci_write_pwrreg(host, pwr);
 
 	spin_unlock_irqrestore(&host->lock, flags);
+
+ out:
+	pm_runtime_mark_last_busy(mmc_dev(mmc));
+	pm_runtime_put_autosuspend(mmc_dev(mmc));
 }
 
 static int mmci_get_ro(struct mmc_host *mmc)
@@ -1326,7 +1397,7 @@
 	if (ret)
 		goto unmap;
 
-	if (dev->irq[1] == NO_IRQ)
+	if (dev->irq[1] == NO_IRQ || !dev->irq[1])
 		host->singleirq = true;
 	else {
 		ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED,
@@ -1346,6 +1417,8 @@
 
 	mmci_dma_setup(host);
 
+	pm_runtime_set_autosuspend_delay(&dev->dev, 50);
+	pm_runtime_use_autosuspend(&dev->dev);
 	pm_runtime_put(&dev->dev);
 
 	mmc_add_host(mmc);
@@ -1430,43 +1503,49 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int mmci_suspend(struct amba_device *dev, pm_message_t state)
+#ifdef CONFIG_SUSPEND
+static int mmci_suspend(struct device *dev)
 {
-	struct mmc_host *mmc = amba_get_drvdata(dev);
+	struct amba_device *adev = to_amba_device(dev);
+	struct mmc_host *mmc = amba_get_drvdata(adev);
 	int ret = 0;
 
 	if (mmc) {
 		struct mmci_host *host = mmc_priv(mmc);
 
 		ret = mmc_suspend_host(mmc);
-		if (ret == 0)
+		if (ret == 0) {
+			pm_runtime_get_sync(dev);
 			writel(0, host->base + MMCIMASK0);
+		}
 	}
 
 	return ret;
 }
 
-static int mmci_resume(struct amba_device *dev)
+static int mmci_resume(struct device *dev)
 {
-	struct mmc_host *mmc = amba_get_drvdata(dev);
+	struct amba_device *adev = to_amba_device(dev);
+	struct mmc_host *mmc = amba_get_drvdata(adev);
 	int ret = 0;
 
 	if (mmc) {
 		struct mmci_host *host = mmc_priv(mmc);
 
 		writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+		pm_runtime_put(dev);
 
 		ret = mmc_resume_host(mmc);
 	}
 
 	return ret;
 }
-#else
-#define mmci_suspend	NULL
-#define mmci_resume	NULL
 #endif
 
+static const struct dev_pm_ops mmci_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mmci_suspend, mmci_resume)
+};
+
 static struct amba_id mmci_ids[] = {
 	{
 		.id	= 0x00041180,
@@ -1512,26 +1591,15 @@
 static struct amba_driver mmci_driver = {
 	.drv		= {
 		.name	= DRIVER_NAME,
+		.pm	= &mmci_dev_pm_ops,
 	},
 	.probe		= mmci_probe,
 	.remove		= __devexit_p(mmci_remove),
-	.suspend	= mmci_suspend,
-	.resume		= mmci_resume,
 	.id_table	= mmci_ids,
 };
 
-static int __init mmci_init(void)
-{
-	return amba_driver_register(&mmci_driver);
-}
+module_amba_driver(mmci_driver);
 
-static void __exit mmci_exit(void)
-{
-	amba_driver_unregister(&mmci_driver);
-}
-
-module_init(mmci_init);
-module_exit(mmci_exit);
 module_param(fmax, uint, 0444);
 
 MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver");
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 79e4143..d437ccf 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -13,16 +13,6 @@
 #define MCI_PWR_ON		0x03
 #define MCI_OD			(1 << 6)
 #define MCI_ROD			(1 << 7)
-/*
- * The ST Micro version does not have ROD and reuse the voltage registers
- * for direction settings
- */
-#define MCI_ST_DATA2DIREN	(1 << 2)
-#define MCI_ST_CMDDIREN		(1 << 3)
-#define MCI_ST_DATA0DIREN	(1 << 4)
-#define MCI_ST_DATA31DIREN	(1 << 5)
-#define MCI_ST_FBCLKEN		(1 << 7)
-#define MCI_ST_DATA74DIREN	(1 << 8)
 
 #define MMCICLOCK		0x004
 #define MCI_CLK_ENABLE		(1 << 8)
@@ -160,7 +150,7 @@
 	(MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \
 	 MCI_TXFIFOHALFEMPTYMASK)
 
-#define NR_SG		16
+#define NR_SG		128
 
 struct clk;
 struct variant_data;
@@ -189,7 +179,8 @@
 
 	unsigned int		mclk;
 	unsigned int		cclk;
-	u32			pwr;
+	u32			pwr_reg;
+	u32			clk_reg;
 	struct mmci_platform_data *plat;
 	struct variant_data	*variant;
 
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 4184b79..b2058b4 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -33,6 +33,7 @@
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
 #include <linux/dmaengine.h>
+#include <linux/types.h>
 
 #include <asm/dma.h>
 #include <asm/irq.h>
@@ -254,7 +255,7 @@
 	if (nents != data->sg_len)
 		return -EINVAL;
 
-	host->desc = host->dma->device->device_prep_slave_sg(host->dma,
+	host->desc = dmaengine_prep_slave_sg(host->dma,
 		data->sg, data->sg_len, slave_dirn,
 		DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 
@@ -267,6 +268,7 @@
 	wmb();
 
 	dmaengine_submit(host->desc);
+	dma_async_issue_pending(host->dma);
 
 	return 0;
 }
@@ -710,6 +712,7 @@
 	config->src_addr_width = 4;
 	config->dst_maxburst = host->burstlen;
 	config->src_maxburst = host->burstlen;
+	config->device_fc = false;
 
 	return dmaengine_slave_config(host->dma, config);
 }
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index 382c835..b0f2ef9 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -38,10 +38,10 @@
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
 #include <linux/module.h>
+#include <linux/fsl/mxs-dma.h>
 
 #include <mach/mxs.h>
 #include <mach/common.h>
-#include <mach/dma.h>
 #include <mach/mmc.h>
 
 #define DRIVER_NAME	"mxs-mmc"
@@ -305,7 +305,7 @@
 }
 
 static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
-	struct mxs_mmc_host *host, unsigned int append)
+	struct mxs_mmc_host *host, unsigned long flags)
 {
 	struct dma_async_tx_descriptor *desc;
 	struct mmc_data *data = host->data;
@@ -324,8 +324,8 @@
 		sg_len = SSP_PIO_NUM;
 	}
 
-	desc = host->dmach->device->device_prep_slave_sg(host->dmach,
-				sgl, sg_len, host->slave_dirn, append);
+	desc = dmaengine_prep_slave_sg(host->dmach,
+				sgl, sg_len, host->slave_dirn, flags);
 	if (desc) {
 		desc->callback = mxs_mmc_dma_irq_callback;
 		desc->callback_param = host;
@@ -358,7 +358,7 @@
 	host->ssp_pio_words[2] = cmd1;
 	host->dma_dir = DMA_NONE;
 	host->slave_dirn = DMA_TRANS_NONE;
-	desc = mxs_mmc_prep_dma(host, 0);
+	desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK);
 	if (!desc)
 		goto out;
 
@@ -398,7 +398,7 @@
 	host->ssp_pio_words[2] = cmd1;
 	host->dma_dir = DMA_NONE;
 	host->slave_dirn = DMA_TRANS_NONE;
-	desc = mxs_mmc_prep_dma(host, 0);
+	desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK);
 	if (!desc)
 		goto out;
 
@@ -526,7 +526,7 @@
 	host->data = data;
 	host->dma_dir = dma_data_dir;
 	host->slave_dirn = slave_dirn;
-	desc = mxs_mmc_prep_dma(host, 1);
+	desc = mxs_mmc_prep_dma(host, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc)
 		goto out;
 
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index fd0c661..47adb16 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -26,6 +26,9 @@
 #include <linux/platform_device.h>
 #include <linux/timer.h>
 #include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/core.h>
 #include <linux/mmc/mmc.h>
@@ -106,17 +109,6 @@
 #define SOFTRESET		(1 << 1)
 #define RESETDONE		(1 << 0)
 
-/*
- * FIXME: Most likely all the data using these _DEVID defines should come
- * from the platform_data, or implemented in controller and slot specific
- * functions.
- */
-#define OMAP_MMC1_DEVID		0
-#define OMAP_MMC2_DEVID		1
-#define OMAP_MMC3_DEVID		2
-#define OMAP_MMC4_DEVID		3
-#define OMAP_MMC5_DEVID		4
-
 #define MMC_AUTOSUSPEND_DELAY	100
 #define MMC_TIMEOUT_MS		20
 #define OMAP_MMC_MIN_CLOCK	400000
@@ -164,7 +156,6 @@
 	void	__iomem		*base;
 	resource_size_t		mapbase;
 	spinlock_t		irq_lock; /* Prevent races with irq handler */
-	unsigned int		id;
 	unsigned int		dma_len;
 	unsigned int		dma_sg_idx;
 	unsigned char		bus_mode;
@@ -179,7 +170,6 @@
 	int			got_dbclk;
 	int			response_busy;
 	int			context_loss;
-	int			dpm_state;
 	int			vdd;
 	int			protect_card;
 	int			reqs_blocked;
@@ -241,28 +231,7 @@
 
 #ifdef CONFIG_REGULATOR
 
-static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on,
-				  int vdd)
-{
-	struct omap_hsmmc_host *host =
-		platform_get_drvdata(to_platform_device(dev));
-	int ret;
-
-	if (mmc_slot(host).before_set_reg)
-		mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
-
-	if (power_on)
-		ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
-	else
-		ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
-
-	if (mmc_slot(host).after_set_reg)
-		mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
-
-	return ret;
-}
-
-static int omap_hsmmc_235_set_power(struct device *dev, int slot, int power_on,
+static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
 				   int vdd)
 {
 	struct omap_hsmmc_host *host =
@@ -275,6 +244,13 @@
 	 */
 	if (!host->vcc)
 		return 0;
+	/*
+	 * With DT, never turn OFF the regulator. This is because
+	 * the pbias cell programming support is still missing when
+	 * booting with Device tree
+	 */
+	if (of_have_populated_dt() && !vdd)
+		return 0;
 
 	if (mmc_slot(host).before_set_reg)
 		mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
@@ -318,106 +294,16 @@
 	return ret;
 }
 
-static int omap_hsmmc_4_set_power(struct device *dev, int slot, int power_on,
-					int vdd)
-{
-	return 0;
-}
-
-static int omap_hsmmc_1_set_sleep(struct device *dev, int slot, int sleep,
-				  int vdd, int cardsleep)
-{
-	struct omap_hsmmc_host *host =
-		platform_get_drvdata(to_platform_device(dev));
-	int mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
-
-	return regulator_set_mode(host->vcc, mode);
-}
-
-static int omap_hsmmc_235_set_sleep(struct device *dev, int slot, int sleep,
-				   int vdd, int cardsleep)
-{
-	struct omap_hsmmc_host *host =
-		platform_get_drvdata(to_platform_device(dev));
-	int err, mode;
-
-	/*
-	 * If we don't see a Vcc regulator, assume it's a fixed
-	 * voltage always-on regulator.
-	 */
-	if (!host->vcc)
-		return 0;
-
-	mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
-
-	if (!host->vcc_aux)
-		return regulator_set_mode(host->vcc, mode);
-
-	if (cardsleep) {
-		/* VCC can be turned off if card is asleep */
-		if (sleep)
-			err = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
-		else
-			err = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
-	} else
-		err = regulator_set_mode(host->vcc, mode);
-	if (err)
-		return err;
-
-	if (!mmc_slot(host).vcc_aux_disable_is_sleep)
-		return regulator_set_mode(host->vcc_aux, mode);
-
-	if (sleep)
-		return regulator_disable(host->vcc_aux);
-	else
-		return regulator_enable(host->vcc_aux);
-}
-
-static int omap_hsmmc_4_set_sleep(struct device *dev, int slot, int sleep,
-					int vdd, int cardsleep)
-{
-	return 0;
-}
-
 static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
 {
 	struct regulator *reg;
-	int ret = 0;
 	int ocr_value = 0;
 
-	switch (host->id) {
-	case OMAP_MMC1_DEVID:
-		/* On-chip level shifting via PBIAS0/PBIAS1 */
-		mmc_slot(host).set_power = omap_hsmmc_1_set_power;
-		mmc_slot(host).set_sleep = omap_hsmmc_1_set_sleep;
-		break;
-	case OMAP_MMC2_DEVID:
-	case OMAP_MMC3_DEVID:
-	case OMAP_MMC5_DEVID:
-		/* Off-chip level shifting, or none */
-		mmc_slot(host).set_power = omap_hsmmc_235_set_power;
-		mmc_slot(host).set_sleep = omap_hsmmc_235_set_sleep;
-		break;
-	case OMAP_MMC4_DEVID:
-		mmc_slot(host).set_power = omap_hsmmc_4_set_power;
-		mmc_slot(host).set_sleep = omap_hsmmc_4_set_sleep;
-	default:
-		pr_err("MMC%d configuration not supported!\n", host->id);
-		return -EINVAL;
-	}
+	mmc_slot(host).set_power = omap_hsmmc_set_power;
 
 	reg = regulator_get(host->dev, "vmmc");
 	if (IS_ERR(reg)) {
 		dev_dbg(host->dev, "vmmc regulator missing\n");
-		/*
-		* HACK: until fixed.c regulator is usable,
-		* we don't require a main regulator
-		* for MMC2 or MMC3
-		*/
-		if (host->id == OMAP_MMC1_DEVID) {
-			ret = PTR_ERR(reg);
-			goto err;
-		}
 	} else {
 		host->vcc = reg;
 		ocr_value = mmc_regulator_get_ocrmask(reg);
@@ -425,8 +311,8 @@
 			mmc_slot(host).ocr_mask = ocr_value;
 		} else {
 			if (!(mmc_slot(host).ocr_mask & ocr_value)) {
-				pr_err("MMC%d ocrmask %x is not supported\n",
-					host->id, mmc_slot(host).ocr_mask);
+				dev_err(host->dev, "ocrmask %x is not supported\n",
+					mmc_slot(host).ocr_mask);
 				mmc_slot(host).ocr_mask = 0;
 				return -EINVAL;
 			}
@@ -459,11 +345,6 @@
 	}
 
 	return 0;
-
-err:
-	mmc_slot(host).set_power = NULL;
-	mmc_slot(host).set_sleep = NULL;
-	return ret;
 }
 
 static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
@@ -471,7 +352,6 @@
 	regulator_put(host->vcc);
 	regulator_put(host->vcc_aux);
 	mmc_slot(host).set_power = NULL;
-	mmc_slot(host).set_sleep = NULL;
 }
 
 static inline int omap_hsmmc_have_reg(void)
@@ -710,7 +590,7 @@
 	OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
 			OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
 
-	if (host->id == OMAP_MMC1_DEVID) {
+	if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
 		if (host->power_mode != MMC_POWER_OFF &&
 		    (1 << ios->vdd) <= MMC_VDD_23_24)
 			hctl = SDVS18;
@@ -1261,14 +1141,14 @@
 	host->reqs_blocked = 0;
 	if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) {
 		if (host->protect_card) {
-			pr_info("%s: cover is closed, "
+			dev_info(host->dev, "%s: cover is closed, "
 					 "card is now accessible\n",
 					 mmc_hostname(host->mmc));
 			host->protect_card = 0;
 		}
 	} else {
 		if (!host->protect_card) {
-			pr_info("%s: cover is open, "
+			dev_info(host->dev, "%s: cover is open, "
 					 "card is now inaccessible\n",
 					 mmc_hostname(host->mmc));
 			host->protect_card = 1;
@@ -1405,7 +1285,7 @@
 
 	if (!next && data->host_cookie &&
 	    data->host_cookie != host->next_data.cookie) {
-		pr_warning("[%s] invalid cookie: data->host_cookie %d"
+		dev_warn(host->dev, "[%s] invalid cookie: data->host_cookie %d"
 		       " host->next_data.cookie %d\n",
 		       __func__, data->host_cookie, host->next_data.cookie);
 		data->host_cookie = 0;
@@ -1663,7 +1543,13 @@
 		 * of external transceiver; but they all handle 1.8V.
 		 */
 		if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
-			(ios->vdd == DUAL_VOLT_OCR_BIT)) {
+			(ios->vdd == DUAL_VOLT_OCR_BIT) &&
+			/*
+			 * With pbias cell programming missing, this
+			 * can't be allowed when booting with device
+			 * tree.
+			 */
+			(!of_have_populated_dt())) {
 				/*
 				 * The mmc_select_voltage fn of the core does
 				 * not seem to set the power_mode to
@@ -1748,7 +1634,7 @@
 	return 0;
 }
 
-static int omap_hsmmc_disable_fclk(struct mmc_host *mmc, int lazy)
+static int omap_hsmmc_disable_fclk(struct mmc_host *mmc)
 {
 	struct omap_hsmmc_host *host = mmc_priv(mmc);
 
@@ -1782,15 +1668,8 @@
 	if (host->pdata->get_context_loss_count)
 		context_loss = host->pdata->get_context_loss_count(host->dev);
 
-	seq_printf(s, "mmc%d:\n"
-			" enabled:\t%d\n"
-			" dpm_state:\t%d\n"
-			" nesting_cnt:\t%d\n"
-			" ctx_loss:\t%d:%d\n"
-			"\nregs:\n",
-			mmc->index, mmc->enabled ? 1 : 0,
-			host->dpm_state, mmc->nesting_cnt,
-			host->context_loss, context_loss);
+	seq_printf(s, "mmc%d:\n ctx_loss:\t%d:%d\n\nregs:\n",
+			mmc->index, host->context_loss, context_loss);
 
 	if (host->suspended) {
 		seq_printf(s, "host suspended, can't read registers\n");
@@ -1847,6 +1726,65 @@
 
 #endif
 
+#ifdef CONFIG_OF
+static u16 omap4_reg_offset = 0x100;
+
+static const struct of_device_id omap_mmc_of_match[] = {
+	{
+		.compatible = "ti,omap2-hsmmc",
+	},
+	{
+		.compatible = "ti,omap3-hsmmc",
+	},
+	{
+		.compatible = "ti,omap4-hsmmc",
+		.data = &omap4_reg_offset,
+	},
+	{},
+}
+MODULE_DEVICE_TABLE(of, omap_mmc_of_match);
+
+static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
+{
+	struct omap_mmc_platform_data *pdata;
+	struct device_node *np = dev->of_node;
+	u32 bus_width;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL; /* out of memory */
+
+	if (of_find_property(np, "ti,dual-volt", NULL))
+		pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
+
+	/* This driver only supports 1 slot */
+	pdata->nr_slots = 1;
+	pdata->slots[0].switch_pin = of_get_named_gpio(np, "cd-gpios", 0);
+	pdata->slots[0].gpio_wp = of_get_named_gpio(np, "wp-gpios", 0);
+
+	if (of_find_property(np, "ti,non-removable", NULL)) {
+		pdata->slots[0].nonremovable = true;
+		pdata->slots[0].no_regulator_off_init = true;
+	}
+	of_property_read_u32(np, "ti,bus-width", &bus_width);
+	if (bus_width == 4)
+		pdata->slots[0].caps |= MMC_CAP_4_BIT_DATA;
+	else if (bus_width == 8)
+		pdata->slots[0].caps |= MMC_CAP_8_BIT_DATA;
+
+	if (of_find_property(np, "ti,needs-special-reset", NULL))
+		pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
+
+	return pdata;
+}
+#else
+static inline struct omap_mmc_platform_data
+			*of_get_hsmmc_pdata(struct device *dev)
+{
+	return NULL;
+}
+#endif
+
 static int __init omap_hsmmc_probe(struct platform_device *pdev)
 {
 	struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
@@ -1854,6 +1792,16 @@
 	struct omap_hsmmc_host *host = NULL;
 	struct resource *res;
 	int ret, irq;
+	const struct of_device_id *match;
+
+	match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
+	if (match) {
+		pdata = of_get_hsmmc_pdata(&pdev->dev);
+		if (match->data) {
+			u16 *offsetp = match->data;
+			pdata->reg_offset = *offsetp;
+		}
+	}
 
 	if (pdata == NULL) {
 		dev_err(&pdev->dev, "Platform Data is missing\n");
@@ -1894,7 +1842,6 @@
 	host->dev->dma_mask = &pdata->dma_mask;
 	host->dma_ch	= -1;
 	host->irq	= irq;
-	host->id	= pdev->id;
 	host->slot_id	= 0;
 	host->mapbase	= res->start;
 	host->base	= ioremap(host->mapbase, SZ_4K);
@@ -1912,8 +1859,12 @@
 	if (mmc_slot(host).vcc_aux_disable_is_sleep)
 		mmc_slot(host).no_off = 1;
 
-	mmc->f_min	= OMAP_MMC_MIN_CLOCK;
-	mmc->f_max	= OMAP_MMC_MAX_CLOCK;
+	mmc->f_min = OMAP_MMC_MIN_CLOCK;
+
+	if (pdata->max_freq > 0)
+		mmc->f_max = pdata->max_freq;
+	else
+		mmc->f_max = OMAP_MMC_MAX_CLOCK;
 
 	spin_lock_init(&host->irq_lock);
 
@@ -1926,7 +1877,6 @@
 
 	omap_hsmmc_context_save(host);
 
-	mmc->caps |= MMC_CAP_DISABLE;
 	if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) {
 		dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n");
 		mmc->caps2 |= MMC_CAP2_NO_MULTI_READ;
@@ -1977,32 +1927,19 @@
 
 	omap_hsmmc_conf_bus_power(host);
 
-	/* Select DMA lines */
-	switch (host->id) {
-	case OMAP_MMC1_DEVID:
-		host->dma_line_tx = OMAP24XX_DMA_MMC1_TX;
-		host->dma_line_rx = OMAP24XX_DMA_MMC1_RX;
-		break;
-	case OMAP_MMC2_DEVID:
-		host->dma_line_tx = OMAP24XX_DMA_MMC2_TX;
-		host->dma_line_rx = OMAP24XX_DMA_MMC2_RX;
-		break;
-	case OMAP_MMC3_DEVID:
-		host->dma_line_tx = OMAP34XX_DMA_MMC3_TX;
-		host->dma_line_rx = OMAP34XX_DMA_MMC3_RX;
-		break;
-	case OMAP_MMC4_DEVID:
-		host->dma_line_tx = OMAP44XX_DMA_MMC4_TX;
-		host->dma_line_rx = OMAP44XX_DMA_MMC4_RX;
-		break;
-	case OMAP_MMC5_DEVID:
-		host->dma_line_tx = OMAP44XX_DMA_MMC5_TX;
-		host->dma_line_rx = OMAP44XX_DMA_MMC5_RX;
-		break;
-	default:
-		dev_err(mmc_dev(host->mmc), "Invalid MMC id\n");
+	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+	if (!res) {
+		dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
 		goto err_irq;
 	}
+	host->dma_line_tx = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+	if (!res) {
+		dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n");
+		goto err_irq;
+	}
+	host->dma_line_rx = res->start;
 
 	/* Request IRQ for MMC operations */
 	ret = request_irq(host->irq, omap_hsmmc_irq, 0,
@@ -2083,6 +2020,7 @@
 err_irq:
 	pm_runtime_mark_last_busy(host->dev);
 	pm_runtime_put_autosuspend(host->dev);
+	pm_runtime_disable(host->dev);
 	clk_put(host->fclk);
 	if (host->got_dbclk) {
 		clk_disable(host->dbclk);
@@ -2269,6 +2207,7 @@
 		.name = DRIVER_NAME,
 		.owner = THIS_MODULE,
 		.pm = &omap_hsmmc_dev_pm_ops,
+		.of_match_table = of_match_ptr(omap_mmc_of_match),
 	},
 };
 
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 0be4e20..6193a0d 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -464,7 +464,7 @@
 		err = PTR_ERR(clk);
 		goto err_clk_get;
 	}
-	clk_enable(clk);
+	clk_prepare_enable(clk);
 	pltfm_host->clk = clk;
 
 	if (!is_imx25_esdhc(imx_data))
@@ -559,7 +559,7 @@
 		gpio_free(boarddata->wp_gpio);
 no_card_detect_pin:
 no_board_data:
-	clk_disable(pltfm_host->clk);
+	clk_disable_unprepare(pltfm_host->clk);
 	clk_put(pltfm_host->clk);
 err_clk_get:
 	kfree(imx_data);
@@ -586,7 +586,7 @@
 		gpio_free(boarddata->cd_gpio);
 	}
 
-	clk_disable(pltfm_host->clk);
+	clk_disable_unprepare(pltfm_host->clk);
 	clk_put(pltfm_host->clk);
 	kfree(imx_data);
 
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 5d876ff..f8eb1fb 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -1,7 +1,7 @@
 /*
  * Freescale eSDHC controller driver.
  *
- * Copyright (c) 2007, 2010 Freescale Semiconductor, Inc.
+ * Copyright (c) 2007, 2010, 2012 Freescale Semiconductor, Inc.
  * Copyright (c) 2009 MontaVista Software, Inc.
  *
  * Authors: Xiaobo Xie <X.Xie@freescale.com>
@@ -14,6 +14,7 @@
  */
 
 #include <linux/io.h>
+#include <linux/of.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/mmc/host.h>
@@ -114,6 +115,34 @@
 	return pltfm_host->clock / 256 / 16;
 }
 
+static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+	/* Workaround to reduce the clock frequency for p1010 esdhc */
+	if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
+		if (clock > 20000000)
+			clock -= 5000000;
+		if (clock > 40000000)
+			clock -= 5000000;
+	}
+
+	/* Set the clock */
+	esdhc_set_clock(host, clock);
+}
+
+#ifdef CONFIG_PM
+static u32 esdhc_proctl;
+static void esdhc_of_suspend(struct sdhci_host *host)
+{
+	esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL);
+}
+
+static void esdhc_of_resume(struct sdhci_host *host)
+{
+	esdhc_of_enable_dma(host);
+	sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
+}
+#endif
+
 static struct sdhci_ops sdhci_esdhc_ops = {
 	.read_l = sdhci_be32bs_readl,
 	.read_w = esdhc_readw,
@@ -121,10 +150,14 @@
 	.write_l = sdhci_be32bs_writel,
 	.write_w = esdhc_writew,
 	.write_b = esdhc_writeb,
-	.set_clock = esdhc_set_clock,
+	.set_clock = esdhc_of_set_clock,
 	.enable_dma = esdhc_of_enable_dma,
 	.get_max_clock = esdhc_of_get_max_clock,
 	.get_min_clock = esdhc_of_get_min_clock,
+#ifdef CONFIG_PM
+	.platform_suspend = esdhc_of_suspend,
+	.platform_resume = esdhc_of_resume,
+#endif
 };
 
 static struct sdhci_pltfm_data sdhci_esdhc_pdata = {
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 6ebdc40..fbbebe2 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -29,6 +29,12 @@
 #include "sdhci.h"
 
 /*
+ * PCI device IDs
+ */
+#define PCI_DEVICE_ID_INTEL_PCH_SDIO0	0x8809
+#define PCI_DEVICE_ID_INTEL_PCH_SDIO1	0x880a
+
+/*
  * PCI registers
  */
 
@@ -47,6 +53,7 @@
 
 struct sdhci_pci_fixes {
 	unsigned int		quirks;
+	unsigned int		quirks2;
 	bool			allow_runtime_pm;
 
 	int			(*probe) (struct sdhci_pci_chip *);
@@ -73,6 +80,7 @@
 	struct pci_dev		*pdev;
 
 	unsigned int		quirks;
+	unsigned int		quirks2;
 	bool			allow_runtime_pm;
 	const struct sdhci_pci_fixes *fixes;
 
@@ -172,6 +180,12 @@
 	return 0;
 }
 
+static int pch_hc_probe_slot(struct sdhci_pci_slot *slot)
+{
+	slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+	return 0;
+}
+
 #ifdef CONFIG_PM_RUNTIME
 
 static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id)
@@ -244,7 +258,8 @@
 static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot)
 {
 	slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
-	slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC;
+	slot->host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC |
+				  MMC_CAP2_HC_ERASE_SZ;
 	return 0;
 }
 
@@ -271,6 +286,7 @@
 
 static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = {
 	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+	.quirks2	= SDHCI_QUIRK2_HOST_OFF_CARD_ON,
 	.allow_runtime_pm = true,
 	.probe_slot	= mfd_sdio_probe_slot,
 };
@@ -281,6 +297,11 @@
 	.probe_slot	= mfd_emmc_probe_slot,
 };
 
+static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
+	.quirks		= SDHCI_QUIRK_BROKEN_ADMA,
+	.probe_slot	= pch_hc_probe_slot,
+};
+
 /* O2Micro extra registers */
 #define O2_SD_LOCK_WP		0xD3
 #define O2_SD_MULTI_VCC3V	0xEE
@@ -817,6 +838,22 @@
 	},
 
 	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_PCH_SDIO0,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (kernel_ulong_t)&sdhci_intel_pch_sdio,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_PCH_SDIO1,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (kernel_ulong_t)&sdhci_intel_pch_sdio,
+	},
+
+	{
 		.vendor		= PCI_VENDOR_ID_O2,
 		.device		= PCI_DEVICE_ID_O2_8120,
 		.subvendor	= PCI_ANY_ID,
@@ -1206,6 +1243,7 @@
 	host->hw_name = "PCI";
 	host->ops = &sdhci_pci_ops;
 	host->quirks = chip->quirks;
+	host->quirks2 = chip->quirks2;
 
 	host->irq = pdev->irq;
 
@@ -1365,6 +1403,7 @@
 	chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data;
 	if (chip->fixes) {
 		chip->quirks = chip->fixes->quirks;
+		chip->quirks2 = chip->fixes->quirks2;
 		chip->allow_runtime_pm = chip->fixes->allow_runtime_pm;
 	}
 	chip->num_slots = slots;
@@ -1379,6 +1418,8 @@
 
 	slots = chip->num_slots;	/* Quirk may have changed this */
 
+	pci_enable_msi(pdev);
+
 	for (i = 0; i < slots; i++) {
 		slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i);
 		if (IS_ERR(slot)) {
@@ -1397,6 +1438,8 @@
 	return 0;
 
 free:
+	pci_disable_msi(pdev);
+
 	pci_set_drvdata(pdev, NULL);
 	kfree(chip);
 
@@ -1419,6 +1462,8 @@
 		for (i = 0; i < chip->num_slots; i++)
 			sdhci_pci_remove_slot(chip->slots[i]);
 
+		pci_disable_msi(pdev);
+
 		pci_set_drvdata(pdev, NULL);
 		kfree(chip);
 	}
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 1af756e..b19e7d4 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -518,9 +518,6 @@
 	if (pdata->cd_type == S3C_SDHCI_CD_PERMANENT)
 		host->mmc->caps = MMC_CAP_NONREMOVABLE;
 
-	if (pdata->host_caps)
-		host->mmc->caps |= pdata->host_caps;
-
 	if (pdata->pm_caps)
 		host->mmc->pm_caps |= pdata->pm_caps;
 
@@ -544,6 +541,9 @@
 	if (pdata->host_caps)
 		host->mmc->caps |= pdata->host_caps;
 
+	if (pdata->host_caps2)
+		host->mmc->caps2 |= pdata->host_caps2;
+
 	ret = sdhci_add_host(host);
 	if (ret) {
 		dev_err(dev, "sdhci_add_host() failed\n");
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index b7f8b33..6dfa82e 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -300,20 +300,15 @@
 
 	return sdhci_resume_host(host);
 }
-
-const struct dev_pm_ops sdhci_pm_ops = {
-	.suspend	= sdhci_suspend,
-	.resume		= sdhci_resume,
-};
 #endif
 
+static SIMPLE_DEV_PM_OPS(sdhci_pm_ops, sdhci_suspend, sdhci_resume);
+
 static struct platform_driver sdhci_driver = {
 	.driver = {
 		.name	= "sdhci",
 		.owner	= THIS_MODULE,
-#ifdef CONFIG_PM
 		.pm	= &sdhci_pm_ops,
-#endif
 	},
 	.probe		= sdhci_probe,
 	.remove		= __devexit_p(sdhci_remove),
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 78a36eb..53b2650 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -19,11 +19,11 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/gpio.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
-#include <linux/module.h>
 
 #include <asm/gpio.h>
 
@@ -32,6 +32,19 @@
 
 #include "sdhci-pltfm.h"
 
+#define NVQUIRK_FORCE_SDHCI_SPEC_200	BIT(0)
+#define NVQUIRK_ENABLE_BLOCK_GAP_DET	BIT(1)
+
+struct sdhci_tegra_soc_data {
+	struct sdhci_pltfm_data *pdata;
+	u32 nvquirks;
+};
+
+struct sdhci_tegra {
+	const struct tegra_sdhci_platform_data *plat;
+	const struct sdhci_tegra_soc_data *soc_data;
+};
+
 static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
 {
 	u32 val;
@@ -47,7 +60,12 @@
 
 static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
 {
-	if (unlikely(reg == SDHCI_HOST_VERSION)) {
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_tegra *tegra_host = pltfm_host->priv;
+	const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
+
+	if (unlikely((soc_data->nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200) &&
+			(reg == SDHCI_HOST_VERSION))) {
 		/* Erratum: Version register is invalid in HW. */
 		return SDHCI_SPEC_200;
 	}
@@ -57,6 +75,10 @@
 
 static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
 {
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_tegra *tegra_host = pltfm_host->priv;
+	const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
+
 	/* Seems like we're getting spurious timeout and crc errors, so
 	 * disable signalling of them. In case of real errors software
 	 * timers should take care of eventually detecting them.
@@ -66,7 +88,8 @@
 
 	writel(val, host->ioaddr + reg);
 
-	if (unlikely(reg == SDHCI_INT_ENABLE)) {
+	if (unlikely((soc_data->nvquirks & NVQUIRK_ENABLE_BLOCK_GAP_DET) &&
+			(reg == SDHCI_INT_ENABLE))) {
 		/* Erratum: Must enable block gap interrupt detection */
 		u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL);
 		if (val & SDHCI_INT_CARD_INT)
@@ -77,10 +100,11 @@
 	}
 }
 
-static unsigned int tegra_sdhci_get_ro(struct sdhci_host *sdhci)
+static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
 {
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
-	struct tegra_sdhci_platform_data *plat = pltfm_host->priv;
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_tegra *tegra_host = pltfm_host->priv;
+	const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
 
 	if (!gpio_is_valid(plat->wp_gpio))
 		return -1;
@@ -99,7 +123,8 @@
 static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	struct tegra_sdhci_platform_data *plat = pltfm_host->priv;
+	struct sdhci_tegra *tegra_host = pltfm_host->priv;
+	const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
 	u32 ctrl;
 
 	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
@@ -125,7 +150,8 @@
 	.platform_8bit_width = tegra_sdhci_8bit,
 };
 
-static struct sdhci_pltfm_data sdhci_tegra_pdata = {
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+static struct sdhci_pltfm_data sdhci_tegra20_pdata = {
 	.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
 		  SDHCI_QUIRK_SINGLE_POWER_WRITE |
 		  SDHCI_QUIRK_NO_HISPD_BIT |
@@ -133,8 +159,35 @@
 	.ops  = &tegra_sdhci_ops,
 };
 
+static struct sdhci_tegra_soc_data soc_data_tegra20 = {
+	.pdata = &sdhci_tegra20_pdata,
+	.nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 |
+		    NVQUIRK_ENABLE_BLOCK_GAP_DET,
+};
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+static struct sdhci_pltfm_data sdhci_tegra30_pdata = {
+	.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
+		  SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
+		  SDHCI_QUIRK_SINGLE_POWER_WRITE |
+		  SDHCI_QUIRK_NO_HISPD_BIT |
+		  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
+	.ops  = &tegra_sdhci_ops,
+};
+
+static struct sdhci_tegra_soc_data soc_data_tegra30 = {
+	.pdata = &sdhci_tegra30_pdata,
+};
+#endif
+
 static const struct of_device_id sdhci_tegra_dt_match[] __devinitdata = {
-	{ .compatible = "nvidia,tegra20-sdhci", },
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+	{ .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 },
+#endif
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+	{ .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 },
+#endif
 	{}
 };
 MODULE_DEVICE_TABLE(of, sdhci_dt_ids);
@@ -165,13 +218,22 @@
 
 static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
 {
+	const struct of_device_id *match;
+	const struct sdhci_tegra_soc_data *soc_data;
+	struct sdhci_host *host;
 	struct sdhci_pltfm_host *pltfm_host;
 	struct tegra_sdhci_platform_data *plat;
-	struct sdhci_host *host;
+	struct sdhci_tegra *tegra_host;
 	struct clk *clk;
 	int rc;
 
-	host = sdhci_pltfm_init(pdev, &sdhci_tegra_pdata);
+	match = of_match_device(sdhci_tegra_dt_match, &pdev->dev);
+	if (match)
+		soc_data = match->data;
+	else
+		soc_data = &soc_data_tegra20;
+
+	host = sdhci_pltfm_init(pdev, soc_data->pdata);
 	if (IS_ERR(host))
 		return PTR_ERR(host);
 
@@ -188,7 +250,17 @@
 		goto err_no_plat;
 	}
 
-	pltfm_host->priv = plat;
+	tegra_host = devm_kzalloc(&pdev->dev, sizeof(*tegra_host), GFP_KERNEL);
+	if (!tegra_host) {
+		dev_err(mmc_dev(host->mmc), "failed to allocate tegra_host\n");
+		rc = -ENOMEM;
+		goto err_no_plat;
+	}
+
+	tegra_host->plat = plat;
+	tegra_host->soc_data = soc_data;
+
+	pltfm_host->priv = tegra_host;
 
 	if (gpio_is_valid(plat->power_gpio)) {
 		rc = gpio_request(plat->power_gpio, "sdhci_power");
@@ -284,7 +356,8 @@
 {
 	struct sdhci_host *host = platform_get_drvdata(pdev);
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	struct tegra_sdhci_platform_data *plat = pltfm_host->priv;
+	struct sdhci_tegra *tegra_host = pltfm_host->priv;
+	const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
 	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
 
 	sdhci_remove_host(host, dead);
@@ -327,5 +400,5 @@
 module_platform_driver(sdhci_tegra_driver);
 
 MODULE_DESCRIPTION("SDHCI driver for Tegra");
-MODULE_AUTHOR(" Google, Inc.");
+MODULE_AUTHOR("Google, Inc.");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 8d66706..8262cad 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2267,8 +2267,8 @@
 {
 	irqreturn_t result;
 	struct sdhci_host *host = dev_id;
-	u32 intmask;
-	int cardint = 0;
+	u32 intmask, unexpected = 0;
+	int cardint = 0, max_loops = 16;
 
 	spin_lock(&host->lock);
 
@@ -2286,6 +2286,7 @@
 		goto out;
 	}
 
+again:
 	DBG("*** %s got interrupt: 0x%08x\n",
 		mmc_hostname(host->mmc), intmask);
 
@@ -2344,19 +2345,23 @@
 	intmask &= ~SDHCI_INT_CARD_INT;
 
 	if (intmask) {
-		pr_err("%s: Unexpected interrupt 0x%08x.\n",
-			mmc_hostname(host->mmc), intmask);
-		sdhci_dumpregs(host);
-
+		unexpected |= intmask;
 		sdhci_writel(host, intmask, SDHCI_INT_STATUS);
 	}
 
 	result = IRQ_HANDLED;
 
-	mmiowb();
+	intmask = sdhci_readl(host, SDHCI_INT_STATUS);
+	if (intmask && --max_loops)
+		goto again;
 out:
 	spin_unlock(&host->lock);
 
+	if (unexpected) {
+		pr_err("%s: Unexpected interrupt 0x%08x.\n",
+			   mmc_hostname(host->mmc), unexpected);
+		sdhci_dumpregs(host);
+	}
 	/*
 	 * We have to delay this as it calls back into the driver.
 	 */
@@ -2379,6 +2384,9 @@
 	int ret;
 	bool has_tuning_timer;
 
+	if (host->ops->platform_suspend)
+		host->ops->platform_suspend(host);
+
 	sdhci_disable_card_detection(host);
 
 	/* Disable tuning since we are suspending */
@@ -2423,12 +2431,24 @@
 	if (ret)
 		return ret;
 
-	sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
-	mmiowb();
+	if ((host->mmc->pm_flags & MMC_PM_KEEP_POWER) &&
+	    (host->quirks2 & SDHCI_QUIRK2_HOST_OFF_CARD_ON)) {
+		/* Card keeps power but host controller does not */
+		sdhci_init(host, 0);
+		host->pwr = 0;
+		host->clock = 0;
+		sdhci_do_set_ios(host, &host->mmc->ios);
+	} else {
+		sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
+		mmiowb();
+	}
 
 	ret = mmc_resume_host(host->mmc);
 	sdhci_enable_card_detection(host);
 
+	if (host->ops->platform_resume)
+		host->ops->platform_resume(host);
+
 	/* Set the re-tuning expiration flag */
 	if ((host->version >= SDHCI_SPEC_300) && host->tuning_count &&
 	    (host->tuning_mode == SDHCI_TUNING_MODE_1))
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index ad265b9..f761f23 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -275,6 +275,8 @@
 	void	(*platform_reset_exit)(struct sdhci_host *host, u8 mask);
 	int	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
 	void	(*hw_reset)(struct sdhci_host *host);
+	void	(*platform_suspend)(struct sdhci_host *host);
+	void	(*platform_resume)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 75a4854..aafaf0b 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -286,7 +286,7 @@
 			 DMA_FROM_DEVICE);
 	if (ret > 0) {
 		host->dma_active = true;
-		desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+		desc = dmaengine_prep_slave_sg(chan, sg, ret,
 			DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	}
 
@@ -335,7 +335,7 @@
 			 DMA_TO_DEVICE);
 	if (ret > 0) {
 		host->dma_active = true;
-		desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+		desc = dmaengine_prep_slave_sg(chan, sg, ret,
 			DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	}
 
@@ -746,7 +746,6 @@
 	case MMC_SET_WRITE_PROT:
 	case MMC_CLR_WRITE_PROT:
 	case MMC_ERASE:
-	case MMC_GEN_CMD:
 		tmp |= CMD_SET_RBSY;
 		break;
 	}
@@ -829,7 +828,6 @@
 	case MMC_SET_WRITE_PROT:
 	case MMC_CLR_WRITE_PROT:
 	case MMC_ERASE:
-	case MMC_GEN_CMD:
 		mask = MASK_START_CMD | MASK_MRBSYE;
 		break;
 	default:
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 58da3c4..934b68e 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -90,6 +90,15 @@
 	return 0;
 }
 
+static void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev)
+{
+	mmc_detect_change(dev_get_drvdata(&pdev->dev), msecs_to_jiffies(100));
+}
+
+static const struct sh_mobile_sdhi_ops sdhi_ops = {
+	.cd_wakeup = sh_mobile_sdhi_cd_wakeup,
+};
+
 static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
 {
 	struct sh_mobile_sdhi *priv;
@@ -109,6 +118,12 @@
 	mmc_data = &priv->mmc_data;
 	p->pdata = mmc_data;
 
+	if (p->init) {
+		ret = p->init(pdev, &sdhi_ops);
+		if (ret)
+			goto einit;
+	}
+
 	snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
 	priv->clk = clk_get(&pdev->dev, clk_name);
 	if (IS_ERR(priv->clk)) {
@@ -117,8 +132,6 @@
 		goto eclkget;
 	}
 
-	clk_enable(priv->clk);
-
 	mmc_data->hclk = clk_get_rate(priv->clk);
 	mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
 	mmc_data->get_cd = sh_mobile_sdhi_get_cd;
@@ -129,6 +142,7 @@
 			mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
 		mmc_data->ocr_mask = p->tmio_ocr_mask;
 		mmc_data->capabilities |= p->tmio_caps;
+		mmc_data->cd_gpio = p->cd_gpio;
 
 		if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) {
 			priv->param_tx.slave_id = p->dma_slave_tx;
@@ -211,7 +225,7 @@
 
 	dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
 		 mmc_hostname(host->mmc), (unsigned long)
-		 (platform_get_resource(pdev,IORESOURCE_MEM, 0)->start),
+		 (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start),
 		 mmc_data->hclk / 1000000);
 
 	return ret;
@@ -232,9 +246,11 @@
 eirq_card_detect:
 	tmio_mmc_host_remove(host);
 eprobe:
-	clk_disable(priv->clk);
 	clk_put(priv->clk);
 eclkget:
+	if (p->cleanup)
+		p->cleanup(pdev);
+einit:
 	kfree(priv);
 	return ret;
 }
@@ -258,8 +274,11 @@
 		free_irq(irq, host);
 	}
 
-	clk_disable(priv->clk);
 	clk_put(priv->clk);
+
+	if (p->cleanup)
+		p->cleanup(pdev);
+
 	kfree(priv);
 
 	return 0;
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index f96c536..d857f5c 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -47,16 +47,14 @@
 	struct mmc_request      *mrq;
 	struct mmc_data         *data;
 	struct mmc_host         *mmc;
-	unsigned int		sdio_irq_enabled;
+
+	/* Controller power state */
+	bool			power;
 
 	/* Callbacks for clock / power control */
 	void (*set_pwr)(struct platform_device *host, int state);
 	void (*set_clk_div)(struct platform_device *host, int state);
 
-	int			pm_error;
-	/* recognise system-wide suspend in runtime PM methods */
-	bool			pm_global;
-
 	/* pio related stuff */
 	struct scatterlist      *sg_ptr;
 	struct scatterlist      *sg_orig;
@@ -86,6 +84,7 @@
 	spinlock_t		lock;		/* protect host private data */
 	unsigned long		last_req_ts;
 	struct mutex		ios_lock;	/* protect set_ios() context */
+	bool			native_hotplug;
 };
 
 int tmio_mmc_host_probe(struct tmio_mmc_host **host,
diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c
index 8253ec1..fff9286 100644
--- a/drivers/mmc/host/tmio_mmc_dma.c
+++ b/drivers/mmc/host/tmio_mmc_dma.c
@@ -88,7 +88,7 @@
 
 	ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE);
 	if (ret > 0)
-		desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+		desc = dmaengine_prep_slave_sg(chan, sg, ret,
 			DMA_DEV_TO_MEM, DMA_CTRL_ACK);
 
 	if (desc) {
@@ -169,7 +169,7 @@
 
 	ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE);
 	if (ret > 0)
-		desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+		desc = dmaengine_prep_slave_sg(chan, sg, ret,
 			DMA_MEM_TO_DEV, DMA_CTRL_ACK);
 
 	if (desc) {
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index e219889..9a7996a 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -34,6 +34,7 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/mfd/tmio.h>
+#include <linux/mmc/cd-gpio.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/tmio.h>
 #include <linux/module.h>
@@ -127,7 +128,6 @@
 	struct tmio_mmc_host *host = mmc_priv(mmc);
 
 	if (enable) {
-		host->sdio_irq_enabled = 1;
 		host->sdio_irq_mask = TMIO_SDIO_MASK_ALL &
 					~TMIO_SDIO_STAT_IOIRQ;
 		sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
@@ -136,7 +136,6 @@
 		host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
 		sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
 		sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
-		host->sdio_irq_enabled = 0;
 	}
 }
 
@@ -304,6 +303,7 @@
 {
 	struct mmc_data *data = host->data;
 	int c = cmd->opcode;
+	u32 irq_mask = TMIO_MASK_CMD;
 
 	/* Command 12 is handled by hardware */
 	if (cmd->opcode == 12 && !cmd->arg) {
@@ -339,7 +339,9 @@
 			c |= TRANSFER_READ;
 	}
 
-	tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_CMD);
+	if (!host->native_hotplug)
+		irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
+	tmio_mmc_enable_mmc_irqs(host, irq_mask);
 
 	/* Fire off the command */
 	sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg);
@@ -758,7 +760,7 @@
 static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct tmio_mmc_host *host = mmc_priv(mmc);
-	struct tmio_mmc_data *pdata = host->pdata;
+	struct device *dev = &host->pdev->dev;
 	unsigned long flags;
 
 	mutex_lock(&host->ios_lock);
@@ -766,13 +768,13 @@
 	spin_lock_irqsave(&host->lock, flags);
 	if (host->mrq) {
 		if (IS_ERR(host->mrq)) {
-			dev_dbg(&host->pdev->dev,
+			dev_dbg(dev,
 				"%s.%d: concurrent .set_ios(), clk %u, mode %u\n",
 				current->comm, task_pid_nr(current),
 				ios->clock, ios->power_mode);
 			host->mrq = ERR_PTR(-EINTR);
 		} else {
-			dev_dbg(&host->pdev->dev,
+			dev_dbg(dev,
 				"%s.%d: CMD%u active since %lu, now %lu!\n",
 				current->comm, task_pid_nr(current),
 				host->mrq->cmd->opcode, host->last_req_ts, jiffies);
@@ -788,13 +790,15 @@
 	spin_unlock_irqrestore(&host->lock, flags);
 
 	/*
-	 * pdata->power == false only if COLD_CD is available, otherwise only
-	 * in short time intervals during probing or resuming
+	 * host->power toggles between false and true in both cases - either
+	 * or not the controller can be runtime-suspended during inactivity.
+	 * But if the controller has to be kept on, the runtime-pm usage_count
+	 * is kept positive, so no suspending actually takes place.
 	 */
 	if (ios->power_mode == MMC_POWER_ON && ios->clock) {
-		if (!pdata->power) {
-			pm_runtime_get_sync(&host->pdev->dev);
-			pdata->power = true;
+		if (!host->power) {
+			pm_runtime_get_sync(dev);
+			host->power = true;
 		}
 		tmio_mmc_set_clock(host, ios->clock);
 		/* power up SD bus */
@@ -805,9 +809,9 @@
 	} else if (ios->power_mode != MMC_POWER_UP) {
 		if (host->set_pwr && ios->power_mode == MMC_POWER_OFF)
 			host->set_pwr(host->pdev, 0);
-		if (pdata->power) {
-			pdata->power = false;
-			pm_runtime_put(&host->pdev->dev);
+		if (host->power) {
+			host->power = false;
+			pm_runtime_put(dev);
 		}
 		tmio_mmc_clk_stop(host);
 	}
@@ -913,7 +917,11 @@
 	else
 		mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 
-	pdata->power = false;
+	_host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD ||
+				  mmc->caps & MMC_CAP_NEEDS_POLL ||
+				  mmc->caps & MMC_CAP_NONREMOVABLE);
+
+	_host->power = false;
 	pm_runtime_enable(&pdev->dev);
 	ret = pm_runtime_resume(&pdev->dev);
 	if (ret < 0)
@@ -926,14 +934,13 @@
 	 *  3) a worker thread polls the sdhi - indicated by MMC_CAP_NEEDS_POLL
 	 *  4) the medium is non-removable - indicated by MMC_CAP_NONREMOVABLE
 	 *
-	 *  While we increment the rtpm counter for all scenarios when the mmc
-	 *  core activates us by calling an appropriate set_ios(), we must
+	 *  While we increment the runtime PM counter for all scenarios when
+	 *  the mmc core activates us by calling an appropriate set_ios(), we
+	 *  must additionally ensure that in case 2) the tmio mmc hardware stays
 	 *  additionally ensure that in case 2) the tmio mmc hardware stays
 	 *  powered on during runtime for the card detection to work.
 	 */
-	if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD
-		|| mmc->caps & MMC_CAP_NEEDS_POLL
-		|| mmc->caps & MMC_CAP_NONREMOVABLE))
+	if (_host->native_hotplug)
 		pm_runtime_get_noresume(&pdev->dev);
 
 	tmio_mmc_clk_stop(_host);
@@ -963,9 +970,19 @@
 		irq_mask |= TMIO_MASK_READOP;
 	if (!_host->chan_tx)
 		irq_mask |= TMIO_MASK_WRITEOP;
+	if (!_host->native_hotplug)
+		irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
 
 	tmio_mmc_enable_mmc_irqs(_host, irq_mask);
 
+	if (pdata->flags & TMIO_MMC_USE_GPIO_CD) {
+		ret = mmc_cd_gpio_request(mmc, pdata->cd_gpio);
+		if (ret < 0) {
+			tmio_mmc_host_remove(_host);
+			return ret;
+		}
+	}
+
 	*host = _host;
 
 	return 0;
@@ -983,22 +1000,22 @@
 void tmio_mmc_host_remove(struct tmio_mmc_host *host)
 {
 	struct platform_device *pdev = host->pdev;
+	struct tmio_mmc_data *pdata = host->pdata;
+	struct mmc_host *mmc = host->mmc;
 
-	/*
-	 * We don't have to manipulate pdata->power here: if there is a card in
-	 * the slot, the runtime PM is active and our .runtime_resume() will not
-	 * be run. If there is no card in the slot and the platform can suspend
-	 * the controller, the runtime PM is suspended and pdata->power == false,
-	 * so, our .runtime_resume() will not try to detect a card in the slot.
-	 */
-	if (host->pdata->flags & TMIO_MMC_HAS_COLD_CD
-		|| host->mmc->caps & MMC_CAP_NEEDS_POLL
-		|| host->mmc->caps & MMC_CAP_NONREMOVABLE)
+	if (pdata->flags & TMIO_MMC_USE_GPIO_CD)
+		/*
+		 * This means we can miss a card-eject, but this is anyway
+		 * possible, because of delayed processing of hotplug events.
+		 */
+		mmc_cd_gpio_free(mmc);
+
+	if (!host->native_hotplug)
 		pm_runtime_get_sync(&pdev->dev);
 
 	dev_pm_qos_hide_latency_limit(&pdev->dev);
 
-	mmc_remove_host(host->mmc);
+	mmc_remove_host(mmc);
 	cancel_work_sync(&host->done);
 	cancel_delayed_work_sync(&host->delayed_reset_work);
 	tmio_mmc_release_dma(host);
@@ -1007,7 +1024,7 @@
 	pm_runtime_disable(&pdev->dev);
 
 	iounmap(host->ctl);
-	mmc_free_host(host->mmc);
+	mmc_free_host(mmc);
 }
 EXPORT_SYMBOL(tmio_mmc_host_remove);
 
@@ -1021,8 +1038,6 @@
 	if (!ret)
 		tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
 
-	host->pm_error = pm_runtime_put_sync(dev);
-
 	return ret;
 }
 EXPORT_SYMBOL(tmio_mmc_host_suspend);
@@ -1032,20 +1047,10 @@
 	struct mmc_host *mmc = dev_get_drvdata(dev);
 	struct tmio_mmc_host *host = mmc_priv(mmc);
 
+	tmio_mmc_reset(host);
+	tmio_mmc_enable_dma(host, true);
+
 	/* The MMC core will perform the complete set up */
-	host->pdata->power = false;
-
-	host->pm_global = true;
-	if (!host->pm_error)
-		pm_runtime_get_sync(dev);
-
-	if (host->pm_global) {
-		/* Runtime PM resume callback didn't run */
-		tmio_mmc_reset(host);
-		tmio_mmc_enable_dma(host, true);
-		host->pm_global = false;
-	}
-
 	return mmc_resume_host(mmc);
 }
 EXPORT_SYMBOL(tmio_mmc_host_resume);
@@ -1062,19 +1067,10 @@
 {
 	struct mmc_host *mmc = dev_get_drvdata(dev);
 	struct tmio_mmc_host *host = mmc_priv(mmc);
-	struct tmio_mmc_data *pdata = host->pdata;
 
 	tmio_mmc_reset(host);
 	tmio_mmc_enable_dma(host, true);
 
-	if (pdata->power) {
-		/* Only entered after a card-insert interrupt */
-		if (!mmc->card)
-			tmio_mmc_set_ios(mmc, &mmc->ios);
-		mmc_detect_change(mmc, msecs_to_jiffies(100));
-	}
-	host->pm_global = false;
-
 	return 0;
 }
 EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 1be6218..5760c1a 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -1,6 +1,6 @@
 menuconfig MTD
 	tristate "Memory Technology Device (MTD) support"
-	depends on HAS_IOMEM
+	depends on GENERIC_IO
 	help
 	  Memory Technology Devices are flash, RAM and similar chips, often
 	  used for solid state file systems on embedded devices. This option
@@ -304,9 +304,6 @@
 	  buffer in a flash partition where it can be read back at some
 	  later point.
 
-	  To use, add console=ttyMTDx to the kernel command line,
-	  where x is the MTD device number to use.
-
 config MTD_SWAP
 	tristate "Swap on MTD device support"
 	depends on MTD && SWAP
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index e1e122f..dbbd2ed 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -87,7 +87,7 @@
 
 static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
 		     size_t *retlen, void **virt, resource_size_t *phys);
-static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len);
+static int cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len);
 
 static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
 static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
@@ -262,9 +262,9 @@
 static void fixup_use_point(struct mtd_info *mtd)
 {
 	struct map_info *map = mtd->priv;
-	if (!mtd->point && map_is_linear(map)) {
-		mtd->point   = cfi_intelext_point;
-		mtd->unpoint = cfi_intelext_unpoint;
+	if (!mtd->_point && map_is_linear(map)) {
+		mtd->_point   = cfi_intelext_point;
+		mtd->_unpoint = cfi_intelext_unpoint;
 	}
 }
 
@@ -274,8 +274,8 @@
 	struct cfi_private *cfi = map->fldrv_priv;
 	if (cfi->cfiq->BufWriteTimeoutTyp) {
 		printk(KERN_INFO "Using buffer write method\n" );
-		mtd->write = cfi_intelext_write_buffers;
-		mtd->writev = cfi_intelext_writev;
+		mtd->_write = cfi_intelext_write_buffers;
+		mtd->_writev = cfi_intelext_writev;
 	}
 }
 
@@ -443,15 +443,15 @@
 	mtd->type = MTD_NORFLASH;
 
 	/* Fill in the default mtd operations */
-	mtd->erase   = cfi_intelext_erase_varsize;
-	mtd->read    = cfi_intelext_read;
-	mtd->write   = cfi_intelext_write_words;
-	mtd->sync    = cfi_intelext_sync;
-	mtd->lock    = cfi_intelext_lock;
-	mtd->unlock  = cfi_intelext_unlock;
-	mtd->is_locked = cfi_intelext_is_locked;
-	mtd->suspend = cfi_intelext_suspend;
-	mtd->resume  = cfi_intelext_resume;
+	mtd->_erase   = cfi_intelext_erase_varsize;
+	mtd->_read    = cfi_intelext_read;
+	mtd->_write   = cfi_intelext_write_words;
+	mtd->_sync    = cfi_intelext_sync;
+	mtd->_lock    = cfi_intelext_lock;
+	mtd->_unlock  = cfi_intelext_unlock;
+	mtd->_is_locked = cfi_intelext_is_locked;
+	mtd->_suspend = cfi_intelext_suspend;
+	mtd->_resume  = cfi_intelext_resume;
 	mtd->flags   = MTD_CAP_NORFLASH;
 	mtd->name    = map->name;
 	mtd->writesize = 1;
@@ -600,12 +600,12 @@
 	}
 
 #ifdef CONFIG_MTD_OTP
-	mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
-	mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
-	mtd->write_user_prot_reg = cfi_intelext_write_user_prot_reg;
-	mtd->lock_user_prot_reg = cfi_intelext_lock_user_prot_reg;
-	mtd->get_fact_prot_info = cfi_intelext_get_fact_prot_info;
-	mtd->get_user_prot_info = cfi_intelext_get_user_prot_info;
+	mtd->_read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
+	mtd->_read_user_prot_reg = cfi_intelext_read_user_prot_reg;
+	mtd->_write_user_prot_reg = cfi_intelext_write_user_prot_reg;
+	mtd->_lock_user_prot_reg = cfi_intelext_lock_user_prot_reg;
+	mtd->_get_fact_prot_info = cfi_intelext_get_fact_prot_info;
+	mtd->_get_user_prot_info = cfi_intelext_get_user_prot_info;
 #endif
 
 	/* This function has the potential to distort the reality
@@ -1017,8 +1017,6 @@
 	case FL_READY:
 	case FL_STATUS:
 	case FL_JEDEC_QUERY:
-		/* We should really make set_vpp() count, rather than doing this */
-		DISABLE_VPP(map);
 		break;
 	default:
 		printk(KERN_ERR "%s: put_chip() called with oldstate %d!!\n", map->name, chip->oldstate);
@@ -1324,7 +1322,7 @@
 	int chipnum;
 	int ret = 0;
 
-	if (!map->virt || (from + len > mtd->size))
+	if (!map->virt)
 		return -EINVAL;
 
 	/* Now lock the chip(s) to POINT state */
@@ -1334,7 +1332,6 @@
 	ofs = from - (chipnum << cfi->chipshift);
 
 	*virt = map->virt + cfi->chips[chipnum].start + ofs;
-	*retlen = 0;
 	if (phys)
 		*phys = map->phys + cfi->chips[chipnum].start + ofs;
 
@@ -1369,12 +1366,12 @@
 	return 0;
 }
 
-static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
+static int cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
 	struct map_info *map = mtd->priv;
 	struct cfi_private *cfi = map->fldrv_priv;
 	unsigned long ofs;
-	int chipnum;
+	int chipnum, err = 0;
 
 	/* Now unlock the chip(s) POINT state */
 
@@ -1382,7 +1379,7 @@
 	chipnum = (from >> cfi->chipshift);
 	ofs = from - (chipnum <<  cfi->chipshift);
 
-	while (len) {
+	while (len && !err) {
 		unsigned long thislen;
 		struct flchip *chip;
 
@@ -1400,8 +1397,10 @@
 			chip->ref_point_counter--;
 			if(chip->ref_point_counter == 0)
 				chip->state = FL_READY;
-		} else
-			printk(KERN_ERR "%s: Warning: unpoint called on non pointed region\n", map->name); /* Should this give an error? */
+		} else {
+			printk(KERN_ERR "%s: Error: unpoint called on non pointed region\n", map->name);
+			err = -EINVAL;
+		}
 
 		put_chip(map, chip, chip->start);
 		mutex_unlock(&chip->mutex);
@@ -1410,6 +1409,8 @@
 		ofs = 0;
 		chipnum++;
 	}
+
+	return err;
 }
 
 static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
@@ -1456,8 +1457,6 @@
 	chipnum = (from >> cfi->chipshift);
 	ofs = from - (chipnum <<  cfi->chipshift);
 
-	*retlen = 0;
-
 	while (len) {
 		unsigned long thislen;
 
@@ -1551,7 +1550,8 @@
 	}
 
 	xip_enable(map, chip, adr);
- out:	put_chip(map, chip, adr);
+ out:	DISABLE_VPP(map);
+	put_chip(map, chip, adr);
 	mutex_unlock(&chip->mutex);
 	return ret;
 }
@@ -1565,10 +1565,6 @@
 	int chipnum;
 	unsigned long ofs;
 
-	*retlen = 0;
-	if (!len)
-		return 0;
-
 	chipnum = to >> cfi->chipshift;
 	ofs = to  - (chipnum << cfi->chipshift);
 
@@ -1794,7 +1790,8 @@
 	}
 
 	xip_enable(map, chip, cmd_adr);
- out:	put_chip(map, chip, cmd_adr);
+ out:	DISABLE_VPP(map);
+	put_chip(map, chip, cmd_adr);
 	mutex_unlock(&chip->mutex);
 	return ret;
 }
@@ -1813,7 +1810,6 @@
 	for (i = 0; i < count; i++)
 		len += vecs[i].iov_len;
 
-	*retlen = 0;
 	if (!len)
 		return 0;
 
@@ -1932,6 +1928,7 @@
 			ret = -EIO;
 		} else if (chipstatus & 0x20 && retries--) {
 			printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus);
+			DISABLE_VPP(map);
 			put_chip(map, chip, adr);
 			mutex_unlock(&chip->mutex);
 			goto retry;
@@ -1944,7 +1941,8 @@
 	}
 
 	xip_enable(map, chip, adr);
- out:	put_chip(map, chip, adr);
+ out:	DISABLE_VPP(map);
+	put_chip(map, chip, adr);
 	mutex_unlock(&chip->mutex);
 	return ret;
 }
@@ -2086,7 +2084,8 @@
 	}
 
 	xip_enable(map, chip, adr);
-out:	put_chip(map, chip, adr);
+ out:	DISABLE_VPP(map);
+	put_chip(map, chip, adr);
 	mutex_unlock(&chip->mutex);
 	return ret;
 }
@@ -2483,7 +2482,7 @@
 			   allowed to. Or should we return -EAGAIN, because the upper layers
 			   ought to have already shut down anything which was using the device
 			   anyway? The latter for now. */
-			printk(KERN_NOTICE "Flash device refused suspend due to active operation (state %d)\n", chip->oldstate);
+			printk(KERN_NOTICE "Flash device refused suspend due to active operation (state %d)\n", chip->state);
 			ret = -EAGAIN;
 		case FL_PM_SUSPENDED:
 			break;
@@ -2526,12 +2525,10 @@
 		if (!region->lockmap)
 			continue;
 
-		for (block = 0; block < region->numblocks; block++) {
+		for_each_clear_bit(block, region->lockmap, region->numblocks) {
 			len = region->erasesize;
 			adr = region->offset + block * len;
-
-			if (!test_bit(block, region->lockmap))
-				cfi_intelext_unlock(mtd, adr, len);
+			cfi_intelext_unlock(mtd, adr, len);
 		}
 	}
 }
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 8d70895..d02592e 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -59,6 +59,9 @@
 static int cfi_amdstd_reboot(struct notifier_block *, unsigned long, void *);
 static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 
+static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
+				  size_t *retlen, const u_char *buf);
+
 static void cfi_amdstd_destroy(struct mtd_info *);
 
 struct mtd_info *cfi_cmdset_0002(struct map_info *, int);
@@ -189,7 +192,7 @@
 	struct cfi_private *cfi = map->fldrv_priv;
 	if (cfi->cfiq->BufWriteTimeoutTyp) {
 		pr_debug("Using buffer write method\n" );
-		mtd->write = cfi_amdstd_write_buffers;
+		mtd->_write = cfi_amdstd_write_buffers;
 	}
 }
 
@@ -228,8 +231,8 @@
 static void fixup_use_secsi(struct mtd_info *mtd)
 {
 	/* Setup for chips with a secsi area */
-	mtd->read_user_prot_reg = cfi_amdstd_secsi_read;
-	mtd->read_fact_prot_reg = cfi_amdstd_secsi_read;
+	mtd->_read_user_prot_reg = cfi_amdstd_secsi_read;
+	mtd->_read_fact_prot_reg = cfi_amdstd_secsi_read;
 }
 
 static void fixup_use_erase_chip(struct mtd_info *mtd)
@@ -238,7 +241,7 @@
 	struct cfi_private *cfi = map->fldrv_priv;
 	if ((cfi->cfiq->NumEraseRegions == 1) &&
 		((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) {
-		mtd->erase = cfi_amdstd_erase_chip;
+		mtd->_erase = cfi_amdstd_erase_chip;
 	}
 
 }
@@ -249,8 +252,8 @@
  */
 static void fixup_use_atmel_lock(struct mtd_info *mtd)
 {
-	mtd->lock = cfi_atmel_lock;
-	mtd->unlock = cfi_atmel_unlock;
+	mtd->_lock = cfi_atmel_lock;
+	mtd->_unlock = cfi_atmel_unlock;
 	mtd->flags |= MTD_POWERUP_LOCK;
 }
 
@@ -429,12 +432,12 @@
 	mtd->type = MTD_NORFLASH;
 
 	/* Fill in the default mtd operations */
-	mtd->erase   = cfi_amdstd_erase_varsize;
-	mtd->write   = cfi_amdstd_write_words;
-	mtd->read    = cfi_amdstd_read;
-	mtd->sync    = cfi_amdstd_sync;
-	mtd->suspend = cfi_amdstd_suspend;
-	mtd->resume  = cfi_amdstd_resume;
+	mtd->_erase   = cfi_amdstd_erase_varsize;
+	mtd->_write   = cfi_amdstd_write_words;
+	mtd->_read    = cfi_amdstd_read;
+	mtd->_sync    = cfi_amdstd_sync;
+	mtd->_suspend = cfi_amdstd_suspend;
+	mtd->_resume  = cfi_amdstd_resume;
 	mtd->flags   = MTD_CAP_NORFLASH;
 	mtd->name    = map->name;
 	mtd->writesize = 1;
@@ -443,6 +446,7 @@
 	pr_debug("MTD %s(): write buffer size %d\n", __func__,
 			mtd->writebufsize);
 
+	mtd->_panic_write = cfi_amdstd_panic_write;
 	mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot;
 
 	if (cfi->cfi_mode==CFI_MODE_CFI){
@@ -770,8 +774,6 @@
 
 	case FL_READY:
 	case FL_STATUS:
-		/* We should really make set_vpp() count, rather than doing this */
-		DISABLE_VPP(map);
 		break;
 	default:
 		printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate);
@@ -1013,13 +1015,9 @@
 	int ret = 0;
 
 	/* ofs: offset within the first chip that the first read should start */
-
 	chipnum = (from >> cfi->chipshift);
 	ofs = from - (chipnum <<  cfi->chipshift);
 
-
-	*retlen = 0;
-
 	while (len) {
 		unsigned long thislen;
 
@@ -1097,16 +1095,11 @@
 	int chipnum;
 	int ret = 0;
 
-
 	/* ofs: offset within the first chip that the first read should start */
-
 	/* 8 secsi bytes per chip */
 	chipnum=from>>3;
 	ofs=from & 7;
 
-
-	*retlen = 0;
-
 	while (len) {
 		unsigned long thislen;
 
@@ -1234,6 +1227,7 @@
 	xip_enable(map, chip, adr);
  op_done:
 	chip->state = FL_READY;
+	DISABLE_VPP(map);
 	put_chip(map, chip, adr);
 	mutex_unlock(&chip->mutex);
 
@@ -1251,10 +1245,6 @@
 	unsigned long ofs, chipstart;
 	DECLARE_WAITQUEUE(wait, current);
 
-	*retlen = 0;
-	if (!len)
-		return 0;
-
 	chipnum = to >> cfi->chipshift;
 	ofs = to  - (chipnum << cfi->chipshift);
 	chipstart = cfi->chips[chipnum].start;
@@ -1476,6 +1466,7 @@
 	ret = -EIO;
  op_done:
 	chip->state = FL_READY;
+	DISABLE_VPP(map);
 	put_chip(map, chip, adr);
 	mutex_unlock(&chip->mutex);
 
@@ -1493,10 +1484,6 @@
 	int chipnum;
 	unsigned long ofs;
 
-	*retlen = 0;
-	if (!len)
-		return 0;
-
 	chipnum = to >> cfi->chipshift;
 	ofs = to  - (chipnum << cfi->chipshift);
 
@@ -1562,6 +1549,238 @@
 	return 0;
 }
 
+/*
+ * Wait for the flash chip to become ready to write data
+ *
+ * This is only called during the panic_write() path. When panic_write()
+ * is called, the kernel is in the process of a panic, and will soon be
+ * dead. Therefore we don't take any locks, and attempt to get access
+ * to the chip as soon as possible.
+ */
+static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
+				 unsigned long adr)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	int retries = 10;
+	int i;
+
+	/*
+	 * If the driver thinks the chip is idle, and no toggle bits
+	 * are changing, then the chip is actually idle for sure.
+	 */
+	if (chip->state == FL_READY && chip_ready(map, adr))
+		return 0;
+
+	/*
+	 * Try several times to reset the chip and then wait for it
+	 * to become idle. The upper limit of a few milliseconds of
+	 * delay isn't a big problem: the kernel is dying anyway. It
+	 * is more important to save the messages.
+	 */
+	while (retries > 0) {
+		const unsigned long timeo = (HZ / 1000) + 1;
+
+		/* send the reset command */
+		map_write(map, CMD(0xF0), chip->start);
+
+		/* wait for the chip to become ready */
+		for (i = 0; i < jiffies_to_usecs(timeo); i++) {
+			if (chip_ready(map, adr))
+				return 0;
+
+			udelay(1);
+		}
+	}
+
+	/* the chip never became ready */
+	return -EBUSY;
+}
+
+/*
+ * Write out one word of data to a single flash chip during a kernel panic
+ *
+ * This is only called during the panic_write() path. When panic_write()
+ * is called, the kernel is in the process of a panic, and will soon be
+ * dead. Therefore we don't take any locks, and attempt to get access
+ * to the chip as soon as possible.
+ *
+ * The implementation of this routine is intentionally similar to
+ * do_write_oneword(), in order to ease code maintenance.
+ */
+static int do_panic_write_oneword(struct map_info *map, struct flchip *chip,
+				  unsigned long adr, map_word datum)
+{
+	const unsigned long uWriteTimeout = (HZ / 1000) + 1;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int retry_cnt = 0;
+	map_word oldd;
+	int ret = 0;
+	int i;
+
+	adr += chip->start;
+
+	ret = cfi_amdstd_panic_wait(map, chip, adr);
+	if (ret)
+		return ret;
+
+	pr_debug("MTD %s(): PANIC WRITE 0x%.8lx(0x%.8lx)\n",
+			__func__, adr, datum.x[0]);
+
+	/*
+	 * Check for a NOP for the case when the datum to write is already
+	 * present - it saves time and works around buggy chips that corrupt
+	 * data at other locations when 0xff is written to a location that
+	 * already contains 0xff.
+	 */
+	oldd = map_read(map, adr);
+	if (map_word_equal(map, oldd, datum)) {
+		pr_debug("MTD %s(): NOP\n", __func__);
+		goto op_done;
+	}
+
+	ENABLE_VPP(map);
+
+retry:
+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	map_write(map, datum, adr);
+
+	for (i = 0; i < jiffies_to_usecs(uWriteTimeout); i++) {
+		if (chip_ready(map, adr))
+			break;
+
+		udelay(1);
+	}
+
+	if (!chip_good(map, adr, datum)) {
+		/* reset on all failures. */
+		map_write(map, CMD(0xF0), chip->start);
+		/* FIXME - should have reset delay before continuing */
+
+		if (++retry_cnt <= MAX_WORD_RETRIES)
+			goto retry;
+
+		ret = -EIO;
+	}
+
+op_done:
+	DISABLE_VPP(map);
+	return ret;
+}
+
+/*
+ * Write out some data during a kernel panic
+ *
+ * This is used by the mtdoops driver to save the dying messages from a
+ * kernel which has panic'd.
+ *
+ * This routine ignores all of the locking used throughout the rest of the
+ * driver, in order to ensure that the data gets written out no matter what
+ * state this driver (and the flash chip itself) was in when the kernel crashed.
+ *
+ * The implementation of this routine is intentionally similar to
+ * cfi_amdstd_write_words(), in order to ease code maintenance.
+ */
+static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
+				  size_t *retlen, const u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long ofs, chipstart;
+	int ret = 0;
+	int chipnum;
+
+	chipnum = to >> cfi->chipshift;
+	ofs = to - (chipnum << cfi->chipshift);
+	chipstart = cfi->chips[chipnum].start;
+
+	/* If it's not bus aligned, do the first byte write */
+	if (ofs & (map_bankwidth(map) - 1)) {
+		unsigned long bus_ofs = ofs & ~(map_bankwidth(map) - 1);
+		int i = ofs - bus_ofs;
+		int n = 0;
+		map_word tmp_buf;
+
+		ret = cfi_amdstd_panic_wait(map, &cfi->chips[chipnum], bus_ofs);
+		if (ret)
+			return ret;
+
+		/* Load 'tmp_buf' with old contents of flash */
+		tmp_buf = map_read(map, bus_ofs + chipstart);
+
+		/* Number of bytes to copy from buffer */
+		n = min_t(int, len, map_bankwidth(map) - i);
+
+		tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n);
+
+		ret = do_panic_write_oneword(map, &cfi->chips[chipnum],
+					     bus_ofs, tmp_buf);
+		if (ret)
+			return ret;
+
+		ofs += n;
+		buf += n;
+		(*retlen) += n;
+		len -= n;
+
+		if (ofs >> cfi->chipshift) {
+			chipnum++;
+			ofs = 0;
+			if (chipnum == cfi->numchips)
+				return 0;
+		}
+	}
+
+	/* We are now aligned, write as much as possible */
+	while (len >= map_bankwidth(map)) {
+		map_word datum;
+
+		datum = map_word_load(map, buf);
+
+		ret = do_panic_write_oneword(map, &cfi->chips[chipnum],
+					     ofs, datum);
+		if (ret)
+			return ret;
+
+		ofs += map_bankwidth(map);
+		buf += map_bankwidth(map);
+		(*retlen) += map_bankwidth(map);
+		len -= map_bankwidth(map);
+
+		if (ofs >> cfi->chipshift) {
+			chipnum++;
+			ofs = 0;
+			if (chipnum == cfi->numchips)
+				return 0;
+
+			chipstart = cfi->chips[chipnum].start;
+		}
+	}
+
+	/* Write the trailing bytes if any */
+	if (len & (map_bankwidth(map) - 1)) {
+		map_word tmp_buf;
+
+		ret = cfi_amdstd_panic_wait(map, &cfi->chips[chipnum], ofs);
+		if (ret)
+			return ret;
+
+		tmp_buf = map_read(map, ofs + chipstart);
+
+		tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);
+
+		ret = do_panic_write_oneword(map, &cfi->chips[chipnum],
+					     ofs, tmp_buf);
+		if (ret)
+			return ret;
+
+		(*retlen) += len;
+	}
+
+	return 0;
+}
+
 
 /*
  * Handle devices with one erase region, that only implement
@@ -1649,6 +1868,7 @@
 
 	chip->state = FL_READY;
 	xip_enable(map, chip, adr);
+	DISABLE_VPP(map);
 	put_chip(map, chip, adr);
 	mutex_unlock(&chip->mutex);
 
@@ -1739,6 +1959,7 @@
 	}
 
 	chip->state = FL_READY;
+	DISABLE_VPP(map);
 	put_chip(map, chip, adr);
 	mutex_unlock(&chip->mutex);
 	return ret;
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c
index 85e8018..096993f 100644
--- a/drivers/mtd/chips/cfi_cmdset_0020.c
+++ b/drivers/mtd/chips/cfi_cmdset_0020.c
@@ -228,15 +228,15 @@
 		}
 
 	/* Also select the correct geometry setup too */
-	mtd->erase = cfi_staa_erase_varsize;
-	mtd->read = cfi_staa_read;
-        mtd->write = cfi_staa_write_buffers;
-	mtd->writev = cfi_staa_writev;
-	mtd->sync = cfi_staa_sync;
-	mtd->lock = cfi_staa_lock;
-	mtd->unlock = cfi_staa_unlock;
-	mtd->suspend = cfi_staa_suspend;
-	mtd->resume = cfi_staa_resume;
+	mtd->_erase = cfi_staa_erase_varsize;
+	mtd->_read = cfi_staa_read;
+	mtd->_write = cfi_staa_write_buffers;
+	mtd->_writev = cfi_staa_writev;
+	mtd->_sync = cfi_staa_sync;
+	mtd->_lock = cfi_staa_lock;
+	mtd->_unlock = cfi_staa_unlock;
+	mtd->_suspend = cfi_staa_suspend;
+	mtd->_resume = cfi_staa_resume;
 	mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE;
 	mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
 	mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
@@ -394,8 +394,6 @@
 	chipnum = (from >> cfi->chipshift);
 	ofs = from - (chipnum <<  cfi->chipshift);
 
-	*retlen = 0;
-
 	while (len) {
 		unsigned long thislen;
 
@@ -617,10 +615,6 @@
 	int chipnum;
 	unsigned long ofs;
 
-	*retlen = 0;
-	if (!len)
-		return 0;
-
 	chipnum = to >> cfi->chipshift;
 	ofs = to  - (chipnum << cfi->chipshift);
 
@@ -904,12 +898,6 @@
 	int i, first;
 	struct mtd_erase_region_info *regions = mtd->eraseregions;
 
-	if (instr->addr > mtd->size)
-		return -EINVAL;
-
-	if ((instr->len + instr->addr) > mtd->size)
-		return -EINVAL;
-
 	/* Check that both start and end of the requested erase are
 	 * aligned with the erasesize at the appropriate addresses.
 	 */
@@ -1155,9 +1143,6 @@
 	if (len & (mtd->erasesize -1))
 		return -EINVAL;
 
-	if ((len + ofs) > mtd->size)
-		return -EINVAL;
-
 	chipnum = ofs >> cfi->chipshift;
 	adr = ofs - (chipnum << cfi->chipshift);
 
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c
index 8e46405..f992418 100644
--- a/drivers/mtd/chips/cfi_util.c
+++ b/drivers/mtd/chips/cfi_util.c
@@ -173,12 +173,6 @@
 	int i, first;
 	struct mtd_erase_region_info *regions = mtd->eraseregions;
 
-	if (ofs > mtd->size)
-		return -EINVAL;
-
-	if ((len + ofs) > mtd->size)
-		return -EINVAL;
-
 	/* Check that both start and end of the requested erase are
 	 * aligned with the erasesize at the appropriate addresses.
 	 */
diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h
index 89c6595..800b0e8 100644
--- a/drivers/mtd/chips/fwh_lock.h
+++ b/drivers/mtd/chips/fwh_lock.h
@@ -101,7 +101,7 @@
 {
 	printk(KERN_NOTICE "using fwh lock/unlock method\n");
 	/* Setup for the chips with the fwh lock method */
-	mtd->lock   = fwh_lock_varsize;
-	mtd->unlock = fwh_unlock_varsize;
+	mtd->_lock   = fwh_lock_varsize;
+	mtd->_unlock = fwh_unlock_varsize;
 }
 #endif /* FWH_LOCK_H */
diff --git a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c
index f2b8729..f7a5bca 100644
--- a/drivers/mtd/chips/map_absent.c
+++ b/drivers/mtd/chips/map_absent.c
@@ -55,10 +55,10 @@
 	mtd->name 	= map->name;
 	mtd->type 	= MTD_ABSENT;
 	mtd->size 	= map->size;
-	mtd->erase 	= map_absent_erase;
-	mtd->read 	= map_absent_read;
-	mtd->write 	= map_absent_write;
-	mtd->sync 	= map_absent_sync;
+	mtd->_erase 	= map_absent_erase;
+	mtd->_read 	= map_absent_read;
+	mtd->_write 	= map_absent_write;
+	mtd->_sync 	= map_absent_sync;
 	mtd->flags 	= 0;
 	mtd->erasesize  = PAGE_SIZE;
 	mtd->writesize  = 1;
@@ -70,13 +70,11 @@
 
 static int map_absent_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
 {
-	*retlen = 0;
 	return -ENODEV;
 }
 
 static int map_absent_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
 {
-	*retlen = 0;
 	return -ENODEV;
 }
 
diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c
index 67640cc..991c2a1 100644
--- a/drivers/mtd/chips/map_ram.c
+++ b/drivers/mtd/chips/map_ram.c
@@ -64,11 +64,11 @@
 	mtd->name = map->name;
 	mtd->type = MTD_RAM;
 	mtd->size = map->size;
-	mtd->erase = mapram_erase;
-	mtd->get_unmapped_area = mapram_unmapped_area;
-	mtd->read = mapram_read;
-	mtd->write = mapram_write;
-	mtd->sync = mapram_nop;
+	mtd->_erase = mapram_erase;
+	mtd->_get_unmapped_area = mapram_unmapped_area;
+	mtd->_read = mapram_read;
+	mtd->_write = mapram_write;
+	mtd->_sync = mapram_nop;
 	mtd->flags = MTD_CAP_RAM;
 	mtd->writesize = 1;
 
@@ -122,14 +122,10 @@
 	unsigned long i;
 
 	allff = map_word_ff(map);
-
 	for (i=0; i<instr->len; i += map_bankwidth(map))
 		map_write(map, allff, instr->addr + i);
-
 	instr->state = MTD_ERASE_DONE;
-
 	mtd_erase_callback(instr);
-
 	return 0;
 }
 
diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c
index 593f73d..47a43cf 100644
--- a/drivers/mtd/chips/map_rom.c
+++ b/drivers/mtd/chips/map_rom.c
@@ -41,11 +41,11 @@
 	mtd->name = map->name;
 	mtd->type = MTD_ROM;
 	mtd->size = map->size;
-	mtd->get_unmapped_area = maprom_unmapped_area;
-	mtd->read = maprom_read;
-	mtd->write = maprom_write;
-	mtd->sync = maprom_nop;
-	mtd->erase = maprom_erase;
+	mtd->_get_unmapped_area = maprom_unmapped_area;
+	mtd->_read = maprom_read;
+	mtd->_write = maprom_write;
+	mtd->_sync = maprom_nop;
+	mtd->_erase = maprom_erase;
 	mtd->flags = MTD_CAP_ROM;
 	mtd->erasesize = map->size;
 	mtd->writesize = 1;
@@ -85,8 +85,7 @@
 
 static int maprom_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
 {
-	printk(KERN_NOTICE "maprom_write called\n");
-	return -EIO;
+	return -EROFS;
 }
 
 static int maprom_erase (struct mtd_info *mtd, struct erase_info *info)
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 37b05c3..4cdb2af 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -1,5 +1,6 @@
 menu "Self-contained MTD device drivers"
 	depends on MTD!=n
+	depends on HAS_IOMEM
 
 config MTD_PMC551
 	tristate "Ramix PMC551 PCI Mezzanine RAM card support"
@@ -102,6 +103,13 @@
 	help
 	  This option enables FAST_READ access supported by ST M25Pxx.
 
+config MTD_SPEAR_SMI
+	tristate "SPEAR MTD NOR Support through SMI controller"
+	depends on PLAT_SPEAR
+	default y
+	help
+	  This enable SNOR support on SPEAR platforms using SMI controller
+
 config MTD_SST25L
 	tristate "Support SST25L (non JEDEC) SPI Flash chips"
 	depends on SPI_MASTER
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 56c7cd4..a4dd1d8 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -17,6 +17,7 @@
 obj-$(CONFIG_MTD_BLOCK2MTD)	+= block2mtd.o
 obj-$(CONFIG_MTD_DATAFLASH)	+= mtd_dataflash.o
 obj-$(CONFIG_MTD_M25P80)	+= m25p80.o
+obj-$(CONFIG_MTD_SPEAR_SMI)	+= spear_smi.o
 obj-$(CONFIG_MTD_SST25L)	+= sst25l.o
 
 CFLAGS_docg3.o			+= -I$(src)
\ No newline at end of file
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index e7e46d1..a4a80b7 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -104,14 +104,6 @@
 	int offset = from & (PAGE_SIZE-1);
 	int cpylen;
 
-	if (from > mtd->size)
-		return -EINVAL;
-	if (from + len > mtd->size)
-		len = mtd->size - from;
-
-	if (retlen)
-		*retlen = 0;
-
 	while (len) {
 		if ((offset + len) > PAGE_SIZE)
 			cpylen = PAGE_SIZE - offset;	// multiple pages
@@ -148,8 +140,6 @@
 	int offset = to & ~PAGE_MASK;	// page offset
 	int cpylen;
 
-	if (retlen)
-		*retlen = 0;
 	while (len) {
 		if ((offset+len) > PAGE_SIZE)
 			cpylen = PAGE_SIZE - offset;	// multiple pages
@@ -188,13 +178,6 @@
 	struct block2mtd_dev *dev = mtd->priv;
 	int err;
 
-	if (!len)
-		return 0;
-	if (to >= mtd->size)
-		return -ENOSPC;
-	if (to + len > mtd->size)
-		len = mtd->size - to;
-
 	mutex_lock(&dev->write_mutex);
 	err = _block2mtd_write(dev, buf, to, len, retlen);
 	mutex_unlock(&dev->write_mutex);
@@ -283,13 +266,14 @@
 	dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
 	dev->mtd.erasesize = erase_size;
 	dev->mtd.writesize = 1;
+	dev->mtd.writebufsize = PAGE_SIZE;
 	dev->mtd.type = MTD_RAM;
 	dev->mtd.flags = MTD_CAP_RAM;
-	dev->mtd.erase = block2mtd_erase;
-	dev->mtd.write = block2mtd_write;
-	dev->mtd.writev = mtd_writev;
-	dev->mtd.sync = block2mtd_sync;
-	dev->mtd.read = block2mtd_read;
+	dev->mtd._erase = block2mtd_erase;
+	dev->mtd._write = block2mtd_write;
+	dev->mtd._writev = mtd_writev;
+	dev->mtd._sync = block2mtd_sync;
+	dev->mtd._read = block2mtd_read;
 	dev->mtd.priv = dev;
 	dev->mtd.owner = THIS_MODULE;
 
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c
index b1cdf64..a4eb8b5 100644
--- a/drivers/mtd/devices/doc2000.c
+++ b/drivers/mtd/devices/doc2000.c
@@ -562,14 +562,15 @@
 
 	mtd->type = MTD_NANDFLASH;
 	mtd->flags = MTD_CAP_NANDFLASH;
-	mtd->writesize = 512;
+	mtd->writebufsize = mtd->writesize = 512;
 	mtd->oobsize = 16;
+	mtd->ecc_strength = 2;
 	mtd->owner = THIS_MODULE;
-	mtd->erase = doc_erase;
-	mtd->read = doc_read;
-	mtd->write = doc_write;
-	mtd->read_oob = doc_read_oob;
-	mtd->write_oob = doc_write_oob;
+	mtd->_erase = doc_erase;
+	mtd->_read = doc_read;
+	mtd->_write = doc_write;
+	mtd->_read_oob = doc_read_oob;
+	mtd->_write_oob = doc_write_oob;
 	this->curfloor = -1;
 	this->curchip = -1;
 	mutex_init(&this->lock);
@@ -602,13 +603,7 @@
 	int i, len256 = 0, ret=0;
 	size_t left = len;
 
-	/* Don't allow read past end of device */
-	if (from >= this->totlen)
-		return -EINVAL;
-
 	mutex_lock(&this->lock);
-
-	*retlen = 0;
 	while (left) {
 		len = left;
 
@@ -748,13 +743,7 @@
 	size_t left = len;
 	int status;
 
-	/* Don't allow write past end of device */
-	if (to >= this->totlen)
-		return -EINVAL;
-
 	mutex_lock(&this->lock);
-
-	*retlen = 0;
 	while (left) {
 		len = left;
 
diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c
index 7543b98..f692795 100644
--- a/drivers/mtd/devices/doc2001.c
+++ b/drivers/mtd/devices/doc2001.c
@@ -346,14 +346,15 @@
 
 	/* FIXME: erase size is not always 8KiB */
 	mtd->erasesize = 0x2000;
-	mtd->writesize = 512;
+	mtd->writebufsize = mtd->writesize = 512;
 	mtd->oobsize = 16;
+	mtd->ecc_strength = 2;
 	mtd->owner = THIS_MODULE;
-	mtd->erase = doc_erase;
-	mtd->read = doc_read;
-	mtd->write = doc_write;
-	mtd->read_oob = doc_read_oob;
-	mtd->write_oob = doc_write_oob;
+	mtd->_erase = doc_erase;
+	mtd->_read = doc_read;
+	mtd->_write = doc_write;
+	mtd->_read_oob = doc_read_oob;
+	mtd->_write_oob = doc_write_oob;
 	this->curfloor = -1;
 	this->curchip = -1;
 
@@ -383,10 +384,6 @@
 	void __iomem *docptr = this->virtadr;
 	struct Nand *mychip = &this->chips[from >> (this->chipshift)];
 
-	/* Don't allow read past end of device */
-	if (from >= this->totlen)
-		return -EINVAL;
-
 	/* Don't allow a single read to cross a 512-byte block boundary */
 	if (from + len > ((from | 0x1ff) + 1))
 		len = ((from | 0x1ff) + 1) - from;
@@ -494,10 +491,6 @@
 	void __iomem *docptr = this->virtadr;
 	struct Nand *mychip = &this->chips[to >> (this->chipshift)];
 
-	/* Don't allow write past end of device */
-	if (to >= this->totlen)
-		return -EINVAL;
-
 #if 0
 	/* Don't allow a single write to cross a 512-byte block boundary */
 	if (to + len > ( (to | 0x1ff) + 1))
@@ -599,7 +592,6 @@
 		printk("Error programming flash\n");
 		/* Error in programming
 		   FIXME: implement Bad Block Replacement (in nftl.c ??) */
-		*retlen = 0;
 		ret = -EIO;
 	}
 	dummy = ReadDOC(docptr, LastDataRead);
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c
index 177510d..04eb2e4 100644
--- a/drivers/mtd/devices/doc2001plus.c
+++ b/drivers/mtd/devices/doc2001plus.c
@@ -467,14 +467,15 @@
 
 	mtd->type = MTD_NANDFLASH;
 	mtd->flags = MTD_CAP_NANDFLASH;
-	mtd->writesize = 512;
+	mtd->writebufsize = mtd->writesize = 512;
 	mtd->oobsize = 16;
+	mtd->ecc_strength = 2;
 	mtd->owner = THIS_MODULE;
-	mtd->erase = doc_erase;
-	mtd->read = doc_read;
-	mtd->write = doc_write;
-	mtd->read_oob = doc_read_oob;
-	mtd->write_oob = doc_write_oob;
+	mtd->_erase = doc_erase;
+	mtd->_read = doc_read;
+	mtd->_write = doc_write;
+	mtd->_read_oob = doc_read_oob;
+	mtd->_write_oob = doc_write_oob;
 	this->curfloor = -1;
 	this->curchip = -1;
 
@@ -581,10 +582,6 @@
 	void __iomem * docptr = this->virtadr;
 	struct Nand *mychip = &this->chips[from >> (this->chipshift)];
 
-	/* Don't allow read past end of device */
-	if (from >= this->totlen)
-		return -EINVAL;
-
 	/* Don't allow a single read to cross a 512-byte block boundary */
 	if (from + len > ((from | 0x1ff) + 1))
 		len = ((from | 0x1ff) + 1) - from;
@@ -700,10 +697,6 @@
 	void __iomem * docptr = this->virtadr;
 	struct Nand *mychip = &this->chips[to >> (this->chipshift)];
 
-	/* Don't allow write past end of device */
-	if (to >= this->totlen)
-		return -EINVAL;
-
 	/* Don't allow writes which aren't exactly one block (512 bytes) */
 	if ((to & 0x1ff) || (len != 0x200))
 		return -EINVAL;
@@ -800,7 +793,6 @@
 		printk("MTD: Error 0x%x programming at 0x%x\n", dummy, (int)to);
 		/* Error in programming
 		   FIXME: implement Bad Block Replacement (in nftl.c ??) */
-		*retlen = 0;
 		ret = -EIO;
 	}
 	dummy = ReadDOC(docptr, Mplus_LastDataRead);
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index ad11ef0a..8272c02 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -80,14 +80,9 @@
 	.oobavail = 8,
 };
 
-/**
- * struct docg3_bch - BCH engine
- */
-static struct bch_control *docg3_bch;
-
 static inline u8 doc_readb(struct docg3 *docg3, u16 reg)
 {
-	u8 val = readb(docg3->base + reg);
+	u8 val = readb(docg3->cascade->base + reg);
 
 	trace_docg3_io(0, 8, reg, (int)val);
 	return val;
@@ -95,7 +90,7 @@
 
 static inline u16 doc_readw(struct docg3 *docg3, u16 reg)
 {
-	u16 val = readw(docg3->base + reg);
+	u16 val = readw(docg3->cascade->base + reg);
 
 	trace_docg3_io(0, 16, reg, (int)val);
 	return val;
@@ -103,13 +98,13 @@
 
 static inline void doc_writeb(struct docg3 *docg3, u8 val, u16 reg)
 {
-	writeb(val, docg3->base + reg);
+	writeb(val, docg3->cascade->base + reg);
 	trace_docg3_io(1, 8, reg, val);
 }
 
 static inline void doc_writew(struct docg3 *docg3, u16 val, u16 reg)
 {
-	writew(val, docg3->base + reg);
+	writew(val, docg3->cascade->base + reg);
 	trace_docg3_io(1, 16, reg, val);
 }
 
@@ -643,7 +638,8 @@
 
 	for (i = 0; i < DOC_ECC_BCH_SIZE; i++)
 		ecc[i] = bitrev8(hwecc[i]);
-	numerrs = decode_bch(docg3_bch, NULL, DOC_ECC_BCH_COVERED_BYTES,
+	numerrs = decode_bch(docg3->cascade->bch, NULL,
+			     DOC_ECC_BCH_COVERED_BYTES,
 			     NULL, ecc, NULL, errorpos);
 	BUG_ON(numerrs == -EINVAL);
 	if (numerrs < 0)
@@ -734,7 +730,7 @@
  * doc_read_page_getbytes - Reads bytes from a prepared page
  * @docg3: the device
  * @len: the number of bytes to be read (must be a multiple of 4)
- * @buf: the buffer to be filled in
+ * @buf: the buffer to be filled in (or NULL is forget bytes)
  * @first: 1 if first time read, DOC_READADDRESS should be set
  *
  */
@@ -849,7 +845,7 @@
 			struct mtd_oob_ops *ops)
 {
 	struct docg3 *docg3 = mtd->priv;
-	int block0, block1, page, ret, ofs = 0;
+	int block0, block1, page, ret, skip, ofs = 0;
 	u8 *oobbuf = ops->oobbuf;
 	u8 *buf = ops->datbuf;
 	size_t len, ooblen, nbdata, nboob;
@@ -869,34 +865,36 @@
 
 	doc_dbg("doc_read_oob(from=%lld, mode=%d, data=(%p:%zu), oob=(%p:%zu))\n",
 		from, ops->mode, buf, len, oobbuf, ooblen);
-	if ((len % DOC_LAYOUT_PAGE_SIZE) || (ooblen % DOC_LAYOUT_OOB_SIZE) ||
-	    (from % DOC_LAYOUT_PAGE_SIZE))
+	if (ooblen % DOC_LAYOUT_OOB_SIZE)
 		return -EINVAL;
 
-	ret = -EINVAL;
-	calc_block_sector(from + len, &block0, &block1, &page, &ofs,
-			  docg3->reliable);
-	if (block1 > docg3->max_block)
-		goto err;
+	if (from + len > mtd->size)
+		return -EINVAL;
 
 	ops->oobretlen = 0;
 	ops->retlen = 0;
 	ret = 0;
+	skip = from % DOC_LAYOUT_PAGE_SIZE;
+	mutex_lock(&docg3->cascade->lock);
 	while (!ret && (len > 0 || ooblen > 0)) {
-		calc_block_sector(from, &block0, &block1, &page, &ofs,
+		calc_block_sector(from - skip, &block0, &block1, &page, &ofs,
 			docg3->reliable);
-		nbdata = min_t(size_t, len, (size_t)DOC_LAYOUT_PAGE_SIZE);
+		nbdata = min_t(size_t, len, DOC_LAYOUT_PAGE_SIZE - skip);
 		nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE);
 		ret = doc_read_page_prepare(docg3, block0, block1, page, ofs);
 		if (ret < 0)
-			goto err;
+			goto out;
 		ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES);
 		if (ret < 0)
 			goto err_in_read;
-		ret = doc_read_page_getbytes(docg3, nbdata, buf, 1);
+		ret = doc_read_page_getbytes(docg3, skip, NULL, 1);
+		if (ret < skip)
+			goto err_in_read;
+		ret = doc_read_page_getbytes(docg3, nbdata, buf, 0);
 		if (ret < nbdata)
 			goto err_in_read;
-		doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE - nbdata,
+		doc_read_page_getbytes(docg3,
+				       DOC_LAYOUT_PAGE_SIZE - nbdata - skip,
 				       NULL, 0);
 		ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0);
 		if (ret < nboob)
@@ -950,13 +948,15 @@
 		len -= nbdata;
 		ooblen -= nboob;
 		from += DOC_LAYOUT_PAGE_SIZE;
+		skip = 0;
 	}
 
+out:
+	mutex_unlock(&docg3->cascade->lock);
 	return ret;
 err_in_read:
 	doc_read_page_finish(docg3);
-err:
-	return ret;
+	goto out;
 }
 
 /**
@@ -1114,10 +1114,10 @@
  */
 static int doc_write_erase_wait_status(struct docg3 *docg3)
 {
-	int status, ret = 0;
+	int i, status, ret = 0;
 
-	if (!doc_is_ready(docg3))
-		usleep_range(3000, 3000);
+	for (i = 0; !doc_is_ready(docg3) && i < 5; i++)
+		msleep(20);
 	if (!doc_is_ready(docg3)) {
 		doc_dbg("Timeout reached and the chip is still not ready\n");
 		ret = -EAGAIN;
@@ -1196,18 +1196,19 @@
 	int block0, block1, page, ret, ofs = 0;
 
 	doc_dbg("doc_erase(from=%lld, len=%lld\n", info->addr, info->len);
-	doc_set_device_id(docg3, docg3->device_id);
 
 	info->state = MTD_ERASE_PENDING;
 	calc_block_sector(info->addr + info->len, &block0, &block1, &page,
 			  &ofs, docg3->reliable);
 	ret = -EINVAL;
-	if (block1 > docg3->max_block || page || ofs)
+	if (info->addr + info->len > mtd->size || page || ofs)
 		goto reset_err;
 
 	ret = 0;
 	calc_block_sector(info->addr, &block0, &block1, &page, &ofs,
 			  docg3->reliable);
+	mutex_lock(&docg3->cascade->lock);
+	doc_set_device_id(docg3, docg3->device_id);
 	doc_set_reliable_mode(docg3);
 	for (len = info->len; !ret && len > 0; len -= mtd->erasesize) {
 		info->state = MTD_ERASING;
@@ -1215,6 +1216,7 @@
 		block0 += 2;
 		block1 += 2;
 	}
+	mutex_unlock(&docg3->cascade->lock);
 
 	if (ret)
 		goto reset_err;
@@ -1401,7 +1403,7 @@
 			 struct mtd_oob_ops *ops)
 {
 	struct docg3 *docg3 = mtd->priv;
-	int block0, block1, page, ret, pofs = 0, autoecc, oobdelta;
+	int ret, autoecc, oobdelta;
 	u8 *oobbuf = ops->oobbuf;
 	u8 *buf = ops->datbuf;
 	size_t len, ooblen;
@@ -1438,12 +1440,8 @@
 	if (len && ooblen &&
 	    (len / DOC_LAYOUT_PAGE_SIZE) != (ooblen / oobdelta))
 		return -EINVAL;
-
-	ret = -EINVAL;
-	calc_block_sector(ofs + len, &block0, &block1, &page, &pofs,
-			  docg3->reliable);
-	if (block1 > docg3->max_block)
-		goto err;
+	if (ofs + len > mtd->size)
+		return -EINVAL;
 
 	ops->oobretlen = 0;
 	ops->retlen = 0;
@@ -1457,6 +1455,7 @@
 	if (autoecc < 0)
 		return autoecc;
 
+	mutex_lock(&docg3->cascade->lock);
 	while (!ret && len > 0) {
 		memset(oob, 0, sizeof(oob));
 		if (ofs == docg3->oob_write_ofs)
@@ -1477,8 +1476,9 @@
 		}
 		ops->retlen += DOC_LAYOUT_PAGE_SIZE;
 	}
-err:
+
 	doc_set_device_id(docg3, 0);
+	mutex_unlock(&docg3->cascade->lock);
 	return ret;
 }
 
@@ -1535,9 +1535,11 @@
 	struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
 	int dps0;
 
+	mutex_lock(&docg3->cascade->lock);
 	doc_set_device_id(docg3, docg3->device_id);
 	dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS);
 	doc_set_device_id(docg3, 0);
+	mutex_unlock(&docg3->cascade->lock);
 
 	return sprintf(buf, "%d\n", !(dps0 & DOC_DPS_KEY_OK));
 }
@@ -1548,9 +1550,11 @@
 	struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
 	int dps1;
 
+	mutex_lock(&docg3->cascade->lock);
 	doc_set_device_id(docg3, docg3->device_id);
 	dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS);
 	doc_set_device_id(docg3, 0);
+	mutex_unlock(&docg3->cascade->lock);
 
 	return sprintf(buf, "%d\n", !(dps1 & DOC_DPS_KEY_OK));
 }
@@ -1565,10 +1569,12 @@
 	if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
 		return -EINVAL;
 
+	mutex_lock(&docg3->cascade->lock);
 	doc_set_device_id(docg3, docg3->device_id);
 	for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
 		doc_writeb(docg3, buf[i], DOC_DPS0_KEY);
 	doc_set_device_id(docg3, 0);
+	mutex_unlock(&docg3->cascade->lock);
 	return count;
 }
 
@@ -1582,10 +1588,12 @@
 	if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
 		return -EINVAL;
 
+	mutex_lock(&docg3->cascade->lock);
 	doc_set_device_id(docg3, docg3->device_id);
 	for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
 		doc_writeb(docg3, buf[i], DOC_DPS1_KEY);
 	doc_set_device_id(docg3, 0);
+	mutex_unlock(&docg3->cascade->lock);
 	return count;
 }
 
@@ -1601,13 +1609,13 @@
 };
 
 static int doc_register_sysfs(struct platform_device *pdev,
-			      struct mtd_info **floors)
+			      struct docg3_cascade *cascade)
 {
 	int ret = 0, floor, i = 0;
 	struct device *dev = &pdev->dev;
 
-	for (floor = 0; !ret && floor < DOC_MAX_NBFLOORS && floors[floor];
-	     floor++)
+	for (floor = 0; !ret && floor < DOC_MAX_NBFLOORS &&
+		     cascade->floors[floor]; floor++)
 		for (i = 0; !ret && i < 4; i++)
 			ret = device_create_file(dev, &doc_sys_attrs[floor][i]);
 	if (!ret)
@@ -1621,12 +1629,12 @@
 }
 
 static void doc_unregister_sysfs(struct platform_device *pdev,
-				 struct mtd_info **floors)
+				 struct docg3_cascade *cascade)
 {
 	struct device *dev = &pdev->dev;
 	int floor, i;
 
-	for (floor = 0; floor < DOC_MAX_NBFLOORS && floors[floor];
+	for (floor = 0; floor < DOC_MAX_NBFLOORS && cascade->floors[floor];
 	     floor++)
 		for (i = 0; i < 4; i++)
 			device_remove_file(dev, &doc_sys_attrs[floor][i]);
@@ -1640,7 +1648,11 @@
 	struct docg3 *docg3 = (struct docg3 *)s->private;
 
 	int pos = 0;
-	u8 fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL);
+	u8 fctrl;
+
+	mutex_lock(&docg3->cascade->lock);
+	fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL);
+	mutex_unlock(&docg3->cascade->lock);
 
 	pos += seq_printf(s,
 		 "FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n",
@@ -1658,9 +1670,12 @@
 {
 	struct docg3 *docg3 = (struct docg3 *)s->private;
 
-	int pos = 0;
-	int pctrl = doc_register_readb(docg3, DOC_ASICMODE);
-	int mode = pctrl & 0x03;
+	int pos = 0, pctrl, mode;
+
+	mutex_lock(&docg3->cascade->lock);
+	pctrl = doc_register_readb(docg3, DOC_ASICMODE);
+	mode = pctrl & 0x03;
+	mutex_unlock(&docg3->cascade->lock);
 
 	pos += seq_printf(s,
 			 "%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (",
@@ -1692,7 +1707,11 @@
 {
 	struct docg3 *docg3 = (struct docg3 *)s->private;
 	int pos = 0;
-	int id = doc_register_readb(docg3, DOC_DEVICESELECT);
+	int id;
+
+	mutex_lock(&docg3->cascade->lock);
+	id = doc_register_readb(docg3, DOC_DEVICESELECT);
+	mutex_unlock(&docg3->cascade->lock);
 
 	pos += seq_printf(s, "DeviceId = %d\n", id);
 	return pos;
@@ -1705,6 +1724,7 @@
 	int pos = 0;
 	int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high;
 
+	mutex_lock(&docg3->cascade->lock);
 	protect = doc_register_readb(docg3, DOC_PROTECTION);
 	dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS);
 	dps0_low = doc_register_readw(docg3, DOC_DPS0_ADDRLOW);
@@ -1712,6 +1732,7 @@
 	dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS);
 	dps1_low = doc_register_readw(docg3, DOC_DPS1_ADDRLOW);
 	dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH);
+	mutex_unlock(&docg3->cascade->lock);
 
 	pos += seq_printf(s, "Protection = 0x%02x (",
 			 protect);
@@ -1804,7 +1825,7 @@
 
 	switch (chip_id) {
 	case DOC_CHIPID_G3:
-		mtd->name = kasprintf(GFP_KERNEL, "DiskOnChip G3 floor %d",
+		mtd->name = kasprintf(GFP_KERNEL, "docg3.%d",
 				      docg3->device_id);
 		docg3->max_block = 2047;
 		break;
@@ -1817,16 +1838,17 @@
 	mtd->erasesize = DOC_LAYOUT_BLOCK_SIZE * DOC_LAYOUT_NBPLANES;
 	if (docg3->reliable == 2)
 		mtd->erasesize /= 2;
-	mtd->writesize = DOC_LAYOUT_PAGE_SIZE;
+	mtd->writebufsize = mtd->writesize = DOC_LAYOUT_PAGE_SIZE;
 	mtd->oobsize = DOC_LAYOUT_OOB_SIZE;
 	mtd->owner = THIS_MODULE;
-	mtd->erase = doc_erase;
-	mtd->read = doc_read;
-	mtd->write = doc_write;
-	mtd->read_oob = doc_read_oob;
-	mtd->write_oob = doc_write_oob;
-	mtd->block_isbad = doc_block_isbad;
+	mtd->_erase = doc_erase;
+	mtd->_read = doc_read;
+	mtd->_write = doc_write;
+	mtd->_read_oob = doc_read_oob;
+	mtd->_write_oob = doc_write_oob;
+	mtd->_block_isbad = doc_block_isbad;
 	mtd->ecclayout = &docg3_oobinfo;
+	mtd->ecc_strength = DOC_ECC_BCH_T;
 }
 
 /**
@@ -1834,6 +1856,7 @@
  * @base: the io space where the device is probed
  * @floor: the floor of the probed device
  * @dev: the device
+ * @cascade: the cascade of chips this devices will belong to
  *
  * Checks whether a device at the specified IO range, and floor is available.
  *
@@ -1841,8 +1864,8 @@
  * if a memory allocation failed. If floor 0 is checked, a reset of the ASIC is
  * launched.
  */
-static struct mtd_info *doc_probe_device(void __iomem *base, int floor,
-					 struct device *dev)
+static struct mtd_info * __init
+doc_probe_device(struct docg3_cascade *cascade, int floor, struct device *dev)
 {
 	int ret, bbt_nbpages;
 	u16 chip_id, chip_id_inv;
@@ -1865,7 +1888,7 @@
 
 	docg3->dev = dev;
 	docg3->device_id = floor;
-	docg3->base = base;
+	docg3->cascade = cascade;
 	doc_set_device_id(docg3, docg3->device_id);
 	if (!floor)
 		doc_set_asic_mode(docg3, DOC_ASICMODE_RESET);
@@ -1882,7 +1905,7 @@
 	switch (chip_id) {
 	case DOC_CHIPID_G3:
 		doc_info("Found a G3 DiskOnChip at addr %p, floor %d\n",
-			 base, floor);
+			 docg3->cascade->base, floor);
 		break;
 	default:
 		doc_err("Chip id %04x is not a DiskOnChip G3 chip\n", chip_id);
@@ -1927,10 +1950,12 @@
 static int docg3_resume(struct platform_device *pdev)
 {
 	int i;
+	struct docg3_cascade *cascade;
 	struct mtd_info **docg3_floors, *mtd;
 	struct docg3 *docg3;
 
-	docg3_floors = platform_get_drvdata(pdev);
+	cascade = platform_get_drvdata(pdev);
+	docg3_floors = cascade->floors;
 	mtd = docg3_floors[0];
 	docg3 = mtd->priv;
 
@@ -1952,11 +1977,13 @@
 static int docg3_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	int floor, i;
+	struct docg3_cascade *cascade;
 	struct mtd_info **docg3_floors, *mtd;
 	struct docg3 *docg3;
 	u8 ctrl, pwr_down;
 
-	docg3_floors = platform_get_drvdata(pdev);
+	cascade = platform_get_drvdata(pdev);
+	docg3_floors = cascade->floors;
 	for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) {
 		mtd = docg3_floors[floor];
 		if (!mtd)
@@ -2006,7 +2033,7 @@
 	struct resource *ress;
 	void __iomem *base;
 	int ret, floor, found = 0;
-	struct mtd_info **docg3_floors;
+	struct docg3_cascade *cascade;
 
 	ret = -ENXIO;
 	ress = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -2017,17 +2044,19 @@
 	base = ioremap(ress->start, DOC_IOSPACE_SIZE);
 
 	ret = -ENOMEM;
-	docg3_floors = kzalloc(sizeof(*docg3_floors) * DOC_MAX_NBFLOORS,
-			       GFP_KERNEL);
-	if (!docg3_floors)
+	cascade = kzalloc(sizeof(*cascade) * DOC_MAX_NBFLOORS,
+			  GFP_KERNEL);
+	if (!cascade)
 		goto nomem1;
-	docg3_bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T,
+	cascade->base = base;
+	mutex_init(&cascade->lock);
+	cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T,
 			     DOC_ECC_BCH_PRIMPOLY);
-	if (!docg3_bch)
+	if (!cascade->bch)
 		goto nomem2;
 
 	for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) {
-		mtd = doc_probe_device(base, floor, dev);
+		mtd = doc_probe_device(cascade, floor, dev);
 		if (IS_ERR(mtd)) {
 			ret = PTR_ERR(mtd);
 			goto err_probe;
@@ -2038,7 +2067,7 @@
 			else
 				continue;
 		}
-		docg3_floors[floor] = mtd;
+		cascade->floors[floor] = mtd;
 		ret = mtd_device_parse_register(mtd, part_probes, NULL, NULL,
 						0);
 		if (ret)
@@ -2046,26 +2075,26 @@
 		found++;
 	}
 
-	ret = doc_register_sysfs(pdev, docg3_floors);
+	ret = doc_register_sysfs(pdev, cascade);
 	if (ret)
 		goto err_probe;
 	if (!found)
 		goto notfound;
 
-	platform_set_drvdata(pdev, docg3_floors);
-	doc_dbg_register(docg3_floors[0]->priv);
+	platform_set_drvdata(pdev, cascade);
+	doc_dbg_register(cascade->floors[0]->priv);
 	return 0;
 
 notfound:
 	ret = -ENODEV;
 	dev_info(dev, "No supported DiskOnChip found\n");
 err_probe:
-	free_bch(docg3_bch);
+	kfree(cascade->bch);
 	for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
-		if (docg3_floors[floor])
-			doc_release_device(docg3_floors[floor]);
+		if (cascade->floors[floor])
+			doc_release_device(cascade->floors[floor]);
 nomem2:
-	kfree(docg3_floors);
+	kfree(cascade);
 nomem1:
 	iounmap(base);
 noress:
@@ -2080,19 +2109,19 @@
  */
 static int __exit docg3_release(struct platform_device *pdev)
 {
-	struct mtd_info **docg3_floors = platform_get_drvdata(pdev);
-	struct docg3 *docg3 = docg3_floors[0]->priv;
-	void __iomem *base = docg3->base;
+	struct docg3_cascade *cascade = platform_get_drvdata(pdev);
+	struct docg3 *docg3 = cascade->floors[0]->priv;
+	void __iomem *base = cascade->base;
 	int floor;
 
-	doc_unregister_sysfs(pdev, docg3_floors);
+	doc_unregister_sysfs(pdev, cascade);
 	doc_dbg_unregister(docg3);
 	for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
-		if (docg3_floors[floor])
-			doc_release_device(docg3_floors[floor]);
+		if (cascade->floors[floor])
+			doc_release_device(cascade->floors[floor]);
 
-	kfree(docg3_floors);
-	free_bch(docg3_bch);
+	free_bch(docg3->cascade->bch);
+	kfree(cascade);
 	iounmap(base);
 	return 0;
 }
diff --git a/drivers/mtd/devices/docg3.h b/drivers/mtd/devices/docg3.h
index db0da43..19fb93f 100644
--- a/drivers/mtd/devices/docg3.h
+++ b/drivers/mtd/devices/docg3.h
@@ -22,6 +22,8 @@
 #ifndef _MTD_DOCG3_H
 #define _MTD_DOCG3_H
 
+#include <linux/mtd/mtd.h>
+
 /*
  * Flash memory areas :
  *   - 0x0000 .. 0x07ff : IPL
@@ -267,9 +269,23 @@
 #define DOC_LAYOUT_DPS_KEY_LENGTH	8
 
 /**
+ * struct docg3_cascade - Cascade of 1 to 4 docg3 chips
+ * @floors: floors (ie. one physical docg3 chip is one floor)
+ * @base: IO space to access all chips in the cascade
+ * @bch: the BCH correcting control structure
+ * @lock: lock to protect docg3 IO space from concurrent accesses
+ */
+struct docg3_cascade {
+	struct mtd_info *floors[DOC_MAX_NBFLOORS];
+	void __iomem *base;
+	struct bch_control *bch;
+	struct mutex lock;
+};
+
+/**
  * struct docg3 - DiskOnChip driver private data
  * @dev: the device currently under control
- * @base: mapped IO space
+ * @cascade: the cascade this device belongs to
  * @device_id: number of the cascaded DoCG3 device (0, 1, 2 or 3)
  * @if_cfg: if true, reads are on 16bits, else reads are on 8bits
 
@@ -287,7 +303,7 @@
  */
 struct docg3 {
 	struct device *dev;
-	void __iomem *base;
+	struct docg3_cascade *cascade;
 	unsigned int device_id:4;
 	unsigned int if_cfg:1;
 	unsigned int reliable:2;
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c
index 3a11ea6..82bd00a 100644
--- a/drivers/mtd/devices/lart.c
+++ b/drivers/mtd/devices/lart.c
@@ -367,9 +367,6 @@
    printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n", __func__, instr->addr, instr->len);
 #endif
 
-   /* sanity checks */
-   if (instr->addr + instr->len > mtd->size) return (-EINVAL);
-
    /*
 	* check that both start and end of the requested erase are
 	* aligned with the erasesize at the appropriate addresses.
@@ -440,10 +437,6 @@
    printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n", __func__, (__u32)from, len);
 #endif
 
-   /* sanity checks */
-   if (!len) return (0);
-   if (from + len > mtd->size) return (-EINVAL);
-
    /* we always read len bytes */
    *retlen = len;
 
@@ -522,11 +515,8 @@
    printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n", __func__, (__u32)to, len);
 #endif
 
-   *retlen = 0;
-
    /* sanity checks */
    if (!len) return (0);
-   if (to + len > mtd->size) return (-EINVAL);
 
    /* first, we write a 0xFF.... padded byte until we reach a dword boundary */
    if (to & (BUSWIDTH - 1))
@@ -630,14 +620,15 @@
    mtd.name = module_name;
    mtd.type = MTD_NORFLASH;
    mtd.writesize = 1;
+   mtd.writebufsize = 4;
    mtd.flags = MTD_CAP_NORFLASH;
    mtd.size = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM + FLASH_BLOCKSIZE_MAIN * FLASH_NUMBLOCKS_16m_MAIN;
    mtd.erasesize = FLASH_BLOCKSIZE_MAIN;
    mtd.numeraseregions = ARRAY_SIZE(erase_regions);
    mtd.eraseregions = erase_regions;
-   mtd.erase = flash_erase;
-   mtd.read = flash_read;
-   mtd.write = flash_write;
+   mtd._erase = flash_erase;
+   mtd._read = flash_read;
+   mtd._write = flash_write;
    mtd.owner = THIS_MODULE;
 
 #ifdef LART_DEBUG
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 7c60ddd..1924d24 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -288,9 +288,6 @@
 			__func__, (long long)instr->addr,
 			(long long)instr->len);
 
-	/* sanity checks */
-	if (instr->addr + instr->len > flash->mtd.size)
-		return -EINVAL;
 	div_u64_rem(instr->len, mtd->erasesize, &rem);
 	if (rem)
 		return -EINVAL;
@@ -349,13 +346,6 @@
 	pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
 			__func__, (u32)from, len);
 
-	/* sanity checks */
-	if (!len)
-		return 0;
-
-	if (from + len > flash->mtd.size)
-		return -EINVAL;
-
 	spi_message_init(&m);
 	memset(t, 0, (sizeof t));
 
@@ -371,9 +361,6 @@
 	t[1].len = len;
 	spi_message_add_tail(&t[1], &m);
 
-	/* Byte count starts at zero. */
-	*retlen = 0;
-
 	mutex_lock(&flash->lock);
 
 	/* Wait till previous write/erase is done. */
@@ -417,15 +404,6 @@
 	pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
 			__func__, (u32)to, len);
 
-	*retlen = 0;
-
-	/* sanity checks */
-	if (!len)
-		return(0);
-
-	if (to + len > flash->mtd.size)
-		return -EINVAL;
-
 	spi_message_init(&m);
 	memset(t, 0, (sizeof t));
 
@@ -509,15 +487,6 @@
 	pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
 			__func__, (u32)to, len);
 
-	*retlen = 0;
-
-	/* sanity checks */
-	if (!len)
-		return 0;
-
-	if (to + len > flash->mtd.size)
-		return -EINVAL;
-
 	spi_message_init(&m);
 	memset(t, 0, (sizeof t));
 
@@ -908,14 +877,14 @@
 	flash->mtd.writesize = 1;
 	flash->mtd.flags = MTD_CAP_NORFLASH;
 	flash->mtd.size = info->sector_size * info->n_sectors;
-	flash->mtd.erase = m25p80_erase;
-	flash->mtd.read = m25p80_read;
+	flash->mtd._erase = m25p80_erase;
+	flash->mtd._read = m25p80_read;
 
 	/* sst flash chips use AAI word program */
 	if (JEDEC_MFR(info->jedec_id) == CFI_MFR_SST)
-		flash->mtd.write = sst_write;
+		flash->mtd._write = sst_write;
 	else
-		flash->mtd.write = m25p80_write;
+		flash->mtd._write = m25p80_write;
 
 	/* prefer "small sector" erase if possible */
 	if (info->flags & SECT_4K) {
@@ -932,6 +901,7 @@
 	ppdata.of_node = spi->dev.of_node;
 	flash->mtd.dev.parent = &spi->dev;
 	flash->page_size = info->page_size;
+	flash->mtd.writebufsize = flash->page_size;
 
 	if (info->addr_width)
 		flash->addr_width = info->addr_width;
@@ -1004,21 +974,7 @@
 	 */
 };
 
-
-static int __init m25p80_init(void)
-{
-	return spi_register_driver(&m25p80_driver);
-}
-
-
-static void __exit m25p80_exit(void)
-{
-	spi_unregister_driver(&m25p80_driver);
-}
-
-
-module_init(m25p80_init);
-module_exit(m25p80_exit);
+module_spi_driver(m25p80_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Mike Lavender");
diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c
index 8423fb6..182849d 100644
--- a/drivers/mtd/devices/ms02-nv.c
+++ b/drivers/mtd/devices/ms02-nv.c
@@ -59,12 +59,8 @@
 {
 	struct ms02nv_private *mp = mtd->priv;
 
-	if (from + len > mtd->size)
-		return -EINVAL;
-
 	memcpy(buf, mp->uaddr + from, len);
 	*retlen = len;
-
 	return 0;
 }
 
@@ -73,12 +69,8 @@
 {
 	struct ms02nv_private *mp = mtd->priv;
 
-	if (to + len > mtd->size)
-		return -EINVAL;
-
 	memcpy(mp->uaddr + to, buf, len);
 	*retlen = len;
-
 	return 0;
 }
 
@@ -215,8 +207,8 @@
 	mtd->size = fixsize;
 	mtd->name = (char *)ms02nv_name;
 	mtd->owner = THIS_MODULE;
-	mtd->read = ms02nv_read;
-	mtd->write = ms02nv_write;
+	mtd->_read = ms02nv_read;
+	mtd->_write = ms02nv_write;
 	mtd->writesize = 1;
 
 	ret = -EIO;
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index 236057e..928fb0e 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -164,9 +164,6 @@
 	      dev_name(&spi->dev), (long long)instr->addr,
 	      (long long)instr->len);
 
-	/* Sanity checks */
-	if (instr->addr + instr->len > mtd->size)
-		return -EINVAL;
 	div_u64_rem(instr->len, priv->page_size, &rem);
 	if (rem)
 		return -EINVAL;
@@ -252,14 +249,6 @@
 	pr_debug("%s: read 0x%x..0x%x\n", dev_name(&priv->spi->dev),
 			(unsigned)from, (unsigned)(from + len));
 
-	*retlen = 0;
-
-	/* Sanity checks */
-	if (!len)
-		return 0;
-	if (from + len > mtd->size)
-		return -EINVAL;
-
 	/* Calculate flash page/byte address */
 	addr = (((unsigned)from / priv->page_size) << priv->page_offset)
 		+ ((unsigned)from % priv->page_size);
@@ -328,14 +317,6 @@
 	pr_debug("%s: write 0x%x..0x%x\n",
 		dev_name(&spi->dev), (unsigned)to, (unsigned)(to + len));
 
-	*retlen = 0;
-
-	/* Sanity checks */
-	if (!len)
-		return 0;
-	if ((to + len) > mtd->size)
-		return -EINVAL;
-
 	spi_message_init(&msg);
 
 	x[0].tx_buf = command = priv->command;
@@ -490,8 +471,6 @@
 
 	if ((off + len) > 64)
 		len = 64 - off;
-	if (len == 0)
-		return len;
 
 	spi_message_init(&m);
 
@@ -611,16 +590,16 @@
 
 static char *otp_setup(struct mtd_info *device, char revision)
 {
-	device->get_fact_prot_info = dataflash_get_otp_info;
-	device->read_fact_prot_reg = dataflash_read_fact_otp;
-	device->get_user_prot_info = dataflash_get_otp_info;
-	device->read_user_prot_reg = dataflash_read_user_otp;
+	device->_get_fact_prot_info = dataflash_get_otp_info;
+	device->_read_fact_prot_reg = dataflash_read_fact_otp;
+	device->_get_user_prot_info = dataflash_get_otp_info;
+	device->_read_user_prot_reg = dataflash_read_user_otp;
 
 	/* rev c parts (at45db321c and at45db1281 only!) use a
 	 * different write procedure; not (yet?) implemented.
 	 */
 	if (revision > 'c')
-		device->write_user_prot_reg = dataflash_write_user_otp;
+		device->_write_user_prot_reg = dataflash_write_user_otp;
 
 	return ", OTP";
 }
@@ -672,9 +651,9 @@
 	device->owner = THIS_MODULE;
 	device->type = MTD_DATAFLASH;
 	device->flags = MTD_WRITEABLE;
-	device->erase = dataflash_erase;
-	device->read = dataflash_read;
-	device->write = dataflash_write;
+	device->_erase = dataflash_erase;
+	device->_read = dataflash_read;
+	device->_write = dataflash_write;
 	device->priv = priv;
 
 	device->dev.parent = &spi->dev;
@@ -946,18 +925,7 @@
 	/* FIXME:  investigate suspend and resume... */
 };
 
-static int __init dataflash_init(void)
-{
-	return spi_register_driver(&dataflash_driver);
-}
-module_init(dataflash_init);
-
-static void __exit dataflash_exit(void)
-{
-	spi_unregister_driver(&dataflash_driver);
-}
-module_exit(dataflash_exit);
-
+module_spi_driver(dataflash_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Andrew Victor, David Brownell");
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c
index 2562689..ec59d65 100644
--- a/drivers/mtd/devices/mtdram.c
+++ b/drivers/mtd/devices/mtdram.c
@@ -34,34 +34,23 @@
 
 static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
-	if (instr->addr + instr->len > mtd->size)
-		return -EINVAL;
-
 	memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
-
 	instr->state = MTD_ERASE_DONE;
 	mtd_erase_callback(instr);
-
 	return 0;
 }
 
 static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
 		size_t *retlen, void **virt, resource_size_t *phys)
 {
-	if (from + len > mtd->size)
-		return -EINVAL;
-
-	/* can we return a physical address with this driver? */
-	if (phys)
-		return -EINVAL;
-
 	*virt = mtd->priv + from;
 	*retlen = len;
 	return 0;
 }
 
-static void ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
+static int ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
+	return 0;
 }
 
 /*
@@ -80,11 +69,7 @@
 static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
 		size_t *retlen, u_char *buf)
 {
-	if (from + len > mtd->size)
-		return -EINVAL;
-
 	memcpy(buf, mtd->priv + from, len);
-
 	*retlen = len;
 	return 0;
 }
@@ -92,11 +77,7 @@
 static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
 		size_t *retlen, const u_char *buf)
 {
-	if (to + len > mtd->size)
-		return -EINVAL;
-
 	memcpy((char *)mtd->priv + to, buf, len);
-
 	*retlen = len;
 	return 0;
 }
@@ -126,12 +107,12 @@
 	mtd->priv = mapped_address;
 
 	mtd->owner = THIS_MODULE;
-	mtd->erase = ram_erase;
-	mtd->point = ram_point;
-	mtd->unpoint = ram_unpoint;
-	mtd->get_unmapped_area = ram_get_unmapped_area;
-	mtd->read = ram_read;
-	mtd->write = ram_write;
+	mtd->_erase = ram_erase;
+	mtd->_point = ram_point;
+	mtd->_unpoint = ram_unpoint;
+	mtd->_get_unmapped_area = ram_get_unmapped_area;
+	mtd->_read = ram_read;
+	mtd->_write = ram_write;
 
 	if (mtd_device_register(mtd, NULL, 0))
 		return -EIO;
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 23423bd..67823de 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -33,45 +33,33 @@
 
 static LIST_HEAD(phram_list);
 
-
 static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
 	u_char *start = mtd->priv;
 
-	if (instr->addr + instr->len > mtd->size)
-		return -EINVAL;
-
 	memset(start + instr->addr, 0xff, instr->len);
 
-	/* This'll catch a few races. Free the thing before returning :)
+	/*
+	 * This'll catch a few races. Free the thing before returning :)
 	 * I don't feel at all ashamed. This kind of thing is possible anyway
 	 * with flash, but unlikely.
 	 */
-
 	instr->state = MTD_ERASE_DONE;
-
 	mtd_erase_callback(instr);
-
 	return 0;
 }
 
 static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
 		size_t *retlen, void **virt, resource_size_t *phys)
 {
-	if (from + len > mtd->size)
-		return -EINVAL;
-
-	/* can we return a physical address with this driver? */
-	if (phys)
-		return -EINVAL;
-
 	*virt = mtd->priv + from;
 	*retlen = len;
 	return 0;
 }
 
-static void phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
+static int phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
+	return 0;
 }
 
 static int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
@@ -79,14 +67,7 @@
 {
 	u_char *start = mtd->priv;
 
-	if (from >= mtd->size)
-		return -EINVAL;
-
-	if (len > mtd->size - from)
-		len = mtd->size - from;
-
 	memcpy(buf, start + from, len);
-
 	*retlen = len;
 	return 0;
 }
@@ -96,20 +77,11 @@
 {
 	u_char *start = mtd->priv;
 
-	if (to >= mtd->size)
-		return -EINVAL;
-
-	if (len > mtd->size - to)
-		len = mtd->size - to;
-
 	memcpy(start + to, buf, len);
-
 	*retlen = len;
 	return 0;
 }
 
-
-
 static void unregister_devices(void)
 {
 	struct phram_mtd_list *this, *safe;
@@ -142,11 +114,11 @@
 	new->mtd.name = name;
 	new->mtd.size = len;
 	new->mtd.flags = MTD_CAP_RAM;
-        new->mtd.erase = phram_erase;
-	new->mtd.point = phram_point;
-	new->mtd.unpoint = phram_unpoint;
-	new->mtd.read = phram_read;
-	new->mtd.write = phram_write;
+	new->mtd._erase = phram_erase;
+	new->mtd._point = phram_point;
+	new->mtd._unpoint = phram_unpoint;
+	new->mtd._read = phram_read;
+	new->mtd._write = phram_write;
 	new->mtd.owner = THIS_MODULE;
 	new->mtd.type = MTD_RAM;
 	new->mtd.erasesize = PAGE_SIZE;
@@ -233,7 +205,17 @@
 	return 1;		\
 } while (0)
 
-static int phram_setup(const char *val, struct kernel_param *kp)
+/*
+ * This shall contain the module parameter if any. It is of the form:
+ * - phram=<device>,<address>,<size> for module case
+ * - phram.phram=<device>,<address>,<size> for built-in case
+ * We leave 64 bytes for the device name, 12 for the address and 12 for the
+ * size.
+ * Example: phram.phram=rootfs,0xa0000000,512Mi
+ */
+static __initdata char phram_paramline[64+12+12];
+
+static int __init phram_setup(const char *val)
 {
 	char buf[64+12+12], *str = buf;
 	char *token[3];
@@ -282,12 +264,28 @@
 	return ret;
 }
 
-module_param_call(phram, phram_setup, NULL, NULL, 000);
+static int __init phram_param_call(const char *val, struct kernel_param *kp)
+{
+	/*
+	 * This function is always called before 'init_phram()', whether
+	 * built-in or module.
+	 */
+	if (strlen(val) >= sizeof(phram_paramline))
+		return -ENOSPC;
+	strcpy(phram_paramline, val);
+
+	return 0;
+}
+
+module_param_call(phram, phram_param_call, NULL, NULL, 000);
 MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>\"");
 
 
 static int __init init_phram(void)
 {
+	if (phram_paramline[0])
+		return phram_setup(phram_paramline);
+
 	return 0;
 }
 
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
index ecff765..0c51b98 100644
--- a/drivers/mtd/devices/pmc551.c
+++ b/drivers/mtd/devices/pmc551.c
@@ -93,14 +93,49 @@
 #include <linux/fs.h>
 #include <linux/ioctl.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <linux/pci.h>
-
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/pmc551.h>
+
+#define PMC551_VERSION \
+	"Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n"
+
+#define PCI_VENDOR_ID_V3_SEMI 0x11b0
+#define PCI_DEVICE_ID_V3_SEMI_V370PDC 0x0200
+
+#define PMC551_PCI_MEM_MAP0 0x50
+#define PMC551_PCI_MEM_MAP1 0x54
+#define PMC551_PCI_MEM_MAP_MAP_ADDR_MASK 0x3ff00000
+#define PMC551_PCI_MEM_MAP_APERTURE_MASK 0x000000f0
+#define PMC551_PCI_MEM_MAP_REG_EN 0x00000002
+#define PMC551_PCI_MEM_MAP_ENABLE 0x00000001
+
+#define PMC551_SDRAM_MA  0x60
+#define PMC551_SDRAM_CMD 0x62
+#define PMC551_DRAM_CFG  0x64
+#define PMC551_SYS_CTRL_REG 0x78
+
+#define PMC551_DRAM_BLK0 0x68
+#define PMC551_DRAM_BLK1 0x6c
+#define PMC551_DRAM_BLK2 0x70
+#define PMC551_DRAM_BLK3 0x74
+#define PMC551_DRAM_BLK_GET_SIZE(x) (524288 << ((x >> 4) & 0x0f))
+#define PMC551_DRAM_BLK_SET_COL_MUX(x, v) (((x) & ~0x00007000) | (((v) & 0x7) << 12))
+#define PMC551_DRAM_BLK_SET_ROW_MUX(x, v) (((x) & ~0x00000f00) | (((v) & 0xf) << 8))
+
+struct mypriv {
+	struct pci_dev *dev;
+	u_char *start;
+	u32 base_map0;
+	u32 curr_map0;
+	u32 asize;
+	struct mtd_info *nextpmc551;
+};
 
 static struct mtd_info *pmc551list;
 
+static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
+			size_t *retlen, void **virt, resource_size_t *phys);
+
 static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
 	struct mypriv *priv = mtd->priv;
@@ -116,16 +151,6 @@
 #endif
 
 	end = instr->addr + instr->len - 1;
-
-	/* Is it past the end? */
-	if (end > mtd->size) {
-#ifdef CONFIG_MTD_PMC551_DEBUG
-		printk(KERN_DEBUG "pmc551_erase() out of bounds (%ld > %ld)\n",
-			(long)end, (long)mtd->size);
-#endif
-		return -EINVAL;
-	}
-
 	eoff_hi = end & ~(priv->asize - 1);
 	soff_hi = instr->addr & ~(priv->asize - 1);
 	eoff_lo = end & (priv->asize - 1);
@@ -179,18 +204,6 @@
 	printk(KERN_DEBUG "pmc551_point(%ld, %ld)\n", (long)from, (long)len);
 #endif
 
-	if (from + len > mtd->size) {
-#ifdef CONFIG_MTD_PMC551_DEBUG
-		printk(KERN_DEBUG "pmc551_point() out of bounds (%ld > %ld)\n",
-			(long)from + len, (long)mtd->size);
-#endif
-		return -EINVAL;
-	}
-
-	/* can we return a physical address with this driver? */
-	if (phys)
-		return -EINVAL;
-
 	soff_hi = from & ~(priv->asize - 1);
 	soff_lo = from & (priv->asize - 1);
 
@@ -206,11 +219,12 @@
 	return 0;
 }
 
-static void pmc551_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
+static int pmc551_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
 #ifdef CONFIG_MTD_PMC551_DEBUG
 	printk(KERN_DEBUG "pmc551_unpoint()\n");
 #endif
+	return 0;
 }
 
 static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
@@ -229,16 +243,6 @@
 #endif
 
 	end = from + len - 1;
-
-	/* Is it past the end? */
-	if (end > mtd->size) {
-#ifdef CONFIG_MTD_PMC551_DEBUG
-		printk(KERN_DEBUG "pmc551_read() out of bounds (%ld > %ld)\n",
-			(long)end, (long)mtd->size);
-#endif
-		return -EINVAL;
-	}
-
 	soff_hi = from & ~(priv->asize - 1);
 	eoff_hi = end & ~(priv->asize - 1);
 	soff_lo = from & (priv->asize - 1);
@@ -296,16 +300,6 @@
 #endif
 
 	end = to + len - 1;
-	/* Is it past the end?  or did the u32 wrap? */
-	if (end > mtd->size) {
-#ifdef CONFIG_MTD_PMC551_DEBUG
-		printk(KERN_DEBUG "pmc551_write() out of bounds (end: %ld, "
-			"size: %ld, to: %ld)\n", (long)end, (long)mtd->size,
-			(long)to);
-#endif
-		return -EINVAL;
-	}
-
 	soff_hi = to & ~(priv->asize - 1);
 	eoff_hi = end & ~(priv->asize - 1);
 	soff_lo = to & (priv->asize - 1);
@@ -359,7 +353,7 @@
  * mechanism
  * returns the size of the memory region found.
  */
-static u32 fixup_pmc551(struct pci_dev *dev)
+static int fixup_pmc551(struct pci_dev *dev)
 {
 #ifdef CONFIG_MTD_PMC551_BUGFIX
 	u32 dram_data;
@@ -669,7 +663,7 @@
 	struct mypriv *priv;
 	int found = 0;
 	struct mtd_info *mtd;
-	u32 length = 0;
+	int length = 0;
 
 	if (msize) {
 		msize = (1 << (ffs(msize) - 1)) << 20;
@@ -787,11 +781,11 @@
 
 		mtd->size = msize;
 		mtd->flags = MTD_CAP_RAM;
-		mtd->erase = pmc551_erase;
-		mtd->read = pmc551_read;
-		mtd->write = pmc551_write;
-		mtd->point = pmc551_point;
-		mtd->unpoint = pmc551_unpoint;
+		mtd->_erase = pmc551_erase;
+		mtd->_read = pmc551_read;
+		mtd->_write = pmc551_write;
+		mtd->_point = pmc551_point;
+		mtd->_unpoint = pmc551_unpoint;
 		mtd->type = MTD_RAM;
 		mtd->name = "PMC551 RAM board";
 		mtd->erasesize = 0x10000;
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index e585263..8f52fc8 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -42,7 +42,6 @@
 #include <linux/ioctl.h>
 #include <linux/init.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <linux/mtd/mtd.h>
 
@@ -76,7 +75,7 @@
 static int slram_erase(struct mtd_info *, struct erase_info *);
 static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, void **,
 		resource_size_t *);
-static void slram_unpoint(struct mtd_info *, loff_t, size_t);
+static int slram_unpoint(struct mtd_info *, loff_t, size_t);
 static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 
@@ -84,21 +83,13 @@
 {
 	slram_priv_t *priv = mtd->priv;
 
-	if (instr->addr + instr->len > mtd->size) {
-		return(-EINVAL);
-	}
-
 	memset(priv->start + instr->addr, 0xff, instr->len);
-
 	/* This'll catch a few races. Free the thing before returning :)
 	 * I don't feel at all ashamed. This kind of thing is possible anyway
 	 * with flash, but unlikely.
 	 */
-
 	instr->state = MTD_ERASE_DONE;
-
 	mtd_erase_callback(instr);
-
 	return(0);
 }
 
@@ -107,20 +98,14 @@
 {
 	slram_priv_t *priv = mtd->priv;
 
-	/* can we return a physical address with this driver? */
-	if (phys)
-		return -EINVAL;
-
-	if (from + len > mtd->size)
-		return -EINVAL;
-
 	*virt = priv->start + from;
 	*retlen = len;
 	return(0);
 }
 
-static void slram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
+static int slram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
+	return 0;
 }
 
 static int slram_read(struct mtd_info *mtd, loff_t from, size_t len,
@@ -128,14 +113,7 @@
 {
 	slram_priv_t *priv = mtd->priv;
 
-	if (from > mtd->size)
-		return -EINVAL;
-
-	if (from + len > mtd->size)
-		len = mtd->size - from;
-
 	memcpy(buf, priv->start + from, len);
-
 	*retlen = len;
 	return(0);
 }
@@ -145,11 +123,7 @@
 {
 	slram_priv_t *priv = mtd->priv;
 
-	if (to + len > mtd->size)
-		return -EINVAL;
-
 	memcpy(priv->start + to, buf, len);
-
 	*retlen = len;
 	return(0);
 }
@@ -200,11 +174,11 @@
 	(*curmtd)->mtdinfo->name = name;
 	(*curmtd)->mtdinfo->size = length;
 	(*curmtd)->mtdinfo->flags = MTD_CAP_RAM;
-        (*curmtd)->mtdinfo->erase = slram_erase;
-	(*curmtd)->mtdinfo->point = slram_point;
-	(*curmtd)->mtdinfo->unpoint = slram_unpoint;
-	(*curmtd)->mtdinfo->read = slram_read;
-	(*curmtd)->mtdinfo->write = slram_write;
+	(*curmtd)->mtdinfo->_erase = slram_erase;
+	(*curmtd)->mtdinfo->_point = slram_point;
+	(*curmtd)->mtdinfo->_unpoint = slram_unpoint;
+	(*curmtd)->mtdinfo->_read = slram_read;
+	(*curmtd)->mtdinfo->_write = slram_write;
 	(*curmtd)->mtdinfo->owner = THIS_MODULE;
 	(*curmtd)->mtdinfo->type = MTD_RAM;
 	(*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c
new file mode 100644
index 0000000..797d43c
--- /dev/null
+++ b/drivers/mtd/devices/spear_smi.c
@@ -0,0 +1,1147 @@
+/*
+ * SMI (Serial Memory Controller) device driver for Serial NOR Flash on
+ * SPEAr platform
+ * The serial nor interface is largely based on drivers/mtd/m25p80.c,
+ * however the SPI interface has been replaced by SMI.
+ *
+ * Copyright © 2010 STMicroelectronics.
+ * Ashish Priyadarshi
+ * Shiraz Hashim <shiraz.hashim@st.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/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/spear_smi.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+/* SMI clock rate */
+#define SMI_MAX_CLOCK_FREQ	50000000 /* 50 MHz */
+
+/* MAX time out to safely come out of a erase or write busy conditions */
+#define SMI_PROBE_TIMEOUT	(HZ / 10)
+#define SMI_MAX_TIME_OUT	(3 * HZ)
+
+/* timeout for command completion */
+#define SMI_CMD_TIMEOUT		(HZ / 10)
+
+/* registers of smi */
+#define SMI_CR1		0x0	/* SMI control register 1 */
+#define SMI_CR2		0x4	/* SMI control register 2 */
+#define SMI_SR		0x8	/* SMI status register */
+#define SMI_TR		0xC	/* SMI transmit register */
+#define SMI_RR		0x10	/* SMI receive register */
+
+/* defines for control_reg 1 */
+#define BANK_EN		(0xF << 0)	/* enables all banks */
+#define DSEL_TIME	(0x6 << 4)	/* Deselect time 6 + 1 SMI_CK periods */
+#define SW_MODE		(0x1 << 28)	/* enables SW Mode */
+#define WB_MODE		(0x1 << 29)	/* Write Burst Mode */
+#define FAST_MODE	(0x1 << 15)	/* Fast Mode */
+#define HOLD1		(0x1 << 16)	/* Clock Hold period selection */
+
+/* defines for control_reg 2 */
+#define SEND		(0x1 << 7)	/* Send data */
+#define TFIE		(0x1 << 8)	/* Transmission Flag Interrupt Enable */
+#define WCIE		(0x1 << 9)	/* Write Complete Interrupt Enable */
+#define RD_STATUS_REG	(0x1 << 10)	/* reads status reg */
+#define WE		(0x1 << 11)	/* Write Enable */
+
+#define TX_LEN_SHIFT	0
+#define RX_LEN_SHIFT	4
+#define BANK_SHIFT	12
+
+/* defines for status register */
+#define SR_WIP		0x1	/* Write in progress */
+#define SR_WEL		0x2	/* Write enable latch */
+#define SR_BP0		0x4	/* Block protect 0 */
+#define SR_BP1		0x8	/* Block protect 1 */
+#define SR_BP2		0x10	/* Block protect 2 */
+#define SR_SRWD		0x80	/* SR write protect */
+#define TFF		0x100	/* Transfer Finished Flag */
+#define WCF		0x200	/* Transfer Finished Flag */
+#define ERF1		0x400	/* Forbidden Write Request */
+#define ERF2		0x800	/* Forbidden Access */
+
+#define WM_SHIFT	12
+
+/* flash opcodes */
+#define OPCODE_RDID	0x9f	/* Read JEDEC ID */
+
+/* Flash Device Ids maintenance section */
+
+/* data structure to maintain flash ids from different vendors */
+struct flash_device {
+	char *name;
+	u8 erase_cmd;
+	u32 device_id;
+	u32 pagesize;
+	unsigned long sectorsize;
+	unsigned long size_in_bytes;
+};
+
+#define FLASH_ID(n, es, id, psize, ssize, size)	\
+{				\
+	.name = n,		\
+	.erase_cmd = es,	\
+	.device_id = id,	\
+	.pagesize = psize,	\
+	.sectorsize = ssize,	\
+	.size_in_bytes = size	\
+}
+
+static struct flash_device flash_devices[] = {
+	FLASH_ID("st m25p16"     , 0xd8, 0x00152020, 0x100, 0x10000, 0x200000),
+	FLASH_ID("st m25p32"     , 0xd8, 0x00162020, 0x100, 0x10000, 0x400000),
+	FLASH_ID("st m25p64"     , 0xd8, 0x00172020, 0x100, 0x10000, 0x800000),
+	FLASH_ID("st m25p128"    , 0xd8, 0x00182020, 0x100, 0x40000, 0x1000000),
+	FLASH_ID("st m25p05"     , 0xd8, 0x00102020, 0x80 , 0x8000 , 0x10000),
+	FLASH_ID("st m25p10"     , 0xd8, 0x00112020, 0x80 , 0x8000 , 0x20000),
+	FLASH_ID("st m25p20"     , 0xd8, 0x00122020, 0x100, 0x10000, 0x40000),
+	FLASH_ID("st m25p40"     , 0xd8, 0x00132020, 0x100, 0x10000, 0x80000),
+	FLASH_ID("st m25p80"     , 0xd8, 0x00142020, 0x100, 0x10000, 0x100000),
+	FLASH_ID("st m45pe10"    , 0xd8, 0x00114020, 0x100, 0x10000, 0x20000),
+	FLASH_ID("st m45pe20"    , 0xd8, 0x00124020, 0x100, 0x10000, 0x40000),
+	FLASH_ID("st m45pe40"    , 0xd8, 0x00134020, 0x100, 0x10000, 0x80000),
+	FLASH_ID("st m45pe80"    , 0xd8, 0x00144020, 0x100, 0x10000, 0x100000),
+	FLASH_ID("sp s25fl004"   , 0xd8, 0x00120201, 0x100, 0x10000, 0x80000),
+	FLASH_ID("sp s25fl008"   , 0xd8, 0x00130201, 0x100, 0x10000, 0x100000),
+	FLASH_ID("sp s25fl016"   , 0xd8, 0x00140201, 0x100, 0x10000, 0x200000),
+	FLASH_ID("sp s25fl032"   , 0xd8, 0x00150201, 0x100, 0x10000, 0x400000),
+	FLASH_ID("sp s25fl064"   , 0xd8, 0x00160201, 0x100, 0x10000, 0x800000),
+	FLASH_ID("atmel 25f512"  , 0x52, 0x0065001F, 0x80 , 0x8000 , 0x10000),
+	FLASH_ID("atmel 25f1024" , 0x52, 0x0060001F, 0x100, 0x8000 , 0x20000),
+	FLASH_ID("atmel 25f2048" , 0x52, 0x0063001F, 0x100, 0x10000, 0x40000),
+	FLASH_ID("atmel 25f4096" , 0x52, 0x0064001F, 0x100, 0x10000, 0x80000),
+	FLASH_ID("atmel 25fs040" , 0xd7, 0x0004661F, 0x100, 0x10000, 0x80000),
+	FLASH_ID("mac 25l512"    , 0xd8, 0x001020C2, 0x010, 0x10000, 0x10000),
+	FLASH_ID("mac 25l1005"   , 0xd8, 0x001120C2, 0x010, 0x10000, 0x20000),
+	FLASH_ID("mac 25l2005"   , 0xd8, 0x001220C2, 0x010, 0x10000, 0x40000),
+	FLASH_ID("mac 25l4005"   , 0xd8, 0x001320C2, 0x010, 0x10000, 0x80000),
+	FLASH_ID("mac 25l4005a"  , 0xd8, 0x001320C2, 0x010, 0x10000, 0x80000),
+	FLASH_ID("mac 25l8005"   , 0xd8, 0x001420C2, 0x010, 0x10000, 0x100000),
+	FLASH_ID("mac 25l1605"   , 0xd8, 0x001520C2, 0x100, 0x10000, 0x200000),
+	FLASH_ID("mac 25l1605a"  , 0xd8, 0x001520C2, 0x010, 0x10000, 0x200000),
+	FLASH_ID("mac 25l3205"   , 0xd8, 0x001620C2, 0x100, 0x10000, 0x400000),
+	FLASH_ID("mac 25l3205a"  , 0xd8, 0x001620C2, 0x100, 0x10000, 0x400000),
+	FLASH_ID("mac 25l6405"   , 0xd8, 0x001720C2, 0x100, 0x10000, 0x800000),
+};
+
+/* Define spear specific structures */
+
+struct spear_snor_flash;
+
+/**
+ * struct spear_smi - Structure for SMI Device
+ *
+ * @clk: functional clock
+ * @status: current status register of SMI.
+ * @clk_rate: functional clock rate of SMI (default: SMI_MAX_CLOCK_FREQ)
+ * @lock: lock to prevent parallel access of SMI.
+ * @io_base: base address for registers of SMI.
+ * @pdev: platform device
+ * @cmd_complete: queue to wait for command completion of NOR-flash.
+ * @num_flashes: number of flashes actually present on board.
+ * @flash: separate structure for each Serial NOR-flash attached to SMI.
+ */
+struct spear_smi {
+	struct clk *clk;
+	u32 status;
+	unsigned long clk_rate;
+	struct mutex lock;
+	void __iomem *io_base;
+	struct platform_device *pdev;
+	wait_queue_head_t cmd_complete;
+	u32 num_flashes;
+	struct spear_snor_flash *flash[MAX_NUM_FLASH_CHIP];
+};
+
+/**
+ * struct spear_snor_flash - Structure for Serial NOR Flash
+ *
+ * @bank: Bank number(0, 1, 2, 3) for each NOR-flash.
+ * @dev_id: Device ID of NOR-flash.
+ * @lock: lock to manage flash read, write and erase operations
+ * @mtd: MTD info for each NOR-flash.
+ * @num_parts: Total number of partition in each bank of NOR-flash.
+ * @parts: Partition info for each bank of NOR-flash.
+ * @page_size: Page size of NOR-flash.
+ * @base_addr: Base address of NOR-flash.
+ * @erase_cmd: erase command may vary on different flash types
+ * @fast_mode: flash supports read in fast mode
+ */
+struct spear_snor_flash {
+	u32 bank;
+	u32 dev_id;
+	struct mutex lock;
+	struct mtd_info mtd;
+	u32 num_parts;
+	struct mtd_partition *parts;
+	u32 page_size;
+	void __iomem *base_addr;
+	u8 erase_cmd;
+	u8 fast_mode;
+};
+
+static inline struct spear_snor_flash *get_flash_data(struct mtd_info *mtd)
+{
+	return container_of(mtd, struct spear_snor_flash, mtd);
+}
+
+/**
+ * spear_smi_read_sr - Read status register of flash through SMI
+ * @dev: structure of SMI information.
+ * @bank: bank to which flash is connected
+ *
+ * This routine will return the status register of the flash chip present at the
+ * given bank.
+ */
+static int spear_smi_read_sr(struct spear_smi *dev, u32 bank)
+{
+	int ret;
+	u32 ctrlreg1;
+
+	mutex_lock(&dev->lock);
+	dev->status = 0; /* Will be set in interrupt handler */
+
+	ctrlreg1 = readl(dev->io_base + SMI_CR1);
+	/* program smi in hw mode */
+	writel(ctrlreg1 & ~(SW_MODE | WB_MODE), dev->io_base + SMI_CR1);
+
+	/* performing a rsr instruction in hw mode */
+	writel((bank << BANK_SHIFT) | RD_STATUS_REG | TFIE,
+			dev->io_base + SMI_CR2);
+
+	/* wait for tff */
+	ret = wait_event_interruptible_timeout(dev->cmd_complete,
+			dev->status & TFF, SMI_CMD_TIMEOUT);
+
+	/* copy dev->status (lower 16 bits) in order to release lock */
+	if (ret > 0)
+		ret = dev->status & 0xffff;
+	else
+		ret = -EIO;
+
+	/* restore the ctrl regs state */
+	writel(ctrlreg1, dev->io_base + SMI_CR1);
+	writel(0, dev->io_base + SMI_CR2);
+	mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**
+ * spear_smi_wait_till_ready - wait till flash is ready
+ * @dev: structure of SMI information.
+ * @bank: flash corresponding to this bank
+ * @timeout: timeout for busy wait condition
+ *
+ * This routine checks for WIP (write in progress) bit in Status register
+ * If successful the routine returns 0 else -EBUSY
+ */
+static int spear_smi_wait_till_ready(struct spear_smi *dev, u32 bank,
+		unsigned long timeout)
+{
+	unsigned long finish;
+	int status;
+
+	finish = jiffies + timeout;
+	do {
+		status = spear_smi_read_sr(dev, bank);
+		if (status < 0)
+			continue; /* try till timeout */
+		else if (!(status & SR_WIP))
+			return 0;
+
+		cond_resched();
+	} while (!time_after_eq(jiffies, finish));
+
+	dev_err(&dev->pdev->dev, "smi controller is busy, timeout\n");
+	return status;
+}
+
+/**
+ * spear_smi_int_handler - SMI Interrupt Handler.
+ * @irq: irq number
+ * @dev_id: structure of SMI device, embedded in dev_id.
+ *
+ * The handler clears all interrupt conditions and records the status in
+ * dev->status which is used by the driver later.
+ */
+static irqreturn_t spear_smi_int_handler(int irq, void *dev_id)
+{
+	u32 status = 0;
+	struct spear_smi *dev = dev_id;
+
+	status = readl(dev->io_base + SMI_SR);
+
+	if (unlikely(!status))
+		return IRQ_NONE;
+
+	/* clear all interrupt conditions */
+	writel(0, dev->io_base + SMI_SR);
+
+	/* copy the status register in dev->status */
+	dev->status |= status;
+
+	/* send the completion */
+	wake_up_interruptible(&dev->cmd_complete);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * spear_smi_hw_init - initializes the smi controller.
+ * @dev: structure of smi device
+ *
+ * this routine initializes the smi controller wit the default values
+ */
+static void spear_smi_hw_init(struct spear_smi *dev)
+{
+	unsigned long rate = 0;
+	u32 prescale = 0;
+	u32 val;
+
+	rate = clk_get_rate(dev->clk);
+
+	/* functional clock of smi */
+	prescale = DIV_ROUND_UP(rate, dev->clk_rate);
+
+	/*
+	 * setting the standard values, fast mode, prescaler for
+	 * SMI_MAX_CLOCK_FREQ (50MHz) operation and bank enable
+	 */
+	val = HOLD1 | BANK_EN | DSEL_TIME | (prescale << 8);
+
+	mutex_lock(&dev->lock);
+	writel(val, dev->io_base + SMI_CR1);
+	mutex_unlock(&dev->lock);
+}
+
+/**
+ * get_flash_index - match chip id from a flash list.
+ * @flash_id: a valid nor flash chip id obtained from board.
+ *
+ * try to validate the chip id by matching from a list, if not found then simply
+ * returns negative. In case of success returns index in to the flash devices
+ * array.
+ */
+static int get_flash_index(u32 flash_id)
+{
+	int index;
+
+	/* Matches chip-id to entire list of 'serial-nor flash' ids */
+	for (index = 0; index < ARRAY_SIZE(flash_devices); index++) {
+		if (flash_devices[index].device_id == flash_id)
+			return index;
+	}
+
+	/* Memory chip is not listed and not supported */
+	return -ENODEV;
+}
+
+/**
+ * spear_smi_write_enable - Enable the flash to do write operation
+ * @dev: structure of SMI device
+ * @bank: enable write for flash connected to this bank
+ *
+ * Set write enable latch with Write Enable command.
+ * Returns 0 on success.
+ */
+static int spear_smi_write_enable(struct spear_smi *dev, u32 bank)
+{
+	int ret;
+	u32 ctrlreg1;
+
+	mutex_lock(&dev->lock);
+	dev->status = 0; /* Will be set in interrupt handler */
+
+	ctrlreg1 = readl(dev->io_base + SMI_CR1);
+	/* program smi in h/w mode */
+	writel(ctrlreg1 & ~SW_MODE, dev->io_base + SMI_CR1);
+
+	/* give the flash, write enable command */
+	writel((bank << BANK_SHIFT) | WE | TFIE, dev->io_base + SMI_CR2);
+
+	ret = wait_event_interruptible_timeout(dev->cmd_complete,
+			dev->status & TFF, SMI_CMD_TIMEOUT);
+
+	/* restore the ctrl regs state */
+	writel(ctrlreg1, dev->io_base + SMI_CR1);
+	writel(0, dev->io_base + SMI_CR2);
+
+	if (ret <= 0) {
+		ret = -EIO;
+		dev_err(&dev->pdev->dev,
+			"smi controller failed on write enable\n");
+	} else {
+		/* check whether write mode status is set for required bank */
+		if (dev->status & (1 << (bank + WM_SHIFT)))
+			ret = 0;
+		else {
+			dev_err(&dev->pdev->dev, "couldn't enable write\n");
+			ret = -EIO;
+		}
+	}
+
+	mutex_unlock(&dev->lock);
+	return ret;
+}
+
+static inline u32
+get_sector_erase_cmd(struct spear_snor_flash *flash, u32 offset)
+{
+	u32 cmd;
+	u8 *x = (u8 *)&cmd;
+
+	x[0] = flash->erase_cmd;
+	x[1] = offset >> 16;
+	x[2] = offset >> 8;
+	x[3] = offset;
+
+	return cmd;
+}
+
+/**
+ * spear_smi_erase_sector - erase one sector of flash
+ * @dev: structure of SMI information
+ * @command: erase command to be send
+ * @bank: bank to which this command needs to be send
+ * @bytes: size of command
+ *
+ * Erase one sector of flash memory at offset ``offset'' which is any
+ * address within the sector which should be erased.
+ * Returns 0 if successful, non-zero otherwise.
+ */
+static int spear_smi_erase_sector(struct spear_smi *dev,
+		u32 bank, u32 command, u32 bytes)
+{
+	u32 ctrlreg1 = 0;
+	int ret;
+
+	ret = spear_smi_wait_till_ready(dev, bank, SMI_MAX_TIME_OUT);
+	if (ret)
+		return ret;
+
+	ret = spear_smi_write_enable(dev, bank);
+	if (ret)
+		return ret;
+
+	mutex_lock(&dev->lock);
+
+	ctrlreg1 = readl(dev->io_base + SMI_CR1);
+	writel((ctrlreg1 | SW_MODE) & ~WB_MODE, dev->io_base + SMI_CR1);
+
+	/* send command in sw mode */
+	writel(command, dev->io_base + SMI_TR);
+
+	writel((bank << BANK_SHIFT) | SEND | TFIE | (bytes << TX_LEN_SHIFT),
+			dev->io_base + SMI_CR2);
+
+	ret = wait_event_interruptible_timeout(dev->cmd_complete,
+			dev->status & TFF, SMI_CMD_TIMEOUT);
+
+	if (ret <= 0) {
+		ret = -EIO;
+		dev_err(&dev->pdev->dev, "sector erase failed\n");
+	} else
+		ret = 0; /* success */
+
+	/* restore ctrl regs */
+	writel(ctrlreg1, dev->io_base + SMI_CR1);
+	writel(0, dev->io_base + SMI_CR2);
+
+	mutex_unlock(&dev->lock);
+	return ret;
+}
+
+/**
+ * spear_mtd_erase - perform flash erase operation as requested by user
+ * @mtd: Provides the memory characteristics
+ * @e_info: Provides the erase information
+ *
+ * Erase an address range on the flash chip. The address range may extend
+ * one or more erase sectors. Return an error is there is a problem erasing.
+ */
+static int spear_mtd_erase(struct mtd_info *mtd, struct erase_info *e_info)
+{
+	struct spear_snor_flash *flash = get_flash_data(mtd);
+	struct spear_smi *dev = mtd->priv;
+	u32 addr, command, bank;
+	int len, ret;
+
+	if (!flash || !dev)
+		return -ENODEV;
+
+	bank = flash->bank;
+	if (bank > dev->num_flashes - 1) {
+		dev_err(&dev->pdev->dev, "Invalid Bank Num");
+		return -EINVAL;
+	}
+
+	addr = e_info->addr;
+	len = e_info->len;
+
+	mutex_lock(&flash->lock);
+
+	/* now erase sectors in loop */
+	while (len) {
+		command = get_sector_erase_cmd(flash, addr);
+		/* preparing the command for flash */
+		ret = spear_smi_erase_sector(dev, bank, command, 4);
+		if (ret) {
+			e_info->state = MTD_ERASE_FAILED;
+			mutex_unlock(&flash->lock);
+			return ret;
+		}
+		addr += mtd->erasesize;
+		len -= mtd->erasesize;
+	}
+
+	mutex_unlock(&flash->lock);
+	e_info->state = MTD_ERASE_DONE;
+	mtd_erase_callback(e_info);
+
+	return 0;
+}
+
+/**
+ * spear_mtd_read - performs flash read operation as requested by the user
+ * @mtd: MTD information of the memory bank
+ * @from: Address from which to start read
+ * @len: Number of bytes to be read
+ * @retlen: Fills the Number of bytes actually read
+ * @buf: Fills this after reading
+ *
+ * Read an address range from the flash chip. The address range
+ * may be any size provided it is within the physical boundaries.
+ * Returns 0 on success, non zero otherwise
+ */
+static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
+		size_t *retlen, u8 *buf)
+{
+	struct spear_snor_flash *flash = get_flash_data(mtd);
+	struct spear_smi *dev = mtd->priv;
+	void *src;
+	u32 ctrlreg1, val;
+	int ret;
+
+	if (!flash || !dev)
+		return -ENODEV;
+
+	if (flash->bank > dev->num_flashes - 1) {
+		dev_err(&dev->pdev->dev, "Invalid Bank Num");
+		return -EINVAL;
+	}
+
+	/* select address as per bank number */
+	src = flash->base_addr + from;
+
+	mutex_lock(&flash->lock);
+
+	/* wait till previous write/erase is done. */
+	ret = spear_smi_wait_till_ready(dev, flash->bank, SMI_MAX_TIME_OUT);
+	if (ret) {
+		mutex_unlock(&flash->lock);
+		return ret;
+	}
+
+	mutex_lock(&dev->lock);
+	/* put smi in hw mode not wbt mode */
+	ctrlreg1 = val = readl(dev->io_base + SMI_CR1);
+	val &= ~(SW_MODE | WB_MODE);
+	if (flash->fast_mode)
+		val |= FAST_MODE;
+
+	writel(val, dev->io_base + SMI_CR1);
+
+	memcpy_fromio(buf, (u8 *)src, len);
+
+	/* restore ctrl reg1 */
+	writel(ctrlreg1, dev->io_base + SMI_CR1);
+	mutex_unlock(&dev->lock);
+
+	*retlen = len;
+	mutex_unlock(&flash->lock);
+
+	return 0;
+}
+
+static inline int spear_smi_cpy_toio(struct spear_smi *dev, u32 bank,
+		void *dest, const void *src, size_t len)
+{
+	int ret;
+	u32 ctrlreg1;
+
+	/* wait until finished previous write command. */
+	ret = spear_smi_wait_till_ready(dev, bank, SMI_MAX_TIME_OUT);
+	if (ret)
+		return ret;
+
+	/* put smi in write enable */
+	ret = spear_smi_write_enable(dev, bank);
+	if (ret)
+		return ret;
+
+	/* put smi in hw, write burst mode */
+	mutex_lock(&dev->lock);
+
+	ctrlreg1 = readl(dev->io_base + SMI_CR1);
+	writel((ctrlreg1 | WB_MODE) & ~SW_MODE, dev->io_base + SMI_CR1);
+
+	memcpy_toio(dest, src, len);
+
+	writel(ctrlreg1, dev->io_base + SMI_CR1);
+
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+/**
+ * spear_mtd_write - performs write operation as requested by the user.
+ * @mtd: MTD information of the memory bank.
+ * @to:	Address to write.
+ * @len: Number of bytes to be written.
+ * @retlen: Number of bytes actually wrote.
+ * @buf: Buffer from which the data to be taken.
+ *
+ * Write an address range to the flash chip. Data must be written in
+ * flash_page_size chunks. The address range may be any size provided
+ * it is within the physical boundaries.
+ * Returns 0 on success, non zero otherwise
+ */
+static int spear_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
+		size_t *retlen, const u8 *buf)
+{
+	struct spear_snor_flash *flash = get_flash_data(mtd);
+	struct spear_smi *dev = mtd->priv;
+	void *dest;
+	u32 page_offset, page_size;
+	int ret;
+
+	if (!flash || !dev)
+		return -ENODEV;
+
+	if (flash->bank > dev->num_flashes - 1) {
+		dev_err(&dev->pdev->dev, "Invalid Bank Num");
+		return -EINVAL;
+	}
+
+	/* select address as per bank number */
+	dest = flash->base_addr + to;
+	mutex_lock(&flash->lock);
+
+	page_offset = (u32)to % flash->page_size;
+
+	/* do if all the bytes fit onto one page */
+	if (page_offset + len <= flash->page_size) {
+		ret = spear_smi_cpy_toio(dev, flash->bank, dest, buf, len);
+		if (!ret)
+			*retlen += len;
+	} else {
+		u32 i;
+
+		/* the size of data remaining on the first page */
+		page_size = flash->page_size - page_offset;
+
+		ret = spear_smi_cpy_toio(dev, flash->bank, dest, buf,
+				page_size);
+		if (ret)
+			goto err_write;
+		else
+			*retlen += page_size;
+
+		/* write everything in pagesize chunks */
+		for (i = page_size; i < len; i += page_size) {
+			page_size = len - i;
+			if (page_size > flash->page_size)
+				page_size = flash->page_size;
+
+			ret = spear_smi_cpy_toio(dev, flash->bank, dest + i,
+					buf + i, page_size);
+			if (ret)
+				break;
+			else
+				*retlen += page_size;
+		}
+	}
+
+err_write:
+	mutex_unlock(&flash->lock);
+
+	return ret;
+}
+
+/**
+ * spear_smi_probe_flash - Detects the NOR Flash chip.
+ * @dev: structure of SMI information.
+ * @bank: bank on which flash must be probed
+ *
+ * This routine will check whether there exists a flash chip on a given memory
+ * bank ID.
+ * Return index of the probed flash in flash devices structure
+ */
+static int spear_smi_probe_flash(struct spear_smi *dev, u32 bank)
+{
+	int ret;
+	u32 val = 0;
+
+	ret = spear_smi_wait_till_ready(dev, bank, SMI_PROBE_TIMEOUT);
+	if (ret)
+		return ret;
+
+	mutex_lock(&dev->lock);
+
+	dev->status = 0; /* Will be set in interrupt handler */
+	/* put smi in sw mode */
+	val = readl(dev->io_base + SMI_CR1);
+	writel(val | SW_MODE, dev->io_base + SMI_CR1);
+
+	/* send readid command in sw mode */
+	writel(OPCODE_RDID, dev->io_base + SMI_TR);
+
+	val = (bank << BANK_SHIFT) | SEND | (1 << TX_LEN_SHIFT) |
+		(3 << RX_LEN_SHIFT) | TFIE;
+	writel(val, dev->io_base + SMI_CR2);
+
+	/* wait for TFF */
+	ret = wait_event_interruptible_timeout(dev->cmd_complete,
+			dev->status & TFF, SMI_CMD_TIMEOUT);
+	if (ret <= 0) {
+		ret = -ENODEV;
+		goto err_probe;
+	}
+
+	/* get memory chip id */
+	val = readl(dev->io_base + SMI_RR);
+	val &= 0x00ffffff;
+	ret = get_flash_index(val);
+
+err_probe:
+	/* clear sw mode */
+	val = readl(dev->io_base + SMI_CR1);
+	writel(val & ~SW_MODE, dev->io_base + SMI_CR1);
+
+	mutex_unlock(&dev->lock);
+	return ret;
+}
+
+
+#ifdef CONFIG_OF
+static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev,
+					       struct device_node *np)
+{
+	struct spear_smi_plat_data *pdata = dev_get_platdata(&pdev->dev);
+	struct device_node *pp = NULL;
+	const __be32 *addr;
+	u32 val;
+	int len;
+	int i = 0;
+
+	if (!np)
+		return -ENODEV;
+
+	of_property_read_u32(np, "clock-rate", &val);
+	pdata->clk_rate = val;
+
+	pdata->board_flash_info = devm_kzalloc(&pdev->dev,
+					       sizeof(*pdata->board_flash_info),
+					       GFP_KERNEL);
+
+	/* Fill structs for each subnode (flash device) */
+	while ((pp = of_get_next_child(np, pp))) {
+		struct spear_smi_flash_info *flash_info;
+
+		flash_info = &pdata->board_flash_info[i];
+		pdata->np[i] = pp;
+
+		/* Read base-addr and size from DT */
+		addr = of_get_property(pp, "reg", &len);
+		pdata->board_flash_info->mem_base = be32_to_cpup(&addr[0]);
+		pdata->board_flash_info->size = be32_to_cpup(&addr[1]);
+
+		if (of_get_property(pp, "st,smi-fast-mode", NULL))
+			pdata->board_flash_info->fast_mode = 1;
+
+		i++;
+	}
+
+	pdata->num_flashes = i;
+
+	return 0;
+}
+#else
+static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev,
+					       struct device_node *np)
+{
+	return -ENOSYS;
+}
+#endif
+
+static int spear_smi_setup_banks(struct platform_device *pdev,
+				 u32 bank, struct device_node *np)
+{
+	struct spear_smi *dev = platform_get_drvdata(pdev);
+	struct mtd_part_parser_data ppdata = {};
+	struct spear_smi_flash_info *flash_info;
+	struct spear_smi_plat_data *pdata;
+	struct spear_snor_flash *flash;
+	struct mtd_partition *parts = NULL;
+	int count = 0;
+	int flash_index;
+	int ret = 0;
+
+	pdata = dev_get_platdata(&pdev->dev);
+	if (bank > pdata->num_flashes - 1)
+		return -EINVAL;
+
+	flash_info = &pdata->board_flash_info[bank];
+	if (!flash_info)
+		return -ENODEV;
+
+	flash = kzalloc(sizeof(*flash), GFP_ATOMIC);
+	if (!flash)
+		return -ENOMEM;
+	flash->bank = bank;
+	flash->fast_mode = flash_info->fast_mode ? 1 : 0;
+	mutex_init(&flash->lock);
+
+	/* verify whether nor flash is really present on board */
+	flash_index = spear_smi_probe_flash(dev, bank);
+	if (flash_index < 0) {
+		dev_info(&dev->pdev->dev, "smi-nor%d not found\n", bank);
+		ret = flash_index;
+		goto err_probe;
+	}
+	/* map the memory for nor flash chip */
+	flash->base_addr = ioremap(flash_info->mem_base, flash_info->size);
+	if (!flash->base_addr) {
+		ret = -EIO;
+		goto err_probe;
+	}
+
+	dev->flash[bank] = flash;
+	flash->mtd.priv = dev;
+
+	if (flash_info->name)
+		flash->mtd.name = flash_info->name;
+	else
+		flash->mtd.name = flash_devices[flash_index].name;
+
+	flash->mtd.type = MTD_NORFLASH;
+	flash->mtd.writesize = 1;
+	flash->mtd.flags = MTD_CAP_NORFLASH;
+	flash->mtd.size = flash_info->size;
+	flash->mtd.erasesize = flash_devices[flash_index].sectorsize;
+	flash->page_size = flash_devices[flash_index].pagesize;
+	flash->mtd.writebufsize = flash->page_size;
+	flash->erase_cmd = flash_devices[flash_index].erase_cmd;
+	flash->mtd._erase = spear_mtd_erase;
+	flash->mtd._read = spear_mtd_read;
+	flash->mtd._write = spear_mtd_write;
+	flash->dev_id = flash_devices[flash_index].device_id;
+
+	dev_info(&dev->pdev->dev, "mtd .name=%s .size=%llx(%lluM)\n",
+			flash->mtd.name, flash->mtd.size,
+			flash->mtd.size / (1024 * 1024));
+
+	dev_info(&dev->pdev->dev, ".erasesize = 0x%x(%uK)\n",
+			flash->mtd.erasesize, flash->mtd.erasesize / 1024);
+
+#ifndef CONFIG_OF
+	if (flash_info->partitions) {
+		parts = flash_info->partitions;
+		count = flash_info->nr_partitions;
+	}
+#endif
+	ppdata.of_node = np;
+
+	ret = mtd_device_parse_register(&flash->mtd, NULL, &ppdata, parts,
+					count);
+	if (ret) {
+		dev_err(&dev->pdev->dev, "Err MTD partition=%d\n", ret);
+		goto err_map;
+	}
+
+	return 0;
+
+err_map:
+	iounmap(flash->base_addr);
+
+err_probe:
+	kfree(flash);
+	return ret;
+}
+
+/**
+ * spear_smi_probe - Entry routine
+ * @pdev: platform device structure
+ *
+ * This is the first routine which gets invoked during booting and does all
+ * initialization/allocation work. The routine looks for available memory banks,
+ * and do proper init for any found one.
+ * Returns 0 on success, non zero otherwise
+ */
+static int __devinit spear_smi_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct spear_smi_plat_data *pdata = NULL;
+	struct spear_smi *dev;
+	struct resource *smi_base;
+	int irq, ret = 0;
+	int i;
+
+	if (np) {
+		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+		if (!pdata) {
+			pr_err("%s: ERROR: no memory", __func__);
+			ret = -ENOMEM;
+			goto err;
+		}
+		pdev->dev.platform_data = pdata;
+		ret = spear_smi_probe_config_dt(pdev, np);
+		if (ret) {
+			ret = -ENODEV;
+			dev_err(&pdev->dev, "no platform data\n");
+			goto err;
+		}
+	} else {
+		pdata = dev_get_platdata(&pdev->dev);
+		if (pdata < 0) {
+			ret = -ENODEV;
+			dev_err(&pdev->dev, "no platform data\n");
+			goto err;
+		}
+	}
+
+	smi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!smi_base) {
+		ret = -ENODEV;
+		dev_err(&pdev->dev, "invalid smi base address\n");
+		goto err;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		ret = -ENODEV;
+		dev_err(&pdev->dev, "invalid smi irq\n");
+		goto err;
+	}
+
+	dev = kzalloc(sizeof(*dev), GFP_ATOMIC);
+	if (!dev) {
+		ret = -ENOMEM;
+		dev_err(&pdev->dev, "mem alloc fail\n");
+		goto err;
+	}
+
+	smi_base = request_mem_region(smi_base->start, resource_size(smi_base),
+			pdev->name);
+	if (!smi_base) {
+		ret = -EBUSY;
+		dev_err(&pdev->dev, "request mem region fail\n");
+		goto err_mem;
+	}
+
+	dev->io_base = ioremap(smi_base->start, resource_size(smi_base));
+	if (!dev->io_base) {
+		ret = -EIO;
+		dev_err(&pdev->dev, "ioremap fail\n");
+		goto err_ioremap;
+	}
+
+	dev->pdev = pdev;
+	dev->clk_rate = pdata->clk_rate;
+
+	if (dev->clk_rate < 0 || dev->clk_rate > SMI_MAX_CLOCK_FREQ)
+		dev->clk_rate = SMI_MAX_CLOCK_FREQ;
+
+	dev->num_flashes = pdata->num_flashes;
+
+	if (dev->num_flashes > MAX_NUM_FLASH_CHIP) {
+		dev_err(&pdev->dev, "exceeding max number of flashes\n");
+		dev->num_flashes = MAX_NUM_FLASH_CHIP;
+	}
+
+	dev->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(dev->clk)) {
+		ret = PTR_ERR(dev->clk);
+		goto err_clk;
+	}
+
+	ret = clk_enable(dev->clk);
+	if (ret)
+		goto err_clk_enable;
+
+	ret = request_irq(irq, spear_smi_int_handler, 0, pdev->name, dev);
+	if (ret) {
+		dev_err(&dev->pdev->dev, "SMI IRQ allocation failed\n");
+		goto err_irq;
+	}
+
+	mutex_init(&dev->lock);
+	init_waitqueue_head(&dev->cmd_complete);
+	spear_smi_hw_init(dev);
+	platform_set_drvdata(pdev, dev);
+
+	/* loop for each serial nor-flash which is connected to smi */
+	for (i = 0; i < dev->num_flashes; i++) {
+		ret = spear_smi_setup_banks(pdev, i, pdata->np[i]);
+		if (ret) {
+			dev_err(&dev->pdev->dev, "bank setup failed\n");
+			goto err_bank_setup;
+		}
+	}
+
+	return 0;
+
+err_bank_setup:
+	free_irq(irq, dev);
+	platform_set_drvdata(pdev, NULL);
+err_irq:
+	clk_disable(dev->clk);
+err_clk_enable:
+	clk_put(dev->clk);
+err_clk:
+	iounmap(dev->io_base);
+err_ioremap:
+	release_mem_region(smi_base->start, resource_size(smi_base));
+err_mem:
+	kfree(dev);
+err:
+	return ret;
+}
+
+/**
+ * spear_smi_remove - Exit routine
+ * @pdev: platform device structure
+ *
+ * free all allocations and delete the partitions.
+ */
+static int __devexit spear_smi_remove(struct platform_device *pdev)
+{
+	struct spear_smi *dev;
+	struct spear_smi_plat_data *pdata;
+	struct spear_snor_flash *flash;
+	struct resource *smi_base;
+	int ret;
+	int i, irq;
+
+	dev = platform_get_drvdata(pdev);
+	if (!dev) {
+		dev_err(&pdev->dev, "dev is null\n");
+		return -ENODEV;
+	}
+
+	pdata = dev_get_platdata(&pdev->dev);
+
+	/* clean up for all nor flash */
+	for (i = 0; i < dev->num_flashes; i++) {
+		flash = dev->flash[i];
+		if (!flash)
+			continue;
+
+		/* clean up mtd stuff */
+		ret = mtd_device_unregister(&flash->mtd);
+		if (ret)
+			dev_err(&pdev->dev, "error removing mtd\n");
+
+		iounmap(flash->base_addr);
+		kfree(flash);
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	free_irq(irq, dev);
+
+	clk_disable(dev->clk);
+	clk_put(dev->clk);
+	iounmap(dev->io_base);
+	kfree(dev);
+
+	smi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(smi_base->start, resource_size(smi_base));
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+int spear_smi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct spear_smi *dev = platform_get_drvdata(pdev);
+
+	if (dev && dev->clk)
+		clk_disable(dev->clk);
+
+	return 0;
+}
+
+int spear_smi_resume(struct platform_device *pdev)
+{
+	struct spear_smi *dev = platform_get_drvdata(pdev);
+	int ret = -EPERM;
+
+	if (dev && dev->clk)
+		ret = clk_enable(dev->clk);
+
+	if (!ret)
+		spear_smi_hw_init(dev);
+	return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id spear_smi_id_table[] = {
+	{ .compatible = "st,spear600-smi" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, spear_smi_id_table);
+#endif
+
+static struct platform_driver spear_smi_driver = {
+	.driver = {
+		.name = "smi",
+		.bus = &platform_bus_type,
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(spear_smi_id_table),
+	},
+	.probe = spear_smi_probe,
+	.remove = __devexit_p(spear_smi_remove),
+	.suspend = spear_smi_suspend,
+	.resume = spear_smi_resume,
+};
+
+static int spear_smi_init(void)
+{
+	return platform_driver_register(&spear_smi_driver);
+}
+module_init(spear_smi_init);
+
+static void spear_smi_exit(void)
+{
+	platform_driver_unregister(&spear_smi_driver);
+}
+module_exit(spear_smi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ashish Priyadarshi, Shiraz Hashim <shiraz.hashim@st.com>");
+MODULE_DESCRIPTION("MTD SMI driver for serial nor flash chips");
diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c
index 5fc1983..ab8a2f4 100644
--- a/drivers/mtd/devices/sst25l.c
+++ b/drivers/mtd/devices/sst25l.c
@@ -175,9 +175,6 @@
 	int err;
 
 	/* Sanity checks */
-	if (instr->addr + instr->len > flash->mtd.size)
-		return -EINVAL;
-
 	if ((uint32_t)instr->len % mtd->erasesize)
 		return -EINVAL;
 
@@ -223,16 +220,6 @@
 	unsigned char command[4];
 	int ret;
 
-	/* Sanity checking */
-	if (len == 0)
-		return 0;
-
-	if (from + len > flash->mtd.size)
-		return -EINVAL;
-
-	if (retlen)
-		*retlen = 0;
-
 	spi_message_init(&message);
 	memset(&transfer, 0, sizeof(transfer));
 
@@ -274,13 +261,6 @@
 	int i, j, ret, bytes, copied = 0;
 	unsigned char command[5];
 
-	/* Sanity checks */
-	if (!len)
-		return 0;
-
-	if (to + len > flash->mtd.size)
-		return -EINVAL;
-
 	if ((uint32_t)to % mtd->writesize)
 		return -EINVAL;
 
@@ -402,10 +382,11 @@
 	flash->mtd.flags	= MTD_CAP_NORFLASH;
 	flash->mtd.erasesize	= flash_info->erase_size;
 	flash->mtd.writesize	= flash_info->page_size;
+	flash->mtd.writebufsize	= flash_info->page_size;
 	flash->mtd.size		= flash_info->page_size * flash_info->nr_pages;
-	flash->mtd.erase	= sst25l_erase;
-	flash->mtd.read		= sst25l_read;
-	flash->mtd.write 	= sst25l_write;
+	flash->mtd._erase	= sst25l_erase;
+	flash->mtd._read		= sst25l_read;
+	flash->mtd._write 	= sst25l_write;
 
 	dev_info(&spi->dev, "%s (%lld KiB)\n", flash_info->name,
 		 (long long)flash->mtd.size >> 10);
@@ -418,9 +399,9 @@
 	      flash->mtd.numeraseregions);
 
 
-	ret = mtd_device_parse_register(&flash->mtd, NULL, 0,
-			data ? data->parts : NULL,
-			data ? data->nr_parts : 0);
+	ret = mtd_device_parse_register(&flash->mtd, NULL, NULL,
+					data ? data->parts : NULL,
+					data ? data->nr_parts : 0);
 	if (ret) {
 		kfree(flash);
 		dev_set_drvdata(&spi->dev, NULL);
@@ -450,18 +431,7 @@
 	.remove		= __devexit_p(sst25l_remove),
 };
 
-static int __init sst25l_init(void)
-{
-	return spi_register_driver(&sst25l_driver);
-}
-
-static void __exit sst25l_exit(void)
-{
-	spi_unregister_driver(&sst25l_driver);
-}
-
-module_init(sst25l_init);
-module_exit(sst25l_exit);
+module_spi_driver(sst25l_driver);
 
 MODULE_DESCRIPTION("MTD SPI driver for SST25L Flash chips");
 MODULE_AUTHOR("Andre Renaud <andre@bluewatersys.com>, "
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index 28646c9..3af3514 100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
@@ -56,7 +56,7 @@
 	if (memcmp(mtd->name, "DiskOnChip", 10))
 		return;
 
-	if (!mtd->block_isbad) {
+	if (!mtd->_block_isbad) {
 		printk(KERN_ERR
 "INFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
 "Please use the new diskonchip driver under the NAND subsystem.\n");
diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c
index 536bbce..d3cfe26b 100644
--- a/drivers/mtd/lpddr/lpddr_cmds.c
+++ b/drivers/mtd/lpddr/lpddr_cmds.c
@@ -40,7 +40,7 @@
 static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
 static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
 			size_t *retlen, void **mtdbuf, resource_size_t *phys);
-static void lpddr_unpoint(struct mtd_info *mtd, loff_t adr, size_t len);
+static int lpddr_unpoint(struct mtd_info *mtd, loff_t adr, size_t len);
 static int get_chip(struct map_info *map, struct flchip *chip, int mode);
 static int chip_ready(struct map_info *map, struct flchip *chip, int mode);
 static void put_chip(struct map_info *map, struct flchip *chip);
@@ -63,18 +63,18 @@
 	mtd->type = MTD_NORFLASH;
 
 	/* Fill in the default mtd operations */
-	mtd->read = lpddr_read;
+	mtd->_read = lpddr_read;
 	mtd->type = MTD_NORFLASH;
 	mtd->flags = MTD_CAP_NORFLASH;
 	mtd->flags &= ~MTD_BIT_WRITEABLE;
-	mtd->erase = lpddr_erase;
-	mtd->write = lpddr_write_buffers;
-	mtd->writev = lpddr_writev;
-	mtd->lock = lpddr_lock;
-	mtd->unlock = lpddr_unlock;
+	mtd->_erase = lpddr_erase;
+	mtd->_write = lpddr_write_buffers;
+	mtd->_writev = lpddr_writev;
+	mtd->_lock = lpddr_lock;
+	mtd->_unlock = lpddr_unlock;
 	if (map_is_linear(map)) {
-		mtd->point = lpddr_point;
-		mtd->unpoint = lpddr_unpoint;
+		mtd->_point = lpddr_point;
+		mtd->_unpoint = lpddr_unpoint;
 	}
 	mtd->size = 1 << lpddr->qinfo->DevSizeShift;
 	mtd->erasesize = 1 << lpddr->qinfo->UniformBlockSizeShift;
@@ -530,14 +530,12 @@
 	struct flchip *chip = &lpddr->chips[chipnum];
 	int ret = 0;
 
-	if (!map->virt || (adr + len > mtd->size))
+	if (!map->virt)
 		return -EINVAL;
 
 	/* ofs: offset within the first chip that the first read should start */
 	ofs = adr - (chipnum << lpddr->chipshift);
-
 	*mtdbuf = (void *)map->virt + chip->start + ofs;
-	*retlen = 0;
 
 	while (len) {
 		unsigned long thislen;
@@ -575,11 +573,11 @@
 	return 0;
 }
 
-static void lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len)
+static int lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len)
 {
 	struct map_info *map = mtd->priv;
 	struct lpddr_private *lpddr = map->fldrv_priv;
-	int chipnum = adr >> lpddr->chipshift;
+	int chipnum = adr >> lpddr->chipshift, err = 0;
 	unsigned long ofs;
 
 	/* ofs: offset within the first chip that the first read should start */
@@ -603,9 +601,11 @@
 			chip->ref_point_counter--;
 			if (chip->ref_point_counter == 0)
 				chip->state = FL_READY;
-		} else
+		} else {
 			printk(KERN_WARNING "%s: Warning: unpoint called on non"
 					"pointed region\n", map->name);
+			err = -EINVAL;
+		}
 
 		put_chip(map, chip);
 		mutex_unlock(&chip->mutex);
@@ -614,6 +614,8 @@
 		ofs = 0;
 		chipnum++;
 	}
+
+	return err;
 }
 
 static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
@@ -637,13 +639,11 @@
 	int chipnum;
 	unsigned long ofs, vec_seek, i;
 	int wbufsize = 1 << lpddr->qinfo->BufSizeShift;
-
 	size_t len = 0;
 
 	for (i = 0; i < count; i++)
 		len += vecs[i].iov_len;
 
-	*retlen = 0;
 	if (!len)
 		return 0;
 
@@ -688,9 +688,6 @@
 	ofs = instr->addr;
 	len = instr->len;
 
-	if (ofs > mtd->size || (len + ofs) > mtd->size)
-		return -EINVAL;
-
 	while (len > 0) {
 		ret = do_erase_oneblock(mtd, ofs);
 		if (ret)
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 6c5c431..8af67cf 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -1,5 +1,6 @@
 menu "Mapping drivers for chip access"
 	depends on MTD!=n
+	depends on HAS_IOMEM
 
 config MTD_COMPLEX_MAPPINGS
 	bool "Support non-linear mappings of flash chips"
diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c
index 650126c..ef5cde8 100644
--- a/drivers/mtd/maps/bfin-async-flash.c
+++ b/drivers/mtd/maps/bfin-async-flash.c
@@ -164,8 +164,8 @@
 		return -ENXIO;
 	}
 
-	mtd_device_parse_register(state->mtd, part_probe_types, 0,
-			pdata->parts, pdata->nr_parts);
+	mtd_device_parse_register(state->mtd, part_probe_types, NULL,
+				  pdata->parts, pdata->nr_parts);
 
 	platform_set_drvdata(pdev, state);
 
diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c
index f43b365..080f060 100644
--- a/drivers/mtd/maps/dc21285.c
+++ b/drivers/mtd/maps/dc21285.c
@@ -196,7 +196,7 @@
 
 	dc21285_mtd->owner = THIS_MODULE;
 
-	mtd_device_parse_register(dc21285_mtd, probes, 0, NULL, 0);
+	mtd_device_parse_register(dc21285_mtd, probes, NULL, NULL, 0);
 
 	if(machine_is_ebsa285()) {
 		/*
diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c
index 33cce89..e4de96b 100644
--- a/drivers/mtd/maps/gpio-addr-flash.c
+++ b/drivers/mtd/maps/gpio-addr-flash.c
@@ -252,8 +252,8 @@
 	}
 
 
-	mtd_device_parse_register(state->mtd, part_probe_types, 0,
-			pdata->parts, pdata->nr_parts);
+	mtd_device_parse_register(state->mtd, part_probe_types, NULL,
+				  pdata->parts, pdata->nr_parts);
 
 	return 0;
 }
diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c
index 49c1418..8ed6cb4 100644
--- a/drivers/mtd/maps/h720x-flash.c
+++ b/drivers/mtd/maps/h720x-flash.c
@@ -85,8 +85,8 @@
 	if (mymtd) {
 		mymtd->owner = THIS_MODULE;
 
-		mtd_device_parse_register(mymtd, NULL, 0,
-				h720x_partitions, NUM_PARTITIONS);
+		mtd_device_parse_register(mymtd, NULL, NULL,
+					  h720x_partitions, NUM_PARTITIONS);
 		return 0;
 	}
 
diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c
index f47aedb..834a06c 100644
--- a/drivers/mtd/maps/impa7.c
+++ b/drivers/mtd/maps/impa7.c
@@ -91,7 +91,7 @@
 		if (impa7_mtd[i]) {
 			impa7_mtd[i]->owner = THIS_MODULE;
 			devicesfound++;
-			mtd_device_parse_register(impa7_mtd[i], NULL, 0,
+			mtd_device_parse_register(impa7_mtd[i], NULL, NULL,
 						  partitions,
 						  ARRAY_SIZE(partitions));
 		}
diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c
index 08c2396..92e1f41 100644
--- a/drivers/mtd/maps/intel_vr_nor.c
+++ b/drivers/mtd/maps/intel_vr_nor.c
@@ -72,7 +72,7 @@
 {
 	/* register the flash bank */
 	/* partition the flash bank */
-	return mtd_device_parse_register(p->info, NULL, 0, NULL, 0);
+	return mtd_device_parse_register(p->info, NULL, NULL, NULL, 0);
 }
 
 static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c
index fc7d4d0..4a41ced 100644
--- a/drivers/mtd/maps/ixp2000.c
+++ b/drivers/mtd/maps/ixp2000.c
@@ -226,7 +226,7 @@
 	}
 	info->mtd->owner = THIS_MODULE;
 
-	err = mtd_device_parse_register(info->mtd, probes, 0, NULL, 0);
+	err = mtd_device_parse_register(info->mtd, probes, NULL, NULL, 0);
 	if (err)
 		goto Error;
 
diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c
index 8b54101..e864fc6 100644
--- a/drivers/mtd/maps/ixp4xx.c
+++ b/drivers/mtd/maps/ixp4xx.c
@@ -182,6 +182,9 @@
 {
 	struct flash_platform_data *plat = dev->dev.platform_data;
 	struct ixp4xx_flash_info *info;
+	struct mtd_part_parser_data ppdata = {
+		.origin = dev->resource->start,
+	};
 	int err = -1;
 
 	if (!plat)
@@ -247,7 +250,7 @@
 	/* Use the fast version */
 	info->map.write = ixp4xx_write16;
 
-	err = mtd_device_parse_register(info->mtd, probes, dev->resource->start,
+	err = mtd_device_parse_register(info->mtd, probes, &ppdata,
 			plat->parts, plat->nr_parts);
 	if (err) {
 		printk(KERN_ERR "Could not parse partitions\n");
diff --git a/drivers/mtd/maps/l440gx.c b/drivers/mtd/maps/l440gx.c
index dd0360b..74bd98e 100644
--- a/drivers/mtd/maps/l440gx.c
+++ b/drivers/mtd/maps/l440gx.c
@@ -27,17 +27,21 @@
 
 
 /* Is this really the vpp port? */
+static DEFINE_SPINLOCK(l440gx_vpp_lock);
+static int l440gx_vpp_refcnt;
 static void l440gx_set_vpp(struct map_info *map, int vpp)
 {
-	unsigned long l;
+	unsigned long flags;
 
-	l = inl(VPP_PORT);
+	spin_lock_irqsave(&l440gx_vpp_lock, flags);
 	if (vpp) {
-		l |= 1;
+		if (++l440gx_vpp_refcnt == 1)   /* first nested 'on' */
+			outl(inl(VPP_PORT) | 1, VPP_PORT);
 	} else {
-		l &= ~1;
+		if (--l440gx_vpp_refcnt == 0)   /* last nested 'off' */
+			outl(inl(VPP_PORT) & ~1, VPP_PORT);
 	}
-	outl(l, VPP_PORT);
+	spin_unlock_irqrestore(&l440gx_vpp_lock, flags);
 }
 
 static struct map_info l440gx_map = {
diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c
index 7b889de..b5401e3 100644
--- a/drivers/mtd/maps/lantiq-flash.c
+++ b/drivers/mtd/maps/lantiq-flash.c
@@ -45,6 +45,7 @@
 };
 
 static char ltq_map_name[] = "ltq_nor";
+static const char *ltq_probe_types[] __devinitconst = { "cmdlinepart", NULL };
 
 static map_word
 ltq_read16(struct map_info *map, unsigned long adr)
@@ -168,8 +169,9 @@
 	cfi->addr_unlock1 ^= 1;
 	cfi->addr_unlock2 ^= 1;
 
-	err = mtd_device_parse_register(ltq_mtd->mtd, NULL, 0,
-			ltq_mtd_data->parts, ltq_mtd_data->nr_parts);
+	err = mtd_device_parse_register(ltq_mtd->mtd, ltq_probe_types, NULL,
+					ltq_mtd_data->parts,
+					ltq_mtd_data->nr_parts);
 	if (err) {
 		dev_err(&pdev->dev, "failed to add partitions\n");
 		goto err_destroy;
diff --git a/drivers/mtd/maps/latch-addr-flash.c b/drivers/mtd/maps/latch-addr-flash.c
index 8fed58e..3c7ad17 100644
--- a/drivers/mtd/maps/latch-addr-flash.c
+++ b/drivers/mtd/maps/latch-addr-flash.c
@@ -199,8 +199,9 @@
 	}
 	info->mtd->owner = THIS_MODULE;
 
-	mtd_device_parse_register(info->mtd, NULL, 0,
-			latch_addr_data->parts, latch_addr_data->nr_parts);
+	mtd_device_parse_register(info->mtd, NULL, NULL,
+				  latch_addr_data->parts,
+				  latch_addr_data->nr_parts);
 	return 0;
 
 iounmap:
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index e8e9fec..a3cfad3 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -14,7 +14,6 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
@@ -295,13 +294,24 @@
 }
 
 
+static DEFINE_SPINLOCK(pcmcia_vpp_lock);
+static int pcmcia_vpp_refcnt;
 static void pcmciamtd_set_vpp(struct map_info *map, int on)
 {
 	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
 	struct pcmcia_device *link = dev->p_dev;
+	unsigned long flags;
 
 	pr_debug("dev = %p on = %d vpp = %d\n\n", dev, on, dev->vpp);
-	pcmcia_fixup_vpp(link, on ? dev->vpp : 0);
+	spin_lock_irqsave(&pcmcia_vpp_lock, flags);
+	if (on) {
+		if (++pcmcia_vpp_refcnt == 1)   /* first nested 'on' */
+			pcmcia_fixup_vpp(link, dev->vpp);
+	} else {
+		if (--pcmcia_vpp_refcnt == 0)   /* last nested 'off' */
+			pcmcia_fixup_vpp(link, 0);
+	}
+	spin_unlock_irqrestore(&pcmcia_vpp_lock, flags);
 }
 
 
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index abc5626..21b0b71 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -27,6 +27,8 @@
 	struct mtd_info		*mtd[MAX_RESOURCES];
 	struct mtd_info		*cmtd;
 	struct map_info		map[MAX_RESOURCES];
+	spinlock_t		vpp_lock;
+	int			vpp_refcnt;
 };
 
 static int physmap_flash_remove(struct platform_device *dev)
@@ -63,12 +65,26 @@
 {
 	struct platform_device *pdev;
 	struct physmap_flash_data *physmap_data;
+	struct physmap_flash_info *info;
+	unsigned long flags;
 
 	pdev = (struct platform_device *)map->map_priv_1;
 	physmap_data = pdev->dev.platform_data;
 
-	if (physmap_data->set_vpp)
-		physmap_data->set_vpp(pdev, state);
+	if (!physmap_data->set_vpp)
+		return;
+
+	info = platform_get_drvdata(pdev);
+
+	spin_lock_irqsave(&info->vpp_lock, flags);
+	if (state) {
+		if (++info->vpp_refcnt == 1)    /* first nested 'on' */
+			physmap_data->set_vpp(pdev, 1);
+	} else {
+		if (--info->vpp_refcnt == 0)    /* last nested 'off' */
+			physmap_data->set_vpp(pdev, 0);
+	}
+	spin_unlock_irqrestore(&info->vpp_lock, flags);
 }
 
 static const char *rom_probe_types[] = {
@@ -172,9 +188,11 @@
 	if (err)
 		goto err_out;
 
+	spin_lock_init(&info->vpp_lock);
+
 	part_types = physmap_data->part_probe_types ? : part_probe_types;
 
-	mtd_device_parse_register(info->cmtd, part_types, 0,
+	mtd_device_parse_register(info->cmtd, part_types, NULL,
 				  physmap_data->parts, physmap_data->nr_parts);
 	return 0;
 
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c
index 45876d0..891558d 100644
--- a/drivers/mtd/maps/plat-ram.c
+++ b/drivers/mtd/maps/plat-ram.c
@@ -222,8 +222,9 @@
 	/* check to see if there are any available partitions, or wether
 	 * to add this device whole */
 
-	err = mtd_device_parse_register(info->mtd, pdata->probes, 0,
-			pdata->partitions, pdata->nr_partitions);
+	err = mtd_device_parse_register(info->mtd, pdata->probes, NULL,
+					pdata->partitions,
+					pdata->nr_partitions);
 	if (!err)
 		dev_info(&pdev->dev, "registered mtd device\n");
 
diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c
index 436d121..81884c2 100644
--- a/drivers/mtd/maps/pxa2xx-flash.c
+++ b/drivers/mtd/maps/pxa2xx-flash.c
@@ -98,7 +98,8 @@
 	}
 	info->mtd->owner = THIS_MODULE;
 
-	mtd_device_parse_register(info->mtd, probes, 0, flash->parts, flash->nr_parts);
+	mtd_device_parse_register(info->mtd, probes, NULL, flash->parts,
+				  flash->nr_parts);
 
 	platform_set_drvdata(pdev, info);
 	return 0;
diff --git a/drivers/mtd/maps/rbtx4939-flash.c b/drivers/mtd/maps/rbtx4939-flash.c
index 3da63fc..6f52e1f 100644
--- a/drivers/mtd/maps/rbtx4939-flash.c
+++ b/drivers/mtd/maps/rbtx4939-flash.c
@@ -102,8 +102,8 @@
 	info->mtd->owner = THIS_MODULE;
 	if (err)
 		goto err_out;
-	err = mtd_device_parse_register(info->mtd, NULL, 0,
-			pdata->parts, pdata->nr_parts);
+	err = mtd_device_parse_register(info->mtd, NULL, NULL, pdata->parts,
+					pdata->nr_parts);
 
 	if (err)
 		goto err_out;
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
index 5028219..a675bdb 100644
--- a/drivers/mtd/maps/sa1100-flash.c
+++ b/drivers/mtd/maps/sa1100-flash.c
@@ -23,106 +23,6 @@
 #include <asm/sizes.h>
 #include <asm/mach/flash.h>
 
-#if 0
-/*
- * This is here for documentation purposes only - until these people
- * submit their machine types.  It will be gone January 2005.
- */
-static struct mtd_partition consus_partitions[] = {
-	{
-		.name		= "Consus boot firmware",
-		.offset		= 0,
-		.size		= 0x00040000,
-		.mask_flags	= MTD_WRITABLE, /* force read-only */
-	}, {
-		.name		= "Consus kernel",
-		.offset		= 0x00040000,
-		.size		= 0x00100000,
-		.mask_flags	= 0,
-	}, {
-		.name		= "Consus disk",
-		.offset		= 0x00140000,
-		/* The rest (up to 16M) for jffs.  We could put 0 and
-		   make it find the size automatically, but right now
-		   i have 32 megs.  jffs will use all 32 megs if given
-		   the chance, and this leads to horrible problems
-		   when you try to re-flash the image because blob
-		   won't erase the whole partition. */
-		.size		= 0x01000000 - 0x00140000,
-		.mask_flags	= 0,
-	}, {
-		/* this disk is a secondary disk, which can be used as
-		   needed, for simplicity, make it the size of the other
-		   consus partition, although realistically it could be
-		   the remainder of the disk (depending on the file
-		   system used) */
-		 .name		= "Consus disk2",
-		 .offset	= 0x01000000,
-		 .size		= 0x01000000 - 0x00140000,
-		 .mask_flags	= 0,
-	}
-};
-
-/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
-static struct mtd_partition frodo_partitions[] =
-{
-	{
-		.name		= "bootloader",
-		.size		= 0x00040000,
-		.offset		= 0x00000000,
-		.mask_flags	= MTD_WRITEABLE
-	}, {
-		.name		= "bootloader params",
-		.size		= 0x00040000,
-		.offset		= MTDPART_OFS_APPEND,
-		.mask_flags	= MTD_WRITEABLE
-	}, {
-		.name		= "kernel",
-		.size		= 0x00100000,
-		.offset		= MTDPART_OFS_APPEND,
-		.mask_flags	= MTD_WRITEABLE
-	}, {
-		.name		= "ramdisk",
-		.size		= 0x00400000,
-		.offset		= MTDPART_OFS_APPEND,
-		.mask_flags	= MTD_WRITEABLE
-	}, {
-		.name		= "file system",
-		.size		= MTDPART_SIZ_FULL,
-		.offset		= MTDPART_OFS_APPEND
-	}
-};
-
-static struct mtd_partition jornada56x_partitions[] = {
-	{
-		.name		= "bootldr",
-		.size		= 0x00040000,
-		.offset		= 0,
-		.mask_flags	= MTD_WRITEABLE,
-	}, {
-		.name		= "rootfs",
-		.size		= MTDPART_SIZ_FULL,
-		.offset		= MTDPART_OFS_APPEND,
-	}
-};
-
-static void jornada56x_set_vpp(int vpp)
-{
-	if (vpp)
-		GPSR = GPIO_GPIO26;
-	else
-		GPCR = GPIO_GPIO26;
-	GPDR |= GPIO_GPIO26;
-}
-
-/*
- * Machine        Phys          Size    set_vpp
- * Consus    : SA1100_CS0_PHYS SZ_32M
- * Frodo     : SA1100_CS0_PHYS SZ_32M
- * Jornada56x: SA1100_CS0_PHYS SZ_32M jornada56x_set_vpp
- */
-#endif
-
 struct sa_subdev_info {
 	char name[16];
 	struct map_info map;
@@ -136,10 +36,22 @@
 	struct sa_subdev_info	subdev[0];
 };
 
+static DEFINE_SPINLOCK(sa1100_vpp_lock);
+static int sa1100_vpp_refcnt;
 static void sa1100_set_vpp(struct map_info *map, int on)
 {
 	struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
-	subdev->plat->set_vpp(on);
+	unsigned long flags;
+
+	spin_lock_irqsave(&sa1100_vpp_lock, flags);
+	if (on) {
+		if (++sa1100_vpp_refcnt == 1)   /* first nested 'on' */
+			subdev->plat->set_vpp(1);
+	} else {
+		if (--sa1100_vpp_refcnt == 0)   /* last nested 'off' */
+			subdev->plat->set_vpp(0);
+	}
+	spin_unlock_irqrestore(&sa1100_vpp_lock, flags);
 }
 
 static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
@@ -352,8 +264,8 @@
 	/*
 	 * Partition selection stuff.
 	 */
-	mtd_device_parse_register(info->mtd, part_probes, 0,
-			plat->parts, plat->nr_parts);
+	mtd_device_parse_register(info->mtd, part_probes, NULL, plat->parts,
+				  plat->nr_parts);
 
 	platform_set_drvdata(pdev, info);
 	err = 0;
@@ -373,21 +285,9 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static void sa1100_mtd_shutdown(struct platform_device *dev)
-{
-	struct sa_info *info = platform_get_drvdata(dev);
-	if (info && mtd_suspend(info->mtd) == 0)
-		mtd_resume(info->mtd);
-}
-#else
-#define sa1100_mtd_shutdown NULL
-#endif
-
 static struct platform_driver sa1100_mtd_driver = {
 	.probe		= sa1100_mtd_probe,
 	.remove		= __exit_p(sa1100_mtd_remove),
-	.shutdown	= sa1100_mtd_shutdown,
 	.driver		= {
 		.name	= "sa1100-mtd",
 		.owner	= THIS_MODULE,
diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c
index 496c407..9d900ad 100644
--- a/drivers/mtd/maps/solutionengine.c
+++ b/drivers/mtd/maps/solutionengine.c
@@ -92,8 +92,8 @@
 		mtd_device_register(eprom_mtd, NULL, 0);
 	}
 
-	mtd_device_parse_register(flash_mtd, probes, 0,
-			superh_se_partitions, NUM_PARTITIONS);
+	mtd_device_parse_register(flash_mtd, probes, NULL,
+				  superh_se_partitions, NUM_PARTITIONS);
 
 	return 0;
 }
diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c
index 6793074..cfff454 100644
--- a/drivers/mtd/maps/uclinux.c
+++ b/drivers/mtd/maps/uclinux.c
@@ -85,7 +85,7 @@
 	}
 
 	mtd->owner = THIS_MODULE;
-	mtd->point = uclinux_point;
+	mtd->_point = uclinux_point;
 	mtd->priv = mapp;
 
 	uclinux_ram_mtdinfo = mtd;
diff --git a/drivers/mtd/maps/vmu-flash.c b/drivers/mtd/maps/vmu-flash.c
index 3a04b07..2e2b094 100644
--- a/drivers/mtd/maps/vmu-flash.c
+++ b/drivers/mtd/maps/vmu-flash.c
@@ -360,9 +360,6 @@
 	int index = 0, retval, partition, leftover, numblocks;
 	unsigned char cx;
 
-	if (len < 1)
-		return -EIO;
-
 	mpart = mtd->priv;
 	mdev = mpart->mdev;
 	partition = mpart->partition;
@@ -434,11 +431,6 @@
 	partition = mpart->partition;
 	card = maple_get_drvdata(mdev);
 
-	/* simple sanity checks */
-	if (len < 1) {
-		error = -EIO;
-		goto failed;
-	}
 	numblocks = card->parts[partition].numblocks;
 	if (to + len > numblocks * card->blocklen)
 		len = numblocks * card->blocklen - to;
@@ -544,9 +536,9 @@
 	mtd_cur->flags = MTD_WRITEABLE|MTD_NO_ERASE;
 	mtd_cur->size = part_cur->numblocks * card->blocklen;
 	mtd_cur->erasesize = card->blocklen;
-	mtd_cur->write = vmu_flash_write;
-	mtd_cur->read = vmu_flash_read;
-	mtd_cur->sync = vmu_flash_sync;
+	mtd_cur->_write = vmu_flash_write;
+	mtd_cur->_read = vmu_flash_read;
+	mtd_cur->_sync = vmu_flash_sync;
 	mtd_cur->writesize = card->blocklen;
 
 	mpart = kmalloc(sizeof(struct mdev_part), GFP_KERNEL);
diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c
index aa7e0cb..71b0ba7 100644
--- a/drivers/mtd/maps/wr_sbc82xx_flash.c
+++ b/drivers/mtd/maps/wr_sbc82xx_flash.c
@@ -142,7 +142,7 @@
 			nr_parts = ARRAY_SIZE(smallflash_parts);
 		}
 
-		mtd_device_parse_register(sbcmtd[i], part_probes, 0,
+		mtd_device_parse_register(sbcmtd[i], part_probes, NULL,
 					  defparts, nr_parts);
 	}
 	return 0;
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 424ca5f..f1f0671 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -233,6 +233,7 @@
 	ret = __get_mtd_device(dev->mtd);
 	if (ret)
 		goto error_release;
+	dev->file_mode = mode;
 
 unlock:
 	dev->open++;
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index af65912..6c6d807 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -321,8 +321,12 @@
 	mutex_unlock(&mtdblk->cache_mutex);
 
 	if (!--mtdblk->count) {
-		/* It was the last usage. Free the cache */
-		mtd_sync(mbd->mtd);
+		/*
+		 * It was the last usage. Free the cache, but only sync if
+		 * opened for writing.
+		 */
+		if (mbd->file_mode & FMODE_WRITE)
+			mtd_sync(mbd->mtd);
 		vfree(mtdblk->cache_data);
 	}
 
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 50c6a1e..94eb05b 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -31,15 +31,14 @@
 #include <linux/compat.h>
 #include <linux/mount.h>
 #include <linux/blkpg.h>
+#include <linux/magic.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/map.h>
 
 #include <asm/uaccess.h>
 
-#define MTD_INODE_FS_MAGIC 0x11307854
 static DEFINE_MUTEX(mtd_mutex);
-static struct vfsmount *mtd_inode_mnt __read_mostly;
 
 /*
  * Data structure to hold the pointer to the mtd device as well
@@ -75,7 +74,9 @@
 	return -EINVAL;
 }
 
-
+static int count;
+static struct vfsmount *mnt;
+static struct file_system_type mtd_inodefs_type;
 
 static int mtdchar_open(struct inode *inode, struct file *file)
 {
@@ -92,6 +93,10 @@
 	if ((file->f_mode & FMODE_WRITE) && (minor & 1))
 		return -EACCES;
 
+	ret = simple_pin_fs(&mtd_inodefs_type, &mnt, &count);
+	if (ret)
+		return ret;
+
 	mutex_lock(&mtd_mutex);
 	mtd = get_mtd_device(NULL, devnum);
 
@@ -106,7 +111,7 @@
 		goto out;
 	}
 
-	mtd_ino = iget_locked(mtd_inode_mnt->mnt_sb, devnum);
+	mtd_ino = iget_locked(mnt->mnt_sb, devnum);
 	if (!mtd_ino) {
 		put_mtd_device(mtd);
 		ret = -ENOMEM;
@@ -141,6 +146,7 @@
 
 out:
 	mutex_unlock(&mtd_mutex);
+	simple_release_fs(&mnt, &count);
 	return ret;
 } /* mtdchar_open */
 
@@ -162,6 +168,7 @@
 	put_mtd_device(mtd);
 	file->private_data = NULL;
 	kfree(mfi);
+	simple_release_fs(&mnt, &count);
 
 	return 0;
 } /* mtdchar_close */
@@ -405,7 +412,7 @@
 	if (length > 4096)
 		return -EINVAL;
 
-	if (!mtd->write_oob)
+	if (!mtd->_write_oob)
 		ret = -EOPNOTSUPP;
 	else
 		ret = access_ok(VERIFY_READ, ptr, length) ? 0 : -EFAULT;
@@ -576,7 +583,7 @@
 			!access_ok(VERIFY_READ, req.usr_data, req.len) ||
 			!access_ok(VERIFY_READ, req.usr_oob, req.ooblen))
 		return -EFAULT;
-	if (!mtd->write_oob)
+	if (!mtd->_write_oob)
 		return -EOPNOTSUPP;
 
 	ops.mode = req.mode;
@@ -1175,10 +1182,15 @@
 #endif
 };
 
+static const struct super_operations mtd_ops = {
+	.drop_inode = generic_delete_inode,
+	.statfs = simple_statfs,
+};
+
 static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type,
 				int flags, const char *dev_name, void *data)
 {
-	return mount_pseudo(fs_type, "mtd_inode:", NULL, NULL, MTD_INODE_FS_MAGIC);
+	return mount_pseudo(fs_type, "mtd_inode:", &mtd_ops, NULL, MTD_INODE_FS_MAGIC);
 }
 
 static struct file_system_type mtd_inodefs_type = {
@@ -1187,26 +1199,6 @@
        .kill_sb = kill_anon_super,
 };
 
-static void mtdchar_notify_add(struct mtd_info *mtd)
-{
-}
-
-static void mtdchar_notify_remove(struct mtd_info *mtd)
-{
-	struct inode *mtd_ino = ilookup(mtd_inode_mnt->mnt_sb, mtd->index);
-
-	if (mtd_ino) {
-		/* Destroy the inode if it exists */
-		clear_nlink(mtd_ino);
-		iput(mtd_ino);
-	}
-}
-
-static struct mtd_notifier mtdchar_notifier = {
-	.add = mtdchar_notify_add,
-	.remove = mtdchar_notify_remove,
-};
-
 static int __init init_mtdchar(void)
 {
 	int ret;
@@ -1224,19 +1216,8 @@
 		pr_notice("Can't register mtd_inodefs filesystem: %d\n", ret);
 		goto err_unregister_chdev;
 	}
-
-	mtd_inode_mnt = kern_mount(&mtd_inodefs_type);
-	if (IS_ERR(mtd_inode_mnt)) {
-		ret = PTR_ERR(mtd_inode_mnt);
-		pr_notice("Error mounting mtd_inodefs filesystem: %d\n", ret);
-		goto err_unregister_filesystem;
-	}
-	register_mtd_user(&mtdchar_notifier);
-
 	return ret;
 
-err_unregister_filesystem:
-	unregister_filesystem(&mtd_inodefs_type);
 err_unregister_chdev:
 	__unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd");
 	return ret;
@@ -1244,8 +1225,6 @@
 
 static void __exit cleanup_mtdchar(void)
 {
-	unregister_mtd_user(&mtdchar_notifier);
-	kern_unmount(mtd_inode_mnt);
 	unregister_filesystem(&mtd_inodefs_type);
 	__unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd");
 }
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 1ed5103..b900056 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -72,8 +72,6 @@
 	int ret = 0, err;
 	int i;
 
-	*retlen = 0;
-
 	for (i = 0; i < concat->num_subdev; i++) {
 		struct mtd_info *subdev = concat->subdev[i];
 		size_t size, retsize;
@@ -126,11 +124,6 @@
 	int err = -EINVAL;
 	int i;
 
-	if (!(mtd->flags & MTD_WRITEABLE))
-		return -EROFS;
-
-	*retlen = 0;
-
 	for (i = 0; i < concat->num_subdev; i++) {
 		struct mtd_info *subdev = concat->subdev[i];
 		size_t size, retsize;
@@ -145,11 +138,7 @@
 		else
 			size = len;
 
-		if (!(subdev->flags & MTD_WRITEABLE))
-			err = -EROFS;
-		else
-			err = mtd_write(subdev, to, size, &retsize, buf);
-
+		err = mtd_write(subdev, to, size, &retsize, buf);
 		if (err)
 			break;
 
@@ -176,19 +165,10 @@
 	int i;
 	int err = -EINVAL;
 
-	if (!(mtd->flags & MTD_WRITEABLE))
-		return -EROFS;
-
-	*retlen = 0;
-
 	/* Calculate total length of data */
 	for (i = 0; i < count; i++)
 		total_len += vecs[i].iov_len;
 
-	/* Do not allow write past end of device */
-	if ((to + total_len) > mtd->size)
-		return -EINVAL;
-
 	/* Check alignment */
 	if (mtd->writesize > 1) {
 		uint64_t __to = to;
@@ -224,12 +204,8 @@
 		old_iov_len = vecs_copy[entry_high].iov_len;
 		vecs_copy[entry_high].iov_len = size;
 
-		if (!(subdev->flags & MTD_WRITEABLE))
-			err = -EROFS;
-		else
-			err = mtd_writev(subdev, &vecs_copy[entry_low],
-					 entry_high - entry_low + 1, to,
-					 &retsize);
+		err = mtd_writev(subdev, &vecs_copy[entry_low],
+				 entry_high - entry_low + 1, to, &retsize);
 
 		vecs_copy[entry_high].iov_len = old_iov_len - size;
 		vecs_copy[entry_high].iov_base += size;
@@ -403,15 +379,6 @@
 	uint64_t length, offset = 0;
 	struct erase_info *erase;
 
-	if (!(mtd->flags & MTD_WRITEABLE))
-		return -EROFS;
-
-	if (instr->addr > concat->mtd.size)
-		return -EINVAL;
-
-	if (instr->len + instr->addr > concat->mtd.size)
-		return -EINVAL;
-
 	/*
 	 * Check for proper erase block alignment of the to-be-erased area.
 	 * It is easier to do this based on the super device's erase
@@ -459,8 +426,6 @@
 			return -EINVAL;
 	}
 
-	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
-
 	/* make a local copy of instr to avoid modifying the caller's struct */
 	erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
 
@@ -499,10 +464,6 @@
 		else
 			erase->len = length;
 
-		if (!(subdev->flags & MTD_WRITEABLE)) {
-			err = -EROFS;
-			break;
-		}
 		length -= erase->len;
 		if ((err = concat_dev_erase(subdev, erase))) {
 			/* sanity check: should never happen since
@@ -538,9 +499,6 @@
 	struct mtd_concat *concat = CONCAT(mtd);
 	int i, err = -EINVAL;
 
-	if ((len + ofs) > mtd->size)
-		return -EINVAL;
-
 	for (i = 0; i < concat->num_subdev; i++) {
 		struct mtd_info *subdev = concat->subdev[i];
 		uint64_t size;
@@ -575,9 +533,6 @@
 	struct mtd_concat *concat = CONCAT(mtd);
 	int i, err = 0;
 
-	if ((len + ofs) > mtd->size)
-		return -EINVAL;
-
 	for (i = 0; i < concat->num_subdev; i++) {
 		struct mtd_info *subdev = concat->subdev[i];
 		uint64_t size;
@@ -650,9 +605,6 @@
 	if (!mtd_can_have_bb(concat->subdev[0]))
 		return res;
 
-	if (ofs > mtd->size)
-		return -EINVAL;
-
 	for (i = 0; i < concat->num_subdev; i++) {
 		struct mtd_info *subdev = concat->subdev[i];
 
@@ -673,12 +625,6 @@
 	struct mtd_concat *concat = CONCAT(mtd);
 	int i, err = -EINVAL;
 
-	if (!mtd_can_have_bb(concat->subdev[0]))
-		return 0;
-
-	if (ofs > mtd->size)
-		return -EINVAL;
-
 	for (i = 0; i < concat->num_subdev; i++) {
 		struct mtd_info *subdev = concat->subdev[i];
 
@@ -716,10 +662,6 @@
 			continue;
 		}
 
-		/* we've found the subdev over which the mapping will reside */
-		if (offset + len > subdev->size)
-			return (unsigned long) -EINVAL;
-
 		return mtd_get_unmapped_area(subdev, len, offset, flags);
 	}
 
@@ -777,16 +719,16 @@
 	concat->mtd.subpage_sft = subdev[0]->subpage_sft;
 	concat->mtd.oobsize = subdev[0]->oobsize;
 	concat->mtd.oobavail = subdev[0]->oobavail;
-	if (subdev[0]->writev)
-		concat->mtd.writev = concat_writev;
-	if (subdev[0]->read_oob)
-		concat->mtd.read_oob = concat_read_oob;
-	if (subdev[0]->write_oob)
-		concat->mtd.write_oob = concat_write_oob;
-	if (subdev[0]->block_isbad)
-		concat->mtd.block_isbad = concat_block_isbad;
-	if (subdev[0]->block_markbad)
-		concat->mtd.block_markbad = concat_block_markbad;
+	if (subdev[0]->_writev)
+		concat->mtd._writev = concat_writev;
+	if (subdev[0]->_read_oob)
+		concat->mtd._read_oob = concat_read_oob;
+	if (subdev[0]->_write_oob)
+		concat->mtd._write_oob = concat_write_oob;
+	if (subdev[0]->_block_isbad)
+		concat->mtd._block_isbad = concat_block_isbad;
+	if (subdev[0]->_block_markbad)
+		concat->mtd._block_markbad = concat_block_markbad;
 
 	concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
 
@@ -833,8 +775,8 @@
 		if (concat->mtd.writesize   !=  subdev[i]->writesize ||
 		    concat->mtd.subpage_sft != subdev[i]->subpage_sft ||
 		    concat->mtd.oobsize    !=  subdev[i]->oobsize ||
-		    !concat->mtd.read_oob  != !subdev[i]->read_oob ||
-		    !concat->mtd.write_oob != !subdev[i]->write_oob) {
+		    !concat->mtd._read_oob  != !subdev[i]->_read_oob ||
+		    !concat->mtd._write_oob != !subdev[i]->_write_oob) {
 			kfree(concat);
 			printk("Incompatible OOB or ECC data on \"%s\"\n",
 			       subdev[i]->name);
@@ -849,15 +791,15 @@
 	concat->num_subdev = num_devs;
 	concat->mtd.name = name;
 
-	concat->mtd.erase = concat_erase;
-	concat->mtd.read = concat_read;
-	concat->mtd.write = concat_write;
-	concat->mtd.sync = concat_sync;
-	concat->mtd.lock = concat_lock;
-	concat->mtd.unlock = concat_unlock;
-	concat->mtd.suspend = concat_suspend;
-	concat->mtd.resume = concat_resume;
-	concat->mtd.get_unmapped_area = concat_get_unmapped_area;
+	concat->mtd._erase = concat_erase;
+	concat->mtd._read = concat_read;
+	concat->mtd._write = concat_write;
+	concat->mtd._sync = concat_sync;
+	concat->mtd._lock = concat_lock;
+	concat->mtd._unlock = concat_unlock;
+	concat->mtd._suspend = concat_suspend;
+	concat->mtd._resume = concat_resume;
+	concat->mtd._get_unmapped_area = concat_get_unmapped_area;
 
 	/*
 	 * Combine the erase block size info of the subdevices:
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 9a9ce71..c837507 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -107,7 +107,7 @@
  */
 static void mtd_release(struct device *dev)
 {
-	struct mtd_info *mtd = dev_get_drvdata(dev);
+	struct mtd_info __maybe_unused *mtd = dev_get_drvdata(dev);
 	dev_t index = MTD_DEVT(mtd->index);
 
 	/* remove /dev/mtdXro node if needed */
@@ -126,7 +126,7 @@
 {
 	struct mtd_info *mtd = dev_get_drvdata(dev);
 
-	if (mtd && mtd->resume)
+	if (mtd)
 		mtd_resume(mtd);
 	return 0;
 }
@@ -610,8 +610,8 @@
 	if (!try_module_get(mtd->owner))
 		return -ENODEV;
 
-	if (mtd->get_device) {
-		err = mtd->get_device(mtd);
+	if (mtd->_get_device) {
+		err = mtd->_get_device(mtd);
 
 		if (err) {
 			module_put(mtd->owner);
@@ -675,14 +675,267 @@
 	--mtd->usecount;
 	BUG_ON(mtd->usecount < 0);
 
-	if (mtd->put_device)
-		mtd->put_device(mtd);
+	if (mtd->_put_device)
+		mtd->_put_device(mtd);
 
 	module_put(mtd->owner);
 }
 EXPORT_SYMBOL_GPL(__put_mtd_device);
 
 /*
+ * Erase is an asynchronous operation.  Device drivers are supposed
+ * to call instr->callback() whenever the operation completes, even
+ * if it completes with a failure.
+ * Callers are supposed to pass a callback function and wait for it
+ * to be called before writing to the block.
+ */
+int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr)
+		return -EINVAL;
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
+	if (!instr->len) {
+		instr->state = MTD_ERASE_DONE;
+		mtd_erase_callback(instr);
+		return 0;
+	}
+	return mtd->_erase(mtd, instr);
+}
+EXPORT_SYMBOL_GPL(mtd_erase);
+
+/*
+ * This stuff for eXecute-In-Place. phys is optional and may be set to NULL.
+ */
+int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
+	      void **virt, resource_size_t *phys)
+{
+	*retlen = 0;
+	*virt = NULL;
+	if (phys)
+		*phys = 0;
+	if (!mtd->_point)
+		return -EOPNOTSUPP;
+	if (from < 0 || from > mtd->size || len > mtd->size - from)
+		return -EINVAL;
+	if (!len)
+		return 0;
+	return mtd->_point(mtd, from, len, retlen, virt, phys);
+}
+EXPORT_SYMBOL_GPL(mtd_point);
+
+/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
+int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
+{
+	if (!mtd->_point)
+		return -EOPNOTSUPP;
+	if (from < 0 || from > mtd->size || len > mtd->size - from)
+		return -EINVAL;
+	if (!len)
+		return 0;
+	return mtd->_unpoint(mtd, from, len);
+}
+EXPORT_SYMBOL_GPL(mtd_unpoint);
+
+/*
+ * Allow NOMMU mmap() to directly map the device (if not NULL)
+ * - return the address to which the offset maps
+ * - return -ENOSYS to indicate refusal to do the mapping
+ */
+unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len,
+				    unsigned long offset, unsigned long flags)
+{
+	if (!mtd->_get_unmapped_area)
+		return -EOPNOTSUPP;
+	if (offset > mtd->size || len > mtd->size - offset)
+		return -EINVAL;
+	return mtd->_get_unmapped_area(mtd, len, offset, flags);
+}
+EXPORT_SYMBOL_GPL(mtd_get_unmapped_area);
+
+int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
+	     u_char *buf)
+{
+	*retlen = 0;
+	if (from < 0 || from > mtd->size || len > mtd->size - from)
+		return -EINVAL;
+	if (!len)
+		return 0;
+	return mtd->_read(mtd, from, len, retlen, buf);
+}
+EXPORT_SYMBOL_GPL(mtd_read);
+
+int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
+	      const u_char *buf)
+{
+	*retlen = 0;
+	if (to < 0 || to > mtd->size || len > mtd->size - to)
+		return -EINVAL;
+	if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	if (!len)
+		return 0;
+	return mtd->_write(mtd, to, len, retlen, buf);
+}
+EXPORT_SYMBOL_GPL(mtd_write);
+
+/*
+ * In blackbox flight recorder like scenarios we want to make successful writes
+ * in interrupt context. panic_write() is only intended to be called when its
+ * known the kernel is about to panic and we need the write to succeed. Since
+ * the kernel is not going to be running for much longer, this function can
+ * break locks and delay to ensure the write succeeds (but not sleep).
+ */
+int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
+		    const u_char *buf)
+{
+	*retlen = 0;
+	if (!mtd->_panic_write)
+		return -EOPNOTSUPP;
+	if (to < 0 || to > mtd->size || len > mtd->size - to)
+		return -EINVAL;
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	if (!len)
+		return 0;
+	return mtd->_panic_write(mtd, to, len, retlen, buf);
+}
+EXPORT_SYMBOL_GPL(mtd_panic_write);
+
+/*
+ * Method to access the protection register area, present in some flash
+ * devices. The user data is one time programmable but the factory data is read
+ * only.
+ */
+int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
+			   size_t len)
+{
+	if (!mtd->_get_fact_prot_info)
+		return -EOPNOTSUPP;
+	if (!len)
+		return 0;
+	return mtd->_get_fact_prot_info(mtd, buf, len);
+}
+EXPORT_SYMBOL_GPL(mtd_get_fact_prot_info);
+
+int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
+			   size_t *retlen, u_char *buf)
+{
+	*retlen = 0;
+	if (!mtd->_read_fact_prot_reg)
+		return -EOPNOTSUPP;
+	if (!len)
+		return 0;
+	return mtd->_read_fact_prot_reg(mtd, from, len, retlen, buf);
+}
+EXPORT_SYMBOL_GPL(mtd_read_fact_prot_reg);
+
+int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf,
+			   size_t len)
+{
+	if (!mtd->_get_user_prot_info)
+		return -EOPNOTSUPP;
+	if (!len)
+		return 0;
+	return mtd->_get_user_prot_info(mtd, buf, len);
+}
+EXPORT_SYMBOL_GPL(mtd_get_user_prot_info);
+
+int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
+			   size_t *retlen, u_char *buf)
+{
+	*retlen = 0;
+	if (!mtd->_read_user_prot_reg)
+		return -EOPNOTSUPP;
+	if (!len)
+		return 0;
+	return mtd->_read_user_prot_reg(mtd, from, len, retlen, buf);
+}
+EXPORT_SYMBOL_GPL(mtd_read_user_prot_reg);
+
+int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
+			    size_t *retlen, u_char *buf)
+{
+	*retlen = 0;
+	if (!mtd->_write_user_prot_reg)
+		return -EOPNOTSUPP;
+	if (!len)
+		return 0;
+	return mtd->_write_user_prot_reg(mtd, to, len, retlen, buf);
+}
+EXPORT_SYMBOL_GPL(mtd_write_user_prot_reg);
+
+int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len)
+{
+	if (!mtd->_lock_user_prot_reg)
+		return -EOPNOTSUPP;
+	if (!len)
+		return 0;
+	return mtd->_lock_user_prot_reg(mtd, from, len);
+}
+EXPORT_SYMBOL_GPL(mtd_lock_user_prot_reg);
+
+/* Chip-supported device locking */
+int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+	if (!mtd->_lock)
+		return -EOPNOTSUPP;
+	if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
+		return -EINVAL;
+	if (!len)
+		return 0;
+	return mtd->_lock(mtd, ofs, len);
+}
+EXPORT_SYMBOL_GPL(mtd_lock);
+
+int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+	if (!mtd->_unlock)
+		return -EOPNOTSUPP;
+	if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
+		return -EINVAL;
+	if (!len)
+		return 0;
+	return mtd->_unlock(mtd, ofs, len);
+}
+EXPORT_SYMBOL_GPL(mtd_unlock);
+
+int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+	if (!mtd->_is_locked)
+		return -EOPNOTSUPP;
+	if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
+		return -EINVAL;
+	if (!len)
+		return 0;
+	return mtd->_is_locked(mtd, ofs, len);
+}
+EXPORT_SYMBOL_GPL(mtd_is_locked);
+
+int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
+{
+	if (!mtd->_block_isbad)
+		return 0;
+	if (ofs < 0 || ofs > mtd->size)
+		return -EINVAL;
+	return mtd->_block_isbad(mtd, ofs);
+}
+EXPORT_SYMBOL_GPL(mtd_block_isbad);
+
+int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+	if (!mtd->_block_markbad)
+		return -EOPNOTSUPP;
+	if (ofs < 0 || ofs > mtd->size)
+		return -EINVAL;
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	return mtd->_block_markbad(mtd, ofs);
+}
+EXPORT_SYMBOL_GPL(mtd_block_markbad);
+
+/*
  * default_mtd_writev - the default writev method
  * @mtd: mtd device description object pointer
  * @vecs: the vectors to write
@@ -729,9 +982,11 @@
 	       unsigned long count, loff_t to, size_t *retlen)
 {
 	*retlen = 0;
-	if (!mtd->writev)
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	if (!mtd->_writev)
 		return default_mtd_writev(mtd, vecs, count, to, retlen);
-	return mtd->writev(mtd, vecs, count, to, retlen);
+	return mtd->_writev(mtd, vecs, count, to, retlen);
 }
 EXPORT_SYMBOL_GPL(mtd_writev);
 
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 3ce99e0..ae36d7e 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -169,7 +169,7 @@
 			cxt->nextpage = 0;
 	}
 
-	while (mtd_can_have_bb(mtd)) {
+	while (1) {
 		ret = mtd_block_isbad(mtd, cxt->nextpage * record_size);
 		if (!ret)
 			break;
@@ -199,9 +199,9 @@
 		return;
 	}
 
-	if (mtd_can_have_bb(mtd) && ret == -EIO) {
+	if (ret == -EIO) {
 		ret = mtd_block_markbad(mtd, cxt->nextpage * record_size);
-		if (ret < 0) {
+		if (ret < 0 && ret != -EOPNOTSUPP) {
 			printk(KERN_ERR "mtdoops: block_markbad failed, aborting\n");
 			return;
 		}
@@ -257,8 +257,7 @@
 	size_t retlen;
 
 	for (page = 0; page < cxt->oops_pages; page++) {
-		if (mtd_can_have_bb(mtd) &&
-		    mtd_block_isbad(mtd, page * record_size))
+		if (mtd_block_isbad(mtd, page * record_size))
 			continue;
 		/* Assume the page is used */
 		mark_page_used(cxt, page);
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index a3d44c3..9651c06 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -65,12 +65,8 @@
 	int res;
 
 	stats = part->master->ecc_stats;
-
-	if (from >= mtd->size)
-		len = 0;
-	else if (from + len > mtd->size)
-		len = mtd->size - from;
-	res = mtd_read(part->master, from + part->offset, len, retlen, buf);
+	res = part->master->_read(part->master, from + part->offset, len,
+				  retlen, buf);
 	if (unlikely(res)) {
 		if (mtd_is_bitflip(res))
 			mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
@@ -84,19 +80,16 @@
 		size_t *retlen, void **virt, resource_size_t *phys)
 {
 	struct mtd_part *part = PART(mtd);
-	if (from >= mtd->size)
-		len = 0;
-	else if (from + len > mtd->size)
-		len = mtd->size - from;
-	return mtd_point(part->master, from + part->offset, len, retlen,
-			 virt, phys);
+
+	return part->master->_point(part->master, from + part->offset, len,
+				    retlen, virt, phys);
 }
 
-static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
+static int part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
 	struct mtd_part *part = PART(mtd);
 
-	mtd_unpoint(part->master, from + part->offset, len);
+	return part->master->_unpoint(part->master, from + part->offset, len);
 }
 
 static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
@@ -107,7 +100,8 @@
 	struct mtd_part *part = PART(mtd);
 
 	offset += part->offset;
-	return mtd_get_unmapped_area(part->master, len, offset, flags);
+	return part->master->_get_unmapped_area(part->master, len, offset,
+						flags);
 }
 
 static int part_read_oob(struct mtd_info *mtd, loff_t from,
@@ -138,7 +132,7 @@
 			return -EINVAL;
 	}
 
-	res = mtd_read_oob(part->master, from + part->offset, ops);
+	res = part->master->_read_oob(part->master, from + part->offset, ops);
 	if (unlikely(res)) {
 		if (mtd_is_bitflip(res))
 			mtd->ecc_stats.corrected++;
@@ -152,55 +146,46 @@
 		size_t len, size_t *retlen, u_char *buf)
 {
 	struct mtd_part *part = PART(mtd);
-	return mtd_read_user_prot_reg(part->master, from, len, retlen, buf);
+	return part->master->_read_user_prot_reg(part->master, from, len,
+						 retlen, buf);
 }
 
 static int part_get_user_prot_info(struct mtd_info *mtd,
 		struct otp_info *buf, size_t len)
 {
 	struct mtd_part *part = PART(mtd);
-	return mtd_get_user_prot_info(part->master, buf, len);
+	return part->master->_get_user_prot_info(part->master, buf, len);
 }
 
 static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
 		size_t len, size_t *retlen, u_char *buf)
 {
 	struct mtd_part *part = PART(mtd);
-	return mtd_read_fact_prot_reg(part->master, from, len, retlen, buf);
+	return part->master->_read_fact_prot_reg(part->master, from, len,
+						 retlen, buf);
 }
 
 static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
 		size_t len)
 {
 	struct mtd_part *part = PART(mtd);
-	return mtd_get_fact_prot_info(part->master, buf, len);
+	return part->master->_get_fact_prot_info(part->master, buf, len);
 }
 
 static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
 		size_t *retlen, const u_char *buf)
 {
 	struct mtd_part *part = PART(mtd);
-	if (!(mtd->flags & MTD_WRITEABLE))
-		return -EROFS;
-	if (to >= mtd->size)
-		len = 0;
-	else if (to + len > mtd->size)
-		len = mtd->size - to;
-	return mtd_write(part->master, to + part->offset, len, retlen, buf);
+	return part->master->_write(part->master, to + part->offset, len,
+				    retlen, buf);
 }
 
 static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
 		size_t *retlen, const u_char *buf)
 {
 	struct mtd_part *part = PART(mtd);
-	if (!(mtd->flags & MTD_WRITEABLE))
-		return -EROFS;
-	if (to >= mtd->size)
-		len = 0;
-	else if (to + len > mtd->size)
-		len = mtd->size - to;
-	return mtd_panic_write(part->master, to + part->offset, len, retlen,
-			       buf);
+	return part->master->_panic_write(part->master, to + part->offset, len,
+					  retlen, buf);
 }
 
 static int part_write_oob(struct mtd_info *mtd, loff_t to,
@@ -208,50 +193,43 @@
 {
 	struct mtd_part *part = PART(mtd);
 
-	if (!(mtd->flags & MTD_WRITEABLE))
-		return -EROFS;
-
 	if (to >= mtd->size)
 		return -EINVAL;
 	if (ops->datbuf && to + ops->len > mtd->size)
 		return -EINVAL;
-	return mtd_write_oob(part->master, to + part->offset, ops);
+	return part->master->_write_oob(part->master, to + part->offset, ops);
 }
 
 static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
 		size_t len, size_t *retlen, u_char *buf)
 {
 	struct mtd_part *part = PART(mtd);
-	return mtd_write_user_prot_reg(part->master, from, len, retlen, buf);
+	return part->master->_write_user_prot_reg(part->master, from, len,
+						  retlen, buf);
 }
 
 static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
 		size_t len)
 {
 	struct mtd_part *part = PART(mtd);
-	return mtd_lock_user_prot_reg(part->master, from, len);
+	return part->master->_lock_user_prot_reg(part->master, from, len);
 }
 
 static int part_writev(struct mtd_info *mtd, const struct kvec *vecs,
 		unsigned long count, loff_t to, size_t *retlen)
 {
 	struct mtd_part *part = PART(mtd);
-	if (!(mtd->flags & MTD_WRITEABLE))
-		return -EROFS;
-	return mtd_writev(part->master, vecs, count, to + part->offset,
-			  retlen);
+	return part->master->_writev(part->master, vecs, count,
+				     to + part->offset, retlen);
 }
 
 static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
 	struct mtd_part *part = PART(mtd);
 	int ret;
-	if (!(mtd->flags & MTD_WRITEABLE))
-		return -EROFS;
-	if (instr->addr >= mtd->size)
-		return -EINVAL;
+
 	instr->addr += part->offset;
-	ret = mtd_erase(part->master, instr);
+	ret = part->master->_erase(part->master, instr);
 	if (ret) {
 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
 			instr->fail_addr -= part->offset;
@@ -262,7 +240,7 @@
 
 void mtd_erase_callback(struct erase_info *instr)
 {
-	if (instr->mtd->erase == part_erase) {
+	if (instr->mtd->_erase == part_erase) {
 		struct mtd_part *part = PART(instr->mtd);
 
 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
@@ -277,52 +255,44 @@
 static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
 	struct mtd_part *part = PART(mtd);
-	if ((len + ofs) > mtd->size)
-		return -EINVAL;
-	return mtd_lock(part->master, ofs + part->offset, len);
+	return part->master->_lock(part->master, ofs + part->offset, len);
 }
 
 static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
 	struct mtd_part *part = PART(mtd);
-	if ((len + ofs) > mtd->size)
-		return -EINVAL;
-	return mtd_unlock(part->master, ofs + part->offset, len);
+	return part->master->_unlock(part->master, ofs + part->offset, len);
 }
 
 static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
 	struct mtd_part *part = PART(mtd);
-	if ((len + ofs) > mtd->size)
-		return -EINVAL;
-	return mtd_is_locked(part->master, ofs + part->offset, len);
+	return part->master->_is_locked(part->master, ofs + part->offset, len);
 }
 
 static void part_sync(struct mtd_info *mtd)
 {
 	struct mtd_part *part = PART(mtd);
-	mtd_sync(part->master);
+	part->master->_sync(part->master);
 }
 
 static int part_suspend(struct mtd_info *mtd)
 {
 	struct mtd_part *part = PART(mtd);
-	return mtd_suspend(part->master);
+	return part->master->_suspend(part->master);
 }
 
 static void part_resume(struct mtd_info *mtd)
 {
 	struct mtd_part *part = PART(mtd);
-	mtd_resume(part->master);
+	part->master->_resume(part->master);
 }
 
 static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
 {
 	struct mtd_part *part = PART(mtd);
-	if (ofs >= mtd->size)
-		return -EINVAL;
 	ofs += part->offset;
-	return mtd_block_isbad(part->master, ofs);
+	return part->master->_block_isbad(part->master, ofs);
 }
 
 static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
@@ -330,12 +300,8 @@
 	struct mtd_part *part = PART(mtd);
 	int res;
 
-	if (!(mtd->flags & MTD_WRITEABLE))
-		return -EROFS;
-	if (ofs >= mtd->size)
-		return -EINVAL;
 	ofs += part->offset;
-	res = mtd_block_markbad(part->master, ofs);
+	res = part->master->_block_markbad(part->master, ofs);
 	if (!res)
 		mtd->ecc_stats.badblocks++;
 	return res;
@@ -410,54 +376,55 @@
 	 */
 	slave->mtd.dev.parent = master->dev.parent;
 
-	slave->mtd.read = part_read;
-	slave->mtd.write = part_write;
+	slave->mtd._read = part_read;
+	slave->mtd._write = part_write;
 
-	if (master->panic_write)
-		slave->mtd.panic_write = part_panic_write;
+	if (master->_panic_write)
+		slave->mtd._panic_write = part_panic_write;
 
-	if (master->point && master->unpoint) {
-		slave->mtd.point = part_point;
-		slave->mtd.unpoint = part_unpoint;
+	if (master->_point && master->_unpoint) {
+		slave->mtd._point = part_point;
+		slave->mtd._unpoint = part_unpoint;
 	}
 
-	if (master->get_unmapped_area)
-		slave->mtd.get_unmapped_area = part_get_unmapped_area;
-	if (master->read_oob)
-		slave->mtd.read_oob = part_read_oob;
-	if (master->write_oob)
-		slave->mtd.write_oob = part_write_oob;
-	if (master->read_user_prot_reg)
-		slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
-	if (master->read_fact_prot_reg)
-		slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
-	if (master->write_user_prot_reg)
-		slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
-	if (master->lock_user_prot_reg)
-		slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
-	if (master->get_user_prot_info)
-		slave->mtd.get_user_prot_info = part_get_user_prot_info;
-	if (master->get_fact_prot_info)
-		slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
-	if (master->sync)
-		slave->mtd.sync = part_sync;
-	if (!partno && !master->dev.class && master->suspend && master->resume) {
-			slave->mtd.suspend = part_suspend;
-			slave->mtd.resume = part_resume;
+	if (master->_get_unmapped_area)
+		slave->mtd._get_unmapped_area = part_get_unmapped_area;
+	if (master->_read_oob)
+		slave->mtd._read_oob = part_read_oob;
+	if (master->_write_oob)
+		slave->mtd._write_oob = part_write_oob;
+	if (master->_read_user_prot_reg)
+		slave->mtd._read_user_prot_reg = part_read_user_prot_reg;
+	if (master->_read_fact_prot_reg)
+		slave->mtd._read_fact_prot_reg = part_read_fact_prot_reg;
+	if (master->_write_user_prot_reg)
+		slave->mtd._write_user_prot_reg = part_write_user_prot_reg;
+	if (master->_lock_user_prot_reg)
+		slave->mtd._lock_user_prot_reg = part_lock_user_prot_reg;
+	if (master->_get_user_prot_info)
+		slave->mtd._get_user_prot_info = part_get_user_prot_info;
+	if (master->_get_fact_prot_info)
+		slave->mtd._get_fact_prot_info = part_get_fact_prot_info;
+	if (master->_sync)
+		slave->mtd._sync = part_sync;
+	if (!partno && !master->dev.class && master->_suspend &&
+	    master->_resume) {
+			slave->mtd._suspend = part_suspend;
+			slave->mtd._resume = part_resume;
 	}
-	if (master->writev)
-		slave->mtd.writev = part_writev;
-	if (master->lock)
-		slave->mtd.lock = part_lock;
-	if (master->unlock)
-		slave->mtd.unlock = part_unlock;
-	if (master->is_locked)
-		slave->mtd.is_locked = part_is_locked;
-	if (master->block_isbad)
-		slave->mtd.block_isbad = part_block_isbad;
-	if (master->block_markbad)
-		slave->mtd.block_markbad = part_block_markbad;
-	slave->mtd.erase = part_erase;
+	if (master->_writev)
+		slave->mtd._writev = part_writev;
+	if (master->_lock)
+		slave->mtd._lock = part_lock;
+	if (master->_unlock)
+		slave->mtd._unlock = part_unlock;
+	if (master->_is_locked)
+		slave->mtd._is_locked = part_is_locked;
+	if (master->_block_isbad)
+		slave->mtd._block_isbad = part_block_isbad;
+	if (master->_block_markbad)
+		slave->mtd._block_markbad = part_block_markbad;
+	slave->mtd._erase = part_erase;
 	slave->master = master;
 	slave->offset = part->offset;
 
@@ -549,7 +516,8 @@
 	}
 
 	slave->mtd.ecclayout = master->ecclayout;
-	if (master->block_isbad) {
+	slave->mtd.ecc_strength = master->ecc_strength;
+	if (master->_block_isbad) {
 		uint64_t offs = 0;
 
 		while (offs < slave->mtd.size) {
@@ -761,7 +729,7 @@
 	for ( ; ret <= 0 && *types; types++) {
 		parser = get_partition_parser(*types);
 		if (!parser && !request_module("%s", *types))
-				parser = get_partition_parser(*types);
+			parser = get_partition_parser(*types);
 		if (!parser)
 			continue;
 		ret = (*parser->parse_fn)(master, pparts, data);
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 31b034b..7d17cec 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -187,7 +187,7 @@
 
 config MTD_NAND_S3C2410
 	tristate "NAND Flash support for Samsung S3C SoCs"
-	depends on ARCH_S3C2410 || ARCH_S3C64XX
+	depends on ARCH_S3C24XX || ARCH_S3C64XX
 	help
 	  This enables the NAND flash controller on the S3C24xx and S3C64xx
 	  SoCs
@@ -246,6 +246,7 @@
 config MTD_NAND_DISKONCHIP
 	tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
+	depends on HAS_IOMEM
 	select REED_SOLOMON
 	select REED_SOLOMON_DEC16
 	help
@@ -313,6 +314,26 @@
 	  load time (assuming you build diskonchip as a module) with the module
 	  parameter "inftl_bbt_write=1".
 
+config MTD_NAND_DOCG4
+	tristate "Support for DiskOnChip G4 (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	select BCH
+	select BITREVERSE
+	help
+	  Support for diskonchip G4 nand flash, found in various smartphones and
+	  PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba
+	  Portege G900, Asus P526, and O2 XDA Zinc.
+
+	  With this driver you will be able to use UBI and create a ubifs on the
+	  device, so you may wish to consider enabling UBI and UBIFS as well.
+
+	  These devices ship with the Mys/Sandisk SAFTL formatting, for which
+	  there is currently no mtd parser, so you may want to use command line
+	  partitioning to segregate write-protected blocks. On the Treo680, the
+	  first five erase blocks (256KiB each) are write-protected, followed
+	  by the block containing the saftl partition table.  This is probably
+	  typical.
+
 config MTD_NAND_SHARPSL
 	tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
 	depends on ARCH_PXA
@@ -420,7 +441,6 @@
 config MTD_NAND_GPMI_NAND
         bool "GPMI NAND Flash Controller driver"
         depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28)
-	select MTD_CMDLINE_PARTS
         help
 	 Enables NAND Flash support for IMX23 or IMX28.
 	 The GPMI controller is very powerful, with the help of BCH
@@ -431,6 +451,7 @@
 
 config MTD_NAND_PLATFORM
 	tristate "Support for generic platform NAND driver"
+	depends on HAS_IOMEM
 	help
 	  This implements a generic NAND driver for on-SOC platform
 	  devices. You will need to provide platform-specific functions
@@ -462,6 +483,16 @@
 	  Enabling this option will enable you to use this to control
 	  external NAND devices.
 
+config MTD_NAND_FSL_IFC
+	tristate "NAND support for Freescale IFC controller"
+	depends on MTD_NAND && FSL_SOC
+	select FSL_IFC
+	help
+	  Various Freescale chips e.g P1010, include a NAND Flash machine
+	  with built-in hardware ECC capabilities.
+	  Enabling this option will enable you to use this to control
+	  external NAND devices.
+
 config MTD_NAND_FSL_UPM
 	tristate "Support for NAND on Freescale UPM"
 	depends on PPC_83xx || PPC_85xx
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 618f4ba..d4b4d87 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -19,6 +19,7 @@
 obj-$(CONFIG_MTD_NAND_S3C2410)		+= s3c2410.o
 obj-$(CONFIG_MTD_NAND_DAVINCI)		+= davinci_nand.o
 obj-$(CONFIG_MTD_NAND_DISKONCHIP)	+= diskonchip.o
+obj-$(CONFIG_MTD_NAND_DOCG4)		+= docg4.o
 obj-$(CONFIG_MTD_NAND_FSMC)		+= fsmc_nand.o
 obj-$(CONFIG_MTD_NAND_H1900)		+= h1910.o
 obj-$(CONFIG_MTD_NAND_RTC_FROM4)	+= rtc_from4.o
@@ -37,6 +38,7 @@
 obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
 obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
+obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
 obj-$(CONFIG_MTD_NAND_SH_FLCTL)		+= sh_flctl.o
 obj-$(CONFIG_MTD_NAND_MXC)		+= mxc_nand.o
diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c
index 6a5ff64..4f20e1d 100644
--- a/drivers/mtd/nand/alauda.c
+++ b/drivers/mtd/nand/alauda.c
@@ -585,12 +585,13 @@
 	mtd->writesize = 1<<card->pageshift;
 	mtd->type = MTD_NANDFLASH;
 	mtd->flags = MTD_CAP_NANDFLASH;
-	mtd->read = alauda_read;
-	mtd->write = alauda_write;
-	mtd->erase = alauda_erase;
-	mtd->block_isbad = alauda_isbad;
+	mtd->_read = alauda_read;
+	mtd->_write = alauda_write;
+	mtd->_erase = alauda_erase;
+	mtd->_block_isbad = alauda_isbad;
 	mtd->priv = al;
 	mtd->owner = THIS_MODULE;
+	mtd->ecc_strength = 1;
 
 	err = mtd_device_register(mtd, NULL, 0);
 	if (err) {
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
index 3197e97..7341695 100644
--- a/drivers/mtd/nand/ams-delta.c
+++ b/drivers/mtd/nand/ams-delta.c
@@ -26,7 +26,7 @@
 #include <asm/io.h>
 #include <mach/hardware.h>
 #include <asm/sizes.h>
-#include <asm/gpio.h>
+#include <linux/gpio.h>
 #include <plat/board-ams-delta.h>
 
 /*
@@ -34,8 +34,6 @@
  */
 static struct mtd_info *ams_delta_mtd = NULL;
 
-#define NAND_MASK (AMS_DELTA_LATCH2_NAND_NRE | AMS_DELTA_LATCH2_NAND_NWE | AMS_DELTA_LATCH2_NAND_CLE | AMS_DELTA_LATCH2_NAND_ALE | AMS_DELTA_LATCH2_NAND_NCE | AMS_DELTA_LATCH2_NAND_NWP)
-
 /*
  * Define partitions for flash devices
  */
@@ -68,10 +66,9 @@
 
 	writew(0, io_base + OMAP_MPUIO_IO_CNTL);
 	writew(byte, this->IO_ADDR_W);
-	ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0);
+	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 0);
 	ndelay(40);
-	ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE,
-			       AMS_DELTA_LATCH2_NAND_NWE);
+	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 1);
 }
 
 static u_char ams_delta_read_byte(struct mtd_info *mtd)
@@ -80,12 +77,11 @@
 	struct nand_chip *this = mtd->priv;
 	void __iomem *io_base = this->priv;
 
-	ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0);
+	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 0);
 	ndelay(40);
 	writew(~0, io_base + OMAP_MPUIO_IO_CNTL);
 	res = readw(this->IO_ADDR_R);
-	ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE,
-			       AMS_DELTA_LATCH2_NAND_NRE);
+	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 1);
 
 	return res;
 }
@@ -132,15 +128,12 @@
 {
 
 	if (ctrl & NAND_CTRL_CHANGE) {
-		unsigned long bits;
-
-		bits = (~ctrl & NAND_NCE) ? AMS_DELTA_LATCH2_NAND_NCE : 0;
-		bits |= (ctrl & NAND_CLE) ? AMS_DELTA_LATCH2_NAND_CLE : 0;
-		bits |= (ctrl & NAND_ALE) ? AMS_DELTA_LATCH2_NAND_ALE : 0;
-
-		ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE |
-				AMS_DELTA_LATCH2_NAND_ALE |
-				AMS_DELTA_LATCH2_NAND_NCE, bits);
+		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NCE,
+				(ctrl & NAND_NCE) == 0);
+		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_CLE,
+				(ctrl & NAND_CLE) != 0);
+		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_ALE,
+				(ctrl & NAND_ALE) != 0);
 	}
 
 	if (cmd != NAND_CMD_NONE)
@@ -152,6 +145,39 @@
 	return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB);
 }
 
+static const struct gpio _mandatory_gpio[] = {
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NCE,
+		.flags	= GPIOF_OUT_INIT_HIGH,
+		.label	= "nand_nce",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NRE,
+		.flags	= GPIOF_OUT_INIT_HIGH,
+		.label	= "nand_nre",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NWP,
+		.flags	= GPIOF_OUT_INIT_HIGH,
+		.label	= "nand_nwp",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NWE,
+		.flags	= GPIOF_OUT_INIT_HIGH,
+		.label	= "nand_nwe",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_NAND_ALE,
+		.flags	= GPIOF_OUT_INIT_LOW,
+		.label	= "nand_ale",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_NAND_CLE,
+		.flags	= GPIOF_OUT_INIT_LOW,
+		.label	= "nand_cle",
+	},
+};
+
 /*
  * Main initialization routine
  */
@@ -223,10 +249,9 @@
 	platform_set_drvdata(pdev, io_base);
 
 	/* Set chip enabled, but  */
-	ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE |
-					  AMS_DELTA_LATCH2_NAND_NWE |
-					  AMS_DELTA_LATCH2_NAND_NCE |
-					  AMS_DELTA_LATCH2_NAND_NWP);
+	err = gpio_request_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
+	if (err)
+		goto out_gpio;
 
 	/* Scan to find existence of the device */
 	if (nand_scan(ams_delta_mtd, 1)) {
@@ -241,7 +266,10 @@
 	goto out;
 
  out_mtd:
+	gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
+out_gpio:
 	platform_set_drvdata(pdev, NULL);
+	gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
 	iounmap(io_base);
 out_release_io:
 	release_mem_region(res->start, resource_size(res));
@@ -262,6 +290,8 @@
 	/* Release resources, unregister device */
 	nand_release(ams_delta_mtd);
 
+	gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
+	gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
 	iounmap(io_base);
 	release_mem_region(res->start, resource_size(res));
 
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 35b4fb5..2165576 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -27,6 +27,10 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_mtd.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
@@ -34,22 +38,10 @@
 #include <linux/dmaengine.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
+#include <linux/platform_data/atmel.h>
 
-#include <mach/board.h>
 #include <mach/cpu.h>
 
-#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW
-#define hard_ecc	1
-#else
-#define hard_ecc	0
-#endif
-
-#ifdef CONFIG_MTD_NAND_ATMEL_ECC_NONE
-#define no_ecc		1
-#else
-#define no_ecc		0
-#endif
-
 static int use_dma = 1;
 module_param(use_dma, int, 0);
 
@@ -95,7 +87,7 @@
 	struct mtd_info		mtd;
 	void __iomem		*io_base;
 	dma_addr_t		io_phys;
-	struct atmel_nand_data	*board;
+	struct atmel_nand_data	board;
 	struct device		*dev;
 	void __iomem		*ecc;
 
@@ -113,8 +105,8 @@
  */
 static void atmel_nand_enable(struct atmel_nand_host *host)
 {
-	if (gpio_is_valid(host->board->enable_pin))
-		gpio_set_value(host->board->enable_pin, 0);
+	if (gpio_is_valid(host->board.enable_pin))
+		gpio_set_value(host->board.enable_pin, 0);
 }
 
 /*
@@ -122,8 +114,8 @@
  */
 static void atmel_nand_disable(struct atmel_nand_host *host)
 {
-	if (gpio_is_valid(host->board->enable_pin))
-		gpio_set_value(host->board->enable_pin, 1);
+	if (gpio_is_valid(host->board.enable_pin))
+		gpio_set_value(host->board.enable_pin, 1);
 }
 
 /*
@@ -144,9 +136,9 @@
 		return;
 
 	if (ctrl & NAND_CLE)
-		writeb(cmd, host->io_base + (1 << host->board->cle));
+		writeb(cmd, host->io_base + (1 << host->board.cle));
 	else
-		writeb(cmd, host->io_base + (1 << host->board->ale));
+		writeb(cmd, host->io_base + (1 << host->board.ale));
 }
 
 /*
@@ -157,8 +149,8 @@
 	struct nand_chip *nand_chip = mtd->priv;
 	struct atmel_nand_host *host = nand_chip->priv;
 
-	return gpio_get_value(host->board->rdy_pin) ^
-                !!host->board->rdy_pin_active_low;
+	return gpio_get_value(host->board.rdy_pin) ^
+                !!host->board.rdy_pin_active_low;
 }
 
 /*
@@ -273,7 +265,7 @@
 		if (atmel_nand_dma_op(mtd, buf, len, 1) == 0)
 			return;
 
-	if (host->board->bus_width_16)
+	if (host->board.bus_width_16)
 		atmel_read_buf16(mtd, buf, len);
 	else
 		atmel_read_buf8(mtd, buf, len);
@@ -289,7 +281,7 @@
 		if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0)
 			return;
 
-	if (host->board->bus_width_16)
+	if (host->board.bus_width_16)
 		atmel_write_buf16(mtd, buf, len);
 	else
 		atmel_write_buf8(mtd, buf, len);
@@ -481,6 +473,56 @@
 	}
 }
 
+#if defined(CONFIG_OF)
+static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+					 struct device_node *np)
+{
+	u32 val;
+	int ecc_mode;
+	struct atmel_nand_data *board = &host->board;
+	enum of_gpio_flags flags;
+
+	if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) {
+		if (val >= 32) {
+			dev_err(host->dev, "invalid addr-offset %u\n", val);
+			return -EINVAL;
+		}
+		board->ale = val;
+	}
+
+	if (of_property_read_u32(np, "atmel,nand-cmd-offset", &val) == 0) {
+		if (val >= 32) {
+			dev_err(host->dev, "invalid cmd-offset %u\n", val);
+			return -EINVAL;
+		}
+		board->cle = val;
+	}
+
+	ecc_mode = of_get_nand_ecc_mode(np);
+
+	board->ecc_mode = ecc_mode < 0 ? NAND_ECC_SOFT : ecc_mode;
+
+	board->on_flash_bbt = of_get_nand_on_flash_bbt(np);
+
+	if (of_get_nand_bus_width(np) == 16)
+		board->bus_width_16 = 1;
+
+	board->rdy_pin = of_get_gpio_flags(np, 0, &flags);
+	board->rdy_pin_active_low = (flags == OF_GPIO_ACTIVE_LOW);
+
+	board->enable_pin = of_get_gpio(np, 1);
+	board->det_pin = of_get_gpio(np, 2);
+
+	return 0;
+}
+#else
+static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+					 struct device_node *np)
+{
+	return -EINVAL;
+}
+#endif
+
 /*
  * Probe for the NAND device.
  */
@@ -491,6 +533,7 @@
 	struct nand_chip *nand_chip;
 	struct resource *regs;
 	struct resource *mem;
+	struct mtd_part_parser_data ppdata = {};
 	int res;
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -517,8 +560,15 @@
 
 	mtd = &host->mtd;
 	nand_chip = &host->nand_chip;
-	host->board = pdev->dev.platform_data;
 	host->dev = &pdev->dev;
+	if (pdev->dev.of_node) {
+		res = atmel_of_init_port(host, pdev->dev.of_node);
+		if (res)
+			goto err_nand_ioremap;
+	} else {
+		memcpy(&host->board, pdev->dev.platform_data,
+		       sizeof(struct atmel_nand_data));
+	}
 
 	nand_chip->priv = host;		/* link the private data structures */
 	mtd->priv = nand_chip;
@@ -529,36 +579,36 @@
 	nand_chip->IO_ADDR_W = host->io_base;
 	nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
 
-	if (gpio_is_valid(host->board->rdy_pin))
+	if (gpio_is_valid(host->board.rdy_pin))
 		nand_chip->dev_ready = atmel_nand_device_ready;
 
+	nand_chip->ecc.mode = host->board.ecc_mode;
+
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (!regs && hard_ecc) {
+	if (!regs && nand_chip->ecc.mode == NAND_ECC_HW) {
 		printk(KERN_ERR "atmel_nand: can't get I/O resource "
 				"regs\nFalling back on software ECC\n");
+		nand_chip->ecc.mode = NAND_ECC_SOFT;
 	}
 
-	nand_chip->ecc.mode = NAND_ECC_SOFT;	/* enable ECC */
-	if (no_ecc)
-		nand_chip->ecc.mode = NAND_ECC_NONE;
-	if (hard_ecc && regs) {
+	if (nand_chip->ecc.mode == NAND_ECC_HW) {
 		host->ecc = ioremap(regs->start, resource_size(regs));
 		if (host->ecc == NULL) {
 			printk(KERN_ERR "atmel_nand: ioremap failed\n");
 			res = -EIO;
 			goto err_ecc_ioremap;
 		}
-		nand_chip->ecc.mode = NAND_ECC_HW;
 		nand_chip->ecc.calculate = atmel_nand_calculate;
 		nand_chip->ecc.correct = atmel_nand_correct;
 		nand_chip->ecc.hwctl = atmel_nand_hwctl;
 		nand_chip->ecc.read_page = atmel_nand_read_page;
 		nand_chip->ecc.bytes = 4;
+		nand_chip->ecc.strength = 1;
 	}
 
 	nand_chip->chip_delay = 20;		/* 20us command delay time */
 
-	if (host->board->bus_width_16)	/* 16-bit bus width */
+	if (host->board.bus_width_16)	/* 16-bit bus width */
 		nand_chip->options |= NAND_BUSWIDTH_16;
 
 	nand_chip->read_buf = atmel_read_buf;
@@ -567,15 +617,15 @@
 	platform_set_drvdata(pdev, host);
 	atmel_nand_enable(host);
 
-	if (gpio_is_valid(host->board->det_pin)) {
-		if (gpio_get_value(host->board->det_pin)) {
+	if (gpio_is_valid(host->board.det_pin)) {
+		if (gpio_get_value(host->board.det_pin)) {
 			printk(KERN_INFO "No SmartMedia card inserted.\n");
 			res = -ENXIO;
 			goto err_no_card;
 		}
 	}
 
-	if (on_flash_bbt) {
+	if (host->board.on_flash_bbt || on_flash_bbt) {
 		printk(KERN_INFO "atmel_nand: Use On Flash BBT\n");
 		nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
 	}
@@ -650,8 +700,9 @@
 	}
 
 	mtd->name = "atmel_nand";
-	res = mtd_device_parse_register(mtd, NULL, 0,
-			host->board->parts, host->board->num_parts);
+	ppdata.of_node = pdev->dev.of_node;
+	res = mtd_device_parse_register(mtd, NULL, &ppdata,
+			host->board.parts, host->board.num_parts);
 	if (!res)
 		return res;
 
@@ -695,11 +746,21 @@
 	return 0;
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id atmel_nand_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-nand" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids);
+#endif
+
 static struct platform_driver atmel_nand_driver = {
 	.remove		= __exit_p(atmel_nand_remove),
 	.driver		= {
 		.name	= "atmel_nand",
 		.owner	= THIS_MODULE,
+		.of_match_table	= of_match_ptr(atmel_nand_dt_ids),
 	},
 };
 
diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c
index 50387fd..6908cdd 100644
--- a/drivers/mtd/nand/bcm_umi_nand.c
+++ b/drivers/mtd/nand/bcm_umi_nand.c
@@ -31,7 +31,6 @@
 #include <linux/mtd/partitions.h>
 
 #include <asm/mach-types.h>
-#include <asm/system.h>
 
 #include <mach/reg_nand.h>
 #include <mach/reg_umi.h>
@@ -476,6 +475,14 @@
 			largepage_bbt.options = NAND_BBT_SCAN2NDPAGE;
 		this->badblock_pattern = &largepage_bbt;
 	}
+
+	/*
+	 * FIXME: ecc strength value of 6 bits per 512 bytes of data is a
+	 * conservative guess, given 13 ecc bytes and using bch alg.
+	 * (Assume Galois field order m=15 to allow a margin of error.)
+	 */
+	this->ecc.strength = 6;
+
 #endif
 
 	/* Now finish off the scan, now that ecc.layout has been initialized. */
@@ -488,7 +495,7 @@
 
 	/* Register the partitions */
 	board_mtd->name = "bcm_umi-nand";
-	mtd_device_parse_register(board_mtd, NULL, 0, NULL, 0);
+	mtd_device_parse_register(board_mtd, NULL, NULL, NULL, 0);
 
 	/* Return happy */
 	return 0;
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index dd899cb..d7b86b9 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -702,9 +702,11 @@
 		if (likely(mtd->writesize >= 512)) {
 			chip->ecc.size = 512;
 			chip->ecc.bytes = 6;
+			chip->ecc.strength = 2;
 		} else {
 			chip->ecc.size = 256;
 			chip->ecc.bytes = 3;
+			chip->ecc.strength = 1;
 			bfin_write_NFC_CTL(bfin_read_NFC_CTL() & ~(1 << NFC_PG_SIZE_OFFSET));
 			SSYNC();
 		}
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index 72d3f23..2a96e1a 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -783,6 +783,7 @@
 	cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
 	cafe->nand.ecc.size = mtd->writesize;
 	cafe->nand.ecc.bytes = 14;
+	cafe->nand.ecc.strength = 4;
 	cafe->nand.ecc.hwctl  = (void *)cafe_nand_bug;
 	cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
 	cafe->nand.ecc.correct  = (void *)cafe_nand_bug;
@@ -799,7 +800,7 @@
 	pci_set_drvdata(pdev, mtd);
 
 	mtd->name = "cafe_nand";
-	mtd_device_parse_register(mtd, part_probes, 0, NULL, 0);
+	mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
 
 	goto out;
 
diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c
index 737ef9a..1024bfc 100644
--- a/drivers/mtd/nand/cmx270_nand.c
+++ b/drivers/mtd/nand/cmx270_nand.c
@@ -219,7 +219,7 @@
 	}
 
 	/* Register the partitions */
-	ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, 0,
+	ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, NULL,
 					partition_info, NUM_PARTITIONS);
 	if (ret)
 		goto err_scan;
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c
index 414afa7..821c34c 100644
--- a/drivers/mtd/nand/cs553x_nand.c
+++ b/drivers/mtd/nand/cs553x_nand.c
@@ -248,6 +248,8 @@
 		goto out_ior;
 	}
 
+	this->ecc.strength = 1;
+
 	new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs);
 
 	cs553x_mtd[cs] = new_mtd;
@@ -313,7 +315,7 @@
 	for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
 		if (cs553x_mtd[i]) {
 			/* If any devices registered, return success. Else the last error. */
-			mtd_device_parse_register(cs553x_mtd[i], NULL, 0,
+			mtd_device_parse_register(cs553x_mtd[i], NULL, NULL,
 						  NULL, 0);
 			err = 0;
 		}
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index 6e56615..d94b03c 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -641,6 +641,7 @@
 			info->chip.ecc.bytes = 3;
 		}
 		info->chip.ecc.size = 512;
+		info->chip.ecc.strength = pdata->ecc_bits;
 		break;
 	default:
 		ret = -EINVAL;
@@ -752,8 +753,8 @@
 	if (ret < 0)
 		goto err_scan;
 
-	ret = mtd_device_parse_register(&info->mtd, NULL, 0,
-			pdata->parts, pdata->nr_parts);
+	ret = mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts,
+					pdata->nr_parts);
 
 	if (ret < 0)
 		goto err_scan;
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 3984d48..a9e57d6 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1590,6 +1590,7 @@
 			ECC_15BITS * (denali->mtd.writesize /
 			ECC_SECTOR_SIZE)))) {
 		/* if MLC OOB size is large enough, use 15bit ECC*/
+		denali->nand.ecc.strength = 15;
 		denali->nand.ecc.layout = &nand_15bit_oob;
 		denali->nand.ecc.bytes = ECC_15BITS;
 		iowrite32(15, denali->flash_reg + ECC_CORRECTION);
@@ -1600,12 +1601,14 @@
 				" contain 8bit ECC correction codes");
 		goto failed_req_irq;
 	} else {
+		denali->nand.ecc.strength = 8;
 		denali->nand.ecc.layout = &nand_8bit_oob;
 		denali->nand.ecc.bytes = ECC_8BITS;
 		iowrite32(8, denali->flash_reg + ECC_CORRECTION);
 	}
 
 	denali->nand.ecc.bytes *= denali->devnum;
+	denali->nand.ecc.strength *= denali->devnum;
 	denali->nand.ecc.layout->eccbytes *=
 		denali->mtd.writesize / ECC_SECTOR_SIZE;
 	denali->nand.ecc.layout->oobfree[0].offset =
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index df921e7..e2ca067 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -1653,6 +1653,7 @@
 	nand->ecc.mode		= NAND_ECC_HW_SYNDROME;
 	nand->ecc.size		= 512;
 	nand->ecc.bytes		= 6;
+	nand->ecc.strength	= 2;
 	nand->bbt_options	= NAND_BBT_USE_FLASH;
 
 	doc->physadr		= physadr;
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c
new file mode 100644
index 0000000..b082026
--- /dev/null
+++ b/drivers/mtd/nand/docg4.c
@@ -0,0 +1,1377 @@
+/*
+ *  Copyright © 2012 Mike Dunn <mikedunn@newsguy.com>
+ *
+ * mtd nand driver for M-Systems DiskOnChip G4
+ *
+ * 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.
+ *
+ * Tested on the Palm Treo 680.  The G4 is also present on Toshiba Portege, Asus
+ * P526, some HTC smartphones (Wizard, Prophet, ...), O2 XDA Zinc, maybe others.
+ * Should work on these as well.  Let me know!
+ *
+ * TODO:
+ *
+ *  Mechanism for management of password-protected areas
+ *
+ *  Hamming ecc when reading oob only
+ *
+ *  According to the M-Sys documentation, this device is also available in a
+ *  "dual-die" configuration having a 256MB capacity, but no mechanism for
+ *  detecting this variant is documented.  Currently this driver assumes 128MB
+ *  capacity.
+ *
+ *  Support for multiple cascaded devices ("floors").  Not sure which gadgets
+ *  contain multiple G4s in a cascaded configuration, if any.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/bch.h>
+#include <linux/bitrev.h>
+
+/*
+ * You'll want to ignore badblocks if you're reading a partition that contains
+ * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since
+ * it does not use mtd nand's method for marking bad blocks (using oob area).
+ * This will also skip the check of the "page written" flag.
+ */
+static bool ignore_badblocks;
+module_param(ignore_badblocks, bool, 0);
+MODULE_PARM_DESC(ignore_badblocks, "no badblock checking performed");
+
+struct docg4_priv {
+	struct mtd_info	*mtd;
+	struct device *dev;
+	void __iomem *virtadr;
+	int status;
+	struct {
+		unsigned int command;
+		int column;
+		int page;
+	} last_command;
+	uint8_t oob_buf[16];
+	uint8_t ecc_buf[7];
+	int oob_page;
+	struct bch_control *bch;
+};
+
+/*
+ * Defines prefixed with DOCG4 are unique to the diskonchip G4.  All others are
+ * shared with other diskonchip devices (P3, G3 at least).
+ *
+ * Functions with names prefixed with docg4_ are mtd / nand interface functions
+ * (though they may also be called internally).  All others are internal.
+ */
+
+#define DOC_IOSPACE_DATA		0x0800
+
+/* register offsets */
+#define DOC_CHIPID			0x1000
+#define DOC_DEVICESELECT		0x100a
+#define DOC_ASICMODE			0x100c
+#define DOC_DATAEND			0x101e
+#define DOC_NOP				0x103e
+
+#define DOC_FLASHSEQUENCE		0x1032
+#define DOC_FLASHCOMMAND		0x1034
+#define DOC_FLASHADDRESS		0x1036
+#define DOC_FLASHCONTROL		0x1038
+#define DOC_ECCCONF0			0x1040
+#define DOC_ECCCONF1			0x1042
+#define DOC_HAMMINGPARITY		0x1046
+#define DOC_BCH_SYNDROM(idx)		(0x1048 + idx)
+
+#define DOC_ASICMODECONFIRM		0x1072
+#define DOC_CHIPID_INV			0x1074
+#define DOC_POWERMODE			0x107c
+
+#define DOCG4_MYSTERY_REG		0x1050
+
+/* apparently used only to write oob bytes 6 and 7 */
+#define DOCG4_OOB_6_7			0x1052
+
+/* DOC_FLASHSEQUENCE register commands */
+#define DOC_SEQ_RESET			0x00
+#define DOCG4_SEQ_PAGE_READ		0x03
+#define DOCG4_SEQ_FLUSH			0x29
+#define DOCG4_SEQ_PAGEWRITE		0x16
+#define DOCG4_SEQ_PAGEPROG		0x1e
+#define DOCG4_SEQ_BLOCKERASE		0x24
+
+/* DOC_FLASHCOMMAND register commands */
+#define DOCG4_CMD_PAGE_READ             0x00
+#define DOC_CMD_ERASECYCLE2		0xd0
+#define DOCG4_CMD_FLUSH                 0x70
+#define DOCG4_CMD_READ2                 0x30
+#define DOC_CMD_PROG_BLOCK_ADDR		0x60
+#define DOCG4_CMD_PAGEWRITE		0x80
+#define DOC_CMD_PROG_CYCLE2		0x10
+#define DOC_CMD_RESET			0xff
+
+/* DOC_POWERMODE register bits */
+#define DOC_POWERDOWN_READY		0x80
+
+/* DOC_FLASHCONTROL register bits */
+#define DOC_CTRL_CE			0x10
+#define DOC_CTRL_UNKNOWN		0x40
+#define DOC_CTRL_FLASHREADY		0x01
+
+/* DOC_ECCCONF0 register bits */
+#define DOC_ECCCONF0_READ_MODE		0x8000
+#define DOC_ECCCONF0_UNKNOWN		0x2000
+#define DOC_ECCCONF0_ECC_ENABLE	        0x1000
+#define DOC_ECCCONF0_DATA_BYTES_MASK	0x07ff
+
+/* DOC_ECCCONF1 register bits */
+#define DOC_ECCCONF1_BCH_SYNDROM_ERR	0x80
+#define DOC_ECCCONF1_ECC_ENABLE         0x07
+#define DOC_ECCCONF1_PAGE_IS_WRITTEN	0x20
+
+/* DOC_ASICMODE register bits */
+#define DOC_ASICMODE_RESET		0x00
+#define DOC_ASICMODE_NORMAL		0x01
+#define DOC_ASICMODE_POWERDOWN		0x02
+#define DOC_ASICMODE_MDWREN		0x04
+#define DOC_ASICMODE_BDETCT_RESET	0x08
+#define DOC_ASICMODE_RSTIN_RESET	0x10
+#define DOC_ASICMODE_RAM_WE		0x20
+
+/* good status values read after read/write/erase operations */
+#define DOCG4_PROGSTATUS_GOOD          0x51
+#define DOCG4_PROGSTATUS_GOOD_2        0xe0
+
+/*
+ * On read operations (page and oob-only), the first byte read from I/O reg is a
+ * status.  On error, it reads 0x73; otherwise, it reads either 0x71 (first read
+ * after reset only) or 0x51, so bit 1 is presumed to be an error indicator.
+ */
+#define DOCG4_READ_ERROR           0x02 /* bit 1 indicates read error */
+
+/* anatomy of the device */
+#define DOCG4_CHIP_SIZE        0x8000000
+#define DOCG4_PAGE_SIZE        0x200
+#define DOCG4_PAGES_PER_BLOCK  0x200
+#define DOCG4_BLOCK_SIZE       (DOCG4_PAGES_PER_BLOCK * DOCG4_PAGE_SIZE)
+#define DOCG4_NUMBLOCKS        (DOCG4_CHIP_SIZE / DOCG4_BLOCK_SIZE)
+#define DOCG4_OOB_SIZE         0x10
+#define DOCG4_CHIP_SHIFT       27    /* log_2(DOCG4_CHIP_SIZE) */
+#define DOCG4_PAGE_SHIFT       9     /* log_2(DOCG4_PAGE_SIZE) */
+#define DOCG4_ERASE_SHIFT      18    /* log_2(DOCG4_BLOCK_SIZE) */
+
+/* all but the last byte is included in ecc calculation */
+#define DOCG4_BCH_SIZE         (DOCG4_PAGE_SIZE + DOCG4_OOB_SIZE - 1)
+
+#define DOCG4_USERDATA_LEN     520 /* 512 byte page plus 8 oob avail to user */
+
+/* expected values from the ID registers */
+#define DOCG4_IDREG1_VALUE     0x0400
+#define DOCG4_IDREG2_VALUE     0xfbff
+
+/* primitive polynomial used to build the Galois field used by hw ecc gen */
+#define DOCG4_PRIMITIVE_POLY   0x4443
+
+#define DOCG4_M                14  /* Galois field is of order 2^14 */
+#define DOCG4_T                4   /* BCH alg corrects up to 4 bit errors */
+
+#define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */
+
+/*
+ * Oob bytes 0 - 6 are available to the user.
+ * Byte 7 is hamming ecc for first 7 bytes.  Bytes 8 - 14 are hw-generated ecc.
+ * Byte 15 (the last) is used by the driver as a "page written" flag.
+ */
+static struct nand_ecclayout docg4_oobinfo = {
+	.eccbytes = 9,
+	.eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
+	.oobavail = 7,
+	.oobfree = { {0, 7} }
+};
+
+/*
+ * The device has a nop register which M-Sys claims is for the purpose of
+ * inserting precise delays.  But beware; at least some operations fail if the
+ * nop writes are replaced with a generic delay!
+ */
+static inline void write_nop(void __iomem *docptr)
+{
+	writew(0, docptr + DOC_NOP);
+}
+
+static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	int i;
+	struct nand_chip *nand = mtd->priv;
+	uint16_t *p = (uint16_t *) buf;
+	len >>= 1;
+
+	for (i = 0; i < len; i++)
+		p[i] = readw(nand->IO_ADDR_R);
+}
+
+static void docg4_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	int i;
+	struct nand_chip *nand = mtd->priv;
+	uint16_t *p = (uint16_t *) buf;
+	len >>= 1;
+
+	for (i = 0; i < len; i++)
+		writew(p[i], nand->IO_ADDR_W);
+}
+
+static int poll_status(struct docg4_priv *doc)
+{
+	/*
+	 * Busy-wait for the FLASHREADY bit to be set in the FLASHCONTROL
+	 * register.  Operations known to take a long time (e.g., block erase)
+	 * should sleep for a while before calling this.
+	 */
+
+	uint16_t flash_status;
+	unsigned int timeo;
+	void __iomem *docptr = doc->virtadr;
+
+	dev_dbg(doc->dev, "%s...\n", __func__);
+
+	/* hardware quirk requires reading twice initially */
+	flash_status = readw(docptr + DOC_FLASHCONTROL);
+
+	timeo = 1000;
+	do {
+		cpu_relax();
+		flash_status = readb(docptr + DOC_FLASHCONTROL);
+	} while (!(flash_status & DOC_CTRL_FLASHREADY) && --timeo);
+
+
+	if (!timeo) {
+		dev_err(doc->dev, "%s: timed out!\n", __func__);
+		return NAND_STATUS_FAIL;
+	}
+
+	if (unlikely(timeo < 50))
+		dev_warn(doc->dev, "%s: nearly timed out; %d remaining\n",
+			 __func__, timeo);
+
+	return 0;
+}
+
+
+static int docg4_wait(struct mtd_info *mtd, struct nand_chip *nand)
+{
+
+	struct docg4_priv *doc = nand->priv;
+	int status = NAND_STATUS_WP;       /* inverse logic?? */
+	dev_dbg(doc->dev, "%s...\n", __func__);
+
+	/* report any previously unreported error */
+	if (doc->status) {
+		status |= doc->status;
+		doc->status = 0;
+		return status;
+	}
+
+	status |= poll_status(doc);
+	return status;
+}
+
+static void docg4_select_chip(struct mtd_info *mtd, int chip)
+{
+	/*
+	 * Select among multiple cascaded chips ("floors").  Multiple floors are
+	 * not yet supported, so the only valid non-negative value is 0.
+	 */
+	struct nand_chip *nand = mtd->priv;
+	struct docg4_priv *doc = nand->priv;
+	void __iomem *docptr = doc->virtadr;
+
+	dev_dbg(doc->dev, "%s: chip %d\n", __func__, chip);
+
+	if (chip < 0)
+		return;		/* deselected */
+
+	if (chip > 0)
+		dev_warn(doc->dev, "multiple floors currently unsupported\n");
+
+	writew(0, docptr + DOC_DEVICESELECT);
+}
+
+static void reset(struct mtd_info *mtd)
+{
+	/* full device reset */
+
+	struct nand_chip *nand = mtd->priv;
+	struct docg4_priv *doc = nand->priv;
+	void __iomem *docptr = doc->virtadr;
+
+	writew(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN,
+	       docptr + DOC_ASICMODE);
+	writew(~(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN),
+	       docptr + DOC_ASICMODECONFIRM);
+	write_nop(docptr);
+
+	writew(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN,
+	       docptr + DOC_ASICMODE);
+	writew(~(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN),
+	       docptr + DOC_ASICMODECONFIRM);
+
+	writew(DOC_ECCCONF1_ECC_ENABLE, docptr + DOC_ECCCONF1);
+
+	poll_status(doc);
+}
+
+static void read_hw_ecc(void __iomem *docptr, uint8_t *ecc_buf)
+{
+	/* read the 7 hw-generated ecc bytes */
+
+	int i;
+	for (i = 0; i < 7; i++) { /* hw quirk; read twice */
+		ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
+		ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
+	}
+}
+
+static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page)
+{
+	/*
+	 * Called after a page read when hardware reports bitflips.
+	 * Up to four bitflips can be corrected.
+	 */
+
+	struct nand_chip *nand = mtd->priv;
+	struct docg4_priv *doc = nand->priv;
+	void __iomem *docptr = doc->virtadr;
+	int i, numerrs, errpos[4];
+	const uint8_t blank_read_hwecc[8] = {
+		0xcf, 0x72, 0xfc, 0x1b, 0xa9, 0xc7, 0xb9, 0 };
+
+	read_hw_ecc(docptr, doc->ecc_buf); /* read 7 hw-generated ecc bytes */
+
+	/* check if read error is due to a blank page */
+	if (!memcmp(doc->ecc_buf, blank_read_hwecc, 7))
+		return 0;	/* yes */
+
+	/* skip additional check of "written flag" if ignore_badblocks */
+	if (ignore_badblocks == false) {
+
+		/*
+		 * If the hw ecc bytes are not those of a blank page, there's
+		 * still a chance that the page is blank, but was read with
+		 * errors.  Check the "written flag" in last oob byte, which
+		 * is set to zero when a page is written.  If more than half
+		 * the bits are set, assume a blank page.  Unfortunately, the
+		 * bit flips(s) are not reported in stats.
+		 */
+
+		if (doc->oob_buf[15]) {
+			int bit, numsetbits = 0;
+			unsigned long written_flag = doc->oob_buf[15];
+			for_each_set_bit(bit, &written_flag, 8)
+				numsetbits++;
+			if (numsetbits > 4) { /* assume blank */
+				dev_warn(doc->dev,
+					 "error(s) in blank page "
+					 "at offset %08x\n",
+					 page * DOCG4_PAGE_SIZE);
+				return 0;
+			}
+		}
+	}
+
+	/*
+	 * The hardware ecc unit produces oob_ecc ^ calc_ecc.  The kernel's bch
+	 * algorithm is used to decode this.  However the hw operates on page
+	 * data in a bit order that is the reverse of that of the bch alg,
+	 * requiring that the bits be reversed on the result.  Thanks to Ivan
+	 * Djelic for his analysis!
+	 */
+	for (i = 0; i < 7; i++)
+		doc->ecc_buf[i] = bitrev8(doc->ecc_buf[i]);
+
+	numerrs = decode_bch(doc->bch, NULL, DOCG4_USERDATA_LEN, NULL,
+			     doc->ecc_buf, NULL, errpos);
+
+	if (numerrs == -EBADMSG) {
+		dev_warn(doc->dev, "uncorrectable errors at offset %08x\n",
+			 page * DOCG4_PAGE_SIZE);
+		return -EBADMSG;
+	}
+
+	BUG_ON(numerrs < 0);	/* -EINVAL, or anything other than -EBADMSG */
+
+	/* undo last step in BCH alg (modulo mirroring not needed) */
+	for (i = 0; i < numerrs; i++)
+		errpos[i] = (errpos[i] & ~7)|(7-(errpos[i] & 7));
+
+	/* fix the errors */
+	for (i = 0; i < numerrs; i++) {
+
+		/* ignore if error within oob ecc bytes */
+		if (errpos[i] > DOCG4_USERDATA_LEN * 8)
+			continue;
+
+		/* if error within oob area preceeding ecc bytes... */
+		if (errpos[i] > DOCG4_PAGE_SIZE * 8)
+			change_bit(errpos[i] - DOCG4_PAGE_SIZE * 8,
+				   (unsigned long *)doc->oob_buf);
+
+		else    /* error in page data */
+			change_bit(errpos[i], (unsigned long *)buf);
+	}
+
+	dev_notice(doc->dev, "%d error(s) corrected at offset %08x\n",
+		   numerrs, page * DOCG4_PAGE_SIZE);
+
+	return numerrs;
+}
+
+static uint8_t docg4_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd->priv;
+	struct docg4_priv *doc = nand->priv;
+
+	dev_dbg(doc->dev, "%s\n", __func__);
+
+	if (doc->last_command.command == NAND_CMD_STATUS) {
+		int status;
+
+		/*
+		 * Previous nand command was status request, so nand
+		 * infrastructure code expects to read the status here.  If an
+		 * error occurred in a previous operation, report it.
+		 */
+		doc->last_command.command = 0;
+
+		if (doc->status) {
+			status = doc->status;
+			doc->status = 0;
+		}
+
+		/* why is NAND_STATUS_WP inverse logic?? */
+		else
+			status = NAND_STATUS_WP | NAND_STATUS_READY;
+
+		return status;
+	}
+
+	dev_warn(doc->dev, "unexpectd call to read_byte()\n");
+
+	return 0;
+}
+
+static void write_addr(struct docg4_priv *doc, uint32_t docg4_addr)
+{
+	/* write the four address bytes packed in docg4_addr to the device */
+
+	void __iomem *docptr = doc->virtadr;
+	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
+	docg4_addr >>= 8;
+	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
+	docg4_addr >>= 8;
+	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
+	docg4_addr >>= 8;
+	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
+}
+
+static int read_progstatus(struct docg4_priv *doc)
+{
+	/*
+	 * This apparently checks the status of programming.  Done after an
+	 * erasure, and after page data is written.  On error, the status is
+	 * saved, to be later retrieved by the nand infrastructure code.
+	 */
+	void __iomem *docptr = doc->virtadr;
+
+	/* status is read from the I/O reg */
+	uint16_t status1 = readw(docptr + DOC_IOSPACE_DATA);
+	uint16_t status2 = readw(docptr + DOC_IOSPACE_DATA);
+	uint16_t status3 = readw(docptr + DOCG4_MYSTERY_REG);
+
+	dev_dbg(doc->dev, "docg4: %s: %02x %02x %02x\n",
+	      __func__, status1, status2, status3);
+
+	if (status1 != DOCG4_PROGSTATUS_GOOD
+	    || status2 != DOCG4_PROGSTATUS_GOOD_2
+	    || status3 != DOCG4_PROGSTATUS_GOOD_2) {
+		doc->status = NAND_STATUS_FAIL;
+		dev_warn(doc->dev, "read_progstatus failed: "
+			 "%02x, %02x, %02x\n", status1, status2, status3);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int pageprog(struct mtd_info *mtd)
+{
+	/*
+	 * Final step in writing a page.  Writes the contents of its
+	 * internal buffer out to the flash array, or some such.
+	 */
+
+	struct nand_chip *nand = mtd->priv;
+	struct docg4_priv *doc = nand->priv;
+	void __iomem *docptr = doc->virtadr;
+	int retval = 0;
+
+	dev_dbg(doc->dev, "docg4: %s\n", __func__);
+
+	writew(DOCG4_SEQ_PAGEPROG, docptr + DOC_FLASHSEQUENCE);
+	writew(DOC_CMD_PROG_CYCLE2, docptr + DOC_FLASHCOMMAND);
+	write_nop(docptr);
+	write_nop(docptr);
+
+	/* Just busy-wait; usleep_range() slows things down noticeably. */
+	poll_status(doc);
+
+	writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
+	writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
+	writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+
+	retval = read_progstatus(doc);
+	writew(0, docptr + DOC_DATAEND);
+	write_nop(docptr);
+	poll_status(doc);
+	write_nop(docptr);
+
+	return retval;
+}
+
+static void sequence_reset(struct mtd_info *mtd)
+{
+	/* common starting sequence for all operations */
+
+	struct nand_chip *nand = mtd->priv;
+	struct docg4_priv *doc = nand->priv;
+	void __iomem *docptr = doc->virtadr;
+
+	writew(DOC_CTRL_UNKNOWN | DOC_CTRL_CE, docptr + DOC_FLASHCONTROL);
+	writew(DOC_SEQ_RESET, docptr + DOC_FLASHSEQUENCE);
+	writew(DOC_CMD_RESET, docptr + DOC_FLASHCOMMAND);
+	write_nop(docptr);
+	write_nop(docptr);
+	poll_status(doc);
+	write_nop(docptr);
+}
+
+static void read_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
+{
+	/* first step in reading a page */
+
+	struct nand_chip *nand = mtd->priv;
+	struct docg4_priv *doc = nand->priv;
+	void __iomem *docptr = doc->virtadr;
+
+	dev_dbg(doc->dev,
+	      "docg4: %s: g4 page %08x\n", __func__, docg4_addr);
+
+	sequence_reset(mtd);
+
+	writew(DOCG4_SEQ_PAGE_READ, docptr + DOC_FLASHSEQUENCE);
+	writew(DOCG4_CMD_PAGE_READ, docptr + DOC_FLASHCOMMAND);
+	write_nop(docptr);
+
+	write_addr(doc, docg4_addr);
+
+	write_nop(docptr);
+	writew(DOCG4_CMD_READ2, docptr + DOC_FLASHCOMMAND);
+	write_nop(docptr);
+	write_nop(docptr);
+
+	poll_status(doc);
+}
+
+static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
+{
+	/* first step in writing a page */
+
+	struct nand_chip *nand = mtd->priv;
+	struct docg4_priv *doc = nand->priv;
+	void __iomem *docptr = doc->virtadr;
+
+	dev_dbg(doc->dev,
+	      "docg4: %s: g4 addr: %x\n", __func__, docg4_addr);
+	sequence_reset(mtd);
+	writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE);
+	writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND);
+	write_nop(docptr);
+	write_addr(doc, docg4_addr);
+	write_nop(docptr);
+	write_nop(docptr);
+	poll_status(doc);
+}
+
+static uint32_t mtd_to_docg4_address(int page, int column)
+{
+	/*
+	 * Convert mtd address to format used by the device, 32 bit packed.
+	 *
+	 * Some notes on G4 addressing... The M-Sys documentation on this device
+	 * claims that pages are 2K in length, and indeed, the format of the
+	 * address used by the device reflects that.  But within each page are
+	 * four 512 byte "sub-pages", each with its own oob data that is
+	 * read/written immediately after the 512 bytes of page data.  This oob
+	 * data contains the ecc bytes for the preceeding 512 bytes.
+	 *
+	 * Rather than tell the mtd nand infrastructure that page size is 2k,
+	 * with four sub-pages each, we engage in a little subterfuge and tell
+	 * the infrastructure code that pages are 512 bytes in size.  This is
+	 * done because during the course of reverse-engineering the device, I
+	 * never observed an instance where an entire 2K "page" was read or
+	 * written as a unit.  Each "sub-page" is always addressed individually,
+	 * its data read/written, and ecc handled before the next "sub-page" is
+	 * addressed.
+	 *
+	 * This requires us to convert addresses passed by the mtd nand
+	 * infrastructure code to those used by the device.
+	 *
+	 * The address that is written to the device consists of four bytes: the
+	 * first two are the 2k page number, and the second is the index into
+	 * the page.  The index is in terms of 16-bit half-words and includes
+	 * the preceeding oob data, so e.g., the index into the second
+	 * "sub-page" is 0x108, and the full device address of the start of mtd
+	 * page 0x201 is 0x00800108.
+	 */
+	int g4_page = page / 4;	                      /* device's 2K page */
+	int g4_index = (page % 4) * 0x108 + column/2; /* offset into page */
+	return (g4_page << 16) | g4_index;	      /* pack */
+}
+
+static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
+			  int page_addr)
+{
+	/* handle standard nand commands */
+
+	struct nand_chip *nand = mtd->priv;
+	struct docg4_priv *doc = nand->priv;
+	uint32_t g4_addr = mtd_to_docg4_address(page_addr, column);
+
+	dev_dbg(doc->dev, "%s %x, page_addr=%x, column=%x\n",
+	      __func__, command, page_addr, column);
+
+	/*
+	 * Save the command and its arguments.  This enables emulation of
+	 * standard flash devices, and also some optimizations.
+	 */
+	doc->last_command.command = command;
+	doc->last_command.column = column;
+	doc->last_command.page = page_addr;
+
+	switch (command) {
+
+	case NAND_CMD_RESET:
+		reset(mtd);
+		break;
+
+	case NAND_CMD_READ0:
+		read_page_prologue(mtd, g4_addr);
+		break;
+
+	case NAND_CMD_STATUS:
+		/* next call to read_byte() will expect a status */
+		break;
+
+	case NAND_CMD_SEQIN:
+		write_page_prologue(mtd, g4_addr);
+
+		/* hack for deferred write of oob bytes */
+		if (doc->oob_page == page_addr)
+			memcpy(nand->oob_poi, doc->oob_buf, 16);
+		break;
+
+	case NAND_CMD_PAGEPROG:
+		pageprog(mtd);
+		break;
+
+	/* we don't expect these, based on review of nand_base.c */
+	case NAND_CMD_READOOB:
+	case NAND_CMD_READID:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+		dev_warn(doc->dev, "docg4_command: "
+			 "unexpected nand command 0x%x\n", command);
+		break;
+
+	}
+}
+
+static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
+		     uint8_t *buf, int page, bool use_ecc)
+{
+	struct docg4_priv *doc = nand->priv;
+	void __iomem *docptr = doc->virtadr;
+	uint16_t status, edc_err, *buf16;
+
+	dev_dbg(doc->dev, "%s: page %08x\n", __func__, page);
+
+	writew(DOC_ECCCONF0_READ_MODE |
+	       DOC_ECCCONF0_ECC_ENABLE |
+	       DOC_ECCCONF0_UNKNOWN |
+	       DOCG4_BCH_SIZE,
+	       docptr + DOC_ECCCONF0);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+
+	/* the 1st byte from the I/O reg is a status; the rest is page data */
+	status = readw(docptr + DOC_IOSPACE_DATA);
+	if (status & DOCG4_READ_ERROR) {
+		dev_err(doc->dev,
+			"docg4_read_page: bad status: 0x%02x\n", status);
+		writew(0, docptr + DOC_DATAEND);
+		return -EIO;
+	}
+
+	dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
+
+	docg4_read_buf(mtd, buf, DOCG4_PAGE_SIZE); /* read the page data */
+
+	/*
+	 * Diskonchips read oob immediately after a page read.  Mtd
+	 * infrastructure issues a separate command for reading oob after the
+	 * page is read.  So we save the oob bytes in a local buffer and just
+	 * copy it if the next command reads oob from the same page.
+	 */
+
+	/* first 14 oob bytes read from I/O reg */
+	docg4_read_buf(mtd, doc->oob_buf, 14);
+
+	/* last 2 read from another reg */
+	buf16 = (uint16_t *)(doc->oob_buf + 14);
+	*buf16 = readw(docptr + DOCG4_MYSTERY_REG);
+
+	write_nop(docptr);
+
+	if (likely(use_ecc == true)) {
+
+		/* read the register that tells us if bitflip(s) detected  */
+		edc_err = readw(docptr + DOC_ECCCONF1);
+		edc_err = readw(docptr + DOC_ECCCONF1);
+		dev_dbg(doc->dev, "%s: edc_err = 0x%02x\n", __func__, edc_err);
+
+		/* If bitflips are reported, attempt to correct with ecc */
+		if (edc_err & DOC_ECCCONF1_BCH_SYNDROM_ERR) {
+			int bits_corrected = correct_data(mtd, buf, page);
+			if (bits_corrected == -EBADMSG)
+				mtd->ecc_stats.failed++;
+			else
+				mtd->ecc_stats.corrected += bits_corrected;
+		}
+	}
+
+	writew(0, docptr + DOC_DATAEND);
+	return 0;
+}
+
+
+static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
+			       uint8_t *buf, int page)
+{
+	return read_page(mtd, nand, buf, page, false);
+}
+
+static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand,
+			   uint8_t *buf, int page)
+{
+	return read_page(mtd, nand, buf, page, true);
+}
+
+static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
+			  int page, int sndcmd)
+{
+	struct docg4_priv *doc = nand->priv;
+	void __iomem *docptr = doc->virtadr;
+	uint16_t status;
+
+	dev_dbg(doc->dev, "%s: page %x\n", __func__, page);
+
+	/*
+	 * Oob bytes are read as part of a normal page read.  If the previous
+	 * nand command was a read of the page whose oob is now being read, just
+	 * copy the oob bytes that we saved in a local buffer and avoid a
+	 * separate oob read.
+	 */
+	if (doc->last_command.command == NAND_CMD_READ0 &&
+	    doc->last_command.page == page) {
+		memcpy(nand->oob_poi, doc->oob_buf, 16);
+		return 0;
+	}
+
+	/*
+	 * Separate read of oob data only.
+	 */
+	docg4_command(mtd, NAND_CMD_READ0, nand->ecc.size, page);
+
+	writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+
+	/* the 1st byte from the I/O reg is a status; the rest is oob data */
+	status = readw(docptr + DOC_IOSPACE_DATA);
+	if (status & DOCG4_READ_ERROR) {
+		dev_warn(doc->dev,
+			 "docg4_read_oob failed: status = 0x%02x\n", status);
+		return -EIO;
+	}
+
+	dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
+
+	docg4_read_buf(mtd, nand->oob_poi, 16);
+
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	writew(0, docptr + DOC_DATAEND);
+	write_nop(docptr);
+
+	return 0;
+}
+
+static void docg4_erase_block(struct mtd_info *mtd, int page)
+{
+	struct nand_chip *nand = mtd->priv;
+	struct docg4_priv *doc = nand->priv;
+	void __iomem *docptr = doc->virtadr;
+	uint16_t g4_page;
+
+	dev_dbg(doc->dev, "%s: page %04x\n", __func__, page);
+
+	sequence_reset(mtd);
+
+	writew(DOCG4_SEQ_BLOCKERASE, docptr + DOC_FLASHSEQUENCE);
+	writew(DOC_CMD_PROG_BLOCK_ADDR, docptr + DOC_FLASHCOMMAND);
+	write_nop(docptr);
+
+	/* only 2 bytes of address are written to specify erase block */
+	g4_page = (uint16_t)(page / 4);  /* to g4's 2k page addressing */
+	writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
+	g4_page >>= 8;
+	writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
+	write_nop(docptr);
+
+	/* start the erasure */
+	writew(DOC_CMD_ERASECYCLE2, docptr + DOC_FLASHCOMMAND);
+	write_nop(docptr);
+	write_nop(docptr);
+
+	usleep_range(500, 1000); /* erasure is long; take a snooze */
+	poll_status(doc);
+	writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
+	writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
+	writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+
+	read_progstatus(doc);
+
+	writew(0, docptr + DOC_DATAEND);
+	write_nop(docptr);
+	poll_status(doc);
+	write_nop(docptr);
+}
+
+static void write_page(struct mtd_info *mtd, struct nand_chip *nand,
+		       const uint8_t *buf, bool use_ecc)
+{
+	struct docg4_priv *doc = nand->priv;
+	void __iomem *docptr = doc->virtadr;
+	uint8_t ecc_buf[8];
+
+	dev_dbg(doc->dev, "%s...\n", __func__);
+
+	writew(DOC_ECCCONF0_ECC_ENABLE |
+	       DOC_ECCCONF0_UNKNOWN |
+	       DOCG4_BCH_SIZE,
+	       docptr + DOC_ECCCONF0);
+	write_nop(docptr);
+
+	/* write the page data */
+	docg4_write_buf16(mtd, buf, DOCG4_PAGE_SIZE);
+
+	/* oob bytes 0 through 5 are written to I/O reg */
+	docg4_write_buf16(mtd, nand->oob_poi, 6);
+
+	/* oob byte 6 written to a separate reg */
+	writew(nand->oob_poi[6], docptr + DOCG4_OOB_6_7);
+
+	write_nop(docptr);
+	write_nop(docptr);
+
+	/* write hw-generated ecc bytes to oob */
+	if (likely(use_ecc == true)) {
+		/* oob byte 7 is hamming code */
+		uint8_t hamming = readb(docptr + DOC_HAMMINGPARITY);
+		hamming = readb(docptr + DOC_HAMMINGPARITY); /* 2nd read */
+		writew(hamming, docptr + DOCG4_OOB_6_7);
+		write_nop(docptr);
+
+		/* read the 7 bch bytes from ecc regs */
+		read_hw_ecc(docptr, ecc_buf);
+		ecc_buf[7] = 0;         /* clear the "page written" flag */
+	}
+
+	/* write user-supplied bytes to oob */
+	else {
+		writew(nand->oob_poi[7], docptr + DOCG4_OOB_6_7);
+		write_nop(docptr);
+		memcpy(ecc_buf, &nand->oob_poi[8], 8);
+	}
+
+	docg4_write_buf16(mtd, ecc_buf, 8);
+	write_nop(docptr);
+	write_nop(docptr);
+	writew(0, docptr + DOC_DATAEND);
+	write_nop(docptr);
+}
+
+static void docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
+				 const uint8_t *buf)
+{
+	return write_page(mtd, nand, buf, false);
+}
+
+static void docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
+			     const uint8_t *buf)
+{
+	return write_page(mtd, nand, buf, true);
+}
+
+static int docg4_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
+			   int page)
+{
+	/*
+	 * Writing oob-only is not really supported, because MLC nand must write
+	 * oob bytes at the same time as page data.  Nonetheless, we save the
+	 * oob buffer contents here, and then write it along with the page data
+	 * if the same page is subsequently written.  This allows user space
+	 * utilities that write the oob data prior to the page data to work
+	 * (e.g., nandwrite).  The disdvantage is that, if the intention was to
+	 * write oob only, the operation is quietly ignored.  Also, oob can get
+	 * corrupted if two concurrent processes are running nandwrite.
+	 */
+
+	/* note that bytes 7..14 are hw generated hamming/ecc and overwritten */
+	struct docg4_priv *doc = nand->priv;
+	doc->oob_page = page;
+	memcpy(doc->oob_buf, nand->oob_poi, 16);
+	return 0;
+}
+
+static int __init read_factory_bbt(struct mtd_info *mtd)
+{
+	/*
+	 * The device contains a read-only factory bad block table.  Read it and
+	 * update the memory-based bbt accordingly.
+	 */
+
+	struct nand_chip *nand = mtd->priv;
+	struct docg4_priv *doc = nand->priv;
+	uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0);
+	uint8_t *buf;
+	int i, block, status;
+
+	buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	read_page_prologue(mtd, g4_addr);
+	status = docg4_read_page(mtd, nand, buf, DOCG4_FACTORY_BBT_PAGE);
+	if (status)
+		goto exit;
+
+	/*
+	 * If no memory-based bbt was created, exit.  This will happen if module
+	 * parameter ignore_badblocks is set.  Then why even call this function?
+	 * For an unknown reason, block erase always fails if it's the first
+	 * operation after device power-up.  The above read ensures it never is.
+	 * Ugly, I know.
+	 */
+	if (nand->bbt == NULL)  /* no memory-based bbt */
+		goto exit;
+
+	/*
+	 * Parse factory bbt and update memory-based bbt.  Factory bbt format is
+	 * simple: one bit per block, block numbers increase left to right (msb
+	 * to lsb).  Bit clear means bad block.
+	 */
+	for (i = block = 0; block < DOCG4_NUMBLOCKS; block += 8, i++) {
+		int bitnum;
+		unsigned long bits = ~buf[i];
+		for_each_set_bit(bitnum, &bits, 8) {
+			int badblock = block + 7 - bitnum;
+			nand->bbt[badblock / 4] |=
+				0x03 << ((badblock % 4) * 2);
+			mtd->ecc_stats.badblocks++;
+			dev_notice(doc->dev, "factory-marked bad block: %d\n",
+				   badblock);
+		}
+	}
+ exit:
+	kfree(buf);
+	return status;
+}
+
+static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+	/*
+	 * Mark a block as bad.  Bad blocks are marked in the oob area of the
+	 * first page of the block.  The default scan_bbt() in the nand
+	 * infrastructure code works fine for building the memory-based bbt
+	 * during initialization, as does the nand infrastructure function that
+	 * checks if a block is bad by reading the bbt.  This function replaces
+	 * the nand default because writes to oob-only are not supported.
+	 */
+
+	int ret, i;
+	uint8_t *buf;
+	struct nand_chip *nand = mtd->priv;
+	struct docg4_priv *doc = nand->priv;
+	struct nand_bbt_descr *bbtd = nand->badblock_pattern;
+	int block = (int)(ofs >> nand->bbt_erase_shift);
+	int page = (int)(ofs >> nand->page_shift);
+	uint32_t g4_addr = mtd_to_docg4_address(page, 0);
+
+	dev_dbg(doc->dev, "%s: %08llx\n", __func__, ofs);
+
+	if (unlikely(ofs & (DOCG4_BLOCK_SIZE - 1)))
+		dev_warn(doc->dev, "%s: ofs %llx not start of block!\n",
+			 __func__, ofs);
+
+	/* allocate blank buffer for page data */
+	buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	/* update bbt in memory */
+	nand->bbt[block / 4] |= 0x01 << ((block & 0x03) * 2);
+
+	/* write bit-wise negation of pattern to oob buffer */
+	memset(nand->oob_poi, 0xff, mtd->oobsize);
+	for (i = 0; i < bbtd->len; i++)
+		nand->oob_poi[bbtd->offs + i] = ~bbtd->pattern[i];
+
+	/* write first page of block */
+	write_page_prologue(mtd, g4_addr);
+	docg4_write_page(mtd, nand, buf);
+	ret = pageprog(mtd);
+	if (!ret)
+		mtd->ecc_stats.badblocks++;
+
+	kfree(buf);
+
+	return ret;
+}
+
+static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs, int getchip)
+{
+	/* only called when module_param ignore_badblocks is set */
+	return 0;
+}
+
+static int docg4_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	/*
+	 * Put the device into "deep power-down" mode.  Note that CE# must be
+	 * deasserted for this to take effect.  The xscale, e.g., can be
+	 * configured to float this signal when the processor enters power-down,
+	 * and a suitable pull-up ensures its deassertion.
+	 */
+
+	int i;
+	uint8_t pwr_down;
+	struct docg4_priv *doc = platform_get_drvdata(pdev);
+	void __iomem *docptr = doc->virtadr;
+
+	dev_dbg(doc->dev, "%s...\n", __func__);
+
+	/* poll the register that tells us we're ready to go to sleep */
+	for (i = 0; i < 10; i++) {
+		pwr_down = readb(docptr + DOC_POWERMODE);
+		if (pwr_down & DOC_POWERDOWN_READY)
+			break;
+		usleep_range(1000, 4000);
+	}
+
+	if (pwr_down & DOC_POWERDOWN_READY) {
+		dev_err(doc->dev, "suspend failed; "
+			"timeout polling DOC_POWERDOWN_READY\n");
+		return -EIO;
+	}
+
+	writew(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN,
+	       docptr + DOC_ASICMODE);
+	writew(~(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN),
+	       docptr + DOC_ASICMODECONFIRM);
+
+	write_nop(docptr);
+
+	return 0;
+}
+
+static int docg4_resume(struct platform_device *pdev)
+{
+
+	/*
+	 * Exit power-down.  Twelve consecutive reads of the address below
+	 * accomplishes this, assuming CE# has been asserted.
+	 */
+
+	struct docg4_priv *doc = platform_get_drvdata(pdev);
+	void __iomem *docptr = doc->virtadr;
+	int i;
+
+	dev_dbg(doc->dev, "%s...\n", __func__);
+
+	for (i = 0; i < 12; i++)
+		readb(docptr + 0x1fff);
+
+	return 0;
+}
+
+static void __init init_mtd_structs(struct mtd_info *mtd)
+{
+	/* initialize mtd and nand data structures */
+
+	/*
+	 * Note that some of the following initializations are not usually
+	 * required within a nand driver because they are performed by the nand
+	 * infrastructure code as part of nand_scan().  In this case they need
+	 * to be initialized here because we skip call to nand_scan_ident() (the
+	 * first half of nand_scan()).  The call to nand_scan_ident() is skipped
+	 * because for this device the chip id is not read in the manner of a
+	 * standard nand device.  Unfortunately, nand_scan_ident() does other
+	 * things as well, such as call nand_set_defaults().
+	 */
+
+	struct nand_chip *nand = mtd->priv;
+	struct docg4_priv *doc = nand->priv;
+
+	mtd->size = DOCG4_CHIP_SIZE;
+	mtd->name = "Msys_Diskonchip_G4";
+	mtd->writesize = DOCG4_PAGE_SIZE;
+	mtd->erasesize = DOCG4_BLOCK_SIZE;
+	mtd->oobsize = DOCG4_OOB_SIZE;
+	nand->chipsize = DOCG4_CHIP_SIZE;
+	nand->chip_shift = DOCG4_CHIP_SHIFT;
+	nand->bbt_erase_shift = nand->phys_erase_shift = DOCG4_ERASE_SHIFT;
+	nand->chip_delay = 20;
+	nand->page_shift = DOCG4_PAGE_SHIFT;
+	nand->pagemask = 0x3ffff;
+	nand->badblockpos = NAND_LARGE_BADBLOCK_POS;
+	nand->badblockbits = 8;
+	nand->ecc.layout = &docg4_oobinfo;
+	nand->ecc.mode = NAND_ECC_HW_SYNDROME;
+	nand->ecc.size = DOCG4_PAGE_SIZE;
+	nand->ecc.prepad = 8;
+	nand->ecc.bytes	= 8;
+	nand->ecc.strength = DOCG4_T;
+	nand->options =
+		NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE | NAND_NO_AUTOINCR;
+	nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
+	nand->controller = &nand->hwcontrol;
+	spin_lock_init(&nand->controller->lock);
+	init_waitqueue_head(&nand->controller->wq);
+
+	/* methods */
+	nand->cmdfunc = docg4_command;
+	nand->waitfunc = docg4_wait;
+	nand->select_chip = docg4_select_chip;
+	nand->read_byte = docg4_read_byte;
+	nand->block_markbad = docg4_block_markbad;
+	nand->read_buf = docg4_read_buf;
+	nand->write_buf = docg4_write_buf16;
+	nand->scan_bbt = nand_default_bbt;
+	nand->erase_cmd = docg4_erase_block;
+	nand->ecc.read_page = docg4_read_page;
+	nand->ecc.write_page = docg4_write_page;
+	nand->ecc.read_page_raw = docg4_read_page_raw;
+	nand->ecc.write_page_raw = docg4_write_page_raw;
+	nand->ecc.read_oob = docg4_read_oob;
+	nand->ecc.write_oob = docg4_write_oob;
+
+	/*
+	 * The way the nand infrastructure code is written, a memory-based bbt
+	 * is not created if NAND_SKIP_BBTSCAN is set.  With no memory bbt,
+	 * nand->block_bad() is used.  So when ignoring bad blocks, we skip the
+	 * scan and define a dummy block_bad() which always returns 0.
+	 */
+	if (ignore_badblocks) {
+		nand->options |= NAND_SKIP_BBTSCAN;
+		nand->block_bad	= docg4_block_neverbad;
+	}
+
+}
+
+static int __init read_id_reg(struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd->priv;
+	struct docg4_priv *doc = nand->priv;
+	void __iomem *docptr = doc->virtadr;
+	uint16_t id1, id2;
+
+	/* check for presence of g4 chip by reading id registers */
+	id1 = readw(docptr + DOC_CHIPID);
+	id1 = readw(docptr + DOCG4_MYSTERY_REG);
+	id2 = readw(docptr + DOC_CHIPID_INV);
+	id2 = readw(docptr + DOCG4_MYSTERY_REG);
+
+	if (id1 == DOCG4_IDREG1_VALUE && id2 == DOCG4_IDREG2_VALUE) {
+		dev_info(doc->dev,
+			 "NAND device: 128MiB Diskonchip G4 detected\n");
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL };
+
+static int __init probe_docg4(struct platform_device *pdev)
+{
+	struct mtd_info *mtd;
+	struct nand_chip *nand;
+	void __iomem *virtadr;
+	struct docg4_priv *doc;
+	int len, retval;
+	struct resource *r;
+	struct device *dev = &pdev->dev;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (r == NULL) {
+		dev_err(dev, "no io memory resource defined!\n");
+		return -ENODEV;
+	}
+
+	virtadr = ioremap(r->start, resource_size(r));
+	if (!virtadr) {
+		dev_err(dev, "Diskonchip ioremap failed: %pR\n", r);
+		return -EIO;
+	}
+
+	len = sizeof(struct mtd_info) + sizeof(struct nand_chip) +
+		sizeof(struct docg4_priv);
+	mtd = kzalloc(len, GFP_KERNEL);
+	if (mtd == NULL) {
+		retval = -ENOMEM;
+		goto fail;
+	}
+	nand = (struct nand_chip *) (mtd + 1);
+	doc = (struct docg4_priv *) (nand + 1);
+	mtd->priv = nand;
+	nand->priv = doc;
+	mtd->owner = THIS_MODULE;
+	doc->virtadr = virtadr;
+	doc->dev = dev;
+
+	init_mtd_structs(mtd);
+
+	/* initialize kernel bch algorithm */
+	doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
+	if (doc->bch == NULL) {
+		retval = -EINVAL;
+		goto fail;
+	}
+
+	platform_set_drvdata(pdev, doc);
+
+	reset(mtd);
+	retval = read_id_reg(mtd);
+	if (retval == -ENODEV) {
+		dev_warn(dev, "No diskonchip G4 device found.\n");
+		goto fail;
+	}
+
+	retval = nand_scan_tail(mtd);
+	if (retval)
+		goto fail;
+
+	retval = read_factory_bbt(mtd);
+	if (retval)
+		goto fail;
+
+	retval = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
+	if (retval)
+		goto fail;
+
+	doc->mtd = mtd;
+	return 0;
+
+ fail:
+	iounmap(virtadr);
+	if (mtd) {
+		/* re-declarations avoid compiler warning */
+		struct nand_chip *nand = mtd->priv;
+		struct docg4_priv *doc = nand->priv;
+		nand_release(mtd); /* deletes partitions and mtd devices */
+		platform_set_drvdata(pdev, NULL);
+		free_bch(doc->bch);
+		kfree(mtd);
+	}
+
+	return retval;
+}
+
+static int __exit cleanup_docg4(struct platform_device *pdev)
+{
+	struct docg4_priv *doc = platform_get_drvdata(pdev);
+	nand_release(doc->mtd);
+	platform_set_drvdata(pdev, NULL);
+	free_bch(doc->bch);
+	kfree(doc->mtd);
+	iounmap(doc->virtadr);
+	return 0;
+}
+
+static struct platform_driver docg4_driver = {
+	.driver		= {
+		.name	= "docg4",
+		.owner	= THIS_MODULE,
+	},
+	.suspend	= docg4_suspend,
+	.resume		= docg4_resume,
+	.remove		= __exit_p(cleanup_docg4),
+};
+
+static int __init docg4_init(void)
+{
+	return platform_driver_probe(&docg4_driver, probe_docg4);
+}
+
+static void __exit docg4_exit(void)
+{
+	platform_driver_unregister(&docg4_driver);
+}
+
+module_init(docg4_init);
+module_exit(docg4_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mike Dunn");
+MODULE_DESCRIPTION("M-Systems DiskOnChip G4 device driver");
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 7195ee6..80b5264 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -813,6 +813,12 @@
 				&fsl_elbc_oob_sp_eccm1 : &fsl_elbc_oob_sp_eccm0;
 		chip->ecc.size = 512;
 		chip->ecc.bytes = 3;
+		chip->ecc.strength = 1;
+		/*
+		 * FIXME: can hardware ecc correct 4 bitflips if page size is
+		 * 2k?  Then does hardware report number of corrections for this
+		 * case?  If so, ecc_stats reporting needs to be fixed as well.
+		 */
 	} else {
 		/* otherwise fall back to default software ECC */
 		chip->ecc.mode = NAND_ECC_SOFT;
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
new file mode 100644
index 0000000..c30ac7b
--- /dev/null
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -0,0 +1,1072 @@
+/*
+ * Freescale Integrated Flash Controller NAND driver
+ *
+ * Copyright 2011-2012 Freescale Semiconductor, Inc
+ *
+ * Author: Dipen Dudhat <Dipen.Dudhat@freescale.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand_ecc.h>
+#include <asm/fsl_ifc.h>
+
+#define ERR_BYTE		0xFF /* Value returned for read
+					bytes when read failed	*/
+#define IFC_TIMEOUT_MSECS	500  /* Maximum number of mSecs to wait
+					for IFC NAND Machine	*/
+
+struct fsl_ifc_ctrl;
+
+/* mtd information per set */
+struct fsl_ifc_mtd {
+	struct mtd_info mtd;
+	struct nand_chip chip;
+	struct fsl_ifc_ctrl *ctrl;
+
+	struct device *dev;
+	int bank;		/* Chip select bank number		*/
+	unsigned int bufnum_mask; /* bufnum = page & bufnum_mask */
+	u8 __iomem *vbase;      /* Chip select base virtual address	*/
+};
+
+/* overview of the fsl ifc controller */
+struct fsl_ifc_nand_ctrl {
+	struct nand_hw_control controller;
+	struct fsl_ifc_mtd *chips[FSL_IFC_BANK_COUNT];
+
+	u8 __iomem *addr;	/* Address of assigned IFC buffer	*/
+	unsigned int page;	/* Last page written to / read from	*/
+	unsigned int read_bytes;/* Number of bytes read during command	*/
+	unsigned int column;	/* Saved column from SEQIN		*/
+	unsigned int index;	/* Pointer to next byte to 'read'	*/
+	unsigned int oob;	/* Non zero if operating on OOB data	*/
+	unsigned int eccread;	/* Non zero for a full-page ECC read	*/
+	unsigned int counter;	/* counter for the initializations	*/
+};
+
+static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl;
+
+/* 512-byte page with 4-bit ECC, 8-bit */
+static struct nand_ecclayout oob_512_8bit_ecc4 = {
+	.eccbytes = 8,
+	.eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
+	.oobfree = { {0, 5}, {6, 2} },
+};
+
+/* 512-byte page with 4-bit ECC, 16-bit */
+static struct nand_ecclayout oob_512_16bit_ecc4 = {
+	.eccbytes = 8,
+	.eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
+	.oobfree = { {2, 6}, },
+};
+
+/* 2048-byte page size with 4-bit ECC */
+static struct nand_ecclayout oob_2048_ecc4 = {
+	.eccbytes = 32,
+	.eccpos = {
+		8, 9, 10, 11, 12, 13, 14, 15,
+		16, 17, 18, 19, 20, 21, 22, 23,
+		24, 25, 26, 27, 28, 29, 30, 31,
+		32, 33, 34, 35, 36, 37, 38, 39,
+	},
+	.oobfree = { {2, 6}, {40, 24} },
+};
+
+/* 4096-byte page size with 4-bit ECC */
+static struct nand_ecclayout oob_4096_ecc4 = {
+	.eccbytes = 64,
+	.eccpos = {
+		8, 9, 10, 11, 12, 13, 14, 15,
+		16, 17, 18, 19, 20, 21, 22, 23,
+		24, 25, 26, 27, 28, 29, 30, 31,
+		32, 33, 34, 35, 36, 37, 38, 39,
+		40, 41, 42, 43, 44, 45, 46, 47,
+		48, 49, 50, 51, 52, 53, 54, 55,
+		56, 57, 58, 59, 60, 61, 62, 63,
+		64, 65, 66, 67, 68, 69, 70, 71,
+	},
+	.oobfree = { {2, 6}, {72, 56} },
+};
+
+/* 4096-byte page size with 8-bit ECC -- requires 218-byte OOB */
+static struct nand_ecclayout oob_4096_ecc8 = {
+	.eccbytes = 128,
+	.eccpos = {
+		8, 9, 10, 11, 12, 13, 14, 15,
+		16, 17, 18, 19, 20, 21, 22, 23,
+		24, 25, 26, 27, 28, 29, 30, 31,
+		32, 33, 34, 35, 36, 37, 38, 39,
+		40, 41, 42, 43, 44, 45, 46, 47,
+		48, 49, 50, 51, 52, 53, 54, 55,
+		56, 57, 58, 59, 60, 61, 62, 63,
+		64, 65, 66, 67, 68, 69, 70, 71,
+		72, 73, 74, 75, 76, 77, 78, 79,
+		80, 81, 82, 83, 84, 85, 86, 87,
+		88, 89, 90, 91, 92, 93, 94, 95,
+		96, 97, 98, 99, 100, 101, 102, 103,
+		104, 105, 106, 107, 108, 109, 110, 111,
+		112, 113, 114, 115, 116, 117, 118, 119,
+		120, 121, 122, 123, 124, 125, 126, 127,
+		128, 129, 130, 131, 132, 133, 134, 135,
+	},
+	.oobfree = { {2, 6}, {136, 82} },
+};
+
+
+/*
+ * Generic flash bbt descriptors
+ */
+static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+		   NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	2, /* 0 on 8-bit small page */
+	.len = 4,
+	.veroffs = 6,
+	.maxblocks = 4,
+	.pattern = bbt_pattern,
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+		   NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	2, /* 0 on 8-bit small page */
+	.len = 4,
+	.veroffs = 6,
+	.maxblocks = 4,
+	.pattern = mirror_pattern,
+};
+
+/*
+ * Set up the IFC hardware block and page address fields, and the ifc nand
+ * structure addr field to point to the correct IFC buffer in memory
+ */
+static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	int buf_num;
+
+	ifc_nand_ctrl->page = page_addr;
+	/* Program ROW0/COL0 */
+	out_be32(&ifc->ifc_nand.row0, page_addr);
+	out_be32(&ifc->ifc_nand.col0, (oob ? IFC_NAND_COL_MS : 0) | column);
+
+	buf_num = page_addr & priv->bufnum_mask;
+
+	ifc_nand_ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2);
+	ifc_nand_ctrl->index = column;
+
+	/* for OOB data point to the second half of the buffer */
+	if (oob)
+		ifc_nand_ctrl->index += mtd->writesize;
+}
+
+static int is_blank(struct mtd_info *mtd, unsigned int bufnum)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2);
+	u32 __iomem *mainarea = (u32 *)addr;
+	u8 __iomem *oob = addr + mtd->writesize;
+	int i;
+
+	for (i = 0; i < mtd->writesize / 4; i++) {
+		if (__raw_readl(&mainarea[i]) != 0xffffffff)
+			return 0;
+	}
+
+	for (i = 0; i < chip->ecc.layout->eccbytes; i++) {
+		int pos = chip->ecc.layout->eccpos[i];
+
+		if (__raw_readb(&oob[pos]) != 0xff)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* returns nonzero if entire page is blank */
+static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
+			  u32 *eccstat, unsigned int bufnum)
+{
+	u32 reg = eccstat[bufnum / 4];
+	int errors;
+
+	errors = (reg >> ((3 - bufnum % 4) * 8)) & 15;
+
+	return errors;
+}
+
+/*
+ * execute IFC NAND command and wait for it to complete
+ */
+static void fsl_ifc_run_command(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	u32 eccstat[4];
+	int i;
+
+	/* set the chip select for NAND Transaction */
+	out_be32(&ifc->ifc_nand.nand_csel, priv->bank << IFC_NAND_CSEL_SHIFT);
+
+	dev_vdbg(priv->dev,
+			"%s: fir0=%08x fcr0=%08x\n",
+			__func__,
+			in_be32(&ifc->ifc_nand.nand_fir0),
+			in_be32(&ifc->ifc_nand.nand_fcr0));
+
+	ctrl->nand_stat = 0;
+
+	/* start read/write seq */
+	out_be32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT);
+
+	/* wait for command complete flag or timeout */
+	wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
+			   IFC_TIMEOUT_MSECS * HZ/1000);
+
+	/* ctrl->nand_stat will be updated from IRQ context */
+	if (!ctrl->nand_stat)
+		dev_err(priv->dev, "Controller is not responding\n");
+	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_FTOER)
+		dev_err(priv->dev, "NAND Flash Timeout Error\n");
+	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER)
+		dev_err(priv->dev, "NAND Flash Write Protect Error\n");
+
+	if (nctrl->eccread) {
+		int errors;
+		int bufnum = nctrl->page & priv->bufnum_mask;
+		int sector = bufnum * chip->ecc.steps;
+		int sector_end = sector + chip->ecc.steps - 1;
+
+		for (i = sector / 4; i <= sector_end / 4; i++)
+			eccstat[i] = in_be32(&ifc->ifc_nand.nand_eccstat[i]);
+
+		for (i = sector; i <= sector_end; i++) {
+			errors = check_read_ecc(mtd, ctrl, eccstat, i);
+
+			if (errors == 15) {
+				/*
+				 * Uncorrectable error.
+				 * OK only if the whole page is blank.
+				 *
+				 * We disable ECCER reporting due to...
+				 * erratum IFC-A002770 -- so report it now if we
+				 * see an uncorrectable error in ECCSTAT.
+				 */
+				if (!is_blank(mtd, bufnum))
+					ctrl->nand_stat |=
+						IFC_NAND_EVTER_STAT_ECCER;
+				break;
+			}
+
+			mtd->ecc_stats.corrected += errors;
+		}
+
+		nctrl->eccread = 0;
+	}
+}
+
+static void fsl_ifc_do_read(struct nand_chip *chip,
+			    int oob,
+			    struct mtd_info *mtd)
+{
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+
+	/* Program FIR/IFC_NAND_FCR0 for Small/Large page */
+	if (mtd->writesize > 512) {
+		out_be32(&ifc->ifc_nand.nand_fir0,
+			 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+			 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+			 (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) |
+			 (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT));
+		out_be32(&ifc->ifc_nand.nand_fir1, 0x0);
+
+		out_be32(&ifc->ifc_nand.nand_fcr0,
+			(NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) |
+			(NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT));
+	} else {
+		out_be32(&ifc->ifc_nand.nand_fir0,
+			 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+			 (IFC_FIR_OP_RA0  << IFC_NAND_FIR0_OP2_SHIFT) |
+			 (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT));
+		out_be32(&ifc->ifc_nand.nand_fir1, 0x0);
+
+		if (oob)
+			out_be32(&ifc->ifc_nand.nand_fcr0,
+				 NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT);
+		else
+			out_be32(&ifc->ifc_nand.nand_fcr0,
+				NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT);
+	}
+}
+
+/* cmdfunc send commands to the IFC NAND Machine */
+static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
+			     int column, int page_addr) {
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+
+	/* clear the read buffer */
+	ifc_nand_ctrl->read_bytes = 0;
+	if (command != NAND_CMD_PAGEPROG)
+		ifc_nand_ctrl->index = 0;
+
+	switch (command) {
+	/* READ0 read the entire buffer to use hardware ECC. */
+	case NAND_CMD_READ0:
+		out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+		set_addr(mtd, 0, page_addr, 0);
+
+		ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+		ifc_nand_ctrl->index += column;
+
+		if (chip->ecc.mode == NAND_ECC_HW)
+			ifc_nand_ctrl->eccread = 1;
+
+		fsl_ifc_do_read(chip, 0, mtd);
+		fsl_ifc_run_command(mtd);
+		return;
+
+	/* READOOB reads only the OOB because no ECC is performed. */
+	case NAND_CMD_READOOB:
+		out_be32(&ifc->ifc_nand.nand_fbcr, mtd->oobsize - column);
+		set_addr(mtd, column, page_addr, 1);
+
+		ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+
+		fsl_ifc_do_read(chip, 1, mtd);
+		fsl_ifc_run_command(mtd);
+
+		return;
+
+	/* READID must read all 8 possible bytes */
+	case NAND_CMD_READID:
+		out_be32(&ifc->ifc_nand.nand_fir0,
+				(IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) |
+				(IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
+				(IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
+		out_be32(&ifc->ifc_nand.nand_fcr0,
+				NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT);
+		/* 8 bytes for manuf, device and exts */
+		out_be32(&ifc->ifc_nand.nand_fbcr, 8);
+		ifc_nand_ctrl->read_bytes = 8;
+
+		set_addr(mtd, 0, 0, 0);
+		fsl_ifc_run_command(mtd);
+		return;
+
+	/* ERASE1 stores the block and page address */
+	case NAND_CMD_ERASE1:
+		set_addr(mtd, 0, page_addr, 0);
+		return;
+
+	/* ERASE2 uses the block and page address from ERASE1 */
+	case NAND_CMD_ERASE2:
+		out_be32(&ifc->ifc_nand.nand_fir0,
+			 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+			 (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT));
+
+		out_be32(&ifc->ifc_nand.nand_fcr0,
+			 (NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) |
+			 (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT));
+
+		out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+		ifc_nand_ctrl->read_bytes = 0;
+		fsl_ifc_run_command(mtd);
+		return;
+
+	/* SEQIN sets up the addr buffer and all registers except the length */
+	case NAND_CMD_SEQIN: {
+		u32 nand_fcr0;
+		ifc_nand_ctrl->column = column;
+		ifc_nand_ctrl->oob = 0;
+
+		if (mtd->writesize > 512) {
+			nand_fcr0 =
+				(NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) |
+				(NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD1_SHIFT);
+
+			out_be32(&ifc->ifc_nand.nand_fir0,
+				 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+				 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+				 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+				 (IFC_FIR_OP_WBCD  << IFC_NAND_FIR0_OP3_SHIFT) |
+				 (IFC_FIR_OP_CW1 << IFC_NAND_FIR0_OP4_SHIFT));
+		} else {
+			nand_fcr0 = ((NAND_CMD_PAGEPROG <<
+					IFC_NAND_FCR0_CMD1_SHIFT) |
+				    (NAND_CMD_SEQIN <<
+					IFC_NAND_FCR0_CMD2_SHIFT));
+
+			out_be32(&ifc->ifc_nand.nand_fir0,
+				 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+				 (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) |
+				 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+				 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) |
+				 (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT));
+			out_be32(&ifc->ifc_nand.nand_fir1,
+				 (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT));
+
+			if (column >= mtd->writesize)
+				nand_fcr0 |=
+				NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT;
+			else
+				nand_fcr0 |=
+				NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT;
+		}
+
+		if (column >= mtd->writesize) {
+			/* OOB area --> READOOB */
+			column -= mtd->writesize;
+			ifc_nand_ctrl->oob = 1;
+		}
+		out_be32(&ifc->ifc_nand.nand_fcr0, nand_fcr0);
+		set_addr(mtd, column, page_addr, ifc_nand_ctrl->oob);
+		return;
+	}
+
+	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
+	case NAND_CMD_PAGEPROG: {
+		if (ifc_nand_ctrl->oob) {
+			out_be32(&ifc->ifc_nand.nand_fbcr,
+				ifc_nand_ctrl->index - ifc_nand_ctrl->column);
+		} else {
+			out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+		}
+
+		fsl_ifc_run_command(mtd);
+		return;
+	}
+
+	case NAND_CMD_STATUS:
+		out_be32(&ifc->ifc_nand.nand_fir0,
+				(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+				(IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT));
+		out_be32(&ifc->ifc_nand.nand_fcr0,
+				NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT);
+		out_be32(&ifc->ifc_nand.nand_fbcr, 1);
+		set_addr(mtd, 0, 0, 0);
+		ifc_nand_ctrl->read_bytes = 1;
+
+		fsl_ifc_run_command(mtd);
+
+		/*
+		 * The chip always seems to report that it is
+		 * write-protected, even when it is not.
+		 */
+		setbits8(ifc_nand_ctrl->addr, NAND_STATUS_WP);
+		return;
+
+	case NAND_CMD_RESET:
+		out_be32(&ifc->ifc_nand.nand_fir0,
+				IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT);
+		out_be32(&ifc->ifc_nand.nand_fcr0,
+				NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT);
+		fsl_ifc_run_command(mtd);
+		return;
+
+	default:
+		dev_err(priv->dev, "%s: error, unsupported command 0x%x.\n",
+					__func__, command);
+	}
+}
+
+static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
+{
+	/* The hardware does not seem to support multiple
+	 * chips per bank.
+	 */
+}
+
+/*
+ * Write buf to the IFC NAND Controller Data Buffer
+ */
+static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	unsigned int bufsize = mtd->writesize + mtd->oobsize;
+
+	if (len <= 0) {
+		dev_err(priv->dev, "%s: len %d bytes", __func__, len);
+		return;
+	}
+
+	if ((unsigned int)len > bufsize - ifc_nand_ctrl->index) {
+		dev_err(priv->dev,
+			"%s: beyond end of buffer (%d requested, %u available)\n",
+			__func__, len, bufsize - ifc_nand_ctrl->index);
+		len = bufsize - ifc_nand_ctrl->index;
+	}
+
+	memcpy_toio(&ifc_nand_ctrl->addr[ifc_nand_ctrl->index], buf, len);
+	ifc_nand_ctrl->index += len;
+}
+
+/*
+ * Read a byte from either the IFC hardware buffer
+ * read function for 8-bit buswidth
+ */
+static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+
+	/*
+	 * If there are still bytes in the IFC buffer, then use the
+	 * next byte.
+	 */
+	if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes)
+		return in_8(&ifc_nand_ctrl->addr[ifc_nand_ctrl->index++]);
+
+	dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
+	return ERR_BYTE;
+}
+
+/*
+ * Read two bytes from the IFC hardware buffer
+ * read function for 16-bit buswith
+ */
+static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	uint16_t data;
+
+	/*
+	 * If there are still bytes in the IFC buffer, then use the
+	 * next byte.
+	 */
+	if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) {
+		data = in_be16((uint16_t *)&ifc_nand_ctrl->
+					addr[ifc_nand_ctrl->index]);
+		ifc_nand_ctrl->index += 2;
+		return (uint8_t) data;
+	}
+
+	dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
+	return ERR_BYTE;
+}
+
+/*
+ * Read from the IFC Controller Data Buffer
+ */
+static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	int avail;
+
+	if (len < 0) {
+		dev_err(priv->dev, "%s: len %d bytes", __func__, len);
+		return;
+	}
+
+	avail = min((unsigned int)len,
+			ifc_nand_ctrl->read_bytes - ifc_nand_ctrl->index);
+	memcpy_fromio(buf, &ifc_nand_ctrl->addr[ifc_nand_ctrl->index], avail);
+	ifc_nand_ctrl->index += avail;
+
+	if (len > avail)
+		dev_err(priv->dev,
+			"%s: beyond end of buffer (%d requested, %d available)\n",
+			__func__, len, avail);
+}
+
+/*
+ * Verify buffer against the IFC Controller Data Buffer
+ */
+static int fsl_ifc_verify_buf(struct mtd_info *mtd,
+			       const u_char *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
+	int i;
+
+	if (len < 0) {
+		dev_err(priv->dev, "%s: write_buf of %d bytes", __func__, len);
+		return -EINVAL;
+	}
+
+	if ((unsigned int)len > nctrl->read_bytes - nctrl->index) {
+		dev_err(priv->dev,
+			"%s: beyond end of buffer (%d requested, %u available)\n",
+			__func__, len, nctrl->read_bytes - nctrl->index);
+
+		nctrl->index = nctrl->read_bytes;
+		return -EINVAL;
+	}
+
+	for (i = 0; i < len; i++)
+		if (in_8(&nctrl->addr[nctrl->index + i]) != buf[i])
+			break;
+
+	nctrl->index += len;
+
+	if (i != len)
+		return -EIO;
+	if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
+		return -EIO;
+
+	return 0;
+}
+
+/*
+ * This function is called after Program and Erase Operations to
+ * check for success or failure.
+ */
+static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	u32 nand_fsr;
+
+	/* Use READ_STATUS command, but wait for the device to be ready */
+	out_be32(&ifc->ifc_nand.nand_fir0,
+		 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+		 (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT));
+	out_be32(&ifc->ifc_nand.nand_fcr0, NAND_CMD_STATUS <<
+			IFC_NAND_FCR0_CMD0_SHIFT);
+	out_be32(&ifc->ifc_nand.nand_fbcr, 1);
+	set_addr(mtd, 0, 0, 0);
+	ifc_nand_ctrl->read_bytes = 1;
+
+	fsl_ifc_run_command(mtd);
+
+	nand_fsr = in_be32(&ifc->ifc_nand.nand_fsr);
+
+	/*
+	 * The chip always seems to report that it is
+	 * write-protected, even when it is not.
+	 */
+	return nand_fsr | NAND_STATUS_WP;
+}
+
+static int fsl_ifc_read_page(struct mtd_info *mtd,
+			      struct nand_chip *chip,
+			      uint8_t *buf, int page)
+{
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+
+	fsl_ifc_read_buf(mtd, buf, mtd->writesize);
+	fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER)
+		dev_err(priv->dev, "NAND Flash ECC Uncorrectable Error\n");
+
+	if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
+		mtd->ecc_stats.failed++;
+
+	return 0;
+}
+
+/* ECC will be calculated automatically, and errors will be detected in
+ * waitfunc.
+ */
+static void fsl_ifc_write_page(struct mtd_info *mtd,
+				struct nand_chip *chip,
+				const uint8_t *buf)
+{
+	fsl_ifc_write_buf(mtd, buf, mtd->writesize);
+	fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+}
+
+static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+
+	dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
+							chip->numchips);
+	dev_dbg(priv->dev, "%s: nand->chipsize = %lld\n", __func__,
+							chip->chipsize);
+	dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__,
+							chip->pagemask);
+	dev_dbg(priv->dev, "%s: nand->chip_delay = %d\n", __func__,
+							chip->chip_delay);
+	dev_dbg(priv->dev, "%s: nand->badblockpos = %d\n", __func__,
+							chip->badblockpos);
+	dev_dbg(priv->dev, "%s: nand->chip_shift = %d\n", __func__,
+							chip->chip_shift);
+	dev_dbg(priv->dev, "%s: nand->page_shift = %d\n", __func__,
+							chip->page_shift);
+	dev_dbg(priv->dev, "%s: nand->phys_erase_shift = %d\n", __func__,
+							chip->phys_erase_shift);
+	dev_dbg(priv->dev, "%s: nand->ecclayout = %p\n", __func__,
+							chip->ecclayout);
+	dev_dbg(priv->dev, "%s: nand->ecc.mode = %d\n", __func__,
+							chip->ecc.mode);
+	dev_dbg(priv->dev, "%s: nand->ecc.steps = %d\n", __func__,
+							chip->ecc.steps);
+	dev_dbg(priv->dev, "%s: nand->ecc.bytes = %d\n", __func__,
+							chip->ecc.bytes);
+	dev_dbg(priv->dev, "%s: nand->ecc.total = %d\n", __func__,
+							chip->ecc.total);
+	dev_dbg(priv->dev, "%s: nand->ecc.layout = %p\n", __func__,
+							chip->ecc.layout);
+	dev_dbg(priv->dev, "%s: mtd->flags = %08x\n", __func__, mtd->flags);
+	dev_dbg(priv->dev, "%s: mtd->size = %lld\n", __func__, mtd->size);
+	dev_dbg(priv->dev, "%s: mtd->erasesize = %d\n", __func__,
+							mtd->erasesize);
+	dev_dbg(priv->dev, "%s: mtd->writesize = %d\n", __func__,
+							mtd->writesize);
+	dev_dbg(priv->dev, "%s: mtd->oobsize = %d\n", __func__,
+							mtd->oobsize);
+
+	return 0;
+}
+
+static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
+{
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	struct nand_chip *chip = &priv->chip;
+	struct nand_ecclayout *layout;
+	u32 csor;
+
+	/* Fill in fsl_ifc_mtd structure */
+	priv->mtd.priv = chip;
+	priv->mtd.owner = THIS_MODULE;
+
+	/* fill in nand_chip structure */
+	/* set up function call table */
+	if ((in_be32(&ifc->cspr_cs[priv->bank].cspr)) & CSPR_PORT_SIZE_16)
+		chip->read_byte = fsl_ifc_read_byte16;
+	else
+		chip->read_byte = fsl_ifc_read_byte;
+
+	chip->write_buf = fsl_ifc_write_buf;
+	chip->read_buf = fsl_ifc_read_buf;
+	chip->verify_buf = fsl_ifc_verify_buf;
+	chip->select_chip = fsl_ifc_select_chip;
+	chip->cmdfunc = fsl_ifc_cmdfunc;
+	chip->waitfunc = fsl_ifc_wait;
+
+	chip->bbt_td = &bbt_main_descr;
+	chip->bbt_md = &bbt_mirror_descr;
+
+	out_be32(&ifc->ifc_nand.ncfgr, 0x0);
+
+	/* set up nand options */
+	chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR;
+	chip->bbt_options = NAND_BBT_USE_FLASH;
+
+
+	if (in_be32(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) {
+		chip->read_byte = fsl_ifc_read_byte16;
+		chip->options |= NAND_BUSWIDTH_16;
+	} else {
+		chip->read_byte = fsl_ifc_read_byte;
+	}
+
+	chip->controller = &ifc_nand_ctrl->controller;
+	chip->priv = priv;
+
+	chip->ecc.read_page = fsl_ifc_read_page;
+	chip->ecc.write_page = fsl_ifc_write_page;
+
+	csor = in_be32(&ifc->csor_cs[priv->bank].csor);
+
+	/* Hardware generates ECC per 512 Bytes */
+	chip->ecc.size = 512;
+	chip->ecc.bytes = 8;
+
+	switch (csor & CSOR_NAND_PGS_MASK) {
+	case CSOR_NAND_PGS_512:
+		if (chip->options & NAND_BUSWIDTH_16) {
+			layout = &oob_512_16bit_ecc4;
+		} else {
+			layout = &oob_512_8bit_ecc4;
+
+			/* Avoid conflict with bad block marker */
+			bbt_main_descr.offs = 0;
+			bbt_mirror_descr.offs = 0;
+		}
+
+		priv->bufnum_mask = 15;
+		break;
+
+	case CSOR_NAND_PGS_2K:
+		layout = &oob_2048_ecc4;
+		priv->bufnum_mask = 3;
+		break;
+
+	case CSOR_NAND_PGS_4K:
+		if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
+		    CSOR_NAND_ECC_MODE_4) {
+			layout = &oob_4096_ecc4;
+		} else {
+			layout = &oob_4096_ecc8;
+			chip->ecc.bytes = 16;
+		}
+
+		priv->bufnum_mask = 1;
+		break;
+
+	default:
+		dev_err(priv->dev, "bad csor %#x: bad page size\n", csor);
+		return -ENODEV;
+	}
+
+	/* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */
+	if (csor & CSOR_NAND_ECC_DEC_EN) {
+		chip->ecc.mode = NAND_ECC_HW;
+		chip->ecc.layout = layout;
+	} else {
+		chip->ecc.mode = NAND_ECC_SOFT;
+	}
+
+	return 0;
+}
+
+static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
+{
+	nand_release(&priv->mtd);
+
+	kfree(priv->mtd.name);
+
+	if (priv->vbase)
+		iounmap(priv->vbase);
+
+	ifc_nand_ctrl->chips[priv->bank] = NULL;
+	dev_set_drvdata(priv->dev, NULL);
+	kfree(priv);
+
+	return 0;
+}
+
+static int match_bank(struct fsl_ifc_regs __iomem *ifc, int bank,
+		      phys_addr_t addr)
+{
+	u32 cspr = in_be32(&ifc->cspr_cs[bank].cspr);
+
+	if (!(cspr & CSPR_V))
+		return 0;
+	if ((cspr & CSPR_MSEL) != CSPR_MSEL_NAND)
+		return 0;
+
+	return (cspr & CSPR_BA) == convert_ifc_address(addr);
+}
+
+static DEFINE_MUTEX(fsl_ifc_nand_mutex);
+
+static int __devinit fsl_ifc_nand_probe(struct platform_device *dev)
+{
+	struct fsl_ifc_regs __iomem *ifc;
+	struct fsl_ifc_mtd *priv;
+	struct resource res;
+	static const char *part_probe_types[]
+		= { "cmdlinepart", "RedBoot", "ofpart", NULL };
+	int ret;
+	int bank;
+	struct device_node *node = dev->dev.of_node;
+	struct mtd_part_parser_data ppdata;
+
+	ppdata.of_node = dev->dev.of_node;
+	if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs)
+		return -ENODEV;
+	ifc = fsl_ifc_ctrl_dev->regs;
+
+	/* get, allocate and map the memory resource */
+	ret = of_address_to_resource(node, 0, &res);
+	if (ret) {
+		dev_err(&dev->dev, "%s: failed to get resource\n", __func__);
+		return ret;
+	}
+
+	/* find which chip select it is connected to */
+	for (bank = 0; bank < FSL_IFC_BANK_COUNT; bank++) {
+		if (match_bank(ifc, bank, res.start))
+			break;
+	}
+
+	if (bank >= FSL_IFC_BANK_COUNT) {
+		dev_err(&dev->dev, "%s: address did not match any chip selects\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_lock(&fsl_ifc_nand_mutex);
+	if (!fsl_ifc_ctrl_dev->nand) {
+		ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL);
+		if (!ifc_nand_ctrl) {
+			dev_err(&dev->dev, "failed to allocate memory\n");
+			mutex_unlock(&fsl_ifc_nand_mutex);
+			return -ENOMEM;
+		}
+
+		ifc_nand_ctrl->read_bytes = 0;
+		ifc_nand_ctrl->index = 0;
+		ifc_nand_ctrl->addr = NULL;
+		fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
+
+		spin_lock_init(&ifc_nand_ctrl->controller.lock);
+		init_waitqueue_head(&ifc_nand_ctrl->controller.wq);
+	} else {
+		ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
+	}
+	mutex_unlock(&fsl_ifc_nand_mutex);
+
+	ifc_nand_ctrl->chips[bank] = priv;
+	priv->bank = bank;
+	priv->ctrl = fsl_ifc_ctrl_dev;
+	priv->dev = &dev->dev;
+
+	priv->vbase = ioremap(res.start, resource_size(&res));
+	if (!priv->vbase) {
+		dev_err(priv->dev, "%s: failed to map chip region\n", __func__);
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	dev_set_drvdata(priv->dev, priv);
+
+	out_be32(&ifc->ifc_nand.nand_evter_en,
+			IFC_NAND_EVTER_EN_OPC_EN |
+			IFC_NAND_EVTER_EN_FTOER_EN |
+			IFC_NAND_EVTER_EN_WPER_EN);
+
+	/* enable NAND Machine Interrupts */
+	out_be32(&ifc->ifc_nand.nand_evter_intr_en,
+			IFC_NAND_EVTER_INTR_OPCIR_EN |
+			IFC_NAND_EVTER_INTR_FTOERIR_EN |
+			IFC_NAND_EVTER_INTR_WPERIR_EN);
+
+	priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start);
+	if (!priv->mtd.name) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = fsl_ifc_chip_init(priv);
+	if (ret)
+		goto err;
+
+	ret = nand_scan_ident(&priv->mtd, 1, NULL);
+	if (ret)
+		goto err;
+
+	ret = fsl_ifc_chip_init_tail(&priv->mtd);
+	if (ret)
+		goto err;
+
+	ret = nand_scan_tail(&priv->mtd);
+	if (ret)
+		goto err;
+
+	/* First look for RedBoot table or partitions on the command
+	 * line, these take precedence over device tree information */
+	mtd_device_parse_register(&priv->mtd, part_probe_types, &ppdata,
+						NULL, 0);
+
+	dev_info(priv->dev, "IFC NAND device at 0x%llx, bank %d\n",
+		 (unsigned long long)res.start, priv->bank);
+	return 0;
+
+err:
+	fsl_ifc_chip_remove(priv);
+	return ret;
+}
+
+static int fsl_ifc_nand_remove(struct platform_device *dev)
+{
+	struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev);
+
+	fsl_ifc_chip_remove(priv);
+
+	mutex_lock(&fsl_ifc_nand_mutex);
+	ifc_nand_ctrl->counter--;
+	if (!ifc_nand_ctrl->counter) {
+		fsl_ifc_ctrl_dev->nand = NULL;
+		kfree(ifc_nand_ctrl);
+	}
+	mutex_unlock(&fsl_ifc_nand_mutex);
+
+	return 0;
+}
+
+static const struct of_device_id fsl_ifc_nand_match[] = {
+	{
+		.compatible = "fsl,ifc-nand",
+	},
+	{}
+};
+
+static struct platform_driver fsl_ifc_nand_driver = {
+	.driver = {
+		.name	= "fsl,ifc-nand",
+		.owner = THIS_MODULE,
+		.of_match_table = fsl_ifc_nand_match,
+	},
+	.probe       = fsl_ifc_nand_probe,
+	.remove      = fsl_ifc_nand_remove,
+};
+
+static int __init fsl_ifc_nand_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&fsl_ifc_nand_driver);
+	if (ret)
+		printk(KERN_ERR "fsl-ifc: Failed to register platform"
+				"driver\n");
+
+	return ret;
+}
+
+static void __exit fsl_ifc_nand_exit(void)
+{
+	platform_driver_unregister(&fsl_ifc_nand_driver);
+}
+
+module_init(fsl_ifc_nand_init);
+module_exit(fsl_ifc_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale");
+MODULE_DESCRIPTION("Freescale Integrated Flash Controller MTD NAND driver");
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index e53b760..1b8330e 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -17,6 +17,10 @@
  */
 
 #include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -27,6 +31,7 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 #include <linux/slab.h>
@@ -34,7 +39,7 @@
 #include <linux/amba/bus.h>
 #include <mtd/mtd-abi.h>
 
-static struct nand_ecclayout fsmc_ecc1_layout = {
+static struct nand_ecclayout fsmc_ecc1_128_layout = {
 	.eccbytes = 24,
 	.eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52,
 		66, 67, 68, 82, 83, 84, 98, 99, 100, 114, 115, 116},
@@ -50,7 +55,127 @@
 	}
 };
 
-static struct nand_ecclayout fsmc_ecc4_lp_layout = {
+static struct nand_ecclayout fsmc_ecc1_64_layout = {
+	.eccbytes = 12,
+	.eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52},
+	.oobfree = {
+		{.offset = 8, .length = 8},
+		{.offset = 24, .length = 8},
+		{.offset = 40, .length = 8},
+		{.offset = 56, .length = 8},
+	}
+};
+
+static struct nand_ecclayout fsmc_ecc1_16_layout = {
+	.eccbytes = 3,
+	.eccpos = {2, 3, 4},
+	.oobfree = {
+		{.offset = 8, .length = 8},
+	}
+};
+
+/*
+ * ECC4 layout for NAND of pagesize 8192 bytes & OOBsize 256 bytes. 13*16 bytes
+ * of OB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block and 46
+ * bytes are free for use.
+ */
+static struct nand_ecclayout fsmc_ecc4_256_layout = {
+	.eccbytes = 208,
+	.eccpos = {  2,   3,   4,   5,   6,   7,   8,
+		9,  10,  11,  12,  13,  14,
+		18,  19,  20,  21,  22,  23,  24,
+		25,  26,  27,  28,  29,  30,
+		34,  35,  36,  37,  38,  39,  40,
+		41,  42,  43,  44,  45,  46,
+		50,  51,  52,  53,  54,  55,  56,
+		57,  58,  59,  60,  61,  62,
+		66,  67,  68,  69,  70,  71,  72,
+		73,  74,  75,  76,  77,  78,
+		82,  83,  84,  85,  86,  87,  88,
+		89,  90,  91,  92,  93,  94,
+		98,  99, 100, 101, 102, 103, 104,
+		105, 106, 107, 108, 109, 110,
+		114, 115, 116, 117, 118, 119, 120,
+		121, 122, 123, 124, 125, 126,
+		130, 131, 132, 133, 134, 135, 136,
+		137, 138, 139, 140, 141, 142,
+		146, 147, 148, 149, 150, 151, 152,
+		153, 154, 155, 156, 157, 158,
+		162, 163, 164, 165, 166, 167, 168,
+		169, 170, 171, 172, 173, 174,
+		178, 179, 180, 181, 182, 183, 184,
+		185, 186, 187, 188, 189, 190,
+		194, 195, 196, 197, 198, 199, 200,
+		201, 202, 203, 204, 205, 206,
+		210, 211, 212, 213, 214, 215, 216,
+		217, 218, 219, 220, 221, 222,
+		226, 227, 228, 229, 230, 231, 232,
+		233, 234, 235, 236, 237, 238,
+		242, 243, 244, 245, 246, 247, 248,
+		249, 250, 251, 252, 253, 254
+	},
+	.oobfree = {
+		{.offset = 15, .length = 3},
+		{.offset = 31, .length = 3},
+		{.offset = 47, .length = 3},
+		{.offset = 63, .length = 3},
+		{.offset = 79, .length = 3},
+		{.offset = 95, .length = 3},
+		{.offset = 111, .length = 3},
+		{.offset = 127, .length = 3},
+		{.offset = 143, .length = 3},
+		{.offset = 159, .length = 3},
+		{.offset = 175, .length = 3},
+		{.offset = 191, .length = 3},
+		{.offset = 207, .length = 3},
+		{.offset = 223, .length = 3},
+		{.offset = 239, .length = 3},
+		{.offset = 255, .length = 1}
+	}
+};
+
+/*
+ * ECC4 layout for NAND of pagesize 4096 bytes & OOBsize 224 bytes. 13*8 bytes
+ * of OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block & 118
+ * bytes are free for use.
+ */
+static struct nand_ecclayout fsmc_ecc4_224_layout = {
+	.eccbytes = 104,
+	.eccpos = {  2,   3,   4,   5,   6,   7,   8,
+		9,  10,  11,  12,  13,  14,
+		18,  19,  20,  21,  22,  23,  24,
+		25,  26,  27,  28,  29,  30,
+		34,  35,  36,  37,  38,  39,  40,
+		41,  42,  43,  44,  45,  46,
+		50,  51,  52,  53,  54,  55,  56,
+		57,  58,  59,  60,  61,  62,
+		66,  67,  68,  69,  70,  71,  72,
+		73,  74,  75,  76,  77,  78,
+		82,  83,  84,  85,  86,  87,  88,
+		89,  90,  91,  92,  93,  94,
+		98,  99, 100, 101, 102, 103, 104,
+		105, 106, 107, 108, 109, 110,
+		114, 115, 116, 117, 118, 119, 120,
+		121, 122, 123, 124, 125, 126
+	},
+	.oobfree = {
+		{.offset = 15, .length = 3},
+		{.offset = 31, .length = 3},
+		{.offset = 47, .length = 3},
+		{.offset = 63, .length = 3},
+		{.offset = 79, .length = 3},
+		{.offset = 95, .length = 3},
+		{.offset = 111, .length = 3},
+		{.offset = 127, .length = 97}
+	}
+};
+
+/*
+ * ECC4 layout for NAND of pagesize 4096 bytes & OOBsize 128 bytes. 13*8 bytes
+ * of OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block & 22
+ * bytes are free for use.
+ */
+static struct nand_ecclayout fsmc_ecc4_128_layout = {
 	.eccbytes = 104,
 	.eccpos = {  2,   3,   4,   5,   6,   7,   8,
 		9,  10,  11,  12,  13,  14,
@@ -82,6 +207,45 @@
 };
 
 /*
+ * ECC4 layout for NAND of pagesize 2048 bytes & OOBsize 64 bytes. 13*4 bytes of
+ * OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block and 10
+ * bytes are free for use.
+ */
+static struct nand_ecclayout fsmc_ecc4_64_layout = {
+	.eccbytes = 52,
+	.eccpos = {  2,   3,   4,   5,   6,   7,   8,
+		9,  10,  11,  12,  13,  14,
+		18,  19,  20,  21,  22,  23,  24,
+		25,  26,  27,  28,  29,  30,
+		34,  35,  36,  37,  38,  39,  40,
+		41,  42,  43,  44,  45,  46,
+		50,  51,  52,  53,  54,  55,  56,
+		57,  58,  59,  60,  61,  62,
+	},
+	.oobfree = {
+		{.offset = 15, .length = 3},
+		{.offset = 31, .length = 3},
+		{.offset = 47, .length = 3},
+		{.offset = 63, .length = 1},
+	}
+};
+
+/*
+ * ECC4 layout for NAND of pagesize 512 bytes & OOBsize 16 bytes. 13 bytes of
+ * OOB size is reserved for ECC, Byte no. 4 & 5 reserved for bad block and One
+ * byte is free for use.
+ */
+static struct nand_ecclayout fsmc_ecc4_16_layout = {
+	.eccbytes = 13,
+	.eccpos = { 0,  1,  2,  3,  6,  7, 8,
+		9, 10, 11, 12, 13, 14
+	},
+	.oobfree = {
+		{.offset = 15, .length = 1},
+	}
+};
+
+/*
  * ECC placement definitions in oobfree type format.
  * There are 13 bytes of ecc for every 512 byte block and it has to be read
  * consecutively and immediately after the 512 byte data block for hardware to
@@ -103,16 +267,6 @@
 	}
 };
 
-static struct nand_ecclayout fsmc_ecc4_sp_layout = {
-	.eccbytes = 13,
-	.eccpos = { 0,  1,  2,  3,  6,  7, 8,
-		9, 10, 11, 12, 13, 14
-	},
-	.oobfree = {
-		{.offset = 15, .length = 1},
-	}
-};
-
 static struct fsmc_eccplace fsmc_ecc4_sp_place = {
 	.eccplace = {
 		{.offset = 0, .length = 4},
@@ -120,75 +274,24 @@
 	}
 };
 
-/*
- * Default partition tables to be used if the partition information not
- * provided through platform data.
- *
- * Default partition layout for small page(= 512 bytes) devices
- * Size for "Root file system" is updated in driver based on actual device size
- */
-static struct mtd_partition partition_info_16KB_blk[] = {
-	{
-		.name = "X-loader",
-		.offset = 0,
-		.size = 4*0x4000,
-	},
-	{
-		.name = "U-Boot",
-		.offset = 0x10000,
-		.size = 20*0x4000,
-	},
-	{
-		.name = "Kernel",
-		.offset = 0x60000,
-		.size = 256*0x4000,
-	},
-	{
-		.name = "Root File System",
-		.offset = 0x460000,
-		.size = MTDPART_SIZ_FULL,
-	},
-};
-
-/*
- * Default partition layout for large page(> 512 bytes) devices
- * Size for "Root file system" is updated in driver based on actual device size
- */
-static struct mtd_partition partition_info_128KB_blk[] = {
-	{
-		.name = "X-loader",
-		.offset = 0,
-		.size = 4*0x20000,
-	},
-	{
-		.name = "U-Boot",
-		.offset = 0x80000,
-		.size = 12*0x20000,
-	},
-	{
-		.name = "Kernel",
-		.offset = 0x200000,
-		.size = 48*0x20000,
-	},
-	{
-		.name = "Root File System",
-		.offset = 0x800000,
-		.size = MTDPART_SIZ_FULL,
-	},
-};
-
-
 /**
  * struct fsmc_nand_data - structure for FSMC NAND device state
  *
  * @pid:		Part ID on the AMBA PrimeCell format
  * @mtd:		MTD info for a NAND flash.
  * @nand:		Chip related info for a NAND flash.
+ * @partitions:		Partition info for a NAND Flash.
+ * @nr_partitions:	Total number of partition of a NAND flash.
  *
  * @ecc_place:		ECC placing locations in oobfree type format.
  * @bank:		Bank number for probed device.
  * @clk:		Clock structure for FSMC.
  *
+ * @read_dma_chan:	DMA channel for read access
+ * @write_dma_chan:	DMA channel for write access to NAND
+ * @dma_access_complete: Completion structure
+ *
+ * @data_pa:		NAND Physical port for Data.
  * @data_va:		NAND port for Data.
  * @cmd_va:		NAND port for Command.
  * @addr_va:		NAND port for Address.
@@ -198,16 +301,23 @@
 	u32			pid;
 	struct mtd_info		mtd;
 	struct nand_chip	nand;
+	struct mtd_partition	*partitions;
+	unsigned int		nr_partitions;
 
 	struct fsmc_eccplace	*ecc_place;
 	unsigned int		bank;
+	struct device		*dev;
+	enum access_mode	mode;
 	struct clk		*clk;
 
-	struct resource		*resregs;
-	struct resource		*rescmd;
-	struct resource		*resaddr;
-	struct resource		*resdata;
+	/* DMA related objects */
+	struct dma_chan		*read_dma_chan;
+	struct dma_chan		*write_dma_chan;
+	struct completion	dma_access_complete;
 
+	struct fsmc_nand_timings *dev_timings;
+
+	dma_addr_t		data_pa;
 	void __iomem		*data_va;
 	void __iomem		*cmd_va;
 	void __iomem		*addr_va;
@@ -251,28 +361,29 @@
 	struct nand_chip *this = mtd->priv;
 	struct fsmc_nand_data *host = container_of(mtd,
 					struct fsmc_nand_data, mtd);
-	struct fsmc_regs *regs = host->regs_va;
+	void *__iomem *regs = host->regs_va;
 	unsigned int bank = host->bank;
 
 	if (ctrl & NAND_CTRL_CHANGE) {
+		u32 pc;
+
 		if (ctrl & NAND_CLE) {
-			this->IO_ADDR_R = (void __iomem *)host->cmd_va;
-			this->IO_ADDR_W = (void __iomem *)host->cmd_va;
+			this->IO_ADDR_R = host->cmd_va;
+			this->IO_ADDR_W = host->cmd_va;
 		} else if (ctrl & NAND_ALE) {
-			this->IO_ADDR_R = (void __iomem *)host->addr_va;
-			this->IO_ADDR_W = (void __iomem *)host->addr_va;
+			this->IO_ADDR_R = host->addr_va;
+			this->IO_ADDR_W = host->addr_va;
 		} else {
-			this->IO_ADDR_R = (void __iomem *)host->data_va;
-			this->IO_ADDR_W = (void __iomem *)host->data_va;
+			this->IO_ADDR_R = host->data_va;
+			this->IO_ADDR_W = host->data_va;
 		}
 
-		if (ctrl & NAND_NCE) {
-			writel(readl(&regs->bank_regs[bank].pc) | FSMC_ENABLE,
-					&regs->bank_regs[bank].pc);
-		} else {
-			writel(readl(&regs->bank_regs[bank].pc) & ~FSMC_ENABLE,
-				       &regs->bank_regs[bank].pc);
-		}
+		pc = readl(FSMC_NAND_REG(regs, bank, PC));
+		if (ctrl & NAND_NCE)
+			pc |= FSMC_ENABLE;
+		else
+			pc &= ~FSMC_ENABLE;
+		writel(pc, FSMC_NAND_REG(regs, bank, PC));
 	}
 
 	mb();
@@ -287,22 +398,42 @@
  * This routine initializes timing parameters related to NAND memory access in
  * FSMC registers
  */
-static void __init fsmc_nand_setup(struct fsmc_regs *regs, uint32_t bank,
-				   uint32_t busw)
+static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
+			   uint32_t busw, struct fsmc_nand_timings *timings)
 {
 	uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
+	uint32_t tclr, tar, thiz, thold, twait, tset;
+	struct fsmc_nand_timings *tims;
+	struct fsmc_nand_timings default_timings = {
+		.tclr	= FSMC_TCLR_1,
+		.tar	= FSMC_TAR_1,
+		.thiz	= FSMC_THIZ_1,
+		.thold	= FSMC_THOLD_4,
+		.twait	= FSMC_TWAIT_6,
+		.tset	= FSMC_TSET_0,
+	};
+
+	if (timings)
+		tims = timings;
+	else
+		tims = &default_timings;
+
+	tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT;
+	tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT;
+	thiz = (tims->thiz & FSMC_THIZ_MASK) << FSMC_THIZ_SHIFT;
+	thold = (tims->thold & FSMC_THOLD_MASK) << FSMC_THOLD_SHIFT;
+	twait = (tims->twait & FSMC_TWAIT_MASK) << FSMC_TWAIT_SHIFT;
+	tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
 
 	if (busw)
-		writel(value | FSMC_DEVWID_16, &regs->bank_regs[bank].pc);
+		writel(value | FSMC_DEVWID_16, FSMC_NAND_REG(regs, bank, PC));
 	else
-		writel(value | FSMC_DEVWID_8, &regs->bank_regs[bank].pc);
+		writel(value | FSMC_DEVWID_8, FSMC_NAND_REG(regs, bank, PC));
 
-	writel(readl(&regs->bank_regs[bank].pc) | FSMC_TCLR_1 | FSMC_TAR_1,
-	       &regs->bank_regs[bank].pc);
-	writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0,
-	       &regs->bank_regs[bank].comm);
-	writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0,
-	       &regs->bank_regs[bank].attrib);
+	writel(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar,
+			FSMC_NAND_REG(regs, bank, PC));
+	writel(thiz | thold | twait | tset, FSMC_NAND_REG(regs, bank, COMM));
+	writel(thiz | thold | twait | tset, FSMC_NAND_REG(regs, bank, ATTRIB));
 }
 
 /*
@@ -312,15 +443,15 @@
 {
 	struct fsmc_nand_data *host = container_of(mtd,
 					struct fsmc_nand_data, mtd);
-	struct fsmc_regs *regs = host->regs_va;
+	void __iomem *regs = host->regs_va;
 	uint32_t bank = host->bank;
 
-	writel(readl(&regs->bank_regs[bank].pc) & ~FSMC_ECCPLEN_256,
-		       &regs->bank_regs[bank].pc);
-	writel(readl(&regs->bank_regs[bank].pc) & ~FSMC_ECCEN,
-			&regs->bank_regs[bank].pc);
-	writel(readl(&regs->bank_regs[bank].pc) | FSMC_ECCEN,
-			&regs->bank_regs[bank].pc);
+	writel(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256,
+			FSMC_NAND_REG(regs, bank, PC));
+	writel(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN,
+			FSMC_NAND_REG(regs, bank, PC));
+	writel(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN,
+			FSMC_NAND_REG(regs, bank, PC));
 }
 
 /*
@@ -333,37 +464,42 @@
 {
 	struct fsmc_nand_data *host = container_of(mtd,
 					struct fsmc_nand_data, mtd);
-	struct fsmc_regs *regs = host->regs_va;
+	void __iomem *regs = host->regs_va;
 	uint32_t bank = host->bank;
 	uint32_t ecc_tmp;
 	unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT;
 
 	do {
-		if (readl(&regs->bank_regs[bank].sts) & FSMC_CODE_RDY)
+		if (readl(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY)
 			break;
 		else
 			cond_resched();
 	} while (!time_after_eq(jiffies, deadline));
 
-	ecc_tmp = readl(&regs->bank_regs[bank].ecc1);
+	if (time_after_eq(jiffies, deadline)) {
+		dev_err(host->dev, "calculate ecc timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC1));
 	ecc[0] = (uint8_t) (ecc_tmp >> 0);
 	ecc[1] = (uint8_t) (ecc_tmp >> 8);
 	ecc[2] = (uint8_t) (ecc_tmp >> 16);
 	ecc[3] = (uint8_t) (ecc_tmp >> 24);
 
-	ecc_tmp = readl(&regs->bank_regs[bank].ecc2);
+	ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC2));
 	ecc[4] = (uint8_t) (ecc_tmp >> 0);
 	ecc[5] = (uint8_t) (ecc_tmp >> 8);
 	ecc[6] = (uint8_t) (ecc_tmp >> 16);
 	ecc[7] = (uint8_t) (ecc_tmp >> 24);
 
-	ecc_tmp = readl(&regs->bank_regs[bank].ecc3);
+	ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC3));
 	ecc[8] = (uint8_t) (ecc_tmp >> 0);
 	ecc[9] = (uint8_t) (ecc_tmp >> 8);
 	ecc[10] = (uint8_t) (ecc_tmp >> 16);
 	ecc[11] = (uint8_t) (ecc_tmp >> 24);
 
-	ecc_tmp = readl(&regs->bank_regs[bank].sts);
+	ecc_tmp = readl(FSMC_NAND_REG(regs, bank, STS));
 	ecc[12] = (uint8_t) (ecc_tmp >> 16);
 
 	return 0;
@@ -379,11 +515,11 @@
 {
 	struct fsmc_nand_data *host = container_of(mtd,
 					struct fsmc_nand_data, mtd);
-	struct fsmc_regs *regs = host->regs_va;
+	void __iomem *regs = host->regs_va;
 	uint32_t bank = host->bank;
 	uint32_t ecc_tmp;
 
-	ecc_tmp = readl(&regs->bank_regs[bank].ecc1);
+	ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC1));
 	ecc[0] = (uint8_t) (ecc_tmp >> 0);
 	ecc[1] = (uint8_t) (ecc_tmp >> 8);
 	ecc[2] = (uint8_t) (ecc_tmp >> 16);
@@ -391,6 +527,166 @@
 	return 0;
 }
 
+/* Count the number of 0's in buff upto a max of max_bits */
+static int count_written_bits(uint8_t *buff, int size, int max_bits)
+{
+	int k, written_bits = 0;
+
+	for (k = 0; k < size; k++) {
+		written_bits += hweight8(~buff[k]);
+		if (written_bits > max_bits)
+			break;
+	}
+
+	return written_bits;
+}
+
+static void dma_complete(void *param)
+{
+	struct fsmc_nand_data *host = param;
+
+	complete(&host->dma_access_complete);
+}
+
+static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,
+		enum dma_data_direction direction)
+{
+	struct dma_chan *chan;
+	struct dma_device *dma_dev;
+	struct dma_async_tx_descriptor *tx;
+	dma_addr_t dma_dst, dma_src, dma_addr;
+	dma_cookie_t cookie;
+	unsigned long flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+	int ret;
+
+	if (direction == DMA_TO_DEVICE)
+		chan = host->write_dma_chan;
+	else if (direction == DMA_FROM_DEVICE)
+		chan = host->read_dma_chan;
+	else
+		return -EINVAL;
+
+	dma_dev = chan->device;
+	dma_addr = dma_map_single(dma_dev->dev, buffer, len, direction);
+
+	if (direction == DMA_TO_DEVICE) {
+		dma_src = dma_addr;
+		dma_dst = host->data_pa;
+		flags |= DMA_COMPL_SRC_UNMAP_SINGLE | DMA_COMPL_SKIP_DEST_UNMAP;
+	} else {
+		dma_src = host->data_pa;
+		dma_dst = dma_addr;
+		flags |= DMA_COMPL_DEST_UNMAP_SINGLE | DMA_COMPL_SKIP_SRC_UNMAP;
+	}
+
+	tx = dma_dev->device_prep_dma_memcpy(chan, dma_dst, dma_src,
+			len, flags);
+
+	if (!tx) {
+		dev_err(host->dev, "device_prep_dma_memcpy error\n");
+		dma_unmap_single(dma_dev->dev, dma_addr, len, direction);
+		return -EIO;
+	}
+
+	tx->callback = dma_complete;
+	tx->callback_param = host;
+	cookie = tx->tx_submit(tx);
+
+	ret = dma_submit_error(cookie);
+	if (ret) {
+		dev_err(host->dev, "dma_submit_error %d\n", cookie);
+		return ret;
+	}
+
+	dma_async_issue_pending(chan);
+
+	ret =
+	wait_for_completion_interruptible_timeout(&host->dma_access_complete,
+				msecs_to_jiffies(3000));
+	if (ret <= 0) {
+		chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+		dev_err(host->dev, "wait_for_completion_timeout\n");
+		return ret ? ret : -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+/*
+ * fsmc_write_buf - write buffer to chip
+ * @mtd:	MTD device structure
+ * @buf:	data buffer
+ * @len:	number of bytes to write
+ */
+static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	int i;
+	struct nand_chip *chip = mtd->priv;
+
+	if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
+			IS_ALIGNED(len, sizeof(uint32_t))) {
+		uint32_t *p = (uint32_t *)buf;
+		len = len >> 2;
+		for (i = 0; i < len; i++)
+			writel(p[i], chip->IO_ADDR_W);
+	} else {
+		for (i = 0; i < len; i++)
+			writeb(buf[i], chip->IO_ADDR_W);
+	}
+}
+
+/*
+ * fsmc_read_buf - read chip data into buffer
+ * @mtd:	MTD device structure
+ * @buf:	buffer to store date
+ * @len:	number of bytes to read
+ */
+static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	int i;
+	struct nand_chip *chip = mtd->priv;
+
+	if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
+			IS_ALIGNED(len, sizeof(uint32_t))) {
+		uint32_t *p = (uint32_t *)buf;
+		len = len >> 2;
+		for (i = 0; i < len; i++)
+			p[i] = readl(chip->IO_ADDR_R);
+	} else {
+		for (i = 0; i < len; i++)
+			buf[i] = readb(chip->IO_ADDR_R);
+	}
+}
+
+/*
+ * fsmc_read_buf_dma - read chip data into buffer
+ * @mtd:	MTD device structure
+ * @buf:	buffer to store date
+ * @len:	number of bytes to read
+ */
+static void fsmc_read_buf_dma(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct fsmc_nand_data *host;
+
+	host = container_of(mtd, struct fsmc_nand_data, mtd);
+	dma_xfer(host, buf, len, DMA_FROM_DEVICE);
+}
+
+/*
+ * fsmc_write_buf_dma - write buffer to chip
+ * @mtd:	MTD device structure
+ * @buf:	data buffer
+ * @len:	number of bytes to write
+ */
+static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
+		int len)
+{
+	struct fsmc_nand_data *host;
+
+	host = container_of(mtd, struct fsmc_nand_data, mtd);
+	dma_xfer(host, (void *)buf, len, DMA_TO_DEVICE);
+}
+
 /*
  * fsmc_read_page_hwecc
  * @mtd:	mtd info structure
@@ -426,7 +722,6 @@
 	uint8_t *oob = (uint8_t *)&ecc_oob[0];
 
 	for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
-
 		chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page);
 		chip->ecc.hwctl(mtd, NAND_ECC_READ);
 		chip->read_buf(mtd, p, eccsize);
@@ -437,17 +732,19 @@
 			group++;
 
 			/*
-			* length is intentionally kept a higher multiple of 2
-			* to read at least 13 bytes even in case of 16 bit NAND
-			* devices
-			*/
-			len = roundup(len, 2);
+			 * length is intentionally kept a higher multiple of 2
+			 * to read at least 13 bytes even in case of 16 bit NAND
+			 * devices
+			 */
+			if (chip->options & NAND_BUSWIDTH_16)
+				len = roundup(len, 2);
+
 			chip->cmdfunc(mtd, NAND_CMD_READOOB, off, page);
 			chip->read_buf(mtd, oob + j, len);
 			j += len;
 		}
 
-		memcpy(&ecc_code[i], oob, 13);
+		memcpy(&ecc_code[i], oob, chip->ecc.bytes);
 		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
 
 		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
@@ -461,7 +758,7 @@
 }
 
 /*
- * fsmc_correct_data
+ * fsmc_bch8_correct_data
  * @mtd:	mtd info structure
  * @dat:	buffer of read data
  * @read_ecc:	ecc read from device spare area
@@ -470,19 +767,51 @@
  * calc_ecc is a 104 bit information containing maximum of 8 error
  * offset informations of 13 bits each in 512 bytes of read data.
  */
-static int fsmc_correct_data(struct mtd_info *mtd, uint8_t *dat,
+static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
 			     uint8_t *read_ecc, uint8_t *calc_ecc)
 {
 	struct fsmc_nand_data *host = container_of(mtd,
 					struct fsmc_nand_data, mtd);
-	struct fsmc_regs *regs = host->regs_va;
+	struct nand_chip *chip = mtd->priv;
+	void __iomem *regs = host->regs_va;
 	unsigned int bank = host->bank;
-	uint16_t err_idx[8];
-	uint64_t ecc_data[2];
+	uint32_t err_idx[8];
 	uint32_t num_err, i;
+	uint32_t ecc1, ecc2, ecc3, ecc4;
 
-	/* The calculated ecc is actually the correction index in data */
-	memcpy(ecc_data, calc_ecc, 13);
+	num_err = (readl(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF;
+
+	/* no bit flipping */
+	if (likely(num_err == 0))
+		return 0;
+
+	/* too many errors */
+	if (unlikely(num_err > 8)) {
+		/*
+		 * This is a temporary erase check. A newly erased page read
+		 * would result in an ecc error because the oob data is also
+		 * erased to FF and the calculated ecc for an FF data is not
+		 * FF..FF.
+		 * This is a workaround to skip performing correction in case
+		 * data is FF..FF
+		 *
+		 * Logic:
+		 * For every page, each bit written as 0 is counted until these
+		 * number of bits are greater than 8 (the maximum correction
+		 * capability of FSMC for each 512 + 13 bytes)
+		 */
+
+		int bits_ecc = count_written_bits(read_ecc, chip->ecc.bytes, 8);
+		int bits_data = count_written_bits(dat, chip->ecc.size, 8);
+
+		if ((bits_ecc + bits_data) <= 8) {
+			if (bits_data)
+				memset(dat, 0xff, chip->ecc.size);
+			return bits_data;
+		}
+
+		return -EBADMSG;
+	}
 
 	/*
 	 * ------------------- calc_ecc[] bit wise -----------|--13 bits--|
@@ -493,27 +822,26 @@
 	 * uint64_t array and error offset indexes are populated in err_idx
 	 * array
 	 */
-	for (i = 0; i < 8; i++) {
-		if (i == 4) {
-			err_idx[4] = ((ecc_data[1] & 0x1) << 12) | ecc_data[0];
-			ecc_data[1] >>= 1;
-			continue;
-		}
-		err_idx[i] = (ecc_data[i/4] & 0x1FFF);
-		ecc_data[i/4] >>= 13;
-	}
+	ecc1 = readl(FSMC_NAND_REG(regs, bank, ECC1));
+	ecc2 = readl(FSMC_NAND_REG(regs, bank, ECC2));
+	ecc3 = readl(FSMC_NAND_REG(regs, bank, ECC3));
+	ecc4 = readl(FSMC_NAND_REG(regs, bank, STS));
 
-	num_err = (readl(&regs->bank_regs[bank].sts) >> 10) & 0xF;
-
-	if (num_err == 0xF)
-		return -EBADMSG;
+	err_idx[0] = (ecc1 >> 0) & 0x1FFF;
+	err_idx[1] = (ecc1 >> 13) & 0x1FFF;
+	err_idx[2] = (((ecc2 >> 0) & 0x7F) << 6) | ((ecc1 >> 26) & 0x3F);
+	err_idx[3] = (ecc2 >> 7) & 0x1FFF;
+	err_idx[4] = (((ecc3 >> 0) & 0x1) << 12) | ((ecc2 >> 20) & 0xFFF);
+	err_idx[5] = (ecc3 >> 1) & 0x1FFF;
+	err_idx[6] = (ecc3 >> 14) & 0x1FFF;
+	err_idx[7] = (((ecc4 >> 16) & 0xFF) << 5) | ((ecc3 >> 27) & 0x1F);
 
 	i = 0;
 	while (num_err--) {
 		change_bit(0, (unsigned long *)&err_idx[i]);
 		change_bit(1, (unsigned long *)&err_idx[i]);
 
-		if (err_idx[i] <= 512 * 8) {
+		if (err_idx[i] < chip->ecc.size * 8) {
 			change_bit(err_idx[i], (unsigned long *)dat);
 			i++;
 		}
@@ -521,6 +849,44 @@
 	return i;
 }
 
+static bool filter(struct dma_chan *chan, void *slave)
+{
+	chan->private = slave;
+	return true;
+}
+
+#ifdef CONFIG_OF
+static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
+					       struct device_node *np)
+{
+	struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
+	u32 val;
+
+	/* Set default NAND width to 8 bits */
+	pdata->width = 8;
+	if (!of_property_read_u32(np, "bank-width", &val)) {
+		if (val == 2) {
+			pdata->width = 16;
+		} else if (val != 1) {
+			dev_err(&pdev->dev, "invalid bank-width %u\n", val);
+			return -EINVAL;
+		}
+	}
+	of_property_read_u32(np, "st,ale-off", &pdata->ale_off);
+	of_property_read_u32(np, "st,cle-off", &pdata->cle_off);
+	if (of_get_property(np, "nand-skip-bbtscan", NULL))
+		pdata->options = NAND_SKIP_BBTSCAN;
+
+	return 0;
+}
+#else
+static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
+					       struct device_node *np)
+{
+	return -ENOSYS;
+}
+#endif
+
 /*
  * fsmc_nand_probe - Probe function
  * @pdev:       platform device structure
@@ -528,102 +894,109 @@
 static int __init fsmc_nand_probe(struct platform_device *pdev)
 {
 	struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
+	struct device_node __maybe_unused *np = pdev->dev.of_node;
+	struct mtd_part_parser_data ppdata = {};
 	struct fsmc_nand_data *host;
 	struct mtd_info *mtd;
 	struct nand_chip *nand;
-	struct fsmc_regs *regs;
 	struct resource *res;
+	dma_cap_mask_t mask;
 	int ret = 0;
 	u32 pid;
 	int i;
 
+	if (np) {
+		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+		pdev->dev.platform_data = pdata;
+		ret = fsmc_nand_probe_config_dt(pdev, np);
+		if (ret) {
+			dev_err(&pdev->dev, "no platform data\n");
+			return -ENODEV;
+		}
+	}
+
 	if (!pdata) {
 		dev_err(&pdev->dev, "platform data is NULL\n");
 		return -EINVAL;
 	}
 
 	/* Allocate memory for the device structure (and zero it) */
-	host = kzalloc(sizeof(*host), GFP_KERNEL);
+	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
 	if (!host) {
 		dev_err(&pdev->dev, "failed to allocate device structure\n");
 		return -ENOMEM;
 	}
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
-	if (!res) {
-		ret = -EIO;
-		goto err_probe1;
+	if (!res)
+		return -EINVAL;
+
+	if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
+				pdev->name)) {
+		dev_err(&pdev->dev, "Failed to get memory data resourse\n");
+		return -ENOENT;
 	}
 
-	host->resdata = request_mem_region(res->start, resource_size(res),
-			pdev->name);
-	if (!host->resdata) {
-		ret = -EIO;
-		goto err_probe1;
-	}
-
-	host->data_va = ioremap(res->start, resource_size(res));
+	host->data_pa = (dma_addr_t)res->start;
+	host->data_va = devm_ioremap(&pdev->dev, res->start,
+			resource_size(res));
 	if (!host->data_va) {
-		ret = -EIO;
-		goto err_probe1;
+		dev_err(&pdev->dev, "data ioremap failed\n");
+		return -ENOMEM;
 	}
 
-	host->resaddr = request_mem_region(res->start + PLAT_NAND_ALE,
-			resource_size(res), pdev->name);
-	if (!host->resaddr) {
-		ret = -EIO;
-		goto err_probe1;
+	if (!devm_request_mem_region(&pdev->dev, res->start + pdata->ale_off,
+			resource_size(res), pdev->name)) {
+		dev_err(&pdev->dev, "Failed to get memory ale resourse\n");
+		return -ENOENT;
 	}
 
-	host->addr_va = ioremap(res->start + PLAT_NAND_ALE, resource_size(res));
+	host->addr_va = devm_ioremap(&pdev->dev, res->start + pdata->ale_off,
+			resource_size(res));
 	if (!host->addr_va) {
-		ret = -EIO;
-		goto err_probe1;
+		dev_err(&pdev->dev, "ale ioremap failed\n");
+		return -ENOMEM;
 	}
 
-	host->rescmd = request_mem_region(res->start + PLAT_NAND_CLE,
-			resource_size(res), pdev->name);
-	if (!host->rescmd) {
-		ret = -EIO;
-		goto err_probe1;
+	if (!devm_request_mem_region(&pdev->dev, res->start + pdata->cle_off,
+			resource_size(res), pdev->name)) {
+		dev_err(&pdev->dev, "Failed to get memory cle resourse\n");
+		return -ENOENT;
 	}
 
-	host->cmd_va = ioremap(res->start + PLAT_NAND_CLE, resource_size(res));
+	host->cmd_va = devm_ioremap(&pdev->dev, res->start + pdata->cle_off,
+			resource_size(res));
 	if (!host->cmd_va) {
-		ret = -EIO;
-		goto err_probe1;
+		dev_err(&pdev->dev, "ale ioremap failed\n");
+		return -ENOMEM;
 	}
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs");
-	if (!res) {
-		ret = -EIO;
-		goto err_probe1;
+	if (!res)
+		return -EINVAL;
+
+	if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
+			pdev->name)) {
+		dev_err(&pdev->dev, "Failed to get memory regs resourse\n");
+		return -ENOENT;
 	}
 
-	host->resregs = request_mem_region(res->start, resource_size(res),
-			pdev->name);
-	if (!host->resregs) {
-		ret = -EIO;
-		goto err_probe1;
-	}
-
-	host->regs_va = ioremap(res->start, resource_size(res));
+	host->regs_va = devm_ioremap(&pdev->dev, res->start,
+			resource_size(res));
 	if (!host->regs_va) {
-		ret = -EIO;
-		goto err_probe1;
+		dev_err(&pdev->dev, "regs ioremap failed\n");
+		return -ENOMEM;
 	}
 
 	host->clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(host->clk)) {
 		dev_err(&pdev->dev, "failed to fetch block clock\n");
-		ret = PTR_ERR(host->clk);
-		host->clk = NULL;
-		goto err_probe1;
+		return PTR_ERR(host->clk);
 	}
 
 	ret = clk_enable(host->clk);
 	if (ret)
-		goto err_probe1;
+		goto err_clk_enable;
 
 	/*
 	 * This device ID is actually a common AMBA ID as used on the
@@ -639,7 +1012,14 @@
 
 	host->bank = pdata->bank;
 	host->select_chip = pdata->select_bank;
-	regs = host->regs_va;
+	host->partitions = pdata->partitions;
+	host->nr_partitions = pdata->nr_partitions;
+	host->dev = &pdev->dev;
+	host->dev_timings = pdata->nand_timings;
+	host->mode = pdata->mode;
+
+	if (host->mode == USE_DMA_ACCESS)
+		init_completion(&host->dma_access_complete);
 
 	/* Link all private pointers */
 	mtd = &host->mtd;
@@ -658,21 +1038,53 @@
 	nand->ecc.size = 512;
 	nand->options = pdata->options;
 	nand->select_chip = fsmc_select_chip;
+	nand->badblockbits = 7;
 
 	if (pdata->width == FSMC_NAND_BW16)
 		nand->options |= NAND_BUSWIDTH_16;
 
-	fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16);
+	switch (host->mode) {
+	case USE_DMA_ACCESS:
+		dma_cap_zero(mask);
+		dma_cap_set(DMA_MEMCPY, mask);
+		host->read_dma_chan = dma_request_channel(mask, filter,
+				pdata->read_dma_priv);
+		if (!host->read_dma_chan) {
+			dev_err(&pdev->dev, "Unable to get read dma channel\n");
+			goto err_req_read_chnl;
+		}
+		host->write_dma_chan = dma_request_channel(mask, filter,
+				pdata->write_dma_priv);
+		if (!host->write_dma_chan) {
+			dev_err(&pdev->dev, "Unable to get write dma channel\n");
+			goto err_req_write_chnl;
+		}
+		nand->read_buf = fsmc_read_buf_dma;
+		nand->write_buf = fsmc_write_buf_dma;
+		break;
+
+	default:
+	case USE_WORD_ACCESS:
+		nand->read_buf = fsmc_read_buf;
+		nand->write_buf = fsmc_write_buf;
+		break;
+	}
+
+	fsmc_nand_setup(host->regs_va, host->bank,
+			nand->options & NAND_BUSWIDTH_16,
+			host->dev_timings);
 
 	if (AMBA_REV_BITS(host->pid) >= 8) {
 		nand->ecc.read_page = fsmc_read_page_hwecc;
 		nand->ecc.calculate = fsmc_read_hwecc_ecc4;
-		nand->ecc.correct = fsmc_correct_data;
+		nand->ecc.correct = fsmc_bch8_correct_data;
 		nand->ecc.bytes = 13;
+		nand->ecc.strength = 8;
 	} else {
 		nand->ecc.calculate = fsmc_read_hwecc_ecc1;
 		nand->ecc.correct = nand_correct_data;
 		nand->ecc.bytes = 3;
+		nand->ecc.strength = 1;
 	}
 
 	/*
@@ -681,19 +1093,52 @@
 	if (nand_scan_ident(&host->mtd, 1, NULL)) {
 		ret = -ENXIO;
 		dev_err(&pdev->dev, "No NAND Device found!\n");
-		goto err_probe;
+		goto err_scan_ident;
 	}
 
 	if (AMBA_REV_BITS(host->pid) >= 8) {
-		if (host->mtd.writesize == 512) {
-			nand->ecc.layout = &fsmc_ecc4_sp_layout;
+		switch (host->mtd.oobsize) {
+		case 16:
+			nand->ecc.layout = &fsmc_ecc4_16_layout;
 			host->ecc_place = &fsmc_ecc4_sp_place;
-		} else {
-			nand->ecc.layout = &fsmc_ecc4_lp_layout;
+			break;
+		case 64:
+			nand->ecc.layout = &fsmc_ecc4_64_layout;
 			host->ecc_place = &fsmc_ecc4_lp_place;
+			break;
+		case 128:
+			nand->ecc.layout = &fsmc_ecc4_128_layout;
+			host->ecc_place = &fsmc_ecc4_lp_place;
+			break;
+		case 224:
+			nand->ecc.layout = &fsmc_ecc4_224_layout;
+			host->ecc_place = &fsmc_ecc4_lp_place;
+			break;
+		case 256:
+			nand->ecc.layout = &fsmc_ecc4_256_layout;
+			host->ecc_place = &fsmc_ecc4_lp_place;
+			break;
+		default:
+			printk(KERN_WARNING "No oob scheme defined for "
+			       "oobsize %d\n", mtd->oobsize);
+			BUG();
 		}
 	} else {
-		nand->ecc.layout = &fsmc_ecc1_layout;
+		switch (host->mtd.oobsize) {
+		case 16:
+			nand->ecc.layout = &fsmc_ecc1_16_layout;
+			break;
+		case 64:
+			nand->ecc.layout = &fsmc_ecc1_64_layout;
+			break;
+		case 128:
+			nand->ecc.layout = &fsmc_ecc1_128_layout;
+			break;
+		default:
+			printk(KERN_WARNING "No oob scheme defined for "
+			       "oobsize %d\n", mtd->oobsize);
+			BUG();
+		}
 	}
 
 	/* Second stage of scan to fill MTD data-structures */
@@ -713,13 +1158,9 @@
 	 * Check for partition info passed
 	 */
 	host->mtd.name = "nand";
-	ret = mtd_device_parse_register(&host->mtd, NULL, 0,
-			host->mtd.size <= 0x04000000 ?
-				partition_info_16KB_blk :
-				partition_info_128KB_blk,
-			host->mtd.size <= 0x04000000 ?
-				ARRAY_SIZE(partition_info_16KB_blk) :
-				ARRAY_SIZE(partition_info_128KB_blk));
+	ppdata.of_node = np;
+	ret = mtd_device_parse_register(&host->mtd, NULL, &ppdata,
+					host->partitions, host->nr_partitions);
 	if (ret)
 		goto err_probe;
 
@@ -728,32 +1169,16 @@
 	return 0;
 
 err_probe:
+err_scan_ident:
+	if (host->mode == USE_DMA_ACCESS)
+		dma_release_channel(host->write_dma_chan);
+err_req_write_chnl:
+	if (host->mode == USE_DMA_ACCESS)
+		dma_release_channel(host->read_dma_chan);
+err_req_read_chnl:
 	clk_disable(host->clk);
-err_probe1:
-	if (host->clk)
-		clk_put(host->clk);
-	if (host->regs_va)
-		iounmap(host->regs_va);
-	if (host->resregs)
-		release_mem_region(host->resregs->start,
-				resource_size(host->resregs));
-	if (host->cmd_va)
-		iounmap(host->cmd_va);
-	if (host->rescmd)
-		release_mem_region(host->rescmd->start,
-				resource_size(host->rescmd));
-	if (host->addr_va)
-		iounmap(host->addr_va);
-	if (host->resaddr)
-		release_mem_region(host->resaddr->start,
-				resource_size(host->resaddr));
-	if (host->data_va)
-		iounmap(host->data_va);
-	if (host->resdata)
-		release_mem_region(host->resdata->start,
-				resource_size(host->resdata));
-
-	kfree(host);
+err_clk_enable:
+	clk_put(host->clk);
 	return ret;
 }
 
@@ -768,24 +1193,15 @@
 
 	if (host) {
 		nand_release(&host->mtd);
+
+		if (host->mode == USE_DMA_ACCESS) {
+			dma_release_channel(host->write_dma_chan);
+			dma_release_channel(host->read_dma_chan);
+		}
 		clk_disable(host->clk);
 		clk_put(host->clk);
-
-		iounmap(host->regs_va);
-		release_mem_region(host->resregs->start,
-				resource_size(host->resregs));
-		iounmap(host->cmd_va);
-		release_mem_region(host->rescmd->start,
-				resource_size(host->rescmd));
-		iounmap(host->addr_va);
-		release_mem_region(host->resaddr->start,
-				resource_size(host->resaddr));
-		iounmap(host->data_va);
-		release_mem_region(host->resdata->start,
-				resource_size(host->resdata));
-
-		kfree(host);
 	}
+
 	return 0;
 }
 
@@ -801,15 +1217,24 @@
 static int fsmc_nand_resume(struct device *dev)
 {
 	struct fsmc_nand_data *host = dev_get_drvdata(dev);
-	if (host)
+	if (host) {
 		clk_enable(host->clk);
+		fsmc_nand_setup(host->regs_va, host->bank,
+				host->nand.options & NAND_BUSWIDTH_16,
+				host->dev_timings);
+	}
 	return 0;
 }
 
-static const struct dev_pm_ops fsmc_nand_pm_ops = {
-	.suspend = fsmc_nand_suspend,
-	.resume = fsmc_nand_resume,
+static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id fsmc_nand_id_table[] = {
+	{ .compatible = "st,spear600-fsmc-nand" },
+	{}
 };
+MODULE_DEVICE_TABLE(of, fsmc_nand_id_table);
 #endif
 
 static struct platform_driver fsmc_nand_driver = {
@@ -817,6 +1242,7 @@
 	.driver = {
 		.owner = THIS_MODULE,
 		.name = "fsmc-nand",
+		.of_match_table = of_match_ptr(fsmc_nand_id_table),
 #ifdef CONFIG_PM
 		.pm = &fsmc_nand_pm_ops,
 #endif
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
index 7db6555..e8ea710 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
@@ -835,7 +835,7 @@
 		| BM_GPMI_CTRL0_ADDRESS_INCREMENT
 		| BF_GPMI_CTRL0_XFER_COUNT(this->command_length);
 	pio[1] = pio[2] = 0;
-	desc = channel->device->device_prep_slave_sg(channel,
+	desc = dmaengine_prep_slave_sg(channel,
 					(struct scatterlist *)pio,
 					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
 	if (!desc) {
@@ -848,8 +848,10 @@
 
 	sg_init_one(sgl, this->cmd_buffer, this->command_length);
 	dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE);
-	desc = channel->device->device_prep_slave_sg(channel,
-					sgl, 1, DMA_MEM_TO_DEV, 1);
+	desc = dmaengine_prep_slave_sg(channel,
+				sgl, 1, DMA_MEM_TO_DEV,
+				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+
 	if (!desc) {
 		pr_err("step 2 error\n");
 		return -1;
@@ -880,8 +882,7 @@
 		| BF_GPMI_CTRL0_ADDRESS(address)
 		| BF_GPMI_CTRL0_XFER_COUNT(this->upper_len);
 	pio[1] = 0;
-	desc = channel->device->device_prep_slave_sg(channel,
-					(struct scatterlist *)pio,
+	desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio,
 					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
 	if (!desc) {
 		pr_err("step 1 error\n");
@@ -890,8 +891,9 @@
 
 	/* [2] send DMA request */
 	prepare_data_dma(this, DMA_TO_DEVICE);
-	desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl,
-						1, DMA_MEM_TO_DEV, 1);
+	desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
+					1, DMA_MEM_TO_DEV,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc) {
 		pr_err("step 2 error\n");
 		return -1;
@@ -916,7 +918,7 @@
 		| BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA)
 		| BF_GPMI_CTRL0_XFER_COUNT(this->upper_len);
 	pio[1] = 0;
-	desc = channel->device->device_prep_slave_sg(channel,
+	desc = dmaengine_prep_slave_sg(channel,
 					(struct scatterlist *)pio,
 					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
 	if (!desc) {
@@ -926,8 +928,9 @@
 
 	/* [2] : send DMA request */
 	prepare_data_dma(this, DMA_FROM_DEVICE);
-	desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl,
-						1, DMA_DEV_TO_MEM, 1);
+	desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
+					1, DMA_DEV_TO_MEM,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc) {
 		pr_err("step 2 error\n");
 		return -1;
@@ -972,9 +975,10 @@
 	pio[4] = payload;
 	pio[5] = auxiliary;
 
-	desc = channel->device->device_prep_slave_sg(channel,
+	desc = dmaengine_prep_slave_sg(channel,
 					(struct scatterlist *)pio,
-					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
+					ARRAY_SIZE(pio), DMA_TRANS_NONE,
+					DMA_CTRL_ACK);
 	if (!desc) {
 		pr_err("step 2 error\n");
 		return -1;
@@ -1007,7 +1011,7 @@
 		| BF_GPMI_CTRL0_ADDRESS(address)
 		| BF_GPMI_CTRL0_XFER_COUNT(0);
 	pio[1] = 0;
-	desc = channel->device->device_prep_slave_sg(channel,
+	desc = dmaengine_prep_slave_sg(channel,
 				(struct scatterlist *)pio, 2,
 				DMA_TRANS_NONE, 0);
 	if (!desc) {
@@ -1036,9 +1040,10 @@
 	pio[3] = geo->page_size;
 	pio[4] = payload;
 	pio[5] = auxiliary;
-	desc = channel->device->device_prep_slave_sg(channel,
+	desc = dmaengine_prep_slave_sg(channel,
 					(struct scatterlist *)pio,
-					ARRAY_SIZE(pio), DMA_TRANS_NONE, 1);
+					ARRAY_SIZE(pio), DMA_TRANS_NONE,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc) {
 		pr_err("step 2 error\n");
 		return -1;
@@ -1055,9 +1060,11 @@
 		| BF_GPMI_CTRL0_ADDRESS(address)
 		| BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
 	pio[1] = 0;
-	desc = channel->device->device_prep_slave_sg(channel,
-				(struct scatterlist *)pio, 2,
-				DMA_TRANS_NONE, 1);
+	pio[2] = 0; /* clear GPMI_HW_GPMI_ECCCTRL, disable the BCH. */
+	desc = dmaengine_prep_slave_sg(channel,
+				(struct scatterlist *)pio, 3,
+				DMA_TRANS_NONE,
+				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc) {
 		pr_err("step 3 error\n");
 		return -1;
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 493ec2f..75b1dde 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -1124,7 +1124,7 @@
 		chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
 
 	/* Do we have a flash based bad block table ? */
-	if (chip->options & NAND_BBT_USE_FLASH)
+	if (chip->bbt_options & NAND_BBT_USE_FLASH)
 		ret = nand_update_bbt(mtd, ofs);
 	else {
 		chipnr = (int)(ofs >> chip->chip_shift);
@@ -1155,7 +1155,7 @@
 	return ret;
 }
 
-static int __devinit nand_boot_set_geometry(struct gpmi_nand_data *this)
+static int nand_boot_set_geometry(struct gpmi_nand_data *this)
 {
 	struct boot_rom_geometry *geometry = &this->rom_geometry;
 
@@ -1182,7 +1182,7 @@
 }
 
 static const char  *fingerprint = "STMP";
-static int __devinit mx23_check_transcription_stamp(struct gpmi_nand_data *this)
+static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
 {
 	struct boot_rom_geometry *rom_geo = &this->rom_geometry;
 	struct device *dev = this->dev;
@@ -1239,7 +1239,7 @@
 }
 
 /* Writes a transcription stamp. */
-static int __devinit mx23_write_transcription_stamp(struct gpmi_nand_data *this)
+static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
 {
 	struct device *dev = this->dev;
 	struct boot_rom_geometry *rom_geo = &this->rom_geometry;
@@ -1322,7 +1322,7 @@
 	return 0;
 }
 
-static int __devinit mx23_boot_init(struct gpmi_nand_data  *this)
+static int mx23_boot_init(struct gpmi_nand_data  *this)
 {
 	struct device *dev = this->dev;
 	struct nand_chip *chip = &this->nand;
@@ -1391,7 +1391,7 @@
 	return 0;
 }
 
-static int __devinit nand_boot_init(struct gpmi_nand_data  *this)
+static int nand_boot_init(struct gpmi_nand_data  *this)
 {
 	nand_boot_set_geometry(this);
 
@@ -1401,7 +1401,7 @@
 	return 0;
 }
 
-static int __devinit gpmi_set_geometry(struct gpmi_nand_data *this)
+static int gpmi_set_geometry(struct gpmi_nand_data *this)
 {
 	int ret;
 
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
index e023bcc..ec6180d 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
@@ -20,7 +20,7 @@
 #include <linux/mtd/nand.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
-#include <mach/dma.h>
+#include <linux/fsl/mxs-dma.h>
 
 struct resources {
 	void          *gpmi_regs;
diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c
index 5dc6f0d..11e4878 100644
--- a/drivers/mtd/nand/h1910.c
+++ b/drivers/mtd/nand/h1910.c
@@ -135,8 +135,8 @@
 	}
 
 	/* Register the partitions */
-	mtd_device_parse_register(h1910_nand_mtd, NULL, 0,
-			partition_info, NUM_PARTITIONS);
+	mtd_device_parse_register(h1910_nand_mtd, NULL, NULL, partition_info,
+				  NUM_PARTITIONS);
 
 	/* Return happy */
 	return 0;
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index ac3b9f2..e4147e8 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -332,6 +332,11 @@
 	chip->ecc.mode		= NAND_ECC_HW_OOB_FIRST;
 	chip->ecc.size		= 512;
 	chip->ecc.bytes		= 9;
+	chip->ecc.strength	= 2;
+	/*
+	 * FIXME: ecc_strength value of 2 bits per 512 bytes of data is a
+	 * conservative guess, given 9 ecc bytes and reed-solomon alg.
+	 */
 
 	if (pdata)
 		chip->ecc.layout = pdata->ecc_layout;
@@ -367,9 +372,9 @@
 		goto err_gpio_free;
 	}
 
-	ret = mtd_device_parse_register(mtd, NULL, 0,
-			pdata ? pdata->partitions : NULL,
-			pdata ? pdata->num_partitions : 0);
+	ret = mtd_device_parse_register(mtd, NULL, NULL,
+					pdata ? pdata->partitions : NULL,
+					pdata ? pdata->num_partitions : 0);
 
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to add mtd device\n");
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 74a43b8..cc0678a 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -1225,9 +1225,16 @@
 		goto escan;
 	}
 
+	if (this->ecc.mode == NAND_ECC_HW) {
+		if (nfc_is_v1())
+			this->ecc.strength = 1;
+		else
+			this->ecc.strength = (host->eccsize == 4) ? 4 : 8;
+	}
+
 	/* Register the partitions */
-	mtd_device_parse_register(mtd, part_probes, 0,
-			pdata->parts, pdata->nr_parts);
+	mtd_device_parse_register(mtd, part_probes, NULL, pdata->parts,
+				  pdata->nr_parts);
 
 	platform_set_drvdata(pdev, host);
 
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 8a393f9..47b19c0 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -123,12 +123,6 @@
 		ret = -EINVAL;
 	}
 
-	/* Do not allow past end of device */
-	if (ofs + len > mtd->size) {
-		pr_debug("%s: past end of device\n", __func__);
-		ret = -EINVAL;
-	}
-
 	return ret;
 }
 
@@ -338,7 +332,7 @@
  */
 static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 {
-	int page, chipnr, res = 0;
+	int page, chipnr, res = 0, i = 0;
 	struct nand_chip *chip = mtd->priv;
 	u16 bad;
 
@@ -356,23 +350,29 @@
 		chip->select_chip(mtd, chipnr);
 	}
 
-	if (chip->options & NAND_BUSWIDTH_16) {
-		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,
-			      page);
-		bad = cpu_to_le16(chip->read_word(mtd));
-		if (chip->badblockpos & 0x1)
-			bad >>= 8;
-		else
-			bad &= 0xFF;
-	} else {
-		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
-		bad = chip->read_byte(mtd);
-	}
+	do {
+		if (chip->options & NAND_BUSWIDTH_16) {
+			chip->cmdfunc(mtd, NAND_CMD_READOOB,
+					chip->badblockpos & 0xFE, page);
+			bad = cpu_to_le16(chip->read_word(mtd));
+			if (chip->badblockpos & 0x1)
+				bad >>= 8;
+			else
+				bad &= 0xFF;
+		} else {
+			chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
+					page);
+			bad = chip->read_byte(mtd);
+		}
 
-	if (likely(chip->badblockbits == 8))
-		res = bad != 0xFF;
-	else
-		res = hweight8(bad) < chip->badblockbits;
+		if (likely(chip->badblockbits == 8))
+			res = bad != 0xFF;
+		else
+			res = hweight8(bad) < chip->badblockbits;
+		ofs += mtd->writesize;
+		page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+		i++;
+	} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
 
 	if (getchip)
 		nand_release_device(mtd);
@@ -386,51 +386,79 @@
  * @ofs: offset from device start
  *
  * This is the default implementation, which can be overridden by a hardware
- * specific driver.
+ * specific driver. We try operations in the following order, according to our
+ * bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH):
+ *  (1) erase the affected block, to allow OOB marker to be written cleanly
+ *  (2) update in-memory BBT
+ *  (3) write bad block marker to OOB area of affected block
+ *  (4) update flash-based BBT
+ * Note that we retain the first error encountered in (3) or (4), finish the
+ * procedures, and dump the error in the end.
 */
 static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
 	struct nand_chip *chip = mtd->priv;
 	uint8_t buf[2] = { 0, 0 };
-	int block, ret, i = 0;
+	int block, res, ret = 0, i = 0;
+	int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM);
 
-	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
-		ofs += mtd->erasesize - mtd->writesize;
+	if (write_oob) {
+		struct erase_info einfo;
+
+		/* Attempt erase before marking OOB */
+		memset(&einfo, 0, sizeof(einfo));
+		einfo.mtd = mtd;
+		einfo.addr = ofs;
+		einfo.len = 1 << chip->phys_erase_shift;
+		nand_erase_nand(mtd, &einfo, 0);
+	}
 
 	/* Get block number */
 	block = (int)(ofs >> chip->bbt_erase_shift);
+	/* Mark block bad in memory-based BBT */
 	if (chip->bbt)
 		chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
 
-	/* Do we have a flash based bad block table? */
-	if (chip->bbt_options & NAND_BBT_USE_FLASH)
-		ret = nand_update_bbt(mtd, ofs);
-	else {
+	/* Write bad block marker to OOB */
+	if (write_oob) {
 		struct mtd_oob_ops ops;
+		loff_t wr_ofs = ofs;
 
 		nand_get_device(chip, mtd, FL_WRITING);
 
-		/*
-		 * Write to first two pages if necessary. If we write to more
-		 * than one location, the first error encountered quits the
-		 * procedure. We write two bytes per location, so we dont have
-		 * to mess with 16 bit access.
-		 */
-		ops.len = ops.ooblen = 2;
 		ops.datbuf = NULL;
 		ops.oobbuf = buf;
-		ops.ooboffs = chip->badblockpos & ~0x01;
+		ops.ooboffs = chip->badblockpos;
+		if (chip->options & NAND_BUSWIDTH_16) {
+			ops.ooboffs &= ~0x01;
+			ops.len = ops.ooblen = 2;
+		} else {
+			ops.len = ops.ooblen = 1;
+		}
 		ops.mode = MTD_OPS_PLACE_OOB;
+
+		/* Write to first/last page(s) if necessary */
+		if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+			wr_ofs += mtd->erasesize - mtd->writesize;
 		do {
-			ret = nand_do_write_oob(mtd, ofs, &ops);
+			res = nand_do_write_oob(mtd, wr_ofs, &ops);
+			if (!ret)
+				ret = res;
 
 			i++;
-			ofs += mtd->writesize;
-		} while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) &&
-				i < 2);
+			wr_ofs += mtd->writesize;
+		} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
 
 		nand_release_device(mtd);
 	}
+
+	/* Update flash-based bad block table */
+	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+		res = nand_update_bbt(mtd, ofs);
+		if (!ret)
+			ret = res;
+	}
+
 	if (!ret)
 		mtd->ecc_stats.badblocks++;
 
@@ -1586,25 +1614,14 @@
 	struct mtd_oob_ops ops;
 	int ret;
 
-	/* Do not allow reads past end of device */
-	if ((from + len) > mtd->size)
-		return -EINVAL;
-	if (!len)
-		return 0;
-
 	nand_get_device(chip, mtd, FL_READING);
-
 	ops.len = len;
 	ops.datbuf = buf;
 	ops.oobbuf = NULL;
 	ops.mode = 0;
-
 	ret = nand_do_read_ops(mtd, from, &ops);
-
 	*retlen = ops.retlen;
-
 	nand_release_device(mtd);
-
 	return ret;
 }
 
@@ -2293,12 +2310,6 @@
 	struct mtd_oob_ops ops;
 	int ret;
 
-	/* Do not allow reads past end of device */
-	if ((to + len) > mtd->size)
-		return -EINVAL;
-	if (!len)
-		return 0;
-
 	/* Wait for the device to get ready */
 	panic_nand_wait(mtd, chip, 400);
 
@@ -2333,25 +2344,14 @@
 	struct mtd_oob_ops ops;
 	int ret;
 
-	/* Do not allow reads past end of device */
-	if ((to + len) > mtd->size)
-		return -EINVAL;
-	if (!len)
-		return 0;
-
 	nand_get_device(chip, mtd, FL_WRITING);
-
 	ops.len = len;
 	ops.datbuf = (uint8_t *)buf;
 	ops.oobbuf = NULL;
 	ops.mode = 0;
-
 	ret = nand_do_write_ops(mtd, to, &ops);
-
 	*retlen = ops.retlen;
-
 	nand_release_device(mtd);
-
 	return ret;
 }
 
@@ -2550,8 +2550,6 @@
 	if (check_offs_len(mtd, instr->addr, instr->len))
 		return -EINVAL;
 
-	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
-
 	/* Grab the lock and see if the device is available */
 	nand_get_device(chip, mtd, FL_ERASING);
 
@@ -2715,10 +2713,6 @@
  */
 static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
 {
-	/* Check for invalid offset */
-	if (offs > mtd->size)
-		return -EINVAL;
-
 	return nand_block_checkbad(mtd, offs, 1, 0);
 }
 
@@ -2857,7 +2851,6 @@
 		chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
 		return 0;
 
-	pr_info("ONFI flash detected\n");
 	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
 	for (i = 0; i < 3; i++) {
 		chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
@@ -2898,7 +2891,8 @@
 	mtd->writesize = le32_to_cpu(p->byte_per_page);
 	mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
 	mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
-	chip->chipsize = (uint64_t)le32_to_cpu(p->blocks_per_lun) * mtd->erasesize;
+	chip->chipsize = le32_to_cpu(p->blocks_per_lun);
+	chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
 	*busw = 0;
 	if (le16_to_cpu(p->features) & 1)
 		*busw = NAND_BUSWIDTH_16;
@@ -2907,6 +2901,7 @@
 	chip->options |= (NAND_NO_READRDY |
 			NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK;
 
+	pr_info("ONFI flash detected\n");
 	return 1;
 }
 
@@ -3238,6 +3233,10 @@
 	int i;
 	struct nand_chip *chip = mtd->priv;
 
+	/* New bad blocks should be marked in OOB, flash-based BBT, or both */
+	BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
+			!(chip->bbt_options & NAND_BBT_USE_FLASH));
+
 	if (!(chip->options & NAND_OWN_BUFFERS))
 		chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
 	if (!chip->buffers)
@@ -3350,6 +3349,7 @@
 		if (!chip->ecc.size)
 			chip->ecc.size = 256;
 		chip->ecc.bytes = 3;
+		chip->ecc.strength = 1;
 		break;
 
 	case NAND_ECC_SOFT_BCH:
@@ -3384,6 +3384,8 @@
 			pr_warn("BCH ECC initialization failed!\n");
 			BUG();
 		}
+		chip->ecc.strength =
+			chip->ecc.bytes*8 / fls(8*chip->ecc.size);
 		break;
 
 	case NAND_ECC_NONE:
@@ -3397,6 +3399,7 @@
 		chip->ecc.write_oob = nand_write_oob_std;
 		chip->ecc.size = mtd->writesize;
 		chip->ecc.bytes = 0;
+		chip->ecc.strength = 0;
 		break;
 
 	default:
@@ -3461,25 +3464,26 @@
 	mtd->type = MTD_NANDFLASH;
 	mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
 						MTD_CAP_NANDFLASH;
-	mtd->erase = nand_erase;
-	mtd->point = NULL;
-	mtd->unpoint = NULL;
-	mtd->read = nand_read;
-	mtd->write = nand_write;
-	mtd->panic_write = panic_nand_write;
-	mtd->read_oob = nand_read_oob;
-	mtd->write_oob = nand_write_oob;
-	mtd->sync = nand_sync;
-	mtd->lock = NULL;
-	mtd->unlock = NULL;
-	mtd->suspend = nand_suspend;
-	mtd->resume = nand_resume;
-	mtd->block_isbad = nand_block_isbad;
-	mtd->block_markbad = nand_block_markbad;
+	mtd->_erase = nand_erase;
+	mtd->_point = NULL;
+	mtd->_unpoint = NULL;
+	mtd->_read = nand_read;
+	mtd->_write = nand_write;
+	mtd->_panic_write = panic_nand_write;
+	mtd->_read_oob = nand_read_oob;
+	mtd->_write_oob = nand_write_oob;
+	mtd->_sync = nand_sync;
+	mtd->_lock = NULL;
+	mtd->_unlock = NULL;
+	mtd->_suspend = nand_suspend;
+	mtd->_resume = nand_resume;
+	mtd->_block_isbad = nand_block_isbad;
+	mtd->_block_markbad = nand_block_markbad;
 	mtd->writebufsize = mtd->writesize;
 
-	/* propagate ecc.layout to mtd_info */
+	/* propagate ecc info to mtd_info */
 	mtd->ecclayout = chip->ecc.layout;
+	mtd->ecc_strength = chip->ecc.strength * chip->ecc.steps;
 
 	/* Check, if we should skip the bad block table scan */
 	if (chip->options & NAND_SKIP_BBTSCAN)
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index ec68854..2b6f632 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -179,6 +179,7 @@
 	chip->ecc.mode = NAND_ECC_HW;
 	chip->ecc.size = 256;
 	chip->ecc.bytes = 3;
+	chip->ecc.strength = 1;
 	chip->priv = ndfc;
 
 	ndfc->mtd.priv = chip;
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index b3a883e..c2b0bba 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -1058,6 +1058,7 @@
 		(pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)) {
 		info->nand.ecc.bytes            = 3;
 		info->nand.ecc.size             = 512;
+		info->nand.ecc.strength         = 1;
 		info->nand.ecc.calculate        = omap_calculate_ecc;
 		info->nand.ecc.hwctl            = omap_enable_hwecc;
 		info->nand.ecc.correct          = omap_correct_data;
@@ -1101,8 +1102,8 @@
 		goto out_release_mem_region;
 	}
 
-	mtd_device_parse_register(&info->mtd, NULL, 0,
-			pdata->parts, pdata->nr_parts);
+	mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts,
+				  pdata->nr_parts);
 
 	platform_set_drvdata(pdev, &info->mtd);
 
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index 29f505a..1d3bfb2 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -129,8 +129,8 @@
 	}
 
 	mtd->name = "orion_nand";
-	ret = mtd_device_parse_register(mtd, NULL, 0,
-			board->parts, board->nr_parts);
+	ret = mtd_device_parse_register(mtd, NULL, NULL, board->parts,
+					board->nr_parts);
 	if (ret) {
 		nand_release(mtd);
 		goto no_dev;
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
index 7f2da69..6404e6e 100644
--- a/drivers/mtd/nand/plat_nand.c
+++ b/drivers/mtd/nand/plat_nand.c
@@ -99,8 +99,9 @@
 	}
 
 	err = mtd_device_parse_register(&data->mtd,
-			pdata->chip.part_probe_types, 0,
-			pdata->chip.partitions, pdata->chip.nr_partitions);
+					pdata->chip.part_probe_types, NULL,
+					pdata->chip.partitions,
+					pdata->chip.nr_partitions);
 
 	if (!err)
 		return err;
diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c
index 7e52af5..0ddd90e 100644
--- a/drivers/mtd/nand/ppchameleonevb.c
+++ b/drivers/mtd/nand/ppchameleonevb.c
@@ -275,11 +275,10 @@
 	ppchameleon_mtd->name = "ppchameleon-nand";
 
 	/* Register the partitions */
-	mtd_device_parse_register(ppchameleon_mtd, NULL, 0,
-			ppchameleon_mtd->size == NAND_SMALL_SIZE ?
-				partition_info_me :
-				partition_info_hi,
-			NUM_PARTITIONS);
+	mtd_device_parse_register(ppchameleon_mtd, NULL, NULL,
+				  ppchameleon_mtd->size == NAND_SMALL_SIZE ?
+					partition_info_me : partition_info_hi,
+				  NUM_PARTITIONS);
 
  nand_evb_init:
 	/****************************
@@ -365,11 +364,10 @@
 	ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME;
 
 	/* Register the partitions */
-	mtd_device_parse_register(ppchameleonevb_mtd, NULL, 0,
-			ppchameleon_mtd->size == NAND_SMALL_SIZE ?
-				partition_info_me :
-				partition_info_hi,
-			NUM_PARTITIONS);
+	mtd_device_parse_register(ppchameleonevb_mtd, NULL, NULL,
+				  ppchameleon_mtd->size == NAND_SMALL_SIZE ?
+				  partition_info_me : partition_info_hi,
+				  NUM_PARTITIONS);
 
 	/* Return happy */
 	return 0;
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 5c3d719..def50ca 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -1002,6 +1002,7 @@
 KEEP_CONFIG:
 	chip->ecc.mode = NAND_ECC_HW;
 	chip->ecc.size = host->page_size;
+	chip->ecc.strength = 1;
 
 	chip->options = NAND_NO_AUTOINCR;
 	chip->options |= NAND_NO_READRDY;
@@ -1228,8 +1229,9 @@
 			continue;
 		}
 
-		ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, 0,
-				pdata->parts[cs], pdata->nr_parts[cs]);
+		ret = mtd_device_parse_register(info->host[cs]->mtd, NULL,
+						NULL, pdata->parts[cs],
+						pdata->nr_parts[cs]);
 		if (!ret)
 			probe_success = 1;
 	}
diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c
index 769a4e0..c204018 100644
--- a/drivers/mtd/nand/r852.c
+++ b/drivers/mtd/nand/r852.c
@@ -891,6 +891,7 @@
 	chip->ecc.mode = NAND_ECC_HW_SYNDROME;
 	chip->ecc.size = R852_DMA_LEN;
 	chip->ecc.bytes = SM_OOB_SIZE;
+	chip->ecc.strength = 2;
 	chip->ecc.hwctl = r852_ecc_hwctl;
 	chip->ecc.calculate = r852_ecc_calculate;
 	chip->ecc.correct = r852_ecc_correct;
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c
index f309add..e55b5cf 100644
--- a/drivers/mtd/nand/rtc_from4.c
+++ b/drivers/mtd/nand/rtc_from4.c
@@ -527,6 +527,7 @@
 	this->ecc.mode = NAND_ECC_HW_SYNDROME;
 	this->ecc.size = 512;
 	this->ecc.bytes = 8;
+	this->ecc.strength = 3;
 	/* return the status of extra status and ECC checks */
 	this->errstat = rtc_from4_errstat;
 	/* set the nand_oobinfo to support FPGA H/W error detection */
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 868685d..91121f3 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -751,8 +751,8 @@
 	if (set)
 		mtd->mtd.name = set->name;
 
-	return mtd_device_parse_register(&mtd->mtd, NULL, 0,
-			set->partitions, set->nr_partitions);
+	return mtd_device_parse_register(&mtd->mtd, NULL, NULL,
+					 set->partitions, set->nr_partitions);
 }
 
 /**
@@ -823,6 +823,7 @@
 		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
 		chip->ecc.correct   = s3c2410_nand_correct_data;
 		chip->ecc.mode	    = NAND_ECC_HW;
+		chip->ecc.strength  = 1;
 
 		switch (info->cpu_type) {
 		case TYPE_S3C2410:
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
index 93b1f74..e9b2b26 100644
--- a/drivers/mtd/nand/sh_flctl.c
+++ b/drivers/mtd/nand/sh_flctl.c
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 
 #include <linux/mtd/mtd.h>
@@ -283,7 +284,7 @@
 static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
 {
 	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-	uint32_t flcmncr_val = readl(FLCMNCR(flctl)) & ~SEL_16BIT;
+	uint32_t flcmncr_val = flctl->flcmncr_base & ~SEL_16BIT;
 	uint32_t flcmdcr_val, addr_len_bytes = 0;
 
 	/* Set SNAND bit if page size is 2048byte */
@@ -303,6 +304,7 @@
 		break;
 	case NAND_CMD_READ0:
 	case NAND_CMD_READOOB:
+	case NAND_CMD_RNDOUT:
 		addr_len_bytes = flctl->rw_ADRCNT;
 		flcmdcr_val |= CDSRC_E;
 		if (flctl->chip.options & NAND_BUSWIDTH_16)
@@ -320,6 +322,7 @@
 		break;
 	case NAND_CMD_READID:
 		flcmncr_val &= ~SNAND_E;
+		flcmdcr_val |= CDSRC_E;
 		addr_len_bytes = ADRCNT_1;
 		break;
 	case NAND_CMD_STATUS:
@@ -513,6 +516,8 @@
 	struct sh_flctl *flctl = mtd_to_flctl(mtd);
 	uint32_t read_cmd = 0;
 
+	pm_runtime_get_sync(&flctl->pdev->dev);
+
 	flctl->read_bytes = 0;
 	if (command != NAND_CMD_PAGEPROG)
 		flctl->index = 0;
@@ -525,7 +530,6 @@
 			execmd_read_page_sector(mtd, page_addr);
 			break;
 		}
-		empty_fifo(flctl);
 		if (flctl->page_size)
 			set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
 				| command);
@@ -547,7 +551,6 @@
 			break;
 		}
 
-		empty_fifo(flctl);
 		if (flctl->page_size) {
 			set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
 				| NAND_CMD_READ0);
@@ -559,15 +562,35 @@
 		flctl->read_bytes = mtd->oobsize;
 		goto read_normal_exit;
 
-	case NAND_CMD_READID:
-		empty_fifo(flctl);
-		set_cmd_regs(mtd, command, command);
-		set_addr(mtd, 0, 0);
+	case NAND_CMD_RNDOUT:
+		if (flctl->hwecc)
+			break;
 
-		flctl->read_bytes = 4;
+		if (flctl->page_size)
+			set_cmd_regs(mtd, command, (NAND_CMD_RNDOUTSTART << 8)
+				| command);
+		else
+			set_cmd_regs(mtd, command, command);
+
+		set_addr(mtd, column, 0);
+
+		flctl->read_bytes = mtd->writesize + mtd->oobsize - column;
+		goto read_normal_exit;
+
+	case NAND_CMD_READID:
+		set_cmd_regs(mtd, command, command);
+
+		/* READID is always performed using an 8-bit bus */
+		if (flctl->chip.options & NAND_BUSWIDTH_16)
+			column <<= 1;
+		set_addr(mtd, column, 0);
+
+		flctl->read_bytes = 8;
 		writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
+		empty_fifo(flctl);
 		start_translation(flctl);
-		read_datareg(flctl, 0);	/* read and end */
+		read_fiforeg(flctl, flctl->read_bytes, 0);
+		wait_completion(flctl);
 		break;
 
 	case NAND_CMD_ERASE1:
@@ -650,29 +673,55 @@
 	default:
 		break;
 	}
-	return;
+	goto runtime_exit;
 
 read_normal_exit:
 	writel(flctl->read_bytes, FLDTCNTR(flctl));	/* set read size */
+	empty_fifo(flctl);
 	start_translation(flctl);
 	read_fiforeg(flctl, flctl->read_bytes, 0);
 	wait_completion(flctl);
+runtime_exit:
+	pm_runtime_put_sync(&flctl->pdev->dev);
 	return;
 }
 
 static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
 {
 	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-	uint32_t flcmncr_val = readl(FLCMNCR(flctl));
+	int ret;
 
 	switch (chipnr) {
 	case -1:
-		flcmncr_val &= ~CE0_ENABLE;
-		writel(flcmncr_val, FLCMNCR(flctl));
+		flctl->flcmncr_base &= ~CE0_ENABLE;
+
+		pm_runtime_get_sync(&flctl->pdev->dev);
+		writel(flctl->flcmncr_base, FLCMNCR(flctl));
+
+		if (flctl->qos_request) {
+			dev_pm_qos_remove_request(&flctl->pm_qos);
+			flctl->qos_request = 0;
+		}
+
+		pm_runtime_put_sync(&flctl->pdev->dev);
 		break;
 	case 0:
-		flcmncr_val |= CE0_ENABLE;
-		writel(flcmncr_val, FLCMNCR(flctl));
+		flctl->flcmncr_base |= CE0_ENABLE;
+
+		if (!flctl->qos_request) {
+			ret = dev_pm_qos_add_request(&flctl->pdev->dev,
+							&flctl->pm_qos, 100);
+			if (ret < 0)
+				dev_err(&flctl->pdev->dev,
+					"PM QoS request failed: %d\n", ret);
+			flctl->qos_request = 1;
+		}
+
+		if (flctl->holden) {
+			pm_runtime_get_sync(&flctl->pdev->dev);
+			writel(HOLDEN, FLHOLDCR(flctl));
+			pm_runtime_put_sync(&flctl->pdev->dev);
+		}
 		break;
 	default:
 		BUG();
@@ -730,11 +779,6 @@
 	return 0;
 }
 
-static void flctl_register_init(struct sh_flctl *flctl, unsigned long val)
-{
-	writel(val, FLCMNCR(flctl));
-}
-
 static int flctl_chip_init_tail(struct mtd_info *mtd)
 {
 	struct sh_flctl *flctl = mtd_to_flctl(mtd);
@@ -781,13 +825,13 @@
 
 		chip->ecc.size = 512;
 		chip->ecc.bytes = 10;
+		chip->ecc.strength = 4;
 		chip->ecc.read_page = flctl_read_page_hwecc;
 		chip->ecc.write_page = flctl_write_page_hwecc;
 		chip->ecc.mode = NAND_ECC_HW;
 
 		/* 4 symbols ECC enabled */
-		writel(readl(FLCMNCR(flctl)) | _4ECCEN | ECCPOS2 | ECCPOS_02,
-				FLCMNCR(flctl));
+		flctl->flcmncr_base |= _4ECCEN | ECCPOS2 | ECCPOS_02;
 	} else {
 		chip->ecc.mode = NAND_ECC_SOFT;
 	}
@@ -819,13 +863,13 @@
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "failed to get I/O memory\n");
-		goto err;
+		goto err_iomap;
 	}
 
 	flctl->reg = ioremap(res->start, resource_size(res));
 	if (flctl->reg == NULL) {
 		dev_err(&pdev->dev, "failed to remap I/O memory\n");
-		goto err;
+		goto err_iomap;
 	}
 
 	platform_set_drvdata(pdev, flctl);
@@ -833,9 +877,9 @@
 	nand = &flctl->chip;
 	flctl_mtd->priv = nand;
 	flctl->pdev = pdev;
+	flctl->flcmncr_base = pdata->flcmncr_val;
 	flctl->hwecc = pdata->has_hwecc;
-
-	flctl_register_init(flctl, pdata->flcmncr_val);
+	flctl->holden = pdata->use_holden;
 
 	nand->options = NAND_NO_AUTOINCR;
 
@@ -855,23 +899,28 @@
 		nand->read_word = flctl_read_word;
 	}
 
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_resume(&pdev->dev);
+
 	ret = nand_scan_ident(flctl_mtd, 1, NULL);
 	if (ret)
-		goto err;
+		goto err_chip;
 
 	ret = flctl_chip_init_tail(flctl_mtd);
 	if (ret)
-		goto err;
+		goto err_chip;
 
 	ret = nand_scan_tail(flctl_mtd);
 	if (ret)
-		goto err;
+		goto err_chip;
 
 	mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
 
 	return 0;
 
-err:
+err_chip:
+	pm_runtime_disable(&pdev->dev);
+err_iomap:
 	kfree(flctl);
 	return ret;
 }
@@ -881,6 +930,7 @@
 	struct sh_flctl *flctl = platform_get_drvdata(pdev);
 
 	nand_release(&flctl->mtd);
+	pm_runtime_disable(&pdev->dev);
 	kfree(flctl);
 
 	return 0;
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
index b175c0f..3421e37 100644
--- a/drivers/mtd/nand/sharpsl.c
+++ b/drivers/mtd/nand/sharpsl.c
@@ -167,6 +167,7 @@
 	this->ecc.mode = NAND_ECC_HW;
 	this->ecc.size = 256;
 	this->ecc.bytes = 3;
+	this->ecc.strength = 1;
 	this->badblock_pattern = data->badblock_pattern;
 	this->ecc.layout = data->ecc_layout;
 	this->ecc.hwctl = sharpsl_nand_enable_hwecc;
@@ -181,8 +182,8 @@
 	/* Register the partitions */
 	sharpsl->mtd.name = "sharpsl-nand";
 
-	err = mtd_device_parse_register(&sharpsl->mtd, NULL, 0,
-			data->partitions, data->nr_partitions);
+	err = mtd_device_parse_register(&sharpsl->mtd, NULL, NULL,
+					data->partitions, data->nr_partitions);
 	if (err)
 		goto err_add;
 
diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c
index 6caa0cd..5aa5180 100644
--- a/drivers/mtd/nand/tmio_nand.c
+++ b/drivers/mtd/nand/tmio_nand.c
@@ -430,6 +430,7 @@
 	nand_chip->ecc.mode = NAND_ECC_HW;
 	nand_chip->ecc.size = 512;
 	nand_chip->ecc.bytes = 6;
+	nand_chip->ecc.strength = 2;
 	nand_chip->ecc.hwctl = tmio_nand_enable_hwecc;
 	nand_chip->ecc.calculate = tmio_nand_calculate_ecc;
 	nand_chip->ecc.correct = tmio_nand_correct_data;
@@ -456,9 +457,9 @@
 		goto err_scan;
 	}
 	/* Register the partitions */
-	retval = mtd_device_parse_register(mtd, NULL, 0,
-			data ? data->partition : NULL,
-			data ? data->num_partitions : 0);
+	retval = mtd_device_parse_register(mtd, NULL, NULL,
+					   data ? data->partition : NULL,
+					   data ? data->num_partitions : 0);
 	if (!retval)
 		return retval;
 
diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c
index c7c4f1d..26398dcf 100644
--- a/drivers/mtd/nand/txx9ndfmc.c
+++ b/drivers/mtd/nand/txx9ndfmc.c
@@ -356,6 +356,7 @@
 		/* txx9ndfmc_nand_scan will overwrite ecc.size and ecc.bytes */
 		chip->ecc.size = 256;
 		chip->ecc.bytes = 3;
+		chip->ecc.strength = 1;
 		chip->chip_delay = 100;
 		chip->controller = &drvdata->hw_control;
 
@@ -386,7 +387,7 @@
 		}
 		mtd->name = txx9_priv->mtdname;
 
-		mtd_device_parse_register(mtd, NULL, 0, NULL, 0);
+		mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
 		drvdata->mtds[i] = mtd;
 	}
 
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index a75382a..c5f4ebf 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -56,13 +56,6 @@
 	if (memcmp(mtd->name, "DiskOnChip", 10))
 		return;
 
-	if (!mtd_can_have_bb(mtd)) {
-		printk(KERN_ERR
-"NFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
-"Please use the new diskonchip driver under the NAND subsystem.\n");
-		return;
-	}
-
 	pr_debug("NFTL: add_mtd for %s\n", mtd->name);
 
 	nftl = kzalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index 772ad29..91467bb 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -1,6 +1,7 @@
 menuconfig MTD_ONENAND
 	tristate "OneNAND Device Support"
 	depends on MTD
+	depends on HAS_IOMEM
 	help
 	  This enables support for accessing all type of OneNAND flash
 	  devices. For further information see
diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c
index 0ccd5bf..1c4f97c 100644
--- a/drivers/mtd/onenand/generic.c
+++ b/drivers/mtd/onenand/generic.c
@@ -70,9 +70,9 @@
 		goto out_iounmap;
 	}
 
-	err = mtd_device_parse_register(&info->mtd, NULL, 0,
-			pdata ? pdata->parts : NULL,
-			pdata ? pdata->nr_parts : 0);
+	err = mtd_device_parse_register(&info->mtd, NULL, NULL,
+					pdata ? pdata->parts : NULL,
+					pdata ? pdata->nr_parts : 0);
 
 	platform_set_drvdata(pdev, info);
 
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index 7e9ea68..398a827 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -751,9 +751,9 @@
 	if ((r = onenand_scan(&c->mtd, 1)) < 0)
 		goto err_release_regulator;
 
-	r = mtd_device_parse_register(&c->mtd, NULL, 0,
-			pdata ? pdata->parts : NULL,
-			pdata ? pdata->nr_parts : 0);
+	r = mtd_device_parse_register(&c->mtd, NULL, NULL,
+				      pdata ? pdata->parts : NULL,
+				      pdata ? pdata->nr_parts : 0);
 	if (r)
 		goto err_release_onenand;
 
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index a061bc1..b3ce12e 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1753,16 +1753,6 @@
 	pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to,
 			(int)len);
 
-	/* Initialize retlen, in case of early exit */
-	*retlen = 0;
-
-	/* Do not allow writes past end of device */
-	if (unlikely((to + len) > mtd->size)) {
-		printk(KERN_ERR "%s: Attempt write to past end of device\n",
-			__func__);
-		return -EINVAL;
-	}
-
 	/* Reject writes, which are not page aligned */
         if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
 		printk(KERN_ERR "%s: Attempt to write not page aligned data\n",
@@ -1890,13 +1880,6 @@
 	ops->retlen = 0;
 	ops->oobretlen = 0;
 
-	/* Do not allow writes past end of device */
-	if (unlikely((to + len) > mtd->size)) {
-		printk(KERN_ERR "%s: Attempt write to past end of device\n",
-			__func__);
-		return -EINVAL;
-	}
-
 	/* Reject writes, which are not page aligned */
         if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
 		printk(KERN_ERR "%s: Attempt to write not page aligned data\n",
@@ -2493,12 +2476,6 @@
 			(unsigned long long)instr->addr,
 			(unsigned long long)instr->len);
 
-	/* Do not allow erase past end of device */
-	if (unlikely((len + addr) > mtd->size)) {
-		printk(KERN_ERR "%s: Erase past end of device\n", __func__);
-		return -EINVAL;
-	}
-
 	if (FLEXONENAND(this)) {
 		/* Find the eraseregion of this address */
 		int i = flexonenand_region(mtd, addr);
@@ -2525,8 +2502,6 @@
 		return -EINVAL;
 	}
 
-	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
-
 	/* Grab the lock and see if the device is available */
 	onenand_get_device(mtd, FL_ERASING);
 
@@ -4103,33 +4078,34 @@
 	mtd->oobavail = this->ecclayout->oobavail;
 
 	mtd->ecclayout = this->ecclayout;
+	mtd->ecc_strength = 1;
 
 	/* Fill in remaining MTD driver data */
 	mtd->type = ONENAND_IS_MLC(this) ? MTD_MLCNANDFLASH : MTD_NANDFLASH;
 	mtd->flags = MTD_CAP_NANDFLASH;
-	mtd->erase = onenand_erase;
-	mtd->point = NULL;
-	mtd->unpoint = NULL;
-	mtd->read = onenand_read;
-	mtd->write = onenand_write;
-	mtd->read_oob = onenand_read_oob;
-	mtd->write_oob = onenand_write_oob;
-	mtd->panic_write = onenand_panic_write;
+	mtd->_erase = onenand_erase;
+	mtd->_point = NULL;
+	mtd->_unpoint = NULL;
+	mtd->_read = onenand_read;
+	mtd->_write = onenand_write;
+	mtd->_read_oob = onenand_read_oob;
+	mtd->_write_oob = onenand_write_oob;
+	mtd->_panic_write = onenand_panic_write;
 #ifdef CONFIG_MTD_ONENAND_OTP
-	mtd->get_fact_prot_info = onenand_get_fact_prot_info;
-	mtd->read_fact_prot_reg = onenand_read_fact_prot_reg;
-	mtd->get_user_prot_info = onenand_get_user_prot_info;
-	mtd->read_user_prot_reg = onenand_read_user_prot_reg;
-	mtd->write_user_prot_reg = onenand_write_user_prot_reg;
-	mtd->lock_user_prot_reg = onenand_lock_user_prot_reg;
+	mtd->_get_fact_prot_info = onenand_get_fact_prot_info;
+	mtd->_read_fact_prot_reg = onenand_read_fact_prot_reg;
+	mtd->_get_user_prot_info = onenand_get_user_prot_info;
+	mtd->_read_user_prot_reg = onenand_read_user_prot_reg;
+	mtd->_write_user_prot_reg = onenand_write_user_prot_reg;
+	mtd->_lock_user_prot_reg = onenand_lock_user_prot_reg;
 #endif
-	mtd->sync = onenand_sync;
-	mtd->lock = onenand_lock;
-	mtd->unlock = onenand_unlock;
-	mtd->suspend = onenand_suspend;
-	mtd->resume = onenand_resume;
-	mtd->block_isbad = onenand_block_isbad;
-	mtd->block_markbad = onenand_block_markbad;
+	mtd->_sync = onenand_sync;
+	mtd->_lock = onenand_lock;
+	mtd->_unlock = onenand_unlock;
+	mtd->_suspend = onenand_suspend;
+	mtd->_resume = onenand_resume;
+	mtd->_block_isbad = onenand_block_isbad;
+	mtd->_block_markbad = onenand_block_markbad;
 	mtd->owner = THIS_MODULE;
 	mtd->writebufsize = mtd->writesize;
 
diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c
index fa1ee43..8e4b3f2 100644
--- a/drivers/mtd/onenand/samsung.c
+++ b/drivers/mtd/onenand/samsung.c
@@ -923,7 +923,7 @@
 		r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 		if (!r) {
 			dev_err(&pdev->dev, "no buffer memory resource defined\n");
-			return -ENOENT;
+			err = -ENOENT;
 			goto ahb_resource_failed;
 		}
 
@@ -964,7 +964,7 @@
 		r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 		if (!r) {
 			dev_err(&pdev->dev, "no dma memory resource defined\n");
-			return -ENOENT;
+			err = -ENOENT;
 			goto dma_resource_failed;
 		}
 
@@ -1014,7 +1014,7 @@
 	if (s3c_read_reg(MEM_CFG_OFFSET) & ONENAND_SYS_CFG1_SYNC_READ)
 		dev_info(&onenand->pdev->dev, "OneNAND Sync. Burst Read enabled\n");
 
-	err = mtd_device_parse_register(mtd, NULL, 0,
+	err = mtd_device_parse_register(mtd, NULL, NULL,
 					pdata ? pdata->parts : NULL,
 					pdata ? pdata->nr_parts : 0);
 
diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c
index 48970c1..580035c 100644
--- a/drivers/mtd/redboot.c
+++ b/drivers/mtd/redboot.c
@@ -78,8 +78,7 @@
 
 	if ( directory < 0 ) {
 		offset = master->size + directory * master->erasesize;
-		while (mtd_can_have_bb(master) &&
-		       mtd_block_isbad(master, offset)) {
+		while (mtd_block_isbad(master, offset)) {
 			if (!offset) {
 			nogood:
 				printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n");
@@ -89,8 +88,7 @@
 		}
 	} else {
 		offset = directory * master->erasesize;
-		while (mtd_can_have_bb(master) &&
-		       mtd_block_isbad(master, offset)) {
+		while (mtd_block_isbad(master, offset)) {
 			offset += master->erasesize;
 			if (offset == master->size)
 				goto nogood;
diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c
index 072ed59..9e2dfd5 100644
--- a/drivers/mtd/sm_ftl.c
+++ b/drivers/mtd/sm_ftl.c
@@ -1256,7 +1256,7 @@
 
 static struct mtd_blktrans_ops sm_ftl_ops = {
 	.name		= "smblk",
-	.major		= -1,
+	.major		= 0,
 	.part_bits	= SM_FTL_PARTN_BITS,
 	.blksize	= SM_SECTOR_SIZE,
 	.getgeo		= sm_getgeo,
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 115749f..0fde9fc 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -945,12 +945,8 @@
 		goto out_free;
 
 	err = -ENOMEM;
-	ubi->peb_buf1 = vmalloc(ubi->peb_size);
-	if (!ubi->peb_buf1)
-		goto out_free;
-
-	ubi->peb_buf2 = vmalloc(ubi->peb_size);
-	if (!ubi->peb_buf2)
+	ubi->peb_buf = vmalloc(ubi->peb_size);
+	if (!ubi->peb_buf)
 		goto out_free;
 
 	err = ubi_debugging_init_dev(ubi);
@@ -1029,8 +1025,7 @@
 out_debugging:
 	ubi_debugging_exit_dev(ubi);
 out_free:
-	vfree(ubi->peb_buf1);
-	vfree(ubi->peb_buf2);
+	vfree(ubi->peb_buf);
 	if (ref)
 		put_device(&ubi->dev);
 	else
@@ -1101,8 +1096,7 @@
 	vfree(ubi->vtbl);
 	put_mtd_device(ubi->mtd);
 	ubi_debugging_exit_dev(ubi);
-	vfree(ubi->peb_buf1);
-	vfree(ubi->peb_buf2);
+	vfree(ubi->peb_buf);
 	ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
 	put_device(&ubi->dev);
 	return 0;
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index e2cdebf..61af9bb 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -386,19 +386,11 @@
 	return count;
 }
 
-static int default_open(struct inode *inode, struct file *file)
-{
-	if (inode->i_private)
-		file->private_data = inode->i_private;
-
-	return 0;
-}
-
 /* File operations for all UBI debugfs files */
 static const struct file_operations dfs_fops = {
 	.read   = dfs_file_read,
 	.write  = dfs_file_write,
-	.open   = default_open,
+	.open	= simple_open,
 	.llseek = no_llseek,
 	.owner  = THIS_MODULE,
 };
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index cd26da8..2455d62 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -529,18 +529,18 @@
 
 	data_size = offset + len;
 	mutex_lock(&ubi->buf_mutex);
-	memset(ubi->peb_buf1 + offset, 0xFF, len);
+	memset(ubi->peb_buf + offset, 0xFF, len);
 
 	/* Read everything before the area where the write failure happened */
 	if (offset > 0) {
-		err = ubi_io_read_data(ubi, ubi->peb_buf1, pnum, 0, offset);
+		err = ubi_io_read_data(ubi, ubi->peb_buf, pnum, 0, offset);
 		if (err && err != UBI_IO_BITFLIPS)
 			goto out_unlock;
 	}
 
-	memcpy(ubi->peb_buf1 + offset, buf, len);
+	memcpy(ubi->peb_buf + offset, buf, len);
 
-	err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size);
+	err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size);
 	if (err) {
 		mutex_unlock(&ubi->buf_mutex);
 		goto write_error;
@@ -979,7 +979,7 @@
  * physical eraseblock @to. The @vid_hdr buffer may be changed by this
  * function. Returns:
  *   o %0 in case of success;
- *   o %MOVE_CANCEL_RACE, %MOVE_TARGET_WR_ERR, %MOVE_CANCEL_BITFLIPS, etc;
+ *   o %MOVE_CANCEL_RACE, %MOVE_TARGET_WR_ERR, %MOVE_TARGET_BITFLIPS, etc;
  *   o a negative error code in case of failure.
  */
 int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
@@ -1053,13 +1053,13 @@
 
 	/*
 	 * OK, now the LEB is locked and we can safely start moving it. Since
-	 * this function utilizes the @ubi->peb_buf1 buffer which is shared
+	 * this function utilizes the @ubi->peb_buf buffer which is shared
 	 * with some other functions - we lock the buffer by taking the
 	 * @ubi->buf_mutex.
 	 */
 	mutex_lock(&ubi->buf_mutex);
 	dbg_wl("read %d bytes of data", aldata_size);
-	err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size);
+	err = ubi_io_read_data(ubi, ubi->peb_buf, from, 0, aldata_size);
 	if (err && err != UBI_IO_BITFLIPS) {
 		ubi_warn("error %d while reading data from PEB %d",
 			 err, from);
@@ -1079,10 +1079,10 @@
 	 */
 	if (vid_hdr->vol_type == UBI_VID_DYNAMIC)
 		aldata_size = data_size =
-			ubi_calc_data_len(ubi, ubi->peb_buf1, data_size);
+			ubi_calc_data_len(ubi, ubi->peb_buf, data_size);
 
 	cond_resched();
-	crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size);
+	crc = crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size);
 	cond_resched();
 
 	/*
@@ -1116,12 +1116,12 @@
 			if (is_error_sane(err))
 				err = MOVE_TARGET_RD_ERR;
 		} else
-			err = MOVE_CANCEL_BITFLIPS;
+			err = MOVE_TARGET_BITFLIPS;
 		goto out_unlock_buf;
 	}
 
 	if (data_size > 0) {
-		err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size);
+		err = ubi_io_write_data(ubi, ubi->peb_buf, to, 0, aldata_size);
 		if (err) {
 			if (err == -EIO)
 				err = MOVE_TARGET_WR_ERR;
@@ -1134,8 +1134,8 @@
 		 * We've written the data and are going to read it back to make
 		 * sure it was written correctly.
 		 */
-
-		err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size);
+		memset(ubi->peb_buf, 0xFF, aldata_size);
+		err = ubi_io_read_data(ubi, ubi->peb_buf, to, 0, aldata_size);
 		if (err) {
 			if (err != UBI_IO_BITFLIPS) {
 				ubi_warn("error %d while reading data back "
@@ -1143,13 +1143,13 @@
 				if (is_error_sane(err))
 					err = MOVE_TARGET_RD_ERR;
 			} else
-				err = MOVE_CANCEL_BITFLIPS;
+				err = MOVE_TARGET_BITFLIPS;
 			goto out_unlock_buf;
 		}
 
 		cond_resched();
 
-		if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) {
+		if (crc != crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size)) {
 			ubi_warn("read data back from PEB %d and it is "
 				 "different", to);
 			err = -EINVAL;
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
index 941bc3c..90b9882 100644
--- a/drivers/mtd/ubi/gluebi.c
+++ b/drivers/mtd/ubi/gluebi.c
@@ -174,11 +174,7 @@
 	int err = 0, lnum, offs, total_read;
 	struct gluebi_device *gluebi;
 
-	if (len < 0 || from < 0 || from + len > mtd->size)
-		return -EINVAL;
-
 	gluebi = container_of(mtd, struct gluebi_device, mtd);
-
 	lnum = div_u64_rem(from, mtd->erasesize, &offs);
 	total_read = len;
 	while (total_read) {
@@ -218,14 +214,7 @@
 	int err = 0, lnum, offs, total_written;
 	struct gluebi_device *gluebi;
 
-	if (len < 0 || to < 0 || len + to > mtd->size)
-		return -EINVAL;
-
 	gluebi = container_of(mtd, struct gluebi_device, mtd);
-
-	if (!(mtd->flags & MTD_WRITEABLE))
-		return -EROFS;
-
 	lnum = div_u64_rem(to, mtd->erasesize, &offs);
 
 	if (len % mtd->writesize || offs % mtd->writesize)
@@ -265,21 +254,13 @@
 	int err, i, lnum, count;
 	struct gluebi_device *gluebi;
 
-	if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize)
-		return -EINVAL;
-	if (instr->len < 0 || instr->addr + instr->len > mtd->size)
-		return -EINVAL;
 	if (mtd_mod_by_ws(instr->addr, mtd) || mtd_mod_by_ws(instr->len, mtd))
 		return -EINVAL;
 
 	lnum = mtd_div_by_eb(instr->addr, mtd);
 	count = mtd_div_by_eb(instr->len, mtd);
-
 	gluebi = container_of(mtd, struct gluebi_device, mtd);
 
-	if (!(mtd->flags & MTD_WRITEABLE))
-		return -EROFS;
-
 	for (i = 0; i < count - 1; i++) {
 		err = ubi_leb_unmap(gluebi->desc, lnum + i);
 		if (err)
@@ -340,11 +321,11 @@
 	mtd->owner      = THIS_MODULE;
 	mtd->writesize  = di->min_io_size;
 	mtd->erasesize  = vi->usable_leb_size;
-	mtd->read       = gluebi_read;
-	mtd->write      = gluebi_write;
-	mtd->erase      = gluebi_erase;
-	mtd->get_device = gluebi_get_device;
-	mtd->put_device = gluebi_put_device;
+	mtd->_read       = gluebi_read;
+	mtd->_write      = gluebi_write;
+	mtd->_erase      = gluebi_erase;
+	mtd->_get_device = gluebi_get_device;
+	mtd->_put_device = gluebi_put_device;
 
 	/*
 	 * In case of dynamic a volume, MTD device size is just volume size. In
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 5cde4e5..43f1a00 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -431,11 +431,11 @@
 			goto out;
 
 		/* Make sure the PEB contains only 0xFF bytes */
-		err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
+		err = ubi_io_read(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
 		if (err)
 			goto out;
 
-		err = ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->peb_size);
+		err = ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->peb_size);
 		if (err == 0) {
 			ubi_err("erased PEB %d, but a non-0xFF byte found",
 				pnum);
@@ -444,17 +444,17 @@
 		}
 
 		/* Write a pattern and check it */
-		memset(ubi->peb_buf1, patterns[i], ubi->peb_size);
-		err = ubi_io_write(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
+		memset(ubi->peb_buf, patterns[i], ubi->peb_size);
+		err = ubi_io_write(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
 		if (err)
 			goto out;
 
-		memset(ubi->peb_buf1, ~patterns[i], ubi->peb_size);
-		err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
+		memset(ubi->peb_buf, ~patterns[i], ubi->peb_size);
+		err = ubi_io_read(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
 		if (err)
 			goto out;
 
-		err = ubi_check_pattern(ubi->peb_buf1, patterns[i],
+		err = ubi_check_pattern(ubi->peb_buf, patterns[i],
 					ubi->peb_size);
 		if (err == 0) {
 			ubi_err("pattern %x checking failed for PEB %d",
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index 0cb17d9..12c43b4 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -789,9 +789,9 @@
 	int err;
 
 	mutex_lock(&ubi->buf_mutex);
-	memset(ubi->peb_buf1, 0x00, ubi->leb_size);
+	memset(ubi->peb_buf, 0x00, ubi->leb_size);
 
-	err = ubi_io_read(ubi, ubi->peb_buf1, pnum, ubi->leb_start,
+	err = ubi_io_read(ubi, ubi->peb_buf, pnum, ubi->leb_start,
 			  ubi->leb_size);
 	if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) {
 		/*
@@ -808,7 +808,7 @@
 	if (err)
 		goto out_unlock;
 
-	if (ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->leb_size))
+	if (ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->leb_size))
 		goto out_unlock;
 
 	ubi_err("PEB %d contains corrupted VID header, and the data does not "
@@ -818,7 +818,7 @@
 	dbg_msg("hexdump of PEB %d offset %d, length %d",
 		pnum, ubi->leb_start, ubi->leb_size);
 	ubi_dbg_print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
-			       ubi->peb_buf1, ubi->leb_size, 1);
+			       ubi->peb_buf, ubi->leb_size, 1);
 	err = 1;
 
 out_unlock:
@@ -1174,7 +1174,7 @@
 
 	ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
 	if (!ech)
-		goto out_slab;
+		goto out_si;
 
 	vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
 	if (!vidh)
@@ -1235,8 +1235,6 @@
 	ubi_free_vid_hdr(ubi, vidh);
 out_ech:
 	kfree(ech);
-out_slab:
-	kmem_cache_destroy(si->scan_leb_slab);
 out_si:
 	ubi_scan_destroy_si(si);
 	return ERR_PTR(err);
@@ -1325,7 +1323,9 @@
 		}
 	}
 
-	kmem_cache_destroy(si->scan_leb_slab);
+	if (si->scan_leb_slab)
+		kmem_cache_destroy(si->scan_leb_slab);
+
 	kfree(si);
 }
 
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index d51d75d..b162790 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -118,7 +118,7 @@
  *                     PEB
  * MOVE_TARGET_WR_ERR: canceled because there was a write error to the target
  *                     PEB
- * MOVE_CANCEL_BITFLIPS: canceled because a bit-flip was detected in the
+ * MOVE_TARGET_BITFLIPS: canceled because a bit-flip was detected in the
  *                       target PEB
  * MOVE_RETRY: retry scrubbing the PEB
  */
@@ -127,7 +127,7 @@
 	MOVE_SOURCE_RD_ERR,
 	MOVE_TARGET_RD_ERR,
 	MOVE_TARGET_WR_ERR,
-	MOVE_CANCEL_BITFLIPS,
+	MOVE_TARGET_BITFLIPS,
 	MOVE_RETRY,
 };
 
@@ -387,9 +387,8 @@
  *                  time (MTD write buffer size)
  * @mtd: MTD device descriptor
  *
- * @peb_buf1: a buffer of PEB size used for different purposes
- * @peb_buf2: another buffer of PEB size used for different purposes
- * @buf_mutex: protects @peb_buf1 and @peb_buf2
+ * @peb_buf: a buffer of PEB size used for different purposes
+ * @buf_mutex: protects @peb_buf
  * @ckvol_mutex: serializes static volume checking when opening
  *
  * @dbg: debugging information for this UBI device
@@ -471,8 +470,7 @@
 	int max_write_size;
 	struct mtd_info *mtd;
 
-	void *peb_buf1;
-	void *peb_buf2;
+	void *peb_buf;
 	struct mutex buf_mutex;
 	struct mutex ckvol_mutex;
 
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 0696e36..7c1a9bf 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -350,18 +350,19 @@
 /**
  * find_wl_entry - find wear-leveling entry closest to certain erase counter.
  * @root: the RB-tree where to look for
- * @max: highest possible erase counter
+ * @diff: maximum possible difference from the smallest erase counter
  *
  * This function looks for a wear leveling entry with erase counter closest to
- * @max and less than @max.
+ * min + @diff, where min is the smallest erase counter.
  */
-static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int max)
+static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int diff)
 {
 	struct rb_node *p;
 	struct ubi_wl_entry *e;
+	int max;
 
 	e = rb_entry(rb_first(root), struct ubi_wl_entry, u.rb);
-	max += e->ec;
+	max = e->ec + diff;
 
 	p = root->rb_node;
 	while (p) {
@@ -389,7 +390,7 @@
  */
 int ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
 {
-	int err, medium_ec;
+	int err;
 	struct ubi_wl_entry *e, *first, *last;
 
 	ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM ||
@@ -427,7 +428,7 @@
 		 * For unknown data we pick a physical eraseblock with medium
 		 * erase counter. But we by no means can pick a physical
 		 * eraseblock with erase counter greater or equivalent than the
-		 * lowest erase counter plus %WL_FREE_MAX_DIFF.
+		 * lowest erase counter plus %WL_FREE_MAX_DIFF/2.
 		 */
 		first = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry,
 					u.rb);
@@ -436,10 +437,8 @@
 		if (last->ec - first->ec < WL_FREE_MAX_DIFF)
 			e = rb_entry(ubi->free.rb_node,
 					struct ubi_wl_entry, u.rb);
-		else {
-			medium_ec = (first->ec + WL_FREE_MAX_DIFF)/2;
-			e = find_wl_entry(&ubi->free, medium_ec);
-		}
+		else
+			e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF/2);
 		break;
 	case UBI_SHORTTERM:
 		/*
@@ -799,7 +798,7 @@
 			scrubbing = 1;
 			goto out_not_moved;
 		}
-		if (err == MOVE_CANCEL_BITFLIPS || err == MOVE_TARGET_WR_ERR ||
+		if (err == MOVE_TARGET_BITFLIPS || err == MOVE_TARGET_WR_ERR ||
 		    err == MOVE_TARGET_RD_ERR) {
 			/*
 			 * Target PEB had bit-flips or write error - torture it.
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 068c356..88bbd8f 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -190,8 +190,10 @@
 	{seeq8005_probe, 0},
 #endif
 #ifdef CONFIG_CS89x0
+#ifndef CONFIG_CS89x0_PLATFORM
  	{cs89x0_probe, 0},
 #endif
+#endif
 #ifdef CONFIG_AT1700
 	{at1700_probe, 0},
 #endif
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index 9abd4eb..dd5e048 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -70,7 +70,6 @@
 #include <linux/bitops.h>
 #include <linux/jiffies.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index 6057b30..0910dce 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -229,7 +229,6 @@
 #include <linux/bitops.h>
 #include <linux/gfp.h>
 
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/io.h>
 
diff --git a/drivers/net/arcnet/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c
index 980e65c..5bed4c4 100644
--- a/drivers/net/arcnet/com20020_cs.c
+++ b/drivers/net/arcnet/com20020_cs.c
@@ -47,7 +47,6 @@
 #include <pcmcia/ds.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #define VERSION "arcnet: COM20020 PCMCIA support loaded.\n"
 
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b920d82..62d2409 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -54,7 +54,6 @@
 #include <linux/inet.h>
 #include <linux/bitops.h>
 #include <linux/io.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <linux/uaccess.h>
 #include <linux/errno.h>
@@ -892,9 +891,15 @@
 
 	switch (bond->params.fail_over_mac) {
 	case BOND_FOM_ACTIVE:
-		if (new_active)
+		if (new_active) {
 			memcpy(bond->dev->dev_addr,  new_active->dev->dev_addr,
 			       new_active->dev->addr_len);
+			write_unlock_bh(&bond->curr_slave_lock);
+			read_unlock(&bond->lock);
+			call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);
+			read_lock(&bond->lock);
+			write_lock_bh(&bond->curr_slave_lock);
+		}
 		break;
 	case BOND_FOM_FOLLOW:
 		/*
@@ -2029,6 +2034,9 @@
 	write_unlock_bh(&bond->lock);
 	unblock_netpoll_tx();
 
+	if (bond->slave_cnt == 0)
+		call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);
+
 	bond_compute_features(bond);
 	if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) &&
 	    (old_features & NETIF_F_VLAN_CHALLENGED))
@@ -3002,7 +3010,11 @@
 					   trans_start + delta_in_ticks)) ||
 			    bond->curr_active_slave != slave) {
 				slave->link = BOND_LINK_UP;
-				bond->current_arp_slave = NULL;
+				if (bond->current_arp_slave) {
+					bond_set_slave_inactive_flags(
+						bond->current_arp_slave);
+					bond->current_arp_slave = NULL;
+				}
 
 				pr_info("%s: link status definitely up for interface %s.\n",
 					bond->dev->name, slave->dev->name);
@@ -3696,17 +3708,52 @@
 	read_unlock(&bond->lock);
 }
 
-static int bond_neigh_setup(struct net_device *dev, struct neigh_parms *parms)
+static int bond_neigh_init(struct neighbour *n)
 {
-	struct bonding *bond = netdev_priv(dev);
+	struct bonding *bond = netdev_priv(n->dev);
 	struct slave *slave = bond->first_slave;
+	const struct net_device_ops *slave_ops;
+	struct neigh_parms parms;
+	int ret;
 
-	if (slave) {
-		const struct net_device_ops *slave_ops
-			= slave->dev->netdev_ops;
-		if (slave_ops->ndo_neigh_setup)
-			return slave_ops->ndo_neigh_setup(slave->dev, parms);
-	}
+	if (!slave)
+		return 0;
+
+	slave_ops = slave->dev->netdev_ops;
+
+	if (!slave_ops->ndo_neigh_setup)
+		return 0;
+
+	parms.neigh_setup = NULL;
+	parms.neigh_cleanup = NULL;
+	ret = slave_ops->ndo_neigh_setup(slave->dev, &parms);
+	if (ret)
+		return ret;
+
+	/*
+	 * Assign slave's neigh_cleanup to neighbour in case cleanup is called
+	 * after the last slave has been detached.  Assumes that all slaves
+	 * utilize the same neigh_cleanup (true at this writing as only user
+	 * is ipoib).
+	 */
+	n->parms->neigh_cleanup = parms.neigh_cleanup;
+
+	if (!parms.neigh_setup)
+		return 0;
+
+	return parms.neigh_setup(n);
+}
+
+/*
+ * The bonding ndo_neigh_setup is called at init time beofre any
+ * slave exists. So we must declare proxy setup function which will
+ * be used at run time to resolve the actual slave neigh param setup.
+ */
+static int bond_neigh_setup(struct net_device *dev,
+			    struct neigh_parms *parms)
+{
+	parms->neigh_setup   = bond_neigh_init;
+
 	return 0;
 }
 
diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c
index 96391c3..b71ce9b 100644
--- a/drivers/net/caif/caif_spi.c
+++ b/drivers/net/caif/caif_spi.c
@@ -127,12 +127,6 @@
 	debugfs_remove(cfspi->dbgfs_dir);
 }
 
-static int dbgfs_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t dbgfs_state(struct file *file, char __user *user_buf,
 			   size_t count, loff_t *ppos)
 {
@@ -243,13 +237,13 @@
 }
 
 static const struct file_operations dbgfs_state_fops = {
-	.open = dbgfs_open,
+	.open = simple_open,
 	.read = dbgfs_state,
 	.owner = THIS_MODULE
 };
 
 static const struct file_operations dbgfs_frame_fops = {
-	.open = dbgfs_open,
+	.open = simple_open,
 	.read = dbgfs_frame,
 	.owner = THIS_MODULE
 };
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index 98a5a7d..034c16b 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -40,7 +40,6 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 
-#include <asm/system.h>
 #include <linux/uaccess.h>
 #include <linux/bitops.h>
 #include <linux/string.h>
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 7cb2785..ec03b40 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -35,7 +35,6 @@
 #include <asm/io.h>         /* CRIS_LED_* I/O functions */
 #include <asm/irq.h>
 #include <asm/dma.h>
-#include <asm/system.h>
 #include <asm/ethernet.h>
 #include <asm/cache.h>
 #include <arch/io_interface_mux.h>
diff --git a/drivers/net/eql.c b/drivers/net/eql.c
index a59cf96..f219d38 100644
--- a/drivers/net/eql.c
+++ b/drivers/net/eql.c
@@ -125,6 +125,7 @@
 #include <linux/if.h>
 #include <linux/if_arp.h>
 #include <linux/if_eql.h>
+#include <linux/pkt_sched.h>
 
 #include <asm/uaccess.h>
 
@@ -143,7 +144,7 @@
 	equalizer_t *eql = (equalizer_t *) param;
 	struct list_head *this, *tmp, *head;
 
-	spin_lock_bh(&eql->queue.lock);
+	spin_lock(&eql->queue.lock);
 	head = &eql->queue.all_slaves;
 	list_for_each_safe(this, tmp, head) {
 		slave_t *slave = list_entry(this, slave_t, list);
@@ -157,7 +158,7 @@
 		}
 
 	}
-	spin_unlock_bh(&eql->queue.lock);
+	spin_unlock(&eql->queue.lock);
 
 	eql->timer.expires = jiffies + EQL_DEFAULT_RESCHED_IVAL;
 	add_timer(&eql->timer);
@@ -341,7 +342,7 @@
 		struct net_device *slave_dev = slave->dev;
 
 		skb->dev = slave_dev;
-		skb->priority = 1;
+		skb->priority = TC_PRIO_FILLER;
 		slave->bytes_queued += skb->len;
 		dev_queue_xmit(skb);
 		dev->stats.tx_packets++;
diff --git a/drivers/net/ethernet/3com/3c574_cs.c b/drivers/net/ethernet/3com/3c574_cs.c
index e61b2f8..66df936 100644
--- a/drivers/net/ethernet/3com/3c574_cs.c
+++ b/drivers/net/ethernet/3com/3c574_cs.c
@@ -95,7 +95,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 /*====================================================================*/
 
diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c
index b23253b..a556c01 100644
--- a/drivers/net/ethernet/3com/3c589_cs.c
+++ b/drivers/net/ethernet/3com/3c589_cs.c
@@ -50,7 +50,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 /* To minimize the size of the driver source I only define operating
    constants if they are used several times.  You'll need the manual
diff --git a/drivers/net/ethernet/8390/3c503.c b/drivers/net/ethernet/8390/3c503.c
index fbab136..49d76bd 100644
--- a/drivers/net/ethernet/8390/3c503.c
+++ b/drivers/net/ethernet/8390/3c503.c
@@ -54,7 +54,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/byteorder.h>
 
 #include "8390.h"
diff --git a/drivers/net/ethernet/8390/ac3200.c b/drivers/net/ethernet/8390/ac3200.c
index 5337dd0..ccf0794 100644
--- a/drivers/net/ethernet/8390/ac3200.c
+++ b/drivers/net/ethernet/8390/ac3200.c
@@ -34,7 +34,6 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
diff --git a/drivers/net/ethernet/8390/apne.c b/drivers/net/ethernet/8390/apne.c
index 3ad5d2f..9239592 100644
--- a/drivers/net/ethernet/8390/apne.c
+++ b/drivers/net/ethernet/8390/apne.c
@@ -39,7 +39,6 @@
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/setup.h>
 #include <asm/amigaints.h>
diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c
index c30adcc9..11476ca 100644
--- a/drivers/net/ethernet/8390/ax88796.c
+++ b/drivers/net/ethernet/8390/ax88796.c
@@ -31,7 +31,6 @@
 
 #include <net/ax88796.h>
 
-#include <asm/system.h>
 
 /* Rename the lib8390.c functions to show that they are in this driver */
 #define __ei_open ax_ei_open
diff --git a/drivers/net/ethernet/8390/axnet_cs.c b/drivers/net/ethernet/8390/axnet_cs.c
index c5bd8eb..e1b3941 100644
--- a/drivers/net/ethernet/8390/axnet_cs.c
+++ b/drivers/net/ethernet/8390/axnet_cs.c
@@ -46,7 +46,6 @@
 #include <pcmcia/cisreg.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 
diff --git a/drivers/net/ethernet/8390/e2100.c b/drivers/net/ethernet/8390/e2100.c
index d16dc53..ed55ce8 100644
--- a/drivers/net/ethernet/8390/e2100.c
+++ b/drivers/net/ethernet/8390/e2100.c
@@ -48,7 +48,6 @@
 #include <linux/delay.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include "8390.h"
 
diff --git a/drivers/net/ethernet/8390/es3210.c b/drivers/net/ethernet/8390/es3210.c
index 6428f9e..ba1b5c9 100644
--- a/drivers/net/ethernet/8390/es3210.c
+++ b/drivers/net/ethernet/8390/es3210.c
@@ -59,7 +59,6 @@
 #include <linux/etherdevice.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include "8390.h"
 
diff --git a/drivers/net/ethernet/8390/etherh.c b/drivers/net/ethernet/8390/etherh.c
index 48c4948..dbefd56 100644
--- a/drivers/net/ethernet/8390/etherh.c
+++ b/drivers/net/ethernet/8390/etherh.c
@@ -45,9 +45,9 @@
 #include <linux/bitops.h>
 #include <linux/jiffies.h>
 
-#include <asm/system.h>
 #include <asm/ecard.h>
 #include <asm/io.h>
+#include <asm/system_info.h>
 
 #define EI_SHIFT(x)	(ei_local->reg_offset[x])
 
diff --git a/drivers/net/ethernet/8390/hp-plus.c b/drivers/net/ethernet/8390/hp-plus.c
index d42938b..52f70f9 100644
--- a/drivers/net/ethernet/8390/hp-plus.c
+++ b/drivers/net/ethernet/8390/hp-plus.c
@@ -33,7 +33,6 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include "8390.h"
diff --git a/drivers/net/ethernet/8390/hp.c b/drivers/net/ethernet/8390/hp.c
index 113f1e0..37fa89a 100644
--- a/drivers/net/ethernet/8390/hp.c
+++ b/drivers/net/ethernet/8390/hp.c
@@ -33,7 +33,6 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include "8390.h"
diff --git a/drivers/net/ethernet/8390/lib8390.c b/drivers/net/ethernet/8390/lib8390.c
index e77f624..b329f5c 100644
--- a/drivers/net/ethernet/8390/lib8390.c
+++ b/drivers/net/ethernet/8390/lib8390.c
@@ -57,7 +57,6 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/bitops.h>
-#include <asm/system.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <asm/irq.h>
diff --git a/drivers/net/ethernet/8390/lne390.c b/drivers/net/ethernet/8390/lne390.c
index 69490ae..479409b 100644
--- a/drivers/net/ethernet/8390/lne390.c
+++ b/drivers/net/ethernet/8390/lne390.c
@@ -46,7 +46,6 @@
 #include <linux/etherdevice.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include "8390.h"
 
diff --git a/drivers/net/ethernet/8390/mac8390.c b/drivers/net/ethernet/8390/mac8390.c
index af5d982..88ccc8b 100644
--- a/drivers/net/ethernet/8390/mac8390.c
+++ b/drivers/net/ethernet/8390/mac8390.c
@@ -37,7 +37,6 @@
 #include <linux/bitops.h>
 #include <linux/io.h>
 
-#include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/hwtest.h>
 #include <asm/macints.h>
diff --git a/drivers/net/ethernet/8390/ne-h8300.c b/drivers/net/ethernet/8390/ne-h8300.c
index 9b9c77d..7fc28f2 100644
--- a/drivers/net/ethernet/8390/ne-h8300.c
+++ b/drivers/net/ethernet/8390/ne-h8300.c
@@ -29,7 +29,6 @@
 #include <linux/etherdevice.h>
 #include <linux/jiffies.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
diff --git a/drivers/net/ethernet/8390/ne.c b/drivers/net/ethernet/8390/ne.c
index f92ea2a..d04911d 100644
--- a/drivers/net/ethernet/8390/ne.c
+++ b/drivers/net/ethernet/8390/ne.c
@@ -53,7 +53,6 @@
 #include <linux/jiffies.h>
 #include <linux/platform_device.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include "8390.h"
diff --git a/drivers/net/ethernet/8390/ne2.c b/drivers/net/ethernet/8390/ne2.c
index 922b320..ef85839 100644
--- a/drivers/net/ethernet/8390/ne2.c
+++ b/drivers/net/ethernet/8390/ne2.c
@@ -76,7 +76,6 @@
 #include <linux/bitops.h>
 #include <linux/jiffies.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
diff --git a/drivers/net/ethernet/8390/ne2k-pci.c b/drivers/net/ethernet/8390/ne2k-pci.c
index 3fab04a..5e8845f 100644
--- a/drivers/net/ethernet/8390/ne2k-pci.c
+++ b/drivers/net/ethernet/8390/ne2k-pci.c
@@ -54,7 +54,6 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
diff --git a/drivers/net/ethernet/8390/ne3210.c b/drivers/net/ethernet/8390/ne3210.c
index 2a3e805..a2f8b2b 100644
--- a/drivers/net/ethernet/8390/ne3210.c
+++ b/drivers/net/ethernet/8390/ne3210.c
@@ -39,7 +39,6 @@
 #include <linux/mm.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include "8390.h"
 
diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c
index f2a4e5d..de1af0b 100644
--- a/drivers/net/ethernet/8390/pcnet_cs.c
+++ b/drivers/net/ethernet/8390/pcnet_cs.c
@@ -49,7 +49,6 @@
 #include <pcmcia/cisreg.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 
diff --git a/drivers/net/ethernet/8390/smc-mca.c b/drivers/net/ethernet/8390/smc-mca.c
index 77efec4..7a68590 100644
--- a/drivers/net/ethernet/8390/smc-mca.c
+++ b/drivers/net/ethernet/8390/smc-mca.c
@@ -47,7 +47,6 @@
 #include <linux/etherdevice.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include "8390.h"
 
diff --git a/drivers/net/ethernet/8390/smc-ultra.c b/drivers/net/ethernet/8390/smc-ultra.c
index 1cc306a..b0fbce3 100644
--- a/drivers/net/ethernet/8390/smc-ultra.c
+++ b/drivers/net/ethernet/8390/smc-ultra.c
@@ -69,7 +69,6 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 
 #include "8390.h"
 
diff --git a/drivers/net/ethernet/8390/smc-ultra32.c b/drivers/net/ethernet/8390/smc-ultra32.c
index bb87053..923e42a 100644
--- a/drivers/net/ethernet/8390/smc-ultra32.c
+++ b/drivers/net/ethernet/8390/smc-ultra32.c
@@ -57,7 +57,6 @@
 #include <linux/etherdevice.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include "8390.h"
 
diff --git a/drivers/net/ethernet/8390/stnic.c b/drivers/net/ethernet/8390/stnic.c
index 3b90375..8df4c41 100644
--- a/drivers/net/ethernet/8390/stnic.c
+++ b/drivers/net/ethernet/8390/stnic.c
@@ -17,7 +17,6 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <mach-se/mach/se.h>
 #include <asm/machvec.h>
diff --git a/drivers/net/ethernet/8390/wd.c b/drivers/net/ethernet/8390/wd.c
index c175fad..03eb3ee 100644
--- a/drivers/net/ethernet/8390/wd.c
+++ b/drivers/net/ethernet/8390/wd.c
@@ -39,7 +39,6 @@
 #include <linux/etherdevice.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include "8390.h"
 
diff --git a/drivers/net/ethernet/8390/zorro8390.c b/drivers/net/ethernet/8390/zorro8390.c
index bcd2732..7818e63 100644
--- a/drivers/net/ethernet/8390/zorro8390.c
+++ b/drivers/net/ethernet/8390/zorro8390.c
@@ -31,7 +31,6 @@
 #include <linux/zorro.h>
 #include <linux/jiffies.h>
 
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
diff --git a/drivers/net/ethernet/alteon/acenic.c b/drivers/net/ethernet/alteon/acenic.c
index 6c3b1c0..7219123 100644
--- a/drivers/net/ethernet/alteon/acenic.c
+++ b/drivers/net/ethernet/alteon/acenic.c
@@ -78,7 +78,6 @@
 #include <net/sock.h>
 #include <net/ip.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/byteorder.h>
diff --git a/drivers/net/ethernet/amd/7990.c b/drivers/net/ethernet/amd/7990.c
index 1b046f5..6e722dc 100644
--- a/drivers/net/ethernet/amd/7990.c
+++ b/drivers/net/ethernet/amd/7990.c
@@ -33,7 +33,6 @@
 #include <linux/socket.h>
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/pgtable.h>
diff --git a/drivers/net/ethernet/amd/am79c961a.c b/drivers/net/ethernet/amd/am79c961a.c
index cc7b9e4..e10ffad 100644
--- a/drivers/net/ethernet/amd/am79c961a.c
+++ b/drivers/net/ethernet/amd/am79c961a.c
@@ -30,7 +30,6 @@
 #include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/system.h>
 
 #define TX_BUFFERS 15
 #define RX_BUFFERS 25
diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c
index 9f62504..64d0d9c 100644
--- a/drivers/net/ethernet/amd/amd8111e.c
+++ b/drivers/net/ethernet/amd/amd8111e.c
@@ -88,7 +88,6 @@
 #include <linux/crc32.h>
 #include <linux/dma-mapping.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
diff --git a/drivers/net/ethernet/amd/declance.c b/drivers/net/ethernet/amd/declance.c
index 7dc508e..75299f5 100644
--- a/drivers/net/ethernet/amd/declance.c
+++ b/drivers/net/ethernet/amd/declance.c
@@ -64,7 +64,6 @@
 #include <linux/types.h>
 
 #include <asm/addrspace.h>
-#include <asm/system.h>
 
 #include <asm/dec/interrupts.h>
 #include <asm/dec/ioasic.h>
diff --git a/drivers/net/ethernet/amd/hplance.c b/drivers/net/ethernet/amd/hplance.c
index 4e2d68a..8baff4e 100644
--- a/drivers/net/ethernet/amd/hplance.c
+++ b/drivers/net/ethernet/amd/hplance.c
@@ -22,7 +22,6 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 
diff --git a/drivers/net/ethernet/amd/mvme147.c b/drivers/net/ethernet/amd/mvme147.c
index 56bc47a9..9af3c30 100644
--- a/drivers/net/ethernet/amd/mvme147.c
+++ b/drivers/net/ethernet/amd/mvme147.c
@@ -22,7 +22,6 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/mvme147hw.h>
diff --git a/drivers/net/ethernet/amd/nmclan_cs.c b/drivers/net/ethernet/amd/nmclan_cs.c
index ebdb9e2..9f59bf6 100644
--- a/drivers/net/ethernet/amd/nmclan_cs.c
+++ b/drivers/net/ethernet/amd/nmclan_cs.c
@@ -154,7 +154,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 /* ----------------------------------------------------------------------------
 Defines
diff --git a/drivers/net/ethernet/amd/sunlance.c b/drivers/net/ethernet/amd/sunlance.c
index e3fe350..d7a3533 100644
--- a/drivers/net/ethernet/amd/sunlance.c
+++ b/drivers/net/ethernet/amd/sunlance.c
@@ -95,7 +95,6 @@
 #include <linux/of_device.h>
 #include <linux/gfp.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/pgtable.h>
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index e37161f..2c9ee55 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -1173,6 +1173,13 @@
 };
 
 
+struct bnx2x_prev_path_list {
+	u8 bus;
+	u8 slot;
+	u8 path;
+	struct list_head list;
+};
+
 struct bnx2x {
 	/* Fields used in the tx and intr/napi performance paths
 	 * are grouped together in the beginning of the structure
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index f1f3ca6..4b05481 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -1721,6 +1721,29 @@
 	} while (0)
 #endif
 
+bool bnx2x_test_firmware_version(struct bnx2x *bp, bool is_err)
+{
+	/* build FW version dword */
+	u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) +
+		    (BCM_5710_FW_MINOR_VERSION << 8) +
+		    (BCM_5710_FW_REVISION_VERSION << 16) +
+		    (BCM_5710_FW_ENGINEERING_VERSION << 24);
+
+	/* read loaded FW from chip */
+	u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM);
+
+	DP(NETIF_MSG_IFUP, "loaded fw %x, my fw %x\n", loaded_fw, my_fw);
+
+	if (loaded_fw != my_fw) {
+		if (is_err)
+			BNX2X_ERR("bnx2x with FW %x was already loaded, which mismatches my %x FW. aborting\n",
+				  loaded_fw, my_fw);
+		return false;
+	}
+
+	return true;
+}
+
 /* must be called with rtnl_lock */
 int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 {
@@ -1815,23 +1838,8 @@
 		}
 		if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP &&
 		    load_code != FW_MSG_CODE_DRV_LOAD_COMMON) {
-			/* build FW version dword */
-			u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) +
-					(BCM_5710_FW_MINOR_VERSION << 8) +
-					(BCM_5710_FW_REVISION_VERSION << 16) +
-					(BCM_5710_FW_ENGINEERING_VERSION << 24);
-
-			/* read loaded FW from chip */
-			u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM);
-
-			DP(BNX2X_MSG_SP, "loaded fw %x, my fw %x",
-			   loaded_fw, my_fw);
-
 			/* abort nic load if version mismatch */
-			if (my_fw != loaded_fw) {
-				BNX2X_ERR("bnx2x with FW %x already loaded, "
-					  "which mismatches my %x FW. aborting",
-					  loaded_fw, my_fw);
+			if (!bnx2x_test_firmware_version(bp, true)) {
 				rc = -EBUSY;
 				LOAD_ERROR_EXIT(bp, load_error2);
 			}
@@ -1866,7 +1874,6 @@
 		 * bnx2x_periodic_task().
 		 */
 		smp_mb();
-		queue_delayed_work(bnx2x_wq, &bp->period_task, 0);
 	} else
 		bp->port.pmf = 0;
 
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index 8b16338..5c27454 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -431,6 +431,9 @@
 
 void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl);
 
+/* validate currect fw is loaded */
+bool bnx2x_test_firmware_version(struct bnx2x *bp, bool is_err);
+
 /* dev_close main block */
 int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode);
 
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
index cd6dfa9..b9b2633 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
@@ -25,31 +25,31 @@
 	(IRO[149].base + ((funcId) * IRO[149].m1))
 #define CSTORM_IGU_MODE_OFFSET (IRO[157].base)
 #define CSTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \
-	(IRO[315].base + ((pfId) * IRO[315].m1))
-#define CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
 	(IRO[316].base + ((pfId) * IRO[316].m1))
+#define CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
+	(IRO[317].base + ((pfId) * IRO[317].m1))
 #define CSTORM_ISCSI_EQ_CONS_OFFSET(pfId, iscsiEqId) \
-	(IRO[308].base + ((pfId) * IRO[308].m1) + ((iscsiEqId) * IRO[308].m2))
-#define CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(pfId, iscsiEqId) \
-	(IRO[310].base + ((pfId) * IRO[310].m1) + ((iscsiEqId) * IRO[310].m2))
-#define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(pfId, iscsiEqId) \
 	(IRO[309].base + ((pfId) * IRO[309].m1) + ((iscsiEqId) * IRO[309].m2))
-#define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(pfId, iscsiEqId) \
+#define CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(pfId, iscsiEqId) \
 	(IRO[311].base + ((pfId) * IRO[311].m1) + ((iscsiEqId) * IRO[311].m2))
-#define CSTORM_ISCSI_EQ_PROD_OFFSET(pfId, iscsiEqId) \
-	(IRO[307].base + ((pfId) * IRO[307].m1) + ((iscsiEqId) * IRO[307].m2))
-#define CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(pfId, iscsiEqId) \
-	(IRO[313].base + ((pfId) * IRO[313].m1) + ((iscsiEqId) * IRO[313].m2))
-#define CSTORM_ISCSI_EQ_SB_NUM_OFFSET(pfId, iscsiEqId) \
+#define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(pfId, iscsiEqId) \
+	(IRO[310].base + ((pfId) * IRO[310].m1) + ((iscsiEqId) * IRO[310].m2))
+#define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(pfId, iscsiEqId) \
 	(IRO[312].base + ((pfId) * IRO[312].m1) + ((iscsiEqId) * IRO[312].m2))
+#define CSTORM_ISCSI_EQ_PROD_OFFSET(pfId, iscsiEqId) \
+	(IRO[308].base + ((pfId) * IRO[308].m1) + ((iscsiEqId) * IRO[308].m2))
+#define CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(pfId, iscsiEqId) \
+	(IRO[314].base + ((pfId) * IRO[314].m1) + ((iscsiEqId) * IRO[314].m2))
+#define CSTORM_ISCSI_EQ_SB_NUM_OFFSET(pfId, iscsiEqId) \
+	(IRO[313].base + ((pfId) * IRO[313].m1) + ((iscsiEqId) * IRO[313].m2))
 #define CSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \
-	(IRO[314].base + ((pfId) * IRO[314].m1))
+	(IRO[315].base + ((pfId) * IRO[315].m1))
 #define CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
-	(IRO[306].base + ((pfId) * IRO[306].m1))
+	(IRO[307].base + ((pfId) * IRO[307].m1))
 #define CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
-	(IRO[305].base + ((pfId) * IRO[305].m1))
+	(IRO[306].base + ((pfId) * IRO[306].m1))
 #define CSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
-	(IRO[304].base + ((pfId) * IRO[304].m1))
+	(IRO[305].base + ((pfId) * IRO[305].m1))
 #define CSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
 	(IRO[151].base + ((funcId) * IRO[151].m1))
 #define CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(pfId) \
@@ -96,37 +96,37 @@
 #define TSTORM_FUNC_EN_OFFSET(funcId) \
 	(IRO[103].base + ((funcId) * IRO[103].m1))
 #define TSTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \
-	(IRO[271].base + ((pfId) * IRO[271].m1))
-#define TSTORM_ISCSI_L2_ISCSI_OOO_CID_TABLE_OFFSET(pfId) \
 	(IRO[272].base + ((pfId) * IRO[272].m1))
-#define TSTORM_ISCSI_L2_ISCSI_OOO_CLIENT_ID_TABLE_OFFSET(pfId) \
+#define TSTORM_ISCSI_L2_ISCSI_OOO_CID_TABLE_OFFSET(pfId) \
 	(IRO[273].base + ((pfId) * IRO[273].m1))
-#define TSTORM_ISCSI_L2_ISCSI_OOO_PROD_OFFSET(pfId) \
+#define TSTORM_ISCSI_L2_ISCSI_OOO_CLIENT_ID_TABLE_OFFSET(pfId) \
 	(IRO[274].base + ((pfId) * IRO[274].m1))
+#define TSTORM_ISCSI_L2_ISCSI_OOO_PROD_OFFSET(pfId) \
+	(IRO[275].base + ((pfId) * IRO[275].m1))
 #define TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
-	(IRO[270].base + ((pfId) * IRO[270].m1))
+	(IRO[271].base + ((pfId) * IRO[271].m1))
 #define TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
-	(IRO[269].base + ((pfId) * IRO[269].m1))
+	(IRO[270].base + ((pfId) * IRO[270].m1))
 #define TSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
-	(IRO[268].base + ((pfId) * IRO[268].m1))
+	(IRO[269].base + ((pfId) * IRO[269].m1))
 #define TSTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
-	(IRO[267].base + ((pfId) * IRO[267].m1))
+	(IRO[268].base + ((pfId) * IRO[268].m1))
 #define TSTORM_ISCSI_TCP_LOCAL_ADV_WND_OFFSET(pfId) \
-	(IRO[276].base + ((pfId) * IRO[276].m1))
+	(IRO[277].base + ((pfId) * IRO[277].m1))
 #define TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \
-	(IRO[263].base + ((pfId) * IRO[263].m1))
-#define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfId) \
 	(IRO[264].base + ((pfId) * IRO[264].m1))
-#define TSTORM_ISCSI_TCP_VARS_MID_LOCAL_MAC_ADDR_OFFSET(pfId) \
+#define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfId) \
 	(IRO[265].base + ((pfId) * IRO[265].m1))
-#define TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfId) \
+#define TSTORM_ISCSI_TCP_VARS_MID_LOCAL_MAC_ADDR_OFFSET(pfId) \
 	(IRO[266].base + ((pfId) * IRO[266].m1))
+#define TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfId) \
+	(IRO[267].base + ((pfId) * IRO[267].m1))
 #define TSTORM_MAC_FILTER_CONFIG_OFFSET(pfId) \
 	(IRO[202].base + ((pfId) * IRO[202].m1))
 #define TSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
 	(IRO[105].base + ((funcId) * IRO[105].m1))
 #define TSTORM_TCP_MAX_CWND_OFFSET(pfId) \
-	(IRO[216].base + ((pfId) * IRO[216].m1))
+	(IRO[217].base + ((pfId) * IRO[217].m1))
 #define TSTORM_VF_TO_PF_OFFSET(funcId) \
 	(IRO[104].base + ((funcId) * IRO[104].m1))
 #define USTORM_AGG_DATA_OFFSET (IRO[206].base)
@@ -140,29 +140,29 @@
 #define USTORM_ETH_PAUSE_ENABLED_OFFSET(portId) \
 	(IRO[183].base + ((portId) * IRO[183].m1))
 #define USTORM_FCOE_EQ_PROD_OFFSET(pfId) \
-	(IRO[317].base + ((pfId) * IRO[317].m1))
+	(IRO[318].base + ((pfId) * IRO[318].m1))
 #define USTORM_FUNC_EN_OFFSET(funcId) \
 	(IRO[178].base + ((funcId) * IRO[178].m1))
 #define USTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \
-	(IRO[281].base + ((pfId) * IRO[281].m1))
-#define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
 	(IRO[282].base + ((pfId) * IRO[282].m1))
-#define USTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \
-	(IRO[286].base + ((pfId) * IRO[286].m1))
-#define USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfId) \
+#define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
 	(IRO[283].base + ((pfId) * IRO[283].m1))
-#define USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
-	(IRO[279].base + ((pfId) * IRO[279].m1))
-#define USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
-	(IRO[278].base + ((pfId) * IRO[278].m1))
-#define USTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
-	(IRO[277].base + ((pfId) * IRO[277].m1))
-#define USTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \
-	(IRO[280].base + ((pfId) * IRO[280].m1))
-#define USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfId) \
+#define USTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \
+	(IRO[287].base + ((pfId) * IRO[287].m1))
+#define USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfId) \
 	(IRO[284].base + ((pfId) * IRO[284].m1))
-#define USTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
+#define USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
+	(IRO[280].base + ((pfId) * IRO[280].m1))
+#define USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
+	(IRO[279].base + ((pfId) * IRO[279].m1))
+#define USTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
+	(IRO[278].base + ((pfId) * IRO[278].m1))
+#define USTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \
+	(IRO[281].base + ((pfId) * IRO[281].m1))
+#define USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfId) \
 	(IRO[285].base + ((pfId) * IRO[285].m1))
+#define USTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
+	(IRO[286].base + ((pfId) * IRO[286].m1))
 #define USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(pfId) \
 	(IRO[182].base + ((pfId) * IRO[182].m1))
 #define USTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
@@ -188,39 +188,39 @@
 #define XSTORM_FUNC_EN_OFFSET(funcId) \
 	(IRO[47].base + ((funcId) * IRO[47].m1))
 #define XSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \
-	(IRO[294].base + ((pfId) * IRO[294].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(pfId) \
-	(IRO[297].base + ((pfId) * IRO[297].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfId) \
-	(IRO[298].base + ((pfId) * IRO[298].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfId) \
-	(IRO[299].base + ((pfId) * IRO[299].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfId) \
-	(IRO[300].base + ((pfId) * IRO[300].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfId) \
-	(IRO[301].base + ((pfId) * IRO[301].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfId) \
-	(IRO[302].base + ((pfId) * IRO[302].m1))
-#define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfId) \
-	(IRO[303].base + ((pfId) * IRO[303].m1))
-#define XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
-	(IRO[293].base + ((pfId) * IRO[293].m1))
-#define XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
-	(IRO[292].base + ((pfId) * IRO[292].m1))
-#define XSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
-	(IRO[291].base + ((pfId) * IRO[291].m1))
-#define XSTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \
-	(IRO[296].base + ((pfId) * IRO[296].m1))
-#define XSTORM_ISCSI_SQ_SIZE_OFFSET(pfId) \
 	(IRO[295].base + ((pfId) * IRO[295].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(pfId) \
+	(IRO[298].base + ((pfId) * IRO[298].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfId) \
+	(IRO[299].base + ((pfId) * IRO[299].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfId) \
+	(IRO[300].base + ((pfId) * IRO[300].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfId) \
+	(IRO[301].base + ((pfId) * IRO[301].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfId) \
+	(IRO[302].base + ((pfId) * IRO[302].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfId) \
+	(IRO[303].base + ((pfId) * IRO[303].m1))
+#define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfId) \
+	(IRO[304].base + ((pfId) * IRO[304].m1))
+#define XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
+	(IRO[294].base + ((pfId) * IRO[294].m1))
+#define XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
+	(IRO[293].base + ((pfId) * IRO[293].m1))
+#define XSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
+	(IRO[292].base + ((pfId) * IRO[292].m1))
+#define XSTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \
+	(IRO[297].base + ((pfId) * IRO[297].m1))
+#define XSTORM_ISCSI_SQ_SIZE_OFFSET(pfId) \
+	(IRO[296].base + ((pfId) * IRO[296].m1))
 #define XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(pfId) \
-	(IRO[290].base + ((pfId) * IRO[290].m1))
+	(IRO[291].base + ((pfId) * IRO[291].m1))
 #define XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \
-	(IRO[289].base + ((pfId) * IRO[289].m1))
+	(IRO[290].base + ((pfId) * IRO[290].m1))
 #define XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(pfId) \
-	(IRO[288].base + ((pfId) * IRO[288].m1))
+	(IRO[289].base + ((pfId) * IRO[289].m1))
 #define XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(pfId) \
-	(IRO[287].base + ((pfId) * IRO[287].m1))
+	(IRO[288].base + ((pfId) * IRO[288].m1))
 #define XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(pfId) \
 	(IRO[44].base + ((pfId) * IRO[44].m1))
 #define XSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
index 5d71b7d..dbff591 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
@@ -1251,6 +1251,9 @@
 
 	#define DRV_MSG_CODE_LINK_STATUS_CHANGED        0x01000000
 
+	#define DRV_MSG_CODE_INITIATE_FLR               0x02000000
+	#define REQ_BC_VER_4_INITIATE_FLR               0x00070213
+
 	#define BIOS_MSG_CODE_LIC_CHALLENGE             0xff010000
 	#define BIOS_MSG_CODE_LIC_RESPONSE              0xff020000
 	#define BIOS_MSG_CODE_VIRT_MAC_PRIM             0xff030000
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index beb4cdb..ad95324 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -35,7 +35,6 @@
 #define ETH_MAX_PACKET_SIZE		1500
 #define ETH_MAX_JUMBO_PACKET_SIZE	9600
 #define MDIO_ACCESS_TIMEOUT		1000
-#define BMAC_CONTROL_RX_ENABLE		2
 #define WC_LANE_MAX			4
 #define I2C_SWITCH_WIDTH		2
 #define I2C_BSC0			0
@@ -1372,7 +1371,14 @@
 		pfc1_val |= XMAC_PFC_CTRL_HI_REG_PFC_REFRESH_EN |
 			XMAC_PFC_CTRL_HI_REG_PFC_STATS_EN |
 			XMAC_PFC_CTRL_HI_REG_RX_PFC_EN |
-			XMAC_PFC_CTRL_HI_REG_TX_PFC_EN;
+			XMAC_PFC_CTRL_HI_REG_TX_PFC_EN |
+			XMAC_PFC_CTRL_HI_REG_FORCE_PFC_XON;
+		/* Write pause and PFC registers */
+		REG_WR(bp, xmac_base + XMAC_REG_PAUSE_CTRL, pause_val);
+		REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL, pfc0_val);
+		REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, pfc1_val);
+		pfc1_val &= ~XMAC_PFC_CTRL_HI_REG_FORCE_PFC_XON;
+
 	}
 
 	/* Write pause and PFC registers */
@@ -3649,6 +3655,33 @@
 	if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) {
 		bnx2x_cl22_read(bp, phy, 0x4, &ld_pause);
 		bnx2x_cl22_read(bp, phy, 0x5, &lp_pause);
+	} else if (CHIP_IS_E3(bp) &&
+		SINGLE_MEDIA_DIRECT(params)) {
+		u8 lane = bnx2x_get_warpcore_lane(phy, params);
+		u16 gp_status, gp_mask;
+		bnx2x_cl45_read(bp, phy,
+				MDIO_AN_DEVAD, MDIO_WC_REG_GP2_STATUS_GP_2_4,
+				&gp_status);
+		gp_mask = (MDIO_WC_REG_GP2_STATUS_GP_2_4_CL73_AN_CMPL |
+			   MDIO_WC_REG_GP2_STATUS_GP_2_4_CL37_LP_AN_CAP) <<
+			lane;
+		if ((gp_status & gp_mask) == gp_mask) {
+			bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+					MDIO_AN_REG_ADV_PAUSE, &ld_pause);
+			bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+					MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
+		} else {
+			bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+					MDIO_AN_REG_CL37_FC_LD, &ld_pause);
+			bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+					MDIO_AN_REG_CL37_FC_LP, &lp_pause);
+			ld_pause = ((ld_pause &
+				     MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH)
+				    << 3);
+			lp_pause = ((lp_pause &
+				     MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH)
+				    << 3);
+		}
 	} else {
 		bnx2x_cl45_read(bp, phy,
 				MDIO_AN_DEVAD,
@@ -3699,7 +3732,23 @@
 	u16 val16 = 0, lane, bam37 = 0;
 	struct bnx2x *bp = params->bp;
 	DP(NETIF_MSG_LINK, "Enable Auto Negotiation for KR\n");
-
+	/* Set to default registers that may be overriden by 10G force */
+	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+			 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7);
+	bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+			 MDIO_WC_REG_PAR_DET_10G_CTRL, 0);
+	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+			 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, 0);
+	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+			MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0xff);
+	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+			MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0x5555);
+	bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
+			 MDIO_WC_REG_IEEE0BLK_AUTONEGNP, 0x0);
+	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+			 MDIO_WC_REG_RX66_CONTROL, 0x7415);
+	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+			 MDIO_WC_REG_SERDESDIGITAL_MISC2, 0x6190);
 	/* Disable Autoneg: re-enable it after adv is done. */
 	bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
 			 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0);
@@ -3945,13 +3994,13 @@
 
 	} else {
 		misc1_val |= 0x9;
-		tap_val = ((0x12 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
-			   (0x2d << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
-			   (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET));
+		tap_val = ((0x0f << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
+			   (0x2b << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
+			   (0x02 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET));
 		tx_driver_val =
-		      ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
+		      ((0x03 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
 		       (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
-		       (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET));
+		       (0x06 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET));
 	}
 	bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
 			 MDIO_WC_REG_SERDESDIGITAL_MISC1, misc1_val);
@@ -4369,7 +4418,7 @@
 		switch (serdes_net_if) {
 		case PORT_HW_CFG_NET_SERDES_IF_KR:
 			/* Enable KR Auto Neg */
-			if (params->loopback_mode == LOOPBACK_NONE)
+			if (params->loopback_mode != LOOPBACK_EXT)
 				bnx2x_warpcore_enable_AN_KR(phy, params, vars);
 			else {
 				DP(NETIF_MSG_LINK, "Setting KR 10G-Force\n");
@@ -6167,12 +6216,14 @@
 
 		tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
 		if (params->phy[EXT_PHY1].type ==
-			  PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE)
-			EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp & 0xfff1);
-		else {
-			EMAC_WR(bp, EMAC_REG_EMAC_LED,
-				(tmp | EMAC_LED_OVERRIDE));
-		}
+			PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE)
+			tmp &= ~(EMAC_LED_1000MB_OVERRIDE |
+				EMAC_LED_100MB_OVERRIDE |
+				EMAC_LED_10MB_OVERRIDE);
+		else
+			tmp |= EMAC_LED_OVERRIDE;
+
+		EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp);
 		break;
 
 	case LED_MODE_OPER:
@@ -6227,10 +6278,15 @@
 				       hw_led_mode);
 		} else if ((params->phy[EXT_PHY1].type ==
 			    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) &&
-			   (mode != LED_MODE_OPER)) {
+			   (mode == LED_MODE_ON)) {
 			REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
 			tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
-			EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp | 0x3);
+			EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp |
+				EMAC_LED_OVERRIDE | EMAC_LED_1000MB_OVERRIDE);
+			/* Break here; otherwise, it'll disable the
+			 * intended override.
+			 */
+			break;
 		} else
 			REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
 			       hw_led_mode);
@@ -6245,13 +6301,9 @@
 			       LED_BLINK_RATE_VAL_E1X_E2);
 		REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
 		       port*4, 1);
-		if ((params->phy[EXT_PHY1].type !=
-		     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) &&
-		    (mode != LED_MODE_OPER)) {
-			tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
-			EMAC_WR(bp, EMAC_REG_EMAC_LED,
-				(tmp & (~EMAC_LED_OVERRIDE)));
-		}
+		tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
+		EMAC_WR(bp, EMAC_REG_EMAC_LED,
+			(tmp & (~EMAC_LED_OVERRIDE)));
 
 		if (CHIP_IS_E1(bp) &&
 		    ((speed == SPEED_2500) ||
@@ -6844,6 +6896,12 @@
 			  SINGLE_MEDIA_DIRECT(params)) &&
 			 (phy_vars[active_external_phy].fault_detected == 0));
 
+	/* Update the PFC configuration in case it was changed */
+	if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
+		vars->link_status |= LINK_STATUS_PFC_ENABLED;
+	else
+		vars->link_status &= ~LINK_STATUS_PFC_ENABLED;
+
 	if (vars->link_up)
 		rc = bnx2x_update_link_up(params, vars, link_10g_plus);
 	else
@@ -8031,7 +8089,9 @@
 	netdev_err(bp->dev,  "Warning: Unqualified SFP+ module detected,"
 			      " Port %d from %s part number %s\n",
 			 params->port, vendor_name, vendor_pn);
-	phy->flags |= FLAGS_SFP_NOT_APPROVED;
+	if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
+	    PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_WARNING_MSG)
+		phy->flags |= FLAGS_SFP_NOT_APPROVED;
 	return -EINVAL;
 }
 
@@ -9091,6 +9151,12 @@
 		tmp2 &= 0xFFEF;
 		bnx2x_cl45_write(bp, phy,
 			MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, tmp2);
+		bnx2x_cl45_read(bp, phy,
+				MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
+				&tmp2);
+		bnx2x_cl45_write(bp, phy,
+				 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
+				 (tmp2 & 0x7fff));
 	}
 
 	return 0;
@@ -9271,12 +9337,11 @@
 				 MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL,
 				 ((1<<5) | (1<<2)));
 	}
-	DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n");
-	bnx2x_8727_specific_func(phy, params, ENABLE_TX);
-	/* If transmitter is disabled, ignore false link up indication */
-	bnx2x_cl45_read(bp, phy,
-			MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
-	if (val1 & (1<<15)) {
+
+	if (!(phy->flags & FLAGS_SFP_NOT_APPROVED)) {
+		DP(NETIF_MSG_LINK, "Enabling 8727 TX laser\n");
+		bnx2x_sfp_set_transmitter(params, phy, 1);
+	} else {
 		DP(NETIF_MSG_LINK, "Tx is disabled\n");
 		return 0;
 	}
@@ -9370,8 +9435,7 @@
 
 	if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
 		bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, 0x400f, &fw_ver1);
-		bnx2x_save_spirom_version(bp, port,
-				((fw_ver1 & 0xf000)>>5) | (fw_ver1 & 0x7f),
+		bnx2x_save_spirom_version(bp, port, fw_ver1 & 0xfff,
 				phy->ver_addr);
 	} else {
 		/* For 32-bit registers in 848xx, access via MDIO2ARM i/f. */
@@ -9794,6 +9858,15 @@
 				other_shmem_base_addr));
 
 	u32 shmem_base_path[2];
+
+	/* Work around for 84833 LED failure inside RESET status */
+	bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+		MDIO_AN_REG_8481_LEGACY_MII_CTRL,
+		MDIO_AN_REG_8481_MII_CTRL_FORCE_1G);
+	bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+		MDIO_AN_REG_8481_1G_100T_EXT_CTRL,
+		MIDO_AN_REG_8481_EXT_CTRL_FORCE_LEDS_OFF);
+
 	shmem_base_path[0] = params->shmem_base;
 	shmem_base_path[1] = other_shmem_base_addr;
 
@@ -10104,7 +10177,7 @@
 	u8 port;
 	u16 val16;
 
-	if (!(CHIP_IS_E1(bp)))
+	if (!(CHIP_IS_E1x(bp)))
 		port = BP_PATH(bp);
 	else
 		port = params->port;
@@ -10131,7 +10204,7 @@
 	u16 val;
 	u8 port;
 
-	if (!(CHIP_IS_E1(bp)))
+	if (!(CHIP_IS_E1x(bp)))
 		port = BP_PATH(bp);
 	else
 		port = params->port;
@@ -12050,6 +12123,9 @@
 
 	bnx2x_emac_init(params, vars);
 
+	if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
+		vars->link_status |= LINK_STATUS_PFC_ENABLED;
+
 	if (params->num_phys == 0) {
 		DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
 		return -EINVAL;
@@ -12129,10 +12205,10 @@
 	 * Hold it as vars low
 	 */
 	 /* clear link led */
+	bnx2x_set_mdio_clk(bp, params->chip_id, port);
 	bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
 
 	if (reset_ext_phy) {
-		bnx2x_set_mdio_clk(bp, params->chip_id, port);
 		for (phy_index = EXT_PHY1; phy_index < params->num_phys;
 		      phy_index++) {
 			if (params->phy[phy_index].link_reset) {
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
index 7ba557a..763535e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
@@ -89,6 +89,8 @@
 #define PFC_BRB_FULL_LB_XON_THRESHOLD				250
 
 #define MAXVAL(a, b) (((a) > (b)) ? (a) : (b))
+
+#define BMAC_CONTROL_RX_ENABLE		2
 /***********************************************************/
 /*                         Structs                         */
 /***********************************************************/
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index f7f9aa8..e077d25 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -52,6 +52,7 @@
 #include <linux/prefetch.h>
 #include <linux/zlib.h>
 #include <linux/io.h>
+#include <linux/semaphore.h>
 #include <linux/stringify.h>
 #include <linux/vmalloc.h>
 
@@ -211,6 +212,10 @@
 
 MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl);
 
+/* Global resources for unloading a previously loaded device */
+#define BNX2X_PREV_WAIT_NEEDED 1
+static DEFINE_SEMAPHORE(bnx2x_prev_sem);
+static LIST_HEAD(bnx2x_prev_list);
 /****************************************************************************
 * General service functions
 ****************************************************************************/
@@ -8812,109 +8817,371 @@
 		bnx2x_undi_int_disable_e1h(bp);
 }
 
-static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
+static void __devinit bnx2x_prev_unload_close_mac(struct bnx2x *bp)
 {
-	u32 val;
+	u32 val, base_addr, offset, mask, reset_reg;
+	bool mac_stopped = false;
+	u8 port = BP_PORT(bp);
 
-	/* possibly another driver is trying to reset the chip */
-	bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
+	reset_reg = REG_RD(bp, MISC_REG_RESET_REG_2);
 
-	/* check if doorbell queue is reset */
-	if (REG_RD(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET)
-	    & MISC_REGISTERS_RESET_REG_1_RST_DORQ) {
+	if (!CHIP_IS_E3(bp)) {
+		val = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port * 4);
+		mask = MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port;
+		if ((mask & reset_reg) && val) {
+			u32 wb_data[2];
+			BNX2X_DEV_INFO("Disable bmac Rx\n");
+			base_addr = BP_PORT(bp) ? NIG_REG_INGRESS_BMAC1_MEM
+						: NIG_REG_INGRESS_BMAC0_MEM;
+			offset = CHIP_IS_E2(bp) ? BIGMAC2_REGISTER_BMAC_CONTROL
+						: BIGMAC_REGISTER_BMAC_CONTROL;
 
-		/*
-		 * Check if it is the UNDI driver
-		 * UNDI driver initializes CID offset for normal bell to 0x7
-		 */
-		val = REG_RD(bp, DORQ_REG_NORM_CID_OFST);
-		if (val == 0x7) {
-			u32 reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
-			/* save our pf_num */
-			int orig_pf_num = bp->pf_num;
-			int port;
-			u32 swap_en, swap_val, value;
+			/*
+			 * use rd/wr since we cannot use dmae. This is safe
+			 * since MCP won't access the bus due to the request
+			 * to unload, and no function on the path can be
+			 * loaded at this time.
+			 */
+			wb_data[0] = REG_RD(bp, base_addr + offset);
+			wb_data[1] = REG_RD(bp, base_addr + offset + 0x4);
+			wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
+			REG_WR(bp, base_addr + offset, wb_data[0]);
+			REG_WR(bp, base_addr + offset + 0x4, wb_data[1]);
 
-			/* clear the UNDI indication */
-			REG_WR(bp, DORQ_REG_NORM_CID_OFST, 0);
+		}
+		BNX2X_DEV_INFO("Disable emac Rx\n");
+		REG_WR(bp, NIG_REG_NIG_EMAC0_EN + BP_PORT(bp)*4, 0);
 
-			BNX2X_DEV_INFO("UNDI is active! reset device\n");
-
-			/* try unload UNDI on port 0 */
-			bp->pf_num = 0;
-			bp->fw_seq =
-			      (SHMEM_RD(bp, func_mb[bp->pf_num].drv_mb_header) &
-				DRV_MSG_SEQ_NUMBER_MASK);
-			reset_code = bnx2x_fw_command(bp, reset_code, 0);
-
-			/* if UNDI is loaded on the other port */
-			if (reset_code != FW_MSG_CODE_DRV_UNLOAD_COMMON) {
-
-				/* send "DONE" for previous unload */
-				bnx2x_fw_command(bp,
-						 DRV_MSG_CODE_UNLOAD_DONE, 0);
-
-				/* unload UNDI on port 1 */
-				bp->pf_num = 1;
-				bp->fw_seq =
-			      (SHMEM_RD(bp, func_mb[bp->pf_num].drv_mb_header) &
-					DRV_MSG_SEQ_NUMBER_MASK);
-				reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
-
-				bnx2x_fw_command(bp, reset_code, 0);
-			}
-
-			bnx2x_undi_int_disable(bp);
-			port = BP_PORT(bp);
-
-			/* close input traffic and wait for it */
-			/* Do not rcv packets to BRB */
-			REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_DRV_MASK :
-					   NIG_REG_LLH0_BRB1_DRV_MASK), 0x0);
-			/* Do not direct rcv packets that are not for MCP to
-			 * the BRB */
-			REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_NOT_MCP :
-					   NIG_REG_LLH0_BRB1_NOT_MCP), 0x0);
-			/* clear AEU */
-			REG_WR(bp, (port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
-					   MISC_REG_AEU_MASK_ATTN_FUNC_0), 0);
-			msleep(10);
-
-			/* save NIG port swap info */
-			swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
-			swap_en = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
-			/* reset device */
-			REG_WR(bp,
-			       GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
-			       0xd3ffffff);
-
-			value = 0x1400;
-			if (CHIP_IS_E3(bp)) {
-				value |= MISC_REGISTERS_RESET_REG_2_MSTAT0;
-				value |= MISC_REGISTERS_RESET_REG_2_MSTAT1;
-			}
-
-			REG_WR(bp,
-			       GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
-			       value);
-
-			/* take the NIG out of reset and restore swap values */
-			REG_WR(bp,
-			       GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET,
-			       MISC_REGISTERS_RESET_REG_1_RST_NIG);
-			REG_WR(bp, NIG_REG_PORT_SWAP, swap_val);
-			REG_WR(bp, NIG_REG_STRAP_OVERRIDE, swap_en);
-
-			/* send unload done to the MCP */
-			bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
-
-			/* restore our func and fw_seq */
-			bp->pf_num = orig_pf_num;
+		mac_stopped = true;
+	} else {
+		if (reset_reg & MISC_REGISTERS_RESET_REG_2_XMAC) {
+			BNX2X_DEV_INFO("Disable xmac Rx\n");
+			base_addr = BP_PORT(bp) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
+			val = REG_RD(bp, base_addr + XMAC_REG_PFC_CTRL_HI);
+			REG_WR(bp, base_addr + XMAC_REG_PFC_CTRL_HI,
+			       val & ~(1 << 1));
+			REG_WR(bp, base_addr + XMAC_REG_PFC_CTRL_HI,
+			       val | (1 << 1));
+			REG_WR(bp, base_addr + XMAC_REG_CTRL, 0);
+			mac_stopped = true;
+		}
+		mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port;
+		if (mask & reset_reg) {
+			BNX2X_DEV_INFO("Disable umac Rx\n");
+			base_addr = BP_PORT(bp) ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
+			REG_WR(bp, base_addr + UMAC_REG_COMMAND_CONFIG, 0);
+			mac_stopped = true;
 		}
 	}
 
-	/* now it's safe to release the lock */
-	bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
+	if (mac_stopped)
+		msleep(20);
+
+}
+
+#define BNX2X_PREV_UNDI_PROD_ADDR(p) (BAR_TSTRORM_INTMEM + 0x1508 + ((p) << 4))
+#define BNX2X_PREV_UNDI_RCQ(val)	((val) & 0xffff)
+#define BNX2X_PREV_UNDI_BD(val)		((val) >> 16 & 0xffff)
+#define BNX2X_PREV_UNDI_PROD(rcq, bd)	((bd) << 16 | (rcq))
+
+static void __devinit bnx2x_prev_unload_undi_inc(struct bnx2x *bp, u8 port,
+						 u8 inc)
+{
+	u16 rcq, bd;
+	u32 tmp_reg = REG_RD(bp, BNX2X_PREV_UNDI_PROD_ADDR(port));
+
+	rcq = BNX2X_PREV_UNDI_RCQ(tmp_reg) + inc;
+	bd = BNX2X_PREV_UNDI_BD(tmp_reg) + inc;
+
+	tmp_reg = BNX2X_PREV_UNDI_PROD(rcq, bd);
+	REG_WR(bp, BNX2X_PREV_UNDI_PROD_ADDR(port), tmp_reg);
+
+	BNX2X_DEV_INFO("UNDI producer [%d] rings bd -> 0x%04x, rcq -> 0x%04x\n",
+		       port, bd, rcq);
+}
+
+static int __devinit bnx2x_prev_mcp_done(struct bnx2x *bp)
+{
+	u32 rc = bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
+	if (!rc) {
+		BNX2X_ERR("MCP response failure, aborting\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static bool __devinit bnx2x_prev_is_path_marked(struct bnx2x *bp)
+{
+	struct bnx2x_prev_path_list *tmp_list;
+	int rc = false;
+
+	if (down_trylock(&bnx2x_prev_sem))
+		return false;
+
+	list_for_each_entry(tmp_list, &bnx2x_prev_list, list) {
+		if (PCI_SLOT(bp->pdev->devfn) == tmp_list->slot &&
+		    bp->pdev->bus->number == tmp_list->bus &&
+		    BP_PATH(bp) == tmp_list->path) {
+			rc = true;
+			BNX2X_DEV_INFO("Path %d was already cleaned from previous drivers\n",
+				       BP_PATH(bp));
+			break;
+		}
+	}
+
+	up(&bnx2x_prev_sem);
+
+	return rc;
+}
+
+static int __devinit bnx2x_prev_mark_path(struct bnx2x *bp)
+{
+	struct bnx2x_prev_path_list *tmp_list;
+	int rc;
+
+	tmp_list = (struct bnx2x_prev_path_list *)
+		    kmalloc(sizeof(struct bnx2x_prev_path_list), GFP_KERNEL);
+	if (!tmp_list) {
+		BNX2X_ERR("Failed to allocate 'bnx2x_prev_path_list'\n");
+		return -ENOMEM;
+	}
+
+	tmp_list->bus = bp->pdev->bus->number;
+	tmp_list->slot = PCI_SLOT(bp->pdev->devfn);
+	tmp_list->path = BP_PATH(bp);
+
+	rc = down_interruptible(&bnx2x_prev_sem);
+	if (rc) {
+		BNX2X_ERR("Received %d when tried to take lock\n", rc);
+		kfree(tmp_list);
+	} else {
+		BNX2X_DEV_INFO("Marked path [%d] - finished previous unload\n",
+				BP_PATH(bp));
+		list_add(&tmp_list->list, &bnx2x_prev_list);
+		up(&bnx2x_prev_sem);
+	}
+
+	return rc;
+}
+
+static bool __devinit bnx2x_can_flr(struct bnx2x *bp)
+{
+	int pos;
+	u32 cap;
+	struct pci_dev *dev = bp->pdev;
+
+	pos = pci_pcie_cap(dev);
+	if (!pos)
+		return false;
+
+	pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP, &cap);
+	if (!(cap & PCI_EXP_DEVCAP_FLR))
+		return false;
+
+	return true;
+}
+
+static int __devinit bnx2x_do_flr(struct bnx2x *bp)
+{
+	int i, pos;
+	u16 status;
+	struct pci_dev *dev = bp->pdev;
+
+	/* probe the capability first */
+	if (bnx2x_can_flr(bp))
+		return -ENOTTY;
+
+	pos = pci_pcie_cap(dev);
+	if (!pos)
+		return -ENOTTY;
+
+	/* Wait for Transaction Pending bit clean */
+	for (i = 0; i < 4; i++) {
+		if (i)
+			msleep((1 << (i - 1)) * 100);
+
+		pci_read_config_word(dev, pos + 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 (bp->common.bc_ver < REQ_BC_VER_4_INITIATE_FLR) {
+		BNX2X_ERR("FLR not supported by BC_VER: 0x%x\n",
+			  bp->common.bc_ver);
+		return -EINVAL;
+	}
+
+	bnx2x_fw_command(bp, DRV_MSG_CODE_INITIATE_FLR, 0);
+
+	return 0;
+}
+
+static int __devinit bnx2x_prev_unload_uncommon(struct bnx2x *bp)
+{
+	int rc;
+
+	BNX2X_DEV_INFO("Uncommon unload Flow\n");
+
+	/* Test if previous unload process was already finished for this path */
+	if (bnx2x_prev_is_path_marked(bp))
+		return bnx2x_prev_mcp_done(bp);
+
+	/* If function has FLR capabilities, and existing FW version matches
+	 * the one required, then FLR will be sufficient to clean any residue
+	 * left by previous driver
+	 */
+	if (bnx2x_test_firmware_version(bp, false) && bnx2x_can_flr(bp))
+		return bnx2x_do_flr(bp);
+
+	/* Close the MCP request, return failure*/
+	rc = bnx2x_prev_mcp_done(bp);
+	if (!rc)
+		rc = BNX2X_PREV_WAIT_NEEDED;
+
+	return rc;
+}
+
+static int __devinit bnx2x_prev_unload_common(struct bnx2x *bp)
+{
+	u32 reset_reg, tmp_reg = 0, rc;
+	/* It is possible a previous function received 'common' answer,
+	 * but hasn't loaded yet, therefore creating a scenario of
+	 * multiple functions receiving 'common' on the same path.
+	 */
+	BNX2X_DEV_INFO("Common unload Flow\n");
+
+	if (bnx2x_prev_is_path_marked(bp))
+		return bnx2x_prev_mcp_done(bp);
+
+	reset_reg = REG_RD(bp, MISC_REG_RESET_REG_1);
+
+	/* Reset should be performed after BRB is emptied */
+	if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_BRB1) {
+		u32 timer_count = 1000;
+		bool prev_undi = false;
+
+		/* Close the MAC Rx to prevent BRB from filling up */
+		bnx2x_prev_unload_close_mac(bp);
+
+		/* Check if the UNDI driver was previously loaded
+		 * UNDI driver initializes CID offset for normal bell to 0x7
+		 */
+		reset_reg = REG_RD(bp, MISC_REG_RESET_REG_1);
+		if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_DORQ) {
+			tmp_reg = REG_RD(bp, DORQ_REG_NORM_CID_OFST);
+			if (tmp_reg == 0x7) {
+				BNX2X_DEV_INFO("UNDI previously loaded\n");
+				prev_undi = true;
+				/* clear the UNDI indication */
+				REG_WR(bp, DORQ_REG_NORM_CID_OFST, 0);
+			}
+		}
+		/* wait until BRB is empty */
+		tmp_reg = REG_RD(bp, BRB1_REG_NUM_OF_FULL_BLOCKS);
+		while (timer_count) {
+			u32 prev_brb = tmp_reg;
+
+			tmp_reg = REG_RD(bp, BRB1_REG_NUM_OF_FULL_BLOCKS);
+			if (!tmp_reg)
+				break;
+
+			BNX2X_DEV_INFO("BRB still has 0x%08x\n", tmp_reg);
+
+			/* reset timer as long as BRB actually gets emptied */
+			if (prev_brb > tmp_reg)
+				timer_count = 1000;
+			else
+				timer_count--;
+
+			/* If UNDI resides in memory, manually increment it */
+			if (prev_undi)
+				bnx2x_prev_unload_undi_inc(bp, BP_PORT(bp), 1);
+
+			udelay(10);
+		}
+
+		if (!timer_count)
+			BNX2X_ERR("Failed to empty BRB, hope for the best\n");
+
+	}
+
+	/* No packets are in the pipeline, path is ready for reset */
+	bnx2x_reset_common(bp);
+
+	rc = bnx2x_prev_mark_path(bp);
+	if (rc) {
+		bnx2x_prev_mcp_done(bp);
+		return rc;
+	}
+
+	return bnx2x_prev_mcp_done(bp);
+}
+
+static int __devinit bnx2x_prev_unload(struct bnx2x *bp)
+{
+	int time_counter = 10;
+	u32 rc, fw, hw_lock_reg, hw_lock_val;
+	BNX2X_DEV_INFO("Entering Previous Unload Flow\n");
+
+       /* Release previously held locks */
+	hw_lock_reg = (BP_FUNC(bp) <= 5) ?
+		      (MISC_REG_DRIVER_CONTROL_1 + BP_FUNC(bp) * 8) :
+		      (MISC_REG_DRIVER_CONTROL_7 + (BP_FUNC(bp) - 6) * 8);
+
+	hw_lock_val = (REG_RD(bp, hw_lock_reg));
+	if (hw_lock_val) {
+		if (hw_lock_val & HW_LOCK_RESOURCE_NVRAM) {
+			BNX2X_DEV_INFO("Release Previously held NVRAM lock\n");
+			REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB,
+			       (MCPR_NVM_SW_ARB_ARB_REQ_CLR1 << BP_PORT(bp)));
+		}
+
+		BNX2X_DEV_INFO("Release Previously held hw lock\n");
+		REG_WR(bp, hw_lock_reg, 0xffffffff);
+	} else
+		BNX2X_DEV_INFO("No need to release hw/nvram locks\n");
+
+	if (MCPR_ACCESS_LOCK_LOCK & REG_RD(bp, MCP_REG_MCPR_ACCESS_LOCK)) {
+		BNX2X_DEV_INFO("Release previously held alr\n");
+		REG_WR(bp, MCP_REG_MCPR_ACCESS_LOCK, 0);
+	}
+
+
+	do {
+		/* Lock MCP using an unload request */
+		fw = bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS, 0);
+		if (!fw) {
+			BNX2X_ERR("MCP response failure, aborting\n");
+			rc = -EBUSY;
+			break;
+		}
+
+		if (fw == FW_MSG_CODE_DRV_UNLOAD_COMMON) {
+			rc = bnx2x_prev_unload_common(bp);
+			break;
+		}
+
+		/* non-common reply from MCP night require looping */
+		rc = bnx2x_prev_unload_uncommon(bp);
+		if (rc != BNX2X_PREV_WAIT_NEEDED)
+			break;
+
+		msleep(20);
+	} while (--time_counter);
+
+	if (!time_counter || rc) {
+		BNX2X_ERR("Failed unloading previous driver, aborting\n");
+		rc = -EBUSY;
+	}
+
+	BNX2X_DEV_INFO("Finished Previous Unload Flow [%d]\n", rc);
+
+	return rc;
 }
 
 static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
@@ -10100,8 +10367,16 @@
 	func = BP_FUNC(bp);
 
 	/* need to reset chip if undi was active */
-	if (!BP_NOMCP(bp))
-		bnx2x_undi_unload(bp);
+	if (!BP_NOMCP(bp)) {
+		/* init fw_seq */
+		bp->fw_seq =
+			SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
+							DRV_MSG_SEQ_NUMBER_MASK;
+		BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
+
+		bnx2x_prev_unload(bp);
+	}
+
 
 	if (CHIP_REV_IS_FPGA(bp))
 		dev_err(&bp->pdev->dev, "FPGA detected\n");
@@ -11431,9 +11706,18 @@
 
 static void __exit bnx2x_cleanup(void)
 {
+	struct list_head *pos, *q;
 	pci_unregister_driver(&bnx2x_pci_driver);
 
 	destroy_workqueue(bnx2x_wq);
+
+	/* Free globablly allocated resources */
+	list_for_each_safe(pos, q, &bnx2x_prev_list) {
+		struct bnx2x_prev_path_list *tmp =
+			list_entry(pos, struct bnx2x_prev_path_list, list);
+		list_del(pos);
+		kfree(tmp);
+	}
 }
 
 void bnx2x_notify_link_changed(struct bnx2x *bp)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
index fd7fb45..c25803b 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
@@ -987,6 +987,7 @@
  * clear; 1 = set. Data valid only in addresses 0-4. all the rest are zero. */
 #define IGU_REG_WRITE_DONE_PENDING				 0x130480
 #define MCP_A_REG_MCPR_SCRATCH					 0x3a0000
+#define MCP_REG_MCPR_ACCESS_LOCK				 0x8009c
 #define MCP_REG_MCPR_CPU_PROGRAM_COUNTER			 0x8501c
 #define MCP_REG_MCPR_GP_INPUTS					 0x800c0
 #define MCP_REG_MCPR_GP_OENABLE					 0x800c8
@@ -1686,6 +1687,7 @@
    [10] rst_dbg; [11] rst_misc_core; [12] rst_dbue (UART); [13]
    Pci_resetmdio_n; [14] rst_emac0_hard_core; [15] rst_emac1_hard_core; 16]
    rst_pxp_rq_rd_wr; 31:17] reserved */
+#define MISC_REG_RESET_REG_1					 0xa580
 #define MISC_REG_RESET_REG_2					 0xa590
 /* [RW 20] 20 bit GRC address where the scratch-pad of the MCP that is
    shared with the driver resides */
@@ -5352,6 +5354,7 @@
 #define XMAC_CTRL_REG_TX_EN					 (0x1<<0)
 #define XMAC_PAUSE_CTRL_REG_RX_PAUSE_EN				 (0x1<<18)
 #define XMAC_PAUSE_CTRL_REG_TX_PAUSE_EN				 (0x1<<17)
+#define XMAC_PFC_CTRL_HI_REG_FORCE_PFC_XON			 (0x1<<1)
 #define XMAC_PFC_CTRL_HI_REG_PFC_REFRESH_EN			 (0x1<<0)
 #define XMAC_PFC_CTRL_HI_REG_PFC_STATS_EN			 (0x1<<3)
 #define XMAC_PFC_CTRL_HI_REG_RX_PFC_EN				 (0x1<<4)
@@ -5606,6 +5609,7 @@
 /* [RC 32] Parity register #0 read clear */
 #define XSEM_REG_XSEM_PRTY_STS_CLR_0				 0x280128
 #define XSEM_REG_XSEM_PRTY_STS_CLR_1				 0x280138
+#define MCPR_ACCESS_LOCK_LOCK					 (1L<<31)
 #define MCPR_NVM_ACCESS_ENABLE_EN				 (1L<<0)
 #define MCPR_NVM_ACCESS_ENABLE_WR_EN				 (1L<<1)
 #define MCPR_NVM_ADDR_NVM_ADDR_VALUE				 (0xffffffL<<0)
@@ -5732,6 +5736,7 @@
 #define MISC_REGISTERS_GPIO_PORT_SHIFT				 4
 #define MISC_REGISTERS_GPIO_SET_POS				 8
 #define MISC_REGISTERS_RESET_REG_1_CLEAR			 0x588
+#define MISC_REGISTERS_RESET_REG_1_RST_BRB1			 (0x1<<0)
 #define MISC_REGISTERS_RESET_REG_1_RST_DORQ			 (0x1<<19)
 #define MISC_REGISTERS_RESET_REG_1_RST_HC			 (0x1<<29)
 #define MISC_REGISTERS_RESET_REG_1_RST_NIG			 (0x1<<7)
@@ -6816,10 +6821,13 @@
 
 #define MDIO_AN_REG_8481_10GBASE_T_AN_CTRL	0x0020
 #define MDIO_AN_REG_8481_LEGACY_MII_CTRL	0xffe0
+#define MDIO_AN_REG_8481_MII_CTRL_FORCE_1G	0x40
 #define MDIO_AN_REG_8481_LEGACY_MII_STATUS	0xffe1
 #define MDIO_AN_REG_8481_LEGACY_AN_ADV		0xffe4
 #define MDIO_AN_REG_8481_LEGACY_AN_EXPANSION	0xffe6
 #define MDIO_AN_REG_8481_1000T_CTRL		0xffe9
+#define MDIO_AN_REG_8481_1G_100T_EXT_CTRL	0xfff0
+#define MIDO_AN_REG_8481_EXT_CTRL_FORCE_LEDS_OFF	0x0008
 #define MDIO_AN_REG_8481_EXPANSION_REG_RD_RW	0xfff5
 #define MDIO_AN_REG_8481_EXPANSION_REG_ACCESS	0xfff7
 #define MDIO_AN_REG_8481_AUX_CTRL		0xfff8
@@ -6939,6 +6947,10 @@
 #define MDIO_WC_REG_GP2_STATUS_GP_2_2			0x81d2
 #define MDIO_WC_REG_GP2_STATUS_GP_2_3			0x81d3
 #define MDIO_WC_REG_GP2_STATUS_GP_2_4			0x81d4
+#define MDIO_WC_REG_GP2_STATUS_GP_2_4_CL73_AN_CMPL 0x1000
+#define MDIO_WC_REG_GP2_STATUS_GP_2_4_CL37_AN_CMPL 0x0100
+#define MDIO_WC_REG_GP2_STATUS_GP_2_4_CL37_LP_AN_CAP 0x0010
+#define MDIO_WC_REG_GP2_STATUS_GP_2_4_CL37_AN_CAP 0x1
 #define MDIO_WC_REG_UC_INFO_B0_DEAD_TRAP		0x81EE
 #define MDIO_WC_REG_UC_INFO_B1_VERSION			0x81F0
 #define MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE		0x81F2
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index 3f52fad..5135733 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -3847,7 +3847,7 @@
 			continue;
 
 		/* If we've got here we are going to find a free entry */
-		for (idx = vec * BNX2X_POOL_VEC_SIZE, i = 0;
+		for (idx = vec * BIT_VEC64_ELEM_SZ, i = 0;
 		      i < BIT_VEC64_ELEM_SZ; idx++, i++)
 
 			if (BIT_VEC64_TEST_BIT(o->pool_mirror, idx)) {
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 7b71387..062ac33 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -48,7 +48,6 @@
 #include <net/checksum.h>
 #include <net/ip.h>
 
-#include <asm/system.h>
 #include <linux/io.h>
 #include <asm/byteorder.h>
 #include <linux/uaccess.h>
@@ -2779,7 +2778,9 @@
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
 	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 &&
-	     (tp->phy_flags & TG3_PHYFLG_MII_SERDES)))
+	     (tp->phy_flags & TG3_PHYFLG_MII_SERDES)) ||
+	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
+	     !tp->pci_fn))
 		return;
 
 	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX ||
diff --git a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
index c9fdceb..6e8bc9d 100644
--- a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
+++ b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
@@ -516,7 +516,7 @@
 
 struct bnad_debugfs_entry {
 	const char *name;
-	mode_t  mode;
+	umode_t  mode;
 	const struct file_operations *fops;
 };
 
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 05ff076a..b126b98 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -2000,13 +2000,6 @@
 /*
  * debugfs support
  */
-
-static int mem_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t mem_read(struct file *file, char __user *buf, size_t count,
 			loff_t *ppos)
 {
@@ -2050,7 +2043,7 @@
 
 static const struct file_operations mem_debugfs_fops = {
 	.owner   = THIS_MODULE,
-	.open    = mem_open,
+	.open    = simple_open,
 	.read    = mem_read,
 	.llseek  = default_llseek,
 };
diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cirrus/Kconfig
index 1f8648f..8388e36 100644
--- a/drivers/net/ethernet/cirrus/Kconfig
+++ b/drivers/net/ethernet/cirrus/Kconfig
@@ -5,8 +5,7 @@
 config NET_VENDOR_CIRRUS
 	bool "Cirrus devices"
 	default y
-	depends on ISA || EISA || MACH_IXDP2351 || ARCH_IXDP2X01 \
-		|| MACH_MX31ADS || MACH_QQ2440 || (ARM && ARCH_EP93XX) || MAC
+	depends on ISA || EISA || ARM || MAC
 	---help---
 	  If you have a network (Ethernet) card belonging to this class, say Y
 	  and read the Ethernet-HOWTO, available from
@@ -21,8 +20,7 @@
 
 config CS89x0
 	tristate "CS89x0 support"
-	depends on (ISA || EISA || MACH_IXDP2351 \
-		|| ARCH_IXDP2X01 || MACH_MX31ADS || MACH_QQ2440)
+	depends on ISA || EISA || ARM
 	---help---
 	  Support for CS89x0 chipset based Ethernet cards. If you have a
 	  network (Ethernet) card of this type, say Y and read the
@@ -33,10 +31,15 @@
 	  To compile this driver as a module, choose M here. The module
 	  will be called cs89x0.
 
-config CS89x0_NONISA_IRQ
-	def_bool y
-	depends on CS89x0 != n
-	depends on MACH_IXDP2351 || ARCH_IXDP2X01 || MACH_MX31ADS || MACH_QQ2440
+config CS89x0_PLATFORM
+	bool "CS89x0 platform driver support"
+	depends on CS89x0
+	help
+	  Say Y to compile the cs89x0 driver as a platform driver. This
+	  makes this driver suitable for use on certain evaluation boards
+	  such as the iMX21ADS.
+
+	  If you are unsure, say N.
 
 config EP93XX_ETH
 	tristate "EP93xx Ethernet support"
diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c
index d5ff936..b9406cb 100644
--- a/drivers/net/ethernet/cirrus/cs89x0.c
+++ b/drivers/net/ethernet/cirrus/cs89x0.c
@@ -100,9 +100,6 @@
 
 */
 
-/* Always include 'config.h' first in case the user wants to turn on
-   or override something. */
-#include <linux/module.h>
 
 /*
  * Set this to zero to disable DMA code
@@ -131,9 +128,12 @@
 
 */
 
+#include <linux/module.h>
+#include <linux/printk.h>
 #include <linux/errno.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
@@ -148,9 +148,9 @@
 #include <linux/delay.h>
 #include <linux/gfp.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <linux/atomic.h>
 #if ALLOW_DMA
 #include <asm/dma.h>
 #endif
@@ -174,26 +174,20 @@
    them to system IRQ numbers. This mapping is card specific and is set to
    the configuration of the Cirrus Eval board for this chip. */
 #if defined(CONFIG_MACH_IXDP2351)
+#define CS89x0_NONISA_IRQ
 static unsigned int netcard_portlist[] __used __initdata = {IXDP2351_VIRT_CS8900_BASE, 0};
 static unsigned int cs8900_irq_map[] = {IRQ_IXDP2351_CS8900, 0, 0, 0};
 #elif defined(CONFIG_ARCH_IXDP2X01)
+#define CS89x0_NONISA_IRQ
 static unsigned int netcard_portlist[] __used __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
 static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
-#elif defined(CONFIG_MACH_QQ2440)
-#include <mach/qq2440.h>
-static unsigned int netcard_portlist[] __used __initdata = { QQ2440_CS8900_VIRT_BASE + 0x300, 0 };
-static unsigned int cs8900_irq_map[] = { QQ2440_CS8900_IRQ, 0, 0, 0 };
-#elif defined(CONFIG_MACH_MX31ADS)
-#include <mach/board-mx31ads.h>
-static unsigned int netcard_portlist[] __used __initdata = {
-	PBC_BASE_ADDRESS + PBC_CS8900A_IOBASE + 0x300, 0
-};
-static unsigned cs8900_irq_map[] = {EXPIO_INT_ENET_INT, 0, 0, 0};
 #else
+#ifndef CONFIG_CS89x0_PLATFORM
 static unsigned int netcard_portlist[] __used __initdata =
    { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
 static unsigned int cs8900_irq_map[] = {10,11,12,5};
 #endif
+#endif
 
 #if DEBUGGING
 static unsigned int net_debug = DEBUGGING;
@@ -236,11 +230,16 @@
 	unsigned char *end_dma_buff;	/* points to the end of the buffer */
 	unsigned char *rx_dma_ptr;	/* points to the next packet  */
 #endif
+#ifdef CONFIG_CS89x0_PLATFORM
+	void __iomem *virt_addr;/* Virtual address for accessing the CS89x0. */
+	unsigned long phys_addr;/* Physical address for accessing the CS89x0. */
+	unsigned long size;	/* Length of CS89x0 memory region. */
+#endif
 };
 
 /* Index to functions, as function prototypes. */
 
-static int cs89x0_probe1(struct net_device *dev, int ioaddr, int modular);
+static int cs89x0_probe1(struct net_device *dev, unsigned long ioaddr, int modular);
 static int net_open(struct net_device *dev);
 static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t net_interrupt(int irq, void *dev_id);
@@ -294,6 +293,7 @@
 __setup("cs89x0_media=", media_fn);
 
 
+#ifndef CONFIG_CS89x0_PLATFORM
 /* Check for a network adaptor of this type, and return '0' iff one exists.
    If dev->base_addr == 0, probe all likely locations.
    If dev->base_addr == 1, always return failure.
@@ -343,6 +343,7 @@
 	return ERR_PTR(err);
 }
 #endif
+#endif
 
 #if defined(CONFIG_MACH_IXDP2351)
 static u16
@@ -504,7 +505,7 @@
  */
 
 static int __init
-cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
+cs89x0_probe1(struct net_device *dev, unsigned long ioaddr, int modular)
 {
 	struct net_local *lp = netdev_priv(dev);
 	static unsigned version_printed;
@@ -529,15 +530,12 @@
 		lp->force = g_cs89x0_media__force;
 #endif
 
-#if defined(CONFIG_MACH_QQ2440)
-		lp->force |= FORCE_RJ45 | FORCE_FULL;
-#endif
         }
 
 	/* Grab the region so we can find another board if autoIRQ fails. */
 	/* WTF is going on here? */
 	if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, DRV_NAME)) {
-		printk(KERN_ERR "%s: request_region(0x%x, 0x%x) failed\n",
+		printk(KERN_ERR "%s: request_region(0x%lx, 0x%x) failed\n",
 				DRV_NAME, ioaddr, NETCARD_IO_EXTENT);
 		retval = -EBUSY;
 		goto out1;
@@ -549,7 +547,7 @@
 	   will skip the test for the ADD_PORT. */
 	if (ioaddr & 1) {
 		if (net_debug > 1)
-			printk(KERN_INFO "%s: odd ioaddr 0x%x\n", dev->name, ioaddr);
+			printk(KERN_INFO "%s: odd ioaddr 0x%lx\n", dev->name, ioaddr);
 	        if ((ioaddr & 2) != 2)
 	        	if ((readword(ioaddr & ~3, ADD_PORT) & ADD_MASK) != ADD_SIG) {
 				printk(KERN_ERR "%s: bad signature 0x%x\n",
@@ -560,13 +558,13 @@
 	}
 
 	ioaddr &= ~3;
-	printk(KERN_DEBUG "PP_addr at %x[%x]: 0x%x\n",
+	printk(KERN_DEBUG "PP_addr at %lx[%x]: 0x%x\n",
 			ioaddr, ADD_PORT, readword(ioaddr, ADD_PORT));
 	writeword(ioaddr, ADD_PORT, PP_ChipID);
 
 	tmp = readword(ioaddr, DATA_PORT);
 	if (tmp != CHIP_EISA_ID_SIG) {
-		printk(KERN_DEBUG "%s: incorrect signature at %x[%x]: 0x%x!="
+		printk(KERN_DEBUG "%s: incorrect signature at %lx[%x]: 0x%x!="
 			CHIP_EISA_ID_SIG_STR "\n",
 			dev->name, ioaddr, DATA_PORT, tmp);
   		retval = -ENODEV;
@@ -736,8 +734,9 @@
 			dev->irq = i;
 	} else {
 		i = lp->isa_config & INT_NO_MASK;
+#ifndef CONFIG_CS89x0_PLATFORM
 		if (lp->chip_type == CS8900) {
-#ifdef CONFIG_CS89x0_NONISA_IRQ
+#ifdef CS89x0_NONISA_IRQ
 		        i = cs8900_irq_map[0];
 #else
 			/* Translate the IRQ using the IRQ mapping table. */
@@ -758,6 +757,7 @@
 			}
 #endif
 		}
+#endif
 		if (!dev->irq)
 			dev->irq = i;
 	}
@@ -1168,6 +1168,7 @@
 	int i;
 
 	if (chip_type == CS8900) {
+#ifndef CONFIG_CS89x0_PLATFORM
 		/* Search the mapping table for the corresponding IRQ pin. */
 		for (i = 0; i != ARRAY_SIZE(cs8900_irq_map); i++)
 			if (cs8900_irq_map[i] == irq)
@@ -1175,6 +1176,10 @@
 		/* Not found */
 		if (i == ARRAY_SIZE(cs8900_irq_map))
 			i = 3;
+#else
+		/* INTRQ0 pin is used for interrupt generation. */
+		i = 0;
+#endif
 		writereg(dev, PP_CS8900_ISAINT, i);
 	} else {
 		writereg(dev, PP_CS8920_ISAINT, irq);
@@ -1228,7 +1233,7 @@
 	}
 	else
 	{
-#ifndef CONFIG_CS89x0_NONISA_IRQ
+#if !defined(CS89x0_NONISA_IRQ) && !defined(CONFIG_CS89x0_PLATFORM)
 		if (((1 << dev->irq) & lp->irq_map) == 0) {
 			printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
                                dev->name, dev->irq, lp->irq_map);
@@ -1746,7 +1751,7 @@
 	return 0;
 }
 
-#ifdef MODULE
+#if defined(MODULE) && !defined(CONFIG_CS89x0_PLATFORM)
 
 static struct net_device *dev_cs89x0;
 
@@ -1900,7 +1905,97 @@
 	release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT);
 	free_netdev(dev_cs89x0);
 }
-#endif /* MODULE */
+#endif /* MODULE && !CONFIG_CS89x0_PLATFORM */
+
+#ifdef CONFIG_CS89x0_PLATFORM
+static int __init cs89x0_platform_probe(struct platform_device *pdev)
+{
+	struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
+	struct net_local *lp;
+	struct resource *mem_res;
+	int err;
+
+	if (!dev)
+		return -ENOMEM;
+
+	lp = netdev_priv(dev);
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	dev->irq = platform_get_irq(pdev, 0);
+	if (mem_res == NULL || dev->irq <= 0) {
+		dev_warn(&dev->dev, "memory/interrupt resource missing.\n");
+		err = -ENXIO;
+		goto free;
+	}
+
+	lp->phys_addr = mem_res->start;
+	lp->size = resource_size(mem_res);
+	if (!request_mem_region(lp->phys_addr, lp->size, DRV_NAME)) {
+		dev_warn(&dev->dev, "request_mem_region() failed.\n");
+		err = -EBUSY;
+		goto free;
+	}
+
+	lp->virt_addr = ioremap(lp->phys_addr, lp->size);
+	if (!lp->virt_addr) {
+		dev_warn(&dev->dev, "ioremap() failed.\n");
+		err = -ENOMEM;
+		goto release;
+	}
+
+	err = cs89x0_probe1(dev, (unsigned long)lp->virt_addr, 0);
+	if (err) {
+		dev_warn(&dev->dev, "no cs8900 or cs8920 detected.\n");
+		goto unmap;
+	}
+
+	platform_set_drvdata(pdev, dev);
+	return 0;
+
+unmap:
+	iounmap(lp->virt_addr);
+release:
+	release_mem_region(lp->phys_addr, lp->size);
+free:
+	free_netdev(dev);
+	return err;
+}
+
+static int cs89x0_platform_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct net_local *lp = netdev_priv(dev);
+
+	unregister_netdev(dev);
+	iounmap(lp->virt_addr);
+	release_mem_region(lp->phys_addr, lp->size);
+	free_netdev(dev);
+	return 0;
+}
+
+static struct platform_driver cs89x0_driver = {
+	.driver	= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.remove	= cs89x0_platform_remove,
+};
+
+static int __init cs89x0_init(void)
+{
+	return platform_driver_probe(&cs89x0_driver, cs89x0_platform_probe);
+}
+
+module_init(cs89x0_init);
+
+static void __exit cs89x0_cleanup(void)
+{
+	platform_driver_unregister(&cs89x0_driver);
+}
+
+module_exit(cs89x0_cleanup);
+
+#endif /* CONFIG_CS89x0_PLATFORM */
 
 /*
  * Local variables:
diff --git a/drivers/net/ethernet/cirrus/mac89x0.c b/drivers/net/ethernet/cirrus/mac89x0.c
index 932fdcc..e285f38 100644
--- a/drivers/net/ethernet/cirrus/mac89x0.c
+++ b/drivers/net/ethernet/cirrus/mac89x0.c
@@ -99,7 +99,6 @@
 #include <linux/bitops.h>
 #include <linux/gfp.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/hwtest.h>
 #include <asm/macints.h>
diff --git a/drivers/net/ethernet/dlink/de600.c b/drivers/net/ethernet/dlink/de600.c
index 682750c..414f0ee 100644
--- a/drivers/net/ethernet/dlink/de600.c
+++ b/drivers/net/ethernet/dlink/de600.c
@@ -46,7 +46,6 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
-#include <asm/system.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/delay.h>
diff --git a/drivers/net/ethernet/dlink/de620.c b/drivers/net/ethernet/dlink/de620.c
index afc5aaa..2e2bc60 100644
--- a/drivers/net/ethernet/dlink/de620.c
+++ b/drivers/net/ethernet/dlink/de620.c
@@ -122,7 +122,6 @@
 #include <linux/skbuff.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 /* Constant definitions for the DE-620 registers, commands and bits */
 #include "de620.h"
diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
index 9eb8159..f7f0bf5 100644
--- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c
+++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
@@ -356,13 +356,13 @@
 
 		if (prop)
 			tbiaddr = *prop;
-	}
 
-	if (tbiaddr == -1) {
-		err = -EBUSY;
-		goto err_free_irqs;
-	} else {
-		out_be32(tbipa, tbiaddr);
+		if (tbiaddr == -1) {
+			err = -EBUSY;
+			goto err_free_irqs;
+		} else {
+			out_be32(tbipa, tbiaddr);
+		}
 	}
 
 	err = of_mdiobus_register(new_bus, np);
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index d9428f0e..e7bed53 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -968,7 +968,6 @@
 	struct gfar_private *priv = NULL;
 	struct gfar __iomem *regs = NULL;
 	int err = 0, i, grp_idx = 0;
-	int len_devname;
 	u32 rstat = 0, tstat = 0, rqueue = 0, tqueue = 0;
 	u32 isrg = 0;
 	u32 __iomem *baddr;
@@ -1169,40 +1168,16 @@
 		priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
 	/* fill out IRQ number and name fields */
-	len_devname = strlen(dev->name);
 	for (i = 0; i < priv->num_grps; i++) {
-		strncpy(&priv->gfargrp[i].int_name_tx[0], dev->name,
-				len_devname);
 		if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
-			strncpy(&priv->gfargrp[i].int_name_tx[len_devname],
-				"_g", sizeof("_g"));
-			priv->gfargrp[i].int_name_tx[
-				strlen(priv->gfargrp[i].int_name_tx)] = i+48;
-			strncpy(&priv->gfargrp[i].int_name_tx[strlen(
-				priv->gfargrp[i].int_name_tx)],
-				"_tx", sizeof("_tx") + 1);
-
-			strncpy(&priv->gfargrp[i].int_name_rx[0], dev->name,
-					len_devname);
-			strncpy(&priv->gfargrp[i].int_name_rx[len_devname],
-					"_g", sizeof("_g"));
-			priv->gfargrp[i].int_name_rx[
-				strlen(priv->gfargrp[i].int_name_rx)] = i+48;
-			strncpy(&priv->gfargrp[i].int_name_rx[strlen(
-				priv->gfargrp[i].int_name_rx)],
-				"_rx", sizeof("_rx") + 1);
-
-			strncpy(&priv->gfargrp[i].int_name_er[0], dev->name,
-					len_devname);
-			strncpy(&priv->gfargrp[i].int_name_er[len_devname],
-				"_g", sizeof("_g"));
-			priv->gfargrp[i].int_name_er[strlen(
-					priv->gfargrp[i].int_name_er)] = i+48;
-			strncpy(&priv->gfargrp[i].int_name_er[strlen(\
-				priv->gfargrp[i].int_name_er)],
-				"_er", sizeof("_er") + 1);
+			sprintf(priv->gfargrp[i].int_name_tx, "%s%s%c%s",
+				dev->name, "_g", '0' + i, "_tx");
+			sprintf(priv->gfargrp[i].int_name_rx, "%s%s%c%s",
+				dev->name, "_g", '0' + i, "_rx");
+			sprintf(priv->gfargrp[i].int_name_er, "%s%s%c%s",
+				dev->name, "_g", '0' + i, "_er");
 		} else
-			priv->gfargrp[i].int_name_tx[len_devname] = '\0';
+			strcpy(priv->gfargrp[i].int_name_tx, dev->name);
 	}
 
 	/* Initialize the filer table */
diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index fc2488a..4c9f8d4 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -517,7 +517,7 @@
 #define RXFCB_PERR_MASK		0x000c
 #define RXFCB_PERR_BADL3	0x0008
 
-#define GFAR_INT_NAME_MAX	IFNAMSIZ + 4
+#define GFAR_INT_NAME_MAX	(IFNAMSIZ + 6)	/* '_g#_xx' */
 
 struct txbd8
 {
diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c
index 4e3cd2f..17a46e7 100644
--- a/drivers/net/ethernet/freescale/ucc_geth.c
+++ b/drivers/net/ethernet/freescale/ucc_geth.c
@@ -3945,6 +3945,8 @@
 		}
 
 	if (max_speed == SPEED_1000) {
+		unsigned int snums = qe_get_num_of_snums();
+
 		/* configure muram FIFOs for gigabit operation */
 		ug_info->uf_info.urfs = UCC_GETH_URFS_GIGA_INIT;
 		ug_info->uf_info.urfet = UCC_GETH_URFET_GIGA_INIT;
@@ -3954,11 +3956,11 @@
 		ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT;
 		ug_info->numThreadsTx = UCC_GETH_NUM_OF_THREADS_4;
 
-		/* If QE's snum number is 46 which means we need to support
+		/* If QE's snum number is 46/76 which means we need to support
 		 * 4 UECs at 1000Base-T simultaneously, we need to allocate
 		 * more Threads to Rx.
 		 */
-		if (qe_get_num_of_snums() == 46)
+		if ((snums == 76) || (snums == 46))
 			ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_6;
 		else
 			ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_4;
diff --git a/drivers/net/ethernet/fujitsu/at1700.c b/drivers/net/ethernet/fujitsu/at1700.c
index 586b46f..3d94797 100644
--- a/drivers/net/ethernet/fujitsu/at1700.c
+++ b/drivers/net/ethernet/fujitsu/at1700.c
@@ -52,7 +52,6 @@
 #include <linux/crc32.h>
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
diff --git a/drivers/net/ethernet/fujitsu/eth16i.c b/drivers/net/ethernet/fujitsu/eth16i.c
index c3f0178..a992d1f 100644
--- a/drivers/net/ethernet/fujitsu/eth16i.c
+++ b/drivers/net/ethernet/fujitsu/eth16i.c
@@ -163,7 +163,6 @@
 #include <linux/jiffies.h>
 #include <linux/io.h>
 
-#include <asm/system.h>
 #include <asm/dma.h>
 
 
diff --git a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
index 0230319..2418faf 100644
--- a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
+++ b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
@@ -57,7 +57,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 /*====================================================================*/
 
diff --git a/drivers/net/ethernet/i825xx/3c507.c b/drivers/net/ethernet/i825xx/3c507.c
index ed6925f..e8984b05 100644
--- a/drivers/net/ethernet/i825xx/3c507.c
+++ b/drivers/net/ethernet/i825xx/3c507.c
@@ -63,7 +63,6 @@
 
 #include <asm/dma.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 /* use 0 for production, 1 for verification, 2..7 for debug */
diff --git a/drivers/net/ethernet/i825xx/3c527.c b/drivers/net/ethernet/i825xx/3c527.c
index ef43f3e..278e791 100644
--- a/drivers/net/ethernet/i825xx/3c527.c
+++ b/drivers/net/ethernet/i825xx/3c527.c
@@ -106,7 +106,6 @@
 #include <linux/semaphore.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
diff --git a/drivers/net/ethernet/i825xx/eepro.c b/drivers/net/ethernet/i825xx/eepro.c
index 7a4ad4a..7f49fd5 100644
--- a/drivers/net/ethernet/i825xx/eepro.c
+++ b/drivers/net/ethernet/i825xx/eepro.c
@@ -148,7 +148,6 @@
 #include <linux/bitops.h>
 #include <linux/ethtool.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
diff --git a/drivers/net/ethernet/i825xx/eexpress.c b/drivers/net/ethernet/i825xx/eexpress.c
index 3fc649e..cc2e66a 100644
--- a/drivers/net/ethernet/i825xx/eexpress.c
+++ b/drivers/net/ethernet/i825xx/eexpress.c
@@ -116,7 +116,6 @@
 #include <linux/bitops.h>
 #include <linux/jiffies.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
diff --git a/drivers/net/ethernet/i825xx/ether1.c b/drivers/net/ethernet/i825xx/ether1.c
index 406a12b..067db3f 100644
--- a/drivers/net/ethernet/i825xx/ether1.c
+++ b/drivers/net/ethernet/i825xx/ether1.c
@@ -48,7 +48,6 @@
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/ecard.h>
diff --git a/drivers/net/ethernet/i825xx/znet.c b/drivers/net/ethernet/i825xx/znet.c
index a436497..bd1f1ef 100644
--- a/drivers/net/ethernet/i825xx/znet.c
+++ b/drivers/net/ethernet/i825xx/znet.c
@@ -100,7 +100,6 @@
 #include <linux/if_arp.h>
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index e877371..9010cea 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -1616,11 +1616,8 @@
 	.probe		= ibmveth_probe,
 	.remove		= ibmveth_remove,
 	.get_desired_dma = ibmveth_get_desired_dma,
-	.driver		= {
-		.name	= ibmveth_driver_name,
-		.owner	= THIS_MODULE,
-		.pm = &ibmveth_pm_ops,
-	}
+	.name		= ibmveth_driver_name,
+	.pm		= &ibmveth_pm_ops,
 };
 
 static int __init ibmveth_module_init(void)
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 0e9aec8..4348b6f 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -164,6 +164,8 @@
 static bool e1000_vlan_used(struct e1000_adapter *adapter);
 static void e1000_vlan_mode(struct net_device *netdev,
 			    netdev_features_t features);
+static void e1000_vlan_filter_on_off(struct e1000_adapter *adapter,
+				     bool filter_on);
 static int e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid);
 static int e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid);
 static void e1000_restore_vlan(struct e1000_adapter *adapter);
@@ -215,7 +217,8 @@
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
-static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
+#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)
+static int debug = -1;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
@@ -979,7 +982,7 @@
 	adapter = netdev_priv(netdev);
 	adapter->netdev = netdev;
 	adapter->pdev = pdev;
-	adapter->msg_enable = (1 << debug) - 1;
+	adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
 	adapter->bars = bars;
 	adapter->need_ioport = need_ioport;
 
@@ -1214,7 +1217,7 @@
 	if (err)
 		goto err_register;
 
-	e1000_vlan_mode(netdev, netdev->features);
+	e1000_vlan_filter_on_off(adapter, false);
 
 	/* print bus type/speed/width info */
 	e_info(probe, "(PCI%s:%dMHz:%d-bit) %pM\n",
@@ -4770,6 +4773,22 @@
 	return false;
 }
 
+static void __e1000_vlan_mode(struct e1000_adapter *adapter,
+			      netdev_features_t features)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl;
+
+	ctrl = er32(CTRL);
+	if (features & NETIF_F_HW_VLAN_RX) {
+		/* enable VLAN tag insert/strip */
+		ctrl |= E1000_CTRL_VME;
+	} else {
+		/* disable VLAN tag insert/strip */
+		ctrl &= ~E1000_CTRL_VME;
+	}
+	ew32(CTRL, ctrl);
+}
 static void e1000_vlan_filter_on_off(struct e1000_adapter *adapter,
 				     bool filter_on)
 {
@@ -4779,6 +4798,7 @@
 	if (!test_bit(__E1000_DOWN, &adapter->flags))
 		e1000_irq_disable(adapter);
 
+	__e1000_vlan_mode(adapter, adapter->netdev->features);
 	if (filter_on) {
 		/* enable VLAN receive filtering */
 		rctl = er32(RCTL);
@@ -4799,24 +4819,14 @@
 }
 
 static void e1000_vlan_mode(struct net_device *netdev,
-	netdev_features_t features)
+			    netdev_features_t features)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
-	struct e1000_hw *hw = &adapter->hw;
-	u32 ctrl;
 
 	if (!test_bit(__E1000_DOWN, &adapter->flags))
 		e1000_irq_disable(adapter);
 
-	ctrl = er32(CTRL);
-	if (features & NETIF_F_HW_VLAN_RX) {
-		/* enable VLAN tag insert/strip */
-		ctrl |= E1000_CTRL_VME;
-	} else {
-		/* disable VLAN tag insert/strip */
-		ctrl &= ~E1000_CTRL_VME;
-	}
-	ew32(CTRL, ctrl);
+	__e1000_vlan_mode(adapter, features);
 
 	if (!test_bit(__E1000_DOWN, &adapter->flags))
 		e1000_irq_enable(adapter);
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index 86cdd47..b83897f 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -161,6 +161,12 @@
 /* Time to wait before putting the device into D3 if there's no link (in ms). */
 #define LINK_TIMEOUT		100
 
+/*
+ * Count for polling __E1000_RESET condition every 10-20msec.
+ * Experimentation has shown the reset can take approximately 210msec.
+ */
+#define E1000_CHECK_RESET_COUNT		25
+
 #define DEFAULT_RDTR			0
 #define DEFAULT_RADV			8
 #define BURST_RDTR			0x20
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 7152eb1..19ab215 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -60,6 +60,11 @@
 char e1000e_driver_name[] = "e1000e";
 const char e1000e_driver_version[] = DRV_VERSION;
 
+#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)
+static int debug = -1;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
 static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state);
 
 static const struct e1000_info *e1000_info_tbl[] = {
@@ -1054,6 +1059,13 @@
 		ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD);
 		/* execute the writes immediately */
 		e1e_flush();
+		/*
+		 * Due to rare timing issues, write to TIDV again to ensure
+		 * the write is successful
+		 */
+		ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD);
+		/* execute the writes immediately */
+		e1e_flush();
 		adapter->tx_hang_recheck = true;
 		return;
 	}
@@ -3611,6 +3623,16 @@
 
 	/* execute the writes immediately */
 	e1e_flush();
+
+	/*
+	 * due to rare timing issues, write to TIDV/RDTR again to ensure the
+	 * write is successful
+	 */
+	ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD);
+	ew32(RDTR, adapter->rx_int_delay | E1000_RDTR_FPD);
+
+	/* execute the writes immediately */
+	e1e_flush();
 }
 
 static void e1000e_update_stats(struct e1000_adapter *adapter);
@@ -3963,6 +3985,10 @@
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct pci_dev *pdev = adapter->pdev;
+	int count = E1000_CHECK_RESET_COUNT;
+
+	while (test_bit(__E1000_RESETTING, &adapter->state) && count--)
+		usleep_range(10000, 20000);
 
 	WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
 
@@ -5467,6 +5493,11 @@
 	netif_device_detach(netdev);
 
 	if (netif_running(netdev)) {
+		int count = E1000_CHECK_RESET_COUNT;
+
+		while (test_bit(__E1000_RESETTING, &adapter->state) && count--)
+			usleep_range(10000, 20000);
+
 		WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
 		e1000e_down(adapter);
 		e1000_free_irq(adapter);
@@ -6172,7 +6203,7 @@
 	adapter->hw.adapter = adapter;
 	adapter->hw.mac.type = ei->mac;
 	adapter->max_hw_frame_size = ei->max_hw_frame_size;
-	adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1;
+	adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
 
 	mmio_start = pci_resource_start(pdev, 0);
 	mmio_len = pci_resource_len(pdev, 0);
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index c490241..5ec3159 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -238,6 +238,11 @@
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
+#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)
+static int debug = -1;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
 struct igb_reg_info {
 	u32 ofs;
 	char *name;
@@ -1893,7 +1898,7 @@
 	adapter->pdev = pdev;
 	hw = &adapter->hw;
 	hw->back = adapter;
-	adapter->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE;
+	adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
 
 	mmio_start = pci_resource_start(pdev, 0);
 	mmio_len = pci_resource_len(pdev, 0);
diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index 217c143..d61ca2a 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -55,6 +55,11 @@
 static const char igbvf_copyright[] =
 		  "Copyright (c) 2009 - 2012 Intel Corporation.";
 
+#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)
+static int debug = -1;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
 static int igbvf_poll(struct napi_struct *napi, int budget);
 static void igbvf_reset(struct igbvf_adapter *);
 static void igbvf_set_interrupt_capability(struct igbvf_adapter *);
@@ -2649,7 +2654,7 @@
 	adapter->flags = ei->flags;
 	adapter->hw.back = adapter;
 	adapter->hw.mac.type = ei->mac;
-	adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1;
+	adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
 
 	/* PCI config space info */
 
diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
index 82aaa79..5fce363 100644
--- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
@@ -134,8 +134,8 @@
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
-#define DEFAULT_DEBUG_LEVEL_SHIFT 3
-static int debug = DEFAULT_DEBUG_LEVEL_SHIFT;
+#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)
+static int debug = -1;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
@@ -442,7 +442,7 @@
 	adapter->netdev = netdev;
 	adapter->pdev = pdev;
 	adapter->hw.back = adapter;
-	adapter->msg_enable = netif_msg_init(debug, DEFAULT_DEBUG_LEVEL_SHIFT);
+	adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
 
 	adapter->hw.hw_addr = pci_ioremap_bar(pdev, BAR_0);
 	if (!adapter->hw.hw_addr) {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 80e26ff..74e1921 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -544,7 +544,7 @@
 	u16 action;
 };
 
-enum ixbge_state_t {
+enum ixgbe_state_t {
 	__IXGBE_TESTING,
 	__IXGBE_RESETTING,
 	__IXGBE_DOWN,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
index dde65f9..652e4b0 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
@@ -44,62 +44,94 @@
 #define DCB_NO_HW_CHG   1  /* DCB configuration did not change */
 #define DCB_HW_CHG      2  /* DCB configuration changed, no reset */
 
-int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg,
-                       struct ixgbe_dcb_config *dst_dcb_cfg, int tc_max)
+int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *scfg,
+		       struct ixgbe_dcb_config *dcfg, int tc_max)
 {
-	struct tc_configuration *src_tc_cfg = NULL;
-	struct tc_configuration *dst_tc_cfg = NULL;
-	int i;
+	struct tc_configuration *src = NULL;
+	struct tc_configuration *dst = NULL;
+	int i, j;
+	int tx = DCB_TX_CONFIG;
+	int rx = DCB_RX_CONFIG;
+	int changes = 0;
 
-	if (!src_dcb_cfg || !dst_dcb_cfg)
-		return -EINVAL;
+	if (!scfg || !dcfg)
+		return changes;
 
 	for (i = DCB_PG_ATTR_TC_0; i < tc_max + DCB_PG_ATTR_TC_0; i++) {
-		src_tc_cfg = &src_dcb_cfg->tc_config[i - DCB_PG_ATTR_TC_0];
-		dst_tc_cfg = &dst_dcb_cfg->tc_config[i - DCB_PG_ATTR_TC_0];
+		src = &scfg->tc_config[i - DCB_PG_ATTR_TC_0];
+		dst = &dcfg->tc_config[i - DCB_PG_ATTR_TC_0];
 
-		dst_tc_cfg->path[DCB_TX_CONFIG].prio_type =
-				src_tc_cfg->path[DCB_TX_CONFIG].prio_type;
+		if (dst->path[tx].prio_type != src->path[tx].prio_type) {
+			dst->path[tx].prio_type = src->path[tx].prio_type;
+			changes |= BIT_PG_TX;
+		}
 
-		dst_tc_cfg->path[DCB_TX_CONFIG].bwg_id =
-				src_tc_cfg->path[DCB_TX_CONFIG].bwg_id;
+		if (dst->path[tx].bwg_id != src->path[tx].bwg_id) {
+			dst->path[tx].bwg_id = src->path[tx].bwg_id;
+			changes |= BIT_PG_TX;
+		}
 
-		dst_tc_cfg->path[DCB_TX_CONFIG].bwg_percent =
-				src_tc_cfg->path[DCB_TX_CONFIG].bwg_percent;
+		if (dst->path[tx].bwg_percent != src->path[tx].bwg_percent) {
+			dst->path[tx].bwg_percent = src->path[tx].bwg_percent;
+			changes |= BIT_PG_TX;
+		}
 
-		dst_tc_cfg->path[DCB_TX_CONFIG].up_to_tc_bitmap =
-				src_tc_cfg->path[DCB_TX_CONFIG].up_to_tc_bitmap;
+		if (dst->path[tx].up_to_tc_bitmap !=
+				src->path[tx].up_to_tc_bitmap) {
+			dst->path[tx].up_to_tc_bitmap =
+				src->path[tx].up_to_tc_bitmap;
+			changes |= (BIT_PG_TX | BIT_PFC | BIT_APP_UPCHG);
+		}
 
-		dst_tc_cfg->path[DCB_RX_CONFIG].prio_type =
-				src_tc_cfg->path[DCB_RX_CONFIG].prio_type;
+		if (dst->path[rx].prio_type != src->path[rx].prio_type) {
+			dst->path[rx].prio_type = src->path[rx].prio_type;
+			changes |= BIT_PG_RX;
+		}
 
-		dst_tc_cfg->path[DCB_RX_CONFIG].bwg_id =
-				src_tc_cfg->path[DCB_RX_CONFIG].bwg_id;
+		if (dst->path[rx].bwg_id != src->path[rx].bwg_id) {
+			dst->path[rx].bwg_id = src->path[rx].bwg_id;
+			changes |= BIT_PG_RX;
+		}
 
-		dst_tc_cfg->path[DCB_RX_CONFIG].bwg_percent =
-				src_tc_cfg->path[DCB_RX_CONFIG].bwg_percent;
+		if (dst->path[rx].bwg_percent != src->path[rx].bwg_percent) {
+			dst->path[rx].bwg_percent = src->path[rx].bwg_percent;
+			changes |= BIT_PG_RX;
+		}
 
-		dst_tc_cfg->path[DCB_RX_CONFIG].up_to_tc_bitmap =
-				src_tc_cfg->path[DCB_RX_CONFIG].up_to_tc_bitmap;
+		if (dst->path[rx].up_to_tc_bitmap !=
+				src->path[rx].up_to_tc_bitmap) {
+			dst->path[rx].up_to_tc_bitmap =
+				src->path[rx].up_to_tc_bitmap;
+			changes |= (BIT_PG_RX | BIT_PFC | BIT_APP_UPCHG);
+		}
 	}
 
 	for (i = DCB_PG_ATTR_BW_ID_0; i < DCB_PG_ATTR_BW_ID_MAX; i++) {
-		dst_dcb_cfg->bw_percentage[DCB_TX_CONFIG]
-			[i-DCB_PG_ATTR_BW_ID_0] = src_dcb_cfg->bw_percentage
-				[DCB_TX_CONFIG][i-DCB_PG_ATTR_BW_ID_0];
-		dst_dcb_cfg->bw_percentage[DCB_RX_CONFIG]
-			[i-DCB_PG_ATTR_BW_ID_0] = src_dcb_cfg->bw_percentage
-				[DCB_RX_CONFIG][i-DCB_PG_ATTR_BW_ID_0];
+		j = i - DCB_PG_ATTR_BW_ID_0;
+		if (dcfg->bw_percentage[tx][j] != scfg->bw_percentage[tx][j]) {
+			dcfg->bw_percentage[tx][j] = scfg->bw_percentage[tx][j];
+			changes |= BIT_PG_TX;
+		}
+		if (dcfg->bw_percentage[rx][j] != scfg->bw_percentage[rx][j]) {
+			dcfg->bw_percentage[rx][j] = scfg->bw_percentage[rx][j];
+			changes |= BIT_PG_RX;
+		}
 	}
 
 	for (i = DCB_PFC_UP_ATTR_0; i < DCB_PFC_UP_ATTR_MAX; i++) {
-		dst_dcb_cfg->tc_config[i - DCB_PFC_UP_ATTR_0].dcb_pfc =
-			src_dcb_cfg->tc_config[i - DCB_PFC_UP_ATTR_0].dcb_pfc;
+		j = i - DCB_PFC_UP_ATTR_0;
+		if (dcfg->tc_config[j].dcb_pfc != scfg->tc_config[j].dcb_pfc) {
+			dcfg->tc_config[j].dcb_pfc = scfg->tc_config[j].dcb_pfc;
+			changes |= BIT_PFC;
+		}
 	}
 
-	dst_dcb_cfg->pfc_mode_enable = src_dcb_cfg->pfc_mode_enable;
+	if (dcfg->pfc_mode_enable != scfg->pfc_mode_enable) {
+		dcfg->pfc_mode_enable = scfg->pfc_mode_enable;
+		changes |= BIT_PFC;
+	}
 
-	return 0;
+	return changes;
 }
 
 static u8 ixgbe_dcbnl_get_state(struct net_device *netdev)
@@ -179,20 +211,6 @@
 	if (up_map != DCB_ATTR_VALUE_UNDEFINED)
 		adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap =
 			up_map;
-
-	if ((adapter->temp_dcb_cfg.tc_config[tc].path[0].prio_type !=
-	     adapter->dcb_cfg.tc_config[tc].path[0].prio_type) ||
-	    (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_id !=
-	     adapter->dcb_cfg.tc_config[tc].path[0].bwg_id) ||
-	    (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent !=
-	     adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent) ||
-	    (adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap !=
-	     adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap))
-		adapter->dcb_set_bitmap |= BIT_PG_TX;
-
-	if (adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap !=
-	     adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap)
-		adapter->dcb_set_bitmap |= BIT_PFC | BIT_APP_UPCHG;
 }
 
 static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id,
@@ -201,10 +219,6 @@
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
 	adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] = bw_pct;
-
-	if (adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] !=
-	    adapter->dcb_cfg.bw_percentage[0][bwg_id])
-		adapter->dcb_set_bitmap |= BIT_PG_TX;
 }
 
 static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc,
@@ -223,20 +237,6 @@
 	if (up_map != DCB_ATTR_VALUE_UNDEFINED)
 		adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap =
 			up_map;
-
-	if ((adapter->temp_dcb_cfg.tc_config[tc].path[1].prio_type !=
-	     adapter->dcb_cfg.tc_config[tc].path[1].prio_type) ||
-	    (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_id !=
-	     adapter->dcb_cfg.tc_config[tc].path[1].bwg_id) ||
-	    (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent !=
-	     adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent) ||
-	    (adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap !=
-	     adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap))
-		adapter->dcb_set_bitmap |= BIT_PG_RX;
-
-	if (adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap !=
-	     adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap)
-		adapter->dcb_set_bitmap |= BIT_PFC;
 }
 
 static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id,
@@ -245,10 +245,6 @@
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
 	adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] = bw_pct;
-
-	if (adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] !=
-	    adapter->dcb_cfg.bw_percentage[1][bwg_id])
-		adapter->dcb_set_bitmap |= BIT_PG_RX;
 }
 
 static void ixgbe_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int tc,
@@ -298,10 +294,8 @@
 
 	adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc = setting;
 	if (adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc !=
-	    adapter->dcb_cfg.tc_config[priority].dcb_pfc) {
-		adapter->dcb_set_bitmap |= BIT_PFC;
+	    adapter->dcb_cfg.tc_config[priority].dcb_pfc)
 		adapter->temp_dcb_cfg.pfc_mode_enable = true;
-	}
 }
 
 static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority,
@@ -336,7 +330,8 @@
 static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
-	int ret, i;
+	int ret = DCB_NO_HW_CHG;
+	int i;
 #ifdef IXGBE_FCOE
 	struct dcb_app app = {
 			      .selector = DCB_APP_IDTYPE_ETHTYPE,
@@ -355,12 +350,13 @@
 
 	/* Fail command if not in CEE mode */
 	if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
-		return 1;
+		return ret;
 
-	ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg,
-				 MAX_TRAFFIC_CLASS);
-	if (ret)
-		return DCB_NO_HW_CHG;
+	adapter->dcb_set_bitmap |= ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg,
+						      &adapter->dcb_cfg,
+						      MAX_TRAFFIC_CLASS);
+	if (!adapter->dcb_set_bitmap)
+		return ret;
 
 	if (adapter->dcb_cfg.pfc_mode_enable) {
 		switch (adapter->hw.mac.type) {
@@ -420,6 +416,8 @@
 
 		for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
 			netdev_set_prio_tc_map(netdev, i, prio_tc[i]);
+
+		ret = DCB_HW_CHG_RST;
 	}
 
 	if (adapter->dcb_set_bitmap & BIT_PFC) {
@@ -430,7 +428,8 @@
 				     DCB_TX_CONFIG, prio_tc);
 		ixgbe_dcb_unpack_pfc(&adapter->dcb_cfg, &pfc_en);
 		ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc_en, prio_tc);
-		ret = DCB_HW_CHG;
+		if (ret != DCB_HW_CHG_RST)
+			ret = DCB_HW_CHG;
 	}
 
 	if (adapter->dcb_cfg.pfc_mode_enable)
@@ -531,9 +530,6 @@
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
 	adapter->temp_dcb_cfg.pfc_mode_enable = state;
-	if (adapter->temp_dcb_cfg.pfc_mode_enable !=
-		adapter->dcb_cfg.pfc_mode_enable)
-		adapter->dcb_set_bitmap |= BIT_PFC;
 }
 
 /**
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 398fc22..3e26b1f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -63,8 +63,8 @@
 			      "Intel(R) 10 Gigabit Network Connection";
 #endif
 #define MAJ 3
-#define MIN 6
-#define BUILD 7
+#define MIN 8
+#define BUILD 21
 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
 	__stringify(BUILD) "-k"
 const char ixgbe_driver_version[] = DRV_VERSION;
@@ -141,13 +141,16 @@
 MODULE_PARM_DESC(allow_unsupported_sfp,
 		 "Allow unsupported and untested SFP+ modules on 82599-based adapters");
 
+#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)
+static int debug = -1;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
 MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
 MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
-#define DEFAULT_DEBUG_LEVEL_SHIFT 3
-
 static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter)
 {
 	if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
@@ -6834,7 +6837,7 @@
 	adapter->pdev = pdev;
 	hw = &adapter->hw;
 	hw->back = adapter;
-	adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
+	adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
 
 	hw->hw_addr = ioremap(pci_resource_start(pdev, 0),
 			      pci_resource_len(pdev, 0));
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index 581c659..307611a 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -91,7 +91,10 @@
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
-#define DEFAULT_DEBUG_LEVEL_SHIFT 3
+#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)
+static int debug = -1;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
 /* forward decls */
 static void ixgbevf_set_itr_msix(struct ixgbevf_q_vector *q_vector);
@@ -3367,7 +3370,7 @@
 	adapter->pdev = pdev;
 	hw = &adapter->hw;
 	hw->back = adapter;
-	adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
+	adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
 
 	/*
 	 * call save state here in standalone driver because it relies on
diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c
index f30db1c..bc58f1d 100644
--- a/drivers/net/ethernet/korina.c
+++ b/drivers/net/ethernet/korina.c
@@ -55,7 +55,6 @@
 #include <linux/crc32.h>
 
 #include <asm/bootinfo.h>
-#include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 75af1af..5e1ca0f 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -57,7 +57,6 @@
 #include <linux/types.h>
 #include <linux/inet_lro.h>
 #include <linux/slab.h>
-#include <asm/system.h>
 
 static char mv643xx_eth_driver_name[] = "mv643xx_eth";
 static char mv643xx_eth_driver_version[] = "1.4";
diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c
index 45a6333..efec6b6 100644
--- a/drivers/net/ethernet/marvell/pxa168_eth.c
+++ b/drivers/net/ethernet/marvell/pxa168_eth.c
@@ -43,7 +43,6 @@
 #include <linux/interrupt.h>
 #include <linux/types.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/cacheflush.h>
 #include <linux/pxa168_eth.h>
 
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 423a1a2..c9b504e 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -1767,13 +1767,14 @@
 
 	sky2_hw_up(sky2);
 
+	/* Enable interrupts from phy/mac for port */
+	imask = sky2_read32(hw, B0_IMSK);
+
 	if (hw->chip_id == CHIP_ID_YUKON_OPT ||
 	    hw->chip_id == CHIP_ID_YUKON_PRM ||
 	    hw->chip_id == CHIP_ID_YUKON_OP_2)
 		imask |= Y2_IS_PHY_QLNK;	/* enable PHY Quick Link */
 
-	/* Enable interrupts from phy/mac for port */
-	imask = sky2_read32(hw, B0_IMSK);
 	imask |= portirq_msk[port];
 	sky2_write32(hw, B0_IMSK, imask);
 	sky2_read32(hw, B0_IMSK);
@@ -2468,6 +2469,17 @@
 	return err;
 }
 
+static inline bool needs_copy(const struct rx_ring_info *re,
+			      unsigned length)
+{
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+	/* Some architectures need the IP header to be aligned */
+	if (!IS_ALIGNED(re->data_addr + ETH_HLEN, sizeof(u32)))
+		return true;
+#endif
+	return length < copybreak;
+}
+
 /* For small just reuse existing skb for next receive */
 static struct sk_buff *receive_copy(struct sky2_port *sky2,
 				    const struct rx_ring_info *re,
@@ -2598,7 +2610,7 @@
 		goto error;
 
 okay:
-	if (length < copybreak)
+	if (needs_copy(re, length))
 		skb = receive_copy(sky2, re, length);
 	else
 		skb = receive_new(sky2, re, length);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 9e2b911..d69fee4 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -83,8 +83,9 @@
 
 #define MLX4_EN_WATCHDOG_TIMEOUT	(15 * HZ)
 
-#define MLX4_EN_ALLOC_ORDER	2
-#define MLX4_EN_ALLOC_SIZE	(PAGE_SIZE << MLX4_EN_ALLOC_ORDER)
+/* Use the maximum between 16384 and a single page */
+#define MLX4_EN_ALLOC_SIZE	PAGE_ALIGN(16384)
+#define MLX4_EN_ALLOC_ORDER	get_order(MLX4_EN_ALLOC_SIZE)
 
 #define MLX4_EN_MAX_LRO_DESCRIPTORS	32
 
diff --git a/drivers/net/ethernet/micrel/ks8842.c b/drivers/net/ethernet/micrel/ks8842.c
index 0686b93..f84dd2d 100644
--- a/drivers/net/ethernet/micrel/ks8842.c
+++ b/drivers/net/ethernet/micrel/ks8842.c
@@ -458,7 +458,7 @@
 	if (sg_dma_len(&ctl->sg) % 4)
 		sg_dma_len(&ctl->sg) += 4 - sg_dma_len(&ctl->sg) % 4;
 
-	ctl->adesc = ctl->chan->device->device_prep_slave_sg(ctl->chan,
+	ctl->adesc = dmaengine_prep_slave_sg(ctl->chan,
 		&ctl->sg, 1, DMA_MEM_TO_DEV,
 		DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
 	if (!ctl->adesc)
@@ -570,7 +570,7 @@
 
 		sg_dma_len(sg) = DMA_BUFFER_SIZE;
 
-		ctl->adesc = ctl->chan->device->device_prep_slave_sg(ctl->chan,
+		ctl->adesc = dmaengine_prep_slave_sg(ctl->chan,
 			sg, 1, DMA_DEV_TO_MEM,
 			DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
 
diff --git a/drivers/net/ethernet/natsemi/jazzsonic.c b/drivers/net/ethernet/natsemi/jazzsonic.c
index 5b89fd3..95dd39f 100644
--- a/drivers/net/ethernet/natsemi/jazzsonic.c
+++ b/drivers/net/ethernet/natsemi/jazzsonic.c
@@ -38,7 +38,6 @@
 #include <linux/slab.h>
 
 #include <asm/bootinfo.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
 #include <asm/dma.h>
diff --git a/drivers/net/ethernet/natsemi/macsonic.c b/drivers/net/ethernet/natsemi/macsonic.c
index e640e23..b9680ba 100644
--- a/drivers/net/ethernet/natsemi/macsonic.c
+++ b/drivers/net/ethernet/natsemi/macsonic.c
@@ -53,7 +53,6 @@
 #include <linux/slab.h>
 
 #include <asm/bootinfo.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
 #include <asm/hwtest.h>
diff --git a/drivers/net/ethernet/natsemi/ns83820.c b/drivers/net/ethernet/natsemi/ns83820.c
index c24b46c..d52728b 100644
--- a/drivers/net/ethernet/natsemi/ns83820.c
+++ b/drivers/net/ethernet/natsemi/ns83820.c
@@ -121,7 +121,6 @@
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #define DRV_NAME "ns83820"
 
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index 22a8de0..6338ef8 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -81,7 +81,6 @@
 #include <linux/prefetch.h>
 #include <net/tcp.h>
 
-#include <asm/system.h>
 #include <asm/div64.h>
 #include <asm/irq.h>
 
diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c
index 8561dd2..aca1304 100644
--- a/drivers/net/ethernet/nvidia/forcedeth.c
+++ b/drivers/net/ethernet/nvidia/forcedeth.c
@@ -69,7 +69,6 @@
 #include <linux/io.h>
 
 #include <asm/irq.h>
-#include <asm/system.h>
 
 #define TX_WORK_PER_LOOP  64
 #define RX_WORK_PER_LOOP  64
diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c
index 6944424..6dfc26d 100644
--- a/drivers/net/ethernet/nxp/lpc_eth.c
+++ b/drivers/net/ethernet/nxp/lpc_eth.c
@@ -1441,7 +1441,7 @@
 	}
 #endif
 	if (!is_valid_ether_addr(ndev->dev_addr))
-		dev_hw_addr_random(ndev, ndev->dev_addr);
+		eth_hw_addr_random(ndev);
 
 	/* Reset the ethernet controller */
 	__lpc_eth_reset(pldat);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 2b5af22..385a4d5 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -36,8 +36,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 25
-#define QLCNIC_LINUX_VERSIONID  "5.0.26"
+#define _QLCNIC_LINUX_SUBVERSION 27
+#define QLCNIC_LINUX_VERSIONID  "5.0.27"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
 		 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 81bb1a6..75c32e8 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -1458,8 +1458,10 @@
 
 		if (netif_running(netdev)) {
 			err = qlcnic_attach(adapter);
-			if (!err)
+			if (!err) {
 				__qlcnic_up(adapter, netdev);
+				qlcnic_restore_indev_addr(netdev, NETDEV_UP);
+			}
 		}
 
 		netif_device_attach(netdev);
diff --git a/drivers/net/ethernet/realtek/atp.c b/drivers/net/ethernet/realtek/atp.c
index 46c1932..e02f04d 100644
--- a/drivers/net/ethernet/realtek/atp.c
+++ b/drivers/net/ethernet/realtek/atp.c
@@ -140,7 +140,6 @@
 #include <linux/delay.h>
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 27c358c..f545093 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -29,7 +29,6 @@
 #include <linux/pci-aspm.h>
 #include <linux/prefetch.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
@@ -5811,7 +5810,10 @@
 
 	rtl_pll_power_up(tp);
 
+	rtl_lock_work(tp);
+	napi_enable(&tp->napi);
 	set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
+	rtl_unlock_work(tp);
 
 	rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
 }
diff --git a/drivers/net/ethernet/renesas/Kconfig b/drivers/net/ethernet/renesas/Kconfig
index 9755b49..3fb2355 100644
--- a/drivers/net/ethernet/renesas/Kconfig
+++ b/drivers/net/ethernet/renesas/Kconfig
@@ -7,7 +7,8 @@
 	depends on SUPERH && \
 		(CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \
 		 CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \
-		 CPU_SUBTYPE_SH7724 || CPU_SUBTYPE_SH7757)
+		 CPU_SUBTYPE_SH7724 || CPU_SUBTYPE_SH7734 || \
+		 CPU_SUBTYPE_SH7757)
 	select CRC32
 	select NET_CORE
 	select MII
@@ -16,4 +17,4 @@
 	---help---
 	  Renesas SuperH Ethernet device driver.
 	  This driver supporting CPUs are:
-		- SH7710, SH7712, SH7763, SH7619, SH7724, and SH7757.
+		- SH7619, SH7710, SH7712, SH7724, SH7734, SH7763 and SH7757.
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 8615961..d63e09b 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -1,8 +1,8 @@
 /*
  *  SuperH Ethernet device driver
  *
- *  Copyright (C) 2006-2008 Nobuhiro Iwamatsu
- *  Copyright (C) 2008-2009 Renesas Solutions Corp.
+ *  Copyright (C) 2006-2012 Nobuhiro Iwamatsu
+ *  Copyright (C) 2008-2012 Renesas Solutions Corp.
  *
  *  This program is free software; you can redistribute it and/or modify it
  *  under the terms and conditions of the GNU General Public License,
@@ -38,6 +38,7 @@
 #include <linux/slab.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
+#include <linux/clk.h>
 #include <linux/sh_eth.h>
 
 #include "sh_eth.h"
@@ -279,8 +280,9 @@
 		return &sh_eth_my_cpu_data;
 }
 
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7734) || defined(CONFIG_CPU_SUBTYPE_SH7763)
 #define SH_ETH_HAS_TSU	1
+static void sh_eth_reset_hw_crc(struct net_device *ndev);
 static void sh_eth_chip_reset(struct net_device *ndev)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -314,6 +316,9 @@
 	sh_eth_write(ndev, 0x0, RDFAR);
 	sh_eth_write(ndev, 0x0, RDFXR);
 	sh_eth_write(ndev, 0x0, RDFFR);
+
+	/* Reset HW CRC register */
+	sh_eth_reset_hw_crc(ndev);
 }
 
 static void sh_eth_set_duplex(struct net_device *ndev)
@@ -370,8 +375,17 @@
 	.no_trimd	= 1,
 	.no_ade		= 1,
 	.tsu		= 1,
+#if defined(CONFIG_CPU_SUBTYPE_SH7734)
+	.hw_crc     = 1,
+#endif
 };
 
+static void sh_eth_reset_hw_crc(struct net_device *ndev)
+{
+	if (sh_eth_my_cpu_data.hw_crc)
+		sh_eth_write(ndev, 0x0, CSMR);
+}
+
 #elif defined(CONFIG_CPU_SUBTYPE_SH7619)
 #define SH_ETH_RESET_DEFAULT	1
 static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
@@ -790,7 +804,7 @@
 	/* all sh_eth int mask */
 	sh_eth_write(ndev, 0, EESIPR);
 
-#if defined(__LITTLE_ENDIAN__)
+#if defined(__LITTLE_ENDIAN)
 	if (mdp->cd->hw_swap)
 		sh_eth_write(ndev, EDMR_EL, EDMR);
 	else
diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h
index 57dc262..0fa14afc 100644
--- a/drivers/net/ethernet/renesas/sh_eth.h
+++ b/drivers/net/ethernet/renesas/sh_eth.h
@@ -1,8 +1,8 @@
 /*
  *  SuperH Ethernet device driver
  *
- *  Copyright (C) 2006-2008 Nobuhiro Iwamatsu
- *  Copyright (C) 2008-2011 Renesas Solutions Corp.
+ *  Copyright (C) 2006-2012 Nobuhiro Iwamatsu
+ *  Copyright (C) 2008-2012 Renesas Solutions Corp.
  *
  *  This program is free software; you can redistribute it and/or modify it
  *  under the terms and conditions of the GNU General Public License,
@@ -98,6 +98,8 @@
 	CEECR,
 	MAFCR,
 	RTRATE,
+	CSMR,
+	RMII_MII,
 
 	/* TSU Absolute address */
 	ARSTR,
@@ -172,6 +174,7 @@
 	[RMCR]	= 0x0458,
 	[RPADIR]	= 0x0460,
 	[FCFTR]	= 0x0468,
+	[CSMR] = 0x04E4,
 
 	[ECMR]	= 0x0500,
 	[ECSR]	= 0x0510,
@@ -200,6 +203,7 @@
 	[CERCR]	= 0x0768,
 	[CEECR]	= 0x0770,
 	[MAFCR]	= 0x0778,
+	[RMII_MII] =  0x0790,
 
 	[ARSTR]	= 0x0000,
 	[TSU_CTRST]	= 0x0004,
@@ -377,7 +381,7 @@
 /*
  * Register's bits
  */
-#ifdef CONFIG_CPU_SUBTYPE_SH7763
+#if defined(CONFIG_CPU_SUBTYPE_SH7734) || defined(CONFIG_CPU_SUBTYPE_SH7763)
 /* EDSR */
 enum EDSR_BIT {
 	EDSR_ENT = 0x01, EDSR_ENR = 0x02,
@@ -689,7 +693,7 @@
  */
 struct sh_eth_txdesc {
 	u32 status;		/* TD0 */
-#if defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if defined(__LITTLE_ENDIAN)
 	u16 pad0;		/* TD1 */
 	u16 buffer_length;	/* TD1 */
 #else
@@ -706,7 +710,7 @@
  */
 struct sh_eth_rxdesc {
 	u32 status;		/* RD0 */
-#if defined(CONFIG_CPU_LITTLE_ENDIAN)
+#if defined(__LITTLE_ENDIAN)
 	u16 frame_length;	/* RD1 */
 	u16 buffer_length;	/* RD1 */
 #else
@@ -751,6 +755,7 @@
 	unsigned rpadir:1;		/* E-DMAC have RPADIR */
 	unsigned no_trimd:1;		/* E-DMAC DO NOT have TRIMD */
 	unsigned no_ade:1;	/* E-DMAC DO NOT have ADE bit in EESR */
+	unsigned hw_crc:1;	/* E-DMAC have CSMR */
 };
 
 struct sh_eth_private {
diff --git a/drivers/net/ethernet/seeq/ether3.c b/drivers/net/ethernet/seeq/ether3.c
index 7b819bd..df808ac 100644
--- a/drivers/net/ethernet/seeq/ether3.c
+++ b/drivers/net/ethernet/seeq/ether3.c
@@ -64,7 +64,6 @@
 #include <linux/delay.h>
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 #include <asm/ecard.h>
 #include <asm/io.h>
 
diff --git a/drivers/net/ethernet/seeq/seeq8005.c b/drivers/net/ethernet/seeq/seeq8005.c
index 7989907..698edbb 100644
--- a/drivers/net/ethernet/seeq/seeq8005.c
+++ b/drivers/net/ethernet/seeq/seeq8005.c
@@ -47,7 +47,6 @@
 #include <linux/bitops.h>
 #include <linux/jiffies.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
diff --git a/drivers/net/ethernet/sfc/mtd.c b/drivers/net/ethernet/sfc/mtd.c
index 26b3c23..7581483 100644
--- a/drivers/net/ethernet/sfc/mtd.c
+++ b/drivers/net/ethernet/sfc/mtd.c
@@ -193,7 +193,7 @@
 		erase->state = MTD_ERASE_DONE;
 	} else {
 		erase->state = MTD_ERASE_FAILED;
-		erase->fail_addr = 0xffffffff;
+		erase->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
 	}
 	mtd_erase_callback(erase);
 	return rc;
@@ -263,10 +263,10 @@
 		part->mtd.owner = THIS_MODULE;
 		part->mtd.priv = efx_mtd;
 		part->mtd.name = part->name;
-		part->mtd.erase = efx_mtd_erase;
-		part->mtd.read = efx_mtd->ops->read;
-		part->mtd.write = efx_mtd->ops->write;
-		part->mtd.sync = efx_mtd_sync;
+		part->mtd._erase = efx_mtd_erase;
+		part->mtd._read = efx_mtd->ops->read;
+		part->mtd._write = efx_mtd->ops->write;
+		part->mtd._sync = efx_mtd_sync;
 
 		if (mtd_device_register(&part->mtd, NULL, 0))
 			goto fail;
diff --git a/drivers/net/ethernet/smsc/smc91c92_cs.c b/drivers/net/ethernet/smsc/smc91c92_cs.c
index d12e48a..04393b5 100644
--- a/drivers/net/ethernet/smsc/smc91c92_cs.c
+++ b/drivers/net/ethernet/smsc/smc91c92_cs.c
@@ -53,7 +53,6 @@
 #include <pcmcia/ss.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 /*====================================================================*/
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index 1dc4fad..fee4493 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -2280,7 +2280,7 @@
 	if (ret)
 		goto out_release_io;
 #if defined(CONFIG_SA1100_ASSABET)
-	NCR_0 |= NCR_ENET_OSC_EN;
+	neponset_ncr_set(NCR_ENET_OSC_EN);
 #endif
 	platform_set_drvdata(pdev, ndev);
 	ret = smc_enable_device(pdev);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index e85ffbd..48d56da 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1737,10 +1737,12 @@
 	struct mac_device_info *mac;
 
 	/* Identify the MAC HW device */
-	if (priv->plat->has_gmac)
+	if (priv->plat->has_gmac) {
+		priv->dev->priv_flags |= IFF_UNICAST_FLT;
 		mac = dwmac1000_setup(priv->ioaddr);
-	else
+	} else {
 		mac = dwmac100_setup(priv->ioaddr);
+	}
 	if (!mac)
 		return -ENOMEM;
 
diff --git a/drivers/net/ethernet/sun/cassini.c b/drivers/net/ethernet/sun/cassini.c
index 3c22955..ce4df61 100644
--- a/drivers/net/ethernet/sun/cassini.c
+++ b/drivers/net/ethernet/sun/cassini.c
@@ -99,7 +99,6 @@
 #include <net/checksum.h>
 
 #include <linux/atomic.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
diff --git a/drivers/net/ethernet/sun/sunbmac.c b/drivers/net/ethernet/sun/sunbmac.c
index f359863..2a83fc5 100644
--- a/drivers/net/ethernet/sun/sunbmac.c
+++ b/drivers/net/ethernet/sun/sunbmac.c
@@ -35,7 +35,6 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 
 #include "sunbmac.h"
 
diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c
index ba04159..558409f 100644
--- a/drivers/net/ethernet/sun/sungem.c
+++ b/drivers/net/ethernet/sun/sungem.c
@@ -41,7 +41,6 @@
 #include <linux/mm.h>
 #include <linux/gfp.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c
index 8b627e2f..b95e7e6 100644
--- a/drivers/net/ethernet/sun/sunhme.c
+++ b/drivers/net/ethernet/sun/sunhme.c
@@ -36,7 +36,6 @@
 #include <linux/bitops.h>
 #include <linux/dma-mapping.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
diff --git a/drivers/net/ethernet/sun/sunqe.c b/drivers/net/ethernet/sun/sunqe.c
index 139d6b4..7d4a040 100644
--- a/drivers/net/ethernet/sun/sunqe.c
+++ b/drivers/net/ethernet/sun/sunqe.c
@@ -28,7 +28,6 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c
index 92a037a..38e3ae9 100644
--- a/drivers/net/ethernet/sun/sunvnet.c
+++ b/drivers/net/ethernet/sun/sunvnet.c
@@ -1259,10 +1259,7 @@
 	.id_table	= vnet_port_match,
 	.probe		= vnet_port_probe,
 	.remove		= vnet_port_remove,
-	.driver		= {
-		.name	= "vnet_port",
-		.owner	= THIS_MODULE,
-	}
+	.name		= "vnet_port",
 };
 
 static int __init vnet_init(void)
diff --git a/drivers/net/ethernet/tundra/tsi108_eth.c b/drivers/net/ethernet/tundra/tsi108_eth.c
index 840e0e9..277c93e 100644
--- a/drivers/net/ethernet/tundra/tsi108_eth.c
+++ b/drivers/net/ethernet/tundra/tsi108_eth.c
@@ -50,7 +50,6 @@
 #include <linux/platform_device.h>
 #include <linux/gfp.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/tsi108.h>
 
diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c
index 39b8cf3..fcfa01f 100644
--- a/drivers/net/ethernet/via/via-rhine.c
+++ b/drivers/net/ethernet/via/via-rhine.c
@@ -503,30 +503,32 @@
 static int rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid);
 static void rhine_restart_tx(struct net_device *dev);
 
-static void rhine_wait_bit(struct rhine_private *rp, u8 reg, u8 mask, bool high)
+static void rhine_wait_bit(struct rhine_private *rp, u8 reg, u8 mask, bool low)
 {
 	void __iomem *ioaddr = rp->base;
 	int i;
 
 	for (i = 0; i < 1024; i++) {
-		if (high ^ !!(ioread8(ioaddr + reg) & mask))
+		bool has_mask_bits = !!(ioread8(ioaddr + reg) & mask);
+
+		if (low ^ has_mask_bits)
 			break;
 		udelay(10);
 	}
 	if (i > 64) {
 		netif_dbg(rp, hw, rp->dev, "%s bit wait (%02x/%02x) cycle "
-			  "count: %04d\n", high ? "high" : "low", reg, mask, i);
+			  "count: %04d\n", low ? "low" : "high", reg, mask, i);
 	}
 }
 
 static void rhine_wait_bit_high(struct rhine_private *rp, u8 reg, u8 mask)
 {
-	rhine_wait_bit(rp, reg, mask, true);
+	rhine_wait_bit(rp, reg, mask, false);
 }
 
 static void rhine_wait_bit_low(struct rhine_private *rp, u8 reg, u8 mask)
 {
-	rhine_wait_bit(rp, reg, mask, false);
+	rhine_wait_bit(rp, reg, mask, true);
 }
 
 static u32 rhine_get_events(struct rhine_private *rp)
diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c
index 5c69c6f..94a1f94 100644
--- a/drivers/net/ethernet/xircom/xirc2ps_cs.c
+++ b/drivers/net/ethernet/xircom/xirc2ps_cs.c
@@ -89,7 +89,6 @@
 #include <pcmcia/ciscode.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 #ifndef MANFID_COMPAQ
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 2a5a34d..64783a0 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -13,7 +13,6 @@
  */
 
 #include <linux/module.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/bitops.h>
 #include <linux/string.h>
diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c
index f1aea0c..acb6369 100644
--- a/drivers/net/hamradio/baycom_par.c
+++ b/drivers/net/hamradio/baycom_par.c
@@ -86,7 +86,6 @@
 #include <linux/bitops.h>
 #include <linux/jiffies.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 /* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 18d8aff..76d5477 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -69,7 +69,6 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index bc02968..aed1a61 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -17,7 +17,6 @@
  * Copyright (C) 2004, 05 Thomas Osterried DL9SAU <thomas@x-berg.in-berlin.de>
  */
 #include <linux/module.h>
-#include <asm/system.h>
 #include <linux/bitops.h>
 #include <asm/uaccess.h>
 #include <linux/crc16.h>
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 3365581..efc6c97 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -177,7 +177,6 @@
 #include <net/ax25.h>
 
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 6963277..5a6412e 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -52,7 +52,6 @@
 #include <linux/bitops.h>
 #include <linux/random.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/firmware.h>
diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c
index 2a51363..168c8f4 100644
--- a/drivers/net/hippi/rrunner.c
+++ b/drivers/net/hippi/rrunner.c
@@ -43,7 +43,6 @@
 #include <linux/slab.h>
 #include <net/sock.h>
 
-#include <asm/system.h>
 #include <asm/cache.h>
 #include <asm/byteorder.h>
 #include <asm/io.h>
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index e535137..4680478 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -356,7 +356,7 @@
 
 config SA1100_FIR
 	tristate "SA1100 Internal IR"
-	depends on ARCH_SA1100 && IRDA
+	depends on ARCH_SA1100 && IRDA && DMA_SA11X0
 
 config VIA_FIR
 	tristate "VIA VT8231/VT1211 SIR/MIR/FIR"
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 617a446..4351296 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -156,7 +156,6 @@
 #include <linux/pci.h>
 #include <linux/rtnetlink.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include <net/irda/wrapper.h>
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index da27050..e250675 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -15,7 +15,7 @@
  *  This driver takes one kernel command line parameter, sa1100ir=, with
  *  the following options:
  *	max_rate:baudrate	- set the maximum baud rate
- *	power_leve:level	- set the transmitter power level
+ *	power_level:level	- set the transmitter power level
  *	tx_lpm:0|1		- set transmit low power mode
  */
 #include <linux/module.h>
@@ -30,13 +30,13 @@
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/sa11x0-dma.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/wrapper.h>
 #include <net/irda/irda_device.h>
 
-#include <asm/irq.h>
-#include <mach/dma.h>
 #include <mach/hardware.h>
 #include <asm/mach/irda.h>
 
@@ -44,8 +44,15 @@
 static int tx_lpm;
 static int max_rate = 4000000;
 
+struct sa1100_buf {
+	struct device		*dev;
+	struct sk_buff		*skb;
+	struct scatterlist	sg;
+	struct dma_chan		*chan;
+	dma_cookie_t		cookie;
+};
+
 struct sa1100_irda {
-	unsigned char		hscr0;
 	unsigned char		utcr4;
 	unsigned char		power;
 	unsigned char		open;
@@ -53,12 +60,8 @@
 	int			speed;
 	int			newspeed;
 
-	struct sk_buff		*txskb;
-	struct sk_buff		*rxskb;
-	dma_addr_t		txbuf_dma;
-	dma_addr_t		rxbuf_dma;
-	dma_regs_t		*txdma;
-	dma_regs_t		*rxdma;
+	struct sa1100_buf	dma_rx;
+	struct sa1100_buf	dma_tx;
 
 	struct device		*dev;
 	struct irda_platform_data *pdata;
@@ -67,23 +70,103 @@
 
 	iobuff_t		tx_buff;
 	iobuff_t		rx_buff;
+
+	int (*tx_start)(struct sk_buff *, struct net_device *, struct sa1100_irda *);
+	irqreturn_t (*irq)(struct net_device *, struct sa1100_irda *);
 };
 
+static int sa1100_irda_set_speed(struct sa1100_irda *, int);
+
 #define IS_FIR(si)		((si)->speed >= 4000000)
 
 #define HPSIR_MAX_RXLEN		2047
 
+static struct dma_slave_config sa1100_irda_sir_tx = {
+	.direction	= DMA_TO_DEVICE,
+	.dst_addr	= __PREG(Ser2UTDR),
+	.dst_addr_width	= DMA_SLAVE_BUSWIDTH_1_BYTE,
+	.dst_maxburst	= 4,
+};
+
+static struct dma_slave_config sa1100_irda_fir_rx = {
+	.direction	= DMA_FROM_DEVICE,
+	.src_addr	= __PREG(Ser2HSDR),
+	.src_addr_width	= DMA_SLAVE_BUSWIDTH_1_BYTE,
+	.src_maxburst	= 8,
+};
+
+static struct dma_slave_config sa1100_irda_fir_tx = {
+	.direction	= DMA_TO_DEVICE,
+	.dst_addr	= __PREG(Ser2HSDR),
+	.dst_addr_width	= DMA_SLAVE_BUSWIDTH_1_BYTE,
+	.dst_maxburst	= 8,
+};
+
+static unsigned sa1100_irda_dma_xferred(struct sa1100_buf *buf)
+{
+	struct dma_chan *chan = buf->chan;
+	struct dma_tx_state state;
+	enum dma_status status;
+
+	status = chan->device->device_tx_status(chan, buf->cookie, &state);
+	if (status != DMA_PAUSED)
+		return 0;
+
+	return sg_dma_len(&buf->sg) - state.residue;
+}
+
+static int sa1100_irda_dma_request(struct device *dev, struct sa1100_buf *buf,
+	const char *name, struct dma_slave_config *cfg)
+{
+	dma_cap_mask_t m;
+	int ret;
+
+	dma_cap_zero(m);
+	dma_cap_set(DMA_SLAVE, m);
+
+	buf->chan = dma_request_channel(m, sa11x0_dma_filter_fn, (void *)name);
+	if (!buf->chan) {
+		dev_err(dev, "unable to request DMA channel for %s\n",
+			name);
+		return -ENOENT;
+	}
+
+	ret = dmaengine_slave_config(buf->chan, cfg);
+	if (ret)
+		dev_warn(dev, "DMA slave_config for %s returned %d\n",
+			name, ret);
+
+	buf->dev = buf->chan->device->dev;
+
+	return 0;
+}
+
+static void sa1100_irda_dma_start(struct sa1100_buf *buf,
+	enum dma_transfer_direction dir, dma_async_tx_callback cb, void *cb_p)
+{
+	struct dma_async_tx_descriptor *desc;
+	struct dma_chan *chan = buf->chan;
+
+	desc = dmaengine_prep_slave_sg(chan, &buf->sg, 1, dir,
+			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (desc) {
+		desc->callback = cb;
+		desc->callback_param = cb_p;
+		buf->cookie = dmaengine_submit(desc);
+		dma_async_issue_pending(chan);
+	}
+}
+
 /*
  * Allocate and map the receive buffer, unless it is already allocated.
  */
 static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
 {
-	if (si->rxskb)
+	if (si->dma_rx.skb)
 		return 0;
 
-	si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
-
-	if (!si->rxskb) {
+	si->dma_rx.skb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
+	if (!si->dma_rx.skb) {
 		printk(KERN_ERR "sa1100_ir: out of memory for RX SKB\n");
 		return -ENOMEM;
 	}
@@ -92,11 +175,14 @@
 	 * Align any IP headers that may be contained
 	 * within the frame.
 	 */
-	skb_reserve(si->rxskb, 1);
+	skb_reserve(si->dma_rx.skb, 1);
 
-	si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data,
-					HPSIR_MAX_RXLEN,
-					DMA_FROM_DEVICE);
+	sg_set_buf(&si->dma_rx.sg, si->dma_rx.skb->data, HPSIR_MAX_RXLEN);
+	if (dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE) == 0) {
+		dev_kfree_skb_any(si->dma_rx.skb);
+		return -ENOMEM;
+	}
+
 	return 0;
 }
 
@@ -106,7 +192,7 @@
  */
 static void sa1100_irda_rx_dma_start(struct sa1100_irda *si)
 {
-	if (!si->rxskb) {
+	if (!si->dma_rx.skb) {
 		printk(KERN_ERR "sa1100_ir: rx buffer went missing\n");
 		return;
 	}
@@ -114,14 +200,343 @@
 	/*
 	 * First empty receive FIFO
 	 */
-	Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
+	Ser2HSCR0 = HSCR0_HSSP;
 
 	/*
 	 * Enable the DMA, receiver and receive interrupt.
 	 */
-	sa1100_clear_dma(si->rxdma);
-	sa1100_start_dma(si->rxdma, si->rxbuf_dma, HPSIR_MAX_RXLEN);
-	Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_RXE;
+	dmaengine_terminate_all(si->dma_rx.chan);
+	sa1100_irda_dma_start(&si->dma_rx, DMA_DEV_TO_MEM, NULL, NULL);
+
+	Ser2HSCR0 = HSCR0_HSSP | HSCR0_RXE;
+}
+
+static void sa1100_irda_check_speed(struct sa1100_irda *si)
+{
+	if (si->newspeed) {
+		sa1100_irda_set_speed(si, si->newspeed);
+		si->newspeed = 0;
+	}
+}
+
+/*
+ * HP-SIR format support.
+ */
+static void sa1100_irda_sirtxdma_irq(void *id)
+{
+	struct net_device *dev = id;
+	struct sa1100_irda *si = netdev_priv(dev);
+
+	dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE);
+	dev_kfree_skb(si->dma_tx.skb);
+	si->dma_tx.skb = NULL;
+
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += sg_dma_len(&si->dma_tx.sg);
+
+	/* We need to ensure that the transmitter has finished. */
+	do
+		rmb();
+	while (Ser2UTSR1 & UTSR1_TBY);
+
+	/*
+	 * Ok, we've finished transmitting.  Now enable the receiver.
+	 * Sometimes we get a receive IRQ immediately after a transmit...
+	 */
+	Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
+	Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
+
+	sa1100_irda_check_speed(si);
+
+	/* I'm hungry! */
+	netif_wake_queue(dev);
+}
+
+static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev,
+	struct sa1100_irda *si)
+{
+	si->tx_buff.data = si->tx_buff.head;
+	si->tx_buff.len  = async_wrap_skb(skb, si->tx_buff.data,
+					  si->tx_buff.truesize);
+
+	si->dma_tx.skb = skb;
+	sg_set_buf(&si->dma_tx.sg, si->tx_buff.data, si->tx_buff.len);
+	if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) {
+		si->dma_tx.skb = NULL;
+		netif_wake_queue(dev);
+		dev->stats.tx_dropped++;
+		return NETDEV_TX_OK;
+	}
+
+	sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_sirtxdma_irq, dev);
+
+	/*
+	 * The mean turn-around time is enforced by XBOF padding,
+	 * so we don't have to do anything special here.
+	 */
+	Ser2UTCR3 = UTCR3_TXE;
+
+	return NETDEV_TX_OK;
+}
+
+static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_irda *si)
+{
+	int status;
+
+	status = Ser2UTSR0;
+
+	/*
+	 * Deal with any receive errors first.  The bytes in error may be
+	 * the only bytes in the receive FIFO, so we do this first.
+	 */
+	while (status & UTSR0_EIF) {
+		int stat, data;
+
+		stat = Ser2UTSR1;
+		data = Ser2UTDR;
+
+		if (stat & (UTSR1_FRE | UTSR1_ROR)) {
+			dev->stats.rx_errors++;
+			if (stat & UTSR1_FRE)
+				dev->stats.rx_frame_errors++;
+			if (stat & UTSR1_ROR)
+				dev->stats.rx_fifo_errors++;
+		} else
+			async_unwrap_char(dev, &dev->stats, &si->rx_buff, data);
+
+		status = Ser2UTSR0;
+	}
+
+	/*
+	 * We must clear certain bits.
+	 */
+	Ser2UTSR0 = status & (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+
+	if (status & UTSR0_RFS) {
+		/*
+		 * There are at least 4 bytes in the FIFO.  Read 3 bytes
+		 * and leave the rest to the block below.
+		 */
+		async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
+		async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
+		async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
+	}
+
+	if (status & (UTSR0_RFS | UTSR0_RID)) {
+		/*
+		 * Fifo contains more than 1 character.
+		 */
+		do {
+			async_unwrap_char(dev, &dev->stats, &si->rx_buff,
+					  Ser2UTDR);
+		} while (Ser2UTSR1 & UTSR1_RNE);
+
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * FIR format support.
+ */
+static void sa1100_irda_firtxdma_irq(void *id)
+{
+	struct net_device *dev = id;
+	struct sa1100_irda *si = netdev_priv(dev);
+	struct sk_buff *skb;
+
+	/*
+	 * Wait for the transmission to complete.  Unfortunately,
+	 * the hardware doesn't give us an interrupt to indicate
+	 * "end of frame".
+	 */
+	do
+		rmb();
+	while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY);
+
+	/*
+	 * Clear the transmit underrun bit.
+	 */
+	Ser2HSSR0 = HSSR0_TUR;
+
+	/*
+	 * Do we need to change speed?  Note that we're lazy
+	 * here - we don't free the old dma_rx.skb.  We don't need
+	 * to allocate a buffer either.
+	 */
+	sa1100_irda_check_speed(si);
+
+	/*
+	 * Start reception.  This disables the transmitter for
+	 * us.  This will be using the existing RX buffer.
+	 */
+	sa1100_irda_rx_dma_start(si);
+
+	/* Account and free the packet. */
+	skb = si->dma_tx.skb;
+	if (skb) {
+		dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1,
+			     DMA_TO_DEVICE);
+		dev->stats.tx_packets ++;
+		dev->stats.tx_bytes += skb->len;
+		dev_kfree_skb_irq(skb);
+		si->dma_tx.skb = NULL;
+	}
+
+	/*
+	 * Make sure that the TX queue is available for sending
+	 * (for retries).  TX has priority over RX at all times.
+	 */
+	netif_wake_queue(dev);
+}
+
+static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev,
+	struct sa1100_irda *si)
+{
+	int mtt = irda_get_mtt(skb);
+
+	si->dma_tx.skb = skb;
+	sg_set_buf(&si->dma_tx.sg, skb->data, skb->len);
+	if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) {
+		si->dma_tx.skb = NULL;
+		netif_wake_queue(dev);
+		dev->stats.tx_dropped++;
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_firtxdma_irq, dev);
+
+	/*
+	 * If we have a mean turn-around time, impose the specified
+	 * specified delay.  We could shorten this by timing from
+	 * the point we received the packet.
+	 */
+	if (mtt)
+		udelay(mtt);
+
+	Ser2HSCR0 = HSCR0_HSSP | HSCR0_TXE;
+
+	return NETDEV_TX_OK;
+}
+
+static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev)
+{
+	struct sk_buff *skb = si->dma_rx.skb;
+	unsigned int len, stat, data;
+
+	if (!skb) {
+		printk(KERN_ERR "sa1100_ir: SKB is NULL!\n");
+		return;
+	}
+
+	/*
+	 * Get the current data position.
+	 */
+	len = sa1100_irda_dma_xferred(&si->dma_rx);
+	if (len > HPSIR_MAX_RXLEN)
+		len = HPSIR_MAX_RXLEN;
+	dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
+
+	do {
+		/*
+		 * Read Status, and then Data.
+		 */
+		stat = Ser2HSSR1;
+		rmb();
+		data = Ser2HSDR;
+
+		if (stat & (HSSR1_CRE | HSSR1_ROR)) {
+			dev->stats.rx_errors++;
+			if (stat & HSSR1_CRE)
+				dev->stats.rx_crc_errors++;
+			if (stat & HSSR1_ROR)
+				dev->stats.rx_frame_errors++;
+		} else
+			skb->data[len++] = data;
+
+		/*
+		 * If we hit the end of frame, there's
+		 * no point in continuing.
+		 */
+		if (stat & HSSR1_EOF)
+			break;
+	} while (Ser2HSSR0 & HSSR0_EIF);
+
+	if (stat & HSSR1_EOF) {
+		si->dma_rx.skb = NULL;
+
+		skb_put(skb, len);
+		skb->dev = dev;
+		skb_reset_mac_header(skb);
+		skb->protocol = htons(ETH_P_IRDA);
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += len;
+
+		/*
+		 * Before we pass the buffer up, allocate a new one.
+		 */
+		sa1100_irda_rx_alloc(si);
+
+		netif_rx(skb);
+	} else {
+		/*
+		 * Remap the buffer - it was previously mapped, and we
+		 * hope that this succeeds.
+		 */
+		dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
+	}
+}
+
+/*
+ * We only have to handle RX events here; transmit events go via the TX
+ * DMA handler. We disable RX, process, and the restart RX.
+ */
+static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_irda *si)
+{
+	/*
+	 * Stop RX DMA
+	 */
+	dmaengine_pause(si->dma_rx.chan);
+
+	/*
+	 * Framing error - we throw away the packet completely.
+	 * Clearing RXE flushes the error conditions and data
+	 * from the fifo.
+	 */
+	if (Ser2HSSR0 & (HSSR0_FRE | HSSR0_RAB)) {
+		dev->stats.rx_errors++;
+
+		if (Ser2HSSR0 & HSSR0_FRE)
+			dev->stats.rx_frame_errors++;
+
+		/*
+		 * Clear out the DMA...
+		 */
+		Ser2HSCR0 = HSCR0_HSSP;
+
+		/*
+		 * Clear selected status bits now, so we
+		 * don't miss them next time around.
+		 */
+		Ser2HSSR0 = HSSR0_FRE | HSSR0_RAB;
+	}
+
+	/*
+	 * Deal with any receive errors.  The any of the lowest
+	 * 8 bytes in the FIFO may contain an error.  We must read
+	 * them one by one.  The "error" could even be the end of
+	 * packet!
+	 */
+	if (Ser2HSSR0 & HSSR0_EIF)
+		sa1100_irda_fir_error(si, dev);
+
+	/*
+	 * No matter what happens, we must restart reception.
+	 */
+	sa1100_irda_rx_dma_start(si);
+
+	return IRQ_HANDLED;
 }
 
 /*
@@ -137,11 +552,12 @@
 	case 57600:	case 115200:
 		brd = 3686400 / (16 * speed) - 1;
 
-		/*
-		 * Stop the receive DMA.
-		 */
-		if (IS_FIR(si))
-			sa1100_stop_dma(si->rxdma);
+		/* Stop the receive DMA, and configure transmit. */
+		if (IS_FIR(si)) {
+			dmaengine_terminate_all(si->dma_rx.chan);
+			dmaengine_slave_config(si->dma_tx.chan,
+						&sa1100_irda_sir_tx);
+		}
 
 		local_irq_save(flags);
 
@@ -161,21 +577,27 @@
 			si->pdata->set_speed(si->dev, speed);
 
 		si->speed = speed;
+		si->tx_start = sa1100_irda_sir_tx_start;
+		si->irq = sa1100_irda_sir_irq;
 
 		local_irq_restore(flags);
 		ret = 0;
 		break;
 
 	case 4000000:
+		if (!IS_FIR(si))
+			dmaengine_slave_config(si->dma_tx.chan,
+						&sa1100_irda_fir_tx);
+
 		local_irq_save(flags);
 
-		si->hscr0 = 0;
-
 		Ser2HSSR0 = 0xff;
-		Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
+		Ser2HSCR0 = HSCR0_HSSP;
 		Ser2UTCR3 = 0;
 
 		si->speed = speed;
+		si->tx_start = sa1100_irda_fir_tx_start;
+		si->irq = sa1100_irda_fir_irq;
 
 		if (si->pdata->set_speed)
 			si->pdata->set_speed(si->dev, speed);
@@ -225,6 +647,86 @@
 	return ret;
 }
 
+static irqreturn_t sa1100_irda_irq(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct sa1100_irda *si = netdev_priv(dev);
+
+	return si->irq(dev, si);
+}
+
+static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct sa1100_irda *si = netdev_priv(dev);
+	int speed = irda_get_next_speed(skb);
+
+	/*
+	 * Does this packet contain a request to change the interface
+	 * speed?  If so, remember it until we complete the transmission
+	 * of this frame.
+	 */
+	if (speed != si->speed && speed != -1)
+		si->newspeed = speed;
+
+	/* If this is an empty frame, we can bypass a lot. */
+	if (skb->len == 0) {
+		sa1100_irda_check_speed(si);
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	netif_stop_queue(dev);
+
+	/* We must not already have a skb to transmit... */
+	BUG_ON(si->dma_tx.skb);
+
+	return si->tx_start(skb, dev, si);
+}
+
+static int
+sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
+{
+	struct if_irda_req *rq = (struct if_irda_req *)ifreq;
+	struct sa1100_irda *si = netdev_priv(dev);
+	int ret = -EOPNOTSUPP;
+
+	switch (cmd) {
+	case SIOCSBANDWIDTH:
+		if (capable(CAP_NET_ADMIN)) {
+			/*
+			 * We are unable to set the speed if the
+			 * device is not running.
+			 */
+			if (si->open) {
+				ret = sa1100_irda_set_speed(si,
+						rq->ifr_baudrate);
+			} else {
+				printk("sa1100_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n");
+				ret = 0;
+			}
+		}
+		break;
+
+	case SIOCSMEDIABUSY:
+		ret = -EPERM;
+		if (capable(CAP_NET_ADMIN)) {
+			irda_device_set_media_busy(dev, TRUE);
+			ret = 0;
+		}
+		break;
+
+	case SIOCGRECEIVING:
+		rq->ifr_receiving = IS_FIR(si) ? 0
+					: si->rx_buff.state != OUTSIDE_FRAME;
+		break;
+
+	default:
+		break;
+	}
+		
+	return ret;
+}
+
 static int sa1100_irda_startup(struct sa1100_irda *si)
 {
 	int ret;
@@ -277,8 +779,8 @@
 	/*
 	 * Stop all DMA activity.
 	 */
-	sa1100_stop_dma(si->rxdma);
-	sa1100_stop_dma(si->txdma);
+	dmaengine_terminate_all(si->dma_rx.chan);
+	dmaengine_terminate_all(si->dma_tx.chan);
 
 	/* Disable the port. */
 	Ser2UTCR3 = 0;
@@ -288,480 +790,6 @@
 		si->pdata->shutdown(si->dev);
 }
 
-#ifdef CONFIG_PM
-/*
- * Suspend the IrDA interface.
- */
-static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state)
-{
-	struct net_device *dev = platform_get_drvdata(pdev);
-	struct sa1100_irda *si;
-
-	if (!dev)
-		return 0;
-
-	si = netdev_priv(dev);
-	if (si->open) {
-		/*
-		 * Stop the transmit queue
-		 */
-		netif_device_detach(dev);
-		disable_irq(dev->irq);
-		sa1100_irda_shutdown(si);
-		__sa1100_irda_set_power(si, 0);
-	}
-
-	return 0;
-}
-
-/*
- * Resume the IrDA interface.
- */
-static int sa1100_irda_resume(struct platform_device *pdev)
-{
-	struct net_device *dev = platform_get_drvdata(pdev);
-	struct sa1100_irda *si;
-
-	if (!dev)
-		return 0;
-
-	si = netdev_priv(dev);
-	if (si->open) {
-		/*
-		 * If we missed a speed change, initialise at the new speed
-		 * directly.  It is debatable whether this is actually
-		 * required, but in the interests of continuing from where
-		 * we left off it is desirable.  The converse argument is
-		 * that we should re-negotiate at 9600 baud again.
-		 */
-		if (si->newspeed) {
-			si->speed = si->newspeed;
-			si->newspeed = 0;
-		}
-
-		sa1100_irda_startup(si);
-		__sa1100_irda_set_power(si, si->power);
-		enable_irq(dev->irq);
-
-		/*
-		 * This automatically wakes up the queue
-		 */
-		netif_device_attach(dev);
-	}
-
-	return 0;
-}
-#else
-#define sa1100_irda_suspend	NULL
-#define sa1100_irda_resume	NULL
-#endif
-
-/*
- * HP-SIR format interrupt service routines.
- */
-static void sa1100_irda_hpsir_irq(struct net_device *dev)
-{
-	struct sa1100_irda *si = netdev_priv(dev);
-	int status;
-
-	status = Ser2UTSR0;
-
-	/*
-	 * Deal with any receive errors first.  The bytes in error may be
-	 * the only bytes in the receive FIFO, so we do this first.
-	 */
-	while (status & UTSR0_EIF) {
-		int stat, data;
-
-		stat = Ser2UTSR1;
-		data = Ser2UTDR;
-
-		if (stat & (UTSR1_FRE | UTSR1_ROR)) {
-			dev->stats.rx_errors++;
-			if (stat & UTSR1_FRE)
-				dev->stats.rx_frame_errors++;
-			if (stat & UTSR1_ROR)
-				dev->stats.rx_fifo_errors++;
-		} else
-			async_unwrap_char(dev, &dev->stats, &si->rx_buff, data);
-
-		status = Ser2UTSR0;
-	}
-
-	/*
-	 * We must clear certain bits.
-	 */
-	Ser2UTSR0 = status & (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
-
-	if (status & UTSR0_RFS) {
-		/*
-		 * There are at least 4 bytes in the FIFO.  Read 3 bytes
-		 * and leave the rest to the block below.
-		 */
-		async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
-		async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
-		async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
-	}
-
-	if (status & (UTSR0_RFS | UTSR0_RID)) {
-		/*
-		 * Fifo contains more than 1 character.
-		 */
-		do {
-			async_unwrap_char(dev, &dev->stats, &si->rx_buff,
-					  Ser2UTDR);
-		} while (Ser2UTSR1 & UTSR1_RNE);
-
-	}
-
-	if (status & UTSR0_TFS && si->tx_buff.len) {
-		/*
-		 * Transmitter FIFO is not full
-		 */
-		do {
-			Ser2UTDR = *si->tx_buff.data++;
-			si->tx_buff.len -= 1;
-		} while (Ser2UTSR1 & UTSR1_TNF && si->tx_buff.len);
-
-		if (si->tx_buff.len == 0) {
-			dev->stats.tx_packets++;
-			dev->stats.tx_bytes += si->tx_buff.data -
-					      si->tx_buff.head;
-
-			/*
-			 * We need to ensure that the transmitter has
-			 * finished.
-			 */
-			do
-				rmb();
-			while (Ser2UTSR1 & UTSR1_TBY);
-
-			/*
-			 * Ok, we've finished transmitting.  Now enable
-			 * the receiver.  Sometimes we get a receive IRQ
-			 * immediately after a transmit...
-			 */
-			Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
-			Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
-
-			if (si->newspeed) {
-				sa1100_irda_set_speed(si, si->newspeed);
-				si->newspeed = 0;
-			}
-
-			/* I'm hungry! */
-			netif_wake_queue(dev);
-		}
-	}
-}
-
-static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev)
-{
-	struct sk_buff *skb = si->rxskb;
-	dma_addr_t dma_addr;
-	unsigned int len, stat, data;
-
-	if (!skb) {
-		printk(KERN_ERR "sa1100_ir: SKB is NULL!\n");
-		return;
-	}
-
-	/*
-	 * Get the current data position.
-	 */
-	dma_addr = sa1100_get_dma_pos(si->rxdma);
-	len = dma_addr - si->rxbuf_dma;
-	if (len > HPSIR_MAX_RXLEN)
-		len = HPSIR_MAX_RXLEN;
-	dma_unmap_single(si->dev, si->rxbuf_dma, len, DMA_FROM_DEVICE);
-
-	do {
-		/*
-		 * Read Status, and then Data.
-		 */
-		stat = Ser2HSSR1;
-		rmb();
-		data = Ser2HSDR;
-
-		if (stat & (HSSR1_CRE | HSSR1_ROR)) {
-			dev->stats.rx_errors++;
-			if (stat & HSSR1_CRE)
-				dev->stats.rx_crc_errors++;
-			if (stat & HSSR1_ROR)
-				dev->stats.rx_frame_errors++;
-		} else
-			skb->data[len++] = data;
-
-		/*
-		 * If we hit the end of frame, there's
-		 * no point in continuing.
-		 */
-		if (stat & HSSR1_EOF)
-			break;
-	} while (Ser2HSSR0 & HSSR0_EIF);
-
-	if (stat & HSSR1_EOF) {
-		si->rxskb = NULL;
-
-		skb_put(skb, len);
-		skb->dev = dev;
-		skb_reset_mac_header(skb);
-		skb->protocol = htons(ETH_P_IRDA);
-		dev->stats.rx_packets++;
-		dev->stats.rx_bytes += len;
-
-		/*
-		 * Before we pass the buffer up, allocate a new one.
-		 */
-		sa1100_irda_rx_alloc(si);
-
-		netif_rx(skb);
-	} else {
-		/*
-		 * Remap the buffer.
-		 */
-		si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data,
-						HPSIR_MAX_RXLEN,
-						DMA_FROM_DEVICE);
-	}
-}
-
-/*
- * FIR format interrupt service routine.  We only have to
- * handle RX events; transmit events go via the TX DMA handler.
- *
- * No matter what, we disable RX, process, and the restart RX.
- */
-static void sa1100_irda_fir_irq(struct net_device *dev)
-{
-	struct sa1100_irda *si = netdev_priv(dev);
-
-	/*
-	 * Stop RX DMA
-	 */
-	sa1100_stop_dma(si->rxdma);
-
-	/*
-	 * Framing error - we throw away the packet completely.
-	 * Clearing RXE flushes the error conditions and data
-	 * from the fifo.
-	 */
-	if (Ser2HSSR0 & (HSSR0_FRE | HSSR0_RAB)) {
-		dev->stats.rx_errors++;
-
-		if (Ser2HSSR0 & HSSR0_FRE)
-			dev->stats.rx_frame_errors++;
-
-		/*
-		 * Clear out the DMA...
-		 */
-		Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
-
-		/*
-		 * Clear selected status bits now, so we
-		 * don't miss them next time around.
-		 */
-		Ser2HSSR0 = HSSR0_FRE | HSSR0_RAB;
-	}
-
-	/*
-	 * Deal with any receive errors.  The any of the lowest
-	 * 8 bytes in the FIFO may contain an error.  We must read
-	 * them one by one.  The "error" could even be the end of
-	 * packet!
-	 */
-	if (Ser2HSSR0 & HSSR0_EIF)
-		sa1100_irda_fir_error(si, dev);
-
-	/*
-	 * No matter what happens, we must restart reception.
-	 */
-	sa1100_irda_rx_dma_start(si);
-}
-
-static irqreturn_t sa1100_irda_irq(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	if (IS_FIR(((struct sa1100_irda *)netdev_priv(dev))))
-		sa1100_irda_fir_irq(dev);
-	else
-		sa1100_irda_hpsir_irq(dev);
-	return IRQ_HANDLED;
-}
-
-/*
- * TX DMA completion handler.
- */
-static void sa1100_irda_txdma_irq(void *id)
-{
-	struct net_device *dev = id;
-	struct sa1100_irda *si = netdev_priv(dev);
-	struct sk_buff *skb = si->txskb;
-
-	si->txskb = NULL;
-
-	/*
-	 * Wait for the transmission to complete.  Unfortunately,
-	 * the hardware doesn't give us an interrupt to indicate
-	 * "end of frame".
-	 */
-	do
-		rmb();
-	while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY);
-
-	/*
-	 * Clear the transmit underrun bit.
-	 */
-	Ser2HSSR0 = HSSR0_TUR;
-
-	/*
-	 * Do we need to change speed?  Note that we're lazy
-	 * here - we don't free the old rxskb.  We don't need
-	 * to allocate a buffer either.
-	 */
-	if (si->newspeed) {
-		sa1100_irda_set_speed(si, si->newspeed);
-		si->newspeed = 0;
-	}
-
-	/*
-	 * Start reception.  This disables the transmitter for
-	 * us.  This will be using the existing RX buffer.
-	 */
-	sa1100_irda_rx_dma_start(si);
-
-	/*
-	 * Account and free the packet.
-	 */
-	if (skb) {
-		dma_unmap_single(si->dev, si->txbuf_dma, skb->len, DMA_TO_DEVICE);
-		dev->stats.tx_packets ++;
-		dev->stats.tx_bytes += skb->len;
-		dev_kfree_skb_irq(skb);
-	}
-
-	/*
-	 * Make sure that the TX queue is available for sending
-	 * (for retries).  TX has priority over RX at all times.
-	 */
-	netif_wake_queue(dev);
-}
-
-static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct sa1100_irda *si = netdev_priv(dev);
-	int speed = irda_get_next_speed(skb);
-
-	/*
-	 * Does this packet contain a request to change the interface
-	 * speed?  If so, remember it until we complete the transmission
-	 * of this frame.
-	 */
-	if (speed != si->speed && speed != -1)
-		si->newspeed = speed;
-
-	/*
-	 * If this is an empty frame, we can bypass a lot.
-	 */
-	if (skb->len == 0) {
-		if (si->newspeed) {
-			si->newspeed = 0;
-			sa1100_irda_set_speed(si, speed);
-		}
-		dev_kfree_skb(skb);
-		return NETDEV_TX_OK;
-	}
-
-	if (!IS_FIR(si)) {
-		netif_stop_queue(dev);
-
-		si->tx_buff.data = si->tx_buff.head;
-		si->tx_buff.len  = async_wrap_skb(skb, si->tx_buff.data,
-						  si->tx_buff.truesize);
-
-		/*
-		 * Set the transmit interrupt enable.  This will fire
-		 * off an interrupt immediately.  Note that we disable
-		 * the receiver so we won't get spurious characteres
-		 * received.
-		 */
-		Ser2UTCR3 = UTCR3_TIE | UTCR3_TXE;
-
-		dev_kfree_skb(skb);
-	} else {
-		int mtt = irda_get_mtt(skb);
-
-		/*
-		 * We must not be transmitting...
-		 */
-		BUG_ON(si->txskb);
-
-		netif_stop_queue(dev);
-
-		si->txskb = skb;
-		si->txbuf_dma = dma_map_single(si->dev, skb->data,
-					 skb->len, DMA_TO_DEVICE);
-
-		sa1100_start_dma(si->txdma, si->txbuf_dma, skb->len);
-
-		/*
-		 * If we have a mean turn-around time, impose the specified
-		 * specified delay.  We could shorten this by timing from
-		 * the point we received the packet.
-		 */
-		if (mtt)
-			udelay(mtt);
-
-		Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE;
-	}
-
-	return NETDEV_TX_OK;
-}
-
-static int
-sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
-{
-	struct if_irda_req *rq = (struct if_irda_req *)ifreq;
-	struct sa1100_irda *si = netdev_priv(dev);
-	int ret = -EOPNOTSUPP;
-
-	switch (cmd) {
-	case SIOCSBANDWIDTH:
-		if (capable(CAP_NET_ADMIN)) {
-			/*
-			 * We are unable to set the speed if the
-			 * device is not running.
-			 */
-			if (si->open) {
-				ret = sa1100_irda_set_speed(si,
-						rq->ifr_baudrate);
-			} else {
-				printk("sa1100_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n");
-				ret = 0;
-			}
-		}
-		break;
-
-	case SIOCSMEDIABUSY:
-		ret = -EPERM;
-		if (capable(CAP_NET_ADMIN)) {
-			irda_device_set_media_busy(dev, TRUE);
-			ret = 0;
-		}
-		break;
-
-	case SIOCGRECEIVING:
-		rq->ifr_receiving = IS_FIR(si) ? 0
-					: si->rx_buff.state != OUTSIDE_FRAME;
-		break;
-
-	default:
-		break;
-	}
-		
-	return ret;
-}
-
 static int sa1100_irda_start(struct net_device *dev)
 {
 	struct sa1100_irda *si = netdev_priv(dev);
@@ -769,26 +797,17 @@
 
 	si->speed = 9600;
 
-	err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev);
-	if (err)
-		goto err_irq;
-
-	err = sa1100_request_dma(DMA_Ser2HSSPRd, "IrDA receive",
-				 NULL, NULL, &si->rxdma);
+	err = sa1100_irda_dma_request(si->dev, &si->dma_rx, "Ser2ICPRc",
+				&sa1100_irda_fir_rx);
 	if (err)
 		goto err_rx_dma;
 
-	err = sa1100_request_dma(DMA_Ser2HSSPWr, "IrDA transmit",
-				 sa1100_irda_txdma_irq, dev, &si->txdma);
+	err = sa1100_irda_dma_request(si->dev, &si->dma_tx, "Ser2ICPTr",
+				&sa1100_irda_sir_tx);
 	if (err)
 		goto err_tx_dma;
 
 	/*
-	 * The interrupt must remain disabled for now.
-	 */
-	disable_irq(dev->irq);
-
-	/*
 	 * Setup the serial port for the specified speed.
 	 */
 	err = sa1100_irda_startup(si);
@@ -803,44 +822,60 @@
 	if (!si->irlap)
 		goto err_irlap;
 
+	err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev);
+	if (err)
+		goto err_irq;
+
 	/*
 	 * Now enable the interrupt and start the queue
 	 */
 	si->open = 1;
 	sa1100_set_power(si, power_level); /* low power mode */
-	enable_irq(dev->irq);
+
 	netif_start_queue(dev);
 	return 0;
 
+err_irq:
+	irlap_close(si->irlap);
 err_irlap:
 	si->open = 0;
 	sa1100_irda_shutdown(si);
 err_startup:
-	sa1100_free_dma(si->txdma);
+	dma_release_channel(si->dma_tx.chan);
 err_tx_dma:
-	sa1100_free_dma(si->rxdma);
+	dma_release_channel(si->dma_rx.chan);
 err_rx_dma:
-	free_irq(dev->irq, dev);
-err_irq:
 	return err;
 }
 
 static int sa1100_irda_stop(struct net_device *dev)
 {
 	struct sa1100_irda *si = netdev_priv(dev);
+	struct sk_buff *skb;
 
-	disable_irq(dev->irq);
+	netif_stop_queue(dev);
+
+	si->open = 0;
 	sa1100_irda_shutdown(si);
 
 	/*
-	 * If we have been doing DMA receive, make sure we
+	 * If we have been doing any DMA activity, make sure we
 	 * tidy that up cleanly.
 	 */
-	if (si->rxskb) {
-		dma_unmap_single(si->dev, si->rxbuf_dma, HPSIR_MAX_RXLEN,
-				 DMA_FROM_DEVICE);
-		dev_kfree_skb(si->rxskb);
-		si->rxskb = NULL;
+	skb = si->dma_rx.skb;
+	if (skb) {
+		dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1,
+			     DMA_FROM_DEVICE);
+		dev_kfree_skb(skb);
+		si->dma_rx.skb = NULL;
+	}
+
+	skb = si->dma_tx.skb;
+	if (skb) {
+		dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1,
+			     DMA_TO_DEVICE);
+		dev_kfree_skb(skb);
+		si->dma_tx.skb = NULL;
 	}
 
 	/* Stop IrLAP */
@@ -849,14 +884,11 @@
 		si->irlap = NULL;
 	}
 
-	netif_stop_queue(dev);
-	si->open = 0;
-
 	/*
 	 * Free resources
 	 */
-	sa1100_free_dma(si->txdma);
-	sa1100_free_dma(si->rxdma);
+	dma_release_channel(si->dma_tx.chan);
+	dma_release_channel(si->dma_rx.chan);
 	free_irq(dev->irq, dev);
 
 	sa1100_set_power(si, 0);
@@ -888,11 +920,15 @@
 	struct net_device *dev;
 	struct sa1100_irda *si;
 	unsigned int baudrate_mask;
-	int err;
+	int err, irq;
 
 	if (!pdev->dev.platform_data)
 		return -EINVAL;
 
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0)
+		return irq < 0 ? irq : -ENXIO;
+
 	err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY;
 	if (err)
 		goto err_mem_1;
@@ -907,22 +943,27 @@
 	if (!dev)
 		goto err_mem_4;
 
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
 	si = netdev_priv(dev);
 	si->dev = &pdev->dev;
 	si->pdata = pdev->dev.platform_data;
 
+	sg_init_table(&si->dma_rx.sg, 1);
+	sg_init_table(&si->dma_tx.sg, 1);
+
 	/*
 	 * Initialise the HP-SIR buffers
 	 */
 	err = sa1100_irda_init_iobuf(&si->rx_buff, 14384);
 	if (err)
 		goto err_mem_5;
-	err = sa1100_irda_init_iobuf(&si->tx_buff, 4000);
+	err = sa1100_irda_init_iobuf(&si->tx_buff, IRDA_SIR_MAX_FRAME);
 	if (err)
 		goto err_mem_5;
 
 	dev->netdev_ops	= &sa1100_irda_netdev_ops;
-	dev->irq	= IRQ_Ser2ICP;
+	dev->irq	= irq;
 
 	irda_init_max_qos_capabilies(&si->qos);
 
@@ -996,6 +1037,74 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+/*
+ * Suspend the IrDA interface.
+ */
+static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct sa1100_irda *si;
+
+	if (!dev)
+		return 0;
+
+	si = netdev_priv(dev);
+	if (si->open) {
+		/*
+		 * Stop the transmit queue
+		 */
+		netif_device_detach(dev);
+		disable_irq(dev->irq);
+		sa1100_irda_shutdown(si);
+		__sa1100_irda_set_power(si, 0);
+	}
+
+	return 0;
+}
+
+/*
+ * Resume the IrDA interface.
+ */
+static int sa1100_irda_resume(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct sa1100_irda *si;
+
+	if (!dev)
+		return 0;
+
+	si = netdev_priv(dev);
+	if (si->open) {
+		/*
+		 * If we missed a speed change, initialise at the new speed
+		 * directly.  It is debatable whether this is actually
+		 * required, but in the interests of continuing from where
+		 * we left off it is desirable.  The converse argument is
+		 * that we should re-negotiate at 9600 baud again.
+		 */
+		if (si->newspeed) {
+			si->speed = si->newspeed;
+			si->newspeed = 0;
+		}
+
+		sa1100_irda_startup(si);
+		__sa1100_irda_set_power(si, si->power);
+		enable_irq(dev->irq);
+
+		/*
+		 * This automatically wakes up the queue
+		 */
+		netif_device_attach(dev);
+	}
+
+	return 0;
+}
+#else
+#define sa1100_irda_suspend	NULL
+#define sa1100_irda_resume	NULL
+#endif
+
 static struct platform_driver sa1100ir_driver = {
 	.probe		= sa1100_irda_probe,
 	.remove		= sa1100_irda_remove,
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index b71998d..32eb94e 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -41,7 +41,6 @@
 #include <linux/in.h>
 #include <linux/init.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
index 0856e1b..f08c85a 100644
--- a/drivers/net/phy/icplus.c
+++ b/drivers/net/phy/icplus.c
@@ -162,7 +162,8 @@
 	/* Enable Auto Power Saving mode */
 	c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
 	c |= IP101A_G_APS_ON;
-	return c;
+
+	return phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c);
 }
 
 static int ip175c_read_status(struct phy_device *phydev)
diff --git a/drivers/net/plip/plip.c b/drivers/net/plip/plip.c
index 1a5a316..bed62d9 100644
--- a/drivers/net/plip/plip.c
+++ b/drivers/net/plip/plip.c
@@ -113,7 +113,6 @@
 
 #include <net/neighbour.h>
 
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/byteorder.h>
 
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 159da29..33f8c51 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -235,7 +235,7 @@
 /* Prototypes. */
 static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
 			struct file *file, unsigned int cmd, unsigned long arg);
-static void ppp_xmit_process(struct ppp *ppp);
+static int ppp_xmit_process(struct ppp *ppp);
 static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb);
 static void ppp_push(struct ppp *ppp);
 static void ppp_channel_push(struct channel *pch);
@@ -968,9 +968,9 @@
 	proto = npindex_to_proto[npi];
 	put_unaligned_be16(proto, pp);
 
-	netif_stop_queue(dev);
 	skb_queue_tail(&ppp->file.xq, skb);
-	ppp_xmit_process(ppp);
+	if (!ppp_xmit_process(ppp))
+		netif_stop_queue(dev);
 	return NETDEV_TX_OK;
 
  outf:
@@ -1048,10 +1048,11 @@
  * Called to do any work queued up on the transmit side
  * that can now be done.
  */
-static void
+static int
 ppp_xmit_process(struct ppp *ppp)
 {
 	struct sk_buff *skb;
+	int ret = 0;
 
 	ppp_xmit_lock(ppp);
 	if (!ppp->closing) {
@@ -1061,10 +1062,13 @@
 			ppp_send_frame(ppp, skb);
 		/* If there's no work left to do, tell the core net
 		   code that we can accept some more. */
-		if (!ppp->xmit_pending && !skb_peek(&ppp->file.xq))
+		if (!ppp->xmit_pending && !skb_peek(&ppp->file.xq)) {
 			netif_wake_queue(ppp->dev);
+			ret = 1;
+		}
 	}
 	ppp_xmit_unlock(ppp);
+	return ret;
 }
 
 static inline struct sk_buff *
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index a57f057..91d2588 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -375,8 +375,8 @@
 	struct net_device *ndev = rio_get_drvdata(rdev);
 	struct rionet_peer *peer, *tmp;
 
-	free_pages((unsigned long)rionet_active, rdev->net->hport->sys_size ?
-					__fls(sizeof(void *)) + 4 : 0);
+	free_pages((unsigned long)rionet_active, get_order(sizeof(void *) *
+			RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size)));
 	unregister_netdev(ndev);
 	free_netdev(ndev);
 
@@ -432,15 +432,16 @@
 	int rc = 0;
 	struct rionet_private *rnet;
 	u16 device_id;
+	const size_t rionet_active_bytes = sizeof(void *) *
+				RIO_MAX_ROUTE_ENTRIES(mport->sys_size);
 
 	rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL,
-			mport->sys_size ? __fls(sizeof(void *)) + 4 : 0);
+			get_order(rionet_active_bytes));
 	if (!rionet_active) {
 		rc = -ENOMEM;
 		goto out;
 	}
-	memset((void *)rionet_active, 0, sizeof(void *) *
-				RIO_MAX_ROUTE_ENTRIES(mport->sys_size));
+	memset((void *)rionet_active, 0, rionet_active_bytes);
 
 	/* Set up private area */
 	rnet = netdev_priv(ndev);
diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c
index 0a0a664..1252d9c 100644
--- a/drivers/net/slip/slhc.c
+++ b/drivers/net/slip/slhc.c
@@ -75,7 +75,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <linux/timer.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <net/checksum.h>
 #include <asm/unaligned.h>
diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c
index 69345df..d4c9db3 100644
--- a/drivers/net/slip/slip.c
+++ b/drivers/net/slip/slip.c
@@ -64,7 +64,6 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/bitops.h>
 #include <linux/sched.h>
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index d7c292a..b15ac81 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -68,7 +68,6 @@
 #include <net/checksum.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include "3c359.h"
 
diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c
index 515f122..b715e6b 100644
--- a/drivers/net/tokenring/abyss.c
+++ b/drivers/net/tokenring/abyss.c
@@ -33,7 +33,6 @@
 #include <linux/netdevice.h>
 #include <linux/trdevice.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
diff --git a/drivers/net/tokenring/ibmtr_cs.c b/drivers/net/tokenring/ibmtr_cs.c
index 91b6846..356e28e 100644
--- a/drivers/net/tokenring/ibmtr_cs.c
+++ b/drivers/net/tokenring/ibmtr_cs.c
@@ -63,7 +63,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #define PCMCIA
 #include "ibmtr.c"
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index 8d71e0d..3e4b4f0 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -127,7 +127,6 @@
 #include <net/checksum.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include "lanstreamer.h"
 
diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
index 1cdc034..28adcdf 100644
--- a/drivers/net/tokenring/madgemc.c
+++ b/drivers/net/tokenring/madgemc.c
@@ -28,7 +28,6 @@
 #include <linux/netdevice.h>
 #include <linux/trdevice.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index fd8dce9..0e23474 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -106,7 +106,6 @@
 #include <net/net_namespace.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include "olympic.h"
 
diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c
index 8d362e6..62d90e4 100644
--- a/drivers/net/tokenring/proteon.c
+++ b/drivers/net/tokenring/proteon.c
@@ -31,7 +31,6 @@
 #include <linux/trdevice.h>
 #include <linux/platform_device.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/pci.h>
diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c
index 46db5c5..ee11e93 100644
--- a/drivers/net/tokenring/skisa.c
+++ b/drivers/net/tokenring/skisa.c
@@ -38,7 +38,6 @@
 #include <linux/trdevice.h>
 #include <linux/platform_device.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/pci.h>
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index 029846a..cb35fb7 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -49,7 +49,6 @@
 #include <linux/bitops.h>
 #include <linux/firmware.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index 102f896..be4813e 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -98,7 +98,6 @@
 #include <linux/firmware.h>
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c
index d3e788a..fb9918d 100644
--- a/drivers/net/tokenring/tmspci.c
+++ b/drivers/net/tokenring/tmspci.c
@@ -34,7 +34,6 @@
 #include <linux/netdevice.h>
 #include <linux/trdevice.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 74d7f76..bb8c72c 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -69,7 +69,6 @@
 #include <net/rtnetlink.h>
 #include <net/sock.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 /* Uncomment to enable debugging */
diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c
index 790cbde..3e41b00 100644
--- a/drivers/net/usb/cdc-phonet.c
+++ b/drivers/net/usb/cdc-phonet.c
@@ -164,12 +164,14 @@
 				/* Can't use pskb_pull() on page in IRQ */
 				memcpy(skb_put(skb, 1), page_address(page), 1);
 				skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
-						page, 1, req->actual_length);
+						page, 1, req->actual_length,
+						PAGE_SIZE);
 				page = NULL;
 			}
 		} else {
 			skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
-					page, 0, req->actual_length);
+					page, 0, req->actual_length,
+					PAGE_SIZE);
 			page = NULL;
 		}
 		if (req->actual_length < PAGE_SIZE)
diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c
index 439690b..685a4e2 100644
--- a/drivers/net/usb/cdc_eem.c
+++ b/drivers/net/usb/cdc_eem.c
@@ -93,6 +93,7 @@
 	/* no jumbogram (16K) support for now */
 
 	dev->net->hard_header_len += EEM_HEAD + ETH_FCS_LEN;
+	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
 
 	return 0;
 }
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index aac68f5..552d24b 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -409,6 +409,42 @@
 		.bInterfaceProtocol = 0xff,
 		.driver_info        = (unsigned long)&qmi_wwan_force_int4,
 	},
+	{	/* ZTE (Vodafone) K3565-Z */
+		.match_flags	    = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
+		.idVendor           = 0x19d2,
+		.idProduct          = 0x0063,
+		.bInterfaceClass    = 0xff,
+		.bInterfaceSubClass = 0xff,
+		.bInterfaceProtocol = 0xff,
+		.driver_info        = (unsigned long)&qmi_wwan_force_int4,
+	},
+	{	/* ZTE (Vodafone) K3570-Z */
+		.match_flags	    = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
+		.idVendor           = 0x19d2,
+		.idProduct          = 0x1008,
+		.bInterfaceClass    = 0xff,
+		.bInterfaceSubClass = 0xff,
+		.bInterfaceProtocol = 0xff,
+		.driver_info        = (unsigned long)&qmi_wwan_force_int4,
+	},
+	{	/* ZTE (Vodafone) K3571-Z */
+		.match_flags	    = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
+		.idVendor           = 0x19d2,
+		.idProduct          = 0x1010,
+		.bInterfaceClass    = 0xff,
+		.bInterfaceSubClass = 0xff,
+		.bInterfaceProtocol = 0xff,
+		.driver_info        = (unsigned long)&qmi_wwan_force_int4,
+	},
+	{	/* ZTE (Vodafone) K4505-Z */
+		.match_flags	    = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
+		.idVendor           = 0x19d2,
+		.idProduct          = 0x0104,
+		.bInterfaceClass    = 0xff,
+		.bInterfaceSubClass = 0xff,
+		.bInterfaceProtocol = 0xff,
+		.driver_info        = (unsigned long)&qmi_wwan_force_int4,
+	},
 	{QMI_GOBI_DEVICE(0x05c6, 0x9212)},	/* Acer Gobi Modem Device */
 	{QMI_GOBI_DEVICE(0x03f0, 0x1f1d)},	/* HP un2400 Gobi Modem Device */
 	{QMI_GOBI_DEVICE(0x03f0, 0x371d)},	/* HP un2430 Mobile Broadband Module */
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index 6dda2fe..d363b31 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -85,32 +85,6 @@
 #define INT_CRERR_CNT		0x06
 #define INT_COL_CNT		0x07
 
-/* Transmit status register errors */
-#define TSR_ECOL		(1<<5)
-#define TSR_LCOL		(1<<4)
-#define TSR_LOSS_CRS		(1<<3)
-#define TSR_JBR			(1<<2)
-#define TSR_ERRORS		(TSR_ECOL | TSR_LCOL | TSR_LOSS_CRS | TSR_JBR)
-/* Receive status register errors */
-#define RSR_CRC			(1<<2)
-#define RSR_FAE			(1<<1)
-#define RSR_ERRORS		(RSR_CRC | RSR_FAE)
-
-/* Media status register definitions */
-#define MSR_DUPLEX		(1<<4)
-#define MSR_SPEED		(1<<3)
-#define MSR_LINK		(1<<2)
-
-/* Interrupt pipe data */
-#define INT_TSR			0x00
-#define INT_RSR			0x01
-#define INT_MSR			0x02
-#define INT_WAKSR		0x03
-#define INT_TXOK_CNT		0x04
-#define INT_RXLOST_CNT		0x05
-#define INT_CRERR_CNT		0x06
-#define INT_COL_CNT		0x07
-
 
 #define	RTL8150_MTU		1540
 #define	RTL8150_TX_TIMEOUT	(HZ)
diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c
index c3197ce..34db195 100644
--- a/drivers/net/usb/zaurus.c
+++ b/drivers/net/usb/zaurus.c
@@ -337,6 +337,11 @@
 	.driver_info = ZAURUS_PXA_INFO,
 },
 {
+	/* Motorola Rokr E6 */
+	USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6027, USB_CLASS_COMM,
+			USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
+	.driver_info = (unsigned long) &bogus_mdlm_info,
+}, {
 	/* Motorola MOTOMAGX phones */
 	USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6425, USB_CLASS_COMM,
 			USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 019da01..4de2760 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -625,12 +625,13 @@
 
 	/* This can happen with OOM and indirect buffers. */
 	if (unlikely(capacity < 0)) {
-		if (net_ratelimit()) {
-			if (likely(capacity == -ENOMEM)) {
+		if (likely(capacity == -ENOMEM)) {
+			if (net_ratelimit()) {
 				dev_warn(&dev->dev,
 					 "TX queue failure: out of memory\n");
 			} else {
-				dev->stats.tx_fifo_errors++;
+			dev->stats.tx_fifo_errors++;
+			if (net_ratelimit())
 				dev_warn(&dev->dev,
 					 "Unexpected TX queue failure: %d\n",
 					 capacity);
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 423eb26..d70ede7 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -290,8 +290,8 @@
 	  Frame Relay or X.25/LAPB.
 
 	  If you want the module to be automatically loaded when the interface
-	  is referenced then you should add "alias hdlcX farsync" to
-	  /etc/modprobe.conf for each interface, where X is 0, 1, 2, ..., or
+	  is referenced then you should add "alias hdlcX farsync" to a file
+	  in /etc/modprobe.d/ for each interface, where X is 0, 1, 2, ..., or
 	  simply use "alias hdlc* farsync" to indicate all of them.
 
 	  To compile this driver as a module, choose M here: the
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 48ab38a..147614e 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -50,7 +50,6 @@
 
 #include <net/sock.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/uaccess.h>
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index fe8d060..c676de7 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -93,7 +93,6 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 
-#include <asm/system.h>
 #include <asm/cache.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
diff --git a/drivers/net/wan/hd64570.c b/drivers/net/wan/hd64570.c
index 33b67d8..cf49033 100644
--- a/drivers/net/wan/hd64570.c
+++ b/drivers/net/wan/hd64570.c
@@ -40,7 +40,6 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include "hd64570.h"
 
diff --git a/drivers/net/wan/hd64572.c b/drivers/net/wan/hd64572.c
index efc0db1..e2779fa 100644
--- a/drivers/net/wan/hd64572.c
+++ b/drivers/net/wan/hd64572.c
@@ -40,7 +40,6 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include "hd64572.h"
 
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index 7beeb9b..a73b49e 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -35,7 +35,6 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index c853161..de3bbf4 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -54,7 +54,6 @@
 #include <linux/sdla.h>
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/uaccess.h>
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index e862369..d7a65e1 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -18,7 +18,6 @@
 
 #include <linux/module.h>
 
-#include <asm/system.h>
 #include <linux/uaccess.h>
 #include <linux/bitops.h>
 #include <linux/string.h>
diff --git a/drivers/net/wimax/i2400m/debugfs.c b/drivers/net/wimax/i2400m/debugfs.c
index 129ba36..4b66ab1 100644
--- a/drivers/net/wimax/i2400m/debugfs.c
+++ b/drivers/net/wimax/i2400m/debugfs.c
@@ -53,17 +53,6 @@
 				   &fops_netdev_queue_stopped);
 }
 
-
-/*
- * inode->i_private has the @data argument to debugfs_create_file()
- */
-static
-int i2400m_stats_open(struct inode *inode, struct file *filp)
-{
-	filp->private_data = inode->i_private;
-	return 0;
-}
-
 /*
  * We don't allow partial reads of this file, as then the reader would
  * get weirdly confused data as it is updated.
@@ -117,7 +106,7 @@
 static
 const struct file_operations i2400m_rx_stats_fops = {
 	.owner =	THIS_MODULE,
-	.open =		i2400m_stats_open,
+	.open =		simple_open,
 	.read =		i2400m_rx_stats_read,
 	.write =	i2400m_rx_stats_write,
 	.llseek =	default_llseek,
@@ -170,7 +159,7 @@
 static
 const struct file_operations i2400m_tx_stats_fops = {
 	.owner =	THIS_MODULE,
-	.open =		i2400m_stats_open,
+	.open =		simple_open,
 	.read =		i2400m_tx_stats_read,
 	.write =	i2400m_tx_stats_write,
 	.llseek =	default_llseek,
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index 63e4b70..1d76ae8 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -597,7 +597,8 @@
 	struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
 
 	strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver) - 1);
-	strncpy(info->fw_version, i2400m->fw_name, sizeof(info->fw_version) - 1);
+	strncpy(info->fw_version,
+	        i2400m->fw_name ? : "", sizeof(info->fw_version) - 1);
 	if (net_dev->dev.parent)
 		strncpy(info->bus_info, dev_name(net_dev->dev.parent),
 			sizeof(info->bus_info) - 1);
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 2c1b8b6..29b1e03 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -339,6 +339,23 @@
 	return result;
 }
 
+static void i2400mu_get_drvinfo(struct net_device *net_dev,
+                                struct ethtool_drvinfo *info)
+{
+	struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
+	struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
+	struct usb_device *udev = i2400mu->usb_dev;
+
+	strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver) - 1);
+	strncpy(info->fw_version,
+	        i2400m->fw_name ? : "", sizeof(info->fw_version) - 1);
+	usb_make_path(udev, info->bus_info, sizeof(info->bus_info));
+}
+
+static const struct ethtool_ops i2400mu_ethtool_ops = {
+	.get_drvinfo = i2400mu_get_drvinfo,
+	.get_link = ethtool_op_get_link,
+};
 
 static
 void i2400mu_netdev_setup(struct net_device *net_dev)
@@ -347,6 +364,7 @@
 	struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
 	i2400mu_init(i2400mu);
 	i2400m_netdev_setup(net_dev);
+	net_dev->ethtool_ops = &i2400mu_ethtool_ops;
 }
 
 
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index ddc061d..520a4b2 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -37,7 +37,6 @@
 #include <linux/scatterlist.h>
 #include <linux/crypto.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/unaligned.h>
 
 #include <linux/netdevice.h>
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index c983c10..630577d 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -37,7 +37,6 @@
 #include <pcmcia/ds.h>
 
 #include <linux/io.h>
-#include <asm/system.h>
 
 #include "airo.h"
 
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 8c5ce8b..e5e8f45 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -71,13 +71,6 @@
 module_param_named(debug, ath5k_debug, uint, 0);
 
 
-static int ath5k_debugfs_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-
 /* debugfs: registers */
 
 struct reg {
@@ -265,7 +258,7 @@
 static const struct file_operations fops_beacon = {
 	.read = read_file_beacon,
 	.write = write_file_beacon,
-	.open = ath5k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -285,7 +278,7 @@
 
 static const struct file_operations fops_reset = {
 	.write = write_file_reset,
-	.open = ath5k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = noop_llseek,
 };
@@ -365,7 +358,7 @@
 static const struct file_operations fops_debug = {
 	.read = read_file_debug,
 	.write = write_file_debug,
-	.open = ath5k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -477,7 +470,7 @@
 static const struct file_operations fops_antenna = {
 	.read = read_file_antenna,
 	.write = write_file_antenna,
-	.open = ath5k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -532,7 +525,7 @@
 
 static const struct file_operations fops_misc = {
 	.read = read_file_misc,
-	.open = ath5k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 };
 
@@ -647,7 +640,7 @@
 static const struct file_operations fops_frameerrors = {
 	.read = read_file_frameerrors,
 	.write = write_file_frameerrors,
-	.open = ath5k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -810,7 +803,7 @@
 static const struct file_operations fops_ani = {
 	.read = read_file_ani,
 	.write = write_file_ani,
-	.open = ath5k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -881,7 +874,7 @@
 static const struct file_operations fops_queue = {
 	.read = read_file_queue,
 	.write = write_file_queue,
-	.open = ath5k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
index 552adb3..d01403a 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.c
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -217,12 +217,6 @@
 		   target->credit_info->cur_free_credits);
 }
 
-static int ath6kl_debugfs_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war)
 {
 	switch (war) {
@@ -263,7 +257,7 @@
 
 static const struct file_operations fops_war_stats = {
 	.read = read_file_war_stats,
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -488,7 +482,7 @@
 }
 
 static const struct file_operations fops_fwlog_mask = {
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.read = ath6kl_fwlog_mask_read,
 	.write = ath6kl_fwlog_mask_write,
 	.owner = THIS_MODULE,
@@ -634,7 +628,7 @@
 
 static const struct file_operations fops_tgt_stats = {
 	.read = read_file_tgt_stats,
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -699,7 +693,7 @@
 
 static const struct file_operations fops_credit_dist_stats = {
 	.read = read_file_credit_dist_stats,
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -802,7 +796,7 @@
 }
 
 static const struct file_operations fops_endpoint_stats = {
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.read = ath6kl_endpoint_stats_read,
 	.write = ath6kl_endpoint_stats_write,
 	.owner = THIS_MODULE,
@@ -875,7 +869,7 @@
 static const struct file_operations fops_diag_reg_read = {
 	.read = ath6kl_regread_read,
 	.write = ath6kl_regread_write,
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -999,7 +993,7 @@
 static const struct file_operations fops_lrssi_roam_threshold = {
 	.read = ath6kl_lrssi_roam_read,
 	.write = ath6kl_lrssi_roam_write,
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -1061,7 +1055,7 @@
 static const struct file_operations fops_diag_reg_write = {
 	.read = ath6kl_regwrite_read,
 	.write = ath6kl_regwrite_write,
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -1166,7 +1160,7 @@
 
 static const struct file_operations fops_roam_table = {
 	.read = ath6kl_roam_table_read,
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -1204,7 +1198,7 @@
 
 static const struct file_operations fops_force_roam = {
 	.write = ath6kl_force_roam_write,
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -1244,7 +1238,7 @@
 
 static const struct file_operations fops_roam_mode = {
 	.write = ath6kl_roam_mode_write,
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -1286,7 +1280,7 @@
 }
 
 static const struct file_operations fops_keepalive = {
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.read = ath6kl_keepalive_read,
 	.write = ath6kl_keepalive_write,
 	.owner = THIS_MODULE,
@@ -1331,7 +1325,7 @@
 }
 
 static const struct file_operations fops_disconnect_timeout = {
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.read = ath6kl_disconnect_timeout_read,
 	.write = ath6kl_disconnect_timeout_write,
 	.owner = THIS_MODULE,
@@ -1512,7 +1506,7 @@
 
 static const struct file_operations fops_create_qos = {
 	.write = ath6kl_create_qos_write,
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -1560,7 +1554,7 @@
 
 static const struct file_operations fops_delete_qos = {
 	.write = ath6kl_delete_qos_write,
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -1593,7 +1587,7 @@
 
 static const struct file_operations fops_bgscan_int = {
 	.write = ath6kl_bgscan_int_write,
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -1651,7 +1645,7 @@
 static const struct file_operations fops_listen_int = {
 	.read = ath6kl_listen_int_read,
 	.write = ath6kl_listen_int_write,
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -1711,7 +1705,7 @@
 
 static const struct file_operations fops_power_params = {
 	.write = ath6kl_power_params_write,
-	.open = ath6kl_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 35d1c8e..ff47b32 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -26,11 +26,6 @@
 #define REG_READ_D(_ah, _reg) \
 	ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
 
-static int ath9k_debugfs_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
 
 static ssize_t ath9k_debugfs_read_buf(struct file *file, char __user *user_buf,
 				      size_t count, loff_t *ppos)
@@ -83,7 +78,7 @@
 static const struct file_operations fops_debug = {
 	.read = read_file_debug,
 	.write = write_file_debug,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -129,7 +124,7 @@
 static const struct file_operations fops_tx_chainmask = {
 	.read = read_file_tx_chainmask,
 	.write = write_file_tx_chainmask,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -172,7 +167,7 @@
 static const struct file_operations fops_rx_chainmask = {
 	.read = read_file_rx_chainmask,
 	.write = write_file_rx_chainmask,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -223,7 +218,7 @@
 static const struct file_operations fops_disable_ani = {
 	.read = read_file_disable_ani,
 	.write = write_file_disable_ani,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -324,7 +319,7 @@
 
 static const struct file_operations fops_dma = {
 	.read = read_file_dma,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -446,7 +441,7 @@
 
 static const struct file_operations fops_interrupt = {
 	.read = read_file_interrupt,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -852,28 +847,28 @@
 
 static const struct file_operations fops_xmit = {
 	.read = read_file_xmit,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
 
 static const struct file_operations fops_stations = {
 	.read = read_file_stations,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
 
 static const struct file_operations fops_misc = {
 	.read = read_file_misc,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
 
 static const struct file_operations fops_reset = {
 	.read = read_file_reset,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -1016,7 +1011,7 @@
 
 static const struct file_operations fops_recv = {
 	.read = read_file_recv,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -1055,7 +1050,7 @@
 static const struct file_operations fops_regidx = {
 	.read = read_file_regidx,
 	.write = write_file_regidx,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -1102,7 +1097,7 @@
 static const struct file_operations fops_regval = {
 	.read = read_file_regval,
 	.write = write_file_regval,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -1191,7 +1186,7 @@
 
 static const struct file_operations fops_dump_nfcal = {
 	.read = read_file_dump_nfcal,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -1219,7 +1214,7 @@
 
 static const struct file_operations fops_base_eeprom = {
 	.read = read_file_base_eeprom,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -1247,7 +1242,7 @@
 
 static const struct file_operations fops_modal_eeprom = {
 	.read = read_file_modal_eeprom,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.c b/drivers/net/wireless/ath/ath9k/dfs_debug.c
index 106d031..4364c10 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_debug.c
+++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c
@@ -60,16 +60,9 @@
 	return retval;
 }
 
-static int ath9k_dfs_debugfs_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-
-	return 0;
-}
-
 static const struct file_operations fops_dfs_stats = {
 	.read = read_file_dfs,
-	.open = ath9k_dfs_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
index d3ff33c..3035deb 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
@@ -16,12 +16,6 @@
 
 #include "htc.h"
 
-static int ath9k_debugfs_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf,
 				       size_t count, loff_t *ppos)
 {
@@ -75,7 +69,7 @@
 
 static const struct file_operations fops_tgt_int_stats = {
 	.read = read_file_tgt_int_stats,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -145,7 +139,7 @@
 
 static const struct file_operations fops_tgt_tx_stats = {
 	.read = read_file_tgt_tx_stats,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -191,7 +185,7 @@
 
 static const struct file_operations fops_tgt_rx_stats = {
 	.read = read_file_tgt_rx_stats,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -243,7 +237,7 @@
 
 static const struct file_operations fops_xmit = {
 	.read = read_file_xmit,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -364,7 +358,7 @@
 
 static const struct file_operations fops_recv = {
 	.read = read_file_recv,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -399,7 +393,7 @@
 
 static const struct file_operations fops_slot = {
 	.read = read_file_slot,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -446,7 +440,7 @@
 
 static const struct file_operations fops_queue = {
 	.read = read_file_queue,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -487,7 +481,7 @@
 static const struct file_operations fops_debug = {
 	.read = read_file_debug,
 	.write = write_file_debug,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -636,7 +630,7 @@
 
 static const struct file_operations fops_base_eeprom = {
 	.read = read_file_base_eeprom,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
@@ -917,7 +911,7 @@
 
 static const struct file_operations fops_modal_eeprom = {
 	.read = read_file_modal_eeprom,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE,
 	.llseek = default_llseek,
 };
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 3879485..215eb25 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -640,7 +640,7 @@
 	an->sta = sta;
 	an->vif = vif;
 
-	if (sta->ht_cap.ht_supported) {
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
 		ath_tx_node_init(sc, an);
 		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
 				     sta->ht_cap.ampdu_factor);
@@ -659,7 +659,7 @@
 	an->sta = NULL;
 #endif
 
-	if (sta->ht_cap.ht_supported)
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
 		ath_tx_node_cleanup(sc, an);
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 4f84849..08bb455 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -1480,12 +1480,6 @@
 
 #ifdef CONFIG_ATH9K_DEBUGFS
 
-static int ath9k_debugfs_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
 				size_t count, loff_t *ppos)
 {
@@ -1553,7 +1547,7 @@
 
 static const struct file_operations fops_rcstat = {
 	.read = read_file_rcstat,
-	.open = ath9k_debugfs_open,
+	.open = simple_open,
 	.owner = THIS_MODULE
 };
 
diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c
index 3c16422..93fe600 100644
--- a/drivers/net/wireless/ath/carl9170/debug.c
+++ b/drivers/net/wireless/ath/carl9170/debug.c
@@ -48,11 +48,6 @@
 #define ADD(buf, off, max, fmt, args...)				\
 	off += snprintf(&buf[off], max - off, fmt, ##args);
 
-static int carl9170_debugfs_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
 
 struct carl9170_debugfs_fops {
 	unsigned int read_bufsize;
@@ -178,7 +173,7 @@
 	.attr = _attr,							\
 	.req_dev_state = _dstate,					\
 	.fops = {							\
-		.open	= carl9170_debugfs_open,			\
+		.open	= simple_open,					\
 		.read	= carl9170_debugfs_read,			\
 		.write	= carl9170_debugfs_write,			\
 		.owner	= THIS_MODULE					\
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 3010cee..6c87a82 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -50,7 +50,6 @@
 #include <linux/timer.h>
 #include <asm/byteorder.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index ec295c4..ded03d2 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -48,7 +48,6 @@
 #include <pcmcia/ciscode.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <linux/wireless.h>
 
 #include "atmel.h"
diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c
index e751fde..e807bd9 100644
--- a/drivers/net/wireless/b43/debugfs.c
+++ b/drivers/net/wireless/b43/debugfs.c
@@ -500,12 +500,6 @@
 
 #undef fappend
 
-static int b43_debugfs_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
 				size_t count, loff_t *ppos)
 {
@@ -624,7 +618,7 @@
 		.read	= _read,				\
 		.write	= _write,				\
 		.fops	= {					\
-			.open	= b43_debugfs_open,		\
+			.open	= simple_open,			\
 			.read	= b43_debugfs_read,		\
 			.write	= b43_debugfs_write,		\
 			.llseek = generic_file_llseek,		\
diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c
index 5e28ad0..1965edb 100644
--- a/drivers/net/wireless/b43legacy/debugfs.c
+++ b/drivers/net/wireless/b43legacy/debugfs.c
@@ -197,12 +197,6 @@
 
 #undef fappend
 
-static int b43legacy_debugfs_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf,
 				size_t count, loff_t *ppos)
 {
@@ -331,7 +325,7 @@
 		.read	= _read,				\
 		.write	= _write,				\
 		.fops	= {					\
-			.open	= b43legacy_debugfs_open,		\
+			.open	= simple_open,				\
 			.read	= b43legacy_debugfs_read,		\
 			.write	= b43legacy_debugfs_write,		\
 			.llseek = generic_file_llseek,			\
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 4fcdac6..2b02257 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -11507,9 +11507,9 @@
 			rc = -ENOMEM;
 			goto out;
 		}
-		/* translate geo->bg to a_band.channels */
+		/* translate geo->a to a_band.channels */
 		for (i = 0; i < geo->a_channels; i++) {
-			a_band->channels[i].band = IEEE80211_BAND_2GHZ;
+			a_band->channels[i].band = IEEE80211_BAND_5GHZ;
 			a_band->channels[i].center_freq = geo->a[i].freq;
 			a_band->channels[i].hw_value = geo->a[i].channel;
 			a_band->channels[i].max_power = geo->a[i].max_power;
diff --git a/drivers/net/wireless/iwlegacy/3945-rs.c b/drivers/net/wireless/iwlegacy/3945-rs.c
index 70bee1a..4b10157 100644
--- a/drivers/net/wireless/iwlegacy/3945-rs.c
+++ b/drivers/net/wireless/iwlegacy/3945-rs.c
@@ -821,12 +821,6 @@
 }
 
 #ifdef CONFIG_MAC80211_DEBUGFS
-static int
-il3945_open_file_generic(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
 
 static ssize_t
 il3945_sta_dbgfs_stats_table_read(struct file *file, char __user *user_buf,
@@ -862,7 +856,7 @@
 
 static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
 	.read = il3945_sta_dbgfs_stats_table_read,
-	.open = il3945_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c
index c5b1d19..b25c01b 100644
--- a/drivers/net/wireless/iwlegacy/3945.c
+++ b/drivers/net/wireless/iwlegacy/3945.c
@@ -499,7 +499,8 @@
 				      le32_to_cpu(rx_end->status), stats);
 
 	skb_add_rx_frag(skb, 0, rxb->page,
-			(void *)rx_hdr->payload - (void *)pkt, len);
+			(void *)rx_hdr->payload - (void *)pkt, len,
+			len);
 
 	il_update_stats(il, false, fc, len);
 	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index b88bb27..c46275a 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -596,7 +596,8 @@
 		return;
 	}
 
-	skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
+	skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len,
+			len);
 
 	il_update_stats(il, false, fc, len);
 	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
diff --git a/drivers/net/wireless/iwlegacy/4965-rs.c b/drivers/net/wireless/iwlegacy/4965-rs.c
index d7e2856..11ab124 100644
--- a/drivers/net/wireless/iwlegacy/4965-rs.c
+++ b/drivers/net/wireless/iwlegacy/4965-rs.c
@@ -2518,12 +2518,6 @@
 }
 
 #ifdef CONFIG_MAC80211_DEBUGFS
-static int
-il4965_open_file_generic(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
 
 static void
 il4965_rs_dbgfs_set_mcs(struct il_lq_sta *lq_sta, u32 * rate_n_flags, int idx)
@@ -2695,7 +2689,7 @@
 static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
 	.write = il4965_rs_sta_dbgfs_scale_table_write,
 	.read = il4965_rs_sta_dbgfs_scale_table_read,
-	.open = il4965_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -2740,7 +2734,7 @@
 
 static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
 	.read = il4965_rs_sta_dbgfs_stats_table_read,
-	.open = il4965_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -2768,7 +2762,7 @@
 
 static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = {
 	.read = il4965_rs_sta_dbgfs_rate_scale_data_read,
-	.open = il4965_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
diff --git a/drivers/net/wireless/iwlegacy/debug.c b/drivers/net/wireless/iwlegacy/debug.c
index 2298491..eff2650 100644
--- a/drivers/net/wireless/iwlegacy/debug.c
+++ b/drivers/net/wireless/iwlegacy/debug.c
@@ -160,18 +160,12 @@
 					const char __user *user_buf,    \
 					size_t count, loff_t *ppos);
 
-static int
-il_dbgfs_open_file_generic(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
 
 #define DEBUGFS_READ_FILE_OPS(name)				\
 	DEBUGFS_READ_FUNC(name);				\
 static const struct file_operations il_dbgfs_##name##_ops = {	\
 	.read = il_dbgfs_##name##_read,				\
-	.open = il_dbgfs_open_file_generic,			\
+	.open = simple_open,					\
 	.llseek = generic_file_llseek,				\
 };
 
@@ -179,7 +173,7 @@
 	DEBUGFS_WRITE_FUNC(name);				\
 static const struct file_operations il_dbgfs_##name##_ops = {	\
 	.write = il_dbgfs_##name##_write,			\
-	.open = il_dbgfs_open_file_generic,			\
+	.open = simple_open,					\
 	.llseek = generic_file_llseek,				\
 };
 
@@ -189,7 +183,7 @@
 static const struct file_operations il_dbgfs_##name##_ops = {	\
 	.write = il_dbgfs_##name##_write,			\
 	.read = il_dbgfs_##name##_read,				\
-	.open = il_dbgfs_open_file_generic,			\
+	.open = simple_open,					\
 	.llseek = generic_file_llseek,				\
 };
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 53f8c51..7e590b3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -3083,11 +3083,6 @@
 }
 
 #ifdef CONFIG_MAC80211_DEBUGFS
-static int open_file_generic(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
 static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
 			     u32 *rate_n_flags, int index)
 {
@@ -3226,7 +3221,7 @@
 static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
 	.write = rs_sta_dbgfs_scale_table_write,
 	.read = rs_sta_dbgfs_scale_table_read,
-	.open = open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
@@ -3269,7 +3264,7 @@
 
 static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
 	.read = rs_sta_dbgfs_stats_table_read,
-	.open = open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -3295,7 +3290,7 @@
 
 static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = {
 	.read = rs_sta_dbgfs_rate_scale_data_read,
-	.open = open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
index 44c6f71..f4b84d1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
@@ -796,7 +796,7 @@
 
 	offset = (void *)hdr - rxb_addr(rxb);
 	p = rxb_steal_page(rxb);
-	skb_add_rx_frag(skb, 0, p, offset, len);
+	skb_add_rx_frag(skb, 0, p, offset, len, len);
 
 	iwl_update_stats(priv, false, fc, len);
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index b7b1c04..2bbaebd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -84,17 +84,11 @@
 					size_t count, loff_t *ppos);
 
 
-static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 #define DEBUGFS_READ_FILE_OPS(name)                                     \
 	DEBUGFS_READ_FUNC(name);                                        \
 static const struct file_operations iwl_dbgfs_##name##_ops = {          \
 	.read = iwl_dbgfs_##name##_read,                       		\
-	.open = iwl_dbgfs_open_file_generic,                    	\
+	.open = simple_open,						\
 	.llseek = generic_file_llseek,					\
 };
 
@@ -102,7 +96,7 @@
 	DEBUGFS_WRITE_FUNC(name);                                       \
 static const struct file_operations iwl_dbgfs_##name##_ops = {          \
 	.write = iwl_dbgfs_##name##_write,                              \
-	.open = iwl_dbgfs_open_file_generic,                    	\
+	.open = simple_open,						\
 	.llseek = generic_file_llseek,					\
 };
 
@@ -113,7 +107,7 @@
 static const struct file_operations iwl_dbgfs_##name##_ops = {          \
 	.write = iwl_dbgfs_##name##_write,                              \
 	.read = iwl_dbgfs_##name##_read,                                \
-	.open = iwl_dbgfs_open_file_generic,                            \
+	.open = simple_open,						\
 	.llseek = generic_file_llseek,					\
 };
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
index b4f796c..4d7b30d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
@@ -1898,17 +1898,11 @@
 					size_t count, loff_t *ppos);
 
 
-static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 #define DEBUGFS_READ_FILE_OPS(name)					\
 	DEBUGFS_READ_FUNC(name);					\
 static const struct file_operations iwl_dbgfs_##name##_ops = {		\
 	.read = iwl_dbgfs_##name##_read,				\
-	.open = iwl_dbgfs_open_file_generic,				\
+	.open = simple_open,						\
 	.llseek = generic_file_llseek,					\
 };
 
@@ -1916,7 +1910,7 @@
 	DEBUGFS_WRITE_FUNC(name);                                       \
 static const struct file_operations iwl_dbgfs_##name##_ops = {          \
 	.write = iwl_dbgfs_##name##_write,                              \
-	.open = iwl_dbgfs_open_file_generic,				\
+	.open = simple_open,						\
 	.llseek = generic_file_llseek,					\
 };
 
@@ -1926,7 +1920,7 @@
 static const struct file_operations iwl_dbgfs_##name##_ops = {		\
 	.write = iwl_dbgfs_##name##_write,				\
 	.read = iwl_dbgfs_##name##_read,				\
-	.open = iwl_dbgfs_open_file_generic,				\
+	.open = simple_open,						\
 	.llseek = generic_file_llseek,					\
 };
 
diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c
index 87eef57..b6199d1 100644
--- a/drivers/net/wireless/iwmc3200wifi/debugfs.c
+++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c
@@ -99,12 +99,6 @@
 			iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write,
 			"%llu\n");
 
-static int iwm_generic_open(struct inode *inode, struct file *filp)
-{
-	filp->private_data = inode->i_private;
-	return 0;
-}
-
 
 static ssize_t iwm_debugfs_txq_read(struct file *filp, char __user *buffer,
 				   size_t count, loff_t *ppos)
@@ -401,28 +395,28 @@
 
 static const struct file_operations iwm_debugfs_txq_fops = {
 	.owner =	THIS_MODULE,
-	.open =		iwm_generic_open,
+	.open =		simple_open,
 	.read =		iwm_debugfs_txq_read,
 	.llseek =	default_llseek,
 };
 
 static const struct file_operations iwm_debugfs_tx_credit_fops = {
 	.owner =	THIS_MODULE,
-	.open =		iwm_generic_open,
+	.open =		simple_open,
 	.read =		iwm_debugfs_tx_credit_read,
 	.llseek =	default_llseek,
 };
 
 static const struct file_operations iwm_debugfs_rx_ticket_fops = {
 	.owner =	THIS_MODULE,
-	.open =		iwm_generic_open,
+	.open =		simple_open,
 	.read =		iwm_debugfs_rx_ticket_read,
 	.llseek =	default_llseek,
 };
 
 static const struct file_operations iwm_debugfs_fw_err_fops = {
 	.owner =	THIS_MODULE,
-	.open =		iwm_generic_open,
+	.open =		simple_open,
 	.read =		iwm_debugfs_fw_err_read,
 	.llseek =	default_llseek,
 };
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c
index 764b40d..0042f20 100644
--- a/drivers/net/wireless/iwmc3200wifi/sdio.c
+++ b/drivers/net/wireless/iwmc3200wifi/sdio.c
@@ -264,13 +264,6 @@
 	return ret;
 }
 
-/* debugfs hooks */
-static int iwm_debugfs_sdio_open(struct inode *inode, struct file *filp)
-{
-	filp->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t iwm_debugfs_sdio_read(struct file *filp, char __user *buffer,
 				     size_t count, loff_t *ppos)
 {
@@ -363,7 +356,7 @@
 
 static const struct file_operations iwm_debugfs_sdio_fops = {
 	.owner =	THIS_MODULE,
-	.open =		iwm_debugfs_sdio_open,
+	.open =		simple_open,
 	.read =		iwm_debugfs_sdio_read,
 	.llseek =	default_llseek,
 };
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index c192671..a06cc28 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -21,12 +21,6 @@
 static void lbs_debug_init(struct lbs_private *priv);
 #endif
 
-static int open_file_generic(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t write_file_dummy(struct file *file, const char __user *buf,
                                 size_t count, loff_t *ppos)
 {
@@ -696,7 +690,7 @@
 
 #define FOPS(fread, fwrite) { \
 	.owner = THIS_MODULE, \
-	.open = open_file_generic, \
+	.open = simple_open, \
 	.read = (fread), \
 	.write = (fwrite), \
 	.llseek = generic_file_llseek, \
@@ -962,7 +956,7 @@
 
 static const struct file_operations lbs_debug_fops = {
 	.owner = THIS_MODULE,
-	.open = open_file_generic,
+	.open = simple_open,
 	.write = lbs_debugfs_write,
 	.read = lbs_debugfs_read,
 	.llseek = default_llseek,
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
index d26a78b..1a84507 100644
--- a/drivers/net/wireless/mwifiex/debugfs.c
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -140,18 +140,6 @@
 static int num_of_items = ARRAY_SIZE(items);
 
 /*
- * Generic proc file open handler.
- *
- * This function is called every time a file is accessed for read or write.
- */
-static int
-mwifiex_open_generic(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-/*
  * Proc info file read handler.
  *
  * This function is called when the 'info' file is opened for reading.
@@ -676,19 +664,19 @@
 static const struct file_operations mwifiex_dfs_##name##_fops = {       \
 	.read = mwifiex_##name##_read,                                  \
 	.write = mwifiex_##name##_write,                                \
-	.open = mwifiex_open_generic,                                   \
+	.open = simple_open,                                            \
 };
 
 #define MWIFIEX_DFS_FILE_READ_OPS(name)                                 \
 static const struct file_operations mwifiex_dfs_##name##_fops = {       \
 	.read = mwifiex_##name##_read,                                  \
-	.open = mwifiex_open_generic,                                   \
+	.open = simple_open,                                            \
 };
 
 #define MWIFIEX_DFS_FILE_WRITE_OPS(name)                                \
 static const struct file_operations mwifiex_dfs_##name##_fops = {       \
 	.write = mwifiex_##name##_write,                                \
-	.open = mwifiex_open_generic,                                   \
+	.open = simple_open,                                            \
 };
 
 
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index dd6c64a..88e3ad2 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -1336,6 +1336,10 @@
 	unsigned long flags;
 
 	sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
+	if (!sd) {
+		printk(KERN_ERR "%s: failed to alloc memory\n", __func__);
+		return;
+	}
 	sd->buf = buf;
 	sd->len = len;
 	sd->type = type;
@@ -1353,6 +1357,10 @@
 	unsigned long flags;
 
 	sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
+	if (!sd) {
+		printk(KERN_ERR "%s: failed to alloc memory\n", __func__);
+		return;
+	}
 	sd->len = -1; /* Abort */
 
 	spin_lock_irqsave(&priv->scan_lock, flags);
diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c
index 851fa10..c5404cb 100644
--- a/drivers/net/wireless/prism54/islpci_mgt.c
+++ b/drivers/net/wireless/prism54/islpci_mgt.c
@@ -24,7 +24,6 @@
 #include <linux/slab.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <linux/if_arp.h>
 
 #include "prismcompat.h"
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 04fec1f..86a738b 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -53,7 +53,6 @@
 #include <net/iw_handler.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 
diff --git a/drivers/net/wireless/wl1251/debugfs.c b/drivers/net/wireless/wl1251/debugfs.c
index 6c27400..448da1f 100644
--- a/drivers/net/wireless/wl1251/debugfs.c
+++ b/drivers/net/wireless/wl1251/debugfs.c
@@ -47,7 +47,7 @@
 									\
 static const struct file_operations name## _ops = {			\
 	.read = name## _read,						\
-	.open = wl1251_open_file_generic,				\
+	.open = simple_open,						\
 	.llseek	= generic_file_llseek,					\
 };
 
@@ -84,7 +84,7 @@
 									\
 static const struct file_operations sub## _ ##name## _ops = {		\
 	.read = sub## _ ##name## _read,					\
-	.open = wl1251_open_file_generic,				\
+	.open = simple_open,						\
 	.llseek	= generic_file_llseek,					\
 };
 
@@ -117,12 +117,6 @@
 	mutex_unlock(&wl->mutex);
 }
 
-static int wl1251_open_file_generic(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u");
 
 DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u");
@@ -235,7 +229,7 @@
 
 static const struct file_operations tx_queue_len_ops = {
 	.read = tx_queue_len_read,
-	.open = wl1251_open_file_generic,
+	.open = simple_open,
 	.llseek = generic_file_llseek,
 };
 
@@ -257,7 +251,7 @@
 
 static const struct file_operations tx_queue_status_ops = {
 	.read = tx_queue_status_read,
-	.open = wl1251_open_file_generic,
+	.open = simple_open,
 	.llseek = generic_file_llseek,
 };
 
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index e1cf727..564d495 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -63,7 +63,7 @@
 									\
 static const struct file_operations name## _ops = {			\
 	.read = name## _read,						\
-	.open = wl1271_open_file_generic,				\
+	.open = simple_open,						\
 	.llseek	= generic_file_llseek,					\
 };
 
@@ -96,7 +96,7 @@
 									\
 static const struct file_operations sub## _ ##name## _ops = {		\
 	.read = sub## _ ##name## _read,					\
-	.open = wl1271_open_file_generic,				\
+	.open = simple_open,						\
 	.llseek	= generic_file_llseek,					\
 };
 
@@ -126,12 +126,6 @@
 	mutex_unlock(&wl->mutex);
 }
 
-static int wl1271_open_file_generic(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u");
 
 DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u");
@@ -243,7 +237,7 @@
 
 static const struct file_operations tx_queue_len_ops = {
 	.read = tx_queue_len_read,
-	.open = wl1271_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -289,7 +283,7 @@
 static const struct file_operations gpio_power_ops = {
 	.read = gpio_power_read,
 	.write = gpio_power_write,
-	.open = wl1271_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -308,7 +302,7 @@
 
 static const struct file_operations start_recovery_ops = {
 	.write = start_recovery_write,
-	.open = wl1271_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -372,7 +366,7 @@
 static const struct file_operations dynamic_ps_timeout_ops = {
 	.read = dynamic_ps_timeout_read,
 	.write = dynamic_ps_timeout_write,
-	.open = wl1271_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -441,7 +435,7 @@
 static const struct file_operations forced_ps_ops = {
 	.read = forced_ps_read,
 	.write = forced_ps_write,
-	.open = wl1271_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -483,7 +477,7 @@
 static const struct file_operations split_scan_timeout_ops = {
 	.read = split_scan_timeout_read,
 	.write = split_scan_timeout_write,
-	.open = wl1271_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -566,7 +560,7 @@
 
 static const struct file_operations driver_state_ops = {
 	.read = driver_state_read,
-	.open = wl1271_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -675,7 +669,7 @@
 
 static const struct file_operations vifs_state_ops = {
 	.read = vifs_state_read,
-	.open = wl1271_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -733,7 +727,7 @@
 static const struct file_operations dtim_interval_ops = {
 	.read = dtim_interval_read,
 	.write = dtim_interval_write,
-	.open = wl1271_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -791,7 +785,7 @@
 static const struct file_operations suspend_dtim_interval_ops = {
 	.read = suspend_dtim_interval_read,
 	.write = suspend_dtim_interval_write,
-	.open = wl1271_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -849,7 +843,7 @@
 static const struct file_operations beacon_interval_ops = {
 	.read = beacon_interval_read,
 	.write = beacon_interval_write,
-	.open = wl1271_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -904,7 +898,7 @@
 static const struct file_operations rx_streaming_interval_ops = {
 	.read = rx_streaming_interval_read,
 	.write = rx_streaming_interval_write,
-	.open = wl1271_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -959,7 +953,7 @@
 static const struct file_operations rx_streaming_always_ops = {
 	.read = rx_streaming_always_read,
 	.write = rx_streaming_always_write,
-	.open = wl1271_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
@@ -1003,7 +997,7 @@
 
 static const struct file_operations beacon_filtering_ops = {
 	.write = beacon_filtering_write,
-	.open = wl1271_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 98fbf54..00f6e69 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -53,7 +53,6 @@
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #include "wl3501.h"
 
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index b161750..663b32c 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -47,6 +47,7 @@
 #include <xen/xenbus.h>
 #include <xen/events.h>
 #include <xen/page.h>
+#include <xen/platform_pci.h>
 #include <xen/grant_table.h>
 
 #include <xen/interface/io/netif.h>
@@ -1964,6 +1965,9 @@
 	if (xen_initial_domain())
 		return 0;
 
+	if (!xen_platform_pci_unplug)
+		return -ENODEV;
+
 	printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n");
 
 	return xenbus_register_frontend(&netfront_driver);
diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c
index b764ac22d..44d01af 100644
--- a/drivers/nubus/nubus.c
+++ b/drivers/nubus/nubus.c
@@ -17,7 +17,6 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <asm/setup.h>
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/hwtest.h>
 #include <linux/proc_fs.h>
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 6ea51dc..8e84ce9 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -91,4 +91,8 @@
 	help
 	  OpenFirmware PCI IRQ routing helpers
 
+config OF_MTD
+	depends on MTD
+	def_bool y
+
 endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index a73f5a5..aa90e60 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -12,3 +12,4 @@
 obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
 obj-$(CONFIG_OF_PCI)	+= of_pci.o
 obj-$(CONFIG_OF_PCI_IRQ)  += of_pci_irq.o
+obj-$(CONFIG_OF_MTD)	+= of_mtd.o
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
index 7e62d15..bba8121 100644
--- a/drivers/of/gpio.c
+++ b/drivers/of/gpio.c
@@ -78,8 +78,9 @@
 EXPORT_SYMBOL(of_get_named_gpio_flags);
 
 /**
- * of_gpio_count - Count GPIOs for a device
+ * of_gpio_named_count - Count GPIOs for a device
  * @np:		device node to count GPIOs for
+ * @propname:	property name containing gpio specifier(s)
  *
  * The function returns the count of GPIOs specified for a node.
  *
@@ -93,14 +94,14 @@
  * defines four GPIOs (so this function will return 4), two of which
  * are not specified.
  */
-unsigned int of_gpio_count(struct device_node *np)
+unsigned int of_gpio_named_count(struct device_node *np, const char* propname)
 {
 	unsigned int cnt = 0;
 
 	do {
 		int ret;
 
-		ret = of_parse_phandle_with_args(np, "gpios", "#gpio-cells",
+		ret = of_parse_phandle_with_args(np, propname, "#gpio-cells",
 						 cnt, NULL);
 		/* A hole in the gpios = <> counts anyway. */
 		if (ret < 0 && ret != -EEXIST)
@@ -109,7 +110,7 @@
 
 	return cnt;
 }
-EXPORT_SYMBOL(of_gpio_count);
+EXPORT_SYMBOL(of_gpio_named_count);
 
 /**
  * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
@@ -228,7 +229,7 @@
 }
 
 /* Private function for resolving node pointer to gpio_chip */
-static int of_gpiochip_is_match(struct gpio_chip *chip, void *data)
+static int of_gpiochip_is_match(struct gpio_chip *chip, const void *data)
 {
 	return chip->of_node == data;
 }
diff --git a/drivers/of/of_mtd.c b/drivers/of/of_mtd.c
new file mode 100644
index 0000000..e7cad62
--- /dev/null
+++ b/drivers/of/of_mtd.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * OF helpers for mtd.
+ *
+ * This file is released under the GPLv2
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/of_mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/export.h>
+
+/**
+ * It maps 'enum nand_ecc_modes_t' found in include/linux/mtd/nand.h
+ * into the device tree binding of 'nand-ecc', so that MTD
+ * device driver can get nand ecc from device tree.
+ */
+static const char *nand_ecc_modes[] = {
+	[NAND_ECC_NONE]		= "none",
+	[NAND_ECC_SOFT]		= "soft",
+	[NAND_ECC_HW]		= "hw",
+	[NAND_ECC_HW_SYNDROME]	= "hw_syndrome",
+	[NAND_ECC_HW_OOB_FIRST]	= "hw_oob_first",
+	[NAND_ECC_SOFT_BCH]	= "soft_bch",
+};
+
+/**
+ * of_get_nand_ecc_mode - Get nand ecc mode for given device_node
+ * @np:	Pointer to the given device_node
+ *
+ * The function gets ecc mode string from property 'nand-ecc-mode',
+ * and return its index in nand_ecc_modes table, or errno in error case.
+ */
+const int of_get_nand_ecc_mode(struct device_node *np)
+{
+	const char *pm;
+	int err, i;
+
+	err = of_property_read_string(np, "nand-ecc-mode", &pm);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i < ARRAY_SIZE(nand_ecc_modes); i++)
+		if (!strcasecmp(pm, nand_ecc_modes[i]))
+			return i;
+
+	return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(of_get_nand_ecc_mode);
+
+/**
+ * of_get_nand_bus_width - Get nand bus witdh for given device_node
+ * @np:	Pointer to the given device_node
+ *
+ * return bus width option, or errno in error case.
+ */
+int of_get_nand_bus_width(struct device_node *np)
+{
+	u32 val;
+
+	if (of_property_read_u32(np, "nand-bus-width", &val))
+		return 8;
+
+	switch(val) {
+	case 8:
+	case 16:
+		return val;
+	default:
+		return -EIO;
+	}
+}
+EXPORT_SYMBOL_GPL(of_get_nand_bus_width);
+
+/**
+ * of_get_nand_on_flash_bbt - Get nand on flash bbt for given device_node
+ * @np:	Pointer to the given device_node
+ *
+ * return true if present false other wise
+ */
+bool of_get_nand_on_flash_bbt(struct device_node *np)
+{
+	return of_property_read_bool(np, "nand-on-flash-bbt");
+}
+EXPORT_SYMBOL_GPL(of_get_nand_on_flash_bbt);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 20fbebd..343ad29 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -253,7 +253,7 @@
 	if (!of_device_is_available(node))
 		return NULL;
 
-	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	dev = amba_device_alloc(NULL, 0, 0);
 	if (!dev)
 		return NULL;
 
@@ -283,14 +283,14 @@
 	if (ret)
 		goto err_free;
 
-	ret = amba_device_register(dev, &iomem_resource);
+	ret = amba_device_add(dev, &iomem_resource);
 	if (ret)
 		goto err_free;
 
 	return dev;
 
 err_free:
-	kfree(dev);
+	amba_device_put(dev);
 	return NULL;
 }
 #else /* CONFIG_ARM_AMBA */
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
index 2f0aa0f..849357c 100644
--- a/drivers/oprofile/oprofilefs.c
+++ b/drivers/oprofile/oprofilefs.c
@@ -117,25 +117,17 @@
 }
 
 
-static int default_open(struct inode *inode, struct file *filp)
-{
-	if (inode->i_private)
-		filp->private_data = inode->i_private;
-	return 0;
-}
-
-
 static const struct file_operations ulong_fops = {
 	.read		= ulong_read_file,
 	.write		= ulong_write_file,
-	.open		= default_open,
+	.open		= simple_open,
 	.llseek		= default_llseek,
 };
 
 
 static const struct file_operations ulong_ro_fops = {
 	.read		= ulong_read_file,
-	.open		= default_open,
+	.open		= simple_open,
 	.llseek		= default_llseek,
 };
 
@@ -187,7 +179,7 @@
 
 static const struct file_operations atomic_ro_fops = {
 	.read		= atomic_read_file,
-	.open		= default_open,
+	.open		= simple_open,
 	.llseek		= default_llseek,
 };
 
@@ -238,7 +230,6 @@
 static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *root_inode;
-	struct dentry *root_dentry;
 
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -251,15 +242,11 @@
 		return -ENOMEM;
 	root_inode->i_op = &simple_dir_inode_operations;
 	root_inode->i_fop = &simple_dir_operations;
-	root_dentry = d_alloc_root(root_inode);
-	if (!root_dentry) {
-		iput(root_inode);
+	sb->s_root = d_make_root(root_inode);
+	if (!sb->s_root)
 		return -ENOMEM;
-	}
 
-	sb->s_root = root_dentry;
-
-	oprofile_create_files(sb, root_dentry);
+	oprofile_create_files(sb, sb->s_root);
 
 	// FIXME: verify kill_litter_super removes our dentries
 	return 0;
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 7ff10c1..432d4bb 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -55,7 +55,6 @@
 
 #include <asm/pdc.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/hardware.h>
 
@@ -553,7 +552,6 @@
 	struct list_head *ln;
         struct pci_dev *dev;
         struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->bridge));
-	int port_base = HBA_PORT_BASE(dino_dev->hba.hba_num);
 
 	DBG(KERN_WARNING "%s(0x%p) bus %d platform_data 0x%p\n",
 	    __func__, bus, bus->secondary,
@@ -599,8 +597,6 @@
 
 
 	list_for_each(ln, &bus->devices) {
-		int i;
-
 		dev = pci_dev_b(ln);
 		if (is_card_dino(&dino_dev->hba.dev->id))
 			dino_card_fixup(dev);
@@ -612,21 +608,6 @@
 		if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
 			continue;
 
-		/* Adjust the I/O Port space addresses */
-		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-			struct resource *res = &dev->resource[i];
-			if (res->flags & IORESOURCE_IO) {
-				res->start |= port_base;
-				res->end |= port_base;
-			}
-#ifdef __LP64__
-			/* Sign Extend MMIO addresses */
-			else if (res->flags & IORESOURCE_MEM) {
-				res->start |= F_EXTEND(0UL);
-				res->end   |= F_EXTEND(0UL);
-			}
-#endif
-		}
 		/* null out the ROM resource if there is one (we don't
 		 * care about an expansion rom on parisc, since it
 		 * usually contains (x86) bios code) */
@@ -991,11 +972,14 @@
 
 	dev->dev.platform_data = dino_dev;
 
-	pci_add_resource(&resources, &dino_dev->hba.io_space);
+	pci_add_resource_offset(&resources, &dino_dev->hba.io_space,
+				HBA_PORT_BASE(dino_dev->hba.hba_num));
 	if (dino_dev->hba.lmmio_space.flags)
-		pci_add_resource(&resources, &dino_dev->hba.lmmio_space);
+		pci_add_resource_offset(&resources, &dino_dev->hba.lmmio_space,
+					dino_dev->hba.lmmio_space_offset);
 	if (dino_dev->hba.elmmio_space.flags)
-		pci_add_resource(&resources, &dino_dev->hba.elmmio_space);
+		pci_add_resource_offset(&resources, &dino_dev->hba.elmmio_space,
+					dino_dev->hba.lmmio_space_offset);
 	if (dino_dev->hba.gmmio_space.flags)
 		pci_add_resource(&resources, &dino_dev->hba.gmmio_space);
 
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index 95930d0..1f9e9fe 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -140,7 +140,6 @@
 #include <asm/pdc.h>
 #include <asm/pdcpat.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <asm/io.h>		/* read/write functions */
 #ifdef CONFIG_SUPERIO
 #include <asm/superio.h>
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index d5f3d75..052fa23 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -43,7 +43,6 @@
 #include <asm/pdc.h>
 #include <asm/pdcpat.h>
 #include <asm/page.h>
-#include <asm/system.h>
 
 #include <asm/ropes.h>
 #include <asm/hardware.h>	/* for register_parisc_driver() stuff */
@@ -635,7 +634,6 @@
 	u16 status;
 #endif
 	struct lba_device *ldev = LBA_DEV(parisc_walk_tree(bus->bridge));
-	int lba_portbase = HBA_PORT_BASE(ldev->hba.hba_num);
 
 	DBG("lba_fixup_bus(0x%p) bus %d platform_data 0x%p\n",
 		bus, bus->secondary, bus->bridge->platform_data);
@@ -726,27 +724,6 @@
 			if (!res->start)
 				continue;
 
-			if (res->flags & IORESOURCE_IO) {
-				DBG("lba_fixup_bus() I/O Ports [%lx/%lx] -> ",
-					res->start, res->end);
-				res->start |= lba_portbase;
-				res->end   |= lba_portbase;
-				DBG("[%lx/%lx]\n", res->start, res->end);
-			} else if (res->flags & IORESOURCE_MEM) {
-				/*
-				** Convert PCI (IO_VIEW) addresses to
-				** processor (PA_VIEW) addresses
-				 */
-				DBG("lba_fixup_bus() MMIO [%lx/%lx] -> ",
-					res->start, res->end);
-				res->start = PCI_HOST_ADDR(HBA_DATA(ldev), res->start);
-				res->end   = PCI_HOST_ADDR(HBA_DATA(ldev), res->end);
-				DBG("[%lx/%lx]\n", res->start, res->end);
-			} else {
-				DBG("lba_fixup_bus() WTF? 0x%lx [%lx/%lx] XXX",
-					res->flags, res->start, res->end);
-			}
-
 			/*
 			** FIXME: this will result in whinging for devices
 			** that share expansion ROMs (think quad tulip), but
@@ -1514,11 +1491,14 @@
 		lba_dev->hba.lmmio_space.flags = 0;
 	}
 
-	pci_add_resource(&resources, &lba_dev->hba.io_space);
+	pci_add_resource_offset(&resources, &lba_dev->hba.io_space,
+				HBA_PORT_BASE(lba_dev->hba.hba_num));
 	if (lba_dev->hba.elmmio_space.start)
-		pci_add_resource(&resources, &lba_dev->hba.elmmio_space);
+		pci_add_resource_offset(&resources, &lba_dev->hba.elmmio_space,
+					lba_dev->hba.lmmio_space_offset);
 	if (lba_dev->hba.lmmio_space.flags)
-		pci_add_resource(&resources, &lba_dev->hba.lmmio_space);
+		pci_add_resource_offset(&resources, &lba_dev->hba.lmmio_space,
+					lba_dev->hba.lmmio_space_offset);
 	if (lba_dev->hba.gmmio_space.flags)
 		pci_add_resource(&resources, &lba_dev->hba.gmmio_space);
 
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 37856f7..848bfb8 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -31,6 +31,19 @@
 
 	  When in doubt, say N.
 
+config PCI_REALLOC_ENABLE_AUTO
+	bool "Enable PCI resource re-allocation detection"
+	depends on PCI
+	help
+	  Say Y here if you want the PCI core to detect if PCI resource
+	  re-allocation needs to be enabled. You can always use pci=realloc=on
+          or pci=realloc=off to override it.  Note this feature is a no-op
+          unless PCI_IOV support is also enabled; in that case it will
+          automatically re-allocate PCI resources if SR-IOV BARs have not
+          been allocated by the BIOS.
+
+	  When in doubt, say N.
+
 config PCI_STUB
 	tristate "PCI Stub driver"
 	depends on PCI
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 398f5d8..4ce5ef2 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -18,28 +18,36 @@
 
 #include "pci.h"
 
-void pci_add_resource(struct list_head *resources, struct resource *res)
+void pci_add_resource_offset(struct list_head *resources, struct resource *res,
+			     resource_size_t offset)
 {
-	struct pci_bus_resource *bus_res;
+	struct pci_host_bridge_window *window;
 
-	bus_res = kzalloc(sizeof(struct pci_bus_resource), GFP_KERNEL);
-	if (!bus_res) {
-		printk(KERN_ERR "PCI: can't add bus resource %pR\n", res);
+	window = kzalloc(sizeof(struct pci_host_bridge_window), GFP_KERNEL);
+	if (!window) {
+		printk(KERN_ERR "PCI: can't add host bridge window %pR\n", res);
 		return;
 	}
 
-	bus_res->res = res;
-	list_add_tail(&bus_res->list, resources);
+	window->res = res;
+	window->offset = offset;
+	list_add_tail(&window->list, resources);
+}
+EXPORT_SYMBOL(pci_add_resource_offset);
+
+void pci_add_resource(struct list_head *resources, struct resource *res)
+{
+	pci_add_resource_offset(resources, res, 0);
 }
 EXPORT_SYMBOL(pci_add_resource);
 
 void pci_free_resource_list(struct list_head *resources)
 {
-	struct pci_bus_resource *bus_res, *tmp;
+	struct pci_host_bridge_window *window, *tmp;
 
-	list_for_each_entry_safe(bus_res, tmp, resources, list) {
-		list_del(&bus_res->list);
-		kfree(bus_res);
+	list_for_each_entry_safe(window, tmp, resources, list) {
+		list_del(&window->list);
+		kfree(window);
 	}
 }
 EXPORT_SYMBOL(pci_free_resource_list);
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 9ddf69e..806c44f 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -800,20 +800,10 @@
 	if (slot->flags & SLOT_ENABLED)
 		goto err_exit;
 
-	/* sanity check: dev should be NULL when hot-plugged in */
-	dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
-	if (dev) {
-		/* This case shouldn't happen */
-		err("pci_dev structure already exists.\n");
-		pci_dev_put(dev);
-		retval = -1;
-		goto err_exit;
-	}
-
 	num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
 	if (num == 0) {
-		err("No new device found\n");
-		retval = -1;
+		/* Maybe only part of funcs are added. */
+		dbg("No new device found\n");
 		goto err_exit;
 	}
 
@@ -848,11 +838,16 @@
 
 	pci_bus_add_devices(bus);
 
+	slot->flags |= SLOT_ENABLED;
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
 						  func->function));
-		if (!dev)
+		if (!dev) {
+			/* Do not set SLOT_ENABLED flag if some funcs
+			   are not added. */
+			slot->flags &= (~SLOT_ENABLED);
 			continue;
+		}
 
 		if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
 		    dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) {
@@ -867,7 +862,6 @@
 		pci_dev_put(dev);
 	}
 
-	slot->flags |= SLOT_ENABLED;
 
  err_exit:
 	return retval;
@@ -892,9 +886,12 @@
 {
 	struct acpiphp_func *func;
 	struct pci_dev *pdev;
+	struct pci_bus *bus = slot->bridge->pci_bus;
 
-	/* is this slot already disabled? */
-	if (!(slot->flags & SLOT_ENABLED))
+	/* The slot will be enabled when func 0 is added, so check
+	   func 0 before disable the slot. */
+	pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
+	if (!pdev)
 		goto err_exit;
 
 	list_for_each_entry(func, &slot->funcs, sibling) {
@@ -913,7 +910,7 @@
 				disable_bridges(pdev->subordinate);
 				pci_disable_device(pdev);
 			}
-			pci_remove_bus_device(pdev);
+			__pci_remove_bus_device(pdev);
 			pci_dev_put(pdev);
 		}
 	}
@@ -1070,7 +1067,7 @@
 					res->end) {
 				/* Could not assign a required resources
 				 * for this device, remove it */
-				pci_remove_bus_device(dev);
+				pci_stop_and_remove_bus_device(dev);
 				break;
 			}
 		}
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
index 829c327..ae853cc 100644
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -341,7 +341,7 @@
 		dev = pci_get_slot(slot->bus,
 				    PCI_DEVFN(PCI_SLOT(slot->devfn), i));
 		if (dev) {
-			pci_remove_bus_device(dev);
+			pci_stop_and_remove_bus_device(dev);
 			pci_dev_put(dev);
 		}
 	}
diff --git a/drivers/pci/hotplug/cpcihp_generic.c b/drivers/pci/hotplug/cpcihp_generic.c
index fb3f846..81af764 100644
--- a/drivers/pci/hotplug/cpcihp_generic.c
+++ b/drivers/pci/hotplug/cpcihp_generic.c
@@ -62,7 +62,7 @@
 #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
 
 /* local variables */
-static int debug;
+static bool debug;
 static char *bridge;
 static u8 bridge_busnr;
 static u8 bridge_slot;
diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c
index 6173b9a..1c84940 100644
--- a/drivers/pci/hotplug/cpqphp_pci.c
+++ b/drivers/pci/hotplug/cpqphp_pci.c
@@ -127,7 +127,7 @@
 		struct pci_dev* temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j));
 		if (temp) {
 			pci_dev_put(temp);
-			pci_remove_bus_device(temp);
+			pci_stop_and_remove_bus_device(temp);
 		}
 	}
 	return 0;
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
index 17d10e2..a019c9a 100644
--- a/drivers/pci/hotplug/fakephp.c
+++ b/drivers/pci/hotplug/fakephp.c
@@ -40,7 +40,7 @@
 
 static void remove_callback(void *data)
 {
-	pci_remove_bus_device((struct pci_dev *)data);
+	pci_stop_and_remove_bus_device((struct pci_dev *)data);
 }
 
 static ssize_t legacy_store(struct kobject *kobj, struct attribute *attr,
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
index 5506e0e..4fda7e6 100644
--- a/drivers/pci/hotplug/ibmphp_core.c
+++ b/drivers/pci/hotplug/ibmphp_core.c
@@ -721,7 +721,7 @@
 	for (j = 0; j < 0x08; j++) {
 		temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j);
 		if (temp) {
-			pci_remove_bus_device(temp);
+			pci_stop_and_remove_bus_device(temp);
 			pci_dev_put(temp);
 		}
 	}
diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c
index 2850e64..714ca5c 100644
--- a/drivers/pci/hotplug/ibmphp_ebda.c
+++ b/drivers/pci/hotplug/ibmphp_ebda.c
@@ -368,8 +368,10 @@
 			debug ("rio blk id: %x\n", blk_id);
 
 			rio_table_ptr = kzalloc(sizeof(struct rio_table_hdr), GFP_KERNEL);
-			if (!rio_table_ptr)
-				return -ENOMEM; 
+			if (!rio_table_ptr) {
+				rc = -ENOMEM;
+				goto out;
+			}
 			rio_table_ptr->ver_num = readb (io_mem + offset);
 			rio_table_ptr->scal_count = readb (io_mem + offset + 1);
 			rio_table_ptr->riodev_count = readb (io_mem + offset + 2);
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index bcdbb16..a960fae 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -241,34 +241,79 @@
 	return retval;
 }
 
-static inline int check_link_active(struct controller *ctrl)
+static bool check_link_active(struct controller *ctrl)
 {
-	u16 link_status;
+	bool ret = false;
+	u16 lnk_status;
 
-	if (pciehp_readw(ctrl, PCI_EXP_LNKSTA, &link_status))
-		return 0;
-	return !!(link_status & PCI_EXP_LNKSTA_DLLLA);
+	if (pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status))
+		return ret;
+
+	ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
+
+	if (ret)
+		ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status);
+
+	return ret;
 }
 
-static void pcie_wait_link_active(struct controller *ctrl)
+static void __pcie_wait_link_active(struct controller *ctrl, bool active)
 {
 	int timeout = 1000;
 
-	if (check_link_active(ctrl))
+	if (check_link_active(ctrl) == active)
 		return;
 	while (timeout > 0) {
 		msleep(10);
 		timeout -= 10;
-		if (check_link_active(ctrl))
+		if (check_link_active(ctrl) == active)
 			return;
 	}
-	ctrl_dbg(ctrl, "Data Link Layer Link Active not set in 1000 msec\n");
+	ctrl_dbg(ctrl, "Data Link Layer Link Active not %s in 1000 msec\n",
+			active ? "set" : "cleared");
+}
+
+static void pcie_wait_link_active(struct controller *ctrl)
+{
+	__pcie_wait_link_active(ctrl, true);
+}
+
+static void pcie_wait_link_not_active(struct controller *ctrl)
+{
+	__pcie_wait_link_active(ctrl, false);
+}
+
+static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
+{
+	u32 l;
+	int count = 0;
+	int delay = 1000, step = 20;
+	bool found = false;
+
+	do {
+		found = pci_bus_read_dev_vendor_id(bus, devfn, &l, 0);
+		count++;
+
+		if (found)
+			break;
+
+		msleep(step);
+		delay -= step;
+	} while (delay > 0);
+
+	if (count > 1 && pciehp_debug)
+		printk(KERN_DEBUG "pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n",
+			pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
+			PCI_FUNC(devfn), count, step, l);
+
+	return found;
 }
 
 int pciehp_check_link_status(struct controller *ctrl)
 {
 	u16 lnk_status;
 	int retval = 0;
+	bool found = false;
 
         /*
          * Data Link Layer Link Active Reporting must be capable for
@@ -280,13 +325,10 @@
         else
                 msleep(1000);
 
-	/*
-	 * Need to wait for 1000 ms after Data Link Layer Link Active
-	 * (DLLLA) bit reads 1b before sending configuration request.
-	 * We need it before checking Link Training (LT) bit becuase
-	 * LT is still set even after DLLLA bit is set on some platform.
-	 */
-	msleep(1000);
+	/* wait 100ms before read pci conf, and try in 1s */
+	msleep(100);
+	found = pci_bus_check_dev(ctrl->pcie->port->subordinate,
+					PCI_DEVFN(0, 0));
 
 	retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status);
 	if (retval) {
@@ -302,19 +344,50 @@
 		return retval;
 	}
 
-	/*
-	 * If the port supports Link speeds greater than 5.0 GT/s, we
-	 * must wait for 100 ms after Link training completes before
-	 * sending configuration request.
-	 */
-	if (ctrl->pcie->port->subordinate->max_bus_speed > PCIE_SPEED_5_0GT)
-		msleep(100);
-
 	pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status);
 
+	if (!found && !retval)
+		retval = -1;
+
 	return retval;
 }
 
+static int __pciehp_link_set(struct controller *ctrl, bool enable)
+{
+	u16 lnk_ctrl;
+	int retval = 0;
+
+	retval = pciehp_readw(ctrl, PCI_EXP_LNKCTL, &lnk_ctrl);
+	if (retval) {
+		ctrl_err(ctrl, "Cannot read LNKCTRL register\n");
+		return retval;
+	}
+
+	if (enable)
+		lnk_ctrl &= ~PCI_EXP_LNKCTL_LD;
+	else
+		lnk_ctrl |= PCI_EXP_LNKCTL_LD;
+
+	retval = pciehp_writew(ctrl, PCI_EXP_LNKCTL, lnk_ctrl);
+	if (retval) {
+		ctrl_err(ctrl, "Cannot write LNKCTRL register\n");
+		return retval;
+	}
+	ctrl_dbg(ctrl, "%s: lnk_ctrl = %x\n", __func__, lnk_ctrl);
+
+	return retval;
+}
+
+static int pciehp_link_enable(struct controller *ctrl)
+{
+	return __pciehp_link_set(ctrl, true);
+}
+
+static int pciehp_link_disable(struct controller *ctrl)
+{
+	return __pciehp_link_set(ctrl, false);
+}
+
 int pciehp_get_attention_status(struct slot *slot, u8 *status)
 {
 	struct controller *ctrl = slot->ctrl;
@@ -533,6 +606,10 @@
 	ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
 		 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
 
+	retval = pciehp_link_enable(ctrl);
+	if (retval)
+		ctrl_err(ctrl, "%s: Can not enable the link!\n", __func__);
+
 	return retval;
 }
 
@@ -543,6 +620,14 @@
 	u16 cmd_mask;
 	int retval;
 
+	/* Disable the link at first */
+	pciehp_link_disable(ctrl);
+	/* wait the link is down */
+	if (ctrl->link_active_reporting)
+		pcie_wait_link_not_active(ctrl);
+	else
+		msleep(1000);
+
 	slot_cmd = POWER_OFF;
 	cmd_mask = PCI_EXP_SLTCTL_PCC;
 	retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index a4031df..47d9dc0 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -141,7 +141,7 @@
 				break;
 			}
 		}
-		pci_remove_bus_device(temp);
+		pci_stop_and_remove_bus_device(temp);
 		/*
 		 * Ensure that no new Requests will be generated from
 		 * the device.
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index c56a941..1e117c2 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -389,7 +389,7 @@
 	BUG_ON(!bus->self);
 	pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
 	eeh_remove_bus_device(bus->self);
-	pci_remove_bus_device(bus->self);
+	pci_stop_and_remove_bus_device(bus->self);
 
 	return 0;
 }
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index 72d507b..de57311 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -554,7 +554,7 @@
 				   	     PCI_FUNC(func)));
 		if (dev) {
 			sn_bus_free_data(dev);
-			pci_remove_bus_device(dev);
+			pci_stop_and_remove_bus_device(dev);
 			pci_dev_put(dev);
 		}
 	}
diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c
index a2ccfcd..df7e4bf 100644
--- a/drivers/pci/hotplug/shpchp_pci.c
+++ b/drivers/pci/hotplug/shpchp_pci.c
@@ -124,7 +124,7 @@
 				break;
 			}
 		}
-		pci_remove_bus_device(temp);
+		pci_stop_and_remove_bus_device(temp);
 		pci_dev_put(temp);
 	}
 	return rc;
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 0dab5ec..6554e1a 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -142,7 +142,7 @@
 failed1:
 	pci_dev_put(dev);
 	mutex_lock(&iov->dev->sriov->lock);
-	pci_remove_bus_device(virtfn);
+	pci_stop_and_remove_bus_device(virtfn);
 	virtfn_remove_bus(dev->bus, virtfn_bus(dev, id));
 	mutex_unlock(&iov->dev->sriov->lock);
 
@@ -173,10 +173,16 @@
 
 	sprintf(buf, "virtfn%u", id);
 	sysfs_remove_link(&dev->dev.kobj, buf);
-	sysfs_remove_link(&virtfn->dev.kobj, "physfn");
+	/*
+	 * pci_stop_dev() could have been called for this virtfn already,
+	 * so the directory for the virtfn may have been removed before.
+	 * Double check to avoid spurious sysfs warnings.
+	 */
+	if (virtfn->dev.kobj.sd)
+		sysfs_remove_link(&virtfn->dev.kobj, "physfn");
 
 	mutex_lock(&iov->dev->sriov->lock);
-	pci_remove_bus_device(virtfn);
+	pci_stop_and_remove_bus_device(virtfn);
 	virtfn_remove_bus(dev->bus, virtfn_bus(dev, id));
 	mutex_unlock(&iov->dev->sriov->lock);
 
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 060fd22..0f150f2 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -277,40 +277,6 @@
 	return 0;
 }
 
-/**
- * acpi_dev_run_wake - Enable/disable wake-up for given device.
- * @phys_dev: Device to enable/disable the platform to wake-up the system for.
- * @enable: Whether enable or disable the wake-up functionality.
- *
- * Find the ACPI device object corresponding to @pci_dev and try to
- * enable/disable the GPE associated with it.
- */
-static int acpi_dev_run_wake(struct device *phys_dev, bool enable)
-{
-	struct acpi_device *dev;
-	acpi_handle handle;
-
-	if (!device_run_wake(phys_dev))
-		return -EINVAL;
-
-	handle = DEVICE_ACPI_HANDLE(phys_dev);
-	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &dev))) {
-		dev_dbg(phys_dev, "ACPI handle has no context in %s!\n",
-			__func__);
-		return -ENODEV;
-	}
-
-	if (enable) {
-		acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0);
-		acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number);
-	} else {
-		acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number);
-		acpi_disable_wakeup_device_power(dev);
-	}
-
-	return 0;
-}
-
 static void acpi_pci_propagate_run_wake(struct pci_bus *bus, bool enable)
 {
 	while (bus->parent) {
@@ -318,14 +284,14 @@
 
 		if (bridge->pme_interrupt)
 			return;
-		if (!acpi_dev_run_wake(&bridge->dev, enable))
+		if (!acpi_pm_device_run_wake(&bridge->dev, enable))
 			return;
 		bus = bus->parent;
 	}
 
 	/* We have reached the root bus. */
 	if (bus->bridge)
-		acpi_dev_run_wake(bus->bridge, enable);
+		acpi_pm_device_run_wake(bus->bridge, enable);
 }
 
 static int acpi_pci_run_wake(struct pci_dev *dev, bool enable)
@@ -333,7 +299,7 @@
 	if (dev->pme_interrupt)
 		return 0;
 
-	if (!acpi_dev_run_wake(&dev->dev, enable))
+	if (!acpi_pm_device_run_wake(&dev->dev, enable))
 		return 0;
 
 	acpi_pci_propagate_run_wake(dev->bus, enable);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 8d9616b..6b54b23 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -419,6 +419,16 @@
 		drv->shutdown(pci_dev);
 	pci_msi_shutdown(pci_dev);
 	pci_msix_shutdown(pci_dev);
+
+	/*
+	 * Devices may be enabled to wake up by runtime PM, but they need not
+	 * be supposed to wake up the system from its "power off" state (e.g.
+	 * ACPI S5).  Therefore disable wakeup for all devices that aren't
+	 * supposed to wake up the system at this point.  The state argument
+	 * will be ignored by pci_enable_wake().
+	 */
+	if (!device_may_wakeup(dev))
+		pci_enable_wake(pci_dev, PCI_UNKNOWN, false);
 }
 
 #ifdef CONFIG_PM
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index a3cd8ca..a55e248 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -330,7 +330,7 @@
 	struct pci_dev *pdev = to_pci_dev(dev);
 
 	mutex_lock(&pci_remove_rescan_mutex);
-	pci_remove_bus_device(pdev);
+	pci_stop_and_remove_bus_device(pdev);
 	mutex_unlock(&pci_remove_rescan_mutex);
 }
 
@@ -366,7 +366,10 @@
 
 	if (val) {
 		mutex_lock(&pci_remove_rescan_mutex);
-		pci_rescan_bus(bus);
+		if (!pci_is_root_bus(bus) && list_empty(&bus->devices))
+			pci_rescan_bus_bridge_resize(bus->self);
+		else
+			pci_rescan_bus(bus);
 		mutex_unlock(&pci_remove_rescan_mutex);
 	}
 	return count;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index af295bb..8156744 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -94,6 +94,9 @@
  */
 unsigned int pcibios_max_latency = 255;
 
+/* If set, the PCIe ARI capability will not be used. */
+static bool pcie_ari_disabled;
+
 /**
  * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
  * @bus: pointer to PCI bus structure to search
@@ -825,6 +828,19 @@
 #define pcie_cap_has_sltctl2(type, flags)		\
 		((flags & PCI_EXP_FLAGS_VERS) > 1)
 
+static struct pci_cap_saved_state *pci_find_saved_cap(
+	struct pci_dev *pci_dev, char cap)
+{
+	struct pci_cap_saved_state *tmp;
+	struct hlist_node *pos;
+
+	hlist_for_each_entry(tmp, pos, &pci_dev->saved_cap_space, next) {
+		if (tmp->cap.cap_nr == cap)
+			return tmp;
+	}
+	return NULL;
+}
+
 static int pci_save_pcie_state(struct pci_dev *dev)
 {
 	int pos, i = 0;
@@ -959,6 +975,7 @@
 {
 	int i;
 	u32 val;
+	int tries;
 
 	if (!dev->state_saved)
 		return;
@@ -973,12 +990,16 @@
 	 */
 	for (i = 15; i >= 0; i--) {
 		pci_read_config_dword(dev, i * 4, &val);
-		if (val != dev->saved_config_space[i]) {
+		tries = 10;		
+		while (tries && val != dev->saved_config_space[i]) {
 			dev_dbg(&dev->dev, "restoring config "
 				"space at offset %#x (was %#x, writing %#x)\n",
 				i, val, (int)dev->saved_config_space[i]);
 			pci_write_config_dword(dev,i * 4,
 				dev->saved_config_space[i]);
+			pci_read_config_dword(dev, i * 4, &val);
+			mdelay(10);
+			tries--;
 		}
 	}
 	pci_restore_pcix_state(dev);
@@ -1864,6 +1885,12 @@
 	platform_pci_sleep_wake(dev, false);
 }
 
+static void pci_add_saved_cap(struct pci_dev *pci_dev,
+	struct pci_cap_saved_state *new_cap)
+{
+	hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space);
+}
+
 /**
  * pci_add_save_buffer - allocate buffer for saving given capability registers
  * @dev: the PCI device
@@ -1911,6 +1938,15 @@
 			"unable to preallocate PCI-X save buffer\n");
 }
 
+void pci_free_cap_save_buffers(struct pci_dev *dev)
+{
+	struct pci_cap_saved_state *tmp;
+	struct hlist_node *pos, *n;
+
+	hlist_for_each_entry_safe(tmp, pos, n, &dev->saved_cap_space, next)
+		kfree(tmp);
+}
+
 /**
  * pci_enable_ari - enable ARI forwarding if hardware support it
  * @dev: the PCI device
@@ -1922,7 +1958,7 @@
 	u16 flags, ctrl;
 	struct pci_dev *bridge;
 
-	if (!pci_is_pcie(dev) || dev->devfn)
+	if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn)
 		return;
 
 	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
@@ -3163,6 +3199,31 @@
 EXPORT_SYMBOL_GPL(__pci_reset_function);
 
 /**
+ * __pci_reset_function_locked - reset a PCI device function while holding
+ * the @dev mutex lock.
+ * @dev: PCI device to reset
+ *
+ * Some devices allow an individual function to be reset without affecting
+ * other functions in the same device.  The PCI device must be responsive
+ * to PCI config space in order to use this function.
+ *
+ * The device function is presumed to be unused and the caller is holding
+ * the device mutex lock when this function is called.
+ * Resetting the device will make the contents of PCI configuration space
+ * random, so any caller of this must be prepared to reinitialise the
+ * device including MSI, bus mastering, BARs, decoding IO and memory spaces,
+ * etc.
+ *
+ * Returns 0 if the device function was successfully reset or negative if the
+ * device doesn't support resetting a single function.
+ */
+int __pci_reset_function_locked(struct pci_dev *dev)
+{
+	return pci_dev_reset(dev, 1);
+}
+EXPORT_SYMBOL_GPL(__pci_reset_function_locked);
+
+/**
  * pci_probe_reset_function - check whether the device can be safely reset
  * @dev: PCI device to reset
  *
@@ -3636,6 +3697,68 @@
 	return (pci_specified_resource_alignment(dev) != 0);
 }
 
+/*
+ * This function disables memory decoding and releases memory resources
+ * of the device specified by kernel's boot parameter 'pci=resource_alignment='.
+ * It also rounds up size to specified alignment.
+ * Later on, the kernel will assign page-aligned memory resource back
+ * to the device.
+ */
+void pci_reassigndev_resource_alignment(struct pci_dev *dev)
+{
+	int i;
+	struct resource *r;
+	resource_size_t align, size;
+	u16 command;
+
+	if (!pci_is_reassigndev(dev))
+		return;
+
+	if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL &&
+	    (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) {
+		dev_warn(&dev->dev,
+			"Can't reassign resources to host bridge.\n");
+		return;
+	}
+
+	dev_info(&dev->dev,
+		"Disabling memory decoding and releasing memory resources.\n");
+	pci_read_config_word(dev, PCI_COMMAND, &command);
+	command &= ~PCI_COMMAND_MEMORY;
+	pci_write_config_word(dev, PCI_COMMAND, command);
+
+	align = pci_specified_resource_alignment(dev);
+	for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
+		r = &dev->resource[i];
+		if (!(r->flags & IORESOURCE_MEM))
+			continue;
+		size = resource_size(r);
+		if (size < align) {
+			size = align;
+			dev_info(&dev->dev,
+				"Rounding up size of resource #%d to %#llx.\n",
+				i, (unsigned long long)size);
+		}
+		r->end = size - 1;
+		r->start = 0;
+	}
+	/* Need to disable bridge's resource window,
+	 * to enable the kernel to reassign new resource
+	 * window later on.
+	 */
+	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
+	    (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+		for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
+			r = &dev->resource[i];
+			if (!(r->flags & IORESOURCE_MEM))
+				continue;
+			r->end = resource_size(r) - 1;
+			r->start = 0;
+		}
+		pci_disable_bridge_window(dev);
+	}
+}
+
 ssize_t pci_set_resource_alignment_param(const char *buf, size_t count)
 {
 	if (count > RESOURCE_ALIGNMENT_PARAM_SIZE - 1)
@@ -3714,10 +3837,14 @@
 				pci_no_msi();
 			} else if (!strcmp(str, "noaer")) {
 				pci_no_aer();
+			} else if (!strncmp(str, "realloc=", 8)) {
+				pci_realloc_get_opt(str + 8);
 			} else if (!strncmp(str, "realloc", 7)) {
-				pci_realloc();
+				pci_realloc_get_opt("on");
 			} else if (!strcmp(str, "nodomains")) {
 				pci_no_domains();
+			} else if (!strncmp(str, "noari", 5)) {
+				pcie_ari_disabled = true;
 			} else if (!strncmp(str, "cbiosize=", 9)) {
 				pci_cardbus_io_size = memparse(str + 9, &str);
 			} else if (!strncmp(str, "cbmemsize=", 10)) {
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 1009a5e..e494347 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -73,6 +73,7 @@
 extern void pci_pm_init(struct pci_dev *dev);
 extern void platform_pci_wakeup_init(struct pci_dev *dev);
 extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
+void pci_free_cap_save_buffers(struct pci_dev *dev);
 
 static inline void pci_wakeup_event(struct pci_dev *dev)
 {
@@ -148,7 +149,7 @@
 static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
 #endif
 
-extern void pci_realloc(void);
+void pci_realloc_get_opt(char *);
 
 static inline int pci_no_d1d2(struct pci_dev *dev)
 {
@@ -207,6 +208,8 @@
 	pci_bar_mem64,		/* A 64-bit memory BAR */
 };
 
+bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl,
+				int crs_timeout);
 extern int pci_setup_device(struct pci_dev *dev);
 extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
 				struct resource *res, unsigned int reg);
@@ -225,11 +228,8 @@
 	return bus->self && bus->self->ari_enabled;
 }
 
-#ifdef CONFIG_PCI_QUIRKS
-extern int pci_is_reassigndev(struct pci_dev *dev);
-resource_size_t pci_specified_resource_alignment(struct pci_dev *dev);
+void pci_reassigndev_resource_alignment(struct pci_dev *dev);
 extern void pci_disable_bridge_window(struct pci_dev *dev);
-#endif
 
 /* Single Root I/O Virtualization */
 struct pci_sriov {
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 72962cc..6c8bc58 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -55,6 +55,31 @@
 	  This enables PCI Express ASPM debug support. It will add per-device
 	  interface to control ASPM.
 
+choice
+	prompt "Default ASPM policy"
+	default PCIEASPM_DEFAULT
+	depends on PCIEASPM
+
+config PCIEASPM_DEFAULT
+        bool "BIOS default"
+	depends on PCIEASPM
+	help
+	  Use the BIOS defaults for PCI Express ASPM.
+
+config PCIEASPM_POWERSAVE
+        bool "Powersave"
+	depends on PCIEASPM
+	help
+	  Enable PCI Express ASPM L0s and L1 where possible, even if the
+	  BIOS did not.
+
+config PCIEASPM_PERFORMANCE
+        bool "Performance"
+	depends on PCIEASPM
+	help
+	  Disable PCI Express ASPM L0s and L1, even if the BIOS enabled them.
+endchoice
+
 config PCIE_PME
 	def_bool y
 	depends on PCIEPORTBUS && PM_RUNTIME && EXPERIMENTAL && ACPI
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 24f049e..b500840 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -76,7 +76,15 @@
 #define POLICY_DEFAULT 0	/* BIOS default setting */
 #define POLICY_PERFORMANCE 1	/* high performance */
 #define POLICY_POWERSAVE 2	/* high power saving */
+
+#ifdef CONFIG_PCIEASPM_PERFORMANCE
+static int aspm_policy = POLICY_PERFORMANCE;
+#elif defined CONFIG_PCIEASPM_POWERSAVE
+static int aspm_policy = POLICY_POWERSAVE;
+#else
 static int aspm_policy;
+#endif
+
 static const char *policy_str[] = {
 	[POLICY_DEFAULT] = "default",
 	[POLICY_PERFORMANCE] = "performance",
@@ -500,9 +508,6 @@
 	int pos;
 	u32 reg32;
 
-	if (aspm_disabled)
-		return 0;
-
 	/*
 	 * Some functions in a slot might not all be PCIe functions,
 	 * very strange. Disable ASPM for the whole slot
@@ -511,6 +516,16 @@
 		pos = pci_pcie_cap(child);
 		if (!pos)
 			return -EINVAL;
+
+		/*
+		 * If ASPM is disabled then we're not going to change
+		 * the BIOS state. It's safe to continue even if it's a
+		 * pre-1.1 device
+		 */
+
+		if (aspm_disabled)
+			continue;
+
 		/*
 		 * Disable ASPM for pre-1.1 PCIe device, we follow MS to use
 		 * RBER bit to determine if a function is 1.1 version device
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index bd00a01..eea2ca2 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -34,6 +34,18 @@
 
 extern void pcie_clear_root_pme_status(struct pci_dev *dev);
 
+#ifdef CONFIG_HOTPLUG_PCI_PCIE
+extern bool pciehp_msi_disabled;
+
+static inline bool pciehp_no_msi(void)
+{
+	return pciehp_msi_disabled;
+}
+
+#else  /* !CONFIG_HOTPLUG_PCI_PCIE */
+static inline bool pciehp_no_msi(void) { return false; }
+#endif /* !CONFIG_HOTPLUG_PCI_PCIE */
+
 #ifdef CONFIG_PCIE_PME
 extern bool pcie_pme_msi_disabled;
 
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 595654a..2f589a5 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -19,6 +19,17 @@
 #include "../pci.h"
 #include "portdrv.h"
 
+bool pciehp_msi_disabled;
+
+static int __init pciehp_setup(char *str)
+{
+	if (!strncmp(str, "nomsi", 5))
+		pciehp_msi_disabled = true;
+
+	return 1;
+}
+__setup("pcie_hp=", pciehp_setup);
+
 /**
  * release_pcie_device - free PCI Express port service device structure
  * @dev: Port service device to release
@@ -189,8 +200,9 @@
 {
 	int i, irq = -1;
 
-	/* We have to use INTx if MSI cannot be used for PCIe PME. */
-	if ((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) {
+	/* We have to use INTx if MSI cannot be used for PCIe PME or pciehp. */
+	if (((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) ||
+	    ((mask & PCIE_PORT_SERVICE_HP) && pciehp_no_msi())) {
 		if (dev->pin)
 			irq = dev->irq;
 		goto no_msi;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 71eac9c..5e1ca3c 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -15,6 +15,8 @@
 #define CARDBUS_LATENCY_TIMER	176	/* secondary latency timer */
 #define CARDBUS_RESERVE_BUSNR	3
 
+static LIST_HEAD(pci_host_bridges);
+
 /* Ugh.  Need to stop exporting this to modules. */
 LIST_HEAD(pci_root_buses);
 EXPORT_SYMBOL(pci_root_buses);
@@ -42,6 +44,82 @@
 }
 EXPORT_SYMBOL(no_pci_devices);
 
+static struct pci_host_bridge *pci_host_bridge(struct pci_dev *dev)
+{
+	struct pci_bus *bus;
+	struct pci_host_bridge *bridge;
+
+	bus = dev->bus;
+	while (bus->parent)
+		bus = bus->parent;
+
+	list_for_each_entry(bridge, &pci_host_bridges, list) {
+		if (bridge->bus == bus)
+			return bridge;
+	}
+
+	return NULL;
+}
+
+static bool resource_contains(struct resource *res1, struct resource *res2)
+{
+	return res1->start <= res2->start && res1->end >= res2->end;
+}
+
+void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+			     struct resource *res)
+{
+	struct pci_host_bridge *bridge = pci_host_bridge(dev);
+	struct pci_host_bridge_window *window;
+	resource_size_t offset = 0;
+
+	list_for_each_entry(window, &bridge->windows, list) {
+		if (resource_type(res) != resource_type(window->res))
+			continue;
+
+		if (resource_contains(window->res, res)) {
+			offset = window->offset;
+			break;
+		}
+	}
+
+	region->start = res->start - offset;
+	region->end = res->end - offset;
+}
+EXPORT_SYMBOL(pcibios_resource_to_bus);
+
+static bool region_contains(struct pci_bus_region *region1,
+			    struct pci_bus_region *region2)
+{
+	return region1->start <= region2->start && region1->end >= region2->end;
+}
+
+void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+			     struct pci_bus_region *region)
+{
+	struct pci_host_bridge *bridge = pci_host_bridge(dev);
+	struct pci_host_bridge_window *window;
+	struct pci_bus_region bus_region;
+	resource_size_t offset = 0;
+
+	list_for_each_entry(window, &bridge->windows, list) {
+		if (resource_type(res) != resource_type(window->res))
+			continue;
+
+		bus_region.start = window->res->start - window->offset;
+		bus_region.end = window->res->end - window->offset;
+
+		if (region_contains(&bus_region, region)) {
+			offset = window->offset;
+			break;
+		}
+	}
+
+	res->start = region->start + offset;
+	res->end = region->end + offset;
+}
+EXPORT_SYMBOL(pcibios_bus_to_resource);
+
 /*
  * PCI Bus Class
  */
@@ -135,6 +213,7 @@
 {
 	u32 l, sz, mask;
 	u16 orig_cmd;
+	struct pci_bus_region region;
 
 	mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
 
@@ -214,11 +293,13 @@
 			/* Address above 32-bit boundary; disable the BAR */
 			pci_write_config_dword(dev, pos, 0);
 			pci_write_config_dword(dev, pos + 4, 0);
-			res->start = 0;
-			res->end = sz64;
+			region.start = 0;
+			region.end = sz64;
+			pcibios_bus_to_resource(dev, res, &region);
 		} else {
-			res->start = l64;
-			res->end = l64 + sz64;
+			region.start = l64;
+			region.end = l64 + sz64;
+			pcibios_bus_to_resource(dev, res, &region);
 			dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n",
 				   pos, res);
 		}
@@ -228,8 +309,9 @@
 		if (!sz)
 			goto fail;
 
-		res->start = l;
-		res->end = l + sz;
+		region.start = l;
+		region.end = l + sz;
+		pcibios_bus_to_resource(dev, res, &region);
 
 		dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res);
 	}
@@ -266,7 +348,8 @@
 	struct pci_dev *dev = child->self;
 	u8 io_base_lo, io_limit_lo;
 	unsigned long base, limit;
-	struct resource *res;
+	struct pci_bus_region region;
+	struct resource *res, res2;
 
 	res = child->resource[0];
 	pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
@@ -284,10 +367,14 @@
 
 	if (base && base <= limit) {
 		res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
+		res2.flags = res->flags;
+		region.start = base;
+		region.end = limit + 0xfff;
+		pcibios_bus_to_resource(dev, &res2, &region);
 		if (!res->start)
-			res->start = base;
+			res->start = res2.start;
 		if (!res->end)
-			res->end = limit + 0xfff;
+			res->end = res2.end;
 		dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
 	}
 }
@@ -297,6 +384,7 @@
 	struct pci_dev *dev = child->self;
 	u16 mem_base_lo, mem_limit_lo;
 	unsigned long base, limit;
+	struct pci_bus_region region;
 	struct resource *res;
 
 	res = child->resource[1];
@@ -306,8 +394,9 @@
 	limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
 	if (base && base <= limit) {
 		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
-		res->start = base;
-		res->end = limit + 0xfffff;
+		region.start = base;
+		region.end = limit + 0xfffff;
+		pcibios_bus_to_resource(dev, res, &region);
 		dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
 	}
 }
@@ -317,6 +406,7 @@
 	struct pci_dev *dev = child->self;
 	u16 mem_base_lo, mem_limit_lo;
 	unsigned long base, limit;
+	struct pci_bus_region region;
 	struct resource *res;
 
 	res = child->resource[2];
@@ -353,8 +443,9 @@
 					 IORESOURCE_MEM | IORESOURCE_PREFETCH;
 		if (res->flags & PCI_PREF_RANGE_TYPE_64)
 			res->flags |= IORESOURCE_MEM_64;
-		res->start = base;
-		res->end = limit + 0xfffff;
+		region.start = base;
+		region.end = limit + 0xfffff;
+		pcibios_bus_to_resource(dev, res, &region);
 		dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
 	}
 }
@@ -900,6 +991,8 @@
 	u8 hdr_type;
 	struct pci_slot *slot;
 	int pos = 0;
+	struct pci_bus_region region;
+	struct resource *res;
 
 	if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type))
 		return -EIO;
@@ -926,12 +1019,10 @@
 
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
 	dev->revision = class & 0xff;
-	class >>= 8;				    /* upper 3 bytes */
-	dev->class = class;
-	class >>= 8;
+	dev->class = class >> 8;		    /* upper 3 bytes */
 
-	dev_printk(KERN_DEBUG, &dev->dev, "[%04x:%04x] type %d class %#08x\n",
-		   dev->vendor, dev->device, dev->hdr_type, class);
+	dev_printk(KERN_DEBUG, &dev->dev, "[%04x:%04x] type %02x class %#08x\n",
+		   dev->vendor, dev->device, dev->hdr_type, dev->class);
 
 	/* need to have dev->class ready */
 	dev->cfg_size = pci_cfg_space_size(dev);
@@ -963,20 +1054,28 @@
 			u8 progif;
 			pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
 			if ((progif & 1) == 0) {
-				dev->resource[0].start = 0x1F0;
-				dev->resource[0].end = 0x1F7;
-				dev->resource[0].flags = LEGACY_IO_RESOURCE;
-				dev->resource[1].start = 0x3F6;
-				dev->resource[1].end = 0x3F6;
-				dev->resource[1].flags = LEGACY_IO_RESOURCE;
+				region.start = 0x1F0;
+				region.end = 0x1F7;
+				res = &dev->resource[0];
+				res->flags = LEGACY_IO_RESOURCE;
+				pcibios_bus_to_resource(dev, res, &region);
+				region.start = 0x3F6;
+				region.end = 0x3F6;
+				res = &dev->resource[1];
+				res->flags = LEGACY_IO_RESOURCE;
+				pcibios_bus_to_resource(dev, res, &region);
 			}
 			if ((progif & 4) == 0) {
-				dev->resource[2].start = 0x170;
-				dev->resource[2].end = 0x177;
-				dev->resource[2].flags = LEGACY_IO_RESOURCE;
-				dev->resource[3].start = 0x376;
-				dev->resource[3].end = 0x376;
-				dev->resource[3].flags = LEGACY_IO_RESOURCE;
+				region.start = 0x170;
+				region.end = 0x177;
+				res = &dev->resource[2];
+				res->flags = LEGACY_IO_RESOURCE;
+				pcibios_bus_to_resource(dev, res, &region);
+				region.start = 0x376;
+				region.end = 0x376;
+				res = &dev->resource[3];
+				res->flags = LEGACY_IO_RESOURCE;
+				pcibios_bus_to_resource(dev, res, &region);
 			}
 		}
 		break;
@@ -1013,8 +1112,8 @@
 		return -EIO;
 
 	bad:
-		dev_err(&dev->dev, "ignoring class %02x (doesn't match header "
-			"type %02x)\n", class, dev->hdr_type);
+		dev_err(&dev->dev, "ignoring class %#08x (doesn't match header "
+			"type %02x)\n", dev->class, dev->hdr_type);
 		dev->class = PCI_CLASS_NOT_DEFINED;
 	}
 
@@ -1026,6 +1125,7 @@
 {
 	pci_vpd_release(dev);
 	pci_iov_release(dev);
+	pci_free_cap_save_buffers(dev);
 }
 
 /**
@@ -1118,6 +1218,42 @@
 }
 EXPORT_SYMBOL(alloc_pci_dev);
 
+bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l,
+				 int crs_timeout)
+{
+	int delay = 1;
+
+	if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
+		return false;
+
+	/* some broken boards return 0 or ~0 if a slot is empty: */
+	if (*l == 0xffffffff || *l == 0x00000000 ||
+	    *l == 0x0000ffff || *l == 0xffff0000)
+		return false;
+
+	/* Configuration request Retry Status */
+	while (*l == 0xffff0001) {
+		if (!crs_timeout)
+			return false;
+
+		msleep(delay);
+		delay *= 2;
+		if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
+			return false;
+		/* Card hasn't responded in 60 seconds?  Must be stuck. */
+		if (delay > crs_timeout) {
+			printk(KERN_WARNING "pci %04x:%02x:%02x.%d: not "
+					"responding\n", pci_domain_nr(bus),
+					bus->number, PCI_SLOT(devfn),
+					PCI_FUNC(devfn));
+			return false;
+		}
+	}
+
+	return true;
+}
+EXPORT_SYMBOL(pci_bus_read_dev_vendor_id);
+
 /*
  * Read the config data for a PCI device, sanity-check it
  * and fill in the dev structure...
@@ -1126,32 +1262,10 @@
 {
 	struct pci_dev *dev;
 	u32 l;
-	int delay = 1;
 
-	if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
+	if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000))
 		return NULL;
 
-	/* some broken boards return 0 or ~0 if a slot is empty: */
-	if (l == 0xffffffff || l == 0x00000000 ||
-	    l == 0x0000ffff || l == 0xffff0000)
-		return NULL;
-
-	/* Configuration request Retry Status */
-	while (l == 0xffff0001) {
-		msleep(delay);
-		delay *= 2;
-		if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
-			return NULL;
-		/* Card hasn't responded in 60 seconds?  Must be stuck. */
-		if (delay > 60 * 1000) {
-			printk(KERN_WARNING "pci %04x:%02x:%02x.%d: not "
-					"responding\n", pci_domain_nr(bus),
-					bus->number, PCI_SLOT(devfn),
-					PCI_FUNC(devfn));
-			return NULL;
-		}
-	}
-
 	dev = alloc_pci_dev();
 	if (!dev)
 		return NULL;
@@ -1212,6 +1326,9 @@
 	/* Fix up broken headers */
 	pci_fixup_device(pci_fixup_header, dev);
 
+	/* moved out from quirk header fixup code */
+	pci_reassigndev_resource_alignment(dev);
+
 	/* Clear the state_saved flag. */
 	dev->state_saved = false;
 
@@ -1530,21 +1647,27 @@
 struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 		struct pci_ops *ops, void *sysdata, struct list_head *resources)
 {
-	int error, i;
+	int error;
+	struct pci_host_bridge *bridge;
 	struct pci_bus *b, *b2;
 	struct device *dev;
-	struct pci_bus_resource *bus_res, *n;
+	struct pci_host_bridge_window *window, *n;
 	struct resource *res;
+	resource_size_t offset;
+	char bus_addr[64];
+	char *fmt;
+
+	bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
+	if (!bridge)
+		return NULL;
 
 	b = pci_alloc_bus();
 	if (!b)
-		return NULL;
+		goto err_bus;
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev) {
-		kfree(b);
-		return NULL;
-	}
+	if (!dev)
+		goto err_dev;
 
 	b->sysdata = sysdata;
 	b->ops = ops;
@@ -1556,10 +1679,6 @@
 		goto err_out;
 	}
 
-	down_write(&pci_bus_sem);
-	list_add_tail(&b->node, &pci_root_buses);
-	up_write(&pci_bus_sem);
-
 	dev->parent = parent;
 	dev->release = pci_release_bus_bridge_dev;
 	dev_set_name(dev, "pci%04x:%02x", pci_domain_nr(b), bus);
@@ -1585,31 +1704,53 @@
 
 	b->number = b->secondary = bus;
 
-	/* Add initial resources to the bus */
-	list_for_each_entry_safe(bus_res, n, resources, list)
-		list_move_tail(&bus_res->list, &b->resources);
+	bridge->bus = b;
+	INIT_LIST_HEAD(&bridge->windows);
 
 	if (parent)
 		dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
 	else
 		printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev));
 
-	pci_bus_for_each_resource(b, res, i) {
-		if (res)
-			dev_info(&b->dev, "root bus resource %pR\n", res);
+	/* Add initial resources to the bus */
+	list_for_each_entry_safe(window, n, resources, list) {
+		list_move_tail(&window->list, &bridge->windows);
+		res = window->res;
+		offset = window->offset;
+		pci_bus_add_resource(b, res, 0);
+		if (offset) {
+			if (resource_type(res) == IORESOURCE_IO)
+				fmt = " (bus address [%#06llx-%#06llx])";
+			else
+				fmt = " (bus address [%#010llx-%#010llx])";
+			snprintf(bus_addr, sizeof(bus_addr), fmt,
+				 (unsigned long long) (res->start - offset),
+				 (unsigned long long) (res->end - offset));
+		} else
+			bus_addr[0] = '\0';
+		dev_info(&b->dev, "root bus resource %pR%s\n", res, bus_addr);
 	}
 
+	down_write(&pci_bus_sem);
+	list_add_tail(&bridge->list, &pci_host_bridges);
+	list_add_tail(&b->node, &pci_root_buses);
+	up_write(&pci_bus_sem);
+
 	return b;
 
 class_dev_reg_err:
 	device_unregister(dev);
 dev_reg_err:
 	down_write(&pci_bus_sem);
+	list_del(&bridge->list);
 	list_del(&b->node);
 	up_write(&pci_bus_sem);
 err_out:
 	kfree(dev);
+err_dev:
 	kfree(b);
+err_bus:
+	kfree(bridge);
 	return NULL;
 }
 
@@ -1667,36 +1808,29 @@
 
 #ifdef CONFIG_HOTPLUG
 /**
- * pci_rescan_bus - scan a PCI bus for devices.
- * @bus: PCI bus to scan
+ * pci_rescan_bus_bridge_resize - scan a PCI bus for devices.
+ * @bridge: PCI bridge for the bus to scan
  *
- * Scan a PCI bus and child buses for new devices, adds them,
- * and enables them.
+ * Scan a PCI bus and child buses for new devices, add them,
+ * and enable them, resizing bridge mmio/io resource if necessary
+ * and possible.  The caller must ensure the child devices are already
+ * removed for resizing to occur.
  *
  * Returns the max number of subordinate bus discovered.
  */
-unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
+unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge)
 {
 	unsigned int max;
-	struct pci_dev *dev;
+	struct pci_bus *bus = bridge->subordinate;
 
 	max = pci_scan_child_bus(bus);
 
-	down_read(&pci_bus_sem);
-	list_for_each_entry(dev, &bus->devices, bus_list)
-		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
-		    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
-			if (dev->subordinate)
-				pci_bus_size_bridges(dev->subordinate);
-	up_read(&pci_bus_sem);
+	pci_assign_unassigned_bridge_resources(bridge);
 
-	pci_bus_assign_resources(bus);
-	pci_enable_bridges(bus);
 	pci_bus_add_devices(bus);
 
 	return max;
 }
-EXPORT_SYMBOL_GPL(pci_rescan_bus);
 
 EXPORT_SYMBOL(pci_add_new_bus);
 EXPORT_SYMBOL(pci_scan_slot);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index f722c5f..4bf7102 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -26,73 +26,12 @@
 #include <linux/dmi.h>
 #include <linux/pci-aspm.h>
 #include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/ktime.h>
 #include <asm/dma.h>	/* isa_dma_bridge_buggy */
 #include "pci.h"
 
 /*
- * This quirk function disables memory decoding and releases memory resources
- * of the device specified by kernel's boot parameter 'pci=resource_alignment='.
- * It also rounds up size to specified alignment.
- * Later on, the kernel will assign page-aligned memory resource back
- * to the device.
- */
-static void __devinit quirk_resource_alignment(struct pci_dev *dev)
-{
-	int i;
-	struct resource *r;
-	resource_size_t align, size;
-	u16 command;
-
-	if (!pci_is_reassigndev(dev))
-		return;
-
-	if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL &&
-	    (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) {
-		dev_warn(&dev->dev,
-			"Can't reassign resources to host bridge.\n");
-		return;
-	}
-
-	dev_info(&dev->dev,
-		"Disabling memory decoding and releasing memory resources.\n");
-	pci_read_config_word(dev, PCI_COMMAND, &command);
-	command &= ~PCI_COMMAND_MEMORY;
-	pci_write_config_word(dev, PCI_COMMAND, command);
-
-	align = pci_specified_resource_alignment(dev);
-	for (i=0; i < PCI_BRIDGE_RESOURCES; i++) {
-		r = &dev->resource[i];
-		if (!(r->flags & IORESOURCE_MEM))
-			continue;
-		size = resource_size(r);
-		if (size < align) {
-			size = align;
-			dev_info(&dev->dev,
-				"Rounding up size of resource #%d to %#llx.\n",
-				i, (unsigned long long)size);
-		}
-		r->end = size - 1;
-		r->start = 0;
-	}
-	/* Need to disable bridge's resource window,
-	 * to enable the kernel to reassign new resource
-	 * window later on.
-	 */
-	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
-	    (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
-		for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
-			r = &dev->resource[i];
-			if (!(r->flags & IORESOURCE_MEM))
-				continue;
-			r->end = resource_size(r) - 1;
-			r->start = 0;
-		}
-		pci_disable_bridge_window(dev);
-	}
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_resource_alignment);
-
-/*
  * Decoding should be disabled for a PCI device during BAR sizing to avoid
  * conflict. But doing so may cause problems on host bridge and perhaps other
  * key system devices. For devices that need to have mmio decoding always-on,
@@ -100,10 +39,10 @@
  */
 static void __devinit quirk_mmio_always_on(struct pci_dev *dev)
 {
-	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
-		dev->mmio_always_on = 1;
+	dev->mmio_always_on = 1;
 }
-DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, quirk_mmio_always_on);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID,
+				PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on);
 
 /* The Mellanox Tavor device gives false positive parity errors
  * Mark this device with a broken_parity_status, to allow
@@ -1002,12 +941,12 @@
  */
 static void quirk_cardbus_legacy(struct pci_dev *dev)
 {
-	if ((PCI_CLASS_BRIDGE_CARDBUS << 8) ^ dev->class)
-		return;
 	pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0);
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy);
-DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+			PCI_CLASS_BRIDGE_CARDBUS, 8, quirk_cardbus_legacy);
+DECLARE_PCI_FIXUP_CLASS_RESUME_EARLY(PCI_ANY_ID, PCI_ANY_ID,
+			PCI_CLASS_BRIDGE_CARDBUS, 8, quirk_cardbus_legacy);
 
 /*
  * Following the PCI ordering rules is optional on the AMD762. I'm not
@@ -1164,17 +1103,20 @@
 
 static void __devinit quirk_no_ata_d3(struct pci_dev *pdev)
 {
-	/* Quirk the legacy ATA devices only. The AHCI ones are ok */
-	if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE)
-		pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
+	pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
 }
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_ANY_ID, quirk_no_ata_d3);
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, PCI_ANY_ID, quirk_no_ata_d3);
+/* Quirk the legacy ATA devices only. The AHCI ones are ok */
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_ANY_ID,
+				PCI_CLASS_STORAGE_IDE, 8, quirk_no_ata_d3);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
+				PCI_CLASS_STORAGE_IDE, 8, quirk_no_ata_d3);
 /* ALi loses some register settings that we cannot then restore */
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AL, PCI_ANY_ID, quirk_no_ata_d3);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_AL, PCI_ANY_ID,
+				PCI_CLASS_STORAGE_IDE, 8, quirk_no_ata_d3);
 /* VIA comes back fine but we need to keep it alive or ACPI GTM failures
    occur when mode detecting */
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_no_ata_d3);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_VIA, PCI_ANY_ID,
+				PCI_CLASS_STORAGE_IDE, 8, quirk_no_ata_d3);
 
 /* This was originally an Alpha specific thing, but it really fits here.
  * The i82375 PCI/EISA bridge appears as non-classified. Fix that.
@@ -1873,8 +1815,7 @@
 	case PCI_DEVICE_ID_NETMOS_9745:
 	case PCI_DEVICE_ID_NETMOS_9845:
 	case PCI_DEVICE_ID_NETMOS_9855:
-		if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL &&
-		    num_parallel) {
+		if (num_parallel) {
 			dev_info(&dev->dev, "Netmos %04x (%u parallel, "
 				"%u serial); changing class SERIAL to OTHER "
 				"(use parport_serial)\n",
@@ -1884,7 +1825,8 @@
 		}
 	}
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos);
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID,
+			 PCI_CLASS_COMMUNICATION_SERIAL, 8, quirk_netmos);
 
 static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
 {
@@ -1952,7 +1894,8 @@
 
 	iounmap(csr);
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_e100_interrupt);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
+			PCI_CLASS_NETWORK_ETHERNET, 8, quirk_e100_interrupt);
 
 /*
  * The 82575 and 82598 may experience data corruption issues when transitioning
@@ -2834,12 +2777,11 @@
 static void __devinit fixup_ti816x_class(struct pci_dev* dev)
 {
 	/* TI 816x devices do not have class code set when in PCIe boot mode */
-	if (dev->class == PCI_CLASS_NOT_DEFINED) {
-		dev_info(&dev->dev, "Setting PCI class for 816x PCIe device\n");
-		dev->class = PCI_CLASS_MULTIMEDIA_VIDEO;
-	}
+	dev_info(&dev->dev, "Setting PCI class for 816x PCIe device\n");
+	dev->class = PCI_CLASS_MULTIMEDIA_VIDEO;
 }
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_TI, 0xb800, fixup_ti816x_class);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_TI, 0xb800,
+				 PCI_CLASS_NOT_DEFINED, 0, fixup_ti816x_class);
 
 /* Some PCIe devices do not work reliably with the claimed maximum
  * payload size supported.
@@ -2924,17 +2866,73 @@
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata);
 
+
+static void do_one_fixup_debug(void (*fn)(struct pci_dev *dev), struct pci_dev *dev)
+{
+	ktime_t calltime, delta, rettime;
+	unsigned long long duration;
+
+	printk(KERN_DEBUG "calling  %pF @ %i for %s\n",
+			fn, task_pid_nr(current), dev_name(&dev->dev));
+	calltime = ktime_get();
+	fn(dev);
+	rettime = ktime_get();
+	delta = ktime_sub(rettime, calltime);
+	duration = (unsigned long long) ktime_to_ns(delta) >> 10;
+	printk(KERN_DEBUG "pci fixup %pF returned after %lld usecs for %s\n",
+			fn, duration, dev_name(&dev->dev));
+}
+
+/*
+ * Some BIOS implementations leave the Intel GPU interrupts enabled,
+ * even though no one is handling them (f.e. i915 driver is never loaded).
+ * Additionally the interrupt destination is not set up properly
+ * and the interrupt ends up -somewhere-.
+ *
+ * These spurious interrupts are "sticky" and the kernel disables
+ * the (shared) interrupt line after 100.000+ generated interrupts.
+ *
+ * Fix it by disabling the still enabled interrupts.
+ * This resolves crashes often seen on monitor unplug.
+ */
+#define I915_DEIER_REG 0x4400c
+static void __devinit disable_igfx_irq(struct pci_dev *dev)
+{
+	void __iomem *regs = pci_iomap(dev, 0, 0);
+	if (regs == NULL) {
+		dev_warn(&dev->dev, "igfx quirk: Can't iomap PCI device\n");
+		return;
+	}
+
+	/* Check if any interrupt line is still enabled */
+	if (readl(regs + I915_DEIER_REG) != 0) {
+		dev_warn(&dev->dev, "BIOS left Intel GPU interrupts enabled; "
+			"disabling\n");
+
+		writel(0, regs + I915_DEIER_REG);
+	}
+
+	pci_iounmap(dev, regs);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
+
 static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
 			  struct pci_fixup *end)
 {
-	while (f < end) {
-		if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) &&
-		    (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
+	for (; f < end; f++)
+		if ((f->class == (u32) (dev->class >> f->class_shift) ||
+		     f->class == (u32) PCI_ANY_ID) &&
+		    (f->vendor == dev->vendor ||
+		     f->vendor == (u16) PCI_ANY_ID) &&
+		    (f->device == dev->device ||
+		     f->device == (u16) PCI_ANY_ID)) {
 			dev_dbg(&dev->dev, "calling %pF\n", f->hook);
-			f->hook(dev);
+			if (initcall_debug)
+				do_one_fixup_debug(f->hook, dev);
+			else
+				f->hook(dev);
 		}
-		f++;
-	}
 }
 
 extern struct pci_fixup __start_pci_fixups_early[];
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index ef8b18c..fd77e2b 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -79,7 +79,7 @@
 
 static void __pci_remove_behind_bridge(struct pci_dev *dev);
 /**
- * pci_remove_bus_device - remove a PCI device and any children
+ * pci_stop_and_remove_bus_device - remove a PCI device and any children
  * @dev: the device to remove
  *
  * Remove a PCI device from the device lists, informing the drivers
@@ -90,7 +90,7 @@
  * device lists, remove the /proc entry, and notify userspace
  * (/sbin/hotplug).
  */
-static void __pci_remove_bus_device(struct pci_dev *dev)
+void __pci_remove_bus_device(struct pci_dev *dev)
 {
 	if (dev->subordinate) {
 		struct pci_bus *b = dev->subordinate;
@@ -102,7 +102,9 @@
 
 	pci_destroy_dev(dev);
 }
-void pci_remove_bus_device(struct pci_dev *dev)
+EXPORT_SYMBOL(__pci_remove_bus_device);
+
+void pci_stop_and_remove_bus_device(struct pci_dev *dev)
 {
 	pci_stop_bus_device(dev);
 	__pci_remove_bus_device(dev);
@@ -127,14 +129,15 @@
 }
 
 /**
- * pci_remove_behind_bridge - remove all devices behind a PCI bridge
+ * pci_stop_and_remove_behind_bridge - stop and remove all devices behind
+ *					 a PCI bridge
  * @dev: PCI bridge device
  *
  * Remove all devices on the bus, except for the parent bridge.
  * This also removes any child buses, and any devices they may
  * contain in a depth-first manner.
  */
-void pci_remove_behind_bridge(struct pci_dev *dev)
+void pci_stop_and_remove_behind_bridge(struct pci_dev *dev)
 {
 	pci_stop_behind_bridge(dev);
 	__pci_remove_behind_bridge(dev);
@@ -144,7 +147,15 @@
 {
 	struct list_head *l, *n;
 
-	list_for_each_safe(l, n, &bus->devices) {
+	/*
+	 * VFs could be removed by pci_stop_and_remove_bus_device() in the
+	 *  pci_stop_bus_devices() code path for PF.
+	 *  aka, bus->devices get updated in the process.
+	 * but VFs are inserted after PFs when SRIOV is enabled for PF,
+	 * We can iterate the list backwards to get prev valid PF instead
+	 *  of removed VF.
+	 */
+	list_for_each_prev_safe(l, n, &bus->devices) {
 		struct pci_dev *dev = pci_dev_b(l);
 		pci_stop_bus_device(dev);
 	}
@@ -166,6 +177,6 @@
 	pci_stop_dev(dev);
 }
 
-EXPORT_SYMBOL(pci_remove_bus_device);
-EXPORT_SYMBOL(pci_remove_behind_bridge);
+EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
+EXPORT_SYMBOL(pci_stop_and_remove_behind_bridge);
 EXPORT_SYMBOL_GPL(pci_stop_bus_device);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 86b69f85..8fa2d4b 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -25,10 +25,13 @@
 #include <linux/ioport.h>
 #include <linux/cache.h>
 #include <linux/slab.h>
+#include <asm-generic/pci-bridge.h>
 #include "pci.h"
 
-struct resource_list_x {
-	struct resource_list_x *next;
+unsigned int pci_flags;
+
+struct pci_dev_resource {
+	struct list_head list;
 	struct resource *res;
 	struct pci_dev *dev;
 	resource_size_t start;
@@ -38,21 +41,14 @@
 	unsigned long flags;
 };
 
-#define free_list(type, head) do {                      \
-	struct type *list, *tmp;			\
-	for (list = (head)->next; list;) {		\
-		tmp = list;				\
-		list = list->next;			\
-		kfree(tmp);				\
-	}						\
-	(head)->next = NULL;				\
-} while (0)
-
-int pci_realloc_enable = 0;
-#define pci_realloc_enabled() pci_realloc_enable
-void pci_realloc(void)
+static void free_list(struct list_head *head)
 {
-	pci_realloc_enable = 1;
+	struct pci_dev_resource *dev_res, *tmp;
+
+	list_for_each_entry_safe(dev_res, tmp, head, list) {
+		list_del(&dev_res->list);
+		kfree(dev_res);
+	}
 }
 
 /**
@@ -64,21 +60,18 @@
  * @add_size:	additional size to be optionally added
  *              to the resource
  */
-static void add_to_list(struct resource_list_x *head,
+static int add_to_list(struct list_head *head,
 		 struct pci_dev *dev, struct resource *res,
 		 resource_size_t add_size, resource_size_t min_align)
 {
-	struct resource_list_x *list = head;
-	struct resource_list_x *ln = list->next;
-	struct resource_list_x *tmp;
+	struct pci_dev_resource *tmp;
 
-	tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+	tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
 	if (!tmp) {
 		pr_warning("add_to_list: kmalloc() failed!\n");
-		return;
+		return -ENOMEM;
 	}
 
-	tmp->next = ln;
 	tmp->res = res;
 	tmp->dev = dev;
 	tmp->start = res->start;
@@ -86,19 +79,100 @@
 	tmp->flags = res->flags;
 	tmp->add_size = add_size;
 	tmp->min_align = min_align;
-	list->next = tmp;
+
+	list_add(&tmp->list, head);
+
+	return 0;
 }
 
-static void add_to_failed_list(struct resource_list_x *head,
-				struct pci_dev *dev, struct resource *res)
+static void remove_from_list(struct list_head *head,
+				 struct resource *res)
 {
-	add_to_list(head, dev, res,
-			0 /* dont care */,
-			0 /* dont care */);
+	struct pci_dev_resource *dev_res, *tmp;
+
+	list_for_each_entry_safe(dev_res, tmp, head, list) {
+		if (dev_res->res == res) {
+			list_del(&dev_res->list);
+			kfree(dev_res);
+			break;
+		}
+	}
+}
+
+static resource_size_t get_res_add_size(struct list_head *head,
+					struct resource *res)
+{
+	struct pci_dev_resource *dev_res;
+
+	list_for_each_entry(dev_res, head, list) {
+		if (dev_res->res == res) {
+			int idx = res - &dev_res->dev->resource[0];
+
+			dev_printk(KERN_DEBUG, &dev_res->dev->dev,
+				 "res[%d]=%pR get_res_add_size add_size %llx\n",
+				 idx, dev_res->res,
+				 (unsigned long long)dev_res->add_size);
+
+			return dev_res->add_size;
+		}
+	}
+
+	return 0;
+}
+
+/* Sort resources by alignment */
+static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head)
+{
+	int i;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		struct resource *r;
+		struct pci_dev_resource *dev_res, *tmp;
+		resource_size_t r_align;
+		struct list_head *n;
+
+		r = &dev->resource[i];
+
+		if (r->flags & IORESOURCE_PCI_FIXED)
+			continue;
+
+		if (!(r->flags) || r->parent)
+			continue;
+
+		r_align = pci_resource_alignment(dev, r);
+		if (!r_align) {
+			dev_warn(&dev->dev, "BAR %d: %pR has bogus alignment\n",
+				 i, r);
+			continue;
+		}
+
+		tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+		if (!tmp)
+			panic("pdev_sort_resources(): "
+			      "kmalloc() failed!\n");
+		tmp->res = r;
+		tmp->dev = dev;
+
+		/* fallback is smallest one or list is empty*/
+		n = head;
+		list_for_each_entry(dev_res, head, list) {
+			resource_size_t align;
+
+			align = pci_resource_alignment(dev_res->dev,
+							 dev_res->res);
+
+			if (r_align > align) {
+				n = &dev_res->list;
+				break;
+			}
+		}
+		/* Insert it just before n*/
+		list_add_tail(&tmp->list, n);
+	}
 }
 
 static void __dev_sort_resources(struct pci_dev *dev,
-				 struct resource_list *head)
+				 struct list_head *head)
 {
 	u16 class = dev->class >> 8;
 
@@ -136,49 +210,54 @@
  * additional resources for the element, provided the element
  * is in the head list.
  */
-static void reassign_resources_sorted(struct resource_list_x *realloc_head,
-		struct resource_list *head)
+static void reassign_resources_sorted(struct list_head *realloc_head,
+		struct list_head *head)
 {
 	struct resource *res;
-	struct resource_list_x *list, *tmp, *prev;
-	struct resource_list *hlist;
+	struct pci_dev_resource *add_res, *tmp;
+	struct pci_dev_resource *dev_res;
 	resource_size_t add_size;
 	int idx;
 
-	prev = realloc_head;
-	for (list = realloc_head->next; list;) {
-		res = list->res;
+	list_for_each_entry_safe(add_res, tmp, realloc_head, list) {
+		bool found_match = false;
+
+		res = add_res->res;
 		/* skip resource that has been reset */
 		if (!res->flags)
 			goto out;
 
 		/* skip this resource if not found in head list */
-		for (hlist = head->next; hlist && hlist->res != res;
-				hlist = hlist->next);
-		if (!hlist) { /* just skip */
-			prev = list;
-			list = list->next;
-			continue;
+		list_for_each_entry(dev_res, head, list) {
+			if (dev_res->res == res) {
+				found_match = true;
+				break;
+			}
 		}
+		if (!found_match)/* just skip */
+			continue;
 
-		idx = res - &list->dev->resource[0];
-		add_size=list->add_size;
+		idx = res - &add_res->dev->resource[0];
+		add_size = add_res->add_size;
 		if (!resource_size(res)) {
-			res->start = list->start;
+			res->start = add_res->start;
 			res->end = res->start + add_size - 1;
-			if(pci_assign_resource(list->dev, idx))
+			if (pci_assign_resource(add_res->dev, idx))
 				reset_resource(res);
 		} else {
-			resource_size_t align = list->min_align;
-			res->flags |= list->flags & (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
-			if (pci_reassign_resource(list->dev, idx, add_size, align))
-				dev_printk(KERN_DEBUG, &list->dev->dev, "failed to add optional resources res=%pR\n",
-							res);
+			resource_size_t align = add_res->min_align;
+			res->flags |= add_res->flags &
+				 (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
+			if (pci_reassign_resource(add_res->dev, idx,
+						  add_size, align))
+				dev_printk(KERN_DEBUG, &add_res->dev->dev,
+					   "failed to add %llx res[%d]=%pR\n",
+					   (unsigned long long)add_size,
+					   idx, res);
 		}
 out:
-		tmp = list;
-		prev->next = list = list->next;
-		kfree(tmp);
+		list_del(&add_res->list);
+		kfree(add_res);
 	}
 }
 
@@ -192,35 +271,99 @@
  * Satisfy resource requests of each element in the list. Add
  * requests that could not satisfied to the failed_list.
  */
-static void assign_requested_resources_sorted(struct resource_list *head,
-				 struct resource_list_x *fail_head)
+static void assign_requested_resources_sorted(struct list_head *head,
+				 struct list_head *fail_head)
 {
 	struct resource *res;
-	struct resource_list *list;
+	struct pci_dev_resource *dev_res;
 	int idx;
 
-	for (list = head->next; list; list = list->next) {
-		res = list->res;
-		idx = res - &list->dev->resource[0];
-		if (resource_size(res) && pci_assign_resource(list->dev, idx)) {
-			if (fail_head && !pci_is_root_bus(list->dev->bus)) {
+	list_for_each_entry(dev_res, head, list) {
+		res = dev_res->res;
+		idx = res - &dev_res->dev->resource[0];
+		if (resource_size(res) &&
+		    pci_assign_resource(dev_res->dev, idx)) {
+			if (fail_head && !pci_is_root_bus(dev_res->dev->bus)) {
 				/*
 				 * if the failed res is for ROM BAR, and it will
 				 * be enabled later, don't add it to the list
 				 */
 				if (!((idx == PCI_ROM_RESOURCE) &&
 				      (!(res->flags & IORESOURCE_ROM_ENABLE))))
-					add_to_failed_list(fail_head, list->dev, res);
+					add_to_list(fail_head,
+						    dev_res->dev, res,
+						    0 /* dont care */,
+						    0 /* dont care */);
 			}
 			reset_resource(res);
 		}
 	}
 }
 
-static void __assign_resources_sorted(struct resource_list *head,
-				 struct resource_list_x *realloc_head,
-				 struct resource_list_x *fail_head)
+static void __assign_resources_sorted(struct list_head *head,
+				 struct list_head *realloc_head,
+				 struct list_head *fail_head)
 {
+	/*
+	 * Should not assign requested resources at first.
+	 *   they could be adjacent, so later reassign can not reallocate
+	 *   them one by one in parent resource window.
+	 * Try to assign requested + add_size at begining
+	 *  if could do that, could get out early.
+	 *  if could not do that, we still try to assign requested at first,
+	 *    then try to reassign add_size for some resources.
+	 */
+	LIST_HEAD(save_head);
+	LIST_HEAD(local_fail_head);
+	struct pci_dev_resource *save_res;
+	struct pci_dev_resource *dev_res;
+
+	/* Check if optional add_size is there */
+	if (!realloc_head || list_empty(realloc_head))
+		goto requested_and_reassign;
+
+	/* Save original start, end, flags etc at first */
+	list_for_each_entry(dev_res, head, list) {
+		if (add_to_list(&save_head, dev_res->dev, dev_res->res, 0, 0)) {
+			free_list(&save_head);
+			goto requested_and_reassign;
+		}
+	}
+
+	/* Update res in head list with add_size in realloc_head list */
+	list_for_each_entry(dev_res, head, list)
+		dev_res->res->end += get_res_add_size(realloc_head,
+							dev_res->res);
+
+	/* Try updated head list with add_size added */
+	assign_requested_resources_sorted(head, &local_fail_head);
+
+	/* all assigned with add_size ? */
+	if (list_empty(&local_fail_head)) {
+		/* Remove head list from realloc_head list */
+		list_for_each_entry(dev_res, head, list)
+			remove_from_list(realloc_head, dev_res->res);
+		free_list(&save_head);
+		free_list(head);
+		return;
+	}
+
+	free_list(&local_fail_head);
+	/* Release assigned resource */
+	list_for_each_entry(dev_res, head, list)
+		if (dev_res->res->parent)
+			release_resource(dev_res->res);
+	/* Restore start/end/flags from saved list */
+	list_for_each_entry(save_res, &save_head, list) {
+		struct resource *res = save_res->res;
+
+		res->start = save_res->start;
+		res->end = save_res->end;
+		res->flags = save_res->flags;
+	}
+	free_list(&save_head);
+
+requested_and_reassign:
 	/* Satisfy the must-have resource requests */
 	assign_requested_resources_sorted(head, fail_head);
 
@@ -228,28 +371,27 @@
 		requests */
 	if (realloc_head)
 		reassign_resources_sorted(realloc_head, head);
-	free_list(resource_list, head);
+	free_list(head);
 }
 
 static void pdev_assign_resources_sorted(struct pci_dev *dev,
-				 struct resource_list_x *fail_head)
+				 struct list_head *add_head,
+				 struct list_head *fail_head)
 {
-	struct resource_list head;
+	LIST_HEAD(head);
 
-	head.next = NULL;
 	__dev_sort_resources(dev, &head);
-	__assign_resources_sorted(&head, NULL, fail_head);
+	__assign_resources_sorted(&head, add_head, fail_head);
 
 }
 
 static void pbus_assign_resources_sorted(const struct pci_bus *bus,
-					 struct resource_list_x *realloc_head,
-					 struct resource_list_x *fail_head)
+					 struct list_head *realloc_head,
+					 struct list_head *fail_head)
 {
 	struct pci_dev *dev;
-	struct resource_list head;
+	LIST_HEAD(head);
 
-	head.next = NULL;
 	list_for_each_entry(dev, &bus->devices, bus_list)
 		__dev_sort_resources(dev, &head);
 
@@ -548,20 +690,6 @@
 	return size;
 }
 
-static resource_size_t get_res_add_size(struct resource_list_x *realloc_head,
-					struct resource *res)
-{
-	struct resource_list_x *list;
-
-	/* check if it is in realloc_head list */
-	for (list = realloc_head->next; list && list->res != res;
-			list = list->next);
-	if (list)
-		return list->add_size;
-
-	return 0;
-}
-
 /**
  * pbus_size_io() - size the io window of a given bus
  *
@@ -576,7 +704,7 @@
  * We must be careful with the ISA aliasing though.
  */
 static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
-		resource_size_t add_size, struct resource_list_x *realloc_head)
+		resource_size_t add_size, struct list_head *realloc_head)
 {
 	struct pci_dev *dev;
 	struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
@@ -612,7 +740,7 @@
 	if (children_add_size > add_size)
 		add_size = children_add_size;
 	size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
-		calculate_iosize(size, min_size+add_size, size1,
+		calculate_iosize(size, min_size, add_size + size1,
 			resource_size(b_res), 4096);
 	if (!size0 && !size1) {
 		if (b_res->start || b_res->end)
@@ -626,8 +754,12 @@
 	b_res->start = 4096;
 	b_res->end = b_res->start + size0 - 1;
 	b_res->flags |= IORESOURCE_STARTALIGN;
-	if (size1 > size0 && realloc_head)
+	if (size1 > size0 && realloc_head) {
 		add_to_list(realloc_head, bus->self, b_res, size1-size0, 4096);
+		dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
+				 "%pR to [bus %02x-%02x] add_size %lx\n", b_res,
+				 bus->secondary, bus->subordinate, size1-size0);
+	}
 }
 
 /**
@@ -644,7 +776,7 @@
 static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
 			 unsigned long type, resource_size_t min_size,
 			resource_size_t add_size,
-			struct resource_list_x *realloc_head)
+			struct list_head *realloc_head)
 {
 	struct pci_dev *dev;
 	resource_size_t min_align, align, size, size0, size1;
@@ -726,7 +858,7 @@
 	if (children_add_size > add_size)
 		add_size = children_add_size;
 	size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
-		calculate_memsize(size, min_size+add_size, 0,
+		calculate_memsize(size, min_size, add_size,
 				resource_size(b_res), min_align);
 	if (!size0 && !size1) {
 		if (b_res->start || b_res->end)
@@ -739,8 +871,12 @@
 	b_res->start = min_align;
 	b_res->end = size0 + min_align - 1;
 	b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask;
-	if (size1 > size0 && realloc_head)
+	if (size1 > size0 && realloc_head) {
 		add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align);
+		dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
+				 "%pR to [bus %02x-%02x] add_size %llx\n", b_res,
+				 bus->secondary, bus->subordinate, (unsigned long long)size1-size0);
+	}
 	return 1;
 }
 
@@ -754,25 +890,48 @@
 }
 
 static void pci_bus_size_cardbus(struct pci_bus *bus,
-			struct resource_list_x *realloc_head)
+			struct list_head *realloc_head)
 {
 	struct pci_dev *bridge = bus->self;
 	struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
+	resource_size_t b_res_3_size = pci_cardbus_mem_size * 2;
 	u16 ctrl;
 
+	if (b_res[0].parent)
+		goto handle_b_res_1;
 	/*
 	 * Reserve some resources for CardBus.  We reserve
 	 * a fixed amount of bus space for CardBus bridges.
 	 */
-	b_res[0].start = 0;
-	b_res[0].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
-	if (realloc_head)
-		add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size, 0 /* dont care */);
+	b_res[0].start = pci_cardbus_io_size;
+	b_res[0].end = b_res[0].start + pci_cardbus_io_size - 1;
+	b_res[0].flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
+	if (realloc_head) {
+		b_res[0].end -= pci_cardbus_io_size;
+		add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size,
+				pci_cardbus_io_size);
+	}
 
-	b_res[1].start = 0;
-	b_res[1].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
-	if (realloc_head)
-		add_to_list(realloc_head, bridge, b_res+1, pci_cardbus_io_size, 0 /* dont care */);
+handle_b_res_1:
+	if (b_res[1].parent)
+		goto handle_b_res_2;
+	b_res[1].start = pci_cardbus_io_size;
+	b_res[1].end = b_res[1].start + pci_cardbus_io_size - 1;
+	b_res[1].flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
+	if (realloc_head) {
+		b_res[1].end -= pci_cardbus_io_size;
+		add_to_list(realloc_head, bridge, b_res+1, pci_cardbus_io_size,
+				 pci_cardbus_io_size);
+	}
+
+handle_b_res_2:
+	/* MEM1 must not be pref mmio */
+	pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
+	if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM1) {
+		ctrl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1;
+		pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
+		pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
+	}
 
 	/*
 	 * Check whether prefetchable memory is supported
@@ -785,38 +944,46 @@
 		pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
 	}
 
+	if (b_res[2].parent)
+		goto handle_b_res_3;
 	/*
 	 * If we have prefetchable memory support, allocate
 	 * two regions.  Otherwise, allocate one region of
 	 * twice the size.
 	 */
 	if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
-		b_res[2].start = 0;
-		b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_SIZEALIGN;
-		if (realloc_head)
-			add_to_list(realloc_head, bridge, b_res+2, pci_cardbus_mem_size, 0 /* dont care */);
+		b_res[2].start = pci_cardbus_mem_size;
+		b_res[2].end = b_res[2].start + pci_cardbus_mem_size - 1;
+		b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH |
+				  IORESOURCE_STARTALIGN;
+		if (realloc_head) {
+			b_res[2].end -= pci_cardbus_mem_size;
+			add_to_list(realloc_head, bridge, b_res+2,
+				 pci_cardbus_mem_size, pci_cardbus_mem_size);
+		}
 
-		b_res[3].start = 0;
-		b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
-		if (realloc_head)
-			add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size, 0 /* dont care */);
-	} else {
-		b_res[3].start = 0;
-		b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
-		if (realloc_head)
-			add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size * 2, 0 /* dont care */);
+		/* reduce that to half */
+		b_res_3_size = pci_cardbus_mem_size;
 	}
 
-	/* set the size of the resource to zero, so that the resource does not
-	 * get assigned during required-resource allocation cycle but gets assigned
-	 * during the optional-resource allocation cycle.
- 	 */
-	b_res[0].start = b_res[1].start = b_res[2].start = b_res[3].start = 1;
-	b_res[0].end = b_res[1].end = b_res[2].end = b_res[3].end = 0;
+handle_b_res_3:
+	if (b_res[3].parent)
+		goto handle_done;
+	b_res[3].start = pci_cardbus_mem_size;
+	b_res[3].end = b_res[3].start + b_res_3_size - 1;
+	b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN;
+	if (realloc_head) {
+		b_res[3].end -= b_res_3_size;
+		add_to_list(realloc_head, bridge, b_res+3, b_res_3_size,
+				 pci_cardbus_mem_size);
+	}
+
+handle_done:
+	;
 }
 
 void __ref __pci_bus_size_bridges(struct pci_bus *bus,
-			struct resource_list_x *realloc_head)
+			struct list_head *realloc_head)
 {
 	struct pci_dev *dev;
 	unsigned long mask, prefmask;
@@ -858,7 +1025,8 @@
 		 * Follow thru
 		 */
 	default:
-		pbus_size_io(bus, 0, additional_io_size, realloc_head);
+		pbus_size_io(bus, realloc_head ? 0 : additional_io_size,
+			     additional_io_size, realloc_head);
 		/* If the bridge supports prefetchable range, size it
 		   separately. If it doesn't, or its prefetchable window
 		   has already been allocated by arch code, try
@@ -866,11 +1034,15 @@
 		   resources. */
 		mask = IORESOURCE_MEM;
 		prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
-		if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, realloc_head))
+		if (pbus_size_mem(bus, prefmask, prefmask,
+				  realloc_head ? 0 : additional_mem_size,
+				  additional_mem_size, realloc_head))
 			mask = prefmask; /* Success, size non-prefetch only. */
 		else
 			additional_mem_size += additional_mem_size;
-		pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, realloc_head);
+		pbus_size_mem(bus, mask, IORESOURCE_MEM,
+				realloc_head ? 0 : additional_mem_size,
+				additional_mem_size, realloc_head);
 		break;
 	}
 }
@@ -882,8 +1054,8 @@
 EXPORT_SYMBOL(pci_bus_size_bridges);
 
 static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
-					 struct resource_list_x *realloc_head,
-					 struct resource_list_x *fail_head)
+					 struct list_head *realloc_head,
+					 struct list_head *fail_head)
 {
 	struct pci_bus *b;
 	struct pci_dev *dev;
@@ -922,17 +1094,19 @@
 EXPORT_SYMBOL(pci_bus_assign_resources);
 
 static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge,
-					 struct resource_list_x *fail_head)
+					 struct list_head *add_head,
+					 struct list_head *fail_head)
 {
 	struct pci_bus *b;
 
-	pdev_assign_resources_sorted((struct pci_dev *)bridge, fail_head);
+	pdev_assign_resources_sorted((struct pci_dev *)bridge,
+					 add_head, fail_head);
 
 	b = bridge->subordinate;
 	if (!b)
 		return;
 
-	__pci_bus_assign_resources(b, NULL, fail_head);
+	__pci_bus_assign_resources(b, add_head, fail_head);
 
 	switch (bridge->class >> 8) {
 	case PCI_CLASS_BRIDGE_PCI:
@@ -1095,6 +1269,58 @@
 	return depth;
 }
 
+/*
+ * -1: undefined, will auto detect later
+ *  0: disabled by user
+ *  1: disabled by auto detect
+ *  2: enabled by user
+ *  3: enabled by auto detect
+ */
+enum enable_type {
+	undefined = -1,
+	user_disabled,
+	auto_disabled,
+	user_enabled,
+	auto_enabled,
+};
+
+static enum enable_type pci_realloc_enable __initdata = undefined;
+void __init pci_realloc_get_opt(char *str)
+{
+	if (!strncmp(str, "off", 3))
+		pci_realloc_enable = user_disabled;
+	else if (!strncmp(str, "on", 2))
+		pci_realloc_enable = user_enabled;
+}
+static bool __init pci_realloc_enabled(void)
+{
+	return pci_realloc_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;
+
+	if (pci_realloc_enable != undefined)
+		return;
+
+	for_each_pci_dev(dev) {
+		int i;
+
+		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;
+			}
+		}
+	}
+#endif
+}
 
 /*
  * first try will not touch pci bridge res
@@ -1105,59 +1331,57 @@
 pci_assign_unassigned_resources(void)
 {
 	struct pci_bus *bus;
-	struct resource_list_x realloc_list; /* list of resources that
+	LIST_HEAD(realloc_head); /* list of resources that
 					want additional resources */
+	struct list_head *add_list = NULL;
 	int tried_times = 0;
 	enum release_type rel_type = leaf_only;
-	struct resource_list_x head, *list;
+	LIST_HEAD(fail_head);
+	struct pci_dev_resource *fail_res;
 	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
 				  IORESOURCE_PREFETCH;
-	unsigned long failed_type;
-	int max_depth = pci_get_max_depth();
-	int pci_try_num;
+	int pci_try_num = 1;
 
+	/* don't realloc if asked to do so */
+	pci_realloc_detect();
+	if (pci_realloc_enabled()) {
+		int max_depth = pci_get_max_depth();
 
-	head.next = NULL;
-	realloc_list.next = NULL;
-
-	pci_try_num = max_depth + 1;
-	printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n",
-		 max_depth, pci_try_num);
+		pci_try_num = max_depth + 1;
+		printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n",
+			 max_depth, pci_try_num);
+	}
 
 again:
+	/*
+	 * last try will use add_list, otherwise will try good to have as
+	 * must have, so can realloc parent bridge resource
+	 */
+	if (tried_times + 1 == pci_try_num)
+		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, &realloc_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, &realloc_list, &head);
-	BUG_ON(realloc_list.next);
+		__pci_bus_assign_resources(bus, add_list, &fail_head);
+	if (add_list)
+		BUG_ON(!list_empty(add_list));
 	tried_times++;
 
 	/* any device complain? */
-	if (!head.next)
+	if (list_empty(&fail_head))
 		goto enable_and_dump;
 
-	/* don't realloc if asked to do so */
-	if (!pci_realloc_enabled()) {
-		free_list(resource_list_x, &head);
-		goto enable_and_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");
 
-	failed_type = 0;
-	for (list = head.next; list;) {
-		failed_type |= list->flags;
-		list = list->next;
-	}
-	/*
-	 * io port are tight, don't try extra
-	 * or if reach the limit, don't want to try more
-	 */
-	failed_type &= type_mask;
-	if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) {
-		free_list(resource_list_x, &head);
+		free_list(&fail_head);
 		goto enable_and_dump;
 	}
 
@@ -1172,25 +1396,23 @@
 	 * Try to release leaf bridge's resources that doesn't fit resource of
 	 * child device under that bridge
 	 */
-	for (list = head.next; list;) {
-		bus = list->dev->bus;
-		pci_bus_release_bridge_resources(bus, list->flags & type_mask,
-						  rel_type);
-		list = list->next;
+	list_for_each_entry(fail_res, &fail_head, list) {
+		bus = fail_res->dev->bus;
+		pci_bus_release_bridge_resources(bus,
+						 fail_res->flags & type_mask,
+						 rel_type);
 	}
 	/* restore size and flags */
-	for (list = head.next; list;) {
-		struct resource *res = list->res;
+	list_for_each_entry(fail_res, &fail_head, list) {
+		struct resource *res = fail_res->res;
 
-		res->start = list->start;
-		res->end = list->end;
-		res->flags = list->flags;
-		if (list->dev->subordinate)
+		res->start = fail_res->start;
+		res->end = fail_res->end;
+		res->flags = fail_res->flags;
+		if (fail_res->dev->subordinate)
 			res->flags = 0;
-
-		list = list->next;
 	}
-	free_list(resource_list_x, &head);
+	free_list(&fail_head);
 
 	goto again;
 
@@ -1207,26 +1429,27 @@
 void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
 {
 	struct pci_bus *parent = bridge->subordinate;
+	LIST_HEAD(add_list); /* list of resources that
+					want additional resources */
 	int tried_times = 0;
-	struct resource_list_x head, *list;
+	LIST_HEAD(fail_head);
+	struct pci_dev_resource *fail_res;
 	int retval;
 	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
 				  IORESOURCE_PREFETCH;
 
-	head.next = NULL;
-
 again:
-	pci_bus_size_bridges(parent);
-	__pci_bridge_assign_resources(bridge, &head);
-
+	__pci_bus_size_bridges(parent, &add_list);
+	__pci_bridge_assign_resources(bridge, &add_list, &fail_head);
+	BUG_ON(!list_empty(&add_list));
 	tried_times++;
 
-	if (!head.next)
+	if (list_empty(&fail_head))
 		goto enable_all;
 
 	if (tried_times >= 2) {
 		/* still fail, don't need to try more */
-		free_list(resource_list_x, &head);
+		free_list(&fail_head);
 		goto enable_all;
 	}
 
@@ -1237,27 +1460,24 @@
 	 * Try to release leaf bridge's resources that doesn't fit resource of
 	 * child device under that bridge
 	 */
-	for (list = head.next; list;) {
-		struct pci_bus *bus = list->dev->bus;
-		unsigned long flags = list->flags;
+	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,
 						 whole_subtree);
-		list = list->next;
 	}
 	/* restore size and flags */
-	for (list = head.next; list;) {
-		struct resource *res = list->res;
+	list_for_each_entry(fail_res, &fail_head, list) {
+		struct resource *res = fail_res->res;
 
-		res->start = list->start;
-		res->end = list->end;
-		res->flags = list->flags;
-		if (list->dev->subordinate)
+		res->start = fail_res->start;
+		res->end = fail_res->end;
+		res->flags = fail_res->flags;
+		if (fail_res->dev->subordinate)
 			res->flags = 0;
-
-		list = list->next;
 	}
-	free_list(resource_list_x, &head);
+	free_list(&fail_head);
 
 	goto again;
 
@@ -1267,3 +1487,41 @@
 	pci_enable_bridges(parent);
 }
 EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
+
+#ifdef CONFIG_HOTPLUG
+/**
+ * pci_rescan_bus - scan a PCI bus for devices.
+ * @bus: PCI bus to scan
+ *
+ * Scan a PCI bus and child buses for new devices, adds them,
+ * and enables them.
+ *
+ * Returns the max number of subordinate bus discovered.
+ */
+unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
+{
+	unsigned int max;
+	struct pci_dev *dev;
+	LIST_HEAD(add_list); /* list of resources that
+					want additional resources */
+
+	max = pci_scan_child_bus(bus);
+
+	down_read(&pci_bus_sem);
+	list_for_each_entry(dev, &bus->devices, bus_list)
+		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+		    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+			if (dev->subordinate)
+				__pci_bus_size_bridges(dev->subordinate,
+							 &add_list);
+	up_read(&pci_bus_sem);
+	__pci_bus_assign_resources(bus, &add_list, NULL);
+	BUG_ON(!list_empty(&add_list));
+
+	pci_enable_bridges(bus);
+	pci_bus_add_devices(bus);
+
+	return max;
+}
+EXPORT_SYMBOL_GPL(pci_rescan_bus);
+#endif
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index b66bfdb..eea85da 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -114,7 +114,6 @@
 }
 EXPORT_SYMBOL(pci_claim_resource);
 
-#ifdef CONFIG_PCI_QUIRKS
 void pci_disable_bridge_window(struct pci_dev *dev)
 {
 	dev_info(&dev->dev, "disabling bridge mem windows\n");
@@ -127,9 +126,6 @@
 	pci_write_config_dword(dev, PCI_PREF_MEMORY_BASE, 0x0000fff0);
 	pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, 0xffffffff);
 }
-#endif	/* CONFIG_PCI_QUIRKS */
-
-
 
 static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
 		int resno, resource_size_t size, resource_size_t align)
@@ -158,22 +154,44 @@
 	return ret;
 }
 
+/*
+ * Generic function that returns a value indicating that the device's
+ * original BIOS BAR address was not saved and so is not available for
+ * reinstatement.
+ *
+ * Can be over-ridden by architecture specific code that implements
+ * reinstatement functionality rather than leaving it disabled when
+ * normal allocation attempts fail.
+ */
+resource_size_t __weak pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
+{
+	return 0;
+}
+
 static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev, 
 		int resno, resource_size_t size)
 {
 	struct resource *root, *conflict;
-	resource_size_t start, end;
+	resource_size_t fw_addr, start, end;
 	int ret = 0;
 
-	if (res->flags & IORESOURCE_IO)
-		root = &ioport_resource;
-	else
-		root = &iomem_resource;
+	fw_addr = pcibios_retrieve_fw_addr(dev, resno);
+	if (!fw_addr)
+		return 1;
 
 	start = res->start;
 	end = res->end;
-	res->start = dev->fw_addr[resno];
+	res->start = fw_addr;
 	res->end = res->start + size - 1;
+
+	root = pci_find_parent_resource(dev, res);
+	if (!root) {
+		if (res->flags & IORESOURCE_IO)
+			root = &ioport_resource;
+		else
+			root = &iomem_resource;
+	}
+
 	dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n",
 		 resno, res);
 	conflict = request_resource_conflict(root, res);
@@ -228,16 +246,17 @@
 	int ret;
 
 	if (!res->parent) {
-		dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resouce %pR "
+		dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resource %pR "
 			 "\n", resno, res);
 		return -EINVAL;
 	}
 
-	new_size = resource_size(res) + addsize + min_align;
+	/* already aligned with min_align */
+	new_size = resource_size(res) + addsize;
 	ret = _pci_assign_resource(dev, resno, new_size, min_align);
 	if (!ret) {
 		res->flags &= ~IORESOURCE_STARTALIGN;
-		dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
+		dev_info(&dev->dev, "BAR %d: reassigned %pR\n", resno, res);
 		if (resno < PCI_BRIDGE_RESOURCES)
 			pci_update_resource(dev, resno);
 	}
@@ -267,7 +286,7 @@
 	 * where firmware left it.  That at least has a chance of
 	 * working, which is better than just leaving it disabled.
 	 */
-	if (ret < 0 && dev->fw_addr[resno])
+	if (ret < 0)
 		ret = pci_revert_fw_address(res, dev, resno, size);
 
 	if (!ret) {
@@ -279,53 +298,6 @@
 	return ret;
 }
 
-
-/* Sort resources by alignment */
-void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
-{
-	int i;
-
-	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-		struct resource *r;
-		struct resource_list *list, *tmp;
-		resource_size_t r_align;
-
-		r = &dev->resource[i];
-
-		if (r->flags & IORESOURCE_PCI_FIXED)
-			continue;
-
-		if (!(r->flags) || r->parent)
-			continue;
-
-		r_align = pci_resource_alignment(dev, r);
-		if (!r_align) {
-			dev_warn(&dev->dev, "BAR %d: %pR has bogus alignment\n",
-				 i, r);
-			continue;
-		}
-		for (list = head; ; list = list->next) {
-			resource_size_t align = 0;
-			struct resource_list *ln = list->next;
-
-			if (ln)
-				align = pci_resource_alignment(ln->dev, ln->res);
-
-			if (r_align > align) {
-				tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
-				if (!tmp)
-					panic("pdev_sort_resources(): "
-					      "kmalloc() failed!\n");
-				tmp->next = ln;
-				tmp->res = r;
-				tmp->dev = dev;
-				list->next = tmp;
-				break;
-			}
-		}
-	}
-}
-
 int pci_enable_resources(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index 4010901..fd00ff0 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -544,7 +544,7 @@
 		dev = container_of(bus->devices.next, struct pci_dev,
 				   bus_list);
 		dev_dbg(&dev->dev, "removing device\n");
-		pci_remove_bus_device(dev);
+		pci_stop_and_remove_bus_device(dev);
 	}
 }
 
@@ -1044,7 +1044,7 @@
 				domain, bus, slot, func);
 			continue;
 		}
-		pci_remove_bus_device(pci_dev);
+		pci_stop_and_remove_bus_device(pci_dev);
 		pci_dev_put(pci_dev);
 
 		dev_dbg(&pdev->xdev->dev,
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index f9e3fb3..bba3ab2 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -183,10 +183,14 @@
 config PCMCIA_SOC_COMMON
 	tristate
 
+config PCMCIA_SA11XX_BASE
+	tristate
+
 config PCMCIA_SA1100
 	tristate "SA1100 support"
 	depends on ARM && ARCH_SA1100 && PCMCIA
 	select PCMCIA_SOC_COMMON
+	select PCMCIA_SA11XX_BASE
 	help
 	  Say Y here to include support for SA11x0-based PCMCIA or CF
 	  sockets, found on HP iPAQs, Yopy, and other StrongARM(R)/
@@ -196,8 +200,9 @@
 
 config PCMCIA_SA1111
 	tristate "SA1111 support"
-	depends on ARM && ARCH_SA1100 && SA1111 && PCMCIA
+	depends on ARM && SA1111 && PCMCIA
 	select PCMCIA_SOC_COMMON
+	select PCMCIA_SA11XX_BASE if ARCH_SA1100
 	help
 	  Say Y  here to include support for SA1111-based PCMCIA or CF
 	  sockets, found on the Jornada 720, Graphicsmaster and other
@@ -213,6 +218,7 @@
 		    || ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \
 		    || MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \
 		    || MACH_COLIBRI320)
+	select PCMCIA_SA1111 if ARCH_LUBBOCK && SA1111
 	select PCMCIA_SOC_COMMON
 	help
 	  Say Y here to include support for the PXA2xx PCMCIA controller
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index ec543a4..47525de 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -25,8 +25,9 @@
 obj-$(CONFIG_TCIC)				+= tcic.o
 obj-$(CONFIG_PCMCIA_M8XX)			+= m8xx_pcmcia.o
 obj-$(CONFIG_PCMCIA_SOC_COMMON)			+= soc_common.o
-obj-$(CONFIG_PCMCIA_SA1100)			+= sa11xx_base.o sa1100_cs.o
-obj-$(CONFIG_PCMCIA_SA1111)			+= sa11xx_base.o sa1111_cs.o
+obj-$(CONFIG_PCMCIA_SA11XX_BASE)		+= sa11xx_base.o
+obj-$(CONFIG_PCMCIA_SA1100)			+= sa1100_cs.o
+obj-$(CONFIG_PCMCIA_SA1111)			+= sa1111_cs.o
 obj-$(CONFIG_M32R_PCC)				+= m32r_pcc.o
 obj-$(CONFIG_M32R_CFC)				+= m32r_cfc.o
 obj-$(CONFIG_PCMCIA_BCM63XX)			+= bcm63xx_pcmcia.o
@@ -39,9 +40,10 @@
 obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD)		+= db1xxx_ss.o
 
 sa1111_cs-y					+= sa1111_generic.o
-sa1111_cs-$(CONFIG_ASSABET_NEPONSET)		+= sa1100_neponset.o
-sa1111_cs-$(CONFIG_SA1100_BADGE4)		+= sa1100_badge4.o
-sa1111_cs-$(CONFIG_SA1100_JORNADA720)		+= sa1100_jornada720.o
+sa1111_cs-$(CONFIG_ASSABET_NEPONSET)		+= sa1111_neponset.o
+sa1111_cs-$(CONFIG_SA1100_BADGE4)		+= sa1111_badge4.o
+sa1111_cs-$(CONFIG_SA1100_JORNADA720)		+= sa1111_jornada720.o
+sa1111_cs-$(CONFIG_ARCH_LUBBOCK)		+= sa1111_lubbock.o
 
 sa1100_cs-y					+= sa1100_generic.o
 sa1100_cs-$(CONFIG_SA1100_ASSABET)		+= sa1100_assabet.o
@@ -52,9 +54,7 @@
 sa1100_cs-$(CONFIG_SA1100_SHANNON)		+= sa1100_shannon.o
 sa1100_cs-$(CONFIG_SA1100_SIMPAD)		+= sa1100_simpad.o
 
-pxa2xx_lubbock_cs-y				+= pxa2xx_lubbock.o sa1111_generic.o
 pxa2xx_cm_x2xx_cs-y				+= pxa2xx_cm_x2xx.o pxa2xx_cm_x255.o pxa2xx_cm_x270.o
-pxa2xx-obj-$(CONFIG_ARCH_LUBBOCK)		+= pxa2xx_lubbock_cs.o
 pxa2xx-obj-$(CONFIG_MACH_MAINSTONE)		+= pxa2xx_mainstone.o
 pxa2xx-obj-$(CONFIG_PXA_SHARPSL)		+= pxa2xx_sharpsl.o
 pxa2xx-obj-$(CONFIG_MACH_ARMCORE)		+= pxa2xx_cm_x2xx_cs.o
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
index 4902206..9694c1e 100644
--- a/drivers/pcmcia/at91_cf.c
+++ b/drivers/pcmcia/at91_cf.c
@@ -16,16 +16,17 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
+#include <linux/gpio.h>
 
 #include <pcmcia/ss.h>
 
 #include <mach/hardware.h>
 #include <asm/io.h>
 #include <asm/sizes.h>
-#include <asm/gpio.h>
 
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 
 
 /*
@@ -69,7 +70,7 @@
 {
 	struct at91_cf_socket *cf = _cf;
 
-	if (irq == cf->board->det_pin) {
+	if (irq == gpio_to_irq(cf->board->det_pin)) {
 		unsigned present = at91_cf_present(cf);
 
 		/* kick pccard as needed */
@@ -95,8 +96,8 @@
 
 	/* NOTE: CF is always 3VCARD */
 	if (at91_cf_present(cf)) {
-		int rdy	= cf->board->irq_pin;	/* RDY/nIRQ */
-		int vcc	= cf->board->vcc_pin;
+		int rdy	= gpio_is_valid(cf->board->irq_pin);	/* RDY/nIRQ */
+		int vcc	= gpio_is_valid(cf->board->vcc_pin);
 
 		*sp = SS_DETECT | SS_3VCARD;
 		if (!rdy || gpio_get_value(rdy))
@@ -117,7 +118,7 @@
 	cf = container_of(sock, struct at91_cf_socket, socket);
 
 	/* switch Vcc if needed and possible */
-	if (cf->board->vcc_pin) {
+	if (gpio_is_valid(cf->board->vcc_pin)) {
 		switch (s->Vcc) {
 			case 0:
 				gpio_set_value(cf->board->vcc_pin, 0);
@@ -156,7 +157,7 @@
 	/*
 	 * Use 16 bit accesses unless/until we need 8-bit i/o space.
 	 */
-	csr = at91_sys_read(AT91_SMC_CSR(cf->board->chipselect)) & ~AT91_SMC_DBW;
+	csr = at91_ramc_read(0, AT91_SMC_CSR(cf->board->chipselect)) & ~AT91_SMC_DBW;
 
 	/*
 	 * NOTE: this CF controller ignores IOIS16, so we can't really do
@@ -175,7 +176,7 @@
 		csr |= AT91_SMC_DBW_16;
 		pr_debug("%s: 16bit i/o bus\n", driver_name);
 	}
-	at91_sys_write(AT91_SMC_CSR(cf->board->chipselect), csr);
+	at91_ramc_write(0, AT91_SMC_CSR(cf->board->chipselect), csr);
 
 	io->start = cf->socket.io_offset;
 	io->stop = io->start + SZ_2K - 1;
@@ -221,7 +222,7 @@
 	struct resource		*io;
 	int			status;
 
-	if (!board || !board->det_pin || !board->rst_pin)
+	if (!board || !gpio_is_valid(board->det_pin) || !gpio_is_valid(board->rst_pin))
 		return -ENODEV;
 
 	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -241,7 +242,7 @@
 	status = gpio_request(board->det_pin, "cf_det");
 	if (status < 0)
 		goto fail0;
-	status = request_irq(board->det_pin, at91_cf_irq, 0, driver_name, cf);
+	status = request_irq(gpio_to_irq(board->det_pin), at91_cf_irq, 0, driver_name, cf);
 	if (status < 0)
 		goto fail00;
 	device_init_wakeup(&pdev->dev, 1);
@@ -250,7 +251,7 @@
 	if (status < 0)
 		goto fail0a;
 
-	if (board->vcc_pin) {
+	if (gpio_is_valid(board->vcc_pin)) {
 		status = gpio_request(board->vcc_pin, "cf_vcc");
 		if (status < 0)
 			goto fail0b;
@@ -262,15 +263,15 @@
 	 * unless we report that we handle everything (sigh).
 	 * (Note:  DK board doesn't wire the IRQ pin...)
 	 */
-	if (board->irq_pin) {
+	if (gpio_is_valid(board->irq_pin)) {
 		status = gpio_request(board->irq_pin, "cf_irq");
 		if (status < 0)
 			goto fail0c;
-		status = request_irq(board->irq_pin, at91_cf_irq,
+		status = request_irq(gpio_to_irq(board->irq_pin), at91_cf_irq,
 				IRQF_SHARED, driver_name, cf);
 		if (status < 0)
 			goto fail0d;
-		cf->socket.pci_irq = board->irq_pin;
+		cf->socket.pci_irq = gpio_to_irq(board->irq_pin);
 	} else
 		cf->socket.pci_irq = nr_irqs + 1;
 
@@ -289,7 +290,7 @@
 	}
 
 	pr_info("%s: irqs det #%d, io #%d\n", driver_name,
-		board->det_pin, board->irq_pin);
+		gpio_to_irq(board->det_pin), gpio_to_irq(board->irq_pin));
 
 	cf->socket.owner = THIS_MODULE;
 	cf->socket.dev.parent = &pdev->dev;
@@ -311,19 +312,19 @@
 fail1:
 	if (cf->socket.io_offset)
 		iounmap((void __iomem *) cf->socket.io_offset);
-	if (board->irq_pin) {
-		free_irq(board->irq_pin, cf);
+	if (gpio_is_valid(board->irq_pin)) {
+		free_irq(gpio_to_irq(board->irq_pin), cf);
 fail0d:
 		gpio_free(board->irq_pin);
 	}
 fail0c:
-	if (board->vcc_pin)
+	if (gpio_is_valid(board->vcc_pin))
 		gpio_free(board->vcc_pin);
 fail0b:
 	gpio_free(board->rst_pin);
 fail0a:
 	device_init_wakeup(&pdev->dev, 0);
-	free_irq(board->det_pin, cf);
+	free_irq(gpio_to_irq(board->det_pin), cf);
 fail00:
 	gpio_free(board->det_pin);
 fail0:
@@ -340,15 +341,15 @@
 	pcmcia_unregister_socket(&cf->socket);
 	release_mem_region(io->start, resource_size(io));
 	iounmap((void __iomem *) cf->socket.io_offset);
-	if (board->irq_pin) {
-		free_irq(board->irq_pin, cf);
+	if (gpio_is_valid(board->irq_pin)) {
+		free_irq(gpio_to_irq(board->irq_pin), cf);
 		gpio_free(board->irq_pin);
 	}
-	if (board->vcc_pin)
+	if (gpio_is_valid(board->vcc_pin))
 		gpio_free(board->vcc_pin);
 	gpio_free(board->rst_pin);
 	device_init_wakeup(&pdev->dev, 0);
-	free_irq(board->det_pin, cf);
+	free_irq(gpio_to_irq(board->det_pin), cf);
 	gpio_free(board->det_pin);
 	kfree(cf);
 	return 0;
@@ -362,9 +363,9 @@
 	struct at91_cf_data	*board = cf->board;
 
 	if (device_may_wakeup(&pdev->dev)) {
-		enable_irq_wake(board->det_pin);
-		if (board->irq_pin)
-			enable_irq_wake(board->irq_pin);
+		enable_irq_wake(gpio_to_irq(board->det_pin));
+		if (gpio_is_valid(board->irq_pin))
+			enable_irq_wake(gpio_to_irq(board->irq_pin));
 	}
 	return 0;
 }
@@ -375,9 +376,9 @@
 	struct at91_cf_data	*board = cf->board;
 
 	if (device_may_wakeup(&pdev->dev)) {
-		disable_irq_wake(board->det_pin);
-		if (board->irq_pin)
-			disable_irq_wake(board->irq_pin);
+		disable_irq_wake(gpio_to_irq(board->det_pin));
+		if (gpio_is_valid(board->irq_pin))
+			disable_irq_wake(gpio_to_irq(board->irq_pin));
 	}
 
 	return 0;
diff --git a/drivers/pcmcia/bcm63xx_pcmcia.c b/drivers/pcmcia/bcm63xx_pcmcia.c
index 693577e..c2e997a 100644
--- a/drivers/pcmcia/bcm63xx_pcmcia.c
+++ b/drivers/pcmcia/bcm63xx_pcmcia.c
@@ -475,7 +475,7 @@
 	bcm63xx_cb_dev = NULL;
 }
 
-static struct pci_device_id bcm63xx_cb_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(bcm63xx_cb_table) = {
 	{
 		.vendor		= PCI_VENDOR_ID_BROADCOM,
 		.device		= BCM6348_CPU_ID,
diff --git a/drivers/pcmcia/bfin_cf_pcmcia.c b/drivers/pcmcia/bfin_cf_pcmcia.c
index 4922139..ac1a223 100644
--- a/drivers/pcmcia/bfin_cf_pcmcia.c
+++ b/drivers/pcmcia/bfin_cf_pcmcia.c
@@ -310,18 +310,7 @@
 	.remove = __devexit_p(bfin_cf_remove),
 };
 
-static int __init bfin_cf_init(void)
-{
-	return platform_driver_register(&bfin_cf_driver);
-}
-
-static void __exit bfin_cf_exit(void)
-{
-	platform_driver_unregister(&bfin_cf_driver);
-}
-
-module_init(bfin_cf_init);
-module_exit(bfin_cf_exit);
+module_platform_driver(bfin_cf_driver);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("BFIN CF/PCMCIA Driver");
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 9a58862..6e75153 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -108,5 +108,5 @@
 	struct pci_dev *bridge = s->cb_dev;
 
 	if (bridge)
-		pci_remove_behind_bridge(bridge);
+		pci_stop_and_remove_behind_bridge(bridge);
 }
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index d9ea192..673c14e 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -29,7 +29,6 @@
 #include <linux/device.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 
 #include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c
index 5b7c227..a484b1f 100644
--- a/drivers/pcmcia/db1xxx_ss.c
+++ b/drivers/pcmcia/db1xxx_ss.c
@@ -172,12 +172,12 @@
 	if ((sock->board_type == BOARD_TYPE_DB1200) ||
 	    (sock->board_type == BOARD_TYPE_DB1300)) {
 		ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq,
-				  IRQF_DISABLED, "pcmcia_insert", sock);
+				  0, "pcmcia_insert", sock);
 		if (ret)
 			goto out1;
 
 		ret = request_irq(sock->eject_irq, db1200_pcmcia_cdirq,
-				  IRQF_DISABLED, "pcmcia_eject", sock);
+				  0, "pcmcia_eject", sock);
 		if (ret) {
 			free_irq(sock->insert_irq, sock);
 			goto out1;
@@ -580,18 +580,7 @@
 	.remove		= __devexit_p(db1x_pcmcia_socket_remove),
 };
 
-int __init db1x_pcmcia_socket_load(void)
-{
-	return platform_driver_register(&db1x_pcmcia_socket_driver);
-}
-
-void  __exit db1x_pcmcia_socket_unload(void)
-{
-	platform_driver_unregister(&db1x_pcmcia_socket_driver);
-}
-
-module_init(db1x_pcmcia_socket_load);
-module_exit(db1x_pcmcia_socket_unload);
+module_platform_driver(db1x_pcmcia_socket_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("PCMCIA Socket Services for Alchemy Db/Pb1x00 boards");
diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c
index 06ad3e5..7647d23 100644
--- a/drivers/pcmcia/electra_cf.c
+++ b/drivers/pcmcia/electra_cf.c
@@ -365,17 +365,7 @@
 	.remove   = electra_cf_remove,
 };
 
-static int __init electra_cf_init(void)
-{
-	return platform_driver_register(&electra_cf_driver);
-}
-module_init(electra_cf_init);
-
-static void __exit electra_cf_exit(void)
-{
-	platform_driver_unregister(&electra_cf_driver);
-}
-module_exit(electra_cf_exit);
+module_platform_driver(electra_cf_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index 3e447d03..4e8831b 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -17,7 +17,6 @@
 
 #include <pcmcia/ss.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include "i82092aa.h"
@@ -26,14 +25,9 @@
 MODULE_LICENSE("GPL");
 
 /* PCI core routines */
-static struct pci_device_id i82092aa_pci_ids[] = {
-	{
-	      .vendor = PCI_VENDOR_ID_INTEL,
-	      .device = PCI_DEVICE_ID_INTEL_82092AA_0,
-	      .subvendor = PCI_ANY_ID,
-	      .subdevice = PCI_ANY_ID,
-	 },
-	 {} 
+static DEFINE_PCI_DEVICE_TABLE(i82092aa_pci_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82092AA_0) },
+	{ }
 };
 MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids);
 
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 72a033a..e6f3d17d 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -48,7 +48,6 @@
 #include <linux/bitops.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <pcmcia/ss.h>
 
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index 2adb010..a26f38c 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -24,7 +24,6 @@
 #include <linux/bitops.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <pcmcia/ss.h>
 
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index 1511ff7..2965141 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -24,7 +24,6 @@
 #include <linux/bitops.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/addrspace.h>
 
 #include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 271a590..a3a851e 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -52,7 +52,6 @@
 #include <linux/of_platform.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/mpc8xx.h>
 #include <asm/8xx_immap.h>
@@ -1304,15 +1303,4 @@
 	.remove = m8xx_remove,
 };
 
-static int __init m8xx_init(void)
-{
-	return platform_driver_register(&m8xx_pcmcia_driver);
-}
-
-static void __exit m8xx_exit(void)
-{
-	platform_driver_unregister(&m8xx_pcmcia_driver);
-}
-
-module_init(m8xx_init);
-module_exit(m8xx_exit);
+module_platform_driver(m8xx_pcmcia_driver);
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index 96c72e9..253e386 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -19,7 +19,6 @@
 
 #include <pcmcia/ss.h>
 
-#include <asm/system.h>
 
 #include "pd6729.h"
 #include "i82365.h"
@@ -763,13 +762,8 @@
 	kfree(socket);
 }
 
-static struct pci_device_id pd6729_pci_ids[] = {
-	{
-		.vendor		= PCI_VENDOR_ID_CIRRUS,
-		.device		= PCI_DEVICE_ID_CIRRUS_6729,
-		.subvendor	= PCI_ANY_ID,
-		.subdevice	= PCI_ANY_ID,
-	},
+static DEFINE_PCI_DEVICE_TABLE(pd6729_pci_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6729) },
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, pd6729_pci_ids);
diff --git a/drivers/pcmcia/pxa2xx_balloon3.c b/drivers/pcmcia/pxa2xx_balloon3.c
index 22a75e6..2ef576c 100644
--- a/drivers/pcmcia/pxa2xx_balloon3.c
+++ b/drivers/pcmcia/pxa2xx_balloon3.c
@@ -29,15 +29,6 @@
 
 #include "soc_common.h"
 
-/*
- * These are a list of interrupt sources that provokes a polled
- * check of status
- */
-static struct pcmcia_irqs irqs[] = {
-	{ 0, BALLOON3_S0_CD_IRQ, "PCMCIA0 CD" },
-	{ 0, BALLOON3_BP_NSTSCHG_IRQ, "PCMCIA0 STSCHG" },
-};
-
 static int balloon3_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
 	uint16_t ver;
@@ -49,12 +40,12 @@
 			ver);
 
 	skt->socket.pci_irq = BALLOON3_BP_CF_NRDY_IRQ;
-	return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
+	skt->stat[SOC_STAT_CD].gpio = BALLOON3_GPIO_S0_CD;
+	skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
+	skt->stat[SOC_STAT_BVD1].irq = BALLOON3_BP_NSTSCHG_IRQ;
+	skt->stat[SOC_STAT_BVD1].name = "PCMCIA0 STSCHG";
 
-static void balloon3_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+	return 0;
 }
 
 static unsigned long balloon3_pcmcia_status[2] = {
@@ -85,13 +76,11 @@
 			disable_irq(BALLOON3_BP_NSTSCHG_IRQ);
 	}
 
-	state->detect	= !gpio_get_value(BALLOON3_GPIO_S0_CD);
 	state->ready	= !!(status & BALLOON3_CF_nIRQ);
 	state->bvd1	= !!(status & BALLOON3_CF_nSTSCHG_BVD1);
 	state->bvd2	= 0;	/* not available */
 	state->vs_3v	= 1;	/* Always true its a CF card */
 	state->vs_Xv	= 0;	/* not available */
-	state->wrprot	= 0;	/* not available */
 }
 
 static int balloon3_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
@@ -106,7 +95,6 @@
 static struct pcmcia_low_level balloon3_pcmcia_ops = {
 	.owner			= THIS_MODULE,
 	.hw_init		= balloon3_pcmcia_hw_init,
-	.hw_shutdown		= balloon3_pcmcia_hw_shutdown,
 	.socket_state		= balloon3_pcmcia_socket_state,
 	.configure_socket	= balloon3_pcmcia_configure_socket,
 	.first			= 0,
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
index 64d433e..490bb82 100644
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -29,7 +29,6 @@
 #include <mach/smemc.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <mach/pxa2xx-regs.h>
 #include <asm/mach-types.h>
 
@@ -318,10 +317,7 @@
 
 		skt->nr = ops->first + i;
 		skt->clk = clk;
-		skt->ops = ops;
-		skt->socket.owner = ops->owner;
-		skt->socket.dev.parent = &dev->dev;
-		skt->socket.pci_irq = NO_IRQ;
+		soc_pcmcia_init_one(skt, ops, &dev->dev);
 
 		ret = pxa2xx_drv_pcmcia_add_one(skt);
 		if (ret)
diff --git a/drivers/pcmcia/pxa2xx_cm_x255.c b/drivers/pcmcia/pxa2xx_cm_x255.c
index 31ab6ddf..da40908 100644
--- a/drivers/pcmcia/pxa2xx_cm_x255.c
+++ b/drivers/pcmcia/pxa2xx_cm_x255.c
@@ -25,17 +25,6 @@
 #define GPIO_PCMCIA_S1_RDYINT	(8)
 #define GPIO_PCMCIA_RESET	(9)
 
-#define PCMCIA_S0_CD_VALID	gpio_to_irq(GPIO_PCMCIA_S0_CD_VALID)
-#define PCMCIA_S1_CD_VALID	gpio_to_irq(GPIO_PCMCIA_S1_CD_VALID)
-#define PCMCIA_S0_RDYINT	gpio_to_irq(GPIO_PCMCIA_S0_RDYINT)
-#define PCMCIA_S1_RDYINT	gpio_to_irq(GPIO_PCMCIA_S1_RDYINT)
-
-
-static struct pcmcia_irqs irqs[] = {
-	{ .sock = 0, .str = "PCMCIA0 CD" },
-	{ .sock = 1, .str = "PCMCIA1 CD" },
-};
-
 static int cmx255_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
 	int ret = gpio_request(GPIO_PCMCIA_RESET, "PCCard reset");
@@ -43,19 +32,23 @@
 		return ret;
 	gpio_direction_output(GPIO_PCMCIA_RESET, 0);
 
-	skt->socket.pci_irq = skt->nr == 0 ? PCMCIA_S0_RDYINT : PCMCIA_S1_RDYINT;
-	irqs[0].irq = PCMCIA_S0_CD_VALID;
-	irqs[1].irq = PCMCIA_S1_CD_VALID;
-	ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-	if (!ret)
-		gpio_free(GPIO_PCMCIA_RESET);
+	if (skt->nr == 0) {
+		skt->stat[SOC_STAT_CD].gpio = GPIO_PCMCIA_S0_CD_VALID;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
+		skt->stat[SOC_STAT_RDY].gpio = GPIO_PCMCIA_S0_RDYINT;
+		skt->stat[SOC_STAT_RDY].name = "PCMCIA0 RDY";
+	} else {
+		skt->stat[SOC_STAT_CD].gpio = GPIO_PCMCIA_S1_CD_VALID;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA1 CD";
+		skt->stat[SOC_STAT_RDY].gpio = GPIO_PCMCIA_S1_RDYINT;
+		skt->stat[SOC_STAT_RDY].name = "PCMCIA1 RDY";
+	}
 
-	return ret;
+	return 0;
 }
 
 static void cmx255_pcmcia_shutdown(struct soc_pcmcia_socket *skt)
 {
-	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
 	gpio_free(GPIO_PCMCIA_RESET);
 }
 
@@ -63,16 +56,8 @@
 static void cmx255_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
 				       struct pcmcia_state *state)
 {
-	int cd = skt->nr ? GPIO_PCMCIA_S1_CD_VALID : GPIO_PCMCIA_S0_CD_VALID;
-	int rdy = skt->nr ? GPIO_PCMCIA_S1_RDYINT : GPIO_PCMCIA_S0_RDYINT;
-
-	state->detect = !gpio_get_value(cd);
-	state->ready  = !!gpio_get_value(rdy);
-	state->bvd1   = 1;
-	state->bvd2   = 1;
 	state->vs_3v  = 0;
 	state->vs_Xv  = 0;
-	state->wrprot = 0;  /* not available */
 }
 
 
diff --git a/drivers/pcmcia/pxa2xx_cm_x270.c b/drivers/pcmcia/pxa2xx_cm_x270.c
index 3dc7621..f59223f 100644
--- a/drivers/pcmcia/pxa2xx_cm_x270.c
+++ b/drivers/pcmcia/pxa2xx_cm_x270.c
@@ -22,14 +22,6 @@
 #define GPIO_PCMCIA_S0_RDYINT	(82)
 #define GPIO_PCMCIA_RESET	(53)
 
-#define PCMCIA_S0_CD_VALID	gpio_to_irq(GPIO_PCMCIA_S0_CD_VALID)
-#define PCMCIA_S0_RDYINT	gpio_to_irq(GPIO_PCMCIA_S0_RDYINT)
-
-
-static struct pcmcia_irqs irqs[] = {
-	{ .sock = 0, .str = "PCMCIA0 CD" },
-};
-
 static int cmx270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
 	int ret = gpio_request(GPIO_PCMCIA_RESET, "PCCard reset");
@@ -37,18 +29,16 @@
 		return ret;
 	gpio_direction_output(GPIO_PCMCIA_RESET, 0);
 
-	skt->socket.pci_irq = PCMCIA_S0_RDYINT;
-	irqs[0].irq = PCMCIA_S0_CD_VALID;
-	ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-	if (!ret)
-		gpio_free(GPIO_PCMCIA_RESET);
+	skt->stat[SOC_STAT_CD].gpio = GPIO_PCMCIA_S0_CD_VALID;
+	skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
+	skt->stat[SOC_STAT_RDY].gpio = GPIO_PCMCIA_S0_RDYINT;
+	skt->stat[SOC_STAT_RDY].name = "PCMCIA0 RDY";
 
 	return ret;
 }
 
 static void cmx270_pcmcia_shutdown(struct soc_pcmcia_socket *skt)
 {
-	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
 	gpio_free(GPIO_PCMCIA_RESET);
 }
 
@@ -56,13 +46,8 @@
 static void cmx270_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
 				       struct pcmcia_state *state)
 {
-	state->detect = (gpio_get_value(GPIO_PCMCIA_S0_CD_VALID) == 0) ? 1 : 0;
-	state->ready  = (gpio_get_value(GPIO_PCMCIA_S0_RDYINT) == 0) ? 0 : 1;
-	state->bvd1   = 1;
-	state->bvd2   = 1;
 	state->vs_3v  = 0;
 	state->vs_Xv  = 0;
-	state->wrprot = 0;  /* not available */
 }
 
 
diff --git a/drivers/pcmcia/pxa2xx_colibri.c b/drivers/pcmcia/pxa2xx_colibri.c
index c6dec57..4dee7b2 100644
--- a/drivers/pcmcia/pxa2xx_colibri.c
+++ b/drivers/pcmcia/pxa2xx_colibri.c
@@ -53,13 +53,6 @@
 	{ 0,	GPIOF_INIT_HIGH,"PCMCIA Reset" },
 };
 
-static struct pcmcia_irqs colibri_irqs[] = {
-	{
-		.sock = 0,
-		.str  = "PCMCIA CD"
-	},
-};
-
 static int colibri_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
 	int ret;
@@ -69,19 +62,10 @@
 	if (ret)
 		goto err1;
 
-	colibri_irqs[0].irq = gpio_to_irq(colibri_pcmcia_gpios[DETECT].gpio);
 	skt->socket.pci_irq = gpio_to_irq(colibri_pcmcia_gpios[READY].gpio);
+	skt->stat[SOC_STAT_CD].irq = gpio_to_irq(colibri_pcmcia_gpios[DETECT].gpio);
+	skt->stat[SOC_STAT_CD].name = "PCMCIA CD";
 
-	ret = soc_pcmcia_request_irqs(skt, colibri_irqs,
-					ARRAY_SIZE(colibri_irqs));
-	if (ret)
-		goto err2;
-
-	return ret;
-
-err2:
-	gpio_free_array(colibri_pcmcia_gpios,
-			ARRAY_SIZE(colibri_pcmcia_gpios));
 err1:
 	return ret;
 }
@@ -100,7 +84,6 @@
 	state->ready  = !!gpio_get_value(colibri_pcmcia_gpios[READY].gpio);
 	state->bvd1   = !!gpio_get_value(colibri_pcmcia_gpios[BVD1].gpio);
 	state->bvd2   = !!gpio_get_value(colibri_pcmcia_gpios[BVD2].gpio);
-	state->wrprot = 0;
 	state->vs_3v  = 1;
 	state->vs_Xv  = 0;
 }
diff --git a/drivers/pcmcia/pxa2xx_e740.c b/drivers/pcmcia/pxa2xx_e740.c
index 17cd2ce..8751a32 100644
--- a/drivers/pcmcia/pxa2xx_e740.c
+++ b/drivers/pcmcia/pxa2xx_e740.c
@@ -23,53 +23,27 @@
 
 #include "soc_common.h"
 
-static struct pcmcia_irqs cd_irqs[] = {
-	{
-		.sock = 0,
-		.str  = "CF card detect"
-	},
-	{
-		.sock = 1,
-		.str  = "Wifi switch"
-	},
-};
-
 static int e740_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-	if (skt->nr == 0)
-		skt->socket.pci_irq = gpio_to_irq(GPIO_E740_PCMCIA_RDY0);
-	else
-		skt->socket.pci_irq = gpio_to_irq(GPIO_E740_PCMCIA_RDY1);
+	if (skt->nr == 0) {
+		skt->stat[SOC_STAT_CD].gpio = GPIO_E740_PCMCIA_CD0;
+		skt->stat[SOC_STAT_CD].name = "CF card detect";
+		skt->stat[SOC_STAT_RDY].gpio = GPIO_E740_PCMCIA_RDY0;
+		skt->stat[SOC_STAT_RDY].name = "CF ready";
+	} else {
+		skt->stat[SOC_STAT_CD].gpio = GPIO_E740_PCMCIA_CD1;
+		skt->stat[SOC_STAT_CD].name = "Wifi switch";
+		skt->stat[SOC_STAT_RDY].gpio = GPIO_E740_PCMCIA_RDY1;
+		skt->stat[SOC_STAT_RDY].name = "Wifi ready";
+	}
 
-	cd_irqs[0].irq = gpio_to_irq(GPIO_E740_PCMCIA_CD0);
-	cd_irqs[1].irq = gpio_to_irq(GPIO_E740_PCMCIA_CD1);
-
-	return soc_pcmcia_request_irqs(skt, &cd_irqs[skt->nr], 1);
-}
-
-/*
- * Release all resources.
- */
-static void e740_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_free_irqs(skt, &cd_irqs[skt->nr], 1);
+	return 0;
 }
 
 static void e740_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
 					struct pcmcia_state *state)
 {
-	if (skt->nr == 0) {
-		state->detect = gpio_get_value(GPIO_E740_PCMCIA_CD0) ? 0 : 1;
-		state->ready  = gpio_get_value(GPIO_E740_PCMCIA_RDY0) ? 1 : 0;
-	} else {
-		state->detect = gpio_get_value(GPIO_E740_PCMCIA_CD1) ? 0 : 1;
-		state->ready  = gpio_get_value(GPIO_E740_PCMCIA_RDY1) ? 1 : 0;
-	}
-
 	state->vs_3v  = 1;
-	state->bvd1   = 1;
-	state->bvd2   = 1;
-	state->wrprot = 0;
 	state->vs_Xv  = 0;
 }
 
@@ -109,32 +83,11 @@
 	return 0;
 }
 
-/*
- * Enable card status IRQs on (re-)initialisation.  This can
- * be called at initialisation, power management event, or
- * pcmcia event.
- */
-static void e740_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_enable_irqs(skt, cd_irqs, ARRAY_SIZE(cd_irqs));
-}
-
-/*
- * Disable card status IRQs on suspend.
- */
-static void e740_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_disable_irqs(skt, cd_irqs, ARRAY_SIZE(cd_irqs));
-}
-
 static struct pcmcia_low_level e740_pcmcia_ops = {
 	.owner            = THIS_MODULE,
 	.hw_init          = e740_pcmcia_hw_init,
-	.hw_shutdown      = e740_pcmcia_hw_shutdown,
 	.socket_state     = e740_pcmcia_socket_state,
 	.configure_socket = e740_pcmcia_configure_socket,
-	.socket_init      = e740_pcmcia_socket_init,
-	.socket_suspend   = e740_pcmcia_socket_suspend,
 	.nr               = 2,
 };
 
diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c
deleted file mode 100644
index c21888e..0000000
--- a/drivers/pcmcia/pxa2xx_lubbock.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * linux/drivers/pcmcia/pxa2xx_lubbock.c
- *
- * Author:	George Davis
- * Created:	Jan 10, 2002
- * Copyright:	MontaVista Software 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.
- *
- * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c
- *
- * Lubbock PCMCIA specific routines.
- *
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <mach/hardware.h>
-#include <asm/hardware/sa1111.h>
-#include <asm/mach-types.h>
-#include <mach/lubbock.h>
-
-#include "sa1111_generic.h"
-
-static int
-lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
-				const socket_state_t *state)
-{
-	struct sa1111_pcmcia_socket *s = to_skt(skt);
-	unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set;
-	int ret = 0;
-
-	pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0;
-
-	/* Lubbock uses the Maxim MAX1602, with the following connections:
-	 *
-	 * Socket 0 (PCMCIA):
-	 *	MAX1602	Lubbock		Register
-	 *	Pin	Signal
-	 *	-----	-------		----------------------
-	 *	A0VPP	S0_PWR0		SA-1111 GPIO A<0>
-	 *	A1VPP	S0_PWR1		SA-1111 GPIO A<1>
-	 *	A0VCC	S0_PWR2		SA-1111 GPIO A<2>
-	 *	A1VCC	S0_PWR3		SA-1111 GPIO A<3>
-	 *	VX	VCC
-	 *	VY	+3.3V
-	 *	12IN	+12V
-	 *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
-	 *
-	 * Socket 1 (CF):
-	 *	MAX1602	Lubbock		Register
-	 *	Pin	Signal
-	 *	-----	-------		----------------------
-	 *	A0VPP	GND		VPP is not connected
-	 *	A1VPP	GND		VPP is not connected
-	 *	A0VCC	S1_PWR0		MISC_WR<14>
-	 *	A1VCC	S1_PWR1		MISC_WR<15>
-	 *	VX	VCC
-	 *	VY	+3.3V
-	 *	12IN	GND		VPP is not connected
-	 *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
-	 *
-	 */
-
- again:
-	switch (skt->nr) {
-	case 0:
-		pa_dwr_mask = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
-
-		switch (state->Vcc) {
-		case 0: /* Hi-Z */
-			break;
-
-		case 33: /* VY */
-			pa_dwr_set |= GPIO_A3;
-			break;
-
-		case 50: /* VX */
-			pa_dwr_set |= GPIO_A2;
-			break;
-
-		default:
-			printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
-			       __func__, state->Vcc);
-			ret = -1;
-		}
-
-		switch (state->Vpp) {
-		case 0: /* Hi-Z */
-			break;
-
-		case 120: /* 12IN */
-			pa_dwr_set |= GPIO_A1;
-			break;
-
-		default: /* VCC */
-			if (state->Vpp == state->Vcc)
-				pa_dwr_set |= GPIO_A0;
-			else {
-				printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
-				       __func__, state->Vpp);
-				ret = -1;
-				break;
-			}
-		}
-		break;
-
-	case 1:
-		misc_mask = (1 << 15) | (1 << 14);
-
-		switch (state->Vcc) {
-		case 0: /* Hi-Z */
-			break;
-
-		case 33: /* VY */
-			misc_set |= 1 << 15;
-			break;
-
-		case 50: /* VX */
-			misc_set |= 1 << 14;
-			break;
-
-		default:
-			printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
-			       __func__, state->Vcc);
-			ret = -1;
-			break;
-		}
-
-		if (state->Vpp != state->Vcc && state->Vpp != 0) {
-			printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
-			       __func__, state->Vpp);
-			ret = -1;
-			break;
-		}
-		break;
-
-	default:
-		ret = -1;
-	}
-
-	if (ret == 0)
-		ret = sa1111_pcmcia_configure_socket(skt, state);
-
-	if (ret == 0) {
-		lubbock_set_misc_wr(misc_mask, misc_set);
-		sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
-	}
-
-#if 1
-	if (ret == 0 && state->Vcc == 33) {
-		struct pcmcia_state new_state;
-
-		/*
-		 * HACK ALERT:
-		 * We can't sense the voltage properly on Lubbock before
-		 * actually applying some power to the socket (catch 22).
-		 * Resense the socket Voltage Sense pins after applying
-		 * socket power.
-		 *
-		 * Note: It takes about 2.5ms for the MAX1602 VCC output
-		 * to rise.
-		 */
-		mdelay(3);
-
-		sa1111_pcmcia_socket_state(skt, &new_state);
-
-		if (!new_state.vs_3v && !new_state.vs_Xv) {
-			/*
-			 * Switch to 5V,  Configure socket with 5V voltage
-			 */
-			lubbock_set_misc_wr(misc_mask, 0);
-			sa1111_set_io(s->dev, pa_dwr_mask, 0);
-
-			/*
-			 * It takes about 100ms to turn off Vcc.
-			 */
-			mdelay(100);
-
-			/*
-			 * We need to hack around the const qualifier as
-			 * well to keep this ugly workaround localized and
-			 * not force it to the rest of the code. Barf bags
-			 * available in the seat pocket in front of you!
-			 */
-			((socket_state_t *)state)->Vcc = 50;
-			((socket_state_t *)state)->Vpp = 50;
-			goto again;
-		}
-	}
-#endif
-
-	return ret;
-}
-
-static struct pcmcia_low_level lubbock_pcmcia_ops = {
-	.owner			= THIS_MODULE,
-	.configure_socket	= lubbock_pcmcia_configure_socket,
-	.socket_init		= sa1111_pcmcia_socket_init,
-	.first			= 0,
-	.nr			= 2,
-};
-
-#include "pxa2xx_base.h"
-
-int pcmcia_lubbock_init(struct sa1111_dev *sadev)
-{
-	int ret = -ENODEV;
-
-	if (machine_is_lubbock()) {
-		/*
-		 * Set GPIO_A<3:0> to be outputs for the MAX1600,
-		 * and switch to standby mode.
-		 */
-		sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
-		sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
-		sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
-
-		/* Set CF Socket 1 power to standby mode. */
-		lubbock_set_misc_wr((1 << 15) | (1 << 14), 0);
-
-		pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops);
-		pxa2xx_configure_sockets(&sadev->dev);
-		ret = sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops,
-				pxa2xx_drv_pcmcia_add_one);
-	}
-
-	return ret;
-}
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c
index aded706c..7e32e25 100644
--- a/drivers/pcmcia/pxa2xx_mainstone.c
+++ b/drivers/pcmcia/pxa2xx_mainstone.c
@@ -30,27 +30,26 @@
 #include "soc_common.h"
 
 
-static struct pcmcia_irqs irqs[] = {
-	{ 0, MAINSTONE_S0_CD_IRQ, "PCMCIA0 CD" },
-	{ 1, MAINSTONE_S1_CD_IRQ, "PCMCIA1 CD" },
-	{ 0, MAINSTONE_S0_STSCHG_IRQ, "PCMCIA0 STSCHG" },
-	{ 1, MAINSTONE_S1_STSCHG_IRQ, "PCMCIA1 STSCHG" },
-};
-
 static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
 	/*
 	 * Setup default state of GPIO outputs
 	 * before we enable them as outputs.
 	 */
-
-	skt->socket.pci_irq = (skt->nr == 0) ? MAINSTONE_S0_IRQ : MAINSTONE_S1_IRQ;
-	return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-static void mst_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+	if (skt->nr == 0) {
+		skt->socket.pci_irq = MAINSTONE_S0_IRQ;
+		skt->stat[SOC_STAT_CD].irq = MAINSTONE_S0_CD_IRQ;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
+		skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S0_STSCHG_IRQ;
+		skt->stat[SOC_STAT_BVD1].name = "PCMCIA0 STSCHG";
+	} else {
+		skt->socket.pci_irq = MAINSTONE_S1_IRQ;
+		skt->stat[SOC_STAT_CD].irq = MAINSTONE_S1_CD_IRQ;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA1 CD";
+		skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S1_STSCHG_IRQ;
+		skt->stat[SOC_STAT_BVD1].name = "PCMCIA1 STSCHG";
+	}
+	return 0;
 }
 
 static unsigned long mst_pcmcia_status[2];
@@ -84,7 +83,6 @@
 	state->bvd2   = (status & MST_PCMCIA_nSPKR_BVD2) ? 1 : 0;
 	state->vs_3v  = (status & MST_PCMCIA_nVS1) ? 0 : 1;
 	state->vs_Xv  = (status & MST_PCMCIA_nVS2) ? 0 : 1;
-	state->wrprot = 0;  /* not available */
 }
 
 static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
@@ -131,7 +129,6 @@
 static struct pcmcia_low_level mst_pcmcia_ops __initdata = {
 	.owner			= THIS_MODULE,
 	.hw_init		= mst_pcmcia_hw_init,
-	.hw_shutdown		= mst_pcmcia_hw_shutdown,
 	.socket_state		= mst_pcmcia_socket_state,
 	.configure_socket	= mst_pcmcia_configure_socket,
 	.nr			= 2,
diff --git a/drivers/pcmcia/pxa2xx_palmld.c b/drivers/pcmcia/pxa2xx_palmld.c
index 6a8e011..ed7d4db 100644
--- a/drivers/pcmcia/pxa2xx_palmld.c
+++ b/drivers/pcmcia/pxa2xx_palmld.c
@@ -23,7 +23,6 @@
 static struct gpio palmld_pcmcia_gpios[] = {
 	{ GPIO_NR_PALMLD_PCMCIA_POWER,	GPIOF_INIT_LOW,	"PCMCIA Power" },
 	{ GPIO_NR_PALMLD_PCMCIA_RESET,	GPIOF_INIT_HIGH,"PCMCIA Reset" },
-	{ GPIO_NR_PALMLD_PCMCIA_READY,	GPIOF_IN,	"PCMCIA Ready" },
 };
 
 static int palmld_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
@@ -33,7 +32,8 @@
 	ret = gpio_request_array(palmld_pcmcia_gpios,
 				ARRAY_SIZE(palmld_pcmcia_gpios));
 
-	skt->socket.pci_irq = gpio_to_irq(GPIO_NR_PALMLD_PCMCIA_READY);
+	skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMLD_PCMCIA_READY;
+	skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
 
 	return ret;
 }
@@ -47,10 +47,6 @@
 					struct pcmcia_state *state)
 {
 	state->detect = 1; /* always inserted */
-	state->ready  = !!gpio_get_value(GPIO_NR_PALMLD_PCMCIA_READY);
-	state->bvd1   = 1;
-	state->bvd2   = 1;
-	state->wrprot = 0;
 	state->vs_3v  = 1;
 	state->vs_Xv  = 0;
 }
diff --git a/drivers/pcmcia/pxa2xx_palmtc.c b/drivers/pcmcia/pxa2xx_palmtc.c
index 9e38de7..81225a7 100644
--- a/drivers/pcmcia/pxa2xx_palmtc.c
+++ b/drivers/pcmcia/pxa2xx_palmtc.c
@@ -26,7 +26,6 @@
 	{ GPIO_NR_PALMTC_PCMCIA_POWER2,	GPIOF_INIT_LOW,	"PCMCIA Power 2" },
 	{ GPIO_NR_PALMTC_PCMCIA_POWER3,	GPIOF_INIT_LOW,	"PCMCIA Power 3" },
 	{ GPIO_NR_PALMTC_PCMCIA_RESET,	GPIOF_INIT_HIGH,"PCMCIA Reset" },
-	{ GPIO_NR_PALMTC_PCMCIA_READY,	GPIOF_IN,	"PCMCIA Ready" },
 	{ GPIO_NR_PALMTC_PCMCIA_PWRREADY, GPIOF_IN,	"PCMCIA Power Ready" },
 };
 
@@ -37,7 +36,8 @@
 	ret = gpio_request_array(palmtc_pcmcia_gpios,
 				ARRAY_SIZE(palmtc_pcmcia_gpios));
 
-	skt->socket.pci_irq = gpio_to_irq(GPIO_NR_PALMTC_PCMCIA_READY);
+	skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMTC_PCMCIA_READY;
+	skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
 
 	return ret;
 }
@@ -51,10 +51,6 @@
 					struct pcmcia_state *state)
 {
 	state->detect = 1; /* always inserted */
-	state->ready  = !!gpio_get_value(GPIO_NR_PALMTC_PCMCIA_READY);
-	state->bvd1   = 1;
-	state->bvd2   = 1;
-	state->wrprot = 0;
 	state->vs_3v  = 1;
 	state->vs_Xv  = 0;
 }
diff --git a/drivers/pcmcia/pxa2xx_palmtx.c b/drivers/pcmcia/pxa2xx_palmtx.c
index 80645a6..069b6bb 100644
--- a/drivers/pcmcia/pxa2xx_palmtx.c
+++ b/drivers/pcmcia/pxa2xx_palmtx.c
@@ -23,7 +23,6 @@
 	{ GPIO_NR_PALMTX_PCMCIA_POWER1,	GPIOF_INIT_LOW,	"PCMCIA Power 1" },
 	{ GPIO_NR_PALMTX_PCMCIA_POWER2,	GPIOF_INIT_LOW,	"PCMCIA Power 2" },
 	{ GPIO_NR_PALMTX_PCMCIA_RESET,	GPIOF_INIT_HIGH,"PCMCIA Reset" },
-	{ GPIO_NR_PALMTX_PCMCIA_READY,	GPIOF_IN,	"PCMCIA Ready" },
 };
 
 static int palmtx_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
@@ -33,7 +32,8 @@
 	ret = gpio_request_array(palmtx_pcmcia_gpios,
 				ARRAY_SIZE(palmtx_pcmcia_gpios));
 
-	skt->socket.pci_irq = gpio_to_irq(GPIO_NR_PALMTX_PCMCIA_READY);
+	skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMTX_PCMCIA_READY;
+	skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
 
 	return ret;
 }
@@ -47,10 +47,6 @@
 					struct pcmcia_state *state)
 {
 	state->detect = 1; /* always inserted */
-	state->ready  = !!gpio_get_value(GPIO_NR_PALMTX_PCMCIA_READY);
-	state->bvd1   = 1;
-	state->bvd2   = 1;
-	state->wrprot = 0;
 	state->vs_3v  = 1;
 	state->vs_Xv  = 0;
 }
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index 69ae2fd..b066273 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -46,21 +46,9 @@
 
 static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-	int ret;
-
-	/* Register interrupts */
 	if (SCOOP_DEV[skt->nr].cd_irq >= 0) {
-		struct pcmcia_irqs cd_irq;
-
-		cd_irq.sock = skt->nr;
-		cd_irq.irq  = SCOOP_DEV[skt->nr].cd_irq;
-		cd_irq.str  = SCOOP_DEV[skt->nr].cd_irq_str;
-		ret = soc_pcmcia_request_irqs(skt, &cd_irq, 1);
-
-		if (ret) {
-			printk(KERN_ERR "Request for Compact Flash IRQ failed\n");
-			return ret;
-		}
+		skt->stat[SOC_STAT_CD].irq = SCOOP_DEV[skt->nr].cd_irq;
+		skt->stat[SOC_STAT_CD].name = SCOOP_DEV[skt->nr].cd_irq_str;
 	}
 
 	skt->socket.pci_irq = SCOOP_DEV[skt->nr].irq;
@@ -68,19 +56,6 @@
 	return 0;
 }
 
-static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-	if (SCOOP_DEV[skt->nr].cd_irq >= 0) {
-		struct pcmcia_irqs cd_irq;
-
-		cd_irq.sock = skt->nr;
-		cd_irq.irq  = SCOOP_DEV[skt->nr].cd_irq;
-		cd_irq.str  = SCOOP_DEV[skt->nr].cd_irq_str;
-		soc_pcmcia_free_irqs(skt, &cd_irq, 1);
-	}
-}
-
-
 static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
 				    struct pcmcia_state *state)
 {
@@ -222,7 +197,6 @@
 static struct pcmcia_low_level sharpsl_pcmcia_ops __initdata = {
 	.owner                  = THIS_MODULE,
 	.hw_init                = sharpsl_pcmcia_hw_init,
-	.hw_shutdown            = sharpsl_pcmcia_hw_shutdown,
 	.socket_state           = sharpsl_pcmcia_socket_state,
 	.configure_socket       = sharpsl_pcmcia_configure_socket,
 	.socket_init            = sharpsl_pcmcia_socket_init,
diff --git a/drivers/pcmcia/pxa2xx_stargate2.c b/drivers/pcmcia/pxa2xx_stargate2.c
index 6c2366b..1d73c44 100644
--- a/drivers/pcmcia/pxa2xx_stargate2.c
+++ b/drivers/pcmcia/pxa2xx_stargate2.c
@@ -33,10 +33,6 @@
 #define SG2_S0_GPIO_DETECT	53
 #define SG2_S0_GPIO_READY	81
 
-static struct pcmcia_irqs irqs[] = {
-	{.sock = 0, .str = "PCMCIA0 CD" },
-};
-
 static struct gpio sg2_pcmcia_gpios[] = {
 	{ SG2_S0_GPIO_RESET, GPIOF_OUT_INIT_HIGH, "PCMCIA Reset" },
 	{ SG2_S0_POWER_CTL, GPIOF_OUT_INIT_HIGH, "PCMCIA Power Ctrl" },
@@ -44,27 +40,20 @@
 
 static int sg2_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-	skt->socket.pci_irq = gpio_to_irq(SG2_S0_GPIO_READY);
-	irqs[0].irq = gpio_to_irq(SG2_S0_GPIO_DETECT);
-
-	return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-static void sg2_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+	skt->stat[SOC_STAT_CD].gpio = SG2_S0_GPIO_DETECT;
+	skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
+	skt->stat[SOC_STAT_RDY].gpio = SG2_S0_GPIO_READY;
+	skt->stat[SOC_STAT_RDY].name = "PCMCIA0 RDY";
+	return 0;
 }
 
 static void sg2_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
 				    struct pcmcia_state *state)
 {
-	state->detect = !gpio_get_value(SG2_S0_GPIO_DETECT);
-	state->ready  = !!gpio_get_value(SG2_S0_GPIO_READY);
 	state->bvd1   = 0; /* not available - battery detect on card */
 	state->bvd2   = 0; /* not available */
 	state->vs_3v  = 1; /* not available - voltage detect for card */
 	state->vs_Xv  = 0; /* not available */
-	state->wrprot = 0; /* not available - write protect */
 }
 
 static int sg2_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
@@ -94,24 +83,11 @@
 	return 0;
 }
 
-static void sg2_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-static void sg2_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
 static struct pcmcia_low_level sg2_pcmcia_ops __initdata = {
 	.owner			= THIS_MODULE,
 	.hw_init		= sg2_pcmcia_hw_init,
-	.hw_shutdown		= sg2_pcmcia_hw_shutdown,
 	.socket_state		= sg2_pcmcia_socket_state,
 	.configure_socket	= sg2_pcmcia_configure_socket,
-	.socket_init		= sg2_pcmcia_socket_init,
-	.socket_suspend		= sg2_pcmcia_socket_suspend,
 	.nr			= 1,
 };
 
diff --git a/drivers/pcmcia/pxa2xx_trizeps4.c b/drivers/pcmcia/pxa2xx_trizeps4.c
index 7c33f89..d326ba1 100644
--- a/drivers/pcmcia/pxa2xx_trizeps4.c
+++ b/drivers/pcmcia/pxa2xx_trizeps4.c
@@ -29,32 +29,17 @@
 
 extern void board_pcmcia_power(int power);
 
-static struct pcmcia_irqs irqs[] = {
-	{ .sock = 0, .str = "cs0_cd" }
-	/* on other baseboards we can have more inputs */
-};
-
 static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-	int ret, i;
 	/* we dont have voltage/card/ready detection
 	 * so we dont need interrupts for it
 	 */
 	switch (skt->nr) {
 	case 0:
-		if (gpio_request(GPIO_PRDY, "cf_irq") < 0) {
-			pr_err("%s: sock %d unable to request gpio %d\n", __func__,
-				skt->nr, GPIO_PRDY);
-			return -EBUSY;
-		}
-		if (gpio_direction_input(GPIO_PRDY) < 0) {
-			pr_err("%s: sock %d unable to set input gpio %d\n", __func__,
-				skt->nr, GPIO_PRDY);
-			gpio_free(GPIO_PRDY);
-			return -EINVAL;
-		}
-		skt->socket.pci_irq = gpio_to_irq(GPIO_PRDY);
-		irqs[0].irq = gpio_to_irq(GPIO_PCD);
+		skt->stat[SOC_STAT_CD].gpio = GPIO_PCD;
+		skt->stat[SOC_STAT_CD].name = "cs0_cd";
+		skt->stat[SOC_STAT_RDY].gpio = GPIO_PRDY;
+		skt->stat[SOC_STAT_RDY].name = "cs0_rdy";
 		break;
 	default:
 		break;
@@ -62,39 +47,7 @@
 	/* release the reset of this card */
 	pr_debug("%s: sock %d irq %d\n", __func__, skt->nr, skt->socket.pci_irq);
 
-	/* supplementory irqs for the socket */
-	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
-		if (irqs[i].sock != skt->nr)
-			continue;
-		if (gpio_request(irq_to_gpio(irqs[i].irq), irqs[i].str) < 0) {
-			pr_err("%s: sock %d unable to request gpio %d\n",
-				__func__, skt->nr, irq_to_gpio(irqs[i].irq));
-			ret = -EBUSY;
-			goto error;
-		}
-		if (gpio_direction_input(irq_to_gpio(irqs[i].irq)) < 0) {
-			pr_err("%s: sock %d unable to set input gpio %d\n",
-				__func__, skt->nr, irq_to_gpio(irqs[i].irq));
-			ret = -EINVAL;
-			goto error;
-		}
-	}
-	return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-
-error:
-	for (; i >= 0; i--) {
-		gpio_free(irq_to_gpio(irqs[i].irq));
-	}
-	return (ret);
-}
-
-static void trizeps_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-	int i;
-	/* free allocated gpio's */
-	gpio_free(GPIO_PRDY);
-	for (i = 0; i < ARRAY_SIZE(irqs); i++)
-		gpio_free(irq_to_gpio(irqs[i].irq));
+	return 0;
 }
 
 static unsigned long trizeps_pcmcia_status[2];
@@ -118,13 +71,10 @@
 	switch (skt->nr) {
 	case 0:
 		/* just fill in fix states */
-		state->detect = gpio_get_value(GPIO_PCD) ? 0 : 1;
-		state->ready  = gpio_get_value(GPIO_PRDY) ? 1 : 0;
 		state->bvd1   = (status & ConXS_CFSR_BVD1) ? 1 : 0;
 		state->bvd2   = (status & ConXS_CFSR_BVD2) ? 1 : 0;
 		state->vs_3v  = (status & ConXS_CFSR_VS1) ? 0 : 1;
 		state->vs_Xv  = (status & ConXS_CFSR_VS2) ? 0 : 1;
-		state->wrprot = 0;	/* not available */
 		break;
 
 #ifndef CONFIG_MACH_TRIZEPS_CONXS
@@ -136,7 +86,6 @@
 		state->bvd2   = 0;
 		state->vs_3v  = 0;
 		state->vs_Xv  = 0;
-		state->wrprot = 0;
 		break;
 
 #endif
@@ -204,7 +153,6 @@
 static struct pcmcia_low_level trizeps_pcmcia_ops = {
 	.owner			= THIS_MODULE,
 	.hw_init		= trizeps_pcmcia_hw_init,
-	.hw_shutdown		= trizeps_pcmcia_hw_shutdown,
 	.socket_state		= trizeps_pcmcia_socket_state,
 	.configure_socket	= trizeps_pcmcia_configure_socket,
 	.socket_init		= trizeps_pcmcia_socket_init,
diff --git a/drivers/pcmcia/pxa2xx_viper.c b/drivers/pcmcia/pxa2xx_viper.c
index 1064b1c..cb0c37e 100644
--- a/drivers/pcmcia/pxa2xx_viper.c
+++ b/drivers/pcmcia/pxa2xx_viper.c
@@ -32,13 +32,6 @@
 
 static struct platform_device *arcom_pcmcia_dev;
 
-static struct pcmcia_irqs irqs[] = {
-	{
-		.sock	= 0,
-		.str	= "PCMCIA_CD",
-	},
-};
-
 static inline struct arcom_pcmcia_pdata *viper_get_pdata(void)
 {
 	return arcom_pcmcia_dev->dev.platform_data;
@@ -49,38 +42,28 @@
 	struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
 	unsigned long flags;
 
-	skt->socket.pci_irq = gpio_to_irq(pdata->rdy_gpio);
-	irqs[0].irq = gpio_to_irq(pdata->cd_gpio);
-
-	if (gpio_request(pdata->cd_gpio, "CF detect"))
-		goto err_request_cd;
-
-	if (gpio_request(pdata->rdy_gpio, "CF ready"))
-		goto err_request_rdy;
+	skt->stat[SOC_STAT_CD].gpio = pdata->cd_gpio;
+	skt->stat[SOC_STAT_CD].name = "PCMCIA_CD";
+	skt->stat[SOC_STAT_RDY].gpio = pdata->rdy_gpio;
+	skt->stat[SOC_STAT_RDY].name = "CF ready";
 
 	if (gpio_request(pdata->pwr_gpio, "CF power"))
 		goto err_request_pwr;
 
 	local_irq_save(flags);
 
-	if (gpio_direction_output(pdata->pwr_gpio, 0) ||
-	    gpio_direction_input(pdata->cd_gpio) ||
-	    gpio_direction_input(pdata->rdy_gpio)) {
+	if (gpio_direction_output(pdata->pwr_gpio, 0)) {
 		local_irq_restore(flags);
 		goto err_dir;
 	}
 
 	local_irq_restore(flags);
 
-	return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+	return 0;
 
 err_dir:
 	gpio_free(pdata->pwr_gpio);
 err_request_pwr:
-	gpio_free(pdata->rdy_gpio);
-err_request_rdy:
-	gpio_free(pdata->cd_gpio);
-err_request_cd:
 	dev_err(&arcom_pcmcia_dev->dev, "Failed to setup PCMCIA GPIOs\n");
 	return -1;
 }
@@ -92,22 +75,12 @@
 {
 	struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
 
-	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
 	gpio_free(pdata->pwr_gpio);
-	gpio_free(pdata->rdy_gpio);
-	gpio_free(pdata->cd_gpio);
 }
 
 static void viper_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
 				      struct pcmcia_state *state)
 {
-	struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
-
-	state->detect = !gpio_get_value(pdata->cd_gpio);
-	state->ready  = !!gpio_get_value(pdata->rdy_gpio);
-	state->bvd1   = 1;
-	state->bvd2   = 1;
-	state->wrprot = 0;
 	state->vs_3v  = 1; /* Can only apply 3.3V */
 	state->vs_Xv  = 0;
 }
@@ -204,18 +177,7 @@
 	.id_table	= viper_pcmcia_id_table,
 };
 
-static int __init viper_pcmcia_init(void)
-{
-	return platform_driver_register(&viper_pcmcia_driver);
-}
-
-static void __exit viper_pcmcia_exit(void)
-{
-	return platform_driver_unregister(&viper_pcmcia_driver);
-}
-
-module_init(viper_pcmcia_init);
-module_exit(viper_pcmcia_exit);
+module_platform_driver(viper_pcmcia_driver);
 
 MODULE_DEVICE_TABLE(platform, viper_pcmcia_id_table);
 MODULE_LICENSE("GPL");
diff --git a/drivers/pcmcia/pxa2xx_vpac270.c b/drivers/pcmcia/pxa2xx_vpac270.c
index 61b17d2..a47dcd2 100644
--- a/drivers/pcmcia/pxa2xx_vpac270.c
+++ b/drivers/pcmcia/pxa2xx_vpac270.c
@@ -23,29 +23,14 @@
 #include "soc_common.h"
 
 static struct gpio vpac270_pcmcia_gpios[] = {
-	{ GPIO84_VPAC270_PCMCIA_CD,	GPIOF_IN,	"PCMCIA Card Detect" },
-	{ GPIO35_VPAC270_PCMCIA_RDY,	GPIOF_IN,	"PCMCIA Ready" },
 	{ GPIO107_VPAC270_PCMCIA_PPEN,	GPIOF_INIT_LOW,	"PCMCIA PPEN" },
 	{ GPIO11_VPAC270_PCMCIA_RESET,	GPIOF_INIT_LOW,	"PCMCIA Reset" },
 };
 
 static struct gpio vpac270_cf_gpios[] = {
-	{ GPIO17_VPAC270_CF_CD,		GPIOF_IN,	"CF Card Detect" },
-	{ GPIO12_VPAC270_CF_RDY,	GPIOF_IN,	"CF Ready" },
 	{ GPIO16_VPAC270_CF_RESET,	GPIOF_INIT_LOW,	"CF Reset" },
 };
 
-static struct pcmcia_irqs cd_irqs[] = {
-	{
-		.sock = 0,
-		.str  = "PCMCIA CD"
-	},
-	{
-		.sock = 1,
-		.str  = "CF CD"
-	},
-};
-
 static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
 	int ret;
@@ -54,20 +39,18 @@
 		ret = gpio_request_array(vpac270_pcmcia_gpios,
 				ARRAY_SIZE(vpac270_pcmcia_gpios));
 
-		skt->socket.pci_irq = gpio_to_irq(GPIO35_VPAC270_PCMCIA_RDY);
-		cd_irqs[0].irq = gpio_to_irq(GPIO84_VPAC270_PCMCIA_CD);
-
-		if (!ret)
-			ret = soc_pcmcia_request_irqs(skt, &cd_irqs[0], 1);
+		skt->stat[SOC_STAT_CD].gpio = GPIO84_VPAC270_PCMCIA_CD;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA CD";
+		skt->stat[SOC_STAT_RDY].gpio = GPIO35_VPAC270_PCMCIA_RDY;
+		skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
 	} else {
 		ret = gpio_request_array(vpac270_cf_gpios,
 				ARRAY_SIZE(vpac270_cf_gpios));
 
-		skt->socket.pci_irq = gpio_to_irq(GPIO12_VPAC270_CF_RDY);
-		cd_irqs[1].irq = gpio_to_irq(GPIO17_VPAC270_CF_CD);
-
-		if (!ret)
-			ret = soc_pcmcia_request_irqs(skt, &cd_irqs[1], 1);
+		skt->stat[SOC_STAT_CD].gpio = GPIO17_VPAC270_CF_CD;
+		skt->stat[SOC_STAT_CD].name = "CF CD";
+		skt->stat[SOC_STAT_RDY].gpio = GPIO12_VPAC270_CF_RDY;
+		skt->stat[SOC_STAT_RDY].name = "CF Ready";
 	}
 
 	return ret;
@@ -86,16 +69,6 @@
 static void vpac270_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
 					struct pcmcia_state *state)
 {
-	if (skt->nr == 0) {
-		state->detect = !gpio_get_value(GPIO84_VPAC270_PCMCIA_CD);
-		state->ready  = !!gpio_get_value(GPIO35_VPAC270_PCMCIA_RDY);
-	} else {
-		state->detect = !gpio_get_value(GPIO17_VPAC270_CF_CD);
-		state->ready  = !!gpio_get_value(GPIO12_VPAC270_CF_RDY);
-	}
-	state->bvd1   = 1;
-	state->bvd2   = 1;
-	state->wrprot = 0;
 	state->vs_3v  = 1;
 	state->vs_Xv  = 0;
 }
@@ -117,14 +90,6 @@
 	return 0;
 }
 
-static void vpac270_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void vpac270_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level vpac270_pcmcia_ops = {
 	.owner			= THIS_MODULE,
 
@@ -136,9 +101,6 @@
 
 	.socket_state		= vpac270_pcmcia_socket_state,
 	.configure_socket	= vpac270_pcmcia_configure_socket,
-
-	.socket_init		= vpac270_pcmcia_socket_init,
-	.socket_suspend		= vpac270_pcmcia_socket_suspend,
 };
 
 static struct platform_device *vpac270_pcmcia_device;
diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c
index f1e8822..ba8557e 100644
--- a/drivers/pcmcia/sa1100_assabet.c
+++ b/drivers/pcmcia/sa1100_assabet.c
@@ -10,46 +10,30 @@
 #include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/irq.h>
-#include <asm/signal.h>
 #include <mach/assabet.h>
 
 #include "sa1100_generic.h"
 
-static struct pcmcia_irqs irqs[] = {
-	{ 1, ASSABET_IRQ_GPIO_CF_CD,   "CF CD"   },
-	{ 1, ASSABET_IRQ_GPIO_CF_BVD2, "CF BVD2" },
-	{ 1, ASSABET_IRQ_GPIO_CF_BVD1, "CF BVD1" },
-};
-
 static int assabet_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-	skt->socket.pci_irq = ASSABET_IRQ_GPIO_CF_IRQ;
+	skt->stat[SOC_STAT_CD].gpio = ASSABET_GPIO_CF_CD;
+	skt->stat[SOC_STAT_CD].name = "CF CD";
+	skt->stat[SOC_STAT_BVD1].gpio = ASSABET_GPIO_CF_BVD1;
+	skt->stat[SOC_STAT_BVD1].name = "CF BVD1";
+	skt->stat[SOC_STAT_BVD2].gpio = ASSABET_GPIO_CF_BVD2;
+	skt->stat[SOC_STAT_BVD2].name = "CF BVD2";
+	skt->stat[SOC_STAT_RDY].gpio = ASSABET_GPIO_CF_IRQ;
+	skt->stat[SOC_STAT_RDY].name = "CF RDY";
 
-	return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-/*
- * Release all resources.
- */
-static void assabet_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+	return 0;
 }
 
 static void
 assabet_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
 {
-	unsigned long levels = GPLR;
-
-	state->detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1;
-	state->ready  = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0;
-	state->bvd1   = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0;
-	state->bvd2   = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0;
-	state->wrprot = 0; /* Not available on Assabet. */
 	state->vs_3v  = 1; /* Can only apply 3.3V on Assabet. */
 	state->vs_Xv  = 0;
 }
@@ -78,38 +62,24 @@
 		return -1;
 	}
 
-	/* Silently ignore Vpp, output enable, speaker enable. */
+	/* Silently ignore Vpp, speaker enable. */
 
 	if (state->flags & SS_RESET)
 		mask |= ASSABET_BCR_CF_RST;
+	if (!(state->flags & SS_OUTPUT_ENA))
+		mask |= ASSABET_BCR_CF_BUS_OFF;
 
-	ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR, mask);
+	ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR |
+			ASSABET_BCR_CF_BUS_OFF, mask);
 
 	return 0;
 }
 
 /*
- * Enable card status IRQs on (re-)initialisation.  This can
- * be called at initialisation, power management event, or
- * pcmcia event.
- */
-static void assabet_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-	/*
-	 * Enable CF bus
-	 */
-	ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF);
-
-	soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-/*
  * Disable card status IRQs on suspend.
  */
 static void assabet_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 {
-	soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-
 	/*
 	 * Tristate the CF bus signals.  Also assert CF
 	 * reset as per user guide page 4-11.
@@ -119,14 +89,9 @@
 
 static struct pcmcia_low_level assabet_pcmcia_ops = { 
 	.owner			= THIS_MODULE,
-
 	.hw_init		= assabet_pcmcia_hw_init,
-	.hw_shutdown		= assabet_pcmcia_hw_shutdown,
-
 	.socket_state		= assabet_pcmcia_socket_state,
 	.configure_socket	= assabet_pcmcia_configure_socket,
-
-	.socket_init		= assabet_pcmcia_socket_init,
 	.socket_suspend		= assabet_pcmcia_socket_suspend,
 };
 
diff --git a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c
deleted file mode 100644
index 1ce53f4..0000000
--- a/drivers/pcmcia/sa1100_badge4.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * linux/drivers/pcmcia/sa1100_badge4.c
- *
- * BadgePAD 4 PCMCIA specific routines
- *
- *   Christopher Hoover <ch@hpl.hp.com>
- *
- * Copyright (C) 2002 Hewlett-Packard Company
- *
- * 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/kernel.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <mach/badge4.h>
-#include <asm/hardware/sa1111.h>
-
-#include "sa1111_generic.h"
-
-/*
- * BadgePAD 4 Details
- *
- * PCM Vcc:
- *
- *  PCM Vcc on BadgePAD 4 can be jumpered for 3v3 (short pins 1 and 3
- *  on JP6) or 5v0 (short pins 3 and 5 on JP6).
- *
- * PCM Vpp:
- *
- *  PCM Vpp on BadgePAD 4 can be jumpered for 12v0 (short pins 4 and 6
- *  on JP6) or tied to PCM Vcc (short pins 2 and 4 on JP6).  N.B.,
- *  12v0 operation requires that the power supply actually supply 12v0
- *  via pin 7 of JP7.
- *
- * CF Vcc:
- *
- *  CF Vcc on BadgePAD 4 can be jumpered either for 3v3 (short pins 1
- *  and 2 on JP10) or 5v0 (short pins 2 and 3 on JP10).
- *
- * Unfortunately there's no way programmatically to determine how a
- * given board is jumpered.  This code assumes a default jumpering
- * as described below.
- *
- * If the defaults aren't correct, you may override them with a pcmv
- * setup argument: pcmv=<pcm vcc>,<pcm vpp>,<cf vcc>.  The units are
- * tenths of volts; e.g. pcmv=33,120,50 indicates 3v3 PCM Vcc, 12v0
- * PCM Vpp, and 5v0 CF Vcc.
- *
- */
-
-static int badge4_pcmvcc = 50;  /* pins 3 and 5 jumpered on JP6 */
-static int badge4_pcmvpp = 50;  /* pins 2 and 4 jumpered on JP6 */
-static int badge4_cfvcc = 33;   /* pins 1 and 2 jumpered on JP10 */
-
-static void complain_about_jumpering(const char *whom,
-				     const char *supply,
-				     int given, int wanted)
-{
-	printk(KERN_ERR
-	 "%s: %s %d.%dV wanted but board is jumpered for %s %d.%dV operation"
-	 "; re-jumper the board and/or use pcmv=xx,xx,xx\n",
-	       whom, supply,
-	       wanted / 10, wanted % 10,
-	       supply,
-	       given / 10, given % 10);
-}
-
-static int
-badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
-{
-	int ret;
-
-	switch (skt->nr) {
-	case 0:
-		if ((state->Vcc != 0) &&
-		    (state->Vcc != badge4_pcmvcc)) {
-			complain_about_jumpering(__func__, "pcmvcc",
-						 badge4_pcmvcc, state->Vcc);
-			// Apply power regardless of the jumpering.
-			// return -1;
-		}
-		if ((state->Vpp != 0) &&
-		    (state->Vpp != badge4_pcmvpp)) {
-			complain_about_jumpering(__func__, "pcmvpp",
-						 badge4_pcmvpp, state->Vpp);
-			return -1;
-		}
-		break;
-
-	case 1:
-		if ((state->Vcc != 0) &&
-		    (state->Vcc != badge4_cfvcc)) {
-			complain_about_jumpering(__func__, "cfvcc",
-						 badge4_cfvcc, state->Vcc);
-			return -1;
-		}
-		break;
-
-	default:
-		return -1;
-	}
-
-	ret = sa1111_pcmcia_configure_socket(skt, state);
-	if (ret == 0) {
-		unsigned long flags;
-		int need5V;
-
-		local_irq_save(flags);
-
-		need5V = ((state->Vcc == 50) || (state->Vpp == 50));
-
-		badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(skt->nr), need5V);
-
-		local_irq_restore(flags);
-	}
-
-	return 0;
-}
-
-static struct pcmcia_low_level badge4_pcmcia_ops = {
-	.owner			= THIS_MODULE,
-	.configure_socket	= badge4_pcmcia_configure_socket,
-	.socket_init		= sa1111_pcmcia_socket_init,
-	.first			= 0,
-	.nr			= 2,
-};
-
-int pcmcia_badge4_init(struct device *dev)
-{
-	int ret = -ENODEV;
-
-	if (machine_is_badge4()) {
-		printk(KERN_INFO
-		       "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
-		       __func__,
-		       badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
-
-		sa11xx_drv_pcmcia_ops(&badge4_pcmcia_ops);
-		ret = sa1111_pcmcia_add(dev, &badge4_pcmcia_ops,
-				sa11xx_drv_pcmcia_add_one);
-	}
-
-	return ret;
-}
-
-static int __init pcmv_setup(char *s)
-{
-	int v[4];
-
-	s = get_options(s, ARRAY_SIZE(v), v);
-
-	if (v[0] >= 1) badge4_pcmvcc = v[1];
-	if (v[0] >= 2) badge4_pcmvpp = v[2];
-	if (v[0] >= 3) badge4_cfvcc = v[3];
-
-	return 1;
-}
-
-__setup("pcmv=", pcmv_setup);
diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c
index 30560df..c59c449 100644
--- a/drivers/pcmcia/sa1100_cerf.c
+++ b/drivers/pcmcia/sa1100_cerf.c
@@ -10,6 +10,7 @@
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -19,34 +20,34 @@
 
 #define CERF_SOCKET	1
 
-static struct pcmcia_irqs irqs[] = {
-	{ CERF_SOCKET, CERF_IRQ_GPIO_CF_CD,   "CF_CD"   },
-	{ CERF_SOCKET, CERF_IRQ_GPIO_CF_BVD2, "CF_BVD2" },
-	{ CERF_SOCKET, CERF_IRQ_GPIO_CF_BVD1, "CF_BVD1" }
-};
-
 static int cerf_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-	skt->socket.pci_irq = CERF_IRQ_GPIO_CF_IRQ;
+	int ret;
 
-	return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+	ret = gpio_request_one(CERF_GPIO_CF_RESET, GPIOF_OUT_INIT_LOW, "CF_RESET");
+	if (ret)
+		return ret;
+
+	skt->stat[SOC_STAT_CD].gpio = CERF_GPIO_CF_CD;
+	skt->stat[SOC_STAT_CD].name = "CF_CD";
+	skt->stat[SOC_STAT_BVD1].gpio = CERF_GPIO_CF_BVD1;
+	skt->stat[SOC_STAT_BVD1].name = "CF_BVD1";
+	skt->stat[SOC_STAT_BVD2].gpio = CERF_GPIO_CF_BVD2;
+	skt->stat[SOC_STAT_BVD2].name = "CF_BVD2";
+	skt->stat[SOC_STAT_RDY].gpio = CERF_GPIO_CF_IRQ;
+	skt->stat[SOC_STAT_RDY].name = "CF_IRQ";
+
+	return 0;
 }
 
 static void cerf_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 {
-	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+	gpio_free(CERF_GPIO_CF_RESET);
 }
 
 static void
 cerf_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
 {
-	unsigned long levels = GPLR;
-
-	state->detect	= (levels & CERF_GPIO_CF_CD)  ?0:1;
-	state->ready	= (levels & CERF_GPIO_CF_IRQ) ?1:0;
-	state->bvd1	= (levels & CERF_GPIO_CF_BVD1)?1:0;
-	state->bvd2	= (levels & CERF_GPIO_CF_BVD2)?1:0;
-	state->wrprot	= 0;
 	state->vs_3v	= 1;
 	state->vs_Xv	= 0;
 }
@@ -67,34 +68,17 @@
 		return -1;
 	}
 
-	if (state->flags & SS_RESET) {
-		GPSR = CERF_GPIO_CF_RESET;
-	} else {
-		GPCR = CERF_GPIO_CF_RESET;
-	}
+	gpio_set_value(CERF_GPIO_CF_RESET, !!(state->flags & SS_RESET));
 
 	return 0;
 }
 
-static void cerf_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-static void cerf_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
 static struct pcmcia_low_level cerf_pcmcia_ops = { 
 	.owner			= THIS_MODULE,
 	.hw_init		= cerf_pcmcia_hw_init,
 	.hw_shutdown		= cerf_pcmcia_hw_shutdown,
 	.socket_state		= cerf_pcmcia_socket_state,
 	.configure_socket	= cerf_pcmcia_configure_socket,
-
-	.socket_init		= cerf_pcmcia_socket_init,
-	.socket_suspend		= cerf_pcmcia_socket_suspend,
 };
 
 int __devinit pcmcia_cerf_init(struct device *dev)
diff --git a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c
index edf8f00..d9c7337 100644
--- a/drivers/pcmcia/sa1100_h3600.c
+++ b/drivers/pcmcia/sa1100_h3600.c
@@ -19,36 +19,20 @@
 
 #include "sa1100_generic.h"
 
-static struct pcmcia_irqs irqs[] = {
-	{ .sock = 0, .str = "PCMCIA CD0" }, /* .irq will be filled later */
-	{ .sock = 1, .str = "PCMCIA CD1" }
-};
-
 static int h3600_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
 	int err;
 
 	switch (skt->nr) {
 	case 0:
-		err = gpio_request(H3XXX_GPIO_PCMCIA_IRQ0, "PCMCIA IRQ0");
-		if (err)
-			goto err00;
-		err = gpio_direction_input(H3XXX_GPIO_PCMCIA_IRQ0);
-		if (err)
-			goto err01;
-		skt->socket.pci_irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_IRQ0);
-
-		err = gpio_request(H3XXX_GPIO_PCMCIA_CD0, "PCMCIA CD0");
-		if (err)
-			goto err01;
-		err = gpio_direction_input(H3XXX_GPIO_PCMCIA_CD0);
-		if (err)
-			goto err02;
-		irqs[0].irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_CD0);
+		skt->stat[SOC_STAT_CD].gpio = H3XXX_GPIO_PCMCIA_CD0;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA CD0";
+		skt->stat[SOC_STAT_RDY].gpio = H3XXX_GPIO_PCMCIA_IRQ0;
+		skt->stat[SOC_STAT_RDY].name = "PCMCIA IRQ0";
 
 		err = gpio_request(H3XXX_EGPIO_OPT_NVRAM_ON, "OPT NVRAM ON");
 		if (err)
-			goto err02;
+			goto err01;
 		err = gpio_direction_output(H3XXX_EGPIO_OPT_NVRAM_ON, 0);
 		if (err)
 			goto err03;
@@ -70,30 +54,12 @@
 		err = gpio_direction_output(H3XXX_EGPIO_CARD_RESET, 0);
 		if (err)
 			goto err06;
-		err = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-		if (err)
-			goto err06;
 		break;
 	case 1:
-		err = gpio_request(H3XXX_GPIO_PCMCIA_IRQ1, "PCMCIA IRQ1");
-		if (err)
-			goto err10;
-		err = gpio_direction_input(H3XXX_GPIO_PCMCIA_IRQ1);
-		if (err)
-			goto err11;
-		skt->socket.pci_irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_IRQ1);
-
-		err = gpio_request(H3XXX_GPIO_PCMCIA_CD1, "PCMCIA CD1");
-		if (err)
-			goto err11;
-		err = gpio_direction_input(H3XXX_GPIO_PCMCIA_CD1);
-		if (err)
-			goto err12;
-		irqs[1].irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_CD1);
-
-		err = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-		if (err)
-			goto err12;
+		skt->stat[SOC_STAT_CD].gpio = H3XXX_GPIO_PCMCIA_CD1;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA CD1";
+		skt->stat[SOC_STAT_RDY].gpio = H3XXX_GPIO_PCMCIA_IRQ1;
+		skt->stat[SOC_STAT_RDY].name = "PCMCIA IRQ1";
 		break;
 	}
 	return 0;
@@ -102,19 +68,12 @@
 err05:	gpio_free(H3XXX_EGPIO_OPT_RESET);
 err04:	gpio_free(H3XXX_EGPIO_OPT_ON);
 err03:	gpio_free(H3XXX_EGPIO_OPT_NVRAM_ON);
-err02:	gpio_free(H3XXX_GPIO_PCMCIA_CD0);
 err01:	gpio_free(H3XXX_GPIO_PCMCIA_IRQ0);
-err00:	return err;
-
-err12:	gpio_free(H3XXX_GPIO_PCMCIA_CD0);
-err11:	gpio_free(H3XXX_GPIO_PCMCIA_IRQ0);
-err10:	return err;
+	return err;
 }
 
 static void h3600_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 {
-	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
-  
 	switch (skt->nr) {
 	case 0:
 		/* Disable CF bus: */
@@ -126,12 +85,8 @@
 		gpio_free(H3XXX_EGPIO_OPT_RESET);
 		gpio_free(H3XXX_EGPIO_OPT_ON);
 		gpio_free(H3XXX_EGPIO_OPT_NVRAM_ON);
-		gpio_free(H3XXX_GPIO_PCMCIA_CD0);
-		gpio_free(H3XXX_GPIO_PCMCIA_IRQ0);
 		break;
 	case 1:
-		gpio_free(H3XXX_GPIO_PCMCIA_CD1);
-		gpio_free(H3XXX_GPIO_PCMCIA_IRQ1);
 		break;
 	}
 }
@@ -139,27 +94,10 @@
 static void
 h3600_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
 {
-	switch (skt->nr) {
-	case 0:
-		state->detect = !gpio_get_value(H3XXX_GPIO_PCMCIA_CD0);
-		state->ready = !!gpio_get_value(H3XXX_GPIO_PCMCIA_IRQ0);
-		state->bvd1 = 0;
-		state->bvd2 = 0;
-		state->wrprot = 0; /* Not available on H3600. */
-		state->vs_3v = 0;
-		state->vs_Xv = 0;
-		break;
-
-	case 1:
-		state->detect = !gpio_get_value(H3XXX_GPIO_PCMCIA_CD1);
-		state->ready = !!gpio_get_value(H3XXX_GPIO_PCMCIA_IRQ1);
-		state->bvd1 = 0;
-		state->bvd2 = 0;
-		state->wrprot = 0; /* Not available on H3600. */
-		state->vs_3v = 0;
-		state->vs_Xv = 0;
-		break;
-	}
+	state->bvd1 = 0;
+	state->bvd2 = 0;
+	state->vs_3v = 0;
+	state->vs_Xv = 0;
 }
 
 static int
@@ -186,14 +124,10 @@
 	gpio_set_value(H3XXX_EGPIO_OPT_RESET, 0);
 
 	msleep(10);
-
-	soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 static void h3600_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 {
-	soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-
 	/*
 	 * FIXME:  This doesn't fit well.  We don't have the mechanism in
 	 * the generic PCMCIA layer to deal with the idea of two sockets
diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c
deleted file mode 100644
index 6bcabee..0000000
--- a/drivers/pcmcia/sa1100_jornada720.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * drivers/pcmcia/sa1100_jornada720.c
- *
- * Jornada720 PCMCIA specific routines
- *
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/hardware/sa1111.h>
-#include <asm/mach-types.h>
-
-#include "sa1111_generic.h"
-
-/* Does SOCKET1_3V actually do anything? */
-#define SOCKET0_POWER	GPIO_GPIO0
-#define SOCKET0_3V	GPIO_GPIO2
-#define SOCKET1_POWER	(GPIO_GPIO1 | GPIO_GPIO3)
-#define SOCKET1_3V	GPIO_GPIO3
-
-static int
-jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
-{
-	struct sa1111_pcmcia_socket *s = to_skt(skt);
-	unsigned int pa_dwr_mask, pa_dwr_set;
-	int ret;
-
-	printk(KERN_INFO "%s(): config socket %d vcc %d vpp %d\n", __func__,
-		skt->nr, state->Vcc, state->Vpp);
-
-	switch (skt->nr) {
-	case 0:
-		pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
-
-		switch (state->Vcc) {
-		default:
-		case  0:
-			pa_dwr_set = 0;
-			break;
-		case 33:
-			pa_dwr_set = SOCKET0_POWER | SOCKET0_3V;
-			break;
-		case 50:
-			pa_dwr_set = SOCKET0_POWER;
-			break;
-		}
-		break;
-
-	case 1:
-		pa_dwr_mask = SOCKET1_POWER;
-
-		switch (state->Vcc) {
-		default:
-		case 0:
-			pa_dwr_set = 0;
-			break;
-		case 33:
-			pa_dwr_set = SOCKET1_POWER;
-			break;
-		case 50:
-			pa_dwr_set = SOCKET1_POWER;
-			break;
-		}
-		break;
-
-	default:
-		return -1;
-	}
-
-	if (state->Vpp != state->Vcc && state->Vpp != 0) {
-		printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
-			__func__, state->Vpp);
-		return -EPERM;
-	}
-
-	ret = sa1111_pcmcia_configure_socket(skt, state);
-	if (ret == 0) {
-		unsigned long flags;
-
-		local_irq_save(flags);
-		sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
-		local_irq_restore(flags);
-	}
-
-	return ret;
-}
-
-static struct pcmcia_low_level jornada720_pcmcia_ops = {
-	.owner			= THIS_MODULE,
-	.configure_socket	= jornada720_pcmcia_configure_socket,
-	.socket_init		= sa1111_pcmcia_socket_init,
-	.first			= 0,
-	.nr			= 2,
-};
-
-int __devinit pcmcia_jornada720_init(struct device *dev)
-{
-	int ret = -ENODEV;
-
-	if (machine_is_jornada720()) {
-		unsigned int pin = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
-
-		GRER |= 0x00000002;
-
-		/* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */
-		sa1111_set_io_dir(dev, pin, 0, 0);
-		sa1111_set_io(dev, pin, 0);
-		sa1111_set_sleep_io(dev, pin, 0);
-
-		sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops);
-		ret = sa1111_pcmcia_add(dev, &jornada720_pcmcia_ops,
-				sa11xx_drv_pcmcia_add_one);
-	}
-
-	return ret;
-}
diff --git a/drivers/pcmcia/sa1100_nanoengine.c b/drivers/pcmcia/sa1100_nanoengine.c
index 93b9c9b..35c30ff 100644
--- a/drivers/pcmcia/sa1100_nanoengine.c
+++ b/drivers/pcmcia/sa1100_nanoengine.c
@@ -19,6 +19,7 @@
  */
 #include <linux/device.h>
 #include <linux/errno.h>
+#include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/init.h>
@@ -34,43 +35,23 @@
 
 #include "sa1100_generic.h"
 
-static struct pcmcia_irqs irqs_skt0[] = {
-	/* socket, IRQ, name */
-	{ 0, NANOENGINE_IRQ_GPIO_PC_CD0, "PC CD0" },
-};
-
-static struct pcmcia_irqs irqs_skt1[] = {
-	/* socket, IRQ, name */
-	{ 1, NANOENGINE_IRQ_GPIO_PC_CD1, "PC CD1" },
-};
-
 struct nanoengine_pins {
-	unsigned input_pins;
 	unsigned output_pins;
 	unsigned clear_outputs;
-	unsigned transition_pins;
-	unsigned pci_irq;
-	struct pcmcia_irqs *pcmcia_irqs;
-	unsigned pcmcia_irqs_size;
+	int gpio_rst;
+	int gpio_cd;
+	int gpio_rdy;
 };
 
 static struct nanoengine_pins nano_skts[] = {
 	{
-		.input_pins		= GPIO_PC_READY0 | GPIO_PC_CD0,
-		.output_pins		= GPIO_PC_RESET0,
-		.clear_outputs		= GPIO_PC_RESET0,
-		.transition_pins	= NANOENGINE_IRQ_GPIO_PC_CD0,
-		.pci_irq		= NANOENGINE_IRQ_GPIO_PC_READY0,
-		.pcmcia_irqs		= irqs_skt0,
-		.pcmcia_irqs_size	= ARRAY_SIZE(irqs_skt0)
+		.gpio_rst		= GPIO_PC_RESET0,
+		.gpio_cd		= GPIO_PC_CD0,
+		.gpio_rdy		= GPIO_PC_READY0,
 	}, {
-		.input_pins		= GPIO_PC_READY1 | GPIO_PC_CD1,
-		.output_pins		= GPIO_PC_RESET1,
-		.clear_outputs		= GPIO_PC_RESET1,
-		.transition_pins	= NANOENGINE_IRQ_GPIO_PC_CD1,
-		.pci_irq		= NANOENGINE_IRQ_GPIO_PC_READY1,
-		.pcmcia_irqs		= irqs_skt1,
-		.pcmcia_irqs_size	= ARRAY_SIZE(irqs_skt1)
+		.gpio_rst		= GPIO_PC_RESET1,
+		.gpio_cd		= GPIO_PC_CD1,
+		.gpio_rdy		= GPIO_PC_READY1,
 	}
 };
 
@@ -79,58 +60,38 @@
 static int nanoengine_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
 	unsigned i = skt->nr;
+	int ret;
 
 	if (i >= num_nano_pcmcia_sockets)
 		return -ENXIO;
 
-	GPDR &= ~nano_skts[i].input_pins;
-	GPDR |= nano_skts[i].output_pins;
-	GPCR = nano_skts[i].clear_outputs;
-	irq_set_irq_type(nano_skts[i].transition_pins, IRQ_TYPE_EDGE_BOTH);
-	skt->socket.pci_irq = nano_skts[i].pci_irq;
+	ret = gpio_request_one(nano_skts[i].gpio_rst, GPIOF_OUT_INIT_LOW,
+		i ? "PC RST1" : "PC RST0");
+	if (ret)
+		return ret;
 
-	return soc_pcmcia_request_irqs(skt,
-		nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
+	skt->stat[SOC_STAT_CD].gpio = nano_skts[i].gpio_cd;
+	skt->stat[SOC_STAT_CD].name = i ? "PC CD1" : "PC CD0";
+	skt->stat[SOC_STAT_RDY].gpio = nano_skts[i].gpio_rdy;
+	skt->stat[SOC_STAT_RDY].name = i ? "PC RDY1" : "PC RDY0";
+
+	return 0;
 }
 
-/*
- * Release all resources.
- */
 static void nanoengine_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 {
-	unsigned i = skt->nr;
-
-	if (i >= num_nano_pcmcia_sockets)
-		return;
-
-	soc_pcmcia_free_irqs(skt,
-		nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
+	gpio_free(nano_skts[skt->nr].gpio_rst);
 }
 
 static int nanoengine_pcmcia_configure_socket(
 	struct soc_pcmcia_socket *skt, const socket_state_t *state)
 {
-	unsigned reset;
 	unsigned i = skt->nr;
 
 	if (i >= num_nano_pcmcia_sockets)
 		return -ENXIO;
 
-	switch (i) {
-	case 0:
-		reset = GPIO_PC_RESET0;
-		break;
-	case 1:
-		reset = GPIO_PC_RESET1;
-		break;
-	default:
-		return -ENXIO;
-	}
-
-	if (state->flags & SS_RESET)
-		GPSR = reset;
-	else
-		GPCR = reset;
+	gpio_set_value(nano_skts[skt->nr].gpio_rst, !!(state->flags & SS_RESET));
 
 	return 0;
 }
@@ -138,62 +99,17 @@
 static void nanoengine_pcmcia_socket_state(
 	struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
 {
-	unsigned long levels = GPLR;
 	unsigned i = skt->nr;
 
 	if (i >= num_nano_pcmcia_sockets)
 		return;
 
-	memset(state, 0, sizeof(struct pcmcia_state));
-	switch (i) {
-	case 0:
-		state->ready = (levels & GPIO_PC_READY0) ? 1 : 0;
-		state->detect = !(levels & GPIO_PC_CD0) ? 1 : 0;
-		break;
-	case 1:
-		state->ready = (levels & GPIO_PC_READY1) ? 1 : 0;
-		state->detect = !(levels & GPIO_PC_CD1) ? 1 : 0;
-		break;
-	default:
-		return;
-	}
 	state->bvd1 = 1;
 	state->bvd2 = 1;
-	state->wrprot = 0; /* Not available */
 	state->vs_3v = 1; /* Can only apply 3.3V */
 	state->vs_Xv = 0;
 }
 
-/*
- * Enable card status IRQs on (re-)initialisation.  This can
- * be called at initialisation, power management event, or
- * pcmcia event.
- */
-static void nanoengine_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-	unsigned i = skt->nr;
-
-	if (i >= num_nano_pcmcia_sockets)
-		return;
-
-	soc_pcmcia_enable_irqs(skt,
-		nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
-}
-
-/*
- * Disable card status IRQs on suspend.
- */
-static void nanoengine_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-	unsigned i = skt->nr;
-
-	if (i >= num_nano_pcmcia_sockets)
-		return;
-
-	soc_pcmcia_disable_irqs(skt,
-		nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
-}
-
 static struct pcmcia_low_level nanoengine_pcmcia_ops = {
 	.owner			= THIS_MODULE,
 
@@ -202,8 +118,6 @@
 
 	.configure_socket	= nanoengine_pcmcia_configure_socket,
 	.socket_state		= nanoengine_pcmcia_socket_state,
-	.socket_init		= nanoengine_pcmcia_socket_init,
-	.socket_suspend		= nanoengine_pcmcia_socket_suspend,
 };
 
 int pcmcia_nanoengine_init(struct device *dev)
diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c
deleted file mode 100644
index c95639b..0000000
--- a/drivers/pcmcia/sa1100_neponset.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * linux/drivers/pcmcia/sa1100_neponset.c
- *
- * Neponset PCMCIA specific routines
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <mach/neponset.h>
-#include <asm/hardware/sa1111.h>
-
-#include "sa1111_generic.h"
-
-/*
- * Neponset uses the Maxim MAX1600, with the following connections:
- *
- *   MAX1600      Neponset
- *
- *    A0VCC        SA-1111 GPIO A<1>
- *    A1VCC        SA-1111 GPIO A<0>
- *    A0VPP        CPLD NCR A0VPP
- *    A1VPP        CPLD NCR A1VPP
- *    B0VCC        SA-1111 GPIO A<2>
- *    B1VCC        SA-1111 GPIO A<3>
- *    B0VPP        ground (slot B is CF)
- *    B1VPP        ground (slot B is CF)
- *
- *     VX          VCC (5V)
- *     VY          VCC3_3 (3.3V)
- *     12INA       12V
- *     12INB       ground (slot B is CF)
- *
- * The MAX1600 CODE pin is tied to ground, placing the device in 
- * "Standard Intel code" mode. Refer to the Maxim data sheet for
- * the corresponding truth table.
- */
-
-static int
-neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
-{
-	struct sa1111_pcmcia_socket *s = to_skt(skt);
-	unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set;
-	int ret;
-
-	switch (skt->nr) {
-	case 0:
-		pa_dwr_mask = GPIO_A0 | GPIO_A1;
-		ncr_mask = NCR_A0VPP | NCR_A1VPP;
-
-		if (state->Vpp == 0)
-			ncr_set = 0;
-		else if (state->Vpp == 120)
-			ncr_set = NCR_A1VPP;
-		else if (state->Vpp == state->Vcc)
-			ncr_set = NCR_A0VPP;
-		else {
-			printk(KERN_ERR "%s(): unrecognized VPP %u\n",
-			       __func__, state->Vpp);
-			return -1;
-		}
-		break;
-
-	case 1:
-		pa_dwr_mask = GPIO_A2 | GPIO_A3;
-		ncr_mask = 0;
-		ncr_set = 0;
-
-		if (state->Vpp != state->Vcc && state->Vpp != 0) {
-			printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
-			       __func__, state->Vpp);
-			return -1;
-		}
-		break;
-
-	default:
-		return -1;
-	}
-
-	/*
-	 * pa_dwr_set is the mask for selecting Vcc on both sockets.
-	 * pa_dwr_mask selects which bits (and therefore socket) we change.
-	 */
-	switch (state->Vcc) {
-	default:
-	case 0:  pa_dwr_set = 0;		break;
-	case 33: pa_dwr_set = GPIO_A1|GPIO_A2;	break;
-	case 50: pa_dwr_set = GPIO_A0|GPIO_A3;	break;
-	}
-
-	ret = sa1111_pcmcia_configure_socket(skt, state);
-	if (ret == 0) {
-		unsigned long flags;
-
-		local_irq_save(flags);
-		NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set;
-
-		local_irq_restore(flags);
-		sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
-	}
-
-	return 0;
-}
-
-static void neponset_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-	if (skt->nr == 0)
-		NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
-
-	sa1111_pcmcia_socket_init(skt);
-}
-
-static struct pcmcia_low_level neponset_pcmcia_ops = {
-	.owner			= THIS_MODULE,
-	.configure_socket	= neponset_pcmcia_configure_socket,
-	.socket_init		= neponset_pcmcia_socket_init,
-	.first			= 0,
-	.nr			= 2,
-};
-
-int pcmcia_neponset_init(struct sa1111_dev *sadev)
-{
-	int ret = -ENODEV;
-
-	if (machine_is_assabet()) {
-		/*
-		 * Set GPIO_A<3:0> to be outputs for the MAX1600,
-		 * and switch to standby mode.
-		 */
-		sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
-		sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
-		sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
-		sa11xx_drv_pcmcia_ops(&neponset_pcmcia_ops);
-		ret = sa1111_pcmcia_add(sadev, &neponset_pcmcia_ops,
-				sa11xx_drv_pcmcia_add_one);
-	}
-
-	return ret;
-}
diff --git a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c
index 7ff1b43..decb347 100644
--- a/drivers/pcmcia/sa1100_shannon.c
+++ b/drivers/pcmcia/sa1100_shannon.c
@@ -15,40 +15,35 @@
 #include <asm/irq.h>
 #include "sa1100_generic.h"
 
-static struct pcmcia_irqs irqs[] = {
-	{ 0, SHANNON_IRQ_GPIO_EJECT_0, "PCMCIA_CD_0" },
-	{ 1, SHANNON_IRQ_GPIO_EJECT_1, "PCMCIA_CD_1" },
-};
-
 static int shannon_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
 	/* All those are inputs */
-	GPDR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | 
-		  SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1);
-	GAFR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | 
-		  SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1);
+	GAFR &= ~(GPIO_GPIO(SHANNON_GPIO_EJECT_0) |
+		  GPIO_GPIO(SHANNON_GPIO_EJECT_1) |
+		  GPIO_GPIO(SHANNON_GPIO_RDY_0) |
+		  GPIO_GPIO(SHANNON_GPIO_RDY_1));
 
-	skt->socket.pci_irq = skt->nr ? SHANNON_IRQ_GPIO_RDY_1 : SHANNON_IRQ_GPIO_RDY_0;
+	if (skt->nr == 0) {
+		skt->stat[SOC_STAT_CD].gpio = SHANNON_GPIO_EJECT_0;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA_CD_0";
+		skt->stat[SOC_STAT_RDY].gpio = SHANNON_GPIO_RDY_0;
+		skt->stat[SOC_STAT_RDY].name = "PCMCIA_RDY_0";
+	} else {
+		skt->stat[SOC_STAT_CD].gpio = SHANNON_GPIO_EJECT_1;
+		skt->stat[SOC_STAT_CD].name = "PCMCIA_CD_1";
+		skt->stat[SOC_STAT_RDY].gpio = SHANNON_GPIO_RDY_1;
+		skt->stat[SOC_STAT_RDY].name = "PCMCIA_RDY_1";
+	}
 
-	return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-static void shannon_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+	return 0;
 }
 
 static void
 shannon_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
 			    struct pcmcia_state *state)
 {
-	unsigned long levels = GPLR;
-
 	switch (skt->nr) {
 	case 0:
-		state->detect = (levels & SHANNON_GPIO_EJECT_0) ? 0 : 1;
-		state->ready  = (levels & SHANNON_GPIO_RDY_0) ? 1 : 0;
-		state->wrprot = 0; /* Not available on Shannon. */
 		state->bvd1   = 1; 
 		state->bvd2   = 1; 
 		state->vs_3v  = 1; /* FIXME Can only apply 3.3V on Shannon. */
@@ -56,9 +51,6 @@
 		break;
 
 	case 1:
-		state->detect = (levels & SHANNON_GPIO_EJECT_1) ? 0 : 1;
-		state->ready  = (levels & SHANNON_GPIO_RDY_1) ? 1 : 0;
-		state->wrprot = 0; /* Not available on Shannon. */
 		state->bvd1   = 1; 
 		state->bvd2   = 1; 
 		state->vs_3v  = 1; /* FIXME Can only apply 3.3V on Shannon. */
@@ -92,25 +84,11 @@
 	return 0;
 }
 
-static void shannon_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-static void shannon_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
 static struct pcmcia_low_level shannon_pcmcia_ops = {
 	.owner			= THIS_MODULE,
 	.hw_init		= shannon_pcmcia_hw_init,
-	.hw_shutdown		= shannon_pcmcia_hw_shutdown,
 	.socket_state		= shannon_pcmcia_socket_state,
 	.configure_socket	= shannon_pcmcia_configure_socket,
-
-	.socket_init		= shannon_pcmcia_socket_init,
-	.socket_suspend		= shannon_pcmcia_socket_suspend,
 };
 
 int __devinit pcmcia_shannon_init(struct device *dev)
diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c
index 0fac965..8647b17 100644
--- a/drivers/pcmcia/sa1100_simpad.c
+++ b/drivers/pcmcia/sa1100_simpad.c
@@ -15,24 +15,21 @@
 #include <mach/simpad.h>
 #include "sa1100_generic.h"
  
-static struct pcmcia_irqs irqs[] = {
-	{ 1, IRQ_GPIO_CF_CD, "CF_CD" },
-};
-
 static int simpad_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
 
 	simpad_clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
 
-	skt->socket.pci_irq = IRQ_GPIO_CF_IRQ;
+	skt->stat[SOC_STAT_CD].gpio = GPIO_CF_CD;
+	skt->stat[SOC_STAT_CD].name = "CF_CD";
+	skt->stat[SOC_STAT_RDY].gpio = GPIO_CF_IRQ;
+	skt->stat[SOC_STAT_RDY].name = "CF_RDY";
 
-	return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+	return 0;
 }
 
 static void simpad_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 {
-	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
-
 	/* Disable CF bus: */
 	/*simpad_set_cs3_bit(PCMCIA_BUFF_DIS);*/
 	simpad_clear_cs3_bit(PCMCIA_RESET);
@@ -42,14 +39,13 @@
 simpad_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
 			   struct pcmcia_state *state)
 {
-	unsigned long levels = GPLR;
 	long cs3reg = simpad_get_cs3_ro();
 
-	state->detect=((levels & GPIO_CF_CD)==0)?1:0;
-	state->ready=(levels & GPIO_CF_IRQ)?1:0;
+	/* the detect signal is inverted - fix that up here */
+	state->detect = !state->detect;
+
 	state->bvd1 = 1; /* Might be cs3reg & PCMCIA_BVD1 */
 	state->bvd2 = 1; /* Might be cs3reg & PCMCIA_BVD2 */
-	state->wrprot=0; /* Not available on Simpad. */
 
 	if ((cs3reg & (PCMCIA_VS1|PCMCIA_VS2)) ==
 			(PCMCIA_VS1|PCMCIA_VS2)) {
@@ -99,14 +95,8 @@
 	return 0;
 }
 
-static void simpad_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
 static void simpad_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 {
-	soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 	simpad_set_cs3_bit(PCMCIA_RESET);
 }
 
@@ -116,7 +106,6 @@
 	.hw_shutdown		= simpad_pcmcia_hw_shutdown,
 	.socket_state		= simpad_pcmcia_socket_state,
 	.configure_socket	= simpad_pcmcia_configure_socket,
-	.socket_init		= simpad_pcmcia_socket_init,
 	.socket_suspend		= simpad_pcmcia_socket_suspend,
 };
 
diff --git a/drivers/pcmcia/sa1111_badge4.c b/drivers/pcmcia/sa1111_badge4.c
new file mode 100644
index 0000000..4d206f4
--- /dev/null
+++ b/drivers/pcmcia/sa1111_badge4.c
@@ -0,0 +1,166 @@
+/*
+ * linux/drivers/pcmcia/sa1100_badge4.c
+ *
+ * BadgePAD 4 PCMCIA specific routines
+ *
+ *   Christopher Hoover <ch@hpl.hp.com>
+ *
+ * Copyright (C) 2002 Hewlett-Packard Company
+ *
+ * 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/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <mach/badge4.h>
+#include <asm/hardware/sa1111.h>
+
+#include "sa1111_generic.h"
+
+/*
+ * BadgePAD 4 Details
+ *
+ * PCM Vcc:
+ *
+ *  PCM Vcc on BadgePAD 4 can be jumpered for 3v3 (short pins 1 and 3
+ *  on JP6) or 5v0 (short pins 3 and 5 on JP6).
+ *
+ * PCM Vpp:
+ *
+ *  PCM Vpp on BadgePAD 4 can be jumpered for 12v0 (short pins 4 and 6
+ *  on JP6) or tied to PCM Vcc (short pins 2 and 4 on JP6).  N.B.,
+ *  12v0 operation requires that the power supply actually supply 12v0
+ *  via pin 7 of JP7.
+ *
+ * CF Vcc:
+ *
+ *  CF Vcc on BadgePAD 4 can be jumpered either for 3v3 (short pins 1
+ *  and 2 on JP10) or 5v0 (short pins 2 and 3 on JP10).
+ *
+ * Unfortunately there's no way programmatically to determine how a
+ * given board is jumpered.  This code assumes a default jumpering
+ * as described below.
+ *
+ * If the defaults aren't correct, you may override them with a pcmv
+ * setup argument: pcmv=<pcm vcc>,<pcm vpp>,<cf vcc>.  The units are
+ * tenths of volts; e.g. pcmv=33,120,50 indicates 3v3 PCM Vcc, 12v0
+ * PCM Vpp, and 5v0 CF Vcc.
+ *
+ */
+
+static int badge4_pcmvcc = 50;  /* pins 3 and 5 jumpered on JP6 */
+static int badge4_pcmvpp = 50;  /* pins 2 and 4 jumpered on JP6 */
+static int badge4_cfvcc = 33;   /* pins 1 and 2 jumpered on JP10 */
+
+static void complain_about_jumpering(const char *whom,
+				     const char *supply,
+				     int given, int wanted)
+{
+	printk(KERN_ERR
+	 "%s: %s %d.%dV wanted but board is jumpered for %s %d.%dV operation"
+	 "; re-jumper the board and/or use pcmv=xx,xx,xx\n",
+	       whom, supply,
+	       wanted / 10, wanted % 10,
+	       supply,
+	       given / 10, given % 10);
+}
+
+static int
+badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
+{
+	int ret;
+
+	switch (skt->nr) {
+	case 0:
+		if ((state->Vcc != 0) &&
+		    (state->Vcc != badge4_pcmvcc)) {
+			complain_about_jumpering(__func__, "pcmvcc",
+						 badge4_pcmvcc, state->Vcc);
+			// Apply power regardless of the jumpering.
+			// return -1;
+		}
+		if ((state->Vpp != 0) &&
+		    (state->Vpp != badge4_pcmvpp)) {
+			complain_about_jumpering(__func__, "pcmvpp",
+						 badge4_pcmvpp, state->Vpp);
+			return -1;
+		}
+		break;
+
+	case 1:
+		if ((state->Vcc != 0) &&
+		    (state->Vcc != badge4_cfvcc)) {
+			complain_about_jumpering(__func__, "cfvcc",
+						 badge4_cfvcc, state->Vcc);
+			return -1;
+		}
+		break;
+
+	default:
+		return -1;
+	}
+
+	ret = sa1111_pcmcia_configure_socket(skt, state);
+	if (ret == 0) {
+		unsigned long flags;
+		int need5V;
+
+		local_irq_save(flags);
+
+		need5V = ((state->Vcc == 50) || (state->Vpp == 50));
+
+		badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(skt->nr), need5V);
+
+		local_irq_restore(flags);
+	}
+
+	return ret;
+}
+
+static struct pcmcia_low_level badge4_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+	.configure_socket	= badge4_pcmcia_configure_socket,
+	.first			= 0,
+	.nr			= 2,
+};
+
+int pcmcia_badge4_init(struct device *dev)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_badge4()) {
+		printk(KERN_INFO
+		       "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
+		       __func__,
+		       badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
+
+		sa11xx_drv_pcmcia_ops(&badge4_pcmcia_ops);
+		ret = sa1111_pcmcia_add(dev, &badge4_pcmcia_ops,
+				sa11xx_drv_pcmcia_add_one);
+	}
+
+	return ret;
+}
+
+static int __init pcmv_setup(char *s)
+{
+	int v[4];
+
+	s = get_options(s, ARRAY_SIZE(v), v);
+
+	if (v[0] >= 1) badge4_pcmvcc = v[1];
+	if (v[0] >= 2) badge4_pcmvpp = v[2];
+	if (v[0] >= 3) badge4_cfvcc = v[3];
+
+	return 1;
+}
+
+__setup("pcmv=", pcmv_setup);
diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c
index 27f2fe3..70f728c 100644
--- a/drivers/pcmcia/sa1111_generic.c
+++ b/drivers/pcmcia/sa1111_generic.c
@@ -22,6 +22,40 @@
 
 #include "sa1111_generic.h"
 
+/*
+ * These are offsets from the above base.
+ */
+#define PCCR	0x0000
+#define PCSSR	0x0004
+#define PCSR	0x0008
+
+#define PCSR_S0_READY	(1<<0)
+#define PCSR_S1_READY	(1<<1)
+#define PCSR_S0_DETECT	(1<<2)
+#define PCSR_S1_DETECT	(1<<3)
+#define PCSR_S0_VS1	(1<<4)
+#define PCSR_S0_VS2	(1<<5)
+#define PCSR_S1_VS1	(1<<6)
+#define PCSR_S1_VS2	(1<<7)
+#define PCSR_S0_WP	(1<<8)
+#define PCSR_S1_WP	(1<<9)
+#define PCSR_S0_BVD1	(1<<10)
+#define PCSR_S0_BVD2	(1<<11)
+#define PCSR_S1_BVD1	(1<<12)
+#define PCSR_S1_BVD2	(1<<13)
+
+#define PCCR_S0_RST	(1<<0)
+#define PCCR_S1_RST	(1<<1)
+#define PCCR_S0_FLT	(1<<2)
+#define PCCR_S1_FLT	(1<<3)
+#define PCCR_S0_PWAITEN	(1<<4)
+#define PCCR_S1_PWAITEN	(1<<5)
+#define PCCR_S0_PSE	(1<<6)
+#define PCCR_S1_PSE	(1<<7)
+
+#define PCSSR_S0_SLEEP	(1<<0)
+#define PCSSR_S1_SLEEP	(1<<1)
+
 #define IDX_IRQ_S0_READY_NINT	(0)
 #define IDX_IRQ_S0_CD_VALID	(1)
 #define IDX_IRQ_S0_BVD1_STSCHG	(2)
@@ -29,27 +63,10 @@
 #define IDX_IRQ_S1_CD_VALID	(4)
 #define IDX_IRQ_S1_BVD1_STSCHG	(5)
 
-static struct pcmcia_irqs irqs[] = {
-	{ 0, NO_IRQ, "SA1111 PCMCIA card detect" },
-	{ 0, NO_IRQ, "SA1111 PCMCIA BVD1"        },
-	{ 1, NO_IRQ, "SA1111 CF card detect"     },
-	{ 1, NO_IRQ, "SA1111 CF BVD1"            },
-};
-
-static int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
-{
-	return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-static void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
 void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
 {
 	struct sa1111_pcmcia_socket *s = to_skt(skt);
-	unsigned long status = sa1111_readl(s->dev->mapbase + SA1111_PCSR);
+	unsigned long status = sa1111_readl(s->dev->mapbase + PCSR);
 
 	switch (skt->nr) {
 	case 0:
@@ -105,35 +122,22 @@
 		pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT;
 
 	local_irq_save(flags);
-	val = sa1111_readl(s->dev->mapbase + SA1111_PCCR);
+	val = sa1111_readl(s->dev->mapbase + PCCR);
 	val &= ~pccr_skt_mask;
 	val |= pccr_set_mask & pccr_skt_mask;
-	sa1111_writel(val, s->dev->mapbase + SA1111_PCCR);
+	sa1111_writel(val, s->dev->mapbase + PCCR);
 	local_irq_restore(flags);
 
 	return 0;
 }
 
-void sa1111_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-static void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-	soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
 int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops,
 	int (*add)(struct soc_pcmcia_socket *))
 {
 	struct sa1111_pcmcia_socket *s;
 	int i, ret = 0;
 
-	ops->hw_init = sa1111_pcmcia_hw_init;
-	ops->hw_shutdown = sa1111_pcmcia_hw_shutdown;
 	ops->socket_state = sa1111_pcmcia_socket_state;
-	ops->socket_suspend = sa1111_pcmcia_socket_suspend;
 
 	for (i = 0; i < ops->nr; i++) {
 		s = kzalloc(sizeof(*s), GFP_KERNEL);
@@ -141,13 +145,21 @@
 			return -ENOMEM;
 
 		s->soc.nr = ops->first + i;
-		s->soc.ops = ops;
-		s->soc.socket.owner = ops->owner;
-		s->soc.socket.dev.parent = &dev->dev;
-		s->soc.socket.pci_irq = s->soc.nr ?
-				dev->irq[IDX_IRQ_S0_READY_NINT] :
-				dev->irq[IDX_IRQ_S1_READY_NINT];
+		soc_pcmcia_init_one(&s->soc, ops, &dev->dev);
 		s->dev = dev;
+		if (s->soc.nr) {
+			s->soc.socket.pci_irq = dev->irq[IDX_IRQ_S1_READY_NINT];
+			s->soc.stat[SOC_STAT_CD].irq = dev->irq[IDX_IRQ_S1_CD_VALID];
+			s->soc.stat[SOC_STAT_CD].name = "SA1111 CF card detect";
+			s->soc.stat[SOC_STAT_BVD1].irq = dev->irq[IDX_IRQ_S1_BVD1_STSCHG];
+			s->soc.stat[SOC_STAT_BVD1].name = "SA1111 CF BVD1";
+		} else {
+			s->soc.socket.pci_irq = dev->irq[IDX_IRQ_S0_READY_NINT];
+			s->soc.stat[SOC_STAT_CD].irq = dev->irq[IDX_IRQ_S0_CD_VALID];
+			s->soc.stat[SOC_STAT_CD].name = "SA1111 PCMCIA card detect";
+			s->soc.stat[SOC_STAT_BVD1].irq = dev->irq[IDX_IRQ_S0_BVD1_STSCHG];
+			s->soc.stat[SOC_STAT_BVD1].name = "SA1111 PCMCIA BVD1";
+		}
 
 		ret = add(&s->soc);
 		if (ret == 0) {
@@ -163,26 +175,26 @@
 static int pcmcia_probe(struct sa1111_dev *dev)
 {
 	void __iomem *base;
+	int ret;
+
+	ret = sa1111_enable_device(dev);
+	if (ret)
+		return ret;
 
 	dev_set_drvdata(&dev->dev, NULL);
 
-	if (!request_mem_region(dev->res.start, 512,
-				SA1111_DRIVER_NAME(dev)))
+	if (!request_mem_region(dev->res.start, 512, SA1111_DRIVER_NAME(dev))) {
+		sa1111_disable_device(dev);
 		return -EBUSY;
+	}
 
 	base = dev->mapbase;
 
-	/* Initialize PCMCIA IRQs */
-	irqs[0].irq = dev->irq[IDX_IRQ_S0_CD_VALID];
-	irqs[1].irq = dev->irq[IDX_IRQ_S0_BVD1_STSCHG];
-	irqs[2].irq = dev->irq[IDX_IRQ_S1_CD_VALID];
-	irqs[3].irq = dev->irq[IDX_IRQ_S1_BVD1_STSCHG];
-
 	/*
 	 * Initialise the suspend state.
 	 */
-	sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + SA1111_PCSSR);
-	sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + SA1111_PCCR);
+	sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + PCSSR);
+	sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + PCCR);
 
 #ifdef CONFIG_SA1100_BADGE4
 	pcmcia_badge4_init(&dev->dev);
@@ -212,6 +224,7 @@
 	}
 
 	release_mem_region(dev->res.start, 512);
+	sa1111_disable_device(dev);
 	return 0;
 }
 
diff --git a/drivers/pcmcia/sa1111_generic.h b/drivers/pcmcia/sa1111_generic.h
index 02dc857..f6376e3 100644
--- a/drivers/pcmcia/sa1111_generic.h
+++ b/drivers/pcmcia/sa1111_generic.h
@@ -17,7 +17,6 @@
 
 extern void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *, struct pcmcia_state *);
 extern int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *, const socket_state_t *);
-extern void sa1111_pcmcia_socket_init(struct soc_pcmcia_socket *);
 
 extern int pcmcia_badge4_init(struct device *);
 extern int pcmcia_jornada720_init(struct device *);
diff --git a/drivers/pcmcia/sa1111_jornada720.c b/drivers/pcmcia/sa1111_jornada720.c
new file mode 100644
index 0000000..69428d1
--- /dev/null
+++ b/drivers/pcmcia/sa1111_jornada720.c
@@ -0,0 +1,114 @@
+/*
+ * drivers/pcmcia/sa1100_jornada720.c
+ *
+ * Jornada720 PCMCIA specific routines
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/sa1111.h>
+#include <asm/mach-types.h>
+
+#include "sa1111_generic.h"
+
+/* Does SOCKET1_3V actually do anything? */
+#define SOCKET0_POWER	GPIO_GPIO0
+#define SOCKET0_3V	GPIO_GPIO2
+#define SOCKET1_POWER	(GPIO_GPIO1 | GPIO_GPIO3)
+#define SOCKET1_3V	GPIO_GPIO3
+
+static int
+jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
+{
+	struct sa1111_pcmcia_socket *s = to_skt(skt);
+	unsigned int pa_dwr_mask, pa_dwr_set;
+	int ret;
+
+	printk(KERN_INFO "%s(): config socket %d vcc %d vpp %d\n", __func__,
+		skt->nr, state->Vcc, state->Vpp);
+
+	switch (skt->nr) {
+	case 0:
+		pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
+
+		switch (state->Vcc) {
+		default:
+		case  0:
+			pa_dwr_set = 0;
+			break;
+		case 33:
+			pa_dwr_set = SOCKET0_POWER | SOCKET0_3V;
+			break;
+		case 50:
+			pa_dwr_set = SOCKET0_POWER;
+			break;
+		}
+		break;
+
+	case 1:
+		pa_dwr_mask = SOCKET1_POWER;
+
+		switch (state->Vcc) {
+		default:
+		case 0:
+			pa_dwr_set = 0;
+			break;
+		case 33:
+			pa_dwr_set = SOCKET1_POWER;
+			break;
+		case 50:
+			pa_dwr_set = SOCKET1_POWER;
+			break;
+		}
+		break;
+
+	default:
+		return -1;
+	}
+
+	if (state->Vpp != state->Vcc && state->Vpp != 0) {
+		printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
+			__func__, state->Vpp);
+		return -EPERM;
+	}
+
+	ret = sa1111_pcmcia_configure_socket(skt, state);
+	if (ret == 0)
+		sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
+
+	return ret;
+}
+
+static struct pcmcia_low_level jornada720_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+	.configure_socket	= jornada720_pcmcia_configure_socket,
+	.first			= 0,
+	.nr			= 2,
+};
+
+int __devinit pcmcia_jornada720_init(struct device *dev)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_jornada720()) {
+		unsigned int pin = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
+
+		GRER |= 0x00000002;
+
+		/* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */
+		sa1111_set_io_dir(dev, pin, 0, 0);
+		sa1111_set_io(dev, pin, 0);
+		sa1111_set_sleep_io(dev, pin, 0);
+
+		sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops);
+		ret = sa1111_pcmcia_add(dev, &jornada720_pcmcia_ops,
+				sa11xx_drv_pcmcia_add_one);
+	}
+
+	return ret;
+}
diff --git a/drivers/pcmcia/sa1111_lubbock.c b/drivers/pcmcia/sa1111_lubbock.c
new file mode 100644
index 0000000..c5caf57
--- /dev/null
+++ b/drivers/pcmcia/sa1111_lubbock.c
@@ -0,0 +1,236 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_lubbock.c
+ *
+ * Author:	George Davis
+ * Created:	Jan 10, 2002
+ * Copyright:	MontaVista Software 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.
+ *
+ * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c
+ *
+ * Lubbock PCMCIA specific routines.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/sa1111.h>
+#include <asm/mach-types.h>
+#include <mach/lubbock.h>
+
+#include "sa1111_generic.h"
+
+static int
+lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+				const socket_state_t *state)
+{
+	struct sa1111_pcmcia_socket *s = to_skt(skt);
+	unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set;
+	int ret = 0;
+
+	pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0;
+
+	/* Lubbock uses the Maxim MAX1602, with the following connections:
+	 *
+	 * Socket 0 (PCMCIA):
+	 *	MAX1602	Lubbock		Register
+	 *	Pin	Signal
+	 *	-----	-------		----------------------
+	 *	A0VPP	S0_PWR0		SA-1111 GPIO A<0>
+	 *	A1VPP	S0_PWR1		SA-1111 GPIO A<1>
+	 *	A0VCC	S0_PWR2		SA-1111 GPIO A<2>
+	 *	A1VCC	S0_PWR3		SA-1111 GPIO A<3>
+	 *	VX	VCC
+	 *	VY	+3.3V
+	 *	12IN	+12V
+	 *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
+	 *
+	 * Socket 1 (CF):
+	 *	MAX1602	Lubbock		Register
+	 *	Pin	Signal
+	 *	-----	-------		----------------------
+	 *	A0VPP	GND		VPP is not connected
+	 *	A1VPP	GND		VPP is not connected
+	 *	A0VCC	S1_PWR0		MISC_WR<14>
+	 *	A1VCC	S1_PWR1		MISC_WR<15>
+	 *	VX	VCC
+	 *	VY	+3.3V
+	 *	12IN	GND		VPP is not connected
+	 *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
+	 *
+	 */
+
+ again:
+	switch (skt->nr) {
+	case 0:
+		pa_dwr_mask = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
+
+		switch (state->Vcc) {
+		case 0: /* Hi-Z */
+			break;
+
+		case 33: /* VY */
+			pa_dwr_set |= GPIO_A3;
+			break;
+
+		case 50: /* VX */
+			pa_dwr_set |= GPIO_A2;
+			break;
+
+		default:
+			printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+			       __func__, state->Vcc);
+			ret = -1;
+		}
+
+		switch (state->Vpp) {
+		case 0: /* Hi-Z */
+			break;
+
+		case 120: /* 12IN */
+			pa_dwr_set |= GPIO_A1;
+			break;
+
+		default: /* VCC */
+			if (state->Vpp == state->Vcc)
+				pa_dwr_set |= GPIO_A0;
+			else {
+				printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
+				       __func__, state->Vpp);
+				ret = -1;
+				break;
+			}
+		}
+		break;
+
+	case 1:
+		misc_mask = (1 << 15) | (1 << 14);
+
+		switch (state->Vcc) {
+		case 0: /* Hi-Z */
+			break;
+
+		case 33: /* VY */
+			misc_set |= 1 << 15;
+			break;
+
+		case 50: /* VX */
+			misc_set |= 1 << 14;
+			break;
+
+		default:
+			printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+			       __func__, state->Vcc);
+			ret = -1;
+			break;
+		}
+
+		if (state->Vpp != state->Vcc && state->Vpp != 0) {
+			printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
+			       __func__, state->Vpp);
+			ret = -1;
+			break;
+		}
+		break;
+
+	default:
+		ret = -1;
+	}
+
+	if (ret == 0)
+		ret = sa1111_pcmcia_configure_socket(skt, state);
+
+	if (ret == 0) {
+		lubbock_set_misc_wr(misc_mask, misc_set);
+		sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
+	}
+
+#if 1
+	if (ret == 0 && state->Vcc == 33) {
+		struct pcmcia_state new_state;
+
+		/*
+		 * HACK ALERT:
+		 * We can't sense the voltage properly on Lubbock before
+		 * actually applying some power to the socket (catch 22).
+		 * Resense the socket Voltage Sense pins after applying
+		 * socket power.
+		 *
+		 * Note: It takes about 2.5ms for the MAX1602 VCC output
+		 * to rise.
+		 */
+		mdelay(3);
+
+		sa1111_pcmcia_socket_state(skt, &new_state);
+
+		if (!new_state.vs_3v && !new_state.vs_Xv) {
+			/*
+			 * Switch to 5V,  Configure socket with 5V voltage
+			 */
+			lubbock_set_misc_wr(misc_mask, 0);
+			sa1111_set_io(s->dev, pa_dwr_mask, 0);
+
+			/*
+			 * It takes about 100ms to turn off Vcc.
+			 */
+			mdelay(100);
+
+			/*
+			 * We need to hack around the const qualifier as
+			 * well to keep this ugly workaround localized and
+			 * not force it to the rest of the code. Barf bags
+			 * available in the seat pocket in front of you!
+			 */
+			((socket_state_t *)state)->Vcc = 50;
+			((socket_state_t *)state)->Vpp = 50;
+			goto again;
+		}
+	}
+#endif
+
+	return ret;
+}
+
+static struct pcmcia_low_level lubbock_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+	.configure_socket	= lubbock_pcmcia_configure_socket,
+	.first			= 0,
+	.nr			= 2,
+};
+
+#include "pxa2xx_base.h"
+
+int pcmcia_lubbock_init(struct sa1111_dev *sadev)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_lubbock()) {
+		/*
+		 * Set GPIO_A<3:0> to be outputs for the MAX1600,
+		 * and switch to standby mode.
+		 */
+		sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
+		sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
+		sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
+
+		/* Set CF Socket 1 power to standby mode. */
+		lubbock_set_misc_wr((1 << 15) | (1 << 14), 0);
+
+		pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops);
+		pxa2xx_configure_sockets(&sadev->dev);
+		ret = sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops,
+				pxa2xx_drv_pcmcia_add_one);
+	}
+
+	return ret;
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/pcmcia/sa1111_neponset.c b/drivers/pcmcia/sa1111_neponset.c
new file mode 100644
index 0000000..1d78739
--- /dev/null
+++ b/drivers/pcmcia/sa1111_neponset.c
@@ -0,0 +1,129 @@
+/*
+ * linux/drivers/pcmcia/sa1100_neponset.c
+ *
+ * Neponset PCMCIA specific routines
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <mach/neponset.h>
+#include <asm/hardware/sa1111.h>
+
+#include "sa1111_generic.h"
+
+/*
+ * Neponset uses the Maxim MAX1600, with the following connections:
+ *
+ *   MAX1600      Neponset
+ *
+ *    A0VCC        SA-1111 GPIO A<1>
+ *    A1VCC        SA-1111 GPIO A<0>
+ *    A0VPP        CPLD NCR A0VPP
+ *    A1VPP        CPLD NCR A1VPP
+ *    B0VCC        SA-1111 GPIO A<2>
+ *    B1VCC        SA-1111 GPIO A<3>
+ *    B0VPP        ground (slot B is CF)
+ *    B1VPP        ground (slot B is CF)
+ *
+ *     VX          VCC (5V)
+ *     VY          VCC3_3 (3.3V)
+ *     12INA       12V
+ *     12INB       ground (slot B is CF)
+ *
+ * The MAX1600 CODE pin is tied to ground, placing the device in 
+ * "Standard Intel code" mode. Refer to the Maxim data sheet for
+ * the corresponding truth table.
+ */
+
+static int
+neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
+{
+	struct sa1111_pcmcia_socket *s = to_skt(skt);
+	unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set;
+	int ret;
+
+	switch (skt->nr) {
+	case 0:
+		pa_dwr_mask = GPIO_A0 | GPIO_A1;
+		ncr_mask = NCR_A0VPP | NCR_A1VPP;
+
+		if (state->Vpp == 0)
+			ncr_set = 0;
+		else if (state->Vpp == 120)
+			ncr_set = NCR_A1VPP;
+		else if (state->Vpp == state->Vcc)
+			ncr_set = NCR_A0VPP;
+		else {
+			printk(KERN_ERR "%s(): unrecognized VPP %u\n",
+			       __func__, state->Vpp);
+			return -1;
+		}
+		break;
+
+	case 1:
+		pa_dwr_mask = GPIO_A2 | GPIO_A3;
+		ncr_mask = 0;
+		ncr_set = 0;
+
+		if (state->Vpp != state->Vcc && state->Vpp != 0) {
+			printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
+			       __func__, state->Vpp);
+			return -1;
+		}
+		break;
+
+	default:
+		return -1;
+	}
+
+	/*
+	 * pa_dwr_set is the mask for selecting Vcc on both sockets.
+	 * pa_dwr_mask selects which bits (and therefore socket) we change.
+	 */
+	switch (state->Vcc) {
+	default:
+	case 0:  pa_dwr_set = 0;		break;
+	case 33: pa_dwr_set = GPIO_A1|GPIO_A2;	break;
+	case 50: pa_dwr_set = GPIO_A0|GPIO_A3;	break;
+	}
+
+	ret = sa1111_pcmcia_configure_socket(skt, state);
+	if (ret == 0) {
+		neponset_ncr_frob(ncr_mask, ncr_set);
+		sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
+	}
+
+	return ret;
+}
+
+static struct pcmcia_low_level neponset_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+	.configure_socket	= neponset_pcmcia_configure_socket,
+	.first			= 0,
+	.nr			= 2,
+};
+
+int pcmcia_neponset_init(struct sa1111_dev *sadev)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_assabet()) {
+		/*
+		 * Set GPIO_A<3:0> to be outputs for the MAX1600,
+		 * and switch to standby mode.
+		 */
+		sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
+		sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
+		sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
+		sa11xx_drv_pcmcia_ops(&neponset_pcmcia_ops);
+		ret = sa1111_pcmcia_add(sadev, &neponset_pcmcia_ops,
+				sa11xx_drv_pcmcia_add_one);
+	}
+
+	return ret;
+}
diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c
index 0c62fe3..6eecd7c 100644
--- a/drivers/pcmcia/sa11xx_base.c
+++ b/drivers/pcmcia/sa11xx_base.c
@@ -41,7 +41,6 @@
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 
 #include "soc_common.h"
 #include "sa11xx_base.h"
@@ -236,10 +235,7 @@
 		skt = &sinfo->skt[i];
 
 		skt->nr = first + i;
-		skt->ops = ops;
-		skt->socket.owner = ops->owner;
-		skt->socket.dev.parent = dev;
-		skt->socket.pci_irq = NO_IRQ;
+		soc_pcmcia_init_one(skt, ops, dev);
 
 		ret = sa11xx_drv_pcmcia_add_one(skt);
 		if (ret)
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index a0a9c2a..a2bc6ee 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -32,6 +32,7 @@
 
 
 #include <linux/cpufreq.h>
+#include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -45,10 +46,11 @@
 #include <linux/timer.h>
 
 #include <mach/hardware.h>
-#include <asm/system.h>
 
 #include "soc_common.h"
 
+static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev);
+
 #ifdef CONFIG_PCMCIA_DEBUG
 
 static int pc_debug;
@@ -104,6 +106,93 @@
 }
 EXPORT_SYMBOL(soc_common_pcmcia_get_timing);
 
+static void __soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt,
+	unsigned int nr)
+{
+	unsigned int i;
+
+	for (i = 0; i < nr; i++) {
+		if (skt->stat[i].irq)
+			free_irq(skt->stat[i].irq, skt);
+		if (gpio_is_valid(skt->stat[i].gpio))
+			gpio_free(skt->stat[i].gpio);
+	}
+
+	if (skt->ops->hw_shutdown)
+		skt->ops->hw_shutdown(skt);
+}
+
+static void soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	__soc_pcmcia_hw_shutdown(skt, ARRAY_SIZE(skt->stat));
+}
+
+static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	int ret = 0, i;
+
+	if (skt->ops->hw_init) {
+		ret = skt->ops->hw_init(skt);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
+		if (gpio_is_valid(skt->stat[i].gpio)) {
+			int irq;
+
+			ret = gpio_request_one(skt->stat[i].gpio, GPIOF_IN,
+					       skt->stat[i].name);
+			if (ret) {
+				__soc_pcmcia_hw_shutdown(skt, i);
+				return ret;
+			}
+
+			irq = gpio_to_irq(skt->stat[i].gpio);
+
+			if (i == SOC_STAT_RDY)
+				skt->socket.pci_irq = irq;
+			else
+				skt->stat[i].irq = irq;
+		}
+
+		if (skt->stat[i].irq) {
+			ret = request_irq(skt->stat[i].irq,
+					  soc_common_pcmcia_interrupt,
+					  IRQF_TRIGGER_NONE,
+					  skt->stat[i].name, skt);
+			if (ret) {
+				if (gpio_is_valid(skt->stat[i].gpio))
+					gpio_free(skt->stat[i].gpio);
+				__soc_pcmcia_hw_shutdown(skt, i);
+				return ret;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static void soc_pcmcia_hw_enable(struct soc_pcmcia_socket *skt)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
+		if (skt->stat[i].irq) {
+			irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_RISING);
+			irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_BOTH);
+		}
+}
+
+static void soc_pcmcia_hw_disable(struct soc_pcmcia_socket *skt)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
+		if (skt->stat[i].irq)
+			irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_NONE);
+}
+
 static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt)
 {
 	struct pcmcia_state state;
@@ -111,6 +200,22 @@
 
 	memset(&state, 0, sizeof(struct pcmcia_state));
 
+	/* Make battery voltage state report 'good' */
+	state.bvd1 = 1;
+	state.bvd2 = 1;
+
+	/* CD is active low by default */
+	if (gpio_is_valid(skt->stat[SOC_STAT_CD].gpio))
+		state.detect = !gpio_get_value(skt->stat[SOC_STAT_CD].gpio);
+
+	/* RDY and BVD are active high by default */
+	if (gpio_is_valid(skt->stat[SOC_STAT_RDY].gpio))
+		state.ready = !!gpio_get_value(skt->stat[SOC_STAT_RDY].gpio);
+	if (gpio_is_valid(skt->stat[SOC_STAT_BVD1].gpio))
+		state.bvd1 = !!gpio_get_value(skt->stat[SOC_STAT_BVD1].gpio);
+	if (gpio_is_valid(skt->stat[SOC_STAT_BVD2].gpio))
+		state.bvd2 = !!gpio_get_value(skt->stat[SOC_STAT_BVD2].gpio);
+
 	skt->ops->socket_state(skt, &state);
 
 	stat = state.detect  ? SS_DETECT : 0;
@@ -188,6 +293,7 @@
 	debug(skt, 2, "initializing socket\n");
 	if (skt->ops->socket_init)
 		skt->ops->socket_init(skt);
+	soc_pcmcia_hw_enable(skt);
 	return 0;
 }
 
@@ -207,6 +313,7 @@
 
 	debug(skt, 2, "suspending socket\n");
 
+	soc_pcmcia_hw_disable(skt);
 	if (skt->ops->socket_suspend)
 		skt->ops->socket_suspend(skt);
 
@@ -526,69 +633,6 @@
 };
 
 
-int soc_pcmcia_request_irqs(struct soc_pcmcia_socket *skt,
-			    struct pcmcia_irqs *irqs, int nr)
-{
-	int i, res = 0;
-
-	for (i = 0; i < nr; i++) {
-		if (irqs[i].sock != skt->nr)
-			continue;
-		res = request_irq(irqs[i].irq, soc_common_pcmcia_interrupt,
-				  IRQF_DISABLED, irqs[i].str, skt);
-		if (res)
-			break;
-		irq_set_irq_type(irqs[i].irq, IRQ_TYPE_NONE);
-	}
-
-	if (res) {
-		printk(KERN_ERR "PCMCIA: request for IRQ%d failed (%d)\n",
-			irqs[i].irq, res);
-
-		while (i--)
-			if (irqs[i].sock == skt->nr)
-				free_irq(irqs[i].irq, skt);
-	}
-	return res;
-}
-EXPORT_SYMBOL(soc_pcmcia_request_irqs);
-
-void soc_pcmcia_free_irqs(struct soc_pcmcia_socket *skt,
-			  struct pcmcia_irqs *irqs, int nr)
-{
-	int i;
-
-	for (i = 0; i < nr; i++)
-		if (irqs[i].sock == skt->nr)
-			free_irq(irqs[i].irq, skt);
-}
-EXPORT_SYMBOL(soc_pcmcia_free_irqs);
-
-void soc_pcmcia_disable_irqs(struct soc_pcmcia_socket *skt,
-			     struct pcmcia_irqs *irqs, int nr)
-{
-	int i;
-
-	for (i = 0; i < nr; i++)
-		if (irqs[i].sock == skt->nr)
-			irq_set_irq_type(irqs[i].irq, IRQ_TYPE_NONE);
-}
-EXPORT_SYMBOL(soc_pcmcia_disable_irqs);
-
-void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt,
-			    struct pcmcia_irqs *irqs, int nr)
-{
-	int i;
-
-	for (i = 0; i < nr; i++)
-		if (irqs[i].sock == skt->nr) {
-			irq_set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_RISING);
-			irq_set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_BOTH);
-		}
-}
-EXPORT_SYMBOL(soc_pcmcia_enable_irqs);
-
-
 static LIST_HEAD(soc_pcmcia_sockets);
 static DEFINE_MUTEX(soc_pcmcia_sockets_lock);
 
@@ -635,6 +679,21 @@
 
 #endif
 
+void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt,
+	struct pcmcia_low_level *ops, struct device *dev)
+{
+	int i;
+
+	skt->ops = ops;
+	skt->socket.owner = ops->owner;
+	skt->socket.dev.parent = dev;
+	skt->socket.pci_irq = NO_IRQ;
+
+	for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
+		skt->stat[i].gpio = -EINVAL;
+}
+EXPORT_SYMBOL(soc_pcmcia_init_one);
+
 void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt)
 {
 	mutex_lock(&soc_pcmcia_sockets_lock);
@@ -642,8 +701,9 @@
 
 	pcmcia_unregister_socket(&skt->socket);
 
-	skt->ops->hw_shutdown(skt);
+	soc_pcmcia_hw_shutdown(skt);
 
+	/* should not be required; violates some lowlevel drivers */
 	soc_common_pcmcia_config_skt(skt, &dead_socket);
 
 	list_del(&skt->node);
@@ -700,7 +760,7 @@
 	 */
 	skt->ops->set_timing(skt);
 
-	ret = skt->ops->hw_init(skt);
+	ret = soc_pcmcia_hw_init(skt);
 	if (ret)
 		goto out_err_6;
 
@@ -733,7 +793,7 @@
 	pcmcia_unregister_socket(&skt->socket);
 
  out_err_7:
-	skt->ops->hw_shutdown(skt);
+	soc_pcmcia_hw_shutdown(skt);
  out_err_6:
 	list_del(&skt->node);
 	mutex_unlock(&soc_pcmcia_sockets_lock);
diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h
index 9daa736..e6fcbea 100644
--- a/drivers/pcmcia/soc_common.h
+++ b/drivers/pcmcia/soc_common.h
@@ -50,6 +50,16 @@
 	struct resource		res_attr;
 	void __iomem		*virt_io;
 
+	struct {
+		int		gpio;
+		unsigned int	irq;
+		const char	*name;
+	} stat[4];
+#define SOC_STAT_CD		0	/* Card detect */
+#define SOC_STAT_BVD1		1	/* BATDEAD / IOSTSCHG */
+#define SOC_STAT_BVD2		2	/* BATWARN / IOSPKR */
+#define SOC_STAT_RDY		3	/* Ready / Interrupt */
+
 	unsigned int		irq_state;
 
 	struct timer_list	poll_timer;
@@ -115,25 +125,16 @@
 };
 
 
-struct pcmcia_irqs {
-	int sock;
-	int irq;
-	const char *str;
-};
-
 struct soc_pcmcia_timing {
 	unsigned short io;
 	unsigned short mem;
 	unsigned short attr;
 };
 
-extern int soc_pcmcia_request_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
-extern void soc_pcmcia_free_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
-extern void soc_pcmcia_disable_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
-extern void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
 extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_pcmcia_timing *);
 
-
+void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt,
+	struct pcmcia_low_level *ops, struct device *dev);
 void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt);
 int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt);
 
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index 71aeed9..d688151 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -23,7 +23,6 @@
 #include <linux/pm.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 
 #include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 310160b..cbe15fc 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -47,7 +47,6 @@
 #include <linux/bitops.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <pcmcia/ss.h>
 #include "tcic.h"
diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c
index c6d36b3..cd0a315 100644
--- a/drivers/pcmcia/vrc4173_cardu.c
+++ b/drivers/pcmcia/vrc4173_cardu.c
@@ -563,11 +563,8 @@
 
 __setup("vrc4173_cardu=", vrc4173_cardu_setup);
 
-static struct pci_device_id vrc4173_cardu_id_table[] __devinitdata = {
-	{	.vendor		= PCI_VENDOR_ID_NEC,
-		.device		= PCI_DEVICE_ID_NEC_NAPCCARD,
-		.subvendor	= PCI_ANY_ID,
-		.subdevice	= PCI_ANY_ID, },
+static DEFINE_PCI_DEVICE_TABLE(vrc4173_cardu_id_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NAPCCARD) },
         {0, }
 };
 
diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c
index 379f421..fd5fbd1 100644
--- a/drivers/pcmcia/xxs1500_ss.c
+++ b/drivers/pcmcia/xxs1500_ss.c
@@ -21,7 +21,6 @@
 #include <pcmcia/cistpl.h>
 
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/mach-au1x00/au1000.h>
 
 #define MEM_MAP_SIZE	0x400000
@@ -321,18 +320,7 @@
 	.remove		= __devexit_p(xxs1500_pcmcia_remove),
 };
 
-int __init xxs1500_pcmcia_socket_load(void)
-{
-	return platform_driver_register(&xxs1500_pcmcia_socket_driver);
-}
-
-void  __exit xxs1500_pcmcia_socket_unload(void)
-{
-	platform_driver_unregister(&xxs1500_pcmcia_socket_driver);
-}
-
-module_init(xxs1500_pcmcia_socket_load);
-module_exit(xxs1500_pcmcia_socket_unload);
+module_platform_driver(xxs1500_pcmcia_socket_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("PCMCIA Socket Services for MyCable XXS1500 systems");
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 849c0c1..d07f9ac 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -1352,7 +1352,7 @@
 		.driver_data	= CARDBUS_TYPE_##type,	\
 	}
 
-static struct pci_device_id yenta_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(yenta_table) = {
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1031, TI),
 
 	/*
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index afaf885..abfb964 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -17,21 +17,63 @@
 config PINCONF
 	bool "Support pin configuration controllers"
 
+config GENERIC_PINCONF
+	bool
+	select PINCONF
+
 config DEBUG_PINCTRL
 	bool "Debug PINCTRL calls"
 	depends on DEBUG_KERNEL
 	help
 	  Say Y here to add some extra checks and diagnostics to PINCTRL calls.
 
+config PINCTRL_PXA3xx
+	bool
+	select PINMUX
+
+config PINCTRL_MMP2
+	bool "MMP2 pin controller driver"
+	depends on ARCH_MMP
+	select PINCTRL_PXA3xx
+	select PINCONF
+
+config PINCTRL_PXA168
+	bool "PXA168 pin controller driver"
+	depends on ARCH_MMP
+	select PINCTRL_PXA3xx
+	select PINCONF
+
+config PINCTRL_PXA910
+	bool "PXA910 pin controller driver"
+	depends on ARCH_MMP
+	select PINCTRL_PXA3xx
+	select PINCONF
+
 config PINCTRL_SIRF
 	bool "CSR SiRFprimaII pin controller driver"
 	depends on ARCH_PRIMA2
 	select PINMUX
 
+config PINCTRL_TEGRA
+	bool
+
+config PINCTRL_TEGRA20
+	bool
+	select PINMUX
+	select PINCONF
+	select PINCTRL_TEGRA
+
+config PINCTRL_TEGRA30
+	bool
+	select PINMUX
+	select PINCONF
+	select PINCTRL_TEGRA
+
 config PINCTRL_U300
 	bool "U300 pin controller driver"
 	depends on ARCH_U300
 	select PINMUX
+	select GENERIC_PINCONF
 
 config PINCTRL_COH901
 	bool "ST-Ericsson U300 COH 901 335/571 GPIO"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 827601c..6d4150b 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -5,6 +5,14 @@
 obj-$(CONFIG_PINCTRL)		+= core.o
 obj-$(CONFIG_PINMUX)		+= pinmux.o
 obj-$(CONFIG_PINCONF)		+= pinconf.o
+obj-$(CONFIG_GENERIC_PINCONF)	+= pinconf-generic.o
+obj-$(CONFIG_PINCTRL_PXA3xx)	+= pinctrl-pxa3xx.o
+obj-$(CONFIG_PINCTRL_MMP2)	+= pinctrl-mmp2.o
+obj-$(CONFIG_PINCTRL_PXA168)	+= pinctrl-pxa168.o
+obj-$(CONFIG_PINCTRL_PXA910)	+= pinctrl-pxa910.o
 obj-$(CONFIG_PINCTRL_SIRF)	+= pinctrl-sirf.o
+obj-$(CONFIG_PINCTRL_TEGRA)	+= pinctrl-tegra.o
+obj-$(CONFIG_PINCTRL_TEGRA20)	+= pinctrl-tegra20.o
+obj-$(CONFIG_PINCTRL_TEGRA30)	+= pinctrl-tegra30.o
 obj-$(CONFIG_PINCTRL_U300)	+= pinctrl-u300.o
 obj-$(CONFIG_PINCTRL_COH901)	+= pinctrl-coh901.o
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 894cd5e..ec3b8cc 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -1,12 +1,14 @@
 /*
  * Core driver for the pin control subsystem
  *
- * Copyright (C) 2011 ST-Ericsson SA
+ * Copyright (C) 2011-2012 ST-Ericsson SA
  * Written on behalf of Linaro for ST-Ericsson
  * Based on bits of regulator core, gpio core and clk core
  *
  * Author: Linus Walleij <linus.walleij@linaro.org>
  *
+ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
  * License terms: GNU General Public License (GPL) version 2
  */
 #define pr_fmt(fmt) "pinctrl core: " fmt
@@ -16,11 +18,8 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/slab.h>
-#include <linux/radix-tree.h>
 #include <linux/err.h>
 #include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/spinlock.h>
 #include <linux/sysfs.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
@@ -30,10 +29,36 @@
 #include "pinmux.h"
 #include "pinconf.h"
 
-/* Global list of pin control devices */
-static DEFINE_MUTEX(pinctrldev_list_mutex);
+/**
+ * struct pinctrl_maps - a list item containing part of the mapping table
+ * @node: mapping table list node
+ * @maps: array of mapping table entries
+ * @num_maps: the number of entries in @maps
+ */
+struct pinctrl_maps {
+	struct list_head node;
+	struct pinctrl_map const *maps;
+	unsigned num_maps;
+};
+
+/* Mutex taken by all entry points */
+DEFINE_MUTEX(pinctrl_mutex);
+
+/* Global list of pin control devices (struct pinctrl_dev) */
 static LIST_HEAD(pinctrldev_list);
 
+/* List of pin controller handles (struct pinctrl) */
+static LIST_HEAD(pinctrl_list);
+
+/* List of pinctrl maps (struct pinctrl_maps) */
+static LIST_HEAD(pinctrl_maps);
+
+#define for_each_maps(_maps_node_, _i_, _map_) \
+	list_for_each_entry(_maps_node_, &pinctrl_maps, node) \
+		for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \
+			_i_ < _maps_node_->num_maps; \
+			i++, _map_ = &_maps_node_->maps[_i_])
+
 const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev)
 {
 	/* We're not allowed to register devices without name */
@@ -48,53 +73,31 @@
 EXPORT_SYMBOL_GPL(pinctrl_dev_get_drvdata);
 
 /**
- * get_pinctrl_dev_from_dev() - look up pin controller device
- * @dev: a device pointer, this may be NULL but then devname needs to be
- *	defined instead
- * @devname: the name of a device instance, as returned by dev_name(), this
- *	may be NULL but then dev needs to be defined instead
+ * get_pinctrl_dev_from_devname() - look up pin controller device
+ * @devname: the name of a device instance, as returned by dev_name()
  *
  * Looks up a pin control device matching a certain device name or pure device
  * pointer, the pure device pointer will take precedence.
  */
-struct pinctrl_dev *get_pinctrl_dev_from_dev(struct device *dev,
-					     const char *devname)
+struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *devname)
 {
 	struct pinctrl_dev *pctldev = NULL;
 	bool found = false;
 
-	mutex_lock(&pinctrldev_list_mutex);
-	list_for_each_entry(pctldev, &pinctrldev_list, node) {
-		if (dev && pctldev->dev == dev) {
-			/* Matched on device pointer */
-			found = true;
-			break;
-		}
+	if (!devname)
+		return NULL;
 
-		if (devname &&
-		    !strcmp(dev_name(pctldev->dev), devname)) {
+	list_for_each_entry(pctldev, &pinctrldev_list, node) {
+		if (!strcmp(dev_name(pctldev->dev), devname)) {
 			/* Matched on device name */
 			found = true;
 			break;
 		}
 	}
-	mutex_unlock(&pinctrldev_list_mutex);
 
 	return found ? pctldev : NULL;
 }
 
-struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev, unsigned int pin)
-{
-	struct pin_desc *pindesc;
-	unsigned long flags;
-
-	spin_lock_irqsave(&pctldev->pin_desc_tree_lock, flags);
-	pindesc = radix_tree_lookup(&pctldev->pin_desc_tree, pin);
-	spin_unlock_irqrestore(&pctldev->pin_desc_tree_lock, flags);
-
-	return pindesc;
-}
-
 /**
  * pin_get_from_name() - look up a pin number from a name
  * @pctldev: the pin control device to lookup the pin on
@@ -135,11 +138,11 @@
 	if (pin < 0)
 		return false;
 
+	mutex_lock(&pinctrl_mutex);
 	pindesc = pin_desc_get(pctldev, pin);
-	if (pindesc == NULL)
-		return false;
+	mutex_unlock(&pinctrl_mutex);
 
-	return true;
+	return pindesc != NULL;
 }
 EXPORT_SYMBOL_GPL(pin_is_valid);
 
@@ -150,7 +153,6 @@
 {
 	int i;
 
-	spin_lock(&pctldev->pin_desc_tree_lock);
 	for (i = 0; i < num_pins; i++) {
 		struct pin_desc *pindesc;
 
@@ -164,7 +166,6 @@
 		}
 		kfree(pindesc);
 	}
-	spin_unlock(&pctldev->pin_desc_tree_lock);
 }
 
 static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
@@ -180,10 +181,10 @@
 	}
 
 	pindesc = kzalloc(sizeof(*pindesc), GFP_KERNEL);
-	if (pindesc == NULL)
+	if (pindesc == NULL) {
+		dev_err(pctldev->dev, "failed to alloc struct pin_desc\n");
 		return -ENOMEM;
-
-	spin_lock_init(&pindesc->lock);
+	}
 
 	/* Set owner */
 	pindesc->pctldev = pctldev;
@@ -198,9 +199,7 @@
 		pindesc->dynamic_name = true;
 	}
 
-	spin_lock(&pctldev->pin_desc_tree_lock);
 	radix_tree_insert(&pctldev->pin_desc_tree, number, pindesc);
-	spin_unlock(&pctldev->pin_desc_tree_lock);
 	pr_debug("registered pin %d (%s) on %s\n",
 		 number, pindesc->name, pctldev->desc->name);
 	return 0;
@@ -237,16 +236,13 @@
 	struct pinctrl_gpio_range *range = NULL;
 
 	/* Loop over the ranges */
-	mutex_lock(&pctldev->gpio_ranges_lock);
 	list_for_each_entry(range, &pctldev->gpio_ranges, node) {
 		/* Check if we're in the valid range */
 		if (gpio >= range->base &&
 		    gpio < range->base + range->npins) {
-			mutex_unlock(&pctldev->gpio_ranges_lock);
 			return range;
 		}
 	}
-	mutex_unlock(&pctldev->gpio_ranges_lock);
 
 	return NULL;
 }
@@ -261,14 +257,13 @@
  * the GPIO subsystem, return the device and the matching GPIO range. Returns
  * negative if the GPIO range could not be found in any device.
  */
-int pinctrl_get_device_gpio_range(unsigned gpio,
-				struct pinctrl_dev **outdev,
-				struct pinctrl_gpio_range **outrange)
+static int pinctrl_get_device_gpio_range(unsigned gpio,
+					 struct pinctrl_dev **outdev,
+					 struct pinctrl_gpio_range **outrange)
 {
 	struct pinctrl_dev *pctldev = NULL;
 
 	/* Loop over the pin controllers */
-	mutex_lock(&pinctrldev_list_mutex);
 	list_for_each_entry(pctldev, &pinctrldev_list, node) {
 		struct pinctrl_gpio_range *range;
 
@@ -276,11 +271,9 @@
 		if (range != NULL) {
 			*outdev = pctldev;
 			*outrange = range;
-			mutex_unlock(&pinctrldev_list_mutex);
 			return 0;
 		}
 	}
-	mutex_unlock(&pinctrldev_list_mutex);
 
 	return -EINVAL;
 }
@@ -296,10 +289,11 @@
 void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
 			    struct pinctrl_gpio_range *range)
 {
-	mutex_lock(&pctldev->gpio_ranges_lock);
-	list_add(&range->node, &pctldev->gpio_ranges);
-	mutex_unlock(&pctldev->gpio_ranges_lock);
+	mutex_lock(&pinctrl_mutex);
+	list_add_tail(&range->node, &pctldev->gpio_ranges);
+	mutex_unlock(&pinctrl_mutex);
 }
+EXPORT_SYMBOL_GPL(pinctrl_add_gpio_range);
 
 /**
  * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller
@@ -309,10 +303,11 @@
 void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
 			       struct pinctrl_gpio_range *range)
 {
-	mutex_lock(&pctldev->gpio_ranges_lock);
+	mutex_lock(&pinctrl_mutex);
 	list_del(&range->node);
-	mutex_unlock(&pctldev->gpio_ranges_lock);
+	mutex_unlock(&pinctrl_mutex);
 }
+EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
 
 /**
  * pinctrl_get_group_selector() - returns the group selector for a group
@@ -345,6 +340,531 @@
 	return -EINVAL;
 }
 
+/**
+ * pinctrl_request_gpio() - request a single pin to be used in as GPIO
+ * @gpio: the GPIO pin number from the GPIO subsystem number space
+ *
+ * This function should *ONLY* be used from gpiolib-based GPIO drivers,
+ * as part of their gpio_request() semantics, platforms and individual drivers
+ * shall *NOT* request GPIO pins to be muxed in.
+ */
+int pinctrl_request_gpio(unsigned gpio)
+{
+	struct pinctrl_dev *pctldev;
+	struct pinctrl_gpio_range *range;
+	int ret;
+	int pin;
+
+	mutex_lock(&pinctrl_mutex);
+
+	ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
+	if (ret) {
+		mutex_unlock(&pinctrl_mutex);
+		return -EINVAL;
+	}
+
+	/* Convert to the pin controllers number space */
+	pin = gpio - range->base + range->pin_base;
+
+	ret = pinmux_request_gpio(pctldev, range, pin, gpio);
+
+	mutex_unlock(&pinctrl_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pinctrl_request_gpio);
+
+/**
+ * pinctrl_free_gpio() - free control on a single pin, currently used as GPIO
+ * @gpio: the GPIO pin number from the GPIO subsystem number space
+ *
+ * This function should *ONLY* be used from gpiolib-based GPIO drivers,
+ * as part of their gpio_free() semantics, platforms and individual drivers
+ * shall *NOT* request GPIO pins to be muxed out.
+ */
+void pinctrl_free_gpio(unsigned gpio)
+{
+	struct pinctrl_dev *pctldev;
+	struct pinctrl_gpio_range *range;
+	int ret;
+	int pin;
+
+	mutex_lock(&pinctrl_mutex);
+
+	ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
+	if (ret) {
+		mutex_unlock(&pinctrl_mutex);
+		return;
+	}
+
+	/* Convert to the pin controllers number space */
+	pin = gpio - range->base + range->pin_base;
+
+	pinmux_free_gpio(pctldev, pin, range);
+
+	mutex_unlock(&pinctrl_mutex);
+}
+EXPORT_SYMBOL_GPL(pinctrl_free_gpio);
+
+static int pinctrl_gpio_direction(unsigned gpio, bool input)
+{
+	struct pinctrl_dev *pctldev;
+	struct pinctrl_gpio_range *range;
+	int ret;
+	int pin;
+
+	ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
+	if (ret)
+		return ret;
+
+	/* Convert to the pin controllers number space */
+	pin = gpio - range->base + range->pin_base;
+
+	return pinmux_gpio_direction(pctldev, range, pin, input);
+}
+
+/**
+ * pinctrl_gpio_direction_input() - request a GPIO pin to go into input mode
+ * @gpio: the GPIO pin number from the GPIO subsystem number space
+ *
+ * This function should *ONLY* be used from gpiolib-based GPIO drivers,
+ * as part of their gpio_direction_input() semantics, platforms and individual
+ * drivers shall *NOT* touch pin control GPIO calls.
+ */
+int pinctrl_gpio_direction_input(unsigned gpio)
+{
+	int ret;
+	mutex_lock(&pinctrl_mutex);
+	ret = pinctrl_gpio_direction(gpio, true);
+	mutex_unlock(&pinctrl_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_input);
+
+/**
+ * pinctrl_gpio_direction_output() - request a GPIO pin to go into output mode
+ * @gpio: the GPIO pin number from the GPIO subsystem number space
+ *
+ * This function should *ONLY* be used from gpiolib-based GPIO drivers,
+ * as part of their gpio_direction_output() semantics, platforms and individual
+ * drivers shall *NOT* touch pin control GPIO calls.
+ */
+int pinctrl_gpio_direction_output(unsigned gpio)
+{
+	int ret;
+	mutex_lock(&pinctrl_mutex);
+	ret = pinctrl_gpio_direction(gpio, false);
+	mutex_unlock(&pinctrl_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_output);
+
+static struct pinctrl_state *find_state(struct pinctrl *p,
+					const char *name)
+{
+	struct pinctrl_state *state;
+
+	list_for_each_entry(state, &p->states, node)
+		if (!strcmp(state->name, name))
+			return state;
+
+	return NULL;
+}
+
+static struct pinctrl_state *create_state(struct pinctrl *p,
+					  const char *name)
+{
+	struct pinctrl_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (state == NULL) {
+		dev_err(p->dev,
+			"failed to alloc struct pinctrl_state\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	state->name = name;
+	INIT_LIST_HEAD(&state->settings);
+
+	list_add_tail(&state->node, &p->states);
+
+	return state;
+}
+
+static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
+{
+	struct pinctrl_state *state;
+	struct pinctrl_setting *setting;
+	int ret;
+
+	state = find_state(p, map->name);
+	if (!state)
+		state = create_state(p, map->name);
+	if (IS_ERR(state))
+		return PTR_ERR(state);
+
+	if (map->type == PIN_MAP_TYPE_DUMMY_STATE)
+		return 0;
+
+	setting = kzalloc(sizeof(*setting), GFP_KERNEL);
+	if (setting == NULL) {
+		dev_err(p->dev,
+			"failed to alloc struct pinctrl_setting\n");
+		return -ENOMEM;
+	}
+
+	setting->type = map->type;
+
+	setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
+	if (setting->pctldev == NULL) {
+		dev_err(p->dev, "unknown pinctrl device %s in map entry",
+			map->ctrl_dev_name);
+		kfree(setting);
+		/* Eventually, this should trigger deferred probe */
+		return -ENODEV;
+	}
+
+	switch (map->type) {
+	case PIN_MAP_TYPE_MUX_GROUP:
+		ret = pinmux_map_to_setting(map, setting);
+		break;
+	case PIN_MAP_TYPE_CONFIGS_PIN:
+	case PIN_MAP_TYPE_CONFIGS_GROUP:
+		ret = pinconf_map_to_setting(map, setting);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (ret < 0) {
+		kfree(setting);
+		return ret;
+	}
+
+	list_add_tail(&setting->node, &state->settings);
+
+	return 0;
+}
+
+static struct pinctrl *find_pinctrl(struct device *dev)
+{
+	struct pinctrl *p;
+
+	list_for_each_entry(p, &pinctrl_list, node)
+		if (p->dev == dev)
+			return p;
+
+	return NULL;
+}
+
+static void pinctrl_put_locked(struct pinctrl *p, bool inlist);
+
+static struct pinctrl *create_pinctrl(struct device *dev)
+{
+	struct pinctrl *p;
+	const char *devname;
+	struct pinctrl_maps *maps_node;
+	int i;
+	struct pinctrl_map const *map;
+	int ret;
+
+	/*
+	 * create the state cookie holder struct pinctrl for each
+	 * mapping, this is what consumers will get when requesting
+	 * a pin control handle with pinctrl_get()
+	 */
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (p == NULL) {
+		dev_err(dev, "failed to alloc struct pinctrl\n");
+		return ERR_PTR(-ENOMEM);
+	}
+	p->dev = dev;
+	INIT_LIST_HEAD(&p->states);
+
+	devname = dev_name(dev);
+
+	/* Iterate over the pin control maps to locate the right ones */
+	for_each_maps(maps_node, i, map) {
+		/* Map must be for this device */
+		if (strcmp(map->dev_name, devname))
+			continue;
+
+		ret = add_setting(p, map);
+		if (ret < 0) {
+			pinctrl_put_locked(p, false);
+			return ERR_PTR(ret);
+		}
+	}
+
+	/* Add the pinmux to the global list */
+	list_add_tail(&p->node, &pinctrl_list);
+
+	return p;
+}
+
+static struct pinctrl *pinctrl_get_locked(struct device *dev)
+{
+	struct pinctrl *p;
+
+	if (WARN_ON(!dev))
+		return ERR_PTR(-EINVAL);
+
+	p = find_pinctrl(dev);
+	if (p != NULL)
+		return ERR_PTR(-EBUSY);
+
+	p = create_pinctrl(dev);
+	if (IS_ERR(p))
+		return p;
+
+	return p;
+}
+
+/**
+ * pinctrl_get() - retrieves the pinctrl handle for a device
+ * @dev: the device to obtain the handle for
+ */
+struct pinctrl *pinctrl_get(struct device *dev)
+{
+	struct pinctrl *p;
+
+	mutex_lock(&pinctrl_mutex);
+	p = pinctrl_get_locked(dev);
+	mutex_unlock(&pinctrl_mutex);
+
+	return p;
+}
+EXPORT_SYMBOL_GPL(pinctrl_get);
+
+static void pinctrl_put_locked(struct pinctrl *p, bool inlist)
+{
+	struct pinctrl_state *state, *n1;
+	struct pinctrl_setting *setting, *n2;
+
+	list_for_each_entry_safe(state, n1, &p->states, node) {
+		list_for_each_entry_safe(setting, n2, &state->settings, node) {
+			switch (setting->type) {
+			case PIN_MAP_TYPE_MUX_GROUP:
+				if (state == p->state)
+					pinmux_disable_setting(setting);
+				pinmux_free_setting(setting);
+				break;
+			case PIN_MAP_TYPE_CONFIGS_PIN:
+			case PIN_MAP_TYPE_CONFIGS_GROUP:
+				pinconf_free_setting(setting);
+				break;
+			default:
+				break;
+			}
+			list_del(&setting->node);
+			kfree(setting);
+		}
+		list_del(&state->node);
+		kfree(state);
+	}
+
+	if (inlist)
+		list_del(&p->node);
+	kfree(p);
+}
+
+/**
+ * pinctrl_put() - release a previously claimed pinctrl handle
+ * @p: the pinctrl handle to release
+ */
+void pinctrl_put(struct pinctrl *p)
+{
+	mutex_lock(&pinctrl_mutex);
+	pinctrl_put_locked(p, true);
+	mutex_unlock(&pinctrl_mutex);
+}
+EXPORT_SYMBOL_GPL(pinctrl_put);
+
+static struct pinctrl_state *pinctrl_lookup_state_locked(struct pinctrl *p,
+							 const char *name)
+{
+	struct pinctrl_state *state;
+
+	state = find_state(p, name);
+	if (!state)
+		return ERR_PTR(-ENODEV);
+
+	return state;
+}
+
+/**
+ * pinctrl_lookup_state() - retrieves a state handle from a pinctrl handle
+ * @p: the pinctrl handle to retrieve the state from
+ * @name: the state name to retrieve
+ */
+struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, const char *name)
+{
+	struct pinctrl_state *s;
+
+	mutex_lock(&pinctrl_mutex);
+	s = pinctrl_lookup_state_locked(p, name);
+	mutex_unlock(&pinctrl_mutex);
+
+	return s;
+}
+EXPORT_SYMBOL_GPL(pinctrl_lookup_state);
+
+static int pinctrl_select_state_locked(struct pinctrl *p,
+				       struct pinctrl_state *state)
+{
+	struct pinctrl_setting *setting, *setting2;
+	int ret;
+
+	if (p->state == state)
+		return 0;
+
+	if (p->state) {
+		/*
+		 * The set of groups with a mux configuration in the old state
+		 * may not be identical to the set of groups with a mux setting
+		 * in the new state. While this might be unusual, it's entirely
+		 * possible for the "user"-supplied mapping table to be written
+		 * that way. For each group that was configured in the old state
+		 * but not in the new state, this code puts that group into a
+		 * safe/disabled state.
+		 */
+		list_for_each_entry(setting, &p->state->settings, node) {
+			bool found = false;
+			if (setting->type != PIN_MAP_TYPE_MUX_GROUP)
+				continue;
+			list_for_each_entry(setting2, &state->settings, node) {
+				if (setting2->type != PIN_MAP_TYPE_MUX_GROUP)
+					continue;
+				if (setting2->data.mux.group ==
+						setting->data.mux.group) {
+					found = true;
+					break;
+				}
+			}
+			if (!found)
+				pinmux_disable_setting(setting);
+		}
+	}
+
+	p->state = state;
+
+	/* Apply all the settings for the new state */
+	list_for_each_entry(setting, &state->settings, node) {
+		switch (setting->type) {
+		case PIN_MAP_TYPE_MUX_GROUP:
+			ret = pinmux_enable_setting(setting);
+			break;
+		case PIN_MAP_TYPE_CONFIGS_PIN:
+		case PIN_MAP_TYPE_CONFIGS_GROUP:
+			ret = pinconf_apply_setting(setting);
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		if (ret < 0) {
+			/* FIXME: Difficult to return to prev state */
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * pinctrl_select() - select/activate/program a pinctrl state to HW
+ * @p: the pinctrl handle for the device that requests configuratio
+ * @state: the state handle to select/activate/program
+ */
+int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
+{
+	int ret;
+
+	mutex_lock(&pinctrl_mutex);
+	ret = pinctrl_select_state_locked(p, state);
+	mutex_unlock(&pinctrl_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pinctrl_select_state);
+
+/**
+ * pinctrl_register_mappings() - register a set of pin controller mappings
+ * @maps: the pincontrol mappings table to register. This should probably be
+ *	marked with __initdata so it can be discarded after boot. This
+ *	function will perform a shallow copy for the mapping entries.
+ * @num_maps: the number of maps in the mapping table
+ */
+int pinctrl_register_mappings(struct pinctrl_map const *maps,
+			      unsigned num_maps)
+{
+	int i, ret;
+	struct pinctrl_maps *maps_node;
+
+	pr_debug("add %d pinmux maps\n", num_maps);
+
+	/* First sanity check the new mapping */
+	for (i = 0; i < num_maps; i++) {
+		if (!maps[i].dev_name) {
+			pr_err("failed to register map %s (%d): no device given\n",
+			       maps[i].name, i);
+			return -EINVAL;
+		}
+
+		if (!maps[i].name) {
+			pr_err("failed to register map %d: no map name given\n",
+			       i);
+			return -EINVAL;
+		}
+
+		if (maps[i].type != PIN_MAP_TYPE_DUMMY_STATE &&
+				!maps[i].ctrl_dev_name) {
+			pr_err("failed to register map %s (%d): no pin control device given\n",
+			       maps[i].name, i);
+			return -EINVAL;
+		}
+
+		switch (maps[i].type) {
+		case PIN_MAP_TYPE_DUMMY_STATE:
+			break;
+		case PIN_MAP_TYPE_MUX_GROUP:
+			ret = pinmux_validate_map(&maps[i], i);
+			if (ret < 0)
+				return 0;
+			break;
+		case PIN_MAP_TYPE_CONFIGS_PIN:
+		case PIN_MAP_TYPE_CONFIGS_GROUP:
+			ret = pinconf_validate_map(&maps[i], i);
+			if (ret < 0)
+				return 0;
+			break;
+		default:
+			pr_err("failed to register map %s (%d): invalid type given\n",
+			       maps[i].name, i);
+			return -EINVAL;
+		}
+	}
+
+	maps_node = kzalloc(sizeof(*maps_node), GFP_KERNEL);
+	if (!maps_node) {
+		pr_err("failed to alloc struct pinctrl_maps\n");
+		return -ENOMEM;
+	}
+
+	maps_node->num_maps = num_maps;
+	maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps, GFP_KERNEL);
+	if (!maps_node->maps) {
+		pr_err("failed to duplicate mapping table\n");
+		kfree(maps_node);
+		return -ENOMEM;
+	}
+
+	mutex_lock(&pinctrl_mutex);
+	list_add_tail(&maps_node->node, &pinctrl_maps);
+	mutex_unlock(&pinctrl_mutex);
+
+	return 0;
+}
+
 #ifdef CONFIG_DEBUG_FS
 
 static int pinctrl_pins_show(struct seq_file *s, void *what)
@@ -355,6 +875,8 @@
 
 	seq_printf(s, "registered pins: %d\n", pctldev->desc->npins);
 
+	mutex_lock(&pinctrl_mutex);
+
 	/* The pin number can be retrived from the pin controller descriptor */
 	for (i = 0; i < pctldev->desc->npins; i++) {
 		struct pin_desc *desc;
@@ -375,6 +897,8 @@
 		seq_puts(s, "\n");
 	}
 
+	mutex_unlock(&pinctrl_mutex);
+
 	return 0;
 }
 
@@ -388,6 +912,8 @@
 	if (!ops)
 		return 0;
 
+	mutex_lock(&pinctrl_mutex);
+
 	seq_puts(s, "registered pin groups:\n");
 	while (ops->list_groups(pctldev, selector) >= 0) {
 		const unsigned *pins;
@@ -410,6 +936,7 @@
 		selector++;
 	}
 
+	mutex_unlock(&pinctrl_mutex);
 
 	return 0;
 }
@@ -421,8 +948,9 @@
 
 	seq_puts(s, "GPIO ranges handled:\n");
 
+	mutex_lock(&pinctrl_mutex);
+
 	/* Loop over the ranges */
-	mutex_lock(&pctldev->gpio_ranges_lock);
 	list_for_each_entry(range, &pctldev->gpio_ranges, node) {
 		seq_printf(s, "%u: %s GPIOS [%u - %u] PINS [%u - %u]\n",
 			   range->id, range->name,
@@ -430,7 +958,8 @@
 			   range->pin_base,
 			   (range->pin_base + range->npins - 1));
 	}
-	mutex_unlock(&pctldev->gpio_ranges_lock);
+
+	mutex_unlock(&pinctrl_mutex);
 
 	return 0;
 }
@@ -440,7 +969,9 @@
 	struct pinctrl_dev *pctldev;
 
 	seq_puts(s, "name [pinmux] [pinconf]\n");
-	mutex_lock(&pinctrldev_list_mutex);
+
+	mutex_lock(&pinctrl_mutex);
+
 	list_for_each_entry(pctldev, &pinctrldev_list, node) {
 		seq_printf(s, "%s ", pctldev->desc->name);
 		if (pctldev->desc->pmxops)
@@ -453,7 +984,108 @@
 			seq_puts(s, "no");
 		seq_puts(s, "\n");
 	}
-	mutex_unlock(&pinctrldev_list_mutex);
+
+	mutex_unlock(&pinctrl_mutex);
+
+	return 0;
+}
+
+static inline const char *map_type(enum pinctrl_map_type type)
+{
+	static const char * const names[] = {
+		"INVALID",
+		"DUMMY_STATE",
+		"MUX_GROUP",
+		"CONFIGS_PIN",
+		"CONFIGS_GROUP",
+	};
+
+	if (type >= ARRAY_SIZE(names))
+		return "UNKNOWN";
+
+	return names[type];
+}
+
+static int pinctrl_maps_show(struct seq_file *s, void *what)
+{
+	struct pinctrl_maps *maps_node;
+	int i;
+	struct pinctrl_map const *map;
+
+	seq_puts(s, "Pinctrl maps:\n");
+
+	mutex_lock(&pinctrl_mutex);
+
+	for_each_maps(maps_node, i, map) {
+		seq_printf(s, "device %s\nstate %s\ntype %s (%d)\n",
+			   map->dev_name, map->name, map_type(map->type),
+			   map->type);
+
+		if (map->type != PIN_MAP_TYPE_DUMMY_STATE)
+			seq_printf(s, "controlling device %s\n",
+				   map->ctrl_dev_name);
+
+		switch (map->type) {
+		case PIN_MAP_TYPE_MUX_GROUP:
+			pinmux_show_map(s, map);
+			break;
+		case PIN_MAP_TYPE_CONFIGS_PIN:
+		case PIN_MAP_TYPE_CONFIGS_GROUP:
+			pinconf_show_map(s, map);
+			break;
+		default:
+			break;
+		}
+
+		seq_printf(s, "\n");
+	}
+
+	mutex_unlock(&pinctrl_mutex);
+
+	return 0;
+}
+
+static int pinctrl_show(struct seq_file *s, void *what)
+{
+	struct pinctrl *p;
+	struct pinctrl_state *state;
+	struct pinctrl_setting *setting;
+
+	seq_puts(s, "Requested pin control handlers their pinmux maps:\n");
+
+	mutex_lock(&pinctrl_mutex);
+
+	list_for_each_entry(p, &pinctrl_list, node) {
+		seq_printf(s, "device: %s current state: %s\n",
+			   dev_name(p->dev),
+			   p->state ? p->state->name : "none");
+
+		list_for_each_entry(state, &p->states, node) {
+			seq_printf(s, "  state: %s\n", state->name);
+
+			list_for_each_entry(setting, &state->settings, node) {
+				struct pinctrl_dev *pctldev = setting->pctldev;
+
+				seq_printf(s, "    type: %s controller %s ",
+					   map_type(setting->type),
+					   pinctrl_dev_get_name(pctldev));
+
+				switch (setting->type) {
+				case PIN_MAP_TYPE_MUX_GROUP:
+					pinmux_show_setting(s, setting);
+					break;
+				case PIN_MAP_TYPE_CONFIGS_PIN:
+				case PIN_MAP_TYPE_CONFIGS_GROUP:
+					pinconf_show_setting(s, setting);
+					break;
+				default:
+					break;
+				}
+			}
+		}
+	}
+
+	mutex_unlock(&pinctrl_mutex);
 
 	return 0;
 }
@@ -478,6 +1110,16 @@
 	return single_open(file, pinctrl_devices_show, NULL);
 }
 
+static int pinctrl_maps_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pinctrl_maps_show, NULL);
+}
+
+static int pinctrl_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pinctrl_show, NULL);
+}
+
 static const struct file_operations pinctrl_pins_ops = {
 	.open		= pinctrl_pins_open,
 	.read		= seq_read,
@@ -506,6 +1148,20 @@
 	.release	= single_release,
 };
 
+static const struct file_operations pinctrl_maps_ops = {
+	.open		= pinctrl_maps_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static const struct file_operations pinctrl_ops = {
+	.open		= pinctrl_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 static struct dentry *debugfs_root;
 
 static void pinctrl_init_device_debugfs(struct pinctrl_dev *pctldev)
@@ -547,7 +1203,10 @@
 
 	debugfs_create_file("pinctrl-devices", S_IFREG | S_IRUGO,
 			    debugfs_root, NULL, &pinctrl_devices_ops);
-	pinmux_init_debugfs(debugfs_root);
+	debugfs_create_file("pinctrl-maps", S_IFREG | S_IRUGO,
+			    debugfs_root, NULL, &pinctrl_maps_ops);
+	debugfs_create_file("pinctrl-handles", S_IFREG | S_IRUGO,
+			    debugfs_root, NULL, &pinctrl_ops);
 }
 
 #else /* CONFIG_DEBUG_FS */
@@ -583,18 +1242,18 @@
 	if (pctldesc->name == NULL)
 		return NULL;
 
-	pctldev = kzalloc(sizeof(struct pinctrl_dev), GFP_KERNEL);
-	if (pctldev == NULL)
+	pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
+	if (pctldev == NULL) {
+		dev_err(dev, "failed to alloc struct pinctrl_dev\n");
 		return NULL;
+	}
 
 	/* Initialize pin control device struct */
 	pctldev->owner = pctldesc->owner;
 	pctldev->desc = pctldesc;
 	pctldev->driver_data = driver_data;
 	INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
-	spin_lock_init(&pctldev->pin_desc_tree_lock);
 	INIT_LIST_HEAD(&pctldev->gpio_ranges);
-	mutex_init(&pctldev->gpio_ranges_lock);
 	pctldev->dev = dev;
 
 	/* If we're implementing pinmuxing, check the ops for sanity */
@@ -628,11 +1287,23 @@
 		goto out_err;
 	}
 
+	mutex_lock(&pinctrl_mutex);
+
+	list_add_tail(&pctldev->node, &pinctrldev_list);
+
+	pctldev->p = pinctrl_get_locked(pctldev->dev);
+	if (!IS_ERR(pctldev->p)) {
+		struct pinctrl_state *s =
+			pinctrl_lookup_state_locked(pctldev->p,
+						    PINCTRL_STATE_DEFAULT);
+		if (!IS_ERR(s))
+			pinctrl_select_state_locked(pctldev->p, s);
+	}
+
+	mutex_unlock(&pinctrl_mutex);
+
 	pinctrl_init_device_debugfs(pctldev);
-	mutex_lock(&pinctrldev_list_mutex);
-	list_add(&pctldev->node, &pinctrldev_list);
-	mutex_unlock(&pinctrldev_list_mutex);
-	pinmux_hog_maps(pctldev);
+
 	return pctldev;
 
 out_err:
@@ -653,15 +1324,20 @@
 		return;
 
 	pinctrl_remove_device_debugfs(pctldev);
-	pinmux_unhog_maps(pctldev);
+
+	mutex_lock(&pinctrl_mutex);
+
+	if (!IS_ERR(pctldev->p))
+		pinctrl_put_locked(pctldev->p, true);
+
 	/* TODO: check that no pinmuxes are still active? */
-	mutex_lock(&pinctrldev_list_mutex);
 	list_del(&pctldev->node);
-	mutex_unlock(&pinctrldev_list_mutex);
 	/* Destroy descriptor tree */
 	pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
 			      pctldev->desc->npins);
 	kfree(pctldev);
+
+	mutex_unlock(&pinctrl_mutex);
 }
 EXPORT_SYMBOL_GPL(pinctrl_unregister);
 
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
index cfa86da..17ecf65 100644
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -9,7 +9,10 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#include <linux/mutex.h>
+#include <linux/radix-tree.h>
 #include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/machine.h>
 
 struct pinctrl_gpio_range;
 
@@ -20,34 +23,94 @@
  *	controller
  * @pin_desc_tree: each pin descriptor for this pin controller is stored in
  *	this radix tree
- * @pin_desc_tree_lock: lock for the descriptor tree
  * @gpio_ranges: a list of GPIO ranges that is handled by this pin controller,
  *	ranges are added to this list at runtime
- * @gpio_ranges_lock: lock for the GPIO ranges list
  * @dev: the device entry for this pin controller
  * @owner: module providing the pin controller, used for refcounting
  * @driver_data: driver data for drivers registering to the pin controller
  *	subsystem
- * @pinmux_hogs_lock: lock for the pinmux hog list
- * @pinmux_hogs: list of pinmux maps hogged by this device
+ * @p: result of pinctrl_get() for this device
+ * @device_root: debugfs root for this device
  */
 struct pinctrl_dev {
 	struct list_head node;
 	struct pinctrl_desc *desc;
 	struct radix_tree_root pin_desc_tree;
-	spinlock_t pin_desc_tree_lock;
 	struct list_head gpio_ranges;
-	struct mutex gpio_ranges_lock;
 	struct device *dev;
 	struct module *owner;
 	void *driver_data;
+	struct pinctrl *p;
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *device_root;
 #endif
-#ifdef CONFIG_PINMUX
-	struct mutex pinmux_hogs_lock;
-	struct list_head pinmux_hogs;
-#endif
+};
+
+/**
+ * struct pinctrl - per-device pin control state holder
+ * @node: global list node
+ * @dev: the device using this pin control handle
+ * @states: a list of states for this device
+ * @state: the current state
+ */
+struct pinctrl {
+	struct list_head node;
+	struct device *dev;
+	struct list_head states;
+	struct pinctrl_state *state;
+};
+
+/**
+ * struct pinctrl_state - a pinctrl state for a device
+ * @node: list not for struct pinctrl's @states field
+ * @name: the name of this state
+ * @settings: a list of settings for this state
+ */
+struct pinctrl_state {
+	struct list_head node;
+	const char *name;
+	struct list_head settings;
+};
+
+/**
+ * struct pinctrl_setting_mux - setting data for MAP_TYPE_MUX_GROUP
+ * @group: the group selector to program
+ * @func: the function selector to program
+ */
+struct pinctrl_setting_mux {
+	unsigned group;
+	unsigned func;
+};
+
+/**
+ * struct pinctrl_setting_configs - setting data for MAP_TYPE_CONFIGS_*
+ * @group_or_pin: the group selector or pin ID to program
+ * @configs: a pointer to an array of config parameters/values to program into
+ *	hardware. Each individual pin controller defines the format and meaning
+ *	of config parameters.
+ * @num_configs: the number of entries in array @configs
+ */
+struct pinctrl_setting_configs {
+	unsigned group_or_pin;
+	unsigned long *configs;
+	unsigned num_configs;
+};
+
+/**
+ * struct pinctrl_setting - an individual mux or config setting
+ * @node: list node for struct pinctrl_settings's @settings field
+ * @type: the type of setting
+ * @pctldev: pin control device handling to be programmed
+ * @data: Data specific to the setting type
+ */
+struct pinctrl_setting {
+	struct list_head node;
+	enum pinctrl_map_type type;
+	struct pinctrl_dev *pctldev;
+	union {
+		struct pinctrl_setting_mux mux;
+		struct pinctrl_setting_configs configs;
+	} data;
 };
 
 /**
@@ -56,28 +119,38 @@
  * @name: a name for the pin, e.g. the name of the pin/pad/finger on a
  *	datasheet or such
  * @dynamic_name: if the name of this pin was dynamically allocated
- * @lock: a lock to protect the descriptor structure
- * @mux_requested: whether the pin is already requested by pinmux or not
- * @mux_function: a named muxing function for the pin that will be passed to
- *	subdrivers and shown in debugfs etc
+ * @mux_usecount: If zero, the pin is not claimed, and @owner should be NULL.
+ *	If non-zero, this pin is claimed by @owner. This field is an integer
+ *	rather than a boolean, since pinctrl_get() might process multiple
+ *	mapping table entries that refer to, and hence claim, the same group
+ *	or pin, and each of these will increment the @usecount.
+ * @mux_owner: The name of device that called pinctrl_get().
+ * @mux_setting: The most recent selected mux setting for this pin, if any.
+ * @gpio_owner: If pinctrl_request_gpio() was called for this pin, this is
+ *	the name of the GPIO that "owns" this pin.
  */
 struct pin_desc {
 	struct pinctrl_dev *pctldev;
 	const char *name;
 	bool dynamic_name;
-	spinlock_t lock;
 	/* These fields only added when supporting pinmux drivers */
 #ifdef CONFIG_PINMUX
-	const char *mux_function;
+	unsigned mux_usecount;
+	const char *mux_owner;
+	const struct pinctrl_setting_mux *mux_setting;
+	const char *gpio_owner;
 #endif
 };
 
-struct pinctrl_dev *get_pinctrl_dev_from_dev(struct device *dev,
-					     const char *dev_name);
-struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev, unsigned int pin);
+struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
 int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
-int pinctrl_get_device_gpio_range(unsigned gpio,
-				  struct pinctrl_dev **outdev,
-				  struct pinctrl_gpio_range **outrange);
 int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
 			       const char *pin_group);
+
+static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev,
+					    unsigned int pin)
+{
+	return radix_tree_lookup(&pctldev->pin_desc_tree, pin);
+}
+
+extern struct mutex pinctrl_mutex;
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
new file mode 100644
index 0000000..33fbaea
--- /dev/null
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -0,0 +1,120 @@
+/*
+ * Core driver for the generic pin config portions of the pin control subsystem
+ *
+ * Copyright (C) 2011 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#define pr_fmt(fmt) "generic pinconfig core: " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include "core.h"
+#include "pinconf.h"
+
+#ifdef CONFIG_DEBUG_FS
+
+struct pin_config_item {
+	const enum pin_config_param param;
+	const char * const display;
+	const char * const format;
+};
+
+#define PCONFDUMP(a, b, c) { .param = a, .display = b, .format = c }
+
+struct pin_config_item conf_items[] = {
+	PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL),
+	PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL),
+	PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL),
+	PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", NULL),
+	PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL),
+	PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL),
+	PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL),
+	PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL),
+	PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "time units"),
+	PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"),
+	PCONFDUMP(PIN_CONFIG_LOW_POWER_MODE, "pin low power", "mode"),
+};
+
+void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
+			      struct seq_file *s, unsigned pin)
+{
+	const struct pinconf_ops *ops = pctldev->desc->confops;
+	int i;
+
+	if (!ops->is_generic)
+		return;
+
+	for(i = 0; i < ARRAY_SIZE(conf_items); i++) {
+		unsigned long config;
+		int ret;
+
+		/* We want to check out this parameter */
+		config = pinconf_to_config_packed(conf_items[i].param, 0);
+		ret = pin_config_get_for_pin(pctldev, pin, &config);
+		/* These are legal errors */
+		if (ret == -EINVAL || ret == -ENOTSUPP)
+			continue;
+		if (ret) {
+			seq_printf(s, "ERROR READING CONFIG SETTING %d ", i);
+			continue;
+		}
+		/* Space between multiple configs */
+		seq_puts(s, " ");
+		seq_puts(s, conf_items[i].display);
+		/* Print unit if available */
+		if (conf_items[i].format &&
+		    pinconf_to_config_argument(config) != 0)
+			seq_printf(s, " (%u %s)",
+				   pinconf_to_config_argument(config),
+				   conf_items[i].format);
+	}
+}
+
+void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
+			      struct seq_file *s, const char *gname)
+{
+	const struct pinconf_ops *ops = pctldev->desc->confops;
+	int i;
+
+	if (!ops->is_generic)
+		return;
+
+	for(i = 0; i < ARRAY_SIZE(conf_items); i++) {
+		unsigned long config;
+		int ret;
+
+		/* We want to check out this parameter */
+		config = pinconf_to_config_packed(conf_items[i].param, 0);
+		ret = pin_config_group_get(dev_name(pctldev->dev), gname,
+					   &config);
+		/* These are legal errors */
+		if (ret == -EINVAL || ret == -ENOTSUPP)
+			continue;
+		if (ret) {
+			seq_printf(s, "ERROR READING CONFIG SETTING %d ", i);
+			continue;
+		}
+		/* Space between multiple configs */
+		seq_puts(s, " ");
+		seq_puts(s, conf_items[i].display);
+		/* Print unit if available */
+		if (conf_items[i].format && config != 0)
+			seq_printf(s, " (%u %s)",
+				   pinconf_to_config_argument(config),
+				   conf_items[i].format);
+	}
+}
+
+#endif
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
index 9fb7545..7321e86 100644
--- a/drivers/pinctrl/pinconf.c
+++ b/drivers/pinctrl/pinconf.c
@@ -23,6 +23,37 @@
 #include "core.h"
 #include "pinconf.h"
 
+int pinconf_check_ops(struct pinctrl_dev *pctldev)
+{
+	const struct pinconf_ops *ops = pctldev->desc->confops;
+
+	/* We must be able to read out pin status */
+	if (!ops->pin_config_get && !ops->pin_config_group_get)
+		return -EINVAL;
+	/* We have to be able to config the pins in SOME way */
+	if (!ops->pin_config_set && !ops->pin_config_group_set)
+		return -EINVAL;
+	return 0;
+}
+
+int pinconf_validate_map(struct pinctrl_map const *map, int i)
+{
+	if (!map->data.configs.group_or_pin) {
+		pr_err("failed to register map %s (%d): no group/pin given\n",
+		       map->name, i);
+		return -EINVAL;
+	}
+
+	if (map->data.configs.num_configs &&
+			!map->data.configs.configs) {
+		pr_err("failed to register map %s (%d): no configs ptr given\n",
+		       map->name, i);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
 			   unsigned long *config)
 {
@@ -51,19 +82,27 @@
 	struct pinctrl_dev *pctldev;
 	int pin;
 
-	pctldev = get_pinctrl_dev_from_dev(NULL, dev_name);
-	if (!pctldev)
-		return -EINVAL;
+	mutex_lock(&pinctrl_mutex);
+
+	pctldev = get_pinctrl_dev_from_devname(dev_name);
+	if (!pctldev) {
+		pin = -EINVAL;
+		goto unlock;
+	}
 
 	pin = pin_get_from_name(pctldev, name);
 	if (pin < 0)
-		return pin;
+		goto unlock;
 
-	return pin_config_get_for_pin(pctldev, pin, config);
+	pin = pin_config_get_for_pin(pctldev, pin, config);
+
+unlock:
+	mutex_unlock(&pinctrl_mutex);
+	return pin;
 }
 EXPORT_SYMBOL(pin_config_get);
 
-int pin_config_set_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
+static int pin_config_set_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
 			   unsigned long config)
 {
 	const struct pinconf_ops *ops = pctldev->desc->confops;
@@ -97,17 +136,27 @@
 		   unsigned long config)
 {
 	struct pinctrl_dev *pctldev;
-	int pin;
+	int pin, ret;
 
-	pctldev = get_pinctrl_dev_from_dev(NULL, dev_name);
-	if (!pctldev)
-		return -EINVAL;
+	mutex_lock(&pinctrl_mutex);
+
+	pctldev = get_pinctrl_dev_from_devname(dev_name);
+	if (!pctldev) {
+		ret = -EINVAL;
+		goto unlock;
+	}
 
 	pin = pin_get_from_name(pctldev, name);
-	if (pin < 0)
-		return pin;
+	if (pin < 0) {
+		ret = pin;
+		goto unlock;
+	}
 
-	return pin_config_set_for_pin(pctldev, pin, config);
+	ret = pin_config_set_for_pin(pctldev, pin, config);
+
+unlock:
+	mutex_unlock(&pinctrl_mutex);
+	return ret;
 }
 EXPORT_SYMBOL(pin_config_set);
 
@@ -116,29 +165,39 @@
 {
 	struct pinctrl_dev *pctldev;
 	const struct pinconf_ops *ops;
-	int selector;
+	int selector, ret;
 
-	pctldev = get_pinctrl_dev_from_dev(NULL, dev_name);
-	if (!pctldev)
-		return -EINVAL;
+	mutex_lock(&pinctrl_mutex);
+
+	pctldev = get_pinctrl_dev_from_devname(dev_name);
+	if (!pctldev) {
+		ret = -EINVAL;
+		goto unlock;
+	}
 	ops = pctldev->desc->confops;
 
 	if (!ops || !ops->pin_config_group_get) {
 		dev_err(pctldev->dev, "cannot get configuration for pin "
 			"group, missing group config get function in "
 			"driver\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto unlock;
 	}
 
 	selector = pinctrl_get_group_selector(pctldev, pin_group);
-	if (selector < 0)
-		return selector;
+	if (selector < 0) {
+		ret = selector;
+		goto unlock;
+	}
 
-	return ops->pin_config_group_get(pctldev, selector, config);
+	ret = ops->pin_config_group_get(pctldev, selector, config);
+
+unlock:
+	mutex_unlock(&pinctrl_mutex);
+	return ret;
 }
 EXPORT_SYMBOL(pin_config_group_get);
 
-
 int pin_config_group_set(const char *dev_name, const char *pin_group,
 			 unsigned long config)
 {
@@ -151,27 +210,34 @@
 	int ret;
 	int i;
 
-	pctldev = get_pinctrl_dev_from_dev(NULL, dev_name);
-	if (!pctldev)
-		return -EINVAL;
+	mutex_lock(&pinctrl_mutex);
+
+	pctldev = get_pinctrl_dev_from_devname(dev_name);
+	if (!pctldev) {
+		ret = -EINVAL;
+		goto unlock;
+	}
 	ops = pctldev->desc->confops;
 	pctlops = pctldev->desc->pctlops;
 
 	if (!ops || (!ops->pin_config_group_set && !ops->pin_config_set)) {
 		dev_err(pctldev->dev, "cannot configure pin group, missing "
 			"config function in driver\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto unlock;
 	}
 
 	selector = pinctrl_get_group_selector(pctldev, pin_group);
-	if (selector < 0)
-		return selector;
+	if (selector < 0) {
+		ret = selector;
+		goto unlock;
+	}
 
 	ret = pctlops->get_group_pins(pctldev, selector, &pins, &num_pins);
 	if (ret) {
 		dev_err(pctldev->dev, "cannot configure pin group, error "
 			"getting pins\n");
-		return ret;
+		goto unlock;
 	}
 
 	/*
@@ -185,46 +251,196 @@
 		 * pin-by-pin as well, it returns -EAGAIN.
 		 */
 		if (ret != -EAGAIN)
-			return ret;
+			goto unlock;
 	}
 
 	/*
 	 * If the controller cannot handle entire groups, we configure each pin
 	 * individually.
 	 */
-	if (!ops->pin_config_set)
-		return 0;
+	if (!ops->pin_config_set) {
+		ret = 0;
+		goto unlock;
+	}
 
 	for (i = 0; i < num_pins; i++) {
 		ret = ops->pin_config_set(pctldev, pins[i], config);
 		if (ret < 0)
-			return ret;
+			goto unlock;
+	}
+
+	ret = 0;
+
+unlock:
+	mutex_unlock(&pinctrl_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(pin_config_group_set);
+
+int pinconf_map_to_setting(struct pinctrl_map const *map,
+			  struct pinctrl_setting *setting)
+{
+	struct pinctrl_dev *pctldev = setting->pctldev;
+	int pin;
+
+	switch (setting->type) {
+	case PIN_MAP_TYPE_CONFIGS_PIN:
+		pin = pin_get_from_name(pctldev,
+					map->data.configs.group_or_pin);
+		if (pin < 0) {
+			dev_err(pctldev->dev, "could not map pin config for \"%s\"",
+				map->data.configs.group_or_pin);
+			return pin;
+		}
+		setting->data.configs.group_or_pin = pin;
+		break;
+	case PIN_MAP_TYPE_CONFIGS_GROUP:
+		pin = pinctrl_get_group_selector(pctldev,
+					 map->data.configs.group_or_pin);
+		if (pin < 0) {
+			dev_err(pctldev->dev, "could not map group config for \"%s\"",
+				map->data.configs.group_or_pin);
+			return pin;
+		}
+		setting->data.configs.group_or_pin = pin;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	setting->data.configs.num_configs = map->data.configs.num_configs;
+	setting->data.configs.configs = map->data.configs.configs;
+
+	return 0;
+}
+
+void pinconf_free_setting(struct pinctrl_setting const *setting)
+{
+}
+
+int pinconf_apply_setting(struct pinctrl_setting const *setting)
+{
+	struct pinctrl_dev *pctldev = setting->pctldev;
+	const struct pinconf_ops *ops = pctldev->desc->confops;
+	int i, ret;
+
+	if (!ops) {
+		dev_err(pctldev->dev, "missing confops\n");
+		return -EINVAL;
+	}
+
+	switch (setting->type) {
+	case PIN_MAP_TYPE_CONFIGS_PIN:
+		if (!ops->pin_config_set) {
+			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;
+			}
+		}
+		break;
+	case PIN_MAP_TYPE_CONFIGS_GROUP:
+		if (!ops->pin_config_group_set) {
+			dev_err(pctldev->dev,
+				"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;
+			}
+		}
+		break;
+	default:
+		return -EINVAL;
 	}
 
 	return 0;
 }
-EXPORT_SYMBOL(pin_config_group_set);
-
-int pinconf_check_ops(struct pinctrl_dev *pctldev)
-{
-	const struct pinconf_ops *ops = pctldev->desc->confops;
-
-	/* We must be able to read out pin status */
-	if (!ops->pin_config_get && !ops->pin_config_group_get)
-		return -EINVAL;
-	/* We have to be able to config the pins in SOME way */
-	if (!ops->pin_config_set && !ops->pin_config_group_set)
-		return -EINVAL;
-	return 0;
-}
 
 #ifdef CONFIG_DEBUG_FS
 
+void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map)
+{
+	int i;
+
+	switch (map->type) {
+	case PIN_MAP_TYPE_CONFIGS_PIN:
+		seq_printf(s, "pin ");
+		break;
+	case PIN_MAP_TYPE_CONFIGS_GROUP:
+		seq_printf(s, "group ");
+		break;
+	default:
+		break;
+	}
+
+	seq_printf(s, "%s\n", map->data.configs.group_or_pin);
+
+	for (i = 0; i < map->data.configs.num_configs; i++)
+		seq_printf(s, "config %08lx\n", map->data.configs.configs[i]);
+}
+
+void pinconf_show_setting(struct seq_file *s,
+			  struct pinctrl_setting const *setting)
+{
+	struct pinctrl_dev *pctldev = setting->pctldev;
+	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
+	struct pin_desc *desc;
+	int i;
+
+	switch (setting->type) {
+	case PIN_MAP_TYPE_CONFIGS_PIN:
+		desc = pin_desc_get(setting->pctldev,
+				    setting->data.configs.group_or_pin);
+		seq_printf(s, "pin %s (%d)",
+			   desc->name ? desc->name : "unnamed",
+			   setting->data.configs.group_or_pin);
+		break;
+	case PIN_MAP_TYPE_CONFIGS_GROUP:
+		seq_printf(s, "group %s (%d)",
+			   pctlops->get_group_name(pctldev,
+					setting->data.configs.group_or_pin),
+			   setting->data.configs.group_or_pin);
+		break;
+	default:
+		break;
+	}
+
+	/*
+	 * FIXME: We should really get the pin controler to dump the config
+	 * values, so they can be decoded to something meaningful.
+	 */
+	for (i = 0; i < setting->data.configs.num_configs; i++)
+		seq_printf(s, " %08lx", setting->data.configs.configs[i]);
+
+	seq_printf(s, "\n");
+}
+
 static void pinconf_dump_pin(struct pinctrl_dev *pctldev,
 			     struct seq_file *s, int pin)
 {
 	const struct pinconf_ops *ops = pctldev->desc->confops;
 
+	/* no-op when not using generic pin config */
+	pinconf_generic_dump_pin(pctldev, s, pin);
 	if (ops && ops->pin_config_dbg_show)
 		ops->pin_config_dbg_show(pctldev, s, pin);
 }
@@ -237,6 +453,8 @@
 	seq_puts(s, "Pin config settings per pin\n");
 	seq_puts(s, "Format: pin (name): pinmux setting array\n");
 
+	mutex_lock(&pinctrl_mutex);
+
 	/* The pin number can be retrived from the pin controller descriptor */
 	for (i = 0; i < pctldev->desc->npins; i++) {
 		struct pin_desc *desc;
@@ -255,6 +473,8 @@
 		seq_printf(s, "\n");
 	}
 
+	mutex_unlock(&pinctrl_mutex);
+
 	return 0;
 }
 
@@ -264,6 +484,8 @@
 {
 	const struct pinconf_ops *ops = pctldev->desc->confops;
 
+	/* no-op when not using generic pin config */
+	pinconf_generic_dump_group(pctldev, s, gname);
 	if (ops && ops->pin_config_group_dbg_show)
 		ops->pin_config_group_dbg_show(pctldev, s, selector);
 }
@@ -281,14 +503,20 @@
 	seq_puts(s, "Pin config settings per pin group\n");
 	seq_puts(s, "Format: group (name): pinmux setting array\n");
 
+	mutex_lock(&pinctrl_mutex);
+
 	while (pctlops->list_groups(pctldev, selector) >= 0) {
 		const char *gname = pctlops->get_group_name(pctldev, selector);
 
 		seq_printf(s, "%u (%s):", selector, gname);
 		pinconf_dump_group(pctldev, s, selector, gname);
+		seq_printf(s, "\n");
+
 		selector++;
 	}
 
+	mutex_unlock(&pinctrl_mutex);
+
 	return 0;
 }
 
diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h
index 006b77f..54510de 100644
--- a/drivers/pinctrl/pinconf.h
+++ b/drivers/pinctrl/pinconf.h
@@ -14,12 +14,25 @@
 #ifdef CONFIG_PINCONF
 
 int pinconf_check_ops(struct pinctrl_dev *pctldev);
+int pinconf_validate_map(struct pinctrl_map const *map, int i);
+int pinconf_map_to_setting(struct pinctrl_map const *map,
+			  struct pinctrl_setting *setting);
+void pinconf_free_setting(struct pinctrl_setting const *setting);
+int pinconf_apply_setting(struct pinctrl_setting const *setting);
+void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map);
+void pinconf_show_setting(struct seq_file *s,
+			  struct pinctrl_setting const *setting);
 void pinconf_init_device_debugfs(struct dentry *devroot,
 				 struct pinctrl_dev *pctldev);
+
+/*
+ * You will only be interested in these if you're using PINCONF
+ * so don't supply any stubs for these.
+ */
 int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
 			   unsigned long *config);
-int pin_config_set_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
-			   unsigned long config);
+int pin_config_group_get(const char *dev_name, const char *pin_group,
+			 unsigned long *config);
 
 #else
 
@@ -28,9 +41,70 @@
 	return 0;
 }
 
+static inline int pinconf_validate_map(struct pinctrl_map const *map, int i)
+{
+	return 0;
+}
+
+static inline int pinconf_map_to_setting(struct pinctrl_map const *map,
+			  struct pinctrl_setting *setting)
+{
+	return 0;
+}
+
+static inline void pinconf_free_setting(struct pinctrl_setting const *setting)
+{
+}
+
+static inline int pinconf_apply_setting(struct pinctrl_setting const *setting)
+{
+	return 0;
+}
+
+static inline void pinconf_show_map(struct seq_file *s,
+				    struct pinctrl_map const *map)
+{
+}
+
+static inline void pinconf_show_setting(struct seq_file *s,
+			  struct pinctrl_setting const *setting)
+{
+}
+
 static inline void pinconf_init_device_debugfs(struct dentry *devroot,
 					       struct pinctrl_dev *pctldev)
 {
 }
 
 #endif
+
+/*
+ * The following functions are available if the driver uses the generic
+ * pin config.
+ */
+
+#ifdef CONFIG_GENERIC_PINCONF
+
+void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
+			      struct seq_file *s, unsigned pin);
+
+void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
+			      struct seq_file *s, const char *gname);
+
+#else
+
+static inline void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
+					    struct seq_file *s,
+					    unsigned pin)
+{
+	return;
+}
+
+static inline void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
+					      struct seq_file *s,
+					      const char *gname)
+{
+	return;
+}
+
+#endif
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c
index 69fb707..0797eba 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -22,38 +22,10 @@
 #include <linux/gpio.h>
 #include <linux/list.h>
 #include <linux/slab.h>
-#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinconf-generic.h>
 #include <mach/gpio-u300.h>
-
-/*
- * Bias modes for U300 GPIOs
- *
- * GPIO_U300_CONFIG_BIAS_UNKNOWN: this bias mode is not known to us
- * GPIO_U300_CONFIG_BIAS_FLOAT: no specific bias, the GPIO will float or state
- *	is not controlled by software
- * GPIO_U300_CONFIG_BIAS_PULL_UP: the GPIO will be pulled up (usually with high
- *	impedance to VDD)
- */
-#define GPIO_U300_CONFIG_BIAS_UNKNOWN	0x1000
-#define GPIO_U300_CONFIG_BIAS_FLOAT	0x1001
-#define GPIO_U300_CONFIG_BIAS_PULL_UP	0x1002
-
-/*
- * Drive modes for U300 GPIOs (output)
- *
- * GPIO_U300_CONFIG_DRIVE_PUSH_PULL: the GPIO will be driven actively high and
- *	low, this is the most typical case and is typically achieved with two
- *	active transistors on the output
- * GPIO_U300_CONFIG_DRIVE_OPEN_DRAIN: the GPIO will be driven with open drain
- *	(open collector) which means it is usually wired with other output
- *	ports which are then pulled up with an external resistor
- * GPIO_U300_CONFIG_DRIVE_OPEN_SOURCE: the GPIO will be driven with open drain
- *	(open emitter) which is the same as open drain mutatis mutandis but
- *	pulled to ground
- */
-#define GPIO_U300_CONFIG_DRIVE_PUSH_PULL	0x2000
-#define GPIO_U300_CONFIG_DRIVE_OPEN_DRAIN	0x2001
-#define GPIO_U300_CONFIG_DRIVE_OPEN_SOURCE	0x2002
+#include "pinctrl-coh901.h"
 
 /*
  * Register definitions for COH 901 335 variant
@@ -181,12 +153,12 @@
 #define BS365_GPIO_NUM_PORTS 5
 
 #define U300_FLOATING_INPUT { \
-	.bias_mode = GPIO_U300_CONFIG_BIAS_FLOAT, \
+	.bias_mode = PIN_CONFIG_BIAS_HIGH_IMPEDANCE, \
 	.output = false, \
 }
 
 #define U300_PULL_UP_INPUT { \
-	.bias_mode = GPIO_U300_CONFIG_BIAS_PULL_UP, \
+	.bias_mode = PIN_CONFIG_BIAS_PULL_UP, \
 	.output = false, \
 }
 
@@ -360,14 +332,14 @@
 	 */
 	int gpio = chip->base + offset;
 
-	return pinmux_request_gpio(gpio);
+	return pinctrl_request_gpio(gpio);
 }
 
 static void u300_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
 	int gpio = chip->base + offset;
 
-	pinmux_free_gpio(gpio);
+	pinctrl_free_gpio(gpio);
 }
 
 static int u300_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -448,8 +420,68 @@
 	return retirq;
 }
 
-static int u300_gpio_config(struct gpio_chip *chip, unsigned offset,
-		     u16 param, unsigned long *data)
+/* Returning -EINVAL means "supported but not available" */
+int u300_gpio_config_get(struct gpio_chip *chip,
+			 unsigned offset,
+			 unsigned long *config)
+{
+	struct u300_gpio *gpio = to_u300_gpio(chip);
+	enum pin_config_param param = (enum pin_config_param) *config;
+	bool biasmode;
+	u32 drmode;
+
+	/* One bit per pin, clamp to bool range */
+	biasmode = !!(readl(U300_PIN_REG(offset, per)) & U300_PIN_BIT(offset));
+
+	/* Mask out the two bits for this pin and shift to bits 0,1 */
+	drmode = readl(U300_PIN_REG(offset, pcr));
+	drmode &= (U300_GPIO_PXPCR_PIN_MODE_MASK << ((offset & 0x07) << 1));
+	drmode >>= ((offset & 0x07) << 1);
+
+	switch(param) {
+	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+		*config = 0;
+		if (biasmode)
+			return 0;
+		else
+			return -EINVAL;
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		*config = 0;
+		if (!biasmode)
+			return 0;
+		else
+			return -EINVAL;
+		break;
+	case PIN_CONFIG_DRIVE_PUSH_PULL:
+		*config = 0;
+		if (drmode == U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL)
+			return 0;
+		else
+			return -EINVAL;
+		break;
+	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+		*config = 0;
+		if (drmode == U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN)
+			return 0;
+		else
+			return -EINVAL;
+		break;
+	case PIN_CONFIG_DRIVE_OPEN_SOURCE:
+		*config = 0;
+		if (drmode == U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE)
+			return 0;
+		else
+			return -EINVAL;
+		break;
+	default:
+		break;
+	}
+	return -ENOTSUPP;
+}
+
+int u300_gpio_config_set(struct gpio_chip *chip, unsigned offset,
+			 enum pin_config_param param)
 {
 	struct u300_gpio *gpio = to_u300_gpio(chip);
 	unsigned long flags;
@@ -457,16 +489,16 @@
 
 	local_irq_save(flags);
 	switch (param) {
-	case GPIO_U300_CONFIG_BIAS_UNKNOWN:
-	case GPIO_U300_CONFIG_BIAS_FLOAT:
+	case PIN_CONFIG_BIAS_DISABLE:
+	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
 		val = readl(U300_PIN_REG(offset, per));
 		writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, per));
 		break;
-	case GPIO_U300_CONFIG_BIAS_PULL_UP:
+	case PIN_CONFIG_BIAS_PULL_UP:
 		val = readl(U300_PIN_REG(offset, per));
 		writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, per));
 		break;
-	case GPIO_U300_CONFIG_DRIVE_PUSH_PULL:
+	case PIN_CONFIG_DRIVE_PUSH_PULL:
 		val = readl(U300_PIN_REG(offset, pcr));
 		val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK
 			 << ((offset & 0x07) << 1));
@@ -474,7 +506,7 @@
 			<< ((offset & 0x07) << 1));
 		writel(val, U300_PIN_REG(offset, pcr));
 		break;
-	case GPIO_U300_CONFIG_DRIVE_OPEN_DRAIN:
+	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
 		val = readl(U300_PIN_REG(offset, pcr));
 		val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK
 			 << ((offset & 0x07) << 1));
@@ -482,7 +514,7 @@
 			<< ((offset & 0x07) << 1));
 		writel(val, U300_PIN_REG(offset, pcr));
 		break;
-	case GPIO_U300_CONFIG_DRIVE_OPEN_SOURCE:
+	case PIN_CONFIG_DRIVE_OPEN_SOURCE:
 		val = readl(U300_PIN_REG(offset, pcr));
 		val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK
 			 << ((offset & 0x07) << 1));
@@ -650,13 +682,12 @@
 		u300_gpio_direction_output(&gpio->chip, offset, conf->outval);
 
 		/* Deactivate bias mode for output */
-		u300_gpio_config(&gpio->chip, offset,
-				 GPIO_U300_CONFIG_BIAS_FLOAT,
-				 NULL);
+		u300_gpio_config_set(&gpio->chip, offset,
+				     PIN_CONFIG_BIAS_HIGH_IMPEDANCE);
 
 		/* Set drive mode for output */
-		u300_gpio_config(&gpio->chip, offset,
-				 GPIO_U300_CONFIG_DRIVE_PUSH_PULL, NULL);
+		u300_gpio_config_set(&gpio->chip, offset,
+				     PIN_CONFIG_DRIVE_PUSH_PULL);
 
 		dev_dbg(gpio->dev, "set up pin %d as output, value: %d\n",
 			offset, conf->outval);
@@ -667,7 +698,7 @@
 		u300_gpio_set(&gpio->chip, offset, 0);
 
 		/* Set bias mode for input */
-		u300_gpio_config(&gpio->chip, offset, conf->bias_mode, NULL);
+		u300_gpio_config_set(&gpio->chip, offset, conf->bias_mode);
 
 		dev_dbg(gpio->dev, "set up pin %d as input, bias: %04x\n",
 			offset, conf->bias_mode);
@@ -705,7 +736,6 @@
 	list_for_each_safe(p, n, &gpio->port_list) {
 		port = list_entry(p, struct u300_gpio_port, node);
 		list_del(&port->node);
-		free_irq(port->irq, port);
 		kfree(port);
 	}
 }
@@ -861,10 +891,18 @@
 		goto err_no_chip;
 	}
 
+	/* Spawn pin controller device as child of the GPIO, pass gpio chip */
+	plat->pinctrl_device->dev.platform_data = &gpio->chip;
+	err = platform_device_register(plat->pinctrl_device);
+	if (err)
+		goto err_no_pinctrl;
+
 	platform_set_drvdata(pdev, gpio);
 
 	return 0;
 
+err_no_pinctrl:
+	err = gpiochip_remove(&gpio->chip);
 err_no_chip:
 err_no_port:
 	u300_gpio_free_ports(gpio);
@@ -919,7 +957,6 @@
 	.remove		= __exit_p(u300_gpio_remove),
 };
 
-
 static int __init u300_gpio_init(void)
 {
 	return platform_driver_probe(&u300_gpio_driver, u300_gpio_probe);
diff --git a/drivers/pinctrl/pinctrl-coh901.h b/drivers/pinctrl/pinctrl-coh901.h
new file mode 100644
index 0000000..8729422
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-coh901.h
@@ -0,0 +1,5 @@
+int u300_gpio_config_get(struct gpio_chip *chip,
+			 unsigned offset,
+			 unsigned long *config);
+int u300_gpio_config_set(struct gpio_chip *chip, unsigned offset,
+			 enum pin_config_param param);
diff --git a/drivers/pinctrl/pinctrl-mmp2.c b/drivers/pinctrl/pinctrl-mmp2.c
new file mode 100644
index 0000000..2cfed55
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-mmp2.c
@@ -0,0 +1,722 @@
+/*
+ *  linux/drivers/pinctrl/pinmux-mmp2.c
+ *
+ *  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
+ *  publishhed by the Free Software Foundation.
+ *
+ *  Copyright (C) 2011, Marvell Technology Group Ltd.
+ *
+ *  Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include "pinctrl-pxa3xx.h"
+
+#define MMP2_DS_MASK		0x1800
+#define MMP2_DS_SHIFT		11
+#define MMP2_SLEEP_MASK		0x38
+#define MMP2_SLEEP_SELECT	(1 << 9)
+#define MMP2_SLEEP_DATA		(1 << 8)
+#define MMP2_SLEEP_DIR		(1 << 7)
+
+#define MFPR_MMP2(a, r, f0, f1, f2, f3, f4, f5, f6, f7)		\
+	{							\
+		.name = #a,					\
+		.pin = a,					\
+		.mfpr = r,					\
+		.func = {					\
+			MMP2_MUX_##f0,				\
+			MMP2_MUX_##f1,				\
+			MMP2_MUX_##f2,				\
+			MMP2_MUX_##f3,				\
+			MMP2_MUX_##f4,				\
+			MMP2_MUX_##f5,				\
+			MMP2_MUX_##f6,				\
+			MMP2_MUX_##f7,				\
+		},						\
+	}
+
+#define GRP_MMP2(a, m, p)		\
+	{ .name = a, .mux = MMP2_MUX_##m, .pins = p, .npins = ARRAY_SIZE(p), }
+
+/* 174 pins */
+enum mmp2_pin_list {
+	/* 0~168: GPIO0~GPIO168 */
+	TWSI4_SCL = 169,
+	TWSI4_SDA, /* 170 */
+	G_CLKREQ,
+	VCXO_REQ,
+	VCXO_OUT,
+};
+
+enum mmp2_mux {
+	/* PXA3xx_MUX_GPIO = 0 (predefined in pinctrl-pxa3xx.h) */
+	MMP2_MUX_GPIO = 0,
+	MMP2_MUX_G_CLKREQ,
+	MMP2_MUX_VCXO_REQ,
+	MMP2_MUX_VCXO_OUT,
+	MMP2_MUX_KP_MK,
+	MMP2_MUX_KP_DK,
+	MMP2_MUX_CCIC1,
+	MMP2_MUX_CCIC2,
+	MMP2_MUX_SPI,
+	MMP2_MUX_SSPA2,
+	MMP2_MUX_ROT,
+	MMP2_MUX_I2S,
+	MMP2_MUX_TB,
+	MMP2_MUX_CAM2,
+	MMP2_MUX_HDMI,
+	MMP2_MUX_TWSI2,
+	MMP2_MUX_TWSI3,
+	MMP2_MUX_TWSI4,
+	MMP2_MUX_TWSI5,
+	MMP2_MUX_TWSI6,
+	MMP2_MUX_UART1,
+	MMP2_MUX_UART2,
+	MMP2_MUX_UART3,
+	MMP2_MUX_UART4,
+	MMP2_MUX_SSP1_RX,
+	MMP2_MUX_SSP1_FRM,
+	MMP2_MUX_SSP1_TXRX,
+	MMP2_MUX_SSP2_RX,
+	MMP2_MUX_SSP2_FRM,
+	MMP2_MUX_SSP1,
+	MMP2_MUX_SSP2,
+	MMP2_MUX_SSP3,
+	MMP2_MUX_SSP4,
+	MMP2_MUX_MMC1,
+	MMP2_MUX_MMC2,
+	MMP2_MUX_MMC3,
+	MMP2_MUX_MMC4,
+	MMP2_MUX_ULPI,
+	MMP2_MUX_AC,
+	MMP2_MUX_CA,
+	MMP2_MUX_PWM,
+	MMP2_MUX_USIM,
+	MMP2_MUX_TIPU,
+	MMP2_MUX_PLL,
+	MMP2_MUX_NAND,
+	MMP2_MUX_FSIC,
+	MMP2_MUX_SLEEP_IND,
+	MMP2_MUX_EXT_DMA,
+	MMP2_MUX_ONE_WIRE,
+	MMP2_MUX_LCD,
+	MMP2_MUX_SMC,
+	MMP2_MUX_SMC_INT,
+	MMP2_MUX_MSP,
+	MMP2_MUX_G_CLKOUT,
+	MMP2_MUX_32K_CLKOUT,
+	MMP2_MUX_PRI_JTAG,
+	MMP2_MUX_AAS_JTAG,
+	MMP2_MUX_AAS_GPIO,
+	MMP2_MUX_AAS_SPI,
+	MMP2_MUX_AAS_TWSI,
+	MMP2_MUX_AAS_DEU_EX,
+	MMP2_MUX_NONE = 0xffff,
+};
+
+static struct pinctrl_pin_desc mmp2_pads[] = {
+	/*
+	 * The name indicates function 0 of this pin.
+	 * After reset, function 0 is the default function of pin.
+	 */
+	PINCTRL_PIN(GPIO0, "GPIO0"),
+	PINCTRL_PIN(GPIO1, "GPIO1"),
+	PINCTRL_PIN(GPIO2, "GPIO2"),
+	PINCTRL_PIN(GPIO3, "GPIO3"),
+	PINCTRL_PIN(GPIO4, "GPIO4"),
+	PINCTRL_PIN(GPIO5, "GPIO5"),
+	PINCTRL_PIN(GPIO6, "GPIO6"),
+	PINCTRL_PIN(GPIO7, "GPIO7"),
+	PINCTRL_PIN(GPIO8, "GPIO8"),
+	PINCTRL_PIN(GPIO9, "GPIO9"),
+	PINCTRL_PIN(GPIO10, "GPIO10"),
+	PINCTRL_PIN(GPIO11, "GPIO11"),
+	PINCTRL_PIN(GPIO12, "GPIO12"),
+	PINCTRL_PIN(GPIO13, "GPIO13"),
+	PINCTRL_PIN(GPIO14, "GPIO14"),
+	PINCTRL_PIN(GPIO15, "GPIO15"),
+	PINCTRL_PIN(GPIO16, "GPIO16"),
+	PINCTRL_PIN(GPIO17, "GPIO17"),
+	PINCTRL_PIN(GPIO18, "GPIO18"),
+	PINCTRL_PIN(GPIO19, "GPIO19"),
+	PINCTRL_PIN(GPIO20, "GPIO20"),
+	PINCTRL_PIN(GPIO21, "GPIO21"),
+	PINCTRL_PIN(GPIO22, "GPIO22"),
+	PINCTRL_PIN(GPIO23, "GPIO23"),
+	PINCTRL_PIN(GPIO24, "GPIO24"),
+	PINCTRL_PIN(GPIO25, "GPIO25"),
+	PINCTRL_PIN(GPIO26, "GPIO26"),
+	PINCTRL_PIN(GPIO27, "GPIO27"),
+	PINCTRL_PIN(GPIO28, "GPIO28"),
+	PINCTRL_PIN(GPIO29, "GPIO29"),
+	PINCTRL_PIN(GPIO30, "GPIO30"),
+	PINCTRL_PIN(GPIO31, "GPIO31"),
+	PINCTRL_PIN(GPIO32, "GPIO32"),
+	PINCTRL_PIN(GPIO33, "GPIO33"),
+	PINCTRL_PIN(GPIO34, "GPIO34"),
+	PINCTRL_PIN(GPIO35, "GPIO35"),
+	PINCTRL_PIN(GPIO36, "GPIO36"),
+	PINCTRL_PIN(GPIO37, "GPIO37"),
+	PINCTRL_PIN(GPIO38, "GPIO38"),
+	PINCTRL_PIN(GPIO39, "GPIO39"),
+	PINCTRL_PIN(GPIO40, "GPIO40"),
+	PINCTRL_PIN(GPIO41, "GPIO41"),
+	PINCTRL_PIN(GPIO42, "GPIO42"),
+	PINCTRL_PIN(GPIO43, "GPIO43"),
+	PINCTRL_PIN(GPIO44, "GPIO44"),
+	PINCTRL_PIN(GPIO45, "GPIO45"),
+	PINCTRL_PIN(GPIO46, "GPIO46"),
+	PINCTRL_PIN(GPIO47, "GPIO47"),
+	PINCTRL_PIN(GPIO48, "GPIO48"),
+	PINCTRL_PIN(GPIO49, "GPIO49"),
+	PINCTRL_PIN(GPIO50, "GPIO50"),
+	PINCTRL_PIN(GPIO51, "GPIO51"),
+	PINCTRL_PIN(GPIO52, "GPIO52"),
+	PINCTRL_PIN(GPIO53, "GPIO53"),
+	PINCTRL_PIN(GPIO54, "GPIO54"),
+	PINCTRL_PIN(GPIO55, "GPIO55"),
+	PINCTRL_PIN(GPIO56, "GPIO56"),
+	PINCTRL_PIN(GPIO57, "GPIO57"),
+	PINCTRL_PIN(GPIO58, "GPIO58"),
+	PINCTRL_PIN(GPIO59, "GPIO59"),
+	PINCTRL_PIN(GPIO60, "GPIO60"),
+	PINCTRL_PIN(GPIO61, "GPIO61"),
+	PINCTRL_PIN(GPIO62, "GPIO62"),
+	PINCTRL_PIN(GPIO63, "GPIO63"),
+	PINCTRL_PIN(GPIO64, "GPIO64"),
+	PINCTRL_PIN(GPIO65, "GPIO65"),
+	PINCTRL_PIN(GPIO66, "GPIO66"),
+	PINCTRL_PIN(GPIO67, "GPIO67"),
+	PINCTRL_PIN(GPIO68, "GPIO68"),
+	PINCTRL_PIN(GPIO69, "GPIO69"),
+	PINCTRL_PIN(GPIO70, "GPIO70"),
+	PINCTRL_PIN(GPIO71, "GPIO71"),
+	PINCTRL_PIN(GPIO72, "GPIO72"),
+	PINCTRL_PIN(GPIO73, "GPIO73"),
+	PINCTRL_PIN(GPIO74, "GPIO74"),
+	PINCTRL_PIN(GPIO75, "GPIO75"),
+	PINCTRL_PIN(GPIO76, "GPIO76"),
+	PINCTRL_PIN(GPIO77, "GPIO77"),
+	PINCTRL_PIN(GPIO78, "GPIO78"),
+	PINCTRL_PIN(GPIO79, "GPIO79"),
+	PINCTRL_PIN(GPIO80, "GPIO80"),
+	PINCTRL_PIN(GPIO81, "GPIO81"),
+	PINCTRL_PIN(GPIO82, "GPIO82"),
+	PINCTRL_PIN(GPIO83, "GPIO83"),
+	PINCTRL_PIN(GPIO84, "GPIO84"),
+	PINCTRL_PIN(GPIO85, "GPIO85"),
+	PINCTRL_PIN(GPIO86, "GPIO86"),
+	PINCTRL_PIN(GPIO87, "GPIO87"),
+	PINCTRL_PIN(GPIO88, "GPIO88"),
+	PINCTRL_PIN(GPIO89, "GPIO89"),
+	PINCTRL_PIN(GPIO90, "GPIO90"),
+	PINCTRL_PIN(GPIO91, "GPIO91"),
+	PINCTRL_PIN(GPIO92, "GPIO92"),
+	PINCTRL_PIN(GPIO93, "GPIO93"),
+	PINCTRL_PIN(GPIO94, "GPIO94"),
+	PINCTRL_PIN(GPIO95, "GPIO95"),
+	PINCTRL_PIN(GPIO96, "GPIO96"),
+	PINCTRL_PIN(GPIO97, "GPIO97"),
+	PINCTRL_PIN(GPIO98, "GPIO98"),
+	PINCTRL_PIN(GPIO99, "GPIO99"),
+	PINCTRL_PIN(GPIO100, "GPIO100"),
+	PINCTRL_PIN(GPIO101, "GPIO101"),
+	PINCTRL_PIN(GPIO102, "GPIO102"),
+	PINCTRL_PIN(GPIO103, "GPIO103"),
+	PINCTRL_PIN(GPIO104, "GPIO104"),
+	PINCTRL_PIN(GPIO105, "GPIO105"),
+	PINCTRL_PIN(GPIO106, "GPIO106"),
+	PINCTRL_PIN(GPIO107, "GPIO107"),
+	PINCTRL_PIN(GPIO108, "GPIO108"),
+	PINCTRL_PIN(GPIO109, "GPIO109"),
+	PINCTRL_PIN(GPIO110, "GPIO110"),
+	PINCTRL_PIN(GPIO111, "GPIO111"),
+	PINCTRL_PIN(GPIO112, "GPIO112"),
+	PINCTRL_PIN(GPIO113, "GPIO113"),
+	PINCTRL_PIN(GPIO114, "GPIO114"),
+	PINCTRL_PIN(GPIO115, "GPIO115"),
+	PINCTRL_PIN(GPIO116, "GPIO116"),
+	PINCTRL_PIN(GPIO117, "GPIO117"),
+	PINCTRL_PIN(GPIO118, "GPIO118"),
+	PINCTRL_PIN(GPIO119, "GPIO119"),
+	PINCTRL_PIN(GPIO120, "GPIO120"),
+	PINCTRL_PIN(GPIO121, "GPIO121"),
+	PINCTRL_PIN(GPIO122, "GPIO122"),
+	PINCTRL_PIN(GPIO123, "GPIO123"),
+	PINCTRL_PIN(GPIO124, "GPIO124"),
+	PINCTRL_PIN(GPIO125, "GPIO125"),
+	PINCTRL_PIN(GPIO126, "GPIO126"),
+	PINCTRL_PIN(GPIO127, "GPIO127"),
+	PINCTRL_PIN(GPIO128, "GPIO128"),
+	PINCTRL_PIN(GPIO129, "GPIO129"),
+	PINCTRL_PIN(GPIO130, "GPIO130"),
+	PINCTRL_PIN(GPIO131, "GPIO131"),
+	PINCTRL_PIN(GPIO132, "GPIO132"),
+	PINCTRL_PIN(GPIO133, "GPIO133"),
+	PINCTRL_PIN(GPIO134, "GPIO134"),
+	PINCTRL_PIN(GPIO135, "GPIO135"),
+	PINCTRL_PIN(GPIO136, "GPIO136"),
+	PINCTRL_PIN(GPIO137, "GPIO137"),
+	PINCTRL_PIN(GPIO138, "GPIO138"),
+	PINCTRL_PIN(GPIO139, "GPIO139"),
+	PINCTRL_PIN(GPIO140, "GPIO140"),
+	PINCTRL_PIN(GPIO141, "GPIO141"),
+	PINCTRL_PIN(GPIO142, "GPIO142"),
+	PINCTRL_PIN(GPIO143, "GPIO143"),
+	PINCTRL_PIN(GPIO144, "GPIO144"),
+	PINCTRL_PIN(GPIO145, "GPIO145"),
+	PINCTRL_PIN(GPIO146, "GPIO146"),
+	PINCTRL_PIN(GPIO147, "GPIO147"),
+	PINCTRL_PIN(GPIO148, "GPIO148"),
+	PINCTRL_PIN(GPIO149, "GPIO149"),
+	PINCTRL_PIN(GPIO150, "GPIO150"),
+	PINCTRL_PIN(GPIO151, "GPIO151"),
+	PINCTRL_PIN(GPIO152, "GPIO152"),
+	PINCTRL_PIN(GPIO153, "GPIO153"),
+	PINCTRL_PIN(GPIO154, "GPIO154"),
+	PINCTRL_PIN(GPIO155, "GPIO155"),
+	PINCTRL_PIN(GPIO156, "GPIO156"),
+	PINCTRL_PIN(GPIO157, "GPIO157"),
+	PINCTRL_PIN(GPIO158, "GPIO158"),
+	PINCTRL_PIN(GPIO159, "GPIO159"),
+	PINCTRL_PIN(GPIO160, "GPIO160"),
+	PINCTRL_PIN(GPIO161, "GPIO161"),
+	PINCTRL_PIN(GPIO162, "GPIO162"),
+	PINCTRL_PIN(GPIO163, "GPIO163"),
+	PINCTRL_PIN(GPIO164, "GPIO164"),
+	PINCTRL_PIN(GPIO165, "GPIO165"),
+	PINCTRL_PIN(GPIO166, "GPIO166"),
+	PINCTRL_PIN(GPIO167, "GPIO167"),
+	PINCTRL_PIN(GPIO168, "GPIO168"),
+	PINCTRL_PIN(TWSI4_SCL, "TWSI4_SCL"),
+	PINCTRL_PIN(TWSI4_SDA, "TWSI4_SDA"),
+	PINCTRL_PIN(G_CLKREQ, "G_CLKREQ"),
+	PINCTRL_PIN(VCXO_REQ, "VCXO_REQ"),
+	PINCTRL_PIN(VCXO_OUT, "VCXO_OUT"),
+};
+
+struct pxa3xx_mfp_pin mmp2_mfp[] = {
+	/*       pin         offs   f0        f1          f2          f3          f4          f5        f6        f7  */
+	MFPR_MMP2(GPIO0,     0x054, GPIO,     KP_MK,      NONE,       SPI,        NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO1,     0x058, GPIO,     KP_MK,      NONE,       SPI,        NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO2,     0x05C, GPIO,     KP_MK,      NONE,       SPI,        NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO3,     0x060, GPIO,     KP_MK,      NONE,       SPI,        NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO4,     0x064, GPIO,     KP_MK,      NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO5,     0x068, GPIO,     KP_MK,      NONE,       SPI,        NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO6,     0x06C, GPIO,     KP_MK,      NONE,       SPI,        NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO7,     0x070, GPIO,     KP_MK,      NONE,       SPI,        NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO8,     0x074, GPIO,     KP_MK,      NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO9,     0x078, GPIO,     KP_MK,      NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO10,    0x07C, GPIO,     KP_MK,      NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO11,    0x080, GPIO,     KP_MK,      NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO12,    0x084, GPIO,     KP_MK,      NONE,       CCIC1,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO13,    0x088, GPIO,     KP_MK,      NONE,       CCIC1,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO14,    0x08C, GPIO,     KP_MK,      NONE,       CCIC1,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO15,    0x090, GPIO,     KP_MK,      KP_DK,      CCIC1,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO16,    0x094, GPIO,     KP_DK,      ROT,        CCIC1,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO17,    0x098, GPIO,     KP_DK,      ROT,        CCIC1,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO18,    0x09C, GPIO,     KP_DK,      ROT,        CCIC1,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO19,    0x0A0, GPIO,     KP_DK,      ROT,        CCIC1,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO20,    0x0A4, GPIO,     KP_DK,      TB,         CCIC1,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO21,    0x0A8, GPIO,     KP_DK,      TB,         CCIC1,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO22,    0x0AC, GPIO,     KP_DK,      TB,         CCIC1,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO23,    0x0B0, GPIO,     KP_DK,      TB,         CCIC1,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO24,    0x0B4, GPIO,     I2S,        VCXO_OUT,   NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO25,    0x0B8, GPIO,     I2S,        HDMI,       SSPA2,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO26,    0x0BC, GPIO,     I2S,        HDMI,       SSPA2,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO27,    0x0C0, GPIO,     I2S,        HDMI,       SSPA2,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO28,    0x0C4, GPIO,     I2S,        NONE,       SSPA2,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO29,    0x0C8, GPIO,     UART1,      KP_MK,      NONE,       NONE,       NONE,     AAS_SPI,  NONE),
+	MFPR_MMP2(GPIO30,    0x0CC, GPIO,     UART1,      KP_MK,      NONE,       NONE,       NONE,     AAS_SPI,  NONE),
+	MFPR_MMP2(GPIO31,    0x0D0, GPIO,     UART1,      KP_MK,      NONE,       NONE,       NONE,     AAS_SPI,  NONE),
+	MFPR_MMP2(GPIO32,    0x0D4, GPIO,     UART1,      KP_MK,      NONE,       NONE,       NONE,     AAS_SPI,  NONE),
+	MFPR_MMP2(GPIO33,    0x0D8, GPIO,     SSPA2,      I2S,        NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO34,    0x0DC, GPIO,     SSPA2,      I2S,        NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO35,    0x0E0, GPIO,     SSPA2,      I2S,        NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO36,    0x0E4, GPIO,     SSPA2,      I2S,        NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO37,    0x0E8, GPIO,     MMC2,       SSP1,       TWSI2,      UART2,      UART3,    AAS_SPI,  AAS_TWSI),
+	MFPR_MMP2(GPIO38,    0x0EC, GPIO,     MMC2,       SSP1,       TWSI2,      UART2,      UART3,    AAS_SPI,  AAS_TWSI),
+	MFPR_MMP2(GPIO39,    0x0F0, GPIO,     MMC2,       SSP1,       TWSI2,      UART2,      UART3,    AAS_SPI,  AAS_TWSI),
+	MFPR_MMP2(GPIO40,    0x0F4, GPIO,     MMC2,       SSP1,       TWSI2,      UART2,      UART3,    AAS_SPI,  AAS_TWSI),
+	MFPR_MMP2(GPIO41,    0x0F8, GPIO,     MMC2,       TWSI5,      NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO42,    0x0FC, GPIO,     MMC2,       TWSI5,      NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO43,    0x100, GPIO,     TWSI2,      UART4,      SSP1,       UART2,      UART3,    NONE,     AAS_TWSI),
+	MFPR_MMP2(GPIO44,    0x104, GPIO,     TWSI2,      UART4,      SSP1,       UART2,      UART3,    NONE,     AAS_TWSI),
+	MFPR_MMP2(GPIO45,    0x108, GPIO,     UART1,      UART4,      SSP1,       UART2,      UART3,    NONE,     NONE),
+	MFPR_MMP2(GPIO46,    0x10C, GPIO,     UART1,      UART4,      SSP1,       UART2,      UART3,    NONE,     NONE),
+	MFPR_MMP2(GPIO47,    0x110, GPIO,     UART2,      SSP2,       TWSI6,      CAM2,       AAS_SPI,  AAS_GPIO, NONE),
+	MFPR_MMP2(GPIO48,    0x114, GPIO,     UART2,      SSP2,       TWSI6,      CAM2,       AAS_SPI,  AAS_GPIO, NONE),
+	MFPR_MMP2(GPIO49,    0x118, GPIO,     UART2,      SSP2,       PWM,        CCIC2,      AAS_SPI,  NONE,     NONE),
+	MFPR_MMP2(GPIO50,    0x11C, GPIO,     UART2,      SSP2,       PWM,        CCIC2,      AAS_SPI,  NONE,     NONE),
+	MFPR_MMP2(GPIO51,    0x120, GPIO,     UART3,      ROT,        AAS_GPIO,   PWM,        NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO52,    0x124, GPIO,     UART3,      ROT,        AAS_GPIO,   PWM,        NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO53,    0x128, GPIO,     UART3,      TWSI2,      VCXO_REQ,   NONE,       PWM,      NONE,     AAS_TWSI),
+	MFPR_MMP2(GPIO54,    0x12C, GPIO,     UART3,      TWSI2,      VCXO_OUT,   HDMI,       PWM,      NONE,     AAS_TWSI),
+	MFPR_MMP2(GPIO55,    0x130, GPIO,     SSP2,       SSP1,       UART2,      ROT,        TWSI2,    SSP3,     AAS_TWSI),
+	MFPR_MMP2(GPIO56,    0x134, GPIO,     SSP2,       SSP1,       UART2,      ROT,        TWSI2,    KP_DK,    AAS_TWSI),
+	MFPR_MMP2(GPIO57,    0x138, GPIO,     SSP2_RX,    SSP1_TXRX,  SSP2_FRM,   SSP1_RX,    VCXO_REQ, KP_DK,    NONE),
+	MFPR_MMP2(GPIO58,    0x13C, GPIO,     SSP2,       SSP1_RX,    SSP1_FRM,   SSP1_TXRX,  VCXO_REQ, KP_DK,    NONE),
+	MFPR_MMP2(GPIO59,    0x280, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      UART3,    UART4,    NONE),
+	MFPR_MMP2(GPIO60,    0x284, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      UART3,    UART4,    NONE),
+	MFPR_MMP2(GPIO61,    0x288, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      UART3,    HDMI,     NONE),
+	MFPR_MMP2(GPIO62,    0x28C, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      UART3,    NONE,     NONE),
+	MFPR_MMP2(GPIO63,    0x290, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      MSP,      UART4,    NONE),
+	MFPR_MMP2(GPIO64,    0x294, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      MSP,      UART4,    NONE),
+	MFPR_MMP2(GPIO65,    0x298, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      MSP,      UART4,    NONE),
+	MFPR_MMP2(GPIO66,    0x29C, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      MSP,      UART4,    NONE),
+	MFPR_MMP2(GPIO67,    0x2A0, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      MSP,      NONE,     NONE),
+	MFPR_MMP2(GPIO68,    0x2A4, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      MSP,      LCD,      NONE),
+	MFPR_MMP2(GPIO69,    0x2A8, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      NONE,     LCD,      NONE),
+	MFPR_MMP2(GPIO70,    0x2AC, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      MSP,      LCD,      NONE),
+	MFPR_MMP2(GPIO71,    0x2B0, GPIO,     TWSI3,      NONE,       PWM,        NONE,       NONE,     LCD,      AAS_TWSI),
+	MFPR_MMP2(GPIO72,    0x2B4, GPIO,     TWSI3,      HDMI,       PWM,        NONE,       NONE,     LCD,      AAS_TWSI),
+	MFPR_MMP2(GPIO73,    0x2B8, GPIO,     VCXO_REQ,   32K_CLKOUT, PWM,        VCXO_OUT,   NONE,     LCD,      NONE),
+	MFPR_MMP2(GPIO74,    0x170, GPIO,     LCD,        SMC,        MMC4,       SSP3,       UART2,    UART4,    TIPU),
+	MFPR_MMP2(GPIO75,    0x174, GPIO,     LCD,        SMC,        MMC4,       SSP3,       UART2,    UART4,    TIPU),
+	MFPR_MMP2(GPIO76,    0x178, GPIO,     LCD,        SMC,        MMC4,       SSP3,       UART2,    UART4,    TIPU),
+	MFPR_MMP2(GPIO77,    0x17C, GPIO,     LCD,        SMC,        MMC4,       SSP3,       UART2,    UART4,    TIPU),
+	MFPR_MMP2(GPIO78,    0x180, GPIO,     LCD,        HDMI,       MMC4,       NONE,       SSP4,     AAS_SPI,  TIPU),
+	MFPR_MMP2(GPIO79,    0x184, GPIO,     LCD,        AAS_GPIO,   MMC4,       NONE,       SSP4,     AAS_SPI,  TIPU),
+	MFPR_MMP2(GPIO80,    0x188, GPIO,     LCD,        AAS_GPIO,   MMC4,       NONE,       SSP4,     AAS_SPI,  TIPU),
+	MFPR_MMP2(GPIO81,    0x18C, GPIO,     LCD,        AAS_GPIO,   MMC4,       NONE,       SSP4,     AAS_SPI,  TIPU),
+	MFPR_MMP2(GPIO82,    0x190, GPIO,     LCD,        NONE,       MMC4,       NONE,       NONE,     CCIC2,    TIPU),
+	MFPR_MMP2(GPIO83,    0x194, GPIO,     LCD,        NONE,       MMC4,       NONE,       NONE,     CCIC2,    TIPU),
+	MFPR_MMP2(GPIO84,    0x198, GPIO,     LCD,        SMC,        MMC2,       NONE,       TWSI5,    AAS_TWSI, TIPU),
+	MFPR_MMP2(GPIO85,    0x19C, GPIO,     LCD,        SMC,        MMC2,       NONE,       TWSI5,    AAS_TWSI, TIPU),
+	MFPR_MMP2(GPIO86,    0x1A0, GPIO,     LCD,        SMC,        MMC2,       NONE,       TWSI6,    CCIC2,    TIPU),
+	MFPR_MMP2(GPIO87,    0x1A4, GPIO,     LCD,        SMC,        MMC2,       NONE,       TWSI6,    CCIC2,    TIPU),
+	MFPR_MMP2(GPIO88,    0x1A8, GPIO,     LCD,        AAS_GPIO,   MMC2,       NONE,       NONE,     CCIC2,    TIPU),
+	MFPR_MMP2(GPIO89,    0x1AC, GPIO,     LCD,        AAS_GPIO,   MMC2,       NONE,       NONE,     CCIC2,    TIPU),
+	MFPR_MMP2(GPIO90,    0x1B0, GPIO,     LCD,        AAS_GPIO,   MMC2,       NONE,       NONE,     CCIC2,    TIPU),
+	MFPR_MMP2(GPIO91,    0x1B4, GPIO,     LCD,        AAS_GPIO,   MMC2,       NONE,       NONE,     CCIC2,    TIPU),
+	MFPR_MMP2(GPIO92,    0x1B8, GPIO,     LCD,        AAS_GPIO,   MMC2,       NONE,       NONE,     CCIC2,    TIPU),
+	MFPR_MMP2(GPIO93,    0x1BC, GPIO,     LCD,        AAS_GPIO,   MMC2,       NONE,       NONE,     CCIC2,    TIPU),
+	MFPR_MMP2(GPIO94,    0x1C0, GPIO,     LCD,        AAS_GPIO,   SPI,        NONE,       AAS_SPI,  CCIC2,    TIPU),
+	MFPR_MMP2(GPIO95,    0x1C4, GPIO,     LCD,        TWSI3,      SPI,        AAS_DEU_EX, AAS_SPI,  CCIC2,    TIPU),
+	MFPR_MMP2(GPIO96,    0x1C8, GPIO,     LCD,        TWSI3,      SPI,        AAS_DEU_EX, AAS_SPI,  NONE,     TIPU),
+	MFPR_MMP2(GPIO97,    0x1CC, GPIO,     LCD,        TWSI6,      SPI,        AAS_DEU_EX, AAS_SPI,  NONE,     TIPU),
+	MFPR_MMP2(GPIO98,    0x1D0, GPIO,     LCD,        TWSI6,      SPI,        ONE_WIRE,   NONE,     NONE,     TIPU),
+	MFPR_MMP2(GPIO99,    0x1D4, GPIO,     LCD,        SMC,        SPI,        TWSI5,      NONE,     NONE,     TIPU),
+	MFPR_MMP2(GPIO100,   0x1D8, GPIO,     LCD,        SMC,        SPI,        TWSI5,      NONE,     NONE,     TIPU),
+	MFPR_MMP2(GPIO101,   0x1DC, GPIO,     LCD,        SMC,        SPI,        NONE,       NONE,     NONE,     TIPU),
+	MFPR_MMP2(GPIO102,   0x000, USIM,     GPIO,       FSIC,       KP_DK,      LCD,        NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO103,   0x004, USIM,     GPIO,       FSIC,       KP_DK,      LCD,        NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO104,   0x1FC, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO105,   0x1F8, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO106,   0x1F4, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO107,   0x1F0, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO108,   0x21C, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO109,   0x218, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO110,   0x214, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO111,   0x200, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO112,   0x244, NAND,     GPIO,       MMC3,       SMC,        NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO113,   0x25C, SMC,      GPIO,       EXT_DMA,    MMC3,       SMC,        HDMI,     NONE,     NONE),
+	MFPR_MMP2(GPIO114,   0x164, G_CLKOUT, 32K_CLKOUT, HDMI,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO115,   0x260, GPIO,     NONE,       AC,         UART4,      UART3,      SSP1,     NONE,     NONE),
+	MFPR_MMP2(GPIO116,   0x264, GPIO,     NONE,       AC,         UART4,      UART3,      SSP1,     NONE,     NONE),
+	MFPR_MMP2(GPIO117,   0x268, GPIO,     NONE,       AC,         UART4,      UART3,      SSP1,     NONE,     NONE),
+	MFPR_MMP2(GPIO118,   0x26C, GPIO,     NONE,       AC,         UART4,      UART3,      SSP1,     NONE,     NONE),
+	MFPR_MMP2(GPIO119,   0x270, GPIO,     NONE,       CA,         SSP3,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO120,   0x274, GPIO,     NONE,       CA,         SSP3,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO121,   0x278, GPIO,     NONE,       CA,         SSP3,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO122,   0x27C, GPIO,     NONE,       CA,         SSP3,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO123,   0x148, GPIO,     SLEEP_IND,  ONE_WIRE,   32K_CLKOUT, NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO124,   0x00C, GPIO,     MMC1,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO125,   0x010, GPIO,     MMC1,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO126,   0x014, GPIO,     MMC1,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO127,   0x018, GPIO,     NONE,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO128,   0x01C, GPIO,     NONE,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO129,   0x020, GPIO,     MMC1,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO130,   0x024, GPIO,     MMC1,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO131,   0x028, GPIO,     MMC1,       NONE,       MSP,        NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO132,   0x02C, GPIO,     MMC1,       PRI_JTAG,   MSP,        SSP3,       AAS_JTAG, NONE,     NONE),
+	MFPR_MMP2(GPIO133,   0x030, GPIO,     MMC1,       PRI_JTAG,   MSP,        SSP3,       AAS_JTAG, NONE,     NONE),
+	MFPR_MMP2(GPIO134,   0x034, GPIO,     MMC1,       PRI_JTAG,   MSP,        SSP3,       AAS_JTAG, NONE,     NONE),
+	MFPR_MMP2(GPIO135,   0x038, GPIO,     NONE,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO136,   0x03C, GPIO,     MMC1,       PRI_JTAG,   MSP,        SSP3,       AAS_JTAG, NONE,     NONE),
+	MFPR_MMP2(GPIO137,   0x040, GPIO,     HDMI,       LCD,        MSP,        NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO138,   0x044, GPIO,     NONE,       LCD,        MMC3,       SMC,        NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO139,   0x048, GPIO,     MMC1,       PRI_JTAG,   MSP,        NONE,       AAS_JTAG, NONE,     NONE),
+	MFPR_MMP2(GPIO140,   0x04C, GPIO,     MMC1,       LCD,        NONE,       NONE,       UART2,    UART1,    NONE),
+	MFPR_MMP2(GPIO141,   0x050, GPIO,     MMC1,       LCD,        NONE,       NONE,       UART2,    UART1,    NONE),
+	MFPR_MMP2(GPIO142,   0x008, USIM,     GPIO,       FSIC,       KP_DK,      NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO143,   0x220, NAND,     GPIO,       SMC,        NONE,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO144,   0x224, NAND,     GPIO,       SMC_INT,    SMC,        NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO145,   0x228, SMC,      GPIO,       NONE,       NONE,       SMC,        NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO146,   0x22C, SMC,      GPIO,       NONE,       NONE,       SMC,        NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO147,   0x230, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO148,   0x234, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO149,   0x238, NAND,     GPIO,       NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO150,   0x23C, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO151,   0x240, SMC,      GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO152,   0x248, SMC,      GPIO,       NONE,       NONE,       SMC,        NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO153,   0x24C, SMC,      GPIO,       NONE,       NONE,       SMC,        NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO154,   0x254, SMC_INT,  GPIO,       SMC,        NONE,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO155,   0x258, EXT_DMA,  GPIO,       SMC,        NONE,       EXT_DMA,    NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO156,   0x14C, PRI_JTAG, GPIO,       PWM,        NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO157,   0x150, PRI_JTAG, GPIO,       PWM,        NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO158,   0x154, PRI_JTAG, GPIO,       PWM,        NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO159,   0x158, PRI_JTAG, GPIO,       PWM,        NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO160,   0x250, NAND,     GPIO,       SMC,        NONE,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO161,   0x210, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO162,   0x20C, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO163,   0x208, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO164,   0x204, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO165,   0x1EC, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO166,   0x1E8, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO167,   0x1E4, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(GPIO168,   0x1E0, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(TWSI4_SCL, 0x2BC, TWSI4,    LCD,        NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(TWSI4_SDA, 0x2C0, TWSI4,    LCD,        NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(G_CLKREQ,  0x160, G_CLKREQ, ONE_WIRE,   NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(VCXO_REQ,  0x168, VCXO_REQ, ONE_WIRE,   PLL,        NONE,       NONE,       NONE,     NONE,     NONE),
+	MFPR_MMP2(VCXO_OUT,  0x16C, VCXO_OUT, 32K_CLKOUT, NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
+};
+
+static const unsigned mmp2_uart1_pin1[] = {GPIO29, GPIO30, GPIO31, GPIO32};
+static const unsigned mmp2_uart1_pin2[] = {GPIO45, GPIO46};
+static const unsigned mmp2_uart1_pin3[] = {GPIO140, GPIO141};
+static const unsigned mmp2_uart2_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40};
+static const unsigned mmp2_uart2_pin2[] = {GPIO43, GPIO44, GPIO45, GPIO46};
+static const unsigned mmp2_uart2_pin3[] = {GPIO47, GPIO48, GPIO49, GPIO50};
+static const unsigned mmp2_uart2_pin4[] = {GPIO74, GPIO75, GPIO76, GPIO77};
+static const unsigned mmp2_uart2_pin5[] = {GPIO55, GPIO56};
+static const unsigned mmp2_uart2_pin6[] = {GPIO140, GPIO141};
+static const unsigned mmp2_uart3_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40};
+static const unsigned mmp2_uart3_pin2[] = {GPIO43, GPIO44, GPIO45, GPIO46};
+static const unsigned mmp2_uart3_pin3[] = {GPIO51, GPIO52, GPIO53, GPIO54};
+static const unsigned mmp2_uart3_pin4[] = {GPIO59, GPIO60, GPIO61, GPIO62};
+static const unsigned mmp2_uart3_pin5[] = {GPIO115, GPIO116, GPIO117, GPIO118};
+static const unsigned mmp2_uart3_pin6[] = {GPIO51, GPIO52};
+static const unsigned mmp2_uart4_pin1[] = {GPIO43, GPIO44, GPIO45, GPIO46};
+static const unsigned mmp2_uart4_pin2[] = {GPIO63, GPIO64, GPIO65, GPIO66};
+static const unsigned mmp2_uart4_pin3[] = {GPIO74, GPIO75, GPIO76, GPIO77};
+static const unsigned mmp2_uart4_pin4[] = {GPIO115, GPIO116, GPIO117, GPIO118};
+static const unsigned mmp2_uart4_pin5[] = {GPIO59, GPIO60};
+static const unsigned mmp2_kpdk_pin1[] = {GPIO16, GPIO17, GPIO18, GPIO19};
+static const unsigned mmp2_kpdk_pin2[] = {GPIO16, GPIO17};
+static const unsigned mmp2_twsi2_pin1[] = {GPIO37, GPIO38};
+static const unsigned mmp2_twsi2_pin2[] = {GPIO39, GPIO40};
+static const unsigned mmp2_twsi2_pin3[] = {GPIO43, GPIO44};
+static const unsigned mmp2_twsi2_pin4[] = {GPIO53, GPIO54};
+static const unsigned mmp2_twsi2_pin5[] = {GPIO55, GPIO56};
+static const unsigned mmp2_twsi3_pin1[] = {GPIO71, GPIO72};
+static const unsigned mmp2_twsi3_pin2[] = {GPIO95, GPIO96};
+static const unsigned mmp2_twsi4_pin1[] = {TWSI4_SCL, TWSI4_SDA};
+static const unsigned mmp2_twsi5_pin1[] = {GPIO41, GPIO42};
+static const unsigned mmp2_twsi5_pin2[] = {GPIO84, GPIO85};
+static const unsigned mmp2_twsi5_pin3[] = {GPIO99, GPIO100};
+static const unsigned mmp2_twsi6_pin1[] = {GPIO47, GPIO48};
+static const unsigned mmp2_twsi6_pin2[] = {GPIO86, GPIO87};
+static const unsigned mmp2_twsi6_pin3[] = {GPIO97, GPIO98};
+static const unsigned mmp2_ccic1_pin1[] = {GPIO12, GPIO13, GPIO14, GPIO15,
+	GPIO16, GPIO17, GPIO18, GPIO19, GPIO20, GPIO21, GPIO22, GPIO23};
+static const unsigned mmp2_ccic1_pin2[] = {GPIO59, GPIO60, GPIO61, GPIO62,
+	GPIO63, GPIO64, GPIO65, GPIO66, GPIO67, GPIO68, GPIO69, GPIO70};
+static const unsigned mmp2_ccic2_pin1[] = {GPIO59, GPIO60, GPIO61, GPIO62,
+	GPIO63, GPIO64, GPIO65, GPIO66, GPIO67, GPIO68, GPIO69, GPIO70};
+static const unsigned mmp2_ccic2_pin2[] = {GPIO82, GPIO83, GPIO86, GPIO87,
+	GPIO88, GPIO89, GPIO90, GPIO91, GPIO92, GPIO93, GPIO94, GPIO95};
+static const unsigned mmp2_ulpi_pin1[] = {GPIO59, GPIO60, GPIO61, GPIO62,
+	GPIO63, GPIO64, GPIO65, GPIO66, GPIO67, GPIO68, GPIO69, GPIO70};
+static const unsigned mmp2_ro_pin1[] = {GPIO16, GPIO17};
+static const unsigned mmp2_ro_pin2[] = {GPIO18, GPIO19};
+static const unsigned mmp2_ro_pin3[] = {GPIO51, GPIO52};
+static const unsigned mmp2_ro_pin4[] = {GPIO55, GPIO56};
+static const unsigned mmp2_i2s_pin1[] = {GPIO24, GPIO25, GPIO26, GPIO27,
+	GPIO28};
+static const unsigned mmp2_i2s_pin2[] = {GPIO33, GPIO34, GPIO35, GPIO36};
+static const unsigned mmp2_ssp1_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40};
+static const unsigned mmp2_ssp1_pin2[] = {GPIO43, GPIO44, GPIO45, GPIO46};
+static const unsigned mmp2_ssp1_pin3[] = {GPIO115, GPIO116, GPIO117, GPIO118};
+static const unsigned mmp2_ssp2_pin1[] = {GPIO47, GPIO48, GPIO49, GPIO50};
+static const unsigned mmp2_ssp3_pin1[] = {GPIO119, GPIO120, GPIO121, GPIO122};
+static const unsigned mmp2_ssp3_pin2[] = {GPIO132, GPIO133, GPIO133, GPIO136};
+static const unsigned mmp2_sspa2_pin1[] = {GPIO25, GPIO26, GPIO27, GPIO28};
+static const unsigned mmp2_sspa2_pin2[] = {GPIO33, GPIO34, GPIO35, GPIO36};
+static const unsigned mmp2_mmc1_pin1[] = {GPIO131, GPIO132, GPIO133, GPIO134,
+	GPIO136, GPIO139, GPIO140, GPIO141};
+static const unsigned mmp2_mmc2_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40,
+	GPIO41, GPIO42};
+static const unsigned mmp2_mmc3_pin1[] = {GPIO111, GPIO112, GPIO151, GPIO162,
+	GPIO163, GPIO164, GPIO165, GPIO166, GPIO167, GPIO168};
+
+static struct pxa3xx_pin_group mmp2_grps[] = {
+	GRP_MMP2("uart1 4p1", UART1, mmp2_uart1_pin1),
+	GRP_MMP2("uart1 2p2", UART1, mmp2_uart1_pin2),
+	GRP_MMP2("uart1 2p3", UART1, mmp2_uart1_pin3),
+	GRP_MMP2("uart2 4p1", UART2, mmp2_uart2_pin1),
+	GRP_MMP2("uart2 4p2", UART2, mmp2_uart2_pin2),
+	GRP_MMP2("uart2 4p3", UART2, mmp2_uart2_pin3),
+	GRP_MMP2("uart2 4p4", UART2, mmp2_uart2_pin4),
+	GRP_MMP2("uart2 2p5", UART2, mmp2_uart2_pin5),
+	GRP_MMP2("uart2 2p6", UART2, mmp2_uart2_pin6),
+	GRP_MMP2("uart3 4p1", UART3, mmp2_uart3_pin1),
+	GRP_MMP2("uart3 4p2", UART3, mmp2_uart3_pin2),
+	GRP_MMP2("uart3 4p3", UART3, mmp2_uart3_pin3),
+	GRP_MMP2("uart3 4p4", UART3, mmp2_uart3_pin4),
+	GRP_MMP2("uart3 4p5", UART3, mmp2_uart3_pin5),
+	GRP_MMP2("uart3 2p6", UART3, mmp2_uart3_pin6),
+	GRP_MMP2("uart4 4p1", UART4, mmp2_uart4_pin1),
+	GRP_MMP2("uart4 4p2", UART4, mmp2_uart4_pin2),
+	GRP_MMP2("uart4 4p3", UART4, mmp2_uart4_pin3),
+	GRP_MMP2("uart4 4p4", UART4, mmp2_uart4_pin4),
+	GRP_MMP2("uart4 2p5", UART4, mmp2_uart4_pin5),
+	GRP_MMP2("kpdk 4p1", KP_DK, mmp2_kpdk_pin1),
+	GRP_MMP2("kpdk 4p2", KP_DK, mmp2_kpdk_pin2),
+	GRP_MMP2("twsi2-1", TWSI2, mmp2_twsi2_pin1),
+	GRP_MMP2("twsi2-2", TWSI2, mmp2_twsi2_pin2),
+	GRP_MMP2("twsi2-3", TWSI2, mmp2_twsi2_pin3),
+	GRP_MMP2("twsi2-4", TWSI2, mmp2_twsi2_pin4),
+	GRP_MMP2("twsi2-5", TWSI2, mmp2_twsi2_pin5),
+	GRP_MMP2("twsi3-1", TWSI3, mmp2_twsi3_pin1),
+	GRP_MMP2("twsi3-2", TWSI3, mmp2_twsi3_pin2),
+	GRP_MMP2("twsi4", TWSI4, mmp2_twsi4_pin1),
+	GRP_MMP2("twsi5-1", TWSI5, mmp2_twsi5_pin1),
+	GRP_MMP2("twsi5-2", TWSI5, mmp2_twsi5_pin2),
+	GRP_MMP2("twsi5-3", TWSI5, mmp2_twsi5_pin3),
+	GRP_MMP2("twsi6-1", TWSI6, mmp2_twsi6_pin1),
+	GRP_MMP2("twsi6-2", TWSI6, mmp2_twsi6_pin2),
+	GRP_MMP2("twsi6-3", TWSI6, mmp2_twsi6_pin3),
+	GRP_MMP2("ccic1-1", CCIC1, mmp2_ccic1_pin1),
+	GRP_MMP2("ccic1-2", CCIC1, mmp2_ccic1_pin2),
+	GRP_MMP2("ccic2-1", CCIC2, mmp2_ccic2_pin1),
+	GRP_MMP2("ccic2-1", CCIC2, mmp2_ccic2_pin2),
+	GRP_MMP2("ulpi", ULPI, mmp2_ulpi_pin1),
+	GRP_MMP2("ro-1", ROT, mmp2_ro_pin1),
+	GRP_MMP2("ro-2", ROT, mmp2_ro_pin2),
+	GRP_MMP2("ro-3", ROT, mmp2_ro_pin3),
+	GRP_MMP2("ro-4", ROT, mmp2_ro_pin4),
+	GRP_MMP2("i2s 5p1", I2S, mmp2_i2s_pin1),
+	GRP_MMP2("i2s 4p2", I2S, mmp2_i2s_pin2),
+	GRP_MMP2("ssp1 4p1", SSP1, mmp2_ssp1_pin1),
+	GRP_MMP2("ssp1 4p2", SSP1, mmp2_ssp1_pin2),
+	GRP_MMP2("ssp1 4p3", SSP1, mmp2_ssp1_pin3),
+	GRP_MMP2("ssp2 4p1", SSP2, mmp2_ssp2_pin1),
+	GRP_MMP2("ssp3 4p1", SSP3, mmp2_ssp3_pin1),
+	GRP_MMP2("ssp3 4p2", SSP3, mmp2_ssp3_pin2),
+	GRP_MMP2("sspa2 4p1", SSPA2, mmp2_sspa2_pin1),
+	GRP_MMP2("sspa2 4p2", SSPA2, mmp2_sspa2_pin2),
+	GRP_MMP2("mmc1 8p1", MMC1, mmp2_mmc1_pin1),
+	GRP_MMP2("mmc2 6p1", MMC2, mmp2_mmc2_pin1),
+	GRP_MMP2("mmc3 10p1", MMC3, mmp2_mmc3_pin1),
+};
+
+static const char * const mmp2_uart1_grps[] = {"uart1 4p1", "uart1 2p2",
+	"uart1 2p3"};
+static const char * const mmp2_uart2_grps[] = {"uart2 4p1", "uart2 4p2",
+	"uart2 4p3", "uart2 4p4", "uart2 4p5", "uart2 4p6"};
+static const char * const mmp2_uart3_grps[] = {"uart3 4p1", "uart3 4p2",
+	"uart3 4p3", "uart3 4p4", "uart3 4p5", "uart3 2p6"};
+static const char * const mmp2_uart4_grps[] = {"uart4 4p1", "uart4 4p2",
+	"uart4 4p3", "uart4 4p4", "uart4 2p5"};
+static const char * const mmp2_kpdk_grps[] = {"kpdk 4p1", "kpdk 4p2"};
+static const char * const mmp2_twsi2_grps[] = {"twsi2-1", "twsi2-2",
+	"twsi2-3", "twsi2-4", "twsi2-5"};
+static const char * const mmp2_twsi3_grps[] = {"twsi3-1", "twsi3-2"};
+static const char * const mmp2_twsi4_grps[] = {"twsi4"};
+static const char * const mmp2_twsi5_grps[] = {"twsi5-1", "twsi5-2",
+	"twsi5-3"};
+static const char * const mmp2_twsi6_grps[] = {"twsi6-1", "twsi6-2",
+	"twsi6-3"};
+static const char * const mmp2_ccic1_grps[] = {"ccic1-1", "ccic1-2"};
+static const char * const mmp2_ccic2_grps[] = {"ccic2-1", "ccic2-2"};
+static const char * const mmp2_ulpi_grps[] = {"ulpi"};
+static const char * const mmp2_ro_grps[] = {"ro-1", "ro-2", "ro-3", "ro-4"};
+static const char * const mmp2_i2s_grps[] = {"i2s 5p1", "i2s 4p2"};
+static const char * const mmp2_ssp1_grps[] = {"ssp1 4p1", "ssp1 4p2",
+	"ssp1 4p3"};
+static const char * const mmp2_ssp2_grps[] = {"ssp2 4p1"};
+static const char * const mmp2_ssp3_grps[] = {"ssp3 4p1", "ssp3 4p2"};
+static const char * const mmp2_sspa2_grps[] = {"sspa2 4p1", "sspa2 4p2"};
+static const char * const mmp2_mmc1_grps[] = {"mmc1 8p1"};
+static const char * const mmp2_mmc2_grps[] = {"mmc2 6p1"};
+static const char * const mmp2_mmc3_grps[] = {"mmc3 10p1"};
+
+static struct pxa3xx_pmx_func mmp2_funcs[] = {
+	{"uart1",	ARRAY_AND_SIZE(mmp2_uart1_grps)},
+	{"uart2",	ARRAY_AND_SIZE(mmp2_uart2_grps)},
+	{"uart3",	ARRAY_AND_SIZE(mmp2_uart3_grps)},
+	{"uart4",	ARRAY_AND_SIZE(mmp2_uart4_grps)},
+	{"kpdk",	ARRAY_AND_SIZE(mmp2_kpdk_grps)},
+	{"twsi2",	ARRAY_AND_SIZE(mmp2_twsi2_grps)},
+	{"twsi3",	ARRAY_AND_SIZE(mmp2_twsi3_grps)},
+	{"twsi4",	ARRAY_AND_SIZE(mmp2_twsi4_grps)},
+	{"twsi5",	ARRAY_AND_SIZE(mmp2_twsi5_grps)},
+	{"twsi6",	ARRAY_AND_SIZE(mmp2_twsi6_grps)},
+	{"ccic1",	ARRAY_AND_SIZE(mmp2_ccic1_grps)},
+	{"ccic2",	ARRAY_AND_SIZE(mmp2_ccic2_grps)},
+	{"ulpi",	ARRAY_AND_SIZE(mmp2_ulpi_grps)},
+	{"ro",		ARRAY_AND_SIZE(mmp2_ro_grps)},
+	{"i2s",		ARRAY_AND_SIZE(mmp2_i2s_grps)},
+	{"ssp1",	ARRAY_AND_SIZE(mmp2_ssp1_grps)},
+	{"ssp2",	ARRAY_AND_SIZE(mmp2_ssp2_grps)},
+	{"ssp3",	ARRAY_AND_SIZE(mmp2_ssp3_grps)},
+	{"sspa2",	ARRAY_AND_SIZE(mmp2_sspa2_grps)},
+	{"mmc1",	ARRAY_AND_SIZE(mmp2_mmc1_grps)},
+	{"mmc2",	ARRAY_AND_SIZE(mmp2_mmc2_grps)},
+	{"mmc3",	ARRAY_AND_SIZE(mmp2_mmc3_grps)},
+};
+
+static struct pinctrl_desc mmp2_pctrl_desc = {
+	.name		= "mmp2-pinctrl",
+	.owner		= THIS_MODULE,
+};
+
+static struct pxa3xx_pinmux_info mmp2_info = {
+	.mfp		= mmp2_mfp,
+	.num_mfp	= ARRAY_SIZE(mmp2_mfp),
+	.grps		= mmp2_grps,
+	.num_grps	= ARRAY_SIZE(mmp2_grps),
+	.funcs		= mmp2_funcs,
+	.num_funcs	= ARRAY_SIZE(mmp2_funcs),
+	.num_gpio	= 169,
+	.desc		= &mmp2_pctrl_desc,
+	.pads		= mmp2_pads,
+	.num_pads	= ARRAY_SIZE(mmp2_pads),
+
+	.cputype	= PINCTRL_MMP2,
+	.ds_mask	= MMP2_DS_MASK,
+	.ds_shift	= MMP2_DS_SHIFT,
+};
+
+static int __devinit mmp2_pinmux_probe(struct platform_device *pdev)
+{
+	return pxa3xx_pinctrl_register(pdev, &mmp2_info);
+}
+
+static int __devexit mmp2_pinmux_remove(struct platform_device *pdev)
+{
+	return pxa3xx_pinctrl_unregister(pdev);
+}
+
+static struct platform_driver mmp2_pinmux_driver = {
+	.driver = {
+		.name	= "mmp2-pinmux",
+		.owner	= THIS_MODULE,
+	},
+	.probe	= mmp2_pinmux_probe,
+	.remove	= __devexit_p(mmp2_pinmux_remove),
+};
+
+static int __init mmp2_pinmux_init(void)
+{
+	return platform_driver_register(&mmp2_pinmux_driver);
+}
+core_initcall_sync(mmp2_pinmux_init);
+
+static void __exit mmp2_pinmux_exit(void)
+{
+	platform_driver_unregister(&mmp2_pinmux_driver);
+}
+module_exit(mmp2_pinmux_exit);
+
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("PXA3xx pin control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-pxa168.c b/drivers/pinctrl/pinctrl-pxa168.c
new file mode 100644
index 0000000..c1997fa
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-pxa168.c
@@ -0,0 +1,651 @@
+/*
+ *  linux/drivers/pinctrl/pinmux-pxa168.c
+ *
+ *  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
+ *  publishhed by the Free Software Foundation.
+ *
+ *  Copyright (C) 2011, Marvell Technology Group Ltd.
+ *
+ *  Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include "pinctrl-pxa3xx.h"
+
+#define PXA168_DS_MASK		0x1800
+#define PXA168_DS_SHIFT		11
+#define PXA168_SLEEP_MASK	0x38
+#define PXA168_SLEEP_SELECT	(1 << 9)
+#define PXA168_SLEEP_DATA	(1 << 8)
+#define PXA168_SLEEP_DIR	(1 << 7)
+
+#define MFPR_168(a, r, f0, f1, f2, f3, f4, f5, f6, f7)		\
+	{							\
+		.name = #a,					\
+		.pin = a,					\
+		.mfpr = r,					\
+		.func = {					\
+			PXA168_MUX_##f0,			\
+			PXA168_MUX_##f1,			\
+			PXA168_MUX_##f2,			\
+			PXA168_MUX_##f3,			\
+			PXA168_MUX_##f4,			\
+			PXA168_MUX_##f5,			\
+			PXA168_MUX_##f6,			\
+			PXA168_MUX_##f7,			\
+		},						\
+	}
+
+#define GRP_168(a, m, p)		\
+	{ .name = a, .mux = PXA168_MUX_##m, .pins = p, .npins = ARRAY_SIZE(p), }
+
+/* 131 pins */
+enum pxa168_pin_list {
+	/* 0~122: GPIO0~GPIO122 */
+	PWR_SCL = 123,
+	PWR_SDA,
+	TDI,
+	TMS,
+	TCK,
+	TDO,
+	TRST,
+	WAKEUP = 130,
+};
+
+enum pxa168_mux {
+	/* PXA3xx_MUX_GPIO = 0 (predefined in pinctrl-pxa3xx.h) */
+	PXA168_MUX_GPIO = 0,
+	PXA168_MUX_DFIO,
+	PXA168_MUX_NAND,
+	PXA168_MUX_SMC,
+	PXA168_MUX_SMC_CS0,
+	PXA168_MUX_SMC_CS1,
+	PXA168_MUX_SMC_INT,
+	PXA168_MUX_SMC_RDY,
+	PXA168_MUX_MMC1,
+	PXA168_MUX_MMC2,
+	PXA168_MUX_MMC2_CMD,
+	PXA168_MUX_MMC2_CLK,
+	PXA168_MUX_MMC3,
+	PXA168_MUX_MMC3_CMD,
+	PXA168_MUX_MMC3_CLK,
+	PXA168_MUX_MMC4,
+	PXA168_MUX_MSP,
+	PXA168_MUX_MSP_DAT3,
+	PXA168_MUX_MSP_INS,
+	PXA168_MUX_I2C,
+	PXA168_MUX_PWRI2C,
+	PXA168_MUX_AC97,
+	PXA168_MUX_AC97_SYSCLK,
+	PXA168_MUX_PWM,
+	PXA168_MUX_PWM1,
+	PXA168_MUX_XD,
+	PXA168_MUX_XP,
+	PXA168_MUX_LCD,
+	PXA168_MUX_CCIC,
+	PXA168_MUX_CF,
+	PXA168_MUX_CF_RDY,
+	PXA168_MUX_CF_nINPACK,
+	PXA168_MUX_CF_nWAIT,
+	PXA168_MUX_KP_MKOUT,
+	PXA168_MUX_KP_MKIN,
+	PXA168_MUX_KP_DK,
+	PXA168_MUX_ETH,
+	PXA168_MUX_ETH_TX,
+	PXA168_MUX_ETH_RX,
+	PXA168_MUX_ONE_WIRE,
+	PXA168_MUX_UART1,
+	PXA168_MUX_UART1_TX,
+	PXA168_MUX_UART1_CTS,
+	PXA168_MUX_UART1_nRI,
+	PXA168_MUX_UART1_DTR,
+	PXA168_MUX_UART2,
+	PXA168_MUX_UART2_TX,
+	PXA168_MUX_UART3,
+	PXA168_MUX_UART3_TX,
+	PXA168_MUX_UART3_CTS,
+	PXA168_MUX_SSP1,
+	PXA168_MUX_SSP1_TX,
+	PXA168_MUX_SSP2,
+	PXA168_MUX_SSP2_TX,
+	PXA168_MUX_SSP3,
+	PXA168_MUX_SSP3_TX,
+	PXA168_MUX_SSP4,
+	PXA168_MUX_SSP4_TX,
+	PXA168_MUX_SSP5,
+	PXA168_MUX_SSP5_TX,
+	PXA168_MUX_USB,
+	PXA168_MUX_JTAG,
+	PXA168_MUX_RESET,
+	PXA168_MUX_WAKEUP,
+	PXA168_MUX_EXT_32K_IN,
+	PXA168_MUX_NONE = 0xffff,
+};
+
+static struct pinctrl_pin_desc pxa168_pads[] = {
+	PINCTRL_PIN(GPIO0, "GPIO0"),
+	PINCTRL_PIN(GPIO1, "GPIO1"),
+	PINCTRL_PIN(GPIO2, "GPIO2"),
+	PINCTRL_PIN(GPIO3, "GPIO3"),
+	PINCTRL_PIN(GPIO4, "GPIO4"),
+	PINCTRL_PIN(GPIO5, "GPIO5"),
+	PINCTRL_PIN(GPIO6, "GPIO6"),
+	PINCTRL_PIN(GPIO7, "GPIO7"),
+	PINCTRL_PIN(GPIO8, "GPIO8"),
+	PINCTRL_PIN(GPIO9, "GPIO9"),
+	PINCTRL_PIN(GPIO10, "GPIO10"),
+	PINCTRL_PIN(GPIO11, "GPIO11"),
+	PINCTRL_PIN(GPIO12, "GPIO12"),
+	PINCTRL_PIN(GPIO13, "GPIO13"),
+	PINCTRL_PIN(GPIO14, "GPIO14"),
+	PINCTRL_PIN(GPIO15, "GPIO15"),
+	PINCTRL_PIN(GPIO16, "GPIO16"),
+	PINCTRL_PIN(GPIO17, "GPIO17"),
+	PINCTRL_PIN(GPIO18, "GPIO18"),
+	PINCTRL_PIN(GPIO19, "GPIO19"),
+	PINCTRL_PIN(GPIO20, "GPIO20"),
+	PINCTRL_PIN(GPIO21, "GPIO21"),
+	PINCTRL_PIN(GPIO22, "GPIO22"),
+	PINCTRL_PIN(GPIO23, "GPIO23"),
+	PINCTRL_PIN(GPIO24, "GPIO24"),
+	PINCTRL_PIN(GPIO25, "GPIO25"),
+	PINCTRL_PIN(GPIO26, "GPIO26"),
+	PINCTRL_PIN(GPIO27, "GPIO27"),
+	PINCTRL_PIN(GPIO28, "GPIO28"),
+	PINCTRL_PIN(GPIO29, "GPIO29"),
+	PINCTRL_PIN(GPIO30, "GPIO30"),
+	PINCTRL_PIN(GPIO31, "GPIO31"),
+	PINCTRL_PIN(GPIO32, "GPIO32"),
+	PINCTRL_PIN(GPIO33, "GPIO33"),
+	PINCTRL_PIN(GPIO34, "GPIO34"),
+	PINCTRL_PIN(GPIO35, "GPIO35"),
+	PINCTRL_PIN(GPIO36, "GPIO36"),
+	PINCTRL_PIN(GPIO37, "GPIO37"),
+	PINCTRL_PIN(GPIO38, "GPIO38"),
+	PINCTRL_PIN(GPIO39, "GPIO39"),
+	PINCTRL_PIN(GPIO40, "GPIO40"),
+	PINCTRL_PIN(GPIO41, "GPIO41"),
+	PINCTRL_PIN(GPIO42, "GPIO42"),
+	PINCTRL_PIN(GPIO43, "GPIO43"),
+	PINCTRL_PIN(GPIO44, "GPIO44"),
+	PINCTRL_PIN(GPIO45, "GPIO45"),
+	PINCTRL_PIN(GPIO46, "GPIO46"),
+	PINCTRL_PIN(GPIO47, "GPIO47"),
+	PINCTRL_PIN(GPIO48, "GPIO48"),
+	PINCTRL_PIN(GPIO49, "GPIO49"),
+	PINCTRL_PIN(GPIO50, "GPIO50"),
+	PINCTRL_PIN(GPIO51, "GPIO51"),
+	PINCTRL_PIN(GPIO52, "GPIO52"),
+	PINCTRL_PIN(GPIO53, "GPIO53"),
+	PINCTRL_PIN(GPIO54, "GPIO54"),
+	PINCTRL_PIN(GPIO55, "GPIO55"),
+	PINCTRL_PIN(GPIO56, "GPIO56"),
+	PINCTRL_PIN(GPIO57, "GPIO57"),
+	PINCTRL_PIN(GPIO58, "GPIO58"),
+	PINCTRL_PIN(GPIO59, "GPIO59"),
+	PINCTRL_PIN(GPIO60, "GPIO60"),
+	PINCTRL_PIN(GPIO61, "GPIO61"),
+	PINCTRL_PIN(GPIO62, "GPIO62"),
+	PINCTRL_PIN(GPIO63, "GPIO63"),
+	PINCTRL_PIN(GPIO64, "GPIO64"),
+	PINCTRL_PIN(GPIO65, "GPIO65"),
+	PINCTRL_PIN(GPIO66, "GPIO66"),
+	PINCTRL_PIN(GPIO67, "GPIO67"),
+	PINCTRL_PIN(GPIO68, "GPIO68"),
+	PINCTRL_PIN(GPIO69, "GPIO69"),
+	PINCTRL_PIN(GPIO70, "GPIO70"),
+	PINCTRL_PIN(GPIO71, "GPIO71"),
+	PINCTRL_PIN(GPIO72, "GPIO72"),
+	PINCTRL_PIN(GPIO73, "GPIO73"),
+	PINCTRL_PIN(GPIO74, "GPIO74"),
+	PINCTRL_PIN(GPIO75, "GPIO75"),
+	PINCTRL_PIN(GPIO76, "GPIO76"),
+	PINCTRL_PIN(GPIO77, "GPIO77"),
+	PINCTRL_PIN(GPIO78, "GPIO78"),
+	PINCTRL_PIN(GPIO79, "GPIO79"),
+	PINCTRL_PIN(GPIO80, "GPIO80"),
+	PINCTRL_PIN(GPIO81, "GPIO81"),
+	PINCTRL_PIN(GPIO82, "GPIO82"),
+	PINCTRL_PIN(GPIO83, "GPIO83"),
+	PINCTRL_PIN(GPIO84, "GPIO84"),
+	PINCTRL_PIN(GPIO85, "GPIO85"),
+	PINCTRL_PIN(GPIO86, "GPIO86"),
+	PINCTRL_PIN(GPIO87, "GPIO87"),
+	PINCTRL_PIN(GPIO88, "GPIO88"),
+	PINCTRL_PIN(GPIO89, "GPIO89"),
+	PINCTRL_PIN(GPIO90, "GPIO90"),
+	PINCTRL_PIN(GPIO91, "GPIO91"),
+	PINCTRL_PIN(GPIO92, "GPIO92"),
+	PINCTRL_PIN(GPIO93, "GPIO93"),
+	PINCTRL_PIN(GPIO94, "GPIO94"),
+	PINCTRL_PIN(GPIO95, "GPIO95"),
+	PINCTRL_PIN(GPIO96, "GPIO96"),
+	PINCTRL_PIN(GPIO97, "GPIO97"),
+	PINCTRL_PIN(GPIO98, "GPIO98"),
+	PINCTRL_PIN(GPIO99, "GPIO99"),
+	PINCTRL_PIN(GPIO100, "GPIO100"),
+	PINCTRL_PIN(GPIO101, "GPIO101"),
+	PINCTRL_PIN(GPIO102, "GPIO102"),
+	PINCTRL_PIN(GPIO103, "GPIO103"),
+	PINCTRL_PIN(GPIO104, "GPIO104"),
+	PINCTRL_PIN(GPIO105, "GPIO105"),
+	PINCTRL_PIN(GPIO106, "GPIO106"),
+	PINCTRL_PIN(GPIO107, "GPIO107"),
+	PINCTRL_PIN(GPIO108, "GPIO108"),
+	PINCTRL_PIN(GPIO109, "GPIO109"),
+	PINCTRL_PIN(GPIO110, "GPIO110"),
+	PINCTRL_PIN(GPIO111, "GPIO111"),
+	PINCTRL_PIN(GPIO112, "GPIO112"),
+	PINCTRL_PIN(GPIO113, "GPIO113"),
+	PINCTRL_PIN(GPIO114, "GPIO114"),
+	PINCTRL_PIN(GPIO115, "GPIO115"),
+	PINCTRL_PIN(GPIO116, "GPIO116"),
+	PINCTRL_PIN(GPIO117, "GPIO117"),
+	PINCTRL_PIN(GPIO118, "GPIO118"),
+	PINCTRL_PIN(GPIO119, "GPIO119"),
+	PINCTRL_PIN(GPIO120, "GPIO120"),
+	PINCTRL_PIN(GPIO121, "GPIO121"),
+	PINCTRL_PIN(GPIO122, "GPIO122"),
+	PINCTRL_PIN(PWR_SCL, "PWR_SCL"),
+	PINCTRL_PIN(PWR_SDA, "PWR_SDA"),
+	PINCTRL_PIN(TDI, "TDI"),
+	PINCTRL_PIN(TMS, "TMS"),
+	PINCTRL_PIN(TCK, "TCK"),
+	PINCTRL_PIN(TDO, "TDO"),
+	PINCTRL_PIN(TRST, "TRST"),
+	PINCTRL_PIN(WAKEUP, "WAKEUP"),
+};
+
+struct pxa3xx_mfp_pin pxa168_mfp[] = {
+	/*       pin      offs   f0       f1           f2         f3           f4           f5        f6           f7  */
+	MFPR_168(GPIO0,   0x04C, DFIO,    NONE,        NONE,      MSP,         MMC3_CMD,    GPIO,     MMC3,        NONE),
+	MFPR_168(GPIO1,   0x050, DFIO,    NONE,        NONE,      MSP,         MMC3_CLK,    GPIO,     MMC3,        NONE),
+	MFPR_168(GPIO2,   0x054, DFIO,    NONE,        NONE,      MSP,         NONE,        GPIO,     MMC3,        NONE),
+	MFPR_168(GPIO3,   0x058, DFIO,    NONE,        NONE,      NONE,        NONE,        GPIO,     MMC3,        NONE),
+	MFPR_168(GPIO4,   0x05C, DFIO,    NONE,        NONE,      MSP_DAT3,    NONE,        GPIO,     MMC3,        NONE),
+	MFPR_168(GPIO5,   0x060, DFIO,    NONE,        NONE,      MSP,         NONE,        GPIO,     MMC3,        NONE),
+	MFPR_168(GPIO6,   0x064, DFIO,    NONE,        NONE,      MSP,         NONE,        GPIO,     MMC3,        NONE),
+	MFPR_168(GPIO7,   0x068, DFIO,    NONE,        NONE,      MSP,         NONE,        GPIO,     MMC3,        NONE),
+	MFPR_168(GPIO8,   0x06C, DFIO,    MMC2,        UART3_TX,  NONE,        MMC2_CMD,    GPIO,     MMC3_CLK,    NONE),
+	MFPR_168(GPIO9,   0x070, DFIO,    MMC2,        UART3,     NONE,        MMC2_CLK,    GPIO,     MMC3_CMD,    NONE),
+	MFPR_168(GPIO10,  0x074, DFIO,    MMC2,        UART3,     NONE,        NONE,        GPIO,     MSP_DAT3,    NONE),
+	MFPR_168(GPIO11,  0x078, DFIO,    MMC2,        UART3,     NONE,        NONE,        GPIO,     MSP,         NONE),
+	MFPR_168(GPIO12,  0x07C, DFIO,    MMC2,        UART3,     NONE,        NONE,        GPIO,     MSP,         NONE),
+	MFPR_168(GPIO13,  0x080, DFIO,    MMC2,        UART3,     NONE,        NONE,        GPIO,     MSP,         NONE),
+	MFPR_168(GPIO14,  0x084, DFIO,    MMC2,        NONE,      NONE,        NONE,        GPIO,     MSP,         NONE),
+	MFPR_168(GPIO15,  0x088, DFIO,    MMC2,        NONE,      NONE,        NONE,        GPIO,     MSP,         NONE),
+	MFPR_168(GPIO16,  0x08C, GPIO,    NAND,        SMC_CS0,   SMC_CS1,     NONE,        NONE,     MMC3,        NONE),
+	MFPR_168(GPIO17,  0x090, NAND,    NONE,        NONE,      NONE,        NONE,        GPIO,     MSP,         NONE),
+	MFPR_168(GPIO18,  0x094, GPIO,    NAND,        SMC_CS1,   SMC_CS0,     NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO19,  0x098, SMC_CS0, NONE,        NONE,      CF,          NONE,        GPIO,     NONE,        NONE),
+	MFPR_168(GPIO20,  0x09C, GPIO,    NONE,        SMC_CS1,   CF,          CF_RDY,      NONE,     NONE,        NONE),
+	MFPR_168(GPIO21,  0x0A0, NAND,    MMC2_CLK,    NONE,      NONE,        NONE,        GPIO,     NONE,        NONE),
+	MFPR_168(GPIO22,  0x0A4, NAND,    MMC2_CMD,    NONE,      NONE,        NONE,        GPIO,     NONE,        NONE),
+	MFPR_168(GPIO23,  0x0A8, SMC,     NAND,        NONE,      CF,          NONE,        GPIO,     NONE,        NONE),
+	MFPR_168(GPIO24,  0x0AC, NAND,    NONE,        NONE,      NONE,        NONE,        GPIO,     NONE,        NONE),
+	MFPR_168(GPIO25,  0x0B0, SMC,     NAND,        NONE,      CF,          NONE,        GPIO,     NONE,        NONE),
+	MFPR_168(GPIO26,  0x0B4, GPIO,    NAND,        NONE,      NONE,        CF,          NONE,     NONE,        NONE),
+	MFPR_168(GPIO27,  0x0B8, SMC_INT, NAND,        SMC,       NONE,        SMC_RDY,     GPIO,     NONE,        NONE),
+	MFPR_168(GPIO28,  0x0BC, SMC_RDY, MMC4,        SMC,       CF_RDY,      NONE,        GPIO,     MMC2_CMD,    NONE),
+	MFPR_168(GPIO29,  0x0C0, SMC,     MMC4,        NONE,      CF,          NONE,        GPIO,     MMC2_CLK,    KP_DK),
+	MFPR_168(GPIO30,  0x0C4, SMC,     MMC4,        UART3_TX,  CF,          NONE,        GPIO,     MMC2,        KP_DK),
+	MFPR_168(GPIO31,  0x0C8, SMC,     MMC4,        UART3,     CF,          NONE,        GPIO,     MMC2,        KP_DK),
+	MFPR_168(GPIO32,  0x0CC, SMC,     MMC4,        UART3,     CF,          NONE,        GPIO,     MMC2,        KP_DK),
+	MFPR_168(GPIO33,  0x0D0, SMC,     MMC4,        UART3,     CF,          CF_nINPACK,  GPIO,     MMC2,        KP_DK),
+	MFPR_168(GPIO34,  0x0D4, GPIO,    NONE,        SMC_CS1,   CF,          CF_nWAIT,    NONE,     MMC3,        KP_DK),
+	MFPR_168(GPIO35,  0x0D8, GPIO,    NONE,        SMC,       CF_nINPACK,  NONE,        NONE,     MMC3_CMD,    KP_DK),
+	MFPR_168(GPIO36,  0x0DC, GPIO,    NONE,        SMC,       CF_nWAIT,    NONE,        NONE,     MMC3_CLK,    KP_DK),
+	MFPR_168(GPIO37,  0x000, GPIO,    MMC1,        NONE,      KP_MKOUT,    CCIC,        XP,       KP_MKIN,     KP_DK),
+	MFPR_168(GPIO38,  0x004, GPIO,    MMC1,        NONE,      KP_MKOUT,    CCIC,        XP,       KP_MKIN,     KP_DK),
+	MFPR_168(GPIO39,  0x008, GPIO,    NONE,        NONE,      KP_MKOUT,    CCIC,        XP,       KP_MKIN,     KP_DK),
+	MFPR_168(GPIO40,  0x00C, GPIO,    MMC1,        MSP,       KP_MKOUT,    CCIC,        XP,       KP_MKIN,     KP_DK),
+	MFPR_168(GPIO41,  0x010, GPIO,    MMC1,        MSP,       NONE,        CCIC,        XP,       KP_MKIN,     KP_DK),
+	MFPR_168(GPIO42,  0x014, GPIO,    I2C,         NONE,      MSP,         CCIC,        XP,       KP_MKIN,     KP_DK),
+	MFPR_168(GPIO43,  0x018, GPIO,    MMC1,        MSP,       MSP_INS,     NONE,        NONE,     KP_MKIN,     KP_DK),
+	MFPR_168(GPIO44,  0x01C, GPIO,    MMC1,        MSP_DAT3,  MSP,         CCIC,        XP,       KP_MKIN,     KP_DK),
+	MFPR_168(GPIO45,  0x020, GPIO,    NONE,        NONE,      MSP,         CCIC,        XP,       NONE,        KP_DK),
+	MFPR_168(GPIO46,  0x024, GPIO,    MMC1,        MSP_INS,   MSP,         CCIC,        NONE,     KP_MKOUT,    KP_DK),
+	MFPR_168(GPIO47,  0x028, GPIO,    NONE,        NONE,      MSP_INS,     NONE,        XP,       NONE,        KP_DK),
+	MFPR_168(GPIO48,  0x02C, GPIO,    MMC1,        NONE,      MSP_DAT3,    CCIC,        NONE,     NONE,        KP_DK),
+	MFPR_168(GPIO49,  0x030, GPIO,    MMC1,        NONE,      MSP,         NONE,        XD,       KP_MKOUT,    NONE),
+	MFPR_168(GPIO50,  0x034, GPIO,    I2C,         NONE,      MSP,         CCIC,        XD,       KP_MKOUT,    NONE),
+	MFPR_168(GPIO51,  0x038, GPIO,    MMC1,        NONE,      MSP,         NONE,        XD,       KP_MKOUT,    NONE),
+	MFPR_168(GPIO52,  0x03C, GPIO,    MMC1,        NONE,      MSP,         NONE,        XD,       KP_MKOUT,    NONE),
+	MFPR_168(GPIO53,  0x040, GPIO,    MMC1,        NONE,      NONE,        NONE,        XD,       KP_MKOUT,    NONE),
+	MFPR_168(GPIO54,  0x044, GPIO,    MMC1,        NONE,      NONE,        CCIC,        XD,       KP_MKOUT,    NONE),
+	MFPR_168(GPIO55,  0x048, GPIO,    NONE,        NONE,      MSP,         CCIC,        XD,       KP_MKOUT,    NONE),
+	MFPR_168(GPIO56,  0x0E0, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO57,  0x0E4, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO58,  0x0E8, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO59,  0x0EC, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO60,  0x0F0, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO61,  0x0F4, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO62,  0x0F8, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO63,  0x0FC, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO64,  0x100, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO65,  0x104, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO66,  0x108, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO67,  0x10C, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO68,  0x110, GPIO,    LCD,         NONE,      XD,          NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO69,  0x114, GPIO,    LCD,         NONE,      XD,          NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO70,  0x118, GPIO,    LCD,         NONE,      XD,          NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO71,  0x11C, GPIO,    LCD,         NONE,      XD,          NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO72,  0x120, GPIO,    LCD,         NONE,      XD,          NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO73,  0x124, GPIO,    LCD,         NONE,      XD,          NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO74,  0x128, GPIO,    LCD,         PWM,       XD,          NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO75,  0x12C, GPIO,    LCD,         PWM,       XD,          ONE_WIRE,    NONE,     NONE,        NONE),
+	MFPR_168(GPIO76,  0x130, GPIO,    LCD,         PWM,       I2C,         NONE,        NONE,     MSP_INS,     NONE),
+	MFPR_168(GPIO77,  0x134, GPIO,    LCD,         PWM1,      I2C,         ONE_WIRE,    NONE,     XD,          NONE),
+	MFPR_168(GPIO78,  0x138, GPIO,    LCD,         NONE,      NONE,        NONE,        MMC4,     NONE,        NONE),
+	MFPR_168(GPIO79,  0x13C, GPIO,    LCD,         NONE,      NONE,        ONE_WIRE,    MMC4,     NONE,        NONE),
+	MFPR_168(GPIO80,  0x140, GPIO,    LCD,         NONE,      I2C,         NONE,        MMC4,     NONE,        NONE),
+	MFPR_168(GPIO81,  0x144, GPIO,    LCD,         NONE,      I2C,         ONE_WIRE,    MMC4,     NONE,        NONE),
+	MFPR_168(GPIO82,  0x148, GPIO,    LCD,         PWM,       NONE,        NONE,        MMC4,     NONE,        NONE),
+	MFPR_168(GPIO83,  0x14C, GPIO,    LCD,         PWM,       NONE,        RESET,       MMC4,     NONE,        NONE),
+	MFPR_168(GPIO84,  0x150, GPIO,    NONE,        PWM,       ONE_WIRE,    PWM1,        NONE,     NONE,        EXT_32K_IN),
+	MFPR_168(GPIO85,  0x154, GPIO,    NONE,        PWM1,      NONE,        NONE,        NONE,     NONE,        USB),
+	MFPR_168(GPIO86,  0x158, GPIO,    MMC2,        UART2,     NONE,        JTAG,        ETH_TX,   SSP5_TX,     SSP5),
+	MFPR_168(GPIO87,  0x15C, GPIO,    MMC2,        UART2,     NONE,        JTAG,        ETH_TX,   SSP5,        SSP5_TX),
+	MFPR_168(GPIO88,  0x160, GPIO,    MMC2,        UART2,     UART2_TX,    JTAG,        ETH_TX,   ETH_RX,      SSP5),
+	MFPR_168(GPIO89,  0x164, GPIO,    MMC2,        UART2_TX,  UART2,       JTAG,        ETH_TX,   ETH_RX,      SSP5),
+	MFPR_168(GPIO90,  0x168, GPIO,    MMC2,        NONE,      SSP3,        JTAG,        ETH_TX,   ETH_RX,      NONE),
+	MFPR_168(GPIO91,  0x16C, GPIO,    MMC2,        NONE,      SSP3,        SSP4,        ETH_TX,   ETH_RX,      NONE),
+	MFPR_168(GPIO92,  0x170, GPIO,    MMC2,        NONE,      SSP3,        SSP3_TX,     ETH,      NONE,        NONE),
+	MFPR_168(GPIO93,  0x174, GPIO,    MMC2,        NONE,      SSP3_TX,     SSP3,        ETH,      NONE,        NONE),
+	MFPR_168(GPIO94,  0x178, GPIO,    MMC2_CMD,    SSP3,      AC97_SYSCLK, AC97,        ETH,      NONE,        NONE),
+	MFPR_168(GPIO95,  0x17C, GPIO,    MMC2_CLK,    NONE,      NONE,        AC97,        ETH,      NONE,        NONE),
+	MFPR_168(GPIO96,  0x180, GPIO,    PWM,         NONE,      MMC2,        NONE,        ETH_RX,   ETH_TX,      NONE),
+	MFPR_168(GPIO97,  0x184, GPIO,    PWM,         ONE_WIRE,  NONE,        NONE,        ETH_RX,   ETH_TX,      NONE),
+	MFPR_168(GPIO98,  0x188, GPIO,    PWM1,        UART3_TX,  UART3,       NONE,        ETH_RX,   ETH_TX,      NONE),
+	MFPR_168(GPIO99,  0x18C, GPIO,    ONE_WIRE,    UART3,     UART3_TX,    NONE,        ETH_RX,   ETH_TX,      NONE),
+	MFPR_168(GPIO100, 0x190, GPIO,    NONE,        UART3_CTS, UART3,       NONE,        ETH,      NONE,        NONE),
+	MFPR_168(GPIO101, 0x194, GPIO,    NONE,        UART3,     UART3_CTS,   NONE,        ETH,      NONE,        NONE),
+	MFPR_168(GPIO102, 0x198, GPIO,    I2C,         UART3,     SSP4,        NONE,        NONE,     NONE,        NONE),
+	MFPR_168(GPIO103, 0x19C, GPIO,    I2C,         UART3,     SSP4,        SSP2,        ETH,      NONE,        NONE),
+	MFPR_168(GPIO104, 0x1A0, GPIO,    PWM,         UART1,     SSP4,        SSP4_TX,     AC97,     KP_MKOUT,    NONE),
+	MFPR_168(GPIO105, 0x1A4, GPIO,    I2C,         UART1,     SSP4_TX,     SSP4,        AC97,     KP_MKOUT,    NONE),
+	MFPR_168(GPIO106, 0x1A8, GPIO,    I2C,         PWM1,      AC97_SYSCLK, MMC2,        NONE,     KP_MKOUT,    NONE),
+	MFPR_168(GPIO107, 0x1AC, GPIO,    UART1_TX,    UART1,     NONE,        SSP2,        MSP_DAT3, NONE,        KP_MKIN),
+	MFPR_168(GPIO108, 0x1B0, GPIO,    UART1,       UART1_TX,  NONE,        SSP2_TX,     MSP,      NONE,        KP_MKIN),
+	MFPR_168(GPIO109, 0x1B4, GPIO,    UART1_CTS,   UART1,     NONE,        AC97_SYSCLK, MSP,      NONE,        KP_MKIN),
+	MFPR_168(GPIO110, 0x1B8, GPIO,    UART1,       UART1_CTS, NONE,        SMC_RDY,     MSP,      NONE,        KP_MKIN),
+	MFPR_168(GPIO111, 0x1BC, GPIO,    UART1_nRI,   UART1,     SSP3,        SSP2,        MSP,      XD,          KP_MKOUT),
+	MFPR_168(GPIO112, 0x1C0, GPIO,    UART1_DTR,   UART1,     ONE_WIRE,    SSP2,        MSP,      XD,          KP_MKOUT),
+	MFPR_168(GPIO113, 0x1C4, GPIO,    NONE,        NONE,      NONE,        NONE,        NONE,     AC97_SYSCLK, NONE),
+	MFPR_168(GPIO114, 0x1C8, GPIO,    SSP1,        NONE,      NONE,        NONE,        NONE,     AC97,        NONE),
+	MFPR_168(GPIO115, 0x1CC, GPIO,    SSP1,        NONE,      NONE,        NONE,        NONE,     AC97,        NONE),
+	MFPR_168(GPIO116, 0x1D0, GPIO,    SSP1_TX,     SSP1,      NONE,        NONE,        NONE,     AC97,        NONE),
+	MFPR_168(GPIO117, 0x1D4, GPIO,    SSP1,        SSP1_TX,   NONE,        MMC2_CMD,    NONE,     AC97,        NONE),
+	MFPR_168(GPIO118, 0x1D8, GPIO,    SSP2,        NONE,      NONE,        MMC2_CLK,    NONE,     AC97,        KP_MKIN),
+	MFPR_168(GPIO119, 0x1DC, GPIO,    SSP2,        NONE,      NONE,        MMC2,        NONE,     AC97,        KP_MKIN),
+	MFPR_168(GPIO120, 0x1E0, GPIO,    SSP2,        SSP2_TX,   NONE,        MMC2,        NONE,     NONE,        KP_MKIN),
+	MFPR_168(GPIO121, 0x1E4, GPIO,    SSP2_TX,     SSP2,      NONE,        MMC2,        NONE,     NONE,        KP_MKIN),
+	MFPR_168(GPIO122, 0x1E8, GPIO,    AC97_SYSCLK, SSP2,      PWM,         MMC2,        NONE,     NONE,        NONE),
+	MFPR_168(PWR_SCL, 0x1EC, PWRI2C,  NONE,        NONE,      NONE,        NONE,        NONE,     GPIO,        MMC4),
+	MFPR_168(PWR_SDA, 0x1F0, PWRI2C,  NONE,        NONE,      NONE,        NONE,        NONE,     GPIO,        NONE),
+	MFPR_168(TDI,     0x1F4, JTAG,    PWM1,        UART2,     MMC4,        SSP5,        NONE,     XD,          MMC4),
+	MFPR_168(TMS,     0x1F8, JTAG,    PWM,         UART2,     NONE,        SSP5,        NONE,     XD,          MMC4),
+	MFPR_168(TCK,     0x1FC, JTAG,    PWM,         UART2,     UART2_TX,    SSP5,        NONE,     XD,          MMC4),
+	MFPR_168(TDO,     0x200, JTAG,    PWM,         UART2_TX,  UART2,       SSP5_TX,     NONE,     XD,          MMC4),
+	MFPR_168(TRST,    0x204, JTAG,    ONE_WIRE,    SSP2,      SSP3,        AC97_SYSCLK, NONE,     XD,          MMC4),
+	MFPR_168(WAKEUP,  0x208, WAKEUP,  ONE_WIRE,    PWM1,      PWM,         SSP2,        NONE,     GPIO,        MMC4),
+};
+
+static const unsigned p168_jtag_pin1[] = {TDI, TMS, TCK, TDO, TRST};
+static const unsigned p168_wakeup_pin1[] = {WAKEUP};
+static const unsigned p168_ssp1rx_pin1[] = {GPIO114, GPIO115, GPIO116};
+static const unsigned p168_ssp1tx_pin1[] = {GPIO117};
+static const unsigned p168_ssp4rx_pin1[] = {GPIO102, GPIO103, GPIO104};
+static const unsigned p168_ssp4tx_pin1[] = {GPIO105};
+static const unsigned p168_ssp5rx_pin1[] = {GPIO86, GPIO88, GPIO89};
+static const unsigned p168_ssp5tx_pin1[] = {GPIO87};
+static const unsigned p168_i2c_pin1[] = {GPIO105, GPIO106};
+static const unsigned p168_pwri2c_pin1[] = {PWR_SCL, PWR_SDA};
+static const unsigned p168_mmc1_pin1[] = {GPIO40, GPIO41, GPIO43, GPIO46,
+	GPIO49, GPIO51, GPIO52, GPIO53};
+static const unsigned p168_mmc2_data_pin1[] = {GPIO90, GPIO91, GPIO92, GPIO93};
+static const unsigned p168_mmc2_cmd_pin1[] = {GPIO94};
+static const unsigned p168_mmc2_clk_pin1[] = {GPIO95};
+static const unsigned p168_mmc3_data_pin1[] = {GPIO0, GPIO1, GPIO2, GPIO3,
+	GPIO4, GPIO5, GPIO6, GPIO7};
+static const unsigned p168_mmc3_cmd_pin1[] = {GPIO9};
+static const unsigned p168_mmc3_clk_pin1[] = {GPIO8};
+static const unsigned p168_eth_pin1[] = {GPIO92, GPIO93, GPIO100, GPIO101,
+	GPIO103};
+static const unsigned p168_ethtx_pin1[] = {GPIO86, GPIO87, GPIO88, GPIO89,
+	GPIO90, GPIO91};
+static const unsigned p168_ethrx_pin1[] = {GPIO94, GPIO95, GPIO96, GPIO97,
+	GPIO98, GPIO99};
+static const unsigned p168_uart1rx_pin1[] = {GPIO107};
+static const unsigned p168_uart1tx_pin1[] = {GPIO108};
+static const unsigned p168_uart3rx_pin1[] = {GPIO98, GPIO100, GPIO101};
+static const unsigned p168_uart3tx_pin1[] = {GPIO99};
+static const unsigned p168_msp_pin1[] = {GPIO40, GPIO41, GPIO42, GPIO43,
+	GPIO44, GPIO50};
+static const unsigned p168_ccic_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40,
+	GPIO41, GPIO42, GPIO44, GPIO45, GPIO46, GPIO48, GPIO54, GPIO55};
+static const unsigned p168_xd_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40,
+	GPIO41, GPIO42, GPIO44, GPIO45, GPIO47, GPIO48, GPIO49, GPIO50,
+	GPIO51, GPIO52};
+static const unsigned p168_lcd_pin1[] = {GPIO56, GPIO57, GPIO58, GPIO59,
+	GPIO60, GPIO61, GPIO62, GPIO63, GPIO64, GPIO65, GPIO66, GPIO67,
+	GPIO68, GPIO69, GPIO70, GPIO71, GPIO72, GPIO73, GPIO74, GPIO75,
+	GPIO76, GPIO77, GPIO78, GPIO79, GPIO80, GPIO81, GPIO82, GPIO83};
+static const unsigned p168_dfio_pin1[] = {GPIO0, GPIO1, GPIO2, GPIO3,
+	GPIO4, GPIO5, GPIO6, GPIO7, GPIO8, GPIO9, GPIO10, GPIO11, GPIO12,
+	GPIO13, GPIO14, GPIO15};
+static const unsigned p168_nand_pin1[] = {GPIO16, GPIO17, GPIO21, GPIO22,
+	GPIO24, GPIO26};
+static const unsigned p168_smc_pin1[] = {GPIO23, GPIO25, GPIO29, GPIO35,
+	GPIO36};
+static const unsigned p168_smccs0_pin1[] = {GPIO18};
+static const unsigned p168_smccs1_pin1[] = {GPIO34};
+static const unsigned p168_smcrdy_pin1[] = {GPIO28};
+static const unsigned p168_ac97sysclk_pin1[] = {GPIO113};
+static const unsigned p168_ac97_pin1[] = {GPIO114, GPIO115, GPIO117, GPIO118,
+	GPIO119};
+static const unsigned p168_cf_pin1[] = {GPIO19, GPIO20, GPIO23, GPIO25,
+	GPIO28, GPIO29, GPIO30, GPIO31, GPIO32, GPIO33, GPIO34, GPIO35,
+	GPIO36};
+static const unsigned p168_kpmkin_pin1[] = {GPIO109, GPIO110, GPIO121};
+static const unsigned p168_kpmkout_pin1[] = {GPIO111, GPIO112};
+static const unsigned p168_gpio86_pin1[] = {WAKEUP};
+static const unsigned p168_gpio86_pin2[] = {GPIO86};
+static const unsigned p168_gpio87_pin1[] = {GPIO87};
+static const unsigned p168_gpio87_pin2[] = {PWR_SDA};
+static const unsigned p168_gpio88_pin1[] = {GPIO88};
+static const unsigned p168_gpio88_pin2[] = {PWR_SCL};
+
+static struct pxa3xx_pin_group pxa168_grps[] = {
+	GRP_168("uart1rx-1", UART1, p168_uart1rx_pin1),
+	GRP_168("uart1tx-1", UART1_TX, p168_uart1tx_pin1),
+	GRP_168("uart3rx-1", UART3, p168_uart3rx_pin1),
+	GRP_168("uart3tx-1", UART3_TX, p168_uart3tx_pin1),
+	GRP_168("ssp1rx-1", SSP1, p168_ssp1rx_pin1),
+	GRP_168("ssp1tx-1", SSP1_TX, p168_ssp1tx_pin1),
+	GRP_168("ssp4rx-1", SSP4, p168_ssp4rx_pin1),
+	GRP_168("ssp4tx-1", SSP4_TX, p168_ssp4tx_pin1),
+	GRP_168("ssp5rx-1", SSP5, p168_ssp5rx_pin1),
+	GRP_168("ssp5tx-1", SSP5_TX, p168_ssp5tx_pin1),
+	GRP_168("jtag", JTAG, p168_jtag_pin1),
+	GRP_168("wakeup", WAKEUP, p168_wakeup_pin1),
+	GRP_168("i2c", I2C, p168_i2c_pin1),
+	GRP_168("pwri2c", PWRI2C, p168_pwri2c_pin1),
+	GRP_168("mmc1 8p1", MMC1, p168_mmc1_pin1),
+	GRP_168("mmc2 4p1", MMC2, p168_mmc2_data_pin1),
+	GRP_168("mmc2 cmd1", MMC2_CMD, p168_mmc2_cmd_pin1),
+	GRP_168("mmc2 clk1", MMC2_CLK, p168_mmc2_clk_pin1),
+	GRP_168("mmc3 8p1", MMC3, p168_mmc3_data_pin1),
+	GRP_168("mmc3 cmd1", MMC3_CMD, p168_mmc3_cmd_pin1),
+	GRP_168("mmc3 clk1", MMC3_CLK, p168_mmc3_clk_pin1),
+	GRP_168("eth", ETH, p168_eth_pin1),
+	GRP_168("eth rx", ETH_RX, p168_ethrx_pin1),
+	GRP_168("eth tx", ETH_TX, p168_ethtx_pin1),
+	GRP_168("msp", MSP, p168_msp_pin1),
+	GRP_168("ccic", CCIC, p168_ccic_pin1),
+	GRP_168("xd", XD, p168_xd_pin1),
+	GRP_168("lcd", LCD, p168_lcd_pin1),
+	GRP_168("dfio", DFIO, p168_dfio_pin1),
+	GRP_168("nand", NAND, p168_nand_pin1),
+	GRP_168("smc", SMC, p168_smc_pin1),
+	GRP_168("smc cs0", SMC_CS0, p168_smccs0_pin1),
+	GRP_168("smc cs1", SMC_CS1, p168_smccs1_pin1),
+	GRP_168("smc rdy", SMC_RDY, p168_smcrdy_pin1),
+	GRP_168("ac97 sysclk", AC97_SYSCLK, p168_ac97sysclk_pin1),
+	GRP_168("ac97", AC97, p168_ac97_pin1),
+	GRP_168("cf", CF, p168_cf_pin1),
+	GRP_168("kp mkin 3p1", KP_MKIN, p168_kpmkin_pin1),
+	GRP_168("kp mkout 2p1", KP_MKOUT, p168_kpmkout_pin1),
+	GRP_168("gpio86-1", GPIO, p168_gpio86_pin1),
+	GRP_168("gpio86-2", GPIO, p168_gpio86_pin2),
+	GRP_168("gpio87-1", GPIO, p168_gpio87_pin1),
+	GRP_168("gpio87-2", GPIO, p168_gpio87_pin2),
+	GRP_168("gpio88-1", GPIO, p168_gpio88_pin1),
+	GRP_168("gpio88-2", GPIO, p168_gpio88_pin2),
+};
+
+static const char * const p168_uart1rx_grps[] = {"uart1rx-1"};
+static const char * const p168_uart1tx_grps[] = {"uart1tx-1"};
+static const char * const p168_uart3rx_grps[] = {"uart3rx-1"};
+static const char * const p168_uart3tx_grps[] = {"uart3tx-1"};
+static const char * const p168_ssp1rx_grps[] = {"ssp1rx-1"};
+static const char * const p168_ssp1tx_grps[] = {"ssp1tx-1"};
+static const char * const p168_ssp4rx_grps[] = {"ssp4rx-1"};
+static const char * const p168_ssp4tx_grps[] = {"ssp4tx-1"};
+static const char * const p168_ssp5rx_grps[] = {"ssp5rx-1"};
+static const char * const p168_ssp5tx_grps[] = {"ssp5tx-1"};
+static const char * const p168_i2c_grps[] = {"i2c"};
+static const char * const p168_pwri2c_grps[] = {"pwri2c"};
+static const char * const p168_mmc1_grps[] = {"mmc1 8p1"};
+static const char * const p168_mmc2_data_grps[] = {"mmc2 4p1"};
+static const char * const p168_mmc2_cmd_grps[] = {"mmc2 cmd1"};
+static const char * const p168_mmc2_clk_grps[] = {"mmc2 clk1"};
+static const char * const p168_mmc3_data_grps[] = {"mmc3 8p1"};
+static const char * const p168_mmc3_cmd_grps[] = {"mmc3 cmd1"};
+static const char * const p168_mmc3_clk_grps[] = {"mmc3 clk1"};
+static const char * const p168_eth_grps[] = {"eth"};
+static const char * const p168_ethrx_grps[] = {"eth rx"};
+static const char * const p168_ethtx_grps[] = {"eth tx"};
+static const char * const p168_msp_grps[] = {"msp"};
+static const char * const p168_ccic_grps[] = {"ccic"};
+static const char * const p168_xd_grps[] = {"xd"};
+static const char * const p168_lcd_grps[] = {"lcd"};
+static const char * const p168_dfio_grps[] = {"dfio"};
+static const char * const p168_nand_grps[] = {"nand"};
+static const char * const p168_smc_grps[] = {"smc"};
+static const char * const p168_smccs0_grps[] = {"smc cs0"};
+static const char * const p168_smccs1_grps[] = {"smc cs1"};
+static const char * const p168_smcrdy_grps[] = {"smc rdy"};
+static const char * const p168_ac97sysclk_grps[] = {"ac97 sysclk"};
+static const char * const p168_ac97_grps[] = {"ac97"};
+static const char * const p168_cf_grps[] = {"cf"};
+static const char * const p168_kpmkin_grps[] = {"kp mkin 3p1"};
+static const char * const p168_kpmkout_grps[] = {"kp mkout 2p1"};
+static const char * const p168_gpio86_grps[] = {"gpio86-1", "gpio86-2"};
+static const char * const p168_gpio87_grps[] = {"gpio87-1", "gpio87-2"};
+static const char * const p168_gpio88_grps[] = {"gpio88-1", "gpio88-2"};
+
+static struct pxa3xx_pmx_func pxa168_funcs[] = {
+	{"uart1 rx",	ARRAY_AND_SIZE(p168_uart1rx_grps)},
+	{"uart1 tx",	ARRAY_AND_SIZE(p168_uart1tx_grps)},
+	{"uart3 rx",	ARRAY_AND_SIZE(p168_uart3rx_grps)},
+	{"uart3 tx",	ARRAY_AND_SIZE(p168_uart3tx_grps)},
+	{"ssp1 rx",	ARRAY_AND_SIZE(p168_ssp1rx_grps)},
+	{"ssp1 tx",	ARRAY_AND_SIZE(p168_ssp1tx_grps)},
+	{"ssp4 rx",	ARRAY_AND_SIZE(p168_ssp4rx_grps)},
+	{"ssp4 tx",	ARRAY_AND_SIZE(p168_ssp4tx_grps)},
+	{"ssp5 rx",	ARRAY_AND_SIZE(p168_ssp5rx_grps)},
+	{"ssp5 tx",	ARRAY_AND_SIZE(p168_ssp5tx_grps)},
+	{"i2c",		ARRAY_AND_SIZE(p168_i2c_grps)},
+	{"pwri2c",	ARRAY_AND_SIZE(p168_pwri2c_grps)},
+	{"mmc1",	ARRAY_AND_SIZE(p168_mmc1_grps)},
+	{"mmc2",	ARRAY_AND_SIZE(p168_mmc2_data_grps)},
+	{"mmc2 cmd",	ARRAY_AND_SIZE(p168_mmc2_cmd_grps)},
+	{"mmc2 clk",	ARRAY_AND_SIZE(p168_mmc2_clk_grps)},
+	{"mmc3",	ARRAY_AND_SIZE(p168_mmc3_data_grps)},
+	{"mmc3 cmd",	ARRAY_AND_SIZE(p168_mmc3_cmd_grps)},
+	{"mmc3 clk",	ARRAY_AND_SIZE(p168_mmc3_clk_grps)},
+	{"eth",		ARRAY_AND_SIZE(p168_eth_grps)},
+	{"eth rx",	ARRAY_AND_SIZE(p168_ethrx_grps)},
+	{"eth tx",	ARRAY_AND_SIZE(p168_ethtx_grps)},
+	{"msp",		ARRAY_AND_SIZE(p168_msp_grps)},
+	{"ccic",	ARRAY_AND_SIZE(p168_ccic_grps)},
+	{"xd",		ARRAY_AND_SIZE(p168_xd_grps)},
+	{"lcd",		ARRAY_AND_SIZE(p168_lcd_grps)},
+	{"dfio",	ARRAY_AND_SIZE(p168_dfio_grps)},
+	{"nand",	ARRAY_AND_SIZE(p168_nand_grps)},
+	{"smc",		ARRAY_AND_SIZE(p168_smc_grps)},
+	{"smc cs0",	ARRAY_AND_SIZE(p168_smccs0_grps)},
+	{"smc cs1",	ARRAY_AND_SIZE(p168_smccs1_grps)},
+	{"smc rdy",	ARRAY_AND_SIZE(p168_smcrdy_grps)},
+	{"ac97",	ARRAY_AND_SIZE(p168_ac97_grps)},
+	{"ac97 sysclk",	ARRAY_AND_SIZE(p168_ac97sysclk_grps)},
+	{"cf",		ARRAY_AND_SIZE(p168_cf_grps)},
+	{"kpmkin",	ARRAY_AND_SIZE(p168_kpmkin_grps)},
+	{"kpmkout",	ARRAY_AND_SIZE(p168_kpmkout_grps)},
+	{"gpio86",	ARRAY_AND_SIZE(p168_gpio86_grps)},
+	{"gpio87",	ARRAY_AND_SIZE(p168_gpio87_grps)},
+	{"gpio88",	ARRAY_AND_SIZE(p168_gpio88_grps)},
+};
+
+static struct pinctrl_desc pxa168_pctrl_desc = {
+	.name		= "pxa168-pinctrl",
+	.owner		= THIS_MODULE,
+};
+
+static struct pxa3xx_pinmux_info pxa168_info = {
+	.mfp		= pxa168_mfp,
+	.num_mfp	= ARRAY_SIZE(pxa168_mfp),
+	.grps		= pxa168_grps,
+	.num_grps	= ARRAY_SIZE(pxa168_grps),
+	.funcs		= pxa168_funcs,
+	.num_funcs	= ARRAY_SIZE(pxa168_funcs),
+	.num_gpio	= 128,
+	.desc		= &pxa168_pctrl_desc,
+	.pads		= pxa168_pads,
+	.num_pads	= ARRAY_SIZE(pxa168_pads),
+
+	.cputype	= PINCTRL_PXA168,
+	.ds_mask	= PXA168_DS_MASK,
+	.ds_shift	= PXA168_DS_SHIFT,
+};
+
+static int __devinit pxa168_pinmux_probe(struct platform_device *pdev)
+{
+	return pxa3xx_pinctrl_register(pdev, &pxa168_info);
+}
+
+static int __devexit pxa168_pinmux_remove(struct platform_device *pdev)
+{
+	return pxa3xx_pinctrl_unregister(pdev);
+}
+
+static struct platform_driver pxa168_pinmux_driver = {
+	.driver = {
+		.name	= "pxa168-pinmux",
+		.owner	= THIS_MODULE,
+	},
+	.probe	= pxa168_pinmux_probe,
+	.remove	= __devexit_p(pxa168_pinmux_remove),
+};
+
+static int __init pxa168_pinmux_init(void)
+{
+	return platform_driver_register(&pxa168_pinmux_driver);
+}
+core_initcall_sync(pxa168_pinmux_init);
+
+static void __exit pxa168_pinmux_exit(void)
+{
+	platform_driver_unregister(&pxa168_pinmux_driver);
+}
+module_exit(pxa168_pinmux_exit);
+
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("PXA3xx pin control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-pxa3xx.c b/drivers/pinctrl/pinctrl-pxa3xx.c
new file mode 100644
index 0000000..079dce0
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-pxa3xx.c
@@ -0,0 +1,244 @@
+/*
+ *  linux/drivers/pinctrl/pinctrl-pxa3xx.c
+ *
+ *  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
+ *  publishhed by the Free Software Foundation.
+ *
+ *  Copyright (C) 2011, Marvell Technology Group Ltd.
+ *
+ *  Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include "pinctrl-pxa3xx.h"
+
+static struct pinctrl_gpio_range pxa3xx_pinctrl_gpio_range = {
+	.name		= "PXA3xx GPIO",
+	.id		= 0,
+	.base		= 0,
+	.pin_base	= 0,
+};
+
+static int pxa3xx_list_groups(struct pinctrl_dev *pctrldev, unsigned selector)
+{
+	struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	if (selector >= info->num_grps)
+		return -EINVAL;
+	return 0;
+}
+
+static const char *pxa3xx_get_group_name(struct pinctrl_dev *pctrldev,
+					 unsigned selector)
+{
+	struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	if (selector >= info->num_grps)
+		return NULL;
+	return info->grps[selector].name;
+}
+
+static int pxa3xx_get_group_pins(struct pinctrl_dev *pctrldev,
+				 unsigned selector,
+				 const unsigned **pins,
+				 unsigned *num_pins)
+{
+	struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	if (selector >= info->num_grps)
+		return -EINVAL;
+	*pins = info->grps[selector].pins;
+	*num_pins = info->grps[selector].npins;
+	return 0;
+}
+
+static struct pinctrl_ops pxa3xx_pctrl_ops = {
+	.list_groups	= pxa3xx_list_groups,
+	.get_group_name	= pxa3xx_get_group_name,
+	.get_group_pins	= pxa3xx_get_group_pins,
+};
+
+static int pxa3xx_pmx_list_func(struct pinctrl_dev *pctrldev, unsigned func)
+{
+	struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	if (func >= info->num_funcs)
+		return -EINVAL;
+	return 0;
+}
+
+static const char *pxa3xx_pmx_get_func_name(struct pinctrl_dev *pctrldev,
+					    unsigned func)
+{
+	struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	return info->funcs[func].name;
+}
+
+static int pxa3xx_pmx_get_groups(struct pinctrl_dev *pctrldev, unsigned func,
+				 const char * const **groups,
+				 unsigned * const num_groups)
+{
+	struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	*groups = info->funcs[func].groups;
+	*num_groups = info->funcs[func].num_groups;
+	return 0;
+}
+
+/* Return function number. If failure, return negative value. */
+static int match_mux(struct pxa3xx_mfp_pin *mfp, unsigned mux)
+{
+	int i;
+	for (i = 0; i < PXA3xx_MAX_MUX; i++) {
+		if (mfp->func[i] == mux)
+			break;
+	}
+	if (i >= PXA3xx_MAX_MUX)
+		return -EINVAL;
+	return i;
+}
+
+/* check whether current pin configuration is valid. Negative for failure */
+static int match_group_mux(struct pxa3xx_pin_group *grp,
+			   struct pxa3xx_pinmux_info *info,
+			   unsigned mux)
+{
+	int i, pin, ret = 0;
+	for (i = 0; i < grp->npins; i++) {
+		pin = grp->pins[i];
+		ret = match_mux(&info->mfp[pin], mux);
+		if (ret < 0) {
+			dev_err(info->dev, "Can't find mux %d on pin%d\n",
+				mux, pin);
+			break;
+		}
+	}
+	return ret;
+}
+
+static int pxa3xx_pmx_enable(struct pinctrl_dev *pctrldev, unsigned func,
+			     unsigned group)
+{
+	struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	struct pxa3xx_pin_group *pin_grp = &info->grps[group];
+	unsigned int data;
+	int i, mfpr, pin, pin_func;
+
+	if (!pin_grp->npins ||
+		(match_group_mux(pin_grp, info, pin_grp->mux) < 0)) {
+		dev_err(info->dev, "Failed to set the pin group: %d\n", group);
+		return -EINVAL;
+	}
+	for (i = 0; i < pin_grp->npins; i++) {
+		pin = pin_grp->pins[i];
+		pin_func = match_mux(&info->mfp[pin], pin_grp->mux);
+		mfpr = info->mfp[pin].mfpr;
+		data = readl_relaxed(info->virt_base + mfpr);
+		data &= ~MFPR_FUNC_MASK;
+		data |= pin_func;
+		writel_relaxed(data, info->virt_base + mfpr);
+	}
+	return 0;
+}
+
+static void pxa3xx_pmx_disable(struct pinctrl_dev *pctrldev, unsigned func,
+			       unsigned group)
+{
+}
+
+static int pxa3xx_pmx_request_gpio(struct pinctrl_dev *pctrldev,
+				   struct pinctrl_gpio_range *range,
+				   unsigned pin)
+{
+	struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	unsigned int data;
+	int pin_func, mfpr;
+
+	pin_func = match_mux(&info->mfp[pin], PXA3xx_MUX_GPIO);
+	if (pin_func < 0) {
+		dev_err(info->dev, "No GPIO function on pin%d (%s)\n",
+			pin, info->pads[pin].name);
+		return -EINVAL;
+	}
+	mfpr = info->mfp[pin].mfpr;
+	/* write gpio function into mfpr register */
+	data = readl_relaxed(info->virt_base + mfpr) & ~MFPR_FUNC_MASK;
+	data |= pin_func;
+	writel_relaxed(data, info->virt_base + mfpr);
+	return 0;
+}
+
+static struct pinmux_ops pxa3xx_pmx_ops = {
+	.list_functions		= pxa3xx_pmx_list_func,
+	.get_function_name	= pxa3xx_pmx_get_func_name,
+	.get_function_groups	= pxa3xx_pmx_get_groups,
+	.enable			= pxa3xx_pmx_enable,
+	.disable		= pxa3xx_pmx_disable,
+	.gpio_request_enable	= pxa3xx_pmx_request_gpio,
+};
+
+int pxa3xx_pinctrl_register(struct platform_device *pdev,
+			    struct pxa3xx_pinmux_info *info)
+{
+	struct pinctrl_desc *desc;
+	struct resource *res;
+	int ret = 0;
+
+	if (!info || !info->cputype)
+		return -EINVAL;
+	desc = info->desc;
+	desc->pins = info->pads;
+	desc->npins = info->num_pads;
+	desc->pctlops = &pxa3xx_pctrl_ops;
+	desc->pmxops = &pxa3xx_pmx_ops;
+	info->dev = &pdev->dev;
+	pxa3xx_pinctrl_gpio_range.npins = info->num_gpio;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENOENT;
+	info->phy_base = res->start;
+	info->phy_size = resource_size(res);
+	info->virt_base = ioremap(info->phy_base, info->phy_size);
+	if (!info->virt_base)
+		return -ENOMEM;
+	info->pctrl = pinctrl_register(desc, &pdev->dev, info);
+	if (!info->pctrl) {
+		dev_err(&pdev->dev, "failed to register PXA pinmux driver\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	pinctrl_add_gpio_range(info->pctrl, &pxa3xx_pinctrl_gpio_range);
+	platform_set_drvdata(pdev, info);
+	return 0;
+err:
+	iounmap(info->virt_base);
+	return ret;
+}
+
+int pxa3xx_pinctrl_unregister(struct platform_device *pdev)
+{
+	struct pxa3xx_pinmux_info *info = platform_get_drvdata(pdev);
+
+	pinctrl_unregister(info->pctrl);
+	iounmap(info->virt_base);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static int __init pxa3xx_pinctrl_init(void)
+{
+	pr_info("pxa3xx-pinctrl: PXA3xx pinctrl driver initializing\n");
+	return 0;
+}
+core_initcall_sync(pxa3xx_pinctrl_init);
+
+static void __exit pxa3xx_pinctrl_exit(void)
+{
+}
+module_exit(pxa3xx_pinctrl_exit);
+
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("PXA3xx pin control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-pxa3xx.h b/drivers/pinctrl/pinctrl-pxa3xx.h
new file mode 100644
index 0000000..8135744
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-pxa3xx.h
@@ -0,0 +1,264 @@
+/*
+ *  linux/drivers/pinctrl/pinctrl-pxa3xx.h
+ *
+ *  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
+ *  publishhed by the Free Software Foundation.
+ *
+ *  Copyright (C) 2011, Marvell Technology Group Ltd.
+ *
+ *  Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ */
+
+#ifndef __PINCTRL_PXA3XX_H
+
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#define ARRAY_AND_SIZE(x)	(x), ARRAY_SIZE(x)
+
+#define PXA3xx_MUX_GPIO		0
+
+#define PXA3xx_MAX_MUX		8
+#define MFPR_FUNC_MASK		0x7
+
+enum pxa_cpu_type {
+	PINCTRL_INVALID = 0,
+	PINCTRL_PXA300,
+	PINCTRL_PXA310,
+	PINCTRL_PXA320,
+	PINCTRL_PXA168,
+	PINCTRL_PXA910,
+	PINCTRL_PXA930,
+	PINCTRL_PXA955,
+	PINCTRL_MMP2,
+	PINCTRL_MAX,
+};
+
+struct pxa3xx_mfp_pin {
+	const char *name;
+	const unsigned int pin;
+	const unsigned int mfpr;	/* register offset */
+	const unsigned short func[8];
+};
+
+struct pxa3xx_pin_group {
+	const char *name;
+	const unsigned mux;
+	const unsigned *pins;
+	const unsigned npins;
+};
+
+struct pxa3xx_pmx_func {
+	const char *name;
+	const char * const * groups;
+	const unsigned num_groups;
+};
+
+struct pxa3xx_pinmux_info {
+	struct device *dev;
+	struct pinctrl_dev *pctrl;
+	enum pxa_cpu_type cputype;
+	unsigned int phy_base;
+	unsigned int phy_size;
+	void __iomem *virt_base;
+
+	struct pxa3xx_mfp_pin *mfp;
+	unsigned int num_mfp;
+	struct pxa3xx_pin_group *grps;
+	unsigned int num_grps;
+	struct pxa3xx_pmx_func *funcs;
+	unsigned int num_funcs;
+	unsigned int num_gpio;
+	struct pinctrl_desc *desc;
+	struct pinctrl_pin_desc *pads;
+	unsigned int num_pads;
+
+	unsigned ds_mask;	/* drive strength mask */
+	unsigned ds_shift;	/* drive strength shift */
+	unsigned slp_mask;	/* sleep mask */
+	unsigned slp_input_low;
+	unsigned slp_input_high;
+	unsigned slp_output_low;
+	unsigned slp_output_high;
+	unsigned slp_float;
+};
+
+enum pxa3xx_pin_list {
+	GPIO0 = 0,
+	GPIO1,
+	GPIO2,
+	GPIO3,
+	GPIO4,
+	GPIO5,
+	GPIO6,
+	GPIO7,
+	GPIO8,
+	GPIO9,
+	GPIO10, /* 10 */
+	GPIO11,
+	GPIO12,
+	GPIO13,
+	GPIO14,
+	GPIO15,
+	GPIO16,
+	GPIO17,
+	GPIO18,
+	GPIO19,
+	GPIO20, /* 20 */
+	GPIO21,
+	GPIO22,
+	GPIO23,
+	GPIO24,
+	GPIO25,
+	GPIO26,
+	GPIO27,
+	GPIO28,
+	GPIO29,
+	GPIO30, /* 30 */
+	GPIO31,
+	GPIO32,
+	GPIO33,
+	GPIO34,
+	GPIO35,
+	GPIO36,
+	GPIO37,
+	GPIO38,
+	GPIO39,
+	GPIO40, /* 40 */
+	GPIO41,
+	GPIO42,
+	GPIO43,
+	GPIO44,
+	GPIO45,
+	GPIO46,
+	GPIO47,
+	GPIO48,
+	GPIO49,
+	GPIO50, /* 50 */
+	GPIO51,
+	GPIO52,
+	GPIO53,
+	GPIO54,
+	GPIO55,
+	GPIO56,
+	GPIO57,
+	GPIO58,
+	GPIO59,
+	GPIO60, /* 60 */
+	GPIO61,
+	GPIO62,
+	GPIO63,
+	GPIO64,
+	GPIO65,
+	GPIO66,
+	GPIO67,
+	GPIO68,
+	GPIO69,
+	GPIO70, /* 70 */
+	GPIO71,
+	GPIO72,
+	GPIO73,
+	GPIO74,
+	GPIO75,
+	GPIO76,
+	GPIO77,
+	GPIO78,
+	GPIO79,
+	GPIO80, /* 80 */
+	GPIO81,
+	GPIO82,
+	GPIO83,
+	GPIO84,
+	GPIO85,
+	GPIO86,
+	GPIO87,
+	GPIO88,
+	GPIO89,
+	GPIO90, /* 90 */
+	GPIO91,
+	GPIO92,
+	GPIO93,
+	GPIO94,
+	GPIO95,
+	GPIO96,
+	GPIO97,
+	GPIO98,
+	GPIO99,
+	GPIO100, /* 100 */
+	GPIO101,
+	GPIO102,
+	GPIO103,
+	GPIO104,
+	GPIO105,
+	GPIO106,
+	GPIO107,
+	GPIO108,
+	GPIO109,
+	GPIO110, /* 110 */
+	GPIO111,
+	GPIO112,
+	GPIO113,
+	GPIO114,
+	GPIO115,
+	GPIO116,
+	GPIO117,
+	GPIO118,
+	GPIO119,
+	GPIO120, /* 120 */
+	GPIO121,
+	GPIO122,
+	GPIO123,
+	GPIO124,
+	GPIO125,
+	GPIO126,
+	GPIO127,
+	GPIO128,
+	GPIO129,
+	GPIO130, /* 130 */
+	GPIO131,
+	GPIO132,
+	GPIO133,
+	GPIO134,
+	GPIO135,
+	GPIO136,
+	GPIO137,
+	GPIO138,
+	GPIO139,
+	GPIO140, /* 140 */
+	GPIO141,
+	GPIO142,
+	GPIO143,
+	GPIO144,
+	GPIO145,
+	GPIO146,
+	GPIO147,
+	GPIO148,
+	GPIO149,
+	GPIO150, /* 150 */
+	GPIO151,
+	GPIO152,
+	GPIO153,
+	GPIO154,
+	GPIO155,
+	GPIO156,
+	GPIO157,
+	GPIO158,
+	GPIO159,
+	GPIO160, /* 160 */
+	GPIO161,
+	GPIO162,
+	GPIO163,
+	GPIO164,
+	GPIO165,
+	GPIO166,
+	GPIO167,
+	GPIO168,
+	GPIO169,
+};
+
+extern int pxa3xx_pinctrl_register(struct platform_device *pdev,
+				   struct pxa3xx_pinmux_info *info);
+extern int pxa3xx_pinctrl_unregister(struct platform_device *pdev);
+#endif	/* __PINCTRL_PXA3XX_H */
diff --git a/drivers/pinctrl/pinctrl-pxa910.c b/drivers/pinctrl/pinctrl-pxa910.c
new file mode 100644
index 0000000..c72ab4b
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-pxa910.c
@@ -0,0 +1,1007 @@
+/*
+ *  linux/drivers/pinctrl/pinmux-pxa910.c
+ *
+ *  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
+ *  publishhed by the Free Software Foundation.
+ *
+ *  Copyright (C) 2011, Marvell Technology Group Ltd.
+ *
+ *  Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include "pinctrl-pxa3xx.h"
+
+#define PXA910_DS_MASK		0x1800
+#define PXA910_DS_SHIFT		11
+#define PXA910_SLEEP_MASK	0x38
+#define PXA910_SLEEP_SELECT	(1 << 9)
+#define PXA910_SLEEP_DATA	(1 << 8)
+#define PXA910_SLEEP_DIR	(1 << 7)
+
+#define MFPR_910(a, r, f0, f1, f2, f3, f4, f5, f6, f7)		\
+	{							\
+		.name = #a,					\
+		.pin = a,					\
+		.mfpr = r,					\
+		.func = {					\
+			PXA910_MUX_##f0,			\
+			PXA910_MUX_##f1,			\
+			PXA910_MUX_##f2,			\
+			PXA910_MUX_##f3,			\
+			PXA910_MUX_##f4,			\
+			PXA910_MUX_##f5,			\
+			PXA910_MUX_##f6,			\
+			PXA910_MUX_##f7,			\
+		},						\
+	}
+
+#define GRP_910(a, m, p)		\
+	{ .name = a, .mux = PXA910_MUX_##m, .pins = p, .npins = ARRAY_SIZE(p), }
+
+/* 170 pins */
+enum pxa910_pin_list {
+	/* 0~127: GPIO0~GPIO127 */
+	ND_IO15 = 128,
+	ND_IO14,
+	ND_IO13, /* 130 */
+	ND_IO12,
+	ND_IO11,
+	ND_IO10,
+	ND_IO9,
+	ND_IO8,
+	ND_IO7,
+	ND_IO6,
+	ND_IO5,
+	ND_IO4,
+	ND_IO3, /* 140 */
+	ND_IO2,
+	ND_IO1,
+	ND_IO0,
+	ND_NCS0,
+	ND_NCS1,
+	SM_NCS0,
+	SM_NCS1,
+	ND_NWE,
+	ND_NRE,
+	ND_CLE, /* 150 */
+	ND_ALE,
+	SM_SCLK,
+	ND_RDY0,
+	SM_ADV,
+	ND_RDY1,
+	SM_ADVMUX,
+	SM_RDY,
+	MMC1_DAT7,
+	MMC1_DAT6,
+	MMC1_DAT5, /* 160 */
+	MMC1_DAT4,
+	MMC1_DAT3,
+	MMC1_DAT2,
+	MMC1_DAT1,
+	MMC1_DAT0,
+	MMC1_CMD,
+	MMC1_CLK,
+	MMC1_CD,
+	VCXO_OUT,
+};
+
+enum pxa910_mux {
+	/* PXA3xx_MUX_GPIO = 0 (predefined in pinctrl-pxa3xx.h) */
+	PXA910_MUX_GPIO = 0,
+	PXA910_MUX_NAND,
+	PXA910_MUX_USIM2,
+	PXA910_MUX_EXT_DMA,
+	PXA910_MUX_EXT_INT,
+	PXA910_MUX_MMC1,
+	PXA910_MUX_MMC2,
+	PXA910_MUX_MMC3,
+	PXA910_MUX_SM_INT,
+	PXA910_MUX_PRI_JTAG,
+	PXA910_MUX_SEC1_JTAG,
+	PXA910_MUX_SEC2_JTAG,
+	PXA910_MUX_RESET,	/* SLAVE RESET OUT */
+	PXA910_MUX_CLK_REQ,
+	PXA910_MUX_VCXO_REQ,
+	PXA910_MUX_VCXO_OUT,
+	PXA910_MUX_VCXO_REQ2,
+	PXA910_MUX_VCXO_OUT2,
+	PXA910_MUX_SPI,
+	PXA910_MUX_SPI2,
+	PXA910_MUX_GSSP,
+	PXA910_MUX_SSP0,
+	PXA910_MUX_SSP1,
+	PXA910_MUX_SSP2,
+	PXA910_MUX_DSSP2,
+	PXA910_MUX_DSSP3,
+	PXA910_MUX_UART0,
+	PXA910_MUX_UART1,
+	PXA910_MUX_UART2,
+	PXA910_MUX_TWSI,
+	PXA910_MUX_CCIC,
+	PXA910_MUX_PWM0,
+	PXA910_MUX_PWM1,
+	PXA910_MUX_PWM2,
+	PXA910_MUX_PWM3,
+	PXA910_MUX_HSL,
+	PXA910_MUX_ONE_WIRE,
+	PXA910_MUX_LCD,
+	PXA910_MUX_DAC_ST23,
+	PXA910_MUX_ULPI,
+	PXA910_MUX_TB,
+	PXA910_MUX_KP_MK,
+	PXA910_MUX_KP_DK,
+	PXA910_MUX_TCU_GPOA,
+	PXA910_MUX_TCU_GPOB,
+	PXA910_MUX_ROT,
+	PXA910_MUX_TDS,
+	PXA910_MUX_32K_CLK, /* 32KHz CLK OUT */
+	PXA910_MUX_MN_CLK, /* MN CLK OUT */
+	PXA910_MUX_SMC,
+	PXA910_MUX_SM_ADDR18,
+	PXA910_MUX_SM_ADDR19,
+	PXA910_MUX_SM_ADDR20,
+	PXA910_MUX_NONE = 0xffff,
+};
+
+
+static struct pinctrl_pin_desc pxa910_pads[] = {
+	PINCTRL_PIN(GPIO0, "GPIO0"),
+	PINCTRL_PIN(GPIO1, "GPIO1"),
+	PINCTRL_PIN(GPIO2, "GPIO2"),
+	PINCTRL_PIN(GPIO3, "GPIO3"),
+	PINCTRL_PIN(GPIO4, "GPIO4"),
+	PINCTRL_PIN(GPIO5, "GPIO5"),
+	PINCTRL_PIN(GPIO6, "GPIO6"),
+	PINCTRL_PIN(GPIO7, "GPIO7"),
+	PINCTRL_PIN(GPIO8, "GPIO8"),
+	PINCTRL_PIN(GPIO9, "GPIO9"),
+	PINCTRL_PIN(GPIO10, "GPIO10"),
+	PINCTRL_PIN(GPIO11, "GPIO11"),
+	PINCTRL_PIN(GPIO12, "GPIO12"),
+	PINCTRL_PIN(GPIO13, "GPIO13"),
+	PINCTRL_PIN(GPIO14, "GPIO14"),
+	PINCTRL_PIN(GPIO15, "GPIO15"),
+	PINCTRL_PIN(GPIO16, "GPIO16"),
+	PINCTRL_PIN(GPIO17, "GPIO17"),
+	PINCTRL_PIN(GPIO18, "GPIO18"),
+	PINCTRL_PIN(GPIO19, "GPIO19"),
+	PINCTRL_PIN(GPIO20, "GPIO20"),
+	PINCTRL_PIN(GPIO21, "GPIO21"),
+	PINCTRL_PIN(GPIO22, "GPIO22"),
+	PINCTRL_PIN(GPIO23, "GPIO23"),
+	PINCTRL_PIN(GPIO24, "GPIO24"),
+	PINCTRL_PIN(GPIO25, "GPIO25"),
+	PINCTRL_PIN(GPIO26, "GPIO26"),
+	PINCTRL_PIN(GPIO27, "GPIO27"),
+	PINCTRL_PIN(GPIO28, "GPIO28"),
+	PINCTRL_PIN(GPIO29, "GPIO29"),
+	PINCTRL_PIN(GPIO30, "GPIO30"),
+	PINCTRL_PIN(GPIO31, "GPIO31"),
+	PINCTRL_PIN(GPIO32, "GPIO32"),
+	PINCTRL_PIN(GPIO33, "GPIO33"),
+	PINCTRL_PIN(GPIO34, "GPIO34"),
+	PINCTRL_PIN(GPIO35, "GPIO35"),
+	PINCTRL_PIN(GPIO36, "GPIO36"),
+	PINCTRL_PIN(GPIO37, "GPIO37"),
+	PINCTRL_PIN(GPIO38, "GPIO38"),
+	PINCTRL_PIN(GPIO39, "GPIO39"),
+	PINCTRL_PIN(GPIO40, "GPIO40"),
+	PINCTRL_PIN(GPIO41, "GPIO41"),
+	PINCTRL_PIN(GPIO42, "GPIO42"),
+	PINCTRL_PIN(GPIO43, "GPIO43"),
+	PINCTRL_PIN(GPIO44, "GPIO44"),
+	PINCTRL_PIN(GPIO45, "GPIO45"),
+	PINCTRL_PIN(GPIO46, "GPIO46"),
+	PINCTRL_PIN(GPIO47, "GPIO47"),
+	PINCTRL_PIN(GPIO48, "GPIO48"),
+	PINCTRL_PIN(GPIO49, "GPIO49"),
+	PINCTRL_PIN(GPIO50, "GPIO50"),
+	PINCTRL_PIN(GPIO51, "GPIO51"),
+	PINCTRL_PIN(GPIO52, "GPIO52"),
+	PINCTRL_PIN(GPIO53, "GPIO53"),
+	PINCTRL_PIN(GPIO54, "GPIO54"),
+	PINCTRL_PIN(GPIO55, "GPIO55"),
+	PINCTRL_PIN(GPIO56, "GPIO56"),
+	PINCTRL_PIN(GPIO57, "GPIO57"),
+	PINCTRL_PIN(GPIO58, "GPIO58"),
+	PINCTRL_PIN(GPIO59, "GPIO59"),
+	PINCTRL_PIN(GPIO60, "GPIO60"),
+	PINCTRL_PIN(GPIO61, "GPIO61"),
+	PINCTRL_PIN(GPIO62, "GPIO62"),
+	PINCTRL_PIN(GPIO63, "GPIO63"),
+	PINCTRL_PIN(GPIO64, "GPIO64"),
+	PINCTRL_PIN(GPIO65, "GPIO65"),
+	PINCTRL_PIN(GPIO66, "GPIO66"),
+	PINCTRL_PIN(GPIO67, "GPIO67"),
+	PINCTRL_PIN(GPIO68, "GPIO68"),
+	PINCTRL_PIN(GPIO69, "GPIO69"),
+	PINCTRL_PIN(GPIO70, "GPIO70"),
+	PINCTRL_PIN(GPIO71, "GPIO71"),
+	PINCTRL_PIN(GPIO72, "GPIO72"),
+	PINCTRL_PIN(GPIO73, "GPIO73"),
+	PINCTRL_PIN(GPIO74, "GPIO74"),
+	PINCTRL_PIN(GPIO75, "GPIO75"),
+	PINCTRL_PIN(GPIO76, "GPIO76"),
+	PINCTRL_PIN(GPIO77, "GPIO77"),
+	PINCTRL_PIN(GPIO78, "GPIO78"),
+	PINCTRL_PIN(GPIO79, "GPIO79"),
+	PINCTRL_PIN(GPIO80, "GPIO80"),
+	PINCTRL_PIN(GPIO81, "GPIO81"),
+	PINCTRL_PIN(GPIO82, "GPIO82"),
+	PINCTRL_PIN(GPIO83, "GPIO83"),
+	PINCTRL_PIN(GPIO84, "GPIO84"),
+	PINCTRL_PIN(GPIO85, "GPIO85"),
+	PINCTRL_PIN(GPIO86, "GPIO86"),
+	PINCTRL_PIN(GPIO87, "GPIO87"),
+	PINCTRL_PIN(GPIO88, "GPIO88"),
+	PINCTRL_PIN(GPIO89, "GPIO89"),
+	PINCTRL_PIN(GPIO90, "GPIO90"),
+	PINCTRL_PIN(GPIO91, "GPIO91"),
+	PINCTRL_PIN(GPIO92, "GPIO92"),
+	PINCTRL_PIN(GPIO93, "GPIO93"),
+	PINCTRL_PIN(GPIO94, "GPIO94"),
+	PINCTRL_PIN(GPIO95, "GPIO95"),
+	PINCTRL_PIN(GPIO96, "GPIO96"),
+	PINCTRL_PIN(GPIO97, "GPIO97"),
+	PINCTRL_PIN(GPIO98, "GPIO98"),
+	PINCTRL_PIN(GPIO99, "GPIO99"),
+	PINCTRL_PIN(GPIO100, "GPIO100"),
+	PINCTRL_PIN(GPIO101, "GPIO101"),
+	PINCTRL_PIN(GPIO102, "GPIO102"),
+	PINCTRL_PIN(GPIO103, "GPIO103"),
+	PINCTRL_PIN(GPIO104, "GPIO104"),
+	PINCTRL_PIN(GPIO105, "GPIO105"),
+	PINCTRL_PIN(GPIO106, "GPIO106"),
+	PINCTRL_PIN(GPIO107, "GPIO107"),
+	PINCTRL_PIN(GPIO108, "GPIO108"),
+	PINCTRL_PIN(GPIO109, "GPIO109"),
+	PINCTRL_PIN(GPIO110, "GPIO110"),
+	PINCTRL_PIN(GPIO111, "GPIO111"),
+	PINCTRL_PIN(GPIO112, "GPIO112"),
+	PINCTRL_PIN(GPIO113, "GPIO113"),
+	PINCTRL_PIN(GPIO114, "GPIO114"),
+	PINCTRL_PIN(GPIO115, "GPIO115"),
+	PINCTRL_PIN(GPIO116, "GPIO116"),
+	PINCTRL_PIN(GPIO117, "GPIO117"),
+	PINCTRL_PIN(GPIO118, "GPIO118"),
+	PINCTRL_PIN(GPIO119, "GPIO119"),
+	PINCTRL_PIN(GPIO120, "GPIO120"),
+	PINCTRL_PIN(GPIO121, "GPIO121"),
+	PINCTRL_PIN(GPIO122, "GPIO122"),
+	PINCTRL_PIN(GPIO123, "GPIO123"),
+	PINCTRL_PIN(GPIO124, "GPIO124"),
+	PINCTRL_PIN(GPIO125, "GPIO125"),
+	PINCTRL_PIN(GPIO126, "GPIO126"),
+	PINCTRL_PIN(GPIO127, "GPIO127"),
+	PINCTRL_PIN(ND_IO15, "ND_IO15"),
+	PINCTRL_PIN(ND_IO14, "ND_IO14"),
+	PINCTRL_PIN(ND_IO13, "ND_IO13"),
+	PINCTRL_PIN(ND_IO12, "ND_IO12"),
+	PINCTRL_PIN(ND_IO11, "ND_IO11"),
+	PINCTRL_PIN(ND_IO10, "ND_IO10"),
+	PINCTRL_PIN(ND_IO9, "ND_IO9"),
+	PINCTRL_PIN(ND_IO8, "ND_IO8"),
+	PINCTRL_PIN(ND_IO7, "ND_IO7"),
+	PINCTRL_PIN(ND_IO6, "ND_IO6"),
+	PINCTRL_PIN(ND_IO5, "ND_IO5"),
+	PINCTRL_PIN(ND_IO4, "ND_IO4"),
+	PINCTRL_PIN(ND_IO3, "ND_IO3"),
+	PINCTRL_PIN(ND_IO2, "ND_IO2"),
+	PINCTRL_PIN(ND_IO1, "ND_IO1"),
+	PINCTRL_PIN(ND_IO0, "ND_IO0"),
+	PINCTRL_PIN(ND_NCS0, "ND_NCS0_SM_NCS2"),
+	PINCTRL_PIN(ND_NCS1, "ND_NCS1_SM_NCS3"),
+	PINCTRL_PIN(SM_NCS0, "SM_NCS0"),
+	PINCTRL_PIN(SM_NCS1, "SM_NCS1"),
+	PINCTRL_PIN(ND_NWE, "ND_NWE"),
+	PINCTRL_PIN(ND_NRE, "ND_NRE"),
+	PINCTRL_PIN(ND_CLE, "ND_CLE_SM_NOE"),
+	PINCTRL_PIN(ND_ALE, "ND_ALE_SM_NWE"),
+	PINCTRL_PIN(SM_SCLK, "SM_SCLK"),
+	PINCTRL_PIN(ND_RDY0, "ND_RDY0"),
+	PINCTRL_PIN(SM_ADV, "SM_ADV"),
+	PINCTRL_PIN(ND_RDY1, "ND_RDY1"),
+	PINCTRL_PIN(SM_RDY, "SM_RDY"),
+	PINCTRL_PIN(MMC1_DAT7, "MMC1_DAT7"),
+	PINCTRL_PIN(MMC1_DAT6, "MMC1_DAT6"),
+	PINCTRL_PIN(MMC1_DAT5, "MMC1_DAT5"),
+	PINCTRL_PIN(MMC1_DAT4, "MMC1_DAT4"),
+	PINCTRL_PIN(MMC1_DAT3, "MMC1_DAT3"),
+	PINCTRL_PIN(MMC1_DAT2, "MMC1_DAT2"),
+	PINCTRL_PIN(MMC1_DAT1, "MMC1_DAT1"),
+	PINCTRL_PIN(MMC1_DAT0, "MMC1_DAT0"),
+	PINCTRL_PIN(MMC1_CMD, "MMC1 CMD"),
+	PINCTRL_PIN(MMC1_CLK, "MMC1 CLK"),
+	PINCTRL_PIN(MMC1_CD, "MMC1 CD"),
+	PINCTRL_PIN(VCXO_OUT, "VCXO_OUT"),
+};
+
+struct pxa3xx_mfp_pin pxa910_mfp[] = {
+	/*       pin        offs   f0        f1      f2         f3         f4         f5        f6        f7  */
+	MFPR_910(GPIO0,     0x0DC, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO1,     0x0E0, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO2,     0x0E4, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO3,     0x0E8, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO4,     0x0EC, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO5,     0x0F0, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO6,     0x0F4, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO7,     0x0F8, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO8,     0x0FC, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO9,     0x100, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO10,    0x104, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO11,    0x108, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO12,    0x10C, GPIO,     KP_MK,  NONE,      NONE,      KP_DK,     NONE,     NONE,     NONE),
+	MFPR_910(GPIO13,    0x110, GPIO,     KP_MK,  NONE,      NONE,      KP_DK,     NONE,     NONE,     NONE),
+	MFPR_910(GPIO14,    0x114, GPIO,     KP_MK,  NONE,      NONE,      KP_DK,     TB,       NONE,     NONE),
+	MFPR_910(GPIO15,    0x118, GPIO,     KP_MK,  NONE,      NONE,      KP_DK,     TB,       NONE,     NONE),
+	MFPR_910(GPIO16,    0x11C, GPIO,     KP_DK,  NONE,      NONE,      NONE,      TB,       NONE,     NONE),
+	MFPR_910(GPIO17,    0x120, GPIO,     KP_DK,  NONE,      NONE,      NONE,      TB,       NONE,     NONE),
+	MFPR_910(GPIO18,    0x124, GPIO,     KP_DK,  NONE,      NONE,      ROT,       NONE,     NONE,     NONE),
+	MFPR_910(GPIO19,    0x128, GPIO,     KP_DK,  NONE,      NONE,      ROT,       NONE,     NONE,     NONE),
+	MFPR_910(GPIO20,    0x12C, GPIO,     SSP1,   NONE,      NONE,      VCXO_OUT,  NONE,     NONE,     NONE),
+	MFPR_910(GPIO21,    0x130, GPIO,     SSP1,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO22,    0x134, GPIO,     SSP1,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO23,    0x138, GPIO,     SSP1,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO24,    0x13C, GPIO,     SSP1,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO25,    0x140, GPIO,     GSSP,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO26,    0x144, GPIO,     GSSP,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO27,    0x148, GPIO,     GSSP,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO28,    0x14C, GPIO,     GSSP,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO29,    0x150, GPIO,     UART0,  NONE,      NONE,      UART1,     NONE,     NONE,     NONE),
+	MFPR_910(GPIO30,    0x154, GPIO,     UART0,  NONE,      NONE,      UART1,     NONE,     NONE,     NONE),
+	MFPR_910(GPIO31,    0x158, GPIO,     UART0,  NONE,      NONE,      UART1,     NONE,     NONE,     NONE),
+	MFPR_910(GPIO32,    0x15C, GPIO,     UART0,  DAC_ST23,  NONE,      UART1,     NONE,     NONE,     NONE),
+	MFPR_910(GPIO33,    0x160, GPIO,     MMC2,   SSP0,      SSP2,      NONE,      SPI,      NONE,     MMC3),
+	MFPR_910(GPIO34,    0x164, GPIO,     MMC2,   SSP0,      SSP2,      NONE,      SPI,      NONE,     MMC3),
+	MFPR_910(GPIO35,    0x168, GPIO,     MMC2,   SSP0,      SSP2,      NONE,      SPI,      NONE,     MMC3),
+	MFPR_910(GPIO36,    0x16C, GPIO,     MMC2,   SSP0,      SSP2,      NONE,      SPI,      NONE,     MMC3),
+	MFPR_910(GPIO37,    0x170, GPIO,     MMC2,   NONE,      NONE,      NONE,      SPI,      HSL,      NONE),
+	MFPR_910(GPIO38,    0x174, GPIO,     MMC2,   NONE,      NONE,      NONE,      NONE,     HSL,      NONE),
+	MFPR_910(GPIO39,    0x178, GPIO,     MMC2,   NONE,      NONE,      NONE,      NONE,     HSL,      NONE),
+	MFPR_910(GPIO40,    0x17C, GPIO,     MMC2,   NONE,      NONE,      NONE,      NONE,     HSL,      NONE),
+	MFPR_910(GPIO41,    0x180, GPIO,     MMC2,   NONE,      NONE,      NONE,      NONE,     HSL,      NONE),
+	MFPR_910(GPIO42,    0x184, GPIO,     MMC2,   NONE,      NONE,      NONE,      NONE,     HSL,      NONE),
+	MFPR_910(GPIO43,    0x188, GPIO,     UART1,  NONE,      DAC_ST23,  NONE,      DSSP2,    SPI,      UART2),
+	MFPR_910(GPIO44,    0x18C, GPIO,     UART1,  NONE,      EXT_INT,   NONE,      DSSP2,    SPI,      UART2),
+	MFPR_910(GPIO45,    0x190, GPIO,     UART1,  NONE,      EXT_INT,   NONE,      DSSP2,    SPI,      UART2),
+	MFPR_910(GPIO46,    0x194, GPIO,     UART1,  NONE,      EXT_INT,   NONE,      DSSP2,    SPI,      UART2),
+	MFPR_910(GPIO47,    0x198, GPIO,     SSP0,   NONE,      NONE,      NONE,      SSP2,     UART1,    NONE),
+	MFPR_910(GPIO48,    0x19C, GPIO,     SSP0,   NONE,      NONE,      NONE,      SSP2,     UART1,    NONE),
+	MFPR_910(GPIO49,    0x1A0, GPIO,     SSP0,   UART0,     VCXO_REQ,  NONE,      SSP2,     NONE,     MMC3),
+	MFPR_910(GPIO50,    0x1A4, GPIO,     SSP0,   UART0,     VCXO_OUT,  NONE,      SSP2,     NONE,     MMC3),
+	MFPR_910(GPIO51,    0x1A8, GPIO,     UART2,  PWM1,      TWSI,      SSP0,      NONE,     DSSP3,    NONE),
+	MFPR_910(GPIO52,    0x1AC, GPIO,     UART2,  DAC_ST23,  TWSI,      SSP0,      NONE,     DSSP3,    NONE),
+	MFPR_910(GPIO53,    0x1B0, GPIO,     UART2,  TWSI,      NONE,      SSP0,      NONE,     DSSP3,    NONE),
+	MFPR_910(GPIO54,    0x1B4, GPIO,     UART2,  TWSI,      SSP0,      NONE,      NONE,     DSSP3,    NONE),
+	MFPR_910(GPIO55,    0x2F0, TDS,      GPIO,   TB,        NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO56,    0x2F4, TDS,      GPIO,   TB,        NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO57,    0x2F8, TDS,      GPIO,   TB,        NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO58,    0x2FC, TDS,      GPIO,   TB,        NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO59,    0x300, TDS,      GPIO,   TCU_GPOA,  TCU_GPOB,  ONE_WIRE,  NONE,     NONE,     NONE),
+	MFPR_910(GPIO60,    0x304, GPIO,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO61,    0x308, GPIO,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     HSL),
+	MFPR_910(GPIO62,    0x30C, GPIO,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     HSL),
+	MFPR_910(GPIO63,    0x310, GPIO,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     HSL),
+	MFPR_910(GPIO64,    0x314, GPIO,     SPI2,   NONE,      NONE,      NONE,      NONE,     NONE,     HSL),
+	MFPR_910(GPIO65,    0x318, GPIO,     SPI2,   NONE,      NONE,      NONE,      NONE,     ONE_WIRE, HSL),
+	MFPR_910(GPIO66,    0x31C, GPIO,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     HSL),
+	MFPR_910(GPIO67,    0x1B8, GPIO,     CCIC,   SPI,       NONE,      NONE,      ULPI,     NONE,     USIM2),
+	MFPR_910(GPIO68,    0x1BC, GPIO,     CCIC,   SPI,       NONE,      NONE,      ULPI,     NONE,     USIM2),
+	MFPR_910(GPIO69,    0x1C0, GPIO,     CCIC,   SPI,       NONE,      NONE,      ULPI,     NONE,     USIM2),
+	MFPR_910(GPIO70,    0x1C4, GPIO,     CCIC,   SPI,       NONE,      NONE,      ULPI,     NONE,     NONE),
+	MFPR_910(GPIO71,    0x1C8, GPIO,     CCIC,   SPI,       NONE,      NONE,      ULPI,     NONE,     NONE),
+	MFPR_910(GPIO72,    0x1CC, GPIO,     CCIC,   EXT_DMA,   NONE,      NONE,      ULPI,     NONE,     NONE),
+	MFPR_910(GPIO73,    0x1D0, GPIO,     CCIC,   EXT_DMA,   NONE,      NONE,      ULPI,     NONE,     NONE),
+	MFPR_910(GPIO74,    0x1D4, GPIO,     CCIC,   EXT_DMA,   NONE,      NONE,      ULPI,     NONE,     NONE),
+	MFPR_910(GPIO75,    0x1D8, GPIO,     CCIC,   NONE,      NONE,      NONE,      ULPI,     NONE,     NONE),
+	MFPR_910(GPIO76,    0x1DC, GPIO,     CCIC,   NONE,      NONE,      NONE,      ULPI,     NONE,     NONE),
+	MFPR_910(GPIO77,    0x1E0, GPIO,     CCIC,   NONE,      NONE,      NONE,      ULPI,     NONE,     NONE),
+	MFPR_910(GPIO78,    0x1E4, GPIO,     CCIC,   NONE,      NONE,      NONE,      ULPI,     NONE,     NONE),
+	MFPR_910(GPIO79,    0x1E8, GPIO,     TWSI,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO80,    0x1EC, GPIO,     TWSI,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO81,    0x1F0, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO82,    0x1F4, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO83,    0x1F8, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO84,    0x1FC, GPIO,     LCD,    VCXO_REQ2, NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO85,    0x200, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO86,    0x204, GPIO,     LCD,    VCXO_OUT2, NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO87,    0x208, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO88,    0x20C, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO89,    0x210, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO90,    0x214, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO91,    0x218, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO92,    0x21C, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO93,    0x220, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO94,    0x224, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO95,    0x228, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO96,    0x22C, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO97,    0x230, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO98,    0x234, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO99,    0x0B0, MMC1,     GPIO,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO100,   0x238, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO101,   0x23C, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO102,   0x240, GPIO,     LCD,    DSSP2,     SPI,       NONE,      NONE,     NONE,     SPI2),
+	MFPR_910(GPIO103,   0x244, GPIO,     LCD,    DSSP2,     SPI,       NONE,      NONE,     NONE,     SPI2),
+	MFPR_910(GPIO104,   0x248, GPIO,     LCD,    DSSP2,     SPI,       NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO105,   0x24C, GPIO,     LCD,    DSSP2,     SPI,       NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO106,   0x250, GPIO,     LCD,    DSSP3,     ONE_WIRE,  NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO107,   0x254, GPIO,     LCD,    DSSP3,     SPI,       NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO108,   0x258, GPIO,     LCD,    DSSP3,     SPI,       NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO109,   0x25C, GPIO,     LCD,    DSSP3,     SPI,       NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO110,   0x298, GPIO,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO111,   0x29C, GPIO,     NONE,   DSSP2,     NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO112,   0x2A0, GPIO,     NONE,   DSSP2,     NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO113,   0x2A4, GPIO,     NONE,   DSSP2,     NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO114,   0x2A8, GPIO,     NONE,   DSSP3,     NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO115,   0x2AC, GPIO,     NONE,   DSSP3,     NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO116,   0x2B0, GPIO,     NONE,   DSSP3,     NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO117,   0x0B4, PRI_JTAG, GPIO,   PWM0,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO118,   0x0B8, PRI_JTAG, GPIO,   PWM1,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO119,   0x0BC, PRI_JTAG, GPIO,   PWM2,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO120,   0x0C0, PRI_JTAG, GPIO,   PWM3,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO121,   0x32C, GPIO,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO122,   0x0C8, RESET,    GPIO,   32K_CLK,   NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO123,   0x0CC, CLK_REQ,  GPIO,   ONE_WIRE,  EXT_DMA,   NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO124,   0x0D0, GPIO,     MN_CLK, DAC_ST23,  NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO125,   0x0D4, VCXO_REQ, GPIO,   NONE,      EXT_INT,   NONE,      NONE,     NONE,     NONE),
+	MFPR_910(GPIO126,   0x06C, GPIO,     SMC,    NONE,      SM_ADDR18, NONE,      EXT_DMA,  NONE,     NONE),
+	MFPR_910(GPIO127,   0x070, GPIO,     SMC,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_IO15,   0x004, NAND,     GPIO,   USIM2,     EXT_DMA,   NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_IO14,   0x008, NAND,     GPIO,   USIM2,     NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_IO13,   0x00C, NAND,     GPIO,   USIM2,     EXT_INT,   NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_IO12,   0x010, NAND,     GPIO,   SSP2,      EXT_INT,   NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_IO11,   0x014, NAND,     GPIO,   SSP2,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_IO10,   0x018, NAND,     GPIO,   SSP2,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_IO9,    0x01C, NAND,     GPIO,   SSP2,      NONE,      VCXO_OUT2, NONE,     NONE,     NONE),
+	MFPR_910(ND_IO8,    0x020, NAND,     GPIO,   NONE,      NONE,      PWM3,      NONE,     NONE,     NONE),
+	MFPR_910(ND_IO7,    0x024, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_IO6,    0x028, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_IO5,    0x02C, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_IO4,    0x030, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_IO3,    0x034, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_IO2,    0x038, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_IO1,    0x03C, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_IO0,    0x040, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_NCS0,   0x044, NAND,     GPIO,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_NCS1,   0x048, NAND,     GPIO,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(SM_NCS0,   0x04C, SMC,      GPIO,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(SM_NCS1,   0x050, SMC,      GPIO,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_NWE,    0x054, GPIO,     NAND,   NONE,      SM_ADDR20, NONE,      SMC,      NONE,     NONE),
+	MFPR_910(ND_NRE,    0x058, GPIO,     NAND,   NONE,      SMC,       NONE,      EXT_DMA,  NONE,     NONE),
+	MFPR_910(ND_CLE,    0x05C, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_ALE,    0x060, GPIO,     NAND,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(SM_SCLK,   0x064, MMC3,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_RDY0,   0x068, NAND,     GPIO,   NONE,      SMC,       NONE,      NONE,     NONE,     NONE),
+	MFPR_910(SM_ADV,    0x074, SMC,      GPIO,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(ND_RDY1,   0x078, NAND,     GPIO,   NONE,      SMC,       NONE,      NONE,     NONE,     NONE),
+	MFPR_910(SM_ADVMUX, 0x07C, SMC,      GPIO,   NONE,      SM_ADDR19, NONE,      NONE,     NONE,     NONE),
+	MFPR_910(SM_RDY,    0x080, SMC,      GPIO,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(MMC1_DAT7, 0x084, MMC1,     GPIO,   SEC1_JTAG, TB,        NONE,      NONE,     NONE,     NONE),
+	MFPR_910(MMC1_DAT6, 0x088, MMC1,     GPIO,   SEC1_JTAG, TB,        NONE,      NONE,     NONE,     NONE),
+	MFPR_910(MMC1_DAT5, 0x08C, MMC1,     GPIO,   SEC1_JTAG, TB,        NONE,      NONE,     NONE,     NONE),
+	MFPR_910(MMC1_DAT4, 0x090, MMC1,     GPIO,   NONE,      TB,        NONE,      NONE,     NONE,     NONE),
+	MFPR_910(MMC1_DAT3, 0x094, MMC1,     HSL,    SEC2_JTAG, SSP0,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(MMC1_DAT2, 0x098, MMC1,     HSL,    SEC2_JTAG, SSP2,      SSP0,      NONE,     NONE,     NONE),
+	MFPR_910(MMC1_DAT1, 0x09C, MMC1,     HSL,    SEC2_JTAG, SSP2,      SSP0,      NONE,     NONE,     NONE),
+	MFPR_910(MMC1_DAT0, 0x0A0, MMC1,     HSL,    SEC2_JTAG, SSP2,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(MMC1_CMD,  0x0A4, MMC1,     HSL,    SEC1_JTAG, SSP2,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(MMC1_CLK,  0x0A8, MMC1,     HSL,    SEC2_JTAG, SSP0,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(MMC1_CD,   0x0AC, MMC1,     GPIO,   SEC1_JTAG, NONE,      NONE,      NONE,     NONE,     NONE),
+	MFPR_910(VCXO_OUT,  0x0D8, VCXO_OUT, PWM3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
+};
+
+
+static const unsigned p910_usim2_pin1[] = {GPIO67, GPIO68, GPIO69};
+static const unsigned p910_usim2_pin2[] = {ND_IO15, ND_IO14, ND_IO13};
+static const unsigned p910_mmc1_pin1[] = {MMC1_DAT7, MMC1_DAT6, MMC1_DAT5,
+	MMC1_DAT4, MMC1_DAT3, MMC1_DAT2, MMC1_DAT1, MMC1_DAT0, MMC1_CMD,
+	MMC1_CLK, MMC1_CD, GPIO99};
+static const unsigned p910_mmc2_pin1[] = {GPIO33, GPIO34, GPIO35, GPIO36,
+	GPIO37, GPIO38, GPIO39, GPIO40, GPIO41, GPIO42};
+static const unsigned p910_mmc3_pin1[] = {GPIO33, GPIO34, GPIO35, GPIO36,
+	GPIO49, GPIO50};
+static const unsigned p910_mmc3_pin2[] = {ND_IO7, ND_IO6, ND_IO5, ND_IO4,
+	ND_IO3, ND_IO2, ND_IO1, ND_IO0, ND_CLE, SM_SCLK};
+static const unsigned p910_uart0_pin1[] = {GPIO29, GPIO30, GPIO31, GPIO32};
+static const unsigned p910_uart1_pin1[] = {GPIO47, GPIO48};
+static const unsigned p910_uart1_pin2[] = {GPIO31, GPIO32};
+static const unsigned p910_uart1_pin3[] = {GPIO45, GPIO46};
+static const unsigned p910_uart1_pin4[] = {GPIO29, GPIO30, GPIO31, GPIO32};
+static const unsigned p910_uart1_pin5[] = {GPIO43, GPIO44, GPIO45, GPIO46};
+static const unsigned p910_uart2_pin1[] = {GPIO43, GPIO44};
+static const unsigned p910_uart2_pin2[] = {GPIO51, GPIO52};
+static const unsigned p910_uart2_pin3[] = {GPIO43, GPIO44, GPIO45, GPIO46};
+static const unsigned p910_uart2_pin4[] = {GPIO51, GPIO52, GPIO53, GPIO54};
+static const unsigned p910_twsi_pin1[] = {GPIO51, GPIO52};
+static const unsigned p910_twsi_pin2[] = {GPIO53, GPIO54};
+static const unsigned p910_twsi_pin3[] = {GPIO79, GPIO80};
+static const unsigned p910_ccic_pin1[] = {GPIO67, GPIO68, GPIO69, GPIO70,
+	GPIO71, GPIO72, GPIO73, GPIO74, GPIO75, GPIO76, GPIO77, GPIO78};
+static const unsigned p910_lcd_pin1[] = {GPIO81, GPIO82, GPIO83, GPIO84,
+	GPIO85, GPIO86, GPIO87, GPIO88, GPIO89, GPIO90, GPIO91, GPIO92,
+	GPIO93, GPIO94, GPIO95, GPIO96, GPIO97, GPIO98, GPIO100, GPIO101,
+	GPIO102, GPIO103};
+static const unsigned p910_spi_pin1[] = {GPIO104, GPIO105, GPIO107, GPIO108};
+static const unsigned p910_spi_pin2[] = {GPIO43, GPIO44, GPIO45, GPIO46};
+static const unsigned p910_spi_pin3[] = {GPIO33, GPIO34, GPIO35, GPIO36,
+	GPIO37};
+static const unsigned p910_spi_pin4[] = {GPIO67, GPIO68, GPIO69, GPIO70,
+	GPIO71};
+static const unsigned p910_spi2_pin1[] = {GPIO64, GPIO65};
+static const unsigned p910_spi2_pin2[] = {GPIO102, GPIO103};
+static const unsigned p910_dssp2_pin1[] = {GPIO102, GPIO103, GPIO104, GPIO105};
+static const unsigned p910_dssp2_pin2[] = {GPIO43, GPIO44, GPIO45, GPIO46};
+static const unsigned p910_dssp2_pin3[] = {GPIO111, GPIO112, GPIO113};
+static const unsigned p910_dssp3_pin1[] = {GPIO106, GPIO107, GPIO108, GPIO109};
+static const unsigned p910_dssp3_pin2[] = {GPIO51, GPIO52, GPIO53, GPIO54};
+static const unsigned p910_dssp3_pin3[] = {GPIO114, GPIO115, GPIO116};
+static const unsigned p910_ssp0_pin1[] = {MMC1_DAT3, MMC1_DAT2, MMC1_DAT1,
+	MMC1_CLK};
+static const unsigned p910_ssp0_pin2[] = {GPIO33, GPIO34, GPIO35, GPIO36};
+static const unsigned p910_ssp0_pin3[] = {GPIO47, GPIO48, GPIO49, GPIO50};
+static const unsigned p910_ssp0_pin4[] = {GPIO51, GPIO52, GPIO53, GPIO54};
+static const unsigned p910_ssp1_pin1[] = {GPIO21, GPIO22, GPIO23, GPIO24};
+static const unsigned p910_ssp1_pin2[] = {GPIO20, GPIO21, GPIO22, GPIO23,
+	GPIO24};
+static const unsigned p910_ssp2_pin1[] = {MMC1_DAT2, MMC1_DAT1, MMC1_DAT0,
+	MMC1_CMD};
+static const unsigned p910_ssp2_pin2[] = {GPIO33, GPIO34, GPIO35, GPIO36};
+static const unsigned p910_ssp2_pin3[] = {GPIO47, GPIO48, GPIO49, GPIO50};
+static const unsigned p910_ssp2_pin4[] = {ND_IO12, ND_IO11, ND_IO10, ND_IO9};
+static const unsigned p910_gssp_pin1[] = {GPIO25, GPIO26, GPIO27, GPIO28};
+static const unsigned p910_pwm0_pin1[] = {GPIO117};
+static const unsigned p910_pwm1_pin1[] = {GPIO118};
+static const unsigned p910_pwm1_pin2[] = {GPIO51};
+static const unsigned p910_pwm2_pin1[] = {GPIO119};
+static const unsigned p910_pwm3_pin1[] = {GPIO120};
+static const unsigned p910_pwm3_pin2[] = {ND_IO8};
+static const unsigned p910_pwm3_pin3[] = {VCXO_OUT};
+static const unsigned p910_pri_jtag_pin1[] = {GPIO117, GPIO118, GPIO119,
+	GPIO120};
+static const unsigned p910_sec1_jtag_pin1[] = {MMC1_DAT7, MMC1_DAT6, MMC1_DAT5,
+	MMC1_CMD, MMC1_CD};
+static const unsigned p910_sec2_jtag_pin1[] = {MMC1_DAT3, MMC1_DAT2, MMC1_DAT1,
+	MMC1_DAT0, MMC1_CLK};
+static const unsigned p910_hsl_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40,
+	GPIO41, GPIO42};
+static const unsigned p910_hsl_pin2[] = {GPIO61, GPIO62, GPIO63, GPIO64,
+	GPIO65, GPIO66};
+static const unsigned p910_hsl_pin3[] = {MMC1_DAT3, MMC1_DAT2, MMC1_DAT1,
+	MMC1_DAT0, MMC1_CMD, MMC1_CLK};
+static const unsigned p910_w1_pin1[] = {GPIO59};
+static const unsigned p910_w1_pin2[] = {GPIO65};
+static const unsigned p910_w1_pin3[] = {GPIO106};
+static const unsigned p910_w1_pin4[] = {GPIO123};
+static const unsigned p910_kpmk_pin1[] = {GPIO0, GPIO1, GPIO2, GPIO3, GPIO4,
+	GPIO5, GPIO6, GPIO7, GPIO8, GPIO9, GPIO10, GPIO11, GPIO12, GPIO13,
+	GPIO14, GPIO15};
+static const unsigned p910_kpmk_pin2[] = {GPIO0, GPIO1, GPIO2, GPIO3, GPIO4,
+	GPIO5, GPIO6, GPIO7, GPIO8, GPIO9, GPIO12};
+static const unsigned p910_kpdk_pin1[] = {GPIO12, GPIO13, GPIO14, GPIO15,
+	GPIO16, GPIO17, GPIO18, GPIO19};
+static const unsigned p910_tds_pin1[] = {GPIO55, GPIO56, GPIO57, GPIO58,
+	GPIO59};
+static const unsigned p910_tds_pin2[] = {GPIO55, GPIO57, GPIO58, GPIO59};
+static const unsigned p910_tb_pin1[] = {GPIO14, GPIO15, GPIO16, GPIO17};
+static const unsigned p910_tb_pin2[] = {GPIO55, GPIO56, GPIO57, GPIO58};
+static const unsigned p910_tb_pin3[] = {MMC1_DAT7, MMC1_DAT6, MMC1_DAT5,
+	MMC1_DAT4};
+static const unsigned p910_ext_dma0_pin1[] = {GPIO72};
+static const unsigned p910_ext_dma0_pin2[] = {ND_IO15};
+static const unsigned p910_ext_dma0_pin3[] = {ND_NRE};
+static const unsigned p910_ext_dma1_pin1[] = {GPIO73};
+static const unsigned p910_ext_dma1_pin2[] = {GPIO123};
+static const unsigned p910_ext_dma1_pin3[] = {GPIO126};
+static const unsigned p910_ext_dma2_pin1[] = {GPIO74};
+static const unsigned p910_ext0_int_pin1[] = {GPIO44};
+static const unsigned p910_ext0_int_pin2[] = {ND_IO13};
+static const unsigned p910_ext1_int_pin1[] = {GPIO45};
+static const unsigned p910_ext1_int_pin2[] = {ND_IO12};
+static const unsigned p910_ext2_int_pin1[] = {GPIO46};
+static const unsigned p910_ext2_int_pin2[] = {GPIO125};
+static const unsigned p910_dac_st23_pin1[] = {GPIO32};
+static const unsigned p910_dac_st23_pin2[] = {GPIO43};
+static const unsigned p910_dac_st23_pin3[] = {GPIO52};
+static const unsigned p910_dac_st23_pin4[] = {GPIO124};
+static const unsigned p910_vcxo_out_pin1[] = {GPIO50};
+static const unsigned p910_vcxo_out_pin2[] = {VCXO_OUT};
+static const unsigned p910_vcxo_out_pin3[] = {GPIO20};
+static const unsigned p910_vcxo_req_pin1[] = {GPIO49};
+static const unsigned p910_vcxo_req_pin2[] = {GPIO125};
+static const unsigned p910_vcxo_out2_pin1[] = {GPIO86};
+static const unsigned p910_vcxo_out2_pin2[] = {ND_IO9};
+static const unsigned p910_vcxo_req2_pin1[] = {GPIO84};
+static const unsigned p910_ulpi_pin1[] = {GPIO67, GPIO68, GPIO69, GPIO70,
+	GPIO71, GPIO72, GPIO73, GPIO74, GPIO75, GPIO76, GPIO77, GPIO78};
+static const unsigned p910_nand_pin1[] = {ND_IO15, ND_IO14, ND_IO13, ND_IO12,
+	ND_IO11, ND_IO10, ND_IO9, ND_IO8, ND_IO7, ND_IO6, ND_IO5, ND_IO4,
+	ND_IO3, ND_IO2, ND_IO1, ND_IO0, ND_NCS0, ND_NWE, ND_NRE, ND_CLE,
+	ND_ALE, ND_RDY0};
+static const unsigned p910_gpio0_pin1[] = {GPIO0};
+static const unsigned p910_gpio0_pin2[] = {SM_ADV};
+static const unsigned p910_gpio1_pin1[] = {GPIO1};
+static const unsigned p910_gpio1_pin2[] = {ND_RDY1};
+static const unsigned p910_gpio2_pin1[] = {GPIO2};
+static const unsigned p910_gpio2_pin2[] = {SM_ADVMUX};
+static const unsigned p910_gpio3_pin1[] = {GPIO3};
+static const unsigned p910_gpio3_pin2[] = {SM_RDY};
+static const unsigned p910_gpio20_pin1[] = {GPIO20};
+static const unsigned p910_gpio20_pin2[] = {ND_IO15};
+static const unsigned p910_gpio20_pin3[] = {MMC1_DAT6};
+static const unsigned p910_gpio21_pin1[] = {GPIO21};
+static const unsigned p910_gpio21_pin2[] = {ND_IO14};
+static const unsigned p910_gpio21_pin3[] = {MMC1_DAT5};
+static const unsigned p910_gpio22_pin1[] = {GPIO22};
+static const unsigned p910_gpio22_pin2[] = {ND_IO13};
+static const unsigned p910_gpio22_pin3[] = {MMC1_DAT4};
+static const unsigned p910_gpio23_pin1[] = {GPIO23};
+static const unsigned p910_gpio23_pin2[] = {ND_IO12};
+static const unsigned p910_gpio23_pin3[] = {MMC1_CD};
+static const unsigned p910_gpio24_pin1[] = {GPIO24};
+static const unsigned p910_gpio24_pin2[] = {ND_IO11};
+static const unsigned p910_gpio24_pin3[] = {MMC1_DAT7};
+static const unsigned p910_gpio25_pin1[] = {GPIO25};
+static const unsigned p910_gpio25_pin2[] = {ND_IO10};
+static const unsigned p910_gpio26_pin1[] = {GPIO26};
+static const unsigned p910_gpio26_pin2[] = {ND_IO9};
+static const unsigned p910_gpio27_pin1[] = {GPIO27};
+static const unsigned p910_gpio27_pin2[] = {ND_IO8};
+static const unsigned p910_gpio85_pin1[] = {GPIO85};
+static const unsigned p910_gpio85_pin2[] = {ND_NCS0};
+static const unsigned p910_gpio86_pin1[] = {GPIO86};
+static const unsigned p910_gpio86_pin2[] = {ND_NCS1};
+static const unsigned p910_gpio87_pin1[] = {GPIO87};
+static const unsigned p910_gpio87_pin2[] = {SM_NCS0};
+static const unsigned p910_gpio88_pin1[] = {GPIO88};
+static const unsigned p910_gpio88_pin2[] = {SM_NCS1};
+static const unsigned p910_gpio89_pin1[] = {GPIO89};
+static const unsigned p910_gpio89_pin2[] = {ND_NWE};
+static const unsigned p910_gpio90_pin1[] = {GPIO90};
+static const unsigned p910_gpio90_pin2[] = {ND_NRE};
+static const unsigned p910_gpio91_pin1[] = {GPIO91};
+static const unsigned p910_gpio91_pin2[] = {ND_ALE};
+static const unsigned p910_gpio92_pin1[] = {GPIO92};
+static const unsigned p910_gpio92_pin2[] = {ND_RDY0};
+
+static struct pxa3xx_pin_group pxa910_grps[] = {
+	GRP_910("usim2 3p1", USIM2, p910_usim2_pin1),
+	GRP_910("usim2 3p2", USIM2, p910_usim2_pin2),
+	GRP_910("mmc1 12p", MMC1, p910_mmc1_pin1),
+	GRP_910("mmc2 10p", MMC2, p910_mmc2_pin1),
+	GRP_910("mmc3 6p", MMC3, p910_mmc3_pin1),
+	GRP_910("mmc3 10p", MMC3, p910_mmc3_pin2),
+	GRP_910("uart0 4p", UART0, p910_uart0_pin1),
+	GRP_910("uart1 2p1", UART1, p910_uart1_pin1),
+	GRP_910("uart1 2p2", UART1, p910_uart1_pin2),
+	GRP_910("uart1 2p3", UART1, p910_uart1_pin3),
+	GRP_910("uart1 4p4", UART1, p910_uart1_pin4),
+	GRP_910("uart1 4p5", UART1, p910_uart1_pin5),
+	GRP_910("uart2 2p1", UART2, p910_uart2_pin1),
+	GRP_910("uart2 2p2", UART2, p910_uart2_pin2),
+	GRP_910("uart2 4p3", UART2, p910_uart2_pin3),
+	GRP_910("uart2 4p4", UART2, p910_uart2_pin4),
+	GRP_910("twsi 2p1", TWSI, p910_twsi_pin1),
+	GRP_910("twsi 2p2", TWSI, p910_twsi_pin2),
+	GRP_910("twsi 2p3", TWSI, p910_twsi_pin3),
+	GRP_910("ccic", CCIC, p910_ccic_pin1),
+	GRP_910("lcd", LCD, p910_lcd_pin1),
+	GRP_910("spi 4p1", SPI, p910_spi_pin1),
+	GRP_910("spi 4p2", SPI, p910_spi_pin2),
+	GRP_910("spi 5p3", SPI, p910_spi_pin3),
+	GRP_910("spi 5p4", SPI, p910_spi_pin4),
+	GRP_910("dssp2 4p1", DSSP2, p910_dssp2_pin1),
+	GRP_910("dssp2 4p2", DSSP2, p910_dssp2_pin2),
+	GRP_910("dssp2 3p3", DSSP2, p910_dssp2_pin3),
+	GRP_910("dssp3 4p1", DSSP3, p910_dssp3_pin1),
+	GRP_910("dssp3 4p2", DSSP3, p910_dssp3_pin2),
+	GRP_910("dssp3 3p3", DSSP3, p910_dssp3_pin3),
+	GRP_910("ssp0 4p1", SSP0, p910_ssp0_pin1),
+	GRP_910("ssp0 4p2", SSP0, p910_ssp0_pin2),
+	GRP_910("ssp0 4p3", SSP0, p910_ssp0_pin3),
+	GRP_910("ssp0 4p4", SSP0, p910_ssp0_pin4),
+	GRP_910("ssp1 4p1", SSP1, p910_ssp1_pin1),
+	GRP_910("ssp1 5p2", SSP1, p910_ssp1_pin2),
+	GRP_910("ssp2 4p1", SSP2, p910_ssp2_pin1),
+	GRP_910("ssp2 4p2", SSP2, p910_ssp2_pin2),
+	GRP_910("ssp2 4p3", SSP2, p910_ssp2_pin3),
+	GRP_910("ssp2 4p4", SSP2, p910_ssp2_pin4),
+	GRP_910("gssp", GSSP, p910_gssp_pin1),
+	GRP_910("pwm0", PWM0, p910_pwm0_pin1),
+	GRP_910("pwm1-1", PWM1, p910_pwm1_pin1),
+	GRP_910("pwm1-2", PWM1, p910_pwm1_pin2),
+	GRP_910("pwm2", PWM2, p910_pwm2_pin1),
+	GRP_910("pwm3-1", PWM3, p910_pwm3_pin1),
+	GRP_910("pwm3-2", PWM3, p910_pwm3_pin2),
+	GRP_910("pwm3-3", PWM3, p910_pwm3_pin3),
+	GRP_910("pri jtag", PRI_JTAG, p910_pri_jtag_pin1),
+	GRP_910("sec1 jtag", SEC1_JTAG, p910_sec1_jtag_pin1),
+	GRP_910("sec2 jtag", SEC2_JTAG, p910_sec2_jtag_pin1),
+	GRP_910("hsl 6p1", HSL, p910_hsl_pin1),
+	GRP_910("hsl 6p2", HSL, p910_hsl_pin2),
+	GRP_910("hsl 6p3", HSL, p910_hsl_pin3),
+	GRP_910("w1-1", ONE_WIRE, p910_w1_pin1),
+	GRP_910("w1-2", ONE_WIRE, p910_w1_pin2),
+	GRP_910("w1-3", ONE_WIRE, p910_w1_pin3),
+	GRP_910("w1-4", ONE_WIRE, p910_w1_pin4),
+	GRP_910("kpmk 16p1", KP_MK, p910_kpmk_pin1),
+	GRP_910("kpmk 11p2", KP_MK, p910_kpmk_pin2),
+	GRP_910("kpdk 8p1", KP_DK, p910_kpdk_pin1),
+	GRP_910("tds 5p1", TDS, p910_tds_pin1),
+	GRP_910("tds 4p2", TDS, p910_tds_pin2),
+	GRP_910("tb 4p1", TB, p910_tb_pin1),
+	GRP_910("tb 4p2", TB, p910_tb_pin2),
+	GRP_910("tb 4p3", TB, p910_tb_pin3),
+	GRP_910("ext dma0-1", EXT_DMA, p910_ext_dma0_pin1),
+	GRP_910("ext dma0-2", EXT_DMA, p910_ext_dma0_pin2),
+	GRP_910("ext dma0-3", EXT_DMA, p910_ext_dma0_pin3),
+	GRP_910("ext dma1-1", EXT_DMA, p910_ext_dma1_pin1),
+	GRP_910("ext dma1-2", EXT_DMA, p910_ext_dma1_pin2),
+	GRP_910("ext dma1-3", EXT_DMA, p910_ext_dma1_pin3),
+	GRP_910("ext dma2", EXT_DMA, p910_ext_dma2_pin1),
+	GRP_910("ext0 int-1", EXT_INT, p910_ext0_int_pin1),
+	GRP_910("ext0 int-2", EXT_INT, p910_ext0_int_pin2),
+	GRP_910("ext1 int-1", EXT_INT, p910_ext1_int_pin1),
+	GRP_910("ext1 int-2", EXT_INT, p910_ext1_int_pin2),
+	GRP_910("ext2 int-1", EXT_INT, p910_ext2_int_pin1),
+	GRP_910("ext2 int-2", EXT_INT, p910_ext2_int_pin2),
+	GRP_910("dac st23-1", DAC_ST23, p910_dac_st23_pin1),
+	GRP_910("dac st23-2", DAC_ST23, p910_dac_st23_pin2),
+	GRP_910("dac st23-3", DAC_ST23, p910_dac_st23_pin3),
+	GRP_910("dac st23-4", DAC_ST23, p910_dac_st23_pin4),
+	GRP_910("vcxo out-1", VCXO_OUT, p910_vcxo_out_pin1),
+	GRP_910("vcxo out-2", VCXO_OUT, p910_vcxo_out_pin2),
+	GRP_910("vcxo out-3", VCXO_OUT, p910_vcxo_out_pin3),
+	GRP_910("vcxo req-1", VCXO_REQ, p910_vcxo_req_pin1),
+	GRP_910("vcxo req-2", VCXO_REQ, p910_vcxo_req_pin2),
+	GRP_910("vcxo out2-1", VCXO_OUT2, p910_vcxo_out2_pin1),
+	GRP_910("vcxo out2-2", VCXO_OUT2, p910_vcxo_out2_pin2),
+	GRP_910("vcxo req2", VCXO_REQ2, p910_vcxo_req2_pin1),
+	GRP_910("ulpi", ULPI, p910_ulpi_pin1),
+	GRP_910("nand", NAND, p910_nand_pin1),
+	GRP_910("gpio0-1", GPIO, p910_gpio0_pin1),
+	GRP_910("gpio0-2", GPIO, p910_gpio0_pin2),
+	GRP_910("gpio1-1", GPIO, p910_gpio1_pin1),
+	GRP_910("gpio1-2", GPIO, p910_gpio1_pin2),
+	GRP_910("gpio2-1", GPIO, p910_gpio2_pin1),
+	GRP_910("gpio2-2", GPIO, p910_gpio2_pin2),
+	GRP_910("gpio3-1", GPIO, p910_gpio3_pin1),
+	GRP_910("gpio3-2", GPIO, p910_gpio3_pin2),
+	GRP_910("gpio20-1", GPIO, p910_gpio20_pin1),
+	GRP_910("gpio20-2", GPIO, p910_gpio20_pin2),
+	GRP_910("gpio21-1", GPIO, p910_gpio21_pin1),
+	GRP_910("gpio21-2", GPIO, p910_gpio21_pin2),
+	GRP_910("gpio22-1", GPIO, p910_gpio22_pin1),
+	GRP_910("gpio22-2", GPIO, p910_gpio22_pin2),
+	GRP_910("gpio23-1", GPIO, p910_gpio23_pin1),
+	GRP_910("gpio23-2", GPIO, p910_gpio23_pin2),
+	GRP_910("gpio24-1", GPIO, p910_gpio24_pin1),
+	GRP_910("gpio24-2", GPIO, p910_gpio24_pin2),
+	GRP_910("gpio25-1", GPIO, p910_gpio25_pin1),
+	GRP_910("gpio25-2", GPIO, p910_gpio25_pin2),
+	GRP_910("gpio26-1", GPIO, p910_gpio26_pin1),
+	GRP_910("gpio26-2", GPIO, p910_gpio26_pin2),
+	GRP_910("gpio27-1", GPIO, p910_gpio27_pin1),
+	GRP_910("gpio27-2", GPIO, p910_gpio27_pin2),
+	GRP_910("gpio85-1", GPIO, p910_gpio85_pin1),
+	GRP_910("gpio85-2", GPIO, p910_gpio85_pin2),
+	GRP_910("gpio86-1", GPIO, p910_gpio86_pin1),
+	GRP_910("gpio86-2", GPIO, p910_gpio86_pin2),
+	GRP_910("gpio87-1", GPIO, p910_gpio87_pin1),
+	GRP_910("gpio87-2", GPIO, p910_gpio87_pin2),
+	GRP_910("gpio88-1", GPIO, p910_gpio88_pin1),
+	GRP_910("gpio88-2", GPIO, p910_gpio88_pin2),
+	GRP_910("gpio89-1", GPIO, p910_gpio89_pin1),
+	GRP_910("gpio89-2", GPIO, p910_gpio89_pin2),
+	GRP_910("gpio90-1", GPIO, p910_gpio90_pin1),
+	GRP_910("gpio90-2", GPIO, p910_gpio90_pin2),
+	GRP_910("gpio91-1", GPIO, p910_gpio91_pin1),
+	GRP_910("gpio91-2", GPIO, p910_gpio91_pin2),
+	GRP_910("gpio92-1", GPIO, p910_gpio92_pin1),
+	GRP_910("gpio92-2", GPIO, p910_gpio92_pin2),
+};
+
+static const char * const p910_usim2_grps[] = {"usim2 3p1", "usim2 3p2"};
+static const char * const p910_mmc1_grps[] = {"mmc1 12p"};
+static const char * const p910_mmc2_grps[] = {"mmc2 10p"};
+static const char * const p910_mmc3_grps[] = {"mmc3 6p", "mmc3 10p"};
+static const char * const p910_uart0_grps[] = {"uart0 4p"};
+static const char * const p910_uart1_grps[] = {"uart1 2p1", "uart1 2p2",
+	"uart1 2p3", "uart1 4p4", "uart1 4p5"};
+static const char * const p910_uart2_grps[] = {"uart2 2p1", "uart2 2p2",
+	"uart2 4p3", "uart2 4p4"};
+static const char * const p910_twsi_grps[] = {"twsi 2p1", "twsi 2p2",
+	"twsi 2p3"};
+static const char * const p910_ccic_grps[] = {"ccic"};
+static const char * const p910_lcd_grps[] = {"lcd"};
+static const char * const p910_spi_grps[] = {"spi 4p1", "spi 4p2", "spi 5p3",
+	"spi 5p4"};
+static const char * const p910_dssp2_grps[] = {"dssp2 4p1", "dssp2 4p2",
+	"dssp2 3p3"};
+static const char * const p910_dssp3_grps[] = {"dssp3 4p1", "dssp3 4p2",
+	"dssp3 3p3"};
+static const char * const p910_ssp0_grps[] = {"ssp0 4p1", "ssp0 4p2",
+	"ssp0 4p3", "ssp0 4p4"};
+static const char * const p910_ssp1_grps[] = {"ssp1 4p1", "ssp1 5p2"};
+static const char * const p910_ssp2_grps[] = {"ssp2 4p1", "ssp2 4p2",
+	"ssp2 4p3", "ssp2 4p4"};
+static const char * const p910_gssp_grps[] = {"gssp"};
+static const char * const p910_pwm0_grps[] = {"pwm0"};
+static const char * const p910_pwm1_grps[] = {"pwm1-1", "pwm1-2"};
+static const char * const p910_pwm2_grps[] = {"pwm2"};
+static const char * const p910_pwm3_grps[] = {"pwm3-1", "pwm3-2", "pwm3-3"};
+static const char * const p910_pri_jtag_grps[] = {"pri jtag"};
+static const char * const p910_sec1_jtag_grps[] = {"sec1 jtag"};
+static const char * const p910_sec2_jtag_grps[] = {"sec2 jtag"};
+static const char * const p910_hsl_grps[] = {"hsl 6p1", "hsl 6p2", "hsl 6p3"};
+static const char * const p910_w1_grps[] = {"w1-1", "w1-2", "w1-3", "w1-4"};
+static const char * const p910_kpmk_grps[] = {"kpmk 16p1", "kpmk 11p2"};
+static const char * const p910_kpdk_grps[] = {"kpdk 8p1"};
+static const char * const p910_tds_grps[] = {"tds 5p1", "tds 4p2"};
+static const char * const p910_tb_grps[] = {"tb 4p1", "tb 4p2", "tb 4p3"};
+static const char * const p910_dma0_grps[] = {"ext dma0-1", "ext dma0-2",
+	"ext dma0-3"};
+static const char * const p910_dma1_grps[] = {"ext dma1-1", "ext dma1-2",
+	"ext dma1-3"};
+static const char * const p910_dma2_grps[] = {"ext dma2"};
+static const char * const p910_int0_grps[] = {"ext0 int-1", "ext0 int-2"};
+static const char * const p910_int1_grps[] = {"ext1 int-1", "ext1 int-2"};
+static const char * const p910_int2_grps[] = {"ext2 int-1", "ext2 int-2"};
+static const char * const p910_dac_st23_grps[] = {"dac st23-1", "dac st23-2",
+	"dac st23-3", "dac st23-4"};
+static const char * const p910_vcxo_out_grps[] = {"vcxo out-1", "vcxo out-2",
+	"vcxo out-3"};
+static const char * const p910_vcxo_req_grps[] = {"vcxo req-1", "vcxo req-2"};
+static const char * const p910_vcxo_out2_grps[] = {"vcxo out2-1",
+	"vcxo out2-2"};
+static const char * const p910_vcxo_req2_grps[] = {"vcxo req2"};
+static const char * const p910_ulpi_grps[] = {"ulpi"};
+static const char * const p910_nand_grps[] = {"nand"};
+static const char * const p910_gpio0_grps[] = {"gpio0-1", "gpio0-2"};
+static const char * const p910_gpio1_grps[] = {"gpio1-1", "gpio1-2"};
+static const char * const p910_gpio2_grps[] = {"gpio2-1", "gpio2-2"};
+static const char * const p910_gpio3_grps[] = {"gpio3-1", "gpio3-2"};
+static const char * const p910_gpio20_grps[] = {"gpio20-1", "gpio20-2"};
+static const char * const p910_gpio21_grps[] = {"gpio21-1", "gpio21-2"};
+static const char * const p910_gpio22_grps[] = {"gpio22-1", "gpio22-2"};
+static const char * const p910_gpio23_grps[] = {"gpio23-1", "gpio23-2"};
+static const char * const p910_gpio24_grps[] = {"gpio24-1", "gpio24-2"};
+static const char * const p910_gpio25_grps[] = {"gpio25-1", "gpio25-2"};
+static const char * const p910_gpio26_grps[] = {"gpio26-1", "gpio26-2"};
+static const char * const p910_gpio27_grps[] = {"gpio27-1", "gpio27-2"};
+static const char * const p910_gpio85_grps[] = {"gpio85-1", "gpio85-2"};
+static const char * const p910_gpio86_grps[] = {"gpio86-1", "gpio86-2"};
+static const char * const p910_gpio87_grps[] = {"gpio87-1", "gpio87-2"};
+static const char * const p910_gpio88_grps[] = {"gpio88-1", "gpio88-2"};
+static const char * const p910_gpio89_grps[] = {"gpio89-1", "gpio89-2"};
+static const char * const p910_gpio90_grps[] = {"gpio90-1", "gpio90-2"};
+static const char * const p910_gpio91_grps[] = {"gpio91-1", "gpio91-2"};
+static const char * const p910_gpio92_grps[] = {"gpio92-1", "gpio92-2"};
+
+static struct pxa3xx_pmx_func pxa910_funcs[] = {
+	{"usim2",	ARRAY_AND_SIZE(p910_usim2_grps)},
+	{"mmc1",	ARRAY_AND_SIZE(p910_mmc1_grps)},
+	{"mmc2",	ARRAY_AND_SIZE(p910_mmc2_grps)},
+	{"mmc3",	ARRAY_AND_SIZE(p910_mmc3_grps)},
+	{"uart0",	ARRAY_AND_SIZE(p910_uart0_grps)},
+	{"uart1",	ARRAY_AND_SIZE(p910_uart1_grps)},
+	{"uart2",	ARRAY_AND_SIZE(p910_uart2_grps)},
+	{"twsi",	ARRAY_AND_SIZE(p910_twsi_grps)},
+	{"ccic",	ARRAY_AND_SIZE(p910_ccic_grps)},
+	{"lcd",		ARRAY_AND_SIZE(p910_lcd_grps)},
+	{"spi",		ARRAY_AND_SIZE(p910_spi_grps)},
+	{"dssp2",	ARRAY_AND_SIZE(p910_dssp2_grps)},
+	{"dssp3",	ARRAY_AND_SIZE(p910_dssp3_grps)},
+	{"ssp0",	ARRAY_AND_SIZE(p910_ssp0_grps)},
+	{"ssp1",	ARRAY_AND_SIZE(p910_ssp1_grps)},
+	{"ssp2",	ARRAY_AND_SIZE(p910_ssp2_grps)},
+	{"gssp",	ARRAY_AND_SIZE(p910_gssp_grps)},
+	{"pwm0",	ARRAY_AND_SIZE(p910_pwm0_grps)},
+	{"pwm1",	ARRAY_AND_SIZE(p910_pwm1_grps)},
+	{"pwm2",	ARRAY_AND_SIZE(p910_pwm2_grps)},
+	{"pwm3",	ARRAY_AND_SIZE(p910_pwm3_grps)},
+	{"pri_jtag",	ARRAY_AND_SIZE(p910_pri_jtag_grps)},
+	{"sec1_jtag",	ARRAY_AND_SIZE(p910_sec1_jtag_grps)},
+	{"sec2_jtag",	ARRAY_AND_SIZE(p910_sec2_jtag_grps)},
+	{"hsl",		ARRAY_AND_SIZE(p910_hsl_grps)},
+	{"w1",		ARRAY_AND_SIZE(p910_w1_grps)},
+	{"kpmk",	ARRAY_AND_SIZE(p910_kpmk_grps)},
+	{"kpdk",	ARRAY_AND_SIZE(p910_kpdk_grps)},
+	{"tds",		ARRAY_AND_SIZE(p910_tds_grps)},
+	{"tb",		ARRAY_AND_SIZE(p910_tb_grps)},
+	{"dma0",	ARRAY_AND_SIZE(p910_dma0_grps)},
+	{"dma1",	ARRAY_AND_SIZE(p910_dma1_grps)},
+	{"dma2",	ARRAY_AND_SIZE(p910_dma2_grps)},
+	{"int0",	ARRAY_AND_SIZE(p910_int0_grps)},
+	{"int1",	ARRAY_AND_SIZE(p910_int1_grps)},
+	{"int2",	ARRAY_AND_SIZE(p910_int2_grps)},
+	{"dac_st23",	ARRAY_AND_SIZE(p910_dac_st23_grps)},
+	{"vcxo_out",	ARRAY_AND_SIZE(p910_vcxo_out_grps)},
+	{"vcxo_req",	ARRAY_AND_SIZE(p910_vcxo_req_grps)},
+	{"vcxo_out2",	ARRAY_AND_SIZE(p910_vcxo_out2_grps)},
+	{"vcxo_req2",	ARRAY_AND_SIZE(p910_vcxo_req2_grps)},
+	{"ulpi",	ARRAY_AND_SIZE(p910_ulpi_grps)},
+	{"nand",	ARRAY_AND_SIZE(p910_nand_grps)},
+	{"gpio0",	ARRAY_AND_SIZE(p910_gpio0_grps)},
+	{"gpio1",	ARRAY_AND_SIZE(p910_gpio1_grps)},
+	{"gpio2",	ARRAY_AND_SIZE(p910_gpio2_grps)},
+	{"gpio3",	ARRAY_AND_SIZE(p910_gpio3_grps)},
+	{"gpio20",	ARRAY_AND_SIZE(p910_gpio20_grps)},
+	{"gpio21",	ARRAY_AND_SIZE(p910_gpio21_grps)},
+	{"gpio22",	ARRAY_AND_SIZE(p910_gpio22_grps)},
+	{"gpio23",	ARRAY_AND_SIZE(p910_gpio23_grps)},
+	{"gpio24",	ARRAY_AND_SIZE(p910_gpio24_grps)},
+	{"gpio25",	ARRAY_AND_SIZE(p910_gpio25_grps)},
+	{"gpio26",	ARRAY_AND_SIZE(p910_gpio26_grps)},
+	{"gpio27",	ARRAY_AND_SIZE(p910_gpio27_grps)},
+	{"gpio85",	ARRAY_AND_SIZE(p910_gpio85_grps)},
+	{"gpio86",	ARRAY_AND_SIZE(p910_gpio86_grps)},
+	{"gpio87",	ARRAY_AND_SIZE(p910_gpio87_grps)},
+	{"gpio88",	ARRAY_AND_SIZE(p910_gpio88_grps)},
+	{"gpio89",	ARRAY_AND_SIZE(p910_gpio89_grps)},
+	{"gpio90",	ARRAY_AND_SIZE(p910_gpio90_grps)},
+	{"gpio91",	ARRAY_AND_SIZE(p910_gpio91_grps)},
+	{"gpio92",	ARRAY_AND_SIZE(p910_gpio92_grps)},
+};
+
+static struct pinctrl_desc pxa910_pctrl_desc = {
+	.name		= "pxa910-pinctrl",
+	.owner		= THIS_MODULE,
+};
+
+static struct pxa3xx_pinmux_info pxa910_info = {
+	.mfp		= pxa910_mfp,
+	.num_mfp	= ARRAY_SIZE(pxa910_mfp),
+	.grps		= pxa910_grps,
+	.num_grps	= ARRAY_SIZE(pxa910_grps),
+	.funcs		= pxa910_funcs,
+	.num_funcs	= ARRAY_SIZE(pxa910_funcs),
+	.num_gpio	= 128,
+	.desc		= &pxa910_pctrl_desc,
+	.pads		= pxa910_pads,
+	.num_pads	= ARRAY_SIZE(pxa910_pads),
+
+	.cputype	= PINCTRL_PXA910,
+	.ds_mask	= PXA910_DS_MASK,
+	.ds_shift	= PXA910_DS_SHIFT,
+};
+
+static int __devinit pxa910_pinmux_probe(struct platform_device *pdev)
+{
+	return pxa3xx_pinctrl_register(pdev, &pxa910_info);
+}
+
+static int __devexit pxa910_pinmux_remove(struct platform_device *pdev)
+{
+	return pxa3xx_pinctrl_unregister(pdev);
+}
+
+static struct platform_driver pxa910_pinmux_driver = {
+	.driver = {
+		.name	= "pxa910-pinmux",
+		.owner	= THIS_MODULE,
+	},
+	.probe	= pxa910_pinmux_probe,
+	.remove	= __devexit_p(pxa910_pinmux_remove),
+};
+
+static int __init pxa910_pinmux_init(void)
+{
+	return platform_driver_register(&pxa910_pinmux_driver);
+}
+core_initcall_sync(pxa910_pinmux_init);
+
+static void __exit pxa910_pinmux_exit(void)
+{
+	platform_driver_unregister(&pxa910_pinmux_driver);
+}
+module_exit(pxa910_pinmux_exit);
+
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("PXA3xx pin control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
new file mode 100644
index 0000000..9b32968
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -0,0 +1,559 @@
+/*
+ * Driver for the NVIDIA Tegra pinmux
+ *
+ * Copyright (c) 2011, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Derived from code:
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2010 NVIDIA Corporation
+ * Copyright (C) 2009-2011 ST-Ericsson AB
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+
+#include <mach/pinconf-tegra.h>
+
+#include "pinctrl-tegra.h"
+
+#define DRIVER_NAME "tegra-pinmux-disabled"
+
+struct tegra_pmx {
+	struct device *dev;
+	struct pinctrl_dev *pctl;
+
+	const struct tegra_pinctrl_soc_data *soc;
+
+	int nbanks;
+	void __iomem **regs;
+};
+
+static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
+{
+	return readl(pmx->regs[bank] + reg);
+}
+
+static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg)
+{
+	writel(val, pmx->regs[bank] + reg);
+}
+
+static int tegra_pinctrl_list_groups(struct pinctrl_dev *pctldev,
+				     unsigned group)
+{
+	struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+	if (group >= pmx->soc->ngroups)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+						unsigned group)
+{
+	struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+	if (group >= pmx->soc->ngroups)
+		return NULL;
+
+	return pmx->soc->groups[group].name;
+}
+
+static int tegra_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+					unsigned group,
+					const unsigned **pins,
+					unsigned *num_pins)
+{
+	struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+	if (group >= pmx->soc->ngroups)
+		return -EINVAL;
+
+	*pins = pmx->soc->groups[group].pins;
+	*num_pins = pmx->soc->groups[group].npins;
+
+	return 0;
+}
+
+static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
+				       struct seq_file *s,
+				       unsigned offset)
+{
+	seq_printf(s, " " DRIVER_NAME);
+}
+
+static struct pinctrl_ops tegra_pinctrl_ops = {
+	.list_groups = tegra_pinctrl_list_groups,
+	.get_group_name = tegra_pinctrl_get_group_name,
+	.get_group_pins = tegra_pinctrl_get_group_pins,
+	.pin_dbg_show = tegra_pinctrl_pin_dbg_show,
+};
+
+static int tegra_pinctrl_list_funcs(struct pinctrl_dev *pctldev,
+				    unsigned function)
+{
+	struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+	if (function >= pmx->soc->nfunctions)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+					       unsigned function)
+{
+	struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+	if (function >= pmx->soc->nfunctions)
+		return NULL;
+
+	return pmx->soc->functions[function].name;
+}
+
+static int tegra_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
+					 unsigned function,
+					 const char * const **groups,
+					 unsigned * const num_groups)
+{
+	struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+	if (function >= pmx->soc->nfunctions)
+		return -EINVAL;
+
+	*groups = pmx->soc->functions[function].groups;
+	*num_groups = pmx->soc->functions[function].ngroups;
+
+	return 0;
+}
+
+static int tegra_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function,
+			       unsigned group)
+{
+	struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+	const struct tegra_pingroup *g;
+	int i;
+	u32 val;
+
+	if (group >= pmx->soc->ngroups)
+		return -EINVAL;
+	g = &pmx->soc->groups[group];
+
+	if (g->mux_reg < 0)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(g->funcs); i++) {
+		if (g->funcs[i] == function)
+			break;
+	}
+	if (i == ARRAY_SIZE(g->funcs))
+		return -EINVAL;
+
+	val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
+	val &= ~(0x3 << g->mux_bit);
+	val |= i << g->mux_bit;
+	pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
+
+	return 0;
+}
+
+static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
+				  unsigned function, unsigned group)
+{
+	struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+	const struct tegra_pingroup *g;
+	u32 val;
+
+	if (group >= pmx->soc->ngroups)
+		return;
+	g = &pmx->soc->groups[group];
+
+	if (g->mux_reg < 0)
+		return;
+
+	val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
+	val &= ~(0x3 << g->mux_bit);
+	val |= g->func_safe << g->mux_bit;
+	pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
+}
+
+static struct pinmux_ops tegra_pinmux_ops = {
+	.list_functions = tegra_pinctrl_list_funcs,
+	.get_function_name = tegra_pinctrl_get_func_name,
+	.get_function_groups = tegra_pinctrl_get_func_groups,
+	.enable = tegra_pinctrl_enable,
+	.disable = tegra_pinctrl_disable,
+};
+
+static int tegra_pinconf_reg(struct tegra_pmx *pmx,
+			     const struct tegra_pingroup *g,
+			     enum tegra_pinconf_param param,
+			     s8 *bank, s16 *reg, s8 *bit, s8 *width)
+{
+	switch (param) {
+	case TEGRA_PINCONF_PARAM_PULL:
+		*bank = g->pupd_bank;
+		*reg = g->pupd_reg;
+		*bit = g->pupd_bit;
+		*width = 2;
+		break;
+	case TEGRA_PINCONF_PARAM_TRISTATE:
+		*bank = g->tri_bank;
+		*reg = g->tri_reg;
+		*bit = g->tri_bit;
+		*width = 1;
+		break;
+	case TEGRA_PINCONF_PARAM_ENABLE_INPUT:
+		*bank = g->einput_bank;
+		*reg = g->einput_reg;
+		*bit = g->einput_bit;
+		*width = 1;
+		break;
+	case TEGRA_PINCONF_PARAM_OPEN_DRAIN:
+		*bank = g->odrain_bank;
+		*reg = g->odrain_reg;
+		*bit = g->odrain_bit;
+		*width = 1;
+		break;
+	case TEGRA_PINCONF_PARAM_LOCK:
+		*bank = g->lock_bank;
+		*reg = g->lock_reg;
+		*bit = g->lock_bit;
+		*width = 1;
+		break;
+	case TEGRA_PINCONF_PARAM_IORESET:
+		*bank = g->ioreset_bank;
+		*reg = g->ioreset_reg;
+		*bit = g->ioreset_bit;
+		*width = 1;
+		break;
+	case TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE:
+		*bank = g->drv_bank;
+		*reg = g->drv_reg;
+		*bit = g->hsm_bit;
+		*width = 1;
+		break;
+	case TEGRA_PINCONF_PARAM_SCHMITT:
+		*bank = g->drv_bank;
+		*reg = g->drv_reg;
+		*bit = g->schmitt_bit;
+		*width = 1;
+		break;
+	case TEGRA_PINCONF_PARAM_LOW_POWER_MODE:
+		*bank = g->drv_bank;
+		*reg = g->drv_reg;
+		*bit = g->lpmd_bit;
+		*width = 1;
+		break;
+	case TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH:
+		*bank = g->drv_bank;
+		*reg = g->drv_reg;
+		*bit = g->drvdn_bit;
+		*width = g->drvdn_width;
+		break;
+	case TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH:
+		*bank = g->drv_bank;
+		*reg = g->drv_reg;
+		*bit = g->drvup_bit;
+		*width = g->drvup_width;
+		break;
+	case TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING:
+		*bank = g->drv_bank;
+		*reg = g->drv_reg;
+		*bit = g->slwf_bit;
+		*width = g->slwf_width;
+		break;
+	case TEGRA_PINCONF_PARAM_SLEW_RATE_RISING:
+		*bank = g->drv_bank;
+		*reg = g->drv_reg;
+		*bit = g->slwr_bit;
+		*width = g->slwr_width;
+		break;
+	default:
+		dev_err(pmx->dev, "Invalid config param %04x\n", param);
+		return -ENOTSUPP;
+	}
+
+	if (*reg < 0) {
+		dev_err(pmx->dev,
+			"Config param %04x not supported on group %s\n",
+			param, g->name);
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static int tegra_pinconf_get(struct pinctrl_dev *pctldev,
+			     unsigned pin, unsigned long *config)
+{
+	return -ENOTSUPP;
+}
+
+static int tegra_pinconf_set(struct pinctrl_dev *pctldev,
+			     unsigned pin, unsigned long config)
+{
+	return -ENOTSUPP;
+}
+
+static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev,
+				   unsigned group, unsigned long *config)
+{
+	struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+	enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM(*config);
+	u16 arg;
+	const struct tegra_pingroup *g;
+	int ret;
+	s8 bank, bit, width;
+	s16 reg;
+	u32 val, mask;
+
+	if (group >= pmx->soc->ngroups)
+		return -EINVAL;
+	g = &pmx->soc->groups[group];
+
+	ret = tegra_pinconf_reg(pmx, g, param, &bank, &reg, &bit, &width);
+	if (ret < 0)
+		return ret;
+
+	val = pmx_readl(pmx, bank, reg);
+	mask = (1 << width) - 1;
+	arg = (val >> bit) & mask;
+
+	*config = TEGRA_PINCONF_PACK(param, arg);
+
+	return 0;
+}
+
+static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
+				   unsigned group, unsigned long config)
+{
+	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);
+	const struct tegra_pingroup *g;
+	int ret;
+	s8 bank, bit, width;
+	s16 reg;
+	u32 val, mask;
+
+	if (group >= pmx->soc->ngroups)
+		return -EINVAL;
+	g = &pmx->soc->groups[group];
+
+	ret = tegra_pinconf_reg(pmx, g, param, &bank, &reg, &bit, &width);
+	if (ret < 0)
+		return ret;
+
+	val = pmx_readl(pmx, bank, reg);
+
+	/* LOCK can't be cleared */
+	if (param == TEGRA_PINCONF_PARAM_LOCK) {
+		if ((val & BIT(bit)) && !arg)
+			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)
+		return -EINVAL;
+
+	/* Update register */
+	val &= ~(mask << bit);
+	val |= arg << bit;
+	pmx_writel(pmx, val, bank, reg);
+
+	return 0;
+}
+
+static void tegra_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+				   struct seq_file *s, unsigned offset)
+{
+}
+
+static void tegra_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
+					 struct seq_file *s, unsigned selector)
+{
+}
+
+struct pinconf_ops tegra_pinconf_ops = {
+	.pin_config_get = tegra_pinconf_get,
+	.pin_config_set = tegra_pinconf_set,
+	.pin_config_group_get = tegra_pinconf_group_get,
+	.pin_config_group_set = tegra_pinconf_group_set,
+	.pin_config_dbg_show = tegra_pinconf_dbg_show,
+	.pin_config_group_dbg_show = tegra_pinconf_group_dbg_show,
+};
+
+static struct pinctrl_gpio_range tegra_pinctrl_gpio_range = {
+	.name = "Tegra GPIOs",
+	.id = 0,
+	.base = 0,
+};
+
+static struct pinctrl_desc tegra_pinctrl_desc = {
+	.name = DRIVER_NAME,
+	.pctlops = &tegra_pinctrl_ops,
+	.pmxops = &tegra_pinmux_ops,
+	.confops = &tegra_pinconf_ops,
+	.owner = THIS_MODULE,
+};
+
+static struct of_device_id tegra_pinctrl_of_match[] __devinitdata = {
+#ifdef CONFIG_PINCTRL_TEGRA20
+	{
+		.compatible = "nvidia,tegra20-pinmux-disabled",
+		.data = tegra20_pinctrl_init,
+	},
+#endif
+#ifdef CONFIG_PINCTRL_TEGRA30
+	{
+		.compatible = "nvidia,tegra30-pinmux-disabled",
+		.data = tegra30_pinctrl_init,
+	},
+#endif
+	{},
+};
+
+static int __devinit tegra_pinctrl_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *match;
+	tegra_pinctrl_soc_initf initf = NULL;
+	struct tegra_pmx *pmx;
+	struct resource *res;
+	int i;
+
+	match = of_match_device(tegra_pinctrl_of_match, &pdev->dev);
+	if (match)
+		initf = (tegra_pinctrl_soc_initf)match->data;
+#ifdef CONFIG_PINCTRL_TEGRA20
+	if (!initf)
+		initf = tegra20_pinctrl_init;
+#endif
+	if (!initf) {
+		dev_err(&pdev->dev,
+			"Could not determine SoC-specific init func\n");
+		return -EINVAL;
+	}
+
+	pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
+	if (!pmx) {
+		dev_err(&pdev->dev, "Can't alloc tegra_pmx\n");
+		return -ENOMEM;
+	}
+	pmx->dev = &pdev->dev;
+
+	(*initf)(&pmx->soc);
+
+	tegra_pinctrl_gpio_range.npins = pmx->soc->ngpios;
+	tegra_pinctrl_desc.pins = pmx->soc->pins;
+	tegra_pinctrl_desc.npins = pmx->soc->npins;
+
+	for (i = 0; ; i++) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res)
+			break;
+	}
+	pmx->nbanks = i;
+
+	pmx->regs = devm_kzalloc(&pdev->dev, pmx->nbanks * sizeof(*pmx->regs),
+				 GFP_KERNEL);
+	if (!pmx->regs) {
+		dev_err(&pdev->dev, "Can't alloc regs pointer\n");
+		return -ENODEV;
+	}
+
+	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->pctl = pinctrl_register(&tegra_pinctrl_desc, &pdev->dev, pmx);
+	if (IS_ERR(pmx->pctl)) {
+		dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
+		return PTR_ERR(pmx->pctl);
+	}
+
+	pinctrl_add_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range);
+
+	platform_set_drvdata(pdev, pmx);
+
+	dev_dbg(&pdev->dev, "Probed Tegra pinctrl driver\n");
+
+	return 0;
+}
+
+static int __devexit tegra_pinctrl_remove(struct platform_device *pdev)
+{
+	struct tegra_pmx *pmx = platform_get_drvdata(pdev);
+
+	pinctrl_remove_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range);
+	pinctrl_unregister(pmx->pctl);
+
+	return 0;
+}
+
+static struct platform_driver tegra_pinctrl_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = tegra_pinctrl_of_match,
+	},
+	.probe = tegra_pinctrl_probe,
+	.remove = __devexit_p(tegra_pinctrl_remove),
+};
+
+static int __init tegra_pinctrl_init(void)
+{
+	return platform_driver_register(&tegra_pinctrl_driver);
+}
+arch_initcall(tegra_pinctrl_init);
+
+static void __exit tegra_pinctrl_exit(void)
+{
+	platform_driver_unregister(&tegra_pinctrl_driver);
+}
+module_exit(tegra_pinctrl_exit);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Tegra pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, tegra_pinctrl_of_match);
diff --git a/drivers/pinctrl/pinctrl-tegra.h b/drivers/pinctrl/pinctrl-tegra.h
new file mode 100644
index 0000000..782c795
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-tegra.h
@@ -0,0 +1,163 @@
+/*
+ * Driver for the NVIDIA Tegra pinmux
+ *
+ * Copyright (c) 2011, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __PINMUX_TEGRA_H__
+#define __PINMUX_TEGRA_H__
+
+/**
+ * struct tegra_function - Tegra pinctrl mux function
+ * @name: The name of the function, exported to pinctrl core.
+ * @groups: An array of pin groups that may select this function.
+ * @ngroups: The number of entries in @groups.
+ */
+struct tegra_function {
+	const char *name;
+	const char * const *groups;
+	unsigned ngroups;
+};
+
+/**
+ * struct tegra_pingroup - Tegra pin group
+ * @mux_reg:		Mux register offset. -1 if unsupported.
+ * @mux_bank:		Mux register bank. 0 if unsupported.
+ * @mux_bit:		Mux register bit. 0 if unsupported.
+ * @pupd_reg:		Pull-up/down register offset. -1 if unsupported.
+ * @pupd_bank:		Pull-up/down register bank. 0 if unsupported.
+ * @pupd_bit:		Pull-up/down register bit. 0 if unsupported.
+ * @tri_reg:		Tri-state register offset. -1 if unsupported.
+ * @tri_bank:		Tri-state register bank. 0 if unsupported.
+ * @tri_bit:		Tri-state register bit. 0 if unsupported.
+ * @einput_reg:		Enable-input register offset. -1 if unsupported.
+ * @einput_bank:	Enable-input register bank. 0 if unsupported.
+ * @einput_bit:		Enable-input register bit. 0 if unsupported.
+ * @odrain_reg:		Open-drain register offset. -1 if unsupported.
+ * @odrain_bank:	Open-drain register bank. 0 if unsupported.
+ * @odrain_bit:		Open-drain register bit. 0 if unsupported.
+ * @lock_reg:		Lock register offset. -1 if unsupported.
+ * @lock_bank:		Lock register bank. 0 if unsupported.
+ * @lock_bit:		Lock register bit. 0 if unsupported.
+ * @ioreset_reg:	IO reset register offset. -1 if unsupported.
+ * @ioreset_bank:	IO reset register bank. 0 if unsupported.
+ * @ioreset_bit:	IO reset register bit. 0 if unsupported.
+ * @drv_reg:		Drive fields register offset. -1 if unsupported.
+ *			This register contains the hsm, schmitt, lpmd, drvdn,
+ *			drvup, slwr, and slwf parameters.
+ * @drv_bank:		Drive fields register bank. 0 if unsupported.
+ * @hsm_bit:		High Speed Mode register bit. 0 if unsupported.
+ * @schmitt_bit:	Scmitt register bit. 0 if unsupported.
+ * @lpmd_bit:		Low Power Mode register bit. 0 if unsupported.
+ * @drvdn_bit:		Drive Down register bit. 0 if unsupported.
+ * @drvdn_width:	Drive Down field width. 0 if unsupported.
+ * @drvup_bit:		Drive Up register bit. 0 if unsupported.
+ * @drvup_width:	Drive Up field width. 0 if unsupported.
+ * @slwr_bit:		Slew Rising register bit. 0 if unsupported.
+ * @slwr_width:		Slew Rising field width. 0 if unsupported.
+ * @slwf_bit:		Slew Falling register bit. 0 if unsupported.
+ * @slwf_width:		Slew Falling field width. 0 if unsupported.
+ *
+ * A representation of a group of pins (possibly just one pin) in the Tegra
+ * pin controller. Each group allows some parameter or parameters to be
+ * configured. The most common is mux function selection. Many others exist
+ * such as pull-up/down, tri-state, etc. Tegra's pin controller is complex;
+ * certain groups may only support configuring certain parameters, hence
+ * each parameter is optional, represented by a -1 "reg" value.
+ */
+struct tegra_pingroup {
+	const char *name;
+	const unsigned *pins;
+	unsigned npins;
+	unsigned funcs[4];
+	unsigned func_safe;
+	s16 mux_reg;
+	s16 pupd_reg;
+	s16 tri_reg;
+	s16 einput_reg;
+	s16 odrain_reg;
+	s16 lock_reg;
+	s16 ioreset_reg;
+	s16 drv_reg;
+	u32 mux_bank:2;
+	u32 pupd_bank:2;
+	u32 tri_bank:2;
+	u32 einput_bank:2;
+	u32 odrain_bank:2;
+	u32 ioreset_bank:2;
+	u32 lock_bank:2;
+	u32 drv_bank:2;
+	u32 mux_bit:5;
+	u32 pupd_bit:5;
+	u32 tri_bit:5;
+	u32 einput_bit:5;
+	u32 odrain_bit:5;
+	u32 lock_bit:5;
+	u32 ioreset_bit:5;
+	u32 hsm_bit:5;
+	u32 schmitt_bit:5;
+	u32 lpmd_bit:5;
+	u32 drvdn_bit:5;
+	u32 drvup_bit:5;
+	u32 slwr_bit:5;
+	u32 slwf_bit:5;
+	u32 drvdn_width:6;
+	u32 drvup_width:6;
+	u32 slwr_width:6;
+	u32 slwf_width:6;
+};
+
+/**
+ * struct tegra_pinctrl_soc_data - Tegra pin controller driver configuration
+ * @ngpios:	The number of GPIO pins the pin controller HW affects.
+ * @pins:	An array describing all pins the pin controller affects.
+ *		All pins which are also GPIOs must be listed first within the
+ *		array, and be numbered identically to the GPIO controller's
+ *		numbering.
+ * @npins:	The numbmer of entries in @pins.
+ * @functions:	An array describing all mux functions the SoC supports.
+ * @nfunctions:	The numbmer of entries in @functions.
+ * @groups:	An array describing all pin groups the pin SoC supports.
+ * @ngroups:	The numbmer of entries in @groups.
+ */
+struct tegra_pinctrl_soc_data {
+	unsigned ngpios;
+	const struct pinctrl_pin_desc *pins;
+	unsigned npins;
+	const struct tegra_function *functions;
+	unsigned nfunctions;
+	const struct tegra_pingroup *groups;
+	unsigned ngroups;
+};
+
+/**
+ * tegra_pinctrl_soc_initf() - Retrieve pin controller details for a SoC.
+ * @soc_data:	This pointer must be updated to point at a struct containing
+ *		details of the SoC.
+ */
+typedef void (*tegra_pinctrl_soc_initf)(
+			const struct tegra_pinctrl_soc_data **soc_data);
+
+/**
+ * tegra20_pinctrl_init() - Retrieve pin controller details for Tegra20
+ * @soc_data:	This pointer will be updated to point at a struct containing
+ *		details of Tegra20's pin controller.
+ */
+void tegra20_pinctrl_init(const struct tegra_pinctrl_soc_data **soc_data);
+/**
+ * tegra30_pinctrl_init() - Retrieve pin controller details for Tegra20
+ * @soc_data:	This pointer will be updated to point at a struct containing
+ *		details of Tegra30's pin controller.
+ */
+void tegra30_pinctrl_init(const struct tegra_pinctrl_soc_data **soc_data);
+
+#endif
diff --git a/drivers/pinctrl/pinctrl-tegra20.c b/drivers/pinctrl/pinctrl-tegra20.c
new file mode 100644
index 0000000..f69ff96
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-tegra20.c
@@ -0,0 +1,2860 @@
+/*
+ * Pinctrl data for the NVIDIA Tegra20 pinmux
+ *
+ * Copyright (c) 2011, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Derived from code:
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2010 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "pinctrl-tegra.h"
+
+/*
+ * Most pins affected by the pinmux can also be GPIOs. Define these first.
+ * These must match how the GPIO driver names/numbers its pins.
+ */
+#define _GPIO(offset)			(offset)
+
+#define TEGRA_PIN_VI_GP6_PA0		_GPIO(0)
+#define TEGRA_PIN_UART3_CTS_N_PA1	_GPIO(1)
+#define TEGRA_PIN_DAP2_FS_PA2		_GPIO(2)
+#define TEGRA_PIN_DAP2_SCLK_PA3		_GPIO(3)
+#define TEGRA_PIN_DAP2_DIN_PA4		_GPIO(4)
+#define TEGRA_PIN_DAP2_DOUT_PA5		_GPIO(5)
+#define TEGRA_PIN_SDIO3_CLK_PA6		_GPIO(6)
+#define TEGRA_PIN_SDIO3_CMD_PA7		_GPIO(7)
+#define TEGRA_PIN_GMI_AD17_PB0		_GPIO(8)
+#define TEGRA_PIN_GMI_AD18_PB1		_GPIO(9)
+#define TEGRA_PIN_LCD_PWR0_PB2		_GPIO(10)
+#define TEGRA_PIN_LCD_PCLK_PB3		_GPIO(11)
+#define TEGRA_PIN_SDIO3_DAT3_PB4	_GPIO(12)
+#define TEGRA_PIN_SDIO3_DAT2_PB5	_GPIO(13)
+#define TEGRA_PIN_SDIO3_DAT1_PB6	_GPIO(14)
+#define TEGRA_PIN_SDIO3_DAT0_PB7	_GPIO(15)
+#define TEGRA_PIN_UART3_RTS_N_PC0	_GPIO(16)
+#define TEGRA_PIN_LCD_PWR1_PC1		_GPIO(17)
+#define TEGRA_PIN_UART2_TXD_PC2		_GPIO(18)
+#define TEGRA_PIN_UART2_RXD_PC3		_GPIO(19)
+#define TEGRA_PIN_GEN1_I2C_SCL_PC4	_GPIO(20)
+#define TEGRA_PIN_GEN1_I2C_SDA_PC5	_GPIO(21)
+#define TEGRA_PIN_LCD_PWR2_PC6		_GPIO(22)
+#define TEGRA_PIN_GMI_WP_N_PC7		_GPIO(23)
+#define TEGRA_PIN_SDIO3_DAT5_PD0	_GPIO(24)
+#define TEGRA_PIN_SDIO3_DAT4_PD1	_GPIO(25)
+#define TEGRA_PIN_VI_GP5_PD2		_GPIO(26)
+#define TEGRA_PIN_SDIO3_DAT6_PD3	_GPIO(27)
+#define TEGRA_PIN_SDIO3_DAT7_PD4	_GPIO(28)
+#define TEGRA_PIN_VI_D1_PD5		_GPIO(29)
+#define TEGRA_PIN_VI_VSYNC_PD6		_GPIO(30)
+#define TEGRA_PIN_VI_HSYNC_PD7		_GPIO(31)
+#define TEGRA_PIN_LCD_D0_PE0		_GPIO(32)
+#define TEGRA_PIN_LCD_D1_PE1		_GPIO(33)
+#define TEGRA_PIN_LCD_D2_PE2		_GPIO(34)
+#define TEGRA_PIN_LCD_D3_PE3		_GPIO(35)
+#define TEGRA_PIN_LCD_D4_PE4		_GPIO(36)
+#define TEGRA_PIN_LCD_D5_PE5		_GPIO(37)
+#define TEGRA_PIN_LCD_D6_PE6		_GPIO(38)
+#define TEGRA_PIN_LCD_D7_PE7		_GPIO(39)
+#define TEGRA_PIN_LCD_D8_PF0		_GPIO(40)
+#define TEGRA_PIN_LCD_D9_PF1		_GPIO(41)
+#define TEGRA_PIN_LCD_D10_PF2		_GPIO(42)
+#define TEGRA_PIN_LCD_D11_PF3		_GPIO(43)
+#define TEGRA_PIN_LCD_D12_PF4		_GPIO(44)
+#define TEGRA_PIN_LCD_D13_PF5		_GPIO(45)
+#define TEGRA_PIN_LCD_D14_PF6		_GPIO(46)
+#define TEGRA_PIN_LCD_D15_PF7		_GPIO(47)
+#define TEGRA_PIN_GMI_AD0_PG0		_GPIO(48)
+#define TEGRA_PIN_GMI_AD1_PG1		_GPIO(49)
+#define TEGRA_PIN_GMI_AD2_PG2		_GPIO(50)
+#define TEGRA_PIN_GMI_AD3_PG3		_GPIO(51)
+#define TEGRA_PIN_GMI_AD4_PG4		_GPIO(52)
+#define TEGRA_PIN_GMI_AD5_PG5		_GPIO(53)
+#define TEGRA_PIN_GMI_AD6_PG6		_GPIO(54)
+#define TEGRA_PIN_GMI_AD7_PG7		_GPIO(55)
+#define TEGRA_PIN_GMI_AD8_PH0		_GPIO(56)
+#define TEGRA_PIN_GMI_AD9_PH1		_GPIO(57)
+#define TEGRA_PIN_GMI_AD10_PH2		_GPIO(58)
+#define TEGRA_PIN_GMI_AD11_PH3		_GPIO(59)
+#define TEGRA_PIN_GMI_AD12_PH4		_GPIO(60)
+#define TEGRA_PIN_GMI_AD13_PH5		_GPIO(61)
+#define TEGRA_PIN_GMI_AD14_PH6		_GPIO(62)
+#define TEGRA_PIN_GMI_AD15_PH7		_GPIO(63)
+#define TEGRA_PIN_GMI_HIOW_N_PI0	_GPIO(64)
+#define TEGRA_PIN_GMI_HIOR_N_PI1	_GPIO(65)
+#define TEGRA_PIN_GMI_CS5_N_PI2		_GPIO(66)
+#define TEGRA_PIN_GMI_CS6_N_PI3		_GPIO(67)
+#define TEGRA_PIN_GMI_RST_N_PI4		_GPIO(68)
+#define TEGRA_PIN_GMI_IORDY_PI5		_GPIO(69)
+#define TEGRA_PIN_GMI_CS7_N_PI6		_GPIO(70)
+#define TEGRA_PIN_GMI_WAIT_PI7		_GPIO(71)
+#define TEGRA_PIN_GMI_CS0_N_PJ0		_GPIO(72)
+#define TEGRA_PIN_LCD_DE_PJ1		_GPIO(73)
+#define TEGRA_PIN_GMI_CS1_N_PJ2		_GPIO(74)
+#define TEGRA_PIN_LCD_HSYNC_PJ3		_GPIO(75)
+#define TEGRA_PIN_LCD_VSYNC_PJ4		_GPIO(76)
+#define TEGRA_PIN_UART2_CTS_N_PJ5	_GPIO(77)
+#define TEGRA_PIN_UART2_RTS_N_PJ6	_GPIO(78)
+#define TEGRA_PIN_GMI_AD16_PJ7		_GPIO(79)
+#define TEGRA_PIN_GMI_ADV_N_PK0		_GPIO(80)
+#define TEGRA_PIN_GMI_CLK_PK1		_GPIO(81)
+#define TEGRA_PIN_GMI_CS4_N_PK2		_GPIO(82)
+#define TEGRA_PIN_GMI_CS2_N_PK3		_GPIO(83)
+#define TEGRA_PIN_GMI_CS3_N_PK4		_GPIO(84)
+#define TEGRA_PIN_SPDIF_OUT_PK5		_GPIO(85)
+#define TEGRA_PIN_SPDIF_IN_PK6		_GPIO(86)
+#define TEGRA_PIN_GMI_AD19_PK7		_GPIO(87)
+#define TEGRA_PIN_VI_D2_PL0		_GPIO(88)
+#define TEGRA_PIN_VI_D3_PL1		_GPIO(89)
+#define TEGRA_PIN_VI_D4_PL2		_GPIO(90)
+#define TEGRA_PIN_VI_D5_PL3		_GPIO(91)
+#define TEGRA_PIN_VI_D6_PL4		_GPIO(92)
+#define TEGRA_PIN_VI_D7_PL5		_GPIO(93)
+#define TEGRA_PIN_VI_D8_PL6		_GPIO(94)
+#define TEGRA_PIN_VI_D9_PL7		_GPIO(95)
+#define TEGRA_PIN_LCD_D16_PM0		_GPIO(96)
+#define TEGRA_PIN_LCD_D17_PM1		_GPIO(97)
+#define TEGRA_PIN_LCD_D18_PM2		_GPIO(98)
+#define TEGRA_PIN_LCD_D19_PM3		_GPIO(99)
+#define TEGRA_PIN_LCD_D20_PM4		_GPIO(100)
+#define TEGRA_PIN_LCD_D21_PM5		_GPIO(101)
+#define TEGRA_PIN_LCD_D22_PM6		_GPIO(102)
+#define TEGRA_PIN_LCD_D23_PM7		_GPIO(103)
+#define TEGRA_PIN_DAP1_FS_PN0		_GPIO(104)
+#define TEGRA_PIN_DAP1_DIN_PN1		_GPIO(105)
+#define TEGRA_PIN_DAP1_DOUT_PN2		_GPIO(106)
+#define TEGRA_PIN_DAP1_SCLK_PN3		_GPIO(107)
+#define TEGRA_PIN_LCD_CS0_N_PN4		_GPIO(108)
+#define TEGRA_PIN_LCD_SDOUT_PN5		_GPIO(109)
+#define TEGRA_PIN_LCD_DC0_PN6		_GPIO(110)
+#define TEGRA_PIN_HDMI_INT_N_PN7	_GPIO(111)
+#define TEGRA_PIN_ULPI_DATA7_PO0	_GPIO(112)
+#define TEGRA_PIN_ULPI_DATA0_PO1	_GPIO(113)
+#define TEGRA_PIN_ULPI_DATA1_PO2	_GPIO(114)
+#define TEGRA_PIN_ULPI_DATA2_PO3	_GPIO(115)
+#define TEGRA_PIN_ULPI_DATA3_PO4	_GPIO(116)
+#define TEGRA_PIN_ULPI_DATA4_PO5	_GPIO(117)
+#define TEGRA_PIN_ULPI_DATA5_PO6	_GPIO(118)
+#define TEGRA_PIN_ULPI_DATA6_PO7	_GPIO(119)
+#define TEGRA_PIN_DAP3_FS_PP0		_GPIO(120)
+#define TEGRA_PIN_DAP3_DIN_PP1		_GPIO(121)
+#define TEGRA_PIN_DAP3_DOUT_PP2		_GPIO(122)
+#define TEGRA_PIN_DAP3_SCLK_PP3		_GPIO(123)
+#define TEGRA_PIN_DAP4_FS_PP4		_GPIO(124)
+#define TEGRA_PIN_DAP4_DIN_PP5		_GPIO(125)
+#define TEGRA_PIN_DAP4_DOUT_PP6		_GPIO(126)
+#define TEGRA_PIN_DAP4_SCLK_PP7		_GPIO(127)
+#define TEGRA_PIN_KB_COL0_PQ0		_GPIO(128)
+#define TEGRA_PIN_KB_COL1_PQ1		_GPIO(129)
+#define TEGRA_PIN_KB_COL2_PQ2		_GPIO(130)
+#define TEGRA_PIN_KB_COL3_PQ3		_GPIO(131)
+#define TEGRA_PIN_KB_COL4_PQ4		_GPIO(132)
+#define TEGRA_PIN_KB_COL5_PQ5		_GPIO(133)
+#define TEGRA_PIN_KB_COL6_PQ6		_GPIO(134)
+#define TEGRA_PIN_KB_COL7_PQ7		_GPIO(135)
+#define TEGRA_PIN_KB_ROW0_PR0		_GPIO(136)
+#define TEGRA_PIN_KB_ROW1_PR1		_GPIO(137)
+#define TEGRA_PIN_KB_ROW2_PR2		_GPIO(138)
+#define TEGRA_PIN_KB_ROW3_PR3		_GPIO(139)
+#define TEGRA_PIN_KB_ROW4_PR4		_GPIO(140)
+#define TEGRA_PIN_KB_ROW5_PR5		_GPIO(141)
+#define TEGRA_PIN_KB_ROW6_PR6		_GPIO(142)
+#define TEGRA_PIN_KB_ROW7_PR7		_GPIO(143)
+#define TEGRA_PIN_KB_ROW8_PS0		_GPIO(144)
+#define TEGRA_PIN_KB_ROW9_PS1		_GPIO(145)
+#define TEGRA_PIN_KB_ROW10_PS2		_GPIO(146)
+#define TEGRA_PIN_KB_ROW11_PS3		_GPIO(147)
+#define TEGRA_PIN_KB_ROW12_PS4		_GPIO(148)
+#define TEGRA_PIN_KB_ROW13_PS5		_GPIO(149)
+#define TEGRA_PIN_KB_ROW14_PS6		_GPIO(150)
+#define TEGRA_PIN_KB_ROW15_PS7		_GPIO(151)
+#define TEGRA_PIN_VI_PCLK_PT0		_GPIO(152)
+#define TEGRA_PIN_VI_MCLK_PT1		_GPIO(153)
+#define TEGRA_PIN_VI_D10_PT2		_GPIO(154)
+#define TEGRA_PIN_VI_D11_PT3		_GPIO(155)
+#define TEGRA_PIN_VI_D0_PT4		_GPIO(156)
+#define TEGRA_PIN_GEN2_I2C_SCL_PT5	_GPIO(157)
+#define TEGRA_PIN_GEN2_I2C_SDA_PT6	_GPIO(158)
+#define TEGRA_PIN_GMI_DPD_PT7		_GPIO(159)
+#define TEGRA_PIN_PU0			_GPIO(160)
+#define TEGRA_PIN_PU1			_GPIO(161)
+#define TEGRA_PIN_PU2			_GPIO(162)
+#define TEGRA_PIN_PU3			_GPIO(163)
+#define TEGRA_PIN_PU4			_GPIO(164)
+#define TEGRA_PIN_PU5			_GPIO(165)
+#define TEGRA_PIN_PU6			_GPIO(166)
+#define TEGRA_PIN_JTAG_RTCK_PU7		_GPIO(167)
+#define TEGRA_PIN_PV0			_GPIO(168)
+#define TEGRA_PIN_PV1			_GPIO(169)
+#define TEGRA_PIN_PV2			_GPIO(170)
+#define TEGRA_PIN_PV3			_GPIO(171)
+#define TEGRA_PIN_PV4			_GPIO(172)
+#define TEGRA_PIN_PV5			_GPIO(173)
+#define TEGRA_PIN_PV6			_GPIO(174)
+#define TEGRA_PIN_LCD_DC1_PV7		_GPIO(175)
+#define TEGRA_PIN_LCD_CS1_N_PW0		_GPIO(176)
+#define TEGRA_PIN_LCD_M1_PW1		_GPIO(177)
+#define TEGRA_PIN_SPI2_CS1_N_PW2	_GPIO(178)
+#define TEGRA_PIN_SPI2_CS2_N_PW3	_GPIO(179)
+#define TEGRA_PIN_DAP_MCLK1_PW4		_GPIO(180)
+#define TEGRA_PIN_DAP_MCLK2_PW5		_GPIO(181)
+#define TEGRA_PIN_UART3_TXD_PW6		_GPIO(182)
+#define TEGRA_PIN_UART3_RXD_PW7		_GPIO(183)
+#define TEGRA_PIN_SPI2_MOSI_PX0		_GPIO(184)
+#define TEGRA_PIN_SPI2_MISO_PX1		_GPIO(185)
+#define TEGRA_PIN_SPI2_SCK_PX2		_GPIO(186)
+#define TEGRA_PIN_SPI2_CS0_N_PX3	_GPIO(187)
+#define TEGRA_PIN_SPI1_MOSI_PX4		_GPIO(188)
+#define TEGRA_PIN_SPI1_SCK_PX5		_GPIO(189)
+#define TEGRA_PIN_SPI1_CS0_N_PX6	_GPIO(190)
+#define TEGRA_PIN_SPI1_MISO_PX7		_GPIO(191)
+#define TEGRA_PIN_ULPI_CLK_PY0		_GPIO(192)
+#define TEGRA_PIN_ULPI_DIR_PY1		_GPIO(193)
+#define TEGRA_PIN_ULPI_NXT_PY2		_GPIO(194)
+#define TEGRA_PIN_ULPI_STP_PY3		_GPIO(195)
+#define TEGRA_PIN_SDIO1_DAT3_PY4	_GPIO(196)
+#define TEGRA_PIN_SDIO1_DAT2_PY5	_GPIO(197)
+#define TEGRA_PIN_SDIO1_DAT1_PY6	_GPIO(198)
+#define TEGRA_PIN_SDIO1_DAT0_PY7	_GPIO(199)
+#define TEGRA_PIN_SDIO1_CLK_PZ0		_GPIO(200)
+#define TEGRA_PIN_SDIO1_CMD_PZ1		_GPIO(201)
+#define TEGRA_PIN_LCD_SDIN_PZ2		_GPIO(202)
+#define TEGRA_PIN_LCD_WR_N_PZ3		_GPIO(203)
+#define TEGRA_PIN_LCD_SCK_PZ4		_GPIO(204)
+#define TEGRA_PIN_SYS_CLK_REQ_PZ5	_GPIO(205)
+#define TEGRA_PIN_PWR_I2C_SCL_PZ6	_GPIO(206)
+#define TEGRA_PIN_PWR_I2C_SDA_PZ7	_GPIO(207)
+#define TEGRA_PIN_GMI_AD20_PAA0		_GPIO(208)
+#define TEGRA_PIN_GMI_AD21_PAA1		_GPIO(209)
+#define TEGRA_PIN_GMI_AD22_PAA2		_GPIO(210)
+#define TEGRA_PIN_GMI_AD23_PAA3		_GPIO(211)
+#define TEGRA_PIN_GMI_AD24_PAA4		_GPIO(212)
+#define TEGRA_PIN_GMI_AD25_PAA5		_GPIO(213)
+#define TEGRA_PIN_GMI_AD26_PAA6		_GPIO(214)
+#define TEGRA_PIN_GMI_AD27_PAA7		_GPIO(215)
+#define TEGRA_PIN_LED_BLINK_PBB0	_GPIO(216)
+#define TEGRA_PIN_VI_GP0_PBB1		_GPIO(217)
+#define TEGRA_PIN_CAM_I2C_SCL_PBB2	_GPIO(218)
+#define TEGRA_PIN_CAM_I2C_SDA_PBB3	_GPIO(219)
+#define TEGRA_PIN_VI_GP3_PBB4		_GPIO(220)
+#define TEGRA_PIN_VI_GP4_PBB5		_GPIO(221)
+#define TEGRA_PIN_PBB6			_GPIO(222)
+#define TEGRA_PIN_PBB7			_GPIO(223)
+
+/* All non-GPIO pins follow */
+#define NUM_GPIOS			(TEGRA_PIN_PBB7 + 1)
+#define _PIN(offset)			(NUM_GPIOS + (offset))
+
+#define TEGRA_PIN_CRT_HSYNC		_PIN(30)
+#define TEGRA_PIN_CRT_VSYNC		_PIN(31)
+#define TEGRA_PIN_DDC_SCL		_PIN(32)
+#define TEGRA_PIN_DDC_SDA		_PIN(33)
+#define TEGRA_PIN_OWC			_PIN(34)
+#define TEGRA_PIN_CORE_PWR_REQ		_PIN(35)
+#define TEGRA_PIN_CPU_PWR_REQ		_PIN(36)
+#define TEGRA_PIN_PWR_INT_N		_PIN(37)
+#define TEGRA_PIN_CLK_32_K_IN		_PIN(38)
+#define TEGRA_PIN_DDR_COMP_PD		_PIN(39)
+#define TEGRA_PIN_DDR_COMP_PU		_PIN(40)
+#define TEGRA_PIN_DDR_A0		_PIN(41)
+#define TEGRA_PIN_DDR_A1		_PIN(42)
+#define TEGRA_PIN_DDR_A2		_PIN(43)
+#define TEGRA_PIN_DDR_A3		_PIN(44)
+#define TEGRA_PIN_DDR_A4		_PIN(45)
+#define TEGRA_PIN_DDR_A5		_PIN(46)
+#define TEGRA_PIN_DDR_A6		_PIN(47)
+#define TEGRA_PIN_DDR_A7		_PIN(48)
+#define TEGRA_PIN_DDR_A8		_PIN(49)
+#define TEGRA_PIN_DDR_A9		_PIN(50)
+#define TEGRA_PIN_DDR_A10		_PIN(51)
+#define TEGRA_PIN_DDR_A11		_PIN(52)
+#define TEGRA_PIN_DDR_A12		_PIN(53)
+#define TEGRA_PIN_DDR_A13		_PIN(54)
+#define TEGRA_PIN_DDR_A14		_PIN(55)
+#define TEGRA_PIN_DDR_CAS_N		_PIN(56)
+#define TEGRA_PIN_DDR_BA0		_PIN(57)
+#define TEGRA_PIN_DDR_BA1		_PIN(58)
+#define TEGRA_PIN_DDR_BA2		_PIN(59)
+#define TEGRA_PIN_DDR_DQS0P		_PIN(60)
+#define TEGRA_PIN_DDR_DQS0N		_PIN(61)
+#define TEGRA_PIN_DDR_DQS1P		_PIN(62)
+#define TEGRA_PIN_DDR_DQS1N		_PIN(63)
+#define TEGRA_PIN_DDR_DQS2P		_PIN(64)
+#define TEGRA_PIN_DDR_DQS2N		_PIN(65)
+#define TEGRA_PIN_DDR_DQS3P		_PIN(66)
+#define TEGRA_PIN_DDR_DQS3N		_PIN(67)
+#define TEGRA_PIN_DDR_CKE0		_PIN(68)
+#define TEGRA_PIN_DDR_CKE1		_PIN(69)
+#define TEGRA_PIN_DDR_CLK		_PIN(70)
+#define TEGRA_PIN_DDR_CLK_N		_PIN(71)
+#define TEGRA_PIN_DDR_DM0		_PIN(72)
+#define TEGRA_PIN_DDR_DM1		_PIN(73)
+#define TEGRA_PIN_DDR_DM2		_PIN(74)
+#define TEGRA_PIN_DDR_DM3		_PIN(75)
+#define TEGRA_PIN_DDR_ODT		_PIN(76)
+#define TEGRA_PIN_DDR_QUSE0		_PIN(77)
+#define TEGRA_PIN_DDR_QUSE1		_PIN(78)
+#define TEGRA_PIN_DDR_QUSE2		_PIN(79)
+#define TEGRA_PIN_DDR_QUSE3		_PIN(80)
+#define TEGRA_PIN_DDR_RAS_N		_PIN(81)
+#define TEGRA_PIN_DDR_WE_N		_PIN(82)
+#define TEGRA_PIN_DDR_DQ0		_PIN(83)
+#define TEGRA_PIN_DDR_DQ1		_PIN(84)
+#define TEGRA_PIN_DDR_DQ2		_PIN(85)
+#define TEGRA_PIN_DDR_DQ3		_PIN(86)
+#define TEGRA_PIN_DDR_DQ4		_PIN(87)
+#define TEGRA_PIN_DDR_DQ5		_PIN(88)
+#define TEGRA_PIN_DDR_DQ6		_PIN(89)
+#define TEGRA_PIN_DDR_DQ7		_PIN(90)
+#define TEGRA_PIN_DDR_DQ8		_PIN(91)
+#define TEGRA_PIN_DDR_DQ9		_PIN(92)
+#define TEGRA_PIN_DDR_DQ10		_PIN(93)
+#define TEGRA_PIN_DDR_DQ11		_PIN(94)
+#define TEGRA_PIN_DDR_DQ12		_PIN(95)
+#define TEGRA_PIN_DDR_DQ13		_PIN(96)
+#define TEGRA_PIN_DDR_DQ14		_PIN(97)
+#define TEGRA_PIN_DDR_DQ15		_PIN(98)
+#define TEGRA_PIN_DDR_DQ16		_PIN(99)
+#define TEGRA_PIN_DDR_DQ17		_PIN(100)
+#define TEGRA_PIN_DDR_DQ18		_PIN(101)
+#define TEGRA_PIN_DDR_DQ19		_PIN(102)
+#define TEGRA_PIN_DDR_DQ20		_PIN(103)
+#define TEGRA_PIN_DDR_DQ21		_PIN(104)
+#define TEGRA_PIN_DDR_DQ22		_PIN(105)
+#define TEGRA_PIN_DDR_DQ23		_PIN(106)
+#define TEGRA_PIN_DDR_DQ24		_PIN(107)
+#define TEGRA_PIN_DDR_DQ25		_PIN(108)
+#define TEGRA_PIN_DDR_DQ26		_PIN(109)
+#define TEGRA_PIN_DDR_DQ27		_PIN(110)
+#define TEGRA_PIN_DDR_DQ28		_PIN(111)
+#define TEGRA_PIN_DDR_DQ29		_PIN(112)
+#define TEGRA_PIN_DDR_DQ30		_PIN(113)
+#define TEGRA_PIN_DDR_DQ31		_PIN(114)
+#define TEGRA_PIN_DDR_CS0_N		_PIN(115)
+#define TEGRA_PIN_DDR_CS1_N		_PIN(116)
+#define TEGRA_PIN_SYS_RESET		_PIN(117)
+#define TEGRA_PIN_JTAG_TRST_N		_PIN(118)
+#define TEGRA_PIN_JTAG_TDO		_PIN(119)
+#define TEGRA_PIN_JTAG_TMS		_PIN(120)
+#define TEGRA_PIN_JTAG_TCK		_PIN(121)
+#define TEGRA_PIN_JTAG_TDI		_PIN(122)
+#define TEGRA_PIN_TEST_MODE_EN		_PIN(123)
+
+static const struct pinctrl_pin_desc tegra20_pins[] = {
+	PINCTRL_PIN(TEGRA_PIN_VI_GP6_PA0, "VI_GP6 PA0"),
+	PINCTRL_PIN(TEGRA_PIN_UART3_CTS_N_PA1, "UART3_CTS_N PA1"),
+	PINCTRL_PIN(TEGRA_PIN_DAP2_FS_PA2, "DAP2_FS PA2"),
+	PINCTRL_PIN(TEGRA_PIN_DAP2_SCLK_PA3, "DAP2_SCLK PA3"),
+	PINCTRL_PIN(TEGRA_PIN_DAP2_DIN_PA4, "DAP2_DIN PA4"),
+	PINCTRL_PIN(TEGRA_PIN_DAP2_DOUT_PA5, "DAP2_DOUT PA5"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO3_CLK_PA6, "SDIO3_CLK PA6"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO3_CMD_PA7, "SDIO3_CMD PA7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD17_PB0, "GMI_AD17 PB0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD18_PB1, "GMI_AD18 PB1"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_PWR0_PB2, "LCD_PWR0 PB2"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_PCLK_PB3, "LCD_PCLK PB3"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO3_DAT3_PB4, "SDIO3_DAT3 PB4"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO3_DAT2_PB5, "SDIO3_DAT2 PB5"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO3_DAT1_PB6, "SDIO3_DAT1 PB6"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO3_DAT0_PB7, "SDIO3_DAT0 PB7"),
+	PINCTRL_PIN(TEGRA_PIN_UART3_RTS_N_PC0, "UART3_RTS_N PC0"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_PWR1_PC1, "LCD_PWR1 PC1"),
+	PINCTRL_PIN(TEGRA_PIN_UART2_TXD_PC2, "UART2_TXD PC2"),
+	PINCTRL_PIN(TEGRA_PIN_UART2_RXD_PC3, "UART2_RXD PC3"),
+	PINCTRL_PIN(TEGRA_PIN_GEN1_I2C_SCL_PC4, "GEN1_I2C_SCL PC4"),
+	PINCTRL_PIN(TEGRA_PIN_GEN1_I2C_SDA_PC5, "GEN1_I2C_SDA PC5"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_PWR2_PC6, "LCD_PWR2 PC6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_WP_N_PC7, "GMI_WP_N PC7"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO3_DAT5_PD0, "SDIO3_DAT5 PD0"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO3_DAT4_PD1, "SDIO3_DAT4 PD1"),
+	PINCTRL_PIN(TEGRA_PIN_VI_GP5_PD2, "VI_GP5 PD2"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO3_DAT6_PD3, "SDIO3_DAT6 PD3"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO3_DAT7_PD4, "SDIO3_DAT7 PD4"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D1_PD5, "VI_D1 PD5"),
+	PINCTRL_PIN(TEGRA_PIN_VI_VSYNC_PD6, "VI_VSYNC PD6"),
+	PINCTRL_PIN(TEGRA_PIN_VI_HSYNC_PD7, "VI_HSYNC PD7"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D0_PE0, "LCD_D0 PE0"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D1_PE1, "LCD_D1 PE1"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D2_PE2, "LCD_D2 PE2"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D3_PE3, "LCD_D3 PE3"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D4_PE4, "LCD_D4 PE4"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D5_PE5, "LCD_D5 PE5"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D6_PE6, "LCD_D6 PE6"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D7_PE7, "LCD_D7 PE7"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D8_PF0, "LCD_D8 PF0"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D9_PF1, "LCD_D9 PF1"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D10_PF2, "LCD_D10 PF2"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D11_PF3, "LCD_D11 PF3"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D12_PF4, "LCD_D12 PF4"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D13_PF5, "LCD_D13 PF5"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D14_PF6, "LCD_D14 PF6"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D15_PF7, "LCD_D15 PF7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD0_PG0, "GMI_AD0 PG0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD1_PG1, "GMI_AD1 PG1"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD2_PG2, "GMI_AD2 PG2"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD3_PG3, "GMI_AD3 PG3"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD4_PG4, "GMI_AD4 PG4"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD5_PG5, "GMI_AD5 PG5"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD6_PG6, "GMI_AD6 PG6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD7_PG7, "GMI_AD7 PG7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD8_PH0, "GMI_AD8 PH0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD9_PH1, "GMI_AD9 PH1"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD10_PH2, "GMI_AD10 PH2"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD11_PH3, "GMI_AD11 PH3"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD12_PH4, "GMI_AD12 PH4"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD13_PH5, "GMI_AD13 PH5"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD14_PH6, "GMI_AD14 PH6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD15_PH7, "GMI_AD15 PH7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_HIOW_N_PI0, "GMI_HIOW_N PI0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_HIOR_N_PI1, "GMI_HIOR_N PI1"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS5_N_PI2, "GMI_CS5_N PI2"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS6_N_PI3, "GMI_CS6_N PI3"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_RST_N_PI4, "GMI_RST_N PI4"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_IORDY_PI5, "GMI_IORDY PI5"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS7_N_PI6, "GMI_CS7_N PI6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_WAIT_PI7, "GMI_WAIT PI7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS0_N_PJ0, "GMI_CS0_N PJ0"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_DE_PJ1, "LCD_DE PJ1"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS1_N_PJ2, "GMI_CS1_N PJ2"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_HSYNC_PJ3, "LCD_HSYNC PJ3"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_VSYNC_PJ4, "LCD_VSYNC PJ4"),
+	PINCTRL_PIN(TEGRA_PIN_UART2_CTS_N_PJ5, "UART2_CTS_N PJ5"),
+	PINCTRL_PIN(TEGRA_PIN_UART2_RTS_N_PJ6, "UART2_RTS_N PJ6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD16_PJ7, "GMI_AD16 PJ7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_ADV_N_PK0, "GMI_ADV_N PK0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CLK_PK1, "GMI_CLK PK1"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS4_N_PK2, "GMI_CS4_N PK2"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS2_N_PK3, "GMI_CS2_N PK3"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS3_N_PK4, "GMI_CS3_N PK4"),
+	PINCTRL_PIN(TEGRA_PIN_SPDIF_OUT_PK5, "SPDIF_OUT PK5"),
+	PINCTRL_PIN(TEGRA_PIN_SPDIF_IN_PK6, "SPDIF_IN PK6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD19_PK7, "GMI_AD19 PK7"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D2_PL0, "VI_D2 PL0"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D3_PL1, "VI_D3 PL1"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D4_PL2, "VI_D4 PL2"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D5_PL3, "VI_D5 PL3"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D6_PL4, "VI_D6 PL4"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D7_PL5, "VI_D7 PL5"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D8_PL6, "VI_D8 PL6"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D9_PL7, "VI_D9 PL7"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D16_PM0, "LCD_D16 PM0"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D17_PM1, "LCD_D17 PM1"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D18_PM2, "LCD_D18 PM2"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D19_PM3, "LCD_D19 PM3"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D20_PM4, "LCD_D20 PM4"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D21_PM5, "LCD_D21 PM5"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D22_PM6, "LCD_D22 PM6"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D23_PM7, "LCD_D23 PM7"),
+	PINCTRL_PIN(TEGRA_PIN_DAP1_FS_PN0, "DAP1_FS PN0"),
+	PINCTRL_PIN(TEGRA_PIN_DAP1_DIN_PN1, "DAP1_DIN PN1"),
+	PINCTRL_PIN(TEGRA_PIN_DAP1_DOUT_PN2, "DAP1_DOUT PN2"),
+	PINCTRL_PIN(TEGRA_PIN_DAP1_SCLK_PN3, "DAP1_SCLK PN3"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_CS0_N_PN4, "LCD_CS0_N PN4"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_SDOUT_PN5, "LCD_SDOUT PN5"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_DC0_PN6, "LCD_DC0 PN6"),
+	PINCTRL_PIN(TEGRA_PIN_HDMI_INT_N_PN7, "HDMI_INT_N PN7"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA7_PO0, "ULPI_DATA7 PO0"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA0_PO1, "ULPI_DATA0 PO1"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA1_PO2, "ULPI_DATA1 PO2"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA2_PO3, "ULPI_DATA2 PO3"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA3_PO4, "ULPI_DATA3 PO4"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA4_PO5, "ULPI_DATA4 PO5"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA5_PO6, "ULPI_DATA5 PO6"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA6_PO7, "ULPI_DATA6 PO7"),
+	PINCTRL_PIN(TEGRA_PIN_DAP3_FS_PP0, "DAP3_FS PP0"),
+	PINCTRL_PIN(TEGRA_PIN_DAP3_DIN_PP1, "DAP3_DIN PP1"),
+	PINCTRL_PIN(TEGRA_PIN_DAP3_DOUT_PP2, "DAP3_DOUT PP2"),
+	PINCTRL_PIN(TEGRA_PIN_DAP3_SCLK_PP3, "DAP3_SCLK PP3"),
+	PINCTRL_PIN(TEGRA_PIN_DAP4_FS_PP4, "DAP4_FS PP4"),
+	PINCTRL_PIN(TEGRA_PIN_DAP4_DIN_PP5, "DAP4_DIN PP5"),
+	PINCTRL_PIN(TEGRA_PIN_DAP4_DOUT_PP6, "DAP4_DOUT PP6"),
+	PINCTRL_PIN(TEGRA_PIN_DAP4_SCLK_PP7, "DAP4_SCLK PP7"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL0_PQ0, "KB_COL0 PQ0"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL1_PQ1, "KB_COL1 PQ1"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL2_PQ2, "KB_COL2 PQ2"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL3_PQ3, "KB_COL3 PQ3"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL4_PQ4, "KB_COL4 PQ4"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL5_PQ5, "KB_COL5 PQ5"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL6_PQ6, "KB_COL6 PQ6"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL7_PQ7, "KB_COL7 PQ7"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW0_PR0, "KB_ROW0 PR0"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW1_PR1, "KB_ROW1 PR1"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW2_PR2, "KB_ROW2 PR2"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW3_PR3, "KB_ROW3 PR3"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW4_PR4, "KB_ROW4 PR4"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW5_PR5, "KB_ROW5 PR5"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW6_PR6, "KB_ROW6 PR6"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW7_PR7, "KB_ROW7 PR7"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW8_PS0, "KB_ROW8 PS0"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW9_PS1, "KB_ROW9 PS1"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW10_PS2, "KB_ROW10 PS2"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW11_PS3, "KB_ROW11 PS3"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW12_PS4, "KB_ROW12 PS4"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW13_PS5, "KB_ROW13 PS5"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW14_PS6, "KB_ROW14 PS6"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW15_PS7, "KB_ROW15 PS7"),
+	PINCTRL_PIN(TEGRA_PIN_VI_PCLK_PT0, "VI_PCLK PT0"),
+	PINCTRL_PIN(TEGRA_PIN_VI_MCLK_PT1, "VI_MCLK PT1"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D10_PT2, "VD_D10 PT2"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D11_PT3, "VI_D11 PT3"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D0_PT4, "VI_D0 PT4"),
+	PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SCL_PT5, "GEN2_I2C_SCL PT5"),
+	PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SDA_PT6, "GEN2_I2C_SDA PT6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_DPD_PT7, "GMI_DPD PT7"),
+	/* PU0..6: GPIO only */
+	PINCTRL_PIN(TEGRA_PIN_PU0, "PU0"),
+	PINCTRL_PIN(TEGRA_PIN_PU1, "PU1"),
+	PINCTRL_PIN(TEGRA_PIN_PU2, "PU2"),
+	PINCTRL_PIN(TEGRA_PIN_PU3, "PU3"),
+	PINCTRL_PIN(TEGRA_PIN_PU4, "PU4"),
+	PINCTRL_PIN(TEGRA_PIN_PU5, "PU5"),
+	PINCTRL_PIN(TEGRA_PIN_PU6, "PU6"),
+	PINCTRL_PIN(TEGRA_PIN_JTAG_RTCK_PU7, "JTAG_RTCK PU7"),
+	/* PV0..1: GPIO only */
+	PINCTRL_PIN(TEGRA_PIN_PV0, "PV0"),
+	PINCTRL_PIN(TEGRA_PIN_PV1, "PV1"),
+	/* PV2..3: Balls are named after GPIO not function */
+	PINCTRL_PIN(TEGRA_PIN_PV2, "PV2"),
+	PINCTRL_PIN(TEGRA_PIN_PV3, "PV3"),
+	/* PV4..6: GPIO only */
+	PINCTRL_PIN(TEGRA_PIN_PV4, "PV4"),
+	PINCTRL_PIN(TEGRA_PIN_PV5, "PV5"),
+	PINCTRL_PIN(TEGRA_PIN_PV6, "PV6"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_DC1_PV7, "LCD_DC1 PV7"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_CS1_N_PW0, "LCD_CS1_N PW0"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_M1_PW1, "LCD_M1 PW1"),
+	PINCTRL_PIN(TEGRA_PIN_SPI2_CS1_N_PW2, "SPI2_CS1_N PW2"),
+	PINCTRL_PIN(TEGRA_PIN_SPI2_CS2_N_PW3, "SPI2_CS2_N PW3"),
+	PINCTRL_PIN(TEGRA_PIN_DAP_MCLK1_PW4, "DAP_MCLK1 PW4"),
+	PINCTRL_PIN(TEGRA_PIN_DAP_MCLK2_PW5, "DAP_MCLK2 PW5"),
+	PINCTRL_PIN(TEGRA_PIN_UART3_TXD_PW6, "UART3_TXD PW6"),
+	PINCTRL_PIN(TEGRA_PIN_UART3_RXD_PW7, "UART3_RXD PW7"),
+	PINCTRL_PIN(TEGRA_PIN_SPI2_MOSI_PX0, "SPI2_MOSI PX0"),
+	PINCTRL_PIN(TEGRA_PIN_SPI2_MISO_PX1, "SPI2_MISO PX1"),
+	PINCTRL_PIN(TEGRA_PIN_SPI2_SCK_PX2, "SPI2_SCK PX2"),
+	PINCTRL_PIN(TEGRA_PIN_SPI2_CS0_N_PX3, "SPI2_CS0_N PX3"),
+	PINCTRL_PIN(TEGRA_PIN_SPI1_MOSI_PX4, "SPI1_MOSI PX4"),
+	PINCTRL_PIN(TEGRA_PIN_SPI1_SCK_PX5, "SPI1_SCK PX5"),
+	PINCTRL_PIN(TEGRA_PIN_SPI1_CS0_N_PX6, "SPI1_CS0_N PX6"),
+	PINCTRL_PIN(TEGRA_PIN_SPI1_MISO_PX7, "SPI1_MISO PX7"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_CLK_PY0, "ULPI_CLK PY0"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DIR_PY1, "ULPI_DIR PY1"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_NXT_PY2, "ULPI_NXT PY2"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_STP_PY3, "ULPI_STP PY3"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO1_DAT3_PY4, "SDIO1_DAT3 PY4"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO1_DAT2_PY5, "SDIO1_DAT2 PY5"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO1_DAT1_PY6, "SDIO1_DAT1 PY6"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO1_DAT0_PY7, "SDIO1_DAT0 PY7"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO1_CLK_PZ0, "SDIO1_CLK PZ0"),
+	PINCTRL_PIN(TEGRA_PIN_SDIO1_CMD_PZ1, "SDIO1_CMD PZ1"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_SDIN_PZ2, "LCD_SDIN PZ2"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_WR_N_PZ3, "LCD_WR_N PZ3"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_SCK_PZ4, "LCD_SCK PZ4"),
+	PINCTRL_PIN(TEGRA_PIN_SYS_CLK_REQ_PZ5, "SYS_CLK_REQ PZ5"),
+	PINCTRL_PIN(TEGRA_PIN_PWR_I2C_SCL_PZ6, "PWR_I2C_SCL PZ6"),
+	PINCTRL_PIN(TEGRA_PIN_PWR_I2C_SDA_PZ7, "PWR_I2C_SDA PZ7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD20_PAA0, "GMI_AD20 PAA0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD21_PAA1, "GMI_AD21 PAA1"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD22_PAA2, "GMI_AD22 PAA2"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD23_PAA3, "GMI_AD23 PAA3"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD24_PAA4, "GMI_AD24 PAA4"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD25_PAA5, "GMI_AD25 PAA5"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD26_PAA6, "GMI_AD26 PAA6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD27_PAA7, "GMI_AD27 PAA7"),
+	PINCTRL_PIN(TEGRA_PIN_LED_BLINK_PBB0, "LED_BLINK PBB0"),
+	PINCTRL_PIN(TEGRA_PIN_VI_GP0_PBB1, "VI_GP0 PBB1"),
+	PINCTRL_PIN(TEGRA_PIN_CAM_I2C_SCL_PBB2, "CAM_I2C_SCL PBB2"),
+	PINCTRL_PIN(TEGRA_PIN_CAM_I2C_SDA_PBB3, "CAM_I2C_SDA PBB3"),
+	PINCTRL_PIN(TEGRA_PIN_VI_GP3_PBB4, "VI_GP3 PBB4"),
+	PINCTRL_PIN(TEGRA_PIN_VI_GP4_PBB5, "VI_GP4 PBB5"),
+	PINCTRL_PIN(TEGRA_PIN_PBB6, "PBB6"),
+	PINCTRL_PIN(TEGRA_PIN_PBB7, "PBB7"),
+	PINCTRL_PIN(TEGRA_PIN_CRT_HSYNC, "CRT_HSYNC"),
+	PINCTRL_PIN(TEGRA_PIN_CRT_VSYNC, "CRT_VSYNC"),
+	PINCTRL_PIN(TEGRA_PIN_DDC_SCL, "DDC_SCL"),
+	PINCTRL_PIN(TEGRA_PIN_DDC_SDA, "DDC_SDA"),
+	PINCTRL_PIN(TEGRA_PIN_OWC, "OWC"),
+	PINCTRL_PIN(TEGRA_PIN_CORE_PWR_REQ, "CORE_PWR_REQ"),
+	PINCTRL_PIN(TEGRA_PIN_CPU_PWR_REQ, "CPU_PWR_REQ"),
+	PINCTRL_PIN(TEGRA_PIN_PWR_INT_N, "PWR_INT_N"),
+	PINCTRL_PIN(TEGRA_PIN_CLK_32_K_IN, "CLK_32_K_IN"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_COMP_PD, "DDR_COMP_PD"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_COMP_PU, "DDR_COMP_PU"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_A0, "DDR_A0"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_A1, "DDR_A1"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_A2, "DDR_A2"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_A3, "DDR_A3"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_A4, "DDR_A4"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_A5, "DDR_A5"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_A6, "DDR_A6"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_A7, "DDR_A7"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_A8, "DDR_A8"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_A9, "DDR_A9"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_A10, "DDR_A10"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_A11, "DDR_A11"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_A12, "DDR_A12"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_A13, "DDR_A13"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_A14, "DDR_A14"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_CAS_N, "DDR_CAS_N"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_BA0, "DDR_BA0"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_BA1, "DDR_BA1"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_BA2, "DDR_BA2"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQS0P, "DDR_DQS0P"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQS0N, "DDR_DQS0N"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQS1P, "DDR_DQS1P"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQS1N, "DDR_DQS1N"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQS2P, "DDR_DQS2P"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQS2N, "DDR_DQS2N"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQS3P, "DDR_DQS3P"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQS3N, "DDR_DQS3N"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_CKE0, "DDR_CKE0"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_CKE1, "DDR_CKE1"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_CLK, "DDR_CLK"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_CLK_N, "DDR_CLK_N"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DM0, "DDR_DM0"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DM1, "DDR_DM1"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DM2, "DDR_DM2"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DM3, "DDR_DM3"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_ODT, "DDR_ODT"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_QUSE0, "DDR_QUSE0"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_QUSE1, "DDR_QUSE1"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_QUSE2, "DDR_QUSE2"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_QUSE3, "DDR_QUSE3"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_RAS_N, "DDR_RAS_N"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_WE_N, "DDR_WE_N"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ0, "DDR_DQ0"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ1, "DDR_DQ1"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ2, "DDR_DQ2"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ3, "DDR_DQ3"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ4, "DDR_DQ4"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ5, "DDR_DQ5"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ6, "DDR_DQ6"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ7, "DDR_DQ7"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ8, "DDR_DQ8"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ9, "DDR_DQ9"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ10, "DDR_DQ10"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ11, "DDR_DQ11"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ12, "DDR_DQ12"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ13, "DDR_DQ13"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ14, "DDR_DQ14"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ15, "DDR_DQ15"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ16, "DDR_DQ16"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ17, "DDR_DQ17"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ18, "DDR_DQ18"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ19, "DDR_DQ19"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ20, "DDR_DQ20"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ21, "DDR_DQ21"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ22, "DDR_DQ22"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ23, "DDR_DQ23"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ24, "DDR_DQ24"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ25, "DDR_DQ25"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ26, "DDR_DQ26"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ27, "DDR_DQ27"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ28, "DDR_DQ28"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ29, "DDR_DQ29"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ30, "DDR_DQ30"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_DQ31, "DDR_DQ31"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_CS0_N, "DDR_CS0_N"),
+	PINCTRL_PIN(TEGRA_PIN_DDR_CS1_N, "DDR_CS1_N"),
+	PINCTRL_PIN(TEGRA_PIN_SYS_RESET, "SYS_RESET"),
+	PINCTRL_PIN(TEGRA_PIN_JTAG_TRST_N, "JTAG_TRST_N"),
+	PINCTRL_PIN(TEGRA_PIN_JTAG_TDO, "JTAG_TDO"),
+	PINCTRL_PIN(TEGRA_PIN_JTAG_TMS, "JTAG_TMS"),
+	PINCTRL_PIN(TEGRA_PIN_JTAG_TCK, "JTAG_TCK"),
+	PINCTRL_PIN(TEGRA_PIN_JTAG_TDI, "JTAG_TDI"),
+	PINCTRL_PIN(TEGRA_PIN_TEST_MODE_EN, "TEST_MODE_EN"),
+};
+
+static const unsigned ata_pins[] = {
+	TEGRA_PIN_GMI_CS6_N_PI3,
+	TEGRA_PIN_GMI_CS7_N_PI6,
+	TEGRA_PIN_GMI_RST_N_PI4,
+};
+
+static const unsigned atb_pins[] = {
+	TEGRA_PIN_GMI_CS5_N_PI2,
+	TEGRA_PIN_GMI_DPD_PT7,
+};
+
+static const unsigned atc_pins[] = {
+	TEGRA_PIN_GMI_IORDY_PI5,
+	TEGRA_PIN_GMI_WAIT_PI7,
+	TEGRA_PIN_GMI_ADV_N_PK0,
+	TEGRA_PIN_GMI_CLK_PK1,
+	TEGRA_PIN_GMI_CS2_N_PK3,
+	TEGRA_PIN_GMI_CS3_N_PK4,
+	TEGRA_PIN_GMI_CS4_N_PK2,
+	TEGRA_PIN_GMI_AD0_PG0,
+	TEGRA_PIN_GMI_AD1_PG1,
+	TEGRA_PIN_GMI_AD2_PG2,
+	TEGRA_PIN_GMI_AD3_PG3,
+	TEGRA_PIN_GMI_AD4_PG4,
+	TEGRA_PIN_GMI_AD5_PG5,
+	TEGRA_PIN_GMI_AD6_PG6,
+	TEGRA_PIN_GMI_AD7_PG7,
+	TEGRA_PIN_GMI_HIOW_N_PI0,
+	TEGRA_PIN_GMI_HIOR_N_PI1,
+};
+
+static const unsigned atd_pins[] = {
+	TEGRA_PIN_GMI_AD8_PH0,
+	TEGRA_PIN_GMI_AD9_PH1,
+	TEGRA_PIN_GMI_AD10_PH2,
+	TEGRA_PIN_GMI_AD11_PH3,
+};
+
+static const unsigned ate_pins[] = {
+	TEGRA_PIN_GMI_AD12_PH4,
+	TEGRA_PIN_GMI_AD13_PH5,
+	TEGRA_PIN_GMI_AD14_PH6,
+	TEGRA_PIN_GMI_AD15_PH7,
+};
+
+static const unsigned cdev1_pins[] = {
+	TEGRA_PIN_DAP_MCLK1_PW4,
+};
+
+static const unsigned cdev2_pins[] = {
+	TEGRA_PIN_DAP_MCLK2_PW5,
+};
+
+static const unsigned crtp_pins[] = {
+	TEGRA_PIN_CRT_HSYNC,
+	TEGRA_PIN_CRT_VSYNC,
+};
+
+static const unsigned csus_pins[] = {
+	TEGRA_PIN_VI_MCLK_PT1,
+};
+
+static const unsigned dap1_pins[] = {
+	TEGRA_PIN_DAP1_FS_PN0,
+	TEGRA_PIN_DAP1_DIN_PN1,
+	TEGRA_PIN_DAP1_DOUT_PN2,
+	TEGRA_PIN_DAP1_SCLK_PN3,
+};
+
+static const unsigned dap2_pins[] = {
+	TEGRA_PIN_DAP2_FS_PA2,
+	TEGRA_PIN_DAP2_SCLK_PA3,
+	TEGRA_PIN_DAP2_DIN_PA4,
+	TEGRA_PIN_DAP2_DOUT_PA5,
+};
+
+static const unsigned dap3_pins[] = {
+	TEGRA_PIN_DAP3_FS_PP0,
+	TEGRA_PIN_DAP3_DIN_PP1,
+	TEGRA_PIN_DAP3_DOUT_PP2,
+	TEGRA_PIN_DAP3_SCLK_PP3,
+};
+
+static const unsigned dap4_pins[] = {
+	TEGRA_PIN_DAP4_FS_PP4,
+	TEGRA_PIN_DAP4_DIN_PP5,
+	TEGRA_PIN_DAP4_DOUT_PP6,
+	TEGRA_PIN_DAP4_SCLK_PP7,
+};
+
+static const unsigned ddc_pins[] = {
+	TEGRA_PIN_DDC_SCL,
+	TEGRA_PIN_DDC_SDA,
+};
+
+static const unsigned dta_pins[] = {
+	TEGRA_PIN_VI_D0_PT4,
+	TEGRA_PIN_VI_D1_PD5,
+};
+
+static const unsigned dtb_pins[] = {
+	TEGRA_PIN_VI_D10_PT2,
+	TEGRA_PIN_VI_D11_PT3,
+};
+
+static const unsigned dtc_pins[] = {
+	TEGRA_PIN_VI_HSYNC_PD7,
+	TEGRA_PIN_VI_VSYNC_PD6,
+};
+
+static const unsigned dtd_pins[] = {
+	TEGRA_PIN_VI_PCLK_PT0,
+	TEGRA_PIN_VI_D2_PL0,
+	TEGRA_PIN_VI_D3_PL1,
+	TEGRA_PIN_VI_D4_PL2,
+	TEGRA_PIN_VI_D5_PL3,
+	TEGRA_PIN_VI_D6_PL4,
+	TEGRA_PIN_VI_D7_PL5,
+	TEGRA_PIN_VI_D8_PL6,
+	TEGRA_PIN_VI_D9_PL7,
+};
+
+static const unsigned dte_pins[] = {
+	TEGRA_PIN_VI_GP0_PBB1,
+	TEGRA_PIN_VI_GP3_PBB4,
+	TEGRA_PIN_VI_GP4_PBB5,
+	TEGRA_PIN_VI_GP5_PD2,
+	TEGRA_PIN_VI_GP6_PA0,
+};
+
+static const unsigned dtf_pins[] = {
+	TEGRA_PIN_CAM_I2C_SCL_PBB2,
+	TEGRA_PIN_CAM_I2C_SDA_PBB3,
+};
+
+static const unsigned gma_pins[] = {
+	TEGRA_PIN_GMI_AD20_PAA0,
+	TEGRA_PIN_GMI_AD21_PAA1,
+	TEGRA_PIN_GMI_AD22_PAA2,
+	TEGRA_PIN_GMI_AD23_PAA3,
+};
+
+static const unsigned gmb_pins[] = {
+	TEGRA_PIN_GMI_WP_N_PC7,
+};
+
+static const unsigned gmc_pins[] = {
+	TEGRA_PIN_GMI_AD16_PJ7,
+	TEGRA_PIN_GMI_AD17_PB0,
+	TEGRA_PIN_GMI_AD18_PB1,
+	TEGRA_PIN_GMI_AD19_PK7,
+};
+
+static const unsigned gmd_pins[] = {
+	TEGRA_PIN_GMI_CS0_N_PJ0,
+	TEGRA_PIN_GMI_CS1_N_PJ2,
+};
+
+static const unsigned gme_pins[] = {
+	TEGRA_PIN_GMI_AD24_PAA4,
+	TEGRA_PIN_GMI_AD25_PAA5,
+	TEGRA_PIN_GMI_AD26_PAA6,
+	TEGRA_PIN_GMI_AD27_PAA7,
+};
+
+static const unsigned gpu_pins[] = {
+	TEGRA_PIN_PU0,
+	TEGRA_PIN_PU1,
+	TEGRA_PIN_PU2,
+	TEGRA_PIN_PU3,
+	TEGRA_PIN_PU4,
+	TEGRA_PIN_PU5,
+	TEGRA_PIN_PU6,
+};
+
+static const unsigned gpu7_pins[] = {
+	TEGRA_PIN_JTAG_RTCK_PU7,
+};
+
+static const unsigned gpv_pins[] = {
+	TEGRA_PIN_PV4,
+	TEGRA_PIN_PV5,
+	TEGRA_PIN_PV6,
+};
+
+static const unsigned hdint_pins[] = {
+	TEGRA_PIN_HDMI_INT_N_PN7,
+};
+
+static const unsigned i2cp_pins[] = {
+	TEGRA_PIN_PWR_I2C_SCL_PZ6,
+	TEGRA_PIN_PWR_I2C_SDA_PZ7,
+};
+
+static const unsigned irrx_pins[] = {
+	TEGRA_PIN_UART2_RTS_N_PJ6,
+};
+
+static const unsigned irtx_pins[] = {
+	TEGRA_PIN_UART2_CTS_N_PJ5,
+};
+
+static const unsigned kbca_pins[] = {
+	TEGRA_PIN_KB_ROW0_PR0,
+	TEGRA_PIN_KB_ROW1_PR1,
+	TEGRA_PIN_KB_ROW2_PR2,
+};
+
+static const unsigned kbcb_pins[] = {
+	TEGRA_PIN_KB_ROW7_PR7,
+	TEGRA_PIN_KB_ROW8_PS0,
+	TEGRA_PIN_KB_ROW9_PS1,
+	TEGRA_PIN_KB_ROW10_PS2,
+	TEGRA_PIN_KB_ROW11_PS3,
+	TEGRA_PIN_KB_ROW12_PS4,
+	TEGRA_PIN_KB_ROW13_PS5,
+	TEGRA_PIN_KB_ROW14_PS6,
+	TEGRA_PIN_KB_ROW15_PS7,
+};
+
+static const unsigned kbcc_pins[] = {
+	TEGRA_PIN_KB_COL0_PQ0,
+	TEGRA_PIN_KB_COL1_PQ1,
+};
+
+static const unsigned kbcd_pins[] = {
+	TEGRA_PIN_KB_ROW3_PR3,
+	TEGRA_PIN_KB_ROW4_PR4,
+	TEGRA_PIN_KB_ROW5_PR5,
+	TEGRA_PIN_KB_ROW6_PR6,
+};
+
+static const unsigned kbce_pins[] = {
+	TEGRA_PIN_KB_COL7_PQ7,
+};
+
+static const unsigned kbcf_pins[] = {
+	TEGRA_PIN_KB_COL2_PQ2,
+	TEGRA_PIN_KB_COL3_PQ3,
+	TEGRA_PIN_KB_COL4_PQ4,
+	TEGRA_PIN_KB_COL5_PQ5,
+	TEGRA_PIN_KB_COL6_PQ6,
+};
+
+static const unsigned lcsn_pins[] = {
+	TEGRA_PIN_LCD_CS0_N_PN4,
+};
+
+static const unsigned ld0_pins[] = {
+	TEGRA_PIN_LCD_D0_PE0,
+};
+
+static const unsigned ld1_pins[] = {
+	TEGRA_PIN_LCD_D1_PE1,
+};
+
+static const unsigned ld2_pins[] = {
+	TEGRA_PIN_LCD_D2_PE2,
+};
+
+static const unsigned ld3_pins[] = {
+	TEGRA_PIN_LCD_D3_PE3,
+};
+
+static const unsigned ld4_pins[] = {
+	TEGRA_PIN_LCD_D4_PE4,
+};
+
+static const unsigned ld5_pins[] = {
+	TEGRA_PIN_LCD_D5_PE5,
+};
+
+static const unsigned ld6_pins[] = {
+	TEGRA_PIN_LCD_D6_PE6,
+};
+
+static const unsigned ld7_pins[] = {
+	TEGRA_PIN_LCD_D7_PE7,
+};
+
+static const unsigned ld8_pins[] = {
+	TEGRA_PIN_LCD_D8_PF0,
+};
+
+static const unsigned ld9_pins[] = {
+	TEGRA_PIN_LCD_D9_PF1,
+};
+
+static const unsigned ld10_pins[] = {
+	TEGRA_PIN_LCD_D10_PF2,
+};
+
+static const unsigned ld11_pins[] = {
+	TEGRA_PIN_LCD_D11_PF3,
+};
+
+static const unsigned ld12_pins[] = {
+	TEGRA_PIN_LCD_D12_PF4,
+};
+
+static const unsigned ld13_pins[] = {
+	TEGRA_PIN_LCD_D13_PF5,
+};
+
+static const unsigned ld14_pins[] = {
+	TEGRA_PIN_LCD_D14_PF6,
+};
+
+static const unsigned ld15_pins[] = {
+	TEGRA_PIN_LCD_D15_PF7,
+};
+
+static const unsigned ld16_pins[] = {
+	TEGRA_PIN_LCD_D16_PM0,
+};
+
+static const unsigned ld17_pins[] = {
+	TEGRA_PIN_LCD_D17_PM1,
+};
+
+static const unsigned ldc_pins[] = {
+	TEGRA_PIN_LCD_DC0_PN6,
+};
+
+static const unsigned ldi_pins[] = {
+	TEGRA_PIN_LCD_D22_PM6,
+};
+
+static const unsigned lhp0_pins[] = {
+	TEGRA_PIN_LCD_D21_PM5,
+};
+
+static const unsigned lhp1_pins[] = {
+	TEGRA_PIN_LCD_D18_PM2,
+};
+
+static const unsigned lhp2_pins[] = {
+	TEGRA_PIN_LCD_D19_PM3,
+};
+
+static const unsigned lhs_pins[] = {
+	TEGRA_PIN_LCD_HSYNC_PJ3,
+};
+
+static const unsigned lm0_pins[] = {
+	TEGRA_PIN_LCD_CS1_N_PW0,
+};
+
+static const unsigned lm1_pins[] = {
+	TEGRA_PIN_LCD_M1_PW1,
+};
+
+static const unsigned lpp_pins[] = {
+	TEGRA_PIN_LCD_D23_PM7,
+};
+
+static const unsigned lpw0_pins[] = {
+	TEGRA_PIN_LCD_PWR0_PB2,
+};
+
+static const unsigned lpw1_pins[] = {
+	TEGRA_PIN_LCD_PWR1_PC1,
+};
+
+static const unsigned lpw2_pins[] = {
+	TEGRA_PIN_LCD_PWR2_PC6,
+};
+
+static const unsigned lsc0_pins[] = {
+	TEGRA_PIN_LCD_PCLK_PB3,
+};
+
+static const unsigned lsc1_pins[] = {
+	TEGRA_PIN_LCD_WR_N_PZ3,
+};
+
+static const unsigned lsck_pins[] = {
+	TEGRA_PIN_LCD_SCK_PZ4,
+};
+
+static const unsigned lsda_pins[] = {
+	TEGRA_PIN_LCD_SDOUT_PN5,
+};
+
+static const unsigned lsdi_pins[] = {
+	TEGRA_PIN_LCD_SDIN_PZ2,
+};
+
+static const unsigned lspi_pins[] = {
+	TEGRA_PIN_LCD_DE_PJ1,
+};
+
+static const unsigned lvp0_pins[] = {
+	TEGRA_PIN_LCD_DC1_PV7,
+};
+
+static const unsigned lvp1_pins[] = {
+	TEGRA_PIN_LCD_D20_PM4,
+};
+
+static const unsigned lvs_pins[] = {
+	TEGRA_PIN_LCD_VSYNC_PJ4,
+};
+
+static const unsigned ls_pins[] = {
+	TEGRA_PIN_LCD_PWR0_PB2,
+	TEGRA_PIN_LCD_PWR1_PC1,
+	TEGRA_PIN_LCD_PWR2_PC6,
+	TEGRA_PIN_LCD_SDIN_PZ2,
+	TEGRA_PIN_LCD_SDOUT_PN5,
+	TEGRA_PIN_LCD_WR_N_PZ3,
+	TEGRA_PIN_LCD_CS0_N_PN4,
+	TEGRA_PIN_LCD_DC0_PN6,
+	TEGRA_PIN_LCD_SCK_PZ4,
+};
+
+static const unsigned lc_pins[] = {
+	TEGRA_PIN_LCD_PCLK_PB3,
+	TEGRA_PIN_LCD_DE_PJ1,
+	TEGRA_PIN_LCD_HSYNC_PJ3,
+	TEGRA_PIN_LCD_VSYNC_PJ4,
+	TEGRA_PIN_LCD_CS1_N_PW0,
+	TEGRA_PIN_LCD_M1_PW1,
+	TEGRA_PIN_LCD_DC1_PV7,
+	TEGRA_PIN_HDMI_INT_N_PN7,
+};
+
+static const unsigned ld17_0_pins[] = {
+	TEGRA_PIN_LCD_D0_PE0,
+	TEGRA_PIN_LCD_D1_PE1,
+	TEGRA_PIN_LCD_D2_PE2,
+	TEGRA_PIN_LCD_D3_PE3,
+	TEGRA_PIN_LCD_D4_PE4,
+	TEGRA_PIN_LCD_D5_PE5,
+	TEGRA_PIN_LCD_D6_PE6,
+	TEGRA_PIN_LCD_D7_PE7,
+	TEGRA_PIN_LCD_D8_PF0,
+	TEGRA_PIN_LCD_D9_PF1,
+	TEGRA_PIN_LCD_D10_PF2,
+	TEGRA_PIN_LCD_D11_PF3,
+	TEGRA_PIN_LCD_D12_PF4,
+	TEGRA_PIN_LCD_D13_PF5,
+	TEGRA_PIN_LCD_D14_PF6,
+	TEGRA_PIN_LCD_D15_PF7,
+	TEGRA_PIN_LCD_D16_PM0,
+	TEGRA_PIN_LCD_D17_PM1,
+};
+
+static const unsigned ld19_18_pins[] = {
+	TEGRA_PIN_LCD_D18_PM2,
+	TEGRA_PIN_LCD_D19_PM3,
+};
+
+static const unsigned ld21_20_pins[] = {
+	TEGRA_PIN_LCD_D20_PM4,
+	TEGRA_PIN_LCD_D21_PM5,
+};
+
+static const unsigned ld23_22_pins[] = {
+	TEGRA_PIN_LCD_D22_PM6,
+	TEGRA_PIN_LCD_D23_PM7,
+};
+
+static const unsigned owc_pins[] = {
+	TEGRA_PIN_OWC,
+};
+
+static const unsigned pmc_pins[] = {
+	TEGRA_PIN_LED_BLINK_PBB0,
+	TEGRA_PIN_SYS_CLK_REQ_PZ5,
+	TEGRA_PIN_CORE_PWR_REQ,
+	TEGRA_PIN_CPU_PWR_REQ,
+	TEGRA_PIN_PWR_INT_N,
+};
+
+static const unsigned pta_pins[] = {
+	TEGRA_PIN_GEN2_I2C_SCL_PT5,
+	TEGRA_PIN_GEN2_I2C_SDA_PT6,
+};
+
+static const unsigned rm_pins[] = {
+	TEGRA_PIN_GEN1_I2C_SCL_PC4,
+	TEGRA_PIN_GEN1_I2C_SDA_PC5,
+};
+
+static const unsigned sdb_pins[] = {
+	TEGRA_PIN_SDIO3_CMD_PA7,
+};
+
+static const unsigned sdc_pins[] = {
+	TEGRA_PIN_SDIO3_DAT0_PB7,
+	TEGRA_PIN_SDIO3_DAT1_PB6,
+	TEGRA_PIN_SDIO3_DAT2_PB5,
+	TEGRA_PIN_SDIO3_DAT3_PB4,
+};
+
+static const unsigned sdd_pins[] = {
+	TEGRA_PIN_SDIO3_CLK_PA6,
+};
+
+static const unsigned sdio1_pins[] = {
+	TEGRA_PIN_SDIO1_CLK_PZ0,
+	TEGRA_PIN_SDIO1_CMD_PZ1,
+	TEGRA_PIN_SDIO1_DAT0_PY7,
+	TEGRA_PIN_SDIO1_DAT1_PY6,
+	TEGRA_PIN_SDIO1_DAT2_PY5,
+	TEGRA_PIN_SDIO1_DAT3_PY4,
+};
+
+static const unsigned slxa_pins[] = {
+	TEGRA_PIN_SDIO3_DAT4_PD1,
+};
+
+static const unsigned slxc_pins[] = {
+	TEGRA_PIN_SDIO3_DAT6_PD3,
+};
+
+static const unsigned slxd_pins[] = {
+	TEGRA_PIN_SDIO3_DAT7_PD4,
+};
+
+static const unsigned slxk_pins[] = {
+	TEGRA_PIN_SDIO3_DAT5_PD0,
+};
+
+static const unsigned spdi_pins[] = {
+	TEGRA_PIN_SPDIF_IN_PK6,
+};
+
+static const unsigned spdo_pins[] = {
+	TEGRA_PIN_SPDIF_OUT_PK5,
+};
+
+static const unsigned spia_pins[] = {
+	TEGRA_PIN_SPI2_MOSI_PX0,
+};
+
+static const unsigned spib_pins[] = {
+	TEGRA_PIN_SPI2_MISO_PX1,
+};
+
+static const unsigned spic_pins[] = {
+	TEGRA_PIN_SPI2_CS0_N_PX3,
+	TEGRA_PIN_SPI2_SCK_PX2,
+};
+
+static const unsigned spid_pins[] = {
+	TEGRA_PIN_SPI1_MOSI_PX4,
+};
+
+static const unsigned spie_pins[] = {
+	TEGRA_PIN_SPI1_CS0_N_PX6,
+	TEGRA_PIN_SPI1_SCK_PX5,
+};
+
+static const unsigned spif_pins[] = {
+	TEGRA_PIN_SPI1_MISO_PX7,
+};
+
+static const unsigned spig_pins[] = {
+	TEGRA_PIN_SPI2_CS1_N_PW2,
+};
+
+static const unsigned spih_pins[] = {
+	TEGRA_PIN_SPI2_CS2_N_PW3,
+};
+
+static const unsigned uaa_pins[] = {
+	TEGRA_PIN_ULPI_DATA0_PO1,
+	TEGRA_PIN_ULPI_DATA1_PO2,
+	TEGRA_PIN_ULPI_DATA2_PO3,
+	TEGRA_PIN_ULPI_DATA3_PO4,
+};
+
+static const unsigned uab_pins[] = {
+	TEGRA_PIN_ULPI_DATA4_PO5,
+	TEGRA_PIN_ULPI_DATA5_PO6,
+	TEGRA_PIN_ULPI_DATA6_PO7,
+	TEGRA_PIN_ULPI_DATA7_PO0,
+};
+
+static const unsigned uac_pins[] = {
+	TEGRA_PIN_PV0,
+	TEGRA_PIN_PV1,
+	TEGRA_PIN_PV2,
+	TEGRA_PIN_PV3,
+};
+
+static const unsigned ck32_pins[] = {
+	TEGRA_PIN_CLK_32_K_IN,
+};
+
+static const unsigned uad_pins[] = {
+	TEGRA_PIN_UART2_RXD_PC3,
+	TEGRA_PIN_UART2_TXD_PC2,
+};
+
+static const unsigned uca_pins[] = {
+	TEGRA_PIN_UART3_RXD_PW7,
+	TEGRA_PIN_UART3_TXD_PW6,
+};
+
+static const unsigned ucb_pins[] = {
+	TEGRA_PIN_UART3_CTS_N_PA1,
+	TEGRA_PIN_UART3_RTS_N_PC0,
+};
+
+static const unsigned uda_pins[] = {
+	TEGRA_PIN_ULPI_CLK_PY0,
+	TEGRA_PIN_ULPI_DIR_PY1,
+	TEGRA_PIN_ULPI_NXT_PY2,
+	TEGRA_PIN_ULPI_STP_PY3,
+};
+
+static const unsigned ddrc_pins[] = {
+	TEGRA_PIN_DDR_COMP_PD,
+	TEGRA_PIN_DDR_COMP_PU,
+};
+
+static const unsigned pmca_pins[] = {
+	TEGRA_PIN_LED_BLINK_PBB0,
+};
+
+static const unsigned pmcb_pins[] = {
+	TEGRA_PIN_SYS_CLK_REQ_PZ5,
+};
+
+static const unsigned pmcc_pins[] = {
+	TEGRA_PIN_CORE_PWR_REQ,
+};
+
+static const unsigned pmcd_pins[] = {
+	TEGRA_PIN_CPU_PWR_REQ,
+};
+
+static const unsigned pmce_pins[] = {
+	TEGRA_PIN_PWR_INT_N,
+};
+
+static const unsigned xm2c_pins[] = {
+	TEGRA_PIN_DDR_A0,
+	TEGRA_PIN_DDR_A1,
+	TEGRA_PIN_DDR_A2,
+	TEGRA_PIN_DDR_A3,
+	TEGRA_PIN_DDR_A4,
+	TEGRA_PIN_DDR_A5,
+	TEGRA_PIN_DDR_A6,
+	TEGRA_PIN_DDR_A7,
+	TEGRA_PIN_DDR_A8,
+	TEGRA_PIN_DDR_A9,
+	TEGRA_PIN_DDR_A10,
+	TEGRA_PIN_DDR_A11,
+	TEGRA_PIN_DDR_A12,
+	TEGRA_PIN_DDR_A13,
+	TEGRA_PIN_DDR_A14,
+	TEGRA_PIN_DDR_CAS_N,
+	TEGRA_PIN_DDR_BA0,
+	TEGRA_PIN_DDR_BA1,
+	TEGRA_PIN_DDR_BA2,
+	TEGRA_PIN_DDR_DQS0P,
+	TEGRA_PIN_DDR_DQS0N,
+	TEGRA_PIN_DDR_DQS1P,
+	TEGRA_PIN_DDR_DQS1N,
+	TEGRA_PIN_DDR_DQS2P,
+	TEGRA_PIN_DDR_DQS2N,
+	TEGRA_PIN_DDR_DQS3P,
+	TEGRA_PIN_DDR_DQS3N,
+	TEGRA_PIN_DDR_CS0_N,
+	TEGRA_PIN_DDR_CS1_N,
+	TEGRA_PIN_DDR_CKE0,
+	TEGRA_PIN_DDR_CKE1,
+	TEGRA_PIN_DDR_CLK,
+	TEGRA_PIN_DDR_CLK_N,
+	TEGRA_PIN_DDR_DM0,
+	TEGRA_PIN_DDR_DM1,
+	TEGRA_PIN_DDR_DM2,
+	TEGRA_PIN_DDR_DM3,
+	TEGRA_PIN_DDR_ODT,
+	TEGRA_PIN_DDR_RAS_N,
+	TEGRA_PIN_DDR_WE_N,
+	TEGRA_PIN_DDR_QUSE0,
+	TEGRA_PIN_DDR_QUSE1,
+	TEGRA_PIN_DDR_QUSE2,
+	TEGRA_PIN_DDR_QUSE3,
+};
+
+static const unsigned xm2d_pins[] = {
+	TEGRA_PIN_DDR_DQ0,
+	TEGRA_PIN_DDR_DQ1,
+	TEGRA_PIN_DDR_DQ2,
+	TEGRA_PIN_DDR_DQ3,
+	TEGRA_PIN_DDR_DQ4,
+	TEGRA_PIN_DDR_DQ5,
+	TEGRA_PIN_DDR_DQ6,
+	TEGRA_PIN_DDR_DQ7,
+	TEGRA_PIN_DDR_DQ8,
+	TEGRA_PIN_DDR_DQ9,
+	TEGRA_PIN_DDR_DQ10,
+	TEGRA_PIN_DDR_DQ11,
+	TEGRA_PIN_DDR_DQ12,
+	TEGRA_PIN_DDR_DQ13,
+	TEGRA_PIN_DDR_DQ14,
+	TEGRA_PIN_DDR_DQ15,
+	TEGRA_PIN_DDR_DQ16,
+	TEGRA_PIN_DDR_DQ17,
+	TEGRA_PIN_DDR_DQ18,
+	TEGRA_PIN_DDR_DQ19,
+	TEGRA_PIN_DDR_DQ20,
+	TEGRA_PIN_DDR_DQ21,
+	TEGRA_PIN_DDR_DQ22,
+	TEGRA_PIN_DDR_DQ23,
+	TEGRA_PIN_DDR_DQ24,
+	TEGRA_PIN_DDR_DQ25,
+	TEGRA_PIN_DDR_DQ26,
+	TEGRA_PIN_DDR_DQ27,
+	TEGRA_PIN_DDR_DQ28,
+	TEGRA_PIN_DDR_DQ29,
+	TEGRA_PIN_DDR_DQ30,
+	TEGRA_PIN_DDR_DQ31,
+};
+
+static const unsigned drive_ao1_pins[] = {
+	TEGRA_PIN_SYS_RESET,
+	TEGRA_PIN_PWR_I2C_SCL_PZ6,
+	TEGRA_PIN_PWR_I2C_SDA_PZ7,
+	TEGRA_PIN_KB_ROW0_PR0,
+	TEGRA_PIN_KB_ROW1_PR1,
+	TEGRA_PIN_KB_ROW2_PR2,
+	TEGRA_PIN_KB_ROW3_PR3,
+	TEGRA_PIN_KB_ROW4_PR4,
+	TEGRA_PIN_KB_ROW5_PR5,
+	TEGRA_PIN_KB_ROW6_PR6,
+	TEGRA_PIN_KB_ROW7_PR7,
+};
+
+static const unsigned drive_ao2_pins[] = {
+	TEGRA_PIN_KB_ROW8_PS0,
+	TEGRA_PIN_KB_ROW9_PS1,
+	TEGRA_PIN_KB_ROW10_PS2,
+	TEGRA_PIN_KB_ROW11_PS3,
+	TEGRA_PIN_KB_ROW12_PS4,
+	TEGRA_PIN_KB_ROW13_PS5,
+	TEGRA_PIN_KB_ROW14_PS6,
+	TEGRA_PIN_KB_ROW15_PS7,
+	TEGRA_PIN_KB_COL0_PQ0,
+	TEGRA_PIN_KB_COL1_PQ1,
+	TEGRA_PIN_KB_COL2_PQ2,
+	TEGRA_PIN_KB_COL3_PQ3,
+	TEGRA_PIN_KB_COL4_PQ4,
+	TEGRA_PIN_KB_COL5_PQ5,
+	TEGRA_PIN_KB_COL6_PQ6,
+	TEGRA_PIN_KB_COL7_PQ7,
+	TEGRA_PIN_LED_BLINK_PBB0,
+	TEGRA_PIN_SYS_CLK_REQ_PZ5,
+	TEGRA_PIN_CORE_PWR_REQ,
+	TEGRA_PIN_CPU_PWR_REQ,
+	TEGRA_PIN_PWR_INT_N,
+	TEGRA_PIN_CLK_32_K_IN,
+};
+
+static const unsigned drive_at1_pins[] = {
+	TEGRA_PIN_GMI_IORDY_PI5,
+	TEGRA_PIN_GMI_AD8_PH0,
+	TEGRA_PIN_GMI_AD9_PH1,
+	TEGRA_PIN_GMI_AD10_PH2,
+	TEGRA_PIN_GMI_AD11_PH3,
+	TEGRA_PIN_GMI_AD12_PH4,
+	TEGRA_PIN_GMI_AD13_PH5,
+	TEGRA_PIN_GMI_AD14_PH6,
+	TEGRA_PIN_GMI_AD15_PH7,
+	TEGRA_PIN_GMI_CS7_N_PI6,
+	TEGRA_PIN_GMI_DPD_PT7,
+	TEGRA_PIN_GEN2_I2C_SCL_PT5,
+	TEGRA_PIN_GEN2_I2C_SDA_PT6,
+};
+
+static const unsigned drive_at2_pins[] = {
+	TEGRA_PIN_GMI_WAIT_PI7,
+	TEGRA_PIN_GMI_ADV_N_PK0,
+	TEGRA_PIN_GMI_CLK_PK1,
+	TEGRA_PIN_GMI_CS6_N_PI3,
+	TEGRA_PIN_GMI_CS5_N_PI2,
+	TEGRA_PIN_GMI_CS4_N_PK2,
+	TEGRA_PIN_GMI_CS3_N_PK4,
+	TEGRA_PIN_GMI_CS2_N_PK3,
+	TEGRA_PIN_GMI_AD0_PG0,
+	TEGRA_PIN_GMI_AD1_PG1,
+	TEGRA_PIN_GMI_AD2_PG2,
+	TEGRA_PIN_GMI_AD3_PG3,
+	TEGRA_PIN_GMI_AD4_PG4,
+	TEGRA_PIN_GMI_AD5_PG5,
+	TEGRA_PIN_GMI_AD6_PG6,
+	TEGRA_PIN_GMI_AD7_PG7,
+	TEGRA_PIN_GMI_HIOW_N_PI0,
+	TEGRA_PIN_GMI_HIOR_N_PI1,
+	TEGRA_PIN_GMI_RST_N_PI4,
+};
+
+static const unsigned drive_cdev1_pins[] = {
+	TEGRA_PIN_DAP_MCLK1_PW4,
+};
+
+static const unsigned drive_cdev2_pins[] = {
+	TEGRA_PIN_DAP_MCLK2_PW5,
+};
+
+static const unsigned drive_csus_pins[] = {
+	TEGRA_PIN_VI_MCLK_PT1,
+};
+
+static const unsigned drive_dap1_pins[] = {
+	TEGRA_PIN_DAP1_FS_PN0,
+	TEGRA_PIN_DAP1_DIN_PN1,
+	TEGRA_PIN_DAP1_DOUT_PN2,
+	TEGRA_PIN_DAP1_SCLK_PN3,
+	TEGRA_PIN_SPDIF_OUT_PK5,
+	TEGRA_PIN_SPDIF_IN_PK6,
+};
+
+static const unsigned drive_dap2_pins[] = {
+	TEGRA_PIN_DAP2_FS_PA2,
+	TEGRA_PIN_DAP2_SCLK_PA3,
+	TEGRA_PIN_DAP2_DIN_PA4,
+	TEGRA_PIN_DAP2_DOUT_PA5,
+};
+
+static const unsigned drive_dap3_pins[] = {
+	TEGRA_PIN_DAP3_FS_PP0,
+	TEGRA_PIN_DAP3_DIN_PP1,
+	TEGRA_PIN_DAP3_DOUT_PP2,
+	TEGRA_PIN_DAP3_SCLK_PP3,
+};
+
+static const unsigned drive_dap4_pins[] = {
+	TEGRA_PIN_DAP4_FS_PP4,
+	TEGRA_PIN_DAP4_DIN_PP5,
+	TEGRA_PIN_DAP4_DOUT_PP6,
+	TEGRA_PIN_DAP4_SCLK_PP7,
+};
+
+static const unsigned drive_dbg_pins[] = {
+	TEGRA_PIN_PU0,
+	TEGRA_PIN_PU1,
+	TEGRA_PIN_PU2,
+	TEGRA_PIN_PU3,
+	TEGRA_PIN_PU4,
+	TEGRA_PIN_PU5,
+	TEGRA_PIN_PU6,
+	TEGRA_PIN_JTAG_RTCK_PU7,
+	TEGRA_PIN_GEN1_I2C_SDA_PC5,
+	TEGRA_PIN_GEN1_I2C_SCL_PC4,
+	TEGRA_PIN_JTAG_TRST_N,
+	TEGRA_PIN_JTAG_TDO,
+	TEGRA_PIN_JTAG_TMS,
+	TEGRA_PIN_JTAG_TCK,
+	TEGRA_PIN_JTAG_TDI,
+	TEGRA_PIN_TEST_MODE_EN,
+};
+
+static const unsigned drive_lcd1_pins[] = {
+	TEGRA_PIN_LCD_PWR1_PC1,
+	TEGRA_PIN_LCD_PWR2_PC6,
+	TEGRA_PIN_LCD_SDIN_PZ2,
+	TEGRA_PIN_LCD_SDOUT_PN5,
+	TEGRA_PIN_LCD_WR_N_PZ3,
+	TEGRA_PIN_LCD_CS0_N_PN4,
+	TEGRA_PIN_LCD_DC0_PN6,
+	TEGRA_PIN_LCD_SCK_PZ4,
+};
+
+static const unsigned drive_lcd2_pins[] = {
+	TEGRA_PIN_LCD_PWR0_PB2,
+	TEGRA_PIN_LCD_PCLK_PB3,
+	TEGRA_PIN_LCD_DE_PJ1,
+	TEGRA_PIN_LCD_HSYNC_PJ3,
+	TEGRA_PIN_LCD_VSYNC_PJ4,
+	TEGRA_PIN_LCD_D0_PE0,
+	TEGRA_PIN_LCD_D1_PE1,
+	TEGRA_PIN_LCD_D2_PE2,
+	TEGRA_PIN_LCD_D3_PE3,
+	TEGRA_PIN_LCD_D4_PE4,
+	TEGRA_PIN_LCD_D5_PE5,
+	TEGRA_PIN_LCD_D6_PE6,
+	TEGRA_PIN_LCD_D7_PE7,
+	TEGRA_PIN_LCD_D8_PF0,
+	TEGRA_PIN_LCD_D9_PF1,
+	TEGRA_PIN_LCD_D10_PF2,
+	TEGRA_PIN_LCD_D11_PF3,
+	TEGRA_PIN_LCD_D12_PF4,
+	TEGRA_PIN_LCD_D13_PF5,
+	TEGRA_PIN_LCD_D14_PF6,
+	TEGRA_PIN_LCD_D15_PF7,
+	TEGRA_PIN_LCD_D16_PM0,
+	TEGRA_PIN_LCD_D17_PM1,
+	TEGRA_PIN_LCD_D18_PM2,
+	TEGRA_PIN_LCD_D19_PM3,
+	TEGRA_PIN_LCD_D20_PM4,
+	TEGRA_PIN_LCD_D21_PM5,
+	TEGRA_PIN_LCD_D22_PM6,
+	TEGRA_PIN_LCD_D23_PM7,
+	TEGRA_PIN_LCD_CS1_N_PW0,
+	TEGRA_PIN_LCD_M1_PW1,
+	TEGRA_PIN_LCD_DC1_PV7,
+	TEGRA_PIN_HDMI_INT_N_PN7,
+};
+
+static const unsigned drive_sdmmc2_pins[] = {
+	TEGRA_PIN_SDIO3_DAT4_PD1,
+	TEGRA_PIN_SDIO3_DAT5_PD0,
+	TEGRA_PIN_SDIO3_DAT6_PD3,
+	TEGRA_PIN_SDIO3_DAT7_PD4,
+};
+
+static const unsigned drive_sdmmc3_pins[] = {
+	TEGRA_PIN_SDIO3_CLK_PA6,
+	TEGRA_PIN_SDIO3_CMD_PA7,
+	TEGRA_PIN_SDIO3_DAT0_PB7,
+	TEGRA_PIN_SDIO3_DAT1_PB6,
+	TEGRA_PIN_SDIO3_DAT2_PB5,
+	TEGRA_PIN_SDIO3_DAT3_PB4,
+	TEGRA_PIN_PV4,
+	TEGRA_PIN_PV5,
+	TEGRA_PIN_PV6,
+};
+
+static const unsigned drive_spi_pins[] = {
+	TEGRA_PIN_SPI2_MOSI_PX0,
+	TEGRA_PIN_SPI2_MISO_PX1,
+	TEGRA_PIN_SPI2_SCK_PX2,
+	TEGRA_PIN_SPI2_CS0_N_PX3,
+	TEGRA_PIN_SPI1_MOSI_PX4,
+	TEGRA_PIN_SPI1_SCK_PX5,
+	TEGRA_PIN_SPI1_CS0_N_PX6,
+	TEGRA_PIN_SPI1_MISO_PX7,
+	TEGRA_PIN_SPI2_CS1_N_PW2,
+	TEGRA_PIN_SPI2_CS2_N_PW3,
+};
+
+static const unsigned drive_uaa_pins[] = {
+	TEGRA_PIN_ULPI_DATA0_PO1,
+	TEGRA_PIN_ULPI_DATA1_PO2,
+	TEGRA_PIN_ULPI_DATA2_PO3,
+	TEGRA_PIN_ULPI_DATA3_PO4,
+};
+
+static const unsigned drive_uab_pins[] = {
+	TEGRA_PIN_ULPI_DATA4_PO5,
+	TEGRA_PIN_ULPI_DATA5_PO6,
+	TEGRA_PIN_ULPI_DATA6_PO7,
+	TEGRA_PIN_ULPI_DATA7_PO0,
+	TEGRA_PIN_PV0,
+	TEGRA_PIN_PV1,
+	TEGRA_PIN_PV2,
+	TEGRA_PIN_PV3,
+};
+
+static const unsigned drive_uart2_pins[] = {
+	TEGRA_PIN_UART2_TXD_PC2,
+	TEGRA_PIN_UART2_RXD_PC3,
+	TEGRA_PIN_UART2_RTS_N_PJ6,
+	TEGRA_PIN_UART2_CTS_N_PJ5,
+};
+
+static const unsigned drive_uart3_pins[] = {
+	TEGRA_PIN_UART3_TXD_PW6,
+	TEGRA_PIN_UART3_RXD_PW7,
+	TEGRA_PIN_UART3_RTS_N_PC0,
+	TEGRA_PIN_UART3_CTS_N_PA1,
+};
+
+static const unsigned drive_vi1_pins[] = {
+	TEGRA_PIN_VI_D0_PT4,
+	TEGRA_PIN_VI_D1_PD5,
+	TEGRA_PIN_VI_D2_PL0,
+	TEGRA_PIN_VI_D3_PL1,
+	TEGRA_PIN_VI_D4_PL2,
+	TEGRA_PIN_VI_D5_PL3,
+	TEGRA_PIN_VI_D6_PL4,
+	TEGRA_PIN_VI_D7_PL5,
+	TEGRA_PIN_VI_D8_PL6,
+	TEGRA_PIN_VI_D9_PL7,
+	TEGRA_PIN_VI_D10_PT2,
+	TEGRA_PIN_VI_D11_PT3,
+	TEGRA_PIN_VI_PCLK_PT0,
+	TEGRA_PIN_VI_VSYNC_PD6,
+	TEGRA_PIN_VI_HSYNC_PD7,
+};
+
+static const unsigned drive_vi2_pins[] = {
+	TEGRA_PIN_VI_GP0_PBB1,
+	TEGRA_PIN_CAM_I2C_SCL_PBB2,
+	TEGRA_PIN_CAM_I2C_SDA_PBB3,
+	TEGRA_PIN_VI_GP3_PBB4,
+	TEGRA_PIN_VI_GP4_PBB5,
+	TEGRA_PIN_VI_GP5_PD2,
+	TEGRA_PIN_VI_GP6_PA0,
+};
+
+static const unsigned drive_xm2a_pins[] = {
+	TEGRA_PIN_DDR_A0,
+	TEGRA_PIN_DDR_A1,
+	TEGRA_PIN_DDR_A2,
+	TEGRA_PIN_DDR_A3,
+	TEGRA_PIN_DDR_A4,
+	TEGRA_PIN_DDR_A5,
+	TEGRA_PIN_DDR_A6,
+	TEGRA_PIN_DDR_A7,
+	TEGRA_PIN_DDR_A8,
+	TEGRA_PIN_DDR_A9,
+	TEGRA_PIN_DDR_A10,
+	TEGRA_PIN_DDR_A11,
+	TEGRA_PIN_DDR_A12,
+	TEGRA_PIN_DDR_A13,
+	TEGRA_PIN_DDR_A14,
+	TEGRA_PIN_DDR_BA0,
+	TEGRA_PIN_DDR_BA1,
+	TEGRA_PIN_DDR_BA2,
+	TEGRA_PIN_DDR_CS0_N,
+	TEGRA_PIN_DDR_CS1_N,
+	TEGRA_PIN_DDR_ODT,
+	TEGRA_PIN_DDR_RAS_N,
+	TEGRA_PIN_DDR_CAS_N,
+	TEGRA_PIN_DDR_WE_N,
+	TEGRA_PIN_DDR_CKE0,
+	TEGRA_PIN_DDR_CKE1,
+};
+
+static const unsigned drive_xm2c_pins[] = {
+	TEGRA_PIN_DDR_DQS0P,
+	TEGRA_PIN_DDR_DQS0N,
+	TEGRA_PIN_DDR_DQS1P,
+	TEGRA_PIN_DDR_DQS1N,
+	TEGRA_PIN_DDR_DQS2P,
+	TEGRA_PIN_DDR_DQS2N,
+	TEGRA_PIN_DDR_DQS3P,
+	TEGRA_PIN_DDR_DQS3N,
+	TEGRA_PIN_DDR_QUSE0,
+	TEGRA_PIN_DDR_QUSE1,
+	TEGRA_PIN_DDR_QUSE2,
+	TEGRA_PIN_DDR_QUSE3,
+};
+
+static const unsigned drive_xm2d_pins[] = {
+	TEGRA_PIN_DDR_DQ0,
+	TEGRA_PIN_DDR_DQ1,
+	TEGRA_PIN_DDR_DQ2,
+	TEGRA_PIN_DDR_DQ3,
+	TEGRA_PIN_DDR_DQ4,
+	TEGRA_PIN_DDR_DQ5,
+	TEGRA_PIN_DDR_DQ6,
+	TEGRA_PIN_DDR_DQ7,
+	TEGRA_PIN_DDR_DQ8,
+	TEGRA_PIN_DDR_DQ9,
+	TEGRA_PIN_DDR_DQ10,
+	TEGRA_PIN_DDR_DQ11,
+	TEGRA_PIN_DDR_DQ12,
+	TEGRA_PIN_DDR_DQ13,
+	TEGRA_PIN_DDR_DQ14,
+	TEGRA_PIN_DDR_DQ15,
+	TEGRA_PIN_DDR_DQ16,
+	TEGRA_PIN_DDR_DQ17,
+	TEGRA_PIN_DDR_DQ18,
+	TEGRA_PIN_DDR_DQ19,
+	TEGRA_PIN_DDR_DQ20,
+	TEGRA_PIN_DDR_DQ21,
+	TEGRA_PIN_DDR_DQ22,
+	TEGRA_PIN_DDR_DQ23,
+	TEGRA_PIN_DDR_DQ24,
+	TEGRA_PIN_DDR_DQ25,
+	TEGRA_PIN_DDR_DQ26,
+	TEGRA_PIN_DDR_DQ27,
+	TEGRA_PIN_DDR_DQ28,
+	TEGRA_PIN_DDR_DQ29,
+	TEGRA_PIN_DDR_DQ30,
+	TEGRA_PIN_DDR_DQ31,
+	TEGRA_PIN_DDR_DM0,
+	TEGRA_PIN_DDR_DM1,
+	TEGRA_PIN_DDR_DM2,
+	TEGRA_PIN_DDR_DM3,
+};
+
+static const unsigned drive_xm2clk_pins[] = {
+	TEGRA_PIN_DDR_CLK,
+	TEGRA_PIN_DDR_CLK_N,
+};
+
+static const unsigned drive_sdio1_pins[] = {
+	TEGRA_PIN_SDIO1_CLK_PZ0,
+	TEGRA_PIN_SDIO1_CMD_PZ1,
+	TEGRA_PIN_SDIO1_DAT0_PY7,
+	TEGRA_PIN_SDIO1_DAT1_PY6,
+	TEGRA_PIN_SDIO1_DAT2_PY5,
+	TEGRA_PIN_SDIO1_DAT3_PY4,
+};
+
+static const unsigned drive_crt_pins[] = {
+	TEGRA_PIN_CRT_HSYNC,
+	TEGRA_PIN_CRT_VSYNC,
+};
+
+static const unsigned drive_ddc_pins[] = {
+	TEGRA_PIN_DDC_SCL,
+	TEGRA_PIN_DDC_SDA,
+};
+
+static const unsigned drive_gma_pins[] = {
+	TEGRA_PIN_GMI_AD20_PAA0,
+	TEGRA_PIN_GMI_AD21_PAA1,
+	TEGRA_PIN_GMI_AD22_PAA2,
+	TEGRA_PIN_GMI_AD23_PAA3,
+};
+
+static const unsigned drive_gmb_pins[] = {
+	TEGRA_PIN_GMI_WP_N_PC7,
+};
+
+static const unsigned drive_gmc_pins[] = {
+	TEGRA_PIN_GMI_AD16_PJ7,
+	TEGRA_PIN_GMI_AD17_PB0,
+	TEGRA_PIN_GMI_AD18_PB1,
+	TEGRA_PIN_GMI_AD19_PK7,
+};
+
+static const unsigned drive_gmd_pins[] = {
+	TEGRA_PIN_GMI_CS0_N_PJ0,
+	TEGRA_PIN_GMI_CS1_N_PJ2,
+};
+
+static const unsigned drive_gme_pins[] = {
+	TEGRA_PIN_GMI_AD24_PAA4,
+	TEGRA_PIN_GMI_AD25_PAA5,
+	TEGRA_PIN_GMI_AD26_PAA6,
+	TEGRA_PIN_GMI_AD27_PAA7,
+};
+
+static const unsigned drive_owr_pins[] = {
+	TEGRA_PIN_OWC,
+};
+
+static const unsigned drive_uda_pins[] = {
+	TEGRA_PIN_ULPI_CLK_PY0,
+	TEGRA_PIN_ULPI_DIR_PY1,
+	TEGRA_PIN_ULPI_NXT_PY2,
+	TEGRA_PIN_ULPI_STP_PY3,
+};
+
+enum tegra_mux {
+	TEGRA_MUX_AHB_CLK,
+	TEGRA_MUX_APB_CLK,
+	TEGRA_MUX_AUDIO_SYNC,
+	TEGRA_MUX_CRT,
+	TEGRA_MUX_DAP1,
+	TEGRA_MUX_DAP2,
+	TEGRA_MUX_DAP3,
+	TEGRA_MUX_DAP4,
+	TEGRA_MUX_DAP5,
+	TEGRA_MUX_DISPLAYA,
+	TEGRA_MUX_DISPLAYB,
+	TEGRA_MUX_EMC_TEST0_DLL,
+	TEGRA_MUX_EMC_TEST1_DLL,
+	TEGRA_MUX_GMI,
+	TEGRA_MUX_GMI_INT,
+	TEGRA_MUX_HDMI,
+	TEGRA_MUX_I2CP,
+	TEGRA_MUX_I2C1,
+	TEGRA_MUX_I2C2,
+	TEGRA_MUX_I2C3,
+	TEGRA_MUX_IDE,
+	TEGRA_MUX_IRDA,
+	TEGRA_MUX_KBC,
+	TEGRA_MUX_MIO,
+	TEGRA_MUX_MIPI_HS,
+	TEGRA_MUX_NAND,
+	TEGRA_MUX_OSC,
+	TEGRA_MUX_OWR,
+	TEGRA_MUX_PCIE,
+	TEGRA_MUX_PLLA_OUT,
+	TEGRA_MUX_PLLC_OUT1,
+	TEGRA_MUX_PLLM_OUT1,
+	TEGRA_MUX_PLLP_OUT2,
+	TEGRA_MUX_PLLP_OUT3,
+	TEGRA_MUX_PLLP_OUT4,
+	TEGRA_MUX_PWM,
+	TEGRA_MUX_PWR_INTR,
+	TEGRA_MUX_PWR_ON,
+	TEGRA_MUX_RSVD1,
+	TEGRA_MUX_RSVD2,
+	TEGRA_MUX_RSVD3,
+	TEGRA_MUX_RSVD4,
+	TEGRA_MUX_RTCK,
+	TEGRA_MUX_SDIO1,
+	TEGRA_MUX_SDIO2,
+	TEGRA_MUX_SDIO3,
+	TEGRA_MUX_SDIO4,
+	TEGRA_MUX_SFLASH,
+	TEGRA_MUX_SPDIF,
+	TEGRA_MUX_SPI1,
+	TEGRA_MUX_SPI2,
+	TEGRA_MUX_SPI2_ALT,
+	TEGRA_MUX_SPI3,
+	TEGRA_MUX_SPI4,
+	TEGRA_MUX_TRACE,
+	TEGRA_MUX_TWC,
+	TEGRA_MUX_UARTA,
+	TEGRA_MUX_UARTB,
+	TEGRA_MUX_UARTC,
+	TEGRA_MUX_UARTD,
+	TEGRA_MUX_UARTE,
+	TEGRA_MUX_ULPI,
+	TEGRA_MUX_VI,
+	TEGRA_MUX_VI_SENSOR_CLK,
+	TEGRA_MUX_XIO,
+};
+
+static const char * const ahb_clk_groups[] = {
+	"cdev2",
+};
+
+static const char * const apb_clk_groups[] = {
+	"cdev2",
+};
+
+static const char * const audio_sync_groups[] = {
+	"cdev1",
+};
+
+static const char * const crt_groups[] = {
+	"crtp",
+	"lm1",
+};
+
+static const char * const dap1_groups[] = {
+	"dap1",
+};
+
+static const char * const dap2_groups[] = {
+	"dap2",
+};
+
+static const char * const dap3_groups[] = {
+	"dap3",
+};
+
+static const char * const dap4_groups[] = {
+	"dap4",
+};
+
+static const char * const dap5_groups[] = {
+	"gme",
+};
+
+static const char * const displaya_groups[] = {
+	"lcsn",
+	"ld0",
+	"ld1",
+	"ld10",
+	"ld11",
+	"ld12",
+	"ld13",
+	"ld14",
+	"ld15",
+	"ld16",
+	"ld17",
+	"ld2",
+	"ld3",
+	"ld4",
+	"ld5",
+	"ld6",
+	"ld7",
+	"ld8",
+	"ld9",
+	"ldc",
+	"ldi",
+	"lhp0",
+	"lhp1",
+	"lhp2",
+	"lhs",
+	"lm0",
+	"lm1",
+	"lpp",
+	"lpw0",
+	"lpw1",
+	"lpw2",
+	"lsc0",
+	"lsc1",
+	"lsck",
+	"lsda",
+	"lsdi",
+	"lspi",
+	"lvp0",
+	"lvp1",
+	"lvs",
+};
+
+static const char * const displayb_groups[] = {
+	"lcsn",
+	"ld0",
+	"ld1",
+	"ld10",
+	"ld11",
+	"ld12",
+	"ld13",
+	"ld14",
+	"ld15",
+	"ld16",
+	"ld17",
+	"ld2",
+	"ld3",
+	"ld4",
+	"ld5",
+	"ld6",
+	"ld7",
+	"ld8",
+	"ld9",
+	"ldc",
+	"ldi",
+	"lhp0",
+	"lhp1",
+	"lhp2",
+	"lhs",
+	"lm0",
+	"lm1",
+	"lpp",
+	"lpw0",
+	"lpw1",
+	"lpw2",
+	"lsc0",
+	"lsc1",
+	"lsck",
+	"lsda",
+	"lsdi",
+	"lspi",
+	"lvp0",
+	"lvp1",
+	"lvs",
+};
+
+static const char * const emc_test0_dll_groups[] = {
+	"kbca",
+};
+
+static const char * const emc_test1_dll_groups[] = {
+	"kbcc",
+};
+
+static const char * const gmi_groups[] = {
+	"ata",
+	"atb",
+	"atc",
+	"atd",
+	"ate",
+	"dap1",
+	"dap2",
+	"dap4",
+	"gma",
+	"gmb",
+	"gmc",
+	"gmd",
+	"gme",
+	"gpu",
+	"irrx",
+	"irtx",
+	"pta",
+	"spia",
+	"spib",
+	"spic",
+	"spid",
+	"spie",
+	"uca",
+	"ucb",
+};
+
+static const char * const gmi_int_groups[] = {
+	"gmb",
+};
+
+static const char * const hdmi_groups[] = {
+	"hdint",
+	"lpw0",
+	"lpw2",
+	"lsc1",
+	"lsck",
+	"lsda",
+	"lspi",
+	"pta",
+};
+
+static const char * const i2cp_groups[] = {
+	"i2cp",
+};
+
+static const char * const i2c1_groups[] = {
+	"rm",
+	"spdi",
+	"spdo",
+	"spig",
+	"spih",
+};
+
+static const char * const i2c2_groups[] = {
+	"ddc",
+	"pta",
+};
+
+static const char * const i2c3_groups[] = {
+	"dtf",
+};
+
+static const char * const ide_groups[] = {
+	"ata",
+	"atb",
+	"atc",
+	"atd",
+	"ate",
+	"gmb",
+};
+
+static const char * const irda_groups[] = {
+	"uad",
+};
+
+static const char * const kbc_groups[] = {
+	"kbca",
+	"kbcb",
+	"kbcc",
+	"kbcd",
+	"kbce",
+	"kbcf",
+};
+
+static const char * const mio_groups[] = {
+	"kbcb",
+	"kbcd",
+	"kbcf",
+};
+
+static const char * const mipi_hs_groups[] = {
+	"uaa",
+	"uab",
+};
+
+static const char * const nand_groups[] = {
+	"ata",
+	"atb",
+	"atc",
+	"atd",
+	"ate",
+	"gmb",
+	"gmd",
+	"kbca",
+	"kbcb",
+	"kbcc",
+	"kbcd",
+	"kbce",
+	"kbcf",
+};
+
+static const char * const osc_groups[] = {
+	"cdev1",
+	"cdev2",
+};
+
+static const char * const owr_groups[] = {
+	"kbce",
+	"owc",
+	"uac",
+};
+
+static const char * const pcie_groups[] = {
+	"gpv",
+	"slxa",
+	"slxk",
+};
+
+static const char * const plla_out_groups[] = {
+	"cdev1",
+};
+
+static const char * const pllc_out1_groups[] = {
+	"csus",
+};
+
+static const char * const pllm_out1_groups[] = {
+	"cdev1",
+};
+
+static const char * const pllp_out2_groups[] = {
+	"csus",
+};
+
+static const char * const pllp_out3_groups[] = {
+	"csus",
+};
+
+static const char * const pllp_out4_groups[] = {
+	"cdev2",
+};
+
+static const char * const pwm_groups[] = {
+	"gpu",
+	"sdb",
+	"sdc",
+	"sdd",
+	"ucb",
+};
+
+static const char * const pwr_intr_groups[] = {
+	"pmc",
+};
+
+static const char * const pwr_on_groups[] = {
+	"pmc",
+};
+
+static const char * const rsvd1_groups[] = {
+	"dta",
+	"dtb",
+	"dtc",
+	"dtd",
+	"dte",
+	"gmd",
+	"gme",
+};
+
+static const char * const rsvd2_groups[] = {
+	"crtp",
+	"dap1",
+	"dap3",
+	"dap4",
+	"ddc",
+	"dtb",
+	"dtc",
+	"dte",
+	"dtf",
+	"gpu7",
+	"gpv",
+	"hdint",
+	"i2cp",
+	"owc",
+	"rm",
+	"sdio1",
+	"spdi",
+	"spdo",
+	"uac",
+	"uca",
+	"uda",
+};
+
+static const char * const rsvd3_groups[] = {
+	"crtp",
+	"dap2",
+	"dap3",
+	"ddc",
+	"gpu7",
+	"gpv",
+	"hdint",
+	"i2cp",
+	"ld17",
+	"ldc",
+	"ldi",
+	"lhp0",
+	"lhp1",
+	"lhp2",
+	"lm1",
+	"lpp",
+	"lpw1",
+	"lvp0",
+	"lvp1",
+	"owc",
+	"pmc",
+	"rm",
+	"uac",
+};
+
+static const char * const rsvd4_groups[] = {
+	"ata",
+	"ate",
+	"crtp",
+	"dap3",
+	"dap4",
+	"ddc",
+	"dta",
+	"dtc",
+	"dtd",
+	"dtf",
+	"gpu",
+	"gpu7",
+	"gpv",
+	"hdint",
+	"i2cp",
+	"kbce",
+	"lcsn",
+	"ld0",
+	"ld1",
+	"ld2",
+	"ld3",
+	"ld4",
+	"ld5",
+	"ld6",
+	"ld7",
+	"ld8",
+	"ld9",
+	"ld10",
+	"ld11",
+	"ld12",
+	"ld13",
+	"ld14",
+	"ld15",
+	"ld16",
+	"ld17",
+	"ldc",
+	"ldi",
+	"lhp0",
+	"lhp1",
+	"lhp2",
+	"lhs",
+	"lm0",
+	"lpp",
+	"lpw1",
+	"lsc0",
+	"lsdi",
+	"lvp0",
+	"lvp1",
+	"lvs",
+	"owc",
+	"pmc",
+	"pta",
+	"rm",
+	"spif",
+	"uac",
+	"uca",
+	"ucb",
+};
+
+static const char * const rtck_groups[] = {
+	"gpu7",
+};
+
+static const char * const sdio1_groups[] = {
+	"sdio1",
+};
+
+static const char * const sdio2_groups[] = {
+	"dap1",
+	"dta",
+	"dtd",
+	"kbca",
+	"kbcb",
+	"kbcd",
+	"spdi",
+	"spdo",
+};
+
+static const char * const sdio3_groups[] = {
+	"sdb",
+	"sdc",
+	"sdd",
+	"slxa",
+	"slxc",
+	"slxd",
+	"slxk",
+};
+
+static const char * const sdio4_groups[] = {
+	"atb",
+	"atc",
+	"atd",
+	"gma",
+	"gme",
+};
+
+static const char * const sflash_groups[] = {
+	"gmc",
+	"gmd",
+};
+
+static const char * const spdif_groups[] = {
+	"slxc",
+	"slxd",
+	"spdi",
+	"spdo",
+	"uad",
+};
+
+static const char * const spi1_groups[] = {
+	"dtb",
+	"dte",
+	"spia",
+	"spib",
+	"spic",
+	"spid",
+	"spie",
+	"spif",
+	"uda",
+};
+
+static const char * const spi2_groups[] = {
+	"sdb",
+	"slxa",
+	"slxc",
+	"slxd",
+	"slxk",
+	"spia",
+	"spib",
+	"spic",
+	"spid",
+	"spie",
+	"spif",
+	"spig",
+	"spih",
+	"uab",
+};
+
+static const char * const spi2_alt_groups[] = {
+	"spid",
+	"spie",
+	"spig",
+	"spih",
+};
+
+static const char * const spi3_groups[] = {
+	"gma",
+	"lcsn",
+	"lm0",
+	"lpw0",
+	"lpw2",
+	"lsc1",
+	"lsck",
+	"lsda",
+	"lsdi",
+	"sdc",
+	"sdd",
+	"spia",
+	"spib",
+	"spic",
+	"spif",
+	"spig",
+	"spih",
+	"uaa",
+};
+
+static const char * const spi4_groups[] = {
+	"gmc",
+	"irrx",
+	"irtx",
+	"slxa",
+	"slxc",
+	"slxd",
+	"slxk",
+	"uad",
+};
+
+static const char * const trace_groups[] = {
+	"kbcc",
+	"kbcf",
+};
+
+static const char * const twc_groups[] = {
+	"dap2",
+	"sdc",
+};
+
+static const char * const uarta_groups[] = {
+	"gpu",
+	"irrx",
+	"irtx",
+	"sdb",
+	"sdd",
+	"sdio1",
+	"uaa",
+	"uab",
+	"uad",
+};
+
+static const char * const uartb_groups[] = {
+	"irrx",
+	"irtx",
+};
+
+static const char * const uartc_groups[] = {
+	"uca",
+	"ucb",
+};
+
+static const char * const uartd_groups[] = {
+	"gmc",
+	"uda",
+};
+
+static const char * const uarte_groups[] = {
+	"gma",
+	"sdio1",
+};
+
+static const char * const ulpi_groups[] = {
+	"uaa",
+	"uab",
+	"uda",
+};
+
+static const char * const vi_groups[] = {
+	"dta",
+	"dtb",
+	"dtc",
+	"dtd",
+	"dte",
+	"dtf",
+};
+
+static const char * const vi_sensor_clk_groups[] = {
+	"csus",
+};
+
+static const char * const xio_groups[] = {
+	"ld0",
+	"ld1",
+	"ld10",
+	"ld11",
+	"ld12",
+	"ld13",
+	"ld14",
+	"ld15",
+	"ld16",
+	"ld2",
+	"ld3",
+	"ld4",
+	"ld5",
+	"ld6",
+	"ld7",
+	"ld8",
+	"ld9",
+	"lhs",
+	"lsc0",
+	"lspi",
+	"lvs",
+};
+
+#define FUNCTION(fname)					\
+	{						\
+		.name = #fname,				\
+		.groups = fname##_groups,		\
+		.ngroups = ARRAY_SIZE(fname##_groups),	\
+	}
+
+static const struct tegra_function tegra20_functions[] = {
+	FUNCTION(ahb_clk),
+	FUNCTION(apb_clk),
+	FUNCTION(audio_sync),
+	FUNCTION(crt),
+	FUNCTION(dap1),
+	FUNCTION(dap2),
+	FUNCTION(dap3),
+	FUNCTION(dap4),
+	FUNCTION(dap5),
+	FUNCTION(displaya),
+	FUNCTION(displayb),
+	FUNCTION(emc_test0_dll),
+	FUNCTION(emc_test1_dll),
+	FUNCTION(gmi),
+	FUNCTION(gmi_int),
+	FUNCTION(hdmi),
+	FUNCTION(i2cp),
+	FUNCTION(i2c1),
+	FUNCTION(i2c2),
+	FUNCTION(i2c3),
+	FUNCTION(ide),
+	FUNCTION(irda),
+	FUNCTION(kbc),
+	FUNCTION(mio),
+	FUNCTION(mipi_hs),
+	FUNCTION(nand),
+	FUNCTION(osc),
+	FUNCTION(owr),
+	FUNCTION(pcie),
+	FUNCTION(plla_out),
+	FUNCTION(pllc_out1),
+	FUNCTION(pllm_out1),
+	FUNCTION(pllp_out2),
+	FUNCTION(pllp_out3),
+	FUNCTION(pllp_out4),
+	FUNCTION(pwm),
+	FUNCTION(pwr_intr),
+	FUNCTION(pwr_on),
+	FUNCTION(rsvd1),
+	FUNCTION(rsvd2),
+	FUNCTION(rsvd3),
+	FUNCTION(rsvd4),
+	FUNCTION(rtck),
+	FUNCTION(sdio1),
+	FUNCTION(sdio2),
+	FUNCTION(sdio3),
+	FUNCTION(sdio4),
+	FUNCTION(sflash),
+	FUNCTION(spdif),
+	FUNCTION(spi1),
+	FUNCTION(spi2),
+	FUNCTION(spi2_alt),
+	FUNCTION(spi3),
+	FUNCTION(spi4),
+	FUNCTION(trace),
+	FUNCTION(twc),
+	FUNCTION(uarta),
+	FUNCTION(uartb),
+	FUNCTION(uartc),
+	FUNCTION(uartd),
+	FUNCTION(uarte),
+	FUNCTION(ulpi),
+	FUNCTION(vi),
+	FUNCTION(vi_sensor_clk),
+	FUNCTION(xio),
+};
+
+#define TRISTATE_REG_A		0x14
+#define PIN_MUX_CTL_REG_A	0x80
+#define PULLUPDOWN_REG_A	0xa0
+#define PINGROUP_REG_A		0x868
+
+/* Pin group with mux control, and typically tri-state and pull-up/down too */
+#define MUX_PG(pg_name, f0, f1, f2, f3, f_safe,			\
+	       tri_r, tri_b, mux_r, mux_b, pupd_r, pupd_b)	\
+	{							\
+		.name = #pg_name,				\
+		.pins = pg_name##_pins,				\
+		.npins = ARRAY_SIZE(pg_name##_pins),		\
+		.funcs = {					\
+			TEGRA_MUX_ ## f0,			\
+			TEGRA_MUX_ ## f1,			\
+			TEGRA_MUX_ ## f2,			\
+			TEGRA_MUX_ ## f3,			\
+		},						\
+		.func_safe = TEGRA_MUX_ ## f_safe,		\
+		.mux_reg = ((mux_r) - PIN_MUX_CTL_REG_A),	\
+		.mux_bank = 1,					\
+		.mux_bit = mux_b,				\
+		.pupd_reg = ((pupd_r) - PULLUPDOWN_REG_A),	\
+		.pupd_bank = 2,					\
+		.pupd_bit = pupd_b,				\
+		.tri_reg = ((tri_r) - TRISTATE_REG_A),		\
+		.tri_bank = 0,					\
+		.tri_bit = tri_b,				\
+		.einput_reg = -1,				\
+		.odrain_reg = -1,				\
+		.lock_reg = -1,					\
+		.ioreset_reg = -1,				\
+		.drv_reg = -1,					\
+	}
+
+/* Pin groups with only pull up and pull down control */
+#define PULL_PG(pg_name, pupd_r, pupd_b)			\
+	{							\
+		.name = #pg_name,				\
+		.pins = pg_name##_pins,				\
+		.npins = ARRAY_SIZE(pg_name##_pins),		\
+		.mux_reg = -1,					\
+		.pupd_reg = ((pupd_r) - PULLUPDOWN_REG_A),	\
+		.pupd_bank = 2,					\
+		.pupd_bit = pupd_b,				\
+		.tri_reg = -1,					\
+		.einput_reg = -1,				\
+		.odrain_reg = -1,				\
+		.lock_reg = -1,					\
+		.ioreset_reg = -1,				\
+		.drv_reg = -1,					\
+	}
+
+/* Pin groups for drive strength registers (configurable version) */
+#define DRV_PG_EXT(pg_name, r, hsm_b, schmitt_b, lpmd_b,	\
+		   drvdn_b, drvup_b,				\
+		   slwr_b, slwr_w, slwf_b, slwf_w)		\
+	{							\
+		.name = "drive_" #pg_name,			\
+		.pins = drive_##pg_name##_pins,			\
+		.npins = ARRAY_SIZE(drive_##pg_name##_pins),	\
+		.mux_reg = -1,					\
+		.pupd_reg = -1,					\
+		.tri_reg = -1,					\
+		.einput_reg = -1,				\
+		.odrain_reg = -1,				\
+		.lock_reg = -1,					\
+		.ioreset_reg = -1,				\
+		.drv_reg = ((r) - PINGROUP_REG_A),		\
+		.drv_bank = 3,					\
+		.hsm_bit = hsm_b,				\
+		.schmitt_bit = schmitt_b,			\
+		.lpmd_bit = lpmd_b,				\
+		.drvdn_bit = drvdn_b,				\
+		.drvdn_width = 5,				\
+		.drvup_bit = drvup_b,				\
+		.drvup_width = 5,				\
+		.slwr_bit = slwr_b,				\
+		.slwr_width = slwr_w,				\
+		.slwf_bit = slwf_b,				\
+		.slwf_width = slwf_w,				\
+	}
+
+/* Pin groups for drive strength registers (simple version) */
+#define DRV_PG(pg_name, r) \
+	DRV_PG_EXT(pg_name, r, 2,  3,  4, 12, 20, 28, 2, 30, 2)
+
+static const struct tegra_pingroup tegra20_groups[] = {
+	/*     name,   f0,        f1,        f2,        f3,            f_safe,    tri r/b,  mux r/b,  pupd r/b */
+	MUX_PG(ata,    IDE,       NAND,      GMI,       RSVD4,         IDE,       0x14, 0,  0x80, 24, 0xa0, 0),
+	MUX_PG(atb,    IDE,       NAND,      GMI,       SDIO4,         IDE,       0x14, 1,  0x80, 16, 0xa0, 2),
+	MUX_PG(atc,    IDE,       NAND,      GMI,       SDIO4,         IDE,       0x14, 2,  0x80, 22, 0xa0, 4),
+	MUX_PG(atd,    IDE,       NAND,      GMI,       SDIO4,         IDE,       0x14, 3,  0x80, 20, 0xa0, 6),
+	MUX_PG(ate,    IDE,       NAND,      GMI,       RSVD4,         IDE,       0x18, 25, 0x80, 12, 0xa0, 8),
+	MUX_PG(cdev1,  OSC,       PLLA_OUT,  PLLM_OUT1, AUDIO_SYNC,    OSC,       0x14, 4,  0x88, 2,  0xa8, 0),
+	MUX_PG(cdev2,  OSC,       AHB_CLK,   APB_CLK,   PLLP_OUT4,     OSC,       0x14, 5,  0x88, 4,  0xa8, 2),
+	MUX_PG(crtp,   CRT,       RSVD2,     RSVD3,     RSVD4,         RSVD2,     0x20, 14, 0x98, 20, 0xa4, 24),
+	MUX_PG(csus,   PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, VI_SENSOR_CLK, PLLC_OUT1, 0x14, 6,  0x88, 6,  0xac, 24),
+	MUX_PG(dap1,   DAP1,      RSVD2,     GMI,       SDIO2,         DAP1,      0x14, 7,  0x88, 20, 0xa0, 10),
+	MUX_PG(dap2,   DAP2,      TWC,       RSVD3,     GMI,           DAP2,      0x14, 8,  0x88, 22, 0xa0, 12),
+	MUX_PG(dap3,   DAP3,      RSVD2,     RSVD3,     RSVD4,         DAP3,      0x14, 9,  0x88, 24, 0xa0, 14),
+	MUX_PG(dap4,   DAP4,      RSVD2,     GMI,       RSVD4,         DAP4,      0x14, 10, 0x88, 26, 0xa0, 16),
+	MUX_PG(ddc,    I2C2,      RSVD2,     RSVD3,     RSVD4,         RSVD4,     0x18, 31, 0x88, 0,  0xb0, 28),
+	MUX_PG(dta,    RSVD1,     SDIO2,     VI,        RSVD4,         RSVD4,     0x14, 11, 0x84, 20, 0xa0, 18),
+	MUX_PG(dtb,    RSVD1,     RSVD2,     VI,        SPI1,          RSVD1,     0x14, 12, 0x84, 22, 0xa0, 20),
+	MUX_PG(dtc,    RSVD1,     RSVD2,     VI,        RSVD4,         RSVD1,     0x14, 13, 0x84, 26, 0xa0, 22),
+	MUX_PG(dtd,    RSVD1,     SDIO2,     VI,        RSVD4,         RSVD1,     0x14, 14, 0x84, 28, 0xa0, 24),
+	MUX_PG(dte,    RSVD1,     RSVD2,     VI,        SPI1,          RSVD1,     0x14, 15, 0x84, 30, 0xa0, 26),
+	MUX_PG(dtf,    I2C3,      RSVD2,     VI,        RSVD4,         RSVD4,     0x20, 12, 0x98, 30, 0xa0, 28),
+	MUX_PG(gma,    UARTE,     SPI3,      GMI,       SDIO4,         SPI3,      0x14, 28, 0x84, 0,  0xb0, 20),
+	MUX_PG(gmb,    IDE,       NAND,      GMI,       GMI_INT,       GMI,       0x18, 29, 0x88, 28, 0xb0, 22),
+	MUX_PG(gmc,    UARTD,     SPI4,      GMI,       SFLASH,        SPI4,      0x14, 29, 0x84, 2,  0xb0, 24),
+	MUX_PG(gmd,    RSVD1,     NAND,      GMI,       SFLASH,        GMI,       0x18, 30, 0x88, 30, 0xb0, 26),
+	MUX_PG(gme,    RSVD1,     DAP5,      GMI,       SDIO4,         GMI,       0x18, 0,  0x8c, 0,  0xa8, 24),
+	MUX_PG(gpu,    PWM,       UARTA,     GMI,       RSVD4,         RSVD4,     0x14, 16, 0x8c, 4,  0xa4, 20),
+	MUX_PG(gpu7,   RTCK,      RSVD2,     RSVD3,     RSVD4,         RTCK,      0x20, 11, 0x98, 28, 0xa4, 6),
+	MUX_PG(gpv,    PCIE,      RSVD2,     RSVD3,     RSVD4,         PCIE,      0x14, 17, 0x8c, 2,  0xa0, 30),
+	MUX_PG(hdint,  HDMI,      RSVD2,     RSVD3,     RSVD4,         HDMI,      0x1c, 23, 0x84, 4,  -1,   -1),
+	MUX_PG(i2cp,   I2CP,      RSVD2,     RSVD3,     RSVD4,         RSVD4,     0x14, 18, 0x88, 8,  0xa4, 2),
+	MUX_PG(irrx,   UARTA,     UARTB,     GMI,       SPI4,          UARTB,     0x14, 20, 0x88, 18, 0xa8, 22),
+	MUX_PG(irtx,   UARTA,     UARTB,     GMI,       SPI4,          UARTB,     0x14, 19, 0x88, 16, 0xa8, 20),
+	MUX_PG(kbca,   KBC,       NAND,      SDIO2,     EMC_TEST0_DLL, KBC,       0x14, 22, 0x88, 10, 0xa4, 8),
+	MUX_PG(kbcb,   KBC,       NAND,      SDIO2,     MIO,           KBC,       0x14, 21, 0x88, 12, 0xa4, 10),
+	MUX_PG(kbcc,   KBC,       NAND,      TRACE,     EMC_TEST1_DLL, KBC,       0x18, 26, 0x88, 14, 0xa4, 12),
+	MUX_PG(kbcd,   KBC,       NAND,      SDIO2,     MIO,           KBC,       0x20, 10, 0x98, 26, 0xa4, 14),
+	MUX_PG(kbce,   KBC,       NAND,      OWR,       RSVD4,         KBC,       0x14, 26, 0x80, 28, 0xb0, 2),
+	MUX_PG(kbcf,   KBC,       NAND,      TRACE,     MIO,           KBC,       0x14, 27, 0x80, 26, 0xb0, 0),
+	MUX_PG(lcsn,   DISPLAYA,  DISPLAYB,  SPI3,      RSVD4,         RSVD4,     0x1c, 31, 0x90, 12, -1,   -1),
+	MUX_PG(ld0,    DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 0,  0x94, 0,  -1,   -1),
+	MUX_PG(ld1,    DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 1,  0x94, 2,  -1,   -1),
+	MUX_PG(ld2,    DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 2,  0x94, 4,  -1,   -1),
+	MUX_PG(ld3,    DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 3,  0x94, 6,  -1,   -1),
+	MUX_PG(ld4,    DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 4,  0x94, 8,  -1,   -1),
+	MUX_PG(ld5,    DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 5,  0x94, 10, -1,   -1),
+	MUX_PG(ld6,    DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 6,  0x94, 12, -1,   -1),
+	MUX_PG(ld7,    DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 7,  0x94, 14, -1,   -1),
+	MUX_PG(ld8,    DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 8,  0x94, 16, -1,   -1),
+	MUX_PG(ld9,    DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 9,  0x94, 18, -1,   -1),
+	MUX_PG(ld10,   DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 10, 0x94, 20, -1,   -1),
+	MUX_PG(ld11,   DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 11, 0x94, 22, -1,   -1),
+	MUX_PG(ld12,   DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 12, 0x94, 24, -1,   -1),
+	MUX_PG(ld13,   DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 13, 0x94, 26, -1,   -1),
+	MUX_PG(ld14,   DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 14, 0x94, 28, -1,   -1),
+	MUX_PG(ld15,   DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 15, 0x94, 30, -1,   -1),
+	MUX_PG(ld16,   DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 16, 0x98, 0,  -1,   -1),
+	MUX_PG(ld17,   DISPLAYA,  DISPLAYB,  RSVD3,     RSVD4,         RSVD4,     0x1c, 17, 0x98, 2,  -1,   -1),
+	MUX_PG(ldc,    DISPLAYA,  DISPLAYB,  RSVD3,     RSVD4,         RSVD4,     0x1c, 30, 0x90, 14, -1,   -1),
+	MUX_PG(ldi,    DISPLAYA,  DISPLAYB,  RSVD3,     RSVD4,         RSVD4,     0x20, 6,  0x98, 16, -1,   -1),
+	MUX_PG(lhp0,   DISPLAYA,  DISPLAYB,  RSVD3,     RSVD4,         RSVD4,     0x1c, 18, 0x98, 10, -1,   -1),
+	MUX_PG(lhp1,   DISPLAYA,  DISPLAYB,  RSVD3,     RSVD4,         RSVD4,     0x1c, 19, 0x98, 4,  -1,   -1),
+	MUX_PG(lhp2,   DISPLAYA,  DISPLAYB,  RSVD3,     RSVD4,         RSVD4,     0x1c, 20, 0x98, 6,  -1,   -1),
+	MUX_PG(lhs,    DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x20, 7,  0x90, 22, -1,   -1),
+	MUX_PG(lm0,    DISPLAYA,  DISPLAYB,  SPI3,      RSVD4,         RSVD4,     0x1c, 24, 0x90, 26, -1,   -1),
+	MUX_PG(lm1,    DISPLAYA,  DISPLAYB,  RSVD3,     CRT,           RSVD3,     0x1c, 25, 0x90, 28, -1,   -1),
+	MUX_PG(lpp,    DISPLAYA,  DISPLAYB,  RSVD3,     RSVD4,         RSVD4,     0x20, 8,  0x98, 14, -1,   -1),
+	MUX_PG(lpw0,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x20, 3,  0x90, 0,  -1,   -1),
+	MUX_PG(lpw1,   DISPLAYA,  DISPLAYB,  RSVD3,     RSVD4,         RSVD4,     0x20, 4,  0x90, 2,  -1,   -1),
+	MUX_PG(lpw2,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x20, 5,  0x90, 4,  -1,   -1),
+	MUX_PG(lsc0,   DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 27, 0x90, 18, -1,   -1),
+	MUX_PG(lsc1,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x1c, 28, 0x90, 20, -1,   -1),
+	MUX_PG(lsck,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x1c, 29, 0x90, 16, -1,   -1),
+	MUX_PG(lsda,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x20, 1,  0x90, 8,  -1,   -1),
+	MUX_PG(lsdi,   DISPLAYA,  DISPLAYB,  SPI3,      RSVD4,         DISPLAYA,  0x20, 2,  0x90, 6,  -1,   -1),
+	MUX_PG(lspi,   DISPLAYA,  DISPLAYB,  XIO,       HDMI,          DISPLAYA,  0x20, 0,  0x90, 10, -1,   -1),
+	MUX_PG(lvp0,   DISPLAYA,  DISPLAYB,  RSVD3,     RSVD4,         RSVD4,     0x1c, 21, 0x90, 30, -1,   -1),
+	MUX_PG(lvp1,   DISPLAYA,  DISPLAYB,  RSVD3,     RSVD4,         RSVD4,     0x1c, 22, 0x98, 8,  -1,   -1),
+	MUX_PG(lvs,    DISPLAYA,  DISPLAYB,  XIO,       RSVD4,         RSVD4,     0x1c, 26, 0x90, 24, -1,   -1),
+	MUX_PG(owc,    OWR,       RSVD2,     RSVD3,     RSVD4,         OWR,       0x14, 31, 0x84, 8,  0xb0, 30),
+	MUX_PG(pmc,    PWR_ON,    PWR_INTR,  RSVD3,     RSVD4,         PWR_ON,    0x14, 23, 0x98, 18, -1,   -1),
+	MUX_PG(pta,    I2C2,      HDMI,      GMI,       RSVD4,         RSVD4,     0x14, 24, 0x98, 22, 0xa4, 4),
+	MUX_PG(rm,     I2C1,      RSVD2,     RSVD3,     RSVD4,         RSVD4,     0x14, 25, 0x80, 14, 0xa4, 0),
+	MUX_PG(sdb,    UARTA,     PWM,       SDIO3,     SPI2,          PWM,       0x20, 15, 0x8c, 10, -1,   -1),
+	MUX_PG(sdc,    PWM,       TWC,       SDIO3,     SPI3,          TWC,       0x18, 1,  0x8c, 12, 0xac, 28),
+	MUX_PG(sdd,    UARTA,     PWM,       SDIO3,     SPI3,          PWM,       0x18, 2,  0x8c, 14, 0xac, 30),
+	MUX_PG(sdio1,  SDIO1,     RSVD2,     UARTE,     UARTA,         RSVD2,     0x14, 30, 0x80, 30, 0xb0, 18),
+	MUX_PG(slxa,   PCIE,      SPI4,      SDIO3,     SPI2,          PCIE,      0x18, 3,  0x84, 6,  0xa4, 22),
+	MUX_PG(slxc,   SPDIF,     SPI4,      SDIO3,     SPI2,          SPI4,      0x18, 5,  0x84, 10, 0xa4, 26),
+	MUX_PG(slxd,   SPDIF,     SPI4,      SDIO3,     SPI2,          SPI4,      0x18, 6,  0x84, 12, 0xa4, 28),
+	MUX_PG(slxk,   PCIE,      SPI4,      SDIO3,     SPI2,          PCIE,      0x18, 7,  0x84, 14, 0xa4, 30),
+	MUX_PG(spdi,   SPDIF,     RSVD2,     I2C1,      SDIO2,         RSVD2,     0x18, 8,  0x8c, 8,  0xa4, 16),
+	MUX_PG(spdo,   SPDIF,     RSVD2,     I2C1,      SDIO2,         RSVD2,     0x18, 9,  0x8c, 6,  0xa4, 18),
+	MUX_PG(spia,   SPI1,      SPI2,      SPI3,      GMI,           GMI,       0x18, 10, 0x8c, 30, 0xa8, 4),
+	MUX_PG(spib,   SPI1,      SPI2,      SPI3,      GMI,           GMI,       0x18, 11, 0x8c, 28, 0xa8, 6),
+	MUX_PG(spic,   SPI1,      SPI2,      SPI3,      GMI,           GMI,       0x18, 12, 0x8c, 26, 0xa8, 8),
+	MUX_PG(spid,   SPI2,      SPI1,      SPI2_ALT,  GMI,           GMI,       0x18, 13, 0x8c, 24, 0xa8, 10),
+	MUX_PG(spie,   SPI2,      SPI1,      SPI2_ALT,  GMI,           GMI,       0x18, 14, 0x8c, 22, 0xa8, 12),
+	MUX_PG(spif,   SPI3,      SPI1,      SPI2,      RSVD4,         RSVD4,     0x18, 15, 0x8c, 20, 0xa8, 14),
+	MUX_PG(spig,   SPI3,      SPI2,      SPI2_ALT,  I2C1,          SPI2_ALT,  0x18, 16, 0x8c, 18, 0xa8, 16),
+	MUX_PG(spih,   SPI3,      SPI2,      SPI2_ALT,  I2C1,          SPI2_ALT,  0x18, 17, 0x8c, 16, 0xa8, 18),
+	MUX_PG(uaa,    SPI3,      MIPI_HS,   UARTA,     ULPI,          MIPI_HS,   0x18, 18, 0x80, 0,  0xac, 0),
+	MUX_PG(uab,    SPI2,      MIPI_HS,   UARTA,     ULPI,          MIPI_HS,   0x18, 19, 0x80, 2,  0xac, 2),
+	MUX_PG(uac,    OWR,       RSVD2,     RSVD3,     RSVD4,         RSVD4,     0x18, 20, 0x80, 4,  0xac, 4),
+	MUX_PG(uad,    IRDA,      SPDIF,     UARTA,     SPI4,          SPDIF,     0x18, 21, 0x80, 6,  0xac, 6),
+	MUX_PG(uca,    UARTC,     RSVD2,     GMI,       RSVD4,         RSVD4,     0x18, 22, 0x84, 16, 0xac, 8),
+	MUX_PG(ucb,    UARTC,     PWM,       GMI,       RSVD4,         RSVD4,     0x18, 23, 0x84, 18, 0xac, 10),
+	MUX_PG(uda,    SPI1,      RSVD2,     UARTD,     ULPI,          RSVD2,     0x20, 13, 0x80, 8,  0xb0, 16),
+	/*      pg_name, pupd_r/b */
+	PULL_PG(ck32,    0xb0, 14),
+	PULL_PG(ddrc,    0xac, 26),
+	PULL_PG(pmca,    0xb0, 4),
+	PULL_PG(pmcb,    0xb0, 6),
+	PULL_PG(pmcc,    0xb0, 8),
+	PULL_PG(pmcd,    0xb0, 10),
+	PULL_PG(pmce,    0xb0, 12),
+	PULL_PG(xm2c,    0xa8, 30),
+	PULL_PG(xm2d,    0xa8, 28),
+	PULL_PG(ls,      0xac, 20),
+	PULL_PG(lc,      0xac, 22),
+	PULL_PG(ld17_0,  0xac, 12),
+	PULL_PG(ld19_18, 0xac, 14),
+	PULL_PG(ld21_20, 0xac, 16),
+	PULL_PG(ld23_22, 0xac, 18),
+	/*     pg_name,    r */
+	DRV_PG(ao1,        0x868),
+	DRV_PG(ao2,        0x86c),
+	DRV_PG(at1,        0x870),
+	DRV_PG(at2,        0x874),
+	DRV_PG(cdev1,      0x878),
+	DRV_PG(cdev2,      0x87c),
+	DRV_PG(csus,       0x880),
+	DRV_PG(dap1,       0x884),
+	DRV_PG(dap2,       0x888),
+	DRV_PG(dap3,       0x88c),
+	DRV_PG(dap4,       0x890),
+	DRV_PG(dbg,        0x894),
+	DRV_PG(lcd1,       0x898),
+	DRV_PG(lcd2,       0x89c),
+	DRV_PG(sdmmc2,     0x8a0),
+	DRV_PG(sdmmc3,     0x8a4),
+	DRV_PG(spi,        0x8a8),
+	DRV_PG(uaa,        0x8ac),
+	DRV_PG(uab,        0x8b0),
+	DRV_PG(uart2,      0x8b4),
+	DRV_PG(uart3,      0x8b8),
+	DRV_PG(vi1,        0x8bc),
+	DRV_PG(vi2,        0x8c0),
+	/*         pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, drvup_b, slwr_b, slwr_w, slwf_b, slwf_w */
+	DRV_PG_EXT(xm2a,   0x8c4, -1, -1,  4, 14, 19, 24, 4, 28, 4),
+	DRV_PG_EXT(xm2c,   0x8c8, -1,  3, -1, 14, 19, 24, 4, 28, 4),
+	DRV_PG_EXT(xm2d,   0x8cc, -1,  3, -1, 14, 19, 24, 4, 28, 4),
+	DRV_PG_EXT(xm2clk, 0x8d0, -1, -1, -1, 14, 19, 24, 4, 28, 4),
+	/*     pg_name,    r */
+	DRV_PG(sdio1,      0x8e0),
+	DRV_PG(crt,        0x8ec),
+	DRV_PG(ddc,        0x8f0),
+	DRV_PG(gma,        0x8f4),
+	DRV_PG(gmb,        0x8f8),
+	DRV_PG(gmc,        0x8fc),
+	DRV_PG(gmd,        0x900),
+	DRV_PG(gme,        0x904),
+	DRV_PG(owr,        0x908),
+	DRV_PG(uda,        0x90c),
+};
+
+static const struct tegra_pinctrl_soc_data tegra20_pinctrl = {
+	.ngpios = NUM_GPIOS,
+	.pins = tegra20_pins,
+	.npins = ARRAY_SIZE(tegra20_pins),
+	.functions = tegra20_functions,
+	.nfunctions = ARRAY_SIZE(tegra20_functions),
+	.groups = tegra20_groups,
+	.ngroups = ARRAY_SIZE(tegra20_groups),
+};
+
+void __devinit tegra20_pinctrl_init(const struct tegra_pinctrl_soc_data **soc)
+{
+	*soc = &tegra20_pinctrl;
+}
diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/pinctrl-tegra30.c
new file mode 100644
index 0000000..4d7571d
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-tegra30.c
@@ -0,0 +1,3726 @@
+/*
+ * Pinctrl data for the NVIDIA Tegra30 pinmux
+ *
+ * Copyright (c) 2011, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "pinctrl-tegra.h"
+
+/*
+ * Most pins affected by the pinmux can also be GPIOs. Define these first.
+ * These must match how the GPIO driver names/numbers its pins.
+ */
+#define _GPIO(offset)				(offset)
+
+#define TEGRA_PIN_CLK_32K_OUT_PA0	_GPIO(0)
+#define TEGRA_PIN_UART3_CTS_N_PA1	_GPIO(1)
+#define TEGRA_PIN_DAP2_FS_PA2		_GPIO(2)
+#define TEGRA_PIN_DAP2_SCLK_PA3		_GPIO(3)
+#define TEGRA_PIN_DAP2_DIN_PA4		_GPIO(4)
+#define TEGRA_PIN_DAP2_DOUT_PA5		_GPIO(5)
+#define TEGRA_PIN_SDMMC3_CLK_PA6	_GPIO(6)
+#define TEGRA_PIN_SDMMC3_CMD_PA7	_GPIO(7)
+#define TEGRA_PIN_GMI_A17_PB0		_GPIO(8)
+#define TEGRA_PIN_GMI_A18_PB1		_GPIO(9)
+#define TEGRA_PIN_LCD_PWR0_PB2		_GPIO(10)
+#define TEGRA_PIN_LCD_PCLK_PB3		_GPIO(11)
+#define TEGRA_PIN_SDMMC3_DAT3_PB4	_GPIO(12)
+#define TEGRA_PIN_SDMMC3_DAT2_PB5	_GPIO(13)
+#define TEGRA_PIN_SDMMC3_DAT1_PB6	_GPIO(14)
+#define TEGRA_PIN_SDMMC3_DAT0_PB7	_GPIO(15)
+#define TEGRA_PIN_UART3_RTS_N_PC0	_GPIO(16)
+#define TEGRA_PIN_LCD_PWR1_PC1		_GPIO(17)
+#define TEGRA_PIN_UART2_TXD_PC2		_GPIO(18)
+#define TEGRA_PIN_UART2_RXD_PC3		_GPIO(19)
+#define TEGRA_PIN_GEN1_I2C_SCL_PC4	_GPIO(20)
+#define TEGRA_PIN_GEN1_I2C_SDA_PC5	_GPIO(21)
+#define TEGRA_PIN_LCD_PWR2_PC6		_GPIO(22)
+#define TEGRA_PIN_GMI_WP_N_PC7		_GPIO(23)
+#define TEGRA_PIN_SDMMC3_DAT5_PD0	_GPIO(24)
+#define TEGRA_PIN_SDMMC3_DAT4_PD1	_GPIO(25)
+#define TEGRA_PIN_LCD_DC1_PD2		_GPIO(26)
+#define TEGRA_PIN_SDMMC3_DAT6_PD3	_GPIO(27)
+#define TEGRA_PIN_SDMMC3_DAT7_PD4	_GPIO(28)
+#define TEGRA_PIN_VI_D1_PD5		_GPIO(29)
+#define TEGRA_PIN_VI_VSYNC_PD6		_GPIO(30)
+#define TEGRA_PIN_VI_HSYNC_PD7		_GPIO(31)
+#define TEGRA_PIN_LCD_D0_PE0		_GPIO(32)
+#define TEGRA_PIN_LCD_D1_PE1		_GPIO(33)
+#define TEGRA_PIN_LCD_D2_PE2		_GPIO(34)
+#define TEGRA_PIN_LCD_D3_PE3		_GPIO(35)
+#define TEGRA_PIN_LCD_D4_PE4		_GPIO(36)
+#define TEGRA_PIN_LCD_D5_PE5		_GPIO(37)
+#define TEGRA_PIN_LCD_D6_PE6		_GPIO(38)
+#define TEGRA_PIN_LCD_D7_PE7		_GPIO(39)
+#define TEGRA_PIN_LCD_D8_PF0		_GPIO(40)
+#define TEGRA_PIN_LCD_D9_PF1		_GPIO(41)
+#define TEGRA_PIN_LCD_D10_PF2		_GPIO(42)
+#define TEGRA_PIN_LCD_D11_PF3		_GPIO(43)
+#define TEGRA_PIN_LCD_D12_PF4		_GPIO(44)
+#define TEGRA_PIN_LCD_D13_PF5		_GPIO(45)
+#define TEGRA_PIN_LCD_D14_PF6		_GPIO(46)
+#define TEGRA_PIN_LCD_D15_PF7		_GPIO(47)
+#define TEGRA_PIN_GMI_AD0_PG0		_GPIO(48)
+#define TEGRA_PIN_GMI_AD1_PG1		_GPIO(49)
+#define TEGRA_PIN_GMI_AD2_PG2		_GPIO(50)
+#define TEGRA_PIN_GMI_AD3_PG3		_GPIO(51)
+#define TEGRA_PIN_GMI_AD4_PG4		_GPIO(52)
+#define TEGRA_PIN_GMI_AD5_PG5		_GPIO(53)
+#define TEGRA_PIN_GMI_AD6_PG6		_GPIO(54)
+#define TEGRA_PIN_GMI_AD7_PG7		_GPIO(55)
+#define TEGRA_PIN_GMI_AD8_PH0		_GPIO(56)
+#define TEGRA_PIN_GMI_AD9_PH1		_GPIO(57)
+#define TEGRA_PIN_GMI_AD10_PH2		_GPIO(58)
+#define TEGRA_PIN_GMI_AD11_PH3		_GPIO(59)
+#define TEGRA_PIN_GMI_AD12_PH4		_GPIO(60)
+#define TEGRA_PIN_GMI_AD13_PH5		_GPIO(61)
+#define TEGRA_PIN_GMI_AD14_PH6		_GPIO(62)
+#define TEGRA_PIN_GMI_AD15_PH7		_GPIO(63)
+#define TEGRA_PIN_GMI_WR_N_PI0		_GPIO(64)
+#define TEGRA_PIN_GMI_OE_N_PI1		_GPIO(65)
+#define TEGRA_PIN_GMI_DQS_PI2		_GPIO(66)
+#define TEGRA_PIN_GMI_CS6_N_PI3		_GPIO(67)
+#define TEGRA_PIN_GMI_RST_N_PI4		_GPIO(68)
+#define TEGRA_PIN_GMI_IORDY_PI5		_GPIO(69)
+#define TEGRA_PIN_GMI_CS7_N_PI6		_GPIO(70)
+#define TEGRA_PIN_GMI_WAIT_PI7		_GPIO(71)
+#define TEGRA_PIN_GMI_CS0_N_PJ0		_GPIO(72)
+#define TEGRA_PIN_LCD_DE_PJ1		_GPIO(73)
+#define TEGRA_PIN_GMI_CS1_N_PJ2		_GPIO(74)
+#define TEGRA_PIN_LCD_HSYNC_PJ3		_GPIO(75)
+#define TEGRA_PIN_LCD_VSYNC_PJ4		_GPIO(76)
+#define TEGRA_PIN_UART2_CTS_N_PJ5	_GPIO(77)
+#define TEGRA_PIN_UART2_RTS_N_PJ6	_GPIO(78)
+#define TEGRA_PIN_GMI_A16_PJ7		_GPIO(79)
+#define TEGRA_PIN_GMI_ADV_N_PK0		_GPIO(80)
+#define TEGRA_PIN_GMI_CLK_PK1		_GPIO(81)
+#define TEGRA_PIN_GMI_CS4_N_PK2		_GPIO(82)
+#define TEGRA_PIN_GMI_CS2_N_PK3		_GPIO(83)
+#define TEGRA_PIN_GMI_CS3_N_PK4		_GPIO(84)
+#define TEGRA_PIN_SPDIF_OUT_PK5		_GPIO(85)
+#define TEGRA_PIN_SPDIF_IN_PK6		_GPIO(86)
+#define TEGRA_PIN_GMI_A19_PK7		_GPIO(87)
+#define TEGRA_PIN_VI_D2_PL0		_GPIO(88)
+#define TEGRA_PIN_VI_D3_PL1		_GPIO(89)
+#define TEGRA_PIN_VI_D4_PL2		_GPIO(90)
+#define TEGRA_PIN_VI_D5_PL3		_GPIO(91)
+#define TEGRA_PIN_VI_D6_PL4		_GPIO(92)
+#define TEGRA_PIN_VI_D7_PL5		_GPIO(93)
+#define TEGRA_PIN_VI_D8_PL6		_GPIO(94)
+#define TEGRA_PIN_VI_D9_PL7		_GPIO(95)
+#define TEGRA_PIN_LCD_D16_PM0		_GPIO(96)
+#define TEGRA_PIN_LCD_D17_PM1		_GPIO(97)
+#define TEGRA_PIN_LCD_D18_PM2		_GPIO(98)
+#define TEGRA_PIN_LCD_D19_PM3		_GPIO(99)
+#define TEGRA_PIN_LCD_D20_PM4		_GPIO(100)
+#define TEGRA_PIN_LCD_D21_PM5		_GPIO(101)
+#define TEGRA_PIN_LCD_D22_PM6		_GPIO(102)
+#define TEGRA_PIN_LCD_D23_PM7		_GPIO(103)
+#define TEGRA_PIN_DAP1_FS_PN0		_GPIO(104)
+#define TEGRA_PIN_DAP1_DIN_PN1		_GPIO(105)
+#define TEGRA_PIN_DAP1_DOUT_PN2		_GPIO(106)
+#define TEGRA_PIN_DAP1_SCLK_PN3		_GPIO(107)
+#define TEGRA_PIN_LCD_CS0_N_PN4		_GPIO(108)
+#define TEGRA_PIN_LCD_SDOUT_PN5		_GPIO(109)
+#define TEGRA_PIN_LCD_DC0_PN6		_GPIO(110)
+#define TEGRA_PIN_HDMI_INT_PN7		_GPIO(111)
+#define TEGRA_PIN_ULPI_DATA7_PO0	_GPIO(112)
+#define TEGRA_PIN_ULPI_DATA0_PO1	_GPIO(113)
+#define TEGRA_PIN_ULPI_DATA1_PO2	_GPIO(114)
+#define TEGRA_PIN_ULPI_DATA2_PO3	_GPIO(115)
+#define TEGRA_PIN_ULPI_DATA3_PO4	_GPIO(116)
+#define TEGRA_PIN_ULPI_DATA4_PO5	_GPIO(117)
+#define TEGRA_PIN_ULPI_DATA5_PO6	_GPIO(118)
+#define TEGRA_PIN_ULPI_DATA6_PO7	_GPIO(119)
+#define TEGRA_PIN_DAP3_FS_PP0		_GPIO(120)
+#define TEGRA_PIN_DAP3_DIN_PP1		_GPIO(121)
+#define TEGRA_PIN_DAP3_DOUT_PP2		_GPIO(122)
+#define TEGRA_PIN_DAP3_SCLK_PP3		_GPIO(123)
+#define TEGRA_PIN_DAP4_FS_PP4		_GPIO(124)
+#define TEGRA_PIN_DAP4_DIN_PP5		_GPIO(125)
+#define TEGRA_PIN_DAP4_DOUT_PP6		_GPIO(126)
+#define TEGRA_PIN_DAP4_SCLK_PP7		_GPIO(127)
+#define TEGRA_PIN_KB_COL0_PQ0		_GPIO(128)
+#define TEGRA_PIN_KB_COL1_PQ1		_GPIO(129)
+#define TEGRA_PIN_KB_COL2_PQ2		_GPIO(130)
+#define TEGRA_PIN_KB_COL3_PQ3		_GPIO(131)
+#define TEGRA_PIN_KB_COL4_PQ4		_GPIO(132)
+#define TEGRA_PIN_KB_COL5_PQ5		_GPIO(133)
+#define TEGRA_PIN_KB_COL6_PQ6		_GPIO(134)
+#define TEGRA_PIN_KB_COL7_PQ7		_GPIO(135)
+#define TEGRA_PIN_KB_ROW0_PR0		_GPIO(136)
+#define TEGRA_PIN_KB_ROW1_PR1		_GPIO(137)
+#define TEGRA_PIN_KB_ROW2_PR2		_GPIO(138)
+#define TEGRA_PIN_KB_ROW3_PR3		_GPIO(139)
+#define TEGRA_PIN_KB_ROW4_PR4		_GPIO(140)
+#define TEGRA_PIN_KB_ROW5_PR5		_GPIO(141)
+#define TEGRA_PIN_KB_ROW6_PR6		_GPIO(142)
+#define TEGRA_PIN_KB_ROW7_PR7		_GPIO(143)
+#define TEGRA_PIN_KB_ROW8_PS0		_GPIO(144)
+#define TEGRA_PIN_KB_ROW9_PS1		_GPIO(145)
+#define TEGRA_PIN_KB_ROW10_PS2		_GPIO(146)
+#define TEGRA_PIN_KB_ROW11_PS3		_GPIO(147)
+#define TEGRA_PIN_KB_ROW12_PS4		_GPIO(148)
+#define TEGRA_PIN_KB_ROW13_PS5		_GPIO(149)
+#define TEGRA_PIN_KB_ROW14_PS6		_GPIO(150)
+#define TEGRA_PIN_KB_ROW15_PS7		_GPIO(151)
+#define TEGRA_PIN_VI_PCLK_PT0		_GPIO(152)
+#define TEGRA_PIN_VI_MCLK_PT1		_GPIO(153)
+#define TEGRA_PIN_VI_D10_PT2		_GPIO(154)
+#define TEGRA_PIN_VI_D11_PT3		_GPIO(155)
+#define TEGRA_PIN_VI_D0_PT4		_GPIO(156)
+#define TEGRA_PIN_GEN2_I2C_SCL_PT5	_GPIO(157)
+#define TEGRA_PIN_GEN2_I2C_SDA_PT6	_GPIO(158)
+#define TEGRA_PIN_SDMMC4_CMD_PT7	_GPIO(159)
+#define TEGRA_PIN_PU0			_GPIO(160)
+#define TEGRA_PIN_PU1			_GPIO(161)
+#define TEGRA_PIN_PU2			_GPIO(162)
+#define TEGRA_PIN_PU3			_GPIO(163)
+#define TEGRA_PIN_PU4			_GPIO(164)
+#define TEGRA_PIN_PU5			_GPIO(165)
+#define TEGRA_PIN_PU6			_GPIO(166)
+#define TEGRA_PIN_JTAG_RTCK_PU7		_GPIO(167)
+#define TEGRA_PIN_PV0			_GPIO(168)
+#define TEGRA_PIN_PV1			_GPIO(169)
+#define TEGRA_PIN_PV2			_GPIO(170)
+#define TEGRA_PIN_PV3			_GPIO(171)
+#define TEGRA_PIN_DDC_SCL_PV4		_GPIO(172)
+#define TEGRA_PIN_DDC_SDA_PV5		_GPIO(173)
+#define TEGRA_PIN_CRT_HSYNC_PV6		_GPIO(174)
+#define TEGRA_PIN_CRT_VSYNC_PV7		_GPIO(175)
+#define TEGRA_PIN_LCD_CS1_N_PW0		_GPIO(176)
+#define TEGRA_PIN_LCD_M1_PW1		_GPIO(177)
+#define TEGRA_PIN_SPI2_CS1_N_PW2	_GPIO(178)
+#define TEGRA_PIN_SPI2_CS2_N_PW3	_GPIO(179)
+#define TEGRA_PIN_CLK1_OUT_PW4		_GPIO(180)
+#define TEGRA_PIN_CLK2_OUT_PW5		_GPIO(181)
+#define TEGRA_PIN_UART3_TXD_PW6		_GPIO(182)
+#define TEGRA_PIN_UART3_RXD_PW7		_GPIO(183)
+#define TEGRA_PIN_SPI2_MOSI_PX0		_GPIO(184)
+#define TEGRA_PIN_SPI2_MISO_PX1		_GPIO(185)
+#define TEGRA_PIN_SPI2_SCK_PX2		_GPIO(186)
+#define TEGRA_PIN_SPI2_CS0_N_PX3	_GPIO(187)
+#define TEGRA_PIN_SPI1_MOSI_PX4		_GPIO(188)
+#define TEGRA_PIN_SPI1_SCK_PX5		_GPIO(189)
+#define TEGRA_PIN_SPI1_CS0_N_PX6	_GPIO(190)
+#define TEGRA_PIN_SPI1_MISO_PX7		_GPIO(191)
+#define TEGRA_PIN_ULPI_CLK_PY0		_GPIO(192)
+#define TEGRA_PIN_ULPI_DIR_PY1		_GPIO(193)
+#define TEGRA_PIN_ULPI_NXT_PY2		_GPIO(194)
+#define TEGRA_PIN_ULPI_STP_PY3		_GPIO(195)
+#define TEGRA_PIN_SDMMC1_DAT3_PY4	_GPIO(196)
+#define TEGRA_PIN_SDMMC1_DAT2_PY5	_GPIO(197)
+#define TEGRA_PIN_SDMMC1_DAT1_PY6	_GPIO(198)
+#define TEGRA_PIN_SDMMC1_DAT0_PY7	_GPIO(199)
+#define TEGRA_PIN_SDMMC1_CLK_PZ0	_GPIO(200)
+#define TEGRA_PIN_SDMMC1_CMD_PZ1	_GPIO(201)
+#define TEGRA_PIN_LCD_SDIN_PZ2		_GPIO(202)
+#define TEGRA_PIN_LCD_WR_N_PZ3		_GPIO(203)
+#define TEGRA_PIN_LCD_SCK_PZ4		_GPIO(204)
+#define TEGRA_PIN_SYS_CLK_REQ_PZ5	_GPIO(205)
+#define TEGRA_PIN_PWR_I2C_SCL_PZ6	_GPIO(206)
+#define TEGRA_PIN_PWR_I2C_SDA_PZ7	_GPIO(207)
+#define TEGRA_PIN_SDMMC4_DAT0_PAA0	_GPIO(208)
+#define TEGRA_PIN_SDMMC4_DAT1_PAA1	_GPIO(209)
+#define TEGRA_PIN_SDMMC4_DAT2_PAA2	_GPIO(210)
+#define TEGRA_PIN_SDMMC4_DAT3_PAA3	_GPIO(211)
+#define TEGRA_PIN_SDMMC4_DAT4_PAA4	_GPIO(212)
+#define TEGRA_PIN_SDMMC4_DAT5_PAA5	_GPIO(213)
+#define TEGRA_PIN_SDMMC4_DAT6_PAA6	_GPIO(214)
+#define TEGRA_PIN_SDMMC4_DAT7_PAA7	_GPIO(215)
+#define TEGRA_PIN_PBB0			_GPIO(216)
+#define TEGRA_PIN_CAM_I2C_SCL_PBB1	_GPIO(217)
+#define TEGRA_PIN_CAM_I2C_SDA_PBB2	_GPIO(218)
+#define TEGRA_PIN_PBB3			_GPIO(219)
+#define TEGRA_PIN_PBB4			_GPIO(220)
+#define TEGRA_PIN_PBB5			_GPIO(221)
+#define TEGRA_PIN_PBB6			_GPIO(222)
+#define TEGRA_PIN_PBB7			_GPIO(223)
+#define TEGRA_PIN_CAM_MCLK_PCC0		_GPIO(224)
+#define TEGRA_PIN_PCC1			_GPIO(225)
+#define TEGRA_PIN_PCC2			_GPIO(226)
+#define TEGRA_PIN_SDMMC4_RST_N_PCC3	_GPIO(227)
+#define TEGRA_PIN_SDMMC4_CLK_PCC4	_GPIO(228)
+#define TEGRA_PIN_CLK2_REQ_PCC5		_GPIO(229)
+#define TEGRA_PIN_PEX_L2_RST_N_PCC6	_GPIO(230)
+#define TEGRA_PIN_PEX_L2_CLKREQ_N_PCC7	_GPIO(231)
+#define TEGRA_PIN_PEX_L0_PRSNT_N_PDD0	_GPIO(232)
+#define TEGRA_PIN_PEX_L0_RST_N_PDD1	_GPIO(233)
+#define TEGRA_PIN_PEX_L0_CLKREQ_N_PDD2	_GPIO(234)
+#define TEGRA_PIN_PEX_WAKE_N_PDD3	_GPIO(235)
+#define TEGRA_PIN_PEX_L1_PRSNT_N_PDD4	_GPIO(236)
+#define TEGRA_PIN_PEX_L1_RST_N_PDD5	_GPIO(237)
+#define TEGRA_PIN_PEX_L1_CLKREQ_N_PDD6	_GPIO(238)
+#define TEGRA_PIN_PEX_L2_PRSNT_N_PDD7	_GPIO(239)
+#define TEGRA_PIN_CLK3_OUT_PEE0		_GPIO(240)
+#define TEGRA_PIN_CLK3_REQ_PEE1		_GPIO(241)
+#define TEGRA_PIN_CLK1_REQ_PEE2		_GPIO(242)
+#define TEGRA_PIN_HDMI_CEC_PEE3		_GPIO(243)
+#define TEGRA_PIN_PEE4			_GPIO(244)
+#define TEGRA_PIN_PEE5			_GPIO(245)
+#define TEGRA_PIN_PEE6			_GPIO(246)
+#define TEGRA_PIN_PEE7			_GPIO(247)
+
+/* All non-GPIO pins follow */
+#define NUM_GPIOS				(TEGRA_PIN_PEE7 + 1)
+#define _PIN(offset)				(NUM_GPIOS + (offset))
+
+/* Non-GPIO pins */
+#define TEGRA_PIN_CLK_32K_IN		_PIN(0)
+#define TEGRA_PIN_CORE_PWR_REQ		_PIN(1)
+#define TEGRA_PIN_CPU_PWR_REQ		_PIN(2)
+#define TEGRA_PIN_JTAG_TCK		_PIN(3)
+#define TEGRA_PIN_JTAG_TDI		_PIN(4)
+#define TEGRA_PIN_JTAG_TDO		_PIN(5)
+#define TEGRA_PIN_JTAG_TMS		_PIN(6)
+#define TEGRA_PIN_JTAG_TRST_N		_PIN(7)
+#define TEGRA_PIN_OWR			_PIN(8)
+#define TEGRA_PIN_PWR_INT_N		_PIN(9)
+#define TEGRA_PIN_SYS_RESET_N		_PIN(10)
+#define TEGRA_PIN_TEST_MODE_EN		_PIN(11)
+
+static const struct pinctrl_pin_desc tegra30_pins[] = {
+	PINCTRL_PIN(TEGRA_PIN_CLK_32K_OUT_PA0, "CLK_32K_OUT PA0"),
+	PINCTRL_PIN(TEGRA_PIN_UART3_CTS_N_PA1, "UART3_CTS_N PA1"),
+	PINCTRL_PIN(TEGRA_PIN_DAP2_FS_PA2, "DAP2_FS PA2"),
+	PINCTRL_PIN(TEGRA_PIN_DAP2_SCLK_PA3, "DAP2_SCLK PA3"),
+	PINCTRL_PIN(TEGRA_PIN_DAP2_DIN_PA4, "DAP2_DIN PA4"),
+	PINCTRL_PIN(TEGRA_PIN_DAP2_DOUT_PA5, "DAP2_DOUT PA5"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_PA6, "SDMMC3_CLK PA6"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_CMD_PA7, "SDMMC3_CMD PA7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_A17_PB0, "GMI_A17 PB0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_A18_PB1, "GMI_A18 PB1"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_PWR0_PB2, "LCD_PWR0 PB2"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_PCLK_PB3, "LCD_PCLK PB3"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT3_PB4, "SDMMC3_DAT3 PB4"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT2_PB5, "SDMMC3_DAT2 PB5"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT1_PB6, "SDMMC3_DAT1 PB6"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT0_PB7, "SDMMC3_DAT0 PB7"),
+	PINCTRL_PIN(TEGRA_PIN_UART3_RTS_N_PC0, "UART3_RTS_N PC0"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_PWR1_PC1, "LCD_PWR1 PC1"),
+	PINCTRL_PIN(TEGRA_PIN_UART2_TXD_PC2, "UART2_TXD PC2"),
+	PINCTRL_PIN(TEGRA_PIN_UART2_RXD_PC3, "UART2_RXD PC3"),
+	PINCTRL_PIN(TEGRA_PIN_GEN1_I2C_SCL_PC4, "GEN1_I2C_SCL PC4"),
+	PINCTRL_PIN(TEGRA_PIN_GEN1_I2C_SDA_PC5, "GEN1_I2C_SDA PC5"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_PWR2_PC6, "LCD_PWR2 PC6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_WP_N_PC7, "GMI_WP_N PC7"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT5_PD0, "SDMMC3_DAT5 PD0"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT4_PD1, "SDMMC3_DAT4 PD1"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_DC1_PD2, "LCD_DC1 PD2"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT6_PD3, "SDMMC3_DAT6 PD3"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT7_PD4, "SDMMC3_DAT7 PD4"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D1_PD5, "VI_D1 PD5"),
+	PINCTRL_PIN(TEGRA_PIN_VI_VSYNC_PD6, "VI_VSYNC PD6"),
+	PINCTRL_PIN(TEGRA_PIN_VI_HSYNC_PD7, "VI_HSYNC PD7"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D0_PE0, "LCD_D0 PE0"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D1_PE1, "LCD_D1 PE1"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D2_PE2, "LCD_D2 PE2"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D3_PE3, "LCD_D3 PE3"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D4_PE4, "LCD_D4 PE4"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D5_PE5, "LCD_D5 PE5"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D6_PE6, "LCD_D6 PE6"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D7_PE7, "LCD_D7 PE7"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D8_PF0, "LCD_D8 PF0"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D9_PF1, "LCD_D9 PF1"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D10_PF2, "LCD_D10 PF2"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D11_PF3, "LCD_D11 PF3"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D12_PF4, "LCD_D12 PF4"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D13_PF5, "LCD_D13 PF5"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D14_PF6, "LCD_D14 PF6"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D15_PF7, "LCD_D15 PF7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD0_PG0, "GMI_AD0 PG0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD1_PG1, "GMI_AD1 PG1"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD2_PG2, "GMI_AD2 PG2"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD3_PG3, "GMI_AD3 PG3"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD4_PG4, "GMI_AD4 PG4"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD5_PG5, "GMI_AD5 PG5"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD6_PG6, "GMI_AD6 PG6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD7_PG7, "GMI_AD7 PG7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD8_PH0, "GMI_AD8 PH0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD9_PH1, "GMI_AD9 PH1"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD10_PH2, "GMI_AD10 PH2"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD11_PH3, "GMI_AD11 PH3"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD12_PH4, "GMI_AD12 PH4"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD13_PH5, "GMI_AD13 PH5"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD14_PH6, "GMI_AD14 PH6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD15_PH7, "GMI_AD15 PH7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_WR_N_PI0, "GMI_WR_N PI0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_OE_N_PI1, "GMI_OE_N PI1"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_DQS_PI2, "GMI_DQS PI2"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS6_N_PI3, "GMI_CS6_N PI3"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_RST_N_PI4, "GMI_RST_N PI4"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_IORDY_PI5, "GMI_IORDY PI5"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS7_N_PI6, "GMI_CS7_N PI6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_WAIT_PI7, "GMI_WAIT PI7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS0_N_PJ0, "GMI_CS0_N PJ0"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_DE_PJ1, "LCD_DE PJ1"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS1_N_PJ2, "GMI_CS1_N PJ2"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_HSYNC_PJ3, "LCD_HSYNC PJ3"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_VSYNC_PJ4, "LCD_VSYNC PJ4"),
+	PINCTRL_PIN(TEGRA_PIN_UART2_CTS_N_PJ5, "UART2_CTS_N PJ5"),
+	PINCTRL_PIN(TEGRA_PIN_UART2_RTS_N_PJ6, "UART2_RTS_N PJ6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_A16_PJ7, "GMI_A16 PJ7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_ADV_N_PK0, "GMI_ADV_N PK0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CLK_PK1, "GMI_CLK PK1"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS4_N_PK2, "GMI_CS4_N PK2"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS2_N_PK3, "GMI_CS2_N PK3"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS3_N_PK4, "GMI_CS3_N PK4"),
+	PINCTRL_PIN(TEGRA_PIN_SPDIF_OUT_PK5, "SPDIF_OUT PK5"),
+	PINCTRL_PIN(TEGRA_PIN_SPDIF_IN_PK6, "SPDIF_IN PK6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_A19_PK7, "GMI_A19 PK7"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D2_PL0, "VI_D2 PL0"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D3_PL1, "VI_D3 PL1"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D4_PL2, "VI_D4 PL2"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D5_PL3, "VI_D5 PL3"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D6_PL4, "VI_D6 PL4"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D7_PL5, "VI_D7 PL5"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D8_PL6, "VI_D8 PL6"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D9_PL7, "VI_D9 PL7"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D16_PM0, "LCD_D16 PM0"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D17_PM1, "LCD_D17 PM1"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D18_PM2, "LCD_D18 PM2"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D19_PM3, "LCD_D19 PM3"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D20_PM4, "LCD_D20 PM4"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D21_PM5, "LCD_D21 PM5"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D22_PM6, "LCD_D22 PM6"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_D23_PM7, "LCD_D23 PM7"),
+	PINCTRL_PIN(TEGRA_PIN_DAP1_FS_PN0, "DAP1_FS PN0"),
+	PINCTRL_PIN(TEGRA_PIN_DAP1_DIN_PN1, "DAP1_DIN PN1"),
+	PINCTRL_PIN(TEGRA_PIN_DAP1_DOUT_PN2, "DAP1_DOUT PN2"),
+	PINCTRL_PIN(TEGRA_PIN_DAP1_SCLK_PN3, "DAP1_SCLK PN3"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_CS0_N_PN4, "LCD_CS0_N PN4"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_SDOUT_PN5, "LCD_SDOUT PN5"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_DC0_PN6, "LCD_DC0 PN6"),
+	PINCTRL_PIN(TEGRA_PIN_HDMI_INT_PN7, "HDMI_INT PN7"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA7_PO0, "ULPI_DATA7 PO0"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA0_PO1, "ULPI_DATA0 PO1"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA1_PO2, "ULPI_DATA1 PO2"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA2_PO3, "ULPI_DATA2 PO3"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA3_PO4, "ULPI_DATA3 PO4"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA4_PO5, "ULPI_DATA4 PO5"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA5_PO6, "ULPI_DATA5 PO6"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA6_PO7, "ULPI_DATA6 PO7"),
+	PINCTRL_PIN(TEGRA_PIN_DAP3_FS_PP0, "DAP3_FS PP0"),
+	PINCTRL_PIN(TEGRA_PIN_DAP3_DIN_PP1, "DAP3_DIN PP1"),
+	PINCTRL_PIN(TEGRA_PIN_DAP3_DOUT_PP2, "DAP3_DOUT PP2"),
+	PINCTRL_PIN(TEGRA_PIN_DAP3_SCLK_PP3, "DAP3_SCLK PP3"),
+	PINCTRL_PIN(TEGRA_PIN_DAP4_FS_PP4, "DAP4_FS PP4"),
+	PINCTRL_PIN(TEGRA_PIN_DAP4_DIN_PP5, "DAP4_DIN PP5"),
+	PINCTRL_PIN(TEGRA_PIN_DAP4_DOUT_PP6, "DAP4_DOUT PP6"),
+	PINCTRL_PIN(TEGRA_PIN_DAP4_SCLK_PP7, "DAP4_SCLK PP7"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL0_PQ0, "KB_COL0 PQ0"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL1_PQ1, "KB_COL1 PQ1"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL2_PQ2, "KB_COL2 PQ2"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL3_PQ3, "KB_COL3 PQ3"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL4_PQ4, "KB_COL4 PQ4"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL5_PQ5, "KB_COL5 PQ5"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL6_PQ6, "KB_COL6 PQ6"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL7_PQ7, "KB_COL7 PQ7"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW0_PR0, "KB_ROW0 PR0"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW1_PR1, "KB_ROW1 PR1"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW2_PR2, "KB_ROW2 PR2"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW3_PR3, "KB_ROW3 PR3"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW4_PR4, "KB_ROW4 PR4"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW5_PR5, "KB_ROW5 PR5"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW6_PR6, "KB_ROW6 PR6"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW7_PR7, "KB_ROW7 PR7"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW8_PS0, "KB_ROW8 PS0"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW9_PS1, "KB_ROW9 PS1"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW10_PS2, "KB_ROW10 PS2"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW11_PS3, "KB_ROW11 PS3"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW12_PS4, "KB_ROW12 PS4"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW13_PS5, "KB_ROW13 PS5"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW14_PS6, "KB_ROW14 PS6"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW15_PS7, "KB_ROW15 PS7"),
+	PINCTRL_PIN(TEGRA_PIN_VI_PCLK_PT0, "VI_PCLK PT0"),
+	PINCTRL_PIN(TEGRA_PIN_VI_MCLK_PT1, "VI_MCLK PT1"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D10_PT2, "VI_D10 PT2"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D11_PT3, "VI_D11 PT3"),
+	PINCTRL_PIN(TEGRA_PIN_VI_D0_PT4, "VI_D0 PT4"),
+	PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SCL_PT5, "GEN2_I2C_SCL PT5"),
+	PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SDA_PT6, "GEN2_I2C_SDA PT6"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_CMD_PT7, "SDMMC4_CMD PT7"),
+	PINCTRL_PIN(TEGRA_PIN_PU0, "PU0"),
+	PINCTRL_PIN(TEGRA_PIN_PU1, "PU1"),
+	PINCTRL_PIN(TEGRA_PIN_PU2, "PU2"),
+	PINCTRL_PIN(TEGRA_PIN_PU3, "PU3"),
+	PINCTRL_PIN(TEGRA_PIN_PU4, "PU4"),
+	PINCTRL_PIN(TEGRA_PIN_PU5, "PU5"),
+	PINCTRL_PIN(TEGRA_PIN_PU6, "PU6"),
+	PINCTRL_PIN(TEGRA_PIN_JTAG_RTCK_PU7, "JTAG_RTCK PU7"),
+	PINCTRL_PIN(TEGRA_PIN_PV0, "PV0"),
+	PINCTRL_PIN(TEGRA_PIN_PV1, "PV1"),
+	PINCTRL_PIN(TEGRA_PIN_PV2, "PV2"),
+	PINCTRL_PIN(TEGRA_PIN_PV3, "PV3"),
+	PINCTRL_PIN(TEGRA_PIN_DDC_SCL_PV4, "DDC_SCL PV4"),
+	PINCTRL_PIN(TEGRA_PIN_DDC_SDA_PV5, "DDC_SDA PV5"),
+	PINCTRL_PIN(TEGRA_PIN_CRT_HSYNC_PV6, "CRT_HSYNC PV6"),
+	PINCTRL_PIN(TEGRA_PIN_CRT_VSYNC_PV7, "CRT_VSYNC PV7"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_CS1_N_PW0, "LCD_CS1_N PW0"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_M1_PW1, "LCD_M1 PW1"),
+	PINCTRL_PIN(TEGRA_PIN_SPI2_CS1_N_PW2, "SPI2_CS1_N PW2"),
+	PINCTRL_PIN(TEGRA_PIN_SPI2_CS2_N_PW3, "SPI2_CS2_N PW3"),
+	PINCTRL_PIN(TEGRA_PIN_CLK1_OUT_PW4, "CLK1_OUT PW4"),
+	PINCTRL_PIN(TEGRA_PIN_CLK2_OUT_PW5, "CLK2_OUT PW5"),
+	PINCTRL_PIN(TEGRA_PIN_UART3_TXD_PW6, "UART3_TXD PW6"),
+	PINCTRL_PIN(TEGRA_PIN_UART3_RXD_PW7, "UART3_RXD PW7"),
+	PINCTRL_PIN(TEGRA_PIN_SPI2_MOSI_PX0, "SPI2_MOSI PX0"),
+	PINCTRL_PIN(TEGRA_PIN_SPI2_MISO_PX1, "SPI2_MISO PX1"),
+	PINCTRL_PIN(TEGRA_PIN_SPI2_SCK_PX2, "SPI2_SCK PX2"),
+	PINCTRL_PIN(TEGRA_PIN_SPI2_CS0_N_PX3, "SPI2_CS0_N PX3"),
+	PINCTRL_PIN(TEGRA_PIN_SPI1_MOSI_PX4, "SPI1_MOSI PX4"),
+	PINCTRL_PIN(TEGRA_PIN_SPI1_SCK_PX5, "SPI1_SCK PX5"),
+	PINCTRL_PIN(TEGRA_PIN_SPI1_CS0_N_PX6, "SPI1_CS0_N PX6"),
+	PINCTRL_PIN(TEGRA_PIN_SPI1_MISO_PX7, "SPI1_MISO PX7"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_CLK_PY0, "ULPI_CLK PY0"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DIR_PY1, "ULPI_DIR PY1"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_NXT_PY2, "ULPI_NXT PY2"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_STP_PY3, "ULPI_STP PY3"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT3_PY4, "SDMMC1_DAT3 PY4"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT2_PY5, "SDMMC1_DAT2 PY5"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT1_PY6, "SDMMC1_DAT1 PY6"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT0_PY7, "SDMMC1_DAT0 PY7"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC1_CLK_PZ0, "SDMMC1_CLK PZ0"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC1_CMD_PZ1, "SDMMC1_CMD PZ1"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_SDIN_PZ2, "LCD_SDIN PZ2"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_WR_N_PZ3, "LCD_WR_N PZ3"),
+	PINCTRL_PIN(TEGRA_PIN_LCD_SCK_PZ4, "LCD_SCK PZ4"),
+	PINCTRL_PIN(TEGRA_PIN_SYS_CLK_REQ_PZ5, "SYS_CLK_REQ PZ5"),
+	PINCTRL_PIN(TEGRA_PIN_PWR_I2C_SCL_PZ6, "PWR_I2C_SCL PZ6"),
+	PINCTRL_PIN(TEGRA_PIN_PWR_I2C_SDA_PZ7, "PWR_I2C_SDA PZ7"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT0_PAA0, "SDMMC4_DAT0 PAA0"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT1_PAA1, "SDMMC4_DAT1 PAA1"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT2_PAA2, "SDMMC4_DAT2 PAA2"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT3_PAA3, "SDMMC4_DAT3 PAA3"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT4_PAA4, "SDMMC4_DAT4 PAA4"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT5_PAA5, "SDMMC4_DAT5 PAA5"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT6_PAA6, "SDMMC4_DAT6 PAA6"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT7_PAA7, "SDMMC4_DAT7 PAA7"),
+	PINCTRL_PIN(TEGRA_PIN_PBB0, "PBB0"),
+	PINCTRL_PIN(TEGRA_PIN_CAM_I2C_SCL_PBB1, "CAM_I2C_SCL PBB1"),
+	PINCTRL_PIN(TEGRA_PIN_CAM_I2C_SDA_PBB2, "CAM_I2C_SDA PBB2"),
+	PINCTRL_PIN(TEGRA_PIN_PBB3, "PBB3"),
+	PINCTRL_PIN(TEGRA_PIN_PBB4, "PBB4"),
+	PINCTRL_PIN(TEGRA_PIN_PBB5, "PBB5"),
+	PINCTRL_PIN(TEGRA_PIN_PBB6, "PBB6"),
+	PINCTRL_PIN(TEGRA_PIN_PBB7, "PBB7"),
+	PINCTRL_PIN(TEGRA_PIN_CAM_MCLK_PCC0, "CAM_MCLK PCC0"),
+	PINCTRL_PIN(TEGRA_PIN_PCC1, "PCC1"),
+	PINCTRL_PIN(TEGRA_PIN_PCC2, "PCC2"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_RST_N_PCC3, "SDMMC4_RST_N PCC3"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_CLK_PCC4, "SDMMC4_CLK PCC4"),
+	PINCTRL_PIN(TEGRA_PIN_CLK2_REQ_PCC5, "CLK2_REQ PCC5"),
+	PINCTRL_PIN(TEGRA_PIN_PEX_L2_RST_N_PCC6, "PEX_L2_RST_N PCC6"),
+	PINCTRL_PIN(TEGRA_PIN_PEX_L2_CLKREQ_N_PCC7, "PEX_L2_CLKREQ_N PCC7"),
+	PINCTRL_PIN(TEGRA_PIN_PEX_L0_PRSNT_N_PDD0, "PEX_L0_PRSNT_N PDD0"),
+	PINCTRL_PIN(TEGRA_PIN_PEX_L0_RST_N_PDD1, "PEX_L0_RST_N PDD1"),
+	PINCTRL_PIN(TEGRA_PIN_PEX_L0_CLKREQ_N_PDD2, "PEX_L0_CLKREQ_N PDD2"),
+	PINCTRL_PIN(TEGRA_PIN_PEX_WAKE_N_PDD3, "PEX_WAKE_N PDD3"),
+	PINCTRL_PIN(TEGRA_PIN_PEX_L1_PRSNT_N_PDD4, "PEX_L1_PRSNT_N PDD4"),
+	PINCTRL_PIN(TEGRA_PIN_PEX_L1_RST_N_PDD5, "PEX_L1_RST_N PDD5"),
+	PINCTRL_PIN(TEGRA_PIN_PEX_L1_CLKREQ_N_PDD6, "PEX_L1_CLKREQ_N PDD6"),
+	PINCTRL_PIN(TEGRA_PIN_PEX_L2_PRSNT_N_PDD7, "PEX_L2_PRSNT_N PDD7"),
+	PINCTRL_PIN(TEGRA_PIN_CLK3_OUT_PEE0, "CLK3_OUT PEE0"),
+	PINCTRL_PIN(TEGRA_PIN_CLK3_REQ_PEE1, "CLK3_REQ PEE1"),
+	PINCTRL_PIN(TEGRA_PIN_CLK1_REQ_PEE2, "CLK1_REQ PEE2"),
+	PINCTRL_PIN(TEGRA_PIN_HDMI_CEC_PEE3, "HDMI_CEC PEE3"),
+	PINCTRL_PIN(TEGRA_PIN_PEE4, "PEE4"),
+	PINCTRL_PIN(TEGRA_PIN_PEE5, "PEE5"),
+	PINCTRL_PIN(TEGRA_PIN_PEE6, "PEE6"),
+	PINCTRL_PIN(TEGRA_PIN_PEE7, "PEE7"),
+	PINCTRL_PIN(TEGRA_PIN_CLK_32K_IN, "CLK_32K_IN"),
+	PINCTRL_PIN(TEGRA_PIN_CORE_PWR_REQ, "CORE_PWR_REQ"),
+	PINCTRL_PIN(TEGRA_PIN_CPU_PWR_REQ, "CPU_PWR_REQ"),
+	PINCTRL_PIN(TEGRA_PIN_JTAG_TCK, "JTAG_TCK"),
+	PINCTRL_PIN(TEGRA_PIN_JTAG_TDI, "JTAG_TDI"),
+	PINCTRL_PIN(TEGRA_PIN_JTAG_TDO, "JTAG_TDO"),
+	PINCTRL_PIN(TEGRA_PIN_JTAG_TMS, "JTAG_TMS"),
+	PINCTRL_PIN(TEGRA_PIN_JTAG_TRST_N, "JTAG_TRST_N"),
+	PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"),
+	PINCTRL_PIN(TEGRA_PIN_PWR_INT_N, "PWR_INT_N"),
+	PINCTRL_PIN(TEGRA_PIN_SYS_RESET_N, "SYS_RESET_N"),
+	PINCTRL_PIN(TEGRA_PIN_TEST_MODE_EN, "TEST_MODE_EN"),
+};
+
+static const unsigned clk_32k_out_pa0_pins[] = {
+	TEGRA_PIN_CLK_32K_OUT_PA0,
+};
+
+static const unsigned uart3_cts_n_pa1_pins[] = {
+	TEGRA_PIN_UART3_CTS_N_PA1,
+};
+
+static const unsigned dap2_fs_pa2_pins[] = {
+	TEGRA_PIN_DAP2_FS_PA2,
+};
+
+static const unsigned dap2_sclk_pa3_pins[] = {
+	TEGRA_PIN_DAP2_SCLK_PA3,
+};
+
+static const unsigned dap2_din_pa4_pins[] = {
+	TEGRA_PIN_DAP2_DIN_PA4,
+};
+
+static const unsigned dap2_dout_pa5_pins[] = {
+	TEGRA_PIN_DAP2_DOUT_PA5,
+};
+
+static const unsigned sdmmc3_clk_pa6_pins[] = {
+	TEGRA_PIN_SDMMC3_CLK_PA6,
+};
+
+static const unsigned sdmmc3_cmd_pa7_pins[] = {
+	TEGRA_PIN_SDMMC3_CMD_PA7,
+};
+
+static const unsigned gmi_a17_pb0_pins[] = {
+	TEGRA_PIN_GMI_A17_PB0,
+};
+
+static const unsigned gmi_a18_pb1_pins[] = {
+	TEGRA_PIN_GMI_A18_PB1,
+};
+
+static const unsigned lcd_pwr0_pb2_pins[] = {
+	TEGRA_PIN_LCD_PWR0_PB2,
+};
+
+static const unsigned lcd_pclk_pb3_pins[] = {
+	TEGRA_PIN_LCD_PCLK_PB3,
+};
+
+static const unsigned sdmmc3_dat3_pb4_pins[] = {
+	TEGRA_PIN_SDMMC3_DAT3_PB4,
+};
+
+static const unsigned sdmmc3_dat2_pb5_pins[] = {
+	TEGRA_PIN_SDMMC3_DAT2_PB5,
+};
+
+static const unsigned sdmmc3_dat1_pb6_pins[] = {
+	TEGRA_PIN_SDMMC3_DAT1_PB6,
+};
+
+static const unsigned sdmmc3_dat0_pb7_pins[] = {
+	TEGRA_PIN_SDMMC3_DAT0_PB7,
+};
+
+static const unsigned uart3_rts_n_pc0_pins[] = {
+	TEGRA_PIN_UART3_RTS_N_PC0,
+};
+
+static const unsigned lcd_pwr1_pc1_pins[] = {
+	TEGRA_PIN_LCD_PWR1_PC1,
+};
+
+static const unsigned uart2_txd_pc2_pins[] = {
+	TEGRA_PIN_UART2_TXD_PC2,
+};
+
+static const unsigned uart2_rxd_pc3_pins[] = {
+	TEGRA_PIN_UART2_RXD_PC3,
+};
+
+static const unsigned gen1_i2c_scl_pc4_pins[] = {
+	TEGRA_PIN_GEN1_I2C_SCL_PC4,
+};
+
+static const unsigned gen1_i2c_sda_pc5_pins[] = {
+	TEGRA_PIN_GEN1_I2C_SDA_PC5,
+};
+
+static const unsigned lcd_pwr2_pc6_pins[] = {
+	TEGRA_PIN_LCD_PWR2_PC6,
+};
+
+static const unsigned gmi_wp_n_pc7_pins[] = {
+	TEGRA_PIN_GMI_WP_N_PC7,
+};
+
+static const unsigned sdmmc3_dat5_pd0_pins[] = {
+	TEGRA_PIN_SDMMC3_DAT5_PD0,
+};
+
+static const unsigned sdmmc3_dat4_pd1_pins[] = {
+	TEGRA_PIN_SDMMC3_DAT4_PD1,
+};
+
+static const unsigned lcd_dc1_pd2_pins[] = {
+	TEGRA_PIN_LCD_DC1_PD2,
+};
+
+static const unsigned sdmmc3_dat6_pd3_pins[] = {
+	TEGRA_PIN_SDMMC3_DAT6_PD3,
+};
+
+static const unsigned sdmmc3_dat7_pd4_pins[] = {
+	TEGRA_PIN_SDMMC3_DAT7_PD4,
+};
+
+static const unsigned vi_d1_pd5_pins[] = {
+	TEGRA_PIN_VI_D1_PD5,
+};
+
+static const unsigned vi_vsync_pd6_pins[] = {
+	TEGRA_PIN_VI_VSYNC_PD6,
+};
+
+static const unsigned vi_hsync_pd7_pins[] = {
+	TEGRA_PIN_VI_HSYNC_PD7,
+};
+
+static const unsigned lcd_d0_pe0_pins[] = {
+	TEGRA_PIN_LCD_D0_PE0,
+};
+
+static const unsigned lcd_d1_pe1_pins[] = {
+	TEGRA_PIN_LCD_D1_PE1,
+};
+
+static const unsigned lcd_d2_pe2_pins[] = {
+	TEGRA_PIN_LCD_D2_PE2,
+};
+
+static const unsigned lcd_d3_pe3_pins[] = {
+	TEGRA_PIN_LCD_D3_PE3,
+};
+
+static const unsigned lcd_d4_pe4_pins[] = {
+	TEGRA_PIN_LCD_D4_PE4,
+};
+
+static const unsigned lcd_d5_pe5_pins[] = {
+	TEGRA_PIN_LCD_D5_PE5,
+};
+
+static const unsigned lcd_d6_pe6_pins[] = {
+	TEGRA_PIN_LCD_D6_PE6,
+};
+
+static const unsigned lcd_d7_pe7_pins[] = {
+	TEGRA_PIN_LCD_D7_PE7,
+};
+
+static const unsigned lcd_d8_pf0_pins[] = {
+	TEGRA_PIN_LCD_D8_PF0,
+};
+
+static const unsigned lcd_d9_pf1_pins[] = {
+	TEGRA_PIN_LCD_D9_PF1,
+};
+
+static const unsigned lcd_d10_pf2_pins[] = {
+	TEGRA_PIN_LCD_D10_PF2,
+};
+
+static const unsigned lcd_d11_pf3_pins[] = {
+	TEGRA_PIN_LCD_D11_PF3,
+};
+
+static const unsigned lcd_d12_pf4_pins[] = {
+	TEGRA_PIN_LCD_D12_PF4,
+};
+
+static const unsigned lcd_d13_pf5_pins[] = {
+	TEGRA_PIN_LCD_D13_PF5,
+};
+
+static const unsigned lcd_d14_pf6_pins[] = {
+	TEGRA_PIN_LCD_D14_PF6,
+};
+
+static const unsigned lcd_d15_pf7_pins[] = {
+	TEGRA_PIN_LCD_D15_PF7,
+};
+
+static const unsigned gmi_ad0_pg0_pins[] = {
+	TEGRA_PIN_GMI_AD0_PG0,
+};
+
+static const unsigned gmi_ad1_pg1_pins[] = {
+	TEGRA_PIN_GMI_AD1_PG1,
+};
+
+static const unsigned gmi_ad2_pg2_pins[] = {
+	TEGRA_PIN_GMI_AD2_PG2,
+};
+
+static const unsigned gmi_ad3_pg3_pins[] = {
+	TEGRA_PIN_GMI_AD3_PG3,
+};
+
+static const unsigned gmi_ad4_pg4_pins[] = {
+	TEGRA_PIN_GMI_AD4_PG4,
+};
+
+static const unsigned gmi_ad5_pg5_pins[] = {
+	TEGRA_PIN_GMI_AD5_PG5,
+};
+
+static const unsigned gmi_ad6_pg6_pins[] = {
+	TEGRA_PIN_GMI_AD6_PG6,
+};
+
+static const unsigned gmi_ad7_pg7_pins[] = {
+	TEGRA_PIN_GMI_AD7_PG7,
+};
+
+static const unsigned gmi_ad8_ph0_pins[] = {
+	TEGRA_PIN_GMI_AD8_PH0,
+};
+
+static const unsigned gmi_ad9_ph1_pins[] = {
+	TEGRA_PIN_GMI_AD9_PH1,
+};
+
+static const unsigned gmi_ad10_ph2_pins[] = {
+	TEGRA_PIN_GMI_AD10_PH2,
+};
+
+static const unsigned gmi_ad11_ph3_pins[] = {
+	TEGRA_PIN_GMI_AD11_PH3,
+};
+
+static const unsigned gmi_ad12_ph4_pins[] = {
+	TEGRA_PIN_GMI_AD12_PH4,
+};
+
+static const unsigned gmi_ad13_ph5_pins[] = {
+	TEGRA_PIN_GMI_AD13_PH5,
+};
+
+static const unsigned gmi_ad14_ph6_pins[] = {
+	TEGRA_PIN_GMI_AD14_PH6,
+};
+
+static const unsigned gmi_ad15_ph7_pins[] = {
+	TEGRA_PIN_GMI_AD15_PH7,
+};
+
+static const unsigned gmi_wr_n_pi0_pins[] = {
+	TEGRA_PIN_GMI_WR_N_PI0,
+};
+
+static const unsigned gmi_oe_n_pi1_pins[] = {
+	TEGRA_PIN_GMI_OE_N_PI1,
+};
+
+static const unsigned gmi_dqs_pi2_pins[] = {
+	TEGRA_PIN_GMI_DQS_PI2,
+};
+
+static const unsigned gmi_cs6_n_pi3_pins[] = {
+	TEGRA_PIN_GMI_CS6_N_PI3,
+};
+
+static const unsigned gmi_rst_n_pi4_pins[] = {
+	TEGRA_PIN_GMI_RST_N_PI4,
+};
+
+static const unsigned gmi_iordy_pi5_pins[] = {
+	TEGRA_PIN_GMI_IORDY_PI5,
+};
+
+static const unsigned gmi_cs7_n_pi6_pins[] = {
+	TEGRA_PIN_GMI_CS7_N_PI6,
+};
+
+static const unsigned gmi_wait_pi7_pins[] = {
+	TEGRA_PIN_GMI_WAIT_PI7,
+};
+
+static const unsigned gmi_cs0_n_pj0_pins[] = {
+	TEGRA_PIN_GMI_CS0_N_PJ0,
+};
+
+static const unsigned lcd_de_pj1_pins[] = {
+	TEGRA_PIN_LCD_DE_PJ1,
+};
+
+static const unsigned gmi_cs1_n_pj2_pins[] = {
+	TEGRA_PIN_GMI_CS1_N_PJ2,
+};
+
+static const unsigned lcd_hsync_pj3_pins[] = {
+	TEGRA_PIN_LCD_HSYNC_PJ3,
+};
+
+static const unsigned lcd_vsync_pj4_pins[] = {
+	TEGRA_PIN_LCD_VSYNC_PJ4,
+};
+
+static const unsigned uart2_cts_n_pj5_pins[] = {
+	TEGRA_PIN_UART2_CTS_N_PJ5,
+};
+
+static const unsigned uart2_rts_n_pj6_pins[] = {
+	TEGRA_PIN_UART2_RTS_N_PJ6,
+};
+
+static const unsigned gmi_a16_pj7_pins[] = {
+	TEGRA_PIN_GMI_A16_PJ7,
+};
+
+static const unsigned gmi_adv_n_pk0_pins[] = {
+	TEGRA_PIN_GMI_ADV_N_PK0,
+};
+
+static const unsigned gmi_clk_pk1_pins[] = {
+	TEGRA_PIN_GMI_CLK_PK1,
+};
+
+static const unsigned gmi_cs4_n_pk2_pins[] = {
+	TEGRA_PIN_GMI_CS4_N_PK2,
+};
+
+static const unsigned gmi_cs2_n_pk3_pins[] = {
+	TEGRA_PIN_GMI_CS2_N_PK3,
+};
+
+static const unsigned gmi_cs3_n_pk4_pins[] = {
+	TEGRA_PIN_GMI_CS3_N_PK4,
+};
+
+static const unsigned spdif_out_pk5_pins[] = {
+	TEGRA_PIN_SPDIF_OUT_PK5,
+};
+
+static const unsigned spdif_in_pk6_pins[] = {
+	TEGRA_PIN_SPDIF_IN_PK6,
+};
+
+static const unsigned gmi_a19_pk7_pins[] = {
+	TEGRA_PIN_GMI_A19_PK7,
+};
+
+static const unsigned vi_d2_pl0_pins[] = {
+	TEGRA_PIN_VI_D2_PL0,
+};
+
+static const unsigned vi_d3_pl1_pins[] = {
+	TEGRA_PIN_VI_D3_PL1,
+};
+
+static const unsigned vi_d4_pl2_pins[] = {
+	TEGRA_PIN_VI_D4_PL2,
+};
+
+static const unsigned vi_d5_pl3_pins[] = {
+	TEGRA_PIN_VI_D5_PL3,
+};
+
+static const unsigned vi_d6_pl4_pins[] = {
+	TEGRA_PIN_VI_D6_PL4,
+};
+
+static const unsigned vi_d7_pl5_pins[] = {
+	TEGRA_PIN_VI_D7_PL5,
+};
+
+static const unsigned vi_d8_pl6_pins[] = {
+	TEGRA_PIN_VI_D8_PL6,
+};
+
+static const unsigned vi_d9_pl7_pins[] = {
+	TEGRA_PIN_VI_D9_PL7,
+};
+
+static const unsigned lcd_d16_pm0_pins[] = {
+	TEGRA_PIN_LCD_D16_PM0,
+};
+
+static const unsigned lcd_d17_pm1_pins[] = {
+	TEGRA_PIN_LCD_D17_PM1,
+};
+
+static const unsigned lcd_d18_pm2_pins[] = {
+	TEGRA_PIN_LCD_D18_PM2,
+};
+
+static const unsigned lcd_d19_pm3_pins[] = {
+	TEGRA_PIN_LCD_D19_PM3,
+};
+
+static const unsigned lcd_d20_pm4_pins[] = {
+	TEGRA_PIN_LCD_D20_PM4,
+};
+
+static const unsigned lcd_d21_pm5_pins[] = {
+	TEGRA_PIN_LCD_D21_PM5,
+};
+
+static const unsigned lcd_d22_pm6_pins[] = {
+	TEGRA_PIN_LCD_D22_PM6,
+};
+
+static const unsigned lcd_d23_pm7_pins[] = {
+	TEGRA_PIN_LCD_D23_PM7,
+};
+
+static const unsigned dap1_fs_pn0_pins[] = {
+	TEGRA_PIN_DAP1_FS_PN0,
+};
+
+static const unsigned dap1_din_pn1_pins[] = {
+	TEGRA_PIN_DAP1_DIN_PN1,
+};
+
+static const unsigned dap1_dout_pn2_pins[] = {
+	TEGRA_PIN_DAP1_DOUT_PN2,
+};
+
+static const unsigned dap1_sclk_pn3_pins[] = {
+	TEGRA_PIN_DAP1_SCLK_PN3,
+};
+
+static const unsigned lcd_cs0_n_pn4_pins[] = {
+	TEGRA_PIN_LCD_CS0_N_PN4,
+};
+
+static const unsigned lcd_sdout_pn5_pins[] = {
+	TEGRA_PIN_LCD_SDOUT_PN5,
+};
+
+static const unsigned lcd_dc0_pn6_pins[] = {
+	TEGRA_PIN_LCD_DC0_PN6,
+};
+
+static const unsigned hdmi_int_pn7_pins[] = {
+	TEGRA_PIN_HDMI_INT_PN7,
+};
+
+static const unsigned ulpi_data7_po0_pins[] = {
+	TEGRA_PIN_ULPI_DATA7_PO0,
+};
+
+static const unsigned ulpi_data0_po1_pins[] = {
+	TEGRA_PIN_ULPI_DATA0_PO1,
+};
+
+static const unsigned ulpi_data1_po2_pins[] = {
+	TEGRA_PIN_ULPI_DATA1_PO2,
+};
+
+static const unsigned ulpi_data2_po3_pins[] = {
+	TEGRA_PIN_ULPI_DATA2_PO3,
+};
+
+static const unsigned ulpi_data3_po4_pins[] = {
+	TEGRA_PIN_ULPI_DATA3_PO4,
+};
+
+static const unsigned ulpi_data4_po5_pins[] = {
+	TEGRA_PIN_ULPI_DATA4_PO5,
+};
+
+static const unsigned ulpi_data5_po6_pins[] = {
+	TEGRA_PIN_ULPI_DATA5_PO6,
+};
+
+static const unsigned ulpi_data6_po7_pins[] = {
+	TEGRA_PIN_ULPI_DATA6_PO7,
+};
+
+static const unsigned dap3_fs_pp0_pins[] = {
+	TEGRA_PIN_DAP3_FS_PP0,
+};
+
+static const unsigned dap3_din_pp1_pins[] = {
+	TEGRA_PIN_DAP3_DIN_PP1,
+};
+
+static const unsigned dap3_dout_pp2_pins[] = {
+	TEGRA_PIN_DAP3_DOUT_PP2,
+};
+
+static const unsigned dap3_sclk_pp3_pins[] = {
+	TEGRA_PIN_DAP3_SCLK_PP3,
+};
+
+static const unsigned dap4_fs_pp4_pins[] = {
+	TEGRA_PIN_DAP4_FS_PP4,
+};
+
+static const unsigned dap4_din_pp5_pins[] = {
+	TEGRA_PIN_DAP4_DIN_PP5,
+};
+
+static const unsigned dap4_dout_pp6_pins[] = {
+	TEGRA_PIN_DAP4_DOUT_PP6,
+};
+
+static const unsigned dap4_sclk_pp7_pins[] = {
+	TEGRA_PIN_DAP4_SCLK_PP7,
+};
+
+static const unsigned kb_col0_pq0_pins[] = {
+	TEGRA_PIN_KB_COL0_PQ0,
+};
+
+static const unsigned kb_col1_pq1_pins[] = {
+	TEGRA_PIN_KB_COL1_PQ1,
+};
+
+static const unsigned kb_col2_pq2_pins[] = {
+	TEGRA_PIN_KB_COL2_PQ2,
+};
+
+static const unsigned kb_col3_pq3_pins[] = {
+	TEGRA_PIN_KB_COL3_PQ3,
+};
+
+static const unsigned kb_col4_pq4_pins[] = {
+	TEGRA_PIN_KB_COL4_PQ4,
+};
+
+static const unsigned kb_col5_pq5_pins[] = {
+	TEGRA_PIN_KB_COL5_PQ5,
+};
+
+static const unsigned kb_col6_pq6_pins[] = {
+	TEGRA_PIN_KB_COL6_PQ6,
+};
+
+static const unsigned kb_col7_pq7_pins[] = {
+	TEGRA_PIN_KB_COL7_PQ7,
+};
+
+static const unsigned kb_row0_pr0_pins[] = {
+	TEGRA_PIN_KB_ROW0_PR0,
+};
+
+static const unsigned kb_row1_pr1_pins[] = {
+	TEGRA_PIN_KB_ROW1_PR1,
+};
+
+static const unsigned kb_row2_pr2_pins[] = {
+	TEGRA_PIN_KB_ROW2_PR2,
+};
+
+static const unsigned kb_row3_pr3_pins[] = {
+	TEGRA_PIN_KB_ROW3_PR3,
+};
+
+static const unsigned kb_row4_pr4_pins[] = {
+	TEGRA_PIN_KB_ROW4_PR4,
+};
+
+static const unsigned kb_row5_pr5_pins[] = {
+	TEGRA_PIN_KB_ROW5_PR5,
+};
+
+static const unsigned kb_row6_pr6_pins[] = {
+	TEGRA_PIN_KB_ROW6_PR6,
+};
+
+static const unsigned kb_row7_pr7_pins[] = {
+	TEGRA_PIN_KB_ROW7_PR7,
+};
+
+static const unsigned kb_row8_ps0_pins[] = {
+	TEGRA_PIN_KB_ROW8_PS0,
+};
+
+static const unsigned kb_row9_ps1_pins[] = {
+	TEGRA_PIN_KB_ROW9_PS1,
+};
+
+static const unsigned kb_row10_ps2_pins[] = {
+	TEGRA_PIN_KB_ROW10_PS2,
+};
+
+static const unsigned kb_row11_ps3_pins[] = {
+	TEGRA_PIN_KB_ROW11_PS3,
+};
+
+static const unsigned kb_row12_ps4_pins[] = {
+	TEGRA_PIN_KB_ROW12_PS4,
+};
+
+static const unsigned kb_row13_ps5_pins[] = {
+	TEGRA_PIN_KB_ROW13_PS5,
+};
+
+static const unsigned kb_row14_ps6_pins[] = {
+	TEGRA_PIN_KB_ROW14_PS6,
+};
+
+static const unsigned kb_row15_ps7_pins[] = {
+	TEGRA_PIN_KB_ROW15_PS7,
+};
+
+static const unsigned vi_pclk_pt0_pins[] = {
+	TEGRA_PIN_VI_PCLK_PT0,
+};
+
+static const unsigned vi_mclk_pt1_pins[] = {
+	TEGRA_PIN_VI_MCLK_PT1,
+};
+
+static const unsigned vi_d10_pt2_pins[] = {
+	TEGRA_PIN_VI_D10_PT2,
+};
+
+static const unsigned vi_d11_pt3_pins[] = {
+	TEGRA_PIN_VI_D11_PT3,
+};
+
+static const unsigned vi_d0_pt4_pins[] = {
+	TEGRA_PIN_VI_D0_PT4,
+};
+
+static const unsigned gen2_i2c_scl_pt5_pins[] = {
+	TEGRA_PIN_GEN2_I2C_SCL_PT5,
+};
+
+static const unsigned gen2_i2c_sda_pt6_pins[] = {
+	TEGRA_PIN_GEN2_I2C_SDA_PT6,
+};
+
+static const unsigned sdmmc4_cmd_pt7_pins[] = {
+	TEGRA_PIN_SDMMC4_CMD_PT7,
+};
+
+static const unsigned pu0_pins[] = {
+	TEGRA_PIN_PU0,
+};
+
+static const unsigned pu1_pins[] = {
+	TEGRA_PIN_PU1,
+};
+
+static const unsigned pu2_pins[] = {
+	TEGRA_PIN_PU2,
+};
+
+static const unsigned pu3_pins[] = {
+	TEGRA_PIN_PU3,
+};
+
+static const unsigned pu4_pins[] = {
+	TEGRA_PIN_PU4,
+};
+
+static const unsigned pu5_pins[] = {
+	TEGRA_PIN_PU5,
+};
+
+static const unsigned pu6_pins[] = {
+	TEGRA_PIN_PU6,
+};
+
+static const unsigned jtag_rtck_pu7_pins[] = {
+	TEGRA_PIN_JTAG_RTCK_PU7,
+};
+
+static const unsigned pv0_pins[] = {
+	TEGRA_PIN_PV0,
+};
+
+static const unsigned pv1_pins[] = {
+	TEGRA_PIN_PV1,
+};
+
+static const unsigned pv2_pins[] = {
+	TEGRA_PIN_PV2,
+};
+
+static const unsigned pv3_pins[] = {
+	TEGRA_PIN_PV3,
+};
+
+static const unsigned ddc_scl_pv4_pins[] = {
+	TEGRA_PIN_DDC_SCL_PV4,
+};
+
+static const unsigned ddc_sda_pv5_pins[] = {
+	TEGRA_PIN_DDC_SDA_PV5,
+};
+
+static const unsigned crt_hsync_pv6_pins[] = {
+	TEGRA_PIN_CRT_HSYNC_PV6,
+};
+
+static const unsigned crt_vsync_pv7_pins[] = {
+	TEGRA_PIN_CRT_VSYNC_PV7,
+};
+
+static const unsigned lcd_cs1_n_pw0_pins[] = {
+	TEGRA_PIN_LCD_CS1_N_PW0,
+};
+
+static const unsigned lcd_m1_pw1_pins[] = {
+	TEGRA_PIN_LCD_M1_PW1,
+};
+
+static const unsigned spi2_cs1_n_pw2_pins[] = {
+	TEGRA_PIN_SPI2_CS1_N_PW2,
+};
+
+static const unsigned spi2_cs2_n_pw3_pins[] = {
+	TEGRA_PIN_SPI2_CS2_N_PW3,
+};
+
+static const unsigned clk1_out_pw4_pins[] = {
+	TEGRA_PIN_CLK1_OUT_PW4,
+};
+
+static const unsigned clk2_out_pw5_pins[] = {
+	TEGRA_PIN_CLK2_OUT_PW5,
+};
+
+static const unsigned uart3_txd_pw6_pins[] = {
+	TEGRA_PIN_UART3_TXD_PW6,
+};
+
+static const unsigned uart3_rxd_pw7_pins[] = {
+	TEGRA_PIN_UART3_RXD_PW7,
+};
+
+static const unsigned spi2_mosi_px0_pins[] = {
+	TEGRA_PIN_SPI2_MOSI_PX0,
+};
+
+static const unsigned spi2_miso_px1_pins[] = {
+	TEGRA_PIN_SPI2_MISO_PX1,
+};
+
+static const unsigned spi2_sck_px2_pins[] = {
+	TEGRA_PIN_SPI2_SCK_PX2,
+};
+
+static const unsigned spi2_cs0_n_px3_pins[] = {
+	TEGRA_PIN_SPI2_CS0_N_PX3,
+};
+
+static const unsigned spi1_mosi_px4_pins[] = {
+	TEGRA_PIN_SPI1_MOSI_PX4,
+};
+
+static const unsigned spi1_sck_px5_pins[] = {
+	TEGRA_PIN_SPI1_SCK_PX5,
+};
+
+static const unsigned spi1_cs0_n_px6_pins[] = {
+	TEGRA_PIN_SPI1_CS0_N_PX6,
+};
+
+static const unsigned spi1_miso_px7_pins[] = {
+	TEGRA_PIN_SPI1_MISO_PX7,
+};
+
+static const unsigned ulpi_clk_py0_pins[] = {
+	TEGRA_PIN_ULPI_CLK_PY0,
+};
+
+static const unsigned ulpi_dir_py1_pins[] = {
+	TEGRA_PIN_ULPI_DIR_PY1,
+};
+
+static const unsigned ulpi_nxt_py2_pins[] = {
+	TEGRA_PIN_ULPI_NXT_PY2,
+};
+
+static const unsigned ulpi_stp_py3_pins[] = {
+	TEGRA_PIN_ULPI_STP_PY3,
+};
+
+static const unsigned sdmmc1_dat3_py4_pins[] = {
+	TEGRA_PIN_SDMMC1_DAT3_PY4,
+};
+
+static const unsigned sdmmc1_dat2_py5_pins[] = {
+	TEGRA_PIN_SDMMC1_DAT2_PY5,
+};
+
+static const unsigned sdmmc1_dat1_py6_pins[] = {
+	TEGRA_PIN_SDMMC1_DAT1_PY6,
+};
+
+static const unsigned sdmmc1_dat0_py7_pins[] = {
+	TEGRA_PIN_SDMMC1_DAT0_PY7,
+};
+
+static const unsigned sdmmc1_clk_pz0_pins[] = {
+	TEGRA_PIN_SDMMC1_CLK_PZ0,
+};
+
+static const unsigned sdmmc1_cmd_pz1_pins[] = {
+	TEGRA_PIN_SDMMC1_CMD_PZ1,
+};
+
+static const unsigned lcd_sdin_pz2_pins[] = {
+	TEGRA_PIN_LCD_SDIN_PZ2,
+};
+
+static const unsigned lcd_wr_n_pz3_pins[] = {
+	TEGRA_PIN_LCD_WR_N_PZ3,
+};
+
+static const unsigned lcd_sck_pz4_pins[] = {
+	TEGRA_PIN_LCD_SCK_PZ4,
+};
+
+static const unsigned sys_clk_req_pz5_pins[] = {
+	TEGRA_PIN_SYS_CLK_REQ_PZ5,
+};
+
+static const unsigned pwr_i2c_scl_pz6_pins[] = {
+	TEGRA_PIN_PWR_I2C_SCL_PZ6,
+};
+
+static const unsigned pwr_i2c_sda_pz7_pins[] = {
+	TEGRA_PIN_PWR_I2C_SDA_PZ7,
+};
+
+static const unsigned sdmmc4_dat0_paa0_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT0_PAA0,
+};
+
+static const unsigned sdmmc4_dat1_paa1_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT1_PAA1,
+};
+
+static const unsigned sdmmc4_dat2_paa2_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT2_PAA2,
+};
+
+static const unsigned sdmmc4_dat3_paa3_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT3_PAA3,
+};
+
+static const unsigned sdmmc4_dat4_paa4_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT4_PAA4,
+};
+
+static const unsigned sdmmc4_dat5_paa5_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT5_PAA5,
+};
+
+static const unsigned sdmmc4_dat6_paa6_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT6_PAA6,
+};
+
+static const unsigned sdmmc4_dat7_paa7_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT7_PAA7,
+};
+
+static const unsigned pbb0_pins[] = {
+	TEGRA_PIN_PBB0,
+};
+
+static const unsigned cam_i2c_scl_pbb1_pins[] = {
+	TEGRA_PIN_CAM_I2C_SCL_PBB1,
+};
+
+static const unsigned cam_i2c_sda_pbb2_pins[] = {
+	TEGRA_PIN_CAM_I2C_SDA_PBB2,
+};
+
+static const unsigned pbb3_pins[] = {
+	TEGRA_PIN_PBB3,
+};
+
+static const unsigned pbb4_pins[] = {
+	TEGRA_PIN_PBB4,
+};
+
+static const unsigned pbb5_pins[] = {
+	TEGRA_PIN_PBB5,
+};
+
+static const unsigned pbb6_pins[] = {
+	TEGRA_PIN_PBB6,
+};
+
+static const unsigned pbb7_pins[] = {
+	TEGRA_PIN_PBB7,
+};
+
+static const unsigned cam_mclk_pcc0_pins[] = {
+	TEGRA_PIN_CAM_MCLK_PCC0,
+};
+
+static const unsigned pcc1_pins[] = {
+	TEGRA_PIN_PCC1,
+};
+
+static const unsigned pcc2_pins[] = {
+	TEGRA_PIN_PCC2,
+};
+
+static const unsigned sdmmc4_rst_n_pcc3_pins[] = {
+	TEGRA_PIN_SDMMC4_RST_N_PCC3,
+};
+
+static const unsigned sdmmc4_clk_pcc4_pins[] = {
+	TEGRA_PIN_SDMMC4_CLK_PCC4,
+};
+
+static const unsigned clk2_req_pcc5_pins[] = {
+	TEGRA_PIN_CLK2_REQ_PCC5,
+};
+
+static const unsigned pex_l2_rst_n_pcc6_pins[] = {
+	TEGRA_PIN_PEX_L2_RST_N_PCC6,
+};
+
+static const unsigned pex_l2_clkreq_n_pcc7_pins[] = {
+	TEGRA_PIN_PEX_L2_CLKREQ_N_PCC7,
+};
+
+static const unsigned pex_l0_prsnt_n_pdd0_pins[] = {
+	TEGRA_PIN_PEX_L0_PRSNT_N_PDD0,
+};
+
+static const unsigned pex_l0_rst_n_pdd1_pins[] = {
+	TEGRA_PIN_PEX_L0_RST_N_PDD1,
+};
+
+static const unsigned pex_l0_clkreq_n_pdd2_pins[] = {
+	TEGRA_PIN_PEX_L0_CLKREQ_N_PDD2,
+};
+
+static const unsigned pex_wake_n_pdd3_pins[] = {
+	TEGRA_PIN_PEX_WAKE_N_PDD3,
+};
+
+static const unsigned pex_l1_prsnt_n_pdd4_pins[] = {
+	TEGRA_PIN_PEX_L1_PRSNT_N_PDD4,
+};
+
+static const unsigned pex_l1_rst_n_pdd5_pins[] = {
+	TEGRA_PIN_PEX_L1_RST_N_PDD5,
+};
+
+static const unsigned pex_l1_clkreq_n_pdd6_pins[] = {
+	TEGRA_PIN_PEX_L1_CLKREQ_N_PDD6,
+};
+
+static const unsigned pex_l2_prsnt_n_pdd7_pins[] = {
+	TEGRA_PIN_PEX_L2_PRSNT_N_PDD7,
+};
+
+static const unsigned clk3_out_pee0_pins[] = {
+	TEGRA_PIN_CLK3_OUT_PEE0,
+};
+
+static const unsigned clk3_req_pee1_pins[] = {
+	TEGRA_PIN_CLK3_REQ_PEE1,
+};
+
+static const unsigned clk1_req_pee2_pins[] = {
+	TEGRA_PIN_CLK1_REQ_PEE2,
+};
+
+static const unsigned hdmi_cec_pee3_pins[] = {
+	TEGRA_PIN_HDMI_CEC_PEE3,
+};
+
+static const unsigned clk_32k_in_pins[] = {
+	TEGRA_PIN_CLK_32K_IN,
+};
+
+static const unsigned core_pwr_req_pins[] = {
+	TEGRA_PIN_CORE_PWR_REQ,
+};
+
+static const unsigned cpu_pwr_req_pins[] = {
+	TEGRA_PIN_CPU_PWR_REQ,
+};
+
+static const unsigned owr_pins[] = {
+	TEGRA_PIN_OWR,
+};
+
+static const unsigned pwr_int_n_pins[] = {
+	TEGRA_PIN_PWR_INT_N,
+};
+
+static const unsigned drive_ao1_pins[] = {
+	TEGRA_PIN_KB_ROW0_PR0,
+	TEGRA_PIN_KB_ROW1_PR1,
+	TEGRA_PIN_KB_ROW2_PR2,
+	TEGRA_PIN_KB_ROW3_PR3,
+	TEGRA_PIN_KB_ROW4_PR4,
+	TEGRA_PIN_KB_ROW5_PR5,
+	TEGRA_PIN_KB_ROW6_PR6,
+	TEGRA_PIN_KB_ROW7_PR7,
+	TEGRA_PIN_PWR_I2C_SCL_PZ6,
+	TEGRA_PIN_PWR_I2C_SDA_PZ7,
+	TEGRA_PIN_SYS_RESET_N,
+};
+
+static const unsigned drive_ao2_pins[] = {
+	TEGRA_PIN_CLK_32K_OUT_PA0,
+	TEGRA_PIN_KB_COL0_PQ0,
+	TEGRA_PIN_KB_COL1_PQ1,
+	TEGRA_PIN_KB_COL2_PQ2,
+	TEGRA_PIN_KB_COL3_PQ3,
+	TEGRA_PIN_KB_COL4_PQ4,
+	TEGRA_PIN_KB_COL5_PQ5,
+	TEGRA_PIN_KB_COL6_PQ6,
+	TEGRA_PIN_KB_COL7_PQ7,
+	TEGRA_PIN_KB_ROW8_PS0,
+	TEGRA_PIN_KB_ROW9_PS1,
+	TEGRA_PIN_KB_ROW10_PS2,
+	TEGRA_PIN_KB_ROW11_PS3,
+	TEGRA_PIN_KB_ROW12_PS4,
+	TEGRA_PIN_KB_ROW13_PS5,
+	TEGRA_PIN_KB_ROW14_PS6,
+	TEGRA_PIN_KB_ROW15_PS7,
+	TEGRA_PIN_SYS_CLK_REQ_PZ5,
+	TEGRA_PIN_CLK_32K_IN,
+	TEGRA_PIN_CORE_PWR_REQ,
+	TEGRA_PIN_CPU_PWR_REQ,
+	TEGRA_PIN_PWR_INT_N,
+};
+
+static const unsigned drive_at1_pins[] = {
+	TEGRA_PIN_GMI_AD8_PH0,
+	TEGRA_PIN_GMI_AD9_PH1,
+	TEGRA_PIN_GMI_AD10_PH2,
+	TEGRA_PIN_GMI_AD11_PH3,
+	TEGRA_PIN_GMI_AD12_PH4,
+	TEGRA_PIN_GMI_AD13_PH5,
+	TEGRA_PIN_GMI_AD14_PH6,
+	TEGRA_PIN_GMI_AD15_PH7,
+	TEGRA_PIN_GMI_IORDY_PI5,
+	TEGRA_PIN_GMI_CS7_N_PI6,
+};
+
+static const unsigned drive_at2_pins[] = {
+	TEGRA_PIN_GMI_AD0_PG0,
+	TEGRA_PIN_GMI_AD1_PG1,
+	TEGRA_PIN_GMI_AD2_PG2,
+	TEGRA_PIN_GMI_AD3_PG3,
+	TEGRA_PIN_GMI_AD4_PG4,
+	TEGRA_PIN_GMI_AD5_PG5,
+	TEGRA_PIN_GMI_AD6_PG6,
+	TEGRA_PIN_GMI_AD7_PG7,
+	TEGRA_PIN_GMI_WR_N_PI0,
+	TEGRA_PIN_GMI_OE_N_PI1,
+	TEGRA_PIN_GMI_DQS_PI2,
+	TEGRA_PIN_GMI_CS6_N_PI3,
+	TEGRA_PIN_GMI_RST_N_PI4,
+	TEGRA_PIN_GMI_WAIT_PI7,
+	TEGRA_PIN_GMI_ADV_N_PK0,
+	TEGRA_PIN_GMI_CLK_PK1,
+	TEGRA_PIN_GMI_CS4_N_PK2,
+	TEGRA_PIN_GMI_CS2_N_PK3,
+	TEGRA_PIN_GMI_CS3_N_PK4,
+};
+
+static const unsigned drive_at3_pins[] = {
+	TEGRA_PIN_GMI_WP_N_PC7,
+	TEGRA_PIN_GMI_CS0_N_PJ0,
+};
+
+static const unsigned drive_at4_pins[] = {
+	TEGRA_PIN_GMI_A17_PB0,
+	TEGRA_PIN_GMI_A18_PB1,
+	TEGRA_PIN_GMI_CS1_N_PJ2,
+	TEGRA_PIN_GMI_A16_PJ7,
+	TEGRA_PIN_GMI_A19_PK7,
+};
+
+static const unsigned drive_at5_pins[] = {
+	TEGRA_PIN_GEN2_I2C_SCL_PT5,
+	TEGRA_PIN_GEN2_I2C_SDA_PT6,
+};
+
+static const unsigned drive_cdev1_pins[] = {
+	TEGRA_PIN_CLK1_OUT_PW4,
+	TEGRA_PIN_CLK1_REQ_PEE2,
+};
+
+static const unsigned drive_cdev2_pins[] = {
+	TEGRA_PIN_CLK2_OUT_PW5,
+	TEGRA_PIN_CLK2_REQ_PCC5,
+};
+
+static const unsigned drive_cec_pins[] = {
+	TEGRA_PIN_HDMI_CEC_PEE3,
+};
+
+static const unsigned drive_crt_pins[] = {
+	TEGRA_PIN_CRT_HSYNC_PV6,
+	TEGRA_PIN_CRT_VSYNC_PV7,
+};
+
+static const unsigned drive_csus_pins[] = {
+	TEGRA_PIN_VI_MCLK_PT1,
+};
+
+static const unsigned drive_dap1_pins[] = {
+	TEGRA_PIN_SPDIF_OUT_PK5,
+	TEGRA_PIN_SPDIF_IN_PK6,
+	TEGRA_PIN_DAP1_FS_PN0,
+	TEGRA_PIN_DAP1_DIN_PN1,
+	TEGRA_PIN_DAP1_DOUT_PN2,
+	TEGRA_PIN_DAP1_SCLK_PN3,
+};
+
+static const unsigned drive_dap2_pins[] = {
+	TEGRA_PIN_DAP2_FS_PA2,
+	TEGRA_PIN_DAP2_SCLK_PA3,
+	TEGRA_PIN_DAP2_DIN_PA4,
+	TEGRA_PIN_DAP2_DOUT_PA5,
+};
+
+static const unsigned drive_dap3_pins[] = {
+	TEGRA_PIN_DAP3_FS_PP0,
+	TEGRA_PIN_DAP3_DIN_PP1,
+	TEGRA_PIN_DAP3_DOUT_PP2,
+	TEGRA_PIN_DAP3_SCLK_PP3,
+};
+
+static const unsigned drive_dap4_pins[] = {
+	TEGRA_PIN_DAP4_FS_PP4,
+	TEGRA_PIN_DAP4_DIN_PP5,
+	TEGRA_PIN_DAP4_DOUT_PP6,
+	TEGRA_PIN_DAP4_SCLK_PP7,
+};
+
+static const unsigned drive_dbg_pins[] = {
+	TEGRA_PIN_GEN1_I2C_SCL_PC4,
+	TEGRA_PIN_GEN1_I2C_SDA_PC5,
+	TEGRA_PIN_PU0,
+	TEGRA_PIN_PU1,
+	TEGRA_PIN_PU2,
+	TEGRA_PIN_PU3,
+	TEGRA_PIN_PU4,
+	TEGRA_PIN_PU5,
+	TEGRA_PIN_PU6,
+	TEGRA_PIN_JTAG_RTCK_PU7,
+	TEGRA_PIN_JTAG_TCK,
+	TEGRA_PIN_JTAG_TDI,
+	TEGRA_PIN_JTAG_TDO,
+	TEGRA_PIN_JTAG_TMS,
+	TEGRA_PIN_JTAG_TRST_N,
+	TEGRA_PIN_TEST_MODE_EN,
+};
+
+static const unsigned drive_ddc_pins[] = {
+	TEGRA_PIN_DDC_SCL_PV4,
+	TEGRA_PIN_DDC_SDA_PV5,
+};
+
+static const unsigned drive_dev3_pins[] = {
+	TEGRA_PIN_CLK3_OUT_PEE0,
+	TEGRA_PIN_CLK3_REQ_PEE1,
+};
+
+static const unsigned drive_gma_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT0_PAA0,
+	TEGRA_PIN_SDMMC4_DAT1_PAA1,
+	TEGRA_PIN_SDMMC4_DAT2_PAA2,
+	TEGRA_PIN_SDMMC4_DAT3_PAA3,
+	TEGRA_PIN_SDMMC4_RST_N_PCC3,
+};
+
+static const unsigned drive_gmb_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT4_PAA4,
+	TEGRA_PIN_SDMMC4_DAT5_PAA5,
+	TEGRA_PIN_SDMMC4_DAT6_PAA6,
+	TEGRA_PIN_SDMMC4_DAT7_PAA7,
+};
+
+static const unsigned drive_gmc_pins[] = {
+	TEGRA_PIN_SDMMC4_CLK_PCC4,
+};
+
+static const unsigned drive_gmd_pins[] = {
+	TEGRA_PIN_SDMMC4_CMD_PT7,
+};
+
+static const unsigned drive_gme_pins[] = {
+	TEGRA_PIN_PBB0,
+	TEGRA_PIN_CAM_I2C_SCL_PBB1,
+	TEGRA_PIN_CAM_I2C_SDA_PBB2,
+	TEGRA_PIN_PBB3,
+	TEGRA_PIN_PCC2,
+};
+
+static const unsigned drive_gmf_pins[] = {
+	TEGRA_PIN_PBB4,
+	TEGRA_PIN_PBB5,
+	TEGRA_PIN_PBB6,
+	TEGRA_PIN_PBB7,
+};
+
+static const unsigned drive_gmg_pins[] = {
+	TEGRA_PIN_CAM_MCLK_PCC0,
+};
+
+static const unsigned drive_gmh_pins[] = {
+	TEGRA_PIN_PCC1,
+};
+
+static const unsigned drive_gpv_pins[] = {
+	TEGRA_PIN_PEX_L2_RST_N_PCC6,
+	TEGRA_PIN_PEX_L2_CLKREQ_N_PCC7,
+	TEGRA_PIN_PEX_L0_PRSNT_N_PDD0,
+	TEGRA_PIN_PEX_L0_RST_N_PDD1,
+	TEGRA_PIN_PEX_L0_CLKREQ_N_PDD2,
+	TEGRA_PIN_PEX_WAKE_N_PDD3,
+	TEGRA_PIN_PEX_L1_PRSNT_N_PDD4,
+	TEGRA_PIN_PEX_L1_RST_N_PDD5,
+	TEGRA_PIN_PEX_L1_CLKREQ_N_PDD6,
+	TEGRA_PIN_PEX_L2_PRSNT_N_PDD7,
+};
+
+static const unsigned drive_lcd1_pins[] = {
+	TEGRA_PIN_LCD_PWR1_PC1,
+	TEGRA_PIN_LCD_PWR2_PC6,
+	TEGRA_PIN_LCD_CS0_N_PN4,
+	TEGRA_PIN_LCD_SDOUT_PN5,
+	TEGRA_PIN_LCD_DC0_PN6,
+	TEGRA_PIN_LCD_SDIN_PZ2,
+	TEGRA_PIN_LCD_WR_N_PZ3,
+	TEGRA_PIN_LCD_SCK_PZ4,
+};
+
+static const unsigned drive_lcd2_pins[] = {
+	TEGRA_PIN_LCD_PWR0_PB2,
+	TEGRA_PIN_LCD_PCLK_PB3,
+	TEGRA_PIN_LCD_DC1_PD2,
+	TEGRA_PIN_LCD_D0_PE0,
+	TEGRA_PIN_LCD_D1_PE1,
+	TEGRA_PIN_LCD_D2_PE2,
+	TEGRA_PIN_LCD_D3_PE3,
+	TEGRA_PIN_LCD_D4_PE4,
+	TEGRA_PIN_LCD_D5_PE5,
+	TEGRA_PIN_LCD_D6_PE6,
+	TEGRA_PIN_LCD_D7_PE7,
+	TEGRA_PIN_LCD_D8_PF0,
+	TEGRA_PIN_LCD_D9_PF1,
+	TEGRA_PIN_LCD_D10_PF2,
+	TEGRA_PIN_LCD_D11_PF3,
+	TEGRA_PIN_LCD_D12_PF4,
+	TEGRA_PIN_LCD_D13_PF5,
+	TEGRA_PIN_LCD_D14_PF6,
+	TEGRA_PIN_LCD_D15_PF7,
+	TEGRA_PIN_LCD_DE_PJ1,
+	TEGRA_PIN_LCD_HSYNC_PJ3,
+	TEGRA_PIN_LCD_VSYNC_PJ4,
+	TEGRA_PIN_LCD_D16_PM0,
+	TEGRA_PIN_LCD_D17_PM1,
+	TEGRA_PIN_LCD_D18_PM2,
+	TEGRA_PIN_LCD_D19_PM3,
+	TEGRA_PIN_LCD_D20_PM4,
+	TEGRA_PIN_LCD_D21_PM5,
+	TEGRA_PIN_LCD_D22_PM6,
+	TEGRA_PIN_LCD_D23_PM7,
+	TEGRA_PIN_HDMI_INT_PN7,
+	TEGRA_PIN_LCD_CS1_N_PW0,
+	TEGRA_PIN_LCD_M1_PW1,
+};
+
+static const unsigned drive_owr_pins[] = {
+	TEGRA_PIN_OWR,
+};
+
+static const unsigned drive_sdio1_pins[] = {
+	TEGRA_PIN_SDMMC1_DAT3_PY4,
+	TEGRA_PIN_SDMMC1_DAT2_PY5,
+	TEGRA_PIN_SDMMC1_DAT1_PY6,
+	TEGRA_PIN_SDMMC1_DAT0_PY7,
+	TEGRA_PIN_SDMMC1_CLK_PZ0,
+	TEGRA_PIN_SDMMC1_CMD_PZ1,
+};
+
+static const unsigned drive_sdio2_pins[] = {
+	TEGRA_PIN_SDMMC3_DAT5_PD0,
+	TEGRA_PIN_SDMMC3_DAT4_PD1,
+	TEGRA_PIN_SDMMC3_DAT6_PD3,
+	TEGRA_PIN_SDMMC3_DAT7_PD4,
+};
+
+static const unsigned drive_sdio3_pins[] = {
+	TEGRA_PIN_SDMMC3_CLK_PA6,
+	TEGRA_PIN_SDMMC3_CMD_PA7,
+	TEGRA_PIN_SDMMC3_DAT3_PB4,
+	TEGRA_PIN_SDMMC3_DAT2_PB5,
+	TEGRA_PIN_SDMMC3_DAT1_PB6,
+	TEGRA_PIN_SDMMC3_DAT0_PB7,
+};
+
+static const unsigned drive_spi_pins[] = {
+	TEGRA_PIN_SPI2_CS1_N_PW2,
+	TEGRA_PIN_SPI2_CS2_N_PW3,
+	TEGRA_PIN_SPI2_MOSI_PX0,
+	TEGRA_PIN_SPI2_MISO_PX1,
+	TEGRA_PIN_SPI2_SCK_PX2,
+	TEGRA_PIN_SPI2_CS0_N_PX3,
+	TEGRA_PIN_SPI1_MOSI_PX4,
+	TEGRA_PIN_SPI1_SCK_PX5,
+	TEGRA_PIN_SPI1_CS0_N_PX6,
+	TEGRA_PIN_SPI1_MISO_PX7,
+};
+
+static const unsigned drive_uaa_pins[] = {
+	TEGRA_PIN_ULPI_DATA0_PO1,
+	TEGRA_PIN_ULPI_DATA1_PO2,
+	TEGRA_PIN_ULPI_DATA2_PO3,
+	TEGRA_PIN_ULPI_DATA3_PO4,
+};
+
+static const unsigned drive_uab_pins[] = {
+	TEGRA_PIN_ULPI_DATA7_PO0,
+	TEGRA_PIN_ULPI_DATA4_PO5,
+	TEGRA_PIN_ULPI_DATA5_PO6,
+	TEGRA_PIN_ULPI_DATA6_PO7,
+	TEGRA_PIN_PV0,
+	TEGRA_PIN_PV1,
+	TEGRA_PIN_PV2,
+	TEGRA_PIN_PV3,
+};
+
+static const unsigned drive_uart2_pins[] = {
+	TEGRA_PIN_UART2_TXD_PC2,
+	TEGRA_PIN_UART2_RXD_PC3,
+	TEGRA_PIN_UART2_CTS_N_PJ5,
+	TEGRA_PIN_UART2_RTS_N_PJ6,
+};
+
+static const unsigned drive_uart3_pins[] = {
+	TEGRA_PIN_UART3_CTS_N_PA1,
+	TEGRA_PIN_UART3_RTS_N_PC0,
+	TEGRA_PIN_UART3_TXD_PW6,
+	TEGRA_PIN_UART3_RXD_PW7,
+};
+
+static const unsigned drive_uda_pins[] = {
+	TEGRA_PIN_ULPI_CLK_PY0,
+	TEGRA_PIN_ULPI_DIR_PY1,
+	TEGRA_PIN_ULPI_NXT_PY2,
+	TEGRA_PIN_ULPI_STP_PY3,
+};
+
+static const unsigned drive_vi1_pins[] = {
+	TEGRA_PIN_VI_D1_PD5,
+	TEGRA_PIN_VI_VSYNC_PD6,
+	TEGRA_PIN_VI_HSYNC_PD7,
+	TEGRA_PIN_VI_D2_PL0,
+	TEGRA_PIN_VI_D3_PL1,
+	TEGRA_PIN_VI_D4_PL2,
+	TEGRA_PIN_VI_D5_PL3,
+	TEGRA_PIN_VI_D6_PL4,
+	TEGRA_PIN_VI_D7_PL5,
+	TEGRA_PIN_VI_D8_PL6,
+	TEGRA_PIN_VI_D9_PL7,
+	TEGRA_PIN_VI_PCLK_PT0,
+	TEGRA_PIN_VI_D10_PT2,
+	TEGRA_PIN_VI_D11_PT3,
+	TEGRA_PIN_VI_D0_PT4,
+};
+
+enum tegra_mux {
+	TEGRA_MUX_BLINK,
+	TEGRA_MUX_CEC,
+	TEGRA_MUX_CLK_12M_OUT,
+	TEGRA_MUX_CLK_32K_IN,
+	TEGRA_MUX_CORE_PWR_REQ,
+	TEGRA_MUX_CPU_PWR_REQ,
+	TEGRA_MUX_CRT,
+	TEGRA_MUX_DAP,
+	TEGRA_MUX_DDR,
+	TEGRA_MUX_DEV3,
+	TEGRA_MUX_DISPLAYA,
+	TEGRA_MUX_DISPLAYB,
+	TEGRA_MUX_DTV,
+	TEGRA_MUX_EXTPERIPH1,
+	TEGRA_MUX_EXTPERIPH2,
+	TEGRA_MUX_EXTPERIPH3,
+	TEGRA_MUX_GMI,
+	TEGRA_MUX_GMI_ALT,
+	TEGRA_MUX_HDA,
+	TEGRA_MUX_HDCP,
+	TEGRA_MUX_HDMI,
+	TEGRA_MUX_HSI,
+	TEGRA_MUX_I2C1,
+	TEGRA_MUX_I2C2,
+	TEGRA_MUX_I2C3,
+	TEGRA_MUX_I2C4,
+	TEGRA_MUX_I2CPWR,
+	TEGRA_MUX_I2S0,
+	TEGRA_MUX_I2S1,
+	TEGRA_MUX_I2S2,
+	TEGRA_MUX_I2S3,
+	TEGRA_MUX_I2S4,
+	TEGRA_MUX_INVALID,
+	TEGRA_MUX_KBC,
+	TEGRA_MUX_MIO,
+	TEGRA_MUX_NAND,
+	TEGRA_MUX_NAND_ALT,
+	TEGRA_MUX_OWR,
+	TEGRA_MUX_PCIE,
+	TEGRA_MUX_PWM0,
+	TEGRA_MUX_PWM1,
+	TEGRA_MUX_PWM2,
+	TEGRA_MUX_PWM3,
+	TEGRA_MUX_PWR_INT_N,
+	TEGRA_MUX_RSVD1,
+	TEGRA_MUX_RSVD2,
+	TEGRA_MUX_RSVD3,
+	TEGRA_MUX_RSVD4,
+	TEGRA_MUX_RTCK,
+	TEGRA_MUX_SATA,
+	TEGRA_MUX_SDMMC1,
+	TEGRA_MUX_SDMMC2,
+	TEGRA_MUX_SDMMC3,
+	TEGRA_MUX_SDMMC4,
+	TEGRA_MUX_SPDIF,
+	TEGRA_MUX_SPI1,
+	TEGRA_MUX_SPI2,
+	TEGRA_MUX_SPI2_ALT,
+	TEGRA_MUX_SPI3,
+	TEGRA_MUX_SPI4,
+	TEGRA_MUX_SPI5,
+	TEGRA_MUX_SPI6,
+	TEGRA_MUX_SYSCLK,
+	TEGRA_MUX_TEST,
+	TEGRA_MUX_TRACE,
+	TEGRA_MUX_UARTA,
+	TEGRA_MUX_UARTB,
+	TEGRA_MUX_UARTC,
+	TEGRA_MUX_UARTD,
+	TEGRA_MUX_UARTE,
+	TEGRA_MUX_ULPI,
+	TEGRA_MUX_VGP1,
+	TEGRA_MUX_VGP2,
+	TEGRA_MUX_VGP3,
+	TEGRA_MUX_VGP4,
+	TEGRA_MUX_VGP5,
+	TEGRA_MUX_VGP6,
+	TEGRA_MUX_VI,
+	TEGRA_MUX_VI_ALT1,
+	TEGRA_MUX_VI_ALT2,
+	TEGRA_MUX_VI_ALT3,
+};
+static const char * const blink_groups[] = {
+	"clk_32k_out_pa0",
+};
+
+static const char * const cec_groups[] = {
+	"hdmi_cec_pee3",
+	"owr",
+};
+
+static const char * const clk_12m_out_groups[] = {
+	"pv3",
+};
+
+static const char * const clk_32k_in_groups[] = {
+	"clk_32k_in",
+};
+
+static const char * const core_pwr_req_groups[] = {
+	"core_pwr_req",
+};
+
+static const char * const cpu_pwr_req_groups[] = {
+	"cpu_pwr_req",
+};
+
+static const char * const crt_groups[] = {
+	"crt_hsync_pv6",
+	"crt_vsync_pv7",
+};
+
+static const char * const dap_groups[] = {
+	"clk1_req_pee2",
+	"clk2_req_pcc5",
+};
+
+static const char * const ddr_groups[] = {
+	"vi_d0_pt4",
+	"vi_d1_pd5",
+	"vi_d10_pt2",
+	"vi_d11_pt3",
+	"vi_d2_pl0",
+	"vi_d3_pl1",
+	"vi_d4_pl2",
+	"vi_d5_pl3",
+	"vi_d6_pl4",
+	"vi_d7_pl5",
+	"vi_d8_pl6",
+	"vi_d9_pl7",
+	"vi_hsync_pd7",
+	"vi_vsync_pd6",
+};
+
+static const char * const dev3_groups[] = {
+	"clk3_req_pee1",
+};
+
+static const char * const displaya_groups[] = {
+	"dap3_din_pp1",
+	"dap3_dout_pp2",
+	"dap3_fs_pp0",
+	"dap3_sclk_pp3",
+	"pbb3",
+	"pbb4",
+	"pbb5",
+	"pbb6",
+	"lcd_cs0_n_pn4",
+	"lcd_cs1_n_pw0",
+	"lcd_d0_pe0",
+	"lcd_d1_pe1",
+	"lcd_d10_pf2",
+	"lcd_d11_pf3",
+	"lcd_d12_pf4",
+	"lcd_d13_pf5",
+	"lcd_d14_pf6",
+	"lcd_d15_pf7",
+	"lcd_d16_pm0",
+	"lcd_d17_pm1",
+	"lcd_d18_pm2",
+	"lcd_d19_pm3",
+	"lcd_d2_pe2",
+	"lcd_d20_pm4",
+	"lcd_d21_pm5",
+	"lcd_d22_pm6",
+	"lcd_d23_pm7",
+	"lcd_d3_pe3",
+	"lcd_d4_pe4",
+	"lcd_d5_pe5",
+	"lcd_d6_pe6",
+	"lcd_d7_pe7",
+	"lcd_d8_pf0",
+	"lcd_d9_pf1",
+	"lcd_dc0_pn6",
+	"lcd_dc1_pd2",
+	"lcd_de_pj1",
+	"lcd_hsync_pj3",
+	"lcd_m1_pw1",
+	"lcd_pclk_pb3",
+	"lcd_pwr0_pb2",
+	"lcd_pwr1_pc1",
+	"lcd_pwr2_pc6",
+	"lcd_sck_pz4",
+	"lcd_sdin_pz2",
+	"lcd_sdout_pn5",
+	"lcd_vsync_pj4",
+	"lcd_wr_n_pz3",
+};
+
+static const char * const displayb_groups[] = {
+	"dap3_din_pp1",
+	"dap3_dout_pp2",
+	"dap3_fs_pp0",
+	"dap3_sclk_pp3",
+	"pbb3",
+	"pbb4",
+	"pbb5",
+	"pbb6",
+	"lcd_cs0_n_pn4",
+	"lcd_cs1_n_pw0",
+	"lcd_d0_pe0",
+	"lcd_d1_pe1",
+	"lcd_d10_pf2",
+	"lcd_d11_pf3",
+	"lcd_d12_pf4",
+	"lcd_d13_pf5",
+	"lcd_d14_pf6",
+	"lcd_d15_pf7",
+	"lcd_d16_pm0",
+	"lcd_d17_pm1",
+	"lcd_d18_pm2",
+	"lcd_d19_pm3",
+	"lcd_d2_pe2",
+	"lcd_d20_pm4",
+	"lcd_d21_pm5",
+	"lcd_d22_pm6",
+	"lcd_d23_pm7",
+	"lcd_d3_pe3",
+	"lcd_d4_pe4",
+	"lcd_d5_pe5",
+	"lcd_d6_pe6",
+	"lcd_d7_pe7",
+	"lcd_d8_pf0",
+	"lcd_d9_pf1",
+	"lcd_dc0_pn6",
+	"lcd_dc1_pd2",
+	"lcd_de_pj1",
+	"lcd_hsync_pj3",
+	"lcd_m1_pw1",
+	"lcd_pclk_pb3",
+	"lcd_pwr0_pb2",
+	"lcd_pwr1_pc1",
+	"lcd_pwr2_pc6",
+	"lcd_sck_pz4",
+	"lcd_sdin_pz2",
+	"lcd_sdout_pn5",
+	"lcd_vsync_pj4",
+	"lcd_wr_n_pz3",
+};
+
+static const char * const dtv_groups[] = {
+	"gmi_a17_pb0",
+	"gmi_a18_pb1",
+	"gmi_cs0_n_pj0",
+	"gmi_cs1_n_pj2",
+};
+
+static const char * const extperiph1_groups[] = {
+	"clk1_out_pw4",
+};
+
+static const char * const extperiph2_groups[] = {
+	"clk2_out_pw5",
+};
+
+static const char * const extperiph3_groups[] = {
+	"clk3_out_pee0",
+};
+
+static const char * const gmi_groups[] = {
+	"dap1_din_pn1",
+	"dap1_dout_pn2",
+	"dap1_fs_pn0",
+	"dap1_sclk_pn3",
+	"dap2_din_pa4",
+	"dap2_dout_pa5",
+	"dap2_fs_pa2",
+	"dap2_sclk_pa3",
+	"dap4_din_pp5",
+	"dap4_dout_pp6",
+	"dap4_fs_pp4",
+	"dap4_sclk_pp7",
+	"gen2_i2c_scl_pt5",
+	"gen2_i2c_sda_pt6",
+	"gmi_a16_pj7",
+	"gmi_a17_pb0",
+	"gmi_a18_pb1",
+	"gmi_a19_pk7",
+	"gmi_ad0_pg0",
+	"gmi_ad1_pg1",
+	"gmi_ad10_ph2",
+	"gmi_ad11_ph3",
+	"gmi_ad12_ph4",
+	"gmi_ad13_ph5",
+	"gmi_ad14_ph6",
+	"gmi_ad15_ph7",
+	"gmi_ad2_pg2",
+	"gmi_ad3_pg3",
+	"gmi_ad4_pg4",
+	"gmi_ad5_pg5",
+	"gmi_ad6_pg6",
+	"gmi_ad7_pg7",
+	"gmi_ad8_ph0",
+	"gmi_ad9_ph1",
+	"gmi_adv_n_pk0",
+	"gmi_clk_pk1",
+	"gmi_cs0_n_pj0",
+	"gmi_cs1_n_pj2",
+	"gmi_cs2_n_pk3",
+	"gmi_cs3_n_pk4",
+	"gmi_cs4_n_pk2",
+	"gmi_cs6_n_pi3",
+	"gmi_cs7_n_pi6",
+	"gmi_dqs_pi2",
+	"gmi_iordy_pi5",
+	"gmi_oe_n_pi1",
+	"gmi_rst_n_pi4",
+	"gmi_wait_pi7",
+	"gmi_wp_n_pc7",
+	"gmi_wr_n_pi0",
+	"pu0",
+	"pu1",
+	"pu2",
+	"pu3",
+	"pu4",
+	"pu5",
+	"pu6",
+	"sdmmc4_clk_pcc4",
+	"sdmmc4_cmd_pt7",
+	"sdmmc4_dat0_paa0",
+	"sdmmc4_dat1_paa1",
+	"sdmmc4_dat2_paa2",
+	"sdmmc4_dat3_paa3",
+	"sdmmc4_dat4_paa4",
+	"sdmmc4_dat5_paa5",
+	"sdmmc4_dat6_paa6",
+	"sdmmc4_dat7_paa7",
+	"spi1_cs0_n_px6",
+	"spi1_mosi_px4",
+	"spi1_sck_px5",
+	"spi2_cs0_n_px3",
+	"spi2_miso_px1",
+	"spi2_mosi_px0",
+	"spi2_sck_px2",
+	"uart2_cts_n_pj5",
+	"uart2_rts_n_pj6",
+	"uart3_cts_n_pa1",
+	"uart3_rts_n_pc0",
+	"uart3_rxd_pw7",
+	"uart3_txd_pw6",
+};
+
+static const char * const gmi_alt_groups[] = {
+	"gmi_a16_pj7",
+	"gmi_cs3_n_pk4",
+	"gmi_cs7_n_pi6",
+	"gmi_wp_n_pc7",
+};
+
+static const char * const hda_groups[] = {
+	"clk1_req_pee2",
+	"dap1_din_pn1",
+	"dap1_dout_pn2",
+	"dap1_fs_pn0",
+	"dap1_sclk_pn3",
+	"dap2_din_pa4",
+	"dap2_dout_pa5",
+	"dap2_fs_pa2",
+	"dap2_sclk_pa3",
+	"pex_l0_clkreq_n_pdd2",
+	"pex_l0_prsnt_n_pdd0",
+	"pex_l0_rst_n_pdd1",
+	"pex_l1_clkreq_n_pdd6",
+	"pex_l1_prsnt_n_pdd4",
+	"pex_l1_rst_n_pdd5",
+	"pex_l2_clkreq_n_pcc7",
+	"pex_l2_prsnt_n_pdd7",
+	"pex_l2_rst_n_pcc6",
+	"pex_wake_n_pdd3",
+	"spdif_in_pk6",
+};
+
+static const char * const hdcp_groups[] = {
+	"gen2_i2c_scl_pt5",
+	"gen2_i2c_sda_pt6",
+	"lcd_pwr0_pb2",
+	"lcd_pwr2_pc6",
+	"lcd_sck_pz4",
+	"lcd_sdout_pn5",
+	"lcd_wr_n_pz3",
+};
+
+static const char * const hdmi_groups[] = {
+	"hdmi_int_pn7",
+};
+
+static const char * const hsi_groups[] = {
+	"ulpi_data0_po1",
+	"ulpi_data1_po2",
+	"ulpi_data2_po3",
+	"ulpi_data3_po4",
+	"ulpi_data4_po5",
+	"ulpi_data5_po6",
+	"ulpi_data6_po7",
+	"ulpi_data7_po0",
+};
+
+static const char * const i2c1_groups[] = {
+	"gen1_i2c_scl_pc4",
+	"gen1_i2c_sda_pc5",
+	"spdif_in_pk6",
+	"spdif_out_pk5",
+	"spi2_cs1_n_pw2",
+	"spi2_cs2_n_pw3",
+};
+
+static const char * const i2c2_groups[] = {
+	"gen2_i2c_scl_pt5",
+	"gen2_i2c_sda_pt6",
+};
+
+static const char * const i2c3_groups[] = {
+	"cam_i2c_scl_pbb1",
+	"cam_i2c_sda_pbb2",
+	"sdmmc4_cmd_pt7",
+	"sdmmc4_dat4_paa4",
+};
+
+static const char * const i2c4_groups[] = {
+	"ddc_scl_pv4",
+	"ddc_sda_pv5",
+};
+
+static const char * const i2cpwr_groups[] = {
+	"pwr_i2c_scl_pz6",
+	"pwr_i2c_sda_pz7",
+};
+
+static const char * const i2s0_groups[] = {
+	"dap1_din_pn1",
+	"dap1_dout_pn2",
+	"dap1_fs_pn0",
+	"dap1_sclk_pn3",
+};
+
+static const char * const i2s1_groups[] = {
+	"dap2_din_pa4",
+	"dap2_dout_pa5",
+	"dap2_fs_pa2",
+	"dap2_sclk_pa3",
+};
+
+static const char * const i2s2_groups[] = {
+	"dap3_din_pp1",
+	"dap3_dout_pp2",
+	"dap3_fs_pp0",
+	"dap3_sclk_pp3",
+};
+
+static const char * const i2s3_groups[] = {
+	"dap4_din_pp5",
+	"dap4_dout_pp6",
+	"dap4_fs_pp4",
+	"dap4_sclk_pp7",
+};
+
+static const char * const i2s4_groups[] = {
+	"pbb0",
+	"pbb7",
+	"pcc1",
+	"pcc2",
+	"sdmmc4_dat4_paa4",
+	"sdmmc4_dat5_paa5",
+	"sdmmc4_dat6_paa6",
+	"sdmmc4_dat7_paa7",
+};
+
+static const char * const invalid_groups[] = {
+	"kb_row3_pr3",
+	"sdmmc4_clk_pcc4",
+};
+
+static const char * const kbc_groups[] = {
+	"kb_col0_pq0",
+	"kb_col1_pq1",
+	"kb_col2_pq2",
+	"kb_col3_pq3",
+	"kb_col4_pq4",
+	"kb_col5_pq5",
+	"kb_col6_pq6",
+	"kb_col7_pq7",
+	"kb_row0_pr0",
+	"kb_row1_pr1",
+	"kb_row10_ps2",
+	"kb_row11_ps3",
+	"kb_row12_ps4",
+	"kb_row13_ps5",
+	"kb_row14_ps6",
+	"kb_row15_ps7",
+	"kb_row2_pr2",
+	"kb_row3_pr3",
+	"kb_row4_pr4",
+	"kb_row5_pr5",
+	"kb_row6_pr6",
+	"kb_row7_pr7",
+	"kb_row8_ps0",
+	"kb_row9_ps1",
+};
+
+static const char * const mio_groups[] = {
+	"kb_col6_pq6",
+	"kb_col7_pq7",
+	"kb_row10_ps2",
+	"kb_row11_ps3",
+	"kb_row12_ps4",
+	"kb_row13_ps5",
+	"kb_row14_ps6",
+	"kb_row15_ps7",
+	"kb_row6_pr6",
+	"kb_row7_pr7",
+	"kb_row8_ps0",
+	"kb_row9_ps1",
+};
+
+static const char * const nand_groups[] = {
+	"gmi_ad0_pg0",
+	"gmi_ad1_pg1",
+	"gmi_ad10_ph2",
+	"gmi_ad11_ph3",
+	"gmi_ad12_ph4",
+	"gmi_ad13_ph5",
+	"gmi_ad14_ph6",
+	"gmi_ad15_ph7",
+	"gmi_ad2_pg2",
+	"gmi_ad3_pg3",
+	"gmi_ad4_pg4",
+	"gmi_ad5_pg5",
+	"gmi_ad6_pg6",
+	"gmi_ad7_pg7",
+	"gmi_ad8_ph0",
+	"gmi_ad9_ph1",
+	"gmi_adv_n_pk0",
+	"gmi_clk_pk1",
+	"gmi_cs0_n_pj0",
+	"gmi_cs1_n_pj2",
+	"gmi_cs2_n_pk3",
+	"gmi_cs3_n_pk4",
+	"gmi_cs4_n_pk2",
+	"gmi_cs6_n_pi3",
+	"gmi_cs7_n_pi6",
+	"gmi_dqs_pi2",
+	"gmi_iordy_pi5",
+	"gmi_oe_n_pi1",
+	"gmi_rst_n_pi4",
+	"gmi_wait_pi7",
+	"gmi_wp_n_pc7",
+	"gmi_wr_n_pi0",
+	"kb_col0_pq0",
+	"kb_col1_pq1",
+	"kb_col2_pq2",
+	"kb_col3_pq3",
+	"kb_col4_pq4",
+	"kb_col5_pq5",
+	"kb_col6_pq6",
+	"kb_col7_pq7",
+	"kb_row0_pr0",
+	"kb_row1_pr1",
+	"kb_row10_ps2",
+	"kb_row11_ps3",
+	"kb_row12_ps4",
+	"kb_row13_ps5",
+	"kb_row14_ps6",
+	"kb_row15_ps7",
+	"kb_row2_pr2",
+	"kb_row3_pr3",
+	"kb_row4_pr4",
+	"kb_row5_pr5",
+	"kb_row6_pr6",
+	"kb_row7_pr7",
+	"kb_row8_ps0",
+	"kb_row9_ps1",
+	"sdmmc4_clk_pcc4",
+	"sdmmc4_cmd_pt7",
+};
+
+static const char * const nand_alt_groups[] = {
+	"gmi_cs6_n_pi3",
+	"gmi_cs7_n_pi6",
+	"gmi_rst_n_pi4",
+};
+
+static const char * const owr_groups[] = {
+	"pu0",
+	"pv2",
+	"kb_row5_pr5",
+	"owr",
+};
+
+static const char * const pcie_groups[] = {
+	"pex_l0_clkreq_n_pdd2",
+	"pex_l0_prsnt_n_pdd0",
+	"pex_l0_rst_n_pdd1",
+	"pex_l1_clkreq_n_pdd6",
+	"pex_l1_prsnt_n_pdd4",
+	"pex_l1_rst_n_pdd5",
+	"pex_l2_clkreq_n_pcc7",
+	"pex_l2_prsnt_n_pdd7",
+	"pex_l2_rst_n_pcc6",
+	"pex_wake_n_pdd3",
+};
+
+static const char * const pwm0_groups[] = {
+	"gmi_ad8_ph0",
+	"pu3",
+	"sdmmc3_dat3_pb4",
+	"sdmmc3_dat5_pd0",
+	"uart3_rts_n_pc0",
+};
+
+static const char * const pwm1_groups[] = {
+	"gmi_ad9_ph1",
+	"pu4",
+	"sdmmc3_dat2_pb5",
+	"sdmmc3_dat4_pd1",
+};
+
+static const char * const pwm2_groups[] = {
+	"gmi_ad10_ph2",
+	"pu5",
+	"sdmmc3_clk_pa6",
+};
+
+static const char * const pwm3_groups[] = {
+	"gmi_ad11_ph3",
+	"pu6",
+	"sdmmc3_cmd_pa7",
+};
+
+static const char * const pwr_int_n_groups[] = {
+	"pwr_int_n",
+};
+
+static const char * const rsvd1_groups[] = {
+	"gmi_ad0_pg0",
+	"gmi_ad1_pg1",
+	"gmi_ad12_ph4",
+	"gmi_ad13_ph5",
+	"gmi_ad14_ph6",
+	"gmi_ad15_ph7",
+	"gmi_ad2_pg2",
+	"gmi_ad3_pg3",
+	"gmi_ad4_pg4",
+	"gmi_ad5_pg5",
+	"gmi_ad6_pg6",
+	"gmi_ad7_pg7",
+	"gmi_adv_n_pk0",
+	"gmi_clk_pk1",
+	"gmi_cs0_n_pj0",
+	"gmi_cs1_n_pj2",
+	"gmi_cs2_n_pk3",
+	"gmi_cs3_n_pk4",
+	"gmi_cs4_n_pk2",
+	"gmi_dqs_pi2",
+	"gmi_iordy_pi5",
+	"gmi_oe_n_pi1",
+	"gmi_wait_pi7",
+	"gmi_wp_n_pc7",
+	"gmi_wr_n_pi0",
+	"pu1",
+	"pu2",
+	"pv0",
+	"pv1",
+	"sdmmc3_dat0_pb7",
+	"sdmmc3_dat1_pb6",
+	"sdmmc3_dat2_pb5",
+	"sdmmc3_dat3_pb4",
+	"vi_pclk_pt0",
+};
+
+static const char * const rsvd2_groups[] = {
+	"clk1_out_pw4",
+	"clk2_out_pw5",
+	"clk2_req_pcc5",
+	"clk3_out_pee0",
+	"clk3_req_pee1",
+	"clk_32k_in",
+	"clk_32k_out_pa0",
+	"core_pwr_req",
+	"cpu_pwr_req",
+	"crt_hsync_pv6",
+	"crt_vsync_pv7",
+	"dap3_din_pp1",
+	"dap3_dout_pp2",
+	"dap3_fs_pp0",
+	"dap3_sclk_pp3",
+	"dap4_din_pp5",
+	"dap4_dout_pp6",
+	"dap4_fs_pp4",
+	"dap4_sclk_pp7",
+	"ddc_scl_pv4",
+	"ddc_sda_pv5",
+	"gen1_i2c_scl_pc4",
+	"gen1_i2c_sda_pc5",
+	"pbb0",
+	"pbb7",
+	"pcc1",
+	"pcc2",
+	"pv0",
+	"pv1",
+	"pv2",
+	"pv3",
+	"hdmi_cec_pee3",
+	"hdmi_int_pn7",
+	"jtag_rtck_pu7",
+	"pwr_i2c_scl_pz6",
+	"pwr_i2c_sda_pz7",
+	"pwr_int_n",
+	"sdmmc1_clk_pz0",
+	"sdmmc1_cmd_pz1",
+	"sdmmc1_dat0_py7",
+	"sdmmc1_dat1_py6",
+	"sdmmc1_dat2_py5",
+	"sdmmc1_dat3_py4",
+	"sdmmc3_dat0_pb7",
+	"sdmmc3_dat1_pb6",
+	"sdmmc4_rst_n_pcc3",
+	"spdif_out_pk5",
+	"sys_clk_req_pz5",
+	"uart3_cts_n_pa1",
+	"uart3_rxd_pw7",
+	"uart3_txd_pw6",
+	"ulpi_clk_py0",
+	"ulpi_dir_py1",
+	"ulpi_nxt_py2",
+	"ulpi_stp_py3",
+	"vi_d0_pt4",
+	"vi_d10_pt2",
+	"vi_d11_pt3",
+	"vi_hsync_pd7",
+	"vi_vsync_pd6",
+};
+
+static const char * const rsvd3_groups[] = {
+	"cam_i2c_scl_pbb1",
+	"cam_i2c_sda_pbb2",
+	"clk1_out_pw4",
+	"clk1_req_pee2",
+	"clk2_out_pw5",
+	"clk2_req_pcc5",
+	"clk3_out_pee0",
+	"clk3_req_pee1",
+	"clk_32k_in",
+	"clk_32k_out_pa0",
+	"core_pwr_req",
+	"cpu_pwr_req",
+	"crt_hsync_pv6",
+	"crt_vsync_pv7",
+	"dap2_din_pa4",
+	"dap2_dout_pa5",
+	"dap2_fs_pa2",
+	"dap2_sclk_pa3",
+	"ddc_scl_pv4",
+	"ddc_sda_pv5",
+	"gen1_i2c_scl_pc4",
+	"gen1_i2c_sda_pc5",
+	"pbb0",
+	"pbb7",
+	"pcc1",
+	"pcc2",
+	"pv0",
+	"pv1",
+	"pv2",
+	"pv3",
+	"hdmi_cec_pee3",
+	"hdmi_int_pn7",
+	"jtag_rtck_pu7",
+	"kb_row0_pr0",
+	"kb_row1_pr1",
+	"kb_row2_pr2",
+	"kb_row3_pr3",
+	"lcd_d0_pe0",
+	"lcd_d1_pe1",
+	"lcd_d10_pf2",
+	"lcd_d11_pf3",
+	"lcd_d12_pf4",
+	"lcd_d13_pf5",
+	"lcd_d14_pf6",
+	"lcd_d15_pf7",
+	"lcd_d16_pm0",
+	"lcd_d17_pm1",
+	"lcd_d18_pm2",
+	"lcd_d19_pm3",
+	"lcd_d2_pe2",
+	"lcd_d20_pm4",
+	"lcd_d21_pm5",
+	"lcd_d22_pm6",
+	"lcd_d23_pm7",
+	"lcd_d3_pe3",
+	"lcd_d4_pe4",
+	"lcd_d5_pe5",
+	"lcd_d6_pe6",
+	"lcd_d7_pe7",
+	"lcd_d8_pf0",
+	"lcd_d9_pf1",
+	"lcd_dc0_pn6",
+	"lcd_dc1_pd2",
+	"lcd_de_pj1",
+	"lcd_hsync_pj3",
+	"lcd_m1_pw1",
+	"lcd_pclk_pb3",
+	"lcd_pwr1_pc1",
+	"lcd_vsync_pj4",
+	"owr",
+	"pex_l0_clkreq_n_pdd2",
+	"pex_l0_prsnt_n_pdd0",
+	"pex_l0_rst_n_pdd1",
+	"pex_l1_clkreq_n_pdd6",
+	"pex_l1_prsnt_n_pdd4",
+	"pex_l1_rst_n_pdd5",
+	"pex_l2_clkreq_n_pcc7",
+	"pex_l2_prsnt_n_pdd7",
+	"pex_l2_rst_n_pcc6",
+	"pex_wake_n_pdd3",
+	"pwr_i2c_scl_pz6",
+	"pwr_i2c_sda_pz7",
+	"pwr_int_n",
+	"sdmmc1_clk_pz0",
+	"sdmmc1_cmd_pz1",
+	"sdmmc4_rst_n_pcc3",
+	"sys_clk_req_pz5",
+};
+
+static const char * const rsvd4_groups[] = {
+	"clk1_out_pw4",
+	"clk1_req_pee2",
+	"clk2_out_pw5",
+	"clk2_req_pcc5",
+	"clk3_out_pee0",
+	"clk3_req_pee1",
+	"clk_32k_in",
+	"clk_32k_out_pa0",
+	"core_pwr_req",
+	"cpu_pwr_req",
+	"crt_hsync_pv6",
+	"crt_vsync_pv7",
+	"dap4_din_pp5",
+	"dap4_dout_pp6",
+	"dap4_fs_pp4",
+	"dap4_sclk_pp7",
+	"ddc_scl_pv4",
+	"ddc_sda_pv5",
+	"gen1_i2c_scl_pc4",
+	"gen1_i2c_sda_pc5",
+	"gen2_i2c_scl_pt5",
+	"gen2_i2c_sda_pt6",
+	"gmi_a19_pk7",
+	"gmi_ad0_pg0",
+	"gmi_ad1_pg1",
+	"gmi_ad10_ph2",
+	"gmi_ad11_ph3",
+	"gmi_ad12_ph4",
+	"gmi_ad13_ph5",
+	"gmi_ad14_ph6",
+	"gmi_ad15_ph7",
+	"gmi_ad2_pg2",
+	"gmi_ad3_pg3",
+	"gmi_ad4_pg4",
+	"gmi_ad5_pg5",
+	"gmi_ad6_pg6",
+	"gmi_ad7_pg7",
+	"gmi_ad8_ph0",
+	"gmi_ad9_ph1",
+	"gmi_adv_n_pk0",
+	"gmi_clk_pk1",
+	"gmi_cs2_n_pk3",
+	"gmi_cs4_n_pk2",
+	"gmi_dqs_pi2",
+	"gmi_iordy_pi5",
+	"gmi_oe_n_pi1",
+	"gmi_rst_n_pi4",
+	"gmi_wait_pi7",
+	"gmi_wr_n_pi0",
+	"pcc2",
+	"pu0",
+	"pu1",
+	"pu2",
+	"pu3",
+	"pu4",
+	"pu5",
+	"pu6",
+	"pv0",
+	"pv1",
+	"pv2",
+	"pv3",
+	"hdmi_cec_pee3",
+	"hdmi_int_pn7",
+	"jtag_rtck_pu7",
+	"kb_col2_pq2",
+	"kb_col3_pq3",
+	"kb_col4_pq4",
+	"kb_col5_pq5",
+	"kb_row0_pr0",
+	"kb_row1_pr1",
+	"kb_row2_pr2",
+	"kb_row4_pr4",
+	"lcd_cs0_n_pn4",
+	"lcd_cs1_n_pw0",
+	"lcd_d0_pe0",
+	"lcd_d1_pe1",
+	"lcd_d10_pf2",
+	"lcd_d11_pf3",
+	"lcd_d12_pf4",
+	"lcd_d13_pf5",
+	"lcd_d14_pf6",
+	"lcd_d15_pf7",
+	"lcd_d16_pm0",
+	"lcd_d17_pm1",
+	"lcd_d18_pm2",
+	"lcd_d19_pm3",
+	"lcd_d2_pe2",
+	"lcd_d20_pm4",
+	"lcd_d21_pm5",
+	"lcd_d22_pm6",
+	"lcd_d23_pm7",
+	"lcd_d3_pe3",
+	"lcd_d4_pe4",
+	"lcd_d5_pe5",
+	"lcd_d6_pe6",
+	"lcd_d7_pe7",
+	"lcd_d8_pf0",
+	"lcd_d9_pf1",
+	"lcd_dc0_pn6",
+	"lcd_dc1_pd2",
+	"lcd_de_pj1",
+	"lcd_hsync_pj3",
+	"lcd_m1_pw1",
+	"lcd_pclk_pb3",
+	"lcd_pwr1_pc1",
+	"lcd_sdin_pz2",
+	"lcd_vsync_pj4",
+	"owr",
+	"pex_l0_clkreq_n_pdd2",
+	"pex_l0_prsnt_n_pdd0",
+	"pex_l0_rst_n_pdd1",
+	"pex_l1_clkreq_n_pdd6",
+	"pex_l1_prsnt_n_pdd4",
+	"pex_l1_rst_n_pdd5",
+	"pex_l2_clkreq_n_pcc7",
+	"pex_l2_prsnt_n_pdd7",
+	"pex_l2_rst_n_pcc6",
+	"pex_wake_n_pdd3",
+	"pwr_i2c_scl_pz6",
+	"pwr_i2c_sda_pz7",
+	"pwr_int_n",
+	"spi1_miso_px7",
+	"sys_clk_req_pz5",
+	"uart3_cts_n_pa1",
+	"uart3_rts_n_pc0",
+	"uart3_rxd_pw7",
+	"uart3_txd_pw6",
+	"vi_d0_pt4",
+	"vi_d1_pd5",
+	"vi_d10_pt2",
+	"vi_d11_pt3",
+	"vi_d2_pl0",
+	"vi_d3_pl1",
+	"vi_d4_pl2",
+	"vi_d5_pl3",
+	"vi_d6_pl4",
+	"vi_d7_pl5",
+	"vi_d8_pl6",
+	"vi_d9_pl7",
+	"vi_hsync_pd7",
+	"vi_pclk_pt0",
+	"vi_vsync_pd6",
+};
+
+static const char * const rtck_groups[] = {
+	"jtag_rtck_pu7",
+};
+
+static const char * const sata_groups[] = {
+	"gmi_cs6_n_pi3",
+};
+
+static const char * const sdmmc1_groups[] = {
+	"sdmmc1_clk_pz0",
+	"sdmmc1_cmd_pz1",
+	"sdmmc1_dat0_py7",
+	"sdmmc1_dat1_py6",
+	"sdmmc1_dat2_py5",
+	"sdmmc1_dat3_py4",
+};
+
+static const char * const sdmmc2_groups[] = {
+	"dap1_din_pn1",
+	"dap1_dout_pn2",
+	"dap1_fs_pn0",
+	"dap1_sclk_pn3",
+	"kb_row10_ps2",
+	"kb_row11_ps3",
+	"kb_row12_ps4",
+	"kb_row13_ps5",
+	"kb_row14_ps6",
+	"kb_row15_ps7",
+	"kb_row6_pr6",
+	"kb_row7_pr7",
+	"kb_row8_ps0",
+	"kb_row9_ps1",
+	"spdif_in_pk6",
+	"spdif_out_pk5",
+	"vi_d1_pd5",
+	"vi_d2_pl0",
+	"vi_d3_pl1",
+	"vi_d4_pl2",
+	"vi_d5_pl3",
+	"vi_d6_pl4",
+	"vi_d7_pl5",
+	"vi_d8_pl6",
+	"vi_d9_pl7",
+	"vi_pclk_pt0",
+};
+
+static const char * const sdmmc3_groups[] = {
+	"sdmmc3_clk_pa6",
+	"sdmmc3_cmd_pa7",
+	"sdmmc3_dat0_pb7",
+	"sdmmc3_dat1_pb6",
+	"sdmmc3_dat2_pb5",
+	"sdmmc3_dat3_pb4",
+	"sdmmc3_dat4_pd1",
+	"sdmmc3_dat5_pd0",
+	"sdmmc3_dat6_pd3",
+	"sdmmc3_dat7_pd4",
+};
+
+static const char * const sdmmc4_groups[] = {
+	"cam_i2c_scl_pbb1",
+	"cam_i2c_sda_pbb2",
+	"cam_mclk_pcc0",
+	"pbb0",
+	"pbb3",
+	"pbb4",
+	"pbb5",
+	"pbb6",
+	"pbb7",
+	"pcc1",
+	"sdmmc4_clk_pcc4",
+	"sdmmc4_cmd_pt7",
+	"sdmmc4_dat0_paa0",
+	"sdmmc4_dat1_paa1",
+	"sdmmc4_dat2_paa2",
+	"sdmmc4_dat3_paa3",
+	"sdmmc4_dat4_paa4",
+	"sdmmc4_dat5_paa5",
+	"sdmmc4_dat6_paa6",
+	"sdmmc4_dat7_paa7",
+	"sdmmc4_rst_n_pcc3",
+};
+
+static const char * const spdif_groups[] = {
+	"sdmmc3_dat6_pd3",
+	"sdmmc3_dat7_pd4",
+	"spdif_in_pk6",
+	"spdif_out_pk5",
+	"uart2_rxd_pc3",
+	"uart2_txd_pc2",
+};
+
+static const char * const spi1_groups[] = {
+	"spi1_cs0_n_px6",
+	"spi1_miso_px7",
+	"spi1_mosi_px4",
+	"spi1_sck_px5",
+	"ulpi_clk_py0",
+	"ulpi_dir_py1",
+	"ulpi_nxt_py2",
+	"ulpi_stp_py3",
+};
+
+static const char * const spi2_groups[] = {
+	"sdmmc3_cmd_pa7",
+	"sdmmc3_dat4_pd1",
+	"sdmmc3_dat5_pd0",
+	"sdmmc3_dat6_pd3",
+	"sdmmc3_dat7_pd4",
+	"spi1_cs0_n_px6",
+	"spi1_mosi_px4",
+	"spi1_sck_px5",
+	"spi2_cs0_n_px3",
+	"spi2_cs1_n_pw2",
+	"spi2_cs2_n_pw3",
+	"spi2_miso_px1",
+	"spi2_mosi_px0",
+	"spi2_sck_px2",
+	"ulpi_data4_po5",
+	"ulpi_data5_po6",
+	"ulpi_data6_po7",
+	"ulpi_data7_po0",
+};
+
+static const char * const spi2_alt_groups[] = {
+	"spi1_cs0_n_px6",
+	"spi1_miso_px7",
+	"spi1_mosi_px4",
+	"spi1_sck_px5",
+	"spi2_cs1_n_pw2",
+	"spi2_cs2_n_pw3",
+};
+
+static const char * const spi3_groups[] = {
+	"sdmmc3_clk_pa6",
+	"sdmmc3_dat0_pb7",
+	"sdmmc3_dat1_pb6",
+	"sdmmc3_dat2_pb5",
+	"sdmmc3_dat3_pb4",
+	"sdmmc4_dat0_paa0",
+	"sdmmc4_dat1_paa1",
+	"sdmmc4_dat2_paa2",
+	"sdmmc4_dat3_paa3",
+	"spi1_miso_px7",
+	"spi2_cs0_n_px3",
+	"spi2_cs1_n_pw2",
+	"spi2_cs2_n_pw3",
+	"spi2_miso_px1",
+	"spi2_mosi_px0",
+	"spi2_sck_px2",
+	"ulpi_data0_po1",
+	"ulpi_data1_po2",
+	"ulpi_data2_po3",
+	"ulpi_data3_po4",
+};
+
+static const char * const spi4_groups[] = {
+	"gmi_a16_pj7",
+	"gmi_a17_pb0",
+	"gmi_a18_pb1",
+	"gmi_a19_pk7",
+	"sdmmc3_dat4_pd1",
+	"sdmmc3_dat5_pd0",
+	"sdmmc3_dat6_pd3",
+	"sdmmc3_dat7_pd4",
+	"uart2_cts_n_pj5",
+	"uart2_rts_n_pj6",
+	"uart2_rxd_pc3",
+	"uart2_txd_pc2",
+};
+
+static const char * const spi5_groups[] = {
+	"lcd_cs0_n_pn4",
+	"lcd_cs1_n_pw0",
+	"lcd_pwr0_pb2",
+	"lcd_pwr2_pc6",
+	"lcd_sck_pz4",
+	"lcd_sdin_pz2",
+	"lcd_sdout_pn5",
+	"lcd_wr_n_pz3",
+};
+
+static const char * const spi6_groups[] = {
+	"spi2_cs0_n_px3",
+	"spi2_miso_px1",
+	"spi2_mosi_px0",
+	"spi2_sck_px2",
+};
+
+static const char * const sysclk_groups[] = {
+	"sys_clk_req_pz5",
+};
+
+static const char * const test_groups[] = {
+	"kb_col0_pq0",
+	"kb_col1_pq1",
+};
+
+static const char * const trace_groups[] = {
+	"kb_col0_pq0",
+	"kb_col1_pq1",
+	"kb_col2_pq2",
+	"kb_col3_pq3",
+	"kb_col4_pq4",
+	"kb_col5_pq5",
+	"kb_col6_pq6",
+	"kb_col7_pq7",
+	"kb_row4_pr4",
+	"kb_row5_pr5",
+};
+
+static const char * const uarta_groups[] = {
+	"pu0",
+	"pu1",
+	"pu2",
+	"pu3",
+	"pu4",
+	"pu5",
+	"pu6",
+	"sdmmc1_clk_pz0",
+	"sdmmc1_cmd_pz1",
+	"sdmmc1_dat0_py7",
+	"sdmmc1_dat1_py6",
+	"sdmmc1_dat2_py5",
+	"sdmmc1_dat3_py4",
+	"sdmmc3_clk_pa6",
+	"sdmmc3_cmd_pa7",
+	"uart2_cts_n_pj5",
+	"uart2_rts_n_pj6",
+	"uart2_rxd_pc3",
+	"uart2_txd_pc2",
+	"ulpi_data0_po1",
+	"ulpi_data1_po2",
+	"ulpi_data2_po3",
+	"ulpi_data3_po4",
+	"ulpi_data4_po5",
+	"ulpi_data5_po6",
+	"ulpi_data6_po7",
+	"ulpi_data7_po0",
+};
+
+static const char * const uartb_groups[] = {
+	"uart2_cts_n_pj5",
+	"uart2_rts_n_pj6",
+	"uart2_rxd_pc3",
+	"uart2_txd_pc2",
+};
+
+static const char * const uartc_groups[] = {
+	"uart3_cts_n_pa1",
+	"uart3_rts_n_pc0",
+	"uart3_rxd_pw7",
+	"uart3_txd_pw6",
+};
+
+static const char * const uartd_groups[] = {
+	"gmi_a16_pj7",
+	"gmi_a17_pb0",
+	"gmi_a18_pb1",
+	"gmi_a19_pk7",
+	"ulpi_clk_py0",
+	"ulpi_dir_py1",
+	"ulpi_nxt_py2",
+	"ulpi_stp_py3",
+};
+
+static const char * const uarte_groups[] = {
+	"sdmmc1_dat0_py7",
+	"sdmmc1_dat1_py6",
+	"sdmmc1_dat2_py5",
+	"sdmmc1_dat3_py4",
+	"sdmmc4_dat0_paa0",
+	"sdmmc4_dat1_paa1",
+	"sdmmc4_dat2_paa2",
+	"sdmmc4_dat3_paa3",
+};
+
+static const char * const ulpi_groups[] = {
+	"ulpi_clk_py0",
+	"ulpi_data0_po1",
+	"ulpi_data1_po2",
+	"ulpi_data2_po3",
+	"ulpi_data3_po4",
+	"ulpi_data4_po5",
+	"ulpi_data5_po6",
+	"ulpi_data6_po7",
+	"ulpi_data7_po0",
+	"ulpi_dir_py1",
+	"ulpi_nxt_py2",
+	"ulpi_stp_py3",
+};
+
+static const char * const vgp1_groups[] = {
+	"cam_i2c_scl_pbb1",
+};
+
+static const char * const vgp2_groups[] = {
+	"cam_i2c_sda_pbb2",
+};
+
+static const char * const vgp3_groups[] = {
+	"pbb3",
+	"sdmmc4_dat5_paa5",
+};
+
+static const char * const vgp4_groups[] = {
+	"pbb4",
+	"sdmmc4_dat6_paa6",
+};
+
+static const char * const vgp5_groups[] = {
+	"pbb5",
+	"sdmmc4_dat7_paa7",
+};
+
+static const char * const vgp6_groups[] = {
+	"pbb6",
+	"sdmmc4_rst_n_pcc3",
+};
+
+static const char * const vi_groups[] = {
+	"cam_mclk_pcc0",
+	"vi_d0_pt4",
+	"vi_d1_pd5",
+	"vi_d10_pt2",
+	"vi_d11_pt3",
+	"vi_d2_pl0",
+	"vi_d3_pl1",
+	"vi_d4_pl2",
+	"vi_d5_pl3",
+	"vi_d6_pl4",
+	"vi_d7_pl5",
+	"vi_d8_pl6",
+	"vi_d9_pl7",
+	"vi_hsync_pd7",
+	"vi_mclk_pt1",
+	"vi_pclk_pt0",
+	"vi_vsync_pd6",
+};
+
+static const char * const vi_alt1_groups[] = {
+	"cam_mclk_pcc0",
+	"vi_mclk_pt1",
+};
+
+static const char * const vi_alt2_groups[] = {
+	"vi_mclk_pt1",
+};
+
+static const char * const vi_alt3_groups[] = {
+	"cam_mclk_pcc0",
+	"vi_mclk_pt1",
+};
+
+#define FUNCTION(fname)					\
+	{						\
+		.name = #fname,				\
+		.groups = fname##_groups,		\
+		.ngroups = ARRAY_SIZE(fname##_groups),	\
+	}
+
+static const struct tegra_function tegra30_functions[] = {
+	FUNCTION(blink),
+	FUNCTION(cec),
+	FUNCTION(clk_12m_out),
+	FUNCTION(clk_32k_in),
+	FUNCTION(core_pwr_req),
+	FUNCTION(cpu_pwr_req),
+	FUNCTION(crt),
+	FUNCTION(dap),
+	FUNCTION(ddr),
+	FUNCTION(dev3),
+	FUNCTION(displaya),
+	FUNCTION(displayb),
+	FUNCTION(dtv),
+	FUNCTION(extperiph1),
+	FUNCTION(extperiph2),
+	FUNCTION(extperiph3),
+	FUNCTION(gmi),
+	FUNCTION(gmi_alt),
+	FUNCTION(hda),
+	FUNCTION(hdcp),
+	FUNCTION(hdmi),
+	FUNCTION(hsi),
+	FUNCTION(i2c1),
+	FUNCTION(i2c2),
+	FUNCTION(i2c3),
+	FUNCTION(i2c4),
+	FUNCTION(i2cpwr),
+	FUNCTION(i2s0),
+	FUNCTION(i2s1),
+	FUNCTION(i2s2),
+	FUNCTION(i2s3),
+	FUNCTION(i2s4),
+	FUNCTION(invalid),
+	FUNCTION(kbc),
+	FUNCTION(mio),
+	FUNCTION(nand),
+	FUNCTION(nand_alt),
+	FUNCTION(owr),
+	FUNCTION(pcie),
+	FUNCTION(pwm0),
+	FUNCTION(pwm1),
+	FUNCTION(pwm2),
+	FUNCTION(pwm3),
+	FUNCTION(pwr_int_n),
+	FUNCTION(rsvd1),
+	FUNCTION(rsvd2),
+	FUNCTION(rsvd3),
+	FUNCTION(rsvd4),
+	FUNCTION(rtck),
+	FUNCTION(sata),
+	FUNCTION(sdmmc1),
+	FUNCTION(sdmmc2),
+	FUNCTION(sdmmc3),
+	FUNCTION(sdmmc4),
+	FUNCTION(spdif),
+	FUNCTION(spi1),
+	FUNCTION(spi2),
+	FUNCTION(spi2_alt),
+	FUNCTION(spi3),
+	FUNCTION(spi4),
+	FUNCTION(spi5),
+	FUNCTION(spi6),
+	FUNCTION(sysclk),
+	FUNCTION(test),
+	FUNCTION(trace),
+	FUNCTION(uarta),
+	FUNCTION(uartb),
+	FUNCTION(uartc),
+	FUNCTION(uartd),
+	FUNCTION(uarte),
+	FUNCTION(ulpi),
+	FUNCTION(vgp1),
+	FUNCTION(vgp2),
+	FUNCTION(vgp3),
+	FUNCTION(vgp4),
+	FUNCTION(vgp5),
+	FUNCTION(vgp6),
+	FUNCTION(vi),
+	FUNCTION(vi_alt1),
+	FUNCTION(vi_alt2),
+	FUNCTION(vi_alt3),
+};
+
+#define MUXCTL_REG_A	0x3000
+#define PINGROUP_REG_A	0x868
+
+#define PINGROUP_REG_Y(r) ((r) - MUXCTL_REG_A)
+#define PINGROUP_REG_N(r) -1
+
+#define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior)	\
+	{							\
+		.name = #pg_name,				\
+		.pins = pg_name##_pins,				\
+		.npins = ARRAY_SIZE(pg_name##_pins),		\
+		.funcs = {					\
+			TEGRA_MUX_ ## f0,			\
+			TEGRA_MUX_ ## f1,			\
+			TEGRA_MUX_ ## f2,			\
+			TEGRA_MUX_ ## f3,			\
+		},						\
+		.func_safe = TEGRA_MUX_ ## f_safe,		\
+		.mux_reg = PINGROUP_REG_Y(r),			\
+		.mux_bank = 0,					\
+		.mux_bit = 0,					\
+		.pupd_reg = PINGROUP_REG_Y(r),			\
+		.pupd_bank = 0,					\
+		.pupd_bit = 2,					\
+		.tri_reg = PINGROUP_REG_Y(r),			\
+		.tri_bank = 0,					\
+		.tri_bit = 4,					\
+		.einput_reg = PINGROUP_REG_Y(r),		\
+		.einput_bank = 0,				\
+		.einput_bit = 5,				\
+		.odrain_reg = PINGROUP_REG_##od(r),		\
+		.odrain_bank = 0,				\
+		.odrain_bit = 6,				\
+		.lock_reg = PINGROUP_REG_Y(r),			\
+		.lock_bank = 0,					\
+		.lock_bit = 7,					\
+		.ioreset_reg = PINGROUP_REG_##ior(r),		\
+		.ioreset_bank = 0,				\
+		.ioreset_bit = 8,				\
+		.drv_reg = -1,					\
+	}
+
+#define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b,	\
+		     drvdn_b, drvdn_w, drvup_b, drvup_w,	\
+		     slwr_b, slwr_w, slwf_b, slwf_w)		\
+	{							\
+		.name = "drive_" #pg_name,			\
+		.pins = drive_##pg_name##_pins,			\
+		.npins = ARRAY_SIZE(drive_##pg_name##_pins),	\
+		.mux_reg = -1,					\
+		.pupd_reg = -1,					\
+		.tri_reg = -1,					\
+		.einput_reg = -1,				\
+		.odrain_reg = -1,				\
+		.lock_reg = -1,					\
+		.ioreset_reg = -1,				\
+		.drv_reg = ((r) - PINGROUP_REG_A),		\
+		.drv_bank = 1,					\
+		.hsm_bit = hsm_b,				\
+		.schmitt_bit = schmitt_b,			\
+		.lpmd_bit = lpmd_b,				\
+		.drvdn_bit = drvdn_b,				\
+		.drvdn_width = drvdn_w,				\
+		.drvup_bit = drvup_b,				\
+		.drvup_width = drvup_w,				\
+		.slwr_bit = slwr_b,				\
+		.slwr_width = slwr_w,				\
+		.slwf_bit = slwf_b,				\
+		.slwf_width = slwf_w,				\
+	}
+
+static const struct tegra_pingroup tegra30_groups[] = {
+	/*       pg_name,              f0,           f1,           f2,           f3,           safe,         r,      od, ior */
+	/* FIXME: Fill in correct data in safe column */
+	PINGROUP(clk_32k_out_pa0,      BLINK,        RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x331c, N, N),
+	PINGROUP(uart3_cts_n_pa1,      UARTC,        RSVD2,        GMI,          RSVD4,        RSVD4,        0x317c, N, N),
+	PINGROUP(dap2_fs_pa2,          I2S1,         HDA,          RSVD3,        GMI,          RSVD3,        0x3358, N, N),
+	PINGROUP(dap2_sclk_pa3,        I2S1,         HDA,          RSVD3,        GMI,          RSVD3,        0x3364, N, N),
+	PINGROUP(dap2_din_pa4,         I2S1,         HDA,          RSVD3,        GMI,          RSVD3,        0x335c, N, N),
+	PINGROUP(dap2_dout_pa5,        I2S1,         HDA,          RSVD3,        GMI,          RSVD3,        0x3360, N, N),
+	PINGROUP(sdmmc3_clk_pa6,       UARTA,        PWM2,         SDMMC3,       SPI3,         SPI3,         0x3390, N, N),
+	PINGROUP(sdmmc3_cmd_pa7,       UARTA,        PWM3,         SDMMC3,       SPI2,         SPI2,         0x3394, N, N),
+	PINGROUP(gmi_a17_pb0,          UARTD,        SPI4,         GMI,          DTV,          DTV,          0x3234, N, N),
+	PINGROUP(gmi_a18_pb1,          UARTD,        SPI4,         GMI,          DTV,          DTV,          0x3238, N, N),
+	PINGROUP(lcd_pwr0_pb2,         DISPLAYA,     DISPLAYB,     SPI5,         HDCP,         HDCP,         0x3090, N, N),
+	PINGROUP(lcd_pclk_pb3,         DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x3094, N, N),
+	PINGROUP(sdmmc3_dat3_pb4,      RSVD1,        PWM0,         SDMMC3,       SPI3,         RSVD1,        0x33a4, N, N),
+	PINGROUP(sdmmc3_dat2_pb5,      RSVD1,        PWM1,         SDMMC3,       SPI3,         RSVD1,        0x33a0, N, N),
+	PINGROUP(sdmmc3_dat1_pb6,      RSVD1,        RSVD2,        SDMMC3,       SPI3,         RSVD2,        0x339c, N, N),
+	PINGROUP(sdmmc3_dat0_pb7,      RSVD1,        RSVD2,        SDMMC3,       SPI3,         RSVD2,        0x3398, N, N),
+	PINGROUP(uart3_rts_n_pc0,      UARTC,        PWM0,         GMI,          RSVD4,        RSVD4,        0x3180, N, N),
+	PINGROUP(lcd_pwr1_pc1,         DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x3070, N, N),
+	PINGROUP(uart2_txd_pc2,        UARTB,        SPDIF,        UARTA,        SPI4,         SPI4,         0x3168, N, N),
+	PINGROUP(uart2_rxd_pc3,        UARTB,        SPDIF,        UARTA,        SPI4,         SPI4,         0x3164, N, N),
+	PINGROUP(gen1_i2c_scl_pc4,     I2C1,         RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x31a4, Y, N),
+	PINGROUP(gen1_i2c_sda_pc5,     I2C1,         RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x31a0, Y, N),
+	PINGROUP(lcd_pwr2_pc6,         DISPLAYA,     DISPLAYB,     SPI5,         HDCP,         HDCP,         0x3074, N, N),
+	PINGROUP(gmi_wp_n_pc7,         RSVD1,        NAND,         GMI,          GMI_ALT,      RSVD1,        0x31c0, N, N),
+	PINGROUP(sdmmc3_dat5_pd0,      PWM0,         SPI4,         SDMMC3,       SPI2,         SPI2,         0x33ac, N, N),
+	PINGROUP(sdmmc3_dat4_pd1,      PWM1,         SPI4,         SDMMC3,       SPI2,         SPI2,         0x33a8, N, N),
+	PINGROUP(lcd_dc1_pd2,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x310c, N, N),
+	PINGROUP(sdmmc3_dat6_pd3,      SPDIF,        SPI4,         SDMMC3,       SPI2,         SPI2,         0x33b0, N, N),
+	PINGROUP(sdmmc3_dat7_pd4,      SPDIF,        SPI4,         SDMMC3,       SPI2,         SPI2,         0x33b4, N, N),
+	PINGROUP(vi_d1_pd5,            DDR,          SDMMC2,       VI,           RSVD4,        RSVD4,        0x3128, N, Y),
+	PINGROUP(vi_vsync_pd6,         DDR,          RSVD2,        VI,           RSVD4,        RSVD4,        0x315c, N, Y),
+	PINGROUP(vi_hsync_pd7,         DDR,          RSVD2,        VI,           RSVD4,        RSVD4,        0x3160, N, Y),
+	PINGROUP(lcd_d0_pe0,           DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30a4, N, N),
+	PINGROUP(lcd_d1_pe1,           DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30a8, N, N),
+	PINGROUP(lcd_d2_pe2,           DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30ac, N, N),
+	PINGROUP(lcd_d3_pe3,           DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30b0, N, N),
+	PINGROUP(lcd_d4_pe4,           DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30b4, N, N),
+	PINGROUP(lcd_d5_pe5,           DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30b8, N, N),
+	PINGROUP(lcd_d6_pe6,           DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30bc, N, N),
+	PINGROUP(lcd_d7_pe7,           DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30c0, N, N),
+	PINGROUP(lcd_d8_pf0,           DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30c4, N, N),
+	PINGROUP(lcd_d9_pf1,           DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30c8, N, N),
+	PINGROUP(lcd_d10_pf2,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30cc, N, N),
+	PINGROUP(lcd_d11_pf3,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30d0, N, N),
+	PINGROUP(lcd_d12_pf4,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30d4, N, N),
+	PINGROUP(lcd_d13_pf5,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30d8, N, N),
+	PINGROUP(lcd_d14_pf6,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30dc, N, N),
+	PINGROUP(lcd_d15_pf7,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30e0, N, N),
+	PINGROUP(gmi_ad0_pg0,          RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x31f0, N, N),
+	PINGROUP(gmi_ad1_pg1,          RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x31f4, N, N),
+	PINGROUP(gmi_ad2_pg2,          RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x31f8, N, N),
+	PINGROUP(gmi_ad3_pg3,          RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x31fc, N, N),
+	PINGROUP(gmi_ad4_pg4,          RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x3200, N, N),
+	PINGROUP(gmi_ad5_pg5,          RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x3204, N, N),
+	PINGROUP(gmi_ad6_pg6,          RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x3208, N, N),
+	PINGROUP(gmi_ad7_pg7,          RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x320c, N, N),
+	PINGROUP(gmi_ad8_ph0,          PWM0,         NAND,         GMI,          RSVD4,        RSVD4,        0x3210, N, N),
+	PINGROUP(gmi_ad9_ph1,          PWM1,         NAND,         GMI,          RSVD4,        RSVD4,        0x3214, N, N),
+	PINGROUP(gmi_ad10_ph2,         PWM2,         NAND,         GMI,          RSVD4,        RSVD4,        0x3218, N, N),
+	PINGROUP(gmi_ad11_ph3,         PWM3,         NAND,         GMI,          RSVD4,        RSVD4,        0x321c, N, N),
+	PINGROUP(gmi_ad12_ph4,         RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x3220, N, N),
+	PINGROUP(gmi_ad13_ph5,         RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x3224, N, N),
+	PINGROUP(gmi_ad14_ph6,         RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x3228, N, N),
+	PINGROUP(gmi_ad15_ph7,         RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x322c, N, N),
+	PINGROUP(gmi_wr_n_pi0,         RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x3240, N, N),
+	PINGROUP(gmi_oe_n_pi1,         RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x3244, N, N),
+	PINGROUP(gmi_dqs_pi2,          RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x3248, N, N),
+	PINGROUP(gmi_cs6_n_pi3,        NAND,         NAND_ALT,     GMI,          SATA,         SATA,         0x31e8, N, N),
+	PINGROUP(gmi_rst_n_pi4,        NAND,         NAND_ALT,     GMI,          RSVD4,        RSVD4,        0x324c, N, N),
+	PINGROUP(gmi_iordy_pi5,        RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x31c4, N, N),
+	PINGROUP(gmi_cs7_n_pi6,        NAND,         NAND_ALT,     GMI,          GMI_ALT,      GMI_ALT,      0x31ec, N, N),
+	PINGROUP(gmi_wait_pi7,         RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x31c8, N, N),
+	PINGROUP(gmi_cs0_n_pj0,        RSVD1,        NAND,         GMI,          DTV,          RSVD1,        0x31d4, N, N),
+	PINGROUP(lcd_de_pj1,           DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x3098, N, N),
+	PINGROUP(gmi_cs1_n_pj2,        RSVD1,        NAND,         GMI,          DTV,          RSVD1,        0x31d8, N, N),
+	PINGROUP(lcd_hsync_pj3,        DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x309c, N, N),
+	PINGROUP(lcd_vsync_pj4,        DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30a0, N, N),
+	PINGROUP(uart2_cts_n_pj5,      UARTA,        UARTB,        GMI,          SPI4,         SPI4,         0x3170, N, N),
+	PINGROUP(uart2_rts_n_pj6,      UARTA,        UARTB,        GMI,          SPI4,         SPI4,         0x316c, N, N),
+	PINGROUP(gmi_a16_pj7,          UARTD,        SPI4,         GMI,          GMI_ALT,      GMI_ALT,      0x3230, N, N),
+	PINGROUP(gmi_adv_n_pk0,        RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x31cc, N, N),
+	PINGROUP(gmi_clk_pk1,          RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x31d0, N, N),
+	PINGROUP(gmi_cs4_n_pk2,        RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x31e4, N, N),
+	PINGROUP(gmi_cs2_n_pk3,        RSVD1,        NAND,         GMI,          RSVD4,        RSVD4,        0x31dc, N, N),
+	PINGROUP(gmi_cs3_n_pk4,        RSVD1,        NAND,         GMI,          GMI_ALT,      RSVD1,        0x31e0, N, N),
+	PINGROUP(spdif_out_pk5,        SPDIF,        RSVD2,        I2C1,         SDMMC2,       RSVD2,        0x3354, N, N),
+	PINGROUP(spdif_in_pk6,         SPDIF,        HDA,          I2C1,         SDMMC2,       SDMMC2,       0x3350, N, N),
+	PINGROUP(gmi_a19_pk7,          UARTD,        SPI4,         GMI,          RSVD4,        RSVD4,        0x323c, N, N),
+	PINGROUP(vi_d2_pl0,            DDR,          SDMMC2,       VI,           RSVD4,        RSVD4,        0x312c, N, Y),
+	PINGROUP(vi_d3_pl1,            DDR,          SDMMC2,       VI,           RSVD4,        RSVD4,        0x3130, N, Y),
+	PINGROUP(vi_d4_pl2,            DDR,          SDMMC2,       VI,           RSVD4,        RSVD4,        0x3134, N, Y),
+	PINGROUP(vi_d5_pl3,            DDR,          SDMMC2,       VI,           RSVD4,        RSVD4,        0x3138, N, Y),
+	PINGROUP(vi_d6_pl4,            DDR,          SDMMC2,       VI,           RSVD4,        RSVD4,        0x313c, N, Y),
+	PINGROUP(vi_d7_pl5,            DDR,          SDMMC2,       VI,           RSVD4,        RSVD4,        0x3140, N, Y),
+	PINGROUP(vi_d8_pl6,            DDR,          SDMMC2,       VI,           RSVD4,        RSVD4,        0x3144, N, Y),
+	PINGROUP(vi_d9_pl7,            DDR,          SDMMC2,       VI,           RSVD4,        RSVD4,        0x3148, N, Y),
+	PINGROUP(lcd_d16_pm0,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30e4, N, N),
+	PINGROUP(lcd_d17_pm1,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30e8, N, N),
+	PINGROUP(lcd_d18_pm2,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30ec, N, N),
+	PINGROUP(lcd_d19_pm3,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30f0, N, N),
+	PINGROUP(lcd_d20_pm4,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30f4, N, N),
+	PINGROUP(lcd_d21_pm5,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30f8, N, N),
+	PINGROUP(lcd_d22_pm6,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x30fc, N, N),
+	PINGROUP(lcd_d23_pm7,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x3100, N, N),
+	PINGROUP(dap1_fs_pn0,          I2S0,         HDA,          GMI,          SDMMC2,       SDMMC2,       0x3338, N, N),
+	PINGROUP(dap1_din_pn1,         I2S0,         HDA,          GMI,          SDMMC2,       SDMMC2,       0x333c, N, N),
+	PINGROUP(dap1_dout_pn2,        I2S0,         HDA,          GMI,          SDMMC2,       SDMMC2,       0x3340, N, N),
+	PINGROUP(dap1_sclk_pn3,        I2S0,         HDA,          GMI,          SDMMC2,       SDMMC2,       0x3344, N, N),
+	PINGROUP(lcd_cs0_n_pn4,        DISPLAYA,     DISPLAYB,     SPI5,         RSVD4,        RSVD4,        0x3084, N, N),
+	PINGROUP(lcd_sdout_pn5,        DISPLAYA,     DISPLAYB,     SPI5,         HDCP,         HDCP,         0x307c, N, N),
+	PINGROUP(lcd_dc0_pn6,          DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x3088, N, N),
+	PINGROUP(hdmi_int_pn7,         HDMI,         RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x3110, N, N),
+	PINGROUP(ulpi_data7_po0,       SPI2,         HSI,          UARTA,        ULPI,         ULPI,         0x301c, N, N),
+	PINGROUP(ulpi_data0_po1,       SPI3,         HSI,          UARTA,        ULPI,         ULPI,         0x3000, N, N),
+	PINGROUP(ulpi_data1_po2,       SPI3,         HSI,          UARTA,        ULPI,         ULPI,         0x3004, N, N),
+	PINGROUP(ulpi_data2_po3,       SPI3,         HSI,          UARTA,        ULPI,         ULPI,         0x3008, N, N),
+	PINGROUP(ulpi_data3_po4,       SPI3,         HSI,          UARTA,        ULPI,         ULPI,         0x300c, N, N),
+	PINGROUP(ulpi_data4_po5,       SPI2,         HSI,          UARTA,        ULPI,         ULPI,         0x3010, N, N),
+	PINGROUP(ulpi_data5_po6,       SPI2,         HSI,          UARTA,        ULPI,         ULPI,         0x3014, N, N),
+	PINGROUP(ulpi_data6_po7,       SPI2,         HSI,          UARTA,        ULPI,         ULPI,         0x3018, N, N),
+	PINGROUP(dap3_fs_pp0,          I2S2,         RSVD2,        DISPLAYA,     DISPLAYB,     RSVD2,        0x3030, N, N),
+	PINGROUP(dap3_din_pp1,         I2S2,         RSVD2,        DISPLAYA,     DISPLAYB,     RSVD2,        0x3034, N, N),
+	PINGROUP(dap3_dout_pp2,        I2S2,         RSVD2,        DISPLAYA,     DISPLAYB,     RSVD2,        0x3038, N, N),
+	PINGROUP(dap3_sclk_pp3,        I2S2,         RSVD2,        DISPLAYA,     DISPLAYB,     RSVD2,        0x303c, N, N),
+	PINGROUP(dap4_fs_pp4,          I2S3,         RSVD2,        GMI,          RSVD4,        RSVD4,        0x31a8, N, N),
+	PINGROUP(dap4_din_pp5,         I2S3,         RSVD2,        GMI,          RSVD4,        RSVD4,        0x31ac, N, N),
+	PINGROUP(dap4_dout_pp6,        I2S3,         RSVD2,        GMI,          RSVD4,        RSVD4,        0x31b0, N, N),
+	PINGROUP(dap4_sclk_pp7,        I2S3,         RSVD2,        GMI,          RSVD4,        RSVD4,        0x31b4, N, N),
+	PINGROUP(kb_col0_pq0,          KBC,          NAND,         TRACE,        TEST,         TEST,         0x32fc, N, N),
+	PINGROUP(kb_col1_pq1,          KBC,          NAND,         TRACE,        TEST,         TEST,         0x3300, N, N),
+	PINGROUP(kb_col2_pq2,          KBC,          NAND,         TRACE,        RSVD4,        RSVD4,        0x3304, N, N),
+	PINGROUP(kb_col3_pq3,          KBC,          NAND,         TRACE,        RSVD4,        RSVD4,        0x3308, N, N),
+	PINGROUP(kb_col4_pq4,          KBC,          NAND,         TRACE,        RSVD4,        RSVD4,        0x330c, N, N),
+	PINGROUP(kb_col5_pq5,          KBC,          NAND,         TRACE,        RSVD4,        RSVD4,        0x3310, N, N),
+	PINGROUP(kb_col6_pq6,          KBC,          NAND,         TRACE,        MIO,          MIO,          0x3314, N, N),
+	PINGROUP(kb_col7_pq7,          KBC,          NAND,         TRACE,        MIO,          MIO,          0x3318, N, N),
+	PINGROUP(kb_row0_pr0,          KBC,          NAND,         RSVD3,        RSVD4,        RSVD4,        0x32bc, N, N),
+	PINGROUP(kb_row1_pr1,          KBC,          NAND,         RSVD3,        RSVD4,        RSVD4,        0x32c0, N, N),
+	PINGROUP(kb_row2_pr2,          KBC,          NAND,         RSVD3,        RSVD4,        RSVD4,        0x32c4, N, N),
+	PINGROUP(kb_row3_pr3,          KBC,          NAND,         RSVD3,        INVALID,      RSVD3,        0x32c8, N, N),
+	PINGROUP(kb_row4_pr4,          KBC,          NAND,         TRACE,        RSVD4,        RSVD4,        0x32cc, N, N),
+	PINGROUP(kb_row5_pr5,          KBC,          NAND,         TRACE,        OWR,          OWR,          0x32d0, N, N),
+	PINGROUP(kb_row6_pr6,          KBC,          NAND,         SDMMC2,       MIO,          MIO,          0x32d4, N, N),
+	PINGROUP(kb_row7_pr7,          KBC,          NAND,         SDMMC2,       MIO,          MIO,          0x32d8, N, N),
+	PINGROUP(kb_row8_ps0,          KBC,          NAND,         SDMMC2,       MIO,          MIO,          0x32dc, N, N),
+	PINGROUP(kb_row9_ps1,          KBC,          NAND,         SDMMC2,       MIO,          MIO,          0x32e0, N, N),
+	PINGROUP(kb_row10_ps2,         KBC,          NAND,         SDMMC2,       MIO,          MIO,          0x32e4, N, N),
+	PINGROUP(kb_row11_ps3,         KBC,          NAND,         SDMMC2,       MIO,          MIO,          0x32e8, N, N),
+	PINGROUP(kb_row12_ps4,         KBC,          NAND,         SDMMC2,       MIO,          MIO,          0x32ec, N, N),
+	PINGROUP(kb_row13_ps5,         KBC,          NAND,         SDMMC2,       MIO,          MIO,          0x32f0, N, N),
+	PINGROUP(kb_row14_ps6,         KBC,          NAND,         SDMMC2,       MIO,          MIO,          0x32f4, N, N),
+	PINGROUP(kb_row15_ps7,         KBC,          NAND,         SDMMC2,       MIO,          MIO,          0x32f8, N, N),
+	PINGROUP(vi_pclk_pt0,          RSVD1,        SDMMC2,       VI,           RSVD4,        RSVD4,        0x3154, N, Y),
+	PINGROUP(vi_mclk_pt1,          VI,           VI_ALT1,      VI_ALT2,      VI_ALT3,      VI_ALT3,      0x3158, N, Y),
+	PINGROUP(vi_d10_pt2,           DDR,          RSVD2,        VI,           RSVD4,        RSVD4,        0x314c, N, Y),
+	PINGROUP(vi_d11_pt3,           DDR,          RSVD2,        VI,           RSVD4,        RSVD4,        0x3150, N, Y),
+	PINGROUP(vi_d0_pt4,            DDR,          RSVD2,        VI,           RSVD4,        RSVD4,        0x3124, N, Y),
+	PINGROUP(gen2_i2c_scl_pt5,     I2C2,         HDCP,         GMI,          RSVD4,        RSVD4,        0x3250, Y, N),
+	PINGROUP(gen2_i2c_sda_pt6,     I2C2,         HDCP,         GMI,          RSVD4,        RSVD4,        0x3254, Y, N),
+	PINGROUP(sdmmc4_cmd_pt7,       I2C3,         NAND,         GMI,          SDMMC4,       SDMMC4,       0x325c, N, Y),
+	PINGROUP(pu0,                  OWR,          UARTA,        GMI,          RSVD4,        RSVD4,        0x3184, N, N),
+	PINGROUP(pu1,                  RSVD1,        UARTA,        GMI,          RSVD4,        RSVD4,        0x3188, N, N),
+	PINGROUP(pu2,                  RSVD1,        UARTA,        GMI,          RSVD4,        RSVD4,        0x318c, N, N),
+	PINGROUP(pu3,                  PWM0,         UARTA,        GMI,          RSVD4,        RSVD4,        0x3190, N, N),
+	PINGROUP(pu4,                  PWM1,         UARTA,        GMI,          RSVD4,        RSVD4,        0x3194, N, N),
+	PINGROUP(pu5,                  PWM2,         UARTA,        GMI,          RSVD4,        RSVD4,        0x3198, N, N),
+	PINGROUP(pu6,                  PWM3,         UARTA,        GMI,          RSVD4,        RSVD4,        0x319c, N, N),
+	PINGROUP(jtag_rtck_pu7,        RTCK,         RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x32b0, N, N),
+	PINGROUP(pv0,                  RSVD1,        RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x3040, N, N),
+	PINGROUP(pv1,                  RSVD1,        RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x3044, N, N),
+	PINGROUP(pv2,                  OWR,          RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x3060, N, N),
+	PINGROUP(pv3,                  CLK_12M_OUT,  RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x3064, N, N),
+	PINGROUP(ddc_scl_pv4,          I2C4,         RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x3114, N, N),
+	PINGROUP(ddc_sda_pv5,          I2C4,         RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x3118, N, N),
+	PINGROUP(crt_hsync_pv6,        CRT,          RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x311c, N, N),
+	PINGROUP(crt_vsync_pv7,        CRT,          RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x3120, N, N),
+	PINGROUP(lcd_cs1_n_pw0,        DISPLAYA,     DISPLAYB,     SPI5,         RSVD4,        RSVD4,        0x3104, N, N),
+	PINGROUP(lcd_m1_pw1,           DISPLAYA,     DISPLAYB,     RSVD3,        RSVD4,        RSVD4,        0x3108, N, N),
+	PINGROUP(spi2_cs1_n_pw2,       SPI3,         SPI2,         SPI2_ALT,     I2C1,         I2C1,         0x3388, N, N),
+	PINGROUP(spi2_cs2_n_pw3,       SPI3,         SPI2,         SPI2_ALT,     I2C1,         I2C1,         0x338c, N, N),
+	PINGROUP(clk1_out_pw4,         EXTPERIPH1,   RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x334c, N, N),
+	PINGROUP(clk2_out_pw5,         EXTPERIPH2,   RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x3068, N, N),
+	PINGROUP(uart3_txd_pw6,        UARTC,        RSVD2,        GMI,          RSVD4,        RSVD4,        0x3174, N, N),
+	PINGROUP(uart3_rxd_pw7,        UARTC,        RSVD2,        GMI,          RSVD4,        RSVD4,        0x3178, N, N),
+	PINGROUP(spi2_mosi_px0,        SPI6,         SPI2,         SPI3,         GMI,          GMI,          0x3368, N, N),
+	PINGROUP(spi2_miso_px1,        SPI6,         SPI2,         SPI3,         GMI,          GMI,          0x336c, N, N),
+	PINGROUP(spi2_sck_px2,         SPI6,         SPI2,         SPI3,         GMI,          GMI,          0x3374, N, N),
+	PINGROUP(spi2_cs0_n_px3,       SPI6,         SPI2,         SPI3,         GMI,          GMI,          0x3370, N, N),
+	PINGROUP(spi1_mosi_px4,        SPI2,         SPI1,         SPI2_ALT,     GMI,          GMI,          0x3378, N, N),
+	PINGROUP(spi1_sck_px5,         SPI2,         SPI1,         SPI2_ALT,     GMI,          GMI,          0x337c, N, N),
+	PINGROUP(spi1_cs0_n_px6,       SPI2,         SPI1,         SPI2_ALT,     GMI,          GMI,          0x3380, N, N),
+	PINGROUP(spi1_miso_px7,        SPI3,         SPI1,         SPI2_ALT,     RSVD4,        RSVD4,        0x3384, N, N),
+	PINGROUP(ulpi_clk_py0,         SPI1,         RSVD2,        UARTD,        ULPI,         RSVD2,        0x3020, N, N),
+	PINGROUP(ulpi_dir_py1,         SPI1,         RSVD2,        UARTD,        ULPI,         RSVD2,        0x3024, N, N),
+	PINGROUP(ulpi_nxt_py2,         SPI1,         RSVD2,        UARTD,        ULPI,         RSVD2,        0x3028, N, N),
+	PINGROUP(ulpi_stp_py3,         SPI1,         RSVD2,        UARTD,        ULPI,         RSVD2,        0x302c, N, N),
+	PINGROUP(sdmmc1_dat3_py4,      SDMMC1,       RSVD2,        UARTE,        UARTA,        RSVD2,        0x3050, N, N),
+	PINGROUP(sdmmc1_dat2_py5,      SDMMC1,       RSVD2,        UARTE,        UARTA,        RSVD2,        0x3054, N, N),
+	PINGROUP(sdmmc1_dat1_py6,      SDMMC1,       RSVD2,        UARTE,        UARTA,        RSVD2,        0x3058, N, N),
+	PINGROUP(sdmmc1_dat0_py7,      SDMMC1,       RSVD2,        UARTE,        UARTA,        RSVD2,        0x305c, N, N),
+	PINGROUP(sdmmc1_clk_pz0,       SDMMC1,       RSVD2,        RSVD3,        UARTA,        RSVD3,        0x3048, N, N),
+	PINGROUP(sdmmc1_cmd_pz1,       SDMMC1,       RSVD2,        RSVD3,        UARTA,        RSVD3,        0x304c, N, N),
+	PINGROUP(lcd_sdin_pz2,         DISPLAYA,     DISPLAYB,     SPI5,         RSVD4,        RSVD4,        0x3078, N, N),
+	PINGROUP(lcd_wr_n_pz3,         DISPLAYA,     DISPLAYB,     SPI5,         HDCP,         HDCP,         0x3080, N, N),
+	PINGROUP(lcd_sck_pz4,          DISPLAYA,     DISPLAYB,     SPI5,         HDCP,         HDCP,         0x308c, N, N),
+	PINGROUP(sys_clk_req_pz5,      SYSCLK,       RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x3320, N, N),
+	PINGROUP(pwr_i2c_scl_pz6,      I2CPWR,       RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x32b4, Y, N),
+	PINGROUP(pwr_i2c_sda_pz7,      I2CPWR,       RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x32b8, Y, N),
+	PINGROUP(sdmmc4_dat0_paa0,     UARTE,        SPI3,         GMI,          SDMMC4,       SDMMC4,       0x3260, N, Y),
+	PINGROUP(sdmmc4_dat1_paa1,     UARTE,        SPI3,         GMI,          SDMMC4,       SDMMC4,       0x3264, N, Y),
+	PINGROUP(sdmmc4_dat2_paa2,     UARTE,        SPI3,         GMI,          SDMMC4,       SDMMC4,       0x3268, N, Y),
+	PINGROUP(sdmmc4_dat3_paa3,     UARTE,        SPI3,         GMI,          SDMMC4,       SDMMC4,       0x326c, N, Y),
+	PINGROUP(sdmmc4_dat4_paa4,     I2C3,         I2S4,         GMI,          SDMMC4,       SDMMC4,       0x3270, N, Y),
+	PINGROUP(sdmmc4_dat5_paa5,     VGP3,         I2S4,         GMI,          SDMMC4,       SDMMC4,       0x3274, N, Y),
+	PINGROUP(sdmmc4_dat6_paa6,     VGP4,         I2S4,         GMI,          SDMMC4,       SDMMC4,       0x3278, N, Y),
+	PINGROUP(sdmmc4_dat7_paa7,     VGP5,         I2S4,         GMI,          SDMMC4,       SDMMC4,       0x327c, N, Y),
+	PINGROUP(pbb0,                 I2S4,         RSVD2,        RSVD3,        SDMMC4,       RSVD3,        0x328c, N, N),
+	PINGROUP(cam_i2c_scl_pbb1,     VGP1,         I2C3,         RSVD3,        SDMMC4,       RSVD3,        0x3290, Y, N),
+	PINGROUP(cam_i2c_sda_pbb2,     VGP2,         I2C3,         RSVD3,        SDMMC4,       RSVD3,        0x3294, Y, N),
+	PINGROUP(pbb3,                 VGP3,         DISPLAYA,     DISPLAYB,     SDMMC4,       SDMMC4,       0x3298, N, N),
+	PINGROUP(pbb4,                 VGP4,         DISPLAYA,     DISPLAYB,     SDMMC4,       SDMMC4,       0x329c, N, N),
+	PINGROUP(pbb5,                 VGP5,         DISPLAYA,     DISPLAYB,     SDMMC4,       SDMMC4,       0x32a0, N, N),
+	PINGROUP(pbb6,                 VGP6,         DISPLAYA,     DISPLAYB,     SDMMC4,       SDMMC4,       0x32a4, N, N),
+	PINGROUP(pbb7,                 I2S4,         RSVD2,        RSVD3,        SDMMC4,       RSVD3,        0x32a8, N, N),
+	PINGROUP(cam_mclk_pcc0,        VI,           VI_ALT1,      VI_ALT3,      SDMMC4,       SDMMC4,       0x3284, N, N),
+	PINGROUP(pcc1,                 I2S4,         RSVD2,        RSVD3,        SDMMC4,       RSVD3,        0x3288, N, N),
+	PINGROUP(pcc2,                 I2S4,         RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x32ac, N, N),
+	PINGROUP(sdmmc4_rst_n_pcc3,    VGP6,         RSVD2,        RSVD3,        SDMMC4,       RSVD3,        0x3280, N, Y),
+	PINGROUP(sdmmc4_clk_pcc4,      INVALID,      NAND,         GMI,          SDMMC4,       SDMMC4,       0x3258, N, Y),
+	PINGROUP(clk2_req_pcc5,        DAP,          RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x306c, N, N),
+	PINGROUP(pex_l2_rst_n_pcc6,    PCIE,         HDA,          RSVD3,        RSVD4,        RSVD4,        0x33d8, N, N),
+	PINGROUP(pex_l2_clkreq_n_pcc7, PCIE,         HDA,          RSVD3,        RSVD4,        RSVD4,        0x33dc, N, N),
+	PINGROUP(pex_l0_prsnt_n_pdd0,  PCIE,         HDA,          RSVD3,        RSVD4,        RSVD4,        0x33b8, N, N),
+	PINGROUP(pex_l0_rst_n_pdd1,    PCIE,         HDA,          RSVD3,        RSVD4,        RSVD4,        0x33bc, N, N),
+	PINGROUP(pex_l0_clkreq_n_pdd2, PCIE,         HDA,          RSVD3,        RSVD4,        RSVD4,        0x33c0, N, N),
+	PINGROUP(pex_wake_n_pdd3,      PCIE,         HDA,          RSVD3,        RSVD4,        RSVD4,        0x33c4, N, N),
+	PINGROUP(pex_l1_prsnt_n_pdd4,  PCIE,         HDA,          RSVD3,        RSVD4,        RSVD4,        0x33c8, N, N),
+	PINGROUP(pex_l1_rst_n_pdd5,    PCIE,         HDA,          RSVD3,        RSVD4,        RSVD4,        0x33cc, N, N),
+	PINGROUP(pex_l1_clkreq_n_pdd6, PCIE,         HDA,          RSVD3,        RSVD4,        RSVD4,        0x33d0, N, N),
+	PINGROUP(pex_l2_prsnt_n_pdd7,  PCIE,         HDA,          RSVD3,        RSVD4,        RSVD4,        0x33d4, N, N),
+	PINGROUP(clk3_out_pee0,        EXTPERIPH3,   RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x31b8, N, N),
+	PINGROUP(clk3_req_pee1,        DEV3,         RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x31bc, N, N),
+	PINGROUP(clk1_req_pee2,        DAP,          HDA,          RSVD3,        RSVD4,        RSVD4,        0x3348, N, N),
+	PINGROUP(hdmi_cec_pee3,        CEC,          RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x33e0, Y, N),
+	PINGROUP(clk_32k_in,           CLK_32K_IN,   RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x3330, N, N),
+	PINGROUP(core_pwr_req,         CORE_PWR_REQ, RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x3324, N, N),
+	PINGROUP(cpu_pwr_req,          CPU_PWR_REQ,  RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x3328, N, N),
+	PINGROUP(owr,                  OWR,          CEC,          RSVD3,        RSVD4,        RSVD4,        0x3334, N, N),
+	PINGROUP(pwr_int_n,            PWR_INT_N,    RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x332c, N, N),
+	/* pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */
+	DRV_PINGROUP(ao1,   0x868,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(ao2,   0x86c,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(at1,   0x870,  2,  3,  4,  14,  5,  19,  5,  24,  2,  28,  2),
+	DRV_PINGROUP(at2,   0x874,  2,  3,  4,  14,  5,  19,  5,  24,  2,  28,  2),
+	DRV_PINGROUP(at3,   0x878,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(at4,   0x87c,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(at5,   0x880,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(cdev1, 0x884,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(cdev2, 0x888,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(cec,   0x938,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(crt,   0x8f8,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(csus,  0x88c, -1, -1, -1,  12,  5,  19,  5,  24,  4,  28,  4),
+	DRV_PINGROUP(dap1,  0x890,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(dap2,  0x894,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(dap3,  0x898,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(dap4,  0x89c,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(dbg,   0x8a0,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(ddc,   0x8fc,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(dev3,  0x92c,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(gma,   0x900, -1, -1, -1,  14,  5,  19,  5,  24,  4,  28,  4),
+	DRV_PINGROUP(gmb,   0x904, -1, -1, -1,  14,  5,  19,  5,  24,  4,  28,  4),
+	DRV_PINGROUP(gmc,   0x908, -1, -1, -1,  14,  5,  19,  5,  24,  4,  28,  4),
+	DRV_PINGROUP(gmd,   0x90c, -1, -1, -1,  14,  5,  19,  5,  24,  4,  28,  4),
+	DRV_PINGROUP(gme,   0x910,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(gmf,   0x914,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(gmg,   0x918,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(gmh,   0x91c,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(gpv,   0x928,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(lcd1,  0x8a4,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(lcd2,  0x8a8,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(owr,   0x920,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(sdio1, 0x8ec,  2,  3, -1,  12,  7,  20,  7,  28,  2,  30,  2),
+	DRV_PINGROUP(sdio2, 0x8ac,  2,  3, -1,  12,  7,  20,  7,  28,  2,  30,  2),
+	DRV_PINGROUP(sdio3, 0x8b0,  2,  3, -1,  12,  7,  20,  7,  28,  2,  30,  2),
+	DRV_PINGROUP(spi,   0x8b4,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(uaa,   0x8b8,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(uab,   0x8bc,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(uart2, 0x8c0,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(uart3, 0x8c4,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(uda,   0x924,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2),
+	DRV_PINGROUP(vi1,   0x8c8, -1, -1, -1,  14,  5,  19,  5,  24,  4,  28,  4),
+};
+
+static const struct tegra_pinctrl_soc_data tegra30_pinctrl = {
+	.ngpios = NUM_GPIOS,
+	.pins = tegra30_pins,
+	.npins = ARRAY_SIZE(tegra30_pins),
+	.functions = tegra30_functions,
+	.nfunctions = ARRAY_SIZE(tegra30_functions),
+	.groups = tegra30_groups,
+	.ngroups = ARRAY_SIZE(tegra30_groups),
+};
+
+void __devinit tegra30_pinctrl_init(const struct tegra_pinctrl_soc_data **soc)
+{
+	*soc = &tegra30_pinctrl;
+}
diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c
index c8d02f1..26eb8cc 100644
--- a/drivers/pinctrl/pinctrl-u300.c
+++ b/drivers/pinctrl/pinctrl-u300.c
@@ -19,6 +19,9 @@
 #include <linux/err.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include "pinctrl-coh901.h"
 
 /*
  * Register definitions for the U300 Padmux control registers in the
@@ -162,7 +165,7 @@
 #define U300_SYSCON_PMC4R_APP_MISC_16_APP_UART1_CTS		0x0100
 #define U300_SYSCON_PMC4R_APP_MISC_16_EMIF_1_STATIC_CS5_N	0x0200
 
-#define DRIVER_NAME "pinmux-u300"
+#define DRIVER_NAME "pinctrl-u300"
 
 /*
  * The DB3350 has 467 pads, I have enumerated the pads clockwise around the
@@ -1044,22 +1047,82 @@
 	U300_GPIO_RANGE(25, 181, 1),
 };
 
+static struct pinctrl_gpio_range *u300_match_gpio_range(unsigned pin)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++) {
+		struct pinctrl_gpio_range *range;
+
+		range = &u300_gpio_ranges[i];
+		if (pin >= range->pin_base &&
+		    pin <= (range->pin_base + range->npins - 1))
+			return range;
+	}
+	return NULL;
+}
+
+int u300_pin_config_get(struct pinctrl_dev *pctldev,
+			unsigned pin,
+			unsigned long *config)
+{
+	struct pinctrl_gpio_range *range = u300_match_gpio_range(pin);
+
+	/* We get config for those pins we CAN get it for and that's it */
+	if (!range)
+		return -ENOTSUPP;
+
+	return u300_gpio_config_get(range->gc,
+				    (pin - range->pin_base + range->base),
+				    config);
+}
+
+int u300_pin_config_set(struct pinctrl_dev *pctldev,
+			unsigned pin,
+			unsigned long config)
+{
+	struct pinctrl_gpio_range *range = u300_match_gpio_range(pin);
+	int ret;
+
+	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;
+
+	return 0;
+}
+
+static struct pinconf_ops u300_pconf_ops = {
+	.is_generic = true,
+	.pin_config_get = u300_pin_config_get,
+	.pin_config_set = u300_pin_config_set,
+};
+
 static struct pinctrl_desc u300_pmx_desc = {
 	.name = DRIVER_NAME,
 	.pins = u300_pads,
 	.npins = ARRAY_SIZE(u300_pads),
 	.pctlops = &u300_pctrl_ops,
 	.pmxops = &u300_pmx_ops,
+	.confops = &u300_pconf_ops,
 	.owner = THIS_MODULE,
 };
 
-static int __init u300_pmx_probe(struct platform_device *pdev)
+static int __devinit u300_pmx_probe(struct platform_device *pdev)
 {
 	struct u300_pmx *upmx;
 	struct resource *res;
+	struct gpio_chip *gpio_chip = dev_get_platdata(&pdev->dev);
 	int ret;
 	int i;
 
+	pr_err("U300 PMX PROBE\n");
+
 	/* Create state holders etc for this driver */
 	upmx = devm_kzalloc(&pdev->dev, sizeof(*upmx), GFP_KERNEL);
 	if (!upmx)
@@ -1095,12 +1158,14 @@
 	}
 
 	/* We will handle a range of GPIO pins */
-	for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++)
+	for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++) {
+		u300_gpio_ranges[i].gc = gpio_chip;
 		pinctrl_add_gpio_range(upmx->pctl, &u300_gpio_ranges[i]);
+	}
 
 	platform_set_drvdata(pdev, upmx);
 
-	dev_info(&pdev->dev, "initialized U300 pinmux driver\n");
+	dev_info(&pdev->dev, "initialized U300 pin control driver\n");
 
 	return 0;
 
@@ -1115,7 +1180,7 @@
 	return ret;
 }
 
-static int __exit u300_pmx_remove(struct platform_device *pdev)
+static int __devexit u300_pmx_remove(struct platform_device *pdev)
 {
 	struct u300_pmx *upmx = platform_get_drvdata(pdev);
 	int i;
@@ -1136,12 +1201,13 @@
 		.name = DRIVER_NAME,
 		.owner = THIS_MODULE,
 	},
-	.remove = __exit_p(u300_pmx_remove),
+	.probe = u300_pmx_probe,
+	.remove = __devexit_p(u300_pmx_remove),
 };
 
 static int __init u300_pmx_init(void)
 {
-	return platform_driver_probe(&u300_pmx_driver, u300_pmx_probe);
+	return platform_driver_register(&u300_pmx_driver);
 }
 arch_initcall(u300_pmx_init);
 
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index 7c3193f..4e62783 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -1,12 +1,14 @@
 /*
  * Core driver for the pin muxing portions of the pin control subsystem
  *
- * Copyright (C) 2011 ST-Ericsson SA
+ * Copyright (C) 2011-2012 ST-Ericsson SA
  * Written on behalf of Linaro for ST-Ericsson
  * Based on bits of regulator core, gpio core and clk core
  *
  * Author: Linus Walleij <linus.walleij@linaro.org>
  *
+ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
  * License terms: GNU General Public License (GPL) version 2
  */
 #define pr_fmt(fmt) "pinmux core: " fmt
@@ -19,8 +21,6 @@
 #include <linux/radix-tree.h>
 #include <linux/err.h>
 #include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/sysfs.h>
 #include <linux/debugfs.h>
@@ -28,866 +28,7 @@
 #include <linux/pinctrl/machine.h>
 #include <linux/pinctrl/pinmux.h>
 #include "core.h"
-
-/* List of pinmuxes */
-static DEFINE_MUTEX(pinmux_list_mutex);
-static LIST_HEAD(pinmux_list);
-
-/* Global pinmux maps */
-static struct pinmux_map *pinmux_maps;
-static unsigned pinmux_maps_num;
-
-/**
- * struct pinmux_group - group list item for pinmux groups
- * @node: pinmux group list node
- * @group_selector: the group selector for this group
- */
-struct pinmux_group {
-	struct list_head node;
-	unsigned group_selector;
-};
-
-/**
- * struct pinmux - per-device pinmux state holder
- * @node: global list node
- * @dev: the device using this pinmux
- * @usecount: the number of active users of this mux setting, used to keep
- *	track of nested use cases
- * @pctldev: pin control device handling this pinmux
- * @func_selector: the function selector for the pinmux device handling
- *	this pinmux
- * @groups: the group selectors for the pinmux device and
- *	selector combination handling this pinmux, this is a list that
- *	will be traversed on all pinmux operations such as
- *	get/put/enable/disable
- * @mutex: a lock for the pinmux state holder
- */
-struct pinmux {
-	struct list_head node;
-	struct device *dev;
-	unsigned usecount;
-	struct pinctrl_dev *pctldev;
-	unsigned func_selector;
-	struct list_head groups;
-	struct mutex mutex;
-};
-
-/**
- * struct pinmux_hog - a list item to stash mux hogs
- * @node: pinmux hog list node
- * @map: map entry responsible for this hogging
- * @pmx: the pinmux hogged by this item
- */
-struct pinmux_hog {
-	struct list_head node;
-	struct pinmux_map const *map;
-	struct pinmux *pmx;
-};
-
-/**
- * pin_request() - request a single pin to be muxed in, typically for GPIO
- * @pin: the pin number in the global pin space
- * @function: a functional name to give to this pin, passed to the driver
- *	so it knows what function to mux in, e.g. the string "gpioNN"
- *	means that you want to mux in the pin for use as GPIO number NN
- * @gpio_range: the range matching the GPIO pin if this is a request for a
- *	single GPIO pin
- */
-static int pin_request(struct pinctrl_dev *pctldev,
-		       int pin, const char *function,
-		       struct pinctrl_gpio_range *gpio_range)
-{
-	struct pin_desc *desc;
-	const struct pinmux_ops *ops = pctldev->desc->pmxops;
-	int status = -EINVAL;
-
-	dev_dbg(pctldev->dev, "request pin %d for %s\n", pin, function);
-
-	desc = pin_desc_get(pctldev, pin);
-	if (desc == NULL) {
-		dev_err(pctldev->dev,
-			"pin is not registered so it cannot be requested\n");
-		goto out;
-	}
-
-	if (!function) {
-		dev_err(pctldev->dev, "no function name given\n");
-		return -EINVAL;
-	}
-
-	spin_lock(&desc->lock);
-	if (desc->mux_function) {
-		spin_unlock(&desc->lock);
-		dev_err(pctldev->dev,
-			"pin already requested\n");
-		goto out;
-	}
-	desc->mux_function = function;
-	spin_unlock(&desc->lock);
-
-	/* Let each pin increase references to this module */
-	if (!try_module_get(pctldev->owner)) {
-		dev_err(pctldev->dev,
-			"could not increase module refcount for pin %d\n",
-			pin);
-		status = -EINVAL;
-		goto out_free_pin;
-	}
-
-	/*
-	 * If there is no kind of request function for the pin we just assume
-	 * we got it by default and proceed.
-	 */
-	if (gpio_range && ops->gpio_request_enable)
-		/* This requests and enables a single GPIO pin */
-		status = ops->gpio_request_enable(pctldev, gpio_range, pin);
-	else if (ops->request)
-		status = ops->request(pctldev, pin);
-	else
-		status = 0;
-
-	if (status)
-		dev_err(pctldev->dev, "->request on device %s failed for pin %d\n",
-		       pctldev->desc->name, pin);
-out_free_pin:
-	if (status) {
-		spin_lock(&desc->lock);
-		desc->mux_function = NULL;
-		spin_unlock(&desc->lock);
-	}
-out:
-	if (status)
-		dev_err(pctldev->dev, "pin-%d (%s) status %d\n",
-		       pin, function ? : "?", status);
-
-	return status;
-}
-
-/**
- * pin_free() - release a single muxed in pin so something else can be muxed
- * @pctldev: pin controller device handling this pin
- * @pin: the pin to free
- * @gpio_range: the range matching the GPIO pin if this is a request for a
- *	single GPIO pin
- *
- * This function returns a pointer to the function name in use. This is used
- * for callers that dynamically allocate a function name so it can be freed
- * once the pin is free. This is done for GPIO request functions.
- */
-static const char *pin_free(struct pinctrl_dev *pctldev, int pin,
-			    struct pinctrl_gpio_range *gpio_range)
-{
-	const struct pinmux_ops *ops = pctldev->desc->pmxops;
-	struct pin_desc *desc;
-	const char *func;
-
-	desc = pin_desc_get(pctldev, pin);
-	if (desc == NULL) {
-		dev_err(pctldev->dev,
-			"pin is not registered so it cannot be freed\n");
-		return NULL;
-	}
-
-	/*
-	 * If there is no kind of request function for the pin we just assume
-	 * we got it by default and proceed.
-	 */
-	if (gpio_range && ops->gpio_disable_free)
-		ops->gpio_disable_free(pctldev, gpio_range, pin);
-	else if (ops->free)
-		ops->free(pctldev, pin);
-
-	spin_lock(&desc->lock);
-	func = desc->mux_function;
-	desc->mux_function = NULL;
-	spin_unlock(&desc->lock);
-	module_put(pctldev->owner);
-
-	return func;
-}
-
-/**
- * pinmux_request_gpio() - request a single pin to be muxed in as GPIO
- * @gpio: the GPIO pin number from the GPIO subsystem number space
- *
- * This function should *ONLY* be used from gpiolib-based GPIO drivers,
- * as part of their gpio_request() semantics, platforms and individual drivers
- * shall *NOT* request GPIO pins to be muxed in.
- */
-int pinmux_request_gpio(unsigned gpio)
-{
-	char gpiostr[16];
-	const char *function;
-	struct pinctrl_dev *pctldev;
-	struct pinctrl_gpio_range *range;
-	int ret;
-	int pin;
-
-	ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
-	if (ret)
-		return -EINVAL;
-
-	/* Convert to the pin controllers number space */
-	pin = gpio - range->base + range->pin_base;
-
-	/* Conjure some name stating what chip and pin this is taken by */
-	snprintf(gpiostr, 15, "%s:%d", range->name, gpio);
-
-	function = kstrdup(gpiostr, GFP_KERNEL);
-	if (!function)
-		return -EINVAL;
-
-	ret = pin_request(pctldev, pin, function, range);
-	if (ret < 0)
-		kfree(function);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(pinmux_request_gpio);
-
-/**
- * pinmux_free_gpio() - free a single pin, currently used as GPIO
- * @gpio: the GPIO pin number from the GPIO subsystem number space
- *
- * This function should *ONLY* be used from gpiolib-based GPIO drivers,
- * as part of their gpio_free() semantics, platforms and individual drivers
- * shall *NOT* request GPIO pins to be muxed out.
- */
-void pinmux_free_gpio(unsigned gpio)
-{
-	struct pinctrl_dev *pctldev;
-	struct pinctrl_gpio_range *range;
-	int ret;
-	int pin;
-	const char *func;
-
-	ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
-	if (ret)
-		return;
-
-	/* Convert to the pin controllers number space */
-	pin = gpio - range->base + range->pin_base;
-
-	func = pin_free(pctldev, pin, range);
-	kfree(func);
-}
-EXPORT_SYMBOL_GPL(pinmux_free_gpio);
-
-static int pinmux_gpio_direction(unsigned gpio, bool input)
-{
-	struct pinctrl_dev *pctldev;
-	struct pinctrl_gpio_range *range;
-	const struct pinmux_ops *ops;
-	int ret;
-	int pin;
-
-	ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
-	if (ret)
-		return ret;
-
-	ops = pctldev->desc->pmxops;
-
-	/* Convert to the pin controllers number space */
-	pin = gpio - range->base + range->pin_base;
-
-	if (ops->gpio_set_direction)
-		ret = ops->gpio_set_direction(pctldev, range, pin, input);
-	else
-		ret = 0;
-
-	return ret;
-}
-
-/**
- * pinmux_gpio_direction_input() - request a GPIO pin to go into input mode
- * @gpio: the GPIO pin number from the GPIO subsystem number space
- *
- * This function should *ONLY* be used from gpiolib-based GPIO drivers,
- * as part of their gpio_direction_input() semantics, platforms and individual
- * drivers shall *NOT* touch pinmux GPIO calls.
- */
-int pinmux_gpio_direction_input(unsigned gpio)
-{
-	return pinmux_gpio_direction(gpio, true);
-}
-EXPORT_SYMBOL_GPL(pinmux_gpio_direction_input);
-
-/**
- * pinmux_gpio_direction_output() - request a GPIO pin to go into output mode
- * @gpio: the GPIO pin number from the GPIO subsystem number space
- *
- * This function should *ONLY* be used from gpiolib-based GPIO drivers,
- * as part of their gpio_direction_output() semantics, platforms and individual
- * drivers shall *NOT* touch pinmux GPIO calls.
- */
-int pinmux_gpio_direction_output(unsigned gpio)
-{
-	return pinmux_gpio_direction(gpio, false);
-}
-EXPORT_SYMBOL_GPL(pinmux_gpio_direction_output);
-
-/**
- * pinmux_register_mappings() - register a set of pinmux mappings
- * @maps: the pinmux mappings table to register, this should be marked with
- *	__initdata so it can be discarded after boot, this function will
- *	perform a shallow copy for the mapping entries.
- * @num_maps: the number of maps in the mapping table
- *
- * Only call this once during initialization of your machine, the function is
- * tagged as __init and won't be callable after init has completed. The map
- * passed into this function will be owned by the pinmux core and cannot be
- * freed.
- */
-int __init pinmux_register_mappings(struct pinmux_map const *maps,
-				    unsigned num_maps)
-{
-	void *tmp_maps;
-	int i;
-
-	pr_debug("add %d pinmux maps\n", num_maps);
-
-	/* First sanity check the new mapping */
-	for (i = 0; i < num_maps; i++) {
-		if (!maps[i].name) {
-			pr_err("failed to register map %d: no map name given\n",
-					i);
-			return -EINVAL;
-		}
-
-		if (!maps[i].ctrl_dev && !maps[i].ctrl_dev_name) {
-			pr_err("failed to register map %s (%d): no pin control device given\n",
-			       maps[i].name, i);
-			return -EINVAL;
-		}
-
-		if (!maps[i].function) {
-			pr_err("failed to register map %s (%d): no function ID given\n",
-					maps[i].name, i);
-			return -EINVAL;
-		}
-
-		if (!maps[i].dev && !maps[i].dev_name)
-			pr_debug("add system map %s function %s with no device\n",
-				 maps[i].name,
-				 maps[i].function);
-		else
-			pr_debug("register map %s, function %s\n",
-				 maps[i].name,
-				 maps[i].function);
-	}
-
-	/*
-	 * Make a copy of the map array - string pointers will end up in the
-	 * kernel const section anyway so these do not need to be deep copied.
-	 */
-	if (!pinmux_maps_num) {
-		/* On first call, just copy them */
-		tmp_maps = kmemdup(maps,
-				   sizeof(struct pinmux_map) * num_maps,
-				   GFP_KERNEL);
-		if (!tmp_maps)
-			return -ENOMEM;
-	} else {
-		/* Subsequent calls, reallocate array to new size */
-		size_t oldsize = sizeof(struct pinmux_map) * pinmux_maps_num;
-		size_t newsize = sizeof(struct pinmux_map) * num_maps;
-
-		tmp_maps = krealloc(pinmux_maps, oldsize + newsize, GFP_KERNEL);
-		if (!tmp_maps)
-			return -ENOMEM;
-		memcpy((tmp_maps + oldsize), maps, newsize);
-	}
-
-	pinmux_maps = tmp_maps;
-	pinmux_maps_num += num_maps;
-	return 0;
-}
-
-/**
- * acquire_pins() - acquire all the pins for a certain function on a pinmux
- * @pctldev: the device to take the pins on
- * @func_selector: the function selector to acquire the pins for
- * @group_selector: the group selector containing the pins to acquire
- */
-static int acquire_pins(struct pinctrl_dev *pctldev,
-			unsigned func_selector,
-			unsigned group_selector)
-{
-	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
-	const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
-	const char *func = pmxops->get_function_name(pctldev,
-						     func_selector);
-	const unsigned *pins;
-	unsigned num_pins;
-	int ret;
-	int i;
-
-	ret = pctlops->get_group_pins(pctldev, group_selector,
-				      &pins, &num_pins);
-	if (ret)
-		return ret;
-
-	dev_dbg(pctldev->dev, "requesting the %u pins from group %u\n",
-		num_pins, group_selector);
-
-	/* Try to allocate all pins in this group, one by one */
-	for (i = 0; i < num_pins; i++) {
-		ret = pin_request(pctldev, pins[i], func, NULL);
-		if (ret) {
-			dev_err(pctldev->dev,
-				"could not get pin %d for function %s on device %s - conflicting mux mappings?\n",
-				pins[i], func ? : "(undefined)",
-				pinctrl_dev_get_name(pctldev));
-			/* On error release all taken pins */
-			i--; /* this pin just failed */
-			for (; i >= 0; i--)
-				pin_free(pctldev, pins[i], NULL);
-			return -ENODEV;
-		}
-	}
-	return 0;
-}
-
-/**
- * release_pins() - release pins taken by earlier acquirement
- * @pctldev: the device to free the pins on
- * @group_selector: the group selector containing the pins to free
- */
-static void release_pins(struct pinctrl_dev *pctldev,
-			 unsigned group_selector)
-{
-	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
-	const unsigned *pins;
-	unsigned num_pins;
-	int ret;
-	int i;
-
-	ret = pctlops->get_group_pins(pctldev, group_selector,
-				      &pins, &num_pins);
-	if (ret) {
-		dev_err(pctldev->dev, "could not get pins to release for group selector %d\n",
-			group_selector);
-		return;
-	}
-	for (i = 0; i < num_pins; i++)
-		pin_free(pctldev, pins[i], NULL);
-}
-
-/**
- * pinmux_check_pin_group() - check function and pin group combo
- * @pctldev: device to check the pin group vs function for
- * @func_selector: the function selector to check the pin group for, we have
- *	already looked this up in the calling function
- * @pin_group: the pin group to match to the function
- *
- * This function will check that the pinmux driver can supply the
- * selected pin group for a certain function, returns the group selector if
- * the group and function selector will work fine together, else returns
- * negative
- */
-static int pinmux_check_pin_group(struct pinctrl_dev *pctldev,
-				  unsigned func_selector,
-				  const char *pin_group)
-{
-	const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
-	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
-	int ret;
-
-	/*
-	 * If the driver does not support different pin groups for the
-	 * functions, we only support group 0, and assume this exists.
-	 */
-	if (!pctlops || !pctlops->list_groups)
-		return 0;
-
-	/*
-	 * Passing NULL (no specific group) will select the first and
-	 * hopefully only group of pins available for this function.
-	 */
-	if (!pin_group) {
-		char const * const *groups;
-		unsigned num_groups;
-
-		ret = pmxops->get_function_groups(pctldev, func_selector,
-						  &groups, &num_groups);
-		if (ret)
-			return ret;
-		if (num_groups < 1)
-			return -EINVAL;
-		ret = pinctrl_get_group_selector(pctldev, groups[0]);
-		if (ret < 0) {
-			dev_err(pctldev->dev,
-				"function %s wants group %s but the pin controller does not seem to have that group\n",
-				pmxops->get_function_name(pctldev, func_selector),
-				groups[0]);
-			return ret;
-		}
-
-		if (num_groups > 1)
-			dev_dbg(pctldev->dev,
-				"function %s support more than one group, default-selecting first group %s (%d)\n",
-				pmxops->get_function_name(pctldev, func_selector),
-				groups[0],
-				ret);
-
-		return ret;
-	}
-
-	dev_dbg(pctldev->dev,
-		"check if we have pin group %s on controller %s\n",
-		pin_group, pinctrl_dev_get_name(pctldev));
-
-	ret = pinctrl_get_group_selector(pctldev, pin_group);
-	if (ret < 0) {
-		dev_dbg(pctldev->dev,
-			"%s does not support pin group %s with function %s\n",
-			pinctrl_dev_get_name(pctldev),
-			pin_group,
-			pmxops->get_function_name(pctldev, func_selector));
-	}
-	return ret;
-}
-
-/**
- * pinmux_search_function() - check pin control driver for a certain function
- * @pctldev: device to check for function and position
- * @map: function map containing the function and position to look for
- * @func_selector: returns the applicable function selector if found
- * @group_selector: returns the applicable group selector if found
- *
- * This will search the pinmux driver for an applicable
- * function with a specific pin group, returns 0 if these can be mapped
- * negative otherwise
- */
-static int pinmux_search_function(struct pinctrl_dev *pctldev,
-				  struct pinmux_map const *map,
-				  unsigned *func_selector,
-				  unsigned *group_selector)
-{
-	const struct pinmux_ops *ops = pctldev->desc->pmxops;
-	unsigned selector = 0;
-
-	/* See if this pctldev has this function */
-	while (ops->list_functions(pctldev, selector) >= 0) {
-		const char *fname = ops->get_function_name(pctldev,
-							   selector);
-		int ret;
-
-		if (!strcmp(map->function, fname)) {
-			/* Found the function, check pin group */
-			ret = pinmux_check_pin_group(pctldev, selector,
-						     map->group);
-			if (ret < 0)
-				return ret;
-
-			/* This function and group selector can be used */
-			*func_selector = selector;
-			*group_selector = ret;
-			return 0;
-
-		}
-		selector++;
-	}
-
-	pr_err("%s does not support function %s\n",
-	       pinctrl_dev_get_name(pctldev), map->function);
-	return -EINVAL;
-}
-
-/**
- * pinmux_enable_muxmap() - enable a map entry for a certain pinmux
- */
-static int pinmux_enable_muxmap(struct pinctrl_dev *pctldev,
-				struct pinmux *pmx,
-				struct device *dev,
-				const char *devname,
-				struct pinmux_map const *map)
-{
-	unsigned func_selector;
-	unsigned group_selector;
-	struct pinmux_group *grp;
-	int ret;
-
-	/*
-	 * Note that we're not locking the pinmux mutex here, because
-	 * this is only called at pinmux initialization time when it
-	 * has not been added to any list and thus is not reachable
-	 * by anyone else.
-	 */
-
-	if (pmx->pctldev && pmx->pctldev != pctldev) {
-		dev_err(pctldev->dev,
-			"different pin control devices given for device %s, function %s\n",
-			devname, map->function);
-		return -EINVAL;
-	}
-	pmx->dev = dev;
-	pmx->pctldev = pctldev;
-
-	/* Now go into the driver and try to match a function and group */
-	ret = pinmux_search_function(pctldev, map, &func_selector,
-				     &group_selector);
-	if (ret < 0)
-		return ret;
-
-	/*
-	 * If the function selector is already set, it needs to be identical,
-	 * we support several groups with one function but not several
-	 * functions with one or several groups in the same pinmux.
-	 */
-	if (pmx->func_selector != UINT_MAX &&
-	    pmx->func_selector != func_selector) {
-		dev_err(pctldev->dev,
-			"dual function defines in the map for device %s\n",
-		       devname);
-		return -EINVAL;
-	}
-	pmx->func_selector = func_selector;
-
-	/* Now add this group selector, we may have many of them */
-	grp = kmalloc(sizeof(struct pinmux_group), GFP_KERNEL);
-	if (!grp)
-		return -ENOMEM;
-	grp->group_selector = group_selector;
-	ret = acquire_pins(pctldev, func_selector, group_selector);
-	if (ret) {
-		kfree(grp);
-		return ret;
-	}
-	list_add(&grp->node, &pmx->groups);
-
-	return 0;
-}
-
-static void pinmux_free_groups(struct pinmux *pmx)
-{
-	struct list_head *node, *tmp;
-
-	list_for_each_safe(node, tmp, &pmx->groups) {
-		struct pinmux_group *grp =
-			list_entry(node, struct pinmux_group, node);
-		/* Release all pins taken by this group */
-		release_pins(pmx->pctldev, grp->group_selector);
-		list_del(node);
-		kfree(grp);
-	}
-}
-
-/**
- * pinmux_get() - retrieves the pinmux for a certain device
- * @dev: the device to get the pinmux for
- * @name: an optional specific mux mapping name or NULL, the name is only
- *	needed if you want to have more than one mapping per device, or if you
- *	need an anonymous pinmux (not tied to any specific device)
- */
-struct pinmux *pinmux_get(struct device *dev, const char *name)
-{
-	struct pinmux_map const *map = NULL;
-	struct pinctrl_dev *pctldev = NULL;
-	const char *devname = NULL;
-	struct pinmux *pmx;
-	bool found_map;
-	unsigned num_maps = 0;
-	int ret = -ENODEV;
-	int i;
-
-	/* We must have dev or ID or both */
-	if (!dev && !name)
-		return ERR_PTR(-EINVAL);
-
-	if (dev)
-		devname = dev_name(dev);
-
-	pr_debug("get mux %s for device %s\n", name,
-		 devname ? devname : "(none)");
-
-	/*
-	 * create the state cookie holder struct pinmux for each
-	 * mapping, this is what consumers will get when requesting
-	 * a pinmux handle with pinmux_get()
-	 */
-	pmx = kzalloc(sizeof(struct pinmux), GFP_KERNEL);
-	if (pmx == NULL)
-		return ERR_PTR(-ENOMEM);
-	mutex_init(&pmx->mutex);
-	pmx->func_selector = UINT_MAX;
-	INIT_LIST_HEAD(&pmx->groups);
-
-	/* Iterate over the pinmux maps to locate the right ones */
-	for (i = 0; i < pinmux_maps_num; i++) {
-		map = &pinmux_maps[i];
-		found_map = false;
-
-		/*
-		 * First, try to find the pctldev given in the map
-		 */
-		pctldev = get_pinctrl_dev_from_dev(map->ctrl_dev,
-						   map->ctrl_dev_name);
-		if (!pctldev) {
-			const char *devname = NULL;
-
-			if (map->ctrl_dev)
-				devname = dev_name(map->ctrl_dev);
-			else if (map->ctrl_dev_name)
-				devname = map->ctrl_dev_name;
-
-			pr_warning("could not find a pinctrl device for pinmux function %s, fishy, they shall all have one\n",
-				   map->function);
-			pr_warning("given pinctrl device name: %s",
-				   devname ? devname : "UNDEFINED");
-
-			/* Continue to check the other mappings anyway... */
-			continue;
-		}
-
-		pr_debug("in map, found pctldev %s to handle function %s",
-			 dev_name(pctldev->dev), map->function);
-
-
-		/*
-		 * If we're looking for a specific named map, this must match,
-		 * else we loop and look for the next.
-		 */
-		if (name != NULL) {
-			if (map->name == NULL)
-				continue;
-			if (strcmp(map->name, name))
-				continue;
-		}
-
-		/*
-		 * This is for the case where no device name is given, we
-		 * already know that the function name matches from above
-		 * code.
-		 */
-		if (!map->dev_name && (name != NULL))
-			found_map = true;
-
-		/* If the mapping has a device set up it must match */
-		if (map->dev_name &&
-		    (!devname || !strcmp(map->dev_name, devname)))
-			/* MATCH! */
-			found_map = true;
-
-		/* If this map is applicable, then apply it */
-		if (found_map) {
-			ret = pinmux_enable_muxmap(pctldev, pmx, dev,
-						   devname, map);
-			if (ret) {
-				pinmux_free_groups(pmx);
-				kfree(pmx);
-				return ERR_PTR(ret);
-			}
-			num_maps++;
-		}
-	}
-
-
-	/* We should have atleast one map, right */
-	if (!num_maps) {
-		pr_err("could not find any mux maps for device %s, ID %s\n",
-		       devname ? devname : "(anonymous)",
-		       name ? name : "(undefined)");
-		kfree(pmx);
-		return ERR_PTR(-EINVAL);
-	}
-
-	pr_debug("found %u mux maps for device %s, UD %s\n",
-		 num_maps,
-		 devname ? devname : "(anonymous)",
-		 name ? name : "(undefined)");
-
-	/* Add the pinmux to the global list */
-	mutex_lock(&pinmux_list_mutex);
-	list_add(&pmx->node, &pinmux_list);
-	mutex_unlock(&pinmux_list_mutex);
-
-	return pmx;
-}
-EXPORT_SYMBOL_GPL(pinmux_get);
-
-/**
- * pinmux_put() - release a previously claimed pinmux
- * @pmx: a pinmux previously claimed by pinmux_get()
- */
-void pinmux_put(struct pinmux *pmx)
-{
-	if (pmx == NULL)
-		return;
-
-	mutex_lock(&pmx->mutex);
-	if (pmx->usecount)
-		pr_warn("releasing pinmux with active users!\n");
-	/* Free the groups and all acquired pins */
-	pinmux_free_groups(pmx);
-	mutex_unlock(&pmx->mutex);
-
-	/* Remove from list */
-	mutex_lock(&pinmux_list_mutex);
-	list_del(&pmx->node);
-	mutex_unlock(&pinmux_list_mutex);
-
-	kfree(pmx);
-}
-EXPORT_SYMBOL_GPL(pinmux_put);
-
-/**
- * pinmux_enable() - enable a certain pinmux setting
- * @pmx: the pinmux to enable, previously claimed by pinmux_get()
- */
-int pinmux_enable(struct pinmux *pmx)
-{
-	int ret = 0;
-
-	if (pmx == NULL)
-		return -EINVAL;
-	mutex_lock(&pmx->mutex);
-	if (pmx->usecount++ == 0) {
-		struct pinctrl_dev *pctldev = pmx->pctldev;
-		const struct pinmux_ops *ops = pctldev->desc->pmxops;
-		struct pinmux_group *grp;
-
-		list_for_each_entry(grp, &pmx->groups, node) {
-			ret = ops->enable(pctldev, pmx->func_selector,
-					  grp->group_selector);
-			if (ret) {
-				/*
-				 * TODO: call disable() on all groups we called
-				 * enable() on to this point?
-				 */
-				pmx->usecount--;
-				break;
-			}
-		}
-	}
-	mutex_unlock(&pmx->mutex);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(pinmux_enable);
-
-/**
- * pinmux_disable() - disable a certain pinmux setting
- * @pmx: the pinmux to disable, previously claimed by pinmux_get()
- */
-void pinmux_disable(struct pinmux *pmx)
-{
-	if (pmx == NULL)
-		return;
-
-	mutex_lock(&pmx->mutex);
-	if (--pmx->usecount == 0) {
-		struct pinctrl_dev *pctldev = pmx->pctldev;
-		const struct pinmux_ops *ops = pctldev->desc->pmxops;
-		struct pinmux_group *grp;
-
-		list_for_each_entry(grp, &pmx->groups, node) {
-			ops->disable(pctldev, pmx->func_selector,
-				     grp->group_selector);
-		}
-	}
-	mutex_unlock(&pmx->mutex);
-}
-EXPORT_SYMBOL_GPL(pinmux_disable);
+#include "pinmux.h"
 
 int pinmux_check_ops(struct pinctrl_dev *pctldev)
 {
@@ -917,115 +58,416 @@
 	return 0;
 }
 
-/* Hog a single map entry and add to the hoglist */
-static int pinmux_hog_map(struct pinctrl_dev *pctldev,
-			  struct pinmux_map const *map)
+int pinmux_validate_map(struct pinctrl_map const *map, int i)
 {
-	struct pinmux_hog *hog;
-	struct pinmux *pmx;
-	int ret;
-
-	if (map->dev || map->dev_name) {
-		/*
-		 * TODO: the day we have device tree support, we can
-		 * traverse the device tree and hog to specific device nodes
-		 * without any problems, so then we can hog pinmuxes for
-		 * all devices that just want a static pin mux at this point.
-		 */
-		dev_err(pctldev->dev, "map %s wants to hog a non-system pinmux, this is not going to work\n",
-				map->name);
+	if (!map->data.mux.function) {
+		pr_err("failed to register map %s (%d): no function given\n",
+		       map->name, i);
 		return -EINVAL;
 	}
 
-	hog = kzalloc(sizeof(struct pinmux_hog), GFP_KERNEL);
-	if (!hog)
-		return -ENOMEM;
-
-	pmx = pinmux_get(NULL, map->name);
-	if (IS_ERR(pmx)) {
-		kfree(hog);
-		dev_err(pctldev->dev,
-			"could not get the %s pinmux mapping for hogging\n",
-			map->name);
-		return PTR_ERR(pmx);
-	}
-
-	ret = pinmux_enable(pmx);
-	if (ret) {
-		pinmux_put(pmx);
-		kfree(hog);
-		dev_err(pctldev->dev,
-			"could not enable the %s pinmux mapping for hogging\n",
-			map->name);
-		return ret;
-	}
-
-	hog->map = map;
-	hog->pmx = pmx;
-
-	dev_info(pctldev->dev, "hogged map %s, function %s\n", map->name,
-		 map->function);
-	mutex_lock(&pctldev->pinmux_hogs_lock);
-	list_add(&hog->node, &pctldev->pinmux_hogs);
-	mutex_unlock(&pctldev->pinmux_hogs_lock);
-
 	return 0;
 }
 
 /**
- * pinmux_hog_maps() - hog specific map entries on controller device
- * @pctldev: the pin control device to hog entries on
- *
- * When the pin controllers are registered, there may be some specific pinmux
- * map entries that need to be hogged, i.e. get+enabled until the system shuts
- * down.
+ * pin_request() - request a single pin to be muxed in, typically for GPIO
+ * @pin: the pin number in the global pin space
+ * @owner: a representation of the owner of this pin; typically the device
+ *	name that controls its mux function, or the requested GPIO name
+ * @gpio_range: the range matching the GPIO pin if this is a request for a
+ *	single GPIO pin
  */
-int pinmux_hog_maps(struct pinctrl_dev *pctldev)
+static int pin_request(struct pinctrl_dev *pctldev,
+		       int pin, const char *owner,
+		       struct pinctrl_gpio_range *gpio_range)
 {
-	struct device *dev = pctldev->dev;
-	const char *devname = dev_name(dev);
+	struct pin_desc *desc;
+	const struct pinmux_ops *ops = pctldev->desc->pmxops;
+	int status = -EINVAL;
+
+	dev_dbg(pctldev->dev, "request pin %d for %s\n", pin, owner);
+
+	desc = pin_desc_get(pctldev, pin);
+	if (desc == NULL) {
+		dev_err(pctldev->dev,
+			"pin is not registered so it cannot be requested\n");
+		goto out;
+	}
+
+	if (gpio_range) {
+		/* There's no need to support multiple GPIO requests */
+		if (desc->gpio_owner) {
+			dev_err(pctldev->dev,
+				"pin already requested\n");
+			goto out;
+		}
+
+		desc->gpio_owner = owner;
+	} else {
+		if (desc->mux_usecount && strcmp(desc->mux_owner, owner)) {
+			dev_err(pctldev->dev,
+				"pin already requested\n");
+			goto out;
+		}
+
+		desc->mux_usecount++;
+		if (desc->mux_usecount > 1)
+			return 0;
+
+		desc->mux_owner = owner;
+	}
+
+	/* Let each pin increase references to this module */
+	if (!try_module_get(pctldev->owner)) {
+		dev_err(pctldev->dev,
+			"could not increase module refcount for pin %d\n",
+			pin);
+		status = -EINVAL;
+		goto out_free_pin;
+	}
+
+	/*
+	 * If there is no kind of request function for the pin we just assume
+	 * we got it by default and proceed.
+	 */
+	if (gpio_range && ops->gpio_request_enable)
+		/* This requests and enables a single GPIO pin */
+		status = ops->gpio_request_enable(pctldev, gpio_range, pin);
+	else if (ops->request)
+		status = ops->request(pctldev, pin);
+	else
+		status = 0;
+
+	if (status) {
+		dev_err(pctldev->dev, "->request on device %s failed for pin %d\n",
+		       pctldev->desc->name, pin);
+		module_put(pctldev->owner);
+	}
+
+out_free_pin:
+	if (status) {
+		if (gpio_range) {
+			desc->gpio_owner = NULL;
+		} else {
+			desc->mux_usecount--;
+			if (!desc->mux_usecount)
+				desc->mux_owner = NULL;
+		}
+	}
+out:
+	if (status)
+		dev_err(pctldev->dev, "pin-%d (%s) status %d\n",
+		       pin, owner, status);
+
+	return status;
+}
+
+/**
+ * pin_free() - release a single muxed in pin so something else can be muxed
+ * @pctldev: pin controller device handling this pin
+ * @pin: the pin to free
+ * @gpio_range: the range matching the GPIO pin if this is a request for a
+ *	single GPIO pin
+ *
+ * This function returns a pointer to the previous owner. This is used
+ * for callers that dynamically allocate an owner name so it can be freed
+ * once the pin is free. This is done for GPIO request functions.
+ */
+static const char *pin_free(struct pinctrl_dev *pctldev, int pin,
+			    struct pinctrl_gpio_range *gpio_range)
+{
+	const struct pinmux_ops *ops = pctldev->desc->pmxops;
+	struct pin_desc *desc;
+	const char *owner;
+
+	desc = pin_desc_get(pctldev, pin);
+	if (desc == NULL) {
+		dev_err(pctldev->dev,
+			"pin is not registered so it cannot be freed\n");
+		return NULL;
+	}
+
+	if (!gpio_range) {
+		desc->mux_usecount--;
+		if (desc->mux_usecount)
+			return NULL;
+	}
+
+	/*
+	 * If there is no kind of request function for the pin we just assume
+	 * we got it by default and proceed.
+	 */
+	if (gpio_range && ops->gpio_disable_free)
+		ops->gpio_disable_free(pctldev, gpio_range, pin);
+	else if (ops->free)
+		ops->free(pctldev, pin);
+
+	if (gpio_range) {
+		owner = desc->gpio_owner;
+		desc->gpio_owner = NULL;
+	} else {
+		owner = desc->mux_owner;
+		desc->mux_owner = NULL;
+		desc->mux_setting = NULL;
+	}
+
+	module_put(pctldev->owner);
+
+	return owner;
+}
+
+/**
+ * pinmux_request_gpio() - request pinmuxing for a GPIO pin
+ * @pctldev: pin controller device affected
+ * @pin: the pin to mux in for GPIO
+ * @range: the applicable GPIO range
+ */
+int pinmux_request_gpio(struct pinctrl_dev *pctldev,
+			struct pinctrl_gpio_range *range,
+			unsigned pin, unsigned gpio)
+{
+	char gpiostr[16];
+	const char *owner;
+	int ret;
+
+	/* Conjure some name stating what chip and pin this is taken by */
+	snprintf(gpiostr, 15, "%s:%d", range->name, gpio);
+
+	owner = kstrdup(gpiostr, GFP_KERNEL);
+	if (!owner)
+		return -EINVAL;
+
+	ret = pin_request(pctldev, pin, owner, range);
+	if (ret < 0)
+		kfree(owner);
+
+	return ret;
+}
+
+/**
+ * pinmux_free_gpio() - release a pin from GPIO muxing
+ * @pctldev: the pin controller device for the pin
+ * @pin: the affected currently GPIO-muxed in pin
+ * @range: applicable GPIO range
+ */
+void pinmux_free_gpio(struct pinctrl_dev *pctldev, unsigned pin,
+		      struct pinctrl_gpio_range *range)
+{
+	const char *owner;
+
+	owner = pin_free(pctldev, pin, range);
+	kfree(owner);
+}
+
+/**
+ * pinmux_gpio_direction() - set the direction of a single muxed-in GPIO pin
+ * @pctldev: the pin controller handling this pin
+ * @range: applicable GPIO range
+ * @pin: the affected GPIO pin in this controller
+ * @input: true if we set the pin as input, false for output
+ */
+int pinmux_gpio_direction(struct pinctrl_dev *pctldev,
+			  struct pinctrl_gpio_range *range,
+			  unsigned pin, bool input)
+{
+	const struct pinmux_ops *ops;
+	int ret;
+
+	ops = pctldev->desc->pmxops;
+
+	if (ops->gpio_set_direction)
+		ret = ops->gpio_set_direction(pctldev, range, pin, input);
+	else
+		ret = 0;
+
+	return ret;
+}
+
+static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev,
+					const char *function)
+{
+	const struct pinmux_ops *ops = pctldev->desc->pmxops;
+	unsigned selector = 0;
+
+	/* See if this pctldev has this function */
+	while (ops->list_functions(pctldev, selector) >= 0) {
+		const char *fname = ops->get_function_name(pctldev,
+							   selector);
+
+		if (!strcmp(function, fname))
+			return selector;
+
+		selector++;
+	}
+
+	pr_err("%s does not support function %s\n",
+	       pinctrl_dev_get_name(pctldev), function);
+	return -EINVAL;
+}
+
+int pinmux_map_to_setting(struct pinctrl_map const *map,
+			  struct pinctrl_setting *setting)
+{
+	struct pinctrl_dev *pctldev = setting->pctldev;
+	const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
+	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
+	char const * const *groups;
+	unsigned num_groups;
+	int ret;
+	const char *group;
+	int i;
+	const unsigned *pins;
+	unsigned num_pins;
+
+	setting->data.mux.func =
+		pinmux_func_name_to_selector(pctldev, map->data.mux.function);
+	if (setting->data.mux.func < 0)
+		return setting->data.mux.func;
+
+	ret = pmxops->get_function_groups(pctldev, setting->data.mux.func,
+					  &groups, &num_groups);
+	if (ret < 0)
+		return ret;
+	if (!num_groups)
+		return -EINVAL;
+
+	if (map->data.mux.group) {
+		bool found = false;
+		group = map->data.mux.group;
+		for (i = 0; i < num_groups; i++) {
+			if (!strcmp(group, groups[i])) {
+				found = true;
+				break;
+			}
+		}
+		if (!found)
+			return -EINVAL;
+	} else {
+		group = groups[0];
+	}
+
+	setting->data.mux.group = pinctrl_get_group_selector(pctldev, group);
+	if (setting->data.mux.group < 0)
+		return setting->data.mux.group;
+
+	ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, &pins,
+				      &num_pins);
+	if (ret) {
+		dev_err(pctldev->dev,
+			"could not get pins for device %s group selector %d\n",
+			pinctrl_dev_get_name(pctldev), setting->data.mux.group);
+			return -ENODEV;
+	}
+
+	/* Try to allocate all pins in this group, one by one */
+	for (i = 0; i < num_pins; i++) {
+		ret = pin_request(pctldev, pins[i], map->dev_name, NULL);
+		if (ret) {
+			dev_err(pctldev->dev,
+				"could not get request pin %d on device %s\n",
+				pins[i], pinctrl_dev_get_name(pctldev));
+			/* On error release all taken pins */
+			i--; /* this pin just failed */
+			for (; i >= 0; i--)
+				pin_free(pctldev, pins[i], NULL);
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+void pinmux_free_setting(struct pinctrl_setting const *setting)
+{
+	struct pinctrl_dev *pctldev = setting->pctldev;
+	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
+	const unsigned *pins;
+	unsigned num_pins;
 	int ret;
 	int i;
 
-	INIT_LIST_HEAD(&pctldev->pinmux_hogs);
-	mutex_init(&pctldev->pinmux_hogs_lock);
-
-	for (i = 0; i < pinmux_maps_num; i++) {
-		struct pinmux_map const *map = &pinmux_maps[i];
-
-		if (!map->hog_on_boot)
-			continue;
-
-		if ((map->ctrl_dev == dev) ||
-			(map->ctrl_dev_name &&
-				!strcmp(map->ctrl_dev_name, devname))) {
-			/* OK time to hog! */
-			ret = pinmux_hog_map(pctldev, map);
-			if (ret)
-				return ret;
-		}
+	ret = pctlops->get_group_pins(pctldev, setting->data.mux.group,
+				      &pins, &num_pins);
+	if (ret) {
+		dev_err(pctldev->dev,
+			"could not get pins for device %s group selector %d\n",
+			pinctrl_dev_get_name(pctldev), setting->data.mux.group);
+		return;
 	}
-	return 0;
+
+	for (i = 0; i < num_pins; i++)
+		pin_free(pctldev, pins[i], NULL);
 }
 
-/**
- * pinmux_unhog_maps() - unhog specific map entries on controller device
- * @pctldev: the pin control device to unhog entries on
- */
-void pinmux_unhog_maps(struct pinctrl_dev *pctldev)
+int pinmux_enable_setting(struct pinctrl_setting const *setting)
 {
-	struct list_head *node, *tmp;
+	struct pinctrl_dev *pctldev = setting->pctldev;
+	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
+	const struct pinmux_ops *ops = pctldev->desc->pmxops;
+	int ret;
+	const unsigned *pins;
+	unsigned num_pins;
+	int i;
+	struct pin_desc *desc;
 
-	mutex_lock(&pctldev->pinmux_hogs_lock);
-	list_for_each_safe(node, tmp, &pctldev->pinmux_hogs) {
-		struct pinmux_hog *hog =
-			list_entry(node, struct pinmux_hog, node);
-		pinmux_disable(hog->pmx);
-		pinmux_put(hog->pmx);
-		list_del(node);
-		kfree(hog);
+	ret = pctlops->get_group_pins(pctldev, setting->data.mux.group,
+				      &pins, &num_pins);
+	if (ret) {
+		/* errors only affect debug data, so just warn */
+		dev_warn(pctldev->dev,
+			 "could not get pins for group selector %d\n",
+			 setting->data.mux.group);
+		num_pins = 0;
 	}
-	mutex_unlock(&pctldev->pinmux_hogs_lock);
+
+	for (i = 0; i < num_pins; i++) {
+		desc = pin_desc_get(pctldev, pins[i]);
+		if (desc == NULL) {
+			dev_warn(pctldev->dev,
+				 "could not get pin desc for pin %d\n",
+				 pins[i]);
+			continue;
+		}
+		desc->mux_setting = &(setting->data.mux);
+	}
+
+	return ops->enable(pctldev, setting->data.mux.func,
+			   setting->data.mux.group);
+}
+
+void pinmux_disable_setting(struct pinctrl_setting const *setting)
+{
+	struct pinctrl_dev *pctldev = setting->pctldev;
+	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
+	const struct pinmux_ops *ops = pctldev->desc->pmxops;
+	int ret;
+	const unsigned *pins;
+	unsigned num_pins;
+	int i;
+	struct pin_desc *desc;
+
+	ret = pctlops->get_group_pins(pctldev, setting->data.mux.group,
+				      &pins, &num_pins);
+	if (ret) {
+		/* errors only affect debug data, so just warn */
+		dev_warn(pctldev->dev,
+			 "could not get pins for group selector %d\n",
+			 setting->data.mux.group);
+		num_pins = 0;
+	}
+
+	for (i = 0; i < num_pins; i++) {
+		desc = pin_desc_get(pctldev, pins[i]);
+		if (desc == NULL) {
+			dev_warn(pctldev->dev,
+				 "could not get pin desc for pin %d\n",
+				 pins[i]);
+			continue;
+		}
+		desc->mux_setting = NULL;
+	}
+
+	ops->disable(pctldev, setting->data.mux.func, setting->data.mux.group);
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -1037,6 +479,8 @@
 	const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
 	unsigned func_selector = 0;
 
+	mutex_lock(&pinctrl_mutex);
+
 	while (pmxops->list_functions(pctldev, func_selector) >= 0) {
 		const char *func = pmxops->get_function_name(pctldev,
 							  func_selector);
@@ -1057,24 +501,29 @@
 		seq_puts(s, "]\n");
 
 		func_selector++;
-
 	}
 
+	mutex_unlock(&pinctrl_mutex);
+
 	return 0;
 }
 
 static int pinmux_pins_show(struct seq_file *s, void *what)
 {
 	struct pinctrl_dev *pctldev = s->private;
+	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
+	const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
 	unsigned i, pin;
 
 	seq_puts(s, "Pinmux settings per pin\n");
-	seq_puts(s, "Format: pin (name): pinmuxfunction\n");
+	seq_puts(s, "Format: pin (name): mux_owner gpio_owner hog?\n");
+
+	mutex_lock(&pinctrl_mutex);
 
 	/* The pin number can be retrived from the pin controller descriptor */
 	for (i = 0; i < pctldev->desc->npins; i++) {
-
 		struct pin_desc *desc;
+		bool is_hog = false;
 
 		pin = pctldev->desc->pins[i].number;
 		desc = pin_desc_get(pctldev, pin);
@@ -1082,94 +531,52 @@
 		if (desc == NULL)
 			continue;
 
-		seq_printf(s, "pin %d (%s): %s\n", pin,
+		if (desc->mux_owner &&
+		    !strcmp(desc->mux_owner, pinctrl_dev_get_name(pctldev)))
+			is_hog = true;
+
+		seq_printf(s, "pin %d (%s): %s %s%s", pin,
 			   desc->name ? desc->name : "unnamed",
-			   desc->mux_function ? desc->mux_function
-					      : "UNCLAIMED");
-	}
+			   desc->mux_owner ? desc->mux_owner
+				: "(MUX UNCLAIMED)",
+			   desc->gpio_owner ? desc->gpio_owner
+				: "(GPIO UNCLAIMED)",
+			   is_hog ? " (HOG)" : "");
 
-	return 0;
-}
-
-static int pinmux_hogs_show(struct seq_file *s, void *what)
-{
-	struct pinctrl_dev *pctldev = s->private;
-	struct pinmux_hog *hog;
-
-	seq_puts(s, "Pinmux map hogs held by device\n");
-
-	list_for_each_entry(hog, &pctldev->pinmux_hogs, node)
-		seq_printf(s, "%s\n", hog->map->name);
-
-	return 0;
-}
-
-static int pinmux_show(struct seq_file *s, void *what)
-{
-	struct pinmux *pmx;
-
-	seq_puts(s, "Requested pinmuxes and their maps:\n");
-	list_for_each_entry(pmx, &pinmux_list, node) {
-		struct pinctrl_dev *pctldev = pmx->pctldev;
-		const struct pinmux_ops *pmxops;
-		const struct pinctrl_ops *pctlops;
-		struct pinmux_group *grp;
-
-		if (!pctldev) {
-			seq_puts(s, "NO PIN CONTROLLER DEVICE\n");
-			continue;
-		}
-
-		pmxops = pctldev->desc->pmxops;
-		pctlops = pctldev->desc->pctlops;
-
-		seq_printf(s, "device: %s function: %s (%u),",
-			   pinctrl_dev_get_name(pmx->pctldev),
-			   pmxops->get_function_name(pctldev,
-				   pmx->func_selector),
-			   pmx->func_selector);
-
-		seq_printf(s, " groups: [");
-		list_for_each_entry(grp, &pmx->groups, node) {
-			seq_printf(s, " %s (%u)",
+		if (desc->mux_setting)
+			seq_printf(s, " function %s group %s\n",
+				   pmxops->get_function_name(pctldev,
+					desc->mux_setting->func),
 				   pctlops->get_group_name(pctldev,
-					   grp->group_selector),
-				   grp->group_selector);
-		}
-		seq_printf(s, " ]");
-
-		seq_printf(s, " users: %u map-> %s\n",
-			   pmx->usecount,
-			   pmx->dev ? dev_name(pmx->dev) : "(system)");
+					desc->mux_setting->group));
+		else
+			seq_printf(s, "\n");
 	}
 
+	mutex_unlock(&pinctrl_mutex);
+
 	return 0;
 }
 
-static int pinmux_maps_show(struct seq_file *s, void *what)
+void pinmux_show_map(struct seq_file *s, struct pinctrl_map const *map)
 {
-	int i;
+	seq_printf(s, "group %s\nfunction %s\n",
+		map->data.mux.group ? map->data.mux.group : "(default)",
+		map->data.mux.function);
+}
 
-	seq_puts(s, "Pinmux maps:\n");
+void pinmux_show_setting(struct seq_file *s,
+			 struct pinctrl_setting const *setting)
+{
+	struct pinctrl_dev *pctldev = setting->pctldev;
+	const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
+	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
 
-	for (i = 0; i < pinmux_maps_num; i++) {
-		struct pinmux_map const *map = &pinmux_maps[i];
-
-		seq_printf(s, "%s:\n", map->name);
-		if (map->dev || map->dev_name)
-			seq_printf(s, "  device: %s\n",
-				   map->dev ? dev_name(map->dev) :
-				   map->dev_name);
-		else
-			seq_printf(s, "  SYSTEM MUX\n");
-		seq_printf(s, "  controlling device %s\n",
-			   map->ctrl_dev ? dev_name(map->ctrl_dev) :
-			   map->ctrl_dev_name);
-		seq_printf(s, "  function: %s\n", map->function);
-		seq_printf(s, "  group: %s\n", map->group ? map->group :
-			   "(default)");
-	}
-	return 0;
+	seq_printf(s, "group: %s (%u) function: %s (%u)\n",
+		   pctlops->get_group_name(pctldev, setting->data.mux.group),
+		   setting->data.mux.group,
+		   pmxops->get_function_name(pctldev, setting->data.mux.func),
+		   setting->data.mux.func);
 }
 
 static int pinmux_functions_open(struct inode *inode, struct file *file)
@@ -1182,21 +589,6 @@
 	return single_open(file, pinmux_pins_show, inode->i_private);
 }
 
-static int pinmux_hogs_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, pinmux_hogs_show, inode->i_private);
-}
-
-static int pinmux_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, pinmux_show, NULL);
-}
-
-static int pinmux_maps_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, pinmux_maps_show, NULL);
-}
-
 static const struct file_operations pinmux_functions_ops = {
 	.open		= pinmux_functions_open,
 	.read		= seq_read,
@@ -1211,27 +603,6 @@
 	.release	= single_release,
 };
 
-static const struct file_operations pinmux_hogs_ops = {
-	.open		= pinmux_hogs_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static const struct file_operations pinmux_ops = {
-	.open		= pinmux_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static const struct file_operations pinmux_maps_ops = {
-	.open		= pinmux_maps_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
 void pinmux_init_device_debugfs(struct dentry *devroot,
 			 struct pinctrl_dev *pctldev)
 {
@@ -1239,16 +610,6 @@
 			    devroot, pctldev, &pinmux_functions_ops);
 	debugfs_create_file("pinmux-pins", S_IFREG | S_IRUGO,
 			    devroot, pctldev, &pinmux_pins_ops);
-	debugfs_create_file("pinmux-hogs", S_IFREG | S_IRUGO,
-			    devroot, pctldev, &pinmux_hogs_ops);
-}
-
-void pinmux_init_debugfs(struct dentry *subsys_root)
-{
-	debugfs_create_file("pinmuxes", S_IFREG | S_IRUGO,
-			    subsys_root, NULL, &pinmux_ops);
-	debugfs_create_file("pinmux-maps", S_IFREG | S_IRUGO,
-			    subsys_root, NULL, &pinmux_maps_ops);
 }
 
 #endif /* CONFIG_DEBUG_FS */
diff --git a/drivers/pinctrl/pinmux.h b/drivers/pinctrl/pinmux.h
index 97f5222..6fc4700 100644
--- a/drivers/pinctrl/pinmux.h
+++ b/drivers/pinctrl/pinmux.h
@@ -13,11 +13,29 @@
 #ifdef CONFIG_PINMUX
 
 int pinmux_check_ops(struct pinctrl_dev *pctldev);
+
+int pinmux_validate_map(struct pinctrl_map const *map, int i);
+
+int pinmux_request_gpio(struct pinctrl_dev *pctldev,
+			struct pinctrl_gpio_range *range,
+			unsigned pin, unsigned gpio);
+void pinmux_free_gpio(struct pinctrl_dev *pctldev, unsigned pin,
+		      struct pinctrl_gpio_range *range);
+int pinmux_gpio_direction(struct pinctrl_dev *pctldev,
+			  struct pinctrl_gpio_range *range,
+			  unsigned pin, bool input);
+
+int pinmux_map_to_setting(struct pinctrl_map const *map,
+			  struct pinctrl_setting *setting);
+void pinmux_free_setting(struct pinctrl_setting const *setting);
+int pinmux_enable_setting(struct pinctrl_setting const *setting);
+void pinmux_disable_setting(struct pinctrl_setting const *setting);
+
+void pinmux_show_map(struct seq_file *s, struct pinctrl_map const *map);
+void pinmux_show_setting(struct seq_file *s,
+			 struct pinctrl_setting const *setting);
 void pinmux_init_device_debugfs(struct dentry *devroot,
 				struct pinctrl_dev *pctldev);
-void pinmux_init_debugfs(struct dentry *subsys_root);
-int pinmux_hog_maps(struct pinctrl_dev *pctldev);
-void pinmux_unhog_maps(struct pinctrl_dev *pctldev);
 
 #else
 
@@ -26,21 +44,63 @@
 	return 0;
 }
 
-static inline void pinmux_init_device_debugfs(struct dentry *devroot,
-					      struct pinctrl_dev *pctldev)
-{
-}
-
-static inline void pinmux_init_debugfs(struct dentry *subsys_root)
-{
-}
-
-static inline int pinmux_hog_maps(struct pinctrl_dev *pctldev)
+static inline int pinmux_validate_map(struct pinctrl_map const *map, int i)
 {
 	return 0;
 }
 
-static inline void pinmux_unhog_maps(struct pinctrl_dev *pctldev)
+static inline int pinmux_request_gpio(struct pinctrl_dev *pctldev,
+			struct pinctrl_gpio_range *range,
+			unsigned pin, unsigned gpio)
+{
+	return 0;
+}
+
+static inline void pinmux_free_gpio(struct pinctrl_dev *pctldev,
+				    unsigned pin,
+				    struct pinctrl_gpio_range *range)
+{
+}
+
+static inline int pinmux_gpio_direction(struct pinctrl_dev *pctldev,
+					struct pinctrl_gpio_range *range,
+					unsigned pin, bool input)
+{
+	return 0;
+}
+
+static inline int pinmux_map_to_setting(struct pinctrl_map const *map,
+			  struct pinctrl_setting *setting)
+{
+	return 0;
+}
+
+static inline void pinmux_free_setting(struct pinctrl_setting const *setting)
+{
+}
+
+static inline int pinmux_enable_setting(struct pinctrl_setting const *setting)
+{
+	return 0;
+}
+
+static inline void pinmux_disable_setting(
+			struct pinctrl_setting const *setting)
+{
+}
+
+static inline void pinmux_show_map(struct seq_file *s,
+				   struct pinctrl_map const *map)
+{
+}
+
+static inline void pinmux_show_setting(struct seq_file *s,
+				       struct pinctrl_setting const *setting)
+{
+}
+
+static inline void pinmux_init_device_debugfs(struct dentry *devroot,
+					      struct pinctrl_dev *pctldev)
 {
 }
 
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 15dbd8c..2a262f5 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -26,6 +26,10 @@
 	depends on RFKILL || RFKILL = n
 	depends on ACPI_WMI
 	select INPUT_SPARSEKMAP
+	# Acer WMI depends on ACPI_VIDEO when ACPI is enabled
+	# but for select to work, need to select ACPI_VIDEO's dependencies, ick
+        select VIDEO_OUTPUT_CONTROL if ACPI
+        select ACPI_VIDEO if ACPI
 	---help---
 	  This is a driver for newer Acer (and Wistron) laptops. It adds
 	  wireless radio and bluetooth control, and on some laptops,
@@ -54,7 +58,6 @@
 config ASUS_LAPTOP
 	tristate "Asus Laptop Extras"
 	depends on ACPI
-	depends on !ACPI_ASUS
 	select LEDS_CLASS
 	select NEW_LEDS
 	select BACKLIGHT_CLASS_DEVICE
@@ -460,10 +463,9 @@
 	  If unsure, say N.
 
 config EEEPC_LAPTOP
-	tristate "Eee PC Hotkey Driver (EXPERIMENTAL)"
+	tristate "Eee PC Hotkey Driver"
 	depends on ACPI
 	depends on INPUT
-	depends on EXPERIMENTAL
 	depends on RFKILL || RFKILL = n
 	depends on HOTPLUG_PCI
 	select BACKLIGHT_CLASS_DEVICE
@@ -482,11 +484,10 @@
 	  doesn't work on your Eee PC, try eeepc-wmi instead.
 
 config ASUS_WMI
-	tristate "ASUS WMI Driver (EXPERIMENTAL)"
+	tristate "ASUS WMI Driver"
 	depends on ACPI_WMI
 	depends on INPUT
 	depends on HWMON
-	depends on EXPERIMENTAL
 	depends on BACKLIGHT_CLASS_DEVICE
 	depends on RFKILL || RFKILL = n
 	depends on HOTPLUG_PCI
@@ -501,7 +502,7 @@
 	  be called asus-wmi.
 
 config ASUS_NB_WMI
-	tristate "Asus Notebook WMI Driver (EXPERIMENTAL)"
+	tristate "Asus Notebook WMI Driver"
 	depends on ASUS_WMI
 	---help---
 	  This is a driver for newer Asus notebooks. It adds extra features
@@ -514,7 +515,7 @@
 	  here.
 
 config EEEPC_WMI
-	tristate "Eee PC WMI Driver (EXPERIMENTAL)"
+	tristate "Eee PC WMI Driver"
 	depends on ASUS_WMI
 	---help---
 	  This is a driver for newer Eee PC laptops. It adds extra features
@@ -559,38 +560,6 @@
 	 To compile this driver as a module, choose M here: the module will
 	 be called msi-wmi.
 
-config ACPI_ASUS
-	tristate "ASUS/Medion Laptop Extras (DEPRECATED)"
-	depends on ACPI
-	select BACKLIGHT_CLASS_DEVICE
-	---help---
-	  This driver provides support for extra features of ACPI-compatible
-	  ASUS laptops. As some of Medion laptops are made by ASUS, it may also
-	  support some Medion laptops (such as 9675 for example).  It makes all
-	  the extra buttons generate standard ACPI events that go through
-	  /proc/acpi/events, and (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.
-
-	  Note: display switching code is currently considered EXPERIMENTAL,
-	  toying with these values may even lock your machine.
-
-	  All settings are changed via /proc/acpi/asus directory entries. Owner
-	  and group for these entries can be set with asus_uid and asus_gid
-	  parameters.
-
-	  More information and a userspace daemon for handling the extra buttons
-	  at <http://acpi4asus.sf.net>.
-
-	  If you have an ACPI-compatible ASUS laptop, say Y or M here. This
-	  driver is still under development, so if your laptop is unsupported or
-	  something works not quite as expected, please use the mailing list
-	  available on the above page (acpi4asus-user@lists.sourceforge.net).
-
-	  NOTE: This driver is deprecated and will probably be removed soon,
-	  use asus-laptop instead.
-
 config TOPSTAR_LAPTOP
 	tristate "Topstar Laptop Extras"
 	depends on ACPI
@@ -604,6 +573,7 @@
 config ACPI_TOSHIBA
 	tristate "Toshiba Laptop Extras"
 	depends on ACPI
+	depends on ACPI_WMI
 	select LEDS_CLASS
 	select NEW_LEDS
 	depends on BACKLIGHT_CLASS_DEVICE
@@ -696,33 +666,11 @@
 
 config INTEL_MFLD_THERMAL
        tristate "Thermal driver for Intel Medfield platform"
-       depends on INTEL_SCU_IPC && THERMAL
+       depends on MFD_INTEL_MSIC && THERMAL
        help
          Say Y here to enable thermal driver support for the  Intel Medfield
          platform.
 
-config RAR_REGISTER
-	bool "Restricted Access Region Register Driver"
-	depends on PCI && X86_MRST
-	default n
-	---help---
-	  This driver allows other kernel drivers access to the
-	  contents of the restricted access region control registers.
-
-	  The restricted access region control registers
-	  (rar_registers) are used to pass address and
-	  locking information on restricted access regions
-	  to other drivers that use restricted access regions.
-
-	  The restricted access regions are regions of memory
-	  on the Intel MID Platform that are not accessible to
-	  the x86 processor, but are accessible to dedicated
-	  processors on board peripheral devices.
-
-	  The purpose of the restricted access regions is to
-	  protect sensitive data from compromise by unauthorized
-	  programs running on the x86 processor.
-
 config INTEL_IPS
 	tristate "Intel Intelligent Power Sharing"
 	depends on ACPI
@@ -768,13 +716,18 @@
 
 config SAMSUNG_LAPTOP
 	tristate "Samsung Laptop driver"
-	depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86
+	depends on X86
+	depends on RFKILL || RFKILL = n
+	depends on BACKLIGHT_CLASS_DEVICE
+	select LEDS_CLASS
+	select NEW_LEDS
 	---help---
 	  This module implements a driver for a wide range of different
 	  Samsung laptops.  It offers control over the different
-	  function keys, wireless LED, LCD backlight level, and
-	  sometimes provides a "performance_control" sysfs file to allow
-	  the performance level of the laptop to be changed.
+	  function keys, wireless LED, LCD backlight level.
+
+	  It may also provide some sysfs files described in
+	  <file:Documentation/ABI/testing/sysfs-platform-samsung-laptop>
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called samsung-laptop.
@@ -803,4 +756,14 @@
 	  This driver provides support for backlight control on Samsung Q10
 	  and related laptops, including Dell Latitude X200.
 
+config APPLE_GMUX
+	tristate "Apple Gmux Driver"
+	depends on PNP
+	select BACKLIGHT_CLASS_DEVICE
+	---help---
+	  This driver provides support for the gmux device found on many
+	  Apple laptops, which controls the display mux for the hybrid
+	  graphics as well as the backlight. Currently only backlight
+	  control is supported by the driver.
+
 endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index d328f21..bf7e4f9 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -29,14 +29,16 @@
 obj-$(CONFIG_INTEL_MENLOW)	+= intel_menlow.o
 obj-$(CONFIG_ACPI_WMI)		+= wmi.o
 obj-$(CONFIG_MSI_WMI)		+= msi-wmi.o
-obj-$(CONFIG_ACPI_ASUS)		+= asus_acpi.o
 obj-$(CONFIG_TOPSTAR_LAPTOP)	+= topstar-laptop.o
+
+# toshiba_acpi must link after wmi to ensure that wmi devices are found
+# before toshiba_acpi initializes
 obj-$(CONFIG_ACPI_TOSHIBA)	+= toshiba_acpi.o
+
 obj-$(CONFIG_TOSHIBA_BT_RFKILL)	+= toshiba_bluetooth.o
 obj-$(CONFIG_INTEL_SCU_IPC)	+= intel_scu_ipc.o
 obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
 obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
-obj-$(CONFIG_RAR_REGISTER)	+= intel_rar_register.o
 obj-$(CONFIG_INTEL_IPS)		+= intel_ips.o
 obj-$(CONFIG_GPIO_INTEL_PMIC)	+= intel_pmic_gpio.o
 obj-$(CONFIG_XO1_RFKILL)	+= xo1-rfkill.o
@@ -47,3 +49,4 @@
 obj-$(CONFIG_INTEL_MID_POWER_BUTTON)	+= intel_mid_powerbtn.o
 obj-$(CONFIG_INTEL_OAKTRAIL)	+= intel_oaktrail.o
 obj-$(CONFIG_SAMSUNG_Q10)	+= samsung-q10.o
+obj-$(CONFIG_APPLE_GMUX)	+= apple-gmux.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 1e5290b..c1a3fd8 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -43,6 +43,7 @@
 #include <linux/input/sparse-keymap.h>
 
 #include <acpi/acpi_drivers.h>
+#include <acpi/video.h>
 
 MODULE_AUTHOR("Carlos Corbacho");
 MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
@@ -105,13 +106,19 @@
 	{KE_KEY, 0x22, {KEY_PROG2} },    /* Arcade */
 	{KE_KEY, 0x23, {KEY_PROG3} },    /* P_Key */
 	{KE_KEY, 0x24, {KEY_PROG4} },    /* Social networking_Key */
+	{KE_KEY, 0x29, {KEY_PROG3} },    /* P_Key for TM8372 */
 	{KE_IGNORE, 0x41, {KEY_MUTE} },
 	{KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} },
+	{KE_IGNORE, 0x4d, {KEY_PREVIOUSSONG} },
 	{KE_IGNORE, 0x43, {KEY_NEXTSONG} },
+	{KE_IGNORE, 0x4e, {KEY_NEXTSONG} },
 	{KE_IGNORE, 0x44, {KEY_PLAYPAUSE} },
+	{KE_IGNORE, 0x4f, {KEY_PLAYPAUSE} },
 	{KE_IGNORE, 0x45, {KEY_STOP} },
+	{KE_IGNORE, 0x50, {KEY_STOP} },
 	{KE_IGNORE, 0x48, {KEY_VOLUMEUP} },
 	{KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} },
+	{KE_IGNORE, 0x4a, {KEY_VOLUMEDOWN} },
 	{KE_IGNORE, 0x61, {KEY_SWITCHVIDEOMODE} },
 	{KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} },
 	{KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} },
@@ -153,7 +160,14 @@
 	u16 reserved;
 } __attribute__((packed));
 
-struct wmid3_gds_input_param {	/* Get Device Status input parameter */
+struct wmid3_gds_set_input_param {     /* Set Device Status input parameter */
+	u8 function_num;        /* Function Number */
+	u8 hotkey_number;       /* Hotkey Number */
+	u16 devices;            /* Set Device */
+	u8 volume_value;        /* Volume Value */
+} __attribute__((packed));
+
+struct wmid3_gds_get_input_param {     /* Get Device Status input parameter */
 	u8 function_num;	/* Function Number */
 	u8 hotkey_number;	/* Hotkey Number */
 	u16 devices;		/* Get Device */
@@ -171,6 +185,11 @@
 	u8 length;
 	u16 handle;
 	u16 commun_func_bitmap;
+	u16 application_func_bitmap;
+	u16 media_func_bitmap;
+	u16 display_func_bitmap;
+	u16 others_func_bitmap;
+	u8 commun_fn_key_number;
 } __attribute__((packed));
 
 /*
@@ -207,6 +226,7 @@
 static bool ec_raw_mode;
 static bool has_type_aa;
 static u16 commun_func_bitmap;
+static u8 commun_fn_key_number;
 
 module_param(mailled, int, 0444);
 module_param(brightness, int, 0444);
@@ -468,6 +488,15 @@
 	},
 	{
 		.callback = dmi_matched,
+		.ident = "Lenovo Ideapad S205 (Brazos)",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Brazos"),
+		},
+		.driver_data = &quirk_lenovo_ideapad_s205,
+	},
+	{
+		.callback = dmi_matched,
 		.ident = "Lenovo 3000 N200",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -478,6 +507,25 @@
 	{}
 };
 
+static int video_set_backlight_video_vendor(const struct dmi_system_id *d)
+{
+	interface->capability &= ~ACER_CAP_BRIGHTNESS;
+	pr_info("Brightness must be controlled by generic video driver\n");
+	return 0;
+}
+
+static const struct dmi_system_id video_vendor_dmi_table[] = {
+	{
+		.callback = video_set_backlight_video_vendor,
+		.ident = "Acer TravelMate 4750",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
+		},
+	},
+	{}
+};
+
 /* Find which quirks are needed for a particular vendor/ model pair */
 static void find_quirks(void)
 {
@@ -536,8 +584,7 @@
 	return status;
 }
 
-static acpi_status AMW0_get_u32(u32 *value, u32 cap,
-struct wmi_interface *iface)
+static acpi_status AMW0_get_u32(u32 *value, u32 cap)
 {
 	int err;
 	u8 result;
@@ -607,7 +654,7 @@
 	return AE_OK;
 }
 
-static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
+static acpi_status AMW0_set_u32(u32 value, u32 cap)
 {
 	struct wmab_args args;
 
@@ -692,6 +739,7 @@
 	{ "VPC2004", 0},
 	{ "IBM0068", 0},
 	{ "LEN0068", 0},
+	{ "SNY5001", 0},	/* sony-laptop in charge */
 	{ "", 0},
 };
 
@@ -827,8 +875,7 @@
 	return status;
 }
 
-static acpi_status WMID_get_u32(u32 *value, u32 cap,
-struct wmi_interface *iface)
+static acpi_status WMID_get_u32(u32 *value, u32 cap)
 {
 	acpi_status status;
 	u8 tmp;
@@ -864,7 +911,7 @@
 	return status;
 }
 
-static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
+static acpi_status WMID_set_u32(u32 value, u32 cap)
 {
 	u32 method_id = 0;
 	char param;
@@ -912,13 +959,13 @@
 	struct wmid3_gds_return_value return_value;
 	acpi_status status;
 	union acpi_object *obj;
-	struct wmid3_gds_input_param params = {
+	struct wmid3_gds_get_input_param params = {
 		.function_num = 0x1,
-		.hotkey_number = 0x01,
+		.hotkey_number = commun_fn_key_number,
 		.devices = device,
 	};
 	struct acpi_buffer input = {
-		sizeof(struct wmid3_gds_input_param),
+		sizeof(struct wmid3_gds_get_input_param),
 		&params
 	};
 	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -981,19 +1028,28 @@
 	acpi_status status;
 	union acpi_object *obj;
 	u16 devices;
-	struct wmid3_gds_input_param params = {
+	struct wmid3_gds_get_input_param get_params = {
 		.function_num = 0x1,
-		.hotkey_number = 0x01,
+		.hotkey_number = commun_fn_key_number,
 		.devices = commun_func_bitmap,
 	};
-	struct acpi_buffer input = {
-		sizeof(struct wmid3_gds_input_param),
-		&params
+	struct acpi_buffer get_input = {
+		sizeof(struct wmid3_gds_get_input_param),
+		&get_params
+	};
+	struct wmid3_gds_set_input_param set_params = {
+		.function_num = 0x2,
+		.hotkey_number = commun_fn_key_number,
+		.devices = commun_func_bitmap,
+	};
+	struct acpi_buffer set_input = {
+		sizeof(struct wmid3_gds_set_input_param),
+		&set_params
 	};
 	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
 	struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
 
-	status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
+	status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &get_input, &output);
 	if (ACPI_FAILURE(status))
 		return status;
 
@@ -1006,7 +1062,7 @@
 		return AE_ERROR;
 	}
 	if (obj->buffer.length != 8) {
-		pr_warning("Unknown buffer length %d\n", obj->buffer.length);
+		pr_warn("Unknown buffer length %d\n", obj->buffer.length);
 		kfree(obj);
 		return AE_ERROR;
 	}
@@ -1015,18 +1071,16 @@
 	kfree(obj);
 
 	if (return_value.error_code || return_value.ec_return_value) {
-		pr_warning("Get Current Device Status failed: "
-			"0x%x - 0x%x\n", return_value.error_code,
+		pr_warn("Get Current Device Status failed: 0x%x - 0x%x\n",
+			return_value.error_code,
 			return_value.ec_return_value);
 		return status;
 	}
 
 	devices = return_value.devices;
-	params.function_num = 0x2;
-	params.hotkey_number = 0x01;
-	params.devices = (value) ? (devices | device) : (devices & ~device);
+	set_params.devices = (value) ? (devices | device) : (devices & ~device);
 
-	status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2);
+	status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &set_input, &output2);
 	if (ACPI_FAILURE(status))
 		return status;
 
@@ -1039,7 +1093,7 @@
 		return AE_ERROR;
 	}
 	if (obj->buffer.length != 4) {
-		pr_warning("Unknown buffer length %d\n", obj->buffer.length);
+		pr_warn("Unknown buffer length %d\n", obj->buffer.length);
 		kfree(obj);
 		return AE_ERROR;
 	}
@@ -1048,8 +1102,8 @@
 	kfree(obj);
 
 	if (return_value.error_code || return_value.ec_return_value)
-		pr_warning("Set Device Status failed: "
-			"0x%x - 0x%x\n", return_value.error_code,
+		pr_warn("Set Device Status failed: 0x%x - 0x%x\n",
+			return_value.error_code,
 			return_value.ec_return_value);
 
 	return status;
@@ -1096,6 +1150,8 @@
 		interface->capability |= ACER_CAP_THREEG;
 	if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
 		interface->capability |= ACER_CAP_BLUETOOTH;
+
+	commun_fn_key_number = type_aa->commun_fn_key_number;
 }
 
 static acpi_status WMID_set_capabilities(void)
@@ -1154,15 +1210,15 @@
 
 	switch (interface->type) {
 	case ACER_AMW0:
-		status = AMW0_get_u32(value, cap, interface);
+		status = AMW0_get_u32(value, cap);
 		break;
 	case ACER_AMW0_V2:
 		if (cap == ACER_CAP_MAILLED) {
-			status = AMW0_get_u32(value, cap, interface);
+			status = AMW0_get_u32(value, cap);
 			break;
 		}
 	case ACER_WMID:
-		status = WMID_get_u32(value, cap, interface);
+		status = WMID_get_u32(value, cap);
 		break;
 	case ACER_WMID_v2:
 		if (cap & (ACER_CAP_WIRELESS |
@@ -1170,7 +1226,7 @@
 			   ACER_CAP_THREEG))
 			status = wmid_v2_get_u32(value, cap);
 		else if (wmi_has_guid(WMID_GUID2))
-			status = WMID_get_u32(value, cap, interface);
+			status = WMID_get_u32(value, cap);
 		break;
 	}
 
@@ -1184,10 +1240,10 @@
 	if (interface->capability & cap) {
 		switch (interface->type) {
 		case ACER_AMW0:
-			return AMW0_set_u32(value, cap, interface);
+			return AMW0_set_u32(value, cap);
 		case ACER_AMW0_V2:
 			if (cap == ACER_CAP_MAILLED)
-				return AMW0_set_u32(value, cap, interface);
+				return AMW0_set_u32(value, cap);
 
 			/*
 			 * On some models, some WMID methods don't toggle
@@ -1197,21 +1253,21 @@
 			 */
 			if (cap == ACER_CAP_WIRELESS ||
 				cap == ACER_CAP_BLUETOOTH) {
-				status = WMID_set_u32(value, cap, interface);
+				status = WMID_set_u32(value, cap);
 				if (ACPI_FAILURE(status))
 					return status;
 
-				return AMW0_set_u32(value, cap, interface);
+				return AMW0_set_u32(value, cap);
 			}
 		case ACER_WMID:
-			return WMID_set_u32(value, cap, interface);
+			return WMID_set_u32(value, cap);
 		case ACER_WMID_v2:
 			if (cap & (ACER_CAP_WIRELESS |
 				   ACER_CAP_BLUETOOTH |
 				   ACER_CAP_THREEG))
 				return wmid_v2_set_u32(value, cap);
 			else if (wmi_has_guid(WMID_GUID2))
-				return WMID_set_u32(value, cap, interface);
+				return WMID_set_u32(value, cap);
 		default:
 			return AE_BAD_PARAMETER;
 		}
@@ -1488,8 +1544,8 @@
 	u32 result; \
 	acpi_status status;
 
-	pr_info("This threeg sysfs will be removed in 2012"
-		" - used by: %s\n", current->comm);
+	pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
+		current->comm);
 	status = get_u32(&result, ACER_CAP_THREEG);
 	if (ACPI_SUCCESS(status))
 		return sprintf(buf, "%u\n", result);
@@ -1501,8 +1557,8 @@
 {
 	u32 tmp = simple_strtoul(buf, NULL, 10);
 	acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
-	pr_info("This threeg sysfs will be removed in 2012"
-		" - used by: %s\n", current->comm);
+	pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
+		current->comm);
 	if (ACPI_FAILURE(status))
 		return -EINVAL;
 	return count;
@@ -1513,8 +1569,8 @@
 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
 	char *buf)
 {
-	pr_info("This interface sysfs will be removed in 2012"
-		" - used by: %s\n", current->comm);
+	pr_info("This interface sysfs will be removed in 2012 - used by: %s\n",
+		current->comm);
 	switch (interface->type) {
 	case ACER_AMW0:
 		return sprintf(buf, "AMW0\n");
@@ -1981,9 +2037,13 @@
 	set_quirks();
 
 	if (acpi_video_backlight_support()) {
-		interface->capability &= ~ACER_CAP_BRIGHTNESS;
-		pr_info("Brightness must be controlled by "
-		       "generic video driver\n");
+		if (dmi_check_system(video_vendor_dmi_table)) {
+			acpi_video_unregister();
+		} else {
+			interface->capability &= ~ACER_CAP_BRIGHTNESS;
+			pr_info("Brightness must be controlled by "
+				"acpi video driver\n");
+		}
 	}
 
 	if (wmi_has_guid(WMID_GUID3)) {
@@ -2008,7 +2068,7 @@
 
 	err = platform_driver_register(&acer_platform_driver);
 	if (err) {
-		pr_err("Unable to register platform driver.\n");
+		pr_err("Unable to register platform driver\n");
 		goto error_platform_register;
 	}
 
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 760c6d7..bc8384c 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -244,12 +244,11 @@
 	unsigned char cmd;
 
 	if (verbose)
-		pr_notice("fan %s\n", (state == ACERHDF_FAN_OFF) ?
-				"OFF" : "ON");
+		pr_notice("fan %s\n", state == ACERHDF_FAN_OFF ? "OFF" : "ON");
 
 	if ((state != ACERHDF_FAN_OFF) && (state != ACERHDF_FAN_AUTO)) {
 		pr_err("invalid fan state %d requested, setting to auto!\n",
-			state);
+		       state);
 		state = ACERHDF_FAN_AUTO;
 	}
 
@@ -264,19 +263,18 @@
 {
 	if (fanon > ACERHDF_MAX_FANON) {
 		pr_err("fanon temperature too high, set to %d\n",
-				ACERHDF_MAX_FANON);
+		       ACERHDF_MAX_FANON);
 		fanon = ACERHDF_MAX_FANON;
 	}
 
 	if (kernelmode && prev_interval != interval) {
 		if (interval > ACERHDF_MAX_INTERVAL) {
 			pr_err("interval too high, set to %d\n",
-				ACERHDF_MAX_INTERVAL);
+			       ACERHDF_MAX_INTERVAL);
 			interval = ACERHDF_MAX_INTERVAL;
 		}
 		if (verbose)
-			pr_notice("interval changed to: %d\n",
-					interval);
+			pr_notice("interval changed to: %d\n", interval);
 		thermal->polling_delay = interval*1000;
 		prev_interval = interval;
 	}
@@ -587,8 +585,8 @@
 	}
 
 	if (!bios_cfg) {
-		pr_err("unknown (unsupported) BIOS version %s/%s/%s, "
-			"please report, aborting!\n", vendor, product, version);
+		pr_err("unknown (unsupported) BIOS version %s/%s/%s, please report, aborting!\n",
+		       vendor, product, version);
 		return -EINVAL;
 	}
 
@@ -598,8 +596,7 @@
 	 */
 	if (!kernelmode) {
 		pr_notice("Fan control off, to enable do:\n");
-		pr_notice("echo -n \"enabled\" > "
-			"/sys/class/thermal/thermal_zone0/mode\n");
+		pr_notice("echo -n \"enabled\" > /sys/class/thermal/thermal_zone0/mode\n");
 	}
 
 	return 0;
diff --git a/drivers/platform/x86/amilo-rfkill.c b/drivers/platform/x86/amilo-rfkill.c
index 19170bb..a514bf6 100644
--- a/drivers/platform/x86/amilo-rfkill.c
+++ b/drivers/platform/x86/amilo-rfkill.c
@@ -97,9 +97,12 @@
 
 static int __devinit amilo_rfkill_probe(struct platform_device *device)
 {
+	int rc;
 	const struct dmi_system_id *system_id =
 		dmi_first_match(amilo_rfkill_id_table);
-	int rc;
+
+	if (!system_id)
+		return -ENXIO;
 
 	amilo_rfkill_dev = rfkill_alloc(KBUILD_MODNAME, &device->dev,
 					RFKILL_TYPE_WLAN,
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
new file mode 100644
index 0000000..8a582bd
--- /dev/null
+++ b/drivers/platform/x86/apple-gmux.c
@@ -0,0 +1,244 @@
+/*
+ *  Gmux driver for Apple laptops
+ *
+ *  Copyright (C) Canonical Ltd. <seth.forshee@canonical.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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/backlight.h>
+#include <linux/acpi.h>
+#include <linux/pnp.h>
+#include <linux/apple_bl.h>
+#include <linux/slab.h>
+#include <acpi/video.h>
+#include <asm/io.h>
+
+struct apple_gmux_data {
+	unsigned long iostart;
+	unsigned long iolen;
+
+	struct backlight_device *bdev;
+};
+
+/*
+ * gmux port offsets. Many of these are not yet used, but may be in the
+ * future, and it's useful to have them documented here anyhow.
+ */
+#define GMUX_PORT_VERSION_MAJOR		0x04
+#define GMUX_PORT_VERSION_MINOR		0x05
+#define GMUX_PORT_VERSION_RELEASE	0x06
+#define GMUX_PORT_SWITCH_DISPLAY	0x10
+#define GMUX_PORT_SWITCH_GET_DISPLAY	0x11
+#define GMUX_PORT_INTERRUPT_ENABLE	0x14
+#define GMUX_PORT_INTERRUPT_STATUS	0x16
+#define GMUX_PORT_SWITCH_DDC		0x28
+#define GMUX_PORT_SWITCH_EXTERNAL	0x40
+#define GMUX_PORT_SWITCH_GET_EXTERNAL	0x41
+#define GMUX_PORT_DISCRETE_POWER	0x50
+#define GMUX_PORT_MAX_BRIGHTNESS	0x70
+#define GMUX_PORT_BRIGHTNESS		0x74
+
+#define GMUX_MIN_IO_LEN			(GMUX_PORT_BRIGHTNESS + 4)
+
+#define GMUX_INTERRUPT_ENABLE		0xff
+#define GMUX_INTERRUPT_DISABLE		0x00
+
+#define GMUX_INTERRUPT_STATUS_ACTIVE	0
+#define GMUX_INTERRUPT_STATUS_DISPLAY	(1 << 0)
+#define GMUX_INTERRUPT_STATUS_POWER	(1 << 2)
+#define GMUX_INTERRUPT_STATUS_HOTPLUG	(1 << 3)
+
+#define GMUX_BRIGHTNESS_MASK		0x00ffffff
+#define GMUX_MAX_BRIGHTNESS		GMUX_BRIGHTNESS_MASK
+
+static inline u8 gmux_read8(struct apple_gmux_data *gmux_data, int port)
+{
+	return inb(gmux_data->iostart + port);
+}
+
+static inline void gmux_write8(struct apple_gmux_data *gmux_data, int port,
+			       u8 val)
+{
+	outb(val, gmux_data->iostart + port);
+}
+
+static inline u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
+{
+	return inl(gmux_data->iostart + port);
+}
+
+static int gmux_get_brightness(struct backlight_device *bd)
+{
+	struct apple_gmux_data *gmux_data = bl_get_data(bd);
+	return gmux_read32(gmux_data, GMUX_PORT_BRIGHTNESS) &
+	       GMUX_BRIGHTNESS_MASK;
+}
+
+static int gmux_update_status(struct backlight_device *bd)
+{
+	struct apple_gmux_data *gmux_data = bl_get_data(bd);
+	u32 brightness = bd->props.brightness;
+
+	/*
+	 * Older gmux versions require writing out lower bytes first then
+	 * setting the upper byte to 0 to flush the values. Newer versions
+	 * accept a single u32 write, but the old method also works, so we
+	 * just use the old method for all gmux versions.
+	 */
+	gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS, brightness);
+	gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 1, brightness >> 8);
+	gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 2, brightness >> 16);
+	gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 3, 0);
+
+	return 0;
+}
+
+static const struct backlight_ops gmux_bl_ops = {
+	.get_brightness = gmux_get_brightness,
+	.update_status = gmux_update_status,
+};
+
+static int __devinit gmux_probe(struct pnp_dev *pnp,
+				const struct pnp_device_id *id)
+{
+	struct apple_gmux_data *gmux_data;
+	struct resource *res;
+	struct backlight_properties props;
+	struct backlight_device *bdev;
+	u8 ver_major, ver_minor, ver_release;
+	int ret = -ENXIO;
+
+	gmux_data = kzalloc(sizeof(*gmux_data), GFP_KERNEL);
+	if (!gmux_data)
+		return -ENOMEM;
+	pnp_set_drvdata(pnp, gmux_data);
+
+	res = pnp_get_resource(pnp, IORESOURCE_IO, 0);
+	if (!res) {
+		pr_err("Failed to find gmux I/O resource\n");
+		goto err_free;
+	}
+
+	gmux_data->iostart = res->start;
+	gmux_data->iolen = res->end - res->start;
+
+	if (gmux_data->iolen < GMUX_MIN_IO_LEN) {
+		pr_err("gmux I/O region too small (%lu < %u)\n",
+		       gmux_data->iolen, GMUX_MIN_IO_LEN);
+		goto err_free;
+	}
+
+	if (!request_region(gmux_data->iostart, gmux_data->iolen,
+			    "Apple gmux")) {
+		pr_err("gmux I/O already in use\n");
+		goto err_free;
+	}
+
+	/*
+	 * On some machines the gmux is in ACPI even thought the machine
+	 * doesn't really have a gmux. Check for invalid version information
+	 * to detect this.
+	 */
+	ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
+	ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
+	ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
+	if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
+		pr_info("gmux device not present\n");
+		ret = -ENODEV;
+		goto err_release;
+	}
+
+	pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
+		ver_release);
+
+	memset(&props, 0, sizeof(props));
+	props.type = BACKLIGHT_PLATFORM;
+	props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
+
+	/*
+	 * Currently it's assumed that the maximum brightness is less than
+	 * 2^24 for compatibility with old gmux versions. Cap the max
+	 * brightness at this value, but print a warning if the hardware
+	 * reports something higher so that it can be fixed.
+	 */
+	if (WARN_ON(props.max_brightness > GMUX_MAX_BRIGHTNESS))
+		props.max_brightness = GMUX_MAX_BRIGHTNESS;
+
+	bdev = backlight_device_register("gmux_backlight", &pnp->dev,
+					 gmux_data, &gmux_bl_ops, &props);
+	if (IS_ERR(bdev)) {
+		ret = PTR_ERR(bdev);
+		goto err_release;
+	}
+
+	gmux_data->bdev = bdev;
+	bdev->props.brightness = gmux_get_brightness(bdev);
+	backlight_update_status(bdev);
+
+	/*
+	 * The backlight situation on Macs is complicated. If the gmux is
+	 * present it's the best choice, because it always works for
+	 * backlight control and supports more levels than other options.
+	 * Disable the other backlight choices.
+	 */
+	acpi_video_unregister();
+	apple_bl_unregister();
+
+	return 0;
+
+err_release:
+	release_region(gmux_data->iostart, gmux_data->iolen);
+err_free:
+	kfree(gmux_data);
+	return ret;
+}
+
+static void __devexit gmux_remove(struct pnp_dev *pnp)
+{
+	struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
+
+	backlight_device_unregister(gmux_data->bdev);
+	release_region(gmux_data->iostart, gmux_data->iolen);
+	kfree(gmux_data);
+
+	acpi_video_register();
+	apple_bl_register();
+}
+
+static const struct pnp_device_id gmux_device_ids[] = {
+	{"APP000B", 0},
+	{"", 0}
+};
+
+static struct pnp_driver gmux_pnp_driver = {
+	.name		= "apple-gmux",
+	.probe		= gmux_probe,
+	.remove		= __devexit_p(gmux_remove),
+	.id_table	= gmux_device_ids,
+};
+
+static int __init apple_gmux_init(void)
+{
+	return pnp_register_driver(&gmux_pnp_driver);
+}
+
+static void __exit apple_gmux_exit(void)
+{
+	pnp_unregister_driver(&gmux_pnp_driver);
+}
+
+module_init(apple_gmux_init);
+module_exit(apple_gmux_exit);
+
+MODULE_AUTHOR("Seth Forshee <seth.forshee@canonical.com>");
+MODULE_DESCRIPTION("Apple Gmux Driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pnp, gmux_device_ids);
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index b7944f9..e38f91b 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -81,6 +81,19 @@
 module_param(wapf, uint, 0444);
 MODULE_PARM_DESC(wapf, "WAPF value");
 
+static char *wled_type = "unknown";
+static char *bled_type = "unknown";
+
+module_param(wled_type, charp, 0444);
+MODULE_PARM_DESC(wlan_status, "Set the wled type on boot "
+		 "(unknown, led or rfkill). "
+		 "default is unknown");
+
+module_param(bled_type, charp, 0444);
+MODULE_PARM_DESC(bled_type, "Set the bled type on boot "
+		 "(unknown, led or rfkill). "
+		 "default is unknown");
+
 static int wlan_status = 1;
 static int bluetooth_status = 1;
 static int wimax_status = -1;
@@ -137,6 +150,11 @@
 #define WM_RSTS		0x08    /* internal wimax */
 #define WW_RSTS		0x20    /* internal wwan */
 
+/* WLED and BLED type */
+#define TYPE_UNKNOWN	0
+#define TYPE_LED	1
+#define TYPE_RFKILL	2
+
 /* LED */
 #define METHOD_MLED		"MLED"
 #define METHOD_TLED		"TLED"
@@ -218,8 +236,9 @@
 /*
  * Same thing for rfkill
  */
-struct asus_pega_rfkill {
-	int control_id;		/* type of control. Maps to PEGA_* values */
+struct asus_rfkill {
+	/* type of control. Maps to PEGA_* values or *_RSTS  */
+	int control_id;
 	struct rfkill *rfkill;
 	struct asus_laptop *asus;
 };
@@ -240,6 +259,8 @@
 	struct key_entry *keymap;
 	struct input_polled_dev *pega_accel_poll;
 
+	struct asus_led wled;
+	struct asus_led bled;
 	struct asus_led mled;
 	struct asus_led tled;
 	struct asus_led rled;
@@ -248,6 +269,8 @@
 	struct asus_led kled;
 	struct workqueue_struct *led_workqueue;
 
+	int wled_type;
+	int bled_type;
 	int wireless_status;
 	bool have_rsts;
 	bool is_pega_lucid;
@@ -256,11 +279,11 @@
 	int pega_acc_y;
 	int pega_acc_z;
 
-	struct rfkill *gps_rfkill;
-
-	struct asus_pega_rfkill wlanrfk;
-	struct asus_pega_rfkill btrfk;
-	struct asus_pega_rfkill wwanrfk;
+	struct asus_rfkill wlan;
+	struct asus_rfkill bluetooth;
+	struct asus_rfkill wwan;
+	struct asus_rfkill wimax;
+	struct asus_rfkill gps;
 
 	acpi_handle handle;	/* the handle of the hotk device */
 	u32 ledd_status;	/* status of the LED display */
@@ -274,6 +297,7 @@
 	{KE_KEY, 0x02, { KEY_SCREENLOCK } },
 	{KE_KEY, 0x05, { KEY_WLAN } },
 	{KE_KEY, 0x08, { KEY_F13 } },
+	{KE_KEY, 0x09, { KEY_PROG2 } }, /* Dock */
 	{KE_KEY, 0x17, { KEY_ZOOM } },
 	{KE_KEY, 0x1f, { KEY_BATTERY } },
 	/* End of Lenovo SL Specific keycodes */
@@ -299,6 +323,8 @@
 	{KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
 	{KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
 	{KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */
+	{KE_KEY, 0x6C, { KEY_SLEEP } }, /* Suspend */
+	{KE_KEY, 0x6D, { KEY_SLEEP } }, /* Hibernate */
 	{KE_KEY, 0x7E, { KEY_BLUETOOTH } },
 	{KE_KEY, 0x7D, { KEY_BLUETOOTH } },
 	{KE_KEY, 0x82, { KEY_CAMERA } },
@@ -601,6 +627,10 @@
 
 static void asus_led_exit(struct asus_laptop *asus)
 {
+	if (!IS_ERR_OR_NULL(asus->wled.led.dev))
+		led_classdev_unregister(&asus->wled.led);
+	if (!IS_ERR_OR_NULL(asus->bled.led.dev))
+		led_classdev_unregister(&asus->bled.led);
 	if (!IS_ERR_OR_NULL(asus->mled.led.dev))
 		led_classdev_unregister(&asus->mled.led);
 	if (!IS_ERR_OR_NULL(asus->tled.led.dev))
@@ -642,7 +672,7 @@
 
 static int asus_led_init(struct asus_laptop *asus)
 {
-	int r;
+	int r = 0;
 
 	/*
 	 * The Pegatron Lucid has no physical leds, but all methods are
@@ -661,6 +691,16 @@
 	if (!asus->led_workqueue)
 		return -ENOMEM;
 
+	if (asus->wled_type == TYPE_LED)
+		r = asus_led_register(asus, &asus->wled, "asus::wlan",
+				      METHOD_WLAN);
+	if (r)
+		goto error;
+	if (asus->bled_type == TYPE_LED)
+		r = asus_led_register(asus, &asus->bled, "asus::bluetooth",
+				      METHOD_BLUETOOTH);
+	if (r)
+		goto error;
 	r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED);
 	if (r)
 		goto error;
@@ -963,7 +1003,7 @@
 	return sysfs_acpi_set(asus, buf, count, METHOD_WLAN);
 }
 
-/*
+/*e
  * Bluetooth
  */
 static int asus_bluetooth_set(struct asus_laptop *asus, int status)
@@ -1228,7 +1268,7 @@
 	ret = asus_gps_switch(asus, !!value);
 	if (ret)
 		return ret;
-	rfkill_set_sw_state(asus->gps_rfkill, !value);
+	rfkill_set_sw_state(asus->gps.rfkill, !value);
 	return rv;
 }
 
@@ -1246,46 +1286,127 @@
 	.set_block = asus_gps_rfkill_set,
 };
 
+static int asus_rfkill_set(void *data, bool blocked)
+{
+	struct asus_rfkill *rfk = data;
+	struct asus_laptop *asus = rfk->asus;
+
+	if (rfk->control_id == WL_RSTS)
+		return asus_wlan_set(asus, !blocked);
+	else if (rfk->control_id == BT_RSTS)
+		return asus_bluetooth_set(asus, !blocked);
+	else if (rfk->control_id == WM_RSTS)
+		return asus_wimax_set(asus, !blocked);
+	else if (rfk->control_id == WW_RSTS)
+		return asus_wwan_set(asus, !blocked);
+
+	return -EINVAL;
+}
+
+static const struct rfkill_ops asus_rfkill_ops = {
+	.set_block = asus_rfkill_set,
+};
+
+static void asus_rfkill_terminate(struct asus_rfkill *rfk)
+{
+	if (!rfk->rfkill)
+		return ;
+
+	rfkill_unregister(rfk->rfkill);
+	rfkill_destroy(rfk->rfkill);
+	rfk->rfkill = NULL;
+}
+
 static void asus_rfkill_exit(struct asus_laptop *asus)
 {
-	if (asus->gps_rfkill) {
-		rfkill_unregister(asus->gps_rfkill);
-		rfkill_destroy(asus->gps_rfkill);
-		asus->gps_rfkill = NULL;
+	asus_rfkill_terminate(&asus->wwan);
+	asus_rfkill_terminate(&asus->bluetooth);
+	asus_rfkill_terminate(&asus->wlan);
+	asus_rfkill_terminate(&asus->gps);
+}
+
+static int asus_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
+			     const char *name, int control_id, int type,
+			     const struct rfkill_ops *ops)
+{
+	int result;
+
+	rfk->control_id = control_id;
+	rfk->asus = asus;
+	rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
+				   type, ops, rfk);
+	if (!rfk->rfkill)
+		return -EINVAL;
+
+	result = rfkill_register(rfk->rfkill);
+	if (result) {
+		rfkill_destroy(rfk->rfkill);
+		rfk->rfkill = NULL;
 	}
+
+	return result;
 }
 
 static int asus_rfkill_init(struct asus_laptop *asus)
 {
-	int result;
+	int result = 0;
 
-	if (acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) ||
-	    acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) ||
-	    acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL))
-		return 0;
+	if (asus->is_pega_lucid)
+		return -ENODEV;
 
-	asus->gps_rfkill = rfkill_alloc("asus-gps", &asus->platform_device->dev,
-					RFKILL_TYPE_GPS,
-					&asus_gps_rfkill_ops, asus);
-	if (!asus->gps_rfkill)
-		return -EINVAL;
+	if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) &&
+	    !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) &&
+	    !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL))
+		result = asus_rfkill_setup(asus, &asus->gps, "asus-gps",
+					   -1, RFKILL_TYPE_GPS,
+					   &asus_gps_rfkill_ops);
+	if (result)
+		goto exit;
 
-	result = rfkill_register(asus->gps_rfkill);
-	if (result) {
-		rfkill_destroy(asus->gps_rfkill);
-		asus->gps_rfkill = NULL;
-	}
+
+	if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL) &&
+	    asus->wled_type == TYPE_RFKILL)
+		result = asus_rfkill_setup(asus, &asus->wlan, "asus-wlan",
+					   WL_RSTS, RFKILL_TYPE_WLAN,
+					   &asus_rfkill_ops);
+	if (result)
+		goto exit;
+
+	if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL) &&
+	    asus->bled_type == TYPE_RFKILL)
+		result = asus_rfkill_setup(asus, &asus->bluetooth,
+					   "asus-bluetooth", BT_RSTS,
+					   RFKILL_TYPE_BLUETOOTH,
+					   &asus_rfkill_ops);
+	if (result)
+		goto exit;
+
+	if (!acpi_check_handle(asus->handle, METHOD_WWAN, NULL))
+		result = asus_rfkill_setup(asus, &asus->wwan, "asus-wwan",
+					   WW_RSTS, RFKILL_TYPE_WWAN,
+					   &asus_rfkill_ops);
+	if (result)
+		goto exit;
+
+	if (!acpi_check_handle(asus->handle, METHOD_WIMAX, NULL))
+		result = asus_rfkill_setup(asus, &asus->wimax, "asus-wimax",
+					   WM_RSTS, RFKILL_TYPE_WIMAX,
+					   &asus_rfkill_ops);
+	if (result)
+		goto exit;
+
+exit:
+	if (result)
+		asus_rfkill_exit(asus);
 
 	return result;
 }
 
 static int pega_rfkill_set(void *data, bool blocked)
 {
-	struct asus_pega_rfkill *pega_rfk = data;
+	struct asus_rfkill *rfk = data;
 
-	int ret = asus_pega_lucid_set(pega_rfk->asus, pega_rfk->control_id, !blocked);
-	pr_warn("Setting rfkill %d, to %d; returned %d\n", pega_rfk->control_id, !blocked, ret);
-
+	int ret = asus_pega_lucid_set(rfk->asus, rfk->control_id, !blocked);
 	return ret;
 }
 
@@ -1293,43 +1414,11 @@
 	.set_block = pega_rfkill_set,
 };
 
-static void pega_rfkill_terminate(struct asus_pega_rfkill *pega_rfk)
+static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
+			     const char *name, int controlid, int rfkill_type)
 {
-	pr_warn("Terminating %d\n", pega_rfk->control_id);
-	if (pega_rfk->rfkill) {
-		rfkill_unregister(pega_rfk->rfkill);
-		rfkill_destroy(pega_rfk->rfkill);
-		pega_rfk->rfkill = NULL;
-	}
-}
-
-static void pega_rfkill_exit(struct asus_laptop *asus)
-{
-	pega_rfkill_terminate(&asus->wwanrfk);
-	pega_rfkill_terminate(&asus->btrfk);
-	pega_rfkill_terminate(&asus->wlanrfk);
-}
-
-static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_pega_rfkill *pega_rfk,
-		const char *name, int controlid, int rfkill_type)
-{
-	int result;
-
-	pr_warn("Setting up rfk %s, control %d, type %d\n", name, controlid, rfkill_type);
-	pega_rfk->control_id = controlid;
-	pega_rfk->asus = asus;
-	pega_rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
-					rfkill_type, &pega_rfkill_ops, pega_rfk);
-	if (!pega_rfk->rfkill)
-		return -EINVAL;
-
-	result = rfkill_register(pega_rfk->rfkill);
-	if (result) {
-		rfkill_destroy(pega_rfk->rfkill);
-		pega_rfk->rfkill = NULL;
-	}
-
-	return result;
+	return asus_rfkill_setup(asus, rfk, name, controlid, rfkill_type,
+				 &pega_rfkill_ops);
 }
 
 static int pega_rfkill_init(struct asus_laptop *asus)
@@ -1339,22 +1428,22 @@
 	if(!asus->is_pega_lucid)
 		return -ENODEV;
 
-	ret = pega_rfkill_setup(asus, &asus->wlanrfk, "pega-wlan", PEGA_WLAN, RFKILL_TYPE_WLAN);
+	ret = pega_rfkill_setup(asus, &asus->wlan, "pega-wlan",
+				PEGA_WLAN, RFKILL_TYPE_WLAN);
 	if(ret)
-		return ret;
-	ret = pega_rfkill_setup(asus, &asus->btrfk, "pega-bt", PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
-	if(ret)
-		goto err_btrfk;
-	ret = pega_rfkill_setup(asus, &asus->wwanrfk, "pega-wwan", PEGA_WWAN, RFKILL_TYPE_WWAN);
-	if(ret)
-		goto err_wwanrfk;
+		goto exit;
 
-	pr_warn("Pega rfkill init succeeded\n");
-	return 0;
-err_wwanrfk:
-	pega_rfkill_terminate(&asus->btrfk);
-err_btrfk:
-	pega_rfkill_terminate(&asus->wlanrfk);
+	ret = pega_rfkill_setup(asus, &asus->bluetooth, "pega-bt",
+				PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
+	if(ret)
+		goto exit;
+
+	ret = pega_rfkill_setup(asus, &asus->wwan, "pega-wwan",
+				PEGA_WWAN, RFKILL_TYPE_WWAN);
+
+exit:
+	if (ret)
+		asus_rfkill_exit(asus);
 
 	return ret;
 }
@@ -1364,8 +1453,10 @@
  */
 static void asus_input_notify(struct asus_laptop *asus, int event)
 {
-	if (asus->inputdev)
-		sparse_keymap_report_event(asus->inputdev, event, 1, true);
+	if (!asus->inputdev)
+		return ;
+	if (!sparse_keymap_report_event(asus->inputdev, event, 1, true))
+		pr_info("Unknown key %x pressed\n", event);
 }
 
 static int asus_input_init(struct asus_laptop *asus)
@@ -1375,7 +1466,7 @@
 
 	input = input_allocate_device();
 	if (!input) {
-		pr_info("Unable to allocate input device\n");
+		pr_warn("Unable to allocate input device\n");
 		return -ENOMEM;
 	}
 	input->name = "Asus Laptop extra buttons";
@@ -1390,7 +1481,7 @@
 	}
 	error = input_register_device(input);
 	if (error) {
-		pr_info("Unable to register input device\n");
+		pr_warn("Unable to register input device\n");
 		goto err_free_keymap;
 	}
 
@@ -1688,7 +1779,16 @@
 	if (result)
 		return result;
 
-	/* WLED and BLED are on by default */
+	if (!strcmp(bled_type, "led"))
+		asus->bled_type = TYPE_LED;
+	else if (!strcmp(bled_type, "rfkill"))
+		asus->bled_type = TYPE_RFKILL;
+
+	if (!strcmp(wled_type, "led"))
+		asus->wled_type = TYPE_LED;
+	else if (!strcmp(wled_type, "rfkill"))
+		asus->wled_type = TYPE_RFKILL;
+
 	if (bluetooth_status >= 0)
 		asus_bluetooth_set(asus, !!bluetooth_status);
 
@@ -1786,7 +1886,7 @@
 		goto fail_led;
 
 	result = asus_rfkill_init(asus);
-	if (result)
+	if (result && result != -ENODEV)
 		goto fail_rfkill;
 
 	result = pega_accel_init(asus);
@@ -1828,7 +1928,6 @@
 	asus_led_exit(asus);
 	asus_input_exit(asus);
 	pega_accel_exit(asus);
-	pega_rfkill_exit(asus);
 	asus_platform_exit(asus);
 
 	kfree(asus->name);
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index b0859d4..99a30b5 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -25,6 +25,7 @@
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
+#include <linux/fb.h>
 
 #include "asus-wmi.h"
 
@@ -51,9 +52,14 @@
 module_param(wapf, uint, 0444);
 MODULE_PARM_DESC(wapf, "WAPF value");
 
+static struct quirk_entry quirk_asus_unknown = {
+};
+
 static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
 {
-	driver->wapf = wapf;
+	driver->quirks = &quirk_asus_unknown;
+	driver->quirks->wapf = wapf;
+	driver->panel_power = FB_BLANK_UNBLANK;
 }
 
 static const struct key_entry asus_nb_wmi_keymap[] = {
@@ -70,6 +76,8 @@
 	{ KE_KEY, 0x50, { KEY_EMAIL } },
 	{ KE_KEY, 0x51, { KEY_WWW } },
 	{ KE_KEY, 0x55, { KEY_CALC } },
+	{ KE_IGNORE, 0x57, },  /* Battery mode */
+	{ KE_IGNORE, 0x58, },  /* AC mode */
 	{ KE_KEY, 0x5C, { KEY_F15 } },  /* Power Gear key */
 	{ KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */
 	{ KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */
@@ -99,7 +107,7 @@
 	.keymap = asus_nb_wmi_keymap,
 	.input_name = "Asus WMI hotkeys",
 	.input_phys = ASUS_NB_WMI_FILE "/input0",
-	.quirks = asus_nb_wmi_quirks,
+	.detect_quirks = asus_nb_wmi_quirks,
 };
 
 
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 72d731c..77aadde 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -411,7 +411,7 @@
 
 	if (retval >= 0) {
 		if (level)
-			*level = retval & 0x80 ? retval & 0x7F : 0;
+			*level = retval & 0x7F;
 		if (env)
 			*env = (retval >> 8) & 0x7F;
 		retval = 0;
@@ -571,7 +571,7 @@
 		} else {
 			dev = pci_get_slot(bus, 0);
 			if (dev) {
-				pci_remove_bus_device(dev);
+				pci_stop_and_remove_bus_device(dev);
 				pci_dev_put(dev);
 			}
 		}
@@ -784,7 +784,8 @@
 	arfkill->dev_id = dev_id;
 	arfkill->asus = asus;
 
-	if (dev_id == ASUS_WMI_DEVID_WLAN && asus->driver->hotplug_wireless)
+	if (dev_id == ASUS_WMI_DEVID_WLAN &&
+	    asus->driver->quirks->hotplug_wireless)
 		*rfkill = rfkill_alloc(name, &asus->platform_device->dev, type,
 				       &asus_rfkill_wlan_ops, arfkill);
 	else
@@ -895,7 +896,7 @@
 	if (result && result != -ENODEV)
 		goto exit;
 
-	if (!asus->driver->hotplug_wireless)
+	if (!asus->driver->quirks->hotplug_wireless)
 		goto exit;
 
 	result = asus_setup_pci_hotplug(asus);
@@ -1075,7 +1076,12 @@
  */
 static int read_backlight_power(struct asus_wmi *asus)
 {
-	int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BACKLIGHT);
+	int ret;
+	if (asus->driver->quirks->store_backlight_power)
+		ret = !asus->driver->panel_power;
+	else
+		ret = asus_wmi_get_devstate_simple(asus,
+						   ASUS_WMI_DEVID_BACKLIGHT);
 
 	if (ret < 0)
 		return ret;
@@ -1116,26 +1122,51 @@
 	return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
 }
 
+static u32 get_scalar_command(struct backlight_device *bd)
+{
+	struct asus_wmi *asus = bl_get_data(bd);
+	u32 ctrl_param = 0;
+
+	if ((asus->driver->brightness < bd->props.brightness) ||
+	    bd->props.brightness == bd->props.max_brightness)
+		ctrl_param = 0x00008001;
+	else if ((asus->driver->brightness > bd->props.brightness) ||
+		 bd->props.brightness == 0)
+		ctrl_param = 0x00008000;
+
+	asus->driver->brightness = bd->props.brightness;
+
+	return ctrl_param;
+}
+
 static int update_bl_status(struct backlight_device *bd)
 {
 	struct asus_wmi *asus = bl_get_data(bd);
 	u32 ctrl_param;
-	int power, err;
-
-	ctrl_param = bd->props.brightness;
-
-	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS,
-				    ctrl_param, NULL);
-
-	if (err < 0)
-		return err;
+	int power, err = 0;
 
 	power = read_backlight_power(asus);
 	if (power != -ENODEV && bd->props.power != power) {
 		ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK);
 		err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT,
 					    ctrl_param, NULL);
+		if (asus->driver->quirks->store_backlight_power)
+			asus->driver->panel_power = bd->props.power;
+
+		/* When using scalar brightness, updating the brightness
+		 * will mess with the backlight power */
+		if (asus->driver->quirks->scalar_panel_brightness)
+			return err;
 	}
+
+	if (asus->driver->quirks->scalar_panel_brightness)
+		ctrl_param = get_scalar_command(bd);
+	else
+		ctrl_param = bd->props.brightness;
+
+	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS,
+				    ctrl_param, NULL);
+
 	return err;
 }
 
@@ -1196,10 +1227,15 @@
 
 	asus->backlight_device = bd;
 
+	if (asus->driver->quirks->store_backlight_power)
+		asus->driver->panel_power = power;
+
 	bd->props.brightness = read_brightness(bd);
 	bd->props.power = power;
 	backlight_update_status(bd);
 
+	asus->driver->brightness = bd->props.brightness;
+
 	return 0;
 }
 
@@ -1441,9 +1477,9 @@
 
 	/* CWAP allow to define the behavior of the Fn+F2 key,
 	 * this method doesn't seems to be present on Eee PCs */
-	if (asus->driver->wapf >= 0)
+	if (asus->driver->quirks->wapf >= 0)
 		asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP,
-				      asus->driver->wapf, NULL);
+				      asus->driver->quirks->wapf, NULL);
 
 	return asus_wmi_sysfs_init(asus->platform_device);
 }
@@ -1622,8 +1658,8 @@
 	wdrv->platform_device = pdev;
 	platform_set_drvdata(asus->platform_device, asus);
 
-	if (wdrv->quirks)
-		wdrv->quirks(asus->driver);
+	if (wdrv->detect_quirks)
+		wdrv->detect_quirks(asus->driver);
 
 	err = asus_wmi_platform_init(asus);
 	if (err)
diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
index 8147c10..d43b667 100644
--- a/drivers/platform/x86/asus-wmi.h
+++ b/drivers/platform/x86/asus-wmi.h
@@ -35,9 +35,16 @@
 struct key_entry;
 struct asus_wmi;
 
+struct quirk_entry {
+	bool hotplug_wireless;
+	bool scalar_panel_brightness;
+	bool store_backlight_power;
+	int wapf;
+};
+
 struct asus_wmi_driver {
-	bool			hotplug_wireless;
-	int			wapf;
+	int			brightness;
+	int			panel_power;
 
 	const char		*name;
 	struct module		*owner;
@@ -47,13 +54,14 @@
 	const struct key_entry	*keymap;
 	const char		*input_name;
 	const char		*input_phys;
+	struct quirk_entry	*quirks;
 	/* Returns new code, value, and autorelease values in arguments.
 	 * Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */
 	void (*key_filter) (struct asus_wmi_driver *driver, int *code,
 			    unsigned int *value, bool *autorelease);
 
 	int (*probe) (struct platform_device *device);
-	void (*quirks) (struct asus_wmi_driver *driver);
+	void (*detect_quirks) (struct asus_wmi_driver *driver);
 
 	struct platform_driver	platform_driver;
 	struct platform_device *platform_device;
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c
deleted file mode 100644
index 6f966d6..0000000
--- a/drivers/platform/x86/asus_acpi.c
+++ /dev/null
@@ -1,1513 +0,0 @@
-/*
- *  asus_acpi.c - Asus Laptop ACPI Extras
- *
- *
- *  Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
- *
- *  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
- *
- *
- *  The development page for this driver is located at
- *  http://sourceforge.net/projects/acpi4asus/
- *
- *  Credits:
- *  Pontus Fuchs   - Helper functions, cleanup
- *  Johann Wiesner - Small compile fixes
- *  John Belmonte  - ACPI code for Toshiba laptop was a good starting point.
- *  �ic Burghard  - LED display support for W1N
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/backlight.h>
-#include <acpi/acpi_drivers.h>
-#include <acpi/acpi_bus.h>
-#include <asm/uaccess.h>
-
-#define ASUS_ACPI_VERSION "0.30"
-
-#define PROC_ASUS       "asus"	/* The directory */
-#define PROC_MLED       "mled"
-#define PROC_WLED       "wled"
-#define PROC_TLED       "tled"
-#define PROC_BT         "bluetooth"
-#define PROC_LEDD       "ledd"
-#define PROC_INFO       "info"
-#define PROC_LCD        "lcd"
-#define PROC_BRN        "brn"
-#define PROC_DISP       "disp"
-
-#define ACPI_HOTK_NAME          "Asus Laptop ACPI Extras Driver"
-#define ACPI_HOTK_CLASS         "hotkey"
-#define ACPI_HOTK_DEVICE_NAME   "Hotkey"
-
-/*
- * Some events we use, same for all Asus
- */
-#define BR_UP       0x10
-#define BR_DOWN     0x20
-
-/*
- * Flags for hotk status
- */
-#define MLED_ON     0x01	/* Mail LED */
-#define WLED_ON     0x02	/* Wireless LED */
-#define TLED_ON     0x04	/* Touchpad LED */
-#define BT_ON       0x08	/* Internal Bluetooth */
-
-MODULE_AUTHOR("Julien Lerouge, Karol Kozimor");
-MODULE_DESCRIPTION(ACPI_HOTK_NAME);
-MODULE_LICENSE("GPL");
-
-static uid_t asus_uid;
-static gid_t asus_gid;
-module_param(asus_uid, uint, 0);
-MODULE_PARM_DESC(asus_uid, "UID for entries in /proc/acpi/asus");
-module_param(asus_gid, uint, 0);
-MODULE_PARM_DESC(asus_gid, "GID for entries in /proc/acpi/asus");
-
-/* For each model, all features implemented,
- * those marked with R are relative to HOTK, A for absolute */
-struct model_data {
-	char *name;		/* name of the laptop________________A */
-	char *mt_mled;		/* method to handle mled_____________R */
-	char *mled_status;	/* node to handle mled reading_______A */
-	char *mt_wled;		/* method to handle wled_____________R */
-	char *wled_status;	/* node to handle wled reading_______A */
-	char *mt_tled;		/* method to handle tled_____________R */
-	char *tled_status;	/* node to handle tled reading_______A */
-	char *mt_ledd;		/* method to handle LED display______R */
-	char *mt_bt_switch;	/* method to switch Bluetooth on/off_R */
-	char *bt_status;	/* no model currently supports this__? */
-	char *mt_lcd_switch;	/* method to turn LCD on/off_________A */
-	char *lcd_status;	/* node to read LCD panel state______A */
-	char *brightness_up;	/* method to set brightness up_______A */
-	char *brightness_down;	/* method to set brightness down ____A */
-	char *brightness_set;	/* method to set absolute brightness_R */
-	char *brightness_get;	/* method to get absolute brightness_R */
-	char *brightness_status;/* node to get brightness____________A */
-	char *display_set;	/* method to set video output________R */
-	char *display_get;	/* method to get video output________R */
-};
-
-/*
- * This is the main structure, we can use it to store anything interesting
- * about the hotk device
- */
-struct asus_hotk {
-	struct acpi_device *device;	/* the device we are in */
-	acpi_handle handle;		/* the handle of the hotk device */
-	char status;			/* status of the hotk, for LEDs */
-	u32 ledd_status;		/* status of the LED display */
-	struct model_data *methods;	/* methods available on the laptop */
-	u8 brightness;			/* brightness level */
-	enum {
-		A1x = 0,	/* A1340D, A1300F */
-		A2x,		/* A2500H */
-		A4G,		/* A4700G */
-		D1x,		/* D1 */
-		L2D,		/* L2000D */
-		L3C,		/* L3800C */
-		L3D,		/* L3400D */
-		L3H,		/* L3H, L2000E, L5D */
-		L4R,		/* L4500R */
-		L5x,		/* L5800C */
-		L8L,		/* L8400L */
-		M1A,		/* M1300A */
-		M2E,		/* M2400E, L4400L */
-		M6N,		/* M6800N, W3400N */
-		M6R,		/* M6700R, A3000G */
-		P30,		/* Samsung P30 */
-		S1x,		/* S1300A, but also L1400B and M2400A (L84F) */
-		S2x,		/* S200 (J1 reported), Victor MP-XP7210 */
-		W1N,		/* W1000N */
-		W5A,		/* W5A */
-		W3V,            /* W3030V */
-		xxN,		/* M2400N, M3700N, M5200N, M6800N,
-							 S1300N, S5200N*/
-		A4S,            /* Z81sp */
-		F3Sa,		/* (Centrino) */
-		R1F,
-		END_MODEL
-	} model;		/* Models currently supported */
-	u16 event_count[128];	/* Count for each event TODO make this better */
-};
-
-/* Here we go */
-#define A1x_PREFIX "\\_SB.PCI0.ISA.EC0."
-#define L3C_PREFIX "\\_SB.PCI0.PX40.ECD0."
-#define M1A_PREFIX "\\_SB.PCI0.PX40.EC0."
-#define P30_PREFIX "\\_SB.PCI0.LPCB.EC0."
-#define S1x_PREFIX "\\_SB.PCI0.PX40."
-#define S2x_PREFIX A1x_PREFIX
-#define xxN_PREFIX "\\_SB.PCI0.SBRG.EC0."
-
-static struct model_data model_conf[END_MODEL] = {
-	/*
-	 * TODO I have seen a SWBX and AIBX method on some models, like L1400B,
-	 * it seems to be a kind of switch, but what for ?
-	 */
-
-	{
-	 .name = "A1x",
-	 .mt_mled = "MLED",
-	 .mled_status = "\\MAIL",
-	 .mt_lcd_switch = A1x_PREFIX "_Q10",
-	 .lcd_status = "\\BKLI",
-	 .brightness_up = A1x_PREFIX "_Q0E",
-	 .brightness_down = A1x_PREFIX "_Q0F"},
-
-	{
-	 .name = "A2x",
-	 .mt_mled = "MLED",
-	 .mt_wled = "WLED",
-	 .wled_status = "\\SG66",
-	 .mt_lcd_switch = "\\Q10",
-	 .lcd_status = "\\BAOF",
-	 .brightness_set = "SPLV",
-	 .brightness_get = "GPLV",
-	 .display_set = "SDSP",
-	 .display_get = "\\INFB"},
-
-	{
-	 .name = "A4G",
-	 .mt_mled = "MLED",
-/* WLED present, but not controlled by ACPI */
-	 .mt_lcd_switch = xxN_PREFIX "_Q10",
-	 .brightness_set = "SPLV",
-	 .brightness_get = "GPLV",
-	 .display_set = "SDSP",
-	 .display_get = "\\ADVG"},
-
-	{
-	 .name = "D1x",
-	 .mt_mled = "MLED",
-	 .mt_lcd_switch = "\\Q0D",
-	 .lcd_status = "\\GP11",
-	 .brightness_up = "\\Q0C",
-	 .brightness_down = "\\Q0B",
-	 .brightness_status = "\\BLVL",
-	 .display_set = "SDSP",
-	 .display_get = "\\INFB"},
-
-	{
-	 .name = "L2D",
-	 .mt_mled = "MLED",
-	 .mled_status = "\\SGP6",
-	 .mt_wled = "WLED",
-	 .wled_status = "\\RCP3",
-	 .mt_lcd_switch = "\\Q10",
-	 .lcd_status = "\\SGP0",
-	 .brightness_up = "\\Q0E",
-	 .brightness_down = "\\Q0F",
-	 .display_set = "SDSP",
-	 .display_get = "\\INFB"},
-
-	{
-	 .name = "L3C",
-	 .mt_mled = "MLED",
-	 .mt_wled = "WLED",
-	 .mt_lcd_switch = L3C_PREFIX "_Q10",
-	 .lcd_status = "\\GL32",
-	 .brightness_set = "SPLV",
-	 .brightness_get = "GPLV",
-	 .display_set = "SDSP",
-	 .display_get = "\\_SB.PCI0.PCI1.VGAC.NMAP"},
-
-	{
-	 .name = "L3D",
-	 .mt_mled = "MLED",
-	 .mled_status = "\\MALD",
-	 .mt_wled = "WLED",
-	 .mt_lcd_switch = "\\Q10",
-	 .lcd_status = "\\BKLG",
-	 .brightness_set = "SPLV",
-	 .brightness_get = "GPLV",
-	 .display_set = "SDSP",
-	 .display_get = "\\INFB"},
-
-	{
-	 .name = "L3H",
-	 .mt_mled = "MLED",
-	 .mt_wled = "WLED",
-	 .mt_lcd_switch = "EHK",
-	 .lcd_status = "\\_SB.PCI0.PM.PBC",
-	 .brightness_set = "SPLV",
-	 .brightness_get = "GPLV",
-	 .display_set = "SDSP",
-	 .display_get = "\\INFB"},
-
-	{
-	 .name = "L4R",
-	 .mt_mled = "MLED",
-	 .mt_wled = "WLED",
-	 .wled_status = "\\_SB.PCI0.SBRG.SG13",
-	 .mt_lcd_switch = xxN_PREFIX "_Q10",
-	 .lcd_status = "\\_SB.PCI0.SBSM.SEO4",
-	 .brightness_set = "SPLV",
-	 .brightness_get = "GPLV",
-	 .display_set = "SDSP",
-	 .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"},
-
-	{
-	 .name = "L5x",
-	 .mt_mled = "MLED",
-/* WLED present, but not controlled by ACPI */
-	 .mt_tled = "TLED",
-	 .mt_lcd_switch = "\\Q0D",
-	 .lcd_status = "\\BAOF",
-	 .brightness_set = "SPLV",
-	 .brightness_get = "GPLV",
-	 .display_set = "SDSP",
-	 .display_get = "\\INFB"},
-
-	{
-	 .name = "L8L"
-/* No features, but at least support the hotkeys */
-	 },
-
-	{
-	 .name = "M1A",
-	 .mt_mled = "MLED",
-	 .mt_lcd_switch = M1A_PREFIX "Q10",
-	 .lcd_status = "\\PNOF",
-	 .brightness_up = M1A_PREFIX "Q0E",
-	 .brightness_down = M1A_PREFIX "Q0F",
-	 .brightness_status = "\\BRIT",
-	 .display_set = "SDSP",
-	 .display_get = "\\INFB"},
-
-	{
-	 .name = "M2E",
-	 .mt_mled = "MLED",
-	 .mt_wled = "WLED",
-	 .mt_lcd_switch = "\\Q10",
-	 .lcd_status = "\\GP06",
-	 .brightness_set = "SPLV",
-	 .brightness_get = "GPLV",
-	 .display_set = "SDSP",
-	 .display_get = "\\INFB"},
-
-	{
-	 .name = "M6N",
-	 .mt_mled = "MLED",
-	 .mt_wled = "WLED",
-	 .wled_status = "\\_SB.PCI0.SBRG.SG13",
-	 .mt_lcd_switch = xxN_PREFIX "_Q10",
-	 .lcd_status = "\\_SB.BKLT",
-	 .brightness_set = "SPLV",
-	 .brightness_get = "GPLV",
-	 .display_set = "SDSP",
-	 .display_get = "\\SSTE"},
-
-	{
-	 .name = "M6R",
-	 .mt_mled = "MLED",
-	 .mt_wled = "WLED",
-	 .mt_lcd_switch = xxN_PREFIX "_Q10",
-	 .lcd_status = "\\_SB.PCI0.SBSM.SEO4",
-	 .brightness_set = "SPLV",
-	 .brightness_get = "GPLV",
-	 .display_set = "SDSP",
-	 .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"},
-
-	{
-	 .name = "P30",
-	 .mt_wled = "WLED",
-	 .mt_lcd_switch = P30_PREFIX "_Q0E",
-	 .lcd_status = "\\BKLT",
-	 .brightness_up = P30_PREFIX "_Q68",
-	 .brightness_down = P30_PREFIX "_Q69",
-	 .brightness_get = "GPLV",
-	 .display_set = "SDSP",
-	 .display_get = "\\DNXT"},
-
-	{
-	 .name = "S1x",
-	 .mt_mled = "MLED",
-	 .mled_status = "\\EMLE",
-	 .mt_wled = "WLED",
-	 .mt_lcd_switch = S1x_PREFIX "Q10",
-	 .lcd_status = "\\PNOF",
-	 .brightness_set = "SPLV",
-	 .brightness_get = "GPLV"},
-
-	{
-	 .name = "S2x",
-	 .mt_mled = "MLED",
-	 .mled_status = "\\MAIL",
-	 .mt_lcd_switch = S2x_PREFIX "_Q10",
-	 .lcd_status = "\\BKLI",
-	 .brightness_up = S2x_PREFIX "_Q0B",
-	 .brightness_down = S2x_PREFIX "_Q0A"},
-
-	{
-	 .name = "W1N",
-	 .mt_mled = "MLED",
-	 .mt_wled = "WLED",
-	 .mt_ledd = "SLCM",
-	 .mt_lcd_switch = xxN_PREFIX "_Q10",
-	 .lcd_status = "\\BKLT",
-	 .brightness_set = "SPLV",
-	 .brightness_get = "GPLV",
-	 .display_set = "SDSP",
-	 .display_get = "\\ADVG"},
-
-	{
-	 .name = "W5A",
-	 .mt_bt_switch = "BLED",
-	 .mt_wled = "WLED",
-	 .mt_lcd_switch = xxN_PREFIX "_Q10",
-	 .brightness_set = "SPLV",
-	 .brightness_get = "GPLV",
-	 .display_set = "SDSP",
-	 .display_get = "\\ADVG"},
-
-	{
-	 .name = "W3V",
-	 .mt_mled = "MLED",
-	 .mt_wled = "WLED",
-	 .mt_lcd_switch = xxN_PREFIX "_Q10",
-	 .lcd_status = "\\BKLT",
-	 .brightness_set = "SPLV",
-	 .brightness_get = "GPLV",
-	 .display_set = "SDSP",
-	 .display_get = "\\INFB"},
-
-       {
-	 .name = "xxN",
-	 .mt_mled = "MLED",
-/* WLED present, but not controlled by ACPI */
-	 .mt_lcd_switch = xxN_PREFIX "_Q10",
-	 .lcd_status = "\\BKLT",
-	 .brightness_set = "SPLV",
-	 .brightness_get = "GPLV",
-	 .display_set = "SDSP",
-	.display_get = "\\ADVG"},
-
-	{
-		.name              = "A4S",
-		.brightness_set    = "SPLV",
-		.brightness_get    = "GPLV",
-		.mt_bt_switch      = "BLED",
-		.mt_wled           = "WLED"
-	},
-
-	{
-		.name		= "F3Sa",
-		.mt_bt_switch	= "BLED",
-		.mt_wled	= "WLED",
-		.mt_mled	= "MLED",
-		.brightness_get	= "GPLV",
-		.brightness_set	= "SPLV",
-		.mt_lcd_switch	= "\\_SB.PCI0.SBRG.EC0._Q10",
-		.lcd_status	= "\\_SB.PCI0.SBRG.EC0.RPIN",
-		.display_get	= "\\ADVG",
-		.display_set	= "SDSP",
-	},
-	{
-		.name = "R1F",
-		.mt_bt_switch = "BLED",
-		.mt_mled = "MLED",
-		.mt_wled = "WLED",
-		.mt_lcd_switch = "\\Q10",
-		.lcd_status = "\\GP06",
-		.brightness_set = "SPLV",
-		.brightness_get = "GPLV",
-		.display_set = "SDSP",
-		.display_get = "\\INFB"
-	}
-};
-
-/* procdir we use */
-static struct proc_dir_entry *asus_proc_dir;
-
-static struct backlight_device *asus_backlight_device;
-
-/*
- * This header is made available to allow proper configuration given model,
- * revision number , ... this info cannot go in struct asus_hotk because it is
- * available before the hotk
- */
-static struct acpi_table_header *asus_info;
-
-/* The actual device the driver binds to */
-static struct asus_hotk *hotk;
-
-/*
- * The hotkey driver and autoloading declaration
- */
-static int asus_hotk_add(struct acpi_device *device);
-static int asus_hotk_remove(struct acpi_device *device, int type);
-static void asus_hotk_notify(struct acpi_device *device, u32 event);
-
-static const struct acpi_device_id asus_device_ids[] = {
-	{"ATK0100", 0},
-	{"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, asus_device_ids);
-
-static struct acpi_driver asus_hotk_driver = {
-	.name = "asus_acpi",
-	.class = ACPI_HOTK_CLASS,
-	.owner = THIS_MODULE,
-	.ids = asus_device_ids,
-	.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
-	.ops = {
-		.add = asus_hotk_add,
-		.remove = asus_hotk_remove,
-		.notify = asus_hotk_notify,
-		},
-};
-
-/*
- * This function evaluates an ACPI method, given an int as parameter, the
- * method is searched within the scope of the handle, can be NULL. The output
- * of the method is written is output, which can also be NULL
- *
- * returns 1 if write is successful, 0 else.
- */
-static int write_acpi_int(acpi_handle handle, const char *method, int val,
-			  struct acpi_buffer *output)
-{
-	struct acpi_object_list params;	/* list of input parameters (int) */
-	union acpi_object in_obj;	/* the only param we use */
-	acpi_status status;
-
-	params.count = 1;
-	params.pointer = &in_obj;
-	in_obj.type = ACPI_TYPE_INTEGER;
-	in_obj.integer.value = val;
-
-	status = acpi_evaluate_object(handle, (char *)method, &params, output);
-	return (status == AE_OK);
-}
-
-static int read_acpi_int(acpi_handle handle, const char *method, int *val)
-{
-	struct acpi_buffer output;
-	union acpi_object out_obj;
-	acpi_status status;
-
-	output.length = sizeof(out_obj);
-	output.pointer = &out_obj;
-
-	status = acpi_evaluate_object(handle, (char *)method, NULL, &output);
-	*val = out_obj.integer.value;
-	return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
-}
-
-static int asus_info_proc_show(struct seq_file *m, void *v)
-{
-	int temp;
-
-	seq_printf(m, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n");
-	seq_printf(m, "Model reference    : %s\n", hotk->methods->name);
-	/*
-	 * The SFUN method probably allows the original driver to get the list
-	 * of features supported by a given model. For now, 0x0100 or 0x0800
-	 * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
-	 * The significance of others is yet to be found.
-	 */
-	if (read_acpi_int(hotk->handle, "SFUN", &temp))
-		seq_printf(m, "SFUN value         : 0x%04x\n", temp);
-	/*
-	 * Another value for userspace: the ASYM method returns 0x02 for
-	 * battery low and 0x04 for battery critical, its readings tend to be
-	 * more accurate than those provided by _BST.
-	 * Note: since not all the laptops provide this method, errors are
-	 * silently ignored.
-	 */
-	if (read_acpi_int(hotk->handle, "ASYM", &temp))
-		seq_printf(m, "ASYM value         : 0x%04x\n", temp);
-	if (asus_info) {
-		seq_printf(m, "DSDT length        : %d\n", asus_info->length);
-		seq_printf(m, "DSDT checksum      : %d\n", asus_info->checksum);
-		seq_printf(m, "DSDT revision      : %d\n", asus_info->revision);
-		seq_printf(m, "OEM id             : %.*s\n", ACPI_OEM_ID_SIZE, asus_info->oem_id);
-		seq_printf(m, "OEM table id       : %.*s\n", ACPI_OEM_TABLE_ID_SIZE, asus_info->oem_table_id);
-		seq_printf(m, "OEM revision       : 0x%x\n", asus_info->oem_revision);
-		seq_printf(m, "ASL comp vendor id : %.*s\n", ACPI_NAME_SIZE, asus_info->asl_compiler_id);
-		seq_printf(m, "ASL comp revision  : 0x%x\n", asus_info->asl_compiler_revision);
-	}
-
-	return 0;
-}
-
-static int asus_info_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, asus_info_proc_show, NULL);
-}
-
-static const struct file_operations asus_info_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= asus_info_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-/*
- * /proc handlers
- * We write our info in page, we begin at offset off and cannot write more
- * than count bytes. We set eof to 1 if we handle those 2 values. We return the
- * number of bytes written in page
- */
-
-/* Generic LED functions */
-static int read_led(const char *ledname, int ledmask)
-{
-	if (ledname) {
-		int led_status;
-
-		if (read_acpi_int(NULL, ledname, &led_status))
-			return led_status;
-		else
-			pr_warn("Error reading LED status\n");
-	}
-	return (hotk->status & ledmask) ? 1 : 0;
-}
-
-static int parse_arg(const char __user *buf, unsigned long count, int *val)
-{
-	char s[32];
-	if (!count)
-		return 0;
-	if (count > 31)
-		return -EINVAL;
-	if (copy_from_user(s, buf, count))
-		return -EFAULT;
-	s[count] = 0;
-	if (sscanf(s, "%i", val) != 1)
-		return -EINVAL;
-	return count;
-}
-
-/* FIXME: kill extraneous args so it can be called independently */
-static int
-write_led(const char __user *buffer, unsigned long count,
-	  char *ledname, int ledmask, int invert)
-{
-	int rv, value;
-	int led_out = 0;
-
-	rv = parse_arg(buffer, count, &value);
-	if (rv > 0)
-		led_out = value ? 1 : 0;
-
-	hotk->status =
-	    (led_out) ? (hotk->status | ledmask) : (hotk->status & ~ledmask);
-
-	if (invert)		/* invert target value */
-		led_out = !led_out;
-
-	if (!write_acpi_int(hotk->handle, ledname, led_out, NULL))
-		pr_warn("LED (%s) write failed\n", ledname);
-
-	return rv;
-}
-
-/*
- * Proc handlers for MLED
- */
-static int mled_proc_show(struct seq_file *m, void *v)
-{
-	seq_printf(m, "%d\n", read_led(hotk->methods->mled_status, MLED_ON));
-	return 0;
-}
-
-static int mled_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, mled_proc_show, NULL);
-}
-
-static ssize_t mled_proc_write(struct file *file, const char __user *buffer,
-		size_t count, loff_t *pos)
-{
-	return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1);
-}
-
-static const struct file_operations mled_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= mled_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-	.write		= mled_proc_write,
-};
-
-/*
- * Proc handlers for LED display
- */
-static int ledd_proc_show(struct seq_file *m, void *v)
-{
-	seq_printf(m, "0x%08x\n", hotk->ledd_status);
-	return 0;
-}
-
-static int ledd_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, ledd_proc_show, NULL);
-}
-
-static ssize_t ledd_proc_write(struct file *file, const char __user *buffer,
-		size_t count, loff_t *pos)
-{
-	int rv, value;
-
-	rv = parse_arg(buffer, count, &value);
-	if (rv > 0) {
-		if (!write_acpi_int
-		    (hotk->handle, hotk->methods->mt_ledd, value, NULL))
-			pr_warn("LED display write failed\n");
-		else
-			hotk->ledd_status = (u32) value;
-	}
-	return rv;
-}
-
-static const struct file_operations ledd_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= ledd_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-	.write		= ledd_proc_write,
-};
-
-/*
- * Proc handlers for WLED
- */
-static int wled_proc_show(struct seq_file *m, void *v)
-{
-	seq_printf(m, "%d\n", read_led(hotk->methods->wled_status, WLED_ON));
-	return 0;
-}
-
-static int wled_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, wled_proc_show, NULL);
-}
-
-static ssize_t wled_proc_write(struct file *file, const char __user *buffer,
-		size_t count, loff_t *pos)
-{
-	return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0);
-}
-
-static const struct file_operations wled_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= wled_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-	.write		= wled_proc_write,
-};
-
-/*
- * Proc handlers for Bluetooth
- */
-static int bluetooth_proc_show(struct seq_file *m, void *v)
-{
-	seq_printf(m, "%d\n", read_led(hotk->methods->bt_status, BT_ON));
-	return 0;
-}
-
-static int bluetooth_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, bluetooth_proc_show, NULL);
-}
-
-static ssize_t bluetooth_proc_write(struct file *file,
-		const char __user *buffer, size_t count, loff_t *pos)
-{
-	/* Note: mt_bt_switch controls both internal Bluetooth adapter's
-	   presence and its LED */
-	return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0);
-}
-
-static const struct file_operations bluetooth_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= bluetooth_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-	.write		= bluetooth_proc_write,
-};
-
-/*
- * Proc handlers for TLED
- */
-static int tled_proc_show(struct seq_file *m, void *v)
-{
-	seq_printf(m, "%d\n", read_led(hotk->methods->tled_status, TLED_ON));
-	return 0;
-}
-
-static int tled_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, tled_proc_show, NULL);
-}
-
-static ssize_t tled_proc_write(struct file *file, const char __user *buffer,
-		size_t count, loff_t *pos)
-{
-	return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0);
-}
-
-static const struct file_operations tled_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= tled_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-	.write		= tled_proc_write,
-};
-
-static int get_lcd_state(void)
-{
-	int lcd = 0;
-
-	if (hotk->model == L3H) {
-		/* L3H and the like have to be handled differently */
-		acpi_status status = 0;
-		struct acpi_object_list input;
-		union acpi_object mt_params[2];
-		struct acpi_buffer output;
-		union acpi_object out_obj;
-
-		input.count = 2;
-		input.pointer = mt_params;
-		/* Note: the following values are partly guessed up, but
-		   otherwise they seem to work */
-		mt_params[0].type = ACPI_TYPE_INTEGER;
-		mt_params[0].integer.value = 0x02;
-		mt_params[1].type = ACPI_TYPE_INTEGER;
-		mt_params[1].integer.value = 0x02;
-
-		output.length = sizeof(out_obj);
-		output.pointer = &out_obj;
-
-		status =
-		    acpi_evaluate_object(NULL, hotk->methods->lcd_status,
-					 &input, &output);
-		if (status != AE_OK)
-			return -1;
-		if (out_obj.type == ACPI_TYPE_INTEGER)
-			/* That's what the AML code does */
-			lcd = out_obj.integer.value >> 8;
-	} else if (hotk->model == F3Sa) {
-		unsigned long long tmp;
-		union acpi_object param;
-		struct acpi_object_list input;
-		acpi_status status;
-
-		/* Read pin 11 */
-		param.type = ACPI_TYPE_INTEGER;
-		param.integer.value = 0x11;
-		input.count = 1;
-		input.pointer = &param;
-
-		status = acpi_evaluate_integer(NULL, hotk->methods->lcd_status,
-						&input, &tmp);
-		if (status != AE_OK)
-			return -1;
-
-		lcd = tmp;
-	} else {
-		/* We don't have to check anything if we are here */
-		if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
-			pr_warn("Error reading LCD status\n");
-
-		if (hotk->model == L2D)
-			lcd = ~lcd;
-	}
-
-	return (lcd & 1);
-}
-
-static int set_lcd_state(int value)
-{
-	int lcd = 0;
-	acpi_status status = 0;
-
-	lcd = value ? 1 : 0;
-	if (lcd != get_lcd_state()) {
-		/* switch */
-		if (hotk->model != L3H) {
-			status =
-			    acpi_evaluate_object(NULL,
-						 hotk->methods->mt_lcd_switch,
-						 NULL, NULL);
-		} else {
-			/* L3H and the like must be handled differently */
-			if (!write_acpi_int
-			    (hotk->handle, hotk->methods->mt_lcd_switch, 0x07,
-			     NULL))
-				status = AE_ERROR;
-			/* L3H's AML executes EHK (0x07) upon Fn+F7 keypress,
-			   the exact behaviour is simulated here */
-		}
-		if (ACPI_FAILURE(status))
-			pr_warn("Error switching LCD\n");
-	}
-	return 0;
-
-}
-
-static int lcd_proc_show(struct seq_file *m, void *v)
-{
-	seq_printf(m, "%d\n", get_lcd_state());
-	return 0;
-}
-
-static int lcd_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, lcd_proc_show, NULL);
-}
-
-static ssize_t lcd_proc_write(struct file *file, const char __user *buffer,
-	       size_t count, loff_t *pos)
-{
-	int rv, value;
-
-	rv = parse_arg(buffer, count, &value);
-	if (rv > 0)
-		set_lcd_state(value);
-	return rv;
-}
-
-static const struct file_operations lcd_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= lcd_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-	.write		= lcd_proc_write,
-};
-
-static int read_brightness(struct backlight_device *bd)
-{
-	int value;
-
-	if (hotk->methods->brightness_get) {	/* SPLV/GPLV laptop */
-		if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get,
-				   &value))
-			pr_warn("Error reading brightness\n");
-	} else if (hotk->methods->brightness_status) {	/* For D1 for example */
-		if (!read_acpi_int(NULL, hotk->methods->brightness_status,
-				   &value))
-			pr_warn("Error reading brightness\n");
-	} else			/* No GPLV method */
-		value = hotk->brightness;
-	return value;
-}
-
-/*
- * Change the brightness level
- */
-static int set_brightness(int value)
-{
-	acpi_status status = 0;
-	int ret = 0;
-
-	/* SPLV laptop */
-	if (hotk->methods->brightness_set) {
-		if (!write_acpi_int(hotk->handle, hotk->methods->brightness_set,
-				    value, NULL)) {
-			pr_warn("Error changing brightness\n");
-			ret = -EIO;
-		}
-		goto out;
-	}
-
-	/* No SPLV method if we are here, act as appropriate */
-	value -= read_brightness(NULL);
-	while (value != 0) {
-		status = acpi_evaluate_object(NULL, (value > 0) ?
-					      hotk->methods->brightness_up :
-					      hotk->methods->brightness_down,
-					      NULL, NULL);
-		(value > 0) ? value-- : value++;
-		if (ACPI_FAILURE(status)) {
-			pr_warn("Error changing brightness\n");
-			ret = -EIO;
-		}
-	}
-out:
-	return ret;
-}
-
-static int set_brightness_status(struct backlight_device *bd)
-{
-	return set_brightness(bd->props.brightness);
-}
-
-static int brn_proc_show(struct seq_file *m, void *v)
-{
-	seq_printf(m, "%d\n", read_brightness(NULL));
-	return 0;
-}
-
-static int brn_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, brn_proc_show, NULL);
-}
-
-static ssize_t brn_proc_write(struct file *file, const char __user *buffer,
-	       size_t count, loff_t *pos)
-{
-	int rv, value;
-
-	rv = parse_arg(buffer, count, &value);
-	if (rv > 0) {
-		value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
-		/* 0 <= value <= 15 */
-		set_brightness(value);
-	}
-	return rv;
-}
-
-static const struct file_operations brn_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= brn_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-	.write		= brn_proc_write,
-};
-
-static void set_display(int value)
-{
-	/* no sanity check needed for now */
-	if (!write_acpi_int(hotk->handle, hotk->methods->display_set,
-			    value, NULL))
-		pr_warn("Error setting display\n");
-	return;
-}
-
-/*
- * Now, *this* one could be more user-friendly, but so far, no-one has
- * complained. The significance of bits is the same as in proc_write_disp()
- */
-static int disp_proc_show(struct seq_file *m, void *v)
-{
-	int value = 0;
-
-	if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value))
-		pr_warn("Error reading display status\n");
-	value &= 0x07;	/* needed for some models, shouldn't hurt others */
-	seq_printf(m, "%d\n", value);
-	return 0;
-}
-
-static int disp_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, disp_proc_show, NULL);
-}
-
-/*
- * Experimental support for display switching. As of now: 1 should activate
- * the LCD output, 2 should do for CRT, and 4 for TV-Out. Any combination
- * (bitwise) of these will suffice. I never actually tested 3 displays hooked
- * up simultaneously, so be warned. See the acpi4asus README for more info.
- */
-static ssize_t disp_proc_write(struct file *file, const char __user *buffer,
-		size_t count, loff_t *pos)
-{
-	int rv, value;
-
-	rv = parse_arg(buffer, count, &value);
-	if (rv > 0)
-		set_display(value);
-	return rv;
-}
-
-static const struct file_operations disp_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= disp_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-	.write		= disp_proc_write,
-};
-
-static int
-asus_proc_add(char *name, const struct file_operations *proc_fops, umode_t mode,
-		     struct acpi_device *device)
-{
-	struct proc_dir_entry *proc;
-
-	proc = proc_create_data(name, mode, acpi_device_dir(device),
-				proc_fops, acpi_driver_data(device));
-	if (!proc) {
-		pr_warn("  Unable to create %s fs entry\n", name);
-		return -1;
-	}
-	proc->uid = asus_uid;
-	proc->gid = asus_gid;
-	return 0;
-}
-
-static int asus_hotk_add_fs(struct acpi_device *device)
-{
-	struct proc_dir_entry *proc;
-	umode_t mode;
-
-	if ((asus_uid == 0) && (asus_gid == 0)) {
-		mode = S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP;
-	} else {
-		mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP;
-		pr_warn("  asus_uid and asus_gid parameters are "
-			"deprecated, use chown and chmod instead!\n");
-	}
-
-	acpi_device_dir(device) = asus_proc_dir;
-	if (!acpi_device_dir(device))
-		return -ENODEV;
-
-	proc = proc_create(PROC_INFO, mode, acpi_device_dir(device),
-			   &asus_info_proc_fops);
-	if (proc) {
-		proc->uid = asus_uid;
-		proc->gid = asus_gid;
-	} else {
-		pr_warn("  Unable to create " PROC_INFO " fs entry\n");
-	}
-
-	if (hotk->methods->mt_wled) {
-		asus_proc_add(PROC_WLED, &wled_proc_fops, mode, device);
-	}
-
-	if (hotk->methods->mt_ledd) {
-		asus_proc_add(PROC_LEDD, &ledd_proc_fops, mode, device);
-	}
-
-	if (hotk->methods->mt_mled) {
-		asus_proc_add(PROC_MLED, &mled_proc_fops, mode, device);
-	}
-
-	if (hotk->methods->mt_tled) {
-		asus_proc_add(PROC_TLED, &tled_proc_fops, mode, device);
-	}
-
-	if (hotk->methods->mt_bt_switch) {
-		asus_proc_add(PROC_BT, &bluetooth_proc_fops, mode, device);
-	}
-
-	/*
-	 * We need both read node and write method as LCD switch is also
-	 * accessible from the keyboard
-	 */
-	if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) {
-		asus_proc_add(PROC_LCD, &lcd_proc_fops, mode, device);
-	}
-
-	if ((hotk->methods->brightness_up && hotk->methods->brightness_down) ||
-	    (hotk->methods->brightness_get && hotk->methods->brightness_set)) {
-		asus_proc_add(PROC_BRN, &brn_proc_fops, mode, device);
-	}
-
-	if (hotk->methods->display_set) {
-		asus_proc_add(PROC_DISP, &disp_proc_fops, mode, device);
-	}
-
-	return 0;
-}
-
-static int asus_hotk_remove_fs(struct acpi_device *device)
-{
-	if (acpi_device_dir(device)) {
-		remove_proc_entry(PROC_INFO, acpi_device_dir(device));
-		if (hotk->methods->mt_wled)
-			remove_proc_entry(PROC_WLED, acpi_device_dir(device));
-		if (hotk->methods->mt_mled)
-			remove_proc_entry(PROC_MLED, acpi_device_dir(device));
-		if (hotk->methods->mt_tled)
-			remove_proc_entry(PROC_TLED, acpi_device_dir(device));
-		if (hotk->methods->mt_ledd)
-			remove_proc_entry(PROC_LEDD, acpi_device_dir(device));
-		if (hotk->methods->mt_bt_switch)
-			remove_proc_entry(PROC_BT, acpi_device_dir(device));
-		if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status)
-			remove_proc_entry(PROC_LCD, acpi_device_dir(device));
-		if ((hotk->methods->brightness_up
-		     && hotk->methods->brightness_down)
-		    || (hotk->methods->brightness_get
-			&& hotk->methods->brightness_set))
-			remove_proc_entry(PROC_BRN, acpi_device_dir(device));
-		if (hotk->methods->display_set)
-			remove_proc_entry(PROC_DISP, acpi_device_dir(device));
-	}
-	return 0;
-}
-
-static void asus_hotk_notify(struct acpi_device *device, u32 event)
-{
-	/* TODO Find a better way to handle events count. */
-	if (!hotk)
-		return;
-
-	/*
-	 * The BIOS *should* be sending us device events, but apparently
-	 * Asus uses system events instead, so just ignore any device
-	 * events we get.
-	 */
-	if (event > ACPI_MAX_SYS_NOTIFY)
-		return;
-
-	if ((event & ~((u32) BR_UP)) < 16)
-		hotk->brightness = (event & ~((u32) BR_UP));
-	else if ((event & ~((u32) BR_DOWN)) < 16)
-		hotk->brightness = (event & ~((u32) BR_DOWN));
-
-	acpi_bus_generate_proc_event(hotk->device, event,
-				hotk->event_count[event % 128]++);
-
-	return;
-}
-
-/*
- * Match the model string to the list of supported models. Return END_MODEL if
- * no match or model is NULL.
- */
-static int asus_model_match(char *model)
-{
-	if (model == NULL)
-		return END_MODEL;
-
-	if (strncmp(model, "L3D", 3) == 0)
-		return L3D;
-	else if (strncmp(model, "L2E", 3) == 0 ||
-		 strncmp(model, "L3H", 3) == 0 || strncmp(model, "L5D", 3) == 0)
-		return L3H;
-	else if (strncmp(model, "L3", 2) == 0 || strncmp(model, "L2B", 3) == 0)
-		return L3C;
-	else if (strncmp(model, "L8L", 3) == 0)
-		return L8L;
-	else if (strncmp(model, "L4R", 3) == 0)
-		return L4R;
-	else if (strncmp(model, "M6N", 3) == 0 || strncmp(model, "W3N", 3) == 0)
-		return M6N;
-	else if (strncmp(model, "M6R", 3) == 0 || strncmp(model, "A3G", 3) == 0)
-		return M6R;
-	else if (strncmp(model, "M2N", 3) == 0 ||
-		 strncmp(model, "M3N", 3) == 0 ||
-		 strncmp(model, "M5N", 3) == 0 ||
-		 strncmp(model, "S1N", 3) == 0 ||
-		 strncmp(model, "S5N", 3) == 0)
-		return xxN;
-	else if (strncmp(model, "M1", 2) == 0)
-		return M1A;
-	else if (strncmp(model, "M2", 2) == 0 || strncmp(model, "L4E", 3) == 0)
-		return M2E;
-	else if (strncmp(model, "L2", 2) == 0)
-		return L2D;
-	else if (strncmp(model, "L8", 2) == 0)
-		return S1x;
-	else if (strncmp(model, "D1", 2) == 0)
-		return D1x;
-	else if (strncmp(model, "A1", 2) == 0)
-		return A1x;
-	else if (strncmp(model, "A2", 2) == 0)
-		return A2x;
-	else if (strncmp(model, "J1", 2) == 0)
-		return S2x;
-	else if (strncmp(model, "L5", 2) == 0)
-		return L5x;
-	else if (strncmp(model, "A4G", 3) == 0)
-		return A4G;
-	else if (strncmp(model, "W1N", 3) == 0)
-		return W1N;
-	else if (strncmp(model, "W3V", 3) == 0)
-		return W3V;
-	else if (strncmp(model, "W5A", 3) == 0)
-		return W5A;
-	else if (strncmp(model, "R1F", 3) == 0)
-		return R1F;
-	else if (strncmp(model, "A4S", 3) == 0)
-		return A4S;
-	else if (strncmp(model, "F3Sa", 4) == 0)
-		return F3Sa;
-	else
-		return END_MODEL;
-}
-
-/*
- * This function is used to initialize the hotk with right values. In this
- * method, we can make all the detection we want, and modify the hotk struct
- */
-static int asus_hotk_get_info(void)
-{
-	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-	union acpi_object *model = NULL;
-	int bsts_result;
-	char *string = NULL;
-	acpi_status status;
-
-	/*
-	 * Get DSDT headers early enough to allow for differentiating between
-	 * models, but late enough to allow acpi_bus_register_driver() to fail
-	 * before doing anything ACPI-specific. Should we encounter a machine,
-	 * which needs special handling (i.e. its hotkey device has a different
-	 * HID), this bit will be moved. A global variable asus_info contains
-	 * the DSDT header.
-	 */
-	status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
-	if (ACPI_FAILURE(status))
-		pr_warn("  Couldn't get the DSDT table header\n");
-
-	/* We have to write 0 on init this far for all ASUS models */
-	if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
-		pr_err("  Hotkey initialization failed\n");
-		return -ENODEV;
-	}
-
-	/* This needs to be called for some laptops to init properly */
-	if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result))
-		pr_warn("  Error calling BSTS\n");
-	else if (bsts_result)
-		pr_notice("  BSTS called, 0x%02x returned\n", bsts_result);
-
-	/*
-	 * Try to match the object returned by INIT to the specific model.
-	 * Handle every possible object (or the lack of thereof) the DSDT
-	 * writers might throw at us. When in trouble, we pass NULL to
-	 * asus_model_match() and try something completely different.
-	 */
-	if (buffer.pointer) {
-		model = buffer.pointer;
-		switch (model->type) {
-		case ACPI_TYPE_STRING:
-			string = model->string.pointer;
-			break;
-		case ACPI_TYPE_BUFFER:
-			string = model->buffer.pointer;
-			break;
-		default:
-			kfree(model);
-			model = NULL;
-			break;
-		}
-	}
-	hotk->model = asus_model_match(string);
-	if (hotk->model == END_MODEL) {	/* match failed */
-		if (asus_info &&
-		    strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) {
-			hotk->model = P30;
-			pr_notice("  Samsung P30 detected, supported\n");
-			hotk->methods = &model_conf[hotk->model];
-			kfree(model);
-			return 0;
-		} else {
-			hotk->model = M2E;
-			pr_notice("  unsupported model %s, trying default values\n",
-				  string);
-			pr_notice("  send /proc/acpi/dsdt to the developers\n");
-			kfree(model);
-			return -ENODEV;
-		}
-	}
-	hotk->methods = &model_conf[hotk->model];
-	pr_notice("  %s model detected, supported\n", string);
-
-	/* Sort of per-model blacklist */
-	if (strncmp(string, "L2B", 3) == 0)
-		hotk->methods->lcd_status = NULL;
-	/* L2B is similar enough to L3C to use its settings, with this only
-	   exception */
-	else if (strncmp(string, "A3G", 3) == 0)
-		hotk->methods->lcd_status = "\\BLFG";
-	/* A3G is like M6R */
-	else if (strncmp(string, "S5N", 3) == 0 ||
-		 strncmp(string, "M5N", 3) == 0 ||
-		 strncmp(string, "W3N", 3) == 0)
-		hotk->methods->mt_mled = NULL;
-	/* S5N, M5N and W3N have no MLED */
-	else if (strncmp(string, "L5D", 3) == 0)
-		hotk->methods->mt_wled = NULL;
-	/* L5D's WLED is not controlled by ACPI */
-	else if (strncmp(string, "M2N", 3) == 0 ||
-		 strncmp(string, "W3V", 3) == 0 ||
-		 strncmp(string, "S1N", 3) == 0)
-		hotk->methods->mt_wled = "WLED";
-	/* M2N, S1N and W3V have a usable WLED */
-	else if (asus_info) {
-		if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
-			hotk->methods->mled_status = NULL;
-		/* S1300A reports L84F, but L1400B too, account for that */
-	}
-
-	kfree(model);
-
-	return 0;
-}
-
-static int asus_hotk_check(void)
-{
-	int result = 0;
-
-	result = acpi_bus_get_status(hotk->device);
-	if (result)
-		return result;
-
-	if (hotk->device->status.present) {
-		result = asus_hotk_get_info();
-	} else {
-		pr_err("  Hotkey device not present, aborting\n");
-		return -EINVAL;
-	}
-
-	return result;
-}
-
-static int asus_hotk_found;
-
-static int asus_hotk_add(struct acpi_device *device)
-{
-	acpi_status status = AE_OK;
-	int result;
-
-	pr_notice("Asus Laptop ACPI Extras version %s\n", ASUS_ACPI_VERSION);
-
-	hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
-	if (!hotk)
-		return -ENOMEM;
-
-	hotk->handle = device->handle;
-	strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME);
-	strcpy(acpi_device_class(device), ACPI_HOTK_CLASS);
-	device->driver_data = hotk;
-	hotk->device = device;
-
-	result = asus_hotk_check();
-	if (result)
-		goto end;
-
-	result = asus_hotk_add_fs(device);
-	if (result)
-		goto end;
-
-	/* For laptops without GPLV: init the hotk->brightness value */
-	if ((!hotk->methods->brightness_get)
-	    && (!hotk->methods->brightness_status)
-	    && (hotk->methods->brightness_up && hotk->methods->brightness_down)) {
-		status =
-		    acpi_evaluate_object(NULL, hotk->methods->brightness_down,
-					 NULL, NULL);
-		if (ACPI_FAILURE(status))
-			pr_warn("  Error changing brightness\n");
-		else {
-			status =
-			    acpi_evaluate_object(NULL,
-						 hotk->methods->brightness_up,
-						 NULL, NULL);
-			if (ACPI_FAILURE(status))
-				pr_warn("  Strange, error changing brightness\n");
-		}
-	}
-
-	asus_hotk_found = 1;
-
-	/* LED display is off by default */
-	hotk->ledd_status = 0xFFF;
-
-end:
-	if (result)
-		kfree(hotk);
-
-	return result;
-}
-
-static int asus_hotk_remove(struct acpi_device *device, int type)
-{
-	asus_hotk_remove_fs(device);
-
-	kfree(hotk);
-
-	return 0;
-}
-
-static const struct backlight_ops asus_backlight_data = {
-	.get_brightness = read_brightness,
-	.update_status  = set_brightness_status,
-};
-
-static void asus_acpi_exit(void)
-{
-	if (asus_backlight_device)
-		backlight_device_unregister(asus_backlight_device);
-
-	acpi_bus_unregister_driver(&asus_hotk_driver);
-	remove_proc_entry(PROC_ASUS, acpi_root_dir);
-
-	return;
-}
-
-static int __init asus_acpi_init(void)
-{
-	struct backlight_properties props;
-	int result;
-
-	result = acpi_bus_register_driver(&asus_hotk_driver);
-	if (result < 0)
-		return result;
-
-	asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir);
-	if (!asus_proc_dir) {
-		pr_err("Unable to create /proc entry\n");
-		acpi_bus_unregister_driver(&asus_hotk_driver);
-		return -ENODEV;
-	}
-
-	/*
-	 * This is a bit of a kludge.  We only want this module loaded
-	 * for ASUS systems, but there's currently no way to probe the
-	 * ACPI namespace for ASUS HIDs.  So we just return failure if
-	 * we didn't find one, which will cause the module to be
-	 * unloaded.
-	 */
-	if (!asus_hotk_found) {
-		acpi_bus_unregister_driver(&asus_hotk_driver);
-		remove_proc_entry(PROC_ASUS, acpi_root_dir);
-		return -ENODEV;
-	}
-
-	memset(&props, 0, sizeof(struct backlight_properties));
-	props.type = BACKLIGHT_PLATFORM;
-	props.max_brightness = 15;
-	asus_backlight_device = backlight_device_register("asus", NULL, NULL,
-							  &asus_backlight_data,
-							  &props);
-	if (IS_ERR(asus_backlight_device)) {
-		pr_err("Could not register asus backlight device\n");
-		asus_backlight_device = NULL;
-		asus_acpi_exit();
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-module_init(asus_acpi_init);
-module_exit(asus_acpi_exit);
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index d967344..1887e2f 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -882,6 +882,7 @@
 	},
 	{ }
 };
+MODULE_DEVICE_TABLE(dmi, compal_dmi_table);
 
 static void initialize_power_supply_data(struct compal_data *data)
 {
@@ -1097,16 +1098,3 @@
 MODULE_DESCRIPTION("Compal Laptop Support");
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
-
-MODULE_ALIAS("dmi:*:rnIFL90:rvrIFT00:*");
-MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*");
-MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*");
-MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*");
-MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*");
-MODULE_ALIAS("dmi:*:rnJHL90:rvrREFERENCE:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1012:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1110:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1210:*");
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index d93e962..a05fc9c 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -117,6 +117,7 @@
 	},
 	{ }
 };
+MODULE_DEVICE_TABLE(dmi, dell_device_table);
 
 static struct dmi_system_id __devinitdata dell_blacklist[] = {
 	/* Supported by compal-laptop */
@@ -184,6 +185,33 @@
 		},
 		.driver_data = &quirk_dell_vostro_v130,
 	},
+	{
+		.callback = dmi_matched,
+		.ident = "Dell Vostro 3555",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3555"),
+		},
+		.driver_data = &quirk_dell_vostro_v130,
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Dell Inspiron N311z",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N311z"),
+		},
+		.driver_data = &quirk_dell_vostro_v130,
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Dell Inspiron M5110",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"),
+		},
+		.driver_data = &quirk_dell_vostro_v130,
+	},
 };
 
 static struct calling_interface_buffer *buffer;
@@ -236,9 +264,7 @@
 {
 	switch (dm->type) {
 	case 0xd4: /* Indexed IO */
-		break;
 	case 0xd5: /* Protected Area Type 1 */
-		break;
 	case 0xd6: /* Protected Area Type 2 */
 		break;
 	case 0xda: /* Calling interface */
@@ -615,6 +641,7 @@
 static struct led_classdev touchpad_led = {
 	.name = "dell-laptop::touchpad",
 	.brightness_set = touchpad_led_set,
+	.flags = LED_CORE_SUSPENDRESUME,
 };
 
 static int __devinit touchpad_led_init(struct device *dev)
@@ -794,6 +821,3 @@
 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
 MODULE_DESCRIPTION("Dell laptop driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*");
-MODULE_ALIAS("dmi:*svnDellInc.:*:ct9:*");
-MODULE_ALIAS("dmi:*svnDellComputerCorporation.:*:ct8:*");
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index ea44abd..dab91b4 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -646,7 +646,7 @@
 		} else {
 			dev = pci_get_slot(bus, 0);
 			if (dev) {
-				pci_remove_bus_device(dev);
+				pci_stop_and_remove_bus_device(dev);
 				pci_dev_put(dev);
 			}
 		}
@@ -1251,6 +1251,14 @@
 /*
  * ACPI driver
  */
+static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event)
+{
+	if (!eeepc->inputdev)
+		return ;
+	if (!sparse_keymap_report_event(eeepc->inputdev, event, 1, true))
+		pr_info("Unknown key %x pressed\n", event);
+}
+
 static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
 {
 	struct eeepc_laptop *eeepc = acpi_driver_data(device);
@@ -1287,12 +1295,11 @@
 				* event will be desired value (or else ignored)
 				*/
 			}
-			sparse_keymap_report_event(eeepc->inputdev, event,
-						   1, true);
+			eeepc_input_notify(eeepc, event);
 		}
 	} else {
 		/* Everything else is a bona-fide keypress event */
-		sparse_keymap_report_event(eeepc->inputdev, event, 1, true);
+		eeepc_input_notify(eeepc, event);
 	}
 }
 
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
index 9f6e643..6567613 100644
--- a/drivers/platform/x86/eeepc-wmi.c
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -32,6 +32,7 @@
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
 #include <linux/dmi.h>
+#include <linux/fb.h>
 #include <acpi/acpi_bus.h>
 
 #include "asus-wmi.h"
@@ -84,9 +85,81 @@
 	{ KE_KEY, 0xed, { KEY_CAMERA_DOWN } },
 	{ KE_KEY, 0xee, { KEY_CAMERA_LEFT } },
 	{ KE_KEY, 0xef, { KEY_CAMERA_RIGHT } },
+	{ KE_KEY, 0xf3, { KEY_MENU } },
+	{ KE_KEY, 0xf5, { KEY_HOMEPAGE } },
+	{ KE_KEY, 0xf6, { KEY_ESC } },
 	{ KE_END, 0},
 };
 
+static struct quirk_entry quirk_asus_unknown = {
+};
+
+static struct quirk_entry quirk_asus_1000h = {
+	.hotplug_wireless = true,
+};
+
+static struct quirk_entry quirk_asus_et2012_type1 = {
+	.store_backlight_power = true,
+};
+
+static struct quirk_entry quirk_asus_et2012_type3 = {
+	.scalar_panel_brightness = true,
+	.store_backlight_power = true,
+};
+
+static struct quirk_entry *quirks;
+
+static void et2012_quirks(void)
+{
+	const struct dmi_device *dev = NULL;
+	char oemstring[30];
+
+	while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
+		if (sscanf(dev->name, "AEMS%24c", oemstring) == 1) {
+			if (oemstring[18] == '1')
+				quirks = &quirk_asus_et2012_type1;
+			else if (oemstring[18] == '3')
+				quirks = &quirk_asus_et2012_type3;
+			break;
+		}
+	}
+}
+
+static int dmi_matched(const struct dmi_system_id *dmi)
+{
+	char *model;
+
+	quirks = dmi->driver_data;
+
+	model = (char *)dmi->matches[1].substr;
+	if (unlikely(strncmp(model, "ET2012", 6) == 0))
+		et2012_quirks();
+
+	return 1;
+}
+
+static struct dmi_system_id asus_quirks[] = {
+	{
+		.callback = dmi_matched,
+		.ident = "ASUSTeK Computer INC. 1000H",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "1000H"),
+		},
+		.driver_data = &quirk_asus_1000h,
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "ASUSTeK Computer INC. ET2012E/I",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "ET2012"),
+		},
+		.driver_data = &quirk_asus_unknown,
+	},
+	{},
+};
+
 static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code,
 				 unsigned int *value, bool *autorelease)
 {
@@ -141,33 +214,16 @@
 	return 0;
 }
 
-static void eeepc_dmi_check(struct asus_wmi_driver *driver)
-{
-	const char *model;
-
-	model = dmi_get_system_info(DMI_PRODUCT_NAME);
-	if (!model)
-		return;
-
-	/*
-	 * Whitelist for wlan hotplug
-	 *
-	 * Asus 1000H needs the current hotplug code to handle
-	 * Fn+F2 correctly. We may add other Asus here later, but
-	 * it seems that most of the laptops supported by asus-wmi
-	 * don't need to be on this list
-	 */
-	if (strcmp(model, "1000H") == 0) {
-		driver->hotplug_wireless = true;
-		pr_info("wlan hotplug enabled\n");
-	}
-}
-
 static void eeepc_wmi_quirks(struct asus_wmi_driver *driver)
 {
-	driver->hotplug_wireless = hotplug_wireless;
-	driver->wapf = -1;
-	eeepc_dmi_check(driver);
+	quirks = &quirk_asus_unknown;
+	quirks->hotplug_wireless = hotplug_wireless;
+
+	dmi_check_system(asus_quirks);
+
+	driver->quirks = quirks;
+	driver->quirks->wapf = -1;
+	driver->panel_power = FB_BLANK_UNBLANK;
 }
 
 static struct asus_wmi_driver asus_wmi_driver = {
@@ -179,7 +235,7 @@
 	.input_phys = EEEPC_WMI_FILE "/input0",
 	.key_filter = eeepc_wmi_key_filter,
 	.probe = eeepc_wmi_probe,
-	.quirks = eeepc_wmi_quirks,
+	.detect_quirks = eeepc_wmi_quirks,
 };
 
 
diff --git a/drivers/platform/x86/hdaps.c b/drivers/platform/x86/hdaps.c
index ba68d4e..7387f97 100644
--- a/drivers/platform/x86/hdaps.c
+++ b/drivers/platform/x86/hdaps.c
@@ -375,7 +375,7 @@
 static ssize_t hdaps_temp1_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	u8 temp;
+	u8 uninitialized_var(temp);
 	int ret;
 
 	ret = hdaps_readb_one(HDAPS_PORT_TEMP1, &temp);
@@ -388,7 +388,7 @@
 static ssize_t hdaps_temp2_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	u8 temp;
+	u8 uninitialized_var(temp);
 	int ret;
 
 	ret = hdaps_readb_one(HDAPS_PORT_TEMP2, &temp);
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
index 88a98cf..f7ba316e 100644
--- a/drivers/platform/x86/intel_ips.c
+++ b/drivers/platform/x86/intel_ips.c
@@ -609,25 +609,16 @@
 	bool ret = false;
 	u32 temp_limit;
 	u32 avg_power;
-	const char *msg = "MCP limit exceeded: ";
 
 	spin_lock_irqsave(&ips->turbo_status_lock, flags);
 
 	temp_limit = ips->mcp_temp_limit * 100;
-	if (ips->mcp_avg_temp > temp_limit) {
-		dev_info(&ips->dev->dev,
-			"%sAvg temp %u, limit %u\n", msg, ips->mcp_avg_temp,
-			temp_limit);
+	if (ips->mcp_avg_temp > temp_limit)
 		ret = true;
-	}
 
 	avg_power = ips->cpu_avg_power + ips->mch_avg_power;
-	if (avg_power > ips->mcp_power_limit) {
-		dev_info(&ips->dev->dev,
-			"%sAvg power %u, limit %u\n", msg, avg_power,
-			ips->mcp_power_limit);
+	if (avg_power > ips->mcp_power_limit)
 		ret = true;
-	}
 
 	spin_unlock_irqrestore(&ips->turbo_status_lock, flags);
 
diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c
index f1ae507..0a3594c 100644
--- a/drivers/platform/x86/intel_mid_powerbtn.c
+++ b/drivers/platform/x86/intel_mid_powerbtn.c
@@ -23,21 +23,27 @@
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
-
-#include <asm/intel_scu_ipc.h>
+#include <linux/mfd/intel_msic.h>
 
 #define DRIVER_NAME "msic_power_btn"
 
-#define MSIC_PB_STATUS	0x3f
 #define MSIC_PB_LEVEL	(1 << 3) /* 1 - release, 0 - press */
 
+/*
+ * MSIC document ti_datasheet defines the 1st bit reg 0x21 is used to mask
+ * power button interrupt
+ */
+#define MSIC_PWRBTNM    (1 << 0)
+
 static irqreturn_t mfld_pb_isr(int irq, void *dev_id)
 {
 	struct input_dev *input = dev_id;
 	int ret;
 	u8 pbstat;
 
-	ret = intel_scu_ipc_ioread8(MSIC_PB_STATUS, &pbstat);
+	ret = intel_msic_reg_read(INTEL_MSIC_PBSTATUS, &pbstat);
+	dev_dbg(input->dev.parent, "PB_INT status= %d\n", pbstat);
+
 	if (ret < 0) {
 		dev_err(input->dev.parent, "Read error %d while reading"
 			       " MSIC_PB_STATUS\n", ret);
@@ -88,6 +94,24 @@
 	}
 
 	platform_set_drvdata(pdev, input);
+
+	/*
+	 * SCU firmware might send power button interrupts to IA core before
+	 * kernel boots and doesn't get EOI from IA core. The first bit of
+	 * MSIC reg 0x21 is kept masked, and SCU firmware doesn't send new
+	 * power interrupt to Android kernel. Unmask the bit when probing
+	 * power button in kernel.
+	 * There is a very narrow race between irq handler and power button
+	 * initialization. The race happens rarely. So we needn't worry
+	 * about it.
+	 */
+	error = intel_msic_reg_update(INTEL_MSIC_IRQLVL1MSK, 0, MSIC_PWRBTNM);
+	if (error) {
+		dev_err(&pdev->dev, "Unable to clear power button interrupt, "
+				"error: %d\n", error);
+		goto err_free_irq;
+	}
+
 	return 0;
 
 err_free_irq:
@@ -118,17 +142,7 @@
 	.remove	= __devexit_p(mfld_pb_remove),
 };
 
-static int __init mfld_pb_init(void)
-{
-	return platform_driver_register(&mfld_pb_driver);
-}
-module_init(mfld_pb_init);
-
-static void __exit mfld_pb_exit(void)
-{
-	platform_driver_unregister(&mfld_pb_driver);
-}
-module_exit(mfld_pb_exit);
+module_platform_driver(mfld_pb_driver);
 
 MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>");
 MODULE_DESCRIPTION("Intel Medfield Power Button Driver");
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c
index ccd7b1f..5ae9cd9 100644
--- a/drivers/platform/x86/intel_mid_thermal.c
+++ b/drivers/platform/x86/intel_mid_thermal.c
@@ -33,18 +33,15 @@
 #include <linux/slab.h>
 #include <linux/pm.h>
 #include <linux/thermal.h>
-
-#include <asm/intel_scu_ipc.h>
+#include <linux/mfd/intel_msic.h>
 
 /* Number of thermal sensors */
 #define MSIC_THERMAL_SENSORS	4
 
 /* ADC1 - thermal registers */
-#define MSIC_THERM_ADC1CNTL1	0x1C0
 #define MSIC_ADC_ENBL		0x10
 #define MSIC_ADC_START		0x08
 
-#define MSIC_THERM_ADC1CNTL3	0x1C2
 #define MSIC_ADCTHERM_ENBL	0x04
 #define MSIC_ADCRRDATA_ENBL	0x05
 #define MSIC_CHANL_MASK_VAL	0x0F
@@ -75,8 +72,8 @@
 #define ADC_VAL60C		315
 
 /* ADC base addresses */
-#define ADC_CHNL_START_ADDR	0x1C5	/* increments by 1 */
-#define ADC_DATA_START_ADDR	0x1D4	/* increments by 2 */
+#define ADC_CHNL_START_ADDR	INTEL_MSIC_ADC1ADDR0	/* increments by 1 */
+#define ADC_DATA_START_ADDR	INTEL_MSIC_ADC1SNS0H	/* increments by 2 */
 
 /* MSIC die attributes */
 #define MSIC_DIE_ADC_MIN	488
@@ -189,17 +186,17 @@
 	addr = td_info->chnl_addr;
 
 	/* Enable the msic for conversion before reading */
-	ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCRRDATA_ENBL);
+	ret = intel_msic_reg_write(INTEL_MSIC_ADC1CNTL3, MSIC_ADCRRDATA_ENBL);
 	if (ret)
 		return ret;
 
 	/* Re-toggle the RRDATARD bit (temporary workaround) */
-	ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCTHERM_ENBL);
+	ret = intel_msic_reg_write(INTEL_MSIC_ADC1CNTL3, MSIC_ADCTHERM_ENBL);
 	if (ret)
 		return ret;
 
 	/* Read the higher bits of data */
-	ret = intel_scu_ipc_ioread8(addr, &data);
+	ret = intel_msic_reg_read(addr, &data);
 	if (ret)
 		return ret;
 
@@ -207,7 +204,7 @@
 	adc_val = (data << 2);
 	addr++;
 
-	ret = intel_scu_ipc_ioread8(addr, &data);/* Read lower bits */
+	ret = intel_msic_reg_read(addr, &data);/* Read lower bits */
 	if (ret)
 		return ret;
 
@@ -235,7 +232,7 @@
 	int ret;
 	uint8_t data;
 
-	ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data);
+	ret = intel_msic_reg_read(INTEL_MSIC_ADC1CNTL1, &data);
 	if (ret)
 		return ret;
 
@@ -246,7 +243,7 @@
 		/* Just stop the ADC */
 		data &= (~MSIC_ADC_START);
 	}
-	return intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL1, data);
+	return intel_msic_reg_write(INTEL_MSIC_ADC1CNTL1, data);
 }
 
 /**
@@ -262,21 +259,21 @@
 	int ret;
 
 	/* Enable all the sensor channels */
-	ret = intel_scu_ipc_iowrite8(base_addr, SKIN_SENSOR0_CODE);
+	ret = intel_msic_reg_write(base_addr, SKIN_SENSOR0_CODE);
 	if (ret)
 		return ret;
 
-	ret = intel_scu_ipc_iowrite8(base_addr + 1, SKIN_SENSOR1_CODE);
+	ret = intel_msic_reg_write(base_addr + 1, SKIN_SENSOR1_CODE);
 	if (ret)
 		return ret;
 
-	ret = intel_scu_ipc_iowrite8(base_addr + 2, SYS_SENSOR_CODE);
+	ret = intel_msic_reg_write(base_addr + 2, SYS_SENSOR_CODE);
 	if (ret)
 		return ret;
 
 	/* Since this is the last channel, set the stop bit
 	 * to 1 by ORing the DIE_SENSOR_CODE with 0x10 */
-	ret = intel_scu_ipc_iowrite8(base_addr + 3,
+	ret = intel_msic_reg_write(base_addr + 3,
 			(MSIC_DIE_SENSOR_CODE | 0x10));
 	if (ret)
 		return ret;
@@ -295,11 +292,11 @@
 {
 	int ret;
 	uint8_t data;
-	ret = intel_scu_ipc_ioread8(addr, &data);
+	ret = intel_msic_reg_read(addr, &data);
 	if (ret)
 		return ret;
 	/* Set the stop bit to zero */
-	return intel_scu_ipc_iowrite8(addr, (data & 0xEF));
+	return intel_msic_reg_write(addr, (data & 0xEF));
 }
 
 /**
@@ -322,7 +319,7 @@
 	uint8_t data;
 
 	/* check whether ADC is enabled */
-	ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data);
+	ret = intel_msic_reg_read(INTEL_MSIC_ADC1CNTL1, &data);
 	if (ret)
 		return ret;
 
@@ -331,7 +328,7 @@
 
 	/* ADC is already enabled; Looking for an empty channel */
 	for (i = 0; i < ADC_CHANLS_MAX; i++) {
-		ret = intel_scu_ipc_ioread8(ADC_CHNL_START_ADDR + i, &data);
+		ret = intel_msic_reg_read(ADC_CHNL_START_ADDR + i, &data);
 		if (ret)
 			return ret;
 
@@ -359,12 +356,14 @@
 	 * Ensure that adctherm is disabled before we
 	 * initialize the ADC
 	 */
-	ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL3, &data);
+	ret = intel_msic_reg_read(INTEL_MSIC_ADC1CNTL3, &data);
 	if (ret)
 		return ret;
 
-	if (data & MSIC_ADCTHERM_MASK)
-		dev_warn(dev, "ADCTHERM already set");
+	data &= ~MSIC_ADCTHERM_MASK;
+	ret = intel_msic_reg_write(INTEL_MSIC_ADC1CNTL3, data);
+	if (ret)
+		return ret;
 
 	/* Index of the first channel in which the stop bit is set */
 	channel_index = find_free_channel();
@@ -546,10 +545,11 @@
 	return configure_adc(0);
 }
 
-#define DRIVER_NAME "msic_sensor"
+#define DRIVER_NAME "msic_thermal"
 
 static const struct platform_device_id therm_id_table[] = {
 	{ DRIVER_NAME, 1 },
+	{ "msic_thermal", 1 },
 	{ }
 };
 
@@ -565,18 +565,7 @@
 	.id_table = therm_id_table,
 };
 
-static int __init mid_thermal_module_init(void)
-{
-	return platform_driver_register(&mid_thermal_driver);
-}
-
-static void __exit mid_thermal_module_exit(void)
-{
-	platform_driver_unregister(&mid_thermal_driver);
-}
-
-module_init(mid_thermal_module_init);
-module_exit(mid_thermal_module_exit);
+module_platform_driver(mid_thermal_driver);
 
 MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>");
 MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver");
diff --git a/drivers/platform/x86/intel_oaktrail.c b/drivers/platform/x86/intel_oaktrail.c
index 6ee0b5c..79a0c2f 100644
--- a/drivers/platform/x86/intel_oaktrail.c
+++ b/drivers/platform/x86/intel_oaktrail.c
@@ -313,6 +313,7 @@
 	},
 	{ }
 };
+MODULE_DEVICE_TABLE(dmi, oaktrail_dmi_table);
 
 static int __init oaktrail_init(void)
 {
@@ -394,4 +395,3 @@
 MODULE_DESCRIPTION("Intel Oaktrail Platform ACPI Extras");
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("dmi:*:svnIntelCorporation:pnOakTrailplatform:*");
diff --git a/drivers/platform/x86/intel_rar_register.c b/drivers/platform/x86/intel_rar_register.c
deleted file mode 100644
index c8a6aed..0000000
--- a/drivers/platform/x86/intel_rar_register.c
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- *  rar_register.c - An Intel Restricted Access Region register driver
- *
- *  Copyright(c) 2009 Intel Corporation. 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.
- *
- * -------------------------------------------------------------------
- *  20091204 Mark Allyn <mark.a.allyn@intel.com>
- *	     Ossama Othman <ossama.othman@intel.com>
- *	Cleanup per feedback from Alan Cox and Arjan Van De Ven
- *
- *  20090806 Ossama Othman <ossama.othman@intel.com>
- *      Return zero high address if upper 22 bits is zero.
- *      Cleaned up checkpatch errors.
- *      Clarified that driver is dealing with bus addresses.
- *
- *  20090702 Ossama Othman <ossama.othman@intel.com>
- *      Removed unnecessary include directives
- *      Cleaned up spinlocks.
- *      Cleaned up logging.
- *      Improved invalid parameter checks.
- *      Fixed and simplified RAR address retrieval and RAR locking
- *      code.
- *
- *  20090626 Mark Allyn <mark.a.allyn@intel.com>
- *      Initial publish
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/spinlock.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/rar_register.h>
-
-/* === Lincroft Message Bus Interface === */
-#define LNC_MCR_OFFSET		0xD0	/* Message Control Register */
-#define LNC_MDR_OFFSET		0xD4	/* Message Data Register */
-
-/* Message Opcodes */
-#define LNC_MESSAGE_READ_OPCODE	0xD0
-#define LNC_MESSAGE_WRITE_OPCODE 0xE0
-
-/* Message Write Byte Enables */
-#define LNC_MESSAGE_BYTE_WRITE_ENABLES	0xF
-
-/* B-unit Port */
-#define LNC_BUNIT_PORT	0x3
-
-/* === Lincroft B-Unit Registers - Programmed by IA32 firmware === */
-#define LNC_BRAR0L	0x10
-#define LNC_BRAR0H	0x11
-#define LNC_BRAR1L	0x12
-#define LNC_BRAR1H	0x13
-/* Reserved for SeP */
-#define LNC_BRAR2L	0x14
-#define LNC_BRAR2H	0x15
-
-/* Moorestown supports three restricted access regions. */
-#define MRST_NUM_RAR 3
-
-/* RAR Bus Address Range */
-struct rar_addr {
-	dma_addr_t low;
-	dma_addr_t high;
-};
-
-/*
- *	We create one of these for each RAR
- */
-struct client {
-	int (*callback)(unsigned long data);
-	unsigned long driver_priv;
-	bool busy;
-};
-
-static DEFINE_MUTEX(rar_mutex);
-static DEFINE_MUTEX(lnc_reg_mutex);
-
-/*
- *	One per RAR device (currently only one device)
- */
-struct rar_device {
-	struct rar_addr rar_addr[MRST_NUM_RAR];
-	struct pci_dev *rar_dev;
-	bool registered;
-	bool allocated;
-	struct client client[MRST_NUM_RAR];
-};
-
-/* Current platforms have only one rar_device for 3 rar regions */
-static struct rar_device my_rar_device;
-
-/*
- *	Abstract out multiple device support. Current platforms only
- *	have a single RAR device.
- */
-
-/**
- *	alloc_rar_device	-	return a new RAR structure
- *
- *	Return a new (but not yet ready) RAR device object
- */
-static struct rar_device *alloc_rar_device(void)
-{
-	if (my_rar_device.allocated)
-		return NULL;
-	my_rar_device.allocated = 1;
-	return &my_rar_device;
-}
-
-/**
- *	free_rar_device		-	free a RAR object
- *	@rar: the RAR device being freed
- *
- *	Release a RAR object and any attached resources
- */
-static void free_rar_device(struct rar_device *rar)
-{
-	pci_dev_put(rar->rar_dev);
-	rar->allocated = 0;
-}
-
-/**
- *	_rar_to_device		-	return the device handling this RAR
- *	@rar: RAR number
- *	@off: returned offset
- *
- *	Internal helper for looking up RAR devices. This and alloc are the
- *	two functions that need touching to go to multiple RAR devices.
- */
-static struct rar_device *_rar_to_device(int rar, int *off)
-{
-	if (rar >= 0 && rar < MRST_NUM_RAR) {
-		*off = rar;
-		return &my_rar_device;
-	}
-	return NULL;
-}
-
-/**
- *	rar_to_device		-	return the device handling this RAR
- *	@rar: RAR number
- *	@off: returned offset
- *
- *	Return the device this RAR maps to if one is present, otherwise
- *	returns NULL. Reports the offset relative to the base of this
- *	RAR device in off.
- */
-static struct rar_device *rar_to_device(int rar, int *off)
-{
-	struct rar_device *rar_dev = _rar_to_device(rar, off);
-	if (rar_dev == NULL || !rar_dev->registered)
-		return NULL;
-	return rar_dev;
-}
-
-/**
- *	rar_to_client		-	return the client handling this RAR
- *	@rar: RAR number
- *
- *	Return the client this RAR maps to if a mapping is known, otherwise
- *	returns NULL.
- */
-static struct client *rar_to_client(int rar)
-{
-	int idx;
-	struct rar_device *r = _rar_to_device(rar, &idx);
-	if (r != NULL)
-		return &r->client[idx];
-	return NULL;
-}
-
-/**
- *	rar_read_addr		-	retrieve a RAR mapping
- *	@pdev: PCI device for the RAR
- *	@offset: offset for message
- *	@addr: returned address
- *
- *	Reads the address of a given RAR register. Returns 0 on success
- *	or an error code on failure.
- */
-static int rar_read_addr(struct pci_dev *pdev, int offset, dma_addr_t *addr)
-{
-	/*
-	 * ======== The Lincroft Message Bus Interface ========
-	 * Lincroft registers may be obtained via PCI from
-	 * the host bridge using the Lincroft Message Bus
-	 * Interface.  That message bus interface is generally
-	 * comprised of two registers: a control register (MCR, 0xDO)
-	 * and a data register (MDR, 0xD4).
-	 *
-	 * The MCR (message control register) format is the following:
-	 *   1.  [31:24]: Opcode
-	 *   2.  [23:16]: Port
-	 *   3.  [15:8]: Register Offset
-	 *   4.  [7:4]: Byte Enables (use 0xF to set all of these bits
-	 *              to 1)
-	 *   5.  [3:0]: reserved
-	 *
-	 *  Read (0xD0) and write (0xE0) opcodes are written to the
-	 *  control register when reading and writing to Lincroft
-	 *  registers, respectively.
-	 *
-	 *  We're interested in registers found in the Lincroft
-	 *  B-unit.  The B-unit port is 0x3.
-	 *
-	 *  The six B-unit RAR register offsets we use are listed
-	 *  earlier in this file.
-	 *
-	 *  Lastly writing to the MCR register requires the "Byte
-	 *  enables" bits to be set to 1.  This may be achieved by
-	 *  writing 0xF at bit 4.
-	 *
-	 * The MDR (message data register) format is the following:
-	 *   1. [31:0]: Read/Write Data
-	 *
-	 *  Data being read from this register is only available after
-	 *  writing the appropriate control message to the MCR
-	 *  register.
-	 *
-	 *  Data being written to this register must be written before
-	 *  writing the appropriate control message to the MCR
-	 *  register.
-	*/
-
-	int result;
-	u32 addr32;
-
-	/* Construct control message */
-	u32 const message =
-		 (LNC_MESSAGE_READ_OPCODE << 24)
-		 | (LNC_BUNIT_PORT << 16)
-		 | (offset << 8)
-		 | (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);
-
-	dev_dbg(&pdev->dev, "Offset for 'get' LNC MSG is %x\n", offset);
-
-	/*
-	* We synchronize access to the Lincroft MCR and MDR registers
-	* until BOTH the command is issued through the MCR register
-	* and the corresponding data is read from the MDR register.
-	* Otherwise a race condition would exist between accesses to
-	* both registers.
-	*/
-
-	mutex_lock(&lnc_reg_mutex);
-
-	/* Send the control message */
-	result = pci_write_config_dword(pdev, LNC_MCR_OFFSET, message);
-	if (!result) {
-		/* Read back the address as a 32bit value */
-		result = pci_read_config_dword(pdev, LNC_MDR_OFFSET, &addr32);
-		*addr = (dma_addr_t)addr32;
-	}
-	mutex_unlock(&lnc_reg_mutex);
-	return result;
-}
-
-/**
- *	rar_set_addr		-	Set a RAR mapping
- *	@pdev: PCI device for the RAR
- *	@offset: offset for message
- *	@addr: address to set
- *
- *	Sets the address of a given RAR register. Returns 0 on success
- *	or an error code on failure.
- */
-static int rar_set_addr(struct pci_dev *pdev,
-	int offset,
-	dma_addr_t addr)
-{
-	/*
-	* Data being written to this register must be written before
-	* writing the appropriate control message to the MCR
-	* register.
-	* See rar_get_addrs() for a description of the
-	* message bus interface being used here.
-	*/
-
-	int result;
-
-	/* Construct control message */
-	u32 const message = (LNC_MESSAGE_WRITE_OPCODE << 24)
-		| (LNC_BUNIT_PORT << 16)
-		| (offset << 8)
-		| (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);
-
-	/*
-	* We synchronize access to the Lincroft MCR and MDR registers
-	* until BOTH the command is issued through the MCR register
-	* and the corresponding data is read from the MDR register.
-	* Otherwise a race condition would exist between accesses to
-	* both registers.
-	*/
-
-	mutex_lock(&lnc_reg_mutex);
-
-	/* Send the control message */
-	result = pci_write_config_dword(pdev, LNC_MDR_OFFSET, addr);
-	if (!result)
-		/* And address */
-		result = pci_write_config_dword(pdev, LNC_MCR_OFFSET, message);
-
-	mutex_unlock(&lnc_reg_mutex);
-	return result;
-}
-
-/*
- *	rar_init_params		-	Initialize RAR parameters
- *	@rar: RAR device to initialise
- *
- *	Initialize RAR parameters, such as bus addresses, etc. Returns 0
- *	on success, or an error code on failure.
- */
-static int init_rar_params(struct rar_device *rar)
-{
-	struct pci_dev *pdev = rar->rar_dev;
-	unsigned int i;
-	int result = 0;
-	int offset = 0x10;	/* RAR 0 to 2 in order low/high/low/high/... */
-
-	/* Retrieve RAR start and end bus addresses.
-	* Access the RAR registers through the Lincroft Message Bus
-	* Interface on PCI device: 00:00.0 Host bridge.
-	*/
-
-	for (i = 0; i < MRST_NUM_RAR; ++i) {
-		struct rar_addr *addr = &rar->rar_addr[i];
-
-		result = rar_read_addr(pdev, offset++, &addr->low);
-		if (result != 0)
-			return result;
-
-		result = rar_read_addr(pdev, offset++, &addr->high);
-		if (result != 0)
-			return result;
-
-
-		/*
-		* Only the upper 22 bits of the RAR addresses are
-		* stored in their corresponding RAR registers so we
-		* must set the lower 10 bits accordingly.
-
-		* The low address has its lower 10 bits cleared, and
-		* the high address has all its lower 10 bits set,
-		* e.g.:
-		* low = 0x2ffffc00
-		*/
-
-		addr->low &= (dma_addr_t)0xfffffc00u;
-
-		/*
-		* Set bits 9:0 on uppser address if bits 31:10 are non
-		* zero; otherwize clear all bits
-		*/
-
-		if ((addr->high & 0xfffffc00u) == 0)
-			addr->high = 0;
-		else
-			addr->high |= 0x3ffu;
-	}
-	/* Done accessing the device. */
-
-	if (result == 0) {
-		for (i = 0; i != MRST_NUM_RAR; ++i) {
-			/*
-			* "BRAR" refers to the RAR registers in the
-			* Lincroft B-unit.
-			*/
-			dev_info(&pdev->dev, "BRAR[%u] bus address range = "
-			  "[%lx, %lx]\n", i,
-			  (unsigned long)rar->rar_addr[i].low,
-			  (unsigned long)rar->rar_addr[i].high);
-		}
-	}
-	return result;
-}
-
-/**
- *	rar_get_address		-	get the bus address in a RAR
- *	@start: return value of start address of block
- *	@end: return value of end address of block
- *
- *	The rar_get_address function is used by other device drivers
- *	to obtain RAR address information on a RAR. It takes three
- *	parameters:
- *
- *	The function returns a 0 upon success or an error if there is no RAR
- *	facility on this system.
- */
-int rar_get_address(int rar_index, dma_addr_t *start, dma_addr_t *end)
-{
-	int idx;
-	struct rar_device *rar = rar_to_device(rar_index, &idx);
-
-	if (rar == NULL) {
-		WARN_ON(1);
-		return -ENODEV;
-	}
-
-	*start = rar->rar_addr[idx].low;
-	*end = rar->rar_addr[idx].high;
-	return 0;
-}
-EXPORT_SYMBOL(rar_get_address);
-
-/**
- *	rar_lock	-	lock a RAR register
- *	@rar_index: RAR to lock (0-2)
- *
- *	The rar_lock function is ued by other device drivers to lock an RAR.
- *	once a RAR is locked, it stays locked until the next system reboot.
- *
- *	The function returns a 0 upon success or an error if there is no RAR
- *	facility on this system, or the locking fails
- */
-int rar_lock(int rar_index)
-{
-	struct rar_device *rar;
-	int result;
-	int idx;
-	dma_addr_t low, high;
-
-	rar = rar_to_device(rar_index, &idx);
-
-	if (rar == NULL) {
-		WARN_ON(1);
-		return -EINVAL;
-	}
-
-	low = rar->rar_addr[idx].low & 0xfffffc00u;
-	high = rar->rar_addr[idx].high & 0xfffffc00u;
-
-	/*
-	* Only allow I/O from the graphics and Langwell;
-	* not from the x86 processor
-	*/
-
-	if (rar_index == RAR_TYPE_VIDEO) {
-		low |= 0x00000009;
-		high |= 0x00000015;
-	} else if (rar_index == RAR_TYPE_AUDIO) {
-		/* Only allow I/O from Langwell; nothing from x86 */
-		low |= 0x00000008;
-		high |= 0x00000018;
-	} else
-		/* Read-only from all agents */
-		high |= 0x00000018;
-
-	/*
-	* Now program the register using the Lincroft message
-	* bus interface.
-	*/
-	result = rar_set_addr(rar->rar_dev,
-				2 * idx, low);
-
-	if (result == 0)
-		result = rar_set_addr(rar->rar_dev,
-				2 * idx + 1, high);
-
-	return result;
-}
-EXPORT_SYMBOL(rar_lock);
-
-/**
- *	register_rar		-	register a RAR handler
- *	@num: RAR we wish to register for
- *	@callback: function to call when RAR support is available
- *	@data: data to pass to this function
- *
- *	The register_rar function is to used by other device drivers
- *	to ensure that this driver is ready. As we cannot be sure of
- *	the compile/execute order of drivers in the kernel, it is
- *	best to give this driver a callback function to call when
- *	it is ready to give out addresses. The callback function
- *	would have those steps that continue the initialization of
- *	a driver that do require a valid RAR address. One of those
- *	steps would be to call rar_get_address()
- *
- *	This function return 0 on success or an error code on failure.
- */
-int register_rar(int num, int (*callback)(unsigned long data),
-							unsigned long data)
-{
-	/* For now we hardcode a single RAR device */
-	struct rar_device *rar;
-	struct client *c;
-	int idx;
-	int retval = 0;
-
-	mutex_lock(&rar_mutex);
-
-	/* Do we have a client mapping for this RAR number ? */
-	c = rar_to_client(num);
-	if (c == NULL) {
-		retval = -ERANGE;
-		goto done;
-	}
-	/* Is it claimed ? */
-	if (c->busy) {
-		retval = -EBUSY;
-		goto done;
-	}
-	c->busy = 1;
-
-	/* See if we have a handler for this RAR yet, if we do then fire it */
-	rar = rar_to_device(num, &idx);
-
-	if (rar) {
-		/*
-		* if the driver already registered, then we can simply
-		* call the callback right now
-		*/
-		(*callback)(data);
-		goto done;
-	}
-
-	/* Arrange to be called back when the hardware is found */
-	c->callback = callback;
-	c->driver_priv = data;
-done:
-	mutex_unlock(&rar_mutex);
-	return retval;
-}
-EXPORT_SYMBOL(register_rar);
-
-/**
- *	unregister_rar	-	release a RAR allocation
- *	@num: RAR number
- *
- *	Releases a RAR allocation, or pending allocation. If a callback is
- *	pending then this function will either complete before the unregister
- *	returns or not at all.
- */
-
-void unregister_rar(int num)
-{
-	struct client *c;
-
-	mutex_lock(&rar_mutex);
-	c = rar_to_client(num);
-	if (c == NULL || !c->busy)
-		WARN_ON(1);
-	else
-		c->busy = 0;
-	mutex_unlock(&rar_mutex);
-}
-EXPORT_SYMBOL(unregister_rar);
-
-/**
- *	rar_callback		-	Process callbacks
- *	@rar: new RAR device
- *
- *	Process the callbacks for a newly found RAR device.
- */
-
-static void rar_callback(struct rar_device *rar)
-{
-	struct client *c = &rar->client[0];
-	int i;
-
-	mutex_lock(&rar_mutex);
-
-	rar->registered = 1;	/* Ensure no more callbacks queue */
-
-	for (i = 0; i < MRST_NUM_RAR; i++) {
-		if (c->callback && c->busy) {
-			c->callback(c->driver_priv);
-			c->callback = NULL;
-		}
-		c++;
-	}
-	mutex_unlock(&rar_mutex);
-}
-
-/**
- *	rar_probe		-	PCI probe callback
- *	@dev: PCI device
- *	@id: matching entry in the match table
- *
- *	A RAR device has been discovered. Initialise it and if successful
- *	process any pending callbacks that can now be completed.
- */
-static int rar_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
-	int error;
-	struct rar_device *rar;
-
-	dev_dbg(&dev->dev, "PCI probe starting\n");
-
-	rar = alloc_rar_device();
-	if (rar == NULL)
-		return -EBUSY;
-
-	/* Enable the device */
-	error = pci_enable_device(dev);
-	if (error) {
-		dev_err(&dev->dev,
-			"Error enabling RAR register PCI device\n");
-		goto end_function;
-	}
-
-	/* Fill in the rar_device structure */
-	rar->rar_dev = pci_dev_get(dev);
-	pci_set_drvdata(dev, rar);
-
-	/*
-	 * Initialize the RAR parameters, which have to be retrieved
-	 * via the message bus interface.
-	 */
-	error = init_rar_params(rar);
-	if (error) {
-		pci_disable_device(dev);
-		dev_err(&dev->dev, "Error retrieving RAR addresses\n");
-		goto end_function;
-	}
-	/* now call anyone who has registered (using callbacks) */
-	rar_callback(rar);
-	return 0;
-end_function:
-	free_rar_device(rar);
-	return error;
-}
-
-static DEFINE_PCI_DEVICE_TABLE(rar_pci_id_tbl) = {
-	{ PCI_VDEVICE(INTEL, 0x4110) },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl);
-
-/* field for registering driver to PCI device */
-static struct pci_driver rar_pci_driver = {
-	.name = "rar_register_driver",
-	.id_table = rar_pci_id_tbl,
-	.probe = rar_probe,
-	/* Cannot be unplugged - no remove */
-};
-
-static int __init rar_init_handler(void)
-{
-	return pci_register_driver(&rar_pci_driver);
-}
-
-static void __exit rar_exit_handler(void)
-{
-	pci_unregister_driver(&rar_pci_driver);
-}
-
-module_init(rar_init_handler);
-module_exit(rar_exit_handler);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Intel Restricted Access Region Register Driver");
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index f00d0d1..9215ed7 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -159,7 +159,7 @@
 /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
 static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
 {
-	int i, nc, bytes, d;
+	int nc;
 	u32 offset = 0;
 	int err;
 	u8 cbuf[IPC_WWBUF_SIZE] = { };
@@ -174,55 +174,34 @@
 		return -ENODEV;
 	}
 
-	if (platform != MRST_CPU_CHIP_PENWELL) {
-		bytes = 0;
-		d = 0;
-		for (i = 0; i < count; i++) {
-			cbuf[bytes++] = addr[i];
-			cbuf[bytes++] = addr[i] >> 8;
-			if (id != IPC_CMD_PCNTRL_R)
-				cbuf[bytes++] = data[d++];
-			if (id == IPC_CMD_PCNTRL_M)
-				cbuf[bytes++] = data[d++];
-		}
-		for (i = 0; i < bytes; i += 4)
-			ipc_data_writel(wbuf[i/4], i);
-		ipc_command(bytes << 16 |  id << 12 | 0 << 8 | op);
-	} else {
-		for (nc = 0; nc < count; nc++, offset += 2) {
-			cbuf[offset] = addr[nc];
-			cbuf[offset + 1] = addr[nc] >> 8;
-		}
+	for (nc = 0; nc < count; nc++, offset += 2) {
+		cbuf[offset] = addr[nc];
+		cbuf[offset + 1] = addr[nc] >> 8;
+	}
 
-		if (id == IPC_CMD_PCNTRL_R) {
-			for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
-				ipc_data_writel(wbuf[nc], offset);
-			ipc_command((count*2) << 16 |  id << 12 | 0 << 8 | op);
-		} else if (id == IPC_CMD_PCNTRL_W) {
-			for (nc = 0; nc < count; nc++, offset += 1)
-				cbuf[offset] = data[nc];
-			for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
-				ipc_data_writel(wbuf[nc], offset);
-			ipc_command((count*3) << 16 |  id << 12 | 0 << 8 | op);
-		} else if (id == IPC_CMD_PCNTRL_M) {
-			cbuf[offset] = data[0];
-			cbuf[offset + 1] = data[1];
-			ipc_data_writel(wbuf[0], 0); /* Write wbuff */
-			ipc_command(4 << 16 |  id << 12 | 0 << 8 | op);
-		}
+	if (id == IPC_CMD_PCNTRL_R) {
+		for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
+			ipc_data_writel(wbuf[nc], offset);
+		ipc_command((count*2) << 16 |  id << 12 | 0 << 8 | op);
+	} else if (id == IPC_CMD_PCNTRL_W) {
+		for (nc = 0; nc < count; nc++, offset += 1)
+			cbuf[offset] = data[nc];
+		for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
+			ipc_data_writel(wbuf[nc], offset);
+		ipc_command((count*3) << 16 |  id << 12 | 0 << 8 | op);
+	} else if (id == IPC_CMD_PCNTRL_M) {
+		cbuf[offset] = data[0];
+		cbuf[offset + 1] = data[1];
+		ipc_data_writel(wbuf[0], 0); /* Write wbuff */
+		ipc_command(4 << 16 |  id << 12 | 0 << 8 | op);
 	}
 
 	err = busy_loop();
 	if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */
 		/* Workaround: values are read as 0 without memcpy_fromio */
 		memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16);
-		if (platform != MRST_CPU_CHIP_PENWELL) {
-			for (nc = 0, offset = 2; nc < count; nc++, offset += 3)
-				data[nc] = ipc_data_readb(offset);
-		} else {
-			for (nc = 0; nc < count; nc++)
-				data[nc] = ipc_data_readb(nc);
-		}
+		for (nc = 0; nc < count; nc++)
+			data[nc] = ipc_data_readb(nc);
 	}
 	mutex_unlock(&ipclock);
 	return err;
@@ -503,148 +482,6 @@
 }
 EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl);
 
-#define IPC_FW_LOAD_ADDR 0xFFFC0000 /* Storage location for FW image */
-#define IPC_FW_UPDATE_MBOX_ADDR 0xFFFFDFF4 /* Mailbox between ipc and scu */
-#define IPC_MAX_FW_SIZE 262144 /* 256K storage size for loading the FW image */
-#define IPC_FW_MIP_HEADER_SIZE 2048 /* Firmware MIP header size */
-/* IPC inform SCU to get ready for update process */
-#define IPC_CMD_FW_UPDATE_READY  0x10FE
-/* IPC inform SCU to go for update process */
-#define IPC_CMD_FW_UPDATE_GO     0x20FE
-/* Status code for fw update */
-#define IPC_FW_UPDATE_SUCCESS	0x444f4e45 /* Status code 'DONE' */
-#define IPC_FW_UPDATE_BADN	0x4241444E /* Status code 'BADN' */
-#define IPC_FW_TXHIGH		0x54784849 /* Status code 'IPC_FW_TXHIGH' */
-#define IPC_FW_TXLOW		0x54784c4f /* Status code 'IPC_FW_TXLOW' */
-
-struct fw_update_mailbox {
-	u32    status;
-	u32    scu_flag;
-	u32    driver_flag;
-};
-
-
-/**
- *	intel_scu_ipc_fw_update	-	 Firmware update utility
- *	@buffer: firmware buffer
- *	@length: size of firmware buffer
- *
- *	This function provides an interface to load the firmware into
- *	the SCU. Returns 0 on success or -1 on failure
- */
-int intel_scu_ipc_fw_update(u8 *buffer, u32 length)
-{
-	void __iomem *fw_update_base;
-	struct fw_update_mailbox __iomem *mailbox = NULL;
-	int retry_cnt = 0;
-	u32 status;
-
-	mutex_lock(&ipclock);
-	fw_update_base = ioremap_nocache(IPC_FW_LOAD_ADDR, (128*1024));
-	if (fw_update_base == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENOMEM;
-	}
-	mailbox = ioremap_nocache(IPC_FW_UPDATE_MBOX_ADDR,
-					sizeof(struct fw_update_mailbox));
-	if (mailbox == NULL) {
-		iounmap(fw_update_base);
-		mutex_unlock(&ipclock);
-		return -ENOMEM;
-	}
-
-	ipc_command(IPC_CMD_FW_UPDATE_READY);
-
-	/* Intitialize mailbox */
-	writel(0, &mailbox->status);
-	writel(0, &mailbox->scu_flag);
-	writel(0, &mailbox->driver_flag);
-
-	/* Driver copies the 2KB MIP header to SRAM at 0xFFFC0000*/
-	memcpy_toio(fw_update_base, buffer, 0x800);
-
-	/* Driver sends "FW Update" IPC command (CMD_ID 0xFE; MSG_ID 0x02).
-	* Upon receiving this command, SCU will write the 2K MIP header
-	* from 0xFFFC0000 into NAND.
-	* SCU will write a status code into the Mailbox, and then set scu_flag.
-	*/
-
-	ipc_command(IPC_CMD_FW_UPDATE_GO);
-
-	/*Driver stalls until scu_flag is set */
-	while (readl(&mailbox->scu_flag) != 1) {
-		rmb();
-		mdelay(1);
-	}
-
-	/* Driver checks Mailbox status.
-	 * If the status is 'BADN', then abort (bad NAND).
-	 * If the status is 'IPC_FW_TXLOW', then continue.
-	 */
-	while (readl(&mailbox->status) != IPC_FW_TXLOW) {
-		rmb();
-		mdelay(10);
-	}
-	mdelay(10);
-
-update_retry:
-	if (retry_cnt > 5)
-		goto update_end;
-
-	if (readl(&mailbox->status) != IPC_FW_TXLOW)
-		goto update_end;
-	buffer = buffer + 0x800;
-	memcpy_toio(fw_update_base, buffer, 0x20000);
-	writel(1, &mailbox->driver_flag);
-	while (readl(&mailbox->scu_flag) == 1) {
-		rmb();
-		mdelay(1);
-	}
-
-	/* check for 'BADN' */
-	if (readl(&mailbox->status) == IPC_FW_UPDATE_BADN)
-		goto update_end;
-
-	while (readl(&mailbox->status) != IPC_FW_TXHIGH) {
-		rmb();
-		mdelay(10);
-	}
-	mdelay(10);
-
-	if (readl(&mailbox->status) != IPC_FW_TXHIGH)
-		goto update_end;
-
-	buffer = buffer + 0x20000;
-	memcpy_toio(fw_update_base, buffer, 0x20000);
-	writel(0, &mailbox->driver_flag);
-
-	while (mailbox->scu_flag == 0) {
-		rmb();
-		mdelay(1);
-	}
-
-	/* check for 'BADN' */
-	if (readl(&mailbox->status) == IPC_FW_UPDATE_BADN)
-		goto update_end;
-
-	if (readl(&mailbox->status) == IPC_FW_TXLOW) {
-		++retry_cnt;
-		goto update_retry;
-	}
-
-update_end:
-	status = readl(&mailbox->status);
-
-	iounmap(fw_update_base);
-	iounmap(mailbox);
-	mutex_unlock(&ipclock);
-
-	if (status == IPC_FW_UPDATE_SUCCESS)
-		return 0;
-	return -EIO;
-}
-EXPORT_SYMBOL(intel_scu_ipc_fw_update);
-
 /*
  * Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1
  * When ioc bit is set to 1, caller api must wait for interrupt handler called
@@ -727,7 +564,6 @@
 }
 
 static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
-	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)},
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)},
 	{ 0,}
 };
diff --git a/drivers/platform/x86/intel_scu_ipcutil.c b/drivers/platform/x86/intel_scu_ipcutil.c
index 2d0f913..02bc5a6 100644
--- a/drivers/platform/x86/intel_scu_ipcutil.c
+++ b/drivers/platform/x86/intel_scu_ipcutil.c
@@ -26,13 +26,10 @@
 
 static int major;
 
-#define MAX_FW_SIZE 264192
-
 /* ioctl commnds */
 #define	INTE_SCU_IPC_REGISTER_READ	0
 #define INTE_SCU_IPC_REGISTER_WRITE	1
 #define INTE_SCU_IPC_REGISTER_UPDATE	2
-#define INTE_SCU_IPC_FW_UPDATE		0xA2
 
 struct scu_ipc_data {
 	u32     count;  /* No. of registers */
@@ -88,27 +85,14 @@
 	if (!capable(CAP_SYS_RAWIO))
 		return -EPERM;
 
-	if (cmd == INTE_SCU_IPC_FW_UPDATE) {
-			u8 *fwbuf = kmalloc(MAX_FW_SIZE, GFP_KERNEL);
-			if (fwbuf == NULL)
-				return -ENOMEM;
-			if (copy_from_user(fwbuf, (u8 *)arg, MAX_FW_SIZE)) {
-				kfree(fwbuf);
-				return -EFAULT;
-			}
-			ret = intel_scu_ipc_fw_update(fwbuf, MAX_FW_SIZE);
-			kfree(fwbuf);
-			return ret;
-	} else {
-		if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data)))
-			return -EFAULT;
-		ret = scu_reg_access(cmd, &data);
-		if (ret < 0)
-			return ret;
-		if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data)))
-			return -EFAULT;
-		return 0;
-	}
+	if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data)))
+		return -EFAULT;
+	ret = scu_reg_access(cmd, &data);
+	if (ret < 0)
+		return ret;
+	if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data)))
+		return -EFAULT;
+	return 0;
 }
 
 static const struct file_operations scu_ipc_fops = {
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
index fd73ea8..e2a34b4 100644
--- a/drivers/platform/x86/samsung-laptop.c
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -17,10 +17,18 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/backlight.h>
+#include <linux/leds.h>
 #include <linux/fb.h>
 #include <linux/dmi.h>
 #include <linux/platform_device.h>
 #include <linux/rfkill.h>
+#include <linux/acpi.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/ctype.h>
+#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
+#include <acpi/video.h>
+#endif
 
 /*
  * This driver is needed because a number of Samsung laptops do not hook
@@ -41,9 +49,20 @@
 #define SABI_IFACE_COMPLETE		0x04
 #define SABI_IFACE_DATA			0x05
 
-/* Structure to get data back to the calling function */
-struct sabi_retval {
-	u8 retval[20];
+#define WL_STATUS_WLAN			0x0
+#define WL_STATUS_BT			0x2
+
+/* Structure get/set data using sabi */
+struct sabi_data {
+	union {
+		struct {
+			u32 d0;
+			u32 d1;
+			u16 d2;
+			u8  d3;
+		};
+		u8 data[11];
+	};
 };
 
 struct sabi_header_offsets {
@@ -60,8 +79,8 @@
 	 * Brightness is 0 - 8, as described above.
 	 * Value 0 is for the BIOS to use
 	 */
-	u8 get_brightness;
-	u8 set_brightness;
+	u16 get_brightness;
+	u16 set_brightness;
 
 	/*
 	 * first byte:
@@ -72,40 +91,56 @@
 	 * 0x03 - 3G is on
 	 * TODO, verify 3G is correct, that doesn't seem right...
 	 */
-	u8 get_wireless_button;
-	u8 set_wireless_button;
+	u16 get_wireless_button;
+	u16 set_wireless_button;
 
 	/* 0 is off, 1 is on */
-	u8 get_backlight;
-	u8 set_backlight;
+	u16 get_backlight;
+	u16 set_backlight;
 
 	/*
 	 * 0x80 or 0x00 - no action
 	 * 0x81 - recovery key pressed
 	 */
-	u8 get_recovery_mode;
-	u8 set_recovery_mode;
+	u16 get_recovery_mode;
+	u16 set_recovery_mode;
 
 	/*
 	 * on seclinux: 0 is low, 1 is high,
 	 * on swsmi: 0 is normal, 1 is silent, 2 is turbo
 	 */
-	u8 get_performance_level;
-	u8 set_performance_level;
+	u16 get_performance_level;
+	u16 set_performance_level;
+
+	/* 0x80 is off, 0x81 is on */
+	u16 get_battery_life_extender;
+	u16 set_battery_life_extender;
+
+	/* 0x80 is off, 0x81 is on */
+	u16 get_usb_charge;
+	u16 set_usb_charge;
+
+	/* the first byte is for bluetooth and the third one is for wlan */
+	u16 get_wireless_status;
+	u16 set_wireless_status;
+
+	/* 0x81 to read, (0x82 | level << 8) to set, 0xaabb to enable */
+	u16 kbd_backlight;
 
 	/*
 	 * Tell the BIOS that Linux is running on this machine.
 	 * 81 is on, 80 is off
 	 */
-	u8 set_linux;
+	u16 set_linux;
 };
 
 struct sabi_performance_level {
 	const char *name;
-	u8 value;
+	u16 value;
 };
 
 struct sabi_config {
+	int sabi_version;
 	const char *test_string;
 	u16 main_function;
 	const struct sabi_header_offsets header_offsets;
@@ -117,6 +152,10 @@
 
 static const struct sabi_config sabi_configs[] = {
 	{
+		/* I don't know if it is really 2, but it it is
+		 * less than 3 anyway */
+		.sabi_version = 2,
+
 		.test_string = "SECLINUX",
 
 		.main_function = 0x4c49,
@@ -146,6 +185,17 @@
 			.get_performance_level = 0x08,
 			.set_performance_level = 0x09,
 
+			.get_battery_life_extender = 0xFFFF,
+			.set_battery_life_extender = 0xFFFF,
+
+			.get_usb_charge = 0xFFFF,
+			.set_usb_charge = 0xFFFF,
+
+			.get_wireless_status = 0xFFFF,
+			.set_wireless_status = 0xFFFF,
+
+			.kbd_backlight = 0xFFFF,
+
 			.set_linux = 0x0a,
 		},
 
@@ -164,6 +214,8 @@
 		.max_brightness = 8,
 	},
 	{
+		.sabi_version = 3,
+
 		.test_string = "SwSmi@",
 
 		.main_function = 0x5843,
@@ -193,6 +245,17 @@
 			.get_performance_level = 0x31,
 			.set_performance_level = 0x32,
 
+			.get_battery_life_extender = 0x65,
+			.set_battery_life_extender = 0x66,
+
+			.get_usb_charge = 0x67,
+			.set_usb_charge = 0x68,
+
+			.get_wireless_status = 0x69,
+			.set_wireless_status = 0x6a,
+
+			.kbd_backlight = 0x78,
+
 			.set_linux = 0xff,
 		},
 
@@ -217,16 +280,82 @@
 	{ },
 };
 
-static const struct sabi_config *sabi_config;
+/*
+ * samsung-laptop/    - debugfs root directory
+ *   f0000_segment    - dump f0000 segment
+ *   command          - current command
+ *   data             - current data
+ *   d0, d1, d2, d3   - data fields
+ *   call             - call SABI using command and data
+ *
+ * This allow to call arbitrary sabi commands wihout
+ * modifying the driver at all.
+ * For example, setting the keyboard backlight brightness to 5
+ *
+ *  echo 0x78 > command
+ *  echo 0x0582 > d0
+ *  echo 0 > d1
+ *  echo 0 > d2
+ *  echo 0 > d3
+ *  cat call
+ */
 
-static void __iomem *sabi;
-static void __iomem *sabi_iface;
-static void __iomem *f0000_segment;
-static struct backlight_device *backlight_device;
-static struct mutex sabi_mutex;
-static struct platform_device *sdev;
-static struct rfkill *rfk;
-static bool has_stepping_quirk;
+struct samsung_laptop_debug {
+	struct dentry *root;
+	struct sabi_data data;
+	u16 command;
+
+	struct debugfs_blob_wrapper f0000_wrapper;
+	struct debugfs_blob_wrapper data_wrapper;
+	struct debugfs_blob_wrapper sdiag_wrapper;
+};
+
+struct samsung_laptop;
+
+struct samsung_rfkill {
+	struct samsung_laptop *samsung;
+	struct rfkill *rfkill;
+	enum rfkill_type type;
+};
+
+struct samsung_laptop {
+	const struct sabi_config *config;
+
+	void __iomem *sabi;
+	void __iomem *sabi_iface;
+	void __iomem *f0000_segment;
+
+	struct mutex sabi_mutex;
+
+	struct platform_device *platform_device;
+	struct backlight_device *backlight_device;
+
+	struct samsung_rfkill wlan;
+	struct samsung_rfkill bluetooth;
+
+	struct led_classdev kbd_led;
+	int kbd_led_wk;
+	struct workqueue_struct *led_workqueue;
+	struct work_struct kbd_led_work;
+
+	struct samsung_laptop_debug debug;
+	struct samsung_quirks *quirks;
+
+	bool handle_backlight;
+	bool has_stepping_quirk;
+
+	char sdiag[64];
+};
+
+struct samsung_quirks {
+	bool broken_acpi_video;
+};
+
+static struct samsung_quirks samsung_unknown = {};
+
+static struct samsung_quirks samsung_broken_acpi_video = {
+	.broken_acpi_video = true,
+};
 
 static bool force;
 module_param(force, bool, 0);
@@ -237,176 +366,143 @@
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
-static int sabi_get_command(u8 command, struct sabi_retval *sretval)
+static int sabi_command(struct samsung_laptop *samsung, u16 command,
+			struct sabi_data *in,
+			struct sabi_data *out)
 {
-	int retval = 0;
-	u16 port = readw(sabi + sabi_config->header_offsets.port);
+	const struct sabi_config *config = samsung->config;
+	int ret = 0;
+	u16 port = readw(samsung->sabi + config->header_offsets.port);
 	u8 complete, iface_data;
 
-	mutex_lock(&sabi_mutex);
+	mutex_lock(&samsung->sabi_mutex);
+
+	if (debug) {
+		if (in)
+			pr_info("SABI command:0x%04x "
+				"data:{0x%08x, 0x%08x, 0x%04x, 0x%02x}",
+				command, in->d0, in->d1, in->d2, in->d3);
+		else
+			pr_info("SABI command:0x%04x", command);
+	}
 
 	/* enable memory to be able to write to it */
-	outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
+	outb(readb(samsung->sabi + config->header_offsets.en_mem), port);
 
 	/* write out the command */
-	writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
-	writew(command, sabi_iface + SABI_IFACE_SUB);
-	writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
-	outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
+	writew(config->main_function, samsung->sabi_iface + SABI_IFACE_MAIN);
+	writew(command, samsung->sabi_iface + SABI_IFACE_SUB);
+	writeb(0, samsung->sabi_iface + SABI_IFACE_COMPLETE);
+	if (in) {
+		writel(in->d0, samsung->sabi_iface + SABI_IFACE_DATA);
+		writel(in->d1, samsung->sabi_iface + SABI_IFACE_DATA + 4);
+		writew(in->d2, samsung->sabi_iface + SABI_IFACE_DATA + 8);
+		writeb(in->d3, samsung->sabi_iface + SABI_IFACE_DATA + 10);
+	}
+	outb(readb(samsung->sabi + config->header_offsets.iface_func), port);
 
 	/* write protect memory to make it safe */
-	outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
+	outb(readb(samsung->sabi + config->header_offsets.re_mem), port);
 
 	/* see if the command actually succeeded */
-	complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
-	iface_data = readb(sabi_iface + SABI_IFACE_DATA);
+	complete = readb(samsung->sabi_iface + SABI_IFACE_COMPLETE);
+	iface_data = readb(samsung->sabi_iface + SABI_IFACE_DATA);
+
+	/* iface_data = 0xFF happens when a command is not known
+	 * so we only add a warning in debug mode since we will
+	 * probably issue some unknown command at startup to find
+	 * out which features are supported */
+	if (complete != 0xaa || (iface_data == 0xff && debug))
+		pr_warn("SABI command 0x%04x failed with"
+			" completion flag 0x%02x and interface data 0x%02x",
+			command, complete, iface_data);
+
 	if (complete != 0xaa || iface_data == 0xff) {
-		pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
-		        command, complete, iface_data);
-		retval = -EINVAL;
+		ret = -EINVAL;
 		goto exit;
 	}
-	/*
-	 * Save off the data into a structure so the caller use it.
-	 * Right now we only want the first 4 bytes,
-	 * There are commands that need more, but not for the ones we
-	 * currently care about.
-	 */
-	sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
-	sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
-	sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
-	sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);
 
-exit:
-	mutex_unlock(&sabi_mutex);
-	return retval;
-
-}
-
-static int sabi_set_command(u8 command, u8 data)
-{
-	int retval = 0;
-	u16 port = readw(sabi + sabi_config->header_offsets.port);
-	u8 complete, iface_data;
-
-	mutex_lock(&sabi_mutex);
-
-	/* enable memory to be able to write to it */
-	outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
-
-	/* write out the command */
-	writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
-	writew(command, sabi_iface + SABI_IFACE_SUB);
-	writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
-	writeb(data, sabi_iface + SABI_IFACE_DATA);
-	outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
-
-	/* write protect memory to make it safe */
-	outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
-
-	/* see if the command actually succeeded */
-	complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
-	iface_data = readb(sabi_iface + SABI_IFACE_DATA);
-	if (complete != 0xaa || iface_data == 0xff) {
-		pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
-		       command, complete, iface_data);
-		retval = -EINVAL;
+	if (out) {
+		out->d0 = readl(samsung->sabi_iface + SABI_IFACE_DATA);
+		out->d1 = readl(samsung->sabi_iface + SABI_IFACE_DATA + 4);
+		out->d2 = readw(samsung->sabi_iface + SABI_IFACE_DATA + 2);
+		out->d3 = readb(samsung->sabi_iface + SABI_IFACE_DATA + 1);
 	}
 
-	mutex_unlock(&sabi_mutex);
-	return retval;
+	if (debug && out) {
+		pr_info("SABI return data:{0x%08x, 0x%08x, 0x%04x, 0x%02x}",
+			out->d0, out->d1, out->d2, out->d3);
+	}
+
+exit:
+	mutex_unlock(&samsung->sabi_mutex);
+	return ret;
 }
 
-static void test_backlight(void)
+/* simple wrappers usable with most commands */
+static int sabi_set_commandb(struct samsung_laptop *samsung,
+			     u16 command, u8 data)
 {
-	struct sabi_retval sretval;
+	struct sabi_data in = { { { .d0 = 0, .d1 = 0, .d2 = 0, .d3 = 0 } } };
 
-	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
-	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
-
-	sabi_set_command(sabi_config->commands.set_backlight, 0);
-	printk(KERN_DEBUG "backlight should be off\n");
-
-	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
-	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
-
-	msleep(1000);
-
-	sabi_set_command(sabi_config->commands.set_backlight, 1);
-	printk(KERN_DEBUG "backlight should be on\n");
-
-	sabi_get_command(sabi_config->commands.get_backlight, &sretval);
-	printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+	in.data[0] = data;
+	return sabi_command(samsung, command, &in, NULL);
 }
 
-static void test_wireless(void)
+static int read_brightness(struct samsung_laptop *samsung)
 {
-	struct sabi_retval sretval;
-
-	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
-	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
-
-	sabi_set_command(sabi_config->commands.set_wireless_button, 0);
-	printk(KERN_DEBUG "wireless led should be off\n");
-
-	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
-	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
-
-	msleep(1000);
-
-	sabi_set_command(sabi_config->commands.set_wireless_button, 1);
-	printk(KERN_DEBUG "wireless led should be on\n");
-
-	sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
-	printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
-}
-
-static u8 read_brightness(void)
-{
-	struct sabi_retval sretval;
+	const struct sabi_config *config = samsung->config;
+	const struct sabi_commands *commands = &samsung->config->commands;
+	struct sabi_data sretval;
 	int user_brightness = 0;
 	int retval;
 
-	retval = sabi_get_command(sabi_config->commands.get_brightness,
-				  &sretval);
-	if (!retval) {
-		user_brightness = sretval.retval[0];
-		if (user_brightness > sabi_config->min_brightness)
-			user_brightness -= sabi_config->min_brightness;
-		else
-			user_brightness = 0;
-	}
+	retval = sabi_command(samsung, commands->get_brightness,
+			      NULL, &sretval);
+	if (retval)
+		return retval;
+
+	user_brightness = sretval.data[0];
+	if (user_brightness > config->min_brightness)
+		user_brightness -= config->min_brightness;
+	else
+		user_brightness = 0;
+
 	return user_brightness;
 }
 
-static void set_brightness(u8 user_brightness)
+static void set_brightness(struct samsung_laptop *samsung, u8 user_brightness)
 {
-	u8 user_level = user_brightness + sabi_config->min_brightness;
+	const struct sabi_config *config = samsung->config;
+	const struct sabi_commands *commands = &samsung->config->commands;
+	u8 user_level = user_brightness + config->min_brightness;
 
-	if (has_stepping_quirk && user_level != 0) {
+	if (samsung->has_stepping_quirk && user_level != 0) {
 		/*
 		 * short circuit if the specified level is what's already set
 		 * to prevent the screen from flickering needlessly
 		 */
-		if (user_brightness == read_brightness())
+		if (user_brightness == read_brightness(samsung))
 			return;
 
-		sabi_set_command(sabi_config->commands.set_brightness, 0);
+		sabi_set_commandb(samsung, commands->set_brightness, 0);
 	}
 
-	sabi_set_command(sabi_config->commands.set_brightness, user_level);
+	sabi_set_commandb(samsung, commands->set_brightness, user_level);
 }
 
 static int get_brightness(struct backlight_device *bd)
 {
-	return (int)read_brightness();
+	struct samsung_laptop *samsung = bl_get_data(bd);
+
+	return read_brightness(samsung);
 }
 
-static void check_for_stepping_quirk(void)
+static void check_for_stepping_quirk(struct samsung_laptop *samsung)
 {
-	u8 initial_level;
-	u8 check_level;
-	u8 orig_level = read_brightness();
+	int initial_level;
+	int check_level;
+	int orig_level = read_brightness(samsung);
 
 	/*
 	 * Some laptops exhibit the strange behaviour of stepping toward
@@ -416,34 +512,38 @@
 	 */
 
 	if (orig_level == 0)
-		set_brightness(1);
+		set_brightness(samsung, 1);
 
-	initial_level = read_brightness();
+	initial_level = read_brightness(samsung);
 
 	if (initial_level <= 2)
 		check_level = initial_level + 2;
 	else
 		check_level = initial_level - 2;
 
-	has_stepping_quirk = false;
-	set_brightness(check_level);
+	samsung->has_stepping_quirk = false;
+	set_brightness(samsung, check_level);
 
-	if (read_brightness() != check_level) {
-		has_stepping_quirk = true;
+	if (read_brightness(samsung) != check_level) {
+		samsung->has_stepping_quirk = true;
 		pr_info("enabled workaround for brightness stepping quirk\n");
 	}
 
-	set_brightness(orig_level);
+	set_brightness(samsung, orig_level);
 }
 
 static int update_status(struct backlight_device *bd)
 {
-	set_brightness(bd->props.brightness);
+	struct samsung_laptop *samsung = bl_get_data(bd);
+	const struct sabi_commands *commands = &samsung->config->commands;
+
+	set_brightness(samsung, bd->props.brightness);
 
 	if (bd->props.power == FB_BLANK_UNBLANK)
-		sabi_set_command(sabi_config->commands.set_backlight, 1);
+		sabi_set_commandb(samsung, commands->set_backlight, 1);
 	else
-		sabi_set_command(sabi_config->commands.set_backlight, 0);
+		sabi_set_commandb(samsung, commands->set_backlight, 0);
+
 	return 0;
 }
 
@@ -452,66 +552,101 @@
 	.update_status	= update_status,
 };
 
-static int rfkill_set(void *data, bool blocked)
+static int seclinux_rfkill_set(void *data, bool blocked)
 {
-	/* Do something with blocked...*/
-	/*
-	 * blocked == false is on
-	 * blocked == true is off
-	 */
-	if (blocked)
-		sabi_set_command(sabi_config->commands.set_wireless_button, 0);
-	else
-		sabi_set_command(sabi_config->commands.set_wireless_button, 1);
+	struct samsung_rfkill *srfkill = data;
+	struct samsung_laptop *samsung = srfkill->samsung;
+	const struct sabi_commands *commands = &samsung->config->commands;
 
-	return 0;
+	return sabi_set_commandb(samsung, commands->set_wireless_button,
+				 !blocked);
 }
 
-static struct rfkill_ops rfkill_ops = {
-	.set_block = rfkill_set,
+static struct rfkill_ops seclinux_rfkill_ops = {
+	.set_block = seclinux_rfkill_set,
 };
 
-static int init_wireless(struct platform_device *sdev)
+static int swsmi_wireless_status(struct samsung_laptop *samsung,
+				 struct sabi_data *data)
 {
-	int retval;
+	const struct sabi_commands *commands = &samsung->config->commands;
 
-	rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN,
-			   &rfkill_ops, NULL);
-	if (!rfk)
-		return -ENOMEM;
-
-	retval = rfkill_register(rfk);
-	if (retval) {
-		rfkill_destroy(rfk);
-		return -ENODEV;
-	}
-
-	return 0;
+	return sabi_command(samsung, commands->get_wireless_status,
+			    NULL, data);
 }
 
-static void destroy_wireless(void)
+static int swsmi_rfkill_set(void *priv, bool blocked)
 {
-	rfkill_unregister(rfk);
-	rfkill_destroy(rfk);
+	struct samsung_rfkill *srfkill = priv;
+	struct samsung_laptop *samsung = srfkill->samsung;
+	const struct sabi_commands *commands = &samsung->config->commands;
+	struct sabi_data data;
+	int ret, i;
+
+	ret = swsmi_wireless_status(samsung, &data);
+	if (ret)
+		return ret;
+
+	/* Don't set the state for non-present devices */
+	for (i = 0; i < 4; i++)
+		if (data.data[i] == 0x02)
+			data.data[1] = 0;
+
+	if (srfkill->type == RFKILL_TYPE_WLAN)
+		data.data[WL_STATUS_WLAN] = !blocked;
+	else if (srfkill->type == RFKILL_TYPE_BLUETOOTH)
+		data.data[WL_STATUS_BT] = !blocked;
+
+	return sabi_command(samsung, commands->set_wireless_status,
+			    &data, &data);
 }
 
+static void swsmi_rfkill_query(struct rfkill *rfkill, void *priv)
+{
+	struct samsung_rfkill *srfkill = priv;
+	struct samsung_laptop *samsung = srfkill->samsung;
+	struct sabi_data data;
+	int ret;
+
+	ret = swsmi_wireless_status(samsung, &data);
+	if (ret)
+		return ;
+
+	if (srfkill->type == RFKILL_TYPE_WLAN)
+		ret = data.data[WL_STATUS_WLAN];
+	else if (srfkill->type == RFKILL_TYPE_BLUETOOTH)
+		ret = data.data[WL_STATUS_BT];
+	else
+		return ;
+
+	rfkill_set_sw_state(rfkill, !ret);
+}
+
+static struct rfkill_ops swsmi_rfkill_ops = {
+	.set_block = swsmi_rfkill_set,
+	.query = swsmi_rfkill_query,
+};
+
 static ssize_t get_performance_level(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
-	struct sabi_retval sretval;
+	struct samsung_laptop *samsung = dev_get_drvdata(dev);
+	const struct sabi_config *config = samsung->config;
+	const struct sabi_commands *commands = &config->commands;
+	struct sabi_data sretval;
 	int retval;
 	int i;
 
 	/* Read the state */
-	retval = sabi_get_command(sabi_config->commands.get_performance_level,
-				  &sretval);
+	retval = sabi_command(samsung, commands->get_performance_level,
+			      NULL, &sretval);
 	if (retval)
 		return retval;
 
 	/* The logic is backwards, yeah, lots of fun... */
-	for (i = 0; sabi_config->performance_levels[i].name; ++i) {
-		if (sretval.retval[0] == sabi_config->performance_levels[i].value)
-			return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name);
+	for (i = 0; config->performance_levels[i].name; ++i) {
+		if (sretval.data[0] == config->performance_levels[i].value)
+			return sprintf(buf, "%s\n", config->performance_levels[i].name);
 	}
 	return sprintf(buf, "%s\n", "unknown");
 }
@@ -520,269 +655,178 @@
 				struct device_attribute *attr, const char *buf,
 				size_t count)
 {
-	if (count >= 1) {
-		int i;
-		for (i = 0; sabi_config->performance_levels[i].name; ++i) {
-			const struct sabi_performance_level *level =
-				&sabi_config->performance_levels[i];
-			if (!strncasecmp(level->name, buf, strlen(level->name))) {
-				sabi_set_command(sabi_config->commands.set_performance_level,
-						 level->value);
-				break;
-			}
+	struct samsung_laptop *samsung = dev_get_drvdata(dev);
+	const struct sabi_config *config = samsung->config;
+	const struct sabi_commands *commands = &config->commands;
+	int i;
+
+	if (count < 1)
+		return count;
+
+	for (i = 0; config->performance_levels[i].name; ++i) {
+		const struct sabi_performance_level *level =
+			&config->performance_levels[i];
+		if (!strncasecmp(level->name, buf, strlen(level->name))) {
+			sabi_set_commandb(samsung,
+					  commands->set_performance_level,
+					  level->value);
+			break;
 		}
-		if (!sabi_config->performance_levels[i].name)
-			return -EINVAL;
 	}
+
+	if (!config->performance_levels[i].name)
+		return -EINVAL;
+
 	return count;
 }
+
 static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
 		   get_performance_level, set_performance_level);
 
-
-static int __init dmi_check_cb(const struct dmi_system_id *id)
+static int read_battery_life_extender(struct samsung_laptop *samsung)
 {
-	pr_info("found laptop model '%s'\n",
-		id->ident);
-	return 1;
+	const struct sabi_commands *commands = &samsung->config->commands;
+	struct sabi_data data;
+	int retval;
+
+	if (commands->get_battery_life_extender == 0xFFFF)
+		return -ENODEV;
+
+	memset(&data, 0, sizeof(data));
+	data.data[0] = 0x80;
+	retval = sabi_command(samsung, commands->get_battery_life_extender,
+			      &data, &data);
+
+	if (retval)
+		return retval;
+
+	if (data.data[0] != 0 && data.data[0] != 1)
+		return -ENODEV;
+
+	return data.data[0];
 }
 
-static struct dmi_system_id __initdata samsung_dmi_table[] = {
-	{
-		.ident = "N128",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
-			DMI_MATCH(DMI_BOARD_NAME, "N128"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "N130",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
-			DMI_MATCH(DMI_BOARD_NAME, "N130"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "N510",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "N510"),
-			DMI_MATCH(DMI_BOARD_NAME, "N510"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "X125",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
-			DMI_MATCH(DMI_BOARD_NAME, "X125"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "X120/X170",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"),
-			DMI_MATCH(DMI_BOARD_NAME, "X120/X170"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "NC10",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
-			DMI_MATCH(DMI_BOARD_NAME, "NC10"),
-		},
-		.callback = dmi_check_cb,
-	},
-		{
-		.ident = "NP-Q45",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
-			DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
-		},
-		.callback = dmi_check_cb,
-		},
-	{
-		.ident = "X360",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
-			DMI_MATCH(DMI_BOARD_NAME, "X360"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "R410 Plus",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "R410P"),
-			DMI_MATCH(DMI_BOARD_NAME, "R460"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "R518",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
-			DMI_MATCH(DMI_BOARD_NAME, "R518"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "R519/R719",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"),
-			DMI_MATCH(DMI_BOARD_NAME, "R519/R719"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "N150/N210/N220",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
-			DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "N220",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "N220"),
-			DMI_MATCH(DMI_BOARD_NAME, "N220"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "N150/N210/N220/N230",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"),
-			DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "N150P/N210P/N220P",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"),
-			DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "R700",
-		.matches = {
-		      DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-		      DMI_MATCH(DMI_PRODUCT_NAME, "SR700"),
-		      DMI_MATCH(DMI_BOARD_NAME, "SR700"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "R530/R730",
-		.matches = {
-		      DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-		      DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
-		      DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "NF110/NF210/NF310",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
-			DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "N145P/N250P/N260P",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
-			DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "R70/R71",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR,
-					"SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"),
-			DMI_MATCH(DMI_BOARD_NAME, "R70/R71"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "P460",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "P460"),
-			DMI_MATCH(DMI_BOARD_NAME, "P460"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "R528/R728",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "R528/R728"),
-			DMI_MATCH(DMI_BOARD_NAME, "R528/R728"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{
-		.ident = "NC210/NC110",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"),
-			DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"),
-		},
-		.callback = dmi_check_cb,
-	},
-		{
-		.ident = "X520",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "X520"),
-			DMI_MATCH(DMI_BOARD_NAME, "X520"),
-		},
-		.callback = dmi_check_cb,
-	},
-	{ },
+static int write_battery_life_extender(struct samsung_laptop *samsung,
+				       int enabled)
+{
+	const struct sabi_commands *commands = &samsung->config->commands;
+	struct sabi_data data;
+
+	memset(&data, 0, sizeof(data));
+	data.data[0] = 0x80 | enabled;
+	return sabi_command(samsung, commands->set_battery_life_extender,
+			    &data, NULL);
+}
+
+static ssize_t get_battery_life_extender(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	struct samsung_laptop *samsung = dev_get_drvdata(dev);
+	int ret;
+
+	ret = read_battery_life_extender(samsung);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", ret);
+}
+
+static ssize_t set_battery_life_extender(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct samsung_laptop *samsung = dev_get_drvdata(dev);
+	int ret, value;
+
+	if (!count || sscanf(buf, "%i", &value) != 1)
+		return -EINVAL;
+
+	ret = write_battery_life_extender(samsung, !!value);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static DEVICE_ATTR(battery_life_extender, S_IWUSR | S_IRUGO,
+		   get_battery_life_extender, set_battery_life_extender);
+
+static int read_usb_charge(struct samsung_laptop *samsung)
+{
+	const struct sabi_commands *commands = &samsung->config->commands;
+	struct sabi_data data;
+	int retval;
+
+	if (commands->get_usb_charge == 0xFFFF)
+		return -ENODEV;
+
+	memset(&data, 0, sizeof(data));
+	data.data[0] = 0x80;
+	retval = sabi_command(samsung, commands->get_usb_charge,
+			      &data, &data);
+
+	if (retval)
+		return retval;
+
+	if (data.data[0] != 0 && data.data[0] != 1)
+		return -ENODEV;
+
+	return data.data[0];
+}
+
+static int write_usb_charge(struct samsung_laptop *samsung,
+			    int enabled)
+{
+	const struct sabi_commands *commands = &samsung->config->commands;
+	struct sabi_data data;
+
+	memset(&data, 0, sizeof(data));
+	data.data[0] = 0x80 | enabled;
+	return sabi_command(samsung, commands->set_usb_charge,
+			    &data, NULL);
+}
+
+static ssize_t get_usb_charge(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	struct samsung_laptop *samsung = dev_get_drvdata(dev);
+	int ret;
+
+	ret = read_usb_charge(samsung);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", ret);
+}
+
+static ssize_t set_usb_charge(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct samsung_laptop *samsung = dev_get_drvdata(dev);
+	int ret, value;
+
+	if (!count || sscanf(buf, "%i", &value) != 1)
+		return -EINVAL;
+
+	ret = write_usb_charge(samsung, !!value);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static DEVICE_ATTR(usb_charge, S_IWUSR | S_IRUGO,
+		   get_usb_charge, set_usb_charge);
+
+static struct attribute *platform_attributes[] = {
+	&dev_attr_performance_level.attr,
+	&dev_attr_battery_life_extender.attr,
+	&dev_attr_usb_charge.attr,
+	NULL
 };
-MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
 
 static int find_signature(void __iomem *memcheck, const char *testStr)
 {
@@ -803,153 +847,772 @@
 	return loca;
 }
 
-static int __init samsung_init(void)
+static void samsung_rfkill_exit(struct samsung_laptop *samsung)
 {
-	struct backlight_properties props;
-	struct sabi_retval sretval;
-	unsigned int ifaceP;
-	int i;
-	int loca;
+	if (samsung->wlan.rfkill) {
+		rfkill_unregister(samsung->wlan.rfkill);
+		rfkill_destroy(samsung->wlan.rfkill);
+		samsung->wlan.rfkill = NULL;
+	}
+	if (samsung->bluetooth.rfkill) {
+		rfkill_unregister(samsung->bluetooth.rfkill);
+		rfkill_destroy(samsung->bluetooth.rfkill);
+		samsung->bluetooth.rfkill = NULL;
+	}
+}
+
+static int samsung_new_rfkill(struct samsung_laptop *samsung,
+			      struct samsung_rfkill *arfkill,
+			      const char *name, enum rfkill_type type,
+			      const struct rfkill_ops *ops,
+			      int blocked)
+{
+	struct rfkill **rfkill = &arfkill->rfkill;
+	int ret;
+
+	arfkill->type = type;
+	arfkill->samsung = samsung;
+
+	*rfkill = rfkill_alloc(name, &samsung->platform_device->dev,
+			       type, ops, arfkill);
+
+	if (!*rfkill)
+		return -EINVAL;
+
+	if (blocked != -1)
+		rfkill_init_sw_state(*rfkill, blocked);
+
+	ret = rfkill_register(*rfkill);
+	if (ret) {
+		rfkill_destroy(*rfkill);
+		*rfkill = NULL;
+		return ret;
+	}
+	return 0;
+}
+
+static int __init samsung_rfkill_init_seclinux(struct samsung_laptop *samsung)
+{
+	return samsung_new_rfkill(samsung, &samsung->wlan, "samsung-wlan",
+				  RFKILL_TYPE_WLAN, &seclinux_rfkill_ops, -1);
+}
+
+static int __init samsung_rfkill_init_swsmi(struct samsung_laptop *samsung)
+{
+	struct sabi_data data;
+	int ret;
+
+	ret = swsmi_wireless_status(samsung, &data);
+	if (ret) {
+		/* Some swsmi laptops use the old seclinux way to control
+		 * wireless devices */
+		if (ret == -EINVAL)
+			ret = samsung_rfkill_init_seclinux(samsung);
+		return ret;
+	}
+
+	/* 0x02 seems to mean that the device is no present/available */
+
+	if (data.data[WL_STATUS_WLAN] != 0x02)
+		ret = samsung_new_rfkill(samsung, &samsung->wlan,
+					 "samsung-wlan",
+					 RFKILL_TYPE_WLAN,
+					 &swsmi_rfkill_ops,
+					 !data.data[WL_STATUS_WLAN]);
+	if (ret)
+		goto exit;
+
+	if (data.data[WL_STATUS_BT] != 0x02)
+		ret = samsung_new_rfkill(samsung, &samsung->bluetooth,
+					 "samsung-bluetooth",
+					 RFKILL_TYPE_BLUETOOTH,
+					 &swsmi_rfkill_ops,
+					 !data.data[WL_STATUS_BT]);
+	if (ret)
+		goto exit;
+
+exit:
+	if (ret)
+		samsung_rfkill_exit(samsung);
+
+	return ret;
+}
+
+static int __init samsung_rfkill_init(struct samsung_laptop *samsung)
+{
+	if (samsung->config->sabi_version == 2)
+		return samsung_rfkill_init_seclinux(samsung);
+	if (samsung->config->sabi_version == 3)
+		return samsung_rfkill_init_swsmi(samsung);
+	return 0;
+}
+
+static int kbd_backlight_enable(struct samsung_laptop *samsung)
+{
+	const struct sabi_commands *commands = &samsung->config->commands;
+	struct sabi_data data;
 	int retval;
 
-	mutex_init(&sabi_mutex);
-
-	if (!force && !dmi_check_system(samsung_dmi_table))
+	if (commands->kbd_backlight == 0xFFFF)
 		return -ENODEV;
 
-	f0000_segment = ioremap_nocache(0xf0000, 0xffff);
-	if (!f0000_segment) {
-		pr_err("Can't map the segment at 0xf0000\n");
-		return -EINVAL;
+	memset(&data, 0, sizeof(data));
+	data.d0 = 0xaabb;
+	retval = sabi_command(samsung, commands->kbd_backlight,
+			      &data, &data);
+
+	if (retval)
+		return retval;
+
+	if (data.d0 != 0xccdd)
+		return -ENODEV;
+	return 0;
+}
+
+static int kbd_backlight_read(struct samsung_laptop *samsung)
+{
+	const struct sabi_commands *commands = &samsung->config->commands;
+	struct sabi_data data;
+	int retval;
+
+	memset(&data, 0, sizeof(data));
+	data.data[0] = 0x81;
+	retval = sabi_command(samsung, commands->kbd_backlight,
+			      &data, &data);
+
+	if (retval)
+		return retval;
+
+	return data.data[0];
+}
+
+static int kbd_backlight_write(struct samsung_laptop *samsung, int brightness)
+{
+	const struct sabi_commands *commands = &samsung->config->commands;
+	struct sabi_data data;
+
+	memset(&data, 0, sizeof(data));
+	data.d0 = 0x82 | ((brightness & 0xFF) << 8);
+	return sabi_command(samsung, commands->kbd_backlight,
+			    &data, NULL);
+}
+
+static void kbd_led_update(struct work_struct *work)
+{
+	struct samsung_laptop *samsung;
+
+	samsung = container_of(work, struct samsung_laptop, kbd_led_work);
+	kbd_backlight_write(samsung, samsung->kbd_led_wk);
+}
+
+static void kbd_led_set(struct led_classdev *led_cdev,
+			enum led_brightness value)
+{
+	struct samsung_laptop *samsung;
+
+	samsung = container_of(led_cdev, struct samsung_laptop, kbd_led);
+
+	if (value > samsung->kbd_led.max_brightness)
+		value = samsung->kbd_led.max_brightness;
+	else if (value < 0)
+		value = 0;
+
+	samsung->kbd_led_wk = value;
+	queue_work(samsung->led_workqueue, &samsung->kbd_led_work);
+}
+
+static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
+{
+	struct samsung_laptop *samsung;
+
+	samsung = container_of(led_cdev, struct samsung_laptop, kbd_led);
+	return kbd_backlight_read(samsung);
+}
+
+static void samsung_leds_exit(struct samsung_laptop *samsung)
+{
+	if (!IS_ERR_OR_NULL(samsung->kbd_led.dev))
+		led_classdev_unregister(&samsung->kbd_led);
+	if (samsung->led_workqueue)
+		destroy_workqueue(samsung->led_workqueue);
+}
+
+static int __init samsung_leds_init(struct samsung_laptop *samsung)
+{
+	int ret = 0;
+
+	samsung->led_workqueue = create_singlethread_workqueue("led_workqueue");
+	if (!samsung->led_workqueue)
+		return -ENOMEM;
+
+	if (kbd_backlight_enable(samsung) >= 0) {
+		INIT_WORK(&samsung->kbd_led_work, kbd_led_update);
+
+		samsung->kbd_led.name = "samsung::kbd_backlight";
+		samsung->kbd_led.brightness_set = kbd_led_set;
+		samsung->kbd_led.brightness_get = kbd_led_get;
+		samsung->kbd_led.max_brightness = 8;
+
+		ret = led_classdev_register(&samsung->platform_device->dev,
+					   &samsung->kbd_led);
 	}
 
+	if (ret)
+		samsung_leds_exit(samsung);
+
+	return ret;
+}
+
+static void samsung_backlight_exit(struct samsung_laptop *samsung)
+{
+	if (samsung->backlight_device) {
+		backlight_device_unregister(samsung->backlight_device);
+		samsung->backlight_device = NULL;
+	}
+}
+
+static int __init samsung_backlight_init(struct samsung_laptop *samsung)
+{
+	struct backlight_device *bd;
+	struct backlight_properties props;
+
+	if (!samsung->handle_backlight)
+		return 0;
+
+	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
+	props.max_brightness = samsung->config->max_brightness -
+		samsung->config->min_brightness;
+
+	bd = backlight_device_register("samsung",
+				       &samsung->platform_device->dev,
+				       samsung, &backlight_ops,
+				       &props);
+	if (IS_ERR(bd))
+		return PTR_ERR(bd);
+
+	samsung->backlight_device = bd;
+	samsung->backlight_device->props.brightness = read_brightness(samsung);
+	samsung->backlight_device->props.power = FB_BLANK_UNBLANK;
+	backlight_update_status(samsung->backlight_device);
+
+	return 0;
+}
+
+static umode_t samsung_sysfs_is_visible(struct kobject *kobj,
+				       struct attribute *attr, int idx)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct samsung_laptop *samsung = platform_get_drvdata(pdev);
+	bool ok = true;
+
+	if (attr == &dev_attr_performance_level.attr)
+		ok = !!samsung->config->performance_levels[0].name;
+	if (attr == &dev_attr_battery_life_extender.attr)
+		ok = !!(read_battery_life_extender(samsung) >= 0);
+	if (attr == &dev_attr_usb_charge.attr)
+		ok = !!(read_usb_charge(samsung) >= 0);
+
+	return ok ? attr->mode : 0;
+}
+
+static struct attribute_group platform_attribute_group = {
+	.is_visible = samsung_sysfs_is_visible,
+	.attrs = platform_attributes
+};
+
+static void samsung_sysfs_exit(struct samsung_laptop *samsung)
+{
+	struct platform_device *device = samsung->platform_device;
+
+	sysfs_remove_group(&device->dev.kobj, &platform_attribute_group);
+}
+
+static int __init samsung_sysfs_init(struct samsung_laptop *samsung)
+{
+	struct platform_device *device = samsung->platform_device;
+
+	return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
+
+}
+
+static int show_call(struct seq_file *m, void *data)
+{
+	struct samsung_laptop *samsung = m->private;
+	struct sabi_data *sdata = &samsung->debug.data;
+	int ret;
+
+	seq_printf(m, "SABI 0x%04x {0x%08x, 0x%08x, 0x%04x, 0x%02x}\n",
+		   samsung->debug.command,
+		   sdata->d0, sdata->d1, sdata->d2, sdata->d3);
+
+	ret = sabi_command(samsung, samsung->debug.command, sdata, sdata);
+
+	if (ret) {
+		seq_printf(m, "SABI command 0x%04x failed\n",
+			   samsung->debug.command);
+		return ret;
+	}
+
+	seq_printf(m, "SABI {0x%08x, 0x%08x, 0x%04x, 0x%02x}\n",
+		   sdata->d0, sdata->d1, sdata->d2, sdata->d3);
+	return 0;
+}
+
+static int samsung_debugfs_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, show_call, inode->i_private);
+}
+
+static const struct file_operations samsung_laptop_call_io_ops = {
+	.owner = THIS_MODULE,
+	.open = samsung_debugfs_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static void samsung_debugfs_exit(struct samsung_laptop *samsung)
+{
+	debugfs_remove_recursive(samsung->debug.root);
+}
+
+static int samsung_debugfs_init(struct samsung_laptop *samsung)
+{
+	struct dentry *dent;
+
+	samsung->debug.root = debugfs_create_dir("samsung-laptop", NULL);
+	if (!samsung->debug.root) {
+		pr_err("failed to create debugfs directory");
+		goto error_debugfs;
+	}
+
+	samsung->debug.f0000_wrapper.data = samsung->f0000_segment;
+	samsung->debug.f0000_wrapper.size = 0xffff;
+
+	samsung->debug.data_wrapper.data = &samsung->debug.data;
+	samsung->debug.data_wrapper.size = sizeof(samsung->debug.data);
+
+	samsung->debug.sdiag_wrapper.data = samsung->sdiag;
+	samsung->debug.sdiag_wrapper.size = strlen(samsung->sdiag);
+
+	dent = debugfs_create_u16("command", S_IRUGO | S_IWUSR,
+				  samsung->debug.root, &samsung->debug.command);
+	if (!dent)
+		goto error_debugfs;
+
+	dent = debugfs_create_u32("d0", S_IRUGO | S_IWUSR, samsung->debug.root,
+				  &samsung->debug.data.d0);
+	if (!dent)
+		goto error_debugfs;
+
+	dent = debugfs_create_u32("d1", S_IRUGO | S_IWUSR, samsung->debug.root,
+				  &samsung->debug.data.d1);
+	if (!dent)
+		goto error_debugfs;
+
+	dent = debugfs_create_u16("d2", S_IRUGO | S_IWUSR, samsung->debug.root,
+				  &samsung->debug.data.d2);
+	if (!dent)
+		goto error_debugfs;
+
+	dent = debugfs_create_u8("d3", S_IRUGO | S_IWUSR, samsung->debug.root,
+				 &samsung->debug.data.d3);
+	if (!dent)
+		goto error_debugfs;
+
+	dent = debugfs_create_blob("data", S_IRUGO | S_IWUSR,
+				   samsung->debug.root,
+				   &samsung->debug.data_wrapper);
+	if (!dent)
+		goto error_debugfs;
+
+	dent = debugfs_create_blob("f0000_segment", S_IRUSR | S_IWUSR,
+				   samsung->debug.root,
+				   &samsung->debug.f0000_wrapper);
+	if (!dent)
+		goto error_debugfs;
+
+	dent = debugfs_create_file("call", S_IFREG | S_IRUGO,
+				   samsung->debug.root, samsung,
+				   &samsung_laptop_call_io_ops);
+	if (!dent)
+		goto error_debugfs;
+
+	dent = debugfs_create_blob("sdiag", S_IRUGO | S_IWUSR,
+				   samsung->debug.root,
+				   &samsung->debug.sdiag_wrapper);
+	if (!dent)
+		goto error_debugfs;
+
+	return 0;
+
+error_debugfs:
+	samsung_debugfs_exit(samsung);
+	return -ENOMEM;
+}
+
+static void samsung_sabi_exit(struct samsung_laptop *samsung)
+{
+	const struct sabi_config *config = samsung->config;
+
+	/* Turn off "Linux" mode in the BIOS */
+	if (config && config->commands.set_linux != 0xff)
+		sabi_set_commandb(samsung, config->commands.set_linux, 0x80);
+
+	if (samsung->sabi_iface) {
+		iounmap(samsung->sabi_iface);
+		samsung->sabi_iface = NULL;
+	}
+	if (samsung->f0000_segment) {
+		iounmap(samsung->f0000_segment);
+		samsung->f0000_segment = NULL;
+	}
+
+	samsung->config = NULL;
+}
+
+static __init void samsung_sabi_infos(struct samsung_laptop *samsung, int loca,
+				      unsigned int ifaceP)
+{
+	const struct sabi_config *config = samsung->config;
+
+	printk(KERN_DEBUG "This computer supports SABI==%x\n",
+	       loca + 0xf0000 - 6);
+
+	printk(KERN_DEBUG "SABI header:\n");
+	printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
+	       readw(samsung->sabi + config->header_offsets.port));
+	printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
+	       readb(samsung->sabi + config->header_offsets.iface_func));
+	printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
+	       readb(samsung->sabi + config->header_offsets.en_mem));
+	printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
+	       readb(samsung->sabi + config->header_offsets.re_mem));
+	printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
+	       readw(samsung->sabi + config->header_offsets.data_offset));
+	printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
+	       readw(samsung->sabi + config->header_offsets.data_segment));
+
+	printk(KERN_DEBUG " SABI pointer = 0x%08x\n", ifaceP);
+}
+
+static void __init samsung_sabi_diag(struct samsung_laptop *samsung)
+{
+	int loca = find_signature(samsung->f0000_segment, "SDiaG@");
+	int i;
+
+	if (loca == 0xffff)
+		return ;
+
+	/* Example:
+	 * Ident: @SDiaG@686XX-N90X3A/966-SEC-07HL-S90X3A
+	 *
+	 * Product name: 90X3A
+	 * BIOS Version: 07HL
+	 */
+	loca += 1;
+	for (i = 0; loca < 0xffff && i < sizeof(samsung->sdiag) - 1; loca++) {
+		char temp = readb(samsung->f0000_segment + loca);
+
+		if (isalnum(temp) || temp == '/' || temp == '-')
+			samsung->sdiag[i++] = temp;
+		else
+			break ;
+	}
+
+	if (debug && samsung->sdiag[0])
+		pr_info("sdiag: %s", samsung->sdiag);
+}
+
+static int __init samsung_sabi_init(struct samsung_laptop *samsung)
+{
+	const struct sabi_config *config = NULL;
+	const struct sabi_commands *commands;
+	unsigned int ifaceP;
+	int ret = 0;
+	int i;
+	int loca;
+
+	samsung->f0000_segment = ioremap_nocache(0xf0000, 0xffff);
+	if (!samsung->f0000_segment) {
+		if (debug || force)
+			pr_err("Can't map the segment at 0xf0000\n");
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	samsung_sabi_diag(samsung);
+
 	/* Try to find one of the signatures in memory to find the header */
 	for (i = 0; sabi_configs[i].test_string != 0; ++i) {
-		sabi_config = &sabi_configs[i];
-		loca = find_signature(f0000_segment, sabi_config->test_string);
+		samsung->config = &sabi_configs[i];
+		loca = find_signature(samsung->f0000_segment,
+				      samsung->config->test_string);
 		if (loca != 0xffff)
 			break;
 	}
 
 	if (loca == 0xffff) {
-		pr_err("This computer does not support SABI\n");
-		goto error_no_signature;
+		if (debug || force)
+			pr_err("This computer does not support SABI\n");
+		ret = -ENODEV;
+		goto exit;
 	}
 
+	config = samsung->config;
+	commands = &config->commands;
+
 	/* point to the SMI port Number */
 	loca += 1;
-	sabi = (f0000_segment + loca);
-
-	if (debug) {
-		printk(KERN_DEBUG "This computer supports SABI==%x\n",
-			loca + 0xf0000 - 6);
-		printk(KERN_DEBUG "SABI header:\n");
-		printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
-			readw(sabi + sabi_config->header_offsets.port));
-		printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
-			readb(sabi + sabi_config->header_offsets.iface_func));
-		printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
-			readb(sabi + sabi_config->header_offsets.en_mem));
-		printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
-			readb(sabi + sabi_config->header_offsets.re_mem));
-		printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
-			readw(sabi + sabi_config->header_offsets.data_offset));
-		printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
-			readw(sabi + sabi_config->header_offsets.data_segment));
-	}
+	samsung->sabi = (samsung->f0000_segment + loca);
 
 	/* Get a pointer to the SABI Interface */
-	ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4;
-	ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff;
-	sabi_iface = ioremap_nocache(ifaceP, 16);
-	if (!sabi_iface) {
+	ifaceP = (readw(samsung->sabi + config->header_offsets.data_segment) & 0x0ffff) << 4;
+	ifaceP += readw(samsung->sabi + config->header_offsets.data_offset) & 0x0ffff;
+
+	if (debug)
+		samsung_sabi_infos(samsung, loca, ifaceP);
+
+	samsung->sabi_iface = ioremap_nocache(ifaceP, 16);
+	if (!samsung->sabi_iface) {
 		pr_err("Can't remap %x\n", ifaceP);
-		goto error_no_signature;
-	}
-	if (debug) {
-		printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
-		printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface);
-
-		test_backlight();
-		test_wireless();
-
-		retval = sabi_get_command(sabi_config->commands.get_brightness,
-					  &sretval);
-		printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]);
+		ret = -EINVAL;
+		goto exit;
 	}
 
 	/* Turn on "Linux" mode in the BIOS */
-	if (sabi_config->commands.set_linux != 0xff) {
-		retval = sabi_set_command(sabi_config->commands.set_linux,
-					  0x81);
+	if (commands->set_linux != 0xff) {
+		int retval = sabi_set_commandb(samsung,
+					       commands->set_linux, 0x81);
 		if (retval) {
 			pr_warn("Linux mode was not set!\n");
-			goto error_no_platform;
+			ret = -ENODEV;
+			goto exit;
 		}
 	}
 
 	/* Check for stepping quirk */
-	check_for_stepping_quirk();
+	if (samsung->handle_backlight)
+		check_for_stepping_quirk(samsung);
 
-	/* knock up a platform device to hang stuff off of */
-	sdev = platform_device_register_simple("samsung", -1, NULL, 0);
-	if (IS_ERR(sdev))
-		goto error_no_platform;
+	pr_info("detected SABI interface: %s\n",
+		samsung->config->test_string);
 
-	/* create a backlight device to talk to this one */
-	memset(&props, 0, sizeof(struct backlight_properties));
-	props.type = BACKLIGHT_PLATFORM;
-	props.max_brightness = sabi_config->max_brightness -
-				sabi_config->min_brightness;
-	backlight_device = backlight_device_register("samsung", &sdev->dev,
-						     NULL, &backlight_ops,
-						     &props);
-	if (IS_ERR(backlight_device))
-		goto error_no_backlight;
+exit:
+	if (ret)
+		samsung_sabi_exit(samsung);
 
-	backlight_device->props.brightness = read_brightness();
-	backlight_device->props.power = FB_BLANK_UNBLANK;
-	backlight_update_status(backlight_device);
+	return ret;
+}
 
-	retval = init_wireless(sdev);
-	if (retval)
-		goto error_no_rfk;
+static void samsung_platform_exit(struct samsung_laptop *samsung)
+{
+	if (samsung->platform_device) {
+		platform_device_unregister(samsung->platform_device);
+		samsung->platform_device = NULL;
+	}
+}
 
-	retval = device_create_file(&sdev->dev, &dev_attr_performance_level);
-	if (retval)
-		goto error_file_create;
+static int __init samsung_platform_init(struct samsung_laptop *samsung)
+{
+	struct platform_device *pdev;
 
+	pdev = platform_device_register_simple("samsung", -1, NULL, 0);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	samsung->platform_device = pdev;
+	platform_set_drvdata(samsung->platform_device, samsung);
 	return 0;
+}
 
-error_file_create:
-	destroy_wireless();
+static struct samsung_quirks *quirks;
 
-error_no_rfk:
-	backlight_device_unregister(backlight_device);
+static int __init samsung_dmi_matched(const struct dmi_system_id *d)
+{
+	quirks = d->driver_data;
+	return 0;
+}
 
-error_no_backlight:
-	platform_device_unregister(sdev);
+static struct dmi_system_id __initdata samsung_dmi_table[] = {
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
+		},
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+					"SAMSUNG ELECTRONICS CO., LTD."),
+			DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */
+		},
+	},
+	/* Specific DMI ids for laptop with quirks */
+	{
+	 .callback = samsung_dmi_matched,
+	 .ident = "N150P",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+		DMI_MATCH(DMI_PRODUCT_NAME, "N150P"),
+		DMI_MATCH(DMI_BOARD_NAME, "N150P"),
+		},
+	 .driver_data = &samsung_broken_acpi_video,
+	},
+	{
+	 .callback = samsung_dmi_matched,
+	 .ident = "N145P/N250P/N260P",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+		DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
+		DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
+		},
+	 .driver_data = &samsung_broken_acpi_video,
+	},
+	{
+	 .callback = samsung_dmi_matched,
+	 .ident = "N150/N210/N220",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+		DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
+		DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
+		},
+	 .driver_data = &samsung_broken_acpi_video,
+	},
+	{
+	 .callback = samsung_dmi_matched,
+	 .ident = "NF110/NF210/NF310",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+		DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
+		DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
+		},
+	 .driver_data = &samsung_broken_acpi_video,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
 
-error_no_platform:
-	iounmap(sabi_iface);
+static struct platform_device *samsung_platform_device;
 
-error_no_signature:
-	iounmap(f0000_segment);
-	return -EINVAL;
+static int __init samsung_init(void)
+{
+	struct samsung_laptop *samsung;
+	int ret;
+
+	quirks = &samsung_unknown;
+	if (!force && !dmi_check_system(samsung_dmi_table))
+		return -ENODEV;
+
+	samsung = kzalloc(sizeof(*samsung), GFP_KERNEL);
+	if (!samsung)
+		return -ENOMEM;
+
+	mutex_init(&samsung->sabi_mutex);
+	samsung->handle_backlight = true;
+	samsung->quirks = quirks;
+
+
+#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
+	/* Don't handle backlight here if the acpi video already handle it */
+	if (acpi_video_backlight_support()) {
+		if (samsung->quirks->broken_acpi_video) {
+			pr_info("Disabling ACPI video driver\n");
+			acpi_video_unregister();
+		} else {
+			samsung->handle_backlight = false;
+		}
+	}
+#endif
+
+	ret = samsung_platform_init(samsung);
+	if (ret)
+		goto error_platform;
+
+	ret = samsung_sabi_init(samsung);
+	if (ret)
+		goto error_sabi;
+
+#ifdef CONFIG_ACPI
+	/* Only log that if we are really on a sabi platform */
+	if (acpi_video_backlight_support() &&
+	    !samsung->quirks->broken_acpi_video)
+		pr_info("Backlight controlled by ACPI video driver\n");
+#endif
+
+	ret = samsung_sysfs_init(samsung);
+	if (ret)
+		goto error_sysfs;
+
+	ret = samsung_backlight_init(samsung);
+	if (ret)
+		goto error_backlight;
+
+	ret = samsung_rfkill_init(samsung);
+	if (ret)
+		goto error_rfkill;
+
+	ret = samsung_leds_init(samsung);
+	if (ret)
+		goto error_leds;
+
+	ret = samsung_debugfs_init(samsung);
+	if (ret)
+		goto error_debugfs;
+
+	samsung_platform_device = samsung->platform_device;
+	return ret;
+
+error_debugfs:
+	samsung_leds_exit(samsung);
+error_leds:
+	samsung_rfkill_exit(samsung);
+error_rfkill:
+	samsung_backlight_exit(samsung);
+error_backlight:
+	samsung_sysfs_exit(samsung);
+error_sysfs:
+	samsung_sabi_exit(samsung);
+error_sabi:
+	samsung_platform_exit(samsung);
+error_platform:
+	kfree(samsung);
+	return ret;
 }
 
 static void __exit samsung_exit(void)
 {
-	/* Turn off "Linux" mode in the BIOS */
-	if (sabi_config->commands.set_linux != 0xff)
-		sabi_set_command(sabi_config->commands.set_linux, 0x80);
+	struct samsung_laptop *samsung;
 
-	device_remove_file(&sdev->dev, &dev_attr_performance_level);
-	backlight_device_unregister(backlight_device);
-	destroy_wireless();
-	iounmap(sabi_iface);
-	iounmap(f0000_segment);
-	platform_device_unregister(sdev);
+	samsung = platform_get_drvdata(samsung_platform_device);
+
+	samsung_debugfs_exit(samsung);
+	samsung_leds_exit(samsung);
+	samsung_rfkill_exit(samsung);
+	samsung_backlight_exit(samsung);
+	samsung_sysfs_exit(samsung);
+	samsung_sabi_exit(samsung);
+	samsung_platform_exit(samsung);
+
+	kfree(samsung);
+	samsung_platform_device = NULL;
 }
 
 module_init(samsung_init);
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index c006dee..8a51795 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -127,7 +127,7 @@
 		 "default is -1 (automatic)");
 #endif
 
-static int kbd_backlight;	/* = 1 */
+static int kbd_backlight = 1;
 module_param(kbd_backlight, int, 0444);
 MODULE_PARM_DESC(kbd_backlight,
 		 "set this to 0 to disable keyboard backlight, "
@@ -347,6 +347,7 @@
 	struct input_dev *jog_dev = sony_laptop_input.jog_dev;
 	struct input_dev *key_dev = sony_laptop_input.key_dev;
 	struct sony_laptop_keypress kp = { NULL };
+	int scancode = -1;
 
 	if (event == SONYPI_EVENT_FNKEY_RELEASED ||
 			event == SONYPI_EVENT_ANYBUTTON_RELEASED) {
@@ -380,8 +381,8 @@
 			dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
 			break;
 		}
-		if (sony_laptop_input_index[event] != -1) {
-			kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]];
+		if ((scancode = sony_laptop_input_index[event]) != -1) {
+			kp.key = sony_laptop_input_keycode_map[scancode];
 			if (kp.key != KEY_UNKNOWN)
 				kp.dev = key_dev;
 		}
@@ -389,9 +390,11 @@
 	}
 
 	if (kp.dev) {
+		/* if we have a scancode we emit it so we can always
+		    remap the key */
+		if (scancode != -1)
+			input_event(kp.dev, EV_MSC, MSC_SCAN, scancode);
 		input_report_key(kp.dev, kp.key, 1);
-		/* we emit the scancode so we can always remap the key */
-		input_event(kp.dev, EV_MSC, MSC_SCAN, event);
 		input_sync(kp.dev);
 
 		/* schedule key release */
@@ -466,7 +469,7 @@
 	jog_dev->name = "Sony Vaio Jogdial";
 	jog_dev->id.bustype = BUS_ISA;
 	jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
-	key_dev->dev.parent = &acpi_device->dev;
+	jog_dev->dev.parent = &acpi_device->dev;
 
 	input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE);
 	input_set_capability(jog_dev, EV_REL, REL_WHEEL);
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index ea0c607..d68c000 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -8658,7 +8658,7 @@
 	}
 
 	s = dmi_get_system_info(DMI_PRODUCT_VERSION);
-	if (s && !strnicmp(s, "ThinkPad", 8)) {
+	if (s && !(strnicmp(s, "ThinkPad", 8) && strnicmp(s, "Lenovo", 6))) {
 		tp->model_str = kstrdup(s, GFP_KERNEL);
 		if (!tp->model_str)
 			return -ENOMEM;
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index dcdc1f4..ee79ce6 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -52,6 +52,8 @@
 #include <linux/input/sparse-keymap.h>
 #include <linux/leds.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/i8042.h>
 
 #include <asm/uaccess.h>
 
@@ -61,6 +63,11 @@
 MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
 MODULE_LICENSE("GPL");
 
+#define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
+
+/* Scan code for Fn key on TOS1900 models */
+#define TOS1900_FN_SCAN		0x6e
+
 /* Toshiba ACPI method paths */
 #define METHOD_VIDEO_OUT	"\\_SB_.VALX.DSSX"
 
@@ -95,6 +102,8 @@
 #define HCI_WIRELESS			0x0056
 
 /* field definitions */
+#define HCI_HOTKEY_DISABLE		0x0b
+#define HCI_HOTKEY_ENABLE		0x09
 #define HCI_LCD_BRIGHTNESS_BITS		3
 #define HCI_LCD_BRIGHTNESS_SHIFT	(16-HCI_LCD_BRIGHTNESS_BITS)
 #define HCI_LCD_BRIGHTNESS_LEVELS	(1 << HCI_LCD_BRIGHTNESS_BITS)
@@ -111,6 +120,7 @@
 	const char *method_hci;
 	struct rfkill *bt_rfk;
 	struct input_dev *hotkey_dev;
+	struct work_struct hotkey_work;
 	struct backlight_device *backlight_dev;
 	struct led_classdev led_dev;
 
@@ -118,14 +128,18 @@
 	int last_key_event;
 	int key_event_valid;
 
-	int illumination_supported:1;
-	int video_supported:1;
-	int fan_supported:1;
-	int system_event_supported:1;
+	unsigned int illumination_supported:1;
+	unsigned int video_supported:1;
+	unsigned int fan_supported:1;
+	unsigned int system_event_supported:1;
+	unsigned int ntfy_supported:1;
+	unsigned int info_supported:1;
 
 	struct mutex mutex;
 };
 
+static struct toshiba_acpi_dev *toshiba_acpi;
+
 static const struct acpi_device_id toshiba_device_ids[] = {
 	{"TOS6200", 0},
 	{"TOS6208", 0},
@@ -138,6 +152,8 @@
 	{ KE_KEY, 0x101, { KEY_MUTE } },
 	{ KE_KEY, 0x102, { KEY_ZOOMOUT } },
 	{ KE_KEY, 0x103, { KEY_ZOOMIN } },
+	{ KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
+	{ KE_KEY, 0x139, { KEY_ZOOMRESET } },
 	{ KE_KEY, 0x13b, { KEY_COFFEE } },
 	{ KE_KEY, 0x13c, { KEY_BATTERY } },
 	{ KE_KEY, 0x13d, { KEY_SLEEP } },
@@ -146,7 +162,7 @@
 	{ KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
 	{ KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
 	{ KE_KEY, 0x142, { KEY_WLAN } },
-	{ KE_KEY, 0x143, { KEY_PROG1 } },
+	{ KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } },
 	{ KE_KEY, 0x17f, { KEY_FN } },
 	{ KE_KEY, 0xb05, { KEY_PROG2 } },
 	{ KE_KEY, 0xb06, { KEY_WWW } },
@@ -156,6 +172,7 @@
 	{ KE_KEY, 0xb32, { KEY_NEXTSONG } },
 	{ KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
 	{ KE_KEY, 0xb5a, { KEY_MEDIA } },
+	{ KE_IGNORE, 0x1430, { KEY_RESERVED } },
 	{ KE_END, 0 },
 };
 
@@ -847,10 +864,78 @@
         .update_status  = set_lcd_status,
 };
 
+static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
+				      struct serio *port)
+{
+	if (str & 0x20)
+		return false;
+
+	if (unlikely(data == 0xe0))
+		return false;
+
+	if ((data & 0x7f) == TOS1900_FN_SCAN) {
+		schedule_work(&toshiba_acpi->hotkey_work);
+		return true;
+	}
+
+	return false;
+}
+
+static void toshiba_acpi_hotkey_work(struct work_struct *work)
+{
+	acpi_handle ec_handle = ec_get_handle();
+	acpi_status status;
+
+	if (!ec_handle)
+		return;
+
+	status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL);
+	if (ACPI_FAILURE(status))
+		pr_err("ACPI NTFY method execution failed\n");
+}
+
+/*
+ * Returns hotkey scancode, or < 0 on failure.
+ */
+static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev)
+{
+	struct acpi_buffer buf;
+	union acpi_object out_obj;
+	acpi_status status;
+
+	buf.pointer = &out_obj;
+	buf.length = sizeof(out_obj);
+
+	status = acpi_evaluate_object(dev->acpi_dev->handle, "INFO",
+				      NULL, &buf);
+	if (ACPI_FAILURE(status) || out_obj.type != ACPI_TYPE_INTEGER) {
+		pr_err("ACPI INFO method execution failed\n");
+		return -EIO;
+	}
+
+	return out_obj.integer.value;
+}
+
+static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
+				       int scancode)
+{
+	if (scancode == 0x100)
+		return;
+
+	/* act on key press; ignore key release */
+	if (scancode & 0x80)
+		return;
+
+	if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true))
+		pr_info("Unknown key %x\n", scancode);
+}
+
 static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
 {
 	acpi_status status;
+	acpi_handle ec_handle, handle;
 	int error;
+	u32 hci_result;
 
 	dev->hotkey_dev = input_allocate_device();
 	if (!dev->hotkey_dev) {
@@ -866,21 +951,67 @@
 	if (error)
 		goto err_free_dev;
 
+	/*
+	 * For some machines the SCI responsible for providing hotkey
+	 * notification doesn't fire. We can trigger the notification
+	 * whenever the Fn key is pressed using the NTFY method, if
+	 * supported, so if it's present set up an i8042 key filter
+	 * for this purpose.
+	 */
+	status = AE_ERROR;
+	ec_handle = ec_get_handle();
+	if (ec_handle)
+		status = acpi_get_handle(ec_handle, "NTFY", &handle);
+
+	if (ACPI_SUCCESS(status)) {
+		INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
+
+		error = i8042_install_filter(toshiba_acpi_i8042_filter);
+		if (error) {
+			pr_err("Error installing key filter\n");
+			goto err_free_keymap;
+		}
+
+		dev->ntfy_supported = 1;
+	}
+
+	/*
+	 * Determine hotkey query interface. Prefer using the INFO
+	 * method when it is available.
+	 */
+	status = acpi_get_handle(dev->acpi_dev->handle, "INFO", &handle);
+	if (ACPI_SUCCESS(status)) {
+		dev->info_supported = 1;
+	} else {
+		hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
+		if (hci_result == HCI_SUCCESS)
+			dev->system_event_supported = 1;
+	}
+
+	if (!dev->info_supported && !dev->system_event_supported) {
+		pr_warn("No hotkey query interface found\n");
+		goto err_remove_filter;
+	}
+
 	status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", NULL, NULL);
 	if (ACPI_FAILURE(status)) {
 		pr_info("Unable to enable hotkeys\n");
 		error = -ENODEV;
-		goto err_free_keymap;
+		goto err_remove_filter;
 	}
 
 	error = input_register_device(dev->hotkey_dev);
 	if (error) {
 		pr_info("Unable to register input device\n");
-		goto err_free_keymap;
+		goto err_remove_filter;
 	}
 
+	hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &hci_result);
 	return 0;
 
+ err_remove_filter:
+	if (dev->ntfy_supported)
+		i8042_remove_filter(toshiba_acpi_i8042_filter);
  err_free_keymap:
 	sparse_keymap_free(dev->hotkey_dev);
  err_free_dev:
@@ -895,6 +1026,11 @@
 
 	remove_toshiba_proc_entries(dev);
 
+	if (dev->ntfy_supported) {
+		i8042_remove_filter(toshiba_acpi_i8042_filter);
+		cancel_work_sync(&dev->hotkey_work);
+	}
+
 	if (dev->hotkey_dev) {
 		input_unregister_device(dev->hotkey_dev);
 		sparse_keymap_free(dev->hotkey_dev);
@@ -911,6 +1047,9 @@
 	if (dev->illumination_supported)
 		led_classdev_unregister(&dev->led_dev);
 
+	if (toshiba_acpi)
+		toshiba_acpi = NULL;
+
 	kfree(dev);
 
 	return 0;
@@ -936,12 +1075,14 @@
 {
 	struct toshiba_acpi_dev *dev;
 	const char *hci_method;
-	u32 hci_result;
 	u32 dummy;
 	bool bt_present;
 	int ret = 0;
 	struct backlight_properties props;
 
+	if (toshiba_acpi)
+		return -EBUSY;
+
 	pr_info("Toshiba Laptop ACPI Extras version %s\n",
 	       TOSHIBA_ACPI_VERSION);
 
@@ -963,11 +1104,6 @@
 
 	mutex_init(&dev->mutex);
 
-	/* enable event fifo */
-	hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
-	if (hci_result == HCI_SUCCESS)
-		dev->system_event_supported = 1;
-
 	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
 	dev->backlight_dev = backlight_device_register("toshiba",
@@ -1024,6 +1160,8 @@
 
 	create_toshiba_proc_entries(dev);
 
+	toshiba_acpi = dev;
+
 	return 0;
 
 error:
@@ -1036,40 +1174,64 @@
 	struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
 	u32 hci_result, value;
 	int retries = 3;
+	int scancode;
 
-	if (!dev->system_event_supported || event != 0x80)
+	if (event != 0x80)
 		return;
 
-	do {
-		hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
-		switch (hci_result) {
-		case HCI_SUCCESS:
-			if (value == 0x100)
-				continue;
-			/* act on key press; ignore key release */
-			if (value & 0x80)
-				continue;
-
-			if (!sparse_keymap_report_event(dev->hotkey_dev,
-							value, 1, true)) {
-				pr_info("Unknown key %x\n",
-				       value);
+	if (dev->info_supported) {
+		scancode = toshiba_acpi_query_hotkey(dev);
+		if (scancode < 0)
+			pr_err("Failed to query hotkey event\n");
+		else if (scancode != 0)
+			toshiba_acpi_report_hotkey(dev, scancode);
+	} else if (dev->system_event_supported) {
+		do {
+			hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
+			switch (hci_result) {
+			case HCI_SUCCESS:
+				toshiba_acpi_report_hotkey(dev, (int)value);
+				break;
+			case HCI_NOT_SUPPORTED:
+				/*
+				 * This is a workaround for an unresolved
+				 * issue on some machines where system events
+				 * sporadically become disabled.
+				 */
+				hci_write1(dev, HCI_SYSTEM_EVENT, 1,
+					   &hci_result);
+				pr_notice("Re-enabled hotkeys\n");
+				/* fall through */
+			default:
+				retries--;
+				break;
 			}
-			break;
-		case HCI_NOT_SUPPORTED:
-			/* This is a workaround for an unresolved issue on
-			 * some machines where system events sporadically
-			 * become disabled. */
-			hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
-			pr_notice("Re-enabled hotkeys\n");
-			/* fall through */
-		default:
-			retries--;
-			break;
-		}
-	} while (retries && hci_result != HCI_EMPTY);
+		} while (retries && hci_result != HCI_EMPTY);
+	}
 }
 
+static int toshiba_acpi_suspend(struct acpi_device *acpi_dev,
+				pm_message_t state)
+{
+	struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
+	u32 result;
+
+	if (dev->hotkey_dev)
+		hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE, &result);
+
+	return 0;
+}
+
+static int toshiba_acpi_resume(struct acpi_device *acpi_dev)
+{
+	struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
+	u32 result;
+
+	if (dev->hotkey_dev)
+		hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &result);
+
+	return 0;
+}
 
 static struct acpi_driver toshiba_acpi_driver = {
 	.name	= "Toshiba ACPI driver",
@@ -1080,6 +1242,8 @@
 		.add		= toshiba_acpi_add,
 		.remove		= toshiba_acpi_remove,
 		.notify		= toshiba_acpi_notify,
+		.suspend	= toshiba_acpi_suspend,
+		.resume		= toshiba_acpi_resume,
 	},
 };
 
@@ -1087,6 +1251,14 @@
 {
 	int ret;
 
+	/*
+	 * Machines with this WMI guid aren't supported due to bugs in
+	 * their AML. This check relies on wmi initializing before
+	 * toshiba_acpi to guarantee guids have been identified.
+	 */
+	if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
+		return -ENODEV;
+
 	toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
 	if (!toshiba_proc_dir) {
 		pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
diff --git a/drivers/platform/x86/xo1-rfkill.c b/drivers/platform/x86/xo1-rfkill.c
index e549eee..41781ed 100644
--- a/drivers/platform/x86/xo1-rfkill.c
+++ b/drivers/platform/x86/xo1-rfkill.c
@@ -67,19 +67,8 @@
 	.remove		= __devexit_p(xo1_rfkill_remove),
 };
 
-static int __init xo1_rfkill_init(void)
-{
-	return platform_driver_register(&xo1_rfkill_driver);
-}
-
-static void __exit xo1_rfkill_exit(void)
-{
-	platform_driver_unregister(&xo1_rfkill_driver);
-}
+module_platform_driver(xo1_rfkill_driver);
 
 MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:xo1-rfkill");
-
-module_init(xo1_rfkill_init);
-module_exit(xo1_rfkill_exit);
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index b00c176..d21e8f5 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -321,9 +321,14 @@
 {
 	struct acpi_device *acpi = to_acpi_device(dev);
 	struct pnp_dev *pnp = _pnp;
+	struct device *physical_device;
+
+	physical_device = acpi_get_physical_device(acpi->handle);
+	if (physical_device)
+		put_device(physical_device);
 
 	/* true means it matched */
-	return !acpi_get_physical_device(acpi->handle)
+	return !physical_device
 	    && compare_pnp_id(pnp->id, acpi_device_hid(acpi));
 }
 
diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c
index b859d16..769d265 100644
--- a/drivers/pnp/pnpbios/bioscalls.c
+++ b/drivers/pnp/pnpbios/bioscalls.c
@@ -17,7 +17,6 @@
 
 #include <asm/page.h>
 #include <asm/desc.h>
-#include <asm/system.h>
 #include <asm/byteorder.h>
 
 #include "pnpbios.h"
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index cfe8685..9d42226 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -65,7 +65,6 @@
 
 #include <asm/page.h>
 #include <asm/desc.h>
-#include <asm/system.h>
 #include <asm/byteorder.h>
 
 #include "../base.h"
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 459f664..99dc29f 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -249,7 +249,7 @@
 	  Say Y here to enable support for TWL4030 Battery Charge Interface.
 
 config CHARGER_LP8727
-	tristate "National Semiconductor LP8727 charger driver"
+	tristate "TI/National Semiconductor LP8727 charger driver"
 	depends on I2C
 	help
 	  Say Y here to enable support for LP8727 Charger Driver.
@@ -288,4 +288,23 @@
 	  Say Y to enable support for the battery charger control sysfs and
 	  platform data of MAX8998/LP3974 PMICs.
 
+config CHARGER_SMB347
+	tristate "Summit Microelectronics SMB347 Battery Charger"
+	depends on I2C
+	help
+	  Say Y to include support for Summit Microelectronics SMB347
+	  Battery Charger.
+
+config AB8500_BM
+	bool "AB8500 Battery Management Driver"
+	depends on AB8500_CORE && AB8500_GPADC
+	help
+	  Say Y to include support for AB5500 battery management.
+
+config AB8500_BATTERY_THERM_ON_BATCTRL
+	bool "Thermistor connected on BATCTRL ADC"
+	depends on AB8500_BM
+	help
+	  Say Y to enable battery temperature measurements using
+	  thermistor connected on BATCTRL ADC.
 endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index c590fa5..b6b2434 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -34,6 +34,7 @@
 obj-$(CONFIG_CHARGER_PCF50633)	+= pcf50633-charger.o
 obj-$(CONFIG_BATTERY_JZ4740)	+= jz4740-battery.o
 obj-$(CONFIG_BATTERY_INTEL_MID)	+= intel_mid_battery.o
+obj-$(CONFIG_AB8500_BM)		+= ab8500_charger.o ab8500_btemp.o ab8500_fg.o abx500_chargalg.o
 obj-$(CONFIG_CHARGER_ISP1704)	+= isp1704_charger.o
 obj-$(CONFIG_CHARGER_MAX8903)	+= max8903_charger.o
 obj-$(CONFIG_CHARGER_TWL4030)	+= twl4030_charger.o
@@ -42,3 +43,4 @@
 obj-$(CONFIG_CHARGER_MANAGER)	+= charger-manager.o
 obj-$(CONFIG_CHARGER_MAX8997)	+= max8997_charger.o
 obj-$(CONFIG_CHARGER_MAX8998)	+= max8998_charger.o
+obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
new file mode 100644
index 0000000..d8bb993
--- /dev/null
+++ b/drivers/power/ab8500_btemp.c
@@ -0,0 +1,1124 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Battery temperature driver for AB8500
+ *
+ * License Terms: GNU General Public License v2
+ * Author:
+ *	Johan Palsson <johan.palsson@stericsson.com>
+ *	Karl Komierowski <karl.komierowski@stericsson.com>
+ *	Arun R Murthy <arun.murthy@stericsson.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500-bm.h>
+#include <linux/mfd/abx500/ab8500-gpadc.h>
+#include <linux/jiffies.h>
+
+#define VTVOUT_V			1800
+
+#define BTEMP_THERMAL_LOW_LIMIT		-10
+#define BTEMP_THERMAL_MED_LIMIT		0
+#define BTEMP_THERMAL_HIGH_LIMIT_52	52
+#define BTEMP_THERMAL_HIGH_LIMIT_57	57
+#define BTEMP_THERMAL_HIGH_LIMIT_62	62
+
+#define BTEMP_BATCTRL_CURR_SRC_7UA	7
+#define BTEMP_BATCTRL_CURR_SRC_20UA	20
+
+#define to_ab8500_btemp_device_info(x) container_of((x), \
+	struct ab8500_btemp, btemp_psy);
+
+/**
+ * struct ab8500_btemp_interrupts - ab8500 interrupts
+ * @name:	name of the interrupt
+ * @isr		function pointer to the isr
+ */
+struct ab8500_btemp_interrupts {
+	char *name;
+	irqreturn_t (*isr)(int irq, void *data);
+};
+
+struct ab8500_btemp_events {
+	bool batt_rem;
+	bool btemp_high;
+	bool btemp_medhigh;
+	bool btemp_lowmed;
+	bool btemp_low;
+	bool ac_conn;
+	bool usb_conn;
+};
+
+struct ab8500_btemp_ranges {
+	int btemp_high_limit;
+	int btemp_med_limit;
+	int btemp_low_limit;
+};
+
+/**
+ * struct ab8500_btemp - ab8500 BTEMP device information
+ * @dev:		Pointer to the structure device
+ * @node:		List of AB8500 BTEMPs, hence prepared for reentrance
+ * @curr_source:	What current source we use, in uA
+ * @bat_temp:		Battery temperature in degree Celcius
+ * @prev_bat_temp	Last dispatched battery temperature
+ * @parent:		Pointer to the struct ab8500
+ * @gpadc:		Pointer to the struct gpadc
+ * @fg:			Pointer to the struct fg
+ * @pdata:		Pointer to the abx500_btemp platform data
+ * @bat:		Pointer to the abx500_bm platform data
+ * @btemp_psy:		Structure for BTEMP specific battery properties
+ * @events:		Structure for information about events triggered
+ * @btemp_ranges:	Battery temperature range structure
+ * @btemp_wq:		Work queue for measuring the temperature periodically
+ * @btemp_periodic_work:	Work for measuring the temperature periodically
+ */
+struct ab8500_btemp {
+	struct device *dev;
+	struct list_head node;
+	int curr_source;
+	int bat_temp;
+	int prev_bat_temp;
+	struct ab8500 *parent;
+	struct ab8500_gpadc *gpadc;
+	struct ab8500_fg *fg;
+	struct abx500_btemp_platform_data *pdata;
+	struct abx500_bm_data *bat;
+	struct power_supply btemp_psy;
+	struct ab8500_btemp_events events;
+	struct ab8500_btemp_ranges btemp_ranges;
+	struct workqueue_struct *btemp_wq;
+	struct delayed_work btemp_periodic_work;
+};
+
+/* BTEMP power supply properties */
+static enum power_supply_property ab8500_btemp_props[] = {
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_TEMP,
+};
+
+static LIST_HEAD(ab8500_btemp_list);
+
+/**
+ * ab8500_btemp_get() - returns a reference to the primary AB8500 BTEMP
+ * (i.e. the first BTEMP in the instance list)
+ */
+struct ab8500_btemp *ab8500_btemp_get(void)
+{
+	struct ab8500_btemp *btemp;
+	btemp = list_first_entry(&ab8500_btemp_list, struct ab8500_btemp, node);
+
+	return btemp;
+}
+
+/**
+ * ab8500_btemp_batctrl_volt_to_res() - convert batctrl voltage to resistance
+ * @di:		pointer to the ab8500_btemp structure
+ * @v_batctrl:	measured batctrl voltage
+ * @inst_curr:	measured instant current
+ *
+ * This function returns the battery resistance that is
+ * derived from the BATCTRL voltage.
+ * Returns value in Ohms.
+ */
+static int ab8500_btemp_batctrl_volt_to_res(struct ab8500_btemp *di,
+	int v_batctrl, int inst_curr)
+{
+	int rbs;
+
+	if (is_ab8500_1p1_or_earlier(di->parent)) {
+		/*
+		 * For ABB cut1.0 and 1.1 BAT_CTRL is internally
+		 * connected to 1.8V through a 450k resistor
+		 */
+		return (450000 * (v_batctrl)) / (1800 - v_batctrl);
+	}
+
+	if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL) {
+		/*
+		 * If the battery has internal NTC, we use the current
+		 * source to calculate the resistance, 7uA or 20uA
+		 */
+		rbs = (v_batctrl * 1000
+		       - di->bat->gnd_lift_resistance * inst_curr)
+		      / di->curr_source;
+	} else {
+		/*
+		 * BAT_CTRL is internally
+		 * connected to 1.8V through a 80k resistor
+		 */
+		rbs = (80000 * (v_batctrl)) / (1800 - v_batctrl);
+	}
+
+	return rbs;
+}
+
+/**
+ * ab8500_btemp_read_batctrl_voltage() - measure batctrl voltage
+ * @di:		pointer to the ab8500_btemp structure
+ *
+ * This function returns the voltage on BATCTRL. Returns value in mV.
+ */
+static int ab8500_btemp_read_batctrl_voltage(struct ab8500_btemp *di)
+{
+	int vbtemp;
+	static int prev;
+
+	vbtemp = ab8500_gpadc_convert(di->gpadc, BAT_CTRL);
+	if (vbtemp < 0) {
+		dev_err(di->dev,
+			"%s gpadc conversion failed, using previous value",
+			__func__);
+		return prev;
+	}
+	prev = vbtemp;
+	return vbtemp;
+}
+
+/**
+ * ab8500_btemp_curr_source_enable() - enable/disable batctrl current source
+ * @di:		pointer to the ab8500_btemp structure
+ * @enable:	enable or disable the current source
+ *
+ * Enable or disable the current sources for the BatCtrl AD channel
+ */
+static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di,
+	bool enable)
+{
+	int curr;
+	int ret = 0;
+
+	/*
+	 * BATCTRL current sources are included on AB8500 cut2.0
+	 * and future versions
+	 */
+	if (is_ab8500_1p1_or_earlier(di->parent))
+		return 0;
+
+	/* Only do this for batteries with internal NTC */
+	if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && enable) {
+		if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_7UA)
+			curr = BAT_CTRL_7U_ENA;
+		else
+			curr = BAT_CTRL_20U_ENA;
+
+		dev_dbg(di->dev, "Set BATCTRL %duA\n", di->curr_source);
+
+		ret = abx500_mask_and_set_register_interruptible(di->dev,
+			AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+			FORCE_BAT_CTRL_CMP_HIGH, FORCE_BAT_CTRL_CMP_HIGH);
+		if (ret) {
+			dev_err(di->dev, "%s failed setting cmp_force\n",
+				__func__);
+			return ret;
+		}
+
+		/*
+		 * We have to wait one 32kHz cycle before enabling
+		 * the current source, since ForceBatCtrlCmpHigh needs
+		 * to be written in a separate cycle
+		 */
+		udelay(32);
+
+		ret = abx500_set_register_interruptible(di->dev,
+			AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+			FORCE_BAT_CTRL_CMP_HIGH | curr);
+		if (ret) {
+			dev_err(di->dev, "%s failed enabling current source\n",
+				__func__);
+			goto disable_curr_source;
+		}
+	} else if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && !enable) {
+		dev_dbg(di->dev, "Disable BATCTRL curr source\n");
+
+		/* Write 0 to the curr bits */
+		ret = abx500_mask_and_set_register_interruptible(di->dev,
+			AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+			BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA,
+			~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA));
+		if (ret) {
+			dev_err(di->dev, "%s failed disabling current source\n",
+				__func__);
+			goto disable_curr_source;
+		}
+
+		/* Enable Pull-Up and comparator */
+		ret = abx500_mask_and_set_register_interruptible(di->dev,
+			AB8500_CHARGER,	AB8500_BAT_CTRL_CURRENT_SOURCE,
+			BAT_CTRL_PULL_UP_ENA | BAT_CTRL_CMP_ENA,
+			BAT_CTRL_PULL_UP_ENA | BAT_CTRL_CMP_ENA);
+		if (ret) {
+			dev_err(di->dev, "%s failed enabling PU and comp\n",
+				__func__);
+			goto enable_pu_comp;
+		}
+
+		/*
+		 * We have to wait one 32kHz cycle before disabling
+		 * ForceBatCtrlCmpHigh since this needs to be written
+		 * in a separate cycle
+		 */
+		udelay(32);
+
+		/* Disable 'force comparator' */
+		ret = abx500_mask_and_set_register_interruptible(di->dev,
+			AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+			FORCE_BAT_CTRL_CMP_HIGH, ~FORCE_BAT_CTRL_CMP_HIGH);
+		if (ret) {
+			dev_err(di->dev, "%s failed disabling force comp\n",
+				__func__);
+			goto disable_force_comp;
+		}
+	}
+	return ret;
+
+	/*
+	 * We have to try unsetting FORCE_BAT_CTRL_CMP_HIGH one more time
+	 * if we got an error above
+	 */
+disable_curr_source:
+	/* Write 0 to the curr bits */
+	ret = abx500_mask_and_set_register_interruptible(di->dev,
+			AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+			BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA,
+			~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA));
+	if (ret) {
+		dev_err(di->dev, "%s failed disabling current source\n",
+			__func__);
+		return ret;
+	}
+enable_pu_comp:
+	/* Enable Pull-Up and comparator */
+	ret = abx500_mask_and_set_register_interruptible(di->dev,
+		AB8500_CHARGER,	AB8500_BAT_CTRL_CURRENT_SOURCE,
+		BAT_CTRL_PULL_UP_ENA | BAT_CTRL_CMP_ENA,
+		BAT_CTRL_PULL_UP_ENA | BAT_CTRL_CMP_ENA);
+	if (ret) {
+		dev_err(di->dev, "%s failed enabling PU and comp\n",
+			__func__);
+		return ret;
+	}
+
+disable_force_comp:
+	/*
+	 * We have to wait one 32kHz cycle before disabling
+	 * ForceBatCtrlCmpHigh since this needs to be written
+	 * in a separate cycle
+	 */
+	udelay(32);
+
+	/* Disable 'force comparator' */
+	ret = abx500_mask_and_set_register_interruptible(di->dev,
+		AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+		FORCE_BAT_CTRL_CMP_HIGH, ~FORCE_BAT_CTRL_CMP_HIGH);
+	if (ret) {
+		dev_err(di->dev, "%s failed disabling force comp\n",
+			__func__);
+		return ret;
+	}
+
+	return ret;
+}
+
+/**
+ * ab8500_btemp_get_batctrl_res() - get battery resistance
+ * @di:		pointer to the ab8500_btemp structure
+ *
+ * This function returns the battery pack identification resistance.
+ * Returns value in Ohms.
+ */
+static int ab8500_btemp_get_batctrl_res(struct ab8500_btemp *di)
+{
+	int ret;
+	int batctrl = 0;
+	int res;
+	int inst_curr;
+	int i;
+
+	/*
+	 * BATCTRL current sources are included on AB8500 cut2.0
+	 * and future versions
+	 */
+	ret = ab8500_btemp_curr_source_enable(di, true);
+	if (ret) {
+		dev_err(di->dev, "%s curr source enabled failed\n", __func__);
+		return ret;
+	}
+
+	if (!di->fg)
+		di->fg = ab8500_fg_get();
+	if (!di->fg) {
+		dev_err(di->dev, "No fg found\n");
+		return -EINVAL;
+	}
+
+	ret = ab8500_fg_inst_curr_start(di->fg);
+
+	if (ret) {
+		dev_err(di->dev, "Failed to start current measurement\n");
+		return ret;
+	}
+
+	/*
+	 * Since there is no interrupt when current measurement is done,
+	 * loop for over 250ms (250ms is one sample conversion time
+	 * with 32.768 Khz RTC clock). Note that a stop time must be set
+	 * since the ab8500_btemp_read_batctrl_voltage call can block and
+	 * take an unknown amount of time to complete.
+	 */
+	i = 0;
+
+	do {
+		batctrl += ab8500_btemp_read_batctrl_voltage(di);
+		i++;
+		msleep(20);
+	} while (!ab8500_fg_inst_curr_done(di->fg));
+	batctrl /= i;
+
+	ret = ab8500_fg_inst_curr_finalize(di->fg, &inst_curr);
+	if (ret) {
+		dev_err(di->dev, "Failed to finalize current measurement\n");
+		return ret;
+	}
+
+	res = ab8500_btemp_batctrl_volt_to_res(di, batctrl, inst_curr);
+
+	ret = ab8500_btemp_curr_source_enable(di, false);
+	if (ret) {
+		dev_err(di->dev, "%s curr source disable failed\n", __func__);
+		return ret;
+	}
+
+	dev_dbg(di->dev, "%s batctrl: %d res: %d inst_curr: %d samples: %d\n",
+		__func__, batctrl, res, inst_curr, i);
+
+	return res;
+}
+
+/**
+ * ab8500_btemp_res_to_temp() - resistance to temperature
+ * @di:		pointer to the ab8500_btemp structure
+ * @tbl:	pointer to the resiatance to temperature table
+ * @tbl_size:	size of the resistance to temperature table
+ * @res:	resistance to calculate the temperature from
+ *
+ * This function returns the battery temperature in degrees Celcius
+ * based on the NTC resistance.
+ */
+static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di,
+	const struct abx500_res_to_temp *tbl, int tbl_size, int res)
+{
+	int i, temp;
+	/*
+	 * Calculate the formula for the straight line
+	 * Simple interpolation if we are within
+	 * the resistance table limits, extrapolate
+	 * if resistance is outside the limits.
+	 */
+	if (res > tbl[0].resist)
+		i = 0;
+	else if (res <= tbl[tbl_size - 1].resist)
+		i = tbl_size - 2;
+	else {
+		i = 0;
+		while (!(res <= tbl[i].resist &&
+			res > tbl[i + 1].resist))
+			i++;
+	}
+
+	temp = tbl[i].temp + ((tbl[i + 1].temp - tbl[i].temp) *
+		(res - tbl[i].resist)) / (tbl[i + 1].resist - tbl[i].resist);
+	return temp;
+}
+
+/**
+ * ab8500_btemp_measure_temp() - measure battery temperature
+ * @di:		pointer to the ab8500_btemp structure
+ *
+ * Returns battery temperature (on success) else the previous temperature
+ */
+static int ab8500_btemp_measure_temp(struct ab8500_btemp *di)
+{
+	int temp;
+	static int prev;
+	int rbat, rntc, vntc;
+	u8 id;
+
+	id = di->bat->batt_id;
+
+	if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL &&
+			id != BATTERY_UNKNOWN) {
+
+		rbat = ab8500_btemp_get_batctrl_res(di);
+		if (rbat < 0) {
+			dev_err(di->dev, "%s get batctrl res failed\n",
+				__func__);
+			/*
+			 * Return out-of-range temperature so that
+			 * charging is stopped
+			 */
+			return BTEMP_THERMAL_LOW_LIMIT;
+		}
+
+		temp = ab8500_btemp_res_to_temp(di,
+			di->bat->bat_type[id].r_to_t_tbl,
+			di->bat->bat_type[id].n_temp_tbl_elements, rbat);
+	} else {
+		vntc = ab8500_gpadc_convert(di->gpadc, BTEMP_BALL);
+		if (vntc < 0) {
+			dev_err(di->dev,
+				"%s gpadc conversion failed,"
+				" using previous value\n", __func__);
+			return prev;
+		}
+		/*
+		 * The PCB NTC is sourced from VTVOUT via a 230kOhm
+		 * resistor.
+		 */
+		rntc = 230000 * vntc / (VTVOUT_V - vntc);
+
+		temp = ab8500_btemp_res_to_temp(di,
+			di->bat->bat_type[id].r_to_t_tbl,
+			di->bat->bat_type[id].n_temp_tbl_elements, rntc);
+		prev = temp;
+	}
+	dev_dbg(di->dev, "Battery temperature is %d\n", temp);
+	return temp;
+}
+
+/**
+ * ab8500_btemp_id() - Identify the connected battery
+ * @di:		pointer to the ab8500_btemp structure
+ *
+ * This function will try to identify the battery by reading the ID
+ * resistor. Some brands use a combined ID resistor with a NTC resistor to
+ * both be able to identify and to read the temperature of it.
+ */
+static int ab8500_btemp_id(struct ab8500_btemp *di)
+{
+	int res;
+	u8 i;
+
+	di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA;
+	di->bat->batt_id = BATTERY_UNKNOWN;
+
+	res =  ab8500_btemp_get_batctrl_res(di);
+	if (res < 0) {
+		dev_err(di->dev, "%s get batctrl res failed\n", __func__);
+		return -ENXIO;
+	}
+
+	/* BATTERY_UNKNOWN is defined on position 0, skip it! */
+	for (i = BATTERY_UNKNOWN + 1; i < di->bat->n_btypes; i++) {
+		if ((res <= di->bat->bat_type[i].resis_high) &&
+			(res >= di->bat->bat_type[i].resis_low)) {
+			dev_dbg(di->dev, "Battery detected on %s"
+				" low %d < res %d < high: %d"
+				" index: %d\n",
+				di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL ?
+				"BATCTRL" : "BATTEMP",
+				di->bat->bat_type[i].resis_low, res,
+				di->bat->bat_type[i].resis_high, i);
+
+			di->bat->batt_id = i;
+			break;
+		}
+	}
+
+	if (di->bat->batt_id == BATTERY_UNKNOWN) {
+		dev_warn(di->dev, "Battery identified as unknown"
+			", resistance %d Ohm\n", res);
+		return -ENXIO;
+	}
+
+	/*
+	 * We only have to change current source if the
+	 * detected type is Type 1, else we use the 7uA source
+	 */
+	if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL &&
+			di->bat->batt_id == 1) {
+		dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n");
+		di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA;
+	}
+
+	return di->bat->batt_id;
+}
+
+/**
+ * ab8500_btemp_periodic_work() - Measuring the temperature periodically
+ * @work:	pointer to the work_struct structure
+ *
+ * Work function for measuring the temperature periodically
+ */
+static void ab8500_btemp_periodic_work(struct work_struct *work)
+{
+	int interval;
+	struct ab8500_btemp *di = container_of(work,
+		struct ab8500_btemp, btemp_periodic_work.work);
+
+	di->bat_temp = ab8500_btemp_measure_temp(di);
+
+	if (di->bat_temp != di->prev_bat_temp) {
+		di->prev_bat_temp = di->bat_temp;
+		power_supply_changed(&di->btemp_psy);
+	}
+
+	if (di->events.ac_conn || di->events.usb_conn)
+		interval = di->bat->temp_interval_chg;
+	else
+		interval = di->bat->temp_interval_nochg;
+
+	/* Schedule a new measurement */
+	queue_delayed_work(di->btemp_wq,
+		&di->btemp_periodic_work,
+		round_jiffies(interval * HZ));
+}
+
+/**
+ * ab8500_btemp_batctrlindb_handler() - battery removal detected
+ * @irq:       interrupt number
+ * @_di:       void pointer that has to address of ab8500_btemp
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_btemp_batctrlindb_handler(int irq, void *_di)
+{
+	struct ab8500_btemp *di = _di;
+	dev_err(di->dev, "Battery removal detected!\n");
+
+	di->events.batt_rem = true;
+	power_supply_changed(&di->btemp_psy);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_btemp_templow_handler() - battery temp lower than 10 degrees
+ * @irq:       interrupt number
+ * @_di:       void pointer that has to address of ab8500_btemp
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_btemp_templow_handler(int irq, void *_di)
+{
+	struct ab8500_btemp *di = _di;
+
+	if (is_ab8500_2p0_or_earlier(di->parent)) {
+		dev_dbg(di->dev, "Ignore false btemp low irq"
+			" for ABB cut 1.0, 1.1 and 2.0\n");
+	} else {
+		dev_crit(di->dev, "Battery temperature lower than -10deg c\n");
+
+		di->events.btemp_low = true;
+		di->events.btemp_high = false;
+		di->events.btemp_medhigh = false;
+		di->events.btemp_lowmed = false;
+		power_supply_changed(&di->btemp_psy);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_btemp_temphigh_handler() - battery temp higher than max temp
+ * @irq:       interrupt number
+ * @_di:       void pointer that has to address of ab8500_btemp
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_btemp_temphigh_handler(int irq, void *_di)
+{
+	struct ab8500_btemp *di = _di;
+
+	dev_crit(di->dev, "Battery temperature is higher than MAX temp\n");
+
+	di->events.btemp_high = true;
+	di->events.btemp_medhigh = false;
+	di->events.btemp_lowmed = false;
+	di->events.btemp_low = false;
+	power_supply_changed(&di->btemp_psy);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_btemp_lowmed_handler() - battery temp between low and medium
+ * @irq:       interrupt number
+ * @_di:       void pointer that has to address of ab8500_btemp
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_btemp_lowmed_handler(int irq, void *_di)
+{
+	struct ab8500_btemp *di = _di;
+
+	dev_dbg(di->dev, "Battery temperature is between low and medium\n");
+
+	di->events.btemp_lowmed = true;
+	di->events.btemp_medhigh = false;
+	di->events.btemp_high = false;
+	di->events.btemp_low = false;
+	power_supply_changed(&di->btemp_psy);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_btemp_medhigh_handler() - battery temp between medium and high
+ * @irq:       interrupt number
+ * @_di:       void pointer that has to address of ab8500_btemp
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_btemp_medhigh_handler(int irq, void *_di)
+{
+	struct ab8500_btemp *di = _di;
+
+	dev_dbg(di->dev, "Battery temperature is between medium and high\n");
+
+	di->events.btemp_medhigh = true;
+	di->events.btemp_lowmed = false;
+	di->events.btemp_high = false;
+	di->events.btemp_low = false;
+	power_supply_changed(&di->btemp_psy);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_btemp_periodic() - Periodic temperature measurements
+ * @di:		pointer to the ab8500_btemp structure
+ * @enable:	enable or disable periodic temperature measurements
+ *
+ * Starts of stops periodic temperature measurements. Periodic measurements
+ * should only be done when a charger is connected.
+ */
+static void ab8500_btemp_periodic(struct ab8500_btemp *di,
+	bool enable)
+{
+	dev_dbg(di->dev, "Enable periodic temperature measurements: %d\n",
+		enable);
+	/*
+	 * Make sure a new measurement is done directly by cancelling
+	 * any pending work
+	 */
+	cancel_delayed_work_sync(&di->btemp_periodic_work);
+
+	if (enable)
+		queue_delayed_work(di->btemp_wq, &di->btemp_periodic_work, 0);
+}
+
+/**
+ * ab8500_btemp_get_temp() - get battery temperature
+ * @di:		pointer to the ab8500_btemp structure
+ *
+ * Returns battery temperature
+ */
+static int ab8500_btemp_get_temp(struct ab8500_btemp *di)
+{
+	int temp = 0;
+
+	/*
+	 * The BTEMP events are not reliabe on AB8500 cut2.0
+	 * and prior versions
+	 */
+	if (is_ab8500_2p0_or_earlier(di->parent)) {
+		temp = di->bat_temp * 10;
+	} else {
+		if (di->events.btemp_low) {
+			if (temp > di->btemp_ranges.btemp_low_limit)
+				temp = di->btemp_ranges.btemp_low_limit;
+			else
+				temp = di->bat_temp * 10;
+		} else if (di->events.btemp_high) {
+			if (temp < di->btemp_ranges.btemp_high_limit)
+				temp = di->btemp_ranges.btemp_high_limit;
+			else
+				temp = di->bat_temp * 10;
+		} else if (di->events.btemp_lowmed) {
+			if (temp > di->btemp_ranges.btemp_med_limit)
+				temp = di->btemp_ranges.btemp_med_limit;
+			else
+				temp = di->bat_temp * 10;
+		} else if (di->events.btemp_medhigh) {
+			if (temp < di->btemp_ranges.btemp_med_limit)
+				temp = di->btemp_ranges.btemp_med_limit;
+			else
+				temp = di->bat_temp * 10;
+		} else
+			temp = di->bat_temp * 10;
+	}
+	return temp;
+}
+
+/**
+ * ab8500_btemp_get_batctrl_temp() - get the temperature
+ * @btemp:      pointer to the btemp structure
+ *
+ * Returns the batctrl temperature in millidegrees
+ */
+int ab8500_btemp_get_batctrl_temp(struct ab8500_btemp *btemp)
+{
+	return btemp->bat_temp * 1000;
+}
+
+/**
+ * ab8500_btemp_get_property() - get the btemp properties
+ * @psy:        pointer to the power_supply structure
+ * @psp:        pointer to the power_supply_property structure
+ * @val:        pointer to the power_supply_propval union
+ *
+ * This function gets called when an application tries to get the btemp
+ * properties by reading the sysfs files.
+ * online:	presence of the battery
+ * present:	presence of the battery
+ * technology:	battery technology
+ * temp:	battery temperature
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_btemp_get_property(struct power_supply *psy,
+	enum power_supply_property psp,
+	union power_supply_propval *val)
+{
+	struct ab8500_btemp *di;
+
+	di = to_ab8500_btemp_device_info(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_PRESENT:
+	case POWER_SUPPLY_PROP_ONLINE:
+		if (di->events.batt_rem)
+			val->intval = 0;
+		else
+			val->intval = 1;
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = di->bat->bat_type[di->bat->batt_id].name;
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		val->intval = ab8500_btemp_get_temp(di);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int ab8500_btemp_get_ext_psy_data(struct device *dev, void *data)
+{
+	struct power_supply *psy;
+	struct power_supply *ext;
+	struct ab8500_btemp *di;
+	union power_supply_propval ret;
+	int i, j;
+	bool psy_found = false;
+
+	psy = (struct power_supply *)data;
+	ext = dev_get_drvdata(dev);
+	di = to_ab8500_btemp_device_info(psy);
+
+	/*
+	 * For all psy where the name of your driver
+	 * appears in any supplied_to
+	 */
+	for (i = 0; i < ext->num_supplicants; i++) {
+		if (!strcmp(ext->supplied_to[i], psy->name))
+			psy_found = true;
+	}
+
+	if (!psy_found)
+		return 0;
+
+	/* Go through all properties for the psy */
+	for (j = 0; j < ext->num_properties; j++) {
+		enum power_supply_property prop;
+		prop = ext->properties[j];
+
+		if (ext->get_property(ext, prop, &ret))
+			continue;
+
+		switch (prop) {
+		case POWER_SUPPLY_PROP_PRESENT:
+			switch (ext->type) {
+			case POWER_SUPPLY_TYPE_MAINS:
+				/* AC disconnected */
+				if (!ret.intval && di->events.ac_conn) {
+					di->events.ac_conn = false;
+				}
+				/* AC connected */
+				else if (ret.intval && !di->events.ac_conn) {
+					di->events.ac_conn = true;
+					if (!di->events.usb_conn)
+						ab8500_btemp_periodic(di, true);
+				}
+				break;
+			case POWER_SUPPLY_TYPE_USB:
+				/* USB disconnected */
+				if (!ret.intval && di->events.usb_conn) {
+					di->events.usb_conn = false;
+				}
+				/* USB connected */
+				else if (ret.intval && !di->events.usb_conn) {
+					di->events.usb_conn = true;
+					if (!di->events.ac_conn)
+						ab8500_btemp_periodic(di, true);
+				}
+				break;
+			default:
+				break;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	return 0;
+}
+
+/**
+ * ab8500_btemp_external_power_changed() - callback for power supply changes
+ * @psy:       pointer to the structure power_supply
+ *
+ * This function is pointing to the function pointer external_power_changed
+ * of the structure power_supply.
+ * This function gets executed when there is a change in the external power
+ * supply to the btemp.
+ */
+static void ab8500_btemp_external_power_changed(struct power_supply *psy)
+{
+	struct ab8500_btemp *di = to_ab8500_btemp_device_info(psy);
+
+	class_for_each_device(power_supply_class, NULL,
+		&di->btemp_psy, ab8500_btemp_get_ext_psy_data);
+}
+
+/* ab8500 btemp driver interrupts and their respective isr */
+static struct ab8500_btemp_interrupts ab8500_btemp_irq[] = {
+	{"BAT_CTRL_INDB", ab8500_btemp_batctrlindb_handler},
+	{"BTEMP_LOW", ab8500_btemp_templow_handler},
+	{"BTEMP_HIGH", ab8500_btemp_temphigh_handler},
+	{"BTEMP_LOW_MEDIUM", ab8500_btemp_lowmed_handler},
+	{"BTEMP_MEDIUM_HIGH", ab8500_btemp_medhigh_handler},
+};
+
+#if defined(CONFIG_PM)
+static int ab8500_btemp_resume(struct platform_device *pdev)
+{
+	struct ab8500_btemp *di = platform_get_drvdata(pdev);
+
+	ab8500_btemp_periodic(di, true);
+
+	return 0;
+}
+
+static int ab8500_btemp_suspend(struct platform_device *pdev,
+	pm_message_t state)
+{
+	struct ab8500_btemp *di = platform_get_drvdata(pdev);
+
+	ab8500_btemp_periodic(di, false);
+
+	return 0;
+}
+#else
+#define ab8500_btemp_suspend      NULL
+#define ab8500_btemp_resume       NULL
+#endif
+
+static int __devexit ab8500_btemp_remove(struct platform_device *pdev)
+{
+	struct ab8500_btemp *di = platform_get_drvdata(pdev);
+	int i, irq;
+
+	/* Disable interrupts */
+	for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) {
+		irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
+		free_irq(irq, di);
+	}
+
+	/* Delete the work queue */
+	destroy_workqueue(di->btemp_wq);
+
+	flush_scheduled_work();
+	power_supply_unregister(&di->btemp_psy);
+	platform_set_drvdata(pdev, NULL);
+	kfree(di);
+
+	return 0;
+}
+
+static int __devinit ab8500_btemp_probe(struct platform_device *pdev)
+{
+	int irq, i, ret = 0;
+	u8 val;
+	struct abx500_bm_plat_data *plat_data;
+
+	struct ab8500_btemp *di =
+		kzalloc(sizeof(struct ab8500_btemp), GFP_KERNEL);
+	if (!di)
+		return -ENOMEM;
+
+	/* get parent data */
+	di->dev = &pdev->dev;
+	di->parent = dev_get_drvdata(pdev->dev.parent);
+	di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+
+	/* get btemp specific platform data */
+	plat_data = pdev->dev.platform_data;
+	di->pdata = plat_data->btemp;
+	if (!di->pdata) {
+		dev_err(di->dev, "no btemp platform data supplied\n");
+		ret = -EINVAL;
+		goto free_device_info;
+	}
+
+	/* get battery specific platform data */
+	di->bat = plat_data->battery;
+	if (!di->bat) {
+		dev_err(di->dev, "no battery platform data supplied\n");
+		ret = -EINVAL;
+		goto free_device_info;
+	}
+
+	/* BTEMP supply */
+	di->btemp_psy.name = "ab8500_btemp";
+	di->btemp_psy.type = POWER_SUPPLY_TYPE_BATTERY;
+	di->btemp_psy.properties = ab8500_btemp_props;
+	di->btemp_psy.num_properties = ARRAY_SIZE(ab8500_btemp_props);
+	di->btemp_psy.get_property = ab8500_btemp_get_property;
+	di->btemp_psy.supplied_to = di->pdata->supplied_to;
+	di->btemp_psy.num_supplicants = di->pdata->num_supplicants;
+	di->btemp_psy.external_power_changed =
+		ab8500_btemp_external_power_changed;
+
+
+	/* Create a work queue for the btemp */
+	di->btemp_wq =
+		create_singlethread_workqueue("ab8500_btemp_wq");
+	if (di->btemp_wq == NULL) {
+		dev_err(di->dev, "failed to create work queue\n");
+		goto free_device_info;
+	}
+
+	/* Init work for measuring temperature periodically */
+	INIT_DELAYED_WORK_DEFERRABLE(&di->btemp_periodic_work,
+		ab8500_btemp_periodic_work);
+
+	/* Identify the battery */
+	if (ab8500_btemp_id(di) < 0)
+		dev_warn(di->dev, "failed to identify the battery\n");
+
+	/* Set BTEMP thermal limits. Low and Med are fixed */
+	di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT;
+	di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT;
+
+	ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+		AB8500_BTEMP_HIGH_TH, &val);
+	if (ret < 0) {
+		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+		goto free_btemp_wq;
+	}
+	switch (val) {
+	case BTEMP_HIGH_TH_57_0:
+	case BTEMP_HIGH_TH_57_1:
+		di->btemp_ranges.btemp_high_limit =
+			BTEMP_THERMAL_HIGH_LIMIT_57;
+		break;
+	case BTEMP_HIGH_TH_52:
+		di->btemp_ranges.btemp_high_limit =
+			BTEMP_THERMAL_HIGH_LIMIT_52;
+		break;
+	case BTEMP_HIGH_TH_62:
+		di->btemp_ranges.btemp_high_limit =
+			BTEMP_THERMAL_HIGH_LIMIT_62;
+		break;
+	}
+
+	/* Register BTEMP power supply class */
+	ret = power_supply_register(di->dev, &di->btemp_psy);
+	if (ret) {
+		dev_err(di->dev, "failed to register BTEMP psy\n");
+		goto free_btemp_wq;
+	}
+
+	/* Register interrupts */
+	for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) {
+		irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
+		ret = request_threaded_irq(irq, NULL, ab8500_btemp_irq[i].isr,
+			IRQF_SHARED | IRQF_NO_SUSPEND,
+			ab8500_btemp_irq[i].name, di);
+
+		if (ret) {
+			dev_err(di->dev, "failed to request %s IRQ %d: %d\n"
+				, ab8500_btemp_irq[i].name, irq, ret);
+			goto free_irq;
+		}
+		dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
+			ab8500_btemp_irq[i].name, irq, ret);
+	}
+
+	platform_set_drvdata(pdev, di);
+
+	/* Kick off periodic temperature measurements */
+	ab8500_btemp_periodic(di, true);
+	list_add_tail(&di->node, &ab8500_btemp_list);
+
+	return ret;
+
+free_irq:
+	power_supply_unregister(&di->btemp_psy);
+
+	/* We also have to free all successfully registered irqs */
+	for (i = i - 1; i >= 0; i--) {
+		irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
+		free_irq(irq, di);
+	}
+free_btemp_wq:
+	destroy_workqueue(di->btemp_wq);
+free_device_info:
+	kfree(di);
+
+	return ret;
+}
+
+static struct platform_driver ab8500_btemp_driver = {
+	.probe = ab8500_btemp_probe,
+	.remove = __devexit_p(ab8500_btemp_remove),
+	.suspend = ab8500_btemp_suspend,
+	.resume = ab8500_btemp_resume,
+	.driver = {
+		.name = "ab8500-btemp",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init ab8500_btemp_init(void)
+{
+	return platform_driver_register(&ab8500_btemp_driver);
+}
+
+static void __exit ab8500_btemp_exit(void)
+{
+	platform_driver_unregister(&ab8500_btemp_driver);
+}
+
+subsys_initcall_sync(ab8500_btemp_init);
+module_exit(ab8500_btemp_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy");
+MODULE_ALIAS("platform:ab8500-btemp");
+MODULE_DESCRIPTION("AB8500 battery temperature driver");
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
new file mode 100644
index 0000000..e2b4acc
--- /dev/null
+++ b/drivers/power/ab8500_charger.c
@@ -0,0 +1,2789 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Charger driver for AB8500
+ *
+ * License Terms: GNU General Public License v2
+ * Author:
+ *	Johan Palsson <johan.palsson@stericsson.com>
+ *	Karl Komierowski <karl.komierowski@stericsson.com>
+ *	Arun R Murthy <arun.murthy@stericsson.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/completion.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500-bm.h>
+#include <linux/mfd/abx500/ab8500-gpadc.h>
+#include <linux/mfd/abx500/ux500_chargalg.h>
+#include <linux/usb/otg.h>
+
+/* Charger constants */
+#define NO_PW_CONN			0
+#define AC_PW_CONN			1
+#define USB_PW_CONN			2
+
+#define MAIN_WDOG_ENA			0x01
+#define MAIN_WDOG_KICK			0x02
+#define MAIN_WDOG_DIS			0x00
+#define CHARG_WD_KICK			0x01
+#define MAIN_CH_ENA			0x01
+#define MAIN_CH_NO_OVERSHOOT_ENA_N	0x02
+#define USB_CH_ENA			0x01
+#define USB_CHG_NO_OVERSHOOT_ENA_N	0x02
+#define MAIN_CH_DET			0x01
+#define MAIN_CH_CV_ON			0x04
+#define USB_CH_CV_ON			0x08
+#define VBUS_DET_DBNC100		0x02
+#define VBUS_DET_DBNC1			0x01
+#define OTP_ENABLE_WD			0x01
+
+#define MAIN_CH_INPUT_CURR_SHIFT	4
+#define VBUS_IN_CURR_LIM_SHIFT		4
+
+#define LED_INDICATOR_PWM_ENA		0x01
+#define LED_INDICATOR_PWM_DIS		0x00
+#define LED_IND_CUR_5MA			0x04
+#define LED_INDICATOR_PWM_DUTY_252_256	0xBF
+
+/* HW failure constants */
+#define MAIN_CH_TH_PROT			0x02
+#define VBUS_CH_NOK			0x08
+#define USB_CH_TH_PROT			0x02
+#define VBUS_OVV_TH			0x01
+#define MAIN_CH_NOK			0x01
+#define VBUS_DET			0x80
+
+/* UsbLineStatus register bit masks */
+#define AB8500_USB_LINK_STATUS		0x78
+#define AB8500_STD_HOST_SUSP		0x18
+
+/* Watchdog timeout constant */
+#define WD_TIMER			0x30 /* 4min */
+#define WD_KICK_INTERVAL		(60 * HZ)
+
+/* Lowest charger voltage is 3.39V -> 0x4E */
+#define LOW_VOLT_REG			0x4E
+
+/* UsbLineStatus register - usb types */
+enum ab8500_charger_link_status {
+	USB_STAT_NOT_CONFIGURED,
+	USB_STAT_STD_HOST_NC,
+	USB_STAT_STD_HOST_C_NS,
+	USB_STAT_STD_HOST_C_S,
+	USB_STAT_HOST_CHG_NM,
+	USB_STAT_HOST_CHG_HS,
+	USB_STAT_HOST_CHG_HS_CHIRP,
+	USB_STAT_DEDICATED_CHG,
+	USB_STAT_ACA_RID_A,
+	USB_STAT_ACA_RID_B,
+	USB_STAT_ACA_RID_C_NM,
+	USB_STAT_ACA_RID_C_HS,
+	USB_STAT_ACA_RID_C_HS_CHIRP,
+	USB_STAT_HM_IDGND,
+	USB_STAT_RESERVED,
+	USB_STAT_NOT_VALID_LINK,
+};
+
+enum ab8500_usb_state {
+	AB8500_BM_USB_STATE_RESET_HS,	/* HighSpeed Reset */
+	AB8500_BM_USB_STATE_RESET_FS,	/* FullSpeed/LowSpeed Reset */
+	AB8500_BM_USB_STATE_CONFIGURED,
+	AB8500_BM_USB_STATE_SUSPEND,
+	AB8500_BM_USB_STATE_RESUME,
+	AB8500_BM_USB_STATE_MAX,
+};
+
+/* VBUS input current limits supported in AB8500 in mA */
+#define USB_CH_IP_CUR_LVL_0P05		50
+#define USB_CH_IP_CUR_LVL_0P09		98
+#define USB_CH_IP_CUR_LVL_0P19		193
+#define USB_CH_IP_CUR_LVL_0P29		290
+#define USB_CH_IP_CUR_LVL_0P38		380
+#define USB_CH_IP_CUR_LVL_0P45		450
+#define USB_CH_IP_CUR_LVL_0P5		500
+#define USB_CH_IP_CUR_LVL_0P6		600
+#define USB_CH_IP_CUR_LVL_0P7		700
+#define USB_CH_IP_CUR_LVL_0P8		800
+#define USB_CH_IP_CUR_LVL_0P9		900
+#define USB_CH_IP_CUR_LVL_1P0		1000
+#define USB_CH_IP_CUR_LVL_1P1		1100
+#define USB_CH_IP_CUR_LVL_1P3		1300
+#define USB_CH_IP_CUR_LVL_1P4		1400
+#define USB_CH_IP_CUR_LVL_1P5		1500
+
+#define VBAT_TRESH_IP_CUR_RED		3800
+
+#define to_ab8500_charger_usb_device_info(x) container_of((x), \
+	struct ab8500_charger, usb_chg)
+#define to_ab8500_charger_ac_device_info(x) container_of((x), \
+	struct ab8500_charger, ac_chg)
+
+/**
+ * struct ab8500_charger_interrupts - ab8500 interupts
+ * @name:	name of the interrupt
+ * @isr		function pointer to the isr
+ */
+struct ab8500_charger_interrupts {
+	char *name;
+	irqreturn_t (*isr)(int irq, void *data);
+};
+
+struct ab8500_charger_info {
+	int charger_connected;
+	int charger_online;
+	int charger_voltage;
+	int cv_active;
+	bool wd_expired;
+};
+
+struct ab8500_charger_event_flags {
+	bool mainextchnotok;
+	bool main_thermal_prot;
+	bool usb_thermal_prot;
+	bool vbus_ovv;
+	bool usbchargernotok;
+	bool chgwdexp;
+	bool vbus_collapse;
+};
+
+struct ab8500_charger_usb_state {
+	bool usb_changed;
+	int usb_current;
+	enum ab8500_usb_state state;
+	spinlock_t usb_lock;
+};
+
+/**
+ * struct ab8500_charger - ab8500 Charger device information
+ * @dev:		Pointer to the structure device
+ * @max_usb_in_curr:	Max USB charger input current
+ * @vbus_detected:	VBUS detected
+ * @vbus_detected_start:
+ *			VBUS detected during startup
+ * @ac_conn:		This will be true when the AC charger has been plugged
+ * @vddadc_en_ac:	Indicate if VDD ADC supply is enabled because AC
+ *			charger is enabled
+ * @vddadc_en_usb:	Indicate if VDD ADC supply is enabled because USB
+ *			charger is enabled
+ * @vbat		Battery voltage
+ * @old_vbat		Previously measured battery voltage
+ * @autopower		Indicate if we should have automatic pwron after pwrloss
+ * @parent:		Pointer to the struct ab8500
+ * @gpadc:		Pointer to the struct gpadc
+ * @pdata:		Pointer to the abx500_charger platform data
+ * @bat:		Pointer to the abx500_bm platform data
+ * @flags:		Structure for information about events triggered
+ * @usb_state:		Structure for usb stack information
+ * @ac_chg:		AC charger power supply
+ * @usb_chg:		USB charger power supply
+ * @ac:			Structure that holds the AC charger properties
+ * @usb:		Structure that holds the USB charger properties
+ * @regu:		Pointer to the struct regulator
+ * @charger_wq:		Work queue for the IRQs and checking HW state
+ * @check_vbat_work	Work for checking vbat threshold to adjust vbus current
+ * @check_hw_failure_work:	Work for checking HW state
+ * @check_usbchgnotok_work:	Work for checking USB charger not ok status
+ * @kick_wd_work:		Work for kicking the charger watchdog in case
+ *				of ABB rev 1.* due to the watchog logic bug
+ * @ac_work:			Work for checking AC charger connection
+ * @detect_usb_type_work:	Work for detecting the USB type connected
+ * @usb_link_status_work:	Work for checking the new USB link status
+ * @usb_state_changed_work:	Work for checking USB state
+ * @check_main_thermal_prot_work:
+ *				Work for checking Main thermal status
+ * @check_usb_thermal_prot_work:
+ *				Work for checking USB thermal status
+ */
+struct ab8500_charger {
+	struct device *dev;
+	int max_usb_in_curr;
+	bool vbus_detected;
+	bool vbus_detected_start;
+	bool ac_conn;
+	bool vddadc_en_ac;
+	bool vddadc_en_usb;
+	int vbat;
+	int old_vbat;
+	bool autopower;
+	struct ab8500 *parent;
+	struct ab8500_gpadc *gpadc;
+	struct abx500_charger_platform_data *pdata;
+	struct abx500_bm_data *bat;
+	struct ab8500_charger_event_flags flags;
+	struct ab8500_charger_usb_state usb_state;
+	struct ux500_charger ac_chg;
+	struct ux500_charger usb_chg;
+	struct ab8500_charger_info ac;
+	struct ab8500_charger_info usb;
+	struct regulator *regu;
+	struct workqueue_struct *charger_wq;
+	struct delayed_work check_vbat_work;
+	struct delayed_work check_hw_failure_work;
+	struct delayed_work check_usbchgnotok_work;
+	struct delayed_work kick_wd_work;
+	struct work_struct ac_work;
+	struct work_struct detect_usb_type_work;
+	struct work_struct usb_link_status_work;
+	struct work_struct usb_state_changed_work;
+	struct work_struct check_main_thermal_prot_work;
+	struct work_struct check_usb_thermal_prot_work;
+	struct usb_phy *usb_phy;
+	struct notifier_block nb;
+};
+
+/* AC properties */
+static enum power_supply_property ab8500_charger_ac_props[] = {
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_VOLTAGE_AVG,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+};
+
+/* USB properties */
+static enum power_supply_property ab8500_charger_usb_props[] = {
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_CURRENT_AVG,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_VOLTAGE_AVG,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+};
+
+/**
+ * ab8500_power_loss_handling - set how we handle powerloss.
+ * @di:		pointer to the ab8500_charger structure
+ *
+ * Magic nummbers are from STE HW department.
+ */
+static void ab8500_power_loss_handling(struct ab8500_charger *di)
+{
+	u8 reg;
+	int ret;
+
+	dev_dbg(di->dev, "Autopower : %d\n", di->autopower);
+
+	/* read the autopower register */
+	ret = abx500_get_register_interruptible(di->dev, 0x15, 0x00, &reg);
+	if (ret) {
+		dev_err(di->dev, "%d write failed\n", __LINE__);
+		return;
+	}
+
+	/* enable the OPT emulation registers */
+	ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x2);
+	if (ret) {
+		dev_err(di->dev, "%d write failed\n", __LINE__);
+		return;
+	}
+
+	if (di->autopower)
+		reg |= 0x8;
+	else
+		reg &= ~0x8;
+
+	/* write back the changed value to autopower reg */
+	ret = abx500_set_register_interruptible(di->dev, 0x15, 0x00, reg);
+	if (ret) {
+		dev_err(di->dev, "%d write failed\n", __LINE__);
+		return;
+	}
+
+	/* disable the set OTP registers again */
+	ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x0);
+	if (ret) {
+		dev_err(di->dev, "%d write failed\n", __LINE__);
+		return;
+	}
+}
+
+/**
+ * ab8500_power_supply_changed - a wrapper with local extentions for
+ * power_supply_changed
+ * @di:	  pointer to the ab8500_charger structure
+ * @psy:  pointer to power_supply_that have changed.
+ *
+ */
+static void ab8500_power_supply_changed(struct ab8500_charger *di,
+					struct power_supply *psy)
+{
+	if (di->pdata->autopower_cfg) {
+		if (!di->usb.charger_connected &&
+		    !di->ac.charger_connected &&
+		    di->autopower) {
+			di->autopower = false;
+			ab8500_power_loss_handling(di);
+		} else if (!di->autopower &&
+			   (di->ac.charger_connected ||
+			    di->usb.charger_connected)) {
+			di->autopower = true;
+			ab8500_power_loss_handling(di);
+		}
+	}
+	power_supply_changed(psy);
+}
+
+static void ab8500_charger_set_usb_connected(struct ab8500_charger *di,
+	bool connected)
+{
+	if (connected != di->usb.charger_connected) {
+		dev_dbg(di->dev, "USB connected:%i\n", connected);
+		di->usb.charger_connected = connected;
+		sysfs_notify(&di->usb_chg.psy.dev->kobj, NULL, "present");
+	}
+}
+
+/**
+ * ab8500_charger_get_ac_voltage() - get ac charger voltage
+ * @di:		pointer to the ab8500_charger structure
+ *
+ * Returns ac charger voltage (on success)
+ */
+static int ab8500_charger_get_ac_voltage(struct ab8500_charger *di)
+{
+	int vch;
+
+	/* Only measure voltage if the charger is connected */
+	if (di->ac.charger_connected) {
+		vch = ab8500_gpadc_convert(di->gpadc, MAIN_CHARGER_V);
+		if (vch < 0)
+			dev_err(di->dev, "%s gpadc conv failed,\n", __func__);
+	} else {
+		vch = 0;
+	}
+	return vch;
+}
+
+/**
+ * ab8500_charger_ac_cv() - check if the main charger is in CV mode
+ * @di:		pointer to the ab8500_charger structure
+ *
+ * Returns ac charger CV mode (on success) else error code
+ */
+static int ab8500_charger_ac_cv(struct ab8500_charger *di)
+{
+	u8 val;
+	int ret = 0;
+
+	/* Only check CV mode if the charger is online */
+	if (di->ac.charger_online) {
+		ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+			AB8500_CH_STATUS1_REG, &val);
+		if (ret < 0) {
+			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+			return 0;
+		}
+
+		if (val & MAIN_CH_CV_ON)
+			ret = 1;
+		else
+			ret = 0;
+	}
+
+	return ret;
+}
+
+/**
+ * ab8500_charger_get_vbus_voltage() - get vbus voltage
+ * @di:		pointer to the ab8500_charger structure
+ *
+ * This function returns the vbus voltage.
+ * Returns vbus voltage (on success)
+ */
+static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di)
+{
+	int vch;
+
+	/* Only measure voltage if the charger is connected */
+	if (di->usb.charger_connected) {
+		vch = ab8500_gpadc_convert(di->gpadc, VBUS_V);
+		if (vch < 0)
+			dev_err(di->dev, "%s gpadc conv failed\n", __func__);
+	} else {
+		vch = 0;
+	}
+	return vch;
+}
+
+/**
+ * ab8500_charger_get_usb_current() - get usb charger current
+ * @di:		pointer to the ab8500_charger structure
+ *
+ * This function returns the usb charger current.
+ * Returns usb current (on success) and error code on failure
+ */
+static int ab8500_charger_get_usb_current(struct ab8500_charger *di)
+{
+	int ich;
+
+	/* Only measure current if the charger is online */
+	if (di->usb.charger_online) {
+		ich = ab8500_gpadc_convert(di->gpadc, USB_CHARGER_C);
+		if (ich < 0)
+			dev_err(di->dev, "%s gpadc conv failed\n", __func__);
+	} else {
+		ich = 0;
+	}
+	return ich;
+}
+
+/**
+ * ab8500_charger_get_ac_current() - get ac charger current
+ * @di:		pointer to the ab8500_charger structure
+ *
+ * This function returns the ac charger current.
+ * Returns ac current (on success) and error code on failure.
+ */
+static int ab8500_charger_get_ac_current(struct ab8500_charger *di)
+{
+	int ich;
+
+	/* Only measure current if the charger is online */
+	if (di->ac.charger_online) {
+		ich = ab8500_gpadc_convert(di->gpadc, MAIN_CHARGER_C);
+		if (ich < 0)
+			dev_err(di->dev, "%s gpadc conv failed\n", __func__);
+	} else {
+		ich = 0;
+	}
+	return ich;
+}
+
+/**
+ * ab8500_charger_usb_cv() - check if the usb charger is in CV mode
+ * @di:		pointer to the ab8500_charger structure
+ *
+ * Returns ac charger CV mode (on success) else error code
+ */
+static int ab8500_charger_usb_cv(struct ab8500_charger *di)
+{
+	int ret;
+	u8 val;
+
+	/* Only check CV mode if the charger is online */
+	if (di->usb.charger_online) {
+		ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+			AB8500_CH_USBCH_STAT1_REG, &val);
+		if (ret < 0) {
+			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+			return 0;
+		}
+
+		if (val & USB_CH_CV_ON)
+			ret = 1;
+		else
+			ret = 0;
+	} else {
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/**
+ * ab8500_charger_detect_chargers() - Detect the connected chargers
+ * @di:		pointer to the ab8500_charger structure
+ *
+ * Returns the type of charger connected.
+ * For USB it will not mean we can actually charge from it
+ * but that there is a USB cable connected that we have to
+ * identify. This is used during startup when we don't get
+ * interrupts of the charger detection
+ *
+ * Returns an integer value, that means,
+ * NO_PW_CONN  no power supply is connected
+ * AC_PW_CONN  if the AC power supply is connected
+ * USB_PW_CONN  if the USB power supply is connected
+ * AC_PW_CONN + USB_PW_CONN if USB and AC power supplies are both connected
+ */
+static int ab8500_charger_detect_chargers(struct ab8500_charger *di)
+{
+	int result = NO_PW_CONN;
+	int ret;
+	u8 val;
+
+	/* Check for AC charger */
+	ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+		AB8500_CH_STATUS1_REG, &val);
+	if (ret < 0) {
+		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+		return ret;
+	}
+
+	if (val & MAIN_CH_DET)
+		result = AC_PW_CONN;
+
+	/* Check for USB charger */
+	ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+		AB8500_CH_USBCH_STAT1_REG, &val);
+	if (ret < 0) {
+		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+		return ret;
+	}
+
+	if ((val & VBUS_DET_DBNC1) && (val & VBUS_DET_DBNC100))
+		result |= USB_PW_CONN;
+
+	return result;
+}
+
+/**
+ * ab8500_charger_max_usb_curr() - get the max curr for the USB type
+ * @di:			pointer to the ab8500_charger structure
+ * @link_status:	the identified USB type
+ *
+ * Get the maximum current that is allowed to be drawn from the host
+ * based on the USB type.
+ * Returns error code in case of failure else 0 on success
+ */
+static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
+	enum ab8500_charger_link_status link_status)
+{
+	int ret = 0;
+
+	switch (link_status) {
+	case USB_STAT_STD_HOST_NC:
+	case USB_STAT_STD_HOST_C_NS:
+	case USB_STAT_STD_HOST_C_S:
+		dev_dbg(di->dev, "USB Type - Standard host is "
+			"detected through USB driver\n");
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P09;
+		break;
+	case USB_STAT_HOST_CHG_HS_CHIRP:
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+		break;
+	case USB_STAT_HOST_CHG_HS:
+	case USB_STAT_ACA_RID_C_HS:
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P9;
+		break;
+	case USB_STAT_ACA_RID_A:
+		/*
+		 * Dedicated charger level minus maximum current accessory
+		 * can consume (300mA). Closest level is 1100mA
+		 */
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P1;
+		break;
+	case USB_STAT_ACA_RID_B:
+		/*
+		 * Dedicated charger level minus 120mA (20mA for ACA and
+		 * 100mA for potential accessory). Closest level is 1300mA
+		 */
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P3;
+		break;
+	case USB_STAT_DEDICATED_CHG:
+	case USB_STAT_HOST_CHG_NM:
+	case USB_STAT_ACA_RID_C_HS_CHIRP:
+	case USB_STAT_ACA_RID_C_NM:
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P5;
+		break;
+	case USB_STAT_RESERVED:
+		/*
+		 * This state is used to indicate that VBUS has dropped below
+		 * the detection level 4 times in a row. This is due to the
+		 * charger output current is set to high making the charger
+		 * voltage collapse. This have to be propagated through to
+		 * chargalg. This is done using the property
+		 * POWER_SUPPLY_PROP_CURRENT_AVG = 1
+		 */
+		di->flags.vbus_collapse = true;
+		dev_dbg(di->dev, "USB Type - USB_STAT_RESERVED "
+			"VBUS has collapsed\n");
+		ret = -1;
+		break;
+	case USB_STAT_HM_IDGND:
+	case USB_STAT_NOT_CONFIGURED:
+	case USB_STAT_NOT_VALID_LINK:
+		dev_err(di->dev, "USB Type - Charging not allowed\n");
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05;
+		ret = -ENXIO;
+		break;
+	default:
+		dev_err(di->dev, "USB Type - Unknown\n");
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05;
+		ret = -ENXIO;
+		break;
+	};
+
+	dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d",
+		link_status, di->max_usb_in_curr);
+
+	return ret;
+}
+
+/**
+ * ab8500_charger_read_usb_type() - read the type of usb connected
+ * @di:		pointer to the ab8500_charger structure
+ *
+ * Detect the type of the plugged USB
+ * Returns error code in case of failure else 0 on success
+ */
+static int ab8500_charger_read_usb_type(struct ab8500_charger *di)
+{
+	int ret;
+	u8 val;
+
+	ret = abx500_get_register_interruptible(di->dev,
+		AB8500_INTERRUPT, AB8500_IT_SOURCE21_REG, &val);
+	if (ret < 0) {
+		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+		return ret;
+	}
+	ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
+		AB8500_USB_LINE_STAT_REG, &val);
+	if (ret < 0) {
+		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+		return ret;
+	}
+
+	/* get the USB type */
+	val = (val & AB8500_USB_LINK_STATUS) >> 3;
+	ret = ab8500_charger_max_usb_curr(di,
+		(enum ab8500_charger_link_status) val);
+
+	return ret;
+}
+
+/**
+ * ab8500_charger_detect_usb_type() - get the type of usb connected
+ * @di:		pointer to the ab8500_charger structure
+ *
+ * Detect the type of the plugged USB
+ * Returns error code in case of failure else 0 on success
+ */
+static int ab8500_charger_detect_usb_type(struct ab8500_charger *di)
+{
+	int i, ret;
+	u8 val;
+
+	/*
+	 * On getting the VBUS rising edge detect interrupt there
+	 * is a 250ms delay after which the register UsbLineStatus
+	 * is filled with valid data.
+	 */
+	for (i = 0; i < 10; i++) {
+		msleep(250);
+		ret = abx500_get_register_interruptible(di->dev,
+			AB8500_INTERRUPT, AB8500_IT_SOURCE21_REG,
+			&val);
+		if (ret < 0) {
+			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+			return ret;
+		}
+		ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
+			AB8500_USB_LINE_STAT_REG, &val);
+		if (ret < 0) {
+			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+			return ret;
+		}
+		/*
+		 * Until the IT source register is read the UsbLineStatus
+		 * register is not updated, hence doing the same
+		 * Revisit this:
+		 */
+
+		/* get the USB type */
+		val = (val & AB8500_USB_LINK_STATUS) >> 3;
+		if (val)
+			break;
+	}
+	ret = ab8500_charger_max_usb_curr(di,
+		(enum ab8500_charger_link_status) val);
+
+	return ret;
+}
+
+/*
+ * This array maps the raw hex value to charger voltage used by the AB8500
+ * Values taken from the UM0836
+ */
+static int ab8500_charger_voltage_map[] = {
+	3500 ,
+	3525 ,
+	3550 ,
+	3575 ,
+	3600 ,
+	3625 ,
+	3650 ,
+	3675 ,
+	3700 ,
+	3725 ,
+	3750 ,
+	3775 ,
+	3800 ,
+	3825 ,
+	3850 ,
+	3875 ,
+	3900 ,
+	3925 ,
+	3950 ,
+	3975 ,
+	4000 ,
+	4025 ,
+	4050 ,
+	4060 ,
+	4070 ,
+	4080 ,
+	4090 ,
+	4100 ,
+	4110 ,
+	4120 ,
+	4130 ,
+	4140 ,
+	4150 ,
+	4160 ,
+	4170 ,
+	4180 ,
+	4190 ,
+	4200 ,
+	4210 ,
+	4220 ,
+	4230 ,
+	4240 ,
+	4250 ,
+	4260 ,
+	4270 ,
+	4280 ,
+	4290 ,
+	4300 ,
+	4310 ,
+	4320 ,
+	4330 ,
+	4340 ,
+	4350 ,
+	4360 ,
+	4370 ,
+	4380 ,
+	4390 ,
+	4400 ,
+	4410 ,
+	4420 ,
+	4430 ,
+	4440 ,
+	4450 ,
+	4460 ,
+	4470 ,
+	4480 ,
+	4490 ,
+	4500 ,
+	4510 ,
+	4520 ,
+	4530 ,
+	4540 ,
+	4550 ,
+	4560 ,
+	4570 ,
+	4580 ,
+	4590 ,
+	4600 ,
+};
+
+/*
+ * This array maps the raw hex value to charger current used by the AB8500
+ * Values taken from the UM0836
+ */
+static int ab8500_charger_current_map[] = {
+	100 ,
+	200 ,
+	300 ,
+	400 ,
+	500 ,
+	600 ,
+	700 ,
+	800 ,
+	900 ,
+	1000 ,
+	1100 ,
+	1200 ,
+	1300 ,
+	1400 ,
+	1500 ,
+};
+
+/*
+ * This array maps the raw hex value to VBUS input current used by the AB8500
+ * Values taken from the UM0836
+ */
+static int ab8500_charger_vbus_in_curr_map[] = {
+	USB_CH_IP_CUR_LVL_0P05,
+	USB_CH_IP_CUR_LVL_0P09,
+	USB_CH_IP_CUR_LVL_0P19,
+	USB_CH_IP_CUR_LVL_0P29,
+	USB_CH_IP_CUR_LVL_0P38,
+	USB_CH_IP_CUR_LVL_0P45,
+	USB_CH_IP_CUR_LVL_0P5,
+	USB_CH_IP_CUR_LVL_0P6,
+	USB_CH_IP_CUR_LVL_0P7,
+	USB_CH_IP_CUR_LVL_0P8,
+	USB_CH_IP_CUR_LVL_0P9,
+	USB_CH_IP_CUR_LVL_1P0,
+	USB_CH_IP_CUR_LVL_1P1,
+	USB_CH_IP_CUR_LVL_1P3,
+	USB_CH_IP_CUR_LVL_1P4,
+	USB_CH_IP_CUR_LVL_1P5,
+};
+
+static int ab8500_voltage_to_regval(int voltage)
+{
+	int i;
+
+	/* Special case for voltage below 3.5V */
+	if (voltage < ab8500_charger_voltage_map[0])
+		return LOW_VOLT_REG;
+
+	for (i = 1; i < ARRAY_SIZE(ab8500_charger_voltage_map); i++) {
+		if (voltage < ab8500_charger_voltage_map[i])
+			return i - 1;
+	}
+
+	/* If not last element, return error */
+	i = ARRAY_SIZE(ab8500_charger_voltage_map) - 1;
+	if (voltage == ab8500_charger_voltage_map[i])
+		return i;
+	else
+		return -1;
+}
+
+static int ab8500_current_to_regval(int curr)
+{
+	int i;
+
+	if (curr < ab8500_charger_current_map[0])
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(ab8500_charger_current_map); i++) {
+		if (curr < ab8500_charger_current_map[i])
+			return i - 1;
+	}
+
+	/* If not last element, return error */
+	i = ARRAY_SIZE(ab8500_charger_current_map) - 1;
+	if (curr == ab8500_charger_current_map[i])
+		return i;
+	else
+		return -1;
+}
+
+static int ab8500_vbus_in_curr_to_regval(int curr)
+{
+	int i;
+
+	if (curr < ab8500_charger_vbus_in_curr_map[0])
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(ab8500_charger_vbus_in_curr_map); i++) {
+		if (curr < ab8500_charger_vbus_in_curr_map[i])
+			return i - 1;
+	}
+
+	/* If not last element, return error */
+	i = ARRAY_SIZE(ab8500_charger_vbus_in_curr_map) - 1;
+	if (curr == ab8500_charger_vbus_in_curr_map[i])
+		return i;
+	else
+		return -1;
+}
+
+/**
+ * ab8500_charger_get_usb_cur() - get usb current
+ * @di:		pointer to the ab8500_charger structre
+ *
+ * The usb stack provides the maximum current that can be drawn from
+ * the standard usb host. This will be in mA.
+ * This function converts current in mA to a value that can be written
+ * to the register. Returns -1 if charging is not allowed
+ */
+static int ab8500_charger_get_usb_cur(struct ab8500_charger *di)
+{
+	switch (di->usb_state.usb_current) {
+	case 100:
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P09;
+		break;
+	case 200:
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P19;
+		break;
+	case 300:
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P29;
+		break;
+	case 400:
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P38;
+		break;
+	case 500:
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+		break;
+	default:
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05;
+		return -1;
+		break;
+	};
+	return 0;
+}
+
+/**
+ * ab8500_charger_set_vbus_in_curr() - set VBUS input current limit
+ * @di:		pointer to the ab8500_charger structure
+ * @ich_in:	charger input current limit
+ *
+ * Sets the current that can be drawn from the USB host
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di,
+		int ich_in)
+{
+	int ret;
+	int input_curr_index;
+	int min_value;
+
+	/* We should always use to lowest current limit */
+	min_value = min(di->bat->chg_params->usb_curr_max, ich_in);
+
+	switch (min_value) {
+	case 100:
+		if (di->vbat < VBAT_TRESH_IP_CUR_RED)
+			min_value = USB_CH_IP_CUR_LVL_0P05;
+		break;
+	case 500:
+		if (di->vbat < VBAT_TRESH_IP_CUR_RED)
+			min_value = USB_CH_IP_CUR_LVL_0P45;
+		break;
+	default:
+		break;
+	}
+
+	input_curr_index = ab8500_vbus_in_curr_to_regval(min_value);
+	if (input_curr_index < 0) {
+		dev_err(di->dev, "VBUS input current limit too high\n");
+		return -ENXIO;
+	}
+
+	ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+		AB8500_USBCH_IPT_CRNTLVL_REG,
+		input_curr_index << VBUS_IN_CURR_LIM_SHIFT);
+	if (ret)
+		dev_err(di->dev, "%s write failed\n", __func__);
+
+	return ret;
+}
+
+/**
+ * ab8500_charger_led_en() - turn on/off chargign led
+ * @di:		pointer to the ab8500_charger structure
+ * @on:		flag to turn on/off the chargign led
+ *
+ * Power ON/OFF charging LED indication
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_charger_led_en(struct ab8500_charger *di, int on)
+{
+	int ret;
+
+	if (on) {
+		/* Power ON charging LED indicator, set LED current to 5mA */
+		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+			AB8500_LED_INDICATOR_PWM_CTRL,
+			(LED_IND_CUR_5MA | LED_INDICATOR_PWM_ENA));
+		if (ret) {
+			dev_err(di->dev, "Power ON LED failed\n");
+			return ret;
+		}
+		/* LED indicator PWM duty cycle 252/256 */
+		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+			AB8500_LED_INDICATOR_PWM_DUTY,
+			LED_INDICATOR_PWM_DUTY_252_256);
+		if (ret) {
+			dev_err(di->dev, "Set LED PWM duty cycle failed\n");
+			return ret;
+		}
+	} else {
+		/* Power off charging LED indicator */
+		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+			AB8500_LED_INDICATOR_PWM_CTRL,
+			LED_INDICATOR_PWM_DIS);
+		if (ret) {
+			dev_err(di->dev, "Power-off LED failed\n");
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * ab8500_charger_ac_en() - enable or disable ac charging
+ * @di:		pointer to the ab8500_charger structure
+ * @enable:	enable/disable flag
+ * @vset:	charging voltage
+ * @iset:	charging current
+ *
+ * Enable/Disable AC/Mains charging and turns on/off the charging led
+ * respectively.
+ **/
+static int ab8500_charger_ac_en(struct ux500_charger *charger,
+	int enable, int vset, int iset)
+{
+	int ret;
+	int volt_index;
+	int curr_index;
+	int input_curr_index;
+	u8 overshoot = 0;
+
+	struct ab8500_charger *di = to_ab8500_charger_ac_device_info(charger);
+
+	if (enable) {
+		/* Check if AC is connected */
+		if (!di->ac.charger_connected) {
+			dev_err(di->dev, "AC charger not connected\n");
+			return -ENXIO;
+		}
+
+		/* Enable AC charging */
+		dev_dbg(di->dev, "Enable AC: %dmV %dmA\n", vset, iset);
+
+		/*
+		 * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts
+		 * will be triggered everytime we enable the VDD ADC supply.
+		 * This will turn off charging for a short while.
+		 * It can be avoided by having the supply on when
+		 * there is a charger enabled. Normally the VDD ADC supply
+		 * is enabled everytime a GPADC conversion is triggered. We will
+		 * force it to be enabled from this driver to have
+		 * the GPADC module independant of the AB8500 chargers
+		 */
+		if (!di->vddadc_en_ac) {
+			regulator_enable(di->regu);
+			di->vddadc_en_ac = true;
+		}
+
+		/* Check if the requested voltage or current is valid */
+		volt_index = ab8500_voltage_to_regval(vset);
+		curr_index = ab8500_current_to_regval(iset);
+		input_curr_index = ab8500_current_to_regval(
+			di->bat->chg_params->ac_curr_max);
+		if (volt_index < 0 || curr_index < 0 || input_curr_index < 0) {
+			dev_err(di->dev,
+				"Charger voltage or current too high, "
+				"charging not started\n");
+			return -ENXIO;
+		}
+
+		/* ChVoltLevel: maximum battery charging voltage */
+		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+			AB8500_CH_VOLT_LVL_REG, (u8) volt_index);
+		if (ret) {
+			dev_err(di->dev, "%s write failed\n", __func__);
+			return ret;
+		}
+		/* MainChInputCurr: current that can be drawn from the charger*/
+		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+			AB8500_MCH_IPT_CURLVL_REG,
+			input_curr_index << MAIN_CH_INPUT_CURR_SHIFT);
+		if (ret) {
+			dev_err(di->dev, "%s write failed\n", __func__);
+			return ret;
+		}
+		/* ChOutputCurentLevel: protected output current */
+		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+			AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index);
+		if (ret) {
+			dev_err(di->dev, "%s write failed\n", __func__);
+			return ret;
+		}
+
+		/* Check if VBAT overshoot control should be enabled */
+		if (!di->bat->enable_overshoot)
+			overshoot = MAIN_CH_NO_OVERSHOOT_ENA_N;
+
+		/* Enable Main Charger */
+		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+			AB8500_MCH_CTRL1, MAIN_CH_ENA | overshoot);
+		if (ret) {
+			dev_err(di->dev, "%s write failed\n", __func__);
+			return ret;
+		}
+
+		/* Power on charging LED indication */
+		ret = ab8500_charger_led_en(di, true);
+		if (ret < 0)
+			dev_err(di->dev, "failed to enable LED\n");
+
+		di->ac.charger_online = 1;
+	} else {
+		/* Disable AC charging */
+		if (is_ab8500_1p1_or_earlier(di->parent)) {
+			/*
+			 * For ABB revision 1.0 and 1.1 there is a bug in the
+			 * watchdog logic. That means we have to continously
+			 * kick the charger watchdog even when no charger is
+			 * connected. This is only valid once the AC charger
+			 * has been enabled. This is a bug that is not handled
+			 * by the algorithm and the watchdog have to be kicked
+			 * by the charger driver when the AC charger
+			 * is disabled
+			 */
+			if (di->ac_conn) {
+				queue_delayed_work(di->charger_wq,
+					&di->kick_wd_work,
+					round_jiffies(WD_KICK_INTERVAL));
+			}
+
+			/*
+			 * We can't turn off charging completely
+			 * due to a bug in AB8500 cut1.
+			 * If we do, charging will not start again.
+			 * That is why we set the lowest voltage
+			 * and current possible
+			 */
+			ret = abx500_set_register_interruptible(di->dev,
+				AB8500_CHARGER,
+				AB8500_CH_VOLT_LVL_REG, CH_VOL_LVL_3P5);
+			if (ret) {
+				dev_err(di->dev,
+					"%s write failed\n", __func__);
+				return ret;
+			}
+
+			ret = abx500_set_register_interruptible(di->dev,
+				AB8500_CHARGER,
+				AB8500_CH_OPT_CRNTLVL_REG, CH_OP_CUR_LVL_0P1);
+			if (ret) {
+				dev_err(di->dev,
+					"%s write failed\n", __func__);
+				return ret;
+			}
+		} else {
+			ret = abx500_set_register_interruptible(di->dev,
+				AB8500_CHARGER,
+				AB8500_MCH_CTRL1, 0);
+			if (ret) {
+				dev_err(di->dev,
+					"%s write failed\n", __func__);
+				return ret;
+			}
+		}
+
+		ret = ab8500_charger_led_en(di, false);
+		if (ret < 0)
+			dev_err(di->dev, "failed to disable LED\n");
+
+		di->ac.charger_online = 0;
+		di->ac.wd_expired = false;
+
+		/* Disable regulator if enabled */
+		if (di->vddadc_en_ac) {
+			regulator_disable(di->regu);
+			di->vddadc_en_ac = false;
+		}
+
+		dev_dbg(di->dev, "%s Disabled AC charging\n", __func__);
+	}
+	ab8500_power_supply_changed(di, &di->ac_chg.psy);
+
+	return ret;
+}
+
+/**
+ * ab8500_charger_usb_en() - enable usb charging
+ * @di:		pointer to the ab8500_charger structure
+ * @enable:	enable/disable flag
+ * @vset:	charging voltage
+ * @ich_out:	charger output current
+ *
+ * Enable/Disable USB charging and turns on/off the charging led respectively.
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_charger_usb_en(struct ux500_charger *charger,
+	int enable, int vset, int ich_out)
+{
+	int ret;
+	int volt_index;
+	int curr_index;
+	u8 overshoot = 0;
+
+	struct ab8500_charger *di = to_ab8500_charger_usb_device_info(charger);
+
+	if (enable) {
+		/* Check if USB is connected */
+		if (!di->usb.charger_connected) {
+			dev_err(di->dev, "USB charger not connected\n");
+			return -ENXIO;
+		}
+
+		/*
+		 * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts
+		 * will be triggered everytime we enable the VDD ADC supply.
+		 * This will turn off charging for a short while.
+		 * It can be avoided by having the supply on when
+		 * there is a charger enabled. Normally the VDD ADC supply
+		 * is enabled everytime a GPADC conversion is triggered. We will
+		 * force it to be enabled from this driver to have
+		 * the GPADC module independant of the AB8500 chargers
+		 */
+		if (!di->vddadc_en_usb) {
+			regulator_enable(di->regu);
+			di->vddadc_en_usb = true;
+		}
+
+		/* Enable USB charging */
+		dev_dbg(di->dev, "Enable USB: %dmV %dmA\n", vset, ich_out);
+
+		/* Check if the requested voltage or current is valid */
+		volt_index = ab8500_voltage_to_regval(vset);
+		curr_index = ab8500_current_to_regval(ich_out);
+		if (volt_index < 0 || curr_index < 0) {
+			dev_err(di->dev,
+				"Charger voltage or current too high, "
+				"charging not started\n");
+			return -ENXIO;
+		}
+
+		/* ChVoltLevel: max voltage upto which battery can be charged */
+		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+			AB8500_CH_VOLT_LVL_REG, (u8) volt_index);
+		if (ret) {
+			dev_err(di->dev, "%s write failed\n", __func__);
+			return ret;
+		}
+		/* USBChInputCurr: current that can be drawn from the usb */
+		ret = ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
+		if (ret) {
+			dev_err(di->dev, "setting USBChInputCurr failed\n");
+			return ret;
+		}
+		/* ChOutputCurentLevel: protected output current */
+		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+			AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index);
+		if (ret) {
+			dev_err(di->dev, "%s write failed\n", __func__);
+			return ret;
+		}
+		/* Check if VBAT overshoot control should be enabled */
+		if (!di->bat->enable_overshoot)
+			overshoot = USB_CHG_NO_OVERSHOOT_ENA_N;
+
+		/* Enable USB Charger */
+		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+			AB8500_USBCH_CTRL1_REG, USB_CH_ENA | overshoot);
+		if (ret) {
+			dev_err(di->dev, "%s write failed\n", __func__);
+			return ret;
+		}
+
+		/* If success power on charging LED indication */
+		ret = ab8500_charger_led_en(di, true);
+		if (ret < 0)
+			dev_err(di->dev, "failed to enable LED\n");
+
+		queue_delayed_work(di->charger_wq, &di->check_vbat_work, HZ);
+
+		di->usb.charger_online = 1;
+	} else {
+		/* Disable USB charging */
+		ret = abx500_set_register_interruptible(di->dev,
+			AB8500_CHARGER,
+			AB8500_USBCH_CTRL1_REG, 0);
+		if (ret) {
+			dev_err(di->dev,
+				"%s write failed\n", __func__);
+			return ret;
+		}
+
+		ret = ab8500_charger_led_en(di, false);
+		if (ret < 0)
+			dev_err(di->dev, "failed to disable LED\n");
+
+		di->usb.charger_online = 0;
+		di->usb.wd_expired = false;
+
+		/* Disable regulator if enabled */
+		if (di->vddadc_en_usb) {
+			regulator_disable(di->regu);
+			di->vddadc_en_usb = false;
+		}
+
+		dev_dbg(di->dev, "%s Disabled USB charging\n", __func__);
+
+		/* Cancel any pending Vbat check work */
+		if (delayed_work_pending(&di->check_vbat_work))
+			cancel_delayed_work(&di->check_vbat_work);
+
+	}
+	ab8500_power_supply_changed(di, &di->usb_chg.psy);
+
+	return ret;
+}
+
+/**
+ * ab8500_charger_watchdog_kick() - kick charger watchdog
+ * @di:		pointer to the ab8500_charger structure
+ *
+ * Kick charger watchdog
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_charger_watchdog_kick(struct ux500_charger *charger)
+{
+	int ret;
+	struct ab8500_charger *di;
+
+	if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS)
+		di = to_ab8500_charger_ac_device_info(charger);
+	else if (charger->psy.type == POWER_SUPPLY_TYPE_USB)
+		di = to_ab8500_charger_usb_device_info(charger);
+	else
+		return -ENXIO;
+
+	ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+		AB8500_CHARG_WD_CTRL, CHARG_WD_KICK);
+	if (ret)
+		dev_err(di->dev, "Failed to kick WD!\n");
+
+	return ret;
+}
+
+/**
+ * ab8500_charger_update_charger_current() - update charger current
+ * @di:		pointer to the ab8500_charger structure
+ *
+ * Update the charger output current for the specified charger
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_charger_update_charger_current(struct ux500_charger *charger,
+		int ich_out)
+{
+	int ret;
+	int curr_index;
+	struct ab8500_charger *di;
+
+	if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS)
+		di = to_ab8500_charger_ac_device_info(charger);
+	else if (charger->psy.type == POWER_SUPPLY_TYPE_USB)
+		di = to_ab8500_charger_usb_device_info(charger);
+	else
+		return -ENXIO;
+
+	curr_index = ab8500_current_to_regval(ich_out);
+	if (curr_index < 0) {
+		dev_err(di->dev,
+			"Charger current too high, "
+			"charging not started\n");
+		return -ENXIO;
+	}
+
+	ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+		AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index);
+	if (ret) {
+		dev_err(di->dev, "%s write failed\n", __func__);
+		return ret;
+	}
+
+	/* Reset the main and usb drop input current measurement counter */
+	ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+				AB8500_CHARGER_CTRL,
+				0x1);
+	if (ret) {
+		dev_err(di->dev, "%s write failed\n", __func__);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int ab8500_charger_get_ext_psy_data(struct device *dev, void *data)
+{
+	struct power_supply *psy;
+	struct power_supply *ext;
+	struct ab8500_charger *di;
+	union power_supply_propval ret;
+	int i, j;
+	bool psy_found = false;
+	struct ux500_charger *usb_chg;
+
+	usb_chg = (struct ux500_charger *)data;
+	psy = &usb_chg->psy;
+
+	di = to_ab8500_charger_usb_device_info(usb_chg);
+
+	ext = dev_get_drvdata(dev);
+
+	/* For all psy where the driver name appears in any supplied_to */
+	for (i = 0; i < ext->num_supplicants; i++) {
+		if (!strcmp(ext->supplied_to[i], psy->name))
+			psy_found = true;
+	}
+
+	if (!psy_found)
+		return 0;
+
+	/* Go through all properties for the psy */
+	for (j = 0; j < ext->num_properties; j++) {
+		enum power_supply_property prop;
+		prop = ext->properties[j];
+
+		if (ext->get_property(ext, prop, &ret))
+			continue;
+
+		switch (prop) {
+		case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+			switch (ext->type) {
+			case POWER_SUPPLY_TYPE_BATTERY:
+				di->vbat = ret.intval / 1000;
+				break;
+			default:
+				break;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	return 0;
+}
+
+/**
+ * ab8500_charger_check_vbat_work() - keep vbus current within spec
+ * @work	pointer to the work_struct structure
+ *
+ * Due to a asic bug it is necessary to lower the input current to the vbus
+ * charger when charging with at some specific levels. This issue is only valid
+ * for below a certain battery voltage. This function makes sure that the
+ * the allowed current limit isn't exceeded.
+ */
+static void ab8500_charger_check_vbat_work(struct work_struct *work)
+{
+	int t = 10;
+	struct ab8500_charger *di = container_of(work,
+		struct ab8500_charger, check_vbat_work.work);
+
+	class_for_each_device(power_supply_class, NULL,
+		&di->usb_chg.psy, ab8500_charger_get_ext_psy_data);
+
+	/* First run old_vbat is 0. */
+	if (di->old_vbat == 0)
+		di->old_vbat = di->vbat;
+
+	if (!((di->old_vbat <= VBAT_TRESH_IP_CUR_RED &&
+		di->vbat <= VBAT_TRESH_IP_CUR_RED) ||
+		(di->old_vbat > VBAT_TRESH_IP_CUR_RED &&
+		di->vbat > VBAT_TRESH_IP_CUR_RED))) {
+
+		dev_dbg(di->dev, "Vbat did cross threshold, curr: %d, new: %d,"
+			" old: %d\n", di->max_usb_in_curr, di->vbat,
+			di->old_vbat);
+		ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
+		power_supply_changed(&di->usb_chg.psy);
+	}
+
+	di->old_vbat = di->vbat;
+
+	/*
+	 * No need to check the battery voltage every second when not close to
+	 * the threshold.
+	 */
+	if (di->vbat < (VBAT_TRESH_IP_CUR_RED + 100) &&
+		(di->vbat > (VBAT_TRESH_IP_CUR_RED - 100)))
+			t = 1;
+
+	queue_delayed_work(di->charger_wq, &di->check_vbat_work, t * HZ);
+}
+
+/**
+ * ab8500_charger_check_hw_failure_work() - check main charger failure
+ * @work:	pointer to the work_struct structure
+ *
+ * Work queue function for checking the main charger status
+ */
+static void ab8500_charger_check_hw_failure_work(struct work_struct *work)
+{
+	int ret;
+	u8 reg_value;
+
+	struct ab8500_charger *di = container_of(work,
+		struct ab8500_charger, check_hw_failure_work.work);
+
+	/* Check if the status bits for HW failure is still active */
+	if (di->flags.mainextchnotok) {
+		ret = abx500_get_register_interruptible(di->dev,
+			AB8500_CHARGER, AB8500_CH_STATUS2_REG, &reg_value);
+		if (ret < 0) {
+			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+			return;
+		}
+		if (!(reg_value & MAIN_CH_NOK)) {
+			di->flags.mainextchnotok = false;
+			ab8500_power_supply_changed(di, &di->ac_chg.psy);
+		}
+	}
+	if (di->flags.vbus_ovv) {
+		ret = abx500_get_register_interruptible(di->dev,
+			AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG,
+			&reg_value);
+		if (ret < 0) {
+			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+			return;
+		}
+		if (!(reg_value & VBUS_OVV_TH)) {
+			di->flags.vbus_ovv = false;
+			ab8500_power_supply_changed(di, &di->usb_chg.psy);
+		}
+	}
+	/* If we still have a failure, schedule a new check */
+	if (di->flags.mainextchnotok || di->flags.vbus_ovv) {
+		queue_delayed_work(di->charger_wq,
+			&di->check_hw_failure_work, round_jiffies(HZ));
+	}
+}
+
+/**
+ * ab8500_charger_kick_watchdog_work() - kick the watchdog
+ * @work:	pointer to the work_struct structure
+ *
+ * Work queue function for kicking the charger watchdog.
+ *
+ * For ABB revision 1.0 and 1.1 there is a bug in the watchdog
+ * logic. That means we have to continously kick the charger
+ * watchdog even when no charger is connected. This is only
+ * valid once the AC charger has been enabled. This is
+ * a bug that is not handled by the algorithm and the
+ * watchdog have to be kicked by the charger driver
+ * when the AC charger is disabled
+ */
+static void ab8500_charger_kick_watchdog_work(struct work_struct *work)
+{
+	int ret;
+
+	struct ab8500_charger *di = container_of(work,
+		struct ab8500_charger, kick_wd_work.work);
+
+	ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+		AB8500_CHARG_WD_CTRL, CHARG_WD_KICK);
+	if (ret)
+		dev_err(di->dev, "Failed to kick WD!\n");
+
+	/* Schedule a new watchdog kick */
+	queue_delayed_work(di->charger_wq,
+		&di->kick_wd_work, round_jiffies(WD_KICK_INTERVAL));
+}
+
+/**
+ * ab8500_charger_ac_work() - work to get and set main charger status
+ * @work:	pointer to the work_struct structure
+ *
+ * Work queue function for checking the main charger status
+ */
+static void ab8500_charger_ac_work(struct work_struct *work)
+{
+	int ret;
+
+	struct ab8500_charger *di = container_of(work,
+		struct ab8500_charger, ac_work);
+
+	/*
+	 * Since we can't be sure that the events are received
+	 * synchronously, we have the check if the main charger is
+	 * connected by reading the status register
+	 */
+	ret = ab8500_charger_detect_chargers(di);
+	if (ret < 0)
+		return;
+
+	if (ret & AC_PW_CONN) {
+		di->ac.charger_connected = 1;
+		di->ac_conn = true;
+	} else {
+		di->ac.charger_connected = 0;
+	}
+
+	ab8500_power_supply_changed(di, &di->ac_chg.psy);
+	sysfs_notify(&di->ac_chg.psy.dev->kobj, NULL, "present");
+}
+
+/**
+ * ab8500_charger_detect_usb_type_work() - work to detect USB type
+ * @work:	Pointer to the work_struct structure
+ *
+ * Detect the type of USB plugged
+ */
+static void ab8500_charger_detect_usb_type_work(struct work_struct *work)
+{
+	int ret;
+
+	struct ab8500_charger *di = container_of(work,
+		struct ab8500_charger, detect_usb_type_work);
+
+	/*
+	 * Since we can't be sure that the events are received
+	 * synchronously, we have the check if is
+	 * connected by reading the status register
+	 */
+	ret = ab8500_charger_detect_chargers(di);
+	if (ret < 0)
+		return;
+
+	if (!(ret & USB_PW_CONN)) {
+		di->vbus_detected = 0;
+		ab8500_charger_set_usb_connected(di, false);
+		ab8500_power_supply_changed(di, &di->usb_chg.psy);
+	} else {
+		di->vbus_detected = 1;
+
+		if (is_ab8500_1p1_or_earlier(di->parent)) {
+			ret = ab8500_charger_detect_usb_type(di);
+			if (!ret) {
+				ab8500_charger_set_usb_connected(di, true);
+				ab8500_power_supply_changed(di,
+							    &di->usb_chg.psy);
+			}
+		} else {
+			/* For ABB cut2.0 and onwards we have an IRQ,
+			 * USB_LINK_STATUS that will be triggered when the USB
+			 * link status changes. The exception is USB connected
+			 * during startup. Then we don't get a
+			 * USB_LINK_STATUS IRQ
+			 */
+			if (di->vbus_detected_start) {
+				di->vbus_detected_start = false;
+				ret = ab8500_charger_detect_usb_type(di);
+				if (!ret) {
+					ab8500_charger_set_usb_connected(di,
+						true);
+					ab8500_power_supply_changed(di,
+						&di->usb_chg.psy);
+				}
+			}
+		}
+	}
+}
+
+/**
+ * ab8500_charger_usb_link_status_work() - work to detect USB type
+ * @work:	pointer to the work_struct structure
+ *
+ * Detect the type of USB plugged
+ */
+static void ab8500_charger_usb_link_status_work(struct work_struct *work)
+{
+	int ret;
+
+	struct ab8500_charger *di = container_of(work,
+		struct ab8500_charger, usb_link_status_work);
+
+	/*
+	 * Since we can't be sure that the events are received
+	 * synchronously, we have the check if  is
+	 * connected by reading the status register
+	 */
+	ret = ab8500_charger_detect_chargers(di);
+	if (ret < 0)
+		return;
+
+	if (!(ret & USB_PW_CONN)) {
+		di->vbus_detected = 0;
+		ab8500_charger_set_usb_connected(di, false);
+		ab8500_power_supply_changed(di, &di->usb_chg.psy);
+	} else {
+		di->vbus_detected = 1;
+		ret = ab8500_charger_read_usb_type(di);
+		if (!ret) {
+			/* Update maximum input current */
+			ret = ab8500_charger_set_vbus_in_curr(di,
+					di->max_usb_in_curr);
+			if (ret)
+				return;
+
+			ab8500_charger_set_usb_connected(di, true);
+			ab8500_power_supply_changed(di, &di->usb_chg.psy);
+		} else if (ret == -ENXIO) {
+			/* No valid charger type detected */
+			ab8500_charger_set_usb_connected(di, false);
+			ab8500_power_supply_changed(di, &di->usb_chg.psy);
+		}
+	}
+}
+
+static void ab8500_charger_usb_state_changed_work(struct work_struct *work)
+{
+	int ret;
+	unsigned long flags;
+
+	struct ab8500_charger *di = container_of(work,
+		struct ab8500_charger, usb_state_changed_work);
+
+	if (!di->vbus_detected)
+		return;
+
+	spin_lock_irqsave(&di->usb_state.usb_lock, flags);
+	di->usb_state.usb_changed = false;
+	spin_unlock_irqrestore(&di->usb_state.usb_lock, flags);
+
+	/*
+	 * wait for some time until you get updates from the usb stack
+	 * and negotiations are completed
+	 */
+	msleep(250);
+
+	if (di->usb_state.usb_changed)
+		return;
+
+	dev_dbg(di->dev, "%s USB state: 0x%02x mA: %d\n",
+		__func__, di->usb_state.state, di->usb_state.usb_current);
+
+	switch (di->usb_state.state) {
+	case AB8500_BM_USB_STATE_RESET_HS:
+	case AB8500_BM_USB_STATE_RESET_FS:
+	case AB8500_BM_USB_STATE_SUSPEND:
+	case AB8500_BM_USB_STATE_MAX:
+		ab8500_charger_set_usb_connected(di, false);
+		ab8500_power_supply_changed(di, &di->usb_chg.psy);
+		break;
+
+	case AB8500_BM_USB_STATE_RESUME:
+		/*
+		 * when suspend->resume there should be delay
+		 * of 1sec for enabling charging
+		 */
+		msleep(1000);
+		/* Intentional fall through */
+	case AB8500_BM_USB_STATE_CONFIGURED:
+		/*
+		 * USB is configured, enable charging with the charging
+		 * input current obtained from USB driver
+		 */
+		if (!ab8500_charger_get_usb_cur(di)) {
+			/* Update maximum input current */
+			ret = ab8500_charger_set_vbus_in_curr(di,
+					di->max_usb_in_curr);
+			if (ret)
+				return;
+
+			ab8500_charger_set_usb_connected(di, true);
+			ab8500_power_supply_changed(di, &di->usb_chg.psy);
+		}
+		break;
+
+	default:
+		break;
+	};
+}
+
+/**
+ * ab8500_charger_check_usbchargernotok_work() - check USB chg not ok status
+ * @work:	pointer to the work_struct structure
+ *
+ * Work queue function for checking the USB charger Not OK status
+ */
+static void ab8500_charger_check_usbchargernotok_work(struct work_struct *work)
+{
+	int ret;
+	u8 reg_value;
+	bool prev_status;
+
+	struct ab8500_charger *di = container_of(work,
+		struct ab8500_charger, check_usbchgnotok_work.work);
+
+	/* Check if the status bit for usbchargernotok is still active */
+	ret = abx500_get_register_interruptible(di->dev,
+		AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG, &reg_value);
+	if (ret < 0) {
+		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+		return;
+	}
+	prev_status = di->flags.usbchargernotok;
+
+	if (reg_value & VBUS_CH_NOK) {
+		di->flags.usbchargernotok = true;
+		/* Check again in 1sec */
+		queue_delayed_work(di->charger_wq,
+			&di->check_usbchgnotok_work, HZ);
+	} else {
+		di->flags.usbchargernotok = false;
+		di->flags.vbus_collapse = false;
+	}
+
+	if (prev_status != di->flags.usbchargernotok)
+		ab8500_power_supply_changed(di, &di->usb_chg.psy);
+}
+
+/**
+ * ab8500_charger_check_main_thermal_prot_work() - check main thermal status
+ * @work:	pointer to the work_struct structure
+ *
+ * Work queue function for checking the Main thermal prot status
+ */
+static void ab8500_charger_check_main_thermal_prot_work(
+	struct work_struct *work)
+{
+	int ret;
+	u8 reg_value;
+
+	struct ab8500_charger *di = container_of(work,
+		struct ab8500_charger, check_main_thermal_prot_work);
+
+	/* Check if the status bit for main_thermal_prot is still active */
+	ret = abx500_get_register_interruptible(di->dev,
+		AB8500_CHARGER, AB8500_CH_STATUS2_REG, &reg_value);
+	if (ret < 0) {
+		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+		return;
+	}
+	if (reg_value & MAIN_CH_TH_PROT)
+		di->flags.main_thermal_prot = true;
+	else
+		di->flags.main_thermal_prot = false;
+
+	ab8500_power_supply_changed(di, &di->ac_chg.psy);
+}
+
+/**
+ * ab8500_charger_check_usb_thermal_prot_work() - check usb thermal status
+ * @work:	pointer to the work_struct structure
+ *
+ * Work queue function for checking the USB thermal prot status
+ */
+static void ab8500_charger_check_usb_thermal_prot_work(
+	struct work_struct *work)
+{
+	int ret;
+	u8 reg_value;
+
+	struct ab8500_charger *di = container_of(work,
+		struct ab8500_charger, check_usb_thermal_prot_work);
+
+	/* Check if the status bit for usb_thermal_prot is still active */
+	ret = abx500_get_register_interruptible(di->dev,
+		AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG, &reg_value);
+	if (ret < 0) {
+		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+		return;
+	}
+	if (reg_value & USB_CH_TH_PROT)
+		di->flags.usb_thermal_prot = true;
+	else
+		di->flags.usb_thermal_prot = false;
+
+	ab8500_power_supply_changed(di, &di->usb_chg.psy);
+}
+
+/**
+ * ab8500_charger_mainchunplugdet_handler() - main charger unplugged
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_charger structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_charger_mainchunplugdet_handler(int irq, void *_di)
+{
+	struct ab8500_charger *di = _di;
+
+	dev_dbg(di->dev, "Main charger unplugged\n");
+	queue_work(di->charger_wq, &di->ac_work);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_charger_mainchplugdet_handler() - main charger plugged
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_charger structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_charger_mainchplugdet_handler(int irq, void *_di)
+{
+	struct ab8500_charger *di = _di;
+
+	dev_dbg(di->dev, "Main charger plugged\n");
+	queue_work(di->charger_wq, &di->ac_work);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_charger_mainextchnotok_handler() - main charger not ok
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_charger structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_charger_mainextchnotok_handler(int irq, void *_di)
+{
+	struct ab8500_charger *di = _di;
+
+	dev_dbg(di->dev, "Main charger not ok\n");
+	di->flags.mainextchnotok = true;
+	ab8500_power_supply_changed(di, &di->ac_chg.psy);
+
+	/* Schedule a new HW failure check */
+	queue_delayed_work(di->charger_wq, &di->check_hw_failure_work, 0);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_charger_mainchthprotr_handler() - Die temp is above main charger
+ * thermal protection threshold
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_charger structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_charger_mainchthprotr_handler(int irq, void *_di)
+{
+	struct ab8500_charger *di = _di;
+
+	dev_dbg(di->dev,
+		"Die temp above Main charger thermal protection threshold\n");
+	queue_work(di->charger_wq, &di->check_main_thermal_prot_work);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_charger_mainchthprotf_handler() - Die temp is below main charger
+ * thermal protection threshold
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_charger structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_charger_mainchthprotf_handler(int irq, void *_di)
+{
+	struct ab8500_charger *di = _di;
+
+	dev_dbg(di->dev,
+		"Die temp ok for Main charger thermal protection threshold\n");
+	queue_work(di->charger_wq, &di->check_main_thermal_prot_work);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_charger_vbusdetf_handler() - VBUS falling detected
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_charger structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_charger_vbusdetf_handler(int irq, void *_di)
+{
+	struct ab8500_charger *di = _di;
+
+	dev_dbg(di->dev, "VBUS falling detected\n");
+	queue_work(di->charger_wq, &di->detect_usb_type_work);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_charger_vbusdetr_handler() - VBUS rising detected
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_charger structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_charger_vbusdetr_handler(int irq, void *_di)
+{
+	struct ab8500_charger *di = _di;
+
+	di->vbus_detected = true;
+	dev_dbg(di->dev, "VBUS rising detected\n");
+	queue_work(di->charger_wq, &di->detect_usb_type_work);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_charger_usblinkstatus_handler() - USB link status has changed
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_charger structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_charger_usblinkstatus_handler(int irq, void *_di)
+{
+	struct ab8500_charger *di = _di;
+
+	dev_dbg(di->dev, "USB link status changed\n");
+
+	queue_work(di->charger_wq, &di->usb_link_status_work);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_charger_usbchthprotr_handler() - Die temp is above usb charger
+ * thermal protection threshold
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_charger structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_charger_usbchthprotr_handler(int irq, void *_di)
+{
+	struct ab8500_charger *di = _di;
+
+	dev_dbg(di->dev,
+		"Die temp above USB charger thermal protection threshold\n");
+	queue_work(di->charger_wq, &di->check_usb_thermal_prot_work);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_charger_usbchthprotf_handler() - Die temp is below usb charger
+ * thermal protection threshold
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_charger structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_charger_usbchthprotf_handler(int irq, void *_di)
+{
+	struct ab8500_charger *di = _di;
+
+	dev_dbg(di->dev,
+		"Die temp ok for USB charger thermal protection threshold\n");
+	queue_work(di->charger_wq, &di->check_usb_thermal_prot_work);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_charger_usbchargernotokr_handler() - USB charger not ok detected
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_charger structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_charger_usbchargernotokr_handler(int irq, void *_di)
+{
+	struct ab8500_charger *di = _di;
+
+	dev_dbg(di->dev, "Not allowed USB charger detected\n");
+	queue_delayed_work(di->charger_wq, &di->check_usbchgnotok_work, 0);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_charger_chwdexp_handler() - Charger watchdog expired
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_charger structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_charger_chwdexp_handler(int irq, void *_di)
+{
+	struct ab8500_charger *di = _di;
+
+	dev_dbg(di->dev, "Charger watchdog expired\n");
+
+	/*
+	 * The charger that was online when the watchdog expired
+	 * needs to be restarted for charging to start again
+	 */
+	if (di->ac.charger_online) {
+		di->ac.wd_expired = true;
+		ab8500_power_supply_changed(di, &di->ac_chg.psy);
+	}
+	if (di->usb.charger_online) {
+		di->usb.wd_expired = true;
+		ab8500_power_supply_changed(di, &di->usb_chg.psy);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_charger_vbusovv_handler() - VBUS overvoltage detected
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_charger structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_charger_vbusovv_handler(int irq, void *_di)
+{
+	struct ab8500_charger *di = _di;
+
+	dev_dbg(di->dev, "VBUS overvoltage detected\n");
+	di->flags.vbus_ovv = true;
+	ab8500_power_supply_changed(di, &di->usb_chg.psy);
+
+	/* Schedule a new HW failure check */
+	queue_delayed_work(di->charger_wq, &di->check_hw_failure_work, 0);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_charger_ac_get_property() - get the ac/mains properties
+ * @psy:       pointer to the power_supply structure
+ * @psp:       pointer to the power_supply_property structure
+ * @val:       pointer to the power_supply_propval union
+ *
+ * This function gets called when an application tries to get the ac/mains
+ * properties by reading the sysfs files.
+ * AC/Mains properties are online, present and voltage.
+ * online:     ac/mains charging is in progress or not
+ * present:    presence of the ac/mains
+ * voltage:    AC/Mains voltage
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_charger_ac_get_property(struct power_supply *psy,
+	enum power_supply_property psp,
+	union power_supply_propval *val)
+{
+	struct ab8500_charger *di;
+
+	di = to_ab8500_charger_ac_device_info(psy_to_ux500_charger(psy));
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_HEALTH:
+		if (di->flags.mainextchnotok)
+			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+		else if (di->ac.wd_expired || di->usb.wd_expired)
+			val->intval = POWER_SUPPLY_HEALTH_DEAD;
+		else if (di->flags.main_thermal_prot)
+			val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+		else
+			val->intval = POWER_SUPPLY_HEALTH_GOOD;
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = di->ac.charger_online;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = di->ac.charger_connected;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		di->ac.charger_voltage = ab8500_charger_get_ac_voltage(di);
+		val->intval = di->ac.charger_voltage * 1000;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+		/*
+		 * This property is used to indicate when CV mode is entered
+		 * for the AC charger
+		 */
+		di->ac.cv_active = ab8500_charger_ac_cv(di);
+		val->intval = di->ac.cv_active;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = ab8500_charger_get_ac_current(di) * 1000;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ * ab8500_charger_usb_get_property() - get the usb properties
+ * @psy:        pointer to the power_supply structure
+ * @psp:        pointer to the power_supply_property structure
+ * @val:        pointer to the power_supply_propval union
+ *
+ * This function gets called when an application tries to get the usb
+ * properties by reading the sysfs files.
+ * USB properties are online, present and voltage.
+ * online:     usb charging is in progress or not
+ * present:    presence of the usb
+ * voltage:    vbus voltage
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_charger_usb_get_property(struct power_supply *psy,
+	enum power_supply_property psp,
+	union power_supply_propval *val)
+{
+	struct ab8500_charger *di;
+
+	di = to_ab8500_charger_usb_device_info(psy_to_ux500_charger(psy));
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_HEALTH:
+		if (di->flags.usbchargernotok)
+			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+		else if (di->ac.wd_expired || di->usb.wd_expired)
+			val->intval = POWER_SUPPLY_HEALTH_DEAD;
+		else if (di->flags.usb_thermal_prot)
+			val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+		else if (di->flags.vbus_ovv)
+			val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+		else
+			val->intval = POWER_SUPPLY_HEALTH_GOOD;
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = di->usb.charger_online;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = di->usb.charger_connected;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		di->usb.charger_voltage = ab8500_charger_get_vbus_voltage(di);
+		val->intval = di->usb.charger_voltage * 1000;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+		/*
+		 * This property is used to indicate when CV mode is entered
+		 * for the USB charger
+		 */
+		di->usb.cv_active = ab8500_charger_usb_cv(di);
+		val->intval = di->usb.cv_active;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = ab8500_charger_get_usb_current(di) * 1000;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_AVG:
+		/*
+		 * This property is used to indicate when VBUS has collapsed
+		 * due to too high output current from the USB charger
+		 */
+		if (di->flags.vbus_collapse)
+			val->intval = 1;
+		else
+			val->intval = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ * ab8500_charger_init_hw_registers() - Set up charger related registers
+ * @di:		pointer to the ab8500_charger structure
+ *
+ * Set up charger OVV, watchdog and maximum voltage registers as well as
+ * charging of the backup battery
+ */
+static int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
+{
+	int ret = 0;
+
+	/* Setup maximum charger current and voltage for ABB cut2.0 */
+	if (!is_ab8500_1p1_or_earlier(di->parent)) {
+		ret = abx500_set_register_interruptible(di->dev,
+			AB8500_CHARGER,
+			AB8500_CH_VOLT_LVL_MAX_REG, CH_VOL_LVL_4P6);
+		if (ret) {
+			dev_err(di->dev,
+				"failed to set CH_VOLT_LVL_MAX_REG\n");
+			goto out;
+		}
+
+		ret = abx500_set_register_interruptible(di->dev,
+			AB8500_CHARGER,
+			AB8500_CH_OPT_CRNTLVL_MAX_REG, CH_OP_CUR_LVL_1P6);
+		if (ret) {
+			dev_err(di->dev,
+				"failed to set CH_OPT_CRNTLVL_MAX_REG\n");
+			goto out;
+		}
+	}
+
+	/* VBUS OVV set to 6.3V and enable automatic current limitiation */
+	ret = abx500_set_register_interruptible(di->dev,
+		AB8500_CHARGER,
+		AB8500_USBCH_CTRL2_REG,
+		VBUS_OVV_SELECT_6P3V | VBUS_AUTO_IN_CURR_LIM_ENA);
+	if (ret) {
+		dev_err(di->dev, "failed to set VBUS OVV\n");
+		goto out;
+	}
+
+	/* Enable main watchdog in OTP */
+	ret = abx500_set_register_interruptible(di->dev,
+		AB8500_OTP_EMUL, AB8500_OTP_CONF_15, OTP_ENABLE_WD);
+	if (ret) {
+		dev_err(di->dev, "failed to enable main WD in OTP\n");
+		goto out;
+	}
+
+	/* Enable main watchdog */
+	ret = abx500_set_register_interruptible(di->dev,
+		AB8500_SYS_CTRL2_BLOCK,
+		AB8500_MAIN_WDOG_CTRL_REG, MAIN_WDOG_ENA);
+	if (ret) {
+		dev_err(di->dev, "faile to enable main watchdog\n");
+		goto out;
+	}
+
+	/*
+	 * Due to internal synchronisation, Enable and Kick watchdog bits
+	 * cannot be enabled in a single write.
+	 * A minimum delay of 2*32 kHz period (62.5µs) must be inserted
+	 * between writing Enable then Kick bits.
+	 */
+	udelay(63);
+
+	/* Kick main watchdog */
+	ret = abx500_set_register_interruptible(di->dev,
+		AB8500_SYS_CTRL2_BLOCK,
+		AB8500_MAIN_WDOG_CTRL_REG,
+		(MAIN_WDOG_ENA | MAIN_WDOG_KICK));
+	if (ret) {
+		dev_err(di->dev, "failed to kick main watchdog\n");
+		goto out;
+	}
+
+	/* Disable main watchdog */
+	ret = abx500_set_register_interruptible(di->dev,
+		AB8500_SYS_CTRL2_BLOCK,
+		AB8500_MAIN_WDOG_CTRL_REG, MAIN_WDOG_DIS);
+	if (ret) {
+		dev_err(di->dev, "failed to disable main watchdog\n");
+		goto out;
+	}
+
+	/* Set watchdog timeout */
+	ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+		AB8500_CH_WD_TIMER_REG, WD_TIMER);
+	if (ret) {
+		dev_err(di->dev, "failed to set charger watchdog timeout\n");
+		goto out;
+	}
+
+	/* Backup battery voltage and current */
+	ret = abx500_set_register_interruptible(di->dev,
+		AB8500_RTC,
+		AB8500_RTC_BACKUP_CHG_REG,
+		di->bat->bkup_bat_v |
+		di->bat->bkup_bat_i);
+	if (ret) {
+		dev_err(di->dev, "failed to setup backup battery charging\n");
+		goto out;
+	}
+
+	/* Enable backup battery charging */
+	abx500_mask_and_set_register_interruptible(di->dev,
+		AB8500_RTC, AB8500_RTC_CTRL_REG,
+		RTC_BUP_CH_ENA, RTC_BUP_CH_ENA);
+	if (ret < 0)
+		dev_err(di->dev, "%s mask and set failed\n", __func__);
+
+out:
+	return ret;
+}
+
+/*
+ * ab8500 charger driver interrupts and their respective isr
+ */
+static struct ab8500_charger_interrupts ab8500_charger_irq[] = {
+	{"MAIN_CH_UNPLUG_DET", ab8500_charger_mainchunplugdet_handler},
+	{"MAIN_CHARGE_PLUG_DET", ab8500_charger_mainchplugdet_handler},
+	{"MAIN_EXT_CH_NOT_OK", ab8500_charger_mainextchnotok_handler},
+	{"MAIN_CH_TH_PROT_R", ab8500_charger_mainchthprotr_handler},
+	{"MAIN_CH_TH_PROT_F", ab8500_charger_mainchthprotf_handler},
+	{"VBUS_DET_F", ab8500_charger_vbusdetf_handler},
+	{"VBUS_DET_R", ab8500_charger_vbusdetr_handler},
+	{"USB_LINK_STATUS", ab8500_charger_usblinkstatus_handler},
+	{"USB_CH_TH_PROT_R", ab8500_charger_usbchthprotr_handler},
+	{"USB_CH_TH_PROT_F", ab8500_charger_usbchthprotf_handler},
+	{"USB_CHARGER_NOT_OKR", ab8500_charger_usbchargernotokr_handler},
+	{"VBUS_OVV", ab8500_charger_vbusovv_handler},
+	{"CH_WD_EXP", ab8500_charger_chwdexp_handler},
+};
+
+static int ab8500_charger_usb_notifier_call(struct notifier_block *nb,
+		unsigned long event, void *power)
+{
+	struct ab8500_charger *di =
+		container_of(nb, struct ab8500_charger, nb);
+	enum ab8500_usb_state bm_usb_state;
+	unsigned mA = *((unsigned *)power);
+
+	if (event != USB_EVENT_VBUS) {
+		dev_dbg(di->dev, "not a standard host, returning\n");
+		return NOTIFY_DONE;
+	}
+
+	/* TODO: State is fabricate  here. See if charger really needs USB
+	 * state or if mA is enough
+	 */
+	if ((di->usb_state.usb_current == 2) && (mA > 2))
+		bm_usb_state = AB8500_BM_USB_STATE_RESUME;
+	else if (mA == 0)
+		bm_usb_state = AB8500_BM_USB_STATE_RESET_HS;
+	else if (mA == 2)
+		bm_usb_state = AB8500_BM_USB_STATE_SUSPEND;
+	else if (mA >= 8) /* 8, 100, 500 */
+		bm_usb_state = AB8500_BM_USB_STATE_CONFIGURED;
+	else /* Should never occur */
+		bm_usb_state = AB8500_BM_USB_STATE_RESET_FS;
+
+	dev_dbg(di->dev, "%s usb_state: 0x%02x mA: %d\n",
+		__func__, bm_usb_state, mA);
+
+	spin_lock(&di->usb_state.usb_lock);
+	di->usb_state.usb_changed = true;
+	spin_unlock(&di->usb_state.usb_lock);
+
+	di->usb_state.state = bm_usb_state;
+	di->usb_state.usb_current = mA;
+
+	queue_work(di->charger_wq, &di->usb_state_changed_work);
+
+	return NOTIFY_OK;
+}
+
+#if defined(CONFIG_PM)
+static int ab8500_charger_resume(struct platform_device *pdev)
+{
+	int ret;
+	struct ab8500_charger *di = platform_get_drvdata(pdev);
+
+	/*
+	 * For ABB revision 1.0 and 1.1 there is a bug in the watchdog
+	 * logic. That means we have to continously kick the charger
+	 * watchdog even when no charger is connected. This is only
+	 * valid once the AC charger has been enabled. This is
+	 * a bug that is not handled by the algorithm and the
+	 * watchdog have to be kicked by the charger driver
+	 * when the AC charger is disabled
+	 */
+	if (di->ac_conn && is_ab8500_1p1_or_earlier(di->parent)) {
+		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+			AB8500_CHARG_WD_CTRL, CHARG_WD_KICK);
+		if (ret)
+			dev_err(di->dev, "Failed to kick WD!\n");
+
+		/* If not already pending start a new timer */
+		if (!delayed_work_pending(
+			&di->kick_wd_work)) {
+			queue_delayed_work(di->charger_wq, &di->kick_wd_work,
+				round_jiffies(WD_KICK_INTERVAL));
+		}
+	}
+
+	/* If we still have a HW failure, schedule a new check */
+	if (di->flags.mainextchnotok || di->flags.vbus_ovv) {
+		queue_delayed_work(di->charger_wq,
+			&di->check_hw_failure_work, 0);
+	}
+
+	return 0;
+}
+
+static int ab8500_charger_suspend(struct platform_device *pdev,
+	pm_message_t state)
+{
+	struct ab8500_charger *di = platform_get_drvdata(pdev);
+
+	/* Cancel any pending HW failure check */
+	if (delayed_work_pending(&di->check_hw_failure_work))
+		cancel_delayed_work(&di->check_hw_failure_work);
+
+	return 0;
+}
+#else
+#define ab8500_charger_suspend      NULL
+#define ab8500_charger_resume       NULL
+#endif
+
+static int __devexit ab8500_charger_remove(struct platform_device *pdev)
+{
+	struct ab8500_charger *di = platform_get_drvdata(pdev);
+	int i, irq, ret;
+
+	/* Disable AC charging */
+	ab8500_charger_ac_en(&di->ac_chg, false, 0, 0);
+
+	/* Disable USB charging */
+	ab8500_charger_usb_en(&di->usb_chg, false, 0, 0);
+
+	/* Disable interrupts */
+	for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) {
+		irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name);
+		free_irq(irq, di);
+	}
+
+	/* disable the regulator */
+	regulator_put(di->regu);
+
+	/* Backup battery voltage and current disable */
+	ret = abx500_mask_and_set_register_interruptible(di->dev,
+		AB8500_RTC, AB8500_RTC_CTRL_REG, RTC_BUP_CH_ENA, 0);
+	if (ret < 0)
+		dev_err(di->dev, "%s mask and set failed\n", __func__);
+
+	usb_unregister_notifier(di->usb_phy, &di->nb);
+	usb_put_transceiver(di->usb_phy);
+
+	/* Delete the work queue */
+	destroy_workqueue(di->charger_wq);
+
+	flush_scheduled_work();
+	power_supply_unregister(&di->usb_chg.psy);
+	power_supply_unregister(&di->ac_chg.psy);
+	platform_set_drvdata(pdev, NULL);
+	kfree(di);
+
+	return 0;
+}
+
+static int __devinit ab8500_charger_probe(struct platform_device *pdev)
+{
+	int irq, i, charger_status, ret = 0;
+	struct abx500_bm_plat_data *plat_data;
+
+	struct ab8500_charger *di =
+		kzalloc(sizeof(struct ab8500_charger), GFP_KERNEL);
+	if (!di)
+		return -ENOMEM;
+
+	/* get parent data */
+	di->dev = &pdev->dev;
+	di->parent = dev_get_drvdata(pdev->dev.parent);
+	di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+
+	/* initialize lock */
+	spin_lock_init(&di->usb_state.usb_lock);
+
+	/* get charger specific platform data */
+	plat_data = pdev->dev.platform_data;
+	di->pdata = plat_data->charger;
+
+	if (!di->pdata) {
+		dev_err(di->dev, "no charger platform data supplied\n");
+		ret = -EINVAL;
+		goto free_device_info;
+	}
+
+	/* get battery specific platform data */
+	di->bat = plat_data->battery;
+	if (!di->bat) {
+		dev_err(di->dev, "no battery platform data supplied\n");
+		ret = -EINVAL;
+		goto free_device_info;
+	}
+
+	di->autopower = false;
+
+	/* AC supply */
+	/* power_supply base class */
+	di->ac_chg.psy.name = "ab8500_ac";
+	di->ac_chg.psy.type = POWER_SUPPLY_TYPE_MAINS;
+	di->ac_chg.psy.properties = ab8500_charger_ac_props;
+	di->ac_chg.psy.num_properties = ARRAY_SIZE(ab8500_charger_ac_props);
+	di->ac_chg.psy.get_property = ab8500_charger_ac_get_property;
+	di->ac_chg.psy.supplied_to = di->pdata->supplied_to;
+	di->ac_chg.psy.num_supplicants = di->pdata->num_supplicants;
+	/* ux500_charger sub-class */
+	di->ac_chg.ops.enable = &ab8500_charger_ac_en;
+	di->ac_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
+	di->ac_chg.ops.update_curr = &ab8500_charger_update_charger_current;
+	di->ac_chg.max_out_volt = ab8500_charger_voltage_map[
+		ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
+	di->ac_chg.max_out_curr = ab8500_charger_current_map[
+		ARRAY_SIZE(ab8500_charger_current_map) - 1];
+
+	/* USB supply */
+	/* power_supply base class */
+	di->usb_chg.psy.name = "ab8500_usb";
+	di->usb_chg.psy.type = POWER_SUPPLY_TYPE_USB;
+	di->usb_chg.psy.properties = ab8500_charger_usb_props;
+	di->usb_chg.psy.num_properties = ARRAY_SIZE(ab8500_charger_usb_props);
+	di->usb_chg.psy.get_property = ab8500_charger_usb_get_property;
+	di->usb_chg.psy.supplied_to = di->pdata->supplied_to;
+	di->usb_chg.psy.num_supplicants = di->pdata->num_supplicants;
+	/* ux500_charger sub-class */
+	di->usb_chg.ops.enable = &ab8500_charger_usb_en;
+	di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
+	di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current;
+	di->usb_chg.max_out_volt = ab8500_charger_voltage_map[
+		ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
+	di->usb_chg.max_out_curr = ab8500_charger_current_map[
+		ARRAY_SIZE(ab8500_charger_current_map) - 1];
+
+
+	/* Create a work queue for the charger */
+	di->charger_wq =
+		create_singlethread_workqueue("ab8500_charger_wq");
+	if (di->charger_wq == NULL) {
+		dev_err(di->dev, "failed to create work queue\n");
+		goto free_device_info;
+	}
+
+	/* Init work for HW failure check */
+	INIT_DELAYED_WORK_DEFERRABLE(&di->check_hw_failure_work,
+		ab8500_charger_check_hw_failure_work);
+	INIT_DELAYED_WORK_DEFERRABLE(&di->check_usbchgnotok_work,
+		ab8500_charger_check_usbchargernotok_work);
+
+	/*
+	 * For ABB revision 1.0 and 1.1 there is a bug in the watchdog
+	 * logic. That means we have to continously kick the charger
+	 * watchdog even when no charger is connected. This is only
+	 * valid once the AC charger has been enabled. This is
+	 * a bug that is not handled by the algorithm and the
+	 * watchdog have to be kicked by the charger driver
+	 * when the AC charger is disabled
+	 */
+	INIT_DELAYED_WORK_DEFERRABLE(&di->kick_wd_work,
+		ab8500_charger_kick_watchdog_work);
+
+	INIT_DELAYED_WORK_DEFERRABLE(&di->check_vbat_work,
+		ab8500_charger_check_vbat_work);
+
+	/* Init work for charger detection */
+	INIT_WORK(&di->usb_link_status_work,
+		ab8500_charger_usb_link_status_work);
+	INIT_WORK(&di->ac_work, ab8500_charger_ac_work);
+	INIT_WORK(&di->detect_usb_type_work,
+		ab8500_charger_detect_usb_type_work);
+
+	INIT_WORK(&di->usb_state_changed_work,
+		ab8500_charger_usb_state_changed_work);
+
+	/* Init work for checking HW status */
+	INIT_WORK(&di->check_main_thermal_prot_work,
+		ab8500_charger_check_main_thermal_prot_work);
+	INIT_WORK(&di->check_usb_thermal_prot_work,
+		ab8500_charger_check_usb_thermal_prot_work);
+
+	/*
+	 * VDD ADC supply needs to be enabled from this driver when there
+	 * is a charger connected to avoid erroneous BTEMP_HIGH/LOW
+	 * interrupts during charging
+	 */
+	di->regu = regulator_get(di->dev, "vddadc");
+	if (IS_ERR(di->regu)) {
+		ret = PTR_ERR(di->regu);
+		dev_err(di->dev, "failed to get vddadc regulator\n");
+		goto free_charger_wq;
+	}
+
+
+	/* Initialize OVV, and other registers */
+	ret = ab8500_charger_init_hw_registers(di);
+	if (ret) {
+		dev_err(di->dev, "failed to initialize ABB registers\n");
+		goto free_regulator;
+	}
+
+	/* Register AC charger class */
+	ret = power_supply_register(di->dev, &di->ac_chg.psy);
+	if (ret) {
+		dev_err(di->dev, "failed to register AC charger\n");
+		goto free_regulator;
+	}
+
+	/* Register USB charger class */
+	ret = power_supply_register(di->dev, &di->usb_chg.psy);
+	if (ret) {
+		dev_err(di->dev, "failed to register USB charger\n");
+		goto free_ac;
+	}
+
+	di->usb_phy = usb_get_transceiver();
+	if (!di->usb_phy) {
+		dev_err(di->dev, "failed to get usb transceiver\n");
+		ret = -EINVAL;
+		goto free_usb;
+	}
+	di->nb.notifier_call = ab8500_charger_usb_notifier_call;
+	ret = usb_register_notifier(di->usb_phy, &di->nb);
+	if (ret) {
+		dev_err(di->dev, "failed to register usb notifier\n");
+		goto put_usb_phy;
+	}
+
+	/* Identify the connected charger types during startup */
+	charger_status = ab8500_charger_detect_chargers(di);
+	if (charger_status & AC_PW_CONN) {
+		di->ac.charger_connected = 1;
+		di->ac_conn = true;
+		ab8500_power_supply_changed(di, &di->ac_chg.psy);
+		sysfs_notify(&di->ac_chg.psy.dev->kobj, NULL, "present");
+	}
+
+	if (charger_status & USB_PW_CONN) {
+		dev_dbg(di->dev, "VBUS Detect during startup\n");
+		di->vbus_detected = true;
+		di->vbus_detected_start = true;
+		queue_work(di->charger_wq,
+			&di->detect_usb_type_work);
+	}
+
+	/* Register interrupts */
+	for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) {
+		irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name);
+		ret = request_threaded_irq(irq, NULL, ab8500_charger_irq[i].isr,
+			IRQF_SHARED | IRQF_NO_SUSPEND,
+			ab8500_charger_irq[i].name, di);
+
+		if (ret != 0) {
+			dev_err(di->dev, "failed to request %s IRQ %d: %d\n"
+				, ab8500_charger_irq[i].name, irq, ret);
+			goto free_irq;
+		}
+		dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
+			ab8500_charger_irq[i].name, irq, ret);
+	}
+
+	platform_set_drvdata(pdev, di);
+
+	return ret;
+
+free_irq:
+	usb_unregister_notifier(di->usb_phy, &di->nb);
+
+	/* We also have to free all successfully registered irqs */
+	for (i = i - 1; i >= 0; i--) {
+		irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name);
+		free_irq(irq, di);
+	}
+put_usb_phy:
+	usb_put_transceiver(di->usb_phy);
+free_usb:
+	power_supply_unregister(&di->usb_chg.psy);
+free_ac:
+	power_supply_unregister(&di->ac_chg.psy);
+free_regulator:
+	regulator_put(di->regu);
+free_charger_wq:
+	destroy_workqueue(di->charger_wq);
+free_device_info:
+	kfree(di);
+
+	return ret;
+}
+
+static struct platform_driver ab8500_charger_driver = {
+	.probe = ab8500_charger_probe,
+	.remove = __devexit_p(ab8500_charger_remove),
+	.suspend = ab8500_charger_suspend,
+	.resume = ab8500_charger_resume,
+	.driver = {
+		.name = "ab8500-charger",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init ab8500_charger_init(void)
+{
+	return platform_driver_register(&ab8500_charger_driver);
+}
+
+static void __exit ab8500_charger_exit(void)
+{
+	platform_driver_unregister(&ab8500_charger_driver);
+}
+
+subsys_initcall_sync(ab8500_charger_init);
+module_exit(ab8500_charger_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy");
+MODULE_ALIAS("platform:ab8500-charger");
+MODULE_DESCRIPTION("AB8500 charger management driver");
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
new file mode 100644
index 0000000..c22f2f0
--- /dev/null
+++ b/drivers/power/ab8500_fg.c
@@ -0,0 +1,2637 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2012
+ *
+ * Main and Back-up battery management driver.
+ *
+ * Note: Backup battery management is required in case of Li-Ion battery and not
+ * for capacitive battery. HREF boards have capacitive battery and hence backup
+ * battery management is not used and the supported code is available in this
+ * driver.
+ *
+ * License Terms: GNU General Public License v2
+ * Author:
+ *	Johan Palsson <johan.palsson@stericsson.com>
+ *	Karl Komierowski <karl.komierowski@stericsson.com>
+ *	Arun R Murthy <arun.murthy@stericsson.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/kobject.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500.h>
+#include <linux/slab.h>
+#include <linux/mfd/abx500/ab8500-bm.h>
+#include <linux/delay.h>
+#include <linux/mfd/abx500/ab8500-gpadc.h>
+#include <linux/mfd/abx500.h>
+#include <linux/time.h>
+#include <linux/completion.h>
+
+#define MILLI_TO_MICRO			1000
+#define FG_LSB_IN_MA			1627
+#define QLSB_NANO_AMP_HOURS_X10		1129
+#define INS_CURR_TIMEOUT		(3 * HZ)
+
+#define SEC_TO_SAMPLE(S)		(S * 4)
+
+#define NBR_AVG_SAMPLES			20
+
+#define LOW_BAT_CHECK_INTERVAL		(2 * HZ)
+
+#define VALID_CAPACITY_SEC		(45 * 60) /* 45 minutes */
+#define BATT_OK_MIN			2360 /* mV */
+#define BATT_OK_INCREMENT		50 /* mV */
+#define BATT_OK_MAX_NR_INCREMENTS	0xE
+
+/* FG constants */
+#define BATT_OVV			0x01
+
+#define interpolate(x, x1, y1, x2, y2) \
+	((y1) + ((((y2) - (y1)) * ((x) - (x1))) / ((x2) - (x1))));
+
+#define to_ab8500_fg_device_info(x) container_of((x), \
+	struct ab8500_fg, fg_psy);
+
+/**
+ * struct ab8500_fg_interrupts - ab8500 fg interupts
+ * @name:	name of the interrupt
+ * @isr		function pointer to the isr
+ */
+struct ab8500_fg_interrupts {
+	char *name;
+	irqreturn_t (*isr)(int irq, void *data);
+};
+
+enum ab8500_fg_discharge_state {
+	AB8500_FG_DISCHARGE_INIT,
+	AB8500_FG_DISCHARGE_INITMEASURING,
+	AB8500_FG_DISCHARGE_INIT_RECOVERY,
+	AB8500_FG_DISCHARGE_RECOVERY,
+	AB8500_FG_DISCHARGE_READOUT_INIT,
+	AB8500_FG_DISCHARGE_READOUT,
+	AB8500_FG_DISCHARGE_WAKEUP,
+};
+
+static char *discharge_state[] = {
+	"DISCHARGE_INIT",
+	"DISCHARGE_INITMEASURING",
+	"DISCHARGE_INIT_RECOVERY",
+	"DISCHARGE_RECOVERY",
+	"DISCHARGE_READOUT_INIT",
+	"DISCHARGE_READOUT",
+	"DISCHARGE_WAKEUP",
+};
+
+enum ab8500_fg_charge_state {
+	AB8500_FG_CHARGE_INIT,
+	AB8500_FG_CHARGE_READOUT,
+};
+
+static char *charge_state[] = {
+	"CHARGE_INIT",
+	"CHARGE_READOUT",
+};
+
+enum ab8500_fg_calibration_state {
+	AB8500_FG_CALIB_INIT,
+	AB8500_FG_CALIB_WAIT,
+	AB8500_FG_CALIB_END,
+};
+
+struct ab8500_fg_avg_cap {
+	int avg;
+	int samples[NBR_AVG_SAMPLES];
+	__kernel_time_t time_stamps[NBR_AVG_SAMPLES];
+	int pos;
+	int nbr_samples;
+	int sum;
+};
+
+struct ab8500_fg_battery_capacity {
+	int max_mah_design;
+	int max_mah;
+	int mah;
+	int permille;
+	int level;
+	int prev_mah;
+	int prev_percent;
+	int prev_level;
+	int user_mah;
+};
+
+struct ab8500_fg_flags {
+	bool fg_enabled;
+	bool conv_done;
+	bool charging;
+	bool fully_charged;
+	bool force_full;
+	bool low_bat_delay;
+	bool low_bat;
+	bool bat_ovv;
+	bool batt_unknown;
+	bool calibrate;
+	bool user_cap;
+	bool batt_id_received;
+};
+
+struct inst_curr_result_list {
+	struct list_head list;
+	int *result;
+};
+
+/**
+ * struct ab8500_fg - ab8500 FG device information
+ * @dev:		Pointer to the structure device
+ * @node:		a list of AB8500 FGs, hence prepared for reentrance
+ * @irq			holds the CCEOC interrupt number
+ * @vbat:		Battery voltage in mV
+ * @vbat_nom:		Nominal battery voltage in mV
+ * @inst_curr:		Instantenous battery current in mA
+ * @avg_curr:		Average battery current in mA
+ * @bat_temp		battery temperature
+ * @fg_samples:		Number of samples used in the FG accumulation
+ * @accu_charge:	Accumulated charge from the last conversion
+ * @recovery_cnt:	Counter for recovery mode
+ * @high_curr_cnt:	Counter for high current mode
+ * @init_cnt:		Counter for init mode
+ * @recovery_needed:	Indicate if recovery is needed
+ * @high_curr_mode:	Indicate if we're in high current mode
+ * @init_capacity:	Indicate if initial capacity measuring should be done
+ * @turn_off_fg:	True if fg was off before current measurement
+ * @calib_state		State during offset calibration
+ * @discharge_state:	Current discharge state
+ * @charge_state:	Current charge state
+ * @ab8500_fg_complete	Completion struct used for the instant current reading
+ * @flags:		Structure for information about events triggered
+ * @bat_cap:		Structure for battery capacity specific parameters
+ * @avg_cap:		Average capacity filter
+ * @parent:		Pointer to the struct ab8500
+ * @gpadc:		Pointer to the struct gpadc
+ * @pdata:		Pointer to the abx500_fg platform data
+ * @bat:		Pointer to the abx500_bm platform data
+ * @fg_psy:		Structure that holds the FG specific battery properties
+ * @fg_wq:		Work queue for running the FG algorithm
+ * @fg_periodic_work:	Work to run the FG algorithm periodically
+ * @fg_low_bat_work:	Work to check low bat condition
+ * @fg_reinit_work	Work used to reset and reinitialise the FG algorithm
+ * @fg_work:		Work to run the FG algorithm instantly
+ * @fg_acc_cur_work:	Work to read the FG accumulator
+ * @fg_check_hw_failure_work:	Work for checking HW state
+ * @cc_lock:		Mutex for locking the CC
+ * @fg_kobject:		Structure of type kobject
+ */
+struct ab8500_fg {
+	struct device *dev;
+	struct list_head node;
+	int irq;
+	int vbat;
+	int vbat_nom;
+	int inst_curr;
+	int avg_curr;
+	int bat_temp;
+	int fg_samples;
+	int accu_charge;
+	int recovery_cnt;
+	int high_curr_cnt;
+	int init_cnt;
+	bool recovery_needed;
+	bool high_curr_mode;
+	bool init_capacity;
+	bool turn_off_fg;
+	enum ab8500_fg_calibration_state calib_state;
+	enum ab8500_fg_discharge_state discharge_state;
+	enum ab8500_fg_charge_state charge_state;
+	struct completion ab8500_fg_complete;
+	struct ab8500_fg_flags flags;
+	struct ab8500_fg_battery_capacity bat_cap;
+	struct ab8500_fg_avg_cap avg_cap;
+	struct ab8500 *parent;
+	struct ab8500_gpadc *gpadc;
+	struct abx500_fg_platform_data *pdata;
+	struct abx500_bm_data *bat;
+	struct power_supply fg_psy;
+	struct workqueue_struct *fg_wq;
+	struct delayed_work fg_periodic_work;
+	struct delayed_work fg_low_bat_work;
+	struct delayed_work fg_reinit_work;
+	struct work_struct fg_work;
+	struct work_struct fg_acc_cur_work;
+	struct delayed_work fg_check_hw_failure_work;
+	struct mutex cc_lock;
+	struct kobject fg_kobject;
+};
+static LIST_HEAD(ab8500_fg_list);
+
+/**
+ * ab8500_fg_get() - returns a reference to the primary AB8500 fuel gauge
+ * (i.e. the first fuel gauge in the instance list)
+ */
+struct ab8500_fg *ab8500_fg_get(void)
+{
+	struct ab8500_fg *fg;
+
+	if (list_empty(&ab8500_fg_list))
+		return NULL;
+
+	fg = list_first_entry(&ab8500_fg_list, struct ab8500_fg, node);
+	return fg;
+}
+
+/* Main battery properties */
+static enum power_supply_property ab8500_fg_props[] = {
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CURRENT_AVG,
+	POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
+	POWER_SUPPLY_PROP_ENERGY_FULL,
+	POWER_SUPPLY_PROP_ENERGY_NOW,
+	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+	POWER_SUPPLY_PROP_CHARGE_FULL,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+};
+
+/*
+ * This array maps the raw hex value to lowbat voltage used by the AB8500
+ * Values taken from the UM0836
+ */
+static int ab8500_fg_lowbat_voltage_map[] = {
+	2300 ,
+	2325 ,
+	2350 ,
+	2375 ,
+	2400 ,
+	2425 ,
+	2450 ,
+	2475 ,
+	2500 ,
+	2525 ,
+	2550 ,
+	2575 ,
+	2600 ,
+	2625 ,
+	2650 ,
+	2675 ,
+	2700 ,
+	2725 ,
+	2750 ,
+	2775 ,
+	2800 ,
+	2825 ,
+	2850 ,
+	2875 ,
+	2900 ,
+	2925 ,
+	2950 ,
+	2975 ,
+	3000 ,
+	3025 ,
+	3050 ,
+	3075 ,
+	3100 ,
+	3125 ,
+	3150 ,
+	3175 ,
+	3200 ,
+	3225 ,
+	3250 ,
+	3275 ,
+	3300 ,
+	3325 ,
+	3350 ,
+	3375 ,
+	3400 ,
+	3425 ,
+	3450 ,
+	3475 ,
+	3500 ,
+	3525 ,
+	3550 ,
+	3575 ,
+	3600 ,
+	3625 ,
+	3650 ,
+	3675 ,
+	3700 ,
+	3725 ,
+	3750 ,
+	3775 ,
+	3800 ,
+	3825 ,
+	3850 ,
+	3850 ,
+};
+
+static u8 ab8500_volt_to_regval(int voltage)
+{
+	int i;
+
+	if (voltage < ab8500_fg_lowbat_voltage_map[0])
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(ab8500_fg_lowbat_voltage_map); i++) {
+		if (voltage < ab8500_fg_lowbat_voltage_map[i])
+			return (u8) i - 1;
+	}
+
+	/* If not captured above, return index of last element */
+	return (u8) ARRAY_SIZE(ab8500_fg_lowbat_voltage_map) - 1;
+}
+
+/**
+ * ab8500_fg_is_low_curr() - Low or high current mode
+ * @di:		pointer to the ab8500_fg structure
+ * @curr:	the current to base or our decision on
+ *
+ * Low current mode if the current consumption is below a certain threshold
+ */
+static int ab8500_fg_is_low_curr(struct ab8500_fg *di, int curr)
+{
+	/*
+	 * We want to know if we're in low current mode
+	 */
+	if (curr > -di->bat->fg_params->high_curr_threshold)
+		return true;
+	else
+		return false;
+}
+
+/**
+ * ab8500_fg_add_cap_sample() - Add capacity to average filter
+ * @di:		pointer to the ab8500_fg structure
+ * @sample:	the capacity in mAh to add to the filter
+ *
+ * A capacity is added to the filter and a new mean capacity is calculated and
+ * returned
+ */
+static int ab8500_fg_add_cap_sample(struct ab8500_fg *di, int sample)
+{
+	struct timespec ts;
+	struct ab8500_fg_avg_cap *avg = &di->avg_cap;
+
+	getnstimeofday(&ts);
+
+	do {
+		avg->sum += sample - avg->samples[avg->pos];
+		avg->samples[avg->pos] = sample;
+		avg->time_stamps[avg->pos] = ts.tv_sec;
+		avg->pos++;
+
+		if (avg->pos == NBR_AVG_SAMPLES)
+			avg->pos = 0;
+
+		if (avg->nbr_samples < NBR_AVG_SAMPLES)
+			avg->nbr_samples++;
+
+		/*
+		 * Check the time stamp for each sample. If too old,
+		 * replace with latest sample
+		 */
+	} while (ts.tv_sec - VALID_CAPACITY_SEC > avg->time_stamps[avg->pos]);
+
+	avg->avg = avg->sum / avg->nbr_samples;
+
+	return avg->avg;
+}
+
+/**
+ * ab8500_fg_clear_cap_samples() - Clear average filter
+ * @di:		pointer to the ab8500_fg structure
+ *
+ * The capacity filter is is reset to zero.
+ */
+static void ab8500_fg_clear_cap_samples(struct ab8500_fg *di)
+{
+	int i;
+	struct ab8500_fg_avg_cap *avg = &di->avg_cap;
+
+	avg->pos = 0;
+	avg->nbr_samples = 0;
+	avg->sum = 0;
+	avg->avg = 0;
+
+	for (i = 0; i < NBR_AVG_SAMPLES; i++) {
+		avg->samples[i] = 0;
+		avg->time_stamps[i] = 0;
+	}
+}
+
+/**
+ * ab8500_fg_fill_cap_sample() - Fill average filter
+ * @di:		pointer to the ab8500_fg structure
+ * @sample:	the capacity in mAh to fill the filter with
+ *
+ * The capacity filter is filled with a capacity in mAh
+ */
+static void ab8500_fg_fill_cap_sample(struct ab8500_fg *di, int sample)
+{
+	int i;
+	struct timespec ts;
+	struct ab8500_fg_avg_cap *avg = &di->avg_cap;
+
+	getnstimeofday(&ts);
+
+	for (i = 0; i < NBR_AVG_SAMPLES; i++) {
+		avg->samples[i] = sample;
+		avg->time_stamps[i] = ts.tv_sec;
+	}
+
+	avg->pos = 0;
+	avg->nbr_samples = NBR_AVG_SAMPLES;
+	avg->sum = sample * NBR_AVG_SAMPLES;
+	avg->avg = sample;
+}
+
+/**
+ * ab8500_fg_coulomb_counter() - enable coulomb counter
+ * @di:		pointer to the ab8500_fg structure
+ * @enable:	enable/disable
+ *
+ * Enable/Disable coulomb counter.
+ * On failure returns negative value.
+ */
+static int ab8500_fg_coulomb_counter(struct ab8500_fg *di, bool enable)
+{
+	int ret = 0;
+	mutex_lock(&di->cc_lock);
+	if (enable) {
+		/* To be able to reprogram the number of samples, we have to
+		 * first stop the CC and then enable it again */
+		ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+			AB8500_RTC_CC_CONF_REG, 0x00);
+		if (ret)
+			goto cc_err;
+
+		/* Program the samples */
+		ret = abx500_set_register_interruptible(di->dev,
+			AB8500_GAS_GAUGE, AB8500_GASG_CC_NCOV_ACCU,
+			di->fg_samples);
+		if (ret)
+			goto cc_err;
+
+		/* Start the CC */
+		ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+			AB8500_RTC_CC_CONF_REG,
+			(CC_DEEP_SLEEP_ENA | CC_PWR_UP_ENA));
+		if (ret)
+			goto cc_err;
+
+		di->flags.fg_enabled = true;
+	} else {
+		/* Clear any pending read requests */
+		ret = abx500_set_register_interruptible(di->dev,
+			AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG, 0);
+		if (ret)
+			goto cc_err;
+
+		ret = abx500_set_register_interruptible(di->dev,
+			AB8500_GAS_GAUGE, AB8500_GASG_CC_NCOV_ACCU_CTRL, 0);
+		if (ret)
+			goto cc_err;
+
+		/* Stop the CC */
+		ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+			AB8500_RTC_CC_CONF_REG, 0);
+		if (ret)
+			goto cc_err;
+
+		di->flags.fg_enabled = false;
+
+	}
+	dev_dbg(di->dev, " CC enabled: %d Samples: %d\n",
+		enable, di->fg_samples);
+
+	mutex_unlock(&di->cc_lock);
+
+	return ret;
+cc_err:
+	dev_err(di->dev, "%s Enabling coulomb counter failed\n", __func__);
+	mutex_unlock(&di->cc_lock);
+	return ret;
+}
+
+/**
+ * ab8500_fg_inst_curr_start() - start battery instantaneous current
+ * @di:         pointer to the ab8500_fg structure
+ *
+ * Returns 0 or error code
+ * Note: This is part "one" and has to be called before
+ * ab8500_fg_inst_curr_finalize()
+ */
+ int ab8500_fg_inst_curr_start(struct ab8500_fg *di)
+{
+	u8 reg_val;
+	int ret;
+
+	mutex_lock(&di->cc_lock);
+
+	ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+		AB8500_RTC_CC_CONF_REG, &reg_val);
+	if (ret < 0)
+		goto fail;
+
+	if (!(reg_val & CC_PWR_UP_ENA)) {
+		dev_dbg(di->dev, "%s Enable FG\n", __func__);
+		di->turn_off_fg = true;
+
+		/* Program the samples */
+		ret = abx500_set_register_interruptible(di->dev,
+			AB8500_GAS_GAUGE, AB8500_GASG_CC_NCOV_ACCU,
+			SEC_TO_SAMPLE(10));
+		if (ret)
+			goto fail;
+
+		/* Start the CC */
+		ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+			AB8500_RTC_CC_CONF_REG,
+			(CC_DEEP_SLEEP_ENA | CC_PWR_UP_ENA));
+		if (ret)
+			goto fail;
+	} else {
+		di->turn_off_fg = false;
+	}
+
+	/* Return and WFI */
+	INIT_COMPLETION(di->ab8500_fg_complete);
+	enable_irq(di->irq);
+
+	/* Note: cc_lock is still locked */
+	return 0;
+fail:
+	mutex_unlock(&di->cc_lock);
+	return ret;
+}
+
+/**
+ * ab8500_fg_inst_curr_done() - check if fg conversion is done
+ * @di:         pointer to the ab8500_fg structure
+ *
+ * Returns 1 if conversion done, 0 if still waiting
+ */
+int ab8500_fg_inst_curr_done(struct ab8500_fg *di)
+{
+	return completion_done(&di->ab8500_fg_complete);
+}
+
+/**
+ * ab8500_fg_inst_curr_finalize() - battery instantaneous current
+ * @di:         pointer to the ab8500_fg structure
+ * @res:	battery instantenous current(on success)
+ *
+ * Returns 0 or an error code
+ * Note: This is part "two" and has to be called at earliest 250 ms
+ * after ab8500_fg_inst_curr_start()
+ */
+int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res)
+{
+	u8 low, high;
+	int val;
+	int ret;
+	int timeout;
+
+	if (!completion_done(&di->ab8500_fg_complete)) {
+		timeout = wait_for_completion_timeout(&di->ab8500_fg_complete,
+			INS_CURR_TIMEOUT);
+		dev_dbg(di->dev, "Finalize time: %d ms\n",
+			((INS_CURR_TIMEOUT - timeout) * 1000) / HZ);
+		if (!timeout) {
+			ret = -ETIME;
+			disable_irq(di->irq);
+			dev_err(di->dev, "completion timed out [%d]\n",
+				__LINE__);
+			goto fail;
+		}
+	}
+
+	disable_irq(di->irq);
+
+	ret = abx500_mask_and_set_register_interruptible(di->dev,
+			AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG,
+			READ_REQ, READ_REQ);
+
+	/* 100uS between read request and read is needed */
+	usleep_range(100, 100);
+
+	/* Read CC Sample conversion value Low and high */
+	ret = abx500_get_register_interruptible(di->dev, AB8500_GAS_GAUGE,
+		AB8500_GASG_CC_SMPL_CNVL_REG,  &low);
+	if (ret < 0)
+		goto fail;
+
+	ret = abx500_get_register_interruptible(di->dev, AB8500_GAS_GAUGE,
+		AB8500_GASG_CC_SMPL_CNVH_REG,  &high);
+	if (ret < 0)
+		goto fail;
+
+	/*
+	 * negative value for Discharging
+	 * convert 2's compliment into decimal
+	 */
+	if (high & 0x10)
+		val = (low | (high << 8) | 0xFFFFE000);
+	else
+		val = (low | (high << 8));
+
+	/*
+	 * Convert to unit value in mA
+	 * Full scale input voltage is
+	 * 66.660mV => LSB = 66.660mV/(4096*res) = 1.627mA
+	 * Given a 250ms conversion cycle time the LSB corresponds
+	 * to 112.9 nAh. Convert to current by dividing by the conversion
+	 * time in hours (250ms = 1 / (3600 * 4)h)
+	 * 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm
+	 */
+	val = (val * QLSB_NANO_AMP_HOURS_X10 * 36 * 4) /
+		(1000 * di->bat->fg_res);
+
+	if (di->turn_off_fg) {
+		dev_dbg(di->dev, "%s Disable FG\n", __func__);
+
+		/* Clear any pending read requests */
+		ret = abx500_set_register_interruptible(di->dev,
+			AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG, 0);
+		if (ret)
+			goto fail;
+
+		/* Stop the CC */
+		ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+			AB8500_RTC_CC_CONF_REG, 0);
+		if (ret)
+			goto fail;
+	}
+	mutex_unlock(&di->cc_lock);
+	(*res) = val;
+
+	return 0;
+fail:
+	mutex_unlock(&di->cc_lock);
+	return ret;
+}
+
+/**
+ * ab8500_fg_inst_curr_blocking() - battery instantaneous current
+ * @di:         pointer to the ab8500_fg structure
+ * @res:	battery instantenous current(on success)
+ *
+ * Returns 0 else error code
+ */
+int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di)
+{
+	int ret;
+	int res = 0;
+
+	ret = ab8500_fg_inst_curr_start(di);
+	if (ret) {
+		dev_err(di->dev, "Failed to initialize fg_inst\n");
+		return 0;
+	}
+
+	ret = ab8500_fg_inst_curr_finalize(di, &res);
+	if (ret) {
+		dev_err(di->dev, "Failed to finalize fg_inst\n");
+		return 0;
+	}
+
+	return res;
+}
+
+/**
+ * ab8500_fg_acc_cur_work() - average battery current
+ * @work:	pointer to the work_struct structure
+ *
+ * Updated the average battery current obtained from the
+ * coulomb counter.
+ */
+static void ab8500_fg_acc_cur_work(struct work_struct *work)
+{
+	int val;
+	int ret;
+	u8 low, med, high;
+
+	struct ab8500_fg *di = container_of(work,
+		struct ab8500_fg, fg_acc_cur_work);
+
+	mutex_lock(&di->cc_lock);
+	ret = abx500_set_register_interruptible(di->dev, AB8500_GAS_GAUGE,
+		AB8500_GASG_CC_NCOV_ACCU_CTRL, RD_NCONV_ACCU_REQ);
+	if (ret)
+		goto exit;
+
+	ret = abx500_get_register_interruptible(di->dev, AB8500_GAS_GAUGE,
+		AB8500_GASG_CC_NCOV_ACCU_LOW,  &low);
+	if (ret < 0)
+		goto exit;
+
+	ret = abx500_get_register_interruptible(di->dev, AB8500_GAS_GAUGE,
+		AB8500_GASG_CC_NCOV_ACCU_MED,  &med);
+	if (ret < 0)
+		goto exit;
+
+	ret = abx500_get_register_interruptible(di->dev, AB8500_GAS_GAUGE,
+		AB8500_GASG_CC_NCOV_ACCU_HIGH, &high);
+	if (ret < 0)
+		goto exit;
+
+	/* Check for sign bit in case of negative value, 2's compliment */
+	if (high & 0x10)
+		val = (low | (med << 8) | (high << 16) | 0xFFE00000);
+	else
+		val = (low | (med << 8) | (high << 16));
+
+	/*
+	 * Convert to uAh
+	 * Given a 250ms conversion cycle time the LSB corresponds
+	 * to 112.9 nAh.
+	 * 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm
+	 */
+	di->accu_charge = (val * QLSB_NANO_AMP_HOURS_X10) /
+		(100 * di->bat->fg_res);
+
+	/*
+	 * Convert to unit value in mA
+	 * Full scale input voltage is
+	 * 66.660mV => LSB = 66.660mV/(4096*res) = 1.627mA
+	 * Given a 250ms conversion cycle time the LSB corresponds
+	 * to 112.9 nAh. Convert to current by dividing by the conversion
+	 * time in hours (= samples / (3600 * 4)h)
+	 * 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm
+	 */
+	di->avg_curr = (val * QLSB_NANO_AMP_HOURS_X10 * 36) /
+		(1000 * di->bat->fg_res * (di->fg_samples / 4));
+
+	di->flags.conv_done = true;
+
+	mutex_unlock(&di->cc_lock);
+
+	queue_work(di->fg_wq, &di->fg_work);
+
+	return;
+exit:
+	dev_err(di->dev,
+		"Failed to read or write gas gauge registers\n");
+	mutex_unlock(&di->cc_lock);
+	queue_work(di->fg_wq, &di->fg_work);
+}
+
+/**
+ * ab8500_fg_bat_voltage() - get battery voltage
+ * @di:		pointer to the ab8500_fg structure
+ *
+ * Returns battery voltage(on success) else error code
+ */
+static int ab8500_fg_bat_voltage(struct ab8500_fg *di)
+{
+	int vbat;
+	static int prev;
+
+	vbat = ab8500_gpadc_convert(di->gpadc, MAIN_BAT_V);
+	if (vbat < 0) {
+		dev_err(di->dev,
+			"%s gpadc conversion failed, using previous value\n",
+			__func__);
+		return prev;
+	}
+
+	prev = vbat;
+	return vbat;
+}
+
+/**
+ * ab8500_fg_volt_to_capacity() - Voltage based capacity
+ * @di:		pointer to the ab8500_fg structure
+ * @voltage:	The voltage to convert to a capacity
+ *
+ * Returns battery capacity in per mille based on voltage
+ */
+static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage)
+{
+	int i, tbl_size;
+	struct abx500_v_to_cap *tbl;
+	int cap = 0;
+
+	tbl = di->bat->bat_type[di->bat->batt_id].v_to_cap_tbl,
+	tbl_size = di->bat->bat_type[di->bat->batt_id].n_v_cap_tbl_elements;
+
+	for (i = 0; i < tbl_size; ++i) {
+		if (voltage > tbl[i].voltage)
+			break;
+	}
+
+	if ((i > 0) && (i < tbl_size)) {
+		cap = interpolate(voltage,
+			tbl[i].voltage,
+			tbl[i].capacity * 10,
+			tbl[i-1].voltage,
+			tbl[i-1].capacity * 10);
+	} else if (i == 0) {
+		cap = 1000;
+	} else {
+		cap = 0;
+	}
+
+	dev_dbg(di->dev, "%s Vbat: %d, Cap: %d per mille",
+		__func__, voltage, cap);
+
+	return cap;
+}
+
+/**
+ * ab8500_fg_uncomp_volt_to_capacity() - Uncompensated voltage based capacity
+ * @di:		pointer to the ab8500_fg structure
+ *
+ * Returns battery capacity based on battery voltage that is not compensated
+ * for the voltage drop due to the load
+ */
+static int ab8500_fg_uncomp_volt_to_capacity(struct ab8500_fg *di)
+{
+	di->vbat = ab8500_fg_bat_voltage(di);
+	return ab8500_fg_volt_to_capacity(di, di->vbat);
+}
+
+/**
+ * ab8500_fg_battery_resistance() - Returns the battery inner resistance
+ * @di:		pointer to the ab8500_fg structure
+ *
+ * Returns battery inner resistance added with the fuel gauge resistor value
+ * to get the total resistance in the whole link from gnd to bat+ node.
+ */
+static int ab8500_fg_battery_resistance(struct ab8500_fg *di)
+{
+	int i, tbl_size;
+	struct batres_vs_temp *tbl;
+	int resist = 0;
+
+	tbl = di->bat->bat_type[di->bat->batt_id].batres_tbl;
+	tbl_size = di->bat->bat_type[di->bat->batt_id].n_batres_tbl_elements;
+
+	for (i = 0; i < tbl_size; ++i) {
+		if (di->bat_temp / 10 > tbl[i].temp)
+			break;
+	}
+
+	if ((i > 0) && (i < tbl_size)) {
+		resist = interpolate(di->bat_temp / 10,
+			tbl[i].temp,
+			tbl[i].resist,
+			tbl[i-1].temp,
+			tbl[i-1].resist);
+	} else if (i == 0) {
+		resist = tbl[0].resist;
+	} else {
+		resist = tbl[tbl_size - 1].resist;
+	}
+
+	dev_dbg(di->dev, "%s Temp: %d battery internal resistance: %d"
+	    " fg resistance %d, total: %d (mOhm)\n",
+		__func__, di->bat_temp, resist, di->bat->fg_res / 10,
+		(di->bat->fg_res / 10) + resist);
+
+	/* fg_res variable is in 0.1mOhm */
+	resist += di->bat->fg_res / 10;
+
+	return resist;
+}
+
+/**
+ * ab8500_fg_load_comp_volt_to_capacity() - Load compensated voltage based capacity
+ * @di:		pointer to the ab8500_fg structure
+ *
+ * Returns battery capacity based on battery voltage that is load compensated
+ * for the voltage drop
+ */
+static int ab8500_fg_load_comp_volt_to_capacity(struct ab8500_fg *di)
+{
+	int vbat_comp, res;
+	int i = 0;
+	int vbat = 0;
+
+	ab8500_fg_inst_curr_start(di);
+
+	do {
+		vbat += ab8500_fg_bat_voltage(di);
+		i++;
+		msleep(5);
+	} while (!ab8500_fg_inst_curr_done(di));
+
+	ab8500_fg_inst_curr_finalize(di, &di->inst_curr);
+
+	di->vbat = vbat / i;
+	res = ab8500_fg_battery_resistance(di);
+
+	/* Use Ohms law to get the load compensated voltage */
+	vbat_comp = di->vbat - (di->inst_curr * res) / 1000;
+
+	dev_dbg(di->dev, "%s Measured Vbat: %dmV,Compensated Vbat %dmV, "
+		"R: %dmOhm, Current: %dmA Vbat Samples: %d\n",
+		__func__, di->vbat, vbat_comp, res, di->inst_curr, i);
+
+	return ab8500_fg_volt_to_capacity(di, vbat_comp);
+}
+
+/**
+ * ab8500_fg_convert_mah_to_permille() - Capacity in mAh to permille
+ * @di:		pointer to the ab8500_fg structure
+ * @cap_mah:	capacity in mAh
+ *
+ * Converts capacity in mAh to capacity in permille
+ */
+static int ab8500_fg_convert_mah_to_permille(struct ab8500_fg *di, int cap_mah)
+{
+	return (cap_mah * 1000) / di->bat_cap.max_mah_design;
+}
+
+/**
+ * ab8500_fg_convert_permille_to_mah() - Capacity in permille to mAh
+ * @di:		pointer to the ab8500_fg structure
+ * @cap_pm:	capacity in permille
+ *
+ * Converts capacity in permille to capacity in mAh
+ */
+static int ab8500_fg_convert_permille_to_mah(struct ab8500_fg *di, int cap_pm)
+{
+	return cap_pm * di->bat_cap.max_mah_design / 1000;
+}
+
+/**
+ * ab8500_fg_convert_mah_to_uwh() - Capacity in mAh to uWh
+ * @di:		pointer to the ab8500_fg structure
+ * @cap_mah:	capacity in mAh
+ *
+ * Converts capacity in mAh to capacity in uWh
+ */
+static int ab8500_fg_convert_mah_to_uwh(struct ab8500_fg *di, int cap_mah)
+{
+	u64 div_res;
+	u32 div_rem;
+
+	div_res = ((u64) cap_mah) * ((u64) di->vbat_nom);
+	div_rem = do_div(div_res, 1000);
+
+	/* Make sure to round upwards if necessary */
+	if (div_rem >= 1000 / 2)
+		div_res++;
+
+	return (int) div_res;
+}
+
+/**
+ * ab8500_fg_calc_cap_charging() - Calculate remaining capacity while charging
+ * @di:		pointer to the ab8500_fg structure
+ *
+ * Return the capacity in mAh based on previous calculated capcity and the FG
+ * accumulator register value. The filter is filled with this capacity
+ */
+static int ab8500_fg_calc_cap_charging(struct ab8500_fg *di)
+{
+	dev_dbg(di->dev, "%s cap_mah %d accu_charge %d\n",
+		__func__,
+		di->bat_cap.mah,
+		di->accu_charge);
+
+	/* Capacity should not be less than 0 */
+	if (di->bat_cap.mah + di->accu_charge > 0)
+		di->bat_cap.mah += di->accu_charge;
+	else
+		di->bat_cap.mah = 0;
+	/*
+	 * We force capacity to 100% once when the algorithm
+	 * reports that it's full.
+	 */
+	if (di->bat_cap.mah >= di->bat_cap.max_mah_design ||
+		di->flags.force_full) {
+		di->bat_cap.mah = di->bat_cap.max_mah_design;
+	}
+
+	ab8500_fg_fill_cap_sample(di, di->bat_cap.mah);
+	di->bat_cap.permille =
+		ab8500_fg_convert_mah_to_permille(di, di->bat_cap.mah);
+
+	/* We need to update battery voltage and inst current when charging */
+	di->vbat = ab8500_fg_bat_voltage(di);
+	di->inst_curr = ab8500_fg_inst_curr_blocking(di);
+
+	return di->bat_cap.mah;
+}
+
+/**
+ * ab8500_fg_calc_cap_discharge_voltage() - Capacity in discharge with voltage
+ * @di:		pointer to the ab8500_fg structure
+ * @comp:	if voltage should be load compensated before capacity calc
+ *
+ * Return the capacity in mAh based on the battery voltage. The voltage can
+ * either be load compensated or not. This value is added to the filter and a
+ * new mean value is calculated and returned.
+ */
+static int ab8500_fg_calc_cap_discharge_voltage(struct ab8500_fg *di, bool comp)
+{
+	int permille, mah;
+
+	if (comp)
+		permille = ab8500_fg_load_comp_volt_to_capacity(di);
+	else
+		permille = ab8500_fg_uncomp_volt_to_capacity(di);
+
+	mah = ab8500_fg_convert_permille_to_mah(di, permille);
+
+	di->bat_cap.mah = ab8500_fg_add_cap_sample(di, mah);
+	di->bat_cap.permille =
+		ab8500_fg_convert_mah_to_permille(di, di->bat_cap.mah);
+
+	return di->bat_cap.mah;
+}
+
+/**
+ * ab8500_fg_calc_cap_discharge_fg() - Capacity in discharge with FG
+ * @di:		pointer to the ab8500_fg structure
+ *
+ * Return the capacity in mAh based on previous calculated capcity and the FG
+ * accumulator register value. This value is added to the filter and a
+ * new mean value is calculated and returned.
+ */
+static int ab8500_fg_calc_cap_discharge_fg(struct ab8500_fg *di)
+{
+	int permille_volt, permille;
+
+	dev_dbg(di->dev, "%s cap_mah %d accu_charge %d\n",
+		__func__,
+		di->bat_cap.mah,
+		di->accu_charge);
+
+	/* Capacity should not be less than 0 */
+	if (di->bat_cap.mah + di->accu_charge > 0)
+		di->bat_cap.mah += di->accu_charge;
+	else
+		di->bat_cap.mah = 0;
+
+	if (di->bat_cap.mah >= di->bat_cap.max_mah_design)
+		di->bat_cap.mah = di->bat_cap.max_mah_design;
+
+	/*
+	 * Check against voltage based capacity. It can not be lower
+	 * than what the uncompensated voltage says
+	 */
+	permille = ab8500_fg_convert_mah_to_permille(di, di->bat_cap.mah);
+	permille_volt = ab8500_fg_uncomp_volt_to_capacity(di);
+
+	if (permille < permille_volt) {
+		di->bat_cap.permille = permille_volt;
+		di->bat_cap.mah = ab8500_fg_convert_permille_to_mah(di,
+			di->bat_cap.permille);
+
+		dev_dbg(di->dev, "%s voltage based: perm %d perm_volt %d\n",
+			__func__,
+			permille,
+			permille_volt);
+
+		ab8500_fg_fill_cap_sample(di, di->bat_cap.mah);
+	} else {
+		ab8500_fg_fill_cap_sample(di, di->bat_cap.mah);
+		di->bat_cap.permille =
+			ab8500_fg_convert_mah_to_permille(di, di->bat_cap.mah);
+	}
+
+	return di->bat_cap.mah;
+}
+
+/**
+ * ab8500_fg_capacity_level() - Get the battery capacity level
+ * @di:		pointer to the ab8500_fg structure
+ *
+ * Get the battery capacity level based on the capacity in percent
+ */
+static int ab8500_fg_capacity_level(struct ab8500_fg *di)
+{
+	int ret, percent;
+
+	percent = di->bat_cap.permille / 10;
+
+	if (percent <= di->bat->cap_levels->critical ||
+		di->flags.low_bat)
+		ret = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+	else if (percent <= di->bat->cap_levels->low)
+		ret = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+	else if (percent <= di->bat->cap_levels->normal)
+		ret = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+	else if (percent <= di->bat->cap_levels->high)
+		ret = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
+	else
+		ret = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+
+	return ret;
+}
+
+/**
+ * ab8500_fg_check_capacity_limits() - Check if capacity has changed
+ * @di:		pointer to the ab8500_fg structure
+ * @init:	capacity is allowed to go up in init mode
+ *
+ * Check if capacity or capacity limit has changed and notify the system
+ * about it using the power_supply framework
+ */
+static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init)
+{
+	bool changed = false;
+
+	di->bat_cap.level = ab8500_fg_capacity_level(di);
+
+	if (di->bat_cap.level != di->bat_cap.prev_level) {
+		/*
+		 * We do not allow reported capacity level to go up
+		 * unless we're charging or if we're in init
+		 */
+		if (!(!di->flags.charging && di->bat_cap.level >
+			di->bat_cap.prev_level) || init) {
+			dev_dbg(di->dev, "level changed from %d to %d\n",
+				di->bat_cap.prev_level,
+				di->bat_cap.level);
+			di->bat_cap.prev_level = di->bat_cap.level;
+			changed = true;
+		} else {
+			dev_dbg(di->dev, "level not allowed to go up "
+				"since no charger is connected: %d to %d\n",
+				di->bat_cap.prev_level,
+				di->bat_cap.level);
+		}
+	}
+
+	/*
+	 * If we have received the LOW_BAT IRQ, set capacity to 0 to initiate
+	 * shutdown
+	 */
+	if (di->flags.low_bat) {
+		dev_dbg(di->dev, "Battery low, set capacity to 0\n");
+		di->bat_cap.prev_percent = 0;
+		di->bat_cap.permille = 0;
+		di->bat_cap.prev_mah = 0;
+		di->bat_cap.mah = 0;
+		changed = true;
+	} else if (di->flags.fully_charged) {
+		/*
+		 * We report 100% if algorithm reported fully charged
+		 * unless capacity drops too much
+		 */
+		if (di->flags.force_full) {
+			di->bat_cap.prev_percent = di->bat_cap.permille / 10;
+			di->bat_cap.prev_mah = di->bat_cap.mah;
+		} else if (!di->flags.force_full &&
+			di->bat_cap.prev_percent !=
+			(di->bat_cap.permille) / 10 &&
+			(di->bat_cap.permille / 10) <
+			di->bat->fg_params->maint_thres) {
+			dev_dbg(di->dev,
+				"battery reported full "
+				"but capacity dropping: %d\n",
+				di->bat_cap.permille / 10);
+			di->bat_cap.prev_percent = di->bat_cap.permille / 10;
+			di->bat_cap.prev_mah = di->bat_cap.mah;
+
+			changed = true;
+		}
+	} else if (di->bat_cap.prev_percent != di->bat_cap.permille / 10) {
+		if (di->bat_cap.permille / 10 == 0) {
+			/*
+			 * We will not report 0% unless we've got
+			 * the LOW_BAT IRQ, no matter what the FG
+			 * algorithm says.
+			 */
+			di->bat_cap.prev_percent = 1;
+			di->bat_cap.permille = 1;
+			di->bat_cap.prev_mah = 1;
+			di->bat_cap.mah = 1;
+
+			changed = true;
+		} else if (!(!di->flags.charging &&
+			(di->bat_cap.permille / 10) >
+			di->bat_cap.prev_percent) || init) {
+			/*
+			 * We do not allow reported capacity to go up
+			 * unless we're charging or if we're in init
+			 */
+			dev_dbg(di->dev,
+				"capacity changed from %d to %d (%d)\n",
+				di->bat_cap.prev_percent,
+				di->bat_cap.permille / 10,
+				di->bat_cap.permille);
+			di->bat_cap.prev_percent = di->bat_cap.permille / 10;
+			di->bat_cap.prev_mah = di->bat_cap.mah;
+
+			changed = true;
+		} else {
+			dev_dbg(di->dev, "capacity not allowed to go up since "
+				"no charger is connected: %d to %d (%d)\n",
+				di->bat_cap.prev_percent,
+				di->bat_cap.permille / 10,
+				di->bat_cap.permille);
+		}
+	}
+
+	if (changed) {
+		power_supply_changed(&di->fg_psy);
+		if (di->flags.fully_charged && di->flags.force_full) {
+			dev_dbg(di->dev, "Battery full, notifying.\n");
+			di->flags.force_full = false;
+			sysfs_notify(&di->fg_kobject, NULL, "charge_full");
+		}
+		sysfs_notify(&di->fg_kobject, NULL, "charge_now");
+	}
+}
+
+static void ab8500_fg_charge_state_to(struct ab8500_fg *di,
+	enum ab8500_fg_charge_state new_state)
+{
+	dev_dbg(di->dev, "Charge state from %d [%s] to %d [%s]\n",
+		di->charge_state,
+		charge_state[di->charge_state],
+		new_state,
+		charge_state[new_state]);
+
+	di->charge_state = new_state;
+}
+
+static void ab8500_fg_discharge_state_to(struct ab8500_fg *di,
+	enum ab8500_fg_discharge_state new_state)
+{
+	dev_dbg(di->dev, "Disharge state from %d [%s] to %d [%s]\n",
+		di->discharge_state,
+		discharge_state[di->discharge_state],
+		new_state,
+		discharge_state[new_state]);
+
+	di->discharge_state = new_state;
+}
+
+/**
+ * ab8500_fg_algorithm_charging() - FG algorithm for when charging
+ * @di:		pointer to the ab8500_fg structure
+ *
+ * Battery capacity calculation state machine for when we're charging
+ */
+static void ab8500_fg_algorithm_charging(struct ab8500_fg *di)
+{
+	/*
+	 * If we change to discharge mode
+	 * we should start with recovery
+	 */
+	if (di->discharge_state != AB8500_FG_DISCHARGE_INIT_RECOVERY)
+		ab8500_fg_discharge_state_to(di,
+			AB8500_FG_DISCHARGE_INIT_RECOVERY);
+
+	switch (di->charge_state) {
+	case AB8500_FG_CHARGE_INIT:
+		di->fg_samples = SEC_TO_SAMPLE(
+			di->bat->fg_params->accu_charging);
+
+		ab8500_fg_coulomb_counter(di, true);
+		ab8500_fg_charge_state_to(di, AB8500_FG_CHARGE_READOUT);
+
+		break;
+
+	case AB8500_FG_CHARGE_READOUT:
+		/*
+		 * Read the FG and calculate the new capacity
+		 */
+		mutex_lock(&di->cc_lock);
+		if (!di->flags.conv_done) {
+			/* Wasn't the CC IRQ that got us here */
+			mutex_unlock(&di->cc_lock);
+			dev_dbg(di->dev, "%s CC conv not done\n",
+				__func__);
+
+			break;
+		}
+		di->flags.conv_done = false;
+		mutex_unlock(&di->cc_lock);
+
+		ab8500_fg_calc_cap_charging(di);
+
+		break;
+
+	default:
+		break;
+	}
+
+	/* Check capacity limits */
+	ab8500_fg_check_capacity_limits(di, false);
+}
+
+static void force_capacity(struct ab8500_fg *di)
+{
+	int cap;
+
+	ab8500_fg_clear_cap_samples(di);
+	cap = di->bat_cap.user_mah;
+	if (cap > di->bat_cap.max_mah_design) {
+		dev_dbg(di->dev, "Remaining cap %d can't be bigger than total"
+			" %d\n", cap, di->bat_cap.max_mah_design);
+		cap = di->bat_cap.max_mah_design;
+	}
+	ab8500_fg_fill_cap_sample(di, di->bat_cap.user_mah);
+	di->bat_cap.permille = ab8500_fg_convert_mah_to_permille(di, cap);
+	di->bat_cap.mah = cap;
+	ab8500_fg_check_capacity_limits(di, true);
+}
+
+static bool check_sysfs_capacity(struct ab8500_fg *di)
+{
+	int cap, lower, upper;
+	int cap_permille;
+
+	cap = di->bat_cap.user_mah;
+
+	cap_permille = ab8500_fg_convert_mah_to_permille(di,
+		di->bat_cap.user_mah);
+
+	lower = di->bat_cap.permille - di->bat->fg_params->user_cap_limit * 10;
+	upper = di->bat_cap.permille + di->bat->fg_params->user_cap_limit * 10;
+
+	if (lower < 0)
+		lower = 0;
+	/* 1000 is permille, -> 100 percent */
+	if (upper > 1000)
+		upper = 1000;
+
+	dev_dbg(di->dev, "Capacity limits:"
+		" (Lower: %d User: %d Upper: %d) [user: %d, was: %d]\n",
+		lower, cap_permille, upper, cap, di->bat_cap.mah);
+
+	/* If within limits, use the saved capacity and exit estimation...*/
+	if (cap_permille > lower && cap_permille < upper) {
+		dev_dbg(di->dev, "OK! Using users cap %d uAh now\n", cap);
+		force_capacity(di);
+		return true;
+	}
+	dev_dbg(di->dev, "Capacity from user out of limits, ignoring");
+	return false;
+}
+
+/**
+ * ab8500_fg_algorithm_discharging() - FG algorithm for when discharging
+ * @di:		pointer to the ab8500_fg structure
+ *
+ * Battery capacity calculation state machine for when we're discharging
+ */
+static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di)
+{
+	int sleep_time;
+
+	/* If we change to charge mode we should start with init */
+	if (di->charge_state != AB8500_FG_CHARGE_INIT)
+		ab8500_fg_charge_state_to(di, AB8500_FG_CHARGE_INIT);
+
+	switch (di->discharge_state) {
+	case AB8500_FG_DISCHARGE_INIT:
+		/* We use the FG IRQ to work on */
+		di->init_cnt = 0;
+		di->fg_samples = SEC_TO_SAMPLE(di->bat->fg_params->init_timer);
+		ab8500_fg_coulomb_counter(di, true);
+		ab8500_fg_discharge_state_to(di,
+			AB8500_FG_DISCHARGE_INITMEASURING);
+
+		/* Intentional fallthrough */
+	case AB8500_FG_DISCHARGE_INITMEASURING:
+		/*
+		 * Discard a number of samples during startup.
+		 * After that, use compensated voltage for a few
+		 * samples to get an initial capacity.
+		 * Then go to READOUT
+		 */
+		sleep_time = di->bat->fg_params->init_timer;
+
+		/* Discard the first [x] seconds */
+		if (di->init_cnt >
+			di->bat->fg_params->init_discard_time) {
+			ab8500_fg_calc_cap_discharge_voltage(di, true);
+
+			ab8500_fg_check_capacity_limits(di, true);
+		}
+
+		di->init_cnt += sleep_time;
+		if (di->init_cnt > di->bat->fg_params->init_total_time)
+			ab8500_fg_discharge_state_to(di,
+				AB8500_FG_DISCHARGE_READOUT_INIT);
+
+		break;
+
+	case AB8500_FG_DISCHARGE_INIT_RECOVERY:
+		di->recovery_cnt = 0;
+		di->recovery_needed = true;
+		ab8500_fg_discharge_state_to(di,
+			AB8500_FG_DISCHARGE_RECOVERY);
+
+		/* Intentional fallthrough */
+
+	case AB8500_FG_DISCHARGE_RECOVERY:
+		sleep_time = di->bat->fg_params->recovery_sleep_timer;
+
+		/*
+		 * We should check the power consumption
+		 * If low, go to READOUT (after x min) or
+		 * RECOVERY_SLEEP if time left.
+		 * If high, go to READOUT
+		 */
+		di->inst_curr = ab8500_fg_inst_curr_blocking(di);
+
+		if (ab8500_fg_is_low_curr(di, di->inst_curr)) {
+			if (di->recovery_cnt >
+				di->bat->fg_params->recovery_total_time) {
+				di->fg_samples = SEC_TO_SAMPLE(
+					di->bat->fg_params->accu_high_curr);
+				ab8500_fg_coulomb_counter(di, true);
+				ab8500_fg_discharge_state_to(di,
+					AB8500_FG_DISCHARGE_READOUT);
+				di->recovery_needed = false;
+			} else {
+				queue_delayed_work(di->fg_wq,
+					&di->fg_periodic_work,
+					sleep_time * HZ);
+			}
+			di->recovery_cnt += sleep_time;
+		} else {
+			di->fg_samples = SEC_TO_SAMPLE(
+				di->bat->fg_params->accu_high_curr);
+			ab8500_fg_coulomb_counter(di, true);
+			ab8500_fg_discharge_state_to(di,
+				AB8500_FG_DISCHARGE_READOUT);
+		}
+		break;
+
+	case AB8500_FG_DISCHARGE_READOUT_INIT:
+		di->fg_samples = SEC_TO_SAMPLE(
+			di->bat->fg_params->accu_high_curr);
+		ab8500_fg_coulomb_counter(di, true);
+		ab8500_fg_discharge_state_to(di,
+				AB8500_FG_DISCHARGE_READOUT);
+		break;
+
+	case AB8500_FG_DISCHARGE_READOUT:
+		di->inst_curr = ab8500_fg_inst_curr_blocking(di);
+
+		if (ab8500_fg_is_low_curr(di, di->inst_curr)) {
+			/* Detect mode change */
+			if (di->high_curr_mode) {
+				di->high_curr_mode = false;
+				di->high_curr_cnt = 0;
+			}
+
+			if (di->recovery_needed) {
+				ab8500_fg_discharge_state_to(di,
+					AB8500_FG_DISCHARGE_RECOVERY);
+
+				queue_delayed_work(di->fg_wq,
+					&di->fg_periodic_work, 0);
+
+				break;
+			}
+
+			ab8500_fg_calc_cap_discharge_voltage(di, true);
+		} else {
+			mutex_lock(&di->cc_lock);
+			if (!di->flags.conv_done) {
+				/* Wasn't the CC IRQ that got us here */
+				mutex_unlock(&di->cc_lock);
+				dev_dbg(di->dev, "%s CC conv not done\n",
+					__func__);
+
+				break;
+			}
+			di->flags.conv_done = false;
+			mutex_unlock(&di->cc_lock);
+
+			/* Detect mode change */
+			if (!di->high_curr_mode) {
+				di->high_curr_mode = true;
+				di->high_curr_cnt = 0;
+			}
+
+			di->high_curr_cnt +=
+				di->bat->fg_params->accu_high_curr;
+			if (di->high_curr_cnt >
+				di->bat->fg_params->high_curr_time)
+				di->recovery_needed = true;
+
+			ab8500_fg_calc_cap_discharge_fg(di);
+		}
+
+		ab8500_fg_check_capacity_limits(di, false);
+
+		break;
+
+	case AB8500_FG_DISCHARGE_WAKEUP:
+		ab8500_fg_coulomb_counter(di, true);
+		di->inst_curr = ab8500_fg_inst_curr_blocking(di);
+
+		ab8500_fg_calc_cap_discharge_voltage(di, true);
+
+		di->fg_samples = SEC_TO_SAMPLE(
+			di->bat->fg_params->accu_high_curr);
+		ab8500_fg_coulomb_counter(di, true);
+		ab8500_fg_discharge_state_to(di,
+				AB8500_FG_DISCHARGE_READOUT);
+
+		ab8500_fg_check_capacity_limits(di, false);
+
+		break;
+
+	default:
+		break;
+	}
+}
+
+/**
+ * ab8500_fg_algorithm_calibrate() - Internal columb counter offset calibration
+ * @di:		pointer to the ab8500_fg structure
+ *
+ */
+static void ab8500_fg_algorithm_calibrate(struct ab8500_fg *di)
+{
+	int ret;
+
+	switch (di->calib_state) {
+	case AB8500_FG_CALIB_INIT:
+		dev_dbg(di->dev, "Calibration ongoing...\n");
+
+		ret = abx500_mask_and_set_register_interruptible(di->dev,
+			AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG,
+			CC_INT_CAL_N_AVG_MASK, CC_INT_CAL_SAMPLES_8);
+		if (ret < 0)
+			goto err;
+
+		ret = abx500_mask_and_set_register_interruptible(di->dev,
+			AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG,
+			CC_INTAVGOFFSET_ENA, CC_INTAVGOFFSET_ENA);
+		if (ret < 0)
+			goto err;
+		di->calib_state = AB8500_FG_CALIB_WAIT;
+		break;
+	case AB8500_FG_CALIB_END:
+		ret = abx500_mask_and_set_register_interruptible(di->dev,
+			AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG,
+			CC_MUXOFFSET, CC_MUXOFFSET);
+		if (ret < 0)
+			goto err;
+		di->flags.calibrate = false;
+		dev_dbg(di->dev, "Calibration done...\n");
+		queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
+		break;
+	case AB8500_FG_CALIB_WAIT:
+		dev_dbg(di->dev, "Calibration WFI\n");
+	default:
+		break;
+	}
+	return;
+err:
+	/* Something went wrong, don't calibrate then */
+	dev_err(di->dev, "failed to calibrate the CC\n");
+	di->flags.calibrate = false;
+	di->calib_state = AB8500_FG_CALIB_INIT;
+	queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
+}
+
+/**
+ * ab8500_fg_algorithm() - Entry point for the FG algorithm
+ * @di:		pointer to the ab8500_fg structure
+ *
+ * Entry point for the battery capacity calculation state machine
+ */
+static void ab8500_fg_algorithm(struct ab8500_fg *di)
+{
+	if (di->flags.calibrate)
+		ab8500_fg_algorithm_calibrate(di);
+	else {
+		if (di->flags.charging)
+			ab8500_fg_algorithm_charging(di);
+		else
+			ab8500_fg_algorithm_discharging(di);
+	}
+
+	dev_dbg(di->dev, "[FG_DATA] %d %d %d %d %d %d %d %d %d "
+		"%d %d %d %d %d %d %d\n",
+		di->bat_cap.max_mah_design,
+		di->bat_cap.mah,
+		di->bat_cap.permille,
+		di->bat_cap.level,
+		di->bat_cap.prev_mah,
+		di->bat_cap.prev_percent,
+		di->bat_cap.prev_level,
+		di->vbat,
+		di->inst_curr,
+		di->avg_curr,
+		di->accu_charge,
+		di->flags.charging,
+		di->charge_state,
+		di->discharge_state,
+		di->high_curr_mode,
+		di->recovery_needed);
+}
+
+/**
+ * ab8500_fg_periodic_work() - Run the FG state machine periodically
+ * @work:	pointer to the work_struct structure
+ *
+ * Work queue function for periodic work
+ */
+static void ab8500_fg_periodic_work(struct work_struct *work)
+{
+	struct ab8500_fg *di = container_of(work, struct ab8500_fg,
+		fg_periodic_work.work);
+
+	if (di->init_capacity) {
+		/* A dummy read that will return 0 */
+		di->inst_curr = ab8500_fg_inst_curr_blocking(di);
+		/* Get an initial capacity calculation */
+		ab8500_fg_calc_cap_discharge_voltage(di, true);
+		ab8500_fg_check_capacity_limits(di, true);
+		di->init_capacity = false;
+
+		queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
+	} else if (di->flags.user_cap) {
+		if (check_sysfs_capacity(di)) {
+			ab8500_fg_check_capacity_limits(di, true);
+			if (di->flags.charging)
+				ab8500_fg_charge_state_to(di,
+					AB8500_FG_CHARGE_INIT);
+			else
+				ab8500_fg_discharge_state_to(di,
+					AB8500_FG_DISCHARGE_READOUT_INIT);
+		}
+		di->flags.user_cap = false;
+		queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
+	} else
+		ab8500_fg_algorithm(di);
+
+}
+
+/**
+ * ab8500_fg_check_hw_failure_work() - Check OVV_BAT condition
+ * @work:	pointer to the work_struct structure
+ *
+ * Work queue function for checking the OVV_BAT condition
+ */
+static void ab8500_fg_check_hw_failure_work(struct work_struct *work)
+{
+	int ret;
+	u8 reg_value;
+
+	struct ab8500_fg *di = container_of(work, struct ab8500_fg,
+		fg_check_hw_failure_work.work);
+
+	/*
+	 * If we have had a battery over-voltage situation,
+	 * check ovv-bit to see if it should be reset.
+	 */
+	if (di->flags.bat_ovv) {
+		ret = abx500_get_register_interruptible(di->dev,
+			AB8500_CHARGER, AB8500_CH_STAT_REG,
+			&reg_value);
+		if (ret < 0) {
+			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+			return;
+		}
+		if ((reg_value & BATT_OVV) != BATT_OVV) {
+			dev_dbg(di->dev, "Battery recovered from OVV\n");
+			di->flags.bat_ovv = false;
+			power_supply_changed(&di->fg_psy);
+			return;
+		}
+
+		/* Not yet recovered from ovv, reschedule this test */
+		queue_delayed_work(di->fg_wq, &di->fg_check_hw_failure_work,
+				   round_jiffies(HZ));
+	}
+}
+
+/**
+ * ab8500_fg_low_bat_work() - Check LOW_BAT condition
+ * @work:	pointer to the work_struct structure
+ *
+ * Work queue function for checking the LOW_BAT condition
+ */
+static void ab8500_fg_low_bat_work(struct work_struct *work)
+{
+	int vbat;
+
+	struct ab8500_fg *di = container_of(work, struct ab8500_fg,
+		fg_low_bat_work.work);
+
+	vbat = ab8500_fg_bat_voltage(di);
+
+	/* Check if LOW_BAT still fulfilled */
+	if (vbat < di->bat->fg_params->lowbat_threshold) {
+		di->flags.low_bat = true;
+		dev_warn(di->dev, "Battery voltage still LOW\n");
+
+		/*
+		 * We need to re-schedule this check to be able to detect
+		 * if the voltage increases again during charging
+		 */
+		queue_delayed_work(di->fg_wq, &di->fg_low_bat_work,
+			round_jiffies(LOW_BAT_CHECK_INTERVAL));
+	} else {
+		di->flags.low_bat = false;
+		dev_warn(di->dev, "Battery voltage OK again\n");
+	}
+
+	/* This is needed to dispatch LOW_BAT */
+	ab8500_fg_check_capacity_limits(di, false);
+
+	/* Set this flag to check if LOW_BAT IRQ still occurs */
+	di->flags.low_bat_delay = false;
+}
+
+/**
+ * ab8500_fg_battok_calc - calculate the bit pattern corresponding
+ * to the target voltage.
+ * @di:       pointer to the ab8500_fg structure
+ * @target    target voltage
+ *
+ * Returns bit pattern closest to the target voltage
+ * valid return values are 0-14. (0-BATT_OK_MAX_NR_INCREMENTS)
+ */
+
+static int ab8500_fg_battok_calc(struct ab8500_fg *di, int target)
+{
+	if (target > BATT_OK_MIN +
+		(BATT_OK_INCREMENT * BATT_OK_MAX_NR_INCREMENTS))
+		return BATT_OK_MAX_NR_INCREMENTS;
+	if (target < BATT_OK_MIN)
+		return 0;
+	return (target - BATT_OK_MIN) / BATT_OK_INCREMENT;
+}
+
+/**
+ * ab8500_fg_battok_init_hw_register - init battok levels
+ * @di:       pointer to the ab8500_fg structure
+ *
+ */
+
+static int ab8500_fg_battok_init_hw_register(struct ab8500_fg *di)
+{
+	int selected;
+	int sel0;
+	int sel1;
+	int cbp_sel0;
+	int cbp_sel1;
+	int ret;
+	int new_val;
+
+	sel0 = di->bat->fg_params->battok_falling_th_sel0;
+	sel1 = di->bat->fg_params->battok_raising_th_sel1;
+
+	cbp_sel0 = ab8500_fg_battok_calc(di, sel0);
+	cbp_sel1 = ab8500_fg_battok_calc(di, sel1);
+
+	selected = BATT_OK_MIN + cbp_sel0 * BATT_OK_INCREMENT;
+
+	if (selected != sel0)
+		dev_warn(di->dev, "Invalid voltage step:%d, using %d %d\n",
+			sel0, selected, cbp_sel0);
+
+	selected = BATT_OK_MIN + cbp_sel1 * BATT_OK_INCREMENT;
+
+	if (selected != sel1)
+		dev_warn(di->dev, "Invalid voltage step:%d, using %d %d\n",
+			sel1, selected, cbp_sel1);
+
+	new_val = cbp_sel0 | (cbp_sel1 << 4);
+
+	dev_dbg(di->dev, "using: %x %d %d\n", new_val, cbp_sel0, cbp_sel1);
+	ret = abx500_set_register_interruptible(di->dev, AB8500_SYS_CTRL2_BLOCK,
+		AB8500_BATT_OK_REG, new_val);
+	return ret;
+}
+
+/**
+ * ab8500_fg_instant_work() - Run the FG state machine instantly
+ * @work:	pointer to the work_struct structure
+ *
+ * Work queue function for instant work
+ */
+static void ab8500_fg_instant_work(struct work_struct *work)
+{
+	struct ab8500_fg *di = container_of(work, struct ab8500_fg, fg_work);
+
+	ab8500_fg_algorithm(di);
+}
+
+/**
+ * ab8500_fg_cc_data_end_handler() - isr to get battery avg current.
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_fg structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_fg_cc_data_end_handler(int irq, void *_di)
+{
+	struct ab8500_fg *di = _di;
+	complete(&di->ab8500_fg_complete);
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_fg_cc_convend_handler() - isr to get battery avg current.
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_fg structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_fg_cc_int_calib_handler(int irq, void *_di)
+{
+	struct ab8500_fg *di = _di;
+	di->calib_state = AB8500_FG_CALIB_END;
+	queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_fg_cc_convend_handler() - isr to get battery avg current.
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_fg structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_fg_cc_convend_handler(int irq, void *_di)
+{
+	struct ab8500_fg *di = _di;
+
+	queue_work(di->fg_wq, &di->fg_acc_cur_work);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_fg_batt_ovv_handler() - Battery OVV occured
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_fg structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_fg_batt_ovv_handler(int irq, void *_di)
+{
+	struct ab8500_fg *di = _di;
+
+	dev_dbg(di->dev, "Battery OVV\n");
+	di->flags.bat_ovv = true;
+	power_supply_changed(&di->fg_psy);
+
+	/* Schedule a new HW failure check */
+	queue_delayed_work(di->fg_wq, &di->fg_check_hw_failure_work, 0);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_fg_lowbatf_handler() - Battery voltage is below LOW threshold
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_fg structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_fg_lowbatf_handler(int irq, void *_di)
+{
+	struct ab8500_fg *di = _di;
+
+	if (!di->flags.low_bat_delay) {
+		dev_warn(di->dev, "Battery voltage is below LOW threshold\n");
+		di->flags.low_bat_delay = true;
+		/*
+		 * Start a timer to check LOW_BAT again after some time
+		 * This is done to avoid shutdown on single voltage dips
+		 */
+		queue_delayed_work(di->fg_wq, &di->fg_low_bat_work,
+			round_jiffies(LOW_BAT_CHECK_INTERVAL));
+	}
+	return IRQ_HANDLED;
+}
+
+/**
+ * ab8500_fg_get_property() - get the fg properties
+ * @psy:	pointer to the power_supply structure
+ * @psp:	pointer to the power_supply_property structure
+ * @val:	pointer to the power_supply_propval union
+ *
+ * This function gets called when an application tries to get the
+ * fg properties by reading the sysfs files.
+ * voltage_now:		battery voltage
+ * current_now:		battery instant current
+ * current_avg:		battery average current
+ * charge_full_design:	capacity where battery is considered full
+ * charge_now:		battery capacity in nAh
+ * capacity:		capacity in percent
+ * capacity_level:	capacity level
+ *
+ * Returns error code in case of failure else 0 on success
+ */
+static int ab8500_fg_get_property(struct power_supply *psy,
+	enum power_supply_property psp,
+	union power_supply_propval *val)
+{
+	struct ab8500_fg *di;
+
+	di = to_ab8500_fg_device_info(psy);
+
+	/*
+	 * If battery is identified as unknown and charging of unknown
+	 * batteries is disabled, we always report 100% capacity and
+	 * capacity level UNKNOWN, since we can't calculate
+	 * remaining capacity
+	 */
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		if (di->flags.bat_ovv)
+			val->intval = BATT_OVV_VALUE * 1000;
+		else
+			val->intval = di->vbat * 1000;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = di->inst_curr * 1000;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_AVG:
+		val->intval = di->avg_curr * 1000;
+		break;
+	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+		val->intval = ab8500_fg_convert_mah_to_uwh(di,
+				di->bat_cap.max_mah_design);
+		break;
+	case POWER_SUPPLY_PROP_ENERGY_FULL:
+		val->intval = ab8500_fg_convert_mah_to_uwh(di,
+				di->bat_cap.max_mah);
+		break;
+	case POWER_SUPPLY_PROP_ENERGY_NOW:
+		if (di->flags.batt_unknown && !di->bat->chg_unknown_bat &&
+				di->flags.batt_id_received)
+			val->intval = ab8500_fg_convert_mah_to_uwh(di,
+					di->bat_cap.max_mah);
+		else
+			val->intval = ab8500_fg_convert_mah_to_uwh(di,
+					di->bat_cap.prev_mah);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+		val->intval = di->bat_cap.max_mah_design;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+		val->intval = di->bat_cap.max_mah;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_NOW:
+		if (di->flags.batt_unknown && !di->bat->chg_unknown_bat &&
+				di->flags.batt_id_received)
+			val->intval = di->bat_cap.max_mah;
+		else
+			val->intval = di->bat_cap.prev_mah;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		if (di->flags.batt_unknown && !di->bat->chg_unknown_bat &&
+				di->flags.batt_id_received)
+			val->intval = 100;
+		else
+			val->intval = di->bat_cap.prev_percent;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+		if (di->flags.batt_unknown && !di->bat->chg_unknown_bat &&
+				di->flags.batt_id_received)
+			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
+		else
+			val->intval = di->bat_cap.prev_level;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data)
+{
+	struct power_supply *psy;
+	struct power_supply *ext;
+	struct ab8500_fg *di;
+	union power_supply_propval ret;
+	int i, j;
+	bool psy_found = false;
+
+	psy = (struct power_supply *)data;
+	ext = dev_get_drvdata(dev);
+	di = to_ab8500_fg_device_info(psy);
+
+	/*
+	 * For all psy where the name of your driver
+	 * appears in any supplied_to
+	 */
+	for (i = 0; i < ext->num_supplicants; i++) {
+		if (!strcmp(ext->supplied_to[i], psy->name))
+			psy_found = true;
+	}
+
+	if (!psy_found)
+		return 0;
+
+	/* Go through all properties for the psy */
+	for (j = 0; j < ext->num_properties; j++) {
+		enum power_supply_property prop;
+		prop = ext->properties[j];
+
+		if (ext->get_property(ext, prop, &ret))
+			continue;
+
+		switch (prop) {
+		case POWER_SUPPLY_PROP_STATUS:
+			switch (ext->type) {
+			case POWER_SUPPLY_TYPE_BATTERY:
+				switch (ret.intval) {
+				case POWER_SUPPLY_STATUS_UNKNOWN:
+				case POWER_SUPPLY_STATUS_DISCHARGING:
+				case POWER_SUPPLY_STATUS_NOT_CHARGING:
+					if (!di->flags.charging)
+						break;
+					di->flags.charging = false;
+					di->flags.fully_charged = false;
+					queue_work(di->fg_wq, &di->fg_work);
+					break;
+				case POWER_SUPPLY_STATUS_FULL:
+					if (di->flags.fully_charged)
+						break;
+					di->flags.fully_charged = true;
+					di->flags.force_full = true;
+					/* Save current capacity as maximum */
+					di->bat_cap.max_mah = di->bat_cap.mah;
+					queue_work(di->fg_wq, &di->fg_work);
+					break;
+				case POWER_SUPPLY_STATUS_CHARGING:
+					if (di->flags.charging)
+						break;
+					di->flags.charging = true;
+					di->flags.fully_charged = false;
+					queue_work(di->fg_wq, &di->fg_work);
+					break;
+				};
+			default:
+				break;
+			};
+			break;
+		case POWER_SUPPLY_PROP_TECHNOLOGY:
+			switch (ext->type) {
+			case POWER_SUPPLY_TYPE_BATTERY:
+				if (!di->flags.batt_id_received) {
+					const struct abx500_battery_type *b;
+
+					b = &(di->bat->bat_type[di->bat->batt_id]);
+
+					di->flags.batt_id_received = true;
+
+					di->bat_cap.max_mah_design =
+						MILLI_TO_MICRO *
+						b->charge_full_design;
+
+					di->bat_cap.max_mah =
+						di->bat_cap.max_mah_design;
+
+					di->vbat_nom = b->nominal_voltage;
+				}
+
+				if (ret.intval)
+					di->flags.batt_unknown = false;
+				else
+					di->flags.batt_unknown = true;
+				break;
+			default:
+				break;
+			}
+			break;
+		case POWER_SUPPLY_PROP_TEMP:
+			switch (ext->type) {
+			case POWER_SUPPLY_TYPE_BATTERY:
+			    if (di->flags.batt_id_received)
+				di->bat_temp = ret.intval;
+				break;
+			default:
+				break;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	return 0;
+}
+
+/**
+ * ab8500_fg_init_hw_registers() - Set up FG related registers
+ * @di:		pointer to the ab8500_fg structure
+ *
+ * Set up battery OVV, low battery voltage registers
+ */
+static int ab8500_fg_init_hw_registers(struct ab8500_fg *di)
+{
+	int ret;
+
+	/* Set VBAT OVV threshold */
+	ret = abx500_mask_and_set_register_interruptible(di->dev,
+		AB8500_CHARGER,
+		AB8500_BATT_OVV,
+		BATT_OVV_TH_4P75,
+		BATT_OVV_TH_4P75);
+	if (ret) {
+		dev_err(di->dev, "failed to set BATT_OVV\n");
+		goto out;
+	}
+
+	/* Enable VBAT OVV detection */
+	ret = abx500_mask_and_set_register_interruptible(di->dev,
+		AB8500_CHARGER,
+		AB8500_BATT_OVV,
+		BATT_OVV_ENA,
+		BATT_OVV_ENA);
+	if (ret) {
+		dev_err(di->dev, "failed to enable BATT_OVV\n");
+		goto out;
+	}
+
+	/* Low Battery Voltage */
+	ret = abx500_set_register_interruptible(di->dev,
+		AB8500_SYS_CTRL2_BLOCK,
+		AB8500_LOW_BAT_REG,
+		ab8500_volt_to_regval(
+			di->bat->fg_params->lowbat_threshold) << 1 |
+		LOW_BAT_ENABLE);
+	if (ret) {
+		dev_err(di->dev, "%s write failed\n", __func__);
+		goto out;
+	}
+
+	/* Battery OK threshold */
+	ret = ab8500_fg_battok_init_hw_register(di);
+	if (ret) {
+		dev_err(di->dev, "BattOk init write failed.\n");
+		goto out;
+	}
+out:
+	return ret;
+}
+
+/**
+ * ab8500_fg_external_power_changed() - callback for power supply changes
+ * @psy:       pointer to the structure power_supply
+ *
+ * This function is the entry point of the pointer external_power_changed
+ * of the structure power_supply.
+ * This function gets executed when there is a change in any external power
+ * supply that this driver needs to be notified of.
+ */
+static void ab8500_fg_external_power_changed(struct power_supply *psy)
+{
+	struct ab8500_fg *di = to_ab8500_fg_device_info(psy);
+
+	class_for_each_device(power_supply_class, NULL,
+		&di->fg_psy, ab8500_fg_get_ext_psy_data);
+}
+
+/**
+ * abab8500_fg_reinit_work() - work to reset the FG algorithm
+ * @work:	pointer to the work_struct structure
+ *
+ * Used to reset the current battery capacity to be able to
+ * retrigger a new voltage base capacity calculation. For
+ * test and verification purpose.
+ */
+static void ab8500_fg_reinit_work(struct work_struct *work)
+{
+	struct ab8500_fg *di = container_of(work, struct ab8500_fg,
+		fg_reinit_work.work);
+
+	if (di->flags.calibrate == false) {
+		dev_dbg(di->dev, "Resetting FG state machine to init.\n");
+		ab8500_fg_clear_cap_samples(di);
+		ab8500_fg_calc_cap_discharge_voltage(di, true);
+		ab8500_fg_charge_state_to(di, AB8500_FG_CHARGE_INIT);
+		ab8500_fg_discharge_state_to(di, AB8500_FG_DISCHARGE_INIT);
+		queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
+
+	} else {
+		dev_err(di->dev, "Residual offset calibration ongoing "
+			"retrying..\n");
+		/* Wait one second until next try*/
+		queue_delayed_work(di->fg_wq, &di->fg_reinit_work,
+			round_jiffies(1));
+	}
+}
+
+/**
+ * ab8500_fg_reinit() - forces FG algorithm to reinitialize with current values
+ *
+ * This function can be used to force the FG algorithm to recalculate a new
+ * voltage based battery capacity.
+ */
+void ab8500_fg_reinit(void)
+{
+	struct ab8500_fg *di = ab8500_fg_get();
+	/* User won't be notified if a null pointer returned. */
+	if (di != NULL)
+		queue_delayed_work(di->fg_wq, &di->fg_reinit_work, 0);
+}
+
+/* Exposure to the sysfs interface */
+
+struct ab8500_fg_sysfs_entry {
+	struct attribute attr;
+	ssize_t (*show)(struct ab8500_fg *, char *);
+	ssize_t (*store)(struct ab8500_fg *, const char *, size_t);
+};
+
+static ssize_t charge_full_show(struct ab8500_fg *di, char *buf)
+{
+	return sprintf(buf, "%d\n", di->bat_cap.max_mah);
+}
+
+static ssize_t charge_full_store(struct ab8500_fg *di, const char *buf,
+				 size_t count)
+{
+	unsigned long charge_full;
+	ssize_t ret = -EINVAL;
+
+	ret = strict_strtoul(buf, 10, &charge_full);
+
+	dev_dbg(di->dev, "Ret %zd charge_full %lu", ret, charge_full);
+
+	if (!ret) {
+		di->bat_cap.max_mah = (int) charge_full;
+		ret = count;
+	}
+	return ret;
+}
+
+static ssize_t charge_now_show(struct ab8500_fg *di, char *buf)
+{
+	return sprintf(buf, "%d\n", di->bat_cap.prev_mah);
+}
+
+static ssize_t charge_now_store(struct ab8500_fg *di, const char *buf,
+				 size_t count)
+{
+	unsigned long charge_now;
+	ssize_t ret;
+
+	ret = strict_strtoul(buf, 10, &charge_now);
+
+	dev_dbg(di->dev, "Ret %zd charge_now %lu was %d",
+		ret, charge_now, di->bat_cap.prev_mah);
+
+	if (!ret) {
+		di->bat_cap.user_mah = (int) charge_now;
+		di->flags.user_cap = true;
+		ret = count;
+		queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
+	}
+	return ret;
+}
+
+static struct ab8500_fg_sysfs_entry charge_full_attr =
+	__ATTR(charge_full, 0644, charge_full_show, charge_full_store);
+
+static struct ab8500_fg_sysfs_entry charge_now_attr =
+	__ATTR(charge_now, 0644, charge_now_show, charge_now_store);
+
+static ssize_t
+ab8500_fg_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+	struct ab8500_fg_sysfs_entry *entry;
+	struct ab8500_fg *di;
+
+	entry = container_of(attr, struct ab8500_fg_sysfs_entry, attr);
+	di = container_of(kobj, struct ab8500_fg, fg_kobject);
+
+	if (!entry->show)
+		return -EIO;
+
+	return entry->show(di, buf);
+}
+static ssize_t
+ab8500_fg_store(struct kobject *kobj, struct attribute *attr, const char *buf,
+		size_t count)
+{
+	struct ab8500_fg_sysfs_entry *entry;
+	struct ab8500_fg *di;
+
+	entry = container_of(attr, struct ab8500_fg_sysfs_entry, attr);
+	di = container_of(kobj, struct ab8500_fg, fg_kobject);
+
+	if (!entry->store)
+		return -EIO;
+
+	return entry->store(di, buf, count);
+}
+
+static const struct sysfs_ops ab8500_fg_sysfs_ops = {
+	.show = ab8500_fg_show,
+	.store = ab8500_fg_store,
+};
+
+static struct attribute *ab8500_fg_attrs[] = {
+	&charge_full_attr.attr,
+	&charge_now_attr.attr,
+	NULL,
+};
+
+static struct kobj_type ab8500_fg_ktype = {
+	.sysfs_ops = &ab8500_fg_sysfs_ops,
+	.default_attrs = ab8500_fg_attrs,
+};
+
+/**
+ * ab8500_chargalg_sysfs_exit() - de-init of sysfs entry
+ * @di:                pointer to the struct ab8500_chargalg
+ *
+ * This function removes the entry in sysfs.
+ */
+static void ab8500_fg_sysfs_exit(struct ab8500_fg *di)
+{
+	kobject_del(&di->fg_kobject);
+}
+
+/**
+ * ab8500_chargalg_sysfs_init() - init of sysfs entry
+ * @di:                pointer to the struct ab8500_chargalg
+ *
+ * This function adds an entry in sysfs.
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_fg_sysfs_init(struct ab8500_fg *di)
+{
+	int ret = 0;
+
+	ret = kobject_init_and_add(&di->fg_kobject,
+		&ab8500_fg_ktype,
+		NULL, "battery");
+	if (ret < 0)
+		dev_err(di->dev, "failed to create sysfs entry\n");
+
+	return ret;
+}
+/* Exposure to the sysfs interface <<END>> */
+
+#if defined(CONFIG_PM)
+static int ab8500_fg_resume(struct platform_device *pdev)
+{
+	struct ab8500_fg *di = platform_get_drvdata(pdev);
+
+	/*
+	 * Change state if we're not charging. If we're charging we will wake
+	 * up on the FG IRQ
+	 */
+	if (!di->flags.charging) {
+		ab8500_fg_discharge_state_to(di, AB8500_FG_DISCHARGE_WAKEUP);
+		queue_work(di->fg_wq, &di->fg_work);
+	}
+
+	return 0;
+}
+
+static int ab8500_fg_suspend(struct platform_device *pdev,
+	pm_message_t state)
+{
+	struct ab8500_fg *di = platform_get_drvdata(pdev);
+
+	flush_delayed_work(&di->fg_periodic_work);
+
+	/*
+	 * If the FG is enabled we will disable it before going to suspend
+	 * only if we're not charging
+	 */
+	if (di->flags.fg_enabled && !di->flags.charging)
+		ab8500_fg_coulomb_counter(di, false);
+
+	return 0;
+}
+#else
+#define ab8500_fg_suspend      NULL
+#define ab8500_fg_resume       NULL
+#endif
+
+static int __devexit ab8500_fg_remove(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct ab8500_fg *di = platform_get_drvdata(pdev);
+
+	list_del(&di->node);
+
+	/* Disable coulomb counter */
+	ret = ab8500_fg_coulomb_counter(di, false);
+	if (ret)
+		dev_err(di->dev, "failed to disable coulomb counter\n");
+
+	destroy_workqueue(di->fg_wq);
+	ab8500_fg_sysfs_exit(di);
+
+	flush_scheduled_work();
+	power_supply_unregister(&di->fg_psy);
+	platform_set_drvdata(pdev, NULL);
+	kfree(di);
+	return ret;
+}
+
+/* ab8500 fg driver interrupts and their respective isr */
+static struct ab8500_fg_interrupts ab8500_fg_irq[] = {
+	{"NCONV_ACCU", ab8500_fg_cc_convend_handler},
+	{"BATT_OVV", ab8500_fg_batt_ovv_handler},
+	{"LOW_BAT_F", ab8500_fg_lowbatf_handler},
+	{"CC_INT_CALIB", ab8500_fg_cc_int_calib_handler},
+	{"CCEOC", ab8500_fg_cc_data_end_handler},
+};
+
+static int __devinit ab8500_fg_probe(struct platform_device *pdev)
+{
+	int i, irq;
+	int ret = 0;
+	struct abx500_bm_plat_data *plat_data;
+
+	struct ab8500_fg *di =
+		kzalloc(sizeof(struct ab8500_fg), GFP_KERNEL);
+	if (!di)
+		return -ENOMEM;
+
+	mutex_init(&di->cc_lock);
+
+	/* get parent data */
+	di->dev = &pdev->dev;
+	di->parent = dev_get_drvdata(pdev->dev.parent);
+	di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+
+	/* get fg specific platform data */
+	plat_data = pdev->dev.platform_data;
+	di->pdata = plat_data->fg;
+	if (!di->pdata) {
+		dev_err(di->dev, "no fg platform data supplied\n");
+		ret = -EINVAL;
+		goto free_device_info;
+	}
+
+	/* get battery specific platform data */
+	di->bat = plat_data->battery;
+	if (!di->bat) {
+		dev_err(di->dev, "no battery platform data supplied\n");
+		ret = -EINVAL;
+		goto free_device_info;
+	}
+
+	di->fg_psy.name = "ab8500_fg";
+	di->fg_psy.type = POWER_SUPPLY_TYPE_BATTERY;
+	di->fg_psy.properties = ab8500_fg_props;
+	di->fg_psy.num_properties = ARRAY_SIZE(ab8500_fg_props);
+	di->fg_psy.get_property = ab8500_fg_get_property;
+	di->fg_psy.supplied_to = di->pdata->supplied_to;
+	di->fg_psy.num_supplicants = di->pdata->num_supplicants;
+	di->fg_psy.external_power_changed = ab8500_fg_external_power_changed;
+
+	di->bat_cap.max_mah_design = MILLI_TO_MICRO *
+		di->bat->bat_type[di->bat->batt_id].charge_full_design;
+
+	di->bat_cap.max_mah = di->bat_cap.max_mah_design;
+
+	di->vbat_nom = di->bat->bat_type[di->bat->batt_id].nominal_voltage;
+
+	di->init_capacity = true;
+
+	ab8500_fg_charge_state_to(di, AB8500_FG_CHARGE_INIT);
+	ab8500_fg_discharge_state_to(di, AB8500_FG_DISCHARGE_INIT);
+
+	/* Create a work queue for running the FG algorithm */
+	di->fg_wq = create_singlethread_workqueue("ab8500_fg_wq");
+	if (di->fg_wq == NULL) {
+		dev_err(di->dev, "failed to create work queue\n");
+		goto free_device_info;
+	}
+
+	/* Init work for running the fg algorithm instantly */
+	INIT_WORK(&di->fg_work, ab8500_fg_instant_work);
+
+	/* Init work for getting the battery accumulated current */
+	INIT_WORK(&di->fg_acc_cur_work, ab8500_fg_acc_cur_work);
+
+	/* Init work for reinitialising the fg algorithm */
+	INIT_DELAYED_WORK_DEFERRABLE(&di->fg_reinit_work,
+		ab8500_fg_reinit_work);
+
+	/* Work delayed Queue to run the state machine */
+	INIT_DELAYED_WORK_DEFERRABLE(&di->fg_periodic_work,
+		ab8500_fg_periodic_work);
+
+	/* Work to check low battery condition */
+	INIT_DELAYED_WORK_DEFERRABLE(&di->fg_low_bat_work,
+		ab8500_fg_low_bat_work);
+
+	/* Init work for HW failure check */
+	INIT_DELAYED_WORK_DEFERRABLE(&di->fg_check_hw_failure_work,
+		ab8500_fg_check_hw_failure_work);
+
+	/* Initialize OVV, and other registers */
+	ret = ab8500_fg_init_hw_registers(di);
+	if (ret) {
+		dev_err(di->dev, "failed to initialize registers\n");
+		goto free_inst_curr_wq;
+	}
+
+	/* Consider battery unknown until we're informed otherwise */
+	di->flags.batt_unknown = true;
+	di->flags.batt_id_received = false;
+
+	/* Register FG power supply class */
+	ret = power_supply_register(di->dev, &di->fg_psy);
+	if (ret) {
+		dev_err(di->dev, "failed to register FG psy\n");
+		goto free_inst_curr_wq;
+	}
+
+	di->fg_samples = SEC_TO_SAMPLE(di->bat->fg_params->init_timer);
+	ab8500_fg_coulomb_counter(di, true);
+
+	/* Initialize completion used to notify completion of inst current */
+	init_completion(&di->ab8500_fg_complete);
+
+	/* Register interrupts */
+	for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq); i++) {
+		irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name);
+		ret = request_threaded_irq(irq, NULL, ab8500_fg_irq[i].isr,
+			IRQF_SHARED | IRQF_NO_SUSPEND,
+			ab8500_fg_irq[i].name, di);
+
+		if (ret != 0) {
+			dev_err(di->dev, "failed to request %s IRQ %d: %d\n"
+				, ab8500_fg_irq[i].name, irq, ret);
+			goto free_irq;
+		}
+		dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
+			ab8500_fg_irq[i].name, irq, ret);
+	}
+	di->irq = platform_get_irq_byname(pdev, "CCEOC");
+	disable_irq(di->irq);
+
+	platform_set_drvdata(pdev, di);
+
+	ret = ab8500_fg_sysfs_init(di);
+	if (ret) {
+		dev_err(di->dev, "failed to create sysfs entry\n");
+		goto free_irq;
+	}
+
+	/* Calibrate the fg first time */
+	di->flags.calibrate = true;
+	di->calib_state = AB8500_FG_CALIB_INIT;
+
+	/* Use room temp as default value until we get an update from driver. */
+	di->bat_temp = 210;
+
+	/* Run the FG algorithm */
+	queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
+
+	list_add_tail(&di->node, &ab8500_fg_list);
+
+	return ret;
+
+free_irq:
+	power_supply_unregister(&di->fg_psy);
+
+	/* We also have to free all successfully registered irqs */
+	for (i = i - 1; i >= 0; i--) {
+		irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name);
+		free_irq(irq, di);
+	}
+free_inst_curr_wq:
+	destroy_workqueue(di->fg_wq);
+free_device_info:
+	kfree(di);
+
+	return ret;
+}
+
+static struct platform_driver ab8500_fg_driver = {
+	.probe = ab8500_fg_probe,
+	.remove = __devexit_p(ab8500_fg_remove),
+	.suspend = ab8500_fg_suspend,
+	.resume = ab8500_fg_resume,
+	.driver = {
+		.name = "ab8500-fg",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init ab8500_fg_init(void)
+{
+	return platform_driver_register(&ab8500_fg_driver);
+}
+
+static void __exit ab8500_fg_exit(void)
+{
+	platform_driver_unregister(&ab8500_fg_driver);
+}
+
+subsys_initcall_sync(ab8500_fg_init);
+module_exit(ab8500_fg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Johan Palsson, Karl Komierowski");
+MODULE_ALIAS("platform:ab8500-fg");
+MODULE_DESCRIPTION("AB8500 Fuel Gauge driver");
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
new file mode 100644
index 0000000..804b88c
--- /dev/null
+++ b/drivers/power/abx500_chargalg.c
@@ -0,0 +1,1921 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Charging algorithm driver for abx500 variants
+ *
+ * License Terms: GNU General Public License v2
+ * Authors:
+ *	Johan Palsson <johan.palsson@stericsson.com>
+ *	Karl Komierowski <karl.komierowski@stericsson.com>
+ *	Arun R Murthy <arun.murthy@stericsson.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ux500_chargalg.h>
+#include <linux/mfd/abx500/ab8500-bm.h>
+
+/* Watchdog kick interval */
+#define CHG_WD_INTERVAL			(6 * HZ)
+
+/* End-of-charge criteria counter */
+#define EOC_COND_CNT			10
+
+/* Recharge criteria counter */
+#define RCH_COND_CNT			3
+
+#define to_abx500_chargalg_device_info(x) container_of((x), \
+	struct abx500_chargalg, chargalg_psy);
+
+enum abx500_chargers {
+	NO_CHG,
+	AC_CHG,
+	USB_CHG,
+};
+
+struct abx500_chargalg_charger_info {
+	enum abx500_chargers conn_chg;
+	enum abx500_chargers prev_conn_chg;
+	enum abx500_chargers online_chg;
+	enum abx500_chargers prev_online_chg;
+	enum abx500_chargers charger_type;
+	bool usb_chg_ok;
+	bool ac_chg_ok;
+	int usb_volt;
+	int usb_curr;
+	int ac_volt;
+	int ac_curr;
+	int usb_vset;
+	int usb_iset;
+	int ac_vset;
+	int ac_iset;
+};
+
+struct abx500_chargalg_suspension_status {
+	bool suspended_change;
+	bool ac_suspended;
+	bool usb_suspended;
+};
+
+struct abx500_chargalg_battery_data {
+	int temp;
+	int volt;
+	int avg_curr;
+	int inst_curr;
+	int percent;
+};
+
+enum abx500_chargalg_states {
+	STATE_HANDHELD_INIT,
+	STATE_HANDHELD,
+	STATE_CHG_NOT_OK_INIT,
+	STATE_CHG_NOT_OK,
+	STATE_HW_TEMP_PROTECT_INIT,
+	STATE_HW_TEMP_PROTECT,
+	STATE_NORMAL_INIT,
+	STATE_NORMAL,
+	STATE_WAIT_FOR_RECHARGE_INIT,
+	STATE_WAIT_FOR_RECHARGE,
+	STATE_MAINTENANCE_A_INIT,
+	STATE_MAINTENANCE_A,
+	STATE_MAINTENANCE_B_INIT,
+	STATE_MAINTENANCE_B,
+	STATE_TEMP_UNDEROVER_INIT,
+	STATE_TEMP_UNDEROVER,
+	STATE_TEMP_LOWHIGH_INIT,
+	STATE_TEMP_LOWHIGH,
+	STATE_SUSPENDED_INIT,
+	STATE_SUSPENDED,
+	STATE_OVV_PROTECT_INIT,
+	STATE_OVV_PROTECT,
+	STATE_SAFETY_TIMER_EXPIRED_INIT,
+	STATE_SAFETY_TIMER_EXPIRED,
+	STATE_BATT_REMOVED_INIT,
+	STATE_BATT_REMOVED,
+	STATE_WD_EXPIRED_INIT,
+	STATE_WD_EXPIRED,
+};
+
+static const char *states[] = {
+	"HANDHELD_INIT",
+	"HANDHELD",
+	"CHG_NOT_OK_INIT",
+	"CHG_NOT_OK",
+	"HW_TEMP_PROTECT_INIT",
+	"HW_TEMP_PROTECT",
+	"NORMAL_INIT",
+	"NORMAL",
+	"WAIT_FOR_RECHARGE_INIT",
+	"WAIT_FOR_RECHARGE",
+	"MAINTENANCE_A_INIT",
+	"MAINTENANCE_A",
+	"MAINTENANCE_B_INIT",
+	"MAINTENANCE_B",
+	"TEMP_UNDEROVER_INIT",
+	"TEMP_UNDEROVER",
+	"TEMP_LOWHIGH_INIT",
+	"TEMP_LOWHIGH",
+	"SUSPENDED_INIT",
+	"SUSPENDED",
+	"OVV_PROTECT_INIT",
+	"OVV_PROTECT",
+	"SAFETY_TIMER_EXPIRED_INIT",
+	"SAFETY_TIMER_EXPIRED",
+	"BATT_REMOVED_INIT",
+	"BATT_REMOVED",
+	"WD_EXPIRED_INIT",
+	"WD_EXPIRED",
+};
+
+struct abx500_chargalg_events {
+	bool batt_unknown;
+	bool mainextchnotok;
+	bool batt_ovv;
+	bool batt_rem;
+	bool btemp_underover;
+	bool btemp_lowhigh;
+	bool main_thermal_prot;
+	bool usb_thermal_prot;
+	bool main_ovv;
+	bool vbus_ovv;
+	bool usbchargernotok;
+	bool safety_timer_expired;
+	bool maintenance_timer_expired;
+	bool ac_wd_expired;
+	bool usb_wd_expired;
+	bool ac_cv_active;
+	bool usb_cv_active;
+	bool vbus_collapsed;
+};
+
+/**
+ * struct abx500_charge_curr_maximization - Charger maximization parameters
+ * @original_iset:	the non optimized/maximised charger current
+ * @current_iset:	the charging current used at this moment
+ * @test_delta_i:	the delta between the current we want to charge and the
+			current that is really going into the battery
+ * @condition_cnt:	number of iterations needed before a new charger current
+			is set
+ * @max_current:	maximum charger current
+ * @wait_cnt:		to avoid too fast current step down in case of charger
+ *			voltage collapse, we insert this delay between step
+ *			down
+ * @level:		tells in how many steps the charging current has been
+			increased
+ */
+struct abx500_charge_curr_maximization {
+	int original_iset;
+	int current_iset;
+	int test_delta_i;
+	int condition_cnt;
+	int max_current;
+	int wait_cnt;
+	u8 level;
+};
+
+enum maxim_ret {
+	MAXIM_RET_NOACTION,
+	MAXIM_RET_CHANGE,
+	MAXIM_RET_IBAT_TOO_HIGH,
+};
+
+/**
+ * struct abx500_chargalg - abx500 Charging algorithm device information
+ * @dev:		pointer to the structure device
+ * @charge_status:	battery operating status
+ * @eoc_cnt:		counter used to determine end-of_charge
+ * @rch_cnt:		counter used to determine start of recharge
+ * @maintenance_chg:	indicate if maintenance charge is active
+ * @t_hyst_norm		temperature hysteresis when the temperature has been
+ *			over or under normal limits
+ * @t_hyst_lowhigh	temperature hysteresis when the temperature has been
+ *			over or under the high or low limits
+ * @charge_state:	current state of the charging algorithm
+ * @ccm			charging current maximization parameters
+ * @chg_info:		information about connected charger types
+ * @batt_data:		data of the battery
+ * @susp_status:	current charger suspension status
+ * @pdata:		pointer to the abx500_chargalg platform data
+ * @bat:		pointer to the abx500_bm platform data
+ * @chargalg_psy:	structure that holds the battery properties exposed by
+ *			the charging algorithm
+ * @events:		structure for information about events triggered
+ * @chargalg_wq:		work queue for running the charging algorithm
+ * @chargalg_periodic_work:	work to run the charging algorithm periodically
+ * @chargalg_wd_work:		work to kick the charger watchdog periodically
+ * @chargalg_work:		work to run the charging algorithm instantly
+ * @safety_timer:		charging safety timer
+ * @maintenance_timer:		maintenance charging timer
+ * @chargalg_kobject:		structure of type kobject
+ */
+struct abx500_chargalg {
+	struct device *dev;
+	int charge_status;
+	int eoc_cnt;
+	int rch_cnt;
+	bool maintenance_chg;
+	int t_hyst_norm;
+	int t_hyst_lowhigh;
+	enum abx500_chargalg_states charge_state;
+	struct abx500_charge_curr_maximization ccm;
+	struct abx500_chargalg_charger_info chg_info;
+	struct abx500_chargalg_battery_data batt_data;
+	struct abx500_chargalg_suspension_status susp_status;
+	struct abx500_chargalg_platform_data *pdata;
+	struct abx500_bm_data *bat;
+	struct power_supply chargalg_psy;
+	struct ux500_charger *ac_chg;
+	struct ux500_charger *usb_chg;
+	struct abx500_chargalg_events events;
+	struct workqueue_struct *chargalg_wq;
+	struct delayed_work chargalg_periodic_work;
+	struct delayed_work chargalg_wd_work;
+	struct work_struct chargalg_work;
+	struct timer_list safety_timer;
+	struct timer_list maintenance_timer;
+	struct kobject chargalg_kobject;
+};
+
+/* Main battery properties */
+static enum power_supply_property abx500_chargalg_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+};
+
+/**
+ * abx500_chargalg_safety_timer_expired() - Expiration of the safety timer
+ * @data:	pointer to the abx500_chargalg structure
+ *
+ * This function gets called when the safety timer for the charger
+ * expires
+ */
+static void abx500_chargalg_safety_timer_expired(unsigned long data)
+{
+	struct abx500_chargalg *di = (struct abx500_chargalg *) data;
+	dev_err(di->dev, "Safety timer expired\n");
+	di->events.safety_timer_expired = true;
+
+	/* Trigger execution of the algorithm instantly */
+	queue_work(di->chargalg_wq, &di->chargalg_work);
+}
+
+/**
+ * abx500_chargalg_maintenance_timer_expired() - Expiration of
+ * the maintenance timer
+ * @i:		pointer to the abx500_chargalg structure
+ *
+ * This function gets called when the maintenence timer
+ * expires
+ */
+static void abx500_chargalg_maintenance_timer_expired(unsigned long data)
+{
+
+	struct abx500_chargalg *di = (struct abx500_chargalg *) data;
+	dev_dbg(di->dev, "Maintenance timer expired\n");
+	di->events.maintenance_timer_expired = true;
+
+	/* Trigger execution of the algorithm instantly */
+	queue_work(di->chargalg_wq, &di->chargalg_work);
+}
+
+/**
+ * abx500_chargalg_state_to() - Change charge state
+ * @di:		pointer to the abx500_chargalg structure
+ *
+ * This function gets called when a charge state change should occur
+ */
+static void abx500_chargalg_state_to(struct abx500_chargalg *di,
+	enum abx500_chargalg_states state)
+{
+	dev_dbg(di->dev,
+		"State changed: %s (From state: [%d] %s =to=> [%d] %s )\n",
+		di->charge_state == state ? "NO" : "YES",
+		di->charge_state,
+		states[di->charge_state],
+		state,
+		states[state]);
+
+	di->charge_state = state;
+}
+
+/**
+ * abx500_chargalg_check_charger_connection() - Check charger connection change
+ * @di:		pointer to the abx500_chargalg structure
+ *
+ * This function will check if there is a change in the charger connection
+ * and change charge state accordingly. AC has precedence over USB.
+ */
+static int abx500_chargalg_check_charger_connection(struct abx500_chargalg *di)
+{
+	if (di->chg_info.conn_chg != di->chg_info.prev_conn_chg ||
+		di->susp_status.suspended_change) {
+		/*
+		 * Charger state changed or suspension
+		 * has changed since last update
+		 */
+		if ((di->chg_info.conn_chg & AC_CHG) &&
+			!di->susp_status.ac_suspended) {
+			dev_dbg(di->dev, "Charging source is AC\n");
+			if (di->chg_info.charger_type != AC_CHG) {
+				di->chg_info.charger_type = AC_CHG;
+				abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
+			}
+		} else if ((di->chg_info.conn_chg & USB_CHG) &&
+			!di->susp_status.usb_suspended) {
+			dev_dbg(di->dev, "Charging source is USB\n");
+			di->chg_info.charger_type = USB_CHG;
+			abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
+		} else if (di->chg_info.conn_chg &&
+			(di->susp_status.ac_suspended ||
+			di->susp_status.usb_suspended)) {
+			dev_dbg(di->dev, "Charging is suspended\n");
+			di->chg_info.charger_type = NO_CHG;
+			abx500_chargalg_state_to(di, STATE_SUSPENDED_INIT);
+		} else {
+			dev_dbg(di->dev, "Charging source is OFF\n");
+			di->chg_info.charger_type = NO_CHG;
+			abx500_chargalg_state_to(di, STATE_HANDHELD_INIT);
+		}
+		di->chg_info.prev_conn_chg = di->chg_info.conn_chg;
+		di->susp_status.suspended_change = false;
+	}
+	return di->chg_info.conn_chg;
+}
+
+/**
+ * abx500_chargalg_start_safety_timer() - Start charging safety timer
+ * @di:		pointer to the abx500_chargalg structure
+ *
+ * The safety timer is used to avoid overcharging of old or bad batteries.
+ * There are different timers for AC and USB
+ */
+static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di)
+{
+	unsigned long timer_expiration = 0;
+
+	switch (di->chg_info.charger_type) {
+	case AC_CHG:
+		timer_expiration =
+		round_jiffies(jiffies +
+			(di->bat->main_safety_tmr_h * 3600 * HZ));
+		break;
+
+	case USB_CHG:
+		timer_expiration =
+		round_jiffies(jiffies +
+			(di->bat->usb_safety_tmr_h * 3600 * HZ));
+		break;
+
+	default:
+		dev_err(di->dev, "Unknown charger to charge from\n");
+		break;
+	}
+
+	di->events.safety_timer_expired = false;
+	di->safety_timer.expires = timer_expiration;
+	if (!timer_pending(&di->safety_timer))
+		add_timer(&di->safety_timer);
+	else
+		mod_timer(&di->safety_timer, timer_expiration);
+}
+
+/**
+ * abx500_chargalg_stop_safety_timer() - Stop charging safety timer
+ * @di:		pointer to the abx500_chargalg structure
+ *
+ * The safety timer is stopped whenever the NORMAL state is exited
+ */
+static void abx500_chargalg_stop_safety_timer(struct abx500_chargalg *di)
+{
+	di->events.safety_timer_expired = false;
+	del_timer(&di->safety_timer);
+}
+
+/**
+ * abx500_chargalg_start_maintenance_timer() - Start charging maintenance timer
+ * @di:		pointer to the abx500_chargalg structure
+ * @duration:	duration of ther maintenance timer in hours
+ *
+ * The maintenance timer is used to maintain the charge in the battery once
+ * the battery is considered full. These timers are chosen to match the
+ * discharge curve of the battery
+ */
+static void abx500_chargalg_start_maintenance_timer(struct abx500_chargalg *di,
+	int duration)
+{
+	unsigned long timer_expiration;
+
+	/* Convert from hours to jiffies */
+	timer_expiration = round_jiffies(jiffies + (duration * 3600 * HZ));
+
+	di->events.maintenance_timer_expired = false;
+	di->maintenance_timer.expires = timer_expiration;
+	if (!timer_pending(&di->maintenance_timer))
+		add_timer(&di->maintenance_timer);
+	else
+		mod_timer(&di->maintenance_timer, timer_expiration);
+}
+
+/**
+ * abx500_chargalg_stop_maintenance_timer() - Stop maintenance timer
+ * @di:		pointer to the abx500_chargalg structure
+ *
+ * The maintenance timer is stopped whenever maintenance ends or when another
+ * state is entered
+ */
+static void abx500_chargalg_stop_maintenance_timer(struct abx500_chargalg *di)
+{
+	di->events.maintenance_timer_expired = false;
+	del_timer(&di->maintenance_timer);
+}
+
+/**
+ * abx500_chargalg_kick_watchdog() - Kick charger watchdog
+ * @di:		pointer to the abx500_chargalg structure
+ *
+ * The charger watchdog have to be kicked periodically whenever the charger is
+ * on, else the ABB will reset the system
+ */
+static int abx500_chargalg_kick_watchdog(struct abx500_chargalg *di)
+{
+	/* Check if charger exists and kick watchdog if charging */
+	if (di->ac_chg && di->ac_chg->ops.kick_wd &&
+			di->chg_info.online_chg & AC_CHG)
+		return di->ac_chg->ops.kick_wd(di->ac_chg);
+	else if (di->usb_chg && di->usb_chg->ops.kick_wd &&
+			di->chg_info.online_chg & USB_CHG)
+		return di->usb_chg->ops.kick_wd(di->usb_chg);
+
+	return -ENXIO;
+}
+
+/**
+ * abx500_chargalg_ac_en() - Turn on/off the AC charger
+ * @di:		pointer to the abx500_chargalg structure
+ * @enable:	charger on/off
+ * @vset:	requested charger output voltage
+ * @iset:	requested charger output current
+ *
+ * The AC charger will be turned on/off with the requested charge voltage and
+ * current
+ */
+static int abx500_chargalg_ac_en(struct abx500_chargalg *di, int enable,
+	int vset, int iset)
+{
+	if (!di->ac_chg || !di->ac_chg->ops.enable)
+		return -ENXIO;
+
+	/* Select maximum of what both the charger and the battery supports */
+	if (di->ac_chg->max_out_volt)
+		vset = min(vset, di->ac_chg->max_out_volt);
+	if (di->ac_chg->max_out_curr)
+		iset = min(iset, di->ac_chg->max_out_curr);
+
+	di->chg_info.ac_iset = iset;
+	di->chg_info.ac_vset = vset;
+
+	return di->ac_chg->ops.enable(di->ac_chg, enable, vset, iset);
+}
+
+/**
+ * abx500_chargalg_usb_en() - Turn on/off the USB charger
+ * @di:		pointer to the abx500_chargalg structure
+ * @enable:	charger on/off
+ * @vset:	requested charger output voltage
+ * @iset:	requested charger output current
+ *
+ * The USB charger will be turned on/off with the requested charge voltage and
+ * current
+ */
+static int abx500_chargalg_usb_en(struct abx500_chargalg *di, int enable,
+	int vset, int iset)
+{
+	if (!di->usb_chg || !di->usb_chg->ops.enable)
+		return -ENXIO;
+
+	/* Select maximum of what both the charger and the battery supports */
+	if (di->usb_chg->max_out_volt)
+		vset = min(vset, di->usb_chg->max_out_volt);
+	if (di->usb_chg->max_out_curr)
+		iset = min(iset, di->usb_chg->max_out_curr);
+
+	di->chg_info.usb_iset = iset;
+	di->chg_info.usb_vset = vset;
+
+	return di->usb_chg->ops.enable(di->usb_chg, enable, vset, iset);
+}
+
+/**
+ * abx500_chargalg_update_chg_curr() - Update charger current
+ * @di:		pointer to the abx500_chargalg structure
+ * @iset:	requested charger output current
+ *
+ * The charger output current will be updated for the charger
+ * that is currently in use
+ */
+static int abx500_chargalg_update_chg_curr(struct abx500_chargalg *di,
+		int iset)
+{
+	/* Check if charger exists and update current if charging */
+	if (di->ac_chg && di->ac_chg->ops.update_curr &&
+			di->chg_info.charger_type & AC_CHG) {
+		/*
+		 * Select maximum of what both the charger
+		 * and the battery supports
+		 */
+		if (di->ac_chg->max_out_curr)
+			iset = min(iset, di->ac_chg->max_out_curr);
+
+		di->chg_info.ac_iset = iset;
+
+		return di->ac_chg->ops.update_curr(di->ac_chg, iset);
+	} else if (di->usb_chg && di->usb_chg->ops.update_curr &&
+			di->chg_info.charger_type & USB_CHG) {
+		/*
+		 * Select maximum of what both the charger
+		 * and the battery supports
+		 */
+		if (di->usb_chg->max_out_curr)
+			iset = min(iset, di->usb_chg->max_out_curr);
+
+		di->chg_info.usb_iset = iset;
+
+		return di->usb_chg->ops.update_curr(di->usb_chg, iset);
+	}
+
+	return -ENXIO;
+}
+
+/**
+ * abx500_chargalg_stop_charging() - Stop charging
+ * @di:		pointer to the abx500_chargalg structure
+ *
+ * This function is called from any state where charging should be stopped.
+ * All charging is disabled and all status parameters and timers are changed
+ * accordingly
+ */
+static void abx500_chargalg_stop_charging(struct abx500_chargalg *di)
+{
+	abx500_chargalg_ac_en(di, false, 0, 0);
+	abx500_chargalg_usb_en(di, false, 0, 0);
+	abx500_chargalg_stop_safety_timer(di);
+	abx500_chargalg_stop_maintenance_timer(di);
+	di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+	di->maintenance_chg = false;
+	cancel_delayed_work(&di->chargalg_wd_work);
+	power_supply_changed(&di->chargalg_psy);
+}
+
+/**
+ * abx500_chargalg_hold_charging() - Pauses charging
+ * @di:		pointer to the abx500_chargalg structure
+ *
+ * This function is called in the case where maintenance charging has been
+ * disabled and instead a battery voltage mode is entered to check when the
+ * battery voltage has reached a certain recharge voltage
+ */
+static void abx500_chargalg_hold_charging(struct abx500_chargalg *di)
+{
+	abx500_chargalg_ac_en(di, false, 0, 0);
+	abx500_chargalg_usb_en(di, false, 0, 0);
+	abx500_chargalg_stop_safety_timer(di);
+	abx500_chargalg_stop_maintenance_timer(di);
+	di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
+	di->maintenance_chg = false;
+	cancel_delayed_work(&di->chargalg_wd_work);
+	power_supply_changed(&di->chargalg_psy);
+}
+
+/**
+ * abx500_chargalg_start_charging() - Start the charger
+ * @di:		pointer to the abx500_chargalg structure
+ * @vset:	requested charger output voltage
+ * @iset:	requested charger output current
+ *
+ * A charger will be enabled depending on the requested charger type that was
+ * detected previously.
+ */
+static void abx500_chargalg_start_charging(struct abx500_chargalg *di,
+	int vset, int iset)
+{
+	switch (di->chg_info.charger_type) {
+	case AC_CHG:
+		dev_dbg(di->dev,
+			"AC parameters: Vset %d, Ich %d\n", vset, iset);
+		abx500_chargalg_usb_en(di, false, 0, 0);
+		abx500_chargalg_ac_en(di, true, vset, iset);
+		break;
+
+	case USB_CHG:
+		dev_dbg(di->dev,
+			"USB parameters: Vset %d, Ich %d\n", vset, iset);
+		abx500_chargalg_ac_en(di, false, 0, 0);
+		abx500_chargalg_usb_en(di, true, vset, iset);
+		break;
+
+	default:
+		dev_err(di->dev, "Unknown charger to charge from\n");
+		break;
+	}
+}
+
+/**
+ * abx500_chargalg_check_temp() - Check battery temperature ranges
+ * @di:		pointer to the abx500_chargalg structure
+ *
+ * The battery temperature is checked against the predefined limits and the
+ * charge state is changed accordingly
+ */
+static void abx500_chargalg_check_temp(struct abx500_chargalg *di)
+{
+	if (di->batt_data.temp > (di->bat->temp_low + di->t_hyst_norm) &&
+		di->batt_data.temp < (di->bat->temp_high - di->t_hyst_norm)) {
+		/* Temp OK! */
+		di->events.btemp_underover = false;
+		di->events.btemp_lowhigh = false;
+		di->t_hyst_norm = 0;
+		di->t_hyst_lowhigh = 0;
+	} else {
+		if (((di->batt_data.temp >= di->bat->temp_high) &&
+			(di->batt_data.temp <
+				(di->bat->temp_over - di->t_hyst_lowhigh))) ||
+			((di->batt_data.temp >
+				(di->bat->temp_under + di->t_hyst_lowhigh)) &&
+			(di->batt_data.temp <= di->bat->temp_low))) {
+			/* TEMP minor!!!!! */
+			di->events.btemp_underover = false;
+			di->events.btemp_lowhigh = true;
+			di->t_hyst_norm = di->bat->temp_hysteresis;
+			di->t_hyst_lowhigh = 0;
+		} else if (di->batt_data.temp <= di->bat->temp_under ||
+			di->batt_data.temp >= di->bat->temp_over) {
+			/* TEMP major!!!!! */
+			di->events.btemp_underover = true;
+			di->events.btemp_lowhigh = false;
+			di->t_hyst_norm = 0;
+			di->t_hyst_lowhigh = di->bat->temp_hysteresis;
+		} else {
+		/* Within hysteresis */
+		dev_dbg(di->dev, "Within hysteresis limit temp: %d "
+				"hyst_lowhigh %d, hyst normal %d\n",
+				di->batt_data.temp, di->t_hyst_lowhigh,
+				di->t_hyst_norm);
+		}
+	}
+}
+
+/**
+ * abx500_chargalg_check_charger_voltage() - Check charger voltage
+ * @di:		pointer to the abx500_chargalg structure
+ *
+ * Charger voltage is checked against maximum limit
+ */
+static void abx500_chargalg_check_charger_voltage(struct abx500_chargalg *di)
+{
+	if (di->chg_info.usb_volt > di->bat->chg_params->usb_volt_max)
+		di->chg_info.usb_chg_ok = false;
+	else
+		di->chg_info.usb_chg_ok = true;
+
+	if (di->chg_info.ac_volt > di->bat->chg_params->ac_volt_max)
+		di->chg_info.ac_chg_ok = false;
+	else
+		di->chg_info.ac_chg_ok = true;
+
+}
+
+/**
+ * abx500_chargalg_end_of_charge() - Check if end-of-charge criteria is fulfilled
+ * @di:		pointer to the abx500_chargalg structure
+ *
+ * End-of-charge criteria is fulfilled when the battery voltage is above a
+ * certain limit and the battery current is below a certain limit for a
+ * predefined number of consecutive seconds. If true, the battery is full
+ */
+static void abx500_chargalg_end_of_charge(struct abx500_chargalg *di)
+{
+	if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING &&
+		di->charge_state == STATE_NORMAL &&
+		!di->maintenance_chg && (di->batt_data.volt >=
+		di->bat->bat_type[di->bat->batt_id].termination_vol ||
+		di->events.usb_cv_active || di->events.ac_cv_active) &&
+		di->batt_data.avg_curr <
+		di->bat->bat_type[di->bat->batt_id].termination_curr &&
+		di->batt_data.avg_curr > 0) {
+		if (++di->eoc_cnt >= EOC_COND_CNT) {
+			di->eoc_cnt = 0;
+			di->charge_status = POWER_SUPPLY_STATUS_FULL;
+			di->maintenance_chg = true;
+			dev_dbg(di->dev, "EOC reached!\n");
+			power_supply_changed(&di->chargalg_psy);
+		} else {
+			dev_dbg(di->dev,
+				" EOC limit reached for the %d"
+				" time, out of %d before EOC\n",
+				di->eoc_cnt,
+				EOC_COND_CNT);
+		}
+	} else {
+		di->eoc_cnt = 0;
+	}
+}
+
+static void init_maxim_chg_curr(struct abx500_chargalg *di)
+{
+	di->ccm.original_iset =
+		di->bat->bat_type[di->bat->batt_id].normal_cur_lvl;
+	di->ccm.current_iset =
+		di->bat->bat_type[di->bat->batt_id].normal_cur_lvl;
+	di->ccm.test_delta_i = di->bat->maxi->charger_curr_step;
+	di->ccm.max_current = di->bat->maxi->chg_curr;
+	di->ccm.condition_cnt = di->bat->maxi->wait_cycles;
+	di->ccm.level = 0;
+}
+
+/**
+ * abx500_chargalg_chg_curr_maxim - increases the charger current to
+ *			compensate for the system load
+ * @di		pointer to the abx500_chargalg structure
+ *
+ * This maximization function is used to raise the charger current to get the
+ * battery current as close to the optimal value as possible. The battery
+ * current during charging is affected by the system load
+ */
+static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di)
+{
+	int delta_i;
+
+	if (!di->bat->maxi->ena_maxi)
+		return MAXIM_RET_NOACTION;
+
+	delta_i = di->ccm.original_iset - di->batt_data.inst_curr;
+
+	if (di->events.vbus_collapsed) {
+		dev_dbg(di->dev, "Charger voltage has collapsed %d\n",
+				di->ccm.wait_cnt);
+		if (di->ccm.wait_cnt == 0) {
+			dev_dbg(di->dev, "lowering current\n");
+			di->ccm.wait_cnt++;
+			di->ccm.condition_cnt = di->bat->maxi->wait_cycles;
+			di->ccm.max_current =
+				di->ccm.current_iset - di->ccm.test_delta_i;
+			di->ccm.current_iset = di->ccm.max_current;
+			di->ccm.level--;
+			return MAXIM_RET_CHANGE;
+		} else {
+			dev_dbg(di->dev, "waiting\n");
+			/* Let's go in here twice before lowering curr again */
+			di->ccm.wait_cnt = (di->ccm.wait_cnt + 1) % 3;
+			return MAXIM_RET_NOACTION;
+		}
+	}
+
+	di->ccm.wait_cnt = 0;
+
+	if ((di->batt_data.inst_curr > di->ccm.original_iset)) {
+		dev_dbg(di->dev, " Maximization Ibat (%dmA) too high"
+			" (limit %dmA) (current iset: %dmA)!\n",
+			di->batt_data.inst_curr, di->ccm.original_iset,
+			di->ccm.current_iset);
+
+		if (di->ccm.current_iset == di->ccm.original_iset)
+			return MAXIM_RET_NOACTION;
+
+		di->ccm.condition_cnt = di->bat->maxi->wait_cycles;
+		di->ccm.current_iset = di->ccm.original_iset;
+		di->ccm.level = 0;
+
+		return MAXIM_RET_IBAT_TOO_HIGH;
+	}
+
+	if (delta_i > di->ccm.test_delta_i &&
+		(di->ccm.current_iset + di->ccm.test_delta_i) <
+		di->ccm.max_current) {
+		if (di->ccm.condition_cnt-- == 0) {
+			/* Increse the iset with cco.test_delta_i */
+			di->ccm.condition_cnt = di->bat->maxi->wait_cycles;
+			di->ccm.current_iset += di->ccm.test_delta_i;
+			di->ccm.level++;
+			dev_dbg(di->dev, " Maximization needed, increase"
+				" with %d mA to %dmA (Optimal ibat: %d)"
+				" Level %d\n",
+				di->ccm.test_delta_i,
+				di->ccm.current_iset,
+				di->ccm.original_iset,
+				di->ccm.level);
+			return MAXIM_RET_CHANGE;
+		} else {
+			return MAXIM_RET_NOACTION;
+		}
+	}  else {
+		di->ccm.condition_cnt = di->bat->maxi->wait_cycles;
+		return MAXIM_RET_NOACTION;
+	}
+}
+
+static void handle_maxim_chg_curr(struct abx500_chargalg *di)
+{
+	enum maxim_ret ret;
+	int result;
+
+	ret = abx500_chargalg_chg_curr_maxim(di);
+	switch (ret) {
+	case MAXIM_RET_CHANGE:
+		result = abx500_chargalg_update_chg_curr(di,
+			di->ccm.current_iset);
+		if (result)
+			dev_err(di->dev, "failed to set chg curr\n");
+		break;
+	case MAXIM_RET_IBAT_TOO_HIGH:
+		result = abx500_chargalg_update_chg_curr(di,
+			di->bat->bat_type[di->bat->batt_id].normal_cur_lvl);
+		if (result)
+			dev_err(di->dev, "failed to set chg curr\n");
+		break;
+
+	case MAXIM_RET_NOACTION:
+	default:
+		/* Do nothing..*/
+		break;
+	}
+}
+
+static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data)
+{
+	struct power_supply *psy;
+	struct power_supply *ext;
+	struct abx500_chargalg *di;
+	union power_supply_propval ret;
+	int i, j;
+	bool psy_found = false;
+
+	psy = (struct power_supply *)data;
+	ext = dev_get_drvdata(dev);
+	di = to_abx500_chargalg_device_info(psy);
+	/* For all psy where the driver name appears in any supplied_to */
+	for (i = 0; i < ext->num_supplicants; i++) {
+		if (!strcmp(ext->supplied_to[i], psy->name))
+			psy_found = true;
+	}
+	if (!psy_found)
+		return 0;
+
+	/* Go through all properties for the psy */
+	for (j = 0; j < ext->num_properties; j++) {
+		enum power_supply_property prop;
+		prop = ext->properties[j];
+
+		/* Initialize chargers if not already done */
+		if (!di->ac_chg &&
+			ext->type == POWER_SUPPLY_TYPE_MAINS)
+			di->ac_chg = psy_to_ux500_charger(ext);
+		else if (!di->usb_chg &&
+			ext->type == POWER_SUPPLY_TYPE_USB)
+			di->usb_chg = psy_to_ux500_charger(ext);
+
+		if (ext->get_property(ext, prop, &ret))
+			continue;
+		switch (prop) {
+		case POWER_SUPPLY_PROP_PRESENT:
+			switch (ext->type) {
+			case POWER_SUPPLY_TYPE_BATTERY:
+				/* Battery present */
+				if (ret.intval)
+					di->events.batt_rem = false;
+				/* Battery removed */
+				else
+					di->events.batt_rem = true;
+				break;
+			case POWER_SUPPLY_TYPE_MAINS:
+				/* AC disconnected */
+				if (!ret.intval &&
+					(di->chg_info.conn_chg & AC_CHG)) {
+					di->chg_info.prev_conn_chg =
+						di->chg_info.conn_chg;
+					di->chg_info.conn_chg &= ~AC_CHG;
+				}
+				/* AC connected */
+				else if (ret.intval &&
+					!(di->chg_info.conn_chg & AC_CHG)) {
+					di->chg_info.prev_conn_chg =
+						di->chg_info.conn_chg;
+					di->chg_info.conn_chg |= AC_CHG;
+				}
+				break;
+			case POWER_SUPPLY_TYPE_USB:
+				/* USB disconnected */
+				if (!ret.intval &&
+					(di->chg_info.conn_chg & USB_CHG)) {
+					di->chg_info.prev_conn_chg =
+						di->chg_info.conn_chg;
+					di->chg_info.conn_chg &= ~USB_CHG;
+				}
+				/* USB connected */
+				else if (ret.intval &&
+					!(di->chg_info.conn_chg & USB_CHG)) {
+					di->chg_info.prev_conn_chg =
+						di->chg_info.conn_chg;
+					di->chg_info.conn_chg |= USB_CHG;
+				}
+				break;
+			default:
+				break;
+			}
+			break;
+
+		case POWER_SUPPLY_PROP_ONLINE:
+			switch (ext->type) {
+			case POWER_SUPPLY_TYPE_BATTERY:
+				break;
+			case POWER_SUPPLY_TYPE_MAINS:
+				/* AC offline */
+				if (!ret.intval &&
+					(di->chg_info.online_chg & AC_CHG)) {
+					di->chg_info.prev_online_chg =
+						di->chg_info.online_chg;
+					di->chg_info.online_chg &= ~AC_CHG;
+				}
+				/* AC online */
+				else if (ret.intval &&
+					!(di->chg_info.online_chg & AC_CHG)) {
+					di->chg_info.prev_online_chg =
+						di->chg_info.online_chg;
+					di->chg_info.online_chg |= AC_CHG;
+					queue_delayed_work(di->chargalg_wq,
+						&di->chargalg_wd_work, 0);
+				}
+				break;
+			case POWER_SUPPLY_TYPE_USB:
+				/* USB offline */
+				if (!ret.intval &&
+					(di->chg_info.online_chg & USB_CHG)) {
+					di->chg_info.prev_online_chg =
+						di->chg_info.online_chg;
+					di->chg_info.online_chg &= ~USB_CHG;
+				}
+				/* USB online */
+				else if (ret.intval &&
+					!(di->chg_info.online_chg & USB_CHG)) {
+					di->chg_info.prev_online_chg =
+						di->chg_info.online_chg;
+					di->chg_info.online_chg |= USB_CHG;
+					queue_delayed_work(di->chargalg_wq,
+						&di->chargalg_wd_work, 0);
+				}
+				break;
+			default:
+				break;
+			}
+			break;
+
+		case POWER_SUPPLY_PROP_HEALTH:
+			switch (ext->type) {
+			case POWER_SUPPLY_TYPE_BATTERY:
+				break;
+			case POWER_SUPPLY_TYPE_MAINS:
+				switch (ret.intval) {
+				case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE:
+					di->events.mainextchnotok = true;
+					di->events.main_thermal_prot = false;
+					di->events.main_ovv = false;
+					di->events.ac_wd_expired = false;
+					break;
+				case POWER_SUPPLY_HEALTH_DEAD:
+					di->events.ac_wd_expired = true;
+					di->events.mainextchnotok = false;
+					di->events.main_ovv = false;
+					di->events.main_thermal_prot = false;
+					break;
+				case POWER_SUPPLY_HEALTH_COLD:
+				case POWER_SUPPLY_HEALTH_OVERHEAT:
+					di->events.main_thermal_prot = true;
+					di->events.mainextchnotok = false;
+					di->events.main_ovv = false;
+					di->events.ac_wd_expired = false;
+					break;
+				case POWER_SUPPLY_HEALTH_OVERVOLTAGE:
+					di->events.main_ovv = true;
+					di->events.mainextchnotok = false;
+					di->events.main_thermal_prot = false;
+					di->events.ac_wd_expired = false;
+					break;
+				case POWER_SUPPLY_HEALTH_GOOD:
+					di->events.main_thermal_prot = false;
+					di->events.mainextchnotok = false;
+					di->events.main_ovv = false;
+					di->events.ac_wd_expired = false;
+					break;
+				default:
+					break;
+				}
+				break;
+
+			case POWER_SUPPLY_TYPE_USB:
+				switch (ret.intval) {
+				case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE:
+					di->events.usbchargernotok = true;
+					di->events.usb_thermal_prot = false;
+					di->events.vbus_ovv = false;
+					di->events.usb_wd_expired = false;
+					break;
+				case POWER_SUPPLY_HEALTH_DEAD:
+					di->events.usb_wd_expired = true;
+					di->events.usbchargernotok = false;
+					di->events.usb_thermal_prot = false;
+					di->events.vbus_ovv = false;
+					break;
+				case POWER_SUPPLY_HEALTH_COLD:
+				case POWER_SUPPLY_HEALTH_OVERHEAT:
+					di->events.usb_thermal_prot = true;
+					di->events.usbchargernotok = false;
+					di->events.vbus_ovv = false;
+					di->events.usb_wd_expired = false;
+					break;
+				case POWER_SUPPLY_HEALTH_OVERVOLTAGE:
+					di->events.vbus_ovv = true;
+					di->events.usbchargernotok = false;
+					di->events.usb_thermal_prot = false;
+					di->events.usb_wd_expired = false;
+					break;
+				case POWER_SUPPLY_HEALTH_GOOD:
+					di->events.usbchargernotok = false;
+					di->events.usb_thermal_prot = false;
+					di->events.vbus_ovv = false;
+					di->events.usb_wd_expired = false;
+					break;
+				default:
+					break;
+				}
+			default:
+				break;
+			}
+			break;
+
+		case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+			switch (ext->type) {
+			case POWER_SUPPLY_TYPE_BATTERY:
+				di->batt_data.volt = ret.intval / 1000;
+				break;
+			case POWER_SUPPLY_TYPE_MAINS:
+				di->chg_info.ac_volt = ret.intval / 1000;
+				break;
+			case POWER_SUPPLY_TYPE_USB:
+				di->chg_info.usb_volt = ret.intval / 1000;
+				break;
+			default:
+				break;
+			}
+			break;
+
+		case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+			switch (ext->type) {
+			case POWER_SUPPLY_TYPE_MAINS:
+				/* AVG is used to indicate when we are
+				 * in CV mode */
+				if (ret.intval)
+					di->events.ac_cv_active = true;
+				else
+					di->events.ac_cv_active = false;
+
+				break;
+			case POWER_SUPPLY_TYPE_USB:
+				/* AVG is used to indicate when we are
+				 * in CV mode */
+				if (ret.intval)
+					di->events.usb_cv_active = true;
+				else
+					di->events.usb_cv_active = false;
+
+				break;
+			default:
+				break;
+			}
+			break;
+
+		case POWER_SUPPLY_PROP_TECHNOLOGY:
+			switch (ext->type) {
+			case POWER_SUPPLY_TYPE_BATTERY:
+				if (ret.intval)
+					di->events.batt_unknown = false;
+				else
+					di->events.batt_unknown = true;
+
+				break;
+			default:
+				break;
+			}
+			break;
+
+		case POWER_SUPPLY_PROP_TEMP:
+			di->batt_data.temp = ret.intval / 10;
+			break;
+
+		case POWER_SUPPLY_PROP_CURRENT_NOW:
+			switch (ext->type) {
+			case POWER_SUPPLY_TYPE_MAINS:
+					di->chg_info.ac_curr =
+						ret.intval / 1000;
+					break;
+			case POWER_SUPPLY_TYPE_USB:
+					di->chg_info.usb_curr =
+						ret.intval / 1000;
+				break;
+			case POWER_SUPPLY_TYPE_BATTERY:
+				di->batt_data.inst_curr = ret.intval / 1000;
+				break;
+			default:
+				break;
+			}
+			break;
+
+		case POWER_SUPPLY_PROP_CURRENT_AVG:
+			switch (ext->type) {
+			case POWER_SUPPLY_TYPE_BATTERY:
+				di->batt_data.avg_curr = ret.intval / 1000;
+				break;
+			case POWER_SUPPLY_TYPE_USB:
+				if (ret.intval)
+					di->events.vbus_collapsed = true;
+				else
+					di->events.vbus_collapsed = false;
+				break;
+			default:
+				break;
+			}
+			break;
+		case POWER_SUPPLY_PROP_CAPACITY:
+			di->batt_data.percent = ret.intval;
+			break;
+		default:
+			break;
+		}
+	}
+	return 0;
+}
+
+/**
+ * abx500_chargalg_external_power_changed() - callback for power supply changes
+ * @psy:       pointer to the structure power_supply
+ *
+ * This function is the entry point of the pointer external_power_changed
+ * of the structure power_supply.
+ * This function gets executed when there is a change in any external power
+ * supply that this driver needs to be notified of.
+ */
+static void abx500_chargalg_external_power_changed(struct power_supply *psy)
+{
+	struct abx500_chargalg *di = to_abx500_chargalg_device_info(psy);
+
+	/*
+	 * Trigger execution of the algorithm instantly and read
+	 * all power_supply properties there instead
+	 */
+	queue_work(di->chargalg_wq, &di->chargalg_work);
+}
+
+/**
+ * abx500_chargalg_algorithm() - Main function for the algorithm
+ * @di:		pointer to the abx500_chargalg structure
+ *
+ * This is the main control function for the charging algorithm.
+ * It is called periodically or when something happens that will
+ * trigger a state change
+ */
+static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
+{
+	int charger_status;
+
+	/* Collect data from all power_supply class devices */
+	class_for_each_device(power_supply_class, NULL,
+		&di->chargalg_psy, abx500_chargalg_get_ext_psy_data);
+
+	abx500_chargalg_end_of_charge(di);
+	abx500_chargalg_check_temp(di);
+	abx500_chargalg_check_charger_voltage(di);
+
+	charger_status = abx500_chargalg_check_charger_connection(di);
+	/*
+	 * First check if we have a charger connected.
+	 * Also we don't allow charging of unknown batteries if configured
+	 * this way
+	 */
+	if (!charger_status ||
+		(di->events.batt_unknown && !di->bat->chg_unknown_bat)) {
+		if (di->charge_state != STATE_HANDHELD) {
+			di->events.safety_timer_expired = false;
+			abx500_chargalg_state_to(di, STATE_HANDHELD_INIT);
+		}
+	}
+
+	/* If suspended, we should not continue checking the flags */
+	else if (di->charge_state == STATE_SUSPENDED_INIT ||
+		di->charge_state == STATE_SUSPENDED) {
+		/* We don't do anything here, just don,t continue */
+	}
+
+	/* Safety timer expiration */
+	else if (di->events.safety_timer_expired) {
+		if (di->charge_state != STATE_SAFETY_TIMER_EXPIRED)
+			abx500_chargalg_state_to(di,
+				STATE_SAFETY_TIMER_EXPIRED_INIT);
+	}
+	/*
+	 * Check if any interrupts has occured
+	 * that will prevent us from charging
+	 */
+
+	/* Battery removed */
+	else if (di->events.batt_rem) {
+		if (di->charge_state != STATE_BATT_REMOVED)
+			abx500_chargalg_state_to(di, STATE_BATT_REMOVED_INIT);
+	}
+	/* Main or USB charger not ok. */
+	else if (di->events.mainextchnotok || di->events.usbchargernotok) {
+		/*
+		 * If vbus_collapsed is set, we have to lower the charger
+		 * current, which is done in the normal state below
+		 */
+		if (di->charge_state != STATE_CHG_NOT_OK &&
+				!di->events.vbus_collapsed)
+			abx500_chargalg_state_to(di, STATE_CHG_NOT_OK_INIT);
+	}
+	/* VBUS, Main or VBAT OVV. */
+	else if (di->events.vbus_ovv ||
+			di->events.main_ovv ||
+			di->events.batt_ovv ||
+			!di->chg_info.usb_chg_ok ||
+			!di->chg_info.ac_chg_ok) {
+		if (di->charge_state != STATE_OVV_PROTECT)
+			abx500_chargalg_state_to(di, STATE_OVV_PROTECT_INIT);
+	}
+	/* USB Thermal, stop charging */
+	else if (di->events.main_thermal_prot ||
+		di->events.usb_thermal_prot) {
+		if (di->charge_state != STATE_HW_TEMP_PROTECT)
+			abx500_chargalg_state_to(di,
+				STATE_HW_TEMP_PROTECT_INIT);
+	}
+	/* Battery temp over/under */
+	else if (di->events.btemp_underover) {
+		if (di->charge_state != STATE_TEMP_UNDEROVER)
+			abx500_chargalg_state_to(di,
+				STATE_TEMP_UNDEROVER_INIT);
+	}
+	/* Watchdog expired */
+	else if (di->events.ac_wd_expired ||
+		di->events.usb_wd_expired) {
+		if (di->charge_state != STATE_WD_EXPIRED)
+			abx500_chargalg_state_to(di, STATE_WD_EXPIRED_INIT);
+	}
+	/* Battery temp high/low */
+	else if (di->events.btemp_lowhigh) {
+		if (di->charge_state != STATE_TEMP_LOWHIGH)
+			abx500_chargalg_state_to(di, STATE_TEMP_LOWHIGH_INIT);
+	}
+
+	dev_dbg(di->dev,
+		"[CHARGALG] Vb %d Ib_avg %d Ib_inst %d Tb %d Cap %d Maint %d "
+		"State %s Active_chg %d Chg_status %d AC %d USB %d "
+		"AC_online %d USB_online %d AC_CV %d USB_CV %d AC_I %d "
+		"USB_I %d AC_Vset %d AC_Iset %d USB_Vset %d USB_Iset %d\n",
+		di->batt_data.volt,
+		di->batt_data.avg_curr,
+		di->batt_data.inst_curr,
+		di->batt_data.temp,
+		di->batt_data.percent,
+		di->maintenance_chg,
+		states[di->charge_state],
+		di->chg_info.charger_type,
+		di->charge_status,
+		di->chg_info.conn_chg & AC_CHG,
+		di->chg_info.conn_chg & USB_CHG,
+		di->chg_info.online_chg & AC_CHG,
+		di->chg_info.online_chg & USB_CHG,
+		di->events.ac_cv_active,
+		di->events.usb_cv_active,
+		di->chg_info.ac_curr,
+		di->chg_info.usb_curr,
+		di->chg_info.ac_vset,
+		di->chg_info.ac_iset,
+		di->chg_info.usb_vset,
+		di->chg_info.usb_iset);
+
+	switch (di->charge_state) {
+	case STATE_HANDHELD_INIT:
+		abx500_chargalg_stop_charging(di);
+		di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
+		abx500_chargalg_state_to(di, STATE_HANDHELD);
+		/* Intentional fallthrough */
+
+	case STATE_HANDHELD:
+		break;
+
+	case STATE_SUSPENDED_INIT:
+		if (di->susp_status.ac_suspended)
+			abx500_chargalg_ac_en(di, false, 0, 0);
+		if (di->susp_status.usb_suspended)
+			abx500_chargalg_usb_en(di, false, 0, 0);
+		abx500_chargalg_stop_safety_timer(di);
+		abx500_chargalg_stop_maintenance_timer(di);
+		di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		di->maintenance_chg = false;
+		abx500_chargalg_state_to(di, STATE_SUSPENDED);
+		power_supply_changed(&di->chargalg_psy);
+		/* Intentional fallthrough */
+
+	case STATE_SUSPENDED:
+		/* CHARGING is suspended */
+		break;
+
+	case STATE_BATT_REMOVED_INIT:
+		abx500_chargalg_stop_charging(di);
+		abx500_chargalg_state_to(di, STATE_BATT_REMOVED);
+		/* Intentional fallthrough */
+
+	case STATE_BATT_REMOVED:
+		if (!di->events.batt_rem)
+			abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
+		break;
+
+	case STATE_HW_TEMP_PROTECT_INIT:
+		abx500_chargalg_stop_charging(di);
+		abx500_chargalg_state_to(di, STATE_HW_TEMP_PROTECT);
+		/* Intentional fallthrough */
+
+	case STATE_HW_TEMP_PROTECT:
+		if (!di->events.main_thermal_prot &&
+				!di->events.usb_thermal_prot)
+			abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
+		break;
+
+	case STATE_OVV_PROTECT_INIT:
+		abx500_chargalg_stop_charging(di);
+		abx500_chargalg_state_to(di, STATE_OVV_PROTECT);
+		/* Intentional fallthrough */
+
+	case STATE_OVV_PROTECT:
+		if (!di->events.vbus_ovv &&
+				!di->events.main_ovv &&
+				!di->events.batt_ovv &&
+				di->chg_info.usb_chg_ok &&
+				di->chg_info.ac_chg_ok)
+			abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
+		break;
+
+	case STATE_CHG_NOT_OK_INIT:
+		abx500_chargalg_stop_charging(di);
+		abx500_chargalg_state_to(di, STATE_CHG_NOT_OK);
+		/* Intentional fallthrough */
+
+	case STATE_CHG_NOT_OK:
+		if (!di->events.mainextchnotok &&
+				!di->events.usbchargernotok)
+			abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
+		break;
+
+	case STATE_SAFETY_TIMER_EXPIRED_INIT:
+		abx500_chargalg_stop_charging(di);
+		abx500_chargalg_state_to(di, STATE_SAFETY_TIMER_EXPIRED);
+		/* Intentional fallthrough */
+
+	case STATE_SAFETY_TIMER_EXPIRED:
+		/* We exit this state when charger is removed */
+		break;
+
+	case STATE_NORMAL_INIT:
+		abx500_chargalg_start_charging(di,
+			di->bat->bat_type[di->bat->batt_id].normal_vol_lvl,
+			di->bat->bat_type[di->bat->batt_id].normal_cur_lvl);
+		abx500_chargalg_state_to(di, STATE_NORMAL);
+		abx500_chargalg_start_safety_timer(di);
+		abx500_chargalg_stop_maintenance_timer(di);
+		init_maxim_chg_curr(di);
+		di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
+		di->eoc_cnt = 0;
+		di->maintenance_chg = false;
+		power_supply_changed(&di->chargalg_psy);
+
+		break;
+
+	case STATE_NORMAL:
+		handle_maxim_chg_curr(di);
+		if (di->charge_status == POWER_SUPPLY_STATUS_FULL &&
+			di->maintenance_chg) {
+			if (di->bat->no_maintenance)
+				abx500_chargalg_state_to(di,
+					STATE_WAIT_FOR_RECHARGE_INIT);
+			else
+				abx500_chargalg_state_to(di,
+					STATE_MAINTENANCE_A_INIT);
+		}
+		break;
+
+	/* This state will be used when the maintenance state is disabled */
+	case STATE_WAIT_FOR_RECHARGE_INIT:
+		abx500_chargalg_hold_charging(di);
+		abx500_chargalg_state_to(di, STATE_WAIT_FOR_RECHARGE);
+		di->rch_cnt = RCH_COND_CNT;
+		/* Intentional fallthrough */
+
+	case STATE_WAIT_FOR_RECHARGE:
+		if (di->batt_data.volt <=
+			di->bat->bat_type[di->bat->batt_id].recharge_vol) {
+			if (di->rch_cnt-- == 0)
+				abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
+		} else
+			di->rch_cnt = RCH_COND_CNT;
+		break;
+
+	case STATE_MAINTENANCE_A_INIT:
+		abx500_chargalg_stop_safety_timer(di);
+		abx500_chargalg_start_maintenance_timer(di,
+			di->bat->bat_type[
+				di->bat->batt_id].maint_a_chg_timer_h);
+		abx500_chargalg_start_charging(di,
+			di->bat->bat_type[
+				di->bat->batt_id].maint_a_vol_lvl,
+			di->bat->bat_type[
+				di->bat->batt_id].maint_a_cur_lvl);
+		abx500_chargalg_state_to(di, STATE_MAINTENANCE_A);
+		power_supply_changed(&di->chargalg_psy);
+		/* Intentional fallthrough*/
+
+	case STATE_MAINTENANCE_A:
+		if (di->events.maintenance_timer_expired) {
+			abx500_chargalg_stop_maintenance_timer(di);
+			abx500_chargalg_state_to(di, STATE_MAINTENANCE_B_INIT);
+		}
+		break;
+
+	case STATE_MAINTENANCE_B_INIT:
+		abx500_chargalg_start_maintenance_timer(di,
+			di->bat->bat_type[
+				di->bat->batt_id].maint_b_chg_timer_h);
+		abx500_chargalg_start_charging(di,
+			di->bat->bat_type[
+				di->bat->batt_id].maint_b_vol_lvl,
+			di->bat->bat_type[
+				di->bat->batt_id].maint_b_cur_lvl);
+		abx500_chargalg_state_to(di, STATE_MAINTENANCE_B);
+		power_supply_changed(&di->chargalg_psy);
+		/* Intentional fallthrough*/
+
+	case STATE_MAINTENANCE_B:
+		if (di->events.maintenance_timer_expired) {
+			abx500_chargalg_stop_maintenance_timer(di);
+			abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
+		}
+		break;
+
+	case STATE_TEMP_LOWHIGH_INIT:
+		abx500_chargalg_start_charging(di,
+			di->bat->bat_type[
+				di->bat->batt_id].low_high_vol_lvl,
+			di->bat->bat_type[
+				di->bat->batt_id].low_high_cur_lvl);
+		abx500_chargalg_stop_maintenance_timer(di);
+		di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
+		abx500_chargalg_state_to(di, STATE_TEMP_LOWHIGH);
+		power_supply_changed(&di->chargalg_psy);
+		/* Intentional fallthrough */
+
+	case STATE_TEMP_LOWHIGH:
+		if (!di->events.btemp_lowhigh)
+			abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
+		break;
+
+	case STATE_WD_EXPIRED_INIT:
+		abx500_chargalg_stop_charging(di);
+		abx500_chargalg_state_to(di, STATE_WD_EXPIRED);
+		/* Intentional fallthrough */
+
+	case STATE_WD_EXPIRED:
+		if (!di->events.ac_wd_expired &&
+				!di->events.usb_wd_expired)
+			abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
+		break;
+
+	case STATE_TEMP_UNDEROVER_INIT:
+		abx500_chargalg_stop_charging(di);
+		abx500_chargalg_state_to(di, STATE_TEMP_UNDEROVER);
+		/* Intentional fallthrough */
+
+	case STATE_TEMP_UNDEROVER:
+		if (!di->events.btemp_underover)
+			abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
+		break;
+	}
+
+	/* Start charging directly if the new state is a charge state */
+	if (di->charge_state == STATE_NORMAL_INIT ||
+			di->charge_state == STATE_MAINTENANCE_A_INIT ||
+			di->charge_state == STATE_MAINTENANCE_B_INIT)
+		queue_work(di->chargalg_wq, &di->chargalg_work);
+}
+
+/**
+ * abx500_chargalg_periodic_work() - Periodic work for the algorithm
+ * @work:	pointer to the work_struct structure
+ *
+ * Work queue function for the charging algorithm
+ */
+static void abx500_chargalg_periodic_work(struct work_struct *work)
+{
+	struct abx500_chargalg *di = container_of(work,
+		struct abx500_chargalg, chargalg_periodic_work.work);
+
+	abx500_chargalg_algorithm(di);
+
+	/*
+	 * If a charger is connected then the battery has to be monitored
+	 * frequently, else the work can be delayed.
+	 */
+	if (di->chg_info.conn_chg)
+		queue_delayed_work(di->chargalg_wq,
+			&di->chargalg_periodic_work,
+			di->bat->interval_charging * HZ);
+	else
+		queue_delayed_work(di->chargalg_wq,
+			&di->chargalg_periodic_work,
+			di->bat->interval_not_charging * HZ);
+}
+
+/**
+ * abx500_chargalg_wd_work() - periodic work to kick the charger watchdog
+ * @work:	pointer to the work_struct structure
+ *
+ * Work queue function for kicking the charger watchdog
+ */
+static void abx500_chargalg_wd_work(struct work_struct *work)
+{
+	int ret;
+	struct abx500_chargalg *di = container_of(work,
+		struct abx500_chargalg, chargalg_wd_work.work);
+
+	dev_dbg(di->dev, "abx500_chargalg_wd_work\n");
+
+	ret = abx500_chargalg_kick_watchdog(di);
+	if (ret < 0)
+		dev_err(di->dev, "failed to kick watchdog\n");
+
+	queue_delayed_work(di->chargalg_wq,
+		&di->chargalg_wd_work, CHG_WD_INTERVAL);
+}
+
+/**
+ * abx500_chargalg_work() - Work to run the charging algorithm instantly
+ * @work:	pointer to the work_struct structure
+ *
+ * Work queue function for calling the charging algorithm
+ */
+static void abx500_chargalg_work(struct work_struct *work)
+{
+	struct abx500_chargalg *di = container_of(work,
+		struct abx500_chargalg, chargalg_work);
+
+	abx500_chargalg_algorithm(di);
+}
+
+/**
+ * abx500_chargalg_get_property() - get the chargalg properties
+ * @psy:	pointer to the power_supply structure
+ * @psp:	pointer to the power_supply_property structure
+ * @val:	pointer to the power_supply_propval union
+ *
+ * This function gets called when an application tries to get the
+ * chargalg properties by reading the sysfs files.
+ * status:     charging/discharging/full/unknown
+ * health:     health of the battery
+ * Returns error code in case of failure else 0 on success
+ */
+static int abx500_chargalg_get_property(struct power_supply *psy,
+	enum power_supply_property psp,
+	union power_supply_propval *val)
+{
+	struct abx500_chargalg *di;
+
+	di = to_abx500_chargalg_device_info(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = di->charge_status;
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		if (di->events.batt_ovv) {
+			val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+		} else if (di->events.btemp_underover) {
+			if (di->batt_data.temp <= di->bat->temp_under)
+				val->intval = POWER_SUPPLY_HEALTH_COLD;
+			else
+				val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+		} else {
+			val->intval = POWER_SUPPLY_HEALTH_GOOD;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* Exposure to the sysfs interface */
+
+/**
+ * abx500_chargalg_sysfs_charger() - sysfs store operations
+ * @kobj:      pointer to the struct kobject
+ * @attr:      pointer to the struct attribute
+ * @buf:       buffer that holds the parameter passed from userspace
+ * @length:    length of the parameter passed
+ *
+ * Returns length of the buffer(input taken from user space) on success
+ * else error code on failure
+ * The operation to be performed on passing the parameters from the user space.
+ */
+static ssize_t abx500_chargalg_sysfs_charger(struct kobject *kobj,
+	struct attribute *attr, const char *buf, size_t length)
+{
+	struct abx500_chargalg *di = container_of(kobj,
+		struct abx500_chargalg, chargalg_kobject);
+	long int param;
+	int ac_usb;
+	int ret;
+	char entry = *attr->name;
+
+	switch (entry) {
+	case 'c':
+		ret = strict_strtol(buf, 10, &param);
+		if (ret < 0)
+			return ret;
+
+		ac_usb = param;
+		switch (ac_usb) {
+		case 0:
+			/* Disable charging */
+			di->susp_status.ac_suspended = true;
+			di->susp_status.usb_suspended = true;
+			di->susp_status.suspended_change = true;
+			/* Trigger a state change */
+			queue_work(di->chargalg_wq,
+				&di->chargalg_work);
+			break;
+		case 1:
+			/* Enable AC Charging */
+			di->susp_status.ac_suspended = false;
+			di->susp_status.suspended_change = true;
+			/* Trigger a state change */
+			queue_work(di->chargalg_wq,
+				&di->chargalg_work);
+			break;
+		case 2:
+			/* Enable USB charging */
+			di->susp_status.usb_suspended = false;
+			di->susp_status.suspended_change = true;
+			/* Trigger a state change */
+			queue_work(di->chargalg_wq,
+				&di->chargalg_work);
+			break;
+		default:
+			dev_info(di->dev, "Wrong input\n"
+				"Enter 0. Disable AC/USB Charging\n"
+				"1. Enable AC charging\n"
+				"2. Enable USB Charging\n");
+		};
+		break;
+	};
+	return strlen(buf);
+}
+
+static struct attribute abx500_chargalg_en_charger = \
+{
+	.name = "chargalg",
+	.mode = S_IWUGO,
+};
+
+static struct attribute *abx500_chargalg_chg[] = {
+	&abx500_chargalg_en_charger,
+	NULL
+};
+
+static const struct sysfs_ops abx500_chargalg_sysfs_ops = {
+	.store = abx500_chargalg_sysfs_charger,
+};
+
+static struct kobj_type abx500_chargalg_ktype = {
+	.sysfs_ops = &abx500_chargalg_sysfs_ops,
+	.default_attrs = abx500_chargalg_chg,
+};
+
+/**
+ * abx500_chargalg_sysfs_exit() - de-init of sysfs entry
+ * @di:                pointer to the struct abx500_chargalg
+ *
+ * This function removes the entry in sysfs.
+ */
+static void abx500_chargalg_sysfs_exit(struct abx500_chargalg *di)
+{
+	kobject_del(&di->chargalg_kobject);
+}
+
+/**
+ * abx500_chargalg_sysfs_init() - init of sysfs entry
+ * @di:                pointer to the struct abx500_chargalg
+ *
+ * This function adds an entry in sysfs.
+ * Returns error code in case of failure else 0(on success)
+ */
+static int abx500_chargalg_sysfs_init(struct abx500_chargalg *di)
+{
+	int ret = 0;
+
+	ret = kobject_init_and_add(&di->chargalg_kobject,
+		&abx500_chargalg_ktype,
+		NULL, "abx500_chargalg");
+	if (ret < 0)
+		dev_err(di->dev, "failed to create sysfs entry\n");
+
+	return ret;
+}
+/* Exposure to the sysfs interface <<END>> */
+
+#if defined(CONFIG_PM)
+static int abx500_chargalg_resume(struct platform_device *pdev)
+{
+	struct abx500_chargalg *di = platform_get_drvdata(pdev);
+
+	/* Kick charger watchdog if charging (any charger online) */
+	if (di->chg_info.online_chg)
+		queue_delayed_work(di->chargalg_wq, &di->chargalg_wd_work, 0);
+
+	/*
+	 * Run the charging algorithm directly to be sure we don't
+	 * do it too seldom
+	 */
+	queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0);
+
+	return 0;
+}
+
+static int abx500_chargalg_suspend(struct platform_device *pdev,
+	pm_message_t state)
+{
+	struct abx500_chargalg *di = platform_get_drvdata(pdev);
+
+	if (di->chg_info.online_chg)
+		cancel_delayed_work_sync(&di->chargalg_wd_work);
+
+	cancel_delayed_work_sync(&di->chargalg_periodic_work);
+
+	return 0;
+}
+#else
+#define abx500_chargalg_suspend      NULL
+#define abx500_chargalg_resume       NULL
+#endif
+
+static int __devexit abx500_chargalg_remove(struct platform_device *pdev)
+{
+	struct abx500_chargalg *di = platform_get_drvdata(pdev);
+
+	/* sysfs interface to enable/disbale charging from user space */
+	abx500_chargalg_sysfs_exit(di);
+
+	/* Delete the work queue */
+	destroy_workqueue(di->chargalg_wq);
+
+	flush_scheduled_work();
+	power_supply_unregister(&di->chargalg_psy);
+	platform_set_drvdata(pdev, NULL);
+	kfree(di);
+
+	return 0;
+}
+
+static int __devinit abx500_chargalg_probe(struct platform_device *pdev)
+{
+	struct abx500_bm_plat_data *plat_data;
+	int ret = 0;
+
+	struct abx500_chargalg *di =
+		kzalloc(sizeof(struct abx500_chargalg), GFP_KERNEL);
+	if (!di)
+		return -ENOMEM;
+
+	/* get device struct */
+	di->dev = &pdev->dev;
+
+	plat_data = pdev->dev.platform_data;
+	di->pdata = plat_data->chargalg;
+	di->bat = plat_data->battery;
+
+	/* chargalg supply */
+	di->chargalg_psy.name = "abx500_chargalg";
+	di->chargalg_psy.type = POWER_SUPPLY_TYPE_BATTERY;
+	di->chargalg_psy.properties = abx500_chargalg_props;
+	di->chargalg_psy.num_properties = ARRAY_SIZE(abx500_chargalg_props);
+	di->chargalg_psy.get_property = abx500_chargalg_get_property;
+	di->chargalg_psy.supplied_to = di->pdata->supplied_to;
+	di->chargalg_psy.num_supplicants = di->pdata->num_supplicants;
+	di->chargalg_psy.external_power_changed =
+		abx500_chargalg_external_power_changed;
+
+	/* Initilialize safety timer */
+	init_timer(&di->safety_timer);
+	di->safety_timer.function = abx500_chargalg_safety_timer_expired;
+	di->safety_timer.data = (unsigned long) di;
+
+	/* Initilialize maintenance timer */
+	init_timer(&di->maintenance_timer);
+	di->maintenance_timer.function =
+		abx500_chargalg_maintenance_timer_expired;
+	di->maintenance_timer.data = (unsigned long) di;
+
+	/* Create a work queue for the chargalg */
+	di->chargalg_wq =
+		create_singlethread_workqueue("abx500_chargalg_wq");
+	if (di->chargalg_wq == NULL) {
+		dev_err(di->dev, "failed to create work queue\n");
+		goto free_device_info;
+	}
+
+	/* Init work for chargalg */
+	INIT_DELAYED_WORK_DEFERRABLE(&di->chargalg_periodic_work,
+		abx500_chargalg_periodic_work);
+	INIT_DELAYED_WORK_DEFERRABLE(&di->chargalg_wd_work,
+		abx500_chargalg_wd_work);
+
+	/* Init work for chargalg */
+	INIT_WORK(&di->chargalg_work, abx500_chargalg_work);
+
+	/* To detect charger at startup */
+	di->chg_info.prev_conn_chg = -1;
+
+	/* Register chargalg power supply class */
+	ret = power_supply_register(di->dev, &di->chargalg_psy);
+	if (ret) {
+		dev_err(di->dev, "failed to register chargalg psy\n");
+		goto free_chargalg_wq;
+	}
+
+	platform_set_drvdata(pdev, di);
+
+	/* sysfs interface to enable/disable charging from user space */
+	ret = abx500_chargalg_sysfs_init(di);
+	if (ret) {
+		dev_err(di->dev, "failed to create sysfs entry\n");
+		goto free_psy;
+	}
+
+	/* Run the charging algorithm */
+	queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0);
+
+	dev_info(di->dev, "probe success\n");
+	return ret;
+
+free_psy:
+	power_supply_unregister(&di->chargalg_psy);
+free_chargalg_wq:
+	destroy_workqueue(di->chargalg_wq);
+free_device_info:
+	kfree(di);
+
+	return ret;
+}
+
+static struct platform_driver abx500_chargalg_driver = {
+	.probe = abx500_chargalg_probe,
+	.remove = __devexit_p(abx500_chargalg_remove),
+	.suspend = abx500_chargalg_suspend,
+	.resume = abx500_chargalg_resume,
+	.driver = {
+		.name = "abx500-chargalg",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init abx500_chargalg_init(void)
+{
+	return platform_driver_register(&abx500_chargalg_driver);
+}
+
+static void __exit abx500_chargalg_exit(void)
+{
+	platform_driver_unregister(&abx500_chargalg_driver);
+}
+
+module_init(abx500_chargalg_init);
+module_exit(abx500_chargalg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Johan Palsson, Karl Komierowski");
+MODULE_ALIAS("platform:abx500-chargalg");
+MODULE_DESCRIPTION("abx500 battery charging algorithm");
diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c
index 8a612de..39763015b 100644
--- a/drivers/power/apm_power.c
+++ b/drivers/power/apm_power.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/device.h>
 #include <linux/power_supply.h>
 #include <linux/apm-emulation.h>
 
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c
index 88fd971..9eca9f1 100644
--- a/drivers/power/charger-manager.c
+++ b/drivers/power/charger-manager.c
@@ -134,12 +134,11 @@
 	union power_supply_propval val;
 	int ret;
 
-	if (cm->fuel_gauge)
-		ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
-				POWER_SUPPLY_PROP_VOLTAGE_NOW, &val);
-	else
+	if (!cm->fuel_gauge)
 		return -ENODEV;
 
+	ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
+				POWER_SUPPLY_PROP_VOLTAGE_NOW, &val);
 	if (ret)
 		return ret;
 
@@ -245,9 +244,7 @@
 	struct charger_desc *desc = cm->desc;
 
 	/* Ignore if it's redundent command */
-	if (enable && cm->charger_enabled)
-		return 0;
-	if (!enable && !cm->charger_enabled)
+	if (enable == cm->charger_enabled)
 		return 0;
 
 	if (enable) {
@@ -309,9 +306,7 @@
 
 		if (!strncmp(env_str_save, event, UEVENT_BUF_SIZE))
 			return; /* Duplicated. */
-		else
-			strncpy(env_str_save, event, UEVENT_BUF_SIZE);
-
+		strncpy(env_str_save, event, UEVENT_BUF_SIZE);
 		return;
 	}
 
@@ -387,8 +382,10 @@
 
 	mutex_lock(&cm_list_mtx);
 
-	list_for_each_entry(cm, &cm_list, entry)
-		stop = stop || _cm_monitor(cm);
+	list_for_each_entry(cm, &cm_list, entry) {
+		if (_cm_monitor(cm))
+			stop = true;
+	}
 
 	mutex_unlock(&cm_list_mtx);
 
@@ -402,7 +399,8 @@
 	struct charger_manager *cm = container_of(psy,
 			struct charger_manager, charger_psy);
 	struct charger_desc *desc = cm->desc;
-	int i, ret = 0, uV;
+	int ret = 0;
+	int uV;
 
 	switch (psp) {
 	case POWER_SUPPLY_PROP_STATUS:
@@ -428,8 +426,7 @@
 			val->intval = 0;
 		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-		ret = get_batt_uV(cm, &i);
-		val->intval = i;
+		ret = get_batt_uV(cm, &val->intval);
 		break;
 	case POWER_SUPPLY_PROP_CURRENT_NOW:
 		ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
@@ -697,8 +694,10 @@
 	mutex_lock(&cm_list_mtx);
 	list_for_each_entry(cm, &cm_list, entry) {
 		if (cm->status_save_ext_pwr_inserted != is_ext_pwr_online(cm) ||
-		    cm->status_save_batt != is_batt_present(cm))
+		    cm->status_save_batt != is_batt_present(cm)) {
 			ret = false;
+			break;
+		}
 	}
 	mutex_unlock(&cm_list_mtx);
 
@@ -855,11 +854,10 @@
 
 	platform_set_drvdata(pdev, cm);
 
-	memcpy(&cm->charger_psy, &psy_default,
-				sizeof(psy_default));
+	memcpy(&cm->charger_psy, &psy_default, sizeof(psy_default));
+
 	if (!desc->psy_name) {
-		strncpy(cm->psy_name_buf, psy_default.name,
-				PSY_NAME_MAX);
+		strncpy(cm->psy_name_buf, psy_default.name, PSY_NAME_MAX);
 	} else {
 		strncpy(cm->psy_name_buf, desc->psy_name, PSY_NAME_MAX);
 	}
@@ -894,15 +892,15 @@
 				POWER_SUPPLY_PROP_CURRENT_NOW;
 		cm->charger_psy.num_properties++;
 	}
-	if (!desc->measure_battery_temp) {
-		cm->charger_psy.properties[cm->charger_psy.num_properties] =
-				POWER_SUPPLY_PROP_TEMP_AMBIENT;
-		cm->charger_psy.num_properties++;
-	}
+
 	if (desc->measure_battery_temp) {
 		cm->charger_psy.properties[cm->charger_psy.num_properties] =
 				POWER_SUPPLY_PROP_TEMP;
 		cm->charger_psy.num_properties++;
+	} else {
+		cm->charger_psy.properties[cm->charger_psy.num_properties] =
+				POWER_SUPPLY_PROP_TEMP_AMBIENT;
+		cm->charger_psy.num_properties++;
 	}
 
 	ret = power_supply_register(NULL, &cm->charger_psy);
@@ -933,9 +931,8 @@
 	return 0;
 
 err_chg_enable:
-	if (desc->charger_regulators)
-		regulator_bulk_free(desc->num_charger_regulators,
-					desc->charger_regulators);
+	regulator_bulk_free(desc->num_charger_regulators,
+			    desc->charger_regulators);
 err_bulk_get:
 	power_supply_unregister(&cm->charger_psy);
 err_register:
@@ -961,10 +958,8 @@
 	list_del(&cm->entry);
 	mutex_unlock(&cm_list_mtx);
 
-	if (desc->charger_regulators)
-		regulator_bulk_free(desc->num_charger_regulators,
-					desc->charger_regulators);
-
+	regulator_bulk_free(desc->num_charger_regulators,
+			    desc->charger_regulators);
 	power_supply_unregister(&cm->charger_psy);
 	kfree(cm->charger_psy.properties);
 	kfree(cm->charger_stat);
@@ -982,9 +977,7 @@
 
 static int cm_suspend_prepare(struct device *dev)
 {
-	struct platform_device *pdev = container_of(dev, struct platform_device,
-						    dev);
-	struct charger_manager *cm = platform_get_drvdata(pdev);
+	struct charger_manager *cm = dev_get_drvdata(dev);
 
 	if (!cm_suspended) {
 		if (rtc_dev) {
@@ -1020,9 +1013,7 @@
 
 static void cm_suspend_complete(struct device *dev)
 {
-	struct platform_device *pdev = container_of(dev, struct platform_device,
-						    dev);
-	struct charger_manager *cm = platform_get_drvdata(pdev);
+	struct charger_manager *cm = dev_get_drvdata(dev);
 
 	if (cm_suspended) {
 		if (rtc_dev) {
diff --git a/drivers/power/da9052-battery.c b/drivers/power/da9052-battery.c
index e8ea47a..a5f6a0e 100644
--- a/drivers/power/da9052-battery.c
+++ b/drivers/power/da9052-battery.c
@@ -612,6 +612,7 @@
 	 if (ret)
 		goto err;
 
+	platform_set_drvdata(pdev, bat);
 	return 0;
 
 err:
@@ -633,6 +634,7 @@
 		free_irq(bat->da9052->irq_base + irq, bat);
 	}
 	power_supply_unregister(&bat->psy);
+	kfree(bat);
 
 	return 0;
 }
@@ -645,18 +647,7 @@
 		.owner = THIS_MODULE,
 	},
 };
-
-static int __init da9052_bat_init(void)
-{
-	return platform_driver_register(&da9052_bat_driver);
-}
-module_init(da9052_bat_init);
-
-static void __exit da9052_bat_exit(void)
-{
-	platform_driver_unregister(&da9052_bat_driver);
-}
-module_exit(da9052_bat_exit);
+module_platform_driver(da9052_bat_driver);
 
 MODULE_DESCRIPTION("DA9052 BAT Device Driver");
 MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c
index bfbce5d..6bb6e2f 100644
--- a/drivers/power/ds2782_battery.c
+++ b/drivers/power/ds2782_battery.c
@@ -403,18 +403,7 @@
 	.remove		= ds278x_battery_remove,
 	.id_table	= ds278x_id,
 };
-
-static int __init ds278x_init(void)
-{
-	return i2c_add_driver(&ds278x_battery_driver);
-}
-module_init(ds278x_init);
-
-static void __exit ds278x_exit(void)
-{
-	i2c_del_driver(&ds278x_battery_driver);
-}
-module_exit(ds278x_exit);
+module_i2c_driver(ds278x_battery_driver);
 
 MODULE_AUTHOR("Ryan Mallon");
 MODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauage IC driver");
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c
index 1289a5f..39eb50f 100644
--- a/drivers/power/isp1704_charger.c
+++ b/drivers/power/isp1704_charger.c
@@ -480,6 +480,7 @@
 
 	dev_err(&pdev->dev, "failed to register isp1704 with error %d\n", ret);
 
+	isp1704_charger_set_power(isp, 0);
 	return ret;
 }
 
diff --git a/drivers/power/lp8727_charger.c b/drivers/power/lp8727_charger.c
index c53dd12..d8b7578 100644
--- a/drivers/power/lp8727_charger.c
+++ b/drivers/power/lp8727_charger.c
@@ -1,6 +1,7 @@
 /*
- * Driver for LP8727 Micro/Mini USB IC with intergrated charger
+ * Driver for LP8727 Micro/Mini USB IC with integrated charger
  *
+ *			Copyright (C) 2011 Texas Instruments
  *			Copyright (C) 2011 National Semiconductor
  *
  * This program is free software; you can redistribute it and/or modify
@@ -25,7 +26,7 @@
 #define INT1		0x4
 #define INT2		0x5
 #define STATUS1		0x6
-#define STATUS2 	0x7
+#define STATUS2		0x7
 #define CHGCTRL2	0x9
 
 /* CTRL1 register */
@@ -91,7 +92,7 @@
 	enum lp8727_dev_id devid;
 };
 
-static int lp8727_i2c_read(struct lp8727_chg *pchg, u8 reg, u8 *data, u8 len)
+static int lp8727_read_bytes(struct lp8727_chg *pchg, u8 reg, u8 *data, u8 len)
 {
 	s32 ret;
 
@@ -102,29 +103,22 @@
 	return (ret != len) ? -EIO : 0;
 }
 
-static int lp8727_i2c_write(struct lp8727_chg *pchg, u8 reg, u8 *data, u8 len)
+static inline int lp8727_read_byte(struct lp8727_chg *pchg, u8 reg, u8 *data)
 {
-	s32 ret;
+	return lp8727_read_bytes(pchg, reg, data, 1);
+}
+
+static int lp8727_write_byte(struct lp8727_chg *pchg, u8 reg, u8 data)
+{
+	int ret;
 
 	mutex_lock(&pchg->xfer_lock);
-	ret = i2c_smbus_write_i2c_block_data(pchg->client, reg, len, data);
+	ret = i2c_smbus_write_byte_data(pchg->client, reg, data);
 	mutex_unlock(&pchg->xfer_lock);
 
 	return ret;
 }
 
-static inline int lp8727_i2c_read_byte(struct lp8727_chg *pchg, u8 reg,
-				       u8 *data)
-{
-	return lp8727_i2c_read(pchg, reg, data, 1);
-}
-
-static inline int lp8727_i2c_write_byte(struct lp8727_chg *pchg, u8 reg,
-					u8 *data)
-{
-	return lp8727_i2c_write(pchg, reg, data, 1);
-}
-
 static int lp8727_is_charger_attached(const char *name, int id)
 {
 	if (name) {
@@ -137,37 +131,41 @@
 	return (id >= ID_TA && id <= ID_USB_CHG) ? 1 : 0;
 }
 
-static void lp8727_init_device(struct lp8727_chg *pchg)
+static int lp8727_init_device(struct lp8727_chg *pchg)
 {
 	u8 val;
+	int ret;
 
 	val = ID200_EN | ADC_EN | CP_EN;
-	if (lp8727_i2c_write_byte(pchg, CTRL1, &val))
-		dev_err(pchg->dev, "i2c write err : addr=0x%.2x\n", CTRL1);
+	ret = lp8727_write_byte(pchg, CTRL1, val);
+	if (ret)
+		return ret;
 
 	val = INT_EN | CHGDET_EN;
-	if (lp8727_i2c_write_byte(pchg, CTRL2, &val))
-		dev_err(pchg->dev, "i2c write err : addr=0x%.2x\n", CTRL2);
+	ret = lp8727_write_byte(pchg, CTRL2, val);
+	if (ret)
+		return ret;
+
+	return 0;
 }
 
 static int lp8727_is_dedicated_charger(struct lp8727_chg *pchg)
 {
 	u8 val;
-	lp8727_i2c_read_byte(pchg, STATUS1, &val);
-	return (val & DCPORT);
+	lp8727_read_byte(pchg, STATUS1, &val);
+	return val & DCPORT;
 }
 
 static int lp8727_is_usb_charger(struct lp8727_chg *pchg)
 {
 	u8 val;
-	lp8727_i2c_read_byte(pchg, STATUS1, &val);
-	return (val & CHPORT);
+	lp8727_read_byte(pchg, STATUS1, &val);
+	return val & CHPORT;
 }
 
 static void lp8727_ctrl_switch(struct lp8727_chg *pchg, u8 sw)
 {
-	u8 val = sw;
-	lp8727_i2c_write_byte(pchg, SWCTRL, &val);
+	lp8727_write_byte(pchg, SWCTRL, sw);
 }
 
 static void lp8727_id_detection(struct lp8727_chg *pchg, u8 id, int vbusin)
@@ -207,9 +205,9 @@
 {
 	u8 val;
 
-	lp8727_i2c_read_byte(pchg, CTRL2, &val);
+	lp8727_read_byte(pchg, CTRL2, &val);
 	val |= CHGDET_EN;
-	lp8727_i2c_write_byte(pchg, CTRL2, &val);
+	lp8727_write_byte(pchg, CTRL2, val);
 }
 
 static void lp8727_delayed_func(struct work_struct *_work)
@@ -218,7 +216,7 @@
 	struct lp8727_chg *pchg =
 	    container_of(_work, struct lp8727_chg, work.work);
 
-	if (lp8727_i2c_read(pchg, INT1, intstat, 2)) {
+	if (lp8727_read_bytes(pchg, INT1, intstat, 2)) {
 		dev_err(pchg->dev, "can not read INT registers\n");
 		return;
 	}
@@ -244,20 +242,22 @@
 	return IRQ_HANDLED;
 }
 
-static void lp8727_intr_config(struct lp8727_chg *pchg)
+static int lp8727_intr_config(struct lp8727_chg *pchg)
 {
 	INIT_DELAYED_WORK(&pchg->work, lp8727_delayed_func);
 
 	pchg->irqthread = create_singlethread_workqueue("lp8727-irqthd");
-	if (!pchg->irqthread)
+	if (!pchg->irqthread) {
 		dev_err(pchg->dev, "can not create thread for lp8727\n");
-
-	if (request_threaded_irq(pchg->client->irq,
-				 NULL,
-				 lp8727_isr_func,
-				 IRQF_TRIGGER_FALLING, "lp8727_irq", pchg)) {
-		dev_err(pchg->dev, "lp8727 irq can not be registered\n");
+		return -ENOMEM;
 	}
+
+	return request_threaded_irq(pchg->client->irq,
+				NULL,
+				lp8727_isr_func,
+				IRQF_TRIGGER_FALLING,
+				"lp8727_irq",
+				pchg);
 }
 
 static enum power_supply_property lp8727_charger_prop[] = {
@@ -300,7 +300,7 @@
 	switch (psp) {
 	case POWER_SUPPLY_PROP_STATUS:
 		if (lp8727_is_charger_attached(psy->name, pchg->devid)) {
-			lp8727_i2c_read_byte(pchg, STATUS1, &read);
+			lp8727_read_byte(pchg, STATUS1, &read);
 			if (((read & CHGSTAT) >> 4) == EOC)
 				val->intval = POWER_SUPPLY_STATUS_FULL;
 			else
@@ -310,7 +310,7 @@
 		}
 		break;
 	case POWER_SUPPLY_PROP_HEALTH:
-		lp8727_i2c_read_byte(pchg, STATUS2, &read);
+		lp8727_read_byte(pchg, STATUS2, &read);
 		read = (read & TEMP_STAT) >> 5;
 		if (read >= 0x1 && read <= 0x3)
 			val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
@@ -351,7 +351,7 @@
 			eoc_level = pchg->chg_parm->eoc_level;
 			ichg = pchg->chg_parm->ichg;
 			val = (ichg << 4) | eoc_level;
-			lp8727_i2c_write_byte(pchg, CHGCTRL2, &val);
+			lp8727_write_byte(pchg, CHGCTRL2, val);
 		}
 	}
 }
@@ -439,15 +439,29 @@
 
 	mutex_init(&pchg->xfer_lock);
 
-	lp8727_init_device(pchg);
-	lp8727_intr_config(pchg);
+	ret = lp8727_init_device(pchg);
+	if (ret) {
+		dev_err(pchg->dev, "i2c communication err: %d", ret);
+		goto error;
+	}
+
+	ret = lp8727_intr_config(pchg);
+	if (ret) {
+		dev_err(pchg->dev, "irq handler err: %d", ret);
+		goto error;
+	}
 
 	ret = lp8727_register_psy(pchg);
-	if (ret)
-		dev_err(pchg->dev,
-			"can not register power supplies. err=%d", ret);
+	if (ret) {
+		dev_err(pchg->dev, "power supplies register err: %d", ret);
+		goto error;
+	}
 
 	return 0;
+
+error:
+	kfree(pchg);
+	return ret;
 }
 
 static int __devexit lp8727_remove(struct i2c_client *cl)
@@ -466,6 +480,7 @@
 	{"lp8727", 0},
 	{ }
 };
+MODULE_DEVICE_TABLE(i2c, lp8727_ids);
 
 static struct i2c_driver lp8727_driver = {
 	.driver = {
@@ -475,21 +490,9 @@
 	.remove = __devexit_p(lp8727_remove),
 	.id_table = lp8727_ids,
 };
+module_i2c_driver(lp8727_driver);
 
-static int __init lp8727_init(void)
-{
-	return i2c_add_driver(&lp8727_driver);
-}
-
-static void __exit lp8727_exit(void)
-{
-	i2c_del_driver(&lp8727_driver);
-}
-
-module_init(lp8727_init);
-module_exit(lp8727_exit);
-
-MODULE_DESCRIPTION("National Semiconductor LP8727 charger driver");
-MODULE_AUTHOR
-    ("Woogyom Kim <milo.kim@ti.com>, Daniel Jeong <daniel.jeong@ti.com>");
+MODULE_DESCRIPTION("TI/National Semiconductor LP8727 charger driver");
+MODULE_AUTHOR("Woogyom Kim <milo.kim@ti.com>, "
+	      "Daniel Jeong <daniel.jeong@ti.com>");
 MODULE_LICENSE("GPL");
diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c
index 2f2f9a6..c284143 100644
--- a/drivers/power/max17040_battery.c
+++ b/drivers/power/max17040_battery.c
@@ -290,18 +290,7 @@
 	.resume		= max17040_resume,
 	.id_table	= max17040_id,
 };
-
-static int __init max17040_init(void)
-{
-	return i2c_add_driver(&max17040_i2c_driver);
-}
-module_init(max17040_init);
-
-static void __exit max17040_exit(void)
-{
-	i2c_del_driver(&max17040_i2c_driver);
-}
-module_exit(max17040_exit);
+module_i2c_driver(max17040_i2c_driver);
 
 MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
 MODULE_DESCRIPTION("MAX17040 Fuel Gauge");
diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c
index 86acee2..04620c2 100644
--- a/drivers/power/max17042_battery.c
+++ b/drivers/power/max17042_battery.c
@@ -26,14 +26,47 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
 #include <linux/mod_devicetable.h>
 #include <linux/power_supply.h>
 #include <linux/power/max17042_battery.h>
+#include <linux/of.h>
+
+/* Status register bits */
+#define STATUS_POR_BIT         (1 << 1)
+#define STATUS_BST_BIT         (1 << 3)
+#define STATUS_VMN_BIT         (1 << 8)
+#define STATUS_TMN_BIT         (1 << 9)
+#define STATUS_SMN_BIT         (1 << 10)
+#define STATUS_BI_BIT          (1 << 11)
+#define STATUS_VMX_BIT         (1 << 12)
+#define STATUS_TMX_BIT         (1 << 13)
+#define STATUS_SMX_BIT         (1 << 14)
+#define STATUS_BR_BIT          (1 << 15)
+
+/* Interrupt mask bits */
+#define CONFIG_ALRT_BIT_ENBL	(1 << 2)
+#define STATUS_INTR_SOCMIN_BIT	(1 << 10)
+#define STATUS_INTR_SOCMAX_BIT	(1 << 14)
+
+#define VFSOC0_LOCK		0x0000
+#define VFSOC0_UNLOCK		0x0080
+#define MODEL_UNLOCK1	0X0059
+#define MODEL_UNLOCK2	0X00C4
+#define MODEL_LOCK1		0X0000
+#define MODEL_LOCK2		0X0000
+
+#define dQ_ACC_DIV	0x4
+#define dP_ACC_100	0x1900
+#define dP_ACC_200	0x3200
 
 struct max17042_chip {
 	struct i2c_client *client;
 	struct power_supply battery;
 	struct max17042_platform_data *pdata;
+	struct work_struct work;
+	int    init_complete;
 };
 
 static int max17042_write_reg(struct i2c_client *client, u8 reg, u16 value)
@@ -87,6 +120,9 @@
 				struct max17042_chip, battery);
 	int ret;
 
+	if (!chip->init_complete)
+		return -EAGAIN;
+
 	switch (psp) {
 	case POWER_SUPPLY_PROP_PRESENT:
 		ret = max17042_read_reg(chip->client, MAX17042_STATUS);
@@ -136,21 +172,18 @@
 		val->intval = ret * 625 / 8;
 		break;
 	case POWER_SUPPLY_PROP_CAPACITY:
-		ret = max17042_read_reg(chip->client, MAX17042_SOC);
+		ret = max17042_read_reg(chip->client, MAX17042_RepSOC);
 		if (ret < 0)
 			return ret;
 
 		val->intval = ret >> 8;
 		break;
 	case POWER_SUPPLY_PROP_CHARGE_FULL:
-		ret = max17042_read_reg(chip->client, MAX17042_RepSOC);
+		ret = max17042_read_reg(chip->client, MAX17042_FullCAP);
 		if (ret < 0)
 			return ret;
 
-		if ((ret >> 8) >= MAX17042_BATTERY_FULL)
-			val->intval = 1;
-		else if (ret >= 0)
-			val->intval = 0;
+		val->intval = ret * 1000 / 2;
 		break;
 	case POWER_SUPPLY_PROP_TEMP:
 		ret = max17042_read_reg(chip->client, MAX17042_TEMP);
@@ -210,22 +243,419 @@
 	return 0;
 }
 
+static int max17042_write_verify_reg(struct i2c_client *client,
+				u8 reg, u16 value)
+{
+	int retries = 8;
+	int ret;
+	u16 read_value;
+
+	do {
+		ret = i2c_smbus_write_word_data(client, reg, value);
+		read_value =  max17042_read_reg(client, reg);
+		if (read_value != value) {
+			ret = -EIO;
+			retries--;
+		}
+	} while (retries && read_value != value);
+
+	if (ret < 0)
+		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+	return ret;
+}
+
+static inline void max17042_override_por(
+	struct i2c_client *client, u8 reg, u16 value)
+{
+	if (value)
+		max17042_write_reg(client, reg, value);
+}
+
+static inline void max10742_unlock_model(struct max17042_chip *chip)
+{
+	struct i2c_client *client = chip->client;
+	max17042_write_reg(client, MAX17042_MLOCKReg1, MODEL_UNLOCK1);
+	max17042_write_reg(client, MAX17042_MLOCKReg2, MODEL_UNLOCK2);
+}
+
+static inline void max10742_lock_model(struct max17042_chip *chip)
+{
+	struct i2c_client *client = chip->client;
+	max17042_write_reg(client, MAX17042_MLOCKReg1, MODEL_LOCK1);
+	max17042_write_reg(client, MAX17042_MLOCKReg2, MODEL_LOCK2);
+}
+
+static inline void max17042_write_model_data(struct max17042_chip *chip,
+					u8 addr, int size)
+{
+	struct i2c_client *client = chip->client;
+	int i;
+	for (i = 0; i < size; i++)
+		max17042_write_reg(client, addr + i,
+				chip->pdata->config_data->cell_char_tbl[i]);
+}
+
+static inline void max17042_read_model_data(struct max17042_chip *chip,
+					u8 addr, u16 *data, int size)
+{
+	struct i2c_client *client = chip->client;
+	int i;
+
+	for (i = 0; i < size; i++)
+		data[i] = max17042_read_reg(client, addr + i);
+}
+
+static inline int max17042_model_data_compare(struct max17042_chip *chip,
+					u16 *data1, u16 *data2, int size)
+{
+	int i;
+
+	if (memcmp(data1, data2, size)) {
+		dev_err(&chip->client->dev, "%s compare failed\n", __func__);
+		for (i = 0; i < size; i++)
+			dev_info(&chip->client->dev, "0x%x, 0x%x",
+				data1[i], data2[i]);
+		dev_info(&chip->client->dev, "\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int max17042_init_model(struct max17042_chip *chip)
+{
+	int ret;
+	int table_size =
+		sizeof(chip->pdata->config_data->cell_char_tbl)/sizeof(u16);
+	u16 *temp_data;
+
+	temp_data = kzalloc(table_size, GFP_KERNEL);
+	if (!temp_data)
+		return -ENOMEM;
+
+	max10742_unlock_model(chip);
+	max17042_write_model_data(chip, MAX17042_MODELChrTbl,
+				table_size);
+	max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data,
+				table_size);
+
+	ret = max17042_model_data_compare(
+		chip,
+		chip->pdata->config_data->cell_char_tbl,
+		temp_data,
+		table_size);
+
+	max10742_lock_model(chip);
+	kfree(temp_data);
+
+	return ret;
+}
+
+static int max17042_verify_model_lock(struct max17042_chip *chip)
+{
+	int i;
+	int table_size =
+		sizeof(chip->pdata->config_data->cell_char_tbl);
+	u16 *temp_data;
+	int ret = 0;
+
+	temp_data = kzalloc(table_size, GFP_KERNEL);
+	if (!temp_data)
+		return -ENOMEM;
+
+	max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data,
+				table_size);
+	for (i = 0; i < table_size; i++)
+		if (temp_data[i])
+			ret = -EINVAL;
+
+	kfree(temp_data);
+	return ret;
+}
+
+static void max17042_write_config_regs(struct max17042_chip *chip)
+{
+	struct max17042_config_data *config = chip->pdata->config_data;
+
+	max17042_write_reg(chip->client, MAX17042_CONFIG, config->config);
+	max17042_write_reg(chip->client, MAX17042_LearnCFG, config->learn_cfg);
+	max17042_write_reg(chip->client, MAX17042_FilterCFG,
+			config->filter_cfg);
+	max17042_write_reg(chip->client, MAX17042_RelaxCFG, config->relax_cfg);
+}
+
+static void  max17042_write_custom_regs(struct max17042_chip *chip)
+{
+	struct max17042_config_data *config = chip->pdata->config_data;
+
+	max17042_write_verify_reg(chip->client, MAX17042_RCOMP0,
+				config->rcomp0);
+	max17042_write_verify_reg(chip->client, MAX17042_TempCo,
+				config->tcompc0);
+	max17042_write_reg(chip->client, MAX17042_EmptyTempCo,
+			config->empty_tempco);
+	max17042_write_verify_reg(chip->client, MAX17042_K_empty0,
+				config->kempty0);
+	max17042_write_verify_reg(chip->client, MAX17042_ICHGTerm,
+				config->ichgt_term);
+}
+
+static void max17042_update_capacity_regs(struct max17042_chip *chip)
+{
+	struct max17042_config_data *config = chip->pdata->config_data;
+
+	max17042_write_verify_reg(chip->client, MAX17042_FullCAP,
+				config->fullcap);
+	max17042_write_reg(chip->client, MAX17042_DesignCap,
+			config->design_cap);
+	max17042_write_verify_reg(chip->client, MAX17042_FullCAPNom,
+				config->fullcapnom);
+}
+
+static void max17042_reset_vfsoc0_reg(struct max17042_chip *chip)
+{
+	u16 vfSoc;
+
+	vfSoc = max17042_read_reg(chip->client, MAX17042_VFSOC);
+	max17042_write_reg(chip->client, MAX17042_VFSOC0Enable, VFSOC0_UNLOCK);
+	max17042_write_verify_reg(chip->client, MAX17042_VFSOC0, vfSoc);
+	max17042_write_reg(chip->client, MAX17042_VFSOC0Enable, VFSOC0_LOCK);
+}
+
+static void max17042_load_new_capacity_params(struct max17042_chip *chip)
+{
+	u16 full_cap0, rep_cap, dq_acc, vfSoc;
+	u32 rem_cap;
+
+	struct max17042_config_data *config = chip->pdata->config_data;
+
+	full_cap0 = max17042_read_reg(chip->client, MAX17042_FullCAP0);
+	vfSoc = max17042_read_reg(chip->client, MAX17042_VFSOC);
+
+	/* fg_vfSoc needs to shifted by 8 bits to get the
+	 * perc in 1% accuracy, to get the right rem_cap multiply
+	 * full_cap0, fg_vfSoc and devide by 100
+	 */
+	rem_cap = ((vfSoc >> 8) * full_cap0) / 100;
+	max17042_write_verify_reg(chip->client, MAX17042_RemCap, (u16)rem_cap);
+
+	rep_cap = (u16)rem_cap;
+	max17042_write_verify_reg(chip->client, MAX17042_RepCap, rep_cap);
+
+	/* Write dQ_acc to 200% of Capacity and dP_acc to 200% */
+	dq_acc = config->fullcap / dQ_ACC_DIV;
+	max17042_write_verify_reg(chip->client, MAX17042_dQacc, dq_acc);
+	max17042_write_verify_reg(chip->client, MAX17042_dPacc, dP_ACC_200);
+
+	max17042_write_verify_reg(chip->client, MAX17042_FullCAP,
+			config->fullcap);
+	max17042_write_reg(chip->client, MAX17042_DesignCap,
+			config->design_cap);
+	max17042_write_verify_reg(chip->client, MAX17042_FullCAPNom,
+			config->fullcapnom);
+}
+
+/*
+ * Block write all the override values coming from platform data.
+ * This function MUST be called before the POR initialization proceedure
+ * specified by maxim.
+ */
+static inline void max17042_override_por_values(struct max17042_chip *chip)
+{
+	struct i2c_client *client = chip->client;
+	struct max17042_config_data *config = chip->pdata->config_data;
+
+	max17042_override_por(client, MAX17042_TGAIN, config->tgain);
+	max17042_override_por(client, MAx17042_TOFF, config->toff);
+	max17042_override_por(client, MAX17042_CGAIN, config->cgain);
+	max17042_override_por(client, MAX17042_COFF, config->coff);
+
+	max17042_override_por(client, MAX17042_VALRT_Th, config->valrt_thresh);
+	max17042_override_por(client, MAX17042_TALRT_Th, config->talrt_thresh);
+	max17042_override_por(client, MAX17042_SALRT_Th,
+			config->soc_alrt_thresh);
+	max17042_override_por(client, MAX17042_CONFIG, config->config);
+	max17042_override_por(client, MAX17042_SHDNTIMER, config->shdntimer);
+
+	max17042_override_por(client, MAX17042_DesignCap, config->design_cap);
+	max17042_override_por(client, MAX17042_ICHGTerm, config->ichgt_term);
+
+	max17042_override_por(client, MAX17042_AtRate, config->at_rate);
+	max17042_override_por(client, MAX17042_LearnCFG, config->learn_cfg);
+	max17042_override_por(client, MAX17042_FilterCFG, config->filter_cfg);
+	max17042_override_por(client, MAX17042_RelaxCFG, config->relax_cfg);
+	max17042_override_por(client, MAX17042_MiscCFG, config->misc_cfg);
+	max17042_override_por(client, MAX17042_MaskSOC, config->masksoc);
+
+	max17042_override_por(client, MAX17042_FullCAP, config->fullcap);
+	max17042_override_por(client, MAX17042_FullCAPNom, config->fullcapnom);
+	max17042_override_por(client, MAX17042_SOC_empty, config->socempty);
+	max17042_override_por(client, MAX17042_LAvg_empty, config->lavg_empty);
+	max17042_override_por(client, MAX17042_dQacc, config->dqacc);
+	max17042_override_por(client, MAX17042_dPacc, config->dpacc);
+
+	max17042_override_por(client, MAX17042_V_empty, config->vempty);
+	max17042_override_por(client, MAX17042_TempNom, config->temp_nom);
+	max17042_override_por(client, MAX17042_TempLim, config->temp_lim);
+	max17042_override_por(client, MAX17042_FCTC, config->fctc);
+	max17042_override_por(client, MAX17042_RCOMP0, config->rcomp0);
+	max17042_override_por(client, MAX17042_TempCo, config->tcompc0);
+	max17042_override_por(client, MAX17042_EmptyTempCo,
+			config->empty_tempco);
+	max17042_override_por(client, MAX17042_K_empty0, config->kempty0);
+}
+
+static int max17042_init_chip(struct max17042_chip *chip)
+{
+	int ret;
+	int val;
+
+	max17042_override_por_values(chip);
+	/* After Power up, the MAX17042 requires 500mS in order
+	 * to perform signal debouncing and initial SOC reporting
+	 */
+	msleep(500);
+
+	/* Initialize configaration */
+	max17042_write_config_regs(chip);
+
+	/* write cell characterization data */
+	ret = max17042_init_model(chip);
+	if (ret) {
+		dev_err(&chip->client->dev, "%s init failed\n",
+			__func__);
+		return -EIO;
+	}
+	max17042_verify_model_lock(chip);
+	if (ret) {
+		dev_err(&chip->client->dev, "%s lock verify failed\n",
+			__func__);
+		return -EIO;
+	}
+	/* write custom parameters */
+	max17042_write_custom_regs(chip);
+
+	/* update capacity params */
+	max17042_update_capacity_regs(chip);
+
+	/* delay must be atleast 350mS to allow VFSOC
+	 * to be calculated from the new configuration
+	 */
+	msleep(350);
+
+	/* reset vfsoc0 reg */
+	max17042_reset_vfsoc0_reg(chip);
+
+	/* load new capacity params */
+	max17042_load_new_capacity_params(chip);
+
+	/* Init complete, Clear the POR bit */
+	val = max17042_read_reg(chip->client, MAX17042_STATUS);
+	max17042_write_reg(chip->client, MAX17042_STATUS,
+			val & (~STATUS_POR_BIT));
+	return 0;
+}
+
+static void max17042_set_soc_threshold(struct max17042_chip *chip, u16 off)
+{
+	u16 soc, soc_tr;
+
+	/* program interrupt thesholds such that we should
+	 * get interrupt for every 'off' perc change in the soc
+	 */
+	soc = max17042_read_reg(chip->client, MAX17042_RepSOC) >> 8;
+	soc_tr = (soc + off) << 8;
+	soc_tr |= (soc - off);
+	max17042_write_reg(chip->client, MAX17042_SALRT_Th, soc_tr);
+}
+
+static irqreturn_t max17042_thread_handler(int id, void *dev)
+{
+	struct max17042_chip *chip = dev;
+	u16 val;
+
+	val = max17042_read_reg(chip->client, MAX17042_STATUS);
+	if ((val & STATUS_INTR_SOCMIN_BIT) ||
+		(val & STATUS_INTR_SOCMAX_BIT)) {
+		dev_info(&chip->client->dev, "SOC threshold INTR\n");
+		max17042_set_soc_threshold(chip, 1);
+	}
+
+	power_supply_changed(&chip->battery);
+	return IRQ_HANDLED;
+}
+
+static void max17042_init_worker(struct work_struct *work)
+{
+	struct max17042_chip *chip = container_of(work,
+				struct max17042_chip, work);
+	int ret;
+
+	/* Initialize registers according to values from the platform data */
+	if (chip->pdata->enable_por_init && chip->pdata->config_data) {
+		ret = max17042_init_chip(chip);
+		if (ret)
+			return;
+	}
+
+	chip->init_complete = 1;
+}
+
+#ifdef CONFIG_OF
+static struct max17042_platform_data *
+max17042_get_pdata(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	u32 prop;
+	struct max17042_platform_data *pdata;
+
+	if (!np)
+		return dev->platform_data;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	/*
+	 * Require current sense resistor value to be specified for
+	 * current-sense functionality to be enabled at all.
+	 */
+	if (of_property_read_u32(np, "maxim,rsns-microohm", &prop) == 0) {
+		pdata->r_sns = prop;
+		pdata->enable_current_sense = true;
+	}
+
+	return pdata;
+}
+#else
+static struct max17042_platform_data *
+max17042_get_pdata(struct device *dev)
+{
+	return dev->platform_data;
+}
+#endif
+
 static int __devinit max17042_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
 	struct max17042_chip *chip;
 	int ret;
+	int reg;
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
 		return -EIO;
 
-	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
 	if (!chip)
 		return -ENOMEM;
 
 	chip->client = client;
-	chip->pdata = client->dev.platform_data;
+	chip->pdata = max17042_get_pdata(&client->dev);
+	if (!chip->pdata) {
+		dev_err(&client->dev, "no platform data provided\n");
+		return -EINVAL;
+	}
 
 	i2c_set_clientdata(client, chip);
 
@@ -243,17 +673,9 @@
 	if (chip->pdata->r_sns == 0)
 		chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR;
 
-	ret = power_supply_register(&client->dev, &chip->battery);
-	if (ret) {
-		dev_err(&client->dev, "failed: power supply register\n");
-		kfree(chip);
-		return ret;
-	}
-
-	/* Initialize registers according to values from the platform data */
 	if (chip->pdata->init_data)
 		max17042_set_reg(client, chip->pdata->init_data,
-				 chip->pdata->num_init_data);
+				chip->pdata->num_init_data);
 
 	if (!chip->pdata->enable_current_sense) {
 		max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
@@ -261,7 +683,34 @@
 		max17042_write_reg(client, MAX17042_LearnCFG, 0x0007);
 	}
 
-	return 0;
+	if (client->irq) {
+		ret = request_threaded_irq(client->irq, NULL,
+						max17042_thread_handler,
+						IRQF_TRIGGER_FALLING,
+						chip->battery.name, chip);
+		if (!ret) {
+			reg =  max17042_read_reg(client, MAX17042_CONFIG);
+			reg |= CONFIG_ALRT_BIT_ENBL;
+			max17042_write_reg(client, MAX17042_CONFIG, reg);
+			max17042_set_soc_threshold(chip, 1);
+		} else
+			dev_err(&client->dev, "%s(): cannot get IRQ\n",
+				__func__);
+	}
+
+	reg = max17042_read_reg(chip->client, MAX17042_STATUS);
+
+	if (reg & STATUS_POR_BIT) {
+		INIT_WORK(&chip->work, max17042_init_worker);
+		schedule_work(&chip->work);
+	} else {
+		chip->init_complete = 1;
+	}
+
+	ret = power_supply_register(&client->dev, &chip->battery);
+	if (ret)
+		dev_err(&client->dev, "failed: power supply register\n");
+	return ret;
 }
 
 static int __devexit max17042_remove(struct i2c_client *client)
@@ -269,10 +718,17 @@
 	struct max17042_chip *chip = i2c_get_clientdata(client);
 
 	power_supply_unregister(&chip->battery);
-	kfree(chip);
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id max17042_dt_match[] = {
+	{ .compatible = "maxim,max17042" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, max17042_dt_match);
+#endif
+
 static const struct i2c_device_id max17042_id[] = {
 	{ "max17042", 0 },
 	{ }
@@ -282,23 +738,13 @@
 static struct i2c_driver max17042_i2c_driver = {
 	.driver	= {
 		.name	= "max17042",
+		.of_match_table = of_match_ptr(max17042_dt_match),
 	},
 	.probe		= max17042_probe,
 	.remove		= __devexit_p(max17042_remove),
 	.id_table	= max17042_id,
 };
-
-static int __init max17042_init(void)
-{
-	return i2c_add_driver(&max17042_i2c_driver);
-}
-module_init(max17042_init);
-
-static void __exit max17042_exit(void)
-{
-	i2c_del_driver(&max17042_i2c_driver);
-}
-module_exit(max17042_exit);
+module_i2c_driver(max17042_i2c_driver);
 
 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
 MODULE_DESCRIPTION("MAX17042 Fuel Gauge");
diff --git a/drivers/power/max8998_charger.c b/drivers/power/max8998_charger.c
index 9b3f2bf5..6dc01c2 100644
--- a/drivers/power/max8998_charger.c
+++ b/drivers/power/max8998_charger.c
@@ -19,7 +19,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/module.h>
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/slab.h>
diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h
index 018de2b..cc439fd 100644
--- a/drivers/power/power_supply.h
+++ b/drivers/power/power_supply.h
@@ -10,6 +10,10 @@
  *  You may use this code as per GPL version 2
  */
 
+struct device;
+struct device_type;
+struct power_supply;
+
 #ifdef CONFIG_SYSFS
 
 extern void power_supply_init_attrs(struct device_type *dev_type);
diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c
index da25eb9..995f966 100644
--- a/drivers/power/power_supply_leds.c
+++ b/drivers/power/power_supply_leds.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/device.h>
 #include <linux/power_supply.h>
 #include <linux/slab.h>
 
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index b52b57c..4368e7d 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -12,6 +12,7 @@
  */
 
 #include <linux/ctype.h>
+#include <linux/device.h>
 #include <linux/power_supply.h>
 #include <linux/slab.h>
 #include <linux/stat.h>
diff --git a/drivers/power/sbs-battery.c b/drivers/power/sbs-battery.c
index 9ff8af0..06b659d 100644
--- a/drivers/power/sbs-battery.c
+++ b/drivers/power/sbs-battery.c
@@ -852,18 +852,7 @@
 		.of_match_table = sbs_dt_ids,
 	},
 };
-
-static int __init sbs_battery_init(void)
-{
-	return i2c_add_driver(&sbs_battery_driver);
-}
-module_init(sbs_battery_init);
-
-static void __exit sbs_battery_exit(void)
-{
-	i2c_del_driver(&sbs_battery_driver);
-}
-module_exit(sbs_battery_exit);
+module_i2c_driver(sbs_battery_driver);
 
 MODULE_DESCRIPTION("SBS battery monitor driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/power/smb347-charger.c b/drivers/power/smb347-charger.c
new file mode 100644
index 0000000..ce1694d
--- /dev/null
+++ b/drivers/power/smb347-charger.c
@@ -0,0 +1,1294 @@
+/*
+ * Summit Microelectronics SMB347 Battery Charger Driver
+ *
+ * Copyright (C) 2011, Intel Corporation
+ *
+ * Authors: Bruce E. Robertson <bruce.e.robertson@intel.com>
+ *          Mika Westerberg <mika.westerberg@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/power_supply.h>
+#include <linux/power/smb347-charger.h>
+#include <linux/seq_file.h>
+
+/*
+ * Configuration registers. These are mirrored to volatile RAM and can be
+ * written once %CMD_A_ALLOW_WRITE is set in %CMD_A register. They will be
+ * reloaded from non-volatile registers after POR.
+ */
+#define CFG_CHARGE_CURRENT			0x00
+#define CFG_CHARGE_CURRENT_FCC_MASK		0xe0
+#define CFG_CHARGE_CURRENT_FCC_SHIFT		5
+#define CFG_CHARGE_CURRENT_PCC_MASK		0x18
+#define CFG_CHARGE_CURRENT_PCC_SHIFT		3
+#define CFG_CHARGE_CURRENT_TC_MASK		0x07
+#define CFG_CURRENT_LIMIT			0x01
+#define CFG_CURRENT_LIMIT_DC_MASK		0xf0
+#define CFG_CURRENT_LIMIT_DC_SHIFT		4
+#define CFG_CURRENT_LIMIT_USB_MASK		0x0f
+#define CFG_FLOAT_VOLTAGE			0x03
+#define CFG_FLOAT_VOLTAGE_THRESHOLD_MASK	0xc0
+#define CFG_FLOAT_VOLTAGE_THRESHOLD_SHIFT	6
+#define CFG_STAT				0x05
+#define CFG_STAT_DISABLED			BIT(5)
+#define CFG_STAT_ACTIVE_HIGH			BIT(7)
+#define CFG_PIN					0x06
+#define CFG_PIN_EN_CTRL_MASK			0x60
+#define CFG_PIN_EN_CTRL_ACTIVE_HIGH		0x40
+#define CFG_PIN_EN_CTRL_ACTIVE_LOW		0x60
+#define CFG_PIN_EN_APSD_IRQ			BIT(1)
+#define CFG_PIN_EN_CHARGER_ERROR		BIT(2)
+#define CFG_THERM				0x07
+#define CFG_THERM_SOFT_HOT_COMPENSATION_MASK	0x03
+#define CFG_THERM_SOFT_HOT_COMPENSATION_SHIFT	0
+#define CFG_THERM_SOFT_COLD_COMPENSATION_MASK	0x0c
+#define CFG_THERM_SOFT_COLD_COMPENSATION_SHIFT	2
+#define CFG_THERM_MONITOR_DISABLED		BIT(4)
+#define CFG_SYSOK				0x08
+#define CFG_SYSOK_SUSPEND_HARD_LIMIT_DISABLED	BIT(2)
+#define CFG_OTHER				0x09
+#define CFG_OTHER_RID_MASK			0xc0
+#define CFG_OTHER_RID_ENABLED_AUTO_OTG		0xc0
+#define CFG_OTG					0x0a
+#define CFG_OTG_TEMP_THRESHOLD_MASK		0x30
+#define CFG_OTG_TEMP_THRESHOLD_SHIFT		4
+#define CFG_OTG_CC_COMPENSATION_MASK		0xc0
+#define CFG_OTG_CC_COMPENSATION_SHIFT		6
+#define CFG_TEMP_LIMIT				0x0b
+#define CFG_TEMP_LIMIT_SOFT_HOT_MASK		0x03
+#define CFG_TEMP_LIMIT_SOFT_HOT_SHIFT		0
+#define CFG_TEMP_LIMIT_SOFT_COLD_MASK		0x0c
+#define CFG_TEMP_LIMIT_SOFT_COLD_SHIFT		2
+#define CFG_TEMP_LIMIT_HARD_HOT_MASK		0x30
+#define CFG_TEMP_LIMIT_HARD_HOT_SHIFT		4
+#define CFG_TEMP_LIMIT_HARD_COLD_MASK		0xc0
+#define CFG_TEMP_LIMIT_HARD_COLD_SHIFT		6
+#define CFG_FAULT_IRQ				0x0c
+#define CFG_FAULT_IRQ_DCIN_UV			BIT(2)
+#define CFG_STATUS_IRQ				0x0d
+#define CFG_STATUS_IRQ_TERMINATION_OR_TAPER	BIT(4)
+#define CFG_ADDRESS				0x0e
+
+/* Command registers */
+#define CMD_A					0x30
+#define CMD_A_CHG_ENABLED			BIT(1)
+#define CMD_A_SUSPEND_ENABLED			BIT(2)
+#define CMD_A_ALLOW_WRITE			BIT(7)
+#define CMD_B					0x31
+#define CMD_C					0x33
+
+/* Interrupt Status registers */
+#define IRQSTAT_A				0x35
+#define IRQSTAT_C				0x37
+#define IRQSTAT_C_TERMINATION_STAT		BIT(0)
+#define IRQSTAT_C_TERMINATION_IRQ		BIT(1)
+#define IRQSTAT_C_TAPER_IRQ			BIT(3)
+#define IRQSTAT_E				0x39
+#define IRQSTAT_E_USBIN_UV_STAT			BIT(0)
+#define IRQSTAT_E_USBIN_UV_IRQ			BIT(1)
+#define IRQSTAT_E_DCIN_UV_STAT			BIT(4)
+#define IRQSTAT_E_DCIN_UV_IRQ			BIT(5)
+#define IRQSTAT_F				0x3a
+
+/* Status registers */
+#define STAT_A					0x3b
+#define STAT_A_FLOAT_VOLTAGE_MASK		0x3f
+#define STAT_B					0x3c
+#define STAT_C					0x3d
+#define STAT_C_CHG_ENABLED			BIT(0)
+#define STAT_C_CHG_MASK				0x06
+#define STAT_C_CHG_SHIFT			1
+#define STAT_C_CHARGER_ERROR			BIT(6)
+#define STAT_E					0x3f
+
+/**
+ * struct smb347_charger - smb347 charger instance
+ * @lock: protects concurrent access to online variables
+ * @client: pointer to i2c client
+ * @mains: power_supply instance for AC/DC power
+ * @usb: power_supply instance for USB power
+ * @battery: power_supply instance for battery
+ * @mains_online: is AC/DC input connected
+ * @usb_online: is USB input connected
+ * @charging_enabled: is charging enabled
+ * @dentry: for debugfs
+ * @pdata: pointer to platform data
+ */
+struct smb347_charger {
+	struct mutex		lock;
+	struct i2c_client	*client;
+	struct power_supply	mains;
+	struct power_supply	usb;
+	struct power_supply	battery;
+	bool			mains_online;
+	bool			usb_online;
+	bool			charging_enabled;
+	struct dentry		*dentry;
+	const struct smb347_charger_platform_data *pdata;
+};
+
+/* Fast charge current in uA */
+static const unsigned int fcc_tbl[] = {
+	700000,
+	900000,
+	1200000,
+	1500000,
+	1800000,
+	2000000,
+	2200000,
+	2500000,
+};
+
+/* Pre-charge current in uA */
+static const unsigned int pcc_tbl[] = {
+	100000,
+	150000,
+	200000,
+	250000,
+};
+
+/* Termination current in uA */
+static const unsigned int tc_tbl[] = {
+	37500,
+	50000,
+	100000,
+	150000,
+	200000,
+	250000,
+	500000,
+	600000,
+};
+
+/* Input current limit in uA */
+static const unsigned int icl_tbl[] = {
+	300000,
+	500000,
+	700000,
+	900000,
+	1200000,
+	1500000,
+	1800000,
+	2000000,
+	2200000,
+	2500000,
+};
+
+/* Charge current compensation in uA */
+static const unsigned int ccc_tbl[] = {
+	250000,
+	700000,
+	900000,
+	1200000,
+};
+
+/* Convert register value to current using lookup table */
+static int hw_to_current(const unsigned int *tbl, size_t size, unsigned int val)
+{
+	if (val >= size)
+		return -EINVAL;
+	return tbl[val];
+}
+
+/* Convert current to register value using lookup table */
+static int current_to_hw(const unsigned int *tbl, size_t size, unsigned int val)
+{
+	size_t i;
+
+	for (i = 0; i < size; i++)
+		if (val < tbl[i])
+			break;
+	return i > 0 ? i - 1 : -EINVAL;
+}
+
+static int smb347_read(struct smb347_charger *smb, u8 reg)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(smb->client, reg);
+	if (ret < 0)
+		dev_warn(&smb->client->dev, "failed to read reg 0x%x: %d\n",
+			 reg, ret);
+	return ret;
+}
+
+static int smb347_write(struct smb347_charger *smb, u8 reg, u8 val)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(smb->client, reg, val);
+	if (ret < 0)
+		dev_warn(&smb->client->dev, "failed to write reg 0x%x: %d\n",
+			 reg, ret);
+	return ret;
+}
+
+/**
+ * smb347_update_status - updates the charging status
+ * @smb: pointer to smb347 charger instance
+ *
+ * Function checks status of the charging and updates internal state
+ * accordingly. Returns %0 if there is no change in status, %1 if the
+ * status has changed and negative errno in case of failure.
+ */
+static int smb347_update_status(struct smb347_charger *smb)
+{
+	bool usb = false;
+	bool dc = false;
+	int ret;
+
+	ret = smb347_read(smb, IRQSTAT_E);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Dc and usb are set depending on whether they are enabled in
+	 * platform data _and_ whether corresponding undervoltage is set.
+	 */
+	if (smb->pdata->use_mains)
+		dc = !(ret & IRQSTAT_E_DCIN_UV_STAT);
+	if (smb->pdata->use_usb)
+		usb = !(ret & IRQSTAT_E_USBIN_UV_STAT);
+
+	mutex_lock(&smb->lock);
+	ret = smb->mains_online != dc || smb->usb_online != usb;
+	smb->mains_online = dc;
+	smb->usb_online = usb;
+	mutex_unlock(&smb->lock);
+
+	return ret;
+}
+
+/*
+ * smb347_is_online - returns whether input power source is connected
+ * @smb: pointer to smb347 charger instance
+ *
+ * Returns %true if input power source is connected. Note that this is
+ * dependent on what platform has configured for usable power sources. For
+ * example if USB is disabled, this will return %false even if the USB
+ * cable is connected.
+ */
+static bool smb347_is_online(struct smb347_charger *smb)
+{
+	bool ret;
+
+	mutex_lock(&smb->lock);
+	ret = smb->usb_online || smb->mains_online;
+	mutex_unlock(&smb->lock);
+
+	return ret;
+}
+
+/**
+ * smb347_charging_status - returns status of charging
+ * @smb: pointer to smb347 charger instance
+ *
+ * Function returns charging status. %0 means no charging is in progress,
+ * %1 means pre-charging, %2 fast-charging and %3 taper-charging.
+ */
+static int smb347_charging_status(struct smb347_charger *smb)
+{
+	int ret;
+
+	if (!smb347_is_online(smb))
+		return 0;
+
+	ret = smb347_read(smb, STAT_C);
+	if (ret < 0)
+		return 0;
+
+	return (ret & STAT_C_CHG_MASK) >> STAT_C_CHG_SHIFT;
+}
+
+static int smb347_charging_set(struct smb347_charger *smb, bool enable)
+{
+	int ret = 0;
+
+	if (smb->pdata->enable_control != SMB347_CHG_ENABLE_SW) {
+		dev_dbg(&smb->client->dev,
+			"charging enable/disable in SW disabled\n");
+		return 0;
+	}
+
+	mutex_lock(&smb->lock);
+	if (smb->charging_enabled != enable) {
+		ret = smb347_read(smb, CMD_A);
+		if (ret < 0)
+			goto out;
+
+		smb->charging_enabled = enable;
+
+		if (enable)
+			ret |= CMD_A_CHG_ENABLED;
+		else
+			ret &= ~CMD_A_CHG_ENABLED;
+
+		ret = smb347_write(smb, CMD_A, ret);
+	}
+out:
+	mutex_unlock(&smb->lock);
+	return ret;
+}
+
+static inline int smb347_charging_enable(struct smb347_charger *smb)
+{
+	return smb347_charging_set(smb, true);
+}
+
+static inline int smb347_charging_disable(struct smb347_charger *smb)
+{
+	return smb347_charging_set(smb, false);
+}
+
+static int smb347_update_online(struct smb347_charger *smb)
+{
+	int ret;
+
+	/*
+	 * Depending on whether valid power source is connected or not, we
+	 * disable or enable the charging. We do it manually because it
+	 * depends on how the platform has configured the valid inputs.
+	 */
+	if (smb347_is_online(smb)) {
+		ret = smb347_charging_enable(smb);
+		if (ret < 0)
+			dev_err(&smb->client->dev,
+				"failed to enable charging\n");
+	} else {
+		ret = smb347_charging_disable(smb);
+		if (ret < 0)
+			dev_err(&smb->client->dev,
+				"failed to disable charging\n");
+	}
+
+	return ret;
+}
+
+static int smb347_set_charge_current(struct smb347_charger *smb)
+{
+	int ret, val;
+
+	ret = smb347_read(smb, CFG_CHARGE_CURRENT);
+	if (ret < 0)
+		return ret;
+
+	if (smb->pdata->max_charge_current) {
+		val = current_to_hw(fcc_tbl, ARRAY_SIZE(fcc_tbl),
+				    smb->pdata->max_charge_current);
+		if (val < 0)
+			return val;
+
+		ret &= ~CFG_CHARGE_CURRENT_FCC_MASK;
+		ret |= val << CFG_CHARGE_CURRENT_FCC_SHIFT;
+	}
+
+	if (smb->pdata->pre_charge_current) {
+		val = current_to_hw(pcc_tbl, ARRAY_SIZE(pcc_tbl),
+				    smb->pdata->pre_charge_current);
+		if (val < 0)
+			return val;
+
+		ret &= ~CFG_CHARGE_CURRENT_PCC_MASK;
+		ret |= val << CFG_CHARGE_CURRENT_PCC_SHIFT;
+	}
+
+	if (smb->pdata->termination_current) {
+		val = current_to_hw(tc_tbl, ARRAY_SIZE(tc_tbl),
+				    smb->pdata->termination_current);
+		if (val < 0)
+			return val;
+
+		ret &= ~CFG_CHARGE_CURRENT_TC_MASK;
+		ret |= val;
+	}
+
+	return smb347_write(smb, CFG_CHARGE_CURRENT, ret);
+}
+
+static int smb347_set_current_limits(struct smb347_charger *smb)
+{
+	int ret, val;
+
+	ret = smb347_read(smb, CFG_CURRENT_LIMIT);
+	if (ret < 0)
+		return ret;
+
+	if (smb->pdata->mains_current_limit) {
+		val = current_to_hw(icl_tbl, ARRAY_SIZE(icl_tbl),
+				    smb->pdata->mains_current_limit);
+		if (val < 0)
+			return val;
+
+		ret &= ~CFG_CURRENT_LIMIT_DC_MASK;
+		ret |= val << CFG_CURRENT_LIMIT_DC_SHIFT;
+	}
+
+	if (smb->pdata->usb_hc_current_limit) {
+		val = current_to_hw(icl_tbl, ARRAY_SIZE(icl_tbl),
+				    smb->pdata->usb_hc_current_limit);
+		if (val < 0)
+			return val;
+
+		ret &= ~CFG_CURRENT_LIMIT_USB_MASK;
+		ret |= val;
+	}
+
+	return smb347_write(smb, CFG_CURRENT_LIMIT, ret);
+}
+
+static int smb347_set_voltage_limits(struct smb347_charger *smb)
+{
+	int ret, val;
+
+	ret = smb347_read(smb, CFG_FLOAT_VOLTAGE);
+	if (ret < 0)
+		return ret;
+
+	if (smb->pdata->pre_to_fast_voltage) {
+		val = smb->pdata->pre_to_fast_voltage;
+
+		/* uV */
+		val = clamp_val(val, 2400000, 3000000) - 2400000;
+		val /= 200000;
+
+		ret &= ~CFG_FLOAT_VOLTAGE_THRESHOLD_MASK;
+		ret |= val << CFG_FLOAT_VOLTAGE_THRESHOLD_SHIFT;
+	}
+
+	if (smb->pdata->max_charge_voltage) {
+		val = smb->pdata->max_charge_voltage;
+
+		/* uV */
+		val = clamp_val(val, 3500000, 4500000) - 3500000;
+		val /= 20000;
+
+		ret |= val;
+	}
+
+	return smb347_write(smb, CFG_FLOAT_VOLTAGE, ret);
+}
+
+static int smb347_set_temp_limits(struct smb347_charger *smb)
+{
+	bool enable_therm_monitor = false;
+	int ret, val;
+
+	if (smb->pdata->chip_temp_threshold) {
+		val = smb->pdata->chip_temp_threshold;
+
+		/* degree C */
+		val = clamp_val(val, 100, 130) - 100;
+		val /= 10;
+
+		ret = smb347_read(smb, CFG_OTG);
+		if (ret < 0)
+			return ret;
+
+		ret &= ~CFG_OTG_TEMP_THRESHOLD_MASK;
+		ret |= val << CFG_OTG_TEMP_THRESHOLD_SHIFT;
+
+		ret = smb347_write(smb, CFG_OTG, ret);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = smb347_read(smb, CFG_TEMP_LIMIT);
+	if (ret < 0)
+		return ret;
+
+	if (smb->pdata->soft_cold_temp_limit != SMB347_TEMP_USE_DEFAULT) {
+		val = smb->pdata->soft_cold_temp_limit;
+
+		val = clamp_val(val, 0, 15);
+		val /= 5;
+		/* this goes from higher to lower so invert the value */
+		val = ~val & 0x3;
+
+		ret &= ~CFG_TEMP_LIMIT_SOFT_COLD_MASK;
+		ret |= val << CFG_TEMP_LIMIT_SOFT_COLD_SHIFT;
+
+		enable_therm_monitor = true;
+	}
+
+	if (smb->pdata->soft_hot_temp_limit != SMB347_TEMP_USE_DEFAULT) {
+		val = smb->pdata->soft_hot_temp_limit;
+
+		val = clamp_val(val, 40, 55) - 40;
+		val /= 5;
+
+		ret &= ~CFG_TEMP_LIMIT_SOFT_HOT_MASK;
+		ret |= val << CFG_TEMP_LIMIT_SOFT_HOT_SHIFT;
+
+		enable_therm_monitor = true;
+	}
+
+	if (smb->pdata->hard_cold_temp_limit != SMB347_TEMP_USE_DEFAULT) {
+		val = smb->pdata->hard_cold_temp_limit;
+
+		val = clamp_val(val, -5, 10) + 5;
+		val /= 5;
+		/* this goes from higher to lower so invert the value */
+		val = ~val & 0x3;
+
+		ret &= ~CFG_TEMP_LIMIT_HARD_COLD_MASK;
+		ret |= val << CFG_TEMP_LIMIT_HARD_COLD_SHIFT;
+
+		enable_therm_monitor = true;
+	}
+
+	if (smb->pdata->hard_hot_temp_limit != SMB347_TEMP_USE_DEFAULT) {
+		val = smb->pdata->hard_hot_temp_limit;
+
+		val = clamp_val(val, 50, 65) - 50;
+		val /= 5;
+
+		ret &= ~CFG_TEMP_LIMIT_HARD_HOT_MASK;
+		ret |= val << CFG_TEMP_LIMIT_HARD_HOT_SHIFT;
+
+		enable_therm_monitor = true;
+	}
+
+	ret = smb347_write(smb, CFG_TEMP_LIMIT, ret);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * If any of the temperature limits are set, we also enable the
+	 * thermistor monitoring.
+	 *
+	 * When soft limits are hit, the device will start to compensate
+	 * current and/or voltage depending on the configuration.
+	 *
+	 * When hard limit is hit, the device will suspend charging
+	 * depending on the configuration.
+	 */
+	if (enable_therm_monitor) {
+		ret = smb347_read(smb, CFG_THERM);
+		if (ret < 0)
+			return ret;
+
+		ret &= ~CFG_THERM_MONITOR_DISABLED;
+
+		ret = smb347_write(smb, CFG_THERM, ret);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (smb->pdata->suspend_on_hard_temp_limit) {
+		ret = smb347_read(smb, CFG_SYSOK);
+		if (ret < 0)
+			return ret;
+
+		ret &= ~CFG_SYSOK_SUSPEND_HARD_LIMIT_DISABLED;
+
+		ret = smb347_write(smb, CFG_SYSOK, ret);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (smb->pdata->soft_temp_limit_compensation !=
+	    SMB347_SOFT_TEMP_COMPENSATE_DEFAULT) {
+		val = smb->pdata->soft_temp_limit_compensation & 0x3;
+
+		ret = smb347_read(smb, CFG_THERM);
+		if (ret < 0)
+			return ret;
+
+		ret &= ~CFG_THERM_SOFT_HOT_COMPENSATION_MASK;
+		ret |= val << CFG_THERM_SOFT_HOT_COMPENSATION_SHIFT;
+
+		ret &= ~CFG_THERM_SOFT_COLD_COMPENSATION_MASK;
+		ret |= val << CFG_THERM_SOFT_COLD_COMPENSATION_SHIFT;
+
+		ret = smb347_write(smb, CFG_THERM, ret);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (smb->pdata->charge_current_compensation) {
+		val = current_to_hw(ccc_tbl, ARRAY_SIZE(ccc_tbl),
+				    smb->pdata->charge_current_compensation);
+		if (val < 0)
+			return val;
+
+		ret = smb347_read(smb, CFG_OTG);
+		if (ret < 0)
+			return ret;
+
+		ret &= ~CFG_OTG_CC_COMPENSATION_MASK;
+		ret |= (val & 0x3) << CFG_OTG_CC_COMPENSATION_SHIFT;
+
+		ret = smb347_write(smb, CFG_OTG, ret);
+		if (ret < 0)
+			return ret;
+	}
+
+	return ret;
+}
+
+/*
+ * smb347_set_writable - enables/disables writing to non-volatile registers
+ * @smb: pointer to smb347 charger instance
+ *
+ * You can enable/disable writing to the non-volatile configuration
+ * registers by calling this function.
+ *
+ * Returns %0 on success and negative errno in case of failure.
+ */
+static int smb347_set_writable(struct smb347_charger *smb, bool writable)
+{
+	int ret;
+
+	ret = smb347_read(smb, CMD_A);
+	if (ret < 0)
+		return ret;
+
+	if (writable)
+		ret |= CMD_A_ALLOW_WRITE;
+	else
+		ret &= ~CMD_A_ALLOW_WRITE;
+
+	return smb347_write(smb, CMD_A, ret);
+}
+
+static int smb347_hw_init(struct smb347_charger *smb)
+{
+	int ret;
+
+	ret = smb347_set_writable(smb, true);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Program the platform specific configuration values to the device
+	 * first.
+	 */
+	ret = smb347_set_charge_current(smb);
+	if (ret < 0)
+		goto fail;
+
+	ret = smb347_set_current_limits(smb);
+	if (ret < 0)
+		goto fail;
+
+	ret = smb347_set_voltage_limits(smb);
+	if (ret < 0)
+		goto fail;
+
+	ret = smb347_set_temp_limits(smb);
+	if (ret < 0)
+		goto fail;
+
+	/* If USB charging is disabled we put the USB in suspend mode */
+	if (!smb->pdata->use_usb) {
+		ret = smb347_read(smb, CMD_A);
+		if (ret < 0)
+			goto fail;
+
+		ret |= CMD_A_SUSPEND_ENABLED;
+
+		ret = smb347_write(smb, CMD_A, ret);
+		if (ret < 0)
+			goto fail;
+	}
+
+	ret = smb347_read(smb, CFG_OTHER);
+	if (ret < 0)
+		goto fail;
+
+	/*
+	 * If configured by platform data, we enable hardware Auto-OTG
+	 * support for driving VBUS. Otherwise we disable it.
+	 */
+	ret &= ~CFG_OTHER_RID_MASK;
+	if (smb->pdata->use_usb_otg)
+		ret |= CFG_OTHER_RID_ENABLED_AUTO_OTG;
+
+	ret = smb347_write(smb, CFG_OTHER, ret);
+	if (ret < 0)
+		goto fail;
+
+	ret = smb347_read(smb, CFG_PIN);
+	if (ret < 0)
+		goto fail;
+
+	/*
+	 * Make the charging functionality controllable by a write to the
+	 * command register unless pin control is specified in the platform
+	 * data.
+	 */
+	ret &= ~CFG_PIN_EN_CTRL_MASK;
+
+	switch (smb->pdata->enable_control) {
+	case SMB347_CHG_ENABLE_SW:
+		/* Do nothing, 0 means i2c control */
+		break;
+	case SMB347_CHG_ENABLE_PIN_ACTIVE_LOW:
+		ret |= CFG_PIN_EN_CTRL_ACTIVE_LOW;
+		break;
+	case SMB347_CHG_ENABLE_PIN_ACTIVE_HIGH:
+		ret |= CFG_PIN_EN_CTRL_ACTIVE_HIGH;
+		break;
+	}
+
+	/* Disable Automatic Power Source Detection (APSD) interrupt. */
+	ret &= ~CFG_PIN_EN_APSD_IRQ;
+
+	ret = smb347_write(smb, CFG_PIN, ret);
+	if (ret < 0)
+		goto fail;
+
+	ret = smb347_update_status(smb);
+	if (ret < 0)
+		goto fail;
+
+	ret = smb347_update_online(smb);
+
+fail:
+	smb347_set_writable(smb, false);
+	return ret;
+}
+
+static irqreturn_t smb347_interrupt(int irq, void *data)
+{
+	struct smb347_charger *smb = data;
+	int stat_c, irqstat_e, irqstat_c;
+	irqreturn_t ret = IRQ_NONE;
+
+	stat_c = smb347_read(smb, STAT_C);
+	if (stat_c < 0) {
+		dev_warn(&smb->client->dev, "reading STAT_C failed\n");
+		return IRQ_NONE;
+	}
+
+	irqstat_c = smb347_read(smb, IRQSTAT_C);
+	if (irqstat_c < 0) {
+		dev_warn(&smb->client->dev, "reading IRQSTAT_C failed\n");
+		return IRQ_NONE;
+	}
+
+	irqstat_e = smb347_read(smb, IRQSTAT_E);
+	if (irqstat_e < 0) {
+		dev_warn(&smb->client->dev, "reading IRQSTAT_E failed\n");
+		return IRQ_NONE;
+	}
+
+	/*
+	 * If we get charger error we report the error back to user and
+	 * disable charging.
+	 */
+	if (stat_c & STAT_C_CHARGER_ERROR) {
+		dev_err(&smb->client->dev,
+			"error in charger, disabling charging\n");
+
+		smb347_charging_disable(smb);
+		power_supply_changed(&smb->battery);
+
+		ret = IRQ_HANDLED;
+	}
+
+	/*
+	 * If we reached the termination current the battery is charged and
+	 * we can update the status now. Charging is automatically
+	 * disabled by the hardware.
+	 */
+	if (irqstat_c & (IRQSTAT_C_TERMINATION_IRQ | IRQSTAT_C_TAPER_IRQ)) {
+		if (irqstat_c & IRQSTAT_C_TERMINATION_STAT)
+			power_supply_changed(&smb->battery);
+		ret = IRQ_HANDLED;
+	}
+
+	/*
+	 * If we got an under voltage interrupt it means that AC/USB input
+	 * was connected or disconnected.
+	 */
+	if (irqstat_e & (IRQSTAT_E_USBIN_UV_IRQ | IRQSTAT_E_DCIN_UV_IRQ)) {
+		if (smb347_update_status(smb) > 0) {
+			smb347_update_online(smb);
+			power_supply_changed(&smb->mains);
+			power_supply_changed(&smb->usb);
+		}
+		ret = IRQ_HANDLED;
+	}
+
+	return ret;
+}
+
+static int smb347_irq_set(struct smb347_charger *smb, bool enable)
+{
+	int ret;
+
+	ret = smb347_set_writable(smb, true);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Enable/disable interrupts for:
+	 *	- under voltage
+	 *	- termination current reached
+	 *	- charger error
+	 */
+	if (enable) {
+		ret = smb347_write(smb, CFG_FAULT_IRQ, CFG_FAULT_IRQ_DCIN_UV);
+		if (ret < 0)
+			goto fail;
+
+		ret = smb347_write(smb, CFG_STATUS_IRQ,
+				   CFG_STATUS_IRQ_TERMINATION_OR_TAPER);
+		if (ret < 0)
+			goto fail;
+
+		ret = smb347_read(smb, CFG_PIN);
+		if (ret < 0)
+			goto fail;
+
+		ret |= CFG_PIN_EN_CHARGER_ERROR;
+
+		ret = smb347_write(smb, CFG_PIN, ret);
+	} else {
+		ret = smb347_write(smb, CFG_FAULT_IRQ, 0);
+		if (ret < 0)
+			goto fail;
+
+		ret = smb347_write(smb, CFG_STATUS_IRQ, 0);
+		if (ret < 0)
+			goto fail;
+
+		ret = smb347_read(smb, CFG_PIN);
+		if (ret < 0)
+			goto fail;
+
+		ret &= ~CFG_PIN_EN_CHARGER_ERROR;
+
+		ret = smb347_write(smb, CFG_PIN, ret);
+	}
+
+fail:
+	smb347_set_writable(smb, false);
+	return ret;
+}
+
+static inline int smb347_irq_enable(struct smb347_charger *smb)
+{
+	return smb347_irq_set(smb, true);
+}
+
+static inline int smb347_irq_disable(struct smb347_charger *smb)
+{
+	return smb347_irq_set(smb, false);
+}
+
+static int smb347_irq_init(struct smb347_charger *smb)
+{
+	const struct smb347_charger_platform_data *pdata = smb->pdata;
+	int ret, irq = gpio_to_irq(pdata->irq_gpio);
+
+	ret = gpio_request_one(pdata->irq_gpio, GPIOF_IN, smb->client->name);
+	if (ret < 0)
+		goto fail;
+
+	ret = request_threaded_irq(irq, NULL, smb347_interrupt,
+				   IRQF_TRIGGER_FALLING, smb->client->name,
+				   smb);
+	if (ret < 0)
+		goto fail_gpio;
+
+	ret = smb347_set_writable(smb, true);
+	if (ret < 0)
+		goto fail_irq;
+
+	/*
+	 * Configure the STAT output to be suitable for interrupts: disable
+	 * all other output (except interrupts) and make it active low.
+	 */
+	ret = smb347_read(smb, CFG_STAT);
+	if (ret < 0)
+		goto fail_readonly;
+
+	ret &= ~CFG_STAT_ACTIVE_HIGH;
+	ret |= CFG_STAT_DISABLED;
+
+	ret = smb347_write(smb, CFG_STAT, ret);
+	if (ret < 0)
+		goto fail_readonly;
+
+	ret = smb347_irq_enable(smb);
+	if (ret < 0)
+		goto fail_readonly;
+
+	smb347_set_writable(smb, false);
+	smb->client->irq = irq;
+	return 0;
+
+fail_readonly:
+	smb347_set_writable(smb, false);
+fail_irq:
+	free_irq(irq, smb);
+fail_gpio:
+	gpio_free(pdata->irq_gpio);
+fail:
+	smb->client->irq = 0;
+	return ret;
+}
+
+static int smb347_mains_get_property(struct power_supply *psy,
+				     enum power_supply_property prop,
+				     union power_supply_propval *val)
+{
+	struct smb347_charger *smb =
+		container_of(psy, struct smb347_charger, mains);
+
+	if (prop == POWER_SUPPLY_PROP_ONLINE) {
+		val->intval = smb->mains_online;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static enum power_supply_property smb347_mains_properties[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+};
+
+static int smb347_usb_get_property(struct power_supply *psy,
+				   enum power_supply_property prop,
+				   union power_supply_propval *val)
+{
+	struct smb347_charger *smb =
+		container_of(psy, struct smb347_charger, usb);
+
+	if (prop == POWER_SUPPLY_PROP_ONLINE) {
+		val->intval = smb->usb_online;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static enum power_supply_property smb347_usb_properties[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+};
+
+static int smb347_battery_get_property(struct power_supply *psy,
+				       enum power_supply_property prop,
+				       union power_supply_propval *val)
+{
+	struct smb347_charger *smb =
+			container_of(psy, struct smb347_charger, battery);
+	const struct smb347_charger_platform_data *pdata = smb->pdata;
+	int ret;
+
+	ret = smb347_update_status(smb);
+	if (ret < 0)
+		return ret;
+
+	switch (prop) {
+	case POWER_SUPPLY_PROP_STATUS:
+		if (!smb347_is_online(smb)) {
+			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+			break;
+		}
+		if (smb347_charging_status(smb))
+			val->intval = POWER_SUPPLY_STATUS_CHARGING;
+		else
+			val->intval = POWER_SUPPLY_STATUS_FULL;
+		break;
+
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		if (!smb347_is_online(smb))
+			return -ENODATA;
+
+		/*
+		 * We handle trickle and pre-charging the same, and taper
+		 * and none the same.
+		 */
+		switch (smb347_charging_status(smb)) {
+		case 1:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+			break;
+		case 2:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+			break;
+		default:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+			break;
+		}
+		break;
+
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = pdata->battery_info.technology;
+		break;
+
+	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+		val->intval = pdata->battery_info.voltage_min_design;
+		break;
+
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+		val->intval = pdata->battery_info.voltage_max_design;
+		break;
+
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		if (!smb347_is_online(smb))
+			return -ENODATA;
+		ret = smb347_read(smb, STAT_A);
+		if (ret < 0)
+			return ret;
+
+		ret &= STAT_A_FLOAT_VOLTAGE_MASK;
+		if (ret > 0x3d)
+			ret = 0x3d;
+
+		val->intval = 3500000 + ret * 20000;
+		break;
+
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		if (!smb347_is_online(smb))
+			return -ENODATA;
+
+		ret = smb347_read(smb, STAT_B);
+		if (ret < 0)
+			return ret;
+
+		/*
+		 * The current value is composition of FCC and PCC values
+		 * and we can detect which table to use from bit 5.
+		 */
+		if (ret & 0x20) {
+			val->intval = hw_to_current(fcc_tbl,
+						    ARRAY_SIZE(fcc_tbl),
+						    ret & 7);
+		} else {
+			ret >>= 3;
+			val->intval = hw_to_current(pcc_tbl,
+						    ARRAY_SIZE(pcc_tbl),
+						    ret & 7);
+		}
+		break;
+
+	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+		val->intval = pdata->battery_info.charge_full_design;
+		break;
+
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = pdata->battery_info.name;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static enum power_supply_property smb347_battery_properties[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+};
+
+static int smb347_debugfs_show(struct seq_file *s, void *data)
+{
+	struct smb347_charger *smb = s->private;
+	int ret;
+	u8 reg;
+
+	seq_printf(s, "Control registers:\n");
+	seq_printf(s, "==================\n");
+	for (reg = CFG_CHARGE_CURRENT; reg <= CFG_ADDRESS; reg++) {
+		ret = smb347_read(smb, reg);
+		seq_printf(s, "0x%02x:\t0x%02x\n", reg, ret);
+	}
+	seq_printf(s, "\n");
+
+	seq_printf(s, "Command registers:\n");
+	seq_printf(s, "==================\n");
+	ret = smb347_read(smb, CMD_A);
+	seq_printf(s, "0x%02x:\t0x%02x\n", CMD_A, ret);
+	ret = smb347_read(smb, CMD_B);
+	seq_printf(s, "0x%02x:\t0x%02x\n", CMD_B, ret);
+	ret = smb347_read(smb, CMD_C);
+	seq_printf(s, "0x%02x:\t0x%02x\n", CMD_C, ret);
+	seq_printf(s, "\n");
+
+	seq_printf(s, "Interrupt status registers:\n");
+	seq_printf(s, "===========================\n");
+	for (reg = IRQSTAT_A; reg <= IRQSTAT_F; reg++) {
+		ret = smb347_read(smb, reg);
+		seq_printf(s, "0x%02x:\t0x%02x\n", reg, ret);
+	}
+	seq_printf(s, "\n");
+
+	seq_printf(s, "Status registers:\n");
+	seq_printf(s, "=================\n");
+	for (reg = STAT_A; reg <= STAT_E; reg++) {
+		ret = smb347_read(smb, reg);
+		seq_printf(s, "0x%02x:\t0x%02x\n", reg, ret);
+	}
+
+	return 0;
+}
+
+static int smb347_debugfs_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, smb347_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations smb347_debugfs_fops = {
+	.open		= smb347_debugfs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int smb347_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	static char *battery[] = { "smb347-battery" };
+	const struct smb347_charger_platform_data *pdata;
+	struct device *dev = &client->dev;
+	struct smb347_charger *smb;
+	int ret;
+
+	pdata = dev->platform_data;
+	if (!pdata)
+		return -EINVAL;
+
+	if (!pdata->use_mains && !pdata->use_usb)
+		return -EINVAL;
+
+	smb = devm_kzalloc(dev, sizeof(*smb), GFP_KERNEL);
+	if (!smb)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, smb);
+
+	mutex_init(&smb->lock);
+	smb->client = client;
+	smb->pdata = pdata;
+
+	ret = smb347_hw_init(smb);
+	if (ret < 0)
+		return ret;
+
+	smb->mains.name = "smb347-mains";
+	smb->mains.type = POWER_SUPPLY_TYPE_MAINS;
+	smb->mains.get_property = smb347_mains_get_property;
+	smb->mains.properties = smb347_mains_properties;
+	smb->mains.num_properties = ARRAY_SIZE(smb347_mains_properties);
+	smb->mains.supplied_to = battery;
+	smb->mains.num_supplicants = ARRAY_SIZE(battery);
+
+	smb->usb.name = "smb347-usb";
+	smb->usb.type = POWER_SUPPLY_TYPE_USB;
+	smb->usb.get_property = smb347_usb_get_property;
+	smb->usb.properties = smb347_usb_properties;
+	smb->usb.num_properties = ARRAY_SIZE(smb347_usb_properties);
+	smb->usb.supplied_to = battery;
+	smb->usb.num_supplicants = ARRAY_SIZE(battery);
+
+	smb->battery.name = "smb347-battery";
+	smb->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+	smb->battery.get_property = smb347_battery_get_property;
+	smb->battery.properties = smb347_battery_properties;
+	smb->battery.num_properties = ARRAY_SIZE(smb347_battery_properties);
+
+	ret = power_supply_register(dev, &smb->mains);
+	if (ret < 0)
+		return ret;
+
+	ret = power_supply_register(dev, &smb->usb);
+	if (ret < 0) {
+		power_supply_unregister(&smb->mains);
+		return ret;
+	}
+
+	ret = power_supply_register(dev, &smb->battery);
+	if (ret < 0) {
+		power_supply_unregister(&smb->usb);
+		power_supply_unregister(&smb->mains);
+		return ret;
+	}
+
+	/*
+	 * Interrupt pin is optional. If it is connected, we setup the
+	 * interrupt support here.
+	 */
+	if (pdata->irq_gpio >= 0) {
+		ret = smb347_irq_init(smb);
+		if (ret < 0) {
+			dev_warn(dev, "failed to initialize IRQ: %d\n", ret);
+			dev_warn(dev, "disabling IRQ support\n");
+		}
+	}
+
+	smb->dentry = debugfs_create_file("smb347-regs", S_IRUSR, NULL, smb,
+					  &smb347_debugfs_fops);
+	return 0;
+}
+
+static int smb347_remove(struct i2c_client *client)
+{
+	struct smb347_charger *smb = i2c_get_clientdata(client);
+
+	if (!IS_ERR_OR_NULL(smb->dentry))
+		debugfs_remove(smb->dentry);
+
+	if (client->irq) {
+		smb347_irq_disable(smb);
+		free_irq(client->irq, smb);
+		gpio_free(smb->pdata->irq_gpio);
+	}
+
+	power_supply_unregister(&smb->battery);
+	power_supply_unregister(&smb->usb);
+	power_supply_unregister(&smb->mains);
+	return 0;
+}
+
+static const struct i2c_device_id smb347_id[] = {
+	{ "smb347", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, smb347_id);
+
+static struct i2c_driver smb347_driver = {
+	.driver = {
+		.name = "smb347",
+	},
+	.probe        = smb347_probe,
+	.remove       = __devexit_p(smb347_remove),
+	.id_table     = smb347_id,
+};
+
+static int __init smb347_init(void)
+{
+	return i2c_add_driver(&smb347_driver);
+}
+module_init(smb347_init);
+
+static void __exit smb347_exit(void)
+{
+	i2c_del_driver(&smb347_driver);
+}
+module_exit(smb347_exit);
+
+MODULE_AUTHOR("Bruce E. Robertson <bruce.e.robertson@intel.com>");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
+MODULE_DESCRIPTION("SMB347 battery charger driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("i2c:smb347");
diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c
index 636ebb2..8c9a607 100644
--- a/drivers/power/z2_battery.c
+++ b/drivers/power/z2_battery.c
@@ -316,19 +316,7 @@
 	.remove		= __devexit_p(z2_batt_remove),
 	.id_table	= z2_batt_id,
 };
-
-static int __init z2_batt_init(void)
-{
-	return i2c_add_driver(&z2_batt_driver);
-}
-
-static void __exit z2_batt_exit(void)
-{
-	i2c_del_driver(&z2_batt_driver);
-}
-
-module_init(z2_batt_init);
-module_exit(z2_batt_exit);
+module_i2c_driver(z2_batt_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Peter Edwards <sweetlilmre@gmail.com>");
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index a229de9..36db5a4 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -258,14 +258,6 @@
 	  This driver supports the voltage domain regulators controlled by the
 	  DB8500 PRCMU
 
-config REGULATOR_BQ24022
-	tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC"
-	help
-	  This driver controls a TI bq24022 Charger attached via
-	  GPIOs. The provided current regulator can enable/disable
-	  charging select between 100 mA and 500 mA charging current
-	  limit.
-
 config REGULATOR_TPS6105X
 	tristate "TI TPS6105X Power regulators"
 	depends on TPS6105X
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index b5042c8..94b5274 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -16,7 +16,6 @@
 obj-$(CONFIG_REGULATOR_AB8500)	+= ab8500.o
 obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
 obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
-obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
 obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o
 obj-$(CONFIG_REGULATOR_DA9052)	+= da9052-regulator.o
 obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index 17499a5..53969af 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -138,9 +138,10 @@
 	rdesc->type = REGULATOR_VOLTAGE;
 	rdesc->owner = THIS_MODULE;
 	sreg->mfd = anatopmfd;
-	ret = of_property_read_u32(np, "reg", &sreg->control_reg);
+	ret = of_property_read_u32(np, "anatop-reg-offset",
+				   &sreg->control_reg);
 	if (ret) {
-		dev_err(dev, "no reg property set\n");
+		dev_err(dev, "no anatop-reg-offset property set\n");
 		goto anatop_probe_end;
 	}
 	ret = of_property_read_u32(np, "anatop-vol-bit-width",
diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c
deleted file mode 100644
index 9fab6d1..0000000
--- a/drivers/regulator/bq24022.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Support for TI bq24022 (bqTINY-II) Dual Input (USB/AC Adpater)
- * 1-Cell Li-Ion Charger connected via GPIOs.
- *
- * Copyright (c) 2008 Philipp Zabel
- *
- * 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/platform_device.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/gpio.h>
-#include <linux/regulator/bq24022.h>
-#include <linux/regulator/driver.h>
-
-
-static int bq24022_set_current_limit(struct regulator_dev *rdev,
-					int min_uA, int max_uA)
-{
-	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
-
-	dev_dbg(rdev_get_dev(rdev), "setting current limit to %s mA\n",
-		max_uA >= 500000 ? "500" : "100");
-
-	/* REVISIT: maybe return error if min_uA != 0 ? */
-	gpio_set_value(pdata->gpio_iset2, max_uA >= 500000);
-	return 0;
-}
-
-static int bq24022_get_current_limit(struct regulator_dev *rdev)
-{
-	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
-
-	return gpio_get_value(pdata->gpio_iset2) ? 500000 : 100000;
-}
-
-static int bq24022_enable(struct regulator_dev *rdev)
-{
-	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
-
-	dev_dbg(rdev_get_dev(rdev), "enabling charger\n");
-
-	gpio_set_value(pdata->gpio_nce, 0);
-	return 0;
-}
-
-static int bq24022_disable(struct regulator_dev *rdev)
-{
-	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
-
-	dev_dbg(rdev_get_dev(rdev), "disabling charger\n");
-
-	gpio_set_value(pdata->gpio_nce, 1);
-	return 0;
-}
-
-static int bq24022_is_enabled(struct regulator_dev *rdev)
-{
-	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
-
-	return !gpio_get_value(pdata->gpio_nce);
-}
-
-static struct regulator_ops bq24022_ops = {
-	.set_current_limit = bq24022_set_current_limit,
-	.get_current_limit = bq24022_get_current_limit,
-	.enable            = bq24022_enable,
-	.disable           = bq24022_disable,
-	.is_enabled        = bq24022_is_enabled,
-};
-
-static struct regulator_desc bq24022_desc = {
-	.name  = "bq24022",
-	.ops   = &bq24022_ops,
-	.type  = REGULATOR_CURRENT,
-	.owner = THIS_MODULE,
-};
-
-static int __init bq24022_probe(struct platform_device *pdev)
-{
-	struct bq24022_mach_info *pdata = pdev->dev.platform_data;
-	struct regulator_dev *bq24022;
-	int ret;
-
-	if (!pdata || !pdata->gpio_nce || !pdata->gpio_iset2)
-		return -EINVAL;
-
-	ret = gpio_request(pdata->gpio_nce, "ncharge_en");
-	if (ret) {
-		dev_dbg(&pdev->dev, "couldn't request nCE GPIO: %d\n",
-			pdata->gpio_nce);
-		goto err_ce;
-	}
-	ret = gpio_request(pdata->gpio_iset2, "charge_mode");
-	if (ret) {
-		dev_dbg(&pdev->dev, "couldn't request ISET2 GPIO: %d\n",
-			pdata->gpio_iset2);
-		goto err_iset2;
-	}
-	ret = gpio_direction_output(pdata->gpio_iset2, 0);
-	ret = gpio_direction_output(pdata->gpio_nce, 1);
-
-	bq24022 = regulator_register(&bq24022_desc, &pdev->dev,
-				     pdata->init_data, pdata, NULL);
-	if (IS_ERR(bq24022)) {
-		dev_dbg(&pdev->dev, "couldn't register regulator\n");
-		ret = PTR_ERR(bq24022);
-		goto err_reg;
-	}
-	platform_set_drvdata(pdev, bq24022);
-	dev_dbg(&pdev->dev, "registered regulator\n");
-
-	return 0;
-err_reg:
-	gpio_free(pdata->gpio_iset2);
-err_iset2:
-	gpio_free(pdata->gpio_nce);
-err_ce:
-	return ret;
-}
-
-static int __devexit bq24022_remove(struct platform_device *pdev)
-{
-	struct bq24022_mach_info *pdata = pdev->dev.platform_data;
-	struct regulator_dev *bq24022 = platform_get_drvdata(pdev);
-
-	regulator_unregister(bq24022);
-	gpio_free(pdata->gpio_iset2);
-	gpio_free(pdata->gpio_nce);
-
-	return 0;
-}
-
-static struct platform_driver bq24022_driver = {
-	.driver = {
-		.name = "bq24022",
-	},
-	.remove = __devexit_p(bq24022_remove),
-};
-
-static int __init bq24022_init(void)
-{
-	return platform_driver_probe(&bq24022_driver, bq24022_probe);
-}
-
-static void __exit bq24022_exit(void)
-{
-	platform_driver_unregister(&bq24022_driver);
-}
-
-module_init(bq24022_init);
-module_exit(bq24022_exit);
-
-MODULE_AUTHOR("Philipp Zabel");
-MODULE_DESCRIPTION("TI bq24022 Li-Ion Charger driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index c056abd..e70dd38 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2992,14 +2992,14 @@
 	if (rdev == NULL)
 		return;
 
+	if (rdev->supply)
+		regulator_put(rdev->supply);
 	mutex_lock(&regulator_list_mutex);
 	debugfs_remove_recursive(rdev->debugfs);
 	flush_work_sync(&rdev->disable_work.work);
 	WARN_ON(rdev->open_count);
 	unset_regulator_supplies(rdev);
 	list_del(&rdev->list);
-	if (rdev->supply)
-		regulator_put(rdev->supply);
 	kfree(rdev->constraints);
 	device_unregister(&rdev->dev);
 	mutex_unlock(&regulator_list_mutex);
diff --git a/drivers/regulator/fixed-helper.c b/drivers/regulator/fixed-helper.c
index 30d0a15..cacd33c 100644
--- a/drivers/regulator/fixed-helper.c
+++ b/drivers/regulator/fixed-helper.c
@@ -18,7 +18,6 @@
 
 /**
  * regulator_register_fixed - register a no-op fixed regulator
- * @name: supply name
  * @id: platform device id
  * @supplies: consumers for this regulator
  * @num_supplies: number of consumers
@@ -32,7 +31,7 @@
 	if (!data)
 		return NULL;
 
-	data->cfg.supply_name = "dummy";
+	data->cfg.supply_name = "fixed-dummy";
 	data->cfg.microvolts = 0;
 	data->cfg.gpio = -EINVAL;
 	data->cfg.enabled_at_boot = 1;
diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
index e8cfc99..845aa22 100644
--- a/drivers/regulator/mc13892-regulator.c
+++ b/drivers/regulator/mc13892-regulator.c
@@ -552,7 +552,7 @@
 	mc13xxx_lock(mc13892);
 	ret = mc13xxx_reg_read(mc13892, MC13892_REVISION, &val);
 	if (ret)
-		goto err_free;
+		goto err_unlock;
 
 	/* enable switch auto mode */
 	if ((val & 0x0000FFFF) == 0x45d0) {
@@ -562,7 +562,7 @@
 			MC13892_SWITCHERS4_SW1MODE_AUTO |
 			MC13892_SWITCHERS4_SW2MODE_AUTO);
 		if (ret)
-			goto err_free;
+			goto err_unlock;
 
 		ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5,
 			MC13892_SWITCHERS5_SW3MODE_M |
@@ -570,7 +570,7 @@
 			MC13892_SWITCHERS5_SW3MODE_AUTO |
 			MC13892_SWITCHERS5_SW4MODE_AUTO);
 		if (ret)
-			goto err_free;
+			goto err_unlock;
 	}
 	mc13xxx_unlock(mc13892);
 
@@ -612,10 +612,10 @@
 err:
 	while (--i >= 0)
 		regulator_unregister(priv->regulators[i]);
+	return ret;
 
-err_free:
+err_unlock:
 	mc13xxx_unlock(mc13892);
-
 	return ret;
 }
 
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index 58447db..4ca2db0 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -311,8 +311,7 @@
 	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
 	const struct s5m_voltage_desc *desc;
 	int reg_id = rdev_get_id(rdev);
-	int reg, mask, ret;
-	int i;
+	int sel, reg, mask, ret;
 	u8 val;
 
 	switch (reg_id) {
@@ -333,19 +332,20 @@
 
 	desc = reg_voltage_map[reg_id];
 
-	i = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV);
-	if (i < 0)
-		return i;
+	sel = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV);
+	if (sel < 0)
+		return sel;
 
 	ret = s5m8767_get_voltage_register(rdev, &reg);
 	if (ret)
 		return ret;
 
 	s5m_reg_read(s5m8767->iodev, reg, &val);
-	val = val & mask;
+	val &= ~mask;
+	val |= sel;
 
 	ret = s5m_reg_write(s5m8767->iodev, reg, val);
-	*selector = i;
+	*selector = sel;
 
 	return ret;
 }
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index 29b615c..cfc1f16 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -79,6 +79,11 @@
 				     unsigned selector)
 {
 	struct tps6586x_regulator *info = rdev_get_drvdata(rdev);
+	int rid = rdev_get_id(rdev);
+
+	/* LDO0 has minimal voltage 1.2V rather than 1.25V */
+	if ((rid == TPS6586X_ID_LDO_0) && (selector == 0))
+		return (info->voltages[0] - 50) * 1000;
 
 	return info->voltages[selector] * 1000;
 }
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index 4904a40..ff810e7 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -380,13 +380,15 @@
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(wm831x_dcdc_ilim); i++) {
-		if (max_uA <= wm831x_dcdc_ilim[i])
+		if ((min_uA <= wm831x_dcdc_ilim[i]) &&
+		    (wm831x_dcdc_ilim[i] <= max_uA))
 			break;
 	}
 	if (i == ARRAY_SIZE(wm831x_dcdc_ilim))
 		return -EINVAL;
 
-	return wm831x_set_bits(wm831x, reg, WM831X_DC1_HC_THR_MASK, i);
+	return wm831x_set_bits(wm831x, reg, WM831X_DC1_HC_THR_MASK,
+			       i << WM831X_DC1_HC_THR_SHIFT);
 }
 
 static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev)
@@ -400,7 +402,8 @@
 	if (val < 0)
 		return val;
 
-	return wm831x_dcdc_ilim[val & WM831X_DC1_HC_THR_MASK];
+	val = (val & WM831X_DC1_HC_THR_MASK) >> WM831X_DC1_HC_THR_SHIFT;
+	return wm831x_dcdc_ilim[val];
 }
 
 static struct regulator_ops wm831x_buckv_ops = {
diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c
index 634aac3..b414e09 100644
--- a/drivers/regulator/wm831x-isink.c
+++ b/drivers/regulator/wm831x-isink.c
@@ -101,7 +101,7 @@
 
 	for (i = 0; i < ARRAY_SIZE(wm831x_isinkv_values); i++) {
 		int val = wm831x_isinkv_values[i];
-		if (min_uA >= val && val <= max_uA) {
+		if (min_uA <= val && val <= max_uA) {
 			ret = wm831x_set_bits(wm831x, isink->reg,
 					      WM831X_CS1_ISEL_MASK, i);
 			return ret;
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index f1e4ab0..641e9f6 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -506,22 +506,19 @@
 {
 	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
 	struct wm831x *wm831x = ldo->wm831x;
-	int ctrl_reg = ldo->base + WM831X_LDO_CONTROL;
 	int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
 	int ret;
 
 
 	switch (mode) {
 	case REGULATOR_MODE_NORMAL:
-		ret = wm831x_set_bits(wm831x, on_reg,
-				      WM831X_LDO7_ON_MODE, 0);
+		ret = wm831x_set_bits(wm831x, on_reg, WM831X_LDO7_ON_MODE, 0);
 		if (ret < 0)
 			return ret;
 		break;
 
 	case REGULATOR_MODE_IDLE:
-		ret = wm831x_set_bits(wm831x, ctrl_reg,
-				      WM831X_LDO7_ON_MODE,
+		ret = wm831x_set_bits(wm831x, on_reg, WM831X_LDO7_ON_MODE,
 				      WM831X_LDO7_ON_MODE);
 		if (ret < 0)
 			return ret;
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index ab1e183..05ecfb8 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -99,7 +99,7 @@
 {
 	int i;
 
-	for (i = ARRAY_SIZE(isink_cur) - 1; i >= 0; i--) {
+	for (i = 0; i < ARRAY_SIZE(isink_cur); i++) {
 		if (min_uA <= isink_cur[i] && max_uA >= isink_cur[i]) {
 			*setting = i;
 			return 0;
@@ -186,7 +186,7 @@
 		return 0;
 	}
 
-	return DIV_ROUND_CLOSEST(isink_cur[val], 100);
+	return isink_cur[val];
 }
 
 /* turn on ISINK followed by DCDC */
@@ -495,25 +495,25 @@
 		val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER)
 			& ~WM8350_DCDC_HIB_MODE_MASK;
 		wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
-			wm8350->pmic.dcdc1_hib_mode);
+			val | wm8350->pmic.dcdc1_hib_mode);
 		break;
 	case WM8350_DCDC_3:
 		val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER)
 			& ~WM8350_DCDC_HIB_MODE_MASK;
 		wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
-			wm8350->pmic.dcdc3_hib_mode);
+			val | wm8350->pmic.dcdc3_hib_mode);
 		break;
 	case WM8350_DCDC_4:
 		val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER)
 			& ~WM8350_DCDC_HIB_MODE_MASK;
 		wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
-			wm8350->pmic.dcdc4_hib_mode);
+			val | wm8350->pmic.dcdc4_hib_mode);
 		break;
 	case WM8350_DCDC_6:
 		val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER)
 			& ~WM8350_DCDC_HIB_MODE_MASK;
 		wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
-			wm8350->pmic.dcdc6_hib_mode);
+			val | wm8350->pmic.dcdc6_hib_mode);
 		break;
 	case WM8350_DCDC_2:
 	case WM8350_DCDC_5:
@@ -535,25 +535,25 @@
 		val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
 		wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
 		wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
-			WM8350_DCDC_HIB_MODE_DIS);
+				 val | WM8350_DCDC_HIB_MODE_DIS);
 		break;
 	case WM8350_DCDC_3:
 		val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
 		wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
 		wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
-			WM8350_DCDC_HIB_MODE_DIS);
+				 val | WM8350_DCDC_HIB_MODE_DIS);
 		break;
 	case WM8350_DCDC_4:
 		val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
 		wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
 		wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
-			WM8350_DCDC_HIB_MODE_DIS);
+				 val | WM8350_DCDC_HIB_MODE_DIS);
 		break;
 	case WM8350_DCDC_6:
 		val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
 		wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
 		wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
-			WM8350_DCDC_HIB_MODE_DIS);
+				 val | WM8350_DCDC_HIB_MODE_DIS);
 		break;
 	case WM8350_DCDC_2:
 	case WM8350_DCDC_5:
@@ -575,13 +575,13 @@
 		val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
 		    & ~WM8350_DC2_HIB_MODE_MASK;
 		wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
-				 WM8350_DC2_HIB_MODE_ACTIVE);
+		    (WM8350_DC2_HIB_MODE_ACTIVE << WM8350_DC2_HIB_MODE_SHIFT));
 		break;
 	case WM8350_DCDC_5:
 		val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
-		    & ~WM8350_DC2_HIB_MODE_MASK;
+		    & ~WM8350_DC5_HIB_MODE_MASK;
 		wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
-				 WM8350_DC5_HIB_MODE_ACTIVE);
+		    (WM8350_DC5_HIB_MODE_ACTIVE << WM8350_DC5_HIB_MODE_SHIFT));
 		break;
 	default:
 		return -EINVAL;
@@ -600,13 +600,13 @@
 		val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
 		    & ~WM8350_DC2_HIB_MODE_MASK;
 		wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
-				 WM8350_DC2_HIB_MODE_DISABLE);
+		    (WM8350_DC2_HIB_MODE_DISABLE << WM8350_DC2_HIB_MODE_SHIFT));
 		break;
 	case WM8350_DCDC_5:
 		val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
-		    & ~WM8350_DC2_HIB_MODE_MASK;
+		    & ~WM8350_DC5_HIB_MODE_MASK;
 		wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
-				 WM8350_DC2_HIB_MODE_DISABLE);
+		    (WM8350_DC5_HIB_MODE_DISABLE << WM8350_DC5_HIB_MODE_SHIFT));
 		break;
 	default:
 		return -EINVAL;
@@ -749,7 +749,7 @@
 
 	/* all LDOs have same mV bits */
 	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK;
-	wm8350_reg_write(wm8350, volt_reg, WM8350_LDO1_HIB_MODE_DIS);
+	wm8350_reg_write(wm8350, volt_reg, val | WM8350_LDO1_HIB_MODE_DIS);
 	return 0;
 }
 
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
new file mode 100644
index 0000000..24d880e
--- /dev/null
+++ b/drivers/remoteproc/Kconfig
@@ -0,0 +1,28 @@
+menu "Remoteproc drivers (EXPERIMENTAL)"
+
+# REMOTEPROC gets selected by whoever wants it
+config REMOTEPROC
+	tristate
+	depends on EXPERIMENTAL
+
+config OMAP_REMOTEPROC
+	tristate "OMAP remoteproc support"
+	depends on ARCH_OMAP4
+	depends on OMAP_IOMMU
+	select REMOTEPROC
+	select OMAP_MBOX_FWK
+	select RPMSG
+	help
+	  Say y here to support OMAP's remote processors (dual M3
+	  and DSP on OMAP4) via the remote processor framework.
+
+	  Currently only supported on OMAP4.
+
+	  Usually you want to say y here, in order to enable multimedia
+	  use-cases to run on your platform (multimedia codecs are
+	  offloaded to remote DSP processors using this framework).
+
+	  It's safe to say n here if you're not interested in multimedia
+	  offloading or just want a bare minimum kernel.
+
+endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
new file mode 100644
index 0000000..5445d9b
--- /dev/null
+++ b/drivers/remoteproc/Makefile
@@ -0,0 +1,9 @@
+#
+# Generic framework for controlling remote processors
+#
+
+obj-$(CONFIG_REMOTEPROC)		+= remoteproc.o
+remoteproc-y				:= remoteproc_core.o
+remoteproc-y				+= remoteproc_debugfs.o
+remoteproc-y				+= remoteproc_virtio.o
+obj-$(CONFIG_OMAP_REMOTEPROC)		+= omap_remoteproc.o
diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c
new file mode 100644
index 0000000..69425c4
--- /dev/null
+++ b/drivers/remoteproc/omap_remoteproc.c
@@ -0,0 +1,229 @@
+/*
+ * OMAP Remote Processor driver
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ * Fernando Guzman Lugo <fernando.lugo@ti.com>
+ * Mark Grosen <mgrosen@ti.com>
+ * Suman Anna <s-anna@ti.com>
+ * Hari Kanigeri <h-kanigeri2@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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/remoteproc.h>
+
+#include <plat/mailbox.h>
+#include <plat/remoteproc.h>
+
+#include "omap_remoteproc.h"
+#include "remoteproc_internal.h"
+
+/**
+ * struct omap_rproc - omap remote processor state
+ * @mbox: omap mailbox handle
+ * @nb: notifier block that will be invoked on inbound mailbox messages
+ * @rproc: rproc handle
+ */
+struct omap_rproc {
+	struct omap_mbox *mbox;
+	struct notifier_block nb;
+	struct rproc *rproc;
+};
+
+/**
+ * omap_rproc_mbox_callback() - inbound mailbox message handler
+ * @this: notifier block
+ * @index: unused
+ * @data: mailbox payload
+ *
+ * This handler is invoked by omap's mailbox driver whenever a mailbox
+ * message is received. Usually, the mailbox payload simply contains
+ * the index of the virtqueue that is kicked by the remote processor,
+ * and we let remoteproc core handle it.
+ *
+ * In addition to virtqueue indices, we also have some out-of-band values
+ * that indicates different events. Those values are deliberately very
+ * big so they don't coincide with virtqueue indices.
+ */
+static int omap_rproc_mbox_callback(struct notifier_block *this,
+					unsigned long index, void *data)
+{
+	mbox_msg_t msg = (mbox_msg_t) data;
+	struct omap_rproc *oproc = container_of(this, struct omap_rproc, nb);
+	struct device *dev = oproc->rproc->dev;
+	const char *name = oproc->rproc->name;
+
+	dev_dbg(dev, "mbox msg: 0x%x\n", msg);
+
+	switch (msg) {
+	case RP_MBOX_CRASH:
+		/* just log this for now. later, we'll also do recovery */
+		dev_err(dev, "omap rproc %s crashed\n", name);
+		break;
+	case RP_MBOX_ECHO_REPLY:
+		dev_info(dev, "received echo reply from %s\n", name);
+		break;
+	default:
+		/* msg contains the index of the triggered vring */
+		if (rproc_vq_interrupt(oproc->rproc, msg) == IRQ_NONE)
+			dev_dbg(dev, "no message was found in vqid %d\n", msg);
+	}
+
+	return NOTIFY_DONE;
+}
+
+/* kick a virtqueue */
+static void omap_rproc_kick(struct rproc *rproc, int vqid)
+{
+	struct omap_rproc *oproc = rproc->priv;
+	int ret;
+
+	/* send the index of the triggered virtqueue in the mailbox payload */
+	ret = omap_mbox_msg_send(oproc->mbox, vqid);
+	if (ret)
+		dev_err(rproc->dev, "omap_mbox_msg_send failed: %d\n", ret);
+}
+
+/*
+ * Power up the remote processor.
+ *
+ * This function will be invoked only after the firmware for this rproc
+ * was loaded, parsed successfully, and all of its resource requirements
+ * were met.
+ */
+static int omap_rproc_start(struct rproc *rproc)
+{
+	struct omap_rproc *oproc = rproc->priv;
+	struct platform_device *pdev = to_platform_device(rproc->dev);
+	struct omap_rproc_pdata *pdata = pdev->dev.platform_data;
+	int ret;
+
+	oproc->nb.notifier_call = omap_rproc_mbox_callback;
+
+	/* every omap rproc is assigned a mailbox instance for messaging */
+	oproc->mbox = omap_mbox_get(pdata->mbox_name, &oproc->nb);
+	if (IS_ERR(oproc->mbox)) {
+		ret = PTR_ERR(oproc->mbox);
+		dev_err(rproc->dev, "omap_mbox_get failed: %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * Ping the remote processor. this is only for sanity-sake;
+	 * there is no functional effect whatsoever.
+	 *
+	 * Note that the reply will _not_ arrive immediately: this message
+	 * will wait in the mailbox fifo until the remote processor is booted.
+	 */
+	ret = omap_mbox_msg_send(oproc->mbox, RP_MBOX_ECHO_REQUEST);
+	if (ret) {
+		dev_err(rproc->dev, "omap_mbox_get failed: %d\n", ret);
+		goto put_mbox;
+	}
+
+	ret = pdata->device_enable(pdev);
+	if (ret) {
+		dev_err(rproc->dev, "omap_device_enable failed: %d\n", ret);
+		goto put_mbox;
+	}
+
+	return 0;
+
+put_mbox:
+	omap_mbox_put(oproc->mbox, &oproc->nb);
+	return ret;
+}
+
+/* power off the remote processor */
+static int omap_rproc_stop(struct rproc *rproc)
+{
+	struct platform_device *pdev = to_platform_device(rproc->dev);
+	struct omap_rproc_pdata *pdata = pdev->dev.platform_data;
+	struct omap_rproc *oproc = rproc->priv;
+	int ret;
+
+	ret = pdata->device_shutdown(pdev);
+	if (ret)
+		return ret;
+
+	omap_mbox_put(oproc->mbox, &oproc->nb);
+
+	return 0;
+}
+
+static struct rproc_ops omap_rproc_ops = {
+	.start		= omap_rproc_start,
+	.stop		= omap_rproc_stop,
+	.kick		= omap_rproc_kick,
+};
+
+static int __devinit omap_rproc_probe(struct platform_device *pdev)
+{
+	struct omap_rproc_pdata *pdata = pdev->dev.platform_data;
+	struct omap_rproc *oproc;
+	struct rproc *rproc;
+	int ret;
+
+	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+	if (ret) {
+		dev_err(pdev->dev.parent, "dma_set_coherent_mask: %d\n", ret);
+		return ret;
+	}
+
+	rproc = rproc_alloc(&pdev->dev, pdata->name, &omap_rproc_ops,
+				pdata->firmware, sizeof(*oproc));
+	if (!rproc)
+		return -ENOMEM;
+
+	oproc = rproc->priv;
+	oproc->rproc = rproc;
+
+	platform_set_drvdata(pdev, rproc);
+
+	ret = rproc_register(rproc);
+	if (ret)
+		goto free_rproc;
+
+	return 0;
+
+free_rproc:
+	rproc_free(rproc);
+	return ret;
+}
+
+static int __devexit omap_rproc_remove(struct platform_device *pdev)
+{
+	struct rproc *rproc = platform_get_drvdata(pdev);
+
+	return rproc_unregister(rproc);
+}
+
+static struct platform_driver omap_rproc_driver = {
+	.probe = omap_rproc_probe,
+	.remove = __devexit_p(omap_rproc_remove),
+	.driver = {
+		.name = "omap-rproc",
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(omap_rproc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("OMAP Remote Processor control driver");
diff --git a/drivers/remoteproc/omap_remoteproc.h b/drivers/remoteproc/omap_remoteproc.h
new file mode 100644
index 0000000..f6d2036
--- /dev/null
+++ b/drivers/remoteproc/omap_remoteproc.h
@@ -0,0 +1,69 @@
+/*
+ * Remote processor messaging
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name Texas Instruments nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _OMAP_RPMSG_H
+#define _OMAP_RPMSG_H
+
+/*
+ * enum - Predefined Mailbox Messages
+ *
+ * @RP_MBOX_READY: informs the M3's that we're up and running. this is
+ * part of the init sequence sent that the M3 expects to see immediately
+ * after it is booted.
+ *
+ * @RP_MBOX_PENDING_MSG: informs the receiver that there is an inbound
+ * message waiting in its own receive-side vring. please note that currently
+ * this message is optional: alternatively, one can explicitly send the index
+ * of the triggered virtqueue itself. the preferred approach will be decided
+ * as we progress and experiment with those two different approaches.
+ *
+ * @RP_MBOX_CRASH: this message is sent if BIOS crashes
+ *
+ * @RP_MBOX_ECHO_REQUEST: a mailbox-level "ping" message.
+ *
+ * @RP_MBOX_ECHO_REPLY: a mailbox-level reply to a "ping"
+ *
+ * @RP_MBOX_ABORT_REQUEST: a "please crash" request, used for testing the
+ * recovery mechanism (to some extent).
+ */
+enum omap_rp_mbox_messages {
+	RP_MBOX_READY		= 0xFFFFFF00,
+	RP_MBOX_PENDING_MSG	= 0xFFFFFF01,
+	RP_MBOX_CRASH		= 0xFFFFFF02,
+	RP_MBOX_ECHO_REQUEST	= 0xFFFFFF03,
+	RP_MBOX_ECHO_REPLY	= 0xFFFFFF04,
+	RP_MBOX_ABORT_REQUEST	= 0xFFFFFF05,
+};
+
+#endif /* _OMAP_RPMSG_H */
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
new file mode 100644
index 0000000..ee15c68
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -0,0 +1,1586 @@
+/*
+ * Remote Processor Framework
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ * Mark Grosen <mgrosen@ti.com>
+ * Fernando Guzman Lugo <fernando.lugo@ti.com>
+ * Suman Anna <s-anna@ti.com>
+ * Robert Tivy <rtivy@ti.com>
+ * Armando Uribe De Leon <x0095078@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.
+ */
+
+#define pr_fmt(fmt)    "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/string.h>
+#include <linux/debugfs.h>
+#include <linux/remoteproc.h>
+#include <linux/iommu.h>
+#include <linux/klist.h>
+#include <linux/elf.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_ring.h>
+#include <asm/byteorder.h>
+
+#include "remoteproc_internal.h"
+
+static void klist_rproc_get(struct klist_node *n);
+static void klist_rproc_put(struct klist_node *n);
+
+/*
+ * klist of the available remote processors.
+ *
+ * We need this in order to support name-based lookups (needed by the
+ * rproc_get_by_name()).
+ *
+ * That said, we don't use rproc_get_by_name() at this point.
+ * The use cases that do require its existence should be
+ * scrutinized, and hopefully migrated to rproc_boot() using device-based
+ * binding.
+ *
+ * If/when this materializes, we could drop the klist (and the by_name
+ * API).
+ */
+static DEFINE_KLIST(rprocs, klist_rproc_get, klist_rproc_put);
+
+typedef int (*rproc_handle_resources_t)(struct rproc *rproc,
+				struct resource_table *table, int len);
+typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int avail);
+
+/*
+ * This is the IOMMU fault handler we register with the IOMMU API
+ * (when relevant; not all remote processors access memory through
+ * an IOMMU).
+ *
+ * IOMMU core will invoke this handler whenever the remote processor
+ * will try to access an unmapped device address.
+ *
+ * Currently this is mostly a stub, but it will be later used to trigger
+ * the recovery of the remote processor.
+ */
+static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev,
+		unsigned long iova, int flags)
+{
+	dev_err(dev, "iommu fault: da 0x%lx flags 0x%x\n", iova, flags);
+
+	/*
+	 * Let the iommu core know we're not really handling this fault;
+	 * we just plan to use this as a recovery trigger.
+	 */
+	return -ENOSYS;
+}
+
+static int rproc_enable_iommu(struct rproc *rproc)
+{
+	struct iommu_domain *domain;
+	struct device *dev = rproc->dev;
+	int ret;
+
+	/*
+	 * We currently use iommu_present() to decide if an IOMMU
+	 * setup is needed.
+	 *
+	 * This works for simple cases, but will easily fail with
+	 * platforms that do have an IOMMU, but not for this specific
+	 * rproc.
+	 *
+	 * This will be easily solved by introducing hw capabilities
+	 * that will be set by the remoteproc driver.
+	 */
+	if (!iommu_present(dev->bus)) {
+		dev_dbg(dev, "iommu not found\n");
+		return 0;
+	}
+
+	domain = iommu_domain_alloc(dev->bus);
+	if (!domain) {
+		dev_err(dev, "can't alloc iommu domain\n");
+		return -ENOMEM;
+	}
+
+	iommu_set_fault_handler(domain, rproc_iommu_fault);
+
+	ret = iommu_attach_device(domain, dev);
+	if (ret) {
+		dev_err(dev, "can't attach iommu device: %d\n", ret);
+		goto free_domain;
+	}
+
+	rproc->domain = domain;
+
+	return 0;
+
+free_domain:
+	iommu_domain_free(domain);
+	return ret;
+}
+
+static void rproc_disable_iommu(struct rproc *rproc)
+{
+	struct iommu_domain *domain = rproc->domain;
+	struct device *dev = rproc->dev;
+
+	if (!domain)
+		return;
+
+	iommu_detach_device(domain, dev);
+	iommu_domain_free(domain);
+
+	return;
+}
+
+/*
+ * Some remote processors will ask us to allocate them physically contiguous
+ * memory regions (which we call "carveouts"), and map them to specific
+ * device addresses (which are hardcoded in the firmware).
+ *
+ * They may then ask us to copy objects into specific device addresses (e.g.
+ * code/data sections) or expose us certain symbols in other device address
+ * (e.g. their trace buffer).
+ *
+ * This function is an internal helper with which we can go over the allocated
+ * carveouts and translate specific device address to kernel virtual addresses
+ * so we can access the referenced memory.
+ *
+ * Note: phys_to_virt(iommu_iova_to_phys(rproc->domain, da)) will work too,
+ * but only on kernel direct mapped RAM memory. Instead, we're just using
+ * here the output of the DMA API, which should be more correct.
+ */
+static void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+{
+	struct rproc_mem_entry *carveout;
+	void *ptr = NULL;
+
+	list_for_each_entry(carveout, &rproc->carveouts, node) {
+		int offset = da - carveout->da;
+
+		/* try next carveout if da is too small */
+		if (offset < 0)
+			continue;
+
+		/* try next carveout if da is too large */
+		if (offset + len > carveout->len)
+			continue;
+
+		ptr = carveout->va + offset;
+
+		break;
+	}
+
+	return ptr;
+}
+
+/**
+ * rproc_load_segments() - load firmware segments to memory
+ * @rproc: remote processor which will be booted using these fw segments
+ * @elf_data: the content of the ELF firmware image
+ * @len: firmware size (in bytes)
+ *
+ * This function loads the firmware segments to memory, where the remote
+ * processor expects them.
+ *
+ * Some remote processors will expect their code and data to be placed
+ * in specific device addresses, and can't have them dynamically assigned.
+ *
+ * We currently support only those kind of remote processors, and expect
+ * the program header's paddr member to contain those addresses. We then go
+ * through the physically contiguous "carveout" memory regions which we
+ * allocated (and mapped) earlier on behalf of the remote processor,
+ * and "translate" device address to kernel addresses, so we can copy the
+ * segments where they are expected.
+ *
+ * Currently we only support remote processors that required carveout
+ * allocations and got them mapped onto their iommus. Some processors
+ * might be different: they might not have iommus, and would prefer to
+ * directly allocate memory for every segment/resource. This is not yet
+ * supported, though.
+ */
+static int
+rproc_load_segments(struct rproc *rproc, const u8 *elf_data, size_t len)
+{
+	struct device *dev = rproc->dev;
+	struct elf32_hdr *ehdr;
+	struct elf32_phdr *phdr;
+	int i, ret = 0;
+
+	ehdr = (struct elf32_hdr *)elf_data;
+	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
+
+	/* go through the available ELF segments */
+	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+		u32 da = phdr->p_paddr;
+		u32 memsz = phdr->p_memsz;
+		u32 filesz = phdr->p_filesz;
+		u32 offset = phdr->p_offset;
+		void *ptr;
+
+		if (phdr->p_type != PT_LOAD)
+			continue;
+
+		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
+					phdr->p_type, da, memsz, filesz);
+
+		if (filesz > memsz) {
+			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
+							filesz, memsz);
+			ret = -EINVAL;
+			break;
+		}
+
+		if (offset + filesz > len) {
+			dev_err(dev, "truncated fw: need 0x%x avail 0x%x\n",
+					offset + filesz, len);
+			ret = -EINVAL;
+			break;
+		}
+
+		/* grab the kernel address for this device address */
+		ptr = rproc_da_to_va(rproc, da, memsz);
+		if (!ptr) {
+			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
+			ret = -EINVAL;
+			break;
+		}
+
+		/* put the segment where the remote processor expects it */
+		if (phdr->p_filesz)
+			memcpy(ptr, elf_data + phdr->p_offset, filesz);
+
+		/*
+		 * Zero out remaining memory for this segment.
+		 *
+		 * This isn't strictly required since dma_alloc_coherent already
+		 * did this for us. albeit harmless, we may consider removing
+		 * this.
+		 */
+		if (memsz > filesz)
+			memset(ptr + filesz, 0, memsz - filesz);
+	}
+
+	return ret;
+}
+
+static int
+__rproc_handle_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i)
+{
+	struct rproc *rproc = rvdev->rproc;
+	struct device *dev = rproc->dev;
+	struct fw_rsc_vdev_vring *vring = &rsc->vring[i];
+	dma_addr_t dma;
+	void *va;
+	int ret, size, notifyid;
+
+	dev_dbg(dev, "vdev rsc: vring%d: da %x, qsz %d, align %d\n",
+				i, vring->da, vring->num, vring->align);
+
+	/* make sure reserved bytes are zeroes */
+	if (vring->reserved) {
+		dev_err(dev, "vring rsc has non zero reserved bytes\n");
+		return -EINVAL;
+	}
+
+	/* verify queue size and vring alignment are sane */
+	if (!vring->num || !vring->align) {
+		dev_err(dev, "invalid qsz (%d) or alignment (%d)\n",
+						vring->num, vring->align);
+		return -EINVAL;
+	}
+
+	/* actual size of vring (in bytes) */
+	size = PAGE_ALIGN(vring_size(vring->num, vring->align));
+
+	if (!idr_pre_get(&rproc->notifyids, GFP_KERNEL)) {
+		dev_err(dev, "idr_pre_get failed\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * Allocate non-cacheable memory for the vring. In the future
+	 * this call will also configure the IOMMU for us
+	 */
+	va = dma_alloc_coherent(dev, size, &dma, GFP_KERNEL);
+	if (!va) {
+		dev_err(dev, "dma_alloc_coherent failed\n");
+		return -EINVAL;
+	}
+
+	/* assign an rproc-wide unique index for this vring */
+	/* TODO: assign a notifyid for rvdev updates as well */
+	ret = idr_get_new(&rproc->notifyids, &rvdev->vring[i], &notifyid);
+	if (ret) {
+		dev_err(dev, "idr_get_new failed: %d\n", ret);
+		dma_free_coherent(dev, size, va, dma);
+		return ret;
+	}
+
+	/* let the rproc know the da and notifyid of this vring */
+	/* TODO: expose this to remote processor */
+	vring->da = dma;
+	vring->notifyid = notifyid;
+
+	dev_dbg(dev, "vring%d: va %p dma %x size %x idr %d\n", i, va,
+					dma, size, notifyid);
+
+	rvdev->vring[i].len = vring->num;
+	rvdev->vring[i].align = vring->align;
+	rvdev->vring[i].va = va;
+	rvdev->vring[i].dma = dma;
+	rvdev->vring[i].notifyid = notifyid;
+	rvdev->vring[i].rvdev = rvdev;
+
+	return 0;
+}
+
+static void __rproc_free_vrings(struct rproc_vdev *rvdev, int i)
+{
+	struct rproc *rproc = rvdev->rproc;
+
+	for (i--; i > 0; i--) {
+		struct rproc_vring *rvring = &rvdev->vring[i];
+		int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
+
+		dma_free_coherent(rproc->dev, size, rvring->va, rvring->dma);
+		idr_remove(&rproc->notifyids, rvring->notifyid);
+	}
+}
+
+/**
+ * rproc_handle_vdev() - handle a vdev fw resource
+ * @rproc: the remote processor
+ * @rsc: the vring resource descriptor
+ * @avail: size of available data (for sanity checking the image)
+ *
+ * This resource entry requests the host to statically register a virtio
+ * device (vdev), and setup everything needed to support it. It contains
+ * everything needed to make it possible: the virtio device id, virtio
+ * device features, vrings information, virtio config space, etc...
+ *
+ * Before registering the vdev, the vrings are allocated from non-cacheable
+ * physically contiguous memory. Currently we only support two vrings per
+ * remote processor (temporary limitation). We might also want to consider
+ * doing the vring allocation only later when ->find_vqs() is invoked, and
+ * then release them upon ->del_vqs().
+ *
+ * Note: @da is currently not really handled correctly: we dynamically
+ * allocate it using the DMA API, ignoring requested hard coded addresses,
+ * and we don't take care of any required IOMMU programming. This is all
+ * going to be taken care of when the generic iommu-based DMA API will be
+ * merged. Meanwhile, statically-addressed iommu-based firmware images should
+ * use RSC_DEVMEM resource entries to map their required @da to the physical
+ * address of their base CMA region (ouch, hacky!).
+ *
+ * Returns 0 on success, or an appropriate error code otherwise
+ */
+static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
+								int avail)
+{
+	struct device *dev = rproc->dev;
+	struct rproc_vdev *rvdev;
+	int i, ret;
+
+	/* make sure resource isn't truncated */
+	if (sizeof(*rsc) + rsc->num_of_vrings * sizeof(struct fw_rsc_vdev_vring)
+			+ rsc->config_len > avail) {
+		dev_err(rproc->dev, "vdev rsc is truncated\n");
+		return -EINVAL;
+	}
+
+	/* make sure reserved bytes are zeroes */
+	if (rsc->reserved[0] || rsc->reserved[1]) {
+		dev_err(dev, "vdev rsc has non zero reserved bytes\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "vdev rsc: id %d, dfeatures %x, cfg len %d, %d vrings\n",
+		rsc->id, rsc->dfeatures, rsc->config_len, rsc->num_of_vrings);
+
+	/* we currently support only two vrings per rvdev */
+	if (rsc->num_of_vrings > ARRAY_SIZE(rvdev->vring)) {
+		dev_err(dev, "too many vrings: %d\n", rsc->num_of_vrings);
+		return -EINVAL;
+	}
+
+	rvdev = kzalloc(sizeof(struct rproc_vdev), GFP_KERNEL);
+	if (!rvdev)
+		return -ENOMEM;
+
+	rvdev->rproc = rproc;
+
+	/* allocate the vrings */
+	for (i = 0; i < rsc->num_of_vrings; i++) {
+		ret = __rproc_handle_vring(rvdev, rsc, i);
+		if (ret)
+			goto free_vrings;
+	}
+
+	/* remember the device features */
+	rvdev->dfeatures = rsc->dfeatures;
+
+	list_add_tail(&rvdev->node, &rproc->rvdevs);
+
+	/* it is now safe to add the virtio device */
+	ret = rproc_add_virtio_dev(rvdev, rsc->id);
+	if (ret)
+		goto free_vrings;
+
+	return 0;
+
+free_vrings:
+	__rproc_free_vrings(rvdev, i);
+	kfree(rvdev);
+	return ret;
+}
+
+/**
+ * rproc_handle_trace() - handle a shared trace buffer resource
+ * @rproc: the remote processor
+ * @rsc: the trace resource descriptor
+ * @avail: size of available data (for sanity checking the image)
+ *
+ * In case the remote processor dumps trace logs into memory,
+ * export it via debugfs.
+ *
+ * Currently, the 'da' member of @rsc should contain the device address
+ * where the remote processor is dumping the traces. Later we could also
+ * support dynamically allocating this address using the generic
+ * DMA API (but currently there isn't a use case for that).
+ *
+ * Returns 0 on success, or an appropriate error code otherwise
+ */
+static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
+								int avail)
+{
+	struct rproc_mem_entry *trace;
+	struct device *dev = rproc->dev;
+	void *ptr;
+	char name[15];
+
+	if (sizeof(*rsc) > avail) {
+		dev_err(rproc->dev, "trace rsc is truncated\n");
+		return -EINVAL;
+	}
+
+	/* make sure reserved bytes are zeroes */
+	if (rsc->reserved) {
+		dev_err(dev, "trace rsc has non zero reserved bytes\n");
+		return -EINVAL;
+	}
+
+	/* what's the kernel address of this resource ? */
+	ptr = rproc_da_to_va(rproc, rsc->da, rsc->len);
+	if (!ptr) {
+		dev_err(dev, "erroneous trace resource entry\n");
+		return -EINVAL;
+	}
+
+	trace = kzalloc(sizeof(*trace), GFP_KERNEL);
+	if (!trace) {
+		dev_err(dev, "kzalloc trace failed\n");
+		return -ENOMEM;
+	}
+
+	/* set the trace buffer dma properties */
+	trace->len = rsc->len;
+	trace->va = ptr;
+
+	/* make sure snprintf always null terminates, even if truncating */
+	snprintf(name, sizeof(name), "trace%d", rproc->num_traces);
+
+	/* create the debugfs entry */
+	trace->priv = rproc_create_trace_file(name, rproc, trace);
+	if (!trace->priv) {
+		trace->va = NULL;
+		kfree(trace);
+		return -EINVAL;
+	}
+
+	list_add_tail(&trace->node, &rproc->traces);
+
+	rproc->num_traces++;
+
+	dev_dbg(dev, "%s added: va %p, da 0x%x, len 0x%x\n", name, ptr,
+						rsc->da, rsc->len);
+
+	return 0;
+}
+
+/**
+ * rproc_handle_devmem() - handle devmem resource entry
+ * @rproc: remote processor handle
+ * @rsc: the devmem resource entry
+ * @avail: size of available data (for sanity checking the image)
+ *
+ * Remote processors commonly need to access certain on-chip peripherals.
+ *
+ * Some of these remote processors access memory via an iommu device,
+ * and might require us to configure their iommu before they can access
+ * the on-chip peripherals they need.
+ *
+ * This resource entry is a request to map such a peripheral device.
+ *
+ * These devmem entries will contain the physical address of the device in
+ * the 'pa' member. If a specific device address is expected, then 'da' will
+ * contain it (currently this is the only use case supported). 'len' will
+ * contain the size of the physical region we need to map.
+ *
+ * Currently we just "trust" those devmem entries to contain valid physical
+ * addresses, but this is going to change: we want the implementations to
+ * tell us ranges of physical addresses the firmware is allowed to request,
+ * and not allow firmwares to request access to physical addresses that
+ * are outside those ranges.
+ */
+static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc,
+								int avail)
+{
+	struct rproc_mem_entry *mapping;
+	int ret;
+
+	/* no point in handling this resource without a valid iommu domain */
+	if (!rproc->domain)
+		return -EINVAL;
+
+	if (sizeof(*rsc) > avail) {
+		dev_err(rproc->dev, "devmem rsc is truncated\n");
+		return -EINVAL;
+	}
+
+	/* make sure reserved bytes are zeroes */
+	if (rsc->reserved) {
+		dev_err(rproc->dev, "devmem rsc has non zero reserved bytes\n");
+		return -EINVAL;
+	}
+
+	mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
+	if (!mapping) {
+		dev_err(rproc->dev, "kzalloc mapping failed\n");
+		return -ENOMEM;
+	}
+
+	ret = iommu_map(rproc->domain, rsc->da, rsc->pa, rsc->len, rsc->flags);
+	if (ret) {
+		dev_err(rproc->dev, "failed to map devmem: %d\n", ret);
+		goto out;
+	}
+
+	/*
+	 * We'll need this info later when we'll want to unmap everything
+	 * (e.g. on shutdown).
+	 *
+	 * We can't trust the remote processor not to change the resource
+	 * table, so we must maintain this info independently.
+	 */
+	mapping->da = rsc->da;
+	mapping->len = rsc->len;
+	list_add_tail(&mapping->node, &rproc->mappings);
+
+	dev_dbg(rproc->dev, "mapped devmem pa 0x%x, da 0x%x, len 0x%x\n",
+					rsc->pa, rsc->da, rsc->len);
+
+	return 0;
+
+out:
+	kfree(mapping);
+	return ret;
+}
+
+/**
+ * rproc_handle_carveout() - handle phys contig memory allocation requests
+ * @rproc: rproc handle
+ * @rsc: the resource entry
+ * @avail: size of available data (for image validation)
+ *
+ * This function will handle firmware requests for allocation of physically
+ * contiguous memory regions.
+ *
+ * These request entries should come first in the firmware's resource table,
+ * as other firmware entries might request placing other data objects inside
+ * these memory regions (e.g. data/code segments, trace resource entries, ...).
+ *
+ * Allocating memory this way helps utilizing the reserved physical memory
+ * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries
+ * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB
+ * pressure is important; it may have a substantial impact on performance.
+ */
+static int rproc_handle_carveout(struct rproc *rproc,
+				struct fw_rsc_carveout *rsc, int avail)
+{
+	struct rproc_mem_entry *carveout, *mapping;
+	struct device *dev = rproc->dev;
+	dma_addr_t dma;
+	void *va;
+	int ret;
+
+	if (sizeof(*rsc) > avail) {
+		dev_err(rproc->dev, "carveout rsc is truncated\n");
+		return -EINVAL;
+	}
+
+	/* make sure reserved bytes are zeroes */
+	if (rsc->reserved) {
+		dev_err(dev, "carveout rsc has non zero reserved bytes\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "carveout rsc: da %x, pa %x, len %x, flags %x\n",
+			rsc->da, rsc->pa, rsc->len, rsc->flags);
+
+	mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
+	if (!mapping) {
+		dev_err(dev, "kzalloc mapping failed\n");
+		return -ENOMEM;
+	}
+
+	carveout = kzalloc(sizeof(*carveout), GFP_KERNEL);
+	if (!carveout) {
+		dev_err(dev, "kzalloc carveout failed\n");
+		ret = -ENOMEM;
+		goto free_mapping;
+	}
+
+	va = dma_alloc_coherent(dev, rsc->len, &dma, GFP_KERNEL);
+	if (!va) {
+		dev_err(dev, "failed to dma alloc carveout: %d\n", rsc->len);
+		ret = -ENOMEM;
+		goto free_carv;
+	}
+
+	dev_dbg(dev, "carveout va %p, dma %x, len 0x%x\n", va, dma, rsc->len);
+
+	/*
+	 * Ok, this is non-standard.
+	 *
+	 * Sometimes we can't rely on the generic iommu-based DMA API
+	 * to dynamically allocate the device address and then set the IOMMU
+	 * tables accordingly, because some remote processors might
+	 * _require_ us to use hard coded device addresses that their
+	 * firmware was compiled with.
+	 *
+	 * In this case, we must use the IOMMU API directly and map
+	 * the memory to the device address as expected by the remote
+	 * processor.
+	 *
+	 * Obviously such remote processor devices should not be configured
+	 * to use the iommu-based DMA API: we expect 'dma' to contain the
+	 * physical address in this case.
+	 */
+	if (rproc->domain) {
+		ret = iommu_map(rproc->domain, rsc->da, dma, rsc->len,
+								rsc->flags);
+		if (ret) {
+			dev_err(dev, "iommu_map failed: %d\n", ret);
+			goto dma_free;
+		}
+
+		/*
+		 * We'll need this info later when we'll want to unmap
+		 * everything (e.g. on shutdown).
+		 *
+		 * We can't trust the remote processor not to change the
+		 * resource table, so we must maintain this info independently.
+		 */
+		mapping->da = rsc->da;
+		mapping->len = rsc->len;
+		list_add_tail(&mapping->node, &rproc->mappings);
+
+		dev_dbg(dev, "carveout mapped 0x%x to 0x%x\n", rsc->da, dma);
+
+		/*
+		 * Some remote processors might need to know the pa
+		 * even though they are behind an IOMMU. E.g., OMAP4's
+		 * remote M3 processor needs this so it can control
+		 * on-chip hardware accelerators that are not behind
+		 * the IOMMU, and therefor must know the pa.
+		 *
+		 * Generally we don't want to expose physical addresses
+		 * if we don't have to (remote processors are generally
+		 * _not_ trusted), so we might want to do this only for
+		 * remote processor that _must_ have this (e.g. OMAP4's
+		 * dual M3 subsystem).
+		 */
+		rsc->pa = dma;
+	}
+
+	carveout->va = va;
+	carveout->len = rsc->len;
+	carveout->dma = dma;
+	carveout->da = rsc->da;
+
+	list_add_tail(&carveout->node, &rproc->carveouts);
+
+	return 0;
+
+dma_free:
+	dma_free_coherent(dev, rsc->len, va, dma);
+free_carv:
+	kfree(carveout);
+free_mapping:
+	kfree(mapping);
+	return ret;
+}
+
+/*
+ * A lookup table for resource handlers. The indices are defined in
+ * enum fw_resource_type.
+ */
+static rproc_handle_resource_t rproc_handle_rsc[] = {
+	[RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout,
+	[RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem,
+	[RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace,
+	[RSC_VDEV] = NULL, /* VDEVs were handled upon registrarion */
+};
+
+/* handle firmware resource entries before booting the remote processor */
+static int
+rproc_handle_boot_rsc(struct rproc *rproc, struct resource_table *table, int len)
+{
+	struct device *dev = rproc->dev;
+	rproc_handle_resource_t handler;
+	int ret = 0, i;
+
+	for (i = 0; i < table->num; i++) {
+		int offset = table->offset[i];
+		struct fw_rsc_hdr *hdr = (void *)table + offset;
+		int avail = len - offset - sizeof(*hdr);
+		void *rsc = (void *)hdr + sizeof(*hdr);
+
+		/* make sure table isn't truncated */
+		if (avail < 0) {
+			dev_err(dev, "rsc table is truncated\n");
+			return -EINVAL;
+		}
+
+		dev_dbg(dev, "rsc: type %d\n", hdr->type);
+
+		if (hdr->type >= RSC_LAST) {
+			dev_warn(dev, "unsupported resource %d\n", hdr->type);
+			continue;
+		}
+
+		handler = rproc_handle_rsc[hdr->type];
+		if (!handler)
+			continue;
+
+		ret = handler(rproc, rsc, avail);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+/* handle firmware resource entries while registering the remote processor */
+static int
+rproc_handle_virtio_rsc(struct rproc *rproc, struct resource_table *table, int len)
+{
+	struct device *dev = rproc->dev;
+	int ret = 0, i;
+
+	for (i = 0; i < table->num; i++) {
+		int offset = table->offset[i];
+		struct fw_rsc_hdr *hdr = (void *)table + offset;
+		int avail = len - offset - sizeof(*hdr);
+		struct fw_rsc_vdev *vrsc;
+
+		/* make sure table isn't truncated */
+		if (avail < 0) {
+			dev_err(dev, "rsc table is truncated\n");
+			return -EINVAL;
+		}
+
+		dev_dbg(dev, "%s: rsc type %d\n", __func__, hdr->type);
+
+		if (hdr->type != RSC_VDEV)
+			continue;
+
+		vrsc = (struct fw_rsc_vdev *)hdr->data;
+
+		ret = rproc_handle_vdev(rproc, vrsc, avail);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+/**
+ * rproc_find_rsc_table() - find the resource table
+ * @rproc: the rproc handle
+ * @elf_data: the content of the ELF firmware image
+ * @len: firmware size (in bytes)
+ * @tablesz: place holder for providing back the table size
+ *
+ * This function finds the resource table inside the remote processor's
+ * firmware. It is used both upon the registration of @rproc (in order
+ * to look for and register the supported virito devices), and when the
+ * @rproc is booted.
+ *
+ * Returns the pointer to the resource table if it is found, and write its
+ * size into @tablesz. If a valid table isn't found, NULL is returned
+ * (and @tablesz isn't set).
+ */
+static struct resource_table *
+rproc_find_rsc_table(struct rproc *rproc, const u8 *elf_data, size_t len,
+							int *tablesz)
+{
+	struct elf32_hdr *ehdr;
+	struct elf32_shdr *shdr;
+	const char *name_table;
+	struct device *dev = rproc->dev;
+	struct resource_table *table = NULL;
+	int i;
+
+	ehdr = (struct elf32_hdr *)elf_data;
+	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
+	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
+
+	/* look for the resource table and handle it */
+	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
+		int size = shdr->sh_size;
+		int offset = shdr->sh_offset;
+
+		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
+			continue;
+
+		table = (struct resource_table *)(elf_data + offset);
+
+		/* make sure we have the entire table */
+		if (offset + size > len) {
+			dev_err(dev, "resource table truncated\n");
+			return NULL;
+		}
+
+		/* make sure table has at least the header */
+		if (sizeof(struct resource_table) > size) {
+			dev_err(dev, "header-less resource table\n");
+			return NULL;
+		}
+
+		/* we don't support any version beyond the first */
+		if (table->ver != 1) {
+			dev_err(dev, "unsupported fw ver: %d\n", table->ver);
+			return NULL;
+		}
+
+		/* make sure reserved bytes are zeroes */
+		if (table->reserved[0] || table->reserved[1]) {
+			dev_err(dev, "non zero reserved bytes\n");
+			return NULL;
+		}
+
+		/* make sure the offsets array isn't truncated */
+		if (table->num * sizeof(table->offset[0]) +
+				sizeof(struct resource_table) > size) {
+			dev_err(dev, "resource table incomplete\n");
+			return NULL;
+		}
+
+		*tablesz = shdr->sh_size;
+		break;
+	}
+
+	return table;
+}
+
+/**
+ * rproc_resource_cleanup() - clean up and free all acquired resources
+ * @rproc: rproc handle
+ *
+ * This function will free all resources acquired for @rproc, and it
+ * is called whenever @rproc either shuts down or fails to boot.
+ */
+static void rproc_resource_cleanup(struct rproc *rproc)
+{
+	struct rproc_mem_entry *entry, *tmp;
+	struct device *dev = rproc->dev;
+
+	/* clean up debugfs trace entries */
+	list_for_each_entry_safe(entry, tmp, &rproc->traces, node) {
+		rproc_remove_trace_file(entry->priv);
+		rproc->num_traces--;
+		list_del(&entry->node);
+		kfree(entry);
+	}
+
+	/* clean up carveout allocations */
+	list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) {
+		dma_free_coherent(dev, entry->len, entry->va, entry->dma);
+		list_del(&entry->node);
+		kfree(entry);
+	}
+
+	/* clean up iommu mapping entries */
+	list_for_each_entry_safe(entry, tmp, &rproc->mappings, node) {
+		size_t unmapped;
+
+		unmapped = iommu_unmap(rproc->domain, entry->da, entry->len);
+		if (unmapped != entry->len) {
+			/* nothing much to do besides complaining */
+			dev_err(dev, "failed to unmap %u/%u\n", entry->len,
+								unmapped);
+		}
+
+		list_del(&entry->node);
+		kfree(entry);
+	}
+}
+
+/* make sure this fw image is sane */
+static int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw)
+{
+	const char *name = rproc->firmware;
+	struct device *dev = rproc->dev;
+	struct elf32_hdr *ehdr;
+	char class;
+
+	if (!fw) {
+		dev_err(dev, "failed to load %s\n", name);
+		return -EINVAL;
+	}
+
+	if (fw->size < sizeof(struct elf32_hdr)) {
+		dev_err(dev, "Image is too small\n");
+		return -EINVAL;
+	}
+
+	ehdr = (struct elf32_hdr *)fw->data;
+
+	/* We only support ELF32 at this point */
+	class = ehdr->e_ident[EI_CLASS];
+	if (class != ELFCLASS32) {
+		dev_err(dev, "Unsupported class: %d\n", class);
+		return -EINVAL;
+	}
+
+	/* We assume the firmware has the same endianess as the host */
+# ifdef __LITTLE_ENDIAN
+	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
+# else /* BIG ENDIAN */
+	if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
+# endif
+		dev_err(dev, "Unsupported firmware endianess\n");
+		return -EINVAL;
+	}
+
+	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
+		dev_err(dev, "Image is too small\n");
+		return -EINVAL;
+	}
+
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+		dev_err(dev, "Image is corrupted (bad magic)\n");
+		return -EINVAL;
+	}
+
+	if (ehdr->e_phnum == 0) {
+		dev_err(dev, "No loadable segments\n");
+		return -EINVAL;
+	}
+
+	if (ehdr->e_phoff > fw->size) {
+		dev_err(dev, "Firmware size is too small\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * take a firmware and boot a remote processor with it.
+ */
+static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
+{
+	struct device *dev = rproc->dev;
+	const char *name = rproc->firmware;
+	struct elf32_hdr *ehdr;
+	struct resource_table *table;
+	int ret, tablesz;
+
+	ret = rproc_fw_sanity_check(rproc, fw);
+	if (ret)
+		return ret;
+
+	ehdr = (struct elf32_hdr *)fw->data;
+
+	dev_info(dev, "Booting fw image %s, size %d\n", name, fw->size);
+
+	/*
+	 * if enabling an IOMMU isn't relevant for this rproc, this is
+	 * just a nop
+	 */
+	ret = rproc_enable_iommu(rproc);
+	if (ret) {
+		dev_err(dev, "can't enable iommu: %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * The ELF entry point is the rproc's boot addr (though this is not
+	 * a configurable property of all remote processors: some will always
+	 * boot at a specific hardcoded address).
+	 */
+	rproc->bootaddr = ehdr->e_entry;
+
+	/* look for the resource table */
+	table = rproc_find_rsc_table(rproc, fw->data, fw->size, &tablesz);
+	if (!table)
+		goto clean_up;
+
+	/* handle fw resources which are required to boot rproc */
+	ret = rproc_handle_boot_rsc(rproc, table, tablesz);
+	if (ret) {
+		dev_err(dev, "Failed to process resources: %d\n", ret);
+		goto clean_up;
+	}
+
+	/* load the ELF segments to memory */
+	ret = rproc_load_segments(rproc, fw->data, fw->size);
+	if (ret) {
+		dev_err(dev, "Failed to load program segments: %d\n", ret);
+		goto clean_up;
+	}
+
+	/* power up the remote processor */
+	ret = rproc->ops->start(rproc);
+	if (ret) {
+		dev_err(dev, "can't start rproc %s: %d\n", rproc->name, ret);
+		goto clean_up;
+	}
+
+	rproc->state = RPROC_RUNNING;
+
+	dev_info(dev, "remote processor %s is now up\n", rproc->name);
+
+	return 0;
+
+clean_up:
+	rproc_resource_cleanup(rproc);
+	rproc_disable_iommu(rproc);
+	return ret;
+}
+
+/*
+ * take a firmware and look for virtio devices to register.
+ *
+ * Note: this function is called asynchronously upon registration of the
+ * remote processor (so we must wait until it completes before we try
+ * to unregister the device. one other option is just to use kref here,
+ * that might be cleaner).
+ */
+static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
+{
+	struct rproc *rproc = context;
+	struct resource_table *table;
+	int ret, tablesz;
+
+	if (rproc_fw_sanity_check(rproc, fw) < 0)
+		goto out;
+
+	/* look for the resource table */
+	table = rproc_find_rsc_table(rproc, fw->data, fw->size, &tablesz);
+	if (!table)
+		goto out;
+
+	/* look for virtio devices and register them */
+	ret = rproc_handle_virtio_rsc(rproc, table, tablesz);
+	if (ret)
+		goto out;
+
+out:
+	if (fw)
+		release_firmware(fw);
+	/* allow rproc_unregister() contexts, if any, to proceed */
+	complete_all(&rproc->firmware_loading_complete);
+}
+
+/**
+ * rproc_boot() - boot a remote processor
+ * @rproc: handle of a remote processor
+ *
+ * Boot a remote processor (i.e. load its firmware, power it on, ...).
+ *
+ * If the remote processor is already powered on, this function immediately
+ * returns (successfully).
+ *
+ * Returns 0 on success, and an appropriate error value otherwise.
+ */
+int rproc_boot(struct rproc *rproc)
+{
+	const struct firmware *firmware_p;
+	struct device *dev;
+	int ret;
+
+	if (!rproc) {
+		pr_err("invalid rproc handle\n");
+		return -EINVAL;
+	}
+
+	dev = rproc->dev;
+
+	ret = mutex_lock_interruptible(&rproc->lock);
+	if (ret) {
+		dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret);
+		return ret;
+	}
+
+	/* loading a firmware is required */
+	if (!rproc->firmware) {
+		dev_err(dev, "%s: no firmware to load\n", __func__);
+		ret = -EINVAL;
+		goto unlock_mutex;
+	}
+
+	/* prevent underlying implementation from being removed */
+	if (!try_module_get(dev->driver->owner)) {
+		dev_err(dev, "%s: can't get owner\n", __func__);
+		ret = -EINVAL;
+		goto unlock_mutex;
+	}
+
+	/* skip the boot process if rproc is already powered up */
+	if (atomic_inc_return(&rproc->power) > 1) {
+		ret = 0;
+		goto unlock_mutex;
+	}
+
+	dev_info(dev, "powering up %s\n", rproc->name);
+
+	/* load firmware */
+	ret = request_firmware(&firmware_p, rproc->firmware, dev);
+	if (ret < 0) {
+		dev_err(dev, "request_firmware failed: %d\n", ret);
+		goto downref_rproc;
+	}
+
+	ret = rproc_fw_boot(rproc, firmware_p);
+
+	release_firmware(firmware_p);
+
+downref_rproc:
+	if (ret) {
+		module_put(dev->driver->owner);
+		atomic_dec(&rproc->power);
+	}
+unlock_mutex:
+	mutex_unlock(&rproc->lock);
+	return ret;
+}
+EXPORT_SYMBOL(rproc_boot);
+
+/**
+ * rproc_shutdown() - power off the remote processor
+ * @rproc: the remote processor
+ *
+ * Power off a remote processor (previously booted with rproc_boot()).
+ *
+ * In case @rproc is still being used by an additional user(s), then
+ * this function will just decrement the power refcount and exit,
+ * without really powering off the device.
+ *
+ * Every call to rproc_boot() must (eventually) be accompanied by a call
+ * to rproc_shutdown(). Calling rproc_shutdown() redundantly is a bug.
+ *
+ * Notes:
+ * - we're not decrementing the rproc's refcount, only the power refcount.
+ *   which means that the @rproc handle stays valid even after rproc_shutdown()
+ *   returns, and users can still use it with a subsequent rproc_boot(), if
+ *   needed.
+ * - don't call rproc_shutdown() to unroll rproc_get_by_name(), exactly
+ *   because rproc_shutdown() _does not_ decrement the refcount of @rproc.
+ *   To decrement the refcount of @rproc, use rproc_put() (but _only_ if
+ *   you acquired @rproc using rproc_get_by_name()).
+ */
+void rproc_shutdown(struct rproc *rproc)
+{
+	struct device *dev = rproc->dev;
+	int ret;
+
+	ret = mutex_lock_interruptible(&rproc->lock);
+	if (ret) {
+		dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret);
+		return;
+	}
+
+	/* if the remote proc is still needed, bail out */
+	if (!atomic_dec_and_test(&rproc->power))
+		goto out;
+
+	/* power off the remote processor */
+	ret = rproc->ops->stop(rproc);
+	if (ret) {
+		atomic_inc(&rproc->power);
+		dev_err(dev, "can't stop rproc: %d\n", ret);
+		goto out;
+	}
+
+	/* clean up all acquired resources */
+	rproc_resource_cleanup(rproc);
+
+	rproc_disable_iommu(rproc);
+
+	rproc->state = RPROC_OFFLINE;
+
+	dev_info(dev, "stopped remote processor %s\n", rproc->name);
+
+out:
+	mutex_unlock(&rproc->lock);
+	if (!ret)
+		module_put(dev->driver->owner);
+}
+EXPORT_SYMBOL(rproc_shutdown);
+
+/**
+ * rproc_release() - completely deletes the existence of a remote processor
+ * @kref: the rproc's kref
+ *
+ * This function should _never_ be called directly.
+ *
+ * The only reasonable location to use it is as an argument when kref_put'ing
+ * @rproc's refcount.
+ *
+ * This way it will be called when no one holds a valid pointer to this @rproc
+ * anymore (and obviously after it is removed from the rprocs klist).
+ *
+ * Note: this function is not static because rproc_vdev_release() needs it when
+ * it decrements @rproc's refcount.
+ */
+void rproc_release(struct kref *kref)
+{
+	struct rproc *rproc = container_of(kref, struct rproc, refcount);
+	struct rproc_vdev *rvdev, *rvtmp;
+
+	dev_info(rproc->dev, "removing %s\n", rproc->name);
+
+	rproc_delete_debug_dir(rproc);
+
+	/* clean up remote vdev entries */
+	list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node) {
+		__rproc_free_vrings(rvdev, RVDEV_NUM_VRINGS);
+		list_del(&rvdev->node);
+	}
+
+	/*
+	 * At this point no one holds a reference to rproc anymore,
+	 * so we can directly unroll rproc_alloc()
+	 */
+	rproc_free(rproc);
+}
+
+/* will be called when an rproc is added to the rprocs klist */
+static void klist_rproc_get(struct klist_node *n)
+{
+	struct rproc *rproc = container_of(n, struct rproc, node);
+
+	kref_get(&rproc->refcount);
+}
+
+/* will be called when an rproc is removed from the rprocs klist */
+static void klist_rproc_put(struct klist_node *n)
+{
+	struct rproc *rproc = container_of(n, struct rproc, node);
+
+	kref_put(&rproc->refcount, rproc_release);
+}
+
+static struct rproc *next_rproc(struct klist_iter *i)
+{
+	struct klist_node *n;
+
+	n = klist_next(i);
+	if (!n)
+		return NULL;
+
+	return container_of(n, struct rproc, node);
+}
+
+/**
+ * rproc_get_by_name() - find a remote processor by name and boot it
+ * @name: name of the remote processor
+ *
+ * Finds an rproc handle using the remote processor's name, and then
+ * boot it. If it's already powered on, then just immediately return
+ * (successfully).
+ *
+ * Returns the rproc handle on success, and NULL on failure.
+ *
+ * This function increments the remote processor's refcount, so always
+ * use rproc_put() to decrement it back once rproc isn't needed anymore.
+ *
+ * Note: currently this function (and its counterpart rproc_put()) are not
+ * being used. We need to scrutinize the use cases
+ * that still need them, and see if we can migrate them to use the non
+ * name-based boot/shutdown interface.
+ */
+struct rproc *rproc_get_by_name(const char *name)
+{
+	struct rproc *rproc;
+	struct klist_iter i;
+	int ret;
+
+	/* find the remote processor, and upref its refcount */
+	klist_iter_init(&rprocs, &i);
+	while ((rproc = next_rproc(&i)) != NULL)
+		if (!strcmp(rproc->name, name)) {
+			kref_get(&rproc->refcount);
+			break;
+		}
+	klist_iter_exit(&i);
+
+	/* can't find this rproc ? */
+	if (!rproc) {
+		pr_err("can't find remote processor %s\n", name);
+		return NULL;
+	}
+
+	ret = rproc_boot(rproc);
+	if (ret < 0) {
+		kref_put(&rproc->refcount, rproc_release);
+		return NULL;
+	}
+
+	return rproc;
+}
+EXPORT_SYMBOL(rproc_get_by_name);
+
+/**
+ * rproc_put() - decrement the refcount of a remote processor, and shut it down
+ * @rproc: the remote processor
+ *
+ * This function tries to shutdown @rproc, and it then decrements its
+ * refcount.
+ *
+ * After this function returns, @rproc may _not_ be used anymore, and its
+ * handle should be considered invalid.
+ *
+ * This function should be called _iff_ the @rproc handle was grabbed by
+ * calling rproc_get_by_name().
+ */
+void rproc_put(struct rproc *rproc)
+{
+	/* try to power off the remote processor */
+	rproc_shutdown(rproc);
+
+	/* downref rproc's refcount */
+	kref_put(&rproc->refcount, rproc_release);
+}
+EXPORT_SYMBOL(rproc_put);
+
+/**
+ * rproc_register() - register a remote processor
+ * @rproc: the remote processor handle to register
+ *
+ * Registers @rproc with the remoteproc framework, after it has been
+ * allocated with rproc_alloc().
+ *
+ * This is called by the platform-specific rproc implementation, whenever
+ * a new remote processor device is probed.
+ *
+ * Returns 0 on success and an appropriate error code otherwise.
+ *
+ * Note: this function initiates an asynchronous firmware loading
+ * context, which will look for virtio devices supported by the rproc's
+ * firmware.
+ *
+ * If found, those virtio devices will be created and added, so as a result
+ * of registering this remote processor, additional virtio drivers might be
+ * probed.
+ */
+int rproc_register(struct rproc *rproc)
+{
+	struct device *dev = rproc->dev;
+	int ret = 0;
+
+	/* expose to rproc_get_by_name users */
+	klist_add_tail(&rproc->node, &rprocs);
+
+	dev_info(rproc->dev, "%s is available\n", rproc->name);
+
+	dev_info(dev, "Note: remoteproc is still under development and considered experimental.\n");
+	dev_info(dev, "THE BINARY FORMAT IS NOT YET FINALIZED, and backward compatibility isn't yet guaranteed.\n");
+
+	/* create debugfs entries */
+	rproc_create_debug_dir(rproc);
+
+	/* rproc_unregister() calls must wait until async loader completes */
+	init_completion(&rproc->firmware_loading_complete);
+
+	/*
+	 * We must retrieve early virtio configuration info from
+	 * the firmware (e.g. whether to register a virtio device,
+	 * what virtio features does it support, ...).
+	 *
+	 * We're initiating an asynchronous firmware loading, so we can
+	 * be built-in kernel code, without hanging the boot process.
+	 */
+	ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+					rproc->firmware, dev, GFP_KERNEL,
+					rproc, rproc_fw_config_virtio);
+	if (ret < 0) {
+		dev_err(dev, "request_firmware_nowait failed: %d\n", ret);
+		complete_all(&rproc->firmware_loading_complete);
+		klist_remove(&rproc->node);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(rproc_register);
+
+/**
+ * rproc_alloc() - allocate a remote processor handle
+ * @dev: the underlying device
+ * @name: name of this remote processor
+ * @ops: platform-specific handlers (mainly start/stop)
+ * @firmware: name of firmware file to load
+ * @len: length of private data needed by the rproc driver (in bytes)
+ *
+ * Allocates a new remote processor handle, but does not register
+ * it yet.
+ *
+ * This function should be used by rproc implementations during initialization
+ * of the remote processor.
+ *
+ * After creating an rproc handle using this function, and when ready,
+ * implementations should then call rproc_register() to complete
+ * the registration of the remote processor.
+ *
+ * On success the new rproc is returned, and on failure, NULL.
+ *
+ * Note: _never_ directly deallocate @rproc, even if it was not registered
+ * yet. Instead, if you just need to unroll rproc_alloc(), use rproc_free().
+ */
+struct rproc *rproc_alloc(struct device *dev, const char *name,
+				const struct rproc_ops *ops,
+				const char *firmware, int len)
+{
+	struct rproc *rproc;
+
+	if (!dev || !name || !ops)
+		return NULL;
+
+	rproc = kzalloc(sizeof(struct rproc) + len, GFP_KERNEL);
+	if (!rproc) {
+		dev_err(dev, "%s: kzalloc failed\n", __func__);
+		return NULL;
+	}
+
+	rproc->dev = dev;
+	rproc->name = name;
+	rproc->ops = ops;
+	rproc->firmware = firmware;
+	rproc->priv = &rproc[1];
+
+	atomic_set(&rproc->power, 0);
+
+	kref_init(&rproc->refcount);
+
+	mutex_init(&rproc->lock);
+
+	idr_init(&rproc->notifyids);
+
+	INIT_LIST_HEAD(&rproc->carveouts);
+	INIT_LIST_HEAD(&rproc->mappings);
+	INIT_LIST_HEAD(&rproc->traces);
+	INIT_LIST_HEAD(&rproc->rvdevs);
+
+	rproc->state = RPROC_OFFLINE;
+
+	return rproc;
+}
+EXPORT_SYMBOL(rproc_alloc);
+
+/**
+ * rproc_free() - free an rproc handle that was allocated by rproc_alloc
+ * @rproc: the remote processor handle
+ *
+ * This function should _only_ be used if @rproc was only allocated,
+ * but not registered yet.
+ *
+ * If @rproc was already successfully registered (by calling rproc_register()),
+ * then use rproc_unregister() instead.
+ */
+void rproc_free(struct rproc *rproc)
+{
+	idr_remove_all(&rproc->notifyids);
+	idr_destroy(&rproc->notifyids);
+
+	kfree(rproc);
+}
+EXPORT_SYMBOL(rproc_free);
+
+/**
+ * rproc_unregister() - unregister a remote processor
+ * @rproc: rproc handle to unregister
+ *
+ * Unregisters a remote processor, and decrements its refcount.
+ * If its refcount drops to zero, then @rproc will be freed. If not,
+ * it will be freed later once the last reference is dropped.
+ *
+ * This function should be called when the platform specific rproc
+ * implementation decides to remove the rproc device. it should
+ * _only_ be called if a previous invocation of rproc_register()
+ * has completed successfully.
+ *
+ * After rproc_unregister() returns, @rproc is _not_ valid anymore and
+ * it shouldn't be used. More specifically, don't call rproc_free()
+ * or try to directly free @rproc after rproc_unregister() returns;
+ * none of these are needed, and calling them is a bug.
+ *
+ * Returns 0 on success and -EINVAL if @rproc isn't valid.
+ */
+int rproc_unregister(struct rproc *rproc)
+{
+	struct rproc_vdev *rvdev;
+
+	if (!rproc)
+		return -EINVAL;
+
+	/* if rproc is just being registered, wait */
+	wait_for_completion(&rproc->firmware_loading_complete);
+
+	/* clean up remote vdev entries */
+	list_for_each_entry(rvdev, &rproc->rvdevs, node)
+		rproc_remove_virtio_dev(rvdev);
+
+	/* the rproc is downref'ed as soon as it's removed from the klist */
+	klist_del(&rproc->node);
+
+	/* the rproc will only be released after its refcount drops to zero */
+	kref_put(&rproc->refcount, rproc_release);
+
+	return 0;
+}
+EXPORT_SYMBOL(rproc_unregister);
+
+static int __init remoteproc_init(void)
+{
+	rproc_init_debugfs();
+	return 0;
+}
+module_init(remoteproc_init);
+
+static void __exit remoteproc_exit(void)
+{
+	rproc_exit_debugfs();
+}
+module_exit(remoteproc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Generic Remote Processor Framework");
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
new file mode 100644
index 0000000..85d31a6
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -0,0 +1,172 @@
+/*
+ * Remote Processor Framework
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Mark Grosen <mgrosen@ti.com>
+ * Brian Swetland <swetland@google.com>
+ * Fernando Guzman Lugo <fernando.lugo@ti.com>
+ * Suman Anna <s-anna@ti.com>
+ * Robert Tivy <rtivy@ti.com>
+ * Armando Uribe De Leon <x0095078@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.
+ */
+
+#define pr_fmt(fmt)    "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/remoteproc.h>
+#include <linux/device.h>
+
+/* remoteproc debugfs parent dir */
+static struct dentry *rproc_dbg;
+
+/*
+ * Some remote processors may support dumping trace logs into a shared
+ * memory buffer. We expose this trace buffer using debugfs, so users
+ * can easily tell what's going on remotely.
+ *
+ * We will most probably improve the rproc tracing facilities later on,
+ * but this kind of lightweight and simple mechanism is always good to have,
+ * as it provides very early tracing with little to no dependencies at all.
+ */
+static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf,
+						size_t count, loff_t *ppos)
+{
+	struct rproc_mem_entry *trace = filp->private_data;
+	int len = strnlen(trace->va, trace->len);
+
+	return simple_read_from_buffer(userbuf, count, ppos, trace->va, len);
+}
+
+static const struct file_operations trace_rproc_ops = {
+	.read = rproc_trace_read,
+	.open = simple_open,
+	.llseek	= generic_file_llseek,
+};
+
+/*
+ * A state-to-string lookup table, for exposing a human readable state
+ * via debugfs. Always keep in sync with enum rproc_state
+ */
+static const char * const rproc_state_string[] = {
+	"offline",
+	"suspended",
+	"running",
+	"crashed",
+	"invalid",
+};
+
+/* expose the state of the remote processor via debugfs */
+static ssize_t rproc_state_read(struct file *filp, char __user *userbuf,
+						size_t count, loff_t *ppos)
+{
+	struct rproc *rproc = filp->private_data;
+	unsigned int state;
+	char buf[30];
+	int i;
+
+	state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state;
+
+	i = snprintf(buf, 30, "%.28s (%d)\n", rproc_state_string[state],
+							rproc->state);
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, i);
+}
+
+static const struct file_operations rproc_state_ops = {
+	.read = rproc_state_read,
+	.open = simple_open,
+	.llseek	= generic_file_llseek,
+};
+
+/* expose the name of the remote processor via debugfs */
+static ssize_t rproc_name_read(struct file *filp, char __user *userbuf,
+						size_t count, loff_t *ppos)
+{
+	struct rproc *rproc = filp->private_data;
+	/* need room for the name, a newline and a terminating null */
+	char buf[100];
+	int i;
+
+	i = snprintf(buf, sizeof(buf), "%.98s\n", rproc->name);
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, i);
+}
+
+static const struct file_operations rproc_name_ops = {
+	.read = rproc_name_read,
+	.open = simple_open,
+	.llseek	= generic_file_llseek,
+};
+
+void rproc_remove_trace_file(struct dentry *tfile)
+{
+	debugfs_remove(tfile);
+}
+
+struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
+					struct rproc_mem_entry *trace)
+{
+	struct dentry *tfile;
+
+	tfile = debugfs_create_file(name, 0400, rproc->dbg_dir,
+						trace, &trace_rproc_ops);
+	if (!tfile) {
+		dev_err(rproc->dev, "failed to create debugfs trace entry\n");
+		return NULL;
+	}
+
+	return tfile;
+}
+
+void rproc_delete_debug_dir(struct rproc *rproc)
+{
+	if (!rproc->dbg_dir)
+		return;
+
+	debugfs_remove_recursive(rproc->dbg_dir);
+}
+
+void rproc_create_debug_dir(struct rproc *rproc)
+{
+	struct device *dev = rproc->dev;
+
+	if (!rproc_dbg)
+		return;
+
+	rproc->dbg_dir = debugfs_create_dir(dev_name(dev), rproc_dbg);
+	if (!rproc->dbg_dir)
+		return;
+
+	debugfs_create_file("name", 0400, rproc->dbg_dir,
+					rproc, &rproc_name_ops);
+	debugfs_create_file("state", 0400, rproc->dbg_dir,
+					rproc, &rproc_state_ops);
+}
+
+void __init rproc_init_debugfs(void)
+{
+	if (debugfs_initialized()) {
+		rproc_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
+		if (!rproc_dbg)
+			pr_err("can't create debugfs dir\n");
+	}
+}
+
+void __exit rproc_exit_debugfs(void)
+{
+	if (rproc_dbg)
+		debugfs_remove(rproc_dbg);
+}
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
new file mode 100644
index 0000000..9f336d6
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -0,0 +1,44 @@
+/*
+ * Remote processor framework
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * 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 REMOTEPROC_INTERNAL_H
+#define REMOTEPROC_INTERNAL_H
+
+#include <linux/irqreturn.h>
+
+struct rproc;
+
+/* from remoteproc_core.c */
+void rproc_release(struct kref *kref);
+irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int vq_id);
+
+/* from remoteproc_virtio.c */
+int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id);
+void rproc_remove_virtio_dev(struct rproc_vdev *rvdev);
+
+/* from remoteproc_debugfs.c */
+void rproc_remove_trace_file(struct dentry *tfile);
+struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
+					struct rproc_mem_entry *trace);
+void rproc_delete_debug_dir(struct rproc *rproc);
+void rproc_create_debug_dir(struct rproc *rproc);
+void rproc_init_debugfs(void);
+void rproc_exit_debugfs(void);
+
+#endif /* REMOTEPROC_INTERNAL_H */
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
new file mode 100644
index 0000000..ecf6121
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -0,0 +1,289 @@
+/*
+ * Remote processor messaging transport (OMAP platform-specific bits)
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * 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/export.h>
+#include <linux/remoteproc.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_ring.h>
+#include <linux/err.h>
+#include <linux/kref.h>
+#include <linux/slab.h>
+
+#include "remoteproc_internal.h"
+
+/* kick the remote processor, and let it know which virtqueue to poke at */
+static void rproc_virtio_notify(struct virtqueue *vq)
+{
+	struct rproc_vring *rvring = vq->priv;
+	struct rproc *rproc = rvring->rvdev->rproc;
+	int notifyid = rvring->notifyid;
+
+	dev_dbg(rproc->dev, "kicking vq index: %d\n", notifyid);
+
+	rproc->ops->kick(rproc, notifyid);
+}
+
+/**
+ * rproc_vq_interrupt() - tell remoteproc that a virtqueue is interrupted
+ * @rproc: handle to the remote processor
+ * @notifyid: index of the signalled virtqueue (unique per this @rproc)
+ *
+ * This function should be called by the platform-specific rproc driver,
+ * when the remote processor signals that a specific virtqueue has pending
+ * messages available.
+ *
+ * Returns IRQ_NONE if no message was found in the @notifyid virtqueue,
+ * and otherwise returns IRQ_HANDLED.
+ */
+irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid)
+{
+	struct rproc_vring *rvring;
+
+	dev_dbg(rproc->dev, "vq index %d is interrupted\n", notifyid);
+
+	rvring = idr_find(&rproc->notifyids, notifyid);
+	if (!rvring || !rvring->vq)
+		return IRQ_NONE;
+
+	return vring_interrupt(0, rvring->vq);
+}
+EXPORT_SYMBOL(rproc_vq_interrupt);
+
+static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
+				    unsigned id,
+				    void (*callback)(struct virtqueue *vq),
+				    const char *name)
+{
+	struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+	struct rproc *rproc = vdev_to_rproc(vdev);
+	struct rproc_vring *rvring;
+	struct virtqueue *vq;
+	void *addr;
+	int len, size;
+
+	/* we're temporarily limited to two virtqueues per rvdev */
+	if (id >= ARRAY_SIZE(rvdev->vring))
+		return ERR_PTR(-EINVAL);
+
+	rvring = &rvdev->vring[id];
+
+	addr = rvring->va;
+	len = rvring->len;
+
+	/* zero vring */
+	size = vring_size(len, rvring->align);
+	memset(addr, 0, size);
+
+	dev_dbg(rproc->dev, "vring%d: va %p qsz %d notifyid %d\n",
+					id, addr, len, rvring->notifyid);
+
+	/*
+	 * Create the new vq, and tell virtio we're not interested in
+	 * the 'weak' smp barriers, since we're talking with a real device.
+	 */
+	vq = vring_new_virtqueue(len, rvring->align, vdev, false, addr,
+					rproc_virtio_notify, callback, name);
+	if (!vq) {
+		dev_err(rproc->dev, "vring_new_virtqueue %s failed\n", name);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	rvring->vq = vq;
+	vq->priv = rvring;
+
+	return vq;
+}
+
+static void rproc_virtio_del_vqs(struct virtio_device *vdev)
+{
+	struct virtqueue *vq, *n;
+	struct rproc *rproc = vdev_to_rproc(vdev);
+	struct rproc_vring *rvring;
+
+	/* power down the remote processor before deleting vqs */
+	rproc_shutdown(rproc);
+
+	list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
+		rvring = vq->priv;
+		rvring->vq = NULL;
+		vring_del_virtqueue(vq);
+	}
+}
+
+static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+		       struct virtqueue *vqs[],
+		       vq_callback_t *callbacks[],
+		       const char *names[])
+{
+	struct rproc *rproc = vdev_to_rproc(vdev);
+	int i, ret;
+
+	for (i = 0; i < nvqs; ++i) {
+		vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]);
+		if (IS_ERR(vqs[i])) {
+			ret = PTR_ERR(vqs[i]);
+			goto error;
+		}
+	}
+
+	/* now that the vqs are all set, boot the remote processor */
+	ret = rproc_boot(rproc);
+	if (ret) {
+		dev_err(rproc->dev, "rproc_boot() failed %d\n", ret);
+		goto error;
+	}
+
+	return 0;
+
+error:
+	rproc_virtio_del_vqs(vdev);
+	return ret;
+}
+
+/*
+ * We don't support yet real virtio status semantics.
+ *
+ * The plan is to provide this via the VDEV resource entry
+ * which is part of the firmware: this way the remote processor
+ * will be able to access the status values as set by us.
+ */
+static u8 rproc_virtio_get_status(struct virtio_device *vdev)
+{
+	return 0;
+}
+
+static void rproc_virtio_set_status(struct virtio_device *vdev, u8 status)
+{
+	dev_dbg(&vdev->dev, "status: %d\n", status);
+}
+
+static void rproc_virtio_reset(struct virtio_device *vdev)
+{
+	dev_dbg(&vdev->dev, "reset !\n");
+}
+
+/* provide the vdev features as retrieved from the firmware */
+static u32 rproc_virtio_get_features(struct virtio_device *vdev)
+{
+	struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+
+	return rvdev->dfeatures;
+}
+
+static void rproc_virtio_finalize_features(struct virtio_device *vdev)
+{
+	struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+
+	/* Give virtio_ring a chance to accept features */
+	vring_transport_features(vdev);
+
+	/*
+	 * Remember the finalized features of our vdev, and provide it
+	 * to the remote processor once it is powered on.
+	 *
+	 * Similarly to the status field, we don't expose yet the negotiated
+	 * features to the remote processors at this point. This will be
+	 * fixed as part of a small resource table overhaul and then an
+	 * extension of the virtio resource entries.
+	 */
+	rvdev->gfeatures = vdev->features[0];
+}
+
+static struct virtio_config_ops rproc_virtio_config_ops = {
+	.get_features	= rproc_virtio_get_features,
+	.finalize_features = rproc_virtio_finalize_features,
+	.find_vqs	= rproc_virtio_find_vqs,
+	.del_vqs	= rproc_virtio_del_vqs,
+	.reset		= rproc_virtio_reset,
+	.set_status	= rproc_virtio_set_status,
+	.get_status	= rproc_virtio_get_status,
+};
+
+/*
+ * This function is called whenever vdev is released, and is responsible
+ * to decrement the remote processor's refcount taken when vdev was
+ * added.
+ *
+ * Never call this function directly; it will be called by the driver
+ * core when needed.
+ */
+static void rproc_vdev_release(struct device *dev)
+{
+	struct virtio_device *vdev = dev_to_virtio(dev);
+	struct rproc *rproc = vdev_to_rproc(vdev);
+
+	kref_put(&rproc->refcount, rproc_release);
+}
+
+/**
+ * rproc_add_virtio_dev() - register an rproc-induced virtio device
+ * @rvdev: the remote vdev
+ *
+ * This function registers a virtio device. This vdev's partent is
+ * the rproc device.
+ *
+ * Returns 0 on success or an appropriate error value otherwise.
+ */
+int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
+{
+	struct rproc *rproc = rvdev->rproc;
+	struct device *dev = rproc->dev;
+	struct virtio_device *vdev = &rvdev->vdev;
+	int ret;
+
+	vdev->id.device	= id,
+	vdev->config = &rproc_virtio_config_ops,
+	vdev->dev.parent = dev;
+	vdev->dev.release = rproc_vdev_release;
+
+	/*
+	 * We're indirectly making a non-temporary copy of the rproc pointer
+	 * here, because drivers probed with this vdev will indirectly
+	 * access the wrapping rproc.
+	 *
+	 * Therefore we must increment the rproc refcount here, and decrement
+	 * it _only_ when the vdev is released.
+	 */
+	kref_get(&rproc->refcount);
+
+	ret = register_virtio_device(vdev);
+	if (ret) {
+		kref_put(&rproc->refcount, rproc_release);
+		dev_err(dev, "failed to register vdev: %d\n", ret);
+		goto out;
+	}
+
+	dev_info(dev, "registered %s (type %d)\n", dev_name(&vdev->dev), id);
+
+out:
+	return ret;
+}
+
+/**
+ * rproc_remove_virtio_dev() - remove an rproc-induced virtio device
+ * @rvdev: the remote vdev
+ *
+ * This function unregisters an existing virtio device.
+ */
+void rproc_remove_virtio_dev(struct rproc_vdev *rvdev)
+{
+	unregister_virtio_device(&rvdev->vdev);
+}
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
new file mode 100644
index 0000000..32aead6
--- /dev/null
+++ b/drivers/rpmsg/Kconfig
@@ -0,0 +1,10 @@
+menu "Rpmsg drivers (EXPERIMENTAL)"
+
+# RPMSG always gets selected by whoever wants it
+config RPMSG
+	tristate
+	select VIRTIO
+	select VIRTIO_RING
+	depends on EXPERIMENTAL
+
+endmenu
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
new file mode 100644
index 0000000..7617fcb
--- /dev/null
+++ b/drivers/rpmsg/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_RPMSG)	+= virtio_rpmsg_bus.o
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
new file mode 100644
index 0000000..75506ec
--- /dev/null
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -0,0 +1,1054 @@
+/*
+ * Virtio-based remote processor messaging bus
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * 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) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/rpmsg.h>
+#include <linux/mutex.h>
+
+/**
+ * struct virtproc_info - virtual remote processor state
+ * @vdev:	the virtio device
+ * @rvq:	rx virtqueue
+ * @svq:	tx virtqueue
+ * @rbufs:	kernel address of rx buffers
+ * @sbufs:	kernel address of tx buffers
+ * @last_sbuf:	index of last tx buffer used
+ * @bufs_dma:	dma base addr of the buffers
+ * @tx_lock:	protects svq, sbufs and sleepers, to allow concurrent senders.
+ *		sending a message might require waking up a dozing remote
+ *		processor, which involves sleeping, hence the mutex.
+ * @endpoints:	idr of local endpoints, allows fast retrieval
+ * @endpoints_lock: lock of the endpoints set
+ * @sendq:	wait queue of sending contexts waiting for a tx buffers
+ * @sleepers:	number of senders that are waiting for a tx buffer
+ * @ns_ept:	the bus's name service endpoint
+ *
+ * This structure stores the rpmsg state of a given virtio remote processor
+ * device (there might be several virtio proc devices for each physical
+ * remote processor).
+ */
+struct virtproc_info {
+	struct virtio_device *vdev;
+	struct virtqueue *rvq, *svq;
+	void *rbufs, *sbufs;
+	int last_sbuf;
+	dma_addr_t bufs_dma;
+	struct mutex tx_lock;
+	struct idr endpoints;
+	struct mutex endpoints_lock;
+	wait_queue_head_t sendq;
+	atomic_t sleepers;
+	struct rpmsg_endpoint *ns_ept;
+};
+
+/**
+ * struct rpmsg_channel_info - internal channel info representation
+ * @name: name of service
+ * @src: local address
+ * @dst: destination address
+ */
+struct rpmsg_channel_info {
+	char name[RPMSG_NAME_SIZE];
+	u32 src;
+	u32 dst;
+};
+
+#define to_rpmsg_channel(d) container_of(d, struct rpmsg_channel, dev)
+#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv)
+
+/*
+ * We're allocating 512 buffers of 512 bytes for communications, and then
+ * using the first 256 buffers for RX, and the last 256 buffers for TX.
+ *
+ * Each buffer will have 16 bytes for the msg header and 496 bytes for
+ * the payload.
+ *
+ * This will require a total space of 256KB for the buffers.
+ *
+ * We might also want to add support for user-provided buffers in time.
+ * This will allow bigger buffer size flexibility, and can also be used
+ * to achieve zero-copy messaging.
+ *
+ * Note that these numbers are purely a decision of this driver - we
+ * can change this without changing anything in the firmware of the remote
+ * processor.
+ */
+#define RPMSG_NUM_BUFS		(512)
+#define RPMSG_BUF_SIZE		(512)
+#define RPMSG_TOTAL_BUF_SPACE	(RPMSG_NUM_BUFS * RPMSG_BUF_SIZE)
+
+/*
+ * Local addresses are dynamically allocated on-demand.
+ * We do not dynamically assign addresses from the low 1024 range,
+ * in order to reserve that address range for predefined services.
+ */
+#define RPMSG_RESERVED_ADDRESSES	(1024)
+
+/* Address 53 is reserved for advertising remote services */
+#define RPMSG_NS_ADDR			(53)
+
+/* sysfs show configuration fields */
+#define rpmsg_show_attr(field, path, format_string)			\
+static ssize_t								\
+field##_show(struct device *dev,					\
+			struct device_attribute *attr, char *buf)	\
+{									\
+	struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);		\
+									\
+	return sprintf(buf, format_string, rpdev->path);		\
+}
+
+/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */
+rpmsg_show_attr(name, id.name, "%s\n");
+rpmsg_show_attr(src, src, "0x%x\n");
+rpmsg_show_attr(dst, dst, "0x%x\n");
+rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");
+
+/*
+ * Unique (and free running) index for rpmsg devices.
+ *
+ * Yeah, we're not recycling those numbers (yet?). will be easy
+ * to change if/when we want to.
+ */
+static unsigned int rpmsg_dev_index;
+
+static ssize_t modalias_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+
+	return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev->id.name);
+}
+
+static struct device_attribute rpmsg_dev_attrs[] = {
+	__ATTR_RO(name),
+	__ATTR_RO(modalias),
+	__ATTR_RO(dst),
+	__ATTR_RO(src),
+	__ATTR_RO(announce),
+	__ATTR_NULL
+};
+
+/* rpmsg devices and drivers are matched using the service name */
+static inline int rpmsg_id_match(const struct rpmsg_channel *rpdev,
+				  const struct rpmsg_device_id *id)
+{
+	return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) == 0;
+}
+
+/* match rpmsg channel and rpmsg driver */
+static int rpmsg_dev_match(struct device *dev, struct device_driver *drv)
+{
+	struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+	struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv);
+	const struct rpmsg_device_id *ids = rpdrv->id_table;
+	unsigned int i;
+
+	for (i = 0; ids[i].name[0]; i++)
+		if (rpmsg_id_match(rpdev, &ids[i]))
+			return 1;
+
+	return 0;
+}
+
+static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+
+	return add_uevent_var(env, "MODALIAS=" RPMSG_DEVICE_MODALIAS_FMT,
+					rpdev->id.name);
+}
+
+/* for more info, see below documentation of rpmsg_create_ept() */
+static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp,
+		struct rpmsg_channel *rpdev, rpmsg_rx_cb_t cb,
+		void *priv, u32 addr)
+{
+	int err, tmpaddr, request;
+	struct rpmsg_endpoint *ept;
+	struct device *dev = rpdev ? &rpdev->dev : &vrp->vdev->dev;
+
+	if (!idr_pre_get(&vrp->endpoints, GFP_KERNEL))
+		return NULL;
+
+	ept = kzalloc(sizeof(*ept), GFP_KERNEL);
+	if (!ept) {
+		dev_err(dev, "failed to kzalloc a new ept\n");
+		return NULL;
+	}
+
+	ept->rpdev = rpdev;
+	ept->cb = cb;
+	ept->priv = priv;
+
+	/* do we need to allocate a local address ? */
+	request = addr == RPMSG_ADDR_ANY ? RPMSG_RESERVED_ADDRESSES : addr;
+
+	mutex_lock(&vrp->endpoints_lock);
+
+	/* bind the endpoint to an rpmsg address (and allocate one if needed) */
+	err = idr_get_new_above(&vrp->endpoints, ept, request, &tmpaddr);
+	if (err) {
+		dev_err(dev, "idr_get_new_above failed: %d\n", err);
+		goto free_ept;
+	}
+
+	/* make sure the user's address request is fulfilled, if relevant */
+	if (addr != RPMSG_ADDR_ANY && tmpaddr != addr) {
+		dev_err(dev, "address 0x%x already in use\n", addr);
+		goto rem_idr;
+	}
+
+	ept->addr = tmpaddr;
+
+	mutex_unlock(&vrp->endpoints_lock);
+
+	return ept;
+
+rem_idr:
+	idr_remove(&vrp->endpoints, request);
+free_ept:
+	mutex_unlock(&vrp->endpoints_lock);
+	kfree(ept);
+	return NULL;
+}
+
+/**
+ * rpmsg_create_ept() - create a new rpmsg_endpoint
+ * @rpdev: rpmsg channel device
+ * @cb: rx callback handler
+ * @priv: private data for the driver's use
+ * @addr: local rpmsg address to bind with @cb
+ *
+ * Every rpmsg address in the system is bound to an rx callback (so when
+ * inbound messages arrive, they are dispatched by the rpmsg bus using the
+ * appropriate callback handler) by means of an rpmsg_endpoint struct.
+ *
+ * This function allows drivers to create such an endpoint, and by that,
+ * bind a callback, and possibly some private data too, to an rpmsg address
+ * (either one that is known in advance, or one that will be dynamically
+ * assigned for them).
+ *
+ * Simple rpmsg drivers need not call rpmsg_create_ept, because an endpoint
+ * is already created for them when they are probed by the rpmsg bus
+ * (using the rx callback provided when they registered to the rpmsg bus).
+ *
+ * So things should just work for simple drivers: they already have an
+ * endpoint, their rx callback is bound to their rpmsg address, and when
+ * relevant inbound messages arrive (i.e. messages which their dst address
+ * equals to the src address of their rpmsg channel), the driver's handler
+ * is invoked to process it.
+ *
+ * That said, more complicated drivers might do need to allocate
+ * additional rpmsg addresses, and bind them to different rx callbacks.
+ * To accomplish that, those drivers need to call this function.
+ *
+ * Drivers should provide their @rpdev channel (so the new endpoint would belong
+ * to the same remote processor their channel belongs to), an rx callback
+ * function, an optional private data (which is provided back when the
+ * rx callback is invoked), and an address they want to bind with the
+ * callback. If @addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will
+ * dynamically assign them an available rpmsg address (drivers should have
+ * a very good reason why not to always use RPMSG_ADDR_ANY here).
+ *
+ * Returns a pointer to the endpoint on success, or NULL on error.
+ */
+struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rpdev,
+				rpmsg_rx_cb_t cb, void *priv, u32 addr)
+{
+	return __rpmsg_create_ept(rpdev->vrp, rpdev, cb, priv, addr);
+}
+EXPORT_SYMBOL(rpmsg_create_ept);
+
+/**
+ * __rpmsg_destroy_ept() - destroy an existing rpmsg endpoint
+ * @vrp: virtproc which owns this ept
+ * @ept: endpoing to destroy
+ *
+ * An internal function which destroy an ept without assuming it is
+ * bound to an rpmsg channel. This is needed for handling the internal
+ * name service endpoint, which isn't bound to an rpmsg channel.
+ * See also __rpmsg_create_ept().
+ */
+static void
+__rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept)
+{
+	mutex_lock(&vrp->endpoints_lock);
+	idr_remove(&vrp->endpoints, ept->addr);
+	mutex_unlock(&vrp->endpoints_lock);
+
+	kfree(ept);
+}
+
+/**
+ * rpmsg_destroy_ept() - destroy an existing rpmsg endpoint
+ * @ept: endpoing to destroy
+ *
+ * Should be used by drivers to destroy an rpmsg endpoint previously
+ * created with rpmsg_create_ept().
+ */
+void rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
+{
+	__rpmsg_destroy_ept(ept->rpdev->vrp, ept);
+}
+EXPORT_SYMBOL(rpmsg_destroy_ept);
+
+/*
+ * when an rpmsg driver is probed with a channel, we seamlessly create
+ * it an endpoint, binding its rx callback to a unique local rpmsg
+ * address.
+ *
+ * if we need to, we also announce about this channel to the remote
+ * processor (needed in case the driver is exposing an rpmsg service).
+ */
+static int rpmsg_dev_probe(struct device *dev)
+{
+	struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+	struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
+	struct virtproc_info *vrp = rpdev->vrp;
+	struct rpmsg_endpoint *ept;
+	int err;
+
+	ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, rpdev->src);
+	if (!ept) {
+		dev_err(dev, "failed to create endpoint\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	rpdev->ept = ept;
+	rpdev->src = ept->addr;
+
+	err = rpdrv->probe(rpdev);
+	if (err) {
+		dev_err(dev, "%s: failed: %d\n", __func__, err);
+		rpmsg_destroy_ept(ept);
+		goto out;
+	}
+
+	/* need to tell remote processor's name service about this channel ? */
+	if (rpdev->announce &&
+			virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) {
+		struct rpmsg_ns_msg nsm;
+
+		strncpy(nsm.name, rpdev->id.name, RPMSG_NAME_SIZE);
+		nsm.addr = rpdev->src;
+		nsm.flags = RPMSG_NS_CREATE;
+
+		err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm), RPMSG_NS_ADDR);
+		if (err)
+			dev_err(dev, "failed to announce service %d\n", err);
+	}
+
+out:
+	return err;
+}
+
+static int rpmsg_dev_remove(struct device *dev)
+{
+	struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+	struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
+	struct virtproc_info *vrp = rpdev->vrp;
+	int err = 0;
+
+	/* tell remote processor's name service we're removing this channel */
+	if (rpdev->announce &&
+			virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) {
+		struct rpmsg_ns_msg nsm;
+
+		strncpy(nsm.name, rpdev->id.name, RPMSG_NAME_SIZE);
+		nsm.addr = rpdev->src;
+		nsm.flags = RPMSG_NS_DESTROY;
+
+		err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm), RPMSG_NS_ADDR);
+		if (err)
+			dev_err(dev, "failed to announce service %d\n", err);
+	}
+
+	rpdrv->remove(rpdev);
+
+	rpmsg_destroy_ept(rpdev->ept);
+
+	return err;
+}
+
+static struct bus_type rpmsg_bus = {
+	.name		= "rpmsg",
+	.match		= rpmsg_dev_match,
+	.dev_attrs	= rpmsg_dev_attrs,
+	.uevent		= rpmsg_uevent,
+	.probe		= rpmsg_dev_probe,
+	.remove		= rpmsg_dev_remove,
+};
+
+/**
+ * register_rpmsg_driver() - register an rpmsg driver with the rpmsg bus
+ * @rpdrv: pointer to a struct rpmsg_driver
+ *
+ * Returns 0 on success, and an appropriate error value on failure.
+ */
+int register_rpmsg_driver(struct rpmsg_driver *rpdrv)
+{
+	rpdrv->drv.bus = &rpmsg_bus;
+	return driver_register(&rpdrv->drv);
+}
+EXPORT_SYMBOL(register_rpmsg_driver);
+
+/**
+ * unregister_rpmsg_driver() - unregister an rpmsg driver from the rpmsg bus
+ * @rpdrv: pointer to a struct rpmsg_driver
+ *
+ * Returns 0 on success, and an appropriate error value on failure.
+ */
+void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv)
+{
+	driver_unregister(&rpdrv->drv);
+}
+EXPORT_SYMBOL(unregister_rpmsg_driver);
+
+static void rpmsg_release_device(struct device *dev)
+{
+	struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+
+	kfree(rpdev);
+}
+
+/*
+ * match an rpmsg channel with a channel info struct.
+ * this is used to make sure we're not creating rpmsg devices for channels
+ * that already exist.
+ */
+static int rpmsg_channel_match(struct device *dev, void *data)
+{
+	struct rpmsg_channel_info *chinfo = data;
+	struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+
+	if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src)
+		return 0;
+
+	if (chinfo->dst != RPMSG_ADDR_ANY && chinfo->dst != rpdev->dst)
+		return 0;
+
+	if (strncmp(chinfo->name, rpdev->id.name, RPMSG_NAME_SIZE))
+		return 0;
+
+	/* found a match ! */
+	return 1;
+}
+
+/*
+ * create an rpmsg channel using its name and address info.
+ * this function will be used to create both static and dynamic
+ * channels.
+ */
+static struct rpmsg_channel *rpmsg_create_channel(struct virtproc_info *vrp,
+				struct rpmsg_channel_info *chinfo)
+{
+	struct rpmsg_channel *rpdev;
+	struct device *tmp, *dev = &vrp->vdev->dev;
+	int ret;
+
+	/* make sure a similar channel doesn't already exist */
+	tmp = device_find_child(dev, chinfo, rpmsg_channel_match);
+	if (tmp) {
+		/* decrement the matched device's refcount back */
+		put_device(tmp);
+		dev_err(dev, "channel %s:%x:%x already exist\n",
+				chinfo->name, chinfo->src, chinfo->dst);
+		return NULL;
+	}
+
+	rpdev = kzalloc(sizeof(struct rpmsg_channel), GFP_KERNEL);
+	if (!rpdev) {
+		pr_err("kzalloc failed\n");
+		return NULL;
+	}
+
+	rpdev->vrp = vrp;
+	rpdev->src = chinfo->src;
+	rpdev->dst = chinfo->dst;
+
+	/*
+	 * rpmsg server channels has predefined local address (for now),
+	 * and their existence needs to be announced remotely
+	 */
+	rpdev->announce = rpdev->src != RPMSG_ADDR_ANY ? true : false;
+
+	strncpy(rpdev->id.name, chinfo->name, RPMSG_NAME_SIZE);
+
+	/* very simple device indexing plumbing which is enough for now */
+	dev_set_name(&rpdev->dev, "rpmsg%d", rpmsg_dev_index++);
+
+	rpdev->dev.parent = &vrp->vdev->dev;
+	rpdev->dev.bus = &rpmsg_bus;
+	rpdev->dev.release = rpmsg_release_device;
+
+	ret = device_register(&rpdev->dev);
+	if (ret) {
+		dev_err(dev, "device_register failed: %d\n", ret);
+		put_device(&rpdev->dev);
+		return NULL;
+	}
+
+	return rpdev;
+}
+
+/*
+ * find an existing channel using its name + address properties,
+ * and destroy it
+ */
+static int rpmsg_destroy_channel(struct virtproc_info *vrp,
+					struct rpmsg_channel_info *chinfo)
+{
+	struct virtio_device *vdev = vrp->vdev;
+	struct device *dev;
+
+	dev = device_find_child(&vdev->dev, chinfo, rpmsg_channel_match);
+	if (!dev)
+		return -EINVAL;
+
+	device_unregister(dev);
+
+	put_device(dev);
+
+	return 0;
+}
+
+/* super simple buffer "allocator" that is just enough for now */
+static void *get_a_tx_buf(struct virtproc_info *vrp)
+{
+	unsigned int len;
+	void *ret;
+
+	/* support multiple concurrent senders */
+	mutex_lock(&vrp->tx_lock);
+
+	/*
+	 * either pick the next unused tx buffer
+	 * (half of our buffers are used for sending messages)
+	 */
+	if (vrp->last_sbuf < RPMSG_NUM_BUFS / 2)
+		ret = vrp->sbufs + RPMSG_BUF_SIZE * vrp->last_sbuf++;
+	/* or recycle a used one */
+	else
+		ret = virtqueue_get_buf(vrp->svq, &len);
+
+	mutex_unlock(&vrp->tx_lock);
+
+	return ret;
+}
+
+/**
+ * rpmsg_upref_sleepers() - enable "tx-complete" interrupts, if needed
+ * @vrp: virtual remote processor state
+ *
+ * This function is called before a sender is blocked, waiting for
+ * a tx buffer to become available.
+ *
+ * If we already have blocking senders, this function merely increases
+ * the "sleepers" reference count, and exits.
+ *
+ * Otherwise, if this is the first sender to block, we also enable
+ * virtio's tx callbacks, so we'd be immediately notified when a tx
+ * buffer is consumed (we rely on virtio's tx callback in order
+ * to wake up sleeping senders as soon as a tx buffer is used by the
+ * remote processor).
+ */
+static void rpmsg_upref_sleepers(struct virtproc_info *vrp)
+{
+	/* support multiple concurrent senders */
+	mutex_lock(&vrp->tx_lock);
+
+	/* are we the first sleeping context waiting for tx buffers ? */
+	if (atomic_inc_return(&vrp->sleepers) == 1)
+		/* enable "tx-complete" interrupts before dozing off */
+		virtqueue_enable_cb(vrp->svq);
+
+	mutex_unlock(&vrp->tx_lock);
+}
+
+/**
+ * rpmsg_downref_sleepers() - disable "tx-complete" interrupts, if needed
+ * @vrp: virtual remote processor state
+ *
+ * This function is called after a sender, that waited for a tx buffer
+ * to become available, is unblocked.
+ *
+ * If we still have blocking senders, this function merely decreases
+ * the "sleepers" reference count, and exits.
+ *
+ * Otherwise, if there are no more blocking senders, we also disable
+ * virtio's tx callbacks, to avoid the overhead incurred with handling
+ * those (now redundant) interrupts.
+ */
+static void rpmsg_downref_sleepers(struct virtproc_info *vrp)
+{
+	/* support multiple concurrent senders */
+	mutex_lock(&vrp->tx_lock);
+
+	/* are we the last sleeping context waiting for tx buffers ? */
+	if (atomic_dec_and_test(&vrp->sleepers))
+		/* disable "tx-complete" interrupts */
+		virtqueue_disable_cb(vrp->svq);
+
+	mutex_unlock(&vrp->tx_lock);
+}
+
+/**
+ * rpmsg_send_offchannel_raw() - send a message across to the remote processor
+ * @rpdev: the rpmsg channel
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ * @wait: indicates whether caller should block in case no TX buffers available
+ *
+ * This function is the base implementation for all of the rpmsg sending API.
+ *
+ * It will send @data of length @len to @dst, and say it's from @src. The
+ * message will be sent to the remote processor which the @rpdev channel
+ * belongs to.
+ *
+ * The message is sent using one of the TX buffers that are available for
+ * communication with this remote processor.
+ *
+ * If @wait is true, the caller will be blocked until either a TX buffer is
+ * available, or 15 seconds elapses (we don't want callers to
+ * sleep indefinitely due to misbehaving remote processors), and in that
+ * case -ERESTARTSYS is returned. The number '15' itself was picked
+ * arbitrarily; there's little point in asking drivers to provide a timeout
+ * value themselves.
+ *
+ * Otherwise, if @wait is false, and there are no TX buffers available,
+ * the function will immediately fail, and -ENOMEM will be returned.
+ *
+ * Normally drivers shouldn't use this function directly; instead, drivers
+ * should use the appropriate rpmsg_{try}send{to, _offchannel} API
+ * (see include/linux/rpmsg.h).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+					void *data, int len, bool wait)
+{
+	struct virtproc_info *vrp = rpdev->vrp;
+	struct device *dev = &rpdev->dev;
+	struct scatterlist sg;
+	struct rpmsg_hdr *msg;
+	int err;
+
+	/* bcasting isn't allowed */
+	if (src == RPMSG_ADDR_ANY || dst == RPMSG_ADDR_ANY) {
+		dev_err(dev, "invalid addr (src 0x%x, dst 0x%x)\n", src, dst);
+		return -EINVAL;
+	}
+
+	/*
+	 * We currently use fixed-sized buffers, and therefore the payload
+	 * length is limited.
+	 *
+	 * One of the possible improvements here is either to support
+	 * user-provided buffers (and then we can also support zero-copy
+	 * messaging), or to improve the buffer allocator, to support
+	 * variable-length buffer sizes.
+	 */
+	if (len > RPMSG_BUF_SIZE - sizeof(struct rpmsg_hdr)) {
+		dev_err(dev, "message is too big (%d)\n", len);
+		return -EMSGSIZE;
+	}
+
+	/* grab a buffer */
+	msg = get_a_tx_buf(vrp);
+	if (!msg && !wait)
+		return -ENOMEM;
+
+	/* no free buffer ? wait for one (but bail after 15 seconds) */
+	while (!msg) {
+		/* enable "tx-complete" interrupts, if not already enabled */
+		rpmsg_upref_sleepers(vrp);
+
+		/*
+		 * sleep until a free buffer is available or 15 secs elapse.
+		 * the timeout period is not configurable because there's
+		 * little point in asking drivers to specify that.
+		 * if later this happens to be required, it'd be easy to add.
+		 */
+		err = wait_event_interruptible_timeout(vrp->sendq,
+					(msg = get_a_tx_buf(vrp)),
+					msecs_to_jiffies(15000));
+
+		/* disable "tx-complete" interrupts if we're the last sleeper */
+		rpmsg_downref_sleepers(vrp);
+
+		/* timeout ? */
+		if (!err) {
+			dev_err(dev, "timeout waiting for a tx buffer\n");
+			return -ERESTARTSYS;
+		}
+	}
+
+	msg->len = len;
+	msg->flags = 0;
+	msg->src = src;
+	msg->dst = dst;
+	msg->reserved = 0;
+	memcpy(msg->data, data, len);
+
+	dev_dbg(dev, "TX From 0x%x, To 0x%x, Len %d, Flags %d, Reserved %d\n",
+					msg->src, msg->dst, msg->len,
+					msg->flags, msg->reserved);
+	print_hex_dump(KERN_DEBUG, "rpmsg_virtio TX: ", DUMP_PREFIX_NONE, 16, 1,
+					msg, sizeof(*msg) + msg->len, true);
+
+	sg_init_one(&sg, msg, sizeof(*msg) + len);
+
+	mutex_lock(&vrp->tx_lock);
+
+	/* add message to the remote processor's virtqueue */
+	err = virtqueue_add_buf(vrp->svq, &sg, 1, 0, msg, GFP_KERNEL);
+	if (err < 0) {
+		/*
+		 * need to reclaim the buffer here, otherwise it's lost
+		 * (memory won't leak, but rpmsg won't use it again for TX).
+		 * this will wait for a buffer management overhaul.
+		 */
+		dev_err(dev, "virtqueue_add_buf failed: %d\n", err);
+		goto out;
+	}
+
+	/* tell the remote processor it has a pending message to read */
+	virtqueue_kick(vrp->svq);
+
+	err = 0;
+out:
+	mutex_unlock(&vrp->tx_lock);
+	return err;
+}
+EXPORT_SYMBOL(rpmsg_send_offchannel_raw);
+
+/* called when an rx buffer is used, and it's time to digest a message */
+static void rpmsg_recv_done(struct virtqueue *rvq)
+{
+	struct rpmsg_hdr *msg;
+	unsigned int len;
+	struct rpmsg_endpoint *ept;
+	struct scatterlist sg;
+	struct virtproc_info *vrp = rvq->vdev->priv;
+	struct device *dev = &rvq->vdev->dev;
+	int err;
+
+	msg = virtqueue_get_buf(rvq, &len);
+	if (!msg) {
+		dev_err(dev, "uhm, incoming signal, but no used buffer ?\n");
+		return;
+	}
+
+	dev_dbg(dev, "From: 0x%x, To: 0x%x, Len: %d, Flags: %d, Reserved: %d\n",
+					msg->src, msg->dst, msg->len,
+					msg->flags, msg->reserved);
+	print_hex_dump(KERN_DEBUG, "rpmsg_virtio RX: ", DUMP_PREFIX_NONE, 16, 1,
+					msg, sizeof(*msg) + msg->len, true);
+
+	/*
+	 * We currently use fixed-sized buffers, so trivially sanitize
+	 * the reported payload length.
+	 */
+	if (len > RPMSG_BUF_SIZE ||
+		msg->len > (len - sizeof(struct rpmsg_hdr))) {
+		dev_warn(dev, "inbound msg too big: (%d, %d)\n", len, msg->len);
+		return;
+	}
+
+	/* use the dst addr to fetch the callback of the appropriate user */
+	mutex_lock(&vrp->endpoints_lock);
+	ept = idr_find(&vrp->endpoints, msg->dst);
+	mutex_unlock(&vrp->endpoints_lock);
+
+	if (ept && ept->cb)
+		ept->cb(ept->rpdev, msg->data, msg->len, ept->priv, msg->src);
+	else
+		dev_warn(dev, "msg received with no recepient\n");
+
+	/* publish the real size of the buffer */
+	sg_init_one(&sg, msg, RPMSG_BUF_SIZE);
+
+	/* add the buffer back to the remote processor's virtqueue */
+	err = virtqueue_add_buf(vrp->rvq, &sg, 0, 1, msg, GFP_KERNEL);
+	if (err < 0) {
+		dev_err(dev, "failed to add a virtqueue buffer: %d\n", err);
+		return;
+	}
+
+	/* tell the remote processor we added another available rx buffer */
+	virtqueue_kick(vrp->rvq);
+}
+
+/*
+ * This is invoked whenever the remote processor completed processing
+ * a TX msg we just sent it, and the buffer is put back to the used ring.
+ *
+ * Normally, though, we suppress this "tx complete" interrupt in order to
+ * avoid the incurred overhead.
+ */
+static void rpmsg_xmit_done(struct virtqueue *svq)
+{
+	struct virtproc_info *vrp = svq->vdev->priv;
+
+	dev_dbg(&svq->vdev->dev, "%s\n", __func__);
+
+	/* wake up potential senders that are waiting for a tx buffer */
+	wake_up_interruptible(&vrp->sendq);
+}
+
+/* invoked when a name service announcement arrives */
+static void rpmsg_ns_cb(struct rpmsg_channel *rpdev, void *data, int len,
+							void *priv, u32 src)
+{
+	struct rpmsg_ns_msg *msg = data;
+	struct rpmsg_channel *newch;
+	struct rpmsg_channel_info chinfo;
+	struct virtproc_info *vrp = priv;
+	struct device *dev = &vrp->vdev->dev;
+	int ret;
+
+	print_hex_dump(KERN_DEBUG, "NS announcement: ",
+			DUMP_PREFIX_NONE, 16, 1,
+			data, len, true);
+
+	if (len != sizeof(*msg)) {
+		dev_err(dev, "malformed ns msg (%d)\n", len);
+		return;
+	}
+
+	/*
+	 * the name service ept does _not_ belong to a real rpmsg channel,
+	 * and is handled by the rpmsg bus itself.
+	 * for sanity reasons, make sure a valid rpdev has _not_ sneaked
+	 * in somehow.
+	 */
+	if (rpdev) {
+		dev_err(dev, "anomaly: ns ept has an rpdev handle\n");
+		return;
+	}
+
+	/* don't trust the remote processor for null terminating the name */
+	msg->name[RPMSG_NAME_SIZE - 1] = '\0';
+
+	dev_info(dev, "%sing channel %s addr 0x%x\n",
+			msg->flags & RPMSG_NS_DESTROY ? "destroy" : "creat",
+			msg->name, msg->addr);
+
+	strncpy(chinfo.name, msg->name, sizeof(chinfo.name));
+	chinfo.src = RPMSG_ADDR_ANY;
+	chinfo.dst = msg->addr;
+
+	if (msg->flags & RPMSG_NS_DESTROY) {
+		ret = rpmsg_destroy_channel(vrp, &chinfo);
+		if (ret)
+			dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret);
+	} else {
+		newch = rpmsg_create_channel(vrp, &chinfo);
+		if (!newch)
+			dev_err(dev, "rpmsg_create_channel failed\n");
+	}
+}
+
+static int rpmsg_probe(struct virtio_device *vdev)
+{
+	vq_callback_t *vq_cbs[] = { rpmsg_recv_done, rpmsg_xmit_done };
+	const char *names[] = { "input", "output" };
+	struct virtqueue *vqs[2];
+	struct virtproc_info *vrp;
+	void *bufs_va;
+	int err = 0, i;
+
+	vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
+	if (!vrp)
+		return -ENOMEM;
+
+	vrp->vdev = vdev;
+
+	idr_init(&vrp->endpoints);
+	mutex_init(&vrp->endpoints_lock);
+	mutex_init(&vrp->tx_lock);
+	init_waitqueue_head(&vrp->sendq);
+
+	/* We expect two virtqueues, rx and tx (and in this order) */
+	err = vdev->config->find_vqs(vdev, 2, vqs, vq_cbs, names);
+	if (err)
+		goto free_vrp;
+
+	vrp->rvq = vqs[0];
+	vrp->svq = vqs[1];
+
+	/* allocate coherent memory for the buffers */
+	bufs_va = dma_alloc_coherent(vdev->dev.parent, RPMSG_TOTAL_BUF_SPACE,
+				&vrp->bufs_dma, GFP_KERNEL);
+	if (!bufs_va)
+		goto vqs_del;
+
+	dev_dbg(&vdev->dev, "buffers: va %p, dma 0x%llx\n", bufs_va,
+					(unsigned long long)vrp->bufs_dma);
+
+	/* half of the buffers is dedicated for RX */
+	vrp->rbufs = bufs_va;
+
+	/* and half is dedicated for TX */
+	vrp->sbufs = bufs_va + RPMSG_TOTAL_BUF_SPACE / 2;
+
+	/* set up the receive buffers */
+	for (i = 0; i < RPMSG_NUM_BUFS / 2; i++) {
+		struct scatterlist sg;
+		void *cpu_addr = vrp->rbufs + i * RPMSG_BUF_SIZE;
+
+		sg_init_one(&sg, cpu_addr, RPMSG_BUF_SIZE);
+
+		err = virtqueue_add_buf(vrp->rvq, &sg, 0, 1, cpu_addr,
+								GFP_KERNEL);
+		WARN_ON(err < 0); /* sanity check; this can't really happen */
+	}
+
+	/* suppress "tx-complete" interrupts */
+	virtqueue_disable_cb(vrp->svq);
+
+	vdev->priv = vrp;
+
+	/* if supported by the remote processor, enable the name service */
+	if (virtio_has_feature(vdev, VIRTIO_RPMSG_F_NS)) {
+		/* a dedicated endpoint handles the name service msgs */
+		vrp->ns_ept = __rpmsg_create_ept(vrp, NULL, rpmsg_ns_cb,
+						vrp, RPMSG_NS_ADDR);
+		if (!vrp->ns_ept) {
+			dev_err(&vdev->dev, "failed to create the ns ept\n");
+			err = -ENOMEM;
+			goto free_coherent;
+		}
+	}
+
+	/* tell the remote processor it can start sending messages */
+	virtqueue_kick(vrp->rvq);
+
+	dev_info(&vdev->dev, "rpmsg host is online\n");
+
+	return 0;
+
+free_coherent:
+	dma_free_coherent(vdev->dev.parent, RPMSG_TOTAL_BUF_SPACE, bufs_va,
+					vrp->bufs_dma);
+vqs_del:
+	vdev->config->del_vqs(vrp->vdev);
+free_vrp:
+	kfree(vrp);
+	return err;
+}
+
+static int rpmsg_remove_device(struct device *dev, void *data)
+{
+	device_unregister(dev);
+
+	return 0;
+}
+
+static void __devexit rpmsg_remove(struct virtio_device *vdev)
+{
+	struct virtproc_info *vrp = vdev->priv;
+	int ret;
+
+	vdev->config->reset(vdev);
+
+	ret = device_for_each_child(&vdev->dev, NULL, rpmsg_remove_device);
+	if (ret)
+		dev_warn(&vdev->dev, "can't remove rpmsg device: %d\n", ret);
+
+	if (vrp->ns_ept)
+		__rpmsg_destroy_ept(vrp, vrp->ns_ept);
+
+	idr_remove_all(&vrp->endpoints);
+	idr_destroy(&vrp->endpoints);
+
+	vdev->config->del_vqs(vrp->vdev);
+
+	dma_free_coherent(vdev->dev.parent, RPMSG_TOTAL_BUF_SPACE,
+					vrp->rbufs, vrp->bufs_dma);
+
+	kfree(vrp);
+}
+
+static struct virtio_device_id id_table[] = {
+	{ VIRTIO_ID_RPMSG, VIRTIO_DEV_ANY_ID },
+	{ 0 },
+};
+
+static unsigned int features[] = {
+	VIRTIO_RPMSG_F_NS,
+};
+
+static struct virtio_driver virtio_ipc_driver = {
+	.feature_table	= features,
+	.feature_table_size = ARRAY_SIZE(features),
+	.driver.name	= KBUILD_MODNAME,
+	.driver.owner	= THIS_MODULE,
+	.id_table	= id_table,
+	.probe		= rpmsg_probe,
+	.remove		= __devexit_p(rpmsg_remove),
+};
+
+static int __init rpmsg_init(void)
+{
+	int ret;
+
+	ret = bus_register(&rpmsg_bus);
+	if (ret) {
+		pr_err("failed to register rpmsg bus: %d\n", ret);
+		return ret;
+	}
+
+	ret = register_virtio_driver(&virtio_ipc_driver);
+	if (ret) {
+		pr_err("failed to register virtio driver: %d\n", ret);
+		bus_unregister(&rpmsg_bus);
+	}
+
+	return ret;
+}
+module_init(rpmsg_init);
+
+static void __exit rpmsg_fini(void)
+{
+	unregister_virtio_driver(&virtio_ipc_driver);
+	bus_unregister(&rpmsg_bus);
+}
+module_exit(rpmsg_fini);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio-based remote processor messaging bus");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 3a125b8..8c8377d 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -554,6 +554,13 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-ds1742.
 
+config RTC_DRV_DA9052
+	tristate "Dialog DA9052/DA9053 RTC"
+	depends on PMIC_DA9052
+	help
+	  Say y here to support the RTC driver for Dialog Semiconductor
+	  DA9052-BC and DA9053-AA/Bx PMICs.
+
 config RTC_DRV_EFI
 	tristate "EFI RTC"
 	depends on IA64
@@ -748,7 +755,7 @@
 
 config RTC_DRV_S3C
 	tristate "Samsung S3C series SoC RTC"
-	depends on ARCH_S3C2410 || ARCH_S3C64XX || HAVE_S3C_RTC
+	depends on ARCH_S3C64XX || HAVE_S3C_RTC
 	help
 	  RTC (Realtime Clock) driver for the clock inbuilt into the
 	  Samsung S3C24XX series of SoCs. This can provide periodic
@@ -773,8 +780,8 @@
 	  will be called rtc-ep93xx.
 
 config RTC_DRV_SA1100
-	tristate "SA11x0/PXA2xx"
-	depends on ARCH_SA1100 || ARCH_PXA
+	tristate "SA11x0/PXA2xx/PXA910"
+	depends on ARCH_SA1100 || ARCH_PXA || ARCH_MMP
 	help
 	  If you say Y here you will get access to the real time clock
 	  built into your SA11x0 or PXA2xx CPU.
@@ -1070,4 +1077,14 @@
 	  This drive can also be built as a module. If so, the module
 	  will be called rtc-puv3.
 
+config RTC_DRV_LOONGSON1
+	tristate "loongson1 RTC support"
+	depends on MACH_LOONGSON1
+	help
+	  This is a driver for the loongson1 on-chip Counter0 (Time-Of-Year
+	  counter) to be used as a RTC.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-ls1x.
+
 endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 6e69823..727ae77 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -27,6 +27,7 @@
 obj-$(CONFIG_RTC_DRV_BQ4802)	+= rtc-bq4802.o
 obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc-cmos.o
 obj-$(CONFIG_RTC_DRV_COH901331)	+= rtc-coh901331.o
+obj-$(CONFIG_RTC_DRV_DA9052)	+= rtc-da9052.o
 obj-$(CONFIG_RTC_DRV_DAVINCI)	+= rtc-davinci.o
 obj-$(CONFIG_RTC_DRV_DM355EVM)	+= rtc-dm355evm.o
 obj-$(CONFIG_RTC_DRV_VRTC)	+= rtc-mrst.o
@@ -53,6 +54,7 @@
 obj-$(CONFIG_RTC_DRV_ISL12022)	+= rtc-isl12022.o
 obj-$(CONFIG_RTC_DRV_JZ4740)	+= rtc-jz4740.o
 obj-$(CONFIG_RTC_DRV_LPC32XX)	+= rtc-lpc32xx.o
+obj-$(CONFIG_RTC_DRV_LOONGSON1)	+= rtc-ls1x.o
 obj-$(CONFIG_RTC_DRV_M41T80)	+= rtc-m41t80.o
 obj-$(CONFIG_RTC_DRV_M41T93)	+= rtc-m41t93.o
 obj-$(CONFIG_RTC_DRV_M41T94)	+= rtc-m41t94.o
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index dc87eda..eb415bd 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -458,6 +458,11 @@
 	if (rtc->uie_rtctimer.enabled == enabled)
 		goto out;
 
+	if (rtc->uie_unsupported) {
+		err = -EINVAL;
+		goto out;
+	}
+
 	if (enabled) {
 		struct rtc_time tm;
 		ktime_t now, onesec;
diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c
index f04761e..feddefc 100644
--- a/drivers/rtc/rtc-88pm860x.c
+++ b/drivers/rtc/rtc-88pm860x.c
@@ -72,9 +72,9 @@
 	struct pm860x_rtc_info *info = dev_get_drvdata(dev);
 
 	if (enabled)
-		pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, ALARM);
+		pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM_EN, ALARM_EN);
 	else
-		pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, 0);
+		pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM_EN, 0);
 	return 0;
 }
 
@@ -376,6 +376,9 @@
 	INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work);
 	schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
 #endif	/* VRTC_CALIBRATION */
+
+	device_init_wakeup(&pdev->dev, 1);
+
 	return 0;
 out_rtc:
 	free_irq(info->irq, info);
@@ -401,10 +404,34 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_rtc_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+	if (device_may_wakeup(dev))
+		chip->wakeup_flag |= 1 << PM8607_IRQ_RTC;
+	return 0;
+}
+static int pm860x_rtc_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+	if (device_may_wakeup(dev))
+		chip->wakeup_flag &= ~(1 << PM8607_IRQ_RTC);
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_rtc_pm_ops, pm860x_rtc_suspend, pm860x_rtc_resume);
+
 static struct platform_driver pm860x_rtc_driver = {
 	.driver		= {
 		.name	= "88pm860x-rtc",
 		.owner	= THIS_MODULE,
+		.pm	= &pm860x_rtc_pm_ops,
 	},
 	.probe		= pm860x_rtc_probe,
 	.remove		= __devexit_p(pm860x_rtc_remove),
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
index ee3c122..8318689 100644
--- a/drivers/rtc/rtc-at91sam9.c
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -57,6 +57,7 @@
 	void __iomem		*rtt;
 	struct rtc_device	*rtcdev;
 	u32			imr;
+	void __iomem		*gpbr;
 };
 
 #define rtt_readl(rtc, field) \
@@ -65,9 +66,9 @@
 	__raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field)
 
 #define gpbr_readl(rtc) \
-	at91_sys_read(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR)
+	__raw_readl((rtc)->gpbr)
 #define gpbr_writel(rtc, val) \
-	at91_sys_write(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR, (val))
+	__raw_writel((val), (rtc)->gpbr)
 
 /*
  * Read current time and date in RTC
@@ -287,16 +288,19 @@
 /*
  * Initialize and install RTC driver
  */
-static int __init at91_rtc_probe(struct platform_device *pdev)
+static int __devinit at91_rtc_probe(struct platform_device *pdev)
 {
-	struct resource	*r;
+	struct resource	*r, *r_gpbr;
 	struct sam9_rtc	*rtc;
 	int		ret;
 	u32		mr;
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!r)
+	r_gpbr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!r || !r_gpbr) {
+		dev_err(&pdev->dev, "need 2 ressources\n");
 		return -ENODEV;
+	}
 
 	rtc = kzalloc(sizeof *rtc, GFP_KERNEL);
 	if (!rtc)
@@ -314,6 +318,13 @@
 		goto fail;
 	}
 
+	rtc->gpbr = ioremap(r_gpbr->start, resource_size(r_gpbr));
+	if (!rtc->gpbr) {
+		dev_err(&pdev->dev, "failed to map gpbr registers, aborting.\n");
+		ret = -ENOMEM;
+		goto fail_gpbr;
+	}
+
 	mr = rtt_readl(rtc, MR);
 
 	/* unless RTT is counting at 1 Hz, re-initialize it */
@@ -335,12 +346,12 @@
 
 	/* register irq handler after we know what name we'll use */
 	ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
-				IRQF_DISABLED | IRQF_SHARED,
+				IRQF_SHARED,
 				dev_name(&rtc->rtcdev->dev), rtc);
 	if (ret) {
 		dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS);
 		rtc_device_unregister(rtc->rtcdev);
-		goto fail;
+		goto fail_register;
 	}
 
 	/* NOTE:  sam9260 rev A silicon has a ROM bug which resets the
@@ -356,6 +367,8 @@
 	return 0;
 
 fail_register:
+	iounmap(rtc->gpbr);
+fail_gpbr:
 	iounmap(rtc->rtt);
 fail:
 	platform_set_drvdata(pdev, NULL);
@@ -366,7 +379,7 @@
 /*
  * Disable and remove the RTC driver
  */
-static int __exit at91_rtc_remove(struct platform_device *pdev)
+static int __devexit at91_rtc_remove(struct platform_device *pdev)
 {
 	struct sam9_rtc	*rtc = platform_get_drvdata(pdev);
 	u32		mr = rtt_readl(rtc, MR);
@@ -377,6 +390,7 @@
 
 	rtc_device_unregister(rtc->rtcdev);
 
+	iounmap(rtc->gpbr);
 	iounmap(rtc->rtt);
 	platform_set_drvdata(pdev, NULL);
 	kfree(rtc);
@@ -440,63 +454,20 @@
 #endif
 
 static struct platform_driver at91_rtc_driver = {
-	.driver.name	= "rtc-at91sam9",
-	.driver.owner	= THIS_MODULE,
-	.remove		= __exit_p(at91_rtc_remove),
+	.probe		= at91_rtc_probe,
+	.remove		= __devexit_p(at91_rtc_remove),
 	.shutdown	= at91_rtc_shutdown,
 	.suspend	= at91_rtc_suspend,
 	.resume		= at91_rtc_resume,
+	.driver		= {
+		.name	= "rtc-at91sam9",
+		.owner	= THIS_MODULE,
+	},
 };
 
-/* Chips can have more than one RTT module, and they can be used for more
- * than just RTCs.  So we can't just register as "the" RTT driver.
- *
- * A normal approach in such cases is to create a library to allocate and
- * free the modules.  Here we just use bus_find_device() as like such a
- * library, binding directly ... no runtime "library" footprint is needed.
- */
-static int __init at91_rtc_match(struct device *dev, void *v)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-	int ret;
-
-	/* continue searching if this isn't the RTT we need */
-	if (strcmp("at91_rtt", pdev->name) != 0
-			|| pdev->id != CONFIG_RTC_DRV_AT91SAM9_RTT)
-		goto fail;
-
-	/* else we found it ... but fail unless we can bind to the RTC driver */
-	if (dev->driver) {
-		dev_dbg(dev, "busy, can't use as RTC!\n");
-		goto fail;
-	}
-	dev->driver = &at91_rtc_driver.driver;
-	if (device_attach(dev) == 0) {
-		dev_dbg(dev, "can't attach RTC!\n");
-		goto fail;
-	}
-	ret = at91_rtc_probe(pdev);
-	if (ret == 0)
-		return true;
-
-	dev_dbg(dev, "RTC probe err %d!\n", ret);
-fail:
-	return false;
-}
-
 static int __init at91_rtc_init(void)
 {
-	int status;
-	struct device *rtc;
-
-	status = platform_driver_register(&at91_rtc_driver);
-	if (status)
-		return status;
-	rtc = bus_find_device(&platform_bus_type, NULL,
-			NULL, at91_rtc_match);
-	if (!rtc)
-		platform_driver_unregister(&at91_rtc_driver);
-	return rtc ? 0 : -ENODEV;
+	return platform_driver_register(&at91_rtc_driver);
 }
 module_init(at91_rtc_init);
 
diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c
index 408cc8f..f090159 100644
--- a/drivers/rtc/rtc-bq32k.c
+++ b/drivers/rtc/rtc-bq32k.c
@@ -187,17 +187,7 @@
 	.id_table	= bq32k_id,
 };
 
-static __init int bq32k_init(void)
-{
-	return i2c_add_driver(&bq32k_driver);
-}
-module_init(bq32k_init);
-
-static __exit void bq32k_exit(void)
-{
-	i2c_del_driver(&bq32k_driver);
-}
-module_exit(bq32k_exit);
+module_i2c_driver(bq32k_driver);
 
 MODULE_AUTHOR("Semihalf, Piotr Ziecik <kosmo@semihalf.com>");
 MODULE_DESCRIPTION("TI BQ32000 I2C RTC driver");
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index d7782aa..7d5f56e 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -714,7 +714,7 @@
 			rtc_cmos_int_handler = cmos_interrupt;
 
 		retval = request_irq(rtc_irq, rtc_cmos_int_handler,
-				IRQF_DISABLED, dev_name(&cmos_rtc.rtc->dev),
+				0, dev_name(&cmos_rtc.rtc->dev),
 				cmos_rtc.rtc);
 		if (retval < 0) {
 			dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c
index 80f9c88..a5b8a0c 100644
--- a/drivers/rtc/rtc-coh901331.c
+++ b/drivers/rtc/rtc-coh901331.c
@@ -199,7 +199,7 @@
 	}
 
 	rtap->irq = platform_get_irq(pdev, 0);
-	if (request_irq(rtap->irq, coh901331_interrupt, IRQF_DISABLED,
+	if (request_irq(rtap->irq, coh901331_interrupt, 0,
 			"RTC COH 901 331 Alarm", rtap)) {
 		ret = -EIO;
 		goto out_no_irq;
diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c
new file mode 100644
index 0000000..da6ab52
--- /dev/null
+++ b/drivers/rtc/rtc-da9052.c
@@ -0,0 +1,293 @@
+/*
+ * Real time clock driver for DA9052
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: Dajun Dajun Chen <dajun.chen@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/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+
+#define rtc_err(da9052, fmt, ...) \
+		dev_err(da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__)
+
+struct da9052_rtc {
+	struct rtc_device *rtc;
+	struct da9052 *da9052;
+	int irq;
+};
+
+static int da9052_rtc_enable_alarm(struct da9052 *da9052, bool enable)
+{
+	int ret;
+	if (enable) {
+		ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG,
+					DA9052_ALARM_Y_ALARM_ON,
+					DA9052_ALARM_Y_ALARM_ON);
+		if (ret != 0)
+			rtc_err(da9052, "Failed to enable ALM: %d\n", ret);
+	} else {
+		ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG,
+					DA9052_ALARM_Y_ALARM_ON, 0);
+		if (ret != 0)
+			rtc_err(da9052, "Write error: %d\n", ret);
+	}
+	return ret;
+}
+
+static irqreturn_t da9052_rtc_irq(int irq, void *data)
+{
+	struct da9052_rtc *rtc = data;
+	int ret;
+
+	ret = da9052_reg_read(rtc->da9052, DA9052_ALARM_MI_REG);
+	if (ret < 0) {
+		rtc_err(rtc->da9052, "Read error: %d\n", ret);
+		return IRQ_NONE;
+	}
+
+	if (ret & DA9052_ALARMMI_ALARMTYPE) {
+		da9052_rtc_enable_alarm(rtc->da9052, 0);
+		rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
+	} else
+		rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_PF);
+
+	return IRQ_HANDLED;
+}
+
+static int da9052_read_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm)
+{
+	int ret;
+	uint8_t v[5];
+
+	ret = da9052_group_read(da9052, DA9052_ALARM_MI_REG, 5, v);
+	if (ret != 0) {
+		rtc_err(da9052, "Failed to group read ALM: %d\n", ret);
+		return ret;
+	}
+
+	rtc_tm->tm_year = (v[4] & DA9052_RTC_YEAR) + 100;
+	rtc_tm->tm_mon  = (v[3] & DA9052_RTC_MONTH) - 1;
+	rtc_tm->tm_mday = v[2] & DA9052_RTC_DAY;
+	rtc_tm->tm_hour = v[1] & DA9052_RTC_HOUR;
+	rtc_tm->tm_min  = v[0] & DA9052_RTC_MIN;
+
+	ret = rtc_valid_tm(rtc_tm);
+	if (ret != 0)
+		return ret;
+	return ret;
+}
+
+static int da9052_set_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm)
+{
+	int ret;
+	uint8_t v[3];
+
+	rtc_tm->tm_year -= 100;
+	rtc_tm->tm_mon += 1;
+
+	ret = da9052_reg_update(da9052, DA9052_ALARM_MI_REG,
+				DA9052_RTC_MIN, rtc_tm->tm_min);
+	if (ret != 0) {
+		rtc_err(da9052, "Failed to write ALRM MIN: %d\n", ret);
+		return ret;
+	}
+
+	v[0] = rtc_tm->tm_hour;
+	v[1] = rtc_tm->tm_mday;
+	v[2] = rtc_tm->tm_mon;
+
+	ret = da9052_group_write(da9052, DA9052_ALARM_H_REG, 3, v);
+	if (ret < 0)
+		return ret;
+
+	ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG,
+				DA9052_RTC_YEAR, rtc_tm->tm_year);
+	if (ret != 0)
+		rtc_err(da9052, "Failed to write ALRM YEAR: %d\n", ret);
+
+	return ret;
+}
+
+static int da9052_rtc_get_alarm_status(struct da9052 *da9052)
+{
+	int ret;
+
+	ret = da9052_reg_read(da9052, DA9052_ALARM_Y_REG);
+	if (ret < 0) {
+		rtc_err(da9052, "Failed to read ALM: %d\n", ret);
+		return ret;
+	}
+	ret &= DA9052_ALARM_Y_ALARM_ON;
+	return (ret > 0) ? 1 : 0;
+}
+
+static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+	struct da9052_rtc *rtc = dev_get_drvdata(dev);
+	uint8_t v[6];
+	int ret;
+
+	ret = da9052_group_read(rtc->da9052, DA9052_COUNT_S_REG, 6, v);
+	if (ret < 0) {
+		rtc_err(rtc->da9052, "Failed to read RTC time : %d\n", ret);
+		return ret;
+	}
+
+	rtc_tm->tm_year = (v[5] & DA9052_RTC_YEAR) + 100;
+	rtc_tm->tm_mon  = (v[4] & DA9052_RTC_MONTH) - 1;
+	rtc_tm->tm_mday = v[3] & DA9052_RTC_DAY;
+	rtc_tm->tm_hour = v[2] & DA9052_RTC_HOUR;
+	rtc_tm->tm_min  = v[1] & DA9052_RTC_MIN;
+	rtc_tm->tm_sec  = v[0] & DA9052_RTC_SEC;
+
+	ret = rtc_valid_tm(rtc_tm);
+	if (ret != 0) {
+		rtc_err(rtc->da9052, "rtc_valid_tm failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct da9052_rtc *rtc;
+	uint8_t v[6];
+
+	rtc = dev_get_drvdata(dev);
+
+	v[0] = tm->tm_sec;
+	v[1] = tm->tm_min;
+	v[2] = tm->tm_hour;
+	v[3] = tm->tm_mday;
+	v[4] = tm->tm_mon + 1;
+	v[5] = tm->tm_year - 100;
+
+	return da9052_group_write(rtc->da9052, DA9052_COUNT_S_REG, 6, v);
+}
+
+static int da9052_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	int ret;
+	struct rtc_time *tm = &alrm->time;
+	struct da9052_rtc *rtc = dev_get_drvdata(dev);
+
+	ret = da9052_read_alarm(rtc->da9052, tm);
+
+	if (ret)
+		return ret;
+
+	alrm->enabled = da9052_rtc_get_alarm_status(rtc->da9052);
+
+	return 0;
+}
+
+static int da9052_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	int ret;
+	struct rtc_time *tm = &alrm->time;
+	struct da9052_rtc *rtc = dev_get_drvdata(dev);
+
+	ret = da9052_rtc_enable_alarm(rtc->da9052, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = da9052_set_alarm(rtc->da9052, tm);
+	if (ret)
+		return ret;
+
+	ret = da9052_rtc_enable_alarm(rtc->da9052, 1);
+
+	return ret;
+}
+
+static int da9052_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+	struct da9052_rtc *rtc = dev_get_drvdata(dev);
+
+	return da9052_rtc_enable_alarm(rtc->da9052, enabled);
+}
+
+static const struct rtc_class_ops da9052_rtc_ops = {
+	.read_time	= da9052_rtc_read_time,
+	.set_time	= da9052_rtc_set_time,
+	.read_alarm	= da9052_rtc_read_alarm,
+	.set_alarm	= da9052_rtc_set_alarm,
+	.alarm_irq_enable = da9052_rtc_alarm_irq_enable,
+};
+
+static int __devinit da9052_rtc_probe(struct platform_device *pdev)
+{
+	struct da9052_rtc *rtc;
+	int ret;
+
+	rtc = devm_kzalloc(&pdev->dev, sizeof(struct da9052_rtc), GFP_KERNEL);
+	if (!rtc)
+		return -ENOMEM;
+
+	rtc->da9052 = dev_get_drvdata(pdev->dev.parent);
+	platform_set_drvdata(pdev, rtc);
+	rtc->irq = platform_get_irq_byname(pdev, "ALM");
+	ret = request_threaded_irq(rtc->irq, NULL, da9052_rtc_irq,
+				   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				   "ALM", rtc);
+	if (ret != 0) {
+		rtc_err(rtc->da9052, "irq registration failed: %d\n", ret);
+		goto err_mem;
+	}
+
+	rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+				       &da9052_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc->rtc)) {
+		ret = PTR_ERR(rtc->rtc);
+		goto err_free_irq;
+	}
+
+	return 0;
+
+err_free_irq:
+	free_irq(rtc->irq, rtc);
+err_mem:
+	devm_kfree(&pdev->dev, rtc);
+	return ret;
+}
+
+static int __devexit da9052_rtc_remove(struct platform_device *pdev)
+{
+	struct da9052_rtc *rtc = pdev->dev.platform_data;
+
+	rtc_device_unregister(rtc->rtc);
+	free_irq(rtc->irq, rtc);
+	platform_set_drvdata(pdev, NULL);
+	devm_kfree(&pdev->dev, rtc);
+
+	return 0;
+}
+
+static struct platform_driver da9052_rtc_driver = {
+	.probe	= da9052_rtc_probe,
+	.remove	= __devexit_p(da9052_rtc_remove),
+	.driver = {
+		.name	= "da9052-rtc",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(da9052_rtc_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("RTC driver for Dialog DA9052 PMIC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9052-rtc");
diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c
index 755e1fe..14c2109 100644
--- a/drivers/rtc/rtc-davinci.c
+++ b/drivers/rtc/rtc-davinci.c
@@ -542,7 +542,7 @@
 	rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CCTRL);
 
 	ret = request_irq(davinci_rtc->irq, davinci_rtc_interrupt,
-			  IRQF_DISABLED, "davinci_rtc", davinci_rtc);
+			  0, "davinci_rtc", davinci_rtc);
 	if (ret < 0) {
 		dev_err(dev, "unable to register davinci RTC interrupt\n");
 		goto fail4;
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index 3a33b1f..686a865 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -814,17 +814,7 @@
 	/* REVISIT add suspend/resume */
 };
 
-static int __init ds1305_init(void)
-{
-	return spi_register_driver(&ds1305_driver);
-}
-module_init(ds1305_init);
-
-static void __exit ds1305_exit(void)
-{
-	spi_unregister_driver(&ds1305_driver);
-}
-module_exit(ds1305_exit);
+module_spi_driver(ds1305_driver);
 
 MODULE_DESCRIPTION("RTC driver for DS1305 and DS1306 chips");
 MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 62b0763..cd188ab 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -20,7 +20,8 @@
 
 
 
-/* We can't determine type by probing, but if we expect pre-Linux code
+/*
+ * We can't determine type by probing, but if we expect pre-Linux code
  * to have set the chip up as a clock (turning on the oscillator and
  * setting the date and time), Linux can ignore the non-clock features.
  * That's a natural job for a factory or repair bench.
@@ -36,7 +37,8 @@
 	m41t00,
 	mcp7941x,
 	rx_8025,
-	// rs5c372 too?  different address...
+	last_ds_type /* always last */
+	/* rs5c372 too?  different address... */
 };
 
 
@@ -58,7 +60,8 @@
 #	define DS1337_BIT_CENTURY	0x80	/* in REG_MONTH */
 #define DS1307_REG_YEAR		0x06	/* 00-99 */
 
-/* Other registers (control, status, alarms, trickle charge, NVRAM, etc)
+/*
+ * Other registers (control, status, alarms, trickle charge, NVRAM, etc)
  * start at 7, and they differ a LOT. Only control and status matter for
  * basic RTC date and time functionality; be careful using them.
  */
@@ -102,6 +105,8 @@
 struct ds1307 {
 	u8			offset; /* register's offset */
 	u8			regs[11];
+	u16			nvram_offset;
+	struct bin_attribute	*nvram;
 	enum ds_type		type;
 	unsigned long		flags;
 #define HAS_NVRAM	0		/* bit 0 == sysfs file active */
@@ -116,34 +121,35 @@
 };
 
 struct chip_desc {
-	unsigned		nvram56:1;
 	unsigned		alarm:1;
+	u16			nvram_offset;
+	u16			nvram_size;
 };
 
-static const struct chip_desc chips[] = {
-[ds_1307] = {
-	.nvram56	= 1,
-},
-[ds_1337] = {
-	.alarm		= 1,
-},
-[ds_1338] = {
-	.nvram56	= 1,
-},
-[ds_1339] = {
-	.alarm		= 1,
-},
-[ds_1340] = {
-},
-[ds_3231] = {
-	.alarm		= 1,
-},
-[m41t00] = {
-},
-[mcp7941x] = {
-},
-[rx_8025] = {
-}, };
+static const struct chip_desc chips[last_ds_type] = {
+	[ds_1307] = {
+		.nvram_offset	= 8,
+		.nvram_size	= 56,
+	},
+	[ds_1337] = {
+		.alarm		= 1,
+	},
+	[ds_1338] = {
+		.nvram_offset	= 8,
+		.nvram_size	= 56,
+	},
+	[ds_1339] = {
+		.alarm		= 1,
+	},
+	[ds_3231] = {
+		.alarm		= 1,
+	},
+	[mcp7941x] = {
+		/* this is battery backed SRAM */
+		.nvram_offset	= 0x20,
+		.nvram_size	= 0x40,
+	},
+};
 
 static const struct i2c_device_id ds1307_id[] = {
 	{ "ds1307", ds_1307 },
@@ -372,6 +378,11 @@
 				| DS1340_BIT_CENTURY;
 		break;
 	case mcp7941x:
+		/*
+		 * these bits were cleared when preparing the date/time
+		 * values and need to be set again before writing the
+		 * buffer out to the device.
+		 */
 		buf[DS1307_REG_SECS] |= MCP7941X_BIT_ST;
 		buf[DS1307_REG_WDAY] |= MCP7941X_BIT_VBATEN;
 		break;
@@ -417,7 +428,8 @@
 			ds1307->regs[6], ds1307->regs[7],
 			ds1307->regs[8]);
 
-	/* report alarm time (ALARM1); assume 24 hour and day-of-month modes,
+	/*
+	 * report alarm time (ALARM1); assume 24 hour and day-of-month modes,
 	 * and that all four fields are checked matches
 	 */
 	t->time.tm_sec = bcd2bin(ds1307->regs[0] & 0x7f);
@@ -445,7 +457,7 @@
 
 static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
-	struct i2c_client       *client = to_i2c_client(dev);
+	struct i2c_client	*client = to_i2c_client(dev);
 	struct ds1307		*ds1307 = i2c_get_clientdata(client);
 	unsigned char		*buf = ds1307->regs;
 	u8			control, status;
@@ -541,8 +553,6 @@
 
 /*----------------------------------------------------------------------*/
 
-#define NVRAM_SIZE	56
-
 static ssize_t
 ds1307_nvram_read(struct file *filp, struct kobject *kobj,
 		struct bin_attribute *attr,
@@ -555,14 +565,15 @@
 	client = kobj_to_i2c_client(kobj);
 	ds1307 = i2c_get_clientdata(client);
 
-	if (unlikely(off >= NVRAM_SIZE))
+	if (unlikely(off >= ds1307->nvram->size))
 		return 0;
-	if ((off + count) > NVRAM_SIZE)
-		count = NVRAM_SIZE - off;
+	if ((off + count) > ds1307->nvram->size)
+		count = ds1307->nvram->size - off;
 	if (unlikely(!count))
 		return count;
 
-	result = ds1307->read_block_data(client, 8 + off, count, buf);
+	result = ds1307->read_block_data(client, ds1307->nvram_offset + off,
+								count, buf);
 	if (result < 0)
 		dev_err(&client->dev, "%s error %d\n", "nvram read", result);
 	return result;
@@ -580,14 +591,15 @@
 	client = kobj_to_i2c_client(kobj);
 	ds1307 = i2c_get_clientdata(client);
 
-	if (unlikely(off >= NVRAM_SIZE))
+	if (unlikely(off >= ds1307->nvram->size))
 		return -EFBIG;
-	if ((off + count) > NVRAM_SIZE)
-		count = NVRAM_SIZE - off;
+	if ((off + count) > ds1307->nvram->size)
+		count = ds1307->nvram->size - off;
 	if (unlikely(!count))
 		return count;
 
-	result = ds1307->write_block_data(client, 8 + off, count, buf);
+	result = ds1307->write_block_data(client, ds1307->nvram_offset + off,
+								count, buf);
 	if (result < 0) {
 		dev_err(&client->dev, "%s error %d\n", "nvram write", result);
 		return result;
@@ -595,21 +607,8 @@
 	return count;
 }
 
-static struct bin_attribute nvram = {
-	.attr = {
-		.name	= "nvram",
-		.mode	= S_IRUGO | S_IWUSR,
-	},
-
-	.read	= ds1307_nvram_read,
-	.write	= ds1307_nvram_write,
-	.size	= NVRAM_SIZE,
-};
-
 /*----------------------------------------------------------------------*/
 
-static struct i2c_driver ds1307_driver;
-
 static int __devinit ds1307_probe(struct i2c_client *client,
 				  const struct i2c_device_id *id)
 {
@@ -630,7 +629,8 @@
 	    && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
 		return -EIO;
 
-	if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL)))
+	ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL);
+	if (!ds1307)
 		return -ENOMEM;
 
 	i2c_set_clientdata(client, ds1307);
@@ -652,11 +652,6 @@
 	case ds_1337:
 	case ds_1339:
 	case ds_3231:
-		/* has IRQ? */
-		if (ds1307->client->irq > 0 && chip->alarm) {
-			INIT_WORK(&ds1307->work, ds1307_work);
-			want_irq = true;
-		}
 		/* get registers that the "rtc" read below won't read... */
 		tmp = ds1307->read_block_data(ds1307->client,
 				DS1337_REG_CONTROL, 2, buf);
@@ -670,14 +665,19 @@
 		if (ds1307->regs[0] & DS1337_BIT_nEOSC)
 			ds1307->regs[0] &= ~DS1337_BIT_nEOSC;
 
-		/* Using IRQ?  Disable the square wave and both alarms.
+		/*
+		 * Using IRQ?  Disable the square wave and both alarms.
 		 * For some variants, be sure alarms can trigger when we're
 		 * running on Vbackup (BBSQI/BBSQW)
 		 */
-		if (want_irq) {
+		if (ds1307->client->irq > 0 && chip->alarm) {
+			INIT_WORK(&ds1307->work, ds1307_work);
+
 			ds1307->regs[0] |= DS1337_BIT_INTCN
 					| bbsqi_bitpos[ds1307->type];
 			ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
+
+			want_irq = true;
 		}
 
 		i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
@@ -772,7 +772,8 @@
 		goto exit_free;
 	}
 
-	/* minimal sanity checking; some chips (like DS1340) don't
+	/*
+	 * minimal sanity checking; some chips (like DS1340) don't
 	 * specify the extra bits as must-be-zero, but there are
 	 * still a few values that are clearly out-of-range.
 	 */
@@ -836,11 +837,7 @@
 		}
 
 		break;
-	case rx_8025:
-	case ds_1337:
-	case ds_1339:
-	case ds_1388:
-	case ds_3231:
+	default:
 		break;
 	}
 
@@ -848,7 +845,8 @@
 	switch (ds1307->type) {
 	case ds_1340:
 	case m41t00:
-		/* NOTE: ignores century bits; fix before deploying
+		/*
+		 * NOTE: ignores century bits; fix before deploying
 		 * systems that will run through year 2100.
 		 */
 		break;
@@ -858,7 +856,8 @@
 		if (!(tmp & DS1307_BIT_12HR))
 			break;
 
-		/* Be sure we're in 24 hour mode.  Multi-master systems
+		/*
+		 * Be sure we're in 24 hour mode.  Multi-master systems
 		 * take note...
 		 */
 		tmp = bcd2bin(tmp & 0x1f);
@@ -894,16 +893,31 @@
 		dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
 	}
 
-	if (chip->nvram56) {
-		err = sysfs_create_bin_file(&client->dev.kobj, &nvram);
-		if (err == 0) {
-			set_bit(HAS_NVRAM, &ds1307->flags);
-			dev_info(&client->dev, "56 bytes nvram\n");
+	if (chip->nvram_size) {
+		ds1307->nvram = kzalloc(sizeof(struct bin_attribute),
+							GFP_KERNEL);
+		if (!ds1307->nvram) {
+			err = -ENOMEM;
+			goto exit_nvram;
 		}
+		ds1307->nvram->attr.name = "nvram";
+		ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR;
+		ds1307->nvram->read = ds1307_nvram_read,
+		ds1307->nvram->write = ds1307_nvram_write,
+		ds1307->nvram->size = chip->nvram_size;
+		ds1307->nvram_offset = chip->nvram_offset;
+		err = sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram);
+		if (err) {
+			kfree(ds1307->nvram);
+			goto exit_nvram;
+		}
+		set_bit(HAS_NVRAM, &ds1307->flags);
+		dev_info(&client->dev, "%zu bytes nvram\n", ds1307->nvram->size);
 	}
 
 	return 0;
 
+exit_nvram:
 exit_irq:
 	rtc_device_unregister(ds1307->rtc);
 exit_free:
@@ -913,15 +927,17 @@
 
 static int __devexit ds1307_remove(struct i2c_client *client)
 {
-	struct ds1307		*ds1307 = i2c_get_clientdata(client);
+	struct ds1307 *ds1307 = i2c_get_clientdata(client);
 
 	if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) {
 		free_irq(client->irq, client);
 		cancel_work_sync(&ds1307->work);
 	}
 
-	if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags))
-		sysfs_remove_bin_file(&client->dev.kobj, &nvram);
+	if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) {
+		sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram);
+		kfree(ds1307->nvram);
+	}
 
 	rtc_device_unregister(ds1307->rtc);
 	kfree(ds1307);
@@ -938,17 +954,7 @@
 	.id_table	= ds1307_id,
 };
 
-static int __init ds1307_init(void)
-{
-	return i2c_add_driver(&ds1307_driver);
-}
-module_init(ds1307_init);
-
-static void __exit ds1307_exit(void)
-{
-	i2c_del_driver(&ds1307_driver);
-}
-module_exit(ds1307_exit);
+module_i2c_driver(ds1307_driver);
 
 MODULE_DESCRIPTION("RTC driver for DS1307 and similar chips");
 MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index e6e71de..9663160 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -446,18 +446,7 @@
 	.id_table = ds1374_id,
 };
 
-static int __init ds1374_init(void)
-{
-	return i2c_add_driver(&ds1374_driver);
-}
-
-static void __exit ds1374_exit(void)
-{
-	i2c_del_driver(&ds1374_driver);
-}
-
-module_init(ds1374_init);
-module_exit(ds1374_exit);
+module_i2c_driver(ds1374_driver);
 
 MODULE_AUTHOR("Scott Wood <scottwood@freescale.com>");
 MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC Driver");
diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c
index b038d2c..b0a99e1 100644
--- a/drivers/rtc/rtc-ds1390.c
+++ b/drivers/rtc/rtc-ds1390.c
@@ -175,17 +175,7 @@
 	.remove = __devexit_p(ds1390_remove),
 };
 
-static __init int ds1390_init(void)
-{
-	return spi_register_driver(&ds1390_driver);
-}
-module_init(ds1390_init);
-
-static __exit void ds1390_exit(void)
-{
-	spi_unregister_driver(&ds1390_driver);
-}
-module_exit(ds1390_exit);
+module_spi_driver(ds1390_driver);
 
 MODULE_DESCRIPTION("Dallas/Maxim DS1390/93/94 SPI RTC driver");
 MODULE_AUTHOR("Mark Jackson <mpfj@mimc.co.uk>");
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index 761f36b..1f675f5 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -532,7 +532,7 @@
 	if (pdata->irq > 0) {
 		rtc_read(RTC_CMD1);
 		if (devm_request_irq(&pdev->dev, pdata->irq, ds1511_interrupt,
-			IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) {
+			IRQF_SHARED, pdev->name, pdev) < 0) {
 
 			dev_warn(&pdev->dev, "interrupt not available.\n");
 			pdata->irq = 0;
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index 6f0a1b5..6ccedbb 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -320,7 +320,7 @@
 		writeb(0, ioaddr + RTC_INTERRUPTS);
 		if (devm_request_irq(&pdev->dev, pdata->irq,
 				ds1553_rtc_interrupt,
-				IRQF_DISABLED, pdev->name, pdev) < 0) {
+				0, pdev->name, pdev) < 0) {
 			dev_warn(&pdev->dev, "interrupt not available.\n");
 			pdata->irq = 0;
 		}
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index a319402..7fa67d0 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -202,20 +202,9 @@
 	.id_table = ds1672_id,
 };
 
-static int __init ds1672_init(void)
-{
-	return i2c_add_driver(&ds1672_driver);
-}
-
-static void __exit ds1672_exit(void)
-{
-	i2c_del_driver(&ds1672_driver);
-}
+module_i2c_driver(ds1672_driver);
 
 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
 MODULE_DESCRIPTION("Dallas/Maxim DS1672 timekeeper driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(ds1672_init);
-module_exit(ds1672_exit);
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c
index 27b7bf6..e194509 100644
--- a/drivers/rtc/rtc-ds3232.c
+++ b/drivers/rtc/rtc-ds3232.c
@@ -473,18 +473,7 @@
 	.id_table = ds3232_id,
 };
 
-static int __init ds3232_init(void)
-{
-	return i2c_add_driver(&ds3232_driver);
-}
-
-static void __exit ds3232_exit(void)
-{
-	i2c_del_driver(&ds3232_driver);
-}
-
-module_init(ds3232_init);
-module_exit(ds3232_exit);
+module_i2c_driver(ds3232_driver);
 
 MODULE_AUTHOR("Srikanth Srinivasan <srikanth.srinivasan@freescale.com>");
 MODULE_DESCRIPTION("Maxim/Dallas DS3232 RTC Driver");
diff --git a/drivers/rtc/rtc-ds3234.c b/drivers/rtc/rtc-ds3234.c
index bbd2622..fda7079 100644
--- a/drivers/rtc/rtc-ds3234.c
+++ b/drivers/rtc/rtc-ds3234.c
@@ -173,17 +173,7 @@
 	.remove = __devexit_p(ds3234_remove),
 };
 
-static __init int ds3234_init(void)
-{
-	return spi_register_driver(&ds3234_driver);
-}
-module_init(ds3234_init);
-
-static __exit void ds3234_exit(void)
-{
-	spi_unregister_driver(&ds3234_driver);
-}
-module_exit(ds3234_exit);
+module_spi_driver(ds3234_driver);
 
 MODULE_DESCRIPTION("DS3234 SPI RTC driver");
 MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>");
diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c
index 8414dea..0104ea7 100644
--- a/drivers/rtc/rtc-em3027.c
+++ b/drivers/rtc/rtc-em3027.c
@@ -144,19 +144,8 @@
 	.id_table = em3027_id,
 };
 
-static int __init em3027_init(void)
-{
-	return i2c_add_driver(&em3027_driver);
-}
-
-static void __exit em3027_exit(void)
-{
-	i2c_del_driver(&em3027_driver);
-}
+module_i2c_driver(em3027_driver);
 
 MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
 MODULE_DESCRIPTION("EM Microelectronic EM3027 RTC driver");
 MODULE_LICENSE("GPL");
-
-module_init(em3027_init);
-module_exit(em3027_exit);
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c
index 4cf2e70..86b6ecc 100644
--- a/drivers/rtc/rtc-fm3130.c
+++ b/drivers/rtc/rtc-fm3130.c
@@ -565,17 +565,7 @@
 	.id_table	= fm3130_id,
 };
 
-static int __init fm3130_init(void)
-{
-	return i2c_add_driver(&fm3130_driver);
-}
-module_init(fm3130_init);
-
-static void __exit fm3130_exit(void)
-{
-	i2c_del_driver(&fm3130_driver);
-}
-module_exit(fm3130_exit);
+module_i2c_driver(fm3130_driver);
 
 MODULE_DESCRIPTION("RTC driver for FM3130");
 MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>");
diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c
index 6186833..1850104 100644
--- a/drivers/rtc/rtc-isl12022.c
+++ b/drivers/rtc/rtc-isl12022.c
@@ -309,18 +309,7 @@
 	.id_table	= isl12022_id,
 };
 
-static int __init isl12022_init(void)
-{
-	return i2c_add_driver(&isl12022_driver);
-}
-
-static void __exit isl12022_exit(void)
-{
-	i2c_del_driver(&isl12022_driver);
-}
-
-module_init(isl12022_init);
-module_exit(isl12022_exit);
+module_i2c_driver(isl12022_driver);
 
 MODULE_AUTHOR("roman.fietze@telemotive.de");
 MODULE_DESCRIPTION("ISL 12022 RTC driver");
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
index da8beb8..dd2aeee 100644
--- a/drivers/rtc/rtc-isl1208.c
+++ b/drivers/rtc/rtc-isl1208.c
@@ -710,22 +710,9 @@
 	.id_table = isl1208_id,
 };
 
-static int __init
-isl1208_init(void)
-{
-	return i2c_add_driver(&isl1208_driver);
-}
-
-static void __exit
-isl1208_exit(void)
-{
-	i2c_del_driver(&isl1208_driver);
-}
+module_i2c_driver(isl1208_driver);
 
 MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>");
 MODULE_DESCRIPTION("Intersil ISL1208 RTC driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(isl1208_init);
-module_exit(isl1208_exit);
diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c
index ecc1713..63c7218 100644
--- a/drivers/rtc/rtc-lpc32xx.c
+++ b/drivers/rtc/rtc-lpc32xx.c
@@ -287,7 +287,7 @@
 	if (rtc->irq >= 0) {
 		if (devm_request_irq(&pdev->dev, rtc->irq,
 				     lpc32xx_rtc_alarm_interrupt,
-				     IRQF_DISABLED, pdev->name, rtc) < 0) {
+				     0, pdev->name, rtc) < 0) {
 			dev_warn(&pdev->dev, "Can't request interrupt.\n");
 			rtc->irq = -1;
 		} else {
diff --git a/drivers/rtc/rtc-ls1x.c b/drivers/rtc/rtc-ls1x.c
new file mode 100644
index 0000000..07e81c5
--- /dev/null
+++ b/drivers/rtc/rtc-ls1x.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2011 Zhao Zhang <zhzhl555@gmail.com>
+ *
+ * Derived from driver/rtc/rtc-au1xxx.c
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <asm/mach-loongson1/loongson1.h>
+
+#define LS1X_RTC_REG_OFFSET	(LS1X_RTC_BASE + 0x20)
+#define LS1X_RTC_REGS(x) \
+		((void __iomem *)KSEG1ADDR(LS1X_RTC_REG_OFFSET + (x)))
+
+/*RTC programmable counters 0 and 1*/
+#define SYS_COUNTER_CNTRL		(LS1X_RTC_REGS(0x20))
+#define SYS_CNTRL_ERS			(1 << 23)
+#define SYS_CNTRL_RTS			(1 << 20)
+#define SYS_CNTRL_RM2			(1 << 19)
+#define SYS_CNTRL_RM1			(1 << 18)
+#define SYS_CNTRL_RM0			(1 << 17)
+#define SYS_CNTRL_RS			(1 << 16)
+#define SYS_CNTRL_BP			(1 << 14)
+#define SYS_CNTRL_REN			(1 << 13)
+#define SYS_CNTRL_BRT			(1 << 12)
+#define SYS_CNTRL_TEN			(1 << 11)
+#define SYS_CNTRL_BTT			(1 << 10)
+#define SYS_CNTRL_E0			(1 << 8)
+#define SYS_CNTRL_ETS			(1 << 7)
+#define SYS_CNTRL_32S			(1 << 5)
+#define SYS_CNTRL_TTS			(1 << 4)
+#define SYS_CNTRL_TM2			(1 << 3)
+#define SYS_CNTRL_TM1			(1 << 2)
+#define SYS_CNTRL_TM0			(1 << 1)
+#define SYS_CNTRL_TS			(1 << 0)
+
+/* Programmable Counter 0 Registers */
+#define SYS_TOYTRIM		(LS1X_RTC_REGS(0))
+#define SYS_TOYWRITE0		(LS1X_RTC_REGS(4))
+#define SYS_TOYWRITE1		(LS1X_RTC_REGS(8))
+#define SYS_TOYREAD0		(LS1X_RTC_REGS(0xC))
+#define SYS_TOYREAD1		(LS1X_RTC_REGS(0x10))
+#define SYS_TOYMATCH0		(LS1X_RTC_REGS(0x14))
+#define SYS_TOYMATCH1		(LS1X_RTC_REGS(0x18))
+#define SYS_TOYMATCH2		(LS1X_RTC_REGS(0x1C))
+
+/* Programmable Counter 1 Registers */
+#define SYS_RTCTRIM		(LS1X_RTC_REGS(0x40))
+#define SYS_RTCWRITE0		(LS1X_RTC_REGS(0x44))
+#define SYS_RTCREAD0		(LS1X_RTC_REGS(0x48))
+#define SYS_RTCMATCH0		(LS1X_RTC_REGS(0x4C))
+#define SYS_RTCMATCH1		(LS1X_RTC_REGS(0x50))
+#define SYS_RTCMATCH2		(LS1X_RTC_REGS(0x54))
+
+#define LS1X_SEC_OFFSET		(4)
+#define LS1X_MIN_OFFSET		(10)
+#define LS1X_HOUR_OFFSET	(16)
+#define LS1X_DAY_OFFSET		(21)
+#define LS1X_MONTH_OFFSET	(26)
+
+
+#define LS1X_SEC_MASK		(0x3f)
+#define LS1X_MIN_MASK		(0x3f)
+#define LS1X_HOUR_MASK		(0x1f)
+#define LS1X_DAY_MASK		(0x1f)
+#define LS1X_MONTH_MASK		(0x3f)
+#define LS1X_YEAR_MASK		(0xffffffff)
+
+#define ls1x_get_sec(t)		(((t) >> LS1X_SEC_OFFSET) & LS1X_SEC_MASK)
+#define ls1x_get_min(t)		(((t) >> LS1X_MIN_OFFSET) & LS1X_MIN_MASK)
+#define ls1x_get_hour(t)	(((t) >> LS1X_HOUR_OFFSET) & LS1X_HOUR_MASK)
+#define ls1x_get_day(t)		(((t) >> LS1X_DAY_OFFSET) & LS1X_DAY_MASK)
+#define ls1x_get_month(t)	(((t) >> LS1X_MONTH_OFFSET) & LS1X_MONTH_MASK)
+
+#define RTC_CNTR_OK (SYS_CNTRL_E0 | SYS_CNTRL_32S)
+
+static int ls1x_rtc_read_time(struct device *dev, struct rtc_time *rtm)
+{
+	unsigned long v, t;
+
+	v = readl(SYS_TOYREAD0);
+	t = readl(SYS_TOYREAD1);
+
+	memset(rtm, 0, sizeof(struct rtc_time));
+	t  = mktime((t & LS1X_YEAR_MASK), ls1x_get_month(v),
+			ls1x_get_day(v), ls1x_get_hour(v),
+			ls1x_get_min(v), ls1x_get_sec(v));
+	rtc_time_to_tm(t, rtm);
+
+	return rtc_valid_tm(rtm);
+}
+
+static int ls1x_rtc_set_time(struct device *dev, struct  rtc_time *rtm)
+{
+	unsigned long v, t, c;
+	int ret = -ETIMEDOUT;
+
+	v = ((rtm->tm_mon + 1)  << LS1X_MONTH_OFFSET)
+		| (rtm->tm_mday << LS1X_DAY_OFFSET)
+		| (rtm->tm_hour << LS1X_HOUR_OFFSET)
+		| (rtm->tm_min  << LS1X_MIN_OFFSET)
+		| (rtm->tm_sec  << LS1X_SEC_OFFSET);
+
+	writel(v, SYS_TOYWRITE0);
+	c = 0x10000;
+	/* add timeout check counter, for more safe */
+	while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) && --c)
+		usleep_range(1000, 3000);
+
+	if (!c) {
+		dev_err(dev, "set time timeout!\n");
+		goto err;
+	}
+
+	t = rtm->tm_year + 1900;
+	writel(t, SYS_TOYWRITE1);
+	c = 0x10000;
+	while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) && --c)
+		usleep_range(1000, 3000);
+
+	if (!c) {
+		dev_err(dev, "set time timeout!\n");
+		goto err;
+	}
+	return 0;
+err:
+	return ret;
+}
+
+static struct rtc_class_ops  ls1x_rtc_ops = {
+	.read_time	= ls1x_rtc_read_time,
+	.set_time	= ls1x_rtc_set_time,
+};
+
+static int __devinit ls1x_rtc_probe(struct platform_device *pdev)
+{
+	struct rtc_device *rtcdev;
+	unsigned long v;
+	int ret;
+
+	v = readl(SYS_COUNTER_CNTRL);
+	if (!(v & RTC_CNTR_OK)) {
+		dev_err(&pdev->dev, "rtc counters not working\n");
+		ret = -ENODEV;
+		goto err;
+	}
+	ret = -ETIMEDOUT;
+	/* set to 1 HZ if needed */
+	if (readl(SYS_TOYTRIM) != 32767) {
+		v = 0x100000;
+		while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS) && --v)
+			usleep_range(1000, 3000);
+
+		if (!v) {
+			dev_err(&pdev->dev, "time out\n");
+			goto err;
+		}
+		writel(32767, SYS_TOYTRIM);
+	}
+	/* this loop coundn't be endless */
+	while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS)
+		usleep_range(1000, 3000);
+
+	rtcdev = rtc_device_register("ls1x-rtc", &pdev->dev,
+					&ls1x_rtc_ops , THIS_MODULE);
+	if (IS_ERR(rtcdev)) {
+		ret = PTR_ERR(rtcdev);
+		goto err;
+	}
+
+	platform_set_drvdata(pdev, rtcdev);
+	return 0;
+err:
+	return ret;
+}
+
+static int __devexit ls1x_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_device *rtcdev = platform_get_drvdata(pdev);
+
+	rtc_device_unregister(rtcdev);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver  ls1x_rtc_driver = {
+	.driver		= {
+		.name	= "ls1x-rtc",
+		.owner	= THIS_MODULE,
+	},
+	.remove		= __devexit_p(ls1x_rtc_remove),
+	.probe		= ls1x_rtc_probe,
+};
+
+module_platform_driver(ls1x_rtc_driver);
+
+MODULE_AUTHOR("zhao zhang <zhzhl555@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 64aedd8..4e0f84a 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -900,20 +900,9 @@
 	.id_table = m41t80_id,
 };
 
-static int __init m41t80_rtc_init(void)
-{
-	return i2c_add_driver(&m41t80_driver);
-}
-
-static void __exit m41t80_rtc_exit(void)
-{
-	i2c_del_driver(&m41t80_driver);
-}
+module_i2c_driver(m41t80_driver);
 
 MODULE_AUTHOR("Alexander Bigga <ab@mycable.de>");
 MODULE_DESCRIPTION("ST Microelectronics M41T80 series RTC I2C Client Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(m41t80_rtc_init);
-module_exit(m41t80_rtc_exit);
diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c
index ef71132..10f1c29 100644
--- a/drivers/rtc/rtc-m41t93.c
+++ b/drivers/rtc/rtc-m41t93.c
@@ -206,17 +206,7 @@
 	.remove = __devexit_p(m41t93_remove),
 };
 
-static __init int m41t93_init(void)
-{
-	return spi_register_driver(&m41t93_driver);
-}
-module_init(m41t93_init);
-
-static __exit void m41t93_exit(void)
-{
-	spi_unregister_driver(&m41t93_driver);
-}
-module_exit(m41t93_exit);
+module_spi_driver(m41t93_driver);
 
 MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
 MODULE_DESCRIPTION("Driver for ST M41T93 SPI RTC");
diff --git a/drivers/rtc/rtc-m41t94.c b/drivers/rtc/rtc-m41t94.c
index 2a4721f..6e78193 100644
--- a/drivers/rtc/rtc-m41t94.c
+++ b/drivers/rtc/rtc-m41t94.c
@@ -153,19 +153,7 @@
 	.remove = __devexit_p(m41t94_remove),
 };
 
-static __init int m41t94_init(void)
-{
-	return spi_register_driver(&m41t94_driver);
-}
-
-module_init(m41t94_init);
-
-static __exit void m41t94_exit(void)
-{
-	spi_unregister_driver(&m41t94_driver);
-}
-
-module_exit(m41t94_exit);
+module_spi_driver(m41t94_driver);
 
 MODULE_AUTHOR("Kim B. Heino <Kim.Heino@bluegiga.com>");
 MODULE_DESCRIPTION("Driver for ST M41T94 SPI RTC");
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
index 486142c..a00e332 100644
--- a/drivers/rtc/rtc-max6900.c
+++ b/drivers/rtc/rtc-max6900.c
@@ -261,20 +261,9 @@
 	.id_table = max6900_id,
 };
 
-static int __init max6900_init(void)
-{
-	return i2c_add_driver(&max6900_driver);
-}
-
-static void __exit max6900_exit(void)
-{
-	i2c_del_driver(&max6900_driver);
-}
+module_i2c_driver(max6900_driver);
 
 MODULE_DESCRIPTION("Maxim MAX6900 RTC driver");
 MODULE_AUTHOR("Dale Farnsworth <dale@farnsworth.org>");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(max6900_init);
-module_exit(max6900_exit);
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c
index 1f6b3cc..36c74d2 100644
--- a/drivers/rtc/rtc-max6902.c
+++ b/drivers/rtc/rtc-max6902.c
@@ -160,17 +160,7 @@
 	.remove = __devexit_p(max6902_remove),
 };
 
-static __init int max6902_init(void)
-{
-	return spi_register_driver(&max6902_driver);
-}
-module_init(max6902_init);
-
-static __exit void max6902_exit(void)
-{
-	spi_unregister_driver(&max6902_driver);
-}
-module_exit(max6902_exit);
+module_spi_driver(max6902_driver);
 
 MODULE_DESCRIPTION ("max6902 spi RTC driver");
 MODULE_AUTHOR ("Raphael Assenat");
diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c
index 2d71943..1459055 100644
--- a/drivers/rtc/rtc-max8925.c
+++ b/drivers/rtc/rtc-max8925.c
@@ -193,10 +193,17 @@
 	ret = max8925_reg_read(info->rtc, MAX8925_RTC_IRQ_MASK);
 	if (ret < 0)
 		goto out;
-	if ((ret & ALARM0_IRQ) == 0)
-		alrm->enabled = 1;
-	else
+	if (ret & ALARM0_IRQ) {
 		alrm->enabled = 0;
+	} else {
+		ret = max8925_reg_read(info->rtc, MAX8925_ALARM0_CNTL);
+		if (ret < 0)
+			goto out;
+		if (!ret)
+			alrm->enabled = 0;
+		else
+			alrm->enabled = 1;
+	}
 	ret = max8925_reg_read(info->rtc, MAX8925_RTC_STATUS);
 	if (ret < 0)
 		goto out;
@@ -204,6 +211,7 @@
 		alrm->pending = 1;
 	else
 		alrm->pending = 0;
+	return 0;
 out:
 	return ret;
 }
@@ -220,8 +228,11 @@
 	ret = max8925_bulk_write(info->rtc, MAX8925_ALARM0_SEC, TIME_NUM, buf);
 	if (ret < 0)
 		goto out;
-	/* only enable alarm on year/month/day/hour/min/sec */
-	ret = max8925_reg_write(info->rtc, MAX8925_ALARM0_CNTL, 0x77);
+	if (alrm->enabled)
+		/* only enable alarm on year/month/day/hour/min/sec */
+		ret = max8925_reg_write(info->rtc, MAX8925_ALARM0_CNTL, 0x77);
+	else
+		ret = max8925_reg_write(info->rtc, MAX8925_ALARM0_CNTL, 0x0);
 	if (ret < 0)
 		goto out;
 out:
diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
index 9d3cacc..42f5f82 100644
--- a/drivers/rtc/rtc-mpc5121.c
+++ b/drivers/rtc/rtc-mpc5121.c
@@ -327,7 +327,7 @@
 	dev_set_drvdata(&op->dev, rtc);
 
 	rtc->irq = irq_of_parse_and_map(op->dev.of_node, 1);
-	err = request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DISABLED,
+	err = request_irq(rtc->irq, mpc5121_rtc_handler, 0,
 						"mpc5121-rtc", &op->dev);
 	if (err) {
 		dev_err(&op->dev, "%s: could not request irq: %i\n",
@@ -337,7 +337,7 @@
 
 	rtc->irq_periodic = irq_of_parse_and_map(op->dev.of_node, 0);
 	err = request_irq(rtc->irq_periodic, mpc5121_rtc_handler_upd,
-				IRQF_DISABLED, "mpc5121-rtc_upd", &op->dev);
+				0, "mpc5121-rtc_upd", &op->dev);
 	if (err) {
 		dev_err(&op->dev, "%s: could not request irq: %i\n",
 						__func__, rtc->irq_periodic);
@@ -360,6 +360,8 @@
 						&mpc5200_rtc_ops, THIS_MODULE);
 	}
 
+	rtc->rtc->uie_unsupported = 1;
+
 	if (IS_ERR(rtc->rtc)) {
 		err = PTR_ERR(rtc->rtc);
 		goto out_free_irq;
diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c
index 6cd6c72..f51719b 100644
--- a/drivers/rtc/rtc-mrst.c
+++ b/drivers/rtc/rtc-mrst.c
@@ -366,7 +366,7 @@
 
 	if (rtc_irq) {
 		retval = request_irq(rtc_irq, mrst_rtc_irq,
-				IRQF_DISABLED, dev_name(&mrst_rtc.rtc->dev),
+				0, dev_name(&mrst_rtc.rtc->dev),
 				mrst_rtc.rtc);
 		if (retval < 0) {
 			dev_dbg(dev, "IRQ %d is already in use, err %d\n",
diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c
index 768e2ed..b2185f4 100644
--- a/drivers/rtc/rtc-mv.c
+++ b/drivers/rtc/rtc-mv.c
@@ -12,6 +12,7 @@
 #include <linux/bcd.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
 #include <linux/delay.h>
 #include <linux/gfp.h>
 #include <linux/module.h>
@@ -273,7 +274,7 @@
 	if (pdata->irq >= 0) {
 		writel(0, pdata->ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
 		if (devm_request_irq(&pdev->dev, pdata->irq, mv_rtc_interrupt,
-				     IRQF_DISABLED | IRQF_SHARED,
+				     IRQF_SHARED,
 				     pdev->name, pdata) < 0) {
 			dev_warn(&pdev->dev, "interrupt not available.\n");
 			pdata->irq = -1;
@@ -294,11 +295,19 @@
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static struct of_device_id rtc_mv_of_match_table[] = {
+	{ .compatible = "mrvl,orion-rtc", },
+	{}
+};
+#endif
+
 static struct platform_driver mv_rtc_driver = {
 	.remove		= __exit_p(mv_rtc_remove),
 	.driver		= {
 		.name	= "rtc-mv",
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(rtc_mv_of_match_table),
 	},
 };
 
diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c
index 781068d..b7901098 100644
--- a/drivers/rtc/rtc-nuc900.c
+++ b/drivers/rtc/rtc-nuc900.c
@@ -269,7 +269,7 @@
 
 	nuc900_rtc->irq_num = platform_get_irq(pdev, 0);
 	if (request_irq(nuc900_rtc->irq_num, nuc900_rtc_interrupt,
-				IRQF_DISABLED, "nuc900rtc", nuc900_rtc)) {
+				0, "nuc900rtc", nuc900_rtc)) {
 		dev_err(&pdev->dev, "NUC900 RTC request irq failed\n");
 		err = -EBUSY;
 		goto fail4;
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 7789002..0b614e3 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -348,14 +348,14 @@
 		rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
 
 	/* handle periodic and alarm irqs */
-	if (request_irq(omap_rtc_timer, rtc_irq, IRQF_DISABLED,
+	if (request_irq(omap_rtc_timer, rtc_irq, 0,
 			dev_name(&rtc->dev), rtc)) {
 		pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n",
 			pdev->name, omap_rtc_timer);
 		goto fail1;
 	}
 	if ((omap_rtc_timer != omap_rtc_alarm) &&
-		(request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED,
+		(request_irq(omap_rtc_alarm, rtc_irq, 0,
 			dev_name(&rtc->dev), rtc))) {
 		pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n",
 			pdev->name, omap_rtc_alarm);
diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index b46c400..8361187 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -346,20 +346,9 @@
 	.remove	= __devexit_p(pcf2123_remove),
 };
 
-static int __init pcf2123_init(void)
-{
-	return spi_register_driver(&pcf2123_driver);
-}
-
-static void __exit pcf2123_exit(void)
-{
-	spi_unregister_driver(&pcf2123_driver);
-}
+module_spi_driver(pcf2123_driver);
 
 MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>");
 MODULE_DESCRIPTION("NXP PCF2123 RTC driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(pcf2123_init);
-module_exit(pcf2123_exit);
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 606fdfa..bc0677d 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -252,20 +252,9 @@
 	.id_table	= pcf8563_id,
 };
 
-static int __init pcf8563_init(void)
-{
-	return i2c_add_driver(&pcf8563_driver);
-}
-
-static void __exit pcf8563_exit(void)
-{
-	i2c_del_driver(&pcf8563_driver);
-}
+module_i2c_driver(pcf8563_driver);
 
 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
 MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(pcf8563_init);
-module_exit(pcf8563_exit);
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index 2d201af..019ff35 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -320,18 +320,7 @@
 	.id_table	= pcf8583_id,
 };
 
-static __init int pcf8583_init(void)
-{
-	return i2c_add_driver(&pcf8583_driver);
-}
-
-static __exit void pcf8583_exit(void)
-{
-	i2c_del_driver(&pcf8583_driver);
-}
-
-module_init(pcf8583_init);
-module_exit(pcf8583_exit);
+module_i2c_driver(pcf8583_driver);
 
 MODULE_AUTHOR("Russell King");
 MODULE_DESCRIPTION("PCF8583 I2C RTC driver");
diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c
index 02111fe..22bacdb 100644
--- a/drivers/rtc/rtc-pl030.c
+++ b/drivers/rtc/rtc-pl030.c
@@ -123,7 +123,7 @@
 
 	amba_set_drvdata(dev, rtc);
 
-	ret = request_irq(dev->irq[0], pl030_interrupt, IRQF_DISABLED,
+	ret = request_irq(dev->irq[0], pl030_interrupt, 0,
 			  "rtc-pl030", rtc);
 	if (ret)
 		goto err_irq;
@@ -185,18 +185,7 @@
 	.id_table	= pl030_ids,
 };
 
-static int __init pl030_init(void)
-{
-	return amba_driver_register(&pl030_driver);
-}
-
-static void __exit pl030_exit(void)
-{
-	amba_driver_unregister(&pl030_driver);
-}
-
-module_init(pl030_init);
-module_exit(pl030_exit);
+module_amba_driver(pl030_driver);
 
 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 MODULE_DESCRIPTION("ARM AMBA PL030 RTC Driver");
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index a952c8d..692de73 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -352,7 +352,7 @@
 	}
 
 	if (request_irq(adev->irq[0], pl031_interrupt,
-			IRQF_DISABLED, "rtc-pl031", ldata)) {
+			0, "rtc-pl031", ldata)) {
 		ret = -EIO;
 		goto out_no_irq;
 	}
@@ -431,18 +431,7 @@
 	.remove = pl031_remove,
 };
 
-static int __init pl031_init(void)
-{
-	return amba_driver_register(&pl031_driver);
-}
-
-static void __exit pl031_exit(void)
-{
-	amba_driver_unregister(&pl031_driver);
-}
-
-module_init(pl031_init);
-module_exit(pl031_exit);
+module_amba_driver(pl031_driver);
 
 MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net");
 MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver");
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c
index 9f1d6bc..d00bd24 100644
--- a/drivers/rtc/rtc-pm8xxx.c
+++ b/drivers/rtc/rtc-pm8xxx.c
@@ -520,7 +520,7 @@
 }
 #endif
 
-SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, pm8xxx_rtc_suspend, pm8xxx_rtc_resume);
+static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, pm8xxx_rtc_suspend, pm8xxx_rtc_resume);
 
 static struct platform_driver pm8xxx_rtc_driver = {
 	.probe		= pm8xxx_rtc_probe,
diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c
index fc9f499..0075c8f 100644
--- a/drivers/rtc/rtc-pxa.c
+++ b/drivers/rtc/rtc-pxa.c
@@ -174,14 +174,14 @@
 	struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev);
 	int ret;
 
-	ret = request_irq(pxa_rtc->irq_1Hz, pxa_rtc_irq, IRQF_DISABLED,
+	ret = request_irq(pxa_rtc->irq_1Hz, pxa_rtc_irq, 0,
 			  "rtc 1Hz", dev);
 	if (ret < 0) {
 		dev_err(dev, "can't get irq %i, err %d\n", pxa_rtc->irq_1Hz,
 			ret);
 		goto err_irq_1Hz;
 	}
-	ret = request_irq(pxa_rtc->irq_Alrm, pxa_rtc_irq, IRQF_DISABLED,
+	ret = request_irq(pxa_rtc->irq_Alrm, pxa_rtc_irq, 0,
 			  "rtc Alrm", dev);
 	if (ret < 0) {
 		dev_err(dev, "can't get irq %i, err %d\n", pxa_rtc->irq_Alrm,
diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c
index 2853c2a..7f8e6c2 100644
--- a/drivers/rtc/rtc-r9701.c
+++ b/drivers/rtc/rtc-r9701.c
@@ -159,17 +159,7 @@
 	.remove = __devexit_p(r9701_remove),
 };
 
-static __init int r9701_init(void)
-{
-	return spi_register_driver(&r9701_driver);
-}
-module_init(r9701_init);
-
-static __exit void r9701_exit(void)
-{
-	spi_unregister_driver(&r9701_driver);
-}
-module_exit(r9701_exit);
+module_spi_driver(r9701_driver);
 
 MODULE_DESCRIPTION("r9701 spi RTC driver");
 MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c
index ce2ca85..77074cc 100644
--- a/drivers/rtc/rtc-rs5c348.c
+++ b/drivers/rtc/rtc-rs5c348.c
@@ -235,18 +235,7 @@
 	.remove	= __devexit_p(rs5c348_remove),
 };
 
-static __init int rs5c348_init(void)
-{
-	return spi_register_driver(&rs5c348_driver);
-}
-
-static __exit void rs5c348_exit(void)
-{
-	spi_unregister_driver(&rs5c348_driver);
-}
-
-module_init(rs5c348_init);
-module_exit(rs5c348_exit);
+module_spi_driver(rs5c348_driver);
 
 MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
 MODULE_DESCRIPTION("Ricoh RS5C348 RTC driver");
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index d29f543..fb4842c 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -689,18 +689,7 @@
 	.id_table	= rs5c372_id,
 };
 
-static __init int rs5c372_init(void)
-{
-	return i2c_add_driver(&rs5c372_driver);
-}
-
-static __exit void rs5c372_exit(void)
-{
-	i2c_del_driver(&rs5c372_driver);
-}
-
-module_init(rs5c372_init);
-module_exit(rs5c372_exit);
+module_i2c_driver(rs5c372_driver);
 
 MODULE_AUTHOR(
 		"Pavel Mironchik <pmironchik@optifacio.net>, "
diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c
index ea09ff2..0fbe57b 100644
--- a/drivers/rtc/rtc-rv3029c2.c
+++ b/drivers/rtc/rtc-rv3029c2.c
@@ -436,18 +436,7 @@
 	.id_table = rv3029c2_id,
 };
 
-static int __init rv3029c2_init(void)
-{
-	return i2c_add_driver(&rv3029c2_driver);
-}
-
-static void __exit rv3029c2_exit(void)
-{
-	i2c_del_driver(&rv3029c2_driver);
-}
-
-module_init(rv3029c2_init);
-module_exit(rv3029c2_exit);
+module_i2c_driver(rv3029c2_driver);
 
 MODULE_AUTHOR("Gregory Hermant <gregory.hermant@calao-systems.com>");
 MODULE_DESCRIPTION("Micro Crystal RV3029C2 RTC driver");
diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c
index fde172f..0de902d 100644
--- a/drivers/rtc/rtc-rx8025.c
+++ b/drivers/rtc/rtc-rx8025.c
@@ -644,19 +644,8 @@
 	.id_table	= rx8025_id,
 };
 
-static int __init rx8025_init(void)
-{
-	return i2c_add_driver(&rx8025_driver);
-}
-
-static void __exit rx8025_exit(void)
-{
-	i2c_del_driver(&rx8025_driver);
-}
+module_i2c_driver(rx8025_driver);
 
 MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
 MODULE_DESCRIPTION("RX-8025 SA/NB RTC driver");
 MODULE_LICENSE("GPL");
-
-module_init(rx8025_init);
-module_exit(rx8025_exit);
diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c
index 600b890..d848251 100644
--- a/drivers/rtc/rtc-rx8581.c
+++ b/drivers/rtc/rtc-rx8581.c
@@ -276,20 +276,9 @@
 	.id_table	= rx8581_id,
 };
 
-static int __init rx8581_init(void)
-{
-	return i2c_add_driver(&rx8581_driver);
-}
-
-static void __exit rx8581_exit(void)
-{
-	i2c_del_driver(&rx8581_driver);
-}
+module_i2c_driver(rx8581_driver);
 
 MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com>");
 MODULE_DESCRIPTION("Epson RX-8581 RTC driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(rx8581_init);
-module_exit(rx8581_exit);
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
index f789e00..c9562ce 100644
--- a/drivers/rtc/rtc-s35390a.c
+++ b/drivers/rtc/rtc-s35390a.c
@@ -304,19 +304,8 @@
 	.id_table	= s35390a_id,
 };
 
-static int __init s35390a_rtc_init(void)
-{
-	return i2c_add_driver(&s35390a_driver);
-}
-
-static void __exit s35390a_rtc_exit(void)
-{
-	i2c_del_driver(&s35390a_driver);
-}
+module_i2c_driver(s35390a_driver);
 
 MODULE_AUTHOR("Byron Bradley <byron.bbradley@gmail.com>");
 MODULE_DESCRIPTION("S35390A RTC driver");
 MODULE_LICENSE("GPL");
-
-module_init(s35390a_rtc_init);
-module_exit(s35390a_rtc_exit);
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index aef40bd..9ccea13 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -35,6 +35,8 @@
 
 enum s3c_cpu_type {
 	TYPE_S3C2410,
+	TYPE_S3C2416,
+	TYPE_S3C2443,
 	TYPE_S3C64XX,
 };
 
@@ -132,6 +134,7 @@
 	struct platform_device *pdev = to_platform_device(dev);
 	struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
 	unsigned int tmp = 0;
+	int val;
 
 	if (!is_power_of_2(freq))
 		return -EINVAL;
@@ -139,12 +142,22 @@
 	clk_enable(rtc_clk);
 	spin_lock_irq(&s3c_rtc_pie_lock);
 
-	if (s3c_rtc_cpu_type == TYPE_S3C2410) {
+	if (s3c_rtc_cpu_type != TYPE_S3C64XX) {
 		tmp = readb(s3c_rtc_base + S3C2410_TICNT);
 		tmp &= S3C2410_TICNT_ENABLE;
 	}
 
-	tmp |= (rtc_dev->max_user_freq / freq)-1;
+	val = (rtc_dev->max_user_freq / freq) - 1;
+
+	if (s3c_rtc_cpu_type == TYPE_S3C2416 || s3c_rtc_cpu_type == TYPE_S3C2443) {
+		tmp |= S3C2443_TICNT_PART(val);
+		writel(S3C2443_TICNT1_PART(val), s3c_rtc_base + S3C2443_TICNT1);
+
+		if (s3c_rtc_cpu_type == TYPE_S3C2416)
+			writel(S3C2416_TICNT2_PART(val), s3c_rtc_base + S3C2416_TICNT2);
+	} else {
+		tmp |= val;
+	}
 
 	writel(tmp, s3c_rtc_base + S3C2410_TICNT);
 	spin_unlock_irq(&s3c_rtc_pie_lock);
@@ -371,7 +384,7 @@
 		tmp &= ~S3C2410_RTCCON_RTCEN;
 		writew(tmp, base + S3C2410_RTCCON);
 
-		if (s3c_rtc_cpu_type == TYPE_S3C2410) {
+		if (s3c_rtc_cpu_type != TYPE_S3C64XX) {
 			tmp = readb(base + S3C2410_TICNT);
 			tmp &= ~S3C2410_TICNT_ENABLE;
 			writeb(tmp, base + S3C2410_TICNT);
@@ -428,12 +441,27 @@
 	return 0;
 }
 
+static const struct of_device_id s3c_rtc_dt_match[];
+
+static inline int s3c_rtc_get_driver_data(struct platform_device *pdev)
+{
+#ifdef CONFIG_OF
+	if (pdev->dev.of_node) {
+		const struct of_device_id *match;
+		match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node);
+		return match->data;
+	}
+#endif
+	return platform_get_device_id(pdev)->driver_data;
+}
+
 static int __devinit s3c_rtc_probe(struct platform_device *pdev)
 {
 	struct rtc_device *rtc;
 	struct rtc_time rtc_tm;
 	struct resource *res;
 	int ret;
+	int tmp;
 
 	pr_debug("%s: probe=%p\n", __func__, pdev);
 
@@ -508,13 +536,7 @@
 		goto err_nortc;
 	}
 
-#ifdef CONFIG_OF
-	if (pdev->dev.of_node)
-		s3c_rtc_cpu_type = of_device_is_compatible(pdev->dev.of_node,
-			"samsung,s3c6410-rtc") ? TYPE_S3C64XX : TYPE_S3C2410;
-	else
-#endif
-		s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;
+	s3c_rtc_cpu_type = s3c_rtc_get_driver_data(pdev);
 
 	/* Check RTC Time */
 
@@ -533,24 +555,30 @@
 		dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n");
 	}
 
-	if (s3c_rtc_cpu_type == TYPE_S3C64XX)
+	if (s3c_rtc_cpu_type != TYPE_S3C2410)
 		rtc->max_user_freq = 32768;
 	else
 		rtc->max_user_freq = 128;
 
+	if (s3c_rtc_cpu_type == TYPE_S3C2416 || s3c_rtc_cpu_type == TYPE_S3C2443) {
+		tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
+		tmp |= S3C2443_RTCCON_TICSEL;
+		writew(tmp, s3c_rtc_base + S3C2410_RTCCON);
+	}
+
 	platform_set_drvdata(pdev, rtc);
 
 	s3c_rtc_setfreq(&pdev->dev, 1);
 
 	ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
-			  IRQF_DISABLED,  "s3c2410-rtc alarm", rtc);
+			  0,  "s3c2410-rtc alarm", rtc);
 	if (ret) {
 		dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
 		goto err_alarm_irq;
 	}
 
 	ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
-			  IRQF_DISABLED,  "s3c2410-rtc tick", rtc);
+			  0,  "s3c2410-rtc tick", rtc);
 	if (ret) {
 		dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
 		free_irq(s3c_rtc_alarmno, rtc);
@@ -638,8 +666,19 @@
 
 #ifdef CONFIG_OF
 static const struct of_device_id s3c_rtc_dt_match[] = {
-	{ .compatible = "samsung,s3c2410-rtc" },
-	{ .compatible = "samsung,s3c6410-rtc" },
+	{
+		.compatible = "samsung,s3c2410-rtc"
+		.data = TYPE_S3C2410,
+	}, {
+		.compatible = "samsung,s3c2416-rtc"
+		.data = TYPE_S3C2416,
+	}, {
+		.compatible = "samsung,s3c2443-rtc"
+		.data = TYPE_S3C2443,
+	}, {
+		.compatible = "samsung,s3c6410-rtc"
+		.data = TYPE_S3C64XX,
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
@@ -652,6 +691,12 @@
 		.name		= "s3c2410-rtc",
 		.driver_data	= TYPE_S3C2410,
 	}, {
+		.name		= "s3c2416-rtc",
+		.driver_data	= TYPE_S3C2416,
+	}, {
+		.name		= "s3c2443-rtc",
+		.driver_data	= TYPE_S3C2443,
+	}, {
 		.name		= "s3c64xx-rtc",
 		.driver_data	= TYPE_S3C64XX,
 	},
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index cb9a585..50a5c4a 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -23,94 +23,45 @@
 
 #include <linux/platform_device.h>
 #include <linux/module.h>
+#include <linux/clk.h>
 #include <linux/rtc.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/interrupt.h>
+#include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/of.h>
 #include <linux/pm.h>
 #include <linux/bitops.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/irq.h>
+#include <mach/irqs.h>
 
-#ifdef CONFIG_ARCH_PXA
+#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP)
 #include <mach/regs-rtc.h>
 #endif
 
 #define RTC_DEF_DIVIDER		(32768 - 1)
 #define RTC_DEF_TRIM		0
+#define RTC_FREQ		1024
 
-static const unsigned long RTC_FREQ = 1024;
-static struct rtc_time rtc_alarm;
-static DEFINE_SPINLOCK(sa1100_rtc_lock);
-
-static inline int rtc_periodic_alarm(struct rtc_time *tm)
-{
-	return  (tm->tm_year == -1) ||
-		((unsigned)tm->tm_mon >= 12) ||
-		((unsigned)(tm->tm_mday - 1) >= 31) ||
-		((unsigned)tm->tm_hour > 23) ||
-		((unsigned)tm->tm_min > 59) ||
-		((unsigned)tm->tm_sec > 59);
-}
-
-/*
- * Calculate the next alarm time given the requested alarm time mask
- * and the current time.
- */
-static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now,
-	struct rtc_time *alrm)
-{
-	unsigned long next_time;
-	unsigned long now_time;
-
-	next->tm_year = now->tm_year;
-	next->tm_mon = now->tm_mon;
-	next->tm_mday = now->tm_mday;
-	next->tm_hour = alrm->tm_hour;
-	next->tm_min = alrm->tm_min;
-	next->tm_sec = alrm->tm_sec;
-
-	rtc_tm_to_time(now, &now_time);
-	rtc_tm_to_time(next, &next_time);
-
-	if (next_time < now_time) {
-		/* Advance one day */
-		next_time += 60 * 60 * 24;
-		rtc_time_to_tm(next_time, next);
-	}
-}
-
-static int rtc_update_alarm(struct rtc_time *alrm)
-{
-	struct rtc_time alarm_tm, now_tm;
-	unsigned long now, time;
-	int ret;
-
-	do {
-		now = RCNR;
-		rtc_time_to_tm(now, &now_tm);
-		rtc_next_alarm_time(&alarm_tm, &now_tm, alrm);
-		ret = rtc_tm_to_time(&alarm_tm, &time);
-		if (ret != 0)
-			break;
-
-		RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL);
-		RTAR = time;
-	} while (now != RCNR);
-
-	return ret;
-}
+struct sa1100_rtc {
+	spinlock_t		lock;
+	int			irq_1hz;
+	int			irq_alarm;
+	struct rtc_device	*rtc;
+	struct clk		*clk;
+};
 
 static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
 {
-	struct platform_device *pdev = to_platform_device(dev_id);
-	struct rtc_device *rtc = platform_get_drvdata(pdev);
+	struct sa1100_rtc *info = dev_get_drvdata(dev_id);
+	struct rtc_device *rtc = info->rtc;
 	unsigned int rtsr;
 	unsigned long events = 0;
 
-	spin_lock(&sa1100_rtc_lock);
+	spin_lock(&info->lock);
 
 	rtsr = RTSR;
 	/* clear interrupt sources */
@@ -146,30 +97,28 @@
 
 	rtc_update_irq(rtc, 1, events);
 
-	if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm))
-		rtc_update_alarm(&rtc_alarm);
-
-	spin_unlock(&sa1100_rtc_lock);
+	spin_unlock(&info->lock);
 
 	return IRQ_HANDLED;
 }
 
 static int sa1100_rtc_open(struct device *dev)
 {
+	struct sa1100_rtc *info = dev_get_drvdata(dev);
+	struct rtc_device *rtc = info->rtc;
 	int ret;
-	struct platform_device *plat_dev = to_platform_device(dev);
-	struct rtc_device *rtc = platform_get_drvdata(plat_dev);
 
-	ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED,
-		"rtc 1Hz", dev);
+	ret = clk_prepare_enable(info->clk);
+	if (ret)
+		goto fail_clk;
+	ret = request_irq(info->irq_1hz, sa1100_rtc_interrupt, 0, "rtc 1Hz", dev);
 	if (ret) {
-		dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz);
+		dev_err(dev, "IRQ %d already in use.\n", info->irq_1hz);
 		goto fail_ui;
 	}
-	ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, IRQF_DISABLED,
-		"rtc Alrm", dev);
+	ret = request_irq(info->irq_alarm, sa1100_rtc_interrupt, 0, "rtc Alrm", dev);
 	if (ret) {
-		dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm);
+		dev_err(dev, "IRQ %d already in use.\n", info->irq_alarm);
 		goto fail_ai;
 	}
 	rtc->max_user_freq = RTC_FREQ;
@@ -178,29 +127,36 @@
 	return 0;
 
  fail_ai:
-	free_irq(IRQ_RTC1Hz, dev);
+	free_irq(info->irq_1hz, dev);
  fail_ui:
+	clk_disable_unprepare(info->clk);
+ fail_clk:
 	return ret;
 }
 
 static void sa1100_rtc_release(struct device *dev)
 {
-	spin_lock_irq(&sa1100_rtc_lock);
-	RTSR = 0;
-	spin_unlock_irq(&sa1100_rtc_lock);
+	struct sa1100_rtc *info = dev_get_drvdata(dev);
 
-	free_irq(IRQ_RTCAlrm, dev);
-	free_irq(IRQ_RTC1Hz, dev);
+	spin_lock_irq(&info->lock);
+	RTSR = 0;
+	spin_unlock_irq(&info->lock);
+
+	free_irq(info->irq_alarm, dev);
+	free_irq(info->irq_1hz, dev);
+	clk_disable_unprepare(info->clk);
 }
 
 static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
-	spin_lock_irq(&sa1100_rtc_lock);
+	struct sa1100_rtc *info = dev_get_drvdata(dev);
+
+	spin_lock_irq(&info->lock);
 	if (enabled)
 		RTSR |= RTSR_ALE;
 	else
 		RTSR &= ~RTSR_ALE;
-	spin_unlock_irq(&sa1100_rtc_lock);
+	spin_unlock_irq(&info->lock);
 	return 0;
 }
 
@@ -225,7 +181,6 @@
 {
 	u32	rtsr;
 
-	memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time));
 	rtsr = RTSR;
 	alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0;
 	alrm->pending = (rtsr & RTSR_AL) ? 1 : 0;
@@ -234,17 +189,22 @@
 
 static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
+	struct sa1100_rtc *info = dev_get_drvdata(dev);
+	unsigned long time;
 	int ret;
 
-	spin_lock_irq(&sa1100_rtc_lock);
-	ret = rtc_update_alarm(&alrm->time);
-	if (ret == 0) {
-		if (alrm->enabled)
-			RTSR |= RTSR_ALE;
-		else
-			RTSR &= ~RTSR_ALE;
-	}
-	spin_unlock_irq(&sa1100_rtc_lock);
+	spin_lock_irq(&info->lock);
+	ret = rtc_tm_to_time(&alrm->time, &time);
+	if (ret != 0)
+		goto out;
+	RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL);
+	RTAR = time;
+	if (alrm->enabled)
+		RTSR |= RTSR_ALE;
+	else
+		RTSR &= ~RTSR_ALE;
+out:
+	spin_unlock_irq(&info->lock);
 
 	return ret;
 }
@@ -271,6 +231,27 @@
 static int sa1100_rtc_probe(struct platform_device *pdev)
 {
 	struct rtc_device *rtc;
+	struct sa1100_rtc *info;
+	int irq_1hz, irq_alarm, ret = 0;
+
+	irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz");
+	irq_alarm = platform_get_irq_byname(pdev, "rtc alarm");
+	if (irq_1hz < 0 || irq_alarm < 0)
+		return -ENODEV;
+
+	info = kzalloc(sizeof(struct sa1100_rtc), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+	info->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(info->clk)) {
+		dev_err(&pdev->dev, "failed to find rtc clock source\n");
+		ret = PTR_ERR(info->clk);
+		goto err_clk;
+	}
+	info->irq_1hz = irq_1hz;
+	info->irq_alarm = irq_alarm;
+	spin_lock_init(&info->lock);
+	platform_set_drvdata(pdev, info);
 
 	/*
 	 * According to the manual we should be able to let RTTR be zero
@@ -292,10 +273,11 @@
 	rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops,
 		THIS_MODULE);
 
-	if (IS_ERR(rtc))
-		return PTR_ERR(rtc);
-
-	platform_set_drvdata(pdev, rtc);
+	if (IS_ERR(rtc)) {
+		ret = PTR_ERR(rtc);
+		goto err_dev;
+	}
+	info->rtc = rtc;
 
 	/* Fix for a nasty initialization problem the in SA11xx RTSR register.
 	 * See also the comments in sa1100_rtc_interrupt().
@@ -322,14 +304,24 @@
 	RTSR = RTSR_AL | RTSR_HZ;
 
 	return 0;
+err_dev:
+	platform_set_drvdata(pdev, NULL);
+	clk_put(info->clk);
+err_clk:
+	kfree(info);
+	return ret;
 }
 
 static int sa1100_rtc_remove(struct platform_device *pdev)
 {
-	struct rtc_device *rtc = platform_get_drvdata(pdev);
+	struct sa1100_rtc *info = platform_get_drvdata(pdev);
 
-	if (rtc)
-		rtc_device_unregister(rtc);
+	if (info) {
+		rtc_device_unregister(info->rtc);
+		clk_put(info->clk);
+		platform_set_drvdata(pdev, NULL);
+		kfree(info);
+	}
 
 	return 0;
 }
@@ -337,15 +329,17 @@
 #ifdef CONFIG_PM
 static int sa1100_rtc_suspend(struct device *dev)
 {
+	struct sa1100_rtc *info = dev_get_drvdata(dev);
 	if (device_may_wakeup(dev))
-		enable_irq_wake(IRQ_RTCAlrm);
+		enable_irq_wake(info->irq_alarm);
 	return 0;
 }
 
 static int sa1100_rtc_resume(struct device *dev)
 {
+	struct sa1100_rtc *info = dev_get_drvdata(dev);
 	if (device_may_wakeup(dev))
-		disable_irq_wake(IRQ_RTCAlrm);
+		disable_irq_wake(info->irq_alarm);
 	return 0;
 }
 
@@ -355,6 +349,13 @@
 };
 #endif
 
+static struct of_device_id sa1100_rtc_dt_ids[] = {
+	{ .compatible = "mrvl,sa1100-rtc", },
+	{ .compatible = "mrvl,mmp-rtc", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids);
+
 static struct platform_driver sa1100_rtc_driver = {
 	.probe		= sa1100_rtc_probe,
 	.remove		= sa1100_rtc_remove,
@@ -363,6 +364,7 @@
 #ifdef CONFIG_PM
 		.pm	= &sa1100_rtc_pm_ops,
 #endif
+		.of_match_table = sa1100_rtc_dt_ids,
 	},
 };
 
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 6ac55fd..e55a763 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -666,7 +666,7 @@
 	if (rtc->carry_irq <= 0) {
 		/* register shared periodic/carry/alarm irq */
 		ret = request_irq(rtc->periodic_irq, sh_rtc_shared,
-				  IRQF_DISABLED, "sh-rtc", rtc);
+				  0, "sh-rtc", rtc);
 		if (unlikely(ret)) {
 			dev_err(&pdev->dev,
 				"request IRQ failed with %d, IRQ %d\n", ret,
@@ -676,7 +676,7 @@
 	} else {
 		/* register periodic/carry/alarm irqs */
 		ret = request_irq(rtc->periodic_irq, sh_rtc_periodic,
-				  IRQF_DISABLED, "sh-rtc period", rtc);
+				  0, "sh-rtc period", rtc);
 		if (unlikely(ret)) {
 			dev_err(&pdev->dev,
 				"request period IRQ failed with %d, IRQ %d\n",
@@ -685,7 +685,7 @@
 		}
 
 		ret = request_irq(rtc->carry_irq, sh_rtc_interrupt,
-				  IRQF_DISABLED, "sh-rtc carry", rtc);
+				  0, "sh-rtc carry", rtc);
 		if (unlikely(ret)) {
 			dev_err(&pdev->dev,
 				"request carry IRQ failed with %d, IRQ %d\n",
@@ -695,7 +695,7 @@
 		}
 
 		ret = request_irq(rtc->alarm_irq, sh_rtc_alarm,
-				  IRQF_DISABLED, "sh-rtc alarm", rtc);
+				  0, "sh-rtc alarm", rtc);
 		if (unlikely(ret)) {
 			dev_err(&pdev->dev,
 				"request alarm IRQ failed with %d, IRQ %d\n",
diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c
index 19a28a6..e38da0d 100644
--- a/drivers/rtc/rtc-spear.c
+++ b/drivers/rtc/rtc-spear.c
@@ -77,9 +77,11 @@
 #define STATUS_FAIL		(LOST_WR_TIME | LOST_WR_DATE)
 
 struct spear_rtc_config {
+	struct rtc_device *rtc;
 	struct clk *clk;
 	spinlock_t lock;
 	void __iomem *ioaddr;
+	unsigned int irq_wake;
 };
 
 static inline void spear_rtc_clear_interrupt(struct spear_rtc_config *config)
@@ -149,8 +151,7 @@
 
 static irqreturn_t spear_rtc_irq(int irq, void *dev_id)
 {
-	struct rtc_device *rtc = (struct rtc_device *)dev_id;
-	struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+	struct spear_rtc_config *config = dev_id;
 	unsigned long flags, events = 0;
 	unsigned int irq_data;
 
@@ -161,7 +162,7 @@
 	if ((irq_data & RTC_INT_MASK)) {
 		spear_rtc_clear_interrupt(config);
 		events = RTC_IRQF | RTC_AF;
-		rtc_update_irq(rtc, 1, events);
+		rtc_update_irq(config->rtc, 1, events);
 		return IRQ_HANDLED;
 	} else
 		return IRQ_NONE;
@@ -203,9 +204,7 @@
  */
 static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct rtc_device *rtc = platform_get_drvdata(pdev);
-	struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+	struct spear_rtc_config *config = dev_get_drvdata(dev);
 	unsigned int time, date;
 
 	/* we don't report wday/yday/isdst ... */
@@ -234,9 +233,7 @@
  */
 static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct rtc_device *rtc = platform_get_drvdata(pdev);
-	struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+	struct spear_rtc_config *config = dev_get_drvdata(dev);
 	unsigned int time, date, err = 0;
 
 	if (tm2bcd(tm) < 0)
@@ -266,9 +263,7 @@
  */
 static int spear_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct rtc_device *rtc = platform_get_drvdata(pdev);
-	struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+	struct spear_rtc_config *config = dev_get_drvdata(dev);
 	unsigned int time, date;
 
 	rtc_wait_not_busy(config);
@@ -298,9 +293,7 @@
  */
 static int spear_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct rtc_device *rtc = platform_get_drvdata(pdev);
-	struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+	struct spear_rtc_config *config = dev_get_drvdata(dev);
 	unsigned int time, date, err = 0;
 
 	if (tm2bcd(&alm->time) < 0)
@@ -326,17 +319,42 @@
 
 	return 0;
 }
+
+static int spear_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+	struct spear_rtc_config *config = dev_get_drvdata(dev);
+	int ret = 0;
+
+	spear_rtc_clear_interrupt(config);
+
+	switch (enabled) {
+	case 0:
+		/* alarm off */
+		spear_rtc_disable_interrupt(config);
+		break;
+	case 1:
+		/* alarm on */
+		spear_rtc_enable_interrupt(config);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
 static struct rtc_class_ops spear_rtc_ops = {
 	.read_time = spear_rtc_read_time,
 	.set_time = spear_rtc_set_time,
 	.read_alarm = spear_rtc_read_alarm,
 	.set_alarm = spear_rtc_set_alarm,
+	.alarm_irq_enable = spear_alarm_irq_enable,
 };
 
 static int __devinit spear_rtc_probe(struct platform_device *pdev)
 {
 	struct resource *res;
-	struct rtc_device *rtc;
 	struct spear_rtc_config *config;
 	unsigned int status = 0;
 	int irq;
@@ -376,19 +394,17 @@
 	}
 
 	spin_lock_init(&config->lock);
+	platform_set_drvdata(pdev, config);
 
-	rtc = rtc_device_register(pdev->name, &pdev->dev, &spear_rtc_ops,
-			THIS_MODULE);
-	if (IS_ERR(rtc)) {
+	config->rtc = rtc_device_register(pdev->name, &pdev->dev,
+			&spear_rtc_ops, THIS_MODULE);
+	if (IS_ERR(config->rtc)) {
 		dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
-				PTR_ERR(rtc));
-		status = PTR_ERR(rtc);
+				PTR_ERR(config->rtc));
+		status = PTR_ERR(config->rtc);
 		goto err_iounmap;
 	}
 
-	platform_set_drvdata(pdev, rtc);
-	dev_set_drvdata(&rtc->dev, config);
-
 	/* alarm irqs */
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
@@ -397,7 +413,7 @@
 		goto err_clear_platdata;
 	}
 
-	status = request_irq(irq, spear_rtc_irq, 0, pdev->name, rtc);
+	status = request_irq(irq, spear_rtc_irq, 0, pdev->name, config);
 	if (status) {
 		dev_err(&pdev->dev, "Alarm interrupt IRQ%d already \
 				claimed\n", irq);
@@ -411,8 +427,7 @@
 
 err_clear_platdata:
 	platform_set_drvdata(pdev, NULL);
-	dev_set_drvdata(&rtc->dev, NULL);
-	rtc_device_unregister(rtc);
+	rtc_device_unregister(config->rtc);
 err_iounmap:
 	iounmap(config->ioaddr);
 err_disable_clock:
@@ -429,8 +444,7 @@
 
 static int __devexit spear_rtc_remove(struct platform_device *pdev)
 {
-	struct rtc_device *rtc = platform_get_drvdata(pdev);
-	struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+	struct spear_rtc_config *config = platform_get_drvdata(pdev);
 	int irq;
 	struct resource *res;
 
@@ -448,8 +462,7 @@
 	if (res)
 		release_mem_region(res->start, resource_size(res));
 	platform_set_drvdata(pdev, NULL);
-	dev_set_drvdata(&rtc->dev, NULL);
-	rtc_device_unregister(rtc);
+	rtc_device_unregister(config->rtc);
 
 	return 0;
 }
@@ -458,14 +471,14 @@
 
 static int spear_rtc_suspend(struct platform_device *pdev, pm_message_t state)
 {
-	struct rtc_device *rtc = platform_get_drvdata(pdev);
-	struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+	struct spear_rtc_config *config = platform_get_drvdata(pdev);
 	int irq;
 
 	irq = platform_get_irq(pdev, 0);
-	if (device_may_wakeup(&pdev->dev))
-		enable_irq_wake(irq);
-	else {
+	if (device_may_wakeup(&pdev->dev)) {
+		if (!enable_irq_wake(irq))
+			config->irq_wake = 1;
+	} else {
 		spear_rtc_disable_interrupt(config);
 		clk_disable(config->clk);
 	}
@@ -475,15 +488,17 @@
 
 static int spear_rtc_resume(struct platform_device *pdev)
 {
-	struct rtc_device *rtc = platform_get_drvdata(pdev);
-	struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+	struct spear_rtc_config *config = platform_get_drvdata(pdev);
 	int irq;
 
 	irq = platform_get_irq(pdev, 0);
 
-	if (device_may_wakeup(&pdev->dev))
-		disable_irq_wake(irq);
-	else {
+	if (device_may_wakeup(&pdev->dev)) {
+		if (config->irq_wake) {
+			disable_irq_wake(irq);
+			config->irq_wake = 0;
+		}
+	} else {
 		clk_enable(config->clk);
 		spear_rtc_enable_interrupt(config);
 	}
@@ -498,8 +513,7 @@
 
 static void spear_rtc_shutdown(struct platform_device *pdev)
 {
-	struct rtc_device *rtc = platform_get_drvdata(pdev);
-	struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+	struct spear_rtc_config *config = platform_get_drvdata(pdev);
 
 	spear_rtc_disable_interrupt(config);
 	clk_disable(config->clk);
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
index 7621116..279f5cf 100644
--- a/drivers/rtc/rtc-stk17ta8.c
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -329,7 +329,7 @@
 		writeb(0, ioaddr + RTC_INTERRUPTS);
 		if (devm_request_irq(&pdev->dev, pdata->irq,
 				stk17ta8_rtc_interrupt,
-				IRQF_DISABLED | IRQF_SHARED,
+				IRQF_SHARED,
 				pdev->name, pdev) < 0) {
 			dev_warn(&pdev->dev, "interrupt not available.\n");
 			pdata->irq = 0;
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index d43b4f6..4c2c6df 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -176,6 +176,10 @@
 	unsigned char val;
 	int ret;
 
+	/* if the bit is set, return from here */
+	if (rtc_irq_bits & bit)
+		return 0;
+
 	val = rtc_irq_bits | bit;
 	val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M;
 	ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
@@ -193,6 +197,10 @@
 	unsigned char val;
 	int ret;
 
+	/* if the bit is clear, return from here */
+	if (!(rtc_irq_bits & bit))
+		return 0;
+
 	val = rtc_irq_bits & ~bit;
 	ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
 	if (ret == 0)
@@ -357,7 +365,7 @@
 
 static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
 {
-	unsigned long events = 0;
+	unsigned long events;
 	int ret = IRQ_NONE;
 	int res;
 	u8 rd_reg;
@@ -372,11 +380,11 @@
 	 * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM]
 	 */
 	if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
-		events |= RTC_IRQF | RTC_AF;
+		events = RTC_IRQF | RTC_AF;
 	else
-		events |= RTC_IRQF | RTC_UF;
+		events = RTC_IRQF | RTC_PF;
 
-	res = twl_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M,
+	res = twl_rtc_write_u8(BIT_RTC_STATUS_REG_ALARM_M,
 				   REG_RTC_STATUS_REG);
 	if (res)
 		goto out;
@@ -449,19 +457,11 @@
 			REG_INT_MSK_STS_A);
 	}
 
-	/* Check RTC module status, Enable if it is off */
-	ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG);
+	dev_info(&pdev->dev, "Enabling TWL-RTC\n");
+	ret = twl_rtc_write_u8(BIT_RTC_CTRL_REG_STOP_RTC_M, REG_RTC_CTRL_REG);
 	if (ret < 0)
 		goto out1;
 
-	if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) {
-		dev_info(&pdev->dev, "Enabling TWL-RTC.\n");
-		rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M;
-		ret = twl_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG);
-		if (ret < 0)
-			goto out1;
-	}
-
 	/* init cached IRQ enable bits */
 	ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
 	if (ret < 0)
diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c
index aac0ffe..a12bfac 100644
--- a/drivers/rtc/rtc-tx4939.c
+++ b/drivers/rtc/rtc-tx4939.c
@@ -266,7 +266,7 @@
 	spin_lock_init(&pdata->lock);
 	tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP);
 	if (devm_request_irq(&pdev->dev, irq, tx4939_rtc_interrupt,
-			     IRQF_DISABLED, pdev->name, &pdev->dev) < 0)
+			     0, pdev->name, &pdev->dev) < 0)
 		return -EBUSY;
 	rtc = rtc_device_register(pdev->name, &pdev->dev,
 				  &tx4939_rtc_ops, THIS_MODULE);
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index fcbfdda..5f60a7c 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -333,7 +333,7 @@
 		goto err_device_unregister;
 	}
 
-	retval = request_irq(aie_irq, elapsedtime_interrupt, IRQF_DISABLED,
+	retval = request_irq(aie_irq, elapsedtime_interrupt, 0,
 	                     "elapsed_time", pdev);
 	if (retval < 0)
 		goto err_device_unregister;
@@ -342,7 +342,7 @@
 	if (pie_irq <= 0)
 		goto err_free_irq;
 
-	retval = request_irq(pie_irq, rtclong1_interrupt, IRQF_DISABLED,
+	retval = request_irq(pie_irq, rtclong1_interrupt, 0,
 		             "rtclong1", pdev);
 	if (retval < 0)
 		goto err_free_irq;
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index 8c051d3..403b3d4 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -623,15 +623,7 @@
 	.id_table	= x1205_id,
 };
 
-static int __init x1205_init(void)
-{
-	return i2c_add_driver(&x1205_driver);
-}
-
-static void __exit x1205_exit(void)
-{
-	i2c_del_driver(&x1205_driver);
-}
+module_i2c_driver(x1205_driver);
 
 MODULE_AUTHOR(
 	"Karen Spearel <kas111 at gmail dot com>, "
@@ -639,6 +631,3 @@
 MODULE_DESCRIPTION("Xicor/Intersil X1205 RTC driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(x1205_init);
-module_exit(x1205_exit);
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 110137e..f350912 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -640,6 +640,10 @@
 		dasd_set_target_state(device, DASD_STATE_NEW);
 	/* Now wait for the devices to come up. */
 	wait_event(dasd_init_waitq, _wait_for_device(device));
+
+	dasd_reload_device(device);
+	if (device->discipline->kick_validate)
+		device->discipline->kick_validate(device);
 }
 
 /*
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 46784b8..0cea7e9 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -229,7 +229,7 @@
 }
 
 /* Handle external interruption. */
-static void dasd_ext_handler(unsigned int ext_int_code,
+static void dasd_ext_handler(struct ext_code ext_code,
 			     unsigned int param32, unsigned long param64)
 {
 	struct dasd_ccw_req *cqr, *next;
@@ -239,7 +239,7 @@
 	addr_t ip;
 	int rc;
 
-	switch (ext_int_code >> 24) {
+	switch (ext_code.subcode >> 8) {
 	case DASD_DIAG_CODE_31BIT:
 		ip = (addr_t) param32;
 		break;
@@ -280,7 +280,7 @@
 	cqr->stopclk = get_clock();
 
 	expires = 0;
-	if ((ext_int_code & 0xff0000) == 0) {
+	if ((ext_code.subcode & 0xff) == 0) {
 		cqr->status = DASD_CQR_SUCCESS;
 		/* Start first request on queue if possible -> fast_io. */
 		if (!list_empty(&device->ccw_queue)) {
@@ -296,7 +296,7 @@
 		cqr->status = DASD_CQR_QUEUED;
 		DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for "
 			      "request %p was %d (%d retries left)", cqr,
-			      (ext_int_code >> 16) & 0xff, cqr->retries);
+			      ext_code.subcode & 0xff, cqr->retries);
 		dasd_diag_erp(device);
 	}
 
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 2617b1e..c21871a 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1564,6 +1564,12 @@
 static void dasd_eckd_kick_validate_server(struct dasd_device *device)
 {
 	dasd_get_device(device);
+	/* exit if device not online or in offline processing */
+	if (test_bit(DASD_FLAG_OFFLINE, &device->flags) ||
+	   device->state < DASD_STATE_ONLINE) {
+		dasd_put_device(device);
+		return;
+	}
 	/* queue call to do_validate_server to the kernel event daemon. */
 	schedule_work(&device->kick_validate);
 }
@@ -1993,6 +1999,7 @@
 static int dasd_eckd_online_to_ready(struct dasd_device *device)
 {
 	cancel_work_sync(&device->reload_device);
+	cancel_work_sync(&device->kick_validate);
 	return dasd_alias_remove_device(device);
 };
 
@@ -2263,6 +2270,7 @@
 		 * and only if not suspended
 		 */
 		if (!device->block && private->lcu &&
+		    device->state == DASD_STATE_ONLINE &&
 		    !test_bit(DASD_FLAG_OFFLINE, &device->flags) &&
 		    !test_bit(DASD_FLAG_SUSPENDED, &device->flags)) {
 			/*
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index eaa7e78..30f29a0 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -393,7 +393,7 @@
 /* Handler for external interruption. Perform request post-processing.
  * Prepare read event data request if necessary. Start processing of next
  * request on queue. */
-static void sclp_interrupt_handler(unsigned int ext_int_code,
+static void sclp_interrupt_handler(struct ext_code ext_code,
 				   unsigned int param32, unsigned long param64)
 {
 	struct sclp_req *req;
@@ -818,7 +818,7 @@
 
 /* Handler for external interruption used during initialization. Modify
  * request state to done. */
-static void sclp_check_handler(unsigned int ext_int_code,
+static void sclp_check_handler(struct ext_code ext_code,
 			       unsigned int param32, unsigned long param64)
 {
 	u32 finished_sccb;
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index 0b54a91..231a1d8 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -21,6 +21,7 @@
 #include <asm/chpid.h>
 #include <asm/sclp.h>
 #include <asm/setup.h>
+#include <asm/ctl_reg.h>
 
 #include "sclp.h"
 
@@ -441,9 +442,8 @@
 	start = arg->start_pfn << PAGE_SHIFT;
 	size = arg->nr_pages << PAGE_SHIFT;
 	mutex_lock(&sclp_mem_mutex);
-	for (id = 0; id <= sclp_max_storage_id; id++)
-		if (!test_bit(id, sclp_storage_ids))
-			sclp_attach_storage(id);
+	for_each_clear_bit(id, sclp_storage_ids, sclp_max_storage_id + 1)
+		sclp_attach_storage(id);
 	switch (action) {
 	case MEM_ONLINE:
 	case MEM_GOING_OFFLINE:
diff --git a/drivers/s390/char/sclp_quiesce.c b/drivers/s390/char/sclp_quiesce.c
index 87fc0ac..69df137 100644
--- a/drivers/s390/char/sclp_quiesce.c
+++ b/drivers/s390/char/sclp_quiesce.c
@@ -15,7 +15,6 @@
 #include <linux/reboot.h>
 #include <linux/atomic.h>
 #include <asm/ptrace.h>
-#include <asm/sigp.h>
 #include <asm/smp.h>
 
 #include "sclp.h"
diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c
index fa733ec..69e6c50 100644
--- a/drivers/s390/char/sclp_sdias.c
+++ b/drivers/s390/char/sclp_sdias.c
@@ -8,6 +8,7 @@
 #define KMSG_COMPONENT "sclp_sdias"
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
+#include <linux/completion.h>
 #include <linux/sched.h>
 #include <asm/sclp.h>
 #include <asm/debug.h>
@@ -62,15 +63,29 @@
 } __attribute__((packed));
 
 static struct sdias_sccb sccb __attribute__((aligned(4096)));
+static struct sdias_evbuf sdias_evbuf;
 
-static int sclp_req_done;
-static wait_queue_head_t sdias_wq;
+static DECLARE_COMPLETION(evbuf_accepted);
+static DECLARE_COMPLETION(evbuf_done);
 static DEFINE_MUTEX(sdias_mutex);
 
+/*
+ * Called by SCLP base when read event data has been completed (async mode only)
+ */
+static void sclp_sdias_receiver_fn(struct evbuf_header *evbuf)
+{
+	memcpy(&sdias_evbuf, evbuf,
+	       min_t(unsigned long, sizeof(sdias_evbuf), evbuf->length));
+	complete(&evbuf_done);
+	TRACE("sclp_sdias_receiver_fn done\n");
+}
+
+/*
+ * Called by SCLP base when sdias event has been accepted
+ */
 static void sdias_callback(struct sclp_req *request, void *data)
 {
-	sclp_req_done = 1;
-	wake_up(&sdias_wq); /* Inform caller, that request is complete */
+	complete(&evbuf_accepted);
 	TRACE("callback done\n");
 }
 
@@ -80,7 +95,6 @@
 	int rc;
 
 	for (retries = SDIAS_RETRIES; retries; retries--) {
-		sclp_req_done = 0;
 		TRACE("add request\n");
 		rc = sclp_add_request(req);
 		if (rc) {
@@ -91,16 +105,31 @@
 			continue;
 		}
 		/* initiated, wait for completion of service call */
-		wait_event(sdias_wq, (sclp_req_done == 1));
+		wait_for_completion(&evbuf_accepted);
 		if (req->status == SCLP_REQ_FAILED) {
 			TRACE("sclp request failed\n");
-			rc = -EIO;
 			continue;
 		}
+		/* if not accepted, retry */
+		if (!(sccb.evbuf.hdr.flags & 0x80)) {
+			TRACE("sclp request failed: flags=%x\n",
+			      sccb.evbuf.hdr.flags);
+			continue;
+		}
+		/*
+		 * for the sync interface the response is in the initial sccb
+		 */
+		if (!sclp_sdias_register.receiver_fn) {
+			memcpy(&sdias_evbuf, &sccb.evbuf, sizeof(sdias_evbuf));
+			TRACE("sync request done\n");
+			return 0;
+		}
+		/* otherwise we wait for completion */
+		wait_for_completion(&evbuf_done);
 		TRACE("request done\n");
-		break;
+		return 0;
 	}
-	return rc;
+	return -EIO;
 }
 
 /*
@@ -140,13 +169,12 @@
 		goto out;
 	}
 
-	switch (sccb.evbuf.event_status) {
+	switch (sdias_evbuf.event_status) {
 		case 0:
-			rc = sccb.evbuf.blk_cnt;
+			rc = sdias_evbuf.blk_cnt;
 			break;
 		default:
-			pr_err("SCLP error: %x\n",
-			       sccb.evbuf.event_status);
+			pr_err("SCLP error: %x\n", sdias_evbuf.event_status);
 			rc = -EIO;
 			goto out;
 	}
@@ -211,18 +239,18 @@
 		goto out;
 	}
 
-	switch (sccb.evbuf.event_status) {
+	switch (sdias_evbuf.event_status) {
 		case EVSTATE_ALL_STORED:
 			TRACE("all stored\n");
 		case EVSTATE_PART_STORED:
-			TRACE("part stored: %i\n", sccb.evbuf.blk_cnt);
+			TRACE("part stored: %i\n", sdias_evbuf.blk_cnt);
 			break;
 		case EVSTATE_NO_DATA:
 			TRACE("no data\n");
 		default:
 			pr_err("Error from SCLP while copying hsa. "
 			       "Event status = %x\n",
-			       sccb.evbuf.event_status);
+			       sdias_evbuf.event_status);
 			rc = -EIO;
 	}
 out:
@@ -230,19 +258,50 @@
 	return rc;
 }
 
-int __init sclp_sdias_init(void)
+static int __init sclp_sdias_register_check(void)
 {
 	int rc;
 
+	rc = sclp_register(&sclp_sdias_register);
+	if (rc)
+		return rc;
+	if (sclp_sdias_blk_count() == 0) {
+		sclp_unregister(&sclp_sdias_register);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int __init sclp_sdias_init_sync(void)
+{
+	TRACE("Try synchronous mode\n");
+	sclp_sdias_register.receive_mask = 0;
+	sclp_sdias_register.receiver_fn = NULL;
+	return sclp_sdias_register_check();
+}
+
+static int __init sclp_sdias_init_async(void)
+{
+	TRACE("Try asynchronous mode\n");
+	sclp_sdias_register.receive_mask = EVTYP_SDIAS_MASK;
+	sclp_sdias_register.receiver_fn = sclp_sdias_receiver_fn;
+	return sclp_sdias_register_check();
+}
+
+int __init sclp_sdias_init(void)
+{
 	if (ipl_info.type != IPL_TYPE_FCP_DUMP)
 		return 0;
 	sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long));
 	debug_register_view(sdias_dbf, &debug_sprintf_view);
 	debug_set_level(sdias_dbf, 6);
-	rc = sclp_register(&sclp_sdias_register);
-	if (rc)
-		return rc;
-	init_waitqueue_head(&sdias_wq);
+	if (sclp_sdias_init_sync() == 0)
+		goto out;
+	if (sclp_sdias_init_async() == 0)
+		goto out;
+	TRACE("init failed\n");
+	return -ENODEV;
+out:
 	TRACE("init done\n");
 	return 0;
 }
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 1b6d924..3303d66 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -21,7 +21,6 @@
 #include <asm/ipl.h>
 #include <asm/sclp.h>
 #include <asm/setup.h>
-#include <asm/sigp.h>
 #include <asm/uaccess.h>
 #include <asm/debug.h>
 #include <asm/processor.h>
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index dc67c39..a49c46c 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -601,8 +601,6 @@
 	struct pt_regs *old_regs;
 
 	old_regs = set_irq_regs(regs);
-	s390_idle_check(regs, S390_lowcore.int_clock,
-			S390_lowcore.async_enter_timer);
 	irq_enter();
 	__this_cpu_write(s390_idle.nohz_delay, 1);
 	if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
diff --git a/drivers/s390/cio/crw.c b/drivers/s390/cio/crw.c
index 425f741..d0a2dff 100644
--- a/drivers/s390/cio/crw.c
+++ b/drivers/s390/cio/crw.c
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/wait.h>
 #include <asm/crw.h>
+#include <asm/ctl_reg.h>
 
 static DEFINE_MUTEX(crw_handler_mutex);
 static crw_handler_t crw_handlers[NR_RSCS];
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 770a740..35c685c 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -18,6 +18,7 @@
 #include <linux/atomic.h>
 #include <asm/debug.h>
 #include <asm/qdio.h>
+#include <asm/ipl.h>
 
 #include "cio.h"
 #include "css.h"
@@ -1093,6 +1094,11 @@
 		   q->nr, q->first_to_kick, count, irq_ptr->int_parm);
 no_handler:
 	qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED);
+	/*
+	 * In case of z/VM LGR (Live Guest Migration) QDIO recovery will happen.
+	 * Therefore we call the LGR detection function here.
+	 */
+	lgr_info_log();
 }
 
 static void qdio_establish_handle_irq(struct ccw_device *cdev, int cstat,
@@ -1452,7 +1458,6 @@
 	}
 
 	qdio_setup_ssqd_info(irq_ptr);
-	DBF_EVENT("qib ac:%4x", irq_ptr->qib.ac);
 
 	qdio_detect_hsicq(irq_ptr);
 
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index 452989a..ecf12f0 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -311,7 +311,8 @@
 
 	check_and_setup_qebsm(irq_ptr, qdioac, irq_ptr->ssqd_desc.sch_token);
 	process_ac_flags(irq_ptr, qdioac);
-	DBF_EVENT("qdioac:%4x", qdioac);
+	DBF_EVENT("ac 1:%2x 2:%4x", qdioac, irq_ptr->ssqd_desc.qdioac2);
+	DBF_EVENT("3:%4x qib:%4x", irq_ptr->ssqd_desc.qdioac3, irq_ptr->qib.ac);
 }
 
 void qdio_release_memory(struct qdio_irq *irq_ptr)
diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile
index f0a12d2..af3c7f1 100644
--- a/drivers/s390/crypto/Makefile
+++ b/drivers/s390/crypto/Makefile
@@ -2,16 +2,6 @@
 # S/390 crypto devices
 #
 
-ifdef CONFIG_ZCRYPT_MONOLITHIC
-
-z90crypt-objs := zcrypt_mono.o ap_bus.o zcrypt_api.o \
-		zcrypt_pcica.o zcrypt_pcicc.o zcrypt_pcixcc.o zcrypt_cex2a.o
-obj-$(CONFIG_ZCRYPT) += z90crypt.o
-
-else
-
 ap-objs := ap_bus.o
 obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o zcrypt_pcicc.o zcrypt_pcixcc.o
 obj-$(CONFIG_ZCRYPT) += zcrypt_pcica.o zcrypt_cex2a.o
-
-endif
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 96bbe9d..7e9a72e 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -42,10 +42,10 @@
 #include <asm/reset.h>
 #include <asm/airq.h>
 #include <linux/atomic.h>
-#include <asm/system.h>
 #include <asm/isc.h>
 #include <linux/hrtimer.h>
 #include <linux/ktime.h>
+#include <asm/facility.h>
 
 #include "ap_bus.h"
 
@@ -1862,7 +1862,5 @@
 	}
 }
 
-#ifndef CONFIG_ZCRYPT_MONOLITHIC
 module_init(ap_module_init);
 module_exit(ap_module_exit);
-#endif
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 88ad33e..8852320 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -1220,7 +1220,5 @@
 	misc_deregister(&zcrypt_misc_device);
 }
 
-#ifndef CONFIG_ZCRYPT_MONOLITHIC
 module_init(zcrypt_api_init);
 module_exit(zcrypt_api_exit);
-#endif
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c
index da171b5..0842867 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.c
+++ b/drivers/s390/crypto/zcrypt_cex2a.c
@@ -63,13 +63,11 @@
 	{ /* end of list */ },
 };
 
-#ifndef CONFIG_ZCRYPT_MONOLITHIC
 MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_ids);
 MODULE_AUTHOR("IBM Corporation");
 MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, "
 		   "Copyright 2001, 2006 IBM Corporation");
 MODULE_LICENSE("GPL");
-#endif
 
 static int zcrypt_cex2a_probe(struct ap_device *ap_dev);
 static void zcrypt_cex2a_remove(struct ap_device *ap_dev);
@@ -496,7 +494,5 @@
 	ap_driver_unregister(&zcrypt_cex2a_driver);
 }
 
-#ifndef CONFIG_ZCRYPT_MONOLITHIC
 module_init(zcrypt_cex2a_init);
 module_exit(zcrypt_cex2a_exit);
-#endif
diff --git a/drivers/s390/crypto/zcrypt_mono.c b/drivers/s390/crypto/zcrypt_mono.c
deleted file mode 100644
index eb313c3..0000000
--- a/drivers/s390/crypto/zcrypt_mono.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- *  linux/drivers/s390/crypto/zcrypt_mono.c
- *
- *  zcrypt 2.1.0
- *
- *  Copyright (C)  2001, 2006 IBM Corporation
- *  Author(s): Robert Burroughs
- *	       Eric Rossman (edrossma@us.ibm.com)
- *
- *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
- *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.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, 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/init.h>
-#include <linux/interrupt.h>
-#include <linux/miscdevice.h>
-#include <linux/fs.h>
-#include <linux/proc_fs.h>
-#include <linux/compat.h>
-#include <linux/atomic.h>
-#include <asm/uaccess.h>
-
-#include "ap_bus.h"
-#include "zcrypt_api.h"
-#include "zcrypt_pcica.h"
-#include "zcrypt_pcicc.h"
-#include "zcrypt_pcixcc.h"
-#include "zcrypt_cex2a.h"
-
-/**
- * The module initialization code.
- */
-static int __init zcrypt_init(void)
-{
-	int rc;
-
-	rc = ap_module_init();
-	if (rc)
-		goto out;
-	rc = zcrypt_api_init();
-	if (rc)
-		goto out_ap;
-	rc = zcrypt_pcica_init();
-	if (rc)
-		goto out_api;
-	rc = zcrypt_pcicc_init();
-	if (rc)
-		goto out_pcica;
-	rc = zcrypt_pcixcc_init();
-	if (rc)
-		goto out_pcicc;
-	rc = zcrypt_cex2a_init();
-	if (rc)
-		goto out_pcixcc;
-	return 0;
-
-out_pcixcc:
-	zcrypt_pcixcc_exit();
-out_pcicc:
-	zcrypt_pcicc_exit();
-out_pcica:
-	zcrypt_pcica_exit();
-out_api:
-	zcrypt_api_exit();
-out_ap:
-	ap_module_exit();
-out:
-	return rc;
-}
-
-/**
- * The module termination code.
- */
-static void __exit zcrypt_exit(void)
-{
-	zcrypt_cex2a_exit();
-	zcrypt_pcixcc_exit();
-	zcrypt_pcicc_exit();
-	zcrypt_pcica_exit();
-	zcrypt_api_exit();
-	ap_module_exit();
-}
-
-module_init(zcrypt_init);
-module_exit(zcrypt_exit);
diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c
index d84816f..0effca9 100644
--- a/drivers/s390/crypto/zcrypt_pcica.c
+++ b/drivers/s390/crypto/zcrypt_pcica.c
@@ -53,13 +53,11 @@
 	{ /* end of list */ },
 };
 
-#ifndef CONFIG_ZCRYPT_MONOLITHIC
 MODULE_DEVICE_TABLE(ap, zcrypt_pcica_ids);
 MODULE_AUTHOR("IBM Corporation");
 MODULE_DESCRIPTION("PCICA Cryptographic Coprocessor device driver, "
 		   "Copyright 2001, 2006 IBM Corporation");
 MODULE_LICENSE("GPL");
-#endif
 
 static int zcrypt_pcica_probe(struct ap_device *ap_dev);
 static void zcrypt_pcica_remove(struct ap_device *ap_dev);
@@ -408,7 +406,5 @@
 	ap_driver_unregister(&zcrypt_pcica_driver);
 }
 
-#ifndef CONFIG_ZCRYPT_MONOLITHIC
 module_init(zcrypt_pcica_init);
 module_exit(zcrypt_pcica_exit);
-#endif
diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c
index bdbdbe1..f9523c0 100644
--- a/drivers/s390/crypto/zcrypt_pcicc.c
+++ b/drivers/s390/crypto/zcrypt_pcicc.c
@@ -65,13 +65,11 @@
 	{ /* end of list */ },
 };
 
-#ifndef CONFIG_ZCRYPT_MONOLITHIC
 MODULE_DEVICE_TABLE(ap, zcrypt_pcicc_ids);
 MODULE_AUTHOR("IBM Corporation");
 MODULE_DESCRIPTION("PCICC Cryptographic Coprocessor device driver, "
 		   "Copyright 2001, 2006 IBM Corporation");
 MODULE_LICENSE("GPL");
-#endif
 
 static int zcrypt_pcicc_probe(struct ap_device *ap_dev);
 static void zcrypt_pcicc_remove(struct ap_device *ap_dev);
@@ -614,7 +612,5 @@
 	ap_driver_unregister(&zcrypt_pcicc_driver);
 }
 
-#ifndef CONFIG_ZCRYPT_MONOLITHIC
 module_init(zcrypt_pcicc_init);
 module_exit(zcrypt_pcicc_exit);
-#endif
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index 077b7d1..cf1cbd4 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -75,13 +75,11 @@
 	{ /* end of list */ },
 };
 
-#ifndef CONFIG_ZCRYPT_MONOLITHIC
 MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids);
 MODULE_AUTHOR("IBM Corporation");
 MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, "
 		   "Copyright 2001, 2006 IBM Corporation");
 MODULE_LICENSE("GPL");
-#endif
 
 static int zcrypt_pcixcc_probe(struct ap_device *ap_dev);
 static void zcrypt_pcixcc_remove(struct ap_device *ap_dev);
@@ -1121,7 +1119,5 @@
 	ap_driver_unregister(&zcrypt_pcixcc_driver);
 }
 
-#ifndef CONFIG_ZCRYPT_MONOLITHIC
 module_init(zcrypt_pcixcc_init);
 module_exit(zcrypt_pcixcc_exit);
-#endif
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index 7bc1955..d74e9ae 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -380,15 +380,13 @@
 /*
  * we emulate the request_irq behaviour on top of s390 extints
  */
-static void kvm_extint_handler(unsigned int ext_int_code,
+static void kvm_extint_handler(struct ext_code ext_code,
 			       unsigned int param32, unsigned long param64)
 {
 	struct virtqueue *vq;
-	u16 subcode;
 	u32 param;
 
-	subcode = ext_int_code >> 16;
-	if ((subcode & 0xff00) != VIRTIO_SUBCODE_64)
+	if ((ext_code.subcode & 0xff00) != VIRTIO_SUBCODE_64)
 		return;
 	kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++;
 
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index 826157f..327657e 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -16,7 +16,6 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 8d6e508..2236aea 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -40,7 +40,6 @@
 #include <linux/fs.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/openpromio.h>
 #ifdef CONFIG_PCI
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index 0b31658..a9e468c 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -19,7 +19,6 @@
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index f672491..a3adfb4 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -129,7 +129,6 @@
 #include <linux/interrupt.h>
 #include <linux/device.h>
 #include <asm/dma.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/byteorder.h>
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index f66c33b..d4da370 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -47,7 +47,6 @@
 
 #include <asm/dma.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index d3d18e8..29684c8 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -619,6 +619,7 @@
 
 source "drivers/scsi/megaraid/Kconfig.megaraid"
 source "drivers/scsi/mpt2sas/Kconfig"
+source "drivers/scsi/ufs/Kconfig"
 
 config SCSI_HPTIOP
 	tristate "HighPoint RocketRAID 3xxx/4xxx Controller support"
@@ -974,9 +975,8 @@
 
 config SCSI_IBMVSCSI
 	tristate "IBM Virtual SCSI support"
-	depends on PPC_PSERIES || PPC_ISERIES
+	depends on PPC_PSERIES
 	select SCSI_SRP_ATTRS
-	select VIOPATH if PPC_ISERIES
 	help
 	  This is the IBM POWER Virtual SCSI Client
 
@@ -1904,6 +1904,14 @@
 	  To compile this driver as a module, choose M here. The module will
 	  be called bfa.
 
+config SCSI_VIRTIO
+	tristate "virtio-scsi support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && VIRTIO
+	help
+          This is the virtual HBA driver for virtio.  If the kernel will
+          be used in a virtual machine, say Y or M.
+
+
 endif # SCSI_LOWLEVEL
 
 source "drivers/scsi/pcmcia/Kconfig"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index e4c1a69..8deedea 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -108,6 +108,7 @@
 obj-$(CONFIG_MEGARAID_NEWGEN)	+= megaraid/
 obj-$(CONFIG_MEGARAID_SAS)	+= megaraid/
 obj-$(CONFIG_SCSI_MPT2SAS)	+= mpt2sas/
+obj-$(CONFIG_SCSI_UFSHCD)	+= ufs/
 obj-$(CONFIG_SCSI_ACARD)	+= atp870u.o
 obj-$(CONFIG_SCSI_SUNESP)	+= esp_scsi.o	sun_esp.o
 obj-$(CONFIG_SCSI_GDTH)		+= gdth.o
@@ -141,6 +142,7 @@
 obj-$(CONFIG_SCSI_BNX2_ISCSI)	+= libiscsi.o bnx2i/
 obj-$(CONFIG_BE2ISCSI)		+= libiscsi.o be2iscsi/
 obj-$(CONFIG_SCSI_PMCRAID)	+= pmcraid.o
+obj-$(CONFIG_SCSI_VIRTIO)	+= virtio_scsi.o
 obj-$(CONFIG_VMWARE_PVSCSI)	+= vmw_pvscsi.o
 obj-$(CONFIG_HYPERV_STORAGE)	+= hv_storvsc.o
 
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 409f580..5255166 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -151,7 +151,11 @@
 int aac_commit = -1;
 int startup_timeout = 180;
 int aif_timeout = 120;
+int aac_sync_mode;  /* Only Sync. transfer - disabled */
 
+module_param(aac_sync_mode, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(aac_sync_mode, "Force sync. transfer mode"
+	" 0=off, 1=on");
 module_param(nondasd, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices."
 	" 0=off, 1=on");
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index ffb5878..3fcf627 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,7 +12,7 @@
  *----------------------------------------------------------------------------*/
 
 #ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 28000
+# define AAC_DRIVER_BUILD 28900
 # define AAC_DRIVER_BRANCH "-ms"
 #endif
 #define MAXIMUM_NUM_CONTAINERS	32
@@ -756,8 +756,16 @@
 
 struct src_registers {
 	struct src_mu_registers MUnit;	/* 00h - c7h */
-	__le32 reserved1[130790];	/* c8h - 7fc5fh */
-	struct src_inbound IndexRegs;	/* 7fc60h */
+	union {
+		struct {
+			__le32 reserved1[130790];	/* c8h - 7fc5fh */
+			struct src_inbound IndexRegs;	/* 7fc60h */
+		} tupelo;
+		struct {
+			__le32 reserved1[974];		/* c8h - fffh */
+			struct src_inbound IndexRegs;	/* 1000h */
+		} denali;
+	} u;
 };
 
 #define src_readb(AEP, CSR)		readb(&((AEP)->regs.src.bar0->CSR))
@@ -999,6 +1007,10 @@
 #define AAC_OPT_NEW_COMM		cpu_to_le32(1<<17)
 #define AAC_OPT_NEW_COMM_64		cpu_to_le32(1<<18)
 #define AAC_OPT_NEW_COMM_TYPE1		cpu_to_le32(1<<28)
+#define AAC_OPT_NEW_COMM_TYPE2		cpu_to_le32(1<<29)
+#define AAC_OPT_NEW_COMM_TYPE3		cpu_to_le32(1<<30)
+#define AAC_OPT_NEW_COMM_TYPE4		cpu_to_le32(1<<31)
+
 
 struct aac_dev
 {
@@ -1076,6 +1088,8 @@
 #	define AAC_MIN_FOOTPRINT_SIZE 8192
 #	define AAC_MIN_SRC_BAR0_SIZE 0x400000
 #	define AAC_MIN_SRC_BAR1_SIZE 0x800
+#	define AAC_MIN_SRCV_BAR0_SIZE 0x100000
+#	define AAC_MIN_SRCV_BAR1_SIZE 0x400
 #endif
 	union
 	{
@@ -1116,7 +1130,10 @@
 	u8			msi;
 	int			management_fib_count;
 	spinlock_t		manage_lock;
-
+	spinlock_t		sync_lock;
+	int			sync_mode;
+	struct fib		*sync_fib;
+	struct list_head	sync_fib_list;
 };
 
 #define aac_adapter_interrupt(dev) \
@@ -1163,6 +1180,7 @@
 
 #define FIB_CONTEXT_FLAG_TIMED_OUT		(0x00000001)
 #define FIB_CONTEXT_FLAG			(0x00000002)
+#define FIB_CONTEXT_FLAG_WAIT			(0x00000004)
 
 /*
  *	Define the command values
@@ -1970,6 +1988,7 @@
 int aac_nark_init(struct aac_dev *dev);
 int aac_sa_init(struct aac_dev *dev);
 int aac_src_init(struct aac_dev *dev);
+int aac_srcv_init(struct aac_dev *dev);
 int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify);
 unsigned int aac_response_normal(struct aac_queue * q);
 unsigned int aac_command_normal(struct aac_queue * q);
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 7ac8fdb..a35f54e 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -325,12 +325,14 @@
 {
 	u32 status[5];
 	struct Scsi_Host * host = dev->scsi_host_ptr;
+	extern int aac_sync_mode;
 
 	/*
 	 *	Check the preferred comm settings, defaults from template.
 	 */
 	dev->management_fib_count = 0;
 	spin_lock_init(&dev->manage_lock);
+	spin_lock_init(&dev->sync_lock);
 	dev->max_fib_size = sizeof(struct hw_fib);
 	dev->sg_tablesize = host->sg_tablesize = (dev->max_fib_size
 		- sizeof(struct aac_fibhdr)
@@ -344,13 +346,21 @@
 	 		(status[0] == 0x00000001)) {
 		if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64))
 			dev->raw_io_64 = 1;
-		if (dev->a_ops.adapter_comm) {
-			if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE1)) {
-				dev->comm_interface = AAC_COMM_MESSAGE_TYPE1;
-				dev->raw_io_interface = 1;
-			} else if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM)) {
+		dev->sync_mode = aac_sync_mode;
+		if (dev->a_ops.adapter_comm &&
+			(status[1] & le32_to_cpu(AAC_OPT_NEW_COMM))) {
 				dev->comm_interface = AAC_COMM_MESSAGE;
 				dev->raw_io_interface = 1;
+			if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE1))) {
+				/* driver supports TYPE1 (Tupelo) */
+				dev->comm_interface = AAC_COMM_MESSAGE_TYPE1;
+			} else if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE4)) ||
+				  (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE3)) ||
+				  (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE2))) {
+					/* driver doesn't support TYPE2 (Series7), TYPE3 and TYPE4 */
+					/* switch to sync. mode */
+					dev->comm_interface = AAC_COMM_MESSAGE_TYPE1;
+					dev->sync_mode = 1;
 			}
 		}
 		if ((dev->comm_interface == AAC_COMM_MESSAGE) &&
@@ -455,6 +465,7 @@
 	}
 		
 	INIT_LIST_HEAD(&dev->fib_list);
+	INIT_LIST_HEAD(&dev->sync_fib_list);
 
 	return dev;
 }
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index e5f2d7d..4b32ca4 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -416,6 +416,7 @@
 	unsigned long flags = 0;
 	unsigned long qflags;
 	unsigned long mflags = 0;
+	unsigned long sflags = 0;
 
 
 	if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned)))
@@ -512,6 +513,31 @@
 		spin_lock_irqsave(&fibptr->event_lock, flags);
 	}
 
+	if (dev->sync_mode) {
+		if (wait)
+			spin_unlock_irqrestore(&fibptr->event_lock, flags);
+		spin_lock_irqsave(&dev->sync_lock, sflags);
+		if (dev->sync_fib) {
+			list_add_tail(&fibptr->fiblink, &dev->sync_fib_list);
+			spin_unlock_irqrestore(&dev->sync_lock, sflags);
+		} else {
+			dev->sync_fib = fibptr;
+			spin_unlock_irqrestore(&dev->sync_lock, sflags);
+			aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB,
+				(u32)fibptr->hw_fib_pa, 0, 0, 0, 0, 0,
+				NULL, NULL, NULL, NULL, NULL);
+		}
+		if (wait) {
+			fibptr->flags |= FIB_CONTEXT_FLAG_WAIT;
+			if (down_interruptible(&fibptr->event_wait)) {
+				fibptr->flags &= ~FIB_CONTEXT_FLAG_WAIT;
+				return -EFAULT;
+			}
+			return 0;
+		}
+		return -EINPROGRESS;
+	}
+
 	if (aac_adapter_deliver(fibptr) != 0) {
 		printk(KERN_ERR "aac_fib_send: returned -EBUSY\n");
 		if (wait) {
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 705e13e..0d279c44 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -56,7 +56,7 @@
 
 #include "aacraid.h"
 
-#define AAC_DRIVER_VERSION		"1.1-7"
+#define AAC_DRIVER_VERSION		"1.2-0"
 #ifndef AAC_DRIVER_BRANCH
 #define AAC_DRIVER_BRANCH		""
 #endif
@@ -162,7 +162,10 @@
 	{ 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 59 }, /* Adaptec Catch All */
 	{ 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 60 }, /* Adaptec Rocket Catch All */
 	{ 0x9005, 0x0288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 61 }, /* Adaptec NEMER/ARK Catch All */
-	{ 0x9005, 0x028b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 62 }, /* Adaptec PMC Catch All */
+	{ 0x9005, 0x028b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 62 }, /* Adaptec PMC Series 6 (Tupelo) */
+	{ 0x9005, 0x028c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 63 }, /* Adaptec PMC Series 7 (Denali) */
+	{ 0x9005, 0x028d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 64 }, /* Adaptec PMC Series 8 */
+	{ 0x9005, 0x028f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 65 }, /* Adaptec PMC Series 9 */
 	{ 0,}
 };
 MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
@@ -238,7 +241,10 @@
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "RAID            ", 2 }, /* Adaptec Catch All */
 	{ aac_rkt_init, "aacraid", "ADAPTEC ", "RAID            ", 2 }, /* Adaptec Rocket Catch All */
 	{ aac_nark_init, "aacraid", "ADAPTEC ", "RAID           ", 2 }, /* Adaptec NEMER/ARK Catch All */
-	{ aac_src_init, "aacraid", "ADAPTEC ", "RAID            ", 2 } /* Adaptec PMC Catch All */
+	{ aac_src_init, "aacraid", "ADAPTEC ", "RAID            ", 2 }, /* Adaptec PMC Series 6 (Tupelo) */
+	{ aac_srcv_init, "aacraid", "ADAPTEC ", "RAID            ", 2 }, /* Adaptec PMC Series 7 (Denali) */
+	{ aac_srcv_init, "aacraid", "ADAPTEC ", "RAID            ", 2 }, /* Adaptec PMC Series 8 */
+	{ aac_srcv_init, "aacraid", "ADAPTEC ", "RAID            ", 2 } /* Adaptec PMC Series 9 */
 };
 
 /**
@@ -1102,6 +1108,7 @@
 	int error = -ENODEV;
 	int unique_id = 0;
 	u64 dmamask;
+	extern int aac_sync_mode;
 
 	list_for_each_entry(aac, &aac_devices, entry) {
 		if (aac->id > unique_id)
@@ -1162,6 +1169,21 @@
 	if ((*aac_drivers[index].init)(aac))
 		goto out_unmap;
 
+	if (aac->sync_mode) {
+		if (aac_sync_mode)
+			printk(KERN_INFO "%s%d: Sync. mode enforced "
+				"by driver parameter. This will cause "
+				"a significant performance decrease!\n",
+				aac->name,
+				aac->id);
+		else
+			printk(KERN_INFO "%s%d: Async. mode not supported "
+				"by current driver, sync. mode enforced."
+				"\nPlease update driver to get full performance.\n",
+				aac->name,
+				aac->id);
+	}
+
 	/*
 	 *	Start any kernel threads needed
 	 */
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index ce530f1..b029c7cc7 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -643,6 +643,7 @@
 	if (aac_init_adapter(dev) == NULL)
 		goto error_iounmap;
 	aac_adapter_comm(dev, dev->comm_interface);
+	dev->sync_mode = 0;	/* sync. mode not supported */
 	dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
 	if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
 			IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) {
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
index e5d4457..beb5336 100644
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -385,6 +385,7 @@
 
 	if(aac_init_adapter(dev) == NULL)
 		goto error_irq;
+	dev->sync_mode = 0;	/* sync. mode not supported */
 	if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
 			IRQF_SHARED|IRQF_DISABLED,
 			"aacraid", (void *)dev ) < 0) {
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index 957595a..2bee515 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -96,6 +96,38 @@
 			our_interrupt = 1;
 			/* handle AIF */
 			aac_intr_normal(dev, 0, 2, 0, NULL);
+		} else if (bellbits_shifted & OUTBOUNDDOORBELL_0) {
+			unsigned long sflags;
+			struct list_head *entry;
+			int send_it = 0;
+
+			if (dev->sync_fib) {
+				our_interrupt = 1;
+				if (dev->sync_fib->callback)
+					dev->sync_fib->callback(dev->sync_fib->callback_data,
+						dev->sync_fib);
+				spin_lock_irqsave(&dev->sync_fib->event_lock, sflags);
+				if (dev->sync_fib->flags & FIB_CONTEXT_FLAG_WAIT) {
+					dev->management_fib_count--;
+					up(&dev->sync_fib->event_wait);
+				}
+				spin_unlock_irqrestore(&dev->sync_fib->event_lock, sflags);
+				spin_lock_irqsave(&dev->sync_lock, sflags);
+				if (!list_empty(&dev->sync_fib_list)) {
+					entry = dev->sync_fib_list.next;
+					dev->sync_fib = list_entry(entry, struct fib, fiblink);
+					list_del(entry);
+					send_it = 1;
+				} else {
+					dev->sync_fib = NULL;
+				}
+				spin_unlock_irqrestore(&dev->sync_lock, sflags);
+				if (send_it) {
+					aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB,
+						(u32)dev->sync_fib->hw_fib_pa, 0, 0, 0, 0, 0,
+						NULL, NULL, NULL, NULL, NULL);
+				}
+			}
 		}
 	}
 
@@ -177,56 +209,63 @@
 	 */
 	src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT);
 
-	ok = 0;
-	start = jiffies;
+	if (!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) {
+		ok = 0;
+		start = jiffies;
+
+		/*
+		 *	Wait up to 5 minutes
+		 */
+		while (time_before(jiffies, start+300*HZ)) {
+			udelay(5);	/* Delay 5 microseconds to let Mon960 get info. */
+			/*
+			 *	Mon960 will set doorbell0 bit when it has completed the command.
+			 */
+			if ((src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT) & OUTBOUNDDOORBELL_0) {
+				/*
+				 *	Clear the doorbell.
+				 */
+				src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
+				ok = 1;
+				break;
+			}
+			/*
+			 *	Yield the processor in case we are slow
+			 */
+			msleep(1);
+		}
+		if (unlikely(ok != 1)) {
+			/*
+			 *	Restore interrupt mask even though we timed out
+			 */
+			aac_adapter_enable_int(dev);
+			return -ETIMEDOUT;
+		}
+		/*
+		 *	Pull the synch status from Mailbox 0.
+		 */
+		if (status)
+			*status = readl(&dev->IndexRegs->Mailbox[0]);
+		if (r1)
+			*r1 = readl(&dev->IndexRegs->Mailbox[1]);
+		if (r2)
+			*r2 = readl(&dev->IndexRegs->Mailbox[2]);
+		if (r3)
+			*r3 = readl(&dev->IndexRegs->Mailbox[3]);
+		if (r4)
+			*r4 = readl(&dev->IndexRegs->Mailbox[4]);
+
+		/*
+		 *	Clear the synch command doorbell.
+		 */
+		src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
+	}
 
 	/*
-	 *	Wait up to 30 seconds
+	 *	Restore interrupt mask
 	 */
-	while (time_before(jiffies, start+30*HZ)) {
-		/* Delay 5 microseconds to let Mon960 get info. */
-		udelay(5);
-
-		/* Mon960 will set doorbell0 bit
-		 * when it has completed the command
-		 */
-		if ((src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT) & OUTBOUNDDOORBELL_0) {
-			/* Clear the doorbell */
-			src_writel(dev,
-				MUnit.ODR_C,
-				OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
-			ok = 1;
-			break;
-		}
-
-		 /* Yield the processor in case we are slow */
-		msleep(1);
-	}
-	if (unlikely(ok != 1)) {
-		 /* Restore interrupt mask even though we timed out */
-		aac_adapter_enable_int(dev);
-		return -ETIMEDOUT;
-	}
-
-	 /* Pull the synch status from Mailbox 0 */
-	if (status)
-		*status = readl(&dev->IndexRegs->Mailbox[0]);
-	if (r1)
-		*r1 = readl(&dev->IndexRegs->Mailbox[1]);
-	if (r2)
-		*r2 = readl(&dev->IndexRegs->Mailbox[2]);
-	if (r3)
-		*r3 = readl(&dev->IndexRegs->Mailbox[3]);
-	if (r4)
-		*r4 = readl(&dev->IndexRegs->Mailbox[4]);
-
-	 /* Clear the synch command doorbell */
-	src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
-
-	 /* Restore interrupt mask */
 	aac_adapter_enable_int(dev);
 	return 0;
-
 }
 
 /**
@@ -386,9 +425,7 @@
 {
 	if (!size) {
 		iounmap(dev->regs.src.bar0);
-		dev->regs.src.bar0 = NULL;
-		iounmap(dev->base);
-		dev->base = NULL;
+		dev->base = dev->regs.src.bar0 = NULL;
 		return 0;
 	}
 	dev->regs.src.bar1 = ioremap(pci_resource_start(dev->pdev, 2),
@@ -404,7 +441,27 @@
 		return -1;
 	}
 	dev->IndexRegs = &((struct src_registers __iomem *)
-		dev->base)->IndexRegs;
+		dev->base)->u.tupelo.IndexRegs;
+	return 0;
+}
+
+/**
+ *  aac_srcv_ioremap
+ *	@size: mapping resize request
+ *
+ */
+static int aac_srcv_ioremap(struct aac_dev *dev, u32 size)
+{
+	if (!size) {
+		iounmap(dev->regs.src.bar0);
+		dev->base = dev->regs.src.bar0 = NULL;
+		return 0;
+	}
+	dev->base = dev->regs.src.bar0 = ioremap(dev->scsi_host_ptr->base, size);
+	if (dev->base == NULL)
+		return -1;
+	dev->IndexRegs = &((struct src_registers __iomem *)
+		dev->base)->u.denali.IndexRegs;
 	return 0;
 }
 
@@ -419,7 +476,7 @@
 		bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
 			0, 0, 0, 0, 0, 0, &var, &reset_mask, NULL, NULL, NULL);
 			if (bled || (var != 0x00000001))
-				bled = -EINVAL;
+				return -EINVAL;
 		if (dev->supplement_adapter_info.SupportedOptions2 &
 			AAC_OPTION_DOORBELL_RESET) {
 			src_writel(dev, MUnit.IDR, reset_mask);
@@ -579,15 +636,149 @@
 	dev->dbg_size = AAC_MIN_SRC_BAR1_SIZE;
 
 	aac_adapter_enable_int(dev);
-	/*
-	 *	Tell the adapter that all is configured, and it can
-	 * start accepting requests
-	 */
-	aac_src_start_adapter(dev);
 
+	if (!dev->sync_mode) {
+		/*
+		 * Tell the adapter that all is configured, and it can
+		 * start accepting requests
+		 */
+		aac_src_start_adapter(dev);
+	}
 	return 0;
 
 error_iounmap:
 
 	return -1;
 }
+
+/**
+ *  aac_srcv_init	-	initialize an SRCv card
+ *  @dev: device to configure
+ *
+ */
+
+int aac_srcv_init(struct aac_dev *dev)
+{
+	unsigned long start;
+	unsigned long status;
+	int restart = 0;
+	int instance = dev->id;
+	const char *name = dev->name;
+
+	dev->a_ops.adapter_ioremap = aac_srcv_ioremap;
+	dev->a_ops.adapter_comm = aac_src_select_comm;
+
+	dev->base_size = AAC_MIN_SRCV_BAR0_SIZE;
+	if (aac_adapter_ioremap(dev, dev->base_size)) {
+		printk(KERN_WARNING "%s: unable to map adapter.\n", name);
+		goto error_iounmap;
+	}
+
+	/* Failure to reset here is an option ... */
+	dev->a_ops.adapter_sync_cmd = src_sync_cmd;
+	dev->a_ops.adapter_enable_int = aac_src_disable_interrupt;
+	if ((aac_reset_devices || reset_devices) &&
+		!aac_src_restart_adapter(dev, 0))
+		++restart;
+	/*
+	 *	Check to see if the board panic'd while booting.
+	 */
+	status = src_readl(dev, MUnit.OMR);
+	if (status & KERNEL_PANIC) {
+		if (aac_src_restart_adapter(dev, aac_src_check_health(dev)))
+			goto error_iounmap;
+		++restart;
+	}
+	/*
+	 *	Check to see if the board failed any self tests.
+	 */
+	status = src_readl(dev, MUnit.OMR);
+	if (status & SELF_TEST_FAILED) {
+		printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
+		goto error_iounmap;
+	}
+	/*
+	 *	Check to see if the monitor panic'd while booting.
+	 */
+	if (status & MONITOR_PANIC) {
+		printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
+		goto error_iounmap;
+	}
+	start = jiffies;
+	/*
+	 *	Wait for the adapter to be up and running. Wait up to 3 minutes
+	 */
+	while (!((status = src_readl(dev, MUnit.OMR)) & KERNEL_UP_AND_RUNNING)) {
+		if ((restart &&
+		  (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
+		  time_after(jiffies, start+HZ*startup_timeout)) {
+			printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n",
+					dev->name, instance, status);
+			goto error_iounmap;
+		}
+		if (!restart &&
+		  ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) ||
+		  time_after(jiffies, start + HZ *
+		  ((startup_timeout > 60)
+		    ? (startup_timeout - 60)
+		    : (startup_timeout / 2))))) {
+			if (likely(!aac_src_restart_adapter(dev, aac_src_check_health(dev))))
+				start = jiffies;
+			++restart;
+		}
+		msleep(1);
+	}
+	if (restart && aac_commit)
+		aac_commit = 1;
+	/*
+	 *	Fill in the common function dispatch table.
+	 */
+	dev->a_ops.adapter_interrupt = aac_src_interrupt_adapter;
+	dev->a_ops.adapter_disable_int = aac_src_disable_interrupt;
+	dev->a_ops.adapter_notify = aac_src_notify_adapter;
+	dev->a_ops.adapter_sync_cmd = src_sync_cmd;
+	dev->a_ops.adapter_check_health = aac_src_check_health;
+	dev->a_ops.adapter_restart = aac_src_restart_adapter;
+
+	/*
+	 *	First clear out all interrupts.  Then enable the one's that we
+	 *	can handle.
+	 */
+	aac_adapter_comm(dev, AAC_COMM_MESSAGE);
+	aac_adapter_disable_int(dev);
+	src_writel(dev, MUnit.ODR_C, 0xffffffff);
+	aac_adapter_enable_int(dev);
+
+	if (aac_init_adapter(dev) == NULL)
+		goto error_iounmap;
+	if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1)
+		goto error_iounmap;
+	dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
+	if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
+		IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) {
+		if (dev->msi)
+			pci_disable_msi(dev->pdev);
+		printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
+			name, instance);
+		goto error_iounmap;
+	}
+	dev->dbg_base = dev->scsi_host_ptr->base;
+	dev->dbg_base_mapped = dev->base;
+	dev->dbg_size = dev->base_size;
+
+	aac_adapter_enable_int(dev);
+
+	if (!dev->sync_mode) {
+		/*
+		 * Tell the adapter that all is configured, and it can
+		 * start accepting requests
+		 */
+		aac_src_start_adapter(dev);
+	}
+	return 0;
+
+error_iounmap:
+
+	return -1;
+}
+
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index bfd618a..374c4ed 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -41,7 +41,6 @@
 #include <linux/firmware.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 
 #include <scsi/scsi_cmnd.h>
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index f17c92c..19a3694 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -239,7 +239,6 @@
 #include <asm/irq.h>
 #include <linux/io.h>
 #include <linux/blkdev.h>
-#include <asm/system.h>
 #include <linux/completion.h>
 #include <linux/errno.h>
 #include <linux/string.h>
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index ed119ce..ede91f3 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -42,7 +42,6 @@
 #include <linux/slab.h>
 
 #include <asm/dma.h>
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include "scsi.h"
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index 1c10b79..a3e6ed3 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -53,7 +53,6 @@
 #include <linux/gfp.h>
 
 #include <asm/dma.h>
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include "scsi.h"
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 7d48700..9328121 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -341,10 +341,10 @@
 "				(0/256ms,1/128ms,2/64ms,3/32ms)\n"
 "	slowcrc			Turn on the SLOWCRC bit (Rev B only)\n"		 
 "\n"
-"	Sample /etc/modprobe.conf line:\n"
-"		Enable verbose logging\n"
-"		Set tag depth on Controller 2/Target 2 to 10 tags\n"
-"		Shorten the selection timeout to 128ms\n"
+"	Sample modprobe configuration file:\n"
+"	#	Enable verbose logging\n"
+"	#	Set tag depth on Controller 2/Target 2 to 10 tags\n"
+"	#	Shorten the selection timeout to 128ms\n"
 "\n"
 "	options aic79xx 'aic79xx=verbose.tag_info:{{}.{}.{..10}}.seltime:1'\n"
 );
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index c6251bb..5a477cd 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -360,10 +360,10 @@
 "	seltime:<int>		Selection Timeout\n"
 "				(0/256ms,1/128ms,2/64ms,3/32ms)\n"
 "\n"
-"	Sample /etc/modprobe.conf line:\n"
-"		Toggle EISA/VLB probing\n"
-"		Set tag depth on Controller 1/Target 1 to 10 tags\n"
-"		Shorten the selection timeout to 128ms\n"
+"	Sample modprobe configuration file:\n"
+"	#	Toggle EISA/VLB probing\n"
+"	#	Set tag depth on Controller 1/Target 1 to 10 tags\n"
+"	#	Shorten the selection timeout to 128ms\n"
 "\n"
 "	options aic7xxx 'aic7xxx=probe_eisa_vl.tag_info:{{}.{.10}}.seltime:1'\n"
 );
diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h
index 2863a9d..66cda66 100644
--- a/drivers/scsi/aic94xx/aic94xx.h
+++ b/drivers/scsi/aic94xx/aic94xx.h
@@ -80,6 +80,8 @@
 
 int  asd_execute_task(struct sas_task *, int num, gfp_t gfp_flags);
 
+void asd_set_dmamode(struct domain_device *dev);
+
 /* ---------- TMFs ---------- */
 int  asd_abort_task(struct sas_task *);
 int  asd_abort_task_set(struct domain_device *, u8 *lun);
diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c
index 2e2ddec9..64136c56 100644
--- a/drivers/scsi/aic94xx/aic94xx_dev.c
+++ b/drivers/scsi/aic94xx/aic94xx_dev.c
@@ -109,26 +109,37 @@
 	return 0;
 }
 
-static int asd_init_sata(struct domain_device *dev)
+void asd_set_dmamode(struct domain_device *dev)
 {
 	struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+	struct ata_device *ata_dev = sas_to_ata_dev(dev);
 	int ddb = (int) (unsigned long) dev->lldd_dev;
 	u32 qdepth = 0;
-	int res = 0;
 
-	asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
-	if ((dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT) &&
-	    dev->sata_dev.identify_device &&
-	    dev->sata_dev.identify_device[10] != 0) {
-		u16 w75 = le16_to_cpu(dev->sata_dev.identify_device[75]);
-		u16 w76 = le16_to_cpu(dev->sata_dev.identify_device[76]);
-
-		if (w76 & 0x100) /* NCQ? */
-			qdepth = (w75 & 0x1F) + 1;
+	if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT) {
+		if (ata_id_has_ncq(ata_dev->id))
+			qdepth = ata_id_queue_depth(ata_dev->id);
 		asd_ddbsite_write_dword(asd_ha, ddb, SATA_TAG_ALLOC_MASK,
 					(1ULL<<qdepth)-1);
 		asd_ddbsite_write_byte(asd_ha, ddb, NUM_SATA_TAGS, qdepth);
 	}
+
+	if (qdepth > 0)
+		if (asd_init_sata_tag_ddb(dev) != 0) {
+			unsigned long flags;
+
+			spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
+			ata_dev->flags |= ATA_DFLAG_NCQ_OFF;
+			spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
+		}
+}
+
+static int asd_init_sata(struct domain_device *dev)
+{
+	struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+	int ddb = (int) (unsigned long) dev->lldd_dev;
+
+	asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
 	if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM ||
 	    dev->dev_type == SATA_PM_PORT) {
 		struct dev_to_host_fis *fis = (struct dev_to_host_fis *)
@@ -136,9 +147,8 @@
 		asd_ddbsite_write_byte(asd_ha, ddb, SATA_STATUS, fis->status);
 	}
 	asd_ddbsite_write_word(asd_ha, ddb, NCQ_DATA_SCB_PTR, 0xFFFF);
-	if (qdepth > 0)
-		res = asd_init_sata_tag_ddb(dev);
-	return res;
+
+	return 0;
 }
 
 static int asd_init_target_ddb(struct domain_device *dev)
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index d5ff142..ff80552 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -68,7 +68,6 @@
 	.queuecommand		= sas_queuecommand,
 	.target_alloc		= sas_target_alloc,
 	.slave_configure	= sas_slave_configure,
-	.slave_destroy		= sas_slave_destroy,
 	.scan_finished		= asd_scan_finished,
 	.scan_start		= asd_scan_start,
 	.change_queue_depth	= sas_change_queue_depth,
@@ -82,7 +81,6 @@
 	.use_clustering		= ENABLE_CLUSTERING,
 	.eh_device_reset_handler	= sas_eh_device_reset_handler,
 	.eh_bus_reset_handler	= sas_eh_bus_reset_handler,
-	.slave_alloc		= sas_slave_alloc,
 	.target_destroy		= sas_target_destroy,
 	.ioctl			= sas_ioctl,
 };
@@ -972,7 +970,7 @@
 	if (time < HZ)
 		return 0;
 	/* Wait for discovery to finish */
-	scsi_flush_work(shost);
+	sas_drain_work(SHOST_TO_SAS_HA(shost));
 	return 1;
 }
 
@@ -1010,6 +1008,8 @@
 	.lldd_clear_nexus_ha	= asd_clear_nexus_ha,
 
 	.lldd_control_phy	= asd_control_phy,
+
+	.lldd_ata_set_dmamode	= asd_set_dmamode,
 };
 
 static const struct pci_device_id aic94xx_pci_table[] __devinitdata = {
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
index 0add73b..cf90409 100644
--- a/drivers/scsi/aic94xx/aic94xx_tmf.c
+++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
@@ -181,7 +181,7 @@
 int asd_I_T_nexus_reset(struct domain_device *dev)
 {
 	int res, tmp_res, i;
-	struct sas_phy *phy = sas_find_local_phy(dev);
+	struct sas_phy *phy = sas_get_local_phy(dev);
 	/* Standard mandates link reset for ATA  (type 0) and
 	 * hard reset for SSP (type 1) */
 	int reset_type = (dev->dev_type == SATA_DEV ||
@@ -192,7 +192,7 @@
 	ASD_DPRINTK("sending %s reset to %s\n",
 		    reset_type ? "hard" : "soft", dev_name(&phy->dev));
 	res = sas_phy_reset(phy, reset_type);
-	if (res == TMF_RESP_FUNC_COMPLETE) {
+	if (res == TMF_RESP_FUNC_COMPLETE || res == -ENODEV) {
 		/* wait for the maximum settle time */
 		msleep(500);
 		/* clear all outstanding commands (keep nexus suspended) */
@@ -201,7 +201,7 @@
 	for (i = 0 ; i < 3; i++) {
 		tmp_res = asd_clear_nexus_I_T(dev, NEXUS_PHASE_RESUME);
 		if (tmp_res == TC_RESUME)
-			return res;
+			goto out;
 		msleep(500);
 	}
 
@@ -211,7 +211,10 @@
 	dev_printk(KERN_ERR, &phy->dev,
 		   "Failed to resume nexus after reset 0x%x\n", tmp_res);
 
-	return TMF_RESP_FUNC_FAILED;
+	res = TMF_RESP_FUNC_FAILED;
+ out:
+	sas_put_local_phy(phy);
+	return res;
 }
 
 static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun)
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 2fe9e90..cbde1dca 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -61,7 +61,6 @@
 #include <linux/aer.h>
 #include <asm/dma.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi.h>
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index c454e44..b330438 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -138,7 +138,6 @@
 #include <linux/stringify.h>
 #include <linux/io.h>
 
-#include <asm/system.h>
 #include <asm/ecard.h>
 
 #include "../scsi.h"
diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c
index a750aa7..2a28b4a 100644
--- a/drivers/scsi/arm/arxescsi.c
+++ b/drivers/scsi/arm/arxescsi.c
@@ -305,7 +305,7 @@
 	info->base = base;
 
 	info->info.scsi.io_base		= base + 0x2000;
-	info->info.scsi.irq		= NO_IRQ;
+	info->info.scsi.irq		= 0;
 	info->info.scsi.dma		= NO_DMA;
 	info->info.scsi.io_shift	= 5;
 	info->info.ifcfg.clockrate	= 24; /* MHz */
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index a3398fe..c3b99c9 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -12,7 +12,6 @@
 
 #include <asm/ecard.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include "../scsi.h"
 #include <scsi/scsi_host.h>
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index e85c40b..6206a66 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -2176,7 +2176,7 @@
 	fn = (void (*)(FAS216_Info *, struct scsi_cmnd *, unsigned int))SCpnt->host_scribble;
 	fn(info, SCpnt, result);
 
-	if (info->scsi.irq != NO_IRQ) {
+	if (info->scsi.irq) {
 		spin_lock_irqsave(&info->host_lock, flags);
 		if (info->scsi.phase == PHASE_IDLE)
 			fas216_kick(info);
@@ -2276,7 +2276,7 @@
 	 * We should only be using this if we don't have an interrupt.
 	 * Provide some "incentive" to use the queueing code.
 	 */
-	BUG_ON(info->scsi.irq != NO_IRQ);
+	BUG_ON(info->scsi.irq);
 
 	info->internal_done = 0;
 	fas216_queue_command_lck(SCpnt, fas216_internal_done);
diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h
index 84b7127..df2e1b3 100644
--- a/drivers/scsi/arm/fas216.h
+++ b/drivers/scsi/arm/fas216.h
@@ -12,10 +12,6 @@
 #ifndef FAS216_H
 #define FAS216_H
 
-#ifndef NO_IRQ
-#define NO_IRQ 255
-#endif
-
 #include <scsi/scsi_eh.h>
 
 #include "queue.h"
diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
index 849cdf8..d25f944 100644
--- a/drivers/scsi/arm/oak.c
+++ b/drivers/scsi/arm/oak.c
@@ -13,7 +13,6 @@
 
 #include <asm/ecard.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include "../scsi.h"
 #include <scsi/scsi_host.h>
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index 7e6eca4..68ce085 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -30,7 +30,6 @@
 #include <linux/blkdev.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include <scsi/scsi.h>
@@ -2583,7 +2582,7 @@
 	 * this than via the PCI device table
 	 */
 	if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610) {
-		error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atpdev->chip_ver);
+		atpdev->chip_ver = pdev->revision;
 		if (atpdev->chip_ver < 2)
 			goto err_eio;
 	}
@@ -2602,7 +2601,7 @@
 	base_io &= 0xfffffff8;
 
 	if ((ent->device == ATP880_DEVID1)||(ent->device == ATP880_DEVID2)) {
-		error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atpdev->chip_ver);
+		atpdev->chip_ver = pdev->revision;
 		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);//JCC082803
 
 		host_id = inb(base_io + 0x39);
diff --git a/drivers/scsi/bfa/bfa.h b/drivers/scsi/bfa/bfa.h
index a796de9..4ad7e36 100644
--- a/drivers/scsi/bfa/bfa.h
+++ b/drivers/scsi/bfa/bfa.h
@@ -225,9 +225,9 @@
 };
 
 struct bfa_iocfc_s {
+	bfa_fsm_t		fsm;
 	struct bfa_s		*bfa;
 	struct bfa_iocfc_cfg_s	cfg;
-	int			action;
 	u32		req_cq_pi[BFI_IOC_MAX_CQS];
 	u32		rsp_cq_ci[BFI_IOC_MAX_CQS];
 	u8		hw_qid[BFI_IOC_MAX_CQS];
@@ -236,7 +236,9 @@
 	struct bfa_cb_qe_s	dis_hcb_qe;
 	struct bfa_cb_qe_s	en_hcb_qe;
 	struct bfa_cb_qe_s	stats_hcb_qe;
-	bfa_boolean_t		cfgdone;
+	bfa_boolean_t		submod_enabled;
+	bfa_boolean_t		cb_reqd;	/* Driver call back reqd */
+	bfa_status_t		op_status;	/* Status of bfa iocfc op */
 
 	struct bfa_dma_s	cfg_info;
 	struct bfi_iocfc_cfg_s *cfginfo;
@@ -341,8 +343,6 @@
 void bfa_hwct_msix_get_rme_range(struct bfa_s *bfa, u32 *start,
 				 u32 *end);
 void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t *wwns);
-wwn_t bfa_iocfc_get_pwwn(struct bfa_s *bfa);
-wwn_t bfa_iocfc_get_nwwn(struct bfa_s *bfa);
 int bfa_iocfc_get_pbc_vports(struct bfa_s *bfa,
 				struct bfi_pbc_vport_s *pbc_vport);
 
@@ -428,7 +428,6 @@
 
 void bfa_iocfc_enable(struct bfa_s *bfa);
 void bfa_iocfc_disable(struct bfa_s *bfa);
-void bfa_iocfc_cb_dconf_modinit(struct bfa_s *bfa, bfa_status_t status);
 #define bfa_timer_start(_bfa, _timer, _timercb, _arg, _timeout)		\
 	bfa_timer_begin(&(_bfa)->timer_mod, _timer, _timercb, _arg, _timeout)
 
diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c
index 4bd546b..456e576 100644
--- a/drivers/scsi/bfa/bfa_core.c
+++ b/drivers/scsi/bfa/bfa_core.c
@@ -200,13 +200,431 @@
 #define DEF_CFG_NUM_SBOOT_LUNS		16
 
 /*
+ * IOCFC state machine definitions/declarations
+ */
+bfa_fsm_state_decl(bfa_iocfc, stopped, struct bfa_iocfc_s, enum iocfc_event);
+bfa_fsm_state_decl(bfa_iocfc, initing, struct bfa_iocfc_s, enum iocfc_event);
+bfa_fsm_state_decl(bfa_iocfc, dconf_read, struct bfa_iocfc_s, enum iocfc_event);
+bfa_fsm_state_decl(bfa_iocfc, init_cfg_wait,
+		   struct bfa_iocfc_s, enum iocfc_event);
+bfa_fsm_state_decl(bfa_iocfc, init_cfg_done,
+		   struct bfa_iocfc_s, enum iocfc_event);
+bfa_fsm_state_decl(bfa_iocfc, operational,
+		   struct bfa_iocfc_s, enum iocfc_event);
+bfa_fsm_state_decl(bfa_iocfc, dconf_write,
+		   struct bfa_iocfc_s, enum iocfc_event);
+bfa_fsm_state_decl(bfa_iocfc, stopping, struct bfa_iocfc_s, enum iocfc_event);
+bfa_fsm_state_decl(bfa_iocfc, enabling, struct bfa_iocfc_s, enum iocfc_event);
+bfa_fsm_state_decl(bfa_iocfc, cfg_wait, struct bfa_iocfc_s, enum iocfc_event);
+bfa_fsm_state_decl(bfa_iocfc, disabling, struct bfa_iocfc_s, enum iocfc_event);
+bfa_fsm_state_decl(bfa_iocfc, disabled, struct bfa_iocfc_s, enum iocfc_event);
+bfa_fsm_state_decl(bfa_iocfc, failed, struct bfa_iocfc_s, enum iocfc_event);
+bfa_fsm_state_decl(bfa_iocfc, init_failed,
+		   struct bfa_iocfc_s, enum iocfc_event);
+
+/*
  * forward declaration for IOC FC functions
  */
+static void bfa_iocfc_start_submod(struct bfa_s *bfa);
+static void bfa_iocfc_disable_submod(struct bfa_s *bfa);
+static void bfa_iocfc_send_cfg(void *bfa_arg);
 static void bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status);
 static void bfa_iocfc_disable_cbfn(void *bfa_arg);
 static void bfa_iocfc_hbfail_cbfn(void *bfa_arg);
 static void bfa_iocfc_reset_cbfn(void *bfa_arg);
 static struct bfa_ioc_cbfn_s bfa_iocfc_cbfn;
+static void bfa_iocfc_init_cb(void *bfa_arg, bfa_boolean_t complete);
+static void bfa_iocfc_stop_cb(void *bfa_arg, bfa_boolean_t compl);
+static void bfa_iocfc_enable_cb(void *bfa_arg, bfa_boolean_t compl);
+static void bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl);
+
+static void
+bfa_iocfc_sm_stopped_entry(struct bfa_iocfc_s *iocfc)
+{
+}
+
+static void
+bfa_iocfc_sm_stopped(struct bfa_iocfc_s *iocfc, enum iocfc_event event)
+{
+	bfa_trc(iocfc->bfa, event);
+
+	switch (event) {
+	case IOCFC_E_INIT:
+	case IOCFC_E_ENABLE:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_initing);
+		break;
+	default:
+		bfa_sm_fault(iocfc->bfa, event);
+		break;
+	}
+}
+
+static void
+bfa_iocfc_sm_initing_entry(struct bfa_iocfc_s *iocfc)
+{
+	bfa_ioc_enable(&iocfc->bfa->ioc);
+}
+
+static void
+bfa_iocfc_sm_initing(struct bfa_iocfc_s *iocfc, enum iocfc_event event)
+{
+	bfa_trc(iocfc->bfa, event);
+
+	switch (event) {
+	case IOCFC_E_IOC_ENABLED:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_dconf_read);
+		break;
+	case IOCFC_E_IOC_FAILED:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_init_failed);
+		break;
+	default:
+		bfa_sm_fault(iocfc->bfa, event);
+		break;
+	}
+}
+
+static void
+bfa_iocfc_sm_dconf_read_entry(struct bfa_iocfc_s *iocfc)
+{
+	bfa_dconf_modinit(iocfc->bfa);
+}
+
+static void
+bfa_iocfc_sm_dconf_read(struct bfa_iocfc_s *iocfc, enum iocfc_event event)
+{
+	bfa_trc(iocfc->bfa, event);
+
+	switch (event) {
+	case IOCFC_E_DCONF_DONE:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_init_cfg_wait);
+		break;
+	case IOCFC_E_IOC_FAILED:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_init_failed);
+		break;
+	default:
+		bfa_sm_fault(iocfc->bfa, event);
+		break;
+	}
+}
+
+static void
+bfa_iocfc_sm_init_cfg_wait_entry(struct bfa_iocfc_s *iocfc)
+{
+	bfa_iocfc_send_cfg(iocfc->bfa);
+}
+
+static void
+bfa_iocfc_sm_init_cfg_wait(struct bfa_iocfc_s *iocfc, enum iocfc_event event)
+{
+	bfa_trc(iocfc->bfa, event);
+
+	switch (event) {
+	case IOCFC_E_CFG_DONE:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_init_cfg_done);
+		break;
+	case IOCFC_E_IOC_FAILED:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_init_failed);
+		break;
+	default:
+		bfa_sm_fault(iocfc->bfa, event);
+		break;
+	}
+}
+
+static void
+bfa_iocfc_sm_init_cfg_done_entry(struct bfa_iocfc_s *iocfc)
+{
+	iocfc->bfa->iocfc.op_status = BFA_STATUS_OK;
+	bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.init_hcb_qe,
+		     bfa_iocfc_init_cb, iocfc->bfa);
+}
+
+static void
+bfa_iocfc_sm_init_cfg_done(struct bfa_iocfc_s *iocfc, enum iocfc_event event)
+{
+	bfa_trc(iocfc->bfa, event);
+
+	switch (event) {
+	case IOCFC_E_START:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_operational);
+		break;
+	case IOCFC_E_STOP:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_stopping);
+		break;
+	case IOCFC_E_DISABLE:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_disabling);
+		break;
+	case IOCFC_E_IOC_FAILED:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_failed);
+		break;
+	default:
+		bfa_sm_fault(iocfc->bfa, event);
+		break;
+	}
+}
+
+static void
+bfa_iocfc_sm_operational_entry(struct bfa_iocfc_s *iocfc)
+{
+	bfa_fcport_init(iocfc->bfa);
+	bfa_iocfc_start_submod(iocfc->bfa);
+}
+
+static void
+bfa_iocfc_sm_operational(struct bfa_iocfc_s *iocfc, enum iocfc_event event)
+{
+	bfa_trc(iocfc->bfa, event);
+
+	switch (event) {
+	case IOCFC_E_STOP:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_dconf_write);
+		break;
+	case IOCFC_E_DISABLE:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_disabling);
+		break;
+	case IOCFC_E_IOC_FAILED:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_failed);
+		break;
+	default:
+		bfa_sm_fault(iocfc->bfa, event);
+		break;
+	}
+}
+
+static void
+bfa_iocfc_sm_dconf_write_entry(struct bfa_iocfc_s *iocfc)
+{
+	bfa_dconf_modexit(iocfc->bfa);
+}
+
+static void
+bfa_iocfc_sm_dconf_write(struct bfa_iocfc_s *iocfc, enum iocfc_event event)
+{
+	bfa_trc(iocfc->bfa, event);
+
+	switch (event) {
+	case IOCFC_E_DCONF_DONE:
+	case IOCFC_E_IOC_FAILED:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_stopping);
+		break;
+	default:
+		bfa_sm_fault(iocfc->bfa, event);
+		break;
+	}
+}
+
+static void
+bfa_iocfc_sm_stopping_entry(struct bfa_iocfc_s *iocfc)
+{
+	bfa_ioc_disable(&iocfc->bfa->ioc);
+}
+
+static void
+bfa_iocfc_sm_stopping(struct bfa_iocfc_s *iocfc, enum iocfc_event event)
+{
+	bfa_trc(iocfc->bfa, event);
+
+	switch (event) {
+	case IOCFC_E_IOC_DISABLED:
+		bfa_isr_disable(iocfc->bfa);
+		bfa_iocfc_disable_submod(iocfc->bfa);
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_stopped);
+		iocfc->bfa->iocfc.op_status = BFA_STATUS_OK;
+		bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.stop_hcb_qe,
+			     bfa_iocfc_stop_cb, iocfc->bfa);
+		break;
+	default:
+		bfa_sm_fault(iocfc->bfa, event);
+		break;
+	}
+}
+
+static void
+bfa_iocfc_sm_enabling_entry(struct bfa_iocfc_s *iocfc)
+{
+	bfa_ioc_enable(&iocfc->bfa->ioc);
+}
+
+static void
+bfa_iocfc_sm_enabling(struct bfa_iocfc_s *iocfc, enum iocfc_event event)
+{
+	bfa_trc(iocfc->bfa, event);
+
+	switch (event) {
+	case IOCFC_E_IOC_ENABLED:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_cfg_wait);
+		break;
+	case IOCFC_E_IOC_FAILED:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_failed);
+
+		if (iocfc->bfa->iocfc.cb_reqd == BFA_FALSE)
+			break;
+
+		iocfc->bfa->iocfc.op_status = BFA_STATUS_FAILED;
+		bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.en_hcb_qe,
+			     bfa_iocfc_enable_cb, iocfc->bfa);
+		iocfc->bfa->iocfc.cb_reqd = BFA_FALSE;
+		break;
+	default:
+		bfa_sm_fault(iocfc->bfa, event);
+		break;
+	}
+}
+
+static void
+bfa_iocfc_sm_cfg_wait_entry(struct bfa_iocfc_s *iocfc)
+{
+	bfa_iocfc_send_cfg(iocfc->bfa);
+}
+
+static void
+bfa_iocfc_sm_cfg_wait(struct bfa_iocfc_s *iocfc, enum iocfc_event event)
+{
+	bfa_trc(iocfc->bfa, event);
+
+	switch (event) {
+	case IOCFC_E_CFG_DONE:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_operational);
+		if (iocfc->bfa->iocfc.cb_reqd == BFA_FALSE)
+			break;
+
+		iocfc->bfa->iocfc.op_status = BFA_STATUS_OK;
+		bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.en_hcb_qe,
+			     bfa_iocfc_enable_cb, iocfc->bfa);
+		iocfc->bfa->iocfc.cb_reqd = BFA_FALSE;
+		break;
+	case IOCFC_E_IOC_FAILED:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_failed);
+		if (iocfc->bfa->iocfc.cb_reqd == BFA_FALSE)
+			break;
+
+		iocfc->bfa->iocfc.op_status = BFA_STATUS_FAILED;
+		bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.en_hcb_qe,
+			     bfa_iocfc_enable_cb, iocfc->bfa);
+		iocfc->bfa->iocfc.cb_reqd = BFA_FALSE;
+		break;
+	default:
+		bfa_sm_fault(iocfc->bfa, event);
+		break;
+	}
+}
+
+static void
+bfa_iocfc_sm_disabling_entry(struct bfa_iocfc_s *iocfc)
+{
+	bfa_ioc_disable(&iocfc->bfa->ioc);
+}
+
+static void
+bfa_iocfc_sm_disabling(struct bfa_iocfc_s *iocfc, enum iocfc_event event)
+{
+	bfa_trc(iocfc->bfa, event);
+
+	switch (event) {
+	case IOCFC_E_IOC_DISABLED:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_disabled);
+		break;
+	default:
+		bfa_sm_fault(iocfc->bfa, event);
+		break;
+	}
+}
+
+static void
+bfa_iocfc_sm_disabled_entry(struct bfa_iocfc_s *iocfc)
+{
+	bfa_isr_disable(iocfc->bfa);
+	bfa_iocfc_disable_submod(iocfc->bfa);
+	iocfc->bfa->iocfc.op_status = BFA_STATUS_OK;
+	bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.dis_hcb_qe,
+		     bfa_iocfc_disable_cb, iocfc->bfa);
+}
+
+static void
+bfa_iocfc_sm_disabled(struct bfa_iocfc_s *iocfc, enum iocfc_event event)
+{
+	bfa_trc(iocfc->bfa, event);
+
+	switch (event) {
+	case IOCFC_E_STOP:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_dconf_write);
+		break;
+	case IOCFC_E_ENABLE:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_enabling);
+		break;
+	default:
+		bfa_sm_fault(iocfc->bfa, event);
+		break;
+	}
+}
+
+static void
+bfa_iocfc_sm_failed_entry(struct bfa_iocfc_s *iocfc)
+{
+	bfa_isr_disable(iocfc->bfa);
+	bfa_iocfc_disable_submod(iocfc->bfa);
+}
+
+static void
+bfa_iocfc_sm_failed(struct bfa_iocfc_s *iocfc, enum iocfc_event event)
+{
+	bfa_trc(iocfc->bfa, event);
+
+	switch (event) {
+	case IOCFC_E_STOP:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_dconf_write);
+		break;
+	case IOCFC_E_DISABLE:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_disabling);
+		break;
+	case IOCFC_E_IOC_ENABLED:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_cfg_wait);
+		break;
+	case IOCFC_E_IOC_FAILED:
+		break;
+	default:
+		bfa_sm_fault(iocfc->bfa, event);
+		break;
+	}
+}
+
+static void
+bfa_iocfc_sm_init_failed_entry(struct bfa_iocfc_s *iocfc)
+{
+	bfa_isr_disable(iocfc->bfa);
+	iocfc->bfa->iocfc.op_status = BFA_STATUS_FAILED;
+	bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.init_hcb_qe,
+		     bfa_iocfc_init_cb, iocfc->bfa);
+}
+
+static void
+bfa_iocfc_sm_init_failed(struct bfa_iocfc_s *iocfc, enum iocfc_event event)
+{
+	bfa_trc(iocfc->bfa, event);
+
+	switch (event) {
+	case IOCFC_E_STOP:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_stopping);
+		break;
+	case IOCFC_E_DISABLE:
+		bfa_ioc_disable(&iocfc->bfa->ioc);
+		break;
+	case IOCFC_E_IOC_ENABLED:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_dconf_read);
+		break;
+	case IOCFC_E_IOC_DISABLED:
+		bfa_fsm_set_state(iocfc, bfa_iocfc_sm_stopped);
+		iocfc->bfa->iocfc.op_status = BFA_STATUS_OK;
+		bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.dis_hcb_qe,
+			     bfa_iocfc_disable_cb, iocfc->bfa);
+		break;
+	case IOCFC_E_IOC_FAILED:
+		break;
+	default:
+		bfa_sm_fault(iocfc->bfa, event);
+		break;
+	}
+}
 
 /*
  * BFA Interrupt handling functions
@@ -231,16 +649,19 @@
 	}
 }
 
-static inline void
+bfa_boolean_t
 bfa_isr_rspq(struct bfa_s *bfa, int qid)
 {
 	struct bfi_msg_s *m;
 	u32	pi, ci;
 	struct list_head *waitq;
+	bfa_boolean_t ret;
 
 	ci = bfa_rspq_ci(bfa, qid);
 	pi = bfa_rspq_pi(bfa, qid);
 
+	ret = (ci != pi);
+
 	while (ci != pi) {
 		m = bfa_rspq_elem(bfa, qid, ci);
 		WARN_ON(m->mhdr.msg_class >= BFI_MC_MAX);
@@ -260,6 +681,8 @@
 	waitq = bfa_reqq(bfa, qid);
 	if (!list_empty(waitq))
 		bfa_reqq_resume(bfa, qid);
+
+	return ret;
 }
 
 static inline void
@@ -320,6 +743,7 @@
 {
 	u32 intr, qintr;
 	int queue;
+	bfa_boolean_t rspq_comp = BFA_FALSE;
 
 	intr = readl(bfa->iocfc.bfa_regs.intr_status);
 
@@ -332,11 +756,12 @@
 	 */
 	if (bfa->queue_process) {
 		for (queue = 0; queue < BFI_IOC_MAX_CQS; queue++)
-			bfa_isr_rspq(bfa, queue);
+			if (bfa_isr_rspq(bfa, queue))
+				rspq_comp = BFA_TRUE;
 	}
 
 	if (!intr)
-		return BFA_TRUE;
+		return (qintr | rspq_comp) ? BFA_TRUE : BFA_FALSE;
 
 	/*
 	 * CPE completion queue interrupt
@@ -525,11 +950,9 @@
 	 * Enable interrupt coalescing if it is driver init path
 	 * and not ioc disable/enable path.
 	 */
-	if (!iocfc->cfgdone)
+	if (bfa_fsm_cmp_state(iocfc, bfa_iocfc_sm_init_cfg_wait))
 		cfg_info->intr_attr.coalesce = BFA_TRUE;
 
-	iocfc->cfgdone = BFA_FALSE;
-
 	/*
 	 * dma map IOC configuration itself
 	 */
@@ -549,8 +972,6 @@
 
 	bfa->bfad = bfad;
 	iocfc->bfa = bfa;
-	iocfc->action = BFA_IOCFC_ACT_NONE;
-
 	iocfc->cfg = *cfg;
 
 	/*
@@ -683,6 +1104,8 @@
 
 	for (i = 0; hal_mods[i]; i++)
 		hal_mods[i]->start(bfa);
+
+	bfa->iocfc.submod_enabled = BFA_TRUE;
 }
 
 /*
@@ -693,8 +1116,13 @@
 {
 	int		i;
 
+	if (bfa->iocfc.submod_enabled == BFA_FALSE)
+		return;
+
 	for (i = 0; hal_mods[i]; i++)
 		hal_mods[i]->iocdisable(bfa);
+
+	bfa->iocfc.submod_enabled = BFA_FALSE;
 }
 
 static void
@@ -702,15 +1130,8 @@
 {
 	struct bfa_s	*bfa = bfa_arg;
 
-	if (complete) {
-		if (bfa->iocfc.cfgdone && BFA_DCONF_MOD(bfa)->flashdone)
-			bfa_cb_init(bfa->bfad, BFA_STATUS_OK);
-		else
-			bfa_cb_init(bfa->bfad, BFA_STATUS_FAILED);
-	} else {
-		if (bfa->iocfc.cfgdone)
-			bfa->iocfc.action = BFA_IOCFC_ACT_NONE;
-	}
+	if (complete)
+		bfa_cb_init(bfa->bfad, bfa->iocfc.op_status);
 }
 
 static void
@@ -721,8 +1142,6 @@
 
 	if (compl)
 		complete(&bfad->comp);
-	else
-		bfa->iocfc.action = BFA_IOCFC_ACT_NONE;
 }
 
 static void
@@ -794,8 +1213,6 @@
 	fwcfg->num_uf_bufs    = be16_to_cpu(fwcfg->num_uf_bufs);
 	fwcfg->num_rports     = be16_to_cpu(fwcfg->num_rports);
 
-	iocfc->cfgdone = BFA_TRUE;
-
 	/*
 	 * configure queue register offsets as learnt from firmware
 	 */
@@ -811,22 +1228,13 @@
 	 */
 	bfa_msix_queue_install(bfa);
 
-	/*
-	 * Configuration is complete - initialize/start submodules
-	 */
-	bfa_fcport_init(bfa);
-
-	if (iocfc->action == BFA_IOCFC_ACT_INIT) {
-		if (BFA_DCONF_MOD(bfa)->flashdone == BFA_TRUE)
-			bfa_cb_queue(bfa, &iocfc->init_hcb_qe,
-				bfa_iocfc_init_cb, bfa);
-	} else {
-		if (bfa->iocfc.action == BFA_IOCFC_ACT_ENABLE)
-			bfa_cb_queue(bfa, &bfa->iocfc.en_hcb_qe,
-					bfa_iocfc_enable_cb, bfa);
-		bfa_iocfc_start_submod(bfa);
+	if (bfa->iocfc.cfgrsp->pbc_cfg.pbc_pwwn != 0) {
+		bfa->ioc.attr->pwwn = bfa->iocfc.cfgrsp->pbc_cfg.pbc_pwwn;
+		bfa->ioc.attr->nwwn = bfa->iocfc.cfgrsp->pbc_cfg.pbc_nwwn;
+		bfa_fsm_send_event(iocfc, IOCFC_E_CFG_DONE);
 	}
 }
+
 void
 bfa_iocfc_reset_queues(struct bfa_s *bfa)
 {
@@ -840,6 +1248,23 @@
 	}
 }
 
+/*
+ *	Process FAA pwwn msg from fw.
+ */
+static void
+bfa_iocfc_process_faa_addr(struct bfa_s *bfa, struct bfi_faa_addr_msg_s *msg)
+{
+	struct bfa_iocfc_s		*iocfc   = &bfa->iocfc;
+	struct bfi_iocfc_cfgrsp_s	*cfgrsp  = iocfc->cfgrsp;
+
+	cfgrsp->pbc_cfg.pbc_pwwn = msg->pwwn;
+	cfgrsp->pbc_cfg.pbc_nwwn = msg->nwwn;
+
+	bfa->ioc.attr->pwwn = msg->pwwn;
+	bfa->ioc.attr->nwwn = msg->nwwn;
+	bfa_fsm_send_event(iocfc, IOCFC_E_CFG_DONE);
+}
+
 /* Fabric Assigned Address specific functions */
 
 /*
@@ -855,84 +1280,13 @@
 		if ((ioc_type != BFA_IOC_TYPE_FC) || bfa_mfg_is_mezz(card_type))
 			return BFA_STATUS_FEATURE_NOT_SUPPORTED;
 	} else {
-		if (!bfa_ioc_is_acq_addr(&bfa->ioc))
-			return BFA_STATUS_IOC_NON_OP;
+		return BFA_STATUS_IOC_NON_OP;
 	}
 
 	return BFA_STATUS_OK;
 }
 
 bfa_status_t
-bfa_faa_enable(struct bfa_s *bfa, bfa_cb_iocfc_t cbfn, void *cbarg)
-{
-	struct bfi_faa_en_dis_s faa_enable_req;
-	struct bfa_iocfc_s	*iocfc = &bfa->iocfc;
-	bfa_status_t		status;
-
-	iocfc->faa_args.faa_cb.faa_cbfn = cbfn;
-	iocfc->faa_args.faa_cb.faa_cbarg = cbarg;
-
-	status = bfa_faa_validate_request(bfa);
-	if (status != BFA_STATUS_OK)
-		return status;
-
-	if (iocfc->faa_args.busy == BFA_TRUE)
-		return BFA_STATUS_DEVBUSY;
-
-	if (iocfc->faa_args.faa_state == BFA_FAA_ENABLED)
-		return BFA_STATUS_FAA_ENABLED;
-
-	if (bfa_fcport_is_trunk_enabled(bfa))
-		return BFA_STATUS_ERROR_TRUNK_ENABLED;
-
-	bfa_fcport_cfg_faa(bfa, BFA_FAA_ENABLED);
-	iocfc->faa_args.busy = BFA_TRUE;
-
-	memset(&faa_enable_req, 0, sizeof(struct bfi_faa_en_dis_s));
-	bfi_h2i_set(faa_enable_req.mh, BFI_MC_IOCFC,
-		BFI_IOCFC_H2I_FAA_ENABLE_REQ, bfa_fn_lpu(bfa));
-
-	bfa_ioc_mbox_send(&bfa->ioc, &faa_enable_req,
-			sizeof(struct bfi_faa_en_dis_s));
-
-	return BFA_STATUS_OK;
-}
-
-bfa_status_t
-bfa_faa_disable(struct bfa_s *bfa, bfa_cb_iocfc_t cbfn,
-		void *cbarg)
-{
-	struct bfi_faa_en_dis_s faa_disable_req;
-	struct bfa_iocfc_s	*iocfc = &bfa->iocfc;
-	bfa_status_t		status;
-
-	iocfc->faa_args.faa_cb.faa_cbfn = cbfn;
-	iocfc->faa_args.faa_cb.faa_cbarg = cbarg;
-
-	status = bfa_faa_validate_request(bfa);
-	if (status != BFA_STATUS_OK)
-		return status;
-
-	if (iocfc->faa_args.busy == BFA_TRUE)
-		return BFA_STATUS_DEVBUSY;
-
-	if (iocfc->faa_args.faa_state == BFA_FAA_DISABLED)
-		return BFA_STATUS_FAA_DISABLED;
-
-	bfa_fcport_cfg_faa(bfa, BFA_FAA_DISABLED);
-	iocfc->faa_args.busy = BFA_TRUE;
-
-	memset(&faa_disable_req, 0, sizeof(struct bfi_faa_en_dis_s));
-	bfi_h2i_set(faa_disable_req.mh, BFI_MC_IOCFC,
-		BFI_IOCFC_H2I_FAA_DISABLE_REQ, bfa_fn_lpu(bfa));
-
-	bfa_ioc_mbox_send(&bfa->ioc, &faa_disable_req,
-		sizeof(struct bfi_faa_en_dis_s));
-
-	return BFA_STATUS_OK;
-}
-
-bfa_status_t
 bfa_faa_query(struct bfa_s *bfa, struct bfa_faa_attr_s *attr,
 		bfa_cb_iocfc_t cbfn, void *cbarg)
 {
@@ -963,38 +1317,6 @@
 }
 
 /*
- *	FAA enable response
- */
-static void
-bfa_faa_enable_reply(struct bfa_iocfc_s *iocfc,
-		struct bfi_faa_en_dis_rsp_s *rsp)
-{
-	void	*cbarg = iocfc->faa_args.faa_cb.faa_cbarg;
-	bfa_status_t	status = rsp->status;
-
-	WARN_ON(!iocfc->faa_args.faa_cb.faa_cbfn);
-
-	iocfc->faa_args.faa_cb.faa_cbfn(cbarg, status);
-	iocfc->faa_args.busy = BFA_FALSE;
-}
-
-/*
- *	FAA disable response
- */
-static void
-bfa_faa_disable_reply(struct bfa_iocfc_s *iocfc,
-		struct bfi_faa_en_dis_rsp_s *rsp)
-{
-	void	*cbarg = iocfc->faa_args.faa_cb.faa_cbarg;
-	bfa_status_t	status = rsp->status;
-
-	WARN_ON(!iocfc->faa_args.faa_cb.faa_cbfn);
-
-	iocfc->faa_args.faa_cb.faa_cbfn(cbarg, status);
-	iocfc->faa_args.busy = BFA_FALSE;
-}
-
-/*
  *	FAA query response
  */
 static void
@@ -1023,25 +1345,10 @@
 {
 	struct bfa_s	*bfa = bfa_arg;
 
-	if (status == BFA_STATUS_FAA_ACQ_ADDR) {
-		bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe,
-				bfa_iocfc_init_cb, bfa);
-		return;
-	}
-
-	if (status != BFA_STATUS_OK) {
-		bfa_isr_disable(bfa);
-		if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT)
-			bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe,
-				     bfa_iocfc_init_cb, bfa);
-		else if (bfa->iocfc.action == BFA_IOCFC_ACT_ENABLE)
-			bfa_cb_queue(bfa, &bfa->iocfc.en_hcb_qe,
-					bfa_iocfc_enable_cb, bfa);
-		return;
-	}
-
-	bfa_iocfc_send_cfg(bfa);
-	bfa_dconf_modinit(bfa);
+	if (status == BFA_STATUS_OK)
+		bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_IOC_ENABLED);
+	else
+		bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_IOC_FAILED);
 }
 
 /*
@@ -1052,17 +1359,7 @@
 {
 	struct bfa_s	*bfa = bfa_arg;
 
-	bfa_isr_disable(bfa);
-	bfa_iocfc_disable_submod(bfa);
-
-	if (bfa->iocfc.action == BFA_IOCFC_ACT_STOP)
-		bfa_cb_queue(bfa, &bfa->iocfc.stop_hcb_qe, bfa_iocfc_stop_cb,
-			     bfa);
-	else {
-		WARN_ON(bfa->iocfc.action != BFA_IOCFC_ACT_DISABLE);
-		bfa_cb_queue(bfa, &bfa->iocfc.dis_hcb_qe, bfa_iocfc_disable_cb,
-			     bfa);
-	}
+	bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_IOC_DISABLED);
 }
 
 /*
@@ -1074,13 +1371,7 @@
 	struct bfa_s	*bfa = bfa_arg;
 
 	bfa->queue_process = BFA_FALSE;
-
-	bfa_isr_disable(bfa);
-	bfa_iocfc_disable_submod(bfa);
-
-	if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT)
-		bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, bfa_iocfc_init_cb,
-			     bfa);
+	bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_IOC_FAILED);
 }
 
 /*
@@ -1095,7 +1386,6 @@
 	bfa_isr_enable(bfa);
 }
 
-
 /*
  * Query IOC memory requirement information.
  */
@@ -1171,6 +1461,12 @@
 	INIT_LIST_HEAD(&bfa->comp_q);
 	for (i = 0; i < BFI_IOC_MAX_CQS; i++)
 		INIT_LIST_HEAD(&bfa->reqq_waitq[i]);
+
+	bfa->iocfc.cb_reqd = BFA_FALSE;
+	bfa->iocfc.op_status = BFA_STATUS_OK;
+	bfa->iocfc.submod_enabled = BFA_FALSE;
+
+	bfa_fsm_set_state(&bfa->iocfc, bfa_iocfc_sm_stopped);
 }
 
 /*
@@ -1179,8 +1475,7 @@
 void
 bfa_iocfc_init(struct bfa_s *bfa)
 {
-	bfa->iocfc.action = BFA_IOCFC_ACT_INIT;
-	bfa_ioc_enable(&bfa->ioc);
+	bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_INIT);
 }
 
 /*
@@ -1190,8 +1485,7 @@
 void
 bfa_iocfc_start(struct bfa_s *bfa)
 {
-	if (bfa->iocfc.cfgdone)
-		bfa_iocfc_start_submod(bfa);
+	bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_START);
 }
 
 /*
@@ -1201,12 +1495,8 @@
 void
 bfa_iocfc_stop(struct bfa_s *bfa)
 {
-	bfa->iocfc.action = BFA_IOCFC_ACT_STOP;
-
 	bfa->queue_process = BFA_FALSE;
-	bfa_dconf_modexit(bfa);
-	if (BFA_DCONF_MOD(bfa)->flashdone == BFA_TRUE)
-		bfa_ioc_disable(&bfa->ioc);
+	bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_STOP);
 }
 
 void
@@ -1226,13 +1516,9 @@
 	case BFI_IOCFC_I2H_UPDATEQ_RSP:
 		iocfc->updateq_cbfn(iocfc->updateq_cbarg, BFA_STATUS_OK);
 		break;
-	case BFI_IOCFC_I2H_FAA_ENABLE_RSP:
-		bfa_faa_enable_reply(iocfc,
-			(struct bfi_faa_en_dis_rsp_s *)msg);
-		break;
-	case BFI_IOCFC_I2H_FAA_DISABLE_RSP:
-		bfa_faa_disable_reply(iocfc,
-			(struct bfi_faa_en_dis_rsp_s *)msg);
+	case BFI_IOCFC_I2H_ADDR_MSG:
+		bfa_iocfc_process_faa_addr(bfa,
+				(struct bfi_faa_addr_msg_s *)msg);
 		break;
 	case BFI_IOCFC_I2H_FAA_QUERY_RSP:
 		bfa_faa_query_reply(iocfc, (bfi_faa_query_rsp_t *)msg);
@@ -1306,8 +1592,8 @@
 {
 	bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0,
 		     "IOC Enable");
-	bfa->iocfc.action = BFA_IOCFC_ACT_ENABLE;
-	bfa_ioc_enable(&bfa->ioc);
+	bfa->iocfc.cb_reqd = BFA_TRUE;
+	bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_ENABLE);
 }
 
 void
@@ -1315,17 +1601,16 @@
 {
 	bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0,
 		     "IOC Disable");
-	bfa->iocfc.action = BFA_IOCFC_ACT_DISABLE;
 
 	bfa->queue_process = BFA_FALSE;
-	bfa_ioc_disable(&bfa->ioc);
+	bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_DISABLE);
 }
 
-
 bfa_boolean_t
 bfa_iocfc_is_operational(struct bfa_s *bfa)
 {
-	return bfa_ioc_is_operational(&bfa->ioc) && bfa->iocfc.cfgdone;
+	return bfa_ioc_is_operational(&bfa->ioc) &&
+		bfa_fsm_cmp_state(&bfa->iocfc, bfa_iocfc_sm_operational);
 }
 
 /*
@@ -1567,16 +1852,6 @@
 	}
 }
 
-void
-bfa_iocfc_cb_dconf_modinit(struct bfa_s *bfa, bfa_status_t status)
-{
-	if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT) {
-		if (bfa->iocfc.cfgdone == BFA_TRUE)
-			bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe,
-				bfa_iocfc_init_cb, bfa);
-	}
-}
-
 /*
  * Return the list of PCI vendor/device id lists supported by this
  * BFA instance.
diff --git a/drivers/scsi/bfa/bfa_defs_svc.h b/drivers/scsi/bfa/bfa_defs_svc.h
index cb07c62..36756ce 100644
--- a/drivers/scsi/bfa/bfa_defs_svc.h
+++ b/drivers/scsi/bfa/bfa_defs_svc.h
@@ -52,7 +52,7 @@
 	u16		num_uf_bufs;	/*  unsolicited recv buffers	*/
 	u8		num_cqs;
 	u8		fw_tick_res;	/*  FW clock resolution in ms */
-	u8		rsvd[2];
+	u8		rsvd[6];
 };
 #pragma pack()
 
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
index d4f951f..5d2a130 100644
--- a/drivers/scsi/bfa/bfa_fcs_lport.c
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -5717,6 +5717,8 @@
 
 	if (vport_drv->comp_del)
 		complete(vport_drv->comp_del);
+	else
+		kfree(vport_drv);
 
 	bfa_lps_delete(vport->lps);
 }
diff --git a/drivers/scsi/bfa/bfa_fcs_rport.c b/drivers/scsi/bfa/bfa_fcs_rport.c
index 52628d5..fe0463a 100644
--- a/drivers/scsi/bfa/bfa_fcs_rport.c
+++ b/drivers/scsi/bfa/bfa_fcs_rport.c
@@ -2169,7 +2169,10 @@
 	 * - MAX receive frame size
 	 */
 	rport->cisc = plogi->csp.cisc;
-	rport->maxfrsize = be16_to_cpu(plogi->class3.rxsz);
+	if (be16_to_cpu(plogi->class3.rxsz) < be16_to_cpu(plogi->csp.rxsz))
+		rport->maxfrsize = be16_to_cpu(plogi->class3.rxsz);
+	else
+		rport->maxfrsize = be16_to_cpu(plogi->csp.rxsz);
 
 	bfa_trc(port->fcs, be16_to_cpu(plogi->csp.bbcred));
 	bfa_trc(port->fcs, port->fabric->bb_credit);
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
index eca7ab7..14e6284 100644
--- a/drivers/scsi/bfa/bfa_ioc.c
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -88,7 +88,6 @@
 static void bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc);
 static void bfa_ioc_mbox_flush(struct bfa_ioc_s *ioc);
 static void bfa_ioc_recover(struct bfa_ioc_s *ioc);
-static void bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc);
 static void bfa_ioc_event_notify(struct bfa_ioc_s *ioc ,
 				enum bfa_ioc_event_e event);
 static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc);
@@ -97,7 +96,6 @@
 static void bfa_ioc_fail_notify(struct bfa_ioc_s *ioc);
 static void bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc);
 
-
 /*
  * IOC state machine definitions/declarations
  */
@@ -114,7 +112,6 @@
 	IOC_E_HWERROR		= 10,	/*  hardware error interrupt	*/
 	IOC_E_TIMEOUT		= 11,	/*  timeout			*/
 	IOC_E_HWFAILED		= 12,	/*  PCI mapping failure notice	*/
-	IOC_E_FWRSP_ACQ_ADDR	= 13,	/*  Acquiring address		*/
 };
 
 bfa_fsm_state_decl(bfa_ioc, uninit, struct bfa_ioc_s, enum ioc_event);
@@ -127,7 +124,6 @@
 bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc_s, enum ioc_event);
 bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc_s, enum ioc_event);
 bfa_fsm_state_decl(bfa_ioc, hwfail, struct bfa_ioc_s, enum ioc_event);
-bfa_fsm_state_decl(bfa_ioc, acq_addr, struct bfa_ioc_s, enum ioc_event);
 
 static struct bfa_sm_table_s ioc_sm_table[] = {
 	{BFA_SM(bfa_ioc_sm_uninit), BFA_IOC_UNINIT},
@@ -140,7 +136,6 @@
 	{BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING},
 	{BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},
 	{BFA_SM(bfa_ioc_sm_hwfail), BFA_IOC_HWFAIL},
-	{BFA_SM(bfa_ioc_sm_acq_addr), BFA_IOC_ACQ_ADDR},
 };
 
 /*
@@ -371,17 +366,9 @@
 	switch (event) {
 	case IOC_E_FWRSP_GETATTR:
 		bfa_ioc_timer_stop(ioc);
-		bfa_ioc_check_attr_wwns(ioc);
-		bfa_ioc_hb_monitor(ioc);
 		bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
 		break;
 
-	case IOC_E_FWRSP_ACQ_ADDR:
-		bfa_ioc_timer_stop(ioc);
-		bfa_ioc_hb_monitor(ioc);
-		bfa_fsm_set_state(ioc, bfa_ioc_sm_acq_addr);
-		break;
-
 	case IOC_E_PFFAILED:
 	case IOC_E_HWERROR:
 		bfa_ioc_timer_stop(ioc);
@@ -406,51 +393,6 @@
 	}
 }
 
-/*
- * Acquiring address from fabric (entry function)
- */
-static void
-bfa_ioc_sm_acq_addr_entry(struct bfa_ioc_s *ioc)
-{
-}
-
-/*
- *	Acquiring address from the fabric
- */
-static void
-bfa_ioc_sm_acq_addr(struct bfa_ioc_s *ioc, enum ioc_event event)
-{
-	bfa_trc(ioc, event);
-
-	switch (event) {
-	case IOC_E_FWRSP_GETATTR:
-		bfa_ioc_check_attr_wwns(ioc);
-		bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
-		break;
-
-	case IOC_E_PFFAILED:
-	case IOC_E_HWERROR:
-		bfa_hb_timer_stop(ioc);
-	case IOC_E_HBFAIL:
-		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
-		bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
-		if (event != IOC_E_PFFAILED)
-			bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_GETATTRFAIL);
-		break;
-
-	case IOC_E_DISABLE:
-		bfa_hb_timer_stop(ioc);
-		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
-		break;
-
-	case IOC_E_ENABLE:
-		break;
-
-	default:
-		bfa_sm_fault(ioc, event);
-	}
-}
-
 static void
 bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc)
 {
@@ -458,6 +400,7 @@
 
 	ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
 	bfa_ioc_event_notify(ioc, BFA_IOC_E_ENABLED);
+	bfa_ioc_hb_monitor(ioc);
 	BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC enabled\n");
 	bfa_ioc_aen_post(ioc, BFA_IOC_AEN_ENABLE);
 }
@@ -738,26 +681,60 @@
 bfa_iocpf_sm_fwcheck_entry(struct bfa_iocpf_s *iocpf)
 {
 	struct bfi_ioc_image_hdr_s	fwhdr;
-	u32	fwstate = readl(iocpf->ioc->ioc_regs.ioc_fwstate);
+	u32	r32, fwstate, pgnum, pgoff, loff = 0;
+	int	i;
+
+	/*
+	 * Spin on init semaphore to serialize.
+	 */
+	r32 = readl(iocpf->ioc->ioc_regs.ioc_init_sem_reg);
+	while (r32 & 0x1) {
+		udelay(20);
+		r32 = readl(iocpf->ioc->ioc_regs.ioc_init_sem_reg);
+	}
 
 	/* h/w sem init */
-	if (fwstate == BFI_IOC_UNINIT)
+	fwstate = readl(iocpf->ioc->ioc_regs.ioc_fwstate);
+	if (fwstate == BFI_IOC_UNINIT) {
+		writel(1, iocpf->ioc->ioc_regs.ioc_init_sem_reg);
 		goto sem_get;
+	}
 
 	bfa_ioc_fwver_get(iocpf->ioc, &fwhdr);
 
-	if (swab32(fwhdr.exec) == BFI_FWBOOT_TYPE_NORMAL)
+	if (swab32(fwhdr.exec) == BFI_FWBOOT_TYPE_NORMAL) {
+		writel(1, iocpf->ioc->ioc_regs.ioc_init_sem_reg);
 		goto sem_get;
-
-	bfa_trc(iocpf->ioc, fwstate);
-	bfa_trc(iocpf->ioc, fwhdr.exec);
-	writel(BFI_IOC_UNINIT, iocpf->ioc->ioc_regs.ioc_fwstate);
+	}
 
 	/*
-	 * Try to lock and then unlock the semaphore.
+	 * Clear fwver hdr
+	 */
+	pgnum = PSS_SMEM_PGNUM(iocpf->ioc->ioc_regs.smem_pg0, loff);
+	pgoff = PSS_SMEM_PGOFF(loff);
+	writel(pgnum, iocpf->ioc->ioc_regs.host_page_num_fn);
+
+	for (i = 0; i < sizeof(struct bfi_ioc_image_hdr_s) / sizeof(u32); i++) {
+		bfa_mem_write(iocpf->ioc->ioc_regs.smem_page_start, loff, 0);
+		loff += sizeof(u32);
+	}
+
+	bfa_trc(iocpf->ioc, fwstate);
+	bfa_trc(iocpf->ioc, swab32(fwhdr.exec));
+	writel(BFI_IOC_UNINIT, iocpf->ioc->ioc_regs.ioc_fwstate);
+	writel(BFI_IOC_UNINIT, iocpf->ioc->ioc_regs.alt_ioc_fwstate);
+
+	/*
+	 * Unlock the hw semaphore. Should be here only once per boot.
 	 */
 	readl(iocpf->ioc->ioc_regs.ioc_sem_reg);
 	writel(1, iocpf->ioc->ioc_regs.ioc_sem_reg);
+
+	/*
+	 * unlock init semaphore.
+	 */
+	writel(1, iocpf->ioc->ioc_regs.ioc_init_sem_reg);
+
 sem_get:
 	bfa_ioc_hw_sem_get(iocpf->ioc);
 }
@@ -1707,11 +1684,6 @@
 	u32 i;
 	u32 asicmode;
 
-	/*
-	 * Initialize LMEM first before code download
-	 */
-	bfa_ioc_lmem_init(ioc);
-
 	bfa_trc(ioc, bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)));
 	fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), chunkno);
 
@@ -1999,6 +1971,12 @@
 	bfa_ioc_pll_init_asic(ioc);
 
 	ioc->pllinit = BFA_TRUE;
+
+	/*
+	 * Initialize LMEM
+	 */
+	bfa_ioc_lmem_init(ioc);
+
 	/*
 	 *  release semaphore.
 	 */
@@ -2122,10 +2100,6 @@
 		bfa_ioc_getattr_reply(ioc);
 		break;
 
-	case BFI_IOC_I2H_ACQ_ADDR_REPLY:
-		bfa_fsm_send_event(ioc, IOC_E_FWRSP_ACQ_ADDR);
-		break;
-
 	default:
 		bfa_trc(ioc, msg->mh.msg_id);
 		WARN_ON(1);
@@ -2416,15 +2390,6 @@
 }
 
 /*
- * Return TRUE if IOC is in acquiring address state
- */
-bfa_boolean_t
-bfa_ioc_is_acq_addr(struct bfa_ioc_s *ioc)
-{
-	return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_acq_addr);
-}
-
-/*
  * return true if IOC firmware is different.
  */
 bfa_boolean_t
@@ -2916,17 +2881,6 @@
 	bfa_fsm_send_event(ioc, IOC_E_HBFAIL);
 }
 
-static void
-bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc)
-{
-	if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_LL)
-		return;
-	if (ioc->attr->nwwn == 0)
-		bfa_ioc_aen_post(ioc, BFA_IOC_AEN_INVALID_NWWN);
-	if (ioc->attr->pwwn == 0)
-		bfa_ioc_aen_post(ioc, BFA_IOC_AEN_INVALID_PWWN);
-}
-
 /*
  *  BFA IOC PF private functions
  */
@@ -4495,7 +4449,7 @@
  */
 
 #define BFA_DIAG_MEMTEST_TOV	50000	/* memtest timeout in msec */
-#define BFA_DIAG_FWPING_TOV	1000	/* msec */
+#define CT2_BFA_DIAG_MEMTEST_TOV	(9*30*1000)  /* 4.5 min */
 
 /* IOC event handler */
 static void
@@ -4772,7 +4726,7 @@
 }
 
 static void
-diag_ledtest_comp(struct bfa_diag_s *diag, struct bfi_diag_ledtest_rsp_s * msg)
+diag_ledtest_comp(struct bfa_diag_s *diag, struct bfi_diag_ledtest_rsp_s *msg)
 {
 	bfa_trc(diag, diag->ledtest.lock);
 	diag->ledtest.lock = BFA_FALSE;
@@ -4850,6 +4804,8 @@
 		u32 pattern, struct bfa_diag_memtest_result *result,
 		bfa_cb_diag_t cbfn, void *cbarg)
 {
+	u32	memtest_tov;
+
 	bfa_trc(diag, pattern);
 
 	if (!bfa_ioc_adapter_is_disabled(diag->ioc))
@@ -4869,8 +4825,10 @@
 	/* download memtest code and take LPU0 out of reset */
 	bfa_ioc_boot(diag->ioc, BFI_FWBOOT_TYPE_MEMTEST, BFI_FWBOOT_ENV_OS);
 
+	memtest_tov = (bfa_ioc_asic_gen(diag->ioc) == BFI_ASIC_GEN_CT2) ?
+		       CT2_BFA_DIAG_MEMTEST_TOV : BFA_DIAG_MEMTEST_TOV;
 	bfa_timer_begin(diag->ioc->timer_mod, &diag->timer,
-			bfa_diag_memtest_done, diag, BFA_DIAG_MEMTEST_TOV);
+			bfa_diag_memtest_done, diag, memtest_tov);
 	diag->timer_active = 1;
 	return BFA_STATUS_OK;
 }
@@ -5641,24 +5599,27 @@
 	case BFA_DCONF_SM_INIT:
 		if (dconf->min_cfg) {
 			bfa_trc(dconf->bfa, dconf->min_cfg);
+			bfa_fsm_send_event(&dconf->bfa->iocfc,
+					IOCFC_E_DCONF_DONE);
 			return;
 		}
 		bfa_sm_set_state(dconf, bfa_dconf_sm_flash_read);
-		dconf->flashdone = BFA_FALSE;
-		bfa_trc(dconf->bfa, dconf->flashdone);
+		bfa_timer_start(dconf->bfa, &dconf->timer,
+			bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
 		bfa_status = bfa_flash_read_part(BFA_FLASH(dconf->bfa),
 					BFA_FLASH_PART_DRV, dconf->instance,
 					dconf->dconf,
 					sizeof(struct bfa_dconf_s), 0,
 					bfa_dconf_init_cb, dconf->bfa);
 		if (bfa_status != BFA_STATUS_OK) {
+			bfa_timer_stop(&dconf->timer);
 			bfa_dconf_init_cb(dconf->bfa, BFA_STATUS_FAILED);
 			bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
 			return;
 		}
 		break;
 	case BFA_DCONF_SM_EXIT:
-		dconf->flashdone = BFA_TRUE;
+		bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE);
 	case BFA_DCONF_SM_IOCDISABLE:
 	case BFA_DCONF_SM_WR:
 	case BFA_DCONF_SM_FLASH_COMP:
@@ -5679,15 +5640,20 @@
 
 	switch (event) {
 	case BFA_DCONF_SM_FLASH_COMP:
+		bfa_timer_stop(&dconf->timer);
 		bfa_sm_set_state(dconf, bfa_dconf_sm_ready);
 		break;
 	case BFA_DCONF_SM_TIMEOUT:
 		bfa_sm_set_state(dconf, bfa_dconf_sm_ready);
+		bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_IOC_FAILED);
 		break;
 	case BFA_DCONF_SM_EXIT:
-		dconf->flashdone = BFA_TRUE;
-		bfa_trc(dconf->bfa, dconf->flashdone);
+		bfa_timer_stop(&dconf->timer);
+		bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
+		bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE);
+		break;
 	case BFA_DCONF_SM_IOCDISABLE:
+		bfa_timer_stop(&dconf->timer);
 		bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
 		break;
 	default:
@@ -5710,9 +5676,8 @@
 		bfa_sm_set_state(dconf, bfa_dconf_sm_dirty);
 		break;
 	case BFA_DCONF_SM_EXIT:
-		dconf->flashdone = BFA_TRUE;
-		bfa_trc(dconf->bfa, dconf->flashdone);
 		bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
+		bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE);
 		break;
 	case BFA_DCONF_SM_INIT:
 	case BFA_DCONF_SM_IOCDISABLE:
@@ -5774,9 +5739,7 @@
 		bfa_timer_stop(&dconf->timer);
 	case BFA_DCONF_SM_TIMEOUT:
 		bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
-		dconf->flashdone = BFA_TRUE;
-		bfa_trc(dconf->bfa, dconf->flashdone);
-		bfa_ioc_disable(&dconf->bfa->ioc);
+		bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE);
 		break;
 	default:
 		bfa_sm_fault(dconf->bfa, event);
@@ -5823,8 +5786,8 @@
 		bfa_sm_set_state(dconf, bfa_dconf_sm_dirty);
 		break;
 	case BFA_DCONF_SM_EXIT:
-		dconf->flashdone = BFA_TRUE;
 		bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
+		bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE);
 		break;
 	case BFA_DCONF_SM_IOCDISABLE:
 		break;
@@ -5865,11 +5828,6 @@
 	if (cfg->drvcfg.min_cfg) {
 		bfa_mem_kva_curp(dconf) += sizeof(struct bfa_dconf_hdr_s);
 		dconf->min_cfg = BFA_TRUE;
-		/*
-		 * Set the flashdone flag to TRUE explicitly as no flash
-		 * write will happen in min_cfg mode.
-		 */
-		dconf->flashdone = BFA_TRUE;
 	} else {
 		dconf->min_cfg = BFA_FALSE;
 		bfa_mem_kva_curp(dconf) += sizeof(struct bfa_dconf_s);
@@ -5885,9 +5843,7 @@
 	struct bfa_s *bfa = arg;
 	struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
 
-	dconf->flashdone = BFA_TRUE;
-	bfa_trc(bfa, dconf->flashdone);
-	bfa_iocfc_cb_dconf_modinit(bfa, status);
+	bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP);
 	if (status == BFA_STATUS_OK) {
 		bfa_dconf_read_data_valid(bfa) = BFA_TRUE;
 		if (dconf->dconf->hdr.signature != BFI_DCONF_SIGNATURE)
@@ -5895,7 +5851,7 @@
 		if (dconf->dconf->hdr.version != BFI_DCONF_VERSION)
 			dconf->dconf->hdr.version = BFI_DCONF_VERSION;
 	}
-	bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP);
+	bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_DCONF_DONE);
 }
 
 void
@@ -5977,7 +5933,5 @@
 bfa_dconf_modexit(struct bfa_s *bfa)
 {
 	struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
-	BFA_DCONF_MOD(bfa)->flashdone = BFA_FALSE;
-	bfa_trc(bfa, BFA_DCONF_MOD(bfa)->flashdone);
 	bfa_sm_send_event(dconf, BFA_DCONF_SM_EXIT);
 }
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h
index 546d46b..1a99d4b 100644
--- a/drivers/scsi/bfa/bfa_ioc.h
+++ b/drivers/scsi/bfa/bfa_ioc.h
@@ -373,6 +373,22 @@
 };
 
 /*
+ * IOCFC state machine definitions/declarations
+ */
+enum iocfc_event {
+	IOCFC_E_INIT		= 1,	/* IOCFC init request		*/
+	IOCFC_E_START		= 2,	/* IOCFC mod start request	*/
+	IOCFC_E_STOP		= 3,	/* IOCFC stop request		*/
+	IOCFC_E_ENABLE		= 4,	/* IOCFC enable request		*/
+	IOCFC_E_DISABLE		= 5,	/* IOCFC disable request	*/
+	IOCFC_E_IOC_ENABLED	= 6,	/* IOC enabled message		*/
+	IOCFC_E_IOC_DISABLED	= 7,	/* IOC disabled message		*/
+	IOCFC_E_IOC_FAILED	= 8,	/* failure notice by IOC sm	*/
+	IOCFC_E_DCONF_DONE	= 9,	/* dconf read/write done	*/
+	IOCFC_E_CFG_DONE	= 10,	/* IOCFC config complete	*/
+};
+
+/*
  * ASIC block configurtion related
  */
 
@@ -706,7 +722,6 @@
 struct bfa_dconf_mod_s {
 	bfa_sm_t		sm;
 	u8			instance;
-	bfa_boolean_t		flashdone;
 	bfa_boolean_t		read_data_valid;
 	bfa_boolean_t		min_cfg;
 	struct bfa_timer_s	timer;
diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c
index d1b8f0c..2eb0c6a 100644
--- a/drivers/scsi/bfa/bfa_ioc_ct.c
+++ b/drivers/scsi/bfa/bfa_ioc_ct.c
@@ -786,17 +786,73 @@
 }
 
 #define CT2_NFC_MAX_DELAY	1000
+#define CT2_NFC_VER_VALID	0x143
+#define BFA_IOC_PLL_POLL	1000000
+
+static bfa_boolean_t
+bfa_ioc_ct2_nfc_halted(void __iomem *rb)
+{
+	u32	r32;
+
+	r32 = readl(rb + CT2_NFC_CSR_SET_REG);
+	if (r32 & __NFC_CONTROLLER_HALTED)
+		return BFA_TRUE;
+
+	return BFA_FALSE;
+}
+
+static void
+bfa_ioc_ct2_nfc_resume(void __iomem *rb)
+{
+	u32	r32;
+	int i;
+
+	writel(__HALT_NFC_CONTROLLER, rb + CT2_NFC_CSR_CLR_REG);
+	for (i = 0; i < CT2_NFC_MAX_DELAY; i++) {
+		r32 = readl(rb + CT2_NFC_CSR_SET_REG);
+		if (!(r32 & __NFC_CONTROLLER_HALTED))
+			return;
+		udelay(1000);
+	}
+	WARN_ON(1);
+}
+
 bfa_status_t
 bfa_ioc_ct2_pll_init(void __iomem *rb, enum bfi_asic_mode mode)
 {
-	u32	wgn, r32;
-	int i;
+	u32 wgn, r32, nfc_ver, i;
 
-	/*
-	 * Initialize PLL if not already done by NFC
-	 */
 	wgn = readl(rb + CT2_WGN_STATUS);
-	if (!(wgn & __GLBL_PF_VF_CFG_RDY)) {
+	nfc_ver = readl(rb + CT2_RSC_GPR15_REG);
+
+	if ((wgn == (__A2T_AHB_LOAD | __WGN_READY)) &&
+	    (nfc_ver >= CT2_NFC_VER_VALID)) {
+		if (bfa_ioc_ct2_nfc_halted(rb))
+			bfa_ioc_ct2_nfc_resume(rb);
+
+		writel(__RESET_AND_START_SCLK_LCLK_PLLS,
+		       rb + CT2_CSI_FW_CTL_SET_REG);
+
+		for (i = 0; i < BFA_IOC_PLL_POLL; i++) {
+			r32 = readl(rb + CT2_APP_PLL_LCLK_CTL_REG);
+			if (r32 & __RESET_AND_START_SCLK_LCLK_PLLS)
+				break;
+		}
+
+		WARN_ON(!(r32 & __RESET_AND_START_SCLK_LCLK_PLLS));
+
+		for (i = 0; i < BFA_IOC_PLL_POLL; i++) {
+			r32 = readl(rb + CT2_APP_PLL_LCLK_CTL_REG);
+			if (!(r32 & __RESET_AND_START_SCLK_LCLK_PLLS))
+				break;
+		}
+
+		WARN_ON(r32 & __RESET_AND_START_SCLK_LCLK_PLLS);
+		udelay(1000);
+
+		r32 = readl(rb + CT2_CSI_FW_CTL_REG);
+		WARN_ON(r32 & __RESET_AND_START_SCLK_LCLK_PLLS);
+	} else {
 		writel(__HALT_NFC_CONTROLLER, rb + CT2_NFC_CSR_SET_REG);
 		for (i = 0; i < CT2_NFC_MAX_DELAY; i++) {
 			r32 = readl(rb + CT2_NFC_CSR_SET_REG);
@@ -804,6 +860,34 @@
 				break;
 			udelay(1000);
 		}
+
+		bfa_ioc_ct2_mac_reset(rb);
+		bfa_ioc_ct2_sclk_init(rb);
+		bfa_ioc_ct2_lclk_init(rb);
+
+		/*
+		 * release soft reset on s_clk & l_clk
+		 */
+		r32 = readl(rb + CT2_APP_PLL_SCLK_CTL_REG);
+		writel(r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET,
+		       (rb + CT2_APP_PLL_SCLK_CTL_REG));
+
+		/*
+		 * release soft reset on s_clk & l_clk
+		 */
+		r32 = readl(rb + CT2_APP_PLL_LCLK_CTL_REG);
+		writel(r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET,
+		      (rb + CT2_APP_PLL_LCLK_CTL_REG));
+	}
+
+	/*
+	 * Announce flash device presence, if flash was corrupted.
+	 */
+	if (wgn == (__WGN_READY | __GLBL_PF_VF_CFG_RDY)) {
+		r32 = readl(rb + PSS_GPIO_OUT_REG);
+		writel(r32 & ~1, (rb + PSS_GPIO_OUT_REG));
+		r32 = readl(rb + PSS_GPIO_OE_REG);
+		writel(r32 | 1, (rb + PSS_GPIO_OE_REG));
 	}
 
 	/*
@@ -813,48 +897,25 @@
 	writel(1, (rb + CT2_LPU0_HOSTFN_MBOX0_MSK));
 	writel(1, (rb + CT2_LPU1_HOSTFN_MBOX0_MSK));
 
-	r32 = readl((rb + CT2_LPU0_HOSTFN_CMD_STAT));
-	if (r32 == 1) {
-		writel(1, (rb + CT2_LPU0_HOSTFN_CMD_STAT));
-		readl((rb + CT2_LPU0_HOSTFN_CMD_STAT));
-	}
-	r32 = readl((rb + CT2_LPU1_HOSTFN_CMD_STAT));
-	if (r32 == 1) {
-		writel(1, (rb + CT2_LPU1_HOSTFN_CMD_STAT));
-		readl((rb + CT2_LPU1_HOSTFN_CMD_STAT));
-	}
-
-	bfa_ioc_ct2_mac_reset(rb);
-	bfa_ioc_ct2_sclk_init(rb);
-	bfa_ioc_ct2_lclk_init(rb);
-
-	/*
-	 * release soft reset on s_clk & l_clk
-	 */
-	r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG));
-	writel(r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET,
-		(rb + CT2_APP_PLL_SCLK_CTL_REG));
-
-	/*
-	 * release soft reset on s_clk & l_clk
-	 */
-	r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG));
-	writel(r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET,
-		(rb + CT2_APP_PLL_LCLK_CTL_REG));
-
-	/*
-	 * Announce flash device presence, if flash was corrupted.
-	 */
-	if (wgn == (__WGN_READY | __GLBL_PF_VF_CFG_RDY)) {
-		r32 = readl((rb + PSS_GPIO_OUT_REG));
-		writel(r32 & ~1, (rb + PSS_GPIO_OUT_REG));
-		r32 = readl((rb + PSS_GPIO_OE_REG));
-		writel(r32 | 1, (rb + PSS_GPIO_OE_REG));
+	/* For first time initialization, no need to clear interrupts */
+	r32 = readl(rb + HOST_SEM5_REG);
+	if (r32 & 0x1) {
+		r32 = readl(rb + CT2_LPU0_HOSTFN_CMD_STAT);
+		if (r32 == 1) {
+			writel(1, rb + CT2_LPU0_HOSTFN_CMD_STAT);
+			readl((rb + CT2_LPU0_HOSTFN_CMD_STAT));
+		}
+		r32 = readl(rb + CT2_LPU1_HOSTFN_CMD_STAT);
+		if (r32 == 1) {
+			writel(1, rb + CT2_LPU1_HOSTFN_CMD_STAT);
+			readl(rb + CT2_LPU1_HOSTFN_CMD_STAT);
+		}
 	}
 
 	bfa_ioc_ct2_mem_init(rb);
 
-	writel(BFI_IOC_UNINIT, (rb + CT2_BFA_IOC0_STATE_REG));
-	writel(BFI_IOC_UNINIT, (rb + CT2_BFA_IOC1_STATE_REG));
+	writel(BFI_IOC_UNINIT, rb + CT2_BFA_IOC0_STATE_REG);
+	writel(BFI_IOC_UNINIT, rb + CT2_BFA_IOC1_STATE_REG);
+
 	return BFA_STATUS_OK;
 }
diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c
index aa8a0ea..2e856e6 100644
--- a/drivers/scsi/bfa/bfa_svc.c
+++ b/drivers/scsi/bfa/bfa_svc.c
@@ -1280,6 +1280,7 @@
 	switch (event) {
 	case BFA_LPS_SM_RESUME:
 		bfa_sm_set_state(lps, bfa_lps_sm_login);
+		bfa_lps_send_login(lps);
 		break;
 
 	case BFA_LPS_SM_OFFLINE:
@@ -1578,7 +1579,7 @@
 		break;
 
 	case BFA_STATUS_VPORT_MAX:
-		if (!rsp->ext_status)
+		if (rsp->ext_status)
 			bfa_lps_no_res(lps, rsp->ext_status);
 		break;
 
@@ -3084,33 +3085,6 @@
 }
 
 static void
-bfa_fcport_send_txcredit(void *port_cbarg)
-{
-
-	struct bfa_fcport_s *fcport = port_cbarg;
-	struct bfi_fcport_set_svc_params_req_s *m;
-
-	/*
-	 * check for room in queue to send request now
-	 */
-	m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT);
-	if (!m) {
-		bfa_trc(fcport->bfa, fcport->cfg.tx_bbcredit);
-		return;
-	}
-
-	bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ,
-			bfa_fn_lpu(fcport->bfa));
-	m->tx_bbcredit = cpu_to_be16((u16)fcport->cfg.tx_bbcredit);
-	m->bb_scn = fcport->cfg.bb_scn;
-
-	/*
-	 * queue I/O message to firmware
-	 */
-	bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT, m->mh);
-}
-
-static void
 bfa_fcport_qos_stats_swap(struct bfa_qos_stats_s *d,
 	struct bfa_qos_stats_s *s)
 {
@@ -3602,26 +3576,24 @@
 		return BFA_STATUS_UNSUPP_SPEED;
 	}
 
-	/* For Mezz card, port speed entered needs to be checked */
-	if (bfa_mfg_is_mezz(fcport->bfa->ioc.attr->card_type)) {
-		if (bfa_ioc_get_type(&fcport->bfa->ioc) == BFA_IOC_TYPE_FC) {
-			/* For CT2, 1G is not supported */
-			if ((speed == BFA_PORT_SPEED_1GBPS) &&
-			    (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id)))
-				return BFA_STATUS_UNSUPP_SPEED;
+	/* Port speed entered needs to be checked */
+	if (bfa_ioc_get_type(&fcport->bfa->ioc) == BFA_IOC_TYPE_FC) {
+		/* For CT2, 1G is not supported */
+		if ((speed == BFA_PORT_SPEED_1GBPS) &&
+		    (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id)))
+			return BFA_STATUS_UNSUPP_SPEED;
 
-			/* Already checked for Auto Speed and Max Speed supp */
-			if (!(speed == BFA_PORT_SPEED_1GBPS ||
-			      speed == BFA_PORT_SPEED_2GBPS ||
-			      speed == BFA_PORT_SPEED_4GBPS ||
-			      speed == BFA_PORT_SPEED_8GBPS ||
-			      speed == BFA_PORT_SPEED_16GBPS ||
-			      speed == BFA_PORT_SPEED_AUTO))
-				return BFA_STATUS_UNSUPP_SPEED;
-		} else {
-			if (speed != BFA_PORT_SPEED_10GBPS)
-				return BFA_STATUS_UNSUPP_SPEED;
-		}
+		/* Already checked for Auto Speed and Max Speed supp */
+		if (!(speed == BFA_PORT_SPEED_1GBPS ||
+		      speed == BFA_PORT_SPEED_2GBPS ||
+		      speed == BFA_PORT_SPEED_4GBPS ||
+		      speed == BFA_PORT_SPEED_8GBPS ||
+		      speed == BFA_PORT_SPEED_16GBPS ||
+		      speed == BFA_PORT_SPEED_AUTO))
+			return BFA_STATUS_UNSUPP_SPEED;
+	} else {
+		if (speed != BFA_PORT_SPEED_10GBPS)
+			return BFA_STATUS_UNSUPP_SPEED;
 	}
 
 	fcport->cfg.speed = speed;
@@ -3765,7 +3737,6 @@
 	fcport->cfg.bb_scn = bb_scn;
 	if (bb_scn)
 		fcport->bbsc_op_state = BFA_TRUE;
-	bfa_fcport_send_txcredit(fcport);
 }
 
 /*
@@ -3825,8 +3796,6 @@
 			attr->port_state = BFA_PORT_ST_IOCDIS;
 		else if (bfa_ioc_fw_mismatch(&fcport->bfa->ioc))
 			attr->port_state = BFA_PORT_ST_FWMISMATCH;
-		else if (bfa_ioc_is_acq_addr(&fcport->bfa->ioc))
-			attr->port_state = BFA_PORT_ST_ACQ_ADDR;
 	}
 
 	/* FCoE vlan */
diff --git a/drivers/scsi/bfa/bfa_svc.h b/drivers/scsi/bfa/bfa_svc.h
index b52cbb6..f300675 100644
--- a/drivers/scsi/bfa/bfa_svc.h
+++ b/drivers/scsi/bfa/bfa_svc.h
@@ -663,10 +663,6 @@
 void bfa_cb_lps_cvl_event(void *bfad, void *uarg);
 
 /* FAA specific APIs */
-bfa_status_t bfa_faa_enable(struct bfa_s *bfa,
-			bfa_cb_iocfc_t cbfn, void *cbarg);
-bfa_status_t bfa_faa_disable(struct bfa_s *bfa,
-			bfa_cb_iocfc_t cbfn, void *cbarg);
 bfa_status_t bfa_faa_query(struct bfa_s *bfa, struct bfa_faa_attr_s *attr,
 			bfa_cb_iocfc_t cbfn, void *cbarg);
 
diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c
index 1938fe0..7b1ecd2 100644
--- a/drivers/scsi/bfa/bfad_attr.c
+++ b/drivers/scsi/bfa/bfad_attr.c
@@ -442,6 +442,43 @@
 	return status;
 }
 
+int
+bfad_im_issue_fc_host_lip(struct Scsi_Host *shost)
+{
+	struct bfad_im_port_s *im_port =
+			(struct bfad_im_port_s *) shost->hostdata[0];
+	struct bfad_s *bfad = im_port->bfad;
+	struct bfad_hal_comp fcomp;
+	unsigned long flags;
+	uint32_t status;
+
+	init_completion(&fcomp.comp);
+	spin_lock_irqsave(&bfad->bfad_lock, flags);
+	status = bfa_port_disable(&bfad->bfa.modules.port,
+					bfad_hcb_comp, &fcomp);
+	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+	if (status != BFA_STATUS_OK)
+		return -EIO;
+
+	wait_for_completion(&fcomp.comp);
+	if (fcomp.status != BFA_STATUS_OK)
+		return -EIO;
+
+	spin_lock_irqsave(&bfad->bfad_lock, flags);
+	status = bfa_port_enable(&bfad->bfa.modules.port,
+					bfad_hcb_comp, &fcomp);
+	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+	if (status != BFA_STATUS_OK)
+		return -EIO;
+
+	wait_for_completion(&fcomp.comp);
+	if (fcomp.status != BFA_STATUS_OK)
+		return -EIO;
+
+	return 0;
+}
+
 static int
 bfad_im_vport_delete(struct fc_vport *fc_vport)
 {
@@ -457,8 +494,11 @@
 	unsigned long flags;
 	struct completion fcomp;
 
-	if (im_port->flags & BFAD_PORT_DELETE)
-		goto free_scsi_host;
+	if (im_port->flags & BFAD_PORT_DELETE) {
+		bfad_scsi_host_free(bfad, im_port);
+		list_del(&vport->list_entry);
+		return 0;
+	}
 
 	port = im_port->port;
 
@@ -489,7 +529,6 @@
 
 	wait_for_completion(vport->comp_del);
 
-free_scsi_host:
 	bfad_scsi_host_free(bfad, im_port);
 	list_del(&vport->list_entry);
 	kfree(vport);
@@ -579,7 +618,7 @@
 	.show_rport_dev_loss_tmo = 1,
 	.get_rport_dev_loss_tmo = bfad_im_get_rport_loss_tmo,
 	.set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo,
-
+	.issue_fc_host_lip = bfad_im_issue_fc_host_lip,
 	.vport_create = bfad_im_vport_create,
 	.vport_delete = bfad_im_vport_delete,
 	.vport_disable = bfad_im_vport_disable,
diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c
index 530de2b..e1f4b10 100644
--- a/drivers/scsi/bfa/bfad_bsg.c
+++ b/drivers/scsi/bfa/bfad_bsg.c
@@ -1288,50 +1288,6 @@
 }
 
 int
-bfad_iocmd_faa_enable(struct bfad_s *bfad, void *cmd)
-{
-	struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
-	unsigned long   flags;
-	struct bfad_hal_comp    fcomp;
-
-	init_completion(&fcomp.comp);
-	iocmd->status = BFA_STATUS_OK;
-	spin_lock_irqsave(&bfad->bfad_lock, flags);
-	iocmd->status = bfa_faa_enable(&bfad->bfa, bfad_hcb_comp, &fcomp);
-	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
-
-	if (iocmd->status != BFA_STATUS_OK)
-		goto out;
-
-	wait_for_completion(&fcomp.comp);
-	iocmd->status = fcomp.status;
-out:
-	return 0;
-}
-
-int
-bfad_iocmd_faa_disable(struct bfad_s *bfad, void *cmd)
-{
-	struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
-	unsigned long   flags;
-	struct bfad_hal_comp    fcomp;
-
-	init_completion(&fcomp.comp);
-	iocmd->status = BFA_STATUS_OK;
-	spin_lock_irqsave(&bfad->bfad_lock, flags);
-	iocmd->status = bfa_faa_disable(&bfad->bfa, bfad_hcb_comp, &fcomp);
-	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
-
-	if (iocmd->status != BFA_STATUS_OK)
-		goto out;
-
-	wait_for_completion(&fcomp.comp);
-	iocmd->status = fcomp.status;
-out:
-	return 0;
-}
-
-int
 bfad_iocmd_faa_query(struct bfad_s *bfad, void *cmd)
 {
 	struct bfa_bsg_faa_attr_s *iocmd = (struct bfa_bsg_faa_attr_s *)cmd;
@@ -1918,6 +1874,7 @@
 	struct bfa_bsg_debug_s *iocmd = (struct bfa_bsg_debug_s *)cmd;
 	void	*iocmd_bufptr;
 	unsigned long	flags;
+	u32 offset;
 
 	if (bfad_chk_iocmd_sz(payload_len, sizeof(struct bfa_bsg_debug_s),
 			BFA_DEBUG_FW_CORE_CHUNK_SZ) != BFA_STATUS_OK) {
@@ -1935,8 +1892,10 @@
 
 	iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_debug_s);
 	spin_lock_irqsave(&bfad->bfad_lock, flags);
+	offset = iocmd->offset;
 	iocmd->status = bfa_ioc_debug_fwcore(&bfad->bfa.ioc, iocmd_bufptr,
-				(u32 *)&iocmd->offset, &iocmd->bufsz);
+				&offset, &iocmd->bufsz);
+	iocmd->offset = offset;
 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 out:
 	return 0;
@@ -2633,12 +2592,6 @@
 	case IOCMD_FLASH_DISABLE_OPTROM:
 		rc = bfad_iocmd_ablk_optrom(bfad, cmd, iocmd);
 		break;
-	case IOCMD_FAA_ENABLE:
-		rc = bfad_iocmd_faa_enable(bfad, iocmd);
-		break;
-	case IOCMD_FAA_DISABLE:
-		rc = bfad_iocmd_faa_disable(bfad, iocmd);
-		break;
 	case IOCMD_FAA_QUERY:
 		rc = bfad_iocmd_faa_query(bfad, iocmd);
 		break;
@@ -2809,9 +2762,16 @@
 	struct bfad_im_port_s *im_port =
 			(struct bfad_im_port_s *) job->shost->hostdata[0];
 	struct bfad_s *bfad = im_port->bfad;
+	struct request_queue *request_q = job->req->q;
 	void *payload_kbuf;
 	int rc = -EINVAL;
 
+	/*
+	 * Set the BSG device request_queue size to 256 to support
+	 * payloads larger than 512*1024K bytes.
+	 */
+	blk_queue_max_segments(request_q, 256);
+
 	/* Allocate a temp buffer to hold the passed in user space command */
 	payload_kbuf = kzalloc(job->request_payload.payload_len, GFP_KERNEL);
 	if (!payload_kbuf) {
@@ -3047,8 +3007,7 @@
 	 * Allocate buffer for bsg_fcpt and do a copy_from_user op for payload
 	 * buffer of size bsg_data->payload_len
 	 */
-	bsg_fcpt = (struct bfa_bsg_fcpt_s *)
-		   kzalloc(bsg_data->payload_len, GFP_KERNEL);
+	bsg_fcpt = kzalloc(bsg_data->payload_len, GFP_KERNEL);
 	if (!bsg_fcpt)
 		goto out;
 
@@ -3060,6 +3019,7 @@
 
 	drv_fcxp = kzalloc(sizeof(struct bfad_fcxp), GFP_KERNEL);
 	if (drv_fcxp == NULL) {
+		kfree(bsg_fcpt);
 		rc = -ENOMEM;
 		goto out;
 	}
diff --git a/drivers/scsi/bfa/bfad_bsg.h b/drivers/scsi/bfa/bfad_bsg.h
index e859adb..17ad672 100644
--- a/drivers/scsi/bfa/bfad_bsg.h
+++ b/drivers/scsi/bfa/bfad_bsg.h
@@ -83,8 +83,6 @@
 	IOCMD_PORT_CFG_MODE,
 	IOCMD_FLASH_ENABLE_OPTROM,
 	IOCMD_FLASH_DISABLE_OPTROM,
-	IOCMD_FAA_ENABLE,
-	IOCMD_FAA_DISABLE,
 	IOCMD_FAA_QUERY,
 	IOCMD_CEE_GET_ATTR,
 	IOCMD_CEE_GET_STATS,
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h
index dc5b9d9..7f74f1d 100644
--- a/drivers/scsi/bfa/bfad_drv.h
+++ b/drivers/scsi/bfa/bfad_drv.h
@@ -56,7 +56,7 @@
 #ifdef BFA_DRIVER_VERSION
 #define BFAD_DRIVER_VERSION    BFA_DRIVER_VERSION
 #else
-#define BFAD_DRIVER_VERSION    "3.0.2.2"
+#define BFAD_DRIVER_VERSION    "3.0.23.0"
 #endif
 
 #define BFAD_PROTO_NAME FCPI_NAME
diff --git a/drivers/scsi/bfa/bfi_ms.h b/drivers/scsi/bfa/bfi_ms.h
index 0d9f1fb..d4220e1 100644
--- a/drivers/scsi/bfa/bfi_ms.h
+++ b/drivers/scsi/bfa/bfi_ms.h
@@ -28,17 +28,15 @@
 	BFI_IOCFC_H2I_CFG_REQ		= 1,
 	BFI_IOCFC_H2I_SET_INTR_REQ	= 2,
 	BFI_IOCFC_H2I_UPDATEQ_REQ	= 3,
-	BFI_IOCFC_H2I_FAA_ENABLE_REQ	= 4,
-	BFI_IOCFC_H2I_FAA_DISABLE_REQ	= 5,
-	BFI_IOCFC_H2I_FAA_QUERY_REQ	= 6,
+	BFI_IOCFC_H2I_FAA_QUERY_REQ	= 4,
+	BFI_IOCFC_H2I_ADDR_REQ		= 5,
 };
 
 enum bfi_iocfc_i2h_msgs {
 	BFI_IOCFC_I2H_CFG_REPLY		= BFA_I2HM(1),
 	BFI_IOCFC_I2H_UPDATEQ_RSP	= BFA_I2HM(3),
-	BFI_IOCFC_I2H_FAA_ENABLE_RSP	= BFA_I2HM(4),
-	BFI_IOCFC_I2H_FAA_DISABLE_RSP	= BFA_I2HM(5),
-	BFI_IOCFC_I2H_FAA_QUERY_RSP	= BFA_I2HM(6),
+	BFI_IOCFC_I2H_FAA_QUERY_RSP	= BFA_I2HM(4),
+	BFI_IOCFC_I2H_ADDR_MSG		= BFA_I2HM(5),
 };
 
 struct bfi_iocfc_cfg_s {
@@ -184,6 +182,13 @@
 	struct bfi_mhdr_s mh;	/* common msg header    */
 };
 
+struct bfi_faa_addr_msg_s {
+	struct  bfi_mhdr_s mh;	/* common msg header	*/
+	u8	rsvd[4];
+	wwn_t	pwwn;		/* Fabric acquired PWWN	*/
+	wwn_t	nwwn;		/* Fabric acquired PWWN	*/
+};
+
 /*
  * BFI_IOCFC_H2I_FAA_QUERY_REQ message
  */
diff --git a/drivers/scsi/bfa/bfi_reg.h b/drivers/scsi/bfa/bfi_reg.h
index d892064..ed5f159 100644
--- a/drivers/scsi/bfa/bfi_reg.h
+++ b/drivers/scsi/bfa/bfi_reg.h
@@ -335,11 +335,17 @@
 #define __PMM_1T_PNDB_P			0x00000002
 #define CT2_PMM_1T_CONTROL_REG_P1	0x00023c1c
 #define CT2_WGN_STATUS			0x00014990
+#define __A2T_AHB_LOAD			0x00000800
 #define __WGN_READY			0x00000400
 #define __GLBL_PF_VF_CFG_RDY		0x00000200
+#define CT2_NFC_CSR_CLR_REG		0x00027420
 #define CT2_NFC_CSR_SET_REG		0x00027424
 #define __HALT_NFC_CONTROLLER		0x00000002
 #define __NFC_CONTROLLER_HALTED		0x00001000
+#define CT2_RSC_GPR15_REG		0x0002765c
+#define CT2_CSI_FW_CTL_REG		0x00027080
+#define CT2_CSI_FW_CTL_SET_REG		0x00027088
+#define __RESET_AND_START_SCLK_LCLK_PLLS 0x00010000
 
 #define CT2_CSI_MAC0_CONTROL_REG	0x000270d0
 #define __CSI_MAC_RESET			0x00000010
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index 049ea90..a4953ef 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -62,7 +62,7 @@
 #include "bnx2fc_constants.h"
 
 #define BNX2FC_NAME		"bnx2fc"
-#define BNX2FC_VERSION		"1.0.9"
+#define BNX2FC_VERSION		"1.0.10"
 
 #define PFX			"bnx2fc: "
 
@@ -114,6 +114,8 @@
 #define BNX2FC_HASH_TBL_CHUNK_SIZE	(16 * 1024)
 
 #define BNX2FC_MAX_SEQS			255
+#define BNX2FC_MAX_RETRY_CNT		3
+#define BNX2FC_MAX_RPORT_RETRY_CNT	255
 
 #define BNX2FC_READ			(1 << 1)
 #define BNX2FC_WRITE			(1 << 0)
@@ -121,8 +123,10 @@
 #define BNX2FC_MIN_XID			0
 #define BNX2FC_MAX_XID			\
 			(BNX2FC_MAX_OUTSTANDING_CMNDS + BNX2FC_ELSTM_XIDS - 1)
+#define FCOE_MAX_NUM_XIDS		0x2000
 #define FCOE_MIN_XID			(BNX2FC_MAX_XID + 1)
-#define FCOE_MAX_XID			(FCOE_MIN_XID + 4095)
+#define FCOE_MAX_XID			(FCOE_MIN_XID + FCOE_MAX_NUM_XIDS - 1)
+#define FCOE_XIDS_PER_CPU		(FCOE_MIN_XID + (512 * nr_cpu_ids) - 1)
 #define BNX2FC_MAX_LUN			0xFFFF
 #define BNX2FC_MAX_FCP_TGT		256
 #define BNX2FC_MAX_CMD_LEN		16
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index a9af42e..c1c6a92 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -22,7 +22,7 @@
 
 #define DRV_MODULE_NAME		"bnx2fc"
 #define DRV_MODULE_VERSION	BNX2FC_VERSION
-#define DRV_MODULE_RELDATE	"Oct 21, 2011"
+#define DRV_MODULE_RELDATE	"Jan 22, 2011"
 
 
 static char version[] __devinitdata =
@@ -439,13 +439,13 @@
 	fr->fr_dev = lport;
 
 	bg = &bnx2fc_global;
-	spin_lock_bh(&bg->fcoe_rx_list.lock);
+	spin_lock(&bg->fcoe_rx_list.lock);
 
 	__skb_queue_tail(&bg->fcoe_rx_list, skb);
 	if (bg->fcoe_rx_list.qlen == 1)
 		wake_up_process(bg->thread);
 
-	spin_unlock_bh(&bg->fcoe_rx_list.lock);
+	spin_unlock(&bg->fcoe_rx_list.lock);
 
 	return 0;
 err:
@@ -939,8 +939,14 @@
 
 static int bnx2fc_em_config(struct fc_lport *lport)
 {
+	int max_xid;
+
+	if (nr_cpu_ids <= 2)
+		max_xid = FCOE_XIDS_PER_CPU;
+	else
+		max_xid = FCOE_MAX_XID;
 	if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, FCOE_MIN_XID,
-				FCOE_MAX_XID, NULL)) {
+				max_xid, NULL)) {
 		printk(KERN_ERR PFX "em_config:fc_exch_mgr_alloc failed\n");
 		return -ENOMEM;
 	}
@@ -952,8 +958,8 @@
 {
 	lport->link_up = 0;
 	lport->qfull = 0;
-	lport->max_retry_count = 3;
-	lport->max_rport_retry_count = 3;
+	lport->max_retry_count = BNX2FC_MAX_RETRY_CNT;
+	lport->max_rport_retry_count = BNX2FC_MAX_RPORT_RETRY_CNT;
 	lport->e_d_tov = 2 * 1000;
 	lport->r_a_tov = 10 * 1000;
 
@@ -1536,6 +1542,7 @@
 static int bnx2fc_destroy(struct net_device *netdev)
 {
 	struct bnx2fc_interface *interface = NULL;
+	struct workqueue_struct *timer_work_queue;
 	int rc = 0;
 
 	rtnl_lock();
@@ -1548,9 +1555,9 @@
 		goto netdev_err;
 	}
 
-
-	destroy_workqueue(interface->timer_work_queue);
+	timer_work_queue = interface->timer_work_queue;
 	__bnx2fc_destroy(interface);
+	destroy_workqueue(timer_work_queue);
 
 netdev_err:
 	mutex_unlock(&bnx2fc_dev_lock);
@@ -2054,6 +2061,7 @@
 ifput_err:
 	bnx2fc_net_cleanup(interface);
 	bnx2fc_interface_put(interface);
+	goto mod_err;
 netdev_err:
 	module_put(THIS_MODULE);
 mod_err:
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index 84a78af..e897ce9 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -1682,9 +1682,7 @@
 
 	memset(fcp_cmnd, 0, sizeof(struct fcp_cmnd));
 
-	int_to_scsilun(sc_cmd->device->lun,
-			(struct scsi_lun *) fcp_cmnd->fc_lun);
-
+	int_to_scsilun(sc_cmd->device->lun, &fcp_cmnd->fc_lun);
 
 	fcp_cmnd->fc_dl = htonl(io_req->data_xfer_len);
 	memcpy(fcp_cmnd->fc_cdb, sc_cmd->cmnd, sc_cmd->cmd_len);
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index 1ad0b82..f9d6f41 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -1312,14 +1312,18 @@
 		  ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN) |
 		/* EMC */
 		(1ULL << ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN));
-	if (error_mask1)
+	if (error_mask1) {
 		iscsi_init2.error_bit_map[0] = error_mask1;
-	else
+		mask64 &= (u32)(~mask64);
+		mask64 |= error_mask1;
+	} else
 		iscsi_init2.error_bit_map[0] = (u32) mask64;
 
-	if (error_mask2)
+	if (error_mask2) {
 		iscsi_init2.error_bit_map[1] = error_mask2;
-	else
+		mask64 &= 0xffffffff;
+		mask64 |= ((u64)error_mask2 << 32);
+	} else
 		iscsi_init2.error_bit_map[1] = (u32) (mask64 >> 32);
 
 	iscsi_error_mask = mask64;
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
index 1a947f1..4927cca 100644
--- a/drivers/scsi/bnx2i/bnx2i_init.c
+++ b/drivers/scsi/bnx2i/bnx2i_init.c
@@ -49,11 +49,11 @@
 MODULE_PARM_DESC(en_tcp_dack, "Enable TCP Delayed ACK");
 
 unsigned int error_mask1 = 0x00;
-module_param(error_mask1, int, 0664);
+module_param(error_mask1, uint, 0664);
 MODULE_PARM_DESC(error_mask1, "Config FW iSCSI Error Mask #1");
 
 unsigned int error_mask2 = 0x00;
-module_param(error_mask2, int, 0664);
+module_param(error_mask2, uint, 0664);
 MODULE_PARM_DESC(error_mask2, "Config FW iSCSI Error Mask #2");
 
 unsigned int sq_size;
@@ -393,8 +393,9 @@
 
 	p = &per_cpu(bnx2i_percpu, cpu);
 
-	thread = kthread_create(bnx2i_percpu_io_thread, (void *)p,
-				"bnx2i_thread/%d", cpu);
+	thread = kthread_create_on_node(bnx2i_percpu_io_thread, (void *)p,
+					cpu_to_node(cpu),
+					"bnx2i_thread/%d", cpu);
 	/* bind thread to the cpu */
 	if (likely(!IS_ERR(thread))) {
 		kthread_bind(thread, cpu);
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index 89afd6d..d9253db 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -2147,11 +2147,10 @@
 			enum iscsi_param param, char *buf, int buflen)
 {
 	struct iscsi_conn *conn = cls_conn->dd_data;
-	struct iscsi_session *session = conn->session;
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
 	struct cxgbi_conn *cconn = tcp_conn->dd_data;
 	struct cxgbi_sock *csk = cconn->cep->csk;
-	int value, err = 0;
+	int err;
 
 	log_debug(1 << CXGBI_DBG_ISCSI,
 		"cls_conn 0x%p, param %d, buf(%d) %s.\n",
@@ -2173,15 +2172,7 @@
 							conn->datadgst_en, 0);
 		break;
 	case ISCSI_PARAM_MAX_R2T:
-		sscanf(buf, "%d", &value);
-		if (value <= 0 || !is_power_of_2(value))
-			return -EINVAL;
-		if (session->max_r2t == value)
-			break;
-		iscsi_tcp_r2tpool_free(session);
-		err = iscsi_set_param(cls_conn, param, buf, buflen);
-		if (!err && iscsi_tcp_r2tpool_alloc(session))
-			return -ENOMEM;
+		return iscsi_tcp_set_max_r2t(conn, buf);
 	case ISCSI_PARAM_MAX_RECV_DLENGTH:
 		err = iscsi_set_param(cls_conn, param, buf, buflen);
 		if (!err)
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index c2677ba..4b11bb0 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -72,7 +72,6 @@
 #endif
 
 
-#include <asm/system.h>
 #include <linux/module.h>
 #include <linux/signal.h>
 #include <linux/blkdev.h>
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index cc75cbe..335e851 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -168,6 +168,14 @@
 	.show_host_supported_fc4s = 1,
 	.show_host_active_fc4s = 1,
 	.show_host_maxframe_size = 1,
+	.show_host_serial_number = 1,
+	.show_host_manufacturer = 1,
+	.show_host_model = 1,
+	.show_host_model_description = 1,
+	.show_host_hardware_version = 1,
+	.show_host_driver_version = 1,
+	.show_host_firmware_version = 1,
+	.show_host_optionrom_version = 1,
 
 	.show_host_port_id = 1,
 	.show_host_supported_speeds = 1,
@@ -208,6 +216,14 @@
 	.show_host_supported_fc4s = 1,
 	.show_host_active_fc4s = 1,
 	.show_host_maxframe_size = 1,
+	.show_host_serial_number = 1,
+	.show_host_manufacturer = 1,
+	.show_host_model = 1,
+	.show_host_model_description = 1,
+	.show_host_hardware_version = 1,
+	.show_host_driver_version = 1,
+	.show_host_firmware_version = 1,
+	.show_host_optionrom_version = 1,
 
 	.show_host_port_id = 1,
 	.show_host_supported_speeds = 1,
@@ -364,11 +380,10 @@
 	if (!fcoe) {
 		FCOE_NETDEV_DBG(netdev, "Could not allocate fcoe structure\n");
 		fcoe = ERR_PTR(-ENOMEM);
-		goto out_nomod;
+		goto out_putmod;
 	}
 
 	dev_hold(netdev);
-	kref_init(&fcoe->kref);
 
 	/*
 	 * Initialize FIP.
@@ -384,54 +399,18 @@
 		kfree(fcoe);
 		dev_put(netdev);
 		fcoe = ERR_PTR(err);
-		goto out_nomod;
+		goto out_putmod;
 	}
 
 	goto out;
 
-out_nomod:
+out_putmod:
 	module_put(THIS_MODULE);
 out:
 	return fcoe;
 }
 
 /**
- * fcoe_interface_release() - fcoe_port kref release function
- * @kref: Embedded reference count in an fcoe_interface struct
- */
-static void fcoe_interface_release(struct kref *kref)
-{
-	struct fcoe_interface *fcoe;
-	struct net_device *netdev;
-
-	fcoe = container_of(kref, struct fcoe_interface, kref);
-	netdev = fcoe->netdev;
-	/* tear-down the FCoE controller */
-	fcoe_ctlr_destroy(&fcoe->ctlr);
-	kfree(fcoe);
-	dev_put(netdev);
-	module_put(THIS_MODULE);
-}
-
-/**
- * fcoe_interface_get() - Get a reference to a FCoE interface
- * @fcoe: The FCoE interface to be held
- */
-static inline void fcoe_interface_get(struct fcoe_interface *fcoe)
-{
-	kref_get(&fcoe->kref);
-}
-
-/**
- * fcoe_interface_put() - Put a reference to a FCoE interface
- * @fcoe: The FCoE interface to be released
- */
-static inline void fcoe_interface_put(struct fcoe_interface *fcoe)
-{
-	kref_put(&fcoe->kref, fcoe_interface_release);
-}
-
-/**
  * fcoe_interface_cleanup() - Clean up a FCoE interface
  * @fcoe: The FCoE interface to be cleaned up
  *
@@ -478,7 +457,11 @@
 	rtnl_unlock();
 
 	/* Release the self-reference taken during fcoe_interface_create() */
-	fcoe_interface_put(fcoe);
+	/* tear-down the FCoE controller */
+	fcoe_ctlr_destroy(fip);
+	kfree(fcoe);
+	dev_put(netdev);
+	module_put(THIS_MODULE);
 }
 
 /**
@@ -734,6 +717,85 @@
 	return 0;
 }
 
+
+/**
+ * fcoe_fdmi_info() - Get FDMI related info from net devive for SW FCoE
+ * @lport:  The local port that is associated with the net device
+ * @netdev: The associated net device
+ *
+ * Must be called after fcoe_shost_config() as it will use local port mutex
+ *
+ */
+static void fcoe_fdmi_info(struct fc_lport *lport, struct net_device *netdev)
+{
+	struct fcoe_interface *fcoe;
+	struct fcoe_port *port;
+	struct net_device *realdev;
+	int rc;
+	struct netdev_fcoe_hbainfo fdmi;
+
+	port = lport_priv(lport);
+	fcoe = port->priv;
+	realdev = fcoe->realdev;
+
+	if (!realdev)
+		return;
+
+	/* No FDMI state m/c for NPIV ports */
+	if (lport->vport)
+		return;
+
+	if (realdev->netdev_ops->ndo_fcoe_get_hbainfo) {
+		memset(&fdmi, 0, sizeof(fdmi));
+		rc = realdev->netdev_ops->ndo_fcoe_get_hbainfo(realdev,
+							       &fdmi);
+		if (rc) {
+			printk(KERN_INFO "fcoe: Failed to retrieve FDMI "
+					"information from netdev.\n");
+			return;
+		}
+
+		snprintf(fc_host_serial_number(lport->host),
+			 FC_SERIAL_NUMBER_SIZE,
+			 "%s",
+			 fdmi.serial_number);
+		snprintf(fc_host_manufacturer(lport->host),
+			 FC_SERIAL_NUMBER_SIZE,
+			 "%s",
+			 fdmi.manufacturer);
+		snprintf(fc_host_model(lport->host),
+			 FC_SYMBOLIC_NAME_SIZE,
+			 "%s",
+			 fdmi.model);
+		snprintf(fc_host_model_description(lport->host),
+			 FC_SYMBOLIC_NAME_SIZE,
+			 "%s",
+			 fdmi.model_description);
+		snprintf(fc_host_hardware_version(lport->host),
+			 FC_VERSION_STRING_SIZE,
+			 "%s",
+			 fdmi.hardware_version);
+		snprintf(fc_host_driver_version(lport->host),
+			 FC_VERSION_STRING_SIZE,
+			 "%s",
+			 fdmi.driver_version);
+		snprintf(fc_host_optionrom_version(lport->host),
+			 FC_VERSION_STRING_SIZE,
+			 "%s",
+			 fdmi.optionrom_version);
+		snprintf(fc_host_firmware_version(lport->host),
+			 FC_VERSION_STRING_SIZE,
+			 "%s",
+			 fdmi.firmware_version);
+
+		/* Enable FDMI lport states */
+		lport->fdmi_enabled = 1;
+	} else {
+		lport->fdmi_enabled = 0;
+		printk(KERN_INFO "fcoe: No FDMI support.\n");
+	}
+}
+
 /**
  * fcoe_oem_match() - The match routine for the offloaded exchange manager
  * @fp: The I/O frame
@@ -881,9 +943,6 @@
 		dev_uc_del(netdev, port->data_src_addr);
 	rtnl_unlock();
 
-	/* Release reference held in fcoe_if_create() */
-	fcoe_interface_put(fcoe);
-
 	/* Free queued packets for the per-CPU receive threads */
 	fcoe_percpu_clean(lport);
 
@@ -1047,6 +1106,9 @@
 		goto out_lp_destroy;
 	}
 
+	/* Initialized FDMI information */
+	fcoe_fdmi_info(lport, netdev);
+
 	/*
 	 * fcoe_em_alloc() and fcoe_hostlist_add() both
 	 * need to be atomic with respect to other changes to the
@@ -1070,7 +1132,6 @@
 		goto out_lp_destroy;
 	}
 
-	fcoe_interface_get(fcoe);
 	return lport;
 
 out_lp_destroy:
@@ -1375,7 +1436,7 @@
 		goto err;
 
 	fps = &per_cpu(fcoe_percpu, cpu);
-	spin_lock_bh(&fps->fcoe_rx_list.lock);
+	spin_lock(&fps->fcoe_rx_list.lock);
 	if (unlikely(!fps->thread)) {
 		/*
 		 * The targeted CPU is not ready, let's target
@@ -1386,12 +1447,12 @@
 				"ready for incoming skb- using first online "
 				"CPU.\n");
 
-		spin_unlock_bh(&fps->fcoe_rx_list.lock);
+		spin_unlock(&fps->fcoe_rx_list.lock);
 		cpu = cpumask_first(cpu_online_mask);
 		fps = &per_cpu(fcoe_percpu, cpu);
-		spin_lock_bh(&fps->fcoe_rx_list.lock);
+		spin_lock(&fps->fcoe_rx_list.lock);
 		if (!fps->thread) {
-			spin_unlock_bh(&fps->fcoe_rx_list.lock);
+			spin_unlock(&fps->fcoe_rx_list.lock);
 			goto err;
 		}
 	}
@@ -1402,24 +1463,17 @@
 	 * so we're free to queue skbs into it's queue.
 	 */
 
-	/* If this is a SCSI-FCP frame, and this is already executing on the
-	 * correct CPU, and the queue for this CPU is empty, then go ahead
-	 * and process the frame directly in the softirq context.
-	 * This lets us process completions without context switching from the
-	 * NET_RX softirq, to our receive processing thread, and then back to
-	 * BLOCK softirq context.
+	/*
+	 * Note: We used to have a set of conditions under which we would
+	 * call fcoe_recv_frame directly, rather than queuing to the rx list
+	 * as it could save a few cycles, but doing so is prohibited, as
+	 * fcoe_recv_frame has several paths that may sleep, which is forbidden
+	 * in softirq context.
 	 */
-	if (fh->fh_type == FC_TYPE_FCP &&
-	    cpu == smp_processor_id() &&
-	    skb_queue_empty(&fps->fcoe_rx_list)) {
-		spin_unlock_bh(&fps->fcoe_rx_list.lock);
-		fcoe_recv_frame(skb);
-	} else {
-		__skb_queue_tail(&fps->fcoe_rx_list, skb);
-		if (fps->fcoe_rx_list.qlen == 1)
-			wake_up_process(fps->thread);
-		spin_unlock_bh(&fps->fcoe_rx_list.lock);
-	}
+	__skb_queue_tail(&fps->fcoe_rx_list, skb);
+	if (fps->thread->state == TASK_INTERRUPTIBLE)
+		wake_up_process(fps->thread);
+	spin_unlock(&fps->fcoe_rx_list.lock);
 
 	return 0;
 err:
@@ -1736,23 +1790,29 @@
 {
 	struct fcoe_percpu_s *p = arg;
 	struct sk_buff *skb;
+	struct sk_buff_head tmp;
+
+	skb_queue_head_init(&tmp);
 
 	set_user_nice(current, -20);
 
 	while (!kthread_should_stop()) {
 
 		spin_lock_bh(&p->fcoe_rx_list.lock);
-		while ((skb = __skb_dequeue(&p->fcoe_rx_list)) == NULL) {
+		skb_queue_splice_init(&p->fcoe_rx_list, &tmp);
+		spin_unlock_bh(&p->fcoe_rx_list.lock);
+
+		while ((skb = __skb_dequeue(&tmp)) != NULL)
+			fcoe_recv_frame(skb);
+
+		spin_lock_bh(&p->fcoe_rx_list.lock);
+		if (!skb_queue_len(&p->fcoe_rx_list)) {
 			set_current_state(TASK_INTERRUPTIBLE);
 			spin_unlock_bh(&p->fcoe_rx_list.lock);
 			schedule();
 			set_current_state(TASK_RUNNING);
-			if (kthread_should_stop())
-				return 0;
-			spin_lock_bh(&p->fcoe_rx_list.lock);
-		}
-		spin_unlock_bh(&p->fcoe_rx_list.lock);
-		fcoe_recv_frame(skb);
+		} else
+			spin_unlock_bh(&p->fcoe_rx_list.lock);
 	}
 	return 0;
 }
@@ -2009,20 +2069,13 @@
 {
 	struct fcoe_port *port;
 	struct fcoe_interface *fcoe;
-	int npiv = 0;
 
 	port = container_of(work, struct fcoe_port, destroy_work);
 	mutex_lock(&fcoe_config_mutex);
 
-	/* set if this is an NPIV port */
-	npiv = port->lport->vport ? 1 : 0;
-
 	fcoe = port->priv;
 	fcoe_if_destroy(port->lport);
-
-	/* Do not tear down the fcoe interface for NPIV port */
-	if (!npiv)
-		fcoe_interface_cleanup(fcoe);
+	fcoe_interface_cleanup(fcoe);
 
 	mutex_unlock(&fcoe_config_mutex);
 }
@@ -2133,8 +2186,12 @@
 	/* start FIP Discovery and FLOGI */
 	lport->boot_time = jiffies;
 	fc_fabric_login(lport);
-	if (!fcoe_link_ok(lport))
+	if (!fcoe_link_ok(lport)) {
+		rtnl_unlock();
 		fcoe_ctlr_link_up(&fcoe->ctlr);
+		mutex_unlock(&fcoe_config_mutex);
+		return rc;
+	}
 
 out_nodev:
 	rtnl_unlock();
@@ -2207,31 +2264,14 @@
 static void fcoe_percpu_clean(struct fc_lport *lport)
 {
 	struct fcoe_percpu_s *pp;
-	struct fcoe_rcv_info *fr;
-	struct sk_buff_head *list;
-	struct sk_buff *skb, *next;
-	struct sk_buff *head;
+	struct sk_buff *skb;
 	unsigned int cpu;
 
 	for_each_possible_cpu(cpu) {
 		pp = &per_cpu(fcoe_percpu, cpu);
-		spin_lock_bh(&pp->fcoe_rx_list.lock);
-		list = &pp->fcoe_rx_list;
-		head = list->next;
-		for (skb = head; skb != (struct sk_buff *)list;
-		     skb = next) {
-			next = skb->next;
-			fr = fcoe_dev_from_skb(skb);
-			if (fr->fr_dev == lport) {
-				__skb_unlink(skb, list);
-				kfree_skb(skb);
-			}
-		}
 
-		if (!pp->thread || !cpu_online(cpu)) {
-			spin_unlock_bh(&pp->fcoe_rx_list.lock);
+		if (!pp->thread || !cpu_online(cpu))
 			continue;
-		}
 
 		skb = dev_alloc_skb(0);
 		if (!skb) {
@@ -2240,6 +2280,7 @@
 		}
 		skb->destructor = fcoe_percpu_flush_done;
 
+		spin_lock_bh(&pp->fcoe_rx_list.lock);
 		__skb_queue_tail(&pp->fcoe_rx_list, skb);
 		if (pp->fcoe_rx_list.qlen == 1)
 			wake_up_process(pp->thread);
@@ -2593,12 +2634,15 @@
 	struct Scsi_Host *shost = vport_to_shost(vport);
 	struct fc_lport *n_port = shost_priv(shost);
 	struct fc_lport *vn_port = vport->dd_data;
-	struct fcoe_port *port = lport_priv(vn_port);
 
 	mutex_lock(&n_port->lp_mutex);
 	list_del(&vn_port->list);
 	mutex_unlock(&n_port->lp_mutex);
-	queue_work(fcoe_wq, &port->destroy_work);
+
+	mutex_lock(&fcoe_config_mutex);
+	fcoe_if_destroy(vn_port);
+	mutex_unlock(&fcoe_config_mutex);
+
 	return 0;
 }
 
diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h
index bcc89e6..3c2733a 100644
--- a/drivers/scsi/fcoe/fcoe.h
+++ b/drivers/scsi/fcoe/fcoe.h
@@ -71,8 +71,6 @@
  * @ctlr:	      The FCoE controller (for FIP)
  * @oem:	      The offload exchange manager for all local port
  *		      instances associated with this port
- * @kref:	      The kernel reference
- *
  * This structure is 1:1 with a net devive.
  */
 struct fcoe_interface {
@@ -83,7 +81,6 @@
 	struct packet_type fip_packet_type;
 	struct fcoe_ctlr   ctlr;
 	struct fc_exch_mgr *oem;
-	struct kref	   kref;
 };
 
 #define fcoe_from_ctlr(fip) container_of(fip, struct fcoe_interface, ctlr)
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index e7522dc..249a106 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -242,7 +242,7 @@
 		printk(KERN_INFO "libfcoe: host%d: FIP selected "
 		       "Fibre-Channel Forwarder MAC %pM\n",
 		       fip->lp->host->host_no, sel->fcf_mac);
-		memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN);
+		memcpy(fip->dest_addr, sel->fcoe_mac, ETH_ALEN);
 		fip->map_dest = 0;
 	}
 unlock:
@@ -824,6 +824,7 @@
 			memcpy(fcf->fcf_mac,
 			       ((struct fip_mac_desc *)desc)->fd_mac,
 			       ETH_ALEN);
+			memcpy(fcf->fcoe_mac, fcf->fcf_mac, ETH_ALEN);
 			if (!is_valid_ether_addr(fcf->fcf_mac)) {
 				LIBFCOE_FIP_DBG(fip,
 					"Invalid MAC addr %pM in FIP adv\n",
@@ -1013,6 +1014,7 @@
 	struct fip_desc *desc;
 	struct fip_encaps *els;
 	struct fcoe_dev_stats *stats;
+	struct fcoe_fcf *sel;
 	enum fip_desc_type els_dtype = 0;
 	u8 els_op;
 	u8 sub;
@@ -1040,7 +1042,8 @@
 			goto drop;
 		/* Drop ELS if there are duplicate critical descriptors */
 		if (desc->fip_dtype < 32) {
-			if (desc_mask & 1U << desc->fip_dtype) {
+			if ((desc->fip_dtype != FIP_DT_MAC) &&
+			    (desc_mask & 1U << desc->fip_dtype)) {
 				LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
 						"Descriptors in FIP ELS\n");
 				goto drop;
@@ -1049,17 +1052,32 @@
 		}
 		switch (desc->fip_dtype) {
 		case FIP_DT_MAC:
+			sel = fip->sel_fcf;
 			if (desc_cnt == 1) {
 				LIBFCOE_FIP_DBG(fip, "FIP descriptors "
 						"received out of order\n");
 				goto drop;
 			}
+			/*
+			 * Some switch implementations send two MAC descriptors,
+			 * with first MAC(granted_mac) being the FPMA, and the
+			 * second one(fcoe_mac) is used as destination address
+			 * for sending/receiving FCoE packets. FIP traffic is
+			 * sent using fip_mac. For regular switches, both
+			 * fip_mac and fcoe_mac would be the same.
+			 */
+			if (desc_cnt == 2)
+				memcpy(granted_mac,
+				       ((struct fip_mac_desc *)desc)->fd_mac,
+				       ETH_ALEN);
 
 			if (dlen != sizeof(struct fip_mac_desc))
 				goto len_err;
-			memcpy(granted_mac,
-			       ((struct fip_mac_desc *)desc)->fd_mac,
-			       ETH_ALEN);
+
+			if ((desc_cnt == 3) && (sel))
+				memcpy(sel->fcoe_mac,
+				       ((struct fip_mac_desc *)desc)->fd_mac,
+				       ETH_ALEN);
 			break;
 		case FIP_DT_FLOGI:
 		case FIP_DT_FDISC:
@@ -1273,11 +1291,6 @@
 		 * No Vx_Port description. Clear all NPIV ports,
 		 * followed by physical port
 		 */
-		mutex_lock(&lport->lp_mutex);
-		list_for_each_entry(vn_port, &lport->vports, list)
-			fc_lport_reset(vn_port);
-		mutex_unlock(&lport->lp_mutex);
-
 		mutex_lock(&fip->ctlr_mutex);
 		per_cpu_ptr(lport->dev_stats,
 			    get_cpu())->VLinkFailureCount++;
@@ -1285,6 +1298,11 @@
 		fcoe_ctlr_reset(fip);
 		mutex_unlock(&fip->ctlr_mutex);
 
+		mutex_lock(&lport->lp_mutex);
+		list_for_each_entry(vn_port, &lport->vports, list)
+			fc_lport_reset(vn_port);
+		mutex_unlock(&lport->lp_mutex);
+
 		fc_lport_reset(fip->lp);
 		fcoe_ctlr_solicit(fip, NULL);
 	} else {
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
index 4d119a3..710e149 100644
--- a/drivers/scsi/fcoe/fcoe_transport.c
+++ b/drivers/scsi/fcoe/fcoe_transport.c
@@ -619,8 +619,8 @@
 
 	switch (event) {
 	case NETDEV_UNREGISTER:
-		printk(KERN_ERR "libfcoe_device_notification: NETDEV_UNREGISTER %s\n",
-				netdev->name);
+		LIBFCOE_TRANSPORT_DBG("NETDEV_UNREGISTER %s\n",
+				      netdev->name);
 		fcoe_del_netdev_mapping(netdev);
 		break;
 	}
diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
index a2c6135..53bfcaa 100644
--- a/drivers/scsi/fd_mcs.c
+++ b/drivers/scsi/fd_mcs.c
@@ -93,7 +93,6 @@
 #include <linux/mca-legacy.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include "scsi.h"
 #include <scsi/scsi_host.h>
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index 643f6d5..1a2a1e5 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -282,7 +282,6 @@
 #include <linux/slab.h>
 #include <scsi/scsicam.h>
 
-#include <asm/system.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 81182ba..1a5954f 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -100,7 +100,6 @@
 #undef NCR5380_STAT_LIMIT
 #endif
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <linux/signal.h>
 #include <linux/blkdev.h>
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index d42ec92..5d72274 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -129,7 +129,6 @@
 #include <linux/reboot.h>
 
 #include <asm/dma.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/spinlock.h>
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index b96962c..500e20d 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -56,6 +56,7 @@
 /* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */
 #define HPSA_DRIVER_VERSION "2.0.2-1"
 #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
+#define HPSA "hpsa"
 
 /* How long to wait (in milliseconds) for board to go into simple mode */
 #define MAX_CONFIG_WAIT 30000
@@ -202,30 +203,31 @@
 
 	switch (c->err_info->SenseInfo[12]) {
 	case STATE_CHANGED:
-		dev_warn(&h->pdev->dev, "hpsa%d: a state change "
+		dev_warn(&h->pdev->dev, HPSA "%d: a state change "
 			"detected, command retried\n", h->ctlr);
 		break;
 	case LUN_FAILED:
-		dev_warn(&h->pdev->dev, "hpsa%d: LUN failure "
+		dev_warn(&h->pdev->dev, HPSA "%d: LUN failure "
 			"detected, action required\n", h->ctlr);
 		break;
 	case REPORT_LUNS_CHANGED:
-		dev_warn(&h->pdev->dev, "hpsa%d: report LUN data "
+		dev_warn(&h->pdev->dev, HPSA "%d: report LUN data "
 			"changed, action required\n", h->ctlr);
 	/*
-	 * Note: this REPORT_LUNS_CHANGED condition only occurs on the MSA2012.
+	 * Note: this REPORT_LUNS_CHANGED condition only occurs on the external
+	 * target (array) devices.
 	 */
 		break;
 	case POWER_OR_RESET:
-		dev_warn(&h->pdev->dev, "hpsa%d: a power on "
+		dev_warn(&h->pdev->dev, HPSA "%d: a power on "
 			"or device reset detected\n", h->ctlr);
 		break;
 	case UNIT_ATTENTION_CLEARED:
-		dev_warn(&h->pdev->dev, "hpsa%d: unit attention "
+		dev_warn(&h->pdev->dev, HPSA "%d: unit attention "
 		    "cleared by another initiator\n", h->ctlr);
 		break;
 	default:
-		dev_warn(&h->pdev->dev, "hpsa%d: unknown "
+		dev_warn(&h->pdev->dev, HPSA "%d: unknown "
 			"unit attention detected\n", h->ctlr);
 		break;
 	}
@@ -296,11 +298,23 @@
 	0x40800E11, /* Smart Array 5i */
 	0x409C0E11, /* Smart Array 6400 */
 	0x409D0E11, /* Smart Array 6400 EM */
+	0x40700E11, /* Smart Array 5300 */
+	0x40820E11, /* Smart Array 532 */
+	0x40830E11, /* Smart Array 5312 */
+	0x409A0E11, /* Smart Array 641 */
+	0x409B0E11, /* Smart Array 642 */
+	0x40910E11, /* Smart Array 6i */
 };
 
 /* List of controllers which cannot even be soft reset */
 static u32 soft_unresettable_controller[] = {
 	0x40800E11, /* Smart Array 5i */
+	0x40700E11, /* Smart Array 5300 */
+	0x40820E11, /* Smart Array 532 */
+	0x40830E11, /* Smart Array 5312 */
+	0x409A0E11, /* Smart Array 641 */
+	0x409B0E11, /* Smart Array 642 */
+	0x40910E11, /* Smart Array 6i */
 	/* Exclude 640x boards.  These are two pci devices in one slot
 	 * which share a battery backed cache module.  One controls the
 	 * cache, the other accesses the cache through the one that controls
@@ -475,8 +489,8 @@
 
 static struct scsi_host_template hpsa_driver_template = {
 	.module			= THIS_MODULE,
-	.name			= "hpsa",
-	.proc_name		= "hpsa",
+	.name			= HPSA,
+	.proc_name		= HPSA,
 	.queuecommand		= hpsa_scsi_queue_command,
 	.scan_start		= hpsa_scan_start,
 	.scan_finished		= hpsa_scan_finished,
@@ -577,21 +591,19 @@
 	int i, found = 0;
 	DECLARE_BITMAP(lun_taken, HPSA_MAX_DEVICES);
 
-	memset(&lun_taken[0], 0, HPSA_MAX_DEVICES >> 3);
+	bitmap_zero(lun_taken, HPSA_MAX_DEVICES);
 
 	for (i = 0; i < h->ndevices; i++) {
 		if (h->dev[i]->bus == bus && h->dev[i]->target != -1)
-			set_bit(h->dev[i]->target, lun_taken);
+			__set_bit(h->dev[i]->target, lun_taken);
 	}
 
-	for (i = 0; i < HPSA_MAX_DEVICES; i++) {
-		if (!test_bit(i, lun_taken)) {
-			/* *bus = 1; */
-			*target = i;
-			*lun = 0;
-			found = 1;
-			break;
-		}
+	i = find_first_zero_bit(lun_taken, HPSA_MAX_DEVICES);
+	if (i < HPSA_MAX_DEVICES) {
+		/* *bus = 1; */
+		*target = i;
+		*lun = 0;
+		found = 1;
 	}
 	return !found;
 }
@@ -675,6 +687,20 @@
 	return 0;
 }
 
+/* Update an entry in h->dev[] array. */
+static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno,
+	int entry, struct hpsa_scsi_dev_t *new_entry)
+{
+	/* assumes h->devlock is held */
+	BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES);
+
+	/* Raid level changed. */
+	h->dev[entry]->raid_level = new_entry->raid_level;
+	dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d updated.\n",
+		scsi_device_type(new_entry->devtype), hostno, new_entry->bus,
+		new_entry->target, new_entry->lun);
+}
+
 /* Replace an entry from h->dev[] array. */
 static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno,
 	int entry, struct hpsa_scsi_dev_t *new_entry,
@@ -781,10 +807,25 @@
 	return 1;
 }
 
+static inline int device_updated(struct hpsa_scsi_dev_t *dev1,
+	struct hpsa_scsi_dev_t *dev2)
+{
+	/* Device attributes that can change, but don't mean
+	 * that the device is a different device, nor that the OS
+	 * needs to be told anything about the change.
+	 */
+	if (dev1->raid_level != dev2->raid_level)
+		return 1;
+	return 0;
+}
+
 /* Find needle in haystack.  If exact match found, return DEVICE_SAME,
  * and return needle location in *index.  If scsi3addr matches, but not
  * vendor, model, serial num, etc. return DEVICE_CHANGED, and return needle
- * location in *index.  If needle not found, return DEVICE_NOT_FOUND.
+ * location in *index.
+ * In the case of a minor device attribute change, such as RAID level, just
+ * return DEVICE_UPDATED, along with the updated device's location in index.
+ * If needle not found, return DEVICE_NOT_FOUND.
  */
 static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
 	struct hpsa_scsi_dev_t *haystack[], int haystack_size,
@@ -794,15 +835,19 @@
 #define DEVICE_NOT_FOUND 0
 #define DEVICE_CHANGED 1
 #define DEVICE_SAME 2
+#define DEVICE_UPDATED 3
 	for (i = 0; i < haystack_size; i++) {
 		if (haystack[i] == NULL) /* previously removed. */
 			continue;
 		if (SCSI3ADDR_EQ(needle->scsi3addr, haystack[i]->scsi3addr)) {
 			*index = i;
-			if (device_is_the_same(needle, haystack[i]))
+			if (device_is_the_same(needle, haystack[i])) {
+				if (device_updated(needle, haystack[i]))
+					return DEVICE_UPDATED;
 				return DEVICE_SAME;
-			else
+			} else {
 				return DEVICE_CHANGED;
+			}
 		}
 	}
 	*index = -1;
@@ -838,6 +883,8 @@
 	 * sd[] and remove them from h->dev[], and for any
 	 * devices which have changed, remove the old device
 	 * info and add the new device info.
+	 * If minor device attributes change, just update
+	 * the existing device structure.
 	 */
 	i = 0;
 	nremoved = 0;
@@ -858,6 +905,8 @@
 			 * at the bottom of hpsa_update_scsi_devices()
 			 */
 			sd[entry] = NULL;
+		} else if (device_change == DEVICE_UPDATED) {
+			hpsa_scsi_update_entry(h, hostno, i, sd[entry]);
 		}
 		i++;
 	}
@@ -1257,46 +1306,6 @@
 	cmd_free(h, cp);
 }
 
-static int hpsa_scsi_detect(struct ctlr_info *h)
-{
-	struct Scsi_Host *sh;
-	int error;
-
-	sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h));
-	if (sh == NULL)
-		goto fail;
-
-	sh->io_port = 0;
-	sh->n_io_port = 0;
-	sh->this_id = -1;
-	sh->max_channel = 3;
-	sh->max_cmd_len = MAX_COMMAND_SIZE;
-	sh->max_lun = HPSA_MAX_LUN;
-	sh->max_id = HPSA_MAX_LUN;
-	sh->can_queue = h->nr_cmds;
-	sh->cmd_per_lun = h->nr_cmds;
-	sh->sg_tablesize = h->maxsgentries;
-	h->scsi_host = sh;
-	sh->hostdata[0] = (unsigned long) h;
-	sh->irq = h->intr[h->intr_mode];
-	sh->unique_id = sh->irq;
-	error = scsi_add_host(sh, &h->pdev->dev);
-	if (error)
-		goto fail_host_put;
-	scsi_scan_host(sh);
-	return 0;
-
- fail_host_put:
-	dev_err(&h->pdev->dev, "hpsa_scsi_detect: scsi_add_host"
-		" failed for controller %d\n", h->ctlr);
-	scsi_host_put(sh);
-	return error;
- fail:
-	dev_err(&h->pdev->dev, "hpsa_scsi_detect: scsi_host_alloc"
-		" failed for controller %d\n", h->ctlr);
-	return -ENOMEM;
-}
-
 static void hpsa_pci_unmap(struct pci_dev *pdev,
 	struct CommandList *c, int sg_used, int data_direction)
 {
@@ -1641,7 +1650,7 @@
 	return 1;
 }
 
-static unsigned char *msa2xxx_model[] = {
+static unsigned char *ext_target_model[] = {
 	"MSA2012",
 	"MSA2024",
 	"MSA2312",
@@ -1650,78 +1659,54 @@
 	NULL,
 };
 
-static int is_msa2xxx(struct ctlr_info *h, struct hpsa_scsi_dev_t *device)
+static int is_ext_target(struct ctlr_info *h, struct hpsa_scsi_dev_t *device)
 {
 	int i;
 
-	for (i = 0; msa2xxx_model[i]; i++)
-		if (strncmp(device->model, msa2xxx_model[i],
-			strlen(msa2xxx_model[i])) == 0)
+	for (i = 0; ext_target_model[i]; i++)
+		if (strncmp(device->model, ext_target_model[i],
+			strlen(ext_target_model[i])) == 0)
 			return 1;
 	return 0;
 }
 
 /* Helper function to assign bus, target, lun mapping of devices.
- * Puts non-msa2xxx logical volumes on bus 0, msa2xxx logical
+ * Puts non-external target logical volumes on bus 0, external target logical
  * volumes on bus 1, physical devices on bus 2. and the hba on bus 3.
  * Logical drive target and lun are assigned at this time, but
  * physical device lun and target assignment are deferred (assigned
  * in hpsa_find_target_lun, called by hpsa_scsi_add_entry.)
  */
 static void figure_bus_target_lun(struct ctlr_info *h,
-	u8 *lunaddrbytes, int *bus, int *target, int *lun,
-	struct hpsa_scsi_dev_t *device)
+	u8 *lunaddrbytes, struct hpsa_scsi_dev_t *device)
 {
-	u32 lunid;
+	u32 lunid = le32_to_cpu(*((__le32 *) lunaddrbytes));
 
-	if (is_logical_dev_addr_mode(lunaddrbytes)) {
-		/* logical device */
-		if (unlikely(is_scsi_rev_5(h))) {
-			/* p1210m, logical drives lun assignments
-			 * match SCSI REPORT LUNS data.
-			 */
-			lunid = le32_to_cpu(*((__le32 *) lunaddrbytes));
-			*bus = 0;
-			*target = 0;
-			*lun = (lunid & 0x3fff) + 1;
-		} else {
-			/* not p1210m... */
-			lunid = le32_to_cpu(*((__le32 *) lunaddrbytes));
-			if (is_msa2xxx(h, device)) {
-				/* msa2xxx way, put logicals on bus 1
-				 * and match target/lun numbers box
-				 * reports.
-				 */
-				*bus = 1;
-				*target = (lunid >> 16) & 0x3fff;
-				*lun = lunid & 0x00ff;
-			} else {
-				/* Traditional smart array way. */
-				*bus = 0;
-				*lun = 0;
-				*target = lunid & 0x3fff;
-			}
-		}
-	} else {
-		/* physical device */
+	if (!is_logical_dev_addr_mode(lunaddrbytes)) {
+		/* physical device, target and lun filled in later */
 		if (is_hba_lunid(lunaddrbytes))
-			if (unlikely(is_scsi_rev_5(h))) {
-				*bus = 0; /* put p1210m ctlr at 0,0,0 */
-				*target = 0;
-				*lun = 0;
-				return;
-			} else
-				*bus = 3; /* traditional smartarray */
+			hpsa_set_bus_target_lun(device, 3, 0, lunid & 0x3fff);
 		else
-			*bus = 2; /* physical disk */
-		*target = -1;
-		*lun = -1; /* we will fill these in later. */
+			/* defer target, lun assignment for physical devices */
+			hpsa_set_bus_target_lun(device, 2, -1, -1);
+		return;
 	}
+	/* It's a logical device */
+	if (is_ext_target(h, device)) {
+		/* external target way, put logicals on bus 1
+		 * and match target/lun numbers box
+		 * reports, other smart array, bus 0, target 0, match lunid
+		 */
+		hpsa_set_bus_target_lun(device,
+			1, (lunid >> 16) & 0x3fff, lunid & 0x00ff);
+		return;
+	}
+	hpsa_set_bus_target_lun(device, 0, 0, lunid & 0x3fff);
 }
 
 /*
  * If there is no lun 0 on a target, linux won't find any devices.
- * For the MSA2xxx boxes, we have to manually detect the enclosure
+ * For the external targets (arrays), we have to manually detect the enclosure
  * which is at lun zero, as CCISS_REPORT_PHYSICAL_LUNS doesn't report
  * it for some reason.  *tmpdevice is the target we're adding,
  * this_device is a pointer into the current element of currentsd[]
@@ -1730,46 +1715,46 @@
  * lun 0 assigned.
  * Returns 1 if an enclosure was added, 0 if not.
  */
-static int add_msa2xxx_enclosure_device(struct ctlr_info *h,
+static int add_ext_target_dev(struct ctlr_info *h,
 	struct hpsa_scsi_dev_t *tmpdevice,
 	struct hpsa_scsi_dev_t *this_device, u8 *lunaddrbytes,
-	int bus, int target, int lun, unsigned long lunzerobits[],
-	int *nmsa2xxx_enclosures)
+	unsigned long lunzerobits[], int *n_ext_target_devs)
 {
 	unsigned char scsi3addr[8];
 
-	if (test_bit(target, lunzerobits))
+	if (test_bit(tmpdevice->target, lunzerobits))
 		return 0; /* There is already a lun 0 on this target. */
 
 	if (!is_logical_dev_addr_mode(lunaddrbytes))
 		return 0; /* It's the logical targets that may lack lun 0. */
 
-	if (!is_msa2xxx(h, tmpdevice))
-		return 0; /* It's only the MSA2xxx that have this problem. */
+	if (!is_ext_target(h, tmpdevice))
+		return 0; /* Only external target devices have this problem. */
 
-	if (lun == 0) /* if lun is 0, then obviously we have a lun 0. */
+	if (tmpdevice->lun == 0) /* if lun is 0, then we have a lun 0. */
 		return 0;
 
 	memset(scsi3addr, 0, 8);
-	scsi3addr[3] = target;
+	scsi3addr[3] = tmpdevice->target;
 	if (is_hba_lunid(scsi3addr))
 		return 0; /* Don't add the RAID controller here. */
 
 	if (is_scsi_rev_5(h))
 		return 0; /* p1210m doesn't need to do this. */
 
-	if (*nmsa2xxx_enclosures >= MAX_MSA2XXX_ENCLOSURES) {
-		dev_warn(&h->pdev->dev, "Maximum number of MSA2XXX "
-			"enclosures exceeded.  Check your hardware "
+	if (*n_ext_target_devs >= MAX_EXT_TARGETS) {
+		dev_warn(&h->pdev->dev, "Maximum number of external "
+			"target devices exceeded.  Check your hardware "
 			"configuration.");
 		return 0;
 	}
 
 	if (hpsa_update_device_info(h, scsi3addr, this_device, NULL))
 		return 0;
-	(*nmsa2xxx_enclosures)++;
-	hpsa_set_bus_target_lun(this_device, bus, target, 0);
-	set_bit(target, lunzerobits);
+	(*n_ext_target_devs)++;
+	hpsa_set_bus_target_lun(this_device,
+				tmpdevice->bus, tmpdevice->target, 0);
+	set_bit(tmpdevice->target, lunzerobits);
 	return 1;
 }
 
@@ -1863,10 +1848,9 @@
 	struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice;
 	int ncurrent = 0;
 	int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 8;
-	int i, nmsa2xxx_enclosures, ndevs_to_allocate;
-	int bus, target, lun;
+	int i, n_ext_target_devs, ndevs_to_allocate;
 	int raid_ctlr_position;
-	DECLARE_BITMAP(lunzerobits, HPSA_MAX_TARGETS_PER_CTLR);
+	DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS);
 
 	currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL);
 	physdev_list = kzalloc(reportlunsize, GFP_KERNEL);
@@ -1883,11 +1867,11 @@
 			logdev_list, &nlogicals))
 		goto out;
 
-	/* We might see up to 32 MSA2xxx enclosures, actually 8 of them
-	 * but each of them 4 times through different paths.  The plus 1
-	 * is for the RAID controller.
+	/* We might see up to the maximum number of logical and physical disks
+	 * plus external target devices, and a device for the local RAID
+	 * controller.
 	 */
-	ndevs_to_allocate = nphysicals + nlogicals + MAX_MSA2XXX_ENCLOSURES + 1;
+	ndevs_to_allocate = nphysicals + nlogicals + MAX_EXT_TARGETS + 1;
 
 	/* Allocate the per device structures */
 	for (i = 0; i < ndevs_to_allocate; i++) {
@@ -1913,7 +1897,7 @@
 		raid_ctlr_position = nphysicals + nlogicals;
 
 	/* adjust our table of devices */
-	nmsa2xxx_enclosures = 0;
+	n_ext_target_devs = 0;
 	for (i = 0; i < nphysicals + nlogicals + 1; i++) {
 		u8 *lunaddrbytes, is_OBDR = 0;
 
@@ -1929,26 +1913,24 @@
 		if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice,
 							&is_OBDR))
 			continue; /* skip it if we can't talk to it. */
-		figure_bus_target_lun(h, lunaddrbytes, &bus, &target, &lun,
-			tmpdevice);
+		figure_bus_target_lun(h, lunaddrbytes, tmpdevice);
 		this_device = currentsd[ncurrent];
 
 		/*
-		 * For the msa2xxx boxes, we have to insert a LUN 0 which
+		 * For external target devices, we have to insert a LUN 0 which
 		 * doesn't show up in CCISS_REPORT_PHYSICAL data, but there
 		 * is nonetheless an enclosure device there.  We have to
 		 * present that otherwise linux won't find anything if
 		 * there is no lun 0.
 		 */
-		if (add_msa2xxx_enclosure_device(h, tmpdevice, this_device,
-				lunaddrbytes, bus, target, lun, lunzerobits,
-				&nmsa2xxx_enclosures)) {
+		if (add_ext_target_dev(h, tmpdevice, this_device,
+				lunaddrbytes, lunzerobits,
+				&n_ext_target_devs)) {
 			ncurrent++;
 			this_device = currentsd[ncurrent];
 		}
 
 		*this_device = *tmpdevice;
-		hpsa_set_bus_target_lun(this_device, bus, target, lun);
 
 		switch (this_device->devtype) {
 		case TYPE_ROM:
@@ -2228,13 +2210,42 @@
 
 static int hpsa_register_scsi(struct ctlr_info *h)
 {
-	int rc;
+	struct Scsi_Host *sh;
+	int error;
 
-	rc = hpsa_scsi_detect(h);
-	if (rc != 0)
-		dev_err(&h->pdev->dev, "hpsa_register_scsi: failed"
-			" hpsa_scsi_detect(), rc is %d\n", rc);
-	return rc;
+	sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h));
+	if (sh == NULL)
+		goto fail;
+
+	sh->io_port = 0;
+	sh->n_io_port = 0;
+	sh->this_id = -1;
+	sh->max_channel = 3;
+	sh->max_cmd_len = MAX_COMMAND_SIZE;
+	sh->max_lun = HPSA_MAX_LUN;
+	sh->max_id = HPSA_MAX_LUN;
+	sh->can_queue = h->nr_cmds;
+	sh->cmd_per_lun = h->nr_cmds;
+	sh->sg_tablesize = h->maxsgentries;
+	h->scsi_host = sh;
+	sh->hostdata[0] = (unsigned long) h;
+	sh->irq = h->intr[h->intr_mode];
+	sh->unique_id = sh->irq;
+	error = scsi_add_host(sh, &h->pdev->dev);
+	if (error)
+		goto fail_host_put;
+	scsi_scan_host(sh);
+	return 0;
+
+ fail_host_put:
+	dev_err(&h->pdev->dev, "%s: scsi_add_host"
+		" failed for controller %d\n", __func__, h->ctlr);
+	scsi_host_put(sh);
+	return error;
+ fail:
+	dev_err(&h->pdev->dev, "%s: scsi_host_alloc"
+		" failed for controller %d\n", __func__, h->ctlr);
+	return -ENOMEM;
 }
 
 static int wait_for_device_to_become_ready(struct ctlr_info *h,
@@ -2700,16 +2711,16 @@
 		status = -EINVAL;
 		goto cleanup1;
 	}
-	if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
+	if (ioc->buf_size > ioc->malloc_size * SG_ENTRIES_IN_CMD) {
 		status = -EINVAL;
 		goto cleanup1;
 	}
-	buff = kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
+	buff = kzalloc(SG_ENTRIES_IN_CMD * sizeof(char *), GFP_KERNEL);
 	if (!buff) {
 		status = -ENOMEM;
 		goto cleanup1;
 	}
-	buff_size = kmalloc(MAXSGENTRIES * sizeof(int), GFP_KERNEL);
+	buff_size = kmalloc(SG_ENTRIES_IN_CMD * sizeof(int), GFP_KERNEL);
 	if (!buff_size) {
 		status = -ENOMEM;
 		goto cleanup1;
@@ -3354,7 +3365,7 @@
 static __devinit void init_driver_version(char *driver_version, int len)
 {
 	memset(driver_version, 0, len);
-	strncpy(driver_version, "hpsa " HPSA_DRIVER_VERSION, len - 1);
+	strncpy(driver_version, HPSA " " HPSA_DRIVER_VERSION, len - 1);
 }
 
 static __devinit int write_driver_ver_to_cfgtable(
@@ -3935,7 +3946,7 @@
 		return err;
 	}
 
-	err = pci_request_regions(h->pdev, "hpsa");
+	err = pci_request_regions(h->pdev, HPSA);
 	if (err) {
 		dev_err(&h->pdev->dev,
 			"cannot obtain PCI resources, aborting\n");
@@ -4253,7 +4264,7 @@
 		spin_lock_init(&lockup_detector_lock);
 		hpsa_lockup_detector =
 			kthread_run(detect_controller_lockup_thread,
-						NULL, "hpsa");
+						NULL, HPSA);
 	}
 	if (!hpsa_lockup_detector) {
 		dev_warn(&h->pdev->dev,
@@ -4325,7 +4336,7 @@
 	if (rc != 0)
 		goto clean1;
 
-	sprintf(h->devname, "hpsa%d", number_of_controllers);
+	sprintf(h->devname, HPSA "%d", number_of_controllers);
 	h->ctlr = number_of_controllers;
 	number_of_controllers++;
 
@@ -4482,6 +4493,14 @@
 #endif				/* CONFIG_PCI_MSI */
 }
 
+static void __devexit hpsa_free_device_info(struct ctlr_info *h)
+{
+	int i;
+
+	for (i = 0; i < h->ndevices; i++)
+		kfree(h->dev[i]);
+}
+
 static void __devexit hpsa_remove_one(struct pci_dev *pdev)
 {
 	struct ctlr_info *h;
@@ -4497,6 +4516,7 @@
 	iounmap(h->vaddr);
 	iounmap(h->transtable);
 	iounmap(h->cfgtable);
+	hpsa_free_device_info(h);
 	hpsa_free_sg_chain_blocks(h);
 	pci_free_consistent(h->pdev,
 		h->nr_cmds * sizeof(struct CommandList),
@@ -4530,7 +4550,7 @@
 }
 
 static struct pci_driver hpsa_pci_driver = {
-	.name = "hpsa",
+	.name = HPSA,
 	.probe = hpsa_init_one,
 	.remove = __devexit_p(hpsa_remove_one),
 	.id_table = hpsa_pci_device_id,	/* id_table */
@@ -4592,15 +4612,15 @@
 	 * Each SG entry requires 16 bytes.  The eight registers are programmed
 	 * with the number of 16-byte blocks a command of that size requires.
 	 * The smallest command possible requires 5 such 16 byte blocks.
-	 * the largest command possible requires MAXSGENTRIES + 4 16-byte
+	 * the largest command possible requires SG_ENTRIES_IN_CMD + 4 16-byte
 	 * blocks.  Note, this only extends to the SG entries contained
 	 * within the command block, and does not extend to chained blocks
 	 * of SG elements.   bft[] contains the eight values we write to
 	 * the registers.  They are not evenly distributed, but have more
 	 * sizes for small commands, and fewer sizes for larger commands.
 	 */
-	int bft[8] = {5, 6, 8, 10, 12, 20, 28, MAXSGENTRIES + 4};
-	BUILD_BUG_ON(28 > MAXSGENTRIES + 4);
+	int bft[8] = {5, 6, 8, 10, 12, 20, 28, SG_ENTRIES_IN_CMD + 4};
+	BUILD_BUG_ON(28 > SG_ENTRIES_IN_CMD + 4);
 	/*  5 = 1 s/g entry or 4k
 	 *  6 = 2 s/g entry or 8k
 	 *  8 = 4 s/g entry or 16k
@@ -4613,8 +4633,9 @@
 	memset(h->reply_pool, 0, h->reply_pool_size);
 	h->reply_pool_head = h->reply_pool;
 
-	bft[7] = h->max_sg_entries + 4;
-	calc_bucket_map(bft, ARRAY_SIZE(bft), 32, h->blockFetchTable);
+	bft[7] = SG_ENTRIES_IN_CMD + 4;
+	calc_bucket_map(bft, ARRAY_SIZE(bft),
+				SG_ENTRIES_IN_CMD, h->blockFetchTable);
 	for (i = 0; i < 8; i++)
 		writel(bft[i], &h->transtable->BlockFetch[i]);
 
@@ -4652,14 +4673,13 @@
 		return;
 
 	hpsa_get_max_perf_mode_cmds(h);
-	h->max_sg_entries = 32;
 	/* Performant mode ring buffer and supporting data structures */
 	h->reply_pool_size = h->max_commands * sizeof(u64);
 	h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size,
 				&(h->reply_pool_dhandle));
 
 	/* Need a block fetch table for performant mode */
-	h->blockFetchTable = kmalloc(((h->max_sg_entries+1) *
+	h->blockFetchTable = kmalloc(((SG_ENTRIES_IN_CMD + 1) *
 				sizeof(u32)), GFP_KERNEL);
 
 	if ((h->reply_pool == NULL)
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 91edafb..7b28d54 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -58,7 +58,6 @@
 	unsigned long paddr;
 	int 	nr_cmds; /* Number of commands allowed on this controller */
 	struct CfgTable __iomem *cfgtable;
-	int     max_sg_entries;
 	int	interrupts_enabled;
 	int	major;
 	int 	max_commands;
@@ -317,7 +316,7 @@
 		dev_dbg(&h->pdev->dev, "Read %lx back from board\n",
 			register_value);
 	else
-		dev_dbg(&h->pdev->dev, "hpsa: FIFO Empty read\n");
+		dev_dbg(&h->pdev->dev, "FIFO Empty read\n");
 #endif
 
 	return register_value;
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 3fd4715..8049815 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -23,7 +23,7 @@
 
 /* general boundary defintions */
 #define SENSEINFOBYTES          32 /* may vary between hbas */
-#define MAXSGENTRIES            32
+#define SG_ENTRIES_IN_CMD	32 /* Max SG entries excluding chain blocks */
 #define HPSA_SG_CHAIN		0x80000000
 #define MAXREPLYQS              256
 
@@ -122,12 +122,11 @@
 };
 
 /* FIXME this is a per controller value (barf!) */
-#define HPSA_MAX_TARGETS_PER_CTLR 16
 #define HPSA_MAX_LUN 1024
 #define HPSA_MAX_PHYS_LUN 1024
-#define MAX_MSA2XXX_ENCLOSURES 32
+#define MAX_EXT_TARGETS 32
 #define HPSA_MAX_DEVICES (HPSA_MAX_PHYS_LUN + HPSA_MAX_LUN + \
-	MAX_MSA2XXX_ENCLOSURES + 1) /* + 1 is for the controller itself */
+	MAX_EXT_TARGETS + 1) /* + 1 is for the controller itself */
 
 /* SCSI-3 Commands */
 #pragma pack(1)
@@ -282,7 +281,7 @@
 	struct CommandListHeader Header;
 	struct RequestBlock      Request;
 	struct ErrDescriptor     ErrDesc;
-	struct SGDescriptor      SG[MAXSGENTRIES];
+	struct SGDescriptor      SG[SG_ENTRIES_IN_CMD];
 	/* information associated with the command */
 	u32			   busaddr; /* physical addr of this record */
 	struct ErrorInfo *err_info; /* pointer to the allocated mem */
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 67fc8ff..cd09132 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -32,7 +32,6 @@
 #include <linux/spinlock.h>
 #include <linux/init.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include "scsi.h"
diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile
index a423d96..ff5b5c5 100644
--- a/drivers/scsi/ibmvscsi/Makefile
+++ b/drivers/scsi/ibmvscsi/Makefile
@@ -1,7 +1,6 @@
 obj-$(CONFIG_SCSI_IBMVSCSI)	+= ibmvscsic.o
 
 ibmvscsic-y			+= ibmvscsi.o
-ibmvscsic-$(CONFIG_PPC_ISERIES)	+= iseries_vscsi.o 
 ibmvscsic-$(CONFIG_PPC_PSERIES)	+= rpa_vscsi.o 
 
 obj-$(CONFIG_SCSI_IBMVSCSIS)	+= ibmvstgt.o
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index bdfa223..134a0ae 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -4890,11 +4890,8 @@
 	.probe = ibmvfc_probe,
 	.remove = ibmvfc_remove,
 	.get_desired_dma = ibmvfc_get_desired_dma,
-	.driver = {
-		.name = IBMVFC_NAME,
-		.owner = THIS_MODULE,
-		.pm = &ibmvfc_pm_ops,
-	}
+	.name = IBMVFC_NAME,
+	.pm = &ibmvfc_pm_ops,
 };
 
 static struct fc_function_template ibmvfc_transport_functions = {
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 3d391dc..3a6c474 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -55,13 +55,7 @@
  * and sends a CRQ message back to inform the client that the request has
  * completed.
  *
- * Note that some of the underlying infrastructure is different between
- * machines conforming to the "RS/6000 Platform Architecture" (RPA) and
- * the older iSeries hypervisor models.  To support both, some low level
- * routines have been broken out into rpa_vscsi.c and iseries_vscsi.c.
- * The Makefile should pick one, not two, not zero, of these.
- *
- * TODO: This is currently pretty tied to the IBM i/pSeries hypervisor
+ * TODO: This is currently pretty tied to the IBM pSeries hypervisor
  * interfaces.  It would be really nice to abstract this above an RDMA
  * layer.
  */
@@ -2067,11 +2061,8 @@
 	.probe = ibmvscsi_probe,
 	.remove = ibmvscsi_remove,
 	.get_desired_dma = ibmvscsi_get_desired_dma,
-	.driver = {
-		.name = "ibmvscsi",
-		.owner = THIS_MODULE,
-		.pm = &ibmvscsi_pm_ops,
-	}
+	.name = "ibmvscsi",
+	.pm = &ibmvscsi_pm_ops,
 };
 
 static struct srp_function_template ibmvscsi_transport_functions = {
@@ -2085,9 +2076,7 @@
 	driver_template.can_queue = max_requests;
 	max_events = max_requests + 2;
 
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		ibmvscsi_ops = &iseriesvscsi_ops;
-	else if (firmware_has_feature(FW_FEATURE_VIO))
+	if (firmware_has_feature(FW_FEATURE_VIO))
 		ibmvscsi_ops = &rpavscsi_ops;
 	else
 		return -ENODEV;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 02197a2..c503e17 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -127,7 +127,6 @@
 	int (*resume) (struct ibmvscsi_host_data *hostdata);
 };
 
-extern struct ibmvscsi_ops iseriesvscsi_ops;
 extern struct ibmvscsi_ops rpavscsi_ops;
 
 #endif				/* IBMVSCSI_H */
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index 2256bab..aa7ed81 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -918,10 +918,7 @@
 	.id_table = ibmvstgt_device_table,
 	.probe = ibmvstgt_probe,
 	.remove = ibmvstgt_remove,
-	.driver = {
-		.name = "ibmvscsis",
-		.owner = THIS_MODULE,
-	}
+	.name = "ibmvscsis",
 };
 
 static int get_system_info(void)
diff --git a/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c
deleted file mode 100644
index f477645..0000000
--- a/drivers/scsi/ibmvscsi/iseries_vscsi.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/* ------------------------------------------------------------
- * iSeries_vscsi.c
- * (C) Copyright IBM Corporation 1994, 2003
- * Authors: Colin DeVilbiss (devilbis@us.ibm.com)
- *          Santiago Leon (santil@us.ibm.com)
- *          Dave Boutcher (sleddog@us.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 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
- *
- * ------------------------------------------------------------
- * iSeries-specific functions of the SCSI host adapter for Virtual I/O devices
- *
- * This driver allows the Linux SCSI peripheral drivers to directly
- * access devices in the hosting partition, either on an iSeries
- * hypervisor system or a converged hypervisor system.
- */
-
-#include <asm/iseries/vio.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/vio.h>
-#include <linux/device.h>
-#include "ibmvscsi.h"
-
-/* global variables */
-static struct ibmvscsi_host_data *single_host_data;
-
-/* ------------------------------------------------------------
- * Routines for direct interpartition interaction
- */
-struct srp_lp_event {
-	struct HvLpEvent lpevt;	/* 0x00-0x17          */
-	u32 reserved1;		/* 0x18-0x1B; unused  */
-	u16 version;		/* 0x1C-0x1D; unused  */
-	u16 subtype_rc;		/* 0x1E-0x1F; unused  */
-	struct viosrp_crq crq;	/* 0x20-0x3F          */
-};
-
-/** 
- * standard interface for handling logical partition events.
- */
-static void iseriesvscsi_handle_event(struct HvLpEvent *lpevt)
-{
-	struct srp_lp_event *evt = (struct srp_lp_event *)lpevt;
-
-	if (!evt) {
-		printk(KERN_ERR "ibmvscsi: received null event\n");
-		return;
-	}
-
-	if (single_host_data == NULL) {
-		printk(KERN_ERR
-		       "ibmvscsi: received event, no adapter present\n");
-		return;
-	}
-
-	ibmvscsi_handle_crq(&evt->crq, single_host_data);
-}
-
-/* ------------------------------------------------------------
- * Routines for driver initialization
- */
-static int iseriesvscsi_init_crq_queue(struct crq_queue *queue,
-				       struct ibmvscsi_host_data *hostdata,
-				       int max_requests)
-{
-	int rc;
-
-	single_host_data = hostdata;
-	rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, max_requests);
-	if (rc < 0) {
-		printk("viopath_open failed with rc %d in open_event_path\n",
-		       rc);
-		goto viopath_open_failed;
-	}
-
-	rc = vio_setHandler(viomajorsubtype_scsi, iseriesvscsi_handle_event);
-	if (rc < 0) {
-		printk("vio_setHandler failed with rc %d in open_event_path\n",
-		       rc);
-		goto vio_setHandler_failed;
-	}
-	return 0;
-
-      vio_setHandler_failed:
-	viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests);
-      viopath_open_failed:
-	return -1;
-}
-
-static void iseriesvscsi_release_crq_queue(struct crq_queue *queue,
-					   struct ibmvscsi_host_data *hostdata,
-					   int max_requests)
-{
-	vio_clearHandler(viomajorsubtype_scsi);
-	viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests);
-}
-
-/**
- * reset_crq_queue: - resets a crq after a failure
- * @queue:	crq_queue to initialize and register
- * @hostdata:	ibmvscsi_host_data of host
- *
- * no-op for iSeries
- */
-static int iseriesvscsi_reset_crq_queue(struct crq_queue *queue,
-					struct ibmvscsi_host_data *hostdata)
-{
-	return 0;
-}
-
-/**
- * reenable_crq_queue: - reenables a crq after a failure
- * @queue:	crq_queue to initialize and register
- * @hostdata:	ibmvscsi_host_data of host
- *
- * no-op for iSeries
- */
-static int iseriesvscsi_reenable_crq_queue(struct crq_queue *queue,
-					   struct ibmvscsi_host_data *hostdata)
-{
-	return 0;
-}
-
-/**
- * iseriesvscsi_send_crq: - Send a CRQ
- * @hostdata:	the adapter
- * @word1:	the first 64 bits of the data
- * @word2:	the second 64 bits of the data
- */
-static int iseriesvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
-				 u64 word1, u64 word2)
-{
-	single_host_data = hostdata;
-	return HvCallEvent_signalLpEventFast(viopath_hostLp,
-					     HvLpEvent_Type_VirtualIo,
-					     viomajorsubtype_scsi,
-					     HvLpEvent_AckInd_NoAck,
-					     HvLpEvent_AckType_ImmediateAck,
-					     viopath_sourceinst(viopath_hostLp),
-					     viopath_targetinst(viopath_hostLp),
-					     0,
-					     VIOVERSION << 16, word1, word2, 0,
-					     0);
-}
-
-static int iseriesvscsi_resume(struct ibmvscsi_host_data *hostdata)
-{
-	return 0;
-}
-
-struct ibmvscsi_ops iseriesvscsi_ops = {
-	.init_crq_queue = iseriesvscsi_init_crq_queue,
-	.release_crq_queue = iseriesvscsi_release_crq_queue,
-	.reset_crq_queue = iseriesvscsi_reset_crq_queue,
-	.reenable_crq_queue = iseriesvscsi_reenable_crq_queue,
-	.send_crq = iseriesvscsi_send_crq,
-	.resume = iseriesvscsi_resume,
-};
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index 112f1be..deb5b6d 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -123,7 +123,6 @@
 #include <linux/stat.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include "scsi.h"
 #include <scsi/scsi_host.h>
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index b538f08..e002cd4 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -104,7 +104,9 @@
 static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
 	{ /* Gemstone, Citrine, Obsidian, and Obsidian-E */
 		.mailbox = 0x0042C,
+		.max_cmds = 100,
 		.cache_line_size = 0x20,
+		.clear_isr = 1,
 		{
 			.set_interrupt_mask_reg = 0x0022C,
 			.clr_interrupt_mask_reg = 0x00230,
@@ -126,7 +128,9 @@
 	},
 	{ /* Snipe and Scamp */
 		.mailbox = 0x0052C,
+		.max_cmds = 100,
 		.cache_line_size = 0x20,
+		.clear_isr = 1,
 		{
 			.set_interrupt_mask_reg = 0x00288,
 			.clr_interrupt_mask_reg = 0x0028C,
@@ -148,7 +152,9 @@
 	},
 	{ /* CRoC */
 		.mailbox = 0x00044,
+		.max_cmds = 1000,
 		.cache_line_size = 0x20,
+		.clear_isr = 0,
 		{
 			.set_interrupt_mask_reg = 0x00010,
 			.clr_interrupt_mask_reg = 0x00018,
@@ -183,7 +189,7 @@
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] },
 	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] },
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] }
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] }
 };
 
 static int ipr_max_bus_speeds [] = {
@@ -847,8 +853,6 @@
 
 	ipr_trc_hook(ipr_cmd, IPR_TRACE_START, 0);
 
-	mb();
-
 	ipr_send_command(ipr_cmd);
 }
 
@@ -982,8 +986,6 @@
 
 		ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_IOA_RES_ADDR);
 
-		mb();
-
 		ipr_send_command(ipr_cmd);
 	} else {
 		list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q);
@@ -4339,8 +4341,7 @@
 
 	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
 		if ((res->bus == starget->channel) &&
-		    (res->target == starget->id) &&
-		    (res->lun == 0)) {
+		    (res->target == starget->id)) {
 			return res;
 		}
 	}
@@ -4414,12 +4415,14 @@
 	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata;
 
 	if (ioa_cfg->sis64) {
-		if (starget->channel == IPR_ARRAY_VIRTUAL_BUS)
-			clear_bit(starget->id, ioa_cfg->array_ids);
-		else if (starget->channel == IPR_VSET_VIRTUAL_BUS)
-			clear_bit(starget->id, ioa_cfg->vset_ids);
-		else if (starget->channel == 0)
-			clear_bit(starget->id, ioa_cfg->target_ids);
+		if (!ipr_find_starget(starget)) {
+			if (starget->channel == IPR_ARRAY_VIRTUAL_BUS)
+				clear_bit(starget->id, ioa_cfg->array_ids);
+			else if (starget->channel == IPR_VSET_VIRTUAL_BUS)
+				clear_bit(starget->id, ioa_cfg->vset_ids);
+			else if (starget->channel == 0)
+				clear_bit(starget->id, ioa_cfg->target_ids);
+		}
 	}
 
 	if (sata_port) {
@@ -5048,12 +5051,14 @@
 		del_timer(&ioa_cfg->reset_cmd->timer);
 		ipr_reset_ioa_job(ioa_cfg->reset_cmd);
 	} else if ((int_reg & IPR_PCII_HRRQ_UPDATED) == int_reg) {
-		if (ipr_debug && printk_ratelimit())
-			dev_err(&ioa_cfg->pdev->dev,
-				"Spurious interrupt detected. 0x%08X\n", int_reg);
-		writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32);
-		int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
-		return IRQ_NONE;
+		if (ioa_cfg->clear_isr) {
+			if (ipr_debug && printk_ratelimit())
+				dev_err(&ioa_cfg->pdev->dev,
+					"Spurious interrupt detected. 0x%08X\n", int_reg);
+			writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32);
+			int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
+			return IRQ_NONE;
+		}
 	} else {
 		if (int_reg & IPR_PCII_IOA_UNIT_CHECKED)
 			ioa_cfg->ioa_unit_checked = 1;
@@ -5153,6 +5158,9 @@
 			}
 		}
 
+		if (ipr_cmd && !ioa_cfg->clear_isr)
+			break;
+
 		if (ipr_cmd != NULL) {
 			/* Clear the PCI interrupt */
 			num_hrrq = 0;
@@ -5854,14 +5862,12 @@
 			rc = ipr_build_ioadl(ioa_cfg, ipr_cmd);
 	}
 
-	if (likely(rc == 0)) {
-		mb();
-		ipr_send_command(ipr_cmd);
-	} else {
-		 list_move_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
-		 return SCSI_MLQUEUE_HOST_BUSY;
+	if (unlikely(rc != 0)) {
+		list_move_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+		return SCSI_MLQUEUE_HOST_BUSY;
 	}
 
+	ipr_send_command(ipr_cmd);
 	return 0;
 }
 
@@ -6239,8 +6245,6 @@
 		return AC_ERR_INVALID;
 	}
 
-	mb();
-
 	ipr_send_command(ipr_cmd);
 
 	return 0;
@@ -8277,6 +8281,10 @@
 	if (ioa_cfg->ipr_cmd_pool)
 		pci_pool_destroy (ioa_cfg->ipr_cmd_pool);
 
+	kfree(ioa_cfg->ipr_cmnd_list);
+	kfree(ioa_cfg->ipr_cmnd_list_dma);
+	ioa_cfg->ipr_cmnd_list = NULL;
+	ioa_cfg->ipr_cmnd_list_dma = NULL;
 	ioa_cfg->ipr_cmd_pool = NULL;
 }
 
@@ -8352,11 +8360,19 @@
 	int i;
 
 	ioa_cfg->ipr_cmd_pool = pci_pool_create (IPR_NAME, ioa_cfg->pdev,
-						 sizeof(struct ipr_cmnd), 16, 0);
+						 sizeof(struct ipr_cmnd), 512, 0);
 
 	if (!ioa_cfg->ipr_cmd_pool)
 		return -ENOMEM;
 
+	ioa_cfg->ipr_cmnd_list = kcalloc(IPR_NUM_CMD_BLKS, sizeof(struct ipr_cmnd *), GFP_KERNEL);
+	ioa_cfg->ipr_cmnd_list_dma = kcalloc(IPR_NUM_CMD_BLKS, sizeof(dma_addr_t), GFP_KERNEL);
+
+	if (!ioa_cfg->ipr_cmnd_list || !ioa_cfg->ipr_cmnd_list_dma) {
+		ipr_free_cmd_blks(ioa_cfg);
+		return -ENOMEM;
+	}
+
 	for (i = 0; i < IPR_NUM_CMD_BLKS; i++) {
 		ipr_cmd = pci_pool_alloc (ioa_cfg->ipr_cmd_pool, GFP_KERNEL, &dma_addr);
 
@@ -8584,6 +8600,7 @@
 	host->max_channel = IPR_MAX_BUS_TO_SCAN;
 	host->unique_id = host->host_no;
 	host->max_cmd_len = IPR_MAX_CDB_LEN;
+	host->can_queue = ioa_cfg->max_cmds;
 	pci_set_drvdata(pdev, ioa_cfg);
 
 	p = &ioa_cfg->chip_cfg->regs;
@@ -8768,6 +8785,8 @@
 	/* set SIS 32 or SIS 64 */
 	ioa_cfg->sis64 = ioa_cfg->ipr_chip->sis_type == IPR_SIS64 ? 1 : 0;
 	ioa_cfg->chip_cfg = ioa_cfg->ipr_chip->cfg;
+	ioa_cfg->clear_isr = ioa_cfg->chip_cfg->clear_isr;
+	ioa_cfg->max_cmds = ioa_cfg->chip_cfg->max_cmds;
 
 	if (ipr_transop_timeout)
 		ioa_cfg->transop_timeout = ipr_transop_timeout;
@@ -9191,15 +9210,15 @@
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C3, 0, 0, 0 },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C4, 0, 0, 0 },
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B4, 0, 0, 0 },
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B1, 0, 0, 0 },
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C6, 0, 0, 0 },
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
-		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575D, 0, 0, 0 },
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C8, 0, 0, 0 },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57CE, 0, 0, 0 },
 	{ }
 };
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index b13f9cc..153b8bd 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -38,8 +38,8 @@
 /*
  * Literals
  */
-#define IPR_DRIVER_VERSION "2.5.2"
-#define IPR_DRIVER_DATE "(April 27, 2011)"
+#define IPR_DRIVER_VERSION "2.5.3"
+#define IPR_DRIVER_DATE "(March 10, 2012)"
 
 /*
  * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -53,12 +53,12 @@
  * IPR_NUM_BASE_CMD_BLKS: This defines the maximum number of
  *	ops the mid-layer can send to the adapter.
  */
-#define IPR_NUM_BASE_CMD_BLKS				100
+#define IPR_NUM_BASE_CMD_BLKS			(ioa_cfg->max_cmds)
 
 #define PCI_DEVICE_ID_IBM_OBSIDIAN_E	0x0339
 
 #define PCI_DEVICE_ID_IBM_CROC_FPGA_E2          0x033D
-#define PCI_DEVICE_ID_IBM_CROC_ASIC_E2          0x034A
+#define PCI_DEVICE_ID_IBM_CROCODILE             0x034A
 
 #define IPR_SUBS_DEV_ID_2780	0x0264
 #define IPR_SUBS_DEV_ID_5702	0x0266
@@ -92,7 +92,7 @@
 #define IPR_SUBS_DEV_ID_57B1    0x0355
 
 #define IPR_SUBS_DEV_ID_574D    0x0356
-#define IPR_SUBS_DEV_ID_575D    0x035D
+#define IPR_SUBS_DEV_ID_57C8    0x035D
 
 #define IPR_NAME				"ipr"
 
@@ -153,7 +153,7 @@
 #define IPR_NUM_INTERNAL_CMD_BLKS	(IPR_NUM_HCAMS + \
                                      ((IPR_NUM_RESET_RELOAD_RETRIES + 1) * 2) + 4)
 
-#define IPR_MAX_COMMANDS		IPR_NUM_BASE_CMD_BLKS
+#define IPR_MAX_COMMANDS		100
 #define IPR_NUM_CMD_BLKS		(IPR_NUM_BASE_CMD_BLKS + \
 						IPR_NUM_INTERNAL_CMD_BLKS)
 
@@ -1305,7 +1305,9 @@
 
 struct ipr_chip_cfg_t {
 	u32 mailbox;
+	u16 max_cmds;
 	u8 cache_line_size;
+	u8 clear_isr;
 	struct ipr_interrupt_offsets regs;
 };
 
@@ -1388,6 +1390,7 @@
 	u8 sis64:1;
 	u8 dump_timeout:1;
 	u8 cfg_locked:1;
+	u8 clear_isr:1;
 
 	u8 revid;
 
@@ -1501,8 +1504,9 @@
 	struct ata_host ata_host;
 	char ipr_cmd_label[8];
 #define IPR_CMD_LABEL		"ipr_cmd"
-	struct ipr_cmnd *ipr_cmnd_list[IPR_NUM_CMD_BLKS];
-	dma_addr_t ipr_cmnd_list_dma[IPR_NUM_CMD_BLKS];
+	u32 max_cmds;
+	struct ipr_cmnd **ipr_cmnd_list;
+	dma_addr_t *ipr_cmnd_list_dma;
 }; /* struct ipr_ioa_cfg */
 
 struct ipr_cmnd {
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 6ca9b26..d4bf9c1 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -649,15 +649,13 @@
 
 int isci_host_scan_finished(struct Scsi_Host *shost, unsigned long time)
 {
-	struct isci_host *ihost = SHOST_TO_SAS_HA(shost)->lldd_ha;
+	struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+	struct isci_host *ihost = ha->lldd_ha;
 
 	if (test_bit(IHOST_START_PENDING, &ihost->flags))
 		return 0;
 
-	/* todo: use sas_flush_discovery once it is upstream */
-	scsi_flush_work(shost);
-
-	scsi_flush_work(shost);
+	sas_drain_work(ha);
 
 	dev_dbg(&ihost->pdev->dev,
 		"%s: ihost->status = %d, time = %ld\n",
@@ -1490,6 +1488,15 @@
 static void sci_controller_ready_state_enter(struct sci_base_state_machine *sm)
 {
 	struct isci_host *ihost = container_of(sm, typeof(*ihost), sm);
+	u32 val;
+
+	/* enable clock gating for power control of the scu unit */
+	val = readl(&ihost->smu_registers->clock_gating_control);
+	val &= ~(SMU_CGUCR_GEN_BIT(REGCLK_ENABLE) |
+		 SMU_CGUCR_GEN_BIT(TXCLK_ENABLE) |
+		 SMU_CGUCR_GEN_BIT(XCLK_ENABLE));
+	val |= SMU_CGUCR_GEN_BIT(IDLE_ENABLE);
+	writel(val, &ihost->smu_registers->clock_gating_control);
 
 	/* set the default interrupt coalescence number and timeout value. */
 	sci_controller_set_interrupt_coalescence(ihost, 0, 0);
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 5477f0f..adbad69 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -187,6 +187,7 @@
 	int id; /* unique within a given pci device */
 	struct isci_phy phys[SCI_MAX_PHYS];
 	struct isci_port ports[SCI_MAX_PORTS + 1]; /* includes dummy port */
+	struct asd_sas_port sas_ports[SCI_MAX_PORTS];
 	struct sas_ha_struct sas_ha;
 
 	spinlock_t state_lock;
@@ -393,24 +394,6 @@
 #define sci_controller_clear_invalid_phy(controller, phy) \
 	((controller)->invalid_phy_mask &= ~(1 << (phy)->phy_index))
 
-static inline struct device *sciphy_to_dev(struct isci_phy *iphy)
-{
-
-	if (!iphy || !iphy->isci_port || !iphy->isci_port->isci_host)
-		return NULL;
-
-	return &iphy->isci_port->isci_host->pdev->dev;
-}
-
-static inline struct device *sciport_to_dev(struct isci_port *iport)
-{
-
-	if (!iport || !iport->isci_host)
-		return NULL;
-
-	return &iport->isci_host->pdev->dev;
-}
-
 static inline struct device *scirdev_to_dev(struct isci_remote_device *idev)
 {
 	if (!idev || !idev->isci_port || !idev->isci_port->isci_host)
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 17c4c2c..5137db5 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -60,6 +60,7 @@
 #include <linux/efi.h>
 #include <asm/string.h>
 #include <scsi/scsi_host.h>
+#include "host.h"
 #include "isci.h"
 #include "task.h"
 #include "probe_roms.h"
@@ -154,7 +155,6 @@
 	.queuecommand			= sas_queuecommand,
 	.target_alloc			= sas_target_alloc,
 	.slave_configure		= sas_slave_configure,
-	.slave_destroy			= sas_slave_destroy,
 	.scan_finished			= isci_host_scan_finished,
 	.scan_start			= isci_host_scan_start,
 	.change_queue_depth		= sas_change_queue_depth,
@@ -166,9 +166,6 @@
 	.sg_tablesize			= SG_ALL,
 	.max_sectors			= SCSI_DEFAULT_MAX_SECTORS,
 	.use_clustering			= ENABLE_CLUSTERING,
-	.eh_device_reset_handler	= sas_eh_device_reset_handler,
-	.eh_bus_reset_handler		= isci_bus_reset_handler,
-	.slave_alloc			= sas_slave_alloc,
 	.target_destroy			= sas_target_destroy,
 	.ioctl				= sas_ioctl,
 	.shost_attrs			= isci_host_attrs,
@@ -194,6 +191,9 @@
 	.lldd_lu_reset		= isci_task_lu_reset,
 	.lldd_query_task	= isci_task_query_task,
 
+	/* ata recovery called from ata-eh */
+	.lldd_ata_check_ready	= isci_ata_check_ready,
+
 	/* Port and Adapter management */
 	.lldd_clear_nexus_port	= isci_task_clear_nexus_port,
 	.lldd_clear_nexus_ha	= isci_task_clear_nexus_ha,
@@ -242,18 +242,13 @@
 	if (!sas_ports)
 		return -ENOMEM;
 
-	/*----------------- Libsas Initialization Stuff----------------------
-	 * Set various fields in the sas_ha struct:
-	 */
-
 	sas_ha->sas_ha_name = DRV_NAME;
 	sas_ha->lldd_module = THIS_MODULE;
 	sas_ha->sas_addr    = &isci_host->phys[0].sas_addr[0];
 
-	/* set the array of phy and port structs.  */
 	for (i = 0; i < SCI_MAX_PHYS; i++) {
 		sas_phys[i] = &isci_host->phys[i].sas_phy;
-		sas_ports[i] = &isci_host->ports[i].sas_port;
+		sas_ports[i] = &isci_host->sas_ports[i];
 	}
 
 	sas_ha->sas_phy  = sas_phys;
@@ -528,6 +523,13 @@
 			goto err_host_alloc;
 		}
 		pci_info->hosts[i] = h;
+
+		/* turn on DIF support */
+		scsi_host_set_prot(h->shost,
+				   SHOST_DIF_TYPE1_PROTECTION |
+				   SHOST_DIF_TYPE2_PROTECTION |
+				   SHOST_DIF_TYPE3_PROTECTION);
+		scsi_host_set_guard(h->shost, SHOST_DIX_GUARD_CRC);
 	}
 
 	err = isci_setup_interrupts(pdev);
@@ -551,9 +553,9 @@
 	int i;
 
 	for_each_isci_host(i, ihost, pdev) {
+		wait_for_start(ihost);
 		isci_unregister(ihost);
 		isci_host_deinit(ihost);
-		sci_controller_disable_interrupts(ihost);
 	}
 }
 
diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c
index fe18acf..fab3586 100644
--- a/drivers/scsi/isci/phy.c
+++ b/drivers/scsi/isci/phy.c
@@ -59,6 +59,16 @@
 #include "scu_event_codes.h"
 #include "probe_roms.h"
 
+#undef C
+#define C(a) (#a)
+static const char *phy_state_name(enum sci_phy_states state)
+{
+	static const char * const strings[] = PHY_STATES;
+
+	return strings[state];
+}
+#undef C
+
 /* Maximum arbitration wait time in micro-seconds */
 #define SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME  (700)
 
@@ -67,6 +77,19 @@
 	return iphy->max_negotiated_speed;
 }
 
+static struct isci_host *phy_to_host(struct isci_phy *iphy)
+{
+	struct isci_phy *table = iphy - iphy->phy_index;
+	struct isci_host *ihost = container_of(table, typeof(*ihost), phys[0]);
+
+	return ihost;
+}
+
+static struct device *sciphy_to_dev(struct isci_phy *iphy)
+{
+	return &phy_to_host(iphy)->pdev->dev;
+}
+
 static enum sci_status
 sci_phy_transport_layer_initialization(struct isci_phy *iphy,
 				       struct scu_transport_layer_registers __iomem *reg)
@@ -446,8 +469,8 @@
 	enum sci_phy_states state = iphy->sm.current_state_id;
 
 	if (state != SCI_PHY_STOPPED) {
-		dev_dbg(sciphy_to_dev(iphy),
-			 "%s: in wrong state: %d\n", __func__, state);
+		dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n",
+			__func__, phy_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -472,8 +495,8 @@
 	case SCI_PHY_READY:
 		break;
 	default:
-		dev_dbg(sciphy_to_dev(iphy),
-			"%s: in wrong state: %d\n", __func__, state);
+		dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n",
+			__func__, phy_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -486,8 +509,8 @@
 	enum sci_phy_states state = iphy->sm.current_state_id;
 
 	if (state != SCI_PHY_READY) {
-		dev_dbg(sciphy_to_dev(iphy),
-			"%s: in wrong state: %d\n", __func__, state);
+		dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n",
+			__func__, phy_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -536,8 +559,8 @@
 		return SCI_SUCCESS;
 	}
 	default:
-		dev_dbg(sciphy_to_dev(iphy),
-			"%s: in wrong state: %d\n", __func__, state);
+		dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n",
+			__func__, phy_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 }
@@ -591,6 +614,60 @@
 	sci_change_state(&iphy->sm, next_state);
 }
 
+static const char *phy_event_name(u32 event_code)
+{
+	switch (scu_get_event_code(event_code)) {
+	case SCU_EVENT_PORT_SELECTOR_DETECTED:
+		return "port selector";
+	case SCU_EVENT_SENT_PORT_SELECTION:
+		return "port selection";
+	case SCU_EVENT_HARD_RESET_TRANSMITTED:
+		return "tx hard reset";
+	case SCU_EVENT_HARD_RESET_RECEIVED:
+		return "rx hard reset";
+	case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT:
+		return "identify timeout";
+	case SCU_EVENT_LINK_FAILURE:
+		return "link fail";
+	case SCU_EVENT_SATA_SPINUP_HOLD:
+		return "sata spinup hold";
+	case SCU_EVENT_SAS_15_SSC:
+	case SCU_EVENT_SAS_15:
+		return "sas 1.5";
+	case SCU_EVENT_SAS_30_SSC:
+	case SCU_EVENT_SAS_30:
+		return "sas 3.0";
+	case SCU_EVENT_SAS_60_SSC:
+	case SCU_EVENT_SAS_60:
+		return "sas 6.0";
+	case SCU_EVENT_SATA_15_SSC:
+	case SCU_EVENT_SATA_15:
+		return "sata 1.5";
+	case SCU_EVENT_SATA_30_SSC:
+	case SCU_EVENT_SATA_30:
+		return "sata 3.0";
+	case SCU_EVENT_SATA_60_SSC:
+	case SCU_EVENT_SATA_60:
+		return "sata 6.0";
+	case SCU_EVENT_SAS_PHY_DETECTED:
+		return "sas detect";
+	case SCU_EVENT_SATA_PHY_DETECTED:
+		return "sata detect";
+	default:
+		return "unknown";
+	}
+}
+
+#define phy_event_dbg(iphy, state, code) \
+	dev_dbg(sciphy_to_dev(iphy), "phy-%d:%d: %s event: %s (%x)\n", \
+		phy_to_host(iphy)->id, iphy->phy_index, \
+		phy_state_name(state), phy_event_name(code), code)
+
+#define phy_event_warn(iphy, state, code) \
+	dev_warn(sciphy_to_dev(iphy), "phy-%d:%d: %s event: %s (%x)\n", \
+		phy_to_host(iphy)->id, iphy->phy_index, \
+		phy_state_name(state), phy_event_name(code), code)
+
 enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
 {
 	enum sci_phy_states state = iphy->sm.current_state_id;
@@ -607,11 +684,7 @@
 			iphy->is_in_link_training = true;
 			break;
 		default:
-			dev_dbg(sciphy_to_dev(iphy),
-				"%s: PHY starting substate machine received "
-				"unexpected event_code %x\n",
-				__func__,
-				event_code);
+			phy_event_dbg(iphy, state, event_code);
 			return SCI_FAILURE;
 		}
 		return SCI_SUCCESS;
@@ -648,11 +721,7 @@
 			sci_change_state(&iphy->sm, SCI_PHY_STARTING);
 			break;
 		default:
-			dev_warn(sciphy_to_dev(iphy),
-				 "%s: PHY starting substate machine received "
-				 "unexpected event_code %x\n",
-				 __func__, event_code);
-
+			phy_event_warn(iphy, state, event_code);
 			return SCI_FAILURE;
 			break;
 		}
@@ -677,10 +746,7 @@
 			sci_change_state(&iphy->sm, SCI_PHY_STARTING);
 			break;
 		default:
-			dev_warn(sciphy_to_dev(iphy),
-				 "%s: PHY starting substate machine received "
-				 "unexpected event_code %x\n",
-				 __func__, event_code);
+			phy_event_warn(iphy, state, event_code);
 			return SCI_FAILURE;
 		}
 		return SCI_SUCCESS;
@@ -691,11 +757,7 @@
 			sci_change_state(&iphy->sm, SCI_PHY_STARTING);
 			break;
 		default:
-			dev_warn(sciphy_to_dev(iphy),
-				"%s: PHY starting substate machine received unexpected "
-				"event_code %x\n",
-				__func__,
-				event_code);
+			phy_event_warn(iphy, state, event_code);
 			return SCI_FAILURE;
 		}
 		return SCI_SUCCESS;
@@ -719,11 +781,7 @@
 			break;
 
 		default:
-			dev_warn(sciphy_to_dev(iphy),
-				 "%s: PHY starting substate machine received "
-				 "unexpected event_code %x\n",
-				 __func__, event_code);
-
+			phy_event_warn(iphy, state, event_code);
 			return SCI_FAILURE;
 		}
 		return SCI_SUCCESS;
@@ -751,12 +809,7 @@
 			sci_phy_start_sas_link_training(iphy);
 			break;
 		default:
-			dev_warn(sciphy_to_dev(iphy),
-				 "%s: PHY starting substate machine received "
-				 "unexpected event_code %x\n",
-				 __func__,
-				 event_code);
-
+			phy_event_warn(iphy, state, event_code);
 			return SCI_FAILURE;
 		}
 		return SCI_SUCCESS;
@@ -793,11 +846,7 @@
 			sci_phy_start_sas_link_training(iphy);
 			break;
 		default:
-			dev_warn(sciphy_to_dev(iphy),
-				 "%s: PHY starting substate machine received "
-				 "unexpected event_code %x\n",
-				 __func__, event_code);
-
+			phy_event_warn(iphy, state, event_code);
 			return SCI_FAILURE;
 		}
 
@@ -815,12 +864,7 @@
 			break;
 
 		default:
-			dev_warn(sciphy_to_dev(iphy),
-				 "%s: PHY starting substate machine received "
-				 "unexpected event_code %x\n",
-				 __func__,
-				 event_code);
-
+			phy_event_warn(iphy, state, event_code);
 			return SCI_FAILURE;
 		}
 		return SCI_SUCCESS;
@@ -838,10 +882,7 @@
 				iphy->bcn_received_while_port_unassigned = true;
 			break;
 		default:
-			dev_warn(sciphy_to_dev(iphy),
-				 "%sP SCIC PHY 0x%p ready state machine received "
-				 "unexpected event_code %x\n",
-				 __func__, iphy, event_code);
+			phy_event_warn(iphy, state, event_code);
 			return SCI_FAILURE_INVALID_STATE;
 		}
 		return SCI_SUCCESS;
@@ -852,18 +893,14 @@
 			sci_change_state(&iphy->sm, SCI_PHY_STARTING);
 			break;
 		default:
-			dev_warn(sciphy_to_dev(iphy),
-				 "%s: SCIC PHY 0x%p resetting state machine received "
-				 "unexpected event_code %x\n",
-				 __func__, iphy, event_code);
-
+			phy_event_warn(iphy, state, event_code);
 			return SCI_FAILURE_INVALID_STATE;
 			break;
 		}
 		return SCI_SUCCESS;
 	default:
-		dev_dbg(sciphy_to_dev(iphy),
-			"%s: in wrong state: %d\n", __func__, state);
+		dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n",
+			__func__, phy_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 }
@@ -956,8 +993,8 @@
 		return result;
 	}
 	default:
-		dev_dbg(sciphy_to_dev(iphy),
-			"%s: in wrong state: %d\n", __func__, state);
+		dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n",
+			__func__, phy_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -1299,7 +1336,6 @@
 	sas_addr = cpu_to_be64(sci_sas_addr);
 	memcpy(iphy->sas_addr, &sas_addr, sizeof(sas_addr));
 
-	iphy->isci_port = NULL;
 	iphy->sas_phy.enabled = 0;
 	iphy->sas_phy.id = index;
 	iphy->sas_phy.sas_addr = &iphy->sas_addr[0];
@@ -1333,13 +1369,13 @@
 {
 	int ret = 0;
 	struct isci_phy *iphy = sas_phy->lldd_phy;
-	struct isci_port *iport = iphy->isci_port;
+	struct asd_sas_port *port = sas_phy->port;
 	struct isci_host *ihost = sas_phy->ha->lldd_ha;
 	unsigned long flags;
 
 	dev_dbg(&ihost->pdev->dev,
 		"%s: phy %p; func %d; buf %p; isci phy %p, port %p\n",
-		__func__, sas_phy, func, buf, iphy, iport);
+		__func__, sas_phy, func, buf, iphy, port);
 
 	switch (func) {
 	case PHY_FUNC_DISABLE:
@@ -1356,11 +1392,10 @@
 		break;
 
 	case PHY_FUNC_HARD_RESET:
-		if (!iport)
+		if (!port)
 			return -ENODEV;
 
-		/* Perform the port reset. */
-		ret = isci_port_perform_hard_reset(ihost, iport, iphy);
+		ret = isci_port_perform_hard_reset(ihost, port->lldd_port, iphy);
 
 		break;
 	case PHY_FUNC_GET_EVENTS: {
diff --git a/drivers/scsi/isci/phy.h b/drivers/scsi/isci/phy.h
index 67699c8..0e45833 100644
--- a/drivers/scsi/isci/phy.h
+++ b/drivers/scsi/isci/phy.h
@@ -103,7 +103,6 @@
 	struct scu_transport_layer_registers __iomem *transport_layer_registers;
 	struct scu_link_layer_registers __iomem *link_layer_registers;
 	struct asd_sas_phy sas_phy;
-	struct isci_port *isci_port;
 	u8 sas_addr[SAS_ADDR_SIZE];
 	union {
 		struct sas_identify_frame iaf;
@@ -344,101 +343,65 @@
 	SCIC_PHY_COUNTER_SN_DWORD_SYNC_ERROR
 };
 
-enum sci_phy_states {
-	/**
-	 * Simply the initial state for the base domain state machine.
-	 */
-	SCI_PHY_INITIAL,
-
-	/**
-	 * This state indicates that the phy has successfully been stopped.
-	 * In this state no new IO operations are permitted on this phy.
-	 * This state is entered from the INITIAL state.
-	 * This state is entered from the STARTING state.
-	 * This state is entered from the READY state.
-	 * This state is entered from the RESETTING state.
-	 */
-	SCI_PHY_STOPPED,
-
-	/**
-	 * This state indicates that the phy is in the process of becomming
-	 * ready.  In this state no new IO operations are permitted on this phy.
-	 * This state is entered from the STOPPED state.
-	 * This state is entered from the READY state.
-	 * This state is entered from the RESETTING state.
-	 */
-	SCI_PHY_STARTING,
-
-	/**
-	 * Initial state
-	 */
-	SCI_PHY_SUB_INITIAL,
-
-	/**
-	 * Wait state for the hardware OSSP event type notification
-	 */
-	SCI_PHY_SUB_AWAIT_OSSP_EN,
-
-	/**
-	 * Wait state for the PHY speed notification
-	 */
-	SCI_PHY_SUB_AWAIT_SAS_SPEED_EN,
-
-	/**
-	 * Wait state for the IAF Unsolicited frame notification
-	 */
-	SCI_PHY_SUB_AWAIT_IAF_UF,
-
-	/**
-	 * Wait state for the request to consume power
-	 */
-	SCI_PHY_SUB_AWAIT_SAS_POWER,
-
-	/**
-	 * Wait state for request to consume power
-	 */
-	SCI_PHY_SUB_AWAIT_SATA_POWER,
-
-	/**
-	 * Wait state for the SATA PHY notification
-	 */
-	SCI_PHY_SUB_AWAIT_SATA_PHY_EN,
-
-	/**
-	 * Wait for the SATA PHY speed notification
-	 */
-	SCI_PHY_SUB_AWAIT_SATA_SPEED_EN,
-
-	/**
-	 * Wait state for the SIGNATURE FIS unsolicited frame notification
-	 */
-	SCI_PHY_SUB_AWAIT_SIG_FIS_UF,
-
-	/**
-	 * Exit state for this state machine
-	 */
-	SCI_PHY_SUB_FINAL,
-
-	/**
-	 * This state indicates the the phy is now ready.  Thus, the user
-	 * is able to perform IO operations utilizing this phy as long as it
-	 * is currently part of a valid port.
-	 * This state is entered from the STARTING state.
-	 */
-	SCI_PHY_READY,
-
-	/**
-	 * This state indicates that the phy is in the process of being reset.
-	 * In this state no new IO operations are permitted on this phy.
-	 * This state is entered from the READY state.
-	 */
-	SCI_PHY_RESETTING,
-
-	/**
-	 * Simply the final state for the base phy state machine.
-	 */
-	SCI_PHY_FINAL,
-};
+/**
+ * enum sci_phy_states - phy state machine states
+ * @SCI_PHY_INITIAL: Simply the initial state for the base domain state
+ *		     machine.
+ * @SCI_PHY_STOPPED: phy has successfully been stopped.  In this state
+ *		     no new IO operations are permitted on this phy.
+ * @SCI_PHY_STARTING: the phy is in the process of becomming ready.  In
+ *		      this state no new IO operations are permitted on
+ *		      this phy.
+ * @SCI_PHY_SUB_INITIAL: Initial state
+ * @SCI_PHY_SUB_AWAIT_OSSP_EN: Wait state for the hardware OSSP event
+ *			       type notification
+ * @SCI_PHY_SUB_AWAIT_SAS_SPEED_EN: Wait state for the PHY speed
+ *				    notification
+ * @SCI_PHY_SUB_AWAIT_IAF_UF: Wait state for the IAF Unsolicited frame
+ *			      notification
+ * @SCI_PHY_SUB_AWAIT_SAS_POWER: Wait state for the request to consume
+ *				 power
+ * @SCI_PHY_SUB_AWAIT_SATA_POWER: Wait state for request to consume
+ *				  power
+ * @SCI_PHY_SUB_AWAIT_SATA_PHY_EN: Wait state for the SATA PHY
+ *				   notification
+ * @SCI_PHY_SUB_AWAIT_SATA_SPEED_EN: Wait for the SATA PHY speed
+ *				     notification
+ * @SCI_PHY_SUB_AWAIT_SIG_FIS_UF: Wait state for the SIGNATURE FIS
+ *				  unsolicited frame notification
+ * @SCI_PHY_SUB_FINAL: Exit state for this state machine
+ * @SCI_PHY_READY: phy is now ready.  Thus, the user is able to perform
+ *		   IO operations utilizing this phy as long as it is
+ *		   currently part of a valid port.  This state is
+ *		   entered from the STARTING state.
+ * @SCI_PHY_RESETTING: phy is in the process of being reset.  In this
+ *		       state no new IO operations are permitted on this
+ *		       phy.  This state is entered from the READY state.
+ * @SCI_PHY_FINAL: Simply the final state for the base phy state
+ *		   machine.
+ */
+#define PHY_STATES {\
+	C(PHY_INITIAL),\
+	C(PHY_STOPPED),\
+	C(PHY_STARTING),\
+	C(PHY_SUB_INITIAL),\
+	C(PHY_SUB_AWAIT_OSSP_EN),\
+	C(PHY_SUB_AWAIT_SAS_SPEED_EN),\
+	C(PHY_SUB_AWAIT_IAF_UF),\
+	C(PHY_SUB_AWAIT_SAS_POWER),\
+	C(PHY_SUB_AWAIT_SATA_POWER),\
+	C(PHY_SUB_AWAIT_SATA_PHY_EN),\
+	C(PHY_SUB_AWAIT_SATA_SPEED_EN),\
+	C(PHY_SUB_AWAIT_SIG_FIS_UF),\
+	C(PHY_SUB_FINAL),\
+	C(PHY_READY),\
+	C(PHY_RESETTING),\
+	C(PHY_FINAL),\
+	}
+#undef C
+#define C(a) SCI_##a
+enum sci_phy_states PHY_STATES;
+#undef C
 
 void sci_phy_construct(
 	struct isci_phy *iphy,
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
index 7c6ac58..5fada73 100644
--- a/drivers/scsi/isci/port.c
+++ b/drivers/scsi/isci/port.c
@@ -60,18 +60,29 @@
 #define SCIC_SDS_PORT_HARD_RESET_TIMEOUT  (1000)
 #define SCU_DUMMY_INDEX    (0xFFFF)
 
-static void isci_port_change_state(struct isci_port *iport, enum isci_status status)
+#undef C
+#define C(a) (#a)
+const char *port_state_name(enum sci_port_states state)
 {
-	unsigned long flags;
+	static const char * const strings[] = PORT_STATES;
 
-	dev_dbg(&iport->isci_host->pdev->dev,
-		"%s: iport = %p, state = 0x%x\n",
-		__func__, iport, status);
+	return strings[state];
+}
+#undef C
 
-	/* XXX pointless lock */
-	spin_lock_irqsave(&iport->state_lock, flags);
-	iport->status = status;
-	spin_unlock_irqrestore(&iport->state_lock, flags);
+static struct device *sciport_to_dev(struct isci_port *iport)
+{
+	int i = iport->physical_port_index;
+	struct isci_port *table;
+	struct isci_host *ihost;
+
+	if (i == SCIC_SDS_DUMMY_PORT)
+		i = SCI_MAX_PORTS+1;
+
+	table = iport - i;
+	ihost = container_of(table, typeof(*ihost), ports[0]);
+
+	return &ihost->pdev->dev;
 }
 
 static void sci_port_get_protocols(struct isci_port *iport, struct sci_phy_proto *proto)
@@ -165,18 +176,12 @@
 	struct sci_port_properties properties;
 	unsigned long success = true;
 
-	BUG_ON(iphy->isci_port != NULL);
-
-	iphy->isci_port = iport;
-
 	dev_dbg(&isci_host->pdev->dev,
 		"%s: isci_port = %p\n",
 		__func__, iport);
 
 	spin_lock_irqsave(&iphy->sas_phy.frame_rcvd_lock, flags);
 
-	isci_port_change_state(iphy->isci_port, isci_starting);
-
 	sci_port_get_properties(iport, &properties);
 
 	if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) {
@@ -258,7 +263,6 @@
 					__func__, isci_device);
 				set_bit(IDEV_GONE, &isci_device->flags);
 			}
-			isci_port_change_state(isci_port, isci_stopping);
 		}
 	}
 
@@ -269,52 +273,10 @@
 	isci_host->sas_ha.notify_phy_event(&isci_phy->sas_phy,
 					   PHYE_LOSS_OF_SIGNAL);
 
-	isci_phy->isci_port = NULL;
-
 	dev_dbg(&isci_host->pdev->dev,
 		"%s: isci_port = %p - Done\n", __func__, isci_port);
 }
 
-
-/**
- * isci_port_ready() - This function is called by the sci core when a link
- *    becomes ready.
- * @isci_host: This parameter specifies the isci host object.
- * @port: This parameter specifies the sci port with the active link.
- *
- */
-static void isci_port_ready(struct isci_host *isci_host, struct isci_port *isci_port)
-{
-	dev_dbg(&isci_host->pdev->dev,
-		"%s: isci_port = %p\n", __func__, isci_port);
-
-	complete_all(&isci_port->start_complete);
-	isci_port_change_state(isci_port, isci_ready);
-	return;
-}
-
-/**
- * isci_port_not_ready() - This function is called by the sci core when a link
- *    is not ready. All remote devices on this link will be removed if they are
- *    in the stopping state.
- * @isci_host: This parameter specifies the isci host object.
- * @port: This parameter specifies the sci port with the active link.
- *
- */
-static void isci_port_not_ready(struct isci_host *isci_host, struct isci_port *isci_port)
-{
-	dev_dbg(&isci_host->pdev->dev,
-		"%s: isci_port = %p\n", __func__, isci_port);
-}
-
-static void isci_port_stop_complete(struct isci_host *ihost,
-				    struct isci_port *iport,
-				    enum sci_status completion_status)
-{
-	dev_dbg(&ihost->pdev->dev, "Port stop complete\n");
-}
-
-
 static bool is_port_ready_state(enum sci_port_states state)
 {
 	switch (state) {
@@ -353,7 +315,9 @@
 static void isci_port_hard_reset_complete(struct isci_port *isci_port,
 					  enum sci_status completion_status)
 {
-	dev_dbg(&isci_port->isci_host->pdev->dev,
+	struct isci_host *ihost = isci_port->owning_controller;
+
+	dev_dbg(&ihost->pdev->dev,
 		"%s: isci_port = %p, completion_status=%x\n",
 		     __func__, isci_port, completion_status);
 
@@ -364,23 +328,24 @@
 
 		/* The reset failed.  The port state is now SCI_PORT_FAILED. */
 		if (isci_port->active_phy_mask == 0) {
+			int phy_idx = isci_port->last_active_phy;
+			struct isci_phy *iphy = &ihost->phys[phy_idx];
 
 			/* Generate the link down now to the host, since it
 			 * was intercepted by the hard reset state machine when
 			 * it really happened.
 			 */
-			isci_port_link_down(isci_port->isci_host,
-					    &isci_port->isci_host->phys[
-						   isci_port->last_active_phy],
-					    isci_port);
+			isci_port_link_down(ihost, iphy, isci_port);
 		}
 		/* Advance the port state so that link state changes will be
-		* noticed.
-		*/
+		 * noticed.
+		 */
 		port_state_machine_change(isci_port, SCI_PORT_SUB_WAITING);
 
 	}
-	complete_all(&isci_port->hard_reset_complete);
+	clear_bit(IPORT_RESET_PENDING, &isci_port->state);
+	wake_up(&ihost->eventq);
+
 }
 
 /* This method will return a true value if the specified phy can be assigned to
@@ -835,10 +800,9 @@
 			__func__,
 			iport);
 	} else if (current_state == SCI_PORT_STOPPING) {
-		/* if the port is still stopping then the stop has not completed */
-		isci_port_stop_complete(iport->owning_controller,
-					iport,
-					SCI_FAILURE_TIMEOUT);
+		dev_dbg(sciport_to_dev(iport),
+			"%s: port%d: stop complete timeout\n",
+			__func__, iport->physical_port_index);
 	} else {
 		/* The port is in the ready state and we have a timer
 		 * reporting a timeout this should not happen.
@@ -1003,7 +967,8 @@
 	struct isci_port *iport = container_of(sm, typeof(*iport), sm);
 	struct isci_host *ihost = iport->owning_controller;
 
-	isci_port_ready(ihost, iport);
+	dev_dbg(&ihost->pdev->dev, "%s: port%d ready\n",
+		__func__, iport->physical_port_index);
 
 	for (index = 0; index < SCI_MAX_PHYS; index++) {
 		if (iport->phy_table[index]) {
@@ -1069,7 +1034,8 @@
 	 */
 	sci_port_abort_dummy_request(iport);
 
-	isci_port_not_ready(ihost, iport);
+	dev_dbg(&ihost->pdev->dev, "%s: port%d !ready\n",
+		__func__, iport->physical_port_index);
 
 	if (iport->ready_exit)
 		sci_port_invalidate_dummy_remote_node(iport);
@@ -1081,7 +1047,8 @@
 	struct isci_host *ihost = iport->owning_controller;
 
 	if (iport->active_phy_mask == 0) {
-		isci_port_not_ready(ihost, iport);
+		dev_dbg(&ihost->pdev->dev, "%s: port%d !ready\n",
+			__func__, iport->physical_port_index);
 
 		port_state_machine_change(iport, SCI_PORT_SUB_WAITING);
 	} else
@@ -1097,8 +1064,8 @@
 
 	state = iport->sm.current_state_id;
 	if (state != SCI_PORT_STOPPED) {
-		dev_warn(sciport_to_dev(iport),
-			 "%s: in wrong state: %d\n", __func__, state);
+		dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
+			 __func__, port_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -1172,8 +1139,8 @@
 					  SCI_PORT_STOPPING);
 		return SCI_SUCCESS;
 	default:
-		dev_warn(sciport_to_dev(iport),
-			 "%s: in wrong state: %d\n", __func__, state);
+		dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
+			 __func__, port_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 }
@@ -1187,8 +1154,8 @@
 
 	state = iport->sm.current_state_id;
 	if (state != SCI_PORT_SUB_OPERATIONAL) {
-		dev_warn(sciport_to_dev(iport),
-			 "%s: in wrong state: %d\n", __func__, state);
+		dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
+			 __func__, port_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -1282,8 +1249,8 @@
 					  SCI_PORT_SUB_CONFIGURING);
 		return SCI_SUCCESS;
 	default:
-		dev_warn(sciport_to_dev(iport),
-			 "%s: in wrong state: %d\n", __func__, state);
+		dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
+			 __func__, port_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 }
@@ -1332,8 +1299,8 @@
 					  SCI_PORT_SUB_CONFIGURING);
 		return SCI_SUCCESS;
 	default:
-		dev_warn(sciport_to_dev(iport),
-			 "%s: in wrong state: %d\n", __func__, state);
+		dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
+			 __func__, port_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 }
@@ -1375,8 +1342,8 @@
 		sci_port_general_link_up_handler(iport, iphy, PF_RESUME);
 		return SCI_SUCCESS;
 	default:
-		dev_warn(sciport_to_dev(iport),
-			 "%s: in wrong state: %d\n", __func__, state);
+		dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
+			 __func__, port_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 }
@@ -1405,8 +1372,8 @@
 		sci_port_deactivate_phy(iport, iphy, false);
 		return SCI_SUCCESS;
 	default:
-		dev_warn(sciport_to_dev(iport),
-			 "%s: in wrong state: %d\n", __func__, state);
+		dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
+			 __func__, port_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 }
@@ -1425,8 +1392,8 @@
 		iport->started_request_count++;
 		return SCI_SUCCESS;
 	default:
-		dev_warn(sciport_to_dev(iport),
-			 "%s: in wrong state: %d\n", __func__, state);
+		dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
+			 __func__, port_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 }
@@ -1440,8 +1407,8 @@
 	state = iport->sm.current_state_id;
 	switch (state) {
 	case SCI_PORT_STOPPED:
-		dev_warn(sciport_to_dev(iport),
-			 "%s: in wrong state: %d\n", __func__, state);
+		dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
+			 __func__, port_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	case SCI_PORT_STOPPING:
 		sci_port_decrement_request_count(iport);
@@ -1547,7 +1514,8 @@
 	if (prev_state  == SCI_PORT_RESETTING)
 		isci_port_hard_reset_complete(iport, SCI_SUCCESS);
 	else
-		isci_port_not_ready(ihost, iport);
+		dev_dbg(&ihost->pdev->dev, "%s: port%d !ready\n",
+			__func__, iport->physical_port_index);
 
 	/* Post and suspend the dummy remote node context for this port. */
 	sci_port_post_dummy_remote_node(iport);
@@ -1644,22 +1612,7 @@
 {
 	INIT_LIST_HEAD(&iport->remote_dev_list);
 	INIT_LIST_HEAD(&iport->domain_dev_list);
-	spin_lock_init(&iport->state_lock);
-	init_completion(&iport->start_complete);
 	iport->isci_host = ihost;
-	isci_port_change_state(iport, isci_freed);
-}
-
-/**
- * isci_port_get_state() - This function gets the status of the port object.
- * @isci_port: This parameter points to the isci_port object
- *
- * status of the object as a isci_status enum.
- */
-enum isci_status isci_port_get_state(
-	struct isci_port *isci_port)
-{
-	return isci_port->status;
 }
 
 void sci_port_broadcast_change_received(struct isci_port *iport, struct isci_phy *iphy)
@@ -1670,6 +1623,11 @@
 	isci_port_bc_change_received(ihost, iport, iphy);
 }
 
+static void wait_port_reset(struct isci_host *ihost, struct isci_port *iport)
+{
+	wait_event(ihost->eventq, !test_bit(IPORT_RESET_PENDING, &iport->state));
+}
+
 int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport,
 				 struct isci_phy *iphy)
 {
@@ -1680,9 +1638,8 @@
 	dev_dbg(&ihost->pdev->dev, "%s: iport = %p\n",
 		__func__, iport);
 
-	init_completion(&iport->hard_reset_complete);
-
 	spin_lock_irqsave(&ihost->scic_lock, flags);
+	set_bit(IPORT_RESET_PENDING, &iport->state);
 
 	#define ISCI_PORT_RESET_TIMEOUT SCIC_SDS_SIGNATURE_FIS_TIMEOUT
 	status = sci_port_hard_reset(iport, ISCI_PORT_RESET_TIMEOUT);
@@ -1690,7 +1647,7 @@
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
 	if (status == SCI_SUCCESS) {
-		wait_for_completion(&iport->hard_reset_complete);
+		wait_port_reset(ihost, iport);
 
 		dev_dbg(&ihost->pdev->dev,
 			"%s: iport = %p; hard reset completion\n",
@@ -1704,6 +1661,8 @@
 				__func__, iport, iport->hard_reset_status);
 		}
 	} else {
+		clear_bit(IPORT_RESET_PENDING, &iport->state);
+		wake_up(&ihost->eventq);
 		ret = TMF_RESP_FUNC_FAILED;
 
 		dev_err(&ihost->pdev->dev,
@@ -1726,24 +1685,80 @@
 	return ret;
 }
 
-/**
- * isci_port_deformed() - This function is called by libsas when a port becomes
- *    inactive.
- * @phy: This parameter specifies the libsas phy with the inactive port.
- *
- */
-void isci_port_deformed(struct asd_sas_phy *phy)
+int isci_ata_check_ready(struct domain_device *dev)
 {
-	pr_debug("%s: sas_phy = %p\n", __func__, phy);
+	struct isci_port *iport = dev->port->lldd_port;
+	struct isci_host *ihost = dev_to_ihost(dev);
+	struct isci_remote_device *idev;
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&ihost->scic_lock, flags);
+	idev = isci_lookup_device(dev);
+	spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+	if (!idev)
+		goto out;
+
+	if (test_bit(IPORT_RESET_PENDING, &iport->state))
+		goto out;
+
+	rc = !!iport->active_phy_mask;
+ out:
+	isci_put_device(idev);
+
+	return rc;
 }
 
-/**
- * isci_port_formed() - This function is called by libsas when a port becomes
- *    active.
- * @phy: This parameter specifies the libsas phy with the active port.
- *
- */
+void isci_port_deformed(struct asd_sas_phy *phy)
+{
+	struct isci_host *ihost = phy->ha->lldd_ha;
+	struct isci_port *iport = phy->port->lldd_port;
+	unsigned long flags;
+	int i;
+
+	/* we got a port notification on a port that was subsequently
+	 * torn down and libsas is just now catching up
+	 */
+	if (!iport)
+		return;
+
+	spin_lock_irqsave(&ihost->scic_lock, flags);
+	for (i = 0; i < SCI_MAX_PHYS; i++) {
+		if (iport->active_phy_mask & 1 << i)
+			break;
+	}
+	spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+	if (i >= SCI_MAX_PHYS)
+		dev_dbg(&ihost->pdev->dev, "%s: port: %ld\n",
+			__func__, (long) (iport - &ihost->ports[0]));
+}
+
 void isci_port_formed(struct asd_sas_phy *phy)
 {
-	pr_debug("%s: sas_phy = %p, sas_port = %p\n", __func__, phy, phy->port);
+	struct isci_host *ihost = phy->ha->lldd_ha;
+	struct isci_phy *iphy = to_iphy(phy);
+	struct asd_sas_port *port = phy->port;
+	struct isci_port *iport;
+	unsigned long flags;
+	int i;
+
+	/* initial ports are formed as the driver is still initializing,
+	 * wait for that process to complete
+	 */
+	wait_for_start(ihost);
+
+	spin_lock_irqsave(&ihost->scic_lock, flags);
+	for (i = 0; i < SCI_MAX_PORTS; i++) {
+		iport = &ihost->ports[i];
+		if (iport->active_phy_mask & 1 << iphy->phy_index)
+			break;
+	}
+	spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+	if (i >= SCI_MAX_PORTS)
+		iport = NULL;
+
+	port->lldd_port = iport;
 }
diff --git a/drivers/scsi/isci/port.h b/drivers/scsi/isci/port.h
index 0811609..6b56240 100644
--- a/drivers/scsi/isci/port.h
+++ b/drivers/scsi/isci/port.h
@@ -95,14 +95,11 @@
  * @timer: timeout start/stop operations
  */
 struct isci_port {
-	enum isci_status status;
 	struct isci_host *isci_host;
-	struct asd_sas_port sas_port;
 	struct list_head remote_dev_list;
-	spinlock_t state_lock;
 	struct list_head domain_dev_list;
-	struct completion start_complete;
-	struct completion hard_reset_complete;
+	#define IPORT_RESET_PENDING 0
+	unsigned long state;
 	enum sci_status hard_reset_status;
 	struct sci_base_state_machine sm;
 	bool ready_exit;
@@ -147,70 +144,47 @@
 };
 
 /**
- * enum sci_port_states - This enumeration depicts all the states for the
- *    common port state machine.
- *
- *
+ * enum sci_port_states - port state machine states
+ * @SCI_PORT_STOPPED: port has successfully been stopped.  In this state
+ *		      no new IO operations are permitted.  This state is
+ *		      entered from the STOPPING state.
+ * @SCI_PORT_STOPPING: port is in the process of stopping.  In this
+ *		       state no new IO operations are permitted, but
+ *		       existing IO operations are allowed to complete.
+ *		       This state is entered from the READY state.
+ * @SCI_PORT_READY: port is now ready.  Thus, the user is able to
+ *		    perform IO operations on this port. This state is
+ *		    entered from the STARTING state.
+ * @SCI_PORT_SUB_WAITING: port is started and ready but has no active
+ *			  phys.
+ * @SCI_PORT_SUB_OPERATIONAL: port is started and ready and there is at
+ *			      least one phy operational.
+ * @SCI_PORT_SUB_CONFIGURING: port is started and there was an
+ *			      add/remove phy event.  This state is only
+ *			      used in Automatic Port Configuration Mode
+ *			      (APC)
+ * @SCI_PORT_RESETTING: port is in the process of performing a hard
+ *			reset.  Thus, the user is unable to perform IO
+ *			operations on this port.  This state is entered
+ *			from the READY state.
+ * @SCI_PORT_FAILED: port has failed a reset request.  This state is
+ *		     entered when a port reset request times out. This
+ *		     state is entered from the RESETTING state.
  */
-enum sci_port_states {
-	/**
-	 * This state indicates that the port has successfully been stopped.
-	 * In this state no new IO operations are permitted.
-	 * This state is entered from the STOPPING state.
-	 */
-	SCI_PORT_STOPPED,
-
-	/**
-	 * This state indicates that the port is in the process of stopping.
-	 * In this state no new IO operations are permitted, but existing IO
-	 * operations are allowed to complete.
-	 * This state is entered from the READY state.
-	 */
-	SCI_PORT_STOPPING,
-
-	/**
-	 * This state indicates the port is now ready.  Thus, the user is
-	 * able to perform IO operations on this port.
-	 * This state is entered from the STARTING state.
-	 */
-	SCI_PORT_READY,
-
-	/**
-	 * The substate where the port is started and ready but has no
-	 * active phys.
-	 */
-	SCI_PORT_SUB_WAITING,
-
-	/**
-	 * The substate where the port is started and ready and there is
-	 * at least one phy operational.
-	 */
-	SCI_PORT_SUB_OPERATIONAL,
-
-	/**
-	 * The substate where the port is started and there was an
-	 * add/remove phy event.  This state is only used in Automatic
-	 * Port Configuration Mode (APC)
-	 */
-	SCI_PORT_SUB_CONFIGURING,
-
-	/**
-	 * This state indicates the port is in the process of performing a hard
-	 * reset.  Thus, the user is unable to perform IO operations on this
-	 * port.
-	 * This state is entered from the READY state.
-	 */
-	SCI_PORT_RESETTING,
-
-	/**
-	 * This state indicates the port has failed a reset request.  This state
-	 * is entered when a port reset request times out.
-	 * This state is entered from the RESETTING state.
-	 */
-	SCI_PORT_FAILED,
-
-
-};
+#define PORT_STATES {\
+	C(PORT_STOPPED),\
+	C(PORT_STOPPING),\
+	C(PORT_READY),\
+	C(PORT_SUB_WAITING),\
+	C(PORT_SUB_OPERATIONAL),\
+	C(PORT_SUB_CONFIGURING),\
+	C(PORT_RESETTING),\
+	C(PORT_FAILED),\
+	}
+#undef C
+#define C(a) SCI_##a
+enum sci_port_states PORT_STATES;
+#undef C
 
 static inline void sci_port_decrement_request_count(struct isci_port *iport)
 {
@@ -296,9 +270,6 @@
 	struct isci_port *iport,
 	struct sci_sas_address *sas_address);
 
-enum isci_status isci_port_get_state(
-	struct isci_port *isci_port);
-
 void isci_port_formed(struct asd_sas_phy *);
 void isci_port_deformed(struct asd_sas_phy *);
 
@@ -309,4 +280,5 @@
 
 int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport,
 				 struct isci_phy *iphy);
+int isci_ata_check_ready(struct domain_device *dev);
 #endif /* !defined(_ISCI_PORT_H_) */
diff --git a/drivers/scsi/isci/registers.h b/drivers/scsi/isci/registers.h
index eaa541a..7eb0ccd 100644
--- a/drivers/scsi/isci/registers.h
+++ b/drivers/scsi/isci/registers.h
@@ -370,6 +370,27 @@
 		>> SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT \
 	)
 
+/* ***************************************************************************** */
+#define SMU_CLOCK_GATING_CONTROL_IDLE_ENABLE_SHIFT    (0)
+#define SMU_CLOCK_GATING_CONTROL_IDLE_ENABLE_MASK     (0x00000001)
+#define SMU_CLOCK_GATING_CONTROL_XCLK_ENABLE_SHIFT    (1)
+#define SMU_CLOCK_GATING_CONTROL_XCLK_ENABLE_MASK     (0x00000002)
+#define SMU_CLOCK_GATING_CONTROL_TXCLK_ENABLE_SHIFT   (2)
+#define SMU_CLOCK_GATING_CONTROL_TXCLK_ENABLE_MASK    (0x00000004)
+#define SMU_CLOCK_GATING_CONTROL_REGCLK_ENABLE_SHIFT  (3)
+#define SMU_CLOCK_GATING_CONTROL_REGCLK_ENABLE_MASK   (0x00000008)
+#define SMU_CLOCK_GATING_CONTROL_IDLE_TIMEOUT_SHIFT   (16)
+#define SMU_CLOCK_GATING_CONTROL_IDLE_TIMEOUT_MASK    (0x000F0000)
+#define SMU_CLOCK_GATING_CONTROL_FORCE_IDLE_SHIFT     (31)
+#define SMU_CLOCK_GATING_CONTROL_FORCE_IDLE_MASK      (0x80000000)
+#define SMU_CLOCK_GATING_CONTROL_RESERVED_MASK        (0x7FF0FFF0)
+
+#define SMU_CGUCR_GEN_VAL(name, value) \
+	SCU_GEN_VALUE(SMU_CLOCK_GATING_CONTROL_##name, value)
+
+#define SMU_CGUCR_GEN_BIT(name) \
+	SCU_GEN_BIT(SMU_CLOCK_GATING_CONTROL_##name)
+
 /* -------------------------------------------------------------------------- */
 
 #define SMU_CONTROL_STATUS_TASK_CONTEXT_RANGE_ENABLE_SHIFT      (0)
@@ -992,8 +1013,10 @@
 	u32 mmr_address_window;
 /* 0x00A4 SMDW */
 	u32 mmr_data_window;
-	u32 reserved_A8;
-	u32 reserved_AC;
+/* 0x00A8 CGUCR */
+	u32 clock_gating_control;
+/* 0x00AC CGUPC */
+	u32 clock_gating_performance;
 /* A whole bunch of reserved space */
 	u32 reserved_Bx[4];
 	u32 reserved_Cx[4];
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index dd74b6c..8f501b0 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -62,6 +62,16 @@
 #include "scu_event_codes.h"
 #include "task.h"
 
+#undef C
+#define C(a) (#a)
+const char *dev_state_name(enum sci_remote_device_states state)
+{
+	static const char * const strings[] = REMOTE_DEV_STATES;
+
+	return strings[state];
+}
+#undef C
+
 /**
  * isci_remote_device_not_ready() - This function is called by the ihost when
  *    the remote device is not ready. We mark the isci device as ready (not
@@ -167,8 +177,8 @@
 	case SCI_DEV_FAILED:
 	case SCI_DEV_FINAL:
 	default:
-		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
-			 __func__, state);
+		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
+			 __func__, dev_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	case SCI_DEV_STOPPED:
 		return SCI_SUCCESS;
@@ -226,8 +236,8 @@
 	case SCI_DEV_RESETTING:
 	case SCI_DEV_FINAL:
 	default:
-		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
-			 __func__, state);
+		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
+			 __func__, dev_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	case SCI_DEV_READY:
 	case SCI_STP_DEV_IDLE:
@@ -246,8 +256,8 @@
 	enum sci_remote_device_states state = sm->current_state_id;
 
 	if (state != SCI_DEV_RESETTING) {
-		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
-			 __func__, state);
+		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
+			 __func__, dev_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -262,8 +272,8 @@
 	enum sci_remote_device_states state = sm->current_state_id;
 
 	if (state != SCI_STP_DEV_CMD) {
-		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
-			 __func__, state);
+		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
+			 __func__, dev_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -287,8 +297,8 @@
 	case SCI_SMP_DEV_IDLE:
 	case SCI_DEV_FINAL:
 	default:
-		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
-			 __func__, state);
+		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
+			 __func__, dev_state_name(state));
 		/* Return the frame back to the controller */
 		sci_controller_release_frame(ihost, frame_index);
 		return SCI_FAILURE_INVALID_STATE;
@@ -502,8 +512,8 @@
 	case SCI_DEV_RESETTING:
 	case SCI_DEV_FINAL:
 	default:
-		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
-			 __func__, state);
+		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
+			 __func__, dev_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	case SCI_DEV_READY:
 		/* attempt to start an io request for this device object. The remote
@@ -637,8 +647,8 @@
 	case SCI_DEV_FAILED:
 	case SCI_DEV_FINAL:
 	default:
-		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
-			 __func__, state);
+		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
+			 __func__, dev_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	case SCI_DEV_READY:
 	case SCI_STP_DEV_AWAIT_RESET:
@@ -721,8 +731,8 @@
 	case SCI_DEV_RESETTING:
 	case SCI_DEV_FINAL:
 	default:
-		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
-			 __func__, state);
+		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
+			 __func__, dev_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	case SCI_STP_DEV_IDLE:
 	case SCI_STP_DEV_CMD:
@@ -853,8 +863,8 @@
 	struct isci_host *ihost;
 
 	if (state != SCI_DEV_STOPPED) {
-		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
-			 __func__, state);
+		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
+			 __func__, dev_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -1204,8 +1214,8 @@
 	enum sci_status status;
 
 	if (state != SCI_DEV_STOPPED) {
-		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
-			 __func__, state);
+		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
+			 __func__, dev_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -1308,7 +1318,6 @@
 	clear_bit(IDEV_STOP_PENDING, &idev->flags);
 	clear_bit(IDEV_IO_READY, &idev->flags);
 	clear_bit(IDEV_GONE, &idev->flags);
-	clear_bit(IDEV_EH, &idev->flags);
 	smp_mb__before_clear_bit();
 	clear_bit(IDEV_ALLOCATED, &idev->flags);
 	wake_up(&ihost->eventq);
@@ -1381,34 +1390,17 @@
  *
  * status, zero indicates success.
  */
-int isci_remote_device_found(struct domain_device *domain_dev)
+int isci_remote_device_found(struct domain_device *dev)
 {
-	struct isci_host *isci_host = dev_to_ihost(domain_dev);
-	struct isci_port *isci_port;
-	struct isci_phy *isci_phy;
-	struct asd_sas_port *sas_port;
-	struct asd_sas_phy *sas_phy;
+	struct isci_host *isci_host = dev_to_ihost(dev);
+	struct isci_port *isci_port = dev->port->lldd_port;
 	struct isci_remote_device *isci_device;
 	enum sci_status status;
 
 	dev_dbg(&isci_host->pdev->dev,
-		"%s: domain_device = %p\n", __func__, domain_dev);
+		"%s: domain_device = %p\n", __func__, dev);
 
-	wait_for_start(isci_host);
-
-	sas_port = domain_dev->port;
-	sas_phy = list_first_entry(&sas_port->phy_list, struct asd_sas_phy,
-				   port_phy_el);
-	isci_phy = to_iphy(sas_phy);
-	isci_port = isci_phy->isci_port;
-
-	/* we are being called for a device on this port,
-	 * so it has to come up eventually
-	 */
-	wait_for_completion(&isci_port->start_complete);
-
-	if ((isci_stopping == isci_port_get_state(isci_port)) ||
-	    (isci_stopped == isci_port_get_state(isci_port)))
+	if (!isci_port)
 		return -ENODEV;
 
 	isci_device = isci_remote_device_alloc(isci_host, isci_port);
@@ -1419,7 +1411,7 @@
 	INIT_LIST_HEAD(&isci_device->node);
 
 	spin_lock_irq(&isci_host->scic_lock);
-	isci_device->domain_dev = domain_dev;
+	isci_device->domain_dev = dev;
 	isci_device->isci_port = isci_port;
 	list_add_tail(&isci_device->node, &isci_port->remote_dev_list);
 
@@ -1432,7 +1424,7 @@
 
 	if (status == SCI_SUCCESS) {
 		/* device came up, advertise it to the world */
-		domain_dev->lldd_dev = isci_device;
+		dev->lldd_dev = isci_device;
 	} else
 		isci_put_device(isci_device);
 	spin_unlock_irq(&isci_host->scic_lock);
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index 483ee50..58637ee 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -82,10 +82,9 @@
 	#define IDEV_START_PENDING 0
 	#define IDEV_STOP_PENDING 1
 	#define IDEV_ALLOCATED 2
-	#define IDEV_EH 3
-	#define IDEV_GONE 4
-	#define IDEV_IO_READY 5
-	#define IDEV_IO_NCQERROR 6
+	#define IDEV_GONE 3
+	#define IDEV_IO_READY 4
+	#define IDEV_IO_NCQERROR 5
 	unsigned long flags;
 	struct kref kref;
 	struct isci_port *isci_port;
@@ -180,122 +179,101 @@
 /**
  * enum sci_remote_device_states - This enumeration depicts all the states
  *    for the common remote device state machine.
+ * @SCI_DEV_INITIAL: Simply the initial state for the base remote device
+ * state machine.
  *
+ * @SCI_DEV_STOPPED: This state indicates that the remote device has
+ * successfully been stopped.  In this state no new IO operations are
+ * permitted.  This state is entered from the INITIAL state.  This state
+ * is entered from the STOPPING state.
  *
+ * @SCI_DEV_STARTING: This state indicates the the remote device is in
+ * the process of becoming ready (i.e. starting).  In this state no new
+ * IO operations are permitted.  This state is entered from the STOPPED
+ * state.
+ *
+ * @SCI_DEV_READY: This state indicates the remote device is now ready.
+ * Thus, the user is able to perform IO operations on the remote device.
+ * This state is entered from the STARTING state.
+ *
+ * @SCI_STP_DEV_IDLE: This is the idle substate for the stp remote
+ * device.  When there are no active IO for the device it is is in this
+ * state.
+ *
+ * @SCI_STP_DEV_CMD: This is the command state for for the STP remote
+ * device.  This state is entered when the device is processing a
+ * non-NCQ command.  The device object will fail any new start IO
+ * requests until this command is complete.
+ *
+ * @SCI_STP_DEV_NCQ: This is the NCQ state for the STP remote device.
+ * This state is entered when the device is processing an NCQ reuqest.
+ * It will remain in this state so long as there is one or more NCQ
+ * requests being processed.
+ *
+ * @SCI_STP_DEV_NCQ_ERROR: This is the NCQ error state for the STP
+ * remote device.  This state is entered when an SDB error FIS is
+ * received by the device object while in the NCQ state.  The device
+ * object will only accept a READ LOG command while in this state.
+ *
+ * @SCI_STP_DEV_ATAPI_ERROR: This is the ATAPI error state for the STP
+ * ATAPI remote device.  This state is entered when ATAPI device sends
+ * error status FIS without data while the device object is in CMD
+ * state.  A suspension event is expected in this state.  The device
+ * object will resume right away.
+ *
+ * @SCI_STP_DEV_AWAIT_RESET: This is the READY substate indicates the
+ * device is waiting for the RESET task coming to be recovered from
+ * certain hardware specific error.
+ *
+ * @SCI_SMP_DEV_IDLE: This is the ready operational substate for the
+ * remote device.  This is the normal operational state for a remote
+ * device.
+ *
+ * @SCI_SMP_DEV_CMD: This is the suspended state for the remote device.
+ * This is the state that the device is placed in when a RNC suspend is
+ * received by the SCU hardware.
+ *
+ * @SCI_DEV_STOPPING: This state indicates that the remote device is in
+ * the process of stopping.  In this state no new IO operations are
+ * permitted, but existing IO operations are allowed to complete.  This
+ * state is entered from the READY state.  This state is entered from
+ * the FAILED state.
+ *
+ * @SCI_DEV_FAILED: This state indicates that the remote device has
+ * failed.  In this state no new IO operations are permitted.  This
+ * state is entered from the INITIALIZING state.  This state is entered
+ * from the READY state.
+ *
+ * @SCI_DEV_RESETTING: This state indicates the device is being reset.
+ * In this state no new IO operations are permitted.  This state is
+ * entered from the READY state.
+ *
+ * @SCI_DEV_FINAL: Simply the final state for the base remote device
+ * state machine.
  */
-enum sci_remote_device_states {
-	/**
-	 * Simply the initial state for the base remote device state machine.
-	 */
-	SCI_DEV_INITIAL,
-
-	/**
-	 * This state indicates that the remote device has successfully been
-	 * stopped.  In this state no new IO operations are permitted.
-	 * This state is entered from the INITIAL state.
-	 * This state is entered from the STOPPING state.
-	 */
-	SCI_DEV_STOPPED,
-
-	/**
-	 * This state indicates the the remote device is in the process of
-	 * becoming ready (i.e. starting).  In this state no new IO operations
-	 * are permitted.
-	 * This state is entered from the STOPPED state.
-	 */
-	SCI_DEV_STARTING,
-
-	/**
-	 * This state indicates the remote device is now ready.  Thus, the user
-	 * is able to perform IO operations on the remote device.
-	 * This state is entered from the STARTING state.
-	 */
-	SCI_DEV_READY,
-
-	/**
-	 * This is the idle substate for the stp remote device.  When there are no
-	 * active IO for the device it is is in this state.
-	 */
-	SCI_STP_DEV_IDLE,
-
-	/**
-	 * This is the command state for for the STP remote device.  This state is
-	 * entered when the device is processing a non-NCQ command.  The device object
-	 * will fail any new start IO requests until this command is complete.
-	 */
-	SCI_STP_DEV_CMD,
-
-	/**
-	 * This is the NCQ state for the STP remote device.  This state is entered
-	 * when the device is processing an NCQ reuqest.  It will remain in this state
-	 * so long as there is one or more NCQ requests being processed.
-	 */
-	SCI_STP_DEV_NCQ,
-
-	/**
-	 * This is the NCQ error state for the STP remote device.  This state is
-	 * entered when an SDB error FIS is received by the device object while in the
-	 * NCQ state.  The device object will only accept a READ LOG command while in
-	 * this state.
-	 */
-	SCI_STP_DEV_NCQ_ERROR,
-
-	/**
-	 * This is the ATAPI error state for the STP ATAPI remote device.
-	 * This state is entered when ATAPI device sends error status FIS
-	 * without data while the device object is in CMD state.
-	 * A suspension event is expected in this state.
-	 * The device object will resume right away.
-	 */
-	SCI_STP_DEV_ATAPI_ERROR,
-
-	/**
-	 * This is the READY substate indicates the device is waiting for the RESET task
-	 * coming to be recovered from certain hardware specific error.
-	 */
-	SCI_STP_DEV_AWAIT_RESET,
-
-	/**
-	 * This is the ready operational substate for the remote device.  This is the
-	 * normal operational state for a remote device.
-	 */
-	SCI_SMP_DEV_IDLE,
-
-	/**
-	 * This is the suspended state for the remote device.  This is the state that
-	 * the device is placed in when a RNC suspend is received by the SCU hardware.
-	 */
-	SCI_SMP_DEV_CMD,
-
-	/**
-	 * This state indicates that the remote device is in the process of
-	 * stopping.  In this state no new IO operations are permitted, but
-	 * existing IO operations are allowed to complete.
-	 * This state is entered from the READY state.
-	 * This state is entered from the FAILED state.
-	 */
-	SCI_DEV_STOPPING,
-
-	/**
-	 * This state indicates that the remote device has failed.
-	 * In this state no new IO operations are permitted.
-	 * This state is entered from the INITIALIZING state.
-	 * This state is entered from the READY state.
-	 */
-	SCI_DEV_FAILED,
-
-	/**
-	 * This state indicates the device is being reset.
-	 * In this state no new IO operations are permitted.
-	 * This state is entered from the READY state.
-	 */
-	SCI_DEV_RESETTING,
-
-	/**
-	 * Simply the final state for the base remote device state machine.
-	 */
-	SCI_DEV_FINAL,
-};
+#define REMOTE_DEV_STATES {\
+	C(DEV_INITIAL),\
+	C(DEV_STOPPED),\
+	C(DEV_STARTING),\
+	C(DEV_READY),\
+	C(STP_DEV_IDLE),\
+	C(STP_DEV_CMD),\
+	C(STP_DEV_NCQ),\
+	C(STP_DEV_NCQ_ERROR),\
+	C(STP_DEV_ATAPI_ERROR),\
+	C(STP_DEV_AWAIT_RESET),\
+	C(SMP_DEV_IDLE),\
+	C(SMP_DEV_CMD),\
+	C(DEV_STOPPING),\
+	C(DEV_FAILED),\
+	C(DEV_RESETTING),\
+	C(DEV_FINAL),\
+	}
+#undef C
+#define C(a) SCI_##a
+enum sci_remote_device_states REMOTE_DEV_STATES;
+#undef C
+const char *dev_state_name(enum sci_remote_device_states state);
 
 static inline struct isci_remote_device *rnc_to_dev(struct sci_remote_node_context *rnc)
 {
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 748e833..3a94634 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -60,18 +60,15 @@
 #include "scu_event_codes.h"
 #include "scu_task_context.h"
 
+#undef C
+#define C(a) (#a)
+const char *rnc_state_name(enum scis_sds_remote_node_context_states state)
+{
+	static const char * const strings[] = RNC_STATES;
 
-/**
- *
- * @sci_rnc: The RNC for which the is posted request is being made.
- *
- * This method will return true if the RNC is not in the initial state.  In all
- * other states the RNC is considered active and this will return true. The
- * destroy request of the state machine drives the RNC back to the initial
- * state.  If the state machine changes then this routine will also have to be
- * changed. bool true if the state machine is not in the initial state false if
- * the state machine is in the initial state
- */
+	return strings[state];
+}
+#undef C
 
 /**
  *
diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h
index 41580ad..a241e0f 100644
--- a/drivers/scsi/isci/remote_node_context.h
+++ b/drivers/scsi/isci/remote_node_context.h
@@ -85,61 +85,50 @@
 typedef void (*scics_sds_remote_node_context_callback)(void *);
 
 /**
- * This is the enumeration of the remote node context states.
+ * enum sci_remote_node_context_states
+ * @SCI_RNC_INITIAL initial state for a remote node context.  On a resume
+ * request the remote node context will transition to the posting state.
+ *
+ * @SCI_RNC_POSTING: transition state that posts the RNi to the hardware. Once
+ * the RNC is posted the remote node context will be made ready.
+ *
+ * @SCI_RNC_INVALIDATING: transition state that will post an RNC invalidate to
+ * the hardware.  Once the invalidate is complete the remote node context will
+ * transition to the posting state.
+ *
+ * @SCI_RNC_RESUMING: transition state that will post an RNC resume to the
+ * hardare.  Once the event notification of resume complete is received the
+ * remote node context will transition to the ready state.
+ *
+ * @SCI_RNC_READY: state that the remote node context must be in to accept io
+ * request operations.
+ *
+ * @SCI_RNC_TX_SUSPENDED: state that the remote node context transitions to when
+ * it gets a TX suspend notification from the hardware.
+ *
+ * @SCI_RNC_TX_RX_SUSPENDED: state that the remote node context transitions to
+ * when it gets a TX RX suspend notification from the hardware.
+ *
+ * @SCI_RNC_AWAIT_SUSPENSION: wait state for the remote node context that waits
+ * for a suspend notification from the hardware.  This state is entered when
+ * either there is a request to supend the remote node context or when there is
+ * a TC completion where the remote node will be suspended by the hardware.
  */
-enum scis_sds_remote_node_context_states {
-	/**
-	 * This state is the initial state for a remote node context.  On a resume
-	 * request the remote node context will transition to the posting state.
-	 */
-	SCI_RNC_INITIAL,
-
-	/**
-	 * This is a transition state that posts the RNi to the hardware. Once the RNC
-	 * is posted the remote node context will be made ready.
-	 */
-	SCI_RNC_POSTING,
-
-	/**
-	 * This is a transition state that will post an RNC invalidate to the
-	 * hardware.  Once the invalidate is complete the remote node context will
-	 * transition to the posting state.
-	 */
-	SCI_RNC_INVALIDATING,
-
-	/**
-	 * This is a transition state that will post an RNC resume to the hardare.
-	 * Once the event notification of resume complete is received the remote node
-	 * context will transition to the ready state.
-	 */
-	SCI_RNC_RESUMING,
-
-	/**
-	 * This is the state that the remote node context must be in to accept io
-	 * request operations.
-	 */
-	SCI_RNC_READY,
-
-	/**
-	 * This is the state that the remote node context transitions to when it gets
-	 * a TX suspend notification from the hardware.
-	 */
-	SCI_RNC_TX_SUSPENDED,
-
-	/**
-	 * This is the state that the remote node context transitions to when it gets
-	 * a TX RX suspend notification from the hardware.
-	 */
-	SCI_RNC_TX_RX_SUSPENDED,
-
-	/**
-	 * This state is a wait state for the remote node context that waits for a
-	 * suspend notification from the hardware.  This state is entered when either
-	 * there is a request to supend the remote node context or when there is a TC
-	 * completion where the remote node will be suspended by the hardware.
-	 */
-	SCI_RNC_AWAIT_SUSPENSION
-};
+#define RNC_STATES {\
+	C(RNC_INITIAL),\
+	C(RNC_POSTING),\
+	C(RNC_INVALIDATING),\
+	C(RNC_RESUMING),\
+	C(RNC_READY),\
+	C(RNC_TX_SUSPENDED),\
+	C(RNC_TX_RX_SUSPENDED),\
+	C(RNC_AWAIT_SUSPENSION),\
+	}
+#undef C
+#define C(a) SCI_##a
+enum scis_sds_remote_node_context_states RNC_STATES;
+#undef C
+const char *rnc_state_name(enum scis_sds_remote_node_context_states state);
 
 /**
  *
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index ee0dc05..2def1e3 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -53,6 +53,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <scsi/scsi_cmnd.h>
 #include "isci.h"
 #include "task.h"
 #include "request.h"
@@ -60,6 +61,16 @@
 #include "scu_event_codes.h"
 #include "sas.h"
 
+#undef C
+#define C(a) (#a)
+const char *req_state_name(enum sci_base_request_states state)
+{
+	static const char * const strings[] = REQUEST_STATES;
+
+	return strings[state];
+}
+#undef C
+
 static struct scu_sgl_element_pair *to_sgl_element_pair(struct isci_request *ireq,
 							int idx)
 {
@@ -264,6 +275,141 @@
 	task_context->response_iu_lower = lower_32_bits(dma_addr);
 }
 
+static u8 scu_bg_blk_size(struct scsi_device *sdp)
+{
+	switch (sdp->sector_size) {
+	case 512:
+		return 0;
+	case 1024:
+		return 1;
+	case 4096:
+		return 3;
+	default:
+		return 0xff;
+	}
+}
+
+static u32 scu_dif_bytes(u32 len, u32 sector_size)
+{
+	return (len >> ilog2(sector_size)) * 8;
+}
+
+static void scu_ssp_ireq_dif_insert(struct isci_request *ireq, u8 type, u8 op)
+{
+	struct scu_task_context *tc = ireq->tc;
+	struct scsi_cmnd *scmd = ireq->ttype_ptr.io_task_ptr->uldd_task;
+	u8 blk_sz = scu_bg_blk_size(scmd->device);
+
+	tc->block_guard_enable = 1;
+	tc->blk_prot_en = 1;
+	tc->blk_sz = blk_sz;
+	/* DIF write insert */
+	tc->blk_prot_func = 0x2;
+
+	tc->transfer_length_bytes += scu_dif_bytes(tc->transfer_length_bytes,
+						   scmd->device->sector_size);
+
+	/* always init to 0, used by hw */
+	tc->interm_crc_val = 0;
+
+	tc->init_crc_seed = 0;
+	tc->app_tag_verify = 0;
+	tc->app_tag_gen = 0;
+	tc->ref_tag_seed_verify = 0;
+
+	/* always init to same as bg_blk_sz */
+	tc->UD_bytes_immed_val = scmd->device->sector_size;
+
+	tc->reserved_DC_0 = 0;
+
+	/* always init to 8 */
+	tc->DIF_bytes_immed_val = 8;
+
+	tc->reserved_DC_1 = 0;
+	tc->bgc_blk_sz = scmd->device->sector_size;
+	tc->reserved_E0_0 = 0;
+	tc->app_tag_gen_mask = 0;
+
+	/** setup block guard control **/
+	tc->bgctl = 0;
+
+	/* DIF write insert */
+	tc->bgctl_f.op = 0x2;
+
+	tc->app_tag_verify_mask = 0;
+
+	/* must init to 0 for hw */
+	tc->blk_guard_err = 0;
+
+	tc->reserved_E8_0 = 0;
+
+	if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2))
+		tc->ref_tag_seed_gen = scsi_get_lba(scmd) & 0xffffffff;
+	else if (type & SCSI_PROT_DIF_TYPE3)
+		tc->ref_tag_seed_gen = 0;
+}
+
+static void scu_ssp_ireq_dif_strip(struct isci_request *ireq, u8 type, u8 op)
+{
+	struct scu_task_context *tc = ireq->tc;
+	struct scsi_cmnd *scmd = ireq->ttype_ptr.io_task_ptr->uldd_task;
+	u8 blk_sz = scu_bg_blk_size(scmd->device);
+
+	tc->block_guard_enable = 1;
+	tc->blk_prot_en = 1;
+	tc->blk_sz = blk_sz;
+	/* DIF read strip */
+	tc->blk_prot_func = 0x1;
+
+	tc->transfer_length_bytes += scu_dif_bytes(tc->transfer_length_bytes,
+						   scmd->device->sector_size);
+
+	/* always init to 0, used by hw */
+	tc->interm_crc_val = 0;
+
+	tc->init_crc_seed = 0;
+	tc->app_tag_verify = 0;
+	tc->app_tag_gen = 0;
+
+	if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2))
+		tc->ref_tag_seed_verify = scsi_get_lba(scmd) & 0xffffffff;
+	else if (type & SCSI_PROT_DIF_TYPE3)
+		tc->ref_tag_seed_verify = 0;
+
+	/* always init to same as bg_blk_sz */
+	tc->UD_bytes_immed_val = scmd->device->sector_size;
+
+	tc->reserved_DC_0 = 0;
+
+	/* always init to 8 */
+	tc->DIF_bytes_immed_val = 8;
+
+	tc->reserved_DC_1 = 0;
+	tc->bgc_blk_sz = scmd->device->sector_size;
+	tc->reserved_E0_0 = 0;
+	tc->app_tag_gen_mask = 0;
+
+	/** setup block guard control **/
+	tc->bgctl = 0;
+
+	/* DIF read strip */
+	tc->bgctl_f.crc_verify = 1;
+	tc->bgctl_f.op = 0x1;
+	if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2)) {
+		tc->bgctl_f.ref_tag_chk = 1;
+		tc->bgctl_f.app_f_detect = 1;
+	} else if (type & SCSI_PROT_DIF_TYPE3)
+		tc->bgctl_f.app_ref_f_detect = 1;
+
+	tc->app_tag_verify_mask = 0;
+
+	/* must init to 0 for hw */
+	tc->blk_guard_err = 0;
+
+	tc->reserved_E8_0 = 0;
+	tc->ref_tag_seed_gen = 0;
+}
+
 /**
  * This method is will fill in the SCU Task Context for a SSP IO request.
  * @sci_req:
@@ -274,6 +420,10 @@
 						      u32 len)
 {
 	struct scu_task_context *task_context = ireq->tc;
+	struct sas_task *sas_task = ireq->ttype_ptr.io_task_ptr;
+	struct scsi_cmnd *scmd = sas_task->uldd_task;
+	u8 prot_type = scsi_get_prot_type(scmd);
+	u8 prot_op = scsi_get_prot_op(scmd);
 
 	scu_ssp_reqeust_construct_task_context(ireq, task_context);
 
@@ -296,6 +446,13 @@
 
 	if (task_context->transfer_length_bytes > 0)
 		sci_request_build_sgl(ireq);
+
+	if (prot_type != SCSI_PROT_DIF_TYPE0) {
+		if (prot_op == SCSI_PROT_READ_STRIP)
+			scu_ssp_ireq_dif_strip(ireq, prot_type, prot_op);
+		else if (prot_op == SCSI_PROT_WRITE_INSERT)
+			scu_ssp_ireq_dif_insert(ireq, prot_type, prot_op);
+	}
 }
 
 /**
@@ -519,18 +676,12 @@
 	if (test_bit(IREQ_TMF, &ireq->flags)) {
 		struct isci_tmf *tmf = isci_request_access_tmf(ireq);
 
-		if (tmf->tmf_code == isci_tmf_sata_srst_high ||
-		    tmf->tmf_code == isci_tmf_sata_srst_low) {
-			scu_stp_raw_request_construct_task_context(ireq);
-			return SCI_SUCCESS;
-		} else {
-			dev_err(&ireq->owning_controller->pdev->dev,
-				"%s: Request 0x%p received un-handled SAT "
-				"management protocol 0x%x.\n",
-				__func__, ireq, tmf->tmf_code);
+		dev_err(&ireq->owning_controller->pdev->dev,
+			"%s: Request 0x%p received un-handled SAT "
+			"management protocol 0x%x.\n",
+			__func__, ireq, tmf->tmf_code);
 
-			return SCI_FAILURE;
-		}
+		return SCI_FAILURE;
 	}
 
 	if (!sas_protocol_ata(task->task_proto)) {
@@ -627,34 +778,6 @@
 	return status;
 }
 
-enum sci_status sci_task_request_construct_sata(struct isci_request *ireq)
-{
-	enum sci_status status = SCI_SUCCESS;
-
-	/* check for management protocols */
-	if (test_bit(IREQ_TMF, &ireq->flags)) {
-		struct isci_tmf *tmf = isci_request_access_tmf(ireq);
-
-		if (tmf->tmf_code == isci_tmf_sata_srst_high ||
-		    tmf->tmf_code == isci_tmf_sata_srst_low) {
-			scu_stp_raw_request_construct_task_context(ireq);
-		} else {
-			dev_err(&ireq->owning_controller->pdev->dev,
-				"%s: Request 0x%p received un-handled SAT "
-				"Protocol 0x%x.\n",
-				__func__, ireq, tmf->tmf_code);
-
-			return SCI_FAILURE;
-		}
-	}
-
-	if (status != SCI_SUCCESS)
-		return status;
-	sci_change_state(&ireq->sm, SCI_REQ_CONSTRUCTED);
-
-	return status;
-}
-
 /**
  * sci_req_tx_bytes - bytes transferred when reply underruns request
  * @ireq: request that was terminated early
@@ -756,9 +879,6 @@
 	case SCI_REQ_STP_PIO_WAIT_FRAME:
 	case SCI_REQ_STP_PIO_DATA_IN:
 	case SCI_REQ_STP_PIO_DATA_OUT:
-	case SCI_REQ_STP_SOFT_RESET_WAIT_H2D_ASSERTED:
-	case SCI_REQ_STP_SOFT_RESET_WAIT_H2D_DIAG:
-	case SCI_REQ_STP_SOFT_RESET_WAIT_D2H:
 	case SCI_REQ_ATAPI_WAIT_H2D:
 	case SCI_REQ_ATAPI_WAIT_PIO_SETUP:
 	case SCI_REQ_ATAPI_WAIT_D2H:
@@ -800,7 +920,8 @@
 
 	state = ireq->sm.current_state_id;
 	if (WARN_ONCE(state != SCI_REQ_COMPLETED,
-		      "isci: request completion from wrong state (%d)\n", state))
+		      "isci: request completion from wrong state (%s)\n",
+		      req_state_name(state)))
 		return SCI_FAILURE_INVALID_STATE;
 
 	if (ireq->saved_rx_frame_index != SCU_INVALID_FRAME_INDEX)
@@ -821,8 +942,8 @@
 	state = ireq->sm.current_state_id;
 
 	if (state != SCI_REQ_STP_PIO_DATA_IN) {
-		dev_warn(&ihost->pdev->dev, "%s: (%x) in wrong state %d\n",
-			 __func__, event_code, state);
+		dev_warn(&ihost->pdev->dev, "%s: (%x) in wrong state %s\n",
+			 __func__, event_code, req_state_name(state));
 
 		return SCI_FAILURE_INVALID_STATE;
 	}
@@ -1938,59 +2059,6 @@
 		return status;
 	}
 
-	case SCI_REQ_STP_SOFT_RESET_WAIT_D2H: {
-		struct dev_to_host_fis *frame_header;
-		u32 *frame_buffer;
-
-		status = sci_unsolicited_frame_control_get_header(&ihost->uf_control,
-								       frame_index,
-								       (void **)&frame_header);
-		if (status != SCI_SUCCESS) {
-			dev_err(&ihost->pdev->dev,
-				"%s: SCIC IO Request 0x%p could not get frame "
-				"header for frame index %d, status %x\n",
-				__func__,
-				stp_req,
-				frame_index,
-				status);
-			return status;
-		}
-
-		switch (frame_header->fis_type) {
-		case FIS_REGD2H:
-			sci_unsolicited_frame_control_get_buffer(&ihost->uf_control,
-								      frame_index,
-								      (void **)&frame_buffer);
-
-			sci_controller_copy_sata_response(&ireq->stp.rsp,
-							       frame_header,
-							       frame_buffer);
-
-			/* The command has completed with error */
-			ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
-			ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
-			break;
-
-		default:
-			dev_warn(&ihost->pdev->dev,
-				 "%s: IO Request:0x%p Frame Id:%d protocol "
-				 "violation occurred\n",
-				 __func__,
-				 stp_req,
-				 frame_index);
-
-			ireq->scu_status = SCU_TASK_DONE_UNEXP_FIS;
-			ireq->sci_status = SCI_FAILURE_PROTOCOL_VIOLATION;
-			break;
-		}
-
-		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
-
-		/* Frame has been decoded return it to the controller */
-		sci_controller_release_frame(ihost, frame_index);
-
-		return status;
-	}
 	case SCI_REQ_ATAPI_WAIT_PIO_SETUP: {
 		struct sas_task *task = isci_request_access_task(ireq);
 
@@ -2088,57 +2156,6 @@
 	return status;
 }
 
-static enum sci_status
-stp_request_soft_reset_await_h2d_asserted_tc_event(struct isci_request *ireq,
-						   u32 completion_code)
-{
-	switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
-	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
-		ireq->scu_status = SCU_TASK_DONE_GOOD;
-		ireq->sci_status = SCI_SUCCESS;
-		sci_change_state(&ireq->sm, SCI_REQ_STP_SOFT_RESET_WAIT_H2D_DIAG);
-		break;
-
-	default:
-		/*
-		 * All other completion status cause the IO to be complete.
-		 * If a NAK was received, then it is up to the user to retry
-		 * the request.
-		 */
-		ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
-		ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
-		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
-		break;
-	}
-
-	return SCI_SUCCESS;
-}
-
-static enum sci_status
-stp_request_soft_reset_await_h2d_diagnostic_tc_event(struct isci_request *ireq,
-						     u32 completion_code)
-{
-	switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
-	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
-		ireq->scu_status = SCU_TASK_DONE_GOOD;
-		ireq->sci_status = SCI_SUCCESS;
-		sci_change_state(&ireq->sm, SCI_REQ_STP_SOFT_RESET_WAIT_D2H);
-		break;
-
-	default:
-		/* All other completion status cause the IO to be complete.  If
-		 * a NAK was received, then it is up to the user to retry the
-		 * request.
-		 */
-		ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
-		ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
-		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
-		break;
-	}
-
-	return SCI_SUCCESS;
-}
-
 static enum sci_status atapi_raw_completion(struct isci_request *ireq, u32 completion_code,
 						  enum sci_base_request_states next)
 {
@@ -2284,14 +2301,6 @@
 	case SCI_REQ_STP_PIO_DATA_OUT:
 		return pio_data_out_tx_done_tc_event(ireq, completion_code);
 
-	case SCI_REQ_STP_SOFT_RESET_WAIT_H2D_ASSERTED:
-		return stp_request_soft_reset_await_h2d_asserted_tc_event(ireq,
-									  completion_code);
-
-	case SCI_REQ_STP_SOFT_RESET_WAIT_H2D_DIAG:
-		return stp_request_soft_reset_await_h2d_diagnostic_tc_event(ireq,
-									    completion_code);
-
 	case SCI_REQ_ABORTING:
 		return request_aborting_state_tc_event(ireq,
 						       completion_code);
@@ -2308,12 +2317,8 @@
 		return atapi_data_tc_completion_handler(ireq, completion_code);
 
 	default:
-		dev_warn(&ihost->pdev->dev,
-			 "%s: SCIC IO Request given task completion "
-			 "notification %x while in wrong state %d\n",
-			 __func__,
-			 completion_code,
-			 state);
+		dev_warn(&ihost->pdev->dev, "%s: %x in wrong state %s\n",
+			 __func__, completion_code, req_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 }
@@ -3065,10 +3070,6 @@
 	 */
 	if (!task && dev->dev_type == SAS_END_DEV) {
 		state = SCI_REQ_TASK_WAIT_TC_COMP;
-	} else if (!task &&
-		   (isci_request_access_tmf(ireq)->tmf_code == isci_tmf_sata_srst_high ||
-		    isci_request_access_tmf(ireq)->tmf_code == isci_tmf_sata_srst_low)) {
-		state = SCI_REQ_STP_SOFT_RESET_WAIT_H2D_ASSERTED;
 	} else if (task && task->task_proto == SAS_PROTOCOL_SMP) {
 		state = SCI_REQ_SMP_WAIT_RESP;
 	} else if (task && sas_protocol_ata(task->task_proto) &&
@@ -3125,31 +3126,6 @@
 	ireq->target_device->working_request = ireq;
 }
 
-static void sci_stp_request_started_soft_reset_await_h2d_asserted_completion_enter(struct sci_base_state_machine *sm)
-{
-	struct isci_request *ireq = container_of(sm, typeof(*ireq), sm);
-
-	ireq->target_device->working_request = ireq;
-}
-
-static void sci_stp_request_started_soft_reset_await_h2d_diagnostic_completion_enter(struct sci_base_state_machine *sm)
-{
-	struct isci_request *ireq = container_of(sm, typeof(*ireq), sm);
-	struct scu_task_context *tc = ireq->tc;
-	struct host_to_dev_fis *h2d_fis;
-	enum sci_status status;
-
-	/* Clear the SRST bit */
-	h2d_fis = &ireq->stp.cmd;
-	h2d_fis->control = 0;
-
-	/* Clear the TC control bit */
-	tc->control_frame = 0;
-
-	status = sci_controller_continue_io(ireq);
-	WARN_ONCE(status != SCI_SUCCESS, "isci: continue io failure\n");
-}
-
 static const struct sci_base_state sci_request_state_table[] = {
 	[SCI_REQ_INIT] = { },
 	[SCI_REQ_CONSTRUCTED] = { },
@@ -3168,13 +3144,6 @@
 	[SCI_REQ_STP_PIO_DATA_OUT] = { },
 	[SCI_REQ_STP_UDMA_WAIT_TC_COMP] = { },
 	[SCI_REQ_STP_UDMA_WAIT_D2H] = { },
-	[SCI_REQ_STP_SOFT_RESET_WAIT_H2D_ASSERTED] = {
-		.enter_state = sci_stp_request_started_soft_reset_await_h2d_asserted_completion_enter,
-	},
-	[SCI_REQ_STP_SOFT_RESET_WAIT_H2D_DIAG] = {
-		.enter_state = sci_stp_request_started_soft_reset_await_h2d_diagnostic_completion_enter,
-	},
-	[SCI_REQ_STP_SOFT_RESET_WAIT_D2H] = { },
 	[SCI_REQ_TASK_WAIT_TC_COMP] = { },
 	[SCI_REQ_TASK_WAIT_TC_RESP] = { },
 	[SCI_REQ_SMP_WAIT_RESP] = { },
@@ -3649,8 +3618,7 @@
 		/* Cause this task to be scheduled in the SCSI error
 		 * handler thread.
 		 */
-		isci_execpath_callback(ihost, task,
-				       sas_task_abort);
+		sas_task_abort(task);
 
 		/* Change the status, since we are holding
 		 * the I/O until it is managed by the SCSI
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h
index be38933..057f237 100644
--- a/drivers/scsi/isci/request.h
+++ b/drivers/scsi/isci/request.h
@@ -182,138 +182,103 @@
 }
 
 /**
- * enum sci_base_request_states - This enumeration depicts all the states for
- *    the common request state machine.
+ * enum sci_base_request_states - request state machine states
  *
+ * @SCI_REQ_INIT: Simply the initial state for the base request state machine.
  *
+ * @SCI_REQ_CONSTRUCTED: This state indicates that the request has been
+ * constructed.  This state is entered from the INITIAL state.
+ *
+ * @SCI_REQ_STARTED: This state indicates that the request has been started.
+ * This state is entered from the CONSTRUCTED state.
+ *
+ * @SCI_REQ_STP_UDMA_WAIT_TC_COMP:
+ * @SCI_REQ_STP_UDMA_WAIT_D2H:
+ * @SCI_REQ_STP_NON_DATA_WAIT_H2D:
+ * @SCI_REQ_STP_NON_DATA_WAIT_D2H:
+ *
+ * @SCI_REQ_STP_PIO_WAIT_H2D: While in this state the IO request object is
+ * waiting for the TC completion notification for the H2D Register FIS
+ *
+ * @SCI_REQ_STP_PIO_WAIT_FRAME: While in this state the IO request object is
+ * waiting for either a PIO Setup FIS or a D2H register FIS.  The type of frame
+ * received is based on the result of the prior frame and line conditions.
+ *
+ * @SCI_REQ_STP_PIO_DATA_IN: While in this state the IO request object is
+ * waiting for a DATA frame from the device.
+ *
+ * @SCI_REQ_STP_PIO_DATA_OUT: While in this state the IO request object is
+ * waiting to transmit the next data frame to the device.
+ *
+ * @SCI_REQ_ATAPI_WAIT_H2D: While in this state the IO request object is
+ * waiting for the TC completion notification for the H2D Register FIS
+ *
+ * @SCI_REQ_ATAPI_WAIT_PIO_SETUP: While in this state the IO request object is
+ * waiting for either a PIO Setup.
+ *
+ * @SCI_REQ_ATAPI_WAIT_D2H: The non-data IO transit to this state in this state
+ * after receiving TC completion. While in this state IO request object is
+ * waiting for D2H status frame as UF.
+ *
+ * @SCI_REQ_ATAPI_WAIT_TC_COMP: When transmitting raw frames hardware reports
+ * task context completion after every frame submission, so in the
+ * non-accelerated case we need to expect the completion for the "cdb" frame.
+ *
+ * @SCI_REQ_TASK_WAIT_TC_COMP: The AWAIT_TC_COMPLETION sub-state indicates that
+ * the started raw task management request is waiting for the transmission of
+ * the initial frame (i.e. command, task, etc.).
+ *
+ * @SCI_REQ_TASK_WAIT_TC_RESP: This sub-state indicates that the started task
+ * management request is waiting for the reception of an unsolicited frame
+ * (i.e.  response IU).
+ *
+ * @SCI_REQ_SMP_WAIT_RESP: This sub-state indicates that the started task
+ * management request is waiting for the reception of an unsolicited frame
+ * (i.e.  response IU).
+ *
+ * @SCI_REQ_SMP_WAIT_TC_COMP: The AWAIT_TC_COMPLETION sub-state indicates that
+ * the started SMP request is waiting for the transmission of the initial frame
+ * (i.e.  command, task, etc.).
+ *
+ * @SCI_REQ_COMPLETED: This state indicates that the request has completed.
+ * This state is entered from the STARTED state. This state is entered from the
+ * ABORTING state.
+ *
+ * @SCI_REQ_ABORTING: This state indicates that the request is in the process
+ * of being terminated/aborted.  This state is entered from the CONSTRUCTED
+ * state.  This state is entered from the STARTED state.
+ *
+ * @SCI_REQ_FINAL: Simply the final state for the base request state machine.
  */
-enum sci_base_request_states {
-	/*
-	 * Simply the initial state for the base request state machine.
-	 */
-	SCI_REQ_INIT,
-
-	/*
-	 * This state indicates that the request has been constructed.
-	 * This state is entered from the INITIAL state.
-	 */
-	SCI_REQ_CONSTRUCTED,
-
-	/*
-	 * This state indicates that the request has been started. This state
-	 * is entered from the CONSTRUCTED state.
-	 */
-	SCI_REQ_STARTED,
-
-	SCI_REQ_STP_UDMA_WAIT_TC_COMP,
-	SCI_REQ_STP_UDMA_WAIT_D2H,
-
-	SCI_REQ_STP_NON_DATA_WAIT_H2D,
-	SCI_REQ_STP_NON_DATA_WAIT_D2H,
-
-	SCI_REQ_STP_SOFT_RESET_WAIT_H2D_ASSERTED,
-	SCI_REQ_STP_SOFT_RESET_WAIT_H2D_DIAG,
-	SCI_REQ_STP_SOFT_RESET_WAIT_D2H,
-
-	/*
-	 * While in this state the IO request object is waiting for the TC
-	 * completion notification for the H2D Register FIS
-	 */
-	SCI_REQ_STP_PIO_WAIT_H2D,
-
-	/*
-	 * While in this state the IO request object is waiting for either a
-	 * PIO Setup FIS or a D2H register FIS.  The type of frame received is
-	 * based on the result of the prior frame and line conditions.
-	 */
-	SCI_REQ_STP_PIO_WAIT_FRAME,
-
-	/*
-	 * While in this state the IO request object is waiting for a DATA
-	 * frame from the device.
-	 */
-	SCI_REQ_STP_PIO_DATA_IN,
-
-	/*
-	 * While in this state the IO request object is waiting to transmit
-	 * the next data frame to the device.
-	 */
-	SCI_REQ_STP_PIO_DATA_OUT,
-
-	/*
-	 * While in this state the IO request object is waiting for the TC
-	 * completion notification for the H2D Register FIS
-	 */
-	SCI_REQ_ATAPI_WAIT_H2D,
-
-	/*
-	 * While in this state the IO request object is waiting for either a
-	 * PIO Setup.
-	 */
-	SCI_REQ_ATAPI_WAIT_PIO_SETUP,
-
-	/*
-	 * The non-data IO transit to this state in this state after receiving
-	 * TC completion. While in this state IO request object is waiting for
-	 * D2H status frame as UF.
-	 */
-	SCI_REQ_ATAPI_WAIT_D2H,
-
-	/*
-	 * When transmitting raw frames hardware reports task context completion
-	 * after every frame submission, so in the non-accelerated case we need
-	 * to expect the completion for the "cdb" frame.
-	 */
-	SCI_REQ_ATAPI_WAIT_TC_COMP,
-
-	/*
-	 * The AWAIT_TC_COMPLETION sub-state indicates that the started raw
-	 * task management request is waiting for the transmission of the
-	 * initial frame (i.e. command, task, etc.).
-	 */
-	SCI_REQ_TASK_WAIT_TC_COMP,
-
-	/*
-	 * This sub-state indicates that the started task management request
-	 * is waiting for the reception of an unsolicited frame
-	 * (i.e. response IU).
-	 */
-	SCI_REQ_TASK_WAIT_TC_RESP,
-
-	/*
-	 * This sub-state indicates that the started task management request
-	 * is waiting for the reception of an unsolicited frame
-	 * (i.e. response IU).
-	 */
-	SCI_REQ_SMP_WAIT_RESP,
-
-	/*
-	 * The AWAIT_TC_COMPLETION sub-state indicates that the started SMP
-	 * request is waiting for the transmission of the initial frame
-	 * (i.e. command, task, etc.).
-	 */
-	SCI_REQ_SMP_WAIT_TC_COMP,
-
-	/*
-	 * This state indicates that the request has completed.
-	 * This state is entered from the STARTED state. This state is entered
-	 * from the ABORTING state.
-	 */
-	SCI_REQ_COMPLETED,
-
-	/*
-	 * This state indicates that the request is in the process of being
-	 * terminated/aborted.
-	 * This state is entered from the CONSTRUCTED state.
-	 * This state is entered from the STARTED state.
-	 */
-	SCI_REQ_ABORTING,
-
-	/*
-	 * Simply the final state for the base request state machine.
-	 */
-	SCI_REQ_FINAL,
-};
+#define REQUEST_STATES {\
+	C(REQ_INIT),\
+	C(REQ_CONSTRUCTED),\
+	C(REQ_STARTED),\
+	C(REQ_STP_UDMA_WAIT_TC_COMP),\
+	C(REQ_STP_UDMA_WAIT_D2H),\
+	C(REQ_STP_NON_DATA_WAIT_H2D),\
+	C(REQ_STP_NON_DATA_WAIT_D2H),\
+	C(REQ_STP_PIO_WAIT_H2D),\
+	C(REQ_STP_PIO_WAIT_FRAME),\
+	C(REQ_STP_PIO_DATA_IN),\
+	C(REQ_STP_PIO_DATA_OUT),\
+	C(REQ_ATAPI_WAIT_H2D),\
+	C(REQ_ATAPI_WAIT_PIO_SETUP),\
+	C(REQ_ATAPI_WAIT_D2H),\
+	C(REQ_ATAPI_WAIT_TC_COMP),\
+	C(REQ_TASK_WAIT_TC_COMP),\
+	C(REQ_TASK_WAIT_TC_RESP),\
+	C(REQ_SMP_WAIT_RESP),\
+	C(REQ_SMP_WAIT_TC_COMP),\
+	C(REQ_COMPLETED),\
+	C(REQ_ABORTING),\
+	C(REQ_FINAL),\
+	}
+#undef C
+#define C(a) SCI_##a
+enum sci_base_request_states REQUEST_STATES;
+#undef C
+const char *req_state_name(enum sci_base_request_states state);
 
 enum sci_status sci_request_start(struct isci_request *ireq);
 enum sci_status sci_io_request_terminate(struct isci_request *ireq);
@@ -446,10 +411,7 @@
 			    struct isci_remote_device *idev,
 			    u16 io_tag,
 			    struct isci_request *ireq);
-enum sci_status
-sci_task_request_construct_ssp(struct isci_request *ireq);
-enum sci_status
-sci_task_request_construct_sata(struct isci_request *ireq);
+enum sci_status sci_task_request_construct_ssp(struct isci_request *ireq);
 void sci_smp_request_copy_response(struct isci_request *ireq);
 
 static inline int isci_task_is_ncq_recovery(struct sas_task *task)
diff --git a/drivers/scsi/isci/scu_task_context.h b/drivers/scsi/isci/scu_task_context.h
index 7df87d9..869a979 100644
--- a/drivers/scsi/isci/scu_task_context.h
+++ b/drivers/scsi/isci/scu_task_context.h
@@ -866,9 +866,9 @@
 	struct transport_snapshot snapshot; /* read only set to 0 */
 
 	/* OFFSET 0x5C */
-	u32 block_protection_enable:1;
-	u32 block_size:2;
-	u32 block_protection_function:2;
+	u32 blk_prot_en:1;
+	u32 blk_sz:2;
+	u32 blk_prot_func:2;
 	u32 reserved_5C_0:9;
 	u32 active_sgl_element:2;  /* read only set to 0 */
 	u32 sgl_exhausted:1;  /* read only set to 0 */
@@ -896,33 +896,56 @@
 	u32 reserved_C4_CC[3];
 
 	/* OFFSET 0xD0 */
-	u32 intermediate_crc_value:16;
-	u32 initial_crc_seed:16;
+	u32 interm_crc_val:16;
+	u32 init_crc_seed:16;
 
 	/* OFFSET 0xD4 */
-	u32 application_tag_for_verify:16;
-	u32 application_tag_for_generate:16;
+	u32 app_tag_verify:16;
+	u32 app_tag_gen:16;
 
 	/* OFFSET 0xD8 */
-	u32 reference_tag_seed_for_verify_function;
+	u32 ref_tag_seed_verify;
 
 	/* OFFSET 0xDC */
-	u32 reserved_DC;
+	u32 UD_bytes_immed_val:13;
+	u32 reserved_DC_0:3;
+	u32 DIF_bytes_immed_val:4;
+	u32 reserved_DC_1:12;
 
 	/* OFFSET 0xE0 */
-	u32 reserved_E0_0:16;
-	u32 application_tag_mask_for_generate:16;
+	u32 bgc_blk_sz:13;
+	u32 reserved_E0_0:3;
+	u32 app_tag_gen_mask:16;
 
 	/* OFFSET 0xE4 */
-	u32 block_protection_control:16;
-	u32 application_tag_mask_for_verify:16;
+	union {
+		u16 bgctl;
+		struct {
+			u16 crc_verify:1;
+			u16 app_tag_chk:1;
+			u16 ref_tag_chk:1;
+			u16 op:2;
+			u16 legacy:1;
+			u16 invert_crc_seed:1;
+			u16 ref_tag_gen:1;
+			u16 fixed_ref_tag:1;
+			u16 invert_crc:1;
+			u16 app_ref_f_detect:1;
+			u16 uninit_dif_check_err:1;
+			u16 uninit_dif_bypass:1;
+			u16 app_f_detect:1;
+			u16 reserved_0:2;
+		} bgctl_f;
+	};
+
+	u16 app_tag_verify_mask;
 
 	/* OFFSET 0xE8 */
-	u32 block_protection_error:8;
+	u32 blk_guard_err:8;
 	u32 reserved_E8_0:24;
 
 	/* OFFSET 0xEC */
-	u32 reference_tag_seed_for_verify;
+	u32 ref_tag_seed_gen;
 
 	/* OFFSET 0xF0 */
 	u32 intermediate_crc_valid_snapshot:16;
@@ -937,6 +960,6 @@
 	/* OFFSET 0xFC */
 	u32 reference_tag_seed_for_generate_function_snapshot;
 
-};
+} __packed;
 
 #endif /* _SCU_TASK_CONTEXT_H_ */
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index f5a3f7d..374254e 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -96,8 +96,7 @@
 			__func__, task, response, status);
 
 		task->lldd_task = NULL;
-
-		isci_execpath_callback(ihost, task, task->task_done);
+		task->task_done(task);
 		break;
 
 	case isci_perform_aborted_io_completion:
@@ -117,8 +116,7 @@
 			"%s: Error - task = %p, response=%d, "
 			"status=%d\n",
 			__func__, task, response, status);
-
-		isci_execpath_callback(ihost, task, sas_task_abort);
+		sas_task_abort(task);
 		break;
 
 	default:
@@ -249,46 +247,6 @@
 	return 0;
 }
 
-static enum sci_status isci_sata_management_task_request_build(struct isci_request *ireq)
-{
-	struct isci_tmf *isci_tmf;
-	enum sci_status status;
-
-	if (!test_bit(IREQ_TMF, &ireq->flags))
-		return SCI_FAILURE;
-
-	isci_tmf = isci_request_access_tmf(ireq);
-
-	switch (isci_tmf->tmf_code) {
-
-	case isci_tmf_sata_srst_high:
-	case isci_tmf_sata_srst_low: {
-		struct host_to_dev_fis *fis = &ireq->stp.cmd;
-
-		memset(fis, 0, sizeof(*fis));
-
-		fis->fis_type  =  0x27;
-		fis->flags     &= ~0x80;
-		fis->flags     &= 0xF0;
-		if (isci_tmf->tmf_code == isci_tmf_sata_srst_high)
-			fis->control |= ATA_SRST;
-		else
-			fis->control &= ~ATA_SRST;
-		break;
-	}
-	/* other management commnd go here... */
-	default:
-		return SCI_FAILURE;
-	}
-
-	/* core builds the protocol specific request
-	 *  based on the h2d fis.
-	 */
-	status = sci_task_request_construct_sata(ireq);
-
-	return status;
-}
-
 static struct isci_request *isci_task_request_build(struct isci_host *ihost,
 						    struct isci_remote_device *idev,
 						    u16 tag, struct isci_tmf *isci_tmf)
@@ -328,13 +286,6 @@
 			return NULL;
 	}
 
-	if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
-		isci_tmf->proto = SAS_PROTOCOL_SATA;
-		status = isci_sata_management_task_request_build(ireq);
-
-		if (status != SCI_SUCCESS)
-			return NULL;
-	}
 	return ireq;
 }
 
@@ -873,53 +824,20 @@
 	return ret;
 }
 
-static int isci_task_send_lu_reset_sata(struct isci_host *ihost,
-				 struct isci_remote_device *idev, u8 *lun)
+int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
 {
-	int ret = TMF_RESP_FUNC_FAILED;
-	struct isci_tmf tmf;
-
-	/* Send the soft reset to the target */
-	#define ISCI_SRST_TIMEOUT_MS 25000 /* 25 second timeout. */
-	isci_task_build_tmf(&tmf, isci_tmf_sata_srst_high, NULL, NULL);
-
-	ret = isci_task_execute_tmf(ihost, idev, &tmf, ISCI_SRST_TIMEOUT_MS);
-
-	if (ret != TMF_RESP_FUNC_COMPLETE) {
-		dev_dbg(&ihost->pdev->dev,
-			 "%s: Assert SRST failed (%p) = %x",
-			 __func__, idev, ret);
-
-		/* Return the failure so that the LUN reset is escalated
-		 * to a target reset.
-		 */
-	}
-	return ret;
-}
-
-/**
- * isci_task_lu_reset() - This function is one of the SAS Domain Template
- *    functions. This is one of the Task Management functoins called by libsas,
- *    to reset the given lun. Note the assumption that while this call is
- *    executing, no I/O will be sent by the host to the device.
- * @lun: This parameter specifies the lun to be reset.
- *
- * status, zero indicates success.
- */
-int isci_task_lu_reset(struct domain_device *domain_device, u8 *lun)
-{
-	struct isci_host *isci_host = dev_to_ihost(domain_device);
+	struct isci_host *isci_host = dev_to_ihost(dev);
 	struct isci_remote_device *isci_device;
 	unsigned long flags;
 	int ret;
 
 	spin_lock_irqsave(&isci_host->scic_lock, flags);
-	isci_device = isci_lookup_device(domain_device);
+	isci_device = isci_lookup_device(dev);
 	spin_unlock_irqrestore(&isci_host->scic_lock, flags);
 
 	dev_dbg(&isci_host->pdev->dev,
 		"%s: domain_device=%p, isci_host=%p; isci_device=%p\n",
-		 __func__, domain_device, isci_host, isci_device);
+		 __func__, dev, isci_host, isci_device);
 
 	if (!isci_device) {
 		/* If the device is gone, stop the escalations. */
@@ -928,11 +846,11 @@
 		ret = TMF_RESP_FUNC_COMPLETE;
 		goto out;
 	}
-	set_bit(IDEV_EH, &isci_device->flags);
 
 	/* Send the task management part of the reset. */
-	if (sas_protocol_ata(domain_device->tproto)) {
-		ret = isci_task_send_lu_reset_sata(isci_host, isci_device, lun);
+	if (dev_is_sata(dev)) {
+		sas_ata_schedule_reset(dev);
+		ret = TMF_RESP_FUNC_COMPLETE;
 	} else
 		ret = isci_task_send_lu_reset_sas(isci_host, isci_device, lun);
 
@@ -1062,9 +980,6 @@
 		"%s: dev = %p, task = %p, old_request == %p\n",
 		__func__, isci_device, task, old_request);
 
-	if (isci_device)
-		set_bit(IDEV_EH, &isci_device->flags);
-
 	/* Device reset conditions signalled in task_state_flags are the
 	 * responsbility of libsas to observe at the start of the error
 	 * handler thread.
@@ -1332,29 +1247,35 @@
 }
 
 static int isci_reset_device(struct isci_host *ihost,
+			     struct domain_device *dev,
 			     struct isci_remote_device *idev)
 {
-	struct sas_phy *phy = sas_find_local_phy(idev->domain_dev);
-	enum sci_status status;
-	unsigned long flags;
 	int rc;
+	unsigned long flags;
+	enum sci_status status;
+	struct sas_phy *phy = sas_get_local_phy(dev);
+	struct isci_port *iport = dev->port->lldd_port;
 
 	dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev);
 
 	spin_lock_irqsave(&ihost->scic_lock, flags);
 	status = sci_remote_device_reset(idev);
-	if (status != SCI_SUCCESS) {
-		spin_unlock_irqrestore(&ihost->scic_lock, flags);
+	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
+	if (status != SCI_SUCCESS) {
 		dev_dbg(&ihost->pdev->dev,
 			 "%s: sci_remote_device_reset(%p) returned %d!\n",
 			 __func__, idev, status);
-
-		return TMF_RESP_FUNC_FAILED;
+		rc = TMF_RESP_FUNC_FAILED;
+		goto out;
 	}
-	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
-	rc = sas_phy_reset(phy, true);
+	if (scsi_is_sas_phy_local(phy)) {
+		struct isci_phy *iphy = &ihost->phys[phy->number];
+
+		rc = isci_port_perform_hard_reset(ihost, iport, iphy);
+	} else
+		rc = sas_phy_reset(phy, !dev_is_sata(dev));
 
 	/* Terminate in-progress I/O now. */
 	isci_remote_device_nuke_requests(ihost, idev);
@@ -1371,7 +1292,8 @@
 	}
 
 	dev_dbg(&ihost->pdev->dev, "%s: idev %p complete.\n", __func__, idev);
-
+ out:
+	sas_put_local_phy(phy);
 	return rc;
 }
 
@@ -1386,35 +1308,15 @@
 	idev = isci_lookup_device(dev);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
-	if (!idev || !test_bit(IDEV_EH, &idev->flags)) {
-		ret = TMF_RESP_FUNC_COMPLETE;
-		goto out;
-	}
-
-	ret = isci_reset_device(ihost, idev);
- out:
-	isci_put_device(idev);
-	return ret;
-}
-
-int isci_bus_reset_handler(struct scsi_cmnd *cmd)
-{
-	struct domain_device *dev = sdev_to_domain_dev(cmd->device);
-	struct isci_host *ihost = dev_to_ihost(dev);
-	struct isci_remote_device *idev;
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&ihost->scic_lock, flags);
-	idev = isci_lookup_device(dev);
-	spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
 	if (!idev) {
+		/* XXX: need to cleanup any ireqs targeting this
+		 * domain_device
+		 */
 		ret = TMF_RESP_FUNC_COMPLETE;
 		goto out;
 	}
 
-	ret = isci_reset_device(ihost, idev);
+	ret = isci_reset_device(ihost, dev, idev);
  out:
 	isci_put_device(idev);
 	return ret;
diff --git a/drivers/scsi/isci/task.h b/drivers/scsi/isci/task.h
index 1b27b37..7b6d0e3 100644
--- a/drivers/scsi/isci/task.h
+++ b/drivers/scsi/isci/task.h
@@ -86,8 +86,6 @@
 	isci_tmf_func_none      = 0,
 	isci_tmf_ssp_task_abort = TMF_ABORT_TASK,
 	isci_tmf_ssp_lun_reset  = TMF_LU_RESET,
-	isci_tmf_sata_srst_high = TMF_LU_RESET + 0x100, /* Non SCSI */
-	isci_tmf_sata_srst_low  = TMF_LU_RESET + 0x101  /* Non SCSI */
 };
 /**
  * struct isci_tmf - This class represents the task management object which
@@ -210,8 +208,6 @@
 	struct scsi_cmnd *scsi_cmd,
 	void (*donefunc)(struct scsi_cmnd *));
 
-int isci_bus_reset_handler(struct scsi_cmnd *cmd);
-
 /**
  * enum isci_completion_selection - This enum defines the possible actions to
  *    take with respect to a given request's notification back to libsas.
@@ -321,40 +317,4 @@
 	return task_notification_selection;
 
 }
-/**
-* isci_execpath_callback() - This function is called from the task
-* execute path when the task needs to callback libsas about the submit-time
-* task failure.  The callback occurs either through the task's done function
-* or through sas_task_abort.  In the case of regular non-discovery SATA/STP I/O
-* requests, libsas takes the host lock before calling execute task.  Therefore
-* in this situation the host lock must be managed before calling the func.
-*
-* @ihost: This parameter is the controller to which the I/O request was sent.
-* @task: This parameter is the I/O request.
-* @func: This parameter is the function to call in the correct context.
-* @status: This parameter is the status code for the completed task.
-*
-*/
-static inline void isci_execpath_callback(struct isci_host *ihost,
-					  struct sas_task  *task,
-					  void (*func)(struct sas_task *))
-{
-	struct domain_device *dev = task->dev;
-
-	if (dev_is_sata(dev) && task->uldd_task) {
-		unsigned long flags;
-
-		/* Since we are still in the submit path, and since
-		 * libsas takes the host lock on behalf of SATA
-		 * devices before I/O starts (in the non-discovery case),
-		 * we need to unlock before we can call the callback function.
-		 */
-		raw_local_irq_save(flags);
-		spin_unlock(dev->sata_dev.ap->lock);
-		func(task);
-		spin_lock(dev->sata_dev.ap->lock);
-		raw_local_irq_restore(flags);
-	} else
-		func(task);
-}
 #endif /* !defined(_SCI_TASK_H_) */
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index db47158..453a740 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -684,10 +684,8 @@
 				       int buflen)
 {
 	struct iscsi_conn *conn = cls_conn->dd_data;
-	struct iscsi_session *session = conn->session;
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
 	struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
-	int value;
 
 	switch(param) {
 	case ISCSI_PARAM_HDRDGST_EN:
@@ -699,16 +697,7 @@
 			sock_no_sendpage : tcp_sw_conn->sock->ops->sendpage;
 		break;
 	case ISCSI_PARAM_MAX_R2T:
-		sscanf(buf, "%d", &value);
-		if (value <= 0 || !is_power_of_2(value))
-			return -EINVAL;
-		if (session->max_r2t == value)
-			break;
-		iscsi_tcp_r2tpool_free(session);
-		iscsi_set_param(cls_conn, param, buf, buflen);
-		if (iscsi_tcp_r2tpool_alloc(session))
-			return -ENOMEM;
-		break;
+		return iscsi_tcp_set_max_r2t(conn, buf);
 	default:
 		return iscsi_set_param(cls_conn, param, buf, buflen);
 	}
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
index 1d1b0c9..8e561e6 100644
--- a/drivers/scsi/libfc/fc_disc.c
+++ b/drivers/scsi/libfc/fc_disc.c
@@ -337,6 +337,13 @@
 			schedule_delayed_work(&disc->disc_work, delay);
 		} else
 			fc_disc_done(disc, DISC_EV_FAILED);
+	} else if (PTR_ERR(fp) == -FC_EX_CLOSED) {
+		/*
+		 * if discovery fails due to lport reset, clear
+		 * pending flag so that subsequent discovery can
+		 * continue
+		 */
+		disc->pending = 0;
 	}
 }
 
diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c
index e17a28d..c2384d5 100644
--- a/drivers/scsi/libfc/fc_elsct.c
+++ b/drivers/scsi/libfc/fc_elsct.c
@@ -56,8 +56,7 @@
 		rc = fc_els_fill(lport, did, fp, op, &r_ctl, &fh_type);
 	else {
 		/* CT requests */
-		rc = fc_ct_fill(lport, did, fp, op, &r_ctl, &fh_type);
-		did = FC_FID_DIR_SERV;
+		rc = fc_ct_fill(lport, did, fp, op, &r_ctl, &fh_type, &did);
 	}
 
 	if (rc) {
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index 4d70d96..aceffad 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -1642,9 +1642,10 @@
 		case FC_RCTL_ACK_0:
 			break;
 		default:
-			FC_EXCH_DBG(ep, "BLS rctl %x - %s received",
-				    fh->fh_r_ctl,
-				    fc_exch_rctl_name(fh->fh_r_ctl));
+			if (ep)
+				FC_EXCH_DBG(ep, "BLS rctl %x - %s received",
+					    fh->fh_r_ctl,
+					    fc_exch_rctl_name(fh->fh_r_ctl));
 			break;
 		}
 		fc_frame_free(fp);
@@ -2262,7 +2263,18 @@
 	mp->class = class;
 	/* adjust em exch xid range for offload */
 	mp->min_xid = min_xid;
-	mp->max_xid = max_xid;
+
+       /* reduce range so per cpu pool fits into PCPU_MIN_UNIT_SIZE pool */
+	pool_exch_range = (PCPU_MIN_UNIT_SIZE - sizeof(*pool)) /
+		sizeof(struct fc_exch *);
+	if ((max_xid - min_xid + 1) / (fc_cpu_mask + 1) > pool_exch_range) {
+		mp->max_xid = pool_exch_range * (fc_cpu_mask + 1) +
+			min_xid - 1;
+	} else {
+		mp->max_xid = max_xid;
+		pool_exch_range = (mp->max_xid - mp->min_xid + 1) /
+			(fc_cpu_mask + 1);
+	}
 
 	mp->ep_pool = mempool_create_slab_pool(2, fc_em_cachep);
 	if (!mp->ep_pool)
@@ -2273,7 +2285,6 @@
 	 * divided across all cpus. The exch pointers array memory is
 	 * allocated for exch range per pool.
 	 */
-	pool_exch_range = (mp->max_xid - mp->min_xid + 1) / (fc_cpu_mask + 1);
 	mp->pool_max_index = pool_exch_range - 1;
 
 	/*
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index b577c90..f735730 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -1074,8 +1074,7 @@
 	fsp->cdb_cmd.fc_dl = htonl(fsp->data_len);
 	fsp->cdb_cmd.fc_flags = fsp->req_flags & ~FCP_CFL_LEN_MASK;
 
-	int_to_scsilun(fsp->cmd->device->lun,
-		       (struct scsi_lun *)fsp->cdb_cmd.fc_lun);
+	int_to_scsilun(fsp->cmd->device->lun, &fsp->cdb_cmd.fc_lun);
 	memcpy(fsp->cdb_cmd.fc_cdb, fsp->cmd->cmnd, fsp->cmd->cmd_len);
 
 	spin_lock_irqsave(&si->scsi_queue_lock, flags);
@@ -1257,7 +1256,7 @@
 
 	fsp->cdb_cmd.fc_dl = htonl(fsp->data_len);
 	fsp->cdb_cmd.fc_tm_flags = FCP_TMF_LUN_RESET;
-	int_to_scsilun(lun, (struct scsi_lun *)fsp->cdb_cmd.fc_lun);
+	int_to_scsilun(lun, &fsp->cdb_cmd.fc_lun);
 
 	fsp->wait_for_comp = 1;
 	init_completion(&fsp->tm_done);
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index c1a808c..ef9560d 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -116,6 +116,8 @@
 static void fc_lport_enter_scr(struct fc_lport *);
 static void fc_lport_enter_ready(struct fc_lport *);
 static void fc_lport_enter_logo(struct fc_lport *);
+static void fc_lport_enter_fdmi(struct fc_lport *lport);
+static void fc_lport_enter_ms(struct fc_lport *, enum fc_lport_state);
 
 static const char *fc_lport_state_names[] = {
 	[LPORT_ST_DISABLED] = "disabled",
@@ -126,6 +128,11 @@
 	[LPORT_ST_RSPN_ID] =  "RSPN_ID",
 	[LPORT_ST_RFT_ID] =   "RFT_ID",
 	[LPORT_ST_RFF_ID] =   "RFF_ID",
+	[LPORT_ST_FDMI] =     "FDMI",
+	[LPORT_ST_RHBA] =     "RHBA",
+	[LPORT_ST_RPA] =      "RPA",
+	[LPORT_ST_DHBA] =     "DHBA",
+	[LPORT_ST_DPRT] =     "DPRT",
 	[LPORT_ST_SCR] =      "SCR",
 	[LPORT_ST_READY] =    "Ready",
 	[LPORT_ST_LOGO] =     "LOGO",
@@ -183,11 +190,14 @@
 		if (lport->state == LPORT_ST_DNS) {
 			lport->dns_rdata = rdata;
 			fc_lport_enter_ns(lport, LPORT_ST_RNN_ID);
+		} else if (lport->state == LPORT_ST_FDMI) {
+			lport->ms_rdata = rdata;
+			fc_lport_enter_ms(lport, LPORT_ST_DHBA);
 		} else {
 			FC_LPORT_DBG(lport, "Received an READY event "
 				     "on port (%6.6x) for the directory "
 				     "server, but the lport is not "
-				     "in the DNS state, it's in the "
+				     "in the DNS or FDMI state, it's in the "
 				     "%d state", rdata->ids.port_id,
 				     lport->state);
 			lport->tt.rport_logoff(rdata);
@@ -196,7 +206,10 @@
 	case RPORT_EV_LOGO:
 	case RPORT_EV_FAILED:
 	case RPORT_EV_STOP:
-		lport->dns_rdata = NULL;
+		if (rdata->ids.port_id == FC_FID_DIR_SERV)
+			lport->dns_rdata = NULL;
+		else if (rdata->ids.port_id == FC_FID_MGMT_SERV)
+			lport->ms_rdata = NULL;
 		break;
 	case RPORT_EV_NONE:
 		break;
@@ -1148,7 +1161,10 @@
 			fc_lport_enter_ns(lport, LPORT_ST_RFF_ID);
 			break;
 		case LPORT_ST_RFF_ID:
-			fc_lport_enter_scr(lport);
+			if (lport->fdmi_enabled)
+				fc_lport_enter_fdmi(lport);
+			else
+				fc_lport_enter_scr(lport);
 			break;
 		default:
 			/* should have already been caught by state checks */
@@ -1163,6 +1179,85 @@
 }
 
 /**
+ * fc_lport_ms_resp() - Handle response to a management server
+ *			exchange
+ * @sp:	    current sequence in exchange
+ * @fp:	    response frame
+ * @lp_arg: Fibre Channel host port instance
+ *
+ * Locking Note: This function will be called without the lport lock
+ * held, but it will lock, call an _enter_* function or fc_lport_error()
+ * and then unlock the lport.
+ */
+static void fc_lport_ms_resp(struct fc_seq *sp, struct fc_frame *fp,
+			     void *lp_arg)
+{
+	struct fc_lport *lport = lp_arg;
+	struct fc_frame_header *fh;
+	struct fc_ct_hdr *ct;
+
+	FC_LPORT_DBG(lport, "Received a ms %s\n", fc_els_resp_type(fp));
+
+	if (fp == ERR_PTR(-FC_EX_CLOSED))
+		return;
+
+	mutex_lock(&lport->lp_mutex);
+
+	if (lport->state < LPORT_ST_RHBA || lport->state > LPORT_ST_DPRT) {
+		FC_LPORT_DBG(lport, "Received a management server response, "
+			     "but in state %s\n", fc_lport_state(lport));
+		if (IS_ERR(fp))
+			goto err;
+		goto out;
+	}
+
+	if (IS_ERR(fp)) {
+		fc_lport_error(lport, fp);
+		goto err;
+	}
+
+	fh = fc_frame_header_get(fp);
+	ct = fc_frame_payload_get(fp, sizeof(*ct));
+
+	if (fh && ct && fh->fh_type == FC_TYPE_CT &&
+	    ct->ct_fs_type == FC_FST_MGMT &&
+	    ct->ct_fs_subtype == FC_FDMI_SUBTYPE) {
+		FC_LPORT_DBG(lport, "Received a management server response, "
+				    "reason=%d explain=%d\n",
+				    ct->ct_reason,
+				    ct->ct_explan);
+
+		switch (lport->state) {
+		case LPORT_ST_RHBA:
+			if (ntohs(ct->ct_cmd) == FC_FS_ACC)
+				fc_lport_enter_ms(lport, LPORT_ST_RPA);
+			else /* Error Skip RPA */
+				fc_lport_enter_scr(lport);
+			break;
+		case LPORT_ST_RPA:
+			fc_lport_enter_scr(lport);
+			break;
+		case LPORT_ST_DPRT:
+			fc_lport_enter_ms(lport, LPORT_ST_RHBA);
+			break;
+		case LPORT_ST_DHBA:
+			fc_lport_enter_ms(lport, LPORT_ST_DPRT);
+			break;
+		default:
+			/* should have already been caught by state checks */
+			break;
+		}
+	} else {
+		/* Invalid Frame? */
+		fc_lport_error(lport, fp);
+	}
+out:
+	fc_frame_free(fp);
+err:
+	mutex_unlock(&lport->lp_mutex);
+}
+
+/**
  * fc_lport_scr_resp() - Handle response to State Change Register (SCR) request
  * @sp:	    current sequence in SCR exchange
  * @fp:	    response frame
@@ -1339,6 +1434,123 @@
 }
 
 /**
+ * fc_lport_enter_ms() - management server commands
+ * @lport: Fibre Channel local port to register
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this routine.
+ */
+static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state)
+{
+	struct fc_frame *fp;
+	enum fc_fdmi_req cmd;
+	int size = sizeof(struct fc_ct_hdr);
+	size_t len;
+	int numattrs;
+
+	FC_LPORT_DBG(lport, "Entered %s state from %s state\n",
+		     fc_lport_state_names[state],
+		     fc_lport_state(lport));
+
+	fc_lport_state_enter(lport, state);
+
+	switch (state) {
+	case LPORT_ST_RHBA:
+		cmd = FC_FDMI_RHBA;
+		/* Number of HBA Attributes */
+		numattrs = 10;
+		len = sizeof(struct fc_fdmi_rhba);
+		len -= sizeof(struct fc_fdmi_attr_entry);
+		len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
+		len += FC_FDMI_HBA_ATTR_NODENAME_LEN;
+		len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN;
+		len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN;
+		len += FC_FDMI_HBA_ATTR_MODEL_LEN;
+		len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN;
+		len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN;
+		len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN;
+		len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN;
+		len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN;
+		len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN;
+
+		size += len;
+		break;
+	case LPORT_ST_RPA:
+		cmd = FC_FDMI_RPA;
+		/* Number of Port Attributes */
+		numattrs = 6;
+		len = sizeof(struct fc_fdmi_rpa);
+		len -= sizeof(struct fc_fdmi_attr_entry);
+		len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
+		len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN;
+		len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN;
+		len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN;
+		len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN;
+		len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN;
+		len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN;
+
+		size += len;
+		break;
+	case LPORT_ST_DPRT:
+		cmd = FC_FDMI_DPRT;
+		len = sizeof(struct fc_fdmi_dprt);
+		size += len;
+		break;
+	case LPORT_ST_DHBA:
+		cmd = FC_FDMI_DHBA;
+		len = sizeof(struct fc_fdmi_dhba);
+		size += len;
+		break;
+	default:
+		fc_lport_error(lport, NULL);
+		return;
+	}
+
+	FC_LPORT_DBG(lport, "Cmd=0x%x Len %d size %d\n",
+			     cmd, (int)len, size);
+	fp = fc_frame_alloc(lport, size);
+	if (!fp) {
+		fc_lport_error(lport, fp);
+		return;
+	}
+
+	if (!lport->tt.elsct_send(lport, FC_FID_MGMT_SERV, fp, cmd,
+				  fc_lport_ms_resp,
+				  lport, 3 * lport->r_a_tov))
+		fc_lport_error(lport, fp);
+}
+
+/**
+ * fc_rport_enter_fdmi() - Create a fc_rport for the management server
+ * @lport: The local port requesting a remote port for the management server
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this routine.
+ */
+static void fc_lport_enter_fdmi(struct fc_lport *lport)
+{
+	struct fc_rport_priv *rdata;
+
+	FC_LPORT_DBG(lport, "Entered FDMI state from %s state\n",
+		     fc_lport_state(lport));
+
+	fc_lport_state_enter(lport, LPORT_ST_FDMI);
+
+	mutex_lock(&lport->disc.disc_mutex);
+	rdata = lport->tt.rport_create(lport, FC_FID_MGMT_SERV);
+	mutex_unlock(&lport->disc.disc_mutex);
+	if (!rdata)
+		goto err;
+
+	rdata->ops = &fc_lport_rport_ops;
+	lport->tt.rport_login(rdata);
+	return;
+
+err:
+	fc_lport_error(lport, NULL);
+}
+
+/**
  * fc_lport_timeout() - Handler for the retry_work timer
  * @work: The work struct of the local port
  */
@@ -1371,6 +1583,15 @@
 	case LPORT_ST_RFF_ID:
 		fc_lport_enter_ns(lport, lport->state);
 		break;
+	case LPORT_ST_FDMI:
+		fc_lport_enter_fdmi(lport);
+		break;
+	case LPORT_ST_RHBA:
+	case LPORT_ST_RPA:
+	case LPORT_ST_DHBA:
+	case LPORT_ST_DPRT:
+		fc_lport_enter_ms(lport, lport->state);
+		break;
 	case LPORT_ST_SCR:
 		fc_lport_enter_scr(lport);
 		break;
@@ -1522,8 +1743,16 @@
 	mfs = ntohs(flp->fl_csp.sp_bb_data) &
 		FC_SP_BB_DATA_MASK;
 	if (mfs >= FC_SP_MIN_MAX_PAYLOAD &&
-	    mfs < lport->mfs)
+	    mfs <= lport->mfs) {
 		lport->mfs = mfs;
+		fc_host_maxframe_size(lport->host) = mfs;
+	} else {
+		FC_LPORT_DBG(lport, "FLOGI bad mfs:%hu response, "
+			     "lport->mfs:%hu\n", mfs, lport->mfs);
+		fc_lport_error(lport, fp);
+		goto err;
+	}
+
 	csp_flags = ntohs(flp->fl_csp.sp_features);
 	r_a_tov = ntohl(flp->fl_csp.sp_r_a_tov);
 	e_d_tov = ntohl(flp->fl_csp.sp_e_d_tov);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 143bbe4..82c3fd4 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1909,6 +1909,16 @@
 	ISCSI_DBG_EH(session, "scsi cmd %p timedout\n", sc);
 
 	spin_lock(&session->lock);
+	task = (struct iscsi_task *)sc->SCp.ptr;
+	if (!task) {
+		/*
+		 * Raced with completion. Blk layer has taken ownership
+		 * so let timeout code complete it now.
+		 */
+		rc = BLK_EH_HANDLED;
+		goto done;
+	}
+
 	if (session->state != ISCSI_STATE_LOGGED_IN) {
 		/*
 		 * We are probably in the middle of iscsi recovery so let
@@ -1925,16 +1935,6 @@
 		goto done;
 	}
 
-	task = (struct iscsi_task *)sc->SCp.ptr;
-	if (!task) {
-		/*
-		 * Raced with completion. Just reset timer, and let it
-		 * complete normally
-		 */
-		rc = BLK_EH_RESET_TIMER;
-		goto done;
-	}
-
 	/*
 	 * If we have sent (at least queued to the network layer) a pdu or
 	 * recvd one for the task since the last timeout ask for
@@ -2807,6 +2807,7 @@
 	kfree(session->username);
 	kfree(session->username_in);
 	kfree(session->targetname);
+	kfree(session->targetalias);
 	kfree(session->initiatorname);
 	kfree(session->ifacename);
 
@@ -3200,7 +3201,7 @@
 		sscanf(buf, "%d", &session->initial_r2t_en);
 		break;
 	case ISCSI_PARAM_MAX_R2T:
-		sscanf(buf, "%d", &session->max_r2t);
+		sscanf(buf, "%hu", &session->max_r2t);
 		break;
 	case ISCSI_PARAM_IMM_DATA_EN:
 		sscanf(buf, "%d", &session->imm_data_en);
@@ -3233,6 +3234,8 @@
 		return iscsi_switch_str_param(&session->password_in, buf);
 	case ISCSI_PARAM_TARGET_NAME:
 		return iscsi_switch_str_param(&session->targetname, buf);
+	case ISCSI_PARAM_TARGET_ALIAS:
+		return iscsi_switch_str_param(&session->targetalias, buf);
 	case ISCSI_PARAM_TPGT:
 		sscanf(buf, "%d", &session->tpgt);
 		break;
@@ -3299,6 +3302,9 @@
 	case ISCSI_PARAM_TARGET_NAME:
 		len = sprintf(buf, "%s\n", session->targetname);
 		break;
+	case ISCSI_PARAM_TARGET_ALIAS:
+		len = sprintf(buf, "%s\n", session->targetalias);
+		break;
 	case ISCSI_PARAM_TPGT:
 		len = sprintf(buf, "%d\n", session->tpgt);
 		break;
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index 7f0465b..552e8a2 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -1170,6 +1170,24 @@
 }
 EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_free);
 
+int iscsi_tcp_set_max_r2t(struct iscsi_conn *conn, char *buf)
+{
+	struct iscsi_session *session = conn->session;
+	unsigned short r2ts = 0;
+
+	sscanf(buf, "%hu", &r2ts);
+	if (session->max_r2t == r2ts)
+		return 0;
+
+	if (!r2ts || !is_power_of_2(r2ts))
+		return -EINVAL;
+
+	session->max_r2t = r2ts;
+	iscsi_tcp_r2tpool_free(session);
+	return iscsi_tcp_r2tpool_alloc(session);
+}
+EXPORT_SYMBOL_GPL(iscsi_tcp_set_max_r2t);
+
 void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn,
 			      struct iscsi_stats *stats)
 {
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index db9238f..bc0cecc 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -23,6 +23,8 @@
 
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
+#include <linux/async.h>
+#include <linux/export.h>
 
 #include <scsi/sas_ata.h>
 #include "sas_internal.h"
@@ -93,22 +95,47 @@
 static void sas_ata_task_done(struct sas_task *task)
 {
 	struct ata_queued_cmd *qc = task->uldd_task;
-	struct domain_device *dev;
+	struct domain_device *dev = task->dev;
 	struct task_status_struct *stat = &task->task_status;
 	struct ata_task_resp *resp = (struct ata_task_resp *)stat->buf;
-	struct sas_ha_struct *sas_ha;
+	struct sas_ha_struct *sas_ha = dev->port->ha;
 	enum ata_completion_errors ac;
 	unsigned long flags;
 	struct ata_link *link;
+	struct ata_port *ap;
+
+	spin_lock_irqsave(&dev->done_lock, flags);
+	if (test_bit(SAS_HA_FROZEN, &sas_ha->state))
+		task = NULL;
+	else if (qc && qc->scsicmd)
+		ASSIGN_SAS_TASK(qc->scsicmd, NULL);
+	spin_unlock_irqrestore(&dev->done_lock, flags);
+
+	/* check if libsas-eh got to the task before us */
+	if (unlikely(!task))
+		return;
 
 	if (!qc)
 		goto qc_already_gone;
 
-	dev = qc->ap->private_data;
-	sas_ha = dev->port->ha;
-	link = &dev->sata_dev.ap->link;
+	ap = qc->ap;
+	link = &ap->link;
 
-	spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
+	spin_lock_irqsave(ap->lock, flags);
+	/* check if we lost the race with libata/sas_ata_post_internal() */
+	if (unlikely(ap->pflags & ATA_PFLAG_FROZEN)) {
+		spin_unlock_irqrestore(ap->lock, flags);
+		if (qc->scsicmd)
+			goto qc_already_gone;
+		else {
+			/* if eh is not involved and the port is frozen then the
+			 * ata internal abort process has taken responsibility
+			 * for this sas_task
+			 */
+			return;
+		}
+	}
+
 	if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD ||
 	    ((stat->stat == SAM_STAT_CHECK_CONDITION &&
 	      dev->sata_dev.command_set == ATAPI_COMMAND_SET))) {
@@ -121,10 +148,6 @@
 			if (unlikely(link->eh_info.err_mask))
 				qc->flags |= ATA_QCFLAG_FAILED;
 		}
-
-		dev->sata_dev.sstatus = resp->sstatus;
-		dev->sata_dev.serror = resp->serror;
-		dev->sata_dev.scontrol = resp->scontrol;
 	} else {
 		ac = sas_to_ata_err(stat);
 		if (ac) {
@@ -144,24 +167,8 @@
 	}
 
 	qc->lldd_task = NULL;
-	if (qc->scsicmd)
-		ASSIGN_SAS_TASK(qc->scsicmd, NULL);
 	ata_qc_complete(qc);
-	spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
-
-	/*
-	 * If the sas_task has an ata qc, a scsi_cmnd and the aborted
-	 * flag is set, then we must have come in via the libsas EH
-	 * functions.  When we exit this function, we need to put the
-	 * scsi_cmnd on the list of finished errors.  The ata_qc_complete
-	 * call cleans up the libata side of things but we're protected
-	 * from the scsi_cmnd going away because the scsi_cmnd is owned
-	 * by the EH, making libata's call to scsi_done a NOP.
-	 */
-	spin_lock_irqsave(&task->task_state_lock, flags);
-	if (qc->scsicmd && task->task_state_flags & SAS_TASK_STATE_ABORTED)
-		scsi_eh_finish_cmd(qc->scsicmd, &sas_ha->eh_done_q);
-	spin_unlock_irqrestore(&task->task_state_lock, flags);
+	spin_unlock_irqrestore(ap->lock, flags);
 
 qc_already_gone:
 	list_del_init(&task->list);
@@ -170,23 +177,30 @@
 
 static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
 {
-	int res;
+	unsigned long flags;
 	struct sas_task *task;
-	struct domain_device *dev = qc->ap->private_data;
+	struct scatterlist *sg;
+	int ret = AC_ERR_SYSTEM;
+	unsigned int si, xfer = 0;
+	struct ata_port *ap = qc->ap;
+	struct domain_device *dev = ap->private_data;
 	struct sas_ha_struct *sas_ha = dev->port->ha;
 	struct Scsi_Host *host = sas_ha->core.shost;
 	struct sas_internal *i = to_sas_internal(host->transportt);
-	struct scatterlist *sg;
-	unsigned int xfer = 0;
-	unsigned int si;
+
+	/* TODO: audit callers to ensure they are ready for qc_issue to
+	 * unconditionally re-enable interrupts
+	 */
+	local_irq_save(flags);
+	spin_unlock(ap->lock);
 
 	/* If the device fell off, no sense in issuing commands */
-	if (dev->gone)
-		return AC_ERR_SYSTEM;
+	if (test_bit(SAS_DEV_GONE, &dev->state))
+		goto out;
 
 	task = sas_alloc_task(GFP_ATOMIC);
 	if (!task)
-		return AC_ERR_SYSTEM;
+		goto out;
 	task->dev = dev;
 	task->task_proto = SAS_PROTOCOL_STP;
 	task->task_done = sas_ata_task_done;
@@ -231,21 +245,24 @@
 		ASSIGN_SAS_TASK(qc->scsicmd, task);
 
 	if (sas_ha->lldd_max_execute_num < 2)
-		res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC);
+		ret = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC);
 	else
-		res = sas_queue_up(task);
+		ret = sas_queue_up(task);
 
 	/* Examine */
-	if (res) {
-		SAS_DPRINTK("lldd_execute_task returned: %d\n", res);
+	if (ret) {
+		SAS_DPRINTK("lldd_execute_task returned: %d\n", ret);
 
 		if (qc->scsicmd)
 			ASSIGN_SAS_TASK(qc->scsicmd, NULL);
 		sas_free_task(task);
-		return AC_ERR_SYSTEM;
+		ret = AC_ERR_SYSTEM;
 	}
 
-	return 0;
+ out:
+	spin_lock(ap->lock);
+	local_irq_restore(flags);
+	return ret;
 }
 
 static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc)
@@ -256,81 +273,220 @@
 	return true;
 }
 
-static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class,
-			       unsigned long deadline)
+static struct sas_internal *dev_to_sas_internal(struct domain_device *dev)
+{
+	return to_sas_internal(dev->port->ha->core.shost->transportt);
+}
+
+static void sas_get_ata_command_set(struct domain_device *dev);
+
+int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy)
+{
+	if (phy->attached_tproto & SAS_PROTOCOL_STP)
+		dev->tproto = phy->attached_tproto;
+	if (phy->attached_sata_dev)
+		dev->tproto |= SATA_DEV;
+
+	if (phy->attached_dev_type == SATA_PENDING)
+		dev->dev_type = SATA_PENDING;
+	else {
+		int res;
+
+		dev->dev_type = SATA_DEV;
+		res = sas_get_report_phy_sata(dev->parent, phy->phy_id,
+					      &dev->sata_dev.rps_resp);
+		if (res) {
+			SAS_DPRINTK("report phy sata to %016llx:0x%x returned "
+				    "0x%x\n", SAS_ADDR(dev->parent->sas_addr),
+				    phy->phy_id, res);
+			return res;
+		}
+		memcpy(dev->frame_rcvd, &dev->sata_dev.rps_resp.rps.fis,
+		       sizeof(struct dev_to_host_fis));
+		/* TODO switch to ata_dev_classify() */
+		sas_get_ata_command_set(dev);
+	}
+	return 0;
+}
+
+static int sas_ata_clear_pending(struct domain_device *dev, struct ex_phy *phy)
+{
+	int res;
+
+	/* we weren't pending, so successfully end the reset sequence now */
+	if (dev->dev_type != SATA_PENDING)
+		return 1;
+
+	/* hmmm, if this succeeds do we need to repost the domain_device to the
+	 * lldd so it can pick up new parameters?
+	 */
+	res = sas_get_ata_info(dev, phy);
+	if (res)
+		return 0; /* retry */
+	else
+		return 1;
+}
+
+static int smp_ata_check_ready(struct ata_link *link)
+{
+	int res;
+	struct ata_port *ap = link->ap;
+	struct domain_device *dev = ap->private_data;
+	struct domain_device *ex_dev = dev->parent;
+	struct sas_phy *phy = sas_get_local_phy(dev);
+	struct ex_phy *ex_phy = &ex_dev->ex_dev.ex_phy[phy->number];
+
+	res = sas_ex_phy_discover(ex_dev, phy->number);
+	sas_put_local_phy(phy);
+
+	/* break the wait early if the expander is unreachable,
+	 * otherwise keep polling
+	 */
+	if (res == -ECOMM)
+		return res;
+	if (res != SMP_RESP_FUNC_ACC)
+		return 0;
+
+	switch (ex_phy->attached_dev_type) {
+	case SATA_PENDING:
+		return 0;
+	case SAS_END_DEV:
+		if (ex_phy->attached_sata_dev)
+			return sas_ata_clear_pending(dev, ex_phy);
+	default:
+		return -ENODEV;
+	}
+}
+
+static int local_ata_check_ready(struct ata_link *link)
 {
 	struct ata_port *ap = link->ap;
 	struct domain_device *dev = ap->private_data;
-	struct sas_internal *i =
-		to_sas_internal(dev->port->ha->core.shost->transportt);
-	int res = TMF_RESP_FUNC_FAILED;
-	int ret = 0;
+	struct sas_internal *i = dev_to_sas_internal(dev);
 
-	if (i->dft->lldd_I_T_nexus_reset)
-		res = i->dft->lldd_I_T_nexus_reset(dev);
-
-	if (res != TMF_RESP_FUNC_COMPLETE) {
-		SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __func__);
-		ret = -EAGAIN;
+	if (i->dft->lldd_ata_check_ready)
+		return i->dft->lldd_ata_check_ready(dev);
+	else {
+		/* lldd's that don't implement 'ready' checking get the
+		 * old default behavior of not coordinating reset
+		 * recovery with libata
+		 */
+		return 1;
 	}
+}
 
+static int sas_ata_printk(const char *level, const struct domain_device *ddev,
+			  const char *fmt, ...)
+{
+	struct ata_port *ap = ddev->sata_dev.ap;
+	struct device *dev = &ddev->rphy->dev;
+	struct va_format vaf;
+	va_list args;
+	int r;
+
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	r = printk("%ssas: ata%u: %s: %pV",
+		   level, ap->print_id, dev_name(dev), &vaf);
+
+	va_end(args);
+
+	return r;
+}
+
+static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class,
+			      unsigned long deadline)
+{
+	int ret = 0, res;
+	struct sas_phy *phy;
+	struct ata_port *ap = link->ap;
+	int (*check_ready)(struct ata_link *link);
+	struct domain_device *dev = ap->private_data;
+	struct sas_internal *i = dev_to_sas_internal(dev);
+
+	res = i->dft->lldd_I_T_nexus_reset(dev);
+	if (res == -ENODEV)
+		return res;
+
+	if (res != TMF_RESP_FUNC_COMPLETE)
+		sas_ata_printk(KERN_DEBUG, dev, "Unable to reset ata device?\n");
+
+	phy = sas_get_local_phy(dev);
+	if (scsi_is_sas_phy_local(phy))
+		check_ready = local_ata_check_ready;
+	else
+		check_ready = smp_ata_check_ready;
+	sas_put_local_phy(phy);
+
+	ret = ata_wait_after_reset(link, deadline, check_ready);
+	if (ret && ret != -EAGAIN)
+		sas_ata_printk(KERN_ERR, dev, "reset failed (errno=%d)\n", ret);
+
+	/* XXX: if the class changes during the reset the upper layer
+	 * should be informed, if the device has gone away we assume
+	 * libsas will eventually delete it
+	 */
 	switch (dev->sata_dev.command_set) {
-		case ATA_COMMAND_SET:
-			SAS_DPRINTK("%s: Found ATA device.\n", __func__);
-			*class = ATA_DEV_ATA;
-			break;
-		case ATAPI_COMMAND_SET:
-			SAS_DPRINTK("%s: Found ATAPI device.\n", __func__);
-			*class = ATA_DEV_ATAPI;
-			break;
-		default:
-			SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
-				    __func__,
-				    dev->sata_dev.command_set);
-			*class = ATA_DEV_UNKNOWN;
-			break;
+	case ATA_COMMAND_SET:
+		*class = ATA_DEV_ATA;
+		break;
+	case ATAPI_COMMAND_SET:
+		*class = ATA_DEV_ATAPI;
+		break;
 	}
 
 	ap->cbl = ATA_CBL_SATA;
 	return ret;
 }
 
-static int sas_ata_soft_reset(struct ata_link *link, unsigned int *class,
-			       unsigned long deadline)
+/*
+ * notify the lldd to forget the sas_task for this internal ata command
+ * that bypasses scsi-eh
+ */
+static void sas_ata_internal_abort(struct sas_task *task)
 {
-	struct ata_port *ap = link->ap;
-	struct domain_device *dev = ap->private_data;
-	struct sas_internal *i =
-		to_sas_internal(dev->port->ha->core.shost->transportt);
-	int res = TMF_RESP_FUNC_FAILED;
-	int ret = 0;
+	struct sas_internal *si = dev_to_sas_internal(task->dev);
+	unsigned long flags;
+	int res;
 
-	if (i->dft->lldd_ata_soft_reset)
-		res = i->dft->lldd_ata_soft_reset(dev);
+	spin_lock_irqsave(&task->task_state_lock, flags);
+	if (task->task_state_flags & SAS_TASK_STATE_ABORTED ||
+	    task->task_state_flags & SAS_TASK_STATE_DONE) {
+		spin_unlock_irqrestore(&task->task_state_lock, flags);
+		SAS_DPRINTK("%s: Task %p already finished.\n", __func__,
+			    task);
+		goto out;
+	}
+	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
 
-	if (res != TMF_RESP_FUNC_COMPLETE) {
-		SAS_DPRINTK("%s: Unable to soft reset\n", __func__);
-		ret = -EAGAIN;
+	res = si->dft->lldd_abort_task(task);
+
+	spin_lock_irqsave(&task->task_state_lock, flags);
+	if (task->task_state_flags & SAS_TASK_STATE_DONE ||
+	    res == TMF_RESP_FUNC_COMPLETE) {
+		spin_unlock_irqrestore(&task->task_state_lock, flags);
+		goto out;
 	}
 
-	switch (dev->sata_dev.command_set) {
-	case ATA_COMMAND_SET:
-		SAS_DPRINTK("%s: Found ATA device.\n", __func__);
-		*class = ATA_DEV_ATA;
-		break;
-	case ATAPI_COMMAND_SET:
-		SAS_DPRINTK("%s: Found ATAPI device.\n", __func__);
-		*class = ATA_DEV_ATAPI;
-		break;
-	default:
-		SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
-			    __func__, dev->sata_dev.command_set);
-		*class = ATA_DEV_UNKNOWN;
-		break;
-	}
+	/* XXX we are not prepared to deal with ->lldd_abort_task()
+	 * failures.  TODO: lldds need to unconditionally forget about
+	 * aborted ata tasks, otherwise we (likely) leak the sas task
+	 * here
+	 */
+	SAS_DPRINTK("%s: Task %p leaked.\n", __func__, task);
 
-	ap->cbl = ATA_CBL_SATA;
-	return ret;
+	if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+		task->task_state_flags &= ~SAS_TASK_STATE_ABORTED;
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+	return;
+ out:
+	list_del_init(&task->list);
+	sas_free_task(task);
 }
 
 static void sas_ata_post_internal(struct ata_queued_cmd *qc)
@@ -340,30 +496,35 @@
 
 	if (qc->err_mask) {
 		/*
-		 * Find the sas_task and kill it.  By this point,
-		 * libata has decided to kill the qc, so we needn't
-		 * bother with sas_ata_task_done.  But we still
-		 * ought to abort the task.
+		 * Find the sas_task and kill it.  By this point, libata
+		 * has decided to kill the qc and has frozen the port.
+		 * In this state sas_ata_task_done() will no longer free
+		 * the sas_task, so we need to notify the lldd (via
+		 * ->lldd_abort_task) that the task is dead and free it
+		 *  ourselves.
 		 */
 		struct sas_task *task = qc->lldd_task;
-		unsigned long flags;
 
 		qc->lldd_task = NULL;
-		if (task) {
-			/* Should this be a AT(API) device reset? */
-			spin_lock_irqsave(&task->task_state_lock, flags);
-			task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
-			spin_unlock_irqrestore(&task->task_state_lock, flags);
-
-			task->uldd_task = NULL;
-			__sas_task_abort(task);
-		}
+		if (!task)
+			return;
+		task->uldd_task = NULL;
+		sas_ata_internal_abort(task);
 	}
 }
 
+
+static void sas_ata_set_dmamode(struct ata_port *ap, struct ata_device *ata_dev)
+{
+	struct domain_device *dev = ap->private_data;
+	struct sas_internal *i = dev_to_sas_internal(dev);
+
+	if (i->dft->lldd_ata_set_dmamode)
+		i->dft->lldd_ata_set_dmamode(dev);
+}
+
 static struct ata_port_operations sas_sata_ops = {
 	.prereset		= ata_std_prereset,
-	.softreset		= sas_ata_soft_reset,
 	.hardreset		= sas_ata_hard_reset,
 	.postreset		= ata_std_postreset,
 	.error_handler		= ata_std_error_handler,
@@ -374,6 +535,7 @@
 	.qc_fill_rtf		= sas_ata_qc_fill_rtf,
 	.port_start		= ata_sas_port_start,
 	.port_stop		= ata_sas_port_stop,
+	.set_dmamode		= sas_ata_set_dmamode,
 };
 
 static struct ata_port_info sata_port_info = {
@@ -384,11 +546,10 @@
 	.port_ops = &sas_sata_ops
 };
 
-int sas_ata_init_host_and_port(struct domain_device *found_dev,
-			       struct scsi_target *starget)
+int sas_ata_init_host_and_port(struct domain_device *found_dev)
 {
-	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
-	struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+	struct sas_ha_struct *ha = found_dev->port->ha;
+	struct Scsi_Host *shost = ha->core.shost;
 	struct ata_port *ap;
 
 	ata_host_init(&found_dev->sata_dev.ata_host,
@@ -406,6 +567,8 @@
 	ap->private_data = found_dev;
 	ap->cbl = ATA_CBL_SATA;
 	ap->scsi_host = shost;
+	/* publish initialized ata port */
+	smp_wmb();
 	found_dev->sata_dev.ap = ap;
 
 	return 0;
@@ -436,168 +599,14 @@
 	complete(waiting);
 }
 
-static void sas_task_timedout(unsigned long _task)
-{
-	struct sas_task *task = (void *) _task;
-	unsigned long flags;
-
-	spin_lock_irqsave(&task->task_state_lock, flags);
-	if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
-		task->task_state_flags |= SAS_TASK_STATE_ABORTED;
-	spin_unlock_irqrestore(&task->task_state_lock, flags);
-
-	complete(&task->completion);
-}
-
-static void sas_disc_task_done(struct sas_task *task)
-{
-	if (!del_timer(&task->timer))
-		return;
-	complete(&task->completion);
-}
-
-#define SAS_DEV_TIMEOUT 10
-
-/**
- * sas_execute_task -- Basic task processing for discovery
- * @task: the task to be executed
- * @buffer: pointer to buffer to do I/O
- * @size: size of @buffer
- * @dma_dir: DMA direction.  DMA_xxx
- */
-static int sas_execute_task(struct sas_task *task, void *buffer, int size,
-			    enum dma_data_direction dma_dir)
-{
-	int res = 0;
-	struct scatterlist *scatter = NULL;
-	struct task_status_struct *ts = &task->task_status;
-	int num_scatter = 0;
-	int retries = 0;
-	struct sas_internal *i =
-		to_sas_internal(task->dev->port->ha->core.shost->transportt);
-
-	if (dma_dir != DMA_NONE) {
-		scatter = kzalloc(sizeof(*scatter), GFP_KERNEL);
-		if (!scatter)
-			goto out;
-
-		sg_init_one(scatter, buffer, size);
-		num_scatter = 1;
-	}
-
-	task->task_proto = task->dev->tproto;
-	task->scatter = scatter;
-	task->num_scatter = num_scatter;
-	task->total_xfer_len = size;
-	task->data_dir = dma_dir;
-	task->task_done = sas_disc_task_done;
-	if (dma_dir != DMA_NONE &&
-	    sas_protocol_ata(task->task_proto)) {
-		task->num_scatter = dma_map_sg(task->dev->port->ha->dev,
-					       task->scatter,
-					       task->num_scatter,
-					       task->data_dir);
-	}
-
-	for (retries = 0; retries < 5; retries++) {
-		task->task_state_flags = SAS_TASK_STATE_PENDING;
-		init_completion(&task->completion);
-
-		task->timer.data = (unsigned long) task;
-		task->timer.function = sas_task_timedout;
-		task->timer.expires = jiffies + SAS_DEV_TIMEOUT*HZ;
-		add_timer(&task->timer);
-
-		res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
-		if (res) {
-			del_timer(&task->timer);
-			SAS_DPRINTK("executing SAS discovery task failed:%d\n",
-				    res);
-			goto ex_err;
-		}
-		wait_for_completion(&task->completion);
-		res = -ECOMM;
-		if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
-			int res2;
-			SAS_DPRINTK("task aborted, flags:0x%x\n",
-				    task->task_state_flags);
-			res2 = i->dft->lldd_abort_task(task);
-			SAS_DPRINTK("came back from abort task\n");
-			if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
-				if (res2 == TMF_RESP_FUNC_COMPLETE)
-					continue; /* Retry the task */
-				else
-					goto ex_err;
-			}
-		}
-		if (task->task_status.stat == SAM_STAT_BUSY ||
-			   task->task_status.stat == SAM_STAT_TASK_SET_FULL ||
-			   task->task_status.stat == SAS_QUEUE_FULL) {
-			SAS_DPRINTK("task: q busy, sleeping...\n");
-			schedule_timeout_interruptible(HZ);
-		} else if (task->task_status.stat == SAM_STAT_CHECK_CONDITION) {
-			struct scsi_sense_hdr shdr;
-
-			if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size,
-						  &shdr)) {
-				SAS_DPRINTK("couldn't normalize sense\n");
-				continue;
-			}
-			if ((shdr.sense_key == 6 && shdr.asc == 0x29) ||
-			    (shdr.sense_key == 2 && shdr.asc == 4 &&
-			     shdr.ascq == 1)) {
-				SAS_DPRINTK("device %016llx LUN: %016llx "
-					    "powering up or not ready yet, "
-					    "sleeping...\n",
-					    SAS_ADDR(task->dev->sas_addr),
-					    SAS_ADDR(task->ssp_task.LUN));
-
-				schedule_timeout_interruptible(5*HZ);
-			} else if (shdr.sense_key == 1) {
-				res = 0;
-				break;
-			} else if (shdr.sense_key == 5) {
-				break;
-			} else {
-				SAS_DPRINTK("dev %016llx LUN: %016llx "
-					    "sense key:0x%x ASC:0x%x ASCQ:0x%x"
-					    "\n",
-					    SAS_ADDR(task->dev->sas_addr),
-					    SAS_ADDR(task->ssp_task.LUN),
-					    shdr.sense_key,
-					    shdr.asc, shdr.ascq);
-			}
-		} else if (task->task_status.resp != SAS_TASK_COMPLETE ||
-			   task->task_status.stat != SAM_STAT_GOOD) {
-			SAS_DPRINTK("task finished with resp:0x%x, "
-				    "stat:0x%x\n",
-				    task->task_status.resp,
-				    task->task_status.stat);
-			goto ex_err;
-		} else {
-			res = 0;
-			break;
-		}
-	}
-ex_err:
-	if (dma_dir != DMA_NONE) {
-		if (sas_protocol_ata(task->task_proto))
-			dma_unmap_sg(task->dev->port->ha->dev,
-				     task->scatter, task->num_scatter,
-				     task->data_dir);
-		kfree(scatter);
-	}
-out:
-	return res;
-}
-
-/* ---------- SATA ---------- */
-
 static void sas_get_ata_command_set(struct domain_device *dev)
 {
 	struct dev_to_host_fis *fis =
 		(struct dev_to_host_fis *) dev->frame_rcvd;
 
+	if (dev->dev_type == SATA_PENDING)
+		return;
+
 	if ((fis->sector_count == 1 && /* ATA */
 	     fis->lbal         == 1 &&
 	     fis->lbam         == 0 &&
@@ -636,224 +645,152 @@
 		dev->sata_dev.command_set = ATAPI_COMMAND_SET;
 }
 
-/**
- * sas_issue_ata_cmd -- Basic SATA command processing for discovery
- * @dev: the device to send the command to
- * @command: the command register
- * @features: the features register
- * @buffer: pointer to buffer to do I/O
- * @size: size of @buffer
- * @dma_dir: DMA direction.  DMA_xxx
- */
-static int sas_issue_ata_cmd(struct domain_device *dev, u8 command,
-			     u8 features, void *buffer, int size,
-			     enum dma_data_direction dma_dir)
+void sas_probe_sata(struct asd_sas_port *port)
 {
-	int res = 0;
-	struct sas_task *task;
-	struct dev_to_host_fis *d2h_fis = (struct dev_to_host_fis *)
-		&dev->frame_rcvd[0];
+	struct domain_device *dev, *n;
+	int err;
 
-	res = -ENOMEM;
-	task = sas_alloc_task(GFP_KERNEL);
-	if (!task)
-		goto out;
+	mutex_lock(&port->ha->disco_mutex);
+	list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) {
+		if (!dev_is_sata(dev))
+			continue;
 
-	task->dev = dev;
-
-	task->ata_task.fis.fis_type = 0x27;
-	task->ata_task.fis.command = command;
-	task->ata_task.fis.features = features;
-	task->ata_task.fis.device = d2h_fis->device;
-	task->ata_task.retry_count = 1;
-
-	res = sas_execute_task(task, buffer, size, dma_dir);
-
-	sas_free_task(task);
-out:
-	return res;
-}
-
-#define ATA_IDENTIFY_DEV         0xEC
-#define ATA_IDENTIFY_PACKET_DEV  0xA1
-#define ATA_SET_FEATURES         0xEF
-#define ATA_FEATURE_PUP_STBY_SPIN_UP 0x07
-
-/**
- * sas_discover_sata_dev -- discover a STP/SATA device (SATA_DEV)
- * @dev: STP/SATA device of interest (ATA/ATAPI)
- *
- * The LLDD has already been notified of this device, so that we can
- * send FISes to it.  Here we try to get IDENTIFY DEVICE or IDENTIFY
- * PACKET DEVICE, if ATAPI device, so that the LLDD can fine-tune its
- * performance for this device.
- */
-static int sas_discover_sata_dev(struct domain_device *dev)
-{
-	int     res;
-	__le16  *identify_x;
-	u8      command;
-
-	identify_x = kzalloc(512, GFP_KERNEL);
-	if (!identify_x)
-		return -ENOMEM;
-
-	if (dev->sata_dev.command_set == ATA_COMMAND_SET) {
-		dev->sata_dev.identify_device = identify_x;
-		command = ATA_IDENTIFY_DEV;
-	} else {
-		dev->sata_dev.identify_packet_device = identify_x;
-		command = ATA_IDENTIFY_PACKET_DEV;
+		err = sas_ata_init_host_and_port(dev);
+		if (err)
+			sas_fail_probe(dev, __func__, err);
+		else
+			ata_sas_async_port_init(dev->sata_dev.ap);
 	}
+	mutex_unlock(&port->ha->disco_mutex);
 
-	res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
-				DMA_FROM_DEVICE);
-	if (res)
-		goto out_err;
+	list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) {
+		if (!dev_is_sata(dev))
+			continue;
 
-	/* lives on the media? */
-	if (le16_to_cpu(identify_x[0]) & 4) {
-		/* incomplete response */
-		SAS_DPRINTK("sending SET FEATURE/PUP_STBY_SPIN_UP to "
-			    "dev %llx\n", SAS_ADDR(dev->sas_addr));
-		if (!(identify_x[83] & cpu_to_le16(1<<6)))
-			goto cont1;
-		res = sas_issue_ata_cmd(dev, ATA_SET_FEATURES,
-					ATA_FEATURE_PUP_STBY_SPIN_UP,
-					NULL, 0, DMA_NONE);
-		if (res)
-			goto cont1;
+		sas_ata_wait_eh(dev);
 
-		schedule_timeout_interruptible(5*HZ); /* More time? */
-		res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
-					DMA_FROM_DEVICE);
-		if (res)
-			goto out_err;
+		/* if libata could not bring the link up, don't surface
+		 * the device
+		 */
+		if (ata_dev_disabled(sas_to_ata_dev(dev)))
+			sas_fail_probe(dev, __func__, -ENODEV);
 	}
-cont1:
-	/* XXX Hint: register this SATA device with SATL.
-	   When this returns, dev->sata_dev->lu is alive and
-	   present.
-	sas_satl_register_dev(dev);
-	*/
-
-	sas_fill_in_rphy(dev, dev->rphy);
-
-	return 0;
-out_err:
-	dev->sata_dev.identify_packet_device = NULL;
-	dev->sata_dev.identify_device = NULL;
-	kfree(identify_x);
-	return res;
-}
-
-static int sas_discover_sata_pm(struct domain_device *dev)
-{
-	return -ENODEV;
 }
 
 /**
  * sas_discover_sata -- discover an STP/SATA domain device
  * @dev: pointer to struct domain_device of interest
  *
- * First we notify the LLDD of this device, so we can send frames to
- * it.  Then depending on the type of device we call the appropriate
- * discover functions.  Once device discover is done, we notify the
- * LLDD so that it can fine-tune its parameters for the device, by
- * removing it and then adding it.  That is, the second time around,
- * the driver would have certain fields, that it is looking at, set.
- * Finally we initialize the kobj so that the device can be added to
- * the system at registration time.  Devices directly attached to a HA
- * port, have no parents.  All other devices do, and should have their
- * "parent" pointer set appropriately before calling this function.
+ * Devices directly attached to a HA port, have no parents.  All other
+ * devices do, and should have their "parent" pointer set appropriately
+ * before calling this function.
  */
 int sas_discover_sata(struct domain_device *dev)
 {
 	int res;
 
+	if (dev->dev_type == SATA_PM)
+		return -ENODEV;
+
 	sas_get_ata_command_set(dev);
+	sas_fill_in_rphy(dev, dev->rphy);
 
 	res = sas_notify_lldd_dev_found(dev);
 	if (res)
 		return res;
 
-	switch (dev->dev_type) {
-	case SATA_DEV:
-		res = sas_discover_sata_dev(dev);
-		break;
-	case SATA_PM:
-		res = sas_discover_sata_pm(dev);
-		break;
-	default:
-		break;
-	}
-	sas_notify_lldd_dev_gone(dev);
-	if (!res) {
-		sas_notify_lldd_dev_found(dev);
-		res = sas_rphy_add(dev->rphy);
-	}
+	sas_discover_event(dev->port, DISCE_PROBE);
+	return 0;
+}
 
-	return res;
+static void async_sas_ata_eh(void *data, async_cookie_t cookie)
+{
+	struct domain_device *dev = data;
+	struct ata_port *ap = dev->sata_dev.ap;
+	struct sas_ha_struct *ha = dev->port->ha;
+
+	/* hold a reference over eh since we may be racing with final
+	 * remove once all commands are completed
+	 */
+	kref_get(&dev->kref);
+	sas_ata_printk(KERN_DEBUG, dev, "dev error handler\n");
+	ata_scsi_port_error_handler(ha->core.shost, ap);
+	sas_put_device(dev);
+}
+
+static bool sas_ata_dev_eh_valid(struct domain_device *dev)
+{
+	struct ata_port *ap;
+
+	if (!dev_is_sata(dev))
+		return false;
+	ap = dev->sata_dev.ap;
+	/* consume fully initialized ata ports */
+	smp_rmb();
+	return !!ap;
 }
 
 void sas_ata_strategy_handler(struct Scsi_Host *shost)
 {
-	struct scsi_device *sdev;
+	struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
+	LIST_HEAD(async);
+	int i;
 
-	shost_for_each_device(sdev, shost) {
-		struct domain_device *ddev = sdev_to_domain_dev(sdev);
-		struct ata_port *ap = ddev->sata_dev.ap;
+	/* it's ok to defer revalidation events during ata eh, these
+	 * disks are in one of three states:
+	 * 1/ present for initial domain discovery, and these
+	 *    resets will cause bcn flutters
+	 * 2/ hot removed, we'll discover that after eh fails
+	 * 3/ hot added after initial discovery, lost the race, and need
+	 *    to catch the next train.
+	 */
+	sas_disable_revalidation(sas_ha);
 
-		if (!dev_is_sata(ddev))
-			continue;
+	spin_lock_irq(&sas_ha->phy_port_lock);
+	for (i = 0; i < sas_ha->num_phys; i++) {
+		struct asd_sas_port *port = sas_ha->sas_port[i];
+		struct domain_device *dev;
 
-		ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata port error handler");
-		ata_scsi_port_error_handler(shost, ap);
+		spin_lock(&port->dev_list_lock);
+		list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+			if (!sas_ata_dev_eh_valid(dev))
+				continue;
+			async_schedule_domain(async_sas_ata_eh, dev, &async);
+		}
+		spin_unlock(&port->dev_list_lock);
 	}
+	spin_unlock_irq(&sas_ha->phy_port_lock);
+
+	async_synchronize_full_domain(&async);
+
+	sas_enable_revalidation(sas_ha);
 }
 
-int sas_ata_timed_out(struct scsi_cmnd *cmd, struct sas_task *task,
-		      enum blk_eh_timer_return *rtn)
+void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
+		struct list_head *done_q)
 {
-	struct domain_device *ddev = cmd_to_domain_dev(cmd);
-
-	if (!dev_is_sata(ddev) || task)
-		return 0;
-
-	/* we're a sata device with no task, so this must be a libata
-	 * eh timeout.  Ideally should hook into libata timeout
-	 * handling, but there's no point, it just wants to activate
-	 * the eh thread */
-	*rtn = BLK_EH_NOT_HANDLED;
-	return 1;
-}
-
-int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
-	       struct list_head *done_q)
-{
-	int rtn = 0;
 	struct scsi_cmnd *cmd, *n;
-	struct ata_port *ap;
+	struct domain_device *eh_dev;
 
 	do {
 		LIST_HEAD(sata_q);
-
-		ap = NULL;
+		eh_dev = NULL;
 
 		list_for_each_entry_safe(cmd, n, work_q, eh_entry) {
 			struct domain_device *ddev = cmd_to_domain_dev(cmd);
 
 			if (!dev_is_sata(ddev) || TO_SAS_TASK(cmd))
 				continue;
-			if (ap && ap != ddev->sata_dev.ap)
+			if (eh_dev && eh_dev != ddev)
 				continue;
-			ap = ddev->sata_dev.ap;
-			rtn = 1;
+			eh_dev = ddev;
 			list_move(&cmd->eh_entry, &sata_q);
 		}
 
 		if (!list_empty(&sata_q)) {
-			ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata cmd error handler\n");
+			struct ata_port *ap = eh_dev->sata_dev.ap;
+
+			sas_ata_printk(KERN_DEBUG, eh_dev, "cmd error handler\n");
 			ata_scsi_cmd_error_handler(shost, ap, &sata_q);
 			/*
 			 * ata's error handler may leave the cmd on the list
@@ -869,7 +806,36 @@
 			while (!list_empty(&sata_q))
 				list_del_init(sata_q.next);
 		}
-	} while (ap);
+	} while (eh_dev);
+}
 
-	return rtn;
+void sas_ata_schedule_reset(struct domain_device *dev)
+{
+	struct ata_eh_info *ehi;
+	struct ata_port *ap;
+	unsigned long flags;
+
+	if (!dev_is_sata(dev))
+		return;
+
+	ap = dev->sata_dev.ap;
+	ehi = &ap->link.eh_info;
+
+	spin_lock_irqsave(ap->lock, flags);
+	ehi->err_mask |= AC_ERR_TIMEOUT;
+	ehi->action |= ATA_EH_RESET;
+	ata_port_schedule_eh(ap);
+	spin_unlock_irqrestore(ap->lock, flags);
+}
+EXPORT_SYMBOL_GPL(sas_ata_schedule_reset);
+
+void sas_ata_wait_eh(struct domain_device *dev)
+{
+	struct ata_port *ap;
+
+	if (!dev_is_sata(dev))
+		return;
+
+	ap = dev->sata_dev.ap;
+	ata_port_wait_eh(ap);
 }
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 54a5199..3646796 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -30,29 +30,30 @@
 
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_transport_sas.h>
+#include <scsi/sas_ata.h>
 #include "../scsi_sas_internal.h"
 
 /* ---------- Basic task processing for discovery purposes ---------- */
 
 void sas_init_dev(struct domain_device *dev)
 {
-        INIT_LIST_HEAD(&dev->siblings);
-        INIT_LIST_HEAD(&dev->dev_list_node);
-        switch (dev->dev_type) {
-        case SAS_END_DEV:
-                break;
-        case EDGE_DEV:
-        case FANOUT_DEV:
-                INIT_LIST_HEAD(&dev->ex_dev.children);
-                break;
-        case SATA_DEV:
-        case SATA_PM:
-        case SATA_PM_PORT:
-                INIT_LIST_HEAD(&dev->sata_dev.children);
-                break;
-        default:
-                break;
-        }
+	switch (dev->dev_type) {
+	case SAS_END_DEV:
+		break;
+	case EDGE_DEV:
+	case FANOUT_DEV:
+		INIT_LIST_HEAD(&dev->ex_dev.children);
+		mutex_init(&dev->ex_dev.cmd_mutex);
+		break;
+	case SATA_DEV:
+	case SATA_PM:
+	case SATA_PM_PORT:
+	case SATA_PENDING:
+		INIT_LIST_HEAD(&dev->sata_dev.children);
+		break;
+	default:
+		break;
+	}
 }
 
 /* ---------- Domain device discovery ---------- */
@@ -68,19 +69,18 @@
  */
 static int sas_get_port_device(struct asd_sas_port *port)
 {
-	unsigned long flags;
 	struct asd_sas_phy *phy;
 	struct sas_rphy *rphy;
 	struct domain_device *dev;
 
-	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	dev = sas_alloc_device();
 	if (!dev)
 		return -ENOMEM;
 
-	spin_lock_irqsave(&port->phy_list_lock, flags);
+	spin_lock_irq(&port->phy_list_lock);
 	if (list_empty(&port->phy_list)) {
-		spin_unlock_irqrestore(&port->phy_list_lock, flags);
-		kfree(dev);
+		spin_unlock_irq(&port->phy_list_lock);
+		sas_put_device(dev);
 		return -ENODEV;
 	}
 	phy = container_of(port->phy_list.next, struct asd_sas_phy, port_phy_el);
@@ -88,7 +88,7 @@
 	memcpy(dev->frame_rcvd, phy->frame_rcvd, min(sizeof(dev->frame_rcvd),
 					     (size_t)phy->frame_rcvd_size));
 	spin_unlock(&phy->frame_rcvd_lock);
-	spin_unlock_irqrestore(&port->phy_list_lock, flags);
+	spin_unlock_irq(&port->phy_list_lock);
 
 	if (dev->frame_rcvd[0] == 0x34 && port->oob_mode == SATA_OOB_MODE) {
 		struct dev_to_host_fis *fis =
@@ -130,9 +130,14 @@
 	}
 
 	if (!rphy) {
-		kfree(dev);
+		sas_put_device(dev);
 		return -ENODEV;
 	}
+
+	spin_lock_irq(&port->phy_list_lock);
+	list_for_each_entry(phy, &port->phy_list, port_phy_el)
+		sas_phy_set_target(phy, dev);
+	spin_unlock_irq(&port->phy_list_lock);
 	rphy->identify.phy_identifier = phy->phy->identify.phy_identifier;
 	memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE);
 	sas_fill_in_rphy(dev, rphy);
@@ -147,11 +152,17 @@
 	memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE);
 	memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE);
 	port->disc.max_level = 0;
+	sas_device_set_phy(dev, port->port);
 
 	dev->rphy = rphy;
-	spin_lock_irq(&port->dev_list_lock);
-	list_add_tail(&dev->dev_list_node, &port->dev_list);
-	spin_unlock_irq(&port->dev_list_lock);
+
+	if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEV)
+		list_add_tail(&dev->disco_list_node, &port->disco_list);
+	else {
+		spin_lock_irq(&port->dev_list_lock);
+		list_add_tail(&dev->dev_list_node, &port->dev_list);
+		spin_unlock_irq(&port->dev_list_lock);
+	}
 
 	return 0;
 }
@@ -173,6 +184,7 @@
 			       dev_name(sas_ha->dev),
 			       SAS_ADDR(dev->sas_addr), res);
 		}
+		kref_get(&dev->kref);
 	}
 	return res;
 }
@@ -184,12 +196,40 @@
 	struct Scsi_Host *shost = sas_ha->core.shost;
 	struct sas_internal *i = to_sas_internal(shost->transportt);
 
-	if (i->dft->lldd_dev_gone)
+	if (i->dft->lldd_dev_gone) {
 		i->dft->lldd_dev_gone(dev);
+		sas_put_device(dev);
+	}
 }
 
-/* ---------- Common/dispatchers ---------- */
+static void sas_probe_devices(struct work_struct *work)
+{
+	struct domain_device *dev, *n;
+	struct sas_discovery_event *ev =
+		container_of(work, struct sas_discovery_event, work);
+	struct asd_sas_port *port = ev->port;
 
+	clear_bit(DISCE_PROBE, &port->disc.pending);
+
+	/* devices must be domain members before link recovery and probe */
+	list_for_each_entry(dev, &port->disco_list, disco_list_node) {
+		spin_lock_irq(&port->dev_list_lock);
+		list_add_tail(&dev->dev_list_node, &port->dev_list);
+		spin_unlock_irq(&port->dev_list_lock);
+	}
+
+	sas_probe_sata(port);
+
+	list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) {
+		int err;
+
+		err = sas_rphy_add(dev->rphy);
+		if (err)
+			sas_fail_probe(dev, __func__, err);
+		else
+			list_del_init(&dev->disco_list_node);
+	}
+}
 
 /**
  * sas_discover_end_dev -- discover an end device (SSP, etc)
@@ -203,22 +243,36 @@
 
 	res = sas_notify_lldd_dev_found(dev);
 	if (res)
-		goto out_err2;
-
-	res = sas_rphy_add(dev->rphy);
-	if (res)
-		goto out_err;
+		return res;
+	sas_discover_event(dev->port, DISCE_PROBE);
 
 	return 0;
-
-out_err:
-	sas_notify_lldd_dev_gone(dev);
-out_err2:
-	return res;
 }
 
 /* ---------- Device registration and unregistration ---------- */
 
+void sas_free_device(struct kref *kref)
+{
+	struct domain_device *dev = container_of(kref, typeof(*dev), kref);
+
+	if (dev->parent)
+		sas_put_device(dev->parent);
+
+	sas_port_put_phy(dev->phy);
+	dev->phy = NULL;
+
+	/* remove the phys and ports, everything else should be gone */
+	if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV)
+		kfree(dev->ex_dev.ex_phy);
+
+	if (dev_is_sata(dev) && dev->sata_dev.ap) {
+		ata_sas_port_destroy(dev->sata_dev.ap);
+		dev->sata_dev.ap = NULL;
+	}
+
+	kfree(dev);
+}
+
 static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_device *dev)
 {
 	sas_notify_lldd_dev_gone(dev);
@@ -230,34 +284,84 @@
 	spin_lock_irq(&port->dev_list_lock);
 	list_del_init(&dev->dev_list_node);
 	spin_unlock_irq(&port->dev_list_lock);
+
+	sas_put_device(dev);
+}
+
+static void sas_destruct_devices(struct work_struct *work)
+{
+	struct domain_device *dev, *n;
+	struct sas_discovery_event *ev =
+		container_of(work, struct sas_discovery_event, work);
+	struct asd_sas_port *port = ev->port;
+
+	clear_bit(DISCE_DESTRUCT, &port->disc.pending);
+
+	list_for_each_entry_safe(dev, n, &port->destroy_list, disco_list_node) {
+		list_del_init(&dev->disco_list_node);
+
+		sas_remove_children(&dev->rphy->dev);
+		sas_rphy_delete(dev->rphy);
+		dev->rphy = NULL;
+		sas_unregister_common_dev(port, dev);
+	}
 }
 
 void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev)
 {
-	if (dev->rphy) {
-		sas_remove_children(&dev->rphy->dev);
-		sas_rphy_delete(dev->rphy);
+	if (!test_bit(SAS_DEV_DESTROY, &dev->state) &&
+	    !list_empty(&dev->disco_list_node)) {
+		/* this rphy never saw sas_rphy_add */
+		list_del_init(&dev->disco_list_node);
+		sas_rphy_free(dev->rphy);
 		dev->rphy = NULL;
+		sas_unregister_common_dev(port, dev);
 	}
-	if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) {
-		/* remove the phys and ports, everything else should be gone */
-		kfree(dev->ex_dev.ex_phy);
-		dev->ex_dev.ex_phy = NULL;
+
+	if (dev->rphy && !test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) {
+		sas_rphy_unlink(dev->rphy);
+		list_move_tail(&dev->disco_list_node, &port->destroy_list);
+		sas_discover_event(dev->port, DISCE_DESTRUCT);
 	}
-	sas_unregister_common_dev(port, dev);
 }
 
-void sas_unregister_domain_devices(struct asd_sas_port *port)
+void sas_unregister_domain_devices(struct asd_sas_port *port, int gone)
 {
 	struct domain_device *dev, *n;
 
-	list_for_each_entry_safe_reverse(dev, n, &port->dev_list, dev_list_node)
+	list_for_each_entry_safe_reverse(dev, n, &port->dev_list, dev_list_node) {
+		if (gone)
+			set_bit(SAS_DEV_GONE, &dev->state);
+		sas_unregister_dev(port, dev);
+	}
+
+	list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node)
 		sas_unregister_dev(port, dev);
 
 	port->port->rphy = NULL;
 
 }
 
+void sas_device_set_phy(struct domain_device *dev, struct sas_port *port)
+{
+	struct sas_ha_struct *ha;
+	struct sas_phy *new_phy;
+
+	if (!dev)
+		return;
+
+	ha = dev->port->ha;
+	new_phy = sas_port_get_phy(port);
+
+	/* pin and record last seen phy */
+	spin_lock_irq(&ha->phy_port_lock);
+	if (new_phy) {
+		sas_port_put_phy(dev->phy);
+		dev->phy = new_phy;
+	}
+	spin_unlock_irq(&ha->phy_port_lock);
+}
+
 /* ---------- Discovery and Revalidation ---------- */
 
 /**
@@ -277,8 +381,7 @@
 		container_of(work, struct sas_discovery_event, work);
 	struct asd_sas_port *port = ev->port;
 
-	sas_begin_event(DISCE_DISCOVER_DOMAIN, &port->disc.disc_event_lock,
-			&port->disc.pending);
+	clear_bit(DISCE_DISCOVER_DOMAIN, &port->disc.pending);
 
 	if (port->port_dev)
 		return;
@@ -318,11 +421,12 @@
 		sas_rphy_free(dev->rphy);
 		dev->rphy = NULL;
 
+		list_del_init(&dev->disco_list_node);
 		spin_lock_irq(&port->dev_list_lock);
 		list_del_init(&dev->dev_list_node);
 		spin_unlock_irq(&port->dev_list_lock);
 
-		kfree(dev); /* not kobject_register-ed yet */
+		sas_put_device(dev);
 		port->port_dev = NULL;
 	}
 
@@ -336,21 +440,51 @@
 	struct sas_discovery_event *ev =
 		container_of(work, struct sas_discovery_event, work);
 	struct asd_sas_port *port = ev->port;
+	struct sas_ha_struct *ha = port->ha;
 
-	sas_begin_event(DISCE_REVALIDATE_DOMAIN, &port->disc.disc_event_lock,
-			&port->disc.pending);
+	/* prevent revalidation from finding sata links in recovery */
+	mutex_lock(&ha->disco_mutex);
+	if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) {
+		SAS_DPRINTK("REVALIDATION DEFERRED on port %d, pid:%d\n",
+			    port->id, task_pid_nr(current));
+		goto out;
+	}
+
+	clear_bit(DISCE_REVALIDATE_DOMAIN, &port->disc.pending);
 
 	SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
 		    task_pid_nr(current));
+
 	if (port->port_dev)
 		res = sas_ex_revalidate_domain(port->port_dev);
 
 	SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
 		    port->id, task_pid_nr(current), res);
+ out:
+	mutex_unlock(&ha->disco_mutex);
 }
 
 /* ---------- Events ---------- */
 
+static void sas_chain_work(struct sas_ha_struct *ha, struct work_struct *work)
+{
+	/* chained work is not subject to SA_HA_DRAINING or SAS_HA_REGISTERED */
+	scsi_queue_work(ha->core.shost, work);
+}
+
+static void sas_chain_event(int event, unsigned long *pending,
+			    struct work_struct *work,
+			    struct sas_ha_struct *ha)
+{
+	if (!test_and_set_bit(event, pending)) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&ha->state_lock, flags);
+		sas_chain_work(ha, work);
+		spin_unlock_irqrestore(&ha->state_lock, flags);
+	}
+}
+
 int sas_discover_event(struct asd_sas_port *port, enum discover_event ev)
 {
 	struct sas_discovery *disc;
@@ -361,8 +495,7 @@
 
 	BUG_ON(ev >= DISC_NUM_EVENTS);
 
-	sas_queue_event(ev, &disc->disc_event_lock, &disc->pending,
-			&disc->disc_work[ev].work, port->ha);
+	sas_chain_event(ev, &disc->pending, &disc->disc_work[ev].work, port->ha);
 
 	return 0;
 }
@@ -380,9 +513,10 @@
 	static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = {
 		[DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
 		[DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
+		[DISCE_PROBE] = sas_probe_devices,
+		[DISCE_DESTRUCT] = sas_destruct_devices,
 	};
 
-	spin_lock_init(&disc->disc_event_lock);
 	disc->pending = 0;
 	for (i = 0; i < DISC_NUM_EVENTS; i++) {
 		INIT_WORK(&disc->disc_work[i].work, sas_event_fns[i]);
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index 9db30fb..16639bb 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -22,15 +22,103 @@
  *
  */
 
+#include <linux/export.h>
 #include <scsi/scsi_host.h>
 #include "sas_internal.h"
 #include "sas_dump.h"
 
+void sas_queue_work(struct sas_ha_struct *ha, struct work_struct *work)
+{
+	if (!test_bit(SAS_HA_REGISTERED, &ha->state))
+		return;
+
+	if (test_bit(SAS_HA_DRAINING, &ha->state))
+		list_add(&work->entry, &ha->defer_q);
+	else
+		scsi_queue_work(ha->core.shost, work);
+}
+
+static void sas_queue_event(int event, unsigned long *pending,
+			    struct work_struct *work,
+			    struct sas_ha_struct *ha)
+{
+	if (!test_and_set_bit(event, pending)) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&ha->state_lock, flags);
+		sas_queue_work(ha, work);
+		spin_unlock_irqrestore(&ha->state_lock, flags);
+	}
+}
+
+
+void __sas_drain_work(struct sas_ha_struct *ha)
+{
+	struct workqueue_struct *wq = ha->core.shost->work_q;
+	struct work_struct *w, *_w;
+
+	set_bit(SAS_HA_DRAINING, &ha->state);
+	/* flush submitters */
+	spin_lock_irq(&ha->state_lock);
+	spin_unlock_irq(&ha->state_lock);
+
+	drain_workqueue(wq);
+
+	spin_lock_irq(&ha->state_lock);
+	clear_bit(SAS_HA_DRAINING, &ha->state);
+	list_for_each_entry_safe(w, _w, &ha->defer_q, entry) {
+		list_del_init(&w->entry);
+		sas_queue_work(ha, w);
+	}
+	spin_unlock_irq(&ha->state_lock);
+}
+
+int sas_drain_work(struct sas_ha_struct *ha)
+{
+	int err;
+
+	err = mutex_lock_interruptible(&ha->drain_mutex);
+	if (err)
+		return err;
+	if (test_bit(SAS_HA_REGISTERED, &ha->state))
+		__sas_drain_work(ha);
+	mutex_unlock(&ha->drain_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sas_drain_work);
+
+void sas_disable_revalidation(struct sas_ha_struct *ha)
+{
+	mutex_lock(&ha->disco_mutex);
+	set_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state);
+	mutex_unlock(&ha->disco_mutex);
+}
+
+void sas_enable_revalidation(struct sas_ha_struct *ha)
+{
+	int i;
+
+	mutex_lock(&ha->disco_mutex);
+	clear_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state);
+	for (i = 0; i < ha->num_phys; i++) {
+		struct asd_sas_port *port = ha->sas_port[i];
+		const int ev = DISCE_REVALIDATE_DOMAIN;
+		struct sas_discovery *d = &port->disc;
+
+		if (!test_and_clear_bit(ev, &d->pending))
+			continue;
+
+		sas_queue_event(ev, &d->pending, &d->disc_work[ev].work, ha);
+	}
+	mutex_unlock(&ha->disco_mutex);
+}
+
 static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
 {
 	BUG_ON(event >= HA_NUM_EVENTS);
 
-	sas_queue_event(event, &sas_ha->event_lock, &sas_ha->pending,
+	sas_queue_event(event, &sas_ha->pending,
 			&sas_ha->ha_events[event].work, sas_ha);
 }
 
@@ -40,7 +128,7 @@
 
 	BUG_ON(event >= PORT_NUM_EVENTS);
 
-	sas_queue_event(event, &ha->event_lock, &phy->port_events_pending,
+	sas_queue_event(event, &phy->port_events_pending,
 			&phy->port_events[event].work, ha);
 }
 
@@ -50,7 +138,7 @@
 
 	BUG_ON(event >= PHY_NUM_EVENTS);
 
-	sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending,
+	sas_queue_event(event, &phy->phy_events_pending,
 			&phy->phy_events[event].work, ha);
 }
 
@@ -62,8 +150,6 @@
 
 	int i;
 
-	spin_lock_init(&sas_ha->event_lock);
-
 	for (i = 0; i < HA_NUM_EVENTS; i++) {
 		INIT_WORK(&sas_ha->ha_events[i].work, sas_ha_event_fns[i]);
 		sas_ha->ha_events[i].ha = sas_ha;
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 1b831c5..05acd9e 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -28,6 +28,7 @@
 
 #include "sas_internal.h"
 
+#include <scsi/sas_ata.h>
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_transport_sas.h>
 #include "../scsi_sas_internal.h"
@@ -71,11 +72,18 @@
 	struct sas_internal *i =
 		to_sas_internal(dev->port->ha->core.shost->transportt);
 
+	mutex_lock(&dev->ex_dev.cmd_mutex);
 	for (retry = 0; retry < 3; retry++) {
-		task = sas_alloc_task(GFP_KERNEL);
-		if (!task)
-			return -ENOMEM;
+		if (test_bit(SAS_DEV_GONE, &dev->state)) {
+			res = -ECOMM;
+			break;
+		}
 
+		task = sas_alloc_task(GFP_KERNEL);
+		if (!task) {
+			res = -ENOMEM;
+			break;
+		}
 		task->dev = dev;
 		task->task_proto = dev->tproto;
 		sg_init_one(&task->smp_task.smp_req, req, req_size);
@@ -93,7 +101,7 @@
 		if (res) {
 			del_timer(&task->timer);
 			SAS_DPRINTK("executing SMP task failed:%d\n", res);
-			goto ex_err;
+			break;
 		}
 
 		wait_for_completion(&task->completion);
@@ -103,24 +111,30 @@
 			i->dft->lldd_abort_task(task);
 			if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
 				SAS_DPRINTK("SMP task aborted and not done\n");
-				goto ex_err;
+				break;
 			}
 		}
 		if (task->task_status.resp == SAS_TASK_COMPLETE &&
 		    task->task_status.stat == SAM_STAT_GOOD) {
 			res = 0;
 			break;
-		} if (task->task_status.resp == SAS_TASK_COMPLETE &&
-		      task->task_status.stat == SAS_DATA_UNDERRUN) {
+		}
+		if (task->task_status.resp == SAS_TASK_COMPLETE &&
+		    task->task_status.stat == SAS_DATA_UNDERRUN) {
 			/* no error, but return the number of bytes of
 			 * underrun */
 			res = task->task_status.residual;
 			break;
-		} if (task->task_status.resp == SAS_TASK_COMPLETE &&
-		      task->task_status.stat == SAS_DATA_OVERRUN) {
+		}
+		if (task->task_status.resp == SAS_TASK_COMPLETE &&
+		    task->task_status.stat == SAS_DATA_OVERRUN) {
 			res = -EMSGSIZE;
 			break;
-		} else {
+		}
+		if (task->task_status.resp == SAS_TASK_UNDELIVERED &&
+		    task->task_status.stat == SAS_DEVICE_UNKNOWN)
+			break;
+		else {
 			SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
 				    "status 0x%x\n", __func__,
 				    SAS_ADDR(dev->sas_addr),
@@ -130,11 +144,10 @@
 			task = NULL;
 		}
 	}
-ex_err:
+	mutex_unlock(&dev->ex_dev.cmd_mutex);
+
 	BUG_ON(retry == 3 && task != NULL);
-	if (task != NULL) {
-		sas_free_task(task);
-	}
+	sas_free_task(task);
 	return res;
 }
 
@@ -153,19 +166,49 @@
 	return kzalloc(size, GFP_KERNEL);
 }
 
-/* ---------- Expander configuration ---------- */
-
-static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
-			   void *disc_resp)
+static char sas_route_char(struct domain_device *dev, struct ex_phy *phy)
 {
+	switch (phy->routing_attr) {
+	case TABLE_ROUTING:
+		if (dev->ex_dev.t2t_supp)
+			return 'U';
+		else
+			return 'T';
+	case DIRECT_ROUTING:
+		return 'D';
+	case SUBTRACTIVE_ROUTING:
+		return 'S';
+	default:
+		return '?';
+	}
+}
+
+static enum sas_dev_type to_dev_type(struct discover_resp *dr)
+{
+	/* This is detecting a failure to transmit initial dev to host
+	 * FIS as described in section J.5 of sas-2 r16
+	 */
+	if (dr->attached_dev_type == NO_DEVICE && dr->attached_sata_dev &&
+	    dr->linkrate >= SAS_LINK_RATE_1_5_GBPS)
+		return SATA_PENDING;
+	else
+		return dr->attached_dev_type;
+}
+
+static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp)
+{
+	enum sas_dev_type dev_type;
+	enum sas_linkrate linkrate;
+	u8 sas_addr[SAS_ADDR_SIZE];
+	struct smp_resp *resp = rsp;
+	struct discover_resp *dr = &resp->disc;
 	struct expander_device *ex = &dev->ex_dev;
 	struct ex_phy *phy = &ex->ex_phy[phy_id];
-	struct smp_resp *resp = disc_resp;
-	struct discover_resp *dr = &resp->disc;
 	struct sas_rphy *rphy = dev->rphy;
-	int rediscover = (phy->phy != NULL);
+	bool new_phy = !phy->phy;
+	char *type;
 
-	if (!rediscover) {
+	if (new_phy) {
 		phy->phy = sas_phy_alloc(&rphy->dev, phy_id);
 
 		/* FIXME: error_handling */
@@ -184,8 +227,13 @@
 		break;
 	}
 
+	/* check if anything important changed to squelch debug */
+	dev_type = phy->attached_dev_type;
+	linkrate  = phy->linkrate;
+	memcpy(sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
+
+	phy->attached_dev_type = to_dev_type(dr);
 	phy->phy_id = phy_id;
-	phy->attached_dev_type = dr->attached_dev_type;
 	phy->linkrate = dr->linkrate;
 	phy->attached_sata_host = dr->attached_sata_host;
 	phy->attached_sata_dev  = dr->attached_sata_dev;
@@ -200,9 +248,11 @@
 	phy->last_da_index = -1;
 
 	phy->phy->identify.sas_address = SAS_ADDR(phy->attached_sas_addr);
-	phy->phy->identify.device_type = phy->attached_dev_type;
+	phy->phy->identify.device_type = dr->attached_dev_type;
 	phy->phy->identify.initiator_port_protocols = phy->attached_iproto;
 	phy->phy->identify.target_port_protocols = phy->attached_tproto;
+	if (!phy->attached_tproto && dr->attached_sata_dev)
+		phy->phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
 	phy->phy->identify.phy_identifier = phy_id;
 	phy->phy->minimum_linkrate_hw = dr->hmin_linkrate;
 	phy->phy->maximum_linkrate_hw = dr->hmax_linkrate;
@@ -210,20 +260,76 @@
 	phy->phy->maximum_linkrate = dr->pmax_linkrate;
 	phy->phy->negotiated_linkrate = phy->linkrate;
 
-	if (!rediscover)
+	if (new_phy)
 		if (sas_phy_add(phy->phy)) {
 			sas_phy_free(phy->phy);
 			return;
 		}
 
-	SAS_DPRINTK("ex %016llx phy%02d:%c attached: %016llx\n",
-		    SAS_ADDR(dev->sas_addr), phy->phy_id,
-		    phy->routing_attr == TABLE_ROUTING ? 'T' :
-		    phy->routing_attr == DIRECT_ROUTING ? 'D' :
-		    phy->routing_attr == SUBTRACTIVE_ROUTING ? 'S' : '?',
-		    SAS_ADDR(phy->attached_sas_addr));
+	switch (phy->attached_dev_type) {
+	case SATA_PENDING:
+		type = "stp pending";
+		break;
+	case NO_DEVICE:
+		type = "no device";
+		break;
+	case SAS_END_DEV:
+		if (phy->attached_iproto) {
+			if (phy->attached_tproto)
+				type = "host+target";
+			else
+				type = "host";
+		} else {
+			if (dr->attached_sata_dev)
+				type = "stp";
+			else
+				type = "ssp";
+		}
+		break;
+	case EDGE_DEV:
+	case FANOUT_DEV:
+		type = "smp";
+		break;
+	default:
+		type = "unknown";
+	}
 
-	return;
+	/* this routine is polled by libata error recovery so filter
+	 * unimportant messages
+	 */
+	if (new_phy || phy->attached_dev_type != dev_type ||
+	    phy->linkrate != linkrate ||
+	    SAS_ADDR(phy->attached_sas_addr) != SAS_ADDR(sas_addr))
+		/* pass */;
+	else
+		return;
+
+	SAS_DPRINTK("ex %016llx phy%02d:%c:%X attached: %016llx (%s)\n",
+		    SAS_ADDR(dev->sas_addr), phy->phy_id,
+		    sas_route_char(dev, phy), phy->linkrate,
+		    SAS_ADDR(phy->attached_sas_addr), type);
+}
+
+/* check if we have an existing attached ata device on this expander phy */
+struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id)
+{
+	struct ex_phy *ex_phy = &ex_dev->ex_dev.ex_phy[phy_id];
+	struct domain_device *dev;
+	struct sas_rphy *rphy;
+
+	if (!ex_phy->port)
+		return NULL;
+
+	rphy = ex_phy->port->rphy;
+	if (!rphy)
+		return NULL;
+
+	dev = sas_find_dev_by_rphy(rphy);
+
+	if (dev && dev_is_sata(dev))
+		return dev;
+
+	return NULL;
 }
 
 #define DISCOVER_REQ_SIZE  16
@@ -232,39 +338,25 @@
 static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req,
 				      u8 *disc_resp, int single)
 {
-	int i, res;
+	struct discover_resp *dr;
+	int res;
 
 	disc_req[9] = single;
-	for (i = 1 ; i < 3; i++) {
-		struct discover_resp *dr;
 
-		res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
-				       disc_resp, DISCOVER_RESP_SIZE);
-		if (res)
-			return res;
-		/* This is detecting a failure to transmit initial
-		 * dev to host FIS as described in section G.5 of
-		 * sas-2 r 04b */
-		dr = &((struct smp_resp *)disc_resp)->disc;
-		if (memcmp(dev->sas_addr, dr->attached_sas_addr,
-			  SAS_ADDR_SIZE) == 0) {
-			sas_printk("Found loopback topology, just ignore it!\n");
-			return 0;
-		}
-		if (!(dr->attached_dev_type == 0 &&
-		      dr->attached_sata_dev))
-			break;
-		/* In order to generate the dev to host FIS, we
-		 * send a link reset to the expander port */
-		sas_smp_phy_control(dev, single, PHY_FUNC_LINK_RESET, NULL);
-		/* Wait for the reset to trigger the negotiation */
-		msleep(500);
+	res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
+			       disc_resp, DISCOVER_RESP_SIZE);
+	if (res)
+		return res;
+	dr = &((struct smp_resp *)disc_resp)->disc;
+	if (memcmp(dev->sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE) == 0) {
+		sas_printk("Found loopback topology, just ignore it!\n");
+		return 0;
 	}
 	sas_set_ex_phy(dev, single, disc_resp);
 	return 0;
 }
 
-static int sas_ex_phy_discover(struct domain_device *dev, int single)
+int sas_ex_phy_discover(struct domain_device *dev, int single)
 {
 	struct expander_device *ex = &dev->ex_dev;
 	int  res = 0;
@@ -569,9 +661,8 @@
 #define RPS_REQ_SIZE  16
 #define RPS_RESP_SIZE 60
 
-static int sas_get_report_phy_sata(struct domain_device *dev,
-					  int phy_id,
-					  struct smp_resp *rps_resp)
+int sas_get_report_phy_sata(struct domain_device *dev, int phy_id,
+			    struct smp_resp *rps_resp)
 {
 	int res;
 	u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE);
@@ -657,10 +748,11 @@
 	if (phy->attached_sata_host || phy->attached_sata_ps)
 		return NULL;
 
-	child = kzalloc(sizeof(*child), GFP_KERNEL);
+	child = sas_alloc_device();
 	if (!child)
 		return NULL;
 
+	kref_get(&parent->kref);
 	child->parent = parent;
 	child->port   = parent->port;
 	child->iproto = phy->attached_iproto;
@@ -676,24 +768,13 @@
 		}
 	}
 	sas_ex_get_linkrate(parent, child, phy);
+	sas_device_set_phy(child, phy->port);
 
 #ifdef CONFIG_SCSI_SAS_ATA
 	if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) {
-		child->dev_type = SATA_DEV;
-		if (phy->attached_tproto & SAS_PROTOCOL_STP)
-			child->tproto = phy->attached_tproto;
-		if (phy->attached_sata_dev)
-			child->tproto |= SATA_DEV;
-		res = sas_get_report_phy_sata(parent, phy_id,
-					      &child->sata_dev.rps_resp);
-		if (res) {
-			SAS_DPRINTK("report phy sata to %016llx:0x%x returned "
-				    "0x%x\n", SAS_ADDR(parent->sas_addr),
-				    phy_id, res);
+		res = sas_get_ata_info(child, phy);
+		if (res)
 			goto out_free;
-		}
-		memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis,
-		       sizeof(struct dev_to_host_fis));
 
 		rphy = sas_end_device_alloc(phy->port);
 		if (unlikely(!rphy))
@@ -703,9 +784,7 @@
 
 		child->rphy = rphy;
 
-		spin_lock_irq(&parent->port->dev_list_lock);
-		list_add_tail(&child->dev_list_node, &parent->port->dev_list);
-		spin_unlock_irq(&parent->port->dev_list_lock);
+		list_add_tail(&child->disco_list_node, &parent->port->disco_list);
 
 		res = sas_discover_sata(child);
 		if (res) {
@@ -729,9 +808,7 @@
 		child->rphy = rphy;
 		sas_fill_in_rphy(child, rphy);
 
-		spin_lock_irq(&parent->port->dev_list_lock);
-		list_add_tail(&child->dev_list_node, &parent->port->dev_list);
-		spin_unlock_irq(&parent->port->dev_list_lock);
+		list_add_tail(&child->disco_list_node, &parent->port->disco_list);
 
 		res = sas_discover_end_dev(child);
 		if (res) {
@@ -755,6 +832,7 @@
 	sas_rphy_free(child->rphy);
 	child->rphy = NULL;
 
+	list_del(&child->disco_list_node);
 	spin_lock_irq(&parent->port->dev_list_lock);
 	list_del(&child->dev_list_node);
 	spin_unlock_irq(&parent->port->dev_list_lock);
@@ -762,7 +840,7 @@
 	sas_port_delete(phy->port);
  out_err:
 	phy->port = NULL;
-	kfree(child);
+	sas_put_device(child);
 	return NULL;
 }
 
@@ -809,7 +887,7 @@
 			    phy->attached_phy_id);
 		return NULL;
 	}
-	child = kzalloc(sizeof(*child), GFP_KERNEL);
+	child = sas_alloc_device();
 	if (!child)
 		return NULL;
 
@@ -835,6 +913,7 @@
 	child->rphy = rphy;
 	edev = rphy_to_expander_device(rphy);
 	child->dev_type = phy->attached_dev_type;
+	kref_get(&parent->kref);
 	child->parent = parent;
 	child->port = port;
 	child->iproto = phy->attached_iproto;
@@ -858,7 +937,7 @@
 		spin_lock_irq(&parent->port->dev_list_lock);
 		list_del(&child->dev_list_node);
 		spin_unlock_irq(&parent->port->dev_list_lock);
-		kfree(child);
+		sas_put_device(child);
 		return NULL;
 	}
 	list_add_tail(&child->siblings, &parent->ex_dev.children);
@@ -908,7 +987,8 @@
 
 	if (ex_phy->attached_dev_type != SAS_END_DEV &&
 	    ex_phy->attached_dev_type != FANOUT_DEV &&
-	    ex_phy->attached_dev_type != EDGE_DEV) {
+	    ex_phy->attached_dev_type != EDGE_DEV &&
+	    ex_phy->attached_dev_type != SATA_PENDING) {
 		SAS_DPRINTK("unknown device type(0x%x) attached to ex %016llx "
 			    "phy 0x%x\n", ex_phy->attached_dev_type,
 			    SAS_ADDR(dev->sas_addr),
@@ -934,6 +1014,7 @@
 
 	switch (ex_phy->attached_dev_type) {
 	case SAS_END_DEV:
+	case SATA_PENDING:
 		child = sas_ex_discover_end_dev(dev, phy_id);
 		break;
 	case FANOUT_DEV:
@@ -1128,32 +1209,25 @@
 						 struct ex_phy *parent_phy,
 						 struct ex_phy *child_phy)
 {
-	static const char ra_char[] = {
-		[DIRECT_ROUTING] = 'D',
-		[SUBTRACTIVE_ROUTING] = 'S',
-		[TABLE_ROUTING] = 'T',
-	};
 	static const char *ex_type[] = {
 		[EDGE_DEV] = "edge",
 		[FANOUT_DEV] = "fanout",
 	};
 	struct domain_device *parent = child->parent;
 
-	sas_printk("%s ex %016llx (T2T supp:%d) phy 0x%x <--> %s ex %016llx "
-		   "(T2T supp:%d) phy 0x%x has %c:%c routing link!\n",
+	sas_printk("%s ex %016llx phy 0x%x <--> %s ex %016llx "
+		   "phy 0x%x has %c:%c routing link!\n",
 
 		   ex_type[parent->dev_type],
 		   SAS_ADDR(parent->sas_addr),
-		   parent->ex_dev.t2t_supp,
 		   parent_phy->phy_id,
 
 		   ex_type[child->dev_type],
 		   SAS_ADDR(child->sas_addr),
-		   child->ex_dev.t2t_supp,
 		   child_phy->phy_id,
 
-		   ra_char[parent_phy->routing_attr],
-		   ra_char[child_phy->routing_attr]);
+		   sas_route_char(parent, parent_phy),
+		   sas_route_char(child, child_phy));
 }
 
 static int sas_check_eeds(struct domain_device *child,
@@ -1610,8 +1684,8 @@
 	return res;
 }
 
-static int sas_get_phy_attached_sas_addr(struct domain_device *dev,
-					 int phy_id, u8 *attached_sas_addr)
+static int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id,
+				    u8 *sas_addr, enum sas_dev_type *type)
 {
 	int res;
 	struct smp_resp *disc_resp;
@@ -1623,10 +1697,11 @@
 	dr = &disc_resp->disc;
 
 	res = sas_get_phy_discover(dev, phy_id, disc_resp);
-	if (!res) {
-		memcpy(attached_sas_addr,disc_resp->disc.attached_sas_addr,8);
-		if (dr->attached_dev_type == 0)
-			memset(attached_sas_addr, 0, 8);
+	if (res == 0) {
+		memcpy(sas_addr, disc_resp->disc.attached_sas_addr, 8);
+		*type = to_dev_type(dr);
+		if (*type == 0)
+			memset(sas_addr, 0, 8);
 	}
 	kfree(disc_resp);
 	return res;
@@ -1748,7 +1823,7 @@
 	struct domain_device *child, *n;
 
 	list_for_each_entry_safe(child, n, &ex->children, siblings) {
-		child->gone = 1;
+		set_bit(SAS_DEV_GONE, &child->state);
 		if (child->dev_type == EDGE_DEV ||
 		    child->dev_type == FANOUT_DEV)
 			sas_unregister_ex_tree(port, child);
@@ -1763,27 +1838,28 @@
 {
 	struct expander_device *ex_dev = &parent->ex_dev;
 	struct ex_phy *phy = &ex_dev->ex_phy[phy_id];
-	struct domain_device *child, *n;
+	struct domain_device *child, *n, *found = NULL;
 	if (last) {
 		list_for_each_entry_safe(child, n,
 			&ex_dev->children, siblings) {
 			if (SAS_ADDR(child->sas_addr) ==
 			    SAS_ADDR(phy->attached_sas_addr)) {
-				child->gone = 1;
+				set_bit(SAS_DEV_GONE, &child->state);
 				if (child->dev_type == EDGE_DEV ||
 				    child->dev_type == FANOUT_DEV)
 					sas_unregister_ex_tree(parent->port, child);
 				else
 					sas_unregister_dev(parent->port, child);
+				found = child;
 				break;
 			}
 		}
-		parent->gone = 1;
 		sas_disable_routing(parent, phy->attached_sas_addr);
 	}
 	memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
 	if (phy->port) {
 		sas_port_delete_phy(phy->port, phy->phy);
+		sas_device_set_phy(found, phy->port);
 		if (phy->port->num_phys == 0)
 			sas_port_delete(phy->port);
 		phy->port = NULL;
@@ -1874,39 +1950,71 @@
 	return res;
 }
 
+static bool dev_type_flutter(enum sas_dev_type new, enum sas_dev_type old)
+{
+	if (old == new)
+		return true;
+
+	/* treat device directed resets as flutter, if we went
+	 * SAS_END_DEV to SATA_PENDING the link needs recovery
+	 */
+	if ((old == SATA_PENDING && new == SAS_END_DEV) ||
+	    (old == SAS_END_DEV && new == SATA_PENDING))
+		return true;
+
+	return false;
+}
+
 static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last)
 {
 	struct expander_device *ex = &dev->ex_dev;
 	struct ex_phy *phy = &ex->ex_phy[phy_id];
-	u8 attached_sas_addr[8];
+	enum sas_dev_type type = NO_DEVICE;
+	u8 sas_addr[8];
 	int res;
 
-	res = sas_get_phy_attached_sas_addr(dev, phy_id, attached_sas_addr);
+	res = sas_get_phy_attached_dev(dev, phy_id, sas_addr, &type);
 	switch (res) {
 	case SMP_RESP_NO_PHY:
 		phy->phy_state = PHY_NOT_PRESENT;
 		sas_unregister_devs_sas_addr(dev, phy_id, last);
-		goto out; break;
+		return res;
 	case SMP_RESP_PHY_VACANT:
 		phy->phy_state = PHY_VACANT;
 		sas_unregister_devs_sas_addr(dev, phy_id, last);
-		goto out; break;
+		return res;
 	case SMP_RESP_FUNC_ACC:
 		break;
 	}
 
-	if (SAS_ADDR(attached_sas_addr) == 0) {
+	if (SAS_ADDR(sas_addr) == 0) {
 		phy->phy_state = PHY_EMPTY;
 		sas_unregister_devs_sas_addr(dev, phy_id, last);
-	} else if (SAS_ADDR(attached_sas_addr) ==
-		   SAS_ADDR(phy->attached_sas_addr)) {
-		SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter\n",
-			    SAS_ADDR(dev->sas_addr), phy_id);
+		return res;
+	} else if (SAS_ADDR(sas_addr) == SAS_ADDR(phy->attached_sas_addr) &&
+		   dev_type_flutter(type, phy->attached_dev_type)) {
+		struct domain_device *ata_dev = sas_ex_to_ata(dev, phy_id);
+		char *action = "";
+
 		sas_ex_phy_discover(dev, phy_id);
-	} else
-		res = sas_discover_new(dev, phy_id);
-out:
-	return res;
+
+		if (ata_dev && phy->attached_dev_type == SATA_PENDING)
+			action = ", needs recovery";
+		SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter%s\n",
+			    SAS_ADDR(dev->sas_addr), phy_id, action);
+		return res;
+	}
+
+	/* delete the old link */
+	if (SAS_ADDR(phy->attached_sas_addr) &&
+	    SAS_ADDR(sas_addr) != SAS_ADDR(phy->attached_sas_addr)) {
+		SAS_DPRINTK("ex %016llx phy 0x%x replace %016llx\n",
+			    SAS_ADDR(dev->sas_addr), phy_id,
+			    SAS_ADDR(phy->attached_sas_addr));
+		sas_unregister_devs_sas_addr(dev, phy_id, last);
+	}
+
+	return sas_discover_new(dev, phy_id);
 }
 
 /**
diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c
index 3814d3e..d247925 100644
--- a/drivers/scsi/libsas/sas_host_smp.c
+++ b/drivers/scsi/libsas/sas_host_smp.c
@@ -187,11 +187,14 @@
 	struct sas_internal *i =
 		to_sas_internal(sas_ha->core.shost->transportt);
 	struct sas_phy_linkrates rates;
+	struct asd_sas_phy *asd_phy;
 
 	if (phy_id >= sas_ha->num_phys) {
 		resp_data[2] = SMP_RESP_NO_PHY;
 		return;
 	}
+
+	asd_phy = sas_ha->sas_phy[phy_id];
 	switch (phy_op) {
 	case PHY_FUNC_NOP:
 	case PHY_FUNC_LINK_RESET:
@@ -210,7 +213,13 @@
 	rates.minimum_linkrate = min;
 	rates.maximum_linkrate = max;
 
-	if (i->dft->lldd_control_phy(sas_ha->sas_phy[phy_id], phy_op, &rates))
+	/* filter reset requests through libata eh */
+	if (phy_op == PHY_FUNC_LINK_RESET && sas_try_ata_reset(asd_phy) == 0) {
+		resp_data[2] = SMP_RESP_FUNC_ACC;
+		return;
+	}
+
+	if (i->dft->lldd_control_phy(asd_phy, phy_op, &rates))
 		resp_data[2] = SMP_RESP_FUNC_FAILED;
 	else
 		resp_data[2] = SMP_RESP_FUNC_ACC;
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index d81c3b1..120bff6 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -28,6 +28,7 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/spinlock.h>
+#include <scsi/sas_ata.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_transport.h>
@@ -97,14 +98,14 @@
 		container_of(work, struct sas_ha_event, work);
 	struct sas_ha_struct *ha = ev->ha;
 
-	sas_begin_event(HAE_RESET, &ha->event_lock,
-			&ha->pending);
+	clear_bit(HAE_RESET, &ha->pending);
 }
 
 int sas_register_ha(struct sas_ha_struct *sas_ha)
 {
 	int error = 0;
 
+	mutex_init(&sas_ha->disco_mutex);
 	spin_lock_init(&sas_ha->phy_port_lock);
 	sas_hash_addr(sas_ha->hashed_sas_addr, sas_ha->sas_addr);
 
@@ -113,8 +114,10 @@
 	else if (sas_ha->lldd_queue_size == -1)
 		sas_ha->lldd_queue_size = 128; /* Sanity */
 
-	sas_ha->state = SAS_HA_REGISTERED;
+	set_bit(SAS_HA_REGISTERED, &sas_ha->state);
 	spin_lock_init(&sas_ha->state_lock);
+	mutex_init(&sas_ha->drain_mutex);
+	INIT_LIST_HEAD(&sas_ha->defer_q);
 
 	error = sas_register_phys(sas_ha);
 	if (error) {
@@ -144,6 +147,7 @@
 	}
 
 	INIT_LIST_HEAD(&sas_ha->eh_done_q);
+	INIT_LIST_HEAD(&sas_ha->eh_ata_q);
 
 	return 0;
 
@@ -156,17 +160,23 @@
 
 int sas_unregister_ha(struct sas_ha_struct *sas_ha)
 {
-	unsigned long flags;
-
-	/* Set the state to unregistered to avoid further
-	 * events to be queued */
-	spin_lock_irqsave(&sas_ha->state_lock, flags);
-	sas_ha->state = SAS_HA_UNREGISTERED;
-	spin_unlock_irqrestore(&sas_ha->state_lock, flags);
-	scsi_flush_work(sas_ha->core.shost);
+	/* Set the state to unregistered to avoid further unchained
+	 * events to be queued, and flush any in-progress drainers
+	 */
+	mutex_lock(&sas_ha->drain_mutex);
+	spin_lock_irq(&sas_ha->state_lock);
+	clear_bit(SAS_HA_REGISTERED, &sas_ha->state);
+	spin_unlock_irq(&sas_ha->state_lock);
+	__sas_drain_work(sas_ha);
+	mutex_unlock(&sas_ha->drain_mutex);
 
 	sas_unregister_ports(sas_ha);
 
+	/* flush unregistration work */
+	mutex_lock(&sas_ha->drain_mutex);
+	__sas_drain_work(sas_ha);
+	mutex_unlock(&sas_ha->drain_mutex);
+
 	if (sas_ha->lldd_max_execute_num > 1) {
 		sas_shutdown_queue(sas_ha);
 		sas_ha->lldd_max_execute_num = 1;
@@ -190,15 +200,41 @@
 	return sas_smp_get_phy_events(phy);
 }
 
-int sas_phy_enable(struct sas_phy *phy, int enable)
+int sas_try_ata_reset(struct asd_sas_phy *asd_phy)
 {
-	int ret;
-	enum phy_func command;
+	struct domain_device *dev = NULL;
 
-	if (enable)
-		command = PHY_FUNC_LINK_RESET;
+	/* try to route user requested link resets through libata */
+	if (asd_phy->port)
+		dev = asd_phy->port->port_dev;
+
+	/* validate that dev has been probed */
+	if (dev)
+		dev = sas_find_dev_by_rphy(dev->rphy);
+
+	if (dev && dev_is_sata(dev)) {
+		sas_ata_schedule_reset(dev);
+		sas_ata_wait_eh(dev);
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+/**
+ * transport_sas_phy_reset - reset a phy and permit libata to manage the link
+ *
+ * phy reset request via sysfs in host workqueue context so we know we
+ * can block on eh and safely traverse the domain_device topology
+ */
+static int transport_sas_phy_reset(struct sas_phy *phy, int hard_reset)
+{
+	enum phy_func reset_type;
+
+	if (hard_reset)
+		reset_type = PHY_FUNC_HARD_RESET;
 	else
-		command = PHY_FUNC_DISABLE;
+		reset_type = PHY_FUNC_LINK_RESET;
 
 	if (scsi_is_sas_phy_local(phy)) {
 		struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
@@ -207,15 +243,52 @@
 		struct sas_internal *i =
 			to_sas_internal(sas_ha->core.shost->transportt);
 
-		if (!enable) {
-			sas_phy_disconnected(asd_phy);
-			sas_ha->notify_phy_event(asd_phy, PHYE_LOSS_OF_SIGNAL);
-		}
-		ret = i->dft->lldd_control_phy(asd_phy, command, NULL);
+		if (!hard_reset && sas_try_ata_reset(asd_phy) == 0)
+			return 0;
+		return i->dft->lldd_control_phy(asd_phy, reset_type, NULL);
 	} else {
 		struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
 		struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
-		ret = sas_smp_phy_control(ddev, phy->number, command, NULL);
+		struct domain_device *ata_dev = sas_ex_to_ata(ddev, phy->number);
+
+		if (ata_dev && !hard_reset) {
+			sas_ata_schedule_reset(ata_dev);
+			sas_ata_wait_eh(ata_dev);
+			return 0;
+		} else
+			return sas_smp_phy_control(ddev, phy->number, reset_type, NULL);
+	}
+}
+
+static int sas_phy_enable(struct sas_phy *phy, int enable)
+{
+	int ret;
+	enum phy_func cmd;
+
+	if (enable)
+		cmd = PHY_FUNC_LINK_RESET;
+	else
+		cmd = PHY_FUNC_DISABLE;
+
+	if (scsi_is_sas_phy_local(phy)) {
+		struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+		struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
+		struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
+		struct sas_internal *i =
+			to_sas_internal(sas_ha->core.shost->transportt);
+
+		if (enable)
+			ret = transport_sas_phy_reset(phy, 0);
+		else
+			ret = i->dft->lldd_control_phy(asd_phy, cmd, NULL);
+	} else {
+		struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
+		struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
+
+		if (enable)
+			ret = transport_sas_phy_reset(phy, 0);
+		else
+			ret = sas_smp_phy_control(ddev, phy->number, cmd, NULL);
 	}
 	return ret;
 }
@@ -225,6 +298,9 @@
 	int ret;
 	enum phy_func reset_type;
 
+	if (!phy->enabled)
+		return -ENODEV;
+
 	if (hard_reset)
 		reset_type = PHY_FUNC_HARD_RESET;
 	else
@@ -285,9 +361,101 @@
 	return ret;
 }
 
+static void sas_phy_release(struct sas_phy *phy)
+{
+	kfree(phy->hostdata);
+	phy->hostdata = NULL;
+}
+
+static void phy_reset_work(struct work_struct *work)
+{
+	struct sas_phy_data *d = container_of(work, typeof(*d), reset_work);
+
+	d->reset_result = transport_sas_phy_reset(d->phy, d->hard_reset);
+}
+
+static void phy_enable_work(struct work_struct *work)
+{
+	struct sas_phy_data *d = container_of(work, typeof(*d), enable_work);
+
+	d->enable_result = sas_phy_enable(d->phy, d->enable);
+}
+
+static int sas_phy_setup(struct sas_phy *phy)
+{
+	struct sas_phy_data *d = kzalloc(sizeof(*d), GFP_KERNEL);
+
+	if (!d)
+		return -ENOMEM;
+
+	mutex_init(&d->event_lock);
+	INIT_WORK(&d->reset_work, phy_reset_work);
+	INIT_WORK(&d->enable_work, phy_enable_work);
+	d->phy = phy;
+	phy->hostdata = d;
+
+	return 0;
+}
+
+static int queue_phy_reset(struct sas_phy *phy, int hard_reset)
+{
+	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+	struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+	struct sas_phy_data *d = phy->hostdata;
+	int rc;
+
+	if (!d)
+		return -ENOMEM;
+
+	/* libsas workqueue coordinates ata-eh reset with discovery */
+	mutex_lock(&d->event_lock);
+	d->reset_result = 0;
+	d->hard_reset = hard_reset;
+
+	spin_lock_irq(&ha->state_lock);
+	sas_queue_work(ha, &d->reset_work);
+	spin_unlock_irq(&ha->state_lock);
+
+	rc = sas_drain_work(ha);
+	if (rc == 0)
+		rc = d->reset_result;
+	mutex_unlock(&d->event_lock);
+
+	return rc;
+}
+
+static int queue_phy_enable(struct sas_phy *phy, int enable)
+{
+	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+	struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+	struct sas_phy_data *d = phy->hostdata;
+	int rc;
+
+	if (!d)
+		return -ENOMEM;
+
+	/* libsas workqueue coordinates ata-eh reset with discovery */
+	mutex_lock(&d->event_lock);
+	d->enable_result = 0;
+	d->enable = enable;
+
+	spin_lock_irq(&ha->state_lock);
+	sas_queue_work(ha, &d->enable_work);
+	spin_unlock_irq(&ha->state_lock);
+
+	rc = sas_drain_work(ha);
+	if (rc == 0)
+		rc = d->enable_result;
+	mutex_unlock(&d->event_lock);
+
+	return rc;
+}
+
 static struct sas_function_template sft = {
-	.phy_enable = sas_phy_enable,
-	.phy_reset = sas_phy_reset,
+	.phy_enable = queue_phy_enable,
+	.phy_reset = queue_phy_reset,
+	.phy_setup = sas_phy_setup,
+	.phy_release = sas_phy_release,
 	.set_phy_speed = sas_set_phy_speed,
 	.get_linkerrors = sas_get_linkerrors,
 	.smp_handler = sas_smp_handler,
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 14e21b5..f05c638 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -30,6 +30,7 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_sas.h>
 #include <scsi/libsas.h>
+#include <scsi/sas_ata.h>
 
 #define sas_printk(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__)
 
@@ -38,6 +39,18 @@
 #define TO_SAS_TASK(_scsi_cmd)  ((void *)(_scsi_cmd)->host_scribble)
 #define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
 
+struct sas_phy_data {
+	/* let reset be performed in sas_queue_work() context */
+	struct sas_phy *phy;
+	struct mutex event_lock;
+	int hard_reset;
+	int reset_result;
+	struct work_struct reset_work;
+	int enable;
+	int enable_result;
+	struct work_struct enable_work;
+};
+
 void sas_scsi_recover_host(struct Scsi_Host *shost);
 
 int sas_show_class(enum sas_class class, char *buf);
@@ -56,6 +69,9 @@
 int  sas_init_queue(struct sas_ha_struct *sas_ha);
 int  sas_init_events(struct sas_ha_struct *sas_ha);
 void sas_shutdown_queue(struct sas_ha_struct *sas_ha);
+void sas_disable_revalidation(struct sas_ha_struct *ha);
+void sas_enable_revalidation(struct sas_ha_struct *ha);
+void __sas_drain_work(struct sas_ha_struct *ha);
 
 void sas_deform_port(struct asd_sas_phy *phy, int gone);
 
@@ -64,6 +80,7 @@
 void sas_porte_link_reset_err(struct work_struct *work);
 void sas_porte_timer_event(struct work_struct *work);
 void sas_porte_hard_reset(struct work_struct *work);
+void sas_queue_work(struct sas_ha_struct *ha, struct work_struct *work);
 
 int sas_notify_lldd_dev_found(struct domain_device *);
 void sas_notify_lldd_dev_gone(struct domain_device *);
@@ -72,10 +89,17 @@
 			enum phy_func phy_func, struct sas_phy_linkrates *);
 int sas_smp_get_phy_events(struct sas_phy *phy);
 
+void sas_device_set_phy(struct domain_device *dev, struct sas_port *port);
 struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
-
+struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
+int sas_ex_phy_discover(struct domain_device *dev, int single);
+int sas_get_report_phy_sata(struct domain_device *dev, int phy_id,
+			    struct smp_resp *rps_resp);
+int sas_try_ata_reset(struct asd_sas_phy *phy);
 void sas_hae_reset(struct work_struct *work);
 
+void sas_free_device(struct kref *kref);
+
 #ifdef CONFIG_SCSI_SAS_HOST_SMP
 extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
 				struct request *rsp);
@@ -90,36 +114,13 @@
 }
 #endif
 
-static inline void sas_queue_event(int event, spinlock_t *lock,
-				   unsigned long *pending,
-				   struct work_struct *work,
-				   struct sas_ha_struct *sas_ha)
+static inline void sas_fail_probe(struct domain_device *dev, const char *func, int err)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(lock, flags);
-	if (test_bit(event, pending)) {
-		spin_unlock_irqrestore(lock, flags);
-		return;
-	}
-	__set_bit(event, pending);
-	spin_unlock_irqrestore(lock, flags);
-
-	spin_lock_irqsave(&sas_ha->state_lock, flags);
-	if (sas_ha->state != SAS_HA_UNREGISTERED) {
-		scsi_queue_work(sas_ha->core.shost, work);
-	}
-	spin_unlock_irqrestore(&sas_ha->state_lock, flags);
-}
-
-static inline void sas_begin_event(int event, spinlock_t *lock,
-				   unsigned long *pending)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(lock, flags);
-	__clear_bit(event, pending);
-	spin_unlock_irqrestore(lock, flags);
+	SAS_DPRINTK("%s: for %s device %16llx returned %d\n",
+		    func, dev->parent ? "exp-attached" :
+					    "direct-attached",
+		    SAS_ADDR(dev->sas_addr), err);
+	sas_unregister_dev(dev->port, dev);
 }
 
 static inline void sas_fill_in_rphy(struct domain_device *dev,
@@ -132,6 +133,7 @@
 	case SATA_DEV:
 		/* FIXME: need sata device type */
 	case SAS_END_DEV:
+	case SATA_PENDING:
 		rphy->identify.device_type = SAS_END_DEVICE;
 		break;
 	case EDGE_DEV:
@@ -146,6 +148,22 @@
 	}
 }
 
+static inline void sas_phy_set_target(struct asd_sas_phy *p, struct domain_device *dev)
+{
+	struct sas_phy *phy = p->phy;
+
+	if (dev) {
+		if (dev_is_sata(dev))
+			phy->identify.device_type = SAS_END_DEVICE;
+		else
+			phy->identify.device_type = dev->dev_type;
+		phy->identify.target_port_protocols = dev->tproto;
+	} else {
+		phy->identify.device_type = SAS_PHY_UNUSED;
+		phy->identify.target_port_protocols = 0;
+	}
+}
+
 static inline void sas_add_parent_port(struct domain_device *dev, int phy_id)
 {
 	struct expander_device *ex = &dev->ex_dev;
@@ -161,4 +179,23 @@
 	sas_port_add_phy(ex->parent_port, ex_phy->phy);
 }
 
+static inline struct domain_device *sas_alloc_device(void)
+{
+	struct domain_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+
+	if (dev) {
+		INIT_LIST_HEAD(&dev->siblings);
+		INIT_LIST_HEAD(&dev->dev_list_node);
+		INIT_LIST_HEAD(&dev->disco_list_node);
+		kref_init(&dev->kref);
+		spin_lock_init(&dev->done_lock);
+	}
+	return dev;
+}
+
+static inline void sas_put_device(struct domain_device *dev)
+{
+	kref_put(&dev->kref, sas_free_device);
+}
+
 #endif /* _SAS_INTERNAL_H_ */
diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c
index e0f5018e..dcfd4a9 100644
--- a/drivers/scsi/libsas/sas_phy.c
+++ b/drivers/scsi/libsas/sas_phy.c
@@ -36,8 +36,7 @@
 		container_of(work, struct asd_sas_event, work);
 	struct asd_sas_phy *phy = ev->phy;
 
-	sas_begin_event(PHYE_LOSS_OF_SIGNAL, &phy->ha->event_lock,
-			&phy->phy_events_pending);
+	clear_bit(PHYE_LOSS_OF_SIGNAL, &phy->phy_events_pending);
 	phy->error = 0;
 	sas_deform_port(phy, 1);
 }
@@ -48,8 +47,7 @@
 		container_of(work, struct asd_sas_event, work);
 	struct asd_sas_phy *phy = ev->phy;
 
-	sas_begin_event(PHYE_OOB_DONE, &phy->ha->event_lock,
-			&phy->phy_events_pending);
+	clear_bit(PHYE_OOB_DONE, &phy->phy_events_pending);
 	phy->error = 0;
 }
 
@@ -63,8 +61,7 @@
 	struct sas_internal *i =
 		to_sas_internal(sas_ha->core.shost->transportt);
 
-	sas_begin_event(PHYE_OOB_ERROR, &phy->ha->event_lock,
-			&phy->phy_events_pending);
+	clear_bit(PHYE_OOB_ERROR, &phy->phy_events_pending);
 
 	sas_deform_port(phy, 1);
 
@@ -95,8 +92,7 @@
 	struct sas_internal *i =
 		to_sas_internal(sas_ha->core.shost->transportt);
 
-	sas_begin_event(PHYE_SPINUP_HOLD, &phy->ha->event_lock,
-			&phy->phy_events_pending);
+	clear_bit(PHYE_SPINUP_HOLD, &phy->phy_events_pending);
 
 	phy->error = 0;
 	i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index 42fd1f2..eb19c01 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -104,13 +104,11 @@
 
 	/* add the phy to the port */
 	list_add_tail(&phy->port_phy_el, &port->phy_list);
+	sas_phy_set_target(phy, port->port_dev);
 	phy->port = port;
 	port->num_phys++;
 	port->phy_mask |= (1U << phy->id);
 
-	if (!port->phy)
-		port->phy = phy->phy;
-
 	if (*(u64 *)port->attached_sas_addr == 0) {
 		port->class = phy->class;
 		memcpy(port->attached_sas_addr, phy->attached_sas_addr,
@@ -125,7 +123,7 @@
 	spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
 
 	if (!port->port) {
-		port->port = sas_port_alloc(phy->phy->dev.parent, port->id);
+		port->port = sas_port_alloc(phy->phy->dev.parent, phy->id);
 		BUG_ON(!port->port);
 		sas_port_add(port->port);
 	}
@@ -170,13 +168,13 @@
 		dev->pathways--;
 
 	if (port->num_phys == 1) {
-		if (dev && gone)
-			dev->gone = 1;
-		sas_unregister_domain_devices(port);
+		sas_unregister_domain_devices(port, gone);
 		sas_port_delete(port->port);
 		port->port = NULL;
-	} else
+	} else {
 		sas_port_delete_phy(port->port, phy->phy);
+		sas_device_set_phy(dev, port->port);
+	}
 
 	if (si->dft->lldd_port_deformed)
 		si->dft->lldd_port_deformed(phy);
@@ -185,6 +183,7 @@
 	spin_lock(&port->phy_list_lock);
 
 	list_del_init(&phy->port_phy_el);
+	sas_phy_set_target(phy, NULL);
 	phy->port = NULL;
 	port->num_phys--;
 	port->phy_mask &= ~(1U << phy->id);
@@ -213,8 +212,7 @@
 		container_of(work, struct asd_sas_event, work);
 	struct asd_sas_phy *phy = ev->phy;
 
-	sas_begin_event(PORTE_BYTES_DMAED, &phy->ha->event_lock,
-			&phy->port_events_pending);
+	clear_bit(PORTE_BYTES_DMAED, &phy->port_events_pending);
 
 	sas_form_port(phy);
 }
@@ -227,8 +225,7 @@
 	unsigned long flags;
 	u32 prim;
 
-	sas_begin_event(PORTE_BROADCAST_RCVD, &phy->ha->event_lock,
-			&phy->port_events_pending);
+	clear_bit(PORTE_BROADCAST_RCVD, &phy->port_events_pending);
 
 	spin_lock_irqsave(&phy->sas_prim_lock, flags);
 	prim = phy->sas_prim;
@@ -244,8 +241,7 @@
 		container_of(work, struct asd_sas_event, work);
 	struct asd_sas_phy *phy = ev->phy;
 
-	sas_begin_event(PORTE_LINK_RESET_ERR, &phy->ha->event_lock,
-			&phy->port_events_pending);
+	clear_bit(PORTE_LINK_RESET_ERR, &phy->port_events_pending);
 
 	sas_deform_port(phy, 1);
 }
@@ -256,8 +252,7 @@
 		container_of(work, struct asd_sas_event, work);
 	struct asd_sas_phy *phy = ev->phy;
 
-	sas_begin_event(PORTE_TIMER_EVENT, &phy->ha->event_lock,
-			&phy->port_events_pending);
+	clear_bit(PORTE_TIMER_EVENT, &phy->port_events_pending);
 
 	sas_deform_port(phy, 1);
 }
@@ -268,8 +263,7 @@
 		container_of(work, struct asd_sas_event, work);
 	struct asd_sas_phy *phy = ev->phy;
 
-	sas_begin_event(PORTE_HARD_RESET, &phy->ha->event_lock,
-			&phy->port_events_pending);
+	clear_bit(PORTE_HARD_RESET, &phy->port_events_pending);
 
 	sas_deform_port(phy, 1);
 }
@@ -282,6 +276,8 @@
 	memset(port, 0, sizeof(*port));
 	port->id = i;
 	INIT_LIST_HEAD(&port->dev_list);
+	INIT_LIST_HEAD(&port->disco_list);
+	INIT_LIST_HEAD(&port->destroy_list);
 	spin_lock_init(&port->phy_list_lock);
 	INIT_LIST_HEAD(&port->phy_list);
 	port->ha = sas_ha;
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index b6e233d..f0b9b7b 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -49,27 +49,12 @@
 #include <linux/scatterlist.h>
 #include <linux/libata.h>
 
-/* ---------- SCSI Host glue ---------- */
-
-static void sas_scsi_task_done(struct sas_task *task)
+/* record final status and free the task */
+static void sas_end_task(struct scsi_cmnd *sc, struct sas_task *task)
 {
 	struct task_status_struct *ts = &task->task_status;
-	struct scsi_cmnd *sc = task->uldd_task;
 	int hs = 0, stat = 0;
 
-	if (unlikely(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
-		/* Aborted tasks will be completed by the error handler */
-		SAS_DPRINTK("task done but aborted\n");
-		return;
-	}
-
-	if (unlikely(!sc)) {
-		SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n");
-		list_del_init(&task->list);
-		sas_free_task(task);
-		return;
-	}
-
 	if (ts->resp == SAS_TASK_UNDELIVERED) {
 		/* transport error */
 		hs = DID_NO_CONNECT;
@@ -124,10 +109,41 @@
 			break;
 		}
 	}
-	ASSIGN_SAS_TASK(sc, NULL);
+
 	sc->result = (hs << 16) | stat;
+	ASSIGN_SAS_TASK(sc, NULL);
 	list_del_init(&task->list);
 	sas_free_task(task);
+}
+
+static void sas_scsi_task_done(struct sas_task *task)
+{
+	struct scsi_cmnd *sc = task->uldd_task;
+	struct domain_device *dev = task->dev;
+	struct sas_ha_struct *ha = dev->port->ha;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->done_lock, flags);
+	if (test_bit(SAS_HA_FROZEN, &ha->state))
+		task = NULL;
+	else
+		ASSIGN_SAS_TASK(sc, NULL);
+	spin_unlock_irqrestore(&dev->done_lock, flags);
+
+	if (unlikely(!task)) {
+		/* task will be completed by the error handler */
+		SAS_DPRINTK("task done but aborted\n");
+		return;
+	}
+
+	if (unlikely(!sc)) {
+		SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n");
+		list_del_init(&task->list);
+		sas_free_task(task);
+		return;
+	}
+
+	sas_end_task(sc, task);
 	sc->scsi_done(sc);
 }
 
@@ -192,17 +208,15 @@
 	int res = 0;
 
 	/* If the device fell off, no sense in issuing commands */
-	if (dev->gone) {
+	if (test_bit(SAS_DEV_GONE, &dev->state)) {
 		cmd->result = DID_BAD_TARGET << 16;
 		goto out_done;
 	}
 
 	if (dev_is_sata(dev)) {
-		unsigned long flags;
-
-		spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
+		spin_lock_irq(dev->sata_dev.ap->lock);
 		res = ata_sas_queuecmd(cmd, dev->sata_dev.ap);
-		spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
+		spin_unlock_irq(dev->sata_dev.ap->lock);
 		return res;
 	}
 
@@ -235,24 +249,38 @@
 
 static void sas_eh_finish_cmd(struct scsi_cmnd *cmd)
 {
-	struct sas_task *task = TO_SAS_TASK(cmd);
 	struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host);
+	struct sas_task *task = TO_SAS_TASK(cmd);
 
-	/* remove the aborted task flag to allow the task to be
-	 * completed now. At this point, we only get called following
-	 * an actual abort of the task, so we should be guaranteed not
-	 * to be racing with any completions from the LLD (hence we
-	 * don't need the task state lock to clear the flag) */
-	task->task_state_flags &= ~SAS_TASK_STATE_ABORTED;
-	/* Now call task_done.  However, task will be free'd after
-	 * this */
-	task->task_done(task);
+	/* At this point, we only get called following an actual abort
+	 * of the task, so we should be guaranteed not to be racing with
+	 * any completions from the LLD.  Task is freed after this.
+	 */
+	sas_end_task(cmd, task);
+
 	/* now finish the command and move it on to the error
 	 * handler done list, this also takes it off the
-	 * error handler pending list */
+	 * error handler pending list.
+	 */
 	scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q);
 }
 
+static void sas_eh_defer_cmd(struct scsi_cmnd *cmd)
+{
+	struct domain_device *dev = cmd_to_domain_dev(cmd);
+	struct sas_ha_struct *ha = dev->port->ha;
+	struct sas_task *task = TO_SAS_TASK(cmd);
+
+	if (!dev_is_sata(dev)) {
+		sas_eh_finish_cmd(cmd);
+		return;
+	}
+
+	/* report the timeout to libata */
+	sas_end_task(cmd, task);
+	list_move_tail(&cmd->eh_entry, &ha->eh_ata_q);
+}
+
 static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd)
 {
 	struct scsi_cmnd *cmd, *n;
@@ -260,7 +288,7 @@
 	list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
 		if (cmd->device->sdev_target == my_cmd->device->sdev_target &&
 		    cmd->device->lun == my_cmd->device->lun)
-			sas_eh_finish_cmd(cmd);
+			sas_eh_defer_cmd(cmd);
 	}
 }
 
@@ -295,6 +323,7 @@
 	TASK_IS_DONE,
 	TASK_IS_ABORTED,
 	TASK_IS_AT_LU,
+	TASK_IS_NOT_AT_HA,
 	TASK_IS_NOT_AT_LU,
 	TASK_ABORT_FAILED,
 };
@@ -311,19 +340,18 @@
 		struct scsi_core *core = &ha->core;
 		struct sas_task *t, *n;
 
+		mutex_lock(&core->task_queue_flush);
 		spin_lock_irqsave(&core->task_queue_lock, flags);
-		list_for_each_entry_safe(t, n, &core->task_queue, list) {
+		list_for_each_entry_safe(t, n, &core->task_queue, list)
 			if (task == t) {
 				list_del_init(&t->list);
-				spin_unlock_irqrestore(&core->task_queue_lock,
-						       flags);
-				SAS_DPRINTK("%s: task 0x%p aborted from "
-					    "task_queue\n",
-					    __func__, task);
-				return TASK_IS_ABORTED;
+				break;
 			}
-		}
 		spin_unlock_irqrestore(&core->task_queue_lock, flags);
+		mutex_unlock(&core->task_queue_flush);
+
+		if (task == t)
+			return TASK_IS_NOT_AT_HA;
 	}
 
 	for (i = 0; i < 5; i++) {
@@ -411,30 +439,26 @@
 	return res;
 }
 
-/* Find the sas_phy that's attached to this device */
-struct sas_phy *sas_find_local_phy(struct domain_device *dev)
+/* take a reference on the last known good phy for this device */
+struct sas_phy *sas_get_local_phy(struct domain_device *dev)
 {
-	struct domain_device *pdev = dev->parent;
-	struct ex_phy *exphy = NULL;
-	int i;
+	struct sas_ha_struct *ha = dev->port->ha;
+	struct sas_phy *phy;
+	unsigned long flags;
 
-	/* Directly attached device */
-	if (!pdev)
-		return dev->port->phy;
+	/* a published domain device always has a valid phy, it may be
+	 * stale, but it is never NULL
+	 */
+	BUG_ON(!dev->phy);
 
-	/* Otherwise look in the expander */
-	for (i = 0; i < pdev->ex_dev.num_phys; i++)
-		if (!memcmp(dev->sas_addr,
-			    pdev->ex_dev.ex_phy[i].attached_sas_addr,
-			    SAS_ADDR_SIZE)) {
-			exphy = &pdev->ex_dev.ex_phy[i];
-			break;
-		}
+	spin_lock_irqsave(&ha->phy_port_lock, flags);
+	phy = dev->phy;
+	get_device(&phy->dev);
+	spin_unlock_irqrestore(&ha->phy_port_lock, flags);
 
-	BUG_ON(!exphy);
-	return exphy->phy;
+	return phy;
 }
-EXPORT_SYMBOL_GPL(sas_find_local_phy);
+EXPORT_SYMBOL_GPL(sas_get_local_phy);
 
 /* Attempt to send a LUN reset message to a device */
 int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
@@ -461,7 +485,7 @@
 int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
 {
 	struct domain_device *dev = cmd_to_domain_dev(cmd);
-	struct sas_phy *phy = sas_find_local_phy(dev);
+	struct sas_phy *phy = sas_get_local_phy(dev);
 	int res;
 
 	res = sas_phy_reset(phy, 1);
@@ -469,6 +493,8 @@
 		SAS_DPRINTK("Bus reset of %s failed 0x%x\n",
 			    kobject_name(&phy->dev.kobj),
 			    res);
+	sas_put_local_phy(phy);
+
 	if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE)
 		return SUCCESS;
 
@@ -495,9 +521,7 @@
 	return FAILED;
 }
 
-static int sas_eh_handle_sas_errors(struct Scsi_Host *shost,
-				    struct list_head *work_q,
-				    struct list_head *done_q)
+static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head *work_q)
 {
 	struct scsi_cmnd *cmd, *n;
 	enum task_disposition res = TASK_IS_DONE;
@@ -505,13 +529,28 @@
 	struct sas_internal *i = to_sas_internal(shost->transportt);
 	unsigned long flags;
 	struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+	LIST_HEAD(done);
 
-Again:
+	/* clean out any commands that won the completion vs eh race */
 	list_for_each_entry_safe(cmd, n, work_q, eh_entry) {
-		struct sas_task *task = TO_SAS_TASK(cmd);
+		struct domain_device *dev = cmd_to_domain_dev(cmd);
+		struct sas_task *task;
+
+		spin_lock_irqsave(&dev->done_lock, flags);
+		/* by this point the lldd has either observed
+		 * SAS_HA_FROZEN and is leaving the task alone, or has
+		 * won the race with eh and decided to complete it
+		 */
+		task = TO_SAS_TASK(cmd);
+		spin_unlock_irqrestore(&dev->done_lock, flags);
 
 		if (!task)
-			continue;
+			list_move_tail(&cmd->eh_entry, &done);
+	}
+
+ Again:
+	list_for_each_entry_safe(cmd, n, work_q, eh_entry) {
+		struct sas_task *task = TO_SAS_TASK(cmd);
 
 		list_del_init(&cmd->eh_entry);
 
@@ -531,15 +570,23 @@
 		cmd->eh_eflags = 0;
 
 		switch (res) {
+		case TASK_IS_NOT_AT_HA:
+			SAS_DPRINTK("%s: task 0x%p is not at ha: %s\n",
+				    __func__, task,
+				    cmd->retries ? "retry" : "aborted");
+			if (cmd->retries)
+				cmd->retries--;
+			sas_eh_finish_cmd(cmd);
+			continue;
 		case TASK_IS_DONE:
 			SAS_DPRINTK("%s: task 0x%p is done\n", __func__,
 				    task);
-			sas_eh_finish_cmd(cmd);
+			sas_eh_defer_cmd(cmd);
 			continue;
 		case TASK_IS_ABORTED:
 			SAS_DPRINTK("%s: task 0x%p is aborted\n",
 				    __func__, task);
-			sas_eh_finish_cmd(cmd);
+			sas_eh_defer_cmd(cmd);
 			continue;
 		case TASK_IS_AT_LU:
 			SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
@@ -550,7 +597,7 @@
 					    "recovered\n",
 					    SAS_ADDR(task->dev),
 					    cmd->device->lun);
-				sas_eh_finish_cmd(cmd);
+				sas_eh_defer_cmd(cmd);
 				sas_scsi_clear_queue_lu(work_q, cmd);
 				goto Again;
 			}
@@ -560,7 +607,8 @@
 			SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n",
 				    task);
 			tmf_resp = sas_recover_I_T(task->dev);
-			if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
+			if (tmf_resp == TMF_RESP_FUNC_COMPLETE ||
+			    tmf_resp == -ENODEV) {
 				struct domain_device *dev = task->dev;
 				SAS_DPRINTK("I_T %016llx recovered\n",
 					    SAS_ADDR(task->dev->sas_addr));
@@ -607,13 +655,16 @@
 			goto clear_q;
 		}
 	}
-	return list_empty(work_q);
-clear_q:
+ out:
+	list_splice_tail(&done, work_q);
+	list_splice_tail_init(&ha->eh_ata_q, work_q);
+	return;
+
+ clear_q:
 	SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__);
 	list_for_each_entry_safe(cmd, n, work_q, eh_entry)
 		sas_eh_finish_cmd(cmd);
-
-	return list_empty(work_q);
+	goto out;
 }
 
 void sas_scsi_recover_host(struct Scsi_Host *shost)
@@ -627,12 +678,17 @@
 	shost->host_eh_scheduled = 0;
 	spin_unlock_irqrestore(shost->host_lock, flags);
 
-	SAS_DPRINTK("Enter %s\n", __func__);
+	SAS_DPRINTK("Enter %s busy: %d failed: %d\n",
+		    __func__, shost->host_busy, shost->host_failed);
 	/*
 	 * Deal with commands that still have SAS tasks (i.e. they didn't
-	 * complete via the normal sas_task completion mechanism)
+	 * complete via the normal sas_task completion mechanism),
+	 * SAS_HA_FROZEN gives eh dominion over all sas_task completion.
 	 */
-	if (sas_eh_handle_sas_errors(shost, &eh_work_q, &ha->eh_done_q))
+	set_bit(SAS_HA_FROZEN, &ha->state);
+	sas_eh_handle_sas_errors(shost, &eh_work_q);
+	clear_bit(SAS_HA_FROZEN, &ha->state);
+	if (list_empty(&eh_work_q))
 		goto out;
 
 	/*
@@ -641,59 +697,26 @@
 	 * scsi_unjam_host does, but we skip scsi_eh_abort_cmds because any
 	 * command we see here has no sas_task and is thus unknown to the HA.
 	 */
-	if (!sas_ata_eh(shost, &eh_work_q, &ha->eh_done_q))
-		if (!scsi_eh_get_sense(&eh_work_q, &ha->eh_done_q))
-			scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q);
+	sas_ata_eh(shost, &eh_work_q, &ha->eh_done_q);
+	if (!scsi_eh_get_sense(&eh_work_q, &ha->eh_done_q))
+		scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q);
 
 out:
+	if (ha->lldd_max_execute_num > 1)
+		wake_up_process(ha->core.queue_thread);
+
 	/* now link into libata eh --- if we have any ata devices */
 	sas_ata_strategy_handler(shost);
 
 	scsi_eh_flush_done_q(&ha->eh_done_q);
 
-	SAS_DPRINTK("--- Exit %s\n", __func__);
-	return;
+	SAS_DPRINTK("--- Exit %s: busy: %d failed: %d\n",
+		    __func__, shost->host_busy, shost->host_failed);
 }
 
 enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
 {
-	struct sas_task *task = TO_SAS_TASK(cmd);
-	unsigned long flags;
-	enum blk_eh_timer_return rtn;
-
-	if (sas_ata_timed_out(cmd, task, &rtn))
-		return rtn;
-
-	if (!task) {
-		cmd->request->timeout /= 2;
-		SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n",
-			    cmd, task, (cmd->request->timeout ?
-			    "BLK_EH_RESET_TIMER" : "BLK_EH_NOT_HANDLED"));
-		if (!cmd->request->timeout)
-			return BLK_EH_NOT_HANDLED;
-		return BLK_EH_RESET_TIMER;
-	}
-
-	spin_lock_irqsave(&task->task_state_lock, flags);
-	BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED);
-	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
-		spin_unlock_irqrestore(&task->task_state_lock, flags);
-		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: "
-			    "BLK_EH_HANDLED\n", cmd, task);
-		return BLK_EH_HANDLED;
-	}
-	if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) {
-		spin_unlock_irqrestore(&task->task_state_lock, flags);
-		SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: "
-			    "BLK_EH_RESET_TIMER\n",
-			    cmd, task);
-		return BLK_EH_RESET_TIMER;
-	}
-	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
-	spin_unlock_irqrestore(&task->task_state_lock, flags);
-
-	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: BLK_EH_NOT_HANDLED\n",
-		    cmd, task);
+	scmd_printk(KERN_DEBUG, cmd, "command %p timed out\n", cmd);
 
 	return BLK_EH_NOT_HANDLED;
 }
@@ -737,27 +760,15 @@
 	return found_dev;
 }
 
-static inline struct domain_device *sas_find_target(struct scsi_target *starget)
-{
-	struct sas_rphy *rphy = dev_to_rphy(starget->dev.parent);
-
-	return sas_find_dev_by_rphy(rphy);
-}
-
 int sas_target_alloc(struct scsi_target *starget)
 {
-	struct domain_device *found_dev = sas_find_target(starget);
-	int res;
+	struct sas_rphy *rphy = dev_to_rphy(starget->dev.parent);
+	struct domain_device *found_dev = sas_find_dev_by_rphy(rphy);
 
 	if (!found_dev)
 		return -ENODEV;
 
-	if (dev_is_sata(found_dev)) {
-		res = sas_ata_init_host_and_port(found_dev, starget);
-		if (res)
-			return res;
-	}
-
+	kref_get(&found_dev->kref);
 	starget->hostdata = found_dev;
 	return 0;
 }
@@ -797,14 +808,6 @@
 	return 0;
 }
 
-void sas_slave_destroy(struct scsi_device *scsi_dev)
-{
-	struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
-
-	if (dev_is_sata(dev))
-		sas_to_ata_dev(dev)->class = ATA_DEV_NONE;
-}
-
 int sas_change_queue_depth(struct scsi_device *sdev, int depth, int reason)
 {
 	struct domain_device *dev = sdev_to_domain_dev(sdev);
@@ -871,9 +874,11 @@
 	int res;
 	struct sas_internal *i = to_sas_internal(core->shost->transportt);
 
+	mutex_lock(&core->task_queue_flush);
 	spin_lock_irqsave(&core->task_queue_lock, flags);
 	while (!kthread_should_stop() &&
-	       !list_empty(&core->task_queue)) {
+	       !list_empty(&core->task_queue) &&
+	       !test_bit(SAS_HA_FROZEN, &sas_ha->state)) {
 
 		can_queue = sas_ha->lldd_queue_size - core->task_queue_size;
 		if (can_queue >= 0) {
@@ -909,6 +914,7 @@
 		}
 	}
 	spin_unlock_irqrestore(&core->task_queue_lock, flags);
+	mutex_unlock(&core->task_queue_flush);
 }
 
 /**
@@ -935,6 +941,7 @@
 	struct scsi_core *core = &sas_ha->core;
 
 	spin_lock_init(&core->task_queue_lock);
+	mutex_init(&core->task_queue_flush);
 	core->task_queue_size = 0;
 	INIT_LIST_HEAD(&core->task_queue);
 
@@ -972,49 +979,6 @@
 }
 
 /*
- * Call the LLDD task abort routine directly.  This function is intended for
- * use by upper layers that need to tell the LLDD to abort a task.
- */
-int __sas_task_abort(struct sas_task *task)
-{
-	struct sas_internal *si =
-		to_sas_internal(task->dev->port->ha->core.shost->transportt);
-	unsigned long flags;
-	int res;
-
-	spin_lock_irqsave(&task->task_state_lock, flags);
-	if (task->task_state_flags & SAS_TASK_STATE_ABORTED ||
-	    task->task_state_flags & SAS_TASK_STATE_DONE) {
-		spin_unlock_irqrestore(&task->task_state_lock, flags);
-		SAS_DPRINTK("%s: Task %p already finished.\n", __func__,
-			    task);
-		return 0;
-	}
-	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
-	spin_unlock_irqrestore(&task->task_state_lock, flags);
-
-	if (!si->dft->lldd_abort_task)
-		return -ENODEV;
-
-	res = si->dft->lldd_abort_task(task);
-
-	spin_lock_irqsave(&task->task_state_lock, flags);
-	if ((task->task_state_flags & SAS_TASK_STATE_DONE) ||
-	    (res == TMF_RESP_FUNC_COMPLETE))
-	{
-		spin_unlock_irqrestore(&task->task_state_lock, flags);
-		task->task_done(task);
-		return 0;
-	}
-
-	if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
-		task->task_state_flags &= ~SAS_TASK_STATE_ABORTED;
-	spin_unlock_irqrestore(&task->task_state_lock, flags);
-
-	return -EAGAIN;
-}
-
-/*
  * Tell an upper layer that it needs to initiate an abort for a given task.
  * This should only ever be called by an LLDD.
  */
@@ -1043,27 +1007,15 @@
 	}
 }
 
-int sas_slave_alloc(struct scsi_device *scsi_dev)
-{
-	struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
-
-	if (dev_is_sata(dev))
-		return ata_sas_port_init(dev->sata_dev.ap);
-
-	return 0;
-}
-
 void sas_target_destroy(struct scsi_target *starget)
 {
-	struct domain_device *found_dev = sas_find_target(starget);
+	struct domain_device *found_dev = starget->hostdata;
 
 	if (!found_dev)
 		return;
 
-	if (dev_is_sata(found_dev))
-		ata_sas_port_destroy(found_dev->sata_dev.ap);
-
-	return;
+	starget->hostdata = NULL;
+	sas_put_device(found_dev);
 }
 
 static void sas_parse_addr(u8 *sas_addr, const char *p)
@@ -1108,16 +1060,12 @@
 EXPORT_SYMBOL_GPL(sas_queuecommand);
 EXPORT_SYMBOL_GPL(sas_target_alloc);
 EXPORT_SYMBOL_GPL(sas_slave_configure);
-EXPORT_SYMBOL_GPL(sas_slave_destroy);
 EXPORT_SYMBOL_GPL(sas_change_queue_depth);
 EXPORT_SYMBOL_GPL(sas_change_queue_type);
 EXPORT_SYMBOL_GPL(sas_bios_param);
-EXPORT_SYMBOL_GPL(__sas_task_abort);
 EXPORT_SYMBOL_GPL(sas_task_abort);
 EXPORT_SYMBOL_GPL(sas_phy_reset);
-EXPORT_SYMBOL_GPL(sas_phy_enable);
 EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler);
 EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler);
-EXPORT_SYMBOL_GPL(sas_slave_alloc);
 EXPORT_SYMBOL_GPL(sas_target_destroy);
 EXPORT_SYMBOL_GPL(sas_ioctl);
diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile
index 88928f0..fe5d396 100644
--- a/drivers/scsi/lpfc/Makefile
+++ b/drivers/scsi/lpfc/Makefile
@@ -1,7 +1,7 @@
 #/*******************************************************************
 # * This file is part of the Emulex Linux Device Driver for         *
 # * Fibre Channel Host Bus Adapters.                                *
-# * Copyright (C) 2004-2011 Emulex.  All rights reserved.           *
+# * Copyright (C) 2004-2012 Emulex.  All rights reserved.           *
 # * EMULEX and SLI are trademarks of Emulex.                        *
 # * www.emulex.com                                                  *
 # *                                                                 *
@@ -22,6 +22,8 @@
 ccflags-$(GCOV) := -fprofile-arcs -ftest-coverage
 ccflags-$(GCOV) += -O0
 
+ccflags-y += -Werror
+
 obj-$(CONFIG_SCSI_LPFC) := lpfc.o
 
 lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o	\
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 825f930..3a1ffdd 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2011 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2012 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -534,6 +534,7 @@
 	void (*lpfc_scsi_prep_cmnd)
 		(struct lpfc_vport *, struct lpfc_scsi_buf *,
 		 struct lpfc_nodelist *);
+
 	/* IOCB interface function jump table entries */
 	int (*__lpfc_sli_issue_iocb)
 		(struct lpfc_hba *, uint32_t,
@@ -541,8 +542,6 @@
 	void (*__lpfc_sli_release_iocbq)(struct lpfc_hba *,
 			 struct lpfc_iocbq *);
 	int (*lpfc_hba_down_post)(struct lpfc_hba *phba);
-
-
 	IOCB_t * (*lpfc_get_iocb_from_iocbq)
 		(struct lpfc_iocbq *);
 	void (*lpfc_scsi_cmd_iocb_cmpl)
@@ -551,10 +550,12 @@
 	/* MBOX interface function jump table entries */
 	int (*lpfc_sli_issue_mbox)
 		(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
+
 	/* Slow-path IOCB process function jump table entries */
 	void (*lpfc_sli_handle_slow_ring_event)
 		(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		 uint32_t mask);
+
 	/* INIT device interface function jump table entries */
 	int (*lpfc_sli_hbq_to_firmware)
 		(struct lpfc_hba *, uint32_t, struct hbq_dmabuf *);
@@ -573,6 +574,10 @@
 	int (*lpfc_selective_reset)
 		(struct lpfc_hba *);
 
+	int (*lpfc_bg_scsi_prep_dma_buf)
+		(struct lpfc_hba *, struct lpfc_scsi_buf *);
+	/* Add new entries here */
+
 	/* SLI4 specific HBA data structure */
 	struct lpfc_sli4_hba sli4_hba;
 
@@ -835,9 +840,12 @@
 	struct dentry *debug_dumpData;   /* BlockGuard BPL */
 	struct dentry *debug_dumpDif;    /* BlockGuard BPL */
 	struct dentry *debug_InjErrLBA;  /* LBA to inject errors at */
+	struct dentry *debug_InjErrNPortID;  /* NPortID to inject errors at */
+	struct dentry *debug_InjErrWWPN;  /* WWPN to inject errors at */
 	struct dentry *debug_writeGuard; /* inject write guard_tag errors */
 	struct dentry *debug_writeApp;   /* inject write app_tag errors */
 	struct dentry *debug_writeRef;   /* inject write ref_tag errors */
+	struct dentry *debug_readGuard;  /* inject read guard_tag errors */
 	struct dentry *debug_readApp;    /* inject read app_tag errors */
 	struct dentry *debug_readRef;    /* inject read ref_tag errors */
 
@@ -845,10 +853,13 @@
 	uint32_t lpfc_injerr_wgrd_cnt;
 	uint32_t lpfc_injerr_wapp_cnt;
 	uint32_t lpfc_injerr_wref_cnt;
+	uint32_t lpfc_injerr_rgrd_cnt;
 	uint32_t lpfc_injerr_rapp_cnt;
 	uint32_t lpfc_injerr_rref_cnt;
+	uint32_t lpfc_injerr_nportid;
+	struct lpfc_name lpfc_injerr_wwpn;
 	sector_t lpfc_injerr_lba;
-#define LPFC_INJERR_LBA_OFF	(sector_t)0xffffffffffffffff
+#define LPFC_INJERR_LBA_OFF	(sector_t)(-1)
 
 	struct dentry *debug_slow_ring_trc;
 	struct lpfc_debugfs_trc *slow_ring_trc;
@@ -901,6 +912,8 @@
 	atomic_t fast_event_count;
 	uint32_t fcoe_eventtag;
 	uint32_t fcoe_eventtag_at_fcf_scan;
+	uint32_t fcoe_cvl_eventtag;
+	uint32_t fcoe_cvl_eventtag_attn;
 	struct lpfc_fcf fcf;
 	uint8_t fc_map[3];
 	uint8_t valid_vlan;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index f6697cb..5eb2bc1 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2011 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2012 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -353,7 +353,7 @@
 	struct lpfc_hba   *phba = vport->phba;
 	uint32_t if_type;
 	uint8_t sli_family;
-	char fwrev[32];
+	char fwrev[FW_REV_STR_SIZE];
 	int len;
 
 	lpfc_decode_firmware_rev(phba, fwrev, 1);
@@ -922,11 +922,15 @@
 	rc = lpfc_sli4_pdev_status_reg_wait(phba);
 
 	if (rc == -EPERM) {
-		/* no privilage for reset, restore if needed */
-		if (before_fc_flag & FC_OFFLINE_MODE)
-			goto out;
+		/* no privilage for reset */
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"3150 No privilage to perform the requested "
+				"access: x%x\n", reg_val);
 	} else if (rc == -EIO) {
 		/* reset failed, there is nothing more we can do */
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"3153 Fail to perform the requested "
+				"access: x%x\n", reg_val);
 		return rc;
 	}
 
@@ -2571,7 +2575,7 @@
 # lpfc_enable_da_id: This turns on the DA_ID CT command that deregisters
 # objects that have been registered with the nameserver after login.
 */
-LPFC_VPORT_ATTR_R(enable_da_id, 0, 0, 1,
+LPFC_VPORT_ATTR_R(enable_da_id, 1, 0, 1,
 		  "Deregister nameserver objects before LOGO");
 
 /*
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index 56a86ba..141e4b4 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -589,7 +589,10 @@
 	}
 	cmdiocbq->iocb.un.elsreq64.bdl.bdeSize =
 		(request_nseg + reply_nseg) * sizeof(struct ulp_bde64);
-	cmdiocbq->iocb.ulpContext = rpi;
+	if (phba->sli_rev == LPFC_SLI_REV4)
+		cmdiocbq->iocb.ulpContext = phba->sli4_hba.rpi_ids[rpi];
+	else
+		cmdiocbq->iocb.ulpContext = rpi;
 	cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
 	cmdiocbq->context1 = NULL;
 	cmdiocbq->context2 = NULL;
@@ -1768,7 +1771,7 @@
 	bf_set(lpfc_mbx_set_diag_state_link_type,
 	       &link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_tp);
 	bf_set(lpfc_mbx_set_diag_lpbk_type, &link_diag_loopback->u.req,
-	       LPFC_DIAG_LOOPBACK_TYPE_SERDES);
+	       LPFC_DIAG_LOOPBACK_TYPE_INTERNAL);
 
 	mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO);
 	if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) {
@@ -3977,7 +3980,7 @@
 			case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES:
 				lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
 						"3106 Handled SLI_CONFIG "
-						"subsys_fcoe, opcode:x%x\n",
+						"subsys_comn, opcode:x%x\n",
 						opcode);
 				rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job,
 							nemb_mse, dmabuf);
@@ -3985,7 +3988,7 @@
 			default:
 				lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
 						"3107 Reject SLI_CONFIG "
-						"subsys_fcoe, opcode:x%x\n",
+						"subsys_comn, opcode:x%x\n",
 						opcode);
 				rc = -EPERM;
 				break;
@@ -4556,7 +4559,12 @@
 							+ sizeof(MAILBOX_t));
 		}
 	} else if (phba->sli_rev == LPFC_SLI_REV4) {
-		if (pmb->mbxCommand == MBX_DUMP_MEMORY) {
+		/* Let type 4 (well known data) through because the data is
+		 * returned in varwords[4-8]
+		 * otherwise check the recieve length and fetch the buffer addr
+		 */
+		if ((pmb->mbxCommand == MBX_DUMP_MEMORY) &&
+			(pmb->un.varDmp.type != DMP_WELL_KNOWN)) {
 			/* rebuild the command for sli4 using our own buffers
 			* like we do for biu diags
 			*/
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 26924b7..330dd71 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -462,3 +462,4 @@
 int lpfc_selective_reset(struct lpfc_hba *);
 int lpfc_sli4_read_config(struct lpfc_hba *phba);
 int lpfc_scsi_buf_update(struct lpfc_hba *phba);
+void lpfc_sli4_node_prep(struct lpfc_hba *phba);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 707081d..93e96b3 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -1076,7 +1076,7 @@
 lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol,
 	size_t size)
 {
-	char fwrev[16];
+	char fwrev[FW_REV_STR_SIZE];
 	int n;
 
 	lpfc_decode_firmware_rev(vport->phba, fwrev, 0);
@@ -1834,7 +1834,7 @@
 	uint8_t *fwname;
 
 	if (phba->sli_rev == LPFC_SLI_REV4)
-		sprintf(fwrevision, "%s", vp->rev.opFwName);
+		snprintf(fwrevision, FW_REV_STR_SIZE, "%s", vp->rev.opFwName);
 	else if (vp->rev.rBit) {
 		if (psli->sli_flag & LPFC_SLI_ACTIVE)
 			rev = vp->rev.sli2FwRev;
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 3587a3f..af04b0d 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2007-2011 Emulex.  All rights reserved.           *
+ * Copyright (C) 2007-2012 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -997,36 +997,41 @@
 	return nbytes;
 }
 
-static int
-lpfc_debugfs_dif_err_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t
 lpfc_debugfs_dif_err_read(struct file *file, char __user *buf,
 	size_t nbytes, loff_t *ppos)
 {
 	struct dentry *dent = file->f_dentry;
 	struct lpfc_hba *phba = file->private_data;
-	char cbuf[16];
+	char cbuf[32];
+	uint64_t tmp = 0;
 	int cnt = 0;
 
 	if (dent == phba->debug_writeGuard)
-		cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_wgrd_cnt);
+		cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wgrd_cnt);
 	else if (dent == phba->debug_writeApp)
-		cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_wapp_cnt);
+		cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wapp_cnt);
 	else if (dent == phba->debug_writeRef)
-		cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_wref_cnt);
+		cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wref_cnt);
+	else if (dent == phba->debug_readGuard)
+		cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rgrd_cnt);
 	else if (dent == phba->debug_readApp)
-		cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_rapp_cnt);
+		cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rapp_cnt);
 	else if (dent == phba->debug_readRef)
-		cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_rref_cnt);
-	else if (dent == phba->debug_InjErrLBA)
-		cnt = snprintf(cbuf, 16, "0x%lx\n",
-				 (unsigned long) phba->lpfc_injerr_lba);
-	else
+		cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rref_cnt);
+	else if (dent == phba->debug_InjErrNPortID)
+		cnt = snprintf(cbuf, 32, "0x%06x\n", phba->lpfc_injerr_nportid);
+	else if (dent == phba->debug_InjErrWWPN) {
+		memcpy(&tmp, &phba->lpfc_injerr_wwpn, sizeof(struct lpfc_name));
+		tmp = cpu_to_be64(tmp);
+		cnt = snprintf(cbuf, 32, "0x%016llx\n", tmp);
+	} else if (dent == phba->debug_InjErrLBA) {
+		if (phba->lpfc_injerr_lba == (sector_t)(-1))
+			cnt = snprintf(cbuf, 32, "off\n");
+		else
+			cnt = snprintf(cbuf, 32, "0x%llx\n",
+				 (uint64_t) phba->lpfc_injerr_lba);
+	} else
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 			 "0547 Unknown debugfs error injection entry\n");
 
@@ -1040,7 +1045,7 @@
 	struct dentry *dent = file->f_dentry;
 	struct lpfc_hba *phba = file->private_data;
 	char dstbuf[32];
-	unsigned long tmp;
+	uint64_t tmp = 0;
 	int size;
 
 	memset(dstbuf, 0, 32);
@@ -1048,7 +1053,12 @@
 	if (copy_from_user(dstbuf, buf, size))
 		return 0;
 
-	if (strict_strtoul(dstbuf, 0, &tmp))
+	if (dent == phba->debug_InjErrLBA) {
+		if ((buf[0] == 'o') && (buf[1] == 'f') && (buf[2] == 'f'))
+			tmp = (uint64_t)(-1);
+	}
+
+	if ((tmp == 0) && (kstrtoull(dstbuf, 0, &tmp)))
 		return 0;
 
 	if (dent == phba->debug_writeGuard)
@@ -1057,13 +1067,20 @@
 		phba->lpfc_injerr_wapp_cnt = (uint32_t)tmp;
 	else if (dent == phba->debug_writeRef)
 		phba->lpfc_injerr_wref_cnt = (uint32_t)tmp;
+	else if (dent == phba->debug_readGuard)
+		phba->lpfc_injerr_rgrd_cnt = (uint32_t)tmp;
 	else if (dent == phba->debug_readApp)
 		phba->lpfc_injerr_rapp_cnt = (uint32_t)tmp;
 	else if (dent == phba->debug_readRef)
 		phba->lpfc_injerr_rref_cnt = (uint32_t)tmp;
 	else if (dent == phba->debug_InjErrLBA)
 		phba->lpfc_injerr_lba = (sector_t)tmp;
-	else
+	else if (dent == phba->debug_InjErrNPortID)
+		phba->lpfc_injerr_nportid = (uint32_t)(tmp & Mask_DID);
+	else if (dent == phba->debug_InjErrWWPN) {
+		tmp = cpu_to_be64(tmp);
+		memcpy(&phba->lpfc_injerr_wwpn, &tmp, sizeof(struct lpfc_name));
+	} else
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 			 "0548 Unknown debugfs error injection entry\n");
 
@@ -3517,7 +3534,7 @@
 #undef lpfc_debugfs_op_dif_err
 static const struct file_operations lpfc_debugfs_op_dif_err = {
 	.owner =	THIS_MODULE,
-	.open =		lpfc_debugfs_dif_err_open,
+	.open =		simple_open,
 	.llseek =	lpfc_debugfs_lseek,
 	.read =		lpfc_debugfs_dif_err_read,
 	.write =	lpfc_debugfs_dif_err_write,
@@ -3945,6 +3962,28 @@
 		}
 		phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
 
+		snprintf(name, sizeof(name), "InjErrNPortID");
+		phba->debug_InjErrNPortID =
+			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+			phba->hba_debugfs_root,
+			phba, &lpfc_debugfs_op_dif_err);
+		if (!phba->debug_InjErrNPortID) {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+				"0809 Cannot create debugfs InjErrNPortID\n");
+			goto debug_failed;
+		}
+
+		snprintf(name, sizeof(name), "InjErrWWPN");
+		phba->debug_InjErrWWPN =
+			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+			phba->hba_debugfs_root,
+			phba, &lpfc_debugfs_op_dif_err);
+		if (!phba->debug_InjErrWWPN) {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+				"0810 Cannot create debugfs InjErrWWPN\n");
+			goto debug_failed;
+		}
+
 		snprintf(name, sizeof(name), "writeGuardInjErr");
 		phba->debug_writeGuard =
 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
@@ -3978,6 +4017,17 @@
 			goto debug_failed;
 		}
 
+		snprintf(name, sizeof(name), "readGuardInjErr");
+		phba->debug_readGuard =
+			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+			phba->hba_debugfs_root,
+			phba, &lpfc_debugfs_op_dif_err);
+		if (!phba->debug_readGuard) {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+				"0808 Cannot create debugfs readGuard\n");
+			goto debug_failed;
+		}
+
 		snprintf(name, sizeof(name), "readAppInjErr");
 		phba->debug_readApp =
 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
@@ -4306,6 +4356,14 @@
 			debugfs_remove(phba->debug_InjErrLBA); /* InjErrLBA */
 			phba->debug_InjErrLBA = NULL;
 		}
+		if (phba->debug_InjErrNPortID) {	 /* InjErrNPortID */
+			debugfs_remove(phba->debug_InjErrNPortID);
+			phba->debug_InjErrNPortID = NULL;
+		}
+		if (phba->debug_InjErrWWPN) {
+			debugfs_remove(phba->debug_InjErrWWPN); /* InjErrWWPN */
+			phba->debug_InjErrWWPN = NULL;
+		}
 		if (phba->debug_writeGuard) {
 			debugfs_remove(phba->debug_writeGuard); /* writeGuard */
 			phba->debug_writeGuard = NULL;
@@ -4318,6 +4376,10 @@
 			debugfs_remove(phba->debug_writeRef); /* writeRef */
 			phba->debug_writeRef = NULL;
 		}
+		if (phba->debug_readGuard) {
+			debugfs_remove(phba->debug_readGuard); /* readGuard */
+			phba->debug_readGuard = NULL;
+		}
 		if (phba->debug_readApp) {
 			debugfs_remove(phba->debug_readApp); /* readApp */
 			phba->debug_readApp = NULL;
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 7afc757..3407b39 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2011 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2012 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -925,9 +925,17 @@
 		 * due to new FCF discovery
 		 */
 		if ((phba->hba_flag & HBA_FIP_SUPPORT) &&
-		    (phba->fcf.fcf_flag & FCF_DISCOVERY) &&
-		    !((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
-		     (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))) {
+		    (phba->fcf.fcf_flag & FCF_DISCOVERY)) {
+			if (phba->link_state < LPFC_LINK_UP)
+				goto stop_rr_fcf_flogi;
+			if ((phba->fcoe_cvl_eventtag_attn ==
+			     phba->fcoe_cvl_eventtag) &&
+			    (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+			    (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))
+				goto stop_rr_fcf_flogi;
+			else
+				phba->fcoe_cvl_eventtag_attn =
+					phba->fcoe_cvl_eventtag;
 			lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS,
 					"2611 FLOGI failed on FCF (x%x), "
 					"status:x%x/x%x, tmo:x%x, perform "
@@ -943,6 +951,7 @@
 				goto out;
 		}
 
+stop_rr_fcf_flogi:
 		/* FLOGI failure */
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
 				"2858 FLOGI failure Status:x%x/x%x TMO:x%x\n",
@@ -1526,7 +1535,6 @@
 			memcpy(&ndlp->active_rrqs.xri_bitmap,
 				&rrq.xri_bitmap,
 				sizeof(ndlp->active_rrqs.xri_bitmap));
-		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
 		/* Since we are swapping the ndlp passed in with the new one
 		 * and the did has already been swapped, copy over the
 		 * state and names.
@@ -1536,6 +1544,7 @@
 		memcpy(&new_ndlp->nlp_nodename, &ndlp->nlp_nodename,
 			sizeof(struct lpfc_name));
 		new_ndlp->nlp_state = ndlp->nlp_state;
+		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
 		/* Fix up the rport accordingly */
 		rport = ndlp->rport;
 		if (rport) {
@@ -7172,7 +7181,7 @@
 			goto out;
 		/* FDISC failed */
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-				 "0126 FDISC failed. (%d/%d)\n",
+				 "0126 FDISC failed. (x%x/x%x)\n",
 				 irsp->ulpStatus, irsp->un.ulpWord[4]);
 		goto fdisc_failed;
 	}
@@ -7283,6 +7292,7 @@
 	int rc;
 
 	vport->port_state = LPFC_FDISC;
+	vport->fc_myDID = 0;
 	cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
 	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
 				     ELS_CMD_FDISC);
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 678a4b1..b507536 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2011 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2012 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -2843,7 +2843,14 @@
 	struct lpfc_vport *vport = mboxq->vport;
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 
-	if (mboxq->u.mb.mbxStatus) {
+	/*
+	 * VFI not supported for interface type 0, so ignore any mailbox
+	 * error (except VFI in use) and continue with the discovery.
+	 */
+	if (mboxq->u.mb.mbxStatus &&
+	    (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+			LPFC_SLI_INTF_IF_TYPE_0) &&
+	    mboxq->u.mb.mbxStatus != MBX_VFI_IN_USE) {
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
 			 "2018 REG_VFI mbxStatus error x%x "
 			 "HBA state x%x\n",
@@ -2977,9 +2984,9 @@
 				"topology\n");
 				/* Get Loop Map information */
 		if (bf_get(lpfc_mbx_read_top_il, la)) {
-			spin_lock_irq(shost->host_lock);
+			spin_lock(shost->host_lock);
 			vport->fc_flag |= FC_LBIT;
-			spin_unlock_irq(shost->host_lock);
+			spin_unlock(shost->host_lock);
 		}
 
 		vport->fc_myDID = bf_get(lpfc_mbx_read_top_alpa_granted, la);
@@ -3029,9 +3036,9 @@
 				phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
 		}
 		vport->fc_myDID = phba->fc_pref_DID;
-		spin_lock_irq(shost->host_lock);
+		spin_lock(shost->host_lock);
 		vport->fc_flag |= FC_LBIT;
-		spin_unlock_irq(shost->host_lock);
+		spin_unlock(shost->host_lock);
 	}
 	spin_unlock_irq(&phba->hbalock);
 
@@ -5332,6 +5339,10 @@
 {
 	uint16_t *rpi = param;
 
+	/* check for active node */
+	if (!NLP_CHK_NODE_ACT(ndlp))
+		return 0;
+
 	return ndlp->nlp_rpi == *rpi;
 }
 
@@ -5669,14 +5680,13 @@
 				ret = 1;
 				spin_unlock_irq(shost->host_lock);
 				goto out;
-			} else {
+			} else if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
+				ret = 1;
 				lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-					"2624 RPI %x DID %x flg %x still "
-					"logged in\n",
-					ndlp->nlp_rpi, ndlp->nlp_DID,
-					ndlp->nlp_flag);
-				if (ndlp->nlp_flag & NLP_RPI_REGISTERED)
-					ret = 1;
+						"2624 RPI %x DID %x flag %x "
+						"still logged in\n",
+						ndlp->nlp_rpi, ndlp->nlp_DID,
+						ndlp->nlp_flag);
 			}
 		}
 		spin_unlock_irq(shost->host_lock);
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 7245bea..5f280b5 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2010 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2011 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -70,6 +70,7 @@
 /* vendor ID used in SCSI netlink calls */
 #define LPFC_NL_VENDOR_ID (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX)
 
+#define FW_REV_STR_SIZE	32
 /* Common Transport structures and definitions */
 
 union CtRevisionId {
@@ -2567,6 +2568,8 @@
 
 #define  DMP_MEM_REG             0x1
 #define  DMP_NV_PARAMS           0x2
+#define  DMP_LMSD                0x3 /* Link Module Serial Data */
+#define  DMP_WELL_KNOWN          0x4
 
 #define  DMP_REGION_VPD          0xe
 #define  DMP_VPD_SIZE            0x400  /* maximum amount of VPD */
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index e5bfa7f..91f0976 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2009 Emulex.  All rights reserved.                *
+ * Copyright (C) 2009-2012 Emulex.  All rights reserved.                *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -321,6 +321,10 @@
 #define CQE_STATUS_CMD_REJECT		0xb
 #define CQE_STATUS_FCP_TGT_LENCHECK	0xc
 #define CQE_STATUS_NEED_BUFF_ENTRY	0xf
+#define CQE_STATUS_DI_ERROR		0x16
+
+/* Used when mapping CQE status to IOCB */
+#define LPFC_IOCB_STATUS_MASK		0xf
 
 /* Status returned by hardware (valid only if status = CQE_STATUS_SUCCESS). */
 #define CQE_HW_STATUS_NO_ERR		0x0
@@ -334,6 +338,12 @@
 #define CQE_CODE_XRI_ABORTED		0x5
 #define CQE_CODE_RECEIVE_V1		0x9
 
+/*
+ * Define mask value for xri_aborted and wcqe completed CQE extended status.
+ * Currently, extended status is limited to 9 bits (0x0 -> 0x103) .
+ */
+#define WCQE_PARAM_MASK		0x1FF;
+
 /* completion queue entry for wqe completions */
 struct lpfc_wcqe_complete {
 	uint32_t word0;
@@ -348,6 +358,21 @@
 #define lpfc_wcqe_c_hw_status_WORD	word0
 	uint32_t total_data_placed;
 	uint32_t parameter;
+#define lpfc_wcqe_c_bg_edir_SHIFT	5
+#define lpfc_wcqe_c_bg_edir_MASK	0x00000001
+#define lpfc_wcqe_c_bg_edir_WORD	parameter
+#define lpfc_wcqe_c_bg_tdpv_SHIFT	3
+#define lpfc_wcqe_c_bg_tdpv_MASK	0x00000001
+#define lpfc_wcqe_c_bg_tdpv_WORD	parameter
+#define lpfc_wcqe_c_bg_re_SHIFT		2
+#define lpfc_wcqe_c_bg_re_MASK		0x00000001
+#define lpfc_wcqe_c_bg_re_WORD		parameter
+#define lpfc_wcqe_c_bg_ae_SHIFT		1
+#define lpfc_wcqe_c_bg_ae_MASK		0x00000001
+#define lpfc_wcqe_c_bg_ae_WORD		parameter
+#define lpfc_wcqe_c_bg_ge_SHIFT		0
+#define lpfc_wcqe_c_bg_ge_MASK		0x00000001
+#define lpfc_wcqe_c_bg_ge_WORD		parameter
 	uint32_t word3;
 #define lpfc_wcqe_c_valid_SHIFT		lpfc_cqe_valid_SHIFT
 #define lpfc_wcqe_c_valid_MASK		lpfc_cqe_valid_MASK
@@ -359,8 +384,8 @@
 #define lpfc_wcqe_c_pv_MASK		0x00000001
 #define lpfc_wcqe_c_pv_WORD		word3
 #define lpfc_wcqe_c_priority_SHIFT	24
-#define lpfc_wcqe_c_priority_MASK		0x00000007
-#define lpfc_wcqe_c_priority_WORD		word3
+#define lpfc_wcqe_c_priority_MASK	0x00000007
+#define lpfc_wcqe_c_priority_WORD	word3
 #define lpfc_wcqe_c_code_SHIFT		lpfc_cqe_code_SHIFT
 #define lpfc_wcqe_c_code_MASK		lpfc_cqe_code_MASK
 #define lpfc_wcqe_c_code_WORD		lpfc_cqe_code_WORD
@@ -715,12 +740,20 @@
 #define lpfc_eqcq_doorbell_eqci_SHIFT		9
 #define lpfc_eqcq_doorbell_eqci_MASK		0x0001
 #define lpfc_eqcq_doorbell_eqci_WORD		word0
-#define lpfc_eqcq_doorbell_cqid_SHIFT		0
-#define lpfc_eqcq_doorbell_cqid_MASK		0x03FF
-#define lpfc_eqcq_doorbell_cqid_WORD		word0
-#define lpfc_eqcq_doorbell_eqid_SHIFT		0
-#define lpfc_eqcq_doorbell_eqid_MASK		0x01FF
-#define lpfc_eqcq_doorbell_eqid_WORD		word0
+#define lpfc_eqcq_doorbell_cqid_lo_SHIFT	0
+#define lpfc_eqcq_doorbell_cqid_lo_MASK		0x03FF
+#define lpfc_eqcq_doorbell_cqid_lo_WORD		word0
+#define lpfc_eqcq_doorbell_cqid_hi_SHIFT	11
+#define lpfc_eqcq_doorbell_cqid_hi_MASK		0x001F
+#define lpfc_eqcq_doorbell_cqid_hi_WORD		word0
+#define lpfc_eqcq_doorbell_eqid_lo_SHIFT	0
+#define lpfc_eqcq_doorbell_eqid_lo_MASK		0x01FF
+#define lpfc_eqcq_doorbell_eqid_lo_WORD		word0
+#define lpfc_eqcq_doorbell_eqid_hi_SHIFT	11
+#define lpfc_eqcq_doorbell_eqid_hi_MASK		0x001F
+#define lpfc_eqcq_doorbell_eqid_hi_WORD		word0
+#define LPFC_CQID_HI_FIELD_SHIFT		10
+#define LPFC_EQID_HI_FIELD_SHIFT		9
 
 #define LPFC_BMBX			0x0160
 #define lpfc_bmbx_addr_SHIFT		2
@@ -3313,7 +3346,11 @@
 	uint32_t rsrvd4;
 	struct wqe_did	wqe_dest;
 	struct wqe_common wqe_com; /* words 6-11 */
-	uint32_t rsvd_12_15[4];
+	uint32_t word12;
+#define xmit_bls_rsp64_temprpi_SHIFT  0
+#define xmit_bls_rsp64_temprpi_MASK   0x0000ffff
+#define xmit_bls_rsp64_temprpi_WORD   word12
+	uint32_t rsvd_13_15[3];
 };
 
 struct wqe_rctl_dfctl {
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index dfea2da..9598fdc 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2011 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2012 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -32,6 +32,7 @@
 #include <linux/aer.h>
 #include <linux/slab.h>
 #include <linux/firmware.h>
+#include <linux/miscdevice.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
@@ -1474,8 +1475,12 @@
 				phba->sli4_hba.u.if_type2.STATUSregaddr,
 				&portstat_reg.word0);
 		/* consider PCI bus read error as pci_channel_offline */
-		if (pci_rd_rc1 == -EIO)
+		if (pci_rd_rc1 == -EIO) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"3151 PCI bus read access failure: x%x\n",
+				readl(phba->sli4_hba.u.if_type2.STATUSregaddr));
 			return;
+		}
 		reg_err1 = readl(phba->sli4_hba.u.if_type2.ERR1regaddr);
 		reg_err2 = readl(phba->sli4_hba.u.if_type2.ERR2regaddr);
 		if (bf_get(lpfc_sliport_status_oti, &portstat_reg)) {
@@ -1525,6 +1530,9 @@
 			}
 			/* fall through for not able to recover */
 		}
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"3152 Unrecoverable error, bring the port "
+				"offline\n");
 		lpfc_sli4_offline_eratt(phba);
 		break;
 	case LPFC_SLI_INTF_IF_TYPE_1:
@@ -2333,13 +2341,20 @@
 			continue;
 		}
 
+		/* take care of nodes in unused state before the state
+		 * machine taking action.
+		 */
+		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
+			lpfc_nlp_put(ndlp);
+			continue;
+		}
+
 		if (ndlp->nlp_type & NLP_FABRIC)
 			lpfc_disc_state_machine(vport, ndlp, NULL,
 					NLP_EVT_DEVICE_RECOVERY);
 
 		lpfc_disc_state_machine(vport, ndlp, NULL,
 					     NLP_EVT_DEVICE_RM);
-
 	}
 
 	/* At this point, ALL ndlp's should be gone
@@ -2513,6 +2528,42 @@
 }
 
 /**
+ * lpfc_sli4_node_prep - Assign RPIs for active nodes.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * Allocate RPIs for all active remote nodes. This is needed whenever
+ * an SLI4 adapter is reset and the driver is not unloading. Its purpose
+ * is to fixup the temporary rpi assignments.
+ **/
+void
+lpfc_sli4_node_prep(struct lpfc_hba *phba)
+{
+	struct lpfc_nodelist  *ndlp, *next_ndlp;
+	struct lpfc_vport **vports;
+	int i;
+
+	if (phba->sli_rev != LPFC_SLI_REV4)
+		return;
+
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL) {
+		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+			if (vports[i]->load_flag & FC_UNLOADING)
+				continue;
+
+			list_for_each_entry_safe(ndlp, next_ndlp,
+						 &vports[i]->fc_nodes,
+						 nlp_listp) {
+				if (NLP_CHK_NODE_ACT(ndlp))
+					ndlp->nlp_rpi =
+						lpfc_sli4_alloc_rpi(phba);
+			}
+		}
+	}
+	lpfc_destroy_vport_work_array(phba, vports);
+}
+
+/**
  * lpfc_online - Initialize and bring a HBA online
  * @phba: pointer to lpfc hba data structure.
  *
@@ -2654,6 +2705,13 @@
 				spin_lock_irq(shost->host_lock);
 				ndlp->nlp_flag &= ~NLP_NPR_ADISC;
 				spin_unlock_irq(shost->host_lock);
+				/*
+				 * Whenever an SLI4 port goes offline, free the
+				 * RPI. Get a new RPI when the adapter port
+				 * comes back online.
+				 */
+				if (phba->sli_rev == LPFC_SLI_REV4)
+					lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi);
 				lpfc_unreg_rpi(vports[i], ndlp);
 			}
 		}
@@ -2726,9 +2784,13 @@
 
 	spin_lock_irq(&phba->hbalock);
 	spin_lock(&phba->scsi_buf_list_lock);
-	list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list)
+	list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) {
 		sb->cur_iocbq.sli4_xritag =
 			phba->sli4_hba.xri_ids[sb->cur_iocbq.sli4_lxritag];
+		set_bit(sb->cur_iocbq.sli4_lxritag, phba->sli4_hba.xri_bmask);
+		phba->sli4_hba.max_cfg_param.xri_used++;
+		phba->sli4_hba.xri_count++;
+	}
 	spin_unlock(&phba->scsi_buf_list_lock);
 	spin_unlock_irq(&phba->hbalock);
 	return 0;
@@ -3663,6 +3725,7 @@
 		break;
 
 	case LPFC_FIP_EVENT_TYPE_FCF_DEAD:
+		phba->fcoe_cvl_eventtag = acqe_fip->event_tag;
 		lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
 			"2549 FCF (x%x) disconnected from network, "
 			"tag:x%x\n", acqe_fip->index, acqe_fip->event_tag);
@@ -3724,6 +3787,7 @@
 		}
 		break;
 	case LPFC_FIP_EVENT_TYPE_CVL:
+		phba->fcoe_cvl_eventtag = acqe_fip->event_tag;
 		lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
 			"2718 Clear Virtual Link Received for VPI 0x%x"
 			" tag 0x%x\n", acqe_fip->index, acqe_fip->event_tag);
@@ -4327,6 +4391,7 @@
 	uint8_t pn_page[LPFC_MAX_SUPPORTED_PAGES] = {0};
 	struct lpfc_mqe *mqe;
 	int longs, sli_family;
+	int sges_per_segment;
 
 	/* Before proceed, wait for POST done and device ready */
 	rc = lpfc_sli4_post_status_check(phba);
@@ -4390,6 +4455,11 @@
 	phba->fc_map[1] = LPFC_FCOE_FCF_MAP1;
 	phba->fc_map[2] = LPFC_FCOE_FCF_MAP2;
 
+	/* With BlockGuard we can have multiple SGEs per Data Segemnt */
+	sges_per_segment = 1;
+	if (phba->cfg_enable_bg)
+		sges_per_segment = 2;
+
 	/*
 	 * Since the sg_tablesize is module parameter, the sg_dma_buf_size
 	 * used to create the sg_dma_buf_pool must be dynamically calculated.
@@ -4398,7 +4468,8 @@
 	 * sgl sizes of must be a power of 2.
 	 */
 	buf_size = (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp) +
-		    ((phba->cfg_sg_seg_cnt + 2) * sizeof(struct sli4_sge)));
+		    (((phba->cfg_sg_seg_cnt * sges_per_segment) + 2) *
+		    sizeof(struct sli4_sge)));
 
 	sli_family = bf_get(lpfc_sli_intf_sli_family, &phba->sli4_hba.sli_intf);
 	max_buf_size = LPFC_SLI4_MAX_BUF_SIZE;
@@ -4415,6 +4486,7 @@
 	default:
 		break;
 	}
+
 	for (dma_buf_size = LPFC_SLI4_MIN_BUF_SIZE;
 	     dma_buf_size < max_buf_size && buf_size > dma_buf_size;
 	     dma_buf_size = dma_buf_size << 1)
@@ -5158,8 +5230,7 @@
 	 * rpi is normalized to a zero base because the physical rpi is
 	 * port based.
 	 */
-	curr_rpi_range = phba->sli4_hba.next_rpi -
-		phba->sli4_hba.max_cfg_param.rpi_base;
+	curr_rpi_range = phba->sli4_hba.next_rpi;
 	spin_unlock_irq(&phba->hbalock);
 
 	/*
@@ -5750,10 +5821,9 @@
 					readl(phba->sli4_hba.u.if_type2.
 					      ERR2regaddr);
 				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-					"2888 Port Error Detected "
-					"during POST: "
-					"port status reg 0x%x, "
-					"port_smphr reg 0x%x, "
+					"2888 Unrecoverable port error "
+					"following POST: port status reg "
+					"0x%x, port_smphr reg 0x%x, "
 					"error 1=0x%x, error 2=0x%x\n",
 					reg_data.word0,
 					portsmphr_reg.word0,
@@ -6074,7 +6144,6 @@
 		phba->sli4_hba.next_xri = phba->sli4_hba.max_cfg_param.xri_base;
 		phba->vpi_base = phba->sli4_hba.max_cfg_param.vpi_base;
 		phba->vfi_base = phba->sli4_hba.max_cfg_param.vfi_base;
-		phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.rpi_base;
 		phba->max_vpi = (phba->sli4_hba.max_cfg_param.max_vpi > 0) ?
 				(phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0;
 		phba->max_vports = phba->max_vpi;
@@ -7163,6 +7232,7 @@
 	uint32_t rdy_chk, num_resets = 0, reset_again = 0;
 	union lpfc_sli4_cfg_shdr *shdr;
 	struct lpfc_register reg_data;
+	uint16_t devid;
 
 	if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
 	switch (if_type) {
@@ -7209,7 +7279,9 @@
 			       LPFC_SLIPORT_INIT_PORT);
 			writel(reg_data.word0, phba->sli4_hba.u.if_type2.
 			       CTRLregaddr);
-
+			/* flush */
+			pci_read_config_word(phba->pcidev,
+					     PCI_DEVICE_ID, &devid);
 			/*
 			 * Poll the Port Status Register and wait for RDY for
 			 * up to 10 seconds.  If the port doesn't respond, treat
@@ -7223,19 +7295,17 @@
 					rc = -ENODEV;
 					goto out;
 				}
+				if (bf_get(lpfc_sliport_status_rn, &reg_data))
+					reset_again++;
 				if (bf_get(lpfc_sliport_status_rdy, &reg_data))
 					break;
-				if (bf_get(lpfc_sliport_status_rn, &reg_data)) {
-					reset_again++;
-					break;
-				}
 			}
 
 			/*
 			 * If the port responds to the init request with
 			 * reset needed, delay for a bit and restart the loop.
 			 */
-			if (reset_again) {
+			if (reset_again && (rdy_chk < 1000)) {
 				msleep(10);
 				reset_again = 0;
 				continue;
@@ -7249,11 +7319,10 @@
 				phba->work_status[1] = readl(
 					phba->sli4_hba.u.if_type2.ERR2regaddr);
 				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-					"2890 Port Error Detected "
-					"during Port Reset: "
-					"port status reg 0x%x, "
+					"2890 Port error detected during port "
+					"reset(%d): port status reg 0x%x, "
 					"error 1=0x%x, error 2=0x%x\n",
-					reg_data.word0,
+					num_resets, reg_data.word0,
 					phba->work_status[0],
 					phba->work_status[1]);
 				rc = -ENODEV;
@@ -8112,6 +8181,9 @@
 	vport->load_flag |= FC_UNLOADING;
 	spin_unlock_irq(shost->host_lock);
 
+	kfree(phba->vpi_bmask);
+	kfree(phba->vpi_ids);
+
 	lpfc_stop_hba_timers(phba);
 
 	phba->pport->work_port_events = 0;
@@ -8644,6 +8716,9 @@
 	/* Final cleanup of txcmplq and reset the HBA */
 	lpfc_sli_brdrestart(phba);
 
+	kfree(phba->vpi_bmask);
+	kfree(phba->vpi_ids);
+
 	lpfc_stop_hba_timers(phba);
 	spin_lock_irq(&phba->hbalock);
 	list_del_init(&vport->listentry);
@@ -9058,7 +9133,7 @@
 int
 lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw)
 {
-	char fwrev[32];
+	char fwrev[FW_REV_STR_SIZE];
 	struct lpfc_grp_hdr *image = (struct lpfc_grp_hdr *)fw->data;
 	struct list_head dma_buffer_list;
 	int i, rc = 0;
@@ -10012,6 +10087,36 @@
 	return;
 }
 
+/**
+ * lpfc_mgmt_open - method called when 'lpfcmgmt' is opened from userspace
+ * @inode: pointer to the inode representing the lpfcmgmt device
+ * @filep: pointer to the file representing the open lpfcmgmt device
+ *
+ * This routine puts a reference count on the lpfc module whenever the
+ * character device is opened
+ **/
+static int
+lpfc_mgmt_open(struct inode *inode, struct file *filep)
+{
+	try_module_get(THIS_MODULE);
+	return 0;
+}
+
+/**
+ * lpfc_mgmt_release - method called when 'lpfcmgmt' is closed in userspace
+ * @inode: pointer to the inode representing the lpfcmgmt device
+ * @filep: pointer to the file representing the open lpfcmgmt device
+ *
+ * This routine removes a reference count from the lpfc module when the
+ * character device is closed
+ **/
+static int
+lpfc_mgmt_release(struct inode *inode, struct file *filep)
+{
+	module_put(THIS_MODULE);
+	return 0;
+}
+
 static struct pci_device_id lpfc_id_table[] = {
 	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER,
 		PCI_ANY_ID, PCI_ANY_ID, },
@@ -10124,6 +10229,17 @@
 	.err_handler    = &lpfc_err_handler,
 };
 
+static const struct file_operations lpfc_mgmt_fop = {
+	.open = lpfc_mgmt_open,
+	.release = lpfc_mgmt_release,
+};
+
+static struct miscdevice lpfc_mgmt_dev = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "lpfcmgmt",
+	.fops = &lpfc_mgmt_fop,
+};
+
 /**
  * lpfc_init - lpfc module initialization routine
  *
@@ -10144,6 +10260,11 @@
 	printk(LPFC_MODULE_DESC "\n");
 	printk(LPFC_COPYRIGHT "\n");
 
+	error = misc_register(&lpfc_mgmt_dev);
+	if (error)
+		printk(KERN_ERR "Could not register lpfcmgmt device, "
+			"misc_register returned with status %d", error);
+
 	if (lpfc_enable_npiv) {
 		lpfc_transport_functions.vport_create = lpfc_vport_create;
 		lpfc_transport_functions.vport_delete = lpfc_vport_delete;
@@ -10180,6 +10301,7 @@
 static void __exit
 lpfc_exit(void)
 {
+	misc_deregister(&lpfc_mgmt_dev);
 	pci_unregister_driver(&lpfc_driver);
 	fc_release_transport(lpfc_transport_template);
 	if (lpfc_enable_npiv)
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index e8bb005..15ca2a9a 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -1,7 +1,7 @@
  /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2012 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -48,6 +48,10 @@
 lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		 struct lpfc_name *nn, struct lpfc_name *pn)
 {
+	/* First, we MUST have a RPI registered */
+	if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED))
+		return 0;
+
 	/* Compare the ADISC rsp WWNN / WWPN matches our internal node
 	 * table entry for that node.
 	 */
@@ -385,6 +389,10 @@
 	if (!mbox)
 		goto out;
 
+	/* Registering an existing RPI behaves differently for SLI3 vs SLI4 */
+	if (phba->sli_rev == LPFC_SLI_REV4)
+		lpfc_unreg_rpi(vport, ndlp);
+
 	rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID,
 			    (uint8_t *) sp, mbox, ndlp->nlp_rpi);
 	if (rc) {
@@ -432,11 +440,15 @@
 		spin_unlock_irq(shost->host_lock);
 		stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD;
 		stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
-		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
+		rc = lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
 			ndlp, mbox);
+		if (rc)
+			mempool_free(mbox, phba->mbox_mem_pool);
 		return 1;
 	}
-	lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox);
+	rc = lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox);
+	if (rc)
+		mempool_free(mbox, phba->mbox_mem_pool);
 	return 1;
 out:
 	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
@@ -445,11 +457,43 @@
 	return 0;
 }
 
+/**
+ * lpfc_mbx_cmpl_resume_rpi - Resume RPI completion routine
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: pointer to mailbox object
+ *
+ * This routine is invoked to issue a completion to a rcv'ed
+ * ADISC or PDISC after the paused RPI has been resumed.
+ **/
+static void
+lpfc_mbx_cmpl_resume_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+	struct lpfc_vport *vport;
+	struct lpfc_iocbq *elsiocb;
+	struct lpfc_nodelist *ndlp;
+	uint32_t cmd;
+
+	elsiocb = (struct lpfc_iocbq *)mboxq->context1;
+	ndlp = (struct lpfc_nodelist *) mboxq->context2;
+	vport = mboxq->vport;
+	cmd = elsiocb->drvrTimeout;
+
+	if (cmd == ELS_CMD_ADISC) {
+		lpfc_els_rsp_adisc_acc(vport, elsiocb, ndlp);
+	} else {
+		lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, elsiocb,
+			ndlp, NULL);
+	}
+	kfree(elsiocb);
+	mempool_free(mboxq, phba->mbox_mem_pool);
+}
+
 static int
 lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		struct lpfc_iocbq *cmdiocb)
 {
 	struct Scsi_Host   *shost = lpfc_shost_from_vport(vport);
+	struct lpfc_iocbq  *elsiocb;
 	struct lpfc_dmabuf *pcmd;
 	struct serv_parm   *sp;
 	struct lpfc_name   *pnn, *ppn;
@@ -475,12 +519,43 @@
 
 	icmd = &cmdiocb->iocb;
 	if (icmd->ulpStatus == 0 && lpfc_check_adisc(vport, ndlp, pnn, ppn)) {
+
+		/*
+		 * As soon as  we send ACC, the remote NPort can
+		 * start sending us data. Thus, for SLI4 we must
+		 * resume the RPI before the ACC goes out.
+		 */
+		if (vport->phba->sli_rev == LPFC_SLI_REV4) {
+			elsiocb = kmalloc(sizeof(struct lpfc_iocbq),
+				GFP_KERNEL);
+			if (elsiocb) {
+
+				/* Save info from cmd IOCB used in rsp */
+				memcpy((uint8_t *)elsiocb, (uint8_t *)cmdiocb,
+					sizeof(struct lpfc_iocbq));
+
+				/* Save the ELS cmd */
+				elsiocb->drvrTimeout = cmd;
+
+				lpfc_sli4_resume_rpi(ndlp,
+					lpfc_mbx_cmpl_resume_rpi, elsiocb);
+				goto out;
+			}
+		}
+
 		if (cmd == ELS_CMD_ADISC) {
 			lpfc_els_rsp_adisc_acc(vport, cmdiocb, ndlp);
 		} else {
-			lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp,
-					 NULL);
+			lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb,
+				ndlp, NULL);
 		}
+out:
+		/* If we are authenticated, move to the proper state */
+		if (ndlp->nlp_type & NLP_FCP_TARGET)
+			lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
+		else
+			lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
+
 		return 1;
 	}
 	/* Reject this request because invalid parameters */
@@ -1229,7 +1304,7 @@
 	}
 
 	if (phba->sli_rev == LPFC_SLI_REV4) {
-		rc = lpfc_sli4_resume_rpi(ndlp);
+		rc = lpfc_sli4_resume_rpi(ndlp, NULL, NULL);
 		if (rc) {
 			/* Stay in state and retry. */
 			ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index c60f5d0..88f3a83 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2011 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2012 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -39,8 +39,8 @@
 #include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
-#include "lpfc_scsi.h"
 #include "lpfc.h"
+#include "lpfc_scsi.h"
 #include "lpfc_logmsg.h"
 #include "lpfc_crtn.h"
 #include "lpfc_vport.h"
@@ -51,13 +51,19 @@
 int _dump_buf_done;
 
 static char *dif_op_str[] = {
-	"SCSI_PROT_NORMAL",
-	"SCSI_PROT_READ_INSERT",
-	"SCSI_PROT_WRITE_STRIP",
-	"SCSI_PROT_READ_STRIP",
-	"SCSI_PROT_WRITE_INSERT",
-	"SCSI_PROT_READ_PASS",
-	"SCSI_PROT_WRITE_PASS",
+	"PROT_NORMAL",
+	"PROT_READ_INSERT",
+	"PROT_WRITE_STRIP",
+	"PROT_READ_STRIP",
+	"PROT_WRITE_INSERT",
+	"PROT_READ_PASS",
+	"PROT_WRITE_PASS",
+};
+
+static char *dif_grd_str[] = {
+	"NO_GUARD",
+	"DIF_CRC",
+	"DIX_IP",
 };
 
 struct scsi_dif_tuple {
@@ -1280,32 +1286,51 @@
 }
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-/*
- * Given a scsi cmnd, determine the BlockGuard tags to be used with it
+
+/* Return if if error injection is detected by Initiator */
+#define BG_ERR_INIT	0x1
+/* Return if if error injection is detected by Target */
+#define BG_ERR_TGT	0x2
+/* Return if if swapping CSUM<-->CRC is required for error injection */
+#define BG_ERR_SWAP	0x10
+/* Return if disabling Guard/Ref/App checking is required for error injection */
+#define BG_ERR_CHECK	0x20
+
+/**
+ * lpfc_bg_err_inject - Determine if we should inject an error
+ * @phba: The Hba for which this call is being executed.
  * @sc: The SCSI command to examine
  * @reftag: (out) BlockGuard reference tag for transmitted data
  * @apptag: (out) BlockGuard application tag for transmitted data
  * @new_guard (in) Value to replace CRC with if needed
  *
- * Returns (1) if error injection was performed, (0) otherwise
- */
+ * Returns BG_ERR_* bit mask or 0 if request ignored
+ **/
 static int
 lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 		uint32_t *reftag, uint16_t *apptag, uint32_t new_guard)
 {
 	struct scatterlist *sgpe; /* s/g prot entry */
 	struct scatterlist *sgde; /* s/g data entry */
-	struct scsi_dif_tuple *src;
+	struct lpfc_scsi_buf *lpfc_cmd = NULL;
+	struct scsi_dif_tuple *src = NULL;
+	struct lpfc_nodelist *ndlp;
+	struct lpfc_rport_data *rdata;
 	uint32_t op = scsi_get_prot_op(sc);
 	uint32_t blksize;
 	uint32_t numblks;
 	sector_t lba;
 	int rc = 0;
+	int blockoff = 0;
 
 	if (op == SCSI_PROT_NORMAL)
 		return 0;
 
+	sgpe = scsi_prot_sglist(sc);
+	sgde = scsi_sglist(sc);
 	lba = scsi_get_lba(sc);
+
+	/* First check if we need to match the LBA */
 	if (phba->lpfc_injerr_lba != LPFC_INJERR_LBA_OFF) {
 		blksize = lpfc_cmd_blksize(sc);
 		numblks = (scsi_bufflen(sc) + blksize - 1) / blksize;
@@ -1314,142 +1339,380 @@
 		if ((phba->lpfc_injerr_lba < lba) ||
 			(phba->lpfc_injerr_lba >= (lba + numblks)))
 			return 0;
+		if (sgpe) {
+			blockoff = phba->lpfc_injerr_lba - lba;
+			numblks = sg_dma_len(sgpe) /
+				sizeof(struct scsi_dif_tuple);
+			if (numblks < blockoff)
+				blockoff = numblks;
+		}
 	}
 
-	sgpe = scsi_prot_sglist(sc);
-	sgde = scsi_sglist(sc);
+	/* Next check if we need to match the remote NPortID or WWPN */
+	rdata = sc->device->hostdata;
+	if (rdata && rdata->pnode) {
+		ndlp = rdata->pnode;
+
+		/* Make sure we have the right NPortID if one is specified */
+		if (phba->lpfc_injerr_nportid  &&
+			(phba->lpfc_injerr_nportid != ndlp->nlp_DID))
+			return 0;
+
+		/*
+		 * Make sure we have the right WWPN if one is specified.
+		 * wwn[0] should be a non-zero NAA in a good WWPN.
+		 */
+		if (phba->lpfc_injerr_wwpn.u.wwn[0]  &&
+			(memcmp(&ndlp->nlp_portname, &phba->lpfc_injerr_wwpn,
+				sizeof(struct lpfc_name)) != 0))
+			return 0;
+	}
+
+	/* Setup a ptr to the protection data if the SCSI host provides it */
+	if (sgpe) {
+		src = (struct scsi_dif_tuple *)sg_virt(sgpe);
+		src += blockoff;
+		lpfc_cmd = (struct lpfc_scsi_buf *)sc->host_scribble;
+	}
 
 	/* Should we change the Reference Tag */
 	if (reftag) {
-		/*
-		 * If we are SCSI_PROT_WRITE_STRIP, the protection data is
-		 * being stripped from the wire, thus it doesn't matter.
-		 */
-		if ((op == SCSI_PROT_WRITE_PASS) ||
-			(op == SCSI_PROT_WRITE_INSERT)) {
-			if (phba->lpfc_injerr_wref_cnt) {
+		if (phba->lpfc_injerr_wref_cnt) {
+			switch (op) {
+			case SCSI_PROT_WRITE_PASS:
+				if (src) {
+					/*
+					 * For WRITE_PASS, force the error
+					 * to be sent on the wire. It should
+					 * be detected by the Target.
+					 * If blockoff != 0 error will be
+					 * inserted in middle of the IO.
+					 */
 
+					lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+					"9076 BLKGRD: Injecting reftag error: "
+					"write lba x%lx + x%x oldrefTag x%x\n",
+					(unsigned long)lba, blockoff,
+					be32_to_cpu(src->ref_tag));
+
+					/*
+					 * Save the old ref_tag so we can
+					 * restore it on completion.
+					 */
+					if (lpfc_cmd) {
+						lpfc_cmd->prot_data_type =
+							LPFC_INJERR_REFTAG;
+						lpfc_cmd->prot_data_segment =
+							src;
+						lpfc_cmd->prot_data =
+							src->ref_tag;
+					}
+					src->ref_tag = cpu_to_be32(0xDEADBEEF);
+					phba->lpfc_injerr_wref_cnt--;
+					if (phba->lpfc_injerr_wref_cnt == 0) {
+						phba->lpfc_injerr_nportid = 0;
+						phba->lpfc_injerr_lba =
+							LPFC_INJERR_LBA_OFF;
+						memset(&phba->lpfc_injerr_wwpn,
+						  0, sizeof(struct lpfc_name));
+					}
+					rc = BG_ERR_TGT | BG_ERR_CHECK;
+
+					break;
+				}
+				/* Drop thru */
+			case SCSI_PROT_WRITE_INSERT:
+				/*
+				 * For WRITE_INSERT, force the error
+				 * to be sent on the wire. It should be
+				 * detected by the Target.
+				 */
 				/* DEADBEEF will be the reftag on the wire */
 				*reftag = 0xDEADBEEF;
 				phba->lpfc_injerr_wref_cnt--;
-				phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
-				rc = 1;
+				if (phba->lpfc_injerr_wref_cnt == 0) {
+					phba->lpfc_injerr_nportid = 0;
+					phba->lpfc_injerr_lba =
+					LPFC_INJERR_LBA_OFF;
+					memset(&phba->lpfc_injerr_wwpn,
+						0, sizeof(struct lpfc_name));
+				}
+				rc = BG_ERR_TGT | BG_ERR_CHECK;
 
 				lpfc_printf_log(phba, KERN_ERR, LOG_BG,
-					"9081 BLKGRD: Injecting reftag error: "
+					"9078 BLKGRD: Injecting reftag error: "
 					"write lba x%lx\n", (unsigned long)lba);
+				break;
+			case SCSI_PROT_WRITE_STRIP:
+				/*
+				 * For WRITE_STRIP and WRITE_PASS,
+				 * force the error on data
+				 * being copied from SLI-Host to SLI-Port.
+				 */
+				*reftag = 0xDEADBEEF;
+				phba->lpfc_injerr_wref_cnt--;
+				if (phba->lpfc_injerr_wref_cnt == 0) {
+					phba->lpfc_injerr_nportid = 0;
+					phba->lpfc_injerr_lba =
+						LPFC_INJERR_LBA_OFF;
+					memset(&phba->lpfc_injerr_wwpn,
+						0, sizeof(struct lpfc_name));
+				}
+				rc = BG_ERR_INIT;
+
+				lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+					"9077 BLKGRD: Injecting reftag error: "
+					"write lba x%lx\n", (unsigned long)lba);
+				break;
 			}
-		} else {
-			if (phba->lpfc_injerr_rref_cnt) {
+		}
+		if (phba->lpfc_injerr_rref_cnt) {
+			switch (op) {
+			case SCSI_PROT_READ_INSERT:
+			case SCSI_PROT_READ_STRIP:
+			case SCSI_PROT_READ_PASS:
+				/*
+				 * For READ_STRIP and READ_PASS, force the
+				 * error on data being read off the wire. It
+				 * should force an IO error to the driver.
+				 */
 				*reftag = 0xDEADBEEF;
 				phba->lpfc_injerr_rref_cnt--;
-				phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
-				rc = 1;
+				if (phba->lpfc_injerr_rref_cnt == 0) {
+					phba->lpfc_injerr_nportid = 0;
+					phba->lpfc_injerr_lba =
+						LPFC_INJERR_LBA_OFF;
+					memset(&phba->lpfc_injerr_wwpn,
+						0, sizeof(struct lpfc_name));
+				}
+				rc = BG_ERR_INIT;
 
 				lpfc_printf_log(phba, KERN_ERR, LOG_BG,
-					"9076 BLKGRD: Injecting reftag error: "
+					"9079 BLKGRD: Injecting reftag error: "
 					"read lba x%lx\n", (unsigned long)lba);
+				break;
 			}
 		}
 	}
 
 	/* Should we change the Application Tag */
 	if (apptag) {
-		/*
-		 * If we are SCSI_PROT_WRITE_STRIP, the protection data is
-		 * being stripped from the wire, thus it doesn't matter.
-		 */
-		if ((op == SCSI_PROT_WRITE_PASS) ||
-			(op == SCSI_PROT_WRITE_INSERT)) {
-			if (phba->lpfc_injerr_wapp_cnt) {
+		if (phba->lpfc_injerr_wapp_cnt) {
+			switch (op) {
+			case SCSI_PROT_WRITE_PASS:
+				if (src) {
+					/*
+					 * For WRITE_PASS, force the error
+					 * to be sent on the wire. It should
+					 * be detected by the Target.
+					 * If blockoff != 0 error will be
+					 * inserted in middle of the IO.
+					 */
 
+					lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+					"9080 BLKGRD: Injecting apptag error: "
+					"write lba x%lx + x%x oldappTag x%x\n",
+					(unsigned long)lba, blockoff,
+					be16_to_cpu(src->app_tag));
+
+					/*
+					 * Save the old app_tag so we can
+					 * restore it on completion.
+					 */
+					if (lpfc_cmd) {
+						lpfc_cmd->prot_data_type =
+							LPFC_INJERR_APPTAG;
+						lpfc_cmd->prot_data_segment =
+							src;
+						lpfc_cmd->prot_data =
+							src->app_tag;
+					}
+					src->app_tag = cpu_to_be16(0xDEAD);
+					phba->lpfc_injerr_wapp_cnt--;
+					if (phba->lpfc_injerr_wapp_cnt == 0) {
+						phba->lpfc_injerr_nportid = 0;
+						phba->lpfc_injerr_lba =
+							LPFC_INJERR_LBA_OFF;
+						memset(&phba->lpfc_injerr_wwpn,
+						  0, sizeof(struct lpfc_name));
+					}
+					rc = BG_ERR_TGT | BG_ERR_CHECK;
+					break;
+				}
+				/* Drop thru */
+			case SCSI_PROT_WRITE_INSERT:
+				/*
+				 * For WRITE_INSERT, force the
+				 * error to be sent on the wire. It should be
+				 * detected by the Target.
+				 */
 				/* DEAD will be the apptag on the wire */
 				*apptag = 0xDEAD;
 				phba->lpfc_injerr_wapp_cnt--;
-				phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
-				rc = 1;
+				if (phba->lpfc_injerr_wapp_cnt == 0) {
+					phba->lpfc_injerr_nportid = 0;
+					phba->lpfc_injerr_lba =
+						LPFC_INJERR_LBA_OFF;
+					memset(&phba->lpfc_injerr_wwpn,
+						0, sizeof(struct lpfc_name));
+				}
+				rc = BG_ERR_TGT | BG_ERR_CHECK;
 
 				lpfc_printf_log(phba, KERN_ERR, LOG_BG,
-					"9077 BLKGRD: Injecting apptag error: "
+					"0813 BLKGRD: Injecting apptag error: "
 					"write lba x%lx\n", (unsigned long)lba);
+				break;
+			case SCSI_PROT_WRITE_STRIP:
+				/*
+				 * For WRITE_STRIP and WRITE_PASS,
+				 * force the error on data
+				 * being copied from SLI-Host to SLI-Port.
+				 */
+				*apptag = 0xDEAD;
+				phba->lpfc_injerr_wapp_cnt--;
+				if (phba->lpfc_injerr_wapp_cnt == 0) {
+					phba->lpfc_injerr_nportid = 0;
+					phba->lpfc_injerr_lba =
+						LPFC_INJERR_LBA_OFF;
+					memset(&phba->lpfc_injerr_wwpn,
+						0, sizeof(struct lpfc_name));
+				}
+				rc = BG_ERR_INIT;
+
+				lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+					"0812 BLKGRD: Injecting apptag error: "
+					"write lba x%lx\n", (unsigned long)lba);
+				break;
 			}
-		} else {
-			if (phba->lpfc_injerr_rapp_cnt) {
+		}
+		if (phba->lpfc_injerr_rapp_cnt) {
+			switch (op) {
+			case SCSI_PROT_READ_INSERT:
+			case SCSI_PROT_READ_STRIP:
+			case SCSI_PROT_READ_PASS:
+				/*
+				 * For READ_STRIP and READ_PASS, force the
+				 * error on data being read off the wire. It
+				 * should force an IO error to the driver.
+				 */
 				*apptag = 0xDEAD;
 				phba->lpfc_injerr_rapp_cnt--;
-				phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
-				rc = 1;
+				if (phba->lpfc_injerr_rapp_cnt == 0) {
+					phba->lpfc_injerr_nportid = 0;
+					phba->lpfc_injerr_lba =
+						LPFC_INJERR_LBA_OFF;
+					memset(&phba->lpfc_injerr_wwpn,
+						0, sizeof(struct lpfc_name));
+				}
+				rc = BG_ERR_INIT;
 
 				lpfc_printf_log(phba, KERN_ERR, LOG_BG,
-					"9078 BLKGRD: Injecting apptag error: "
+					"0814 BLKGRD: Injecting apptag error: "
+					"read lba x%lx\n", (unsigned long)lba);
+				break;
+			}
+		}
+	}
+
+
+	/* Should we change the Guard Tag */
+	if (new_guard) {
+		if (phba->lpfc_injerr_wgrd_cnt) {
+			switch (op) {
+			case SCSI_PROT_WRITE_PASS:
+				rc = BG_ERR_CHECK;
+				/* Drop thru */
+
+			case SCSI_PROT_WRITE_INSERT:
+				/*
+				 * For WRITE_INSERT, force the
+				 * error to be sent on the wire. It should be
+				 * detected by the Target.
+				 */
+				phba->lpfc_injerr_wgrd_cnt--;
+				if (phba->lpfc_injerr_wgrd_cnt == 0) {
+					phba->lpfc_injerr_nportid = 0;
+					phba->lpfc_injerr_lba =
+						LPFC_INJERR_LBA_OFF;
+					memset(&phba->lpfc_injerr_wwpn,
+						0, sizeof(struct lpfc_name));
+				}
+
+				rc |= BG_ERR_TGT | BG_ERR_SWAP;
+				/* Signals the caller to swap CRC->CSUM */
+
+				lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+					"0817 BLKGRD: Injecting guard error: "
+					"write lba x%lx\n", (unsigned long)lba);
+				break;
+			case SCSI_PROT_WRITE_STRIP:
+				/*
+				 * For WRITE_STRIP and WRITE_PASS,
+				 * force the error on data
+				 * being copied from SLI-Host to SLI-Port.
+				 */
+				phba->lpfc_injerr_wgrd_cnt--;
+				if (phba->lpfc_injerr_wgrd_cnt == 0) {
+					phba->lpfc_injerr_nportid = 0;
+					phba->lpfc_injerr_lba =
+						LPFC_INJERR_LBA_OFF;
+					memset(&phba->lpfc_injerr_wwpn,
+						0, sizeof(struct lpfc_name));
+				}
+
+				rc = BG_ERR_INIT | BG_ERR_SWAP;
+				/* Signals the caller to swap CRC->CSUM */
+
+				lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+					"0816 BLKGRD: Injecting guard error: "
+					"write lba x%lx\n", (unsigned long)lba);
+				break;
+			}
+		}
+		if (phba->lpfc_injerr_rgrd_cnt) {
+			switch (op) {
+			case SCSI_PROT_READ_INSERT:
+			case SCSI_PROT_READ_STRIP:
+			case SCSI_PROT_READ_PASS:
+				/*
+				 * For READ_STRIP and READ_PASS, force the
+				 * error on data being read off the wire. It
+				 * should force an IO error to the driver.
+				 */
+				phba->lpfc_injerr_rgrd_cnt--;
+				if (phba->lpfc_injerr_rgrd_cnt == 0) {
+					phba->lpfc_injerr_nportid = 0;
+					phba->lpfc_injerr_lba =
+						LPFC_INJERR_LBA_OFF;
+					memset(&phba->lpfc_injerr_wwpn,
+						0, sizeof(struct lpfc_name));
+				}
+
+				rc = BG_ERR_INIT | BG_ERR_SWAP;
+				/* Signals the caller to swap CRC->CSUM */
+
+				lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+					"0818 BLKGRD: Injecting guard error: "
 					"read lba x%lx\n", (unsigned long)lba);
 			}
 		}
 	}
 
-	/* Should we change the Guard Tag */
-
-	/*
-	 * If we are SCSI_PROT_WRITE_INSERT, the protection data is
-	 * being on the wire is being fully generated on the HBA.
-	 * The host cannot change it or force an error.
-	 */
-	if (((op == SCSI_PROT_WRITE_STRIP) ||
-		(op == SCSI_PROT_WRITE_PASS)) &&
-		phba->lpfc_injerr_wgrd_cnt) {
-		if (sgpe) {
-			src = (struct scsi_dif_tuple *)sg_virt(sgpe);
-			/*
-			 * Just inject an error in the first
-			 * prot block.
-			 */
-			lpfc_printf_log(phba, KERN_ERR, LOG_BG,
-				"9079 BLKGRD: Injecting guard error: "
-				"write lba x%lx oldGuard x%x refTag x%x\n",
-				(unsigned long)lba, src->guard_tag,
-				src->ref_tag);
-
-			src->guard_tag = (uint16_t)new_guard;
-			phba->lpfc_injerr_wgrd_cnt--;
-			phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
-			rc = 1;
-
-		} else {
-			blksize = lpfc_cmd_blksize(sc);
-			/*
-			 * Jump past the first data block
-			 * and inject an error in the
-			 * prot data. The prot data is already
-			 * embedded after the regular data.
-			 */
-			src = (struct scsi_dif_tuple *)
-					(sg_virt(sgde) + blksize);
-
-			lpfc_printf_log(phba, KERN_ERR, LOG_BG,
-				"9080 BLKGRD: Injecting guard error: "
-				"write lba x%lx oldGuard x%x refTag x%x\n",
-				(unsigned long)lba, src->guard_tag,
-				src->ref_tag);
-
-			src->guard_tag = (uint16_t)new_guard;
-			phba->lpfc_injerr_wgrd_cnt--;
-			phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
-			rc = 1;
-		}
-	}
 	return rc;
 }
 #endif
 
-/*
- * Given a scsi cmnd, determine the BlockGuard opcodes to be used with it
+/**
+ * lpfc_sc_to_bg_opcodes - Determine the BlockGuard opcodes to be used with
+ * the specified SCSI command.
+ * @phba: The Hba for which this call is being executed.
  * @sc: The SCSI command to examine
  * @txopt: (out) BlockGuard operation for transmitted data
  * @rxopt: (out) BlockGuard operation for received data
  *
  * Returns: zero on success; non-zero if tx and/or rx op cannot be determined
  *
- */
+ **/
 static int
 lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 		uint8_t *txop, uint8_t *rxop)
@@ -1461,20 +1724,20 @@
 		switch (scsi_get_prot_op(sc)) {
 		case SCSI_PROT_READ_INSERT:
 		case SCSI_PROT_WRITE_STRIP:
-			*txop = BG_OP_IN_CSUM_OUT_NODIF;
 			*rxop = BG_OP_IN_NODIF_OUT_CSUM;
+			*txop = BG_OP_IN_CSUM_OUT_NODIF;
 			break;
 
 		case SCSI_PROT_READ_STRIP:
 		case SCSI_PROT_WRITE_INSERT:
-			*txop = BG_OP_IN_NODIF_OUT_CRC;
 			*rxop = BG_OP_IN_CRC_OUT_NODIF;
+			*txop = BG_OP_IN_NODIF_OUT_CRC;
 			break;
 
 		case SCSI_PROT_READ_PASS:
 		case SCSI_PROT_WRITE_PASS:
-			*txop = BG_OP_IN_CSUM_OUT_CRC;
 			*rxop = BG_OP_IN_CRC_OUT_CSUM;
+			*txop = BG_OP_IN_CSUM_OUT_CRC;
 			break;
 
 		case SCSI_PROT_NORMAL:
@@ -1490,20 +1753,20 @@
 		switch (scsi_get_prot_op(sc)) {
 		case SCSI_PROT_READ_STRIP:
 		case SCSI_PROT_WRITE_INSERT:
-			*txop = BG_OP_IN_NODIF_OUT_CRC;
 			*rxop = BG_OP_IN_CRC_OUT_NODIF;
+			*txop = BG_OP_IN_NODIF_OUT_CRC;
 			break;
 
 		case SCSI_PROT_READ_PASS:
 		case SCSI_PROT_WRITE_PASS:
-			*txop = BG_OP_IN_CRC_OUT_CRC;
 			*rxop = BG_OP_IN_CRC_OUT_CRC;
+			*txop = BG_OP_IN_CRC_OUT_CRC;
 			break;
 
 		case SCSI_PROT_READ_INSERT:
 		case SCSI_PROT_WRITE_STRIP:
-			*txop = BG_OP_IN_CRC_OUT_NODIF;
 			*rxop = BG_OP_IN_NODIF_OUT_CRC;
+			*txop = BG_OP_IN_CRC_OUT_NODIF;
 			break;
 
 		case SCSI_PROT_NORMAL:
@@ -1519,8 +1782,88 @@
 	return ret;
 }
 
-/*
- * This function sets up buffer list for protection groups of
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+/**
+ * lpfc_bg_err_opcodes - reDetermine the BlockGuard opcodes to be used with
+ * the specified SCSI command in order to force a guard tag error.
+ * @phba: The Hba for which this call is being executed.
+ * @sc: The SCSI command to examine
+ * @txopt: (out) BlockGuard operation for transmitted data
+ * @rxopt: (out) BlockGuard operation for received data
+ *
+ * Returns: zero on success; non-zero if tx and/or rx op cannot be determined
+ *
+ **/
+static int
+lpfc_bg_err_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc,
+		uint8_t *txop, uint8_t *rxop)
+{
+	uint8_t guard_type = scsi_host_get_guard(sc->device->host);
+	uint8_t ret = 0;
+
+	if (guard_type == SHOST_DIX_GUARD_IP) {
+		switch (scsi_get_prot_op(sc)) {
+		case SCSI_PROT_READ_INSERT:
+		case SCSI_PROT_WRITE_STRIP:
+			*rxop = BG_OP_IN_NODIF_OUT_CRC;
+			*txop = BG_OP_IN_CRC_OUT_NODIF;
+			break;
+
+		case SCSI_PROT_READ_STRIP:
+		case SCSI_PROT_WRITE_INSERT:
+			*rxop = BG_OP_IN_CSUM_OUT_NODIF;
+			*txop = BG_OP_IN_NODIF_OUT_CSUM;
+			break;
+
+		case SCSI_PROT_READ_PASS:
+		case SCSI_PROT_WRITE_PASS:
+			*rxop = BG_OP_IN_CSUM_OUT_CRC;
+			*txop = BG_OP_IN_CRC_OUT_CSUM;
+			break;
+
+		case SCSI_PROT_NORMAL:
+		default:
+			break;
+
+		}
+	} else {
+		switch (scsi_get_prot_op(sc)) {
+		case SCSI_PROT_READ_STRIP:
+		case SCSI_PROT_WRITE_INSERT:
+			*rxop = BG_OP_IN_CSUM_OUT_NODIF;
+			*txop = BG_OP_IN_NODIF_OUT_CSUM;
+			break;
+
+		case SCSI_PROT_READ_PASS:
+		case SCSI_PROT_WRITE_PASS:
+			*rxop = BG_OP_IN_CSUM_OUT_CSUM;
+			*txop = BG_OP_IN_CSUM_OUT_CSUM;
+			break;
+
+		case SCSI_PROT_READ_INSERT:
+		case SCSI_PROT_WRITE_STRIP:
+			*rxop = BG_OP_IN_NODIF_OUT_CSUM;
+			*txop = BG_OP_IN_CSUM_OUT_NODIF;
+			break;
+
+		case SCSI_PROT_NORMAL:
+		default:
+			break;
+		}
+	}
+
+	return ret;
+}
+#endif
+
+/**
+ * lpfc_bg_setup_bpl - Setup BlockGuard BPL with no protection data
+ * @phba: The Hba for which this call is being executed.
+ * @sc: pointer to scsi command we're working on
+ * @bpl: pointer to buffer list for protection groups
+ * @datacnt: number of segments of data that have been dma mapped
+ *
+ * This function sets up BPL buffer list for protection groups of
  * type LPFC_PG_TYPE_NO_DIF
  *
  * This is usually used when the HBA is instructed to generate
@@ -1539,12 +1882,11 @@
  *                                |more Data BDE's ... (opt)|
  *                                +-------------------------+
  *
- * @sc: pointer to scsi command we're working on
- * @bpl: pointer to buffer list for protection groups
- * @datacnt: number of segments of data that have been dma mapped
  *
  * Note: Data s/g buffers have been dma mapped
- */
+ *
+ * Returns the number of BDEs added to the BPL.
+ **/
 static int
 lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 		struct ulp_bde64 *bpl, int datasegcnt)
@@ -1555,6 +1897,8 @@
 	dma_addr_t physaddr;
 	int i = 0, num_bde = 0, status;
 	int datadir = sc->sc_data_direction;
+	uint32_t rc;
+	uint32_t checking = 1;
 	uint32_t reftag;
 	unsigned blksize;
 	uint8_t txop, rxop;
@@ -1565,11 +1909,16 @@
 
 	/* extract some info from the scsi command for pde*/
 	blksize = lpfc_cmd_blksize(sc);
-	reftag = scsi_get_lba(sc) & 0xffffffff;
+	reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-	/* reftag is the only error we can inject here */
-	lpfc_bg_err_inject(phba, sc, &reftag, 0, 0);
+	rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1);
+	if (rc) {
+		if (rc & BG_ERR_SWAP)
+			lpfc_bg_err_opcodes(phba, sc, &txop, &rxop);
+		if (rc & BG_ERR_CHECK)
+			checking = 0;
+	}
 #endif
 
 	/* setup PDE5 with what we have */
@@ -1592,8 +1941,8 @@
 	bf_set(pde6_optx, pde6, txop);
 	bf_set(pde6_oprx, pde6, rxop);
 	if (datadir == DMA_FROM_DEVICE) {
-		bf_set(pde6_ce, pde6, 1);
-		bf_set(pde6_re, pde6, 1);
+		bf_set(pde6_ce, pde6, checking);
+		bf_set(pde6_re, pde6, checking);
 	}
 	bf_set(pde6_ai, pde6, 1);
 	bf_set(pde6_ae, pde6, 0);
@@ -1627,9 +1976,16 @@
 	return num_bde;
 }
 
-/*
- * This function sets up buffer list for protection groups of
- * type LPFC_PG_TYPE_DIF_BUF
+/**
+ * lpfc_bg_setup_bpl_prot - Setup BlockGuard BPL with protection data
+ * @phba: The Hba for which this call is being executed.
+ * @sc: pointer to scsi command we're working on
+ * @bpl: pointer to buffer list for protection groups
+ * @datacnt: number of segments of data that have been dma mapped
+ * @protcnt: number of segment of protection data that have been dma mapped
+ *
+ * This function sets up BPL buffer list for protection groups of
+ * type LPFC_PG_TYPE_DIF
  *
  * This is usually used when DIFs are in their own buffers,
  * separate from the data. The HBA can then by instructed
@@ -1654,14 +2010,11 @@
  *                                    |          ...            |
  *                                    +-------------------------+
  *
- * @sc: pointer to scsi command we're working on
- * @bpl: pointer to buffer list for protection groups
- * @datacnt: number of segments of data that have been dma mapped
- * @protcnt: number of segment of protection data that have been dma mapped
- *
  * Note: It is assumed that both data and protection s/g buffers have been
  *       mapped for DMA
- */
+ *
+ * Returns the number of BDEs added to the BPL.
+ **/
 static int
 lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 		struct ulp_bde64 *bpl, int datacnt, int protcnt)
@@ -1681,6 +2034,8 @@
 	int datadir = sc->sc_data_direction;
 	unsigned char pgdone = 0, alldone = 0;
 	unsigned blksize;
+	uint32_t rc;
+	uint32_t checking = 1;
 	uint32_t reftag;
 	uint8_t txop, rxop;
 	int num_bde = 0;
@@ -1701,11 +2056,16 @@
 
 	/* extract some info from the scsi command */
 	blksize = lpfc_cmd_blksize(sc);
-	reftag = scsi_get_lba(sc) & 0xffffffff;
+	reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-	/* reftag / guard tag are the only errors we can inject here */
-	lpfc_bg_err_inject(phba, sc, &reftag, 0, 0xDEAD);
+	rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1);
+	if (rc) {
+		if (rc & BG_ERR_SWAP)
+			lpfc_bg_err_opcodes(phba, sc, &txop, &rxop);
+		if (rc & BG_ERR_CHECK)
+			checking = 0;
+	}
 #endif
 
 	split_offset = 0;
@@ -1729,8 +2089,8 @@
 		bf_set(pde6_type, pde6, LPFC_PDE6_DESCRIPTOR);
 		bf_set(pde6_optx, pde6, txop);
 		bf_set(pde6_oprx, pde6, rxop);
-		bf_set(pde6_ce, pde6, 1);
-		bf_set(pde6_re, pde6, 1);
+		bf_set(pde6_ce, pde6, checking);
+		bf_set(pde6_re, pde6, checking);
 		bf_set(pde6_ai, pde6, 1);
 		bf_set(pde6_ae, pde6, 0);
 		bf_set(pde6_apptagval, pde6, 0);
@@ -1852,13 +2212,358 @@
 	return num_bde;
 }
 
-/*
+/**
+ * lpfc_bg_setup_sgl - Setup BlockGuard SGL with no protection data
+ * @phba: The Hba for which this call is being executed.
+ * @sc: pointer to scsi command we're working on
+ * @sgl: pointer to buffer list for protection groups
+ * @datacnt: number of segments of data that have been dma mapped
+ *
+ * This function sets up SGL buffer list for protection groups of
+ * type LPFC_PG_TYPE_NO_DIF
+ *
+ * This is usually used when the HBA is instructed to generate
+ * DIFs and insert them into data stream (or strip DIF from
+ * incoming data stream)
+ *
+ * The buffer list consists of just one protection group described
+ * below:
+ *                                +-------------------------+
+ *   start of prot group  -->     |         DI_SEED         |
+ *                                +-------------------------+
+ *                                |         Data SGE        |
+ *                                +-------------------------+
+ *                                |more Data SGE's ... (opt)|
+ *                                +-------------------------+
+ *
+ *
+ * Note: Data s/g buffers have been dma mapped
+ *
+ * Returns the number of SGEs added to the SGL.
+ **/
+static int
+lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
+		struct sli4_sge *sgl, int datasegcnt)
+{
+	struct scatterlist *sgde = NULL; /* s/g data entry */
+	struct sli4_sge_diseed *diseed = NULL;
+	dma_addr_t physaddr;
+	int i = 0, num_sge = 0, status;
+	int datadir = sc->sc_data_direction;
+	uint32_t reftag;
+	unsigned blksize;
+	uint8_t txop, rxop;
+	uint32_t rc;
+	uint32_t checking = 1;
+	uint32_t dma_len;
+	uint32_t dma_offset = 0;
+
+	status  = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop);
+	if (status)
+		goto out;
+
+	/* extract some info from the scsi command for pde*/
+	blksize = lpfc_cmd_blksize(sc);
+	reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */
+
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+	rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1);
+	if (rc) {
+		if (rc & BG_ERR_SWAP)
+			lpfc_bg_err_opcodes(phba, sc, &txop, &rxop);
+		if (rc & BG_ERR_CHECK)
+			checking = 0;
+	}
+#endif
+
+	/* setup DISEED with what we have */
+	diseed = (struct sli4_sge_diseed *) sgl;
+	memset(diseed, 0, sizeof(struct sli4_sge_diseed));
+	bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DISEED);
+
+	/* Endianness conversion if necessary */
+	diseed->ref_tag = cpu_to_le32(reftag);
+	diseed->ref_tag_tran = diseed->ref_tag;
+
+	/* setup DISEED with the rest of the info */
+	bf_set(lpfc_sli4_sge_dif_optx, diseed, txop);
+	bf_set(lpfc_sli4_sge_dif_oprx, diseed, rxop);
+	if (datadir == DMA_FROM_DEVICE) {
+		bf_set(lpfc_sli4_sge_dif_ce, diseed, checking);
+		bf_set(lpfc_sli4_sge_dif_re, diseed, checking);
+	}
+	bf_set(lpfc_sli4_sge_dif_ai, diseed, 1);
+	bf_set(lpfc_sli4_sge_dif_me, diseed, 0);
+
+	/* Endianness conversion if necessary for DISEED */
+	diseed->word2 = cpu_to_le32(diseed->word2);
+	diseed->word3 = cpu_to_le32(diseed->word3);
+
+	/* advance bpl and increment sge count */
+	num_sge++;
+	sgl++;
+
+	/* assumption: caller has already run dma_map_sg on command data */
+	scsi_for_each_sg(sc, sgde, datasegcnt, i) {
+		physaddr = sg_dma_address(sgde);
+		dma_len = sg_dma_len(sgde);
+		sgl->addr_lo = cpu_to_le32(putPaddrLow(physaddr));
+		sgl->addr_hi = cpu_to_le32(putPaddrHigh(physaddr));
+		if ((i + 1) == datasegcnt)
+			bf_set(lpfc_sli4_sge_last, sgl, 1);
+		else
+			bf_set(lpfc_sli4_sge_last, sgl, 0);
+		bf_set(lpfc_sli4_sge_offset, sgl, dma_offset);
+		bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA);
+
+		sgl->sge_len = cpu_to_le32(dma_len);
+		dma_offset += dma_len;
+
+		sgl++;
+		num_sge++;
+	}
+
+out:
+	return num_sge;
+}
+
+/**
+ * lpfc_bg_setup_sgl_prot - Setup BlockGuard SGL with protection data
+ * @phba: The Hba for which this call is being executed.
+ * @sc: pointer to scsi command we're working on
+ * @sgl: pointer to buffer list for protection groups
+ * @datacnt: number of segments of data that have been dma mapped
+ * @protcnt: number of segment of protection data that have been dma mapped
+ *
+ * This function sets up SGL buffer list for protection groups of
+ * type LPFC_PG_TYPE_DIF
+ *
+ * This is usually used when DIFs are in their own buffers,
+ * separate from the data. The HBA can then by instructed
+ * to place the DIFs in the outgoing stream.  For read operations,
+ * The HBA could extract the DIFs and place it in DIF buffers.
+ *
+ * The buffer list for this type consists of one or more of the
+ * protection groups described below:
+ *                                    +-------------------------+
+ *   start of first prot group  -->   |         DISEED          |
+ *                                    +-------------------------+
+ *                                    |      DIF (Prot SGE)     |
+ *                                    +-------------------------+
+ *                                    |        Data SGE         |
+ *                                    +-------------------------+
+ *                                    |more Data SGE's ... (opt)|
+ *                                    +-------------------------+
+ *   start of new  prot group  -->    |         DISEED          |
+ *                                    +-------------------------+
+ *                                    |          ...            |
+ *                                    +-------------------------+
+ *
+ * Note: It is assumed that both data and protection s/g buffers have been
+ *       mapped for DMA
+ *
+ * Returns the number of SGEs added to the SGL.
+ **/
+static int
+lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
+		struct sli4_sge *sgl, int datacnt, int protcnt)
+{
+	struct scatterlist *sgde = NULL; /* s/g data entry */
+	struct scatterlist *sgpe = NULL; /* s/g prot entry */
+	struct sli4_sge_diseed *diseed = NULL;
+	dma_addr_t dataphysaddr, protphysaddr;
+	unsigned short curr_data = 0, curr_prot = 0;
+	unsigned int split_offset;
+	unsigned int protgroup_len, protgroup_offset = 0, protgroup_remainder;
+	unsigned int protgrp_blks, protgrp_bytes;
+	unsigned int remainder, subtotal;
+	int status;
+	unsigned char pgdone = 0, alldone = 0;
+	unsigned blksize;
+	uint32_t reftag;
+	uint8_t txop, rxop;
+	uint32_t dma_len;
+	uint32_t rc;
+	uint32_t checking = 1;
+	uint32_t dma_offset = 0;
+	int num_sge = 0;
+
+	sgpe = scsi_prot_sglist(sc);
+	sgde = scsi_sglist(sc);
+
+	if (!sgpe || !sgde) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+				"9082 Invalid s/g entry: data=0x%p prot=0x%p\n",
+				sgpe, sgde);
+		return 0;
+	}
+
+	status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop);
+	if (status)
+		goto out;
+
+	/* extract some info from the scsi command */
+	blksize = lpfc_cmd_blksize(sc);
+	reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */
+
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+	rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1);
+	if (rc) {
+		if (rc & BG_ERR_SWAP)
+			lpfc_bg_err_opcodes(phba, sc, &txop, &rxop);
+		if (rc & BG_ERR_CHECK)
+			checking = 0;
+	}
+#endif
+
+	split_offset = 0;
+	do {
+		/* setup DISEED with what we have */
+		diseed = (struct sli4_sge_diseed *) sgl;
+		memset(diseed, 0, sizeof(struct sli4_sge_diseed));
+		bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DISEED);
+
+		/* Endianness conversion if necessary */
+		diseed->ref_tag = cpu_to_le32(reftag);
+		diseed->ref_tag_tran = diseed->ref_tag;
+
+		/* setup DISEED with the rest of the info */
+		bf_set(lpfc_sli4_sge_dif_optx, diseed, txop);
+		bf_set(lpfc_sli4_sge_dif_oprx, diseed, rxop);
+		bf_set(lpfc_sli4_sge_dif_ce, diseed, checking);
+		bf_set(lpfc_sli4_sge_dif_re, diseed, checking);
+		bf_set(lpfc_sli4_sge_dif_ai, diseed, 1);
+		bf_set(lpfc_sli4_sge_dif_me, diseed, 0);
+
+		/* Endianness conversion if necessary for DISEED */
+		diseed->word2 = cpu_to_le32(diseed->word2);
+		diseed->word3 = cpu_to_le32(diseed->word3);
+
+		/* advance sgl and increment bde count */
+		num_sge++;
+		sgl++;
+
+		/* setup the first BDE that points to protection buffer */
+		protphysaddr = sg_dma_address(sgpe) + protgroup_offset;
+		protgroup_len = sg_dma_len(sgpe) - protgroup_offset;
+
+		/* must be integer multiple of the DIF block length */
+		BUG_ON(protgroup_len % 8);
+
+		/* Now setup DIF SGE */
+		sgl->word2 = 0;
+		bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DIF);
+		sgl->addr_hi = le32_to_cpu(putPaddrHigh(protphysaddr));
+		sgl->addr_lo = le32_to_cpu(putPaddrLow(protphysaddr));
+		sgl->word2 = cpu_to_le32(sgl->word2);
+
+		protgrp_blks = protgroup_len / 8;
+		protgrp_bytes = protgrp_blks * blksize;
+
+		/* check if DIF SGE is crossing the 4K boundary; if so split */
+		if ((sgl->addr_lo & 0xfff) + protgroup_len > 0x1000) {
+			protgroup_remainder = 0x1000 - (sgl->addr_lo & 0xfff);
+			protgroup_offset += protgroup_remainder;
+			protgrp_blks = protgroup_remainder / 8;
+			protgrp_bytes = protgrp_blks * blksize;
+		} else {
+			protgroup_offset = 0;
+			curr_prot++;
+		}
+
+		num_sge++;
+
+		/* setup SGE's for data blocks associated with DIF data */
+		pgdone = 0;
+		subtotal = 0; /* total bytes processed for current prot grp */
+		while (!pgdone) {
+			if (!sgde) {
+				lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+					"9086 BLKGRD:%s Invalid data segment\n",
+						__func__);
+				return 0;
+			}
+			sgl++;
+			dataphysaddr = sg_dma_address(sgde) + split_offset;
+
+			remainder = sg_dma_len(sgde) - split_offset;
+
+			if ((subtotal + remainder) <= protgrp_bytes) {
+				/* we can use this whole buffer */
+				dma_len = remainder;
+				split_offset = 0;
+
+				if ((subtotal + remainder) == protgrp_bytes)
+					pgdone = 1;
+			} else {
+				/* must split this buffer with next prot grp */
+				dma_len = protgrp_bytes - subtotal;
+				split_offset += dma_len;
+			}
+
+			subtotal += dma_len;
+
+			sgl->addr_lo = cpu_to_le32(putPaddrLow(dataphysaddr));
+			sgl->addr_hi = cpu_to_le32(putPaddrHigh(dataphysaddr));
+			bf_set(lpfc_sli4_sge_last, sgl, 0);
+			bf_set(lpfc_sli4_sge_offset, sgl, dma_offset);
+			bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA);
+
+			sgl->sge_len = cpu_to_le32(dma_len);
+			dma_offset += dma_len;
+
+			num_sge++;
+			curr_data++;
+
+			if (split_offset)
+				break;
+
+			/* Move to the next s/g segment if possible */
+			sgde = sg_next(sgde);
+		}
+
+		if (protgroup_offset) {
+			/* update the reference tag */
+			reftag += protgrp_blks;
+			sgl++;
+			continue;
+		}
+
+		/* are we done ? */
+		if (curr_prot == protcnt) {
+			bf_set(lpfc_sli4_sge_last, sgl, 1);
+			alldone = 1;
+		} else if (curr_prot < protcnt) {
+			/* advance to next prot buffer */
+			sgpe = sg_next(sgpe);
+			sgl++;
+
+			/* update the reference tag */
+			reftag += protgrp_blks;
+		} else {
+			/* if we're here, we have a bug */
+			lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+				"9085 BLKGRD: bug in %s\n", __func__);
+		}
+
+	} while (!alldone);
+
+out:
+
+	return num_sge;
+}
+
+/**
+ * lpfc_prot_group_type - Get prtotection group type of SCSI command
+ * @phba: The Hba for which this call is being executed.
+ * @sc: pointer to scsi command we're working on
+ *
  * Given a SCSI command that supports DIF, determine composition of protection
  * groups involved in setting up buffer lists
  *
- * Returns:
- *			      for DIF (for both read and write)
- * */
+ * Returns: Protection group type (with or without DIF)
+ *
+ **/
 static int
 lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc)
 {
@@ -1885,13 +2590,17 @@
 	return ret;
 }
 
-/*
+/**
+ * lpfc_bg_scsi_prep_dma_buf_s3 - DMA mapping for scsi buffer to SLI3 IF spec
+ * @phba: The Hba for which this call is being executed.
+ * @lpfc_cmd: The scsi buffer which is going to be prep'ed.
+ *
  * This is the protection/DIF aware version of
  * lpfc_scsi_prep_dma_buf(). It may be a good idea to combine the
  * two functions eventually, but for now, it's here
- */
+ **/
 static int
-lpfc_bg_scsi_prep_dma_buf(struct lpfc_hba *phba,
+lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba,
 		struct lpfc_scsi_buf *lpfc_cmd)
 {
 	struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;
@@ -2147,7 +2856,21 @@
 		cmd->sense_buffer[8] = 0;     /* Information descriptor type */
 		cmd->sense_buffer[9] = 0xa;   /* Additional descriptor length */
 		cmd->sense_buffer[10] = 0x80; /* Validity bit */
-		bghm /= cmd->device->sector_size;
+
+		/* bghm is a "on the wire" FC frame based count */
+		switch (scsi_get_prot_op(cmd)) {
+		case SCSI_PROT_READ_INSERT:
+		case SCSI_PROT_WRITE_STRIP:
+			bghm /= cmd->device->sector_size;
+			break;
+		case SCSI_PROT_READ_STRIP:
+		case SCSI_PROT_WRITE_INSERT:
+		case SCSI_PROT_READ_PASS:
+		case SCSI_PROT_WRITE_PASS:
+			bghm /= (cmd->device->sector_size +
+				sizeof(struct scsi_dif_tuple));
+			break;
+		}
 
 		failing_sector = scsi_get_lba(cmd);
 		failing_sector += bghm;
@@ -2160,7 +2883,7 @@
 		/* No error was reported - problem in FW? */
 		cmd->result = ScsiResult(DID_ERROR, 0);
 		lpfc_printf_log(phba, KERN_ERR, LOG_BG,
-			"9057 BLKGRD: no errors reported!\n");
+			"9057 BLKGRD: Unknown error reported!\n");
 	}
 
 out:
@@ -2292,6 +3015,180 @@
 }
 
 /**
+ * lpfc_bg_scsi_adjust_dl - Adjust SCSI data length for BlockGuard
+ * @phba: The Hba for which this call is being executed.
+ * @lpfc_cmd: The scsi buffer which is going to be adjusted.
+ *
+ * Adjust the data length to account for how much data
+ * is actually on the wire.
+ *
+ * returns the adjusted data length
+ **/
+static int
+lpfc_bg_scsi_adjust_dl(struct lpfc_hba *phba,
+		struct lpfc_scsi_buf *lpfc_cmd)
+{
+	struct scsi_cmnd *sc = lpfc_cmd->pCmd;
+	int diflen, fcpdl;
+	unsigned blksize;
+
+	fcpdl = scsi_bufflen(sc);
+
+	/* Check if there is protection data on the wire */
+	if (sc->sc_data_direction == DMA_FROM_DEVICE) {
+		/* Read */
+		if (scsi_get_prot_op(sc) ==  SCSI_PROT_READ_INSERT)
+			return fcpdl;
+
+	} else {
+		/* Write */
+		if (scsi_get_prot_op(sc) ==  SCSI_PROT_WRITE_STRIP)
+			return fcpdl;
+	}
+
+	/* If protection data on the wire, adjust the count accordingly */
+	blksize = lpfc_cmd_blksize(sc);
+	diflen = (fcpdl / blksize) * 8;
+	fcpdl += diflen;
+	return fcpdl;
+}
+
+/**
+ * lpfc_bg_scsi_prep_dma_buf_s4 - DMA mapping for scsi buffer to SLI4 IF spec
+ * @phba: The Hba for which this call is being executed.
+ * @lpfc_cmd: The scsi buffer which is going to be mapped.
+ *
+ * This is the protection/DIF aware version of
+ * lpfc_scsi_prep_dma_buf(). It may be a good idea to combine the
+ * two functions eventually, but for now, it's here
+ **/
+static int
+lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba,
+		struct lpfc_scsi_buf *lpfc_cmd)
+{
+	struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;
+	struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd;
+	struct sli4_sge *sgl = (struct sli4_sge *)(lpfc_cmd->fcp_bpl);
+	IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
+	uint32_t num_bde = 0;
+	int datasegcnt, protsegcnt, datadir = scsi_cmnd->sc_data_direction;
+	int prot_group_type = 0;
+	int fcpdl;
+
+	/*
+	 * Start the lpfc command prep by bumping the sgl beyond fcp_cmnd
+	 *  fcp_rsp regions to the first data bde entry
+	 */
+	if (scsi_sg_count(scsi_cmnd)) {
+		/*
+		 * The driver stores the segment count returned from pci_map_sg
+		 * because this a count of dma-mappings used to map the use_sg
+		 * pages.  They are not guaranteed to be the same for those
+		 * architectures that implement an IOMMU.
+		 */
+		datasegcnt = dma_map_sg(&phba->pcidev->dev,
+					scsi_sglist(scsi_cmnd),
+					scsi_sg_count(scsi_cmnd), datadir);
+		if (unlikely(!datasegcnt))
+			return 1;
+
+		sgl += 1;
+		/* clear the last flag in the fcp_rsp map entry */
+		sgl->word2 = le32_to_cpu(sgl->word2);
+		bf_set(lpfc_sli4_sge_last, sgl, 0);
+		sgl->word2 = cpu_to_le32(sgl->word2);
+
+		sgl += 1;
+		lpfc_cmd->seg_cnt = datasegcnt;
+		if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+					"9087 BLKGRD: %s: Too many sg segments"
+					" from dma_map_sg.  Config %d, seg_cnt"
+					" %d\n",
+					__func__, phba->cfg_sg_seg_cnt,
+					lpfc_cmd->seg_cnt);
+			scsi_dma_unmap(scsi_cmnd);
+			return 1;
+		}
+
+		prot_group_type = lpfc_prot_group_type(phba, scsi_cmnd);
+
+		switch (prot_group_type) {
+		case LPFC_PG_TYPE_NO_DIF:
+			num_bde = lpfc_bg_setup_sgl(phba, scsi_cmnd, sgl,
+					datasegcnt);
+			/* we should have 2 or more entries in buffer list */
+			if (num_bde < 2)
+				goto err;
+			break;
+		case LPFC_PG_TYPE_DIF_BUF:{
+			/*
+			 * This type indicates that protection buffers are
+			 * passed to the driver, so that needs to be prepared
+			 * for DMA
+			 */
+			protsegcnt = dma_map_sg(&phba->pcidev->dev,
+					scsi_prot_sglist(scsi_cmnd),
+					scsi_prot_sg_count(scsi_cmnd), datadir);
+			if (unlikely(!protsegcnt)) {
+				scsi_dma_unmap(scsi_cmnd);
+				return 1;
+			}
+
+			lpfc_cmd->prot_seg_cnt = protsegcnt;
+			if (lpfc_cmd->prot_seg_cnt
+			    > phba->cfg_prot_sg_seg_cnt) {
+				lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+					"9088 BLKGRD: %s: Too many prot sg "
+					"segments from dma_map_sg.  Config %d,"
+						"prot_seg_cnt %d\n", __func__,
+						phba->cfg_prot_sg_seg_cnt,
+						lpfc_cmd->prot_seg_cnt);
+				dma_unmap_sg(&phba->pcidev->dev,
+					     scsi_prot_sglist(scsi_cmnd),
+					     scsi_prot_sg_count(scsi_cmnd),
+					     datadir);
+				scsi_dma_unmap(scsi_cmnd);
+				return 1;
+			}
+
+			num_bde = lpfc_bg_setup_sgl_prot(phba, scsi_cmnd, sgl,
+					datasegcnt, protsegcnt);
+			/* we should have 3 or more entries in buffer list */
+			if (num_bde < 3)
+				goto err;
+			break;
+		}
+		case LPFC_PG_TYPE_INVALID:
+		default:
+			lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+					"9083 Unexpected protection group %i\n",
+					prot_group_type);
+			return 1;
+		}
+	}
+
+	fcpdl = lpfc_bg_scsi_adjust_dl(phba, lpfc_cmd);
+
+	fcp_cmnd->fcpDl = be32_to_cpu(fcpdl);
+
+	/*
+	 * Due to difference in data length between DIF/non-DIF paths,
+	 * we need to set word 4 of IOCB here
+	 */
+	iocb_cmd->un.fcpi.fcpi_parm = fcpdl;
+	lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_DIF;
+
+	return 0;
+err:
+	lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+			"9084 Could not setup all needed BDE's"
+			"prot_group_type=%d, num_bde=%d\n",
+			prot_group_type, num_bde);
+	return 1;
+}
+
+/**
  * lpfc_scsi_prep_dma_buf - Wrapper function for DMA mapping of scsi buffer
  * @phba: The Hba for which this call is being executed.
  * @lpfc_cmd: The scsi buffer which is going to be mapped.
@@ -2310,6 +3207,25 @@
 }
 
 /**
+ * lpfc_bg_scsi_prep_dma_buf - Wrapper function for DMA mapping of scsi buffer
+ * using BlockGuard.
+ * @phba: The Hba for which this call is being executed.
+ * @lpfc_cmd: The scsi buffer which is going to be mapped.
+ *
+ * This routine wraps the actual DMA mapping function pointer from the
+ * lpfc_hba struct.
+ *
+ * Return codes:
+ *	1 - Error
+ *	0 - Success
+ **/
+static inline int
+lpfc_bg_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
+{
+	return phba->lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd);
+}
+
+/**
  * lpfc_send_scsi_error_event - Posts an event when there is SCSI error
  * @phba: Pointer to hba context object.
  * @vport: Pointer to vport object.
@@ -2639,6 +3555,37 @@
 	/* pick up SLI4 exhange busy status from HBA */
 	lpfc_cmd->exch_busy = pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY;
 
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+	if (lpfc_cmd->prot_data_type) {
+		struct scsi_dif_tuple *src = NULL;
+
+		src =  (struct scsi_dif_tuple *)lpfc_cmd->prot_data_segment;
+		/*
+		 * Used to restore any changes to protection
+		 * data for error injection.
+		 */
+		switch (lpfc_cmd->prot_data_type) {
+		case LPFC_INJERR_REFTAG:
+			src->ref_tag =
+				lpfc_cmd->prot_data;
+			break;
+		case LPFC_INJERR_APPTAG:
+			src->app_tag =
+				(uint16_t)lpfc_cmd->prot_data;
+			break;
+		case LPFC_INJERR_GUARD:
+			src->guard_tag =
+				(uint16_t)lpfc_cmd->prot_data;
+			break;
+		default:
+			break;
+		}
+
+		lpfc_cmd->prot_data = 0;
+		lpfc_cmd->prot_data_type = 0;
+		lpfc_cmd->prot_data_segment = NULL;
+	}
+#endif
 	if (pnode && NLP_CHK_NODE_ACT(pnode))
 		atomic_dec(&pnode->cmd_pending);
 
@@ -3072,12 +4019,14 @@
 	case LPFC_PCI_DEV_LP:
 		phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s3;
 		phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s3;
+		phba->lpfc_bg_scsi_prep_dma_buf = lpfc_bg_scsi_prep_dma_buf_s3;
 		phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s3;
 		phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s3;
 		break;
 	case LPFC_PCI_DEV_OC:
 		phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s4;
 		phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s4;
+		phba->lpfc_bg_scsi_prep_dma_buf = lpfc_bg_scsi_prep_dma_buf_s4;
 		phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s4;
 		phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s4;
 		break;
@@ -3238,20 +4187,10 @@
 		cmnd->result = err;
 		goto out_fail_command;
 	}
-	/*
-	 * Do not let the mid-layer retry I/O too fast. If an I/O is retried
-	 * without waiting a bit then indicate that the device is busy.
-	 */
-	if (cmnd->retries &&
-	    time_before(jiffies, (cmnd->jiffies_at_alloc +
-				  msecs_to_jiffies(LPFC_RETRY_PAUSE *
-						   cmnd->retries))))
-		return SCSI_MLQUEUE_DEVICE_BUSY;
 	ndlp = rdata->pnode;
 
 	if ((scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) &&
-		(!(phba->sli3_options & LPFC_SLI3_BG_ENABLED) ||
-		(phba->sli_rev == LPFC_SLI_REV4))) {
+		(!(phba->sli3_options & LPFC_SLI3_BG_ENABLED))) {
 
 		lpfc_printf_log(phba, KERN_ERR, LOG_BG,
 				"9058 BLKGRD: ERROR: rcvd protected cmd:%02x"
@@ -3297,63 +4236,48 @@
 	if (scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) {
 		if (vport->phba->cfg_enable_bg) {
 			lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
-				"9033 BLKGRD: rcvd protected cmd:%02x op:%02x "
-				"str=%s\n",
-				cmnd->cmnd[0], scsi_get_prot_op(cmnd),
-				dif_op_str[scsi_get_prot_op(cmnd)]);
-			lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
-				"9034 BLKGRD: CDB: %02x %02x %02x %02x %02x "
-				"%02x %02x %02x %02x %02x\n",
-				cmnd->cmnd[0], cmnd->cmnd[1], cmnd->cmnd[2],
-				cmnd->cmnd[3], cmnd->cmnd[4], cmnd->cmnd[5],
-				cmnd->cmnd[6], cmnd->cmnd[7], cmnd->cmnd[8],
-				cmnd->cmnd[9]);
+				"9033 BLKGRD: rcvd protected cmd:%02x op=%s "
+				"guard=%s\n", cmnd->cmnd[0],
+				dif_op_str[scsi_get_prot_op(cmnd)],
+				dif_grd_str[scsi_host_get_guard(shost)]);
 			if (cmnd->cmnd[0] == READ_10)
 				lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
 					"9035 BLKGRD: READ @ sector %llu, "
-					"count %u\n",
+					"cnt %u, rpt %d\n",
 					(unsigned long long)scsi_get_lba(cmnd),
-					blk_rq_sectors(cmnd->request));
+					blk_rq_sectors(cmnd->request),
+					(cmnd->cmnd[1]>>5));
 			else if (cmnd->cmnd[0] == WRITE_10)
 				lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
 					"9036 BLKGRD: WRITE @ sector %llu, "
-					"count %u cmd=%p\n",
+					"cnt %u, wpt %d\n",
 					(unsigned long long)scsi_get_lba(cmnd),
 					blk_rq_sectors(cmnd->request),
-					cmnd);
+					(cmnd->cmnd[1]>>5));
 		}
 
 		err = lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd);
 	} else {
 		if (vport->phba->cfg_enable_bg) {
 			lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
-					"9038 BLKGRD: rcvd unprotected cmd:"
-					"%02x op:%02x str=%s\n",
-					cmnd->cmnd[0], scsi_get_prot_op(cmnd),
-					dif_op_str[scsi_get_prot_op(cmnd)]);
-				lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
-					"9039 BLKGRD: CDB: %02x %02x %02x "
-					"%02x %02x %02x %02x %02x %02x %02x\n",
-					cmnd->cmnd[0], cmnd->cmnd[1],
-					cmnd->cmnd[2], cmnd->cmnd[3],
-					cmnd->cmnd[4], cmnd->cmnd[5],
-					cmnd->cmnd[6], cmnd->cmnd[7],
-					cmnd->cmnd[8], cmnd->cmnd[9]);
+				"9038 BLKGRD: rcvd unprotected cmd:"
+				"%02x op=%s guard=%s\n", cmnd->cmnd[0],
+				dif_op_str[scsi_get_prot_op(cmnd)],
+				dif_grd_str[scsi_host_get_guard(shost)]);
 			if (cmnd->cmnd[0] == READ_10)
 				lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
 					"9040 dbg: READ @ sector %llu, "
-					"count %u\n",
+					"cnt %u, rpt %d\n",
 					(unsigned long long)scsi_get_lba(cmnd),
-					 blk_rq_sectors(cmnd->request));
+					 blk_rq_sectors(cmnd->request),
+					(cmnd->cmnd[1]>>5));
 			else if (cmnd->cmnd[0] == WRITE_10)
 				lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
-					 "9041 dbg: WRITE @ sector %llu, "
-					 "count %u cmd=%p\n",
-					 (unsigned long long)scsi_get_lba(cmnd),
-					 blk_rq_sectors(cmnd->request), cmnd);
-			else
-				lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
-					 "9042 dbg: parser not implemented\n");
+					"9041 dbg: WRITE @ sector %llu, "
+					"cnt %u, wpt %d\n",
+					(unsigned long long)scsi_get_lba(cmnd),
+					blk_rq_sectors(cmnd->request),
+					(cmnd->cmnd[1]>>5));
 		}
 		err = lpfc_scsi_prep_dma_buf(phba, lpfc_cmd);
 	}
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
index 9075a08..21a2ffe 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.h
+++ b/drivers/scsi/lpfc/lpfc_scsi.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2012 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -150,9 +150,18 @@
 	struct lpfc_iocbq cur_iocbq;
 	wait_queue_head_t *waitq;
 	unsigned long start_time;
+
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+	/* Used to restore any changes to protection data for error injection */
+	void *prot_data_segment;
+	uint32_t prot_data;
+	uint32_t prot_data_type;
+#define	LPFC_INJERR_REFTAG	1
+#define	LPFC_INJERR_APPTAG	2
+#define	LPFC_INJERR_GUARD	3
+#endif
 };
 
 #define LPFC_SCSI_DMA_EXT_SIZE 264
 #define LPFC_BPL_SIZE          1024
-#define LPFC_RETRY_PAUSE       300
 #define MDAC_DIRECT_CMD                  0x22
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 23a2759..dbaf5b9 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2011 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2012 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -293,7 +293,9 @@
 	}
 	bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, released);
 	bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT);
-	bf_set(lpfc_eqcq_doorbell_eqid, &doorbell, q->queue_id);
+	bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell,
+			(q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT));
+	bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id);
 	writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr);
 	/* PCI read to flush PCI pipeline on re-arming for INTx mode */
 	if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM))
@@ -372,7 +374,9 @@
 		bf_set(lpfc_eqcq_doorbell_arm, &doorbell, 1);
 	bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, released);
 	bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_COMPLETION);
-	bf_set(lpfc_eqcq_doorbell_cqid, &doorbell, q->queue_id);
+	bf_set(lpfc_eqcq_doorbell_cqid_hi, &doorbell,
+			(q->queue_id >> LPFC_CQID_HI_FIELD_SHIFT));
+	bf_set(lpfc_eqcq_doorbell_cqid_lo, &doorbell, q->queue_id);
 	writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr);
 	return released;
 }
@@ -554,81 +558,6 @@
 }
 
 /**
- * __lpfc_set_rrq_active - set RRQ active bit in the ndlp's xri_bitmap.
- * @phba: Pointer to HBA context object.
- * @ndlp: nodelist pointer for this target.
- * @xritag: xri used in this exchange.
- * @rxid: Remote Exchange ID.
- * @send_rrq: Flag used to determine if we should send rrq els cmd.
- *
- * This function is called with hbalock held.
- * The active bit is set in the ndlp's active rrq xri_bitmap. Allocates an
- * rrq struct and adds it to the active_rrq_list.
- *
- * returns  0 for rrq slot for this xri
- *         < 0  Were not able to get rrq mem or invalid parameter.
- **/
-static int
-__lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
-		uint16_t xritag, uint16_t rxid, uint16_t send_rrq)
-{
-	struct lpfc_node_rrq *rrq;
-	int empty;
-	uint32_t did = 0;
-
-
-	if (!ndlp)
-		return -EINVAL;
-
-	if (!phba->cfg_enable_rrq)
-		return -EINVAL;
-
-	if (phba->pport->load_flag & FC_UNLOADING) {
-		phba->hba_flag &= ~HBA_RRQ_ACTIVE;
-		goto out;
-	}
-	did = ndlp->nlp_DID;
-
-	/*
-	 * set the active bit even if there is no mem available.
-	 */
-	if (NLP_CHK_FREE_REQ(ndlp))
-		goto out;
-
-	if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING))
-		goto out;
-
-	if (test_and_set_bit(xritag, ndlp->active_rrqs.xri_bitmap))
-		goto out;
-
-	rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL);
-	if (rrq) {
-		rrq->send_rrq = send_rrq;
-		rrq->xritag = xritag;
-		rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1);
-		rrq->ndlp = ndlp;
-		rrq->nlp_DID = ndlp->nlp_DID;
-		rrq->vport = ndlp->vport;
-		rrq->rxid = rxid;
-		empty = list_empty(&phba->active_rrq_list);
-		rrq->send_rrq = send_rrq;
-		list_add_tail(&rrq->list, &phba->active_rrq_list);
-		if (!(phba->hba_flag & HBA_RRQ_ACTIVE)) {
-			phba->hba_flag |= HBA_RRQ_ACTIVE;
-			if (empty)
-				lpfc_worker_wake_up(phba);
-		}
-		return 0;
-	}
-out:
-	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-			"2921 Can't set rrq active xri:0x%x rxid:0x%x"
-			" DID:0x%x Send:%d\n",
-			xritag, rxid, did, send_rrq);
-	return -EINVAL;
-}
-
-/**
  * lpfc_clr_rrq_active - Clears RRQ active bit in xri_bitmap.
  * @phba: Pointer to HBA context object.
  * @xritag: xri used in this exchange.
@@ -856,15 +785,68 @@
  **/
 int
 lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
-			uint16_t xritag, uint16_t rxid, uint16_t send_rrq)
+		    uint16_t xritag, uint16_t rxid, uint16_t send_rrq)
 {
-	int ret;
 	unsigned long iflags;
+	struct lpfc_node_rrq *rrq;
+	int empty;
+
+	if (!ndlp)
+		return -EINVAL;
+
+	if (!phba->cfg_enable_rrq)
+		return -EINVAL;
 
 	spin_lock_irqsave(&phba->hbalock, iflags);
-	ret = __lpfc_set_rrq_active(phba, ndlp, xritag, rxid, send_rrq);
+	if (phba->pport->load_flag & FC_UNLOADING) {
+		phba->hba_flag &= ~HBA_RRQ_ACTIVE;
+		goto out;
+	}
+
+	/*
+	 * set the active bit even if there is no mem available.
+	 */
+	if (NLP_CHK_FREE_REQ(ndlp))
+		goto out;
+
+	if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING))
+		goto out;
+
+	if (test_and_set_bit(xritag, ndlp->active_rrqs.xri_bitmap))
+		goto out;
+
 	spin_unlock_irqrestore(&phba->hbalock, iflags);
-	return ret;
+	rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL);
+	if (!rrq) {
+		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+				"3155 Unable to allocate RRQ xri:0x%x rxid:0x%x"
+				" DID:0x%x Send:%d\n",
+				xritag, rxid, ndlp->nlp_DID, send_rrq);
+		return -EINVAL;
+	}
+	rrq->send_rrq = send_rrq;
+	rrq->xritag = xritag;
+	rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1);
+	rrq->ndlp = ndlp;
+	rrq->nlp_DID = ndlp->nlp_DID;
+	rrq->vport = ndlp->vport;
+	rrq->rxid = rxid;
+	rrq->send_rrq = send_rrq;
+	spin_lock_irqsave(&phba->hbalock, iflags);
+	empty = list_empty(&phba->active_rrq_list);
+	list_add_tail(&rrq->list, &phba->active_rrq_list);
+	phba->hba_flag |= HBA_RRQ_ACTIVE;
+	if (empty)
+		lpfc_worker_wake_up(phba);
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+	return 0;
+out:
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+			"2921 Can't set rrq active xri:0x%x rxid:0x%x"
+			" DID:0x%x Send:%d\n",
+			xritag, rxid, ndlp->nlp_DID, send_rrq);
+	return -EINVAL;
 }
 
 /**
@@ -5629,6 +5611,8 @@
 			rc = -ENOMEM;
 			goto free_vpi_ids;
 		}
+		phba->sli4_hba.max_cfg_param.xri_used = 0;
+		phba->sli4_hba.xri_count = 0;
 		phba->sli4_hba.xri_ids = kzalloc(count *
 						 sizeof(uint16_t),
 						 GFP_KERNEL);
@@ -6163,6 +6147,7 @@
 		rc = -ENODEV;
 		goto out_free_mbox;
 	}
+	lpfc_sli4_node_prep(phba);
 
 	/* Create all the SLI4 queues */
 	rc = lpfc_sli4_queue_create(phba);
@@ -7267,11 +7252,13 @@
 
 out_not_finished:
 	spin_lock_irqsave(&phba->hbalock, iflags);
-	mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED;
-	__lpfc_mbox_cmpl_put(phba, mboxq);
-	/* Release the token */
-	psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
-	phba->sli.mbox_active = NULL;
+	if (phba->sli.mbox_active) {
+		mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED;
+		__lpfc_mbox_cmpl_put(phba, mboxq);
+		/* Release the token */
+		psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+		phba->sli.mbox_active = NULL;
+	}
 	spin_unlock_irqrestore(&phba->hbalock, iflags);
 
 	return MBX_NOT_FINISHED;
@@ -7555,6 +7542,8 @@
 
 	sgl  = (struct sli4_sge *)sglq->sgl;
 	icmd = &piocbq->iocb;
+	if (icmd->ulpCommand == CMD_XMIT_BLS_RSP64_CX)
+		return sglq->sli4_xritag;
 	if (icmd->un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) {
 		numBdes = icmd->un.genreq64.bdl.bdeSize /
 				sizeof(struct ulp_bde64);
@@ -7756,6 +7745,8 @@
 		if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
 			if (pcmd && (*pcmd == ELS_CMD_FLOGI ||
 				*pcmd == ELS_CMD_SCR ||
+				*pcmd == ELS_CMD_FDISC ||
+				*pcmd == ELS_CMD_LOGO ||
 				*pcmd == ELS_CMD_PLOGI)) {
 				bf_set(els_req64_sp, &wqe->els_req, 1);
 				bf_set(els_req64_sid, &wqe->els_req,
@@ -7763,7 +7754,7 @@
 				bf_set(wqe_ct, &wqe->els_req.wqe_com, 1);
 				bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
 					phba->vpi_ids[phba->pport->vpi]);
-			} else if (iocbq->context1) {
+			} else if (pcmd && iocbq->context1) {
 				bf_set(wqe_ct, &wqe->els_req.wqe_com, 0);
 				bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
 					phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
@@ -7830,12 +7821,16 @@
 		bf_set(wqe_lnk, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpXS);
 		/* Always open the exchange */
 		bf_set(wqe_xc, &wqe->fcp_iwrite.wqe_com, 0);
-		bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1);
 		bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE);
 		bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com,
 		       LPFC_WQE_LENLOC_WORD4);
 		bf_set(wqe_ebde_cnt, &wqe->fcp_iwrite.wqe_com, 0);
 		bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpPU);
+		if (iocbq->iocb_flag & LPFC_IO_DIF) {
+			iocbq->iocb_flag &= ~LPFC_IO_DIF;
+			bf_set(wqe_dif, &wqe->generic.wqe_com, 1);
+		}
+		bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1);
 		break;
 	case CMD_FCP_IREAD64_CR:
 		/* word3 iocb=iotag wqe=payload_offset_len */
@@ -7849,12 +7844,16 @@
 		bf_set(wqe_lnk, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpXS);
 		/* Always open the exchange */
 		bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0);
-		bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1);
 		bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ);
 		bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com,
 		       LPFC_WQE_LENLOC_WORD4);
 		bf_set(wqe_ebde_cnt, &wqe->fcp_iread.wqe_com, 0);
 		bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU);
+		if (iocbq->iocb_flag & LPFC_IO_DIF) {
+			iocbq->iocb_flag &= ~LPFC_IO_DIF;
+			bf_set(wqe_dif, &wqe->generic.wqe_com, 1);
+		}
+		bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1);
 		break;
 	case CMD_FCP_ICMND64_CR:
 		/* word3 iocb=IO_TAG wqe=reserved */
@@ -7982,6 +7981,7 @@
 		xritag = 0;
 		break;
 	case CMD_XMIT_BLS_RSP64_CX:
+		ndlp = (struct lpfc_nodelist *)iocbq->context1;
 		/* As BLS ABTS RSP WQE is very different from other WQEs,
 		 * we re-construct this WQE here based on information in
 		 * iocbq from scratch.
@@ -8008,8 +8008,15 @@
 		}
 		bf_set(xmit_bls_rsp64_seqcnthi, &wqe->xmit_bls_rsp, 0xffff);
 		bf_set(wqe_xmit_bls_pt, &wqe->xmit_bls_rsp.wqe_dest, 0x1);
+
+		/* Use CT=VPI */
+		bf_set(wqe_els_did, &wqe->xmit_bls_rsp.wqe_dest,
+			ndlp->nlp_DID);
+		bf_set(xmit_bls_rsp64_temprpi, &wqe->xmit_bls_rsp,
+			iocbq->iocb.ulpContext);
+		bf_set(wqe_ct, &wqe->xmit_bls_rsp.wqe_com, 1);
 		bf_set(wqe_ctxt_tag, &wqe->xmit_bls_rsp.wqe_com,
-		       iocbq->iocb.ulpContext);
+			phba->vpi_ids[phba->pport->vpi]);
 		bf_set(wqe_qosd, &wqe->xmit_bls_rsp.wqe_com, 1);
 		bf_set(wqe_lenloc, &wqe->xmit_bls_rsp.wqe_com,
 		       LPFC_WQE_LENLOC_NONE);
@@ -8073,8 +8080,7 @@
 
 	if (piocb->sli4_xritag == NO_XRI) {
 		if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
-		    piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN ||
-		    piocb->iocb.ulpCommand == CMD_XMIT_BLS_RSP64_CX)
+		    piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
 			sglq = NULL;
 		else {
 			if (pring->txq_cnt) {
@@ -8383,20 +8389,32 @@
 			   struct sli4_wcqe_xri_aborted *axri)
 {
 	struct lpfc_vport *vport;
+	uint32_t ext_status = 0;
 
-	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
+	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
 		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
 				"3115 Node Context not found, driver "
 				"ignoring abts err event\n");
+		return;
+	}
+
 	vport = ndlp->vport;
 	lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
 			"3116 Port generated FCP XRI ABORT event on "
-			"vpi %d rpi %d xri x%x status 0x%x\n",
+			"vpi %d rpi %d xri x%x status 0x%x parameter x%x\n",
 			ndlp->vport->vpi, ndlp->nlp_rpi,
 			bf_get(lpfc_wcqe_xa_xri, axri),
-			bf_get(lpfc_wcqe_xa_status, axri));
+			bf_get(lpfc_wcqe_xa_status, axri),
+			axri->parameter);
 
-	if (bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT)
+	/*
+	 * Catch the ABTS protocol failure case.  Older OCe FW releases returned
+	 * LOCAL_REJECT and 0 for a failed ABTS exchange and later OCe and
+	 * LPe FW releases returned LOCAL_REJECT and SEQUENCE_TIMEOUT.
+	 */
+	ext_status = axri->parameter & WCQE_PARAM_MASK;
+	if ((bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT) &&
+	    ((ext_status == IOERR_SEQUENCE_TIMEOUT) || (ext_status == 0)))
 		lpfc_sli_abts_recover_port(vport, ndlp);
 }
 
@@ -9802,12 +9820,11 @@
 	unsigned long timeout;
 
 	timeout = msecs_to_jiffies(LPFC_MBOX_TMO * 1000) + jiffies;
+
 	spin_lock_irq(&phba->hbalock);
 	psli->sli_flag |= LPFC_SLI_ASYNC_MBX_BLK;
-	spin_unlock_irq(&phba->hbalock);
 
 	if (psli->sli_flag & LPFC_SLI_ACTIVE) {
-		spin_lock_irq(&phba->hbalock);
 		/* Determine how long we might wait for the active mailbox
 		 * command to be gracefully completed by firmware.
 		 */
@@ -9826,7 +9843,9 @@
 				 */
 				break;
 		}
-	}
+	} else
+		spin_unlock_irq(&phba->hbalock);
+
 	lpfc_sli_mbox_sys_flush(phba);
 }
 
@@ -10653,12 +10672,14 @@
 			      struct lpfc_wcqe_complete *wcqe)
 {
 	unsigned long iflags;
+	uint32_t status;
 	size_t offset = offsetof(struct lpfc_iocbq, iocb);
 
 	memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset,
 	       sizeof(struct lpfc_iocbq) - offset);
 	/* Map WCQE parameters into irspiocb parameters */
-	pIocbIn->iocb.ulpStatus = bf_get(lpfc_wcqe_c_status, wcqe);
+	status = bf_get(lpfc_wcqe_c_status, wcqe);
+	pIocbIn->iocb.ulpStatus = (status & LPFC_IOCB_STATUS_MASK);
 	if (pIocbOut->iocb_flag & LPFC_IO_FCP)
 		if (pIocbIn->iocb.ulpStatus == IOSTAT_FCP_RSP_ERROR)
 			pIocbIn->iocb.un.fcpi.fcpi_parm =
@@ -10671,6 +10692,44 @@
 		pIocbIn->iocb.un.genreq64.bdl.bdeSize = wcqe->total_data_placed;
 	}
 
+	/* Convert BG errors for completion status */
+	if (status == CQE_STATUS_DI_ERROR) {
+		pIocbIn->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
+
+		if (bf_get(lpfc_wcqe_c_bg_edir, wcqe))
+			pIocbIn->iocb.un.ulpWord[4] = IOERR_RX_DMA_FAILED;
+		else
+			pIocbIn->iocb.un.ulpWord[4] = IOERR_TX_DMA_FAILED;
+
+		pIocbIn->iocb.unsli3.sli3_bg.bgstat = 0;
+		if (bf_get(lpfc_wcqe_c_bg_ge, wcqe)) /* Guard Check failed */
+			pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
+				BGS_GUARD_ERR_MASK;
+		if (bf_get(lpfc_wcqe_c_bg_ae, wcqe)) /* App Tag Check failed */
+			pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
+				BGS_APPTAG_ERR_MASK;
+		if (bf_get(lpfc_wcqe_c_bg_re, wcqe)) /* Ref Tag Check failed */
+			pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
+				BGS_REFTAG_ERR_MASK;
+
+		/* Check to see if there was any good data before the error */
+		if (bf_get(lpfc_wcqe_c_bg_tdpv, wcqe)) {
+			pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
+				BGS_HI_WATER_MARK_PRESENT_MASK;
+			pIocbIn->iocb.unsli3.sli3_bg.bghm =
+				wcqe->total_data_placed;
+		}
+
+		/*
+		* Set ALL the error bits to indicate we don't know what
+		* type of error it is.
+		*/
+		if (!pIocbIn->iocb.unsli3.sli3_bg.bgstat)
+			pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
+				(BGS_REFTAG_ERR_MASK | BGS_APPTAG_ERR_MASK |
+				BGS_GUARD_ERR_MASK);
+	}
+
 	/* Pick up HBA exchange busy condition */
 	if (bf_get(lpfc_wcqe_c_xb, wcqe)) {
 		spin_lock_irqsave(&phba->hbalock, iflags);
@@ -13227,7 +13286,7 @@
 	LPFC_MBOXQ_t *mbox;
 	uint32_t reqlen, alloclen, index;
 	uint32_t mbox_tmo;
-	uint16_t rsrc_start, rsrc_size, els_xri_cnt;
+	uint16_t rsrc_start, rsrc_size, els_xri_cnt, post_els_xri_cnt;
 	uint16_t xritag_start = 0, lxri = 0;
 	struct lpfc_rsrc_blks *rsrc_blk;
 	int cnt, ttl_cnt, rc = 0;
@@ -13249,6 +13308,7 @@
 
 	cnt = 0;
 	ttl_cnt = 0;
+	post_els_xri_cnt = els_xri_cnt;
 	list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list,
 			    list) {
 		rsrc_start = rsrc_blk->rsrc_start;
@@ -13258,11 +13318,12 @@
 				"3014 Working ELS Extent start %d, cnt %d\n",
 				rsrc_start, rsrc_size);
 
-		loop_cnt = min(els_xri_cnt, rsrc_size);
-		if (ttl_cnt + loop_cnt >= els_xri_cnt) {
-			loop_cnt = els_xri_cnt - ttl_cnt;
-			ttl_cnt = els_xri_cnt;
-		}
+		loop_cnt = min(post_els_xri_cnt, rsrc_size);
+		if (loop_cnt < post_els_xri_cnt) {
+			post_els_xri_cnt -= loop_cnt;
+			ttl_cnt += loop_cnt;
+		} else
+			ttl_cnt += post_els_xri_cnt;
 
 		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 		if (!mbox)
@@ -14042,6 +14103,13 @@
 {
 	if (cmd_iocbq)
 		lpfc_sli_release_iocbq(phba, cmd_iocbq);
+
+	/* Failure means BLS ABORT RSP did not get delivered to remote node*/
+	if (rsp_iocbq && rsp_iocbq->iocb.ulpStatus)
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+			"3154 BLS ABORT RSP failed, data:  x%x/x%x\n",
+			rsp_iocbq->iocb.ulpStatus,
+			rsp_iocbq->iocb.un.ulpWord[4]);
 }
 
 /**
@@ -14151,15 +14219,14 @@
 		 * field and RX_ID from ABTS for RX_ID field.
 		 */
 		bf_set(lpfc_abts_orig, &icmd->un.bls_rsp, LPFC_ABTS_UNSOL_RSP);
-		bf_set(lpfc_abts_rxid, &icmd->un.bls_rsp, rxid);
 	} else {
 		/* ABTS sent by initiator to CT exchange, construction
 		 * of BA_ACC will need to allocate a new XRI as for the
-		 * XRI_TAG and RX_ID fields.
+		 * XRI_TAG field.
 		 */
 		bf_set(lpfc_abts_orig, &icmd->un.bls_rsp, LPFC_ABTS_UNSOL_INT);
-		bf_set(lpfc_abts_rxid, &icmd->un.bls_rsp, NO_XRI);
 	}
+	bf_set(lpfc_abts_rxid, &icmd->un.bls_rsp, rxid);
 	bf_set(lpfc_abts_oxid, &icmd->un.bls_rsp, oxid);
 
 	/* Xmit CT abts response on exchange <xid> */
@@ -14748,7 +14815,8 @@
  * provided rpi via a bitmask.
  **/
 int
-lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp)
+lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp,
+	void (*cmpl)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *arg)
 {
 	LPFC_MBOXQ_t *mboxq;
 	struct lpfc_hba *phba = ndlp->phba;
@@ -14761,6 +14829,13 @@
 
 	/* Post all rpi memory regions to the port. */
 	lpfc_resume_rpi(mboxq, ndlp);
+	if (cmpl) {
+		mboxq->mbox_cmpl = cmpl;
+		mboxq->context1 = arg;
+		mboxq->context2 = ndlp;
+	} else
+		mboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+	mboxq->vport = ndlp->vport;
 	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
 	if (rc == MBX_NOT_FINISHED) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
@@ -14982,6 +15057,7 @@
 	LPFC_MBOXQ_t *mboxq;
 
 	phba->fcoe_eventtag_at_fcf_scan = phba->fcoe_eventtag;
+	phba->fcoe_cvl_eventtag_attn = phba->fcoe_cvl_eventtag;
 	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (!mboxq) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 29c13b6..3290b8e 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -69,6 +69,7 @@
 #define LPFC_USE_FCPWQIDX	0x80    /* Submit to specified FCPWQ index */
 #define DSS_SECURITY_OP		0x100	/* security IO */
 #define LPFC_IO_ON_Q		0x200	/* The IO is still on the TXCMPLQ */
+#define LPFC_IO_DIF		0x400	/* T10 DIF IO */
 
 #define LPFC_FIP_ELS_ID_MASK	0xc000	/* ELS_ID range 0-3, non-shifted mask */
 #define LPFC_FIP_ELS_ID_SHIFT	14
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 3f266e2..c19d139 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -633,7 +633,8 @@
 void lpfc_sli4_remove_rpis(struct lpfc_hba *);
 void lpfc_sli4_async_event_proc(struct lpfc_hba *);
 void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *);
-int lpfc_sli4_resume_rpi(struct lpfc_nodelist *);
+int lpfc_sli4_resume_rpi(struct lpfc_nodelist *,
+			void (*)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *);
 void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *);
 void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *);
 void lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *,
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index dd044d0..25cefc2 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2011 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2012 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.3.28"
+#define LPFC_DRIVER_VERSION "8.3.30"
 #define LPFC_DRIVER_NAME		"lpfc"
 #define LPFC_SP_DRIVER_HANDLER_NAME	"lpfc:sp"
 #define LPFC_FP_DRIVER_HANDLER_NAME	"lpfc:fp"
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index e617337..e5cd8d8 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -22,7 +22,6 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/prom.h>
-#include <asm/system.h>
 #include <asm/pci-bridge.h>
 #include <asm/macio.h>
 
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index 2bccfbe..24828b5 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -43,7 +43,6 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 
 #include <asm/macintosh.h>
 #include <asm/macints.h>
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 4944747..e8a04ae 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -33,7 +33,6 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/prom.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/hydra.h>
 #include <asm/processor.h>
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index a78036f..8a59a77 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -132,7 +132,7 @@
 		pdev = ioc->pdev;
 		if ((pdev == NULL))
 			return -1;
-		pci_remove_bus_device(pdev);
+		pci_stop_and_remove_bus_device(pdev);
 		return 0;
 }
 
@@ -657,7 +657,7 @@
 		return;
 
 	/* eat the loginfos associated with task aborts */
-	if (ioc->ignore_loginfos && (log_info == 30050000 || log_info ==
+	if (ioc->ignore_loginfos && (log_info == 0x30050000 || log_info ==
 	    0x31140000 || log_info == 0x31130000))
 		return;
 
@@ -2060,12 +2060,10 @@
 {
 	int i = 0;
 	char desc[16];
-	u8 revision;
 	u32 iounit_pg1_flags;
 	u32 bios_version;
 
 	bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
-	pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision);
 	strncpy(desc, ioc->manu_pg0.ChipName, 16);
 	printk(MPT2SAS_INFO_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), "
 	   "ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n",
@@ -2074,7 +2072,7 @@
 	   (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
 	   (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
 	   ioc->facts.FWVersion.Word & 0x000000FF,
-	   revision,
+	   ioc->pdev->revision,
 	   (bios_version & 0xFF000000) >> 24,
 	   (bios_version & 0x00FF0000) >> 16,
 	   (bios_version & 0x0000FF00) >> 8,
@@ -2575,6 +2573,11 @@
 
 	ioc->chain_lookup = (struct chain_tracker *)__get_free_pages(
 	    GFP_KERNEL, ioc->chain_pages);
+	if (!ioc->chain_lookup) {
+		printk(MPT2SAS_ERR_FMT "chain_lookup: get_free_pages failed, "
+		    "sz(%d)\n", ioc->name, (int)sz);
+		goto out;
+	}
 	ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev,
 	    ioc->request_sz, 16, 0);
 	if (!ioc->chain_dma_pool) {
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index 7fceb89..3b9a28e 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -1026,7 +1026,6 @@
 {
 	struct mpt2_ioctl_iocinfo karg;
 	struct MPT2SAS_ADAPTER *ioc;
-	u8 revision;
 
 	if (copy_from_user(&karg, arg, sizeof(karg))) {
 		printk(KERN_ERR "failure at %s:%d/%s()!\n",
@@ -1046,8 +1045,7 @@
 		karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2;
 	if (ioc->pfacts)
 		karg.port_number = ioc->pfacts[0].PortNumber;
-	pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision);
-	karg.hw_rev = revision;
+	karg.hw_rev = ioc->pdev->revision;
 	karg.pci_id = ioc->pdev->device;
 	karg.subsystem_device = ioc->pdev->subsystem_device;
 	karg.subsystem_vendor = ioc->pdev->subsystem_vendor;
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 193e33e..d953a57 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -5744,7 +5744,7 @@
 }
 
 /**
- * _scsih_sas_broadcast_primative_event - handle broadcast events
+ * _scsih_sas_broadcast_primitive_event - handle broadcast events
  * @ioc: per adapter object
  * @fw_event: The fw_event_work object
  * Context: user.
@@ -5752,7 +5752,7 @@
  * Return nothing.
  */
 static void
-_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
+_scsih_sas_broadcast_primitive_event(struct MPT2SAS_ADAPTER *ioc,
     struct fw_event_work *fw_event)
 {
 	struct scsi_cmnd *scmd;
@@ -7263,7 +7263,7 @@
 		    fw_event);
 		break;
 	case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
-		_scsih_sas_broadcast_primative_event(ioc,
+		_scsih_sas_broadcast_primitive_event(ioc,
 		    fw_event);
 		break;
 	case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index 6f58919..cc59dff 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -60,7 +60,6 @@
 	.queuecommand		= sas_queuecommand,
 	.target_alloc		= sas_target_alloc,
 	.slave_configure	= sas_slave_configure,
-	.slave_destroy		= sas_slave_destroy,
 	.scan_finished		= mvs_scan_finished,
 	.scan_start		= mvs_scan_start,
 	.change_queue_depth	= sas_change_queue_depth,
@@ -74,7 +73,6 @@
 	.use_clustering		= ENABLE_CLUSTERING,
 	.eh_device_reset_handler = sas_eh_device_reset_handler,
 	.eh_bus_reset_handler	= sas_eh_bus_reset_handler,
-	.slave_alloc		= sas_slave_alloc,
 	.target_destroy		= sas_target_destroy,
 	.ioctl			= sas_ioctl,
 	.shost_attrs		= mvst_host_attrs,
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index 01ab9c4..fd3b283 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -308,7 +308,7 @@
 	if (mvs_prv->scan_finished == 0)
 		return 0;
 
-	scsi_flush_work(shost);
+	sas_drain_work(sha);
 	return 1;
 }
 
@@ -893,9 +893,6 @@
 
 	mvi = ((struct mvs_device *)task->dev->lldd_dev)->mvi_info;
 
-	if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL))
-		spin_unlock_irq(dev->sata_dev.ap->lock);
-
 	spin_lock_irqsave(&mvi->lock, flags);
 	rc = mvs_task_prep(task, mvi, is_tmf, tmf, &pass);
 	if (rc)
@@ -906,9 +903,6 @@
 				(MVS_CHIP_SLOT_SZ - 1));
 	spin_unlock_irqrestore(&mvi->lock, flags);
 
-	if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL))
-		spin_lock_irq(dev->sata_dev.ap->lock);
-
 	return rc;
 }
 
@@ -1480,10 +1474,11 @@
 static int mvs_debug_I_T_nexus_reset(struct domain_device *dev)
 {
 	int rc;
-	struct sas_phy *phy = sas_find_local_phy(dev);
+	struct sas_phy *phy = sas_get_local_phy(dev);
 	int reset_type = (dev->dev_type == SATA_DEV ||
 			(dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
 	rc = sas_phy_reset(phy, reset_type);
+	sas_put_local_phy(phy);
 	msleep(2000);
 	return rc;
 }
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 4b3b475..5982a58 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -115,7 +115,6 @@
 
 #include <asm/dma.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 0029249..62b6168 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -38,7 +38,6 @@
 #include <linux/dma-mapping.h>
 
 #include <asm/dma.h>
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include <scsi/scsi.h>
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index de0b1a7..21883a2 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -54,7 +54,6 @@
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <asm/dma.h>
-#include <asm/system.h>
 
 /* The driver prints some debugging information on the console if DEBUG
    is defined and non-zero. */
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index f2018b4..2f72c98 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -113,7 +113,6 @@
  
 #include <linux/module.h>
 
-#include <asm/system.h>
 #include <linux/signal.h>
 #include <linux/proc_fs.h>
 #include <asm/io.h>
diff --git a/drivers/scsi/pm8001/pm8001_chips.h b/drivers/scsi/pm8001/pm8001_chips.h
index 4efa4d0..9241c78 100644
--- a/drivers/scsi/pm8001/pm8001_chips.h
+++ b/drivers/scsi/pm8001/pm8001_chips.h
@@ -46,9 +46,9 @@
 	return *((u32 *)virt_addr);
 }
 
-static inline void pm8001_write_32(void *addr, u32 offset, u32 val)
+static inline void pm8001_write_32(void *addr, u32 offset, __le32 val)
 {
-	*((u32 *)(addr + offset)) = val;
+	*((__le32 *)(addr + offset)) = val;
 }
 
 static inline u32 pm8001_cr32(struct pm8001_hba_info *pm8001_ha, u32 bar,
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index e12c4f6..9d82ee5 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -338,26 +338,25 @@
 }
 
 /**
- * bar4_shift - function is called to shift BAR base address
- * @pm8001_ha : our hba card information
+ * pm8001_bar4_shift - function is called to shift BAR base address
+ * @pm8001_ha : our hba card infomation
  * @shiftValue : shifting value in memory bar.
  */
-static int bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue)
+int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue)
 {
 	u32 regVal;
-	u32 max_wait_count;
+	unsigned long start;
 
 	/* program the inbound AXI translation Lower Address */
 	pm8001_cw32(pm8001_ha, 1, SPC_IBW_AXI_TRANSLATION_LOW, shiftValue);
 
 	/* confirm the setting is written */
-	max_wait_count = 1 * 1000 * 1000;  /* 1 sec */
+	start = jiffies + HZ; /* 1 sec */
 	do {
-		udelay(1);
 		regVal = pm8001_cr32(pm8001_ha, 1, SPC_IBW_AXI_TRANSLATION_LOW);
-	} while ((regVal != shiftValue) && (--max_wait_count));
+	} while ((regVal != shiftValue) && time_before(jiffies, start));
 
-	if (!max_wait_count) {
+	if (regVal != shiftValue) {
 		PM8001_INIT_DBG(pm8001_ha,
 			pm8001_printk("TIMEOUT:SPC_IBW_AXI_TRANSLATION_LOW"
 			" = 0x%x\n", regVal));
@@ -375,6 +374,7 @@
 mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, u32 SSCbit)
 {
 	u32 value, offset, i;
+	unsigned long flags;
 
 #define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000
 #define SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000
@@ -388,16 +388,23 @@
     * Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3)
     * Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7)
     */
-	if (-1 == bar4_shift(pm8001_ha, SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR))
+	spin_lock_irqsave(&pm8001_ha->lock, flags);
+	if (-1 == pm8001_bar4_shift(pm8001_ha,
+				SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR)) {
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 		return;
+	}
 
 	for (i = 0; i < 4; i++) {
 		offset = SAS2_SETTINGS_LOCAL_PHY_0_3_OFFSET + 0x4000 * i;
 		pm8001_cw32(pm8001_ha, 2, offset, 0x80001501);
 	}
 	/* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
-	if (-1 == bar4_shift(pm8001_ha, SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR))
+	if (-1 == pm8001_bar4_shift(pm8001_ha,
+				SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR)) {
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 		return;
+	}
 	for (i = 4; i < 8; i++) {
 		offset = SAS2_SETTINGS_LOCAL_PHY_4_7_OFFSET + 0x4000 * (i-4);
 		pm8001_cw32(pm8001_ha, 2, offset, 0x80001501);
@@ -421,7 +428,8 @@
 	pm8001_cw32(pm8001_ha, 2, 0xd8, 0x8000C016);
 
 	/*set the shifted destination address to 0x0 to avoid error operation */
-	bar4_shift(pm8001_ha, 0x0);
+	pm8001_bar4_shift(pm8001_ha, 0x0);
+	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 	return;
 }
 
@@ -437,6 +445,7 @@
 	u32 offset;
 	u32 value;
 	u32 i;
+	unsigned long flags;
 
 #define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000
 #define OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000
@@ -445,24 +454,30 @@
 #define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF
 
 	value = interval & OPEN_RETRY_INTERVAL_REG_MASK;
+	spin_lock_irqsave(&pm8001_ha->lock, flags);
 	/* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/
-	if (-1 == bar4_shift(pm8001_ha,
-			     OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR))
+	if (-1 == pm8001_bar4_shift(pm8001_ha,
+			     OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR)) {
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 		return;
+	}
 	for (i = 0; i < 4; i++) {
 		offset = OPEN_RETRY_INTERVAL_PHY_0_3_OFFSET + 0x4000 * i;
 		pm8001_cw32(pm8001_ha, 2, offset, value);
 	}
 
-	if (-1 == bar4_shift(pm8001_ha,
-			     OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR))
+	if (-1 == pm8001_bar4_shift(pm8001_ha,
+			     OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR)) {
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 		return;
+	}
 	for (i = 4; i < 8; i++) {
 		offset = OPEN_RETRY_INTERVAL_PHY_4_7_OFFSET + 0x4000 * (i-4);
 		pm8001_cw32(pm8001_ha, 2, offset, value);
 	}
 	/*set the shifted destination address to 0x0 to avoid error operation */
-	bar4_shift(pm8001_ha, 0x0);
+	pm8001_bar4_shift(pm8001_ha, 0x0);
+	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 	return;
 }
 
@@ -607,7 +622,8 @@
 	update_inbnd_queue_table(pm8001_ha, 0);
 	update_outbnd_queue_table(pm8001_ha, 0);
 	mpi_set_phys_g3_with_ssc(pm8001_ha, 0);
-	mpi_set_open_retry_interval_reg(pm8001_ha, 7);
+	/* 7->130ms, 34->500ms, 119->1.5s */
+	mpi_set_open_retry_interval_reg(pm8001_ha, 119);
 	/* notify firmware update finished and check initialization status */
 	if (0 == mpi_init_check(pm8001_ha)) {
 		PM8001_INIT_DBG(pm8001_ha,
@@ -688,8 +704,11 @@
 		PM8001_INIT_DBG(pm8001_ha,
 			pm8001_printk("Firmware is ready for reset .\n"));
 	} else {
-	/* Trigger NMI twice via RB6 */
-		if (-1 == bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
+		unsigned long flags;
+		/* Trigger NMI twice via RB6 */
+		spin_lock_irqsave(&pm8001_ha->lock, flags);
+		if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 			PM8001_FAIL_DBG(pm8001_ha,
 				pm8001_printk("Shift Bar4 to 0x%x failed\n",
 					RB6_ACCESS_REG));
@@ -715,8 +734,10 @@
 			PM8001_FAIL_DBG(pm8001_ha,
 				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
 				pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 			return -1;
 		}
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 	}
 	return 0;
 }
@@ -733,6 +754,7 @@
 	u32	regVal, toggleVal;
 	u32	max_wait_count;
 	u32	regVal1, regVal2, regVal3;
+	unsigned long flags;
 
 	/* step1: Check FW is ready for soft reset */
 	if (soft_reset_ready_check(pm8001_ha) != 0) {
@@ -743,7 +765,9 @@
 	/* step 2: clear NMI status register on AAP1 and IOP, write the same
 	value to clear */
 	/* map 0x60000 to BAR4(0x20), BAR2(win) */
-	if (-1 == bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
+	spin_lock_irqsave(&pm8001_ha->lock, flags);
+	if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 		PM8001_FAIL_DBG(pm8001_ha,
 			pm8001_printk("Shift Bar4 to 0x%x failed\n",
 			MBIC_AAP1_ADDR_BASE));
@@ -754,7 +778,8 @@
 		pm8001_printk("MBIC - NMI Enable VPE0 (IOP)= 0x%x\n", regVal));
 	pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0);
 	/* map 0x70000 to BAR4(0x20), BAR2(win) */
-	if (-1 == bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
+	if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 		PM8001_FAIL_DBG(pm8001_ha,
 			pm8001_printk("Shift Bar4 to 0x%x failed\n",
 			MBIC_IOP_ADDR_BASE));
@@ -796,7 +821,8 @@
 
 	/* read required registers for confirmming */
 	/* map 0x0700000 to BAR4(0x20), BAR2(win) */
-	if (-1 == bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
+	if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 		PM8001_FAIL_DBG(pm8001_ha,
 			pm8001_printk("Shift Bar4 to 0x%x failed\n",
 			GSM_ADDR_BASE));
@@ -862,7 +888,8 @@
 	/* step 5: delay 10 usec */
 	udelay(10);
 	/* step 5-b: set GPIO-0 output control to tristate anyway */
-	if (-1 == bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
+	if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 		PM8001_INIT_DBG(pm8001_ha,
 				pm8001_printk("Shift Bar4 to 0x%x failed\n",
 				GPIO_ADDR_BASE));
@@ -878,7 +905,8 @@
 
 	/* Step 6: Reset the IOP and AAP1 */
 	/* map 0x00000 to BAR4(0x20), BAR2(win) */
-	if (-1 == bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
+	if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 		PM8001_FAIL_DBG(pm8001_ha,
 			pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
 			SPC_TOP_LEVEL_ADDR_BASE));
@@ -915,7 +943,8 @@
 
 	/* step 11: reads and sets the GSM Configuration and Reset Register */
 	/* map 0x0700000 to BAR4(0x20), BAR2(win) */
-	if (-1 == bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
+	if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 		PM8001_FAIL_DBG(pm8001_ha,
 			pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
 			GSM_ADDR_BASE));
@@ -968,7 +997,8 @@
 
 	/* step 13: bring the IOP and AAP1 out of reset */
 	/* map 0x00000 to BAR4(0x20), BAR2(win) */
-	if (-1 == bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
+	if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 		PM8001_FAIL_DBG(pm8001_ha,
 			pm8001_printk("Shift Bar4 to 0x%x failed\n",
 			SPC_TOP_LEVEL_ADDR_BASE));
@@ -1010,6 +1040,7 @@
 				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
 				pm8001_cr32(pm8001_ha, 0,
 				MSGU_SCRATCH_PAD_3)));
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 			return -1;
 		}
 
@@ -1039,9 +1070,12 @@
 				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
 				pm8001_cr32(pm8001_ha, 0,
 				MSGU_SCRATCH_PAD_3)));
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 			return -1;
 		}
 	}
+	pm8001_bar4_shift(pm8001_ha, 0);
+	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 
 	PM8001_INIT_DBG(pm8001_ha,
 		pm8001_printk("SPC soft reset Complete\n"));
@@ -1157,8 +1191,8 @@
 	msi_index = int_vec_idx * MSIX_TABLE_ELEMENT_SIZE;
 	msi_index += MSIX_TABLE_BASE;
 	pm8001_cw32(pm8001_ha, 0,  msi_index, MSIX_INTERRUPT_DISABLE);
-
 }
+
 /**
  * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt
  * @pm8001_ha: our hba card information
@@ -1212,7 +1246,7 @@
 	consumer_index = pm8001_read_32(circularQ->ci_virt);
 	circularQ->consumer_index = cpu_to_le32(consumer_index);
 	if (((circularQ->producer_idx + bcCount) % 256) ==
-		circularQ->consumer_index) {
+		le32_to_cpu(circularQ->consumer_index)) {
 		*messagePtr = NULL;
 		return -1;
 	}
@@ -1321,7 +1355,8 @@
 	u32 header_tmp;
 	do {
 		/* If there are not-yet-delivered messages ... */
-		if (circularQ->producer_index != circularQ->consumer_idx) {
+		if (le32_to_cpu(circularQ->producer_index)
+			!= circularQ->consumer_idx) {
 			/*Get the pointer to the circular queue buffer element*/
 			msgHeader = (struct mpi_msg_hdr *)
 				(circularQ->base_virt +
@@ -1329,14 +1364,14 @@
 			/* read header */
 			header_tmp = pm8001_read_32(msgHeader);
 			msgHeader_tmp = cpu_to_le32(header_tmp);
-			if (0 != (msgHeader_tmp & 0x80000000)) {
+			if (0 != (le32_to_cpu(msgHeader_tmp) & 0x80000000)) {
 				if (OPC_OUB_SKIP_ENTRY !=
-					(msgHeader_tmp & 0xfff)) {
+					(le32_to_cpu(msgHeader_tmp) & 0xfff)) {
 					*messagePtr1 =
 						((u8 *)msgHeader) +
 						sizeof(struct mpi_msg_hdr);
-					*pBC = (u8)((msgHeader_tmp >> 24) &
-						0x1f);
+					*pBC = (u8)((le32_to_cpu(msgHeader_tmp)
+						>> 24) & 0x1f);
 					PM8001_IO_DBG(pm8001_ha,
 						pm8001_printk(": CI=%d PI=%d "
 						"msgHeader=%x\n",
@@ -1347,8 +1382,8 @@
 				} else {
 					circularQ->consumer_idx =
 						(circularQ->consumer_idx +
-						((msgHeader_tmp >> 24) & 0x1f))
-						% 256;
+						((le32_to_cpu(msgHeader_tmp)
+						>> 24) & 0x1f)) % 256;
 					msgHeader_tmp = 0;
 					pm8001_write_32(msgHeader, 0, 0);
 					/* update the CI of outbound queue */
@@ -1360,7 +1395,8 @@
 			} else {
 				circularQ->consumer_idx =
 					(circularQ->consumer_idx +
-					((msgHeader_tmp >> 24) & 0x1f)) % 256;
+					((le32_to_cpu(msgHeader_tmp) >> 24) &
+					0x1f)) % 256;
 				msgHeader_tmp = 0;
 				pm8001_write_32(msgHeader, 0, 0);
 				/* update the CI of outbound queue */
@@ -1376,7 +1412,8 @@
 			producer_index = pm8001_read_32(pi_virt);
 			circularQ->producer_index = cpu_to_le32(producer_index);
 		}
-	} while (circularQ->producer_index != circularQ->consumer_idx);
+	} while (le32_to_cpu(circularQ->producer_index) !=
+		circularQ->consumer_idx);
 	/* while we don't have any more not-yet-delivered message */
 	/* report empty */
 	return MPI_IO_STATUS_BUSY;
@@ -1388,24 +1425,191 @@
 	struct pm8001_device *pm8001_dev;
 	struct domain_device *dev;
 
+	/*
+	 * So far, all users of this stash an associated structure here.
+	 * If we get here, and this pointer is null, then the action
+	 * was cancelled. This nullification happens when the device
+	 * goes away.
+	 */
+	pm8001_dev = pw->data; /* Most stash device structure */
+	if ((pm8001_dev == NULL)
+	 || ((pw->handler != IO_XFER_ERROR_BREAK)
+	  && (pm8001_dev->dev_type == NO_DEVICE))) {
+		kfree(pw);
+		return;
+	}
+
 	switch (pw->handler) {
+	case IO_XFER_ERROR_BREAK:
+	{	/* This one stashes the sas_task instead */
+		struct sas_task *t = (struct sas_task *)pm8001_dev;
+		u32 tag;
+		struct pm8001_ccb_info *ccb;
+		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
+		unsigned long flags, flags1;
+		struct task_status_struct *ts;
+		int i;
+
+		if (pm8001_query_task(t) == TMF_RESP_FUNC_SUCC)
+			break; /* Task still on lu */
+		spin_lock_irqsave(&pm8001_ha->lock, flags);
+
+		spin_lock_irqsave(&t->task_state_lock, flags1);
+		if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
+			spin_unlock_irqrestore(&t->task_state_lock, flags1);
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			break; /* Task got completed by another */
+		}
+		spin_unlock_irqrestore(&t->task_state_lock, flags1);
+
+		/* Search for a possible ccb that matches the task */
+		for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
+			ccb = &pm8001_ha->ccb_info[i];
+			tag = ccb->ccb_tag;
+			if ((tag != 0xFFFFFFFF) && (ccb->task == t))
+				break;
+		}
+		if (!ccb) {
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			break; /* Task got freed by another */
+		}
+		ts = &t->task_status;
+		ts->resp = SAS_TASK_COMPLETE;
+		/* Force the midlayer to retry */
+		ts->stat = SAS_QUEUE_FULL;
+		pm8001_dev = ccb->device;
+		if (pm8001_dev)
+			pm8001_dev->running_req--;
+		spin_lock_irqsave(&t->task_state_lock, flags1);
+		t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
+		t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
+		t->task_state_flags |= SAS_TASK_STATE_DONE;
+		if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
+			spin_unlock_irqrestore(&t->task_state_lock, flags1);
+			PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("task 0x%p"
+				" done with event 0x%x resp 0x%x stat 0x%x but"
+				" aborted by upper layer!\n",
+				t, pw->handler, ts->resp, ts->stat));
+			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&t->task_state_lock, flags1);
+			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+			mb();/* in order to force CPU ordering */
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			t->task_done(t);
+		}
+	}	break;
+	case IO_XFER_OPEN_RETRY_TIMEOUT:
+	{	/* This one stashes the sas_task instead */
+		struct sas_task *t = (struct sas_task *)pm8001_dev;
+		u32 tag;
+		struct pm8001_ccb_info *ccb;
+		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
+		unsigned long flags, flags1;
+		int i, ret = 0;
+
+		PM8001_IO_DBG(pm8001_ha,
+			pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n"));
+
+		ret = pm8001_query_task(t);
+
+		PM8001_IO_DBG(pm8001_ha,
+			switch (ret) {
+			case TMF_RESP_FUNC_SUCC:
+				pm8001_printk("...Task on lu\n");
+				break;
+
+			case TMF_RESP_FUNC_COMPLETE:
+				pm8001_printk("...Task NOT on lu\n");
+				break;
+
+			default:
+				pm8001_printk("...query task failed!!!\n");
+				break;
+			});
+
+		spin_lock_irqsave(&pm8001_ha->lock, flags);
+
+		spin_lock_irqsave(&t->task_state_lock, flags1);
+
+		if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
+			spin_unlock_irqrestore(&t->task_state_lock, flags1);
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
+				(void)pm8001_abort_task(t);
+			break; /* Task got completed by another */
+		}
+
+		spin_unlock_irqrestore(&t->task_state_lock, flags1);
+
+		/* Search for a possible ccb that matches the task */
+		for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
+			ccb = &pm8001_ha->ccb_info[i];
+			tag = ccb->ccb_tag;
+			if ((tag != 0xFFFFFFFF) && (ccb->task == t))
+				break;
+		}
+		if (!ccb) {
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
+				(void)pm8001_abort_task(t);
+			break; /* Task got freed by another */
+		}
+
+		pm8001_dev = ccb->device;
+		dev = pm8001_dev->sas_device;
+
+		switch (ret) {
+		case TMF_RESP_FUNC_SUCC: /* task on lu */
+			ccb->open_retry = 1; /* Snub completion */
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			ret = pm8001_abort_task(t);
+			ccb->open_retry = 0;
+			switch (ret) {
+			case TMF_RESP_FUNC_SUCC:
+			case TMF_RESP_FUNC_COMPLETE:
+				break;
+			default: /* device misbehavior */
+				ret = TMF_RESP_FUNC_FAILED;
+				PM8001_IO_DBG(pm8001_ha,
+					pm8001_printk("...Reset phy\n"));
+				pm8001_I_T_nexus_reset(dev);
+				break;
+			}
+			break;
+
+		case TMF_RESP_FUNC_COMPLETE: /* task not on lu */
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			/* Do we need to abort the task locally? */
+			break;
+
+		default: /* device misbehavior */
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			ret = TMF_RESP_FUNC_FAILED;
+			PM8001_IO_DBG(pm8001_ha,
+				pm8001_printk("...Reset phy\n"));
+			pm8001_I_T_nexus_reset(dev);
+		}
+
+		if (ret == TMF_RESP_FUNC_FAILED)
+			t = NULL;
+		pm8001_open_reject_retry(pm8001_ha, t, pm8001_dev);
+		PM8001_IO_DBG(pm8001_ha, pm8001_printk("...Complete\n"));
+	}	break;
 	case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
-		pm8001_dev = pw->data;
 		dev = pm8001_dev->sas_device;
 		pm8001_I_T_nexus_reset(dev);
 		break;
 	case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY:
-		pm8001_dev = pw->data;
 		dev = pm8001_dev->sas_device;
 		pm8001_I_T_nexus_reset(dev);
 		break;
 	case IO_DS_IN_ERROR:
-		pm8001_dev = pw->data;
 		dev = pm8001_dev->sas_device;
 		pm8001_I_T_nexus_reset(dev);
 		break;
 	case IO_DS_NON_OPERATIONAL:
-		pm8001_dev = pw->data;
 		dev = pm8001_dev->sas_device;
 		pm8001_I_T_nexus_reset(dev);
 		break;
@@ -1460,6 +1664,11 @@
 	status = le32_to_cpu(psspPayload->status);
 	tag = le32_to_cpu(psspPayload->tag);
 	ccb = &pm8001_ha->ccb_info[tag];
+	if ((status == IO_ABORTED) && ccb->open_retry) {
+		/* Being completed by another */
+		ccb->open_retry = 0;
+		return;
+	}
 	pm8001_dev = ccb->device;
 	param = le32_to_cpu(psspPayload->param);
 
@@ -1515,6 +1724,8 @@
 			pm8001_printk("IO_XFER_ERROR_BREAK\n"));
 		ts->resp = SAS_TASK_COMPLETE;
 		ts->stat = SAS_OPEN_REJECT;
+		/* Force the midlayer to retry */
+		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
 		break;
 	case IO_XFER_ERROR_PHY_NOT_READY:
 		PM8001_IO_DBG(pm8001_ha,
@@ -1719,9 +1930,8 @@
 	case IO_XFER_ERROR_BREAK:
 		PM8001_IO_DBG(pm8001_ha,
 			pm8001_printk("IO_XFER_ERROR_BREAK\n"));
-		ts->resp = SAS_TASK_COMPLETE;
-		ts->stat = SAS_INTERRUPTED;
-		break;
+		pm8001_handle_event(pm8001_ha, t, IO_XFER_ERROR_BREAK);
+		return;
 	case IO_XFER_ERROR_PHY_NOT_READY:
 		PM8001_IO_DBG(pm8001_ha,
 			pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n"));
@@ -1800,10 +2010,8 @@
 	case IO_XFER_OPEN_RETRY_TIMEOUT:
 		PM8001_IO_DBG(pm8001_ha,
 			pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n"));
-		ts->resp = SAS_TASK_COMPLETE;
-		ts->stat = SAS_OPEN_REJECT;
-		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
-		break;
+		pm8001_handle_event(pm8001_ha, t, IO_XFER_OPEN_RETRY_TIMEOUT);
+		return;
 	case IO_XFER_ERROR_UNEXPECTED_PHASE:
 		PM8001_IO_DBG(pm8001_ha,
 			pm8001_printk("IO_XFER_ERROR_UNEXPECTED_PHASE\n"));
@@ -1877,7 +2085,6 @@
 {
 	struct sas_task *t;
 	struct pm8001_ccb_info *ccb;
-	unsigned long flags = 0;
 	u32 param;
 	u32 status;
 	u32 tag;
@@ -1886,6 +2093,7 @@
 	struct ata_task_resp *resp ;
 	u32 *sata_resp;
 	struct pm8001_device *pm8001_dev;
+	unsigned long flags;
 
 	psataPayload = (struct sata_completion_resp *)(piomb + 4);
 	status = le32_to_cpu(psataPayload->status);
@@ -2016,9 +2224,9 @@
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/*in order to force CPU ordering*/
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irq(&pm8001_ha->lock);
 			t->task_done(t);
-			spin_lock_irqsave(&pm8001_ha->lock, flags);
+			spin_lock_irq(&pm8001_ha->lock);
 			return;
 		}
 		break;
@@ -2036,9 +2244,9 @@
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/*ditto*/
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irq(&pm8001_ha->lock);
 			t->task_done(t);
-			spin_lock_irqsave(&pm8001_ha->lock, flags);
+			spin_lock_irq(&pm8001_ha->lock);
 			return;
 		}
 		break;
@@ -2064,9 +2272,9 @@
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/* ditto*/
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irq(&pm8001_ha->lock);
 			t->task_done(t);
-			spin_lock_irqsave(&pm8001_ha->lock, flags);
+			spin_lock_irq(&pm8001_ha->lock);
 			return;
 		}
 		break;
@@ -2131,9 +2339,9 @@
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/*ditto*/
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irq(&pm8001_ha->lock);
 			t->task_done(t);
-			spin_lock_irqsave(&pm8001_ha->lock, flags);
+			spin_lock_irq(&pm8001_ha->lock);
 			return;
 		}
 		break;
@@ -2155,9 +2363,9 @@
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/*ditto*/
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irq(&pm8001_ha->lock);
 			t->task_done(t);
-			spin_lock_irqsave(&pm8001_ha->lock, flags);
+			spin_lock_irq(&pm8001_ha->lock);
 			return;
 		}
 		break;
@@ -2190,16 +2398,16 @@
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 		mb();/* ditto */
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irq(&pm8001_ha->lock);
 		t->task_done(t);
-		spin_lock_irqsave(&pm8001_ha->lock, flags);
+		spin_lock_irq(&pm8001_ha->lock);
 	} else if (!t->uldd_task) {
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 		mb();/*ditto*/
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irq(&pm8001_ha->lock);
 		t->task_done(t);
-		spin_lock_irqsave(&pm8001_ha->lock, flags);
+		spin_lock_irq(&pm8001_ha->lock);
 	}
 }
 
@@ -2207,7 +2415,6 @@
 static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
 {
 	struct sas_task *t;
-	unsigned long flags = 0;
 	struct task_status_struct *ts;
 	struct pm8001_ccb_info *ccb;
 	struct pm8001_device *pm8001_dev;
@@ -2217,6 +2424,7 @@
 	u32 tag = le32_to_cpu(psataPayload->tag);
 	u32 port_id = le32_to_cpu(psataPayload->port_id);
 	u32 dev_id = le32_to_cpu(psataPayload->device_id);
+	unsigned long flags;
 
 	ccb = &pm8001_ha->ccb_info[tag];
 	t = ccb->task;
@@ -2287,9 +2495,9 @@
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/*ditto*/
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irq(&pm8001_ha->lock);
 			t->task_done(t);
-			spin_lock_irqsave(&pm8001_ha->lock, flags);
+			spin_lock_irq(&pm8001_ha->lock);
 			return;
 		}
 		break;
@@ -2402,16 +2610,16 @@
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 		mb();/* ditto */
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irq(&pm8001_ha->lock);
 		t->task_done(t);
-		spin_lock_irqsave(&pm8001_ha->lock, flags);
+		spin_lock_irq(&pm8001_ha->lock);
 	} else if (!t->uldd_task) {
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 		mb();/*ditto*/
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irq(&pm8001_ha->lock);
 		t->task_done(t);
-		spin_lock_irqsave(&pm8001_ha->lock, flags);
+		spin_lock_irq(&pm8001_ha->lock);
 	}
 }
 
@@ -2857,7 +3065,7 @@
 
 	memset((u8 *)&payload, 0, sizeof(payload));
 	circularQ = &pm8001_ha->inbnd_q_tbl[Qnum];
-	payload.tag = 1;
+	payload.tag = cpu_to_le32(1);
 	payload.sea_phyid_portid = cpu_to_le32(((SEA & 0xFFFF) << 8) |
 		((phyId & 0x0F) << 4) | (port_id & 0x0F));
 	payload.param0 = cpu_to_le32(param0);
@@ -2929,9 +3137,9 @@
 	phy->phy_type |= PORT_TYPE_SAS;
 	phy->identify.device_type = deviceType;
 	phy->phy_attached = 1;
-	if (phy->identify.device_type == SAS_END_DEV)
+	if (phy->identify.device_type == SAS_END_DEVICE)
 		phy->identify.target_port_protocols = SAS_PROTOCOL_SSP;
-	else if (phy->identify.device_type != NO_DEVICE)
+	else if (phy->identify.device_type != SAS_PHY_UNUSED)
 		phy->identify.target_port_protocols = SAS_PROTOCOL_SMP;
 	phy->sas_phy.oob_mode = SAS_OOB_MODE;
 	sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE);
@@ -3075,7 +3283,7 @@
 		(struct dev_reg_resp *)(piomb + 4);
 
 	htag = le32_to_cpu(registerRespPayload->tag);
-	ccb = &pm8001_ha->ccb_info[registerRespPayload->tag];
+	ccb = &pm8001_ha->ccb_info[htag];
 	pm8001_dev = ccb->device;
 	status = le32_to_cpu(registerRespPayload->status);
 	device_id = le32_to_cpu(registerRespPayload->device_id);
@@ -3149,7 +3357,7 @@
 	struct fw_control_ex	fw_control_context;
 	struct fw_flash_Update_resp *ppayload =
 		(struct fw_flash_Update_resp *)(piomb + 4);
-	u32 tag = le32_to_cpu(ppayload->tag);
+	u32 tag = ppayload->tag;
 	struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
 	status = le32_to_cpu(ppayload->status);
 	memcpy(&fw_control_context,
@@ -3238,13 +3446,12 @@
 
 	struct task_abort_resp *pPayload =
 		(struct task_abort_resp *)(piomb + 4);
-	ccb = &pm8001_ha->ccb_info[pPayload->tag];
-	t = ccb->task;
-
 
 	status = le32_to_cpu(pPayload->status);
 	tag = le32_to_cpu(pPayload->tag);
 	scp = le32_to_cpu(pPayload->scp);
+	ccb = &pm8001_ha->ccb_info[tag];
+	t = ccb->task;
 	PM8001_IO_DBG(pm8001_ha,
 		pm8001_printk(" status = 0x%x\n", status));
 	if (t == NULL)
@@ -3270,7 +3477,7 @@
 	t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
 	t->task_state_flags |= SAS_TASK_STATE_DONE;
 	spin_unlock_irqrestore(&t->task_state_lock, flags);
-	pm8001_ccb_task_free(pm8001_ha, t, ccb, pPayload->tag);
+	pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 	mb();
 	t->task_done(t);
 	return 0;
@@ -3497,7 +3704,7 @@
 static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
 {
 	u32 pHeader = (u32)*(u32 *)piomb;
-	u8 opc = (u8)((le32_to_cpu(pHeader)) & 0xFFF);
+	u8 opc = (u8)(pHeader & 0xFFF);
 
 	PM8001_MSG_DBG(pm8001_ha, pm8001_printk("process_one_iomb:"));
 
@@ -3664,9 +3871,11 @@
 {
 	struct outbound_queue_table *circularQ;
 	void *pMsg1 = NULL;
-	u8 bc = 0;
+	u8 uninitialized_var(bc);
 	u32 ret = MPI_IO_STATUS_FAIL;
+	unsigned long flags;
 
+	spin_lock_irqsave(&pm8001_ha->lock, flags);
 	circularQ = &pm8001_ha->outbnd_q_tbl[0];
 	do {
 		ret = mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
@@ -3677,16 +3886,16 @@
 			mpi_msg_free_set(pm8001_ha, pMsg1, circularQ, bc);
 		}
 		if (MPI_IO_STATUS_BUSY == ret) {
-			u32 producer_idx;
 			/* Update the producer index from SPC */
-			producer_idx = pm8001_read_32(circularQ->pi_virt);
-			circularQ->producer_index = cpu_to_le32(producer_idx);
-			if (circularQ->producer_index ==
+			circularQ->producer_index =
+				cpu_to_le32(pm8001_read_32(circularQ->pi_virt));
+			if (le32_to_cpu(circularQ->producer_index) ==
 				circularQ->consumer_idx)
 				/* OQ is empty */
 				break;
 		}
 	} while (1);
+	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 	return ret;
 }
 
@@ -3712,9 +3921,9 @@
 	}
 }
 
-static void build_smp_cmd(u32 deviceID, u32 hTag, struct smp_req *psmp_cmd)
+static void build_smp_cmd(u32 deviceID, __le32 hTag, struct smp_req *psmp_cmd)
 {
-	psmp_cmd->tag = cpu_to_le32(hTag);
+	psmp_cmd->tag = hTag;
 	psmp_cmd->device_id = cpu_to_le32(deviceID);
 	psmp_cmd->len_ip_ir = cpu_to_le32(1|(1 << 1));
 }
@@ -3798,7 +4007,7 @@
 	struct ssp_ini_io_start_req ssp_cmd;
 	u32 tag = ccb->ccb_tag;
 	int ret;
-	__le64 phys_addr;
+	u64 phys_addr;
 	struct inbound_queue_table *circularQ;
 	u32 opc = OPC_INB_SSPINIIOSTART;
 	memset(&ssp_cmd, 0, sizeof(ssp_cmd));
@@ -3819,15 +4028,15 @@
 	/* fill in PRD (scatter/gather) table, if any */
 	if (task->num_scatter > 1) {
 		pm8001_chip_make_sg(task->scatter, ccb->n_elem, ccb->buf_prd);
-		phys_addr = cpu_to_le64(ccb->ccb_dma_handle +
-				offsetof(struct pm8001_ccb_info, buf_prd[0]));
-		ssp_cmd.addr_low = lower_32_bits(phys_addr);
-		ssp_cmd.addr_high = upper_32_bits(phys_addr);
+		phys_addr = ccb->ccb_dma_handle +
+				offsetof(struct pm8001_ccb_info, buf_prd[0]);
+		ssp_cmd.addr_low = cpu_to_le32(lower_32_bits(phys_addr));
+		ssp_cmd.addr_high = cpu_to_le32(upper_32_bits(phys_addr));
 		ssp_cmd.esgl = cpu_to_le32(1<<31);
 	} else if (task->num_scatter == 1) {
-		__le64 dma_addr = cpu_to_le64(sg_dma_address(task->scatter));
-		ssp_cmd.addr_low = lower_32_bits(dma_addr);
-		ssp_cmd.addr_high = upper_32_bits(dma_addr);
+		u64 dma_addr = sg_dma_address(task->scatter);
+		ssp_cmd.addr_low = cpu_to_le32(lower_32_bits(dma_addr));
+		ssp_cmd.addr_high = cpu_to_le32(upper_32_bits(dma_addr));
 		ssp_cmd.len = cpu_to_le32(task->total_xfer_len);
 		ssp_cmd.esgl = 0;
 	} else if (task->num_scatter == 0) {
@@ -3850,7 +4059,7 @@
 	int ret;
 	struct sata_start_req sata_cmd;
 	u32 hdr_tag, ncg_tag = 0;
-	__le64 phys_addr;
+	u64 phys_addr;
 	u32 ATAP = 0x0;
 	u32 dir;
 	struct inbound_queue_table *circularQ;
@@ -3889,13 +4098,13 @@
 	/* fill in PRD (scatter/gather) table, if any */
 	if (task->num_scatter > 1) {
 		pm8001_chip_make_sg(task->scatter, ccb->n_elem, ccb->buf_prd);
-		phys_addr = cpu_to_le64(ccb->ccb_dma_handle +
-				offsetof(struct pm8001_ccb_info, buf_prd[0]));
+		phys_addr = ccb->ccb_dma_handle +
+				offsetof(struct pm8001_ccb_info, buf_prd[0]);
 		sata_cmd.addr_low = lower_32_bits(phys_addr);
 		sata_cmd.addr_high = upper_32_bits(phys_addr);
 		sata_cmd.esgl = cpu_to_le32(1 << 31);
 	} else if (task->num_scatter == 1) {
-		__le64 dma_addr = cpu_to_le64(sg_dma_address(task->scatter));
+		u64 dma_addr = sg_dma_address(task->scatter);
 		sata_cmd.addr_low = lower_32_bits(dma_addr);
 		sata_cmd.addr_high = upper_32_bits(dma_addr);
 		sata_cmd.len = cpu_to_le32(task->total_xfer_len);
@@ -4039,7 +4248,7 @@
 
 	circularQ = &pm8001_ha->inbnd_q_tbl[0];
 	memset(&payload, 0, sizeof(payload));
-	payload.tag = 1;
+	payload.tag = cpu_to_le32(1);
 	payload.device_id = cpu_to_le32(device_id);
 	PM8001_MSG_DBG(pm8001_ha,
 		pm8001_printk("unregister device device_id = %d\n", device_id));
@@ -4063,7 +4272,7 @@
 	u32 opc = OPC_INB_LOCAL_PHY_CONTROL;
 	memset(&payload, 0, sizeof(payload));
 	circularQ = &pm8001_ha->inbnd_q_tbl[0];
-	payload.tag = 1;
+	payload.tag = cpu_to_le32(1);
 	payload.phyop_phyid =
 		cpu_to_le32(((phy_op & 0xff) << 8) | (phyId & 0x0F));
 	ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload);
@@ -4092,12 +4301,9 @@
 static irqreturn_t
 pm8001_chip_isr(struct pm8001_hba_info *pm8001_ha)
 {
-	unsigned long flags;
-	spin_lock_irqsave(&pm8001_ha->lock, flags);
 	pm8001_chip_interrupt_disable(pm8001_ha);
 	process_oq(pm8001_ha);
 	pm8001_chip_interrupt_enable(pm8001_ha);
-	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 	return IRQ_HANDLED;
 }
 
@@ -4360,8 +4566,10 @@
 	payload.cur_image_offset = cpu_to_le32(info->cur_image_offset);
 	payload.total_image_len = cpu_to_le32(info->total_image_len);
 	payload.len = info->sgl.im_len.len ;
-	payload.sgl_addr_lo = lower_32_bits(info->sgl.addr);
-	payload.sgl_addr_hi = upper_32_bits(info->sgl.addr);
+	payload.sgl_addr_lo =
+		cpu_to_le32(lower_32_bits(le64_to_cpu(info->sgl.addr)));
+	payload.sgl_addr_hi =
+		cpu_to_le32(upper_32_bits(le64_to_cpu(info->sgl.addr)));
 	ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload);
 	return ret;
 }
diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h
index 9091320..1a4611e 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.h
+++ b/drivers/scsi/pm8001/pm8001_hwi.h
@@ -625,7 +625,7 @@
 	__le32	tag;
 	__le32	len_ir_vpdd;
 	__le32	vpd_offset;
-	u32	reserved[8];
+	__le32	reserved[8];
 	__le32	resp_addr_lo;
 	__le32	resp_addr_hi;
 	__le32	resp_len;
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index c21a216..36efaa7 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -62,7 +62,6 @@
 	.queuecommand		= sas_queuecommand,
 	.target_alloc		= sas_target_alloc,
 	.slave_configure	= sas_slave_configure,
-	.slave_destroy		= sas_slave_destroy,
 	.scan_finished		= pm8001_scan_finished,
 	.scan_start		= pm8001_scan_start,
 	.change_queue_depth	= sas_change_queue_depth,
@@ -76,7 +75,6 @@
 	.use_clustering		= ENABLE_CLUSTERING,
 	.eh_device_reset_handler = sas_eh_device_reset_handler,
 	.eh_bus_reset_handler	= sas_eh_bus_reset_handler,
-	.slave_alloc		= sas_slave_alloc,
 	.target_destroy		= sas_target_destroy,
 	.ioctl			= sas_ioctl,
 	.shost_attrs		= pm8001_host_attrs,
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index fb3dc99..3b11edd 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -166,6 +166,7 @@
 	struct pm8001_hba_info *pm8001_ha = NULL;
 	struct sas_phy_linkrates *rates;
 	DECLARE_COMPLETION_ONSTACK(completion);
+	unsigned long flags;
 	pm8001_ha = sas_phy->ha->lldd_ha;
 	pm8001_ha->phy[phy_id].enable_completion = &completion;
 	switch (func) {
@@ -209,8 +210,29 @@
 	case PHY_FUNC_DISABLE:
 		PM8001_CHIP_DISP->phy_stop_req(pm8001_ha, phy_id);
 		break;
+	case PHY_FUNC_GET_EVENTS:
+		spin_lock_irqsave(&pm8001_ha->lock, flags);
+		if (-1 == pm8001_bar4_shift(pm8001_ha,
+					(phy_id < 4) ? 0x30000 : 0x40000)) {
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			return -EINVAL;
+		}
+		{
+			struct sas_phy *phy = sas_phy->phy;
+			uint32_t *qp = (uint32_t *)(((char *)
+				pm8001_ha->io_mem[2].memvirtaddr)
+				+ 0x1034 + (0x4000 * (phy_id & 3)));
+
+			phy->invalid_dword_count = qp[0];
+			phy->running_disparity_error_count = qp[1];
+			phy->loss_of_dword_sync_count = qp[3];
+			phy->phy_reset_problem_count = qp[4];
+		}
+		pm8001_bar4_shift(pm8001_ha, 0);
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		return 0;
 	default:
-		rc = -ENOSYS;
+		rc = -EOPNOTSUPP;
 	}
 	msleep(300);
 	return rc;
@@ -234,12 +256,14 @@
 
 int pm8001_scan_finished(struct Scsi_Host *shost, unsigned long time)
 {
+	struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+
 	/* give the phy enabling interrupt event time to come in (1s
 	* is empirically about all it takes) */
 	if (time < HZ)
 		return 0;
 	/* Wait for discovery to finish */
-	scsi_flush_work(shost);
+	sas_drain_work(ha);
 	return 1;
 }
 
@@ -340,7 +364,7 @@
 	struct pm8001_ccb_info *ccb;
 	u32 tag = 0xdeadbeef, rc, n_elem = 0;
 	u32 n = num;
-	unsigned long flags = 0, flags_libsas = 0;
+	unsigned long flags = 0;
 
 	if (!dev->port) {
 		struct task_status_struct *tsm = &t->task_status;
@@ -364,11 +388,7 @@
 				ts->stat = SAS_PHY_DOWN;
 
 				spin_unlock_irqrestore(&pm8001_ha->lock, flags);
-				spin_unlock_irqrestore(dev->sata_dev.ap->lock,
-						flags_libsas);
 				t->task_done(t);
-				spin_lock_irqsave(dev->sata_dev.ap->lock,
-					flags_libsas);
 				spin_lock_irqsave(&pm8001_ha->lock, flags);
 				if (n > 1)
 					t = list_entry(t->list.next,
@@ -516,6 +536,7 @@
 	task->lldd_task = NULL;
 	ccb->task = NULL;
 	ccb->ccb_tag = 0xFFFFFFFF;
+	ccb->open_retry = 0;
 	pm8001_ccb_free(pm8001_ha, ccb_idx);
 }
 
@@ -615,7 +636,7 @@
 	wait_for_completion(&completion);
 	if (dev->dev_type == SAS_END_DEV)
 		msleep(50);
-	pm8001_ha->flags |= PM8001F_RUN_TIME ;
+	pm8001_ha->flags = PM8001F_RUN_TIME;
 	return 0;
 found_out:
 	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
@@ -860,6 +881,77 @@
 		tmf);
 }
 
+/* retry commands by ha, by task and/or by device */
+void pm8001_open_reject_retry(
+	struct pm8001_hba_info *pm8001_ha,
+	struct sas_task *task_to_close,
+	struct pm8001_device *device_to_close)
+{
+	int i;
+	unsigned long flags;
+
+	if (pm8001_ha == NULL)
+		return;
+
+	spin_lock_irqsave(&pm8001_ha->lock, flags);
+
+	for (i = 0; i < PM8001_MAX_CCB; i++) {
+		struct sas_task *task;
+		struct task_status_struct *ts;
+		struct pm8001_device *pm8001_dev;
+		unsigned long flags1;
+		u32 tag;
+		struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[i];
+
+		pm8001_dev = ccb->device;
+		if (!pm8001_dev || (pm8001_dev->dev_type == NO_DEVICE))
+			continue;
+		if (!device_to_close) {
+			uintptr_t d = (uintptr_t)pm8001_dev
+					- (uintptr_t)&pm8001_ha->devices;
+			if (((d % sizeof(*pm8001_dev)) != 0)
+			 || ((d / sizeof(*pm8001_dev)) >= PM8001_MAX_DEVICES))
+				continue;
+		} else if (pm8001_dev != device_to_close)
+			continue;
+		tag = ccb->ccb_tag;
+		if (!tag || (tag == 0xFFFFFFFF))
+			continue;
+		task = ccb->task;
+		if (!task || !task->task_done)
+			continue;
+		if (task_to_close && (task != task_to_close))
+			continue;
+		ts = &task->task_status;
+		ts->resp = SAS_TASK_COMPLETE;
+		/* Force the midlayer to retry */
+		ts->stat = SAS_OPEN_REJECT;
+		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+		if (pm8001_dev)
+			pm8001_dev->running_req--;
+		spin_lock_irqsave(&task->task_state_lock, flags1);
+		task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
+		task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
+		task->task_state_flags |= SAS_TASK_STATE_DONE;
+		if (unlikely((task->task_state_flags
+				& SAS_TASK_STATE_ABORTED))) {
+			spin_unlock_irqrestore(&task->task_state_lock,
+				flags1);
+			pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
+		} else {
+			spin_unlock_irqrestore(&task->task_state_lock,
+				flags1);
+			pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
+			mb();/* in order to force CPU ordering */
+			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			task->task_done(task);
+			spin_lock_irqsave(&pm8001_ha->lock, flags);
+		}
+	}
+
+	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+}
+
 /**
   * Standard mandates link reset for ATA  (type 0) and hard reset for
   * SSP (type 1) , only for RECOVERY
@@ -875,12 +967,14 @@
 
 	pm8001_dev = dev->lldd_dev;
 	pm8001_ha = pm8001_find_ha_by_dev(dev);
-	phy = sas_find_local_phy(dev);
+	phy = sas_get_local_phy(dev);
 
 	if (dev_is_sata(dev)) {
 		DECLARE_COMPLETION_ONSTACK(completion_setstate);
-		if (scsi_is_sas_phy_local(phy))
-			return 0;
+		if (scsi_is_sas_phy_local(phy)) {
+			rc = 0;
+			goto out;
+		}
 		rc = sas_phy_reset(phy, 1);
 		msleep(2000);
 		rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
@@ -889,12 +983,14 @@
 		rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha,
 			pm8001_dev, 0x01);
 		wait_for_completion(&completion_setstate);
-	} else{
-	rc = sas_phy_reset(phy, 1);
-	msleep(2000);
+	} else {
+		rc = sas_phy_reset(phy, 1);
+		msleep(2000);
 	}
 	PM8001_EH_DBG(pm8001_ha, pm8001_printk(" for device[%x]:rc=%d\n",
 		pm8001_dev->device_id, rc));
+ out:
+	sas_put_local_phy(phy);
 	return rc;
 }
 
@@ -906,10 +1002,11 @@
 	struct pm8001_device *pm8001_dev = dev->lldd_dev;
 	struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev);
 	if (dev_is_sata(dev)) {
-		struct sas_phy *phy = sas_find_local_phy(dev);
+		struct sas_phy *phy = sas_get_local_phy(dev);
 		rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
 			dev, 1, 0);
 		rc = sas_phy_reset(phy, 1);
+		sas_put_local_phy(phy);
 		rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha,
 			pm8001_dev, 0x01);
 		msleep(2000);
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 93959fe..1100820 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -235,6 +235,7 @@
 	struct pm8001_device	*device;
 	struct pm8001_prd	buf_prd[PM8001_MAX_DMA_SG];
 	struct fw_control_ex	*fw_control_context;
+	u8			open_retry;
 };
 
 struct mpi_mem {
@@ -484,10 +485,15 @@
 int pm8001_lu_reset(struct domain_device *dev, u8 *lun);
 int pm8001_I_T_nexus_reset(struct domain_device *dev);
 int pm8001_query_task(struct sas_task *task);
+void pm8001_open_reject_retry(
+	struct pm8001_hba_info *pm8001_ha,
+	struct sas_task *task_to_close,
+	struct pm8001_device *device_to_close);
 int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr,
 	dma_addr_t *pphys_addr, u32 *pphys_addr_hi, u32 *pphys_addr_lo,
 	u32 mem_size, u32 align);
 
+int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
 
 /* ctl shared API */
 extern struct device_attribute *pm8001_host_attrs[];
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index d838205..6c6486f 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -359,7 +359,6 @@
 #include <asm/byteorder.h>
 #include <asm/processor.h>
 #include <asm/types.h>
-#include <asm/system.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 9f41b3b..5926f5a 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -356,7 +356,8 @@
 		else if (start == (ha->flt_region_boot * 4) ||
 		    start == (ha->flt_region_fw * 4))
 			valid = 1;
-		else if (IS_QLA25XX(ha) || IS_QLA8XXX_TYPE(ha))
+		else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)
+			|| IS_CNA_CAPABLE(ha) || IS_QLA2031(ha))
 			valid = 1;
 		if (!valid) {
 			ql_log(ql_log_warn, vha, 0x7065,
@@ -627,144 +628,6 @@
 };
 
 static ssize_t
-qla2x00_sysfs_write_edc(struct file *filp, struct kobject *kobj,
-			struct bin_attribute *bin_attr,
-			char *buf, loff_t off, size_t count)
-{
-	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
-	    struct device, kobj)));
-	struct qla_hw_data *ha = vha->hw;
-	uint16_t dev, adr, opt, len;
-	int rval;
-
-	ha->edc_data_len = 0;
-
-	if (!capable(CAP_SYS_ADMIN) || off != 0 || count < 8)
-		return -EINVAL;
-
-	if (!ha->edc_data) {
-		ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
-		    &ha->edc_data_dma);
-		if (!ha->edc_data) {
-			ql_log(ql_log_warn, vha, 0x7073,
-			    "Unable to allocate memory for EDC write.\n");
-			return -ENOMEM;
-		}
-	}
-
-	dev = le16_to_cpup((void *)&buf[0]);
-	adr = le16_to_cpup((void *)&buf[2]);
-	opt = le16_to_cpup((void *)&buf[4]);
-	len = le16_to_cpup((void *)&buf[6]);
-
-	if (!(opt & BIT_0))
-		if (len == 0 || len > DMA_POOL_SIZE || len > count - 8)
-			return -EINVAL;
-
-	memcpy(ha->edc_data, &buf[8], len);
-
-	rval = qla2x00_write_sfp(vha, ha->edc_data_dma, ha->edc_data,
-	    dev, adr, len, opt);
-	if (rval != QLA_SUCCESS) {
-		ql_log(ql_log_warn, vha, 0x7074,
-		    "Unable to write EDC (%x) %02x:%04x:%02x:%02x:%02hhx\n",
-		    rval, dev, adr, opt, len, buf[8]);
-		return -EIO;
-	}
-
-	return count;
-}
-
-static struct bin_attribute sysfs_edc_attr = {
-	.attr = {
-		.name = "edc",
-		.mode = S_IWUSR,
-	},
-	.size = 0,
-	.write = qla2x00_sysfs_write_edc,
-};
-
-static ssize_t
-qla2x00_sysfs_write_edc_status(struct file *filp, struct kobject *kobj,
-			struct bin_attribute *bin_attr,
-			char *buf, loff_t off, size_t count)
-{
-	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
-	    struct device, kobj)));
-	struct qla_hw_data *ha = vha->hw;
-	uint16_t dev, adr, opt, len;
-	int rval;
-
-	ha->edc_data_len = 0;
-
-	if (!capable(CAP_SYS_ADMIN) || off != 0 || count < 8)
-		return -EINVAL;
-
-	if (!ha->edc_data) {
-		ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
-		    &ha->edc_data_dma);
-		if (!ha->edc_data) {
-			ql_log(ql_log_warn, vha, 0x708c,
-			    "Unable to allocate memory for EDC status.\n");
-			return -ENOMEM;
-		}
-	}
-
-	dev = le16_to_cpup((void *)&buf[0]);
-	adr = le16_to_cpup((void *)&buf[2]);
-	opt = le16_to_cpup((void *)&buf[4]);
-	len = le16_to_cpup((void *)&buf[6]);
-
-	if (!(opt & BIT_0))
-		if (len == 0 || len > DMA_POOL_SIZE)
-			return -EINVAL;
-
-	memset(ha->edc_data, 0, len);
-	rval = qla2x00_read_sfp(vha, ha->edc_data_dma, ha->edc_data,
-			dev, adr, len, opt);
-	if (rval != QLA_SUCCESS) {
-		ql_log(ql_log_info, vha, 0x7075,
-		    "Unable to write EDC status (%x) %02x:%04x:%02x:%02x.\n",
-		    rval, dev, adr, opt, len);
-		return -EIO;
-	}
-
-	ha->edc_data_len = len;
-
-	return count;
-}
-
-static ssize_t
-qla2x00_sysfs_read_edc_status(struct file *filp, struct kobject *kobj,
-			   struct bin_attribute *bin_attr,
-			   char *buf, loff_t off, size_t count)
-{
-	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
-	    struct device, kobj)));
-	struct qla_hw_data *ha = vha->hw;
-
-	if (!capable(CAP_SYS_ADMIN) || off != 0 || count == 0)
-		return 0;
-
-	if (!ha->edc_data || ha->edc_data_len == 0 || ha->edc_data_len > count)
-		return -EINVAL;
-
-	memcpy(buf, ha->edc_data, ha->edc_data_len);
-
-	return ha->edc_data_len;
-}
-
-static struct bin_attribute sysfs_edc_status_attr = {
-	.attr = {
-		.name = "edc_status",
-		.mode = S_IRUSR | S_IWUSR,
-	},
-	.size = 0,
-	.write = qla2x00_sysfs_write_edc_status,
-	.read = qla2x00_sysfs_read_edc_status,
-};
-
-static ssize_t
 qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
 		       struct bin_attribute *bin_attr,
 		       char *buf, loff_t off, size_t count)
@@ -879,8 +742,6 @@
 	{ "vpd", &sysfs_vpd_attr, 1 },
 	{ "sfp", &sysfs_sfp_attr, 1 },
 	{ "reset", &sysfs_reset_attr, },
-	{ "edc", &sysfs_edc_attr, 2 },
-	{ "edc_status", &sysfs_edc_status_attr, 2 },
 	{ "xgmac_stats", &sysfs_xgmac_stats_attr, 3 },
 	{ "dcbx_tlv", &sysfs_dcbx_tlv_attr, 3 },
 	{ NULL },
@@ -898,7 +759,7 @@
 			continue;
 		if (iter->is4GBp_only == 2 && !IS_QLA25XX(vha->hw))
 			continue;
-		if (iter->is4GBp_only == 3 && !(IS_QLA8XXX_TYPE(vha->hw)))
+		if (iter->is4GBp_only == 3 && !(IS_CNA_CAPABLE(vha->hw)))
 			continue;
 
 		ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
@@ -926,7 +787,7 @@
 			continue;
 		if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha))
 			continue;
-		if (iter->is4GBp_only == 3 && !!(IS_QLA8XXX_TYPE(vha->hw)))
+		if (iter->is4GBp_only == 3 && !(IS_CNA_CAPABLE(vha->hw)))
 			continue;
 
 		sysfs_remove_bin_file(&host->shost_gendev.kobj,
@@ -1231,7 +1092,7 @@
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA81XX(ha))
+	if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
 		return snprintf(buf, PAGE_SIZE, "\n");
 
 	return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%d)\n",
@@ -1278,7 +1139,7 @@
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA81XX(ha))
+	if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
 		return snprintf(buf, PAGE_SIZE, "\n");
 
 	return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
@@ -1293,7 +1154,7 @@
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA81XX(ha))
+	if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
 		return snprintf(buf, PAGE_SIZE, "\n");
 
 	return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n",
@@ -1316,7 +1177,7 @@
 {
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 
-	if (!IS_QLA8XXX_TYPE(vha->hw))
+	if (!IS_CNA_CAPABLE(vha->hw))
 		return snprintf(buf, PAGE_SIZE, "\n");
 
 	return snprintf(buf, PAGE_SIZE, "%d\n", vha->fcoe_vlan_id);
@@ -1328,7 +1189,7 @@
 {
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 
-	if (!IS_QLA8XXX_TYPE(vha->hw))
+	if (!IS_CNA_CAPABLE(vha->hw))
 		return snprintf(buf, PAGE_SIZE, "\n");
 
 	return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -1364,7 +1225,7 @@
 	else if (!vha->hw->flags.eeh_busy)
 		rval = qla2x00_get_thermal_temp(vha, &temp, &frac);
 	if (rval != QLA_SUCCESS)
-		temp = frac = 0;
+		return snprintf(buf, PAGE_SIZE, "\n");
 
 	return snprintf(buf, PAGE_SIZE, "%d.%02d\n", temp, frac);
 }
@@ -1493,6 +1354,9 @@
 	case PORT_SPEED_10GB:
 		speed = FC_PORTSPEED_10GBIT;
 		break;
+	case PORT_SPEED_16GB:
+		speed = FC_PORTSPEED_16GBIT;
+		break;
 	}
 	fc_host_speed(shost) = speed;
 }
@@ -1643,10 +1507,14 @@
 	 * final cleanup of firmware resources (PCBs and XCBs).
 	 */
 	if (fcport->loop_id != FC_NO_LOOP_ID &&
-	    !test_bit(UNLOADING, &fcport->vha->dpc_flags))
-		fcport->vha->hw->isp_ops->fabric_logout(fcport->vha,
-			fcport->loop_id, fcport->d_id.b.domain,
-			fcport->d_id.b.area, fcport->d_id.b.al_pa);
+	    !test_bit(UNLOADING, &fcport->vha->dpc_flags)) {
+		if (IS_FWI2_CAPABLE(fcport->vha->hw))
+			fcport->vha->hw->isp_ops->fabric_logout(fcport->vha,
+			    fcport->loop_id, fcport->d_id.b.domain,
+			    fcport->d_id.b.area, fcport->d_id.b.al_pa);
+		else
+			qla2x00_port_logout(fcport->vha, fcport);
+	}
 }
 
 static int
@@ -1889,6 +1757,7 @@
 			break;
 		}
 	}
+
 	if (qos) {
 		ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, 0,
 			qos);
@@ -2086,7 +1955,7 @@
 	fc_host_max_npiv_vports(vha->host) = ha->max_npiv_vports;
 	fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count;
 
-	if (IS_QLA8XXX_TYPE(ha))
+	if (IS_CNA_CAPABLE(ha))
 		speed = FC_PORTSPEED_10GBIT;
 	else if (IS_QLA25XX(ha))
 		speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT |
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 2c47142..f74cc06 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -11,29 +11,36 @@
 #include <linux/delay.h>
 
 /* BSG support for ELS/CT pass through */
-inline srb_t *
-qla2x00_get_ctx_bsg_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size)
+void
+qla2x00_bsg_job_done(void *data, void *ptr, int res)
 {
-	srb_t *sp;
+	srb_t *sp = (srb_t *)ptr;
+	struct scsi_qla_host *vha = (scsi_qla_host_t *)data;
+	struct fc_bsg_job *bsg_job = sp->u.bsg_job;
+
+	bsg_job->reply->result = res;
+	bsg_job->job_done(bsg_job);
+	sp->free(vha, sp);
+}
+
+void
+qla2x00_bsg_sp_free(void *data, void *ptr)
+{
+	srb_t *sp = (srb_t *)ptr;
+	struct scsi_qla_host *vha = (scsi_qla_host_t *)data;
+	struct fc_bsg_job *bsg_job = sp->u.bsg_job;
 	struct qla_hw_data *ha = vha->hw;
-	struct srb_ctx *ctx;
 
-	sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL);
-	if (!sp)
-		goto done;
-	ctx = kzalloc(size, GFP_KERNEL);
-	if (!ctx) {
-		mempool_free(sp, ha->srb_mempool);
-		sp = NULL;
-		goto done;
-	}
+	dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+	    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
 
-	memset(sp, 0, sizeof(*sp));
-	sp->fcport = fcport;
-	sp->ctx = ctx;
-	ctx->iocbs = 1;
-done:
-	return sp;
+	dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+	    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+
+	if (sp->type == SRB_CT_CMD ||
+	    sp->type == SRB_ELS_CMD_HST)
+		kfree(sp->fcport);
+	mempool_free(sp, vha->hw->srb_mempool);
 }
 
 int
@@ -101,8 +108,6 @@
 	uint32_t len;
 	uint32_t oper;
 
-	bsg_job->reply->reply_payload_rcv_len = 0;
-
 	if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA82XX(ha))) {
 		ret = -EINVAL;
 		goto exit_fcp_prio_cfg;
@@ -217,6 +222,7 @@
 	bsg_job->job_done(bsg_job);
 	return ret;
 }
+
 static int
 qla2x00_process_els(struct fc_bsg_job *bsg_job)
 {
@@ -230,7 +236,6 @@
 	int req_sg_cnt, rsp_sg_cnt;
 	int rval =  (DRIVER_ERROR << 16);
 	uint16_t nextlid = 0;
-	struct srb_ctx *els;
 
 	if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) {
 		rport = bsg_job->rport;
@@ -337,20 +342,21 @@
 	}
 
 	/* Alloc SRB structure */
-	sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_ctx));
+	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
 	if (!sp) {
 		rval = -ENOMEM;
 		goto done_unmap_sg;
 	}
 
-	els = sp->ctx;
-	els->type =
+	sp->type =
 		(bsg_job->request->msgcode == FC_BSG_RPT_ELS ?
 		SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST);
-	els->name =
+	sp->name =
 		(bsg_job->request->msgcode == FC_BSG_RPT_ELS ?
 		"bsg_els_rpt" : "bsg_els_hst");
-	els->u.bsg_job = bsg_job;
+	sp->u.bsg_job = bsg_job;
+	sp->free = qla2x00_bsg_sp_free;
+	sp->done = qla2x00_bsg_job_done;
 
 	ql_dbg(ql_dbg_user, vha, 0x700a,
 	    "bsg rqst type: %s els type: %x - loop-id=%x "
@@ -362,7 +368,6 @@
 	if (rval != QLA_SUCCESS) {
 		ql_log(ql_log_warn, vha, 0x700e,
 		    "qla2x00_start_sp failed = %d\n", rval);
-		kfree(sp->ctx);
 		mempool_free(sp, ha->srb_mempool);
 		rval = -EIO;
 		goto done_unmap_sg;
@@ -409,7 +414,6 @@
 	uint16_t loop_id;
 	struct fc_port *fcport;
 	char  *type = "FC_BSG_HST_CT";
-	struct srb_ctx *ct;
 
 	req_sg_cnt =
 		dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
@@ -486,19 +490,20 @@
 	fcport->loop_id = loop_id;
 
 	/* Alloc SRB structure */
-	sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_ctx));
+	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
 	if (!sp) {
 		ql_log(ql_log_warn, vha, 0x7015,
-		    "qla2x00_get_ctx_bsg_sp failed.\n");
+		    "qla2x00_get_sp failed.\n");
 		rval = -ENOMEM;
 		goto done_free_fcport;
 	}
 
-	ct = sp->ctx;
-	ct->type = SRB_CT_CMD;
-	ct->name = "bsg_ct";
-	ct->iocbs = qla24xx_calc_ct_iocbs(req_sg_cnt + rsp_sg_cnt);
-	ct->u.bsg_job = bsg_job;
+	sp->type = SRB_CT_CMD;
+	sp->name = "bsg_ct";
+	sp->iocbs = qla24xx_calc_ct_iocbs(req_sg_cnt + rsp_sg_cnt);
+	sp->u.bsg_job = bsg_job;
+	sp->free = qla2x00_bsg_sp_free;
+	sp->done = qla2x00_bsg_job_done;
 
 	ql_dbg(ql_dbg_user, vha, 0x7016,
 	    "bsg rqst type: %s else type: %x - "
@@ -511,7 +516,6 @@
 	if (rval != QLA_SUCCESS) {
 		ql_log(ql_log_warn, vha, 0x7017,
 		    "qla2x00_start_sp failed=%d.\n", rval);
-		kfree(sp->ctx);
 		mempool_free(sp, ha->srb_mempool);
 		rval = -EIO;
 		goto done_free_fcport;
@@ -540,7 +544,7 @@
 	int rval = 0;
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA81XX(ha))
+	if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
 		goto done_set_internal;
 
 	new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1);
@@ -582,7 +586,7 @@
 	uint16_t new_config[4];
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA81XX(ha))
+	if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
 		goto done_reset_internal;
 
 	memset(new_config, 0 , sizeof(new_config));
@@ -707,7 +711,7 @@
 
 	if ((ha->current_topology == ISP_CFG_F ||
 	    (atomic_read(&vha->loop_state) == LOOP_DOWN) ||
-	    (IS_QLA81XX(ha) &&
+	    ((IS_QLA81XX(ha) || IS_QLA83XX(ha)) &&
 	    le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE
 	    && req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
 		elreq.options == EXTERNAL_LOOPBACK) {
@@ -717,13 +721,12 @@
 		command_sent = INT_DEF_LB_ECHO_CMD;
 		rval = qla2x00_echo_test(vha, &elreq, response);
 	} else {
-		if (IS_QLA81XX(ha)) {
+		if (IS_QLA81XX(ha) || IS_QLA8031(ha)) {
 			memset(config, 0, sizeof(config));
 			memset(new_config, 0, sizeof(new_config));
 			if (qla81xx_get_port_config(vha, config)) {
 				ql_log(ql_log_warn, vha, 0x701f,
 				    "Get port config failed.\n");
-				bsg_job->reply->reply_payload_rcv_len = 0;
 				bsg_job->reply->result = (DID_ERROR << 16);
 				rval = -EPERM;
 				goto done_free_dma_req;
@@ -737,8 +740,6 @@
 					new_config)) {
 					ql_log(ql_log_warn, vha, 0x7024,
 					    "Internal loopback failed.\n");
-					bsg_job->reply->reply_payload_rcv_len =
-						0;
 					bsg_job->reply->result =
 						(DID_ERROR << 16);
 					rval = -EPERM;
@@ -750,8 +751,6 @@
 				 */
 				if (qla81xx_reset_internal_loopback(vha,
 					config, 1)) {
-					bsg_job->reply->reply_payload_rcv_len =
-						0;
 					bsg_job->reply->result =
 						(DID_ERROR << 16);
 					rval = -EPERM;
@@ -788,7 +787,6 @@
 					    "MPI reset failed.\n");
 				}
 
-				bsg_job->reply->reply_payload_rcv_len = 0;
 				bsg_job->reply->result = (DID_ERROR << 16);
 				rval = -EIO;
 				goto done_free_dma_req;
@@ -813,7 +811,6 @@
 		fw_sts_ptr += sizeof(response);
 		*fw_sts_ptr = command_sent;
 		rval = 0;
-		bsg_job->reply->reply_payload_rcv_len = 0;
 		bsg_job->reply->result = (DID_ERROR << 16);
 	} else {
 		ql_dbg(ql_dbg_user, vha, 0x702d,
@@ -872,7 +869,7 @@
 	if (rval) {
 		ql_log(ql_log_warn, vha, 0x7030,
 		    "Vendor request 84xx reset failed.\n");
-		rval = bsg_job->reply->reply_payload_rcv_len = 0;
+		rval = 0;
 		bsg_job->reply->result = (DID_ERROR << 16);
 
 	} else {
@@ -971,9 +968,8 @@
 		ql_log(ql_log_warn, vha, 0x7037,
 		    "Vendor request 84xx updatefw failed.\n");
 
-		rval = bsg_job->reply->reply_payload_rcv_len = 0;
+		rval = 0;
 		bsg_job->reply->result = (DID_ERROR << 16);
-
 	} else {
 		ql_dbg(ql_dbg_user, vha, 0x7038,
 		    "Vendor request 84xx updatefw completed.\n");
@@ -1159,7 +1155,7 @@
 		ql_log(ql_log_warn, vha, 0x7043,
 		    "Vendor request 84xx mgmt failed.\n");
 
-		rval = bsg_job->reply->reply_payload_rcv_len = 0;
+		rval = 0;
 		bsg_job->reply->result = (DID_ERROR << 16);
 
 	} else {
@@ -1210,8 +1206,6 @@
 	uint16_t mb[MAILBOX_REGISTER_COUNT];
 	uint8_t *rsp_ptr = NULL;
 
-	bsg_job->reply->reply_payload_rcv_len = 0;
-
 	if (!IS_IIDMA_CAPABLE(vha->hw)) {
 		ql_log(ql_log_info, vha, 0x7046, "iiDMA not supported.\n");
 		return -EINVAL;
@@ -1304,8 +1298,6 @@
 	int valid = 0;
 	struct qla_hw_data *ha = vha->hw;
 
-	bsg_job->reply->reply_payload_rcv_len = 0;
-
 	if (unlikely(pci_channel_offline(ha->pdev)))
 		return -EINVAL;
 
@@ -1331,7 +1323,7 @@
 		    start == (ha->flt_region_fw * 4))
 			valid = 1;
 		else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
-		    IS_QLA8XXX_TYPE(ha))
+		    IS_CNA_CAPABLE(ha) || IS_QLA2031(ha))
 			valid = 1;
 		if (!valid) {
 			ql_log(ql_log_warn, vha, 0x7058,
@@ -1617,6 +1609,9 @@
 	struct Scsi_Host *host;
 	scsi_qla_host_t *vha;
 
+	/* In case no data transferred. */
+	bsg_job->reply->reply_payload_rcv_len = 0;
+
 	if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) {
 		rport = bsg_job->rport;
 		fcport = *(fc_port_t **) rport->dd_data;
@@ -1655,6 +1650,7 @@
 	case FC_BSG_RPT_CT:
 	default:
 		ql_log(ql_log_warn, vha, 0x705a, "Unsupported BSG request.\n");
+		bsg_job->reply->result = ret;
 		break;
 	}
 	return ret;
@@ -1669,7 +1665,6 @@
 	int cnt, que;
 	unsigned long flags;
 	struct req_que *req;
-	struct srb_ctx *sp_bsg;
 
 	/* find the bsg job from the active list of commands */
 	spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1681,11 +1676,9 @@
 		for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
 			sp = req->outstanding_cmds[cnt];
 			if (sp) {
-				sp_bsg = sp->ctx;
-
-				if (((sp_bsg->type == SRB_CT_CMD) ||
-					(sp_bsg->type == SRB_ELS_CMD_HST))
-					&& (sp_bsg->u.bsg_job == bsg_job)) {
+				if (((sp->type == SRB_CT_CMD) ||
+					(sp->type == SRB_ELS_CMD_HST))
+					&& (sp->u.bsg_job == bsg_job)) {
 					spin_unlock_irqrestore(&ha->hardware_lock, flags);
 					if (ha->isp_ops->abort_command(sp)) {
 						ql_log(ql_log_warn, vha, 0x7089,
@@ -1715,7 +1708,6 @@
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 	if (bsg_job->request->msgcode == FC_BSG_HST_CT)
 		kfree(sp->fcport);
-	kfree(sp->ctx);
 	mempool_free(sp, ha->srb_mempool);
 	return 0;
 }
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 45cbf0b..897731b 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -11,23 +11,27 @@
  * ----------------------------------------------------------------------
  * |             Level            |   Last Value Used  |     Holes	|
  * ----------------------------------------------------------------------
- * | Module Init and Probe        |       0x0116       | 0xfa           |
- * | Mailbox commands             |       0x112b       |		|
- * | Device Discovery             |       0x2084       |		|
- * | Queue Command and IO tracing |       0x302f       | 0x3008,0x302d, |
- * |                              |                    | 0x302e         |
+ * | Module Init and Probe        |       0x0120       | 0x4b,0xba,0xfa |
+ * | Mailbox commands             |       0x113e       | 0x112c-0x112e  |
+ * |                              |                    | 0x113a         |
+ * | Device Discovery             |       0x2086       | 0x2020-0x2022  |
+ * | Queue Command and IO tracing |       0x302f       | 0x3006,0x3008  |
+ * |                              |                    | 0x302d-0x302e  |
  * | DPC Thread                   |       0x401c       |		|
- * | Async Events                 |       0x5057       | 0x5052		|
- * | Timer Routines               |       0x6011       | 0x600e,0x600f  |
- * | User Space Interactions      |       0x709e       | 0x7018,0x702e  |
- * |                              |                    | 0x7039,0x7045  |
+ * | Async Events                 |       0x505d       | 0x502b-0x502f  |
+ * |                              |                    | 0x5047,0x5052  |
+ * | Timer Routines               |       0x6011       | 0x600e-0x600f  |
+ * | User Space Interactions      |       0x709f       | 0x7018,0x702e, |
+ * |                              |                    | 0x7039,0x7045, |
+ * |                              |                    | 0x7073-0x7075, |
+ * |                              |                    | 0x708c         |
  * | Task Management              |       0x803c       | 0x8025-0x8026  |
  * |                              |                    | 0x800b,0x8039  |
  * | AER/EEH                      |       0x900f       |		|
  * | Virtual Port                 |       0xa007       |		|
- * | ISP82XX Specific             |       0xb052       |    		|
- * | MultiQ                       |       0xc00b       |		|
- * | Misc                         |       0xd00b       |		|
+ * | ISP82XX Specific             |       0xb054       | 0xb053         |
+ * | MultiQ                       |       0xc00c       |		|
+ * | Misc                         |       0xd010       |		|
  * ----------------------------------------------------------------------
  */
 
@@ -85,7 +89,7 @@
 	WRT_REG_WORD(&reg->mailbox0, MBC_DUMP_RISC_RAM_EXTENDED);
 	clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
 
-	dwords = GID_LIST_SIZE / 4;
+	dwords = qla2x00_gid_list_size(ha) / 4;
 	for (cnt = 0; cnt < ram_dwords && rval == QLA_SUCCESS;
 	    cnt += dwords, addr += dwords) {
 		if (cnt + dwords > ram_dwords)
@@ -260,7 +264,7 @@
 	WRT_MAILBOX_REG(ha, reg, 0, MBC_DUMP_RISC_RAM_EXTENDED);
 	clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
 
-	words = GID_LIST_SIZE / 2;
+	words = qla2x00_gid_list_size(ha) / 2;
 	for (cnt = 0; cnt < ram_words && rval == QLA_SUCCESS;
 	    cnt += words, addr += words) {
 		if (cnt + words > ram_words)
@@ -375,6 +379,77 @@
 }
 
 static inline void *
+qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
+{
+	struct qla2xxx_mqueue_chain *q;
+	struct qla2xxx_mqueue_header *qh;
+	struct req_que *req;
+	struct rsp_que *rsp;
+	int que;
+
+	if (!ha->mqenable)
+		return ptr;
+
+	/* Request queues */
+	for (que = 1; que < ha->max_req_queues; que++) {
+		req = ha->req_q_map[que];
+		if (!req)
+			break;
+
+		/* Add chain. */
+		q = ptr;
+		*last_chain = &q->type;
+		q->type = __constant_htonl(DUMP_CHAIN_QUEUE);
+		q->chain_size = htonl(
+		    sizeof(struct qla2xxx_mqueue_chain) +
+		    sizeof(struct qla2xxx_mqueue_header) +
+		    (req->length * sizeof(request_t)));
+		ptr += sizeof(struct qla2xxx_mqueue_chain);
+
+		/* Add header. */
+		qh = ptr;
+		qh->queue = __constant_htonl(TYPE_REQUEST_QUEUE);
+		qh->number = htonl(que);
+		qh->size = htonl(req->length * sizeof(request_t));
+		ptr += sizeof(struct qla2xxx_mqueue_header);
+
+		/* Add data. */
+		memcpy(ptr, req->ring, req->length * sizeof(request_t));
+		ptr += req->length * sizeof(request_t);
+	}
+
+	/* Response queues */
+	for (que = 1; que < ha->max_rsp_queues; que++) {
+		rsp = ha->rsp_q_map[que];
+		if (!rsp)
+			break;
+
+		/* Add chain. */
+		q = ptr;
+		*last_chain = &q->type;
+		q->type = __constant_htonl(DUMP_CHAIN_QUEUE);
+		q->chain_size = htonl(
+		    sizeof(struct qla2xxx_mqueue_chain) +
+		    sizeof(struct qla2xxx_mqueue_header) +
+		    (rsp->length * sizeof(response_t)));
+		ptr += sizeof(struct qla2xxx_mqueue_chain);
+
+		/* Add header. */
+		qh = ptr;
+		qh->queue = __constant_htonl(TYPE_RESPONSE_QUEUE);
+		qh->number = htonl(que);
+		qh->size = htonl(rsp->length * sizeof(response_t));
+		ptr += sizeof(struct qla2xxx_mqueue_header);
+
+		/* Add data. */
+		memcpy(ptr, rsp->ring, rsp->length * sizeof(response_t));
+		ptr += rsp->length * sizeof(response_t);
+	}
+
+	return ptr;
+}
+
+static inline void *
 qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
 {
 	uint32_t cnt, que_idx;
@@ -382,7 +457,7 @@
 	struct qla2xxx_mq_chain *mq = ptr;
 	struct device_reg_25xxmq __iomem *reg;
 
-	if (!ha->mqenable)
+	if (!ha->mqenable || IS_QLA83XX(ha))
 		return ptr;
 
 	mq = ptr;
@@ -1322,12 +1397,16 @@
 	nxt = qla24xx_copy_eft(ha, nxt);
 
 	/* Chain entries -- started with MQ. */
-	qla25xx_copy_fce(ha, nxt_chain, &last_chain);
+	nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
+	nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain);
 	if (last_chain) {
 		ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
 		*last_chain |= __constant_htonl(DUMP_CHAIN_LAST);
 	}
 
+	/* Adjust valid length. */
+	ha->fw_dump_len = (nxt_chain - (void *)ha->fw_dump);
+
 qla25xx_fw_dump_failed_0:
 	qla2xxx_dump_post_process(base_vha, rval);
 
@@ -1636,12 +1715,16 @@
 	nxt = qla24xx_copy_eft(ha, nxt);
 
 	/* Chain entries -- started with MQ. */
-	qla25xx_copy_fce(ha, nxt_chain, &last_chain);
+	nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
+	nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain);
 	if (last_chain) {
 		ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
 		*last_chain |= __constant_htonl(DUMP_CHAIN_LAST);
 	}
 
+	/* Adjust valid length. */
+	ha->fw_dump_len = (nxt_chain - (void *)ha->fw_dump);
+
 qla81xx_fw_dump_failed_0:
 	qla2xxx_dump_post_process(base_vha, rval);
 
@@ -1650,6 +1733,507 @@
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
+void
+qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
+{
+	int		rval;
+	uint32_t	cnt, reg_data;
+	uint32_t	risc_address;
+	struct qla_hw_data *ha = vha->hw;
+	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+	uint32_t __iomem *dmp_reg;
+	uint32_t	*iter_reg;
+	uint16_t __iomem *mbx_reg;
+	unsigned long	flags;
+	struct qla83xx_fw_dump *fw;
+	uint32_t	ext_mem_cnt;
+	void		*nxt, *nxt_chain;
+	uint32_t	*last_chain = NULL;
+	struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
+
+	risc_address = ext_mem_cnt = 0;
+	flags = 0;
+
+	if (!hardware_locked)
+		spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	if (!ha->fw_dump) {
+		ql_log(ql_log_warn, vha, 0xd00c,
+		    "No buffer available for dump!!!\n");
+		goto qla83xx_fw_dump_failed;
+	}
+
+	if (ha->fw_dumped) {
+		ql_log(ql_log_warn, vha, 0xd00d,
+		    "Firmware has been previously dumped (%p) -- ignoring "
+		    "request...\n", ha->fw_dump);
+		goto qla83xx_fw_dump_failed;
+	}
+	fw = &ha->fw_dump->isp.isp83;
+	qla2xxx_prep_dump(ha, ha->fw_dump);
+
+	fw->host_status = htonl(RD_REG_DWORD(&reg->host_status));
+
+	/* Pause RISC. */
+	rval = qla24xx_pause_risc(reg);
+	if (rval != QLA_SUCCESS)
+		goto qla83xx_fw_dump_failed_0;
+
+	WRT_REG_DWORD(&reg->iobase_addr, 0x6000);
+	dmp_reg = &reg->iobase_window;
+	reg_data = RD_REG_DWORD(dmp_reg);
+	WRT_REG_DWORD(dmp_reg, 0);
+
+	dmp_reg = &reg->unused_4_1[0];
+	reg_data = RD_REG_DWORD(dmp_reg);
+	WRT_REG_DWORD(dmp_reg, 0);
+
+	WRT_REG_DWORD(&reg->iobase_addr, 0x6010);
+	dmp_reg = &reg->unused_4_1[2];
+	reg_data = RD_REG_DWORD(dmp_reg);
+	WRT_REG_DWORD(dmp_reg, 0);
+
+	/* select PCR and disable ecc checking and correction */
+	WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+	RD_REG_DWORD(&reg->iobase_addr);
+	WRT_REG_DWORD(&reg->iobase_select, 0x60000000);	/* write to F0h = PCR */
+
+	/* Host/Risc registers. */
+	iter_reg = fw->host_risc_reg;
+	iter_reg = qla24xx_read_window(reg, 0x7000, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x7010, 16, iter_reg);
+	qla24xx_read_window(reg, 0x7040, 16, iter_reg);
+
+	/* PCIe registers. */
+	WRT_REG_DWORD(&reg->iobase_addr, 0x7C00);
+	RD_REG_DWORD(&reg->iobase_addr);
+	WRT_REG_DWORD(&reg->iobase_window, 0x01);
+	dmp_reg = &reg->iobase_c4;
+	fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++));
+	fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++));
+	fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg));
+	fw->pcie_regs[3] = htonl(RD_REG_DWORD(&reg->iobase_window));
+
+	WRT_REG_DWORD(&reg->iobase_window, 0x00);
+	RD_REG_DWORD(&reg->iobase_window);
+
+	/* Host interface registers. */
+	dmp_reg = &reg->flash_addr;
+	for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
+		fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+	/* Disable interrupts. */
+	WRT_REG_DWORD(&reg->ictrl, 0);
+	RD_REG_DWORD(&reg->ictrl);
+
+	/* Shadow registers. */
+	WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+	RD_REG_DWORD(&reg->iobase_addr);
+	WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
+	fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+	WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
+	fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+	WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
+	fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+	WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
+	fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+	WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
+	fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+	WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
+	fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+	WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
+	fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+	WRT_REG_DWORD(&reg->iobase_select, 0xB0700000);
+	fw->shadow_reg[7] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+	WRT_REG_DWORD(&reg->iobase_select, 0xB0800000);
+	fw->shadow_reg[8] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+	WRT_REG_DWORD(&reg->iobase_select, 0xB0900000);
+	fw->shadow_reg[9] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+	WRT_REG_DWORD(&reg->iobase_select, 0xB0A00000);
+	fw->shadow_reg[10] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+	/* RISC I/O register. */
+	WRT_REG_DWORD(&reg->iobase_addr, 0x0010);
+	fw->risc_io_reg = htonl(RD_REG_DWORD(&reg->iobase_window));
+
+	/* Mailbox registers. */
+	mbx_reg = &reg->mailbox0;
+	for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
+		fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+
+	/* Transfer sequence registers. */
+	iter_reg = fw->xseq_gp_reg;
+	iter_reg = qla24xx_read_window(reg, 0xBE00, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xBE10, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xBE20, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xBE30, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xBE40, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xBE50, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xBE60, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xBE70, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg);
+	qla24xx_read_window(reg, 0xBF70, 16, iter_reg);
+
+	iter_reg = fw->xseq_0_reg;
+	iter_reg = qla24xx_read_window(reg, 0xBFC0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xBFD0, 16, iter_reg);
+	qla24xx_read_window(reg, 0xBFE0, 16, iter_reg);
+
+	qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg);
+
+	qla24xx_read_window(reg, 0xBEF0, 16, fw->xseq_2_reg);
+
+	/* Receive sequence registers. */
+	iter_reg = fw->rseq_gp_reg;
+	iter_reg = qla24xx_read_window(reg, 0xFE00, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xFE10, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xFE20, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xFE30, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xFE40, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xFE50, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xFE60, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xFE70, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg);
+	qla24xx_read_window(reg, 0xFF70, 16, iter_reg);
+
+	iter_reg = fw->rseq_0_reg;
+	iter_reg = qla24xx_read_window(reg, 0xFFC0, 16, iter_reg);
+	qla24xx_read_window(reg, 0xFFD0, 16, iter_reg);
+
+	qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg);
+	qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg);
+	qla24xx_read_window(reg, 0xFEF0, 16, fw->rseq_3_reg);
+
+	/* Auxiliary sequence registers. */
+	iter_reg = fw->aseq_gp_reg;
+	iter_reg = qla24xx_read_window(reg, 0xB000, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xB010, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xB020, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xB030, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xB040, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xB050, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xB060, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xB070, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xB100, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xB110, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xB120, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xB130, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xB140, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xB150, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0xB160, 16, iter_reg);
+	qla24xx_read_window(reg, 0xB170, 16, iter_reg);
+
+	iter_reg = fw->aseq_0_reg;
+	iter_reg = qla24xx_read_window(reg, 0xB0C0, 16, iter_reg);
+	qla24xx_read_window(reg, 0xB0D0, 16, iter_reg);
+
+	qla24xx_read_window(reg, 0xB0E0, 16, fw->aseq_1_reg);
+	qla24xx_read_window(reg, 0xB0F0, 16, fw->aseq_2_reg);
+	qla24xx_read_window(reg, 0xB1F0, 16, fw->aseq_3_reg);
+
+	/* Command DMA registers. */
+	iter_reg = fw->cmd_dma_reg;
+	iter_reg = qla24xx_read_window(reg, 0x7100, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x7120, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x7130, 16, iter_reg);
+	qla24xx_read_window(reg, 0x71F0, 16, iter_reg);
+
+	/* Queues. */
+	iter_reg = fw->req0_dma_reg;
+	iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
+	dmp_reg = &reg->iobase_q;
+	for (cnt = 0; cnt < 7; cnt++)
+		*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+	iter_reg = fw->resp0_dma_reg;
+	iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
+	dmp_reg = &reg->iobase_q;
+	for (cnt = 0; cnt < 7; cnt++)
+		*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+	iter_reg = fw->req1_dma_reg;
+	iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
+	dmp_reg = &reg->iobase_q;
+	for (cnt = 0; cnt < 7; cnt++)
+		*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+	/* Transmit DMA registers. */
+	iter_reg = fw->xmt0_dma_reg;
+	iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg);
+	qla24xx_read_window(reg, 0x7610, 16, iter_reg);
+
+	iter_reg = fw->xmt1_dma_reg;
+	iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg);
+	qla24xx_read_window(reg, 0x7630, 16, iter_reg);
+
+	iter_reg = fw->xmt2_dma_reg;
+	iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg);
+	qla24xx_read_window(reg, 0x7650, 16, iter_reg);
+
+	iter_reg = fw->xmt3_dma_reg;
+	iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg);
+	qla24xx_read_window(reg, 0x7670, 16, iter_reg);
+
+	iter_reg = fw->xmt4_dma_reg;
+	iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg);
+	qla24xx_read_window(reg, 0x7690, 16, iter_reg);
+
+	qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg);
+
+	/* Receive DMA registers. */
+	iter_reg = fw->rcvt0_data_dma_reg;
+	iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg);
+	qla24xx_read_window(reg, 0x7710, 16, iter_reg);
+
+	iter_reg = fw->rcvt1_data_dma_reg;
+	iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg);
+	qla24xx_read_window(reg, 0x7730, 16, iter_reg);
+
+	/* RISC registers. */
+	iter_reg = fw->risc_gp_reg;
+	iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg);
+	qla24xx_read_window(reg, 0x0F70, 16, iter_reg);
+
+	/* Local memory controller registers. */
+	iter_reg = fw->lmc_reg;
+	iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x3060, 16, iter_reg);
+	qla24xx_read_window(reg, 0x3070, 16, iter_reg);
+
+	/* Fibre Protocol Module registers. */
+	iter_reg = fw->fpm_hdw_reg;
+	iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x40B0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x40C0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x40D0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x40E0, 16, iter_reg);
+	qla24xx_read_window(reg, 0x40F0, 16, iter_reg);
+
+	/* RQ0 Array registers. */
+	iter_reg = fw->rq0_array_reg;
+	iter_reg = qla24xx_read_window(reg, 0x5C00, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5C10, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5C20, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5C30, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5C40, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5C50, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5C60, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5C70, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5C80, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5C90, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5CA0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5CB0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5CC0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5CD0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5CE0, 16, iter_reg);
+	qla24xx_read_window(reg, 0x5CF0, 16, iter_reg);
+
+	/* RQ1 Array registers. */
+	iter_reg = fw->rq1_array_reg;
+	iter_reg = qla24xx_read_window(reg, 0x5D00, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5D10, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5D20, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5D30, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5D40, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5D50, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5D60, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5D70, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5D80, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5D90, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5DA0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5DB0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5DC0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5DD0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5DE0, 16, iter_reg);
+	qla24xx_read_window(reg, 0x5DF0, 16, iter_reg);
+
+	/* RP0 Array registers. */
+	iter_reg = fw->rp0_array_reg;
+	iter_reg = qla24xx_read_window(reg, 0x5E00, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5E10, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5E20, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5E30, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5E40, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5E50, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5E60, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5E70, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5E80, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5E90, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5EA0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5EB0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5EC0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5ED0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5EE0, 16, iter_reg);
+	qla24xx_read_window(reg, 0x5EF0, 16, iter_reg);
+
+	/* RP1 Array registers. */
+	iter_reg = fw->rp1_array_reg;
+	iter_reg = qla24xx_read_window(reg, 0x5F00, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5F10, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5F20, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5F30, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5F40, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5F50, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5F60, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5F70, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5F80, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5F90, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5FA0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5FB0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5FC0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5FD0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x5FE0, 16, iter_reg);
+	qla24xx_read_window(reg, 0x5FF0, 16, iter_reg);
+
+	iter_reg = fw->at0_array_reg;
+	iter_reg = qla24xx_read_window(reg, 0x7080, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x7090, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x70A0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x70B0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x70C0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x70D0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x70E0, 16, iter_reg);
+	qla24xx_read_window(reg, 0x70F0, 16, iter_reg);
+
+	/* I/O Queue Control registers. */
+	qla24xx_read_window(reg, 0x7800, 16, fw->queue_control_reg);
+
+	/* Frame Buffer registers. */
+	iter_reg = fw->fb_hdw_reg;
+	iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6060, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6070, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x61B0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x61C0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6530, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6540, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6550, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6560, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6570, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6580, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x6590, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x65A0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x65B0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x65C0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x65D0, 16, iter_reg);
+	iter_reg = qla24xx_read_window(reg, 0x65E0, 16, iter_reg);
+	qla24xx_read_window(reg, 0x6F00, 16, iter_reg);
+
+	/* Multi queue registers */
+	nxt_chain = qla25xx_copy_mq(ha, (void *)ha->fw_dump + ha->chain_offset,
+	    &last_chain);
+
+	rval = qla24xx_soft_reset(ha);
+	if (rval != QLA_SUCCESS) {
+		ql_log(ql_log_warn, vha, 0xd00e,
+		    "SOFT RESET FAILED, forcing continuation of dump!!!\n");
+		rval = QLA_SUCCESS;
+
+		ql_log(ql_log_warn, vha, 0xd00f, "try a bigger hammer!!!\n");
+
+		WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
+		RD_REG_DWORD(&reg->hccr);
+
+		WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
+		RD_REG_DWORD(&reg->hccr);
+
+		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
+		RD_REG_DWORD(&reg->hccr);
+
+		for (cnt = 30000; cnt && (RD_REG_WORD(&reg->mailbox0)); cnt--)
+			udelay(5);
+
+		if (!cnt) {
+			nxt = fw->code_ram;
+			nxt += sizeof(fw->code_ram),
+			nxt += (ha->fw_memory_size - 0x100000 + 1);
+			goto copy_queue;
+		} else
+			ql_log(ql_log_warn, vha, 0xd010,
+			    "bigger hammer success?\n");
+	}
+
+	rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram),
+	    &nxt);
+	if (rval != QLA_SUCCESS)
+		goto qla83xx_fw_dump_failed_0;
+
+copy_queue:
+	nxt = qla2xxx_copy_queues(ha, nxt);
+
+	nxt = qla24xx_copy_eft(ha, nxt);
+
+	/* Chain entries -- started with MQ. */
+	nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
+	nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain);
+	if (last_chain) {
+		ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
+		*last_chain |= __constant_htonl(DUMP_CHAIN_LAST);
+	}
+
+	/* Adjust valid length. */
+	ha->fw_dump_len = (nxt_chain - (void *)ha->fw_dump);
+
+qla83xx_fw_dump_failed_0:
+	qla2xxx_dump_post_process(base_vha, rval);
+
+qla83xx_fw_dump_failed:
+	if (!hardware_locked)
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
 /****************************************************************************/
 /*                         Driver Debug Functions.                          */
 /****************************************************************************/
@@ -1782,13 +2366,13 @@
 	vaf.va = &va;
 
 	switch (level) {
-	case 0: /* FATAL LOG */
+	case ql_log_fatal: /* FATAL LOG */
 		pr_crit("%s%pV", pbuf, &vaf);
 		break;
-	case 1:
+	case ql_log_warn:
 		pr_err("%s%pV", pbuf, &vaf);
 		break;
-	case 2:
+	case ql_log_info:
 		pr_warn("%s%pV", pbuf, &vaf);
 		break;
 	default:
@@ -1837,13 +2421,13 @@
 	vaf.va = &va;
 
 	switch (level) {
-	case 0: /* FATAL LOG */
+	case ql_log_fatal: /* FATAL LOG */
 		pr_crit("%s%pV", pbuf, &vaf);
 		break;
-	case 1:
+	case ql_log_warn:
 		pr_err("%s%pV", pbuf, &vaf);
 		break;
-	case 2:
+	case ql_log_info:
 		pr_warn("%s%pV", pbuf, &vaf);
 		break;
 	default:
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index 5f1b6d9..2157bdf 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -165,6 +165,54 @@
 	uint32_t ext_mem[1];
 };
 
+struct qla83xx_fw_dump {
+	uint32_t host_status;
+	uint32_t host_risc_reg[48];
+	uint32_t pcie_regs[4];
+	uint32_t host_reg[32];
+	uint32_t shadow_reg[11];
+	uint32_t risc_io_reg;
+	uint16_t mailbox_reg[32];
+	uint32_t xseq_gp_reg[256];
+	uint32_t xseq_0_reg[48];
+	uint32_t xseq_1_reg[16];
+	uint32_t xseq_2_reg[16];
+	uint32_t rseq_gp_reg[256];
+	uint32_t rseq_0_reg[32];
+	uint32_t rseq_1_reg[16];
+	uint32_t rseq_2_reg[16];
+	uint32_t rseq_3_reg[16];
+	uint32_t aseq_gp_reg[256];
+	uint32_t aseq_0_reg[32];
+	uint32_t aseq_1_reg[16];
+	uint32_t aseq_2_reg[16];
+	uint32_t aseq_3_reg[16];
+	uint32_t cmd_dma_reg[64];
+	uint32_t req0_dma_reg[15];
+	uint32_t resp0_dma_reg[15];
+	uint32_t req1_dma_reg[15];
+	uint32_t xmt0_dma_reg[32];
+	uint32_t xmt1_dma_reg[32];
+	uint32_t xmt2_dma_reg[32];
+	uint32_t xmt3_dma_reg[32];
+	uint32_t xmt4_dma_reg[32];
+	uint32_t xmt_data_dma_reg[16];
+	uint32_t rcvt0_data_dma_reg[32];
+	uint32_t rcvt1_data_dma_reg[32];
+	uint32_t risc_gp_reg[128];
+	uint32_t lmc_reg[128];
+	uint32_t fpm_hdw_reg[256];
+	uint32_t rq0_array_reg[256];
+	uint32_t rq1_array_reg[256];
+	uint32_t rp0_array_reg[256];
+	uint32_t rp1_array_reg[256];
+	uint32_t queue_control_reg[16];
+	uint32_t fb_hdw_reg[432];
+	uint32_t at0_array_reg[128];
+	uint32_t code_ram[0x2400];
+	uint32_t ext_mem[1];
+};
+
 #define EFT_NUM_BUFFERS		4
 #define EFT_BYTES_PER_BUFFER	0x4000
 #define EFT_SIZE		((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS))
@@ -192,9 +240,23 @@
 	uint32_t qregs[4 * QLA_MQ_SIZE];
 };
 
+struct qla2xxx_mqueue_header {
+	uint32_t queue;
+#define TYPE_REQUEST_QUEUE	0x1
+#define TYPE_RESPONSE_QUEUE	0x2
+	uint32_t number;
+	uint32_t size;
+};
+
+struct qla2xxx_mqueue_chain {
+	uint32_t type;
+	uint32_t chain_size;
+};
+
 #define DUMP_CHAIN_VARIANT	0x80000000
 #define DUMP_CHAIN_FCE		0x7FFFFAF0
 #define DUMP_CHAIN_MQ		0x7FFFFAF1
+#define DUMP_CHAIN_QUEUE	0x7FFFFAF2
 #define DUMP_CHAIN_LAST		0x80000000
 
 struct qla2xxx_fw_dump {
@@ -228,6 +290,7 @@
 		struct qla24xx_fw_dump isp24;
 		struct qla25xx_fw_dump isp25;
 		struct qla81xx_fw_dump isp81;
+		struct qla83xx_fw_dump isp83;
 	} isp;
 };
 
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index af1003f..a244303 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -125,17 +125,17 @@
  * Fibre Channel device definitions.
  */
 #define WWN_SIZE		8	/* Size of WWPN, WWN & WWNN */
-#define MAX_FIBRE_DEVICES	512
+#define MAX_FIBRE_DEVICES_2100	512
+#define MAX_FIBRE_DEVICES_2400	2048
+#define MAX_FIBRE_DEVICES_LOOP	128
+#define MAX_FIBRE_DEVICES_MAX	MAX_FIBRE_DEVICES_2400
 #define MAX_FIBRE_LUNS  	0xFFFF
-#define	MAX_RSCN_COUNT		32
 #define	MAX_HOST_COUNT		16
 
 /*
  * Host adapter default definitions.
  */
 #define MAX_BUSES		1  /* We only have one bus today */
-#define MAX_TARGETS_2100	MAX_FIBRE_DEVICES
-#define MAX_TARGETS_2200	MAX_FIBRE_DEVICES
 #define MIN_LUNS		8
 #define MAX_LUNS		MAX_FIBRE_LUNS
 #define MAX_CMDS_PER_LUN	255
@@ -202,20 +202,12 @@
 /*
  * SCSI Request Block
  */
-typedef struct srb {
-	atomic_t ref_count;
-	struct fc_port *fcport;
-	uint32_t handle;
-
+struct srb_cmd {
 	struct scsi_cmnd *cmd;		/* Linux SCSI command pkt */
-
-	uint16_t flags;
-
 	uint32_t request_sense_length;
 	uint8_t *request_sense_ptr;
-
 	void *ctx;
-} srb_t;
+};
 
 /*
  * SRB flag definitions
@@ -254,10 +246,7 @@
 	} u;
 
 	struct timer_list timer;
-
-	void (*done)(srb_t *);
-	void (*free)(srb_t *);
-	void (*timeout)(srb_t *);
+	void (*timeout)(void *);
 };
 
 /* Values for srb_ctx type */
@@ -268,16 +257,37 @@
 #define SRB_CT_CMD	5
 #define SRB_ADISC_CMD	6
 #define SRB_TM_CMD	7
+#define SRB_SCSI_CMD	8
 
-struct srb_ctx {
+typedef struct srb {
+	atomic_t ref_count;
+	struct fc_port *fcport;
+	uint32_t handle;
+	uint16_t flags;
 	uint16_t type;
 	char *name;
 	int iocbs;
 	union {
-		struct srb_iocb *iocb_cmd;
+		struct srb_iocb iocb_cmd;
 		struct fc_bsg_job *bsg_job;
+		struct srb_cmd scmd;
 	} u;
-};
+	void (*done)(void *, void *, int);
+	void (*free)(void *, void *);
+} srb_t;
+
+#define GET_CMD_SP(sp) (sp->u.scmd.cmd)
+#define SET_CMD_SP(sp, cmd) (sp->u.scmd.cmd = cmd)
+#define GET_CMD_CTX_SP(sp) (sp->u.scmd.ctx)
+
+#define GET_CMD_SENSE_LEN(sp) \
+	(sp->u.scmd.request_sense_length)
+#define SET_CMD_SENSE_LEN(sp, len) \
+	(sp->u.scmd.request_sense_length = len)
+#define GET_CMD_SENSE_PTR(sp) \
+	(sp->u.scmd.request_sense_ptr)
+#define SET_CMD_SENSE_PTR(sp, ptr) \
+	(sp->u.scmd.request_sense_ptr = ptr)
 
 struct msg_echo_lb {
 	dma_addr_t send_dma;
@@ -653,8 +663,10 @@
 #define MBC_DIAGNOSTIC_LOOP_BACK	0x45	/* Diagnostic loop back. */
 #define MBC_ONLINE_SELF_TEST		0x46	/* Online self-test. */
 #define MBC_ENHANCED_GET_PORT_DATABASE	0x47	/* Get port database + login */
+#define MBC_CONFIGURE_VF		0x4b	/* Configure VFs */
 #define MBC_RESET_LINK_STATUS		0x52	/* Reset Link Error Status */
 #define MBC_IOCB_COMMAND_A64		0x54	/* Execute IOCB command (64) */
+#define MBC_PORT_LOGOUT			0x56	/* Port Logout request */
 #define MBC_SEND_RNID_ELS		0x57	/* Send RNID ELS request */
 #define MBC_SET_RNID_PARAMS		0x59	/* Set RNID parameters */
 #define MBC_GET_RNID_PARAMS		0x5a	/* Data Rate */
@@ -1709,6 +1721,7 @@
 
 	uint16_t vp_idx;
 	uint8_t fc4_type;
+	uint8_t scan_state;
 } fc_port_t;
 
 /*
@@ -1761,7 +1774,6 @@
 
 #define	GID_PT_CMD	0x1A1
 #define	GID_PT_REQ_SIZE	(16 + 4)
-#define	GID_PT_RSP_SIZE	(16 + (MAX_FIBRE_DEVICES * 4))
 
 #define	GPN_ID_CMD	0x112
 #define	GPN_ID_REQ_SIZE	(16 + 4)
@@ -2051,7 +2063,9 @@
 		} ga_nxt;
 
 		struct {
-			struct ct_sns_gid_pt_data entries[MAX_FIBRE_DEVICES];
+			/* Assume the largest number of targets for the union */
+			struct ct_sns_gid_pt_data
+			    entries[MAX_FIBRE_DEVICES_MAX];
 		} gid_pt;
 
 		struct {
@@ -2112,7 +2126,11 @@
 
 #define	GID_PT_SNS_SCMD_LEN	6
 #define	GID_PT_SNS_CMD_SIZE	28
-#define	GID_PT_SNS_DATA_SIZE	(MAX_FIBRE_DEVICES * 4 + 16)
+/*
+ * Assume MAX_FIBRE_DEVICES_2100 as these defines are only used with older
+ * adapters.
+ */
+#define	GID_PT_SNS_DATA_SIZE	(MAX_FIBRE_DEVICES_2100 * 4 + 16)
 
 #define	GPN_ID_SNS_SCMD_LEN	6
 #define	GPN_ID_SNS_CMD_SIZE	28
@@ -2160,7 +2178,6 @@
 	uint16_t loop_id;	/* ISP23XX         -- 6 bytes. */
 	uint16_t reserved_1;	/* ISP24XX         -- 8 bytes. */
 };
-#define GID_LIST_SIZE (sizeof(struct gid_list_info) * MAX_FIBRE_DEVICES)
 
 /* NPIV */
 typedef struct vport_info {
@@ -2261,6 +2278,7 @@
 #define QLA_MIDX_DEFAULT	0
 #define QLA_MIDX_RSP_Q		1
 #define QLA_PCI_MSIX_CONTROL	0xa2
+#define QLA_83XX_PCI_MSIX_CONTROL	0x92
 
 struct scsi_qla_host;
 
@@ -2341,7 +2359,7 @@
 #define QLA_MQ_SIZE 32
 #define QLA_MAX_QUEUES 256
 #define ISP_QUE_REG(ha, id) \
-	((ha->mqenable) ? \
+	((ha->mqenable || IS_QLA83XX(ha)) ? \
 	((void *)(ha->mqiobase) +\
 	(QLA_QUE_PAGE * id)) :\
 	((void *)(ha->iobase)))
@@ -2461,6 +2479,7 @@
 #define MIN_IOBASE_LEN          0x100
 /* Multi queue data structs */
 	device_reg_t __iomem *mqiobase;
+	device_reg_t __iomem *msixbase;
 	uint16_t        msix_count;
 	uint8_t         mqenable;
 	struct req_que **req_q_map;
@@ -2485,6 +2504,7 @@
 	atomic_t	loop_down_timer;         /* loop down timer */
 	uint8_t		link_down_timeout;       /* link down timeout */
 	uint16_t	max_loop_id;
+	uint16_t	max_fibre_devices;	/* Maximum number of targets */
 
 	uint16_t	fb_rev;
 	uint16_t	min_external_loopid;    /* First external loop Id */
@@ -2494,6 +2514,7 @@
 #define PORT_SPEED_2GB  0x01
 #define PORT_SPEED_4GB  0x03
 #define PORT_SPEED_8GB  0x04
+#define PORT_SPEED_16GB 0x05
 #define PORT_SPEED_10GB	0x13
 	uint16_t	link_data_rate;         /* F/W operating speed */
 
@@ -2515,6 +2536,8 @@
 #define PCI_DEVICE_ID_QLOGIC_ISP2532    0x2532
 #define PCI_DEVICE_ID_QLOGIC_ISP8432    0x8432
 #define PCI_DEVICE_ID_QLOGIC_ISP8001	0x8001
+#define PCI_DEVICE_ID_QLOGIC_ISP8031	0x8031
+#define PCI_DEVICE_ID_QLOGIC_ISP2031	0x2031
 	uint32_t	device_type;
 #define DT_ISP2100                      BIT_0
 #define DT_ISP2200                      BIT_1
@@ -2531,7 +2554,9 @@
 #define DT_ISP8432                      BIT_12
 #define DT_ISP8001			BIT_13
 #define DT_ISP8021			BIT_14
-#define DT_ISP_LAST			(DT_ISP8021 << 1)
+#define DT_ISP2031			BIT_15
+#define DT_ISP8031			BIT_16
+#define DT_ISP_LAST			(DT_ISP8031 << 1)
 
 #define DT_T10_PI                       BIT_25
 #define DT_IIDMA                        BIT_26
@@ -2555,26 +2580,30 @@
 #define IS_QLA2532(ha)  (DT_MASK(ha) & DT_ISP2532)
 #define IS_QLA8432(ha)  (DT_MASK(ha) & DT_ISP8432)
 #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_QLA2031(ha)	(DT_MASK(ha) & DT_ISP2031)
+#define IS_QLA8031(ha)	(DT_MASK(ha) & DT_ISP8031)
 
 #define IS_QLA23XX(ha)  (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
 			IS_QLA6312(ha) || IS_QLA6322(ha))
 #define IS_QLA24XX(ha)  (IS_QLA2422(ha) || IS_QLA2432(ha))
 #define IS_QLA54XX(ha)  (IS_QLA5422(ha) || IS_QLA5432(ha))
 #define IS_QLA25XX(ha)  (IS_QLA2532(ha))
+#define IS_QLA83XX(ha)	(IS_QLA2031(ha) || IS_QLA8031(ha))
 #define IS_QLA84XX(ha)  (IS_QLA8432(ha))
 #define IS_QLA24XX_TYPE(ha)     (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \
 				IS_QLA84XX(ha))
-#define IS_QLA81XX(ha)		(IS_QLA8001(ha))
-#define IS_QLA8XXX_TYPE(ha)	(IS_QLA81XX(ha) || IS_QLA82XX(ha))
+#define IS_CNA_CAPABLE(ha)	(IS_QLA81XX(ha) || IS_QLA82XX(ha) || \
+				IS_QLA8031(ha))
 #define IS_QLA2XXX_MIDTYPE(ha)	(IS_QLA24XX(ha) || IS_QLA84XX(ha) || \
 				IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
-				IS_QLA82XX(ha))
-#define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha))
-#define IS_NOPOLLING_TYPE(ha)	((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && \
-				(ha)->flags.msix_enabled)
-#define IS_FAC_REQUIRED(ha)	(IS_QLA81XX(ha))
-#define IS_NOCACHE_VPD_TYPE(ha)	(IS_QLA81XX(ha))
+				IS_QLA82XX(ha) || IS_QLA83XX(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)
+#define IS_FAC_REQUIRED(ha)	(IS_QLA81XX(ha) || IS_QLA83XX(ha))
+#define IS_NOCACHE_VPD_TYPE(ha)	(IS_QLA81XX(ha) || IS_QLA83XX(ha))
 #define IS_ALOGIO_CAPABLE(ha)	(IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha))
 
 #define IS_T10_PI_CAPABLE(ha)   ((ha)->device_type & DT_T10_PI)
@@ -2583,6 +2612,8 @@
 #define IS_ZIO_SUPPORTED(ha)    ((ha)->device_type & DT_ZIO_SUPPORTED)
 #define IS_OEM_001(ha)          ((ha)->device_type & DT_OEM_001)
 #define HAS_EXTENDED_IDS(ha)    ((ha)->device_type & DT_EXTENDED_IDS)
+#define IS_CT6_SUPPORTED(ha)	((ha)->device_type & DT_CT6_SUPPORTED)
+#define IS_MQUE_CAPABLE(ha)	((ha)->mqenable || IS_QLA83XX(ha))
 
 	/* HBA serial number */
 	uint8_t		serial0;
@@ -2621,10 +2652,6 @@
 	void		*sfp_data;
 	dma_addr_t	sfp_data_dma;
 
-	uint8_t		*edc_data;
-	dma_addr_t	edc_data_dma;
-	uint16_t	edc_data_len;
-
 #define XGMAC_DATA_SIZE	4096
 	void		*xgmac_data;
 	dma_addr_t	xgmac_data_dma;
@@ -2653,6 +2680,8 @@
 	void		*async_pd;
 	dma_addr_t	async_pd_dma;
 
+	void		*swl;
+
 	/* These are used by mailbox operations. */
 	volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT];
 
@@ -2674,6 +2703,8 @@
 	uint16_t	fw_minor_version;
 	uint16_t	fw_subminor_version;
 	uint16_t	fw_attributes;
+	uint16_t	fw_attributes_h;
+	uint16_t	fw_attributes_ext[2];
 	uint32_t	fw_memory_size;
 	uint32_t	fw_transfer_size;
 	uint32_t	fw_srisc_address;
@@ -2851,7 +2882,6 @@
 	volatile struct {
 		uint32_t	init_done		:1;
 		uint32_t	online			:1;
-		uint32_t	rscn_queue_overflow	:1;
 		uint32_t	reset_active		:1;
 
 		uint32_t	management_server_logged_in :1;
@@ -2905,11 +2935,6 @@
 
 
 
-	/* RSCN queue. */
-	uint32_t rscn_queue[MAX_RSCN_COUNT];
-	uint8_t rscn_in_ptr;
-	uint8_t rscn_out_ptr;
-
 	/* Timeout timers. */
 	uint8_t         loop_down_abort_time;    /* port down timer */
 	atomic_t        loop_down_timer;         /* loop down timer */
@@ -3005,7 +3030,6 @@
 #define QLA_ABORTED			0x105
 #define QLA_SUSPENDED			0x106
 #define QLA_BUSY			0x107
-#define QLA_RSCNS_HANDLED		0x108
 #define QLA_ALREADY_REGISTERED		0x109
 
 #define NVRAM_DELAY()		udelay(10)
@@ -3021,6 +3045,7 @@
 #define OPTROM_SIZE_25XX	0x200000
 #define OPTROM_SIZE_81XX	0x400000
 #define OPTROM_SIZE_82XX	0x800000
+#define OPTROM_SIZE_83XX	0x1000000
 
 #define OPTROM_BURST_SIZE	0x1000
 #define OPTROM_BURST_DWORDS	(OPTROM_BURST_SIZE / 4)
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 0b4c2b7..499c74e 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -114,7 +114,7 @@
 {
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
+	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha))
 		goto out;
 	if (!ha->fce)
 		goto out;
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index aa69486..6d7d775 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1327,6 +1327,11 @@
 #define FLT_REG_GOLD_FW		0x2f
 #define FLT_REG_FCP_PRIO_0	0x87
 #define FLT_REG_FCP_PRIO_1	0x88
+#define FLT_REG_FCOE_FW		0xA4
+#define FLT_REG_FCOE_VPD_0	0xA9
+#define FLT_REG_FCOE_NVRAM_0	0xAA
+#define FLT_REG_FCOE_VPD_1	0xAB
+#define FLT_REG_FCOE_NVRAM_1	0xAC
 
 struct qla_flt_region {
 	uint32_t code;
@@ -1494,6 +1499,11 @@
 #define MBC_GET_XGMAC_STATS	0x7a
 #define MBC_GET_DCBX_PARAMS	0x51
 
+/*
+ * ISP83xx mailbox commands
+ */
+#define MBC_WRITE_REMOTE_REG 0x0001 /* Write remote register */
+
 /* Flash access control option field bit definitions */
 #define FAC_OPT_FORCE_SEMAPHORE		BIT_15
 #define FAC_OPT_REQUESTOR_ID		BIT_14
@@ -1875,4 +1885,7 @@
 #define FA_NPIV_CONF0_ADDR_81	0xD1000
 #define FA_NPIV_CONF1_ADDR_81	0xD2000
 
+/* 83XX Flash locations -- occupies second 8MB region. */
+#define FA_FLASH_LAYOUT_ADDR_83	0xFC400
+
 #endif
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 408679b..9f06580 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -71,8 +71,6 @@
     uint16_t *);
 extern void qla2x00_async_adisc_done(struct scsi_qla_host *, fc_port_t *,
     uint16_t *);
-extern void qla2x00_async_tm_cmd_done(struct scsi_qla_host *, fc_port_t *,
-	struct srb_iocb *);
 extern void *qla2x00_alloc_iocbs(struct scsi_qla_host *, srb_t *);
 extern int qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *, fc_port_t *);
 
@@ -156,8 +154,7 @@
 extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *);
 extern scsi_qla_host_t * qla24xx_create_vhost(struct fc_vport *);
 
-extern void qla2x00_sp_compl(struct qla_hw_data *, srb_t *);
-
+extern void qla2x00_sp_free_dma(void *, void *);
 extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
 
 extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int, int);
@@ -205,8 +202,7 @@
 qla2x00_execute_fw(scsi_qla_host_t *, uint32_t);
 
 extern int
-qla2x00_get_fw_version(scsi_qla_host_t *, uint16_t *, uint16_t *, uint16_t *,
-    uint16_t *, uint32_t *, uint8_t *, uint32_t *, uint8_t *);
+qla2x00_get_fw_version(scsi_qla_host_t *);
 
 extern int
 qla2x00_get_fw_options(scsi_qla_host_t *, uint16_t *);
@@ -371,6 +367,9 @@
 extern int
 qla81xx_set_port_config(scsi_qla_host_t *, uint16_t *);
 
+extern int
+qla2x00_port_logout(scsi_qla_host_t *, struct fc_port *);
+
 /*
  * Global Function Prototypes in qla_isr.c source file.
  */
@@ -409,8 +408,10 @@
 extern int qla24xx_beacon_on(struct scsi_qla_host *);
 extern int qla24xx_beacon_off(struct scsi_qla_host *);
 extern void qla24xx_beacon_blink(struct scsi_qla_host *);
+extern void qla83xx_beacon_blink(struct scsi_qla_host *);
 extern int qla82xx_beacon_on(struct scsi_qla_host *);
 extern int qla82xx_beacon_off(struct scsi_qla_host *);
+extern int qla83xx_write_remote_reg(struct scsi_qla_host *, uint32_t, uint32_t);
 
 extern uint8_t *qla2x00_read_optrom_data(struct scsi_qla_host *, uint8_t *,
     uint32_t, uint32_t);
@@ -541,6 +542,10 @@
 
 /* IOCB related functions */
 extern int qla82xx_start_scsi(srb_t *);
+extern void qla2x00_sp_free(void *, void *);
+extern void qla2x00_sp_timeout(unsigned long);
+extern void qla2x00_bsg_job_done(void *, void *, int);
+extern void qla2x00_bsg_sp_free(void *, void *);
 
 /* Interrupt related */
 extern irqreturn_t qla82xx_intr_handler(int, void *);
@@ -576,6 +581,8 @@
 extern int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *);
 extern int qla82xx_check_md_needed(scsi_qla_host_t *);
 extern void qla82xx_chip_reset_cleanup(scsi_qla_host_t *);
+extern int qla81xx_set_led_config(scsi_qla_host_t *, uint16_t *);
+extern int qla81xx_get_led_config(scsi_qla_host_t *, uint16_t *);
 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 *);
@@ -589,6 +596,9 @@
 extern int qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t,
 	uint16_t *, uint16_t *);
 
+/* 83xx related functions */
+extern void qla83xx_fw_dump(scsi_qla_host_t *, int);
+
 /* Minidump related functions */
 extern int qla82xx_md_get_template_size(scsi_qla_host_t *);
 extern int qla82xx_md_get_template(scsi_qla_host_t *);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 4aea4ae..3128f80 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -240,6 +240,12 @@
 	return (rval);
 }
 
+static inline int
+qla2x00_gid_pt_rsp_size(scsi_qla_host_t *vha)
+{
+	return vha->hw->max_fibre_devices * 4 + 16;
+}
+
 /**
  * qla2x00_gid_pt() - SNS scan for fabric devices via GID_PT command.
  * @ha: HA context
@@ -261,20 +267,21 @@
 
 	struct ct_sns_gid_pt_data *gid_data;
 	struct qla_hw_data *ha = vha->hw;
+	uint16_t gid_pt_rsp_size;
 
 	if (IS_QLA2100(ha) || IS_QLA2200(ha))
 		return qla2x00_sns_gid_pt(vha, list);
 
 	gid_data = NULL;
-
+	gid_pt_rsp_size = qla2x00_gid_pt_rsp_size(vha);
 	/* Issue GID_PT */
 	/* Prepare common MS IOCB */
 	ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GID_PT_REQ_SIZE,
-	    GID_PT_RSP_SIZE);
+	    gid_pt_rsp_size);
 
 	/* Prepare CT request */
 	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GID_PT_CMD,
-	    GID_PT_RSP_SIZE);
+	    gid_pt_rsp_size);
 	ct_rsp = &ha->ct_sns->p.rsp;
 
 	/* Prepare CT arguments -- port_type */
@@ -292,7 +299,7 @@
 		rval = QLA_FUNCTION_FAILED;
 	} else {
 		/* Set port IDs in switch info list. */
-		for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+		for (i = 0; i < ha->max_fibre_devices; i++) {
 			gid_data = &ct_rsp->rsp.gid_pt.entries[i];
 			list[i].d_id.b.domain = gid_data->port_id[0];
 			list[i].d_id.b.area = gid_data->port_id[1];
@@ -313,7 +320,7 @@
 		 * single call.  Return a failed status, and let GA_NXT handle
 		 * the overload.
 		 */
-		if (i == MAX_FIBRE_DEVICES)
+		if (i == ha->max_fibre_devices)
 			rval = QLA_FUNCTION_FAILED;
 	}
 
@@ -330,7 +337,7 @@
 int
 qla2x00_gpn_id(scsi_qla_host_t *vha, sw_info_t *list)
 {
-	int		rval;
+	int		rval = QLA_SUCCESS;
 	uint16_t	i;
 
 	ms_iocb_entry_t	*ms_pkt;
@@ -341,7 +348,7 @@
 	if (IS_QLA2100(ha) || IS_QLA2200(ha))
 		return qla2x00_sns_gpn_id(vha, list);
 
-	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+	for (i = 0; i < ha->max_fibre_devices; i++) {
 		/* Issue GPN_ID */
 		/* Prepare common MS IOCB */
 		ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GPN_ID_REQ_SIZE,
@@ -364,9 +371,11 @@
 			/*EMPTY*/
 			ql_dbg(ql_dbg_disc, vha, 0x2056,
 			    "GPN_ID issue IOCB failed (%d).\n", rval);
+			break;
 		} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
 		    "GPN_ID") != QLA_SUCCESS) {
 			rval = QLA_FUNCTION_FAILED;
+			break;
 		} else {
 			/* Save portname */
 			memcpy(list[i].port_name,
@@ -391,7 +400,7 @@
 int
 qla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
 {
-	int		rval;
+	int		rval = QLA_SUCCESS;
 	uint16_t	i;
 	struct qla_hw_data *ha = vha->hw;
 	ms_iocb_entry_t	*ms_pkt;
@@ -401,7 +410,7 @@
 	if (IS_QLA2100(ha) || IS_QLA2200(ha))
 		return qla2x00_sns_gnn_id(vha, list);
 
-	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+	for (i = 0; i < ha->max_fibre_devices; i++) {
 		/* Issue GNN_ID */
 		/* Prepare common MS IOCB */
 		ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GNN_ID_REQ_SIZE,
@@ -424,9 +433,11 @@
 			/*EMPTY*/
 			ql_dbg(ql_dbg_disc, vha, 0x2057,
 			    "GNN_ID issue IOCB failed (%d).\n", rval);
+			break;
 		} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
 		    "GNN_ID") != QLA_SUCCESS) {
 			rval = QLA_FUNCTION_FAILED;
+			break;
 		} else {
 			/* Save nodename */
 			memcpy(list[i].node_name,
@@ -735,7 +746,7 @@
 static int
 qla2x00_sns_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
 {
-	int		rval;
+	int		rval = QLA_SUCCESS;
 	struct qla_hw_data *ha = vha->hw;
 	struct sns_cmd_pkt	*sns_cmd;
 
@@ -814,11 +825,14 @@
 	uint16_t	i;
 	uint8_t		*entry;
 	struct sns_cmd_pkt	*sns_cmd;
+	uint16_t gid_pt_sns_data_size;
+
+	gid_pt_sns_data_size = qla2x00_gid_pt_rsp_size(vha);
 
 	/* Issue GID_PT. */
 	/* Prepare SNS command request. */
 	sns_cmd = qla2x00_prep_sns_cmd(vha, GID_PT_CMD, GID_PT_SNS_SCMD_LEN,
-	    GID_PT_SNS_DATA_SIZE);
+	    gid_pt_sns_data_size);
 
 	/* Prepare SNS command arguments -- port_type. */
 	sns_cmd->p.cmd.param[0] = NS_NX_PORT_TYPE;
@@ -839,7 +853,7 @@
 		rval = QLA_FUNCTION_FAILED;
 	} else {
 		/* Set port IDs in switch info list. */
-		for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+		for (i = 0; i < ha->max_fibre_devices; i++) {
 			entry = &sns_cmd->p.gid_data[(i * 4) + 16];
 			list[i].d_id.b.domain = entry[1];
 			list[i].d_id.b.area = entry[2];
@@ -858,7 +872,7 @@
 		 * single call.  Return a failed status, and let GA_NXT handle
 		 * the overload.
 		 */
-		if (i == MAX_FIBRE_DEVICES)
+		if (i == ha->max_fibre_devices)
 			rval = QLA_FUNCTION_FAILED;
 	}
 
@@ -877,12 +891,12 @@
 static int
 qla2x00_sns_gpn_id(scsi_qla_host_t *vha, sw_info_t *list)
 {
-	int		rval;
+	int		rval = QLA_SUCCESS;
 	struct qla_hw_data *ha = vha->hw;
 	uint16_t	i;
 	struct sns_cmd_pkt	*sns_cmd;
 
-	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+	for (i = 0; i < ha->max_fibre_devices; i++) {
 		/* Issue GPN_ID */
 		/* Prepare SNS command request. */
 		sns_cmd = qla2x00_prep_sns_cmd(vha, GPN_ID_CMD,
@@ -933,12 +947,12 @@
 static int
 qla2x00_sns_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
 {
-	int		rval;
+	int		rval = QLA_SUCCESS;
 	struct qla_hw_data *ha = vha->hw;
 	uint16_t	i;
 	struct sns_cmd_pkt	*sns_cmd;
 
-	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+	for (i = 0; i < ha->max_fibre_devices; i++) {
 		/* Issue GNN_ID */
 		/* Prepare SNS command request. */
 		sns_cmd = qla2x00_prep_sns_cmd(vha, GNN_ID_CMD,
@@ -1107,20 +1121,26 @@
 static int
 qla2x00_mgmt_svr_login(scsi_qla_host_t *vha)
 {
-	int ret;
+	int ret, rval;
 	uint16_t mb[MAILBOX_REGISTER_COUNT];
 	struct qla_hw_data *ha = vha->hw;
 	ret = QLA_SUCCESS;
 	if (vha->flags.management_server_logged_in)
 		return ret;
 
-	ha->isp_ops->fabric_login(vha, vha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa,
-	    mb, BIT_1|BIT_0);
-	if (mb[0] != MBS_COMMAND_COMPLETE) {
-		ql_dbg(ql_dbg_disc, vha, 0x2024,
-		    "Failed management_server login: loopid=%x mb[0]=%x "
-		    "mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x.\n",
-		    vha->mgmt_svr_loop_id, mb[0], mb[1], mb[2], mb[6], mb[7]);
+	rval = ha->isp_ops->fabric_login(vha, vha->mgmt_svr_loop_id, 0xff, 0xff,
+	    0xfa, mb, BIT_1|BIT_0);
+	if (rval != QLA_SUCCESS || mb[0] != MBS_COMMAND_COMPLETE) {
+		if (rval == QLA_MEMORY_ALLOC_FAILED)
+			ql_dbg(ql_dbg_disc, vha, 0x2085,
+			    "Failed management_server login: loopid=%x "
+			    "rval=%d\n", vha->mgmt_svr_loop_id, rval);
+		else
+			ql_dbg(ql_dbg_disc, vha, 0x2024,
+			    "Failed management_server login: loopid=%x "
+			    "mb[0]=%x mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x.\n",
+			    vha->mgmt_svr_loop_id, mb[0], mb[1], mb[2], mb[6],
+			    mb[7]);
 		ret = QLA_FUNCTION_FAILED;
 	} else
 		vha->flags.management_server_logged_in = 1;
@@ -1547,7 +1567,7 @@
 	eiter = (struct ct_fdmi_port_attr *) (entries + size);
 	eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED);
 	eiter->len = __constant_cpu_to_be16(4 + 4);
-	if (IS_QLA8XXX_TYPE(ha))
+	if (IS_CNA_CAPABLE(ha))
 		eiter->a.sup_speed = __constant_cpu_to_be32(
 		    FDMI_PORT_SPEED_10GB);
 	else if (IS_QLA25XX(ha))
@@ -1594,6 +1614,10 @@
 		eiter->a.cur_speed =
 		    __constant_cpu_to_be32(FDMI_PORT_SPEED_10GB);
 		break;
+	case PORT_SPEED_16GB:
+		eiter->a.cur_speed =
+		    __constant_cpu_to_be32(FDMI_PORT_SPEED_16GB);
+		break;
 	default:
 		eiter->a.cur_speed =
 		    __constant_cpu_to_be32(FDMI_PORT_SPEED_UNKNOWN);
@@ -1724,7 +1748,7 @@
 int
 qla2x00_gfpn_id(scsi_qla_host_t *vha, sw_info_t *list)
 {
-	int		rval;
+	int		rval = QLA_SUCCESS;
 	uint16_t	i;
 	struct qla_hw_data *ha = vha->hw;
 	ms_iocb_entry_t	*ms_pkt;
@@ -1734,7 +1758,7 @@
 	if (!IS_IIDMA_CAPABLE(ha))
 		return QLA_FUNCTION_FAILED;
 
-	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+	for (i = 0; i < ha->max_fibre_devices; i++) {
 		/* Issue GFPN_ID */
 		/* Prepare common MS IOCB */
 		ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GFPN_ID_REQ_SIZE,
@@ -1757,9 +1781,11 @@
 			/*EMPTY*/
 			ql_dbg(ql_dbg_disc, vha, 0x2023,
 			    "GFPN_ID issue IOCB failed (%d).\n", rval);
+			break;
 		} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
 		    "GFPN_ID") != QLA_SUCCESS) {
 			rval = QLA_FUNCTION_FAILED;
+			break;
 		} else {
 			/* Save fabric portname */
 			memcpy(list[i].fabric_port_name,
@@ -1846,7 +1872,7 @@
 	if (rval)
 		return rval;
 
-	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+	for (i = 0; i < ha->max_fibre_devices; i++) {
 		/* Issue GFPN_ID */
 		/* Prepare common MS IOCB */
 		ms_pkt = qla24xx_prep_ms_fm_iocb(vha, GPSC_REQ_SIZE,
@@ -1947,7 +1973,7 @@
 	struct qla_hw_data *ha = vha->hw;
 	uint8_t fcp_scsi_features = 0;
 
-	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+	for (i = 0; i < ha->max_fibre_devices; i++) {
 		/* Set default FC4 Type as UNKNOWN so the default is to
 		 * Process this port */
 		list[i].fc4_type = FC4_TYPE_UNKNOWN;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 1fa067e..b946564 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -29,7 +29,6 @@
 static int qla2x00_configure_local_loop(scsi_qla_host_t *);
 static int qla2x00_configure_fabric(scsi_qla_host_t *);
 static int qla2x00_find_all_fabric_devs(scsi_qla_host_t *, struct list_head *);
-static int qla2x00_device_resync(scsi_qla_host_t *);
 static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *,
     uint16_t *);
 
@@ -41,11 +40,10 @@
 
 /* SRB Extensions ---------------------------------------------------------- */
 
-static void
-qla2x00_ctx_sp_timeout(unsigned long __data)
+void
+qla2x00_sp_timeout(unsigned long __data)
 {
 	srb_t *sp = (srb_t *)__data;
-	struct srb_ctx *ctx;
 	struct srb_iocb *iocb;
 	fc_port_t *fcport = sp->fcport;
 	struct qla_hw_data *ha = fcport->vha->hw;
@@ -55,79 +53,25 @@
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	req = ha->req_q_map[0];
 	req->outstanding_cmds[sp->handle] = NULL;
-	ctx = sp->ctx;
-	iocb = ctx->u.iocb_cmd;
+	iocb = &sp->u.iocb_cmd;
 	iocb->timeout(sp);
-	iocb->free(sp);
+	sp->free(fcport->vha, sp);
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
-static void
-qla2x00_ctx_sp_free(srb_t *sp)
+void
+qla2x00_sp_free(void *data, void *ptr)
 {
-	struct srb_ctx *ctx = sp->ctx;
-	struct srb_iocb *iocb = ctx->u.iocb_cmd;
-	struct scsi_qla_host *vha = sp->fcport->vha;
+	srb_t *sp = (srb_t *)ptr;
+	struct srb_iocb *iocb = &sp->u.iocb_cmd;
+	struct scsi_qla_host *vha = (scsi_qla_host_t *)data;
 
 	del_timer(&iocb->timer);
-	kfree(iocb);
-	kfree(ctx);
-	mempool_free(sp, sp->fcport->vha->hw->srb_mempool);
+	mempool_free(sp, vha->hw->srb_mempool);
 
 	QLA_VHA_MARK_NOT_BUSY(vha);
 }
 
-inline srb_t *
-qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size,
-    unsigned long tmo)
-{
-	srb_t *sp = NULL;
-	struct qla_hw_data *ha = vha->hw;
-	struct srb_ctx *ctx;
-	struct srb_iocb *iocb;
-	uint8_t bail;
-
-	QLA_VHA_MARK_BUSY(vha, bail);
-	if (bail)
-		return NULL;
-
-	sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL);
-	if (!sp)
-		goto done;
-	ctx = kzalloc(size, GFP_KERNEL);
-	if (!ctx) {
-		mempool_free(sp, ha->srb_mempool);
-		sp = NULL;
-		goto done;
-	}
-	iocb = kzalloc(sizeof(struct srb_iocb), GFP_KERNEL);
-	if (!iocb) {
-		mempool_free(sp, ha->srb_mempool);
-		sp = NULL;
-		kfree(ctx);
-		goto done;
-	}
-
-	memset(sp, 0, sizeof(*sp));
-	sp->fcport = fcport;
-	sp->ctx = ctx;
-	ctx->iocbs = 1;
-	ctx->u.iocb_cmd = iocb;
-	iocb->free = qla2x00_ctx_sp_free;
-
-	init_timer(&iocb->timer);
-	if (!tmo)
-		goto done;
-	iocb->timer.expires = jiffies + tmo * HZ;
-	iocb->timer.data = (unsigned long)sp;
-	iocb->timer.function = qla2x00_ctx_sp_timeout;
-	add_timer(&iocb->timer);
-done:
-	if (!sp)
-		QLA_VHA_MARK_NOT_BUSY(vha);
-	return sp;
-}
-
 /* Asynchronous Login/Logout Routines -------------------------------------- */
 
 static inline unsigned long
@@ -149,19 +93,19 @@
 }
 
 static void
-qla2x00_async_iocb_timeout(srb_t *sp)
+qla2x00_async_iocb_timeout(void *data)
 {
+	srb_t *sp = (srb_t *)data;
 	fc_port_t *fcport = sp->fcport;
-	struct srb_ctx *ctx = sp->ctx;
 
 	ql_dbg(ql_dbg_disc, fcport->vha, 0x2071,
 	    "Async-%s timeout - hdl=%x portid=%02x%02x%02x.\n",
-	    ctx->name, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area,
+	    sp->name, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area,
 	    fcport->d_id.b.al_pa);
 
 	fcport->flags &= ~FCF_ASYNC_SENT;
-	if (ctx->type == SRB_LOGIN_CMD) {
-		struct srb_iocb *lio = ctx->u.iocb_cmd;
+	if (sp->type == SRB_LOGIN_CMD) {
+		struct srb_iocb *lio = &sp->u.iocb_cmd;
 		qla2x00_post_async_logout_work(fcport->vha, fcport, NULL);
 		/* Retry as needed. */
 		lio->u.logio.data[0] = MBS_COMMAND_ERROR;
@@ -173,14 +117,16 @@
 }
 
 static void
-qla2x00_async_login_ctx_done(srb_t *sp)
+qla2x00_async_login_sp_done(void *data, void *ptr, int res)
 {
-	struct srb_ctx *ctx = sp->ctx;
-	struct srb_iocb *lio = ctx->u.iocb_cmd;
+	srb_t *sp = (srb_t *)ptr;
+	struct srb_iocb *lio = &sp->u.iocb_cmd;
+	struct scsi_qla_host *vha = (scsi_qla_host_t *)data;
 
-	qla2x00_post_async_login_done_work(sp->fcport->vha, sp->fcport,
-		lio->u.logio.data);
-	lio->free(sp);
+	if (!test_bit(UNLOADING, &vha->dpc_flags))
+		qla2x00_post_async_login_done_work(sp->fcport->vha, sp->fcport,
+		    lio->u.logio.data);
+	sp->free(sp->fcport->vha, sp);
 }
 
 int
@@ -188,22 +134,21 @@
     uint16_t *data)
 {
 	srb_t *sp;
-	struct srb_ctx *ctx;
 	struct srb_iocb *lio;
 	int rval;
 
 	rval = QLA_FUNCTION_FAILED;
-	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
-	    qla2x00_get_async_timeout(vha) + 2);
+	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
 	if (!sp)
 		goto done;
 
-	ctx = sp->ctx;
-	ctx->type = SRB_LOGIN_CMD;
-	ctx->name = "login";
-	lio = ctx->u.iocb_cmd;
+	sp->type = SRB_LOGIN_CMD;
+	sp->name = "login";
+	qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
+
+	lio = &sp->u.iocb_cmd;
 	lio->timeout = qla2x00_async_iocb_timeout;
-	lio->done = qla2x00_async_login_ctx_done;
+	sp->done = qla2x00_async_login_sp_done;
 	lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;
 	if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
 		lio->u.logio.flags |= SRB_LOGIN_RETRIED;
@@ -219,42 +164,43 @@
 	return rval;
 
 done_free_sp:
-	lio->free(sp);
+	sp->free(fcport->vha, sp);
 done:
 	return rval;
 }
 
 static void
-qla2x00_async_logout_ctx_done(srb_t *sp)
+qla2x00_async_logout_sp_done(void *data, void *ptr, int res)
 {
-	struct srb_ctx *ctx = sp->ctx;
-	struct srb_iocb *lio = ctx->u.iocb_cmd;
+	srb_t *sp = (srb_t *)ptr;
+	struct srb_iocb *lio = &sp->u.iocb_cmd;
+	struct scsi_qla_host *vha = (scsi_qla_host_t *)data;
 
-	qla2x00_post_async_logout_done_work(sp->fcport->vha, sp->fcport,
-	    lio->u.logio.data);
-	lio->free(sp);
+	if (!test_bit(UNLOADING, &vha->dpc_flags))
+		qla2x00_post_async_logout_done_work(sp->fcport->vha, sp->fcport,
+		    lio->u.logio.data);
+	sp->free(sp->fcport->vha, sp);
 }
 
 int
 qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
 {
 	srb_t *sp;
-	struct srb_ctx *ctx;
 	struct srb_iocb *lio;
 	int rval;
 
 	rval = QLA_FUNCTION_FAILED;
-	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
-	    qla2x00_get_async_timeout(vha) + 2);
+	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
 	if (!sp)
 		goto done;
 
-	ctx = sp->ctx;
-	ctx->type = SRB_LOGOUT_CMD;
-	ctx->name = "logout";
-	lio = ctx->u.iocb_cmd;
+	sp->type = SRB_LOGOUT_CMD;
+	sp->name = "logout";
+	qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
+
+	lio = &sp->u.iocb_cmd;
 	lio->timeout = qla2x00_async_iocb_timeout;
-	lio->done = qla2x00_async_logout_ctx_done;
+	sp->done = qla2x00_async_logout_sp_done;
 	rval = qla2x00_start_sp(sp);
 	if (rval != QLA_SUCCESS)
 		goto done_free_sp;
@@ -266,20 +212,22 @@
 	return rval;
 
 done_free_sp:
-	lio->free(sp);
+	sp->free(fcport->vha, sp);
 done:
 	return rval;
 }
 
 static void
-qla2x00_async_adisc_ctx_done(srb_t *sp)
+qla2x00_async_adisc_sp_done(void *data, void *ptr, int res)
 {
-	struct srb_ctx *ctx = sp->ctx;
-	struct srb_iocb *lio = ctx->u.iocb_cmd;
+	srb_t *sp = (srb_t *)ptr;
+	struct srb_iocb *lio = &sp->u.iocb_cmd;
+	struct scsi_qla_host *vha = (scsi_qla_host_t *)data;
 
-	qla2x00_post_async_adisc_done_work(sp->fcport->vha, sp->fcport,
-	    lio->u.logio.data);
-	lio->free(sp);
+	if (!test_bit(UNLOADING, &vha->dpc_flags))
+		qla2x00_post_async_adisc_done_work(sp->fcport->vha, sp->fcport,
+		    lio->u.logio.data);
+	sp->free(sp->fcport->vha, sp);
 }
 
 int
@@ -287,22 +235,21 @@
     uint16_t *data)
 {
 	srb_t *sp;
-	struct srb_ctx *ctx;
 	struct srb_iocb *lio;
 	int rval;
 
 	rval = QLA_FUNCTION_FAILED;
-	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
-	    qla2x00_get_async_timeout(vha) + 2);
+	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
 	if (!sp)
 		goto done;
 
-	ctx = sp->ctx;
-	ctx->type = SRB_ADISC_CMD;
-	ctx->name = "adisc";
-	lio = ctx->u.iocb_cmd;
+	sp->type = SRB_ADISC_CMD;
+	sp->name = "adisc";
+	qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
+
+	lio = &sp->u.iocb_cmd;
 	lio->timeout = qla2x00_async_iocb_timeout;
-	lio->done = qla2x00_async_adisc_ctx_done;
+	sp->done = qla2x00_async_adisc_sp_done;
 	if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
 		lio->u.logio.flags |= SRB_LOGIN_RETRIED;
 	rval = qla2x00_start_sp(sp);
@@ -316,46 +263,62 @@
 	return rval;
 
 done_free_sp:
-	lio->free(sp);
+	sp->free(fcport->vha, sp);
 done:
 	return rval;
 }
 
 static void
-qla2x00_async_tm_cmd_ctx_done(srb_t *sp)
+qla2x00_async_tm_cmd_done(void *data, void *ptr, int res)
 {
-	struct srb_ctx *ctx = sp->ctx;
-	struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd;
+	srb_t *sp = (srb_t *)ptr;
+	struct srb_iocb *iocb = &sp->u.iocb_cmd;
+	struct scsi_qla_host *vha = (scsi_qla_host_t *)data;
+	uint32_t flags;
+	uint16_t lun;
+	int rval;
 
-	qla2x00_async_tm_cmd_done(sp->fcport->vha, sp->fcport, iocb);
-	iocb->free(sp);
+	if (!test_bit(UNLOADING, &vha->dpc_flags)) {
+		flags = iocb->u.tmf.flags;
+		lun = (uint16_t)iocb->u.tmf.lun;
+
+		/* Issue Marker IOCB */
+		rval = qla2x00_marker(vha, vha->hw->req_q_map[0],
+			vha->hw->rsp_q_map[0], sp->fcport->loop_id, lun,
+			flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
+
+		if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) {
+			ql_dbg(ql_dbg_taskm, vha, 0x8030,
+			    "TM IOCB failed (%x).\n", rval);
+		}
+	}
+	sp->free(sp->fcport->vha, sp);
 }
 
 int
-qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
+qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t tm_flags, uint32_t lun,
 	uint32_t tag)
 {
 	struct scsi_qla_host *vha = fcport->vha;
 	srb_t *sp;
-	struct srb_ctx *ctx;
 	struct srb_iocb *tcf;
 	int rval;
 
 	rval = QLA_FUNCTION_FAILED;
-	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
-	    qla2x00_get_async_timeout(vha) + 2);
+	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
 	if (!sp)
 		goto done;
 
-	ctx = sp->ctx;
-	ctx->type = SRB_TM_CMD;
-	ctx->name = "tmf";
-	tcf = ctx->u.iocb_cmd;
-	tcf->u.tmf.flags = flags;
+	sp->type = SRB_TM_CMD;
+	sp->name = "tmf";
+	qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
+
+	tcf = &sp->u.iocb_cmd;
+	tcf->u.tmf.flags = tm_flags;
 	tcf->u.tmf.lun = lun;
 	tcf->u.tmf.data = tag;
 	tcf->timeout = qla2x00_async_iocb_timeout;
-	tcf->done = qla2x00_async_tm_cmd_ctx_done;
+	sp->done = qla2x00_async_tm_cmd_done;
 
 	rval = qla2x00_start_sp(sp);
 	if (rval != QLA_SUCCESS)
@@ -368,7 +331,7 @@
 	return rval;
 
 done_free_sp:
-	tcf->free(sp);
+	sp->free(fcport->vha, sp);
 done:
 	return rval;
 }
@@ -387,6 +350,13 @@
 		 * requests.
 		 */
 		rval = qla2x00_get_port_database(vha, fcport, 0);
+		if (rval == QLA_NOT_LOGGED_IN) {
+			fcport->flags &= ~FCF_ASYNC_SENT;
+			fcport->flags |= FCF_LOGIN_NEEDED;
+			set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
+			break;
+		}
+
 		if (rval != QLA_SUCCESS) {
 			qla2x00_post_async_logout_work(vha, fcport, NULL);
 			qla2x00_post_async_login_work(vha, fcport, NULL);
@@ -452,30 +422,6 @@
 	return;
 }
 
-void
-qla2x00_async_tm_cmd_done(struct scsi_qla_host *vha, fc_port_t *fcport,
-    struct srb_iocb *iocb)
-{
-	int rval;
-	uint32_t flags;
-	uint16_t lun;
-
-	flags = iocb->u.tmf.flags;
-	lun = (uint16_t)iocb->u.tmf.lun;
-
-	/* Issue Marker IOCB */
-	rval = qla2x00_marker(vha, vha->hw->req_q_map[0],
-		vha->hw->rsp_q_map[0], fcport->loop_id, lun,
-		flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
-
-	if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) {
-		ql_dbg(ql_dbg_taskm, vha, 0x8030,
-		    "TM IOCB failed (%x).\n", rval);
-	}
-
-	return;
-}
-
 /****************************************************************************/
 /*                QLogic ISP2x00 Hardware Support Functions.                */
 /****************************************************************************/
@@ -969,6 +915,9 @@
 {
 	uint16_t mb[4] = {0x1010, 0, 1, 0};
 
+	if (!IS_QLA81XX(vha->hw))
+		return QLA_SUCCESS;
+
 	return qla81xx_write_mpi_register(vha, mb);
 }
 
@@ -1262,7 +1211,9 @@
 		mem_size = (ha->fw_memory_size - 0x11000 + 1) *
 		    sizeof(uint16_t);
 	} else if (IS_FWI2_CAPABLE(ha)) {
-		if (IS_QLA81XX(ha))
+		if (IS_QLA83XX(ha))
+			fixed_size = offsetof(struct qla83xx_fw_dump, ext_mem);
+		else if (IS_QLA81XX(ha))
 			fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem);
 		else if (IS_QLA25XX(ha))
 			fixed_size = offsetof(struct qla25xx_fw_dump, ext_mem);
@@ -1270,10 +1221,20 @@
 			fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
 		mem_size = (ha->fw_memory_size - 0x100000 + 1) *
 		    sizeof(uint32_t);
-		if (ha->mqenable)
-			mq_size = sizeof(struct qla2xxx_mq_chain);
+		if (ha->mqenable) {
+			if (!IS_QLA83XX(ha))
+				mq_size = sizeof(struct qla2xxx_mq_chain);
+			/*
+			 * Allocate maximum buffer size for all queues.
+			 * Resizing must be done at end-of-dump processing.
+			 */
+			mq_size += ha->max_req_queues *
+			    (req->length * sizeof(request_t));
+			mq_size += ha->max_rsp_queues *
+			    (rsp->length * sizeof(response_t));
+		}
 		/* Allocate memory for Fibre Channel Event Buffer. */
-		if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
+		if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha))
 			goto try_eft;
 
 		tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
@@ -1484,17 +1445,8 @@
 				fw_major_version = ha->fw_major_version;
 				if (IS_QLA82XX(ha))
 					qla82xx_check_md_needed(vha);
-				else {
-					rval = qla2x00_get_fw_version(vha,
-					    &ha->fw_major_version,
-					    &ha->fw_minor_version,
-					    &ha->fw_subminor_version,
-					    &ha->fw_attributes,
-					    &ha->fw_memory_size,
-					    ha->mpi_version,
-					    &ha->mpi_capabilities,
-					    ha->phy_version);
-				}
+				else
+					rval = qla2x00_get_fw_version(vha);
 				if (rval != QLA_SUCCESS)
 					goto failed;
 				ha->flags.npiv_supported = 0;
@@ -1535,6 +1487,9 @@
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 	}
 
+	if (IS_QLA83XX(ha))
+		goto skip_fac_check;
+
 	if (rval == QLA_SUCCESS && IS_FAC_REQUIRED(ha)) {
 		uint32_t size;
 
@@ -1547,6 +1502,11 @@
 			    "Unsupported FAC firmware (%d.%02d.%02d).\n",
 			    ha->fw_major_version, ha->fw_minor_version,
 			    ha->fw_subminor_version);
+skip_fac_check:
+			if (IS_QLA83XX(ha)) {
+				ha->flags.fac_supported = 0;
+				rval = QLA_SUCCESS;
+			}
 		}
 	}
 failed:
@@ -1725,7 +1685,7 @@
 	struct req_que *req = ha->req_q_map[0];
 	struct rsp_que *rsp = ha->rsp_q_map[0];
 
-/* Setup ring parameters in initialization control block. */
+	/* Setup ring parameters in initialization control block. */
 	icb = (struct init_cb_24xx *)ha->init_cb;
 	icb->request_q_outpointer = __constant_cpu_to_le16(0);
 	icb->response_q_inpointer = __constant_cpu_to_le16(0);
@@ -1736,7 +1696,7 @@
 	icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
 	icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
 
-	if (ha->mqenable) {
+	if (ha->mqenable || IS_QLA83XX(ha)) {
 		icb->qos = __constant_cpu_to_le16(QLA_DEFAULT_QUE_QOS);
 		icb->rid = __constant_cpu_to_le16(rid);
 		if (ha->flags.msix_enabled) {
@@ -1756,7 +1716,8 @@
 				__constant_cpu_to_le32(BIT_18);
 
 		/* Use Disable MSIX Handshake mode for capable adapters */
-		if (IS_MSIX_NACK_CAPABLE(ha)) {
+		if ((ha->fw_attributes & BIT_6) && (IS_MSIX_NACK_CAPABLE(ha)) &&
+		    (ha->flags.msix_enabled)) {
 			icb->firmware_options_2 &=
 				__constant_cpu_to_le32(~BIT_22);
 			ha->flags.disable_msix_handshake = 1;
@@ -1800,7 +1761,6 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req;
 	struct rsp_que *rsp;
-	struct scsi_qla_host *vp;
 	struct mid_init_cb_24xx *mid_init_cb =
 	    (struct mid_init_cb_24xx *) ha->init_cb;
 
@@ -1831,11 +1791,6 @@
 	}
 
 	spin_lock(&ha->vport_slock);
-	/* Clear RSCN queue. */
-	list_for_each_entry(vp, &ha->vp_list, list) {
-		vp->rscn_in_ptr = 0;
-		vp->rscn_out_ptr = 0;
-	}
 
 	spin_unlock(&ha->vport_slock);
 
@@ -2028,7 +1983,7 @@
 	    &loop_id, &al_pa, &area, &domain, &topo, &sw_cap);
 	if (rval != QLA_SUCCESS) {
 		if (LOOP_TRANSITION(vha) || atomic_read(&ha->loop_down_timer) ||
-		    IS_QLA8XXX_TYPE(ha) ||
+		    IS_CNA_CAPABLE(ha) ||
 		    (rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
 			ql_dbg(ql_dbg_disc, vha, 0x2008,
 			    "Loop is in a transition state.\n");
@@ -2120,7 +2075,7 @@
 	uint16_t index;
 	struct qla_hw_data *ha = vha->hw;
 	int use_tbl = !IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
-	    !IS_QLA8XXX_TYPE(ha);
+	    !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha);
 
 	if (memcmp(model, BINZERO, len) != 0) {
 		strncpy(ha->model_number, model, len);
@@ -2596,13 +2551,11 @@
 	if (ha->current_topology == ISP_CFG_FL &&
 	    (test_bit(LOCAL_LOOP_UPDATE, &flags))) {
 
-		vha->flags.rscn_queue_overflow = 1;
 		set_bit(RSCN_UPDATE, &flags);
 
 	} else if (ha->current_topology == ISP_CFG_F &&
 	    (test_bit(LOCAL_LOOP_UPDATE, &flags))) {
 
-		vha->flags.rscn_queue_overflow = 1;
 		set_bit(RSCN_UPDATE, &flags);
 		clear_bit(LOCAL_LOOP_UPDATE, &flags);
 
@@ -2612,7 +2565,6 @@
 	} else if (!vha->flags.online ||
 	    (test_bit(ABORT_ISP_ACTIVE, &flags))) {
 
-		vha->flags.rscn_queue_overflow = 1;
 		set_bit(RSCN_UPDATE, &flags);
 		set_bit(LOCAL_LOOP_UPDATE, &flags);
 	}
@@ -2622,8 +2574,7 @@
 			ql_dbg(ql_dbg_disc, vha, 0x2015,
 			    "Loop resync needed, failing.\n");
 			rval = QLA_FUNCTION_FAILED;
-		}
-		else
+		} else
 			rval = qla2x00_configure_local_loop(vha);
 	}
 
@@ -2662,8 +2613,6 @@
 			set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
 		if (test_bit(RSCN_UPDATE, &save_flags)) {
 			set_bit(RSCN_UPDATE, &vha->dpc_flags);
-			if (!IS_ALOGIO_CAPABLE(ha))
-				vha->flags.rscn_queue_overflow = 1;
 		}
 	}
 
@@ -2699,7 +2648,7 @@
 
 	found_devs = 0;
 	new_fcport = NULL;
-	entries = MAX_FIBRE_DEVICES;
+	entries = MAX_FIBRE_DEVICES_LOOP;
 
 	ql_dbg(ql_dbg_disc, vha, 0x2016,
 	    "Getting FCAL position map.\n");
@@ -2707,7 +2656,7 @@
 		qla2x00_get_fcal_position_map(vha, NULL);
 
 	/* Get list of logged in devices. */
-	memset(ha->gid_list, 0, GID_LIST_SIZE);
+	memset(ha->gid_list, 0, qla2x00_gid_list_size(ha));
 	rval = qla2x00_get_id_list(vha, ha->gid_list, ha->gid_list_dma,
 	    &entries);
 	if (rval != QLA_SUCCESS)
@@ -2971,7 +2920,7 @@
 static int
 qla2x00_configure_fabric(scsi_qla_host_t *vha)
 {
-	int	rval, rval2;
+	int	rval;
 	fc_port_t	*fcport, *fcptemp;
 	uint16_t	next_loopid;
 	uint16_t	mb[MAILBOX_REGISTER_COUNT];
@@ -2995,12 +2944,6 @@
 	}
 	vha->device_flags |= SWITCH_FOUND;
 
-	/* Mark devices that need re-synchronization. */
-	rval2 = qla2x00_device_resync(vha);
-	if (rval2 == QLA_RSCNS_HANDLED) {
-		/* No point doing the scan, just continue. */
-		return (QLA_SUCCESS);
-	}
 	do {
 		/* FDMI support. */
 		if (ql2xfdmienable &&
@@ -3012,8 +2955,12 @@
 			loop_id = NPH_SNS;
 		else
 			loop_id = SIMPLE_NAME_SERVER;
-		ha->isp_ops->fabric_login(vha, loop_id, 0xff, 0xff,
-		    0xfc, mb, BIT_1 | BIT_0);
+		rval = ha->isp_ops->fabric_login(vha, loop_id, 0xff, 0xff,
+		    0xfc, mb, BIT_1|BIT_0);
+		if (rval != QLA_SUCCESS) {
+			set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+			return rval;
+		}
 		if (mb[0] != MBS_COMMAND_COMPLETE) {
 			ql_dbg(ql_dbg_disc, vha, 0x2042,
 			    "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x "
@@ -3044,6 +2991,13 @@
 			}
 		}
 
+#define QLA_FCPORT_SCAN		1
+#define QLA_FCPORT_FOUND	2
+
+		list_for_each_entry(fcport, &vha->vp_fcports, list) {
+			fcport->scan_state = QLA_FCPORT_SCAN;
+		}
+
 		rval = qla2x00_find_all_fabric_devs(vha, &new_fcports);
 		if (rval != QLA_SUCCESS)
 			break;
@@ -3059,7 +3013,8 @@
 			if ((fcport->flags & FCF_FABRIC_DEVICE) == 0)
 				continue;
 
-			if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
+			if (fcport->scan_state == QLA_FCPORT_SCAN &&
+			    atomic_read(&fcport->state) == FCS_ONLINE) {
 				qla2x00_mark_device_lost(vha, fcport,
 				    ql2xplogiabsentdevice, 0);
 				if (fcport->loop_id != FC_NO_LOOP_ID &&
@@ -3184,20 +3139,21 @@
 	rval = QLA_SUCCESS;
 
 	/* Try GID_PT to get device list, else GAN. */
-	swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_KERNEL);
+	if (!ha->swl)
+		ha->swl = kcalloc(ha->max_fibre_devices, sizeof(sw_info_t),
+		    GFP_KERNEL);
+	swl = ha->swl;
 	if (!swl) {
 		/*EMPTY*/
 		ql_dbg(ql_dbg_disc, vha, 0x2054,
 		    "GID_PT allocations failed, fallback on GA_NXT.\n");
 	} else {
+		memset(swl, 0, ha->max_fibre_devices * sizeof(sw_info_t));
 		if (qla2x00_gid_pt(vha, swl) != QLA_SUCCESS) {
-			kfree(swl);
 			swl = NULL;
 		} else if (qla2x00_gpn_id(vha, swl) != QLA_SUCCESS) {
-			kfree(swl);
 			swl = NULL;
 		} else if (qla2x00_gnn_id(vha, swl) != QLA_SUCCESS) {
-			kfree(swl);
 			swl = NULL;
 		} else if (ql2xiidmaenable &&
 		    qla2x00_gfpn_id(vha, swl) == QLA_SUCCESS) {
@@ -3215,7 +3171,6 @@
 	if (new_fcport == NULL) {
 		ql_log(ql_log_warn, vha, 0x205e,
 		    "Failed to allocate memory for fcport.\n");
-		kfree(swl);
 		return (QLA_MEMORY_ALLOC_FAILED);
 	}
 	new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
@@ -3332,6 +3287,8 @@
 			    WWN_SIZE))
 				continue;
 
+			fcport->scan_state = QLA_FCPORT_FOUND;
+
 			found++;
 
 			/* Update port state. */
@@ -3368,6 +3325,7 @@
 			fcport->flags |= FCF_LOGIN_NEEDED;
 			if (fcport->loop_id != FC_NO_LOOP_ID &&
 			    (fcport->flags & FCF_FCP2_DEVICE) == 0 &&
+			    (fcport->flags & FCF_ASYNC_SENT) == 0 &&
 			    fcport->port_type != FCT_INITIATOR &&
 			    fcport->port_type != FCT_BROADCAST) {
 				ha->isp_ops->fabric_logout(vha, fcport->loop_id,
@@ -3390,14 +3348,12 @@
 		if (new_fcport == NULL) {
 			ql_log(ql_log_warn, vha, 0x2066,
 			    "Memory allocation failed for fcport.\n");
-			kfree(swl);
 			return (QLA_MEMORY_ALLOC_FAILED);
 		}
 		new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
 		new_fcport->d_id.b24 = nxt_d_id.b24;
 	}
 
-	kfree(swl);
 	kfree(new_fcport);
 
 	return (rval);
@@ -3470,6 +3426,9 @@
 
 		/* If not in use then it is free to use. */
 		if (!found) {
+			ql_dbg(ql_dbg_disc, dev->vha, 0x2086,
+			    "Assigning new loopid=%x, portid=%x.\n",
+			    dev->loop_id, dev->d_id.b24);
 			break;
 		}
 
@@ -3488,110 +3447,6 @@
 }
 
 /*
- * qla2x00_device_resync
- *	Marks devices in the database that needs resynchronization.
- *
- * Input:
- *	ha = adapter block pointer.
- *
- * Context:
- *	Kernel context.
- */
-static int
-qla2x00_device_resync(scsi_qla_host_t *vha)
-{
-	int	rval;
-	uint32_t mask;
-	fc_port_t *fcport;
-	uint32_t rscn_entry;
-	uint8_t rscn_out_iter;
-	uint8_t format;
-	port_id_t d_id = {};
-
-	rval = QLA_RSCNS_HANDLED;
-
-	while (vha->rscn_out_ptr != vha->rscn_in_ptr ||
-	    vha->flags.rscn_queue_overflow) {
-
-		rscn_entry = vha->rscn_queue[vha->rscn_out_ptr];
-		format = MSB(MSW(rscn_entry));
-		d_id.b.domain = LSB(MSW(rscn_entry));
-		d_id.b.area = MSB(LSW(rscn_entry));
-		d_id.b.al_pa = LSB(LSW(rscn_entry));
-
-		ql_dbg(ql_dbg_disc, vha, 0x2020,
-		    "RSCN queue entry[%d] = [%02x/%02x%02x%02x].\n",
-		    vha->rscn_out_ptr, format, d_id.b.domain, d_id.b.area,
-		    d_id.b.al_pa);
-
-		vha->rscn_out_ptr++;
-		if (vha->rscn_out_ptr == MAX_RSCN_COUNT)
-			vha->rscn_out_ptr = 0;
-
-		/* Skip duplicate entries. */
-		for (rscn_out_iter = vha->rscn_out_ptr;
-		    !vha->flags.rscn_queue_overflow &&
-		    rscn_out_iter != vha->rscn_in_ptr;
-		    rscn_out_iter = (rscn_out_iter ==
-			(MAX_RSCN_COUNT - 1)) ? 0: rscn_out_iter + 1) {
-
-			if (rscn_entry != vha->rscn_queue[rscn_out_iter])
-				break;
-
-			ql_dbg(ql_dbg_disc, vha, 0x2021,
-			    "Skipping duplicate RSCN queue entry found at "
-			    "[%d].\n", rscn_out_iter);
-
-			vha->rscn_out_ptr = rscn_out_iter;
-		}
-
-		/* Queue overflow, set switch default case. */
-		if (vha->flags.rscn_queue_overflow) {
-			ql_dbg(ql_dbg_disc, vha, 0x2022,
-			    "device_resync: rscn overflow.\n");
-
-			format = 3;
-			vha->flags.rscn_queue_overflow = 0;
-		}
-
-		switch (format) {
-		case 0:
-			mask = 0xffffff;
-			break;
-		case 1:
-			mask = 0xffff00;
-			break;
-		case 2:
-			mask = 0xff0000;
-			break;
-		default:
-			mask = 0x0;
-			d_id.b24 = 0;
-			vha->rscn_out_ptr = vha->rscn_in_ptr;
-			break;
-		}
-
-		rval = QLA_SUCCESS;
-
-		list_for_each_entry(fcport, &vha->vp_fcports, list) {
-			if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
-			    (fcport->d_id.b24 & mask) != d_id.b24 ||
-			    fcport->port_type == FCT_BROADCAST)
-				continue;
-
-			if (atomic_read(&fcport->state) == FCS_ONLINE) {
-				if (format != 3 ||
-				    fcport->port_type != FCT_INITIATOR) {
-					qla2x00_mark_device_lost(vha, fcport,
-					    0, 0);
-				}
-			}
-		}
-	}
-	return (rval);
-}
-
-/*
  * qla2x00_fabric_dev_login
  *	Login fabric target device and update FC port database.
  *
@@ -3644,6 +3499,9 @@
 		} else {
 			qla2x00_update_fcport(vha, fcport);
 		}
+	} else {
+		/* Retry Login. */
+		qla2x00_mark_device_lost(vha, fcport, 1, 0);
 	}
 
 	return (rval);
@@ -3684,9 +3542,12 @@
 		    fcport->d_id.b.area, fcport->d_id.b.al_pa);
 
 		/* Login fcport on switch. */
-		ha->isp_ops->fabric_login(vha, fcport->loop_id,
+		rval = ha->isp_ops->fabric_login(vha, fcport->loop_id,
 		    fcport->d_id.b.domain, fcport->d_id.b.area,
 		    fcport->d_id.b.al_pa, mb, BIT_0);
+		if (rval != QLA_SUCCESS) {
+			return rval;
+		}
 		if (mb[0] == MBS_PORT_ID_USED) {
 			/*
 			 * Device has another loop ID.  The firmware team
@@ -4100,15 +3961,8 @@
 			ha->isp_abort_cnt = 0;
 			clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
 
-			if (IS_QLA81XX(ha))
-				qla2x00_get_fw_version(vha,
-				    &ha->fw_major_version,
-				    &ha->fw_minor_version,
-				    &ha->fw_subminor_version,
-				    &ha->fw_attributes, &ha->fw_memory_size,
-				    ha->mpi_version, &ha->mpi_capabilities,
-				    ha->phy_version);
-
+			if (IS_QLA81XX(ha) || IS_QLA8031(ha))
+				qla2x00_get_fw_version(vha);
 			if (ha->fce) {
 				ha->flags.fce_enabled = 1;
 				memset(ha->fce, 0,
@@ -4974,7 +4828,6 @@
 
 	ql_log(ql_log_info, vha, 0x009a, "Update operational firmware.\n");
 	ha->flags.running_gold_fw = 1;
-
 	return rval;
 }
 
@@ -5009,6 +4862,7 @@
 qla24xx_configure_vhba(scsi_qla_host_t *vha)
 {
 	int rval = QLA_SUCCESS;
+	int rval2;
 	uint16_t mb[MAILBOX_REGISTER_COUNT];
 	struct qla_hw_data *ha = vha->hw;
 	struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
@@ -5033,12 +4887,18 @@
 	vha->flags.management_server_logged_in = 0;
 
 	/* Login to SNS first */
-	ha->isp_ops->fabric_login(vha, NPH_SNS, 0xff, 0xff, 0xfc, mb, BIT_1);
-	if (mb[0] != MBS_COMMAND_COMPLETE) {
-		ql_dbg(ql_dbg_init, vha, 0x0103,
-		    "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x "
-		    "mb[6]=%x mb[7]=%x.\n",
-		    NPH_SNS, mb[0], mb[1], mb[2], mb[6], mb[7]);
+	rval2 = ha->isp_ops->fabric_login(vha, NPH_SNS, 0xff, 0xff, 0xfc, mb,
+	    BIT_1);
+	if (rval2 != QLA_SUCCESS || mb[0] != MBS_COMMAND_COMPLETE) {
+		if (rval2 == QLA_MEMORY_ALLOC_FAILED)
+			ql_dbg(ql_dbg_init, vha, 0x0120,
+			    "Failed SNS login: loop_id=%x, rval2=%d\n",
+			    NPH_SNS, rval2);
+		else
+			ql_dbg(ql_dbg_init, vha, 0x0103,
+			    "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
+			    "mb[2]=%x mb[6]=%x mb[7]=%x.\n",
+			    NPH_SNS, mb[0], mb[1], mb[2], mb[6], mb[7]);
 		return (QLA_FUNCTION_FAILED);
 	}
 
@@ -5214,10 +5074,10 @@
 		nv->reset_delay = 5;
 		nv->max_luns_per_target = __constant_cpu_to_le16(128);
 		nv->port_down_retry_count = __constant_cpu_to_le16(30);
-		nv->link_down_timeout = __constant_cpu_to_le16(30);
+		nv->link_down_timeout = __constant_cpu_to_le16(180);
 		nv->enode_mac[0] = 0x00;
-		nv->enode_mac[1] = 0x02;
-		nv->enode_mac[2] = 0x03;
+		nv->enode_mac[1] = 0xC0;
+		nv->enode_mac[2] = 0xDD;
 		nv->enode_mac[3] = 0x04;
 		nv->enode_mac[4] = 0x05;
 		nv->enode_mac[5] = 0x06 + ha->port_no;
@@ -5248,9 +5108,9 @@
 	memcpy(icb->enode_mac, nv->enode_mac, sizeof(icb->enode_mac));
 	/* Some boards (with valid NVRAMs) still have NULL enode_mac!! */
 	if (!memcmp(icb->enode_mac, "\0\0\0\0\0\0", sizeof(icb->enode_mac))) {
-		icb->enode_mac[0] = 0x01;
-		icb->enode_mac[1] = 0x02;
-		icb->enode_mac[2] = 0x03;
+		icb->enode_mac[0] = 0x00;
+		icb->enode_mac[1] = 0xC0;
+		icb->enode_mac[2] = 0xDD;
 		icb->enode_mac[3] = 0x04;
 		icb->enode_mac[4] = 0x05;
 		icb->enode_mac[5] = 0x06 + ha->port_no;
@@ -5353,6 +5213,10 @@
 	if (ql2xloginretrycount)
 		ha->login_retry_count = ql2xloginretrycount;
 
+	/* if not running MSI-X we need handshaking on interrupts */
+	if (!vha->hw->flags.msix_enabled && IS_QLA83XX(ha))
+		icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_22);
+
 	/* Enable ZIO. */
 	if (!vha->flags.init_done) {
 		ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 7cc4f36..6e45764 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -72,16 +72,19 @@
 qla2x00_clean_dsd_pool(struct qla_hw_data *ha, srb_t *sp)
 {
 	struct dsd_dma *dsd_ptr, *tdsd_ptr;
+	struct crc_context *ctx;
+
+	ctx = (struct crc_context *)GET_CMD_CTX_SP(sp);
 
 	/* clean up allocated prev pool */
 	list_for_each_entry_safe(dsd_ptr, tdsd_ptr,
-	    &((struct crc_context *)sp->ctx)->dsd_list, list) {
+	    &ctx->dsd_list, list) {
 		dma_pool_free(ha->dl_dma_pool, dsd_ptr->dsd_addr,
 		    dsd_ptr->dsd_list_dma);
 		list_del(&dsd_ptr->list);
 		kfree(dsd_ptr);
 	}
-	INIT_LIST_HEAD(&((struct crc_context *)sp->ctx)->dsd_list);
+	INIT_LIST_HEAD(&ctx->dsd_list);
 }
 
 static inline void
@@ -113,8 +116,7 @@
 		return 0;
 	 *
 	 */
-
-	switch (scsi_get_prot_op(sp->cmd)) {
+	switch (scsi_get_prot_op(GET_CMD_SP(sp))) {
 	case SCSI_PROT_READ_STRIP:
 	case SCSI_PROT_WRITE_INSERT:
 		if (ql2xenablehba_err_chk >= 1)
@@ -144,3 +146,44 @@
 	    test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
 	    test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
 }
+
+static inline srb_t *
+qla2x00_get_sp(scsi_qla_host_t *vha, fc_port_t *fcport, gfp_t flag)
+{
+	srb_t *sp = NULL;
+	struct qla_hw_data *ha = vha->hw;
+	uint8_t bail;
+
+	QLA_VHA_MARK_BUSY(vha, bail);
+	if (unlikely(bail))
+		return NULL;
+
+	sp = mempool_alloc(ha->srb_mempool, flag);
+	if (!sp)
+		goto done;
+
+	memset(sp, 0, sizeof(*sp));
+	sp->fcport = fcport;
+	sp->iocbs = 1;
+done:
+	if (!sp)
+		QLA_VHA_MARK_NOT_BUSY(vha);
+	return sp;
+}
+
+static inline void
+qla2x00_init_timer(srb_t *sp, unsigned long tmo)
+{
+	init_timer(&sp->u.iocb_cmd.timer);
+	sp->u.iocb_cmd.timer.expires = jiffies + tmo * HZ;
+	sp->u.iocb_cmd.timer.data = (unsigned long)sp;
+	sp->u.iocb_cmd.timer.function = qla2x00_sp_timeout;
+	add_timer(&sp->u.iocb_cmd.timer);
+	sp->free = qla2x00_sp_free;
+}
+
+static inline int
+qla2x00_gid_list_size(struct qla_hw_data *ha)
+{
+	return sizeof(struct gid_list_info) * ha->max_fibre_devices;
+}
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 55a9676..eac9509 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -22,18 +22,19 @@
 qla2x00_get_cmd_direction(srb_t *sp)
 {
 	uint16_t cflags;
+	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
 
 	cflags = 0;
 
 	/* Set transfer direction */
-	if (sp->cmd->sc_data_direction == DMA_TO_DEVICE) {
+	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
 		cflags = CF_WRITE;
 		sp->fcport->vha->hw->qla_stats.output_bytes +=
-		    scsi_bufflen(sp->cmd);
-	} else if (sp->cmd->sc_data_direction == DMA_FROM_DEVICE) {
+		    scsi_bufflen(cmd);
+	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
 		cflags = CF_READ;
 		sp->fcport->vha->hw->qla_stats.input_bytes +=
-		    scsi_bufflen(sp->cmd);
+		    scsi_bufflen(cmd);
 	}
 	return (cflags);
 }
@@ -143,12 +144,13 @@
 static inline int
 qla24xx_configure_prot_mode(srb_t *sp, uint16_t *fw_prot_opts)
 {
-	uint8_t	guard = scsi_host_get_guard(sp->cmd->device->host);
+	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
+	uint8_t	guard = scsi_host_get_guard(cmd->device->host);
 
 	/* We only support T10 DIF right now */
 	if (guard != SHOST_DIX_GUARD_CRC) {
 		ql_dbg(ql_dbg_io, sp->fcport->vha, 0x3007,
-		    "Unsupported guard: %d for cmd=%p.\n", guard, sp->cmd);
+		    "Unsupported guard: %d for cmd=%p.\n", guard, cmd);
 		return 0;
 	}
 
@@ -156,7 +158,7 @@
 	*fw_prot_opts = 0;
 
 	/* Translate SCSI opcode to a protection opcode */
-	switch (scsi_get_prot_op(sp->cmd)) {
+	switch (scsi_get_prot_op(cmd)) {
 	case SCSI_PROT_READ_STRIP:
 		*fw_prot_opts |= PO_MODE_DIF_REMOVE;
 		break;
@@ -180,7 +182,7 @@
 		break;
 	}
 
-	return scsi_prot_sg_count(sp->cmd);
+	return scsi_prot_sg_count(cmd);
 }
 
 /*
@@ -201,7 +203,7 @@
 	struct scatterlist *sg;
 	int i;
 
-	cmd = sp->cmd;
+	cmd = GET_CMD_SP(sp);
 
 	/* Update entry type to indicate Command Type 2 IOCB */
 	*((uint32_t *)(&cmd_pkt->entry_type)) =
@@ -259,7 +261,7 @@
 	struct scatterlist *sg;
 	int i;
 
-	cmd = sp->cmd;
+	cmd = GET_CMD_SP(sp);
 
 	/* Update entry type to indicate Command Type 3 IOCB */
 	*((uint32_t *)(&cmd_pkt->entry_type)) =
@@ -333,7 +335,7 @@
 	vha = sp->fcport->vha;
 	ha = vha->hw;
 	reg = &ha->iobase->isp;
-	cmd = sp->cmd;
+	cmd = GET_CMD_SP(sp);
 	req = ha->req_q_map[0];
 	rsp = ha->rsp_q_map[0];
 	/* So we know we haven't pci_map'ed anything yet */
@@ -391,7 +393,7 @@
 	req->current_outstanding_cmd = handle;
 	req->outstanding_cmds[handle] = sp;
 	sp->handle = handle;
-	sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
+	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
 	req->cnt -= req_cnt;
 
 	cmd_pkt = (cmd_entry_t *)req->ring_ptr;
@@ -403,7 +405,7 @@
 
 	/* Set target ID and LUN number*/
 	SET_TARGET_ID(ha, cmd_pkt->target, sp->fcport->loop_id);
-	cmd_pkt->lun = cpu_to_le16(sp->cmd->device->lun);
+	cmd_pkt->lun = cpu_to_le16(cmd->device->lun);
 
 	/* Update tagged queuing modifier */
 	if (scsi_populate_tag_msg(cmd, tag)) {
@@ -473,7 +475,6 @@
 {
 	struct qla_hw_data *ha = vha->hw;
 	device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
-	struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp;
 
 	if (IS_QLA82XX(ha)) {
 		qla82xx_start_iocbs(vha);
@@ -487,9 +488,9 @@
 			req->ring_ptr++;
 
 		/* Set chip new ring index. */
-		if (ha->mqenable) {
-			WRT_REG_DWORD(&reg->isp25mq.req_q_in, req->ring_index);
-			RD_REG_DWORD(&ioreg->hccr);
+		if (ha->mqenable || IS_QLA83XX(ha)) {
+			WRT_REG_DWORD(req->req_q_in, req->ring_index);
+			RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr);
 		} else if (IS_FWI2_CAPABLE(ha)) {
 			WRT_REG_DWORD(&reg->isp24.req_q_in, req->ring_index);
 			RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
@@ -609,7 +610,7 @@
 	struct dsd_dma *dsd_ptr;
 	struct ct6_dsd *ctx;
 
-	cmd = sp->cmd;
+	cmd = GET_CMD_SP(sp);
 
 	/* Update entry type to indicate Command Type 3 IOCB */
 	*((uint32_t *)(&cmd_pkt->entry_type)) =
@@ -636,7 +637,7 @@
 	}
 
 	cur_seg = scsi_sglist(cmd);
-	ctx = sp->ctx;
+	ctx = GET_CMD_CTX_SP(sp);
 
 	while (tot_dsds) {
 		avail_dsds = (tot_dsds > QLA_DSDS_PER_IOCB) ?
@@ -725,7 +726,7 @@
 	int i;
 	struct req_que *req;
 
-	cmd = sp->cmd;
+	cmd = GET_CMD_SP(sp);
 
 	/* Update entry type to indicate Command Type 3 IOCB */
 	*((uint32_t *)(&cmd_pkt->entry_type)) =
@@ -745,12 +746,12 @@
 		cmd_pkt->task_mgmt_flags =
 		    __constant_cpu_to_le16(TMF_WRITE_DATA);
 		sp->fcport->vha->hw->qla_stats.output_bytes +=
-		    scsi_bufflen(sp->cmd);
+		    scsi_bufflen(cmd);
 	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
 		cmd_pkt->task_mgmt_flags =
 		    __constant_cpu_to_le16(TMF_READ_DATA);
 		sp->fcport->vha->hw->qla_stats.input_bytes +=
-		    scsi_bufflen(sp->cmd);
+		    scsi_bufflen(cmd);
 	}
 
 	/* One DSD is available in the Command Type 3 IOCB */
@@ -797,7 +798,7 @@
 qla24xx_set_t10dif_tags(srb_t *sp, struct fw_dif_context *pkt,
     unsigned int protcnt)
 {
-	struct scsi_cmnd *cmd = sp->cmd;
+	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
 	scsi_qla_host_t *vha = shost_priv(cmd->device->host);
 
 	switch (scsi_get_prot_type(cmd)) {
@@ -952,16 +953,16 @@
 	struct qla2_sgx sgx;
 	dma_addr_t	sle_dma;
 	uint32_t	sle_dma_len, tot_prot_dma_len = 0;
-	struct scsi_cmnd *cmd = sp->cmd;
+	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
 
 	prot_int = cmd->device->sector_size;
 
 	memset(&sgx, 0, sizeof(struct qla2_sgx));
-	sgx.tot_bytes = scsi_bufflen(sp->cmd);
-	sgx.cur_sg = scsi_sglist(sp->cmd);
+	sgx.tot_bytes = scsi_bufflen(cmd);
+	sgx.cur_sg = scsi_sglist(cmd);
 	sgx.sp = sp;
 
-	sg_prot = scsi_prot_sglist(sp->cmd);
+	sg_prot = scsi_prot_sglist(cmd);
 
 	while (qla24xx_get_one_block_sg(prot_int, &sgx, &partial)) {
 
@@ -995,7 +996,7 @@
 			}
 
 			list_add_tail(&dsd_ptr->list,
-			    &((struct crc_context *)sp->ctx)->dsd_list);
+			    &((struct crc_context *)sp->u.scmd.ctx)->dsd_list);
 
 			sp->flags |= SRB_CRC_CTX_DSD_VALID;
 
@@ -1044,11 +1045,12 @@
 	uint32_t *cur_dsd = dsd;
 	int	i;
 	uint16_t	used_dsds = tot_dsds;
-	scsi_qla_host_t *vha = shost_priv(sp->cmd->device->host);
+	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
+	scsi_qla_host_t *vha = shost_priv(cmd->device->host);
 
 	uint8_t		*cp;
 
-	scsi_for_each_sg(sp->cmd, sg, tot_dsds, i) {
+	scsi_for_each_sg(cmd, sg, tot_dsds, i) {
 		dma_addr_t	sle_dma;
 
 		/* Allocate additional continuation packets? */
@@ -1078,7 +1080,7 @@
 			}
 
 			list_add_tail(&dsd_ptr->list,
-			    &((struct crc_context *)sp->ctx)->dsd_list);
+			    &((struct crc_context *)sp->u.scmd.ctx)->dsd_list);
 
 			sp->flags |= SRB_CRC_CTX_DSD_VALID;
 
@@ -1091,17 +1093,16 @@
 		sle_dma = sg_dma_address(sg);
 		ql_dbg(ql_dbg_io, vha, 0x300a,
 		    "sg entry %d - addr=0x%x 0x%x, " "len=%d for cmd=%p.\n",
-		    i, LSD(sle_dma), MSD(sle_dma), sg_dma_len(sg),
-		    sp->cmd);
+		    i, LSD(sle_dma), MSD(sle_dma), sg_dma_len(sg), cmd);
 		*cur_dsd++ = cpu_to_le32(LSD(sle_dma));
 		*cur_dsd++ = cpu_to_le32(MSD(sle_dma));
 		*cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
 		avail_dsds--;
 
-		if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) {
+		if (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_PASS) {
 			cp = page_address(sg_page(sg)) + sg->offset;
 			ql_dbg(ql_dbg_io, vha, 0x300b,
-			    "User data buffer=%p for cmd=%p.\n", cp, sp->cmd);
+			    "User data buffer=%p for cmd=%p.\n", cp, cmd);
 		}
 	}
 	/* Null termination */
@@ -1128,8 +1129,7 @@
 	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 	uint8_t		*cp;
 
-
-	cmd = sp->cmd;
+	cmd = GET_CMD_SP(sp);
 	scsi_for_each_prot_sg(cmd, sg, tot_dsds, i) {
 		dma_addr_t	sle_dma;
 
@@ -1160,7 +1160,7 @@
 			}
 
 			list_add_tail(&dsd_ptr->list,
-			    &((struct crc_context *)sp->ctx)->dsd_list);
+			    &((struct crc_context *)sp->u.scmd.ctx)->dsd_list);
 
 			sp->flags |= SRB_CRC_CTX_DSD_VALID;
 
@@ -1171,7 +1171,7 @@
 			cur_dsd = (uint32_t *)next_dsd;
 		}
 		sle_dma = sg_dma_address(sg);
-		if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) {
+		if (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_PASS) {
 			ql_dbg(ql_dbg_io, vha, 0x3027,
 			    "%s(): %p, sg_entry %d - "
 			    "addr=0x%x0x%x, len=%d.\n",
@@ -1182,7 +1182,7 @@
 		*cur_dsd++ = cpu_to_le32(MSD(sle_dma));
 		*cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
 
-		if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) {
+		if (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_PASS) {
 			cp = page_address(sg_page(sg)) + sg->offset;
 			ql_dbg(ql_dbg_io, vha, 0x3028,
 			    "%s(): Protection Data buffer = %p.\n", __func__,
@@ -1228,7 +1228,7 @@
 	dma_addr_t		crc_ctx_dma;
 	char			tag[2];
 
-	cmd = sp->cmd;
+	cmd = GET_CMD_SP(sp);
 
 	sgc = 0;
 	/* Update entry type to indicate Command Type CRC_2 IOCB */
@@ -1256,15 +1256,15 @@
 		    __constant_cpu_to_le16(CF_READ_DATA);
 	}
 
-	if ((scsi_get_prot_op(sp->cmd) == SCSI_PROT_READ_INSERT) ||
-	    (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_STRIP) ||
-	    (scsi_get_prot_op(sp->cmd) == SCSI_PROT_READ_STRIP) ||
-	    (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_INSERT))
+	if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) ||
+	    (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP) ||
+	    (scsi_get_prot_op(cmd) == SCSI_PROT_READ_STRIP) ||
+	    (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_INSERT))
 		bundling = 0;
 
 	/* Allocate CRC context from global pool */
-	crc_ctx_pkt = sp->ctx = dma_pool_alloc(ha->dl_dma_pool,
-	    GFP_ATOMIC, &crc_ctx_dma);
+	crc_ctx_pkt = sp->u.scmd.ctx =
+	    dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, &crc_ctx_dma);
 
 	if (!crc_ctx_pkt)
 		goto crc_queuing_error;
@@ -1310,7 +1310,7 @@
 	else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
 		fcp_cmnd->additional_cdb_len |= 2;
 
-	int_to_scsilun(sp->cmd->device->lun, &fcp_cmnd->lun);
+	int_to_scsilun(cmd->device->lun, &fcp_cmnd->lun);
 	memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
 	cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len);
 	cmd_pkt->fcp_cmnd_dseg_address[0] = cpu_to_le32(
@@ -1345,7 +1345,7 @@
 	blk_size = cmd->device->sector_size;
 	dif_bytes = (data_bytes / blk_size) * 8;
 
-	switch (scsi_get_prot_op(sp->cmd)) {
+	switch (scsi_get_prot_op(GET_CMD_SP(sp))) {
 	case SCSI_PROT_READ_INSERT:
 	case SCSI_PROT_WRITE_STRIP:
 	    total_bytes = data_bytes;
@@ -1445,7 +1445,7 @@
 	uint16_t	tot_dsds;
 	struct req_que *req = NULL;
 	struct rsp_que *rsp = NULL;
-	struct scsi_cmnd *cmd = sp->cmd;
+	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
 	struct scsi_qla_host *vha = sp->fcport->vha;
 	struct qla_hw_data *ha = vha->hw;
 	char		tag[2];
@@ -1510,7 +1510,7 @@
 	req->current_outstanding_cmd = handle;
 	req->outstanding_cmds[handle] = sp;
 	sp->handle = handle;
-	sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
+	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
 	req->cnt -= req_cnt;
 
 	cmd_pkt = (struct cmd_type_7 *)req->ring_ptr;
@@ -1529,7 +1529,7 @@
 	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
 	cmd_pkt->vp_index = sp->fcport->vp_idx;
 
-	int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
+	int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
 	host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
 
 	/* Update tagged queuing modifier -- default is TSK_SIMPLE (0). */
@@ -1611,7 +1611,7 @@
 	uint16_t		fw_prot_opts = 0;
 	struct req_que		*req = NULL;
 	struct rsp_que		*rsp = NULL;
-	struct scsi_cmnd	*cmd = sp->cmd;
+	struct scsi_cmnd	*cmd = GET_CMD_SP(sp);
 	struct scsi_qla_host	*vha = sp->fcport->vha;
 	struct qla_hw_data	*ha = vha->hw;
 	struct cmd_type_crc_2	*cmd_pkt;
@@ -1728,7 +1728,7 @@
 	req->current_outstanding_cmd = handle;
 	req->outstanding_cmds[handle] = sp;
 	sp->handle = handle;
-	sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
+	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
 	req->cnt -= req_cnt;
 
 	/* Fill-in common area */
@@ -1744,7 +1744,7 @@
 	cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
 	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
 
-	int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
+	int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
 	host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
 
 	/* Total Data and protection segment(s) */
@@ -1797,7 +1797,7 @@
 
 static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp)
 {
-	struct scsi_cmnd *cmd = sp->cmd;
+	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
 	struct qla_hw_data *ha = sp->fcport->vha->hw;
 	int affinity = cmd->request->cpu;
 
@@ -1818,7 +1818,6 @@
 	uint32_t index, handle;
 	request_t *pkt;
 	uint16_t cnt, req_cnt;
-	struct srb_ctx *ctx;
 
 	pkt = NULL;
 	req_cnt = 1;
@@ -1848,15 +1847,13 @@
 	sp->handle = handle;
 
 	/* Adjust entry-counts as needed. */
-	if (sp->ctx) {
-		ctx = sp->ctx;
-		req_cnt = ctx->iocbs;
-	}
+	if (sp->type != SRB_SCSI_CMD)
+		req_cnt = sp->iocbs;
 
 skip_cmd_array:
 	/* Check for room on request queue. */
 	if (req->cnt < req_cnt) {
-		if (ha->mqenable)
+		if (ha->mqenable || IS_QLA83XX(ha))
 			cnt = RD_REG_DWORD(&reg->isp25mq.req_q_out);
 		else if (IS_QLA82XX(ha))
 			cnt = RD_REG_DWORD(&reg->isp82.req_q_out);
@@ -1889,8 +1886,7 @@
 static void
 qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio)
 {
-	struct srb_ctx *ctx = sp->ctx;
-	struct srb_iocb *lio = ctx->u.iocb_cmd;
+	struct srb_iocb *lio = &sp->u.iocb_cmd;
 
 	logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
 	logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI);
@@ -1909,8 +1905,7 @@
 qla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx)
 {
 	struct qla_hw_data *ha = sp->fcport->vha->hw;
-	struct srb_ctx *ctx = sp->ctx;
-	struct srb_iocb *lio = ctx->u.iocb_cmd;
+	struct srb_iocb *lio = &sp->u.iocb_cmd;
 	uint16_t opts;
 
 	mbx->entry_type = MBX_IOCB_TYPE;
@@ -1999,8 +1994,7 @@
 	struct fc_port *fcport = sp->fcport;
 	scsi_qla_host_t *vha = fcport->vha;
 	struct qla_hw_data *ha = vha->hw;
-	struct srb_ctx *ctx = sp->ctx;
-	struct srb_iocb *iocb = ctx->u.iocb_cmd;
+	struct srb_iocb *iocb = &sp->u.iocb_cmd;
 	struct req_que *req = vha->req;
 
 	flags = iocb->u.tmf.flags;
@@ -2027,7 +2021,7 @@
 static void
 qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
 {
-	struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job;
+	struct fc_bsg_job *bsg_job = sp->u.bsg_job;
 
         els_iocb->entry_type = ELS_IOCB_TYPE;
         els_iocb->entry_count = 1;
@@ -2041,7 +2035,7 @@
         els_iocb->rx_dsd_count = __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt);
 
 	els_iocb->opcode =
-	    (((struct srb_ctx *)sp->ctx)->type == SRB_ELS_CMD_RPT) ?
+	    sp->type == SRB_ELS_CMD_RPT ?
 	    bsg_job->request->rqst_data.r_els.els_code :
 	    bsg_job->request->rqst_data.h_els.command_code;
         els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
@@ -2078,7 +2072,7 @@
 	uint16_t tot_dsds;
 	scsi_qla_host_t *vha = sp->fcport->vha;
 	struct qla_hw_data *ha = vha->hw;
-	struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job;
+	struct fc_bsg_job *bsg_job = sp->u.bsg_job;
 	int loop_iterartion = 0;
 	int cont_iocb_prsnt = 0;
 	int entry_count = 1;
@@ -2155,7 +2149,7 @@
 	uint16_t tot_dsds;
         scsi_qla_host_t *vha = sp->fcport->vha;
 	struct qla_hw_data *ha = vha->hw;
-	struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job;
+	struct fc_bsg_job *bsg_job = sp->u.bsg_job;
 	int loop_iterartion = 0;
 	int cont_iocb_prsnt = 0;
 	int entry_count = 1;
@@ -2245,12 +2239,12 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req = NULL;
 	struct rsp_que *rsp = NULL;
-	char		tag[2];
+	char tag[2];
 
 	/* Setup device pointers. */
 	ret = 0;
 	reg = &ha->iobase->isp82;
-	cmd = sp->cmd;
+	cmd = GET_CMD_SP(sp);
 	req = vha->req;
 	rsp = ha->rsp_q_map[0];
 
@@ -2354,12 +2348,14 @@
 		if (req->cnt < (req_cnt + 2))
 			goto queuing_error;
 
-		ctx = sp->ctx = mempool_alloc(ha->ctx_mempool, GFP_ATOMIC);
-		if (!sp->ctx) {
+		ctx = sp->u.scmd.ctx =
+		    mempool_alloc(ha->ctx_mempool, GFP_ATOMIC);
+		if (!ctx) {
 			ql_log(ql_log_fatal, vha, 0x3010,
 			    "Failed to allocate ctx for cmd=%p.\n", cmd);
 			goto queuing_error;
 		}
+
 		memset(ctx, 0, sizeof(struct ct6_dsd));
 		ctx->fcp_cmnd = dma_pool_alloc(ha->fcp_cmnd_dma_pool,
 			GFP_ATOMIC, &ctx->fcp_cmnd_dma);
@@ -2410,12 +2406,12 @@
 		if (qla24xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds))
 			goto queuing_error_fcp_cmnd;
 
-		int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
+		int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
 		host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
 
 		/* build FCP_CMND IU */
 		memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd));
-		int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun);
+		int_to_scsilun(cmd->device->lun, &ctx->fcp_cmnd->lun);
 		ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len;
 
 		if (cmd->sc_data_direction == DMA_TO_DEVICE)
@@ -2495,9 +2491,9 @@
 		cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
 		cmd_pkt->vp_index = sp->fcport->vp_idx;
 
-		int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
+		int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
 		host_to_fcp_swap((uint8_t *)&cmd_pkt->lun,
-			sizeof(cmd_pkt->lun));
+		    sizeof(cmd_pkt->lun));
 
 		/*
 		 * Update tagged queuing modifier -- default is TSK_SIMPLE (0).
@@ -2538,7 +2534,7 @@
 	req->current_outstanding_cmd = handle;
 	req->outstanding_cmds[handle] = sp;
 	sp->handle = handle;
-	sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
+	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
 	req->cnt -= req_cnt;
 	wmb();
 
@@ -2584,9 +2580,9 @@
 	if (tot_dsds)
 		scsi_dma_unmap(cmd);
 
-	if (sp->ctx) {
-		mempool_free(sp->ctx, ha->ctx_mempool);
-		sp->ctx = NULL;
+	if (sp->u.scmd.ctx) {
+		mempool_free(sp->u.scmd.ctx, ha->ctx_mempool);
+		sp->u.scmd.ctx = NULL;
 	}
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
@@ -2599,7 +2595,6 @@
 	int rval;
 	struct qla_hw_data *ha = sp->fcport->vha->hw;
 	void *pkt;
-	struct srb_ctx *ctx = sp->ctx;
 	unsigned long flags;
 
 	rval = QLA_FUNCTION_FAILED;
@@ -2612,7 +2607,7 @@
 	}
 
 	rval = QLA_SUCCESS;
-	switch (ctx->type) {
+	switch (sp->type) {
 	case SRB_LOGIN_CMD:
 		IS_FWI2_CAPABLE(ha) ?
 		    qla24xx_login_iocb(sp, pkt) :
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 349843e..f79844c 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -44,8 +44,8 @@
 
 	rsp = (struct rsp_que *) dev_id;
 	if (!rsp) {
-		printk(KERN_INFO
-		    "%s(): NULL response queue pointer.\n", __func__);
+		ql_log(ql_log_info, NULL, 0x505d,
+		    "%s: NULL response queue pointer.\n", __func__);
 		return (IRQ_NONE);
 	}
 
@@ -141,8 +141,8 @@
 
 	rsp = (struct rsp_que *) dev_id;
 	if (!rsp) {
-		printk(KERN_INFO
-		    "%s(): NULL response queue pointer.\n", __func__);
+		ql_log(ql_log_info, NULL, 0x5058,
+		    "%s: NULL response queue pointer.\n", __func__);
 		return (IRQ_NONE);
 	}
 
@@ -289,7 +289,7 @@
 		mb[cnt] = RD_REG_WORD(wptr);
 
 	ql_dbg(ql_dbg_async, vha, 0x5021,
-	    "Inter-Driver Commucation %s -- "
+	    "Inter-Driver Communication %s -- "
 	    "%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]);
@@ -318,7 +318,7 @@
 qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
 {
 #define LS_UNKNOWN	2
-	static char	*link_speeds[] = { "1", "2", "?", "4", "8", "10" };
+	static char *link_speeds[] = { "1", "2", "?", "4", "8", "16", "10" };
 	char		*link_speed;
 	uint16_t	handle_cnt;
 	uint16_t	cnt, mbx;
@@ -328,12 +328,11 @@
 	struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
 	struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82;
 	uint32_t	rscn_entry, host_pid;
-	uint8_t		rscn_queue_index;
 	unsigned long	flags;
 
 	/* Setup to process RIO completion. */
 	handle_cnt = 0;
-	if (IS_QLA8XXX_TYPE(ha))
+	if (IS_CNA_CAPABLE(ha))
 		goto skip_rio;
 	switch (mb[0]) {
 	case MBA_SCSI_COMPLETION:
@@ -405,7 +404,8 @@
 		break;
 
 	case MBA_SYSTEM_ERR:		/* System Error */
-		mbx = IS_QLA81XX(ha) ? RD_REG_WORD(&reg24->mailbox7) : 0;
+		mbx = (IS_QLA81XX(ha) || IS_QLA83XX(ha)) ?
+			RD_REG_WORD(&reg24->mailbox7) : 0;
 		ql_log(ql_log_warn, vha, 0x5003,
 		    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh "
 		    "mbx7=%xh.\n", mb[1], mb[2], mb[3], mbx);
@@ -418,6 +418,7 @@
 				    "Unrecoverable Hardware Error: adapter "
 				    "marked OFFLINE!\n");
 				vha->flags.online = 0;
+				vha->device_flags |= DFLG_DEV_FAILED;
 			} else {
 				/* Check to see if MPI timeout occurred */
 				if ((mbx & MBX_3) && (ha->flags.port0))
@@ -431,6 +432,7 @@
 			    "Unrecoverable Hardware Error: adapter marked "
 			    "OFFLINE!\n");
 			vha->flags.online = 0;
+			vha->device_flags |= DFLG_DEV_FAILED;
 		} else
 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
 		break;
@@ -482,10 +484,10 @@
 			ha->link_data_rate = PORT_SPEED_1GB;
 		} else {
 			link_speed = link_speeds[LS_UNKNOWN];
-			if (mb[1] < 5)
+			if (mb[1] < 6)
 				link_speed = link_speeds[mb[1]];
 			else if (mb[1] == 0x13)
-				link_speed = link_speeds[5];
+				link_speed = link_speeds[6];
 			ha->link_data_rate = mb[1];
 		}
 
@@ -497,7 +499,8 @@
 		break;
 
 	case MBA_LOOP_DOWN:		/* Loop Down Event */
-		mbx = IS_QLA81XX(ha) ? RD_REG_WORD(&reg24->mailbox4) : 0;
+		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;
 		ql_dbg(ql_dbg_async, vha, 0x500b,
 		    "LOOP DOWN detected (%x %x %x %x).\n",
@@ -547,7 +550,7 @@
 		if (IS_QLA2100(ha))
 			break;
 
-		if (IS_QLA8XXX_TYPE(ha)) {
+		if (IS_QLA81XX(ha) || IS_QLA82XX(ha) || IS_QLA8031(ha)) {
 			ql_dbg(ql_dbg_async, vha, 0x500d,
 			    "DCBX Completed -- %04x %04x %04x.\n",
 			    mb[1], mb[2], mb[3]);
@@ -681,8 +684,6 @@
 
 		qla2x00_mark_all_devices_lost(vha, 1);
 
-		vha->flags.rscn_queue_overflow = 1;
-
 		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
 		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
 		break;
@@ -711,15 +712,6 @@
 
 		/* Ignore reserved bits from RSCN-payload. */
 		rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2];
-		rscn_queue_index = vha->rscn_in_ptr + 1;
-		if (rscn_queue_index == MAX_RSCN_COUNT)
-			rscn_queue_index = 0;
-		if (rscn_queue_index != vha->rscn_out_ptr) {
-			vha->rscn_queue[vha->rscn_in_ptr] = rscn_entry;
-			vha->rscn_in_ptr = rscn_queue_index;
-		} else {
-			vha->flags.rscn_queue_overflow = 1;
-		}
 
 		atomic_set(&vha->loop_down_timer, 0);
 		vha->flags.management_server_logged_in = 0;
@@ -809,6 +801,10 @@
 	case MBA_IDC_TIME_EXT:
 		qla81xx_idc_event(vha, mb[0], mb[1]);
 		break;
+	default:
+		ql_dbg(ql_dbg_async, vha, 0x5057,
+		    "Unknown AEN:%04x %04x %04x %04x\n",
+		    mb[0], mb[1], mb[2], mb[3]);
 	}
 
 	if (!vha->vp_idx && ha->num_vhosts)
@@ -845,8 +841,7 @@
 		req->outstanding_cmds[index] = NULL;
 
 		/* Save ISP completion status */
-		sp->cmd->result = DID_OK << 16;
-		qla2x00_sp_compl(ha, sp);
+		sp->done(ha, sp, DID_OK << 16);
 	} else {
 		ql_log(ql_log_warn, vha, 0x3016, "Invalid SCSI SRB.\n");
 
@@ -903,7 +898,6 @@
 	fc_port_t *fcport;
 	srb_t *sp;
 	struct srb_iocb *lio;
-	struct srb_ctx *ctx;
 	uint16_t *data;
 	uint16_t status;
 
@@ -911,9 +905,8 @@
 	if (!sp)
 		return;
 
-	ctx = sp->ctx;
-	lio = ctx->u.iocb_cmd;
-	type = ctx->name;
+	lio = &sp->u.iocb_cmd;
+	type = sp->name;
 	fcport = sp->fcport;
 	data = lio->u.logio.data;
 
@@ -937,7 +930,7 @@
 	}
 
 	status = le16_to_cpu(mbx->status);
-	if (status == 0x30 && ctx->type == SRB_LOGIN_CMD &&
+	if (status == 0x30 && sp->type == SRB_LOGIN_CMD &&
 	    le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE)
 		status = 0;
 	if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
@@ -948,7 +941,7 @@
 		    le16_to_cpu(mbx->mb1));
 
 		data[0] = MBS_COMMAND_COMPLETE;
-		if (ctx->type == SRB_LOGIN_CMD) {
+		if (sp->type == SRB_LOGIN_CMD) {
 			fcport->port_type = FCT_TARGET;
 			if (le16_to_cpu(mbx->mb1) & BIT_0)
 				fcport->port_type = FCT_INITIATOR;
@@ -979,7 +972,7 @@
 	    le16_to_cpu(mbx->mb7));
 
 logio_done:
-	lio->done(sp);
+	sp->done(vha, sp, 0);
 }
 
 static void
@@ -988,29 +981,18 @@
 {
 	const char func[] = "CT_IOCB";
 	const char *type;
-	struct qla_hw_data *ha = vha->hw;
 	srb_t *sp;
-	struct srb_ctx *sp_bsg;
 	struct fc_bsg_job *bsg_job;
 	uint16_t comp_status;
+	int res;
 
 	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
 	if (!sp)
 		return;
 
-	sp_bsg = sp->ctx;
-	bsg_job = sp_bsg->u.bsg_job;
+	bsg_job = sp->u.bsg_job;
 
-	type = NULL;
-	switch (sp_bsg->type) {
-	case SRB_CT_CMD:
-		type = "ct pass-through";
-		break;
-	default:
-		ql_log(ql_log_warn, vha, 0x5047,
-		    "Unrecognized SRB: (%p) type=%d.\n", sp, sp_bsg->type);
-		return;
-	}
+	type = "ct pass-through";
 
 	comp_status = le16_to_cpu(pkt->comp_status);
 
@@ -1022,7 +1004,7 @@
 
 	if (comp_status != CS_COMPLETE) {
 		if (comp_status == CS_DATA_UNDERRUN) {
-			bsg_job->reply->result = DID_OK << 16;
+			res = DID_OK << 16;
 			bsg_job->reply->reply_payload_rcv_len =
 			    le16_to_cpu(((sts_entry_t *)pkt)->rsp_info_len);
 
@@ -1035,30 +1017,19 @@
 			ql_log(ql_log_warn, vha, 0x5049,
 			    "CT pass-through-%s error "
 			    "comp_status-status=0x%x.\n", type, comp_status);
-			bsg_job->reply->result = DID_ERROR << 16;
+			res = DID_ERROR << 16;
 			bsg_job->reply->reply_payload_rcv_len = 0;
 		}
 		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5035,
 		    (uint8_t *)pkt, sizeof(*pkt));
 	} else {
-		bsg_job->reply->result =  DID_OK << 16;
+		res = DID_OK << 16;
 		bsg_job->reply->reply_payload_rcv_len =
 		    bsg_job->reply_payload.payload_len;
 		bsg_job->reply_len = 0;
 	}
 
-	dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
-	    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
-
-	dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
-	    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
-
-	if (sp_bsg->type == SRB_ELS_CMD_HST || sp_bsg->type == SRB_CT_CMD)
-		kfree(sp->fcport);
-
-	kfree(sp->ctx);
-	mempool_free(sp, ha->srb_mempool);
-	bsg_job->job_done(bsg_job);
+	sp->done(vha, sp, res);
 }
 
 static void
@@ -1067,22 +1038,20 @@
 {
 	const char func[] = "ELS_CT_IOCB";
 	const char *type;
-	struct qla_hw_data *ha = vha->hw;
 	srb_t *sp;
-	struct srb_ctx *sp_bsg;
 	struct fc_bsg_job *bsg_job;
 	uint16_t comp_status;
 	uint32_t fw_status[3];
 	uint8_t* fw_sts_ptr;
+	int res;
 
 	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
 	if (!sp)
 		return;
-	sp_bsg = sp->ctx;
-	bsg_job = sp_bsg->u.bsg_job;
+	bsg_job = sp->u.bsg_job;
 
 	type = NULL;
-	switch (sp_bsg->type) {
+	switch (sp->type) {
 	case SRB_ELS_CMD_RPT:
 	case SRB_ELS_CMD_HST:
 		type = "els";
@@ -1091,8 +1060,8 @@
 		type = "ct pass-through";
 		break;
 	default:
-		ql_log(ql_log_warn, vha, 0x503e,
-		    "Unrecognized SRB: (%p) type=%d.\n", sp, sp_bsg->type);
+		ql_dbg(ql_dbg_user, vha, 0x503e,
+		    "Unrecognized SRB: (%p) type=%d.\n", sp, sp->type);
 		return;
 	}
 
@@ -1108,11 +1077,11 @@
 
 	if (comp_status != CS_COMPLETE) {
 		if (comp_status == CS_DATA_UNDERRUN) {
-			bsg_job->reply->result = DID_OK << 16;
+			res = DID_OK << 16;
 			bsg_job->reply->reply_payload_rcv_len =
-				le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count);
+			    le16_to_cpu(((struct els_sts_entry_24xx *)pkt)->total_byte_count);
 
-			ql_log(ql_log_info, vha, 0x503f,
+			ql_dbg(ql_dbg_user, vha, 0x503f,
 			    "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x "
 			    "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n",
 			    type, sp->handle, comp_status, fw_status[1], fw_status[2],
@@ -1122,7 +1091,7 @@
 			memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
 		}
 		else {
-			ql_log(ql_log_info, vha, 0x5040,
+			ql_dbg(ql_dbg_user, vha, 0x5040,
 			    "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x "
 			    "error subcode 1=0x%x error subcode 2=0x%x.\n",
 			    type, sp->handle, comp_status,
@@ -1130,32 +1099,21 @@
 				pkt)->error_subcode_1),
 			    le16_to_cpu(((struct els_sts_entry_24xx *)
 				    pkt)->error_subcode_2));
-			bsg_job->reply->result = DID_ERROR << 16;
+			res = DID_ERROR << 16;
 			bsg_job->reply->reply_payload_rcv_len = 0;
 			fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
 			memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
 		}
-		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5056,
+		ql_dump_buffer(ql_dbg_user + ql_dbg_buffer, vha, 0x5056,
 				(uint8_t *)pkt, sizeof(*pkt));
 	}
 	else {
-		bsg_job->reply->result =  DID_OK << 16;
+		res =  DID_OK << 16;
 		bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len;
 		bsg_job->reply_len = 0;
 	}
 
-	dma_unmap_sg(&ha->pdev->dev,
-	    bsg_job->request_payload.sg_list,
-	    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
-	dma_unmap_sg(&ha->pdev->dev,
-	    bsg_job->reply_payload.sg_list,
-	    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
-	if ((sp_bsg->type == SRB_ELS_CMD_HST) ||
-	    (sp_bsg->type == SRB_CT_CMD))
-		kfree(sp->fcport);
-	kfree(sp->ctx);
-	mempool_free(sp, ha->srb_mempool);
-	bsg_job->job_done(bsg_job);
+	sp->done(vha, sp, res);
 }
 
 static void
@@ -1167,7 +1125,6 @@
 	fc_port_t *fcport;
 	srb_t *sp;
 	struct srb_iocb *lio;
-	struct srb_ctx *ctx;
 	uint16_t *data;
 	uint32_t iop[2];
 
@@ -1175,9 +1132,8 @@
 	if (!sp)
 		return;
 
-	ctx = sp->ctx;
-	lio = ctx->u.iocb_cmd;
-	type = ctx->name;
+	lio = &sp->u.iocb_cmd;
+	type = sp->name;
 	fcport = sp->fcport;
 	data = lio->u.logio.data;
 
@@ -1185,7 +1141,7 @@
 	data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
 		QLA_LOGIO_LOGIN_RETRIED : 0;
 	if (logio->entry_status) {
-		ql_log(ql_log_warn, vha, 0x5034,
+		ql_log(ql_log_warn, fcport->vha, 0x5034,
 		    "Async-%s error entry - hdl=%x"
 		    "portid=%02x%02x%02x entry-status=%x.\n",
 		    type, sp->handle, fcport->d_id.b.domain,
@@ -1198,14 +1154,14 @@
 	}
 
 	if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
-		ql_dbg(ql_dbg_async, vha, 0x5036,
+		ql_dbg(ql_dbg_async, fcport->vha, 0x5036,
 		    "Async-%s complete - hdl=%x portid=%02x%02x%02x "
 		    "iop0=%x.\n", type, sp->handle, fcport->d_id.b.domain,
 		    fcport->d_id.b.area, fcport->d_id.b.al_pa,
 		    le32_to_cpu(logio->io_parameter[0]));
 
 		data[0] = MBS_COMMAND_COMPLETE;
-		if (ctx->type != SRB_LOGIN_CMD)
+		if (sp->type != SRB_LOGIN_CMD)
 			goto logio_done;
 
 		iop[0] = le32_to_cpu(logio->io_parameter[0]);
@@ -1239,7 +1195,7 @@
 		break;
 	}
 
-	ql_dbg(ql_dbg_async, vha, 0x5037,
+	ql_dbg(ql_dbg_async, fcport->vha, 0x5037,
 	    "Async-%s failed - hdl=%x portid=%02x%02x%02x comp=%x "
 	    "iop0=%x iop1=%x.\n", type, sp->handle, fcport->d_id.b.domain,
 	    fcport->d_id.b.area, fcport->d_id.b.al_pa,
@@ -1248,7 +1204,7 @@
 	    le32_to_cpu(logio->io_parameter[1]));
 
 logio_done:
-	lio->done(sp);
+	sp->done(vha, sp, 0);
 }
 
 static void
@@ -1260,7 +1216,6 @@
 	fc_port_t *fcport;
 	srb_t *sp;
 	struct srb_iocb *iocb;
-	struct srb_ctx *ctx;
 	struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
 	int error = 1;
 
@@ -1268,30 +1223,29 @@
 	if (!sp)
 		return;
 
-	ctx = sp->ctx;
-	iocb = ctx->u.iocb_cmd;
-	type = ctx->name;
+	iocb = &sp->u.iocb_cmd;
+	type = sp->name;
 	fcport = sp->fcport;
 
 	if (sts->entry_status) {
-		ql_log(ql_log_warn, vha, 0x5038,
+		ql_log(ql_log_warn, fcport->vha, 0x5038,
 		    "Async-%s error - hdl=%x entry-status(%x).\n",
 		    type, sp->handle, sts->entry_status);
 	} else if (sts->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
-		ql_log(ql_log_warn, vha, 0x5039,
+		ql_log(ql_log_warn, fcport->vha, 0x5039,
 		    "Async-%s error - hdl=%x completion status(%x).\n",
 		    type, sp->handle, sts->comp_status);
 	} else if (!(le16_to_cpu(sts->scsi_status) &
 	    SS_RESPONSE_INFO_LEN_VALID)) {
-		ql_log(ql_log_warn, vha, 0x503a,
+		ql_log(ql_log_warn, fcport->vha, 0x503a,
 		    "Async-%s error - hdl=%x no response info(%x).\n",
 		    type, sp->handle, sts->scsi_status);
 	} else if (le32_to_cpu(sts->rsp_data_len) < 4) {
-		ql_log(ql_log_warn, vha, 0x503b,
+		ql_log(ql_log_warn, fcport->vha, 0x503b,
 		    "Async-%s error - hdl=%x not enough response(%d).\n",
 		    type, sp->handle, sts->rsp_data_len);
 	} else if (sts->data[3]) {
-		ql_log(ql_log_warn, vha, 0x503c,
+		ql_log(ql_log_warn, fcport->vha, 0x503c,
 		    "Async-%s error - hdl=%x response(%x).\n",
 		    type, sp->handle, sts->data[3]);
 	} else {
@@ -1304,7 +1258,7 @@
 		    (uint8_t *)sts, sizeof(*sts));
 	}
 
-	iocb->done(sp);
+	sp->done(vha, sp, 0);
 }
 
 /**
@@ -1390,25 +1344,32 @@
 
 static inline void
 qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
-    uint32_t sense_len, struct rsp_que *rsp)
+		     uint32_t sense_len, struct rsp_que *rsp, int res)
 {
 	struct scsi_qla_host *vha = sp->fcport->vha;
-	struct scsi_cmnd *cp = sp->cmd;
+	struct scsi_cmnd *cp = GET_CMD_SP(sp);
+	uint32_t track_sense_len;
 
 	if (sense_len >= SCSI_SENSE_BUFFERSIZE)
 		sense_len = SCSI_SENSE_BUFFERSIZE;
 
-	sp->request_sense_length = sense_len;
-	sp->request_sense_ptr = cp->sense_buffer;
-	if (sp->request_sense_length > par_sense_len)
+	SET_CMD_SENSE_LEN(sp, sense_len);
+	SET_CMD_SENSE_PTR(sp, cp->sense_buffer);
+	track_sense_len = sense_len;
+
+	if (sense_len > par_sense_len)
 		sense_len = par_sense_len;
 
 	memcpy(cp->sense_buffer, sense_data, sense_len);
 
-	sp->request_sense_ptr += sense_len;
-	sp->request_sense_length -= sense_len;
-	if (sp->request_sense_length != 0)
+	SET_CMD_SENSE_PTR(sp, cp->sense_buffer + sense_len);
+	track_sense_len -= sense_len;
+	SET_CMD_SENSE_LEN(sp, track_sense_len);
+
+	if (track_sense_len != 0) {
 		rsp->status_srb = sp;
+		cp->result = res;
+	}
 
 	if (sense_len) {
 		ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x301c,
@@ -1436,7 +1397,7 @@
 qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
 {
 	struct scsi_qla_host *vha = sp->fcport->vha;
-	struct scsi_cmnd *cmd = sp->cmd;
+	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
 	uint8_t		*ap = &sts24->data[12];
 	uint8_t		*ep = &sts24->data[20];
 	uint32_t	e_ref_tag, a_ref_tag;
@@ -1580,6 +1541,7 @@
 	uint16_t que;
 	struct req_que *req;
 	int logit = 1;
+	int res = 0;
 
 	sts = (sts_entry_t *) pkt;
 	sts24 = (struct sts_entry_24xx *) pkt;
@@ -1619,7 +1581,7 @@
 		qla2xxx_wake_dpc(vha);
 		return;
 	}
-	cp = sp->cmd;
+	cp = GET_CMD_SP(sp);
 	if (cp == NULL) {
 		ql_dbg(ql_dbg_io, vha, 0x3018,
 		    "Command already returned (0x%x/%p).\n",
@@ -1668,11 +1630,11 @@
 			par_sense_len -= rsp_info_len;
 		}
 		if (rsp_info_len > 3 && rsp_info[3]) {
-			ql_dbg(ql_dbg_io, vha, 0x3019,
+			ql_dbg(ql_dbg_io, fcport->vha, 0x3019,
 			    "FCP I/O protocol failure (0x%x/0x%x).\n",
 			    rsp_info_len, rsp_info[3]);
 
-			cp->result = DID_BUS_BUSY << 16;
+			res = DID_BUS_BUSY << 16;
 			goto out;
 		}
 	}
@@ -1689,7 +1651,7 @@
 	case CS_COMPLETE:
 	case CS_QUEUE_FULL:
 		if (scsi_status == 0) {
-			cp->result = DID_OK << 16;
+			res = DID_OK << 16;
 			break;
 		}
 		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
@@ -1699,19 +1661,19 @@
 			if (!lscsi_status &&
 			    ((unsigned)(scsi_bufflen(cp) - resid) <
 			     cp->underflow)) {
-				ql_dbg(ql_dbg_io, vha, 0x301a,
+				ql_dbg(ql_dbg_io, fcport->vha, 0x301a,
 				    "Mid-layer underflow "
 				    "detected (0x%x of 0x%x bytes).\n",
 				    resid, scsi_bufflen(cp));
 
-				cp->result = DID_ERROR << 16;
+				res = DID_ERROR << 16;
 				break;
 			}
 		}
-		cp->result = DID_OK << 16 | lscsi_status;
+		res = DID_OK << 16 | lscsi_status;
 
 		if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
-			ql_dbg(ql_dbg_io, vha, 0x301b,
+			ql_dbg(ql_dbg_io, fcport->vha, 0x301b,
 			    "QUEUE FULL detected.\n");
 			break;
 		}
@@ -1724,7 +1686,7 @@
 			break;
 
 		qla2x00_handle_sense(sp, sense_data, par_sense_len, sense_len,
-		    rsp);
+		    rsp, res);
 		break;
 
 	case CS_DATA_UNDERRUN:
@@ -1733,36 +1695,36 @@
 		scsi_set_resid(cp, resid);
 		if (scsi_status & SS_RESIDUAL_UNDER) {
 			if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) {
-				ql_dbg(ql_dbg_io, vha, 0x301d,
+				ql_dbg(ql_dbg_io, fcport->vha, 0x301d,
 				    "Dropped frame(s) detected "
 				    "(0x%x of 0x%x bytes).\n",
 				    resid, scsi_bufflen(cp));
 
-				cp->result = DID_ERROR << 16 | lscsi_status;
+				res = DID_ERROR << 16 | lscsi_status;
 				goto check_scsi_status;
 			}
 
 			if (!lscsi_status &&
 			    ((unsigned)(scsi_bufflen(cp) - resid) <
 			    cp->underflow)) {
-				ql_dbg(ql_dbg_io, vha, 0x301e,
+				ql_dbg(ql_dbg_io, fcport->vha, 0x301e,
 				    "Mid-layer underflow "
 				    "detected (0x%x of 0x%x bytes).\n",
 				    resid, scsi_bufflen(cp));
 
-				cp->result = DID_ERROR << 16;
+				res = DID_ERROR << 16;
 				break;
 			}
 		} else {
-			ql_dbg(ql_dbg_io, vha, 0x301f,
+			ql_dbg(ql_dbg_io, fcport->vha, 0x301f,
 			    "Dropped frame(s) detected (0x%x "
 			    "of 0x%x bytes).\n", resid, scsi_bufflen(cp));
 
-			cp->result = DID_ERROR << 16 | lscsi_status;
+			res = DID_ERROR << 16 | lscsi_status;
 			goto check_scsi_status;
 		}
 
-		cp->result = DID_OK << 16 | lscsi_status;
+		res = DID_OK << 16 | lscsi_status;
 		logit = 0;
 
 check_scsi_status:
@@ -1772,7 +1734,7 @@
 		 */
 		if (lscsi_status != 0) {
 			if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
-				ql_dbg(ql_dbg_io, vha, 0x3020,
+				ql_dbg(ql_dbg_io, fcport->vha, 0x3020,
 				    "QUEUE FULL detected.\n");
 				logit = 1;
 				break;
@@ -1785,7 +1747,7 @@
 				break;
 
 			qla2x00_handle_sense(sp, sense_data, par_sense_len,
-			    sense_len, rsp);
+			    sense_len, rsp, res);
 		}
 		break;
 
@@ -1802,7 +1764,7 @@
 		 * while we try to recover so instruct the mid layer
 		 * to requeue until the class decides how to handle this.
 		 */
-		cp->result = DID_TRANSPORT_DISRUPTED << 16;
+		res = DID_TRANSPORT_DISRUPTED << 16;
 
 		if (comp_status == CS_TIMEOUT) {
 			if (IS_FWI2_CAPABLE(ha))
@@ -1812,7 +1774,7 @@
 				break;
 		}
 
-		ql_dbg(ql_dbg_io, vha, 0x3021,
+		ql_dbg(ql_dbg_io, fcport->vha, 0x3021,
 		    "Port down status: port-state=0x%x.\n",
 		    atomic_read(&fcport->state));
 
@@ -1821,25 +1783,25 @@
 		break;
 
 	case CS_ABORTED:
-		cp->result = DID_RESET << 16;
+		res = DID_RESET << 16;
 		break;
 
 	case CS_DIF_ERROR:
 		logit = qla2x00_handle_dif_error(sp, sts24);
 		break;
 	default:
-		cp->result = DID_ERROR << 16;
+		res = DID_ERROR << 16;
 		break;
 	}
 
 out:
 	if (logit)
-		ql_dbg(ql_dbg_io, vha, 0x3022,
+		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 "
 		    "rsp_info=0x%x resid=0x%x fw_resid=0x%x.\n",
-		    comp_status, scsi_status, cp->result, vha->host_no,
+		    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],
@@ -1848,7 +1810,7 @@
 		    resid_len, fw_resid_len);
 
 	if (rsp->status_srb == NULL)
-		qla2x00_sp_compl(ha, sp);
+		sp->done(ha, sp, res);
 }
 
 /**
@@ -1861,84 +1823,52 @@
 static void
 qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
 {
-	uint8_t		sense_sz = 0;
+	uint8_t	sense_sz = 0;
 	struct qla_hw_data *ha = rsp->hw;
 	struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
-	srb_t		*sp = rsp->status_srb;
+	srb_t *sp = rsp->status_srb;
 	struct scsi_cmnd *cp;
+	uint32_t sense_len;
+	uint8_t *sense_ptr;
 
-	if (sp != NULL && sp->request_sense_length != 0) {
-		cp = sp->cmd;
-		if (cp == NULL) {
-			ql_log(ql_log_warn, vha, 0x3025,
-			    "cmd is NULL: already returned to OS (sp=%p).\n",
-			    sp);
+	if (!sp || !GET_CMD_SENSE_LEN(sp))
+		return;
 
-			rsp->status_srb = NULL;
-			return;
-		}
+	sense_len = GET_CMD_SENSE_LEN(sp);
+	sense_ptr = GET_CMD_SENSE_PTR(sp);
 
-		if (sp->request_sense_length > sizeof(pkt->data)) {
-			sense_sz = sizeof(pkt->data);
-		} else {
-			sense_sz = sp->request_sense_length;
-		}
+	cp = GET_CMD_SP(sp);
+	if (cp == NULL) {
+		ql_log(ql_log_warn, vha, 0x3025,
+		    "cmd is NULL: already returned to OS (sp=%p).\n", sp);
 
-		/* Move sense data. */
-		if (IS_FWI2_CAPABLE(ha))
-			host_to_fcp_swap(pkt->data, sizeof(pkt->data));
-		memcpy(sp->request_sense_ptr, pkt->data, sense_sz);
-		ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302c,
-			sp->request_sense_ptr, sense_sz);
-
-		sp->request_sense_ptr += sense_sz;
-		sp->request_sense_length -= sense_sz;
-
-		/* Place command on done queue. */
-		if (sp->request_sense_length == 0) {
-			rsp->status_srb = NULL;
-			qla2x00_sp_compl(ha, sp);
-		}
+		rsp->status_srb = NULL;
+		return;
 	}
-}
 
-static int
-qla2x00_free_sp_ctx(scsi_qla_host_t *vha, srb_t *sp)
-{
-	struct qla_hw_data *ha = vha->hw;
-	struct srb_ctx *ctx;
+	if (sense_len > sizeof(pkt->data))
+		sense_sz = sizeof(pkt->data);
+	else
+		sense_sz = sense_len;
 
-	if (!sp->ctx)
-		return 1;
+	/* Move sense data. */
+	if (IS_FWI2_CAPABLE(ha))
+		host_to_fcp_swap(pkt->data, sizeof(pkt->data));
+	memcpy(sense_ptr, pkt->data, sense_sz);
+	ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302c,
+		sense_ptr, sense_sz);
 
-	ctx = sp->ctx;
+	sense_len -= sense_sz;
+	sense_ptr += sense_sz;
 
-	if (ctx->type == SRB_LOGIN_CMD ||
-	    ctx->type == SRB_LOGOUT_CMD ||
-	    ctx->type == SRB_TM_CMD) {
-		ctx->u.iocb_cmd->done(sp);
-		return 0;
-	} else if (ctx->type == SRB_ADISC_CMD) {
-		ctx->u.iocb_cmd->free(sp);
-		return 0;
-	} else {
-		struct fc_bsg_job *bsg_job;
+	SET_CMD_SENSE_PTR(sp, sense_ptr);
+	SET_CMD_SENSE_LEN(sp, sense_len);
 
-		bsg_job = ctx->u.bsg_job;
-		if (ctx->type == SRB_ELS_CMD_HST ||
-		    ctx->type == SRB_CT_CMD)
-			kfree(sp->fcport);
-
-		bsg_job->reply->reply_data.ctels_reply.status =
-		    FC_CTELS_STATUS_OK;
-		bsg_job->reply->result = DID_ERROR << 16;
-		bsg_job->reply->reply_payload_rcv_len = 0;
-		kfree(sp->ctx);
-		mempool_free(sp, ha->srb_mempool);
-		bsg_job->job_done(bsg_job);
-		return 0;
+	/* Place command on done queue. */
+	if (sense_len == 0) {
+		rsp->status_srb = NULL;
+		sp->done(ha, sp, cp->result);
 	}
-	return 1;
 }
 
 /**
@@ -1953,53 +1883,34 @@
 	struct qla_hw_data *ha = vha->hw;
 	const char func[] = "ERROR-IOCB";
 	uint16_t que = MSW(pkt->handle);
-	struct req_que *req = ha->req_q_map[que];
+	struct req_que *req = NULL;
+	int res = DID_ERROR << 16;
 
-	if (pkt->entry_status & RF_INV_E_ORDER)
-		ql_dbg(ql_dbg_async, vha, 0x502a,
-		    "Invalid Entry Order.\n");
-	else if (pkt->entry_status & RF_INV_E_COUNT)
-		ql_dbg(ql_dbg_async, vha, 0x502b,
-		    "Invalid Entry Count.\n");
-	else if (pkt->entry_status & RF_INV_E_PARAM)
-		ql_dbg(ql_dbg_async, vha, 0x502c,
-		    "Invalid Entry Parameter.\n");
-	else if (pkt->entry_status & RF_INV_E_TYPE)
-		ql_dbg(ql_dbg_async, vha, 0x502d,
-		    "Invalid Entry Type.\n");
-	else if (pkt->entry_status & RF_BUSY)
-		ql_dbg(ql_dbg_async, vha, 0x502e,
-		    "Busy.\n");
-	else
-		ql_dbg(ql_dbg_async, vha, 0x502f,
-		    "UNKNOWN flag error.\n");
+	ql_dbg(ql_dbg_async, vha, 0x502a,
+	    "type of error status in response: 0x%x\n", pkt->entry_status);
+
+	if (que >= ha->max_req_queues || !ha->req_q_map[que])
+		goto fatal;
+
+	req = ha->req_q_map[que];
+
+	if (pkt->entry_status & RF_BUSY)
+		res = DID_BUS_BUSY << 16;
 
 	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
 	if (sp) {
-		if (qla2x00_free_sp_ctx(vha, sp)) {
-			if (pkt->entry_status &
-			    (RF_INV_E_ORDER | RF_INV_E_COUNT |
-			     RF_INV_E_PARAM | RF_INV_E_TYPE)) {
-				sp->cmd->result = DID_ERROR << 16;
-			} else if (pkt->entry_status & RF_BUSY) {
-				sp->cmd->result = DID_BUS_BUSY << 16;
-			} else {
-				sp->cmd->result = DID_ERROR << 16;
-			}
-			qla2x00_sp_compl(ha, sp);
-		}
-	} else if (pkt->entry_type == COMMAND_A64_TYPE || pkt->entry_type ==
-		COMMAND_TYPE || pkt->entry_type == COMMAND_TYPE_7
-		|| pkt->entry_type == COMMAND_TYPE_6) {
-		ql_log(ql_log_warn, vha, 0x5030,
-		    "Error entry - invalid handle.\n");
-
-		if (IS_QLA82XX(ha))
-			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
-		else
-			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
-		qla2xxx_wake_dpc(vha);
+		sp->done(ha, sp, res);
+		return;
 	}
+fatal:
+	ql_log(ql_log_warn, vha, 0x5030,
+	    "Error entry - invalid handle/queue.\n");
+
+	if (IS_QLA82XX(ha))
+		set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
+	else
+		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+	qla2xxx_wake_dpc(vha);
 }
 
 /**
@@ -2127,7 +2038,7 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 
-	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
+	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha))
 		return;
 
 	rval = QLA_SUCCESS;
@@ -2168,7 +2079,7 @@
 }
 
 /**
- * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
+ * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP24xx.
  * @irq:
  * @dev_id: SCSI driver HA context
  *
@@ -2192,8 +2103,8 @@
 
 	rsp = (struct rsp_que *) dev_id;
 	if (!rsp) {
-		printk(KERN_INFO
-		    "%s(): NULL response queue pointer.\n", __func__);
+		ql_log(ql_log_info, NULL, 0x5059,
+		    "%s: NULL response queue pointer.\n", __func__);
 		return IRQ_NONE;
 	}
 
@@ -2276,8 +2187,8 @@
 
 	rsp = (struct rsp_que *) dev_id;
 	if (!rsp) {
-		printk(KERN_INFO
-		"%s(): NULL response queue pointer.\n", __func__);
+		ql_log(ql_log_info, NULL, 0x505a,
+		    "%s: NULL response queue pointer.\n", __func__);
 		return IRQ_NONE;
 	}
 	ha = rsp->hw;
@@ -2306,8 +2217,8 @@
 
 	rsp = (struct rsp_que *) dev_id;
 	if (!rsp) {
-		printk(KERN_INFO
-			"%s(): NULL response queue pointer.\n", __func__);
+		ql_log(ql_log_info, NULL, 0x505b,
+		    "%s: NULL response queue pointer.\n", __func__);
 		return IRQ_NONE;
 	}
 	ha = rsp->hw;
@@ -2340,8 +2251,8 @@
 
 	rsp = (struct rsp_que *) dev_id;
 	if (!rsp) {
-		printk(KERN_INFO
-			"%s(): NULL response queue pointer.\n", __func__);
+		ql_log(ql_log_info, NULL, 0x505c,
+		    "%s: NULL response queue pointer.\n", __func__);
 		return IRQ_NONE;
 	}
 	ha = rsp->hw;
@@ -2530,8 +2441,14 @@
 	}
 
 	/* Enable MSI-X vector for response queue update for queue 0 */
-	if (ha->mqiobase &&  (ha->max_rsp_queues > 1 || ha->max_req_queues > 1))
-		ha->mqenable = 1;
+	if (IS_QLA83XX(ha)) {
+		if (ha->msixbase && ha->mqiobase &&
+		    (ha->max_rsp_queues > 1 || ha->max_req_queues > 1))
+			ha->mqenable = 1;
+	} else
+		if (ha->mqiobase
+		    && (ha->max_rsp_queues > 1 || ha->max_req_queues > 1))
+			ha->mqenable = 1;
 	ql_dbg(ql_dbg_multiq, vha, 0xc005,
 	    "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n",
 	    ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues);
@@ -2552,8 +2469,8 @@
 	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
 	/* If possible, enable MSI-X. */
-	if (!IS_QLA2432(ha) && !IS_QLA2532(ha) &&
-		!IS_QLA8432(ha) && !IS_QLA8XXX_TYPE(ha))
+	if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
+		!IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha))
 		goto skip_msi;
 
 	if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
@@ -2615,7 +2532,7 @@
 	 * FIXME: Noted that 8014s were being dropped during NK testing.
 	 * Timing deltas during MSI-X/INTa transitions?
 	 */
-	if (IS_QLA81XX(ha) || IS_QLA82XX(ha))
+	if (IS_QLA81XX(ha) || IS_QLA82XX(ha) || IS_QLA83XX(ha))
 		goto fail;
 	spin_lock_irq(&ha->hardware_lock);
 	if (IS_FWI2_CAPABLE(ha)) {
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 08f1d01..b4a2339 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -46,17 +46,17 @@
 	struct qla_hw_data *ha = vha->hw;
 	scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
 
-	ql_dbg(ql_dbg_mbx, base_vha, 0x1000, "Entered %s.\n", __func__);
+	ql_dbg(ql_dbg_mbx, vha, 0x1000, "Entered %s.\n", __func__);
 
 	if (ha->pdev->error_state > pci_channel_io_frozen) {
-		ql_log(ql_log_warn, base_vha, 0x1001,
+		ql_log(ql_log_warn, vha, 0x1001,
 		    "error_state is greater than pci_channel_io_frozen, "
 		    "exiting.\n");
 		return QLA_FUNCTION_TIMEOUT;
 	}
 
 	if (vha->device_flags & DFLG_DEV_FAILED) {
-		ql_log(ql_log_warn, base_vha, 0x1002,
+		ql_log(ql_log_warn, vha, 0x1002,
 		    "Device in failed state, exiting.\n");
 		return QLA_FUNCTION_TIMEOUT;
 	}
@@ -69,7 +69,7 @@
 
 
 	if (ha->flags.pci_channel_io_perm_failure) {
-		ql_log(ql_log_warn, base_vha, 0x1003,
+		ql_log(ql_log_warn, vha, 0x1003,
 		    "Perm failure on EEH timeout MBX, exiting.\n");
 		return QLA_FUNCTION_TIMEOUT;
 	}
@@ -77,7 +77,7 @@
 	if (ha->flags.isp82xx_fw_hung) {
 		/* Setting Link-Down error */
 		mcp->mb[0] = MBS_LINK_DOWN_ERROR;
-		ql_log(ql_log_warn, base_vha, 0x1004,
+		ql_log(ql_log_warn, vha, 0x1004,
 		    "FW hung = %d.\n", ha->flags.isp82xx_fw_hung);
 		return QLA_FUNCTION_TIMEOUT;
 	}
@@ -89,8 +89,9 @@
 	 */
 	if (!wait_for_completion_timeout(&ha->mbx_cmd_comp, mcp->tov * HZ)) {
 		/* Timeout occurred. Return error. */
-		ql_log(ql_log_warn, base_vha, 0x1005,
-		    "Cmd access timeout, Exiting.\n");
+		ql_log(ql_log_warn, vha, 0x1005,
+		    "Cmd access timeout, cmd=0x%x, Exiting.\n",
+		    mcp->mb[0]);
 		return QLA_FUNCTION_TIMEOUT;
 	}
 
@@ -98,7 +99,7 @@
 	/* Save mailbox command for debug */
 	ha->mcp = mcp;
 
-	ql_dbg(ql_dbg_mbx, base_vha, 0x1006,
+	ql_dbg(ql_dbg_mbx, vha, 0x1006,
 	    "Prepare to issue mbox cmd=0x%x.\n", mcp->mb[0]);
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -127,28 +128,28 @@
 		iptr++;
 	}
 
-	ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1111,
+	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, base_vha, 0x1112,
+	ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1112,
 	    (uint8_t *)mcp->mb, 16);
-	ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1113,
+	ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1113,
 	    ".\n");
-	ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1114,
+	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, base_vha, 0x1115,
+	ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1115,
 	    ".\n");
-	ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1116,
+	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, base_vha, 0x1117,
+	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, base_vha, 0x100e);
+	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;
 	clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
 
 	/* Unlock mbx registers and wait for interrupt */
-	ql_dbg(ql_dbg_mbx, base_vha, 0x100f,
+	ql_dbg(ql_dbg_mbx, vha, 0x100f,
 	    "Going to unlock irq & waiting for interrupts. "
 	    "jiffies=%lx.\n", jiffies);
 
@@ -163,7 +164,7 @@
 				spin_unlock_irqrestore(&ha->hardware_lock,
 					flags);
 				ha->flags.mbox_busy = 0;
-				ql_dbg(ql_dbg_mbx, base_vha, 0x1010,
+				ql_dbg(ql_dbg_mbx, vha, 0x1010,
 				    "Pending mailbox timeout, exiting.\n");
 				rval = QLA_FUNCTION_TIMEOUT;
 				goto premature_exit;
@@ -180,7 +181,7 @@
 		clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
 
 	} else {
-		ql_dbg(ql_dbg_mbx, base_vha, 0x1011,
+		ql_dbg(ql_dbg_mbx, vha, 0x1011,
 		    "Cmd=%x Polling Mode.\n", command);
 
 		if (IS_QLA82XX(ha)) {
@@ -189,7 +190,7 @@
 				spin_unlock_irqrestore(&ha->hardware_lock,
 					flags);
 				ha->flags.mbox_busy = 0;
-				ql_dbg(ql_dbg_mbx, base_vha, 0x1012,
+				ql_dbg(ql_dbg_mbx, vha, 0x1012,
 				    "Pending mailbox timeout, exiting.\n");
 				rval = QLA_FUNCTION_TIMEOUT;
 				goto premature_exit;
@@ -214,7 +215,7 @@
 			    command == MBC_LOAD_RISC_RAM_EXTENDED))
 				msleep(10);
 		} /* while */
-		ql_dbg(ql_dbg_mbx, base_vha, 0x1013,
+		ql_dbg(ql_dbg_mbx, vha, 0x1013,
 		    "Waited %d sec.\n",
 		    (uint)((jiffies - (wait_time - (mcp->tov * HZ)))/HZ));
 	}
@@ -223,7 +224,7 @@
 	if (ha->flags.mbox_int) {
 		uint16_t *iptr2;
 
-		ql_dbg(ql_dbg_mbx, base_vha, 0x1014,
+		ql_dbg(ql_dbg_mbx, vha, 0x1014,
 		    "Cmd=%x completed.\n", command);
 
 		/* Got interrupt. Clear the flag. */
@@ -236,7 +237,7 @@
 			mcp->mb[0] = MBS_LINK_DOWN_ERROR;
 			ha->mcp = NULL;
 			rval = QLA_FUNCTION_FAILED;
-			ql_log(ql_log_warn, base_vha, 0x1015,
+			ql_log(ql_log_warn, vha, 0x1015,
 			    "FW hung = %d.\n", ha->flags.isp82xx_fw_hung);
 			goto premature_exit;
 		}
@@ -268,13 +269,19 @@
 			mb0 = RD_MAILBOX_REG(ha, &reg->isp, 0);
 			ictrl = RD_REG_WORD(&reg->isp.ictrl);
 		}
-		ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1119,
+		ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1119,
 		    "MBX Command timeout for cmd %x.\n", command);
-		ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x111a,
+		ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111a,
 		    "iocontrol=%x jiffies=%lx.\n", ictrl, jiffies);
-		ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x111b,
+		ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111b,
 		    "mb[0] = 0x%x.\n", mb0);
-		ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1019);
+		ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1019);
+
+		/*
+		 * Attempt to capture a firmware dump for further analysis
+		 * of the current firmware state
+		 */
+		ha->isp_ops->fw_dump(vha, 0);
 
 		rval = QLA_FUNCTION_TIMEOUT;
 	}
@@ -285,7 +292,7 @@
 	ha->mcp = NULL;
 
 	if ((abort_active || !io_lock_on) && !IS_NOPOLLING_TYPE(ha)) {
-		ql_dbg(ql_dbg_mbx, base_vha, 0x101a,
+		ql_dbg(ql_dbg_mbx, vha, 0x101a,
 		    "Checking for additional resp interrupt.\n");
 
 		/* polling mode for non isp_abort commands. */
@@ -297,7 +304,7 @@
 		if (!io_lock_on || (mcp->flags & IOCTL_CMD) ||
 		    ha->flags.eeh_busy) {
 			/* not in dpc. schedule it for dpc to take over. */
-			ql_dbg(ql_dbg_mbx, base_vha, 0x101b,
+			ql_dbg(ql_dbg_mbx, vha, 0x101b,
 			    "Timeout, schedule isp_abort_needed.\n");
 
 			if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
@@ -313,15 +320,16 @@
 					    CRB_NIU_XG_PAUSE_CTL_P1);
 				}
 				ql_log(ql_log_info, base_vha, 0x101c,
-				    "Mailbox cmd timeout occured. "
-				    "Scheduling ISP abort eeh_busy=0x%x.\n",
-					ha->flags.eeh_busy);
+				    "Mailbox cmd timeout occured, cmd=0x%x, "
+				    "mb[0]=0x%x, eeh_busy=0x%x. Scheduling ISP "
+				    "abort.\n", command, mcp->mb[0],
+				    ha->flags.eeh_busy);
 				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
 				qla2xxx_wake_dpc(vha);
 			}
 		} else if (!abort_active) {
 			/* call abort directly since we are in the DPC thread */
-			ql_dbg(ql_dbg_mbx, base_vha, 0x101d,
+			ql_dbg(ql_dbg_mbx, vha, 0x101d,
 			    "Timeout, calling abort_isp.\n");
 
 			if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
@@ -337,9 +345,9 @@
 					    CRB_NIU_XG_PAUSE_CTL_P1);
 				}
 				ql_log(ql_log_info, base_vha, 0x101e,
-				    "Mailbox cmd timeout occured. "
-				    "Scheduling ISP abort.\n");
-
+				    "Mailbox cmd timeout occured, cmd=0x%x, "
+				    "mb[0]=0x%x. Scheduling ISP abort ",
+				    command, mcp->mb[0]);
 				set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
 				clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
 				/* Allow next mbx cmd to come in. */
@@ -350,7 +358,7 @@
 					    &vha->dpc_flags);
 				}
 				clear_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
-				ql_dbg(ql_dbg_mbx, base_vha, 0x101f,
+				ql_dbg(ql_dbg_mbx, vha, 0x101f,
 				    "Finished abort_isp.\n");
 				goto mbx_done;
 			}
@@ -364,8 +372,8 @@
 mbx_done:
 	if (rval) {
 		ql_dbg(ql_dbg_mbx, base_vha, 0x1020,
-		    "**** Failed mbx[0]=%x, mb[1]=%x, mb[2]=%x, cmd=%x ****.\n",
-		    mcp->mb[0], mcp->mb[1], mcp->mb[2], command);
+		    "**** Failed mbx[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x, cmd=%x ****.\n",
+		    mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], command);
 	} else {
 		ql_dbg(ql_dbg_mbx, base_vha, 0x1021, "Done %s.\n", __func__);
 	}
@@ -455,7 +463,7 @@
 		mcp->mb[1] = MSW(risc_addr);
 		mcp->mb[2] = LSW(risc_addr);
 		mcp->mb[3] = 0;
-		if (IS_QLA81XX(ha)) {
+		if (IS_QLA81XX(ha) || IS_QLA83XX(ha)) {
 			struct nvram_81xx *nv = ha->nvram;
 			mcp->mb[4] = (nv->enhanced_features &
 			    EXTENDED_BB_CREDITS);
@@ -508,21 +516,22 @@
  *	Kernel context.
  */
 int
-qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor,
-    uint16_t *subminor, uint16_t *attributes, uint32_t *memory, uint8_t *mpi,
-    uint32_t *mpi_caps, uint8_t *phy)
+qla2x00_get_fw_version(scsi_qla_host_t *vha)
 {
 	int		rval;
 	mbx_cmd_t	mc;
 	mbx_cmd_t	*mcp = &mc;
+	struct qla_hw_data *ha = vha->hw;
 
 	ql_dbg(ql_dbg_mbx, vha, 0x1029, "Entered %s.\n", __func__);
 
 	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))
+	if (IS_QLA81XX(vha->hw) || IS_QLA8031(ha))
 		mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8;
+	if (IS_QLA83XX(vha->hw))
+		mcp->in_mb |= MBX_17|MBX_16|MBX_15;
 	mcp->flags = 0;
 	mcp->tov = MBX_TOV_SECONDS;
 	rval = qla2x00_mailbox_command(vha, mcp);
@@ -530,23 +539,37 @@
 		goto failed;
 
 	/* Return mailbox data. */
-	*major = mcp->mb[1];
-	*minor = mcp->mb[2];
-	*subminor = mcp->mb[3];
-	*attributes = mcp->mb[6];
+	ha->fw_major_version = mcp->mb[1];
+	ha->fw_minor_version = mcp->mb[2];
+	ha->fw_subminor_version = mcp->mb[3];
+	ha->fw_attributes = mcp->mb[6];
 	if (IS_QLA2100(vha->hw) || IS_QLA2200(vha->hw))
-		*memory = 0x1FFFF;			/* Defaults to 128KB. */
+		ha->fw_memory_size = 0x1FFFF;		/* Defaults to 128KB. */
 	else
-		*memory = (mcp->mb[5] << 16) | mcp->mb[4];
-	if (IS_QLA81XX(vha->hw)) {
-		mpi[0] = mcp->mb[10] & 0xff;
-		mpi[1] = mcp->mb[11] >> 8;
-		mpi[2] = mcp->mb[11] & 0xff;
-		*mpi_caps = (mcp->mb[12] << 16) | mcp->mb[13];
-		phy[0] = mcp->mb[8] & 0xff;
-		phy[1] = mcp->mb[9] >> 8;
-		phy[2] = mcp->mb[9] & 0xff;
+		ha->fw_memory_size = (mcp->mb[5] << 16) | mcp->mb[4];
+	if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw)) {
+		ha->mpi_version[0] = mcp->mb[10] & 0xff;
+		ha->mpi_version[1] = mcp->mb[11] >> 8;
+		ha->mpi_version[2] = mcp->mb[11] & 0xff;
+		ha->mpi_capabilities = (mcp->mb[12] << 16) | mcp->mb[13];
+		ha->phy_version[0] = mcp->mb[8] & 0xff;
+		ha->phy_version[1] = mcp->mb[9] >> 8;
+		ha->phy_version[2] = mcp->mb[9] & 0xff;
 	}
+	if (IS_QLA83XX(ha)) {
+		if (mcp->mb[6] & BIT_15) {
+			ha->fw_attributes_h = mcp->mb[15];
+			ha->fw_attributes_ext[0] = mcp->mb[16];
+			ha->fw_attributes_ext[1] = mcp->mb[17];
+			ql_dbg(ql_dbg_mbx, vha, 0x1139,
+			    "%s: FW_attributes Upper: 0x%x, Lower: 0x%x.\n",
+			    __func__, mcp->mb[15], mcp->mb[6]);
+		} else
+			ql_dbg(ql_dbg_mbx, vha, 0x112f,
+			    "%s: FwAttributes [Upper]  invalid, MB6:%04x\n",
+			    __func__, mcp->mb[6]);
+	}
+
 failed:
 	if (rval != QLA_SUCCESS) {
 		/*EMPTY*/
@@ -859,6 +882,7 @@
 	scsi_qla_host_t *vha = fcport->vha;
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req = vha->req;
+	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
 
 	ql_dbg(ql_dbg_mbx, vha, 0x103b, "Entered %s.\n", __func__);
 
@@ -881,7 +905,7 @@
 		mcp->mb[1] = fcport->loop_id << 8;
 	mcp->mb[2] = (uint16_t)handle;
 	mcp->mb[3] = (uint16_t)(handle >> 16);
-	mcp->mb[6] = (uint16_t)sp->cmd->device->lun;
+	mcp->mb[6] = (uint16_t)cmd->device->lun;
 	mcp->out_mb = MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
 	mcp->in_mb = MBX_0;
 	mcp->tov = MBX_TOV_SECONDS;
@@ -1028,7 +1052,7 @@
 	mcp->mb[9] = vha->vp_idx;
 	mcp->out_mb = MBX_9|MBX_0;
 	mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
-	if (IS_QLA8XXX_TYPE(vha->hw))
+	if (IS_CNA_CAPABLE(vha->hw))
 		mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10;
 	mcp->tov = MBX_TOV_SECONDS;
 	mcp->flags = 0;
@@ -1052,7 +1076,7 @@
 	} else {
 		ql_dbg(ql_dbg_mbx, vha, 0x1048, "Done %s.\n", __func__);
 
-		if (IS_QLA8XXX_TYPE(vha->hw)) {
+		if (IS_CNA_CAPABLE(vha->hw)) {
 			vha->fcoe_vlan_id = mcp->mb[9] & 0xfff;
 			vha->fcoe_fcf_idx = mcp->mb[10];
 			vha->fcoe_vn_port_mac[5] = mcp->mb[11] >> 8;
@@ -1163,7 +1187,7 @@
 	mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
 	mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
 	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
-	if (IS_QLA81XX(ha) && ha->ex_init_cb->ex_version) {
+	if ((IS_QLA81XX(ha) || IS_QLA83XX(ha)) && ha->ex_init_cb->ex_version) {
 		mcp->mb[1] = BIT_0;
 		mcp->mb[10] = MSW(ha->ex_init_cb_dma);
 		mcp->mb[11] = LSW(ha->ex_init_cb_dma);
@@ -1172,7 +1196,11 @@
 		mcp->mb[14] = sizeof(*ha->ex_init_cb);
 		mcp->out_mb |= MBX_14|MBX_13|MBX_12|MBX_11|MBX_10;
 	}
-	mcp->in_mb = MBX_0;
+	/* 1 and 2 should normally be captured. */
+	mcp->in_mb = MBX_2|MBX_1|MBX_0;
+	if (IS_QLA83XX(ha))
+		/* mb3 is additional info about the installed SFP. */
+		mcp->in_mb  |= MBX_3;
 	mcp->buf_size = size;
 	mcp->flags = MBX_DMA_OUT;
 	mcp->tov = MBX_TOV_SECONDS;
@@ -1181,7 +1209,8 @@
 	if (rval != QLA_SUCCESS) {
 		/*EMPTY*/
 		ql_dbg(ql_dbg_mbx, vha, 0x104d,
-		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+		    "Failed=%x mb[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x,.\n",
+		    rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3]);
 	} else {
 		/*EMPTY*/
 		ql_dbg(ql_dbg_mbx, vha, 0x104e, "Done %s.\n", __func__);
@@ -1260,6 +1289,7 @@
 		goto gpd_error_out;
 
 	if (IS_FWI2_CAPABLE(ha)) {
+		uint64_t zero = 0;
 		pd24 = (struct port_database_24xx *) pd;
 
 		/* Check for logged in state. */
@@ -1273,6 +1303,14 @@
 			goto gpd_error_out;
 		}
 
+		if (fcport->loop_id == FC_NO_LOOP_ID ||
+		    (memcmp(fcport->port_name, (uint8_t *)&zero, 8) &&
+		     memcmp(fcport->port_name, pd24->port_name, 8))) {
+			/* We lost the device mid way. */
+			rval = QLA_NOT_LOGGED_IN;
+			goto gpd_error_out;
+		}
+
 		/* Names are little-endian. */
 		memcpy(fcport->node_name, pd24->node_name, WWN_SIZE);
 		memcpy(fcport->port_name, pd24->port_name, WWN_SIZE);
@@ -1289,6 +1327,8 @@
 		else
 			fcport->port_type = FCT_TARGET;
 	} else {
+		uint64_t zero = 0;
+
 		/* Check for logged in state. */
 		if (pd->master_state != PD_STATE_PORT_LOGGED_IN &&
 		    pd->slave_state != PD_STATE_PORT_LOGGED_IN) {
@@ -1301,6 +1341,14 @@
 			goto gpd_error_out;
 		}
 
+		if (fcport->loop_id == FC_NO_LOOP_ID ||
+		    (memcmp(fcport->port_name, (uint8_t *)&zero, 8) &&
+		     memcmp(fcport->port_name, pd->port_name, 8))) {
+			/* We lost the device mid way. */
+			rval = QLA_NOT_LOGGED_IN;
+			goto gpd_error_out;
+		}
+
 		/* Names are little-endian. */
 		memcpy(fcport->node_name, pd->node_name, WWN_SIZE);
 		memcpy(fcport->port_name, pd->port_name, WWN_SIZE);
@@ -1481,7 +1529,7 @@
 
 	ql_dbg(ql_dbg_mbx, vha, 0x105a, "Entered %s.\n", __func__);
 
-	if (IS_QLA8XXX_TYPE(vha->hw)) {
+	if (IS_CNA_CAPABLE(vha->hw)) {
 		/* Logout across all FCFs. */
 		mcp->mb[0] = MBC_LIP_FULL_LOGIN;
 		mcp->mb[1] = BIT_1;
@@ -1622,7 +1670,8 @@
 	lg->port_id[1] = area;
 	lg->port_id[2] = domain;
 	lg->vp_index = vha->vp_idx;
-	rval = qla2x00_issue_iocb(vha, lg, lg_dma, 0);
+	rval = qla2x00_issue_iocb_timeout(vha, lg, lg_dma, 0,
+	    (ha->r_a_tov / 10 * 2) + 2);
 	if (rval != QLA_SUCCESS) {
 		ql_dbg(ql_dbg_mbx, vha, 0x1063,
 		    "Failed to issue login IOCB (%x).\n", rval);
@@ -1885,8 +1934,8 @@
 	lg->port_id[1] = area;
 	lg->port_id[2] = domain;
 	lg->vp_index = vha->vp_idx;
-
-	rval = qla2x00_issue_iocb(vha, lg, lg_dma, 0);
+	rval = qla2x00_issue_iocb_timeout(vha, lg, lg_dma, 0,
+	    (ha->r_a_tov / 10 * 2) + 2);
 	if (rval != QLA_SUCCESS) {
 		ql_dbg(ql_dbg_mbx, vha, 0x106f,
 		    "Failed to issue logout IOCB (%x).\n", rval);
@@ -2094,7 +2143,7 @@
 	mcp->mb[0] = MBC_GET_RESOURCE_COUNTS;
 	mcp->out_mb = MBX_0;
 	mcp->in_mb = MBX_11|MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
-	if (IS_QLA81XX(vha->hw))
+	if (IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw))
 		mcp->in_mb |= MBX_12;
 	mcp->tov = MBX_TOV_SECONDS;
 	mcp->flags = 0;
@@ -2121,7 +2170,7 @@
 			*orig_iocb_cnt = mcp->mb[10];
 		if (vha->hw->flags.npiv_supported && max_npiv_vports)
 			*max_npiv_vports = mcp->mb[11];
-		if (IS_QLA81XX(vha->hw) && max_fcfs)
+		if ((IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw)) && max_fcfs)
 			*max_fcfs = mcp->mb[12];
 	}
 
@@ -2686,7 +2735,8 @@
 
 	ql_dbg(ql_dbg_mbx, vha, 0x10aa, "Entered %s.\n", __func__);
 
-	if (!IS_QLA25XX(vha->hw) && !IS_QLA81XX(vha->hw))
+	if (!IS_QLA25XX(vha->hw) && !IS_QLA81XX(vha->hw) &&
+	    !IS_QLA83XX(vha->hw))
 		return QLA_FUNCTION_FAILED;
 
 	if (unlikely(pci_channel_offline(vha->hw->pdev)))
@@ -2828,7 +2878,7 @@
 	mcp->mb[0] = MBC_PORT_PARAMS;
 	mcp->mb[1] = loop_id;
 	mcp->mb[2] = BIT_0;
-	if (IS_QLA8XXX_TYPE(vha->hw))
+	if (IS_CNA_CAPABLE(vha->hw))
 		mcp->mb[3] = port_speed & (BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0);
 	else
 		mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
@@ -3298,6 +3348,8 @@
 	mcp->mb[12] = req->qos;
 	mcp->mb[11] = req->vp_idx;
 	mcp->mb[13] = req->rid;
+	if (IS_QLA83XX(ha))
+		mcp->mb[15] = 0;
 
 	reg = (struct device_reg_25xxmq *)((void *)(ha->mqiobase) +
 		QLA_QUE_PAGE * req->id);
@@ -3311,12 +3363,21 @@
 			MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
 	mcp->in_mb = MBX_0;
 	mcp->flags = MBX_DMA_OUT;
-	mcp->tov = 60;
+	mcp->tov = MBX_TOV_SECONDS * 2;
+
+	if (IS_QLA81XX(ha) || IS_QLA83XX(ha))
+		mcp->in_mb |= MBX_1;
+	if (IS_QLA83XX(ha)) {
+		mcp->out_mb |= MBX_15;
+		/* debug q create issue in SR-IOV */
+		mcp->in_mb |= MBX_9 | MBX_8 | MBX_7;
+	}
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	if (!(req->options & BIT_0)) {
 		WRT_REG_DWORD(&reg->req_q_in, 0);
-		WRT_REG_DWORD(&reg->req_q_out, 0);
+		if (!IS_QLA83XX(ha))
+			WRT_REG_DWORD(&reg->req_q_out, 0);
 	}
 	req->req_q_in = &reg->req_q_in;
 	req->req_q_out = &reg->req_q_out;
@@ -3354,6 +3415,8 @@
 	mcp->mb[5] = rsp->length;
 	mcp->mb[14] = rsp->msix->entry;
 	mcp->mb[13] = rsp->rid;
+	if (IS_QLA83XX(ha))
+		mcp->mb[15] = 0;
 
 	reg = (struct device_reg_25xxmq *)((void *)(ha->mqiobase) +
 		QLA_QUE_PAGE * rsp->id);
@@ -3367,12 +3430,23 @@
 			|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
 	mcp->in_mb = MBX_0;
 	mcp->flags = MBX_DMA_OUT;
-	mcp->tov = 60;
+	mcp->tov = MBX_TOV_SECONDS * 2;
+
+	if (IS_QLA81XX(ha)) {
+		mcp->out_mb |= MBX_12|MBX_11|MBX_10;
+		mcp->in_mb |= MBX_1;
+	} else if (IS_QLA83XX(ha)) {
+		mcp->out_mb |= MBX_15|MBX_12|MBX_11|MBX_10;
+		mcp->in_mb |= MBX_1;
+		/* debug q create issue in SR-IOV */
+		mcp->in_mb |= MBX_9 | MBX_8 | MBX_7;
+	}
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	if (!(rsp->options & BIT_0)) {
 		WRT_REG_DWORD(&reg->rsp_q_out, 0);
-		WRT_REG_DWORD(&reg->rsp_q_in, 0);
+		if (!IS_QLA83XX(ha))
+			WRT_REG_DWORD(&reg->rsp_q_in, 0);
 	}
 
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -3424,7 +3498,7 @@
 
 	ql_dbg(ql_dbg_mbx, vha, 0x10dc, "Entered %s.\n", __func__);
 
-	if (!IS_QLA81XX(vha->hw))
+	if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw))
 		return QLA_FUNCTION_FAILED;
 
 	mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
@@ -3454,7 +3528,7 @@
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
-	if (!IS_QLA81XX(vha->hw))
+	if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw))
 		return QLA_FUNCTION_FAILED;
 
 	ql_dbg(ql_dbg_mbx, vha, 0x10df, "Entered %s.\n", __func__);
@@ -3486,7 +3560,7 @@
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
-	if (!IS_QLA81XX(vha->hw))
+	if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw))
 		return QLA_FUNCTION_FAILED;
 
 	ql_dbg(ql_dbg_mbx, vha, 0x10e2, "Entered %s.\n", __func__);
@@ -3641,7 +3715,7 @@
 
 	ql_dbg(ql_dbg_mbx, vha, 0x10ee, "Entered %s.\n", __func__);
 
-	if (!IS_QLA8XXX_TYPE(vha->hw))
+	if (!IS_CNA_CAPABLE(vha->hw))
 		return QLA_FUNCTION_FAILED;
 
 	mcp->mb[0] = MBC_GET_XGMAC_STATS;
@@ -3680,7 +3754,7 @@
 
 	ql_dbg(ql_dbg_mbx, vha, 0x10f1, "Entered %s.\n", __func__);
 
-	if (!IS_QLA8XXX_TYPE(vha->hw))
+	if (!IS_CNA_CAPABLE(vha->hw))
 		return QLA_FUNCTION_FAILED;
 
 	mcp->mb[0] = MBC_GET_DCBX_PARAMS;
@@ -3775,7 +3849,7 @@
 
 	mcp->out_mb = MBX_21|MBX_20|MBX_19|MBX_18|MBX_17|MBX_16|MBX_15|
 	    MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0;
-	if (IS_QLA8XXX_TYPE(vha->hw))
+	if (IS_CNA_CAPABLE(vha->hw))
 		mcp->out_mb |= MBX_2;
 	mcp->in_mb = MBX_19|MBX_18|MBX_3|MBX_2|MBX_1|MBX_0;
 
@@ -3813,7 +3887,7 @@
 	memset(mcp->mb, 0 , sizeof(mcp->mb));
 	mcp->mb[0] = MBC_DIAGNOSTIC_ECHO;
 	mcp->mb[1] = mreq->options | BIT_6;	/* BIT_6 specifies 64bit address */
-	if (IS_QLA8XXX_TYPE(ha)) {
+	if (IS_CNA_CAPABLE(ha)) {
 		mcp->mb[1] |= BIT_15;
 		mcp->mb[2] = vha->fcoe_fcf_idx;
 	}
@@ -3831,13 +3905,14 @@
 
 	mcp->out_mb = MBX_21|MBX_20|MBX_17|MBX_16|MBX_15|
 	    MBX_14|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0;
-	if (IS_QLA8XXX_TYPE(ha))
+	if (IS_CNA_CAPABLE(ha))
 		mcp->out_mb |= MBX_2;
 
 	mcp->in_mb = MBX_0;
-	if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA8XXX_TYPE(ha))
+	if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
+	    IS_CNA_CAPABLE(ha) || IS_QLA2031(ha))
 		mcp->in_mb |= MBX_1;
-	if (IS_QLA8XXX_TYPE(ha))
+	if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha))
 		mcp->in_mb |= MBX_3;
 
 	mcp->tov = MBX_TOV_SECONDS;
@@ -3976,6 +4051,7 @@
 
 	return rval;
 }
+
 int
 qla2x00_get_data_rate(scsi_qla_host_t *vha)
 {
@@ -3993,6 +4069,8 @@
 	mcp->mb[1] = 0;
 	mcp->out_mb = MBX_1|MBX_0;
 	mcp->in_mb = MBX_2|MBX_1|MBX_0;
+	if (IS_QLA83XX(ha))
+		mcp->in_mb |= MBX_3;
 	mcp->tov = MBX_TOV_SECONDS;
 	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(vha, mcp);
@@ -4018,7 +4096,7 @@
 
 	ql_dbg(ql_dbg_mbx, vha, 0x1109, "Entered %s.\n", __func__);
 
-	if (!IS_QLA81XX(ha))
+	if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
 		return QLA_FUNCTION_FAILED;
 	mcp->mb[0] = MBC_GET_PORT_CONFIG;
 	mcp->out_mb = MBX_0;
@@ -4299,6 +4377,90 @@
 }
 
 int
+qla81xx_set_led_config(scsi_qla_host_t *vha, uint16_t *led_cfg)
+{
+	int rval;
+	struct qla_hw_data *ha = vha->hw;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
+		return QLA_FUNCTION_FAILED;
+
+	ql_dbg(ql_dbg_mbx, vha, 0x1133, "Entered %s.\n", __func__);
+
+	memset(mcp, 0, sizeof(mbx_cmd_t));
+	mcp->mb[0] = MBC_SET_LED_CONFIG;
+	mcp->mb[1] = led_cfg[0];
+	mcp->mb[2] = led_cfg[1];
+	if (IS_QLA8031(ha)) {
+		mcp->mb[3] = led_cfg[2];
+		mcp->mb[4] = led_cfg[3];
+		mcp->mb[5] = led_cfg[4];
+		mcp->mb[6] = led_cfg[5];
+	}
+
+	mcp->out_mb = MBX_2|MBX_1|MBX_0;
+	if (IS_QLA8031(ha))
+		mcp->out_mb |= MBX_6|MBX_5|MBX_4|MBX_3;
+	mcp->in_mb = MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+
+	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS) {
+		ql_dbg(ql_dbg_mbx, vha, 0x1134,
+		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+	} else {
+		ql_dbg(ql_dbg_mbx, vha, 0x1135, "Done %s.\n", __func__);
+	}
+
+	return rval;
+}
+
+int
+qla81xx_get_led_config(scsi_qla_host_t *vha, uint16_t *led_cfg)
+{
+	int rval;
+	struct qla_hw_data *ha = vha->hw;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
+		return QLA_FUNCTION_FAILED;
+
+	ql_dbg(ql_dbg_mbx, vha, 0x1136, "Entered %s.\n", __func__);
+
+	memset(mcp, 0, sizeof(mbx_cmd_t));
+	mcp->mb[0] = MBC_GET_LED_CONFIG;
+
+	mcp->out_mb = MBX_0;
+	mcp->in_mb = MBX_2|MBX_1|MBX_0;
+	if (IS_QLA8031(ha))
+		mcp->in_mb |= MBX_6|MBX_5|MBX_4|MBX_3;
+	mcp->tov = 30;
+	mcp->flags = 0;
+
+	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS) {
+		ql_dbg(ql_dbg_mbx, vha, 0x1137,
+		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+	} else {
+		led_cfg[0] = mcp->mb[1];
+		led_cfg[1] = mcp->mb[2];
+		if (IS_QLA8031(ha)) {
+			led_cfg[2] = mcp->mb[3];
+			led_cfg[3] = mcp->mb[4];
+			led_cfg[4] = mcp->mb[5];
+			led_cfg[5] = mcp->mb[6];
+		}
+		ql_dbg(ql_dbg_mbx, vha, 0x1138, "Done %s.\n", __func__);
+	}
+
+	return rval;
+}
+
+int
 qla82xx_mbx_beacon_ctl(scsi_qla_host_t *vha, int enable)
 {
 	int rval;
@@ -4321,7 +4483,7 @@
 
 	mcp->out_mb = MBX_7|MBX_0;
 	mcp->in_mb = MBX_0;
-	mcp->tov = 30;
+	mcp->tov = MBX_TOV_SECONDS;
 	mcp->flags = 0;
 
 	rval = qla2x00_mailbox_command(vha, mcp);
@@ -4335,3 +4497,75 @@
 
 	return rval;
 }
+
+int
+qla83xx_write_remote_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t data)
+{
+	int rval;
+	struct qla_hw_data *ha = vha->hw;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	if (!IS_QLA83XX(ha))
+		return QLA_FUNCTION_FAILED;
+
+	ql_dbg(ql_dbg_mbx, vha, 0x1130, "Entered %s.\n", __func__);
+
+	mcp->mb[0] = MBC_WRITE_REMOTE_REG;
+	mcp->mb[1] = LSW(reg);
+	mcp->mb[2] = MSW(reg);
+	mcp->mb[3] = LSW(data);
+	mcp->mb[4] = MSW(data);
+	mcp->out_mb = MBX_4|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, 0x1131,
+		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+	} else {
+		ql_dbg(ql_dbg_mbx, vha, 0x1132,
+		    "Done %s.\n", __func__);
+	}
+
+	return rval;
+}
+
+int
+qla2x00_port_logout(scsi_qla_host_t *vha, struct fc_port *fcport)
+{
+	int rval;
+	struct qla_hw_data *ha = vha->hw;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+		ql_dbg(ql_dbg_mbx, vha, 0x113b,
+		    "Implicit LOGO Unsupported.\n");
+		return QLA_FUNCTION_FAILED;
+	}
+
+
+	ql_dbg(ql_dbg_mbx, vha, 0x113c, "Done %s.\n",  __func__);
+
+	/* Perform Implicit LOGO. */
+	mcp->mb[0] = MBC_PORT_LOGOUT;
+	mcp->mb[1] = fcport->loop_id;
+	mcp->mb[10] = BIT_15;
+	mcp->out_mb = MBX_10|MBX_1|MBX_0;
+	mcp->in_mb = 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, 0x113d,
+		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+	else
+		ql_dbg(ql_dbg_mbx, vha, 0x113e, "Done %s.\n", __func__);
+
+	return rval;
+}
+
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index f488cc6..aa062a1 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -479,7 +479,7 @@
 	host->max_channel = MAX_BUSES - 1;
 	host->max_lun = ql2xmaxlun;
 	host->unique_id = host->host_no;
-	host->max_id = MAX_TARGETS_2200;
+	host->max_id = ha->max_fibre_devices;
 	host->transportt = qla2xxx_transport_vport_template;
 
 	ql_dbg(ql_dbg_vport, vha, 0xa007,
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index 270ba31..f052853 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -908,27 +908,37 @@
 	return 0;
 }
 
+int
+qla82xx_md_rw_32(struct qla_hw_data *ha, uint32_t off, u32 data, uint8_t flag)
+{
+	uint32_t  off_value, rval = 0;
+
+	WRT_REG_DWORD((void *)(CRB_WINDOW_2M + ha->nx_pcibase),
+	    (off & 0xFFFF0000));
+
+	/* Read back value to make sure write has gone through */
+	RD_REG_DWORD((void *)(CRB_WINDOW_2M + ha->nx_pcibase));
+	off_value  = (off & 0x0000FFFF);
+
+	if (flag)
+		WRT_REG_DWORD((void *)
+		    (off_value + CRB_INDIRECT_2M + ha->nx_pcibase),
+		    data);
+	else
+		rval = RD_REG_DWORD((void *)
+		    (off_value + CRB_INDIRECT_2M + ha->nx_pcibase));
+
+	return rval;
+}
+
 static int
 qla82xx_do_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
 {
-	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+	/* Dword reads to flash. */
+	qla82xx_md_rw_32(ha, MD_DIRECT_ROM_WINDOW, (addr & 0xFFFF0000), 1);
+	*valp = qla82xx_md_rw_32(ha, MD_DIRECT_ROM_READ_BASE +
+	    (addr & 0x0000FFFF), 0, 0);
 
-	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr);
-	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
-	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3);
-	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0xb);
-	qla82xx_wait_rom_busy(ha);
-	if (qla82xx_wait_rom_done(ha)) {
-		ql_log(ql_log_fatal, vha, 0x00ba,
-		    "Error waiting for rom done.\n");
-		return -1;
-	}
-	/* Reset abyte_cnt and dummy_byte_cnt */
-	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
-	udelay(10);
-	cond_resched();
-	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0);
-	*valp = qla82xx_rd_32(ha, QLA82XX_ROMUSB_ROM_RDATA);
 	return 0;
 }
 
@@ -2040,8 +2050,8 @@
 
 	rsp = (struct rsp_que *) dev_id;
 	if (!rsp) {
-		printk(KERN_INFO
-			"%s(): NULL response queue pointer.\n", __func__);
+		ql_log(ql_log_info, NULL, 0xb054,
+		    "%s: NULL response queue pointer.\n", __func__);
 		return IRQ_NONE;
 	}
 	ha = rsp->hw;
@@ -3136,12 +3146,7 @@
 	fw_minor_version = ha->fw_minor_version;
 	fw_subminor_version = ha->fw_subminor_version;
 
-	rval = qla2x00_get_fw_version(vha, &ha->fw_major_version,
-	    &ha->fw_minor_version, &ha->fw_subminor_version,
-	    &ha->fw_attributes, &ha->fw_memory_size,
-	    ha->mpi_version, &ha->mpi_capabilities,
-	    ha->phy_version);
-
+	rval = qla2x00_get_fw_version(vha);
 	if (rval != QLA_SUCCESS)
 		return rval;
 
@@ -3150,7 +3155,6 @@
 			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,
 				    "Firmware version differs "
 				    "Previous version: %d:%d:%d - "
@@ -3614,7 +3618,7 @@
 			for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
 				sp = req->outstanding_cmds[cnt];
 				if (sp) {
-					if (!sp->ctx ||
+					if (!sp->u.scmd.ctx ||
 					    (sp->flags & SRB_FCP_CMND_DMA_VALID)) {
 						spin_unlock_irqrestore(
 						    &ha->hardware_lock, flags);
@@ -3645,29 +3649,6 @@
 }
 
 /* Minidump related functions */
-int
-qla82xx_md_rw_32(struct qla_hw_data *ha, uint32_t off, u32 data, uint8_t flag)
-{
-	uint32_t  off_value, rval = 0;
-
-	WRT_REG_DWORD((void *)(CRB_WINDOW_2M + ha->nx_pcibase),
-	    (off & 0xFFFF0000));
-
-	/* Read back value to make sure write has gone through */
-	RD_REG_DWORD((void *)(CRB_WINDOW_2M + ha->nx_pcibase));
-	off_value  = (off & 0x0000FFFF);
-
-	if (flag)
-		WRT_REG_DWORD((void *)
-		    (off_value + CRB_INDIRECT_2M + ha->nx_pcibase),
-		    data);
-	else
-		rval = RD_REG_DWORD((void *)
-		    (off_value + CRB_INDIRECT_2M + ha->nx_pcibase));
-
-	return rval;
-}
-
 static int
 qla82xx_minidump_process_control(scsi_qla_host_t *vha,
 	qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr)
@@ -4117,8 +4098,9 @@
 	data_ptr = (uint32_t *)ha->md_dump;
 
 	if (ha->fw_dumped) {
-		ql_log(ql_log_info, vha, 0xb037,
-		    "Firmware dump available to retrive\n");
+		ql_log(ql_log_warn, vha, 0xb037,
+		    "Firmware has been previously dumped (%p) "
+		    "-- ignoring request.\n", ha->fw_dump);
 		goto md_failed;
 	}
 
@@ -4161,7 +4143,7 @@
 
 	total_data_size = ha->md_dump_size;
 
-	ql_dbg(ql_log_info, vha, 0xb03d,
+	ql_dbg(ql_dbg_p3p, vha, 0xb03d,
 	    "Total minidump data_size 0x%x to be captured\n", total_data_size);
 
 	/* Check whether template obtained is valid */
@@ -4284,7 +4266,7 @@
 	}
 
 	if (data_collected != total_data_size) {
-		ql_dbg(ql_log_warn, vha, 0xb043,
+		ql_dbg(ql_dbg_p3p, vha, 0xb043,
 		    "MiniDump data mismatch: Data collected: [0x%x],"
 		    "total_data_size:[0x%x]\n",
 		    data_collected, total_data_size);
diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h
index 57a226b..4ac50e2 100644
--- a/drivers/scsi/qla2xxx/qla_nx.h
+++ b/drivers/scsi/qla2xxx/qla_nx.h
@@ -888,7 +888,8 @@
 };
 
 #define MBC_TOGGLE_INTERRUPT	0x10
-#define MBC_SET_LED_CONFIG	0x125
+#define MBC_SET_LED_CONFIG	0x125	/* FCoE specific LED control */
+#define MBC_GET_LED_CONFIG	0x126	/* FCoE specific LED control */
 
 /* Flash  offset */
 #define FLT_REG_BOOTLOAD_82XX	0x72
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 036030c..a2f9992 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -304,7 +304,6 @@
 	struct req_que **, struct rsp_que **);
 static void qla2x00_free_fw_dump(struct qla_hw_data *);
 static void qla2x00_mem_free(struct qla_hw_data *);
-static void qla2x00_sp_free_dma(srb_t *);
 
 /* -------------------------------------------------------------------------- */
 static int qla2x00_alloc_queues(struct qla_hw_data *ha)
@@ -559,28 +558,75 @@
 	return str;
 }
 
-static inline srb_t *
-qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport,
-	struct scsi_cmnd *cmd)
+void
+qla2x00_sp_free_dma(void *vha, void *ptr)
 {
-	srb_t *sp;
-	struct qla_hw_data *ha = vha->hw;
+	srb_t *sp = (srb_t *)ptr;
+	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
+	struct qla_hw_data *ha = sp->fcport->vha->hw;
+	void *ctx = GET_CMD_CTX_SP(sp);
 
-	sp = mempool_alloc(ha->srb_mempool, GFP_ATOMIC);
-	if (!sp) {
-		ql_log(ql_log_warn, vha, 0x3006,
-		    "Memory allocation failed for sp.\n");
-		return sp;
+	if (sp->flags & SRB_DMA_VALID) {
+		scsi_dma_unmap(cmd);
+		sp->flags &= ~SRB_DMA_VALID;
 	}
 
-	atomic_set(&sp->ref_count, 1);
-	sp->fcport = fcport;
-	sp->cmd = cmd;
-	sp->flags = 0;
-	CMD_SP(cmd) = (void *)sp;
-	sp->ctx = NULL;
+	if (sp->flags & SRB_CRC_PROT_DMA_VALID) {
+		dma_unmap_sg(&ha->pdev->dev, scsi_prot_sglist(cmd),
+		    scsi_prot_sg_count(cmd), cmd->sc_data_direction);
+		sp->flags &= ~SRB_CRC_PROT_DMA_VALID;
+	}
 
-	return sp;
+	if (sp->flags & SRB_CRC_CTX_DSD_VALID) {
+		/* List assured to be having elements */
+		qla2x00_clean_dsd_pool(ha, sp);
+		sp->flags &= ~SRB_CRC_CTX_DSD_VALID;
+	}
+
+	if (sp->flags & SRB_CRC_CTX_DMA_VALID) {
+		dma_pool_free(ha->dl_dma_pool, ctx,
+		    ((struct crc_context *)ctx)->crc_ctx_dma);
+		sp->flags &= ~SRB_CRC_CTX_DMA_VALID;
+	}
+
+	if (sp->flags & SRB_FCP_CMND_DMA_VALID) {
+		struct ct6_dsd *ctx1 = (struct ct6_dsd *)ctx;
+
+		dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd,
+			ctx1->fcp_cmnd_dma);
+		list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list);
+		ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt;
+		ha->gbl_dsd_avail += ctx1->dsd_use_cnt;
+		mempool_free(ctx1, ha->ctx_mempool);
+		ctx1 = NULL;
+	}
+
+	CMD_SP(cmd) = NULL;
+	mempool_free(sp, ha->srb_mempool);
+}
+
+static void
+qla2x00_sp_compl(void *data, void *ptr, int res)
+{
+	struct qla_hw_data *ha = (struct qla_hw_data *)data;
+	srb_t *sp = (srb_t *)ptr;
+	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
+
+	cmd->result = res;
+
+	if (atomic_read(&sp->ref_count) == 0) {
+		ql_dbg(ql_dbg_io, sp->fcport->vha, 0x3015,
+		    "SP reference-count to ZERO -- sp=%p cmd=%p.\n",
+		    sp, GET_CMD_SP(sp));
+		if (ql2xextended_error_logging & ql_dbg_io)
+			BUG();
+		return;
+	}
+	if (!atomic_dec_and_test(&sp->ref_count))
+		return;
+
+	qla2x00_sp_free_dma(ha, sp);
+	cmd->scsi_done(cmd);
 }
 
 static int
@@ -644,10 +690,17 @@
 		goto qc24_target_busy;
 	}
 
-	sp = qla2x00_get_new_sp(base_vha, fcport, cmd);
+	sp = qla2x00_get_sp(base_vha, fcport, GFP_ATOMIC);
 	if (!sp)
 		goto qc24_host_busy;
 
+	sp->u.scmd.cmd = cmd;
+	sp->type = SRB_SCSI_CMD;
+	atomic_set(&sp->ref_count, 1);
+	CMD_SP(cmd) = (void *)sp;
+	sp->free = qla2x00_sp_free_dma;
+	sp->done = qla2x00_sp_compl;
+
 	rval = ha->isp_ops->start_scsi(sp);
 	if (rval != QLA_SUCCESS) {
 		ql_dbg(ql_dbg_io, vha, 0x3013,
@@ -658,8 +711,7 @@
 	return 0;
 
 qc24_host_busy_free_sp:
-	qla2x00_sp_free_dma(sp);
-	mempool_free(sp, ha->srb_mempool);
+	qla2x00_sp_free_dma(ha, sp);
 
 qc24_host_busy:
 	return SCSI_MLQUEUE_HOST_BUSY;
@@ -893,7 +945,7 @@
 	}
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	qla2x00_sp_compl(ha, sp);
+	sp->done(ha, sp, 0);
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	/* Did the command return during mailbox execution? */
@@ -925,6 +977,7 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req;
 	srb_t *sp;
+	struct scsi_cmnd *cmd;
 
 	status = QLA_SUCCESS;
 
@@ -935,28 +988,29 @@
 		sp = req->outstanding_cmds[cnt];
 		if (!sp)
 			continue;
-		if ((sp->ctx) && !IS_PROT_IO(sp))
+		if (sp->type != SRB_SCSI_CMD)
 			continue;
 		if (vha->vp_idx != sp->fcport->vha->vp_idx)
 			continue;
 		match = 0;
+		cmd = GET_CMD_SP(sp);
 		switch (type) {
 		case WAIT_HOST:
 			match = 1;
 			break;
 		case WAIT_TARGET:
-			match = sp->cmd->device->id == t;
+			match = cmd->device->id == t;
 			break;
 		case WAIT_LUN:
-			match = (sp->cmd->device->id == t &&
-				sp->cmd->device->lun == l);
+			match = (cmd->device->id == t &&
+				cmd->device->lun == l);
 			break;
 		}
 		if (!match)
 			continue;
 
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
-		status = qla2x00_eh_wait_on_command(sp->cmd);
+		status = qla2x00_eh_wait_on_command(cmd);
 		spin_lock_irqsave(&ha->hardware_lock, flags);
 	}
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -1219,7 +1273,7 @@
 		}
 	}
 
-	if (ha->flags.enable_lip_full_login && !IS_QLA8XXX_TYPE(ha)) {
+	if (ha->flags.enable_lip_full_login && !IS_CNA_CAPABLE(ha)) {
 		ret = qla2x00_full_login_lip(vha);
 		if (ret != QLA_SUCCESS) {
 			ql_dbg(ql_dbg_taskm, vha, 0x802d,
@@ -1249,7 +1303,6 @@
 	int que, cnt;
 	unsigned long flags;
 	srb_t *sp;
-	struct srb_ctx *ctx;
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req;
 
@@ -1262,31 +1315,7 @@
 			sp = req->outstanding_cmds[cnt];
 			if (sp) {
 				req->outstanding_cmds[cnt] = NULL;
-				if (!sp->ctx ||
-					(sp->flags & SRB_FCP_CMND_DMA_VALID) ||
-					IS_PROT_IO(sp)) {
-					sp->cmd->result = res;
-					qla2x00_sp_compl(ha, sp);
-				} else {
-					ctx = sp->ctx;
-					if (ctx->type == SRB_ELS_CMD_RPT ||
-					    ctx->type == SRB_ELS_CMD_HST ||
-					    ctx->type == SRB_CT_CMD) {
-						struct fc_bsg_job *bsg_job =
-						    ctx->u.bsg_job;
-						if (bsg_job->request->msgcode
-						    == FC_BSG_HST_CT)
-							kfree(sp->fcport);
-						bsg_job->req->errors = 0;
-						bsg_job->reply->result = res;
-						bsg_job->job_done(bsg_job);
-						kfree(sp->ctx);
-						mempool_free(sp,
-							ha->srb_mempool);
-					} else {
-						ctx->u.iocb_cmd->free(sp);
-					}
-				}
+				sp->done(vha, sp, res);
 			}
 		}
 	}
@@ -1488,9 +1517,6 @@
 	uint16_t msix;
 	int cpus;
 
-	if (IS_QLA82XX(ha))
-		return qla82xx_iospace_config(ha);
-
 	if (pci_request_selected_regions(ha->pdev, ha->bars,
 	    QLA2XXX_DRIVER_NAME)) {
 		ql_log_pci(ql_log_fatal, ha->pdev, 0x0011,
@@ -1593,6 +1619,96 @@
 }
 
 
+static int
+qla83xx_iospace_config(struct qla_hw_data *ha)
+{
+	uint16_t msix;
+	int cpus;
+
+	if (pci_request_selected_regions(ha->pdev, ha->bars,
+	    QLA2XXX_DRIVER_NAME)) {
+		ql_log_pci(ql_log_fatal, ha->pdev, 0x0117,
+		    "Failed to reserve PIO/MMIO regions (%s), aborting.\n",
+		    pci_name(ha->pdev));
+
+		goto iospace_error_exit;
+	}
+
+	/* Use MMIO operations for all accesses. */
+	if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) {
+		ql_log_pci(ql_log_warn, ha->pdev, 0x0118,
+		    "Invalid pci I/O region size (%s).\n",
+		    pci_name(ha->pdev));
+		goto iospace_error_exit;
+	}
+	if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) {
+		ql_log_pci(ql_log_warn, ha->pdev, 0x0119,
+		    "Invalid PCI mem region size (%s), aborting\n",
+			pci_name(ha->pdev));
+		goto iospace_error_exit;
+	}
+
+	ha->iobase = ioremap(pci_resource_start(ha->pdev, 0), MIN_IOBASE_LEN);
+	if (!ha->iobase) {
+		ql_log_pci(ql_log_fatal, ha->pdev, 0x011a,
+		    "Cannot remap MMIO (%s), aborting.\n",
+		    pci_name(ha->pdev));
+		goto iospace_error_exit;
+	}
+
+	/* 64bit PCI BAR - BAR2 will correspoond to region 4 */
+	/* 83XX 26XX always use MQ type access for queues
+	 * - mbar 2, a.k.a region 4 */
+	ha->max_req_queues = ha->max_rsp_queues = 1;
+	ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 4),
+			pci_resource_len(ha->pdev, 4));
+
+	if (!ha->mqiobase) {
+		ql_log_pci(ql_log_fatal, ha->pdev, 0x011d,
+		    "BAR2/region4 not enabled\n");
+		goto mqiobase_exit;
+	}
+
+	ha->msixbase = ioremap(pci_resource_start(ha->pdev, 2),
+			pci_resource_len(ha->pdev, 2));
+	if (ha->msixbase) {
+		/* Read MSIX vector size of the board */
+		pci_read_config_word(ha->pdev,
+		    QLA_83XX_PCI_MSIX_CONTROL, &msix);
+		ha->msix_count = msix;
+		/* Max queues are bounded by available msix vectors */
+		/* queue 0 uses two msix vectors */
+		if (ql2xmultique_tag) {
+			cpus = num_online_cpus();
+			ha->max_rsp_queues = (ha->msix_count - 1 > cpus) ?
+				(cpus + 1) : (ha->msix_count - 1);
+			ha->max_req_queues = 2;
+		} else if (ql2xmaxqueues > 1) {
+			ha->max_req_queues = ql2xmaxqueues > QLA_MQ_SIZE ?
+						QLA_MQ_SIZE : ql2xmaxqueues;
+			ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc00c,
+			    "QoS mode set, max no of request queues:%d.\n",
+			    ha->max_req_queues);
+			ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b,
+			    "QoS mode set, max no of request queues:%d.\n",
+			    ha->max_req_queues);
+		}
+		ql_log_pci(ql_log_info, ha->pdev, 0x011c,
+		    "MSI-X vector count: %d.\n", msix);
+	} else
+		ql_log_pci(ql_log_info, ha->pdev, 0x011e,
+		    "BAR 1 not enabled.\n");
+
+mqiobase_exit:
+	ha->msix_count = ha->max_rsp_queues + 1;
+	ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011f,
+	    "MSIX Count:%d.\n", ha->msix_count);
+	return 0;
+
+iospace_error_exit:
+	return -ENOMEM;
+}
+
 static struct isp_operations qla2100_isp_ops = {
 	.pci_config		= qla2100_pci_config,
 	.reset_chip		= qla2x00_reset_chip,
@@ -1769,7 +1885,7 @@
 	.fw_dump		= qla81xx_fw_dump,
 	.beacon_on		= qla24xx_beacon_on,
 	.beacon_off		= qla24xx_beacon_off,
-	.beacon_blink		= qla24xx_beacon_blink,
+	.beacon_blink		= qla83xx_beacon_blink,
 	.read_optrom		= qla25xx_read_optrom_data,
 	.write_optrom		= qla24xx_write_optrom_data,
 	.get_flash_version	= qla24xx_get_flash_version,
@@ -1815,6 +1931,43 @@
 	.iospace_config     	= qla82xx_iospace_config,
 };
 
+static struct isp_operations qla83xx_isp_ops = {
+	.pci_config		= qla25xx_pci_config,
+	.reset_chip		= qla24xx_reset_chip,
+	.chip_diag		= qla24xx_chip_diag,
+	.config_rings		= qla24xx_config_rings,
+	.reset_adapter		= qla24xx_reset_adapter,
+	.nvram_config		= qla81xx_nvram_config,
+	.update_fw_options	= qla81xx_update_fw_options,
+	.load_risc		= qla81xx_load_risc,
+	.pci_info_str		= qla24xx_pci_info_str,
+	.fw_version_str		= qla24xx_fw_version_str,
+	.intr_handler		= qla24xx_intr_handler,
+	.enable_intrs		= qla24xx_enable_intrs,
+	.disable_intrs		= qla24xx_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		= qla83xx_fw_dump,
+	.beacon_on		= qla24xx_beacon_on,
+	.beacon_off		= qla24xx_beacon_off,
+	.beacon_blink		= qla83xx_beacon_blink,
+	.read_optrom		= qla25xx_read_optrom_data,
+	.write_optrom		= qla24xx_write_optrom_data,
+	.get_flash_version	= qla24xx_get_flash_version,
+	.start_scsi		= qla24xx_dif_start_scsi,
+	.abort_isp		= qla2x00_abort_isp,
+	.iospace_config		= qla83xx_iospace_config,
+};
+
 static inline void
 qla2x00_set_isp_flags(struct qla_hw_data *ha)
 {
@@ -1909,6 +2062,22 @@
 		/* 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;
+		ha->device_type |= DT_FWI2;
+		ha->device_type |= DT_IIDMA;
+		ha->device_type |= DT_T10_PI;
+		ha->fw_srisc_address = RISC_START_ADDRESS_2400;
+		break;
+	case PCI_DEVICE_ID_QLOGIC_ISP8031:
+		ha->device_type |= DT_ISP8031;
+		ha->device_type |= DT_ZIO_SUPPORTED;
+		ha->device_type |= DT_FWI2;
+		ha->device_type |= DT_IIDMA;
+		ha->device_type |= DT_T10_PI;
+		ha->fw_srisc_address = RISC_START_ADDRESS_2400;
+		break;
 	}
 
 	if (IS_QLA82XX(ha))
@@ -1966,7 +2135,7 @@
 	char pci_info[30];
 	char fw_str[30];
 	struct scsi_host_template *sht;
-	int bars, max_id, mem_only = 0;
+	int bars, mem_only = 0;
 	uint16_t req_length = 0, rsp_length = 0;
 	struct req_que *req = NULL;
 	struct rsp_que *rsp = NULL;
@@ -1980,7 +2149,9 @@
 	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 ||
 	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532 ||
 	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001 ||
-	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8021) {
+	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8021 ||
+	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2031 ||
+	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8031) {
 		bars = pci_select_bars(pdev, IORESOURCE_MEM);
 		mem_only = 1;
 		ql_dbg_pci(ql_dbg_init, pdev, 0x0007,
@@ -2020,9 +2191,8 @@
 	qla2x00_set_isp_flags(ha);
 
 	/* Set EEH reset type to fundamental if required by hba */
-	if ( IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha)) {
+	if (IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha))
 		pdev->needs_freset = 1;
-	}
 
 	ha->prev_topology = 0;
 	ha->init_cb_size = sizeof(init_cb_t);
@@ -2030,9 +2200,8 @@
 	ha->optrom_size = OPTROM_SIZE_2300;
 
 	/* Assign ISP specific operations. */
-	max_id = MAX_TARGETS_2200;
 	if (IS_QLA2100(ha)) {
-		max_id = MAX_TARGETS_2100;
+		ha->max_fibre_devices = MAX_FIBRE_DEVICES_2100;
 		ha->mbx_count = MAILBOX_REGISTER_COUNT_2100;
 		req_length = REQUEST_ENTRY_CNT_2100;
 		rsp_length = RESPONSE_ENTRY_CNT_2100;
@@ -2044,6 +2213,7 @@
 		ha->nvram_data_off = ~0;
 		ha->isp_ops = &qla2100_isp_ops;
 	} else if (IS_QLA2200(ha)) {
+		ha->max_fibre_devices = MAX_FIBRE_DEVICES_2100;
 		ha->mbx_count = MAILBOX_REGISTER_COUNT_2200;
 		req_length = REQUEST_ENTRY_CNT_2200;
 		rsp_length = RESPONSE_ENTRY_CNT_2100;
@@ -2055,6 +2225,7 @@
 		ha->nvram_data_off = ~0;
 		ha->isp_ops = &qla2100_isp_ops;
 	} else if (IS_QLA23XX(ha)) {
+		ha->max_fibre_devices = MAX_FIBRE_DEVICES_2100;
 		ha->mbx_count = MAILBOX_REGISTER_COUNT;
 		req_length = REQUEST_ENTRY_CNT_2200;
 		rsp_length = RESPONSE_ENTRY_CNT_2300;
@@ -2068,6 +2239,7 @@
 		ha->nvram_data_off = ~0;
 		ha->isp_ops = &qla2300_isp_ops;
 	} else if (IS_QLA24XX_TYPE(ha)) {
+		ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
 		ha->mbx_count = MAILBOX_REGISTER_COUNT;
 		req_length = REQUEST_ENTRY_CNT_24XX;
 		rsp_length = RESPONSE_ENTRY_CNT_2300;
@@ -2082,6 +2254,7 @@
 		ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF;
 		ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA;
 	} else if (IS_QLA25XX(ha)) {
+		ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
 		ha->mbx_count = MAILBOX_REGISTER_COUNT;
 		req_length = REQUEST_ENTRY_CNT_24XX;
 		rsp_length = RESPONSE_ENTRY_CNT_2300;
@@ -2096,6 +2269,7 @@
 		ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF;
 		ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA;
 	} else if (IS_QLA81XX(ha)) {
+		ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
 		ha->mbx_count = MAILBOX_REGISTER_COUNT;
 		req_length = REQUEST_ENTRY_CNT_24XX;
 		rsp_length = RESPONSE_ENTRY_CNT_2300;
@@ -2110,6 +2284,7 @@
 		ha->nvram_conf_off = ~0;
 		ha->nvram_data_off = ~0;
 	} else if (IS_QLA82XX(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;
@@ -2123,14 +2298,31 @@
 		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->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
+		ha->mbx_count = MAILBOX_REGISTER_COUNT;
+		req_length = REQUEST_ENTRY_CNT_24XX;
+		rsp_length = RESPONSE_ENTRY_CNT_2300;
+		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 = &qla83xx_isp_ops;
+		ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_81XX;
+		ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX;
+		ha->nvram_conf_off = ~0;
+		ha->nvram_data_off = ~0;
 	}
+
 	ql_dbg_pci(ql_dbg_init, pdev, 0x001e,
 	    "mbx_count=%d, req_length=%d, "
 	    "rsp_length=%d, max_loop_id=%d, init_cb_size=%d, "
-	    "gid_list_info_size=%d, optrom_size=%d, nvram_npiv_size=%d, .\n",
+	    "gid_list_info_size=%d, optrom_size=%d, nvram_npiv_size=%d, "
+	    "max_fibre_devices=%d.\n",
 	    ha->mbx_count, req_length, rsp_length, ha->max_loop_id,
 	    ha->init_cb_size, ha->gid_list_info_size, ha->optrom_size,
-	    ha->nvram_npiv_size);
+	    ha->nvram_npiv_size, ha->max_fibre_devices);
 	ql_dbg_pci(ql_dbg_init, pdev, 0x001f,
 	    "isp_ops=%p, flash_conf_off=%d, "
 	    "flash_data_off=%d, nvram_conf_off=%d, nvram_data_off=%d.\n",
@@ -2204,7 +2396,7 @@
 	    "mgmt_svr_loop_id=%d, sg_tablesize=%d.\n",
 	    host->can_queue, base_vha->req,
 	    base_vha->mgmt_svr_loop_id, host->sg_tablesize);
-	host->max_id = max_id;
+	host->max_id = ha->max_fibre_devices;
 	host->this_id = 255;
 	host->cmd_per_lun = 3;
 	host->unique_id = host->host_no;
@@ -2251,7 +2443,7 @@
 	req->req_q_out = &ha->iobase->isp24.req_q_out;
 	rsp->rsp_q_in = &ha->iobase->isp24.rsp_q_in;
 	rsp->rsp_q_out = &ha->iobase->isp24.rsp_q_out;
-	if (ha->mqenable) {
+	if (ha->mqenable || IS_QLA83XX(ha)) {
 		req->req_q_in = &ha->mqiobase->isp25mq.req_q_in;
 		req->req_q_out = &ha->mqiobase->isp25mq.req_q_out;
 		rsp->rsp_q_in = &ha->mqiobase->isp25mq.rsp_q_in;
@@ -2552,6 +2744,9 @@
 
 		if (ha->mqiobase)
 			iounmap(ha->mqiobase);
+
+		if (IS_QLA83XX(ha) && ha->msixbase)
+			iounmap(ha->msixbase);
 	}
 
 	pci_release_selected_regions(ha->pdev, ha->bars);
@@ -2751,8 +2946,8 @@
 	if (!ha->init_cb)
 		goto fail;
 
-	ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, GID_LIST_SIZE,
-		&ha->gid_list_dma, GFP_KERNEL);
+	ha->gid_list = dma_alloc_coherent(&ha->pdev->dev,
+		qla2x00_gid_list_size(ha), &ha->gid_list_dma, GFP_KERNEL);
 	if (!ha->gid_list)
 		goto fail_free_init_cb;
 
@@ -2893,7 +3088,7 @@
 		ha->npiv_info = NULL;
 
 	/* Get consistent memory allocated for EX-INIT-CB. */
-	if (IS_QLA8XXX_TYPE(ha)) {
+	if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha)) {
 		ha->ex_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
 		    &ha->ex_init_cb_dma);
 		if (!ha->ex_init_cb)
@@ -2967,7 +3162,8 @@
 	mempool_destroy(ha->srb_mempool);
 	ha->srb_mempool = NULL;
 fail_free_gid_list:
-	dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,
+	dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha),
+	ha->gid_list,
 	ha->gid_list_dma);
 	ha->gid_list = NULL;
 	ha->gid_list_dma = 0;
@@ -3045,9 +3241,6 @@
 	if (ha->sfp_data)
 		dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma);
 
-	if (ha->edc_data)
-		dma_pool_free(ha->s_dma_pool, ha->edc_data, ha->edc_data_dma);
-
 	if (ha->ms_iocb)
 		dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
 
@@ -3062,8 +3255,8 @@
 		dma_pool_destroy(ha->s_dma_pool);
 
 	if (ha->gid_list)
-		dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,
-		ha->gid_list_dma);
+		dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha),
+		ha->gid_list, ha->gid_list_dma);
 
 	if (IS_QLA82XX(ha)) {
 		if (!list_empty(&ha->gbl_dsd_list)) {
@@ -3095,6 +3288,7 @@
 	vfree(ha->optrom_buffer);
 	kfree(ha->nvram);
 	kfree(ha->npiv_info);
+	kfree(ha->swl);
 
 	ha->srb_mempool = NULL;
 	ha->ctx_mempool = NULL;
@@ -3661,75 +3855,6 @@
 	}
 }
 
-static void
-qla2x00_sp_free_dma(srb_t *sp)
-{
-	struct scsi_cmnd *cmd = sp->cmd;
-	struct qla_hw_data *ha = sp->fcport->vha->hw;
-
-	if (sp->flags & SRB_DMA_VALID) {
-		scsi_dma_unmap(cmd);
-		sp->flags &= ~SRB_DMA_VALID;
-	}
-
-	if (sp->flags & SRB_CRC_PROT_DMA_VALID) {
-		dma_unmap_sg(&ha->pdev->dev, scsi_prot_sglist(cmd),
-		    scsi_prot_sg_count(cmd), cmd->sc_data_direction);
-		sp->flags &= ~SRB_CRC_PROT_DMA_VALID;
-	}
-
-	if (sp->flags & SRB_CRC_CTX_DSD_VALID) {
-		/* List assured to be having elements */
-		qla2x00_clean_dsd_pool(ha, sp);
-		sp->flags &= ~SRB_CRC_CTX_DSD_VALID;
-	}
-
-	if (sp->flags & SRB_CRC_CTX_DMA_VALID) {
-		dma_pool_free(ha->dl_dma_pool, sp->ctx,
-		    ((struct crc_context *)sp->ctx)->crc_ctx_dma);
-		sp->flags &= ~SRB_CRC_CTX_DMA_VALID;
-	}
-
-	if (sp->flags & SRB_FCP_CMND_DMA_VALID) {
-		struct ct6_dsd *ctx = sp->ctx;
-		dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd,
-			ctx->fcp_cmnd_dma);
-		list_splice(&ctx->dsd_list, &ha->gbl_dsd_list);
-		ha->gbl_dsd_inuse -= ctx->dsd_use_cnt;
-		ha->gbl_dsd_avail += ctx->dsd_use_cnt;
-		mempool_free(sp->ctx, ha->ctx_mempool);
-		sp->ctx = NULL;
-	}
-
-	CMD_SP(cmd) = NULL;
-}
-
-static void
-qla2x00_sp_final_compl(struct qla_hw_data *ha, srb_t *sp)
-{
-	struct scsi_cmnd *cmd = sp->cmd;
-
-	qla2x00_sp_free_dma(sp);
-	mempool_free(sp, ha->srb_mempool);
-	cmd->scsi_done(cmd);
-}
-
-void
-qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp)
-{
-	if (atomic_read(&sp->ref_count) == 0) {
-		ql_dbg(ql_dbg_io, sp->fcport->vha, 0x3015,
-		    "SP reference-count to ZERO -- sp=%p cmd=%p.\n",
-		    sp, sp->cmd);
-		if (ql2xextended_error_logging & ql_dbg_io)
-			BUG();
-		return;
-	}
-	if (!atomic_dec_and_test(&sp->ref_count))
-		return;
-	qla2x00_sp_final_compl(ha, sp);
-}
-
 /**************************************************************************
 *   qla2x00_timer
 *
@@ -3800,7 +3925,7 @@
 					sp = req->outstanding_cmds[index];
 					if (!sp)
 						continue;
-					if (sp->ctx && !IS_PROT_IO(sp))
+					if (sp->type != SRB_SCSI_CMD)
 						continue;
 					sfcp = sp->fcport;
 					if (!(sfcp->flags & FCF_FCP2_DEVICE))
@@ -3889,7 +4014,7 @@
 
 /* Firmware interface routines. */
 
-#define FW_BLOBS	8
+#define FW_BLOBS	10
 #define FW_ISP21XX	0
 #define FW_ISP22XX	1
 #define FW_ISP2300	2
@@ -3898,6 +4023,8 @@
 #define FW_ISP25XX	5
 #define FW_ISP81XX	6
 #define FW_ISP82XX	7
+#define FW_ISP2031	8
+#define FW_ISP8031	9
 
 #define FW_FILE_ISP21XX	"ql2100_fw.bin"
 #define FW_FILE_ISP22XX	"ql2200_fw.bin"
@@ -3907,6 +4034,8 @@
 #define FW_FILE_ISP25XX	"ql2500_fw.bin"
 #define FW_FILE_ISP81XX	"ql8100_fw.bin"
 #define FW_FILE_ISP82XX	"ql8200_fw.bin"
+#define FW_FILE_ISP2031	"ql2600_fw.bin"
+#define FW_FILE_ISP8031	"ql8300_fw.bin"
 
 static DEFINE_MUTEX(qla_fw_lock);
 
@@ -3919,6 +4048,8 @@
 	{ .name = FW_FILE_ISP25XX, },
 	{ .name = FW_FILE_ISP81XX, },
 	{ .name = FW_FILE_ISP82XX, },
+	{ .name = FW_FILE_ISP2031, },
+	{ .name = FW_FILE_ISP8031, },
 };
 
 struct fw_blob *
@@ -3927,7 +4058,6 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct fw_blob *blob;
 
-	blob = NULL;
 	if (IS_QLA2100(ha)) {
 		blob = &qla_fw_blobs[FW_ISP21XX];
 	} else if (IS_QLA2200(ha)) {
@@ -3944,6 +4074,12 @@
 		blob = &qla_fw_blobs[FW_ISP81XX];
 	} else if (IS_QLA82XX(ha)) {
 		blob = &qla_fw_blobs[FW_ISP82XX];
+	} else if (IS_QLA2031(ha)) {
+		blob = &qla_fw_blobs[FW_ISP2031];
+	} else if (IS_QLA8031(ha)) {
+		blob = &qla_fw_blobs[FW_ISP8031];
+	} else {
+		return NULL;
 	}
 
 	mutex_lock(&qla_fw_lock);
@@ -4265,6 +4401,7 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5422) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2031) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8001) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8021) },
 	{ 0 },
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 16bc728..3c13c0a 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -568,6 +568,9 @@
 	else if (IS_QLA82XX(ha)) {
 		*start = FA_FLASH_LAYOUT_ADDR_82;
 		goto end;
+	} else if (IS_QLA83XX(ha)) {
+		*start = FA_FLASH_LAYOUT_ADDR_83;
+		goto end;
 	}
 	/* Begin with first PCI expansion ROM header. */
 	buf = (uint8_t *)req->ring;
@@ -721,13 +724,22 @@
 		    le32_to_cpu(region->size));
 
 		switch (le32_to_cpu(region->code) & 0xff) {
+		case FLT_REG_FCOE_FW:
+			if (!IS_QLA8031(ha))
+				break;
+			ha->flt_region_fw = start;
+			break;
 		case FLT_REG_FW:
+			if (IS_QLA8031(ha))
+				break;
 			ha->flt_region_fw = start;
 			break;
 		case FLT_REG_BOOT_CODE:
 			ha->flt_region_boot = start;
 			break;
 		case FLT_REG_VPD_0:
+			if (IS_QLA8031(ha))
+				break;
 			ha->flt_region_vpd_nvram = start;
 			if (IS_QLA82XX(ha))
 				break;
@@ -735,16 +747,20 @@
 				ha->flt_region_vpd = start;
 			break;
 		case FLT_REG_VPD_1:
-			if (IS_QLA82XX(ha))
+			if (IS_QLA82XX(ha) || IS_QLA8031(ha))
 				break;
 			if (!ha->flags.port0)
 				ha->flt_region_vpd = start;
 			break;
 		case FLT_REG_NVRAM_0:
+			if (IS_QLA8031(ha))
+				break;
 			if (ha->flags.port0)
 				ha->flt_region_nvram = start;
 			break;
 		case FLT_REG_NVRAM_1:
+			if (IS_QLA8031(ha))
+				break;
 			if (!ha->flags.port0)
 				ha->flt_region_nvram = start;
 			break;
@@ -785,6 +801,31 @@
 		case FLT_REG_VPD_82XX:
 			ha->flt_region_vpd = start;
 			break;
+		case FLT_REG_FCOE_VPD_0:
+			if (!IS_QLA8031(ha))
+				break;
+			ha->flt_region_vpd_nvram = start;
+			if (ha->flags.port0)
+				ha->flt_region_vpd = start;
+			break;
+		case FLT_REG_FCOE_VPD_1:
+			if (!IS_QLA8031(ha))
+				break;
+			if (!ha->flags.port0)
+				ha->flt_region_vpd = start;
+			break;
+		case FLT_REG_FCOE_NVRAM_0:
+			if (!IS_QLA8031(ha))
+				break;
+			if (ha->flags.port0)
+				ha->flt_region_nvram = start;
+			break;
+		case FLT_REG_FCOE_NVRAM_1:
+			if (!IS_QLA8031(ha))
+				break;
+			if (!ha->flags.port0)
+				ha->flt_region_nvram = start;
+			break;
 		}
 	}
 	goto done;
@@ -804,15 +845,12 @@
 	    def_npiv_conf0[def] : def_npiv_conf1[def];
 done:
 	ql_dbg(ql_dbg_init, vha, 0x004a,
-	    "FLT[%s]: boot=0x%x fw=0x%x vpd_nvram=0x%x vpd=0x%x.\n",
-	    loc, ha->flt_region_boot,
-	    ha->flt_region_fw, ha->flt_region_vpd_nvram,
-	    ha->flt_region_vpd);
-	ql_dbg(ql_dbg_init, vha, 0x004b,
-	    "nvram=0x%x fdt=0x%x flt=0x%x npiv=0x%x fcp_prif_cfg=0x%x.\n",
-	    ha->flt_region_nvram,
-	    ha->flt_region_fdt, ha->flt_region_flt,
-	    ha->flt_region_npiv_conf, ha->flt_region_fcp_prio);
+	    "FLT[%s]: boot=0x%x fw=0x%x vpd_nvram=0x%x vpd=0x%x nvram=0x%x "
+	    "fdt=0x%x flt=0x%x npiv=0x%x fcp_prif_cfg=0x%x.\n",
+	    loc, ha->flt_region_boot, ha->flt_region_fw,
+	    ha->flt_region_vpd_nvram, ha->flt_region_vpd, ha->flt_region_nvram,
+	    ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_npiv_conf,
+	    ha->flt_region_fcp_prio);
 }
 
 static void
@@ -948,7 +986,8 @@
 	uint32_t flt_addr;
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_QLA8XXX_TYPE(ha))
+	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
+	    !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha))
 		return QLA_SUCCESS;
 
 	ret = qla2xxx_find_flt_start(vha, &flt_addr);
@@ -974,7 +1013,8 @@
 	struct qla_npiv_entry *entry;
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_QLA8XXX_TYPE(ha))
+	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
+	    !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha))
 		return;
 
 	ha->isp_ops->read_optrom(vha, (uint8_t *)&hdr,
@@ -1144,8 +1184,8 @@
 	struct qla_hw_data *ha = vha->hw;
 
 	/* Prepare burst-capable write on supported ISPs. */
-	if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && !(faddr & 0xfff) &&
-	    dwords > OPTROM_BURST_DWORDS) {
+	if ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha)) &&
+	    !(faddr & 0xfff) && dwords > OPTROM_BURST_DWORDS) {
 		optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
 		    &optrom_dma, GFP_KERNEL);
 		if (!optrom) {
@@ -1619,6 +1659,71 @@
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
+void
+qla83xx_beacon_blink(struct scsi_qla_host *vha)
+{
+	uint32_t led_select_value;
+	struct qla_hw_data *ha = vha->hw;
+	uint16_t led_cfg[6];
+	uint16_t orig_led_cfg[6];
+
+	if (!IS_QLA83XX(ha) && !IS_QLA81XX(ha))
+		return;
+
+	if (IS_QLA2031(ha) && ha->beacon_blink_led) {
+		if (ha->flags.port0)
+			led_select_value = 0x00201320;
+		else
+			led_select_value = 0x00201328;
+
+		qla83xx_write_remote_reg(vha, led_select_value, 0x40002000);
+		qla83xx_write_remote_reg(vha, led_select_value + 4, 0x40002000);
+		msleep(1000);
+		qla83xx_write_remote_reg(vha, led_select_value, 0x40004000);
+		qla83xx_write_remote_reg(vha, led_select_value + 4, 0x40004000);
+	} else if ((IS_QLA8031(ha) || IS_QLA81XX(ha)) && ha->beacon_blink_led) {
+		int rval;
+
+		/* Save Current */
+		rval = qla81xx_get_led_config(vha, orig_led_cfg);
+		/* Do the blink */
+		if (rval == QLA_SUCCESS) {
+			if (IS_QLA81XX(ha)) {
+				led_cfg[0] = 0x4000;
+				led_cfg[1] = 0x2000;
+				led_cfg[2] = 0;
+				led_cfg[3] = 0;
+				led_cfg[4] = 0;
+				led_cfg[5] = 0;
+			} else {
+				led_cfg[0] = 0x4000;
+				led_cfg[1] = 0x4000;
+				led_cfg[2] = 0x4000;
+				led_cfg[3] = 0x2000;
+				led_cfg[4] = 0;
+				led_cfg[5] = 0x2000;
+			}
+			rval = qla81xx_set_led_config(vha, led_cfg);
+			msleep(1000);
+			if (IS_QLA81XX(ha)) {
+				led_cfg[0] = 0x4000;
+				led_cfg[1] = 0x2000;
+				led_cfg[2] = 0;
+			} else {
+				led_cfg[0] = 0x4000;
+				led_cfg[1] = 0x2000;
+				led_cfg[2] = 0x4000;
+				led_cfg[3] = 0x4000;
+				led_cfg[4] = 0;
+				led_cfg[5] = 0x2000;
+			}
+			rval = qla81xx_set_led_config(vha, led_cfg);
+		}
+		/* On exit, restore original (presumes no status change) */
+		qla81xx_set_led_config(vha, orig_led_cfg);
+	}
+}
+
 int
 qla24xx_beacon_on(struct scsi_qla_host *vha)
 {
@@ -1630,6 +1735,9 @@
 	if (IS_QLA82XX(ha))
 		return QLA_SUCCESS;
 
+	if (IS_QLA8031(ha) || IS_QLA81XX(ha))
+		goto skip_gpio; /* let blink handle it */
+
 	if (ha->beacon_blink_led == 0) {
 		/* Enable firmware for update */
 		ha->fw_options[1] |= ADD_FO1_DISABLE_GPIO_LED_CTRL;
@@ -1644,6 +1752,9 @@
 			return QLA_FUNCTION_FAILED;
 		}
 
+		if (IS_QLA2031(ha))
+			goto skip_gpio;
+
 		spin_lock_irqsave(&ha->hardware_lock, flags);
 		gpio_data = RD_REG_DWORD(&reg->gpiod);
 
@@ -1658,6 +1769,7 @@
 	/* So all colors blink together. */
 	ha->beacon_color_state = 0;
 
+skip_gpio:
 	/* Let the per HBA timer kick off the blinking process. */
 	ha->beacon_blink_led = 1;
 
@@ -1676,6 +1788,13 @@
 		return QLA_SUCCESS;
 
 	ha->beacon_blink_led = 0;
+
+	if (IS_QLA2031(ha))
+		goto set_fw_options;
+
+	if (IS_QLA8031(ha) || IS_QLA81XX(ha))
+		return QLA_SUCCESS;
+
 	ha->beacon_color_state = QLA_LED_ALL_ON;
 
 	ha->isp_ops->beacon_blink(vha);	/* Will flip to all off. */
@@ -1690,6 +1809,7 @@
 	RD_REG_DWORD(&reg->gpiod);
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
+set_fw_options:
 	ha->fw_options[1] &= ~ADD_FO1_DISABLE_GPIO_LED_CTRL;
 
 	if (qla2x00_set_fw_options(vha, ha->fw_options) != QLA_SUCCESS) {
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index bfe6854..7f2492e 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -150,8 +150,6 @@
 #define QL4_SESS_RECOVERY_TMO		120	/* iSCSI session */
 						/* recovery timeout */
 
-#define MSB(x) ((uint8_t)((uint16_t)(x) >> 8))
-#define LSW(x) ((uint16_t)(x))
 #define LSDW(x) ((u32)((u64)(x)))
 #define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16))
 
@@ -223,6 +221,15 @@
 	uint16_t reserved2;
 };
 
+/* Mailbox request block structure */
+struct mrb {
+	struct scsi_qla_host *ha;
+	struct mbox_cmd_iocb *mbox;
+	uint32_t mbox_cmd;
+	uint16_t iocb_cnt;		/* Number of used iocbs */
+	uint32_t pid;
+};
+
 /*
  * Asynchronous Event Queue structure
  */
@@ -265,7 +272,7 @@
 					   * retried */
 	uint32_t default_time2wait;	  /* Default Min time between
 					   * relogins (+aens) */
-
+	uint16_t chap_tbl_idx;
 };
 
 struct qla_ddb_index {
@@ -284,6 +291,7 @@
 	uint16_t options;
 #define DDB_OPT_IPV6 0x0e0e
 #define DDB_OPT_IPV4 0x0f0f
+	uint8_t isid[6];
 };
 
 /*
@@ -303,7 +311,28 @@
 #define DF_ISNS_DISCOVERED	2	/* Device was discovered via iSNS */
 #define DF_FO_MASKED		3
 
+enum qla4_work_type {
+	QLA4_EVENT_AEN,
+	QLA4_EVENT_PING_STATUS,
+};
 
+struct qla4_work_evt {
+	struct list_head list;
+	enum qla4_work_type type;
+	union {
+		struct {
+			enum iscsi_host_event_code code;
+			uint32_t data_size;
+			uint8_t data[0];
+		} aen;
+		struct {
+			uint32_t status;
+			uint32_t pid;
+			uint32_t data_size;
+			uint8_t data[0];
+		} ping;
+	} u;
+};
 
 struct ql82xx_hw_data {
 	/* Offsets for flash/nvram access (set to ~0 if not used). */
@@ -657,6 +686,7 @@
 	struct dma_pool *chap_dma_pool;
 	uint8_t *chap_list; /* CHAP table cache */
 	struct mutex  chap_sem;
+
 #define CHAP_DMA_BLOCK_SIZE    512
 	struct workqueue_struct *task_wq;
 	unsigned long ddb_idx_map[MAX_DDB_ENTRIES / BITS_PER_LONG];
@@ -674,6 +704,15 @@
 	uint16_t sec_ddb_idx;
 	int is_reset;
 	uint16_t temperature;
+
+	/* event work list */
+	struct list_head work_list;
+	spinlock_t work_lock;
+
+	/* mbox iocb */
+#define MAX_MRB		128
+	struct mrb *active_mrb_array[MAX_MRB];
+	uint32_t mrb_index;
 };
 
 struct ql4_task_data {
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index 7825c14..210cd1d 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -331,6 +331,10 @@
 /*  Mailbox command definitions */
 #define MBOX_CMD_ABOUT_FW			0x0009
 #define MBOX_CMD_PING				0x000B
+#define PING_IPV6_PROTOCOL_ENABLE		0x1
+#define PING_IPV6_LINKLOCAL_ADDR		0x4
+#define PING_IPV6_ADDR0				0x8
+#define PING_IPV6_ADDR1				0xC
 #define MBOX_CMD_ENABLE_INTRS			0x0010
 #define INTR_DISABLE				0
 #define INTR_ENABLE				1
@@ -396,6 +400,10 @@
 #define FW_ADDSTATE_DHCPv4_LEASE_EXPIRED	0x0008
 #define FW_ADDSTATE_LINK_UP			0x0010
 #define FW_ADDSTATE_ISNS_SVC_ENABLED		0x0020
+#define FW_ADDSTATE_LINK_SPEED_10MBPS		0x0100
+#define FW_ADDSTATE_LINK_SPEED_100MBPS		0x0200
+#define FW_ADDSTATE_LINK_SPEED_1GBPS		0x0400
+#define FW_ADDSTATE_LINK_SPEED_10GBPS		0x0800
 
 #define MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS	0x006B
 #define IPV6_DEFAULT_DDB_ENTRY			0x0001
@@ -918,6 +926,8 @@
 #define ET_CMND_T3		 0x19
 #define ET_PASSTHRU0		 0x3A
 #define ET_PASSTHRU_STATUS	 0x3C
+#define ET_MBOX_CMD		0x38
+#define ET_MBOX_STATUS		0x39
 
 	uint8_t entryStatus;
 	uint8_t systemDefined;
@@ -1118,6 +1128,20 @@
 	uint8_t res4[16];	/* 30-3F */
 };
 
+struct mbox_cmd_iocb {
+	struct qla4_header hdr;	/* 00-03 */
+	uint32_t handle;	/* 04-07 */
+	uint32_t in_mbox[8];	/* 08-25 */
+	uint32_t res1[6];	/* 26-3F */
+};
+
+struct mbox_status_iocb {
+	struct qla4_header hdr;	/* 00-03 */
+	uint32_t handle;	/* 04-07 */
+	uint32_t out_mbox[8];	/* 08-25 */
+	uint32_t res1[6];	/* 26-3F */
+};
+
 /*
  * ISP queue - response queue entry definition.
  */
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index d0dd4b3..9105366 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -81,6 +81,8 @@
 		      uint32_t offset, uint32_t length, uint32_t options);
 int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
 		uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts);
+int qla4xxx_get_chap_index(struct scsi_qla_host *ha, char *username,
+			   char *password, int bidi, uint16_t *chap_index);
 
 void qla4xxx_queue_iocb(struct scsi_qla_host *ha);
 void qla4xxx_complete_iocb(struct scsi_qla_host *ha);
@@ -181,6 +183,13 @@
 int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
 		       struct ddb_entry *ddb_entry, uint32_t state);
 void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset);
+int qla4xxx_post_aen_work(struct scsi_qla_host *ha, uint32_t aen_code,
+			  uint32_t data_size, uint8_t *data);
+int qla4xxx_ping_iocb(struct scsi_qla_host *ha, uint32_t options,
+		      uint32_t payload_size, uint32_t pid, uint8_t *ipaddr);
+int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha,
+			       uint32_t status, uint32_t pid,
+			       uint32_t data_size, uint8_t *data);
 
 /* BSG Functions */
 int qla4xxx_bsg_request(struct bsg_job *bsg_job);
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index 90614f3..90ee5d8 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -86,6 +86,7 @@
 int qla4xxx_init_rings(struct scsi_qla_host *ha)
 {
 	unsigned long flags = 0;
+	int i;
 
 	/* Initialize request queue. */
 	spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -125,6 +126,10 @@
 
 	qla4xxx_init_response_q_entries(ha);
 
+	/* Initialize mabilbox active array */
+	for (i = 0; i < MAX_MRB; i++)
+		ha->active_mrb_array[i] = NULL;
+
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	return QLA_SUCCESS;
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index 4106693..2a2022a 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -445,3 +445,95 @@
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 	return ret;
 }
+
+static struct mrb *qla4xxx_get_new_mrb(struct scsi_qla_host *ha)
+{
+	struct mrb *mrb;
+
+	mrb = kzalloc(sizeof(*mrb), GFP_KERNEL);
+	if (!mrb)
+		return mrb;
+
+	mrb->ha = ha;
+	return mrb;
+}
+
+static int qla4xxx_send_mbox_iocb(struct scsi_qla_host *ha, struct mrb *mrb,
+				  uint32_t *in_mbox)
+{
+	int rval = QLA_SUCCESS;
+	uint32_t i;
+	unsigned long flags;
+	uint32_t index = 0;
+
+	/* Acquire hardware specific lock */
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	/* Get pointer to the queue entry for the marker */
+	rval = qla4xxx_get_req_pkt(ha, (struct queue_entry **) &(mrb->mbox));
+	if (rval != QLA_SUCCESS)
+		goto exit_mbox_iocb;
+
+	index = ha->mrb_index;
+	/* get valid mrb index*/
+	for (i = 0; i < MAX_MRB; i++) {
+		index++;
+		if (index == MAX_MRB)
+			index = 1;
+		if (ha->active_mrb_array[index] == NULL) {
+			ha->mrb_index = index;
+			break;
+		}
+	}
+
+	mrb->iocb_cnt = 1;
+	ha->active_mrb_array[index] = mrb;
+	mrb->mbox->handle = index;
+	mrb->mbox->hdr.entryType = ET_MBOX_CMD;
+	mrb->mbox->hdr.entryCount = mrb->iocb_cnt;
+	memcpy(mrb->mbox->in_mbox, in_mbox, 32);
+	mrb->mbox_cmd = in_mbox[0];
+	wmb();
+
+	ha->isp_ops->queue_iocb(ha);
+exit_mbox_iocb:
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	return rval;
+}
+
+int qla4xxx_ping_iocb(struct scsi_qla_host *ha, uint32_t options,
+		      uint32_t payload_size, uint32_t pid, uint8_t *ipaddr)
+{
+	uint32_t in_mbox[8];
+	struct mrb *mrb = NULL;
+	int rval = QLA_SUCCESS;
+
+	memset(in_mbox, 0, sizeof(in_mbox));
+
+	mrb = qla4xxx_get_new_mrb(ha);
+	if (!mrb) {
+		DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: fail to get new mrb\n",
+				  __func__));
+		rval = QLA_ERROR;
+		goto exit_ping;
+	}
+
+	in_mbox[0] = MBOX_CMD_PING;
+	in_mbox[1] = options;
+	memcpy(&in_mbox[2], &ipaddr[0], 4);
+	memcpy(&in_mbox[3], &ipaddr[4], 4);
+	memcpy(&in_mbox[4], &ipaddr[8], 4);
+	memcpy(&in_mbox[5], &ipaddr[12], 4);
+	in_mbox[6] = payload_size;
+
+	mrb->pid = pid;
+	rval = qla4xxx_send_mbox_iocb(ha, mrb, in_mbox);
+
+	if (rval != QLA_SUCCESS)
+		goto exit_ping;
+
+	return rval;
+exit_ping:
+	kfree(mrb);
+	return rval;
+}
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 9582886..fc542a9 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -385,6 +385,71 @@
 	queue_work(ha->task_wq, &task_data->task_work);
 }
 
+static struct mrb *qla4xxx_del_mrb_from_active_array(struct scsi_qla_host *ha,
+						     uint32_t index)
+{
+	struct mrb *mrb = NULL;
+
+	/* validate handle and remove from active array */
+	if (index >= MAX_MRB)
+		return mrb;
+
+	mrb = ha->active_mrb_array[index];
+	ha->active_mrb_array[index] = NULL;
+	if (!mrb)
+		return mrb;
+
+	/* update counters */
+	ha->req_q_count += mrb->iocb_cnt;
+	ha->iocb_cnt -= mrb->iocb_cnt;
+
+	return mrb;
+}
+
+static void qla4xxx_mbox_status_entry(struct scsi_qla_host *ha,
+				      struct mbox_status_iocb *mbox_sts_entry)
+{
+	struct mrb *mrb;
+	uint32_t status;
+	uint32_t data_size;
+
+	mrb = qla4xxx_del_mrb_from_active_array(ha,
+					le32_to_cpu(mbox_sts_entry->handle));
+
+	if (mrb == NULL) {
+		ql4_printk(KERN_WARNING, ha, "%s: mrb[%d] is null\n", __func__,
+			   mbox_sts_entry->handle);
+		return;
+	}
+
+	switch (mrb->mbox_cmd) {
+	case MBOX_CMD_PING:
+		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: mbox_cmd = 0x%x, "
+				  "mbox_sts[0] = 0x%x, mbox_sts[6] = 0x%x\n",
+				  __func__, mrb->mbox_cmd,
+				  mbox_sts_entry->out_mbox[0],
+				  mbox_sts_entry->out_mbox[6]));
+
+		if (mbox_sts_entry->out_mbox[0] == MBOX_STS_COMMAND_COMPLETE)
+			status = ISCSI_PING_SUCCESS;
+		else
+			status = mbox_sts_entry->out_mbox[6];
+
+		data_size = sizeof(mbox_sts_entry->out_mbox);
+
+		qla4xxx_post_ping_evt_work(ha, status, mrb->pid, data_size,
+					(uint8_t *) mbox_sts_entry->out_mbox);
+		break;
+
+	default:
+		DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: invalid mbox_cmd = "
+				  "0x%x\n", __func__, mrb->mbox_cmd));
+	}
+
+	kfree(mrb);
+	return;
+}
+
 /**
  * qla4xxx_process_response_queue - process response queue completions
  * @ha: Pointer to host adapter structure.
@@ -461,6 +526,13 @@
 				      "ignoring\n", ha->host_no, __func__));
 			break;
 
+		case ET_MBOX_STATUS:
+			DEBUG2(ql4_printk(KERN_INFO, ha,
+					  "%s: mbox status IOCB\n", __func__));
+			qla4xxx_mbox_status_entry(ha,
+					(struct mbox_status_iocb *)sts_entry);
+			break;
+
 		default:
 			/*
 			 * Invalid entry in response queue, reset RISC
@@ -576,6 +648,9 @@
 				set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);
 
 			ql4_printk(KERN_INFO, ha, "%s: LINK UP\n", __func__);
+			qla4xxx_post_aen_work(ha, ISCSI_EVENT_LINKUP,
+					      sizeof(mbox_sts),
+					      (uint8_t *) mbox_sts);
 			break;
 
 		case MBOX_ASTS_LINK_DOWN:
@@ -584,6 +659,9 @@
 				set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);
 
 			ql4_printk(KERN_INFO, ha, "%s: LINK DOWN\n", __func__);
+			qla4xxx_post_aen_work(ha, ISCSI_EVENT_LINKDOWN,
+					      sizeof(mbox_sts),
+					      (uint8_t *) mbox_sts);
 			break;
 
 		case MBOX_ASTS_HEARTBEAT:
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index e1e66a4..7ac21da 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -622,7 +622,7 @@
 		return QLA_ERROR;
 	}
 
-	ql4_printk(KERN_INFO, ha, "%ld firmare IOCBs available (%d).\n",
+	ql4_printk(KERN_INFO, ha, "%ld firmware IOCBs available (%d).\n",
 	    ha->host_no, mbox_sts[2]);
 
 	return QLA_SUCCESS;
@@ -661,6 +661,8 @@
 	}
 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
 	memset(&mbox_sts, 0, sizeof(mbox_sts));
+	if (fw_ddb_entry)
+		memset(fw_ddb_entry, 0, sizeof(struct dev_db_entry));
 
 	mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY;
 	mbox_cmd[1] = (uint32_t) fw_ddb_index;
@@ -1424,8 +1426,8 @@
  * match is found. If a match is not found then add the entry in FLASH and
  * return the index at which entry is written in the FLASH.
  **/
-static int qla4xxx_get_chap_index(struct scsi_qla_host *ha, char *username,
-			    char *password, int bidi, uint16_t *chap_index)
+int qla4xxx_get_chap_index(struct scsi_qla_host *ha, char *username,
+			   char *password, int bidi, uint16_t *chap_index)
 {
 	int i, rval;
 	int free_index = -1;
@@ -1444,6 +1446,11 @@
 		return QLA_ERROR;
 	}
 
+	if (!username || !password) {
+		ql4_printk(KERN_ERR, ha, "Do not have username and psw\n");
+		return QLA_ERROR;
+	}
+
 	mutex_lock(&ha->chap_sem);
 	for (i = 0; i < max_chap_entries; i++) {
 		chap_table = (struct ql4_chap_table *)ha->chap_list + i;
@@ -1600,7 +1607,7 @@
 	char *ip;
 	uint16_t iscsi_opts = 0;
 	uint32_t options = 0;
-	uint16_t idx;
+	uint16_t idx, *ptid;
 
 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
 					  &fw_ddb_entry_dma, GFP_KERNEL);
@@ -1626,6 +1633,14 @@
 		goto exit_set_param;
 	}
 
+	ptid = (uint16_t *)&fw_ddb_entry->isid[1];
+	*ptid = cpu_to_le16((uint16_t)ddb_entry->sess->target_id);
+
+	DEBUG2(ql4_printk(KERN_INFO, ha, "ISID [%02x%02x%02x%02x%02x%02x]\n",
+			  fw_ddb_entry->isid[5], fw_ddb_entry->isid[4],
+			  fw_ddb_entry->isid[3], fw_ddb_entry->isid[2],
+			  fw_ddb_entry->isid[1], fw_ddb_entry->isid[0]));
+
 	iscsi_opts = le16_to_cpu(fw_ddb_entry->iscsi_options);
 	memset(fw_ddb_entry->iscsi_alias, 0, sizeof(fw_ddb_entry->iscsi_alias));
 
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c
index 65253df..e1e46b6 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.c
+++ b/drivers/scsi/qla4xxx/ql4_nx.c
@@ -841,11 +841,8 @@
 		done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK));
 		if (done == 1)
 			break;
-		if (timeout >= qla4_8xxx_rom_lock_timeout) {
-			ql4_printk(KERN_WARNING, ha,
-			    "%s: Failed to acquire rom lock", __func__);
+		if (timeout >= qla4_8xxx_rom_lock_timeout)
 			return -1;
-		}
 
 		timeout++;
 
@@ -996,18 +993,6 @@
 	else
 		qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff);
 
-	/* reset ms */
-	val = qla4_8xxx_rd_32(ha, QLA82XX_CRB_QDR_NET + 0xe4);
-	val |= (1 << 1);
-	qla4_8xxx_wr_32(ha, QLA82XX_CRB_QDR_NET + 0xe4, val);
-
-	msleep(20);
-	/* unreset ms */
-	val = qla4_8xxx_rd_32(ha, QLA82XX_CRB_QDR_NET + 0xe4);
-	val &= ~(1 << 1);
-	qla4_8xxx_wr_32(ha, QLA82XX_CRB_QDR_NET + 0xe4, val);
-	msleep(20);
-
 	qla4_8xxx_rom_unlock(ha);
 
 	/* Read the signature value from the flash.
diff --git a/drivers/scsi/qla4xxx/ql4_nx.h b/drivers/scsi/qla4xxx/ql4_nx.h
index dc45ac9..dc7500e 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.h
+++ b/drivers/scsi/qla4xxx/ql4_nx.h
@@ -623,6 +623,7 @@
 
 #define ADDR_ERROR	((unsigned long) 0xffffffff)
 #define MAX_CTL_CHECK	1000
+#define QLA82XX_FWERROR_CODE(code)	((code >> 8) & 0x1fffff)
 
 /***************************************************************************
  *		PCI related defines.
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index edf5034..ee47820 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -32,14 +32,14 @@
 /*
  * Module parameter information and variables
  */
-int ql4xdisablesysfsboot = 1;
+static int ql4xdisablesysfsboot = 1;
 module_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ql4xdisablesysfsboot,
 		 " Set to disable exporting boot targets to sysfs.\n"
 		 "\t\t  0 - Export boot targets\n"
 		 "\t\t  1 - Do not export boot targets (Default)");
 
-int ql4xdontresethba = 0;
+int ql4xdontresethba;
 module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ql4xdontresethba,
 		 " Don't reset the HBA for driver recovery.\n"
@@ -71,7 +71,7 @@
 static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO;
 module_param(ql4xsess_recovery_tmo, int, S_IRUGO);
 MODULE_PARM_DESC(ql4xsess_recovery_tmo,
-		"Target Session Recovery Timeout.\n"
+		" Target Session Recovery Timeout.\n"
 		"\t\t  Default: 120 sec.");
 
 static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha);
@@ -83,6 +83,8 @@
 /*
  * iSCSI template entry points
  */
+static int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess,
+				     enum iscsi_param param, char *buf);
 static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
 				  enum iscsi_param param, char *buf);
 static int qla4xxx_host_get_param(struct Scsi_Host *shost,
@@ -118,6 +120,13 @@
 static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session);
 static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn,
 				   struct iscsi_stats *stats);
+static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
+			     uint32_t iface_type, uint32_t payload_size,
+			     uint32_t pid, struct sockaddr *dst_addr);
+static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
+				 uint32_t *num_entries, char *buf);
+static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx);
+
 /*
  * SCSI host template entry points
  */
@@ -179,7 +188,7 @@
 	.destroy_conn           = qla4xxx_conn_destroy,
 	.set_param              = iscsi_set_param,
 	.get_conn_param		= qla4xxx_conn_get_param,
-	.get_session_param	= iscsi_session_get_param,
+	.get_session_param	= qla4xxx_session_get_param,
 	.get_ep_param           = qla4xxx_get_ep_param,
 	.ep_connect		= qla4xxx_ep_connect,
 	.ep_poll		= qla4xxx_ep_poll,
@@ -194,10 +203,93 @@
 	.set_iface_param	= qla4xxx_iface_set_param,
 	.get_iface_param	= qla4xxx_get_iface_param,
 	.bsg_request		= qla4xxx_bsg_request,
+	.send_ping		= qla4xxx_send_ping,
+	.get_chap		= qla4xxx_get_chap_list,
+	.delete_chap		= qla4xxx_delete_chap,
 };
 
 static struct scsi_transport_template *qla4xxx_scsi_transport;
 
+static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
+			     uint32_t iface_type, uint32_t payload_size,
+			     uint32_t pid, struct sockaddr *dst_addr)
+{
+	struct scsi_qla_host *ha = to_qla_host(shost);
+	struct sockaddr_in *addr;
+	struct sockaddr_in6 *addr6;
+	uint32_t options = 0;
+	uint8_t ipaddr[IPv6_ADDR_LEN];
+	int rval;
+
+	memset(ipaddr, 0, IPv6_ADDR_LEN);
+	/* IPv4 to IPv4 */
+	if ((iface_type == ISCSI_IFACE_TYPE_IPV4) &&
+	    (dst_addr->sa_family == AF_INET)) {
+		addr = (struct sockaddr_in *)dst_addr;
+		memcpy(ipaddr, &addr->sin_addr.s_addr, IP_ADDR_LEN);
+		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv4 Ping src: %pI4 "
+				  "dest: %pI4\n", __func__,
+				  &ha->ip_config.ip_address, ipaddr));
+		rval = qla4xxx_ping_iocb(ha, options, payload_size, pid,
+					 ipaddr);
+		if (rval)
+			rval = -EINVAL;
+	} else if ((iface_type == ISCSI_IFACE_TYPE_IPV6) &&
+		   (dst_addr->sa_family == AF_INET6)) {
+		/* IPv6 to IPv6 */
+		addr6 = (struct sockaddr_in6 *)dst_addr;
+		memcpy(ipaddr, &addr6->sin6_addr.in6_u.u6_addr8, IPv6_ADDR_LEN);
+
+		options |= PING_IPV6_PROTOCOL_ENABLE;
+
+		/* Ping using LinkLocal address */
+		if ((iface_num == 0) || (iface_num == 1)) {
+			DEBUG2(ql4_printk(KERN_INFO, ha, "%s: LinkLocal Ping "
+					  "src: %pI6 dest: %pI6\n", __func__,
+					  &ha->ip_config.ipv6_link_local_addr,
+					  ipaddr));
+			options |= PING_IPV6_LINKLOCAL_ADDR;
+			rval = qla4xxx_ping_iocb(ha, options, payload_size,
+						 pid, ipaddr);
+		} else {
+			ql4_printk(KERN_WARNING, ha, "%s: iface num = %d "
+				   "not supported\n", __func__, iface_num);
+			rval = -ENOSYS;
+			goto exit_send_ping;
+		}
+
+		/*
+		 * If ping using LinkLocal address fails, try ping using
+		 * IPv6 address
+		 */
+		if (rval != QLA_SUCCESS) {
+			options &= ~PING_IPV6_LINKLOCAL_ADDR;
+			if (iface_num == 0) {
+				options |= PING_IPV6_ADDR0;
+				DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 "
+						  "Ping src: %pI6 "
+						  "dest: %pI6\n", __func__,
+						  &ha->ip_config.ipv6_addr0,
+						  ipaddr));
+			} else if (iface_num == 1) {
+				options |= PING_IPV6_ADDR1;
+				DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 "
+						  "Ping src: %pI6 "
+						  "dest: %pI6\n", __func__,
+						  &ha->ip_config.ipv6_addr1,
+						  ipaddr));
+			}
+			rval = qla4xxx_ping_iocb(ha, options, payload_size,
+						 pid, ipaddr);
+			if (rval)
+				rval = -EINVAL;
+		}
+	} else
+		rval = -ENOSYS;
+exit_send_ping:
+	return rval;
+}
+
 static umode_t ql4_attr_is_visible(int param_type, int param)
 {
 	switch (param_type) {
@@ -206,6 +298,8 @@
 		case ISCSI_HOST_PARAM_HWADDRESS:
 		case ISCSI_HOST_PARAM_IPADDRESS:
 		case ISCSI_HOST_PARAM_INITIATOR_NAME:
+		case ISCSI_HOST_PARAM_PORT_STATE:
+		case ISCSI_HOST_PARAM_PORT_SPEED:
 			return S_IRUGO;
 		default:
 			return 0;
@@ -225,6 +319,12 @@
 		case ISCSI_PARAM_MAX_RECV_DLENGTH:
 		case ISCSI_PARAM_MAX_XMIT_DLENGTH:
 		case ISCSI_PARAM_IFACE_NAME:
+		case ISCSI_PARAM_CHAP_OUT_IDX:
+		case ISCSI_PARAM_CHAP_IN_IDX:
+		case ISCSI_PARAM_USERNAME:
+		case ISCSI_PARAM_PASSWORD:
+		case ISCSI_PARAM_USERNAME_IN:
+		case ISCSI_PARAM_PASSWORD_IN:
 			return S_IRUGO;
 		default:
 			return 0;
@@ -255,6 +355,189 @@
 	return 0;
 }
 
+static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
+				  uint32_t *num_entries, char *buf)
+{
+	struct scsi_qla_host *ha = to_qla_host(shost);
+	struct ql4_chap_table *chap_table;
+	struct iscsi_chap_rec *chap_rec;
+	int max_chap_entries = 0;
+	int valid_chap_entries = 0;
+	int ret = 0, i;
+
+	if (is_qla8022(ha))
+		max_chap_entries = (ha->hw.flt_chap_size / 2) /
+					sizeof(struct ql4_chap_table);
+	else
+		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
+
+	ql4_printk(KERN_INFO, ha, "%s: num_entries = %d, CHAP idx = %d\n",
+			__func__, *num_entries, chap_tbl_idx);
+
+	if (!buf) {
+		ret = -ENOMEM;
+		goto exit_get_chap_list;
+	}
+
+	chap_rec = (struct iscsi_chap_rec *) buf;
+	mutex_lock(&ha->chap_sem);
+	for (i = chap_tbl_idx; i < max_chap_entries; i++) {
+		chap_table = (struct ql4_chap_table *)ha->chap_list + i;
+		if (chap_table->cookie !=
+		    __constant_cpu_to_le16(CHAP_VALID_COOKIE))
+			continue;
+
+		chap_rec->chap_tbl_idx = i;
+		strncpy(chap_rec->username, chap_table->name,
+			ISCSI_CHAP_AUTH_NAME_MAX_LEN);
+		strncpy(chap_rec->password, chap_table->secret,
+			QL4_CHAP_MAX_SECRET_LEN);
+		chap_rec->password_length = chap_table->secret_len;
+
+		if (chap_table->flags & BIT_7) /* local */
+			chap_rec->chap_type = CHAP_TYPE_OUT;
+
+		if (chap_table->flags & BIT_6) /* peer */
+			chap_rec->chap_type = CHAP_TYPE_IN;
+
+		chap_rec++;
+
+		valid_chap_entries++;
+		if (valid_chap_entries == *num_entries)
+			break;
+		else
+			continue;
+	}
+	mutex_unlock(&ha->chap_sem);
+
+exit_get_chap_list:
+	ql4_printk(KERN_INFO, ha, "%s: Valid CHAP Entries = %d\n",
+			__func__,  valid_chap_entries);
+	*num_entries = valid_chap_entries;
+	return ret;
+}
+
+static int __qla4xxx_is_chap_active(struct device *dev, void *data)
+{
+	int ret = 0;
+	uint16_t *chap_tbl_idx = (uint16_t *) data;
+	struct iscsi_cls_session *cls_session;
+	struct iscsi_session *sess;
+	struct ddb_entry *ddb_entry;
+
+	if (!iscsi_is_session_dev(dev))
+		goto exit_is_chap_active;
+
+	cls_session = iscsi_dev_to_session(dev);
+	sess = cls_session->dd_data;
+	ddb_entry = sess->dd_data;
+
+	if (iscsi_session_chkready(cls_session))
+		goto exit_is_chap_active;
+
+	if (ddb_entry->chap_tbl_idx == *chap_tbl_idx)
+		ret = 1;
+
+exit_is_chap_active:
+	return ret;
+}
+
+static int qla4xxx_is_chap_active(struct Scsi_Host *shost,
+				  uint16_t chap_tbl_idx)
+{
+	int ret = 0;
+
+	ret = device_for_each_child(&shost->shost_gendev, &chap_tbl_idx,
+				    __qla4xxx_is_chap_active);
+
+	return ret;
+}
+
+static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx)
+{
+	struct scsi_qla_host *ha = to_qla_host(shost);
+	struct ql4_chap_table *chap_table;
+	dma_addr_t chap_dma;
+	int max_chap_entries = 0;
+	uint32_t offset = 0;
+	uint32_t chap_size;
+	int ret = 0;
+
+	chap_table = dma_pool_alloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma);
+	if (chap_table == NULL)
+		return -ENOMEM;
+
+	memset(chap_table, 0, sizeof(struct ql4_chap_table));
+
+	if (is_qla8022(ha))
+		max_chap_entries = (ha->hw.flt_chap_size / 2) /
+				   sizeof(struct ql4_chap_table);
+	else
+		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
+
+	if (chap_tbl_idx > max_chap_entries) {
+		ret = -EINVAL;
+		goto exit_delete_chap;
+	}
+
+	/* Check if chap index is in use.
+	 * If chap is in use don't delet chap entry */
+	ret = qla4xxx_is_chap_active(shost, chap_tbl_idx);
+	if (ret) {
+		ql4_printk(KERN_INFO, ha, "CHAP entry %d is in use, cannot "
+			   "delete from flash\n", chap_tbl_idx);
+		ret = -EBUSY;
+		goto exit_delete_chap;
+	}
+
+	chap_size = sizeof(struct ql4_chap_table);
+	if (is_qla40XX(ha))
+		offset = FLASH_CHAP_OFFSET | (chap_tbl_idx * chap_size);
+	else {
+		offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2);
+		/* flt_chap_size is CHAP table size for both ports
+		 * so divide it by 2 to calculate the offset for second port
+		 */
+		if (ha->port_num == 1)
+			offset += (ha->hw.flt_chap_size / 2);
+		offset += (chap_tbl_idx * chap_size);
+	}
+
+	ret = qla4xxx_get_flash(ha, chap_dma, offset, chap_size);
+	if (ret != QLA_SUCCESS) {
+		ret = -EINVAL;
+		goto exit_delete_chap;
+	}
+
+	DEBUG2(ql4_printk(KERN_INFO, ha, "Chap Cookie: x%x\n",
+			  __le16_to_cpu(chap_table->cookie)));
+
+	if (__le16_to_cpu(chap_table->cookie) != CHAP_VALID_COOKIE) {
+		ql4_printk(KERN_ERR, ha, "No valid chap entry found\n");
+		goto exit_delete_chap;
+	}
+
+	chap_table->cookie = __constant_cpu_to_le16(0xFFFF);
+
+	offset = FLASH_CHAP_OFFSET |
+			(chap_tbl_idx * sizeof(struct ql4_chap_table));
+	ret = qla4xxx_set_flash(ha, chap_dma, offset, chap_size,
+				FLASH_OPT_RMW_COMMIT);
+	if (ret == QLA_SUCCESS && ha->chap_list) {
+		mutex_lock(&ha->chap_sem);
+		/* Update ha chap_list cache */
+		memcpy((struct ql4_chap_table *)ha->chap_list + chap_tbl_idx,
+			chap_table, sizeof(struct ql4_chap_table));
+		mutex_unlock(&ha->chap_sem);
+	}
+	if (ret != QLA_SUCCESS)
+		ret =  -EINVAL;
+
+exit_delete_chap:
+	dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma);
+	return ret;
+}
+
 static int qla4xxx_get_iface_param(struct iscsi_iface *iface,
 				   enum iscsi_param_type param_type,
 				   int param, char *buf)
@@ -548,6 +831,43 @@
 	return ret;
 }
 
+static void qla4xxx_set_port_speed(struct Scsi_Host *shost)
+{
+	struct scsi_qla_host *ha = to_qla_host(shost);
+	struct iscsi_cls_host *ihost = shost->shost_data;
+	uint32_t speed = ISCSI_PORT_SPEED_UNKNOWN;
+
+	qla4xxx_get_firmware_state(ha);
+
+	switch (ha->addl_fw_state & 0x0F00) {
+	case FW_ADDSTATE_LINK_SPEED_10MBPS:
+		speed = ISCSI_PORT_SPEED_10MBPS;
+		break;
+	case FW_ADDSTATE_LINK_SPEED_100MBPS:
+		speed = ISCSI_PORT_SPEED_100MBPS;
+		break;
+	case FW_ADDSTATE_LINK_SPEED_1GBPS:
+		speed = ISCSI_PORT_SPEED_1GBPS;
+		break;
+	case FW_ADDSTATE_LINK_SPEED_10GBPS:
+		speed = ISCSI_PORT_SPEED_10GBPS;
+		break;
+	}
+	ihost->port_speed = speed;
+}
+
+static void qla4xxx_set_port_state(struct Scsi_Host *shost)
+{
+	struct scsi_qla_host *ha = to_qla_host(shost);
+	struct iscsi_cls_host *ihost = shost->shost_data;
+	uint32_t state = ISCSI_PORT_STATE_DOWN;
+
+	if (test_bit(AF_LINK_UP, &ha->flags))
+		state = ISCSI_PORT_STATE_UP;
+
+	ihost->port_state = state;
+}
+
 static int qla4xxx_host_get_param(struct Scsi_Host *shost,
 				  enum iscsi_host_param param, char *buf)
 {
@@ -564,6 +884,14 @@
 	case ISCSI_HOST_PARAM_INITIATOR_NAME:
 		len = sprintf(buf, "%s\n", ha->name_string);
 		break;
+	case ISCSI_HOST_PARAM_PORT_STATE:
+		qla4xxx_set_port_state(shost);
+		len = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost));
+		break;
+	case ISCSI_HOST_PARAM_PORT_SPEED:
+		qla4xxx_set_port_speed(shost);
+		len = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost));
+		break;
 	default:
 		return -ENOSYS;
 	}
@@ -968,6 +1296,41 @@
 	return rval;
 }
 
+static int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess,
+				     enum iscsi_param param, char *buf)
+{
+	struct iscsi_session *sess = cls_sess->dd_data;
+	struct ddb_entry *ddb_entry = sess->dd_data;
+	struct scsi_qla_host *ha = ddb_entry->ha;
+	int rval, len;
+	uint16_t idx;
+
+	switch (param) {
+	case ISCSI_PARAM_CHAP_IN_IDX:
+		rval = qla4xxx_get_chap_index(ha, sess->username_in,
+					      sess->password_in, BIDI_CHAP,
+					      &idx);
+		if (rval)
+			return -EINVAL;
+
+		len = sprintf(buf, "%hu\n", idx);
+		break;
+	case ISCSI_PARAM_CHAP_OUT_IDX:
+		rval = qla4xxx_get_chap_index(ha, sess->username,
+					      sess->password, LOCAL_CHAP,
+					      &idx);
+		if (rval)
+			return -EINVAL;
+
+		len = sprintf(buf, "%hu\n", idx);
+		break;
+	default:
+		return iscsi_session_get_param(cls_sess, param, buf);
+	}
+
+	return len;
+}
+
 static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn,
 				  enum iscsi_param param, char *buf)
 {
@@ -1506,13 +1869,17 @@
 {
 	int buflen = 0;
 	struct iscsi_session *sess;
+	struct ddb_entry *ddb_entry;
 	struct iscsi_conn *conn;
 	char ip_addr[DDB_IPADDR_LEN];
 	uint16_t options = 0;
 
 	sess = cls_sess->dd_data;
+	ddb_entry = sess->dd_data;
 	conn = cls_conn->dd_data;
 
+	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);
 
@@ -1552,6 +1919,8 @@
 			(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,
@@ -1638,6 +2007,7 @@
 				le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
 
 	/* 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);
 
@@ -1666,6 +2036,9 @@
 	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),
@@ -2113,7 +2486,7 @@
 				halt_status = qla4_8xxx_rd_32(ha,
 						QLA82XX_PEG_HALT_STATUS1);
 
-				if (LSW(MSB(halt_status)) == 0x67)
+				if (QLA82XX_FWERROR_CODE(halt_status) == 0x67)
 					ql4_printk(KERN_ERR, ha, "%s:"
 						   " Firmware aborted with"
 						   " error code 0x00006700."
@@ -2230,6 +2603,10 @@
 		}
 	}
 
+	/* Process any deferred work. */
+	if (!list_empty(&ha->work_list))
+		start_dpc++;
+
 	/* Wakeup the dpc routine for this adapter, if needed. */
 	if (start_dpc ||
 	     test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
@@ -2795,6 +3172,109 @@
 		queue_work(ha->dpc_thread, &ha->dpc_work);
 }
 
+static struct qla4_work_evt *
+qla4xxx_alloc_work(struct scsi_qla_host *ha, uint32_t data_size,
+		   enum qla4_work_type type)
+{
+	struct qla4_work_evt *e;
+	uint32_t size = sizeof(struct qla4_work_evt) + data_size;
+
+	e = kzalloc(size, GFP_ATOMIC);
+	if (!e)
+		return NULL;
+
+	INIT_LIST_HEAD(&e->list);
+	e->type = type;
+	return e;
+}
+
+static void qla4xxx_post_work(struct scsi_qla_host *ha,
+			     struct qla4_work_evt *e)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ha->work_lock, flags);
+	list_add_tail(&e->list, &ha->work_list);
+	spin_unlock_irqrestore(&ha->work_lock, flags);
+	qla4xxx_wake_dpc(ha);
+}
+
+int qla4xxx_post_aen_work(struct scsi_qla_host *ha,
+			  enum iscsi_host_event_code aen_code,
+			  uint32_t data_size, uint8_t *data)
+{
+	struct qla4_work_evt *e;
+
+	e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_AEN);
+	if (!e)
+		return QLA_ERROR;
+
+	e->u.aen.code = aen_code;
+	e->u.aen.data_size = data_size;
+	memcpy(e->u.aen.data, data, data_size);
+
+	qla4xxx_post_work(ha, e);
+
+	return QLA_SUCCESS;
+}
+
+int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha,
+			       uint32_t status, uint32_t pid,
+			       uint32_t data_size, uint8_t *data)
+{
+	struct qla4_work_evt *e;
+
+	e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_PING_STATUS);
+	if (!e)
+		return QLA_ERROR;
+
+	e->u.ping.status = status;
+	e->u.ping.pid = pid;
+	e->u.ping.data_size = data_size;
+	memcpy(e->u.ping.data, data, data_size);
+
+	qla4xxx_post_work(ha, e);
+
+	return QLA_SUCCESS;
+}
+
+static void qla4xxx_do_work(struct scsi_qla_host *ha)
+{
+	struct qla4_work_evt *e, *tmp;
+	unsigned long flags;
+	LIST_HEAD(work);
+
+	spin_lock_irqsave(&ha->work_lock, flags);
+	list_splice_init(&ha->work_list, &work);
+	spin_unlock_irqrestore(&ha->work_lock, flags);
+
+	list_for_each_entry_safe(e, tmp, &work, list) {
+		list_del_init(&e->list);
+
+		switch (e->type) {
+		case QLA4_EVENT_AEN:
+			iscsi_post_host_event(ha->host_no,
+					      &qla4xxx_iscsi_transport,
+					      e->u.aen.code,
+					      e->u.aen.data_size,
+					      e->u.aen.data);
+			break;
+		case QLA4_EVENT_PING_STATUS:
+			iscsi_ping_comp_event(ha->host_no,
+					      &qla4xxx_iscsi_transport,
+					      e->u.ping.status,
+					      e->u.ping.pid,
+					      e->u.ping.data_size,
+					      e->u.ping.data);
+			break;
+		default:
+			ql4_printk(KERN_WARNING, ha, "event type: 0x%x not "
+				   "supported", e->type);
+		}
+		kfree(e);
+	}
+}
+
 /**
  * qla4xxx_do_dpc - dpc routine
  * @data: in our case pointer to adapter structure
@@ -2826,6 +3306,9 @@
 		return;
 	}
 
+	/* post events to application */
+	qla4xxx_do_work(ha);
+
 	if (is_qla8022(ha)) {
 		if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) {
 			qla4_8xxx_idc_lock(ha);
@@ -2962,7 +3445,6 @@
 int qla4_8xxx_iospace_config(struct scsi_qla_host *ha)
 {
 	int status = 0;
-	uint8_t revision_id;
 	unsigned long mem_base, mem_len, db_base, db_len;
 	struct pci_dev *pdev = ha->pdev;
 
@@ -2974,10 +3456,9 @@
 		goto iospace_error_exit;
 	}
 
-	pci_read_config_byte(pdev, PCI_REVISION_ID, &revision_id);
 	DEBUG2(printk(KERN_INFO "%s: revision-id=%d\n",
-	    __func__, revision_id));
-	ha->revision_id = revision_id;
+	    __func__, pdev->revision));
+	ha->revision_id = pdev->revision;
 
 	/* remap phys address */
 	mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
@@ -3341,9 +3822,8 @@
 		/* Check Boot Mode */
 		val = rd_nvram_byte(ha, addr);
 		if (!(val & 0x07)) {
-			DEBUG2(ql4_printk(KERN_ERR, ha,
-					  "%s: Failed Boot options : 0x%x\n",
-					  __func__, val));
+			DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Adapter boot "
+					  "options : 0x%x\n", __func__, val));
 			ret = QLA_ERROR;
 			goto exit_boot_info;
 		}
@@ -3388,9 +3868,8 @@
 		}
 		/* Check Boot Mode */
 		if (!(buf[1] & 0x07)) {
-			DEBUG2(ql4_printk(KERN_INFO, ha,
-					  "Failed: Boot options : 0x%x\n",
-					  buf[1]));
+			DEBUG2(ql4_printk(KERN_INFO, ha, "Firmware boot options"
+					  " : 0x%x\n", buf[1]));
 			ret = QLA_ERROR;
 			goto exit_boot_info_free;
 		}
@@ -3411,12 +3890,11 @@
 			  " target ID %d\n", __func__, ddb_index[0],
 			  ddb_index[1]));
 
-	ha->pri_ddb_idx = ddb_index[0];
-	ha->sec_ddb_idx = ddb_index[1];
-
 exit_boot_info_free:
 	dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma);
 exit_boot_info:
+	ha->pri_ddb_idx = ddb_index[0];
+	ha->sec_ddb_idx = ddb_index[1];
 	return ret;
 }
 
@@ -3497,8 +3975,8 @@
 
 	if (qla4xxx_bootdb_by_index(ha, fw_ddb_entry,
 				   fw_ddb_entry_dma, ddb_index)) {
-		DEBUG2(ql4_printk(KERN_ERR, ha,
-				  "%s: Flash DDB read Failed\n", __func__));
+		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: No Flash DDB found at "
+				  "index [%d]\n", __func__, ddb_index));
 		ret = QLA_ERROR;
 		goto exit_boot_target;
 	}
@@ -3576,8 +4054,8 @@
 	ddb_index[1] = 0xffff;
 	ret = get_fw_boot_info(ha, ddb_index);
 	if (ret != QLA_SUCCESS) {
-		DEBUG2(ql4_printk(KERN_ERR, ha,
-				  "%s: Failed to set boot info.\n", __func__));
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+				"%s: No boot target configured.\n", __func__));
 		return ret;
 	}
 
@@ -3590,8 +4068,8 @@
 	rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_pri_sess),
 				      ddb_index[0]);
 	if (rval != QLA_SUCCESS) {
-		DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Failed to get "
-				  "primary target\n", __func__));
+		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary boot target not "
+				  "configured\n", __func__));
 	} else
 		ret = QLA_SUCCESS;
 
@@ -3602,8 +4080,8 @@
 	rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_sec_sess),
 				      ddb_index[1]);
 	if (rval != QLA_SUCCESS) {
-		DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Failed to get "
-				  "secondary target\n", __func__));
+		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Secondary boot target not"
+				  " configured\n", __func__));
 	} else
 		ret = QLA_SUCCESS;
 
@@ -3772,11 +4250,13 @@
 		sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr);
 
 	tddb->port = le16_to_cpu(fw_ddb_entry->port);
+	memcpy(&tddb->isid[0], &fw_ddb_entry->isid[0], sizeof(tddb->isid));
 }
 
 static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha,
 				     struct ql4_tuple_ddb *old_tddb,
-				     struct ql4_tuple_ddb *new_tddb)
+				     struct ql4_tuple_ddb *new_tddb,
+				     uint8_t is_isid_compare)
 {
 	if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name))
 		return QLA_ERROR;
@@ -3787,6 +4267,26 @@
 	if (old_tddb->port != new_tddb->port)
 		return QLA_ERROR;
 
+	/* For multi sessions, driver generates the ISID, so do not compare
+	 * ISID in reset path since it would be a comparision between the
+	 * driver generated ISID and firmware generated ISID. This could
+	 * lead to adding duplicated DDBs in the list as driver generated
+	 * ISID would not match firmware generated ISID.
+	 */
+	if (is_isid_compare) {
+		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: old ISID [%02x%02x%02x"
+			"%02x%02x%02x] New ISID [%02x%02x%02x%02x%02x%02x]\n",
+			__func__, old_tddb->isid[5], old_tddb->isid[4],
+			old_tddb->isid[3], old_tddb->isid[2], old_tddb->isid[1],
+			old_tddb->isid[0], new_tddb->isid[5], new_tddb->isid[4],
+			new_tddb->isid[3], new_tddb->isid[2], new_tddb->isid[1],
+			new_tddb->isid[0]));
+
+		if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0],
+			   sizeof(old_tddb->isid)))
+			return QLA_ERROR;
+	}
+
 	DEBUG2(ql4_printk(KERN_INFO, ha,
 			  "Match Found, fw[%d,%d,%s,%s], [%d,%d,%s,%s]",
 			  old_tddb->port, old_tddb->tpgt, old_tddb->ip_addr,
@@ -3829,7 +4329,7 @@
 			continue;
 
 		qla4xxx_get_param_ddb(ddb_entry, tmp_tddb);
-		if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb)) {
+		if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, false)) {
 			ret = QLA_SUCCESS; /* found */
 			goto exit_check;
 		}
@@ -3872,7 +4372,7 @@
 
 	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
 		qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb);
-		if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb)) {
+		if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, true)) {
 			ret = QLA_SUCCESS; /* found */
 			goto exit_check;
 		}
@@ -4038,6 +4538,10 @@
 		if (ret == QLA_ERROR)
 			break;
 
+		/* Ignore DDB if invalid state (unassigned) */
+		if (state == DDB_DS_UNASSIGNED)
+			goto continue_next_st;
+
 		/* Check if ST, add to the list_st */
 		if (strlen((char *) fw_ddb_entry->iscsi_name) != 0)
 			goto continue_next_st;
@@ -4397,6 +4901,9 @@
 
 	spin_lock_init(&ha->hardware_lock);
 
+	/* Initialize work list */
+	INIT_LIST_HEAD(&ha->work_list);
+
 	/* Allocate dma buffers */
 	if (qla4xxx_mem_alloc(ha)) {
 		ql4_printk(KERN_WARNING, ha,
@@ -4524,8 +5031,8 @@
 	       ha->patch_number, ha->build_number);
 
 	if (qla4xxx_setup_boot_info(ha))
-		ql4_printk(KERN_ERR, ha, "%s:ISCSI boot info setup failed\n",
-			   __func__);
+		ql4_printk(KERN_ERR, ha,
+			   "%s: No iSCSI boot target configured\n", __func__);
 
 		/* Perform the build ddb list and login to each */
 	qla4xxx_build_ddb_list(ha, INIT_ADAPTER);
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index 133989b..97b30c1 100644
--- a/drivers/scsi/qla4xxx/ql4_version.h
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -5,4 +5,4 @@
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
 
-#define QLA4XXX_DRIVER_VERSION	"5.02.00-k12"
+#define QLA4XXX_DRIVER_VERSION	"5.02.00-k16"
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index e40dc1c..b191dd5 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -35,7 +35,6 @@
 #include "qlogicpti.h"
 
 #include <asm/dma.h>
-#include <asm/system.h>
 #include <asm/ptrace.h>
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 2aeb2e9..07322ec 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -782,12 +782,6 @@
 	blk_complete_request(cmd->request);
 }
 
-/* Move this to a header if it becomes more generally useful */
-static struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
-{
-	return *(struct scsi_driver **)cmd->request->rq_disk->private_data;
-}
-
 /**
  * scsi_finish_command - cleanup and pass command back to upper layer
  * @cmd: the command
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 68da6c09..182d5a5 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -101,6 +101,7 @@
 #define DEF_LBPU 0
 #define DEF_LBPWS 0
 #define DEF_LBPWS10 0
+#define DEF_LBPRZ 1
 #define DEF_LOWEST_ALIGNED 0
 #define DEF_NO_LUN_0   0
 #define DEF_NUM_PARTS   0
@@ -126,6 +127,7 @@
 #define SCSI_DEBUG_OPT_TRANSPORT_ERR   16
 #define SCSI_DEBUG_OPT_DIF_ERR   32
 #define SCSI_DEBUG_OPT_DIX_ERR   64
+#define SCSI_DEBUG_OPT_MAC_TIMEOUT  128
 /* When "every_nth" > 0 then modulo "every_nth" commands:
  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
  *   - a RECOVERED_ERROR is simulated on successful read and write
@@ -185,6 +187,7 @@
 static unsigned int scsi_debug_lbpu = DEF_LBPU;
 static unsigned int scsi_debug_lbpws = DEF_LBPWS;
 static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10;
+static unsigned int scsi_debug_lbprz = DEF_LBPRZ;
 static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
 static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
 static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
@@ -774,10 +777,10 @@
 	return 0x3c;
 }
 
-/* Thin provisioning VPD page (SBC-3) */
+/* Logical block provisioning VPD page (SBC-3) */
 static int inquiry_evpd_b2(unsigned char *arr)
 {
-	memset(arr, 0, 0x8);
+	memset(arr, 0, 0x4);
 	arr[0] = 0;			/* threshold exponent */
 
 	if (scsi_debug_lbpu)
@@ -789,7 +792,10 @@
 	if (scsi_debug_lbpws10)
 		arr[1] |= 1 << 5;
 
-	return 0x8;
+	if (scsi_debug_lbprz)
+		arr[1] |= 1 << 2;
+
+	return 0x4;
 }
 
 #define SDEBUG_LONG_INQ_SZ 96
@@ -1070,8 +1076,11 @@
 	arr[13] = scsi_debug_physblk_exp & 0xf;
 	arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
 
-	if (scsi_debug_lbp())
+	if (scsi_debug_lbp()) {
 		arr[14] |= 0x80; /* LBPME */
+		if (scsi_debug_lbprz)
+			arr[14] |= 0x40; /* LBPRZ */
+	}
 
 	arr[15] = scsi_debug_lowest_aligned & 0xff;
 
@@ -2045,10 +2054,13 @@
 		block = lba + alignment;
 		rem = do_div(block, granularity);
 
-		if (rem == 0 && lba + granularity <= end &&
-		    block < map_size)
+		if (rem == 0 && lba + granularity <= end && block < map_size) {
 			clear_bit(block, map_storep);
-
+			if (scsi_debug_lbprz)
+				memset(fake_storep +
+				       block * scsi_debug_sector_size, 0,
+				       scsi_debug_sector_size);
+		}
 		lba += granularity - rem;
 	}
 }
@@ -2220,7 +2232,7 @@
 	mapped = map_state(lba, &num);
 
 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
-	put_unaligned_be32(16, &arr[0]);	/* Parameter Data Length */
+	put_unaligned_be32(20, &arr[0]);	/* Parameter Data Length */
 	put_unaligned_be64(lba, &arr[8]);	/* LBA */
 	put_unaligned_be32(num, &arr[16]);	/* Number of blocks */
 	arr[20] = !mapped;			/* mapped = 0, unmapped = 1 */
@@ -2730,6 +2742,7 @@
 module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO);
 module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO);
 module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO);
+module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO);
 module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
 module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
 module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
@@ -2771,6 +2784,7 @@
 MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
 MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
 MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
+MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
 MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
 MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
 MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");
@@ -3615,6 +3629,9 @@
 			scsi_debug_every_nth = -1;
 		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
 			return 0; /* ignore command causing timeout */
+		else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
+			 scsi_medium_access_command(SCpnt))
+			return 0; /* time out reads and writes */
 		else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
 			inj_recovered = 1; /* to reads and writes below */
 		else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 5f84a14..2cfcbff 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -30,6 +30,7 @@
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_dbg.h>
 #include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_host.h>
@@ -141,11 +142,11 @@
 	else if (host->hostt->eh_timed_out)
 		rtn = host->hostt->eh_timed_out(scmd);
 
+	scmd->result |= DID_TIME_OUT << 16;
+
 	if (unlikely(rtn == BLK_EH_NOT_HANDLED &&
-		     !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
-		scmd->result |= DID_TIME_OUT << 16;
+		     !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD)))
 		rtn = BLK_EH_HANDLED;
-	}
 
 	return rtn;
 }
@@ -366,6 +367,14 @@
 			return TARGET_ERROR;
 
 	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;
+		}
+		return SUCCESS;
+
 	default:
 		return SUCCESS;
 	}
@@ -770,6 +779,7 @@
 			     int cmnd_size, int timeout, unsigned sense_bytes)
 {
 	struct scsi_device *sdev = scmd->device;
+	struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd);
 	struct Scsi_Host *shost = sdev->host;
 	DECLARE_COMPLETION_ONSTACK(done);
 	unsigned long timeleft;
@@ -824,6 +834,10 @@
 	}
 
 	scsi_eh_restore_cmnd(scmd, &ses);
+
+	if (sdrv->eh_action)
+		rtn = sdrv->eh_action(scmd, cmnd, cmnd_size, rtn);
+
 	return rtn;
 }
 
@@ -1540,7 +1554,7 @@
 			 * Need to modify host byte to signal a
 			 * permanent target failure
 			 */
-			scmd->result |= (DID_TARGET_FAILURE << 16);
+			set_host_byte(scmd, DID_TARGET_FAILURE);
 			rtn = SUCCESS;
 		}
 		/* if rtn == FAILED, we have no sense information;
@@ -1560,7 +1574,7 @@
 	case RESERVATION_CONFLICT:
 		sdev_printk(KERN_INFO, scmd->device,
 			    "reservation conflict\n");
-		scmd->result |= (DID_NEXUS_FAILURE << 16);
+		set_host_byte(scmd, DID_NEXUS_FAILURE);
 		return SUCCESS; /* causes immediate i/o error */
 	default:
 		return FAILED;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index a33b2b6..ead6405 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -682,11 +682,11 @@
 		error = -ENOLINK;
 		break;
 	case DID_TARGET_FAILURE:
-		cmd->result |= (DID_OK << 16);
+		set_host_byte(cmd, DID_OK);
 		error = -EREMOTEIO;
 		break;
 	case DID_NEXUS_FAILURE:
-		cmd->result |= (DID_OK << 16);
+		set_host_byte(cmd, DID_OK);
 		error = -EBADE;
 		break;
 	default:
@@ -880,6 +880,7 @@
 				    cmd->cmnd[0] == WRITE_SAME)) {
 				description = "Discard failure";
 				action = ACTION_FAIL;
+				error = -EREMOTEIO;
 			} else
 				action = ACTION_FAIL;
 			break;
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index f59d4a0..80fbe2a 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -313,7 +313,7 @@
 #define FC_STARGET_NUM_ATTRS 	3
 #define FC_RPORT_NUM_ATTRS	10
 #define FC_VPORT_NUM_ATTRS	9
-#define FC_HOST_NUM_ATTRS	22
+#define FC_HOST_NUM_ATTRS	29
 
 struct fc_internal {
 	struct scsi_transport_template t;
@@ -399,6 +399,20 @@
 	fc_host->max_npiv_vports = 0;
 	memset(fc_host->serial_number, 0,
 		sizeof(fc_host->serial_number));
+	memset(fc_host->manufacturer, 0,
+		sizeof(fc_host->manufacturer));
+	memset(fc_host->model, 0,
+		sizeof(fc_host->model));
+	memset(fc_host->model_description, 0,
+		sizeof(fc_host->model_description));
+	memset(fc_host->hardware_version, 0,
+		sizeof(fc_host->hardware_version));
+	memset(fc_host->driver_version, 0,
+		sizeof(fc_host->driver_version));
+	memset(fc_host->firmware_version, 0,
+		sizeof(fc_host->firmware_version));
+	memset(fc_host->optionrom_version, 0,
+		sizeof(fc_host->optionrom_version));
 
 	fc_host->port_id = -1;
 	fc_host->port_type = FC_PORTTYPE_UNKNOWN;
@@ -1513,6 +1527,13 @@
 fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20);
 fc_private_host_rd_attr(max_npiv_vports, "%u\n", 20);
 fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1));
+fc_private_host_rd_attr(manufacturer, "%s\n", FC_SERIAL_NUMBER_SIZE + 1);
+fc_private_host_rd_attr(model, "%s\n", FC_SYMBOLIC_NAME_SIZE + 1);
+fc_private_host_rd_attr(model_description, "%s\n", FC_SYMBOLIC_NAME_SIZE + 1);
+fc_private_host_rd_attr(hardware_version, "%s\n", FC_VERSION_STRING_SIZE + 1);
+fc_private_host_rd_attr(driver_version, "%s\n", FC_VERSION_STRING_SIZE + 1);
+fc_private_host_rd_attr(firmware_version, "%s\n", FC_VERSION_STRING_SIZE + 1);
+fc_private_host_rd_attr(optionrom_version, "%s\n", FC_VERSION_STRING_SIZE + 1);
 
 
 /* Dynamic Host Attributes */
@@ -2208,6 +2229,13 @@
 		SETUP_HOST_ATTRIBUTE_RD_NS(npiv_vports_inuse);
 	}
 	SETUP_HOST_ATTRIBUTE_RD(serial_number);
+	SETUP_HOST_ATTRIBUTE_RD(manufacturer);
+	SETUP_HOST_ATTRIBUTE_RD(model);
+	SETUP_HOST_ATTRIBUTE_RD(model_description);
+	SETUP_HOST_ATTRIBUTE_RD(hardware_version);
+	SETUP_HOST_ATTRIBUTE_RD(driver_version);
+	SETUP_HOST_ATTRIBUTE_RD(firmware_version);
+	SETUP_HOST_ATTRIBUTE_RD(optionrom_version);
 
 	SETUP_HOST_ATTRIBUTE_RD(port_id);
 	SETUP_HOST_ATTRIBUTE_RD(port_type);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index cfd4914..1cf640e 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -727,10 +727,11 @@
 	kfree(session);
 }
 
-static int iscsi_is_session_dev(const struct device *dev)
+int iscsi_is_session_dev(const struct device *dev)
 {
 	return dev->release == iscsi_session_release;
 }
+EXPORT_SYMBOL_GPL(iscsi_is_session_dev);
 
 static int iscsi_iter_session_fn(struct device *dev, void *data)
 {
@@ -1476,6 +1477,66 @@
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_login_event);
 
+void iscsi_post_host_event(uint32_t host_no, struct iscsi_transport *transport,
+			   enum iscsi_host_event_code code, uint32_t data_size,
+			   uint8_t *data)
+{
+	struct nlmsghdr *nlh;
+	struct sk_buff *skb;
+	struct iscsi_uevent *ev;
+	int len = NLMSG_SPACE(sizeof(*ev) + data_size);
+
+	skb = alloc_skb(len, GFP_NOIO);
+	if (!skb) {
+		printk(KERN_ERR "gracefully ignored host event (%d):%d OOM\n",
+		       host_no, code);
+		return;
+	}
+
+	nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
+	ev = NLMSG_DATA(nlh);
+	ev->transport_handle = iscsi_handle(transport);
+	ev->type = ISCSI_KEVENT_HOST_EVENT;
+	ev->r.host_event.host_no = host_no;
+	ev->r.host_event.code = code;
+	ev->r.host_event.data_size = data_size;
+
+	if (data_size)
+		memcpy((char *)ev + sizeof(*ev), data, data_size);
+
+	iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_NOIO);
+}
+EXPORT_SYMBOL_GPL(iscsi_post_host_event);
+
+void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport,
+			   uint32_t status, uint32_t pid, uint32_t data_size,
+			   uint8_t *data)
+{
+	struct nlmsghdr *nlh;
+	struct sk_buff *skb;
+	struct iscsi_uevent *ev;
+	int len = NLMSG_SPACE(sizeof(*ev) + data_size);
+
+	skb = alloc_skb(len, GFP_NOIO);
+	if (!skb) {
+		printk(KERN_ERR "gracefully ignored ping comp: OOM\n");
+		return;
+	}
+
+	nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
+	ev = NLMSG_DATA(nlh);
+	ev->transport_handle = iscsi_handle(transport);
+	ev->type = ISCSI_KEVENT_PING_COMP;
+	ev->r.ping_comp.host_no = host_no;
+	ev->r.ping_comp.status = status;
+	ev->r.ping_comp.pid = pid;
+	ev->r.ping_comp.data_size = data_size;
+	memcpy((char *)ev + sizeof(*ev), data, data_size);
+
+	iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_NOIO);
+}
+EXPORT_SYMBOL_GPL(iscsi_ping_comp_event);
+
 static int
 iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi,
 		    void *payload, int size)
@@ -1915,6 +1976,123 @@
 }
 
 static int
+iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev)
+{
+	struct Scsi_Host *shost;
+	struct sockaddr *dst_addr;
+	int err;
+
+	if (!transport->send_ping)
+		return -ENOSYS;
+
+	shost = scsi_host_lookup(ev->u.iscsi_ping.host_no);
+	if (!shost) {
+		printk(KERN_ERR "iscsi_ping could not find host no %u\n",
+		       ev->u.iscsi_ping.host_no);
+		return -ENODEV;
+	}
+
+	dst_addr = (struct sockaddr *)((char *)ev + sizeof(*ev));
+	err = transport->send_ping(shost, ev->u.iscsi_ping.iface_num,
+				   ev->u.iscsi_ping.iface_type,
+				   ev->u.iscsi_ping.payload_size,
+				   ev->u.iscsi_ping.pid,
+				   dst_addr);
+	scsi_host_put(shost);
+	return err;
+}
+
+static int
+iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
+{
+	struct iscsi_uevent *ev = NLMSG_DATA(nlh);
+	struct Scsi_Host *shost = NULL;
+	struct iscsi_chap_rec *chap_rec;
+	struct iscsi_internal *priv;
+	struct sk_buff *skbchap;
+	struct nlmsghdr *nlhchap;
+	struct iscsi_uevent *evchap;
+	uint32_t chap_buf_size;
+	int len, err = 0;
+	char *buf;
+
+	if (!transport->get_chap)
+		return -EINVAL;
+
+	priv = iscsi_if_transport_lookup(transport);
+	if (!priv)
+		return -EINVAL;
+
+	chap_buf_size = (ev->u.get_chap.num_entries * sizeof(*chap_rec));
+	len = NLMSG_SPACE(sizeof(*ev) + chap_buf_size);
+
+	shost = scsi_host_lookup(ev->u.get_chap.host_no);
+	if (!shost) {
+		printk(KERN_ERR "%s: failed. Cound not find host no %u\n",
+		       __func__, ev->u.get_chap.host_no);
+		return -ENODEV;
+	}
+
+	do {
+		int actual_size;
+
+		skbchap = alloc_skb(len, GFP_KERNEL);
+		if (!skbchap) {
+			printk(KERN_ERR "can not deliver chap: OOM\n");
+			err = -ENOMEM;
+			goto exit_get_chap;
+		}
+
+		nlhchap = __nlmsg_put(skbchap, 0, 0, 0,
+				      (len - sizeof(*nlhchap)), 0);
+		evchap = NLMSG_DATA(nlhchap);
+		memset(evchap, 0, sizeof(*evchap));
+		evchap->transport_handle = iscsi_handle(transport);
+		evchap->type = nlh->nlmsg_type;
+		evchap->u.get_chap.host_no = ev->u.get_chap.host_no;
+		evchap->u.get_chap.chap_tbl_idx = ev->u.get_chap.chap_tbl_idx;
+		evchap->u.get_chap.num_entries = ev->u.get_chap.num_entries;
+		buf = (char *) ((char *)evchap + sizeof(*evchap));
+		memset(buf, 0, chap_buf_size);
+
+		err = transport->get_chap(shost, ev->u.get_chap.chap_tbl_idx,
+				    &evchap->u.get_chap.num_entries, buf);
+
+		actual_size = NLMSG_SPACE(sizeof(*ev) + chap_buf_size);
+		skb_trim(skbchap, NLMSG_ALIGN(actual_size));
+		nlhchap->nlmsg_len = actual_size;
+
+		err = iscsi_multicast_skb(skbchap, ISCSI_NL_GRP_ISCSID,
+					  GFP_KERNEL);
+	} while (err < 0 && err != -ECONNREFUSED);
+
+exit_get_chap:
+	scsi_host_put(shost);
+	return err;
+}
+
+static int iscsi_delete_chap(struct iscsi_transport *transport,
+			     struct iscsi_uevent *ev)
+{
+	struct Scsi_Host *shost;
+	int err = 0;
+
+	if (!transport->delete_chap)
+		return -ENOSYS;
+
+	shost = scsi_host_lookup(ev->u.delete_chap.host_no);
+	if (!shost) {
+		printk(KERN_ERR "%s could not find host no %u\n",
+		       __func__, ev->u.delete_chap.host_no);
+		return -ENODEV;
+	}
+
+	err = transport->delete_chap(shost, ev->u.delete_chap.chap_tbl_idx);
+	scsi_host_put(shost);
+	return err;
+}
+
+static int
 iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
 {
 	int err = 0;
@@ -1941,7 +2119,7 @@
 	switch (nlh->nlmsg_type) {
 	case ISCSI_UEVENT_CREATE_SESSION:
 		err = iscsi_if_create_session(priv, ep, ev,
-					      NETLINK_CREDS(skb)->pid,
+					      NETLINK_CB(skb).pid,
 					      ev->u.c_session.initial_cmdsn,
 					      ev->u.c_session.cmds_max,
 					      ev->u.c_session.queue_depth);
@@ -1954,7 +2132,7 @@
 		}
 
 		err = iscsi_if_create_session(priv, ep, ev,
-					NETLINK_CREDS(skb)->pid,
+					NETLINK_CB(skb).pid,
 					ev->u.c_bound_session.initial_cmdsn,
 					ev->u.c_bound_session.cmds_max,
 					ev->u.c_bound_session.queue_depth);
@@ -2059,6 +2237,15 @@
 		err = iscsi_set_iface_params(transport, ev,
 					     nlmsg_attrlen(nlh, sizeof(*ev)));
 		break;
+	case ISCSI_UEVENT_PING:
+		err = iscsi_send_ping(transport, ev);
+		break;
+	case ISCSI_UEVENT_GET_CHAP:
+		err = iscsi_get_chap(transport, nlh);
+		break;
+	case ISCSI_UEVENT_DELETE_CHAP:
+		err = iscsi_delete_chap(transport, ev);
+		break;
 	default:
 		err = -ENOSYS;
 		break;
@@ -2108,9 +2295,11 @@
 			 */
 			if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
 				break;
+			if (ev->type == ISCSI_UEVENT_GET_CHAP && !err)
+				break;
 			err = iscsi_if_send_reply(group, nlh->nlmsg_seq,
 				nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
-		} while (err < 0 && err != -ECONNREFUSED);
+		} while (err < 0 && err != -ECONNREFUSED && err != -ESRCH);
 		skb_pull(skb, rlen);
 	}
 	mutex_unlock(&rx_queue_mutex);
@@ -2286,6 +2475,8 @@
 iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1);
 iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1);
 iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);
+iscsi_session_attr(chap_out_idx, ISCSI_PARAM_CHAP_OUT_IDX, 1);
+iscsi_session_attr(chap_in_idx, ISCSI_PARAM_CHAP_IN_IDX, 1);
 iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0);
 iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
 iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
@@ -2382,6 +2573,8 @@
 	&dev_attr_priv_sess_recovery_tmo.attr,
 	&dev_attr_priv_sess_state.attr,
 	&dev_attr_priv_sess_creator.attr,
+	&dev_attr_sess_chap_out_idx.attr,
+	&dev_attr_sess_chap_in_idx.attr,
 	NULL,
 };
 
@@ -2413,6 +2606,10 @@
 		param = ISCSI_PARAM_TARGET_NAME;
 	else if (attr == &dev_attr_sess_tpgt.attr)
 		param = ISCSI_PARAM_TPGT;
+	else if (attr == &dev_attr_sess_chap_in_idx.attr)
+		param = ISCSI_PARAM_CHAP_IN_IDX;
+	else if (attr == &dev_attr_sess_chap_out_idx.attr)
+		param = ISCSI_PARAM_CHAP_OUT_IDX;
 	else if (attr == &dev_attr_sess_password.attr)
 		param = ISCSI_PARAM_USERNAME;
 	else if (attr == &dev_attr_sess_password_in.attr)
@@ -2476,12 +2673,16 @@
 iscsi_host_attr(hwaddress, ISCSI_HOST_PARAM_HWADDRESS);
 iscsi_host_attr(ipaddress, ISCSI_HOST_PARAM_IPADDRESS);
 iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
+iscsi_host_attr(port_state, ISCSI_HOST_PARAM_PORT_STATE);
+iscsi_host_attr(port_speed, ISCSI_HOST_PARAM_PORT_SPEED);
 
 static struct attribute *iscsi_host_attrs[] = {
 	&dev_attr_host_netdev.attr,
 	&dev_attr_host_hwaddress.attr,
 	&dev_attr_host_ipaddress.attr,
 	&dev_attr_host_initiatorname.attr,
+	&dev_attr_host_port_state.attr,
+	&dev_attr_host_port_speed.attr,
 	NULL,
 };
 
@@ -2501,6 +2702,10 @@
 		param = ISCSI_HOST_PARAM_IPADDRESS;
 	else if (attr == &dev_attr_host_initiatorname.attr)
 		param = ISCSI_HOST_PARAM_INITIATOR_NAME;
+	else if (attr == &dev_attr_host_port_state.attr)
+		param = ISCSI_HOST_PARAM_PORT_STATE;
+	else if (attr == &dev_attr_host_port_speed.attr)
+		param = ISCSI_HOST_PARAM_PORT_SPEED;
 	else {
 		WARN_ONCE(1, "Invalid host attr");
 		return 0;
@@ -2514,6 +2719,61 @@
 	.is_visible = iscsi_host_attr_is_visible,
 };
 
+/* convert iscsi_port_speed values to ascii string name */
+static const struct {
+	enum iscsi_port_speed	value;
+	char			*name;
+} iscsi_port_speed_names[] = {
+	{ISCSI_PORT_SPEED_UNKNOWN,	"Unknown" },
+	{ISCSI_PORT_SPEED_10MBPS,	"10 Mbps" },
+	{ISCSI_PORT_SPEED_100MBPS,	"100 Mbps" },
+	{ISCSI_PORT_SPEED_1GBPS,	"1 Gbps" },
+	{ISCSI_PORT_SPEED_10GBPS,	"10 Gbps" },
+};
+
+char *iscsi_get_port_speed_name(struct Scsi_Host *shost)
+{
+	int i;
+	char *speed = "Unknown!";
+	struct iscsi_cls_host *ihost = shost->shost_data;
+	uint32_t port_speed = ihost->port_speed;
+
+	for (i = 0; i < ARRAY_SIZE(iscsi_port_speed_names); i++) {
+		if (iscsi_port_speed_names[i].value & port_speed) {
+			speed = iscsi_port_speed_names[i].name;
+			break;
+		}
+	}
+	return speed;
+}
+EXPORT_SYMBOL_GPL(iscsi_get_port_speed_name);
+
+/* convert iscsi_port_state values to ascii string name */
+static const struct {
+	enum iscsi_port_state	value;
+	char			*name;
+} iscsi_port_state_names[] = {
+	{ISCSI_PORT_STATE_DOWN,		"LINK DOWN" },
+	{ISCSI_PORT_STATE_UP,		"LINK UP" },
+};
+
+char *iscsi_get_port_state_name(struct Scsi_Host *shost)
+{
+	int i;
+	char *state = "Unknown!";
+	struct iscsi_cls_host *ihost = shost->shost_data;
+	uint32_t port_state = ihost->port_state;
+
+	for (i = 0; i < ARRAY_SIZE(iscsi_port_state_names); i++) {
+		if (iscsi_port_state_names[i].value & port_state) {
+			state = iscsi_port_state_names[i].name;
+			break;
+		}
+	}
+	return state;
+}
+EXPORT_SYMBOL_GPL(iscsi_get_port_state_name);
+
 static int iscsi_session_match(struct attribute_container *cont,
 			   struct device *dev)
 {
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 9d9330a..f7565fc 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -615,6 +615,7 @@
 	error = i->f->phy_reset(phy, hard_reset);
 	if (error)
 		return error;
+	phy->enabled = 1;
 	return count;
 };
 
@@ -652,9 +653,21 @@
 sas_phy_linkerror_attr(loss_of_dword_sync_count);
 sas_phy_linkerror_attr(phy_reset_problem_count);
 
+static int sas_phy_setup(struct transport_container *tc, struct device *dev,
+			 struct device *cdev)
+{
+	struct sas_phy *phy = dev_to_phy(dev);
+	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+	struct sas_internal *i = to_sas_internal(shost->transportt);
+
+	if (i->f->phy_setup)
+		i->f->phy_setup(phy);
+
+	return 0;
+}
 
 static DECLARE_TRANSPORT_CLASS(sas_phy_class,
-		"sas_phy", NULL, NULL, NULL);
+		"sas_phy", sas_phy_setup, NULL, NULL);
 
 static int sas_phy_match(struct attribute_container *cont, struct device *dev)
 {
@@ -678,7 +691,11 @@
 static void sas_phy_release(struct device *dev)
 {
 	struct sas_phy *phy = dev_to_phy(dev);
+	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+	struct sas_internal *i = to_sas_internal(shost->transportt);
 
+	if (i->f->phy_release)
+		i->f->phy_release(phy);
 	put_device(dev->parent);
 	kfree(phy);
 }
@@ -1044,6 +1061,29 @@
 EXPORT_SYMBOL(scsi_is_sas_port);
 
 /**
+ * sas_port_get_phy - try to take a reference on a port member
+ * @port: port to check
+ */
+struct sas_phy *sas_port_get_phy(struct sas_port *port)
+{
+	struct sas_phy *phy;
+
+	mutex_lock(&port->phy_list_mutex);
+	if (list_empty(&port->phy_list))
+		phy = NULL;
+	else {
+		struct list_head *ent = port->phy_list.next;
+
+		phy = list_entry(ent, typeof(*phy), port_siblings);
+		get_device(&phy->dev);
+	}
+	mutex_unlock(&port->phy_list_mutex);
+
+	return phy;
+}
+EXPORT_SYMBOL(sas_port_get_phy);
+
+/**
  * sas_port_add_phy - add another phy to a port to form a wide port
  * @port:	port to add the phy to
  * @phy:	phy to add
@@ -1603,6 +1643,20 @@
 EXPORT_SYMBOL(sas_rphy_delete);
 
 /**
+ * sas_rphy_unlink  -  unlink SAS remote PHY
+ * @rphy:	SAS remote phy to unlink from its parent port
+ *
+ * Removes port reference to an rphy
+ */
+void sas_rphy_unlink(struct sas_rphy *rphy)
+{
+	struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);
+
+	parent->rphy = NULL;
+}
+EXPORT_SYMBOL(sas_rphy_unlink);
+
+/**
  * sas_rphy_remove  -  remove SAS remote PHY
  * @rphy:	SAS remote phy to remove
  *
@@ -1612,7 +1666,6 @@
 sas_rphy_remove(struct sas_rphy *rphy)
 {
 	struct device *dev = &rphy->dev;
-	struct sas_port *parent = dev_to_sas_port(dev->parent);
 
 	switch (rphy->identify.device_type) {
 	case SAS_END_DEVICE:
@@ -1626,10 +1679,9 @@
 		break;
 	}
 
+	sas_rphy_unlink(rphy);
 	transport_remove_device(dev);
 	device_del(dev);
-
-	parent->rphy = NULL;
 }
 EXPORT_SYMBOL(sas_rphy_remove);
 
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index d173b90..5ba5c2a 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -107,6 +107,7 @@
 static int sd_resume(struct device *);
 static void sd_rescan(struct device *);
 static int sd_done(struct scsi_cmnd *);
+static int sd_eh_action(struct scsi_cmnd *, unsigned char *, int, int);
 static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);
 static void scsi_disk_release(struct device *cdev);
 static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
@@ -346,6 +347,31 @@
 	return count;
 }
 
+static ssize_t
+sd_show_max_medium_access_timeouts(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct scsi_disk *sdkp = to_scsi_disk(dev);
+
+	return snprintf(buf, 20, "%u\n", sdkp->max_medium_access_timeouts);
+}
+
+static ssize_t
+sd_store_max_medium_access_timeouts(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct scsi_disk *sdkp = to_scsi_disk(dev);
+	int err;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	err = kstrtouint(buf, 10, &sdkp->max_medium_access_timeouts);
+
+	return err ? err : count;
+}
+
 static struct device_attribute sd_disk_attrs[] = {
 	__ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type,
 	       sd_store_cache_type),
@@ -360,6 +386,9 @@
 	__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_medium_access_timeouts, S_IRUGO|S_IWUSR,
+	       sd_show_max_medium_access_timeouts,
+	       sd_store_max_medium_access_timeouts),
 	__ATTR_NULL,
 };
 
@@ -382,6 +411,7 @@
 	},
 	.rescan			= sd_rescan,
 	.done			= sd_done,
+	.eh_action		= sd_eh_action,
 };
 
 /*
@@ -497,6 +527,8 @@
 		max(sdkp->physical_block_size,
 		    sdkp->unmap_granularity * logical_block_size);
 
+	sdkp->provisioning_mode = mode;
+
 	switch (mode) {
 
 	case SD_LBP_DISABLE:
@@ -524,8 +556,6 @@
 
 	q->limits.max_discard_sectors = max_blocks * (logical_block_size >> 9);
 	queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
-
-	sdkp->provisioning_mode = mode;
 }
 
 /**
@@ -634,7 +664,7 @@
 }
 
 /**
- *	sd_init_command - build a scsi (read or write) command from
+ *	sd_prep_fn - build a scsi (read or write) command from
  *	information in the request structure.
  *	@SCpnt: pointer to mid-level's per scsi command structure that
  *	contains request and into which the scsi command is written
@@ -681,7 +711,7 @@
 	ret = BLKPREP_KILL;
 
 	SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,
-					"sd_init_command: block=%llu, "
+					"sd_prep_fn: block=%llu, "
 					"count=%d\n",
 					(unsigned long long)block,
 					this_count));
@@ -1182,9 +1212,14 @@
 	retval = -ENODEV;
 
 	if (scsi_block_when_processing_errors(sdp)) {
+		retval = scsi_autopm_get_device(sdp);
+		if (retval)
+			goto out;
+
 		sshdr  = kzalloc(sizeof(*sshdr), GFP_KERNEL);
 		retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES,
 					      sshdr);
+		scsi_autopm_put_device(sdp);
 	}
 
 	/* failed to execute TUR, assume media not present */
@@ -1313,6 +1348,55 @@
 	.unlock_native_capacity	= sd_unlock_native_capacity,
 };
 
+/**
+ *	sd_eh_action - error handling callback
+ *	@scmd:		sd-issued command that has failed
+ *	@eh_cmnd:	The command that was sent during error handling
+ *	@eh_cmnd_len:	Length of eh_cmnd in bytes
+ *	@eh_disp:	The recovery disposition suggested by the midlayer
+ *
+ *	This function is called by the SCSI midlayer upon completion of
+ *	an error handling command (TEST UNIT READY, START STOP UNIT,
+ *	etc.) The command sent to the device by the error handler is
+ *	stored in eh_cmnd. The result of sending the eh command is
+ *	passed in eh_disp.
+ **/
+static int sd_eh_action(struct scsi_cmnd *scmd, unsigned char *eh_cmnd,
+			int eh_cmnd_len, int eh_disp)
+{
+	struct scsi_disk *sdkp = scsi_disk(scmd->request->rq_disk);
+
+	if (!scsi_device_online(scmd->device) ||
+	    !scsi_medium_access_command(scmd))
+		return eh_disp;
+
+	/*
+	 * The device has timed out executing a medium access command.
+	 * However, the TEST UNIT READY command sent during error
+	 * handling completed successfully. Either the device is in the
+	 * process of recovering or has it suffered an internal failure
+	 * that prevents access to the storage medium.
+	 */
+	if (host_byte(scmd->result) == DID_TIME_OUT && eh_disp == SUCCESS &&
+	    eh_cmnd_len && eh_cmnd[0] == TEST_UNIT_READY)
+		sdkp->medium_access_timed_out++;
+
+	/*
+	 * If the device keeps failing read/write commands but TEST UNIT
+	 * READY always completes successfully we assume that medium
+	 * access is no longer possible and take the device offline.
+	 */
+	if (sdkp->medium_access_timed_out >= sdkp->max_medium_access_timeouts) {
+		scmd_printk(KERN_ERR, scmd,
+			    "Medium access timeout failure. Offlining disk!\n");
+		scsi_device_set_state(scmd->device, SDEV_OFFLINE);
+
+		return FAILED;
+	}
+
+	return eh_disp;
+}
+
 static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
 {
 	u64 start_lba = blk_rq_pos(scmd->request);
@@ -1402,6 +1486,8 @@
 	    (!sense_valid || sense_deferred))
 		goto out;
 
+	sdkp->medium_access_timed_out = 0;
+
 	switch (sshdr.sense_key) {
 	case HARDWARE_ERROR:
 	case MEDIUM_ERROR:
@@ -2523,6 +2609,7 @@
 	sdkp->RCD = 0;
 	sdkp->ATO = 0;
 	sdkp->first_scan = 1;
+	sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS;
 
 	sd_revalidate_disk(gd);
 
@@ -2562,8 +2649,8 @@
  *	(e.g. /dev/sda). More precisely it is the block device major 
  *	and minor number that is chosen here.
  *
- *	Assume sd_attach is not re-entrant (for time being)
- *	Also think about sd_attach() and sd_remove() running coincidentally.
+ *	Assume sd_probe is not re-entrant (for time being)
+ *	Also think about sd_probe() and sd_remove() running coincidentally.
  **/
 static int sd_probe(struct device *dev)
 {
@@ -2578,7 +2665,7 @@
 		goto out;
 
 	SCSI_LOG_HLQUEUE(3, sdev_printk(KERN_INFO, sdp,
-					"sd_attach\n"));
+					"sd_probe\n"));
 
 	error = -ENOMEM;
 	sdkp = kzalloc(sizeof(*sdkp), GFP_KERNEL);
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 4163f29..f703f48 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -20,6 +20,7 @@
  */
 #define SD_MAX_RETRIES		5
 #define SD_PASSTHROUGH_RETRIES	1
+#define SD_MAX_MEDIUM_TIMEOUTS	2
 
 /*
  * Size of the initial data buffer for mode and read capacity data
@@ -59,6 +60,8 @@
 	u32		unmap_alignment;
 	u32		index;
 	unsigned int	physical_block_size;
+	unsigned int	max_medium_access_timeouts;
+	unsigned int	medium_access_timed_out;
 	u8		media_present;
 	u8		write_prot;
 	u8		protection_type;/* Data Integrity Field */
@@ -88,6 +91,38 @@
 		    (sdsk)->disk->disk_name, ##a) :			\
 	sdev_printk(prefix, (sdsk)->device, fmt, ##a)
 
+static inline int scsi_medium_access_command(struct scsi_cmnd *scmd)
+{
+	switch (scmd->cmnd[0]) {
+	case READ_6:
+	case READ_10:
+	case READ_12:
+	case READ_16:
+	case SYNCHRONIZE_CACHE:
+	case VERIFY:
+	case VERIFY_12:
+	case VERIFY_16:
+	case WRITE_6:
+	case WRITE_10:
+	case WRITE_12:
+	case WRITE_16:
+	case WRITE_SAME:
+	case WRITE_SAME_16:
+	case UNMAP:
+		return 1;
+	case VARIABLE_LENGTH_CMD:
+		switch (scmd->cmnd[9]) {
+		case READ_32:
+		case VERIFY_32:
+		case WRITE_32:
+		case WRITE_SAME_32:
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
 /*
  * A DIF-capable target device can be formatted with different
  * protection schemes.  Currently 0 through 3 are defined:
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 9b28f39..e41998c 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -42,7 +42,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/dma.h>
-#include <asm/system.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_dbg.h>
@@ -1106,6 +1105,12 @@
                                     STp->drv_buffer));
 		}
 		STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
+		if (!STp->drv_buffer && STp->immediate_filemark) {
+			printk(KERN_WARNING
+			    "%s: non-buffered tape: disabling writing immediate filemarks\n",
+			    name);
+			STp->immediate_filemark = 0;
+		}
 	}
 	st_release_request(SRpnt);
 	SRpnt = NULL;
@@ -1177,6 +1182,7 @@
 static int st_open(struct inode *inode, struct file *filp)
 {
 	int i, retval = (-EIO);
+	int resumed = 0;
 	struct scsi_tape *STp;
 	struct st_partstat *STps;
 	int dev = TAPE_NR(inode);
@@ -1211,6 +1217,11 @@
 	write_unlock(&st_dev_arr_lock);
 	STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0;
 
+	if (scsi_autopm_get_device(STp->device) < 0) {
+		retval = -EIO;
+		goto err_out;
+	}
+	resumed = 1;
 	if (!scsi_block_when_processing_errors(STp->device)) {
 		retval = (-ENXIO);
 		goto err_out;
@@ -1258,6 +1269,8 @@
 	normalize_buffer(STp->buffer);
 	STp->in_use = 0;
 	scsi_tape_put(STp);
+	if (resumed)
+		scsi_autopm_put_device(STp->device);
 	mutex_unlock(&st_mutex);
 	return retval;
 
@@ -1306,6 +1319,8 @@
 
 		memset(cmd, 0, MAX_COMMAND_SIZE);
 		cmd[0] = WRITE_FILEMARKS;
+		if (STp->immediate_filemark)
+			cmd[1] = 1;
 		cmd[4] = 1 + STp->two_fm;
 
 		SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
@@ -1391,6 +1406,7 @@
 	write_lock(&st_dev_arr_lock);
 	STp->in_use = 0;
 	write_unlock(&st_dev_arr_lock);
+	scsi_autopm_put_device(STp->device);
 	scsi_tape_put(STp);
 
 	return result;
@@ -2172,8 +2188,9 @@
 		       name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
 		       STp->scsi2_logical);
 		printk(KERN_INFO
-		       "%s:    sysv: %d nowait: %d sili: %d\n", name, STm->sysv, STp->immediate,
-			STp->sili);
+		       "%s:    sysv: %d nowait: %d sili: %d nowait_filemark: %d\n",
+		       name, STm->sysv, STp->immediate, STp->sili,
+		       STp->immediate_filemark);
 		printk(KERN_INFO "%s:    debugging: %d\n",
 		       name, debugging);
 	}
@@ -2215,6 +2232,7 @@
 			STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
 		STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
 		STp->immediate = (options & MT_ST_NOWAIT) != 0;
+		STp->immediate_filemark = (options & MT_ST_NOWAIT_EOF) != 0;
 		STm->sysv = (options & MT_ST_SYSV) != 0;
 		STp->sili = (options & MT_ST_SILI) != 0;
 		DEB( debugging = (options & MT_ST_DEBUGGING) != 0;
@@ -2246,6 +2264,8 @@
 			STp->scsi2_logical = value;
 		if ((options & MT_ST_NOWAIT) != 0)
 			STp->immediate = value;
+		if ((options & MT_ST_NOWAIT_EOF) != 0)
+			STp->immediate_filemark = value;
 		if ((options & MT_ST_SYSV) != 0)
 			STm->sysv = value;
 		if ((options & MT_ST_SILI) != 0)
@@ -2705,7 +2725,8 @@
 		cmd[0] = WRITE_FILEMARKS;
 		if (cmd_in == MTWSM)
 			cmd[1] = 2;
-		if (cmd_in == MTWEOFI)
+		if (cmd_in == MTWEOFI ||
+		    (cmd_in == MTWEOF && STp->immediate_filemark))
 			cmd[1] |= 1;
 		cmd[2] = (arg >> 16);
 		cmd[3] = (arg >> 8);
@@ -4084,6 +4105,7 @@
 	tpnt->scsi2_logical = ST_SCSI2LOGICAL;
 	tpnt->sili = ST_SILI;
 	tpnt->immediate = ST_NOWAIT;
+	tpnt->immediate_filemark = 0;
 	tpnt->default_drvbuffer = 0xff;		/* No forced buffering */
 	tpnt->partition = 0;
 	tpnt->new_partition = 0;
@@ -4154,6 +4176,7 @@
 		if (error)
 			goto out_free_tape;
 	}
+	scsi_autopm_put_device(SDp);
 
 	sdev_printk(KERN_NOTICE, SDp,
 		    "Attached scsi tape %s\n", tape_name(tpnt));
@@ -4201,6 +4224,7 @@
 	struct scsi_tape *tpnt;
 	int i, j, mode;
 
+	scsi_autopm_get_device(SDp);
 	write_lock(&st_dev_arr_lock);
 	for (i = 0; i < st_dev_max; i++) {
 		tpnt = scsi_tapes[i];
@@ -4467,6 +4491,7 @@
 	options |= STp->scsi2_logical ? MT_ST_SCSI2LOGICAL : 0;
 	options |= STm->sysv ? MT_ST_SYSV : 0;
 	options |= STp->immediate ? MT_ST_NOWAIT : 0;
+	options |= STp->immediate_filemark ? MT_ST_NOWAIT_EOF : 0;
 	options |= STp->sili ? MT_ST_SILI : 0;
 
 	l = snprintf(buf, PAGE_SIZE, "0x%08x\n", options);
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index f91a67c..ea35632 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -120,6 +120,7 @@
 	unsigned char c_algo;			/* compression algorithm */
 	unsigned char pos_unknown;			/* after reset position unknown */
 	unsigned char sili;			/* use SILI when reading in variable b mode */
+	unsigned char immediate_filemark;	/* write filemark immediately */
 	int tape_type;
 	int long_timeout;	/* timeout for commands known to take long time */
 
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index baf7328..6e25889 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -63,7 +63,6 @@
 #include <linux/blkdev.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <asm/sun3ints.h>
 #include <asm/dvma.h>
diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c
index fbba78e..a3dd55d 100644
--- a/drivers/scsi/sun3_scsi_vme.c
+++ b/drivers/scsi/sun3_scsi_vme.c
@@ -25,7 +25,6 @@
 #include <linux/blkdev.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <asm/sun3ints.h>
 #include <asm/dvma.h>
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
index 012c86e..ac4eca6 100644
--- a/drivers/scsi/sym53c416.c
+++ b/drivers/scsi/sym53c416.c
@@ -37,7 +37,6 @@
 #include <linux/proc_fs.h>
 #include <linux/spinlock.h>
 #include <asm/dma.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <linux/blkdev.h>
 #include <linux/isapnp.h>
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index 041eaaa..d672d97 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -106,7 +106,6 @@
  * $Log: t128.c,v $
  */
 
-#include <asm/system.h>
 #include <linux/signal.h>
 #include <linux/io.h>
 #include <linux/blkdev.h>
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 90e104d..9c216e5 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -410,7 +410,6 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/byteorder.h>
 #include <linux/proc_fs.h>
 #include <linux/blkdev.h>
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
new file mode 100644
index 0000000..8f27f9d
--- /dev/null
+++ b/drivers/scsi/ufs/Kconfig
@@ -0,0 +1,49 @@
+#
+# Kernel configuration file for the UFS Host Controller
+#
+# This code is based on drivers/scsi/ufs/Kconfig
+# Copyright (C) 2011  Samsung Samsung India Software Operations
+#
+# Santosh Yaraganavi <santosh.sy@samsung.com>
+# Vinayak Holikatti <h.vinayak@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 distributed in the hope that it will be useful,
+# but WITHOUT 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.
+
+config SCSI_UFSHCD
+	tristate "Universal Flash Storage host controller driver"
+	depends on PCI && SCSI
+	---help---
+	This is a generic driver which supports PCIe UFS Host controllers.
diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
new file mode 100644
index 0000000..adf7895
--- /dev/null
+++ b/drivers/scsi/ufs/Makefile
@@ -0,0 +1,2 @@
+# UFSHCD makefile
+obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
new file mode 100644
index 0000000..b207529
--- /dev/null
+++ b/drivers/scsi/ufs/ufs.h
@@ -0,0 +1,207 @@
+/*
+ * Universal Flash Storage Host controller driver
+ *
+ * This code is based on drivers/scsi/ufs/ufs.h
+ * Copyright (C) 2011-2012 Samsung India Software Operations
+ *
+ * Santosh Yaraganavi <santosh.sy@samsung.com>
+ * Vinayak Holikatti <h.vinayak@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 distributed in the hope that it will be useful,
+ * but WITHOUT 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 _UFS_H
+#define _UFS_H
+
+#define MAX_CDB_SIZE	16
+
+#define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
+			((byte3 << 24) | (byte2 << 16) |\
+			 (byte1 << 8) | (byte0))
+
+/*
+ * UFS Protocol Information Unit related definitions
+ */
+
+/* Task management functions */
+enum {
+	UFS_ABORT_TASK		= 0x01,
+	UFS_ABORT_TASK_SET	= 0x02,
+	UFS_CLEAR_TASK_SET	= 0x04,
+	UFS_LOGICAL_RESET	= 0x08,
+	UFS_QUERY_TASK		= 0x80,
+	UFS_QUERY_TASK_SET	= 0x81,
+};
+
+/* UTP UPIU Transaction Codes Initiator to Target */
+enum {
+	UPIU_TRANSACTION_NOP_OUT	= 0x00,
+	UPIU_TRANSACTION_COMMAND	= 0x01,
+	UPIU_TRANSACTION_DATA_OUT	= 0x02,
+	UPIU_TRANSACTION_TASK_REQ	= 0x04,
+	UPIU_TRANSACTION_QUERY_REQ	= 0x26,
+};
+
+/* UTP UPIU Transaction Codes Target to Initiator */
+enum {
+	UPIU_TRANSACTION_NOP_IN		= 0x20,
+	UPIU_TRANSACTION_RESPONSE	= 0x21,
+	UPIU_TRANSACTION_DATA_IN	= 0x22,
+	UPIU_TRANSACTION_TASK_RSP	= 0x24,
+	UPIU_TRANSACTION_READY_XFER	= 0x31,
+	UPIU_TRANSACTION_QUERY_RSP	= 0x36,
+};
+
+/* UPIU Read/Write flags */
+enum {
+	UPIU_CMD_FLAGS_NONE	= 0x00,
+	UPIU_CMD_FLAGS_WRITE	= 0x20,
+	UPIU_CMD_FLAGS_READ	= 0x40,
+};
+
+/* UPIU Task Attributes */
+enum {
+	UPIU_TASK_ATTR_SIMPLE	= 0x00,
+	UPIU_TASK_ATTR_ORDERED	= 0x01,
+	UPIU_TASK_ATTR_HEADQ	= 0x02,
+	UPIU_TASK_ATTR_ACA	= 0x03,
+};
+
+/* UTP QUERY Transaction Specific Fields OpCode */
+enum {
+	UPIU_QUERY_OPCODE_NOP		= 0x0,
+	UPIU_QUERY_OPCODE_READ_DESC	= 0x1,
+	UPIU_QUERY_OPCODE_WRITE_DESC	= 0x2,
+	UPIU_QUERY_OPCODE_READ_ATTR	= 0x3,
+	UPIU_QUERY_OPCODE_WRITE_ATTR	= 0x4,
+	UPIU_QUERY_OPCODE_READ_FLAG	= 0x5,
+	UPIU_QUERY_OPCODE_SET_FLAG	= 0x6,
+	UPIU_QUERY_OPCODE_CLEAR_FLAG	= 0x7,
+	UPIU_QUERY_OPCODE_TOGGLE_FLAG	= 0x8,
+};
+
+/* UTP Transfer Request Command Type (CT) */
+enum {
+	UPIU_COMMAND_SET_TYPE_SCSI	= 0x0,
+	UPIU_COMMAND_SET_TYPE_UFS	= 0x1,
+	UPIU_COMMAND_SET_TYPE_QUERY	= 0x2,
+};
+
+enum {
+	MASK_SCSI_STATUS	= 0xFF,
+	MASK_TASK_RESPONSE	= 0xFF00,
+	MASK_RSP_UPIU_RESULT	= 0xFFFF,
+};
+
+/* Task management service response */
+enum {
+	UPIU_TASK_MANAGEMENT_FUNC_COMPL		= 0x00,
+	UPIU_TASK_MANAGEMENT_FUNC_NOT_SUPPORTED = 0x04,
+	UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED	= 0x08,
+	UPIU_TASK_MANAGEMENT_FUNC_FAILED	= 0x05,
+	UPIU_INCORRECT_LOGICAL_UNIT_NO		= 0x09,
+};
+/**
+ * struct utp_upiu_header - UPIU header structure
+ * @dword_0: UPIU header DW-0
+ * @dword_1: UPIU header DW-1
+ * @dword_2: UPIU header DW-2
+ */
+struct utp_upiu_header {
+	u32 dword_0;
+	u32 dword_1;
+	u32 dword_2;
+};
+
+/**
+ * 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
+ * @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;
+	u32 residual_transfer_count;
+	u32 reserved[4];
+	u16 sense_data_len;
+	u8 sense_data[18];
+};
+
+/**
+ * struct utp_upiu_task_req - Task request UPIU structure
+ * @header - UPIU header structure DW0 to DW-2
+ * @input_param1: Input parameter 1 DW-3
+ * @input_param2: Input parameter 2 DW-4
+ * @input_param3: Input parameter 3 DW-5
+ * @reserved: Reserved double words DW-6 to DW-7
+ */
+struct utp_upiu_task_req {
+	struct utp_upiu_header header;
+	u32 input_param1;
+	u32 input_param2;
+	u32 input_param3;
+	u32 reserved[2];
+};
+
+/**
+ * struct utp_upiu_task_rsp - Task Management Response UPIU structure
+ * @header: UPIU header structure DW0-DW-2
+ * @output_param1: Ouput parameter 1 DW3
+ * @output_param2: Output parameter 2 DW4
+ * @reserved: Reserved double words DW-5 to DW-7
+ */
+struct utp_upiu_task_rsp {
+	struct utp_upiu_header header;
+	u32 output_param1;
+	u32 output_param2;
+	u32 reserved[3];
+};
+
+#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
new file mode 100644
index 0000000..52b96e8
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -0,0 +1,1978 @@
+/*
+ * Universal Flash Storage Host controller driver
+ *
+ * This code is based on drivers/scsi/ufs/ufshcd.c
+ * Copyright (C) 2011-2012 Samsung India Software Operations
+ *
+ * Santosh Yaraganavi <santosh.sy@samsung.com>
+ * Vinayak Holikatti <h.vinayak@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 distributed in the hope that it will be useful,
+ * but WITHOUT 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_eh.h>
+
+#include "ufs.h"
+#include "ufshci.h"
+
+#define UFSHCD "ufshcd"
+#define UFSHCD_DRIVER_VERSION "0.1"
+
+enum {
+	UFSHCD_MAX_CHANNEL	= 0,
+	UFSHCD_MAX_ID		= 1,
+	UFSHCD_MAX_LUNS		= 8,
+	UFSHCD_CMD_PER_LUN	= 32,
+	UFSHCD_CAN_QUEUE	= 32,
+};
+
+/* UFSHCD states */
+enum {
+	UFSHCD_STATE_OPERATIONAL,
+	UFSHCD_STATE_RESET,
+	UFSHCD_STATE_ERROR,
+};
+
+/* Interrupt configuration options */
+enum {
+	UFSHCD_INT_DISABLE,
+	UFSHCD_INT_ENABLE,
+	UFSHCD_INT_CLEAR,
+};
+
+/* Interrupt aggregation options */
+enum {
+	INT_AGGR_RESET,
+	INT_AGGR_CONFIG,
+};
+
+/**
+ * struct uic_command - UIC command structure
+ * @command: UIC command
+ * @argument1: UIC command argument 1
+ * @argument2: UIC command argument 2
+ * @argument3: UIC command argument 3
+ * @cmd_active: Indicate if UIC command is outstanding
+ * @result: UIC command result
+ */
+struct uic_command {
+	u32 command;
+	u32 argument1;
+	u32 argument2;
+	u32 argument3;
+	int cmd_active;
+	int result;
+};
+
+/**
+ * struct ufs_hba - per adapter private structure
+ * @mmio_base: UFSHCI base register address
+ * @ucdl_base_addr: UFS Command Descriptor base address
+ * @utrdl_base_addr: UTP Transfer Request Descriptor base address
+ * @utmrdl_base_addr: UTP Task Management Descriptor base address
+ * @ucdl_dma_addr: UFS Command Descriptor DMA address
+ * @utrdl_dma_addr: UTRDL DMA address
+ * @utmrdl_dma_addr: UTMRDL DMA address
+ * @host: Scsi_Host instance of the driver
+ * @pdev: PCI device handle
+ * @lrb: local reference block
+ * @outstanding_tasks: Bits representing outstanding task requests
+ * @outstanding_reqs: Bits representing outstanding transfer requests
+ * @capabilities: UFS Controller Capabilities
+ * @nutrs: Transfer Request Queue depth supported by controller
+ * @nutmrs: Task Management Queue depth supported by controller
+ * @active_uic_cmd: handle of active UIC command
+ * @ufshcd_tm_wait_queue: wait queue for task management
+ * @tm_condition: condition variable for task management
+ * @ufshcd_state: UFSHCD states
+ * @int_enable_mask: Interrupt Mask Bits
+ * @uic_workq: Work queue for UIC completion handling
+ * @feh_workq: Work queue for fatal controller error handling
+ * @errors: HBA errors
+ */
+struct ufs_hba {
+	void __iomem *mmio_base;
+
+	/* Virtual memory reference */
+	struct utp_transfer_cmd_desc *ucdl_base_addr;
+	struct utp_transfer_req_desc *utrdl_base_addr;
+	struct utp_task_req_desc *utmrdl_base_addr;
+
+	/* DMA memory reference */
+	dma_addr_t ucdl_dma_addr;
+	dma_addr_t utrdl_dma_addr;
+	dma_addr_t utmrdl_dma_addr;
+
+	struct Scsi_Host *host;
+	struct pci_dev *pdev;
+
+	struct ufshcd_lrb *lrb;
+
+	unsigned long outstanding_tasks;
+	unsigned long outstanding_reqs;
+
+	u32 capabilities;
+	int nutrs;
+	int nutmrs;
+	u32 ufs_version;
+
+	struct uic_command active_uic_cmd;
+	wait_queue_head_t ufshcd_tm_wait_queue;
+	unsigned long tm_condition;
+
+	u32 ufshcd_state;
+	u32 int_enable_mask;
+
+	/* Work Queues */
+	struct work_struct uic_workq;
+	struct work_struct feh_workq;
+
+	/* HBA Errors */
+	u32 errors;
+};
+
+/**
+ * struct ufshcd_lrb - local reference block
+ * @utr_descriptor_ptr: UTRD address of the command
+ * @ucd_cmd_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
+ * @sense_buffer: pointer to sense buffer address of the SCSI command
+ * @sense_bufflen: Length of the sense buffer
+ * @scsi_status: SCSI status of the command
+ * @command_type: SCSI, UFS, Query.
+ * @task_tag: Task tag of the command
+ * @lun: LUN of the command
+ */
+struct ufshcd_lrb {
+	struct utp_transfer_req_desc *utr_descriptor_ptr;
+	struct utp_upiu_cmd *ucd_cmd_ptr;
+	struct utp_upiu_rsp *ucd_rsp_ptr;
+	struct ufshcd_sg_entry *ucd_prdt_ptr;
+
+	struct scsi_cmnd *cmd;
+	u8 *sense_buffer;
+	unsigned int sense_bufflen;
+	int scsi_status;
+
+	int command_type;
+	int task_tag;
+	unsigned int lun;
+};
+
+/**
+ * ufshcd_get_ufs_version - Get the UFS version supported by the HBA
+ * @hba - Pointer to adapter instance
+ *
+ * Returns UFSHCI version supported by the controller
+ */
+static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
+{
+	return readl(hba->mmio_base + REG_UFS_VERSION);
+}
+
+/**
+ * ufshcd_is_device_present - Check if any device connected to
+ *			      the host controller
+ * @reg_hcs - host controller status register value
+ *
+ * Returns 0 if device present, non-zero if no device detected
+ */
+static inline int ufshcd_is_device_present(u32 reg_hcs)
+{
+	return (DEVICE_PRESENT & reg_hcs) ? 0 : -1;
+}
+
+/**
+ * ufshcd_get_tr_ocs - Get the UTRD Overall Command Status
+ * @lrb: pointer to local command reference block
+ *
+ * This function is used to get the OCS field from UTRD
+ * Returns the OCS field in the UTRD
+ */
+static inline int ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp)
+{
+	return lrbp->utr_descriptor_ptr->header.dword_2 & MASK_OCS;
+}
+
+/**
+ * ufshcd_get_tmr_ocs - Get the UTMRD Overall Command Status
+ * @task_req_descp: pointer to utp_task_req_desc structure
+ *
+ * This function is used to get the OCS field from UTMRD
+ * Returns the OCS field in the UTMRD
+ */
+static inline int
+ufshcd_get_tmr_ocs(struct utp_task_req_desc *task_req_descp)
+{
+	return task_req_descp->header.dword_2 & MASK_OCS;
+}
+
+/**
+ * ufshcd_get_tm_free_slot - get a free slot for task management request
+ * @hba: per adapter instance
+ *
+ * Returns maximum number of task management request slots in case of
+ * task management queue full or returns the free slot number
+ */
+static inline int ufshcd_get_tm_free_slot(struct ufs_hba *hba)
+{
+	return find_first_zero_bit(&hba->outstanding_tasks, hba->nutmrs);
+}
+
+/**
+ * ufshcd_utrl_clear - Clear a bit in UTRLCLR register
+ * @hba: per adapter instance
+ * @pos: position of the bit to be cleared
+ */
+static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
+{
+	writel(~(1 << pos),
+		(hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
+}
+
+/**
+ * ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY
+ * @reg: Register value of host controller status
+ *
+ * Returns integer, 0 on Success and positive value if failed
+ */
+static inline int ufshcd_get_lists_status(u32 reg)
+{
+	/*
+	 * The mask 0xFF is for the following HCS register bits
+	 * Bit		Description
+	 *  0		Device Present
+	 *  1		UTRLRDY
+	 *  2		UTMRLRDY
+	 *  3		UCRDY
+	 *  4		HEI
+	 *  5		DEI
+	 * 6-7		reserved
+	 */
+	return (((reg) & (0xFF)) >> 1) ^ (0x07);
+}
+
+/**
+ * ufshcd_get_uic_cmd_result - Get the UIC command result
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets the result of UIC command completion
+ * Returns 0 on success, non zero value on error
+ */
+static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
+{
+	return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) &
+	       MASK_UIC_COMMAND_RESULT;
+}
+
+/**
+ * ufshcd_free_hba_memory - Free allocated memory for LRB, request
+ *			    and task lists
+ * @hba: Pointer to adapter instance
+ */
+static inline void ufshcd_free_hba_memory(struct ufs_hba *hba)
+{
+	size_t utmrdl_size, utrdl_size, ucdl_size;
+
+	kfree(hba->lrb);
+
+	if (hba->utmrdl_base_addr) {
+		utmrdl_size = sizeof(struct utp_task_req_desc) * hba->nutmrs;
+		dma_free_coherent(&hba->pdev->dev, utmrdl_size,
+				  hba->utmrdl_base_addr, hba->utmrdl_dma_addr);
+	}
+
+	if (hba->utrdl_base_addr) {
+		utrdl_size =
+		(sizeof(struct utp_transfer_req_desc) * hba->nutrs);
+		dma_free_coherent(&hba->pdev->dev, utrdl_size,
+				  hba->utrdl_base_addr, hba->utrdl_dma_addr);
+	}
+
+	if (hba->ucdl_base_addr) {
+		ucdl_size =
+		(sizeof(struct utp_transfer_cmd_desc) * hba->nutrs);
+		dma_free_coherent(&hba->pdev->dev, ucdl_size,
+				  hba->ucdl_base_addr, hba->ucdl_dma_addr);
+	}
+}
+
+/**
+ * ufshcd_is_valid_req_rsp - checks if controller TR response is valid
+ * @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)
+{
+	return ((be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24) ==
+		 UPIU_TRANSACTION_RESPONSE) ? 0 : DID_ERROR << 16;
+}
+
+/**
+ * ufshcd_get_rsp_upiu_result - Get the result from response UPIU
+ * @ucd_rsp_ptr: pointer to response UPIU
+ *
+ * This function gets the response status and scsi_status from response UPIU
+ * Returns the response result code.
+ */
+static inline int
+ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr)
+{
+	return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT;
+}
+
+/**
+ * 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
+ *		aggregation, #define INT_AGGR_COUNTER_THRESHOLD_VALUE and
+ *		INT_AGGR_TIMEOUT_VALUE are used.
+ * @hba: per adapter instance
+ * @option: Interrupt aggregation option
+ */
+static inline void
+ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
+{
+	switch (option) {
+	case INT_AGGR_RESET:
+		writel((INT_AGGR_ENABLE |
+			INT_AGGR_COUNTER_AND_TIMER_RESET),
+			(hba->mmio_base +
+			 REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+		break;
+	case INT_AGGR_CONFIG:
+		writel((INT_AGGR_ENABLE |
+			INT_AGGR_PARAM_WRITE |
+			INT_AGGR_COUNTER_THRESHOLD_VALUE |
+			INT_AGGR_TIMEOUT_VALUE),
+			(hba->mmio_base +
+			 REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+		break;
+	}
+}
+
+/**
+ * ufshcd_enable_run_stop_reg - Enable run-stop registers,
+ *			When run-stop registers are set to 1, it indicates the
+ *			host controller that it can process the requests
+ * @hba: per adapter instance
+ */
+static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
+{
+	writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
+	       (hba->mmio_base +
+		REG_UTP_TASK_REQ_LIST_RUN_STOP));
+	writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
+	       (hba->mmio_base +
+		REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
+}
+
+/**
+ * ufshcd_hba_stop - Send controller to reset state
+ * @hba: per adapter instance
+ */
+static inline void ufshcd_hba_stop(struct ufs_hba *hba)
+{
+	writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
+}
+
+/**
+ * ufshcd_hba_start - Start controller initialization sequence
+ * @hba: per adapter instance
+ */
+static inline void ufshcd_hba_start(struct ufs_hba *hba)
+{
+	writel(CONTROLLER_ENABLE , (hba->mmio_base + REG_CONTROLLER_ENABLE));
+}
+
+/**
+ * ufshcd_is_hba_active - Get controller state
+ * @hba: per adapter instance
+ *
+ * Returns zero if controller is active, 1 otherwise
+ */
+static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
+{
+	return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
+}
+
+/**
+ * ufshcd_send_command - Send SCSI or device management commands
+ * @hba: per adapter instance
+ * @task_tag: Task tag of the command
+ */
+static inline
+void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
+{
+	__set_bit(task_tag, &hba->outstanding_reqs);
+	writel((1 << task_tag),
+	       (hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL));
+}
+
+/**
+ * ufshcd_copy_sense_data - Copy sense data in case of check condition
+ * @lrb - pointer to local reference block
+ */
+static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
+{
+	int len;
+	if (lrbp->sense_buffer) {
+		len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len);
+		memcpy(lrbp->sense_buffer,
+			lrbp->ucd_rsp_ptr->sense_data,
+			min_t(int, len, SCSI_SENSE_BUFFERSIZE));
+	}
+}
+
+/**
+ * ufshcd_hba_capabilities - Read controller capabilities
+ * @hba: per adapter instance
+ */
+static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
+{
+	hba->capabilities =
+		readl(hba->mmio_base + REG_CONTROLLER_CAPABILITIES);
+
+	/* nutrs and nutmrs are 0 based values */
+	hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1;
+	hba->nutmrs =
+	((hba->capabilities & MASK_TASK_MANAGEMENT_REQUEST_SLOTS) >> 16) + 1;
+}
+
+/**
+ * ufshcd_send_uic_command - Send UIC commands to unipro layers
+ * @hba: per adapter instance
+ * @uic_command: UIC command
+ */
+static inline void
+ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
+{
+	/* Write Args */
+	writel(uic_cmnd->argument1,
+	      (hba->mmio_base + REG_UIC_COMMAND_ARG_1));
+	writel(uic_cmnd->argument2,
+	      (hba->mmio_base + REG_UIC_COMMAND_ARG_2));
+	writel(uic_cmnd->argument3,
+	      (hba->mmio_base + REG_UIC_COMMAND_ARG_3));
+
+	/* Write UIC Cmd */
+	writel((uic_cmnd->command & COMMAND_OPCODE_MASK),
+	       (hba->mmio_base + REG_UIC_COMMAND));
+}
+
+/**
+ * ufshcd_map_sg - Map scatter-gather list to prdt
+ * @lrbp - pointer to local reference block
+ *
+ * Returns 0 in case of success, non-zero value in case of failure
+ */
+static int ufshcd_map_sg(struct ufshcd_lrb *lrbp)
+{
+	struct ufshcd_sg_entry *prd_table;
+	struct scatterlist *sg;
+	struct scsi_cmnd *cmd;
+	int sg_segments;
+	int i;
+
+	cmd = lrbp->cmd;
+	sg_segments = scsi_dma_map(cmd);
+	if (sg_segments < 0)
+		return sg_segments;
+
+	if (sg_segments) {
+		lrbp->utr_descriptor_ptr->prd_table_length =
+					cpu_to_le16((u16) (sg_segments));
+
+		prd_table = (struct ufshcd_sg_entry *)lrbp->ucd_prdt_ptr;
+
+		scsi_for_each_sg(cmd, sg, sg_segments, i) {
+			prd_table[i].size  =
+				cpu_to_le32(((u32) sg_dma_len(sg))-1);
+			prd_table[i].base_addr =
+				cpu_to_le32(lower_32_bits(sg->dma_address));
+			prd_table[i].upper_addr =
+				cpu_to_le32(upper_32_bits(sg->dma_address));
+		}
+	} else {
+		lrbp->utr_descriptor_ptr->prd_table_length = 0;
+	}
+
+	return 0;
+}
+
+/**
+ * ufshcd_int_config - enable/disable interrupts
+ * @hba: per adapter instance
+ * @option: interrupt option
+ */
+static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
+{
+	switch (option) {
+	case UFSHCD_INT_ENABLE:
+		writel(hba->int_enable_mask,
+		      (hba->mmio_base + REG_INTERRUPT_ENABLE));
+		break;
+	case UFSHCD_INT_DISABLE:
+		if (hba->ufs_version == UFSHCI_VERSION_10)
+			writel(INTERRUPT_DISABLE_MASK_10,
+			      (hba->mmio_base + REG_INTERRUPT_ENABLE));
+		else
+			writel(INTERRUPT_DISABLE_MASK_11,
+			       (hba->mmio_base + REG_INTERRUPT_ENABLE));
+		break;
+	}
+}
+
+/**
+ * ufshcd_compose_upiu - form UFS Protocol Information Unit(UPIU)
+ * @lrb - pointer to local reference block
+ */
+static void ufshcd_compose_upiu(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;
+
+	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;
+		} else {
+			data_direction = UTP_NO_DATA_TRANSFER;
+			upiu_flags = UPIU_CMD_FLAGS_NONE;
+		}
+
+		/* 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->transfersize);
+
+		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 */
+		break;
+	case UTP_CMD_TYPE_UFS:
+		/* For UFS native command implementation */
+		break;
+	} /* end of switch */
+}
+
+/**
+ * ufshcd_queuecommand - main entry point for SCSI requests
+ * @cmd: command from SCSI Midlayer
+ * @done: call back function
+ *
+ * Returns 0 for success, non-zero in case of failure
+ */
+static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
+{
+	struct ufshcd_lrb *lrbp;
+	struct ufs_hba *hba;
+	unsigned long flags;
+	int tag;
+	int err = 0;
+
+	hba = shost_priv(host);
+
+	tag = cmd->request->tag;
+
+	if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
+		err = SCSI_MLQUEUE_HOST_BUSY;
+		goto out;
+	}
+
+	lrbp = &hba->lrb[tag];
+
+	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->command_type = UTP_CMD_TYPE_SCSI;
+
+	/* form UPIU before issuing the command */
+	ufshcd_compose_upiu(lrbp);
+	err = ufshcd_map_sg(lrbp);
+	if (err)
+		goto out;
+
+	/* issue command to the controller */
+	spin_lock_irqsave(hba->host->host_lock, flags);
+	ufshcd_send_command(hba, tag);
+	spin_unlock_irqrestore(hba->host->host_lock, flags);
+out:
+	return err;
+}
+
+/**
+ * ufshcd_memory_alloc - allocate memory for host memory space data structures
+ * @hba: per adapter instance
+ *
+ * 1. Allocate DMA memory for Command Descriptor array
+ *	Each command descriptor consist of Command UPIU, Response UPIU and PRDT
+ * 2. Allocate DMA memory for UTP Transfer Request Descriptor List (UTRDL).
+ * 3. Allocate DMA memory for UTP Task Management Request Descriptor List
+ *	(UTMRDL)
+ * 4. Allocate memory for local reference block(lrb).
+ *
+ * Returns 0 for success, non-zero in case of failure
+ */
+static int ufshcd_memory_alloc(struct ufs_hba *hba)
+{
+	size_t utmrdl_size, utrdl_size, ucdl_size;
+
+	/* Allocate memory for UTP command descriptors */
+	ucdl_size = (sizeof(struct utp_transfer_cmd_desc) * hba->nutrs);
+	hba->ucdl_base_addr = dma_alloc_coherent(&hba->pdev->dev,
+						 ucdl_size,
+						 &hba->ucdl_dma_addr,
+						 GFP_KERNEL);
+
+	/*
+	 * UFSHCI requires UTP command descriptor to be 128 byte aligned.
+	 * make sure hba->ucdl_dma_addr is aligned to PAGE_SIZE
+	 * if hba->ucdl_dma_addr is aligned to PAGE_SIZE, then it will
+	 * be aligned to 128 bytes as well
+	 */
+	if (!hba->ucdl_base_addr ||
+	    WARN_ON(hba->ucdl_dma_addr & (PAGE_SIZE - 1))) {
+		dev_err(&hba->pdev->dev,
+			"Command Descriptor Memory allocation failed\n");
+		goto out;
+	}
+
+	/*
+	 * Allocate memory for UTP Transfer descriptors
+	 * UFSHCI requires 1024 byte alignment of UTRD
+	 */
+	utrdl_size = (sizeof(struct utp_transfer_req_desc) * hba->nutrs);
+	hba->utrdl_base_addr = dma_alloc_coherent(&hba->pdev->dev,
+						  utrdl_size,
+						  &hba->utrdl_dma_addr,
+						  GFP_KERNEL);
+	if (!hba->utrdl_base_addr ||
+	    WARN_ON(hba->utrdl_dma_addr & (PAGE_SIZE - 1))) {
+		dev_err(&hba->pdev->dev,
+			"Transfer Descriptor Memory allocation failed\n");
+		goto out;
+	}
+
+	/*
+	 * Allocate memory for UTP Task Management descriptors
+	 * UFSHCI requires 1024 byte alignment of UTMRD
+	 */
+	utmrdl_size = sizeof(struct utp_task_req_desc) * hba->nutmrs;
+	hba->utmrdl_base_addr = dma_alloc_coherent(&hba->pdev->dev,
+						   utmrdl_size,
+						   &hba->utmrdl_dma_addr,
+						   GFP_KERNEL);
+	if (!hba->utmrdl_base_addr ||
+	    WARN_ON(hba->utmrdl_dma_addr & (PAGE_SIZE - 1))) {
+		dev_err(&hba->pdev->dev,
+		"Task Management Descriptor Memory allocation failed\n");
+		goto out;
+	}
+
+	/* Allocate memory for local reference block */
+	hba->lrb = kcalloc(hba->nutrs, sizeof(struct ufshcd_lrb), GFP_KERNEL);
+	if (!hba->lrb) {
+		dev_err(&hba->pdev->dev, "LRB Memory allocation failed\n");
+		goto out;
+	}
+	return 0;
+out:
+	ufshcd_free_hba_memory(hba);
+	return -ENOMEM;
+}
+
+/**
+ * ufshcd_host_memory_configure - configure local reference block with
+ *				memory offsets
+ * @hba: per adapter instance
+ *
+ * Configure Host memory space
+ * 1. Update Corresponding UTRD.UCDBA and UTRD.UCDBAU with UCD DMA
+ * address.
+ * 2. Update each UTRD with Response UPIU offset, Response UPIU length
+ * and PRDT offset.
+ * 3. Save the corresponding addresses of UTRD, UCD.CMD, UCD.RSP and UCD.PRDT
+ * into local reference block.
+ */
+static void ufshcd_host_memory_configure(struct ufs_hba *hba)
+{
+	struct utp_transfer_cmd_desc *cmd_descp;
+	struct utp_transfer_req_desc *utrdlp;
+	dma_addr_t cmd_desc_dma_addr;
+	dma_addr_t cmd_desc_element_addr;
+	u16 response_offset;
+	u16 prdt_offset;
+	int cmd_desc_size;
+	int i;
+
+	utrdlp = hba->utrdl_base_addr;
+	cmd_descp = hba->ucdl_base_addr;
+
+	response_offset =
+		offsetof(struct utp_transfer_cmd_desc, response_upiu);
+	prdt_offset =
+		offsetof(struct utp_transfer_cmd_desc, prd_table);
+
+	cmd_desc_size = sizeof(struct utp_transfer_cmd_desc);
+	cmd_desc_dma_addr = hba->ucdl_dma_addr;
+
+	for (i = 0; i < hba->nutrs; i++) {
+		/* Configure UTRD with command descriptor base address */
+		cmd_desc_element_addr =
+				(cmd_desc_dma_addr + (cmd_desc_size * i));
+		utrdlp[i].command_desc_base_addr_lo =
+				cpu_to_le32(lower_32_bits(cmd_desc_element_addr));
+		utrdlp[i].command_desc_base_addr_hi =
+				cpu_to_le32(upper_32_bits(cmd_desc_element_addr));
+
+		/* Response upiu and prdt offset should be in double words */
+		utrdlp[i].response_upiu_offset =
+				cpu_to_le16((response_offset >> 2));
+		utrdlp[i].prd_table_offset =
+				cpu_to_le16((prdt_offset >> 2));
+		utrdlp[i].response_upiu_length =
+				cpu_to_le16(ALIGNED_UPIU_SIZE);
+
+		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_rsp_ptr =
+			(struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
+		hba->lrb[i].ucd_prdt_ptr =
+			(struct ufshcd_sg_entry *)cmd_descp[i].prd_table;
+	}
+}
+
+/**
+ * ufshcd_dme_link_startup - Notify Unipro to perform link startup
+ * @hba: per adapter instance
+ *
+ * UIC_CMD_DME_LINK_STARTUP command must be issued to Unipro layer,
+ * in order to initialize the Unipro link startup procedure.
+ * Once the Unipro links are up, the device connected to the controller
+ * is detected.
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_dme_link_startup(struct ufs_hba *hba)
+{
+	struct uic_command *uic_cmd;
+	unsigned long flags;
+
+	/* check if controller is ready to accept UIC commands */
+	if (((readl(hba->mmio_base + REG_CONTROLLER_STATUS)) &
+	    UIC_COMMAND_READY) == 0x0) {
+		dev_err(&hba->pdev->dev,
+			"Controller not ready"
+			" to accept UIC commands\n");
+		return -EIO;
+	}
+
+	spin_lock_irqsave(hba->host->host_lock, flags);
+
+	/* form UIC command */
+	uic_cmd = &hba->active_uic_cmd;
+	uic_cmd->command = UIC_CMD_DME_LINK_STARTUP;
+	uic_cmd->argument1 = 0;
+	uic_cmd->argument2 = 0;
+	uic_cmd->argument3 = 0;
+
+	/* enable UIC related interrupts */
+	hba->int_enable_mask |= UIC_COMMAND_COMPL;
+	ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+
+	/* sending UIC commands to controller */
+	ufshcd_send_uic_command(hba, uic_cmd);
+	spin_unlock_irqrestore(hba->host->host_lock, flags);
+	return 0;
+}
+
+/**
+ * ufshcd_make_hba_operational - Make UFS controller operational
+ * @hba: per adapter instance
+ *
+ * To bring UFS host controller to operational state,
+ * 1. Check if device is present
+ * 2. Configure run-stop-registers
+ * 3. Enable required interrupts
+ * 4. Configure interrupt aggregation
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_make_hba_operational(struct ufs_hba *hba)
+{
+	int err = 0;
+	u32 reg;
+
+	/* check if device present */
+	reg = readl((hba->mmio_base + REG_CONTROLLER_STATUS));
+	if (ufshcd_is_device_present(reg)) {
+		dev_err(&hba->pdev->dev, "cc: Device not present\n");
+		err = -ENXIO;
+		goto out;
+	}
+
+	/*
+	 * UCRDY, UTMRLDY and UTRLRDY bits must be 1
+	 * DEI, HEI bits must be 0
+	 */
+	if (!(ufshcd_get_lists_status(reg))) {
+		ufshcd_enable_run_stop_reg(hba);
+	} else {
+		dev_err(&hba->pdev->dev,
+			"Host controller not ready to process requests");
+		err = -EIO;
+		goto out;
+	}
+
+	/* Enable required interrupts */
+	hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL |
+				 UIC_ERROR |
+				 UTP_TASK_REQ_COMPL |
+				 DEVICE_FATAL_ERROR |
+				 CONTROLLER_FATAL_ERROR |
+				 SYSTEM_BUS_FATAL_ERROR);
+	ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+
+	/* Configure interrupt aggregation */
+	ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
+
+	if (hba->ufshcd_state == UFSHCD_STATE_RESET)
+		scsi_unblock_requests(hba->host);
+
+	hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
+	scsi_scan_host(hba->host);
+out:
+	return err;
+}
+
+/**
+ * ufshcd_hba_enable - initialize the controller
+ * @hba: per adapter instance
+ *
+ * The controller resets itself and controller firmware initialization
+ * sequence kicks off. When controller is ready it will set
+ * the Host Controller Enable bit to 1.
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_hba_enable(struct ufs_hba *hba)
+{
+	int retry;
+
+	/*
+	 * msleep of 1 and 5 used in this function might result in msleep(20),
+	 * but it was necessary to send the UFS FPGA to reset mode during
+	 * development and testing of this driver. msleep can be changed to
+	 * mdelay and retry count can be reduced based on the controller.
+	 */
+	if (!ufshcd_is_hba_active(hba)) {
+
+		/* change controller state to "reset state" */
+		ufshcd_hba_stop(hba);
+
+		/*
+		 * This delay is based on the testing done with UFS host
+		 * controller FPGA. The delay can be changed based on the
+		 * host controller used.
+		 */
+		msleep(5);
+	}
+
+	/* start controller initialization sequence */
+	ufshcd_hba_start(hba);
+
+	/*
+	 * To initialize a UFS host controller HCE bit must be set to 1.
+	 * During initialization the HCE bit value changes from 1->0->1.
+	 * When the host controller completes initialization sequence
+	 * it sets the value of HCE bit to 1. The same HCE bit is read back
+	 * to check if the controller has completed initialization sequence.
+	 * So without this delay the value HCE = 1, set in the previous
+	 * instruction might be read back.
+	 * This delay can be changed based on the controller.
+	 */
+	msleep(1);
+
+	/* wait for the host controller to complete initialization */
+	retry = 10;
+	while (ufshcd_is_hba_active(hba)) {
+		if (retry) {
+			retry--;
+		} else {
+			dev_err(&hba->pdev->dev,
+				"Controller enable failed\n");
+			return -EIO;
+		}
+		msleep(5);
+	}
+	return 0;
+}
+
+/**
+ * ufshcd_initialize_hba - start the initialization process
+ * @hba: per adapter instance
+ *
+ * 1. Enable the controller via ufshcd_hba_enable.
+ * 2. Program the Transfer Request List Address with the starting address of
+ * UTRDL.
+ * 3. Program the Task Management Request List Address with starting address
+ * of UTMRDL.
+ *
+ * Returns 0 on success, non-zero value on failure.
+ */
+static int ufshcd_initialize_hba(struct ufs_hba *hba)
+{
+	if (ufshcd_hba_enable(hba))
+		return -EIO;
+
+	/* Configure UTRL and UTMRL base address registers */
+	writel(hba->utrdl_dma_addr,
+	       (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L));
+	writel(lower_32_bits(hba->utrdl_dma_addr),
+	       (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_H));
+	writel(hba->utmrdl_dma_addr,
+	       (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_L));
+	writel(upper_32_bits(hba->utmrdl_dma_addr),
+	       (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_H));
+
+	/* Initialize unipro link startup procedure */
+	return ufshcd_dme_link_startup(hba);
+}
+
+/**
+ * ufshcd_do_reset - reset the host controller
+ * @hba: per adapter instance
+ *
+ * Returns SUCCESS/FAILED
+ */
+static int ufshcd_do_reset(struct ufs_hba *hba)
+{
+	struct ufshcd_lrb *lrbp;
+	unsigned long flags;
+	int tag;
+
+	/* block commands from midlayer */
+	scsi_block_requests(hba->host);
+
+	spin_lock_irqsave(hba->host->host_lock, flags);
+	hba->ufshcd_state = UFSHCD_STATE_RESET;
+
+	/* send controller to reset state */
+	ufshcd_hba_stop(hba);
+	spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+	/* abort outstanding commands */
+	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;
+		}
+	}
+
+	/* clear outstanding request/task bit maps */
+	hba->outstanding_reqs = 0;
+	hba->outstanding_tasks = 0;
+
+	/* start the initialization process */
+	if (ufshcd_initialize_hba(hba)) {
+		dev_err(&hba->pdev->dev,
+			"Reset: Controller initialization failed\n");
+		return FAILED;
+	}
+	return SUCCESS;
+}
+
+/**
+ * ufshcd_slave_alloc - handle initial SCSI device configurations
+ * @sdev: pointer to SCSI device
+ *
+ * Returns success
+ */
+static int ufshcd_slave_alloc(struct scsi_device *sdev)
+{
+	struct ufs_hba *hba;
+
+	hba = shost_priv(sdev->host);
+	sdev->tagged_supported = 1;
+
+	/* Mode sense(6) is not supported by UFS, so use Mode sense(10) */
+	sdev->use_10_for_ms = 1;
+	scsi_set_tag_type(sdev, MSG_SIMPLE_TAG);
+
+	/*
+	 * Inform SCSI Midlayer that the LUN queue depth is same as the
+	 * controller queue depth. If a LUN queue depth is less than the
+	 * controller queue depth and if the LUN reports
+	 * SAM_STAT_TASK_SET_FULL, the LUN queue depth will be adjusted
+	 * with scsi_adjust_queue_depth.
+	 */
+	scsi_activate_tcq(sdev, hba->nutrs);
+	return 0;
+}
+
+/**
+ * ufshcd_slave_destroy - remove SCSI device configurations
+ * @sdev: pointer to SCSI device
+ */
+static void ufshcd_slave_destroy(struct scsi_device *sdev)
+{
+	struct ufs_hba *hba;
+
+	hba = shost_priv(sdev->host);
+	scsi_deactivate_tcq(sdev, hba->nutrs);
+}
+
+/**
+ * ufshcd_task_req_compl - handle task management request completion
+ * @hba: per adapter instance
+ * @index: index of the completed request
+ *
+ * Returns SUCCESS/FAILED
+ */
+static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index)
+{
+	struct utp_task_req_desc *task_req_descp;
+	struct utp_upiu_task_rsp *task_rsp_upiup;
+	unsigned long flags;
+	int ocs_value;
+	int task_result;
+
+	spin_lock_irqsave(hba->host->host_lock, flags);
+
+	/* Clear completed tasks from outstanding_tasks */
+	__clear_bit(index, &hba->outstanding_tasks);
+
+	task_req_descp = hba->utmrdl_base_addr;
+	ocs_value = ufshcd_get_tmr_ocs(&task_req_descp[index]);
+
+	if (ocs_value == OCS_SUCCESS) {
+		task_rsp_upiup = (struct utp_upiu_task_rsp *)
+				task_req_descp[index].task_rsp_upiu;
+		task_result = be32_to_cpu(task_rsp_upiup->header.dword_1);
+		task_result = ((task_result & MASK_TASK_RESPONSE) >> 8);
+
+		if (task_result != UPIU_TASK_MANAGEMENT_FUNC_COMPL ||
+		    task_result != UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED)
+			task_result = FAILED;
+	} else {
+		task_result = FAILED;
+		dev_err(&hba->pdev->dev,
+			"trc: Invalid ocs = %x\n", ocs_value);
+	}
+	spin_unlock_irqrestore(hba->host->host_lock, flags);
+	return task_result;
+}
+
+/**
+ * ufshcd_adjust_lun_qdepth - Update LUN queue depth if device responds with
+ *			      SAM_STAT_TASK_SET_FULL SCSI command status.
+ * @cmd: pointer to SCSI command
+ */
+static void ufshcd_adjust_lun_qdepth(struct scsi_cmnd *cmd)
+{
+	struct ufs_hba *hba;
+	int i;
+	int lun_qdepth = 0;
+
+	hba = shost_priv(cmd->device->host);
+
+	/*
+	 * LUN queue depth can be obtained by counting outstanding commands
+	 * on the LUN.
+	 */
+	for (i = 0; i < hba->nutrs; i++) {
+		if (test_bit(i, &hba->outstanding_reqs)) {
+
+			/*
+			 * Check if the outstanding command belongs
+			 * to the LUN which reported SAM_STAT_TASK_SET_FULL.
+			 */
+			if (cmd->device->lun == hba->lrb[i].lun)
+				lun_qdepth++;
+		}
+	}
+
+	/*
+	 * LUN queue depth will be total outstanding commands, except the
+	 * command for which the LUN reported SAM_STAT_TASK_SET_FULL.
+	 */
+	scsi_adjust_queue_depth(cmd->device, MSG_SIMPLE_TAG, lun_qdepth - 1);
+}
+
+/**
+ * ufshcd_scsi_cmd_status - Update SCSI command result based on SCSI status
+ * @lrb: pointer to local reference block of completed command
+ * @scsi_status: SCSI command status
+ *
+ * Returns value base on SCSI command status
+ */
+static inline int
+ufshcd_scsi_cmd_status(struct ufshcd_lrb *lrbp, int scsi_status)
+{
+	int result = 0;
+
+	switch (scsi_status) {
+	case SAM_STAT_GOOD:
+		result |= DID_OK << 16 |
+			  COMMAND_COMPLETE << 8 |
+			  SAM_STAT_GOOD;
+		break;
+	case SAM_STAT_CHECK_CONDITION:
+		result |= DID_OK << 16 |
+			  COMMAND_COMPLETE << 8 |
+			  SAM_STAT_CHECK_CONDITION;
+		ufshcd_copy_sense_data(lrbp);
+		break;
+	case SAM_STAT_BUSY:
+		result |= SAM_STAT_BUSY;
+		break;
+	case SAM_STAT_TASK_SET_FULL:
+
+		/*
+		 * If a LUN reports SAM_STAT_TASK_SET_FULL, then the LUN queue
+		 * depth needs to be adjusted to the exact number of
+		 * outstanding commands the LUN can handle at any given time.
+		 */
+		ufshcd_adjust_lun_qdepth(lrbp->cmd);
+		result |= SAM_STAT_TASK_SET_FULL;
+		break;
+	case SAM_STAT_TASK_ABORTED:
+		result |= SAM_STAT_TASK_ABORTED;
+		break;
+	default:
+		result |= DID_ERROR << 16;
+		break;
+	} /* end of switch */
+
+	return result;
+}
+
+/**
+ * ufshcd_transfer_rsp_status - Get overall status of the response
+ * @hba: per adapter instance
+ * @lrb: pointer to local reference block of completed command
+ *
+ * Returns result of the command to notify SCSI midlayer
+ */
+static inline int
+ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+	int result = 0;
+	int scsi_status;
+	int ocs;
+
+	/* overall command status of utrd */
+	ocs = ufshcd_get_tr_ocs(lrbp);
+
+	switch (ocs) {
+	case OCS_SUCCESS:
+
+		/* check if the returned transfer response is valid */
+		result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
+		if (result) {
+			dev_err(&hba->pdev->dev,
+				"Invalid response = %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;
+		break;
+	case OCS_INVALID_CMD_TABLE_ATTR:
+	case OCS_INVALID_PRDT_ATTR:
+	case OCS_MISMATCH_DATA_BUF_SIZE:
+	case OCS_MISMATCH_RESP_UPIU_SIZE:
+	case OCS_PEER_COMM_FAILURE:
+	case OCS_FATAL_ERROR:
+	default:
+		result |= DID_ERROR << 16;
+		dev_err(&hba->pdev->dev,
+		"OCS error from controller = %x\n", ocs);
+		break;
+	} /* end of switch */
+
+	return result;
+}
+
+/**
+ * ufshcd_transfer_req_compl - handle SCSI and query command completion
+ * @hba: per adapter instance
+ */
+static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
+{
+	struct ufshcd_lrb *lrb;
+	unsigned long completed_reqs;
+	u32 tr_doorbell;
+	int result;
+	int index;
+
+	lrb = hba->lrb;
+	tr_doorbell =
+		readl(hba->mmio_base + 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)) {
+
+			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);
+
+				/* Mark completed command as NULL in LRB */
+				lrb[index].cmd = NULL;
+			}
+		} /* end of if */
+	} /* end of for */
+
+	/* clear corresponding bits of completed commands */
+	hba->outstanding_reqs ^= completed_reqs;
+
+	/* Reset interrupt aggregation counters */
+	ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
+}
+
+/**
+ * ufshcd_uic_cc_handler - handle UIC command completion
+ * @work: pointer to a work queue structure
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static void ufshcd_uic_cc_handler (struct work_struct *work)
+{
+	struct ufs_hba *hba;
+
+	hba = container_of(work, struct ufs_hba, uic_workq);
+
+	if ((hba->active_uic_cmd.command == UIC_CMD_DME_LINK_STARTUP) &&
+	    !(ufshcd_get_uic_cmd_result(hba))) {
+
+		if (ufshcd_make_hba_operational(hba))
+			dev_err(&hba->pdev->dev,
+				"cc: hba not operational state\n");
+		return;
+	}
+}
+
+/**
+ * ufshcd_fatal_err_handler - handle fatal errors
+ * @hba: per adapter instance
+ */
+static void ufshcd_fatal_err_handler(struct work_struct *work)
+{
+	struct ufs_hba *hba;
+	hba = container_of(work, struct ufs_hba, feh_workq);
+
+	/* check if reset is already in progress */
+	if (hba->ufshcd_state != UFSHCD_STATE_RESET)
+		ufshcd_do_reset(hba);
+}
+
+/**
+ * ufshcd_err_handler - Check for fatal errors
+ * @work: pointer to a work queue structure
+ */
+static void ufshcd_err_handler(struct ufs_hba *hba)
+{
+	u32 reg;
+
+	if (hba->errors & INT_FATAL_ERRORS)
+		goto fatal_eh;
+
+	if (hba->errors & UIC_ERROR) {
+
+		reg = readl(hba->mmio_base +
+			    REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
+		if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
+			goto fatal_eh;
+	}
+	return;
+fatal_eh:
+	hba->ufshcd_state = UFSHCD_STATE_ERROR;
+	schedule_work(&hba->feh_workq);
+}
+
+/**
+ * ufshcd_tmc_handler - handle task management function completion
+ * @hba: per adapter instance
+ */
+static void ufshcd_tmc_handler(struct ufs_hba *hba)
+{
+	u32 tm_doorbell;
+
+	tm_doorbell = readl(hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL);
+	hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks;
+	wake_up_interruptible(&hba->ufshcd_tm_wait_queue);
+}
+
+/**
+ * ufshcd_sl_intr - Interrupt service routine
+ * @hba: per adapter instance
+ * @intr_status: contains interrupts generated by the controller
+ */
+static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
+{
+	hba->errors = UFSHCD_ERROR_MASK & intr_status;
+	if (hba->errors)
+		ufshcd_err_handler(hba);
+
+	if (intr_status & UIC_COMMAND_COMPL)
+		schedule_work(&hba->uic_workq);
+
+	if (intr_status & UTP_TASK_REQ_COMPL)
+		ufshcd_tmc_handler(hba);
+
+	if (intr_status & UTP_TRANSFER_REQ_COMPL)
+		ufshcd_transfer_req_compl(hba);
+}
+
+/**
+ * ufshcd_intr - Main interrupt service routine
+ * @irq: irq number
+ * @__hba: pointer to adapter instance
+ *
+ * Returns IRQ_HANDLED - If interrupt is valid
+ *		IRQ_NONE - If invalid interrupt
+ */
+static irqreturn_t ufshcd_intr(int irq, void *__hba)
+{
+	u32 intr_status;
+	irqreturn_t retval = IRQ_NONE;
+	struct ufs_hba *hba = __hba;
+
+	spin_lock(hba->host->host_lock);
+	intr_status = readl(hba->mmio_base + REG_INTERRUPT_STATUS);
+
+	if (intr_status) {
+		ufshcd_sl_intr(hba, intr_status);
+
+		/* If UFSHCI 1.0 then clear interrupt status register */
+		if (hba->ufs_version == UFSHCI_VERSION_10)
+			writel(intr_status,
+			       (hba->mmio_base + REG_INTERRUPT_STATUS));
+		retval = IRQ_HANDLED;
+	}
+	spin_unlock(hba->host->host_lock);
+	return retval;
+}
+
+/**
+ * ufshcd_issue_tm_cmd - issues task management commands to controller
+ * @hba: per adapter instance
+ * @lrbp: pointer to local reference block
+ *
+ * Returns SUCCESS/FAILED
+ */
+static int
+ufshcd_issue_tm_cmd(struct ufs_hba *hba,
+		    struct ufshcd_lrb *lrbp,
+		    u8 tm_function)
+{
+	struct utp_task_req_desc *task_req_descp;
+	struct utp_upiu_task_req *task_req_upiup;
+	struct Scsi_Host *host;
+	unsigned long flags;
+	int free_slot = 0;
+	int err;
+
+	host = hba->host;
+
+	spin_lock_irqsave(host->host_lock, flags);
+
+	/* If task management queue is full */
+	free_slot = ufshcd_get_tm_free_slot(hba);
+	if (free_slot >= hba->nutmrs) {
+		spin_unlock_irqrestore(host->host_lock, flags);
+		dev_err(&hba->pdev->dev, "Task management queue full\n");
+		err = FAILED;
+		goto out;
+	}
+
+	task_req_descp = hba->utmrdl_base_addr;
+	task_req_descp += free_slot;
+
+	/* Configure task request descriptor */
+	task_req_descp->header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD);
+	task_req_descp->header.dword_2 =
+			cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+
+	/* Configure task request UPIU */
+	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));
+	task_req_upiup->header.dword_1 =
+	cpu_to_be32(UPIU_HEADER_DWORD(0, tm_function, 0, 0));
+
+	task_req_upiup->input_param1 = lrbp->lun;
+	task_req_upiup->input_param1 =
+		cpu_to_be32(task_req_upiup->input_param1);
+	task_req_upiup->input_param2 = lrbp->task_tag;
+	task_req_upiup->input_param2 =
+		cpu_to_be32(task_req_upiup->input_param2);
+
+	/* send command to the controller */
+	__set_bit(free_slot, &hba->outstanding_tasks);
+	writel((1 << free_slot),
+	       (hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL));
+
+	spin_unlock_irqrestore(host->host_lock, flags);
+
+	/* wait until the task management command is completed */
+	err =
+	wait_event_interruptible_timeout(hba->ufshcd_tm_wait_queue,
+					 (test_bit(free_slot,
+					 &hba->tm_condition) != 0),
+					 60 * HZ);
+	if (!err) {
+		dev_err(&hba->pdev->dev,
+			"Task management command timed-out\n");
+		err = FAILED;
+		goto out;
+	}
+	clear_bit(free_slot, &hba->tm_condition);
+	return ufshcd_task_req_compl(hba, free_slot);
+out:
+	return err;
+}
+
+/**
+ * ufshcd_device_reset - reset device and abort all the pending commands
+ * @cmd: SCSI command pointer
+ *
+ * Returns SUCCESS/FAILED
+ */
+static int ufshcd_device_reset(struct scsi_cmnd *cmd)
+{
+	struct Scsi_Host *host;
+	struct ufs_hba *hba;
+	unsigned int tag;
+	u32 pos;
+	int err;
+
+	host = cmd->device->host;
+	hba = shost_priv(host);
+	tag = cmd->request->tag;
+
+	err = ufshcd_issue_tm_cmd(hba, &hba->lrb[tag], UFS_LOGICAL_RESET);
+	if (err)
+		goto out;
+
+	for (pos = 0; pos < hba->nutrs; pos++) {
+		if (test_bit(pos, &hba->outstanding_reqs) &&
+		    (hba->lrb[tag].lun == hba->lrb[pos].lun)) {
+
+			/* clear the respective UTRLCLR register bit */
+			ufshcd_utrl_clear(hba, pos);
+
+			clear_bit(pos, &hba->outstanding_reqs);
+
+			if (hba->lrb[pos].cmd) {
+				scsi_dma_unmap(hba->lrb[pos].cmd);
+				hba->lrb[pos].cmd->result =
+						DID_ABORT << 16;
+				hba->lrb[pos].cmd->scsi_done(cmd);
+				hba->lrb[pos].cmd = NULL;
+			}
+		}
+	} /* end of for */
+out:
+	return err;
+}
+
+/**
+ * ufshcd_host_reset - Main reset function registered with scsi layer
+ * @cmd: SCSI command pointer
+ *
+ * Returns SUCCESS/FAILED
+ */
+static int ufshcd_host_reset(struct scsi_cmnd *cmd)
+{
+	struct ufs_hba *hba;
+
+	hba = shost_priv(cmd->device->host);
+
+	if (hba->ufshcd_state == UFSHCD_STATE_RESET)
+		return SUCCESS;
+
+	return (ufshcd_do_reset(hba) == SUCCESS) ? SUCCESS : FAILED;
+}
+
+/**
+ * ufshcd_abort - abort a specific command
+ * @cmd: SCSI command pointer
+ *
+ * Returns SUCCESS/FAILED
+ */
+static int ufshcd_abort(struct scsi_cmnd *cmd)
+{
+	struct Scsi_Host *host;
+	struct ufs_hba *hba;
+	unsigned long flags;
+	unsigned int tag;
+	int err;
+
+	host = cmd->device->host;
+	hba = shost_priv(host);
+	tag = cmd->request->tag;
+
+	spin_lock_irqsave(host->host_lock, flags);
+
+	/* check if command is still pending */
+	if (!(test_bit(tag, &hba->outstanding_reqs))) {
+		err = FAILED;
+		spin_unlock_irqrestore(host->host_lock, flags);
+		goto out;
+	}
+	spin_unlock_irqrestore(host->host_lock, flags);
+
+	err = ufshcd_issue_tm_cmd(hba, &hba->lrb[tag], UFS_ABORT_TASK);
+	if (err)
+		goto out;
+
+	scsi_dma_unmap(cmd);
+
+	spin_lock_irqsave(host->host_lock, flags);
+
+	/* clear the respective UTRLCLR register bit */
+	ufshcd_utrl_clear(hba, tag);
+
+	__clear_bit(tag, &hba->outstanding_reqs);
+	hba->lrb[tag].cmd = NULL;
+	spin_unlock_irqrestore(host->host_lock, flags);
+out:
+	return err;
+}
+
+static struct scsi_host_template ufshcd_driver_template = {
+	.module			= THIS_MODULE,
+	.name			= UFSHCD,
+	.proc_name		= UFSHCD,
+	.queuecommand		= ufshcd_queuecommand,
+	.slave_alloc		= ufshcd_slave_alloc,
+	.slave_destroy		= ufshcd_slave_destroy,
+	.eh_abort_handler	= ufshcd_abort,
+	.eh_device_reset_handler = ufshcd_device_reset,
+	.eh_host_reset_handler	= ufshcd_host_reset,
+	.this_id		= -1,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= UFSHCD_CMD_PER_LUN,
+	.can_queue		= UFSHCD_CAN_QUEUE,
+};
+
+/**
+ * ufshcd_shutdown - main function to put the controller in reset state
+ * @pdev: pointer to PCI device handle
+ */
+static void ufshcd_shutdown(struct pci_dev *pdev)
+{
+	ufshcd_hba_stop((struct ufs_hba *)pci_get_drvdata(pdev));
+}
+
+#ifdef CONFIG_PM
+/**
+ * ufshcd_suspend - suspend power management function
+ * @pdev: pointer to PCI device handle
+ * @state: power state
+ *
+ * Returns -ENOSYS
+ */
+static int ufshcd_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	/*
+	 * TODO:
+	 * 1. Block SCSI requests from SCSI midlayer
+	 * 2. Change the internal driver state to non operational
+	 * 3. Set UTRLRSR and UTMRLRSR bits to zero
+	 * 4. Wait until outstanding commands are completed
+	 * 5. Set HCE to zero to send the UFS host controller to reset state
+	 */
+
+	return -ENOSYS;
+}
+
+/**
+ * ufshcd_resume - resume power management function
+ * @pdev: pointer to PCI device handle
+ *
+ * Returns -ENOSYS
+ */
+static int ufshcd_resume(struct pci_dev *pdev)
+{
+	/*
+	 * TODO:
+	 * 1. Set HCE to 1, to start the UFS host controller
+	 * initialization process
+	 * 2. Set UTRLRSR and UTMRLRSR bits to 1
+	 * 3. Change the internal driver state to operational
+	 * 4. Unblock SCSI requests from SCSI midlayer
+	 */
+
+	return -ENOSYS;
+}
+#endif /* CONFIG_PM */
+
+/**
+ * ufshcd_hba_free - free allocated memory for
+ *			host memory space data structures
+ * @hba: per adapter instance
+ */
+static void ufshcd_hba_free(struct ufs_hba *hba)
+{
+	iounmap(hba->mmio_base);
+	ufshcd_free_hba_memory(hba);
+	pci_release_regions(hba->pdev);
+}
+
+/**
+ * ufshcd_remove - de-allocate PCI/SCSI host and host memory space
+ *		data structure memory
+ * @pdev - pointer to PCI handle
+ */
+static void ufshcd_remove(struct pci_dev *pdev)
+{
+	struct ufs_hba *hba = pci_get_drvdata(pdev);
+
+	/* disable interrupts */
+	ufshcd_int_config(hba, UFSHCD_INT_DISABLE);
+	free_irq(pdev->irq, hba);
+
+	ufshcd_hba_stop(hba);
+	ufshcd_hba_free(hba);
+
+	scsi_remove_host(hba->host);
+	scsi_host_put(hba->host);
+	pci_set_drvdata(pdev, NULL);
+	pci_clear_master(pdev);
+	pci_disable_device(pdev);
+}
+
+/**
+ * ufshcd_set_dma_mask - Set dma mask based on the controller
+ *			 addressing capability
+ * @pdev: PCI device structure
+ *
+ * Returns 0 for success, non-zero for failure
+ */
+static int ufshcd_set_dma_mask(struct ufs_hba *hba)
+{
+	int err;
+	u64 dma_mask;
+
+	/*
+	 * If controller supports 64 bit addressing mode, then set the DMA
+	 * mask to 64-bit, else set the DMA mask to 32-bit
+	 */
+	if (hba->capabilities & MASK_64_ADDRESSING_SUPPORT)
+		dma_mask = DMA_BIT_MASK(64);
+	else
+		dma_mask = DMA_BIT_MASK(32);
+
+	err = pci_set_dma_mask(hba->pdev, dma_mask);
+	if (err)
+		return err;
+
+	err = pci_set_consistent_dma_mask(hba->pdev, dma_mask);
+
+	return err;
+}
+
+/**
+ * ufshcd_probe - probe routine of the driver
+ * @pdev: pointer to PCI device handle
+ * @id: PCI device id
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int __devinit
+ufshcd_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct Scsi_Host *host;
+	struct ufs_hba *hba;
+	int err;
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "pci_enable_device failed\n");
+		goto out_error;
+	}
+
+	pci_set_master(pdev);
+
+	host = scsi_host_alloc(&ufshcd_driver_template,
+				sizeof(struct ufs_hba));
+	if (!host) {
+		dev_err(&pdev->dev, "scsi_host_alloc failed\n");
+		err = -ENOMEM;
+		goto out_disable;
+	}
+	hba = shost_priv(host);
+
+	err = pci_request_regions(pdev, UFSHCD);
+	if (err < 0) {
+		dev_err(&pdev->dev, "request regions failed\n");
+		goto out_disable;
+	}
+
+	hba->mmio_base = pci_ioremap_bar(pdev, 0);
+	if (!hba->mmio_base) {
+		dev_err(&pdev->dev, "memory map failed\n");
+		err = -ENOMEM;
+		goto out_release_regions;
+	}
+
+	hba->host = host;
+	hba->pdev = pdev;
+
+	/* Read capabilities registers */
+	ufshcd_hba_capabilities(hba);
+
+	/* Get UFS version supported by the controller */
+	hba->ufs_version = ufshcd_get_ufs_version(hba);
+
+	err = ufshcd_set_dma_mask(hba);
+	if (err) {
+		dev_err(&pdev->dev, "set dma mask failed\n");
+		goto out_iounmap;
+	}
+
+	/* Allocate memory for host memory space */
+	err = ufshcd_memory_alloc(hba);
+	if (err) {
+		dev_err(&pdev->dev, "Memory allocation failed\n");
+		goto out_iounmap;
+	}
+
+	/* Configure LRB */
+	ufshcd_host_memory_configure(hba);
+
+	host->can_queue = hba->nutrs;
+	host->cmd_per_lun = hba->nutrs;
+	host->max_id = UFSHCD_MAX_ID;
+	host->max_lun = UFSHCD_MAX_LUNS;
+	host->max_channel = UFSHCD_MAX_CHANNEL;
+	host->unique_id = host->host_no;
+	host->max_cmd_len = MAX_CDB_SIZE;
+
+	/* Initailize wait queue for task management */
+	init_waitqueue_head(&hba->ufshcd_tm_wait_queue);
+
+	/* Initialize work queues */
+	INIT_WORK(&hba->uic_workq, ufshcd_uic_cc_handler);
+	INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
+
+	/* IRQ registration */
+	err = request_irq(pdev->irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
+	if (err) {
+		dev_err(&pdev->dev, "request irq failed\n");
+		goto out_lrb_free;
+	}
+
+	/* Enable SCSI tag mapping */
+	err = scsi_init_shared_tag_map(host, host->can_queue);
+	if (err) {
+		dev_err(&pdev->dev, "init shared queue failed\n");
+		goto out_free_irq;
+	}
+
+	pci_set_drvdata(pdev, hba);
+
+	err = scsi_add_host(host, &pdev->dev);
+	if (err) {
+		dev_err(&pdev->dev, "scsi_add_host failed\n");
+		goto out_free_irq;
+	}
+
+	/* Initialization routine */
+	err = ufshcd_initialize_hba(hba);
+	if (err) {
+		dev_err(&pdev->dev, "Initialization failed\n");
+		goto out_free_irq;
+	}
+
+	return 0;
+
+out_free_irq:
+	free_irq(pdev->irq, hba);
+out_lrb_free:
+	ufshcd_free_hba_memory(hba);
+out_iounmap:
+	iounmap(hba->mmio_base);
+out_release_regions:
+	pci_release_regions(pdev);
+out_disable:
+	scsi_host_put(host);
+	pci_clear_master(pdev);
+	pci_disable_device(pdev);
+out_error:
+	return err;
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = {
+	{ PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ }	/* terminate list */
+};
+
+MODULE_DEVICE_TABLE(pci, ufshcd_pci_tbl);
+
+static struct pci_driver ufshcd_pci_driver = {
+	.name = UFSHCD,
+	.id_table = ufshcd_pci_tbl,
+	.probe = ufshcd_probe,
+	.remove = __devexit_p(ufshcd_remove),
+	.shutdown = ufshcd_shutdown,
+#ifdef CONFIG_PM
+	.suspend = ufshcd_suspend,
+	.resume = ufshcd_resume,
+#endif
+};
+
+/**
+ * ufshcd_init - Driver registration routine
+ */
+static int __init ufshcd_init(void)
+{
+	return pci_register_driver(&ufshcd_pci_driver);
+}
+module_init(ufshcd_init);
+
+/**
+ * ufshcd_exit - Driver exit clean-up routine
+ */
+static void __exit ufshcd_exit(void)
+{
+	pci_unregister_driver(&ufshcd_pci_driver);
+}
+module_exit(ufshcd_exit);
+
+
+MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>, "
+	      "Vinayak Holikatti <h.vinayak@samsung.com>");
+MODULE_DESCRIPTION("Generic UFS host controller driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(UFSHCD_DRIVER_VERSION);
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
new file mode 100644
index 0000000..6e3510f
--- /dev/null
+++ b/drivers/scsi/ufs/ufshci.h
@@ -0,0 +1,376 @@
+/*
+ * Universal Flash Storage Host controller driver
+ *
+ * This code is based on drivers/scsi/ufs/ufshci.h
+ * Copyright (C) 2011-2012 Samsung India Software Operations
+ *
+ * Santosh Yaraganavi <santosh.sy@samsung.com>
+ * Vinayak Holikatti <h.vinayak@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 distributed in the hope that it will be useful,
+ * but WITHOUT 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 _UFSHCI_H
+#define _UFSHCI_H
+
+enum {
+	TASK_REQ_UPIU_SIZE_DWORDS	= 8,
+	TASK_RSP_UPIU_SIZE_DWORDS	= 8,
+	ALIGNED_UPIU_SIZE		= 128,
+};
+
+/* UFSHCI Registers */
+enum {
+	REG_CONTROLLER_CAPABILITIES		= 0x00,
+	REG_UFS_VERSION				= 0x08,
+	REG_CONTROLLER_DEV_ID			= 0x10,
+	REG_CONTROLLER_PROD_ID			= 0x14,
+	REG_INTERRUPT_STATUS			= 0x20,
+	REG_INTERRUPT_ENABLE			= 0x24,
+	REG_CONTROLLER_STATUS			= 0x30,
+	REG_CONTROLLER_ENABLE			= 0x34,
+	REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER	= 0x38,
+	REG_UIC_ERROR_CODE_DATA_LINK_LAYER	= 0x3C,
+	REG_UIC_ERROR_CODE_NETWORK_LAYER	= 0x40,
+	REG_UIC_ERROR_CODE_TRANSPORT_LAYER	= 0x44,
+	REG_UIC_ERROR_CODE_DME			= 0x48,
+	REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL	= 0x4C,
+	REG_UTP_TRANSFER_REQ_LIST_BASE_L	= 0x50,
+	REG_UTP_TRANSFER_REQ_LIST_BASE_H	= 0x54,
+	REG_UTP_TRANSFER_REQ_DOOR_BELL		= 0x58,
+	REG_UTP_TRANSFER_REQ_LIST_CLEAR		= 0x5C,
+	REG_UTP_TRANSFER_REQ_LIST_RUN_STOP	= 0x60,
+	REG_UTP_TASK_REQ_LIST_BASE_L		= 0x70,
+	REG_UTP_TASK_REQ_LIST_BASE_H		= 0x74,
+	REG_UTP_TASK_REQ_DOOR_BELL		= 0x78,
+	REG_UTP_TASK_REQ_LIST_CLEAR		= 0x7C,
+	REG_UTP_TASK_REQ_LIST_RUN_STOP		= 0x80,
+	REG_UIC_COMMAND				= 0x90,
+	REG_UIC_COMMAND_ARG_1			= 0x94,
+	REG_UIC_COMMAND_ARG_2			= 0x98,
+	REG_UIC_COMMAND_ARG_3			= 0x9C,
+};
+
+/* Controller capability masks */
+enum {
+	MASK_TRANSFER_REQUESTS_SLOTS		= 0x0000001F,
+	MASK_TASK_MANAGEMENT_REQUEST_SLOTS	= 0x00070000,
+	MASK_64_ADDRESSING_SUPPORT		= 0x01000000,
+	MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT	= 0x02000000,
+	MASK_UIC_DME_TEST_MODE_SUPPORT		= 0x04000000,
+};
+
+/* UFS Version 08h */
+#define MINOR_VERSION_NUM_MASK		UFS_MASK(0xFFFF, 0)
+#define MAJOR_VERSION_NUM_MASK		UFS_MASK(0xFFFF, 16)
+
+/* Controller UFSHCI version */
+enum {
+	UFSHCI_VERSION_10 = 0x00010000,
+	UFSHCI_VERSION_11 = 0x00010100,
+};
+
+/*
+ * HCDDID - Host Controller Identification Descriptor
+ *	  - Device ID and Device Class 10h
+ */
+#define DEVICE_CLASS	UFS_MASK(0xFFFF, 0)
+#define DEVICE_ID	UFS_MASK(0xFF, 24)
+
+/*
+ * HCPMID - Host Controller Identification Descriptor
+ *	  - Product/Manufacturer ID  14h
+ */
+#define MANUFACTURE_ID_MASK	UFS_MASK(0xFFFF, 0)
+#define PRODUCT_ID_MASK		UFS_MASK(0xFFFF, 16)
+
+#define UFS_BIT(x)	(1L << (x))
+
+#define UTP_TRANSFER_REQ_COMPL			UFS_BIT(0)
+#define UIC_DME_END_PT_RESET			UFS_BIT(1)
+#define UIC_ERROR				UFS_BIT(2)
+#define UIC_TEST_MODE				UFS_BIT(3)
+#define UIC_POWER_MODE				UFS_BIT(4)
+#define UIC_HIBERNATE_EXIT			UFS_BIT(5)
+#define UIC_HIBERNATE_ENTER			UFS_BIT(6)
+#define UIC_LINK_LOST				UFS_BIT(7)
+#define UIC_LINK_STARTUP			UFS_BIT(8)
+#define UTP_TASK_REQ_COMPL			UFS_BIT(9)
+#define UIC_COMMAND_COMPL			UFS_BIT(10)
+#define DEVICE_FATAL_ERROR			UFS_BIT(11)
+#define CONTROLLER_FATAL_ERROR			UFS_BIT(16)
+#define SYSTEM_BUS_FATAL_ERROR			UFS_BIT(17)
+
+#define UFSHCD_ERROR_MASK	(UIC_ERROR |\
+				DEVICE_FATAL_ERROR |\
+				CONTROLLER_FATAL_ERROR |\
+				SYSTEM_BUS_FATAL_ERROR)
+
+#define INT_FATAL_ERRORS	(DEVICE_FATAL_ERROR |\
+				CONTROLLER_FATAL_ERROR |\
+				SYSTEM_BUS_FATAL_ERROR)
+
+/* HCS - Host Controller Status 30h */
+#define DEVICE_PRESENT				UFS_BIT(0)
+#define UTP_TRANSFER_REQ_LIST_READY		UFS_BIT(1)
+#define UTP_TASK_REQ_LIST_READY			UFS_BIT(2)
+#define UIC_COMMAND_READY			UFS_BIT(3)
+#define HOST_ERROR_INDICATOR			UFS_BIT(4)
+#define DEVICE_ERROR_INDICATOR			UFS_BIT(5)
+#define UIC_POWER_MODE_CHANGE_REQ_STATUS_MASK	UFS_MASK(0x7, 8)
+
+/* HCE - Host Controller Enable 34h */
+#define CONTROLLER_ENABLE	UFS_BIT(0)
+#define CONTROLLER_DISABLE	0x0
+
+/* UECPA - Host UIC Error Code PHY Adapter Layer 38h */
+#define UIC_PHY_ADAPTER_LAYER_ERROR			UFS_BIT(31)
+#define UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK		0x1F
+
+/* UECDL - Host UIC Error Code Data Link Layer 3Ch */
+#define UIC_DATA_LINK_LAYER_ERROR		UFS_BIT(31)
+#define UIC_DATA_LINK_LAYER_ERROR_CODE_MASK	0x7FFF
+#define UIC_DATA_LINK_LAYER_ERROR_PA_INIT	0x2000
+
+/* UECN - Host UIC Error Code Network Layer 40h */
+#define UIC_NETWORK_LAYER_ERROR			UFS_BIT(31)
+#define UIC_NETWORK_LAYER_ERROR_CODE_MASK	0x7
+
+/* UECT - Host UIC Error Code Transport Layer 44h */
+#define UIC_TRANSPORT_LAYER_ERROR		UFS_BIT(31)
+#define UIC_TRANSPORT_LAYER_ERROR_CODE_MASK	0x7F
+
+/* UECDME - Host UIC Error Code DME 48h */
+#define UIC_DME_ERROR			UFS_BIT(31)
+#define UIC_DME_ERROR_CODE_MASK		0x1
+
+#define INT_AGGR_TIMEOUT_VAL_MASK		0xFF
+#define INT_AGGR_COUNTER_THRESHOLD_MASK		UFS_MASK(0x1F, 8)
+#define INT_AGGR_COUNTER_AND_TIMER_RESET	UFS_BIT(16)
+#define INT_AGGR_STATUS_BIT			UFS_BIT(20)
+#define INT_AGGR_PARAM_WRITE			UFS_BIT(24)
+#define INT_AGGR_ENABLE				UFS_BIT(31)
+
+/* UTRLRSR - UTP Transfer Request Run-Stop Register 60h */
+#define UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT	UFS_BIT(0)
+
+/* UTMRLRSR - UTP Task Management Request Run-Stop Register 80h */
+#define UTP_TASK_REQ_LIST_RUN_STOP_BIT		UFS_BIT(0)
+
+/* UICCMD - UIC Command */
+#define COMMAND_OPCODE_MASK		0xFF
+#define GEN_SELECTOR_INDEX_MASK		0xFFFF
+
+#define MIB_ATTRIBUTE_MASK		UFS_MASK(0xFFFF, 16)
+#define RESET_LEVEL			0xFF
+
+#define ATTR_SET_TYPE_MASK		UFS_MASK(0xFF, 16)
+#define CONFIG_RESULT_CODE_MASK		0xFF
+#define GENERIC_ERROR_CODE_MASK		0xFF
+
+/* UIC Commands */
+enum {
+	UIC_CMD_DME_GET			= 0x01,
+	UIC_CMD_DME_SET			= 0x02,
+	UIC_CMD_DME_PEER_GET		= 0x03,
+	UIC_CMD_DME_PEER_SET		= 0x04,
+	UIC_CMD_DME_POWERON		= 0x10,
+	UIC_CMD_DME_POWEROFF		= 0x11,
+	UIC_CMD_DME_ENABLE		= 0x12,
+	UIC_CMD_DME_RESET		= 0x14,
+	UIC_CMD_DME_END_PT_RST		= 0x15,
+	UIC_CMD_DME_LINK_STARTUP	= 0x16,
+	UIC_CMD_DME_HIBER_ENTER		= 0x17,
+	UIC_CMD_DME_HIBER_EXIT		= 0x18,
+	UIC_CMD_DME_TEST_MODE		= 0x1A,
+};
+
+/* UIC Config result code / Generic error code */
+enum {
+	UIC_CMD_RESULT_SUCCESS			= 0x00,
+	UIC_CMD_RESULT_INVALID_ATTR		= 0x01,
+	UIC_CMD_RESULT_FAILURE			= 0x01,
+	UIC_CMD_RESULT_INVALID_ATTR_VALUE	= 0x02,
+	UIC_CMD_RESULT_READ_ONLY_ATTR		= 0x03,
+	UIC_CMD_RESULT_WRITE_ONLY_ATTR		= 0x04,
+	UIC_CMD_RESULT_BAD_INDEX		= 0x05,
+	UIC_CMD_RESULT_LOCKED_ATTR		= 0x06,
+	UIC_CMD_RESULT_BAD_TEST_FEATURE_INDEX	= 0x07,
+	UIC_CMD_RESULT_PEER_COMM_FAILURE	= 0x08,
+	UIC_CMD_RESULT_BUSY			= 0x09,
+	UIC_CMD_RESULT_DME_FAILURE		= 0x0A,
+};
+
+#define MASK_UIC_COMMAND_RESULT			0xFF
+
+#define INT_AGGR_COUNTER_THRESHOLD_VALUE	(0x1F << 8)
+#define INT_AGGR_TIMEOUT_VALUE			(0x02)
+
+/* Interrupt disable masks */
+enum {
+	/* Interrupt disable mask for UFSHCI v1.0 */
+	INTERRUPT_DISABLE_MASK_10	= 0xFFFF,
+
+	/* Interrupt disable mask for UFSHCI v1.1 */
+	INTERRUPT_DISABLE_MASK_11	= 0x0,
+};
+
+/*
+ * Request Descriptor Definitions
+ */
+
+/* Transfer request command type */
+enum {
+	UTP_CMD_TYPE_SCSI		= 0x0,
+	UTP_CMD_TYPE_UFS		= 0x1,
+	UTP_CMD_TYPE_DEV_MANAGE		= 0x2,
+};
+
+enum {
+	UTP_SCSI_COMMAND		= 0x00000000,
+	UTP_NATIVE_UFS_COMMAND		= 0x10000000,
+	UTP_DEVICE_MANAGEMENT_FUNCTION	= 0x20000000,
+	UTP_REQ_DESC_INT_CMD		= 0x01000000,
+};
+
+/* UTP Transfer Request Data Direction (DD) */
+enum {
+	UTP_NO_DATA_TRANSFER	= 0x00000000,
+	UTP_HOST_TO_DEVICE	= 0x02000000,
+	UTP_DEVICE_TO_HOST	= 0x04000000,
+};
+
+/* Overall command status values */
+enum {
+	OCS_SUCCESS			= 0x0,
+	OCS_INVALID_CMD_TABLE_ATTR	= 0x1,
+	OCS_INVALID_PRDT_ATTR		= 0x2,
+	OCS_MISMATCH_DATA_BUF_SIZE	= 0x3,
+	OCS_MISMATCH_RESP_UPIU_SIZE	= 0x4,
+	OCS_PEER_COMM_FAILURE		= 0x5,
+	OCS_ABORTED			= 0x6,
+	OCS_FATAL_ERROR			= 0x7,
+	OCS_INVALID_COMMAND_STATUS	= 0x0F,
+	MASK_OCS			= 0x0F,
+};
+
+/**
+ * struct ufshcd_sg_entry - UFSHCI PRD Entry
+ * @base_addr: Lower 32bit physical address DW-0
+ * @upper_addr: Upper 32bit physical address DW-1
+ * @reserved: Reserved for future use DW-2
+ * @size: size of physical segment DW-3
+ */
+struct ufshcd_sg_entry {
+	u32    base_addr;
+	u32    upper_addr;
+	u32    reserved;
+	u32    size;
+};
+
+/**
+ * struct utp_transfer_cmd_desc - UFS Command Descriptor structure
+ * @command_upiu: Command UPIU Frame address
+ * @response_upiu: Response UPIU Frame address
+ * @prd_table: Physical Region Descriptor
+ */
+struct utp_transfer_cmd_desc {
+	u8 command_upiu[ALIGNED_UPIU_SIZE];
+	u8 response_upiu[ALIGNED_UPIU_SIZE];
+	struct ufshcd_sg_entry    prd_table[SG_ALL];
+};
+
+/**
+ * struct request_desc_header - Descriptor Header common to both UTRD and UTMRD
+ * @dword0: Descriptor Header DW0
+ * @dword1: Descriptor Header DW1
+ * @dword2: Descriptor Header DW2
+ * @dword3: Descriptor Header DW3
+ */
+struct request_desc_header {
+	u32 dword_0;
+	u32 dword_1;
+	u32 dword_2;
+	u32 dword_3;
+};
+
+/**
+ * struct utp_transfer_req_desc - UTRD structure
+ * @header: UTRD header DW-0 to DW-3
+ * @command_desc_base_addr_lo: UCD base address low DW-4
+ * @command_desc_base_addr_hi: UCD base address high DW-5
+ * @response_upiu_length: response UPIU length DW-6
+ * @response_upiu_offset: response UPIU offset DW-6
+ * @prd_table_length: Physical region descriptor length DW-7
+ * @prd_table_offset: Physical region descriptor offset DW-7
+ */
+struct utp_transfer_req_desc {
+
+	/* DW 0-3 */
+	struct request_desc_header header;
+
+	/* DW 4-5*/
+	u32  command_desc_base_addr_lo;
+	u32  command_desc_base_addr_hi;
+
+	/* DW 6 */
+	u16  response_upiu_length;
+	u16  response_upiu_offset;
+
+	/* DW 7 */
+	u16  prd_table_length;
+	u16  prd_table_offset;
+};
+
+/**
+ * struct utp_task_req_desc - UTMRD structure
+ * @header: UTMRD header DW-0 to DW-3
+ * @task_req_upiu: Pointer to task request UPIU DW-4 to DW-11
+ * @task_rsp_upiu: Pointer to task response UPIU DW12 to DW-19
+ */
+struct utp_task_req_desc {
+
+	/* DW 0-3 */
+	struct request_desc_header header;
+
+	/* DW 4-11 */
+	u32 task_req_upiu[TASK_REQ_UPIU_SIZE_DWORDS];
+
+	/* DW 12-19 */
+	u32 task_rsp_upiu[TASK_RSP_UPIU_SIZE_DWORDS];
+};
+
+#endif /* End of Header */
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index 7e22b73..14e0c40 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -141,7 +141,6 @@
 #include <linux/delay.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/dma.h>
 
 #define ULTRASTOR_PRIVATE	/* Get the private stuff from ultrastor.h */
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
new file mode 100644
index 0000000..efccd72
--- /dev/null
+++ b/drivers/scsi/virtio_scsi.c
@@ -0,0 +1,594 @@
+/*
+ * Virtio SCSI HBA driver
+ *
+ * Copyright IBM Corp. 2010
+ * Copyright Red Hat, Inc. 2011
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
+ *  Paolo Bonzini   <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mempool.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+
+#define VIRTIO_SCSI_MEMPOOL_SZ 64
+
+/* Command queue element */
+struct virtio_scsi_cmd {
+	struct scsi_cmnd *sc;
+	struct completion *comp;
+	union {
+		struct virtio_scsi_cmd_req       cmd;
+		struct virtio_scsi_ctrl_tmf_req  tmf;
+		struct virtio_scsi_ctrl_an_req   an;
+	} req;
+	union {
+		struct virtio_scsi_cmd_resp      cmd;
+		struct virtio_scsi_ctrl_tmf_resp tmf;
+		struct virtio_scsi_ctrl_an_resp  an;
+		struct virtio_scsi_event         evt;
+	} resp;
+} ____cacheline_aligned_in_smp;
+
+/* Driver instance state */
+struct virtio_scsi {
+	/* Protects ctrl_vq, req_vq and sg[] */
+	spinlock_t vq_lock;
+
+	struct virtio_device *vdev;
+	struct virtqueue *ctrl_vq;
+	struct virtqueue *event_vq;
+	struct virtqueue *req_vq;
+
+	/* For sglist construction when adding commands to the virtqueue.  */
+	struct scatterlist sg[];
+};
+
+static struct kmem_cache *virtscsi_cmd_cache;
+static mempool_t *virtscsi_cmd_pool;
+
+static inline struct Scsi_Host *virtio_scsi_host(struct virtio_device *vdev)
+{
+	return vdev->priv;
+}
+
+static void virtscsi_compute_resid(struct scsi_cmnd *sc, u32 resid)
+{
+	if (!resid)
+		return;
+
+	if (!scsi_bidi_cmnd(sc)) {
+		scsi_set_resid(sc, resid);
+		return;
+	}
+
+	scsi_in(sc)->resid = min(resid, scsi_in(sc)->length);
+	scsi_out(sc)->resid = resid - scsi_in(sc)->resid;
+}
+
+/**
+ * virtscsi_complete_cmd - finish a scsi_cmd and invoke scsi_done
+ *
+ * Called with vq_lock held.
+ */
+static void virtscsi_complete_cmd(void *buf)
+{
+	struct virtio_scsi_cmd *cmd = buf;
+	struct scsi_cmnd *sc = cmd->sc;
+	struct virtio_scsi_cmd_resp *resp = &cmd->resp.cmd;
+
+	dev_dbg(&sc->device->sdev_gendev,
+		"cmd %p response %u status %#02x sense_len %u\n",
+		sc, resp->response, resp->status, resp->sense_len);
+
+	sc->result = resp->status;
+	virtscsi_compute_resid(sc, resp->resid);
+	switch (resp->response) {
+	case VIRTIO_SCSI_S_OK:
+		set_host_byte(sc, DID_OK);
+		break;
+	case VIRTIO_SCSI_S_OVERRUN:
+		set_host_byte(sc, DID_ERROR);
+		break;
+	case VIRTIO_SCSI_S_ABORTED:
+		set_host_byte(sc, DID_ABORT);
+		break;
+	case VIRTIO_SCSI_S_BAD_TARGET:
+		set_host_byte(sc, DID_BAD_TARGET);
+		break;
+	case VIRTIO_SCSI_S_RESET:
+		set_host_byte(sc, DID_RESET);
+		break;
+	case VIRTIO_SCSI_S_BUSY:
+		set_host_byte(sc, DID_BUS_BUSY);
+		break;
+	case VIRTIO_SCSI_S_TRANSPORT_FAILURE:
+		set_host_byte(sc, DID_TRANSPORT_DISRUPTED);
+		break;
+	case VIRTIO_SCSI_S_TARGET_FAILURE:
+		set_host_byte(sc, DID_TARGET_FAILURE);
+		break;
+	case VIRTIO_SCSI_S_NEXUS_FAILURE:
+		set_host_byte(sc, DID_NEXUS_FAILURE);
+		break;
+	default:
+		scmd_printk(KERN_WARNING, sc, "Unknown response %d",
+			    resp->response);
+		/* fall through */
+	case VIRTIO_SCSI_S_FAILURE:
+		set_host_byte(sc, DID_ERROR);
+		break;
+	}
+
+	WARN_ON(resp->sense_len > VIRTIO_SCSI_SENSE_SIZE);
+	if (sc->sense_buffer) {
+		memcpy(sc->sense_buffer, resp->sense,
+		       min_t(u32, resp->sense_len, VIRTIO_SCSI_SENSE_SIZE));
+		if (resp->sense_len)
+			set_driver_byte(sc, DRIVER_SENSE);
+	}
+
+	mempool_free(cmd, virtscsi_cmd_pool);
+	sc->scsi_done(sc);
+}
+
+static void virtscsi_vq_done(struct virtqueue *vq, void (*fn)(void *buf))
+{
+	struct Scsi_Host *sh = virtio_scsi_host(vq->vdev);
+	struct virtio_scsi *vscsi = shost_priv(sh);
+	void *buf;
+	unsigned long flags;
+	unsigned int len;
+
+	spin_lock_irqsave(&vscsi->vq_lock, flags);
+
+	do {
+		virtqueue_disable_cb(vq);
+		while ((buf = virtqueue_get_buf(vq, &len)) != NULL)
+			fn(buf);
+	} while (!virtqueue_enable_cb(vq));
+
+	spin_unlock_irqrestore(&vscsi->vq_lock, flags);
+}
+
+static void virtscsi_req_done(struct virtqueue *vq)
+{
+	virtscsi_vq_done(vq, virtscsi_complete_cmd);
+};
+
+static void virtscsi_complete_free(void *buf)
+{
+	struct virtio_scsi_cmd *cmd = buf;
+
+	if (cmd->comp)
+		complete_all(cmd->comp);
+	mempool_free(cmd, virtscsi_cmd_pool);
+}
+
+static void virtscsi_ctrl_done(struct virtqueue *vq)
+{
+	virtscsi_vq_done(vq, virtscsi_complete_free);
+};
+
+static void virtscsi_event_done(struct virtqueue *vq)
+{
+	virtscsi_vq_done(vq, virtscsi_complete_free);
+};
+
+static void virtscsi_map_sgl(struct scatterlist *sg, unsigned int *p_idx,
+			     struct scsi_data_buffer *sdb)
+{
+	struct sg_table *table = &sdb->table;
+	struct scatterlist *sg_elem;
+	unsigned int idx = *p_idx;
+	int i;
+
+	for_each_sg(table->sgl, sg_elem, table->nents, i)
+		sg_set_buf(&sg[idx++], sg_virt(sg_elem), sg_elem->length);
+
+	*p_idx = idx;
+}
+
+/**
+ * virtscsi_map_cmd - map a scsi_cmd to a virtqueue scatterlist
+ * @vscsi	: virtio_scsi state
+ * @cmd		: command structure
+ * @out_num	: number of read-only elements
+ * @in_num	: number of write-only elements
+ * @req_size	: size of the request buffer
+ * @resp_size	: size of the response buffer
+ *
+ * Called with vq_lock held.
+ */
+static void virtscsi_map_cmd(struct virtio_scsi *vscsi,
+			     struct virtio_scsi_cmd *cmd,
+			     unsigned *out_num, unsigned *in_num,
+			     size_t req_size, size_t resp_size)
+{
+	struct scsi_cmnd *sc = cmd->sc;
+	struct scatterlist *sg = vscsi->sg;
+	unsigned int idx = 0;
+
+	if (sc) {
+		struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
+		BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize);
+
+		/* TODO: check feature bit and fail if unsupported?  */
+		BUG_ON(sc->sc_data_direction == DMA_BIDIRECTIONAL);
+	}
+
+	/* Request header.  */
+	sg_set_buf(&sg[idx++], &cmd->req, req_size);
+
+	/* Data-out buffer.  */
+	if (sc && sc->sc_data_direction != DMA_FROM_DEVICE)
+		virtscsi_map_sgl(sg, &idx, scsi_out(sc));
+
+	*out_num = idx;
+
+	/* Response header.  */
+	sg_set_buf(&sg[idx++], &cmd->resp, resp_size);
+
+	/* Data-in buffer */
+	if (sc && sc->sc_data_direction != DMA_TO_DEVICE)
+		virtscsi_map_sgl(sg, &idx, scsi_in(sc));
+
+	*in_num = idx - *out_num;
+}
+
+static int virtscsi_kick_cmd(struct virtio_scsi *vscsi, struct virtqueue *vq,
+			     struct virtio_scsi_cmd *cmd,
+			     size_t req_size, size_t resp_size, gfp_t gfp)
+{
+	unsigned int out_num, in_num;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&vscsi->vq_lock, flags);
+
+	virtscsi_map_cmd(vscsi, cmd, &out_num, &in_num, req_size, resp_size);
+
+	ret = virtqueue_add_buf(vq, vscsi->sg, out_num, in_num, cmd, gfp);
+	if (ret >= 0)
+		virtqueue_kick(vq);
+
+	spin_unlock_irqrestore(&vscsi->vq_lock, flags);
+	return ret;
+}
+
+static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
+{
+	struct virtio_scsi *vscsi = shost_priv(sh);
+	struct virtio_scsi_cmd *cmd;
+	int ret;
+
+	dev_dbg(&sc->device->sdev_gendev,
+		"cmd %p CDB: %#02x\n", sc, sc->cmnd[0]);
+
+	ret = SCSI_MLQUEUE_HOST_BUSY;
+	cmd = mempool_alloc(virtscsi_cmd_pool, GFP_ATOMIC);
+	if (!cmd)
+		goto out;
+
+	memset(cmd, 0, sizeof(*cmd));
+	cmd->sc = sc;
+	cmd->req.cmd = (struct virtio_scsi_cmd_req){
+		.lun[0] = 1,
+		.lun[1] = sc->device->id,
+		.lun[2] = (sc->device->lun >> 8) | 0x40,
+		.lun[3] = sc->device->lun & 0xff,
+		.tag = (unsigned long)sc,
+		.task_attr = VIRTIO_SCSI_S_SIMPLE,
+		.prio = 0,
+		.crn = 0,
+	};
+
+	BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE);
+	memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len);
+
+	if (virtscsi_kick_cmd(vscsi, vscsi->req_vq, cmd,
+			      sizeof cmd->req.cmd, sizeof cmd->resp.cmd,
+			      GFP_ATOMIC) >= 0)
+		ret = 0;
+
+out:
+	return ret;
+}
+
+static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
+{
+	DECLARE_COMPLETION_ONSTACK(comp);
+	int ret;
+
+	cmd->comp = &comp;
+	ret = virtscsi_kick_cmd(vscsi, vscsi->ctrl_vq, cmd,
+			       sizeof cmd->req.tmf, sizeof cmd->resp.tmf,
+			       GFP_NOIO);
+	if (ret < 0)
+		return FAILED;
+
+	wait_for_completion(&comp);
+	if (cmd->resp.tmf.response != VIRTIO_SCSI_S_OK &&
+	    cmd->resp.tmf.response != VIRTIO_SCSI_S_FUNCTION_SUCCEEDED)
+		return FAILED;
+
+	return SUCCESS;
+}
+
+static int virtscsi_device_reset(struct scsi_cmnd *sc)
+{
+	struct virtio_scsi *vscsi = shost_priv(sc->device->host);
+	struct virtio_scsi_cmd *cmd;
+
+	sdev_printk(KERN_INFO, sc->device, "device reset\n");
+	cmd = mempool_alloc(virtscsi_cmd_pool, GFP_NOIO);
+	if (!cmd)
+		return FAILED;
+
+	memset(cmd, 0, sizeof(*cmd));
+	cmd->sc = sc;
+	cmd->req.tmf = (struct virtio_scsi_ctrl_tmf_req){
+		.type = VIRTIO_SCSI_T_TMF,
+		.subtype = VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET,
+		.lun[0] = 1,
+		.lun[1] = sc->device->id,
+		.lun[2] = (sc->device->lun >> 8) | 0x40,
+		.lun[3] = sc->device->lun & 0xff,
+	};
+	return virtscsi_tmf(vscsi, cmd);
+}
+
+static int virtscsi_abort(struct scsi_cmnd *sc)
+{
+	struct virtio_scsi *vscsi = shost_priv(sc->device->host);
+	struct virtio_scsi_cmd *cmd;
+
+	scmd_printk(KERN_INFO, sc, "abort\n");
+	cmd = mempool_alloc(virtscsi_cmd_pool, GFP_NOIO);
+	if (!cmd)
+		return FAILED;
+
+	memset(cmd, 0, sizeof(*cmd));
+	cmd->sc = sc;
+	cmd->req.tmf = (struct virtio_scsi_ctrl_tmf_req){
+		.type = VIRTIO_SCSI_T_TMF,
+		.subtype = VIRTIO_SCSI_T_TMF_ABORT_TASK,
+		.lun[0] = 1,
+		.lun[1] = sc->device->id,
+		.lun[2] = (sc->device->lun >> 8) | 0x40,
+		.lun[3] = sc->device->lun & 0xff,
+		.tag = (unsigned long)sc,
+	};
+	return virtscsi_tmf(vscsi, cmd);
+}
+
+static struct scsi_host_template virtscsi_host_template = {
+	.module = THIS_MODULE,
+	.name = "Virtio SCSI HBA",
+	.proc_name = "virtio_scsi",
+	.queuecommand = virtscsi_queuecommand,
+	.this_id = -1,
+	.eh_abort_handler = virtscsi_abort,
+	.eh_device_reset_handler = virtscsi_device_reset,
+
+	.can_queue = 1024,
+	.dma_boundary = UINT_MAX,
+	.use_clustering = ENABLE_CLUSTERING,
+};
+
+#define virtscsi_config_get(vdev, fld) \
+	({ \
+		typeof(((struct virtio_scsi_config *)0)->fld) __val; \
+		vdev->config->get(vdev, \
+				  offsetof(struct virtio_scsi_config, fld), \
+				  &__val, sizeof(__val)); \
+		__val; \
+	})
+
+#define virtscsi_config_set(vdev, fld, val) \
+	(void)({ \
+		typeof(((struct virtio_scsi_config *)0)->fld) __val = (val); \
+		vdev->config->set(vdev, \
+				  offsetof(struct virtio_scsi_config, fld), \
+				  &__val, sizeof(__val)); \
+	})
+
+static int virtscsi_init(struct virtio_device *vdev,
+			 struct virtio_scsi *vscsi)
+{
+	int err;
+	struct virtqueue *vqs[3];
+	vq_callback_t *callbacks[] = {
+		virtscsi_ctrl_done,
+		virtscsi_event_done,
+		virtscsi_req_done
+	};
+	const char *names[] = {
+		"control",
+		"event",
+		"request"
+	};
+
+	/* Discover virtqueues and write information to configuration.  */
+	err = vdev->config->find_vqs(vdev, 3, vqs, callbacks, names);
+	if (err)
+		return err;
+
+	vscsi->ctrl_vq = vqs[0];
+	vscsi->event_vq = vqs[1];
+	vscsi->req_vq = vqs[2];
+
+	virtscsi_config_set(vdev, cdb_size, VIRTIO_SCSI_CDB_SIZE);
+	virtscsi_config_set(vdev, sense_size, VIRTIO_SCSI_SENSE_SIZE);
+	return 0;
+}
+
+static int __devinit virtscsi_probe(struct virtio_device *vdev)
+{
+	struct Scsi_Host *shost;
+	struct virtio_scsi *vscsi;
+	int err;
+	u32 sg_elems;
+	u32 cmd_per_lun;
+
+	/* We need to know how many segments before we allocate.
+	 * We need an extra sg elements at head and tail.
+	 */
+	sg_elems = virtscsi_config_get(vdev, seg_max) ?: 1;
+
+	/* Allocate memory and link the structs together.  */
+	shost = scsi_host_alloc(&virtscsi_host_template,
+		sizeof(*vscsi) + sizeof(vscsi->sg[0]) * (sg_elems + 2));
+
+	if (!shost)
+		return -ENOMEM;
+
+	shost->sg_tablesize = sg_elems;
+	vscsi = shost_priv(shost);
+	vscsi->vdev = vdev;
+	vdev->priv = shost;
+
+	/* Random initializations.  */
+	spin_lock_init(&vscsi->vq_lock);
+	sg_init_table(vscsi->sg, sg_elems + 2);
+
+	err = virtscsi_init(vdev, vscsi);
+	if (err)
+		goto virtscsi_init_failed;
+
+	cmd_per_lun = virtscsi_config_get(vdev, cmd_per_lun) ?: 1;
+	shost->cmd_per_lun = min_t(u32, cmd_per_lun, shost->can_queue);
+	shost->max_sectors = virtscsi_config_get(vdev, max_sectors) ?: 0xFFFF;
+	shost->max_lun = virtscsi_config_get(vdev, max_lun) + 1;
+	shost->max_id = virtscsi_config_get(vdev, max_target) + 1;
+	shost->max_channel = 0;
+	shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE;
+	err = scsi_add_host(shost, &vdev->dev);
+	if (err)
+		goto scsi_add_host_failed;
+
+	scsi_scan_host(shost);
+
+	return 0;
+
+scsi_add_host_failed:
+	vdev->config->del_vqs(vdev);
+virtscsi_init_failed:
+	scsi_host_put(shost);
+	return err;
+}
+
+static void virtscsi_remove_vqs(struct virtio_device *vdev)
+{
+	/* Stop all the virtqueues. */
+	vdev->config->reset(vdev);
+
+	vdev->config->del_vqs(vdev);
+}
+
+static void __devexit virtscsi_remove(struct virtio_device *vdev)
+{
+	struct Scsi_Host *shost = virtio_scsi_host(vdev);
+
+	scsi_remove_host(shost);
+
+	virtscsi_remove_vqs(vdev);
+	scsi_host_put(shost);
+}
+
+#ifdef CONFIG_PM
+static int virtscsi_freeze(struct virtio_device *vdev)
+{
+	virtscsi_remove_vqs(vdev);
+	return 0;
+}
+
+static int virtscsi_restore(struct virtio_device *vdev)
+{
+	struct Scsi_Host *sh = virtio_scsi_host(vdev);
+	struct virtio_scsi *vscsi = shost_priv(sh);
+
+	return virtscsi_init(vdev, vscsi);
+}
+#endif
+
+static struct virtio_device_id id_table[] = {
+	{ VIRTIO_ID_SCSI, VIRTIO_DEV_ANY_ID },
+	{ 0 },
+};
+
+static struct virtio_driver virtio_scsi_driver = {
+	.driver.name = KBUILD_MODNAME,
+	.driver.owner = THIS_MODULE,
+	.id_table = id_table,
+	.probe = virtscsi_probe,
+#ifdef CONFIG_PM
+	.freeze = virtscsi_freeze,
+	.restore = virtscsi_restore,
+#endif
+	.remove = __devexit_p(virtscsi_remove),
+};
+
+static int __init init(void)
+{
+	int ret = -ENOMEM;
+
+	virtscsi_cmd_cache = KMEM_CACHE(virtio_scsi_cmd, 0);
+	if (!virtscsi_cmd_cache) {
+		printk(KERN_ERR "kmem_cache_create() for "
+				"virtscsi_cmd_cache failed\n");
+		goto error;
+	}
+
+
+	virtscsi_cmd_pool =
+		mempool_create_slab_pool(VIRTIO_SCSI_MEMPOOL_SZ,
+					 virtscsi_cmd_cache);
+	if (!virtscsi_cmd_pool) {
+		printk(KERN_ERR "mempool_create() for"
+				"virtscsi_cmd_pool failed\n");
+		goto error;
+	}
+	ret = register_virtio_driver(&virtio_scsi_driver);
+	if (ret < 0)
+		goto error;
+
+	return 0;
+
+error:
+	if (virtscsi_cmd_pool) {
+		mempool_destroy(virtscsi_cmd_pool);
+		virtscsi_cmd_pool = NULL;
+	}
+	if (virtscsi_cmd_cache) {
+		kmem_cache_destroy(virtscsi_cmd_cache);
+		virtscsi_cmd_cache = NULL;
+	}
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	unregister_virtio_driver(&virtio_scsi_driver);
+	mempool_destroy(virtscsi_cmd_pool);
+	kmem_cache_destroy(virtscsi_cmd_cache);
+}
+module_init(init);
+module_exit(fini);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio SCSI HBA driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index 7264116..4411d42 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -17,7 +17,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Maintained by: Alok N Kataria <akataria@vmware.com>
+ * Maintained by: Arvind Kumar <arvindkumar@vmware.com>
  *
  */
 
@@ -1178,11 +1178,67 @@
 	return 0;
 }
 
+/*
+ * Query the device, fetch the config info and return the
+ * maximum number of targets on the adapter. In case of
+ * failure due to any reason return default i.e. 16.
+ */
+static u32 pvscsi_get_max_targets(struct pvscsi_adapter *adapter)
+{
+	struct PVSCSICmdDescConfigCmd cmd;
+	struct PVSCSIConfigPageHeader *header;
+	struct device *dev;
+	dma_addr_t configPagePA;
+	void *config_page;
+	u32 numPhys = 16;
+
+	dev = pvscsi_dev(adapter);
+	config_page = pci_alloc_consistent(adapter->dev, PAGE_SIZE,
+					   &configPagePA);
+	if (!config_page) {
+		dev_warn(dev, "vmw_pvscsi: failed to allocate memory for config page\n");
+		goto exit;
+	}
+	BUG_ON(configPagePA & ~PAGE_MASK);
+
+	/* Fetch config info from the device. */
+	cmd.configPageAddress = ((u64)PVSCSI_CONFIG_CONTROLLER_ADDRESS) << 32;
+	cmd.configPageNum = PVSCSI_CONFIG_PAGE_CONTROLLER;
+	cmd.cmpAddr = configPagePA;
+	cmd._pad = 0;
+
+	/*
+	 * Mark the completion page header with error values. If the device
+	 * completes the command successfully, it sets the status values to
+	 * indicate success.
+	 */
+	header = config_page;
+	memset(header, 0, sizeof *header);
+	header->hostStatus = BTSTAT_INVPARAM;
+	header->scsiStatus = SDSTAT_CHECK;
+
+	pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_CONFIG, &cmd, sizeof cmd);
+
+	if (header->hostStatus == BTSTAT_SUCCESS &&
+	    header->scsiStatus == SDSTAT_GOOD) {
+		struct PVSCSIConfigPageController *config;
+
+		config = config_page;
+		numPhys = config->numPhys;
+	} else
+		dev_warn(dev, "vmw_pvscsi: PVSCSI_CMD_CONFIG failed. hostStatus = 0x%x, scsiStatus = 0x%x\n",
+			 header->hostStatus, header->scsiStatus);
+	pci_free_consistent(adapter->dev, PAGE_SIZE, config_page, configPagePA);
+exit:
+	return numPhys;
+}
+
 static int __devinit pvscsi_probe(struct pci_dev *pdev,
 				  const struct pci_device_id *id)
 {
 	struct pvscsi_adapter *adapter;
 	struct Scsi_Host *host;
+	struct device *dev;
 	unsigned int i;
 	unsigned long flags = 0;
 	int error;
@@ -1272,6 +1328,13 @@
 	}
 
 	/*
+	 * Ask the device for max number of targets.
+	 */
+	host->max_id = pvscsi_get_max_targets(adapter);
+	dev = pvscsi_dev(adapter);
+	dev_info(dev, "vmw_pvscsi: host->max_id: %u\n", host->max_id);
+
+	/*
 	 * From this point on we should reset the adapter if anything goes
 	 * wrong.
 	 */
diff --git a/drivers/scsi/vmw_pvscsi.h b/drivers/scsi/vmw_pvscsi.h
index 62e36e7..3546e86 100644
--- a/drivers/scsi/vmw_pvscsi.h
+++ b/drivers/scsi/vmw_pvscsi.h
@@ -17,7 +17,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Maintained by: Alok N Kataria <akataria@vmware.com>
+ * Maintained by: Arvind Kumar <arvindkumar@vmware.com>
  *
  */
 
@@ -26,7 +26,7 @@
 
 #include <linux/types.h>
 
-#define PVSCSI_DRIVER_VERSION_STRING   "1.0.1.0-k"
+#define PVSCSI_DRIVER_VERSION_STRING   "1.0.2.0-k"
 
 #define PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT 128
 
@@ -39,28 +39,45 @@
  * host adapter status/error codes
  */
 enum HostBusAdapterStatus {
-   BTSTAT_SUCCESS       = 0x00,  /* CCB complete normally with no errors */
-   BTSTAT_LINKED_COMMAND_COMPLETED           = 0x0a,
-   BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG = 0x0b,
-   BTSTAT_DATA_UNDERRUN = 0x0c,
-   BTSTAT_SELTIMEO      = 0x11,  /* SCSI selection timeout */
-   BTSTAT_DATARUN       = 0x12,  /* data overrun/underrun */
-   BTSTAT_BUSFREE       = 0x13,  /* unexpected bus free */
-   BTSTAT_INVPHASE      = 0x14,  /* invalid bus phase or sequence requested by target */
-   BTSTAT_LUNMISMATCH   = 0x17,  /* linked CCB has different LUN from first CCB */
-   BTSTAT_SENSFAILED    = 0x1b,  /* auto request sense failed */
-   BTSTAT_TAGREJECT     = 0x1c,  /* SCSI II tagged queueing message rejected by target */
-   BTSTAT_BADMSG        = 0x1d,  /* unsupported message received by the host adapter */
-   BTSTAT_HAHARDWARE    = 0x20,  /* host adapter hardware failed */
-   BTSTAT_NORESPONSE    = 0x21,  /* target did not respond to SCSI ATN, sent a SCSI RST */
-   BTSTAT_SENTRST       = 0x22,  /* host adapter asserted a SCSI RST */
-   BTSTAT_RECVRST       = 0x23,  /* other SCSI devices asserted a SCSI RST */
-   BTSTAT_DISCONNECT    = 0x24,  /* target device reconnected improperly (w/o tag) */
-   BTSTAT_BUSRESET      = 0x25,  /* host adapter issued BUS device reset */
-   BTSTAT_ABORTQUEUE    = 0x26,  /* abort queue generated */
-   BTSTAT_HASOFTWARE    = 0x27,  /* host adapter software error */
-   BTSTAT_HATIMEOUT     = 0x30,  /* host adapter hardware timeout error */
-   BTSTAT_SCSIPARITY    = 0x34,  /* SCSI parity error detected */
+	BTSTAT_SUCCESS       = 0x00,  /* CCB complete normally with no errors */
+	BTSTAT_LINKED_COMMAND_COMPLETED           = 0x0a,
+	BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG = 0x0b,
+	BTSTAT_DATA_UNDERRUN = 0x0c,
+	BTSTAT_SELTIMEO      = 0x11,  /* SCSI selection timeout */
+	BTSTAT_DATARUN       = 0x12,  /* data overrun/underrun */
+	BTSTAT_BUSFREE       = 0x13,  /* unexpected bus free */
+	BTSTAT_INVPHASE      = 0x14,  /* invalid bus phase or sequence
+				       * requested by target */
+	BTSTAT_LUNMISMATCH   = 0x17,  /* linked CCB has different LUN from
+				       * first CCB */
+	BTSTAT_INVPARAM      = 0x1a,  /* invalid parameter in CCB or segment
+				       * list */
+	BTSTAT_SENSFAILED    = 0x1b,  /* auto request sense failed */
+	BTSTAT_TAGREJECT     = 0x1c,  /* SCSI II tagged queueing message
+				       * rejected by target */
+	BTSTAT_BADMSG        = 0x1d,  /* unsupported message received by the
+				       * host adapter */
+	BTSTAT_HAHARDWARE    = 0x20,  /* host adapter hardware failed */
+	BTSTAT_NORESPONSE    = 0x21,  /* target did not respond to SCSI ATN,
+				       * sent a SCSI RST */
+	BTSTAT_SENTRST       = 0x22,  /* host adapter asserted a SCSI RST */
+	BTSTAT_RECVRST       = 0x23,  /* other SCSI devices asserted a SCSI
+				       * RST */
+	BTSTAT_DISCONNECT    = 0x24,  /* target device reconnected improperly
+				       * (w/o tag) */
+	BTSTAT_BUSRESET      = 0x25,  /* host adapter issued BUS device reset */
+	BTSTAT_ABORTQUEUE    = 0x26,  /* abort queue generated */
+	BTSTAT_HASOFTWARE    = 0x27,  /* host adapter software error */
+	BTSTAT_HATIMEOUT     = 0x30,  /* host adapter hardware timeout error */
+	BTSTAT_SCSIPARITY    = 0x34,  /* SCSI parity error detected */
+};
+
+/*
+ * SCSI device status values.
+ */
+enum ScsiDeviceStatus {
+	SDSTAT_GOOD  = 0x00, /* No errors. */
+	SDSTAT_CHECK = 0x02, /* Check condition. */
 };
 
 /*
@@ -114,6 +131,29 @@
 } __packed;
 
 /*
+ * Command descriptor for PVSCSI_CMD_CONFIG --
+ */
+
+struct PVSCSICmdDescConfigCmd {
+	u64 cmpAddr;
+	u64 configPageAddress;
+	u32 configPageNum;
+	u32 _pad;
+} __packed;
+
+enum PVSCSIConfigPageType {
+	PVSCSI_CONFIG_PAGE_CONTROLLER = 0x1958,
+	PVSCSI_CONFIG_PAGE_PHY        = 0x1959,
+	PVSCSI_CONFIG_PAGE_DEVICE     = 0x195a,
+};
+
+enum PVSCSIConfigPageAddressType {
+	PVSCSI_CONFIG_CONTROLLER_ADDRESS = 0x2120,
+	PVSCSI_CONFIG_BUSTARGET_ADDRESS  = 0x2121,
+	PVSCSI_CONFIG_PHY_ADDRESS        = 0x2122,
+};
+
+/*
  * Command descriptor for PVSCSI_CMD_ABORT_CMD --
  *
  * - currently does not support specifying the LUN.
@@ -332,6 +372,27 @@
 	u32	_pad[2];
 } __packed;
 
+struct PVSCSIConfigPageHeader {
+	u32 pageNum;
+	u16 numDwords;
+	u16 hostStatus;
+	u16 scsiStatus;
+	u16 reserved[3];
+} __packed;
+
+struct PVSCSIConfigPageController {
+	struct PVSCSIConfigPageHeader header;
+	u64 nodeWWN; /* Device name as defined in the SAS spec. */
+	u16 manufacturer[64];
+	u16 serialNumber[64];
+	u16 opromVersion[32];
+	u16 hwVersion[32];
+	u16 firmwareVersion[32];
+	u32 numPhys;
+	u8  useConsecutivePhyWWNs;
+	u8  reserved[3];
+} __packed;
+
 /*
  * Interrupt status / IRQ bits.
  */
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index 9ee0afe..d89a5df 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -179,7 +179,6 @@
 #include <linux/stat.h>
 #include <linux/io.h>
 
-#include <asm/system.h>
 #include <asm/dma.h>
 
 #include <scsi/scsi.h>
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c
index 92d314a..91b6d52 100644
--- a/drivers/sh/clk/cpg.c
+++ b/drivers/sh/clk/cpg.c
@@ -26,7 +26,7 @@
 		  clk->mapped_reg);
 }
 
-static struct clk_ops sh_clk_mstp32_clk_ops = {
+static struct sh_clk_ops sh_clk_mstp32_clk_ops = {
 	.enable		= sh_clk_mstp32_enable,
 	.disable	= sh_clk_mstp32_disable,
 	.recalc		= followparent_recalc,
@@ -150,7 +150,7 @@
 	iowrite32(value, clk->mapped_reg);
 }
 
-static struct clk_ops sh_clk_div6_clk_ops = {
+static struct sh_clk_ops sh_clk_div6_clk_ops = {
 	.recalc		= sh_clk_div6_recalc,
 	.round_rate	= sh_clk_div_round_rate,
 	.set_rate	= sh_clk_div6_set_rate,
@@ -158,7 +158,7 @@
 	.disable	= sh_clk_div6_disable,
 };
 
-static struct clk_ops sh_clk_div6_reparent_clk_ops = {
+static struct sh_clk_ops sh_clk_div6_reparent_clk_ops = {
 	.recalc		= sh_clk_div6_recalc,
 	.round_rate	= sh_clk_div_round_rate,
 	.set_rate	= sh_clk_div6_set_rate,
@@ -200,7 +200,7 @@
 }
 
 static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
-					   struct clk_ops *ops)
+					   struct sh_clk_ops *ops)
 {
 	struct clk *clkp;
 	void *freq_table;
@@ -317,13 +317,13 @@
 	iowrite32(ioread32(clk->mapped_reg) | (1 << 8), clk->mapped_reg);
 }
 
-static struct clk_ops sh_clk_div4_clk_ops = {
+static struct sh_clk_ops sh_clk_div4_clk_ops = {
 	.recalc		= sh_clk_div4_recalc,
 	.set_rate	= sh_clk_div4_set_rate,
 	.round_rate	= sh_clk_div_round_rate,
 };
 
-static struct clk_ops sh_clk_div4_enable_clk_ops = {
+static struct sh_clk_ops sh_clk_div4_enable_clk_ops = {
 	.recalc		= sh_clk_div4_recalc,
 	.set_rate	= sh_clk_div4_set_rate,
 	.round_rate	= sh_clk_div_round_rate,
@@ -331,7 +331,7 @@
 	.disable	= sh_clk_div4_disable,
 };
 
-static struct clk_ops sh_clk_div4_reparent_clk_ops = {
+static struct sh_clk_ops sh_clk_div4_reparent_clk_ops = {
 	.recalc		= sh_clk_div4_recalc,
 	.set_rate	= sh_clk_div4_set_rate,
 	.round_rate	= sh_clk_div_round_rate,
@@ -341,7 +341,7 @@
 };
 
 static int __init sh_clk_div4_register_ops(struct clk *clks, int nr,
-			struct clk_div4_table *table, struct clk_ops *ops)
+			struct clk_div4_table *table, struct sh_clk_ops *ops)
 {
 	struct clk *clkp;
 	void *freq_table;
diff --git a/drivers/sh/intc/balancing.c b/drivers/sh/intc/balancing.c
index cec7a96..bc78080 100644
--- a/drivers/sh/intc/balancing.c
+++ b/drivers/sh/intc/balancing.c
@@ -9,7 +9,7 @@
  */
 #include "internals.h"
 
-static unsigned long dist_handle[NR_IRQS];
+static unsigned long dist_handle[INTC_NR_IRQS];
 
 void intc_balancing_enable(unsigned int irq)
 {
diff --git a/drivers/sh/intc/chip.c b/drivers/sh/intc/chip.c
index 7b246ef..012df26 100644
--- a/drivers/sh/intc/chip.c
+++ b/drivers/sh/intc/chip.c
@@ -2,13 +2,14 @@
  * IRQ chip definitions for INTC IRQs.
  *
  * Copyright (C) 2007, 2008 Magnus Damm
- * Copyright (C) 2009, 2010 Paul Mundt
+ * Copyright (C) 2009 - 2012 Paul Mundt
  *
  * 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/cpumask.h>
+#include <linux/bsearch.h>
 #include <linux/io.h>
 #include "internals.h"
 
@@ -58,11 +59,6 @@
 	}
 }
 
-static int intc_set_wake(struct irq_data *data, unsigned int on)
-{
-	return 0; /* allow wakeup, but setup hardware in intc_suspend() */
-}
-
 #ifdef CONFIG_SMP
 /*
  * This is held with the irq desc lock held, so we don't require any
@@ -78,7 +74,7 @@
 
 	cpumask_copy(data->affinity, cpumask);
 
-	return 0;
+	return IRQ_SET_MASK_OK_NOCOPY;
 }
 #endif
 
@@ -122,28 +118,12 @@
 					     unsigned int nr_hp,
 					     unsigned int irq)
 {
-	int i;
+	struct intc_handle_int key;
 
-	/*
-	 * this doesn't scale well, but...
-	 *
-	 * this function should only be used for cerain uncommon
-	 * operations such as intc_set_priority() and intc_set_type()
-	 * and in those rare cases performance doesn't matter that much.
-	 * keeping the memory footprint low is more important.
-	 *
-	 * one rather simple way to speed this up and still keep the
-	 * memory footprint down is to make sure the array is sorted
-	 * and then perform a bisect to lookup the irq.
-	 */
-	for (i = 0; i < nr_hp; i++) {
-		if ((hp + i)->irq != irq)
-			continue;
+	key.irq = irq;
+	key.handle = 0;
 
-		return hp + i;
-	}
-
-	return NULL;
+	return bsearch(&key, hp, nr_hp, sizeof(*hp), intc_handle_int_cmp);
 }
 
 int intc_set_priority(unsigned int irq, unsigned int prio)
@@ -223,10 +203,9 @@
 	.irq_mask_ack		= intc_mask_ack,
 	.irq_enable		= intc_enable,
 	.irq_disable		= intc_disable,
-	.irq_shutdown		= intc_disable,
 	.irq_set_type		= intc_set_type,
-	.irq_set_wake		= intc_set_wake,
 #ifdef CONFIG_SMP
 	.irq_set_affinity	= intc_set_affinity,
 #endif
+	.flags			= IRQCHIP_SKIP_SET_WAKE,
 };
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c
index e53e449..7e562cc 100644
--- a/drivers/sh/intc/core.c
+++ b/drivers/sh/intc/core.c
@@ -2,7 +2,7 @@
  * Shared interrupt handling code for IPR and INTC2 types of IRQs.
  *
  * Copyright (C) 2007, 2008 Magnus Damm
- * Copyright (C) 2009, 2010 Paul Mundt
+ * Copyright (C) 2009 - 2012 Paul Mundt
  *
  * Based on intc2.c and ipr.c
  *
@@ -31,18 +31,19 @@
 #include <linux/spinlock.h>
 #include <linux/radix-tree.h>
 #include <linux/export.h>
+#include <linux/sort.h>
 #include "internals.h"
 
 LIST_HEAD(intc_list);
 DEFINE_RAW_SPINLOCK(intc_big_lock);
-unsigned int nr_intc_controllers;
+static unsigned int nr_intc_controllers;
 
 /*
  * Default priority level
  * - this needs to be at least 2 for 5-bit priorities on 7780
  */
 static unsigned int default_prio_level = 2;	/* 2 - 16 */
-static unsigned int intc_prio_level[NR_IRQS];	/* for now */
+static unsigned int intc_prio_level[INTC_NR_IRQS];	/* for now */
 
 unsigned int intc_get_dfl_prio_level(void)
 {
@@ -267,6 +268,9 @@
 			k += save_reg(d, k, hw->prio_regs[i].set_reg, smp);
 			k += save_reg(d, k, hw->prio_regs[i].clr_reg, smp);
 		}
+
+		sort(d->prio, hw->nr_prio_regs, sizeof(*d->prio),
+		     intc_handle_int_cmp, NULL);
 	}
 
 	if (hw->sense_regs) {
@@ -277,6 +281,9 @@
 
 		for (i = 0; i < hw->nr_sense_regs; i++)
 			k += save_reg(d, k, hw->sense_regs[i].reg, 0);
+
+		sort(d->sense, hw->nr_sense_regs, sizeof(*d->sense),
+		     intc_handle_int_cmp, NULL);
 	}
 
 	if (hw->subgroups)
diff --git a/drivers/sh/intc/handle.c b/drivers/sh/intc/handle.c
index 057ce56..7863a44 100644
--- a/drivers/sh/intc/handle.c
+++ b/drivers/sh/intc/handle.c
@@ -13,7 +13,7 @@
 #include <linux/spinlock.h>
 #include "internals.h"
 
-static unsigned long ack_handle[NR_IRQS];
+static unsigned long ack_handle[INTC_NR_IRQS];
 
 static intc_enum __init intc_grp_id(struct intc_desc *desc,
 				    intc_enum enum_id)
@@ -172,9 +172,8 @@
 	return 0;
 }
 
-static unsigned int __init intc_ack_data(struct intc_desc *desc,
-					  struct intc_desc_int *d,
-					  intc_enum enum_id)
+static unsigned int intc_ack_data(struct intc_desc *desc,
+				  struct intc_desc_int *d, intc_enum enum_id)
 {
 	struct intc_mask_reg *mr = desc->hw.ack_regs;
 	unsigned int i, j, fn, mode;
diff --git a/drivers/sh/intc/internals.h b/drivers/sh/intc/internals.h
index b0e9155..f034a97 100644
--- a/drivers/sh/intc/internals.h
+++ b/drivers/sh/intc/internals.h
@@ -108,6 +108,14 @@
 #endif
 }
 
+static inline int intc_handle_int_cmp(const void *a, const void *b)
+{
+	const struct intc_handle_int *_a = a;
+	const struct intc_handle_int *_b = b;
+
+	return _a->irq - _b->irq;
+}
+
 /* access.c */
 extern unsigned long
 (*intc_reg_fns[])(unsigned long addr, unsigned long h, unsigned long data);
@@ -157,7 +165,6 @@
 /* core.c */
 extern struct list_head intc_list;
 extern raw_spinlock_t intc_big_lock;
-extern unsigned int nr_intc_controllers;
 extern struct bus_type intc_subsys;
 
 unsigned int intc_get_dfl_prio_level(void);
diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c
index c7ec49f..93cec21 100644
--- a/drivers/sh/intc/virq.c
+++ b/drivers/sh/intc/virq.c
@@ -17,7 +17,7 @@
 #include <linux/export.h>
 #include "internals.h"
 
-static struct intc_map_entry intc_irq_xlate[NR_IRQS];
+static struct intc_map_entry intc_irq_xlate[INTC_NR_IRQS];
 
 struct intc_virq_list {
 	unsigned int irq;
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 0b06e36..3ed7483 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -293,7 +293,7 @@
 
 config SPI_S3C24XX
 	tristate "Samsung S3C24XX series SPI"
-	depends on ARCH_S3C2410 && EXPERIMENTAL
+	depends on ARCH_S3C24XX && EXPERIMENTAL
 	select SPI_BITBANG
 	help
 	  SPI driver for Samsung S3C24XX series ARM SoCs
diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
index 8418eb0..b9f0192 100644
--- a/drivers/spi/spi-dw-mid.c
+++ b/drivers/spi/spi-dw-mid.c
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
+#include <linux/types.h>
 
 #include "spi-dw.h"
 
@@ -136,6 +137,7 @@
 	txconf.dst_maxburst = LNW_DMA_MSIZE_16;
 	txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 	txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+	txconf.device_fc = false;
 
 	txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
 				       (unsigned long) &txconf);
@@ -144,7 +146,7 @@
 	dws->tx_sgl.dma_address = dws->tx_dma;
 	dws->tx_sgl.length = dws->len;
 
-	txdesc = txchan->device->device_prep_slave_sg(txchan,
+	txdesc = dmaengine_prep_slave_sg(txchan,
 				&dws->tx_sgl,
 				1,
 				DMA_MEM_TO_DEV,
@@ -158,6 +160,7 @@
 	rxconf.src_maxburst = LNW_DMA_MSIZE_16;
 	rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 	rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+	rxconf.device_fc = false;
 
 	rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
 				       (unsigned long) &rxconf);
@@ -166,7 +169,7 @@
 	dws->rx_sgl.dma_address = dws->rx_dma;
 	dws->rx_sgl.length = dws->len;
 
-	rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
+	rxdesc = dmaengine_prep_slave_sg(rxchan,
 				&dws->rx_sgl,
 				1,
 				DMA_DEV_TO_MEM,
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index 082458d..d1a495f 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -63,12 +63,6 @@
 };
 
 #ifdef CONFIG_DEBUG_FS
-static int spi_show_regs_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 #define SPI_REGS_BUFSIZE	1024
 static ssize_t  spi_show_regs(struct file *file, char __user *user_buf,
 				size_t count, loff_t *ppos)
@@ -128,7 +122,7 @@
 
 static const struct file_operations mrst_spi_regs_ops = {
 	.owner		= THIS_MODULE,
-	.open		= spi_show_regs_open,
+	.open		= simple_open,
 	.read		= spi_show_regs,
 	.llseek		= default_llseek,
 };
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index d46e55c..6db2887 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -633,8 +633,8 @@
 	if (!nents)
 		return ERR_PTR(-ENOMEM);
 
-	txd = chan->device->device_prep_slave_sg(chan, sgt->sgl, nents,
-						 slave_dirn, DMA_CTRL_ACK);
+	txd = dmaengine_prep_slave_sg(chan, sgt->sgl, nents,
+					slave_dirn, DMA_CTRL_ACK);
 	if (!txd) {
 		dma_unmap_sg(chan->device->dev, sgt->sgl, sgt->nents, dir);
 		return ERR_PTR(-ENOMEM);
diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c
index 610f739..9b0d716 100644
--- a/drivers/spi/spi-omap-uwire.c
+++ b/drivers/spi/spi-omap-uwire.c
@@ -47,7 +47,6 @@
 #include <linux/spi/spi_bitbang.h>
 #include <linux/module.h>
 
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/io.h>
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 13448c8..e496f79 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -359,11 +359,6 @@
 
 	orion_spi = spi_master_get_devdata(spi->master);
 
-	/* Fix ac timing if required.   */
-	if (orion_spi->spi_info->enable_clock_fix)
-		orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
-				  (1 << 14));
-
 	if ((spi->max_speed_hz == 0)
 			|| (spi->max_speed_hz > orion_spi->max_speed))
 		spi->max_speed_hz = orion_spi->max_speed;
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index dc8485d..96f0da6 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -880,10 +880,12 @@
 	struct dma_slave_config rx_conf = {
 		.src_addr = SSP_DR(pl022->phybase),
 		.direction = DMA_DEV_TO_MEM,
+		.device_fc = false,
 	};
 	struct dma_slave_config tx_conf = {
 		.dst_addr = SSP_DR(pl022->phybase),
 		.direction = DMA_MEM_TO_DEV,
+		.device_fc = false,
 	};
 	unsigned int pages;
 	int ret;
@@ -1017,7 +1019,7 @@
 		goto err_tx_sgmap;
 
 	/* Send both scatterlists */
-	rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
+	rxdesc = dmaengine_prep_slave_sg(rxchan,
 				      pl022->sgt_rx.sgl,
 				      rx_sglen,
 				      DMA_DEV_TO_MEM,
@@ -1025,7 +1027,7 @@
 	if (!rxdesc)
 		goto err_rxdesc;
 
-	txdesc = txchan->device->device_prep_slave_sg(txchan,
+	txdesc = dmaengine_prep_slave_sg(txchan,
 				      pl022->sgt_tx.sgl,
 				      tx_sglen,
 				      DMA_MEM_TO_DEV,
diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c
index fc06453..8ee7d79 100644
--- a/drivers/spi/spi-s3c24xx.c
+++ b/drivers/spi/spi-s3c24xx.c
@@ -24,10 +24,10 @@
 
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
+#include <linux/spi/s3c24xx.h>
 #include <linux/module.h>
 
 #include <plat/regs-spi.h>
-#include <mach/spi.h>
 
 #include <plat/fiq.h>
 #include <asm/fiq.h>
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index 5c6fa5e..ec47d3b 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -1099,7 +1099,7 @@
 		sg_dma_address(sg) = dma->rx_buf_dma + sg->offset;
 	}
 	sg = dma->sg_rx_p;
-	desc_rx = dma->chan_rx->device->device_prep_slave_sg(dma->chan_rx, sg,
+	desc_rx = dmaengine_prep_slave_sg(dma->chan_rx, sg,
 					num, DMA_DEV_TO_MEM,
 					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc_rx) {
@@ -1158,7 +1158,7 @@
 		sg_dma_address(sg) = dma->tx_buf_dma + sg->offset;
 	}
 	sg = dma->sg_tx_p;
-	desc_tx = dma->chan_tx->device->device_prep_slave_sg(dma->chan_tx,
+	desc_tx = dmaengine_prep_slave_sg(dma->chan_tx,
 					sg, num, DMA_MEM_TO_DEV,
 					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc_tx) {
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index f1abfb1..97d412d 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -64,8 +64,6 @@
 
 source "drivers/staging/line6/Kconfig"
 
-source "drivers/gpu/drm/nouveau/Kconfig"
-
 source "drivers/staging/octeon/Kconfig"
 
 source "drivers/staging/serqt_usb2/Kconfig"
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 59e0953..c283212 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -381,8 +381,7 @@
 
 repeat:
 	fdt = files_fdtable(files);
-	fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds,
-				files->next_fd);
+	fd = find_next_zero_bit(fdt->open_fds, fdt->max_fds, files->next_fd);
 
 	/*
 	 * N.B. For clone tasks sharing a files structure, this test
@@ -410,11 +409,11 @@
 		goto repeat;
 	}
 
-	FD_SET(fd, fdt->open_fds);
+	__set_open_fd(fd, fdt);
 	if (flags & O_CLOEXEC)
-		FD_SET(fd, fdt->close_on_exec);
+		__set_close_on_exec(fd, fdt);
 	else
-		FD_CLR(fd, fdt->close_on_exec);
+		__clear_close_on_exec(fd, fdt);
 	files->next_fd = fd + 1;
 #if 1
 	/* Sanity check */
@@ -455,7 +454,7 @@
 static void __put_unused_fd(struct files_struct *files, unsigned int fd)
 {
 	struct fdtable *fdt = files_fdtable(files);
-	__FD_CLR(fd, fdt->open_fds);
+	__clear_open_fd(fd, fdt);
 	if (fd < files->next_fd)
 		files->next_fd = fd;
 }
@@ -481,7 +480,7 @@
 	if (!filp)
 		goto out_unlock;
 	rcu_assign_pointer(fdt->fd[fd], NULL);
-	FD_CLR(fd, fdt->close_on_exec);
+	__clear_close_on_exec(fd, fdt);
 	__put_unused_fd(files, fd);
 	spin_unlock(&files->file_lock);
 	retval = filp_close(filp, files);
diff --git a/drivers/staging/asus_oled/README b/drivers/staging/asus_oled/README
index 0d82a6d..2d72123 100644
--- a/drivers/staging/asus_oled/README
+++ b/drivers/staging/asus_oled/README
@@ -52,7 +52,7 @@
 
    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.conf:
+   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
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index db1fd63..bf185e2 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -42,7 +42,6 @@
 #include <linux/cdev.h>
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
-#include <asm/system.h>
 
 #include "comedidev.h"
 #include "internal.h"
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index c9e8c47..915157d 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -86,7 +86,6 @@
 #include "../comedidev.h"
 #include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <asm/system.h>
 
 #include "comedi_pci.h"
 #include "8253.h"
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index fd274e9..13e9c80 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -55,7 +55,6 @@
 #include "comedi_pci.h"
 #include "../comedidev.h"
 
-#include <asm/system.h>
 
 #define PCI_MITE_SIZE		4096
 #define PCI_DAQ_SIZE		4096
diff --git a/drivers/staging/crystalhd/bc_dts_defs.h b/drivers/staging/crystalhd/bc_dts_defs.h
index 8cd51a7..647e116 100644
--- a/drivers/staging/crystalhd/bc_dts_defs.h
+++ b/drivers/staging/crystalhd/bc_dts_defs.h
@@ -26,6 +26,8 @@
 #ifndef _BC_DTS_DEFS_H_
 #define _BC_DTS_DEFS_H_
 
+#include <linux/types.h>
+
 /* BIT Mask */
 #define BC_BIT(_x)		(1 << (_x))
 
diff --git a/drivers/staging/crystalhd/crystalhd.h b/drivers/staging/crystalhd/crystalhd.h
index 3f4d795..b3a550b 100644
--- a/drivers/staging/crystalhd/crystalhd.h
+++ b/drivers/staging/crystalhd/crystalhd.h
@@ -1,7 +1,6 @@
 #ifndef _CRYSTALHD_H_
 #define _CRYSTALHD_H_
 
-#include <asm/system.h>
 #include "bc_dts_defs.h"
 #include "crystalhd_misc.h"
 #include "bc_dts_glob_lnx.h"
diff --git a/drivers/staging/crystalhd/crystalhd_lnx.h b/drivers/staging/crystalhd/crystalhd_lnx.h
index a81f929..a9e3633 100644
--- a/drivers/staging/crystalhd/crystalhd_lnx.h
+++ b/drivers/staging/crystalhd/crystalhd_lnx.h
@@ -45,7 +45,6 @@
 #include <linux/io.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <linux/uaccess.h>
 
 #include "crystalhd.h"
diff --git a/drivers/staging/crystalhd/crystalhd_misc.h b/drivers/staging/crystalhd/crystalhd_misc.h
index 84c8793..8cdaa7a 100644
--- a/drivers/staging/crystalhd/crystalhd_misc.h
+++ b/drivers/staging/crystalhd/crystalhd_misc.h
@@ -37,6 +37,7 @@
 #include <linux/ioctl.h>
 #include <linux/dma-mapping.h>
 #include <linux/sched.h>
+#include "bc_dts_glob_lnx.h"
 
 /* Global log level variable defined in crystal_misc.c file */
 extern uint32_t g_linklog_level;
diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c
index 3f919ba..886f565 100644
--- a/drivers/staging/et131x/et131x.c
+++ b/drivers/staging/et131x/et131x.c
@@ -70,7 +70,6 @@
 #include <linux/delay.h>
 #include <linux/bitops.h>
 #include <linux/io.h>
-#include <asm/system.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
index 7569aa0..c4a8a0a 100644
--- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
+++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
@@ -29,7 +29,6 @@
 #include <linux/interrupt.h>
 #include <linux/in.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/bitops.h>
 
 #include <linux/netdevice.h>
diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c
index c0ca709..02cc234 100644
--- a/drivers/staging/iio/gyro/adis16060_core.c
+++ b/drivers/staging/iio/gyro/adis16060_core.c
@@ -14,7 +14,6 @@
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
-#include <linux/module.h>
 
 #include "../iio.h"
 #include "../sysfs.h"
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index 7e5caa3..4f4b7d6 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -6,7 +6,7 @@
 	  don't have the "normal" Linux kernel quality level.
 	  Most of them don't follow properly the V4L, DVB and/or RC API's,
 	  so, they won't likely work fine with the existing applications.
-	  That also means that, one fixed, their API's will change to match
+	  That also means that, once fixed, their API's will change to match
 	  the existing ones.
 
           If you wish to work on these drivers, to help improve them, or
diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c
index aae0505..ea4f992 100644
--- a/drivers/staging/media/as102/as102_drv.c
+++ b/drivers/staging/media/as102/as102_drv.c
@@ -27,7 +27,7 @@
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 
-/* header file for Usb device driver*/
+/* header file for usb device driver*/
 #include "as102_drv.h"
 #include "as102_fw.h"
 #include "dvbdev.h"
diff --git a/drivers/staging/media/as102/as102_drv.h b/drivers/staging/media/as102/as102_drv.h
index 957f0ed..b0e5a23 100644
--- a/drivers/staging/media/as102/as102_drv.h
+++ b/drivers/staging/media/as102/as102_drv.h
@@ -76,7 +76,7 @@
 	struct as10x_bus_adapter_t bus_adap;
 	struct list_head device_entry;
 	struct kref kref;
-	unsigned long minor;
+	uint8_t elna_cfg;
 
 	struct dvb_adapter dvb_adap;
 	struct dvb_frontend dvb_fe;
diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c
index bdc5a38..5917657 100644
--- a/drivers/staging/media/as102/as102_fe.c
+++ b/drivers/staging/media/as102/as102_fe.c
@@ -265,7 +265,7 @@
 
 	if (acquire) {
 		if (elna_enable)
-			as10x_cmd_set_context(&dev->bus_adap, 1010, 0xC0);
+			as10x_cmd_set_context(&dev->bus_adap, CONTEXT_LNA, dev->elna_cfg);
 
 		ret = as10x_cmd_turn_on(&dev->bus_adap);
 	} else {
@@ -337,7 +337,7 @@
 	strncpy(dvb_fe->ops.info.name, as102_dev->name,
 		sizeof(dvb_fe->ops.info.name));
 
-	/* register dbvb frontend */
+	/* register dvb frontend */
 	errno = dvb_register_frontend(dvb_adap, dvb_fe);
 	if (errno == 0)
 		dvb_fe->tuner_priv = as102_dev;
@@ -349,7 +349,7 @@
 					 struct as10x_tps *as10x_tps)
 {
 
-	/* extract consteallation */
+	/* extract constellation */
 	switch (as10x_tps->modulation) {
 	case CONST_QPSK:
 		fe_tps->modulation = QPSK;
diff --git a/drivers/staging/media/as102/as102_fw.h b/drivers/staging/media/as102/as102_fw.h
index bd21f05..4bfc684 100644
--- a/drivers/staging/media/as102/as102_fw.h
+++ b/drivers/staging/media/as102/as102_fw.h
@@ -29,7 +29,7 @@
 	union {
 		unsigned char request[2];
 		unsigned char length[2];
-	} u;
+	} __packed u;
 	struct as10x_raw_fw_pkt raw;
 } __packed;
 
diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c
index d775be0..0f6bfe7 100644
--- a/drivers/staging/media/as102/as102_usb_drv.c
+++ b/drivers/staging/media/as102/as102_usb_drv.c
@@ -57,6 +57,17 @@
 	NULL /* Terminating entry */
 };
 
+/* eLNA configuration: devices built on the reference design work best
+   with 0xA0, while custom designs seem to require 0xC0 */
+static uint8_t const as102_elna_cfg[] = {
+	0xA0,
+	0xC0,
+	0xC0,
+	0xA0,
+	0xA0,
+	0x00 /* Terminating entry */
+};
+
 struct usb_driver as102_usb_driver = {
 	.name		= DRIVER_FULL_NAME,
 	.probe		= as102_usb_probe,
@@ -270,6 +281,8 @@
 		}
 
 		urb->transfer_buffer = dev->stream + (i * AS102_USB_BUF_SIZE);
+		urb->transfer_dma = dev->dma_addr + (i * AS102_USB_BUF_SIZE);
+		urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
 		urb->transfer_buffer_length = AS102_USB_BUF_SIZE;
 
 		dev->stream_urb[i] = urb;
@@ -369,8 +382,10 @@
 	/* Assign the user-friendly device name */
 	for (i = 0; i < (sizeof(as102_usb_id_table) /
 			 sizeof(struct usb_device_id)); i++) {
-		if (id == &as102_usb_id_table[i])
+		if (id == &as102_usb_id_table[i]) {
 			as102_dev->name = as102_device_names[i];
+			as102_dev->elna_cfg = as102_elna_cfg[i];
+		}
 	}
 
 	if (as102_dev->name == NULL)
diff --git a/drivers/staging/media/as102/as10x_cmd.h b/drivers/staging/media/as102/as10x_cmd.h
index 4ea249e..e21ec6c 100644
--- a/drivers/staging/media/as102/as10x_cmd.h
+++ b/drivers/staging/media/as102/as10x_cmd.h
@@ -99,14 +99,14 @@
 	struct {
 		/* request identifier */
 		uint16_t proc_id;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
 		uint16_t proc_id;
 		/* error */
 		uint8_t error;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_turn_off {
@@ -114,14 +114,14 @@
 	struct {
 		/* request identifier */
 		uint16_t proc_id;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
 		uint16_t proc_id;
 		/* error */
 		uint8_t err;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_set_tune {
@@ -131,14 +131,14 @@
 		uint16_t proc_id;
 		/* tune params */
 		struct as10x_tune_args args;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
 		uint16_t proc_id;
 		/* response error */
 		uint8_t error;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_get_tune_status {
@@ -146,7 +146,7 @@
 	struct {
 		/* request identifier */
 		uint16_t proc_id;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
@@ -155,7 +155,7 @@
 		uint8_t error;
 		/* tune status */
 		struct as10x_tune_status sts;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_get_tps {
@@ -163,7 +163,7 @@
 	struct {
 		/* request identifier */
 		uint16_t proc_id;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
@@ -172,7 +172,7 @@
 		uint8_t error;
 		/* tps details */
 		struct as10x_tps tps;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_common {
@@ -180,14 +180,14 @@
 	struct {
 		/* request identifier */
 		uint16_t  proc_id;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
 		uint16_t proc_id;
 		/* response error */
 		uint8_t error;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_add_pid_filter {
@@ -201,7 +201,7 @@
 		uint8_t stream_type;
 		/* PID index in filter table */
 		uint8_t idx;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
@@ -210,7 +210,7 @@
 		uint8_t error;
 		/* Filter id */
 		uint8_t filter_id;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_del_pid_filter {
@@ -220,14 +220,14 @@
 		uint16_t  proc_id;
 		/* PID to remove */
 		uint16_t  pid;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
 		uint16_t proc_id;
 		/* response error */
 		uint8_t error;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_start_streaming {
@@ -235,14 +235,14 @@
 	struct {
 		/* request identifier */
 		uint16_t proc_id;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
 		uint16_t proc_id;
 		/* error */
 		uint8_t error;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_stop_streaming {
@@ -250,14 +250,14 @@
 	struct {
 		/* request identifier */
 		uint16_t proc_id;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
 		uint16_t proc_id;
 		/* error */
 		uint8_t error;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_get_demod_stats {
@@ -265,7 +265,7 @@
 	struct {
 		/* request identifier */
 		uint16_t proc_id;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
@@ -274,7 +274,7 @@
 		uint8_t error;
 		/* demod stats */
 		struct as10x_demod_stats stats;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_get_impulse_resp {
@@ -282,7 +282,7 @@
 	struct {
 		/* request identifier */
 		uint16_t proc_id;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
@@ -291,7 +291,7 @@
 		uint8_t error;
 		/* impulse response ready */
 		uint8_t is_ready;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_fw_context {
@@ -305,7 +305,7 @@
 		uint16_t tag;
 		/* context request type */
 		uint16_t type;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
@@ -316,7 +316,7 @@
 		uint16_t type;
 		/* error */
 		uint8_t error;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_set_register {
@@ -328,14 +328,14 @@
 		struct as10x_register_addr reg_addr;
 		/* register content */
 		struct as10x_register_value reg_val;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
 		uint16_t proc_id;
 		/* error */
 		uint8_t error;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_get_register {
@@ -345,7 +345,7 @@
 		uint16_t proc_id;
 		/* register description */
 		struct as10x_register_addr reg_addr;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
@@ -354,7 +354,7 @@
 		uint8_t error;
 		/* register content */
 		struct as10x_register_value reg_val;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_cfg_change_mode {
@@ -364,14 +364,14 @@
 		uint16_t proc_id;
 		/* mode */
 		uint8_t mode;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
 		uint16_t proc_id;
 		/* error */
 		uint8_t error;
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 struct as10x_cmd_header_t {
@@ -394,7 +394,7 @@
 		struct as10x_register_addr reg_addr;
 		/* nb blocks to read */
 		uint16_t num_blocks;
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		/* response identifier */
@@ -408,8 +408,8 @@
 			uint8_t  data8[DUMP_BLOCK_SIZE];
 			uint16_t data16[DUMP_BLOCK_SIZE / sizeof(uint16_t)];
 			uint32_t data32[DUMP_BLOCK_SIZE / sizeof(uint32_t)];
-		} u;
-	} rsp;
+		} __packed u;
+	} __packed rsp;
 } __packed;
 
 union as10x_dumplog_memory {
@@ -418,7 +418,7 @@
 		uint16_t proc_id;
 		/* dump memory type request */
 		uint8_t dump_req;
-	} req;
+	} __packed req;
 	struct {
 		/* request identifier */
 		uint16_t proc_id;
@@ -428,7 +428,7 @@
 		uint8_t dump_rsp;
 		/* dump data */
 		uint8_t data[DUMP_BLOCK_SIZE];
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 union as10x_raw_data {
@@ -437,14 +437,14 @@
 		uint16_t proc_id;
 		uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
 			     - 2 /* proc_id */];
-	} req;
+	} __packed req;
 	/* response */
 	struct {
 		uint16_t proc_id;
 		uint8_t error;
 		uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
 			     - 2 /* proc_id */ - 1 /* rc */];
-	} rsp;
+	} __packed rsp;
 } __packed;
 
 struct as10x_cmd_t {
@@ -469,7 +469,7 @@
 		union as10x_dump_memory		dump_memory;
 		union as10x_dumplog_memory	dumplog_memory;
 		union as10x_raw_data		raw_data;
-	} body;
+	} __packed body;
 } __packed;
 
 struct as10x_token_cmd_t {
diff --git a/drivers/staging/media/as102/as10x_types.h b/drivers/staging/media/as102/as10x_types.h
index fde8140..af26e05 100644
--- a/drivers/staging/media/as102/as10x_types.h
+++ b/drivers/staging/media/as102/as10x_types.h
@@ -181,7 +181,7 @@
 		uint8_t  value8;   /* 8 bit value */
 		uint16_t value16;  /* 16 bit value */
 		uint32_t value32;  /* 32 bit value */
-	} u;
+	} __packed u;
 } __packed;
 
 struct as10x_register_addr {
diff --git a/drivers/staging/media/easycap/easycap_main.c b/drivers/staging/media/easycap/easycap_main.c
index 3d439b7..d0fe34a 100644
--- a/drivers/staging/media/easycap/easycap_main.c
+++ b/drivers/staging/media/easycap/easycap_main.c
@@ -2849,13 +2849,11 @@
 	.poll		= easycap_poll,
 	.mmap		= easycap_mmap,
 };
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
+
 /*
- *  WHEN THE EasyCAP IS PHYSICALLY PLUGGED IN, THIS FUNCTION IS CALLED THREE
- *  TIMES, ONCE FOR EACH OF THE THREE INTERFACES.  BEWARE.
+ * When the device is plugged, this function is called three times,
+ * one for each interface.
  */
-/*---------------------------------------------------------------------------*/
 static int easycap_usb_probe(struct usb_interface *intf,
 			    const struct usb_device_id *id)
 {
@@ -2884,7 +2882,6 @@
 
 	usbdev = interface_to_usbdev(intf);
 
-/*---------------------------------------------------------------------------*/
 	alt = usb_altnum_to_altsetting(intf, 0);
 	if (!alt) {
 		SAY("ERROR: usb_host_interface not found\n");
@@ -2896,11 +2893,8 @@
 		SAY("ERROR: intf_descriptor is NULL\n");
 		return -EFAULT;
 	}
-/*---------------------------------------------------------------------------*/
-/*
- *  GET PROPERTIES OF PROBED INTERFACE
- */
-/*---------------------------------------------------------------------------*/
+
+	/* Get properties of probed interface */
 	bInterfaceNumber = interface->bInterfaceNumber;
 	bInterfaceClass = interface->bInterfaceClass;
 	bInterfaceSubClass = interface->bInterfaceSubClass;
@@ -2912,28 +2906,23 @@
 		(long int)(intf->cur_altsetting - intf->altsetting));
 	JOT(4, "intf[%i]: bInterfaceClass=0x%02X bInterfaceSubClass=0x%02X\n",
 			bInterfaceNumber, bInterfaceClass, bInterfaceSubClass);
-/*---------------------------------------------------------------------------*/
-/*
- *  A NEW struct easycap IS ALWAYS ALLOCATED WHEN INTERFACE 0 IS PROBED.
- *  IT IS NOT POSSIBLE HERE TO FREE ANY EXISTING struct easycap.  THIS
- *  SHOULD HAVE BEEN DONE BY easycap_delete() WHEN THE EasyCAP WAS
- *  PHYSICALLY UNPLUGGED.
- *
- *  THE POINTER peasycap TO THE struct easycap IS REMEMBERED WHEN
- *  INTERFACES 1 AND 2 ARE PROBED.
-*/
-/*---------------------------------------------------------------------------*/
+
+	/*
+	 * A new struct easycap is always allocated when interface 0 is probed.
+	 * It is not possible here to free any existing struct easycap.
+	 * This should have been done by easycap_delete() when the device was
+	 * physically unplugged.
+	 * The allocated struct easycap is saved for later usage when
+	 * interfaces 1 and 2 are probed.
+	 */
 	if (0 == bInterfaceNumber) {
 		peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
 		if (!peasycap) {
 			SAY("ERROR: Could not allocate peasycap\n");
 			return -ENOMEM;
 		}
-/*---------------------------------------------------------------------------*/
-/*
- *  PERFORM URGENT INTIALIZATIONS ...
-*/
-/*---------------------------------------------------------------------------*/
+
+		/* Perform urgent initializations */
 		peasycap->minor = -1;
 		kref_init(&peasycap->kref);
 		JOM(8, "intf[%i]: after kref_init(..._video) "
@@ -2976,11 +2965,7 @@
 
 		peasycap->allocation_video_struct = sizeof(struct easycap);
 
-/*---------------------------------------------------------------------------*/
-/*
- *  ... AND FURTHER INITIALIZE THE STRUCTURE
-*/
-/*---------------------------------------------------------------------------*/
+		/* and further initialize the structure */
 		peasycap->pusb_device = usbdev;
 		peasycap->pusb_interface = intf;
 
@@ -3002,11 +2987,7 @@
 
 		peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
 
-/*---------------------------------------------------------------------------*/
-/*
- *  DYNAMICALLY FILL IN THE AVAILABLE FORMATS ...
- */
-/*---------------------------------------------------------------------------*/
+		/* Dynamically fill in the available formats */
 		rc = easycap_video_fillin_formats();
 		if (0 > rc) {
 			SAM("ERROR: fillin_formats() rc = %i\n", rc);
@@ -3014,10 +2995,8 @@
 		}
 		JOM(4, "%i formats available\n", rc);
 
-		/*  ... AND POPULATE easycap.inputset[] */
-
+		/* Populate easycap.inputset[] */
 		inputset = peasycap->inputset;
-
 		fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN;
 		m = 0;
 		mask = 0;
@@ -3030,7 +3009,6 @@
 				mask = easycap_standard[i].mask;
 			}
 		}
-
 		if (1 != m) {
 			SAM("ERROR: "
 			    "inputset->standard_offset unpopulated, %i=m\n", m);
@@ -3089,14 +3067,13 @@
 		JOM(4, "populated inputset[]\n");
 		JOM(4, "finished initialization\n");
 	} else {
-/*---------------------------------------------------------------------------*/
-/*
- *                                 FIXME
- *
- *  IDENTIFY THE APPROPRIATE POINTER peasycap FOR INTERFACES 1 AND 2.
- *  THE ADDRESS OF peasycap->pusb_device IS RELUCTANTLY USED FOR THIS PURPOSE.
- */
-/*---------------------------------------------------------------------------*/
+
+		/*
+		 * FIXME: Identify the appropriate pointer
+		 * peasycap for interfaces 1 and 2.
+		 * The address of peasycap->pusb_device
+		 * is reluctantly used for this purpose.
+		 */
 		for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
 			if (usbdev == easycapdc60_dongle[ndong].peasycap->
 									pusb_device) {
@@ -3117,7 +3094,7 @@
 			return -ENODEV;
 		}
 	}
-/*---------------------------------------------------------------------------*/
+
 	if ((USB_CLASS_VIDEO == bInterfaceClass) ||
 	    (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
 		if (-1 == peasycap->video_interface) {
@@ -3149,14 +3126,12 @@
 			}
 		}
 	}
-/*---------------------------------------------------------------------------*/
-/*
- *  INVESTIGATE ALL ALTSETTINGS.
- *  DONE IN DETAIL BECAUSE USB DEVICE 05e1:0408 HAS DISPARATE INCARNATIONS.
- */
-/*---------------------------------------------------------------------------*/
-	isokalt = 0;
 
+	/*
+	 * Investigate all altsettings. This is done in detail
+	 * because USB device 05e1:0408 has disparate incarnations.
+	 */
+	isokalt = 0;
 	for (i = 0; i < intf->num_altsetting; i++) {
 		alt = usb_altnum_to_altsetting(intf, i);
 		if (!alt) {
@@ -3172,7 +3147,6 @@
 		if (0 == interface->bNumEndpoints)
 			JOM(4, "intf[%i]alt[%i] has no endpoints\n",
 						bInterfaceNumber, i);
-/*---------------------------------------------------------------------------*/
 		for (j = 0; j < interface->bNumEndpoints; j++) {
 			ep = &alt->endpoint[j].desc;
 			if (!ep) {
@@ -3312,19 +3286,12 @@
 			}
 		}
 	}
-/*---------------------------------------------------------------------------*/
-/*
- *  PERFORM INITIALIZATION OF THE PROBED INTERFACE
- */
-/*---------------------------------------------------------------------------*/
+
+	/* Perform initialization of the probed interface */
 	JOM(4, "initialization begins for interface %i\n",
 		interface->bInterfaceNumber);
 	switch (bInterfaceNumber) {
-/*---------------------------------------------------------------------------*/
-/*
- *  INTERFACE 0 IS THE VIDEO INTERFACE
- */
-/*---------------------------------------------------------------------------*/
+	/* 0: Video interface */
 	case 0: {
 		if (!peasycap) {
 			SAM("MISTAKE: peasycap is NULL\n");
@@ -3337,11 +3304,8 @@
 		peasycap->video_altsetting_on = okalt[isokalt - 1];
 		JOM(4, "%i=video_altsetting_on <====\n",
 					peasycap->video_altsetting_on);
-/*---------------------------------------------------------------------------*/
-/*
- *  DECIDE THE VIDEO STREAMING PARAMETERS
- */
-/*---------------------------------------------------------------------------*/
+
+		/* Decide video streaming parameters */
 		peasycap->video_endpointnumber = okepn[isokalt - 1];
 		JOM(4, "%i=video_endpointnumber\n", peasycap->video_endpointnumber);
 		maxpacketsize = okmps[isokalt - 1];
@@ -3373,7 +3337,6 @@
 			SAM("MISTAKE: peasycap->video_isoc_buffer_size too big\n");
 			return -EFAULT;
 		}
-/*---------------------------------------------------------------------------*/
 		if (-1 == peasycap->video_interface) {
 			SAM("MISTAKE:  video_interface is unset\n");
 			return -EFAULT;
@@ -3398,14 +3361,13 @@
 			SAM("MISTAKE:  video_isoc_buffer_size is unset\n");
 			return -EFAULT;
 		}
-/*---------------------------------------------------------------------------*/
-/*
- *  ALLOCATE MEMORY FOR VIDEO BUFFERS.  LISTS MUST BE INITIALIZED FIRST.
- */
-/*---------------------------------------------------------------------------*/
+
+		/*
+		 * Allocate memory for video buffers.
+		 * Lists must be initialized first.
+		 */
 		INIT_LIST_HEAD(&(peasycap->urb_video_head));
 		peasycap->purb_video_head = &(peasycap->urb_video_head);
-/*---------------------------------------------------------------------------*/
 		JOM(4, "allocating %i frame buffers of size %li\n",
 				FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
 		JOM(4, ".... each scattered over %li pages\n",
@@ -3436,7 +3398,6 @@
 		peasycap->frame_read = 0;
 		JOM(4, "allocation of frame buffers done:  %i pages\n", k *
 									m);
-/*---------------------------------------------------------------------------*/
 		JOM(4, "allocating %i field buffers of size %li\n",
 				FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
 		JOM(4, ".... each scattered over %li pages\n",
@@ -3468,7 +3429,6 @@
 		peasycap->field_read = 0;
 		JOM(4, "allocation of field buffers done:  %i pages\n", k *
 									m);
-/*---------------------------------------------------------------------------*/
 		JOM(4, "allocating %i isoc video buffers of size %i\n",
 						VIDEO_ISOC_BUFFER_MANY,
 						peasycap->video_isoc_buffer_size);
@@ -3492,11 +3452,8 @@
 		}
 		JOM(4, "allocation of isoc video buffers done: %i pages\n",
 						k * (0x01 << VIDEO_ISOC_ORDER));
-/*---------------------------------------------------------------------------*/
-/*
- *  ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
- */
-/*---------------------------------------------------------------------------*/
+
+		/* Allocate and initialize multiple struct usb */
 		JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
 		JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n",
 						peasycap->video_isoc_framesperdesc);
@@ -3515,7 +3472,6 @@
 			}
 
 			peasycap->allocation_video_urb += 1;
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 			pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
 			if (!pdata_urb) {
 				SAM("ERROR: Could not allocate struct data_urb.\n");
@@ -3530,11 +3486,8 @@
 			pdata_urb->length = 0;
 			list_add_tail(&(pdata_urb->list_head),
 							peasycap->purb_video_head);
-/*---------------------------------------------------------------------------*/
-/*
- *  ... AND INITIALIZE THEM
- */
-/*---------------------------------------------------------------------------*/
+
+			/* Initialize allocated urbs */
 			if (!k) {
 				JOM(4, "initializing video urbs thus:\n");
 				JOM(4, "  purb->interval = 1;\n");
@@ -3582,20 +3535,16 @@
 			}
 		}
 		JOM(4, "allocation of %i struct urb done.\n", k);
-/*--------------------------------------------------------------------------*/
-/*
- *  SAVE POINTER peasycap IN THIS INTERFACE.
- */
-/*--------------------------------------------------------------------------*/
+
+		/* Save pointer peasycap in this interface */
 		usb_set_intfdata(intf, peasycap);
-/*---------------------------------------------------------------------------*/
-/*
- *  IT IS ESSENTIAL TO INITIALIZE THE HARDWARE BEFORE, RATHER THAN AFTER,
- *  THE DEVICE IS REGISTERED, BECAUSE SOME VERSIONS OF THE videodev MODULE
- *  CALL easycap_open() IMMEDIATELY AFTER REGISTRATION, CAUSING A CLASH.
- *  BEWARE.
-*/
-/*---------------------------------------------------------------------------*/
+
+		/*
+		 * It is essential to initialize the hardware before,
+		 * rather than after, the device is registered,
+		 * because some udev rules triggers easycap_open()
+		 * immediately after registration, causing a clash.
+		 */
 		peasycap->ntsc = easycap_ntsc;
 		JOM(8, "defaulting initially to %s\n",
 			easycap_ntsc ? "NTSC" : "PAL");
@@ -3604,27 +3553,20 @@
 			SAM("ERROR: reset() rc = %i\n", rc);
 			return -EFAULT;
 		}
-/*--------------------------------------------------------------------------*/
-/*
- *  THE VIDEO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
- */
-/*--------------------------------------------------------------------------*/
+
+		/* The video device can now be registered */
 		if (v4l2_device_register(&intf->dev, &peasycap->v4l2_device)) {
 			SAM("v4l2_device_register() failed\n");
 			return -ENODEV;
 		}
 		JOM(4, "registered device instance: %s\n",
 			peasycap->v4l2_device.name);
-/*---------------------------------------------------------------------------*/
-/*
- *                                 FIXME
- *
- *
- *  THIS IS BELIEVED TO BE HARMLESS, BUT MAY WELL BE UNNECESSARY OR WRONG:
-*/
-/*---------------------------------------------------------------------------*/
+
+		/*
+		 * FIXME: This is believed to be harmless,
+		 * but may well be unnecessary or wrong.
+		 */
 		peasycap->video_device.v4l2_dev = NULL;
-/*---------------------------------------------------------------------------*/
 
 
 		strcpy(&peasycap->video_device.name[0], "easycapdc60");
@@ -3648,28 +3590,19 @@
 
 		break;
 	}
-/*--------------------------------------------------------------------------*/
-/*
- *  INTERFACE 1 IS THE AUDIO CONTROL INTERFACE
- *  INTERFACE 2 IS THE AUDIO STREAMING INTERFACE
- */
-/*--------------------------------------------------------------------------*/
+	/* 1: Audio control */
 	case 1: {
 		if (!peasycap) {
 			SAM("MISTAKE: peasycap is NULL\n");
 			return -EFAULT;
 		}
-/*--------------------------------------------------------------------------*/
-/*
- *  SAVE POINTER peasycap IN INTERFACE 1
- */
-/*--------------------------------------------------------------------------*/
+		/* Save pointer peasycap in this interface */
 		usb_set_intfdata(intf, peasycap);
 		JOM(4, "no initialization required for interface %i\n",
 					interface->bInterfaceNumber);
 		break;
 	}
-/*--------------------------------------------------------------------------*/
+	/* 2: Audio streaming */
 	case 2: {
 		if (!peasycap) {
 			SAM("MISTAKE: peasycap is NULL\n");
@@ -3769,15 +3702,14 @@
 			SAM("MISTAKE:  audio_isoc_buffer_size is unset\n");
 			return -EFAULT;
 		}
-/*---------------------------------------------------------------------------*/
-/*
- *  ALLOCATE MEMORY FOR AUDIO BUFFERS.  LISTS MUST BE INITIALIZED FIRST.
- */
-/*---------------------------------------------------------------------------*/
+
+		/*
+		 * Allocate memory for audio buffers.
+		 * Lists must be initialized first.
+		 */
 		INIT_LIST_HEAD(&(peasycap->urb_audio_head));
 		peasycap->purb_audio_head = &(peasycap->urb_audio_head);
 
-/*---------------------------------------------------------------------------*/
 		JOM(4, "allocating %i isoc audio buffers of size %i\n",
 			AUDIO_ISOC_BUFFER_MANY,
 			peasycap->audio_isoc_buffer_size);
@@ -3800,11 +3732,8 @@
 			peasycap->audio_isoc_buffer[k].kount = k;
 		}
 		JOM(4, "allocation of isoc audio buffers done.\n");
-/*---------------------------------------------------------------------------*/
-/*
- *  ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
- */
-/*---------------------------------------------------------------------------*/
+
+		/* Allocate and initialize urbs */
 		JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
 		JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n",
 					peasycap->audio_isoc_framesperdesc);
@@ -3822,7 +3751,6 @@
 				return -ENOMEM;
 			}
 			peasycap->allocation_audio_urb += 1 ;
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 			pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
 			if (!pdata_urb) {
 				usb_free_urb(purb);
@@ -3837,11 +3765,7 @@
 			pdata_urb->length = 0;
 			list_add_tail(&(pdata_urb->list_head),
 							peasycap->purb_audio_head);
-/*---------------------------------------------------------------------------*/
-/*
- *  ... AND INITIALIZE THEM
- */
-/*---------------------------------------------------------------------------*/
+
 			if (!k) {
 				JOM(4, "initializing audio urbs thus:\n");
 				JOM(4, "  purb->interval = 1;\n");
@@ -3889,17 +3813,11 @@
 			}
 		}
 		JOM(4, "allocation of %i struct urb done.\n", k);
-/*---------------------------------------------------------------------------*/
-/*
- *  SAVE POINTER peasycap IN THIS INTERFACE.
- */
-/*---------------------------------------------------------------------------*/
+
+		/* Save pointer peasycap in this interface */
 		usb_set_intfdata(intf, peasycap);
-/*---------------------------------------------------------------------------*/
-/*
- *  THE AUDIO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
- */
-/*---------------------------------------------------------------------------*/
+
+		/* The audio device can now be registered */
 		JOM(4, "initializing ALSA card\n");
 
 		rc = easycap_alsa_probe(peasycap);
@@ -3915,11 +3833,7 @@
 		peasycap->registered_audio++;
 		break;
 	}
-/*---------------------------------------------------------------------------*/
-/*
- *  INTERFACES OTHER THAN 0, 1 AND 2 ARE UNEXPECTED
- */
-/*---------------------------------------------------------------------------*/
+	/* Interfaces other than 0,1,2 are unexpected */
 	default:
 		JOM(4, "ERROR: unexpected interface %i\n", bInterfaceNumber);
 		return -EINVAL;
diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c
index 6c9279a..ece2dd1 100644
--- a/drivers/staging/media/go7007/go7007-driver.c
+++ b/drivers/staging/media/go7007/go7007-driver.c
@@ -30,7 +30,6 @@
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
-#include <asm/system.h>
 #include <linux/videodev2.h>
 #include <media/tuner.h>
 #include <media/v4l2-common.h>
diff --git a/drivers/staging/media/go7007/go7007-i2c.c b/drivers/staging/media/go7007/go7007-i2c.c
index b8cfa1a..6bc82aa 100644
--- a/drivers/staging/media/go7007/go7007-i2c.c
+++ b/drivers/staging/media/go7007/go7007-i2c.c
@@ -26,7 +26,6 @@
 #include <linux/i2c.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
-#include <asm/system.h>
 
 #include "go7007-priv.h"
 #include "wis-i2c.h"
diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c
index 2b27d8d..3ef4cd8 100644
--- a/drivers/staging/media/go7007/go7007-v4l2.c
+++ b/drivers/staging/media/go7007/go7007-v4l2.c
@@ -34,7 +34,6 @@
 #include <linux/i2c.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
-#include <asm/system.h>
 
 #include "go7007.h"
 #include "go7007-priv.h"
@@ -1050,15 +1049,15 @@
 	return 0;
 }
 
-/* VIDIOC_ENUMSTD on go7007 were used for enumberating the supported fps and
+/* VIDIOC_ENUMSTD on go7007 were used for enumerating the supported fps and
    its resolution, when the device is not connected to TV.
-   This were an API abuse, probably used by the lack of specific IOCTL's to
-   enumberate it, by the time the driver were written.
+   This is were an API abuse, probably used by the lack of specific IOCTL's to
+   enumerate it, by the time the driver was written.
 
    However, since kernel 2.6.19, two new ioctls (VIDIOC_ENUM_FRAMEINTERVALS
    and VIDIOC_ENUM_FRAMESIZES) were added for this purpose.
 
-   The two functions bellow implements the newer ioctls
+   The two functions below implement the newer ioctls
 */
 static int vidioc_enum_framesizes(struct file *filp, void *priv,
 				  struct v4l2_frmsizeenum *fsize)
diff --git a/drivers/staging/media/go7007/s2250-board.c b/drivers/staging/media/go7007/s2250-board.c
index e7736a9..014d384 100644
--- a/drivers/staging/media/go7007/s2250-board.c
+++ b/drivers/staging/media/go7007/s2250-board.c
@@ -192,6 +192,7 @@
 {
 	struct go7007 *go = i2c_get_adapdata(client->adapter);
 	struct go7007_usb *usb;
+	int rc;
 	u8 *buf;
 	struct s2250 *dec = i2c_get_clientdata(client);
 
@@ -216,12 +217,13 @@
 		kfree(buf);
 		return -EINTR;
 	}
-	if (go7007_usb_vendor_request(go, 0x57, addr, val, buf, 16, 1) < 0) {
+	rc = go7007_usb_vendor_request(go, 0x57, addr, val, buf, 16, 1);
+	mutex_unlock(&usb->i2c_lock);
+	if (rc < 0) {
 		kfree(buf);
-		return -EFAULT;
+		return rc;
 	}
 
-	mutex_unlock(&usb->i2c_lock);
 	if (buf[0] == 0) {
 		unsigned int subaddr, val_read;
 
@@ -254,6 +256,7 @@
 {
 	struct go7007 *go = i2c_get_adapdata(client->adapter);
 	struct go7007_usb *usb;
+	int rc;
 	u8 *buf;
 
 	if (go == NULL)
@@ -276,11 +279,12 @@
 		kfree(buf);
 		return -EINTR;
 	}
-	if (go7007_usb_vendor_request(go, 0x58, addr, 0, buf, 16, 1) < 0) {
-		kfree(buf);
-		return -EFAULT;
-	}
+	rc = go7007_usb_vendor_request(go, 0x58, addr, 0, buf, 16, 1);
 	mutex_unlock(&usb->i2c_lock);
+	if (rc < 0) {
+		kfree(buf);
+		return rc;
+	}
 
 	*val = (buf[0] << 8) | buf[1];
 	kfree(buf);
diff --git a/drivers/staging/media/go7007/snd-go7007.c b/drivers/staging/media/go7007/snd-go7007.c
index d071c838..5af29ff 100644
--- a/drivers/staging/media/go7007/snd-go7007.c
+++ b/drivers/staging/media/go7007/snd-go7007.c
@@ -29,7 +29,6 @@
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
-#include <asm/system.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c
index 8dd8897..3295ea6 100644
--- a/drivers/staging/media/lirc/lirc_serial.c
+++ b/drivers/staging/media/lirc/lirc_serial.c
@@ -66,7 +66,6 @@
 #include <linux/poll.h>
 #include <linux/platform_device.h>
 
-#include <asm/system.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/fcntl.h>
@@ -1282,7 +1281,7 @@
 /*
  * some architectures (e.g. intel xscale) align the 8bit serial registers
  * on 32bit word boundaries.
- * See linux-kernel/serial/8250.c serial_in()/out()
+ * See linux-kernel/drivers/tty/serial/8250/8250.c serial_in()/out()
  */
 module_param(ioshift, int, S_IRUGO);
 MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)");
diff --git a/drivers/staging/media/lirc/lirc_sir.c b/drivers/staging/media/lirc/lirc_sir.c
index c94382b..945d962 100644
--- a/drivers/staging/media/lirc/lirc_sir.c
+++ b/drivers/staging/media/lirc/lirc_sir.c
@@ -49,7 +49,6 @@
 #include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/poll.h>
-#include <asm/system.h>
 #include <linux/io.h>
 #include <asm/irq.h>
 #include <linux/fcntl.h>
diff --git a/drivers/staging/media/solo6x10/Kconfig b/drivers/staging/media/solo6x10/Kconfig
index 03dcac4..63352de 100644
--- a/drivers/staging/media/solo6x10/Kconfig
+++ b/drivers/staging/media/solo6x10/Kconfig
@@ -5,4 +5,4 @@
 	select SND_PCM
 	---help---
 	  This driver supports the Softlogic based MPEG-4 and h.264 codec
-	  codec cards.
+	  cards.
diff --git a/drivers/staging/media/solo6x10/core.c b/drivers/staging/media/solo6x10/core.c
index f974f64..d2fd842 100644
--- a/drivers/staging/media/solo6x10/core.c
+++ b/drivers/staging/media/solo6x10/core.c
@@ -195,28 +195,28 @@
 			SOLO6010_SYS_CFG_OUTDIV(3);
 	solo_reg_write(solo_dev, SOLO_SYS_CFG, reg);
 
-        if (solo_dev->flags & FLAGS_6110) {
-                u32 sys_clock_MHz = SOLO_CLOCK_MHZ;
-                u32 pll_DIVQ;
-                u32 pll_DIVF;
+	if (solo_dev->flags & FLAGS_6110) {
+		u32 sys_clock_MHz = SOLO_CLOCK_MHZ;
+		u32 pll_DIVQ;
+		u32 pll_DIVF;
 
-                if (sys_clock_MHz < 125) {
-                        pll_DIVQ = 3;
-                        pll_DIVF = (sys_clock_MHz * 4) / 3;
-                } else {
-                        pll_DIVQ = 2;
-                        pll_DIVF = (sys_clock_MHz * 2) / 3;
-                }
+		if (sys_clock_MHz < 125) {
+			pll_DIVQ = 3;
+			pll_DIVF = (sys_clock_MHz * 4) / 3;
+		} else {
+			pll_DIVQ = 2;
+			pll_DIVF = (sys_clock_MHz * 2) / 3;
+		}
 
-                solo_reg_write(solo_dev, SOLO6110_PLL_CONFIG,
+		solo_reg_write(solo_dev, SOLO6110_PLL_CONFIG,
 			       SOLO6110_PLL_RANGE_5_10MHZ |
 			       SOLO6110_PLL_DIVR(9) |
 			       SOLO6110_PLL_DIVQ_EXP(pll_DIVQ) |
 			       SOLO6110_PLL_DIVF(pll_DIVF) | SOLO6110_PLL_FSEN);
-		mdelay(1);      // PLL Locking time (1ms)
+		mdelay(1);      /* PLL Locking time (1ms) */
 
 		solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 3 << 8); /* ? */
-        } else
+	} else
 		solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 1 << 8); /* ? */
 
 	solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, SOLO_CLOCK_MHZ - 1);
diff --git a/drivers/staging/mei/wd.c b/drivers/staging/mei/wd.c
index a6910da..cf4c29d 100644
--- a/drivers/staging/mei/wd.c
+++ b/drivers/staging/mei/wd.c
@@ -323,6 +323,7 @@
 	mutex_lock(&dev->device_lock);
 
 	dev->wd_timeout = timeout;
+	wd_dev->timeout = timeout;
 	mei_wd_set_start_timeout(dev, dev->wd_timeout);
 
 	mutex_unlock(&dev->device_lock);
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c
index 4683d5f..6183573 100644
--- a/drivers/staging/panel/panel.c
+++ b/drivers/staging/panel/panel.c
@@ -58,7 +58,6 @@
 
 #include <linux/io.h>
 #include <linux/uaccess.h>
-#include <asm/system.h>
 
 #define LCD_MINOR		156
 #define KEYPAD_MINOR		185
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index e4ade55..4fe52f6 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -4159,7 +4159,7 @@
 		argv[0] = RadioPowerPath;
 		argv[2] = NULL;
 
-		call_usermodehelper(RadioPowerPath, argv, envp, 1);
+		call_usermodehelper(RadioPowerPath, argv, envp, UMH_WAIT_PROC);
 	}
 }
 
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
index a7fa9aa..f026b71 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
@@ -208,7 +208,7 @@
 
 	if (priv->rtllib->state != RTLLIB_LINKED)
 		return;
-	call_usermodehelper(ac_dc_check_script_path, argv, envp, 1);
+	call_usermodehelper(ac_dc_check_script_path, argv, envp, UMH_WAIT_PROC);
 
 	return;
 };
@@ -2296,7 +2296,7 @@
 
 		argv[0] = RadioPowerPath;
 		argv[2] = NULL;
-		call_usermodehelper(RadioPowerPath, argv, envp, 1);
+		call_usermodehelper(RadioPowerPath, argv, envp, UMH_WAIT_PROC);
 	}
 }
 
diff --git a/drivers/staging/sbe-2t3e3/io.c b/drivers/staging/sbe-2t3e3/io.c
index b458ff0..9a50bcc 100644
--- a/drivers/staging/sbe-2t3e3/io.c
+++ b/drivers/staging/sbe-2t3e3/io.c
@@ -11,7 +11,6 @@
  */
 
 #include <linux/ip.h>
-#include <asm/system.h>
 #include "2t3e3.h"
 #include "ctrl.h"
 
diff --git a/drivers/staging/ste_rmi4/Makefile b/drivers/staging/ste_rmi4/Makefile
index 176f469..e4c0335 100644
--- a/drivers/staging/ste_rmi4/Makefile
+++ b/drivers/staging/ste_rmi4/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the RMI4 touchscreen driver.
 #
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_i2c_rmi4.o
-obj-$(CONFIG_MACH_U8500) += board-mop500-u8500uib-rmi4.o
+obj-$(CONFIG_MACH_MOP500) += board-mop500-u8500uib-rmi4.o
diff --git a/drivers/staging/telephony/ixj.c b/drivers/staging/telephony/ixj.c
index d5f923b..f960279 100644
--- a/drivers/staging/telephony/ixj.c
+++ b/drivers/staging/telephony/ixj.c
@@ -5927,7 +5927,8 @@
 	j->caplist[j->caps].cap = PHONE_VENDOR_QUICKNET;
 	strcpy(j->caplist[j->caps].desc, "Quicknet Technologies, Inc. (www.quicknet.net)");
 	j->caplist[j->caps].captype = vendor;
-	j->caplist[j->caps].handle = j->caps++;
+	j->caplist[j->caps].handle = j->caps;
+	j->caps++;
 	j->caplist[j->caps].captype = device;
 	switch (j->cardtype) {
 	case QTI_PHONEJACK:
@@ -5947,11 +5948,13 @@
 		break;
 	}
 	j->caplist[j->caps].cap = j->cardtype;
-	j->caplist[j->caps].handle = j->caps++;
+	j->caplist[j->caps].handle = j->caps;
+	j->caps++;
 	strcpy(j->caplist[j->caps].desc, "POTS");
 	j->caplist[j->caps].captype = port;
 	j->caplist[j->caps].cap = pots;
-	j->caplist[j->caps].handle = j->caps++;
+	j->caplist[j->caps].handle = j->caps;
+	j->caps++;
 
  	/* add devices that can do speaker/mic */
 	switch (j->cardtype) {
@@ -5962,7 +5965,8 @@
 		strcpy(j->caplist[j->caps].desc, "SPEAKER");
 		j->caplist[j->caps].captype = port;
 		j->caplist[j->caps].cap = speaker;
-		j->caplist[j->caps].handle = j->caps++;
+		j->caplist[j->caps].handle = j->caps;
+		j->caps++;
         default:
      		break;
 	}
@@ -5973,7 +5977,8 @@
 		strcpy(j->caplist[j->caps].desc, "HANDSET");
 		j->caplist[j->caps].captype = port;
 		j->caplist[j->caps].cap = handset;
-		j->caplist[j->caps].handle = j->caps++;
+		j->caplist[j->caps].handle = j->caps;
+		j->caps++;
 		break;
         default:
      		break;
@@ -5985,7 +5990,8 @@
 		strcpy(j->caplist[j->caps].desc, "PSTN");
 		j->caplist[j->caps].captype = port;
 		j->caplist[j->caps].cap = pstn;
-		j->caplist[j->caps].handle = j->caps++;
+		j->caplist[j->caps].handle = j->caps;
+		j->caps++;
 		break;
         default:
      		break;
@@ -5995,50 +6001,59 @@
 	strcpy(j->caplist[j->caps].desc, "ULAW");
 	j->caplist[j->caps].captype = codec;
 	j->caplist[j->caps].cap = ULAW;
-	j->caplist[j->caps].handle = j->caps++;
+	j->caplist[j->caps].handle = j->caps;
+	j->caps++;
 
 	strcpy(j->caplist[j->caps].desc, "LINEAR 16 bit");
 	j->caplist[j->caps].captype = codec;
 	j->caplist[j->caps].cap = LINEAR16;
-	j->caplist[j->caps].handle = j->caps++;
+	j->caplist[j->caps].handle = j->caps;
+	j->caps++;
 
 	strcpy(j->caplist[j->caps].desc, "LINEAR 8 bit");
 	j->caplist[j->caps].captype = codec;
 	j->caplist[j->caps].cap = LINEAR8;
-	j->caplist[j->caps].handle = j->caps++;
+	j->caplist[j->caps].handle = j->caps;
+	j->caps++;
 
 	strcpy(j->caplist[j->caps].desc, "Windows Sound System");
 	j->caplist[j->caps].captype = codec;
 	j->caplist[j->caps].cap = WSS;
-	j->caplist[j->caps].handle = j->caps++;
+	j->caplist[j->caps].handle = j->caps;
+	j->caps++;
 
 	/* software ALAW codec, made from ULAW */
 	strcpy(j->caplist[j->caps].desc, "ALAW");
 	j->caplist[j->caps].captype = codec;
 	j->caplist[j->caps].cap = ALAW;
-	j->caplist[j->caps].handle = j->caps++;
+	j->caplist[j->caps].handle = j->caps;
+	j->caps++;
 
 	/* version 12 of the 8020 does the following codecs in a broken way */
 	if (j->dsp.low != 0x20 || j->ver.low != 0x12) {
 		strcpy(j->caplist[j->caps].desc, "G.723.1 6.3kbps");
 		j->caplist[j->caps].captype = codec;
 		j->caplist[j->caps].cap = G723_63;
-		j->caplist[j->caps].handle = j->caps++;
+		j->caplist[j->caps].handle = j->caps;
+		j->caps++;
 
 		strcpy(j->caplist[j->caps].desc, "G.723.1 5.3kbps");
 		j->caplist[j->caps].captype = codec;
 		j->caplist[j->caps].cap = G723_53;
-		j->caplist[j->caps].handle = j->caps++;
+		j->caplist[j->caps].handle = j->caps;
+		j->caps++;
 
 		strcpy(j->caplist[j->caps].desc, "TrueSpeech 4.8kbps");
 		j->caplist[j->caps].captype = codec;
 		j->caplist[j->caps].cap = TS48;
-		j->caplist[j->caps].handle = j->caps++;
+		j->caplist[j->caps].handle = j->caps;
+		j->caps++;
 
 		strcpy(j->caplist[j->caps].desc, "TrueSpeech 4.1kbps");
 		j->caplist[j->caps].captype = codec;
 		j->caplist[j->caps].cap = TS41;
-		j->caplist[j->caps].handle = j->caps++;
+		j->caplist[j->caps].handle = j->caps;
+		j->caps++;
 	}
 
 	/* 8020 chips can do TS8.5 native, and 8021/8022 can load it */
@@ -6046,7 +6061,8 @@
 		strcpy(j->caplist[j->caps].desc, "TrueSpeech 8.5kbps");
 		j->caplist[j->caps].captype = codec;
 		j->caplist[j->caps].cap = TS85;
-		j->caplist[j->caps].handle = j->caps++;
+		j->caplist[j->caps].handle = j->caps;
+		j->caps++;
 	}
 
 	/* 8021 chips can do G728 */
@@ -6054,7 +6070,8 @@
 		strcpy(j->caplist[j->caps].desc, "G.728 16kbps");
 		j->caplist[j->caps].captype = codec;
 		j->caplist[j->caps].cap = G728;
-		j->caplist[j->caps].handle = j->caps++;
+		j->caplist[j->caps].handle = j->caps;
+		j->caps++;
 	}
 
 	/* 8021/8022 chips can do G729 if loaded */
@@ -6062,13 +6079,15 @@
 		strcpy(j->caplist[j->caps].desc, "G.729A 8kbps");
 		j->caplist[j->caps].captype = codec;
 		j->caplist[j->caps].cap = G729;
-		j->caplist[j->caps].handle = j->caps++;
+		j->caplist[j->caps].handle = j->caps;
+		j->caps++;
 	}
 	if (j->dsp.low != 0x20 && j->flags.g729_loaded) {
 		strcpy(j->caplist[j->caps].desc, "G.729B 8kbps");
 		j->caplist[j->caps].captype = codec;
 		j->caplist[j->caps].cap = G729B;
-		j->caplist[j->caps].handle = j->caps++;
+		j->caplist[j->caps].handle = j->caps;
+		j->caps++;
 	}
 }
 
diff --git a/drivers/staging/telephony/phonedev.c b/drivers/staging/telephony/phonedev.c
index 1915af2..1dd0b67 100644
--- a/drivers/staging/telephony/phonedev.c
+++ b/drivers/staging/telephony/phonedev.c
@@ -24,7 +24,6 @@
 #include <linux/phonedev.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #include <linux/kmod.h>
 #include <linux/sem.h>
diff --git a/drivers/staging/tidspbridge/include/dspbridge/host_os.h b/drivers/staging/tidspbridge/include/dspbridge/host_os.h
index a2f31c6..ed00d3d 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/host_os.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/host_os.h
@@ -17,7 +17,6 @@
 #ifndef _HOST_OS_H_
 #define _HOST_OS_H_
 
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <linux/semaphore.h>
 #include <linux/uaccess.h>
diff --git a/drivers/staging/wlags49_h2/hcf.c b/drivers/staging/wlags49_h2/hcf.c
index b0087733..5957c3a 100644
--- a/drivers/staging/wlags49_h2/hcf.c
+++ b/drivers/staging/wlags49_h2/hcf.c
@@ -91,6 +91,7 @@
 #include "hcf.h"                // HCF and MSF common include file
 #include "hcfdef.h"             // HCF specific include file
 #include "mmd.h"                // MoreModularDriver common include file
+#include <linux/bug.h>
 #include <linux/kernel.h>
 
 #if ! defined offsetof
diff --git a/drivers/staging/wlags49_h2/wl_cs.c b/drivers/staging/wlags49_h2/wl_cs.c
index a2cbb29..7084f41 100644
--- a/drivers/staging/wlags49_h2/wl_cs.c
+++ b/drivers/staging/wlags49_h2/wl_cs.c
@@ -74,7 +74,6 @@
 #include <linux/in.h>
 #include <linux/delay.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/bitops.h>
 
 #include <linux/netdevice.h>
diff --git a/drivers/staging/wlags49_h2/wl_main.c b/drivers/staging/wlags49_h2/wl_main.c
index dab603e..d5bf0a7 100644
--- a/drivers/staging/wlags49_h2/wl_main.c
+++ b/drivers/staging/wlags49_h2/wl_main.c
@@ -86,8 +86,7 @@
 // #include <linux/in.h>
 // #include <linux/delay.h>
 // #include <asm/io.h>
-// #include <asm/system.h>
-// #include <asm/bitops.h>
+// // #include <asm/bitops.h>
 #include <linux/unistd.h>
 #include <asm/uaccess.h>
 
diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c
index 9c16f54..90820ff 100644
--- a/drivers/staging/wlags49_h2/wl_netdev.c
+++ b/drivers/staging/wlags49_h2/wl_netdev.c
@@ -79,8 +79,7 @@
 // #include <linux/delay.h>
 // #include <linux/skbuff.h>
 // #include <asm/io.h>
-// #include <asm/system.h>
-// #include <asm/bitops.h>
+// // #include <asm/bitops.h>
 
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
diff --git a/drivers/staging/wlags49_h2/wl_pci.c b/drivers/staging/wlags49_h2/wl_pci.c
index 2bd9b84..3df990c 100644
--- a/drivers/staging/wlags49_h2/wl_pci.c
+++ b/drivers/staging/wlags49_h2/wl_pci.c
@@ -77,7 +77,6 @@
 #include <linux/interrupt.h>
 #include <linux/in.h>
 #include <linux/delay.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
diff --git a/drivers/staging/wlags49_h2/wl_util.c b/drivers/staging/wlags49_h2/wl_util.c
index b748a3f..f104e6f 100644
--- a/drivers/staging/wlags49_h2/wl_util.c
+++ b/drivers/staging/wlags49_h2/wl_util.c
@@ -73,8 +73,7 @@
 // #include <linux/in.h>
 // #include <linux/delay.h>
 // #include <asm/io.h>
-// #include <asm/system.h>
-// #include <asm/bitops.h>
+// // #include <asm/bitops.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c
index ed2c800..2734dac 100644
--- a/drivers/staging/zcache/zcache-main.c
+++ b/drivers/staging/zcache/zcache-main.c
@@ -1811,9 +1811,9 @@
 static struct cleancache_ops zcache_cleancache_ops = {
 	.put_page = zcache_cleancache_put_page,
 	.get_page = zcache_cleancache_get_page,
-	.flush_page = zcache_cleancache_flush_page,
-	.flush_inode = zcache_cleancache_flush_inode,
-	.flush_fs = zcache_cleancache_flush_fs,
+	.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
 };
@@ -1921,8 +1921,8 @@
 static struct frontswap_ops zcache_frontswap_ops = {
 	.put_page = zcache_frontswap_put_page,
 	.get_page = zcache_frontswap_get_page,
-	.flush_page = zcache_frontswap_flush_page,
-	.flush_area = zcache_frontswap_flush_area,
+	.invalidate_page = zcache_frontswap_flush_page,
+	.invalidate_area = zcache_frontswap_flush_area,
 	.init = zcache_frontswap_init
 };
 
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 1c6f700..8b1d5e6 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -781,7 +781,7 @@
 	struct scatterlist *sgl;
 	u32 length = cmd->se_cmd.data_length;
 	int nents = DIV_ROUND_UP(length, PAGE_SIZE);
-	int i = 0, ret;
+	int i = 0, j = 0, ret;
 	/*
 	 * If no SCSI payload is present, allocate the default iovecs used for
 	 * iSCSI PDU Header
@@ -822,17 +822,15 @@
 	 */
         ret = iscsit_allocate_iovecs(cmd);
         if (ret < 0)
-		goto page_alloc_failed;
+		return -ENOMEM;
 
 	return 0;
 
 page_alloc_failed:
-	while (i >= 0) {
-		__free_page(sg_page(&sgl[i]));
-		i--;
-	}
-	kfree(cmd->t_mem_sg);
-	cmd->t_mem_sg = NULL;
+	while (j < i)
+		__free_page(sg_page(&sgl[j++]));
+
+	kfree(sgl);
 	return -ENOMEM;
 }
 
@@ -1007,8 +1005,8 @@
 	/*
 	 * The CDB is going to an se_device_t.
 	 */
-	ret = iscsit_get_lun_for_cmd(cmd, hdr->cdb,
-				get_unaligned_le64(&hdr->lun));
+	ret = transport_lookup_cmd_lun(&cmd->se_cmd,
+				       scsilun_to_int(&hdr->lun));
 	if (ret < 0) {
 		if (cmd->se_cmd.scsi_sense_reason == TCM_NON_EXISTENT_LUN) {
 			pr_debug("Responding to non-acl'ed,"
@@ -1364,7 +1362,7 @@
 		 * outstanding_r2ts reaches zero, go ahead and send the delayed
 		 * TASK_ABORTED status.
 		 */
-		if (atomic_read(&se_cmd->t_transport_aborted) != 0) {
+		if (se_cmd->transport_state & CMD_T_ABORTED) {
 			if (hdr->flags & ISCSI_FLAG_CMD_FINAL)
 				if (--cmd->outstanding_r2ts < 1) {
 					iscsit_stop_dataout_timer(cmd);
@@ -1472,14 +1470,12 @@
 	unsigned char *ping_data = NULL;
 	int cmdsn_ret, niov = 0, ret = 0, rx_got, rx_size;
 	u32 checksum, data_crc, padding = 0, payload_length;
-	u64 lun;
 	struct iscsi_cmd *cmd = NULL;
 	struct kvec *iov = NULL;
 	struct iscsi_nopout *hdr;
 
 	hdr			= (struct iscsi_nopout *) buf;
 	payload_length		= ntoh24(hdr->dlength);
-	lun			= get_unaligned_le64(&hdr->lun);
 	hdr->itt		= be32_to_cpu(hdr->itt);
 	hdr->ttt		= be32_to_cpu(hdr->ttt);
 	hdr->cmdsn		= be32_to_cpu(hdr->cmdsn);
@@ -1689,13 +1685,11 @@
 	struct se_tmr_req *se_tmr;
 	struct iscsi_tmr_req *tmr_req;
 	struct iscsi_tm *hdr;
-	u32 payload_length;
 	int out_of_order_cmdsn = 0;
 	int ret;
 	u8 function;
 
 	hdr			= (struct iscsi_tm *) buf;
-	payload_length		= ntoh24(hdr->dlength);
 	hdr->itt		= be32_to_cpu(hdr->itt);
 	hdr->rtt		= be32_to_cpu(hdr->rtt);
 	hdr->cmdsn		= be32_to_cpu(hdr->cmdsn);
@@ -1747,8 +1741,8 @@
 	 * Locate the struct se_lun for all TMRs not related to ERL=2 TASK_REASSIGN
 	 */
 	if (function != ISCSI_TM_FUNC_TASK_REASSIGN) {
-		ret = iscsit_get_lun_for_tmr(cmd,
-				get_unaligned_le64(&hdr->lun));
+		ret = transport_lookup_tmr_lun(&cmd->se_cmd,
+					       scsilun_to_int(&hdr->lun));
 		if (ret < 0) {
 			cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
 			se_tmr->response = ISCSI_TMF_RSP_NO_LUN;
@@ -2207,14 +2201,10 @@
 	struct iscsi_conn *conn,
 	unsigned char *buf)
 {
-	u32 unpacked_lun;
-	u64 lun;
 	struct iscsi_snack *hdr;
 
 	hdr			= (struct iscsi_snack *) buf;
 	hdr->flags		&= ~ISCSI_FLAG_CMD_FINAL;
-	lun			= get_unaligned_le64(&hdr->lun);
-	unpacked_lun		= scsilun_to_int((struct scsi_lun *)&lun);
 	hdr->itt		= be32_to_cpu(hdr->itt);
 	hdr->ttt		= be32_to_cpu(hdr->ttt);
 	hdr->exp_statsn		= be32_to_cpu(hdr->exp_statsn);
@@ -3514,7 +3504,6 @@
 	struct iscsi_cmd *cmd = NULL;
 	struct iscsi_conn *conn;
 	struct iscsi_queue_req *qr = NULL;
-	struct se_cmd *se_cmd;
 	struct iscsi_thread_set *ts = arg;
 	/*
 	 * Allow ourselves to be interrupted by SIGINT so that a
@@ -3697,8 +3686,6 @@
 				goto transport_err;
 			}
 
-			se_cmd = &cmd->se_cmd;
-
 			if (map_sg && !conn->conn_ops->IFMarker) {
 				if (iscsit_fe_sendpage_sg(cmd, conn) < 0) {
 					conn->tx_response_queue = 0;
@@ -4171,7 +4158,7 @@
 	if (!atomic_read(&sess->session_reinstatement) &&
 	     atomic_read(&sess->session_fall_back_to_erl0)) {
 		spin_unlock_bh(&sess->conn_lock);
-		iscsit_close_session(sess);
+		target_put_session(sess->se_sess);
 
 		return 0;
 	} else if (atomic_read(&sess->session_logout)) {
@@ -4292,7 +4279,7 @@
 	iscsit_dec_conn_usage_count(conn);
 	iscsit_stop_session(sess, 1, 1);
 	iscsit_dec_session_usage_count(sess);
-	iscsit_close_session(sess);
+	target_put_session(sess->se_sess);
 }
 
 static void iscsit_logout_post_handler_samecid(
@@ -4458,7 +4445,7 @@
 	} else
 		spin_unlock_bh(&sess->conn_lock);
 
-	iscsit_close_session(sess);
+	target_put_session(sess->se_sess);
 	return 0;
 }
 
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index 6b35b37..00c58cc 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -812,9 +812,6 @@
 	if (!se_nacl_new)
 		return ERR_PTR(-ENOMEM);
 
-	acl = container_of(se_nacl_new, struct iscsi_node_acl,
-				se_node_acl);
-
 	cmdsn_depth = ISCSI_TPG_ATTRIB(tpg)->default_cmdsn_depth;
 	/*
 	 * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
@@ -825,7 +822,8 @@
 	if (IS_ERR(se_nacl))
 		return se_nacl;
 
-	stats_cg = &acl->se_node_acl.acl_fabric_stat_group;
+	acl = container_of(se_nacl, struct iscsi_node_acl, se_node_acl);
+	stats_cg = &se_nacl->acl_fabric_stat_group;
 
 	stats_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
 				GFP_KERNEL);
@@ -1505,28 +1503,6 @@
 	return cmd->i_state;
 }
 
-static int iscsi_is_state_remove(struct se_cmd *se_cmd)
-{
-	struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
-
-	return (cmd->i_state == ISTATE_REMOVE);
-}
-
-static int lio_sess_logged_in(struct se_session *se_sess)
-{
-	struct iscsi_session *sess = se_sess->fabric_sess_ptr;
-	int ret;
-	/*
-	 * Called with spin_lock_bh(&tpg_lock); and
-	 * spin_lock(&se_tpg->session_lock); held.
-	 */
-	spin_lock(&sess->conn_lock);
-	ret = (sess->session_state != TARG_SESS_STATE_LOGGED_IN);
-	spin_unlock(&sess->conn_lock);
-
-	return ret;
-}
-
 static u32 lio_sess_get_index(struct se_session *se_sess)
 {
 	struct iscsi_session *sess = se_sess->fabric_sess_ptr;
@@ -1700,8 +1676,8 @@
 	atomic_set(&sess->session_reinstatement, 1);
 	spin_unlock(&sess->conn_lock);
 
-	iscsit_inc_session_usage_count(sess);
 	iscsit_stop_time2retain_timer(sess);
+	iscsit_stop_session(sess, 1, 1);
 
 	return 1;
 }
@@ -1717,28 +1693,9 @@
 	 * If the iSCSI Session for the iSCSI Initiator Node exists,
 	 * forcefully shutdown the iSCSI NEXUS.
 	 */
-	iscsit_stop_session(sess, 1, 1);
-	iscsit_dec_session_usage_count(sess);
 	iscsit_close_session(sess);
 }
 
-static void lio_tpg_stop_session(
-	struct se_session *se_sess,
-	int sess_sleep,
-	int conn_sleep)
-{
-	struct iscsi_session *sess = se_sess->fabric_sess_ptr;
-
-	iscsit_stop_session(sess, sess_sleep, conn_sleep);
-}
-
-static void lio_tpg_fall_back_to_erl0(struct se_session *se_sess)
-{
-	struct iscsi_session *sess = se_sess->fabric_sess_ptr;
-
-	iscsit_fall_back_to_erl0(sess);
-}
-
 static u32 lio_tpg_get_inst_index(struct se_portal_group *se_tpg)
 {
 	struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr;
@@ -1802,9 +1759,6 @@
 	fabric->tf_ops.release_cmd = &lio_release_cmd;
 	fabric->tf_ops.shutdown_session = &lio_tpg_shutdown_session;
 	fabric->tf_ops.close_session = &lio_tpg_close_session;
-	fabric->tf_ops.stop_session = &lio_tpg_stop_session;
-	fabric->tf_ops.fall_back_to_erl0 = &lio_tpg_fall_back_to_erl0;
-	fabric->tf_ops.sess_logged_in = &lio_sess_logged_in;
 	fabric->tf_ops.sess_get_index = &lio_sess_get_index;
 	fabric->tf_ops.sess_get_initiator_sid = &lio_sess_get_initiator_sid;
 	fabric->tf_ops.write_pending = &lio_write_pending;
@@ -1818,7 +1772,6 @@
 	fabric->tf_ops.queue_tm_rsp = &lio_queue_tm_rsp;
 	fabric->tf_ops.set_fabric_sense_len = &lio_set_fabric_sense_len;
 	fabric->tf_ops.get_fabric_sense_len = &lio_get_fabric_sense_len;
-	fabric->tf_ops.is_state_remove = &iscsi_is_state_remove;
 	/*
 	 * Setup function pointers for generic logic in target_core_fabric_configfs.c
 	 */
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
index 0ec3b77..2aaee7e 100644
--- a/drivers/target/iscsi/iscsi_target_core.h
+++ b/drivers/target/iscsi/iscsi_target_core.h
@@ -9,7 +9,7 @@
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
 
-#define ISCSIT_VERSION			"v4.1.0-rc1"
+#define ISCSIT_VERSION			"v4.1.0-rc2"
 #define ISCSI_MAX_DATASN_MISSING_COUNT	16
 #define ISCSI_TX_THREAD_TCP_TIMEOUT	2
 #define ISCSI_RX_THREAD_TCP_TIMEOUT	2
diff --git a/drivers/target/iscsi/iscsi_target_device.c b/drivers/target/iscsi/iscsi_target_device.c
index f63ea35..bcc4098 100644
--- a/drivers/target/iscsi/iscsi_target_device.c
+++ b/drivers/target/iscsi/iscsi_target_device.c
@@ -28,25 +28,6 @@
 #include "iscsi_target_tpg.h"
 #include "iscsi_target_util.h"
 
-int iscsit_get_lun_for_tmr(
-	struct iscsi_cmd *cmd,
-	u64 lun)
-{
-	u32 unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun);
-
-	return transport_lookup_tmr_lun(&cmd->se_cmd, unpacked_lun);
-}
-
-int iscsit_get_lun_for_cmd(
-	struct iscsi_cmd *cmd,
-	unsigned char *cdb,
-	u64 lun)
-{
-	u32 unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun);
-
-	return transport_lookup_cmd_lun(&cmd->se_cmd, unpacked_lun);
-}
-
 void iscsit_determine_maxcmdsn(struct iscsi_session *sess)
 {
 	struct se_node_acl *se_nacl;
diff --git a/drivers/target/iscsi/iscsi_target_device.h b/drivers/target/iscsi/iscsi_target_device.h
index bef1cad..a0e2df9 100644
--- a/drivers/target/iscsi/iscsi_target_device.h
+++ b/drivers/target/iscsi/iscsi_target_device.h
@@ -1,8 +1,6 @@
 #ifndef ISCSI_TARGET_DEVICE_H
 #define ISCSI_TARGET_DEVICE_H
 
-extern int iscsit_get_lun_for_tmr(struct iscsi_cmd *, u64);
-extern int iscsit_get_lun_for_cmd(struct iscsi_cmd *, unsigned char *, u64);
 extern void iscsit_determine_maxcmdsn(struct iscsi_session *);
 extern void iscsit_increment_maxcmdsn(struct iscsi_cmd *, struct iscsi_session *);
 
diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c
index 4784511..1ab0560 100644
--- a/drivers/target/iscsi/iscsi_target_erl0.c
+++ b/drivers/target/iscsi/iscsi_target_erl0.c
@@ -783,7 +783,7 @@
 	}
 
 	spin_unlock_bh(&se_tpg->session_lock);
-	iscsit_close_session(sess);
+	target_put_session(sess->se_sess);
 }
 
 extern void iscsit_start_time2retain_handler(struct iscsi_session *sess)
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index 27901e3..006f605 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -416,7 +416,7 @@
 	struct iscsi_datain_req *dr;
 	struct se_cmd *se_cmd = &cmd->se_cmd;
 
-	if (!atomic_read(&se_cmd->t_transport_complete)) {
+	if (!(se_cmd->transport_state & CMD_T_COMPLETE)) {
 		pr_err("Ignoring ITT: 0x%08x Data SNACK\n",
 				cmd->init_task_tag);
 		return 0;
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 1ee33a8..a3656c9 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -181,14 +181,16 @@
 	if (sess->session_state == TARG_SESS_STATE_FAILED) {
 		spin_unlock_bh(&sess->conn_lock);
 		iscsit_dec_session_usage_count(sess);
-		return iscsit_close_session(sess);
+		target_put_session(sess->se_sess);
+		return 0;
 	}
 	spin_unlock_bh(&sess->conn_lock);
 
 	iscsit_stop_session(sess, 1, 1);
 	iscsit_dec_session_usage_count(sess);
 
-	return iscsit_close_session(sess);
+	target_put_session(sess->se_sess);
+	return 0;
 }
 
 static void iscsi_login_set_conn_values(
@@ -881,7 +883,7 @@
 static int __iscsi_target_login_thread(struct iscsi_np *np)
 {
 	u8 buffer[ISCSI_HDR_LEN], iscsi_opcode, zero_tsih = 0;
-	int err, ret = 0, ip_proto, sock_type, set_sctp_conn_flag, stop;
+	int err, ret = 0, set_sctp_conn_flag, stop;
 	struct iscsi_conn *conn = NULL;
 	struct iscsi_login *login;
 	struct iscsi_portal_group *tpg = NULL;
@@ -894,8 +896,6 @@
 	flush_signals(current);
 	set_sctp_conn_flag = 0;
 	sock = np->np_socket;
-	ip_proto = np->np_ip_proto;
-	sock_type = np->np_sock_type;
 
 	spin_lock_bh(&np->np_thread_lock);
 	if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index e89fa74..2dba448 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -90,7 +90,7 @@
 		return -1;
 
 	if (len > max_length) {
-		pr_err("Length of input: %d exeeds max_length:"
+		pr_err("Length of input: %d exceeds max_length:"
 			" %d\n", len, max_length);
 		return -1;
 	}
@@ -173,13 +173,11 @@
 	struct iscsi_conn *conn,
 	struct iscsi_login *login)
 {
-	int req_csg, req_nsg, rsp_csg, rsp_nsg;
+	int req_csg, req_nsg;
 	u32 payload_length;
 	struct iscsi_login_req *login_req;
-	struct iscsi_login_rsp *login_rsp;
 
 	login_req = (struct iscsi_login_req *) login->req;
-	login_rsp = (struct iscsi_login_rsp *) login->rsp;
 	payload_length = ntoh24(login_req->dlength);
 
 	switch (login_req->opcode & ISCSI_OPCODE_MASK) {
@@ -203,9 +201,7 @@
 	}
 
 	req_csg = (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
-	rsp_csg = (login_rsp->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
 	req_nsg = (login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK);
-	rsp_nsg = (login_rsp->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK);
 
 	if (req_csg != login->current_stage) {
 		pr_err("Initiator unexpectedly changed login stage"
@@ -753,12 +749,10 @@
 	struct iscsi_session *sess = conn->sess;
 	struct iscsi_tiqn *tiqn;
 	struct iscsi_login_req *login_req;
-	struct iscsi_targ_login_rsp *login_rsp;
 	u32 payload_length;
 	int sessiontype = 0, ret = 0;
 
 	login_req = (struct iscsi_login_req *) login->req;
-	login_rsp = (struct iscsi_targ_login_rsp *) login->rsp;
 	payload_length = ntoh24(login_req->dlength);
 
 	login->first_request	= 1;
diff --git a/drivers/target/iscsi/iscsi_target_nodeattrib.c b/drivers/target/iscsi/iscsi_target_nodeattrib.c
index b3c699c..11dc293 100644
--- a/drivers/target/iscsi/iscsi_target_nodeattrib.c
+++ b/drivers/target/iscsi/iscsi_target_nodeattrib.c
@@ -49,7 +49,7 @@
 	a->default_erl = NA_DEFAULT_ERL;
 }
 
-extern int iscsit_na_dataout_timeout(
+int iscsit_na_dataout_timeout(
 	struct iscsi_node_acl *acl,
 	u32 dataout_timeout)
 {
@@ -74,7 +74,7 @@
 	return 0;
 }
 
-extern int iscsit_na_dataout_timeout_retries(
+int iscsit_na_dataout_timeout_retries(
 	struct iscsi_node_acl *acl,
 	u32 dataout_timeout_retries)
 {
@@ -100,7 +100,7 @@
 	return 0;
 }
 
-extern int iscsit_na_nopin_timeout(
+int iscsit_na_nopin_timeout(
 	struct iscsi_node_acl *acl,
 	u32 nopin_timeout)
 {
@@ -155,7 +155,7 @@
 	return 0;
 }
 
-extern int iscsit_na_nopin_response_timeout(
+int iscsit_na_nopin_response_timeout(
 	struct iscsi_node_acl *acl,
 	u32 nopin_response_timeout)
 {
@@ -181,7 +181,7 @@
 	return 0;
 }
 
-extern int iscsit_na_random_datain_pdu_offsets(
+int iscsit_na_random_datain_pdu_offsets(
 	struct iscsi_node_acl *acl,
 	u32 random_datain_pdu_offsets)
 {
@@ -201,7 +201,7 @@
 	return 0;
 }
 
-extern int iscsit_na_random_datain_seq_offsets(
+int iscsit_na_random_datain_seq_offsets(
 	struct iscsi_node_acl *acl,
 	u32 random_datain_seq_offsets)
 {
@@ -221,7 +221,7 @@
 	return 0;
 }
 
-extern int iscsit_na_random_r2t_offsets(
+int iscsit_na_random_r2t_offsets(
 	struct iscsi_node_acl *acl,
 	u32 random_r2t_offsets)
 {
@@ -241,7 +241,7 @@
 	return 0;
 }
 
-extern int iscsit_na_default_erl(
+int iscsit_na_default_erl(
 	struct iscsi_node_acl *acl,
 	u32 default_erl)
 {
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 5b77316..eb05c9d 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -874,8 +874,8 @@
 static int iscsi_check_numerical_range_value(struct iscsi_param *param, char *value)
 {
 	char *left_val_ptr = NULL, *right_val_ptr = NULL;
-	char *tilde_ptr = NULL, *tmp_ptr = NULL;
-	u32 left_val, right_val, local_left_val, local_right_val;
+	char *tilde_ptr = NULL;
+	u32 left_val, right_val, local_left_val;
 
 	if (strcmp(param->name, IFMARKINT) &&
 	    strcmp(param->name, OFMARKINT)) {
@@ -903,8 +903,8 @@
 	if (iscsi_check_numerical_value(param, right_val_ptr) < 0)
 		return -1;
 
-	left_val = simple_strtoul(left_val_ptr, &tmp_ptr, 0);
-	right_val = simple_strtoul(right_val_ptr, &tmp_ptr, 0);
+	left_val = simple_strtoul(left_val_ptr, NULL, 0);
+	right_val = simple_strtoul(right_val_ptr, NULL, 0);
 	*tilde_ptr = '~';
 
 	if (right_val < left_val) {
@@ -928,8 +928,7 @@
 	left_val_ptr = param->value;
 	right_val_ptr = param->value + strlen(left_val_ptr) + 1;
 
-	local_left_val = simple_strtoul(left_val_ptr, &tmp_ptr, 0);
-	local_right_val = simple_strtoul(right_val_ptr, &tmp_ptr, 0);
+	local_left_val = simple_strtoul(left_val_ptr, NULL, 0);
 	*tilde_ptr = '~';
 
 	if (param->set_param) {
@@ -1189,7 +1188,7 @@
 	if (IS_TYPE_NUMBER_RANGE(param)) {
 		u32 left_val = 0, right_val = 0, recieved_value = 0;
 		char *left_val_ptr = NULL, *right_val_ptr = NULL;
-		char *tilde_ptr = NULL, *tmp_ptr = NULL;
+		char *tilde_ptr = NULL;
 
 		if (!strcmp(value, IRRELEVANT) || !strcmp(value, REJECT)) {
 			if (iscsi_update_param_value(param, value) < 0)
@@ -1213,9 +1212,9 @@
 
 		left_val_ptr = param->value;
 		right_val_ptr = param->value + strlen(left_val_ptr) + 1;
-		left_val = simple_strtoul(left_val_ptr, &tmp_ptr, 0);
-		right_val = simple_strtoul(right_val_ptr, &tmp_ptr, 0);
-		recieved_value = simple_strtoul(value, &tmp_ptr, 0);
+		left_val = simple_strtoul(left_val_ptr, NULL, 0);
+		right_val = simple_strtoul(right_val_ptr, NULL, 0);
+		recieved_value = simple_strtoul(value, NULL, 0);
 
 		*tilde_ptr = '~';
 
diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c
index 255ed35..e01da9d 100644
--- a/drivers/target/iscsi/iscsi_target_tmr.c
+++ b/drivers/target/iscsi/iscsi_target_tmr.c
@@ -250,7 +250,7 @@
 	 * so if we have received all DataOUT we can safety ignore Initiator.
 	 */
 	if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) {
-		if (!atomic_read(&cmd->se_cmd.t_transport_sent)) {
+		if (!(cmd->se_cmd.transport_state & CMD_T_SENT)) {
 			pr_debug("WRITE ITT: 0x%08x: t_state: %d"
 				" never sent to transport\n",
 				cmd->init_task_tag, cmd->se_cmd.t_state);
@@ -314,7 +314,7 @@
 		cmd->acked_data_sn = (tmr_req->exp_data_sn - 1);
 	}
 
-	if (!atomic_read(&cmd->se_cmd.t_transport_sent)) {
+	if (!(cmd->se_cmd.transport_state & CMD_T_SENT)) {
 		pr_debug("READ ITT: 0x%08x: t_state: %d never sent to"
 			" transport\n", cmd->init_task_tag,
 			cmd->se_cmd.t_state);
@@ -322,7 +322,7 @@
 		return 0;
 	}
 
-	if (!atomic_read(&se_cmd->t_transport_complete)) {
+	if (!(se_cmd->transport_state & CMD_T_COMPLETE)) {
 		pr_err("READ ITT: 0x%08x: t_state: %d, never returned"
 			" from transport\n", cmd->init_task_tag,
 			cmd->se_cmd.t_state);
diff --git a/drivers/target/iscsi/iscsi_target_tq.c b/drivers/target/iscsi/iscsi_target_tq.c
index 0baac5b..977e1cf 100644
--- a/drivers/target/iscsi/iscsi_target_tq.c
+++ b/drivers/target/iscsi/iscsi_target_tq.c
@@ -536,12 +536,6 @@
 		return -ENOMEM;
 	}
 
-	spin_lock_init(&active_ts_lock);
-	spin_lock_init(&inactive_ts_lock);
-	spin_lock_init(&ts_bitmap_lock);
-	INIT_LIST_HEAD(&active_ts_list);
-	INIT_LIST_HEAD(&inactive_ts_list);
-
 	return 0;
 }
 
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 11287e1..4eba86d 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -229,6 +229,7 @@
 {
 	struct iscsi_cmd *cmd;
 	struct se_cmd *se_cmd;
+	int rc;
 	u8 tcm_function;
 
 	cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
@@ -286,10 +287,8 @@
 		goto out;
 	}
 
-	se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd,
-				cmd->tmr_req, tcm_function,
-				GFP_KERNEL);
-	if (!se_cmd->se_tmr_req)
+	rc = core_tmr_alloc_req(se_cmd, cmd->tmr_req, tcm_function, GFP_KERNEL);
+	if (rc < 0)
 		goto out;
 
 	cmd->tmr_req->se_tmr_req = se_cmd->se_tmr_req;
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index c47ff7f..a9b4eee 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -44,138 +44,12 @@
 /* Local pointer to allocated TCM configfs fabric module */
 static struct target_fabric_configfs *tcm_loop_fabric_configfs;
 
+static struct workqueue_struct *tcm_loop_workqueue;
 static struct kmem_cache *tcm_loop_cmd_cache;
 
 static int tcm_loop_hba_no_cnt;
 
-/*
- * Allocate a tcm_loop cmd descriptor from target_core_mod code
- *
- * Can be called from interrupt context in tcm_loop_queuecommand() below
- */
-static struct se_cmd *tcm_loop_allocate_core_cmd(
-	struct tcm_loop_hba *tl_hba,
-	struct se_portal_group *se_tpg,
-	struct scsi_cmnd *sc)
-{
-	struct se_cmd *se_cmd;
-	struct se_session *se_sess;
-	struct tcm_loop_nexus *tl_nexus = tl_hba->tl_nexus;
-	struct tcm_loop_cmd *tl_cmd;
-	int sam_task_attr;
-
-	if (!tl_nexus) {
-		scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus"
-				" does not exist\n");
-		set_host_byte(sc, DID_ERROR);
-		return NULL;
-	}
-	se_sess = tl_nexus->se_sess;
-
-	tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_ATOMIC);
-	if (!tl_cmd) {
-		pr_err("Unable to allocate struct tcm_loop_cmd\n");
-		set_host_byte(sc, DID_ERROR);
-		return NULL;
-	}
-	se_cmd = &tl_cmd->tl_se_cmd;
-	/*
-	 * Save the pointer to struct scsi_cmnd *sc
-	 */
-	tl_cmd->sc = sc;
-	/*
-	 * Locate the SAM Task Attr from struct scsi_cmnd *
-	 */
-	if (sc->device->tagged_supported) {
-		switch (sc->tag) {
-		case HEAD_OF_QUEUE_TAG:
-			sam_task_attr = MSG_HEAD_TAG;
-			break;
-		case ORDERED_QUEUE_TAG:
-			sam_task_attr = MSG_ORDERED_TAG;
-			break;
-		default:
-			sam_task_attr = MSG_SIMPLE_TAG;
-			break;
-		}
-	} else
-		sam_task_attr = MSG_SIMPLE_TAG;
-
-	/*
-	 * Initialize struct se_cmd descriptor from target_core_mod infrastructure
-	 */
-	transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess,
-			scsi_bufflen(sc), sc->sc_data_direction, sam_task_attr,
-			&tl_cmd->tl_sense_buf[0]);
-
-	if (scsi_bidi_cmnd(sc))
-		se_cmd->se_cmd_flags |= SCF_BIDI;
-
-	/*
-	 * Locate the struct se_lun pointer and attach it to struct se_cmd
-	 */
-	if (transport_lookup_cmd_lun(se_cmd, tl_cmd->sc->device->lun) < 0) {
-		kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);
-		set_host_byte(sc, DID_NO_CONNECT);
-		return NULL;
-	}
-
-	return se_cmd;
-}
-
-/*
- * Called by struct target_core_fabric_ops->new_cmd_map()
- *
- * Always called in process context.  A non zero return value
- * here will signal to handle an exception based on the return code.
- */
-static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd)
-{
-	struct tcm_loop_cmd *tl_cmd = container_of(se_cmd,
-				struct tcm_loop_cmd, tl_se_cmd);
-	struct scsi_cmnd *sc = tl_cmd->sc;
-	struct scatterlist *sgl_bidi = NULL;
-	u32 sgl_bidi_count = 0;
-	int ret;
-	/*
-	 * Allocate the necessary tasks to complete the received CDB+data
-	 */
-	ret = transport_generic_allocate_tasks(se_cmd, sc->cmnd);
-	if (ret != 0)
-		return ret;
-	/*
-	 * For BIDI commands, pass in the extra READ buffer
-	 * to transport_generic_map_mem_to_cmd() below..
-	 */
-	if (se_cmd->se_cmd_flags & SCF_BIDI) {
-		struct scsi_data_buffer *sdb = scsi_in(sc);
-
-		sgl_bidi = sdb->table.sgl;
-		sgl_bidi_count = sdb->table.nents;
-	}
-	/*
-	 * Because some userspace code via scsi-generic do not memset their
-	 * associated read buffers, go ahead and do that here for type
-	 * SCF_SCSI_CONTROL_SG_IO_CDB.  Also note that this is currently
-	 * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB
-	 * by target core in transport_generic_allocate_tasks() ->
-	 * transport_generic_cmd_sequencer().
-	 */
-	if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB &&
-	    se_cmd->data_direction == DMA_FROM_DEVICE) {
-		struct scatterlist *sg = scsi_sglist(sc);
-		unsigned char *buf = kmap(sg_page(sg)) + sg->offset;
-
-		if (buf != NULL) {
-			memset(buf, 0, sg->length);
-			kunmap(sg_page(sg));
-		}
-	}
-
-	/* Tell the core about our preallocated memory */
-	return transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc),
-			scsi_sg_count(sc), sgl_bidi, sgl_bidi_count);
-}
+static int tcm_loop_queue_status(struct se_cmd *se_cmd);
 
 /*
  * Called from struct target_core_fabric_ops->check_stop_free()
@@ -187,7 +61,7 @@
 	 * pointer.  These will be released directly in tcm_loop_device_reset()
 	 * with transport_generic_free_cmd().
 	 */
-	if (se_cmd->se_tmr_req)
+	if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
 		return 0;
 	/*
 	 * Release the struct se_cmd, which will make a callback to release
@@ -263,50 +137,152 @@
 }
 
 /*
- * Main entry point from struct scsi_host_template for incoming SCSI CDB+Data
- * from Linux/SCSI subsystem for SCSI low level device drivers (LLDs)
+ * Locate the SAM Task Attr from struct scsi_cmnd *
  */
-static int tcm_loop_queuecommand(
-	struct Scsi_Host *sh,
-	struct scsi_cmnd *sc)
+static int tcm_loop_sam_attr(struct scsi_cmnd *sc)
 {
-	struct se_cmd *se_cmd;
-	struct se_portal_group *se_tpg;
+	if (sc->device->tagged_supported) {
+		switch (sc->tag) {
+		case HEAD_OF_QUEUE_TAG:
+			return MSG_HEAD_TAG;
+		case ORDERED_QUEUE_TAG:
+			return MSG_ORDERED_TAG;
+		default:
+			break;
+		}
+	}
+
+	return MSG_SIMPLE_TAG;
+}
+
+static void tcm_loop_submission_work(struct work_struct *work)
+{
+	struct tcm_loop_cmd *tl_cmd =
+		container_of(work, struct tcm_loop_cmd, work);
+	struct se_cmd *se_cmd = &tl_cmd->tl_se_cmd;
+	struct scsi_cmnd *sc = tl_cmd->sc;
+	struct tcm_loop_nexus *tl_nexus;
 	struct tcm_loop_hba *tl_hba;
 	struct tcm_loop_tpg *tl_tpg;
+	struct scatterlist *sgl_bidi = NULL;
+	u32 sgl_bidi_count = 0;
+	int ret;
 
-	pr_debug("tcm_loop_queuecommand() %d:%d:%d:%d got CDB: 0x%02x"
-		" scsi_buf_len: %u\n", sc->device->host->host_no,
-		sc->device->id, sc->device->channel, sc->device->lun,
-		sc->cmnd[0], scsi_bufflen(sc));
-	/*
-	 * Locate the tcm_loop_hba_t pointer
-	 */
 	tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
 	tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
+
 	/*
 	 * Ensure that this tl_tpg reference from the incoming sc->device->id
 	 * has already been configured via tcm_loop_make_naa_tpg().
 	 */
 	if (!tl_tpg->tl_hba) {
 		set_host_byte(sc, DID_NO_CONNECT);
-		sc->scsi_done(sc);
-		return 0;
+		goto out_done;
 	}
-	se_tpg = &tl_tpg->tl_se_tpg;
+
+	tl_nexus = tl_hba->tl_nexus;
+	if (!tl_nexus) {
+		scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus"
+				" does not exist\n");
+		set_host_byte(sc, DID_ERROR);
+		goto out_done;
+	}
+
+	transport_init_se_cmd(se_cmd, tl_tpg->tl_se_tpg.se_tpg_tfo,
+			tl_nexus->se_sess,
+			scsi_bufflen(sc), sc->sc_data_direction,
+			tcm_loop_sam_attr(sc), &tl_cmd->tl_sense_buf[0]);
+
+	if (scsi_bidi_cmnd(sc)) {
+		struct scsi_data_buffer *sdb = scsi_in(sc);
+
+		sgl_bidi = sdb->table.sgl;
+		sgl_bidi_count = sdb->table.nents;
+		se_cmd->se_cmd_flags |= SCF_BIDI;
+
+	}
+
+	if (transport_lookup_cmd_lun(se_cmd, tl_cmd->sc->device->lun) < 0) {
+		kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);
+		set_host_byte(sc, DID_NO_CONNECT);
+		goto out_done;
+	}
+
 	/*
-	 * Determine the SAM Task Attribute and allocate tl_cmd and
-	 * tl_cmd->tl_se_cmd from TCM infrastructure
+	 * Because some userspace code via scsi-generic do not memset their
+	 * associated read buffers, go ahead and do that here for type
+	 * SCF_SCSI_CONTROL_SG_IO_CDB.  Also note that this is currently
+	 * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB
+	 * by target core in transport_generic_allocate_tasks() ->
+	 * transport_generic_cmd_sequencer().
 	 */
-	se_cmd = tcm_loop_allocate_core_cmd(tl_hba, se_tpg, sc);
-	if (!se_cmd) {
+	if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB &&
+	    se_cmd->data_direction == DMA_FROM_DEVICE) {
+		struct scatterlist *sg = scsi_sglist(sc);
+		unsigned char *buf = kmap(sg_page(sg)) + sg->offset;
+
+		if (buf != NULL) {
+			memset(buf, 0, sg->length);
+			kunmap(sg_page(sg));
+		}
+	}
+
+	ret = transport_generic_allocate_tasks(se_cmd, sc->cmnd);
+	if (ret == -ENOMEM) {
+		transport_send_check_condition_and_sense(se_cmd,
+				TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
+		transport_generic_free_cmd(se_cmd, 0);
+		return;
+	} else if (ret < 0) {
+		if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
+			tcm_loop_queue_status(se_cmd);
+		else
+			transport_send_check_condition_and_sense(se_cmd,
+					se_cmd->scsi_sense_reason, 0);
+		transport_generic_free_cmd(se_cmd, 0);
+		return;
+	}
+
+	ret = transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc),
+			scsi_sg_count(sc), sgl_bidi, sgl_bidi_count);
+	if (ret) {
+		transport_send_check_condition_and_sense(se_cmd,
+					se_cmd->scsi_sense_reason, 0);
+		transport_generic_free_cmd(se_cmd, 0);
+		return;
+	}
+	transport_handle_cdb_direct(se_cmd);
+	return;
+
+out_done:
+	sc->scsi_done(sc);
+	return;
+}
+
+/*
+ * ->queuecommand can be and usually is called from interrupt context, so
+ * defer the actual submission to a workqueue.
+ */
+static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
+{
+	struct tcm_loop_cmd *tl_cmd;
+
+	pr_debug("tcm_loop_queuecommand() %d:%d:%d:%d got CDB: 0x%02x"
+		" scsi_buf_len: %u\n", sc->device->host->host_no,
+		sc->device->id, sc->device->channel, sc->device->lun,
+		sc->cmnd[0], scsi_bufflen(sc));
+
+	tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_ATOMIC);
+	if (!tl_cmd) {
+		pr_err("Unable to allocate struct tcm_loop_cmd\n");
+		set_host_byte(sc, DID_ERROR);
 		sc->scsi_done(sc);
 		return 0;
 	}
-	/*
-	 * Queue up the newly allocated to be processed in TCM thread context.
-	*/
-	transport_generic_handle_cdb_map(se_cmd);
+
+	tl_cmd->sc = sc;
+	INIT_WORK(&tl_cmd->work, tcm_loop_submission_work);
+	queue_work(tcm_loop_workqueue, &tl_cmd->work);
 	return 0;
 }
 
@@ -324,7 +300,7 @@
 	struct tcm_loop_nexus *tl_nexus;
 	struct tcm_loop_tmr *tl_tmr = NULL;
 	struct tcm_loop_tpg *tl_tpg;
-	int ret = FAILED;
+	int ret = FAILED, rc;
 	/*
 	 * Locate the tcm_loop_hba_t pointer
 	 */
@@ -365,12 +341,9 @@
 	transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, 0,
 				DMA_NONE, MSG_SIMPLE_TAG,
 				&tl_cmd->tl_sense_buf[0]);
-	/*
-	 * Allocate the LUN_RESET TMR
-	 */
-	se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, tl_tmr,
-						TMR_LUN_RESET, GFP_KERNEL);
-	if (IS_ERR(se_cmd->se_tmr_req))
+
+	rc = core_tmr_alloc_req(se_cmd, tl_tmr, TMR_LUN_RESET, GFP_KERNEL);
+	if (rc < 0)
 		goto release;
 	/*
 	 * Locate the underlying TCM struct se_lun from sc->device->lun
@@ -762,22 +735,6 @@
 	return 1;
 }
 
-static int tcm_loop_is_state_remove(struct se_cmd *se_cmd)
-{
-	/*
-	 * Assume struct scsi_cmnd is not in remove state..
-	 */
-	return 0;
-}
-
-static int tcm_loop_sess_logged_in(struct se_session *se_sess)
-{
-	/*
-	 * Assume that TL Nexus is always active
-	 */
-	return 1;
-}
-
 static u32 tcm_loop_sess_get_index(struct se_session *se_sess)
 {
 	return 1;
@@ -811,19 +768,6 @@
 	return;
 };
 
-static void tcm_loop_stop_session(
-	struct se_session *se_sess,
-	int sess_sleep,
-	int conn_sleep)
-{
-	return;
-}
-
-static void tcm_loop_fall_back_to_erl0(struct se_session *se_sess)
-{
-	return;
-}
-
 static int tcm_loop_write_pending(struct se_cmd *se_cmd)
 {
 	/*
@@ -855,6 +799,9 @@
 
 	sc->result = SAM_STAT_GOOD;
 	set_host_byte(sc, DID_OK);
+	if ((se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) ||
+	    (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT))
+		scsi_set_resid(sc, se_cmd->residual_count);
 	sc->scsi_done(sc);
 	return 0;
 }
@@ -880,6 +827,9 @@
 		sc->result = se_cmd->scsi_status;
 
 	set_host_byte(sc, DID_OK);
+	if ((se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) ||
+	    (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT))
+		scsi_set_resid(sc, se_cmd->residual_count);
 	sc->scsi_done(sc);
 	return 0;
 }
@@ -1361,7 +1311,6 @@
 static int tcm_loop_register_configfs(void)
 {
 	struct target_fabric_configfs *fabric;
-	struct config_group *tf_cg;
 	int ret;
 	/*
 	 * Set the TCM Loop HBA counter to zero
@@ -1407,14 +1356,10 @@
 	/*
 	 * Used for setting up remaining TCM resources in process context
 	 */
-	fabric->tf_ops.new_cmd_map = &tcm_loop_new_cmd_map;
 	fabric->tf_ops.check_stop_free = &tcm_loop_check_stop_free;
 	fabric->tf_ops.release_cmd = &tcm_loop_release_cmd;
 	fabric->tf_ops.shutdown_session = &tcm_loop_shutdown_session;
 	fabric->tf_ops.close_session = &tcm_loop_close_session;
-	fabric->tf_ops.stop_session = &tcm_loop_stop_session;
-	fabric->tf_ops.fall_back_to_erl0 = &tcm_loop_fall_back_to_erl0;
-	fabric->tf_ops.sess_logged_in = &tcm_loop_sess_logged_in;
 	fabric->tf_ops.sess_get_index = &tcm_loop_sess_get_index;
 	fabric->tf_ops.sess_get_initiator_sid = NULL;
 	fabric->tf_ops.write_pending = &tcm_loop_write_pending;
@@ -1431,9 +1376,7 @@
 	fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp;
 	fabric->tf_ops.set_fabric_sense_len = &tcm_loop_set_fabric_sense_len;
 	fabric->tf_ops.get_fabric_sense_len = &tcm_loop_get_fabric_sense_len;
-	fabric->tf_ops.is_state_remove = &tcm_loop_is_state_remove;
 
-	tf_cg = &fabric->tf_group;
 	/*
 	 * Setup function pointers for generic logic in target_core_fabric_configfs.c
 	 */
@@ -1490,7 +1433,11 @@
 
 static int __init tcm_loop_fabric_init(void)
 {
-	int ret;
+	int ret = -ENOMEM;
+
+	tcm_loop_workqueue = alloc_workqueue("tcm_loop", 0, 0);
+	if (!tcm_loop_workqueue)
+		goto out;
 
 	tcm_loop_cmd_cache = kmem_cache_create("tcm_loop_cmd_cache",
 				sizeof(struct tcm_loop_cmd),
@@ -1499,20 +1446,27 @@
 	if (!tcm_loop_cmd_cache) {
 		pr_debug("kmem_cache_create() for"
 			" tcm_loop_cmd_cache failed\n");
-		return -ENOMEM;
+		goto out_destroy_workqueue;
 	}
 
 	ret = tcm_loop_alloc_core_bus();
 	if (ret)
-		return ret;
+		goto out_destroy_cache;
 
 	ret = tcm_loop_register_configfs();
-	if (ret) {
-		tcm_loop_release_core_bus();
-		return ret;
-	}
+	if (ret)
+		goto out_release_core_bus;
 
 	return 0;
+
+out_release_core_bus:
+	tcm_loop_release_core_bus();
+out_destroy_cache:
+	kmem_cache_destroy(tcm_loop_cmd_cache);
+out_destroy_workqueue:
+	destroy_workqueue(tcm_loop_workqueue);
+out:
+	return ret;
 }
 
 static void __exit tcm_loop_fabric_exit(void)
@@ -1520,6 +1474,7 @@
 	tcm_loop_deregister_configfs();
 	tcm_loop_release_core_bus();
 	kmem_cache_destroy(tcm_loop_cmd_cache);
+	destroy_workqueue(tcm_loop_workqueue);
 }
 
 MODULE_DESCRIPTION("TCM loopback virtual Linux/SCSI fabric module");
diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h
index 15a0364..7b54893 100644
--- a/drivers/target/loopback/tcm_loop.h
+++ b/drivers/target/loopback/tcm_loop.h
@@ -1,4 +1,4 @@
-#define TCM_LOOP_VERSION		"v2.1-rc1"
+#define TCM_LOOP_VERSION		"v2.1-rc2"
 #define TL_WWN_ADDR_LEN			256
 #define TL_TPGS_PER_HBA			32
 
@@ -12,9 +12,9 @@
 	u32 sc_cmd_state;
 	/* Pointer to the CDB+Data descriptor from Linux/SCSI subsystem */
 	struct scsi_cmnd *sc;
-	struct list_head *tl_cmd_list;
 	/* The TCM I/O descriptor that is accessed via container_of() */
 	struct se_cmd tl_se_cmd;
+	struct work_struct work;
 	/* Sense buffer that will be mapped into outgoing status */
 	unsigned char tl_sense_buf[TRANSPORT_SENSE_BUFFER];
 };
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 01a2691..c7746a3 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -30,6 +30,7 @@
 #include <linux/export.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
+#include <asm/unaligned.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_backend.h>
@@ -267,8 +268,7 @@
 		 * changed.
 		 */
 		if (primary) {
-			tg_pt_id = ((ptr[2] << 8) & 0xff);
-			tg_pt_id |= (ptr[3] & 0xff);
+			tg_pt_id = get_unaligned_be16(ptr + 2);
 			/*
 			 * Locate the matching target port group ID from
 			 * the global tg_pt_gp list
@@ -312,8 +312,7 @@
 			 * the Target Port in question for the the incoming
 			 * SET_TARGET_PORT_GROUPS op.
 			 */
-			rtpi = ((ptr[2] << 8) & 0xff);
-			rtpi |= (ptr[3] & 0xff);
+			rtpi = get_unaligned_be16(ptr + 2);
 			/*
 			 * Locate the matching relative target port identifer
 			 * for the struct se_device storage object.
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c
index f3d71fa..30a6770 100644
--- a/drivers/target/target_core_cdb.c
+++ b/drivers/target/target_core_cdb.c
@@ -66,32 +66,15 @@
 }
 
 static int
-target_emulate_inquiry_std(struct se_cmd *cmd)
+target_emulate_inquiry_std(struct se_cmd *cmd, char *buf)
 {
 	struct se_lun *lun = cmd->se_lun;
 	struct se_device *dev = cmd->se_dev;
-	struct se_portal_group *tpg = lun->lun_sep->sep_tpg;
-	unsigned char *buf;
 
-	/*
-	 * Make sure we at least have 6 bytes of INQUIRY response
-	 * payload going back for EVPD=0
-	 */
-	if (cmd->data_length < 6) {
-		pr_err("SCSI Inquiry payload length: %u"
-			" too small for EVPD=0\n", cmd->data_length);
-		return -EINVAL;
-	}
+	/* Set RMB (removable media) for tape devices */
+	if (dev->transport->get_device_type(dev) == TYPE_TAPE)
+		buf[1] = 0x80;
 
-	buf = transport_kmap_data_sg(cmd);
-
-	if (dev == tpg->tpg_virt_lun0.lun_se_dev) {
-		buf[0] = 0x3f; /* Not connected */
-	} else {
-		buf[0] = dev->transport->get_device_type(dev);
-		if (buf[0] == TYPE_TAPE)
-			buf[1] = 0x80;
-	}
 	buf[2] = dev->transport->get_device_rev(dev);
 
 	/*
@@ -112,29 +95,13 @@
 	if (dev->se_sub_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED)
 		target_fill_alua_data(lun->lun_sep, buf);
 
-	if (cmd->data_length < 8) {
-		buf[4] = 1; /* Set additional length to 1 */
-		goto out;
-	}
-
-	buf[7] = 0x32; /* Sync=1 and CmdQue=1 */
-
-	/*
-	 * Do not include vendor, product, reversion info in INQUIRY
-	 * response payload for cdbs with a small allocation length.
-	 */
-	if (cmd->data_length < 36) {
-		buf[4] = 3; /* Set additional length to 3 */
-		goto out;
-	}
+	buf[7] = 0x2; /* CmdQue=1 */
 
 	snprintf(&buf[8], 8, "LIO-ORG");
 	snprintf(&buf[16], 16, "%s", dev->se_sub_dev->t10_wwn.model);
 	snprintf(&buf[32], 4, "%s", dev->se_sub_dev->t10_wwn.revision);
 	buf[4] = 31; /* Set additional length to 31 */
 
-out:
-	transport_kunmap_data_sg(cmd);
 	return 0;
 }
 
@@ -152,12 +119,6 @@
 		unit_serial_len = strlen(dev->se_sub_dev->t10_wwn.unit_serial);
 		unit_serial_len++; /* For NULL Terminator */
 
-		if (((len + 4) + unit_serial_len) > cmd->data_length) {
-			len += unit_serial_len;
-			buf[2] = ((len >> 8) & 0xff);
-			buf[3] = (len & 0xff);
-			return 0;
-		}
 		len += sprintf(&buf[4], "%s",
 			dev->se_sub_dev->t10_wwn.unit_serial);
 		len++; /* Extra Byte for NULL Terminator */
@@ -229,9 +190,6 @@
 	if (!(dev->se_sub_dev->su_dev_flags & SDF_EMULATED_VPD_UNIT_SERIAL))
 		goto check_t10_vend_desc;
 
-	if (off + 20 > cmd->data_length)
-		goto check_t10_vend_desc;
-
 	/* CODE SET == Binary */
 	buf[off++] = 0x1;
 
@@ -283,12 +241,6 @@
 			strlen(&dev->se_sub_dev->t10_wwn.unit_serial[0]);
 		unit_serial_len++; /* For NULL Terminator */
 
-		if ((len + (id_len + 4) +
-		    (prod_len + unit_serial_len)) >
-				cmd->data_length) {
-			len += (prod_len + unit_serial_len);
-			goto check_port;
-		}
 		id_len += sprintf(&buf[off+12], "%s:%s", prod,
 				&dev->se_sub_dev->t10_wwn.unit_serial[0]);
 	}
@@ -306,7 +258,6 @@
 	/*
 	 * struct se_port is only set for INQUIRY VPD=1 through $FABRIC_MOD
 	 */
-check_port:
 	port = lun->lun_sep;
 	if (port) {
 		struct t10_alua_lu_gp *lu_gp;
@@ -323,10 +274,6 @@
 		 * Get the PROTOCOL IDENTIFIER as defined by spc4r17
 		 * section 7.5.1 Table 362
 		 */
-		if (((len + 4) + 8) > cmd->data_length) {
-			len += 8;
-			goto check_tpgi;
-		}
 		buf[off] =
 			(tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4);
 		buf[off++] |= 0x1; /* CODE SET == Binary */
@@ -350,15 +297,10 @@
 		 * Get the PROTOCOL IDENTIFIER as defined by spc4r17
 		 * section 7.5.1 Table 362
 		 */
-check_tpgi:
 		if (dev->se_sub_dev->t10_alua.alua_type !=
 				SPC3_ALUA_EMULATED)
 			goto check_scsi_name;
 
-		if (((len + 4) + 8) > cmd->data_length) {
-			len += 8;
-			goto check_lu_gp;
-		}
 		tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
 		if (!tg_pt_gp_mem)
 			goto check_lu_gp;
@@ -391,10 +333,6 @@
 		 * section 7.7.3.8
 		 */
 check_lu_gp:
-		if (((len + 4) + 8) > cmd->data_length) {
-			len += 8;
-			goto check_scsi_name;
-		}
 		lu_gp_mem = dev->dev_alua_lu_gp_mem;
 		if (!lu_gp_mem)
 			goto check_scsi_name;
@@ -435,10 +373,6 @@
 		/* Header size + Designation descriptor */
 		scsi_name_len += 4;
 
-		if (((len + 4) + scsi_name_len) > cmd->data_length) {
-			len += scsi_name_len;
-			goto set_len;
-		}
 		buf[off] =
 			(tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4);
 		buf[off++] |= 0x3; /* CODE SET == UTF-8 */
@@ -474,7 +408,6 @@
 		/* Header size + Designation descriptor */
 		len += (scsi_name_len + 4);
 	}
-set_len:
 	buf[2] = ((len >> 8) & 0xff);
 	buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */
 	return 0;
@@ -484,9 +417,6 @@
 static int
 target_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
 {
-	if (cmd->data_length < 60)
-		return 0;
-
 	buf[3] = 0x3c;
 	/* Set HEADSUP, ORDSUP, SIMPSUP */
 	buf[5] = 0x07;
@@ -512,20 +442,6 @@
 	if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws)
 		have_tp = 1;
 
-	if (cmd->data_length < (0x10 + 4)) {
-		pr_debug("Received data_length: %u"
-			" too small for EVPD 0xb0\n",
-			cmd->data_length);
-		return -EINVAL;
-	}
-
-	if (have_tp && cmd->data_length < (0x3c + 4)) {
-		pr_debug("Received data_length: %u"
-			" too small for TPE=1 EVPD 0xb0\n",
-			cmd->data_length);
-		have_tp = 0;
-	}
-
 	buf[0] = dev->transport->get_device_type(dev);
 	buf[3] = have_tp ? 0x3c : 0x10;
 
@@ -540,7 +456,7 @@
 	/*
 	 * Set MAXIMUM TRANSFER LENGTH
 	 */
-	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.max_sectors, &buf[8]);
+	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.fabric_max_sectors, &buf[8]);
 
 	/*
 	 * Set OPTIMAL TRANSFER LENGTH
@@ -548,10 +464,9 @@
 	put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.optimal_sectors, &buf[12]);
 
 	/*
-	 * Exit now if we don't support TP or the initiator sent a too
-	 * short buffer.
+	 * Exit now if we don't support TP.
 	 */
-	if (!have_tp || cmd->data_length < (0x3c + 4))
+	if (!have_tp)
 		return 0;
 
 	/*
@@ -589,10 +504,7 @@
 
 	buf[0] = dev->transport->get_device_type(dev);
 	buf[3] = 0x3c;
-
-	if (cmd->data_length >= 5 &&
-	    dev->se_sub_dev->se_dev_attrib.is_nonrot)
-		buf[5] = 1;
+	buf[5] = dev->se_sub_dev->se_dev_attrib.is_nonrot ? 1 : 0;
 
 	return 0;
 }
@@ -671,8 +583,6 @@
 {
 	int p;
 
-	if (cmd->data_length < 8)
-		return 0;
 	/*
 	 * Only report the INQUIRY EVPD=1 pages after a valid NAA
 	 * Registered Extended LUN WWN has been set via ConfigFS
@@ -681,8 +591,7 @@
 	if (cmd->se_dev->se_sub_dev->su_dev_flags &
 			SDF_EMULATED_VPD_UNIT_SERIAL) {
 		buf[3] = ARRAY_SIZE(evpd_handlers);
-		for (p = 0; p < min_t(int, ARRAY_SIZE(evpd_handlers),
-				      cmd->data_length - 4); ++p)
+		for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p)
 			buf[p + 4] = evpd_handlers[p].page;
 	}
 
@@ -693,45 +602,54 @@
 {
 	struct se_cmd *cmd = task->task_se_cmd;
 	struct se_device *dev = cmd->se_dev;
-	unsigned char *buf;
+	struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg;
+	unsigned char *buf, *map_buf;
 	unsigned char *cdb = cmd->t_task_cdb;
 	int p, ret;
 
+	map_buf = transport_kmap_data_sg(cmd);
+	/*
+	 * If SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is not set, then we
+	 * know we actually allocated a full page.  Otherwise, if the
+	 * data buffer is too small, allocate a temporary buffer so we
+	 * don't have to worry about overruns in all our INQUIRY
+	 * emulation handling.
+	 */
+	if (cmd->data_length < SE_INQUIRY_BUF &&
+	    (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) {
+		buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL);
+		if (!buf) {
+			transport_kunmap_data_sg(cmd);
+			cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+			return -ENOMEM;
+		}
+	} else {
+		buf = map_buf;
+	}
+
+	if (dev == tpg->tpg_virt_lun0.lun_se_dev)
+		buf[0] = 0x3f; /* Not connected */
+	else
+		buf[0] = dev->transport->get_device_type(dev);
+
 	if (!(cdb[1] & 0x1)) {
 		if (cdb[2]) {
 			pr_err("INQUIRY with EVPD==0 but PAGE CODE=%02x\n",
 			       cdb[2]);
 			cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 
-		ret = target_emulate_inquiry_std(cmd);
+		ret = target_emulate_inquiry_std(cmd, buf);
 		goto out;
 	}
 
-	/*
-	 * Make sure we at least have 4 bytes of INQUIRY response
-	 * payload for 0x00 going back for EVPD=1.  Note that 0x80
-	 * and 0x83 will check for enough payload data length and
-	 * jump to set_len: label when there is not enough inquiry EVPD
-	 * payload length left for the next outgoing EVPD metadata
-	 */
-	if (cmd->data_length < 4) {
-		pr_err("SCSI Inquiry payload length: %u"
-			" too small for EVPD=1\n", cmd->data_length);
-		cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
-		return -EINVAL;
-	}
-
-	buf = transport_kmap_data_sg(cmd);
-
-	buf[0] = dev->transport->get_device_type(dev);
-
 	for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) {
 		if (cdb[2] == evpd_handlers[p].page) {
 			buf[1] = cdb[2];
 			ret = evpd_handlers[p].emulate(cmd, buf);
-			goto out_unmap;
+			goto out;
 		}
 	}
 
@@ -739,9 +657,13 @@
 	cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
 	ret = -EINVAL;
 
-out_unmap:
-	transport_kunmap_data_sg(cmd);
 out:
+	if (buf != map_buf) {
+		memcpy(map_buf, buf, cmd->data_length);
+		kfree(buf);
+	}
+	transport_kunmap_data_sg(cmd);
+
 	if (!ret) {
 		task->task_scsi_status = GOOD;
 		transport_complete_task(task, 1);
@@ -772,11 +694,6 @@
 	buf[5] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff;
 	buf[6] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff;
 	buf[7] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff;
-	/*
-	 * Set max 32-bit blocks to signal SERVICE ACTION READ_CAPACITY_16
-	*/
-	if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws)
-		put_unaligned_be32(0xFFFFFFFF, &buf[0]);
 
 	transport_kunmap_data_sg(cmd);
 
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 6e043ee..cbb6653 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -52,8 +52,8 @@
 
 extern struct t10_alua_lu_gp *default_lu_gp;
 
-static struct list_head g_tf_list;
-static struct mutex g_tf_lock;
+static LIST_HEAD(g_tf_list);
+static DEFINE_MUTEX(g_tf_lock);
 
 struct target_core_configfs_attribute {
 	struct configfs_attribute attr;
@@ -421,18 +421,6 @@
 		pr_err("Missing tfo->close_session()\n");
 		return -EINVAL;
 	}
-	if (!tfo->stop_session) {
-		pr_err("Missing tfo->stop_session()\n");
-		return -EINVAL;
-	}
-	if (!tfo->fall_back_to_erl0) {
-		pr_err("Missing tfo->fall_back_to_erl0()\n");
-		return -EINVAL;
-	}
-	if (!tfo->sess_logged_in) {
-		pr_err("Missing tfo->sess_logged_in()\n");
-		return -EINVAL;
-	}
 	if (!tfo->sess_get_index) {
 		pr_err("Missing tfo->sess_get_index()\n");
 		return -EINVAL;
@@ -477,10 +465,6 @@
 		pr_err("Missing tfo->get_fabric_sense_len()\n");
 		return -EINVAL;
 	}
-	if (!tfo->is_state_remove) {
-		pr_err("Missing tfo->is_state_remove()\n");
-		return -EINVAL;
-	}
 	/*
 	 * We at least require tfo->fabric_make_wwn(), tfo->fabric_drop_wwn()
 	 * tfo->fabric_make_tpg() and tfo->fabric_drop_tpg() in
@@ -702,6 +686,9 @@
 DEF_DEV_ATTRIB(max_sectors);
 SE_DEV_ATTR(max_sectors, S_IRUGO | S_IWUSR);
 
+DEF_DEV_ATTRIB(fabric_max_sectors);
+SE_DEV_ATTR(fabric_max_sectors, S_IRUGO | S_IWUSR);
+
 DEF_DEV_ATTRIB(optimal_sectors);
 SE_DEV_ATTR(optimal_sectors, S_IRUGO | S_IWUSR);
 
@@ -741,6 +728,7 @@
 	&target_core_dev_attrib_block_size.attr,
 	&target_core_dev_attrib_hw_max_sectors.attr,
 	&target_core_dev_attrib_max_sectors.attr,
+	&target_core_dev_attrib_fabric_max_sectors.attr,
 	&target_core_dev_attrib_optimal_sectors.attr,
 	&target_core_dev_attrib_hw_queue_depth.attr,
 	&target_core_dev_attrib_queue_depth.attr,
@@ -2304,7 +2292,7 @@
 
 	if (!(tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICT_ALUA)) {
 		pr_err("Unable to process implict configfs ALUA"
-			" transition while TPGS_IMPLICT_ALUA is diabled\n");
+			" transition while TPGS_IMPLICT_ALUA is disabled\n");
 		return -EINVAL;
 	}
 
@@ -2865,7 +2853,6 @@
 	struct se_subsystem_dev *se_dev = container_of(to_config_group(item),
 				struct se_subsystem_dev, se_dev_group);
 	struct se_hba *hba;
-	struct se_subsystem_api *t;
 	struct config_item *df_item;
 	struct config_group *dev_cg, *tg_pt_gp_cg, *dev_stat_grp;
 	int i;
@@ -2873,7 +2860,6 @@
 	hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item);
 
 	mutex_lock(&hba->hba_access_mutex);
-	t = hba->transport;
 
 	dev_stat_grp = &se_dev->dev_stat_grps.stat_group;
 	for (i = 0; dev_stat_grp->default_groups[i]; i++) {
@@ -3117,8 +3103,6 @@
 	config_group_init(&subsys->su_group);
 	mutex_init(&subsys->su_mutex);
 
-	INIT_LIST_HEAD(&g_tf_list);
-	mutex_init(&g_tf_lock);
 	ret = init_se_kmem_caches();
 	if (ret < 0)
 		return ret;
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index edbcabb..aa62677 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -72,7 +72,7 @@
 	}
 
 	spin_lock_irqsave(&se_sess->se_node_acl->device_list_lock, flags);
-	se_cmd->se_deve = &se_sess->se_node_acl->device_list[unpacked_lun];
+	se_cmd->se_deve = se_sess->se_node_acl->device_list[unpacked_lun];
 	if (se_cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) {
 		struct se_dev_entry *deve = se_cmd->se_deve;
 
@@ -159,13 +159,8 @@
 		dev->read_bytes += se_cmd->data_length;
 	spin_unlock_irqrestore(&dev->stats_lock, flags);
 
-	/*
-	 * Add the iscsi_cmd_t to the struct se_lun's cmd list.  This list is used
-	 * for tracking state of struct se_cmds during LUN shutdown events.
-	 */
 	spin_lock_irqsave(&se_lun->lun_cmd_lock, flags);
 	list_add_tail(&se_cmd->se_lun_node, &se_lun->lun_cmd_list);
-	atomic_set(&se_cmd->transport_lun_active, 1);
 	spin_unlock_irqrestore(&se_lun->lun_cmd_lock, flags);
 
 	return 0;
@@ -187,7 +182,7 @@
 	}
 
 	spin_lock_irqsave(&se_sess->se_node_acl->device_list_lock, flags);
-	se_cmd->se_deve = &se_sess->se_node_acl->device_list[unpacked_lun];
+	se_cmd->se_deve = se_sess->se_node_acl->device_list[unpacked_lun];
 	deve = se_cmd->se_deve;
 
 	if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) {
@@ -245,7 +240,7 @@
 
 	spin_lock_irq(&nacl->device_list_lock);
 	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
-		deve = &nacl->device_list[i];
+		deve = nacl->device_list[i];
 
 		if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS))
 			continue;
@@ -291,7 +286,7 @@
 
 	spin_lock_irq(&nacl->device_list_lock);
 	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
-		deve = &nacl->device_list[i];
+		deve = nacl->device_list[i];
 
 		if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS))
 			continue;
@@ -311,7 +306,7 @@
 	}
 	spin_unlock_irq(&nacl->device_list_lock);
 
-	kfree(nacl->device_list);
+	array_free(nacl->device_list, TRANSPORT_MAX_LUNS_PER_TPG);
 	nacl->device_list = NULL;
 
 	return 0;
@@ -323,7 +318,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&se_nacl->device_list_lock, flags);
-	deve = &se_nacl->device_list[se_cmd->orig_fe_lun];
+	deve = se_nacl->device_list[se_cmd->orig_fe_lun];
 	deve->deve_cmds--;
 	spin_unlock_irqrestore(&se_nacl->device_list_lock, flags);
 }
@@ -336,7 +331,7 @@
 	struct se_dev_entry *deve;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[mapped_lun];
+	deve = nacl->device_list[mapped_lun];
 	if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) {
 		deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY;
 		deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE;
@@ -361,7 +356,7 @@
 	int enable)
 {
 	struct se_port *port = lun->lun_sep;
-	struct se_dev_entry *deve = &nacl->device_list[mapped_lun];
+	struct se_dev_entry *deve = nacl->device_list[mapped_lun];
 	int trans = 0;
 	/*
 	 * If the MappedLUN entry is being disabled, the entry in
@@ -475,7 +470,7 @@
 
 		spin_lock_irq(&nacl->device_list_lock);
 		for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
-			deve = &nacl->device_list[i];
+			deve = nacl->device_list[i];
 			if (lun != deve->se_lun)
 				continue;
 			spin_unlock_irq(&nacl->device_list_lock);
@@ -652,12 +647,13 @@
 {
 	struct se_cmd *se_cmd = se_task->task_se_cmd;
 	struct se_dev_entry *deve;
-	struct se_lun *se_lun;
 	struct se_session *se_sess = se_cmd->se_sess;
 	unsigned char *buf;
-	u32 cdb_offset = 0, lun_count = 0, offset = 8, i;
+	u32 lun_count = 0, offset = 8, i;
 
-	buf = (unsigned char *) transport_kmap_data_sg(se_cmd);
+	buf = transport_kmap_data_sg(se_cmd);
+	if (!buf)
+		return -ENOMEM;
 
 	/*
 	 * If no struct se_session pointer is present, this struct se_cmd is
@@ -672,22 +668,20 @@
 
 	spin_lock_irq(&se_sess->se_node_acl->device_list_lock);
 	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
-		deve = &se_sess->se_node_acl->device_list[i];
+		deve = se_sess->se_node_acl->device_list[i];
 		if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS))
 			continue;
-		se_lun = deve->se_lun;
 		/*
 		 * We determine the correct LUN LIST LENGTH even once we
 		 * have reached the initial allocation length.
 		 * See SPC2-R20 7.19.
 		 */
 		lun_count++;
-		if ((cdb_offset + 8) >= se_cmd->data_length)
+		if ((offset + 8) > se_cmd->data_length)
 			continue;
 
 		int_to_scsilun(deve->mapped_lun, (struct scsi_lun *)&buf[offset]);
 		offset += 8;
-		cdb_offset += 8;
 	}
 	spin_unlock_irq(&se_sess->se_node_acl->device_list_lock);
 
@@ -695,12 +689,12 @@
 	 * See SPC3 r07, page 159.
 	 */
 done:
-	transport_kunmap_data_sg(se_cmd);
 	lun_count *= 8;
 	buf[0] = ((lun_count >> 24) & 0xff);
 	buf[1] = ((lun_count >> 16) & 0xff);
 	buf[2] = ((lun_count >> 8) & 0xff);
 	buf[3] = (lun_count & 0xff);
+	transport_kunmap_data_sg(se_cmd);
 
 	se_task->task_scsi_status = GOOD;
 	transport_complete_task(se_task, 1);
@@ -894,10 +888,15 @@
 						limits->logical_block_size);
 	dev->se_sub_dev->se_dev_attrib.max_sectors = limits->max_sectors;
 	/*
-	 * Set optimal_sectors from max_sectors, which can be lowered via
-	 * configfs.
+	 * Set fabric_max_sectors, which is reported in block limits
+	 * VPD page (B0h).
 	 */
-	dev->se_sub_dev->se_dev_attrib.optimal_sectors = limits->max_sectors;
+	dev->se_sub_dev->se_dev_attrib.fabric_max_sectors = DA_FABRIC_MAX_SECTORS;
+	/*
+	 * Set optimal_sectors from fabric_max_sectors, which can be
+	 * lowered via configfs.
+	 */
+	dev->se_sub_dev->se_dev_attrib.optimal_sectors = DA_FABRIC_MAX_SECTORS;
 	/*
 	 * queue_depth is based on subsystem plugin dependent requirements.
 	 */
@@ -1229,6 +1228,54 @@
 	return 0;
 }
 
+int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors)
+{
+	if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+		pr_err("dev[%p]: Unable to change SE Device"
+			" fabric_max_sectors while dev_export_obj: %d count exists\n",
+			dev, atomic_read(&dev->dev_export_obj.obj_access_count));
+		return -EINVAL;
+	}
+	if (!fabric_max_sectors) {
+		pr_err("dev[%p]: Illegal ZERO value for"
+			" fabric_max_sectors\n", dev);
+		return -EINVAL;
+	}
+	if (fabric_max_sectors < DA_STATUS_MAX_SECTORS_MIN) {
+		pr_err("dev[%p]: Passed fabric_max_sectors: %u less than"
+			" DA_STATUS_MAX_SECTORS_MIN: %u\n", dev, fabric_max_sectors,
+				DA_STATUS_MAX_SECTORS_MIN);
+		return -EINVAL;
+	}
+	if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+		if (fabric_max_sectors > dev->se_sub_dev->se_dev_attrib.hw_max_sectors) {
+			pr_err("dev[%p]: Passed fabric_max_sectors: %u"
+				" greater than TCM/SE_Device max_sectors:"
+				" %u\n", dev, fabric_max_sectors,
+				dev->se_sub_dev->se_dev_attrib.hw_max_sectors);
+			 return -EINVAL;
+		}
+	} else {
+		if (fabric_max_sectors > DA_STATUS_MAX_SECTORS_MAX) {
+			pr_err("dev[%p]: Passed fabric_max_sectors: %u"
+				" greater than DA_STATUS_MAX_SECTORS_MAX:"
+				" %u\n", dev, fabric_max_sectors,
+				DA_STATUS_MAX_SECTORS_MAX);
+			return -EINVAL;
+		}
+	}
+	/*
+	 * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks()
+	 */
+	fabric_max_sectors = se_dev_align_max_sectors(fabric_max_sectors,
+						      dev->se_sub_dev->se_dev_attrib.block_size);
+
+	dev->se_sub_dev->se_dev_attrib.fabric_max_sectors = fabric_max_sectors;
+	pr_debug("dev[%p]: SE Device max_sectors changed to %u\n",
+			dev, fabric_max_sectors);
+	return 0;
+}
+
 int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors)
 {
 	if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
@@ -1242,10 +1289,10 @@
 				" changed for TCM/pSCSI\n", dev);
 		return -EINVAL;
 	}
-	if (optimal_sectors > dev->se_sub_dev->se_dev_attrib.max_sectors) {
+	if (optimal_sectors > dev->se_sub_dev->se_dev_attrib.fabric_max_sectors) {
 		pr_err("dev[%p]: Passed optimal_sectors %u cannot be"
-			" greater than max_sectors: %u\n", dev,
-			optimal_sectors, dev->se_sub_dev->se_dev_attrib.max_sectors);
+			" greater than fabric_max_sectors: %u\n", dev,
+			optimal_sectors, dev->se_sub_dev->se_dev_attrib.fabric_max_sectors);
 		return -EINVAL;
 	}
 
@@ -1380,7 +1427,7 @@
 		spin_unlock(&tpg->tpg_lun_lock);
 		return NULL;
 	}
-	lun = &tpg->tpg_lun_list[unpacked_lun];
+	lun = tpg->tpg_lun_list[unpacked_lun];
 
 	if (lun->lun_status != TRANSPORT_LUN_STATUS_FREE) {
 		pr_err("%s Logical Unit Number: %u is not free on"
@@ -1413,7 +1460,7 @@
 		spin_unlock(&tpg->tpg_lun_lock);
 		return NULL;
 	}
-	lun = &tpg->tpg_lun_list[unpacked_lun];
+	lun = tpg->tpg_lun_list[unpacked_lun];
 
 	if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) {
 		pr_err("%s Logical Unit Number: %u is not active on"
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index 9a2ce11..405cc98 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -108,7 +108,7 @@
 	 * tpg_1/attrib/demo_mode_write_protect=1
 	 */
 	spin_lock_irq(&lacl->se_lun_nacl->device_list_lock);
-	deve = &lacl->se_lun_nacl->device_list[lacl->mapped_lun];
+	deve = lacl->se_lun_nacl->device_list[lacl->mapped_lun];
 	if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)
 		lun_access = deve->lun_flags;
 	else
@@ -137,7 +137,7 @@
 	struct se_lun_acl *lacl = container_of(to_config_group(lun_acl_ci),
 			struct se_lun_acl, se_lun_group);
 	struct se_node_acl *nacl = lacl->se_lun_nacl;
-	struct se_dev_entry *deve = &nacl->device_list[lacl->mapped_lun];
+	struct se_dev_entry *deve = nacl->device_list[lacl->mapped_lun];
 	struct se_portal_group *se_tpg;
 	/*
 	 * Determine if the underlying MappedLUN has already been released..
@@ -168,7 +168,7 @@
 	ssize_t len;
 
 	spin_lock_irq(&se_nacl->device_list_lock);
-	deve = &se_nacl->device_list[lacl->mapped_lun];
+	deve = se_nacl->device_list[lacl->mapped_lun];
 	len = sprintf(page, "%d\n",
 			(deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) ?
 			1 : 0);
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 8572eae..2ec299e 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -46,6 +46,9 @@
 
 #include "target_core_iblock.h"
 
+#define IBLOCK_MAX_BIO_PER_TASK	 32	/* max # of bios to submit at a time */
+#define IBLOCK_BIO_POOL_SIZE	128
+
 static struct se_subsystem_api iblock_template;
 
 static void iblock_bio_done(struct bio *, int);
@@ -56,51 +59,25 @@
  */
 static int iblock_attach_hba(struct se_hba *hba, u32 host_id)
 {
-	struct iblock_hba *ib_host;
-
-	ib_host = kzalloc(sizeof(struct iblock_hba), GFP_KERNEL);
-	if (!ib_host) {
-		pr_err("Unable to allocate memory for"
-				" struct iblock_hba\n");
-		return -ENOMEM;
-	}
-
-	ib_host->iblock_host_id = host_id;
-
-	hba->hba_ptr = ib_host;
-
 	pr_debug("CORE_HBA[%d] - TCM iBlock HBA Driver %s on"
 		" Generic Target Core Stack %s\n", hba->hba_id,
 		IBLOCK_VERSION, TARGET_CORE_MOD_VERSION);
-
-	pr_debug("CORE_HBA[%d] - Attached iBlock HBA: %u to Generic\n",
-		hba->hba_id, ib_host->iblock_host_id);
-
 	return 0;
 }
 
 static void iblock_detach_hba(struct se_hba *hba)
 {
-	struct iblock_hba *ib_host = hba->hba_ptr;
-
-	pr_debug("CORE_HBA[%d] - Detached iBlock HBA: %u from Generic"
-		" Target Core\n", hba->hba_id, ib_host->iblock_host_id);
-
-	kfree(ib_host);
-	hba->hba_ptr = NULL;
 }
 
 static void *iblock_allocate_virtdevice(struct se_hba *hba, const char *name)
 {
 	struct iblock_dev *ib_dev = NULL;
-	struct iblock_hba *ib_host = hba->hba_ptr;
 
 	ib_dev = kzalloc(sizeof(struct iblock_dev), GFP_KERNEL);
 	if (!ib_dev) {
 		pr_err("Unable to allocate struct iblock_dev\n");
 		return NULL;
 	}
-	ib_dev->ibd_host = ib_host;
 
 	pr_debug( "IBLOCK: Allocated ib_dev for %s\n", name);
 
@@ -126,10 +103,8 @@
 		return ERR_PTR(ret);
 	}
 	memset(&dev_limits, 0, sizeof(struct se_dev_limits));
-	/*
-	 * These settings need to be made tunable..
-	 */
-	ib_dev->ibd_bio_set = bioset_create(32, 0);
+
+	ib_dev->ibd_bio_set = bioset_create(IBLOCK_BIO_POOL_SIZE, 0);
 	if (!ib_dev->ibd_bio_set) {
 		pr_err("IBLOCK: Unable to create bioset()\n");
 		return ERR_PTR(-ENOMEM);
@@ -155,8 +130,8 @@
 	q = bdev_get_queue(bd);
 	limits = &dev_limits.limits;
 	limits->logical_block_size = bdev_logical_block_size(bd);
-	limits->max_hw_sectors = queue_max_hw_sectors(q);
-	limits->max_sectors = queue_max_sectors(q);
+	limits->max_hw_sectors = UINT_MAX;
+	limits->max_sectors = UINT_MAX;
 	dev_limits.hw_queue_depth = q->nr_requests;
 	dev_limits.queue_depth = q->nr_requests;
 
@@ -230,7 +205,7 @@
 		return NULL;
 	}
 
-	atomic_set(&ib_req->ib_bio_cnt, 0);
+	atomic_set(&ib_req->pending, 1);
 	return &ib_req->ib_task;
 }
 
@@ -510,24 +485,35 @@
 	bio->bi_destructor = iblock_bio_destructor;
 	bio->bi_end_io = &iblock_bio_done;
 	bio->bi_sector = lba;
-	atomic_inc(&ib_req->ib_bio_cnt);
+	atomic_inc(&ib_req->pending);
 
 	pr_debug("Set bio->bi_sector: %llu\n", (unsigned long long)bio->bi_sector);
-	pr_debug("Set ib_req->ib_bio_cnt: %d\n",
-			atomic_read(&ib_req->ib_bio_cnt));
+	pr_debug("Set ib_req->pending: %d\n", atomic_read(&ib_req->pending));
 	return bio;
 }
 
+static void iblock_submit_bios(struct bio_list *list, int rw)
+{
+	struct blk_plug plug;
+	struct bio *bio;
+
+	blk_start_plug(&plug);
+	while ((bio = bio_list_pop(list)))
+		submit_bio(rw, bio);
+	blk_finish_plug(&plug);
+}
+
 static int iblock_do_task(struct se_task *task)
 {
 	struct se_cmd *cmd = task->task_se_cmd;
 	struct se_device *dev = cmd->se_dev;
+	struct iblock_req *ibr = IBLOCK_REQ(task);
 	struct bio *bio;
 	struct bio_list list;
 	struct scatterlist *sg;
 	u32 i, sg_num = task->task_sg_nents;
 	sector_t block_lba;
-	struct blk_plug plug;
+	unsigned bio_cnt;
 	int rw;
 
 	if (task->task_data_direction == DMA_TO_DEVICE) {
@@ -572,6 +558,7 @@
 
 	bio_list_init(&list);
 	bio_list_add(&list, bio);
+	bio_cnt = 1;
 
 	for_each_sg(task->task_sg, sg, task->task_sg_nents, i) {
 		/*
@@ -581,10 +568,16 @@
 		 */
 		while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset)
 				!= sg->length) {
+			if (bio_cnt >= IBLOCK_MAX_BIO_PER_TASK) {
+				iblock_submit_bios(&list, rw);
+				bio_cnt = 0;
+			}
+
 			bio = iblock_get_bio(task, block_lba, sg_num);
 			if (!bio)
 				goto fail;
 			bio_list_add(&list, bio);
+			bio_cnt++;
 		}
 
 		/* Always in 512 byte units for Linux/Block */
@@ -592,11 +585,12 @@
 		sg_num--;
 	}
 
-	blk_start_plug(&plug);
-	while ((bio = bio_list_pop(&list)))
-		submit_bio(rw, bio);
-	blk_finish_plug(&plug);
+	iblock_submit_bios(&list, rw);
 
+	if (atomic_dec_and_test(&ibr->pending)) {
+		transport_complete_task(task,
+				!atomic_read(&ibr->ib_bio_err_cnt));
+	}
 	return 0;
 
 fail:
@@ -648,7 +642,7 @@
 
 	bio_put(bio);
 
-	if (!atomic_dec_and_test(&ibr->ib_bio_cnt))
+	if (!atomic_dec_and_test(&ibr->pending))
 		return;
 
 	pr_debug("done[%p] bio: %p task_lba: %llu bio_lba: %llu err=%d\n",
diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h
index 5cf1860..e929370 100644
--- a/drivers/target/target_core_iblock.h
+++ b/drivers/target/target_core_iblock.h
@@ -8,7 +8,7 @@
 
 struct iblock_req {
 	struct se_task ib_task;
-	atomic_t ib_bio_cnt;
+	atomic_t pending;
 	atomic_t ib_bio_err_cnt;
 } ____cacheline_aligned;
 
@@ -19,11 +19,6 @@
 	u32	ibd_flags;
 	struct bio_set	*ibd_bio_set;
 	struct block_device *ibd_bd;
-	struct iblock_hba *ibd_host;
-} ____cacheline_aligned;
-
-struct iblock_hba {
-	int		iblock_host_id;
 } ____cacheline_aligned;
 
 #endif /* TARGET_CORE_IBLOCK_H */
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index 4500136..21c0563 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -53,6 +53,7 @@
 int	se_dev_set_emulate_rest_reord(struct se_device *dev, int);
 int	se_dev_set_queue_depth(struct se_device *, u32);
 int	se_dev_set_max_sectors(struct se_device *, u32);
+int	se_dev_set_fabric_max_sectors(struct se_device *, u32);
 int	se_dev_set_optimal_sectors(struct se_device *, u32);
 int	se_dev_set_block_size(struct se_device *, u32);
 struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_hba *,
@@ -75,6 +76,8 @@
 int	core_delete_hba(struct se_hba *);
 
 /* target_core_tmr.c */
+void	core_tmr_abort_task(struct se_device *, struct se_tmr_req *,
+			struct se_session *);
 int	core_tmr_lun_reset(struct se_device *, struct se_tmr_req *,
 		struct list_head *, struct se_cmd *);
 
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 63e703b..86f0c3b 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -338,7 +338,7 @@
 		return core_scsi2_reservation_seq_non_holder(cmd,
 					cdb, pr_reg_type);
 
-	se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
+	se_deve = se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
 	/*
 	 * Determine if the registration should be ignored due to
 	 * non-matching ISIDs in core_scsi3_pr_reservation_check().
@@ -1000,7 +1000,7 @@
 {
 	struct se_subsystem_dev *su_dev = dev->se_sub_dev;
 	struct se_node_acl *nacl = lun_acl->se_lun_nacl;
-	struct se_dev_entry *deve = &nacl->device_list[lun_acl->mapped_lun];
+	struct se_dev_entry *deve = nacl->device_list[lun_acl->mapped_lun];
 
 	if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS)
 		return 0;
@@ -1497,7 +1497,7 @@
 	struct se_dev_entry *dest_se_deve = NULL, *local_se_deve;
 	struct t10_pr_registration *dest_pr_reg, *local_pr_reg, *pr_reg_e;
 	struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe;
-	struct list_head tid_dest_list;
+	LIST_HEAD(tid_dest_list);
 	struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp;
 	struct target_core_fabric_ops *tmp_tf_ops;
 	unsigned char *buf;
@@ -1508,9 +1508,8 @@
 	u32 dest_rtpi = 0;
 
 	memset(dest_iport, 0, 64);
-	INIT_LIST_HEAD(&tid_dest_list);
 
-	local_se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
+	local_se_deve = se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
 	/*
 	 * Allocate a struct pr_transport_id_holder and setup the
 	 * local_node_acl and local_se_deve pointers and add to
@@ -2127,7 +2126,7 @@
 		return -EINVAL;
 	}
 	se_tpg = se_sess->se_tpg;
-	se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
+	se_deve = se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
 
 	if (se_tpg->se_tpg_tfo->sess_get_initiator_sid) {
 		memset(&isid_buf[0], 0, PR_REG_ISID_LEN);
@@ -2427,9 +2426,7 @@
 	u64 res_key)
 {
 	struct se_session *se_sess = cmd->se_sess;
-	struct se_dev_entry *se_deve;
 	struct se_lun *se_lun = cmd->se_lun;
-	struct se_portal_group *se_tpg;
 	struct t10_pr_registration *pr_reg, *pr_res_holder;
 	struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr;
 	char i_buf[PR_REG_ISID_ID_LEN];
@@ -2442,8 +2439,6 @@
 		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 		return -EINVAL;
 	}
-	se_tpg = se_sess->se_tpg;
-	se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
 	/*
 	 * Locate the existing *pr_reg via struct se_node_acl pointers
 	 */
@@ -3001,10 +2996,9 @@
 	int abort)
 {
 	struct se_device *dev = cmd->se_dev;
-	struct se_dev_entry *se_deve;
 	struct se_node_acl *pr_reg_nacl;
 	struct se_session *se_sess = cmd->se_sess;
-	struct list_head preempt_and_abort_list;
+	LIST_HEAD(preempt_and_abort_list);
 	struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder;
 	struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr;
 	u32 pr_res_mapped_lun = 0;
@@ -3016,7 +3010,6 @@
 		return -EINVAL;
 	}
 
-	se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
 	pr_reg_n = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl,
 				se_sess);
 	if (!pr_reg_n) {
@@ -3037,7 +3030,6 @@
 		cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
 		return -EINVAL;
 	}
-	INIT_LIST_HEAD(&preempt_and_abort_list);
 
 	spin_lock(&dev->dev_reservation_lock);
 	pr_res_holder = dev->dev_pr_res_holder;
@@ -3353,7 +3345,7 @@
 {
 	struct se_session *se_sess = cmd->se_sess;
 	struct se_device *dev = cmd->se_dev;
-	struct se_dev_entry *se_deve, *dest_se_deve = NULL;
+	struct se_dev_entry *dest_se_deve = NULL;
 	struct se_lun *se_lun = cmd->se_lun;
 	struct se_node_acl *pr_res_nacl, *pr_reg_nacl, *dest_node_acl = NULL;
 	struct se_port *se_port;
@@ -3378,7 +3370,6 @@
 	memset(i_buf, 0, PR_REG_ISID_ID_LEN);
 	se_tpg = se_sess->se_tpg;
 	tf_ops = se_tpg->se_tpg_tfo;
-	se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
 	/*
 	 * Follow logic from spc4r17 Section 5.7.8, Table 50 --
 	 *	Register behaviors for a REGISTER AND MOVE service action
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index 8d4def3..94c905f 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -69,7 +69,7 @@
 		return -ENOMEM;
 	}
 	phv->phv_host_id = host_id;
-	phv->phv_mode = PHV_VIRUTAL_HOST_ID;
+	phv->phv_mode = PHV_VIRTUAL_HOST_ID;
 
 	hba->hba_ptr = phv;
 
@@ -114,7 +114,7 @@
 			return 0;
 
 		phv->phv_lld_host = NULL;
-		phv->phv_mode = PHV_VIRUTAL_HOST_ID;
+		phv->phv_mode = PHV_VIRTUAL_HOST_ID;
 
 		pr_debug("CORE_HBA[%d] - Disabled pSCSI HBA Passthrough"
 			" %s\n", hba->hba_id, (sh->hostt->name) ?
@@ -531,7 +531,7 @@
 			return ERR_PTR(-ENODEV);
 		}
 		/*
-		 * For the newer PHV_VIRUTAL_HOST_ID struct scsi_device
+		 * For the newer PHV_VIRTUAL_HOST_ID struct scsi_device
 		 * reference, we enforce that udev_path has been set
 		 */
 		if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) {
@@ -540,7 +540,7 @@
 			return ERR_PTR(-EINVAL);
 		}
 		/*
-		 * If no scsi_host_id= was passed for PHV_VIRUTAL_HOST_ID,
+		 * If no scsi_host_id= was passed for PHV_VIRTUAL_HOST_ID,
 		 * use the original TCM hba ID to reference Linux/SCSI Host No
 		 * and enable for PHV_LLD_SCSI_HOST_NO mode.
 		 */
@@ -569,8 +569,8 @@
 			}
 		}
 	} else {
-		if (phv->phv_mode == PHV_VIRUTAL_HOST_ID) {
-			pr_err("pSCSI: PHV_VIRUTAL_HOST_ID set while"
+		if (phv->phv_mode == PHV_VIRTUAL_HOST_ID) {
+			pr_err("pSCSI: PHV_VIRTUAL_HOST_ID set while"
 				" struct Scsi_Host exists\n");
 			return ERR_PTR(-EEXIST);
 		}
@@ -600,7 +600,7 @@
 		}
 
 		if (!dev) {
-			if (phv->phv_mode == PHV_VIRUTAL_HOST_ID)
+			if (phv->phv_mode == PHV_VIRTUAL_HOST_ID)
 				scsi_host_put(sh);
 			else if (legacy_mode_enable) {
 				pscsi_pmode_enable_hba(hba, 0);
@@ -616,7 +616,7 @@
 	pr_err("pSCSI: Unable to locate %d:%d:%d:%d\n", sh->host_no,
 		pdv->pdv_channel_id,  pdv->pdv_target_id, pdv->pdv_lun_id);
 
-	if (phv->phv_mode == PHV_VIRUTAL_HOST_ID)
+	if (phv->phv_mode == PHV_VIRTUAL_HOST_ID)
 		scsi_host_put(sh);
 	else if (legacy_mode_enable) {
 		pscsi_pmode_enable_hba(hba, 0);
@@ -898,7 +898,7 @@
 	ssize_t bl;
 	int i;
 
-	if (phv->phv_mode == PHV_VIRUTAL_HOST_ID)
+	if (phv->phv_mode == PHV_VIRTUAL_HOST_ID)
 		snprintf(host_id, 16, "%d", pdv->pdv_host_id);
 	else
 		snprintf(host_id, 16, "PHBA Mode");
diff --git a/drivers/target/target_core_pscsi.h b/drivers/target/target_core_pscsi.h
index fdc17b6..43f1c41 100644
--- a/drivers/target/target_core_pscsi.h
+++ b/drivers/target/target_core_pscsi.h
@@ -49,7 +49,7 @@
 } ____cacheline_aligned;
 
 typedef enum phv_modes {
-	PHV_VIRUTAL_HOST_ID,
+	PHV_VIRTUAL_HOST_ID,
 	PHV_LLD_SCSI_HOST_NO
 } phv_modes_t;
 
diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c
index f8c2d2c..3d44beb 100644
--- a/drivers/target/target_core_stat.c
+++ b/drivers/target/target_core_stat.c
@@ -954,7 +954,6 @@
 {
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
 	struct se_port *sep;
-	struct se_portal_group *tpg;
 	ssize_t ret;
 
 	spin_lock(&lun->lun_sep_lock);
@@ -963,7 +962,6 @@
 		spin_unlock(&lun->lun_sep_lock);
 		return -ENODEV;
 	}
-	tpg = sep->sep_tpg;
 
 	ret = snprintf(page, PAGE_SIZE, "%llu\n", sep->sep_stats.cmd_pdus);
 	spin_unlock(&lun->lun_sep_lock);
@@ -976,7 +974,6 @@
 {
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
 	struct se_port *sep;
-	struct se_portal_group *tpg;
 	ssize_t ret;
 
 	spin_lock(&lun->lun_sep_lock);
@@ -985,7 +982,6 @@
 		spin_unlock(&lun->lun_sep_lock);
 		return -ENODEV;
 	}
-	tpg = sep->sep_tpg;
 
 	ret = snprintf(page, PAGE_SIZE, "%u\n",
 			(u32)(sep->sep_stats.rx_data_octets >> 20));
@@ -999,7 +995,6 @@
 {
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
 	struct se_port *sep;
-	struct se_portal_group *tpg;
 	ssize_t ret;
 
 	spin_lock(&lun->lun_sep_lock);
@@ -1008,7 +1003,6 @@
 		spin_unlock(&lun->lun_sep_lock);
 		return -ENODEV;
 	}
-	tpg = sep->sep_tpg;
 
 	ret = snprintf(page, PAGE_SIZE, "%u\n",
 			(u32)(sep->sep_stats.tx_data_octets >> 20));
@@ -1022,7 +1016,6 @@
 {
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
 	struct se_port *sep;
-	struct se_portal_group *tpg;
 	ssize_t ret;
 
 	spin_lock(&lun->lun_sep_lock);
@@ -1031,7 +1024,6 @@
 		spin_unlock(&lun->lun_sep_lock);
 		return -ENODEV;
 	}
-	tpg = sep->sep_tpg;
 
 	/* FIXME: scsiTgtPortHsInCommands */
 	ret = snprintf(page, PAGE_SIZE, "%u\n", 0);
@@ -1253,7 +1245,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
@@ -1275,16 +1267,14 @@
 	struct se_node_acl *nacl = lacl->se_lun_nacl;
 	struct se_dev_entry *deve;
 	struct se_lun *lun;
-	struct se_portal_group *tpg;
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
 	}
-	tpg = nacl->se_tpg;
 	lun = deve->se_lun;
 	/* scsiDeviceIndex */
 	ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_se_dev->dev_index);
@@ -1304,7 +1294,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
@@ -1327,7 +1317,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
@@ -1349,7 +1339,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
@@ -1371,7 +1361,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
@@ -1393,7 +1383,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
@@ -1415,7 +1405,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
@@ -1437,7 +1427,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
@@ -1459,7 +1449,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
@@ -1481,7 +1471,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
@@ -1503,7 +1493,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
@@ -1525,7 +1515,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
@@ -1548,7 +1538,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
@@ -1621,7 +1611,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
@@ -1643,16 +1633,14 @@
 	struct se_node_acl *nacl = lacl->se_lun_nacl;
 	struct se_dev_entry *deve;
 	struct se_lun *lun;
-	struct se_portal_group *tpg;
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
 	}
-	tpg = nacl->se_tpg;
 	lun = deve->se_lun;
 	/* scsiDeviceIndex */
 	ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_se_dev->dev_index);
@@ -1672,7 +1660,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
@@ -1721,7 +1709,7 @@
 	ssize_t ret;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[lacl->mapped_lun];
+	deve = nacl->device_list[lacl->mapped_lun];
 	if (!deve->se_lun || !deve->se_lun_acl) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -ENODEV;
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index dcb0618..f015839 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -40,7 +40,7 @@
 #include "target_core_alua.h"
 #include "target_core_pr.h"
 
-struct se_tmr_req *core_tmr_alloc_req(
+int core_tmr_alloc_req(
 	struct se_cmd *se_cmd,
 	void *fabric_tmr_ptr,
 	u8 function,
@@ -48,17 +48,20 @@
 {
 	struct se_tmr_req *tmr;
 
-	tmr = kmem_cache_zalloc(se_tmr_req_cache, gfp_flags);
+	tmr = kzalloc(sizeof(struct se_tmr_req), gfp_flags);
 	if (!tmr) {
 		pr_err("Unable to allocate struct se_tmr_req\n");
-		return ERR_PTR(-ENOMEM);
+		return -ENOMEM;
 	}
+
+	se_cmd->se_cmd_flags |= SCF_SCSI_TMR_CDB;
+	se_cmd->se_tmr_req = tmr;
 	tmr->task_cmd = se_cmd;
 	tmr->fabric_tmr_ptr = fabric_tmr_ptr;
 	tmr->function = function;
 	INIT_LIST_HEAD(&tmr->tmr_list);
 
-	return tmr;
+	return 0;
 }
 EXPORT_SYMBOL(core_tmr_alloc_req);
 
@@ -69,7 +72,7 @@
 	unsigned long flags;
 
 	if (!dev) {
-		kmem_cache_free(se_tmr_req_cache, tmr);
+		kfree(tmr);
 		return;
 	}
 
@@ -77,7 +80,7 @@
 	list_del(&tmr->tmr_list);
 	spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
 
-	kmem_cache_free(se_tmr_req_cache, tmr);
+	kfree(tmr);
 }
 
 static void core_tmr_handle_tas_abort(
@@ -115,6 +118,70 @@
 	return 1;
 }
 
+void core_tmr_abort_task(
+	struct se_device *dev,
+	struct se_tmr_req *tmr,
+	struct se_session *se_sess)
+{
+	struct se_cmd *se_cmd, *tmp_cmd;
+	unsigned long flags;
+	int ref_tag;
+
+	spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
+	list_for_each_entry_safe(se_cmd, tmp_cmd,
+			&se_sess->sess_cmd_list, se_cmd_list) {
+
+		if (dev != se_cmd->se_dev)
+			continue;
+		ref_tag = se_cmd->se_tfo->get_task_tag(se_cmd);
+		if (tmr->ref_task_tag != ref_tag)
+			continue;
+
+		printk("ABORT_TASK: Found referenced %s task_tag: %u\n",
+			se_cmd->se_tfo->get_fabric_name(), ref_tag);
+
+		spin_lock_irq(&se_cmd->t_state_lock);
+		if (se_cmd->transport_state & CMD_T_COMPLETE) {
+			printk("ABORT_TASK: ref_tag: %u already complete, skipping\n", ref_tag);
+			spin_unlock_irq(&se_cmd->t_state_lock);
+			spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+			goto out;
+		}
+		se_cmd->transport_state |= CMD_T_ABORTED;
+		spin_unlock_irq(&se_cmd->t_state_lock);
+
+		list_del_init(&se_cmd->se_cmd_list);
+		kref_get(&se_cmd->cmd_kref);
+		spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+
+		cancel_work_sync(&se_cmd->work);
+		transport_wait_for_tasks(se_cmd);
+		/*
+		 * Now send SAM_STAT_TASK_ABORTED status for the referenced
+		 * se_cmd descriptor..
+		 */
+		transport_send_task_abort(se_cmd);
+		/*
+		 * Also deal with possible extra acknowledge reference..
+		 */
+		if (se_cmd->se_cmd_flags & SCF_ACK_KREF)
+			target_put_sess_cmd(se_sess, se_cmd);
+
+		target_put_sess_cmd(se_sess, se_cmd);
+
+		printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for"
+				" ref_tag: %d\n", ref_tag);
+		tmr->response = TMR_FUNCTION_COMPLETE;
+		return;
+	}
+	spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+
+out:
+	printk("ABORT_TASK: Sending TMR_TASK_DOES_NOT_EXIST for ref_tag: %d\n",
+			tmr->ref_task_tag);
+	tmr->response = TMR_TASK_DOES_NOT_EXIST;
+}
+
 static void core_tmr_drain_tmr_list(
 	struct se_device *dev,
 	struct se_tmr_req *tmr,
@@ -150,7 +217,7 @@
 			continue;
 
 		spin_lock(&cmd->t_state_lock);
-		if (!atomic_read(&cmd->t_transport_active)) {
+		if (!(cmd->transport_state & CMD_T_ACTIVE)) {
 			spin_unlock(&cmd->t_state_lock);
 			continue;
 		}
@@ -255,15 +322,15 @@
 			cmd->t_task_cdb[0]);
 		pr_debug("LUN_RESET: ITT[0x%08x] - pr_res_key: 0x%016Lx"
 			" t_task_cdbs: %d t_task_cdbs_left: %d"
-			" t_task_cdbs_sent: %d -- t_transport_active: %d"
-			" t_transport_stop: %d t_transport_sent: %d\n",
+			" t_task_cdbs_sent: %d -- CMD_T_ACTIVE: %d"
+			" CMD_T_STOP: %d CMD_T_SENT: %d\n",
 			cmd->se_tfo->get_task_tag(cmd), cmd->pr_res_key,
 			cmd->t_task_list_num,
 			atomic_read(&cmd->t_task_cdbs_left),
 			atomic_read(&cmd->t_task_cdbs_sent),
-			atomic_read(&cmd->t_transport_active),
-			atomic_read(&cmd->t_transport_stop),
-			atomic_read(&cmd->t_transport_sent));
+			(cmd->transport_state & CMD_T_ACTIVE) != 0,
+			(cmd->transport_state & CMD_T_STOP) != 0,
+			(cmd->transport_state & CMD_T_SENT) != 0);
 
 		/*
 		 * If the command may be queued onto a workqueue cancel it now.
@@ -287,19 +354,19 @@
 		}
 		fe_count = atomic_read(&cmd->t_fe_count);
 
-		if (atomic_read(&cmd->t_transport_active)) {
-			pr_debug("LUN_RESET: got t_transport_active = 1 for"
+		if (!(cmd->transport_state & CMD_T_ACTIVE)) {
+			pr_debug("LUN_RESET: got CMD_T_ACTIVE for"
 				" task: %p, t_fe_count: %d dev: %p\n", task,
 				fe_count, dev);
-			atomic_set(&cmd->t_transport_aborted, 1);
+			cmd->transport_state |= CMD_T_ABORTED;
 			spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
 			core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
 			continue;
 		}
-		pr_debug("LUN_RESET: Got t_transport_active = 0 for task: %p,"
+		pr_debug("LUN_RESET: Got !CMD_T_ACTIVE for task: %p,"
 			" t_fe_count: %d dev: %p\n", task, fe_count, dev);
-		atomic_set(&cmd->t_transport_aborted, 1);
+		cmd->transport_state |= CMD_T_ABORTED;
 		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
 		core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
@@ -339,7 +406,7 @@
 		if (prout_cmd == cmd)
 			continue;
 
-		atomic_set(&cmd->t_transport_queue_active, 0);
+		cmd->transport_state &= ~CMD_T_QUEUED;
 		atomic_dec(&qobj->queue_cnt);
 		list_move_tail(&cmd->se_queue_node, &drain_cmd_list);
 	}
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index 06336ec..70c3ffb 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -64,7 +64,7 @@
 
 	spin_lock_irq(&nacl->device_list_lock);
 	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
-		deve = &nacl->device_list[i];
+		deve = nacl->device_list[i];
 
 		if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS))
 			continue;
@@ -163,7 +163,7 @@
 
 	spin_lock(&tpg->tpg_lun_lock);
 	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
-		lun = &tpg->tpg_lun_list[i];
+		lun = tpg->tpg_lun_list[i];
 		if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE)
 			continue;
 
@@ -222,6 +222,34 @@
 	return 0;
 }
 
+void array_free(void *array, int n)
+{
+	void **a = array;
+	int i;
+
+	for (i = 0; i < n; i++)
+		kfree(a[i]);
+	kfree(a);
+}
+
+static void *array_zalloc(int n, size_t size, gfp_t flags)
+{
+	void **a;
+	int i;
+
+	a = kzalloc(n * sizeof(void*), flags);
+	if (!a)
+		return NULL;
+	for (i = 0; i < n; i++) {
+		a[i] = kzalloc(size, flags);
+		if (!a[i]) {
+			array_free(a, n);
+			return NULL;
+		}
+	}
+	return a;
+}
+
 /*      core_create_device_list_for_node():
  *
  *
@@ -231,15 +259,15 @@
 	struct se_dev_entry *deve;
 	int i;
 
-	nacl->device_list = kzalloc(sizeof(struct se_dev_entry) *
-				TRANSPORT_MAX_LUNS_PER_TPG, GFP_KERNEL);
+	nacl->device_list = array_zalloc(TRANSPORT_MAX_LUNS_PER_TPG,
+			sizeof(struct se_dev_entry), GFP_KERNEL);
 	if (!nacl->device_list) {
 		pr_err("Unable to allocate memory for"
 			" struct se_node_acl->device_list\n");
 		return -ENOMEM;
 	}
 	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
-		deve = &nacl->device_list[i];
+		deve = nacl->device_list[i];
 
 		atomic_set(&deve->ua_count, 0);
 		atomic_set(&deve->pr_ref_count, 0);
@@ -274,6 +302,8 @@
 
 	INIT_LIST_HEAD(&acl->acl_list);
 	INIT_LIST_HEAD(&acl->acl_sess_list);
+	kref_init(&acl->acl_kref);
+	init_completion(&acl->acl_free_comp);
 	spin_lock_init(&acl->device_list_lock);
 	spin_lock_init(&acl->nacl_sess_lock);
 	atomic_set(&acl->acl_pr_ref_count, 0);
@@ -329,19 +359,19 @@
 
 void core_tpg_clear_object_luns(struct se_portal_group *tpg)
 {
-	int i, ret;
+	int i;
 	struct se_lun *lun;
 
 	spin_lock(&tpg->tpg_lun_lock);
 	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
-		lun = &tpg->tpg_lun_list[i];
+		lun = tpg->tpg_lun_list[i];
 
 		if ((lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) ||
 		    (lun->lun_se_dev == NULL))
 			continue;
 
 		spin_unlock(&tpg->tpg_lun_lock);
-		ret = core_dev_del_lun(tpg, lun->unpacked_lun);
+		core_dev_del_lun(tpg, lun->unpacked_lun);
 		spin_lock(&tpg->tpg_lun_lock);
 	}
 	spin_unlock(&tpg->tpg_lun_lock);
@@ -402,6 +432,8 @@
 
 	INIT_LIST_HEAD(&acl->acl_list);
 	INIT_LIST_HEAD(&acl->acl_sess_list);
+	kref_init(&acl->acl_kref);
+	init_completion(&acl->acl_free_comp);
 	spin_lock_init(&acl->device_list_lock);
 	spin_lock_init(&acl->nacl_sess_lock);
 	atomic_set(&acl->acl_pr_ref_count, 0);
@@ -448,39 +480,47 @@
 	struct se_node_acl *acl,
 	int force)
 {
+	LIST_HEAD(sess_list);
 	struct se_session *sess, *sess_tmp;
-	int dynamic_acl = 0;
+	unsigned long flags;
+	int rc;
 
 	spin_lock_irq(&tpg->acl_node_lock);
 	if (acl->dynamic_node_acl) {
 		acl->dynamic_node_acl = 0;
-		dynamic_acl = 1;
 	}
 	list_del(&acl->acl_list);
 	tpg->num_node_acls--;
 	spin_unlock_irq(&tpg->acl_node_lock);
 
-	spin_lock_bh(&tpg->session_lock);
-	list_for_each_entry_safe(sess, sess_tmp,
-				&tpg->tpg_sess_list, sess_list) {
-		if (sess->se_node_acl != acl)
-			continue;
-		/*
-		 * Determine if the session needs to be closed by our context.
-		 */
-		if (!tpg->se_tpg_tfo->shutdown_session(sess))
+	spin_lock_irqsave(&acl->nacl_sess_lock, flags);
+	acl->acl_stop = 1;
+
+	list_for_each_entry_safe(sess, sess_tmp, &acl->acl_sess_list,
+				sess_acl_list) {
+		if (sess->sess_tearing_down != 0)
 			continue;
 
-		spin_unlock_bh(&tpg->session_lock);
-		/*
-		 * If the $FABRIC_MOD session for the Initiator Node ACL exists,
-		 * forcefully shutdown the $FABRIC_MOD session/nexus.
-		 */
-		tpg->se_tpg_tfo->close_session(sess);
-
-		spin_lock_bh(&tpg->session_lock);
+		target_get_session(sess);
+		list_move(&sess->sess_acl_list, &sess_list);
 	}
-	spin_unlock_bh(&tpg->session_lock);
+	spin_unlock_irqrestore(&acl->nacl_sess_lock, flags);
+
+	list_for_each_entry_safe(sess, sess_tmp, &sess_list, sess_acl_list) {
+		list_del(&sess->sess_acl_list);
+
+		rc = tpg->se_tpg_tfo->shutdown_session(sess);
+		target_put_session(sess);
+		if (!rc)
+			continue;
+		target_put_session(sess);
+	}
+	target_put_nacl(acl);
+	/*
+	 * Wait for last target_put_nacl() to complete in target_complete_nacl()
+	 * for active fabric session transport_deregister_session() callbacks.
+	 */
+	wait_for_completion(&acl->acl_free_comp);
 
 	core_tpg_wait_for_nacl_pr_ref(acl);
 	core_clear_initiator_node_from_tpg(acl, tpg);
@@ -507,6 +547,7 @@
 {
 	struct se_session *sess, *init_sess = NULL;
 	struct se_node_acl *acl;
+	unsigned long flags;
 	int dynamic_acl = 0;
 
 	spin_lock_irq(&tpg->acl_node_lock);
@@ -525,7 +566,7 @@
 	}
 	spin_unlock_irq(&tpg->acl_node_lock);
 
-	spin_lock_bh(&tpg->session_lock);
+	spin_lock_irqsave(&tpg->session_lock, flags);
 	list_for_each_entry(sess, &tpg->tpg_sess_list, sess_list) {
 		if (sess->se_node_acl != acl)
 			continue;
@@ -537,7 +578,7 @@
 				" depth and force session reinstatement"
 				" use the \"force=1\" parameter.\n",
 				tpg->se_tpg_tfo->get_fabric_name(), initiatorname);
-			spin_unlock_bh(&tpg->session_lock);
+			spin_unlock_irqrestore(&tpg->session_lock, flags);
 
 			spin_lock_irq(&tpg->acl_node_lock);
 			if (dynamic_acl)
@@ -567,7 +608,7 @@
 	acl->queue_depth = queue_depth;
 
 	if (core_set_queue_depth_for_node(tpg, acl) < 0) {
-		spin_unlock_bh(&tpg->session_lock);
+		spin_unlock_irqrestore(&tpg->session_lock, flags);
 		/*
 		 * Force session reinstatement if
 		 * core_set_queue_depth_for_node() failed, because we assume
@@ -583,7 +624,7 @@
 		spin_unlock_irq(&tpg->acl_node_lock);
 		return -EINVAL;
 	}
-	spin_unlock_bh(&tpg->session_lock);
+	spin_unlock_irqrestore(&tpg->session_lock, flags);
 	/*
 	 * If the $FABRIC_MOD session for the Initiator Node ACL exists,
 	 * forcefully shutdown the $FABRIC_MOD session/nexus.
@@ -647,8 +688,8 @@
 	struct se_lun *lun;
 	u32 i;
 
-	se_tpg->tpg_lun_list = kzalloc((sizeof(struct se_lun) *
-				TRANSPORT_MAX_LUNS_PER_TPG), GFP_KERNEL);
+	se_tpg->tpg_lun_list = array_zalloc(TRANSPORT_MAX_LUNS_PER_TPG,
+			sizeof(struct se_lun), GFP_KERNEL);
 	if (!se_tpg->tpg_lun_list) {
 		pr_err("Unable to allocate struct se_portal_group->"
 				"tpg_lun_list\n");
@@ -656,7 +697,7 @@
 	}
 
 	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
-		lun = &se_tpg->tpg_lun_list[i];
+		lun = se_tpg->tpg_lun_list[i];
 		lun->unpacked_lun = i;
 		lun->lun_status = TRANSPORT_LUN_STATUS_FREE;
 		atomic_set(&lun->lun_acl_count, 0);
@@ -742,7 +783,7 @@
 		core_tpg_release_virtual_lun0(se_tpg);
 
 	se_tpg->se_tpg_fabric_ptr = NULL;
-	kfree(se_tpg->tpg_lun_list);
+	array_free(se_tpg->tpg_lun_list, TRANSPORT_MAX_LUNS_PER_TPG);
 	return 0;
 }
 EXPORT_SYMBOL(core_tpg_deregister);
@@ -763,7 +804,7 @@
 	}
 
 	spin_lock(&tpg->tpg_lun_lock);
-	lun = &tpg->tpg_lun_list[unpacked_lun];
+	lun = tpg->tpg_lun_list[unpacked_lun];
 	if (lun->lun_status == TRANSPORT_LUN_STATUS_ACTIVE) {
 		pr_err("TPG Logical Unit Number: %u is already active"
 			" on %s Target Portal Group: %u, ignoring request.\n",
@@ -821,7 +862,7 @@
 	}
 
 	spin_lock(&tpg->tpg_lun_lock);
-	lun = &tpg->tpg_lun_list[unpacked_lun];
+	lun = tpg->tpg_lun_list[unpacked_lun];
 	if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) {
 		pr_err("%s Logical Unit Number: %u is not active on"
 			" Target Portal Group: %u, ignoring request.\n",
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 929cc93..443704f 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -37,6 +37,7 @@
 #include <linux/in.h>
 #include <linux/cdrom.h>
 #include <linux/module.h>
+#include <linux/ratelimit.h>
 #include <asm/unaligned.h>
 #include <net/sock.h>
 #include <net/tcp.h>
@@ -58,7 +59,6 @@
 
 static struct workqueue_struct *target_completion_wq;
 static struct kmem_cache *se_sess_cache;
-struct kmem_cache *se_tmr_req_cache;
 struct kmem_cache *se_ua_cache;
 struct kmem_cache *t10_pr_reg_cache;
 struct kmem_cache *t10_alua_lu_gp_cache;
@@ -77,26 +77,17 @@
 static void transport_put_cmd(struct se_cmd *cmd);
 static void transport_remove_cmd_from_queue(struct se_cmd *cmd);
 static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq);
-static void transport_generic_request_failure(struct se_cmd *);
 static void target_complete_ok_work(struct work_struct *work);
 
 int init_se_kmem_caches(void)
 {
-	se_tmr_req_cache = kmem_cache_create("se_tmr_cache",
-			sizeof(struct se_tmr_req), __alignof__(struct se_tmr_req),
-			0, NULL);
-	if (!se_tmr_req_cache) {
-		pr_err("kmem_cache_create() for struct se_tmr_req"
-				" failed\n");
-		goto out;
-	}
 	se_sess_cache = kmem_cache_create("se_sess_cache",
 			sizeof(struct se_session), __alignof__(struct se_session),
 			0, NULL);
 	if (!se_sess_cache) {
 		pr_err("kmem_cache_create() for struct se_session"
 				" failed\n");
-		goto out_free_tmr_req_cache;
+		goto out;
 	}
 	se_ua_cache = kmem_cache_create("se_ua_cache",
 			sizeof(struct se_ua), __alignof__(struct se_ua),
@@ -169,8 +160,6 @@
 	kmem_cache_destroy(se_ua_cache);
 out_free_sess_cache:
 	kmem_cache_destroy(se_sess_cache);
-out_free_tmr_req_cache:
-	kmem_cache_destroy(se_tmr_req_cache);
 out:
 	return -ENOMEM;
 }
@@ -178,7 +167,6 @@
 void release_se_kmem_caches(void)
 {
 	destroy_workqueue(target_completion_wq);
-	kmem_cache_destroy(se_tmr_req_cache);
 	kmem_cache_destroy(se_sess_cache);
 	kmem_cache_destroy(se_ua_cache);
 	kmem_cache_destroy(t10_pr_reg_cache);
@@ -258,13 +246,14 @@
 	INIT_LIST_HEAD(&se_sess->sess_cmd_list);
 	INIT_LIST_HEAD(&se_sess->sess_wait_list);
 	spin_lock_init(&se_sess->sess_cmd_lock);
+	kref_init(&se_sess->sess_kref);
 
 	return se_sess;
 }
 EXPORT_SYMBOL(transport_init_session);
 
 /*
- * Called with spin_lock_bh(&struct se_portal_group->session_lock called.
+ * Called with spin_lock_irqsave(&struct se_portal_group->session_lock called.
  */
 void __transport_register_session(
 	struct se_portal_group *se_tpg,
@@ -293,6 +282,8 @@
 					&buf[0], PR_REG_ISID_LEN);
 			se_sess->sess_bin_isid = get_unaligned_be64(&buf[0]);
 		}
+		kref_get(&se_nacl->acl_kref);
+
 		spin_lock_irq(&se_nacl->nacl_sess_lock);
 		/*
 		 * The se_nacl->nacl_sess pointer will be set to the
@@ -317,12 +308,48 @@
 	struct se_session *se_sess,
 	void *fabric_sess_ptr)
 {
-	spin_lock_bh(&se_tpg->session_lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&se_tpg->session_lock, flags);
 	__transport_register_session(se_tpg, se_nacl, se_sess, fabric_sess_ptr);
-	spin_unlock_bh(&se_tpg->session_lock);
+	spin_unlock_irqrestore(&se_tpg->session_lock, flags);
 }
 EXPORT_SYMBOL(transport_register_session);
 
+static void target_release_session(struct kref *kref)
+{
+	struct se_session *se_sess = container_of(kref,
+			struct se_session, sess_kref);
+	struct se_portal_group *se_tpg = se_sess->se_tpg;
+
+	se_tpg->se_tpg_tfo->close_session(se_sess);
+}
+
+void target_get_session(struct se_session *se_sess)
+{
+	kref_get(&se_sess->sess_kref);
+}
+EXPORT_SYMBOL(target_get_session);
+
+int target_put_session(struct se_session *se_sess)
+{
+	return kref_put(&se_sess->sess_kref, target_release_session);
+}
+EXPORT_SYMBOL(target_put_session);
+
+static void target_complete_nacl(struct kref *kref)
+{
+	struct se_node_acl *nacl = container_of(kref,
+				struct se_node_acl, acl_kref);
+
+	complete(&nacl->acl_free_comp);
+}
+
+void target_put_nacl(struct se_node_acl *nacl)
+{
+	kref_put(&nacl->acl_kref, target_complete_nacl);
+}
+
 void transport_deregister_session_configfs(struct se_session *se_sess)
 {
 	struct se_node_acl *se_nacl;
@@ -333,7 +360,8 @@
 	se_nacl = se_sess->se_node_acl;
 	if (se_nacl) {
 		spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags);
-		list_del(&se_sess->sess_acl_list);
+		if (se_nacl->acl_stop == 0)
+			list_del(&se_sess->sess_acl_list);
 		/*
 		 * If the session list is empty, then clear the pointer.
 		 * Otherwise, set the struct se_session pointer from the tail
@@ -360,13 +388,16 @@
 void transport_deregister_session(struct se_session *se_sess)
 {
 	struct se_portal_group *se_tpg = se_sess->se_tpg;
+	struct target_core_fabric_ops *se_tfo;
 	struct se_node_acl *se_nacl;
 	unsigned long flags;
+	bool comp_nacl = true;
 
 	if (!se_tpg) {
 		transport_free_session(se_sess);
 		return;
 	}
+	se_tfo = se_tpg->se_tpg_tfo;
 
 	spin_lock_irqsave(&se_tpg->session_lock, flags);
 	list_del(&se_sess->sess_list);
@@ -379,29 +410,34 @@
 	 * struct se_node_acl if it had been previously dynamically generated.
 	 */
 	se_nacl = se_sess->se_node_acl;
-	if (se_nacl) {
-		spin_lock_irqsave(&se_tpg->acl_node_lock, flags);
-		if (se_nacl->dynamic_node_acl) {
-			if (!se_tpg->se_tpg_tfo->tpg_check_demo_mode_cache(
-					se_tpg)) {
-				list_del(&se_nacl->acl_list);
-				se_tpg->num_node_acls--;
-				spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags);
 
-				core_tpg_wait_for_nacl_pr_ref(se_nacl);
-				core_free_device_list_for_node(se_nacl, se_tpg);
-				se_tpg->se_tpg_tfo->tpg_release_fabric_acl(se_tpg,
-						se_nacl);
-				spin_lock_irqsave(&se_tpg->acl_node_lock, flags);
-			}
+	spin_lock_irqsave(&se_tpg->acl_node_lock, flags);
+	if (se_nacl && se_nacl->dynamic_node_acl) {
+		if (!se_tfo->tpg_check_demo_mode_cache(se_tpg)) {
+			list_del(&se_nacl->acl_list);
+			se_tpg->num_node_acls--;
+			spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags);
+			core_tpg_wait_for_nacl_pr_ref(se_nacl);
+			core_free_device_list_for_node(se_nacl, se_tpg);
+			se_tfo->tpg_release_fabric_acl(se_tpg, se_nacl);
+
+			comp_nacl = false;
+			spin_lock_irqsave(&se_tpg->acl_node_lock, flags);
 		}
-		spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags);
 	}
-
-	transport_free_session(se_sess);
+	spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags);
 
 	pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n",
 		se_tpg->se_tpg_tfo->get_fabric_name());
+	/*
+	 * If last kref is dropping now for an explict NodeACL, awake sleeping
+	 * ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group
+	 * removal context.
+	 */
+	if (se_nacl && comp_nacl == true)
+		target_put_nacl(se_nacl);
+
+	transport_free_session(se_sess);
 }
 EXPORT_SYMBOL(transport_deregister_session);
 
@@ -437,7 +473,7 @@
 
 /*	transport_cmd_check_stop():
  *
- *	'transport_off = 1' determines if t_transport_active should be cleared.
+ *	'transport_off = 1' determines if CMD_T_ACTIVE should be cleared.
  *	'transport_off = 2' determines if task_dev_state should be removed.
  *
  *	A non-zero u8 t_state sets cmd->t_state.
@@ -455,12 +491,11 @@
 	 * Determine if IOCTL context caller in requesting the stopping of this
 	 * command for LUN shutdown purposes.
 	 */
-	if (atomic_read(&cmd->transport_lun_stop)) {
-		pr_debug("%s:%d atomic_read(&cmd->transport_lun_stop)"
-			" == TRUE for ITT: 0x%08x\n", __func__, __LINE__,
-			cmd->se_tfo->get_task_tag(cmd));
+	if (cmd->transport_state & CMD_T_LUN_STOP) {
+		pr_debug("%s:%d CMD_T_LUN_STOP for ITT: 0x%08x\n",
+			__func__, __LINE__, cmd->se_tfo->get_task_tag(cmd));
 
-		atomic_set(&cmd->t_transport_active, 0);
+		cmd->transport_state &= ~CMD_T_ACTIVE;
 		if (transport_off == 2)
 			transport_all_task_dev_remove_state(cmd);
 		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
@@ -472,9 +507,9 @@
 	 * Determine if frontend context caller is requesting the stopping of
 	 * this command for frontend exceptions.
 	 */
-	if (atomic_read(&cmd->t_transport_stop)) {
-		pr_debug("%s:%d atomic_read(&cmd->t_transport_stop) =="
-			" TRUE for ITT: 0x%08x\n", __func__, __LINE__,
+	if (cmd->transport_state & CMD_T_STOP) {
+		pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08x\n",
+			__func__, __LINE__,
 			cmd->se_tfo->get_task_tag(cmd));
 
 		if (transport_off == 2)
@@ -492,7 +527,7 @@
 		return 1;
 	}
 	if (transport_off) {
-		atomic_set(&cmd->t_transport_active, 0);
+		cmd->transport_state &= ~CMD_T_ACTIVE;
 		if (transport_off == 2) {
 			transport_all_task_dev_remove_state(cmd);
 			/*
@@ -540,31 +575,21 @@
 		return;
 
 	spin_lock_irqsave(&cmd->t_state_lock, flags);
-	if (!atomic_read(&cmd->transport_dev_active)) {
-		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-		goto check_lun;
+	if (cmd->transport_state & CMD_T_DEV_ACTIVE) {
+		cmd->transport_state &= ~CMD_T_DEV_ACTIVE;
+		transport_all_task_dev_remove_state(cmd);
 	}
-	atomic_set(&cmd->transport_dev_active, 0);
-	transport_all_task_dev_remove_state(cmd);
 	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
-
-check_lun:
 	spin_lock_irqsave(&lun->lun_cmd_lock, flags);
-	if (atomic_read(&cmd->transport_lun_active)) {
-		list_del(&cmd->se_lun_node);
-		atomic_set(&cmd->transport_lun_active, 0);
-#if 0
-		pr_debug("Removed ITT: 0x%08x from LUN LIST[%d]\n"
-			cmd->se_tfo->get_task_tag(cmd), lun->unpacked_lun);
-#endif
-	}
+	if (!list_empty(&cmd->se_lun_node))
+		list_del_init(&cmd->se_lun_node);
 	spin_unlock_irqrestore(&lun->lun_cmd_lock, flags);
 }
 
 void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
 {
-	if (!cmd->se_tmr_req)
+	if (!(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
 		transport_lun_remove_cmd(cmd);
 
 	if (transport_cmd_check_stop_to_fabric(cmd))
@@ -585,7 +610,7 @@
 	if (t_state) {
 		spin_lock_irqsave(&cmd->t_state_lock, flags);
 		cmd->t_state = t_state;
-		atomic_set(&cmd->t_transport_active, 1);
+		cmd->transport_state |= CMD_T_ACTIVE;
 		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 	}
 
@@ -601,7 +626,7 @@
 		list_add(&cmd->se_queue_node, &qobj->qobj_list);
 	else
 		list_add_tail(&cmd->se_queue_node, &qobj->qobj_list);
-	atomic_set(&cmd->t_transport_queue_active, 1);
+	cmd->transport_state |= CMD_T_QUEUED;
 	spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
 
 	wake_up_interruptible(&qobj->thread_wq);
@@ -620,8 +645,7 @@
 	}
 	cmd = list_first_entry(&qobj->qobj_list, struct se_cmd, se_queue_node);
 
-	atomic_set(&cmd->t_transport_queue_active, 0);
-
+	cmd->transport_state &= ~CMD_T_QUEUED;
 	list_del_init(&cmd->se_queue_node);
 	atomic_dec(&qobj->queue_cnt);
 	spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
@@ -635,20 +659,14 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
-	if (!atomic_read(&cmd->t_transport_queue_active)) {
+	if (!(cmd->transport_state & CMD_T_QUEUED)) {
 		spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
 		return;
 	}
-	atomic_set(&cmd->t_transport_queue_active, 0);
+	cmd->transport_state &= ~CMD_T_QUEUED;
 	atomic_dec(&qobj->queue_cnt);
 	list_del_init(&cmd->se_queue_node);
 	spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
-
-	if (atomic_read(&cmd->t_transport_queue_active)) {
-		pr_err("ITT: 0x%08x t_transport_queue_active: %d\n",
-			cmd->se_tfo->get_task_tag(cmd),
-			atomic_read(&cmd->t_transport_queue_active));
-	}
 }
 
 /*
@@ -719,7 +737,7 @@
 	}
 
 	if (!success)
-		cmd->t_tasks_failed = 1;
+		cmd->transport_state |= CMD_T_FAILED;
 
 	/*
 	 * Decrement the outstanding t_task_cdbs_left count.  The last
@@ -730,17 +748,24 @@
 		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 		return;
 	}
-
-	if (cmd->t_tasks_failed) {
+	/*
+	 * Check for case where an explict ABORT_TASK has been received
+	 * and transport_wait_for_tasks() will be waiting for completion..
+	 */
+	if (cmd->transport_state & CMD_T_ABORTED &&
+	    cmd->transport_state & CMD_T_STOP) {
+		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+		complete(&cmd->t_transport_stop_comp);
+		return;
+	} else if (cmd->transport_state & CMD_T_FAILED) {
 		cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 		INIT_WORK(&cmd->work, target_complete_failure_work);
 	} else {
-		atomic_set(&cmd->t_transport_complete, 1);
 		INIT_WORK(&cmd->work, target_complete_ok_work);
 	}
 
 	cmd->t_state = TRANSPORT_COMPLETE;
-	atomic_set(&cmd->t_transport_active, 1);
+	cmd->transport_state |= (CMD_T_COMPLETE | CMD_T_ACTIVE);
 	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
 	queue_work(target_completion_wq, &cmd->work);
@@ -1488,7 +1513,7 @@
 	init_completion(&cmd->t_transport_stop_comp);
 	init_completion(&cmd->cmd_wait_comp);
 	spin_lock_init(&cmd->t_state_lock);
-	atomic_set(&cmd->transport_dev_active, 1);
+	cmd->transport_state = CMD_T_DEV_ACTIVE;
 
 	cmd->se_tfo = tfo;
 	cmd->se_sess = se_sess;
@@ -1618,7 +1643,7 @@
 		return -EINVAL;
 	}
 	/*
-	 * Set TRANSPORT_NEW_CMD state and cmd->t_transport_active=1 following
+	 * Set TRANSPORT_NEW_CMD state and CMD_T_ACTIVE following
 	 * transport_generic_handle_cdb*() -> transport_add_cmd_to_queue()
 	 * in existing usage to ensure that outstanding descriptors are handled
 	 * correctly during shutdown via transport_wait_for_tasks()
@@ -1627,7 +1652,8 @@
 	 * this to be called for initial descriptor submission.
 	 */
 	cmd->t_state = TRANSPORT_NEW_CMD;
-	atomic_set(&cmd->t_transport_active, 1);
+	cmd->transport_state |= CMD_T_ACTIVE;
+
 	/*
 	 * transport_generic_new_cmd() is already handling QUEUE_FULL,
 	 * so follow TRANSPORT_NEW_CMD processing thread context usage
@@ -1716,6 +1742,74 @@
 }
 EXPORT_SYMBOL(target_submit_cmd);
 
+static void target_complete_tmr_failure(struct work_struct *work)
+{
+	struct se_cmd *se_cmd = container_of(work, struct se_cmd, work);
+
+	se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST;
+	se_cmd->se_tfo->queue_tm_rsp(se_cmd);
+	transport_generic_free_cmd(se_cmd, 0);
+}
+
+/**
+ * target_submit_tmr - lookup unpacked lun and submit uninitialized se_cmd
+ *                     for TMR CDBs
+ *
+ * @se_cmd: command descriptor to submit
+ * @se_sess: associated se_sess for endpoint
+ * @sense: pointer to SCSI sense buffer
+ * @unpacked_lun: unpacked LUN to reference for struct se_lun
+ * @fabric_context: fabric context for TMR req
+ * @tm_type: Type of TM request
+ * @gfp: gfp type for caller
+ * @tag: referenced task tag for TMR_ABORT_TASK
+ * @flags: submit cmd flags
+ *
+ * Callable from all contexts.
+ **/
+
+int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
+		unsigned char *sense, u32 unpacked_lun,
+		void *fabric_tmr_ptr, unsigned char tm_type,
+		gfp_t gfp, unsigned int tag, int flags)
+{
+	struct se_portal_group *se_tpg;
+	int ret;
+
+	se_tpg = se_sess->se_tpg;
+	BUG_ON(!se_tpg);
+
+	transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess,
+			      0, DMA_NONE, MSG_SIMPLE_TAG, sense);
+	/*
+	 * FIXME: Currently expect caller to handle se_cmd->se_tmr_req
+	 * allocation failure.
+	 */
+	ret = core_tmr_alloc_req(se_cmd, fabric_tmr_ptr, tm_type, gfp);
+	if (ret < 0)
+		return -ENOMEM;
+
+	if (tm_type == TMR_ABORT_TASK)
+		se_cmd->se_tmr_req->ref_task_tag = tag;
+
+	/* See target_submit_cmd for commentary */
+	target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF));
+
+	ret = transport_lookup_tmr_lun(se_cmd, unpacked_lun);
+	if (ret) {
+		/*
+		 * For callback during failure handling, push this work off
+		 * to process context with TMR_LUN_DOES_NOT_EXIST status.
+		 */
+		INIT_WORK(&se_cmd->work, target_complete_tmr_failure);
+		schedule_work(&se_cmd->work);
+		return 0;
+	}
+	transport_generic_handle_tmr(se_cmd);
+	return 0;
+}
+EXPORT_SYMBOL(target_submit_tmr);
+
 /*
  * Used by fabric module frontends defining a TFO->new_cmd_map() caller
  * to  queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD_MAP in order to
@@ -1847,7 +1941,7 @@
 /*
  * Handle SAM-esque emulation for generic transport request failures.
  */
-static void transport_generic_request_failure(struct se_cmd *cmd)
+void transport_generic_request_failure(struct se_cmd *cmd)
 {
 	int ret = 0;
 
@@ -1859,14 +1953,14 @@
 		cmd->t_state, cmd->scsi_sense_reason);
 	pr_debug("-----[ t_tasks: %d t_task_cdbs_left: %d"
 		" t_task_cdbs_sent: %d t_task_cdbs_ex_left: %d --"
-		" t_transport_active: %d t_transport_stop: %d"
-		" t_transport_sent: %d\n", cmd->t_task_list_num,
+		" CMD_T_ACTIVE: %d CMD_T_STOP: %d CMD_T_SENT: %d\n",
+		cmd->t_task_list_num,
 		atomic_read(&cmd->t_task_cdbs_left),
 		atomic_read(&cmd->t_task_cdbs_sent),
 		atomic_read(&cmd->t_task_cdbs_ex_left),
-		atomic_read(&cmd->t_transport_active),
-		atomic_read(&cmd->t_transport_stop),
-		atomic_read(&cmd->t_transport_sent));
+		(cmd->transport_state & CMD_T_ACTIVE) != 0,
+		(cmd->transport_state & CMD_T_STOP) != 0,
+		(cmd->transport_state & CMD_T_SENT) != 0);
 
 	/*
 	 * For SAM Task Attribute emulation for failed struct se_cmd
@@ -1939,6 +2033,7 @@
 	cmd->t_state = TRANSPORT_COMPLETE_QF_OK;
 	transport_handle_queue_full(cmd, cmd->se_dev);
 }
+EXPORT_SYMBOL(transport_generic_request_failure);
 
 static inline u32 transport_lba_21(unsigned char *cdb)
 {
@@ -2125,7 +2220,7 @@
 
 	if (atomic_read(&cmd->t_task_cdbs_sent) ==
 	    cmd->t_task_list_num)
-		atomic_set(&cmd->t_transport_sent, 1);
+		cmd->transport_state |= CMD_T_SENT;
 
 	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
@@ -2136,8 +2231,9 @@
 	if (error != 0) {
 		spin_lock_irqsave(&cmd->t_state_lock, flags);
 		task->task_flags &= ~TF_ACTIVE;
+		cmd->transport_state &= ~CMD_T_SENT;
 		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-		atomic_set(&cmd->t_transport_sent, 0);
+
 		transport_stop_tasks_for_cmd(cmd);
 		transport_generic_request_failure(cmd);
 	}
@@ -2847,7 +2943,7 @@
 
 			pr_err("Unsupported SA: 0x%02x\n",
 				cmd->t_task_cdb[1] & 0x1f);
-			goto out_unsupported_cdb;
+			goto out_invalid_cdb_field;
 		}
 		/*FALLTHROUGH*/
 	case ACCESS_CONTROL_IN:
@@ -2929,7 +3025,7 @@
 		cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
 		break;
 	case SYNCHRONIZE_CACHE:
-	case 0x91: /* SYNCHRONIZE_CACHE_16: */
+	case SYNCHRONIZE_CACHE_16:
 		/*
 		 * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE
 		 */
@@ -3081,6 +3177,13 @@
 		cmd->data_length = size;
 	}
 
+	if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB &&
+	    sectors > dev->se_sub_dev->se_dev_attrib.fabric_max_sectors) {
+		printk_ratelimited(KERN_ERR "SCSI OP %02xh with too big sectors %u\n",
+				   cdb[0], sectors);
+		goto out_invalid_cdb_field;
+	}
+
 	/* reject any command that we don't have a handler for */
 	if (!(passthrough || cmd->execute_task ||
 	     (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)))
@@ -3384,7 +3487,7 @@
 {
 	BUG_ON(!cmd->se_tfo);
 
-	if (cmd->se_tmr_req)
+	if (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
 		core_tmr_release_req(cmd->se_tmr_req);
 	if (cmd->t_task_cdb != cmd->__t_task_cdb)
 		kfree(cmd->t_task_cdb);
@@ -3421,8 +3524,8 @@
 			goto out_busy;
 	}
 
-	if (atomic_read(&cmd->transport_dev_active)) {
-		atomic_set(&cmd->transport_dev_active, 0);
+	if (cmd->transport_state & CMD_T_DEV_ACTIVE) {
+		cmd->transport_state &= ~CMD_T_DEV_ACTIVE;
 		transport_all_task_dev_remove_state(cmd);
 		free_tasks = 1;
 	}
@@ -3527,10 +3630,12 @@
 
 void transport_kunmap_data_sg(struct se_cmd *cmd)
 {
-	if (!cmd->t_data_nents)
+	if (!cmd->t_data_nents) {
 		return;
-	else if (cmd->t_data_nents == 1)
+	} else if (cmd->t_data_nents == 1) {
 		kunmap(sg_page(cmd->t_data_sg));
+		return;
+	}
 
 	vunmap(cmd->t_data_vmap);
 	cmd->t_data_vmap = NULL;
@@ -3860,8 +3965,10 @@
 	if (task_cdbs < 0)
 		goto out_fail;
 	else if (!task_cdbs && (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)) {
+		spin_lock_irq(&cmd->t_state_lock);
 		cmd->t_state = TRANSPORT_COMPLETE;
-		atomic_set(&cmd->t_transport_active, 1);
+		cmd->transport_state |= CMD_T_ACTIVE;
+		spin_unlock_irq(&cmd->t_state_lock);
 
 		if (cmd->t_task_cdb[0] == REQUEST_SENSE) {
 			u8 ua_asc = 0, ua_ascq = 0;
@@ -3942,9 +4049,9 @@
 
 	/*
 	 * Clear the se_cmd for WRITE_PENDING status in order to set
-	 * cmd->t_transport_active=0 so that transport_generic_handle_data
-	 * can be called from HW target mode interrupt code.  This is safe
-	 * to be called with transport_off=1 before the cmd->se_tfo->write_pending
+	 * CMD_T_ACTIVE so that transport_generic_handle_data can be called
+	 * from HW target mode interrupt code.  This is safe to be called
+	 * with transport_off=1 before the cmd->se_tfo->write_pending
 	 * because the se_cmd->se_lun pointer is not being cleared.
 	 */
 	transport_cmd_check_stop(cmd, 1, 0);
@@ -3971,7 +4078,7 @@
 void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
 {
 	if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) {
-		if (wait_for_tasks && cmd->se_tmr_req)
+		if (wait_for_tasks && (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
 			 transport_wait_for_tasks(cmd);
 
 		transport_release_cmd(cmd);
@@ -4007,8 +4114,10 @@
 	 * fabric acknowledgement that requires two target_put_sess_cmd()
 	 * invocations before se_cmd descriptor release.
 	 */
-	if (ack_kref == true)
+	if (ack_kref == true) {
 		kref_get(&se_cmd->cmd_kref);
+		se_cmd->se_cmd_flags |= SCF_ACK_KREF;
+	}
 
 	spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
 	list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
@@ -4026,7 +4135,7 @@
 	spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
 	if (list_empty(&se_cmd->se_cmd_list)) {
 		spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
-		WARN_ON(1);
+		se_cmd->se_tfo->release_cmd(se_cmd);
 		return;
 	}
 	if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) {
@@ -4130,15 +4239,16 @@
 	 * be stopped, we can safely ignore this struct se_cmd.
 	 */
 	spin_lock_irqsave(&cmd->t_state_lock, flags);
-	if (atomic_read(&cmd->t_transport_stop)) {
-		atomic_set(&cmd->transport_lun_stop, 0);
-		pr_debug("ConfigFS ITT[0x%08x] - t_transport_stop =="
-			" TRUE, skipping\n", cmd->se_tfo->get_task_tag(cmd));
+	if (cmd->transport_state & CMD_T_STOP) {
+		cmd->transport_state &= ~CMD_T_LUN_STOP;
+
+		pr_debug("ConfigFS ITT[0x%08x] - CMD_T_STOP, skipping\n",
+			 cmd->se_tfo->get_task_tag(cmd));
 		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 		transport_cmd_check_stop(cmd, 1, 0);
 		return -EPERM;
 	}
-	atomic_set(&cmd->transport_lun_fe_stop, 1);
+	cmd->transport_state |= CMD_T_LUN_FE_STOP;
 	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
 	wake_up_interruptible(&cmd->se_dev->dev_queue_obj.thread_wq);
@@ -4171,9 +4281,8 @@
 	while (!list_empty(&lun->lun_cmd_list)) {
 		cmd = list_first_entry(&lun->lun_cmd_list,
 		       struct se_cmd, se_lun_node);
-		list_del(&cmd->se_lun_node);
+		list_del_init(&cmd->se_lun_node);
 
-		atomic_set(&cmd->transport_lun_active, 0);
 		/*
 		 * This will notify iscsi_target_transport.c:
 		 * transport_cmd_check_stop() that a LUN shutdown is in
@@ -4184,7 +4293,7 @@
 			"_lun_stop for  ITT: 0x%08x\n",
 			cmd->se_lun->unpacked_lun,
 			cmd->se_tfo->get_task_tag(cmd));
-		atomic_set(&cmd->transport_lun_stop, 1);
+		cmd->transport_state |= CMD_T_LUN_STOP;
 		spin_unlock(&cmd->t_state_lock);
 
 		spin_unlock_irqrestore(&lun->lun_cmd_lock, lun_flags);
@@ -4214,11 +4323,11 @@
 			cmd->se_tfo->get_task_tag(cmd));
 
 		spin_lock_irqsave(&cmd->t_state_lock, cmd_flags);
-		if (!atomic_read(&cmd->transport_dev_active)) {
+		if (!(cmd->transport_state & CMD_T_DEV_ACTIVE)) {
 			spin_unlock_irqrestore(&cmd->t_state_lock, cmd_flags);
 			goto check_cond;
 		}
-		atomic_set(&cmd->transport_dev_active, 0);
+		cmd->transport_state &= ~CMD_T_DEV_ACTIVE;
 		transport_all_task_dev_remove_state(cmd);
 		spin_unlock_irqrestore(&cmd->t_state_lock, cmd_flags);
 
@@ -4238,7 +4347,7 @@
 		 * finished accessing it.
 		 */
 		spin_lock_irqsave(&cmd->t_state_lock, cmd_flags);
-		if (atomic_read(&cmd->transport_lun_fe_stop)) {
+		if (cmd->transport_state & CMD_T_LUN_FE_STOP) {
 			pr_debug("SE_LUN[%d] - Detected FE stop for"
 				" struct se_cmd: %p ITT: 0x%08x\n",
 				lun->unpacked_lun,
@@ -4297,7 +4406,8 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&cmd->t_state_lock, flags);
-	if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && !(cmd->se_tmr_req)) {
+	if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) &&
+	    !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) {
 		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 		return false;
 	}
@@ -4305,7 +4415,8 @@
 	 * Only perform a possible wait_for_tasks if SCF_SUPPORTED_SAM_OPCODE
 	 * has been set in transport_set_supported_SAM_opcode().
 	 */
-	if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) && !cmd->se_tmr_req) {
+	if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) &&
+	    !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) {
 		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 		return false;
 	}
@@ -4316,8 +4427,7 @@
 	 * transport_clear_lun_from_sessions() once the ConfigFS context caller
 	 * has completed its operation on the struct se_cmd.
 	 */
-	if (atomic_read(&cmd->transport_lun_stop)) {
-
+	if (cmd->transport_state & CMD_T_LUN_STOP) {
 		pr_debug("wait_for_tasks: Stopping"
 			" wait_for_completion(&cmd->t_tasktransport_lun_fe"
 			"_stop_comp); for ITT: 0x%08x\n",
@@ -4345,18 +4455,18 @@
 			"stop_comp); for ITT: 0x%08x\n",
 			cmd->se_tfo->get_task_tag(cmd));
 
-		atomic_set(&cmd->transport_lun_stop, 0);
+		cmd->transport_state &= ~CMD_T_LUN_STOP;
 	}
-	if (!atomic_read(&cmd->t_transport_active) ||
-	     atomic_read(&cmd->t_transport_aborted)) {
+
+	if (!(cmd->transport_state & CMD_T_ACTIVE)) {
 		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 		return false;
 	}
 
-	atomic_set(&cmd->t_transport_stop, 1);
+	cmd->transport_state |= CMD_T_STOP;
 
 	pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08x"
-		" i_state: %d, t_state: %d, t_transport_stop = TRUE\n",
+		" i_state: %d, t_state: %d, CMD_T_STOP\n",
 		cmd, cmd->se_tfo->get_task_tag(cmd),
 		cmd->se_tfo->get_cmd_state(cmd), cmd->t_state);
 
@@ -4367,8 +4477,7 @@
 	wait_for_completion(&cmd->t_transport_stop_comp);
 
 	spin_lock_irqsave(&cmd->t_state_lock, flags);
-	atomic_set(&cmd->t_transport_active, 0);
-	atomic_set(&cmd->t_transport_stop, 0);
+	cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP);
 
 	pr_debug("wait_for_tasks: Stopped wait_for_compltion("
 		"&cmd->t_transport_stop_comp) for ITT: 0x%08x\n",
@@ -4597,7 +4706,7 @@
 {
 	int ret = 0;
 
-	if (atomic_read(&cmd->t_transport_aborted) != 0) {
+	if (cmd->transport_state & CMD_T_ABORTED) {
 		if (!send_status ||
 		     (cmd->se_cmd_flags & SCF_SENT_DELAYED_TAS))
 			return 1;
@@ -4634,7 +4743,7 @@
 	 */
 	if (cmd->data_direction == DMA_TO_DEVICE) {
 		if (cmd->se_tfo->write_pending_status(cmd) != 0) {
-			atomic_inc(&cmd->t_transport_aborted);
+			cmd->transport_state |= CMD_T_ABORTED;
 			smp_mb__after_atomic_inc();
 		}
 	}
@@ -4655,7 +4764,7 @@
 
 	switch (tmr->function) {
 	case TMR_ABORT_TASK:
-		tmr->response = TMR_FUNCTION_REJECTED;
+		core_tmr_abort_task(dev, tmr, cmd->se_sess);
 		break;
 	case TMR_ABORT_TASK_SET:
 	case TMR_CLEAR_ACA:
diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c
index 3e12f6b..6666a0c 100644
--- a/drivers/target/target_core_ua.c
+++ b/drivers/target/target_core_ua.c
@@ -53,7 +53,7 @@
 	if (!nacl)
 		return 0;
 
-	deve = &nacl->device_list[cmd->orig_fe_lun];
+	deve = nacl->device_list[cmd->orig_fe_lun];
 	if (!atomic_read(&deve->ua_count))
 		return 0;
 	/*
@@ -110,7 +110,7 @@
 	ua->ua_ascq = ascq;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[unpacked_lun];
+	deve = nacl->device_list[unpacked_lun];
 
 	spin_lock(&deve->ua_lock);
 	list_for_each_entry_safe(ua_p, ua_tmp, &deve->ua_list, ua_nacl_list) {
@@ -220,7 +220,7 @@
 		return;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[cmd->orig_fe_lun];
+	deve = nacl->device_list[cmd->orig_fe_lun];
 	if (!atomic_read(&deve->ua_count)) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return;
@@ -289,7 +289,7 @@
 		return -EINVAL;
 
 	spin_lock_irq(&nacl->device_list_lock);
-	deve = &nacl->device_list[cmd->orig_fe_lun];
+	deve = nacl->device_list[cmd->orig_fe_lun];
 	if (!atomic_read(&deve->ua_count)) {
 		spin_unlock_irq(&nacl->device_list_lock);
 		return -EPERM;
diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h
index e05c551..8306579 100644
--- a/drivers/target/tcm_fc/tcm_fc.h
+++ b/drivers/target/tcm_fc/tcm_fc.h
@@ -17,7 +17,7 @@
 #ifndef __TCM_FC_H__
 #define __TCM_FC_H__
 
-#define FT_VERSION "0.3"
+#define FT_VERSION "0.4"
 
 #define FT_NAMELEN 32		/* length of ASCII WWPNs including pad */
 #define FT_TPG_NAMELEN 32	/* max length of TPG name */
@@ -113,12 +113,10 @@
  * Commands
  */
 struct ft_cmd {
-	u32 lun;                        /* LUN from request */
 	struct ft_sess *sess;		/* session held for cmd */
 	struct fc_seq *seq;		/* sequence in exchange mgr */
 	struct se_cmd se_cmd;		/* Local TCM I/O descriptor */
 	struct fc_frame *req_frame;
-	unsigned char *cdb;		/* pointer to CDB inside frame */
 	u32 write_data_len;		/* data received on writes */
 	struct work_struct work;
 	/* Local sense buffer */
@@ -143,11 +141,8 @@
 void ft_sess_put(struct ft_sess *);
 int ft_sess_shutdown(struct se_session *);
 void ft_sess_close(struct se_session *);
-void ft_sess_stop(struct se_session *, int, int);
-int ft_sess_logged_in(struct se_session *);
 u32 ft_sess_get_index(struct se_session *);
 u32 ft_sess_get_port_name(struct se_session *, unsigned char *, u32);
-void ft_sess_set_erl0(struct se_session *);
 
 void ft_lport_add(struct fc_lport *, void *);
 void ft_lport_del(struct fc_lport *, void *);
@@ -165,7 +160,6 @@
 u32 ft_get_task_tag(struct se_cmd *);
 int ft_get_cmd_state(struct se_cmd *);
 int ft_queue_tm_resp(struct se_cmd *);
-int ft_is_state_remove(struct se_cmd *);
 
 /*
  * other internal functions.
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c
index 9e7e26c..62dec97 100644
--- a/drivers/target/tcm_fc/tfc_cmd.c
+++ b/drivers/target/tcm_fc/tfc_cmd.c
@@ -59,9 +59,6 @@
 	se_cmd = &cmd->se_cmd;
 	pr_debug("%s: cmd %p sess %p seq %p se_cmd %p\n",
 		caller, cmd, cmd->sess, cmd->seq, se_cmd);
-	pr_debug("%s: cmd %p cdb %p\n",
-		caller, cmd, cmd->cdb);
-	pr_debug("%s: cmd %p lun %d\n", caller, cmd, cmd->lun);
 
 	pr_debug("%s: cmd %p data_nents %u len %u se_cmd_flags <0x%x>\n",
 		caller, cmd, se_cmd->t_data_nents,
@@ -81,8 +78,6 @@
 			caller, cmd, ep->sid, ep->did, ep->oxid, ep->rxid,
 			sp->id, ep->esb_stat);
 	}
-	print_hex_dump(KERN_INFO, "ft_dump_cmd ", DUMP_PREFIX_NONE,
-		16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0);
 }
 
 static void ft_free_cmd(struct ft_cmd *cmd)
@@ -249,11 +244,6 @@
 	return 0;
 }
 
-int ft_is_state_remove(struct se_cmd *se_cmd)
-{
-	return 0;	/* XXX TBD */
-}
-
 /*
  * FC sequence response handler for follow-on sequences (data) and aborts.
  */
@@ -325,10 +315,12 @@
 
 	fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_DD_CMD_STATUS, 0);
 	sp = fr_seq(fp);
-	if (sp)
+	if (sp) {
 		lport->tt.seq_send(lport, sp, fp);
-	else
+		lport->tt.exch_done(sp);
+	} else {
 		lport->tt.frame_send(lport, fp);
+	}
 }
 
 /*
@@ -358,16 +350,10 @@
  */
 static void ft_send_tm(struct ft_cmd *cmd)
 {
-	struct se_tmr_req *tmr;
 	struct fcp_cmnd *fcp;
-	struct ft_sess *sess;
+	int rc;
 	u8 tm_func;
 
-	transport_init_se_cmd(&cmd->se_cmd, &ft_configfs->tf_ops,
-			cmd->sess->se_sess, 0, DMA_NONE, 0,
-			&cmd->ft_sense_buffer[0]);
-	target_get_sess_cmd(cmd->sess->se_sess, &cmd->se_cmd, false);
-
 	fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));
 
 	switch (fcp->fc_tm_flags) {
@@ -396,44 +382,12 @@
 		return;
 	}
 
-	pr_debug("alloc tm cmd fn %d\n", tm_func);
-	tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func, GFP_KERNEL);
-	if (!tmr) {
-		pr_debug("alloc failed\n");
+	/* FIXME: Add referenced task tag for ABORT_TASK */
+	rc = target_submit_tmr(&cmd->se_cmd, cmd->sess->se_sess,
+		&cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
+		cmd, tm_func, GFP_KERNEL, 0, 0);
+	if (rc < 0)
 		ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED);
-		return;
-	}
-	cmd->se_cmd.se_tmr_req = tmr;
-
-	switch (fcp->fc_tm_flags) {
-	case FCP_TMF_LUN_RESET:
-		cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun);
-		if (transport_lookup_tmr_lun(&cmd->se_cmd, cmd->lun) < 0) {
-			/*
-			 * Make sure to clean up newly allocated TMR request
-			 * since "unable to  handle TMR request because failed
-			 * to get to LUN"
-			 */
-			pr_debug("Failed to get LUN for TMR func %d, "
-				  "se_cmd %p, unpacked_lun %d\n",
-				  tm_func, &cmd->se_cmd, cmd->lun);
-			ft_dump_cmd(cmd, __func__);
-			sess = cmd->sess;
-			transport_send_check_condition_and_sense(&cmd->se_cmd,
-				cmd->se_cmd.scsi_sense_reason, 0);
-			ft_sess_put(sess);
-			return;
-		}
-		break;
-	case FCP_TMF_TGT_RESET:
-	case FCP_TMF_CLR_TASK_SET:
-	case FCP_TMF_ABT_TASK_SET:
-	case FCP_TMF_CLR_ACA:
-		break;
-	default:
-		return;
-	}
-	transport_generic_handle_tmr(&cmd->se_cmd);
 }
 
 /*
@@ -538,7 +492,6 @@
 	struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame);
 	struct fcp_cmnd *fcp;
 	int data_dir = 0;
-	u32 data_len;
 	int task_attr;
 
 	fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));
@@ -548,47 +501,6 @@
 	if (fcp->fc_flags & FCP_CFL_LEN_MASK)
 		goto err;		/* not handling longer CDBs yet */
 
-	if (fcp->fc_tm_flags) {
-		task_attr = FCP_PTA_SIMPLE;
-		data_dir = DMA_NONE;
-		data_len = 0;
-	} else {
-		switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) {
-		case 0:
-			data_dir = DMA_NONE;
-			break;
-		case FCP_CFL_RDDATA:
-			data_dir = DMA_FROM_DEVICE;
-			break;
-		case FCP_CFL_WRDATA:
-			data_dir = DMA_TO_DEVICE;
-			break;
-		case FCP_CFL_WRDATA | FCP_CFL_RDDATA:
-			goto err;	/* TBD not supported by tcm_fc yet */
-		}
-		/*
-		 * Locate the SAM Task Attr from fc_pri_ta
-		 */
-		switch (fcp->fc_pri_ta & FCP_PTA_MASK) {
-		case FCP_PTA_HEADQ:
-			task_attr = MSG_HEAD_TAG;
-			break;
-		case FCP_PTA_ORDERED:
-			task_attr = MSG_ORDERED_TAG;
-			break;
-		case FCP_PTA_ACA:
-			task_attr = MSG_ACA_TAG;
-			break;
-		case FCP_PTA_SIMPLE: /* Fallthrough */
-		default:
-			task_attr = MSG_SIMPLE_TAG;
-		}
-
-
-		task_attr = fcp->fc_pri_ta & FCP_PTA_MASK;
-		data_len = ntohl(fcp->fc_dl);
-		cmd->cdb = fcp->fc_cdb;
-	}
 	/*
 	 * Check for FCP task management flags
 	 */
@@ -596,15 +508,46 @@
 		ft_send_tm(cmd);
 		return;
 	}
+
+	switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) {
+	case 0:
+		data_dir = DMA_NONE;
+		break;
+	case FCP_CFL_RDDATA:
+		data_dir = DMA_FROM_DEVICE;
+		break;
+	case FCP_CFL_WRDATA:
+		data_dir = DMA_TO_DEVICE;
+		break;
+	case FCP_CFL_WRDATA | FCP_CFL_RDDATA:
+		goto err;	/* TBD not supported by tcm_fc yet */
+	}
+	/*
+	 * Locate the SAM Task Attr from fc_pri_ta
+	 */
+	switch (fcp->fc_pri_ta & FCP_PTA_MASK) {
+	case FCP_PTA_HEADQ:
+		task_attr = MSG_HEAD_TAG;
+		break;
+	case FCP_PTA_ORDERED:
+		task_attr = MSG_ORDERED_TAG;
+		break;
+	case FCP_PTA_ACA:
+		task_attr = MSG_ACA_TAG;
+		break;
+	case FCP_PTA_SIMPLE: /* Fallthrough */
+	default:
+		task_attr = MSG_SIMPLE_TAG;
+	}
+
 	fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd);
-	cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun);
 	/*
 	 * Use a single se_cmd->cmd_kref as we expect to release se_cmd
 	 * directly from ft_check_stop_free callback in response path.
 	 */
-	target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, cmd->cdb,
-				&cmd->ft_sense_buffer[0], cmd->lun, data_len,
-				task_attr, data_dir, 0);
+	target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb,
+			&cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
+			ntohl(fcp->fc_dl), task_attr, data_dir, 0);
 	pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl);
 	return;
 
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c
index 73852fb..f357039 100644
--- a/drivers/target/tcm_fc/tfc_conf.c
+++ b/drivers/target/tcm_fc/tfc_conf.c
@@ -529,9 +529,6 @@
 	.release_cmd =			ft_release_cmd,
 	.shutdown_session =		ft_sess_shutdown,
 	.close_session =		ft_sess_close,
-	.stop_session =			ft_sess_stop,
-	.fall_back_to_erl0 =		ft_sess_set_erl0,
-	.sess_logged_in =		ft_sess_logged_in,
 	.sess_get_index =		ft_sess_get_index,
 	.sess_get_initiator_sid =	NULL,
 	.write_pending =		ft_write_pending,
@@ -544,7 +541,6 @@
 	.queue_tm_rsp =			ft_queue_tm_resp,
 	.get_fabric_sense_len =		ft_get_fabric_sense_len,
 	.set_fabric_sense_len =		ft_set_fabric_sense_len,
-	.is_state_remove =		ft_is_state_remove,
 	/*
 	 * Setup function pointers for generic logic in
 	 * target_core_fabric_configfs.c
diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c
index eff512b..cb99da9 100644
--- a/drivers/target/tcm_fc/tfc_sess.c
+++ b/drivers/target/tcm_fc/tfc_sess.c
@@ -309,11 +309,9 @@
 void ft_sess_close(struct se_session *se_sess)
 {
 	struct ft_sess *sess = se_sess->fabric_sess_ptr;
-	struct fc_lport *lport;
 	u32 port_id;
 
 	mutex_lock(&ft_lport_lock);
-	lport = sess->tport->lport;
 	port_id = sess->port_id;
 	if (port_id == -1) {
 		mutex_unlock(&ft_lport_lock);
@@ -328,20 +326,6 @@
 	synchronize_rcu();		/* let transport deregister happen */
 }
 
-void ft_sess_stop(struct se_session *se_sess, int sess_sleep, int conn_sleep)
-{
-	struct ft_sess *sess = se_sess->fabric_sess_ptr;
-
-	pr_debug("port_id %x\n", sess->port_id);
-}
-
-int ft_sess_logged_in(struct se_session *se_sess)
-{
-	struct ft_sess *sess = se_sess->fabric_sess_ptr;
-
-	return sess->port_id != -1;
-}
-
 u32 ft_sess_get_index(struct se_session *se_sess)
 {
 	struct ft_sess *sess = se_sess->fabric_sess_ptr;
@@ -357,11 +341,6 @@
 	return ft_format_wwn(buf, len, sess->port_name);
 }
 
-void ft_sess_set_erl0(struct se_session *se_sess)
-{
-	/* XXX TBD called when out of memory */
-}
-
 /*
  * libfc ops involving sessions.
  */
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index f7f71b2..514a691 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -18,3 +18,11 @@
 	depends on THERMAL
 	depends on HWMON=y || HWMON=THERMAL
 	default y
+
+config SPEAR_THERMAL
+	bool "SPEAr thermal sensor driver"
+	depends on THERMAL
+	depends on PLAT_SPEAR
+	help
+	  Enable this to plug the SPEAr thermal sensor driver into the Linux
+	  thermal framework
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 31108a0..a9fff0b 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_THERMAL)		+= thermal_sys.o
+obj-$(CONFIG_SPEAR_THERMAL)		+= spear_thermal.o
\ No newline at end of file
diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c
new file mode 100644
index 0000000..c2e32df
--- /dev/null
+++ b/drivers/thermal/spear_thermal.c
@@ -0,0 +1,206 @@
+/*
+ * SPEAr thermal driver.
+ *
+ * Copyright (C) 2011-2012 ST Microelectronics
+ * Author: Vincenzo Frascino <vincenzo.frascino@st.com>
+ *
+ * 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/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/spear_thermal.h>
+#include <linux/thermal.h>
+
+#define MD_FACTOR	1000
+
+/* SPEAr Thermal Sensor Dev Structure */
+struct spear_thermal_dev {
+	/* pointer to base address of the thermal sensor */
+	void __iomem *thermal_base;
+	/* clk structure */
+	struct clk *clk;
+	/* pointer to thermal flags */
+	unsigned int flags;
+};
+
+static inline int thermal_get_temp(struct thermal_zone_device *thermal,
+				unsigned long *temp)
+{
+	struct spear_thermal_dev *stdev = thermal->devdata;
+
+	/*
+	 * Data are ready to be read after 628 usec from POWERDOWN signal
+	 * (PDN) = 1
+	 */
+	*temp = (readl_relaxed(stdev->thermal_base) & 0x7F) * MD_FACTOR;
+	return 0;
+}
+
+static struct thermal_zone_device_ops ops = {
+	.get_temp = thermal_get_temp,
+};
+
+#ifdef CONFIG_PM
+static int spear_thermal_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev);
+	struct spear_thermal_dev *stdev = spear_thermal->devdata;
+	unsigned int actual_mask = 0;
+
+	/* Disable SPEAr Thermal Sensor */
+	actual_mask = readl_relaxed(stdev->thermal_base);
+	writel_relaxed(actual_mask & ~stdev->flags, stdev->thermal_base);
+
+	clk_disable(stdev->clk);
+	dev_info(dev, "Suspended.\n");
+
+	return 0;
+}
+
+static int spear_thermal_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev);
+	struct spear_thermal_dev *stdev = spear_thermal->devdata;
+	unsigned int actual_mask = 0;
+	int ret = 0;
+
+	ret = clk_enable(stdev->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't enable clock\n");
+		return ret;
+	}
+
+	/* Enable SPEAr Thermal Sensor */
+	actual_mask = readl_relaxed(stdev->thermal_base);
+	writel_relaxed(actual_mask | stdev->flags, stdev->thermal_base);
+
+	dev_info(dev, "Resumed.\n");
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(spear_thermal_pm_ops, spear_thermal_suspend,
+		spear_thermal_resume);
+
+static int spear_thermal_probe(struct platform_device *pdev)
+{
+	struct thermal_zone_device *spear_thermal = NULL;
+	struct spear_thermal_dev *stdev;
+	struct spear_thermal_pdata *pdata;
+	int ret = 0;
+	struct resource *stres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!stres) {
+		dev_err(&pdev->dev, "memory resource missing\n");
+		return -ENODEV;
+	}
+
+	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata) {
+		dev_err(&pdev->dev, "platform data is NULL\n");
+		return -EINVAL;
+	}
+
+	stdev = devm_kzalloc(&pdev->dev, sizeof(*stdev), GFP_KERNEL);
+	if (!stdev) {
+		dev_err(&pdev->dev, "kzalloc fail\n");
+		return -ENOMEM;
+	}
+
+	/* Enable thermal sensor */
+	stdev->thermal_base = devm_ioremap(&pdev->dev, stres->start,
+			resource_size(stres));
+	if (!stdev->thermal_base) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		return -ENOMEM;
+	}
+
+	stdev->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(stdev->clk)) {
+		dev_err(&pdev->dev, "Can't get clock\n");
+		return PTR_ERR(stdev->clk);
+	}
+
+	ret = clk_enable(stdev->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't enable clock\n");
+		goto put_clk;
+	}
+
+	stdev->flags = pdata->thermal_flags;
+	writel_relaxed(stdev->flags, stdev->thermal_base);
+
+	spear_thermal = thermal_zone_device_register("spear_thermal", 0,
+				stdev, &ops, 0, 0, 0, 0);
+	if (IS_ERR(spear_thermal)) {
+		dev_err(&pdev->dev, "thermal zone device is NULL\n");
+		ret = PTR_ERR(spear_thermal);
+		goto disable_clk;
+	}
+
+	platform_set_drvdata(pdev, spear_thermal);
+
+	dev_info(&spear_thermal->device, "Thermal Sensor Loaded at: 0x%p.\n",
+			stdev->thermal_base);
+
+	return 0;
+
+disable_clk:
+	clk_disable(stdev->clk);
+put_clk:
+	clk_put(stdev->clk);
+
+	return ret;
+}
+
+static int spear_thermal_exit(struct platform_device *pdev)
+{
+	unsigned int actual_mask = 0;
+	struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev);
+	struct spear_thermal_dev *stdev = spear_thermal->devdata;
+
+	thermal_zone_device_unregister(spear_thermal);
+	platform_set_drvdata(pdev, NULL);
+
+	/* Disable SPEAr Thermal Sensor */
+	actual_mask = readl_relaxed(stdev->thermal_base);
+	writel_relaxed(actual_mask & ~stdev->flags, stdev->thermal_base);
+
+	clk_disable(stdev->clk);
+	clk_put(stdev->clk);
+
+	return 0;
+}
+
+static struct platform_driver spear_thermal_driver = {
+	.probe = spear_thermal_probe,
+	.remove = spear_thermal_exit,
+	.driver = {
+		.name = "spear_thermal",
+		.owner = THIS_MODULE,
+		.pm = &spear_thermal_pm_ops,
+	},
+};
+
+module_platform_driver(spear_thermal_driver);
+
+MODULE_AUTHOR("Vincenzo Frascino <vincenzo.frascino@st.com>");
+MODULE_DESCRIPTION("SPEAr thermal driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 220ce7e..022bacb 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -23,6 +23,8 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -39,8 +41,6 @@
 MODULE_DESCRIPTION("Generic thermal management sysfs support");
 MODULE_LICENSE("GPL");
 
-#define PREFIX "Thermal: "
-
 struct thermal_cooling_device_instance {
 	int id;
 	char name[THERMAL_NAME_LENGTH];
@@ -60,13 +60,11 @@
 static LIST_HEAD(thermal_cdev_list);
 static DEFINE_MUTEX(thermal_list_lock);
 
-static unsigned int thermal_event_seqnum;
-
 static int get_idr(struct idr *idr, struct mutex *lock, int *id)
 {
 	int err;
 
-      again:
+again:
 	if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
 		return -ENOMEM;
 
@@ -152,9 +150,9 @@
 	if (!tz->ops->set_mode)
 		return -EPERM;
 
-	if (!strncmp(buf, "enabled", sizeof("enabled")))
+	if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
 		result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
-	else if (!strncmp(buf, "disabled", sizeof("disabled")))
+	else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
 		result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
 	else
 		result = -EINVAL;
@@ -283,8 +281,7 @@
 static DEVICE_ATTR(type, 0444, type_show, NULL);
 static DEVICE_ATTR(temp, 0444, temp_show, NULL);
 static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
-static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, \
-		   passive_store);
+static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
 
 static struct device_attribute trip_point_attrs[] = {
 	__ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
@@ -313,22 +310,6 @@
 	__ATTR(trip_point_11_temp, 0444, trip_point_temp_show, NULL),
 };
 
-#define TRIP_POINT_ATTR_ADD(_dev, _index, result)     \
-do {    \
-	result = device_create_file(_dev,	\
-				&trip_point_attrs[_index * 2]);	\
-	if (result)	\
-		break;	\
-	result = device_create_file(_dev,	\
-			&trip_point_attrs[_index * 2 + 1]);	\
-} while (0)
-
-#define TRIP_POINT_ATTR_REMOVE(_dev, _index)	\
-do {	\
-	device_remove_file(_dev, &trip_point_attrs[_index * 2]);	\
-	device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]);	\
-} while (0)
-
 /* sys I/F for cooling device */
 #define to_cooling_device(_dev)	\
 	container_of(_dev, struct thermal_cooling_device, device)
@@ -835,15 +816,14 @@
 		return 0;
 
 	device_remove_file(&tz->device, &dev->attr);
-      remove_symbol_link:
+remove_symbol_link:
 	sysfs_remove_link(&tz->device.kobj, dev->name);
-      release_idr:
+release_idr:
 	release_idr(&tz->idr, &tz->lock, dev->id);
-      free_mem:
+free_mem:
 	kfree(dev);
 	return result;
 }
-
 EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
 
 /**
@@ -873,14 +853,13 @@
 
 	return -ENODEV;
 
-      unbind:
+unbind:
 	device_remove_file(&tz->device, &pos->attr);
 	sysfs_remove_link(&tz->device.kobj, pos->name);
 	release_idr(&tz->idr, &tz->lock, pos->id);
 	kfree(pos);
 	return 0;
 }
-
 EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
 
 static void thermal_release(struct device *dev)
@@ -888,7 +867,8 @@
 	struct thermal_zone_device *tz;
 	struct thermal_cooling_device *cdev;
 
-	if (!strncmp(dev_name(dev), "thermal_zone", sizeof "thermal_zone" - 1)) {
+	if (!strncmp(dev_name(dev), "thermal_zone",
+		     sizeof("thermal_zone") - 1)) {
 		tz = to_thermal_zone(dev);
 		kfree(tz);
 	} else {
@@ -908,8 +888,9 @@
  * @devdata:	device private data.
  * @ops:		standard thermal cooling devices callbacks.
  */
-struct thermal_cooling_device *thermal_cooling_device_register(
-     char *type, void *devdata, const struct thermal_cooling_device_ops *ops)
+struct thermal_cooling_device *
+thermal_cooling_device_register(char *type, void *devdata,
+				const struct thermal_cooling_device_ops *ops)
 {
 	struct thermal_cooling_device *cdev;
 	struct thermal_zone_device *pos;
@@ -974,12 +955,11 @@
 	if (!result)
 		return cdev;
 
-      unregister:
+unregister:
 	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
 	device_unregister(&cdev->device);
 	return ERR_PTR(result);
 }
-
 EXPORT_SYMBOL(thermal_cooling_device_register);
 
 /**
@@ -1024,7 +1004,6 @@
 	device_unregister(&cdev->device);
 	return;
 }
-
 EXPORT_SYMBOL(thermal_cooling_device_unregister);
 
 /**
@@ -1044,8 +1023,7 @@
 
 	if (tz->ops->get_temp(tz, &temp)) {
 		/* get_temp failed - retry it later */
-		printk(KERN_WARNING PREFIX "failed to read out thermal zone "
-		       "%d\n", tz->id);
+		pr_warn("failed to read out thermal zone %d\n", tz->id);
 		goto leave;
 	}
 
@@ -1060,9 +1038,8 @@
 					ret = tz->ops->notify(tz, count,
 							      trip_type);
 				if (!ret) {
-					printk(KERN_EMERG
-					       "Critical temperature reached (%ld C), shutting down.\n",
-					       temp/1000);
+					pr_emerg("Critical temperature reached (%ld C), shutting down\n",
+						 temp/1000);
 					orderly_poweroff(true);
 				}
 			}
@@ -1100,7 +1077,7 @@
 
 	tz->last_temperature = temp;
 
-      leave:
+leave:
 	if (tz->passive)
 		thermal_zone_device_set_polling(tz, tz->passive_delay);
 	else if (tz->polling_delay)
@@ -1199,7 +1176,12 @@
 	}
 
 	for (count = 0; count < trips; count++) {
-		TRIP_POINT_ATTR_ADD(&tz->device, count, result);
+		result = device_create_file(&tz->device,
+					    &trip_point_attrs[count * 2]);
+		if (result)
+			break;
+		result = device_create_file(&tz->device,
+					    &trip_point_attrs[count * 2 + 1]);
 		if (result)
 			goto unregister;
 		tz->ops->get_trip_type(tz, count, &trip_type);
@@ -1235,12 +1217,11 @@
 	if (!result)
 		return tz;
 
-      unregister:
+unregister:
 	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
 	device_unregister(&tz->device);
 	return ERR_PTR(result);
 }
-
 EXPORT_SYMBOL(thermal_zone_device_register);
 
 /**
@@ -1279,9 +1260,12 @@
 	if (tz->ops->get_mode)
 		device_remove_file(&tz->device, &dev_attr_mode);
 
-	for (count = 0; count < tz->trips; count++)
-		TRIP_POINT_ATTR_REMOVE(&tz->device, count);
-
+	for (count = 0; count < tz->trips; count++) {
+		device_remove_file(&tz->device,
+				   &trip_point_attrs[count * 2]);
+		device_remove_file(&tz->device,
+				   &trip_point_attrs[count * 2 + 1]);
+	}
 	thermal_remove_hwmon_sysfs(tz);
 	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
 	idr_destroy(&tz->idr);
@@ -1289,7 +1273,6 @@
 	device_unregister(&tz->device);
 	return;
 }
-
 EXPORT_SYMBOL(thermal_zone_device_unregister);
 
 #ifdef CONFIG_NET
@@ -1312,10 +1295,11 @@
 	void *msg_header;
 	int size;
 	int result;
+	static unsigned int thermal_event_seqnum;
 
 	/* allocate memory */
-	size = nla_total_size(sizeof(struct thermal_genl_event)) + \
-				nla_total_size(0);
+	size = nla_total_size(sizeof(struct thermal_genl_event)) +
+	       nla_total_size(0);
 
 	skb = genlmsg_new(size, GFP_ATOMIC);
 	if (!skb)
@@ -1331,8 +1315,8 @@
 	}
 
 	/* fill the data */
-	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT, \
-			sizeof(struct thermal_genl_event));
+	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
+			   sizeof(struct thermal_genl_event));
 
 	if (!attr) {
 		nlmsg_free(skb);
@@ -1359,7 +1343,7 @@
 
 	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
 	if (result)
-		printk(KERN_INFO "failed to send netlink event:%d", result);
+		pr_info("failed to send netlink event:%d\n", result);
 
 	return result;
 }
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index afadcd43..24145c3 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -85,7 +85,6 @@
 
 #include <asm/setup.h>
 
-#include <asm/system.h>
 
 #include <asm/irq.h>
 
diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig
index 4222035..0282a83 100644
--- a/drivers/tty/hvc/Kconfig
+++ b/drivers/tty/hvc/Kconfig
@@ -24,16 +24,6 @@
 	depends on HVC_CONSOLE
 	default n
 
-config HVC_ISERIES
-	bool "iSeries Hypervisor Virtual Console support"
-	depends on PPC_ISERIES
-	default y
-	select HVC_DRIVER
-	select HVC_IRQ
-	select VIOPATH
-	help
-	  iSeries machines support a hypervisor virtual console.
-
 config HVC_OPAL
 	bool "OPAL Console support"
 	depends on PPC_POWERNV
@@ -76,11 +66,23 @@
 	help
 	  Xen virtual console device driver
 
+config HVC_XEN_FRONTEND
+	bool "Xen Hypervisor Multiple Consoles support"
+	depends on HVC_XEN
+	select XEN_XENBUS_FRONTEND
+	default y
+	help
+	  Xen driver for secondary virtual consoles
+
 config HVC_UDBG
        bool "udbg based fake hypervisor console"
        depends on PPC && EXPERIMENTAL
        select HVC_DRIVER
        default n
+       help
+         This is meant to be used during HW bring up or debugging when
+	 no other console mechanism exist but udbg, to get you a quick
+	 console for userspace. Do NOT enable in production kernels. 
 
 config HVC_DCC
        bool "ARM JTAG DCC console"
diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile
index 89abf40b..4ca3723 100644
--- a/drivers/tty/hvc/Makefile
+++ b/drivers/tty/hvc/Makefile
@@ -1,7 +1,6 @@
 obj-$(CONFIG_HVC_CONSOLE)	+= hvc_vio.o hvsi_lib.o
 obj-$(CONFIG_HVC_OPAL)		+= hvc_opal.o hvsi_lib.o
 obj-$(CONFIG_HVC_OLD_HVSI)	+= hvsi.o
-obj-$(CONFIG_HVC_ISERIES)	+= hvc_iseries.o
 obj-$(CONFIG_HVC_RTAS)		+= hvc_rtas.o
 obj-$(CONFIG_HVC_TILE)		+= hvc_tile.o
 obj-$(CONFIG_HVC_DCC)		+= hvc_dcc.o
diff --git a/drivers/tty/hvc/hvc_iseries.c b/drivers/tty/hvc/hvc_iseries.c
deleted file mode 100644
index 3f4a897..0000000
--- a/drivers/tty/hvc/hvc_iseries.c
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- * iSeries vio driver interface to hvc_console.c
- *
- * This code is based heavily on hvc_vio.c and viocons.c
- *
- * Copyright (C) 2006 Stephen Rothwell, 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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 <stdarg.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/console.h>
-
-#include <asm/hvconsole.h>
-#include <asm/vio.h>
-#include <asm/prom.h>
-#include <asm/firmware.h>
-#include <asm/iseries/vio.h>
-#include <asm/iseries/hv_call.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_lp_event.h>
-
-#include "hvc_console.h"
-
-#define VTTY_PORTS 10
-
-static DEFINE_SPINLOCK(consolelock);
-static DEFINE_SPINLOCK(consoleloglock);
-
-static const char hvc_driver_name[] = "hvc_console";
-
-#define IN_BUF_SIZE	200
-
-/*
- * Our port information.
- */
-static struct port_info {
-	HvLpIndex lp;
-	u64 seq;	/* sequence number of last HV send */
-	u64 ack;	/* last ack from HV */
-	struct hvc_struct *hp;
-	int in_start;
-	int in_end;
-	unsigned char in_buf[IN_BUF_SIZE];
-} port_info[VTTY_PORTS] = {
-	[ 0 ... VTTY_PORTS - 1 ] = {
-		.lp = HvLpIndexInvalid
-	}
-};
-
-#define viochar_is_console(pi)	((pi) == &port_info[0])
-
-static struct vio_device_id hvc_driver_table[] __devinitdata = {
-	{"serial", "IBM,iSeries-vty"},
-	{ "", "" }
-};
-MODULE_DEVICE_TABLE(vio, hvc_driver_table);
-
-static void hvlog(char *fmt, ...)
-{
-	int i;
-	unsigned long flags;
-	va_list args;
-	static char buf[256];
-
-	spin_lock_irqsave(&consoleloglock, flags);
-	va_start(args, fmt);
-	i = vscnprintf(buf, sizeof(buf) - 1, fmt, args);
-	va_end(args);
-	buf[i++] = '\r';
-	HvCall_writeLogBuffer(buf, i);
-	spin_unlock_irqrestore(&consoleloglock, flags);
-}
-
-/*
- * Initialize the common fields in a charLpEvent
- */
-static void init_data_event(struct viocharlpevent *viochar, HvLpIndex lp)
-{
-	struct HvLpEvent *hev = &viochar->event;
-
-	memset(viochar, 0, sizeof(struct viocharlpevent));
-
-	hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK |
-		HV_LP_EVENT_INT;
-	hev->xType = HvLpEvent_Type_VirtualIo;
-	hev->xSubtype = viomajorsubtype_chario | viochardata;
-	hev->xSourceLp = HvLpConfig_getLpIndex();
-	hev->xTargetLp = lp;
-	hev->xSizeMinus1 = sizeof(struct viocharlpevent);
-	hev->xSourceInstanceId = viopath_sourceinst(lp);
-	hev->xTargetInstanceId = viopath_targetinst(lp);
-}
-
-static int get_chars(uint32_t vtermno, char *buf, int count)
-{
-	struct port_info *pi;
-	int n = 0;
-	unsigned long flags;
-
-	if (vtermno >= VTTY_PORTS)
-		return -EINVAL;
-	if (count == 0)
-		return 0;
-
-	pi = &port_info[vtermno];
-	spin_lock_irqsave(&consolelock, flags);
-
-	if (pi->in_end == 0)
-		goto done;
-
-	n = pi->in_end - pi->in_start;
-	if (n > count)
-		n = count;
-	memcpy(buf, &pi->in_buf[pi->in_start], n);
-	pi->in_start += n;
-	if (pi->in_start == pi->in_end) {
-		pi->in_start = 0;
-		pi->in_end = 0;
-	}
-done:
-	spin_unlock_irqrestore(&consolelock, flags);
-	return n;
-}
-
-static int put_chars(uint32_t vtermno, const char *buf, int count)
-{
-	struct viocharlpevent *viochar;
-	struct port_info *pi;
-	HvLpEvent_Rc hvrc;
-	unsigned long flags;
-	int sent = 0;
-
-	if (vtermno >= VTTY_PORTS)
-		return -EINVAL;
-
-	pi = &port_info[vtermno];
-
-	spin_lock_irqsave(&consolelock, flags);
-
-	if (viochar_is_console(pi) && !viopath_isactive(pi->lp)) {
-		HvCall_writeLogBuffer(buf, count);
-		sent = count;
-		goto done;
-	}
-
-	viochar = vio_get_event_buffer(viomajorsubtype_chario);
-	if (viochar == NULL) {
-		hvlog("\n\rviocons: Can't get viochar buffer.");
-		goto done;
-	}
-
-	while ((count > 0) && ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) {
-		int len;
-
-		len = (count > VIOCHAR_MAX_DATA) ? VIOCHAR_MAX_DATA : count;
-
-		if (viochar_is_console(pi))
-			HvCall_writeLogBuffer(buf, len);
-
-		init_data_event(viochar, pi->lp);
-
-		viochar->len = len;
-		viochar->event.xCorrelationToken = pi->seq++;
-		viochar->event.xSizeMinus1 =
-			offsetof(struct viocharlpevent, data) + len;
-
-		memcpy(viochar->data, buf, len);
-
-		hvrc = HvCallEvent_signalLpEvent(&viochar->event);
-		if (hvrc)
-			hvlog("\n\rerror sending event! return code %d\n\r",
-				(int)hvrc);
-		sent += len;
-		count -= len;
-		buf += len;
-	}
-
-	vio_free_event_buffer(viomajorsubtype_chario, viochar);
-done:
-	spin_unlock_irqrestore(&consolelock, flags);
-	return sent;
-}
-
-static const struct hv_ops hvc_get_put_ops = {
-	.get_chars = get_chars,
-	.put_chars = put_chars,
-	.notifier_add = notifier_add_irq,
-	.notifier_del = notifier_del_irq,
-	.notifier_hangup = notifier_hangup_irq,
-};
-
-static int __devinit hvc_vio_probe(struct vio_dev *vdev,
-			const struct vio_device_id *id)
-{
-	struct hvc_struct *hp;
-	struct port_info *pi;
-
-	/* probed with invalid parameters. */
-	if (!vdev || !id)
-		return -EPERM;
-
-	if (vdev->unit_address >= VTTY_PORTS)
-		return -ENODEV;
-
-	pi = &port_info[vdev->unit_address];
-
-	hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops,
-			VIOCHAR_MAX_DATA);
-	if (IS_ERR(hp))
-		return PTR_ERR(hp);
-	pi->hp = hp;
-	dev_set_drvdata(&vdev->dev, pi);
-
-	return 0;
-}
-
-static int __devexit hvc_vio_remove(struct vio_dev *vdev)
-{
-	struct port_info *pi = dev_get_drvdata(&vdev->dev);
-	struct hvc_struct *hp = pi->hp;
-
-	return hvc_remove(hp);
-}
-
-static struct vio_driver hvc_vio_driver = {
-	.id_table	= hvc_driver_table,
-	.probe		= hvc_vio_probe,
-	.remove		= __devexit_p(hvc_vio_remove),
-	.driver		= {
-		.name	= hvc_driver_name,
-		.owner	= THIS_MODULE,
-	}
-};
-
-static void hvc_open_event(struct HvLpEvent *event)
-{
-	unsigned long flags;
-	struct viocharlpevent *cevent = (struct viocharlpevent *)event;
-	u8 port = cevent->virtual_device;
-	struct port_info *pi;
-	int reject = 0;
-
-	if (hvlpevent_is_ack(event)) {
-		if (port >= VTTY_PORTS)
-			return;
-
-		spin_lock_irqsave(&consolelock, flags);
-
-		pi = &port_info[port];
-		if (event->xRc == HvLpEvent_Rc_Good) {
-			pi->seq = pi->ack = 0;
-			/*
-			 * This line allows connections from the primary
-			 * partition but once one is connected from the
-			 * primary partition nothing short of a reboot
-			 * of linux will allow access from the hosting
-			 * partition again without a required iSeries fix.
-			 */
-			pi->lp = event->xTargetLp;
-		}
-
-		spin_unlock_irqrestore(&consolelock, flags);
-		if (event->xRc != HvLpEvent_Rc_Good)
-			printk(KERN_WARNING
-			       "hvc: handle_open_event: event->xRc == (%d).\n",
-			       event->xRc);
-
-		if (event->xCorrelationToken != 0) {
-			atomic_t *aptr= (atomic_t *)event->xCorrelationToken;
-			atomic_set(aptr, 1);
-		} else
-			printk(KERN_WARNING
-			       "hvc: weird...got open ack without atomic\n");
-		return;
-	}
-
-	/* This had better require an ack, otherwise complain */
-	if (!hvlpevent_need_ack(event)) {
-		printk(KERN_WARNING "hvc: viocharopen without ack bit!\n");
-		return;
-	}
-
-	spin_lock_irqsave(&consolelock, flags);
-
-	/* Make sure this is a good virtual tty */
-	if (port >= VTTY_PORTS) {
-		event->xRc = HvLpEvent_Rc_SubtypeError;
-		cevent->subtype_result_code = viorc_openRejected;
-		/*
-		 * Flag state here since we can't printk while holding
-		 * the consolelock spinlock.
-		 */
-		reject = 1;
-	} else {
-		pi = &port_info[port];
-		if ((pi->lp != HvLpIndexInvalid) &&
-				(pi->lp != event->xSourceLp)) {
-			/*
-			 * If this is tty is already connected to a different
-			 * partition, fail.
-			 */
-			event->xRc = HvLpEvent_Rc_SubtypeError;
-			cevent->subtype_result_code = viorc_openRejected;
-			reject = 2;
-		} else {
-			pi->lp = event->xSourceLp;
-			event->xRc = HvLpEvent_Rc_Good;
-			cevent->subtype_result_code = viorc_good;
-			pi->seq = pi->ack = 0;
-		}
-	}
-
-	spin_unlock_irqrestore(&consolelock, flags);
-
-	if (reject == 1)
-		printk(KERN_WARNING "hvc: open rejected: bad virtual tty.\n");
-	else if (reject == 2)
-		printk(KERN_WARNING "hvc: open rejected: console in exclusive "
-				"use by another partition.\n");
-
-	/* Return the acknowledgement */
-	HvCallEvent_ackLpEvent(event);
-}
-
-/*
- * Handle a close charLpEvent.  This should ONLY be an Interrupt because the
- * virtual console should never actually issue a close event to the hypervisor
- * because the virtual console never goes away.  A close event coming from the
- * hypervisor simply means that there are no client consoles connected to the
- * virtual console.
- */
-static void hvc_close_event(struct HvLpEvent *event)
-{
-	unsigned long flags;
-	struct viocharlpevent *cevent = (struct viocharlpevent *)event;
-	u8 port = cevent->virtual_device;
-
-	if (!hvlpevent_is_int(event)) {
-		printk(KERN_WARNING
-			"hvc: got unexpected close acknowledgement\n");
-		return;
-	}
-
-	if (port >= VTTY_PORTS) {
-		printk(KERN_WARNING
-			"hvc: close message from invalid virtual device.\n");
-		return;
-	}
-
-	/* For closes, just mark the console partition invalid */
-	spin_lock_irqsave(&consolelock, flags);
-
-	if (port_info[port].lp == event->xSourceLp)
-		port_info[port].lp = HvLpIndexInvalid;
-
-	spin_unlock_irqrestore(&consolelock, flags);
-}
-
-static void hvc_data_event(struct HvLpEvent *event)
-{
-	unsigned long flags;
-	struct viocharlpevent *cevent = (struct viocharlpevent *)event;
-	struct port_info *pi;
-	int n;
-	u8 port = cevent->virtual_device;
-
-	if (port >= VTTY_PORTS) {
-		printk(KERN_WARNING "hvc: data on invalid virtual device %d\n",
-				port);
-		return;
-	}
-	if (cevent->len == 0)
-		return;
-
-	/*
-	 * Change 05/01/2003 - Ryan Arnold: If a partition other than
-	 * the current exclusive partition tries to send us data
-	 * events then just drop them on the floor because we don't
-	 * want his stinking data.  He isn't authorized to receive
-	 * data because he wasn't the first one to get the console,
-	 * therefore he shouldn't be allowed to send data either.
-	 * This will work without an iSeries fix.
-	 */
-	pi = &port_info[port];
-	if (pi->lp != event->xSourceLp)
-		return;
-
-	spin_lock_irqsave(&consolelock, flags);
-
-	n = IN_BUF_SIZE - pi->in_end;
-	if (n > cevent->len)
-		n = cevent->len;
-	if (n > 0) {
-		memcpy(&pi->in_buf[pi->in_end], cevent->data, n);
-		pi->in_end += n;
-	}
-	spin_unlock_irqrestore(&consolelock, flags);
-	if (n == 0)
-		printk(KERN_WARNING "hvc: input buffer overflow\n");
-}
-
-static void hvc_ack_event(struct HvLpEvent *event)
-{
-	struct viocharlpevent *cevent = (struct viocharlpevent *)event;
-	unsigned long flags;
-	u8 port = cevent->virtual_device;
-
-	if (port >= VTTY_PORTS) {
-		printk(KERN_WARNING "hvc: data on invalid virtual device\n");
-		return;
-	}
-
-	spin_lock_irqsave(&consolelock, flags);
-	port_info[port].ack = event->xCorrelationToken;
-	spin_unlock_irqrestore(&consolelock, flags);
-}
-
-static void hvc_config_event(struct HvLpEvent *event)
-{
-	struct viocharlpevent *cevent = (struct viocharlpevent *)event;
-
-	if (cevent->data[0] == 0x01)
-		printk(KERN_INFO "hvc: window resized to %d: %d: %d: %d\n",
-		       cevent->data[1], cevent->data[2],
-		       cevent->data[3], cevent->data[4]);
-	else
-		printk(KERN_WARNING "hvc: unknown config event\n");
-}
-
-static void hvc_handle_event(struct HvLpEvent *event)
-{
-	int charminor;
-
-	if (event == NULL)
-		return;
-
-	charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
-	switch (charminor) {
-	case viocharopen:
-		hvc_open_event(event);
-		break;
-	case viocharclose:
-		hvc_close_event(event);
-		break;
-	case viochardata:
-		hvc_data_event(event);
-		break;
-	case viocharack:
-		hvc_ack_event(event);
-		break;
-	case viocharconfig:
-		hvc_config_event(event);
-		break;
-	default:
-		if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {
-			event->xRc = HvLpEvent_Rc_InvalidSubtype;
-			HvCallEvent_ackLpEvent(event);
-		}
-	}
-}
-
-static int __init send_open(HvLpIndex remoteLp, void *sem)
-{
-	return HvCallEvent_signalLpEventFast(remoteLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_chario | viocharopen,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(remoteLp),
-			viopath_targetinst(remoteLp),
-			(u64)(unsigned long)sem, VIOVERSION << 16,
-			0, 0, 0, 0);
-}
-
-static int __init hvc_vio_init(void)
-{
-	atomic_t wait_flag;
-	int rc;
-
-	if (!firmware_has_feature(FW_FEATURE_ISERIES))
-		return -EIO;
-
-	/* +2 for fudge */
-	rc = viopath_open(HvLpConfig_getPrimaryLpIndex(),
-			viomajorsubtype_chario, VIOCHAR_WINDOW + 2);
-	if (rc)
-		printk(KERN_WARNING "hvc: error opening to primary %d\n", rc);
-
-	if (viopath_hostLp == HvLpIndexInvalid)
-		vio_set_hostlp();
-
-	/*
-	 * And if the primary is not the same as the hosting LP, open to the
-	 * hosting lp
-	 */
-	if ((viopath_hostLp != HvLpIndexInvalid) &&
-	    (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) {
-		printk(KERN_INFO "hvc: open path to hosting (%d)\n",
-				viopath_hostLp);
-		rc = viopath_open(viopath_hostLp, viomajorsubtype_chario,
-				VIOCHAR_WINDOW + 2);	/* +2 for fudge */
-		if (rc)
-			printk(KERN_WARNING
-				"error opening to partition %d: %d\n",
-				viopath_hostLp, rc);
-	}
-
-	if (vio_setHandler(viomajorsubtype_chario, hvc_handle_event) < 0)
-		printk(KERN_WARNING
-			"hvc: error seting handler for console events!\n");
-
-	/*
-	 * First, try to open the console to the hosting lp.
-	 * Wait on a semaphore for the response.
-	 */
-	atomic_set(&wait_flag, 0);
-	if ((viopath_isactive(viopath_hostLp)) &&
-	    (send_open(viopath_hostLp, &wait_flag) == 0)) {
-		printk(KERN_INFO "hvc: hosting partition %d\n", viopath_hostLp);
-		while (atomic_read(&wait_flag) == 0)
-			mb();
-		atomic_set(&wait_flag, 0);
-	}
-
-	/*
-	 * If we don't have an active console, try the primary
-	 */
-	if ((!viopath_isactive(port_info[0].lp)) &&
-	    (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) &&
-	    (send_open(HvLpConfig_getPrimaryLpIndex(), &wait_flag) == 0)) {
-		printk(KERN_INFO "hvc: opening console to primary partition\n");
-		while (atomic_read(&wait_flag) == 0)
-			mb();
-	}
-
-	/* Register as a vio device to receive callbacks */
-	rc = vio_register_driver(&hvc_vio_driver);
-
-	return rc;
-}
-module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
-
-static void __exit hvc_vio_exit(void)
-{
-	vio_unregister_driver(&hvc_vio_driver);
-}
-module_exit(hvc_vio_exit);
-
-/* the device tree order defines our numbering */
-static int __init hvc_find_vtys(void)
-{
-	struct device_node *vty;
-	int num_found = 0;
-
-	for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
-			vty = of_find_node_by_name(vty, "vty")) {
-		const uint32_t *vtermno;
-
-		/* We have statically defined space for only a certain number
-		 * of console adapters.
-		 */
-		if ((num_found >= MAX_NR_HVC_CONSOLES) ||
-				(num_found >= VTTY_PORTS)) {
-			of_node_put(vty);
-			break;
-		}
-
-		vtermno = of_get_property(vty, "reg", NULL);
-		if (!vtermno)
-			continue;
-
-		if (!of_device_is_compatible(vty, "IBM,iSeries-vty"))
-			continue;
-
-		if (num_found == 0)
-			add_preferred_console("hvc", 0, NULL);
-		hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops);
-		++num_found;
-	}
-
-	return num_found;
-}
-console_initcall(hvc_find_vtys);
diff --git a/drivers/tty/hvc/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c
index 4c9b13e..7222827 100644
--- a/drivers/tty/hvc/hvc_udbg.c
+++ b/drivers/tty/hvc/hvc_udbg.c
@@ -36,7 +36,7 @@
 {
 	int i;
 
-	for (i = 0; i < count; i++)
+	for (i = 0; i < count && udbg_putc; i++)
 		udbg_putc(buf[i]);
 
 	return i;
@@ -67,6 +67,9 @@
 {
 	struct hvc_struct *hp;
 
+	if (!udbg_putc)
+		return -ENODEV;
+
 	BUG_ON(hvc_udbg_dev);
 
 	hp = hvc_alloc(0, 0, &hvc_udbg_ops, 16);
@@ -88,6 +91,9 @@
 
 static int __init hvc_udbg_console_init(void)
 {
+	if (!udbg_putc)
+		return -ENODEV;
+
 	hvc_instantiate(0, 0, &hvc_udbg_ops);
 	add_preferred_console("hvc", 0, NULL);
 
diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c
index fc3c3ad..ee30779 100644
--- a/drivers/tty/hvc/hvc_vio.c
+++ b/drivers/tty/hvc/hvc_vio.c
@@ -46,7 +46,6 @@
 #include <asm/hvconsole.h>
 #include <asm/vio.h>
 #include <asm/prom.h>
-#include <asm/firmware.h>
 #include <asm/hvsi.h>
 #include <asm/udbg.h>
 
@@ -311,20 +310,14 @@
 static struct vio_driver hvc_vio_driver = {
 	.id_table	= hvc_driver_table,
 	.probe		= hvc_vio_probe,
-	.remove		= __devexit_p(hvc_vio_remove),
-	.driver		= {
-		.name	= hvc_driver_name,
-		.owner	= THIS_MODULE,
-	}
+	.remove		= hvc_vio_remove,
+	.name		= hvc_driver_name,
 };
 
 static int __init hvc_vio_init(void)
 {
 	int rc;
 
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		return -EIO;
-
 	/* Register as a vio device to receive callbacks */
 	rc = vio_register_driver(&hvc_vio_driver);
 
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index a1b0a75..83d5c88 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -23,44 +23,74 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/list.h>
 
+#include <asm/io.h>
 #include <asm/xen/hypervisor.h>
 
 #include <xen/xen.h>
+#include <xen/interface/xen.h>
+#include <xen/hvm.h>
+#include <xen/grant_table.h>
 #include <xen/page.h>
 #include <xen/events.h>
 #include <xen/interface/io/console.h>
 #include <xen/hvc-console.h>
+#include <xen/xenbus.h>
 
 #include "hvc_console.h"
 
 #define HVC_COOKIE   0x58656e /* "Xen" in hex */
 
-static struct hvc_struct *hvc;
-static int xencons_irq;
+struct xencons_info {
+	struct list_head list;
+	struct xenbus_device *xbdev;
+	struct xencons_interface *intf;
+	unsigned int evtchn;
+	struct hvc_struct *hvc;
+	int irq;
+	int vtermno;
+	grant_ref_t gntref;
+};
+
+static LIST_HEAD(xenconsoles);
+static DEFINE_SPINLOCK(xencons_lock);
 
 /* ------------------------------------------------------------------ */
 
-static unsigned long console_pfn = ~0ul;
-
-static inline struct xencons_interface *xencons_interface(void)
+static struct xencons_info *vtermno_to_xencons(int vtermno)
 {
-	if (console_pfn == ~0ul)
-		return mfn_to_virt(xen_start_info->console.domU.mfn);
-	else
-		return __va(console_pfn << PAGE_SHIFT);
+	struct xencons_info *entry, *n, *ret = NULL;
+
+	if (list_empty(&xenconsoles))
+			return NULL;
+
+	list_for_each_entry_safe(entry, n, &xenconsoles, list) {
+		if (entry->vtermno == vtermno) {
+			ret  = entry;
+			break;
+		}
+	}
+
+	return ret;
 }
 
-static inline void notify_daemon(void)
+static inline int xenbus_devid_to_vtermno(int devid)
+{
+	return devid + HVC_COOKIE;
+}
+
+static inline void notify_daemon(struct xencons_info *cons)
 {
 	/* Use evtchn: this is called early, before irq is set up. */
-	notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
+	notify_remote_via_evtchn(cons->evtchn);
 }
 
-static int __write_console(const char *data, int len)
+static int __write_console(struct xencons_info *xencons,
+		const char *data, int len)
 {
-	struct xencons_interface *intf = xencons_interface();
 	XENCONS_RING_IDX cons, prod;
+	struct xencons_interface *intf = xencons->intf;
 	int sent = 0;
 
 	cons = intf->out_cons;
@@ -75,13 +105,16 @@
 	intf->out_prod = prod;
 
 	if (sent)
-		notify_daemon();
+		notify_daemon(xencons);
 	return sent;
 }
 
 static int domU_write_console(uint32_t vtermno, const char *data, int len)
 {
 	int ret = len;
+	struct xencons_info *cons = vtermno_to_xencons(vtermno);
+	if (cons == NULL)
+		return -EINVAL;
 
 	/*
 	 * Make sure the whole buffer is emitted, polling if
@@ -90,7 +123,7 @@
 	 * kernel is crippled.
 	 */
 	while (len) {
-		int sent = __write_console(data, len);
+		int sent = __write_console(cons, data, len);
 		
 		data += sent;
 		len -= sent;
@@ -104,9 +137,13 @@
 
 static int domU_read_console(uint32_t vtermno, char *buf, int len)
 {
-	struct xencons_interface *intf = xencons_interface();
+	struct xencons_interface *intf;
 	XENCONS_RING_IDX cons, prod;
 	int recv = 0;
+	struct xencons_info *xencons = vtermno_to_xencons(vtermno);
+	if (xencons == NULL)
+		return -EINVAL;
+	intf = xencons->intf;
 
 	cons = intf->in_cons;
 	prod = intf->in_prod;
@@ -119,7 +156,7 @@
 	mb();			/* read ring before consuming */
 	intf->in_cons = cons;
 
-	notify_daemon();
+	notify_daemon(xencons);
 	return recv;
 }
 
@@ -157,68 +194,407 @@
 	.notifier_hangup = notifier_hangup_irq,
 };
 
-static int __init xen_hvc_init(void)
+static int xen_hvm_console_init(void)
 {
-	struct hvc_struct *hp;
-	struct hv_ops *ops;
+	int r;
+	uint64_t v = 0;
+	unsigned long mfn;
+	struct xencons_info *info;
+
+	if (!xen_hvm_domain())
+		return -ENODEV;
+
+	info = vtermno_to_xencons(HVC_COOKIE);
+	if (!info) {
+		info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+		if (!info)
+			return -ENOMEM;
+	}
+
+	/* already configured */
+	if (info->intf != NULL)
+		return 0;
+
+	r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);
+	if (r < 0) {
+		kfree(info);
+		return -ENODEV;
+	}
+	info->evtchn = v;
+	hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v);
+	if (r < 0) {
+		kfree(info);
+		return -ENODEV;
+	}
+	mfn = v;
+	info->intf = ioremap(mfn << PAGE_SHIFT, PAGE_SIZE);
+	if (info->intf == NULL) {
+		kfree(info);
+		return -ENODEV;
+	}
+	info->vtermno = HVC_COOKIE;
+
+	spin_lock(&xencons_lock);
+	list_add_tail(&info->list, &xenconsoles);
+	spin_unlock(&xencons_lock);
+
+	return 0;
+}
+
+static int xen_pv_console_init(void)
+{
+	struct xencons_info *info;
 
 	if (!xen_pv_domain())
 		return -ENODEV;
 
-	if (xen_initial_domain()) {
-		ops = &dom0_hvc_ops;
-		xencons_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0);
-	} else {
-		if (!xen_start_info->console.domU.evtchn)
-			return -ENODEV;
+	if (!xen_start_info->console.domU.evtchn)
+		return -ENODEV;
 
-		ops = &domU_hvc_ops;
-		xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
+	info = vtermno_to_xencons(HVC_COOKIE);
+	if (!info) {
+		info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+		if (!info)
+			return -ENOMEM;
 	}
-	if (xencons_irq < 0)
-		xencons_irq = 0;
-	else
-		irq_set_noprobe(xencons_irq);
 
-	hp = hvc_alloc(HVC_COOKIE, xencons_irq, ops, 256);
-	if (IS_ERR(hp))
-		return PTR_ERR(hp);
+	/* already configured */
+	if (info->intf != NULL)
+		return 0;
 
-	hvc = hp;
+	info->evtchn = xen_start_info->console.domU.evtchn;
+	info->intf = mfn_to_virt(xen_start_info->console.domU.mfn);
+	info->vtermno = HVC_COOKIE;
 
-	console_pfn = mfn_to_pfn(xen_start_info->console.domU.mfn);
+	spin_lock(&xencons_lock);
+	list_add_tail(&info->list, &xenconsoles);
+	spin_unlock(&xencons_lock);
+
+	return 0;
+}
+
+static int xen_initial_domain_console_init(void)
+{
+	struct xencons_info *info;
+
+	if (!xen_initial_domain())
+		return -ENODEV;
+
+	info = vtermno_to_xencons(HVC_COOKIE);
+	if (!info) {
+		info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+		if (!info)
+			return -ENOMEM;
+	}
+
+	info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0);
+	info->vtermno = HVC_COOKIE;
+
+	spin_lock(&xencons_lock);
+	list_add_tail(&info->list, &xenconsoles);
+	spin_unlock(&xencons_lock);
 
 	return 0;
 }
 
 void xen_console_resume(void)
 {
-	if (xencons_irq)
-		rebind_evtchn_irq(xen_start_info->console.domU.evtchn, xencons_irq);
+	struct xencons_info *info = vtermno_to_xencons(HVC_COOKIE);
+	if (info != NULL && info->irq)
+		rebind_evtchn_irq(info->evtchn, info->irq);
+}
+
+static void xencons_disconnect_backend(struct xencons_info *info)
+{
+	if (info->irq > 0)
+		unbind_from_irqhandler(info->irq, NULL);
+	info->irq = 0;
+	if (info->evtchn > 0)
+		xenbus_free_evtchn(info->xbdev, info->evtchn);
+	info->evtchn = 0;
+	if (info->gntref > 0)
+		gnttab_free_grant_references(info->gntref);
+	info->gntref = 0;
+	if (info->hvc != NULL)
+		hvc_remove(info->hvc);
+	info->hvc = NULL;
+}
+
+static void xencons_free(struct xencons_info *info)
+{
+	free_page((unsigned long)info->intf);
+	info->intf = NULL;
+	info->vtermno = 0;
+	kfree(info);
+}
+
+static int xen_console_remove(struct xencons_info *info)
+{
+	xencons_disconnect_backend(info);
+	spin_lock(&xencons_lock);
+	list_del(&info->list);
+	spin_unlock(&xencons_lock);
+	if (info->xbdev != NULL)
+		xencons_free(info);
+	else {
+		if (xen_hvm_domain())
+			iounmap(info->intf);
+		kfree(info);
+	}
+	return 0;
+}
+
+#ifdef CONFIG_HVC_XEN_FRONTEND
+static struct xenbus_driver xencons_driver;
+
+static int xencons_remove(struct xenbus_device *dev)
+{
+	return xen_console_remove(dev_get_drvdata(&dev->dev));
+}
+
+static int xencons_connect_backend(struct xenbus_device *dev,
+				  struct xencons_info *info)
+{
+	int ret, evtchn, devid, ref, irq;
+	struct xenbus_transaction xbt;
+	grant_ref_t gref_head;
+	unsigned long mfn;
+
+	ret = xenbus_alloc_evtchn(dev, &evtchn);
+	if (ret)
+		return ret;
+	info->evtchn = evtchn;
+	irq = bind_evtchn_to_irq(evtchn);
+	if (irq < 0)
+		return irq;
+	info->irq = irq;
+	devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
+	info->hvc = hvc_alloc(xenbus_devid_to_vtermno(devid),
+			irq, &domU_hvc_ops, 256);
+	if (IS_ERR(info->hvc))
+		return PTR_ERR(info->hvc);
+	if (xen_pv_domain())
+		mfn = virt_to_mfn(info->intf);
+	else
+		mfn = __pa(info->intf) >> PAGE_SHIFT;
+	ret = gnttab_alloc_grant_references(1, &gref_head);
+	if (ret < 0)
+		return ret;
+	info->gntref = gref_head;
+	ref = gnttab_claim_grant_reference(&gref_head);
+	if (ref < 0)
+		return ref;
+	gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id,
+			mfn, 0);
+
+ again:
+	ret = xenbus_transaction_start(&xbt);
+	if (ret) {
+		xenbus_dev_fatal(dev, ret, "starting transaction");
+		return ret;
+	}
+	ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", ref);
+	if (ret)
+		goto error_xenbus;
+	ret = xenbus_printf(xbt, dev->nodename, "port", "%u",
+			    evtchn);
+	if (ret)
+		goto error_xenbus;
+	ret = xenbus_printf(xbt, dev->nodename, "type", "ioemu");
+	if (ret)
+		goto error_xenbus;
+	ret = xenbus_transaction_end(xbt, 0);
+	if (ret) {
+		if (ret == -EAGAIN)
+			goto again;
+		xenbus_dev_fatal(dev, ret, "completing transaction");
+		return ret;
+	}
+
+	xenbus_switch_state(dev, XenbusStateInitialised);
+	return 0;
+
+ error_xenbus:
+	xenbus_transaction_end(xbt, 1);
+	xenbus_dev_fatal(dev, ret, "writing xenstore");
+	return ret;
+}
+
+static int __devinit xencons_probe(struct xenbus_device *dev,
+				  const struct xenbus_device_id *id)
+{
+	int ret, devid;
+	struct xencons_info *info;
+
+	devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
+	if (devid == 0)
+		return -ENODEV;
+
+	info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+	if (!info)
+		goto error_nomem;
+	dev_set_drvdata(&dev->dev, info);
+	info->xbdev = dev;
+	info->vtermno = xenbus_devid_to_vtermno(devid);
+	info->intf = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
+	if (!info->intf)
+		goto error_nomem;
+
+	ret = xencons_connect_backend(dev, info);
+	if (ret < 0)
+		goto error;
+	spin_lock(&xencons_lock);
+	list_add_tail(&info->list, &xenconsoles);
+	spin_unlock(&xencons_lock);
+
+	return 0;
+
+ error_nomem:
+	ret = -ENOMEM;
+	xenbus_dev_fatal(dev, ret, "allocating device memory");
+ error:
+	xencons_disconnect_backend(info);
+	xencons_free(info);
+	return ret;
+}
+
+static int xencons_resume(struct xenbus_device *dev)
+{
+	struct xencons_info *info = dev_get_drvdata(&dev->dev);
+
+	xencons_disconnect_backend(info);
+	memset(info->intf, 0, PAGE_SIZE);
+	return xencons_connect_backend(dev, info);
+}
+
+static void xencons_backend_changed(struct xenbus_device *dev,
+				   enum xenbus_state backend_state)
+{
+	switch (backend_state) {
+	case XenbusStateReconfiguring:
+	case XenbusStateReconfigured:
+	case XenbusStateInitialising:
+	case XenbusStateInitialised:
+	case XenbusStateUnknown:
+	case XenbusStateClosed:
+		break;
+
+	case XenbusStateInitWait:
+		break;
+
+	case XenbusStateConnected:
+		xenbus_switch_state(dev, XenbusStateConnected);
+		break;
+
+	case XenbusStateClosing:
+		xenbus_frontend_closed(dev);
+		break;
+	}
+}
+
+static const struct xenbus_device_id xencons_ids[] = {
+	{ "console" },
+	{ "" }
+};
+
+
+static DEFINE_XENBUS_DRIVER(xencons, "xenconsole",
+	.probe = xencons_probe,
+	.remove = xencons_remove,
+	.resume = xencons_resume,
+	.otherend_changed = xencons_backend_changed,
+);
+#endif /* CONFIG_HVC_XEN_FRONTEND */
+
+static int __init xen_hvc_init(void)
+{
+	int r;
+	struct xencons_info *info;
+	const struct hv_ops *ops;
+
+	if (!xen_domain())
+		return -ENODEV;
+
+	if (xen_initial_domain()) {
+		ops = &dom0_hvc_ops;
+		r = xen_initial_domain_console_init();
+		if (r < 0)
+			return r;
+		info = vtermno_to_xencons(HVC_COOKIE);
+	} else {
+		ops = &domU_hvc_ops;
+		if (xen_hvm_domain())
+			r = xen_hvm_console_init();
+		else
+			r = xen_pv_console_init();
+		if (r < 0)
+			return r;
+
+		info = vtermno_to_xencons(HVC_COOKIE);
+		info->irq = bind_evtchn_to_irq(info->evtchn);
+	}
+	if (info->irq < 0)
+		info->irq = 0; /* NO_IRQ */
+	else
+		irq_set_noprobe(info->irq);
+
+	info->hvc = hvc_alloc(HVC_COOKIE, info->irq, ops, 256);
+	if (IS_ERR(info->hvc)) {
+		r = PTR_ERR(info->hvc);
+		spin_lock(&xencons_lock);
+		list_del(&info->list);
+		spin_unlock(&xencons_lock);
+		if (info->irq)
+			unbind_from_irqhandler(info->irq, NULL);
+		kfree(info);
+		return r;
+	}
+
+	r = 0;
+#ifdef CONFIG_HVC_XEN_FRONTEND
+	r = xenbus_register_frontend(&xencons_driver);
+#endif
+	return r;
 }
 
 static void __exit xen_hvc_fini(void)
 {
-	if (hvc)
-		hvc_remove(hvc);
+	struct xencons_info *entry, *next;
+
+	if (list_empty(&xenconsoles))
+			return;
+
+	list_for_each_entry_safe(entry, next, &xenconsoles, list) {
+		xen_console_remove(entry);
+	}
 }
 
 static int xen_cons_init(void)
 {
-	struct hv_ops *ops;
+	const struct hv_ops *ops;
 
-	if (!xen_pv_domain())
+	if (!xen_domain())
 		return 0;
 
 	if (xen_initial_domain())
 		ops = &dom0_hvc_ops;
-	else
+	else {
+		int r;
 		ops = &domU_hvc_ops;
 
+		if (xen_hvm_domain())
+			r = xen_hvm_console_init();
+		else
+			r = xen_pv_console_init();
+		if (r < 0)
+			return r;
+	}
+
 	hvc_instantiate(HVC_COOKIE, 0, ops);
 	return 0;
 }
 
+
 module_init(xen_hvc_init);
 module_exit(xen_hvc_fini);
 console_initcall(xen_cons_init);
@@ -230,6 +606,9 @@
 	unsigned int linelen, off = 0;
 	const char *pos;
 
+	if (!xen_pv_domain())
+		return;
+
 	dom0_write_console(0, string, len);
 
 	if (xen_initial_domain())
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index d237591..3436436 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -879,10 +879,7 @@
 	.id_table	= hvcs_driver_table,
 	.probe		= hvcs_probe,
 	.remove		= __devexit_p(hvcs_remove),
-	.driver		= {
-		.name	= hvcs_driver_name,
-		.owner	= THIS_MODULE,
-	}
+	.name		= hvcs_driver_name,
 };
 
 /* Only called from hvcs_get_pi please */
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c
index 03c1497..e1235ac 100644
--- a/drivers/tty/isicom.c
+++ b/drivers/tty/isicom.c
@@ -102,7 +102,7 @@
  *	You can find the original tools for this direct from Multitech
  *		ftp://ftp.multitech.com/ISI-Cards/
  *
- *	Having installed the cards the module options (/etc/modprobe.conf)
+ *	Having installed the cards the module options (/etc/modprobe.d/)
  *
  *	options isicom   io=card1,card2,card3,card4 irq=card1,card2,card3,card4
  *
@@ -133,7 +133,6 @@
 
 #include <linux/uaccess.h>
 #include <linux/io.h>
-#include <asm/system.h>
 
 #include <linux/pci.h>
 
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 8a8d044..324467d2 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -46,7 +46,6 @@
 #include <linux/slab.h>
 #include <linux/ratelimit.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 17ff377..c6f372d 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -41,7 +41,6 @@
 #include <linux/slab.h>
 #include <linux/ratelimit.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index a09ce3e..1b2db9a 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -102,7 +102,6 @@
 #include <linux/if.h>
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 #include <asm/termios.h>
 #include <asm/uaccess.h>
 
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index d2256d0..94b6eda 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -50,7 +50,6 @@
 #include <linux/uaccess.h>
 #include <linux/module.h>
 
-#include <asm/system.h>
 
 /* number of characters left in xmit buffer before select has we have room */
 #define WAKEUP_CHARS 256
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index f96ecae..eeae7fa 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -27,7 +27,6 @@
 #include <linux/devpts_fs.h>
 #include <linux/slab.h>
 
-#include <asm/system.h>
 
 #ifdef CONFIG_UNIX98_PTYS
 static struct tty_driver *ptm_driver;
diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c
index f899996..a44345a 100644
--- a/drivers/tty/serial/21285.c
+++ b/drivers/tty/serial/21285.c
@@ -16,6 +16,7 @@
 
 #include <asm/irq.h>
 #include <asm/mach-types.h>
+#include <asm/system_info.h>
 #include <asm/hardware/dec21285.h>
 #include <mach/hardware.h>
 
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index 7398390..5ce78252 100644
--- a/drivers/tty/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
@@ -39,7 +39,6 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/delay.h>
 #include <asm/uaccess.h>
 
diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c
index 8609060..29b695d 100644
--- a/drivers/tty/serial/8250/serial_cs.c
+++ b/drivers/tty/serial/8250/serial_cs.c
@@ -43,7 +43,6 @@
 #include <linux/delay.h>
 #include <linux/major.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 76e7764..665beb6 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -853,7 +853,7 @@
 
 config SERIAL_ICOM
 	tristate "IBM Multiport Serial Adapter"
-	depends on PCI && (PPC_ISERIES || PPC_PSERIES)
+	depends on PCI && PPC_PSERIES
 	select SERIAL_CORE
 	select FW_LOADER
 	help
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 20d795d..0c65c9e 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -51,6 +51,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/scatterlist.h>
 #include <linux/delay.h>
+#include <linux/types.h>
 
 #include <asm/io.h>
 #include <asm/sizes.h>
@@ -271,6 +272,7 @@
 		.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
 		.direction = DMA_MEM_TO_DEV,
 		.dst_maxburst = uap->fifosize >> 1,
+		.device_fc = false,
 	};
 	struct dma_chan *chan;
 	dma_cap_mask_t mask;
@@ -304,6 +306,7 @@
 			.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
 			.direction = DMA_DEV_TO_MEM,
 			.src_maxburst = uap->fifosize >> 1,
+			.device_fc = false,
 		};
 
 		chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
@@ -481,7 +484,7 @@
 		return -EBUSY;
 	}
 
-	desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_MEM_TO_DEV,
+	desc = dmaengine_prep_slave_sg(chan, &dmatx->sg, 1, DMA_MEM_TO_DEV,
 					     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc) {
 		dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE);
@@ -664,7 +667,6 @@
 static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
 {
 	struct dma_chan *rxchan = uap->dmarx.chan;
-	struct dma_device *dma_dev;
 	struct pl011_dmarx_data *dmarx = &uap->dmarx;
 	struct dma_async_tx_descriptor *desc;
 	struct pl011_sgbuf *sgbuf;
@@ -675,8 +677,7 @@
 	/* Start the RX DMA job */
 	sgbuf = uap->dmarx.use_buf_b ?
 		&uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
-	dma_dev = rxchan->device;
-	desc = rxchan->device->device_prep_slave_sg(rxchan, &sgbuf->sg, 1,
+	desc = dmaengine_prep_slave_sg(rxchan, &sgbuf->sg, 1,
 					DMA_DEV_TO_MEM,
 					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	/*
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 10605ec..f9a6be7 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -1526,6 +1526,8 @@
 	atmel_pops.set_wake	= fns->set_wake;
 }
 
+struct platform_device *atmel_default_console_device;	/* the serial console device */
+
 #ifdef CONFIG_SERIAL_ATMEL_CONSOLE
 static void atmel_console_putchar(struct uart_port *port, int ch)
 {
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 23d7916..5b07c0c 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -34,9 +34,9 @@
 
 #include <asm/irq.h>
 #include <asm/dma.h>
-#include <asm/system.h>
 
 #include <arch/svinto.h>
+#include <arch/system.h>
 
 /* non-arch dependent serial structures are in linux/serial.h */
 #include <linux/serial.h>
diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c
index e3699a8..6491b86 100644
--- a/drivers/tty/serial/dz.c
+++ b/drivers/tty/serial/dz.c
@@ -52,7 +52,6 @@
 #include <linux/atomic.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <asm/dec/interrupts.h>
 #include <asm/dec/kn01.h>
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index d55709a..defc4e3 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -52,7 +52,6 @@
 #include <linux/firmware.h>
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 0b7fed7..e7fecee 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1508,7 +1508,7 @@
 		ret = PTR_ERR(sport->clk);
 		goto unmap;
 	}
-	clk_enable(sport->clk);
+	clk_prepare_enable(sport->clk);
 
 	sport->port.uartclk = clk_get_rate(sport->clk);
 
@@ -1531,8 +1531,8 @@
 	if (pdata && pdata->exit)
 		pdata->exit(pdev);
 clkput:
+	clk_disable_unprepare(sport->clk);
 	clk_put(sport->clk);
-	clk_disable(sport->clk);
 unmap:
 	iounmap(sport->port.membase);
 free:
@@ -1552,11 +1552,10 @@
 
 	if (sport) {
 		uart_remove_one_port(&imx_reg, &sport->port);
+		clk_disable_unprepare(sport->clk);
 		clk_put(sport->clk);
 	}
 
-	clk_disable(sport->clk);
-
 	if (pdata && pdata->exit)
 		pdata->exit(pdev);
 
diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c
index a9234ba8..c4b50af 100644
--- a/drivers/tty/serial/mfd.c
+++ b/drivers/tty/serial/mfd.c
@@ -127,11 +127,6 @@
 
 #define HSU_REGS_BUFSIZE	1024
 
-static int hsu_show_regs_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
 
 static ssize_t port_show_regs(struct file *file, char __user *user_buf,
 				size_t count, loff_t *ppos)
@@ -231,14 +226,14 @@
 
 static const struct file_operations port_regs_ops = {
 	.owner		= THIS_MODULE,
-	.open		= hsu_show_regs_open,
+	.open		= simple_open,
 	.read		= port_show_regs,
 	.llseek		= default_llseek,
 };
 
 static const struct file_operations dma_regs_ops = {
 	.owner		= THIS_MODULE,
-	.open		= hsu_show_regs_open,
+	.open		= simple_open,
 	.read		= dma_show_regs,
 	.llseek		= default_llseek,
 };
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 5e85e1e..fca13dc 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -50,7 +50,6 @@
 
 #include <linux/atomic.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 
 #include <mach/hardware.h>
 #include <mach/dma.h>
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 332f2eb..08b9962 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -304,11 +304,7 @@
 #ifdef CONFIG_DEBUG_FS
 
 #define PCH_REGS_BUFSIZE	1024
-static int pch_show_regs_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
+
 
 static ssize_t port_show_regs(struct file *file, char __user *user_buf,
 				size_t count, loff_t *ppos)
@@ -362,7 +358,7 @@
 
 static const struct file_operations port_regs_ops = {
 	.owner		= THIS_MODULE,
-	.open		= pch_show_regs_open,
+	.open		= simple_open,
 	.read		= port_show_regs,
 	.llseek		= default_llseek,
 };
@@ -844,7 +840,7 @@
 
 	sg_dma_address(sg) = priv->rx_buf_dma;
 
-	desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx,
+	desc = dmaengine_prep_slave_sg(priv->chan_rx,
 			sg, 1, DMA_DEV_TO_MEM,
 			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 
@@ -1003,7 +999,7 @@
 			sg_dma_len(sg) = size;
 	}
 
-	desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx,
+	desc = dmaengine_prep_slave_sg(priv->chan_tx,
 					priv->sg_tx_p, nent, DMA_MEM_TO_DEV,
 					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc) {
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index e2fd3d8..5847a4b 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -36,6 +36,7 @@
 #include <linux/circ_buf.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
@@ -44,6 +45,8 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 
+#define PXA_NAME_LEN		8
+
 struct uart_pxa_port {
 	struct uart_port        port;
 	unsigned char           ier;
@@ -51,7 +54,7 @@
 	unsigned char           mcr;
 	unsigned int            lsr_break_flag;
 	struct clk		*clk;
-	char			*name;
+	char			name[PXA_NAME_LEN];
 };
 
 static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
@@ -781,6 +784,31 @@
 };
 #endif
 
+static struct of_device_id serial_pxa_dt_ids[] = {
+	{ .compatible = "mrvl,pxa-uart", },
+	{ .compatible = "mrvl,mmp-uart", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, serial_pxa_dt_ids);
+
+static int serial_pxa_probe_dt(struct platform_device *pdev,
+			       struct uart_pxa_port *sport)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	if (!np)
+		return 1;
+
+	ret = of_alias_get_id(np, "serial");
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
+		return ret;
+	}
+	sport->port.line = ret;
+	return 0;
+}
+
 static int serial_pxa_probe(struct platform_device *dev)
 {
 	struct uart_pxa_port *sport;
@@ -808,20 +836,16 @@
 	sport->port.irq = irqres->start;
 	sport->port.fifosize = 64;
 	sport->port.ops = &serial_pxa_pops;
-	sport->port.line = dev->id;
 	sport->port.dev = &dev->dev;
 	sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
 	sport->port.uartclk = clk_get_rate(sport->clk);
 
-	switch (dev->id) {
-	case 0: sport->name = "FFUART"; break;
-	case 1: sport->name = "BTUART"; break;
-	case 2: sport->name = "STUART"; break;
-	case 3: sport->name = "HWUART"; break;
-	default:
-		sport->name = "???";
-		break;
-	}
+	ret = serial_pxa_probe_dt(dev, sport);
+	if (ret > 0)
+		sport->port.line = dev->id;
+	else if (ret < 0)
+		goto err_clk;
+	snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1);
 
 	sport->port.membase = ioremap(mmres->start, resource_size(mmres));
 	if (!sport->port.membase) {
@@ -829,7 +853,7 @@
 		goto err_clk;
 	}
 
-	serial_pxa_ports[dev->id] = sport;
+	serial_pxa_ports[sport->port.line] = sport;
 
 	uart_add_one_port(&serial_pxa_reg, &sport->port);
 	platform_set_drvdata(dev, sport);
@@ -866,6 +890,7 @@
 #ifdef CONFIG_PM
 		.pm	= &serial_pxa_pm_ops,
 #endif
+		.of_match_table = serial_pxa_dt_ids,
 	},
 };
 
diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
index ef7a21a..2ca5959 100644
--- a/drivers/tty/serial/sa1100.c
+++ b/drivers/tty/serial/sa1100.c
@@ -38,6 +38,7 @@
 
 #include <asm/irq.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 #include <asm/mach/serial_sa1100.h>
 
 /* We've been assigned a range on the "Low-density serial ports" major */
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 61b7fd2..bf461cf 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1229,17 +1229,20 @@
 	port->icount.tx += sg_dma_len(&s->sg_tx);
 
 	async_tx_ack(s->desc_tx);
-	s->cookie_tx = -EINVAL;
 	s->desc_tx = NULL;
 
 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 		uart_write_wakeup(port);
 
 	if (!uart_circ_empty(xmit)) {
+		s->cookie_tx = 0;
 		schedule_work(&s->work_tx);
-	} else if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-		u16 ctrl = sci_in(port, SCSCR);
-		sci_out(port, SCSCR, ctrl & ~SCSCR_TIE);
+	} else {
+		s->cookie_tx = -EINVAL;
+		if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+			u16 ctrl = sci_in(port, SCSCR);
+			sci_out(port, SCSCR, ctrl & ~SCSCR_TIE);
+		}
 	}
 
 	spin_unlock_irqrestore(&port->lock, flags);
@@ -1338,7 +1341,7 @@
 		struct scatterlist *sg = &s->sg_rx[i];
 		struct dma_async_tx_descriptor *desc;
 
-		desc = chan->device->device_prep_slave_sg(chan,
+		desc = dmaengine_prep_slave_sg(chan,
 			sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
 
 		if (desc) {
@@ -1453,7 +1456,7 @@
 
 	BUG_ON(!sg_dma_len(sg));
 
-	desc = chan->device->device_prep_slave_sg(chan,
+	desc = dmaengine_prep_slave_sg(chan,
 			sg, s->sg_len_tx, DMA_MEM_TO_DEV,
 			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc) {
@@ -1501,8 +1504,10 @@
 	}
 
 	if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
-	    s->cookie_tx < 0)
+	    s->cookie_tx < 0) {
+		s->cookie_tx = 0;
 		schedule_work(&s->work_tx);
+	}
 #endif
 
 	if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index a60523f..5b3eda2 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -22,7 +22,7 @@
 #include <linux/io.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
-#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/consumer.h>
 
 #include "sirfsoc_uart.h"
 
@@ -673,12 +673,10 @@
 	port->irq = res->start;
 
 	if (sirfport->hw_flow_ctrl) {
-		sirfport->pmx = pinmux_get(&pdev->dev, NULL);
-		ret = IS_ERR(sirfport->pmx);
+		sirfport->p = pinctrl_get_select_default(&pdev->dev);
+		ret = IS_ERR(sirfport->p);
 		if (ret)
-			goto pmx_err;
-
-		pinmux_enable(sirfport->pmx);
+			goto pin_err;
 	}
 
 	port->ops = &sirfsoc_uart_ops;
@@ -695,11 +693,9 @@
 
 port_err:
 	platform_set_drvdata(pdev, NULL);
-	if (sirfport->hw_flow_ctrl) {
-		pinmux_disable(sirfport->pmx);
-		pinmux_put(sirfport->pmx);
-	}
-pmx_err:
+	if (sirfport->hw_flow_ctrl)
+		pinctrl_put(sirfport->p);
+pin_err:
 irq_err:
 	devm_iounmap(&pdev->dev, port->membase);
 err:
@@ -711,10 +707,8 @@
 	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) {
-		pinmux_disable(sirfport->pmx);
-		pinmux_put(sirfport->pmx);
-	}
+	if (sirfport->hw_flow_ctrl)
+		pinctrl_put(sirfport->p);
 	devm_iounmap(&pdev->dev, port->membase);
 	uart_remove_one_port(&sirfsoc_uart_drv, port);
 	return 0;
diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h
index fc64260..6e207fd 100644
--- a/drivers/tty/serial/sirfsoc_uart.h
+++ b/drivers/tty/serial/sirfsoc_uart.h
@@ -162,7 +162,7 @@
 	unsigned char			ms_enabled;
 
 	struct uart_port		port;
-	struct pinmux			*pmx;
+	struct pinctrl			*p;
 };
 
 /* Hardware Flow Control */
diff --git a/drivers/tty/serial/sn_console.c b/drivers/tty/serial/sn_console.c
index 4e1b551..1c6de9f 100644
--- a/drivers/tty/serial/sn_console.c
+++ b/drivers/tty/serial/sn_console.c
@@ -743,6 +743,7 @@
 			spin_lock_irqsave(&port->sc_port.lock, flags);
 			port->sc_port.irq = SGI_UART_VECTOR;
 			port->sc_ops = &intr_ops;
+			irq_set_handler(port->sc_port.irq, handle_level_irq);
 
 			/* turn on receive interrupts */
 			ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index 3ba5d28..505961c 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -23,6 +23,7 @@
 #include <asm/spitfire.h>
 #include <asm/prom.h>
 #include <asm/irq.h>
+#include <asm/setup.h>
 
 #if defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index 62dacd0..f0d93eb 100644
--- a/drivers/tty/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
@@ -37,6 +37,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/prom.h>
+#include <asm/setup.h>
 
 #if defined(CONFIG_SERIAL_SUNSAB_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index d3ca6da..675303b 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -41,6 +41,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/prom.h>
+#include <asm/setup.h>
 
 #if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
index da44158..babd947 100644
--- a/drivers/tty/serial/sunzilog.c
+++ b/drivers/tty/serial/sunzilog.c
@@ -37,6 +37,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/prom.h>
+#include <asm/setup.h>
 
 #if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
@@ -1580,7 +1581,7 @@
 	if (err)
 		goto out_unregister_uart;
 
-	if (!zilog_irq) {
+	if (zilog_irq) {
 		struct uart_sunzilog_port *up = sunzilog_irq_chain;
 		err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
 				  "zs", sunzilog_irq_chain);
@@ -1621,7 +1622,7 @@
 {
 	platform_driver_unregister(&zs_driver);
 
-	if (!zilog_irq) {
+	if (zilog_irq) {
 		struct uart_sunzilog_port *up = sunzilog_irq_chain;
 
 		/* Disable Interrupts */
diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c
index b7455b5..4001eee 100644
--- a/drivers/tty/serial/zs.c
+++ b/drivers/tty/serial/zs.c
@@ -67,7 +67,6 @@
 #include <linux/types.h>
 
 #include <linux/atomic.h>
-#include <asm/system.h>
 
 #include <asm/dec/interrupts.h>
 #include <asm/dec/ioasic_addrs.h>
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 8e518da..593d40a 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -86,7 +86,6 @@
 #include <linux/ioctl.h>
 #include <linux/synclink.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/dma.h>
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index 34b1a3c..aa1debf 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -73,7 +73,6 @@
 #include <linux/hdlc.h>
 #include <linux/synclink.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/dma.h>
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index 4fb6c4b..a3dddc1 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -58,7 +58,6 @@
 #include <linux/delay.h>
 #include <linux/ioctl.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/dma.h>
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index ecb8e22..05728894 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -327,7 +327,7 @@
 		if (is_global_init(p))
 			continue;
 
-		force_sig(sig, p);
+		do_send_sig_info(sig, SEND_SIG_FORCED, p, true);
 	}
 	read_unlock(&tasklist_lock);
 }
@@ -346,7 +346,7 @@
 
 static void moom_callback(struct work_struct *ignored)
 {
-	out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0, NULL);
+	out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0, NULL, true);
 }
 
 static DECLARE_WORK(moom_work, moom_callback);
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index dd8a938..d939bd7 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -97,7 +97,6 @@
 #include <linux/ratelimit.h>
 
 #include <linux/uaccess.h>
-#include <asm/system.h>
 
 #include <linux/kbd_kern.h>
 #include <linux/vt_kern.h>
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 9314d93..a1b9a2f 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -23,7 +23,6 @@
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #undef TTY_DEBUG_WAIT_UNTIL_SENT
 
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 84c4a7d..3bdd4b1 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -99,7 +99,6 @@
 #include <linux/notifier.h>
 #include <linux/device.h>
 #include <linux/io.h>
-#include <asm/system.h>
 #include <linux/uaccess.h>
 #include <linux/kdb.h>
 #include <linux/ctype.h>
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index e4405e0..cbd8f5f 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -16,7 +16,7 @@
 	# ARM:
 	default y if SA1111
 	default y if ARCH_OMAP
-	default y if ARCH_S3C2410
+	default y if ARCH_S3C24XX
 	default y if PXA27x
 	default y if PXA3xx
 	default y if ARCH_EP93XX
@@ -44,7 +44,7 @@
 	default y if PPC_MPC512x
 	default y if ARCH_IXP4XX
 	default y if ARCH_W90X900
-	default y if ARCH_AT91SAM9G45
+	default y if ARCH_AT91
 	default y if ARCH_MXC
 	default y if ARCH_OMAP3
 	default y if ARCH_CNS3XXX
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 9e186f3..d2b9af5 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -50,7 +50,6 @@
 static const struct file_operations default_file_operations;
 static struct vfsmount *usbfs_mount;
 static int usbfs_mount_count;	/* = 0 */
-static int ignore_mount = 0;
 
 static struct dentry *devices_usbfs_dentry;
 static int num_buses;	/* = 0 */
@@ -256,7 +255,7 @@
 	 * i.e. it's a simple_pin_fs from create_special_files,
 	 * then ignore it.
 	 */
-	if (ignore_mount)
+	if (*flags & MS_KERNMOUNT)
 		return 0;
 
 	if (parse_options(sb, data)) {
@@ -429,18 +428,10 @@
 	return retval;
 }
 
-static int default_open (struct inode *inode, struct file *file)
-{
-	if (inode->i_private)
-		file->private_data = inode->i_private;
-
-	return 0;
-}
-
 static const struct file_operations default_file_operations = {
 	.read =		default_read_file,
 	.write =	default_write_file,
-	.open =		default_open,
+	.open =		simple_open,
 	.llseek =	default_file_lseek,
 };
 
@@ -454,7 +445,6 @@
 static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *inode;
-	struct dentry *root;
 
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -462,19 +452,11 @@
 	sb->s_op = &usbfs_ops;
 	sb->s_time_gran = 1;
 	inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0);
-
-	if (!inode) {
-		dbg("%s: could not get inode!",__func__);
-		return -ENOMEM;
-	}
-
-	root = d_alloc_root(inode);
-	if (!root) {
+	sb->s_root = d_make_root(inode);
+	if (!sb->s_root) {
 		dbg("%s: could not get root dentry!",__func__);
-		iput(inode);
 		return -ENOMEM;
 	}
-	sb->s_root = root;
 	return 0;
 }
 
@@ -591,11 +573,6 @@
 	struct dentry *parent;
 	int retval;
 
-	/* the simple_pin_fs calls will call remount with no options
-	 * without this flag that would overwrite the real mount options (if any)
-	 */
-	ignore_mount = 1;
-
 	/* create the devices special file */
 	retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count);
 	if (retval) {
@@ -603,8 +580,6 @@
 		goto exit;
 	}
 
-	ignore_mount = 0;
-
 	parent = usbfs_mount->mnt_root;
 	devices_usbfs_dentry = fs_create_file ("devices",
 					       listmode | S_IFREG, parent,
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index c14a397..2633f75 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -137,7 +137,7 @@
 
 config USB_AT91
 	tristate "Atmel AT91 USB Device Port"
-	depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45
+	depends on ARCH_AT91
 	help
 	   Many Atmel AT91 processors (such as the AT91RM2000) have a
 	   full speed USB Device Port with support for five configurable
@@ -150,7 +150,7 @@
 config USB_ATMEL_USBA
 	tristate "Atmel USBA"
 	select USB_GADGET_DUALSPEED
-	depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
+	depends on AVR32 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
 	help
 	  USBA is the integrated high-speed USB Device controller on
 	  the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
@@ -284,7 +284,7 @@
 
 config USB_S3C2410
 	tristate "S3C2410 USB Device Controller"
-	depends on ARCH_S3C2410
+	depends on ARCH_S3C24XX
 	help
 	  Samsung's S3C2410 is an ARM-4 processor with an integrated
 	  full speed USB 1.1 device controller.  It has 4 configurable
@@ -299,7 +299,7 @@
 
 config USB_S3C_HSUDC
 	tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller"
-	depends on ARCH_S3C2410
+	depends on ARCH_S3C24XX
 	select USB_GADGET_DUALSPEED
 	help
 	  Samsung's S3C2416, S3C2443 and S3C2450 is an ARM9 based SoC
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 2204a4c..7777927 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -54,7 +54,6 @@
 #include <linux/prefetch.h>
 
 #include <asm/byteorder.h>
-#include <asm/system.h>
 #include <asm/unaligned.h>
 
 /* gadget stack */
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 15a8cdb..0c935d7 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -29,17 +29,19 @@
 #include <linux/clk.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include <asm/byteorder.h>
 #include <mach/hardware.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/gpio.h>
 
 #include <mach/board.h>
 #include <mach/cpu.h>
 #include <mach/at91sam9261_matrix.h>
+#include <mach/at91_matrix.h>
 
 #include "at91_udc.h"
 
@@ -910,9 +912,9 @@
 		} else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
 			u32	usbpucr;
 
-			usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
+			usbpucr = at91_matrix_read(AT91_MATRIX_USBPUCR);
 			usbpucr |= AT91_MATRIX_USBPUCR_PUON;
-			at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
+			at91_matrix_write(AT91_MATRIX_USBPUCR, usbpucr);
 		}
 	} else {
 		stop_activity(udc);
@@ -928,9 +930,9 @@
 		} else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
 			u32	usbpucr;
 
-			usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
+			usbpucr = at91_matrix_read(AT91_MATRIX_USBPUCR);
 			usbpucr &= ~AT91_MATRIX_USBPUCR_PUON;
-			at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
+			at91_matrix_write(AT91_MATRIX_USBPUCR, usbpucr);
 		}
 		clk_off(udc);
 	}
@@ -1706,7 +1708,27 @@
 	spin_unlock_irqrestore(&udc->lock, flags);
 }
 
-static int __init at91udc_probe(struct platform_device *pdev)
+static void __devinit at91udc_of_init(struct at91_udc *udc,
+				     struct device_node *np)
+{
+	struct at91_udc_data *board = &udc->board;
+	u32 val;
+	enum of_gpio_flags flags;
+
+	if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0)
+		board->vbus_polled = 1;
+
+	board->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
+						  &flags);
+	board->vbus_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+
+	board->pullup_pin = of_get_named_gpio_flags(np, "atmel,pullup-gpio", 0,
+						  &flags);
+
+	board->pullup_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+}
+
+static int __devinit at91udc_probe(struct platform_device *pdev)
 {
 	struct device	*dev = &pdev->dev;
 	struct at91_udc	*udc;
@@ -1741,7 +1763,11 @@
 	/* init software state */
 	udc = &controller;
 	udc->gadget.dev.parent = dev;
-	udc->board = *(struct at91_udc_data *) dev->platform_data;
+	if (pdev->dev.of_node)
+		at91udc_of_init(udc, pdev->dev.of_node);
+	else
+		memcpy(&udc->board, dev->platform_data,
+		       sizeof(struct at91_udc_data));
 	udc->pdev = pdev;
 	udc->enabled = 0;
 	spin_lock_init(&udc->lock);
@@ -1970,6 +1996,15 @@
 #define	at91udc_resume	NULL
 #endif
 
+#if defined(CONFIG_OF)
+static const struct of_device_id at91_udc_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-udc" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, at91_udc_dt_ids);
+#endif
+
 static struct platform_driver at91_udc_driver = {
 	.remove		= __exit_p(at91udc_remove),
 	.shutdown	= at91udc_shutdown,
@@ -1978,6 +2013,7 @@
 	.driver		= {
 		.name	= (char *) driver_name,
 		.owner	= THIS_MODULE,
+		.of_match_table	= of_match_ptr(at91_udc_dt_ids),
 	},
 };
 
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index 5e10f65..9f98508 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -332,12 +332,12 @@
 
 static void toggle_bias(int is_on)
 {
-	unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR);
+	unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
 
 	if (is_on)
-		at91_sys_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
+		at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
 	else
-		at91_sys_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
+		at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
 }
 
 #else
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index e1cd56c..a6dfd21 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -44,7 +44,6 @@
 #include <asm/byteorder.h>
 #include <linux/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/unaligned.h>
 
 #define DRIVER_DESC	"USB Host+Gadget Emulator"
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index 7f445ec..1cbba70 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1063,13 +1063,9 @@
 				  &simple_dir_operations,
 				  &simple_dir_inode_operations,
 				  &data->perms);
-	if (unlikely(!inode))
+	sb->s_root = d_make_root(inode);
+	if (unlikely(!sb->s_root))
 		goto Enomem;
-	sb->s_root = d_alloc_root(inode);
-	if (unlikely(!sb->s_root)) {
-		iput(inode);
-		goto Enomem;
-	}
 
 	/* EP0 file */
 	if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,
diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c
index 7cdcb63..965a629 100644
--- a/drivers/usb/gadget/f_phonet.c
+++ b/drivers/usb/gadget/f_phonet.c
@@ -345,7 +345,7 @@
 		}
 
 		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
-				skb->len <= 1, req->actual);
+				skb->len <= 1, req->actual, PAGE_SIZE);
 		page = NULL;
 
 		if (req->actual < req->length) { /* Last fragment */
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index b30e21f..5f94e79 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -43,7 +43,6 @@
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/unaligned.h>
 #include <asm/dma.h>
 
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index e1dfd32..e151d6b 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -43,7 +43,6 @@
 #include <asm/byteorder.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/unaligned.h>
 
 
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 4f18a0e..8793f32 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -1571,20 +1571,18 @@
 
 static void destroy_ep_files (struct dev_data *dev)
 {
-	struct list_head	*entry, *tmp;
-
 	DBG (dev, "%s %d\n", __func__, dev->state);
 
 	/* dev->state must prevent interference */
 restart:
 	spin_lock_irq (&dev->lock);
-	list_for_each_safe (entry, tmp, &dev->epfiles) {
+	while (!list_empty(&dev->epfiles)) {
 		struct ep_data	*ep;
 		struct inode	*parent;
 		struct dentry	*dentry;
 
 		/* break link to FS */
-		ep = list_entry (entry, struct ep_data, epfiles);
+		ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles);
 		list_del_init (&ep->epfiles);
 		dentry = ep->dentry;
 		ep->dentry = NULL;
@@ -1607,8 +1605,7 @@
 		dput (dentry);
 		mutex_unlock (&parent->i_mutex);
 
-		/* fds may still be open */
-		goto restart;
+		spin_lock_irq (&dev->lock);
 	}
 	spin_unlock_irq (&dev->lock);
 }
@@ -2061,10 +2058,8 @@
 	if (!inode)
 		goto Enomem;
 	inode->i_op = &simple_dir_inode_operations;
-	if (!(sb->s_root = d_alloc_root (inode))) {
-		iput(inode);
+	if (!(sb->s_root = d_make_root (inode)))
 		goto Enomem;
-	}
 
 	/* the ep0 file is named after the controller we expect;
 	 * user mode code can use it for sanity checks, like we do.
diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c
index edd52d9..f9cedd5 100644
--- a/drivers/usb/gadget/langwell_udc.c
+++ b/drivers/usb/gadget/langwell_udc.c
@@ -32,7 +32,6 @@
 #include <linux/pm.h>
 #include <linux/io.h>
 #include <linux/irq.h>
-#include <asm/system.h>
 #include <asm/unaligned.h>
 
 #include "langwell_udc.h"
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index 19bbe80..a73cf40 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -34,7 +34,6 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/platform_data/mv_usb.h>
-#include <asm/system.h>
 #include <asm/unaligned.h>
 
 #include "mv_udc.h"
diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c
index 01ae56f..43ac748 100644
--- a/drivers/usb/gadget/net2272.c
+++ b/drivers/usb/gadget/net2272.c
@@ -42,7 +42,6 @@
 #include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
-#include <asm/system.h>
 #include <asm/unaligned.h>
 
 #include "net2272.h"
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index a5ccabc..ac335af 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -59,7 +59,6 @@
 #include <asm/byteorder.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/unaligned.h>
 
 
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index b44830d..3b4b6dd 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -40,7 +40,6 @@
 #include <asm/byteorder.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/unaligned.h>
 #include <asm/mach-types.h>
 
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index d83134b..4e4dc1f 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -34,7 +34,6 @@
 #include <asm/byteorder.h>
 #include <linux/io.h>
 #include <linux/irq.h>
-#include <asm/system.h>
 #include <linux/uaccess.h>
 #include <asm/unaligned.h>
 
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index 1b33634..41ed69c 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -41,7 +41,6 @@
 #include <asm/byteorder.h>
 #include <asm/dma.h>
 #include <asm/gpio.h>
-#include <asm/system.h>
 #include <asm/mach-types.h>
 #include <asm/unaligned.h>
 
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index d3cdffe..73a934a 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -34,7 +34,6 @@
 
 #include <asm/io.h>
 #include <asm/byteorder.h>
-#include <asm/system.h>
 #include <asm/unaligned.h>
 
 
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index ab9c65e..195524c 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -37,7 +37,6 @@
 #include <asm/byteorder.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/unaligned.h>
 #include <mach/irqs.h>
 
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index a5a3ef1..cf14c95 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -13,6 +13,8 @@
 
 #include <linux/clk.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 /* interface and function clocks */
 static struct clk *iclk, *fclk;
@@ -115,6 +117,8 @@
 	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
 };
 
+static u64 at91_ehci_dma_mask = DMA_BIT_MASK(32);
+
 static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd;
@@ -137,6 +141,13 @@
 		goto fail_create_hcd;
 	}
 
+	/* Right now device-tree probed devices don't get dma_mask set.
+	 * Since shared usb code relies on it, set it here for now.
+	 * Once we have dma capability bindings this can go away.
+	 */
+	if (!pdev->dev.dma_mask)
+		pdev->dev.dma_mask = &at91_ehci_dma_mask;
+
 	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
 	if (!hcd) {
 		retval = -ENOMEM;
@@ -225,9 +236,21 @@
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_ehci_dt_ids[] = {
+	{ .compatible = "atmel,at91sam9g45-ehci" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
+#endif
+
 static struct platform_driver ehci_atmel_driver = {
 	.probe		= ehci_atmel_drv_probe,
 	.remove		= __devexit_p(ehci_atmel_drv_remove),
 	.shutdown	= usb_hcd_platform_shutdown,
-	.driver.name	= "atmel-ehci",
+	.driver		= {
+		.name	= "atmel-ehci",
+		.of_match_table	= of_match_ptr(atmel_ehci_dt_ids),
+	},
 };
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index fd9109d..680e1a3 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -352,7 +352,6 @@
 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 int debug_lpm_open(struct inode *, struct file *);
 static ssize_t debug_lpm_read(struct file *file, char __user *user_buf,
 				   size_t count, loff_t *ppos);
 static ssize_t debug_lpm_write(struct file *file, const char __user *buffer,
@@ -385,7 +384,7 @@
 };
 static const struct file_operations debug_lpm_fops = {
 	.owner		= THIS_MODULE,
-	.open		= debug_lpm_open,
+	.open		= simple_open,
 	.read		= debug_lpm_read,
 	.write		= debug_lpm_write,
 	.release	= debug_lpm_close,
@@ -970,12 +969,6 @@
 	return file->private_data ? 0 : -ENOMEM;
 }
 
-static int debug_lpm_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static int debug_lpm_close(struct inode *inode, struct file *file)
 {
 	return 0;
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index aede637..057cdda 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -45,7 +45,6 @@
 #include <asm/byteorder.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/unaligned.h>
 
 #if defined(CONFIG_PPC_PS3)
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 9248800..9e65e30 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -70,7 +70,6 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/byteorder.h>
 
 #include "isp116x.h"
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index 9e63cdf..2ed112d 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -84,7 +84,6 @@
 #include <linux/prefetch.h>
 
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 77afabc..09f597a 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -14,6 +14,8 @@
 
 #include <linux/clk.h>
 #include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
 
 #include <mach/hardware.h>
 #include <asm/gpio.h>
@@ -25,6 +27,10 @@
 #error "CONFIG_ARCH_AT91 must be defined."
 #endif
 
+#define valid_port(index)	((index) >= 0 && (index) < AT91_MAX_USBH_PORTS)
+#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;
 static int clocked;
@@ -238,26 +244,26 @@
 
 static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable)
 {
-	if (port < 0 || port >= 2)
+	if (!valid_port(port))
 		return;
 
 	if (!gpio_is_valid(pdata->vbus_pin[port]))
 		return;
 
 	gpio_set_value(pdata->vbus_pin[port],
-		       !pdata->vbus_pin_active_low[port] ^ enable);
+		       pdata->vbus_pin_active_low[port] ^ enable);
 }
 
 static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port)
 {
-	if (port < 0 || port >= 2)
+	if (!valid_port(port))
 		return -EINVAL;
 
 	if (!gpio_is_valid(pdata->vbus_pin[port]))
 		return -EINVAL;
 
 	return gpio_get_value(pdata->vbus_pin[port]) ^
-		!pdata->vbus_pin_active_low[port];
+		pdata->vbus_pin_active_low[port];
 }
 
 /*
@@ -269,9 +275,9 @@
 	int length = ohci_hub_status_data(hcd, buf);
 	int port;
 
-	for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) {
+	at91_for_each_port(port) {
 		if (pdata->overcurrent_changed[port]) {
-			if (! length)
+			if (!length)
 				length = 1;
 			buf[0] |= 1 << (port + 1);
 		}
@@ -295,11 +301,17 @@
 		"ohci_at91_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n",
 		hcd, typeReq, wValue, wIndex, buf, wLength);
 
+	wIndex--;
+
 	switch (typeReq) {
 	case SetPortFeature:
 		if (wValue == USB_PORT_FEAT_POWER) {
 			dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n");
-			ohci_at91_usb_set_power(pdata, wIndex - 1, 1);
+			if (valid_port(wIndex)) {
+				ohci_at91_usb_set_power(pdata, wIndex, 1);
+				ret = 0;
+			}
+
 			goto out;
 		}
 		break;
@@ -310,9 +322,9 @@
 			dev_dbg(hcd->self.controller,
 				"ClearPortFeature: C_OVER_CURRENT\n");
 
-			if (wIndex == 1 || wIndex == 2) {
-				pdata->overcurrent_changed[wIndex-1] = 0;
-				pdata->overcurrent_status[wIndex-1] = 0;
+			if (valid_port(wIndex)) {
+				pdata->overcurrent_changed[wIndex] = 0;
+				pdata->overcurrent_status[wIndex] = 0;
 			}
 
 			goto out;
@@ -321,9 +333,8 @@
 			dev_dbg(hcd->self.controller,
 				"ClearPortFeature: OVER_CURRENT\n");
 
-			if (wIndex == 1 || wIndex == 2) {
-				pdata->overcurrent_status[wIndex-1] = 0;
-			}
+			if (valid_port(wIndex))
+				pdata->overcurrent_status[wIndex] = 0;
 
 			goto out;
 
@@ -331,15 +342,15 @@
 			dev_dbg(hcd->self.controller,
 				"ClearPortFeature: POWER\n");
 
-			if (wIndex == 1 || wIndex == 2) {
-				ohci_at91_usb_set_power(pdata, wIndex - 1, 0);
+			if (valid_port(wIndex)) {
+				ohci_at91_usb_set_power(pdata, wIndex, 0);
 				return 0;
 			}
 		}
 		break;
 	}
 
-	ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
+	ret = ohci_hub_control(hcd, typeReq, wValue, wIndex + 1, buf, wLength);
 	if (ret)
 		goto out;
 
@@ -375,18 +386,15 @@
 
 		dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex);
 
-		if (wIndex == 1 || wIndex == 2) {
-			if (! ohci_at91_usb_get_power(pdata, wIndex-1)) {
+		if (valid_port(wIndex)) {
+			if (!ohci_at91_usb_get_power(pdata, wIndex))
 				*data &= ~cpu_to_le32(RH_PS_PPS);
-			}
 
-			if (pdata->overcurrent_changed[wIndex-1]) {
+			if (pdata->overcurrent_changed[wIndex])
 				*data |= cpu_to_le32(RH_PS_OCIC);
-			}
 
-			if (pdata->overcurrent_status[wIndex-1]) {
+			if (pdata->overcurrent_status[wIndex])
 				*data |= cpu_to_le32(RH_PS_POCI);
-			}
 		}
 	}
 
@@ -448,13 +456,14 @@
 
 	/* From the GPIO notifying the over-current situation, find
 	 * out the corresponding port */
-	gpio = irq_to_gpio(irq);
-	for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) {
-		if (pdata->overcurrent_pin[port] == gpio)
+	at91_for_each_port(port) {
+		if (gpio_to_irq(pdata->overcurrent_pin[port]) == irq) {
+			gpio = pdata->overcurrent_pin[port];
 			break;
+		}
 	}
 
-	if (port == ARRAY_SIZE(pdata->overcurrent_pin)) {
+	if (port == AT91_MAX_USBH_PORTS) {
 		dev_err(& pdev->dev, "overcurrent interrupt from unknown GPIO\n");
 		return IRQ_HANDLED;
 	}
@@ -464,7 +473,7 @@
 	/* When notified of an over-current situation, disable power
 	   on the corresponding port, and mark this port in
 	   over-current. */
-	if (! val) {
+	if (!val) {
 		ohci_at91_usb_set_power(pdata, port, 0);
 		pdata->overcurrent_status[port]  = 1;
 		pdata->overcurrent_changed[port] = 1;
@@ -476,34 +485,133 @@
 	return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id at91_ohci_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-ohci" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, at91_ohci_dt_ids);
+
+static u64 at91_ohci_dma_mask = DMA_BIT_MASK(32);
+
+static int __devinit ohci_at91_of_init(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int i, gpio;
+	enum of_gpio_flags flags;
+	struct at91_usbh_data	*pdata;
+	u32 ports;
+
+	if (!np)
+		return 0;
+
+	/* Right now device-tree probed devices don't get dma_mask set.
+	 * Since shared usb code relies on it, set it here for now.
+	 * Once we have dma capability bindings this can go away.
+	 */
+	if (!pdev->dev.dma_mask)
+		pdev->dev.dma_mask = &at91_ohci_dma_mask;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	if (!of_property_read_u32(np, "num-ports", &ports))
+		pdata->ports = ports;
+
+	at91_for_each_port(i) {
+		gpio = of_get_named_gpio_flags(np, "atmel,vbus-gpio", i, &flags);
+		pdata->vbus_pin[i] = gpio;
+		if (!gpio_is_valid(gpio))
+			continue;
+		pdata->vbus_pin_active_low[i] = flags & OF_GPIO_ACTIVE_LOW;
+	}
+
+	at91_for_each_port(i)
+		pdata->overcurrent_pin[i] =
+			of_get_named_gpio_flags(np, "atmel,oc-gpio", i, &flags);
+
+	pdev->dev.platform_data = pdata;
+
+	return 0;
+}
+#else
+static int __devinit ohci_at91_of_init(struct platform_device *pdev)
+{
+	return 0;
+}
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
 {
-	struct at91_usbh_data	*pdata = pdev->dev.platform_data;
+	struct at91_usbh_data	*pdata;
 	int			i;
+	int			gpio;
+	int			ret;
+
+	ret = ohci_at91_of_init(pdev);
+	if (ret)
+		return ret;
+
+	pdata = pdev->dev.platform_data;
 
 	if (pdata) {
-		for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) {
+		at91_for_each_port(i) {
 			if (!gpio_is_valid(pdata->vbus_pin[i]))
 				continue;
-			gpio_request(pdata->vbus_pin[i], "ohci_vbus");
+			gpio = pdata->vbus_pin[i];
+
+			ret = gpio_request(gpio, "ohci_vbus");
+			if (ret) {
+				dev_err(&pdev->dev,
+					"can't request vbus gpio %d\n", gpio);
+				continue;
+			}
+			ret = gpio_direction_output(gpio,
+						!pdata->vbus_pin_active_low[i]);
+			if (ret) {
+				dev_err(&pdev->dev,
+					"can't put vbus gpio %d as output %d\n",
+					gpio, !pdata->vbus_pin_active_low[i]);
+				gpio_free(gpio);
+				continue;
+			}
+
 			ohci_at91_usb_set_power(pdata, i, 1);
 		}
 
-		for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) {
-			int ret;
-
+		at91_for_each_port(i) {
 			if (!gpio_is_valid(pdata->overcurrent_pin[i]))
 				continue;
-			gpio_request(pdata->overcurrent_pin[i], "ohci_overcurrent");
+			gpio = pdata->overcurrent_pin[i];
 
-			ret = request_irq(gpio_to_irq(pdata->overcurrent_pin[i]),
+			ret = gpio_request(gpio, "ohci_overcurrent");
+			if (ret) {
+				dev_err(&pdev->dev,
+					"can't request overcurrent gpio %d\n",
+					gpio);
+				continue;
+			}
+
+			ret = gpio_direction_input(gpio);
+			if (ret) {
+				dev_err(&pdev->dev,
+					"can't configure overcurrent gpio %d as input\n",
+					gpio);
+				gpio_free(gpio);
+				continue;
+			}
+
+			ret = request_irq(gpio_to_irq(gpio),
 					  ohci_hcd_at91_overcurrent_irq,
 					  IRQF_SHARED, "ohci_overcurrent", pdev);
 			if (ret) {
-				gpio_free(pdata->overcurrent_pin[i]);
-				dev_warn(& pdev->dev, "cannot get GPIO IRQ for overcurrent\n");
+				gpio_free(gpio);
+				dev_err(&pdev->dev,
+					"can't get gpio IRQ for overcurrent\n");
 			}
 		}
 	}
@@ -518,14 +626,14 @@
 	int			i;
 
 	if (pdata) {
-		for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) {
+		at91_for_each_port(i) {
 			if (!gpio_is_valid(pdata->vbus_pin[i]))
 				continue;
 			ohci_at91_usb_set_power(pdata, i, 0);
 			gpio_free(pdata->vbus_pin[i]);
 		}
 
-		for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) {
+		at91_for_each_port(i) {
 			if (!gpio_is_valid(pdata->overcurrent_pin[i]))
 				continue;
 			free_irq(gpio_to_irq(pdata->overcurrent_pin[i]), pdev);
@@ -595,5 +703,6 @@
 	.driver		= {
 		.name	= "at91_ohci",
 		.owner	= THIS_MODULE,
+		.of_match_table	= of_match_ptr(at91_ohci_dt_ids),
 	},
 };
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index cd5e382..235171f 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -42,7 +42,6 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 
@@ -1000,7 +999,7 @@
 #define SA1111_DRIVER		ohci_hcd_sa1111_driver
 #endif
 
-#if defined(CONFIG_ARCH_S3C2410) || defined(CONFIG_ARCH_S3C64XX)
+#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S3C64XX)
 #include "ohci-s3c2410.c"
 #define PLATFORM_DRIVER		ohci_hcd_s3c2410_driver
 #endif
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 4bde4f9..e1004fb 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -16,87 +16,37 @@
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <mach/assabet.h>
-#include <mach/badge4.h>
 #include <asm/hardware/sa1111.h>
 
 #ifndef CONFIG_SA1111
 #error "This file is SA-1111 bus glue.  CONFIG_SA1111 must be defined."
 #endif
 
-extern int usb_disabled(void);
+#define USB_STATUS	0x0118
+#define USB_RESET	0x011c
+#define USB_IRQTEST	0x0120
 
-/*-------------------------------------------------------------------------*/
+#define USB_RESET_FORCEIFRESET	(1 << 0)
+#define USB_RESET_FORCEHCRESET	(1 << 1)
+#define USB_RESET_CLKGENRESET	(1 << 2)
+#define USB_RESET_SIMSCALEDOWN	(1 << 3)
+#define USB_RESET_USBINTTEST	(1 << 4)
+#define USB_RESET_SLEEPSTBYEN	(1 << 5)
+#define USB_RESET_PWRSENSELOW	(1 << 6)
+#define USB_RESET_PWRCTRLLOW	(1 << 7)
 
-static void sa1111_start_hc(struct sa1111_dev *dev)
-{
-	unsigned int usb_rst = 0;
-
-	printk(KERN_DEBUG "%s: starting SA-1111 OHCI USB Controller\n",
-	       __FILE__);
-
-#ifdef CONFIG_SA1100_BADGE4
-	if (machine_is_badge4()) {
-		badge4_set_5V(BADGE4_5V_USB, 1);
-	}
-#endif
-
-	if (machine_is_xp860() ||
-	    machine_has_neponset() ||
-	    machine_is_pfs168() ||
-	    machine_is_badge4())
-		usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW;
-
-	/*
-	 * Configure the power sense and control lines.  Place the USB
-	 * host controller in reset.
-	 */
-	sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
-		      dev->mapbase + SA1111_USB_RESET);
-
-	/*
-	 * Now, carefully enable the USB clock, and take
-	 * the USB host controller out of reset.
-	 */
-	sa1111_enable_device(dev);
-	udelay(11);
-	sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET);
-}
-
-static void sa1111_stop_hc(struct sa1111_dev *dev)
-{
-	unsigned int usb_rst;
-	printk(KERN_DEBUG "%s: stopping SA-1111 OHCI USB Controller\n",
-	       __FILE__);
-
-	/*
-	 * Put the USB host controller into reset.
-	 */
-	usb_rst = sa1111_readl(dev->mapbase + SA1111_USB_RESET);
-	sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
-		      dev->mapbase + SA1111_USB_RESET);
-
-	/*
-	 * Stop the USB clock.
-	 */
-	sa1111_disable_device(dev);
-
-#ifdef CONFIG_SA1100_BADGE4
-	if (machine_is_badge4()) {
-		/* Disable power to the USB bus */
-		badge4_set_5V(BADGE4_5V_USB, 0);
-	}
-#endif
-}
-
-
-/*-------------------------------------------------------------------------*/
+#define USB_STATUS_IRQHCIRMTWKUP  (1 <<  7)
+#define USB_STATUS_IRQHCIBUFFACC  (1 <<  8)
+#define USB_STATUS_NIRQHCIM       (1 <<  9)
+#define USB_STATUS_NHCIMFCLR      (1 << 10)
+#define USB_STATUS_USBPWRSENSE    (1 << 11)
 
 #if 0
 static void dump_hci_status(struct usb_hcd *hcd, const char *label)
 {
-	unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS);
+	unsigned long status = sa1111_readl(hcd->regs + USB_STATUS);
 
-	dbg ("%s USB_STATUS = { %s%s%s%s%s}", label,
+	dbg("%s USB_STATUS = { %s%s%s%s%s}", label,
 	     ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
 	     ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
 	     ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
@@ -105,98 +55,27 @@
 }
 #endif
 
-/*-------------------------------------------------------------------------*/
-
-/* configure so an HC device and id are always provided */
-/* always called with process context; sleeping is OK */
-
-
-/**
- * usb_hcd_sa1111_probe - initialize SA-1111-based HCDs
- * Context: !in_interrupt()
- *
- * 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.
- *
- * Store this function in the HCD's struct pci_driver as probe().
- */
-int usb_hcd_sa1111_probe (const struct hc_driver *driver,
-			  struct sa1111_dev *dev)
+static int ohci_sa1111_reset(struct usb_hcd *hcd)
 {
-	struct usb_hcd *hcd;
-	int retval;
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
 
-	hcd = usb_create_hcd (driver, &dev->dev, "sa1111");
-	if (!hcd)
-		return -ENOMEM;
-	hcd->rsrc_start = dev->res.start;
-	hcd->rsrc_len = resource_size(&dev->res);
+	ohci_hcd_init(ohci);
+	return ohci_init(ohci);
+}
 
-	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		dbg("request_mem_region failed");
-		retval = -EBUSY;
-		goto err1;
+static int __devinit ohci_sa1111_start(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
+	int ret;
+
+	ret = ohci_run(ohci);
+	if (ret < 0) {
+		ohci_err(ohci, "can't start\n");
+		ohci_stop(hcd);
 	}
-	hcd->regs = dev->mapbase;
-
-	sa1111_start_hc(dev);
-	ohci_hcd_init(hcd_to_ohci(hcd));
-
-	retval = usb_add_hcd(hcd, dev->irq[1], 0);
-	if (retval == 0)
-		return retval;
-
-	sa1111_stop_hc(dev);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- err1:
-	usb_put_hcd(hcd);
-	return retval;
+	return ret;
 }
 
-
-/* may be called without controller electrically present */
-/* may be called with controller, bus, and devices active */
-
-/**
- * usb_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
- * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
- *
- * Reverses the effect of usb_hcd_sa1111_probe(), first invoking
- * the HCD's stop() method.  It is always called from a thread
- * context, normally "rmmod", "apmd", or something similar.
- *
- */
-void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev)
-{
-	usb_remove_hcd(hcd);
-	sa1111_stop_hc(dev);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-	usb_put_hcd(hcd);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int __devinit
-ohci_sa1111_start (struct usb_hcd *hcd)
-{
-	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
-	int		ret;
-
-	if ((ret = ohci_init(ohci)) < 0)
-		return ret;
-
-	if ((ret = ohci_run (ohci)) < 0) {
-		err ("can't start %s", hcd->self.bus_name);
-		ohci_stop (hcd);
-		return ret;
-	}
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
 static const struct hc_driver ohci_sa1111_hc_driver = {
 	.description =		hcd_name,
 	.product_desc =		"SA-1111 OHCI",
@@ -211,8 +90,10 @@
 	/*
 	 * basic lifecycle operations
 	 */
+	.reset =		ohci_sa1111_reset,
 	.start =		ohci_sa1111_start,
 	.stop =			ohci_stop,
+	.shutdown =		ohci_shutdown,
 
 	/*
 	 * managing i/o requests and associated device resources
@@ -238,33 +119,139 @@
 	.start_port_reset =	ohci_start_port_reset,
 };
 
-/*-------------------------------------------------------------------------*/
-
-static int ohci_hcd_sa1111_drv_probe(struct sa1111_dev *dev)
+static int sa1111_start_hc(struct sa1111_dev *dev)
 {
+	unsigned int usb_rst = 0;
+	int ret;
+
+	dev_dbg(&dev->dev, "starting SA-1111 OHCI USB Controller\n");
+
+	if (machine_is_xp860() ||
+	    machine_has_neponset() ||
+	    machine_is_pfs168() ||
+	    machine_is_badge4())
+		usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW;
+
+	/*
+	 * Configure the power sense and control lines.  Place the USB
+	 * host controller in reset.
+	 */
+	sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
+		      dev->mapbase + USB_RESET);
+
+	/*
+	 * Now, carefully enable the USB clock, and take
+	 * the USB host controller out of reset.
+	 */
+	ret = sa1111_enable_device(dev);
+	if (ret == 0) {
+		udelay(11);
+		sa1111_writel(usb_rst, dev->mapbase + USB_RESET);
+	}
+
+	return ret;
+}
+
+static void sa1111_stop_hc(struct sa1111_dev *dev)
+{
+	unsigned int usb_rst;
+
+	dev_dbg(&dev->dev, "stopping SA-1111 OHCI USB Controller\n");
+
+	/*
+	 * Put the USB host controller into reset.
+	 */
+	usb_rst = sa1111_readl(dev->mapbase + USB_RESET);
+	sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
+		      dev->mapbase + USB_RESET);
+
+	/*
+	 * Stop the USB clock.
+	 */
+	sa1111_disable_device(dev);
+}
+
+/**
+ * ohci_hcd_sa1111_probe - initialize SA-1111-based HCDs
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it.
+ */
+static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev)
+{
+	struct usb_hcd *hcd;
 	int ret;
 
 	if (usb_disabled())
 		return -ENODEV;
 
-	ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, dev);
+	hcd = usb_create_hcd(&ohci_sa1111_hc_driver, &dev->dev, "sa1111");
+	if (!hcd)
+		return -ENOMEM;
+
+	hcd->rsrc_start = dev->res.start;
+	hcd->rsrc_len = resource_size(&dev->res);
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		dbg("request_mem_region failed");
+		ret = -EBUSY;
+		goto err1;
+	}
+
+	hcd->regs = dev->mapbase;
+
+	ret = sa1111_start_hc(dev);
+	if (ret)
+		goto err2;
+
+	ret = usb_add_hcd(hcd, dev->irq[1], 0);
+	if (ret == 0)
+		return ret;
+
+	sa1111_stop_hc(dev);
+ err2:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ err1:
+	usb_put_hcd(hcd);
 	return ret;
 }
 
-static int ohci_hcd_sa1111_drv_remove(struct sa1111_dev *dev)
+/**
+ * ohci_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
+ * @dev: USB Host Controller being removed
+ *
+ * Reverses the effect of ohci_hcd_sa1111_probe(), first invoking
+ * the HCD's stop() method.
+ */
+static int ohci_hcd_sa1111_remove(struct sa1111_dev *dev)
 {
 	struct usb_hcd *hcd = sa1111_get_drvdata(dev);
 
-	usb_hcd_sa1111_remove(hcd, dev);
+	usb_remove_hcd(hcd);
+	sa1111_stop_hc(dev);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+
 	return 0;
 }
 
+static void ohci_hcd_sa1111_shutdown(struct sa1111_dev *dev)
+{
+	struct usb_hcd *hcd = sa1111_get_drvdata(dev);
+
+	if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+		hcd->driver->shutdown(hcd);
+		sa1111_stop_hc(dev);
+	}
+}
+
 static struct sa1111_driver ohci_hcd_sa1111_driver = {
 	.drv = {
 		.name	= "sa1111-ohci",
+		.owner	= THIS_MODULE,
 	},
 	.devid		= SA1111_DEVID_USB,
-	.probe		= ohci_hcd_sa1111_drv_probe,
-	.remove		= ohci_hcd_sa1111_drv_remove,
+	.probe		= ohci_hcd_sa1111_probe,
+	.remove		= ohci_hcd_sa1111_remove,
+	.shutdown	= ohci_hcd_sa1111_shutdown,
 };
-
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index 015c7c6..3b38030 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -40,7 +40,6 @@
 #include <linux/io.h>
 
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/unaligned.h>
 
 #include <linux/irq.h>
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 7732d69..11de5f1 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -893,4 +893,5 @@
 		quirk_usb_handoff_xhci(pdev);
 	pci_disable_device(pdev);
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+			PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff);
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 2a2cce2..91ce1c0 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -51,7 +51,6 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 16dd6a6..dbbd1ba 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -55,7 +55,6 @@
 #include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/byteorder.h>
 
 	/* FIXME ohci.h is ONLY for internal use by the OHCI driver.
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index e37dea8..e4db350 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -45,7 +45,6 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 
 #include "uhci-hcd.h"
 
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index 97cb459..d05c7fb 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -115,12 +115,12 @@
 	slave_conf.dst_addr = usb_fifo_addr;
 	slave_conf.dst_addr_width = addr_width;
 	slave_conf.dst_maxburst = 16;
+	slave_conf.device_fc = false;
 
 	dma_chan->device->device_control(dma_chan, DMA_SLAVE_CONFIG,
 					     (unsigned long) &slave_conf);
 
-	dma_desc = dma_chan->device->
-			device_prep_slave_sg(dma_chan, &sg, 1, direction,
+	dma_desc = dmaengine_prep_slave_sg(dma_chan, &sg, 1, direction,
 					     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!dma_desc)
 		return false;
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 3648c82..6ec7f83 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -786,9 +786,8 @@
 	sg_dma_address(&sg) = pkt->dma + pkt->actual;
 	sg_dma_len(&sg) = pkt->trans;
 
-	desc = chan->device->device_prep_slave_sg(chan, &sg, 1, dir,
-						  DMA_PREP_INTERRUPT |
-						  DMA_CTRL_ACK);
+	desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc)
 		return;
 
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 7c229d3..ff8605b 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1724,7 +1724,8 @@
 
 /*
  * Module parameter to control latency timer for NDI FTDI-based USB devices.
- * If this value is not set in modprobe.conf.local its value will be set to 1ms.
+ * If this value is not set in /etc/modprobe.d/ its value will be set
+ * to 1ms.
  */
 static int ndi_latency_timer = 1;
 
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 6815701..836cfa9 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -903,8 +903,10 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff),
 	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff) },
-	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff),
+	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) },
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index fe2d803..7691c86 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -222,7 +222,7 @@
 	  for usb-storage and ub drivers, and allows to switch binding
 	  of these devices without rebuilding modules.
 
-	  Typical syntax of /etc/modprobe.conf is:
+	  Typical syntax of /etc/modprobe.d/*conf is:
 
 		options libusual bias="ub"
 
diff --git a/drivers/uwb/allocator.c b/drivers/uwb/allocator.c
index e45e673..6e3e713 100644
--- a/drivers/uwb/allocator.c
+++ b/drivers/uwb/allocator.c
@@ -334,10 +334,8 @@
 
 
 	/* fill the not available vector from the available bm */
-	for (bit_index = 0; bit_index < UWB_NUM_MAS; bit_index++) {
-		if (!test_bit(bit_index, available->bm))
-			ai->bm[bit_index] = UWB_RSV_MAS_NOT_AVAIL;
-	}
+	for_each_clear_bit(bit_index, available->bm, UWB_NUM_MAS)
+		ai->bm[bit_index] = UWB_RSV_MAS_NOT_AVAIL;
 
 	if (ai->max_interval == 1) {
 		get_row_descriptors(ai);
diff --git a/drivers/uwb/uwb-debug.c b/drivers/uwb/uwb-debug.c
index 2eecec0..6ec45be 100644
--- a/drivers/uwb/uwb-debug.c
+++ b/drivers/uwb/uwb-debug.c
@@ -159,13 +159,6 @@
 	return uwb_rc_ie_rm(rc, ie_to_rm->data[0]);
 }
 
-static int command_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-
-	return 0;
-}
-
 static ssize_t command_write(struct file *file, const char __user *buf,
 			 size_t len, loff_t *off)
 {
@@ -206,7 +199,7 @@
 }
 
 static const struct file_operations command_fops = {
-	.open   = command_open,
+	.open	= simple_open,
 	.write  = command_write,
 	.read   = NULL,
 	.llseek = no_llseek,
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 9dab1f5..f0da2c3 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -588,7 +588,7 @@
 
 	vhost_net_stop(n, &tx_sock, &rx_sock);
 	vhost_net_flush(n);
-	vhost_dev_cleanup(&n->dev);
+	vhost_dev_cleanup(&n->dev, false);
 	if (tx_sock)
 		fput(tx_sock->file);
 	if (rx_sock)
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index bdb2d64..947f00d 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -222,6 +222,8 @@
 		if (work) {
 			__set_current_state(TASK_RUNNING);
 			work->fn(work);
+			if (need_resched())
+				schedule();
 		} else
 			schedule();
 
@@ -403,7 +405,7 @@
 	if (!memory)
 		return -ENOMEM;
 
-	vhost_dev_cleanup(dev);
+	vhost_dev_cleanup(dev, true);
 
 	memory->nregions = 0;
 	RCU_INIT_POINTER(dev->memory, memory);
@@ -434,8 +436,8 @@
 	return j;
 }
 
-/* Caller should have device mutex */
-void vhost_dev_cleanup(struct vhost_dev *dev)
+/* Caller should have device mutex if and only if locked is set */
+void vhost_dev_cleanup(struct vhost_dev *dev, bool locked)
 {
 	int i;
 
@@ -472,7 +474,8 @@
 	dev->log_file = NULL;
 	/* No one will access memory at this point */
 	kfree(rcu_dereference_protected(dev->memory,
-					lockdep_is_held(&dev->mutex)));
+					locked ==
+						lockdep_is_held(&dev->mutex)));
 	RCU_INIT_POINTER(dev->memory, NULL);
 	WARN_ON(!list_empty(&dev->work_list));
 	if (dev->worker) {
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index a801e28..8dcf4cc 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -163,7 +163,7 @@
 long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue *vqs, int nvqs);
 long vhost_dev_check_owner(struct vhost_dev *);
 long vhost_dev_reset_owner(struct vhost_dev *);
-void vhost_dev_cleanup(struct vhost_dev *);
+void vhost_dev_cleanup(struct vhost_dev *, bool locked);
 long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg);
 int vhost_vq_access_ok(struct vhost_virtqueue *vq);
 int vhost_log_access_ok(struct vhost_dev *);
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 6ca0c40..a290be5 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1123,6 +1123,18 @@
 	help
 	  Say Y here if you want to control the backlight of your display.
 
+config FB_I740
+	tristate "Intel740 support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && FB && PCI
+	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select VGASTATE
+	select FB_DDC
+	help
+	  This driver supports graphics cards based on Intel740 chip.
+
 config FB_I810
 	tristate "Intel 810/815 support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL && FB && PCI && X86_32 && AGP_INTEL
@@ -2001,18 +2013,6 @@
 	---help---
 	  Driver for the on-chip SH-Mobile HDMI controller.
 
-config FB_SH_MOBILE_MERAM
-	tristate "SuperH Mobile MERAM read ahead support for LCDC"
-	depends on FB_SH_MOBILE_LCDC
-	default y
-	---help---
-	  Enable MERAM support for the SH-Mobile LCD controller.
-
-	  This will allow for caching of the framebuffer to provide more
-	  reliable access under heavy main memory bus traffic situations.
-	  Up to 4 memory channels can be configured, allowing 4 RGB or
-	  2 YCbCr framebuffers to be configured.
-
 config FB_TMIO
 	tristate "Toshiba Mobile IO FrameBuffer support"
 	depends on FB && MFD_CORE
@@ -2061,7 +2061,7 @@
 
 config FB_S3C2410
 	tristate "S3C2410 LCD framebuffer support"
-	depends on FB && ARCH_S3C2410
+	depends on FB && ARCH_S3C24XX
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
@@ -2233,6 +2233,7 @@
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
+	select FB_CFB_REV_PIXELS_IN_BYTE
 	---help---
 	  This is the frame buffer device driver for the TI LCD controller
 	  found on DA8xx/OMAP-L1xx SoCs.
@@ -2269,6 +2270,7 @@
 	select FB_SYS_IMAGEBLIT
 	select FB_SYS_FOPS
 	select FB_DEFERRED_IO
+	select INPUT_XEN_KBDDEV_FRONTEND
 	select XEN_XENBUS_FRONTEND
 	default y
 	help
@@ -2411,7 +2413,7 @@
 
 source "drivers/video/omap/Kconfig"
 source "drivers/video/omap2/Kconfig"
-
+source "drivers/video/exynos/Kconfig"
 source "drivers/video/backlight/Kconfig"
 
 if VT
@@ -2422,4 +2424,16 @@
 	source "drivers/video/logo/Kconfig"
 endif
 
+config FB_SH_MOBILE_MERAM
+	tristate "SuperH Mobile MERAM read ahead support"
+	depends on (SUPERH || ARCH_SHMOBILE)
+	select GENERIC_ALLOCATOR
+	---help---
+	  Enable MERAM support for the SuperH controller.
+
+	  This will allow for caching of the framebuffer to provide more
+	  reliable access under heavy main memory bus traffic situations.
+	  Up to 4 memory channels can be configured, allowing 4 RGB or
+	  2 YCbCr framebuffers to be configured.
+
 endmenu
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 1426068..9356add 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -15,6 +15,8 @@
 obj-$(CONFIG_LOGO)		  += logo/
 obj-y				  += backlight/
 
+obj-$(CONFIG_EXYNOS_VIDEO)     += exynos/
+
 obj-$(CONFIG_FB_CFB_FILLRECT)  += cfbfillrect.o
 obj-$(CONFIG_FB_CFB_COPYAREA)  += cfbcopyarea.o
 obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
@@ -37,6 +39,7 @@
 obj-$(CONFIG_FB_PM2)              += pm2fb.o
 obj-$(CONFIG_FB_PM3)		  += pm3fb.o
 
+obj-$(CONFIG_FB_I740)		  += i740fb.o
 obj-$(CONFIG_FB_MATROX)		  += matrox/
 obj-$(CONFIG_FB_RIVA)		  += riva/
 obj-$(CONFIG_FB_NVIDIA)		  += nvidia/
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index f23cae09..887df9d 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -53,7 +53,6 @@
 #include <linux/platform_device.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index e40c00f..d99505b 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -421,24 +421,18 @@
 		var->red.length = var->green.length = var->blue.length
 			= var->bits_per_pixel;
 		break;
-	case 15:
 	case 16:
 		if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
 			/* RGB:565 mode */
 			var->red.offset = 11;
 			var->blue.offset = 0;
-			var->green.length = 6;
-		} else if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB555) {
-			var->red.offset = 10;
-			var->blue.offset = 0;
-			var->green.length = 5;
 		} else {
-			/* BGR:555 mode */
+			/* BGR:565 mode */
 			var->red.offset = 0;
-			var->blue.offset = 10;
-			var->green.length = 5;
+			var->blue.offset = 11;
 		}
 		var->green.offset = 5;
+		var->green.length = 6;
 		var->red.length = var->blue.length = 5;
 		break;
 	case 32:
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index de9da67..befcbd8 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -477,7 +477,8 @@
 	u32 sys_clksrc;
 
 	/* Allocate new device private */
-	fbdev = kzalloc(sizeof(struct au1100fb_device), GFP_KERNEL);
+	fbdev = devm_kzalloc(&dev->dev, sizeof(struct au1100fb_device),
+			     GFP_KERNEL);
 	if (!fbdev) {
 		print_err("fail to allocate device private record");
 		return -ENOMEM;
@@ -498,8 +499,9 @@
 	au1100fb_fix.mmio_start = regs_res->start;
 	au1100fb_fix.mmio_len = resource_size(regs_res);
 
-	if (!request_mem_region(au1100fb_fix.mmio_start, au1100fb_fix.mmio_len,
-				DRIVER_NAME)) {
+	if (!devm_request_mem_region(au1100fb_fix.mmio_start,
+				     au1100fb_fix.mmio_len,
+				     DRIVER_NAME)) {
 		print_err("fail to lock memory region at 0x%08lx",
 				au1100fb_fix.mmio_start);
 		return -EBUSY;
@@ -514,8 +516,9 @@
 	fbdev->fb_len = fbdev->panel->xres * fbdev->panel->yres *
 		  	(fbdev->panel->bpp >> 3) * AU1100FB_NBR_VIDEO_BUFFERS;
 
-	fbdev->fb_mem = dma_alloc_coherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len),
-					&fbdev->fb_phys, GFP_KERNEL);
+	fbdev->fb_mem = dmam_alloc_coherent(&dev->dev, &dev->dev,
+					    PAGE_ALIGN(fbdev->fb_len),
+					    &fbdev->fb_phys, GFP_KERNEL);
 	if (!fbdev->fb_mem) {
 		print_err("fail to allocate frambuffer (size: %dK))",
 			  fbdev->fb_len / 1024);
@@ -557,14 +560,14 @@
 	fbdev->info.fbops = &au1100fb_ops;
 	fbdev->info.fix = au1100fb_fix;
 
-	if (!(fbdev->info.pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL))) {
+	fbdev->info.pseudo_palette =
+		devm_kzalloc(&dev->dev, sizeof(u32) * 16, GFP_KERNEL);
+	if (!fbdev->info.pseudo_palette)
 		return -ENOMEM;
-	}
 
 	if (fb_alloc_cmap(&fbdev->info.cmap, AU1100_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
 		print_err("Fail to allocate colormap (%d entries)",
 			   AU1100_LCD_NBR_PALETTE_ENTRIES);
-		kfree(fbdev->info.pseudo_palette);
 		return -EFAULT;
 	}
 
@@ -582,9 +585,6 @@
 	return 0;
 
 failed:
-	if (fbdev->regs) {
-		release_mem_region(fbdev->regs_phys, fbdev->regs_len);
-	}
 	if (fbdev->fb_mem) {
 		dma_free_noncoherent(&dev->dev, fbdev->fb_len, fbdev->fb_mem,
 				     fbdev->fb_phys);
@@ -592,10 +592,9 @@
 	if (fbdev->info.cmap.len != 0) {
 		fb_dealloc_cmap(&fbdev->info.cmap);
 	}
-	kfree(fbdev);
 	platform_set_drvdata(dev, NULL);
 
-	return 0;
+	return -ENODEV;
 }
 
 int au1100fb_drv_remove(struct platform_device *dev)
@@ -615,14 +614,7 @@
 	/* Clean up all probe data */
 	unregister_framebuffer(&fbdev->info);
 
-	release_mem_region(fbdev->regs_phys, fbdev->regs_len);
-
-	dma_free_coherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem,
-			  fbdev->fb_phys);
-
 	fb_dealloc_cmap(&fbdev->info.cmap);
-	kfree(fbdev->info.pseudo_palette);
-	kfree((void*)fbdev);
 
 	return 0;
 }
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
index 04e4479..3e9a773 100644
--- a/drivers/video/au1200fb.c
+++ b/drivers/video/au1200fb.c
@@ -1724,7 +1724,7 @@
 		/* Allocate the framebuffer to the maximum screen size */
 		fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8;
 
-		fbdev->fb_mem = dma_alloc_noncoherent(&dev->dev,
+		fbdev->fb_mem = dmam_alloc_noncoherent(&dev->dev, &dev->dev,
 				PAGE_ALIGN(fbdev->fb_len),
 				&fbdev->fb_phys, GFP_KERNEL);
 		if (!fbdev->fb_mem) {
@@ -1788,9 +1788,6 @@
 
 failed:
 	/* NOTE: This only does the current plane/window that failed; others are still active */
-	if (fbdev->fb_mem)
-		dma_free_noncoherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len),
-				fbdev->fb_mem, fbdev->fb_phys);
 	if (fbi) {
 		if (fbi->cmap.len != 0)
 			fb_dealloc_cmap(&fbi->cmap);
@@ -1817,10 +1814,6 @@
 
 		/* Clean up all probe data */
 		unregister_framebuffer(fbi);
-		if (fbdev->fb_mem)
-			dma_free_noncoherent(&dev->dev,
-					PAGE_ALIGN(fbdev->fb_len),
-					fbdev->fb_mem, fbdev->fb_phys);
 		if (fbi->cmap.len != 0)
 			fb_dealloc_cmap(&fbi->cmap);
 		kfree(fbi->pseudo_palette);
diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c
index a1376dc..f49181c 100644
--- a/drivers/video/backlight/88pm860x_bl.c
+++ b/drivers/video/backlight/88pm860x_bl.c
@@ -67,6 +67,28 @@
 	return ret;
 }
 
+static int backlight_power_set(struct pm860x_chip *chip, int port,
+		int on)
+{
+	int ret = -EINVAL;
+
+	switch (port) {
+	case PM8606_BACKLIGHT1:
+		ret = on ? pm8606_osc_enable(chip, WLED1_DUTY) :
+			pm8606_osc_disable(chip, WLED1_DUTY);
+		break;
+	case PM8606_BACKLIGHT2:
+		ret = on ? pm8606_osc_enable(chip, WLED2_DUTY) :
+			pm8606_osc_disable(chip, WLED2_DUTY);
+		break;
+	case PM8606_BACKLIGHT3:
+		ret = on ? pm8606_osc_enable(chip, WLED3_DUTY) :
+			pm8606_osc_disable(chip, WLED3_DUTY);
+		break;
+	}
+	return ret;
+}
+
 static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
 {
 	struct pm860x_backlight_data *data = bl_get_data(bl);
@@ -79,6 +101,9 @@
 	else
 		value = brightness;
 
+	if (brightness)
+		backlight_power_set(chip, data->port, 1);
+
 	ret = pm860x_reg_write(data->i2c, wled_a(data->port), value);
 	if (ret < 0)
 		goto out;
@@ -115,6 +140,9 @@
 	if (ret < 0)
 		goto out;
 
+	if (brightness == 0)
+		backlight_power_set(chip, data->port, 0);
+
 	dev_dbg(chip->dev, "set brightness %d\n", value);
 	data->current_brightness = value;
 	return 0;
@@ -170,7 +198,6 @@
 	struct backlight_device *bl;
 	struct resource *res;
 	struct backlight_properties props;
-	unsigned char value;
 	char name[MFD_NAME_SIZE];
 	int ret;
 
@@ -187,7 +214,8 @@
 		return -EINVAL;
 	}
 
-	data = kzalloc(sizeof(struct pm860x_backlight_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_backlight_data),
+			    GFP_KERNEL);
 	if (data == NULL)
 		return -ENOMEM;
 	strncpy(name, res->name, MFD_NAME_SIZE);
@@ -200,7 +228,6 @@
 	data->port = pdata->flags;
 	if (data->port < 0) {
 		dev_err(&pdev->dev, "wrong platform data is assigned");
-		kfree(data);
 		return -EINVAL;
 	}
 
@@ -211,33 +238,12 @@
 					&pm860x_backlight_ops, &props);
 	if (IS_ERR(bl)) {
 		dev_err(&pdev->dev, "failed to register backlight\n");
-		kfree(data);
 		return PTR_ERR(bl);
 	}
 	bl->props.brightness = MAX_BRIGHTNESS;
 
 	platform_set_drvdata(pdev, bl);
 
-	/* Enable reference VSYS */
-	ret = pm860x_reg_read(data->i2c, PM8606_VSYS);
-	if (ret < 0)
-		goto out;
-	if ((ret & PM8606_VSYS_EN) == 0) {
-		value = ret | PM8606_VSYS_EN;
-		ret = pm860x_reg_write(data->i2c, PM8606_VSYS, value);
-		if (ret < 0)
-			goto out;
-	}
-	/* Enable reference OSC */
-	ret = pm860x_reg_read(data->i2c, PM8606_MISC);
-	if (ret < 0)
-		goto out;
-	if ((ret & PM8606_MISC_OSC_EN) == 0) {
-		value = ret | PM8606_MISC_OSC_EN;
-		ret = pm860x_reg_write(data->i2c, PM8606_MISC, value);
-		if (ret < 0)
-			goto out;
-	}
 	/* read current backlight */
 	ret = pm860x_backlight_get_brightness(bl);
 	if (ret < 0)
@@ -247,17 +253,14 @@
 	return 0;
 out:
 	backlight_device_unregister(bl);
-	kfree(data);
 	return ret;
 }
 
 static int pm860x_backlight_remove(struct platform_device *pdev)
 {
 	struct backlight_device *bl = platform_get_drvdata(pdev);
-	struct pm860x_backlight_data *data = bl_get_data(bl);
 
 	backlight_device_unregister(bl);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 681b369..af16884 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -245,6 +245,12 @@
 	  If you have a LCD backlight connected to the WLED output of DA9030
 	  or DA9034 WLED output, say Y here to enable this driver.
 
+config BACKLIGHT_DA9052
+	tristate "Dialog DA9052/DA9053 WLED"
+	depends on PMIC_DA9052
+	help
+	  Enable the Backlight Driver for DA9052-BC and DA9053-AA/Bx PMICs.
+
 config BACKLIGHT_MAX8925
 	tristate "Backlight driver for MAX8925"
 	depends on MFD_MAX8925
@@ -334,6 +340,27 @@
 	  If you have a AnalogicTech AAT2870 say Y to enable the
 	  backlight driver.
 
+config BACKLIGHT_LP855X
+	tristate "Backlight driver for TI LP855X"
+	depends on BACKLIGHT_CLASS_DEVICE && I2C
+	help
+	  This supports TI LP8550, LP8551, LP8552, LP8553 and LP8556
+	  backlight driver.
+
+config BACKLIGHT_OT200
+	tristate "Backlight driver for ot200 visualisation device"
+	depends on BACKLIGHT_CLASS_DEVICE && CS5535_MFGPT && GPIO_CS5535
+	help
+	  To compile this driver as a module, choose M here: the module will be
+	  called ot200_bl.
+
+config BACKLIGHT_PANDORA
+	tristate "Backlight driver for Pandora console"
+	depends on TWL4030_CORE
+	help
+	  If you have a Pandora console, say Y to enable the
+	  backlight driver.
+
 endif # BACKLIGHT_CLASS_DEVICE
 
 endif # BACKLIGHT_LCD_SUPPORT
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index af5cf65..36855ae 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -22,11 +22,14 @@
 obj-$(CONFIG_BACKLIGHT_HP700)	+= jornada720_bl.o
 obj-$(CONFIG_BACKLIGHT_HP680)	+= hp680_bl.o
 obj-$(CONFIG_BACKLIGHT_LOCOMO)	+= locomolcd.o
+obj-$(CONFIG_BACKLIGHT_LP855X)	+= lp855x_bl.o
 obj-$(CONFIG_BACKLIGHT_OMAP1)	+= omap1_bl.o
+obj-$(CONFIG_BACKLIGHT_PANDORA)	+= pandora_bl.o
 obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
 obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
 obj-$(CONFIG_BACKLIGHT_PWM)	+= pwm_bl.o
 obj-$(CONFIG_BACKLIGHT_DA903X)	+= da903x_bl.o
+obj-$(CONFIG_BACKLIGHT_DA9052)	+= da9052_bl.o
 obj-$(CONFIG_BACKLIGHT_MAX8925)	+= max8925_bl.o
 obj-$(CONFIG_BACKLIGHT_APPLE)	+= apple_bl.o
 obj-$(CONFIG_BACKLIGHT_TOSA)	+= tosa_bl.o
@@ -38,4 +41,4 @@
 obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
 obj-$(CONFIG_BACKLIGHT_PCF50633)	+= pcf50633-backlight.o
 obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o
-
+obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o
diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c
index 331f1ef..7ff7522 100644
--- a/drivers/video/backlight/aat2870_bl.c
+++ b/drivers/video/backlight/aat2870_bl.c
@@ -145,7 +145,9 @@
 		goto out;
 	}
 
-	aat2870_bl = kzalloc(sizeof(struct aat2870_bl_driver_data), GFP_KERNEL);
+	aat2870_bl = devm_kzalloc(&pdev->dev,
+				  sizeof(struct aat2870_bl_driver_data),
+				  GFP_KERNEL);
 	if (!aat2870_bl) {
 		dev_err(&pdev->dev,
 			"Failed to allocate memory for aat2870 backlight\n");
@@ -162,7 +164,7 @@
 		dev_err(&pdev->dev,
 			"Failed allocate memory for backlight device\n");
 		ret = PTR_ERR(bd);
-		goto out_kfree;
+		goto out;
 	}
 
 	aat2870_bl->pdev = pdev;
@@ -199,8 +201,6 @@
 
 out_bl_dev_unregister:
 	backlight_device_unregister(bd);
-out_kfree:
-	kfree(aat2870_bl);
 out:
 	return ret;
 }
@@ -215,7 +215,6 @@
 	backlight_update_status(bd);
 
 	backlight_device_unregister(bd);
-	kfree(aat2870_bl);
 
 	return 0;
 }
diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c
index 2e630bf..4911ea7 100644
--- a/drivers/video/backlight/adp5520_bl.c
+++ b/drivers/video/backlight/adp5520_bl.c
@@ -289,7 +289,7 @@
 	struct adp5520_bl *data;
 	int ret = 0;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
 	if (data == NULL)
 		return -ENOMEM;
 
@@ -298,7 +298,6 @@
 
 	if (data->pdata  == NULL) {
 		dev_err(&pdev->dev, "missing platform data\n");
-		kfree(data);
 		return -ENODEV;
 	}
 
@@ -314,7 +313,6 @@
 				       &adp5520_bl_ops, &props);
 	if (IS_ERR(bl)) {
 		dev_err(&pdev->dev, "failed to register backlight\n");
-		kfree(data);
 		return PTR_ERR(bl);
 	}
 
@@ -326,7 +324,6 @@
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register sysfs\n");
 		backlight_device_unregister(bl);
-		kfree(data);
 	}
 
 	platform_set_drvdata(pdev, bl);
@@ -348,7 +345,6 @@
 				&adp5520_bl_attr_group);
 
 	backlight_device_unregister(bl);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c
index 378276c..550dbf0 100644
--- a/drivers/video/backlight/adp8860_bl.c
+++ b/drivers/video/backlight/adp8860_bl.c
@@ -819,17 +819,7 @@
 	.id_table = adp8860_id,
 };
 
-static int __init adp8860_init(void)
-{
-	return i2c_add_driver(&adp8860_driver);
-}
-module_init(adp8860_init);
-
-static void __exit adp8860_exit(void)
-{
-	i2c_del_driver(&adp8860_driver);
-}
-module_exit(adp8860_exit);
+module_i2c_driver(adp8860_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c
index 6735059..9be58c6 100644
--- a/drivers/video/backlight/adp8870_bl.c
+++ b/drivers/video/backlight/adp8870_bl.c
@@ -991,17 +991,7 @@
 	.id_table = adp8870_id,
 };
 
-static int __init adp8870_init(void)
-{
-	return i2c_add_driver(&adp8870_driver);
-}
-module_init(adp8870_init);
-
-static void __exit adp8870_exit(void)
-{
-	i2c_del_driver(&adp8870_driver);
-}
-module_exit(adp8870_exit);
+module_i2c_driver(adp8870_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
diff --git a/drivers/video/backlight/ams369fg06.c b/drivers/video/backlight/ams369fg06.c
index 7838a23..7bdadc7 100644
--- a/drivers/video/backlight/ams369fg06.c
+++ b/drivers/video/backlight/ams369fg06.c
@@ -629,18 +629,7 @@
 	.resume		= ams369fg06_resume,
 };
 
-static int __init ams369fg06_init(void)
-{
-	return spi_register_driver(&ams369fg06_driver);
-}
-
-static void __exit ams369fg06_exit(void)
-{
-	spi_unregister_driver(&ams369fg06_driver);
-}
-
-module_init(ams369fg06_init);
-module_exit(ams369fg06_exit);
+module_spi_driver(ams369fg06_driver);
 
 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
 MODULE_DESCRIPTION("ams369fg06 LCD Driver");
diff --git a/drivers/video/backlight/apple_bl.c b/drivers/video/backlight/apple_bl.c
index be98d15..a523b25 100644
--- a/drivers/video/backlight/apple_bl.c
+++ b/drivers/video/backlight/apple_bl.c
@@ -24,6 +24,7 @@
 #include <linux/io.h>
 #include <linux/pci.h>
 #include <linux/acpi.h>
+#include <linux/atomic.h>
 
 static struct backlight_device *apple_backlight_device;
 
@@ -221,14 +222,32 @@
 	},
 };
 
+static atomic_t apple_bl_registered = ATOMIC_INIT(0);
+
+int apple_bl_register(void)
+{
+	if (atomic_xchg(&apple_bl_registered, 1) == 0)
+		return acpi_bus_register_driver(&apple_bl_driver);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(apple_bl_register);
+
+void apple_bl_unregister(void)
+{
+	if (atomic_xchg(&apple_bl_registered, 0) == 1)
+		acpi_bus_unregister_driver(&apple_bl_driver);
+}
+EXPORT_SYMBOL_GPL(apple_bl_unregister);
+
 static int __init apple_bl_init(void)
 {
-	return acpi_bus_register_driver(&apple_bl_driver);
+	return apple_bl_register();
 }
 
 static void __exit apple_bl_exit(void)
 {
-	acpi_bus_unregister_driver(&apple_bl_driver);
+	apple_bl_unregister();
 }
 
 module_init(apple_bl_init);
diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c
index c6533ba..6dab13f 100644
--- a/drivers/video/backlight/corgi_lcd.c
+++ b/drivers/video/backlight/corgi_lcd.c
@@ -629,17 +629,7 @@
 	.resume		= corgi_lcd_resume,
 };
 
-static int __init corgi_lcd_init(void)
-{
-	return spi_register_driver(&corgi_lcd_driver);
-}
-module_init(corgi_lcd_init);
-
-static void __exit corgi_lcd_exit(void)
-{
-	spi_unregister_driver(&corgi_lcd_driver);
-}
-module_exit(corgi_lcd_exit);
+module_spi_driver(corgi_lcd_driver);
 
 MODULE_DESCRIPTION("LCD and backlight driver for SHARP C7x0/Cxx00");
 MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
index 6c8c540..22489eb 100644
--- a/drivers/video/backlight/cr_bllcd.c
+++ b/drivers/video/backlight/cr_bllcd.c
@@ -212,7 +212,7 @@
 			      &gpio_bar);
 	gpio_bar &= ~0x3F;
 
-	crp = kzalloc(sizeof(*crp), GFP_KERNEL);
+	crp = devm_kzalloc(&pdev->dev, sizeof(*crp), GFP_KERNEL);
 	if (!crp) {
 		lcd_device_unregister(ldp);
 		backlight_device_unregister(bdp);
@@ -243,7 +243,6 @@
 	backlight_device_unregister(crp->cr_backlight_device);
 	lcd_device_unregister(crp->cr_lcd_device);
 	pci_dev_put(lpc_dev);
-	kfree(crp);
 
 	return 0;
 }
diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c
index abb4a06..30e1968 100644
--- a/drivers/video/backlight/da903x_bl.c
+++ b/drivers/video/backlight/da903x_bl.c
@@ -110,7 +110,7 @@
 	struct backlight_properties props;
 	int max_brightness;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
 	if (data == NULL)
 		return -ENOMEM;
 
@@ -124,7 +124,6 @@
 	default:
 		dev_err(&pdev->dev, "invalid backlight device ID(%d)\n",
 				pdev->id);
-		kfree(data);
 		return -EINVAL;
 	}
 
@@ -143,7 +142,6 @@
 				       &da903x_backlight_ops, &props);
 	if (IS_ERR(bl)) {
 		dev_err(&pdev->dev, "failed to register backlight\n");
-		kfree(data);
 		return PTR_ERR(bl);
 	}
 
@@ -157,10 +155,8 @@
 static int da903x_backlight_remove(struct platform_device *pdev)
 {
 	struct backlight_device *bl = platform_get_drvdata(pdev);
-	struct da903x_backlight_data *data = bl_get_data(bl);
 
 	backlight_device_unregister(bl);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/video/backlight/da9052_bl.c b/drivers/video/backlight/da9052_bl.c
new file mode 100644
index 0000000..b628d68
--- /dev/null
+++ b/drivers/video/backlight/da9052_bl.c
@@ -0,0 +1,187 @@
+/*
+ * Backlight Driver for Dialog DA9052 PMICs
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@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/backlight.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+
+#define DA9052_MAX_BRIGHTNESS		0xFF
+
+enum {
+	DA9052_WLEDS_OFF,
+	DA9052_WLEDS_ON,
+};
+
+enum {
+	DA9052_TYPE_WLED1,
+	DA9052_TYPE_WLED2,
+	DA9052_TYPE_WLED3,
+};
+
+static unsigned char wled_bank[] = {
+	DA9052_LED1_CONF_REG,
+	DA9052_LED2_CONF_REG,
+	DA9052_LED3_CONF_REG,
+};
+
+struct da9052_bl {
+	struct da9052 *da9052;
+	uint brightness;
+	uint state;
+	uint led_reg;
+};
+
+static int da9052_adjust_wled_brightness(struct da9052_bl *wleds)
+{
+	unsigned char boost_en;
+	unsigned char i_sink;
+	int ret;
+
+	boost_en = 0x3F;
+	i_sink = 0xFF;
+	if (wleds->state == DA9052_WLEDS_OFF) {
+		boost_en = 0x00;
+		i_sink = 0x00;
+	}
+
+	ret = da9052_reg_write(wleds->da9052, DA9052_BOOST_REG, boost_en);
+	if (ret < 0)
+		return ret;
+
+	ret = da9052_reg_write(wleds->da9052, DA9052_LED_CONT_REG, i_sink);
+	if (ret < 0)
+		return ret;
+
+	ret = da9052_reg_write(wleds->da9052, wled_bank[wleds->led_reg], 0x0);
+	if (ret < 0)
+		return ret;
+
+	msleep(10);
+
+	if (wleds->brightness) {
+		ret = da9052_reg_write(wleds->da9052, wled_bank[wleds->led_reg],
+				       wleds->brightness);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int da9052_backlight_update_status(struct backlight_device *bl)
+{
+	int brightness = bl->props.brightness;
+	struct da9052_bl *wleds = bl_get_data(bl);
+
+	wleds->brightness = brightness;
+	wleds->state = DA9052_WLEDS_ON;
+
+	return da9052_adjust_wled_brightness(wleds);
+}
+
+static int da9052_backlight_get_brightness(struct backlight_device *bl)
+{
+	struct da9052_bl *wleds = bl_get_data(bl);
+
+	return wleds->brightness;
+}
+
+static const struct backlight_ops da9052_backlight_ops = {
+	.update_status = da9052_backlight_update_status,
+	.get_brightness = da9052_backlight_get_brightness,
+};
+
+static int da9052_backlight_probe(struct platform_device *pdev)
+{
+	struct backlight_device *bl;
+	struct backlight_properties props;
+	struct da9052_bl *wleds;
+
+	wleds = devm_kzalloc(&pdev->dev, sizeof(struct da9052_bl), GFP_KERNEL);
+	if (!wleds)
+		return -ENOMEM;
+
+	wleds->da9052 = dev_get_drvdata(pdev->dev.parent);
+	wleds->brightness = 0;
+	wleds->led_reg = platform_get_device_id(pdev)->driver_data;
+	wleds->state = DA9052_WLEDS_OFF;
+
+	props.type = BACKLIGHT_RAW;
+	props.max_brightness = DA9052_MAX_BRIGHTNESS;
+
+	bl = backlight_device_register(pdev->name, wleds->da9052->dev, wleds,
+				       &da9052_backlight_ops, &props);
+	if (IS_ERR(bl)) {
+		dev_err(&pdev->dev, "Failed to register backlight\n");
+		devm_kfree(&pdev->dev, wleds);
+		return PTR_ERR(bl);
+	}
+
+	bl->props.max_brightness = DA9052_MAX_BRIGHTNESS;
+	bl->props.brightness = 0;
+	platform_set_drvdata(pdev, bl);
+
+	return da9052_adjust_wled_brightness(wleds);
+}
+
+static int da9052_backlight_remove(struct platform_device *pdev)
+{
+	struct backlight_device *bl = platform_get_drvdata(pdev);
+	struct da9052_bl *wleds = bl_get_data(bl);
+
+	wleds->brightness = 0;
+	wleds->state = DA9052_WLEDS_OFF;
+	da9052_adjust_wled_brightness(wleds);
+	backlight_device_unregister(bl);
+	devm_kfree(&pdev->dev, wleds);
+
+	return 0;
+}
+
+static struct platform_device_id da9052_wled_ids[] = {
+	{
+		.name		= "da9052-wled1",
+		.driver_data	= DA9052_TYPE_WLED1,
+	},
+	{
+		.name		= "da9052-wled2",
+		.driver_data	= DA9052_TYPE_WLED2,
+	},
+	{
+		.name		= "da9052-wled3",
+		.driver_data	= DA9052_TYPE_WLED3,
+	},
+};
+
+static struct platform_driver da9052_wled_driver = {
+	.probe		= da9052_backlight_probe,
+	.remove		= da9052_backlight_remove,
+	.id_table	= da9052_wled_ids,
+	.driver	= {
+		.name	= "da9052-wled",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(da9052_wled_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("Backlight driver for DA9052 PMIC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9052-backlight");
diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c
index b62b8b9..08214e1 100644
--- a/drivers/video/backlight/ep93xx_bl.c
+++ b/drivers/video/backlight/ep93xx_bl.c
@@ -17,11 +17,6 @@
 #include <linux/fb.h>
 #include <linux/backlight.h>
 
-#include <mach/hardware.h>
-
-#define EP93XX_RASTER_REG(x)		(EP93XX_RASTER_BASE + (x))
-#define EP93XX_RASTER_BRIGHTNESS	EP93XX_RASTER_REG(0x20)
-
 #define EP93XX_MAX_COUNT		255
 #define EP93XX_MAX_BRIGHT		255
 #define EP93XX_DEF_BRIGHT		128
@@ -35,7 +30,7 @@
 {
 	struct ep93xxbl *ep93xxbl = bl_get_data(bl);
 
-	__raw_writel((brightness << 8) | EP93XX_MAX_COUNT, ep93xxbl->mmio);
+	writel((brightness << 8) | EP93XX_MAX_COUNT, ep93xxbl->mmio);
 
 	ep93xxbl->brightness = brightness;
 
@@ -70,21 +65,29 @@
 	struct ep93xxbl *ep93xxbl;
 	struct backlight_device *bl;
 	struct backlight_properties props;
+	struct resource *res;
 
 	ep93xxbl = devm_kzalloc(&dev->dev, sizeof(*ep93xxbl), GFP_KERNEL);
 	if (!ep93xxbl)
 		return -ENOMEM;
 
+	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
 	/*
-	 * This register is located in the range already ioremap'ed by
-	 * the framebuffer driver.  A MFD driver seems a bit of overkill
-	 * to handle this so use the static I/O mapping; this address
-	 * is already virtual.
+	 * FIXME - We don't do a request_mem_region here because we are
+	 * sharing the register space with the framebuffer driver (see
+	 * drivers/video/ep93xx-fb.c) and doing so will cause the second
+	 * loaded driver to return -EBUSY.
 	 *
 	 * NOTE: No locking is required; the framebuffer does not touch
 	 * this register.
 	 */
-	ep93xxbl->mmio = EP93XX_RASTER_BRIGHTNESS;
+	ep93xxbl->mmio = devm_ioremap(&dev->dev, res->start,
+				      resource_size(res));
+	if (!ep93xxbl->mmio)
+		return -ENXIO;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
 	props.type = BACKLIGHT_RAW;
diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c
index 27d1d7a..6022b67 100644
--- a/drivers/video/backlight/l4f00242t03.c
+++ b/drivers/video/backlight/l4f00242t03.c
@@ -274,18 +274,7 @@
 	.shutdown	= l4f00242t03_shutdown,
 };
 
-static __init int l4f00242t03_init(void)
-{
-	return spi_register_driver(&l4f00242t03_driver);
-}
-
-static __exit void l4f00242t03_exit(void)
-{
-	spi_unregister_driver(&l4f00242t03_driver);
-}
-
-module_init(l4f00242t03_init);
-module_exit(l4f00242t03_exit);
+module_spi_driver(l4f00242t03_driver);
 
 MODULE_AUTHOR("Alberto Panizzo <maramaopercheseimorto@gmail.com>");
 MODULE_DESCRIPTION("EPSON L4F00242T03 LCD");
diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c
index 78dafc0..efd352b 100644
--- a/drivers/video/backlight/ld9040.c
+++ b/drivers/video/backlight/ld9040.c
@@ -856,18 +856,7 @@
 	.resume		= ld9040_resume,
 };
 
-static int __init ld9040_init(void)
-{
-	return spi_register_driver(&ld9040_driver);
-}
-
-static void __exit ld9040_exit(void)
-{
-	spi_unregister_driver(&ld9040_driver);
-}
-
-module_init(ld9040_init);
-module_exit(ld9040_exit);
+module_spi_driver(ld9040_driver);
 
 MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
 MODULE_DESCRIPTION("ld9040 LCD Driver");
diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c
index 4ec78cf..4161f9e 100644
--- a/drivers/video/backlight/lms283gf05.c
+++ b/drivers/video/backlight/lms283gf05.c
@@ -226,18 +226,7 @@
 	.remove		= __devexit_p(lms283gf05_remove),
 };
 
-static __init int lms283gf05_init(void)
-{
-	return spi_register_driver(&lms283gf05_driver);
-}
-
-static __exit void lms283gf05_exit(void)
-{
-	spi_unregister_driver(&lms283gf05_driver);
-}
-
-module_init(lms283gf05_init);
-module_exit(lms283gf05_exit);
+module_spi_driver(lms283gf05_driver);
 
 MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
 MODULE_DESCRIPTION("LCD283GF05 LCD");
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
index be20b5c..3a6d541 100644
--- a/drivers/video/backlight/locomolcd.c
+++ b/drivers/video/backlight/locomolcd.c
@@ -229,14 +229,7 @@
 
 static int __init locomolcd_init(void)
 {
-	int ret = locomo_driver_register(&poodle_lcd_driver);
-	if (ret)
-		return ret;
-
-#ifdef CONFIG_SA1100_COLLIE
-	sa1100fb_lcd_power = locomolcd_power;
-#endif
-	return 0;
+	return locomo_driver_register(&poodle_lcd_driver);
 }
 
 static void __exit locomolcd_exit(void)
diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c
new file mode 100644
index 0000000..72a0e0c
--- /dev/null
+++ b/drivers/video/backlight/lp855x_bl.c
@@ -0,0 +1,331 @@
+/*
+ * TI LP855x Backlight Driver
+ *
+ *			Copyright (C) 2011 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/backlight.h>
+#include <linux/err.h>
+#include <linux/lp855x.h>
+
+/* Registers */
+#define BRIGHTNESS_CTRL		(0x00)
+#define DEVICE_CTRL		(0x01)
+
+#define BUF_SIZE		20
+#define DEFAULT_BL_NAME		"lcd-backlight"
+#define MAX_BRIGHTNESS		255
+
+struct lp855x {
+	const char *chipname;
+	enum lp855x_chip_id chip_id;
+	struct i2c_client *client;
+	struct backlight_device *bl;
+	struct device *dev;
+	struct mutex xfer_lock;
+	struct lp855x_platform_data *pdata;
+};
+
+static int lp855x_read_byte(struct lp855x *lp, u8 reg, u8 *data)
+{
+	int ret;
+
+	mutex_lock(&lp->xfer_lock);
+	ret = i2c_smbus_read_byte_data(lp->client, reg);
+	if (ret < 0) {
+		mutex_unlock(&lp->xfer_lock);
+		dev_err(lp->dev, "failed to read 0x%.2x\n", reg);
+		return ret;
+	}
+	mutex_unlock(&lp->xfer_lock);
+
+	*data = (u8)ret;
+	return 0;
+}
+
+static int lp855x_write_byte(struct lp855x *lp, u8 reg, u8 data)
+{
+	int ret;
+
+	mutex_lock(&lp->xfer_lock);
+	ret = i2c_smbus_write_byte_data(lp->client, reg, data);
+	mutex_unlock(&lp->xfer_lock);
+
+	return ret;
+}
+
+static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr)
+{
+	u8 start, end;
+
+	switch (lp->chip_id) {
+	case LP8550:
+	case LP8551:
+	case LP8552:
+	case LP8553:
+		start = EEPROM_START;
+		end = EEPROM_END;
+		break;
+	case LP8556:
+		start = EPROM_START;
+		end = EPROM_END;
+		break;
+	default:
+		return false;
+	}
+
+	return (addr >= start && addr <= end);
+}
+
+static int lp855x_init_registers(struct lp855x *lp)
+{
+	u8 val, addr;
+	int i, ret;
+	struct lp855x_platform_data *pd = lp->pdata;
+
+	val = pd->initial_brightness;
+	ret = lp855x_write_byte(lp, BRIGHTNESS_CTRL, val);
+	if (ret)
+		return ret;
+
+	val = pd->device_control;
+	ret = lp855x_write_byte(lp, DEVICE_CTRL, val);
+	if (ret)
+		return ret;
+
+	if (pd->load_new_rom_data && pd->size_program) {
+		for (i = 0; i < pd->size_program; i++) {
+			addr = pd->rom_data[i].addr;
+			val = pd->rom_data[i].val;
+			if (!lp855x_is_valid_rom_area(lp, addr))
+				continue;
+
+			ret = lp855x_write_byte(lp, addr, val);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int lp855x_bl_update_status(struct backlight_device *bl)
+{
+	struct lp855x *lp = bl_get_data(bl);
+	enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode;
+
+	if (bl->props.state & BL_CORE_SUSPENDED)
+		bl->props.brightness = 0;
+
+	if (mode == PWM_BASED) {
+		struct lp855x_pwm_data *pd = &lp->pdata->pwm_data;
+		int br = bl->props.brightness;
+		int max_br = bl->props.max_brightness;
+
+		if (pd->pwm_set_intensity)
+			pd->pwm_set_intensity(br, max_br);
+
+	} else if (mode == REGISTER_BASED) {
+		u8 val = bl->props.brightness;
+		lp855x_write_byte(lp, BRIGHTNESS_CTRL, val);
+	}
+
+	return 0;
+}
+
+static int lp855x_bl_get_brightness(struct backlight_device *bl)
+{
+	struct lp855x *lp = bl_get_data(bl);
+	enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode;
+
+	if (mode == PWM_BASED) {
+		struct lp855x_pwm_data *pd = &lp->pdata->pwm_data;
+		int max_br = bl->props.max_brightness;
+
+		if (pd->pwm_get_intensity)
+			bl->props.brightness = pd->pwm_get_intensity(max_br);
+
+	} else if (mode == REGISTER_BASED) {
+		u8 val = 0;
+
+		lp855x_read_byte(lp, BRIGHTNESS_CTRL, &val);
+		bl->props.brightness = val;
+	}
+
+	return bl->props.brightness;
+}
+
+static const struct backlight_ops lp855x_bl_ops = {
+	.options = BL_CORE_SUSPENDRESUME,
+	.update_status = lp855x_bl_update_status,
+	.get_brightness = lp855x_bl_get_brightness,
+};
+
+static int lp855x_backlight_register(struct lp855x *lp)
+{
+	struct backlight_device *bl;
+	struct backlight_properties props;
+	struct lp855x_platform_data *pdata = lp->pdata;
+	char *name = pdata->name ? : DEFAULT_BL_NAME;
+
+	props.type = BACKLIGHT_PLATFORM;
+	props.max_brightness = MAX_BRIGHTNESS;
+
+	if (pdata->initial_brightness > props.max_brightness)
+		pdata->initial_brightness = props.max_brightness;
+
+	props.brightness = pdata->initial_brightness;
+
+	bl = backlight_device_register(name, lp->dev, lp,
+				       &lp855x_bl_ops, &props);
+	if (IS_ERR(bl))
+		return PTR_ERR(bl);
+
+	lp->bl = bl;
+
+	return 0;
+}
+
+static void lp855x_backlight_unregister(struct lp855x *lp)
+{
+	if (lp->bl)
+		backlight_device_unregister(lp->bl);
+}
+
+static ssize_t lp855x_get_chip_id(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct lp855x *lp = dev_get_drvdata(dev);
+	return scnprintf(buf, BUF_SIZE, "%s\n", lp->chipname);
+}
+
+static ssize_t lp855x_get_bl_ctl_mode(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct lp855x *lp = dev_get_drvdata(dev);
+	enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode;
+	char *strmode = NULL;
+
+	if (mode == PWM_BASED)
+		strmode = "pwm based";
+	else if (mode == REGISTER_BASED)
+		strmode = "register based";
+
+	return scnprintf(buf, BUF_SIZE, "%s\n", strmode);
+}
+
+static DEVICE_ATTR(chip_id, S_IRUGO, lp855x_get_chip_id, NULL);
+static DEVICE_ATTR(bl_ctl_mode, S_IRUGO, lp855x_get_bl_ctl_mode, NULL);
+
+static struct attribute *lp855x_attributes[] = {
+	&dev_attr_chip_id.attr,
+	&dev_attr_bl_ctl_mode.attr,
+	NULL,
+};
+
+static const struct attribute_group lp855x_attr_group = {
+	.attrs = lp855x_attributes,
+};
+
+static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
+{
+	struct lp855x *lp;
+	struct lp855x_platform_data *pdata = cl->dev.platform_data;
+	enum lp855x_brightness_ctrl_mode mode;
+	int ret;
+
+	if (!pdata) {
+		dev_err(&cl->dev, "no platform data supplied\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
+		return -EIO;
+
+	lp = devm_kzalloc(&cl->dev, sizeof(struct lp855x), GFP_KERNEL);
+	if (!lp)
+		return -ENOMEM;
+
+	mode = pdata->mode;
+	lp->client = cl;
+	lp->dev = &cl->dev;
+	lp->pdata = pdata;
+	lp->chipname = id->name;
+	lp->chip_id = id->driver_data;
+	i2c_set_clientdata(cl, lp);
+
+	mutex_init(&lp->xfer_lock);
+
+	ret = lp855x_init_registers(lp);
+	if (ret) {
+		dev_err(lp->dev, "i2c communication err: %d", ret);
+		if (mode == REGISTER_BASED)
+			goto err_dev;
+	}
+
+	ret = lp855x_backlight_register(lp);
+	if (ret) {
+		dev_err(lp->dev,
+			"failed to register backlight. err: %d\n", ret);
+		goto err_dev;
+	}
+
+	ret = sysfs_create_group(&lp->dev->kobj, &lp855x_attr_group);
+	if (ret) {
+		dev_err(lp->dev, "failed to register sysfs. err: %d\n", ret);
+		goto err_sysfs;
+	}
+
+	backlight_update_status(lp->bl);
+	return 0;
+
+err_sysfs:
+	lp855x_backlight_unregister(lp);
+err_dev:
+	return ret;
+}
+
+static int __devexit lp855x_remove(struct i2c_client *cl)
+{
+	struct lp855x *lp = i2c_get_clientdata(cl);
+
+	lp->bl->props.brightness = 0;
+	backlight_update_status(lp->bl);
+	sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group);
+	lp855x_backlight_unregister(lp);
+
+	return 0;
+}
+
+static const struct i2c_device_id lp855x_ids[] = {
+	{"lp8550", LP8550},
+	{"lp8551", LP8551},
+	{"lp8552", LP8552},
+	{"lp8553", LP8553},
+	{"lp8556", LP8556},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lp855x_ids);
+
+static struct i2c_driver lp855x_driver = {
+	.driver = {
+		   .name = "lp855x",
+		   },
+	.probe = lp855x_probe,
+	.remove = __devexit_p(lp855x_remove),
+	.id_table = lp855x_ids,
+};
+
+module_i2c_driver(lp855x_driver);
+
+MODULE_DESCRIPTION("Texas Instruments LP855x Backlight driver");
+MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c
index cca43c0..333949f 100644
--- a/drivers/video/backlight/ltv350qv.c
+++ b/drivers/video/backlight/ltv350qv.c
@@ -321,17 +321,7 @@
 	.resume		= ltv350qv_resume,
 };
 
-static int __init ltv350qv_init(void)
-{
-	return spi_register_driver(&ltv350qv_driver);
-}
-
-static void __exit ltv350qv_exit(void)
-{
-	spi_unregister_driver(&ltv350qv_driver);
-}
-module_init(ltv350qv_init);
-module_exit(ltv350qv_exit);
+module_spi_driver(ltv350qv_driver);
 
 MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
 MODULE_DESCRIPTION("Samsung LTV350QV LCD Driver");
diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c
index c915e3b..e833ac7 100644
--- a/drivers/video/backlight/max8925_bl.c
+++ b/drivers/video/backlight/max8925_bl.c
@@ -129,7 +129,8 @@
 		return -EINVAL;
 	}
 
-	data = kzalloc(sizeof(struct max8925_backlight_data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(struct max8925_backlight_data),
+			    GFP_KERNEL);
 	if (data == NULL)
 		return -ENOMEM;
 	strncpy(name, res->name, MAX8925_NAME_SIZE);
@@ -143,7 +144,6 @@
 					&max8925_backlight_ops, &props);
 	if (IS_ERR(bl)) {
 		dev_err(&pdev->dev, "failed to register backlight\n");
-		kfree(data);
 		return PTR_ERR(bl);
 	}
 	bl->props.brightness = MAX_BRIGHTNESS;
@@ -165,17 +165,14 @@
 	return 0;
 out:
 	backlight_device_unregister(bl);
-	kfree(data);
 	return ret;
 }
 
 static int __devexit max8925_backlight_remove(struct platform_device *pdev)
 {
 	struct backlight_device *bl = platform_get_drvdata(pdev);
-	struct max8925_backlight_data *data = bl_get_data(bl);
 
 	backlight_device_unregister(bl);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c
index d8cde27..0175bfb 100644
--- a/drivers/video/backlight/omap1_bl.c
+++ b/drivers/video/backlight/omap1_bl.c
@@ -141,7 +141,8 @@
 	if (!pdata)
 		return -ENXIO;
 
-	bl = kzalloc(sizeof(struct omap_backlight), GFP_KERNEL);
+	bl = devm_kzalloc(&pdev->dev, sizeof(struct omap_backlight),
+			  GFP_KERNEL);
 	if (unlikely(!bl))
 		return -ENOMEM;
 
@@ -150,10 +151,8 @@
 	props.max_brightness = OMAPBL_MAX_INTENSITY;
 	dev = backlight_device_register("omap-bl", &pdev->dev, bl, &omapbl_ops,
 					&props);
-	if (IS_ERR(dev)) {
-		kfree(bl);
+	if (IS_ERR(dev))
 		return PTR_ERR(dev);
-	}
 
 	bl->powermode = FB_BLANK_POWERDOWN;
 	bl->current_intensity = 0;
@@ -177,10 +176,8 @@
 static int omapbl_remove(struct platform_device *pdev)
 {
 	struct backlight_device *dev = platform_get_drvdata(pdev);
-	struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
 
 	backlight_device_unregister(dev);
-	kfree(bl);
 
 	return 0;
 }
diff --git a/drivers/video/backlight/ot200_bl.c b/drivers/video/backlight/ot200_bl.c
new file mode 100644
index 0000000..f519d55
--- /dev/null
+++ b/drivers/video/backlight/ot200_bl.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2012 Bachmann electronic GmbH
+ *	Christian Gmeiner <christian.gmeiner@gmail.com>
+ *
+ * Backlight driver for ot200 visualisation device from
+ * Bachmann electronic GmbH.
+ *
+ * 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/fb.h>
+#include <linux/backlight.h>
+#include <linux/gpio.h>
+#include <linux/cs5535.h>
+
+static struct cs5535_mfgpt_timer *pwm_timer;
+
+/* this array defines the mapping of brightness in % to pwm frequency */
+static const u8 dim_table[101] = {0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+				  2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
+				  4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9,
+				  10, 10, 11, 11, 12, 12, 13, 14, 15, 15, 16,
+				  17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28,
+				  30, 31, 33, 35, 37, 39, 41, 43, 45, 47, 50,
+				  53, 55, 58, 61, 65, 68, 72, 75, 79, 84, 88,
+				  93, 97, 103, 108, 114, 120, 126, 133, 140,
+				  147, 155, 163};
+
+struct ot200_backlight_data {
+	int current_brightness;
+};
+
+#define GPIO_DIMM	27
+#define SCALE		1
+#define CMP1MODE	0x2	/* compare on GE; output high on compare
+				 * greater than or equal */
+#define PWM_SETUP	(SCALE | CMP1MODE << 6 | MFGPT_SETUP_CNTEN)
+#define MAX_COMP2	163
+
+static int ot200_backlight_update_status(struct backlight_device *bl)
+{
+	struct ot200_backlight_data *data = bl_get_data(bl);
+	int brightness = bl->props.brightness;
+
+	if (bl->props.state & BL_CORE_FBBLANK)
+		brightness = 0;
+
+	/* enable or disable PWM timer */
+	if (brightness == 0)
+		cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP, 0);
+	else if (data->current_brightness == 0) {
+		cs5535_mfgpt_write(pwm_timer, MFGPT_REG_COUNTER, 0);
+		cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP,
+			MFGPT_SETUP_CNTEN);
+	}
+
+	/* apply new brightness value */
+	cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP1,
+		MAX_COMP2 - dim_table[brightness]);
+	data->current_brightness = brightness;
+
+	return 0;
+}
+
+static int ot200_backlight_get_brightness(struct backlight_device *bl)
+{
+	struct ot200_backlight_data *data = bl_get_data(bl);
+	return data->current_brightness;
+}
+
+static const struct backlight_ops ot200_backlight_ops = {
+	.update_status	= ot200_backlight_update_status,
+	.get_brightness	= ot200_backlight_get_brightness,
+};
+
+static int ot200_backlight_probe(struct platform_device *pdev)
+{
+	struct backlight_device *bl;
+	struct ot200_backlight_data *data;
+	struct backlight_properties props;
+	int retval = 0;
+
+	/* request gpio */
+	if (gpio_request(GPIO_DIMM, "ot200 backlight dimmer") < 0) {
+		dev_err(&pdev->dev, "failed to request GPIO %d\n", GPIO_DIMM);
+		return -ENODEV;
+	}
+
+	/* request timer */
+	pwm_timer = cs5535_mfgpt_alloc_timer(7, MFGPT_DOMAIN_ANY);
+	if (!pwm_timer) {
+		dev_err(&pdev->dev, "MFGPT 7 not available\n");
+		retval = -ENODEV;
+		goto error_mfgpt_alloc;
+	}
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		retval = -ENOMEM;
+		goto error_kzalloc;
+	}
+
+	/* setup gpio */
+	cs5535_gpio_set(GPIO_DIMM, GPIO_OUTPUT_ENABLE);
+	cs5535_gpio_set(GPIO_DIMM, GPIO_OUTPUT_AUX1);
+
+	/* setup timer */
+	cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP1, 0);
+	cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP2, MAX_COMP2);
+	cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP, PWM_SETUP);
+
+	data->current_brightness = 100;
+	props.max_brightness = 100;
+	props.brightness = 100;
+	props.type = BACKLIGHT_RAW;
+
+	bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, data,
+					&ot200_backlight_ops, &props);
+	if (IS_ERR(bl)) {
+		dev_err(&pdev->dev, "failed to register backlight\n");
+		retval = PTR_ERR(bl);
+		goto error_backlight_device_register;
+	}
+
+	platform_set_drvdata(pdev, bl);
+
+	return 0;
+
+error_backlight_device_register:
+	kfree(data);
+error_kzalloc:
+	cs5535_mfgpt_free_timer(pwm_timer);
+error_mfgpt_alloc:
+	gpio_free(GPIO_DIMM);
+	return retval;
+}
+
+static int ot200_backlight_remove(struct platform_device *pdev)
+{
+	struct backlight_device *bl = platform_get_drvdata(pdev);
+	struct ot200_backlight_data *data = bl_get_data(bl);
+
+	backlight_device_unregister(bl);
+
+	/* on module unload set brightness to 100% */
+	cs5535_mfgpt_write(pwm_timer, MFGPT_REG_COUNTER, 0);
+	cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN);
+	cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP1,
+		MAX_COMP2 - dim_table[100]);
+
+	cs5535_mfgpt_free_timer(pwm_timer);
+	gpio_free(GPIO_DIMM);
+
+	kfree(data);
+	return 0;
+}
+
+static struct platform_driver ot200_backlight_driver = {
+	.driver		= {
+		.name	= "ot200-backlight",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ot200_backlight_probe,
+	.remove		= ot200_backlight_remove,
+};
+
+module_platform_driver(ot200_backlight_driver);
+
+MODULE_DESCRIPTION("backlight driver for ot200 visualisation device");
+MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ot200-backlight");
diff --git a/drivers/video/backlight/pandora_bl.c b/drivers/video/backlight/pandora_bl.c
new file mode 100644
index 0000000..4ec3074
--- /dev/null
+++ b/drivers/video/backlight/pandora_bl.c
@@ -0,0 +1,171 @@
+/*
+ * Backlight driver for Pandora handheld.
+ * Pandora uses TWL4030 PWM0 -> TPS61161 combo for control backlight.
+ * Based on pwm_bl.c
+ *
+ * Copyright 2009,2012 Gražvydas Ignotas <notasas@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/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/i2c/twl.h>
+#include <linux/err.h>
+
+#define TWL_PWM0_ON		0x00
+#define TWL_PWM0_OFF		0x01
+
+#define TWL_INTBR_GPBR1		0x0c
+#define TWL_INTBR_PMBR1		0x0d
+
+#define TWL_PMBR1_PWM0_MUXMASK	0x0c
+#define TWL_PMBR1_PWM0		0x04
+#define PWM0_CLK_ENABLE		BIT(0)
+#define PWM0_ENABLE		BIT(2)
+
+/* range accepted by hardware */
+#define MIN_VALUE 9
+#define MAX_VALUE 63
+#define MAX_USER_VALUE (MAX_VALUE - MIN_VALUE)
+
+#define PANDORABL_WAS_OFF BL_CORE_DRIVER1
+
+static int pandora_backlight_update_status(struct backlight_device *bl)
+{
+	int brightness = bl->props.brightness;
+	u8 r;
+
+	if (bl->props.power != FB_BLANK_UNBLANK)
+		brightness = 0;
+	if (bl->props.state & BL_CORE_FBBLANK)
+		brightness = 0;
+	if (bl->props.state & BL_CORE_SUSPENDED)
+		brightness = 0;
+
+	if ((unsigned int)brightness > MAX_USER_VALUE)
+		brightness = MAX_USER_VALUE;
+
+	if (brightness == 0) {
+		if (bl->props.state & PANDORABL_WAS_OFF)
+			goto done;
+
+		/* first disable PWM0 output, then clock */
+		twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_GPBR1);
+		r &= ~PWM0_ENABLE;
+		twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);
+		r &= ~PWM0_CLK_ENABLE;
+		twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);
+
+		goto done;
+	}
+
+	if (bl->props.state & PANDORABL_WAS_OFF) {
+		/*
+		 * set PWM duty cycle to max. TPS61161 seems to use this
+		 * to calibrate it's PWM sensitivity when it starts.
+		 */
+		twl_i2c_write_u8(TWL4030_MODULE_PWM0, MAX_VALUE,
+					TWL_PWM0_OFF);
+
+		/* first enable clock, then PWM0 out */
+		twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_GPBR1);
+		r &= ~PWM0_ENABLE;
+		r |= PWM0_CLK_ENABLE;
+		twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);
+		r |= PWM0_ENABLE;
+		twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);
+
+		/*
+		 * TI made it very easy to enable digital control, so easy that
+		 * it often triggers unintentionally and disabes PWM control,
+		 * so wait until 1 wire mode detection window ends.
+		 */
+		usleep_range(2000, 10000);
+	}
+
+	twl_i2c_write_u8(TWL4030_MODULE_PWM0, MIN_VALUE + brightness,
+				TWL_PWM0_OFF);
+
+done:
+	if (brightness != 0)
+		bl->props.state &= ~PANDORABL_WAS_OFF;
+	else
+		bl->props.state |= PANDORABL_WAS_OFF;
+
+	return 0;
+}
+
+static int pandora_backlight_get_brightness(struct backlight_device *bl)
+{
+	return bl->props.brightness;
+}
+
+static const struct backlight_ops pandora_backlight_ops = {
+	.options	= BL_CORE_SUSPENDRESUME,
+	.update_status	= pandora_backlight_update_status,
+	.get_brightness	= pandora_backlight_get_brightness,
+};
+
+static int pandora_backlight_probe(struct platform_device *pdev)
+{
+	struct backlight_properties props;
+	struct backlight_device *bl;
+	u8 r;
+
+	memset(&props, 0, sizeof(props));
+	props.max_brightness = MAX_USER_VALUE;
+	props.type = BACKLIGHT_RAW;
+	bl = backlight_device_register(pdev->name, &pdev->dev,
+			NULL, &pandora_backlight_ops, &props);
+	if (IS_ERR(bl)) {
+		dev_err(&pdev->dev, "failed to register backlight\n");
+		return PTR_ERR(bl);
+	}
+
+	platform_set_drvdata(pdev, bl);
+
+	/* 64 cycle period, ON position 0 */
+	twl_i2c_write_u8(TWL4030_MODULE_PWM0, 0x80, TWL_PWM0_ON);
+
+	bl->props.state |= PANDORABL_WAS_OFF;
+	bl->props.brightness = MAX_USER_VALUE;
+	backlight_update_status(bl);
+
+	/* enable PWM function in pin mux */
+	twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_PMBR1);
+	r &= ~TWL_PMBR1_PWM0_MUXMASK;
+	r |= TWL_PMBR1_PWM0;
+	twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_PMBR1);
+
+	return 0;
+}
+
+static int pandora_backlight_remove(struct platform_device *pdev)
+{
+	struct backlight_device *bl = platform_get_drvdata(pdev);
+	backlight_device_unregister(bl);
+	return 0;
+}
+
+static struct platform_driver pandora_backlight_driver = {
+	.driver		= {
+		.name	= "pandora-backlight",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= pandora_backlight_probe,
+	.remove		= pandora_backlight_remove,
+};
+
+module_platform_driver(pandora_backlight_driver);
+
+MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");
+MODULE_DESCRIPTION("Pandora Backlight Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pandora-backlight");
diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c
index 13e88b7..c65853c 100644
--- a/drivers/video/backlight/pcf50633-backlight.c
+++ b/drivers/video/backlight/pcf50633-backlight.c
@@ -101,14 +101,13 @@
 
 static int __devinit pcf50633_bl_probe(struct platform_device *pdev)
 {
-	int ret;
 	struct pcf50633_bl *pcf_bl;
 	struct device *parent = pdev->dev.parent;
 	struct pcf50633_platform_data *pcf50633_data = parent->platform_data;
 	struct pcf50633_bl_platform_data *pdata = pcf50633_data->backlight_data;
 	struct backlight_properties bl_props;
 
-	pcf_bl = kzalloc(sizeof(*pcf_bl), GFP_KERNEL);
+	pcf_bl = devm_kzalloc(&pdev->dev, sizeof(*pcf_bl), GFP_KERNEL);
 	if (!pcf_bl)
 		return -ENOMEM;
 
@@ -129,10 +128,8 @@
 	pcf_bl->bl = backlight_device_register(pdev->name, &pdev->dev, pcf_bl,
 						&pcf50633_bl_ops, &bl_props);
 
-	if (IS_ERR(pcf_bl->bl)) {
-		ret = PTR_ERR(pcf_bl->bl);
-		goto err_free;
-	}
+	if (IS_ERR(pcf_bl->bl))
+		return PTR_ERR(pcf_bl->bl);
 
 	platform_set_drvdata(pdev, pcf_bl);
 
@@ -145,11 +142,6 @@
 	backlight_update_status(pcf_bl->bl);
 
 	return 0;
-
-err_free:
-	kfree(pcf_bl);
-
-	return ret;
 }
 
 static int __devexit pcf50633_bl_remove(struct platform_device *pdev)
@@ -160,8 +152,6 @@
 
 	platform_set_drvdata(pdev, NULL);
 
-	kfree(pcf_bl);
-
 	return 0;
 }
 
diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c
index f0bf491..b667234 100644
--- a/drivers/video/backlight/platform_lcd.c
+++ b/drivers/video/backlight/platform_lcd.c
@@ -121,9 +121,9 @@
 }
 
 #ifdef CONFIG_PM
-static int platform_lcd_suspend(struct platform_device *pdev, pm_message_t st)
+static int platform_lcd_suspend(struct device *dev)
 {
-	struct platform_lcd *plcd = platform_get_drvdata(pdev);
+	struct platform_lcd *plcd = dev_get_drvdata(dev);
 
 	plcd->suspended = 1;
 	platform_lcd_set_power(plcd->lcd, plcd->power);
@@ -131,29 +131,30 @@
 	return 0;
 }
 
-static int platform_lcd_resume(struct platform_device *pdev)
+static int platform_lcd_resume(struct device *dev)
 {
-	struct platform_lcd *plcd = platform_get_drvdata(pdev);
+	struct platform_lcd *plcd = dev_get_drvdata(dev);
 
 	plcd->suspended = 0;
 	platform_lcd_set_power(plcd->lcd, plcd->power);
 
 	return 0;
 }
-#else
-#define platform_lcd_suspend NULL
-#define platform_lcd_resume NULL
+
+static SIMPLE_DEV_PM_OPS(platform_lcd_pm_ops, platform_lcd_suspend,
+			platform_lcd_resume);
 #endif
 
 static struct platform_driver platform_lcd_driver = {
 	.driver		= {
 		.name	= "platform-lcd",
 		.owner	= THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	= &platform_lcd_pm_ops,
+#endif
 	},
 	.probe		= platform_lcd_probe,
 	.remove		= __devexit_p(platform_lcd_remove),
-	.suspend        = platform_lcd_suspend,
-	.resume         = platform_lcd_resume,
 };
 
 module_platform_driver(platform_lcd_driver);
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 7496d04..342b7d7 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -102,7 +102,7 @@
 			return ret;
 	}
 
-	pb = kzalloc(sizeof(*pb), GFP_KERNEL);
+	pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL);
 	if (!pb) {
 		dev_err(&pdev->dev, "no memory for state\n");
 		ret = -ENOMEM;
@@ -121,7 +121,7 @@
 	if (IS_ERR(pb->pwm)) {
 		dev_err(&pdev->dev, "unable to request PWM for backlight\n");
 		ret = PTR_ERR(pb->pwm);
-		goto err_pwm;
+		goto err_alloc;
 	} else
 		dev_dbg(&pdev->dev, "got pwm for backlight\n");
 
@@ -144,8 +144,6 @@
 
 err_bl:
 	pwm_free(pb->pwm);
-err_pwm:
-	kfree(pb);
 err_alloc:
 	if (data->exit)
 		data->exit(&pdev->dev);
@@ -162,7 +160,6 @@
 	pwm_config(pb->pwm, 0, pb->period);
 	pwm_disable(pb->pwm);
 	pwm_free(pb->pwm);
-	kfree(pb);
 	if (data->exit)
 		data->exit(&pdev->dev);
 	return 0;
diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c
index 516db70..e264f55 100644
--- a/drivers/video/backlight/s6e63m0.c
+++ b/drivers/video/backlight/s6e63m0.c
@@ -909,18 +909,7 @@
 	.resume		= s6e63m0_resume,
 };
 
-static int __init s6e63m0_init(void)
-{
-	return spi_register_driver(&s6e63m0_driver);
-}
-
-static void __exit s6e63m0_exit(void)
-{
-	spi_unregister_driver(&s6e63m0_driver);
-}
-
-module_init(s6e63m0_init);
-module_exit(s6e63m0_exit);
+module_spi_driver(s6e63m0_driver);
 
 MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
 MODULE_DESCRIPTION("S6E63M0 LCD Driver");
diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c
index 1997e12..2368b8e 100644
--- a/drivers/video/backlight/tdo24m.c
+++ b/drivers/video/backlight/tdo24m.c
@@ -459,17 +459,7 @@
 	.resume		= tdo24m_resume,
 };
 
-static int __init tdo24m_init(void)
-{
-	return spi_register_driver(&tdo24m_driver);
-}
-module_init(tdo24m_init);
-
-static void __exit tdo24m_exit(void)
-{
-	spi_unregister_driver(&tdo24m_driver);
-}
-module_exit(tdo24m_exit);
+module_spi_driver(tdo24m_driver);
 
 MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
 MODULE_DESCRIPTION("Driver for Toppoly TDO24M LCD Panel");
diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c
index 425a736..2b241ab 100644
--- a/drivers/video/backlight/tosa_bl.c
+++ b/drivers/video/backlight/tosa_bl.c
@@ -181,18 +181,7 @@
 	.id_table	= tosa_bl_id,
 };
 
-static int __init tosa_bl_init(void)
-{
-	return i2c_add_driver(&tosa_bl_driver);
-}
-
-static void __exit tosa_bl_exit(void)
-{
-	i2c_del_driver(&tosa_bl_driver);
-}
-
-module_init(tosa_bl_init);
-module_exit(tosa_bl_exit);
+module_i2c_driver(tosa_bl_driver);
 
 MODULE_AUTHOR("Dmitry Baryshkov");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c
index 772f601..2231aec 100644
--- a/drivers/video/backlight/tosa_lcd.c
+++ b/drivers/video/backlight/tosa_lcd.c
@@ -271,7 +271,7 @@
 }
 #else
 #define tosa_lcd_suspend	NULL
-#define tosa_lcd_reume NULL
+#define tosa_lcd_resume NULL
 #endif
 
 static struct spi_driver tosa_lcd_driver = {
@@ -285,18 +285,7 @@
 	.resume		= tosa_lcd_resume,
 };
 
-static int __init tosa_lcd_init(void)
-{
-	return spi_register_driver(&tosa_lcd_driver);
-}
-
-static void __exit tosa_lcd_exit(void)
-{
-	spi_unregister_driver(&tosa_lcd_driver);
-}
-
-module_init(tosa_lcd_init);
-module_exit(tosa_lcd_exit);
+module_spi_driver(tosa_lcd_driver);
 
 MODULE_AUTHOR("Dmitry Baryshkov");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/backlight/vgg2432a4.c b/drivers/video/backlight/vgg2432a4.c
index b49063c..b617fae 100644
--- a/drivers/video/backlight/vgg2432a4.c
+++ b/drivers/video/backlight/vgg2432a4.c
@@ -262,20 +262,7 @@
 	.resume		= vgg2432a4_resume,
 };
 
-/* Device driver initialisation */
-
-static int __init vgg2432a4_init(void)
-{
-	return spi_register_driver(&vgg2432a4_driver);
-}
-
-static void __exit vgg2432a4_exit(void)
-{
-	spi_unregister_driver(&vgg2432a4_driver);
-}
-
-module_init(vgg2432a4_init);
-module_exit(vgg2432a4_exit);
+module_spi_driver(vgg2432a4_driver);
 
 MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>");
 MODULE_DESCRIPTION("VGG2432A4 LCD Driver");
diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c
index 4e915f5..5d365de 100644
--- a/drivers/video/backlight/wm831x_bl.c
+++ b/drivers/video/backlight/wm831x_bl.c
@@ -186,7 +186,7 @@
 	if (ret < 0)
 		return ret;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
 	if (data == NULL)
 		return -ENOMEM;
 
@@ -200,7 +200,6 @@
 				       &wm831x_backlight_ops, &props);
 	if (IS_ERR(bl)) {
 		dev_err(&pdev->dev, "failed to register backlight\n");
-		kfree(data);
 		return PTR_ERR(bl);
 	}
 
@@ -211,7 +210,6 @@
 	/* Disable the DCDC if it was started so we can bootstrap */
 	wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, WM831X_DC4_ENA, 0);
 
-
 	backlight_update_status(bl);
 
 	return 0;
@@ -220,10 +218,8 @@
 static int wm831x_backlight_remove(struct platform_device *pdev)
 {
 	struct backlight_device *bl = platform_get_drvdata(pdev);
-	struct wm831x_backlight_data *data = bl_get_data(bl);
 
 	backlight_device_unregister(bl);
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/video/bf537-lq035.c b/drivers/video/bf537-lq035.c
index bea53c1..befbc80 100644
--- a/drivers/video/bf537-lq035.c
+++ b/drivers/video/bf537-lq035.c
@@ -383,23 +383,19 @@
 	}
 
 #if (defined(UD) && defined(LBR))
-	if (gpio_request(UD, KBUILD_MODNAME)) {
+	if (gpio_request_one(UD, GPIOF_OUT_INIT_LOW, KBUILD_MODNAME)) {
 		pr_err("requesting GPIO %d failed\n", UD);
 		return -EBUSY;
 	}
 
-	if (gpio_request(LBR, KBUILD_MODNAME)) {
+	if (gpio_request_one(LBR, GPIOF_OUT_INIT_HIGH, KBUILD_MODNAME)) {
 		pr_err("requesting GPIO %d failed\n", LBR);
 		gpio_free(UD);
 		return -EBUSY;
 	}
-
-	gpio_direction_output(UD, 0);
-	gpio_direction_output(LBR, 1);
-
 #endif
 
-	if (gpio_request(MOD, KBUILD_MODNAME)) {
+	if (gpio_request_one(MOD, GPIOF_OUT_INIT_HIGH, KBUILD_MODNAME)) {
 		pr_err("requesting GPIO %d failed\n", MOD);
 #if (defined(UD) && defined(LBR))
 		gpio_free(LBR);
@@ -408,8 +404,6 @@
 		return -EBUSY;
 	}
 
-	gpio_direction_output(MOD, 1);
-
 	SSYNC();
 	return 0;
 }
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index 46b03f5..dc2f004 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -240,7 +240,7 @@
 	u16 eppi_req_18[] = EPPI0_18;
 	u16 disp = fbi->mach_info->disp;
 
-	if (gpio_request(disp, DRIVER_NAME)) {
+	if (gpio_request_one(disp, GPIOF_OUT_INIT_HIGH, DRIVER_NAME)) {
 		printk(KERN_ERR "Requesting GPIO %d failed\n", disp);
 		return -EFAULT;
 	}
@@ -263,8 +263,6 @@
 		}
 	}
 
-	gpio_direction_output(disp, 1);
-
 	return 0;
 }
 
diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c
index c633068..86922ac 100644
--- a/drivers/video/bfin-lq035q1-fb.c
+++ b/drivers/video/bfin-lq035q1-fb.c
@@ -365,10 +365,10 @@
 	 * Drive PPI_FS3 Low
 	 */
 	if (ANOMALY_05000400) {
-		int ret = gpio_request(P_IDENT(P_PPI0_FS3), "PPI_FS3");
+		int ret = gpio_request_one(P_IDENT(P_PPI0_FS3),
+					GPIOF_OUT_INIT_LOW, "PPI_FS3");
 		if (ret)
 			return ret;
-		gpio_direction_output(P_IDENT(P_PPI0_FS3), 0);
 	}
 
 	if (ppi16)
@@ -716,14 +716,14 @@
 	}
 
 	if (info->disp_info->use_bl) {
-		ret = gpio_request(info->disp_info->gpio_bl, "LQ035 Backlight");
+		ret = gpio_request_one(info->disp_info->gpio_bl,
+					GPIOF_OUT_INIT_LOW, "LQ035 Backlight");
 
 		if (ret) {
 			dev_err(&pdev->dev, "failed to request GPIO %d\n",
 				info->disp_info->gpio_bl);
 			goto out9;
 		}
-		gpio_direction_output(info->disp_info->gpio_bl, 0);
 	}
 
 	ret = register_framebuffer(fbinfo);
diff --git a/drivers/video/bfin_adv7393fb.c b/drivers/video/bfin_adv7393fb.c
index 811dd7f..1a268a2 100644
--- a/drivers/video/bfin_adv7393fb.c
+++ b/drivers/video/bfin_adv7393fb.c
@@ -36,9 +36,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/proc_fs.h>
 #include <linux/platform_device.h>
-
 #include <linux/i2c.h>
-#include <linux/i2c-dev.h>
 
 #include "bfin_adv7393fb.h"
 
@@ -411,12 +409,13 @@
 
 	/* Workaround "PPI Does Not Start Properly In Specific Mode" */
 	if (ANOMALY_05000400) {
-		if (gpio_request(P_IDENT(P_PPI0_FS3), "PPI0_FS3")) {
+		ret = gpio_request_one(P_IDENT(P_PPI0_FS3), GPIOF_OUT_INIT_LOW,
+					"PPI0_FS3")
+		if (ret) {
 			dev_err(&client->dev, "PPI0_FS3 GPIO request failed\n");
 			ret = -EBUSY;
 			goto out_8;
 		}
-		gpio_direction_output(P_IDENT(P_PPI0_FS3), 0);
 	}
 
 	if (peripheral_request_list(ppi_pins, DRIVER_NAME)) {
diff --git a/drivers/video/bt431.h b/drivers/video/bt431.h
index c826f27..04e0cfb 100644
--- a/drivers/video/bt431.h
+++ b/drivers/video/bt431.h
@@ -8,7 +8,6 @@
  *	archive for more details.
  */
 #include <linux/types.h>
-#include <asm/system.h>
 
 /*
  * Bt431 cursor generator registers, 32-bit aligned.
diff --git a/drivers/video/bt455.h b/drivers/video/bt455.h
index b7591fe..80f61b0 100644
--- a/drivers/video/bt455.h
+++ b/drivers/video/bt455.h
@@ -8,7 +8,6 @@
  *	archive for more details.
  */
 #include <linux/types.h>
-#include <asm/system.h>
 
 /*
  * Bt455 byte-wide registers, 32-bit aligned.
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 8745637..2e471c2 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -77,7 +77,6 @@
 #include <linux/crc32.h> /* For counting font checksums */
 #include <asm/fb.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 
 #include "fbcon.h"
 
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index a122d92..6d15966 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -22,7 +22,6 @@
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/gio_device.h>
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
index 8503807..c1527f5 100644
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -51,7 +51,6 @@
 #include <linux/i2c-algo-bit.h>
 
 #include <asm/pgtable.h>
-#include <asm/system.h>
 
 #ifdef __arm__
 #include <asm/mach-types.h>
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index 29577bf..47118c7 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -32,6 +32,7 @@
 #include <linux/console.h>
 #include <linux/slab.h>
 #include <video/da8xx-fb.h>
+#include <asm/div64.h>
 
 #define DRIVER_NAME "da8xx_lcdc"
 
@@ -161,6 +162,7 @@
 	int			vsync_timeout;
 #ifdef CONFIG_CPU_FREQ
 	struct notifier_block	freq_transition;
+	unsigned int		lcd_fck_rate;
 #endif
 	void (*panel_power_ctrl)(int);
 };
@@ -174,7 +176,6 @@
 	.activate = 0,
 	.height = -1,
 	.width = -1,
-	.pixclock = 46666,	/* 46us - AUO display */
 	.accel_flags = 0,
 	.left_margin = LEFT_MARGIN,
 	.right_margin = RIGHT_MARGIN,
@@ -238,6 +239,20 @@
 		.pxl_clk = 7833600,
 		.invert_pxl_clk = 0,
 	},
+	[2] = {
+		/* Hitachi SP10Q010 */
+		.name = "SP10Q010",
+		.width = 320,
+		.height = 240,
+		.hfp = 10,
+		.hbp = 10,
+		.hsw = 10,
+		.vfp = 10,
+		.vbp = 10,
+		.vsw = 10,
+		.pxl_clk = 7833600,
+		.invert_pxl_clk = 0,
+	},
 };
 
 /* Enable the Raster Engine of the LCD Controller */
@@ -546,7 +561,26 @@
 	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR)
 		return 1;
 
-	if (info->var.bits_per_pixel == 8) {
+	if (info->var.bits_per_pixel == 4) {
+		if (regno > 15)
+			return 1;
+
+		if (info->var.grayscale) {
+			pal = regno;
+		} else {
+			red >>= 4;
+			green >>= 8;
+			blue >>= 12;
+
+			pal = (red & 0x0f00);
+			pal |= (green & 0x00f0);
+			pal |= (blue & 0x000f);
+		}
+		if (regno == 0)
+			pal |= 0x2000;
+		palette[regno] = pal;
+
+	} else if (info->var.bits_per_pixel == 8) {
 		red >>= 4;
 		green >>= 8;
 		blue >>= 12;
@@ -801,6 +835,7 @@
 		var->blue.length = 8;
 		var->transp.offset = 0;
 		var->transp.length = 0;
+		var->nonstd = 0;
 		break;
 	case 4:
 		var->red.offset = 0;
@@ -811,6 +846,7 @@
 		var->blue.length = 4;
 		var->transp.offset = 0;
 		var->transp.length = 0;
+		var->nonstd = FB_NONSTD_REV_PIX_IN_B;
 		break;
 	case 16:		/* RGB 565 */
 		var->red.offset = 11;
@@ -821,6 +857,7 @@
 		var->blue.length = 5;
 		var->transp.offset = 0;
 		var->transp.length = 0;
+		var->nonstd = 0;
 		break;
 	default:
 		err = -EINVAL;
@@ -840,11 +877,13 @@
 	struct da8xx_fb_par *par;
 
 	par = container_of(nb, struct da8xx_fb_par, freq_transition);
-	if (val == CPUFREQ_PRECHANGE) {
-		lcd_disable_raster();
-	} else if (val == CPUFREQ_POSTCHANGE) {
-		lcd_calc_clk_divider(par);
-		lcd_enable_raster();
+	if (val == CPUFREQ_POSTCHANGE) {
+		if (par->lcd_fck_rate != clk_get_rate(par->lcdc_clk)) {
+			par->lcd_fck_rate = clk_get_rate(par->lcdc_clk);
+			lcd_disable_raster();
+			lcd_calc_clk_divider(par);
+			lcd_enable_raster();
+		}
 	}
 
 	return 0;
@@ -1048,6 +1087,22 @@
 	.fb_blank = cfb_blank,
 };
 
+/* Calculate and return pixel clock period in pico seconds */
+static unsigned int da8xxfb_pixel_clk_period(struct da8xx_fb_par *par)
+{
+	unsigned int lcd_clk, div;
+	unsigned int configured_pix_clk;
+	unsigned long long pix_clk_period_picosec = 1000000000000ULL;
+
+	lcd_clk = clk_get_rate(par->lcdc_clk);
+	div = lcd_clk / par->pxl_clk;
+	configured_pix_clk = (lcd_clk / div);
+
+	do_div(pix_clk_period_picosec, configured_pix_clk);
+
+	return pix_clk_period_picosec;
+}
+
 static int __devinit fb_probe(struct platform_device *device)
 {
 	struct da8xx_lcdc_platform_data *fb_pdata =
@@ -1137,6 +1192,9 @@
 
 	par = da8xx_fb_info->par;
 	par->lcdc_clk = fb_clk;
+#ifdef CONFIG_CPU_FREQ
+	par->lcd_fck_rate = clk_get_rate(fb_clk);
+#endif
 	par->pxl_clk = lcdc_info->pxl_clk;
 	if (fb_pdata->panel_power_ctrl) {
 		par->panel_power_ctrl = fb_pdata->panel_power_ctrl;
@@ -1209,6 +1267,11 @@
 
 	da8xx_fb_var.hsync_len = lcdc_info->hsw;
 	da8xx_fb_var.vsync_len = lcdc_info->vsw;
+	da8xx_fb_var.right_margin = lcdc_info->hfp;
+	da8xx_fb_var.left_margin  = lcdc_info->hbp;
+	da8xx_fb_var.lower_margin = lcdc_info->vfp;
+	da8xx_fb_var.upper_margin = lcdc_info->vbp;
+	da8xx_fb_var.pixclock = da8xxfb_pixel_clk_period(par);
 
 	/* Initialize fbinfo */
 	da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT;
@@ -1264,8 +1327,8 @@
 irq_freq:
 #ifdef CONFIG_CPU_FREQ
 	lcd_da8xx_cpufreq_deregister(par);
-#endif
 err_cpu_freq:
+#endif
 	unregister_framebuffer(da8xx_fb_info);
 
 err_dealloc_cmap:
diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c
index ec56d25..49e3dda 100644
--- a/drivers/video/dnfb.c
+++ b/drivers/video/dnfb.c
@@ -7,7 +7,6 @@
 #include <linux/platform_device.h>
 
 #include <asm/setup.h>
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c
index 2e830ec5..f8babbe 100644
--- a/drivers/video/ep93xx-fb.c
+++ b/drivers/video/ep93xx-fb.c
@@ -519,12 +519,15 @@
 		goto failed;
 	}
 
-	res = request_mem_region(res->start, resource_size(res), pdev->name);
-	if (!res) {
-		err = -EBUSY;
-		goto failed;
-	}
-
+	/*
+	 * FIXME - We don't do a request_mem_region here because we are
+	 * sharing the register space with the backlight driver (see
+	 * drivers/video/backlight/ep93xx_bl.c) and doing so will cause
+	 * the second loaded driver to return -EBUSY.
+	 *
+	 * NOTE: No locking is required; the backlight does not touch
+	 * any of the framebuffer registers.
+	 */
 	fbi->res = res;
 	fbi->mmio_base = ioremap(res->start, resource_size(res));
 	if (!fbi->mmio_base) {
@@ -586,8 +589,6 @@
 		clk_put(fbi->clk);
 	if (fbi->mmio_base)
 		iounmap(fbi->mmio_base);
-	if (fbi->res)
-		release_mem_region(fbi->res->start, resource_size(fbi->res));
 	ep93xxfb_dealloc_videomem(info);
 	if (&info->cmap)
 		fb_dealloc_cmap(&info->cmap);
@@ -608,7 +609,6 @@
 	clk_disable(fbi->clk);
 	clk_put(fbi->clk);
 	iounmap(fbi->mmio_base);
-	release_mem_region(fbi->res->start, resource_size(fbi->res));
 	ep93xxfb_dealloc_videomem(info);
 	fb_dealloc_cmap(&info->cmap);
 
diff --git a/drivers/video/exynos/Kconfig b/drivers/video/exynos/Kconfig
new file mode 100644
index 0000000..1b035b2e
--- /dev/null
+++ b/drivers/video/exynos/Kconfig
@@ -0,0 +1,37 @@
+#
+# Exynos Video configuration
+#
+
+menuconfig EXYNOS_VIDEO
+	bool "Exynos Video driver support"
+	help
+	  This enables support for EXYNOS Video device.
+
+if EXYNOS_VIDEO
+
+#
+# MIPI DSI driver
+#
+
+config EXYNOS_MIPI_DSI
+	bool "EXYNOS MIPI DSI driver support."
+	depends on ARCH_S5PV210 || ARCH_EXYNOS
+	help
+	  This enables support for MIPI-DSI device.
+
+config EXYNOS_LCD_S6E8AX0
+	bool "S6E8AX0 MIPI AMOLED LCD Driver"
+	depends on (EXYNOS_MIPI_DSI && BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE)
+	default n
+	help
+	  If you have an S6E8AX0 MIPI AMOLED LCD Panel, say Y to enable its
+	  LCD control driver.
+
+config EXYNOS_DP
+	bool "EXYNOS DP driver support"
+	depends on ARCH_EXYNOS
+	default n
+	help
+	  This enables support for DP device.
+
+endif # EXYNOS_VIDEO
diff --git a/drivers/video/exynos/Makefile b/drivers/video/exynos/Makefile
new file mode 100644
index 0000000..ec7772e
--- /dev/null
+++ b/drivers/video/exynos/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the exynos video drivers.
+#
+
+obj-$(CONFIG_EXYNOS_MIPI_DSI)		+= exynos_mipi_dsi.o exynos_mipi_dsi_common.o \
+				     	exynos_mipi_dsi_lowlevel.o
+obj-$(CONFIG_EXYNOS_LCD_S6E8AX0)	+= s6e8ax0.o
+obj-$(CONFIG_EXYNOS_DP)			+= exynos_dp_core.o exynos_dp_reg.o
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
new file mode 100644
index 0000000..2a4481c
--- /dev/null
+++ b/drivers/video/exynos/exynos_dp_core.c
@@ -0,0 +1,1058 @@
+/*
+ * Samsung SoC DP (Display Port) interface driver.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * 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 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/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <video/exynos_dp.h>
+
+#include <plat/cpu.h>
+
+#include "exynos_dp_core.h"
+
+static int exynos_dp_init_dp(struct exynos_dp_device *dp)
+{
+	exynos_dp_reset(dp);
+
+	/* SW defined function Normal operation */
+	exynos_dp_enable_sw_function(dp);
+
+	exynos_dp_config_interrupt(dp);
+	exynos_dp_init_analog_func(dp);
+
+	exynos_dp_init_hpd(dp);
+	exynos_dp_init_aux(dp);
+
+	return 0;
+}
+
+static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)
+{
+	int timeout_loop = 0;
+
+	exynos_dp_init_hpd(dp);
+
+	udelay(200);
+
+	while (exynos_dp_get_plug_in_status(dp) != 0) {
+		timeout_loop++;
+		if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+			dev_err(dp->dev, "failed to get hpd plug status\n");
+			return -ETIMEDOUT;
+		}
+		udelay(10);
+	}
+
+	return 0;
+}
+
+static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data)
+{
+	int i;
+	unsigned char sum = 0;
+
+	for (i = 0; i < EDID_BLOCK_LENGTH; i++)
+		sum = sum + edid_data[i];
+
+	return sum;
+}
+
+static int exynos_dp_read_edid(struct exynos_dp_device *dp)
+{
+	unsigned char edid[EDID_BLOCK_LENGTH * 2];
+	unsigned int extend_block = 0;
+	unsigned char sum;
+	unsigned char test_vector;
+	int retval;
+
+	/*
+	 * EDID device address is 0x50.
+	 * However, if necessary, you must have set upper address
+	 * into E-EDID in I2C device, 0x30.
+	 */
+
+	/* Read Extension Flag, Number of 128-byte EDID extension blocks */
+	exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
+				EDID_EXTENSION_FLAG,
+				&extend_block);
+
+	if (extend_block > 0) {
+		dev_dbg(dp->dev, "EDID data includes a single extension!\n");
+
+		/* Read EDID data */
+		retval = exynos_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
+						EDID_HEADER_PATTERN,
+						EDID_BLOCK_LENGTH,
+						&edid[EDID_HEADER_PATTERN]);
+		if (retval != 0) {
+			dev_err(dp->dev, "EDID Read failed!\n");
+			return -EIO;
+		}
+		sum = exynos_dp_calc_edid_check_sum(edid);
+		if (sum != 0) {
+			dev_err(dp->dev, "EDID bad checksum!\n");
+			return -EIO;
+		}
+
+		/* Read additional EDID data */
+		retval = exynos_dp_read_bytes_from_i2c(dp,
+				I2C_EDID_DEVICE_ADDR,
+				EDID_BLOCK_LENGTH,
+				EDID_BLOCK_LENGTH,
+				&edid[EDID_BLOCK_LENGTH]);
+		if (retval != 0) {
+			dev_err(dp->dev, "EDID Read failed!\n");
+			return -EIO;
+		}
+		sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]);
+		if (sum != 0) {
+			dev_err(dp->dev, "EDID bad checksum!\n");
+			return -EIO;
+		}
+
+		exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST,
+					&test_vector);
+		if (test_vector & DPCD_TEST_EDID_READ) {
+			exynos_dp_write_byte_to_dpcd(dp,
+				DPCD_ADDR_TEST_EDID_CHECKSUM,
+				edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
+			exynos_dp_write_byte_to_dpcd(dp,
+				DPCD_ADDR_TEST_RESPONSE,
+				DPCD_TEST_EDID_CHECKSUM_WRITE);
+		}
+	} else {
+		dev_info(dp->dev, "EDID data does not include any extensions.\n");
+
+		/* Read EDID data */
+		retval = exynos_dp_read_bytes_from_i2c(dp,
+				I2C_EDID_DEVICE_ADDR,
+				EDID_HEADER_PATTERN,
+				EDID_BLOCK_LENGTH,
+				&edid[EDID_HEADER_PATTERN]);
+		if (retval != 0) {
+			dev_err(dp->dev, "EDID Read failed!\n");
+			return -EIO;
+		}
+		sum = exynos_dp_calc_edid_check_sum(edid);
+		if (sum != 0) {
+			dev_err(dp->dev, "EDID bad checksum!\n");
+			return -EIO;
+		}
+
+		exynos_dp_read_byte_from_dpcd(dp,
+			DPCD_ADDR_TEST_REQUEST,
+			&test_vector);
+		if (test_vector & DPCD_TEST_EDID_READ) {
+			exynos_dp_write_byte_to_dpcd(dp,
+				DPCD_ADDR_TEST_EDID_CHECKSUM,
+				edid[EDID_CHECKSUM]);
+			exynos_dp_write_byte_to_dpcd(dp,
+				DPCD_ADDR_TEST_RESPONSE,
+				DPCD_TEST_EDID_CHECKSUM_WRITE);
+		}
+	}
+
+	dev_err(dp->dev, "EDID Read success!\n");
+	return 0;
+}
+
+static int exynos_dp_handle_edid(struct exynos_dp_device *dp)
+{
+	u8 buf[12];
+	int i;
+	int retval;
+
+	/* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */
+	exynos_dp_read_bytes_from_dpcd(dp,
+		DPCD_ADDR_DPCD_REV,
+		12, buf);
+
+	/* Read EDID */
+	for (i = 0; i < 3; i++) {
+		retval = exynos_dp_read_edid(dp);
+		if (retval == 0)
+			break;
+	}
+
+	return retval;
+}
+
+static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp,
+						bool enable)
+{
+	u8 data;
+
+	exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data);
+
+	if (enable)
+		exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
+			DPCD_ENHANCED_FRAME_EN |
+			DPCD_LANE_COUNT_SET(data));
+	else
+		exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
+			DPCD_LANE_COUNT_SET(data));
+}
+
+static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp)
+{
+	u8 data;
+	int retval;
+
+	exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
+	retval = DPCD_ENHANCED_FRAME_CAP(data);
+
+	return retval;
+}
+
+static void exynos_dp_set_enhanced_mode(struct exynos_dp_device *dp)
+{
+	u8 data;
+
+	data = exynos_dp_is_enhanced_mode_available(dp);
+	exynos_dp_enable_rx_to_enhanced_mode(dp, data);
+	exynos_dp_enable_enhanced_mode(dp, data);
+}
+
+static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp)
+{
+	exynos_dp_set_training_pattern(dp, DP_NONE);
+
+	exynos_dp_write_byte_to_dpcd(dp,
+		DPCD_ADDR_TRAINING_PATTERN_SET,
+		DPCD_TRAINING_PATTERN_DISABLED);
+}
+
+static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp,
+					int pre_emphasis, int lane)
+{
+	switch (lane) {
+	case 0:
+		exynos_dp_set_lane0_pre_emphasis(dp, pre_emphasis);
+		break;
+	case 1:
+		exynos_dp_set_lane1_pre_emphasis(dp, pre_emphasis);
+		break;
+
+	case 2:
+		exynos_dp_set_lane2_pre_emphasis(dp, pre_emphasis);
+		break;
+
+	case 3:
+		exynos_dp_set_lane3_pre_emphasis(dp, pre_emphasis);
+		break;
+	}
+}
+
+static void exynos_dp_link_start(struct exynos_dp_device *dp)
+{
+	u8 buf[5];
+	int lane;
+	int lane_count;
+
+	lane_count = dp->link_train.lane_count;
+
+	dp->link_train.lt_state = CLOCK_RECOVERY;
+	dp->link_train.eq_loop = 0;
+
+	for (lane = 0; lane < lane_count; lane++)
+		dp->link_train.cr_loop[lane] = 0;
+
+	/* Set sink to D0 (Sink Not Ready) mode. */
+	exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE,
+				DPCD_SET_POWER_STATE_D0);
+
+	/* Set link rate and count as you want to establish*/
+	exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
+	exynos_dp_set_lane_count(dp, dp->link_train.lane_count);
+
+	/* Setup RX configuration */
+	buf[0] = dp->link_train.link_rate;
+	buf[1] = dp->link_train.lane_count;
+	exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET,
+				2, buf);
+
+	/* Set TX pre-emphasis to minimum */
+	for (lane = 0; lane < lane_count; lane++)
+		exynos_dp_set_lane_lane_pre_emphasis(dp,
+			PRE_EMPHASIS_LEVEL_0, lane);
+
+	/* Set training pattern 1 */
+	exynos_dp_set_training_pattern(dp, TRAINING_PTN1);
+
+	/* Set RX training pattern */
+	buf[0] = DPCD_SCRAMBLING_DISABLED |
+		 DPCD_TRAINING_PATTERN_1;
+	exynos_dp_write_byte_to_dpcd(dp,
+		DPCD_ADDR_TRAINING_PATTERN_SET, buf[0]);
+
+	for (lane = 0; lane < lane_count; lane++)
+		buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
+			    DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0;
+	exynos_dp_write_bytes_to_dpcd(dp,
+		DPCD_ADDR_TRAINING_PATTERN_SET,
+		lane_count, buf);
+}
+
+static unsigned char exynos_dp_get_lane_status(u8 link_status[6], int lane)
+{
+	int shift = (lane & 1) * 4;
+	u8 link_value = link_status[lane>>1];
+
+	return (link_value >> shift) & 0xf;
+}
+
+static int exynos_dp_clock_recovery_ok(u8 link_status[6], int lane_count)
+{
+	int lane;
+	u8 lane_status;
+
+	for (lane = 0; lane < lane_count; lane++) {
+		lane_status = exynos_dp_get_lane_status(link_status, lane);
+		if ((lane_status & DPCD_LANE_CR_DONE) == 0)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int exynos_dp_channel_eq_ok(u8 link_status[6], int lane_count)
+{
+	int lane;
+	u8 lane_align;
+	u8 lane_status;
+
+	lane_align = link_status[2];
+	if ((lane_align == DPCD_INTERLANE_ALIGN_DONE) == 0)
+		return -EINVAL;
+
+	for (lane = 0; lane < lane_count; lane++) {
+		lane_status = exynos_dp_get_lane_status(link_status, lane);
+		lane_status &= DPCD_CHANNEL_EQ_BITS;
+		if (lane_status != DPCD_CHANNEL_EQ_BITS)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static unsigned char exynos_dp_get_adjust_request_voltage(u8 adjust_request[2],
+							int lane)
+{
+	int shift = (lane & 1) * 4;
+	u8 link_value = adjust_request[lane>>1];
+
+	return (link_value >> shift) & 0x3;
+}
+
+static unsigned char exynos_dp_get_adjust_request_pre_emphasis(
+					u8 adjust_request[2],
+					int lane)
+{
+	int shift = (lane & 1) * 4;
+	u8 link_value = adjust_request[lane>>1];
+
+	return ((link_value >> shift) & 0xc) >> 2;
+}
+
+static void exynos_dp_set_lane_link_training(struct exynos_dp_device *dp,
+					u8 training_lane_set, int lane)
+{
+	switch (lane) {
+	case 0:
+		exynos_dp_set_lane0_link_training(dp, training_lane_set);
+		break;
+	case 1:
+		exynos_dp_set_lane1_link_training(dp, training_lane_set);
+		break;
+
+	case 2:
+		exynos_dp_set_lane2_link_training(dp, training_lane_set);
+		break;
+
+	case 3:
+		exynos_dp_set_lane3_link_training(dp, training_lane_set);
+		break;
+	}
+}
+
+static unsigned int exynos_dp_get_lane_link_training(
+				struct exynos_dp_device *dp,
+				int lane)
+{
+	u32 reg;
+
+	switch (lane) {
+	case 0:
+		reg = exynos_dp_get_lane0_link_training(dp);
+		break;
+	case 1:
+		reg = exynos_dp_get_lane1_link_training(dp);
+		break;
+	case 2:
+		reg = exynos_dp_get_lane2_link_training(dp);
+		break;
+	case 3:
+		reg = exynos_dp_get_lane3_link_training(dp);
+		break;
+	}
+
+	return reg;
+}
+
+static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp)
+{
+	if (dp->link_train.link_rate == LINK_RATE_2_70GBPS) {
+		/* set to reduced bit rate */
+		dp->link_train.link_rate = LINK_RATE_1_62GBPS;
+		dev_err(dp->dev, "set to bandwidth %.2x\n",
+			dp->link_train.link_rate);
+		dp->link_train.lt_state = START;
+	} else {
+		exynos_dp_training_pattern_dis(dp);
+		/* set enhanced mode if available */
+		exynos_dp_set_enhanced_mode(dp);
+		dp->link_train.lt_state = FAILED;
+	}
+}
+
+static void exynos_dp_get_adjust_train(struct exynos_dp_device *dp,
+				u8 adjust_request[2])
+{
+	int lane;
+	int lane_count;
+	u8 voltage_swing;
+	u8 pre_emphasis;
+	u8 training_lane;
+
+	lane_count = dp->link_train.lane_count;
+	for (lane = 0; lane < lane_count; lane++) {
+		voltage_swing = exynos_dp_get_adjust_request_voltage(
+						adjust_request, lane);
+		pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
+						adjust_request, lane);
+		training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
+				DPCD_PRE_EMPHASIS_SET(pre_emphasis);
+
+		if (voltage_swing == VOLTAGE_LEVEL_3 ||
+		   pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
+			training_lane |= DPCD_MAX_SWING_REACHED;
+			training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
+		}
+		dp->link_train.training_lane[lane] = training_lane;
+	}
+}
+
+static int exynos_dp_check_max_cr_loop(struct exynos_dp_device *dp,
+					u8 voltage_swing)
+{
+	int lane;
+	int lane_count;
+
+	lane_count = dp->link_train.lane_count;
+	for (lane = 0; lane < lane_count; lane++) {
+		if (voltage_swing == VOLTAGE_LEVEL_3 ||
+			dp->link_train.cr_loop[lane] == MAX_CR_LOOP)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
+{
+	u8 data;
+	u8 link_status[6];
+	int lane;
+	int lane_count;
+	u8 buf[5];
+
+	u8 *adjust_request;
+	u8 voltage_swing;
+	u8 pre_emphasis;
+	u8 training_lane;
+
+	udelay(100);
+
+	exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,
+				6, link_status);
+	lane_count = dp->link_train.lane_count;
+
+	if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
+		/* set training pattern 2 for EQ */
+		exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
+
+		adjust_request = link_status + (DPCD_ADDR_ADJUST_REQUEST_LANE0_1
+						- DPCD_ADDR_LANE0_1_STATUS);
+
+		exynos_dp_get_adjust_train(dp, adjust_request);
+
+		buf[0] = DPCD_SCRAMBLING_DISABLED |
+			 DPCD_TRAINING_PATTERN_2;
+		exynos_dp_write_byte_to_dpcd(dp,
+			DPCD_ADDR_TRAINING_LANE0_SET,
+			buf[0]);
+
+		for (lane = 0; lane < lane_count; lane++) {
+			exynos_dp_set_lane_link_training(dp,
+				dp->link_train.training_lane[lane],
+				lane);
+			buf[lane] = dp->link_train.training_lane[lane];
+			exynos_dp_write_byte_to_dpcd(dp,
+				DPCD_ADDR_TRAINING_LANE0_SET + lane,
+				buf[lane]);
+		}
+		dp->link_train.lt_state = EQUALIZER_TRAINING;
+	} else {
+		exynos_dp_read_byte_from_dpcd(dp,
+			DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
+			&data);
+		adjust_request[0] = data;
+
+		exynos_dp_read_byte_from_dpcd(dp,
+			DPCD_ADDR_ADJUST_REQUEST_LANE2_3,
+			&data);
+		adjust_request[1] = data;
+
+		for (lane = 0; lane < lane_count; lane++) {
+			training_lane = exynos_dp_get_lane_link_training(
+							dp, lane);
+			voltage_swing = exynos_dp_get_adjust_request_voltage(
+							adjust_request, lane);
+			pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
+							adjust_request, lane);
+			if ((DPCD_VOLTAGE_SWING_GET(training_lane) == voltage_swing) &&
+			    (DPCD_PRE_EMPHASIS_GET(training_lane) == pre_emphasis))
+				dp->link_train.cr_loop[lane]++;
+			dp->link_train.training_lane[lane] = training_lane;
+		}
+
+		if (exynos_dp_check_max_cr_loop(dp, voltage_swing) != 0) {
+			exynos_dp_reduce_link_rate(dp);
+		} else {
+			exynos_dp_get_adjust_train(dp, adjust_request);
+
+			for (lane = 0; lane < lane_count; lane++) {
+				exynos_dp_set_lane_link_training(dp,
+					dp->link_train.training_lane[lane],
+					lane);
+				buf[lane] = dp->link_train.training_lane[lane];
+				exynos_dp_write_byte_to_dpcd(dp,
+					DPCD_ADDR_TRAINING_LANE0_SET + lane,
+					buf[lane]);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
+{
+	u8 link_status[6];
+	int lane;
+	int lane_count;
+	u8 buf[5];
+	u32 reg;
+
+	u8 *adjust_request;
+
+	udelay(400);
+
+	exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,
+				6, link_status);
+	lane_count = dp->link_train.lane_count;
+
+	if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
+		adjust_request = link_status + (DPCD_ADDR_ADJUST_REQUEST_LANE0_1
+						- DPCD_ADDR_LANE0_1_STATUS);
+
+		if (exynos_dp_channel_eq_ok(link_status, lane_count) == 0) {
+			/* traing pattern Set to Normal */
+			exynos_dp_training_pattern_dis(dp);
+
+			dev_info(dp->dev, "Link Training success!\n");
+
+			exynos_dp_get_link_bandwidth(dp, &reg);
+			dp->link_train.link_rate = reg;
+			dev_dbg(dp->dev, "final bandwidth = %.2x\n",
+				dp->link_train.link_rate);
+
+			exynos_dp_get_lane_count(dp, &reg);
+			dp->link_train.lane_count = reg;
+			dev_dbg(dp->dev, "final lane count = %.2x\n",
+				dp->link_train.lane_count);
+			/* set enhanced mode if available */
+			exynos_dp_set_enhanced_mode(dp);
+
+			dp->link_train.lt_state = FINISHED;
+		} else {
+			/* not all locked */
+			dp->link_train.eq_loop++;
+
+			if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
+				exynos_dp_reduce_link_rate(dp);
+			} else {
+				exynos_dp_get_adjust_train(dp, adjust_request);
+
+				for (lane = 0; lane < lane_count; lane++) {
+					exynos_dp_set_lane_link_training(dp,
+						dp->link_train.training_lane[lane],
+						lane);
+					buf[lane] = dp->link_train.training_lane[lane];
+					exynos_dp_write_byte_to_dpcd(dp,
+						DPCD_ADDR_TRAINING_LANE0_SET + lane,
+						buf[lane]);
+				}
+			}
+		}
+	} else {
+		exynos_dp_reduce_link_rate(dp);
+	}
+
+	return 0;
+}
+
+static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
+			u8 *bandwidth)
+{
+	u8 data;
+
+	/*
+	 * For DP rev.1.1, Maximum link rate of Main Link lanes
+	 * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
+	 */
+	exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data);
+	*bandwidth = data;
+}
+
+static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp,
+			u8 *lane_count)
+{
+	u8 data;
+
+	/*
+	 * For DP rev.1.1, Maximum number of Main Link lanes
+	 * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
+	 */
+	exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
+	*lane_count = DPCD_MAX_LANE_COUNT(data);
+}
+
+static void exynos_dp_init_training(struct exynos_dp_device *dp,
+			enum link_lane_count_type max_lane,
+			enum link_rate_type max_rate)
+{
+	/*
+	 * MACRO_RST must be applied after the PLL_LOCK to avoid
+	 * the DP inter pair skew issue for at least 10 us
+	 */
+	exynos_dp_reset_macro(dp);
+
+	/* Initialize by reading RX's DPCD */
+	exynos_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
+	exynos_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
+
+	if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
+	   (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
+		dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n",
+			dp->link_train.link_rate);
+		dp->link_train.link_rate = LINK_RATE_1_62GBPS;
+	}
+
+	if (dp->link_train.lane_count == 0) {
+		dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n",
+			dp->link_train.lane_count);
+		dp->link_train.lane_count = (u8)LANE_COUNT1;
+	}
+
+	/* Setup TX lane count & rate */
+	if (dp->link_train.lane_count > max_lane)
+		dp->link_train.lane_count = max_lane;
+	if (dp->link_train.link_rate > max_rate)
+		dp->link_train.link_rate = max_rate;
+
+	/* All DP analog module power up */
+	exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
+}
+
+static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
+{
+	int retval = 0;
+	int training_finished;
+
+	/* Turn off unnecessary lane */
+	if (dp->link_train.lane_count == 1)
+		exynos_dp_set_analog_power_down(dp, CH1_BLOCK, 1);
+
+	training_finished = 0;
+
+	dp->link_train.lt_state = START;
+
+	/* Process here */
+	while (!training_finished) {
+		switch (dp->link_train.lt_state) {
+		case START:
+			exynos_dp_link_start(dp);
+			break;
+		case CLOCK_RECOVERY:
+			exynos_dp_process_clock_recovery(dp);
+			break;
+		case EQUALIZER_TRAINING:
+			exynos_dp_process_equalizer_training(dp);
+			break;
+		case FINISHED:
+			training_finished = 1;
+			break;
+		case FAILED:
+			return -EREMOTEIO;
+		}
+	}
+
+	return retval;
+}
+
+static int exynos_dp_set_link_train(struct exynos_dp_device *dp,
+				u32 count,
+				u32 bwtype)
+{
+	int i;
+	int retval;
+
+	for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) {
+		exynos_dp_init_training(dp, count, bwtype);
+		retval = exynos_dp_sw_link_training(dp);
+		if (retval == 0)
+			break;
+
+		udelay(100);
+	}
+
+	return retval;
+}
+
+static int exynos_dp_config_video(struct exynos_dp_device *dp,
+			struct video_info *video_info)
+{
+	int retval = 0;
+	int timeout_loop = 0;
+	int done_count = 0;
+
+	exynos_dp_config_video_slave_mode(dp, video_info);
+
+	exynos_dp_set_video_color_format(dp, video_info->color_depth,
+			video_info->color_space,
+			video_info->dynamic_range,
+			video_info->ycbcr_coeff);
+
+	if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+		dev_err(dp->dev, "PLL is not locked yet.\n");
+		return -EINVAL;
+	}
+
+	for (;;) {
+		timeout_loop++;
+		if (exynos_dp_is_slave_video_stream_clock_on(dp) == 0)
+			break;
+		if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+			dev_err(dp->dev, "Timeout of video streamclk ok\n");
+			return -ETIMEDOUT;
+		}
+
+		mdelay(100);
+	}
+
+	/* Set to use the register calculated M/N video */
+	exynos_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
+
+	/* For video bist, Video timing must be generated by register */
+	exynos_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE);
+
+	/* Disable video mute */
+	exynos_dp_enable_video_mute(dp, 0);
+
+	/* Configure video slave mode */
+	exynos_dp_enable_video_master(dp, 0);
+
+	/* Enable video */
+	exynos_dp_start_video(dp);
+
+	timeout_loop = 0;
+
+	for (;;) {
+		timeout_loop++;
+		if (exynos_dp_is_video_stream_on(dp) == 0) {
+			done_count++;
+			if (done_count > 10)
+				break;
+		} else if (done_count) {
+			done_count = 0;
+		}
+		if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+			dev_err(dp->dev, "Timeout of video streamclk ok\n");
+			return -ETIMEDOUT;
+		}
+
+		mdelay(100);
+	}
+
+	if (retval != 0)
+		dev_err(dp->dev, "Video stream is not detected!\n");
+
+	return retval;
+}
+
+static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable)
+{
+	u8 data;
+
+	if (enable) {
+		exynos_dp_enable_scrambling(dp);
+
+		exynos_dp_read_byte_from_dpcd(dp,
+			DPCD_ADDR_TRAINING_PATTERN_SET,
+			&data);
+		exynos_dp_write_byte_to_dpcd(dp,
+			DPCD_ADDR_TRAINING_PATTERN_SET,
+			(u8)(data & ~DPCD_SCRAMBLING_DISABLED));
+	} else {
+		exynos_dp_disable_scrambling(dp);
+
+		exynos_dp_read_byte_from_dpcd(dp,
+			DPCD_ADDR_TRAINING_PATTERN_SET,
+			&data);
+		exynos_dp_write_byte_to_dpcd(dp,
+			DPCD_ADDR_TRAINING_PATTERN_SET,
+			(u8)(data | DPCD_SCRAMBLING_DISABLED));
+	}
+}
+
+static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
+{
+	struct exynos_dp_device *dp = arg;
+
+	dev_err(dp->dev, "exynos_dp_irq_handler\n");
+	return IRQ_HANDLED;
+}
+
+static int __devinit exynos_dp_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct exynos_dp_device *dp;
+	struct exynos_dp_platdata *pdata;
+
+	int ret = 0;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data\n");
+		return -EINVAL;
+	}
+
+	dp = kzalloc(sizeof(struct exynos_dp_device), GFP_KERNEL);
+	if (!dp) {
+		dev_err(&pdev->dev, "no memory for device data\n");
+		return -ENOMEM;
+	}
+
+	dp->dev = &pdev->dev;
+
+	dp->clock = clk_get(&pdev->dev, "dp");
+	if (IS_ERR(dp->clock)) {
+		dev_err(&pdev->dev, "failed to get clock\n");
+		ret = PTR_ERR(dp->clock);
+		goto err_dp;
+	}
+
+	clk_enable(dp->clock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get registers\n");
+		ret = -EINVAL;
+		goto err_clock;
+	}
+
+	res = request_mem_region(res->start, resource_size(res),
+				dev_name(&pdev->dev));
+	if (!res) {
+		dev_err(&pdev->dev, "failed to request registers region\n");
+		ret = -EINVAL;
+		goto err_clock;
+	}
+
+	dp->res = res;
+
+	dp->reg_base = ioremap(res->start, resource_size(res));
+	if (!dp->reg_base) {
+		dev_err(&pdev->dev, "failed to ioremap\n");
+		ret = -ENOMEM;
+		goto err_req_region;
+	}
+
+	dp->irq = platform_get_irq(pdev, 0);
+	if (!dp->irq) {
+		dev_err(&pdev->dev, "failed to get irq\n");
+		ret = -ENODEV;
+		goto err_ioremap;
+	}
+
+	ret = request_irq(dp->irq, exynos_dp_irq_handler, 0,
+			"exynos-dp", dp);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to request irq\n");
+		goto err_ioremap;
+	}
+
+	dp->video_info = pdata->video_info;
+	if (pdata->phy_init)
+		pdata->phy_init();
+
+	exynos_dp_init_dp(dp);
+
+	ret = exynos_dp_detect_hpd(dp);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to detect hpd\n");
+		goto err_irq;
+	}
+
+	exynos_dp_handle_edid(dp);
+
+	ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count,
+				dp->video_info->link_rate);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to do link train\n");
+		goto err_irq;
+	}
+
+	exynos_dp_enable_scramble(dp, 1);
+	exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
+	exynos_dp_enable_enhanced_mode(dp, 1);
+
+	exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
+	exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
+
+	exynos_dp_init_video(dp);
+	ret = exynos_dp_config_video(dp, dp->video_info);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to config video\n");
+		goto err_irq;
+	}
+
+	platform_set_drvdata(pdev, dp);
+
+	return 0;
+
+err_irq:
+	free_irq(dp->irq, dp);
+err_ioremap:
+	iounmap(dp->reg_base);
+err_req_region:
+	release_mem_region(res->start, resource_size(res));
+err_clock:
+	clk_put(dp->clock);
+err_dp:
+	kfree(dp);
+
+	return ret;
+}
+
+static int __devexit exynos_dp_remove(struct platform_device *pdev)
+{
+	struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
+	struct exynos_dp_device *dp = platform_get_drvdata(pdev);
+
+	if (pdata && pdata->phy_exit)
+		pdata->phy_exit();
+
+	free_irq(dp->irq, dp);
+	iounmap(dp->reg_base);
+
+	clk_disable(dp->clock);
+	clk_put(dp->clock);
+
+	release_mem_region(dp->res->start, resource_size(dp->res));
+
+	kfree(dp);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int exynos_dp_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
+	struct exynos_dp_device *dp = platform_get_drvdata(pdev);
+
+	if (pdata && pdata->phy_exit)
+		pdata->phy_exit();
+
+	clk_disable(dp->clock);
+
+	return 0;
+}
+
+static int exynos_dp_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
+	struct exynos_dp_device *dp = platform_get_drvdata(pdev);
+
+	if (pdata && pdata->phy_init)
+		pdata->phy_init();
+
+	clk_enable(dp->clock);
+
+	exynos_dp_init_dp(dp);
+
+	exynos_dp_detect_hpd(dp);
+	exynos_dp_handle_edid(dp);
+
+	exynos_dp_set_link_train(dp, dp->video_info->lane_count,
+				dp->video_info->link_rate);
+
+	exynos_dp_enable_scramble(dp, 1);
+	exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
+	exynos_dp_enable_enhanced_mode(dp, 1);
+
+	exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
+	exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
+
+	exynos_dp_init_video(dp);
+	exynos_dp_config_video(dp, dp->video_info);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos_dp_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume)
+};
+
+static struct platform_driver exynos_dp_driver = {
+	.probe		= exynos_dp_probe,
+	.remove		= __devexit_p(exynos_dp_remove),
+	.driver		= {
+		.name	= "exynos-dp",
+		.owner	= THIS_MODULE,
+		.pm	= &exynos_dp_pm_ops,
+	},
+};
+
+module_platform_driver(exynos_dp_driver);
+
+MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
+MODULE_DESCRIPTION("Samsung SoC DP Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h
new file mode 100644
index 0000000..90ceaca
--- /dev/null
+++ b/drivers/video/exynos/exynos_dp_core.h
@@ -0,0 +1,206 @@
+/*
+ * Header file for Samsung DP (Display Port) interface driver.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * 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 as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _EXYNOS_DP_CORE_H
+#define _EXYNOS_DP_CORE_H
+
+struct link_train {
+	int eq_loop;
+	int cr_loop[4];
+
+	u8 link_rate;
+	u8 lane_count;
+	u8 training_lane[4];
+
+	enum link_training_state lt_state;
+};
+
+struct exynos_dp_device {
+	struct device		*dev;
+	struct resource		*res;
+	struct clk		*clock;
+	unsigned int		irq;
+	void __iomem		*reg_base;
+
+	struct video_info	*video_info;
+	struct link_train	link_train;
+};
+
+/* exynos_dp_reg.c */
+void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_stop_video(struct exynos_dp_device *dp);
+void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_init_interrupt(struct exynos_dp_device *dp);
+void exynos_dp_reset(struct exynos_dp_device *dp);
+void exynos_dp_config_interrupt(struct exynos_dp_device *dp);
+u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp);
+void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
+				enum analog_power_block block,
+				bool enable);
+void exynos_dp_init_analog_func(struct exynos_dp_device *dp);
+void exynos_dp_init_hpd(struct exynos_dp_device *dp);
+void exynos_dp_reset_aux(struct exynos_dp_device *dp);
+void exynos_dp_init_aux(struct exynos_dp_device *dp);
+int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp);
+void exynos_dp_enable_sw_function(struct exynos_dp_device *dp);
+int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp);
+int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned char data);
+int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned char *data);
+int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned int count,
+				unsigned char data[]);
+int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned int count,
+				unsigned char data[]);
+int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
+				unsigned int device_addr,
+				unsigned int reg_addr);
+int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
+				unsigned int device_addr,
+				unsigned int reg_addr,
+				unsigned int *data);
+int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
+				unsigned int device_addr,
+				unsigned int reg_addr,
+				unsigned int count,
+				unsigned char edid[]);
+void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype);
+void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype);
+void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count);
+void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count);
+void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype);
+void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype);
+void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count);
+void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count);
+void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
+				 enum pattern_set pattern);
+void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp,
+				u32 training_lane);
+void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp,
+				u32 training_lane);
+void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp,
+				u32 training_lane);
+void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp,
+				u32 training_lane);
+u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp);
+u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp);
+u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp);
+u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp);
+void exynos_dp_reset_macro(struct exynos_dp_device *dp);
+int exynos_dp_init_video(struct exynos_dp_device *dp);
+
+void exynos_dp_set_video_color_format(struct exynos_dp_device *dp,
+				u32 color_depth,
+				u32 color_space,
+				u32 dynamic_range,
+				u32 ycbcr_coeff);
+int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp);
+void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
+			enum clock_recovery_m_value_type type,
+			u32 m_value,
+			u32 n_value);
+void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type);
+void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_start_video(struct exynos_dp_device *dp);
+int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp);
+void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp,
+			struct video_info *video_info);
+void exynos_dp_enable_scrambling(struct exynos_dp_device *dp);
+void exynos_dp_disable_scrambling(struct exynos_dp_device *dp);
+
+/* I2C EDID Chip ID, Slave Address */
+#define I2C_EDID_DEVICE_ADDR			0x50
+#define I2C_E_EDID_DEVICE_ADDR			0x30
+
+#define EDID_BLOCK_LENGTH			0x80
+#define EDID_HEADER_PATTERN			0x00
+#define EDID_EXTENSION_FLAG			0x7e
+#define EDID_CHECKSUM				0x7f
+
+/* Definition for DPCD Register */
+#define DPCD_ADDR_DPCD_REV			0x0000
+#define DPCD_ADDR_MAX_LINK_RATE			0x0001
+#define DPCD_ADDR_MAX_LANE_COUNT		0x0002
+#define DPCD_ADDR_LINK_BW_SET			0x0100
+#define DPCD_ADDR_LANE_COUNT_SET		0x0101
+#define DPCD_ADDR_TRAINING_PATTERN_SET		0x0102
+#define DPCD_ADDR_TRAINING_LANE0_SET		0x0103
+#define DPCD_ADDR_LANE0_1_STATUS		0x0202
+#define DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED	0x0204
+#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1	0x0206
+#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3	0x0207
+#define DPCD_ADDR_TEST_REQUEST			0x0218
+#define DPCD_ADDR_TEST_RESPONSE			0x0260
+#define DPCD_ADDR_TEST_EDID_CHECKSUM		0x0261
+#define DPCD_ADDR_SINK_POWER_STATE		0x0600
+
+/* DPCD_ADDR_MAX_LANE_COUNT */
+#define DPCD_ENHANCED_FRAME_CAP(x)		(((x) >> 7) & 0x1)
+#define DPCD_MAX_LANE_COUNT(x)			((x) & 0x1f)
+
+/* DPCD_ADDR_LANE_COUNT_SET */
+#define DPCD_ENHANCED_FRAME_EN			(0x1 << 7)
+#define DPCD_LANE_COUNT_SET(x)			((x) & 0x1f)
+
+/* DPCD_ADDR_TRAINING_PATTERN_SET */
+#define DPCD_SCRAMBLING_DISABLED		(0x1 << 5)
+#define DPCD_SCRAMBLING_ENABLED			(0x0 << 5)
+#define DPCD_TRAINING_PATTERN_2			(0x2 << 0)
+#define DPCD_TRAINING_PATTERN_1			(0x1 << 0)
+#define DPCD_TRAINING_PATTERN_DISABLED		(0x0 << 0)
+
+/* DPCD_ADDR_TRAINING_LANE0_SET */
+#define DPCD_MAX_PRE_EMPHASIS_REACHED		(0x1 << 5)
+#define DPCD_PRE_EMPHASIS_SET(x)		(((x) & 0x3) << 3)
+#define DPCD_PRE_EMPHASIS_GET(x)		(((x) >> 3) & 0x3)
+#define DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0	(0x0 << 3)
+#define DPCD_MAX_SWING_REACHED			(0x1 << 2)
+#define DPCD_VOLTAGE_SWING_SET(x)		(((x) & 0x3) << 0)
+#define DPCD_VOLTAGE_SWING_GET(x)		(((x) >> 0) & 0x3)
+#define DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0	(0x0 << 0)
+
+/* DPCD_ADDR_LANE0_1_STATUS */
+#define DPCD_LANE_SYMBOL_LOCKED			(0x1 << 2)
+#define DPCD_LANE_CHANNEL_EQ_DONE		(0x1 << 1)
+#define DPCD_LANE_CR_DONE			(0x1 << 0)
+#define DPCD_CHANNEL_EQ_BITS			(DPCD_LANE_CR_DONE|	\
+						 DPCD_LANE_CHANNEL_EQ_DONE|\
+						 DPCD_LANE_SYMBOL_LOCKED)
+
+/* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */
+#define DPCD_LINK_STATUS_UPDATED		(0x1 << 7)
+#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED	(0x1 << 6)
+#define DPCD_INTERLANE_ALIGN_DONE		(0x1 << 0)
+
+/* DPCD_ADDR_TEST_REQUEST */
+#define DPCD_TEST_EDID_READ			(0x1 << 2)
+
+/* DPCD_ADDR_TEST_RESPONSE */
+#define DPCD_TEST_EDID_CHECKSUM_WRITE		(0x1 << 2)
+
+/* DPCD_ADDR_SINK_POWER_STATE */
+#define DPCD_SET_POWER_STATE_D0			(0x1 << 0)
+#define DPCD_SET_POWER_STATE_D4			(0x2 << 0)
+
+#endif /* _EXYNOS_DP_CORE_H */
diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c
new file mode 100644
index 0000000..6548afa
--- /dev/null
+++ b/drivers/video/exynos/exynos_dp_reg.c
@@ -0,0 +1,1173 @@
+/*
+ * Samsung DP (Display port) register interface driver.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * 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 as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include <video/exynos_dp.h>
+
+#include <plat/cpu.h>
+
+#include "exynos_dp_core.h"
+#include "exynos_dp_reg.h"
+
+#define COMMON_INT_MASK_1 (0)
+#define COMMON_INT_MASK_2 (0)
+#define COMMON_INT_MASK_3 (0)
+#define COMMON_INT_MASK_4 (0)
+#define INT_STA_MASK (0)
+
+void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable)
+{
+	u32 reg;
+
+	if (enable) {
+		reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+		reg |= HDCP_VIDEO_MUTE;
+		writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+	} else {
+		reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+		reg &= ~HDCP_VIDEO_MUTE;
+		writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+	}
+}
+
+void exynos_dp_stop_video(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+	reg &= ~VIDEO_EN;
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+}
+
+void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable)
+{
+	u32 reg;
+
+	if (enable)
+		reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
+			LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
+	else
+		reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
+			LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
+
+	writel(reg, dp->reg_base + EXYNOS_DP_LANE_MAP);
+}
+
+void exynos_dp_init_interrupt(struct exynos_dp_device *dp)
+{
+	/* Set interrupt pin assertion polarity as high */
+	writel(INT_POL, dp->reg_base + EXYNOS_DP_INT_CTL);
+
+	/* Clear pending regisers */
+	writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
+	writel(0x4f, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_2);
+	writel(0xe0, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_3);
+	writel(0xe7, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
+	writel(0x63, dp->reg_base + EXYNOS_DP_INT_STA);
+
+	/* 0:mask,1: unmask */
+	writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1);
+	writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2);
+	writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3);
+	writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4);
+	writel(0x00, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
+}
+
+void exynos_dp_reset(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	writel(RESET_DP_TX, dp->reg_base + EXYNOS_DP_TX_SW_RESET);
+
+	exynos_dp_stop_video(dp);
+	exynos_dp_enable_video_mute(dp, 0);
+
+	reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
+		AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
+		HDCP_FUNC_EN_N | SW_FUNC_EN_N;
+	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+
+	reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
+		SERDES_FIFO_FUNC_EN_N |
+		LS_CLK_DOMAIN_FUNC_EN_N;
+	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+
+	udelay(20);
+
+	exynos_dp_lane_swap(dp, 0);
+
+	writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+	writel(0x40, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+	writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+	writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+
+	writel(0x0, dp->reg_base + EXYNOS_DP_PKT_SEND_CTL);
+	writel(0x0, dp->reg_base + EXYNOS_DP_HDCP_CTL);
+
+	writel(0x5e, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_L);
+	writel(0x1a, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_H);
+
+	writel(0x10, dp->reg_base + EXYNOS_DP_LINK_DEBUG_CTL);
+
+	writel(0x0, dp->reg_base + EXYNOS_DP_PHY_TEST);
+
+	writel(0x0, dp->reg_base + EXYNOS_DP_VIDEO_FIFO_THRD);
+	writel(0x20, dp->reg_base + EXYNOS_DP_AUDIO_MARGIN);
+
+	writel(0x4, dp->reg_base + EXYNOS_DP_M_VID_GEN_FILTER_TH);
+	writel(0x2, dp->reg_base + EXYNOS_DP_M_AUD_GEN_FILTER_TH);
+
+	writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+
+	exynos_dp_init_interrupt(dp);
+}
+
+void exynos_dp_config_interrupt(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	/* 0: mask, 1: unmask */
+	reg = COMMON_INT_MASK_1;
+	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1);
+
+	reg = COMMON_INT_MASK_2;
+	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2);
+
+	reg = COMMON_INT_MASK_3;
+	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3);
+
+	reg = COMMON_INT_MASK_4;
+	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4);
+
+	reg = INT_STA_MASK;
+	writel(reg, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
+}
+
+u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL);
+	if (reg & PLL_LOCK)
+		return PLL_LOCKED;
+	else
+		return PLL_UNLOCKED;
+}
+
+void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable)
+{
+	u32 reg;
+
+	if (enable) {
+		reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL);
+		reg |= DP_PLL_PD;
+		writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL);
+	} else {
+		reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL);
+		reg &= ~DP_PLL_PD;
+		writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL);
+	}
+}
+
+void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
+				enum analog_power_block block,
+				bool enable)
+{
+	u32 reg;
+
+	switch (block) {
+	case AUX_BLOCK:
+		if (enable) {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg |= AUX_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		} else {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg &= ~AUX_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		}
+		break;
+	case CH0_BLOCK:
+		if (enable) {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg |= CH0_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		} else {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg &= ~CH0_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		}
+		break;
+	case CH1_BLOCK:
+		if (enable) {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg |= CH1_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		} else {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg &= ~CH1_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		}
+		break;
+	case CH2_BLOCK:
+		if (enable) {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg |= CH2_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		} else {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg &= ~CH2_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		}
+		break;
+	case CH3_BLOCK:
+		if (enable) {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg |= CH3_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		} else {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg &= ~CH3_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		}
+		break;
+	case ANALOG_TOTAL:
+		if (enable) {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg |= DP_PHY_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		} else {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg &= ~DP_PHY_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		}
+		break;
+	case POWER_ALL:
+		if (enable) {
+			reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD |
+				CH1_PD | CH0_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		} else {
+			writel(0x00, dp->reg_base + EXYNOS_DP_PHY_PD);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+void exynos_dp_init_analog_func(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
+
+	reg = PLL_LOCK_CHG;
+	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL);
+	reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL);
+	writel(reg, dp->reg_base + EXYNOS_DP_DEBUG_CTL);
+
+	/* Power up PLL */
+	if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED)
+		exynos_dp_set_pll_power_down(dp, 0);
+
+	/* Enable Serdes FIFO function and Link symbol clock domain module */
+	reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+	reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N
+		| AUX_FUNC_EN_N);
+	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+}
+
+void exynos_dp_init_hpd(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = HOTPLUG_CHG | HPD_LOST | PLUG;
+	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
+
+	reg = INT_HPD;
+	writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+	reg &= ~(F_HPD | HPD_CTRL);
+	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+}
+
+void exynos_dp_reset_aux(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	/* Disable AUX channel module */
+	reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+	reg |= AUX_FUNC_EN_N;
+	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+}
+
+void exynos_dp_init_aux(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	/* Clear inerrupts related to AUX channel */
+	reg = RPLY_RECEIV | AUX_ERR;
+	writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
+
+	exynos_dp_reset_aux(dp);
+
+	/* Disable AUX transaction H/W retry */
+	reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0)|
+		AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
+	writel(reg, dp->reg_base + EXYNOS_DP_AUX_HW_RETRY_CTL) ;
+
+	/* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */
+	reg = DEFER_CTRL_EN | DEFER_COUNT(1);
+	writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_DEFER_CTL);
+
+	/* Enable AUX channel module */
+	reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+	reg &= ~AUX_FUNC_EN_N;
+	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+}
+
+int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+	if (reg & HPD_STATUS)
+		return 0;
+
+	return -EINVAL;
+}
+
+void exynos_dp_enable_sw_function(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+	reg &= ~SW_FUNC_EN_N;
+	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+}
+
+int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp)
+{
+	int reg;
+	int retval = 0;
+
+	/* Enable AUX CH operation */
+	reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+	reg |= AUX_EN;
+	writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+
+	/* Is AUX CH command reply received? */
+	reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
+	while (!(reg & RPLY_RECEIV))
+		reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
+
+	/* Clear interrupt source for AUX CH command reply */
+	writel(RPLY_RECEIV, dp->reg_base + EXYNOS_DP_INT_STA);
+
+	/* Clear interrupt source for AUX CH access error */
+	reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
+	if (reg & AUX_ERR) {
+		writel(AUX_ERR, dp->reg_base + EXYNOS_DP_INT_STA);
+		return -EREMOTEIO;
+	}
+
+	/* Check AUX CH error access status */
+	reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_STA);
+	if ((reg & AUX_STATUS_MASK) != 0) {
+		dev_err(dp->dev, "AUX CH error happens: %d\n\n",
+			reg & AUX_STATUS_MASK);
+		return -EREMOTEIO;
+	}
+
+	return retval;
+}
+
+int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned char data)
+{
+	u32 reg;
+	int i;
+	int retval;
+
+	for (i = 0; i < 3; i++) {
+		/* Clear AUX CH data buffer */
+		reg = BUF_CLR;
+		writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+		/* Select DPCD device address */
+		reg = AUX_ADDR_7_0(reg_addr);
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+		reg = AUX_ADDR_15_8(reg_addr);
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+		reg = AUX_ADDR_19_16(reg_addr);
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+		/* Write data buffer */
+		reg = (unsigned int)data;
+		writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+
+		/*
+		 * Set DisplayPort transaction and write 1 byte
+		 * If bit 3 is 1, DisplayPort transaction.
+		 * If Bit 3 is 0, I2C transaction.
+		 */
+		reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+		/* Start AUX transaction */
+		retval = exynos_dp_start_aux_transaction(dp);
+		if (retval == 0)
+			break;
+		else
+			dev_err(dp->dev, "Aux Transaction fail!\n");
+	}
+
+	return retval;
+}
+
+int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned char *data)
+{
+	u32 reg;
+	int i;
+	int retval;
+
+	for (i = 0; i < 10; i++) {
+		/* Clear AUX CH data buffer */
+		reg = BUF_CLR;
+		writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+		/* Select DPCD device address */
+		reg = AUX_ADDR_7_0(reg_addr);
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+		reg = AUX_ADDR_15_8(reg_addr);
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+		reg = AUX_ADDR_19_16(reg_addr);
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+		/*
+		 * Set DisplayPort transaction and read 1 byte
+		 * If bit 3 is 1, DisplayPort transaction.
+		 * If Bit 3 is 0, I2C transaction.
+		 */
+		reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+		/* Start AUX transaction */
+		retval = exynos_dp_start_aux_transaction(dp);
+		if (retval == 0)
+			break;
+		else
+			dev_err(dp->dev, "Aux Transaction fail!\n");
+	}
+
+	/* Read data buffer */
+	reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+	*data = (unsigned char)(reg & 0xff);
+
+	return retval;
+}
+
+int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned int count,
+				unsigned char data[])
+{
+	u32 reg;
+	unsigned int start_offset;
+	unsigned int cur_data_count;
+	unsigned int cur_data_idx;
+	int i;
+	int retval = 0;
+
+	/* Clear AUX CH data buffer */
+	reg = BUF_CLR;
+	writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+	start_offset = 0;
+	while (start_offset < count) {
+		/* Buffer size of AUX CH is 16 * 4bytes */
+		if ((count - start_offset) > 16)
+			cur_data_count = 16;
+		else
+			cur_data_count = count - start_offset;
+
+		for (i = 0; i < 10; i++) {
+			/* Select DPCD device address */
+			reg = AUX_ADDR_7_0(reg_addr + start_offset);
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+			reg = AUX_ADDR_15_8(reg_addr + start_offset);
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+			reg = AUX_ADDR_19_16(reg_addr + start_offset);
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+			for (cur_data_idx = 0; cur_data_idx < cur_data_count;
+			     cur_data_idx++) {
+				reg = data[start_offset + cur_data_idx];
+				writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0
+							  + 4 * cur_data_idx);
+			}
+
+			/*
+			 * Set DisplayPort transaction and write
+			 * If bit 3 is 1, DisplayPort transaction.
+			 * If Bit 3 is 0, I2C transaction.
+			 */
+			reg = AUX_LENGTH(cur_data_count) |
+				AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+			/* Start AUX transaction */
+			retval = exynos_dp_start_aux_transaction(dp);
+			if (retval == 0)
+				break;
+			else
+				dev_err(dp->dev, "Aux Transaction fail!\n");
+		}
+
+		start_offset += cur_data_count;
+	}
+
+	return retval;
+}
+
+int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned int count,
+				unsigned char data[])
+{
+	u32 reg;
+	unsigned int start_offset;
+	unsigned int cur_data_count;
+	unsigned int cur_data_idx;
+	int i;
+	int retval = 0;
+
+	/* Clear AUX CH data buffer */
+	reg = BUF_CLR;
+	writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+	start_offset = 0;
+	while (start_offset < count) {
+		/* Buffer size of AUX CH is 16 * 4bytes */
+		if ((count - start_offset) > 16)
+			cur_data_count = 16;
+		else
+			cur_data_count = count - start_offset;
+
+		/* AUX CH Request Transaction process */
+		for (i = 0; i < 10; i++) {
+			/* Select DPCD device address */
+			reg = AUX_ADDR_7_0(reg_addr + start_offset);
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+			reg = AUX_ADDR_15_8(reg_addr + start_offset);
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+			reg = AUX_ADDR_19_16(reg_addr + start_offset);
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+			/*
+			 * Set DisplayPort transaction and read
+			 * If bit 3 is 1, DisplayPort transaction.
+			 * If Bit 3 is 0, I2C transaction.
+			 */
+			reg = AUX_LENGTH(cur_data_count) |
+				AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+			/* Start AUX transaction */
+			retval = exynos_dp_start_aux_transaction(dp);
+			if (retval == 0)
+				break;
+			else
+				dev_err(dp->dev, "Aux Transaction fail!\n");
+		}
+
+		for (cur_data_idx = 0; cur_data_idx < cur_data_count;
+		    cur_data_idx++) {
+			reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0
+						 + 4 * cur_data_idx);
+			data[start_offset + cur_data_idx] =
+				(unsigned char)reg;
+		}
+
+		start_offset += cur_data_count;
+	}
+
+	return retval;
+}
+
+int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
+				unsigned int device_addr,
+				unsigned int reg_addr)
+{
+	u32 reg;
+	int retval;
+
+	/* Set EDID device address */
+	reg = device_addr;
+	writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+	writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+	writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+	/* Set offset from base address of EDID device */
+	writel(reg_addr, dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+
+	/*
+	 * Set I2C transaction and write address
+	 * If bit 3 is 1, DisplayPort transaction.
+	 * If Bit 3 is 0, I2C transaction.
+	 */
+	reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT |
+		AUX_TX_COMM_WRITE;
+	writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+	/* Start AUX transaction */
+	retval = exynos_dp_start_aux_transaction(dp);
+	if (retval != 0)
+		dev_err(dp->dev, "Aux Transaction fail!\n");
+
+	return retval;
+}
+
+int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
+				unsigned int device_addr,
+				unsigned int reg_addr,
+				unsigned int *data)
+{
+	u32 reg;
+	int i;
+	int retval;
+
+	for (i = 0; i < 10; i++) {
+		/* Clear AUX CH data buffer */
+		reg = BUF_CLR;
+		writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+		/* Select EDID device */
+		retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr);
+		if (retval != 0) {
+			dev_err(dp->dev, "Select EDID device fail!\n");
+			continue;
+		}
+
+		/*
+		 * Set I2C transaction and read data
+		 * If bit 3 is 1, DisplayPort transaction.
+		 * If Bit 3 is 0, I2C transaction.
+		 */
+		reg = AUX_TX_COMM_I2C_TRANSACTION |
+			AUX_TX_COMM_READ;
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+		/* Start AUX transaction */
+		retval = exynos_dp_start_aux_transaction(dp);
+		if (retval == 0)
+			break;
+		else
+			dev_err(dp->dev, "Aux Transaction fail!\n");
+	}
+
+	/* Read data */
+	if (retval == 0)
+		*data = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+
+	return retval;
+}
+
+int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
+				unsigned int device_addr,
+				unsigned int reg_addr,
+				unsigned int count,
+				unsigned char edid[])
+{
+	u32 reg;
+	unsigned int i, j;
+	unsigned int cur_data_idx;
+	unsigned int defer = 0;
+	int retval = 0;
+
+	for (i = 0; i < count; i += 16) {
+		for (j = 0; j < 100; j++) {
+			/* Clear AUX CH data buffer */
+			reg = BUF_CLR;
+			writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+			/* Set normal AUX CH command */
+			reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+			reg &= ~ADDR_ONLY;
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+
+			/*
+			 * If Rx sends defer, Tx sends only reads
+			 * request without sending addres
+			 */
+			if (!defer)
+				retval = exynos_dp_select_i2c_device(dp,
+						device_addr, reg_addr + i);
+			else
+				defer = 0;
+
+			if (retval == 0) {
+				/*
+				 * Set I2C transaction and write data
+				 * If bit 3 is 1, DisplayPort transaction.
+				 * If Bit 3 is 0, I2C transaction.
+				 */
+				reg = AUX_LENGTH(16) |
+					AUX_TX_COMM_I2C_TRANSACTION |
+					AUX_TX_COMM_READ;
+				writel(reg, dp->reg_base +
+					EXYNOS_DP_AUX_CH_CTL_1);
+
+				/* Start AUX transaction */
+				retval = exynos_dp_start_aux_transaction(dp);
+				if (retval == 0)
+					break;
+				else
+					dev_err(dp->dev, "Aux Transaction fail!\n");
+			}
+			/* Check if Rx sends defer */
+			reg = readl(dp->reg_base + EXYNOS_DP_AUX_RX_COMM);
+			if (reg == AUX_RX_COMM_AUX_DEFER ||
+				reg == AUX_RX_COMM_I2C_DEFER) {
+				dev_err(dp->dev, "Defer: %d\n\n", reg);
+				defer = 1;
+			}
+		}
+
+		for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) {
+			reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0
+						 + 4 * cur_data_idx);
+			edid[i + cur_data_idx] = (unsigned char)reg;
+		}
+	}
+
+	return retval;
+}
+
+void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype)
+{
+	u32 reg;
+
+	reg = bwtype;
+	if ((bwtype == LINK_RATE_2_70GBPS) || (bwtype == LINK_RATE_1_62GBPS))
+		writel(reg, dp->reg_base + EXYNOS_DP_LINK_BW_SET);
+}
+
+void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LINK_BW_SET);
+	*bwtype = reg;
+}
+
+void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count)
+{
+	u32 reg;
+
+	reg = count;
+	writel(reg, dp->reg_base + EXYNOS_DP_LANE_COUNT_SET);
+}
+
+void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LANE_COUNT_SET);
+	*count = reg;
+}
+
+void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable)
+{
+	u32 reg;
+
+	if (enable) {
+		reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+		reg |= ENHANCED;
+		writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+	} else {
+		reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+		reg &= ~ENHANCED;
+		writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+	}
+}
+
+void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
+				 enum pattern_set pattern)
+{
+	u32 reg;
+
+	switch (pattern) {
+	case PRBS7:
+		reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7;
+		writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+		break;
+	case D10_2:
+		reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2;
+		writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+		break;
+	case TRAINING_PTN1:
+		reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1;
+		writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+		break;
+	case TRAINING_PTN2:
+		reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2;
+		writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+		break;
+	case DP_NONE:
+		reg = SCRAMBLING_ENABLE |
+			LINK_QUAL_PATTERN_SET_DISABLE |
+			SW_TRAINING_PATTERN_SET_NORMAL;
+		writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+		break;
+	default:
+		break;
+	}
+}
+
+void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+	u32 reg;
+
+	reg = level << PRE_EMPHASIS_SET_SHIFT;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+	u32 reg;
+
+	reg = level << PRE_EMPHASIS_SET_SHIFT;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+	u32 reg;
+
+	reg = level << PRE_EMPHASIS_SET_SHIFT;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+	u32 reg;
+
+	reg = level << PRE_EMPHASIS_SET_SHIFT;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp,
+					u32 training_lane)
+{
+	u32 reg;
+
+	reg = training_lane;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp,
+					u32 training_lane)
+{
+	u32 reg;
+
+	reg = training_lane;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp,
+					u32 training_lane)
+{
+	u32 reg;
+
+	reg = training_lane;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp,
+					u32 training_lane)
+{
+	u32 reg;
+
+	reg = training_lane;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+}
+
+u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+	return reg;
+}
+
+u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+	return reg;
+}
+
+u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+	return reg;
+}
+
+u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+	return reg;
+}
+
+void exynos_dp_reset_macro(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_PHY_TEST);
+	reg |= MACRO_RST;
+	writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
+
+	/* 10 us is the minimum reset time. */
+	udelay(10);
+
+	reg &= ~MACRO_RST;
+	writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
+}
+
+int exynos_dp_init_video(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG;
+	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
+
+	reg = 0x0;
+	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+
+	reg = CHA_CRI(4) | CHA_CTRL;
+	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+
+	reg = 0x0;
+	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+
+	reg = VID_HRES_TH(2) | VID_VRES_TH(0);
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8);
+
+	return 0;
+}
+
+void exynos_dp_set_video_color_format(struct exynos_dp_device *dp,
+			u32 color_depth,
+			u32 color_space,
+			u32 dynamic_range,
+			u32 ycbcr_coeff)
+{
+	u32 reg;
+
+	/* Configure the input color depth, color space, dynamic range */
+	reg = (dynamic_range << IN_D_RANGE_SHIFT) |
+		(color_depth << IN_BPC_SHIFT) |
+		(color_space << IN_COLOR_F_SHIFT);
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2);
+
+	/* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */
+	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3);
+	reg &= ~IN_YC_COEFFI_MASK;
+	if (ycbcr_coeff)
+		reg |= IN_YC_COEFFI_ITU709;
+	else
+		reg |= IN_YC_COEFFI_ITU601;
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_3);
+}
+
+int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+
+	if (!(reg & DET_STA)) {
+		dev_dbg(dp->dev, "Input stream clock not detected.\n");
+		return -EINVAL;
+	}
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+	dev_dbg(dp->dev, "wait SYS_CTL_2.\n");
+
+	if (reg & CHA_STA) {
+		dev_dbg(dp->dev, "Input stream clk is changing\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
+		enum clock_recovery_m_value_type type,
+		u32 m_value,
+		u32 n_value)
+{
+	u32 reg;
+
+	if (type == REGISTER_M) {
+		reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+		reg |= FIX_M_VID;
+		writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+		reg = m_value & 0xff;
+		writel(reg, dp->reg_base + EXYNOS_DP_M_VID_0);
+		reg = (m_value >> 8) & 0xff;
+		writel(reg, dp->reg_base + EXYNOS_DP_M_VID_1);
+		reg = (m_value >> 16) & 0xff;
+		writel(reg, dp->reg_base + EXYNOS_DP_M_VID_2);
+
+		reg = n_value & 0xff;
+		writel(reg, dp->reg_base + EXYNOS_DP_N_VID_0);
+		reg = (n_value >> 8) & 0xff;
+		writel(reg, dp->reg_base + EXYNOS_DP_N_VID_1);
+		reg = (n_value >> 16) & 0xff;
+		writel(reg, dp->reg_base + EXYNOS_DP_N_VID_2);
+	} else  {
+		reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+		reg &= ~FIX_M_VID;
+		writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+
+		writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_0);
+		writel(0x80, dp->reg_base + EXYNOS_DP_N_VID_1);
+		writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_2);
+	}
+}
+
+void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type)
+{
+	u32 reg;
+
+	if (type == VIDEO_TIMING_FROM_CAPTURE) {
+		reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+		reg &= ~FORMAT_SEL;
+		writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+	} else {
+		reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+		reg |= FORMAT_SEL;
+		writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+	}
+}
+
+void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable)
+{
+	u32 reg;
+
+	if (enable) {
+		reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+		reg &= ~VIDEO_MODE_MASK;
+		reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE;
+		writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+	} else {
+		reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+		reg &= ~VIDEO_MODE_MASK;
+		reg |= VIDEO_MODE_SLAVE_MODE;
+		writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+	}
+}
+
+void exynos_dp_start_video(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+	reg |= VIDEO_EN;
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+}
+
+int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+	if (!(reg & STRM_VALID)) {
+		dev_dbg(dp->dev, "Input video stream is not detected.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp,
+			struct video_info *video_info)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+	reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N);
+	reg |= MASTER_VID_FUNC_EN_N;
+	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+	reg &= ~INTERACE_SCAN_CFG;
+	reg |= (video_info->interlaced << 2);
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+	reg &= ~VSYNC_POLARITY_CFG;
+	reg |= (video_info->v_sync_polarity << 1);
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+	reg &= ~HSYNC_POLARITY_CFG;
+	reg |= (video_info->h_sync_polarity << 0);
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+
+	reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE;
+	writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+}
+
+void exynos_dp_enable_scrambling(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+	reg &= ~SCRAMBLING_DISABLE;
+	writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+}
+
+void exynos_dp_disable_scrambling(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+	reg |= SCRAMBLING_DISABLE;
+	writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+}
diff --git a/drivers/video/exynos/exynos_dp_reg.h b/drivers/video/exynos/exynos_dp_reg.h
new file mode 100644
index 0000000..42f608e
--- /dev/null
+++ b/drivers/video/exynos/exynos_dp_reg.h
@@ -0,0 +1,335 @@
+/*
+ * Register definition file for Samsung DP driver
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * 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.
+ */
+
+#ifndef _EXYNOS_DP_REG_H
+#define _EXYNOS_DP_REG_H
+
+#define EXYNOS_DP_TX_SW_RESET			0x14
+#define EXYNOS_DP_FUNC_EN_1			0x18
+#define EXYNOS_DP_FUNC_EN_2			0x1C
+#define EXYNOS_DP_VIDEO_CTL_1			0x20
+#define EXYNOS_DP_VIDEO_CTL_2			0x24
+#define EXYNOS_DP_VIDEO_CTL_3			0x28
+
+#define EXYNOS_DP_VIDEO_CTL_8			0x3C
+#define EXYNOS_DP_VIDEO_CTL_10			0x44
+
+#define EXYNOS_DP_LANE_MAP			0x35C
+
+#define EXYNOS_DP_AUX_HW_RETRY_CTL		0x390
+
+#define EXYNOS_DP_COMMON_INT_STA_1		0x3C4
+#define EXYNOS_DP_COMMON_INT_STA_2		0x3C8
+#define EXYNOS_DP_COMMON_INT_STA_3		0x3CC
+#define EXYNOS_DP_COMMON_INT_STA_4		0x3D0
+#define EXYNOS_DP_INT_STA			0x3DC
+#define EXYNOS_DP_COMMON_INT_MASK_1		0x3E0
+#define EXYNOS_DP_COMMON_INT_MASK_2		0x3E4
+#define EXYNOS_DP_COMMON_INT_MASK_3		0x3E8
+#define EXYNOS_DP_COMMON_INT_MASK_4		0x3EC
+#define EXYNOS_DP_INT_STA_MASK			0x3F8
+#define EXYNOS_DP_INT_CTL			0x3FC
+
+#define EXYNOS_DP_SYS_CTL_1			0x600
+#define EXYNOS_DP_SYS_CTL_2			0x604
+#define EXYNOS_DP_SYS_CTL_3			0x608
+#define EXYNOS_DP_SYS_CTL_4			0x60C
+
+#define EXYNOS_DP_PKT_SEND_CTL			0x640
+#define EXYNOS_DP_HDCP_CTL			0x648
+
+#define EXYNOS_DP_LINK_BW_SET			0x680
+#define EXYNOS_DP_LANE_COUNT_SET		0x684
+#define EXYNOS_DP_TRAINING_PTN_SET		0x688
+#define EXYNOS_DP_LN0_LINK_TRAINING_CTL		0x68C
+#define EXYNOS_DP_LN1_LINK_TRAINING_CTL		0x690
+#define EXYNOS_DP_LN2_LINK_TRAINING_CTL		0x694
+#define EXYNOS_DP_LN3_LINK_TRAINING_CTL		0x698
+
+#define EXYNOS_DP_DEBUG_CTL			0x6C0
+#define EXYNOS_DP_HPD_DEGLITCH_L		0x6C4
+#define EXYNOS_DP_HPD_DEGLITCH_H		0x6C8
+#define EXYNOS_DP_LINK_DEBUG_CTL		0x6E0
+
+#define EXYNOS_DP_M_VID_0			0x700
+#define EXYNOS_DP_M_VID_1			0x704
+#define EXYNOS_DP_M_VID_2			0x708
+#define EXYNOS_DP_N_VID_0			0x70C
+#define EXYNOS_DP_N_VID_1			0x710
+#define EXYNOS_DP_N_VID_2			0x714
+
+#define EXYNOS_DP_PLL_CTL			0x71C
+#define EXYNOS_DP_PHY_PD			0x720
+#define EXYNOS_DP_PHY_TEST			0x724
+
+#define EXYNOS_DP_VIDEO_FIFO_THRD		0x730
+#define EXYNOS_DP_AUDIO_MARGIN			0x73C
+
+#define EXYNOS_DP_M_VID_GEN_FILTER_TH		0x764
+#define EXYNOS_DP_M_AUD_GEN_FILTER_TH		0x778
+#define EXYNOS_DP_AUX_CH_STA			0x780
+#define EXYNOS_DP_AUX_CH_DEFER_CTL		0x788
+#define EXYNOS_DP_AUX_RX_COMM			0x78C
+#define EXYNOS_DP_BUFFER_DATA_CTL		0x790
+#define EXYNOS_DP_AUX_CH_CTL_1			0x794
+#define EXYNOS_DP_AUX_ADDR_7_0			0x798
+#define EXYNOS_DP_AUX_ADDR_15_8			0x79C
+#define EXYNOS_DP_AUX_ADDR_19_16		0x7A0
+#define EXYNOS_DP_AUX_CH_CTL_2			0x7A4
+
+#define EXYNOS_DP_BUF_DATA_0			0x7C0
+
+#define EXYNOS_DP_SOC_GENERAL_CTL		0x800
+
+/* EXYNOS_DP_TX_SW_RESET */
+#define RESET_DP_TX				(0x1 << 0)
+
+/* EXYNOS_DP_FUNC_EN_1 */
+#define MASTER_VID_FUNC_EN_N			(0x1 << 7)
+#define SLAVE_VID_FUNC_EN_N			(0x1 << 5)
+#define AUD_FIFO_FUNC_EN_N			(0x1 << 4)
+#define AUD_FUNC_EN_N				(0x1 << 3)
+#define HDCP_FUNC_EN_N				(0x1 << 2)
+#define CRC_FUNC_EN_N				(0x1 << 1)
+#define SW_FUNC_EN_N				(0x1 << 0)
+
+/* EXYNOS_DP_FUNC_EN_2 */
+#define SSC_FUNC_EN_N				(0x1 << 7)
+#define AUX_FUNC_EN_N				(0x1 << 2)
+#define SERDES_FIFO_FUNC_EN_N			(0x1 << 1)
+#define LS_CLK_DOMAIN_FUNC_EN_N			(0x1 << 0)
+
+/* EXYNOS_DP_VIDEO_CTL_1 */
+#define VIDEO_EN				(0x1 << 7)
+#define HDCP_VIDEO_MUTE				(0x1 << 6)
+
+/* EXYNOS_DP_VIDEO_CTL_1 */
+#define IN_D_RANGE_MASK				(0x1 << 7)
+#define IN_D_RANGE_SHIFT			(7)
+#define IN_D_RANGE_CEA				(0x1 << 7)
+#define IN_D_RANGE_VESA				(0x0 << 7)
+#define IN_BPC_MASK				(0x7 << 4)
+#define IN_BPC_SHIFT				(4)
+#define IN_BPC_12_BITS				(0x3 << 4)
+#define IN_BPC_10_BITS				(0x2 << 4)
+#define IN_BPC_8_BITS				(0x1 << 4)
+#define IN_BPC_6_BITS				(0x0 << 4)
+#define IN_COLOR_F_MASK				(0x3 << 0)
+#define IN_COLOR_F_SHIFT			(0)
+#define IN_COLOR_F_YCBCR444			(0x2 << 0)
+#define IN_COLOR_F_YCBCR422			(0x1 << 0)
+#define IN_COLOR_F_RGB				(0x0 << 0)
+
+/* EXYNOS_DP_VIDEO_CTL_3 */
+#define IN_YC_COEFFI_MASK			(0x1 << 7)
+#define IN_YC_COEFFI_SHIFT			(7)
+#define IN_YC_COEFFI_ITU709			(0x1 << 7)
+#define IN_YC_COEFFI_ITU601			(0x0 << 7)
+#define VID_CHK_UPDATE_TYPE_MASK		(0x1 << 4)
+#define VID_CHK_UPDATE_TYPE_SHIFT		(4)
+#define VID_CHK_UPDATE_TYPE_1			(0x1 << 4)
+#define VID_CHK_UPDATE_TYPE_0			(0x0 << 4)
+
+/* EXYNOS_DP_VIDEO_CTL_8 */
+#define VID_HRES_TH(x)				(((x) & 0xf) << 4)
+#define VID_VRES_TH(x)				(((x) & 0xf) << 0)
+
+/* EXYNOS_DP_VIDEO_CTL_10 */
+#define FORMAT_SEL				(0x1 << 4)
+#define INTERACE_SCAN_CFG			(0x1 << 2)
+#define VSYNC_POLARITY_CFG			(0x1 << 1)
+#define HSYNC_POLARITY_CFG			(0x1 << 0)
+
+/* EXYNOS_DP_LANE_MAP */
+#define LANE3_MAP_LOGIC_LANE_0			(0x0 << 6)
+#define LANE3_MAP_LOGIC_LANE_1			(0x1 << 6)
+#define LANE3_MAP_LOGIC_LANE_2			(0x2 << 6)
+#define LANE3_MAP_LOGIC_LANE_3			(0x3 << 6)
+#define LANE2_MAP_LOGIC_LANE_0			(0x0 << 4)
+#define LANE2_MAP_LOGIC_LANE_1			(0x1 << 4)
+#define LANE2_MAP_LOGIC_LANE_2			(0x2 << 4)
+#define LANE2_MAP_LOGIC_LANE_3			(0x3 << 4)
+#define LANE1_MAP_LOGIC_LANE_0			(0x0 << 2)
+#define LANE1_MAP_LOGIC_LANE_1			(0x1 << 2)
+#define LANE1_MAP_LOGIC_LANE_2			(0x2 << 2)
+#define LANE1_MAP_LOGIC_LANE_3			(0x3 << 2)
+#define LANE0_MAP_LOGIC_LANE_0			(0x0 << 0)
+#define LANE0_MAP_LOGIC_LANE_1			(0x1 << 0)
+#define LANE0_MAP_LOGIC_LANE_2			(0x2 << 0)
+#define LANE0_MAP_LOGIC_LANE_3			(0x3 << 0)
+
+/* EXYNOS_DP_AUX_HW_RETRY_CTL */
+#define AUX_BIT_PERIOD_EXPECTED_DELAY(x)	(((x) & 0x7) << 8)
+#define AUX_HW_RETRY_INTERVAL_MASK		(0x3 << 3)
+#define AUX_HW_RETRY_INTERVAL_600_MICROSECONDS	(0x0 << 3)
+#define AUX_HW_RETRY_INTERVAL_800_MICROSECONDS	(0x1 << 3)
+#define AUX_HW_RETRY_INTERVAL_1000_MICROSECONDS	(0x2 << 3)
+#define AUX_HW_RETRY_INTERVAL_1800_MICROSECONDS	(0x3 << 3)
+#define AUX_HW_RETRY_COUNT_SEL(x)		(((x) & 0x7) << 0)
+
+/* EXYNOS_DP_COMMON_INT_STA_1 */
+#define VSYNC_DET				(0x1 << 7)
+#define PLL_LOCK_CHG				(0x1 << 6)
+#define SPDIF_ERR				(0x1 << 5)
+#define SPDIF_UNSTBL				(0x1 << 4)
+#define VID_FORMAT_CHG				(0x1 << 3)
+#define AUD_CLK_CHG				(0x1 << 2)
+#define VID_CLK_CHG				(0x1 << 1)
+#define SW_INT					(0x1 << 0)
+
+/* EXYNOS_DP_COMMON_INT_STA_2 */
+#define ENC_EN_CHG				(0x1 << 6)
+#define HW_BKSV_RDY				(0x1 << 3)
+#define HW_SHA_DONE				(0x1 << 2)
+#define HW_AUTH_STATE_CHG			(0x1 << 1)
+#define HW_AUTH_DONE				(0x1 << 0)
+
+/* EXYNOS_DP_COMMON_INT_STA_3 */
+#define AFIFO_UNDER				(0x1 << 7)
+#define AFIFO_OVER				(0x1 << 6)
+#define R0_CHK_FLAG				(0x1 << 5)
+
+/* EXYNOS_DP_COMMON_INT_STA_4 */
+#define PSR_ACTIVE				(0x1 << 7)
+#define PSR_INACTIVE				(0x1 << 6)
+#define SPDIF_BI_PHASE_ERR			(0x1 << 5)
+#define HOTPLUG_CHG				(0x1 << 2)
+#define HPD_LOST				(0x1 << 1)
+#define PLUG					(0x1 << 0)
+
+/* EXYNOS_DP_INT_STA */
+#define INT_HPD					(0x1 << 6)
+#define HW_TRAINING_FINISH			(0x1 << 5)
+#define RPLY_RECEIV				(0x1 << 1)
+#define AUX_ERR					(0x1 << 0)
+
+/* EXYNOS_DP_INT_CTL */
+#define SOFT_INT_CTRL				(0x1 << 2)
+#define INT_POL					(0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_1 */
+#define DET_STA					(0x1 << 2)
+#define FORCE_DET				(0x1 << 1)
+#define DET_CTRL				(0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_2 */
+#define CHA_CRI(x)				(((x) & 0xf) << 4)
+#define CHA_STA					(0x1 << 2)
+#define FORCE_CHA				(0x1 << 1)
+#define CHA_CTRL				(0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_3 */
+#define HPD_STATUS				(0x1 << 6)
+#define F_HPD					(0x1 << 5)
+#define HPD_CTRL				(0x1 << 4)
+#define HDCP_RDY				(0x1 << 3)
+#define STRM_VALID				(0x1 << 2)
+#define F_VALID					(0x1 << 1)
+#define VALID_CTRL				(0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_4 */
+#define FIX_M_AUD				(0x1 << 4)
+#define ENHANCED				(0x1 << 3)
+#define FIX_M_VID				(0x1 << 2)
+#define M_VID_UPDATE_CTRL			(0x3 << 0)
+
+/* EXYNOS_DP_TRAINING_PTN_SET */
+#define SCRAMBLER_TYPE				(0x1 << 9)
+#define HW_LINK_TRAINING_PATTERN		(0x1 << 8)
+#define SCRAMBLING_DISABLE			(0x1 << 5)
+#define SCRAMBLING_ENABLE			(0x0 << 5)
+#define LINK_QUAL_PATTERN_SET_MASK		(0x3 << 2)
+#define LINK_QUAL_PATTERN_SET_PRBS7		(0x3 << 2)
+#define LINK_QUAL_PATTERN_SET_D10_2		(0x1 << 2)
+#define LINK_QUAL_PATTERN_SET_DISABLE		(0x0 << 2)
+#define SW_TRAINING_PATTERN_SET_MASK		(0x3 << 0)
+#define SW_TRAINING_PATTERN_SET_PTN2		(0x2 << 0)
+#define SW_TRAINING_PATTERN_SET_PTN1		(0x1 << 0)
+#define SW_TRAINING_PATTERN_SET_NORMAL		(0x0 << 0)
+
+/* EXYNOS_DP_LN0_LINK_TRAINING_CTL */
+#define PRE_EMPHASIS_SET_SHIFT			(3)
+
+/* EXYNOS_DP_DEBUG_CTL */
+#define PLL_LOCK				(0x1 << 4)
+#define F_PLL_LOCK				(0x1 << 3)
+#define PLL_LOCK_CTRL				(0x1 << 2)
+#define PN_INV					(0x1 << 0)
+
+/* EXYNOS_DP_PLL_CTL */
+#define DP_PLL_PD				(0x1 << 7)
+#define DP_PLL_RESET				(0x1 << 6)
+#define DP_PLL_LOOP_BIT_DEFAULT			(0x1 << 4)
+#define DP_PLL_REF_BIT_1_1250V			(0x5 << 0)
+#define DP_PLL_REF_BIT_1_2500V			(0x7 << 0)
+
+/* EXYNOS_DP_PHY_PD */
+#define DP_PHY_PD				(0x1 << 5)
+#define AUX_PD					(0x1 << 4)
+#define CH3_PD					(0x1 << 3)
+#define CH2_PD					(0x1 << 2)
+#define CH1_PD					(0x1 << 1)
+#define CH0_PD					(0x1 << 0)
+
+/* EXYNOS_DP_PHY_TEST */
+#define MACRO_RST				(0x1 << 5)
+#define CH1_TEST				(0x1 << 1)
+#define CH0_TEST				(0x1 << 0)
+
+/* EXYNOS_DP_AUX_CH_STA */
+#define AUX_BUSY				(0x1 << 4)
+#define AUX_STATUS_MASK				(0xf << 0)
+
+/* EXYNOS_DP_AUX_CH_DEFER_CTL */
+#define DEFER_CTRL_EN				(0x1 << 7)
+#define DEFER_COUNT(x)				(((x) & 0x7f) << 0)
+
+/* EXYNOS_DP_AUX_RX_COMM */
+#define AUX_RX_COMM_I2C_DEFER			(0x2 << 2)
+#define AUX_RX_COMM_AUX_DEFER			(0x2 << 0)
+
+/* EXYNOS_DP_BUFFER_DATA_CTL */
+#define BUF_CLR					(0x1 << 7)
+#define BUF_DATA_COUNT(x)			(((x) & 0x1f) << 0)
+
+/* EXYNOS_DP_AUX_CH_CTL_1 */
+#define AUX_LENGTH(x)				(((x - 1) & 0xf) << 4)
+#define AUX_TX_COMM_MASK			(0xf << 0)
+#define AUX_TX_COMM_DP_TRANSACTION		(0x1 << 3)
+#define AUX_TX_COMM_I2C_TRANSACTION		(0x0 << 3)
+#define AUX_TX_COMM_MOT				(0x1 << 2)
+#define AUX_TX_COMM_WRITE			(0x0 << 0)
+#define AUX_TX_COMM_READ			(0x1 << 0)
+
+/* EXYNOS_DP_AUX_ADDR_7_0 */
+#define AUX_ADDR_7_0(x)				(((x) >> 0) & 0xff)
+
+/* EXYNOS_DP_AUX_ADDR_15_8 */
+#define AUX_ADDR_15_8(x)			(((x) >> 8) & 0xff)
+
+/* EXYNOS_DP_AUX_ADDR_19_16 */
+#define AUX_ADDR_19_16(x)			(((x) >> 16) & 0x0f)
+
+/* EXYNOS_DP_AUX_CH_CTL_2 */
+#define ADDR_ONLY				(0x1 << 1)
+#define AUX_EN					(0x1 << 0)
+
+/* EXYNOS_DP_SOC_GENERAL_CTL */
+#define AUDIO_MODE_SPDIF_MODE			(0x1 << 8)
+#define AUDIO_MODE_MASTER_MODE			(0x0 << 8)
+#define MASTER_VIDEO_INTERLACE_EN		(0x1 << 4)
+#define VIDEO_MASTER_CLK_SEL			(0x1 << 2)
+#define VIDEO_MASTER_MODE_EN			(0x1 << 1)
+#define VIDEO_MODE_MASK				(0x1 << 0)
+#define VIDEO_MODE_SLAVE_MODE			(0x1 << 0)
+#define VIDEO_MODE_MASTER_MODE			(0x0 << 0)
+
+#endif /* _EXYNOS_DP_REG_H */
diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c
new file mode 100644
index 0000000..557091d
--- /dev/null
+++ b/drivers/video/exynos/exynos_mipi_dsi.c
@@ -0,0 +1,600 @@
+/* linux/drivers/video/exynos/exynos_mipi_dsi.c
+ *
+ * Samsung SoC MIPI-DSIM driver.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae, <inki.dae@samsung.com>
+ * Donghwa Lee, <dh09.lee@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/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/ctype.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/memory.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/notifier.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+
+#include <video/exynos_mipi_dsim.h>
+
+#include <plat/fb.h>
+
+#include "exynos_mipi_dsi_common.h"
+#include "exynos_mipi_dsi_lowlevel.h"
+
+struct mipi_dsim_ddi {
+	int				bus_id;
+	struct list_head		list;
+	struct mipi_dsim_lcd_device	*dsim_lcd_dev;
+	struct mipi_dsim_lcd_driver	*dsim_lcd_drv;
+};
+
+static LIST_HEAD(dsim_ddi_list);
+
+static DEFINE_MUTEX(mipi_dsim_lock);
+
+static struct mipi_dsim_platform_data *to_dsim_plat(struct platform_device
+							*pdev)
+{
+	return pdev->dev.platform_data;
+}
+
+static struct regulator_bulk_data supplies[] = {
+	{ .supply = "vdd10", },
+	{ .supply = "vdd18", },
+};
+
+static int exynos_mipi_regulator_enable(struct mipi_dsim_device *dsim)
+{
+	int ret;
+
+	mutex_lock(&dsim->lock);
+	ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
+	mutex_unlock(&dsim->lock);
+
+	return ret;
+}
+
+static int exynos_mipi_regulator_disable(struct mipi_dsim_device *dsim)
+{
+	int ret;
+
+	mutex_lock(&dsim->lock);
+	ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
+	mutex_unlock(&dsim->lock);
+
+	return ret;
+}
+
+/* update all register settings to MIPI DSI controller. */
+static void exynos_mipi_update_cfg(struct mipi_dsim_device *dsim)
+{
+	/*
+	 * data from Display controller(FIMD) is not transferred in video mode
+	 * but in case of command mode, all settings is not updated to
+	 * registers.
+	 */
+	exynos_mipi_dsi_stand_by(dsim, 0);
+
+	exynos_mipi_dsi_init_dsim(dsim);
+	exynos_mipi_dsi_init_link(dsim);
+
+	exynos_mipi_dsi_set_hs_enable(dsim);
+
+	/* set display timing. */
+	exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
+
+	/*
+	 * data from Display controller(FIMD) is transferred in video mode
+	 * but in case of command mode, all settigs is updated to registers.
+	 */
+	exynos_mipi_dsi_stand_by(dsim, 1);
+}
+
+static int exynos_mipi_dsi_early_blank_mode(struct mipi_dsim_device *dsim,
+		int power)
+{
+	struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
+	struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
+
+	switch (power) {
+	case FB_BLANK_POWERDOWN:
+		if (dsim->suspended)
+			return 0;
+
+		if (client_drv && client_drv->suspend)
+			client_drv->suspend(client_dev);
+
+		clk_disable(dsim->clock);
+
+		exynos_mipi_regulator_disable(dsim);
+
+		dsim->suspended = true;
+
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int exynos_mipi_dsi_blank_mode(struct mipi_dsim_device *dsim, int power)
+{
+	struct platform_device *pdev = to_platform_device(dsim->dev);
+	struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
+	struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
+
+	switch (power) {
+	case FB_BLANK_UNBLANK:
+		if (!dsim->suspended)
+			return 0;
+
+		/* lcd panel power on. */
+		if (client_drv && client_drv->power_on)
+			client_drv->power_on(client_dev, 1);
+
+		exynos_mipi_regulator_disable(dsim);
+
+		/* enable MIPI-DSI PHY. */
+		if (dsim->pd->phy_enable)
+			dsim->pd->phy_enable(pdev, true);
+
+		clk_enable(dsim->clock);
+
+		exynos_mipi_update_cfg(dsim);
+
+		/* set lcd panel sequence commands. */
+		if (client_drv && client_drv->set_sequence)
+			client_drv->set_sequence(client_dev);
+
+		dsim->suspended = false;
+
+		break;
+	case FB_BLANK_NORMAL:
+		/* TODO. */
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
+{
+	struct mipi_dsim_ddi *dsim_ddi;
+
+	if (!lcd_dev->name) {
+		pr_err("dsim_lcd_device name is NULL.\n");
+		return -EFAULT;
+	}
+
+	dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
+	if (!dsim_ddi) {
+		pr_err("failed to allocate dsim_ddi object.\n");
+		return -ENOMEM;
+	}
+
+	dsim_ddi->dsim_lcd_dev = lcd_dev;
+
+	mutex_lock(&mipi_dsim_lock);
+	list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
+	mutex_unlock(&mipi_dsim_lock);
+
+	return 0;
+}
+
+struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
+{
+	struct mipi_dsim_ddi *dsim_ddi, *next;
+	struct mipi_dsim_lcd_device *lcd_dev;
+
+	mutex_lock(&mipi_dsim_lock);
+
+	list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
+		if (!dsim_ddi)
+			goto out;
+
+		lcd_dev = dsim_ddi->dsim_lcd_dev;
+		if (!lcd_dev)
+			continue;
+
+		if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) {
+			/**
+			 * bus_id would be used to identify
+			 * connected bus.
+			 */
+			dsim_ddi->bus_id = lcd_dev->bus_id;
+			mutex_unlock(&mipi_dsim_lock);
+
+			return dsim_ddi;
+		}
+
+		list_del(&dsim_ddi->list);
+		kfree(dsim_ddi);
+	}
+
+out:
+	mutex_unlock(&mipi_dsim_lock);
+
+	return NULL;
+}
+
+int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
+{
+	struct mipi_dsim_ddi *dsim_ddi;
+
+	if (!lcd_drv->name) {
+		pr_err("dsim_lcd_driver name is NULL.\n");
+		return -EFAULT;
+	}
+
+	dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv);
+	if (!dsim_ddi) {
+		pr_err("mipi_dsim_ddi object not found.\n");
+		return -EFAULT;
+	}
+
+	dsim_ddi->dsim_lcd_drv = lcd_drv;
+
+	pr_info("registered panel driver(%s) to mipi-dsi driver.\n",
+		lcd_drv->name);
+
+	return 0;
+
+}
+
+struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
+						const char *name)
+{
+	struct mipi_dsim_ddi *dsim_ddi, *next;
+	struct mipi_dsim_lcd_driver *lcd_drv;
+	struct mipi_dsim_lcd_device *lcd_dev;
+	int ret;
+
+	mutex_lock(&dsim->lock);
+
+	list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
+		lcd_drv = dsim_ddi->dsim_lcd_drv;
+		lcd_dev = dsim_ddi->dsim_lcd_dev;
+		if (!lcd_drv || !lcd_dev ||
+			(dsim->id != dsim_ddi->bus_id))
+				continue;
+
+		dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n",
+				lcd_drv->id, lcd_dev->id);
+		dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n",
+				lcd_dev->bus_id, dsim->id);
+
+		if ((strcmp(lcd_drv->name, name) == 0)) {
+			lcd_dev->master = dsim;
+
+			lcd_dev->dev.parent = dsim->dev;
+			dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name);
+
+			ret = device_register(&lcd_dev->dev);
+			if (ret < 0) {
+				dev_err(dsim->dev,
+					"can't register %s, status %d\n",
+					dev_name(&lcd_dev->dev), ret);
+				mutex_unlock(&dsim->lock);
+
+				return NULL;
+			}
+
+			dsim->dsim_lcd_dev = lcd_dev;
+			dsim->dsim_lcd_drv = lcd_drv;
+
+			mutex_unlock(&dsim->lock);
+
+			return dsim_ddi;
+		}
+	}
+
+	mutex_unlock(&dsim->lock);
+
+	return NULL;
+}
+
+/* define MIPI-DSI Master operations. */
+static struct mipi_dsim_master_ops master_ops = {
+	.cmd_read			= exynos_mipi_dsi_rd_data,
+	.cmd_write			= exynos_mipi_dsi_wr_data,
+	.get_dsim_frame_done		= exynos_mipi_dsi_get_frame_done_status,
+	.clear_dsim_frame_done		= exynos_mipi_dsi_clear_frame_done,
+	.set_early_blank_mode		= exynos_mipi_dsi_early_blank_mode,
+	.set_blank_mode			= exynos_mipi_dsi_blank_mode,
+};
+
+static int exynos_mipi_dsi_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct mipi_dsim_device *dsim;
+	struct mipi_dsim_config *dsim_config;
+	struct mipi_dsim_platform_data *dsim_pd;
+	struct mipi_dsim_ddi *dsim_ddi;
+	int ret = -EINVAL;
+
+	dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
+	if (!dsim) {
+		dev_err(&pdev->dev, "failed to allocate dsim object.\n");
+		return -ENOMEM;
+	}
+
+	dsim->pd = to_dsim_plat(pdev);
+	dsim->dev = &pdev->dev;
+	dsim->id = pdev->id;
+
+	/* get mipi_dsim_platform_data. */
+	dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
+	if (dsim_pd == NULL) {
+		dev_err(&pdev->dev, "failed to get platform data for dsim.\n");
+		goto err_clock_get;
+	}
+	/* get mipi_dsim_config. */
+	dsim_config = dsim_pd->dsim_config;
+	if (dsim_config == NULL) {
+		dev_err(&pdev->dev, "failed to get dsim config data.\n");
+		goto err_clock_get;
+	}
+
+	dsim->dsim_config = dsim_config;
+	dsim->master_ops = &master_ops;
+
+	mutex_init(&dsim->lock);
+
+	ret = regulator_bulk_get(&pdev->dev, ARRAY_SIZE(supplies), supplies);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to get regulators: %d\n", ret);
+		goto err_clock_get;
+	}
+
+	dsim->clock = clk_get(&pdev->dev, "dsim0");
+	if (IS_ERR(dsim->clock)) {
+		dev_err(&pdev->dev, "failed to get dsim clock source\n");
+		goto err_clock_get;
+	}
+
+	clk_enable(dsim->clock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get io memory region\n");
+		goto err_platform_get;
+	}
+
+	dsim->res = request_mem_region(res->start, resource_size(res),
+					dev_name(&pdev->dev));
+	if (!dsim->res) {
+		dev_err(&pdev->dev, "failed to request io memory region\n");
+		ret = -ENOMEM;
+		goto err_mem_region;
+	}
+
+	dsim->reg_base = ioremap(res->start, resource_size(res));
+	if (!dsim->reg_base) {
+		dev_err(&pdev->dev, "failed to remap io region\n");
+		ret = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	mutex_init(&dsim->lock);
+
+	/* bind lcd ddi matched with panel name. */
+	dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
+	if (!dsim_ddi) {
+		dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
+		goto err_bind;
+	}
+
+	dsim->irq = platform_get_irq(pdev, 0);
+	if (dsim->irq < 0) {
+		dev_err(&pdev->dev, "failed to request dsim irq resource\n");
+		ret = -EINVAL;
+		goto err_platform_get_irq;
+	}
+
+	ret = request_irq(dsim->irq, exynos_mipi_dsi_interrupt_handler,
+			IRQF_SHARED, pdev->name, dsim);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "failed to request dsim irq\n");
+		ret = -EINVAL;
+		goto err_bind;
+	}
+
+	init_completion(&dsim_wr_comp);
+	init_completion(&dsim_rd_comp);
+
+	/* enable interrupt */
+	exynos_mipi_dsi_init_interrupt(dsim);
+
+	/* initialize mipi-dsi client(lcd panel). */
+	if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe)
+		dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev);
+
+	/* in case that mipi got enabled at bootloader. */
+	if (dsim_pd->enabled)
+		goto out;
+
+	/* lcd panel power on. */
+	if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->power_on)
+		dsim_ddi->dsim_lcd_drv->power_on(dsim_ddi->dsim_lcd_dev, 1);
+
+	exynos_mipi_regulator_enable(dsim);
+
+	/* enable MIPI-DSI PHY. */
+	if (dsim->pd->phy_enable)
+		dsim->pd->phy_enable(pdev, true);
+
+	exynos_mipi_update_cfg(dsim);
+
+	/* set lcd panel sequence commands. */
+	if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->set_sequence)
+		dsim_ddi->dsim_lcd_drv->set_sequence(dsim_ddi->dsim_lcd_dev);
+
+	dsim->suspended = false;
+
+out:
+	platform_set_drvdata(pdev, dsim);
+
+	dev_dbg(&pdev->dev, "mipi-dsi driver(%s mode) has been probed.\n",
+		(dsim_config->e_interface == DSIM_COMMAND) ?
+			"CPU" : "RGB");
+
+	return 0;
+
+err_bind:
+	iounmap(dsim->reg_base);
+
+err_ioremap:
+	release_mem_region(dsim->res->start, resource_size(dsim->res));
+
+err_mem_region:
+	release_resource(dsim->res);
+
+err_platform_get:
+	clk_disable(dsim->clock);
+	clk_put(dsim->clock);
+err_clock_get:
+	kfree(dsim);
+
+err_platform_get_irq:
+	return ret;
+}
+
+static int __devexit exynos_mipi_dsi_remove(struct platform_device *pdev)
+{
+	struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+	struct mipi_dsim_ddi *dsim_ddi, *next;
+	struct mipi_dsim_lcd_driver *dsim_lcd_drv;
+
+	iounmap(dsim->reg_base);
+
+	clk_disable(dsim->clock);
+	clk_put(dsim->clock);
+
+	release_resource(dsim->res);
+	release_mem_region(dsim->res->start, resource_size(dsim->res));
+
+	list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
+		if (dsim_ddi) {
+			if (dsim->id != dsim_ddi->bus_id)
+				continue;
+
+			dsim_lcd_drv = dsim_ddi->dsim_lcd_drv;
+
+			if (dsim_lcd_drv->remove)
+				dsim_lcd_drv->remove(dsim_ddi->dsim_lcd_dev);
+
+			kfree(dsim_ddi);
+		}
+	}
+
+	regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
+	kfree(dsim);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int exynos_mipi_dsi_suspend(struct platform_device *pdev,
+		pm_message_t state)
+{
+	struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+	struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
+	struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
+
+	disable_irq(dsim->irq);
+
+	if (dsim->suspended)
+		return 0;
+
+	if (client_drv && client_drv->suspend)
+		client_drv->suspend(client_dev);
+
+	/* enable MIPI-DSI PHY. */
+	if (dsim->pd->phy_enable)
+		dsim->pd->phy_enable(pdev, false);
+
+	clk_disable(dsim->clock);
+
+	exynos_mipi_regulator_disable(dsim);
+
+	dsim->suspended = true;
+
+	return 0;
+}
+
+static int exynos_mipi_dsi_resume(struct platform_device *pdev)
+{
+	struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+	struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
+	struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
+
+	enable_irq(dsim->irq);
+
+	if (!dsim->suspended)
+		return 0;
+
+	/* lcd panel power on. */
+	if (client_drv && client_drv->power_on)
+		client_drv->power_on(client_dev, 1);
+
+	exynos_mipi_regulator_enable(dsim);
+
+	/* enable MIPI-DSI PHY. */
+	if (dsim->pd->phy_enable)
+		dsim->pd->phy_enable(pdev, true);
+
+	clk_enable(dsim->clock);
+
+	exynos_mipi_update_cfg(dsim);
+
+	/* set lcd panel sequence commands. */
+	if (client_drv && client_drv->set_sequence)
+		client_drv->set_sequence(client_dev);
+
+	dsim->suspended = false;
+
+	return 0;
+}
+#else
+#define exynos_mipi_dsi_suspend NULL
+#define exynos_mipi_dsi_resume NULL
+#endif
+
+static struct platform_driver exynos_mipi_dsi_driver = {
+	.probe = exynos_mipi_dsi_probe,
+	.remove = __devexit_p(exynos_mipi_dsi_remove),
+	.suspend = exynos_mipi_dsi_suspend,
+	.resume = exynos_mipi_dsi_resume,
+	.driver = {
+		   .name = "exynos-mipi-dsim",
+		   .owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(exynos_mipi_dsi_driver);
+
+MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("Samusung SoC MIPI-DSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c b/drivers/video/exynos/exynos_mipi_dsi_common.c
new file mode 100644
index 0000000..14909c1
--- /dev/null
+++ b/drivers/video/exynos/exynos_mipi_dsi_common.c
@@ -0,0 +1,896 @@
+/* linux/drivers/video/exynos/exynos_mipi_dsi_common.c
+ *
+ * Samsung SoC MIPI-DSI common driver.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae, <inki.dae@samsung.com>
+ * Donghwa Lee, <dh09.lee@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/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/ctype.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/memory.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+
+#include <video/mipi_display.h>
+#include <video/exynos_mipi_dsim.h>
+
+#include <mach/map.h>
+
+#include "exynos_mipi_dsi_regs.h"
+#include "exynos_mipi_dsi_lowlevel.h"
+#include "exynos_mipi_dsi_common.h"
+
+#define MIPI_FIFO_TIMEOUT	msecs_to_jiffies(250)
+#define MIPI_RX_FIFO_READ_DONE  0x30800002
+#define MIPI_MAX_RX_FIFO        20
+#define MHZ			(1000 * 1000)
+#define FIN_HZ			(24 * MHZ)
+
+#define DFIN_PLL_MIN_HZ		(6 * MHZ)
+#define DFIN_PLL_MAX_HZ		(12 * MHZ)
+
+#define DFVCO_MIN_HZ		(500 * MHZ)
+#define DFVCO_MAX_HZ		(1000 * MHZ)
+
+#define TRY_GET_FIFO_TIMEOUT	(5000 * 2)
+#define TRY_FIFO_CLEAR		(10)
+
+/* MIPI-DSIM status types. */
+enum {
+	DSIM_STATE_INIT,	/* should be initialized. */
+	DSIM_STATE_STOP,	/* CPU and LCDC are LP mode. */
+	DSIM_STATE_HSCLKEN,	/* HS clock was enabled. */
+	DSIM_STATE_ULPS
+};
+
+/* define DSI lane types. */
+enum {
+	DSIM_LANE_CLOCK = (1 << 0),
+	DSIM_LANE_DATA0 = (1 << 1),
+	DSIM_LANE_DATA1 = (1 << 2),
+	DSIM_LANE_DATA2 = (1 << 3),
+	DSIM_LANE_DATA3 = (1 << 4)
+};
+
+static unsigned int dpll_table[15] = {
+	100, 120, 170, 220, 270,
+	320, 390, 450, 510, 560,
+	640, 690, 770, 870, 950
+};
+
+irqreturn_t exynos_mipi_dsi_interrupt_handler(int irq, void *dev_id)
+{
+	unsigned int intsrc = 0;
+	unsigned int intmsk = 0;
+	struct mipi_dsim_device *dsim = NULL;
+
+	dsim = dev_id;
+	if (!dsim) {
+		dev_dbg(dsim->dev, KERN_ERR "%s:error: wrong parameter\n",
+							__func__);
+		return IRQ_HANDLED;
+	}
+
+	intsrc = exynos_mipi_dsi_read_interrupt(dsim);
+	intmsk = exynos_mipi_dsi_read_interrupt_mask(dsim);
+
+	intmsk = ~(intmsk) & intsrc;
+
+	switch (intmsk) {
+	case INTMSK_RX_DONE:
+		complete(&dsim_rd_comp);
+		dev_dbg(dsim->dev, "MIPI INTMSK_RX_DONE\n");
+		break;
+	case INTMSK_FIFO_EMPTY:
+		complete(&dsim_wr_comp);
+		dev_dbg(dsim->dev, "MIPI INTMSK_FIFO_EMPTY\n");
+		break;
+	default:
+		break;
+	}
+
+	exynos_mipi_dsi_clear_interrupt(dsim, intmsk);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * write long packet to mipi dsi slave
+ * @dsim: mipi dsim device structure.
+ * @data0: packet data to send.
+ * @data1: size of packet data
+ */
+static void exynos_mipi_dsi_long_data_wr(struct mipi_dsim_device *dsim,
+		const unsigned char *data0, unsigned int data_size)
+{
+	unsigned int data_cnt = 0, payload = 0;
+
+	/* in case that data count is more then 4 */
+	for (data_cnt = 0; data_cnt < data_size; data_cnt += 4) {
+		/*
+		 * after sending 4bytes per one time,
+		 * send remainder data less then 4.
+		 */
+		if ((data_size - data_cnt) < 4) {
+			if ((data_size - data_cnt) == 3) {
+				payload = data0[data_cnt] |
+				    data0[data_cnt + 1] << 8 |
+					data0[data_cnt + 2] << 16;
+			dev_dbg(dsim->dev, "count = 3 payload = %x, %x %x %x\n",
+				payload, data0[data_cnt],
+				data0[data_cnt + 1],
+				data0[data_cnt + 2]);
+			} else if ((data_size - data_cnt) == 2) {
+				payload = data0[data_cnt] |
+					data0[data_cnt + 1] << 8;
+			dev_dbg(dsim->dev,
+				"count = 2 payload = %x, %x %x\n", payload,
+				data0[data_cnt],
+				data0[data_cnt + 1]);
+			} else if ((data_size - data_cnt) == 1) {
+				payload = data0[data_cnt];
+			}
+
+			exynos_mipi_dsi_wr_tx_data(dsim, payload);
+		/* send 4bytes per one time. */
+		} else {
+			payload = data0[data_cnt] |
+				data0[data_cnt + 1] << 8 |
+				data0[data_cnt + 2] << 16 |
+				data0[data_cnt + 3] << 24;
+
+			dev_dbg(dsim->dev,
+				"count = 4 payload = %x, %x %x %x %x\n",
+				payload, *(u8 *)(data0 + data_cnt),
+				data0[data_cnt + 1],
+				data0[data_cnt + 2],
+				data0[data_cnt + 3]);
+
+			exynos_mipi_dsi_wr_tx_data(dsim, payload);
+		}
+	}
+}
+
+int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+	const unsigned char *data0, unsigned int data_size)
+{
+	unsigned int check_rx_ack = 0;
+
+	if (dsim->state == DSIM_STATE_ULPS) {
+		dev_err(dsim->dev, "state is ULPS.\n");
+
+		return -EINVAL;
+	}
+
+	/* FIXME!!! why does it need this delay? */
+	msleep(20);
+
+	mutex_lock(&dsim->lock);
+
+	switch (data_id) {
+	/* short packet types of packet types for command. */
+	case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
+	case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
+	case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
+	case MIPI_DSI_DCS_SHORT_WRITE:
+	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+	case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
+		exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]);
+		if (check_rx_ack) {
+			/* process response func should be implemented */
+			mutex_unlock(&dsim->lock);
+			return 0;
+		} else {
+			mutex_unlock(&dsim->lock);
+			return -EINVAL;
+		}
+
+	/* general command */
+	case MIPI_DSI_COLOR_MODE_OFF:
+	case MIPI_DSI_COLOR_MODE_ON:
+	case MIPI_DSI_SHUTDOWN_PERIPHERAL:
+	case MIPI_DSI_TURN_ON_PERIPHERAL:
+		exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]);
+		if (check_rx_ack) {
+			/* process response func should be implemented. */
+			mutex_unlock(&dsim->lock);
+			return 0;
+		} else {
+			mutex_unlock(&dsim->lock);
+			return -EINVAL;
+		}
+
+	/* packet types for video data */
+	case MIPI_DSI_V_SYNC_START:
+	case MIPI_DSI_V_SYNC_END:
+	case MIPI_DSI_H_SYNC_START:
+	case MIPI_DSI_H_SYNC_END:
+	case MIPI_DSI_END_OF_TRANSMISSION:
+		mutex_unlock(&dsim->lock);
+		return 0;
+
+	/* long packet type and null packet */
+	case MIPI_DSI_NULL_PACKET:
+	case MIPI_DSI_BLANKING_PACKET:
+		mutex_unlock(&dsim->lock);
+		return 0;
+	case MIPI_DSI_GENERIC_LONG_WRITE:
+	case MIPI_DSI_DCS_LONG_WRITE:
+	{
+		unsigned int size, payload = 0;
+		INIT_COMPLETION(dsim_wr_comp);
+
+		size = data_size * 4;
+
+		/* if data count is less then 4, then send 3bytes data.  */
+		if (data_size < 4) {
+			payload = data0[0] |
+				data0[1] << 8 |
+				data0[2] << 16;
+
+			exynos_mipi_dsi_wr_tx_data(dsim, payload);
+
+			dev_dbg(dsim->dev, "count = %d payload = %x,%x %x %x\n",
+				data_size, payload, data0[0],
+				data0[1], data0[2]);
+
+		/* in case that data count is more then 4 */
+		} else
+			exynos_mipi_dsi_long_data_wr(dsim, data0, data_size);
+
+		/* put data into header fifo */
+		exynos_mipi_dsi_wr_tx_header(dsim, data_id, data_size & 0xff,
+			(data_size & 0xff00) >> 8);
+
+		if (!wait_for_completion_interruptible_timeout(&dsim_wr_comp,
+							MIPI_FIFO_TIMEOUT)) {
+			dev_warn(dsim->dev, "command write timeout.\n");
+			mutex_unlock(&dsim->lock);
+			return -EAGAIN;
+		}
+
+		if (check_rx_ack) {
+			/* process response func should be implemented. */
+			mutex_unlock(&dsim->lock);
+			return 0;
+		} else {
+			mutex_unlock(&dsim->lock);
+			return -EINVAL;
+		}
+	}
+
+	/* packet typo for video data */
+	case MIPI_DSI_PACKED_PIXEL_STREAM_16:
+	case MIPI_DSI_PACKED_PIXEL_STREAM_18:
+	case MIPI_DSI_PIXEL_STREAM_3BYTE_18:
+	case MIPI_DSI_PACKED_PIXEL_STREAM_24:
+		if (check_rx_ack) {
+			/* process response func should be implemented. */
+			mutex_unlock(&dsim->lock);
+			return 0;
+		} else {
+			mutex_unlock(&dsim->lock);
+			return -EINVAL;
+		}
+	default:
+		dev_warn(dsim->dev,
+			"data id %x is not supported current DSI spec.\n",
+			data_id);
+
+		mutex_unlock(&dsim->lock);
+		return -EINVAL;
+	}
+
+	mutex_unlock(&dsim->lock);
+	return 0;
+}
+
+static unsigned int exynos_mipi_dsi_long_data_rd(struct mipi_dsim_device *dsim,
+		unsigned int req_size, unsigned int rx_data, u8 *rx_buf)
+{
+	unsigned int rcv_pkt, i, j;
+	u16 rxsize;
+
+	/* for long packet */
+	rxsize = (u16)((rx_data & 0x00ffff00) >> 8);
+	dev_dbg(dsim->dev, "mipi dsi rx size : %d\n", rxsize);
+	if (rxsize != req_size) {
+		dev_dbg(dsim->dev,
+			"received size mismatch received: %d, requested: %d\n",
+			rxsize, req_size);
+		goto err;
+	}
+
+	for (i = 0; i < (rxsize >> 2); i++) {
+		rcv_pkt = exynos_mipi_dsi_rd_rx_fifo(dsim);
+		dev_dbg(dsim->dev, "received pkt : %08x\n", rcv_pkt);
+		for (j = 0; j < 4; j++) {
+			rx_buf[(i * 4) + j] =
+					(u8)(rcv_pkt >> (j * 8)) & 0xff;
+			dev_dbg(dsim->dev, "received value : %02x\n",
+					(rcv_pkt >> (j * 8)) & 0xff);
+		}
+	}
+	if (rxsize % 4) {
+		rcv_pkt = exynos_mipi_dsi_rd_rx_fifo(dsim);
+		dev_dbg(dsim->dev, "received pkt : %08x\n", rcv_pkt);
+		for (j = 0; j < (rxsize % 4); j++) {
+			rx_buf[(i * 4) + j] =
+					(u8)(rcv_pkt >> (j * 8)) & 0xff;
+			dev_dbg(dsim->dev, "received value : %02x\n",
+					(rcv_pkt >> (j * 8)) & 0xff);
+		}
+	}
+
+	return rxsize;
+
+err:
+	return -EINVAL;
+}
+
+static unsigned int exynos_mipi_dsi_response_size(unsigned int req_size)
+{
+	switch (req_size) {
+	case 1:
+		return MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE;
+	case 2:
+		return MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE;
+	default:
+		return MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE;
+	}
+}
+
+int exynos_mipi_dsi_rd_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+	unsigned int data0, unsigned int req_size, u8 *rx_buf)
+{
+	unsigned int rx_data, rcv_pkt, i;
+	u8 response = 0;
+	u16 rxsize;
+
+	if (dsim->state == DSIM_STATE_ULPS) {
+		dev_err(dsim->dev, "state is ULPS.\n");
+
+		return -EINVAL;
+	}
+
+	/* FIXME!!! */
+	msleep(20);
+
+	mutex_lock(&dsim->lock);
+	INIT_COMPLETION(dsim_rd_comp);
+	exynos_mipi_dsi_rd_tx_header(dsim,
+		MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, req_size);
+
+	response = exynos_mipi_dsi_response_size(req_size);
+
+	switch (data_id) {
+	case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
+	case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
+	case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
+	case MIPI_DSI_DCS_READ:
+		exynos_mipi_dsi_rd_tx_header(dsim,
+			data_id, data0);
+		/* process response func should be implemented. */
+		break;
+	default:
+		dev_warn(dsim->dev,
+			"data id %x is not supported current DSI spec.\n",
+			data_id);
+
+		return -EINVAL;
+	}
+
+	if (!wait_for_completion_interruptible_timeout(&dsim_rd_comp,
+				MIPI_FIFO_TIMEOUT)) {
+		pr_err("RX done interrupt timeout\n");
+		mutex_unlock(&dsim->lock);
+		return 0;
+	}
+
+	msleep(20);
+
+	rx_data = exynos_mipi_dsi_rd_rx_fifo(dsim);
+
+	if ((u8)(rx_data & 0xff) != response) {
+		printk(KERN_ERR
+			"mipi dsi wrong response rx_data : %x, response:%x\n",
+			rx_data, response);
+		goto clear_rx_fifo;
+	}
+
+	if (req_size <= 2) {
+		/* for short packet */
+		for (i = 0; i < req_size; i++)
+			rx_buf[i] = (rx_data >> (8 + (i * 8))) & 0xff;
+		rxsize = req_size;
+	} else {
+		/* for long packet */
+		rxsize = exynos_mipi_dsi_long_data_rd(dsim, req_size, rx_data,
+							rx_buf);
+		if (rxsize != req_size)
+			goto clear_rx_fifo;
+	}
+
+	rcv_pkt = exynos_mipi_dsi_rd_rx_fifo(dsim);
+
+	msleep(20);
+
+	if (rcv_pkt != MIPI_RX_FIFO_READ_DONE) {
+		dev_info(dsim->dev,
+			"Can't found RX FIFO READ DONE FLAG : %x\n", rcv_pkt);
+		goto clear_rx_fifo;
+	}
+
+	mutex_unlock(&dsim->lock);
+
+	return rxsize;
+
+clear_rx_fifo:
+	i = 0;
+	while (1) {
+		rcv_pkt = exynos_mipi_dsi_rd_rx_fifo(dsim);
+		if ((rcv_pkt == MIPI_RX_FIFO_READ_DONE)
+				|| (i > MIPI_MAX_RX_FIFO))
+			break;
+		dev_dbg(dsim->dev,
+				"mipi dsi clear rx fifo : %08x\n", rcv_pkt);
+		i++;
+	}
+	dev_info(dsim->dev,
+		"mipi dsi rx done count : %d, rcv_pkt : %08x\n", i, rcv_pkt);
+
+	mutex_unlock(&dsim->lock);
+
+	return 0;
+}
+
+static int exynos_mipi_dsi_pll_on(struct mipi_dsim_device *dsim,
+				unsigned int enable)
+{
+	int sw_timeout;
+
+	if (enable) {
+		sw_timeout = 1000;
+
+		exynos_mipi_dsi_enable_pll(dsim, 1);
+		while (1) {
+			sw_timeout--;
+			if (exynos_mipi_dsi_is_pll_stable(dsim))
+				return 0;
+			if (sw_timeout == 0)
+				return -EINVAL;
+		}
+	} else
+		exynos_mipi_dsi_enable_pll(dsim, 0);
+
+	return 0;
+}
+
+static unsigned long exynos_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
+	unsigned int pre_divider, unsigned int main_divider,
+	unsigned int scaler)
+{
+	unsigned long dfin_pll, dfvco, dpll_out;
+	unsigned int i, freq_band = 0xf;
+
+	dfin_pll = (FIN_HZ / pre_divider);
+
+	/******************************************************
+	 *	Serial Clock(=ByteClk X 8)	FreqBand[3:0] *
+	 ******************************************************
+	 *	~ 99.99 MHz			0000
+	 *	100 ~ 119.99 MHz		0001
+	 *	120 ~ 159.99 MHz		0010
+	 *	160 ~ 199.99 MHz		0011
+	 *	200 ~ 239.99 MHz		0100
+	 *	140 ~ 319.99 MHz		0101
+	 *	320 ~ 389.99 MHz		0110
+	 *	390 ~ 449.99 MHz		0111
+	 *	450 ~ 509.99 MHz		1000
+	 *	510 ~ 559.99 MHz		1001
+	 *	560 ~ 639.99 MHz		1010
+	 *	640 ~ 689.99 MHz		1011
+	 *	690 ~ 769.99 MHz		1100
+	 *	770 ~ 869.99 MHz		1101
+	 *	870 ~ 949.99 MHz		1110
+	 *	950 ~ 1000 MHz			1111
+	 ******************************************************/
+	if (dfin_pll < DFIN_PLL_MIN_HZ || dfin_pll > DFIN_PLL_MAX_HZ) {
+		dev_warn(dsim->dev, "fin_pll range should be 6MHz ~ 12MHz\n");
+		exynos_mipi_dsi_enable_afc(dsim, 0, 0);
+	} else {
+		if (dfin_pll < 7 * MHZ)
+			exynos_mipi_dsi_enable_afc(dsim, 1, 0x1);
+		else if (dfin_pll < 8 * MHZ)
+			exynos_mipi_dsi_enable_afc(dsim, 1, 0x0);
+		else if (dfin_pll < 9 * MHZ)
+			exynos_mipi_dsi_enable_afc(dsim, 1, 0x3);
+		else if (dfin_pll < 10 * MHZ)
+			exynos_mipi_dsi_enable_afc(dsim, 1, 0x2);
+		else if (dfin_pll < 11 * MHZ)
+			exynos_mipi_dsi_enable_afc(dsim, 1, 0x5);
+		else
+			exynos_mipi_dsi_enable_afc(dsim, 1, 0x4);
+	}
+
+	dfvco = dfin_pll * main_divider;
+	dev_dbg(dsim->dev, "dfvco = %lu, dfin_pll = %lu, main_divider = %d\n",
+				dfvco, dfin_pll, main_divider);
+	if (dfvco < DFVCO_MIN_HZ || dfvco > DFVCO_MAX_HZ)
+		dev_warn(dsim->dev, "fvco range should be 500MHz ~ 1000MHz\n");
+
+	dpll_out = dfvco / (1 << scaler);
+	dev_dbg(dsim->dev, "dpll_out = %lu, dfvco = %lu, scaler = %d\n",
+		dpll_out, dfvco, scaler);
+
+	for (i = 0; i < ARRAY_SIZE(dpll_table); i++) {
+		if (dpll_out < dpll_table[i] * MHZ) {
+			freq_band = i;
+			break;
+		}
+	}
+
+	dev_dbg(dsim->dev, "freq_band = %d\n", freq_band);
+
+	exynos_mipi_dsi_pll_freq(dsim, pre_divider, main_divider, scaler);
+
+	exynos_mipi_dsi_hs_zero_ctrl(dsim, 0);
+	exynos_mipi_dsi_prep_ctrl(dsim, 0);
+
+	/* Freq Band */
+	exynos_mipi_dsi_pll_freq_band(dsim, freq_band);
+
+	/* Stable time */
+	exynos_mipi_dsi_pll_stable_time(dsim, dsim->dsim_config->pll_stable_time);
+
+	/* Enable PLL */
+	dev_dbg(dsim->dev, "FOUT of mipi dphy pll is %luMHz\n",
+		(dpll_out / MHZ));
+
+	return dpll_out;
+}
+
+static int exynos_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
+	unsigned int byte_clk_sel, unsigned int enable)
+{
+	unsigned int esc_div;
+	unsigned long esc_clk_error_rate;
+	unsigned long hs_clk = 0, byte_clk = 0, escape_clk = 0;
+
+	if (enable) {
+		dsim->e_clk_src = byte_clk_sel;
+
+		/* Escape mode clock and byte clock source */
+		exynos_mipi_dsi_set_byte_clock_src(dsim, byte_clk_sel);
+
+		/* DPHY, DSIM Link : D-PHY clock out */
+		if (byte_clk_sel == DSIM_PLL_OUT_DIV8) {
+			hs_clk = exynos_mipi_dsi_change_pll(dsim,
+				dsim->dsim_config->p, dsim->dsim_config->m,
+				dsim->dsim_config->s);
+			if (hs_clk == 0) {
+				dev_err(dsim->dev,
+					"failed to get hs clock.\n");
+				return -EINVAL;
+			}
+
+			byte_clk = hs_clk / 8;
+			exynos_mipi_dsi_enable_pll_bypass(dsim, 0);
+			exynos_mipi_dsi_pll_on(dsim, 1);
+		/* DPHY : D-PHY clock out, DSIM link : external clock out */
+		} else if (byte_clk_sel == DSIM_EXT_CLK_DIV8) {
+			dev_warn(dsim->dev, "this project is not support\n");
+			dev_warn(dsim->dev,
+				"external clock source for MIPI DSIM.\n");
+		} else if (byte_clk_sel == DSIM_EXT_CLK_BYPASS) {
+			dev_warn(dsim->dev, "this project is not support\n");
+			dev_warn(dsim->dev,
+				"external clock source for MIPI DSIM\n");
+		}
+
+		/* escape clock divider */
+		esc_div = byte_clk / (dsim->dsim_config->esc_clk);
+		dev_dbg(dsim->dev,
+			"esc_div = %d, byte_clk = %lu, esc_clk = %lu\n",
+			esc_div, byte_clk, dsim->dsim_config->esc_clk);
+		if ((byte_clk / esc_div) >= (20 * MHZ) ||
+				(byte_clk / esc_div) >
+					dsim->dsim_config->esc_clk)
+			esc_div += 1;
+
+		escape_clk = byte_clk / esc_div;
+		dev_dbg(dsim->dev,
+			"escape_clk = %lu, byte_clk = %lu, esc_div = %d\n",
+			escape_clk, byte_clk, esc_div);
+
+		/* enable escape clock. */
+		exynos_mipi_dsi_enable_byte_clock(dsim, 1);
+
+		/* enable byte clk and escape clock */
+		exynos_mipi_dsi_set_esc_clk_prs(dsim, 1, esc_div);
+		/* escape clock on lane */
+		exynos_mipi_dsi_enable_esc_clk_on_lane(dsim,
+			(DSIM_LANE_CLOCK | dsim->data_lane), 1);
+
+		dev_dbg(dsim->dev, "byte clock is %luMHz\n",
+			(byte_clk / MHZ));
+		dev_dbg(dsim->dev, "escape clock that user's need is %lu\n",
+			(dsim->dsim_config->esc_clk / MHZ));
+		dev_dbg(dsim->dev, "escape clock divider is %x\n", esc_div);
+		dev_dbg(dsim->dev, "escape clock is %luMHz\n",
+			((byte_clk / esc_div) / MHZ));
+
+		if ((byte_clk / esc_div) > escape_clk) {
+			esc_clk_error_rate = escape_clk /
+				(byte_clk / esc_div);
+			dev_warn(dsim->dev, "error rate is %lu over.\n",
+				(esc_clk_error_rate / 100));
+		} else if ((byte_clk / esc_div) < (escape_clk)) {
+			esc_clk_error_rate = (byte_clk / esc_div) /
+				escape_clk;
+			dev_warn(dsim->dev, "error rate is %lu under.\n",
+				(esc_clk_error_rate / 100));
+		}
+	} else {
+		exynos_mipi_dsi_enable_esc_clk_on_lane(dsim,
+			(DSIM_LANE_CLOCK | dsim->data_lane), 0);
+		exynos_mipi_dsi_set_esc_clk_prs(dsim, 0, 0);
+
+		/* disable escape clock. */
+		exynos_mipi_dsi_enable_byte_clock(dsim, 0);
+
+		if (byte_clk_sel == DSIM_PLL_OUT_DIV8)
+			exynos_mipi_dsi_pll_on(dsim, 0);
+	}
+
+	return 0;
+}
+
+int exynos_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim)
+{
+	dsim->state = DSIM_STATE_INIT;
+
+	switch (dsim->dsim_config->e_no_data_lane) {
+	case DSIM_DATA_LANE_1:
+		dsim->data_lane = DSIM_LANE_DATA0;
+		break;
+	case DSIM_DATA_LANE_2:
+		dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1;
+		break;
+	case DSIM_DATA_LANE_3:
+		dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
+			DSIM_LANE_DATA2;
+		break;
+	case DSIM_DATA_LANE_4:
+		dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
+			DSIM_LANE_DATA2 | DSIM_LANE_DATA3;
+		break;
+	default:
+		dev_info(dsim->dev, "data lane is invalid.\n");
+		return -EINVAL;
+	};
+
+	exynos_mipi_dsi_sw_reset(dsim);
+	exynos_mipi_dsi_func_reset(dsim);
+
+	exynos_mipi_dsi_dp_dn_swap(dsim, 0);
+
+	return 0;
+}
+
+void exynos_mipi_dsi_init_interrupt(struct mipi_dsim_device *dsim)
+{
+	unsigned int src = 0;
+
+	src = (INTSRC_SFR_FIFO_EMPTY | INTSRC_RX_DATA_DONE);
+	exynos_mipi_dsi_set_interrupt(dsim, src, 1);
+
+	src = 0;
+	src = ~(INTMSK_RX_DONE | INTMSK_FIFO_EMPTY);
+	exynos_mipi_dsi_set_interrupt_mask(dsim, src, 1);
+}
+
+int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
+	unsigned int enable)
+{
+	/* enable only frame done interrupt */
+	exynos_mipi_dsi_set_interrupt_mask(dsim, INTMSK_FRAME_DONE, enable);
+
+	return 0;
+}
+
+void exynos_mipi_dsi_stand_by(struct mipi_dsim_device *dsim,
+		unsigned int enable)
+{
+
+	/* consider Main display and Sub display. */
+
+	exynos_mipi_dsi_set_main_stand_by(dsim, enable);
+}
+
+int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
+	struct mipi_dsim_config *dsim_config)
+{
+	struct mipi_dsim_platform_data *dsim_pd;
+	struct fb_videomode *timing;
+
+	dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
+	timing = (struct fb_videomode *)dsim_pd->lcd_panel_info;
+
+	/* in case of VIDEO MODE (RGB INTERFACE), it sets polarities. */
+	if (dsim_config->e_interface == (u32) DSIM_VIDEO) {
+		if (dsim_config->auto_vertical_cnt == 0) {
+			exynos_mipi_dsi_set_main_disp_vporch(dsim,
+				dsim_config->cmd_allow,
+				timing->upper_margin,
+				timing->lower_margin);
+			exynos_mipi_dsi_set_main_disp_hporch(dsim,
+				timing->left_margin,
+				timing->right_margin);
+			exynos_mipi_dsi_set_main_disp_sync_area(dsim,
+				timing->vsync_len,
+				timing->hsync_len);
+		}
+	}
+
+	exynos_mipi_dsi_set_main_disp_resol(dsim, timing->xres,
+			timing->yres);
+
+	exynos_mipi_dsi_display_config(dsim, dsim_config);
+
+	dev_info(dsim->dev, "lcd panel ==> width = %d, height = %d\n",
+			timing->xres, timing->yres);
+
+	return 0;
+}
+
+int exynos_mipi_dsi_init_link(struct mipi_dsim_device *dsim)
+{
+	unsigned int time_out = 100;
+
+	switch (dsim->state) {
+	case DSIM_STATE_INIT:
+		exynos_mipi_dsi_init_fifo_pointer(dsim, 0x1f);
+
+		/* dsi configuration */
+		exynos_mipi_dsi_init_config(dsim);
+		exynos_mipi_dsi_enable_lane(dsim, DSIM_LANE_CLOCK, 1);
+		exynos_mipi_dsi_enable_lane(dsim, dsim->data_lane, 1);
+
+		/* set clock configuration */
+		exynos_mipi_dsi_set_clock(dsim, dsim->dsim_config->e_byte_clk, 1);
+
+		/* check clock and data lane state are stop state */
+		while (!(exynos_mipi_dsi_is_lane_state(dsim))) {
+			time_out--;
+			if (time_out == 0) {
+				dev_err(dsim->dev,
+					"DSI Master is not stop state.\n");
+				dev_err(dsim->dev,
+					"Check initialization process\n");
+
+				return -EINVAL;
+			}
+		}
+		if (time_out != 0) {
+			dev_info(dsim->dev,
+				"DSI Master driver has been completed.\n");
+			dev_info(dsim->dev, "DSI Master state is stop state\n");
+		}
+
+		dsim->state = DSIM_STATE_STOP;
+
+		/* BTA sequence counters */
+		exynos_mipi_dsi_set_stop_state_counter(dsim,
+			dsim->dsim_config->stop_holding_cnt);
+		exynos_mipi_dsi_set_bta_timeout(dsim,
+			dsim->dsim_config->bta_timeout);
+		exynos_mipi_dsi_set_lpdr_timeout(dsim,
+			dsim->dsim_config->rx_timeout);
+
+		return 0;
+	default:
+		dev_info(dsim->dev, "DSI Master is already init.\n");
+		return 0;
+	}
+
+	return 0;
+}
+
+int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim)
+{
+	if (dsim->state != DSIM_STATE_STOP) {
+		dev_warn(dsim->dev, "DSIM is not in stop state.\n");
+		return 0;
+	}
+
+	if (dsim->e_clk_src == DSIM_EXT_CLK_BYPASS) {
+		dev_warn(dsim->dev, "clock source is external bypass.\n");
+		return 0;
+	}
+
+	dsim->state = DSIM_STATE_HSCLKEN;
+
+	 /* set LCDC and CPU transfer mode to HS. */
+	exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
+	exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
+	exynos_mipi_dsi_enable_hs_clock(dsim, 1);
+
+	return 0;
+}
+
+int exynos_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
+		unsigned int mode)
+{
+	if (mode) {
+		if (dsim->state != DSIM_STATE_HSCLKEN) {
+			dev_err(dsim->dev, "HS Clock lane is not enabled.\n");
+			return -EINVAL;
+		}
+
+		exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
+	} else {
+		if (dsim->state == DSIM_STATE_INIT || dsim->state ==
+			DSIM_STATE_ULPS) {
+			dev_err(dsim->dev,
+				"DSI Master is not STOP or HSDT state.\n");
+			return -EINVAL;
+		}
+
+		exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
+	}
+
+	return 0;
+}
+
+int exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
+{
+	return _exynos_mipi_dsi_get_frame_done_status(dsim);
+}
+
+int exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
+{
+	_exynos_mipi_dsi_clear_frame_done(dsim);
+
+	return 0;
+}
+
+int exynos_mipi_dsi_fifo_clear(struct mipi_dsim_device *dsim,
+				unsigned int val)
+{
+	int try = TRY_FIFO_CLEAR;
+
+	exynos_mipi_dsi_sw_reset_release(dsim);
+	exynos_mipi_dsi_func_reset(dsim);
+
+	do {
+		if (exynos_mipi_dsi_get_sw_reset_release(dsim)) {
+			exynos_mipi_dsi_init_interrupt(dsim);
+			dev_dbg(dsim->dev, "reset release done.\n");
+			return 0;
+		}
+	} while (--try);
+
+	dev_err(dsim->dev, "failed to clear dsim fifo.\n");
+	return -EAGAIN;
+}
+
+MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("Samusung SoC MIPI-DSI common driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.h b/drivers/video/exynos/exynos_mipi_dsi_common.h
new file mode 100644
index 0000000..4125522
--- /dev/null
+++ b/drivers/video/exynos/exynos_mipi_dsi_common.h
@@ -0,0 +1,46 @@
+/* linux/drivers/video/exynos_mipi_dsi_common.h
+ *
+ * Header file for Samsung SoC MIPI-DSI common driver.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@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.
+*/
+
+#ifndef _EXYNOS_MIPI_DSI_COMMON_H
+#define _EXYNOS_MIPI_DSI_COMMON_H
+
+static DECLARE_COMPLETION(dsim_rd_comp);
+static DECLARE_COMPLETION(dsim_wr_comp);
+
+int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+	const unsigned char *data0, unsigned int data_size);
+int exynos_mipi_dsi_rd_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+	unsigned int data0, unsigned int req_size, u8 *rx_buf);
+irqreturn_t exynos_mipi_dsi_interrupt_handler(int irq, void *dev_id);
+void exynos_mipi_dsi_init_interrupt(struct mipi_dsim_device *dsim);
+int exynos_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim);
+void exynos_mipi_dsi_stand_by(struct mipi_dsim_device *dsim,
+		unsigned int enable);
+int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
+			struct mipi_dsim_config *dsim_info);
+int exynos_mipi_dsi_init_link(struct mipi_dsim_device *dsim);
+int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim);
+int exynos_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
+		unsigned int mode);
+int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
+	unsigned int enable);
+int exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
+int exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
+
+extern struct fb_info *registered_fb[FB_MAX] __read_mostly;
+
+int exynos_mipi_dsi_fifo_clear(struct mipi_dsim_device *dsim,
+				unsigned int val);
+
+#endif /* _EXYNOS_MIPI_DSI_COMMON_H */
diff --git a/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c
new file mode 100644
index 0000000..0ef38ce
--- /dev/null
+++ b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c
@@ -0,0 +1,618 @@
+/* linux/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c
+ *
+ * Samsung SoC MIPI-DSI lowlevel driver.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae, <inki.dae@samsung.com>
+ * Donghwa Lee, <dh09.lee@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/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+
+#include <video/exynos_mipi_dsim.h>
+
+#include <mach/map.h>
+
+#include "exynos_mipi_dsi_regs.h"
+
+void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg;
+
+	reg = readl(dsim->reg_base + EXYNOS_DSIM_SWRST);
+
+	reg |= DSIM_FUNCRST;
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_SWRST);
+}
+
+void exynos_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg;
+
+	reg = readl(dsim->reg_base + EXYNOS_DSIM_SWRST);
+
+	reg |= DSIM_SWRST;
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_SWRST);
+}
+
+void exynos_mipi_dsi_sw_reset_release(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg;
+
+	reg = readl(dsim->reg_base + EXYNOS_DSIM_INTSRC);
+
+	reg |= INTSRC_SW_RST_RELEASE;
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_INTSRC);
+}
+
+int exynos_mipi_dsi_get_sw_reset_release(struct mipi_dsim_device *dsim)
+{
+	return (readl(dsim->reg_base + EXYNOS_DSIM_INTSRC)) &
+			INTSRC_SW_RST_RELEASE;
+}
+
+unsigned int exynos_mipi_dsi_read_interrupt_mask(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg;
+
+	reg = readl(dsim->reg_base + EXYNOS_DSIM_INTMSK);
+
+	return reg;
+}
+
+void exynos_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
+		unsigned int mode, unsigned int mask)
+{
+	unsigned int reg = 0;
+
+	if (mask)
+		reg |= mode;
+	else
+		reg &= ~mode;
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_INTMSK);
+}
+
+void exynos_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
+		unsigned int cfg)
+{
+	unsigned int reg;
+
+	reg = readl(dsim->reg_base + EXYNOS_DSIM_FIFOCTRL);
+
+	writel(reg & ~(cfg), dsim->reg_base + EXYNOS_DSIM_FIFOCTRL);
+	mdelay(10);
+	reg |= cfg;
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_FIFOCTRL);
+}
+
+/*
+ * this function set PLL P, M and S value in D-PHY
+ */
+void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
+		unsigned int value)
+{
+	writel(DSIM_AFC_CTL(value), dsim->reg_base + EXYNOS_DSIM_PHYACCHR);
+}
+
+void exynos_mipi_dsi_set_main_stand_by(struct mipi_dsim_device *dsim,
+		unsigned int enable)
+{
+	unsigned int reg;
+
+	reg = readl(dsim->reg_base + EXYNOS_DSIM_MDRESOL);
+
+	reg &= ~DSIM_MAIN_STAND_BY;
+
+	if (enable)
+		reg |= DSIM_MAIN_STAND_BY;
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_MDRESOL);
+}
+
+void exynos_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
+	unsigned int width_resol, unsigned int height_resol)
+{
+	unsigned int reg;
+
+	/* standby should be set after configuration so set to not ready*/
+	reg = (readl(dsim->reg_base + EXYNOS_DSIM_MDRESOL)) &
+		~(DSIM_MAIN_STAND_BY);
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_MDRESOL);
+
+	reg &= ~((0x7ff << 16) | (0x7ff << 0));
+	reg |= DSIM_MAIN_VRESOL(height_resol) | DSIM_MAIN_HRESOL(width_resol);
+
+	reg |= DSIM_MAIN_STAND_BY;
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_MDRESOL);
+}
+
+void exynos_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
+	unsigned int cmd_allow, unsigned int vfront, unsigned int vback)
+{
+	unsigned int reg;
+
+	reg = (readl(dsim->reg_base + EXYNOS_DSIM_MVPORCH)) &
+		~((DSIM_CMD_ALLOW_MASK) | (DSIM_STABLE_VFP_MASK) |
+		(DSIM_MAIN_VBP_MASK));
+
+	reg |= (DSIM_CMD_ALLOW_SHIFT(cmd_allow & 0xf) |
+		DSIM_STABLE_VFP_SHIFT(vfront & 0x7ff) |
+		DSIM_MAIN_VBP_SHIFT(vback & 0x7ff));
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_MVPORCH);
+}
+
+void exynos_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
+	unsigned int front, unsigned int back)
+{
+	unsigned int reg;
+
+	reg = (readl(dsim->reg_base + EXYNOS_DSIM_MHPORCH)) &
+		~((DSIM_MAIN_HFP_MASK) | (DSIM_MAIN_HBP_MASK));
+
+	reg |= DSIM_MAIN_HFP_SHIFT(front) | DSIM_MAIN_HBP_SHIFT(back);
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_MHPORCH);
+}
+
+void exynos_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
+	unsigned int vert, unsigned int hori)
+{
+	unsigned int reg;
+
+	reg = (readl(dsim->reg_base + EXYNOS_DSIM_MSYNC)) &
+		~((DSIM_MAIN_VSA_MASK) | (DSIM_MAIN_HSA_MASK));
+
+	reg |= (DSIM_MAIN_VSA_SHIFT(vert & 0x3ff) |
+		DSIM_MAIN_HSA_SHIFT(hori));
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_MSYNC);
+}
+
+void exynos_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
+	unsigned int vert, unsigned int hori)
+{
+	unsigned int reg;
+
+	reg = (readl(dsim->reg_base + EXYNOS_DSIM_SDRESOL)) &
+		~(DSIM_SUB_STANDY_MASK);
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_SDRESOL);
+
+	reg &= ~(DSIM_SUB_VRESOL_MASK) | ~(DSIM_SUB_HRESOL_MASK);
+	reg |= (DSIM_SUB_VRESOL_SHIFT(vert & 0x7ff) |
+		DSIM_SUB_HRESOL_SHIFT(hori & 0x7ff));
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_SDRESOL);
+
+	reg |= DSIM_SUB_STANDY_SHIFT(1);
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_SDRESOL);
+}
+
+void exynos_mipi_dsi_init_config(struct mipi_dsim_device *dsim)
+{
+	struct mipi_dsim_config *dsim_config = dsim->dsim_config;
+
+	unsigned int cfg = (readl(dsim->reg_base + EXYNOS_DSIM_CONFIG)) &
+		~((1 << 28) | (0x1f << 20) | (0x3 << 5));
+
+	cfg =	((DSIM_AUTO_FLUSH(dsim_config->auto_flush)) |
+		(DSIM_EOT_DISABLE(dsim_config->eot_disable)) |
+		(DSIM_AUTO_MODE_SHIFT(dsim_config->auto_vertical_cnt)) |
+		(DSIM_HSE_MODE_SHIFT(dsim_config->hse)) |
+		(DSIM_HFP_MODE_SHIFT(dsim_config->hfp)) |
+		(DSIM_HBP_MODE_SHIFT(dsim_config->hbp)) |
+		(DSIM_HSA_MODE_SHIFT(dsim_config->hsa)) |
+		(DSIM_NUM_OF_DATALANE_SHIFT(dsim_config->e_no_data_lane)));
+
+	writel(cfg, dsim->reg_base + EXYNOS_DSIM_CONFIG);
+}
+
+void exynos_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
+				struct mipi_dsim_config *dsim_config)
+{
+	u32 reg = (readl(dsim->reg_base + EXYNOS_DSIM_CONFIG)) &
+		~((0x3 << 26) | (1 << 25) | (0x3 << 18) | (0x7 << 12) |
+		(0x3 << 16) | (0x7 << 8));
+
+	if (dsim_config->e_interface == DSIM_VIDEO)
+		reg |= (1 << 25);
+	else if (dsim_config->e_interface == DSIM_COMMAND)
+		reg &= ~(1 << 25);
+	else {
+		dev_err(dsim->dev, "unknown lcd type.\n");
+		return;
+	}
+
+	/* main lcd */
+	reg |= ((u8) (dsim_config->e_burst_mode) & 0x3) << 26 |
+		((u8) (dsim_config->e_virtual_ch) & 0x3) << 18 |
+		((u8) (dsim_config->e_pixel_format) & 0x7) << 12;
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_CONFIG);
+}
+
+void exynos_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane,
+	unsigned int enable)
+{
+	unsigned int reg;
+
+	reg = readl(dsim->reg_base + EXYNOS_DSIM_CONFIG);
+
+	if (enable)
+		reg |= DSIM_LANE_ENx(lane);
+	else
+		reg &= ~DSIM_LANE_ENx(lane);
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_CONFIG);
+}
+
+
+void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
+	unsigned int count)
+{
+	unsigned int cfg;
+
+	/* get the data lane number. */
+	cfg = DSIM_NUM_OF_DATALANE_SHIFT(count);
+
+	writel(cfg, dsim->reg_base + EXYNOS_DSIM_CONFIG);
+}
+
+void exynos_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable,
+	unsigned int afc_code)
+{
+	unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_PHYACCHR);
+
+	if (enable) {
+		reg |= (1 << 14);
+		reg &= ~(0x7 << 5);
+		reg |= (afc_code & 0x7) << 5;
+	} else
+		reg &= ~(1 << 14);
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_PHYACCHR);
+}
+
+void exynos_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
+	unsigned int enable)
+{
+	unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL)) &
+		~(DSIM_PLL_BYPASS_SHIFT(0x1));
+
+	reg |= DSIM_PLL_BYPASS_SHIFT(enable);
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL);
+}
+
+void exynos_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p,
+	unsigned int m, unsigned int s)
+{
+	unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL);
+
+	reg |= ((p & 0x3f) << 13) | ((m & 0x1ff) << 4) | ((s & 0x7) << 1);
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL);
+}
+
+void exynos_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
+		unsigned int freq_band)
+{
+	unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL)) &
+		~(DSIM_FREQ_BAND_SHIFT(0x1f));
+
+	reg |= DSIM_FREQ_BAND_SHIFT(freq_band & 0x1f);
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL);
+}
+
+void exynos_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
+		unsigned int pre_divider, unsigned int main_divider,
+		unsigned int scaler)
+{
+	unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL)) &
+		~(0x7ffff << 1);
+
+	reg |= (pre_divider & 0x3f) << 13 | (main_divider & 0x1ff) << 4 |
+		(scaler & 0x7) << 1;
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL);
+}
+
+void exynos_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
+	unsigned int lock_time)
+{
+	writel(lock_time, dsim->reg_base + EXYNOS_DSIM_PLLTMR);
+}
+
+void exynos_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim, unsigned int enable)
+{
+	unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL)) &
+		~(DSIM_PLL_EN_SHIFT(0x1));
+
+	reg |= DSIM_PLL_EN_SHIFT(enable & 0x1);
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL);
+}
+
+void exynos_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
+		unsigned int src)
+{
+	unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL)) &
+		~(DSIM_BYTE_CLK_SRC_SHIFT(0x3));
+
+	reg |= (DSIM_BYTE_CLK_SRC_SHIFT(src));
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL);
+}
+
+void exynos_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
+		unsigned int enable)
+{
+	unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL)) &
+		~(DSIM_BYTE_CLKEN_SHIFT(0x1));
+
+	reg |= DSIM_BYTE_CLKEN_SHIFT(enable);
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL);
+}
+
+void exynos_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
+		unsigned int enable, unsigned int prs_val)
+{
+	unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL)) &
+		~(DSIM_ESC_CLKEN_SHIFT(0x1) | 0xffff);
+
+	reg |= DSIM_ESC_CLKEN_SHIFT(enable);
+	if (enable)
+		reg |= prs_val;
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL);
+}
+
+void exynos_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
+		unsigned int lane_sel, unsigned int enable)
+{
+	unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL);
+
+	if (enable)
+		reg |= DSIM_LANE_ESC_CLKEN(lane_sel);
+	else
+
+		reg &= ~DSIM_LANE_ESC_CLKEN(lane_sel);
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL);
+}
+
+void exynos_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
+	unsigned int enable)
+{
+	unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_ESCMODE)) &
+		~(DSIM_FORCE_STOP_STATE_SHIFT(0x1));
+
+	reg |= (DSIM_FORCE_STOP_STATE_SHIFT(enable & 0x1));
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_ESCMODE);
+}
+
+unsigned int exynos_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_STATUS);
+
+	/**
+	 * check clock and data lane states.
+	 * if MIPI-DSI controller was enabled at bootloader then
+	 * TX_READY_HS_CLK is enabled otherwise STOP_STATE_CLK.
+	 * so it should be checked for two case.
+	 */
+	if ((reg & DSIM_STOP_STATE_DAT(0xf)) &&
+			((reg & DSIM_STOP_STATE_CLK) ||
+			 (reg & DSIM_TX_READY_HS_CLK)))
+		return 1;
+
+	return 0;
+}
+
+void exynos_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
+		unsigned int cnt_val)
+{
+	unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_ESCMODE)) &
+		~(DSIM_STOP_STATE_CNT_SHIFT(0x7ff));
+
+	reg |= (DSIM_STOP_STATE_CNT_SHIFT(cnt_val & 0x7ff));
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_ESCMODE);
+}
+
+void exynos_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
+		unsigned int timeout)
+{
+	unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_TIMEOUT)) &
+		~(DSIM_BTA_TOUT_SHIFT(0xff));
+
+	reg |= (DSIM_BTA_TOUT_SHIFT(timeout));
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_TIMEOUT);
+}
+
+void exynos_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
+		unsigned int timeout)
+{
+	unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_TIMEOUT)) &
+		~(DSIM_LPDR_TOUT_SHIFT(0xffff));
+
+	reg |= (DSIM_LPDR_TOUT_SHIFT(timeout));
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_TIMEOUT);
+}
+
+void exynos_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
+		unsigned int lp)
+{
+	unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_ESCMODE);
+
+	reg &= ~DSIM_CMD_LPDT_LP;
+
+	if (lp)
+		reg |= DSIM_CMD_LPDT_LP;
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_ESCMODE);
+}
+
+void exynos_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
+		unsigned int lp)
+{
+	unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_ESCMODE);
+
+	reg &= ~DSIM_TX_LPDT_LP;
+
+	if (lp)
+		reg |= DSIM_TX_LPDT_LP;
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_ESCMODE);
+}
+
+void exynos_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
+		unsigned int enable)
+{
+	unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL)) &
+		~(DSIM_TX_REQUEST_HSCLK_SHIFT(0x1));
+
+	reg |= DSIM_TX_REQUEST_HSCLK_SHIFT(enable);
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL);
+}
+
+void exynos_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
+		unsigned int swap_en)
+{
+	unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_PHYACCHR1);
+
+	reg &= ~(0x3 << 0);
+	reg |= (swap_en & 0x3) << 0;
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_PHYACCHR1);
+}
+
+void exynos_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
+		unsigned int hs_zero)
+{
+	unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL)) &
+		~(0xf << 28);
+
+	reg |= ((hs_zero & 0xf) << 28);
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL);
+}
+
+void exynos_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep)
+{
+	unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL)) &
+		~(0x7 << 20);
+
+	reg |= ((prep & 0x7) << 20);
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL);
+}
+
+unsigned int exynos_mipi_dsi_read_interrupt(struct mipi_dsim_device *dsim)
+{
+	return readl(dsim->reg_base + EXYNOS_DSIM_INTSRC);
+}
+
+void exynos_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim,
+					unsigned int src)
+{
+	unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_INTSRC);
+
+	reg |= src;
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_INTSRC);
+}
+
+void exynos_mipi_dsi_set_interrupt(struct mipi_dsim_device *dsim,
+					unsigned int src, unsigned int enable)
+{
+	unsigned int reg = 0;
+
+	if (enable)
+		reg |= src;
+	else
+		reg &= ~src;
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_INTSRC);
+}
+
+unsigned int exynos_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg;
+
+	reg = readl(dsim->reg_base + EXYNOS_DSIM_STATUS);
+
+	return reg & (1 << 31) ? 1 : 0;
+}
+
+unsigned int exynos_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim)
+{
+	return readl(dsim->reg_base + EXYNOS_DSIM_FIFOCTRL) & ~(0x1f);
+}
+
+void exynos_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim,
+	unsigned int di, unsigned int data0, unsigned int data1)
+{
+	unsigned int reg = (data1 << 16) | (data0 << 8) | ((di & 0x3f) << 0);
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_PKTHDR);
+}
+
+void exynos_mipi_dsi_rd_tx_header(struct mipi_dsim_device *dsim,
+	unsigned int di, unsigned int data0)
+{
+	unsigned int reg = (data0 << 8) | (di << 0);
+
+	writel(reg, dsim->reg_base + EXYNOS_DSIM_PKTHDR);
+}
+
+unsigned int exynos_mipi_dsi_rd_rx_fifo(struct mipi_dsim_device *dsim)
+{
+	return readl(dsim->reg_base + EXYNOS_DSIM_RXFIFO);
+}
+
+unsigned int _exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_INTSRC);
+
+	return (reg & INTSRC_FRAME_DONE) ? 1 : 0;
+}
+
+void _exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_INTSRC);
+
+	writel(reg | INTSRC_FRAME_DONE, dsim->reg_base +
+		EXYNOS_DSIM_INTSRC);
+}
+
+void exynos_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
+		unsigned int tx_data)
+{
+	writel(tx_data, dsim->reg_base + EXYNOS_DSIM_PAYLOAD);
+}
diff --git a/drivers/video/exynos/exynos_mipi_dsi_lowlevel.h b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.h
new file mode 100644
index 0000000..8546070
--- /dev/null
+++ b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.h
@@ -0,0 +1,112 @@
+/* linux/drivers/video/exynos/exynos_mipi_dsi_lowlevel.h
+ *
+ * Header file for Samsung SoC MIPI-DSI lowlevel driver.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@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.
+*/
+
+#ifndef _EXYNOS_MIPI_DSI_LOWLEVEL_H
+#define _EXYNOS_MIPI_DSI_LOWLEVEL_H
+
+void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim);
+void exynos_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim);
+void exynos_mipi_dsi_sw_reset_release(struct mipi_dsim_device *dsim);
+int exynos_mipi_dsi_get_sw_reset_release(struct mipi_dsim_device *dsim);
+void exynos_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
+	unsigned int mode, unsigned int mask);
+void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
+					unsigned int count);
+void exynos_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
+					unsigned int cfg);
+void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
+				unsigned int value);
+void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
+				unsigned int value);
+void exynos_mipi_dsi_set_main_stand_by(struct mipi_dsim_device *dsim,
+		unsigned int enable);
+void exynos_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
+		unsigned int width_resol, unsigned int height_resol);
+void exynos_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
+	unsigned int cmd_allow, unsigned int vfront, unsigned int vback);
+void exynos_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
+			unsigned int front, unsigned int back);
+void exynos_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
+				unsigned int vert, unsigned int hori);
+void exynos_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
+				unsigned int vert, unsigned int hori);
+void exynos_mipi_dsi_init_config(struct mipi_dsim_device *dsim);
+void exynos_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
+				struct mipi_dsim_config *dsim_config);
+void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
+				unsigned int count);
+void exynos_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane,
+				unsigned int enable);
+void exynos_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable,
+				unsigned int afc_code);
+void exynos_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
+				unsigned int enable);
+void exynos_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p,
+				unsigned int m, unsigned int s);
+void exynos_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
+				unsigned int freq_band);
+void exynos_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
+			unsigned int pre_divider, unsigned int main_divider,
+			unsigned int scaler);
+void exynos_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
+			unsigned int lock_time);
+void exynos_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim,
+					unsigned int enable);
+void exynos_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
+					unsigned int src);
+void exynos_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
+					unsigned int enable);
+void exynos_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
+				unsigned int enable, unsigned int prs_val);
+void exynos_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
+				unsigned int lane_sel, unsigned int enable);
+void exynos_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
+				unsigned int enable);
+unsigned int exynos_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim);
+void exynos_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
+				unsigned int cnt_val);
+void exynos_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
+				unsigned int timeout);
+void exynos_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
+				unsigned int timeout);
+void exynos_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
+					unsigned int lp);
+void exynos_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
+					unsigned int lp);
+void exynos_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
+				unsigned int enable);
+void exynos_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
+				unsigned int swap_en);
+void exynos_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
+				unsigned int hs_zero);
+void exynos_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep);
+unsigned int exynos_mipi_dsi_read_interrupt(struct mipi_dsim_device *dsim);
+unsigned int exynos_mipi_dsi_read_interrupt_mask(struct mipi_dsim_device *dsim);
+void exynos_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim,
+					unsigned int src);
+void exynos_mipi_dsi_set_interrupt(struct mipi_dsim_device *dsim,
+					unsigned int src, unsigned int enable);
+unsigned int exynos_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim);
+unsigned int exynos_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim);
+unsigned int _exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
+void _exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
+void exynos_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim, unsigned int di,
+				unsigned int data0, unsigned int data1);
+void exynos_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
+		unsigned int tx_data);
+void exynos_mipi_dsi_rd_tx_header(struct mipi_dsim_device *dsim,
+		unsigned int data0, unsigned int data1);
+unsigned int exynos_mipi_dsi_rd_rx_fifo(struct mipi_dsim_device *dsim);
+
+#endif /* _EXYNOS_MIPI_DSI_LOWLEVEL_H */
diff --git a/drivers/video/exynos/exynos_mipi_dsi_regs.h b/drivers/video/exynos/exynos_mipi_dsi_regs.h
new file mode 100644
index 0000000..4227106
--- /dev/null
+++ b/drivers/video/exynos/exynos_mipi_dsi_regs.h
@@ -0,0 +1,149 @@
+/* linux/driver/video/exynos/exynos_mipi_dsi_regs.h
+ *
+ * Register definition file for Samsung MIPI-DSIM driver
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@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.
+*/
+
+#ifndef _EXYNOS_MIPI_DSI_REGS_H
+#define _EXYNOS_MIPI_DSI_REGS_H
+
+#define EXYNOS_DSIM_STATUS		0x0	/* Status register */
+#define EXYNOS_DSIM_SWRST		0x4	/* Software reset register */
+#define EXYNOS_DSIM_CLKCTRL		0x8	/* Clock control register */
+#define EXYNOS_DSIM_TIMEOUT		0xc	/* Time out register */
+#define EXYNOS_DSIM_CONFIG		0x10	/* Configuration register */
+#define EXYNOS_DSIM_ESCMODE		0x14	/* Escape mode register */
+
+/* Main display image resolution register */
+#define EXYNOS_DSIM_MDRESOL		0x18
+#define EXYNOS_DSIM_MVPORCH		0x1c	/* Main display Vporch register */
+#define EXYNOS_DSIM_MHPORCH		0x20	/* Main display Hporch register */
+#define EXYNOS_DSIM_MSYNC		0x24	/* Main display sync area register */
+
+/* Sub display image resolution register */
+#define EXYNOS_DSIM_SDRESOL		0x28
+#define EXYNOS_DSIM_INTSRC		0x2c	/* Interrupt source register */
+#define EXYNOS_DSIM_INTMSK		0x30	/* Interrupt mask register */
+#define EXYNOS_DSIM_PKTHDR		0x34	/* Packet Header FIFO register */
+#define EXYNOS_DSIM_PAYLOAD		0x38	/* Payload FIFO register */
+#define EXYNOS_DSIM_RXFIFO		0x3c	/* Read FIFO register */
+#define EXYNOS_DSIM_FIFOTHLD		0x40	/* FIFO threshold level register */
+#define EXYNOS_DSIM_FIFOCTRL		0x44	/* FIFO status and control register */
+
+/* FIFO memory AC characteristic register */
+#define EXYNOS_DSIM_PLLCTRL		0x4c	/* PLL control register */
+#define EXYNOS_DSIM_PLLTMR		0x50	/* PLL timer register */
+#define EXYNOS_DSIM_PHYACCHR		0x54	/* D-PHY AC characteristic register */
+#define EXYNOS_DSIM_PHYACCHR1		0x58	/* D-PHY AC characteristic register1 */
+
+/* DSIM_STATUS */
+#define DSIM_STOP_STATE_DAT(x)		(((x) & 0xf) << 0)
+#define DSIM_STOP_STATE_CLK		(1 << 8)
+#define DSIM_TX_READY_HS_CLK		(1 << 10)
+
+/* DSIM_SWRST */
+#define DSIM_FUNCRST			(1 << 16)
+#define DSIM_SWRST			(1 << 0)
+
+/* EXYNOS_DSIM_TIMEOUT */
+#define DSIM_LPDR_TOUT_SHIFT(x)		((x) << 0)
+#define DSIM_BTA_TOUT_SHIFT(x)		((x) << 16)
+
+/* EXYNOS_DSIM_CLKCTRL */
+#define DSIM_LANE_ESC_CLKEN(x)		(((x) & 0x1f) << 19)
+#define DSIM_BYTE_CLKEN_SHIFT(x)	((x) << 24)
+#define DSIM_BYTE_CLK_SRC_SHIFT(x)	((x) <<	25)
+#define DSIM_PLL_BYPASS_SHIFT(x)	((x) <<	27)
+#define DSIM_ESC_CLKEN_SHIFT(x)		((x) << 28)
+#define DSIM_TX_REQUEST_HSCLK_SHIFT(x)	((x) << 31)
+
+/* EXYNOS_DSIM_CONFIG */
+#define DSIM_LANE_ENx(x)		(((x) & 0x1f) << 0)
+#define DSIM_NUM_OF_DATALANE_SHIFT(x)	((x) << 5)
+#define DSIM_HSA_MODE_SHIFT(x)		((x) << 20)
+#define DSIM_HBP_MODE_SHIFT(x)		((x) << 21)
+#define DSIM_HFP_MODE_SHIFT(x)		((x) << 22)
+#define DSIM_HSE_MODE_SHIFT(x)		((x) << 23)
+#define DSIM_AUTO_MODE_SHIFT(x)		((x) << 24)
+#define DSIM_EOT_DISABLE(x)		((x) << 28)
+#define DSIM_AUTO_FLUSH(x)		((x) << 29)
+
+#define DSIM_NUM_OF_DATA_LANE(x)	((x) << DSIM_NUM_OF_DATALANE_SHIFT)
+
+/* EXYNOS_DSIM_ESCMODE */
+#define DSIM_TX_LPDT_LP			(1 << 6)
+#define DSIM_CMD_LPDT_LP		(1 << 7)
+#define DSIM_FORCE_STOP_STATE_SHIFT(x)	((x) << 20)
+#define DSIM_STOP_STATE_CNT_SHIFT(x)	((x) << 21)
+
+/* EXYNOS_DSIM_MDRESOL */
+#define DSIM_MAIN_STAND_BY		(1 << 31)
+#define DSIM_MAIN_VRESOL(x)		(((x) & 0x7ff) << 16)
+#define DSIM_MAIN_HRESOL(x)		(((x) & 0X7ff) << 0)
+
+/* EXYNOS_DSIM_MVPORCH */
+#define DSIM_CMD_ALLOW_SHIFT(x)		((x) << 28)
+#define DSIM_STABLE_VFP_SHIFT(x)	((x) << 16)
+#define DSIM_MAIN_VBP_SHIFT(x)		((x) << 0)
+#define DSIM_CMD_ALLOW_MASK		(0xf << 28)
+#define DSIM_STABLE_VFP_MASK		(0x7ff << 16)
+#define DSIM_MAIN_VBP_MASK		(0x7ff << 0)
+
+/* EXYNOS_DSIM_MHPORCH */
+#define DSIM_MAIN_HFP_SHIFT(x)		((x) << 16)
+#define DSIM_MAIN_HBP_SHIFT(x)		((x) << 0)
+#define DSIM_MAIN_HFP_MASK		((0xffff) << 16)
+#define DSIM_MAIN_HBP_MASK		((0xffff) << 0)
+
+/* EXYNOS_DSIM_MSYNC */
+#define DSIM_MAIN_VSA_SHIFT(x)		((x) << 22)
+#define DSIM_MAIN_HSA_SHIFT(x)		((x) << 0)
+#define DSIM_MAIN_VSA_MASK		((0x3ff) << 22)
+#define DSIM_MAIN_HSA_MASK		((0xffff) << 0)
+
+/* EXYNOS_DSIM_SDRESOL */
+#define DSIM_SUB_STANDY_SHIFT(x)	((x) << 31)
+#define DSIM_SUB_VRESOL_SHIFT(x)	((x) << 16)
+#define DSIM_SUB_HRESOL_SHIFT(x)	((x) << 0)
+#define DSIM_SUB_STANDY_MASK		((0x1) << 31)
+#define DSIM_SUB_VRESOL_MASK		((0x7ff) << 16)
+#define DSIM_SUB_HRESOL_MASK		((0x7ff) << 0)
+
+/* EXYNOS_DSIM_INTSRC */
+#define INTSRC_PLL_STABLE		(1 << 31)
+#define INTSRC_SW_RST_RELEASE		(1 << 30)
+#define INTSRC_SFR_FIFO_EMPTY		(1 << 29)
+#define INTSRC_FRAME_DONE		(1 << 24)
+#define INTSRC_RX_DATA_DONE		(1 << 18)
+
+/* EXYNOS_DSIM_INTMSK */
+#define INTMSK_FIFO_EMPTY		(1 << 29)
+#define INTMSK_BTA			(1 << 25)
+#define INTMSK_FRAME_DONE		(1 << 24)
+#define INTMSK_RX_TIMEOUT		(1 << 21)
+#define INTMSK_BTA_TIMEOUT		(1 << 20)
+#define INTMSK_RX_DONE			(1 << 18)
+#define INTMSK_RX_TE			(1 << 17)
+#define INTMSK_RX_ACK			(1 << 16)
+#define INTMSK_RX_ECC_ERR		(1 << 15)
+#define INTMSK_RX_CRC_ERR		(1 << 14)
+
+/* EXYNOS_DSIM_FIFOCTRL */
+#define SFR_HEADER_EMPTY		(1 << 22)
+
+/* EXYNOS_DSIM_PHYACCHR */
+#define DSIM_AFC_CTL(x)			(((x) & 0x7) << 5)
+
+/* EXYNOS_DSIM_PLLCTRL */
+#define DSIM_PLL_EN_SHIFT(x)		((x) << 23)
+#define DSIM_FREQ_BAND_SHIFT(x)		((x) << 24)
+
+#endif /* _EXYNOS_MIPI_DSI_REGS_H */
diff --git a/drivers/video/exynos/s6e8ax0.c b/drivers/video/exynos/s6e8ax0.c
new file mode 100644
index 0000000..4aa9ac6
--- /dev/null
+++ b/drivers/video/exynos/s6e8ax0.c
@@ -0,0 +1,898 @@
+/* linux/drivers/video/exynos/s6e8ax0.c
+ *
+ * MIPI-DSI based s6e8ax0 AMOLED lcd 4.65 inch panel driver.
+ *
+ * Inki Dae, <inki.dae@samsung.com>
+ * Donghwa Lee, <dh09.lee@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/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/lcd.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+#include <video/exynos_mipi_dsim.h>
+
+#define LDI_MTP_LENGTH		24
+#define DSIM_PM_STABLE_TIME	10
+#define MIN_BRIGHTNESS		0
+#define MAX_BRIGHTNESS		24
+#define GAMMA_TABLE_COUNT	26
+
+#define POWER_IS_ON(pwr)	((pwr) == FB_BLANK_UNBLANK)
+#define POWER_IS_OFF(pwr)	((pwr) == FB_BLANK_POWERDOWN)
+#define POWER_IS_NRM(pwr)	((pwr) == FB_BLANK_NORMAL)
+
+#define lcd_to_master(a)	(a->dsim_dev->master)
+#define lcd_to_master_ops(a)	((lcd_to_master(a))->master_ops)
+
+enum {
+	DSIM_NONE_STATE = 0,
+	DSIM_RESUME_COMPLETE = 1,
+	DSIM_FRAME_DONE = 2,
+};
+
+struct s6e8ax0 {
+	struct device	*dev;
+	unsigned int			power;
+	unsigned int			id;
+	unsigned int			gamma;
+	unsigned int			acl_enable;
+	unsigned int			cur_acl;
+
+	struct lcd_device	*ld;
+	struct backlight_device	*bd;
+
+	struct mipi_dsim_lcd_device	*dsim_dev;
+	struct lcd_platform_data	*ddi_pd;
+	struct mutex			lock;
+	bool  enabled;
+};
+
+
+static struct regulator_bulk_data supplies[] = {
+	{ .supply = "vdd3", },
+	{ .supply = "vci", },
+};
+
+static void s6e8ax0_regulator_enable(struct s6e8ax0 *lcd)
+{
+	int ret = 0;
+	struct lcd_platform_data *pd = NULL;
+
+	pd = lcd->ddi_pd;
+	mutex_lock(&lcd->lock);
+	if (!lcd->enabled) {
+		ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
+		if (ret)
+			goto out;
+
+		lcd->enabled = true;
+	}
+	msleep(pd->power_on_delay);
+out:
+	mutex_unlock(&lcd->lock);
+}
+
+static void s6e8ax0_regulator_disable(struct s6e8ax0 *lcd)
+{
+	int ret = 0;
+
+	mutex_lock(&lcd->lock);
+	if (lcd->enabled) {
+		ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
+		if (ret)
+			goto out;
+
+		lcd->enabled = false;
+	}
+out:
+	mutex_unlock(&lcd->lock);
+}
+
+static const unsigned char s6e8ax0_22_gamma_30[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xf5, 0x00, 0xff, 0xad, 0xaf,
+	0xbA, 0xc3, 0xd8, 0xc5, 0x9f, 0xc6, 0x9e, 0xc1, 0xdc, 0xc0,
+	0x00, 0x61, 0x00, 0x5a, 0x00, 0x74,
+};
+
+static const unsigned char s6e8ax0_22_gamma_50[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xe8, 0x1f, 0xf7, 0xad, 0xc0,
+	0xb5, 0xc4, 0xdc, 0xc4, 0x9e, 0xc6, 0x9c, 0xbb, 0xd8, 0xbb,
+	0x00, 0x70, 0x00, 0x68, 0x00, 0x86,
+};
+
+static const unsigned char s6e8ax0_22_gamma_60[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xde, 0x1f, 0xef, 0xad, 0xc4,
+	0xb3, 0xc3, 0xdd, 0xc4, 0x9e, 0xc6, 0x9c, 0xbc, 0xd6, 0xba,
+	0x00, 0x75, 0x00, 0x6e, 0x00, 0x8d,
+};
+
+static const unsigned char s6e8ax0_22_gamma_70[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xd8, 0x1f, 0xe7, 0xaf, 0xc8,
+	0xb4, 0xc4, 0xdd, 0xc3, 0x9d, 0xc6, 0x9c, 0xbb, 0xd6, 0xb9,
+	0x00, 0x7a, 0x00, 0x72, 0x00, 0x93,
+};
+
+static const unsigned char s6e8ax0_22_gamma_80[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xc9, 0x1f, 0xde, 0xae, 0xc9,
+	0xb1, 0xc3, 0xdd, 0xc2, 0x9d, 0xc5, 0x9b, 0xbc, 0xd6, 0xbb,
+	0x00, 0x7f, 0x00, 0x77, 0x00, 0x99,
+};
+
+static const unsigned char s6e8ax0_22_gamma_90[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xc7, 0x1f, 0xd9, 0xb0, 0xcc,
+	0xb2, 0xc3, 0xdc, 0xc1, 0x9c, 0xc6, 0x9c, 0xbc, 0xd4, 0xb9,
+	0x00, 0x83, 0x00, 0x7b, 0x00, 0x9e,
+};
+
+static const unsigned char s6e8ax0_22_gamma_100[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xbd, 0x80, 0xcd, 0xba, 0xce,
+	0xb3, 0xc4, 0xde, 0xc3, 0x9c, 0xc4, 0x9, 0xb8, 0xd3, 0xb6,
+	0x00, 0x88, 0x00, 0x80, 0x00, 0xa5,
+};
+
+static const unsigned char s6e8ax0_22_gamma_120[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb9, 0x95, 0xc8, 0xb1, 0xcf,
+	0xb2, 0xc6, 0xdf, 0xc5, 0x9b, 0xc3, 0x99, 0xb6, 0xd2, 0xb6,
+	0x00, 0x8f, 0x00, 0x86, 0x00, 0xac,
+};
+
+static const unsigned char s6e8ax0_22_gamma_130[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc7, 0xb1, 0xd0,
+	0xb2, 0xc4, 0xdd, 0xc3, 0x9a, 0xc3, 0x98, 0xb6, 0xd0, 0xb4,
+	0x00, 0x92, 0x00, 0x8a, 0x00, 0xb1,
+};
+
+static const unsigned char s6e8ax0_22_gamma_140[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc5, 0xb2, 0xd0,
+	0xb3, 0xc3, 0xde, 0xc3, 0x9b, 0xc2, 0x98, 0xb6, 0xd0, 0xb4,
+	0x00, 0x95, 0x00, 0x8d, 0x00, 0xb5,
+};
+
+static const unsigned char s6e8ax0_22_gamma_150[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xa0, 0xc2, 0xb2, 0xd0,
+	0xb2, 0xc1, 0xdd, 0xc2, 0x9b, 0xc2, 0x98, 0xb4, 0xcf, 0xb1,
+	0x00, 0x99, 0x00, 0x90, 0x00, 0xba,
+};
+
+static const unsigned char s6e8ax0_22_gamma_160[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xa5, 0xbf, 0xb0, 0xd0,
+	0xb1, 0xc3, 0xde, 0xc2, 0x99, 0xc1, 0x97, 0xb4, 0xce, 0xb1,
+	0x00, 0x9c, 0x00, 0x93, 0x00, 0xbe,
+};
+
+static const unsigned char s6e8ax0_22_gamma_170[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb5, 0xbf, 0xb1, 0xd1,
+	0xb1, 0xc3, 0xde, 0xc3, 0x99, 0xc0, 0x96, 0xb4, 0xce, 0xb1,
+	0x00, 0x9f, 0x00, 0x96, 0x00, 0xc2,
+};
+
+static const unsigned char s6e8ax0_22_gamma_180[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb7, 0xbe, 0xb3, 0xd2,
+	0xb3, 0xc3, 0xde, 0xc2, 0x97, 0xbf, 0x95, 0xb4, 0xcd, 0xb1,
+	0x00, 0xa2, 0x00, 0x99, 0x00, 0xc5,
+};
+
+static const unsigned char s6e8ax0_22_gamma_190[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbe, 0xb2, 0xd2,
+	0xb2, 0xc3, 0xdd, 0xc3, 0x98, 0xbf, 0x95, 0xb2, 0xcc, 0xaf,
+	0x00, 0xa5, 0x00, 0x9c, 0x00, 0xc9,
+};
+
+static const unsigned char s6e8ax0_22_gamma_200[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbc, 0xb2, 0xd2,
+	0xb1, 0xc4, 0xdd, 0xc3, 0x97, 0xbe, 0x95, 0xb1, 0xcb, 0xae,
+	0x00, 0xa8, 0x00, 0x9f, 0x00, 0xcd,
+};
+
+static const unsigned char s6e8ax0_22_gamma_210[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc1, 0xbd, 0xb1, 0xd1,
+	0xb1, 0xc2, 0xde, 0xc2, 0x97, 0xbe, 0x94, 0xB0, 0xc9, 0xad,
+	0x00, 0xae, 0x00, 0xa4, 0x00, 0xd4,
+};
+
+static const unsigned char s6e8ax0_22_gamma_220[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc7, 0xbd, 0xb1, 0xd1,
+	0xb1, 0xc2, 0xdd, 0xc2, 0x97, 0xbd, 0x94, 0xb0, 0xc9, 0xad,
+	0x00, 0xad, 0x00, 0xa2, 0x00, 0xd3,
+};
+
+static const unsigned char s6e8ax0_22_gamma_230[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc3, 0xbd, 0xb2, 0xd1,
+	0xb1, 0xc3, 0xdd, 0xc1, 0x96, 0xbd, 0x94, 0xb0, 0xc9, 0xad,
+	0x00, 0xb0, 0x00, 0xa7, 0x00, 0xd7,
+};
+
+static const unsigned char s6e8ax0_22_gamma_240[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xcb, 0xbd, 0xb1, 0xd2,
+	0xb1, 0xc3, 0xdD, 0xc2, 0x95, 0xbd, 0x93, 0xaf, 0xc8, 0xab,
+	0x00, 0xb3, 0x00, 0xa9, 0x00, 0xdb,
+};
+
+static const unsigned char s6e8ax0_22_gamma_250[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xcc, 0xbe, 0xb0, 0xd2,
+	0xb0, 0xc3, 0xdD, 0xc2, 0x94, 0xbc, 0x92, 0xae, 0xc8, 0xab,
+	0x00, 0xb6, 0x00, 0xab, 0x00, 0xde,
+};
+
+static const unsigned char s6e8ax0_22_gamma_260[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xd0, 0xbe, 0xaf, 0xd1,
+	0xaf, 0xc2, 0xdd, 0xc1, 0x96, 0xbc, 0x93, 0xaf, 0xc8, 0xac,
+	0x00, 0xb7, 0x00, 0xad, 0x00, 0xe0,
+};
+
+static const unsigned char s6e8ax0_22_gamma_270[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xcF, 0xbd, 0xb0, 0xd2,
+	0xaf, 0xc2, 0xdc, 0xc1, 0x95, 0xbd, 0x93, 0xae, 0xc6, 0xaa,
+	0x00, 0xba, 0x00, 0xb0, 0x00, 0xe4,
+};
+
+static const unsigned char s6e8ax0_22_gamma_280[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xd0, 0xbd, 0xaf, 0xd0,
+	0xad, 0xc4, 0xdd, 0xc3, 0x95, 0xbd, 0x93, 0xac, 0xc5, 0xa9,
+	0x00, 0xbd, 0x00, 0xb2, 0x00, 0xe7,
+};
+
+static const unsigned char s6e8ax0_22_gamma_300[] = {
+	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb5, 0xd3, 0xbd, 0xb1, 0xd2,
+	0xb0, 0xc0, 0xdc, 0xc0, 0x94, 0xba, 0x91, 0xac, 0xc5, 0xa9,
+	0x00, 0xc2, 0x00, 0xb7, 0x00, 0xed,
+};
+
+static const unsigned char *s6e8ax0_22_gamma_table[] = {
+	s6e8ax0_22_gamma_30,
+	s6e8ax0_22_gamma_50,
+	s6e8ax0_22_gamma_60,
+	s6e8ax0_22_gamma_70,
+	s6e8ax0_22_gamma_80,
+	s6e8ax0_22_gamma_90,
+	s6e8ax0_22_gamma_100,
+	s6e8ax0_22_gamma_120,
+	s6e8ax0_22_gamma_130,
+	s6e8ax0_22_gamma_140,
+	s6e8ax0_22_gamma_150,
+	s6e8ax0_22_gamma_160,
+	s6e8ax0_22_gamma_170,
+	s6e8ax0_22_gamma_180,
+	s6e8ax0_22_gamma_190,
+	s6e8ax0_22_gamma_200,
+	s6e8ax0_22_gamma_210,
+	s6e8ax0_22_gamma_220,
+	s6e8ax0_22_gamma_230,
+	s6e8ax0_22_gamma_240,
+	s6e8ax0_22_gamma_250,
+	s6e8ax0_22_gamma_260,
+	s6e8ax0_22_gamma_270,
+	s6e8ax0_22_gamma_280,
+	s6e8ax0_22_gamma_300,
+};
+
+static void s6e8ax0_panel_cond(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+	static const unsigned char data_to_send[] = {
+		0xf8, 0x3d, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c, 0x7d,
+		0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08,
+		0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0,
+		0xc8, 0x08, 0x48, 0xc1, 0x00, 0xc1, 0xff, 0xff, 0xc8
+	};
+
+	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_display_cond(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0xf2, 0x80, 0x03, 0x0d
+	};
+
+	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+/* Gamma 2.2 Setting (200cd, 7500K, 10MPCD) */
+static void s6e8ax0_gamma_cond(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	unsigned int gamma = lcd->bd->props.brightness;
+
+	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+			s6e8ax0_22_gamma_table[gamma],
+			GAMMA_TABLE_COUNT);
+}
+
+static void s6e8ax0_gamma_update(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0xf7, 0x03
+	};
+
+	ops->cmd_write(lcd_to_master(lcd),
+		MIPI_DSI_DCS_SHORT_WRITE_PARAM, data_to_send,
+		ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_etc_cond1(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0xd1, 0xfe, 0x80, 0x00, 0x01, 0x0b, 0x00, 0x00, 0x40,
+		0x0d, 0x00, 0x00
+	};
+
+	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_etc_cond2(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0,
+		0x00
+	};
+
+	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_etc_cond3(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0xe1, 0x10, 0x1c, 0x17, 0x08, 0x1d
+	};
+
+	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_etc_cond4(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0xe2, 0xed, 0x07, 0xc3, 0x13, 0x0d, 0x03
+	};
+
+	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_etc_cond5(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x19, 0x33, 0x02
+	};
+
+	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+static void s6e8ax0_etc_cond6(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0xe3, 0x40
+	};
+
+	ops->cmd_write(lcd_to_master(lcd),
+		MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_etc_cond7(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0xe4, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00
+	};
+
+	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_elvss_set(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0xb1, 0x04, 0x00
+	};
+
+	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_elvss_nvm_set(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0xd9, 0x5c, 0x20, 0x0c, 0x0f, 0x41, 0x00, 0x10, 0x11,
+		0x12, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x80, 0xcb, 0xed,
+		0x64, 0xaf
+	};
+
+	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_sleep_in(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0x10, 0x00
+	};
+
+	ops->cmd_write(lcd_to_master(lcd),
+		MIPI_DSI_DCS_SHORT_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_sleep_out(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0x11, 0x00
+	};
+
+	ops->cmd_write(lcd_to_master(lcd),
+		MIPI_DSI_DCS_SHORT_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_display_on(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0x29, 0x00
+	};
+
+	ops->cmd_write(lcd_to_master(lcd),
+		MIPI_DSI_DCS_SHORT_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_display_off(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0x28, 0x00
+	};
+
+	ops->cmd_write(lcd_to_master(lcd),
+		MIPI_DSI_DCS_SHORT_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_apply_level2_key(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0xf0, 0x5a, 0x5a
+	};
+
+	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_acl_on(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0xc0, 0x01
+	};
+
+	ops->cmd_write(lcd_to_master(lcd),
+		MIPI_DSI_DCS_SHORT_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_acl_off(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	static const unsigned char data_to_send[] = {
+		0xc0, 0x00
+	};
+
+	ops->cmd_write(lcd_to_master(lcd),
+		MIPI_DSI_DCS_SHORT_WRITE,
+		data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+/* Full white 50% reducing setting */
+static void s6e8ax0_acl_ctrl_set(struct s6e8ax0 *lcd)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	/* Full white 50% reducing setting */
+	static const unsigned char cutoff_50[] = {
+		0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
+		0x00, 0x00, 0x04, 0xff,	0x00, 0x00, 0x00, 0x00, 0x00,
+		0x01, 0x08, 0x0f, 0x16, 0x1d, 0x24, 0x2a, 0x31, 0x38,
+		0x3f, 0x46
+	};
+	/* Full white 45% reducing setting */
+	static const unsigned char cutoff_45[] = {
+		0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
+		0x00, 0x00, 0x04, 0xff,	0x00, 0x00, 0x00, 0x00, 0x00,
+		0x01, 0x07, 0x0d, 0x13, 0x19, 0x1f, 0x25, 0x2b, 0x31,
+		0x37, 0x3d
+	};
+	/* Full white 40% reducing setting */
+	static const unsigned char cutoff_40[] = {
+		0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
+		0x00, 0x00, 0x04, 0xff,	0x00, 0x00, 0x00, 0x00, 0x00,
+		0x01, 0x06, 0x0c, 0x11, 0x16, 0x1c, 0x21, 0x26, 0x2b,
+		0x31, 0x36
+	};
+
+	if (lcd->acl_enable) {
+		if (lcd->cur_acl == 0) {
+			if (lcd->gamma == 0 || lcd->gamma == 1) {
+				s6e8ax0_acl_off(lcd);
+				dev_dbg(&lcd->ld->dev,
+					"cur_acl=%d\n", lcd->cur_acl);
+			} else
+				s6e8ax0_acl_on(lcd);
+		}
+		switch (lcd->gamma) {
+		case 0: /* 30cd */
+			s6e8ax0_acl_off(lcd);
+			lcd->cur_acl = 0;
+			break;
+		case 1 ... 3: /* 50cd ~ 90cd */
+			ops->cmd_write(lcd_to_master(lcd),
+				MIPI_DSI_DCS_LONG_WRITE,
+				cutoff_40,
+				ARRAY_SIZE(cutoff_40));
+			lcd->cur_acl = 40;
+			break;
+		case 4 ... 7: /* 120cd ~ 210cd */
+			ops->cmd_write(lcd_to_master(lcd),
+				MIPI_DSI_DCS_LONG_WRITE,
+				cutoff_45,
+				ARRAY_SIZE(cutoff_45));
+			lcd->cur_acl = 45;
+			break;
+		case 8 ... 10: /* 220cd ~ 300cd */
+			ops->cmd_write(lcd_to_master(lcd),
+				MIPI_DSI_DCS_LONG_WRITE,
+				cutoff_50,
+				ARRAY_SIZE(cutoff_50));
+			lcd->cur_acl = 50;
+			break;
+		default:
+			break;
+		}
+	} else {
+		s6e8ax0_acl_off(lcd);
+		lcd->cur_acl = 0;
+		dev_dbg(&lcd->ld->dev, "cur_acl = %d\n", lcd->cur_acl);
+	}
+}
+
+static void s6e8ax0_read_id(struct s6e8ax0 *lcd, u8 *mtp_id)
+{
+	unsigned int ret;
+	unsigned int addr = 0xd1;	/* MTP ID */
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+	ret = ops->cmd_read(lcd_to_master(lcd),
+			MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM,
+			addr, 3, mtp_id);
+}
+
+static int s6e8ax0_panel_init(struct s6e8ax0 *lcd)
+{
+	s6e8ax0_apply_level2_key(lcd);
+	s6e8ax0_sleep_out(lcd);
+	msleep(1);
+	s6e8ax0_panel_cond(lcd);
+	s6e8ax0_display_cond(lcd);
+	s6e8ax0_gamma_cond(lcd);
+	s6e8ax0_gamma_update(lcd);
+
+	s6e8ax0_etc_cond1(lcd);
+	s6e8ax0_etc_cond2(lcd);
+	s6e8ax0_etc_cond3(lcd);
+	s6e8ax0_etc_cond4(lcd);
+	s6e8ax0_etc_cond5(lcd);
+	s6e8ax0_etc_cond6(lcd);
+	s6e8ax0_etc_cond7(lcd);
+
+	s6e8ax0_elvss_nvm_set(lcd);
+	s6e8ax0_elvss_set(lcd);
+
+	s6e8ax0_acl_ctrl_set(lcd);
+	s6e8ax0_acl_on(lcd);
+
+	/* if ID3 value is not 33h, branch private elvss mode */
+	msleep(lcd->ddi_pd->power_on_delay);
+
+	return 0;
+}
+
+static int s6e8ax0_update_gamma_ctrl(struct s6e8ax0 *lcd, int brightness)
+{
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+			s6e8ax0_22_gamma_table[brightness],
+			ARRAY_SIZE(s6e8ax0_22_gamma_table));
+
+	/* update gamma table. */
+	s6e8ax0_gamma_update(lcd);
+	lcd->gamma = brightness;
+
+	return 0;
+}
+
+static int s6e8ax0_gamma_ctrl(struct s6e8ax0 *lcd, int gamma)
+{
+	s6e8ax0_update_gamma_ctrl(lcd, gamma);
+
+	return 0;
+}
+
+static int s6e8ax0_set_power(struct lcd_device *ld, int power)
+{
+	struct s6e8ax0 *lcd = lcd_get_data(ld);
+	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+	int ret = 0;
+
+	if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
+			power != FB_BLANK_NORMAL) {
+		dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
+		return -EINVAL;
+	}
+
+	if ((power == FB_BLANK_UNBLANK) && ops->set_blank_mode) {
+		/* LCD power on */
+		if ((POWER_IS_ON(power) && POWER_IS_OFF(lcd->power))
+			|| (POWER_IS_ON(power) && POWER_IS_NRM(lcd->power))) {
+			ret = ops->set_blank_mode(lcd_to_master(lcd), power);
+			if (!ret && lcd->power != power)
+				lcd->power = power;
+		}
+	} else if ((power == FB_BLANK_POWERDOWN) && ops->set_early_blank_mode) {
+		/* LCD power off */
+		if ((POWER_IS_OFF(power) && POWER_IS_ON(lcd->power)) ||
+		(POWER_IS_ON(lcd->power) && POWER_IS_NRM(power))) {
+			ret = ops->set_early_blank_mode(lcd_to_master(lcd),
+							power);
+			if (!ret && lcd->power != power)
+				lcd->power = power;
+		}
+	}
+
+	return ret;
+}
+
+static int s6e8ax0_get_power(struct lcd_device *ld)
+{
+	struct s6e8ax0 *lcd = lcd_get_data(ld);
+
+	return lcd->power;
+}
+
+static int s6e8ax0_get_brightness(struct backlight_device *bd)
+{
+	return bd->props.brightness;
+}
+
+static int s6e8ax0_set_brightness(struct backlight_device *bd)
+{
+	int ret = 0, brightness = bd->props.brightness;
+	struct s6e8ax0 *lcd = bl_get_data(bd);
+
+	if (brightness < MIN_BRIGHTNESS ||
+		brightness > bd->props.max_brightness) {
+		dev_err(lcd->dev, "lcd brightness should be %d to %d.\n",
+			MIN_BRIGHTNESS, MAX_BRIGHTNESS);
+		return -EINVAL;
+	}
+
+	ret = s6e8ax0_gamma_ctrl(lcd, brightness);
+	if (ret) {
+		dev_err(&bd->dev, "lcd brightness setting failed.\n");
+		return -EIO;
+	}
+
+	return ret;
+}
+
+static struct lcd_ops s6e8ax0_lcd_ops = {
+	.set_power = s6e8ax0_set_power,
+	.get_power = s6e8ax0_get_power,
+};
+
+static const struct backlight_ops s6e8ax0_backlight_ops = {
+	.get_brightness = s6e8ax0_get_brightness,
+	.update_status = s6e8ax0_set_brightness,
+};
+
+static void s6e8ax0_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power)
+{
+	struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+	msleep(lcd->ddi_pd->power_on_delay);
+
+	/* lcd power on */
+	if (power)
+		s6e8ax0_regulator_enable(lcd);
+	else
+		s6e8ax0_regulator_disable(lcd);
+
+	msleep(lcd->ddi_pd->reset_delay);
+
+	/* lcd reset */
+	if (lcd->ddi_pd->reset)
+		lcd->ddi_pd->reset(lcd->ld);
+	msleep(5);
+}
+
+static void s6e8ax0_set_sequence(struct mipi_dsim_lcd_device *dsim_dev)
+{
+	struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+	s6e8ax0_panel_init(lcd);
+	s6e8ax0_display_on(lcd);
+
+	lcd->power = FB_BLANK_UNBLANK;
+}
+
+static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev)
+{
+	struct s6e8ax0 *lcd;
+	int ret;
+	u8 mtp_id[3] = {0, };
+
+	lcd = kzalloc(sizeof(struct s6e8ax0), GFP_KERNEL);
+	if (!lcd) {
+		dev_err(&dsim_dev->dev, "failed to allocate s6e8ax0 structure.\n");
+		return -ENOMEM;
+	}
+
+	lcd->dsim_dev = dsim_dev;
+	lcd->ddi_pd = (struct lcd_platform_data *)dsim_dev->platform_data;
+	lcd->dev = &dsim_dev->dev;
+
+	mutex_init(&lcd->lock);
+
+	ret = regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies);
+	if (ret) {
+		dev_err(lcd->dev, "Failed to get regulators: %d\n", ret);
+		goto err_lcd_register;
+	}
+
+	lcd->ld = lcd_device_register("s6e8ax0", lcd->dev, lcd,
+			&s6e8ax0_lcd_ops);
+	if (IS_ERR(lcd->ld)) {
+		dev_err(lcd->dev, "failed to register lcd ops.\n");
+		ret = PTR_ERR(lcd->ld);
+		goto err_lcd_register;
+	}
+
+	lcd->bd = backlight_device_register("s6e8ax0-bl", lcd->dev, lcd,
+			&s6e8ax0_backlight_ops, NULL);
+	if (IS_ERR(lcd->bd)) {
+		dev_err(lcd->dev, "failed to register backlight ops.\n");
+		ret = PTR_ERR(lcd->bd);
+		goto err_backlight_register;
+	}
+
+	lcd->bd->props.max_brightness = MAX_BRIGHTNESS;
+	lcd->bd->props.brightness = MAX_BRIGHTNESS;
+
+	s6e8ax0_read_id(lcd, mtp_id);
+	if (mtp_id[0] == 0x00)
+		dev_err(lcd->dev, "read id failed\n");
+
+	dev_info(lcd->dev, "Read ID : %x, %x, %x\n",
+			mtp_id[0], mtp_id[1], mtp_id[2]);
+
+	if (mtp_id[2] == 0x33)
+		dev_info(lcd->dev,
+			"ID-3 is 0xff does not support dynamic elvss\n");
+	else
+		dev_info(lcd->dev,
+			"ID-3 is 0x%x support dynamic elvss\n", mtp_id[2]);
+
+	lcd->acl_enable = 1;
+	lcd->cur_acl = 0;
+
+	dev_set_drvdata(&dsim_dev->dev, lcd);
+
+	dev_dbg(lcd->dev, "probed s6e8ax0 panel driver.\n");
+
+	return 0;
+
+err_backlight_register:
+	lcd_device_unregister(lcd->ld);
+
+err_lcd_register:
+	regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
+	kfree(lcd);
+
+	return ret;
+}
+
+#ifdef CONFIG_PM
+static int s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
+{
+	struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+	s6e8ax0_sleep_in(lcd);
+	msleep(lcd->ddi_pd->power_off_delay);
+	s6e8ax0_display_off(lcd);
+
+	s6e8ax0_regulator_disable(lcd);
+
+	return 0;
+}
+
+static int s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev)
+{
+	struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+	s6e8ax0_sleep_out(lcd);
+	msleep(lcd->ddi_pd->power_on_delay);
+
+	s6e8ax0_regulator_enable(lcd);
+	s6e8ax0_set_sequence(dsim_dev);
+
+	return 0;
+}
+#else
+#define s6e8ax0_suspend		NULL
+#define s6e8ax0_resume		NULL
+#endif
+
+static struct mipi_dsim_lcd_driver s6e8ax0_dsim_ddi_driver = {
+	.name = "s6e8ax0",
+	.id = -1,
+
+	.power_on = s6e8ax0_power_on,
+	.set_sequence = s6e8ax0_set_sequence,
+	.probe = s6e8ax0_probe,
+	.suspend = s6e8ax0_suspend,
+	.resume = s6e8ax0_resume,
+};
+
+static int s6e8ax0_init(void)
+{
+	exynos_mipi_dsi_register_lcd_driver(&s6e8ax0_dsim_ddi_driver);
+
+	return 0;
+}
+
+static void s6e8ax0_exit(void)
+{
+	return;
+}
+
+module_init(s6e8ax0_init);
+module_exit(s6e8ax0_exit);
+
+MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
+MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("MIPI-DSI based s6e8ax0 AMOLED LCD Panel Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/exynos/s6e8ax0.h b/drivers/video/exynos/s6e8ax0.h
new file mode 100644
index 0000000..1f1b270
--- /dev/null
+++ b/drivers/video/exynos/s6e8ax0.h
@@ -0,0 +1,21 @@
+/* linux/drivers/video/backlight/s6e8ax0.h
+ *
+ * MIPI-DSI based s6e8ax0 AMOLED LCD Panel definitions.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * Inki Dae, <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@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.
+*/
+
+#ifndef _S6E8AX0_H
+#define _S6E8AX0_H
+
+extern void s6e8ax0_init(void);
+
+#endif
+
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index ac9141b..c6ce416 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1665,6 +1665,7 @@
 	if (ret)
 		return -EINVAL;
 
+	unlink_framebuffer(fb_info);
 	if (fb_info->pixmap.addr &&
 	    (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
 		kfree(fb_info->pixmap.addr);
@@ -1672,7 +1673,6 @@
 	registered_fb[i] = NULL;
 	num_registered_fb--;
 	fb_cleanup_device(fb_info);
-	device_destroy(fb_class, MKDEV(FB_MAJOR, i));
 	event.info = fb_info;
 	fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
 
@@ -1681,6 +1681,22 @@
 	return 0;
 }
 
+int unlink_framebuffer(struct fb_info *fb_info)
+{
+	int i;
+
+	i = fb_info->node;
+	if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
+		return -EINVAL;
+
+	if (fb_info->dev) {
+		device_destroy(fb_class, MKDEV(FB_MAJOR, i));
+		fb_info->dev = NULL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(unlink_framebuffer);
+
 void remove_conflicting_framebuffers(struct apertures_struct *a,
 				     const char *name, bool primary)
 {
diff --git a/drivers/video/i740_reg.h b/drivers/video/i740_reg.h
new file mode 100644
index 0000000..91bac76
--- /dev/null
+++ b/drivers/video/i740_reg.h
@@ -0,0 +1,309 @@
+/**************************************************************************
+
+Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sub license, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ *   Kevin E. Martin <kevin@precisioninsight.com>
+ */
+
+/* I/O register offsets */
+#define SRX VGA_SEQ_I
+#define GRX VGA_GFX_I
+#define ARX VGA_ATT_IW
+#define XRX 0x3D6
+#define MRX 0x3D2
+
+/* VGA Color Palette Registers */
+#define DACMASK		0x3C6
+#define DACSTATE	0x3C7
+#define DACRX		0x3C7
+#define DACWX		0x3C8
+#define DACDATA		0x3C9
+
+/* CRT Controller Registers (CRX) */
+#define START_ADDR_HI		0x0C
+#define START_ADDR_LO		0x0D
+#define VERT_SYNC_END		0x11
+#define EXT_VERT_TOTAL		0x30
+#define EXT_VERT_DISPLAY	0x31
+#define EXT_VERT_SYNC_START	0x32
+#define EXT_VERT_BLANK_START	0x33
+#define EXT_HORIZ_TOTAL		0x35
+#define EXT_HORIZ_BLANK		0x39
+#define EXT_START_ADDR		0x40
+#define EXT_START_ADDR_ENABLE	0x80
+#define EXT_OFFSET		0x41
+#define EXT_START_ADDR_HI	0x42
+#define INTERLACE_CNTL		0x70
+#define INTERLACE_ENABLE	0x80
+#define INTERLACE_DISABLE	0x00
+
+/* Miscellaneous Output Register */
+#define MSR_R		0x3CC
+#define MSR_W		0x3C2
+#define IO_ADDR_SELECT	0x01
+
+#define MDA_BASE	0x3B0
+#define CGA_BASE	0x3D0
+
+/* System Configuration Extension Registers (XRX) */
+#define IO_CTNL		0x09
+#define EXTENDED_ATTR_CNTL	0x02
+#define EXTENDED_CRTC_CNTL	0x01
+
+#define ADDRESS_MAPPING	0x0A
+#define PACKED_MODE_ENABLE	0x04
+#define LINEAR_MODE_ENABLE	0x02
+#define PAGE_MAPPING_ENABLE	0x01
+
+#define BITBLT_CNTL	0x20
+#define COLEXP_MODE		0x30
+#define COLEXP_8BPP		0x00
+#define COLEXP_16BPP		0x10
+#define COLEXP_24BPP		0x20
+#define COLEXP_RESERVED		0x30
+#define CHIP_RESET		0x02
+#define BITBLT_STATUS		0x01
+
+#define DISPLAY_CNTL	0x40
+#define VGA_WRAP_MODE		0x02
+#define VGA_WRAP_AT_256KB	0x00
+#define VGA_NO_WRAP		0x02
+#define GUI_MODE		0x01
+#define STANDARD_VGA_MODE	0x00
+#define HIRES_MODE		0x01
+
+#define DRAM_ROW_TYPE	0x50
+#define DRAM_ROW_0		0x07
+#define DRAM_ROW_0_SDRAM	0x00
+#define DRAM_ROW_0_EMPTY	0x07
+#define DRAM_ROW_1		0x38
+#define DRAM_ROW_1_SDRAM	0x00
+#define DRAM_ROW_1_EMPTY	0x38
+#define DRAM_ROW_CNTL_LO 0x51
+#define DRAM_CAS_LATENCY	0x10
+#define DRAM_RAS_TIMING		0x08
+#define DRAM_RAS_PRECHARGE	0x04
+#define DRAM_ROW_CNTL_HI 0x52
+#define DRAM_EXT_CNTL	0x53
+#define DRAM_REFRESH_RATE	0x03
+#define DRAM_REFRESH_DISABLE	0x00
+#define DRAM_REFRESH_60HZ	0x01
+#define DRAM_REFRESH_FAST_TEST	0x02
+#define DRAM_REFRESH_RESERVED	0x03
+#define DRAM_TIMING	0x54
+#define DRAM_ROW_BNDRY_0 0x55
+#define DRAM_ROW_BNDRY_1 0x56
+
+#define DPMS_SYNC_SELECT 0x61
+#define VSYNC_CNTL		0x08
+#define VSYNC_ON		0x00
+#define VSYNC_OFF		0x08
+#define HSYNC_CNTL		0x02
+#define HSYNC_ON		0x00
+#define HSYNC_OFF		0x02
+
+#define PIXPIPE_CONFIG_0 0x80
+#define DAC_8_BIT		0x80
+#define DAC_6_BIT		0x00
+#define HW_CURSOR_ENABLE	0x10
+#define EXTENDED_PALETTE	0x01
+
+#define PIXPIPE_CONFIG_1 0x81
+#define DISPLAY_COLOR_MODE	0x0F
+#define DISPLAY_VGA_MODE	0x00
+#define DISPLAY_8BPP_MODE	0x02
+#define DISPLAY_15BPP_MODE	0x04
+#define DISPLAY_16BPP_MODE	0x05
+#define DISPLAY_24BPP_MODE	0x06
+#define DISPLAY_32BPP_MODE	0x07
+
+#define PIXPIPE_CONFIG_2 0x82
+#define DISPLAY_GAMMA_ENABLE	0x08
+#define DISPLAY_GAMMA_DISABLE	0x00
+#define OVERLAY_GAMMA_ENABLE	0x04
+#define OVERLAY_GAMMA_DISABLE	0x00
+
+#define CURSOR_CONTROL	0xA0
+#define CURSOR_ORIGIN_SCREEN	0x00
+#define CURSOR_ORIGIN_DISPLAY	0x10
+#define CURSOR_MODE		0x07
+#define CURSOR_MODE_DISABLE	0x00
+#define CURSOR_MODE_32_4C_AX	0x01
+#define CURSOR_MODE_128_2C	0x02
+#define CURSOR_MODE_128_1C	0x03
+#define CURSOR_MODE_64_3C	0x04
+#define CURSOR_MODE_64_4C_AX	0x05
+#define CURSOR_MODE_64_4C	0x06
+#define CURSOR_MODE_RESERVED	0x07
+#define CURSOR_BASEADDR_LO 0xA2
+#define CURSOR_BASEADDR_HI 0xA3
+#define CURSOR_X_LO	0xA4
+#define CURSOR_X_HI	0xA5
+#define CURSOR_X_POS		0x00
+#define CURSOR_X_NEG		0x80
+#define CURSOR_Y_LO	0xA6
+#define CURSOR_Y_HI	0xA7
+#define CURSOR_Y_POS		0x00
+#define CURSOR_Y_NEG		0x80
+
+#define VCLK2_VCO_M	0xC8
+#define VCLK2_VCO_N	0xC9
+#define VCLK2_VCO_MN_MSBS 0xCA
+#define VCO_N_MSBS		0x30
+#define VCO_M_MSBS		0x03
+#define VCLK2_VCO_DIV_SEL 0xCB
+#define POST_DIV_SELECT		0x70
+#define POST_DIV_1		0x00
+#define POST_DIV_2		0x10
+#define POST_DIV_4		0x20
+#define POST_DIV_8		0x30
+#define POST_DIV_16		0x40
+#define POST_DIV_32		0x50
+#define VCO_LOOP_DIV_BY_4M	0x00
+#define VCO_LOOP_DIV_BY_16M	0x04
+#define REF_CLK_DIV_BY_5	0x02
+#define REF_DIV_4		0x00
+#define REF_DIV_1		0x01
+
+#define PLL_CNTL	0xCE
+#define PLL_MEMCLK_SEL		0x03
+#define PLL_MEMCLK__66667KHZ	0x00
+#define PLL_MEMCLK__75000KHZ	0x01
+#define PLL_MEMCLK__88889KHZ	0x02
+#define PLL_MEMCLK_100000KHZ	0x03
+
+/* Multimedia Extension Registers (MRX) */
+#define ACQ_CNTL_1	0x02
+#define ACQ_CNTL_2	0x03
+#define FRAME_CAP_MODE		0x01
+#define CONT_CAP_MODE		0x00
+#define SINGLE_CAP_MODE		0x01
+#define ACQ_CNTL_3	0x04
+#define COL_KEY_CNTL_1		0x3C
+#define BLANK_DISP_OVERLAY	0x20
+
+/* FIFOs */
+#define LP_FIFO		0x1000
+#define HP_FIFO		0x2000
+#define INSTPNT		0x3040
+#define LP_FIFO_COUNT	0x3040
+#define HP_FIFO_COUNT	0x3041
+
+/* FIFO Commands */
+#define CLIENT		0xE0000000
+#define CLIENT_2D	0x60000000
+
+/* Command Parser Mode Register */
+#define COMPARS		0x3038
+#define TWO_D_INST_DISABLE		0x08
+#define THREE_D_INST_DISABLE		0x04
+#define STATE_VAR_UPDATE_DISABLE	0x02
+#define PAL_STIP_DISABLE		0x01
+
+/* Interrupt Control Registers */
+#define IER		0x3030
+#define IIR		0x3032
+#define IMR		0x3034
+#define ISR		0x3036
+#define VMIINTB_EVENT		0x2000
+#define GPIO4_INT		0x1000
+#define DISP_FLIP_EVENT		0x0800
+#define DVD_PORT_DMA		0x0400
+#define DISP_VBLANK		0x0200
+#define FIFO_EMPTY_DMA_DONE	0x0100
+#define INST_PARSER_ERROR	0x0080
+#define USER_DEFINED		0x0040
+#define BREAKPOINT		0x0020
+#define DISP_HORIZ_COUNT	0x0010
+#define DISP_VSYNC		0x0008
+#define CAPTURE_HORIZ_COUNT	0x0004
+#define CAPTURE_VSYNC		0x0002
+#define THREE_D_PIPE_FLUSHED	0x0001
+
+/* FIFO Watermark and Burst Length Control Register */
+#define FWATER_BLC	0x00006000
+#define LMI_BURST_LENGTH	0x7F000000
+#define LMI_FIFO_WATERMARK	0x003F0000
+#define AGP_BURST_LENGTH	0x00007F00
+#define AGP_FIFO_WATERMARK	0x0000003F
+
+/* BitBLT Registers */
+#define SRC_DST_PITCH	0x00040000
+#define DST_PITCH		0x1FFF0000
+#define SRC_PITCH		0x00001FFF
+#define COLEXP_BG_COLOR	0x00040004
+#define COLEXP_FG_COLOR	0x00040008
+#define MONO_SRC_CNTL	0x0004000C
+#define MONO_USE_COLEXP		0x00000000
+#define MONO_USE_SRCEXP		0x08000000
+#define MONO_DATA_ALIGN		0x07000000
+#define MONO_BIT_ALIGN		0x01000000
+#define MONO_BYTE_ALIGN		0x02000000
+#define MONO_WORD_ALIGN		0x03000000
+#define MONO_DWORD_ALIGN	0x04000000
+#define MONO_QWORD_ALIGN	0x05000000
+#define MONO_SRC_INIT_DSCRD	0x003F0000
+#define MONO_SRC_RIGHT_CLIP	0x00003F00
+#define MONO_SRC_LEFT_CLIP	0x0000003F
+#define BITBLT_CONTROL	0x00040010
+#define BLTR_STATUS		0x80000000
+#define DYN_DEPTH		0x03000000
+#define DYN_DEPTH_8BPP		0x00000000
+#define DYN_DEPTH_16BPP		0x01000000
+#define DYN_DEPTH_24BPP		0x02000000
+#define DYN_DEPTH_32BPP		0x03000000	/* Unimplemented on the i740 */
+#define DYN_DEPTH_ENABLE	0x00800000
+#define PAT_VERT_ALIGN		0x00700000
+#define SOLID_PAT_SELECT	0x00080000
+#define PAT_IS_IN_COLOR		0x00000000
+#define PAT_IS_MONO		0x00040000
+#define MONO_PAT_TRANSP		0x00020000
+#define COLOR_TRANSP_ROP	0x00000000
+#define COLOR_TRANSP_DST	0x00008000
+#define COLOR_TRANSP_EQ		0x00000000
+#define COLOR_TRANSP_NOT_EQ	0x00010000
+#define COLOR_TRANSP_ENABLE	0x00004000
+#define MONO_SRC_TRANSP		0x00002000
+#define SRC_IS_IN_COLOR		0x00000000
+#define SRC_IS_MONO		0x00001000
+#define SRC_USE_SRC_ADDR	0x00000000
+#define SRC_USE_BLTDATA		0x00000400
+#define BLT_TOP_TO_BOT		0x00000000
+#define BLT_BOT_TO_TOP		0x00000200
+#define BLT_LEFT_TO_RIGHT	0x00000000
+#define BLT_RIGHT_TO_LEFT	0x00000100
+#define BLT_ROP			0x000000FF
+#define BLT_PAT_ADDR	0x00040014
+#define BLT_SRC_ADDR	0x00040018
+#define BLT_DST_ADDR	0x0004001C
+#define BLT_DST_H_W	0x00040020
+#define BLT_DST_HEIGHT		0x1FFF0000
+#define BLT_DST_WIDTH		0x00001FFF
+#define SRCEXP_BG_COLOR	0x00040024
+#define SRCEXP_FG_COLOR	0x00040028
+#define BLTDATA		0x00050000
diff --git a/drivers/video/i740fb.c b/drivers/video/i740fb.c
new file mode 100644
index 0000000..fe574d8
--- /dev/null
+++ b/drivers/video/i740fb.c
@@ -0,0 +1,1337 @@
+/*
+ * i740fb - framebuffer driver for Intel740
+ * Copyright (c) 2011 Ondrej Zary
+ *
+ * Based on old i740fb driver (c) 2001-2002 Andrey Ulanov <drey@rt.mipt.ru>
+ * which was partially based on:
+ *  VGA 16-color framebuffer driver (c) 1999 Ben Pfaff <pfaffben@debian.org>
+ *	and Petr Vandrovec <VANDROVE@vc.cvut.cz>
+ *  i740 driver from XFree86 (c) 1998-1999 Precision Insight, Inc., Cedar Park,
+ *	Texas.
+ *  i740fb by Patrick LERDA, v0.9
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/console.h>
+#include <video/vga.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "i740_reg.h"
+
+static char *mode_option __devinitdata;
+
+#ifdef CONFIG_MTRR
+static int mtrr __devinitdata = 1;
+#endif
+
+struct i740fb_par {
+	unsigned char __iomem *regs;
+	bool has_sgram;
+#ifdef CONFIG_MTRR
+	int mtrr_reg;
+#endif
+	bool ddc_registered;
+	struct i2c_adapter ddc_adapter;
+	struct i2c_algo_bit_data ddc_algo;
+	u32 pseudo_palette[16];
+	struct mutex open_lock;
+	unsigned int ref_count;
+
+	u8 crtc[VGA_CRT_C];
+	u8 atc[VGA_ATT_C];
+	u8 gdc[VGA_GFX_C];
+	u8 seq[VGA_SEQ_C];
+	u8 misc;
+	u8 vss;
+
+	/* i740 specific registers */
+	u8 display_cntl;
+	u8 pixelpipe_cfg0;
+	u8 pixelpipe_cfg1;
+	u8 pixelpipe_cfg2;
+	u8 video_clk2_m;
+	u8 video_clk2_n;
+	u8 video_clk2_mn_msbs;
+	u8 video_clk2_div_sel;
+	u8 pll_cntl;
+	u8 address_mapping;
+	u8 io_cntl;
+	u8 bitblt_cntl;
+	u8 ext_vert_total;
+	u8 ext_vert_disp_end;
+	u8 ext_vert_sync_start;
+	u8 ext_vert_blank_start;
+	u8 ext_horiz_total;
+	u8 ext_horiz_blank;
+	u8 ext_offset;
+	u8 interlace_cntl;
+	u32 lmi_fifo_watermark;
+	u8 ext_start_addr;
+	u8 ext_start_addr_hi;
+};
+
+#define DACSPEED8	203
+#define DACSPEED16	163
+#define DACSPEED24_SG	136
+#define DACSPEED24_SD	128
+#define DACSPEED32	86
+
+static struct fb_fix_screeninfo i740fb_fix __devinitdata = {
+	.id =		"i740fb",
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_TRUECOLOR,
+	.xpanstep =	8,
+	.ypanstep =	1,
+	.accel =	FB_ACCEL_NONE,
+};
+
+static inline void i740outb(struct i740fb_par *par, u16 port, u8 val)
+{
+	vga_mm_w(par->regs, port, val);
+}
+static inline u8 i740inb(struct i740fb_par *par, u16 port)
+{
+	return vga_mm_r(par->regs, port);
+}
+static inline void i740outreg(struct i740fb_par *par, u16 port, u8 reg, u8 val)
+{
+	vga_mm_w_fast(par->regs, port, reg, val);
+}
+static inline u8 i740inreg(struct i740fb_par *par, u16 port, u8 reg)
+{
+	vga_mm_w(par->regs, port, reg);
+	return vga_mm_r(par->regs, port+1);
+}
+static inline void i740outreg_mask(struct i740fb_par *par, u16 port, u8 reg,
+				   u8 val, u8 mask)
+{
+	vga_mm_w_fast(par->regs, port, reg, (val & mask)
+		| (i740inreg(par, port, reg) & ~mask));
+}
+
+#define REG_DDC_DRIVE	0x62
+#define REG_DDC_STATE	0x63
+#define DDC_SCL		(1 << 3)
+#define DDC_SDA		(1 << 2)
+
+static void i740fb_ddc_setscl(void *data, int val)
+{
+	struct i740fb_par *par = data;
+
+	i740outreg_mask(par, XRX, REG_DDC_DRIVE, DDC_SCL, DDC_SCL);
+	i740outreg_mask(par, XRX, REG_DDC_STATE, val ? DDC_SCL : 0, DDC_SCL);
+}
+
+static void i740fb_ddc_setsda(void *data, int val)
+{
+	struct i740fb_par *par = data;
+
+	i740outreg_mask(par, XRX, REG_DDC_DRIVE, DDC_SDA, DDC_SDA);
+	i740outreg_mask(par, XRX, REG_DDC_STATE, val ? DDC_SDA : 0, DDC_SDA);
+}
+
+static int i740fb_ddc_getscl(void *data)
+{
+	struct i740fb_par *par = data;
+
+	i740outreg_mask(par, XRX, REG_DDC_DRIVE, 0, DDC_SCL);
+
+	return !!(i740inreg(par, XRX, REG_DDC_STATE) & DDC_SCL);
+}
+
+static int i740fb_ddc_getsda(void *data)
+{
+	struct i740fb_par *par = data;
+
+	i740outreg_mask(par, XRX, REG_DDC_DRIVE, 0, DDC_SDA);
+
+	return !!(i740inreg(par, XRX, REG_DDC_STATE) & DDC_SDA);
+}
+
+static int __devinit i740fb_setup_ddc_bus(struct fb_info *info)
+{
+	struct i740fb_par *par = info->par;
+
+	strlcpy(par->ddc_adapter.name, info->fix.id,
+		sizeof(par->ddc_adapter.name));
+	par->ddc_adapter.owner		= THIS_MODULE;
+	par->ddc_adapter.class		= I2C_CLASS_DDC;
+	par->ddc_adapter.algo_data	= &par->ddc_algo;
+	par->ddc_adapter.dev.parent	= info->device;
+	par->ddc_algo.setsda		= i740fb_ddc_setsda;
+	par->ddc_algo.setscl		= i740fb_ddc_setscl;
+	par->ddc_algo.getsda		= i740fb_ddc_getsda;
+	par->ddc_algo.getscl		= i740fb_ddc_getscl;
+	par->ddc_algo.udelay		= 10;
+	par->ddc_algo.timeout		= 20;
+	par->ddc_algo.data		= par;
+
+	i2c_set_adapdata(&par->ddc_adapter, par);
+
+	return i2c_bit_add_bus(&par->ddc_adapter);
+}
+
+static int i740fb_open(struct fb_info *info, int user)
+{
+	struct i740fb_par *par = info->par;
+
+	mutex_lock(&(par->open_lock));
+	par->ref_count++;
+	mutex_unlock(&(par->open_lock));
+
+	return 0;
+}
+
+static int i740fb_release(struct fb_info *info, int user)
+{
+	struct i740fb_par *par = info->par;
+
+	mutex_lock(&(par->open_lock));
+	if (par->ref_count == 0) {
+		printk(KERN_ERR "fb%d: release called with zero refcount\n",
+			info->node);
+		mutex_unlock(&(par->open_lock));
+		return -EINVAL;
+	}
+
+	par->ref_count--;
+	mutex_unlock(&(par->open_lock));
+
+	return 0;
+}
+
+static u32 i740_calc_fifo(struct i740fb_par *par, u32 freq, int bpp)
+{
+	/*
+	 * Would like to calculate these values automatically, but a generic
+	 * algorithm does not seem possible.  Note: These FIFO water mark
+	 * values were tested on several cards and seem to eliminate the
+	 * all of the snow and vertical banding, but fine adjustments will
+	 * probably be required for other cards.
+	 */
+
+	u32 wm;
+
+	switch (bpp) {
+	case 8:
+		if	(freq > 200)
+			wm = 0x18120000;
+		else if (freq > 175)
+			wm = 0x16110000;
+		else if (freq > 135)
+			wm = 0x120E0000;
+		else
+			wm = 0x100D0000;
+		break;
+	case 15:
+	case 16:
+		if (par->has_sgram) {
+			if	(freq > 140)
+				wm = 0x2C1D0000;
+			else if (freq > 120)
+				wm = 0x2C180000;
+			else if (freq > 100)
+				wm = 0x24160000;
+			else if (freq >  90)
+				wm = 0x18120000;
+			else if (freq >  50)
+				wm = 0x16110000;
+			else if (freq >  32)
+				wm = 0x13100000;
+			else
+				wm = 0x120E0000;
+		} else {
+			if	(freq > 160)
+				wm = 0x28200000;
+			else if (freq > 140)
+				wm = 0x2A1E0000;
+			else if (freq > 130)
+				wm = 0x2B1A0000;
+			else if (freq > 120)
+				wm = 0x2C180000;
+			else if (freq > 100)
+				wm = 0x24180000;
+			else if (freq >  90)
+				wm = 0x18120000;
+			else if (freq >  50)
+				wm = 0x16110000;
+			else if (freq >  32)
+				wm = 0x13100000;
+			else
+				wm = 0x120E0000;
+		}
+		break;
+	case 24:
+		if (par->has_sgram) {
+			if	(freq > 130)
+				wm = 0x31200000;
+			else if (freq > 120)
+				wm = 0x2E200000;
+			else if (freq > 100)
+				wm = 0x2C1D0000;
+			else if (freq >  80)
+				wm = 0x25180000;
+			else if (freq >  64)
+				wm = 0x24160000;
+			else if (freq >  49)
+				wm = 0x18120000;
+			else if (freq >  32)
+				wm = 0x16110000;
+			else
+				wm = 0x13100000;
+		} else {
+			if	(freq > 120)
+				wm = 0x311F0000;
+			else if (freq > 100)
+				wm = 0x2C1D0000;
+			else if (freq >  80)
+				wm = 0x25180000;
+			else if (freq >  64)
+				wm = 0x24160000;
+			else if (freq >  49)
+				wm = 0x18120000;
+			else if (freq >  32)
+				wm = 0x16110000;
+			else
+				wm = 0x13100000;
+		}
+		break;
+	case 32:
+		if (par->has_sgram) {
+			if	(freq >  80)
+				wm = 0x2A200000;
+			else if (freq >  60)
+				wm = 0x281A0000;
+			else if (freq >  49)
+				wm = 0x25180000;
+			else if (freq >  32)
+				wm = 0x18120000;
+			else
+				wm = 0x16110000;
+		} else {
+			if	(freq >  80)
+				wm = 0x29200000;
+			else if (freq >  60)
+				wm = 0x281A0000;
+			else if (freq >  49)
+				wm = 0x25180000;
+			else if (freq >  32)
+				wm = 0x18120000;
+			else
+				wm = 0x16110000;
+		}
+		break;
+	}
+
+	return wm;
+}
+
+/* clock calculation from i740fb by Patrick LERDA */
+
+#define I740_RFREQ		1000000
+#define TARGET_MAX_N		30
+#define I740_FFIX		(1 << 8)
+#define I740_RFREQ_FIX		(I740_RFREQ / I740_FFIX)
+#define I740_REF_FREQ		(6667 * I740_FFIX / 100)	/* 66.67 MHz */
+#define I740_MAX_VCO_FREQ	(450 * I740_FFIX)		/* 450 MHz */
+
+static void i740_calc_vclk(u32 freq, struct i740fb_par *par)
+{
+	const u32 err_max    = freq / (200  * I740_RFREQ / I740_FFIX);
+	const u32 err_target = freq / (1000 * I740_RFREQ / I740_FFIX);
+	u32 err_best = 512 * I740_FFIX;
+	u32 f_err, f_vco;
+	int m_best = 0, n_best = 0, p_best = 0, d_best = 0;
+	int m, n;
+
+	p_best = min(15, ilog2(I740_MAX_VCO_FREQ / (freq / I740_RFREQ_FIX)));
+	d_best = 0;
+	f_vco = (freq * (1 << p_best)) / I740_RFREQ_FIX;
+	freq = freq / I740_RFREQ_FIX;
+
+	n = 2;
+	do {
+		n++;
+		m = ((f_vco * n) / I740_REF_FREQ + 2) / 4;
+
+		if (m < 3)
+			m = 3;
+
+		{
+			u32 f_out = (((m * I740_REF_FREQ * (4 << 2 * d_best))
+				 / n) + ((1 << p_best) / 2)) / (1 << p_best);
+
+			f_err = (freq - f_out);
+
+			if (abs(f_err) < err_max) {
+				m_best = m;
+				n_best = n;
+				err_best = f_err;
+			}
+		}
+	} while ((abs(f_err) >= err_target) &&
+		 ((n <= TARGET_MAX_N) || (abs(err_best) > err_max)));
+
+	if (abs(f_err) < err_target) {
+		m_best = m;
+		n_best = n;
+	}
+
+	par->video_clk2_m = (m_best - 2) & 0xFF;
+	par->video_clk2_n = (n_best - 2) & 0xFF;
+	par->video_clk2_mn_msbs = ((((n_best - 2) >> 4) & VCO_N_MSBS)
+				 | (((m_best - 2) >> 8) & VCO_M_MSBS));
+	par->video_clk2_div_sel =
+		((p_best << 4) | (d_best ? 4 : 0) | REF_DIV_1);
+}
+
+static int i740fb_decode_var(const struct fb_var_screeninfo *var,
+			     struct i740fb_par *par, struct fb_info *info)
+{
+	/*
+	 * Get the video params out of 'var'.
+	 * If a value doesn't fit, round it up, if it's too big, return -EINVAL.
+	 */
+
+	u32 xres, right, hslen, left, xtotal;
+	u32 yres, lower, vslen, upper, ytotal;
+	u32 vxres, xoffset, vyres, yoffset;
+	u32 bpp, base, dacspeed24, mem;
+	u8 r7;
+	int i;
+
+	dev_dbg(info->device, "decode_var: xres: %i, yres: %i, xres_v: %i, xres_v: %i\n",
+		  var->xres, var->yres, var->xres_virtual, var->xres_virtual);
+	dev_dbg(info->device, "	xoff: %i, yoff: %i, bpp: %i, graysc: %i\n",
+		  var->xoffset, var->yoffset, var->bits_per_pixel,
+		  var->grayscale);
+	dev_dbg(info->device, "	activate: %i, nonstd: %i, vmode: %i\n",
+		  var->activate, var->nonstd, var->vmode);
+	dev_dbg(info->device, "	pixclock: %i, hsynclen:%i, vsynclen:%i\n",
+		  var->pixclock, var->hsync_len, var->vsync_len);
+	dev_dbg(info->device, "	left: %i, right: %i, up:%i, lower:%i\n",
+		  var->left_margin, var->right_margin, var->upper_margin,
+		  var->lower_margin);
+
+
+	bpp = var->bits_per_pixel;
+	switch (bpp) {
+	case 1 ... 8:
+		bpp = 8;
+		if ((1000000 / var->pixclock) > DACSPEED8) {
+			dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 8bpp)\n",
+				1000000 / var->pixclock, DACSPEED8);
+			return -EINVAL;
+		}
+		break;
+	case 9 ... 15:
+		bpp = 15;
+	case 16:
+		if ((1000000 / var->pixclock) > DACSPEED16) {
+			dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 15/16bpp)\n",
+				1000000 / var->pixclock, DACSPEED16);
+			return -EINVAL;
+		}
+		break;
+	case 17 ... 24:
+		bpp = 24;
+		dacspeed24 = par->has_sgram ? DACSPEED24_SG : DACSPEED24_SD;
+		if ((1000000 / var->pixclock) > dacspeed24) {
+			dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 24bpp)\n",
+				1000000 / var->pixclock, dacspeed24);
+			return -EINVAL;
+		}
+		break;
+	case 25 ... 32:
+		bpp = 32;
+		if ((1000000 / var->pixclock) > DACSPEED32) {
+			dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 32bpp)\n",
+				1000000 / var->pixclock, DACSPEED32);
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	xres = ALIGN(var->xres, 8);
+	vxres = ALIGN(var->xres_virtual, 16);
+	if (vxres < xres)
+		vxres = xres;
+
+	xoffset = ALIGN(var->xoffset, 8);
+	if (xres + xoffset > vxres)
+		xoffset = vxres - xres;
+
+	left = ALIGN(var->left_margin, 8);
+	right = ALIGN(var->right_margin, 8);
+	hslen = ALIGN(var->hsync_len, 8);
+
+	yres = var->yres;
+	vyres = var->yres_virtual;
+	if (yres > vyres)
+		vyres = yres;
+
+	yoffset = var->yoffset;
+	if (yres + yoffset > vyres)
+		yoffset = vyres - yres;
+
+	lower = var->lower_margin;
+	vslen = var->vsync_len;
+	upper = var->upper_margin;
+
+	mem = vxres * vyres * ((bpp + 1) / 8);
+	if (mem > info->screen_size) {
+		dev_err(info->device, "not enough video memory (%d KB requested, %ld KB avaliable)\n",
+			mem >> 10, info->screen_size >> 10);
+		return -ENOMEM;
+	}
+
+	if (yoffset + yres > vyres)
+		yoffset = vyres - yres;
+
+	xtotal = xres + right + hslen + left;
+	ytotal = yres + lower + vslen + upper;
+
+	par->crtc[VGA_CRTC_H_TOTAL] = (xtotal >> 3) - 5;
+	par->crtc[VGA_CRTC_H_DISP] = (xres >> 3) - 1;
+	par->crtc[VGA_CRTC_H_BLANK_START] = ((xres + right) >> 3) - 1;
+	par->crtc[VGA_CRTC_H_SYNC_START] = (xres + right) >> 3;
+	par->crtc[VGA_CRTC_H_SYNC_END] = (((xres + right + hslen) >> 3) & 0x1F)
+		| ((((xres + right + hslen) >> 3) & 0x20) << 2);
+	par->crtc[VGA_CRTC_H_BLANK_END] = ((xres + right + hslen) >> 3 & 0x1F)
+		| 0x80;
+
+	par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
+
+	r7 = 0x10;	/* disable linecompare */
+	if (ytotal & 0x100)
+		r7 |= 0x01;
+	if (ytotal & 0x200)
+		r7 |= 0x20;
+
+	par->crtc[VGA_CRTC_PRESET_ROW] = 0;
+	par->crtc[VGA_CRTC_MAX_SCAN] = 0x40;	/* 1 scanline, no linecmp */
+	if (var->vmode & FB_VMODE_DOUBLE)
+		par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
+	par->crtc[VGA_CRTC_CURSOR_START] = 0x00;
+	par->crtc[VGA_CRTC_CURSOR_END] = 0x00;
+	par->crtc[VGA_CRTC_CURSOR_HI] = 0x00;
+	par->crtc[VGA_CRTC_CURSOR_LO] = 0x00;
+	par->crtc[VGA_CRTC_V_DISP_END] = yres-1;
+	if ((yres-1) & 0x100)
+		r7 |= 0x02;
+	if ((yres-1) & 0x200)
+		r7 |= 0x40;
+
+	par->crtc[VGA_CRTC_V_BLANK_START] = yres + lower - 1;
+	par->crtc[VGA_CRTC_V_SYNC_START] = yres + lower - 1;
+	if ((yres + lower - 1) & 0x100)
+		r7 |= 0x0C;
+	if ((yres + lower - 1) & 0x200) {
+		par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20;
+		r7 |= 0x80;
+	}
+
+	/* disabled IRQ */
+	par->crtc[VGA_CRTC_V_SYNC_END] =
+		((yres + lower - 1 + vslen) & 0x0F) & ~0x10;
+	/* 0x7F for VGA, but some SVGA chips require all 8 bits to be set */
+	par->crtc[VGA_CRTC_V_BLANK_END] = (yres + lower - 1 + vslen) & 0xFF;
+
+	par->crtc[VGA_CRTC_UNDERLINE] = 0x00;
+	par->crtc[VGA_CRTC_MODE] = 0xC3 ;
+	par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
+	par->crtc[VGA_CRTC_OVERFLOW] = r7;
+
+	par->vss = 0x00;	/* 3DA */
+
+	for (i = 0x00; i < 0x10; i++)
+		par->atc[i] = i;
+	par->atc[VGA_ATC_MODE] = 0x81;
+	par->atc[VGA_ATC_OVERSCAN] = 0x00;	/* 0 for EGA, 0xFF for VGA */
+	par->atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
+	par->atc[VGA_ATC_COLOR_PAGE] = 0x00;
+
+	par->misc = 0xC3;
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+		par->misc &= ~0x40;
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+		par->misc &= ~0x80;
+
+	par->seq[VGA_SEQ_CLOCK_MODE] = 0x01;
+	par->seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
+	par->seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
+	par->seq[VGA_SEQ_MEMORY_MODE] = 0x06;
+
+	par->gdc[VGA_GFX_SR_VALUE] = 0x00;
+	par->gdc[VGA_GFX_SR_ENABLE] = 0x00;
+	par->gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
+	par->gdc[VGA_GFX_DATA_ROTATE] = 0x00;
+	par->gdc[VGA_GFX_PLANE_READ] = 0;
+	par->gdc[VGA_GFX_MODE] = 0x02;
+	par->gdc[VGA_GFX_MISC] = 0x05;
+	par->gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
+	par->gdc[VGA_GFX_BIT_MASK] = 0xFF;
+
+	base = (yoffset * vxres + (xoffset & ~7)) >> 2;
+	switch (bpp) {
+	case 8:
+		par->crtc[VGA_CRTC_OFFSET] = vxres >> 3;
+		par->ext_offset = vxres >> 11;
+		par->pixelpipe_cfg1 = DISPLAY_8BPP_MODE;
+		par->bitblt_cntl = COLEXP_8BPP;
+		break;
+	case 15: /* 0rrrrrgg gggbbbbb */
+	case 16: /* rrrrrggg gggbbbbb */
+		par->pixelpipe_cfg1 = (var->green.length == 6) ?
+			DISPLAY_16BPP_MODE : DISPLAY_15BPP_MODE;
+		par->crtc[VGA_CRTC_OFFSET] = vxres >> 2;
+		par->ext_offset = vxres >> 10;
+		par->bitblt_cntl = COLEXP_16BPP;
+		base *= 2;
+		break;
+	case 24:
+		par->crtc[VGA_CRTC_OFFSET] = (vxres * 3) >> 3;
+		par->ext_offset = (vxres * 3) >> 11;
+		par->pixelpipe_cfg1 = DISPLAY_24BPP_MODE;
+		par->bitblt_cntl = COLEXP_24BPP;
+		base &= 0xFFFFFFFE; /* ...ignore the last bit. */
+		base *= 3;
+		break;
+	case 32:
+		par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
+		par->ext_offset = vxres >> 9;
+		par->pixelpipe_cfg1 = DISPLAY_32BPP_MODE;
+		par->bitblt_cntl = COLEXP_RESERVED; /* Unimplemented on i740 */
+		base *= 4;
+		break;
+	}
+
+	par->crtc[VGA_CRTC_START_LO] = base & 0x000000FF;
+	par->crtc[VGA_CRTC_START_HI] = (base & 0x0000FF00) >>  8;
+	par->ext_start_addr =
+		((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE;
+	par->ext_start_addr_hi = (base & 0x3FC00000) >> 22;
+
+	par->pixelpipe_cfg0 = DAC_8_BIT;
+
+	par->pixelpipe_cfg2 = DISPLAY_GAMMA_ENABLE | OVERLAY_GAMMA_ENABLE;
+	par->io_cntl = EXTENDED_CRTC_CNTL;
+	par->address_mapping = LINEAR_MODE_ENABLE | PAGE_MAPPING_ENABLE;
+	par->display_cntl = HIRES_MODE;
+
+	/* Set the MCLK freq */
+	par->pll_cntl = PLL_MEMCLK_100000KHZ; /* 100 MHz -- use as default */
+
+	/* Calculate the extended CRTC regs */
+	par->ext_vert_total = (ytotal - 2) >> 8;
+	par->ext_vert_disp_end = (yres - 1) >> 8;
+	par->ext_vert_sync_start = (yres + lower) >> 8;
+	par->ext_vert_blank_start = (yres + lower) >> 8;
+	par->ext_horiz_total = ((xtotal >> 3) - 5) >> 8;
+	par->ext_horiz_blank = (((xres + right) >> 3) & 0x40) >> 6;
+
+	par->interlace_cntl = INTERLACE_DISABLE;
+
+	/* Set the overscan color to 0. (NOTE: This only affects >8bpp mode) */
+	par->atc[VGA_ATC_OVERSCAN] = 0;
+
+	/* Calculate VCLK that most closely matches the requested dot clock */
+	i740_calc_vclk((((u32)1e9) / var->pixclock) * (u32)(1e3), par);
+
+	/* Since we program the clocks ourselves, always use VCLK2. */
+	par->misc |= 0x0C;
+
+	/* Calculate the FIFO Watermark and Burst Length. */
+	par->lmi_fifo_watermark =
+		i740_calc_fifo(par, 1000000 / var->pixclock, bpp);
+
+	return 0;
+}
+
+static int i740fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	switch (var->bits_per_pixel) {
+	case 8:
+		var->red.offset	= var->green.offset = var->blue.offset = 0;
+		var->red.length	= var->green.length = var->blue.length = 8;
+		break;
+	case 16:
+		switch (var->green.length) {
+		default:
+		case 5:
+			var->red.offset = 10;
+			var->green.offset = 5;
+			var->blue.offset = 0;
+			var->red.length	= 5;
+			var->green.length = 5;
+			var->blue.length = 5;
+			break;
+		case 6:
+			var->red.offset = 11;
+			var->green.offset = 5;
+			var->blue.offset = 0;
+			var->red.length = var->blue.length = 5;
+			break;
+		}
+		break;
+	case 24:
+		var->red.offset = 16;
+		var->green.offset = 8;
+		var->blue.offset = 0;
+		var->red.length	= var->green.length = var->blue.length = 8;
+		break;
+	case 32:
+		var->transp.offset = 24;
+		var->red.offset = 16;
+		var->green.offset = 8;
+		var->blue.offset = 0;
+		var->transp.length = 8;
+		var->red.length = var->green.length = var->blue.length = 8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (var->xres > var->xres_virtual)
+		var->xres_virtual = var->xres;
+
+	if (var->yres > var->yres_virtual)
+		var->yres_virtual = var->yres;
+
+	if (info->monspecs.hfmax && info->monspecs.vfmax &&
+	    info->monspecs.dclkmax && fb_validate_mode(var, info) < 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void vga_protect(struct i740fb_par *par)
+{
+	/* disable the display */
+	i740outreg_mask(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, 0x20, 0x20);
+
+	i740inb(par, 0x3DA);
+	i740outb(par, VGA_ATT_W, 0x00);	/* enable pallete access */
+}
+
+static void vga_unprotect(struct i740fb_par *par)
+{
+	/* reenable display */
+	i740outreg_mask(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, 0, 0x20);
+
+	i740inb(par, 0x3DA);
+	i740outb(par, VGA_ATT_W, 0x20);	/* disable pallete access */
+}
+
+static int i740fb_set_par(struct fb_info *info)
+{
+	struct i740fb_par *par = info->par;
+	u32 itemp;
+	int i;
+
+	i = i740fb_decode_var(&info->var, par, info);
+	if (i)
+		return i;
+
+	memset(info->screen_base, 0, info->screen_size);
+
+	vga_protect(par);
+
+	i740outreg(par, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_DISABLE);
+
+	mdelay(1);
+
+	i740outreg(par, XRX, VCLK2_VCO_M, par->video_clk2_m);
+	i740outreg(par, XRX, VCLK2_VCO_N, par->video_clk2_n);
+	i740outreg(par, XRX, VCLK2_VCO_MN_MSBS, par->video_clk2_mn_msbs);
+	i740outreg(par, XRX, VCLK2_VCO_DIV_SEL, par->video_clk2_div_sel);
+
+	i740outreg_mask(par, XRX, PIXPIPE_CONFIG_0,
+			par->pixelpipe_cfg0 & DAC_8_BIT, 0x80);
+
+	i740inb(par, 0x3DA);
+	i740outb(par, 0x3C0, 0x00);
+
+	/* update misc output register */
+	i740outb(par, VGA_MIS_W, par->misc | 0x01);
+
+	/* synchronous reset on */
+	i740outreg(par, VGA_SEQ_I, VGA_SEQ_RESET, 0x01);
+	/* write sequencer registers */
+	i740outreg(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE,
+			par->seq[VGA_SEQ_CLOCK_MODE] | 0x20);
+	for (i = 2; i < VGA_SEQ_C; i++)
+		i740outreg(par, VGA_SEQ_I, i, par->seq[i]);
+
+	/* synchronous reset off */
+	i740outreg(par, VGA_SEQ_I, VGA_SEQ_RESET, 0x03);
+
+	/* deprotect CRT registers 0-7 */
+	i740outreg(par, VGA_CRT_IC, VGA_CRTC_V_SYNC_END,
+			par->crtc[VGA_CRTC_V_SYNC_END]);
+
+	/* write CRT registers */
+	for (i = 0; i < VGA_CRT_C; i++)
+		i740outreg(par, VGA_CRT_IC, i, par->crtc[i]);
+
+	/* write graphics controller registers */
+	for (i = 0; i < VGA_GFX_C; i++)
+		i740outreg(par, VGA_GFX_I, i, par->gdc[i]);
+
+	/* write attribute controller registers */
+	for (i = 0; i < VGA_ATT_C; i++) {
+		i740inb(par, VGA_IS1_RC);		/* reset flip-flop */
+		i740outb(par, VGA_ATT_IW, i);
+		i740outb(par, VGA_ATT_IW, par->atc[i]);
+	}
+
+	i740inb(par, VGA_IS1_RC);
+	i740outb(par, VGA_ATT_IW, 0x20);
+
+	i740outreg(par, VGA_CRT_IC, EXT_VERT_TOTAL, par->ext_vert_total);
+	i740outreg(par, VGA_CRT_IC, EXT_VERT_DISPLAY, par->ext_vert_disp_end);
+	i740outreg(par, VGA_CRT_IC, EXT_VERT_SYNC_START,
+			par->ext_vert_sync_start);
+	i740outreg(par, VGA_CRT_IC, EXT_VERT_BLANK_START,
+			par->ext_vert_blank_start);
+	i740outreg(par, VGA_CRT_IC, EXT_HORIZ_TOTAL, par->ext_horiz_total);
+	i740outreg(par, VGA_CRT_IC, EXT_HORIZ_BLANK, par->ext_horiz_blank);
+	i740outreg(par, VGA_CRT_IC, EXT_OFFSET, par->ext_offset);
+	i740outreg(par, VGA_CRT_IC, EXT_START_ADDR_HI, par->ext_start_addr_hi);
+	i740outreg(par, VGA_CRT_IC, EXT_START_ADDR, par->ext_start_addr);
+
+	i740outreg_mask(par, VGA_CRT_IC, INTERLACE_CNTL,
+			par->interlace_cntl, INTERLACE_ENABLE);
+	i740outreg_mask(par, XRX, ADDRESS_MAPPING, par->address_mapping, 0x1F);
+	i740outreg_mask(par, XRX, BITBLT_CNTL, par->bitblt_cntl, COLEXP_MODE);
+	i740outreg_mask(par, XRX, DISPLAY_CNTL,
+			par->display_cntl, VGA_WRAP_MODE | GUI_MODE);
+	i740outreg_mask(par, XRX, PIXPIPE_CONFIG_0, par->pixelpipe_cfg0, 0x9B);
+	i740outreg_mask(par, XRX, PIXPIPE_CONFIG_2, par->pixelpipe_cfg2, 0x0C);
+
+	i740outreg(par, XRX, PLL_CNTL, par->pll_cntl);
+
+	i740outreg_mask(par, XRX, PIXPIPE_CONFIG_1,
+			par->pixelpipe_cfg1, DISPLAY_COLOR_MODE);
+
+	itemp = readl(par->regs + FWATER_BLC);
+	itemp &= ~(LMI_BURST_LENGTH | LMI_FIFO_WATERMARK);
+	itemp |= par->lmi_fifo_watermark;
+	writel(itemp, par->regs + FWATER_BLC);
+
+	i740outreg(par, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_60HZ);
+
+	i740outreg_mask(par, MRX, COL_KEY_CNTL_1, 0, BLANK_DISP_OVERLAY);
+	i740outreg_mask(par, XRX, IO_CTNL,
+			par->io_cntl, EXTENDED_ATTR_CNTL | EXTENDED_CRTC_CNTL);
+
+	if (par->pixelpipe_cfg1 != DISPLAY_8BPP_MODE) {
+		i740outb(par, VGA_PEL_MSK, 0xFF);
+		i740outb(par, VGA_PEL_IW, 0x00);
+		for (i = 0; i < 256; i++) {
+			itemp = (par->pixelpipe_cfg0 & DAC_8_BIT) ? i : i >> 2;
+			i740outb(par, VGA_PEL_D, itemp);
+			i740outb(par, VGA_PEL_D, itemp);
+			i740outb(par, VGA_PEL_D, itemp);
+		}
+	}
+
+	/* Wait for screen to stabilize. */
+	mdelay(50);
+	vga_unprotect(par);
+
+	info->fix.line_length =
+			info->var.xres_virtual * info->var.bits_per_pixel / 8;
+	if (info->var.bits_per_pixel == 8)
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	else
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+	return 0;
+}
+
+static int i740fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info)
+{
+	u32 r, g, b;
+
+	dev_dbg(info->device, "setcolreg: regno: %i, red=%d, green=%d, blue=%d, transp=%d, bpp=%d\n",
+		regno, red, green, blue, transp, info->var.bits_per_pixel);
+
+	switch (info->fix.visual) {
+	case FB_VISUAL_PSEUDOCOLOR:
+		if (regno >= 256)
+			return -EINVAL;
+		i740outb(info->par, VGA_PEL_IW, regno);
+		i740outb(info->par, VGA_PEL_D, red >> 8);
+		i740outb(info->par, VGA_PEL_D, green >> 8);
+		i740outb(info->par, VGA_PEL_D, blue >> 8);
+		break;
+	case FB_VISUAL_TRUECOLOR:
+		if (regno >= 16)
+			return -EINVAL;
+		r = (red >> (16 - info->var.red.length))
+			<< info->var.red.offset;
+		b = (blue >> (16 - info->var.blue.length))
+			<< info->var.blue.offset;
+		g = (green >> (16 - info->var.green.length))
+			<< info->var.green.offset;
+		((u32 *) info->pseudo_palette)[regno] = r | g | b;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int i740fb_pan_display(struct fb_var_screeninfo *var,
+				 struct fb_info *info)
+{
+	struct i740fb_par *par = info->par;
+	u32 base = (var->yoffset * info->var.xres_virtual
+		 + (var->xoffset & ~7)) >> 2;
+
+	dev_dbg(info->device, "pan_display: xoffset: %i yoffset: %i base: %i\n",
+		var->xoffset, var->yoffset, base);
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		break;
+	case 15:
+	case 16:
+		base *= 2;
+		break;
+	case 24:
+		/*
+		 * The last bit does not seem to have any effect on the start
+		 * address register in 24bpp mode, so...
+		 */
+		base &= 0xFFFFFFFE; /* ...ignore the last bit. */
+		base *= 3;
+		break;
+	case 32:
+		base *= 4;
+		break;
+	}
+
+	par->crtc[VGA_CRTC_START_LO] = base & 0x000000FF;
+	par->crtc[VGA_CRTC_START_HI] = (base & 0x0000FF00) >>  8;
+	par->ext_start_addr_hi = (base & 0x3FC00000) >> 22;
+	par->ext_start_addr =
+			((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE;
+
+	i740outreg(par, VGA_CRT_IC, VGA_CRTC_START_LO,  base & 0x000000FF);
+	i740outreg(par, VGA_CRT_IC, VGA_CRTC_START_HI,
+			(base & 0x0000FF00) >> 8);
+	i740outreg(par, VGA_CRT_IC, EXT_START_ADDR_HI,
+			(base & 0x3FC00000) >> 22);
+	i740outreg(par, VGA_CRT_IC, EXT_START_ADDR,
+			((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE);
+
+	return 0;
+}
+
+static int i740fb_blank(int blank_mode, struct fb_info *info)
+{
+	struct i740fb_par *par = info->par;
+
+	unsigned char SEQ01;
+	int DPMSSyncSelect;
+
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+	case FB_BLANK_NORMAL:
+		SEQ01 = 0x00;
+		DPMSSyncSelect = HSYNC_ON | VSYNC_ON;
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		SEQ01 = 0x20;
+		DPMSSyncSelect = HSYNC_ON | VSYNC_OFF;
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		SEQ01 = 0x20;
+		DPMSSyncSelect = HSYNC_OFF | VSYNC_ON;
+		break;
+	case FB_BLANK_POWERDOWN:
+		SEQ01 = 0x20;
+		DPMSSyncSelect = HSYNC_OFF | VSYNC_OFF;
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* Turn the screen on/off */
+	i740outb(par, SRX, 0x01);
+	SEQ01 |= i740inb(par, SRX + 1) & ~0x20;
+	i740outb(par, SRX, 0x01);
+	i740outb(par, SRX + 1, SEQ01);
+
+	/* Set the DPMS mode */
+	i740outreg(par, XRX, DPMS_SYNC_SELECT, DPMSSyncSelect);
+
+	/* Let fbcon do a soft blank for us */
+	return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
+}
+
+static struct fb_ops i740fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_open	= i740fb_open,
+	.fb_release	= i740fb_release,
+	.fb_check_var	= i740fb_check_var,
+	.fb_set_par	= i740fb_set_par,
+	.fb_setcolreg	= i740fb_setcolreg,
+	.fb_blank	= i740fb_blank,
+	.fb_pan_display	= i740fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+/* ------------------------------------------------------------------------- */
+
+static int __devinit i740fb_probe(struct pci_dev *dev,
+				  const struct pci_device_id *ent)
+{
+	struct fb_info *info;
+	struct i740fb_par *par;
+	int ret, tmp;
+	bool found = false;
+	u8 *edid;
+
+	info = framebuffer_alloc(sizeof(struct i740fb_par), &(dev->dev));
+	if (!info) {
+		dev_err(&(dev->dev), "cannot allocate framebuffer\n");
+		return -ENOMEM;
+	}
+
+	par = info->par;
+	mutex_init(&par->open_lock);
+
+	info->var.activate = FB_ACTIVATE_NOW;
+	info->var.bits_per_pixel = 8;
+	info->fbops = &i740fb_ops;
+	info->pseudo_palette = par->pseudo_palette;
+
+	ret = pci_enable_device(dev);
+	if (ret) {
+		dev_err(info->device, "cannot enable PCI device\n");
+		goto err_enable_device;
+	}
+
+	ret = pci_request_regions(dev, info->fix.id);
+	if (ret) {
+		dev_err(info->device, "error requesting regions\n");
+		goto err_request_regions;
+	}
+
+	info->screen_base = pci_ioremap_bar(dev, 0);
+	if (!info->screen_base) {
+		dev_err(info->device, "error remapping base\n");
+		ret = -ENOMEM;
+		goto err_ioremap_1;
+	}
+
+	par->regs = pci_ioremap_bar(dev, 1);
+	if (!par->regs) {
+		dev_err(info->device, "error remapping MMIO\n");
+		ret = -ENOMEM;
+		goto err_ioremap_2;
+	}
+
+	/* detect memory size */
+	if ((i740inreg(par, XRX, DRAM_ROW_TYPE) & DRAM_ROW_1)
+							== DRAM_ROW_1_SDRAM)
+		i740outb(par, XRX, DRAM_ROW_BNDRY_1);
+	else
+		i740outb(par, XRX, DRAM_ROW_BNDRY_0);
+	info->screen_size = i740inb(par, XRX + 1) * 1024 * 1024;
+	/* detect memory type */
+	tmp = i740inreg(par, XRX, DRAM_ROW_CNTL_LO);
+	par->has_sgram = !((tmp & DRAM_RAS_TIMING) ||
+			   (tmp & DRAM_RAS_PRECHARGE));
+
+	printk(KERN_INFO "fb%d: Intel740 on %s, %ld KB %s\n", info->node,
+		pci_name(dev), info->screen_size >> 10,
+		par->has_sgram ? "SGRAM" : "SDRAM");
+
+	info->fix = i740fb_fix;
+	info->fix.mmio_start = pci_resource_start(dev, 1);
+	info->fix.mmio_len = pci_resource_len(dev, 1);
+	info->fix.smem_start = pci_resource_start(dev, 0);
+	info->fix.smem_len = info->screen_size;
+	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+
+	if (i740fb_setup_ddc_bus(info) == 0) {
+		par->ddc_registered = true;
+		edid = fb_ddc_read(&par->ddc_adapter);
+		if (edid) {
+			fb_edid_to_monspecs(edid, &info->monspecs);
+			kfree(edid);
+			if (!info->monspecs.modedb)
+				dev_err(info->device,
+					"error getting mode database\n");
+			else {
+				const struct fb_videomode *m;
+
+				fb_videomode_to_modelist(
+					info->monspecs.modedb,
+					info->monspecs.modedb_len,
+					&info->modelist);
+				m = fb_find_best_display(&info->monspecs,
+							 &info->modelist);
+				if (m) {
+					fb_videomode_to_var(&info->var, m);
+					/* fill all other info->var's fields */
+					if (!i740fb_check_var(&info->var, info))
+						found = true;
+				}
+			}
+		}
+	}
+
+	if (!mode_option && !found)
+		mode_option = "640x480-8@60";
+
+	if (mode_option) {
+		ret = fb_find_mode(&info->var, info, mode_option,
+				   info->monspecs.modedb,
+				   info->monspecs.modedb_len,
+				   NULL, info->var.bits_per_pixel);
+		if (!ret || ret == 4) {
+			dev_err(info->device, "mode %s not found\n",
+				mode_option);
+			ret = -EINVAL;
+		}
+	}
+
+	fb_destroy_modedb(info->monspecs.modedb);
+	info->monspecs.modedb = NULL;
+
+	/* maximize virtual vertical size for fast scrolling */
+	info->var.yres_virtual = info->fix.smem_len * 8 /
+			(info->var.bits_per_pixel * info->var.xres_virtual);
+
+	if (ret == -EINVAL)
+		goto err_find_mode;
+
+	ret = fb_alloc_cmap(&info->cmap, 256, 0);
+	if (ret) {
+		dev_err(info->device, "cannot allocate colormap\n");
+		goto err_alloc_cmap;
+	}
+
+	ret = register_framebuffer(info);
+	if (ret) {
+		dev_err(info->device, "error registering framebuffer\n");
+		goto err_reg_framebuffer;
+	}
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+		info->node, info->fix.id);
+	pci_set_drvdata(dev, info);
+#ifdef CONFIG_MTRR
+	if (mtrr) {
+		par->mtrr_reg = -1;
+		par->mtrr_reg = mtrr_add(info->fix.smem_start,
+				info->fix.smem_len, MTRR_TYPE_WRCOMB, 1);
+	}
+#endif
+	return 0;
+
+err_reg_framebuffer:
+	fb_dealloc_cmap(&info->cmap);
+err_alloc_cmap:
+err_find_mode:
+	if (par->ddc_registered)
+		i2c_del_adapter(&par->ddc_adapter);
+	pci_iounmap(dev, par->regs);
+err_ioremap_2:
+	pci_iounmap(dev, info->screen_base);
+err_ioremap_1:
+	pci_release_regions(dev);
+err_request_regions:
+/*	pci_disable_device(dev); */
+err_enable_device:
+	framebuffer_release(info);
+	return ret;
+}
+
+static void __devexit i740fb_remove(struct pci_dev *dev)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+
+	if (info) {
+		struct i740fb_par *par = info->par;
+
+#ifdef CONFIG_MTRR
+		if (par->mtrr_reg >= 0) {
+			mtrr_del(par->mtrr_reg, 0, 0);
+			par->mtrr_reg = -1;
+		}
+#endif
+		unregister_framebuffer(info);
+		fb_dealloc_cmap(&info->cmap);
+		if (par->ddc_registered)
+			i2c_del_adapter(&par->ddc_adapter);
+		pci_iounmap(dev, par->regs);
+		pci_iounmap(dev, info->screen_base);
+		pci_release_regions(dev);
+/*		pci_disable_device(dev); */
+		pci_set_drvdata(dev, NULL);
+		framebuffer_release(info);
+	}
+}
+
+#ifdef CONFIG_PM
+static int i740fb_suspend(struct pci_dev *dev, pm_message_t state)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct i740fb_par *par = info->par;
+
+	/* don't disable console during hibernation and wakeup from it */
+	if (state.event == PM_EVENT_FREEZE || state.event == PM_EVENT_PRETHAW)
+		return 0;
+
+	console_lock();
+	mutex_lock(&(par->open_lock));
+
+	/* do nothing if framebuffer is not active */
+	if (par->ref_count == 0) {
+		mutex_unlock(&(par->open_lock));
+		console_unlock();
+		return 0;
+	}
+
+	fb_set_suspend(info, 1);
+
+	pci_save_state(dev);
+	pci_disable_device(dev);
+	pci_set_power_state(dev, pci_choose_state(dev, state));
+
+	mutex_unlock(&(par->open_lock));
+	console_unlock();
+
+	return 0;
+}
+
+static int i740fb_resume(struct pci_dev *dev)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct i740fb_par *par = info->par;
+
+	console_lock();
+	mutex_lock(&(par->open_lock));
+
+	if (par->ref_count == 0)
+		goto fail;
+
+	pci_set_power_state(dev, PCI_D0);
+	pci_restore_state(dev);
+	if (pci_enable_device(dev))
+		goto fail;
+
+	i740fb_set_par(info);
+	fb_set_suspend(info, 0);
+
+fail:
+	mutex_unlock(&(par->open_lock));
+	console_unlock();
+	return 0;
+}
+#else
+#define i740fb_suspend NULL
+#define i740fb_resume NULL
+#endif /* CONFIG_PM */
+
+#define I740_ID_PCI 0x00d1
+#define I740_ID_AGP 0x7800
+
+static DEFINE_PCI_DEVICE_TABLE(i740fb_id_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_PCI) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_AGP) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, i740fb_id_table);
+
+static struct pci_driver i740fb_driver = {
+	.name		= "i740fb",
+	.id_table	= i740fb_id_table,
+	.probe		= i740fb_probe,
+	.remove		= __devexit_p(i740fb_remove),
+	.suspend	= i740fb_suspend,
+	.resume		= i740fb_resume,
+};
+
+#ifndef MODULE
+static int  __init i740fb_setup(char *options)
+{
+	char *opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((opt = strsep(&options, ",")) != NULL) {
+		if (!*opt)
+			continue;
+#ifdef CONFIG_MTRR
+		else if (!strncmp(opt, "mtrr:", 5))
+			mtrr = simple_strtoul(opt + 5, NULL, 0);
+#endif
+		else
+			mode_option = opt;
+	}
+
+	return 0;
+}
+#endif
+
+int __init i740fb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("i740fb", &option))
+		return -ENODEV;
+	i740fb_setup(option);
+#endif
+
+	return pci_register_driver(&i740fb_driver);
+}
+
+static void __exit i740fb_exit(void)
+{
+	pci_unregister_driver(&i740fb_driver);
+}
+
+module_init(i740fb_init);
+module_exit(i740fb_exit);
+
+MODULE_AUTHOR("(c) 2011 Ondrej Zary <linux@rainbow-software.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("fbdev driver for Intel740");
+
+module_param(mode_option, charp, 0444);
+MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)");
+
+#ifdef CONFIG_MTRR
+module_param(mtrr, int, 0444);
+MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
+#endif
diff --git a/drivers/video/msm/mddi_client_nt35399.c b/drivers/video/msm/mddi_client_nt35399.c
index f239f4a..7fcd67e 100644
--- a/drivers/video/msm/mddi_client_nt35399.c
+++ b/drivers/video/msm/mddi_client_nt35399.c
@@ -155,14 +155,10 @@
 		ret = 0;
 		goto uninit;
 	}
-	ret = gpio_request(gpio, "vsync");
+	ret = gpio_request_one(gpio, GPIOF_IN, "vsync");
 	if (ret)
 		goto err_request_gpio_failed;
 
-	ret = gpio_direction_input(gpio);
-	if (ret)
-		goto err_gpio_direction_input_failed;
-
 	ret = irq = gpio_to_irq(gpio);
 	if (ret < 0)
 		goto err_get_irq_num_failed;
@@ -180,7 +176,6 @@
 	free_irq(gpio_to_irq(gpio), panel->client_data);
 err_request_irq_failed:
 err_get_irq_num_failed:
-err_gpio_direction_input_failed:
 	gpio_free(gpio);
 err_request_gpio_failed:
 	return ret;
diff --git a/drivers/video/msm/mddi_client_toshiba.c b/drivers/video/msm/mddi_client_toshiba.c
index f9bc932..053eb68 100644
--- a/drivers/video/msm/mddi_client_toshiba.c
+++ b/drivers/video/msm/mddi_client_toshiba.c
@@ -186,14 +186,10 @@
 		ret = 0;
 		goto uninit;
 	}
-	ret = gpio_request(gpio, "vsync");
+	ret = gpio_request_one(gpio, GPIOF_IN, "vsync");
 	if (ret)
 		goto err_request_gpio_failed;
 
-	ret = gpio_direction_input(gpio);
-	if (ret)
-		goto err_gpio_direction_input_failed;
-
 	ret = irq = gpio_to_irq(gpio);
 	if (ret < 0)
 		goto err_get_irq_num_failed;
@@ -210,7 +206,6 @@
 	free_irq(gpio_to_irq(gpio), panel);
 err_request_irq_failed:
 err_get_irq_num_failed:
-err_gpio_direction_input_failed:
 	gpio_free(gpio);
 err_request_gpio_failed:
 	return ret;
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index 727a514..eec0d7b 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -337,7 +337,7 @@
 
 	/* This enables the channel */
 	if (mx3_fbi->cookie < 0) {
-		mx3_fbi->txd = dma_chan->device->device_prep_slave_sg(dma_chan,
+		mx3_fbi->txd = dmaengine_prep_slave_sg(dma_chan,
 		      &mx3_fbi->sg[0], 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
 		if (!mx3_fbi->txd) {
 			dev_err(mx3fb->dev, "Cannot allocate descriptor on %d\n",
@@ -1091,7 +1091,7 @@
 	if (mx3_fbi->txd)
 		async_tx_ack(mx3_fbi->txd);
 
-	txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg +
+	txd = dmaengine_prep_slave_sg(dma_chan, sg +
 		mx3_fbi->cur_ipu_buf, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
 	if (!txd) {
 		dev_err(fbi->device,
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index fb3f673..afc9521 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -71,7 +71,6 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig
index 84ff232..1e7536d 100644
--- a/drivers/video/omap/Kconfig
+++ b/drivers/video/omap/Kconfig
@@ -1,11 +1,10 @@
 config FB_OMAP
 	tristate "OMAP frame buffer support (EXPERIMENTAL)"
-	depends on FB && (OMAP2_DSS = "n")
-	depends on ARCH_OMAP1 || ARCH_OMAP2 || ARCH_OMAP3
+	depends on FB
+	depends on ARCH_OMAP1
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
-	select TWL4030_CORE if MACH_OMAP_2430SDP
 	help
           Frame buffer driver for OMAP based boards.
 
@@ -23,13 +22,6 @@
 	  Say Y here if you want to have support for the external
 	  Epson HWA742 LCD controller.
 
-config FB_OMAP_LCDC_BLIZZARD
-	bool "Epson Blizzard LCD controller support"
-	depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL
-	help
-	  Say Y here if you want to have support for the external
-	  Epson Blizzard LCD controller.
-
 config FB_OMAP_MANUAL_UPDATE
 	bool "Default to manual update mode"
 	depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL
@@ -49,7 +41,7 @@
 
 config FB_OMAP_BOOTLOADER_INIT
 	bool "Check bootloader initialization"
-	depends on FB_OMAP || FB_OMAP2
+	depends on FB_OMAP
 	help
 	  Say Y here if you want to enable checking if the bootloader has
 	  already initialized the display controller. In this case the
@@ -68,7 +60,7 @@
 
 config FB_OMAP_DMA_TUNE
         bool "Set DMA SDRAM access priority high"
-        depends on FB_OMAP && ARCH_OMAP1
+        depends on FB_OMAP
         help
           On systems in which video memory is in system memory
           (SDRAM) this will speed up graphics DMA operations.
diff --git a/drivers/video/omap/Makefile b/drivers/video/omap/Makefile
index ef78550..1927faf 100644
--- a/drivers/video/omap/Makefile
+++ b/drivers/video/omap/Makefile
@@ -1,20 +1,14 @@
 #
-# Makefile for the new OMAP framebuffer device driver
+# Makefile for the OMAP1 framebuffer device driver
 #
 
 obj-$(CONFIG_FB_OMAP) += omapfb.o
 
-objs-yy := omapfb_main.o
+objs-yy := omapfb_main.o lcdc.o
 
-objs-y$(CONFIG_ARCH_OMAP1) += lcdc.o
-objs-y$(CONFIG_ARCH_OMAP2) += dispc.o
-objs-y$(CONFIG_ARCH_OMAP3) += dispc.o
-
-objs-$(CONFIG_ARCH_OMAP1)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o
-objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += rfbi.o
+objs-y$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o
 
 objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o
-objs-y$(CONFIG_FB_OMAP_LCDC_BLIZZARD) += blizzard.o
 
 objs-y$(CONFIG_MACH_AMS_DELTA) += lcd_ams_delta.o
 objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o
diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c
deleted file mode 100644
index c0504a8..0000000
--- a/drivers/video/omap/blizzard.c
+++ /dev/null
@@ -1,1648 +0,0 @@
-/*
- * Epson Blizzard LCD controller driver
- *
- * Copyright (C) 2004-2005 Nokia Corporation
- * Authors:     Juha Yrjola   <juha.yrjola@nokia.com>
- *	        Imre Deak     <imre.deak@nokia.com>
- * YUV support: Jussi Laako   <jussi.laako@nokia.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.,
- * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/fb.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-
-#include <plat/dma.h>
-#include <plat/blizzard.h>
-
-#include "omapfb.h"
-#include "dispc.h"
-
-#define MODULE_NAME				"blizzard"
-
-#define BLIZZARD_REV_CODE			0x00
-#define BLIZZARD_CONFIG				0x02
-#define BLIZZARD_PLL_DIV			0x04
-#define BLIZZARD_PLL_LOCK_RANGE			0x06
-#define BLIZZARD_PLL_CLOCK_SYNTH_0		0x08
-#define BLIZZARD_PLL_CLOCK_SYNTH_1		0x0a
-#define BLIZZARD_PLL_MODE			0x0c
-#define BLIZZARD_CLK_SRC			0x0e
-#define BLIZZARD_MEM_BANK0_ACTIVATE		0x10
-#define BLIZZARD_MEM_BANK0_STATUS		0x14
-#define BLIZZARD_PANEL_CONFIGURATION		0x28
-#define BLIZZARD_HDISP				0x2a
-#define BLIZZARD_HNDP				0x2c
-#define BLIZZARD_VDISP0				0x2e
-#define BLIZZARD_VDISP1				0x30
-#define BLIZZARD_VNDP				0x32
-#define BLIZZARD_HSW				0x34
-#define BLIZZARD_VSW				0x38
-#define BLIZZARD_DISPLAY_MODE			0x68
-#define BLIZZARD_INPUT_WIN_X_START_0		0x6c
-#define BLIZZARD_DATA_SOURCE_SELECT		0x8e
-#define BLIZZARD_DISP_MEM_DATA_PORT		0x90
-#define BLIZZARD_DISP_MEM_READ_ADDR0		0x92
-#define BLIZZARD_POWER_SAVE			0xE6
-#define BLIZZARD_NDISP_CTRL_STATUS		0xE8
-
-/* Data source select */
-/* For S1D13745 */
-#define BLIZZARD_SRC_WRITE_LCD_BACKGROUND	0x00
-#define BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE	0x01
-#define BLIZZARD_SRC_WRITE_OVERLAY_ENABLE	0x04
-#define BLIZZARD_SRC_DISABLE_OVERLAY		0x05
-/* For S1D13744 */
-#define BLIZZARD_SRC_WRITE_LCD			0x00
-#define BLIZZARD_SRC_BLT_LCD			0x06
-
-#define BLIZZARD_COLOR_RGB565			0x01
-#define BLIZZARD_COLOR_YUV420			0x09
-
-#define BLIZZARD_VERSION_S1D13745		0x01	/* Hailstorm */
-#define BLIZZARD_VERSION_S1D13744		0x02	/* Blizzard */
-
-#define BLIZZARD_AUTO_UPDATE_TIME		(HZ / 20)
-
-/* Reserve 4 request slots for requests in irq context */
-#define REQ_POOL_SIZE			24
-#define IRQ_REQ_POOL_SIZE		4
-
-#define REQ_FROM_IRQ_POOL 0x01
-
-#define REQ_COMPLETE	0
-#define REQ_PENDING	1
-
-struct blizzard_reg_list {
-	int	start;
-	int	end;
-};
-
-/* These need to be saved / restored separately from the rest. */
-static const struct blizzard_reg_list blizzard_pll_regs[] = {
-	{
-		.start	= 0x04,		/* Don't save PLL ctrl (0x0C) */
-		.end	= 0x0a,
-	},
-	{
-		.start	= 0x0e,		/* Clock configuration */
-		.end	= 0x0e,
-	},
-};
-
-static const struct blizzard_reg_list blizzard_gen_regs[] = {
-	{
-		.start	= 0x18,		/* SDRAM control */
-		.end	= 0x20,
-	},
-	{
-		.start	= 0x28,		/* LCD Panel configuration */
-		.end	= 0x5a,		/* HSSI interface, TV configuration */
-	},
-};
-
-static u8 blizzard_reg_cache[0x5a / 2];
-
-struct update_param {
-	int	plane;
-	int	x, y, width, height;
-	int	out_x, out_y;
-	int	out_width, out_height;
-	int	color_mode;
-	int	bpp;
-	int	flags;
-};
-
-struct blizzard_request {
-	struct list_head entry;
-	unsigned int	 flags;
-
-	int		 (*handler)(struct blizzard_request *req);
-	void		 (*complete)(void *data);
-	void		 *complete_data;
-
-	union {
-		struct update_param	update;
-		struct completion	*sync;
-	} par;
-};
-
-struct plane_info {
-	unsigned long offset;
-	int pos_x, pos_y;
-	int width, height;
-	int out_width, out_height;
-	int scr_width;
-	int color_mode;
-	int bpp;
-};
-
-struct blizzard_struct {
-	enum omapfb_update_mode	update_mode;
-	enum omapfb_update_mode	update_mode_before_suspend;
-
-	struct timer_list	auto_update_timer;
-	int			stop_auto_update;
-	struct omapfb_update_window	auto_update_window;
-	int			enabled_planes;
-	int			vid_nonstd_color;
-	int			vid_scaled;
-	int			last_color_mode;
-	int			zoom_on;
-	int			zoom_area_gx1;
-	int			zoom_area_gx2;
-	int			zoom_area_gy1;
-	int			zoom_area_gy2;
-	int			screen_width;
-	int			screen_height;
-	unsigned		te_connected:1;
-	unsigned		vsync_only:1;
-
-	struct plane_info	plane[OMAPFB_PLANE_NUM];
-
-	struct blizzard_request	req_pool[REQ_POOL_SIZE];
-	struct list_head	pending_req_list;
-	struct list_head	free_req_list;
-	struct semaphore	req_sema;
-	spinlock_t		req_lock;
-
-	unsigned long		sys_ck_rate;
-	struct extif_timings	reg_timings, lut_timings;
-
-	u32			max_transmit_size;
-	u32			extif_clk_period;
-	int			extif_clk_div;
-	unsigned long		pix_tx_time;
-	unsigned long		line_upd_time;
-
-	struct omapfb_device	*fbdev;
-	struct lcd_ctrl_extif	*extif;
-	const struct lcd_ctrl	*int_ctrl;
-
-	void			(*power_up)(struct device *dev);
-	void			(*power_down)(struct device *dev);
-
-	int			version;
-} blizzard;
-
-struct lcd_ctrl blizzard_ctrl;
-
-static u8 blizzard_read_reg(u8 reg)
-{
-	u8 data;
-
-	blizzard.extif->set_bits_per_cycle(8);
-	blizzard.extif->write_command(&reg, 1);
-	blizzard.extif->read_data(&data, 1);
-
-	return data;
-}
-
-static void blizzard_write_reg(u8 reg, u8 val)
-{
-	blizzard.extif->set_bits_per_cycle(8);
-	blizzard.extif->write_command(&reg, 1);
-	blizzard.extif->write_data(&val, 1);
-}
-
-static void blizzard_restart_sdram(void)
-{
-	unsigned long tmo;
-
-	blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 0);
-	udelay(50);
-	blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 1);
-	tmo = jiffies + msecs_to_jiffies(200);
-	while (!(blizzard_read_reg(BLIZZARD_MEM_BANK0_STATUS) & 0x01)) {
-		if (time_after(jiffies, tmo)) {
-			dev_err(blizzard.fbdev->dev,
-					"s1d1374x: SDRAM not ready\n");
-			break;
-		}
-		msleep(1);
-	}
-}
-
-static void blizzard_stop_sdram(void)
-{
-	blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 0);
-}
-
-/* Wait until the last window was completely written into the controllers
- * SDRAM and we can start transferring the next window.
- */
-static void blizzard_wait_line_buffer(void)
-{
-	unsigned long tmo = jiffies + msecs_to_jiffies(30);
-
-	while (blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS) & (1 << 7)) {
-		if (time_after(jiffies, tmo)) {
-			if (printk_ratelimit())
-				dev_err(blizzard.fbdev->dev,
-					"s1d1374x: line buffer not ready\n");
-			break;
-		}
-	}
-}
-
-/* Wait until the YYC color space converter is idle. */
-static void blizzard_wait_yyc(void)
-{
-	unsigned long tmo = jiffies + msecs_to_jiffies(30);
-
-	while (blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS) & (1 << 4)) {
-		if (time_after(jiffies, tmo)) {
-			if (printk_ratelimit())
-				dev_err(blizzard.fbdev->dev,
-					"s1d1374x: YYC not ready\n");
-			break;
-		}
-	}
-}
-
-static void disable_overlay(void)
-{
-	blizzard_write_reg(BLIZZARD_DATA_SOURCE_SELECT,
-				BLIZZARD_SRC_DISABLE_OVERLAY);
-}
-
-static void set_window_regs(int x_start, int y_start, int x_end, int y_end,
-			    int x_out_start, int y_out_start,
-			    int x_out_end, int y_out_end, int color_mode,
-			    int zoom_off, int flags)
-{
-	u8 tmp[18];
-	u8 cmd;
-
-	x_end--;
-	y_end--;
-	tmp[0] = x_start;
-	tmp[1] = x_start >> 8;
-	tmp[2] = y_start;
-	tmp[3] = y_start >> 8;
-	tmp[4] = x_end;
-	tmp[5] = x_end >> 8;
-	tmp[6] = y_end;
-	tmp[7] = y_end >> 8;
-
-	x_out_end--;
-	y_out_end--;
-	tmp[8]  = x_out_start;
-	tmp[9]  = x_out_start >> 8;
-	tmp[10] = y_out_start;
-	tmp[11] = y_out_start >> 8;
-	tmp[12] = x_out_end;
-	tmp[13] = x_out_end >> 8;
-	tmp[14] = y_out_end;
-	tmp[15] = y_out_end >> 8;
-
-	tmp[16] = color_mode;
-	if (zoom_off && blizzard.version == BLIZZARD_VERSION_S1D13745)
-		tmp[17] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND;
-	else if (flags & OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY)
-		tmp[17] = BLIZZARD_SRC_WRITE_OVERLAY_ENABLE;
-	else
-		tmp[17] = blizzard.version == BLIZZARD_VERSION_S1D13744 ?
-				BLIZZARD_SRC_WRITE_LCD :
-				BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE;
-
-	blizzard.extif->set_bits_per_cycle(8);
-	cmd = BLIZZARD_INPUT_WIN_X_START_0;
-	blizzard.extif->write_command(&cmd, 1);
-	blizzard.extif->write_data(tmp, 18);
-}
-
-static void enable_tearsync(int y, int width, int height, int screen_height,
-			    int out_height, int force_vsync)
-{
-	u8 b;
-
-	b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS);
-	b |= 1 << 3;
-	blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b);
-
-	if (likely(blizzard.vsync_only || force_vsync)) {
-		blizzard.extif->enable_tearsync(1, 0);
-		return;
-	}
-
-	if (width * blizzard.pix_tx_time < blizzard.line_upd_time) {
-		blizzard.extif->enable_tearsync(1, 0);
-		return;
-	}
-
-	if ((width * blizzard.pix_tx_time / 1000) * height <
-	    (y + out_height) * (blizzard.line_upd_time / 1000)) {
-		blizzard.extif->enable_tearsync(1, 0);
-		return;
-	}
-
-	blizzard.extif->enable_tearsync(1, y + 1);
-}
-
-static void disable_tearsync(void)
-{
-	u8 b;
-
-	blizzard.extif->enable_tearsync(0, 0);
-	b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS);
-	b &= ~(1 << 3);
-	blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b);
-	b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS);
-}
-
-static inline void set_extif_timings(const struct extif_timings *t);
-
-static inline struct blizzard_request *alloc_req(void)
-{
-	unsigned long flags;
-	struct blizzard_request *req;
-	int req_flags = 0;
-
-	if (!in_interrupt())
-		down(&blizzard.req_sema);
-	else
-		req_flags = REQ_FROM_IRQ_POOL;
-
-	spin_lock_irqsave(&blizzard.req_lock, flags);
-	BUG_ON(list_empty(&blizzard.free_req_list));
-	req = list_entry(blizzard.free_req_list.next,
-			 struct blizzard_request, entry);
-	list_del(&req->entry);
-	spin_unlock_irqrestore(&blizzard.req_lock, flags);
-
-	INIT_LIST_HEAD(&req->entry);
-	req->flags = req_flags;
-
-	return req;
-}
-
-static inline void free_req(struct blizzard_request *req)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&blizzard.req_lock, flags);
-
-	list_move(&req->entry, &blizzard.free_req_list);
-	if (!(req->flags & REQ_FROM_IRQ_POOL))
-		up(&blizzard.req_sema);
-
-	spin_unlock_irqrestore(&blizzard.req_lock, flags);
-}
-
-static void process_pending_requests(void)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&blizzard.req_lock, flags);
-
-	while (!list_empty(&blizzard.pending_req_list)) {
-		struct blizzard_request *req;
-		void (*complete)(void *);
-		void *complete_data;
-
-		req = list_entry(blizzard.pending_req_list.next,
-				 struct blizzard_request, entry);
-		spin_unlock_irqrestore(&blizzard.req_lock, flags);
-
-		if (req->handler(req) == REQ_PENDING)
-			return;
-
-		complete = req->complete;
-		complete_data = req->complete_data;
-		free_req(req);
-
-		if (complete)
-			complete(complete_data);
-
-		spin_lock_irqsave(&blizzard.req_lock, flags);
-	}
-
-	spin_unlock_irqrestore(&blizzard.req_lock, flags);
-}
-
-static void submit_req_list(struct list_head *head)
-{
-	unsigned long flags;
-	int process = 1;
-
-	spin_lock_irqsave(&blizzard.req_lock, flags);
-	if (likely(!list_empty(&blizzard.pending_req_list)))
-		process = 0;
-	list_splice_init(head, blizzard.pending_req_list.prev);
-	spin_unlock_irqrestore(&blizzard.req_lock, flags);
-
-	if (process)
-		process_pending_requests();
-}
-
-static void request_complete(void *data)
-{
-	struct blizzard_request	*req = (struct blizzard_request *)data;
-	void			(*complete)(void *);
-	void			*complete_data;
-
-	complete = req->complete;
-	complete_data = req->complete_data;
-
-	free_req(req);
-
-	if (complete)
-		complete(complete_data);
-
-	process_pending_requests();
-}
-
-
-static int do_full_screen_update(struct blizzard_request *req)
-{
-	int i;
-	int flags;
-
-	for (i = 0; i < 3; i++) {
-		struct plane_info *p = &blizzard.plane[i];
-		if (!(blizzard.enabled_planes & (1 << i))) {
-			blizzard.int_ctrl->enable_plane(i, 0);
-			continue;
-		}
-		dev_dbg(blizzard.fbdev->dev, "pw %d ph %d\n",
-			p->width, p->height);
-		blizzard.int_ctrl->setup_plane(i,
-				OMAPFB_CHANNEL_OUT_LCD, p->offset,
-				p->scr_width, p->pos_x, p->pos_y,
-				p->width, p->height,
-				p->color_mode);
-		blizzard.int_ctrl->enable_plane(i, 1);
-	}
-
-	dev_dbg(blizzard.fbdev->dev, "sw %d sh %d\n",
-		blizzard.screen_width, blizzard.screen_height);
-	blizzard_wait_line_buffer();
-	flags = req->par.update.flags;
-	if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC)
-		enable_tearsync(0, blizzard.screen_width,
-				blizzard.screen_height,
-				blizzard.screen_height,
-				blizzard.screen_height,
-				flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC);
-	else
-		disable_tearsync();
-
-	set_window_regs(0, 0, blizzard.screen_width, blizzard.screen_height,
-			0, 0, blizzard.screen_width, blizzard.screen_height,
-			BLIZZARD_COLOR_RGB565, blizzard.zoom_on, flags);
-	blizzard.zoom_on = 0;
-
-	blizzard.extif->set_bits_per_cycle(16);
-	/* set_window_regs has left the register index at the right
-	 * place, so no need to set it here.
-	 */
-	blizzard.extif->transfer_area(blizzard.screen_width,
-				      blizzard.screen_height,
-				      request_complete, req);
-	return REQ_PENDING;
-}
-
-static int check_1d_intersect(int a1, int a2, int b1, int b2)
-{
-	if (a2 <= b1 || b2 <= a1)
-		return 0;
-	return 1;
-}
-
-/* Setup all planes with an overlapping area with the update window. */
-static int do_partial_update(struct blizzard_request *req, int plane,
-			     int x, int y, int w, int h,
-			     int x_out, int y_out, int w_out, int h_out,
-			     int wnd_color_mode, int bpp)
-{
-	int i;
-	int gx1, gy1, gx2, gy2;
-	int gx1_out, gy1_out, gx2_out, gy2_out;
-	int color_mode;
-	int flags;
-	int zoom_off;
-	int have_zoom_for_this_update = 0;
-
-	/* Global coordinates, relative to pixel 0,0 of the LCD */
-	gx1 = x + blizzard.plane[plane].pos_x;
-	gy1 = y + blizzard.plane[plane].pos_y;
-	gx2 = gx1 + w;
-	gy2 = gy1 + h;
-
-	flags = req->par.update.flags;
-	if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) {
-		gx1_out = gx1;
-		gy1_out = gy1;
-		gx2_out = gx1 + w * 2;
-		gy2_out = gy1 + h * 2;
-	} else {
-		gx1_out = x_out + blizzard.plane[plane].pos_x;
-		gy1_out = y_out + blizzard.plane[plane].pos_y;
-		gx2_out = gx1_out + w_out;
-		gy2_out = gy1_out + h_out;
-	}
-
-	for (i = 0; i < OMAPFB_PLANE_NUM; i++) {
-		struct plane_info *p = &blizzard.plane[i];
-		int px1, py1;
-		int px2, py2;
-		int pw, ph;
-		int pposx, pposy;
-		unsigned long offset;
-
-		if (!(blizzard.enabled_planes & (1 << i))  ||
-		    (wnd_color_mode && i != plane)) {
-			blizzard.int_ctrl->enable_plane(i, 0);
-			continue;
-		}
-		/* Plane coordinates */
-		if (i == plane) {
-			/* Plane in which we are doing the update.
-			 * Local coordinates are the one in the update
-			 * request.
-			 */
-			px1 = x;
-			py1 = y;
-			px2 = x + w;
-			py2 = y + h;
-			pposx = 0;
-			pposy = 0;
-		} else {
-			/* Check if this plane has an overlapping part */
-			px1 = gx1 - p->pos_x;
-			py1 = gy1 - p->pos_y;
-			px2 = gx2 - p->pos_x;
-			py2 = gy2 - p->pos_y;
-			if (px1 >= p->width || py1 >= p->height ||
-			    px2 <= 0 || py2 <= 0) {
-				blizzard.int_ctrl->enable_plane(i, 0);
-				continue;
-			}
-			/* Calculate the coordinates for the overlapping
-			 * part in the plane's local coordinates.
-			 */
-			pposx = -px1;
-			pposy = -py1;
-			if (px1 < 0)
-				px1 = 0;
-			if (py1 < 0)
-				py1 = 0;
-			if (px2 > p->width)
-				px2 = p->width;
-			if (py2 > p->height)
-				py2 = p->height;
-			if (pposx < 0)
-				pposx = 0;
-			if (pposy < 0)
-				pposy = 0;
-		}
-		pw = px2 - px1;
-		ph = py2 - py1;
-		offset = p->offset + (p->scr_width * py1 + px1) * p->bpp / 8;
-		if (wnd_color_mode)
-			/* Window embedded in the plane with a differing
-			 * color mode / bpp. Calculate the number of DMA
-			 * transfer elements in terms of the plane's bpp.
-			 */
-			pw = (pw + 1) * bpp / p->bpp;
-#ifdef VERBOSE
-		dev_dbg(blizzard.fbdev->dev,
-			"plane %d offset %#08lx pposx %d pposy %d "
-			"px1 %d py1 %d pw %d ph %d\n",
-			i, offset, pposx, pposy, px1, py1, pw, ph);
-#endif
-		blizzard.int_ctrl->setup_plane(i,
-				OMAPFB_CHANNEL_OUT_LCD, offset,
-				p->scr_width,
-				pposx, pposy, pw, ph,
-				p->color_mode);
-
-		blizzard.int_ctrl->enable_plane(i, 1);
-	}
-
-	switch (wnd_color_mode) {
-	case OMAPFB_COLOR_YUV420:
-		color_mode = BLIZZARD_COLOR_YUV420;
-		/* Currently only the 16 bits/pixel cycle format is
-		 * supported on the external interface. Adjust the number
-		 * of transfer elements per line for 12bpp format.
-		 */
-		w = (w + 1) * 3 / 4;
-		break;
-	default:
-		color_mode = BLIZZARD_COLOR_RGB565;
-		break;
-	}
-
-	blizzard_wait_line_buffer();
-	if (blizzard.last_color_mode == BLIZZARD_COLOR_YUV420)
-		blizzard_wait_yyc();
-	blizzard.last_color_mode = color_mode;
-	if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC)
-		enable_tearsync(gy1, w, h,
-				blizzard.screen_height,
-				h_out,
-				flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC);
-	else
-		disable_tearsync();
-
-	if ((gx2_out - gx1_out) != (gx2 - gx1) ||
-	    (gy2_out - gy1_out) != (gy2 - gy1))
-		have_zoom_for_this_update = 1;
-
-	/* 'background' type of screen update (as opposed to 'destructive')
-	   can be used to disable scaling if scaling is active */
-	zoom_off = blizzard.zoom_on && !have_zoom_for_this_update &&
-	    (gx1_out == 0) && (gx2_out == blizzard.screen_width) &&
-	    (gy1_out == 0) && (gy2_out == blizzard.screen_height) &&
-	    (gx1 == 0) && (gy1 == 0);
-
-	if (blizzard.zoom_on && !have_zoom_for_this_update && !zoom_off &&
-	    check_1d_intersect(blizzard.zoom_area_gx1, blizzard.zoom_area_gx2,
-			       gx1_out, gx2_out) &&
-	    check_1d_intersect(blizzard.zoom_area_gy1, blizzard.zoom_area_gy2,
-			       gy1_out, gy2_out)) {
-		/* Previous screen update was using scaling, current update
-		 * is not using it. Additionally, current screen update is
-		 * going to overlap with the scaled area. Scaling needs to be
-		 * disabled in order to avoid 'magnifying glass' effect.
-		 * Dummy setup of background window can be used for this.
-		 */
-		set_window_regs(0, 0, blizzard.screen_width,
-				blizzard.screen_height,
-				0, 0, blizzard.screen_width,
-				blizzard.screen_height,
-				BLIZZARD_COLOR_RGB565, 1, flags);
-		blizzard.zoom_on = 0;
-	}
-
-	/* remember scaling settings if we have scaled update */
-	if (have_zoom_for_this_update) {
-		blizzard.zoom_on = 1;
-		blizzard.zoom_area_gx1 = gx1_out;
-		blizzard.zoom_area_gx2 = gx2_out;
-		blizzard.zoom_area_gy1 = gy1_out;
-		blizzard.zoom_area_gy2 = gy2_out;
-	}
-
-	set_window_regs(gx1, gy1, gx2, gy2, gx1_out, gy1_out, gx2_out, gy2_out,
-			color_mode, zoom_off, flags);
-	if (zoom_off)
-		blizzard.zoom_on = 0;
-
-	blizzard.extif->set_bits_per_cycle(16);
-	/* set_window_regs has left the register index at the right
-	 * place, so no need to set it here.
-	 */
-	blizzard.extif->transfer_area(w, h, request_complete, req);
-
-	return REQ_PENDING;
-}
-
-static int send_frame_handler(struct blizzard_request *req)
-{
-	struct update_param *par = &req->par.update;
-	int plane = par->plane;
-
-#ifdef VERBOSE
-	dev_dbg(blizzard.fbdev->dev,
-		"send_frame: x %d y %d w %d h %d "
-		"x_out %d y_out %d w_out %d h_out %d "
-		"color_mode %04x flags %04x planes %01x\n",
-		par->x, par->y, par->width, par->height,
-		par->out_x, par->out_y, par->out_width, par->out_height,
-		par->color_mode, par->flags, blizzard.enabled_planes);
-#endif
-	if (par->flags & OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY)
-		disable_overlay();
-
-	if ((blizzard.enabled_planes & blizzard.vid_nonstd_color) ||
-	     (blizzard.enabled_planes & blizzard.vid_scaled))
-		return do_full_screen_update(req);
-
-	return do_partial_update(req, plane, par->x, par->y,
-				 par->width, par->height,
-				 par->out_x, par->out_y,
-				 par->out_width, par->out_height,
-				 par->color_mode, par->bpp);
-}
-
-static void send_frame_complete(void *data)
-{
-}
-
-#define ADD_PREQ(_x, _y, _w, _h, _x_out, _y_out, _w_out, _h_out) do {	\
-	req = alloc_req();			\
-	req->handler	= send_frame_handler;	\
-	req->complete	= send_frame_complete;	\
-	req->par.update.plane = plane_idx;	\
-	req->par.update.x = _x;			\
-	req->par.update.y = _y;			\
-	req->par.update.width  = _w;		\
-	req->par.update.height = _h;		\
-	req->par.update.out_x = _x_out;		\
-	req->par.update.out_y = _y_out;		\
-	req->par.update.out_width = _w_out;	\
-	req->par.update.out_height = _h_out;	\
-	req->par.update.bpp = bpp;		\
-	req->par.update.color_mode = color_mode;\
-	req->par.update.flags	  = flags;	\
-	list_add_tail(&req->entry, req_head);	\
-} while(0)
-
-static void create_req_list(int plane_idx,
-			    struct omapfb_update_window *win,
-			    struct list_head *req_head)
-{
-	struct blizzard_request *req;
-	int x = win->x;
-	int y = win->y;
-	int width = win->width;
-	int height = win->height;
-	int x_out = win->out_x;
-	int y_out = win->out_y;
-	int width_out = win->out_width;
-	int height_out = win->out_height;
-	int color_mode;
-	int bpp;
-	int flags;
-	unsigned int ystart = y;
-	unsigned int yspan = height;
-	unsigned int ystart_out = y_out;
-	unsigned int yspan_out = height_out;
-
-	flags = win->format & ~OMAPFB_FORMAT_MASK;
-	color_mode = win->format & OMAPFB_FORMAT_MASK;
-	switch (color_mode) {
-	case OMAPFB_COLOR_YUV420:
-		/* Embedded window with different color mode */
-		bpp = 12;
-		/* X, Y, height must be aligned at 2, width at 4 pixels */
-		x &= ~1;
-		y &= ~1;
-		height = yspan = height & ~1;
-		width = width & ~3;
-		break;
-	default:
-		/* Same as the plane color mode */
-		bpp = blizzard.plane[plane_idx].bpp;
-		break;
-	}
-	if (width * height * bpp / 8 > blizzard.max_transmit_size) {
-		yspan = blizzard.max_transmit_size / (width * bpp / 8);
-		yspan_out = yspan * height_out / height;
-		ADD_PREQ(x, ystart, width, yspan, x_out, ystart_out,
-			 width_out, yspan_out);
-		ystart += yspan;
-		ystart_out += yspan_out;
-		yspan = height - yspan;
-		yspan_out = height_out - yspan_out;
-		flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC;
-	}
-
-	ADD_PREQ(x, ystart, width, yspan, x_out, ystart_out,
-		 width_out, yspan_out);
-}
-
-static void auto_update_complete(void *data)
-{
-	if (!blizzard.stop_auto_update)
-		mod_timer(&blizzard.auto_update_timer,
-			  jiffies + BLIZZARD_AUTO_UPDATE_TIME);
-}
-
-static void blizzard_update_window_auto(unsigned long arg)
-{
-	LIST_HEAD(req_list);
-	struct blizzard_request *last;
-	struct omapfb_plane_struct *plane;
-
-	plane = blizzard.fbdev->fb_info[0]->par;
-	create_req_list(plane->idx,
-			&blizzard.auto_update_window, &req_list);
-	last = list_entry(req_list.prev, struct blizzard_request, entry);
-
-	last->complete = auto_update_complete;
-	last->complete_data = NULL;
-
-	submit_req_list(&req_list);
-}
-
-int blizzard_update_window_async(struct fb_info *fbi,
-				 struct omapfb_update_window *win,
-				 void (*complete_callback)(void *arg),
-				 void *complete_callback_data)
-{
-	LIST_HEAD(req_list);
-	struct blizzard_request *last;
-	struct omapfb_plane_struct *plane = fbi->par;
-
-	if (unlikely(blizzard.update_mode != OMAPFB_MANUAL_UPDATE))
-		return -EINVAL;
-	if (unlikely(!blizzard.te_connected &&
-		     (win->format & OMAPFB_FORMAT_FLAG_TEARSYNC)))
-		return -EINVAL;
-
-	create_req_list(plane->idx, win, &req_list);
-	last = list_entry(req_list.prev, struct blizzard_request, entry);
-
-	last->complete = complete_callback;
-	last->complete_data = (void *)complete_callback_data;
-
-	submit_req_list(&req_list);
-
-	return 0;
-}
-EXPORT_SYMBOL(blizzard_update_window_async);
-
-static int update_full_screen(void)
-{
-	return blizzard_update_window_async(blizzard.fbdev->fb_info[0],
-				     &blizzard.auto_update_window, NULL, NULL);
-
-}
-
-static int blizzard_setup_plane(int plane, int channel_out,
-				  unsigned long offset, int screen_width,
-				  int pos_x, int pos_y, int width, int height,
-				  int color_mode)
-{
-	struct plane_info *p;
-
-#ifdef VERBOSE
-	dev_dbg(blizzard.fbdev->dev,
-		    "plane %d ch_out %d offset %#08lx scr_width %d "
-		    "pos_x %d pos_y %d width %d height %d color_mode %d\n",
-		    plane, channel_out, offset, screen_width,
-		    pos_x, pos_y, width, height, color_mode);
-#endif
-	if ((unsigned)plane > OMAPFB_PLANE_NUM)
-		return -EINVAL;
-	p = &blizzard.plane[plane];
-
-	switch (color_mode) {
-	case OMAPFB_COLOR_YUV422:
-	case OMAPFB_COLOR_YUY422:
-		p->bpp = 16;
-		blizzard.vid_nonstd_color &= ~(1 << plane);
-		break;
-	case OMAPFB_COLOR_YUV420:
-		p->bpp = 12;
-		blizzard.vid_nonstd_color |= 1 << plane;
-		break;
-	case OMAPFB_COLOR_RGB565:
-		p->bpp = 16;
-		blizzard.vid_nonstd_color &= ~(1 << plane);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	p->offset = offset;
-	p->pos_x = pos_x;
-	p->pos_y = pos_y;
-	p->width = width;
-	p->height = height;
-	p->scr_width = screen_width;
-	if (!p->out_width)
-		p->out_width = width;
-	if (!p->out_height)
-		p->out_height = height;
-
-	p->color_mode = color_mode;
-
-	return 0;
-}
-
-static int blizzard_set_scale(int plane, int orig_w, int orig_h,
-			      int out_w, int out_h)
-{
-	struct plane_info *p = &blizzard.plane[plane];
-	int r;
-
-	dev_dbg(blizzard.fbdev->dev,
-		"plane %d orig_w %d orig_h %d out_w %d out_h %d\n",
-		plane, orig_w, orig_h, out_w, out_h);
-	if ((unsigned)plane > OMAPFB_PLANE_NUM)
-		return -ENODEV;
-
-	r = blizzard.int_ctrl->set_scale(plane, orig_w, orig_h, out_w, out_h);
-	if (r < 0)
-		return r;
-
-	p->width = orig_w;
-	p->height = orig_h;
-	p->out_width = out_w;
-	p->out_height = out_h;
-	if (orig_w == out_w && orig_h == out_h)
-		blizzard.vid_scaled &= ~(1 << plane);
-	else
-		blizzard.vid_scaled |= 1 << plane;
-
-	return 0;
-}
-
-static int blizzard_set_rotate(int angle)
-{
-	u32 l;
-
-	l = blizzard_read_reg(BLIZZARD_PANEL_CONFIGURATION);
-	l &= ~0x03;
-
-	switch (angle) {
-	case 0:
-		l = l | 0x00;
-		break;
-	case 90:
-		l = l | 0x03;
-		break;
-	case 180:
-		l = l | 0x02;
-		break;
-	case 270:
-		l = l | 0x01;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	blizzard_write_reg(BLIZZARD_PANEL_CONFIGURATION, l);
-
-	return 0;
-}
-
-static int blizzard_enable_plane(int plane, int enable)
-{
-	if (enable)
-		blizzard.enabled_planes |= 1 << plane;
-	else
-		blizzard.enabled_planes &= ~(1 << plane);
-
-	return 0;
-}
-
-static int sync_handler(struct blizzard_request *req)
-{
-	complete(req->par.sync);
-	return REQ_COMPLETE;
-}
-
-static void blizzard_sync(void)
-{
-	LIST_HEAD(req_list);
-	struct blizzard_request *req;
-	struct completion comp;
-
-	req = alloc_req();
-
-	req->handler = sync_handler;
-	req->complete = NULL;
-	init_completion(&comp);
-	req->par.sync = &comp;
-
-	list_add(&req->entry, &req_list);
-	submit_req_list(&req_list);
-
-	wait_for_completion(&comp);
-}
-
-
-static void blizzard_bind_client(struct omapfb_notifier_block *nb)
-{
-	if (blizzard.update_mode == OMAPFB_MANUAL_UPDATE) {
-		omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_READY);
-	}
-}
-
-static int blizzard_set_update_mode(enum omapfb_update_mode mode)
-{
-	if (unlikely(mode != OMAPFB_MANUAL_UPDATE &&
-		     mode != OMAPFB_AUTO_UPDATE &&
-		     mode != OMAPFB_UPDATE_DISABLED))
-		return -EINVAL;
-
-	if (mode == blizzard.update_mode)
-		return 0;
-
-	dev_info(blizzard.fbdev->dev, "s1d1374x: setting update mode to %s\n",
-			mode == OMAPFB_UPDATE_DISABLED ? "disabled" :
-			(mode == OMAPFB_AUTO_UPDATE ? "auto" : "manual"));
-
-	switch (blizzard.update_mode) {
-	case OMAPFB_MANUAL_UPDATE:
-		omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_DISABLED);
-		break;
-	case OMAPFB_AUTO_UPDATE:
-		blizzard.stop_auto_update = 1;
-		del_timer_sync(&blizzard.auto_update_timer);
-		break;
-	case OMAPFB_UPDATE_DISABLED:
-		break;
-	}
-
-	blizzard.update_mode = mode;
-	blizzard_sync();
-	blizzard.stop_auto_update = 0;
-
-	switch (mode) {
-	case OMAPFB_MANUAL_UPDATE:
-		omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_READY);
-		break;
-	case OMAPFB_AUTO_UPDATE:
-		blizzard_update_window_auto(0);
-		break;
-	case OMAPFB_UPDATE_DISABLED:
-		break;
-	}
-
-	return 0;
-}
-
-static enum omapfb_update_mode blizzard_get_update_mode(void)
-{
-	return blizzard.update_mode;
-}
-
-static inline void set_extif_timings(const struct extif_timings *t)
-{
-	blizzard.extif->set_timings(t);
-}
-
-static inline unsigned long round_to_extif_ticks(unsigned long ps, int div)
-{
-	int bus_tick = blizzard.extif_clk_period * div;
-	return (ps + bus_tick - 1) / bus_tick * bus_tick;
-}
-
-static int calc_reg_timing(unsigned long sysclk, int div)
-{
-	struct extif_timings *t;
-	unsigned long systim;
-
-	/* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns,
-	 * AccessTime 2 ns + 12.2 ns (regs),
-	 * WEOffTime = WEOnTime + 1 ns,
-	 * REOffTime = REOnTime + 12 ns (regs),
-	 * CSOffTime = REOffTime + 1 ns
-	 * ReadCycle = 2ns + 2*SYSCLK  (regs),
-	 * WriteCycle = 2*SYSCLK + 2 ns,
-	 * CSPulseWidth = 10 ns */
-
-	systim = 1000000000 / (sysclk / 1000);
-	dev_dbg(blizzard.fbdev->dev,
-		  "Blizzard systim %lu ps extif_clk_period %u div %d\n",
-		  systim, blizzard.extif_clk_period, div);
-
-	t = &blizzard.reg_timings;
-	memset(t, 0, sizeof(*t));
-
-	t->clk_div = div;
-
-	t->cs_on_time = 0;
-	t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
-	t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
-	t->access_time = round_to_extif_ticks(t->re_on_time + 12200, div);
-	t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div);
-	t->re_off_time = round_to_extif_ticks(t->re_on_time + 13000, div);
-	t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div);
-	t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
-	if (t->we_cycle_time < t->we_off_time)
-		t->we_cycle_time = t->we_off_time;
-	t->re_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
-	if (t->re_cycle_time < t->re_off_time)
-		t->re_cycle_time = t->re_off_time;
-	t->cs_pulse_width = 0;
-
-	dev_dbg(blizzard.fbdev->dev, "[reg]cson %d csoff %d reon %d reoff %d\n",
-		 t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
-	dev_dbg(blizzard.fbdev->dev, "[reg]weon %d weoff %d recyc %d wecyc %d\n",
-		 t->we_on_time, t->we_off_time, t->re_cycle_time,
-		 t->we_cycle_time);
-	dev_dbg(blizzard.fbdev->dev, "[reg]rdaccess %d cspulse %d\n",
-		 t->access_time, t->cs_pulse_width);
-
-	return blizzard.extif->convert_timings(t);
-}
-
-static int calc_lut_timing(unsigned long sysclk, int div)
-{
-	struct extif_timings *t;
-	unsigned long systim;
-
-	/* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns,
-	 * AccessTime 2 ns + 4 * SYSCLK + 26 (lut),
-	 * WEOffTime = WEOnTime + 1 ns,
-	 * REOffTime = REOnTime + 4*SYSCLK + 26 ns (lut),
-	 * CSOffTime = REOffTime + 1 ns
-	 * ReadCycle = 2ns + 4*SYSCLK + 26 ns (lut),
-	 * WriteCycle = 2*SYSCLK + 2 ns,
-	 * CSPulseWidth = 10 ns */
-
-	systim = 1000000000 / (sysclk / 1000);
-	dev_dbg(blizzard.fbdev->dev,
-		"Blizzard systim %lu ps extif_clk_period %u div %d\n",
-		systim, blizzard.extif_clk_period, div);
-
-	t = &blizzard.lut_timings;
-	memset(t, 0, sizeof(*t));
-
-	t->clk_div = div;
-
-	t->cs_on_time = 0;
-	t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
-	t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
-	t->access_time = round_to_extif_ticks(t->re_on_time + 4 * systim +
-					      26000, div);
-	t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div);
-	t->re_off_time = round_to_extif_ticks(t->re_on_time + 4 * systim +
-					      26000, div);
-	t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div);
-	t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
-	if (t->we_cycle_time < t->we_off_time)
-		t->we_cycle_time = t->we_off_time;
-	t->re_cycle_time = round_to_extif_ticks(2000 + 4 * systim + 26000, div);
-	if (t->re_cycle_time < t->re_off_time)
-		t->re_cycle_time = t->re_off_time;
-	t->cs_pulse_width = 0;
-
-	dev_dbg(blizzard.fbdev->dev,
-		 "[lut]cson %d csoff %d reon %d reoff %d\n",
-		 t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
-	dev_dbg(blizzard.fbdev->dev,
-		 "[lut]weon %d weoff %d recyc %d wecyc %d\n",
-		 t->we_on_time, t->we_off_time, t->re_cycle_time,
-		 t->we_cycle_time);
-	dev_dbg(blizzard.fbdev->dev, "[lut]rdaccess %d cspulse %d\n",
-		 t->access_time, t->cs_pulse_width);
-
-	return blizzard.extif->convert_timings(t);
-}
-
-static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div)
-{
-	int max_clk_div;
-	int div;
-
-	blizzard.extif->get_clk_info(&blizzard.extif_clk_period, &max_clk_div);
-	for (div = 1; div <= max_clk_div; div++) {
-		if (calc_reg_timing(sysclk, div) == 0)
-			break;
-	}
-	if (div > max_clk_div) {
-		dev_dbg(blizzard.fbdev->dev, "reg timing failed\n");
-		goto err;
-	}
-	*extif_mem_div = div;
-
-	for (div = 1; div <= max_clk_div; div++) {
-		if (calc_lut_timing(sysclk, div) == 0)
-			break;
-	}
-
-	if (div > max_clk_div)
-		goto err;
-
-	blizzard.extif_clk_div = div;
-
-	return 0;
-err:
-	dev_err(blizzard.fbdev->dev, "can't setup timings\n");
-	return -1;
-}
-
-static void calc_blizzard_clk_rates(unsigned long ext_clk,
-				unsigned long *sys_clk, unsigned long *pix_clk)
-{
-	int pix_clk_src;
-	int sys_div = 0, sys_mul = 0;
-	int pix_div;
-
-	pix_clk_src = blizzard_read_reg(BLIZZARD_CLK_SRC);
-	pix_div = ((pix_clk_src >> 3) & 0x1f) + 1;
-	if ((pix_clk_src & (0x3 << 1)) == 0) {
-		/* Source is the PLL */
-		sys_div = (blizzard_read_reg(BLIZZARD_PLL_DIV) & 0x3f) + 1;
-		sys_mul = blizzard_read_reg(BLIZZARD_PLL_CLOCK_SYNTH_0);
-		sys_mul |= ((blizzard_read_reg(BLIZZARD_PLL_CLOCK_SYNTH_1)
-				& 0x0f)	<< 11);
-		*sys_clk = ext_clk * sys_mul / sys_div;
-	} else	/* else source is ext clk, or oscillator */
-		*sys_clk = ext_clk;
-
-	*pix_clk = *sys_clk / pix_div;			/* HZ */
-	dev_dbg(blizzard.fbdev->dev,
-		"ext_clk %ld pix_src %d pix_div %d sys_div %d sys_mul %d\n",
-		ext_clk, pix_clk_src & (0x3 << 1), pix_div, sys_div, sys_mul);
-	dev_dbg(blizzard.fbdev->dev, "sys_clk %ld pix_clk %ld\n",
-		*sys_clk, *pix_clk);
-}
-
-static int setup_tearsync(unsigned long pix_clk, int extif_div)
-{
-	int hdisp, vdisp;
-	int hndp, vndp;
-	int hsw, vsw;
-	int hs, vs;
-	int hs_pol_inv, vs_pol_inv;
-	int use_hsvs, use_ndp;
-	u8  b;
-
-	hsw = blizzard_read_reg(BLIZZARD_HSW);
-	vsw = blizzard_read_reg(BLIZZARD_VSW);
-	hs_pol_inv = !(hsw & 0x80);
-	vs_pol_inv = !(vsw & 0x80);
-	hsw = hsw & 0x7f;
-	vsw = vsw & 0x3f;
-
-	hdisp = blizzard_read_reg(BLIZZARD_HDISP) * 8;
-	vdisp = blizzard_read_reg(BLIZZARD_VDISP0) +
-		((blizzard_read_reg(BLIZZARD_VDISP1) & 0x3) << 8);
-
-	hndp = blizzard_read_reg(BLIZZARD_HNDP) & 0x3f;
-	vndp = blizzard_read_reg(BLIZZARD_VNDP);
-
-	/* time to transfer one pixel (16bpp) in ps */
-	blizzard.pix_tx_time = blizzard.reg_timings.we_cycle_time;
-	if (blizzard.extif->get_max_tx_rate != NULL) {
-		/* The external interface might have a rate limitation,
-		 * if so, we have to maximize our transfer rate.
-		 */
-		unsigned long min_tx_time;
-		unsigned long max_tx_rate = blizzard.extif->get_max_tx_rate();
-
-		dev_dbg(blizzard.fbdev->dev, "max_tx_rate %ld HZ\n",
-			max_tx_rate);
-		min_tx_time = 1000000000 / (max_tx_rate / 1000);  /* ps */
-		if (blizzard.pix_tx_time < min_tx_time)
-			blizzard.pix_tx_time = min_tx_time;
-	}
-
-	/* time to update one line in ps */
-	blizzard.line_upd_time = (hdisp + hndp) * 1000000 / (pix_clk / 1000);
-	blizzard.line_upd_time *= 1000;
-	if (hdisp * blizzard.pix_tx_time > blizzard.line_upd_time)
-		/* transfer speed too low, we might have to use both
-		 * HS and VS */
-		use_hsvs = 1;
-	else
-		/* decent transfer speed, we'll always use only VS */
-		use_hsvs = 0;
-
-	if (use_hsvs && (hs_pol_inv || vs_pol_inv)) {
-		/* HS or'ed with VS doesn't work, use the active high
-		 * TE signal based on HNDP / VNDP */
-		use_ndp = 1;
-		hs_pol_inv = 0;
-		vs_pol_inv = 0;
-		hs = hndp;
-		vs = vndp;
-	} else {
-		/* Use HS or'ed with VS as a TE signal if both are needed
-		 * or VNDP if only vsync is needed. */
-		use_ndp = 0;
-		hs = hsw;
-		vs = vsw;
-		if (!use_hsvs) {
-			hs_pol_inv = 0;
-			vs_pol_inv = 0;
-		}
-	}
-
-	hs = hs * 1000000 / (pix_clk / 1000);		  /* ps */
-	hs *= 1000;
-
-	vs = vs * (hdisp + hndp) * 1000000 / (pix_clk / 1000); /* ps */
-	vs *= 1000;
-
-	if (vs <= hs)
-		return -EDOM;
-	/* set VS to 120% of HS to minimize VS detection time */
-	vs = hs * 12 / 10;
-	/* minimize HS too */
-	if (hs > 10000)
-		hs = 10000;
-
-	b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS);
-	b &= ~0x3;
-	b |= use_hsvs ? 1 : 0;
-	b |= (use_ndp && use_hsvs) ? 0 : 2;
-	blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b);
-
-	blizzard.vsync_only = !use_hsvs;
-
-	dev_dbg(blizzard.fbdev->dev,
-		"pix_clk %ld HZ pix_tx_time %ld ps line_upd_time %ld ps\n",
-		pix_clk, blizzard.pix_tx_time, blizzard.line_upd_time);
-	dev_dbg(blizzard.fbdev->dev,
-		"hs %d ps vs %d ps mode %d vsync_only %d\n",
-		hs, vs, b & 0x3, !use_hsvs);
-
-	return blizzard.extif->setup_tearsync(1, hs, vs,
-					      hs_pol_inv, vs_pol_inv,
-					      extif_div);
-}
-
-static void blizzard_get_caps(int plane, struct omapfb_caps *caps)
-{
-	blizzard.int_ctrl->get_caps(plane, caps);
-	caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE |
-		OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE |
-		OMAPFB_CAPS_WINDOW_SCALE |
-		OMAPFB_CAPS_WINDOW_OVERLAY |
-		OMAPFB_CAPS_WINDOW_ROTATE;
-	if (blizzard.te_connected)
-		caps->ctrl |= OMAPFB_CAPS_TEARSYNC;
-	caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) |
-			   (1 << OMAPFB_COLOR_YUV420);
-}
-
-static void _save_regs(const struct blizzard_reg_list *list, int cnt)
-{
-	int i;
-
-	for (i = 0; i < cnt; i++, list++) {
-		int reg;
-		for (reg = list->start; reg <= list->end; reg += 2)
-			blizzard_reg_cache[reg / 2] = blizzard_read_reg(reg);
-	}
-}
-
-static void _restore_regs(const struct blizzard_reg_list *list, int cnt)
-{
-	int i;
-
-	for (i = 0; i < cnt; i++, list++) {
-		int reg;
-		for (reg = list->start; reg <= list->end; reg += 2)
-			blizzard_write_reg(reg, blizzard_reg_cache[reg / 2]);
-	}
-}
-
-static void blizzard_save_all_regs(void)
-{
-	_save_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs));
-	_save_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs));
-}
-
-static void blizzard_restore_pll_regs(void)
-{
-	_restore_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs));
-}
-
-static void blizzard_restore_gen_regs(void)
-{
-	_restore_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs));
-}
-
-static void blizzard_suspend(void)
-{
-	u32 l;
-	unsigned long tmo;
-
-	if (blizzard.last_color_mode) {
-		update_full_screen();
-		blizzard_sync();
-	}
-	blizzard.update_mode_before_suspend = blizzard.update_mode;
-	/* the following will disable clocks as well */
-	blizzard_set_update_mode(OMAPFB_UPDATE_DISABLED);
-
-	blizzard_save_all_regs();
-
-	blizzard_stop_sdram();
-
-	l = blizzard_read_reg(BLIZZARD_POWER_SAVE);
-	/* Standby, Sleep. We assume we use an external clock. */
-	l |= 0x03;
-	blizzard_write_reg(BLIZZARD_POWER_SAVE, l);
-
-	tmo = jiffies + msecs_to_jiffies(100);
-	while (!(blizzard_read_reg(BLIZZARD_PLL_MODE) & (1 << 1))) {
-		if (time_after(jiffies, tmo)) {
-			dev_err(blizzard.fbdev->dev,
-				"s1d1374x: sleep timeout, stopping PLL manually\n");
-			l = blizzard_read_reg(BLIZZARD_PLL_MODE);
-			l &= ~0x03;
-			/* Disable PLL, counter function */
-			l |= 0x2;
-			blizzard_write_reg(BLIZZARD_PLL_MODE, l);
-			break;
-		}
-		msleep(1);
-	}
-
-	if (blizzard.power_down != NULL)
-		blizzard.power_down(blizzard.fbdev->dev);
-}
-
-static void blizzard_resume(void)
-{
-	u32 l;
-
-	if (blizzard.power_up != NULL)
-		blizzard.power_up(blizzard.fbdev->dev);
-
-	l = blizzard_read_reg(BLIZZARD_POWER_SAVE);
-	/* Standby, Sleep */
-	l &= ~0x03;
-	blizzard_write_reg(BLIZZARD_POWER_SAVE, l);
-
-	blizzard_restore_pll_regs();
-	l = blizzard_read_reg(BLIZZARD_PLL_MODE);
-	l &= ~0x03;
-	/* Enable PLL, counter function */
-	l |= 0x1;
-	blizzard_write_reg(BLIZZARD_PLL_MODE, l);
-
-	while (!(blizzard_read_reg(BLIZZARD_PLL_DIV) & (1 << 7)))
-		msleep(1);
-
-	blizzard_restart_sdram();
-
-	blizzard_restore_gen_regs();
-
-	/* Enable display */
-	blizzard_write_reg(BLIZZARD_DISPLAY_MODE, 0x01);
-
-	/* the following will enable clocks as necessary */
-	blizzard_set_update_mode(blizzard.update_mode_before_suspend);
-
-	/* Force a background update */
-	blizzard.zoom_on = 1;
-	update_full_screen();
-	blizzard_sync();
-}
-
-static int blizzard_init(struct omapfb_device *fbdev, int ext_mode,
-			 struct omapfb_mem_desc *req_vram)
-{
-	int r = 0, i;
-	u8 rev, conf;
-	unsigned long ext_clk;
-	int extif_div;
-	unsigned long sys_clk, pix_clk;
-	struct omapfb_platform_data *omapfb_conf;
-	struct blizzard_platform_data *ctrl_conf;
-
-	blizzard.fbdev = fbdev;
-
-	BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl);
-
-	blizzard.fbdev = fbdev;
-	blizzard.extif = fbdev->ext_if;
-	blizzard.int_ctrl = fbdev->int_ctrl;
-
-	omapfb_conf = fbdev->dev->platform_data;
-	ctrl_conf = omapfb_conf->ctrl_platform_data;
-	if (ctrl_conf == NULL || ctrl_conf->get_clock_rate == NULL) {
-		dev_err(fbdev->dev, "s1d1374x: missing platform data\n");
-		r = -ENOENT;
-		goto err1;
-	}
-
-	blizzard.power_down = ctrl_conf->power_down;
-	blizzard.power_up = ctrl_conf->power_up;
-
-	spin_lock_init(&blizzard.req_lock);
-
-	if ((r = blizzard.int_ctrl->init(fbdev, 1, req_vram)) < 0)
-		goto err1;
-
-	if ((r = blizzard.extif->init(fbdev)) < 0)
-		goto err2;
-
-	blizzard_ctrl.set_color_key = blizzard.int_ctrl->set_color_key;
-	blizzard_ctrl.get_color_key = blizzard.int_ctrl->get_color_key;
-	blizzard_ctrl.setup_mem = blizzard.int_ctrl->setup_mem;
-	blizzard_ctrl.mmap = blizzard.int_ctrl->mmap;
-
-	ext_clk = ctrl_conf->get_clock_rate(fbdev->dev);
-	if ((r = calc_extif_timings(ext_clk, &extif_div)) < 0)
-		goto err3;
-
-	set_extif_timings(&blizzard.reg_timings);
-
-	if (blizzard.power_up != NULL)
-		blizzard.power_up(fbdev->dev);
-
-	calc_blizzard_clk_rates(ext_clk, &sys_clk, &pix_clk);
-
-	if ((r = calc_extif_timings(sys_clk, &extif_div)) < 0)
-		goto err3;
-	set_extif_timings(&blizzard.reg_timings);
-
-	if (!(blizzard_read_reg(BLIZZARD_PLL_DIV) & 0x80)) {
-		dev_err(fbdev->dev,
-			"controller not initialized by the bootloader\n");
-		r = -ENODEV;
-		goto err3;
-	}
-
-	if (ctrl_conf->te_connected) {
-		if ((r = setup_tearsync(pix_clk, extif_div)) < 0)
-			goto err3;
-		blizzard.te_connected = 1;
-	}
-
-	rev = blizzard_read_reg(BLIZZARD_REV_CODE);
-	conf = blizzard_read_reg(BLIZZARD_CONFIG);
-
-	switch (rev & 0xfc) {
-	case 0x9c:
-		blizzard.version = BLIZZARD_VERSION_S1D13744;
-		pr_info("omapfb: s1d13744 LCD controller rev %d "
-			"initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
-		break;
-	case 0xa4:
-		blizzard.version = BLIZZARD_VERSION_S1D13745;
-		pr_info("omapfb: s1d13745 LCD controller rev %d "
-			"initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
-		break;
-	default:
-		dev_err(fbdev->dev, "invalid s1d1374x revision %02x\n",
-			rev);
-		r = -ENODEV;
-		goto err3;
-	}
-
-	blizzard.max_transmit_size = blizzard.extif->max_transmit_size;
-
-	blizzard.update_mode = OMAPFB_UPDATE_DISABLED;
-
-	blizzard.auto_update_window.x = 0;
-	blizzard.auto_update_window.y = 0;
-	blizzard.auto_update_window.width = fbdev->panel->x_res;
-	blizzard.auto_update_window.height = fbdev->panel->y_res;
-	blizzard.auto_update_window.out_x = 0;
-	blizzard.auto_update_window.out_y = 0;
-	blizzard.auto_update_window.out_width = fbdev->panel->x_res;
-	blizzard.auto_update_window.out_height = fbdev->panel->y_res;
-	blizzard.auto_update_window.format = 0;
-
-	blizzard.screen_width = fbdev->panel->x_res;
-	blizzard.screen_height = fbdev->panel->y_res;
-
-	init_timer(&blizzard.auto_update_timer);
-	blizzard.auto_update_timer.function = blizzard_update_window_auto;
-	blizzard.auto_update_timer.data = 0;
-
-	INIT_LIST_HEAD(&blizzard.free_req_list);
-	INIT_LIST_HEAD(&blizzard.pending_req_list);
-	for (i = 0; i < ARRAY_SIZE(blizzard.req_pool); i++)
-		list_add(&blizzard.req_pool[i].entry, &blizzard.free_req_list);
-	BUG_ON(i <= IRQ_REQ_POOL_SIZE);
-	sema_init(&blizzard.req_sema, i - IRQ_REQ_POOL_SIZE);
-
-	return 0;
-err3:
-	if (blizzard.power_down != NULL)
-		blizzard.power_down(fbdev->dev);
-	blizzard.extif->cleanup();
-err2:
-	blizzard.int_ctrl->cleanup();
-err1:
-	return r;
-}
-
-static void blizzard_cleanup(void)
-{
-	blizzard_set_update_mode(OMAPFB_UPDATE_DISABLED);
-	blizzard.extif->cleanup();
-	blizzard.int_ctrl->cleanup();
-	if (blizzard.power_down != NULL)
-		blizzard.power_down(blizzard.fbdev->dev);
-}
-
-struct lcd_ctrl blizzard_ctrl = {
-	.name			= "blizzard",
-	.init			= blizzard_init,
-	.cleanup		= blizzard_cleanup,
-	.bind_client		= blizzard_bind_client,
-	.get_caps		= blizzard_get_caps,
-	.set_update_mode	= blizzard_set_update_mode,
-	.get_update_mode	= blizzard_get_update_mode,
-	.setup_plane		= blizzard_setup_plane,
-	.set_scale		= blizzard_set_scale,
-	.enable_plane		= blizzard_enable_plane,
-	.set_rotate		= blizzard_set_rotate,
-	.update_window		= blizzard_update_window_async,
-	.sync			= blizzard_sync,
-	.suspend		= blizzard_suspend,
-	.resume			= blizzard_resume,
-};
-
diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c
deleted file mode 100644
index 6f61e78..0000000
--- a/drivers/video/omap/dispc.c
+++ /dev/null
@@ -1,1547 +0,0 @@
-/*
- * OMAP2 display controller support
- *
- * Copyright (C) 2005 Nokia Corporation
- * Author: Imre Deak <imre.deak@nokia.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.,
- * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include <plat/sram.h>
-#include <plat/board.h>
-
-#include "omapfb.h"
-#include "dispc.h"
-
-#define MODULE_NAME			"dispc"
-
-#define DSS_BASE			0x48050000
-#define DSS_SYSCONFIG			0x0010
-
-#define DISPC_BASE			0x48050400
-
-/* DISPC common */
-#define DISPC_REVISION			0x0000
-#define DISPC_SYSCONFIG			0x0010
-#define DISPC_SYSSTATUS			0x0014
-#define DISPC_IRQSTATUS			0x0018
-#define DISPC_IRQENABLE			0x001C
-#define DISPC_CONTROL			0x0040
-#define DISPC_CONFIG			0x0044
-#define DISPC_CAPABLE			0x0048
-#define DISPC_DEFAULT_COLOR0		0x004C
-#define DISPC_DEFAULT_COLOR1		0x0050
-#define DISPC_TRANS_COLOR0		0x0054
-#define DISPC_TRANS_COLOR1		0x0058
-#define DISPC_LINE_STATUS		0x005C
-#define DISPC_LINE_NUMBER		0x0060
-#define DISPC_TIMING_H			0x0064
-#define DISPC_TIMING_V			0x0068
-#define DISPC_POL_FREQ			0x006C
-#define DISPC_DIVISOR			0x0070
-#define DISPC_SIZE_DIG			0x0078
-#define DISPC_SIZE_LCD			0x007C
-
-#define DISPC_DATA_CYCLE1		0x01D4
-#define DISPC_DATA_CYCLE2		0x01D8
-#define DISPC_DATA_CYCLE3		0x01DC
-
-/* DISPC GFX plane */
-#define DISPC_GFX_BA0			0x0080
-#define DISPC_GFX_BA1			0x0084
-#define DISPC_GFX_POSITION		0x0088
-#define DISPC_GFX_SIZE			0x008C
-#define DISPC_GFX_ATTRIBUTES		0x00A0
-#define DISPC_GFX_FIFO_THRESHOLD	0x00A4
-#define DISPC_GFX_FIFO_SIZE_STATUS	0x00A8
-#define DISPC_GFX_ROW_INC		0x00AC
-#define DISPC_GFX_PIXEL_INC		0x00B0
-#define DISPC_GFX_WINDOW_SKIP		0x00B4
-#define DISPC_GFX_TABLE_BA		0x00B8
-
-/* DISPC Video plane 1/2 */
-#define DISPC_VID1_BASE			0x00BC
-#define DISPC_VID2_BASE			0x014C
-
-/* Offsets into DISPC_VID1/2_BASE */
-#define DISPC_VID_BA0			0x0000
-#define DISPC_VID_BA1			0x0004
-#define DISPC_VID_POSITION		0x0008
-#define DISPC_VID_SIZE			0x000C
-#define DISPC_VID_ATTRIBUTES		0x0010
-#define DISPC_VID_FIFO_THRESHOLD	0x0014
-#define DISPC_VID_FIFO_SIZE_STATUS	0x0018
-#define DISPC_VID_ROW_INC		0x001C
-#define DISPC_VID_PIXEL_INC		0x0020
-#define DISPC_VID_FIR			0x0024
-#define DISPC_VID_PICTURE_SIZE		0x0028
-#define DISPC_VID_ACCU0			0x002C
-#define DISPC_VID_ACCU1			0x0030
-
-/* 8 elements in 8 byte increments */
-#define DISPC_VID_FIR_COEF_H0		0x0034
-/* 8 elements in 8 byte increments */
-#define DISPC_VID_FIR_COEF_HV0		0x0038
-/* 5 elements in 4 byte increments */
-#define DISPC_VID_CONV_COEF0		0x0074
-
-#define DISPC_IRQ_FRAMEMASK		0x0001
-#define DISPC_IRQ_VSYNC			0x0002
-#define DISPC_IRQ_EVSYNC_EVEN		0x0004
-#define DISPC_IRQ_EVSYNC_ODD		0x0008
-#define DISPC_IRQ_ACBIAS_COUNT_STAT	0x0010
-#define DISPC_IRQ_PROG_LINE_NUM		0x0020
-#define DISPC_IRQ_GFX_FIFO_UNDERFLOW	0x0040
-#define DISPC_IRQ_GFX_END_WIN		0x0080
-#define DISPC_IRQ_PAL_GAMMA_MASK	0x0100
-#define DISPC_IRQ_OCP_ERR		0x0200
-#define DISPC_IRQ_VID1_FIFO_UNDERFLOW	0x0400
-#define DISPC_IRQ_VID1_END_WIN		0x0800
-#define DISPC_IRQ_VID2_FIFO_UNDERFLOW	0x1000
-#define DISPC_IRQ_VID2_END_WIN		0x2000
-#define DISPC_IRQ_SYNC_LOST		0x4000
-
-#define DISPC_IRQ_MASK_ALL		0x7fff
-
-#define DISPC_IRQ_MASK_ERROR		(DISPC_IRQ_GFX_FIFO_UNDERFLOW |	\
-					     DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
-					     DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
-					     DISPC_IRQ_SYNC_LOST)
-
-#define RFBI_CONTROL			0x48050040
-
-#define MAX_PALETTE_SIZE		(256 * 16)
-
-#define FLD_MASK(pos, len)	(((1 << len) - 1) << pos)
-
-#define MOD_REG_FLD(reg, mask, val) \
-	dispc_write_reg((reg), (dispc_read_reg(reg) & ~(mask)) | (val));
-
-#define OMAP2_SRAM_START		0x40200000
-/* Maximum size, in reality this is smaller if SRAM is partially locked. */
-#define OMAP2_SRAM_SIZE			0xa0000		/* 640k */
-
-/* We support the SDRAM / SRAM types. See OMAPFB_PLANE_MEMTYPE_* in omapfb.h */
-#define DISPC_MEMTYPE_NUM		2
-
-#define RESMAP_SIZE(_page_cnt)						\
-	((_page_cnt + (sizeof(unsigned long) * 8) - 1) / 8)
-#define RESMAP_PTR(_res_map, _page_nr)					\
-	(((_res_map)->map) + (_page_nr) / (sizeof(unsigned long) * 8))
-#define RESMAP_MASK(_page_nr)						\
-	(1 << ((_page_nr) & (sizeof(unsigned long) * 8 - 1)))
-
-struct resmap {
-	unsigned long	start;
-	unsigned	page_cnt;
-	unsigned long	*map;
-};
-
-#define MAX_IRQ_HANDLERS            4
-
-static struct {
-	void __iomem	*base;
-
-	struct omapfb_mem_desc	mem_desc;
-	struct resmap		*res_map[DISPC_MEMTYPE_NUM];
-	atomic_t		map_count[OMAPFB_PLANE_NUM];
-
-	dma_addr_t	palette_paddr;
-	void		*palette_vaddr;
-
-	int		ext_mode;
-
-	struct {
-		u32	irq_mask;
-		void	(*callback)(void *);
-		void	*data;
-	} irq_handlers[MAX_IRQ_HANDLERS];
-	struct completion	frame_done;
-
-	int		fir_hinc[OMAPFB_PLANE_NUM];
-	int		fir_vinc[OMAPFB_PLANE_NUM];
-
-	struct clk	*dss_ick, *dss1_fck;
-	struct clk	*dss_54m_fck;
-
-	enum omapfb_update_mode	update_mode;
-	struct omapfb_device	*fbdev;
-
-	struct omapfb_color_key	color_key;
-} dispc;
-
-static void enable_lcd_clocks(int enable);
-
-static void inline dispc_write_reg(int idx, u32 val)
-{
-	__raw_writel(val, dispc.base + idx);
-}
-
-static u32 inline dispc_read_reg(int idx)
-{
-	u32 l = __raw_readl(dispc.base + idx);
-	return l;
-}
-
-/* Select RFBI or bypass mode */
-static void enable_rfbi_mode(int enable)
-{
-	void __iomem *rfbi_control;
-	u32 l;
-
-	l = dispc_read_reg(DISPC_CONTROL);
-	/* Enable RFBI, GPIO0/1 */
-	l &= ~((1 << 11) | (1 << 15) | (1 << 16));
-	l |= enable ? (1 << 11) : 0;
-	/* RFBI En: GPIO0/1=10  RFBI Dis: GPIO0/1=11 */
-	l |= 1 << 15;
-	l |= enable ? 0 : (1 << 16);
-	dispc_write_reg(DISPC_CONTROL, l);
-
-	/* Set bypass mode in RFBI module */
-	rfbi_control = ioremap(RFBI_CONTROL, SZ_1K);
-	if (!rfbi_control) {
-		pr_err("Unable to ioremap rfbi_control\n");
-		return;
-	}
-	l = __raw_readl(rfbi_control);
-	l |= enable ? 0 : (1 << 1);
-	__raw_writel(l, rfbi_control);
-	iounmap(rfbi_control);
-}
-
-static void set_lcd_data_lines(int data_lines)
-{
-	u32 l;
-	int code = 0;
-
-	switch (data_lines) {
-	case 12:
-		code = 0;
-		break;
-	case 16:
-		code = 1;
-		break;
-	case 18:
-		code = 2;
-		break;
-	case 24:
-		code = 3;
-		break;
-	default:
-		BUG();
-	}
-
-	l = dispc_read_reg(DISPC_CONTROL);
-	l &= ~(0x03 << 8);
-	l |= code << 8;
-	dispc_write_reg(DISPC_CONTROL, l);
-}
-
-static void set_load_mode(int mode)
-{
-	BUG_ON(mode & ~(DISPC_LOAD_CLUT_ONLY | DISPC_LOAD_FRAME_ONLY |
-			DISPC_LOAD_CLUT_ONCE_FRAME));
-	MOD_REG_FLD(DISPC_CONFIG, 0x03 << 1, mode << 1);
-}
-
-void omap_dispc_set_lcd_size(int x, int y)
-{
-	BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
-	enable_lcd_clocks(1);
-	MOD_REG_FLD(DISPC_SIZE_LCD, FLD_MASK(16, 11) | FLD_MASK(0, 11),
-			((y - 1) << 16) | (x - 1));
-	enable_lcd_clocks(0);
-}
-EXPORT_SYMBOL(omap_dispc_set_lcd_size);
-
-void omap_dispc_set_digit_size(int x, int y)
-{
-	BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
-	enable_lcd_clocks(1);
-	MOD_REG_FLD(DISPC_SIZE_DIG, FLD_MASK(16, 11) | FLD_MASK(0, 11),
-			((y - 1) << 16) | (x - 1));
-	enable_lcd_clocks(0);
-}
-EXPORT_SYMBOL(omap_dispc_set_digit_size);
-
-static void setup_plane_fifo(int plane, int ext_mode)
-{
-	const u32 ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
-				DISPC_VID1_BASE + DISPC_VID_FIFO_THRESHOLD,
-			        DISPC_VID2_BASE + DISPC_VID_FIFO_THRESHOLD };
-	const u32 fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
-				DISPC_VID1_BASE + DISPC_VID_FIFO_SIZE_STATUS,
-				DISPC_VID2_BASE + DISPC_VID_FIFO_SIZE_STATUS };
-	int low, high;
-	u32 l;
-
-	BUG_ON(plane > 2);
-
-	l = dispc_read_reg(fsz_reg[plane]);
-	l &= FLD_MASK(0, 11);
-	if (ext_mode) {
-		low = l * 3 / 4;
-		high = l;
-	} else {
-		low = l / 4;
-		high = l * 3 / 4;
-	}
-	MOD_REG_FLD(ftrs_reg[plane], FLD_MASK(16, 12) | FLD_MASK(0, 12),
-			(high << 16) | low);
-}
-
-void omap_dispc_enable_lcd_out(int enable)
-{
-	enable_lcd_clocks(1);
-	MOD_REG_FLD(DISPC_CONTROL, 1, enable ? 1 : 0);
-	enable_lcd_clocks(0);
-}
-EXPORT_SYMBOL(omap_dispc_enable_lcd_out);
-
-void omap_dispc_enable_digit_out(int enable)
-{
-	enable_lcd_clocks(1);
-	MOD_REG_FLD(DISPC_CONTROL, 1 << 1, enable ? 1 << 1 : 0);
-	enable_lcd_clocks(0);
-}
-EXPORT_SYMBOL(omap_dispc_enable_digit_out);
-
-static inline int _setup_plane(int plane, int channel_out,
-				  u32 paddr, int screen_width,
-				  int pos_x, int pos_y, int width, int height,
-				  int color_mode)
-{
-	const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
-				DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
-			        DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
-	const u32 ba_reg[] = { DISPC_GFX_BA0, DISPC_VID1_BASE + DISPC_VID_BA0,
-				DISPC_VID2_BASE + DISPC_VID_BA0 };
-	const u32 ps_reg[] = { DISPC_GFX_POSITION,
-				DISPC_VID1_BASE + DISPC_VID_POSITION,
-				DISPC_VID2_BASE + DISPC_VID_POSITION };
-	const u32 sz_reg[] = { DISPC_GFX_SIZE,
-				DISPC_VID1_BASE + DISPC_VID_PICTURE_SIZE,
-				DISPC_VID2_BASE + DISPC_VID_PICTURE_SIZE };
-	const u32 ri_reg[] = { DISPC_GFX_ROW_INC,
-				DISPC_VID1_BASE + DISPC_VID_ROW_INC,
-			        DISPC_VID2_BASE + DISPC_VID_ROW_INC };
-	const u32 vs_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE,
-				DISPC_VID2_BASE + DISPC_VID_SIZE };
-
-	int chout_shift, burst_shift;
-	int chout_val;
-	int color_code;
-	int bpp;
-	int cconv_en;
-	int set_vsize;
-	u32 l;
-
-#ifdef VERBOSE
-	dev_dbg(dispc.fbdev->dev, "plane %d channel %d paddr %#08x scr_width %d"
-		    " pos_x %d pos_y %d width %d height %d color_mode %d\n",
-		    plane, channel_out, paddr, screen_width, pos_x, pos_y,
-		    width, height, color_mode);
-#endif
-
-	set_vsize = 0;
-	switch (plane) {
-	case OMAPFB_PLANE_GFX:
-		burst_shift = 6;
-		chout_shift = 8;
-		break;
-	case OMAPFB_PLANE_VID1:
-	case OMAPFB_PLANE_VID2:
-		burst_shift = 14;
-		chout_shift = 16;
-		set_vsize = 1;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (channel_out) {
-	case OMAPFB_CHANNEL_OUT_LCD:
-		chout_val = 0;
-		break;
-	case OMAPFB_CHANNEL_OUT_DIGIT:
-		chout_val = 1;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	cconv_en = 0;
-	switch (color_mode) {
-	case OMAPFB_COLOR_RGB565:
-		color_code = DISPC_RGB_16_BPP;
-		bpp = 16;
-		break;
-	case OMAPFB_COLOR_YUV422:
-		if (plane == 0)
-			return -EINVAL;
-		color_code = DISPC_UYVY_422;
-		cconv_en = 1;
-		bpp = 16;
-		break;
-	case OMAPFB_COLOR_YUY422:
-		if (plane == 0)
-			return -EINVAL;
-		color_code = DISPC_YUV2_422;
-		cconv_en = 1;
-		bpp = 16;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	l = dispc_read_reg(at_reg[plane]);
-
-	l &= ~(0x0f << 1);
-	l |= color_code << 1;
-	l &= ~(1 << 9);
-	l |= cconv_en << 9;
-
-	l &= ~(0x03 << burst_shift);
-	l |= DISPC_BURST_8x32 << burst_shift;
-
-	l &= ~(1 << chout_shift);
-	l |= chout_val << chout_shift;
-
-	dispc_write_reg(at_reg[plane], l);
-
-	dispc_write_reg(ba_reg[plane], paddr);
-	MOD_REG_FLD(ps_reg[plane],
-		    FLD_MASK(16, 11) | FLD_MASK(0, 11), (pos_y << 16) | pos_x);
-
-	MOD_REG_FLD(sz_reg[plane], FLD_MASK(16, 11) | FLD_MASK(0, 11),
-			((height - 1) << 16) | (width - 1));
-
-	if (set_vsize) {
-		/* Set video size if set_scale hasn't set it */
-		if (!dispc.fir_vinc[plane])
-			MOD_REG_FLD(vs_reg[plane],
-				FLD_MASK(16, 11), (height - 1) << 16);
-		if (!dispc.fir_hinc[plane])
-			MOD_REG_FLD(vs_reg[plane],
-				FLD_MASK(0, 11), width - 1);
-	}
-
-	dispc_write_reg(ri_reg[plane], (screen_width - width) * bpp / 8 + 1);
-
-	return height * screen_width * bpp / 8;
-}
-
-static int omap_dispc_setup_plane(int plane, int channel_out,
-				  unsigned long offset,
-				  int screen_width,
-				  int pos_x, int pos_y, int width, int height,
-				  int color_mode)
-{
-	u32 paddr;
-	int r;
-
-	if ((unsigned)plane > dispc.mem_desc.region_cnt)
-		return -EINVAL;
-	paddr = dispc.mem_desc.region[plane].paddr + offset;
-	enable_lcd_clocks(1);
-	r = _setup_plane(plane, channel_out, paddr,
-			screen_width,
-			pos_x, pos_y, width, height, color_mode);
-	enable_lcd_clocks(0);
-	return r;
-}
-
-static void write_firh_reg(int plane, int reg, u32 value)
-{
-	u32 base;
-
-	if (plane == 1)
-		base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_H0;
-	else
-		base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_H0;
-	dispc_write_reg(base + reg * 8,	value);
-}
-
-static void write_firhv_reg(int plane, int reg, u32 value)
-{
-	u32 base;
-
-	if (plane == 1)
-		base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_HV0;
-	else
-		base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_HV0;
-	dispc_write_reg(base + reg * 8,	value);
-}
-
-static void set_upsampling_coef_table(int plane)
-{
-	const u32 coef[][2] = {
-		{ 0x00800000, 0x00800000 },
-		{ 0x0D7CF800, 0x037B02FF },
-		{ 0x1E70F5FF, 0x0C6F05FE },
-		{ 0x335FF5FE, 0x205907FB },
-		{ 0xF74949F7, 0x00404000 },
-		{ 0xF55F33FB, 0x075920FE },
-		{ 0xF5701EFE, 0x056F0CFF },
-		{ 0xF87C0DFF, 0x027B0300 },
-	};
-	int i;
-
-	for (i = 0; i < 8; i++) {
-		write_firh_reg(plane, i, coef[i][0]);
-		write_firhv_reg(plane, i, coef[i][1]);
-	}
-}
-
-static int omap_dispc_set_scale(int plane,
-				int orig_width, int orig_height,
-				int out_width, int out_height)
-{
-	const u32 at_reg[]  = { 0, DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
-				DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
-	const u32 vs_reg[]  = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE,
-				DISPC_VID2_BASE + DISPC_VID_SIZE };
-	const u32 fir_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_FIR,
-				DISPC_VID2_BASE + DISPC_VID_FIR };
-
-	u32 l;
-	int fir_hinc;
-	int fir_vinc;
-
-	if ((unsigned)plane > OMAPFB_PLANE_NUM)
-		return -ENODEV;
-
-	if (plane == OMAPFB_PLANE_GFX &&
-	    (out_width != orig_width || out_height != orig_height))
-		return -EINVAL;
-
-	enable_lcd_clocks(1);
-	if (orig_width < out_width) {
-		/*
-		 * Upsampling.
-		 * Currently you can only scale both dimensions in one way.
-		 */
-		if (orig_height > out_height ||
-		    orig_width * 8 < out_width ||
-		    orig_height * 8 < out_height) {
-			enable_lcd_clocks(0);
-			return -EINVAL;
-		}
-		set_upsampling_coef_table(plane);
-	} else if (orig_width > out_width) {
-		/* Downsampling not yet supported
-		*/
-
-		enable_lcd_clocks(0);
-		return -EINVAL;
-	}
-	if (!orig_width || orig_width == out_width)
-		fir_hinc = 0;
-	else
-		fir_hinc = 1024 * orig_width / out_width;
-	if (!orig_height || orig_height == out_height)
-		fir_vinc = 0;
-	else
-		fir_vinc = 1024 * orig_height / out_height;
-	dispc.fir_hinc[plane] = fir_hinc;
-	dispc.fir_vinc[plane] = fir_vinc;
-
-	MOD_REG_FLD(fir_reg[plane],
-		    FLD_MASK(16, 12) | FLD_MASK(0, 12),
-		    ((fir_vinc & 4095) << 16) |
-		    (fir_hinc & 4095));
-
-	dev_dbg(dispc.fbdev->dev, "out_width %d out_height %d orig_width %d "
-		"orig_height %d fir_hinc  %d fir_vinc %d\n",
-		out_width, out_height, orig_width, orig_height,
-		fir_hinc, fir_vinc);
-
-	MOD_REG_FLD(vs_reg[plane],
-		    FLD_MASK(16, 11) | FLD_MASK(0, 11),
-		    ((out_height - 1) << 16) | (out_width - 1));
-
-	l = dispc_read_reg(at_reg[plane]);
-	l &= ~(0x03 << 5);
-	l |= fir_hinc ? (1 << 5) : 0;
-	l |= fir_vinc ? (1 << 6) : 0;
-	dispc_write_reg(at_reg[plane], l);
-
-	enable_lcd_clocks(0);
-	return 0;
-}
-
-static int omap_dispc_enable_plane(int plane, int enable)
-{
-	const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
-				DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
-				DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
-	if ((unsigned int)plane > dispc.mem_desc.region_cnt)
-		return -EINVAL;
-
-	enable_lcd_clocks(1);
-	MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);
-	enable_lcd_clocks(0);
-
-	return 0;
-}
-
-static int omap_dispc_set_color_key(struct omapfb_color_key *ck)
-{
-	u32 df_reg, tr_reg;
-	int shift, val;
-
-	switch (ck->channel_out) {
-	case OMAPFB_CHANNEL_OUT_LCD:
-		df_reg = DISPC_DEFAULT_COLOR0;
-		tr_reg = DISPC_TRANS_COLOR0;
-		shift = 10;
-		break;
-	case OMAPFB_CHANNEL_OUT_DIGIT:
-		df_reg = DISPC_DEFAULT_COLOR1;
-		tr_reg = DISPC_TRANS_COLOR1;
-		shift = 12;
-		break;
-	default:
-		return -EINVAL;
-	}
-	switch (ck->key_type) {
-	case OMAPFB_COLOR_KEY_DISABLED:
-		val = 0;
-		break;
-	case OMAPFB_COLOR_KEY_GFX_DST:
-		val = 1;
-		break;
-	case OMAPFB_COLOR_KEY_VID_SRC:
-		val = 3;
-		break;
-	default:
-		return -EINVAL;
-	}
-	enable_lcd_clocks(1);
-	MOD_REG_FLD(DISPC_CONFIG, FLD_MASK(shift, 2), val << shift);
-
-	if (val != 0)
-		dispc_write_reg(tr_reg, ck->trans_key);
-	dispc_write_reg(df_reg, ck->background);
-	enable_lcd_clocks(0);
-
-	dispc.color_key = *ck;
-
-	return 0;
-}
-
-static int omap_dispc_get_color_key(struct omapfb_color_key *ck)
-{
-	*ck = dispc.color_key;
-	return 0;
-}
-
-static void load_palette(void)
-{
-}
-
-static int omap_dispc_set_update_mode(enum omapfb_update_mode mode)
-{
-	int r = 0;
-
-	if (mode != dispc.update_mode) {
-		switch (mode) {
-		case OMAPFB_AUTO_UPDATE:
-		case OMAPFB_MANUAL_UPDATE:
-			enable_lcd_clocks(1);
-			omap_dispc_enable_lcd_out(1);
-			dispc.update_mode = mode;
-			break;
-		case OMAPFB_UPDATE_DISABLED:
-			init_completion(&dispc.frame_done);
-			omap_dispc_enable_lcd_out(0);
-			if (!wait_for_completion_timeout(&dispc.frame_done,
-					msecs_to_jiffies(500))) {
-				dev_err(dispc.fbdev->dev,
-					 "timeout waiting for FRAME DONE\n");
-			}
-			dispc.update_mode = mode;
-			enable_lcd_clocks(0);
-			break;
-		default:
-			r = -EINVAL;
-		}
-	}
-
-	return r;
-}
-
-static void omap_dispc_get_caps(int plane, struct omapfb_caps *caps)
-{
-	caps->ctrl |= OMAPFB_CAPS_PLANE_RELOCATE_MEM;
-	if (plane > 0)
-		caps->ctrl |= OMAPFB_CAPS_PLANE_SCALE;
-	caps->plane_color |= (1 << OMAPFB_COLOR_RGB565) |
-			     (1 << OMAPFB_COLOR_YUV422) |
-			     (1 << OMAPFB_COLOR_YUY422);
-	if (plane == 0)
-		caps->plane_color |= (1 << OMAPFB_COLOR_CLUT_8BPP) |
-				     (1 << OMAPFB_COLOR_CLUT_4BPP) |
-				     (1 << OMAPFB_COLOR_CLUT_2BPP) |
-				     (1 << OMAPFB_COLOR_CLUT_1BPP) |
-				     (1 << OMAPFB_COLOR_RGB444);
-}
-
-static enum omapfb_update_mode omap_dispc_get_update_mode(void)
-{
-	return dispc.update_mode;
-}
-
-static void setup_color_conv_coef(void)
-{
-	u32 mask = FLD_MASK(16, 11) | FLD_MASK(0, 11);
-	int cf1_reg = DISPC_VID1_BASE + DISPC_VID_CONV_COEF0;
-	int cf2_reg = DISPC_VID2_BASE + DISPC_VID_CONV_COEF0;
-	int at1_reg = DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES;
-	int at2_reg = DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES;
-	const struct color_conv_coef {
-		int  ry,  rcr,  rcb,   gy,  gcr,  gcb,   by,  bcr,  bcb;
-		int  full_range;
-	}  ctbl_bt601_5 = {
-		    298,  409,    0,  298, -208, -100,  298,    0,  517, 0,
-	};
-	const struct color_conv_coef *ct;
-#define CVAL(x, y)	(((x & 2047) << 16) | (y & 2047))
-
-	ct = &ctbl_bt601_5;
-
-	MOD_REG_FLD(cf1_reg,		mask,	CVAL(ct->rcr, ct->ry));
-	MOD_REG_FLD(cf1_reg + 4,	mask,	CVAL(ct->gy,  ct->rcb));
-	MOD_REG_FLD(cf1_reg + 8,	mask,	CVAL(ct->gcb, ct->gcr));
-	MOD_REG_FLD(cf1_reg + 12,	mask,	CVAL(ct->bcr, ct->by));
-	MOD_REG_FLD(cf1_reg + 16,	mask,	CVAL(0,	      ct->bcb));
-
-	MOD_REG_FLD(cf2_reg,		mask,	CVAL(ct->rcr, ct->ry));
-	MOD_REG_FLD(cf2_reg + 4,	mask,	CVAL(ct->gy,  ct->rcb));
-	MOD_REG_FLD(cf2_reg + 8,	mask,	CVAL(ct->gcb, ct->gcr));
-	MOD_REG_FLD(cf2_reg + 12,	mask,	CVAL(ct->bcr, ct->by));
-	MOD_REG_FLD(cf2_reg + 16,	mask,	CVAL(0,	      ct->bcb));
-#undef CVAL
-
-	MOD_REG_FLD(at1_reg, (1 << 11), ct->full_range);
-	MOD_REG_FLD(at2_reg, (1 << 11), ct->full_range);
-}
-
-static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div)
-{
-	unsigned long fck, lck;
-
-	*lck_div = 1;
-	pck = max(1, pck);
-	fck = clk_get_rate(dispc.dss1_fck);
-	lck = fck;
-	*pck_div = (lck + pck - 1) / pck;
-	if (is_tft)
-		*pck_div = max(2, *pck_div);
-	else
-		*pck_div = max(3, *pck_div);
-	if (*pck_div > 255) {
-		*pck_div = 255;
-		lck = pck * *pck_div;
-		*lck_div = fck / lck;
-		BUG_ON(*lck_div < 1);
-		if (*lck_div > 255) {
-			*lck_div = 255;
-			dev_warn(dispc.fbdev->dev, "pixclock %d kHz too low.\n",
-				 pck / 1000);
-		}
-	}
-}
-
-static void set_lcd_tft_mode(int enable)
-{
-	u32 mask;
-
-	mask = 1 << 3;
-	MOD_REG_FLD(DISPC_CONTROL, mask, enable ? mask : 0);
-}
-
-static void set_lcd_timings(void)
-{
-	u32 l;
-	int lck_div, pck_div;
-	struct lcd_panel *panel = dispc.fbdev->panel;
-	int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
-	unsigned long fck;
-
-	l = dispc_read_reg(DISPC_TIMING_H);
-	l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
-	l |= ( max(1, (min(64,  panel->hsw))) - 1 ) << 0;
-	l |= ( max(1, (min(256, panel->hfp))) - 1 ) << 8;
-	l |= ( max(1, (min(256, panel->hbp))) - 1 ) << 20;
-	dispc_write_reg(DISPC_TIMING_H, l);
-
-	l = dispc_read_reg(DISPC_TIMING_V);
-	l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
-	l |= ( max(1, (min(64,  panel->vsw))) - 1 ) << 0;
-	l |= ( max(0, (min(255, panel->vfp))) - 0 ) << 8;
-	l |= ( max(0, (min(255, panel->vbp))) - 0 ) << 20;
-	dispc_write_reg(DISPC_TIMING_V, l);
-
-	l = dispc_read_reg(DISPC_POL_FREQ);
-	l &= ~FLD_MASK(12, 6);
-	l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 12;
-	l |= panel->acb & 0xff;
-	dispc_write_reg(DISPC_POL_FREQ, l);
-
-	calc_ck_div(is_tft, panel->pixel_clock * 1000, &lck_div, &pck_div);
-
-	l = dispc_read_reg(DISPC_DIVISOR);
-	l &= ~(FLD_MASK(16, 8) | FLD_MASK(0, 8));
-	l |= (lck_div << 16) | (pck_div << 0);
-	dispc_write_reg(DISPC_DIVISOR, l);
-
-	/* update panel info with the exact clock */
-	fck = clk_get_rate(dispc.dss1_fck);
-	panel->pixel_clock = fck / lck_div / pck_div / 1000;
-}
-
-static void recalc_irq_mask(void)
-{
-	int i;
-	unsigned long irq_mask = DISPC_IRQ_MASK_ERROR;
-
-	for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
-		if (!dispc.irq_handlers[i].callback)
-			continue;
-
-		irq_mask |= dispc.irq_handlers[i].irq_mask;
-	}
-
-	enable_lcd_clocks(1);
-	MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);
-	enable_lcd_clocks(0);
-}
-
-int omap_dispc_request_irq(unsigned long irq_mask, void (*callback)(void *data),
-			   void *data)
-{
-	int i;
-
-	BUG_ON(callback == NULL);
-
-	for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
-		if (dispc.irq_handlers[i].callback)
-			continue;
-
-		dispc.irq_handlers[i].irq_mask = irq_mask;
-		dispc.irq_handlers[i].callback = callback;
-		dispc.irq_handlers[i].data = data;
-		recalc_irq_mask();
-
-		return 0;
-	}
-
-	return -EBUSY;
-}
-EXPORT_SYMBOL(omap_dispc_request_irq);
-
-void omap_dispc_free_irq(unsigned long irq_mask, void (*callback)(void *data),
-			 void *data)
-{
-	int i;
-
-	for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
-		if (dispc.irq_handlers[i].callback == callback &&
-		    dispc.irq_handlers[i].data == data) {
-			dispc.irq_handlers[i].irq_mask = 0;
-			dispc.irq_handlers[i].callback = NULL;
-			dispc.irq_handlers[i].data = NULL;
-			recalc_irq_mask();
-			return;
-		}
-	}
-
-	BUG();
-}
-EXPORT_SYMBOL(omap_dispc_free_irq);
-
-static irqreturn_t omap_dispc_irq_handler(int irq, void *dev)
-{
-	u32 stat;
-	int i = 0;
-
-	enable_lcd_clocks(1);
-
-	stat = dispc_read_reg(DISPC_IRQSTATUS);
-	if (stat & DISPC_IRQ_FRAMEMASK)
-		complete(&dispc.frame_done);
-
-	if (stat & DISPC_IRQ_MASK_ERROR) {
-		if (printk_ratelimit()) {
-			dev_err(dispc.fbdev->dev, "irq error status %04x\n",
-				stat & 0x7fff);
-		}
-	}
-
-	for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
-		if (unlikely(dispc.irq_handlers[i].callback &&
-			     (stat & dispc.irq_handlers[i].irq_mask)))
-			dispc.irq_handlers[i].callback(
-						dispc.irq_handlers[i].data);
-	}
-
-	dispc_write_reg(DISPC_IRQSTATUS, stat);
-
-	enable_lcd_clocks(0);
-
-	return IRQ_HANDLED;
-}
-
-static int get_dss_clocks(void)
-{
-	dispc.dss_ick = clk_get(&dispc.fbdev->dssdev->dev, "ick");
-	if (IS_ERR(dispc.dss_ick)) {
-		dev_err(dispc.fbdev->dev, "can't get ick\n");
-		return PTR_ERR(dispc.dss_ick);
-	}
-
-	dispc.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "fck");
-	if (IS_ERR(dispc.dss1_fck)) {
-		dev_err(dispc.fbdev->dev, "can't get dss1_fck\n");
-		clk_put(dispc.dss_ick);
-		return PTR_ERR(dispc.dss1_fck);
-	}
-
-	dispc.dss_54m_fck = clk_get(&dispc.fbdev->dssdev->dev, "tv_clk");
-	if (IS_ERR(dispc.dss_54m_fck)) {
-		dev_err(dispc.fbdev->dev, "can't get tv_fck\n");
-		clk_put(dispc.dss_ick);
-		clk_put(dispc.dss1_fck);
-		return PTR_ERR(dispc.dss_54m_fck);
-	}
-
-	return 0;
-}
-
-static void put_dss_clocks(void)
-{
-	clk_put(dispc.dss_54m_fck);
-	clk_put(dispc.dss1_fck);
-	clk_put(dispc.dss_ick);
-}
-
-static void enable_lcd_clocks(int enable)
-{
-	if (enable) {
-		clk_enable(dispc.dss_ick);
-		clk_enable(dispc.dss1_fck);
-	} else {
-		clk_disable(dispc.dss1_fck);
-		clk_disable(dispc.dss_ick);
-	}
-}
-
-static void enable_digit_clocks(int enable)
-{
-	if (enable)
-		clk_enable(dispc.dss_54m_fck);
-	else
-		clk_disable(dispc.dss_54m_fck);
-}
-
-static void omap_dispc_suspend(void)
-{
-	if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
-		init_completion(&dispc.frame_done);
-		omap_dispc_enable_lcd_out(0);
-		if (!wait_for_completion_timeout(&dispc.frame_done,
-				msecs_to_jiffies(500))) {
-			dev_err(dispc.fbdev->dev,
-				"timeout waiting for FRAME DONE\n");
-		}
-		enable_lcd_clocks(0);
-	}
-}
-
-static void omap_dispc_resume(void)
-{
-	if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
-		enable_lcd_clocks(1);
-		if (!dispc.ext_mode) {
-			set_lcd_timings();
-			load_palette();
-		}
-		omap_dispc_enable_lcd_out(1);
-	}
-}
-
-
-static int omap_dispc_update_window(struct fb_info *fbi,
-				 struct omapfb_update_window *win,
-				 void (*complete_callback)(void *arg),
-				 void *complete_callback_data)
-{
-	return dispc.update_mode == OMAPFB_UPDATE_DISABLED ? -ENODEV : 0;
-}
-
-static int mmap_kern(struct omapfb_mem_region *region)
-{
-	struct vm_struct	*kvma;
-	struct vm_area_struct	vma;
-	pgprot_t		pgprot;
-	unsigned long		vaddr;
-
-	kvma = get_vm_area(region->size, VM_IOREMAP);
-	if (kvma == NULL) {
-		dev_err(dispc.fbdev->dev, "can't get kernel vm area\n");
-		return -ENOMEM;
-	}
-	vma.vm_mm = &init_mm;
-
-	vaddr = (unsigned long)kvma->addr;
-
-	pgprot = pgprot_writecombine(pgprot_kernel);
-	vma.vm_start = vaddr;
-	vma.vm_end = vaddr + region->size;
-	if (io_remap_pfn_range(&vma, vaddr, region->paddr >> PAGE_SHIFT,
-			   region->size, pgprot) < 0) {
-		dev_err(dispc.fbdev->dev, "kernel mmap for FBMEM failed\n");
-		return -EAGAIN;
-	}
-	region->vaddr = (void *)vaddr;
-
-	return 0;
-}
-
-static void mmap_user_open(struct vm_area_struct *vma)
-{
-	int plane = (int)vma->vm_private_data;
-
-	atomic_inc(&dispc.map_count[plane]);
-}
-
-static void mmap_user_close(struct vm_area_struct *vma)
-{
-	int plane = (int)vma->vm_private_data;
-
-	atomic_dec(&dispc.map_count[plane]);
-}
-
-static const struct vm_operations_struct mmap_user_ops = {
-	.open = mmap_user_open,
-	.close = mmap_user_close,
-};
-
-static int omap_dispc_mmap_user(struct fb_info *info,
-				struct vm_area_struct *vma)
-{
-	struct omapfb_plane_struct *plane = info->par;
-	unsigned long off;
-	unsigned long start;
-	u32 len;
-
-	if (vma->vm_end - vma->vm_start == 0)
-		return 0;
-	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
-		return -EINVAL;
-	off = vma->vm_pgoff << PAGE_SHIFT;
-
-	start = info->fix.smem_start;
-	len = info->fix.smem_len;
-	if (off >= len)
-		return -EINVAL;
-	if ((vma->vm_end - vma->vm_start + off) > len)
-		return -EINVAL;
-	off += start;
-	vma->vm_pgoff = off >> PAGE_SHIFT;
-	vma->vm_flags |= VM_IO | VM_RESERVED;
-	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
-	vma->vm_ops = &mmap_user_ops;
-	vma->vm_private_data = (void *)plane->idx;
-	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
-			     vma->vm_end - vma->vm_start, vma->vm_page_prot))
-		return -EAGAIN;
-	/* vm_ops.open won't be called for mmap itself. */
-	atomic_inc(&dispc.map_count[plane->idx]);
-	return 0;
-}
-
-static void unmap_kern(struct omapfb_mem_region *region)
-{
-	vunmap(region->vaddr);
-}
-
-static int alloc_palette_ram(void)
-{
-	dispc.palette_vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
-		MAX_PALETTE_SIZE, &dispc.palette_paddr, GFP_KERNEL);
-	if (dispc.palette_vaddr == NULL) {
-		dev_err(dispc.fbdev->dev, "failed to alloc palette memory\n");
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
-static void free_palette_ram(void)
-{
-	dma_free_writecombine(dispc.fbdev->dev, MAX_PALETTE_SIZE,
-			dispc.palette_vaddr, dispc.palette_paddr);
-}
-
-static int alloc_fbmem(struct omapfb_mem_region *region)
-{
-	region->vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
-			region->size, &region->paddr, GFP_KERNEL);
-
-	if (region->vaddr == NULL) {
-		dev_err(dispc.fbdev->dev, "unable to allocate FB DMA memory\n");
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
-static void free_fbmem(struct omapfb_mem_region *region)
-{
-	dma_free_writecombine(dispc.fbdev->dev, region->size,
-			      region->vaddr, region->paddr);
-}
-
-static struct resmap *init_resmap(unsigned long start, size_t size)
-{
-	unsigned page_cnt;
-	struct resmap *res_map;
-
-	page_cnt = PAGE_ALIGN(size) / PAGE_SIZE;
-	res_map =
-	    kzalloc(sizeof(struct resmap) + RESMAP_SIZE(page_cnt), GFP_KERNEL);
-	if (res_map == NULL)
-		return NULL;
-	res_map->start = start;
-	res_map->page_cnt = page_cnt;
-	res_map->map = (unsigned long *)(res_map + 1);
-	return res_map;
-}
-
-static void cleanup_resmap(struct resmap *res_map)
-{
-	kfree(res_map);
-}
-
-static inline int resmap_mem_type(unsigned long start)
-{
-	if (start >= OMAP2_SRAM_START &&
-	    start < OMAP2_SRAM_START + OMAP2_SRAM_SIZE)
-		return OMAPFB_MEMTYPE_SRAM;
-	else
-		return OMAPFB_MEMTYPE_SDRAM;
-}
-
-static inline int resmap_page_reserved(struct resmap *res_map, unsigned page_nr)
-{
-	return *RESMAP_PTR(res_map, page_nr) & RESMAP_MASK(page_nr) ? 1 : 0;
-}
-
-static inline void resmap_reserve_page(struct resmap *res_map, unsigned page_nr)
-{
-	BUG_ON(resmap_page_reserved(res_map, page_nr));
-	*RESMAP_PTR(res_map, page_nr) |= RESMAP_MASK(page_nr);
-}
-
-static inline void resmap_free_page(struct resmap *res_map, unsigned page_nr)
-{
-	BUG_ON(!resmap_page_reserved(res_map, page_nr));
-	*RESMAP_PTR(res_map, page_nr) &= ~RESMAP_MASK(page_nr);
-}
-
-static void resmap_reserve_region(unsigned long start, size_t size)
-{
-
-	struct resmap	*res_map;
-	unsigned	start_page;
-	unsigned	end_page;
-	int		mtype;
-	unsigned	i;
-
-	mtype = resmap_mem_type(start);
-	res_map = dispc.res_map[mtype];
-	dev_dbg(dispc.fbdev->dev, "reserve mem type %d start %08lx size %d\n",
-		mtype, start, size);
-	start_page = (start - res_map->start) / PAGE_SIZE;
-	end_page = start_page + PAGE_ALIGN(size) / PAGE_SIZE;
-	for (i = start_page; i < end_page; i++)
-		resmap_reserve_page(res_map, i);
-}
-
-static void resmap_free_region(unsigned long start, size_t size)
-{
-	struct resmap	*res_map;
-	unsigned	start_page;
-	unsigned	end_page;
-	unsigned	i;
-	int		mtype;
-
-	mtype = resmap_mem_type(start);
-	res_map = dispc.res_map[mtype];
-	dev_dbg(dispc.fbdev->dev, "free mem type %d start %08lx size %d\n",
-		mtype, start, size);
-	start_page = (start - res_map->start) / PAGE_SIZE;
-	end_page = start_page + PAGE_ALIGN(size) / PAGE_SIZE;
-	for (i = start_page; i < end_page; i++)
-		resmap_free_page(res_map, i);
-}
-
-static unsigned long resmap_alloc_region(int mtype, size_t size)
-{
-	unsigned i;
-	unsigned total;
-	unsigned start_page;
-	unsigned long start;
-	struct resmap *res_map = dispc.res_map[mtype];
-
-	BUG_ON(mtype >= DISPC_MEMTYPE_NUM || res_map == NULL || !size);
-
-	size = PAGE_ALIGN(size) / PAGE_SIZE;
-	start_page = 0;
-	total = 0;
-	for (i = 0; i < res_map->page_cnt; i++) {
-		if (resmap_page_reserved(res_map, i)) {
-			start_page = i + 1;
-			total = 0;
-		} else if (++total == size)
-			break;
-	}
-	if (total < size)
-		return 0;
-
-	start = res_map->start + start_page * PAGE_SIZE;
-	resmap_reserve_region(start, size * PAGE_SIZE);
-
-	return start;
-}
-
-/* Note that this will only work for user mappings, we don't deal with
- * kernel mappings here, so fbcon will keep using the old region.
- */
-static int omap_dispc_setup_mem(int plane, size_t size, int mem_type,
-				unsigned long *paddr)
-{
-	struct omapfb_mem_region *rg;
-	unsigned long new_addr = 0;
-
-	if ((unsigned)plane > dispc.mem_desc.region_cnt)
-		return -EINVAL;
-	if (mem_type >= DISPC_MEMTYPE_NUM)
-		return -EINVAL;
-	if (dispc.res_map[mem_type] == NULL)
-		return -ENOMEM;
-	rg = &dispc.mem_desc.region[plane];
-	if (size == rg->size && mem_type == rg->type)
-		return 0;
-	if (atomic_read(&dispc.map_count[plane]))
-		return -EBUSY;
-	if (rg->size != 0)
-		resmap_free_region(rg->paddr, rg->size);
-	if (size != 0) {
-		new_addr = resmap_alloc_region(mem_type, size);
-		if (!new_addr) {
-			/* Reallocate old region. */
-			resmap_reserve_region(rg->paddr, rg->size);
-			return -ENOMEM;
-		}
-	}
-	rg->paddr = new_addr;
-	rg->size = size;
-	rg->type = mem_type;
-
-	*paddr = new_addr;
-
-	return 0;
-}
-
-static int setup_fbmem(struct omapfb_mem_desc *req_md)
-{
-	struct omapfb_mem_region	*rg;
-	int i;
-	int r;
-	unsigned long			mem_start[DISPC_MEMTYPE_NUM];
-	unsigned long			mem_end[DISPC_MEMTYPE_NUM];
-
-	if (!req_md->region_cnt) {
-		dev_err(dispc.fbdev->dev, "no memory regions defined\n");
-		return -ENOENT;
-	}
-
-	rg = &req_md->region[0];
-	memset(mem_start, 0xff, sizeof(mem_start));
-	memset(mem_end, 0, sizeof(mem_end));
-
-	for (i = 0; i < req_md->region_cnt; i++, rg++) {
-		int mtype;
-		if (rg->paddr) {
-			rg->alloc = 0;
-			if (rg->vaddr == NULL) {
-				rg->map = 1;
-				if ((r = mmap_kern(rg)) < 0)
-					return r;
-			}
-		} else {
-			if (rg->type != OMAPFB_MEMTYPE_SDRAM) {
-				dev_err(dispc.fbdev->dev,
-					"unsupported memory type\n");
-				return -EINVAL;
-			}
-			rg->alloc = rg->map = 1;
-			if ((r = alloc_fbmem(rg)) < 0)
-				return r;
-		}
-		mtype = rg->type;
-
-		if (rg->paddr < mem_start[mtype])
-			mem_start[mtype] = rg->paddr;
-		if (rg->paddr + rg->size > mem_end[mtype])
-			mem_end[mtype] = rg->paddr + rg->size;
-	}
-
-	for (i = 0; i < DISPC_MEMTYPE_NUM; i++) {
-		unsigned long start;
-		size_t size;
-		if (mem_end[i] == 0)
-			continue;
-		start = mem_start[i];
-		size = mem_end[i] - start;
-		dispc.res_map[i] = init_resmap(start, size);
-		r = -ENOMEM;
-		if (dispc.res_map[i] == NULL)
-			goto fail;
-		/* Initial state is that everything is reserved. This
-		 * includes possible holes as well, which will never be
-		 * freed.
-		 */
-		resmap_reserve_region(start, size);
-	}
-
-	dispc.mem_desc = *req_md;
-
-	return 0;
-fail:
-	for (i = 0; i < DISPC_MEMTYPE_NUM; i++) {
-		if (dispc.res_map[i] != NULL)
-			cleanup_resmap(dispc.res_map[i]);
-	}
-	return r;
-}
-
-static void cleanup_fbmem(void)
-{
-	struct omapfb_mem_region *rg;
-	int i;
-
-	for (i = 0; i < DISPC_MEMTYPE_NUM; i++) {
-		if (dispc.res_map[i] != NULL)
-			cleanup_resmap(dispc.res_map[i]);
-	}
-	rg = &dispc.mem_desc.region[0];
-	for (i = 0; i < dispc.mem_desc.region_cnt; i++, rg++) {
-		if (rg->alloc)
-			free_fbmem(rg);
-		else {
-			if (rg->map)
-				unmap_kern(rg);
-		}
-	}
-}
-
-static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
-			   struct omapfb_mem_desc *req_vram)
-{
-	int r;
-	u32 l;
-	struct lcd_panel *panel = fbdev->panel;
-	void __iomem *ram_fw_base;
-	int tmo = 10000;
-	int skip_init = 0;
-	int i;
-
-	memset(&dispc, 0, sizeof(dispc));
-
-	dispc.base = ioremap(DISPC_BASE, SZ_1K);
-	if (!dispc.base) {
-		dev_err(fbdev->dev, "can't ioremap DISPC\n");
-		return -ENOMEM;
-	}
-
-	dispc.fbdev = fbdev;
-	dispc.ext_mode = ext_mode;
-
-	init_completion(&dispc.frame_done);
-
-	if ((r = get_dss_clocks()) < 0)
-		goto fail0;
-
-	enable_lcd_clocks(1);
-
-#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
-	l = dispc_read_reg(DISPC_CONTROL);
-	/* LCD enabled ? */
-	if (l & 1) {
-		pr_info("omapfb: skipping hardware initialization\n");
-		skip_init = 1;
-	}
-#endif
-
-	if (!skip_init) {
-		/* Reset monitoring works only w/ the 54M clk */
-		enable_digit_clocks(1);
-
-		/* Soft reset */
-		MOD_REG_FLD(DISPC_SYSCONFIG, 1 << 1, 1 << 1);
-
-		while (!(dispc_read_reg(DISPC_SYSSTATUS) & 1)) {
-			if (!--tmo) {
-				dev_err(dispc.fbdev->dev, "soft reset failed\n");
-				r = -ENODEV;
-				enable_digit_clocks(0);
-				goto fail1;
-			}
-		}
-
-		enable_digit_clocks(0);
-	}
-
-	/* Enable smart standby/idle, autoidle and wakeup */
-	l = dispc_read_reg(DISPC_SYSCONFIG);
-	l &= ~((3 << 12) | (3 << 3));
-	l |= (2 << 12) | (2 << 3) | (1 << 2) | (1 << 0);
-	dispc_write_reg(DISPC_SYSCONFIG, l);
-	omap_writel(1 << 0, DSS_BASE + DSS_SYSCONFIG);
-
-	/* Set functional clock autogating */
-	l = dispc_read_reg(DISPC_CONFIG);
-	l |= 1 << 9;
-	dispc_write_reg(DISPC_CONFIG, l);
-
-	l = dispc_read_reg(DISPC_IRQSTATUS);
-	dispc_write_reg(DISPC_IRQSTATUS, l);
-
-	recalc_irq_mask();
-
-	if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler,
-			   0, MODULE_NAME, fbdev)) < 0) {
-		dev_err(dispc.fbdev->dev, "can't get DSS IRQ\n");
-		goto fail1;
-	}
-
-	/* L3 firewall setting: enable access to OCM RAM */
-	ram_fw_base = ioremap(0x68005000, SZ_1K);
-	if (!ram_fw_base) {
-		dev_err(dispc.fbdev->dev, "Cannot ioremap to enable OCM RAM\n");
-		goto fail1;
-	}
-	__raw_writel(0x402000b0, ram_fw_base + 0xa0);
-	iounmap(ram_fw_base);
-
-	if ((r = alloc_palette_ram()) < 0)
-		goto fail2;
-
-	if ((r = setup_fbmem(req_vram)) < 0)
-		goto fail3;
-
-	if (!skip_init) {
-		for (i = 0; i < dispc.mem_desc.region_cnt; i++) {
-			memset(dispc.mem_desc.region[i].vaddr, 0,
-				dispc.mem_desc.region[i].size);
-		}
-
-		/* Set logic clock to fck, pixel clock to fck/2 for now */
-		MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(16, 8), 1 << 16);
-		MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(0, 8), 2 << 0);
-
-		setup_plane_fifo(0, ext_mode);
-		setup_plane_fifo(1, ext_mode);
-		setup_plane_fifo(2, ext_mode);
-
-		setup_color_conv_coef();
-
-		set_lcd_tft_mode(panel->config & OMAP_LCDC_PANEL_TFT);
-		set_load_mode(DISPC_LOAD_FRAME_ONLY);
-
-		if (!ext_mode) {
-			set_lcd_data_lines(panel->data_lines);
-			omap_dispc_set_lcd_size(panel->x_res, panel->y_res);
-			set_lcd_timings();
-		} else
-			set_lcd_data_lines(panel->bpp);
-		enable_rfbi_mode(ext_mode);
-	}
-
-	l = dispc_read_reg(DISPC_REVISION);
-	pr_info("omapfb: DISPC version %d.%d initialized\n",
-		 l >> 4 & 0x0f, l & 0x0f);
-	enable_lcd_clocks(0);
-
-	return 0;
-fail3:
-	free_palette_ram();
-fail2:
-	free_irq(INT_24XX_DSS_IRQ, fbdev);
-fail1:
-	enable_lcd_clocks(0);
-	put_dss_clocks();
-fail0:
-	iounmap(dispc.base);
-	return r;
-}
-
-static void omap_dispc_cleanup(void)
-{
-	int i;
-
-	omap_dispc_set_update_mode(OMAPFB_UPDATE_DISABLED);
-	/* This will also disable clocks that are on */
-	for (i = 0; i < dispc.mem_desc.region_cnt; i++)
-		omap_dispc_enable_plane(i, 0);
-	cleanup_fbmem();
-	free_palette_ram();
-	free_irq(INT_24XX_DSS_IRQ, dispc.fbdev);
-	put_dss_clocks();
-	iounmap(dispc.base);
-}
-
-const struct lcd_ctrl omap2_int_ctrl = {
-	.name			= "internal",
-	.init			= omap_dispc_init,
-	.cleanup		= omap_dispc_cleanup,
-	.get_caps		= omap_dispc_get_caps,
-	.set_update_mode	= omap_dispc_set_update_mode,
-	.get_update_mode	= omap_dispc_get_update_mode,
-	.update_window		= omap_dispc_update_window,
-	.suspend		= omap_dispc_suspend,
-	.resume			= omap_dispc_resume,
-	.setup_plane		= omap_dispc_setup_plane,
-	.setup_mem		= omap_dispc_setup_mem,
-	.set_scale		= omap_dispc_set_scale,
-	.enable_plane		= omap_dispc_enable_plane,
-	.set_color_key		= omap_dispc_set_color_key,
-	.get_color_key		= omap_dispc_get_color_key,
-	.mmap			= omap_dispc_mmap_user,
-};
diff --git a/drivers/video/omap/dispc.h b/drivers/video/omap/dispc.h
deleted file mode 100644
index c15ea77..0000000
--- a/drivers/video/omap/dispc.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef _DISPC_H
-#define _DISPC_H
-
-#include <linux/interrupt.h>
-
-#define DISPC_PLANE_GFX			0
-#define DISPC_PLANE_VID1		1
-#define DISPC_PLANE_VID2		2
-
-#define DISPC_RGB_1_BPP			0x00
-#define DISPC_RGB_2_BPP			0x01
-#define DISPC_RGB_4_BPP			0x02
-#define DISPC_RGB_8_BPP			0x03
-#define DISPC_RGB_12_BPP		0x04
-#define DISPC_RGB_16_BPP		0x06
-#define DISPC_RGB_24_BPP		0x08
-#define DISPC_RGB_24_BPP_UNPACK_32	0x09
-#define DISPC_YUV2_422			0x0a
-#define DISPC_UYVY_422			0x0b
-
-#define DISPC_BURST_4x32		0
-#define DISPC_BURST_8x32		1
-#define DISPC_BURST_16x32		2
-
-#define DISPC_LOAD_CLUT_AND_FRAME	0x00
-#define DISPC_LOAD_CLUT_ONLY		0x01
-#define DISPC_LOAD_FRAME_ONLY		0x02
-#define DISPC_LOAD_CLUT_ONCE_FRAME	0x03
-
-#define DISPC_TFT_DATA_LINES_12		0
-#define DISPC_TFT_DATA_LINES_16		1
-#define DISPC_TFT_DATA_LINES_18		2
-#define DISPC_TFT_DATA_LINES_24		3
-
-extern void omap_dispc_set_lcd_size(int width, int height);
-
-extern void omap_dispc_enable_lcd_out(int enable);
-extern void omap_dispc_enable_digit_out(int enable);
-
-extern int omap_dispc_request_irq(unsigned long irq_mask,
-				   void (*callback)(void *data), void *data);
-extern void omap_dispc_free_irq(unsigned long irq_mask,
-				 void (*callback)(void *data), void *data);
-
-extern const struct lcd_ctrl omap2_int_ctrl;
-#endif
diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c
index 084aa0a..9f1d23c 100644
--- a/drivers/video/omap/hwa742.c
+++ b/drivers/video/omap/hwa742.c
@@ -28,7 +28,6 @@
 #include <linux/interrupt.h>
 
 #include <plat/dma.h>
-#include <plat/hwa742.h>
 #include "omapfb.h"
 
 #define HWA742_REV_CODE_REG       0x0
@@ -942,7 +941,6 @@
 	unsigned long sys_clk, pix_clk;
 	int extif_mem_div;
 	struct omapfb_platform_data *omapfb_conf;
-	struct hwa742_platform_data *ctrl_conf;
 
 	BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl);
 
@@ -951,13 +949,6 @@
 	hwa742.int_ctrl = fbdev->int_ctrl;
 
 	omapfb_conf = fbdev->dev->platform_data;
-	ctrl_conf = omapfb_conf->ctrl_platform_data;
-
-	if (ctrl_conf == NULL) {
-		dev_err(fbdev->dev, "HWA742: missing platform data\n");
-		r = -ENOENT;
-		goto err1;
-	}
 
 	hwa742.sys_ck = clk_get(NULL, "hwa_sys_ck");
 
@@ -995,14 +986,12 @@
 		goto err4;
 	}
 
-	if (ctrl_conf->te_connected) {
-		if ((r = setup_tearsync(pix_clk, extif_mem_div)) < 0) {
-			dev_err(hwa742.fbdev->dev,
-			       "HWA742: can't setup tearing synchronization\n");
-			goto err4;
-		}
-		hwa742.te_connected = 1;
+	if ((r = setup_tearsync(pix_clk, extif_mem_div)) < 0) {
+		dev_err(hwa742.fbdev->dev,
+			"HWA742: can't setup tearing synchronization\n");
+		goto err4;
 	}
+	hwa742.te_connected = 1;
 
 	hwa742.max_transmit_size = hwa742.extif->max_transmit_size;
 
diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c
index 0fdd6f6..d3a3113 100644
--- a/drivers/video/omap/lcd_ams_delta.c
+++ b/drivers/video/omap/lcd_ams_delta.c
@@ -25,6 +25,7 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/lcd.h>
+#include <linux/gpio.h>
 
 #include <plat/board-ams-delta.h>
 #include <mach/hardware.h>
@@ -98,29 +99,41 @@
 
 /* omapfb panel section */
 
+static const struct gpio _gpios[] = {
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_LCD_VBLEN,
+		.flags	= GPIOF_OUT_INIT_LOW,
+		.label	= "lcd_vblen",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_LCD_NDISP,
+		.flags	= GPIOF_OUT_INIT_LOW,
+		.label	= "lcd_ndisp",
+	},
+};
+
 static int ams_delta_panel_init(struct lcd_panel *panel,
 		struct omapfb_device *fbdev)
 {
-	return 0;
+	return gpio_request_array(_gpios, ARRAY_SIZE(_gpios));
 }
 
 static void ams_delta_panel_cleanup(struct lcd_panel *panel)
 {
+	gpio_free_array(_gpios, ARRAY_SIZE(_gpios));
 }
 
 static int ams_delta_panel_enable(struct lcd_panel *panel)
 {
-	ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_NDISP,
-			AMS_DELTA_LATCH2_LCD_NDISP);
-	ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN,
-			AMS_DELTA_LATCH2_LCD_VBLEN);
+	gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_NDISP, 1);
+	gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_VBLEN, 1);
 	return 0;
 }
 
 static void ams_delta_panel_disable(struct lcd_panel *panel)
 {
-	ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN, 0);
-	ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_NDISP, 0);
+	gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_VBLEN, 0);
+	gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_NDISP, 0);
 }
 
 static unsigned long ams_delta_panel_get_caps(struct lcd_panel *panel)
diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c
index 7e8bd8e..e3d3d13 100644
--- a/drivers/video/omap/lcd_inn1610.c
+++ b/drivers/video/omap/lcd_inn1610.c
@@ -22,7 +22,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
-#include <asm/gpio.h>
+#include <linux/gpio.h>
 #include "omapfb.h"
 
 #define MODULE_NAME	"omapfb-lcd_h3"
@@ -32,20 +32,18 @@
 {
 	int r = 0;
 
-	if (gpio_request(14, "lcd_en0")) {
+	/* configure GPIO(14, 15) as outputs */
+	if (gpio_request_one(14, GPIOF_OUT_INIT_LOW, "lcd_en0")) {
 		pr_err(MODULE_NAME ": can't request GPIO 14\n");
 		r = -1;
 		goto exit;
 	}
-	if (gpio_request(15, "lcd_en1")) {
+	if (gpio_request_one(15, GPIOF_OUT_INIT_LOW, "lcd_en1")) {
 		pr_err(MODULE_NAME ": can't request GPIO 15\n");
 		gpio_free(14);
 		r = -1;
 		goto exit;
 	}
-	/* configure GPIO(14, 15) as outputs */
-	gpio_direction_output(14, 0);
-	gpio_direction_output(15, 0);
 exit:
 	return r;
 }
diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c
index 8d546dd..e3880c4 100644
--- a/drivers/video/omap/lcd_mipid.c
+++ b/drivers/video/omap/lcd_mipid.c
@@ -609,19 +609,7 @@
 	.remove	= __devexit_p(mipid_spi_remove),
 };
 
-static int __init mipid_drv_init(void)
-{
-	spi_register_driver(&mipid_spi_driver);
-
-	return 0;
-}
-module_init(mipid_drv_init);
-
-static void __exit mipid_drv_cleanup(void)
-{
-	spi_unregister_driver(&mipid_spi_driver);
-}
-module_exit(mipid_drv_cleanup);
+module_spi_driver(mipid_spi_driver);
 
 MODULE_DESCRIPTION("MIPI display driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap/omapfb.h b/drivers/video/omap/omapfb.h
index af3c9e5..2921d20 100644
--- a/drivers/video/omap/omapfb.h
+++ b/drivers/video/omap/omapfb.h
@@ -47,6 +47,27 @@
 
 struct omapfb_device;
 
+#define OMAPFB_PLANE_NUM		1
+
+struct omapfb_mem_region {
+	u32		paddr;
+	void __iomem	*vaddr;
+	unsigned long	size;
+	u8		type;		/* OMAPFB_PLANE_MEM_* */
+	enum omapfb_color_format format;/* OMAPFB_COLOR_* */
+	unsigned	format_used:1;	/* Must be set when format is set.
+					 * Needed b/c of the badly chosen 0
+					 * base for OMAPFB_COLOR_* values
+					 */
+	unsigned	alloc:1;	/* allocated by the driver */
+	unsigned	map:1;		/* kernel mapped by the driver */
+};
+
+struct omapfb_mem_desc {
+	int				region_cnt;
+	struct omapfb_mem_region	region[OMAPFB_PLANE_NUM];
+};
+
 struct lcd_panel {
 	const char	*name;
 	int		config;		/* TFT/STN, signal inversion */
@@ -207,11 +228,7 @@
 	struct platform_device	*dssdev;	/* dummy dev for clocks */
 };
 
-#ifdef CONFIG_ARCH_OMAP1
 extern struct lcd_ctrl omap1_lcd_ctrl;
-#else
-extern struct lcd_ctrl omap2_disp_ctrl;
-#endif
 
 extern void omapfb_register_panel(struct lcd_panel *panel);
 extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
index b291bfa..f54b463 100644
--- a/drivers/video/omap/omapfb_main.c
+++ b/drivers/video/omap/omapfb_main.c
@@ -34,7 +34,6 @@
 
 #include "omapfb.h"
 #include "lcdc.h"
-#include "dispc.h"
 
 #define MODULE_NAME	"omapfb"
 
@@ -104,29 +103,17 @@
  * ---------------------------------------------------------------------------
  */
 extern struct lcd_ctrl hwa742_ctrl;
-extern struct lcd_ctrl blizzard_ctrl;
 
 static const struct lcd_ctrl *ctrls[] = {
-#ifdef CONFIG_ARCH_OMAP1
 	&omap1_int_ctrl,
-#else
-	&omap2_int_ctrl,
-#endif
 
 #ifdef CONFIG_FB_OMAP_LCDC_HWA742
 	&hwa742_ctrl,
 #endif
-#ifdef CONFIG_FB_OMAP_LCDC_BLIZZARD
-	&blizzard_ctrl,
-#endif
 };
 
 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
-#ifdef CONFIG_ARCH_OMAP1
 extern struct lcd_ctrl_extif omap1_ext_if;
-#else
-extern struct lcd_ctrl_extif omap2_ext_if;
-#endif
 #endif
 
 static void omapfb_rqueue_lock(struct omapfb_device *fbdev)
@@ -170,11 +157,6 @@
 			fbdev->mem_desc.region[i].size =
 				PAGE_ALIGN(def_vram[i]);
 		fbdev->mem_desc.region_cnt = i;
-	} else {
-		struct omapfb_platform_data *conf;
-
-		conf = fbdev->dev->platform_data;
-		fbdev->mem_desc = conf->mem_desc;
 	}
 
 	if (!fbdev->mem_desc.region_cnt) {
@@ -880,7 +862,7 @@
 
 	if (fbdev->ctrl->setup_mem == NULL)
 		return -ENODEV;
-	if (mi->type > OMAPFB_MEMTYPE_MAX)
+	if (mi->type != OMAPFB_MEMTYPE_SDRAM)
 		return -EINVAL;
 
 	size = PAGE_ALIGN(mi->size);
@@ -1721,17 +1703,10 @@
 
 	mutex_init(&fbdev->rqueue_mutex);
 
-#ifdef CONFIG_ARCH_OMAP1
 	fbdev->int_ctrl = &omap1_int_ctrl;
 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
 	fbdev->ext_if = &omap1_ext_if;
 #endif
-#else	/* OMAP2 */
-	fbdev->int_ctrl = &omap2_int_ctrl;
-#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
-	fbdev->ext_if = &omap2_ext_if;
-#endif
-#endif
 	if (omapfb_find_ctrl(fbdev) < 0) {
 		dev_err(fbdev->dev,
 			"LCD controller not found, board not supported\n");
@@ -1766,8 +1741,7 @@
 
 #ifdef CONFIG_FB_OMAP_DMA_TUNE
 	/* Set DMA priority for EMIFF access to highest */
-	if (cpu_class_is_omap1())
-		omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15);
+	omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15);
 #endif
 
 	r = ctrl_change_mode(fbdev->fb_info[0]);
diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c
deleted file mode 100644
index 2c1a340..0000000
--- a/drivers/video/omap/rfbi.c
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- * OMAP2 Remote Frame Buffer Interface support
- *
- * Copyright (C) 2005 Nokia Corporation
- * Author: Juha Yrjölä <juha.yrjola@nokia.com>
- *	   Imre Deak <imre.deak@nokia.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.,
- * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-
-#include "omapfb.h"
-#include "dispc.h"
-
-/* To work around an RFBI transfer rate limitation */
-#define OMAP_RFBI_RATE_LIMIT	1
-
-#define RFBI_BASE		0x48050800
-#define RFBI_REVISION		0x0000
-#define RFBI_SYSCONFIG		0x0010
-#define RFBI_SYSSTATUS		0x0014
-#define RFBI_CONTROL		0x0040
-#define RFBI_PIXEL_CNT		0x0044
-#define RFBI_LINE_NUMBER	0x0048
-#define RFBI_CMD		0x004c
-#define RFBI_PARAM		0x0050
-#define RFBI_DATA		0x0054
-#define RFBI_READ		0x0058
-#define RFBI_STATUS		0x005c
-#define RFBI_CONFIG0		0x0060
-#define RFBI_ONOFF_TIME0	0x0064
-#define RFBI_CYCLE_TIME0	0x0068
-#define RFBI_DATA_CYCLE1_0	0x006c
-#define RFBI_DATA_CYCLE2_0	0x0070
-#define RFBI_DATA_CYCLE3_0	0x0074
-#define RFBI_VSYNC_WIDTH	0x0090
-#define RFBI_HSYNC_WIDTH	0x0094
-
-#define DISPC_BASE		0x48050400
-#define DISPC_CONTROL		0x0040
-#define DISPC_IRQ_FRAMEMASK     0x0001
-
-static struct {
-	void __iomem	*base;
-	void		(*lcdc_callback)(void *data);
-	void		*lcdc_callback_data;
-	unsigned long	l4_khz;
-	int		bits_per_cycle;
-	struct omapfb_device *fbdev;
-	struct clk	*dss_ick;
-	struct clk	*dss1_fck;
-	unsigned	tearsync_pin_cnt;
-	unsigned	tearsync_mode;
-} rfbi;
-
-static inline void rfbi_write_reg(int idx, u32 val)
-{
-	__raw_writel(val, rfbi.base + idx);
-}
-
-static inline u32 rfbi_read_reg(int idx)
-{
-	return __raw_readl(rfbi.base + idx);
-}
-
-static int rfbi_get_clocks(void)
-{
-	rfbi.dss_ick = clk_get(&rfbi.fbdev->dssdev->dev, "ick");
-	if (IS_ERR(rfbi.dss_ick)) {
-		dev_err(rfbi.fbdev->dev, "can't get ick\n");
-		return PTR_ERR(rfbi.dss_ick);
-	}
-
-	rfbi.dss1_fck = clk_get(&rfbi.fbdev->dssdev->dev, "fck");
-	if (IS_ERR(rfbi.dss1_fck)) {
-		dev_err(rfbi.fbdev->dev, "can't get dss1_fck\n");
-		clk_put(rfbi.dss_ick);
-		return PTR_ERR(rfbi.dss1_fck);
-	}
-
-	return 0;
-}
-
-static void rfbi_put_clocks(void)
-{
-	clk_put(rfbi.dss1_fck);
-	clk_put(rfbi.dss_ick);
-}
-
-static void rfbi_enable_clocks(int enable)
-{
-	if (enable) {
-		clk_enable(rfbi.dss_ick);
-		clk_enable(rfbi.dss1_fck);
-	} else {
-		clk_disable(rfbi.dss1_fck);
-		clk_disable(rfbi.dss_ick);
-	}
-}
-
-
-#ifdef VERBOSE
-static void rfbi_print_timings(void)
-{
-	u32 l;
-	u32 time;
-
-	l = rfbi_read_reg(RFBI_CONFIG0);
-	time = 1000000000 / rfbi.l4_khz;
-	if (l & (1 << 4))
-		time *= 2;
-
-	dev_dbg(rfbi.fbdev->dev, "Tick time %u ps\n", time);
-	l = rfbi_read_reg(RFBI_ONOFF_TIME0);
-	dev_dbg(rfbi.fbdev->dev,
-		"CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
-		"REONTIME %d, REOFFTIME %d\n",
-		l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f,
-		(l >> 20) & 0x0f, (l >> 24) & 0x3f);
-
-	l = rfbi_read_reg(RFBI_CYCLE_TIME0);
-	dev_dbg(rfbi.fbdev->dev,
-		"WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
-		"ACCESSTIME %d\n",
-		(l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f,
-		(l >> 22) & 0x3f);
-}
-#else
-static void rfbi_print_timings(void) {}
-#endif
-
-static void rfbi_set_timings(const struct extif_timings *t)
-{
-	u32 l;
-
-	BUG_ON(!t->converted);
-
-	rfbi_enable_clocks(1);
-	rfbi_write_reg(RFBI_ONOFF_TIME0, t->tim[0]);
-	rfbi_write_reg(RFBI_CYCLE_TIME0, t->tim[1]);
-
-	l = rfbi_read_reg(RFBI_CONFIG0);
-	l &= ~(1 << 4);
-	l |= (t->tim[2] ? 1 : 0) << 4;
-	rfbi_write_reg(RFBI_CONFIG0, l);
-
-	rfbi_print_timings();
-	rfbi_enable_clocks(0);
-}
-
-static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
-{
-	*clk_period = 1000000000 / rfbi.l4_khz;
-	*max_clk_div = 2;
-}
-
-static int ps_to_rfbi_ticks(int time, int div)
-{
-	unsigned long tick_ps;
-	int ret;
-
-	/* Calculate in picosecs to yield more exact results */
-	tick_ps = 1000000000 / (rfbi.l4_khz) * div;
-
-	ret = (time + tick_ps - 1) / tick_ps;
-
-	return ret;
-}
-
-#ifdef OMAP_RFBI_RATE_LIMIT
-static unsigned long rfbi_get_max_tx_rate(void)
-{
-	unsigned long	l4_rate, dss1_rate;
-	int		min_l4_ticks = 0;
-	int		i;
-
-	/* According to TI this can't be calculated so make the
-	 * adjustments for a couple of known frequencies and warn for
-	 * others.
-	 */
-	static const struct {
-		unsigned long l4_clk;		/* HZ */
-		unsigned long dss1_clk;		/* HZ */
-		unsigned long min_l4_ticks;
-	} ftab[] = {
-		{ 55,	132,	7, },		/* 7.86 MPix/s */
-		{ 110,	110,	12, },		/* 9.16 MPix/s */
-		{ 110,	132,	10, },		/* 11   Mpix/s */
-		{ 120,	120,	10, },		/* 12   Mpix/s */
-		{ 133,	133,	10, },		/* 13.3 Mpix/s */
-	};
-
-	l4_rate = rfbi.l4_khz / 1000;
-	dss1_rate = clk_get_rate(rfbi.dss1_fck) / 1000000;
-
-	for (i = 0; i < ARRAY_SIZE(ftab); i++) {
-		/* Use a window instead of an exact match, to account
-		 * for different DPLL multiplier / divider pairs.
-		 */
-		if (abs(ftab[i].l4_clk - l4_rate) < 3 &&
-		    abs(ftab[i].dss1_clk - dss1_rate) < 3) {
-			min_l4_ticks = ftab[i].min_l4_ticks;
-			break;
-		}
-	}
-	if (i == ARRAY_SIZE(ftab)) {
-		/* Can't be sure, return anyway the maximum not
-		 * rate-limited. This might cause a problem only for the
-		 * tearing synchronisation.
-		 */
-		dev_err(rfbi.fbdev->dev,
-			"can't determine maximum RFBI transfer rate\n");
-		return rfbi.l4_khz * 1000;
-	}
-	return rfbi.l4_khz * 1000 / min_l4_ticks;
-}
-#else
-static int rfbi_get_max_tx_rate(void)
-{
-	return rfbi.l4_khz * 1000;
-}
-#endif
-
-
-static int rfbi_convert_timings(struct extif_timings *t)
-{
-	u32 l;
-	int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
-	int actim, recyc, wecyc;
-	int div = t->clk_div;
-
-	if (div <= 0 || div > 2)
-		return -1;
-
-	/* Make sure that after conversion it still holds that:
-	 * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff,
-	 * csoff > cson, csoff >= max(weoff, reoff), actim > reon
-	 */
-	weon = ps_to_rfbi_ticks(t->we_on_time, div);
-	weoff = ps_to_rfbi_ticks(t->we_off_time, div);
-	if (weoff <= weon)
-		weoff = weon + 1;
-	if (weon > 0x0f)
-		return -1;
-	if (weoff > 0x3f)
-		return -1;
-
-	reon = ps_to_rfbi_ticks(t->re_on_time, div);
-	reoff = ps_to_rfbi_ticks(t->re_off_time, div);
-	if (reoff <= reon)
-		reoff = reon + 1;
-	if (reon > 0x0f)
-		return -1;
-	if (reoff > 0x3f)
-		return -1;
-
-	cson = ps_to_rfbi_ticks(t->cs_on_time, div);
-	csoff = ps_to_rfbi_ticks(t->cs_off_time, div);
-	if (csoff <= cson)
-		csoff = cson + 1;
-	if (csoff < max(weoff, reoff))
-		csoff = max(weoff, reoff);
-	if (cson > 0x0f)
-		return -1;
-	if (csoff > 0x3f)
-		return -1;
-
-	l =  cson;
-	l |= csoff << 4;
-	l |= weon  << 10;
-	l |= weoff << 14;
-	l |= reon  << 20;
-	l |= reoff << 24;
-
-	t->tim[0] = l;
-
-	actim = ps_to_rfbi_ticks(t->access_time, div);
-	if (actim <= reon)
-		actim = reon + 1;
-	if (actim > 0x3f)
-		return -1;
-
-	wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
-	if (wecyc < weoff)
-		wecyc = weoff;
-	if (wecyc > 0x3f)
-		return -1;
-
-	recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
-	if (recyc < reoff)
-		recyc = reoff;
-	if (recyc > 0x3f)
-		return -1;
-
-	cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
-	if (cs_pulse > 0x3f)
-		return -1;
-
-	l =  wecyc;
-	l |= recyc    << 6;
-	l |= cs_pulse << 12;
-	l |= actim    << 22;
-
-	t->tim[1] = l;
-
-	t->tim[2] = div - 1;
-
-	t->converted = 1;
-
-	return 0;
-}
-
-static int rfbi_setup_tearsync(unsigned pin_cnt,
-			       unsigned hs_pulse_time, unsigned vs_pulse_time,
-			       int hs_pol_inv, int vs_pol_inv, int extif_div)
-{
-	int hs, vs;
-	int min;
-	u32 l;
-
-	if (pin_cnt != 1 && pin_cnt != 2)
-		return -EINVAL;
-
-	hs = ps_to_rfbi_ticks(hs_pulse_time, 1);
-	vs = ps_to_rfbi_ticks(vs_pulse_time, 1);
-	if (hs < 2)
-		return -EDOM;
-	if (pin_cnt == 2)
-		min = 2;
-	else
-		min = 4;
-	if (vs < min)
-		return -EDOM;
-	if (vs == hs)
-		return -EINVAL;
-	rfbi.tearsync_pin_cnt = pin_cnt;
-	dev_dbg(rfbi.fbdev->dev,
-		"setup_tearsync: pins %d hs %d vs %d hs_inv %d vs_inv %d\n",
-		pin_cnt, hs, vs, hs_pol_inv, vs_pol_inv);
-
-	rfbi_enable_clocks(1);
-	rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
-	rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
-
-	l = rfbi_read_reg(RFBI_CONFIG0);
-	if (hs_pol_inv)
-		l &= ~(1 << 21);
-	else
-		l |= 1 << 21;
-	if (vs_pol_inv)
-		l &= ~(1 << 20);
-	else
-		l |= 1 << 20;
-	rfbi_enable_clocks(0);
-
-	return 0;
-}
-
-static int rfbi_enable_tearsync(int enable, unsigned line)
-{
-	u32 l;
-
-	dev_dbg(rfbi.fbdev->dev, "tearsync %d line %d mode %d\n",
-		enable, line, rfbi.tearsync_mode);
-	if (line > (1 << 11) - 1)
-		return -EINVAL;
-
-	rfbi_enable_clocks(1);
-	l = rfbi_read_reg(RFBI_CONFIG0);
-	l &= ~(0x3 << 2);
-	if (enable) {
-		rfbi.tearsync_mode = rfbi.tearsync_pin_cnt;
-		l |= rfbi.tearsync_mode << 2;
-	} else
-		rfbi.tearsync_mode = 0;
-	rfbi_write_reg(RFBI_CONFIG0, l);
-	rfbi_write_reg(RFBI_LINE_NUMBER, line);
-	rfbi_enable_clocks(0);
-
-	return 0;
-}
-
-static void rfbi_write_command(const void *buf, unsigned int len)
-{
-	rfbi_enable_clocks(1);
-	if (rfbi.bits_per_cycle == 16) {
-		const u16 *w = buf;
-		BUG_ON(len & 1);
-		for (; len; len -= 2)
-			rfbi_write_reg(RFBI_CMD, *w++);
-	} else {
-		const u8 *b = buf;
-		BUG_ON(rfbi.bits_per_cycle != 8);
-		for (; len; len--)
-			rfbi_write_reg(RFBI_CMD, *b++);
-	}
-	rfbi_enable_clocks(0);
-}
-
-static void rfbi_read_data(void *buf, unsigned int len)
-{
-	rfbi_enable_clocks(1);
-	if (rfbi.bits_per_cycle == 16) {
-		u16 *w = buf;
-		BUG_ON(len & ~1);
-		for (; len; len -= 2) {
-			rfbi_write_reg(RFBI_READ, 0);
-			*w++ = rfbi_read_reg(RFBI_READ);
-		}
-	} else {
-		u8 *b = buf;
-		BUG_ON(rfbi.bits_per_cycle != 8);
-		for (; len; len--) {
-			rfbi_write_reg(RFBI_READ, 0);
-			*b++ = rfbi_read_reg(RFBI_READ);
-		}
-	}
-	rfbi_enable_clocks(0);
-}
-
-static void rfbi_write_data(const void *buf, unsigned int len)
-{
-	rfbi_enable_clocks(1);
-	if (rfbi.bits_per_cycle == 16) {
-		const u16 *w = buf;
-		BUG_ON(len & 1);
-		for (; len; len -= 2)
-			rfbi_write_reg(RFBI_PARAM, *w++);
-	} else {
-		const u8 *b = buf;
-		BUG_ON(rfbi.bits_per_cycle != 8);
-		for (; len; len--)
-			rfbi_write_reg(RFBI_PARAM, *b++);
-	}
-	rfbi_enable_clocks(0);
-}
-
-static void rfbi_transfer_area(int width, int height,
-				void (callback)(void * data), void *data)
-{
-	u32 w;
-
-	BUG_ON(callback == NULL);
-
-	rfbi_enable_clocks(1);
-	omap_dispc_set_lcd_size(width, height);
-
-	rfbi.lcdc_callback = callback;
-	rfbi.lcdc_callback_data = data;
-
-	rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
-
-	w = rfbi_read_reg(RFBI_CONTROL);
-	w |= 1;				/* enable */
-	if (!rfbi.tearsync_mode)
-		w |= 1 << 4;		/* internal trigger, reset by HW */
-	rfbi_write_reg(RFBI_CONTROL, w);
-
-	omap_dispc_enable_lcd_out(1);
-}
-
-static inline void _stop_transfer(void)
-{
-	u32 w;
-
-	w = rfbi_read_reg(RFBI_CONTROL);
-	rfbi_write_reg(RFBI_CONTROL, w & ~(1 << 0));
-	rfbi_enable_clocks(0);
-}
-
-static void rfbi_dma_callback(void *data)
-{
-	_stop_transfer();
-	rfbi.lcdc_callback(rfbi.lcdc_callback_data);
-}
-
-static void rfbi_set_bits_per_cycle(int bpc)
-{
-	u32 l;
-
-	rfbi_enable_clocks(1);
-	l = rfbi_read_reg(RFBI_CONFIG0);
-	l &= ~(0x03 << 0);
-
-	switch (bpc) {
-	case 8:
-		break;
-	case 16:
-		l |= 3;
-		break;
-	default:
-		BUG();
-	}
-	rfbi_write_reg(RFBI_CONFIG0, l);
-	rfbi.bits_per_cycle = bpc;
-	rfbi_enable_clocks(0);
-}
-
-static int rfbi_init(struct omapfb_device *fbdev)
-{
-	u32 l;
-	int r;
-
-	rfbi.fbdev = fbdev;
-	rfbi.base = ioremap(RFBI_BASE, SZ_1K);
-	if (!rfbi.base) {
-		dev_err(fbdev->dev, "can't ioremap RFBI\n");
-		return -ENOMEM;
-	}
-
-	if ((r = rfbi_get_clocks()) < 0)
-		return r;
-	rfbi_enable_clocks(1);
-
-	rfbi.l4_khz = clk_get_rate(rfbi.dss_ick) / 1000;
-
-	/* Reset */
-	rfbi_write_reg(RFBI_SYSCONFIG, 1 << 1);
-	while (!(rfbi_read_reg(RFBI_SYSSTATUS) & (1 << 0)));
-
-	l = rfbi_read_reg(RFBI_SYSCONFIG);
-	/* Enable autoidle and smart-idle */
-	l |= (1 << 0) | (2 << 3);
-	rfbi_write_reg(RFBI_SYSCONFIG, l);
-
-	/* 16-bit interface, ITE trigger mode, 16-bit data */
-	l = (0x03 << 0) | (0x00 << 2) | (0x01 << 5) | (0x02 << 7);
-	l |= (0 << 9) | (1 << 20) | (1 << 21);
-	rfbi_write_reg(RFBI_CONFIG0, l);
-
-	rfbi_write_reg(RFBI_DATA_CYCLE1_0, 0x00000010);
-
-	l = rfbi_read_reg(RFBI_CONTROL);
-	/* Select CS0, clear bypass mode */
-	l = (0x01 << 2);
-	rfbi_write_reg(RFBI_CONTROL, l);
-
-	r = omap_dispc_request_irq(DISPC_IRQ_FRAMEMASK, rfbi_dma_callback,
-				   NULL);
-	if (r < 0) {
-		dev_err(fbdev->dev, "can't get DISPC irq\n");
-		rfbi_enable_clocks(0);
-		return r;
-	}
-
-	l = rfbi_read_reg(RFBI_REVISION);
-	pr_info("omapfb: RFBI version %d.%d initialized\n",
-		(l >> 4) & 0x0f, l & 0x0f);
-
-	rfbi_enable_clocks(0);
-
-	return 0;
-}
-
-static void rfbi_cleanup(void)
-{
-	omap_dispc_free_irq(DISPC_IRQ_FRAMEMASK, rfbi_dma_callback, NULL);
-	rfbi_put_clocks();
-	iounmap(rfbi.base);
-}
-
-const struct lcd_ctrl_extif omap2_ext_if = {
-	.init			= rfbi_init,
-	.cleanup		= rfbi_cleanup,
-	.get_clk_info		= rfbi_get_clk_info,
-	.get_max_tx_rate	= rfbi_get_max_tx_rate,
-	.set_bits_per_cycle	= rfbi_set_bits_per_cycle,
-	.convert_timings	= rfbi_convert_timings,
-	.set_timings		= rfbi_set_timings,
-	.write_command		= rfbi_write_command,
-	.read_data		= rfbi_read_data,
-	.write_data		= rfbi_write_data,
-	.transfer_area		= rfbi_transfer_area,
-	.setup_tearsync		= rfbi_setup_tearsync,
-	.enable_tearsync	= rfbi_enable_tearsync,
-
-	.max_transmit_size	= (u32) ~0,
-};
-
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
index 51a87e1..d26f37a 100644
--- a/drivers/video/omap2/displays/panel-acx565akm.c
+++ b/drivers/video/omap2/displays/panel-acx565akm.c
@@ -809,18 +809,7 @@
 	.remove	= __devexit_p(acx565akm_spi_remove),
 };
 
-static int __init acx565akm_init(void)
-{
-	return spi_register_driver(&acx565akm_spi_driver);
-}
-
-static void __exit acx565akm_exit(void)
-{
-	spi_unregister_driver(&acx565akm_spi_driver);
-}
-
-module_init(acx565akm_init);
-module_exit(acx565akm_exit);
+module_spi_driver(acx565akm_spi_driver);
 
 MODULE_AUTHOR("Nokia Corporation");
 MODULE_DESCRIPTION("acx565akm LCD Driver");
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c
index 28b9a6d..30fe4df 100644
--- a/drivers/video/omap2/displays/panel-generic-dpi.c
+++ b/drivers/video/omap2/displays/panel-generic-dpi.c
@@ -363,6 +363,29 @@
 
 		.name			= "ortustech_com43h4m10xtc",
 	},
+
+	/* Innolux AT080TN52 */
+	{
+		{
+			.x_res = 800,
+			.y_res = 600,
+
+			.pixel_clock	= 41142,
+
+			.hsw		= 20,
+			.hfp		= 210,
+			.hbp		= 46,
+
+			.vsw		= 10,
+			.vfp		= 12,
+			.vbp		= 23,
+		},
+		.acb			= 0x0,
+		.config			= OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+					  OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO,
+
+		.name			= "innolux_at080tn52",
+	},
 };
 
 struct panel_drv_data {
diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
index e0eb35b..0841cc2 100644
--- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
+++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
@@ -264,16 +264,6 @@
 	.remove		= __devexit_p(lb035q02_panel_spi_remove),
 };
 
-static int __init lb035q02_panel_drv_init(void)
-{
-	return spi_register_driver(&lb035q02_spi_driver);
-}
+module_spi_driver(lb035q02_spi_driver);
 
-static void __exit lb035q02_panel_drv_exit(void)
-{
-	spi_unregister_driver(&lb035q02_spi_driver);
-}
-
-module_init(lb035q02_panel_drv_init);
-module_exit(lb035q02_panel_drv_exit);
 MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
index 0eb31ca..8b38b39 100644
--- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
+++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
@@ -350,18 +350,8 @@
 	},
 };
 
-static int __init nec_8048_lcd_init(void)
-{
-	return spi_register_driver(&nec_8048_spi_driver);
-}
+module_spi_driver(nec_8048_spi_driver);
 
-static void __exit nec_8048_lcd_exit(void)
-{
-	return spi_unregister_driver(&nec_8048_spi_driver);
-}
-
-module_init(nec_8048_lcd_init);
-module_exit(nec_8048_lcd_exit);
 MODULE_AUTHOR("Erik Gilling <konkers@android.com>");
 MODULE_DESCRIPTION("NEC-nl8048hl11-01b Driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 00c5c61..0f21fa5 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -1019,14 +1019,12 @@
 	if (panel_data->use_ext_te) {
 		int gpio = panel_data->ext_te_gpio;
 
-		r = gpio_request(gpio, "taal irq");
+		r = gpio_request_one(gpio, GPIOF_IN, "taal irq");
 		if (r) {
 			dev_err(&dssdev->dev, "GPIO request failed\n");
 			goto err_gpio;
 		}
 
-		gpio_direction_input(gpio);
-
 		r = request_irq(gpio_to_irq(gpio), taal_te_isr,
 				IRQF_TRIGGER_RISING,
 				"taal vsync", dssdev);
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
index e6649aa..32f3fcd 100644
--- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
+++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
@@ -47,16 +47,20 @@
 			TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL)
 
 static const u16 tpo_td043_def_gamma[12] = {
-	106, 200, 289, 375, 460, 543, 625, 705, 785, 864, 942, 1020
+	105, 315, 381, 431, 490, 537, 579, 686, 780, 837, 880, 1023
 };
 
 struct tpo_td043_device {
 	struct spi_device *spi;
 	struct regulator *vcc_reg;
+	int nreset_gpio;
 	u16 gamma[12];
 	u32 mode;
 	u32 hmirror:1;
 	u32 vmirror:1;
+	u32 powered_on:1;
+	u32 spi_suspended:1;
+	u32 power_on_resume:1;
 };
 
 static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
@@ -265,28 +269,16 @@
 	.vbp		= 34,
 };
 
-static int tpo_td043_power_on(struct omap_dss_device *dssdev)
+static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043)
 {
-	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
-	int nreset_gpio = dssdev->reset_gpio;
-	int r;
+	int nreset_gpio = tpo_td043->nreset_gpio;
 
-	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+	if (tpo_td043->powered_on)
 		return 0;
 
-	r = omapdss_dpi_display_enable(dssdev);
-	if (r)
-		goto err0;
-
-	if (dssdev->platform_enable) {
-		r = dssdev->platform_enable(dssdev);
-		if (r)
-			goto err1;
-	}
-
 	regulator_enable(tpo_td043->vcc_reg);
 
-	/* wait for power up */
+	/* wait for regulator to stabilize */
 	msleep(160);
 
 	if (gpio_is_valid(nreset_gpio))
@@ -301,19 +293,15 @@
 			tpo_td043->vmirror);
 	tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma);
 
+	tpo_td043->powered_on = 1;
 	return 0;
-err1:
-	omapdss_dpi_display_disable(dssdev);
-err0:
-	return r;
 }
 
-static void tpo_td043_power_off(struct omap_dss_device *dssdev)
+static void tpo_td043_power_off(struct tpo_td043_device *tpo_td043)
 {
-	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
-	int nreset_gpio = dssdev->reset_gpio;
+	int nreset_gpio = tpo_td043->nreset_gpio;
 
-	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+	if (!tpo_td043->powered_on)
 		return;
 
 	tpo_td043_write(tpo_td043->spi, 3,
@@ -329,54 +317,94 @@
 
 	regulator_disable(tpo_td043->vcc_reg);
 
-	if (dssdev->platform_disable)
-		dssdev->platform_disable(dssdev);
-
-	omapdss_dpi_display_disable(dssdev);
+	tpo_td043->powered_on = 0;
 }
 
-static int tpo_td043_enable(struct omap_dss_device *dssdev)
+static int tpo_td043_enable_dss(struct omap_dss_device *dssdev)
 {
-	int ret;
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+	int r;
 
-	dev_dbg(&dssdev->dev, "enable\n");
+	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+		return 0;
 
-	ret = tpo_td043_power_on(dssdev);
-	if (ret)
-		return ret;
+	r = omapdss_dpi_display_enable(dssdev);
+	if (r)
+		goto err0;
+
+	if (dssdev->platform_enable) {
+		r = dssdev->platform_enable(dssdev);
+		if (r)
+			goto err1;
+	}
+
+	/*
+	 * If we are resuming from system suspend, SPI clocks might not be
+	 * enabled yet, so we'll program the LCD from SPI PM resume callback.
+	 */
+	if (!tpo_td043->spi_suspended) {
+		r = tpo_td043_power_on(tpo_td043);
+		if (r)
+			goto err1;
+	}
 
 	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
 	return 0;
+err1:
+	omapdss_dpi_display_disable(dssdev);
+err0:
+	return r;
+}
+
+static void tpo_td043_disable_dss(struct omap_dss_device *dssdev)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+
+	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+		return;
+
+	if (dssdev->platform_disable)
+		dssdev->platform_disable(dssdev);
+
+	omapdss_dpi_display_disable(dssdev);
+
+	if (!tpo_td043->spi_suspended)
+		tpo_td043_power_off(tpo_td043);
+}
+
+static int tpo_td043_enable(struct omap_dss_device *dssdev)
+{
+	dev_dbg(&dssdev->dev, "enable\n");
+
+	return tpo_td043_enable_dss(dssdev);
 }
 
 static void tpo_td043_disable(struct omap_dss_device *dssdev)
 {
 	dev_dbg(&dssdev->dev, "disable\n");
 
-	tpo_td043_power_off(dssdev);
+	tpo_td043_disable_dss(dssdev);
 
 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 }
 
 static int tpo_td043_suspend(struct omap_dss_device *dssdev)
 {
-	tpo_td043_power_off(dssdev);
+	dev_dbg(&dssdev->dev, "suspend\n");
+
+	tpo_td043_disable_dss(dssdev);
+
 	dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
 	return 0;
 }
 
 static int tpo_td043_resume(struct omap_dss_device *dssdev)
 {
-	int r = 0;
+	dev_dbg(&dssdev->dev, "resume\n");
 
-	r = tpo_td043_power_on(dssdev);
-	if (r)
-		return r;
-
-	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
-	return 0;
+	return tpo_td043_enable_dss(dssdev);
 }
 
 static int tpo_td043_probe(struct omap_dss_device *dssdev)
@@ -408,17 +436,12 @@
 	}
 
 	if (gpio_is_valid(nreset_gpio)) {
-		ret = gpio_request(nreset_gpio, "lcd reset");
+		ret = gpio_request_one(nreset_gpio, GPIOF_OUT_INIT_LOW,
+					"lcd reset");
 		if (ret < 0) {
 			dev_err(&dssdev->dev, "couldn't request reset GPIO\n");
 			goto fail_gpio_req;
 		}
-
-		ret = gpio_direction_output(nreset_gpio, 0);
-		if (ret < 0) {
-			dev_err(&dssdev->dev, "couldn't set GPIO direction\n");
-			goto fail_gpio_direction;
-		}
 	}
 
 	ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group);
@@ -427,8 +450,6 @@
 
 	return 0;
 
-fail_gpio_direction:
-	gpio_free(nreset_gpio);
 fail_gpio_req:
 	regulator_put(tpo_td043->vcc_reg);
 fail_regulator:
@@ -491,6 +512,7 @@
 		return -ENOMEM;
 
 	tpo_td043->spi = spi;
+	tpo_td043->nreset_gpio = dssdev->reset_gpio;
 	dev_set_drvdata(&spi->dev, tpo_td043);
 	dev_set_drvdata(&dssdev->dev, tpo_td043);
 
@@ -509,27 +531,52 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tpo_td043_spi_suspend(struct device *dev)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "tpo_td043_spi_suspend, tpo %p\n", tpo_td043);
+
+	tpo_td043->power_on_resume = tpo_td043->powered_on;
+	tpo_td043_power_off(tpo_td043);
+	tpo_td043->spi_suspended = 1;
+
+	return 0;
+}
+
+static int tpo_td043_spi_resume(struct device *dev)
+{
+	struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
+	int ret;
+
+	dev_dbg(dev, "tpo_td043_spi_resume\n");
+
+	if (tpo_td043->power_on_resume) {
+		ret = tpo_td043_power_on(tpo_td043);
+		if (ret)
+			return ret;
+	}
+	tpo_td043->spi_suspended = 0;
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm,
+	tpo_td043_spi_suspend, tpo_td043_spi_resume);
+
 static struct spi_driver tpo_td043_spi_driver = {
 	.driver = {
 		.name	= "tpo_td043mtea1_panel_spi",
 		.owner	= THIS_MODULE,
+		.pm	= &tpo_td043_spi_pm,
 	},
 	.probe	= tpo_td043_spi_probe,
 	.remove	= __devexit_p(tpo_td043_spi_remove),
 };
 
-static int __init tpo_td043_init(void)
-{
-	return spi_register_driver(&tpo_td043_spi_driver);
-}
-
-static void __exit tpo_td043_exit(void)
-{
-	spi_unregister_driver(&tpo_td043_spi_driver);
-}
-
-module_init(tpo_td043_init);
-module_exit(tpo_td043_exit);
+module_spi_driver(tpo_td043_spi_driver);
 
 MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");
 MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver");
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c
index 87b3e25..b10b3bc 100644
--- a/drivers/video/omap2/dss/apply.c
+++ b/drivers/video/omap2/dss/apply.c
@@ -105,6 +105,9 @@
 	struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
 	struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
 
+	bool fifo_merge_dirty;
+	bool fifo_merge;
+
 	bool irq_enabled;
 } dss_data;
 
@@ -351,6 +354,7 @@
 	bool updating;
 	unsigned long flags;
 	unsigned long t;
+	int r;
 
 	spin_lock_irqsave(&data_lock, flags);
 
@@ -366,11 +370,11 @@
 	spin_unlock_irqrestore(&data_lock, flags);
 
 	t = msecs_to_jiffies(500);
-	wait_for_completion_timeout(&extra_updated_completion, t);
-
-	updating = extra_info_update_ongoing();
-
-	WARN_ON(updating);
+	r = wait_for_completion_timeout(&extra_updated_completion, t);
+	if (r == 0)
+		DSSWARN("timeout in wait_pending_extra_info_updates\n");
+	else if (r < 0)
+		DSSERR("wait_pending_extra_info_updates failed: %d\n", r);
 }
 
 int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
@@ -388,6 +392,10 @@
 	if (mgr_manual_update(mgr))
 		return 0;
 
+	r = dispc_runtime_get();
+	if (r)
+		return r;
+
 	irq = dispc_mgr_get_vsync_irq(mgr->id);
 
 	mp = get_mgr_priv(mgr);
@@ -428,6 +436,8 @@
 		}
 	}
 
+	dispc_runtime_put();
+
 	return r;
 }
 
@@ -451,6 +461,10 @@
 	if (ovl_manual_update(ovl))
 		return 0;
 
+	r = dispc_runtime_get();
+	if (r)
+		return r;
+
 	irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
 
 	op = get_ovl_priv(ovl);
@@ -491,6 +505,8 @@
 		}
 	}
 
+	dispc_runtime_put();
+
 	return r;
 }
 
@@ -585,11 +601,40 @@
 	}
 }
 
+static void dss_write_regs_common(void)
+{
+	const int num_mgrs = omap_dss_get_num_overlay_managers();
+	int i;
+
+	if (!dss_data.fifo_merge_dirty)
+		return;
+
+	for (i = 0; i < num_mgrs; ++i) {
+		struct omap_overlay_manager *mgr;
+		struct mgr_priv_data *mp;
+
+		mgr = omap_dss_get_overlay_manager(i);
+		mp = get_mgr_priv(mgr);
+
+		if (mp->enabled) {
+			if (dss_data.fifo_merge_dirty) {
+				dispc_enable_fifomerge(dss_data.fifo_merge);
+				dss_data.fifo_merge_dirty = false;
+			}
+
+			if (mp->updating)
+				mp->shadow_info_dirty = true;
+		}
+	}
+}
+
 static void dss_write_regs(void)
 {
 	const int num_mgrs = omap_dss_get_num_overlay_managers();
 	int i;
 
+	dss_write_regs_common();
+
 	for (i = 0; i < num_mgrs; ++i) {
 		struct omap_overlay_manager *mgr;
 		struct mgr_priv_data *mp;
@@ -640,6 +685,22 @@
 
 }
 
+static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
+{
+	struct omap_overlay *ovl;
+	struct mgr_priv_data *mp;
+	struct ovl_priv_data *op;
+
+	mp = get_mgr_priv(mgr);
+	mp->shadow_info_dirty = false;
+
+	list_for_each_entry(ovl, &mgr->overlays, list) {
+		op = get_ovl_priv(ovl);
+		op->shadow_info_dirty = false;
+		op->shadow_extra_info_dirty = false;
+	}
+}
+
 void dss_mgr_start_update(struct omap_overlay_manager *mgr)
 {
 	struct mgr_priv_data *mp = get_mgr_priv(mgr);
@@ -659,6 +720,8 @@
 
 	dss_mgr_write_regs(mgr);
 
+	dss_write_regs_common();
+
 	mp->updating = true;
 
 	if (!dss_data.irq_enabled && need_isr())
@@ -666,6 +729,8 @@
 
 	dispc_mgr_enable(mgr->id, true);
 
+	mgr_clear_shadow_dirty(mgr);
+
 	spin_unlock_irqrestore(&data_lock, flags);
 }
 
@@ -709,22 +774,6 @@
 	dss_data.irq_enabled = false;
 }
 
-static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
-{
-	struct omap_overlay *ovl;
-	struct mgr_priv_data *mp;
-	struct ovl_priv_data *op;
-
-	mp = get_mgr_priv(mgr);
-	mp->shadow_info_dirty = false;
-
-	list_for_each_entry(ovl, &mgr->overlays, list) {
-		op = get_ovl_priv(ovl);
-		op->shadow_info_dirty = false;
-		op->shadow_extra_info_dirty = false;
-	}
-}
-
 static void dss_apply_irq_handler(void *data, u32 mask)
 {
 	const int num_mgrs = dss_feat_get_num_mgrs();
@@ -754,9 +803,6 @@
 
 			if (was_busy && !mp->busy)
 				mgr_clear_shadow_dirty(mgr);
-		} else {
-			if (was_updating && !mp->updating)
-				mgr_clear_shadow_dirty(mgr);
 		}
 	}
 
@@ -859,11 +905,20 @@
 	op->extra_info_dirty = true;
 }
 
-static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
+static void dss_apply_fifo_merge(bool use_fifo_merge)
+{
+	if (dss_data.fifo_merge == use_fifo_merge)
+		return;
+
+	dss_data.fifo_merge = use_fifo_merge;
+	dss_data.fifo_merge_dirty = true;
+}
+
+static void dss_ovl_setup_fifo(struct omap_overlay *ovl,
+		bool use_fifo_merge)
 {
 	struct ovl_priv_data *op = get_ovl_priv(ovl);
 	struct omap_dss_device *dssdev;
-	u32 size, burst_size;
 	u32 fifo_low, fifo_high;
 
 	if (!op->enabled && !op->enabling)
@@ -871,33 +926,14 @@
 
 	dssdev = ovl->manager->device;
 
-	size = dispc_ovl_get_fifo_size(ovl->id);
-
-	burst_size = dispc_ovl_get_burst_size(ovl->id);
-
-	switch (dssdev->type) {
-	case OMAP_DISPLAY_TYPE_DPI:
-	case OMAP_DISPLAY_TYPE_DBI:
-	case OMAP_DISPLAY_TYPE_SDI:
-	case OMAP_DISPLAY_TYPE_VENC:
-	case OMAP_DISPLAY_TYPE_HDMI:
-		default_get_overlay_fifo_thresholds(ovl->id, size,
-				burst_size, &fifo_low, &fifo_high);
-		break;
-#ifdef CONFIG_OMAP2_DSS_DSI
-	case OMAP_DISPLAY_TYPE_DSI:
-		dsi_get_overlay_fifo_thresholds(ovl->id, size,
-				burst_size, &fifo_low, &fifo_high);
-		break;
-#endif
-	default:
-		BUG();
-	}
+	dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high,
+			use_fifo_merge);
 
 	dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
 }
 
-static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
+static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr,
+		bool use_fifo_merge)
 {
 	struct omap_overlay *ovl;
 	struct mgr_priv_data *mp;
@@ -908,10 +944,10 @@
 		return;
 
 	list_for_each_entry(ovl, &mgr->overlays, list)
-		dss_ovl_setup_fifo(ovl);
+		dss_ovl_setup_fifo(ovl, use_fifo_merge);
 }
 
-static void dss_setup_fifos(void)
+static void dss_setup_fifos(bool use_fifo_merge)
 {
 	const int num_mgrs = omap_dss_get_num_overlay_managers();
 	struct omap_overlay_manager *mgr;
@@ -919,15 +955,91 @@
 
 	for (i = 0; i < num_mgrs; ++i) {
 		mgr = omap_dss_get_overlay_manager(i);
-		dss_mgr_setup_fifos(mgr);
+		dss_mgr_setup_fifos(mgr, use_fifo_merge);
 	}
 }
 
+static int get_num_used_managers(void)
+{
+	const int num_mgrs = omap_dss_get_num_overlay_managers();
+	struct omap_overlay_manager *mgr;
+	struct mgr_priv_data *mp;
+	int i;
+	int enabled_mgrs;
+
+	enabled_mgrs = 0;
+
+	for (i = 0; i < num_mgrs; ++i) {
+		mgr = omap_dss_get_overlay_manager(i);
+		mp = get_mgr_priv(mgr);
+
+		if (!mp->enabled)
+			continue;
+
+		enabled_mgrs++;
+	}
+
+	return enabled_mgrs;
+}
+
+static int get_num_used_overlays(void)
+{
+	const int num_ovls = omap_dss_get_num_overlays();
+	struct omap_overlay *ovl;
+	struct ovl_priv_data *op;
+	struct mgr_priv_data *mp;
+	int i;
+	int enabled_ovls;
+
+	enabled_ovls = 0;
+
+	for (i = 0; i < num_ovls; ++i) {
+		ovl = omap_dss_get_overlay(i);
+		op = get_ovl_priv(ovl);
+
+		if (!op->enabled && !op->enabling)
+			continue;
+
+		mp = get_mgr_priv(ovl->manager);
+
+		if (!mp->enabled)
+			continue;
+
+		enabled_ovls++;
+	}
+
+	return enabled_ovls;
+}
+
+static bool get_use_fifo_merge(void)
+{
+	int enabled_mgrs = get_num_used_managers();
+	int enabled_ovls = get_num_used_overlays();
+
+	if (!dss_has_feature(FEAT_FIFO_MERGE))
+		return false;
+
+	/*
+	 * In theory the only requirement for fifomerge is enabled_ovls <= 1.
+	 * However, if we have two managers enabled and set/unset the fifomerge,
+	 * we need to set the GO bits in particular sequence for the managers,
+	 * and wait in between.
+	 *
+	 * This is rather difficult as new apply calls can happen at any time,
+	 * so we simplify the problem by requiring also that enabled_mgrs <= 1.
+	 * In practice this shouldn't matter, because when only one overlay is
+	 * enabled, most likely only one output is enabled.
+	 */
+
+	return enabled_mgrs <= 1 && enabled_ovls <= 1;
+}
+
 int dss_mgr_enable(struct omap_overlay_manager *mgr)
 {
 	struct mgr_priv_data *mp = get_mgr_priv(mgr);
 	unsigned long flags;
 	int r;
+	bool fifo_merge;
 
 	mutex_lock(&apply_lock);
 
@@ -945,11 +1057,23 @@
 		goto err;
 	}
 
-	dss_setup_fifos();
+	/* step 1: setup fifos/fifomerge before enabling the manager */
+
+	fifo_merge = get_use_fifo_merge();
+	dss_setup_fifos(fifo_merge);
+	dss_apply_fifo_merge(fifo_merge);
 
 	dss_write_regs();
 	dss_set_go_bits();
 
+	spin_unlock_irqrestore(&data_lock, flags);
+
+	/* wait until fifo config is in */
+	wait_pending_extra_info_updates();
+
+	/* step 2: enable the manager */
+	spin_lock_irqsave(&data_lock, flags);
+
 	if (!mgr_manual_update(mgr))
 		mp->updating = true;
 
@@ -974,6 +1098,7 @@
 {
 	struct mgr_priv_data *mp = get_mgr_priv(mgr);
 	unsigned long flags;
+	bool fifo_merge;
 
 	mutex_lock(&apply_lock);
 
@@ -988,8 +1113,16 @@
 	mp->updating = false;
 	mp->enabled = false;
 
+	fifo_merge = get_use_fifo_merge();
+	dss_setup_fifos(fifo_merge);
+	dss_apply_fifo_merge(fifo_merge);
+
+	dss_write_regs();
+	dss_set_go_bits();
+
 	spin_unlock_irqrestore(&data_lock, flags);
 
+	wait_pending_extra_info_updates();
 out:
 	mutex_unlock(&apply_lock);
 }
@@ -1241,6 +1374,7 @@
 {
 	struct ovl_priv_data *op = get_ovl_priv(ovl);
 	unsigned long flags;
+	bool fifo_merge;
 	int r;
 
 	mutex_lock(&apply_lock);
@@ -1266,7 +1400,22 @@
 		goto err2;
 	}
 
-	dss_setup_fifos();
+	/* step 1: configure fifos/fifomerge for currently enabled ovls */
+
+	fifo_merge = get_use_fifo_merge();
+	dss_setup_fifos(fifo_merge);
+	dss_apply_fifo_merge(fifo_merge);
+
+	dss_write_regs();
+	dss_set_go_bits();
+
+	spin_unlock_irqrestore(&data_lock, flags);
+
+	/* wait for fifo configs to go in */
+	wait_pending_extra_info_updates();
+
+	/* step 2: enable the overlay */
+	spin_lock_irqsave(&data_lock, flags);
 
 	op->enabling = false;
 	dss_apply_ovl_enable(ovl, true);
@@ -1294,6 +1443,7 @@
 {
 	struct ovl_priv_data *op = get_ovl_priv(ovl);
 	unsigned long flags;
+	bool fifo_merge;
 	int r;
 
 	mutex_lock(&apply_lock);
@@ -1308,9 +1458,11 @@
 		goto err;
 	}
 
+	/* step 1: disable the overlay */
 	spin_lock_irqsave(&data_lock, flags);
 
 	dss_apply_ovl_enable(ovl, false);
+
 	dss_write_regs();
 	dss_set_go_bits();
 
@@ -1319,6 +1471,21 @@
 	/* wait for the overlay to be disabled */
 	wait_pending_extra_info_updates();
 
+	/* step 2: configure fifos/fifomerge */
+	spin_lock_irqsave(&data_lock, flags);
+
+	fifo_merge = get_use_fifo_merge();
+	dss_setup_fifos(fifo_merge);
+	dss_apply_fifo_merge(fifo_merge);
+
+	dss_write_regs();
+	dss_set_go_bits();
+
+	spin_unlock_irqrestore(&data_lock, flags);
+
+	/* wait for fifo config to go in */
+	wait_pending_extra_info_updates();
+
 	mutex_unlock(&apply_lock);
 
 	return 0;
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 8613f86..e8a1207 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -183,42 +183,6 @@
 	dss_init_overlay_managers(pdev);
 	dss_init_overlays(pdev);
 
-	r = dss_init_platform_driver();
-	if (r) {
-		DSSERR("Failed to initialize DSS platform driver\n");
-		goto err_dss;
-	}
-
-	r = dispc_init_platform_driver();
-	if (r) {
-		DSSERR("Failed to initialize dispc platform driver\n");
-		goto err_dispc;
-	}
-
-	r = rfbi_init_platform_driver();
-	if (r) {
-		DSSERR("Failed to initialize rfbi platform driver\n");
-		goto err_rfbi;
-	}
-
-	r = venc_init_platform_driver();
-	if (r) {
-		DSSERR("Failed to initialize venc platform driver\n");
-		goto err_venc;
-	}
-
-	r = dsi_init_platform_driver();
-	if (r) {
-		DSSERR("Failed to initialize DSI platform driver\n");
-		goto err_dsi;
-	}
-
-	r = hdmi_init_platform_driver();
-	if (r) {
-		DSSERR("Failed to initialize hdmi\n");
-		goto err_hdmi;
-	}
-
 	r = dss_initialize_debugfs();
 	if (r)
 		goto err_debugfs;
@@ -246,18 +210,6 @@
 err_register:
 	dss_uninitialize_debugfs();
 err_debugfs:
-	hdmi_uninit_platform_driver();
-err_hdmi:
-	dsi_uninit_platform_driver();
-err_dsi:
-	venc_uninit_platform_driver();
-err_venc:
-	dispc_uninit_platform_driver();
-err_dispc:
-	rfbi_uninit_platform_driver();
-err_rfbi:
-	dss_uninit_platform_driver();
-err_dss:
 
 	return r;
 }
@@ -269,13 +221,6 @@
 
 	dss_uninitialize_debugfs();
 
-	hdmi_uninit_platform_driver();
-	dsi_uninit_platform_driver();
-	venc_uninit_platform_driver();
-	rfbi_uninit_platform_driver();
-	dispc_uninit_platform_driver();
-	dss_uninit_platform_driver();
-
 	dss_uninit_overlays(pdev);
 	dss_uninit_overlay_managers(pdev);
 
@@ -525,6 +470,80 @@
 
 /* INIT */
 
+static int __init omap_dss_register_drivers(void)
+{
+	int r;
+
+	r = platform_driver_register(&omap_dss_driver);
+	if (r)
+		return r;
+
+	r = dss_init_platform_driver();
+	if (r) {
+		DSSERR("Failed to initialize DSS platform driver\n");
+		goto err_dss;
+	}
+
+	r = dispc_init_platform_driver();
+	if (r) {
+		DSSERR("Failed to initialize dispc platform driver\n");
+		goto err_dispc;
+	}
+
+	r = rfbi_init_platform_driver();
+	if (r) {
+		DSSERR("Failed to initialize rfbi platform driver\n");
+		goto err_rfbi;
+	}
+
+	r = venc_init_platform_driver();
+	if (r) {
+		DSSERR("Failed to initialize venc platform driver\n");
+		goto err_venc;
+	}
+
+	r = dsi_init_platform_driver();
+	if (r) {
+		DSSERR("Failed to initialize DSI platform driver\n");
+		goto err_dsi;
+	}
+
+	r = hdmi_init_platform_driver();
+	if (r) {
+		DSSERR("Failed to initialize hdmi\n");
+		goto err_hdmi;
+	}
+
+	return 0;
+
+err_hdmi:
+	dsi_uninit_platform_driver();
+err_dsi:
+	venc_uninit_platform_driver();
+err_venc:
+	rfbi_uninit_platform_driver();
+err_rfbi:
+	dispc_uninit_platform_driver();
+err_dispc:
+	dss_uninit_platform_driver();
+err_dss:
+	platform_driver_unregister(&omap_dss_driver);
+
+	return r;
+}
+
+static void __exit omap_dss_unregister_drivers(void)
+{
+	hdmi_uninit_platform_driver();
+	dsi_uninit_platform_driver();
+	venc_uninit_platform_driver();
+	rfbi_uninit_platform_driver();
+	dispc_uninit_platform_driver();
+	dss_uninit_platform_driver();
+
+	platform_driver_unregister(&omap_dss_driver);
+}
+
 #ifdef CONFIG_OMAP2_DSS_MODULE
 static void omap_dss_bus_unregister(void)
 {
@@ -541,7 +560,7 @@
 	if (r)
 		return r;
 
-	r = platform_driver_register(&omap_dss_driver);
+	r = omap_dss_register_drivers();
 	if (r) {
 		omap_dss_bus_unregister();
 		return r;
@@ -562,7 +581,7 @@
 		core.vdds_sdi_reg = NULL;
 	}
 
-	platform_driver_unregister(&omap_dss_driver);
+	omap_dss_unregister_drivers();
 
 	omap_dss_bus_unregister();
 }
@@ -577,7 +596,7 @@
 
 static int __init omap_dss_init2(void)
 {
-	return platform_driver_register(&omap_dss_driver);
+	return omap_dss_register_drivers();
 }
 
 core_initcall(omap_dss_init);
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index e1626a1..ee30937 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -37,7 +37,6 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 
-#include <plat/sram.h>
 #include <plat/clock.h>
 
 #include <video/omapdss.h>
@@ -736,11 +735,11 @@
 		switch (color_mode) {
 		case OMAP_DSS_COLOR_NV12:
 			m = 0x0; break;
-		case OMAP_DSS_COLOR_RGB12U:
+		case OMAP_DSS_COLOR_RGBX16:
 			m = 0x1; break;
 		case OMAP_DSS_COLOR_RGBA16:
 			m = 0x2; break;
-		case OMAP_DSS_COLOR_RGBX16:
+		case OMAP_DSS_COLOR_RGB12U:
 			m = 0x4; break;
 		case OMAP_DSS_COLOR_ARGB16:
 			m = 0x5; break;
@@ -789,9 +788,9 @@
 			m = 0x8; break;
 		case OMAP_DSS_COLOR_RGB24P:
 			m = 0x9; break;
-		case OMAP_DSS_COLOR_YUV2:
+		case OMAP_DSS_COLOR_RGBX16:
 			m = 0xa; break;
-		case OMAP_DSS_COLOR_UYVY:
+		case OMAP_DSS_COLOR_RGBA16:
 			m = 0xb; break;
 		case OMAP_DSS_COLOR_ARGB32:
 			m = 0xc; break;
@@ -909,7 +908,7 @@
 		dispc_ovl_set_burst_size(i, burst_size);
 }
 
-u32 dispc_ovl_get_burst_size(enum omap_plane plane)
+static u32 dispc_ovl_get_burst_size(enum omap_plane plane)
 {
 	unsigned unit = dss_feat_get_burst_size_unit();
 	/* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
@@ -1018,7 +1017,7 @@
 	}
 }
 
-u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
+static u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
 {
 	return dispc.fifo_size[plane];
 }
@@ -1039,13 +1038,13 @@
 	dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
 	dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
 
-	DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
+	DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n",
 			plane,
 			REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
-				lo_start, lo_end),
+				lo_start, lo_end) * unit,
 			REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
-				hi_start, hi_end),
-			low, high);
+				hi_start, hi_end) * unit,
+			low * unit, high * unit);
 
 	dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
 			FLD_VAL(high, hi_start, hi_end) |
@@ -1054,10 +1053,53 @@
 
 void dispc_enable_fifomerge(bool enable)
 {
+	if (!dss_has_feature(FEAT_FIFO_MERGE)) {
+		WARN_ON(enable);
+		return;
+	}
+
 	DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
 	REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
 }
 
+void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
+		u32 *fifo_low, u32 *fifo_high, bool use_fifomerge)
+{
+	/*
+	 * All sizes are in bytes. Both the buffer and burst are made of
+	 * buffer_units, and the fifo thresholds must be buffer_unit aligned.
+	 */
+
+	unsigned buf_unit = dss_feat_get_buffer_size_unit();
+	unsigned ovl_fifo_size, total_fifo_size, burst_size;
+	int i;
+
+	burst_size = dispc_ovl_get_burst_size(plane);
+	ovl_fifo_size = dispc_ovl_get_fifo_size(plane);
+
+	if (use_fifomerge) {
+		total_fifo_size = 0;
+		for (i = 0; i < omap_dss_get_num_overlays(); ++i)
+			total_fifo_size += dispc_ovl_get_fifo_size(i);
+	} else {
+		total_fifo_size = ovl_fifo_size;
+	}
+
+	/*
+	 * We use the same low threshold for both fifomerge and non-fifomerge
+	 * cases, but for fifomerge we calculate the high threshold using the
+	 * combined fifo size
+	 */
+
+	if (dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) {
+		*fifo_low = ovl_fifo_size - burst_size * 2;
+		*fifo_high = total_fifo_size - burst_size;
+	} else {
+		*fifo_low = ovl_fifo_size - burst_size;
+		*fifo_high = total_fifo_size - buf_unit;
+	}
+}
+
 static void dispc_ovl_set_fir(enum omap_plane plane,
 				int hinc, int vinc,
 				enum omap_color_component color_comp)
@@ -1651,6 +1693,7 @@
 		u16 height, u16 out_width, u16 out_height)
 {
 	unsigned int hf, vf;
+	unsigned long pclk = dispc_mgr_pclk_rate(channel);
 
 	/*
 	 * FIXME how to determine the 'A' factor
@@ -1673,13 +1716,16 @@
 
 	if (cpu_is_omap24xx()) {
 		if (vf > 1 && hf > 1)
-			return dispc_mgr_pclk_rate(channel) * 4;
+			return pclk * 4;
 		else
-			return dispc_mgr_pclk_rate(channel) * 2;
+			return pclk * 2;
 	} else if (cpu_is_omap34xx()) {
-		return dispc_mgr_pclk_rate(channel) * vf * hf;
+		return pclk * vf * hf;
 	} else {
-		return dispc_mgr_pclk_rate(channel) * hf;
+		if (hf > 1)
+			return DIV_ROUND_UP(pclk, out_width) * width;
+		else
+			return pclk;
 	}
 }
 
@@ -3272,11 +3318,6 @@
 	if (dss_has_feature(FEAT_FUNCGATED))
 		REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
 
-	/* L3 firewall setting: enable access to OCM RAM */
-	/* XXX this should be somewhere in plat-omap */
-	if (cpu_is_omap24xx())
-		__raw_writel(0x402000b0, OMAP2_L3_IO_ADDRESS(0x680050a0));
-
 	_dispc_setup_color_conv_coef();
 
 	dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
@@ -3298,15 +3339,6 @@
 
 	dispc.pdev = pdev;
 
-	clk = clk_get(&pdev->dev, "fck");
-	if (IS_ERR(clk)) {
-		DSSERR("can't get fck\n");
-		r = PTR_ERR(clk);
-		goto err_get_clk;
-	}
-
-	dispc.dss_clk = clk;
-
 	spin_lock_init(&dispc.irq_lock);
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
@@ -3319,29 +3351,38 @@
 	dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
 	if (!dispc_mem) {
 		DSSERR("can't get IORESOURCE_MEM DISPC\n");
-		r = -EINVAL;
-		goto err_ioremap;
+		return -EINVAL;
 	}
-	dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem));
+
+	dispc.base = devm_ioremap(&pdev->dev, dispc_mem->start,
+				  resource_size(dispc_mem));
 	if (!dispc.base) {
 		DSSERR("can't ioremap DISPC\n");
-		r = -ENOMEM;
-		goto err_ioremap;
+		return -ENOMEM;
 	}
+
 	dispc.irq = platform_get_irq(dispc.pdev, 0);
 	if (dispc.irq < 0) {
 		DSSERR("platform_get_irq failed\n");
-		r = -ENODEV;
-		goto err_irq;
+		return -ENODEV;
 	}
 
-	r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED,
-		"OMAP DISPC", dispc.pdev);
+	r = devm_request_irq(&pdev->dev, dispc.irq, omap_dispc_irq_handler,
+			     IRQF_SHARED, "OMAP DISPC", dispc.pdev);
 	if (r < 0) {
 		DSSERR("request_irq failed\n");
-		goto err_irq;
+		return r;
 	}
 
+	clk = clk_get(&pdev->dev, "fck");
+	if (IS_ERR(clk)) {
+		DSSERR("can't get fck\n");
+		r = PTR_ERR(clk);
+		return r;
+	}
+
+	dispc.dss_clk = clk;
+
 	pm_runtime_enable(&pdev->dev);
 
 	r = dispc_runtime_get();
@@ -3362,12 +3403,7 @@
 
 err_runtime_get:
 	pm_runtime_disable(&pdev->dev);
-	free_irq(dispc.irq, dispc.pdev);
-err_irq:
-	iounmap(dispc.base);
-err_ioremap:
 	clk_put(dispc.dss_clk);
-err_get_clk:
 	return r;
 }
 
@@ -3377,8 +3413,6 @@
 
 	clk_put(dispc.dss_clk);
 
-	free_irq(dispc.irq, dispc.pdev);
-	iounmap(dispc.base);
 	return 0;
 }
 
diff --git a/drivers/video/omap2/dss/dispc_coefs.c b/drivers/video/omap2/dss/dispc_coefs.c
index 069bccb..038c15b 100644
--- a/drivers/video/omap2/dss/dispc_coefs.c
+++ b/drivers/video/omap2/dss/dispc_coefs.c
@@ -19,14 +19,13 @@
 
 #include <linux/kernel.h>
 #include <video/omapdss.h>
-#include "dispc.h"
 
-#define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
+#include "dispc.h"
 
 static const struct dispc_coef coef3_M8[8] = {
 	{ 0,  0, 128,  0, 0 },
 	{ 0, -4, 123,  9, 0 },
-	{ 0, -4, 108, 87, 0 },
+	{ 0, -4, 108, 24, 0 },
 	{ 0, -2,  87, 43, 0 },
 	{ 0, 64,  64,  0, 0 },
 	{ 0, 43,  87, -2, 0 },
@@ -168,7 +167,7 @@
 
 static const struct dispc_coef coef5_M9[8] = {
 	{  -3,  10, 114,  10,  -3 },
-	{  -6,  24, 110,   0,  -1 },
+	{  -6,  24, 111,   0,  -1 },
 	{  -8,  40, 103,  -7,   0 },
 	{ -11,  58,  91, -11,   1 },
 	{   0, -12,  76,  76, -12 },
@@ -319,7 +318,7 @@
 	};
 
 	inc /= 128;
-	for (i = 0; i < ARRAY_LEN(coefs); ++i)
+	for (i = 0; i < ARRAY_SIZE(coefs); ++i)
 		if (inc >= coefs[i].Mmin && inc <= coefs[i].Mmax)
 			return five_taps ? coefs[i].coef_5 : coefs[i].coef_3;
 	return NULL;
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index be331dc..4424c19 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -279,16 +279,6 @@
 }
 EXPORT_SYMBOL(omapdss_default_get_resolution);
 
-void default_get_overlay_fifo_thresholds(enum omap_plane plane,
-		u32 fifo_size, u32 burst_size,
-		u32 *fifo_low, u32 *fifo_high)
-{
-	unsigned buf_unit = dss_feat_get_buffer_size_unit();
-
-	*fifo_high = fifo_size - buf_unit;
-	*fifo_low = fifo_size - burst_size;
-}
-
 int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
 {
 	switch (dssdev->type) {
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 52f36ec..662d14f 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -4524,14 +4524,6 @@
 }
 EXPORT_SYMBOL(omapdss_dsi_enable_te);
 
-void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
-		u32 fifo_size, u32 burst_size,
-		u32 *fifo_low, u32 *fifo_high)
-{
-	*fifo_high = fifo_size - burst_size;
-	*fifo_low = fifo_size - burst_size * 2;
-}
-
 int dsi_init_display(struct omap_dss_device *dssdev)
 {
 	struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
@@ -4695,11 +4687,9 @@
 	struct resource *dsi_mem;
 	struct dsi_data *dsi;
 
-	dsi = kzalloc(sizeof(*dsi), GFP_KERNEL);
-	if (!dsi) {
-		r = -ENOMEM;
-		goto err_alloc;
-	}
+	dsi = devm_kzalloc(&dsidev->dev, sizeof(*dsi), GFP_KERNEL);
+	if (!dsi)
+		return -ENOMEM;
 
 	dsi->pdev = dsidev;
 	dsi_pdev_map[dsi_module] = dsidev;
@@ -4722,12 +4712,6 @@
 	mutex_init(&dsi->lock);
 	sema_init(&dsi->bus_lock, 1);
 
-	r = dsi_get_clocks(dsidev);
-	if (r)
-		goto err_get_clk;
-
-	pm_runtime_enable(&dsidev->dev);
-
 	INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work,
 			dsi_framedone_timeout_work_callback);
 
@@ -4739,27 +4723,27 @@
 	dsi_mem = platform_get_resource(dsi->pdev, IORESOURCE_MEM, 0);
 	if (!dsi_mem) {
 		DSSERR("can't get IORESOURCE_MEM DSI\n");
-		r = -EINVAL;
-		goto err_ioremap;
+		return -EINVAL;
 	}
-	dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem));
+
+	dsi->base = devm_ioremap(&dsidev->dev, dsi_mem->start,
+				 resource_size(dsi_mem));
 	if (!dsi->base) {
 		DSSERR("can't ioremap DSI\n");
-		r = -ENOMEM;
-		goto err_ioremap;
+		return -ENOMEM;
 	}
+
 	dsi->irq = platform_get_irq(dsi->pdev, 0);
 	if (dsi->irq < 0) {
 		DSSERR("platform_get_irq failed\n");
-		r = -ENODEV;
-		goto err_get_irq;
+		return -ENODEV;
 	}
 
-	r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED,
-		dev_name(&dsidev->dev), dsi->pdev);
+	r = devm_request_irq(&dsidev->dev, dsi->irq, omap_dsi_irq_handler,
+			     IRQF_SHARED, dev_name(&dsidev->dev), dsi->pdev);
 	if (r < 0) {
 		DSSERR("request_irq failed\n");
-		goto err_get_irq;
+		return r;
 	}
 
 	/* DSI VCs initialization */
@@ -4771,9 +4755,15 @@
 
 	dsi_calc_clock_param_ranges(dsidev);
 
+	r = dsi_get_clocks(dsidev);
+	if (r)
+		return r;
+
+	pm_runtime_enable(&dsidev->dev);
+
 	r = dsi_runtime_get(dsidev);
 	if (r)
-		goto err_get_dsi;
+		goto err_runtime_get;
 
 	rev = dsi_read_reg(dsidev, DSI_REVISION);
 	dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
@@ -4791,15 +4781,9 @@
 
 	return 0;
 
-err_get_dsi:
-	free_irq(dsi->irq, dsi->pdev);
-err_get_irq:
-	iounmap(dsi->base);
-err_ioremap:
+err_runtime_get:
 	pm_runtime_disable(&dsidev->dev);
-err_get_clk:
-	kfree(dsi);
-err_alloc:
+	dsi_put_clocks(dsidev);
 	return r;
 }
 
@@ -4823,11 +4807,6 @@
 		dsi->vdds_dsi_reg = NULL;
 	}
 
-	free_irq(dsi->irq, dsi->pdev);
-	iounmap(dsi->base);
-
-	kfree(dsi);
-
 	return 0;
 }
 
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 77c2b5a..bd2d5e1 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -33,7 +33,10 @@
 #include <linux/pm_runtime.h>
 
 #include <video/omapdss.h>
+
+#include <plat/cpu.h>
 #include <plat/clock.h>
+
 #include "dss.h"
 #include "dss_features.h"
 
@@ -748,19 +751,19 @@
 	dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
 	if (!dss_mem) {
 		DSSERR("can't get IORESOURCE_MEM DSS\n");
-		r = -EINVAL;
-		goto err_ioremap;
+		return -EINVAL;
 	}
-	dss.base = ioremap(dss_mem->start, resource_size(dss_mem));
+
+	dss.base = devm_ioremap(&pdev->dev, dss_mem->start,
+				resource_size(dss_mem));
 	if (!dss.base) {
 		DSSERR("can't ioremap DSS\n");
-		r = -ENOMEM;
-		goto err_ioremap;
+		return -ENOMEM;
 	}
 
 	r = dss_get_clocks();
 	if (r)
-		goto err_clocks;
+		return r;
 
 	pm_runtime_enable(&pdev->dev);
 
@@ -808,9 +811,6 @@
 err_runtime_get:
 	pm_runtime_disable(&pdev->dev);
 	dss_put_clocks();
-err_clocks:
-	iounmap(dss.base);
-err_ioremap:
 	return r;
 }
 
@@ -819,8 +819,6 @@
 	dpi_exit();
 	sdi_exit();
 
-	iounmap(dss.base);
-
 	pm_runtime_disable(&pdev->dev);
 
 	dss_put_clocks();
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 32ff69f..d4b3dff 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -202,9 +202,6 @@
 		struct omap_dss_device *dssdev);
 bool dss_use_replication(struct omap_dss_device *dssdev,
 		enum omap_color_mode mode);
-void default_get_overlay_fifo_thresholds(enum omap_plane plane,
-		u32 fifo_size, u32 burst_size,
-		u32 *fifo_low, u32 *fifo_high);
 
 /* manager */
 int dss_init_overlay_managers(struct platform_device *pdev);
@@ -313,9 +310,6 @@
 int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
 		bool enable_hsdiv);
 void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
-void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
-		u32 fifo_size, u32 burst_size,
-		u32 *fifo_low, u32 *fifo_high);
 void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
 void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev);
 struct platform_device *dsi_get_dsidev_from_id(int module);
@@ -429,8 +423,8 @@
 
 
 void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
-u32 dispc_ovl_get_fifo_size(enum omap_plane plane);
-u32 dispc_ovl_get_burst_size(enum omap_plane plane);
+void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
+		u32 *fifo_low, u32 *fifo_high, bool use_fifomerge);
 int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
 		bool ilace, bool replication);
 int dispc_ovl_enable(enum omap_plane plane, bool enable);
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index afcb593..ce14aa6 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -41,7 +41,8 @@
 	const struct dss_reg_field *reg_fields;
 	const int num_reg_fields;
 
-	const u32 has_feature;
+	const enum dss_feat_id *features;
+	const int num_features;
 
 	const int num_mgrs;
 	const int num_ovls;
@@ -189,7 +190,8 @@
 	OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
 	OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
 	OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32 |
-	OMAP_DSS_COLOR_ARGB16_1555,
+	OMAP_DSS_COLOR_ARGB16_1555 | OMAP_DSS_COLOR_RGBX16 |
+	OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_XRGB16_1555,
 
 	/* OMAP_DSS_VIDEO1 */
 	OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
@@ -337,15 +339,110 @@
 	[FEAT_PARAM_LINEWIDTH]			= { 1, 2048 },
 };
 
+static const enum dss_feat_id omap2_dss_feat_list[] = {
+	FEAT_LCDENABLEPOL,
+	FEAT_LCDENABLESIGNAL,
+	FEAT_PCKFREEENABLE,
+	FEAT_FUNCGATED,
+	FEAT_ROWREPEATENABLE,
+	FEAT_RESIZECONF,
+};
+
+static const enum dss_feat_id omap3430_dss_feat_list[] = {
+	FEAT_LCDENABLEPOL,
+	FEAT_LCDENABLESIGNAL,
+	FEAT_PCKFREEENABLE,
+	FEAT_FUNCGATED,
+	FEAT_LINEBUFFERSPLIT,
+	FEAT_ROWREPEATENABLE,
+	FEAT_RESIZECONF,
+	FEAT_DSI_PLL_FREQSEL,
+	FEAT_DSI_REVERSE_TXCLKESC,
+	FEAT_VENC_REQUIRES_TV_DAC_CLK,
+	FEAT_CPR,
+	FEAT_PRELOAD,
+	FEAT_FIR_COEF_V,
+	FEAT_ALPHA_FIXED_ZORDER,
+	FEAT_FIFO_MERGE,
+	FEAT_OMAP3_DSI_FIFO_BUG,
+};
+
+static const enum dss_feat_id omap3630_dss_feat_list[] = {
+	FEAT_LCDENABLEPOL,
+	FEAT_LCDENABLESIGNAL,
+	FEAT_PCKFREEENABLE,
+	FEAT_FUNCGATED,
+	FEAT_LINEBUFFERSPLIT,
+	FEAT_ROWREPEATENABLE,
+	FEAT_RESIZECONF,
+	FEAT_DSI_PLL_PWR_BUG,
+	FEAT_DSI_PLL_FREQSEL,
+	FEAT_CPR,
+	FEAT_PRELOAD,
+	FEAT_FIR_COEF_V,
+	FEAT_ALPHA_FIXED_ZORDER,
+	FEAT_FIFO_MERGE,
+	FEAT_OMAP3_DSI_FIFO_BUG,
+};
+
+static const enum dss_feat_id omap4430_es1_0_dss_feat_list[] = {
+	FEAT_MGR_LCD2,
+	FEAT_CORE_CLK_DIV,
+	FEAT_LCD_CLK_SRC,
+	FEAT_DSI_DCS_CMD_CONFIG_VC,
+	FEAT_DSI_VC_OCP_WIDTH,
+	FEAT_DSI_GNQ,
+	FEAT_HANDLE_UV_SEPARATE,
+	FEAT_ATTR2,
+	FEAT_CPR,
+	FEAT_PRELOAD,
+	FEAT_FIR_COEF_V,
+	FEAT_ALPHA_FREE_ZORDER,
+	FEAT_FIFO_MERGE,
+};
+
+static const enum dss_feat_id omap4430_es2_0_1_2_dss_feat_list[] = {
+	FEAT_MGR_LCD2,
+	FEAT_CORE_CLK_DIV,
+	FEAT_LCD_CLK_SRC,
+	FEAT_DSI_DCS_CMD_CONFIG_VC,
+	FEAT_DSI_VC_OCP_WIDTH,
+	FEAT_DSI_GNQ,
+	FEAT_HDMI_CTS_SWMODE,
+	FEAT_HANDLE_UV_SEPARATE,
+	FEAT_ATTR2,
+	FEAT_CPR,
+	FEAT_PRELOAD,
+	FEAT_FIR_COEF_V,
+	FEAT_ALPHA_FREE_ZORDER,
+	FEAT_FIFO_MERGE,
+};
+
+static const enum dss_feat_id omap4_dss_feat_list[] = {
+	FEAT_MGR_LCD2,
+	FEAT_CORE_CLK_DIV,
+	FEAT_LCD_CLK_SRC,
+	FEAT_DSI_DCS_CMD_CONFIG_VC,
+	FEAT_DSI_VC_OCP_WIDTH,
+	FEAT_DSI_GNQ,
+	FEAT_HDMI_CTS_SWMODE,
+	FEAT_HDMI_AUDIO_USE_MCLK,
+	FEAT_HANDLE_UV_SEPARATE,
+	FEAT_ATTR2,
+	FEAT_CPR,
+	FEAT_PRELOAD,
+	FEAT_FIR_COEF_V,
+	FEAT_ALPHA_FREE_ZORDER,
+	FEAT_FIFO_MERGE,
+};
+
 /* OMAP2 DSS Features */
 static const struct omap_dss_features omap2_dss_features = {
 	.reg_fields = omap2_dss_reg_fields,
 	.num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields),
 
-	.has_feature	=
-		FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL |
-		FEAT_PCKFREEENABLE | FEAT_FUNCGATED |
-		FEAT_ROWREPEATENABLE | FEAT_RESIZECONF,
+	.features = omap2_dss_feat_list,
+	.num_features = ARRAY_SIZE(omap2_dss_feat_list),
 
 	.num_mgrs = 2,
 	.num_ovls = 3,
@@ -363,14 +460,8 @@
 	.reg_fields = omap3_dss_reg_fields,
 	.num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
 
-	.has_feature	=
-		FEAT_LCDENABLEPOL |
-		FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
-		FEAT_FUNCGATED | FEAT_ROWREPEATENABLE |
-		FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF |
-		FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC |
-		FEAT_VENC_REQUIRES_TV_DAC_CLK | FEAT_CPR | FEAT_PRELOAD |
-		FEAT_FIR_COEF_V | FEAT_ALPHA_FIXED_ZORDER,
+	.features = omap3430_dss_feat_list,
+	.num_features = ARRAY_SIZE(omap3430_dss_feat_list),
 
 	.num_mgrs = 2,
 	.num_ovls = 3,
@@ -387,14 +478,8 @@
 	.reg_fields = omap3_dss_reg_fields,
 	.num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
 
-	.has_feature    =
-		FEAT_LCDENABLEPOL |
-		FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
-		FEAT_FUNCGATED |
-		FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
-		FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG |
-		FEAT_DSI_PLL_FREQSEL | FEAT_CPR | FEAT_PRELOAD |
-		FEAT_FIR_COEF_V | FEAT_ALPHA_FIXED_ZORDER,
+	.features = omap3630_dss_feat_list,
+	.num_features = ARRAY_SIZE(omap3630_dss_feat_list),
 
 	.num_mgrs = 2,
 	.num_ovls = 3,
@@ -413,13 +498,27 @@
 	.reg_fields = omap4_dss_reg_fields,
 	.num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
 
-	.has_feature	=
-		FEAT_MGR_LCD2 |
-		FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
-		FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
-		FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 |
-		FEAT_CPR | FEAT_PRELOAD | FEAT_FIR_COEF_V |
-		FEAT_ALPHA_FREE_ZORDER,
+	.features = omap4430_es1_0_dss_feat_list,
+	.num_features = ARRAY_SIZE(omap4430_es1_0_dss_feat_list),
+
+	.num_mgrs = 3,
+	.num_ovls = 4,
+	.supported_displays = omap4_dss_supported_displays,
+	.supported_color_modes = omap4_dss_supported_color_modes,
+	.overlay_caps = omap4_dss_overlay_caps,
+	.clksrc_names = omap4_dss_clk_source_names,
+	.dss_params = omap4_dss_param_range,
+	.buffer_size_unit = 16,
+	.burst_size_unit = 16,
+};
+
+/* For OMAP4430 ES 2.0, 2.1 and 2.2 revisions */
+static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = {
+	.reg_fields = omap4_dss_reg_fields,
+	.num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
+
+	.features = omap4430_es2_0_1_2_dss_feat_list,
+	.num_features = ARRAY_SIZE(omap4430_es2_0_1_2_dss_feat_list),
 
 	.num_mgrs = 3,
 	.num_ovls = 4,
@@ -437,13 +536,8 @@
 	.reg_fields = omap4_dss_reg_fields,
 	.num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
 
-	.has_feature	=
-		FEAT_MGR_LCD2 |
-		FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
-		FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
-		FEAT_DSI_GNQ | FEAT_HDMI_CTS_SWMODE |
-		FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | FEAT_CPR |
-		FEAT_PRELOAD | FEAT_FIR_COEF_V | FEAT_ALPHA_FREE_ZORDER,
+	.features = omap4_dss_feat_list,
+	.num_features = ARRAY_SIZE(omap4_dss_feat_list),
 
 	.num_mgrs = 3,
 	.num_ovls = 4,
@@ -547,7 +641,16 @@
 /* DSS has_feature check */
 bool dss_has_feature(enum dss_feat_id id)
 {
-	return omap_current_dss_features->has_feature & id;
+	int i;
+	const enum dss_feat_id *features = omap_current_dss_features->features;
+	const int num_features = omap_current_dss_features->num_features;
+
+	for (i = 0; i < num_features; i++) {
+		if (features[i] == id)
+			return true;
+	}
+
+	return false;
 }
 
 void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end)
@@ -569,6 +672,10 @@
 		omap_current_dss_features = &omap3430_dss_features;
 	else if (omap_rev() == OMAP4430_REV_ES1_0)
 		omap_current_dss_features = &omap4430_es1_0_dss_features;
+	else if (omap_rev() == OMAP4430_REV_ES2_0 ||
+		omap_rev() == OMAP4430_REV_ES2_1 ||
+		omap_rev() == OMAP4430_REV_ES2_2)
+		omap_current_dss_features = &omap4430_es2_0_1_2_dss_features;
 	else if (cpu_is_omap44xx())
 		omap_current_dss_features = &omap4_dss_features;
 	else
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index cd833bb..c332e7d 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -31,33 +31,37 @@
 
 /* DSS has feature id */
 enum dss_feat_id {
-	FEAT_LCDENABLEPOL		= 1 << 3,
-	FEAT_LCDENABLESIGNAL		= 1 << 4,
-	FEAT_PCKFREEENABLE		= 1 << 5,
-	FEAT_FUNCGATED			= 1 << 6,
-	FEAT_MGR_LCD2			= 1 << 7,
-	FEAT_LINEBUFFERSPLIT		= 1 << 8,
-	FEAT_ROWREPEATENABLE		= 1 << 9,
-	FEAT_RESIZECONF			= 1 << 10,
+	FEAT_LCDENABLEPOL,
+	FEAT_LCDENABLESIGNAL,
+	FEAT_PCKFREEENABLE,
+	FEAT_FUNCGATED,
+	FEAT_MGR_LCD2,
+	FEAT_LINEBUFFERSPLIT,
+	FEAT_ROWREPEATENABLE,
+	FEAT_RESIZECONF,
 	/* Independent core clk divider */
-	FEAT_CORE_CLK_DIV		= 1 << 11,
-	FEAT_LCD_CLK_SRC		= 1 << 12,
+	FEAT_CORE_CLK_DIV,
+	FEAT_LCD_CLK_SRC,
 	/* DSI-PLL power command 0x3 is not working */
-	FEAT_DSI_PLL_PWR_BUG		= 1 << 13,
-	FEAT_DSI_PLL_FREQSEL		= 1 << 14,
-	FEAT_DSI_DCS_CMD_CONFIG_VC	= 1 << 15,
-	FEAT_DSI_VC_OCP_WIDTH		= 1 << 16,
-	FEAT_DSI_REVERSE_TXCLKESC	= 1 << 17,
-	FEAT_DSI_GNQ			= 1 << 18,
-	FEAT_HDMI_CTS_SWMODE		= 1 << 19,
-	FEAT_HANDLE_UV_SEPARATE         = 1 << 20,
-	FEAT_ATTR2                      = 1 << 21,
-	FEAT_VENC_REQUIRES_TV_DAC_CLK	= 1 << 22,
-	FEAT_CPR			= 1 << 23,
-	FEAT_PRELOAD			= 1 << 24,
-	FEAT_FIR_COEF_V			= 1 << 25,
-	FEAT_ALPHA_FIXED_ZORDER		= 1 << 26,
-	FEAT_ALPHA_FREE_ZORDER		= 1 << 27,
+	FEAT_DSI_PLL_PWR_BUG,
+	FEAT_DSI_PLL_FREQSEL,
+	FEAT_DSI_DCS_CMD_CONFIG_VC,
+	FEAT_DSI_VC_OCP_WIDTH,
+	FEAT_DSI_REVERSE_TXCLKESC,
+	FEAT_DSI_GNQ,
+	FEAT_HDMI_CTS_SWMODE,
+	FEAT_HDMI_AUDIO_USE_MCLK,
+	FEAT_HANDLE_UV_SEPARATE,
+	FEAT_ATTR2,
+	FEAT_VENC_REQUIRES_TV_DAC_CLK,
+	FEAT_CPR,
+	FEAT_PRELOAD,
+	FEAT_FIR_COEF_V,
+	FEAT_ALPHA_FIXED_ZORDER,
+	FEAT_ALPHA_FREE_ZORDER,
+	FEAT_FIFO_MERGE,
+	/* An unknown HW bug causing the normal FIFO thresholds not to work */
+	FEAT_OMAP3_DSI_FIFO_BUG,
 };
 
 /* DSS register field id */
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index a36b934..c4b4f69 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -58,8 +58,6 @@
 #define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR	4
 #define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR	4
 
-#define OMAP_HDMI_TIMINGS_NB			34
-
 #define HDMI_DEFAULT_REGN 16
 #define HDMI_DEFAULT_REGM2 1
 
@@ -68,8 +66,6 @@
 	struct omap_display_platform_data *pdata;
 	struct platform_device *pdev;
 	struct hdmi_ip_data ip_data;
-	int code;
-	int mode;
 
 	struct clk *sys_clk;
 } hdmi;
@@ -88,77 +84,46 @@
  * map it to corresponding CEA or VESA index.
  */
 
-static const struct hdmi_timings cea_vesa_timings[OMAP_HDMI_TIMINGS_NB] = {
-	{ {640, 480, 25200, 96, 16, 48, 2, 10, 33} , 0 , 0},
-	{ {1280, 720, 74250, 40, 440, 220, 5, 5, 20}, 1, 1},
-	{ {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1},
-	{ {720, 480, 27027, 62, 16, 60, 6, 9, 30}, 0, 0},
-	{ {2880, 576, 108000, 256, 48, 272, 5, 5, 39}, 0, 0},
-	{ {1440, 240, 27027, 124, 38, 114, 3, 4, 15}, 0, 0},
-	{ {1440, 288, 27000, 126, 24, 138, 3, 2, 19}, 0, 0},
-	{ {1920, 540, 74250, 44, 528, 148, 5, 2, 15}, 1, 1},
-	{ {1920, 540, 74250, 44, 88, 148, 5, 2, 15}, 1, 1},
-	{ {1920, 1080, 148500, 44, 88, 148, 5, 4, 36}, 1, 1},
-	{ {720, 576, 27000, 64, 12, 68, 5, 5, 39}, 0, 0},
-	{ {1440, 576, 54000, 128, 24, 136, 5, 5, 39}, 0, 0},
-	{ {1920, 1080, 148500, 44, 528, 148, 5, 4, 36}, 1, 1},
-	{ {2880, 480, 108108, 248, 64, 240, 6, 9, 30}, 0, 0},
-	{ {1920, 1080, 74250, 44, 638, 148, 5, 4, 36}, 1, 1},
-	/* VESA From Here */
-	{ {640, 480, 25175, 96, 16, 48, 2 , 11, 31}, 0, 0},
-	{ {800, 600, 40000, 128, 40, 88, 4 , 1, 23}, 1, 1},
-	{ {848, 480, 33750, 112, 16, 112, 8 , 6, 23}, 1, 1},
-	{ {1280, 768, 79500, 128, 64, 192, 7 , 3, 20}, 1, 0},
-	{ {1280, 800, 83500, 128, 72, 200, 6 , 3, 22}, 1, 0},
-	{ {1360, 768, 85500, 112, 64, 256, 6 , 3, 18}, 1, 1},
-	{ {1280, 960, 108000, 112, 96, 312, 3 , 1, 36}, 1, 1},
-	{ {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38}, 1, 1},
-	{ {1024, 768, 65000, 136, 24, 160, 6, 3, 29}, 0, 0},
-	{ {1400, 1050, 121750, 144, 88, 232, 4, 3, 32}, 1, 0},
-	{ {1440, 900, 106500, 152, 80, 232, 6, 3, 25}, 1, 0},
-	{ {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30}, 1, 0},
-	{ {1366, 768, 85500, 143, 70, 213, 3, 3, 24}, 1, 1},
-	{ {1920, 1080, 148500, 44, 148, 80, 5, 4, 36}, 1, 1},
-	{ {1280, 768, 68250, 32, 48, 80, 7, 3, 12}, 0, 1},
-	{ {1400, 1050, 101000, 32, 48, 80, 4, 3, 23}, 0, 1},
-	{ {1680, 1050, 119000, 32, 48, 80, 6, 3, 21}, 0, 1},
-	{ {1280, 800, 79500, 32, 48, 80, 6, 3, 14}, 0, 1},
-	{ {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1}
+static const struct hdmi_config cea_timings[] = {
+{ {640, 480, 25200, 96, 16, 48, 2, 10, 33, 0, 0, 0}, {1, HDMI_HDMI} },
+{ {720, 480, 27027, 62, 16, 60, 6, 9, 30, 0, 0, 0}, {2, HDMI_HDMI} },
+{ {1280, 720, 74250, 40, 110, 220, 5, 5, 20, 1, 1, 0}, {4, HDMI_HDMI} },
+{ {1920, 540, 74250, 44, 88, 148, 5, 2, 15, 1, 1, 1}, {5, HDMI_HDMI} },
+{ {1440, 240, 27027, 124, 38, 114, 3, 4, 15, 0, 0, 1}, {6, HDMI_HDMI} },
+{ {1920, 1080, 148500, 44, 88, 148, 5, 4, 36, 1, 1, 0}, {16, HDMI_HDMI} },
+{ {720, 576, 27000, 64, 12, 68, 5, 5, 39, 0, 0, 0}, {17, HDMI_HDMI} },
+{ {1280, 720, 74250, 40, 440, 220, 5, 5, 20, 1, 1, 0}, {19, HDMI_HDMI} },
+{ {1920, 540, 74250, 44, 528, 148, 5, 2, 15, 1, 1, 1}, {20, HDMI_HDMI} },
+{ {1440, 288, 27000, 126, 24, 138, 3, 2, 19, 0, 0, 1}, {21, HDMI_HDMI} },
+{ {1440, 576, 54000, 128, 24, 136, 5, 5, 39, 0, 0, 0}, {29, HDMI_HDMI} },
+{ {1920, 1080, 148500, 44, 528, 148, 5, 4, 36, 1, 1, 0}, {31, HDMI_HDMI} },
+{ {1920, 1080, 74250, 44, 638, 148, 5, 4, 36, 1, 1, 0}, {32, HDMI_HDMI} },
+{ {2880, 480, 108108, 248, 64, 240, 6, 9, 30, 0, 0, 0}, {35, HDMI_HDMI} },
+{ {2880, 576, 108000, 256, 48, 272, 5, 5, 39, 0, 0, 0}, {37, HDMI_HDMI} },
 };
-
-/*
- * This is a static mapping array which maps the timing values
- * with corresponding CEA / VESA code
- */
-static const int code_index[OMAP_HDMI_TIMINGS_NB] = {
-	1, 19, 4, 2, 37, 6, 21, 20, 5, 16, 17, 29, 31, 35, 32,
-	/* <--15 CEA 17--> vesa*/
-	4, 9, 0xE, 0x17, 0x1C, 0x27, 0x20, 0x23, 0x10, 0x2A,
-	0X2F, 0x3A, 0X51, 0X52, 0x16, 0x29, 0x39, 0x1B
+static const struct hdmi_config vesa_timings[] = {
+/* VESA From Here */
+{ {640, 480, 25175, 96, 16, 48, 2 , 11, 31, 0, 0, 0}, {4, HDMI_DVI} },
+{ {800, 600, 40000, 128, 40, 88, 4 , 1, 23, 1, 1, 0}, {9, HDMI_DVI} },
+{ {848, 480, 33750, 112, 16, 112, 8 , 6, 23, 1, 1, 0}, {0xE, HDMI_DVI} },
+{ {1280, 768, 79500, 128, 64, 192, 7 , 3, 20, 1, 0, 0}, {0x17, HDMI_DVI} },
+{ {1280, 800, 83500, 128, 72, 200, 6 , 3, 22, 1, 0, 0}, {0x1C, HDMI_DVI} },
+{ {1360, 768, 85500, 112, 64, 256, 6 , 3, 18, 1, 1, 0}, {0x27, HDMI_DVI} },
+{ {1280, 960, 108000, 112, 96, 312, 3 , 1, 36, 1, 1, 0}, {0x20, HDMI_DVI} },
+{ {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38, 1, 1, 0}, {0x23, HDMI_DVI} },
+{ {1024, 768, 65000, 136, 24, 160, 6, 3, 29, 0, 0, 0}, {0x10, HDMI_DVI} },
+{ {1400, 1050, 121750, 144, 88, 232, 4, 3, 32, 1, 0, 0}, {0x2A, HDMI_DVI} },
+{ {1440, 900, 106500, 152, 80, 232, 6, 3, 25, 1, 0, 0}, {0x2F, HDMI_DVI} },
+{ {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30, 1, 0, 0}, {0x3A, HDMI_DVI} },
+{ {1366, 768, 85500, 143, 70, 213, 3, 3, 24, 1, 1, 0}, {0x51, HDMI_DVI} },
+{ {1920, 1080, 148500, 44, 148, 80, 5, 4, 36, 1, 1, 0}, {0x52, HDMI_DVI} },
+{ {1280, 768, 68250, 32, 48, 80, 7, 3, 12, 0, 1, 0}, {0x16, HDMI_DVI} },
+{ {1400, 1050, 101000, 32, 48, 80, 4, 3, 23, 0, 1, 0}, {0x29, HDMI_DVI} },
+{ {1680, 1050, 119000, 32, 48, 80, 6, 3, 21, 0, 1, 0}, {0x39, HDMI_DVI} },
+{ {1280, 800, 79500, 32, 48, 80, 6, 3, 14, 0, 1, 0}, {0x1B, HDMI_DVI} },
+{ {1280, 720, 74250, 40, 110, 220, 5, 5, 20, 1, 1, 0}, {0x55, HDMI_DVI} }
 };
 
-/*
- * This is reverse static mapping which maps the CEA / VESA code
- * to the corresponding timing values
- */
-static const int code_cea[39] = {
-	-1,  0,  3,  3,  2,  8,  5,  5, -1, -1,
-	-1, -1, -1, -1, -1, -1,  9, 10, 10,  1,
-	7,   6,  6, -1, -1, -1, -1, -1, -1, 11,
-	11, 12, 14, -1, -1, 13, 13,  4,  4
-};
-
-static const int code_vesa[85] = {
-	-1, -1, -1, -1, 15, -1, -1, -1, -1, 16,
-	-1, -1, -1, -1, 17, -1, 23, -1, -1, -1,
-	-1, -1, 29, 18, -1, -1, -1, 32, 19, -1,
-	-1, -1, 21, -1, -1, 22, -1, -1, -1, 20,
-	-1, 30, 24, -1, -1, -1, -1, 25, -1, -1,
-	-1, -1, -1, -1, -1, -1, -1, 31, 26, -1,
-	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-	-1, 27, 28, -1, 33};
-
 static int hdmi_runtime_get(void)
 {
 	int r;
@@ -210,88 +175,89 @@
 	return 0;
 }
 
-static int get_timings_index(void)
+static const struct hdmi_config *hdmi_find_timing(
+					const struct hdmi_config *timings_arr,
+					int len)
 {
-	int code;
+	int i;
 
-	if (hdmi.mode == 0)
-		code = code_vesa[hdmi.code];
-	else
-		code = code_cea[hdmi.code];
-
-	if (code == -1)	{
-		/* HDMI code 4 corresponds to 640 * 480 VGA */
-		hdmi.code = 4;
-		/* DVI mode 1 corresponds to HDMI 0 to DVI */
-		hdmi.mode = HDMI_DVI;
-
-		code = code_vesa[hdmi.code];
+	for (i = 0; i < len; i++) {
+		if (timings_arr[i].cm.code == hdmi.ip_data.cfg.cm.code)
+			return &timings_arr[i];
 	}
-	return code;
+	return NULL;
+}
+
+static const struct hdmi_config *hdmi_get_timings(void)
+{
+       const struct hdmi_config *arr;
+       int len;
+
+       if (hdmi.ip_data.cfg.cm.mode == HDMI_DVI) {
+               arr = vesa_timings;
+               len = ARRAY_SIZE(vesa_timings);
+       } else {
+               arr = cea_timings;
+               len = ARRAY_SIZE(cea_timings);
+       }
+
+       return hdmi_find_timing(arr, len);
+}
+
+static bool hdmi_timings_compare(struct omap_video_timings *timing1,
+				const struct hdmi_video_timings *timing2)
+{
+	int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync;
+
+	if ((timing2->pixel_clock == timing1->pixel_clock) &&
+		(timing2->x_res == timing1->x_res) &&
+		(timing2->y_res == timing1->y_res)) {
+
+		timing2_hsync = timing2->hfp + timing2->hsw + timing2->hbp;
+		timing1_hsync = timing1->hfp + timing1->hsw + timing1->hbp;
+		timing2_vsync = timing2->vfp + timing2->vsw + timing2->vbp;
+		timing1_vsync = timing2->vfp + timing2->vsw + timing2->vbp;
+
+		DSSDBG("timing1_hsync = %d timing1_vsync = %d"\
+			"timing2_hsync = %d timing2_vsync = %d\n",
+			timing1_hsync, timing1_vsync,
+			timing2_hsync, timing2_vsync);
+
+		if ((timing1_hsync == timing2_hsync) &&
+			(timing1_vsync == timing2_vsync)) {
+			return true;
+		}
+	}
+	return false;
 }
 
 static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing)
 {
-	int i = 0, code = -1, temp_vsync = 0, temp_hsync = 0;
-	int timing_vsync = 0, timing_hsync = 0;
-	struct hdmi_video_timings temp;
+	int i;
 	struct hdmi_cm cm = {-1};
 	DSSDBG("hdmi_get_code\n");
 
-	for (i = 0; i < OMAP_HDMI_TIMINGS_NB; i++) {
-		temp = cea_vesa_timings[i].timings;
-		if ((temp.pixel_clock == timing->pixel_clock) &&
-			(temp.x_res == timing->x_res) &&
-			(temp.y_res == timing->y_res)) {
-
-			temp_hsync = temp.hfp + temp.hsw + temp.hbp;
-			timing_hsync = timing->hfp + timing->hsw + timing->hbp;
-			temp_vsync = temp.vfp + temp.vsw + temp.vbp;
-			timing_vsync = timing->vfp + timing->vsw + timing->vbp;
-
-			DSSDBG("temp_hsync = %d , temp_vsync = %d"
-				"timing_hsync = %d, timing_vsync = %d\n",
-				temp_hsync, temp_hsync,
-				timing_hsync, timing_vsync);
-
-			if ((temp_hsync == timing_hsync) &&
-					(temp_vsync == timing_vsync)) {
-				code = i;
-				cm.code = code_index[i];
-				if (code < 14)
-					cm.mode = HDMI_HDMI;
-				else
-					cm.mode = HDMI_DVI;
-				DSSDBG("Hdmi_code = %d mode = %d\n",
-					 cm.code, cm.mode);
-				break;
-			 }
+	for (i = 0; i < ARRAY_SIZE(cea_timings); i++) {
+		if (hdmi_timings_compare(timing, &cea_timings[i].timings)) {
+			cm = cea_timings[i].cm;
+			goto end;
+		}
+	}
+	for (i = 0; i < ARRAY_SIZE(vesa_timings); i++) {
+		if (hdmi_timings_compare(timing, &vesa_timings[i].timings)) {
+			cm = vesa_timings[i].cm;
+			goto end;
 		}
 	}
 
-	return cm;
-}
+end:	return cm;
 
-static void update_hdmi_timings(struct hdmi_config *cfg,
-		struct omap_video_timings *timings, int code)
-{
-	cfg->timings.timings.x_res = timings->x_res;
-	cfg->timings.timings.y_res = timings->y_res;
-	cfg->timings.timings.hbp = timings->hbp;
-	cfg->timings.timings.hfp = timings->hfp;
-	cfg->timings.timings.hsw = timings->hsw;
-	cfg->timings.timings.vbp = timings->vbp;
-	cfg->timings.timings.vfp = timings->vfp;
-	cfg->timings.timings.vsw = timings->vsw;
-	cfg->timings.timings.pixel_clock = timings->pixel_clock;
-	cfg->timings.vsync_pol = cea_vesa_timings[code].vsync_pol;
-	cfg->timings.hsync_pol = cea_vesa_timings[code].hsync_pol;
 }
 
 unsigned long hdmi_get_pixel_clock(void)
 {
 	/* HDMI Pixel Clock in Mhz */
-	return hdmi.ip_data.cfg.timings.timings.pixel_clock * 1000;
+	return hdmi.ip_data.cfg.timings.pixel_clock * 1000;
 }
 
 static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
@@ -312,24 +278,24 @@
 
 	refclk = clkin / pi->regn;
 
-	/*
-	 * multiplier is pixel_clk/ref_clk
-	 * Multiplying by 100 to avoid fractional part removal
-	 */
-	pi->regm = (phy * 100 / (refclk)) / 100;
-
 	if (dssdev->clocks.hdmi.regm2 == 0)
 		pi->regm2 = HDMI_DEFAULT_REGM2;
 	else
 		pi->regm2 = dssdev->clocks.hdmi.regm2;
 
 	/*
+	 * multiplier is pixel_clk/ref_clk
+	 * Multiplying by 100 to avoid fractional part removal
+	 */
+	pi->regm = phy * pi->regm2 / refclk;
+
+	/*
 	 * fractional multiplier is remainder of the difference between
 	 * multiplier and actual phy(required pixel clock thus should be
 	 * multiplied by 2^18(262144) divided by the reference clock
 	 */
-	mf = (phy - pi->regm * refclk) * 262144;
-	pi->regmf = mf / (refclk);
+	mf = (phy - pi->regm / pi->regm2 * refclk) * 262144;
+	pi->regmf = pi->regm2 * mf / refclk;
 
 	/*
 	 * Dcofreq should be set to 1 if required pixel clock
@@ -347,7 +313,8 @@
 
 static int hdmi_power_on(struct omap_dss_device *dssdev)
 {
-	int r, code = 0;
+	int r;
+	const struct hdmi_config *timing;
 	struct omap_video_timings *p;
 	unsigned long phy;
 
@@ -363,9 +330,16 @@
 		dssdev->panel.timings.x_res,
 		dssdev->panel.timings.y_res);
 
-	code = get_timings_index();
-	update_hdmi_timings(&hdmi.ip_data.cfg, p, code);
-
+	timing = hdmi_get_timings();
+	if (timing == NULL) {
+		/* HDMI code 4 corresponds to 640 * 480 VGA */
+		hdmi.ip_data.cfg.cm.code = 4;
+		/* DVI mode 1 corresponds to HDMI 0 to DVI */
+		hdmi.ip_data.cfg.cm.mode = HDMI_DVI;
+		hdmi.ip_data.cfg = vesa_timings[0];
+	} else {
+		hdmi.ip_data.cfg = *timing;
+	}
 	phy = p->pixel_clock;
 
 	hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data);
@@ -385,8 +359,6 @@
 		goto err;
 	}
 
-	hdmi.ip_data.cfg.cm.mode = hdmi.mode;
-	hdmi.ip_data.cfg.cm.code = hdmi.code;
 	hdmi.ip_data.ops->video_configure(&hdmi.ip_data);
 
 	/* Make selection of HDMI in DSS */
@@ -453,8 +425,8 @@
 	struct hdmi_cm cm;
 
 	cm = hdmi_get_code(&dssdev->panel.timings);
-	hdmi.code = cm.code;
-	hdmi.mode = cm.mode;
+	hdmi.ip_data.cfg.cm.code = cm.code;
+	hdmi.ip_data.cfg.cm.mode = cm.mode;
 
 	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
 		int r;
@@ -717,13 +689,15 @@
 	if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) {
 		core_cfg.aud_par_busclk = 0;
 		core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW;
-		core_cfg.use_mclk = false;
+		core_cfg.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK);
 	} else {
 		core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8);
 		core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW;
 		core_cfg.use_mclk = true;
-		core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS;
 	}
+
+	if (core_cfg.use_mclk)
+		core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS;
 	core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH;
 	core_cfg.en_spdif = false;
 	/* Use sample frequency from channel status word */
@@ -756,7 +730,7 @@
 static int hdmi_audio_startup(struct snd_pcm_substream *substream,
 				  struct snd_soc_dai *dai)
 {
-	if (!hdmi.mode) {
+	if (!hdmi.ip_data.cfg.cm.mode) {
 		pr_err("Current video settings do not support audio.\n");
 		return -EIO;
 	}
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index d1858e7..e736460 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -494,6 +494,11 @@
 {
 	unsigned long timeout = msecs_to_jiffies(500);
 	u32 irq;
+	int r;
+
+	r = dispc_runtime_get();
+	if (r)
+		return r;
 
 	if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) {
 		irq = DISPC_IRQ_EVSYNC_ODD;
@@ -505,7 +510,12 @@
 		else
 			irq = DISPC_IRQ_VSYNC2;
 	}
-	return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
+
+	r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
+
+	dispc_runtime_put();
+
+	return r;
 }
 
 int dss_init_overlay_managers(struct platform_device *pdev)
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index 55f3980..788a0ef 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -922,35 +922,34 @@
 	rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
 	if (!rfbi_mem) {
 		DSSERR("can't get IORESOURCE_MEM RFBI\n");
-		r = -EINVAL;
-		goto err_ioremap;
+		return -EINVAL;
 	}
-	rfbi.base = ioremap(rfbi_mem->start, resource_size(rfbi_mem));
+
+	rfbi.base = devm_ioremap(&pdev->dev, rfbi_mem->start,
+				 resource_size(rfbi_mem));
 	if (!rfbi.base) {
 		DSSERR("can't ioremap RFBI\n");
-		r = -ENOMEM;
-		goto err_ioremap;
+		return -ENOMEM;
 	}
 
-	pm_runtime_enable(&pdev->dev);
-
-	r = rfbi_runtime_get();
-	if (r)
-		goto err_get_rfbi;
-
-	msleep(10);
-
 	clk = clk_get(&pdev->dev, "ick");
 	if (IS_ERR(clk)) {
 		DSSERR("can't get ick\n");
-		r = PTR_ERR(clk);
-		goto err_get_ick;
+		return PTR_ERR(clk);
 	}
 
 	rfbi.l4_khz = clk_get_rate(clk) / 1000;
 
 	clk_put(clk);
 
+	pm_runtime_enable(&pdev->dev);
+
+	r = rfbi_runtime_get();
+	if (r)
+		goto err_runtime_get;
+
+	msleep(10);
+
 	rev = rfbi_read_reg(RFBI_REVISION);
 	dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n",
 	       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
@@ -959,19 +958,14 @@
 
 	return 0;
 
-err_get_ick:
-	rfbi_runtime_put();
-err_get_rfbi:
+err_runtime_get:
 	pm_runtime_disable(&pdev->dev);
-	iounmap(rfbi.base);
-err_ioremap:
 	return r;
 }
 
 static int omap_rfbihw_remove(struct platform_device *pdev)
 {
 	pm_runtime_disable(&pdev->dev);
-	iounmap(rfbi.base);
 	return 0;
 }
 
diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h
index 50dadba..1f58b84 100644
--- a/drivers/video/omap2/dss/ti_hdmi.h
+++ b/drivers/video/omap2/dss/ti_hdmi.h
@@ -42,6 +42,7 @@
 	HDMI_REFSEL_SYSCLK = 3
 };
 
+/* HDMI timing structure */
 struct hdmi_video_timings {
 	u16 x_res;
 	u16 y_res;
@@ -53,13 +54,9 @@
 	u16 vsw;
 	u16 vfp;
 	u16 vbp;
-};
-
-/* HDMI timing structure */
-struct hdmi_timings {
-	struct hdmi_video_timings timings;
-	int vsync_pol;
-	int hsync_pol;
+	bool vsync_pol;
+	bool hsync_pol;
+	bool interlace;
 };
 
 struct hdmi_cm {
@@ -68,8 +65,7 @@
 };
 
 struct hdmi_config {
-	struct hdmi_timings timings;
-	u16	interlace;
+	struct hdmi_video_timings timings;
 	struct hdmi_cm cm;
 };
 
@@ -117,6 +113,47 @@
 
 };
 
+/*
+ * Refer to section 8.2 in HDMI 1.3 specification for
+ * details about infoframe databytes
+ */
+struct hdmi_core_infoframe_avi {
+	/* Y0, Y1 rgb,yCbCr */
+	u8	db1_format;
+	/* A0  Active information Present */
+	u8	db1_active_info;
+	/* B0, B1 Bar info data valid */
+	u8	db1_bar_info_dv;
+	/* S0, S1 scan information */
+	u8	db1_scan_info;
+	/* C0, C1 colorimetry */
+	u8	db2_colorimetry;
+	/* M0, M1 Aspect ratio (4:3, 16:9) */
+	u8	db2_aspect_ratio;
+	/* R0...R3 Active format aspect ratio */
+	u8	db2_active_fmt_ar;
+	/* ITC IT content. */
+	u8	db3_itc;
+	/* EC0, EC1, EC2 Extended colorimetry */
+	u8	db3_ec;
+	/* Q1, Q0 Quantization range */
+	u8	db3_q_range;
+	/* SC1, SC0 Non-uniform picture scaling */
+	u8	db3_nup_scaling;
+	/* VIC0..6 Video format identification */
+	u8	db4_videocode;
+	/* PR0..PR3 Pixel repetition factor */
+	u8	db5_pixel_repeat;
+	/* Line number end of top bar */
+	u16	db6_7_line_eoftop;
+	/* Line number start of bottom bar */
+	u16	db8_9_line_sofbottom;
+	/* Pixel number end of left bar */
+	u16	db10_11_pixel_eofleft;
+	/* Pixel number start of right bar */
+	u16	db12_13_pixel_sofright;
+};
+
 struct hdmi_ip_data {
 	void __iomem	*base_wp;	/* HDMI wrapper */
 	unsigned long	core_sys_offset;
@@ -126,6 +163,7 @@
 	const struct ti_hdmi_ip_ops *ops;
 	struct hdmi_config cfg;
 	struct hdmi_pll_info pll_data;
+	struct hdmi_core_infoframe_avi avi_cfg;
 
 	/* ti_hdmi_4xxx_ip private data. These should be in a separate struct */
 	int hpd_gpio;
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
index 6847a47..bfe6fe6 100644
--- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
+++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
@@ -587,12 +587,12 @@
 			HDMI_CORE_SYS_TMDS_CTRL, cfg->tclk_sel_clkmult, 6, 5);
 }
 
-static void hdmi_core_aux_infoframe_avi_config(struct hdmi_ip_data *ip_data,
-		struct hdmi_core_infoframe_avi info_avi)
+static void hdmi_core_aux_infoframe_avi_config(struct hdmi_ip_data *ip_data)
 {
 	u32 val;
 	char sum = 0, checksum = 0;
 	void __iomem *av_base = hdmi_av_base(ip_data);
+	struct hdmi_core_infoframe_avi info_avi = ip_data->avi_cfg;
 
 	sum += 0x82 + 0x002 + 0x00D;
 	hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_TYPE, 0x082);
@@ -682,8 +682,7 @@
 }
 
 static void hdmi_wp_init(struct omap_video_timings *timings,
-			struct hdmi_video_format *video_fmt,
-			struct hdmi_video_interface *video_int)
+			struct hdmi_video_format *video_fmt)
 {
 	pr_debug("Enter hdmi_wp_init\n");
 
@@ -698,12 +697,6 @@
 	video_fmt->y_res = 0;
 	video_fmt->x_res = 0;
 
-	video_int->vsp = 0;
-	video_int->hsp = 0;
-
-	video_int->interlacing = 0;
-	video_int->tm = 0; /* HDMI_TIMING_SLAVE */
-
 }
 
 void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start)
@@ -716,15 +709,15 @@
 {
 	pr_debug("Enter hdmi_wp_video_init_format\n");
 
-	video_fmt->y_res = param->timings.timings.y_res;
-	video_fmt->x_res = param->timings.timings.x_res;
+	video_fmt->y_res = param->timings.y_res;
+	video_fmt->x_res = param->timings.x_res;
 
-	timings->hbp = param->timings.timings.hbp;
-	timings->hfp = param->timings.timings.hfp;
-	timings->hsw = param->timings.timings.hsw;
-	timings->vbp = param->timings.timings.vbp;
-	timings->vfp = param->timings.timings.vfp;
-	timings->vsw = param->timings.timings.vsw;
+	timings->hbp = param->timings.hbp;
+	timings->hfp = param->timings.hfp;
+	timings->hsw = param->timings.hsw;
+	timings->vbp = param->timings.vbp;
+	timings->vfp = param->timings.vfp;
+	timings->vsw = param->timings.vsw;
 }
 
 static void hdmi_wp_video_config_format(struct hdmi_ip_data *ip_data,
@@ -740,17 +733,16 @@
 	hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_SIZE, l);
 }
 
-static void hdmi_wp_video_config_interface(struct hdmi_ip_data *ip_data,
-		struct hdmi_video_interface *video_int)
+static void hdmi_wp_video_config_interface(struct hdmi_ip_data *ip_data)
 {
 	u32 r;
 	pr_debug("Enter hdmi_wp_video_config_interface\n");
 
 	r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG);
-	r = FLD_MOD(r, video_int->vsp, 7, 7);
-	r = FLD_MOD(r, video_int->hsp, 6, 6);
-	r = FLD_MOD(r, video_int->interlacing, 3, 3);
-	r = FLD_MOD(r, video_int->tm, 1, 0);
+	r = FLD_MOD(r, ip_data->cfg.timings.vsync_pol, 7, 7);
+	r = FLD_MOD(r, ip_data->cfg.timings.hsync_pol, 6, 6);
+	r = FLD_MOD(r, ip_data->cfg.timings.interlace, 3, 3);
+	r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */
 	hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, r);
 }
 
@@ -778,15 +770,13 @@
 	/* HDMI */
 	struct omap_video_timings video_timing;
 	struct hdmi_video_format video_format;
-	struct hdmi_video_interface video_interface;
 	/* HDMI core */
-	struct hdmi_core_infoframe_avi avi_cfg;
+	struct hdmi_core_infoframe_avi avi_cfg = ip_data->avi_cfg;
 	struct hdmi_core_video_config v_core_cfg;
 	struct hdmi_core_packet_enable_repeat repeat_cfg;
 	struct hdmi_config *cfg = &ip_data->cfg;
 
-	hdmi_wp_init(&video_timing, &video_format,
-		&video_interface);
+	hdmi_wp_init(&video_timing, &video_format);
 
 	hdmi_core_init(&v_core_cfg,
 		&avi_cfg,
@@ -801,12 +791,7 @@
 
 	hdmi_wp_video_config_format(ip_data, &video_format);
 
-	video_interface.vsp = cfg->timings.vsync_pol;
-	video_interface.hsp = cfg->timings.hsync_pol;
-	video_interface.interlacing = cfg->interlace;
-	video_interface.tm = 1 ; /* HDMI_TIMING_MASTER_24BIT */
-
-	hdmi_wp_video_config_interface(ip_data, &video_interface);
+	hdmi_wp_video_config_interface(ip_data);
 
 	/*
 	 * configure core video part
@@ -848,7 +833,7 @@
 	avi_cfg.db10_11_pixel_eofleft = 0;
 	avi_cfg.db12_13_pixel_sofright = 0;
 
-	hdmi_core_aux_infoframe_avi_config(ip_data, avi_cfg);
+	hdmi_core_aux_infoframe_avi_config(ip_data);
 
 	/* enable/repeat the infoframe */
 	repeat_cfg.avi_infoframe = HDMI_PACKETENABLE;
@@ -1076,13 +1061,9 @@
 	u32 r;
 	void __iomem *av_base = hdmi_av_base(ip_data);
 
-	/* audio clock recovery parameters */
-	r = hdmi_read_reg(av_base, HDMI_CORE_AV_ACR_CTRL);
-	r = FLD_MOD(r, cfg->use_mclk, 2, 2);
-	r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1);
-	r = FLD_MOD(r, cfg->cts_mode, 0, 0);
-	hdmi_write_reg(av_base, HDMI_CORE_AV_ACR_CTRL, r);
-
+	/*
+	 * Parameters for generation of Audio Clock Recovery packets
+	 */
 	REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0);
 	REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0);
 	REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0);
@@ -1094,14 +1075,6 @@
 		REG_FLD_MOD(av_base,
 				HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0);
 	} else {
-		/*
-		 * HDMI IP uses this configuration to divide the MCLK to
-		 * update CTS value.
-		 */
-		REG_FLD_MOD(av_base,
-				HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0);
-
-		/* Configure clock for audio packets */
 		REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_1,
 				cfg->aud_par_busclk, 7, 0);
 		REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_2,
@@ -1110,6 +1083,25 @@
 				(cfg->aud_par_busclk >> 16), 7, 0);
 	}
 
+	/* Set ACR clock divisor */
+	REG_FLD_MOD(av_base,
+			HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0);
+
+	r = hdmi_read_reg(av_base, HDMI_CORE_AV_ACR_CTRL);
+	/*
+	 * Use TMDS clock for ACR packets. For devices that use
+	 * the MCLK, this is the first part of the MCLK initialization.
+	 */
+	r = FLD_MOD(r, 0, 2, 2);
+
+	r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1);
+	r = FLD_MOD(r, cfg->cts_mode, 0, 0);
+	hdmi_write_reg(av_base, HDMI_CORE_AV_ACR_CTRL, r);
+
+	/* For devices using MCLK, this completes its initialization. */
+	if (cfg->use_mclk)
+		REG_FLD_MOD(av_base, HDMI_CORE_AV_ACR_CTRL, 1, 2, 2);
+
 	/* Override of SPDIF sample frequency with value in I2S_CHST4 */
 	REG_FLD_MOD(av_base, HDMI_CORE_AV_SPDIF_CTRL,
 						cfg->fs_override, 1, 1);
@@ -1205,7 +1197,7 @@
 {
 	u32 r;
 	u32 deep_color = 0;
-	u32 pclk = ip_data->cfg.timings.timings.pixel_clock;
+	u32 pclk = ip_data->cfg.timings.pixel_clock;
 
 	if (n == NULL || cts == NULL)
 		return -EINVAL;
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h
index a442998..a14d1a0 100644
--- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h
+++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h
@@ -450,46 +450,6 @@
  * Refer to section 8.2 in HDMI 1.3 specification for
  * details about infoframe databytes
  */
-struct hdmi_core_infoframe_avi {
-	/* Y0, Y1 rgb,yCbCr */
-	u8	db1_format;
-	/* A0  Active information Present */
-	u8	db1_active_info;
-	/* B0, B1 Bar info data valid */
-	u8	db1_bar_info_dv;
-	/* S0, S1 scan information */
-	u8	db1_scan_info;
-	/* C0, C1 colorimetry */
-	u8	db2_colorimetry;
-	/* M0, M1 Aspect ratio (4:3, 16:9) */
-	u8	db2_aspect_ratio;
-	/* R0...R3 Active format aspect ratio */
-	u8	db2_active_fmt_ar;
-	/* ITC IT content. */
-	u8	db3_itc;
-	/* EC0, EC1, EC2 Extended colorimetry */
-	u8	db3_ec;
-	/* Q1, Q0 Quantization range */
-	u8	db3_q_range;
-	/* SC1, SC0 Non-uniform picture scaling */
-	u8	db3_nup_scaling;
-	/* VIC0..6 Video format identification */
-	u8	db4_videocode;
-	/* PR0..PR3 Pixel repetition factor */
-	u8	db5_pixel_repeat;
-	/* Line number end of top bar */
-	u16	db6_7_line_eoftop;
-	/* Line number start of bottom bar */
-	u16	db8_9_line_sofbottom;
-	/* Pixel number end of left bar */
-	u16	db10_11_pixel_eofleft;
-	/* Pixel number start of right bar */
-	u16	db12_13_pixel_sofright;
-};
-/*
- * Refer to section 8.2 in HDMI 1.3 specification for
- * details about infoframe databytes
- */
 struct hdmi_core_infoframe_audio {
 	u8 db1_coding_type;
 	u8 db1_channel_count;
@@ -517,13 +477,6 @@
 	u32			x_res;	/* pixel per line */
 };
 
-struct hdmi_video_interface {
-	int	vsp;	/* Vsync polarity */
-	int	hsp;	/* Hsync polarity */
-	int	interlacing;
-	int	tm;	/* Timing mode */
-};
-
 struct hdmi_audio_format {
 	enum hdmi_stereo_channels		stereo_channels;
 	u8					active_chnnls_msk;
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 5c3d0f9..9c3daf7 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -699,6 +699,11 @@
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
 
+	if (cpu_is_omap44xx()) {
+		seq_printf(s, "VENC currently disabled on OMAP44xx\n");
+		return;
+	}
+
 	if (venc_runtime_get())
 		return;
 
@@ -790,39 +795,41 @@
 	venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
 	if (!venc_mem) {
 		DSSERR("can't get IORESOURCE_MEM VENC\n");
-		r = -EINVAL;
-		goto err_ioremap;
+		return -EINVAL;
 	}
-	venc.base = ioremap(venc_mem->start, resource_size(venc_mem));
+
+	venc.base = devm_ioremap(&pdev->dev, venc_mem->start,
+				 resource_size(venc_mem));
 	if (!venc.base) {
 		DSSERR("can't ioremap VENC\n");
-		r = -ENOMEM;
-		goto err_ioremap;
+		return -ENOMEM;
 	}
 
 	r = venc_get_clocks(pdev);
 	if (r)
-		goto err_get_clk;
+		return r;
 
 	pm_runtime_enable(&pdev->dev);
 
 	r = venc_runtime_get();
 	if (r)
-		goto err_get_venc;
+		goto err_runtime_get;
 
 	rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
 	dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
 
 	venc_runtime_put();
 
-	return omap_dss_register_driver(&venc_driver);
+	r = omap_dss_register_driver(&venc_driver);
+	if (r)
+		goto err_reg_panel_driver;
 
-err_get_venc:
+	return 0;
+
+err_reg_panel_driver:
+err_runtime_get:
 	pm_runtime_disable(&pdev->dev);
 	venc_put_clocks();
-err_get_clk:
-	iounmap(venc.base);
-err_ioremap:
 	return r;
 }
 
@@ -837,7 +844,6 @@
 	pm_runtime_disable(&pdev->dev);
 	venc_put_clocks();
 
-	iounmap(venc.base);
 	return 0;
 }
 
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
index 16ba619..6a09ef8 100644
--- a/drivers/video/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -215,7 +215,7 @@
 	int r = 0, i;
 	size_t size;
 
-	if (mi->type > OMAPFB_MEMTYPE_MAX)
+	if (mi->type != OMAPFB_MEMTYPE_SDRAM)
 		return -EINVAL;
 
 	size = PAGE_ALIGN(mi->size);
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index ce15831..b00db40 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -1399,7 +1399,7 @@
 
 	if (!paddr) {
 		DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
-		r = omap_vram_alloc(OMAP_VRAM_MEMTYPE_SDRAM, size, &paddr);
+		r = omap_vram_alloc(size, &paddr);
 	} else {
 		DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr,
 				ofbi->id);
@@ -1487,60 +1487,6 @@
 	return omapfb_alloc_fbmem(fbi, size, paddr);
 }
 
-static enum omap_color_mode fb_format_to_dss_mode(enum omapfb_color_format fmt)
-{
-	enum omap_color_mode mode;
-
-	switch (fmt) {
-	case OMAPFB_COLOR_RGB565:
-		mode = OMAP_DSS_COLOR_RGB16;
-		break;
-	case OMAPFB_COLOR_YUV422:
-		mode = OMAP_DSS_COLOR_YUV2;
-		break;
-	case OMAPFB_COLOR_CLUT_8BPP:
-		mode = OMAP_DSS_COLOR_CLUT8;
-		break;
-	case OMAPFB_COLOR_CLUT_4BPP:
-		mode = OMAP_DSS_COLOR_CLUT4;
-		break;
-	case OMAPFB_COLOR_CLUT_2BPP:
-		mode = OMAP_DSS_COLOR_CLUT2;
-		break;
-	case OMAPFB_COLOR_CLUT_1BPP:
-		mode = OMAP_DSS_COLOR_CLUT1;
-		break;
-	case OMAPFB_COLOR_RGB444:
-		mode = OMAP_DSS_COLOR_RGB12U;
-		break;
-	case OMAPFB_COLOR_YUY422:
-		mode = OMAP_DSS_COLOR_UYVY;
-		break;
-	case OMAPFB_COLOR_ARGB16:
-		mode = OMAP_DSS_COLOR_ARGB16;
-		break;
-	case OMAPFB_COLOR_RGB24U:
-		mode = OMAP_DSS_COLOR_RGB24U;
-		break;
-	case OMAPFB_COLOR_RGB24P:
-		mode = OMAP_DSS_COLOR_RGB24P;
-		break;
-	case OMAPFB_COLOR_ARGB32:
-		mode = OMAP_DSS_COLOR_ARGB32;
-		break;
-	case OMAPFB_COLOR_RGBA32:
-		mode = OMAP_DSS_COLOR_RGBA32;
-		break;
-	case OMAPFB_COLOR_RGBX32:
-		mode = OMAP_DSS_COLOR_RGBX32;
-		break;
-	default:
-		mode = -EINVAL;
-	}
-
-	return mode;
-}
-
 static int omapfb_parse_vram_param(const char *param, int max_entries,
 		unsigned long *sizes, unsigned long *paddrs)
 {
@@ -1614,23 +1560,6 @@
 		memset(&vram_paddrs, 0, sizeof(vram_paddrs));
 	}
 
-	if (fbdev->dev->platform_data) {
-		struct omapfb_platform_data *opd;
-		opd = fbdev->dev->platform_data;
-		for (i = 0; i < opd->mem_desc.region_cnt; ++i) {
-			if (!vram_sizes[i]) {
-				unsigned long size;
-				unsigned long paddr;
-
-				size = opd->mem_desc.region[i].size;
-				paddr = opd->mem_desc.region[i].paddr;
-
-				vram_sizes[i] = size;
-				vram_paddrs[i] = paddr;
-			}
-		}
-	}
-
 	for (i = 0; i < fbdev->num_fbs; i++) {
 		/* allocate memory automatically only for fb0, or if
 		 * excplicitly defined with vram or plat data option */
@@ -1669,7 +1598,7 @@
 	int old_type = rg->type;
 	int r;
 
-	if (type > OMAPFB_MEMTYPE_MAX)
+	if (type != OMAPFB_MEMTYPE_SDRAM)
 		return -EINVAL;
 
 	size = PAGE_ALIGN(size);
@@ -1828,32 +1757,6 @@
 
 	var->rotate = def_rotate;
 
-	/*
-	 * Check if there is a default color format set in the board file,
-	 * and use this format instead the default deducted from the
-	 * display bpp.
-	 */
-	if (fbdev->dev->platform_data) {
-		struct omapfb_platform_data *opd;
-		int id = ofbi->id;
-
-		opd = fbdev->dev->platform_data;
-		if (opd->mem_desc.region[id].format_used) {
-			enum omap_color_mode mode;
-			enum omapfb_color_format format;
-
-			format = opd->mem_desc.region[id].format;
-			mode = fb_format_to_dss_mode(format);
-			if (mode < 0) {
-				r = mode;
-				goto err;
-			}
-			r = dss_mode_to_fb_mode(mode, var);
-			if (r < 0)
-				goto err;
-		}
-	}
-
 	if (display) {
 		u16 w, h;
 		int rotation = (var->rotate + ofbi->rotation[0]) % 4;
diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c
index 9441e2e..87e421e 100644
--- a/drivers/video/omap2/vram.c
+++ b/drivers/video/omap2/vram.c
@@ -33,7 +33,6 @@
 
 #include <asm/setup.h>
 
-#include <plat/sram.h>
 #include <plat/vram.h>
 #include <plat/dma.h>
 
@@ -43,10 +42,6 @@
 #define DBG(format, ...)
 #endif
 
-#define OMAP2_SRAM_START		0x40200000
-/* Maximum size, in reality this is smaller if SRAM is partially locked. */
-#define OMAP2_SRAM_SIZE			0xa0000		/* 640k */
-
 /* postponed regions are used to temporarily store region information at boot
  * time when we cannot yet allocate the region list */
 #define MAX_POSTPONED_REGIONS 10
@@ -74,15 +69,6 @@
 static DEFINE_MUTEX(region_mutex);
 static LIST_HEAD(region_list);
 
-static inline int region_mem_type(unsigned long paddr)
-{
-	if (paddr >= OMAP2_SRAM_START &&
-	    paddr < OMAP2_SRAM_START + OMAP2_SRAM_SIZE)
-		return OMAP_VRAM_MEMTYPE_SRAM;
-	else
-		return OMAP_VRAM_MEMTYPE_SDRAM;
-}
-
 static struct vram_region *omap_vram_create_region(unsigned long paddr,
 		unsigned pages)
 {
@@ -212,9 +198,6 @@
 
 		DBG("checking region %lx %d\n", rm->paddr, rm->pages);
 
-		if (region_mem_type(rm->paddr) != region_mem_type(paddr))
-			continue;
-
 		start = rm->paddr;
 		end = start + (rm->pages << PAGE_SHIFT) - 1;
 		if (start > paddr || end < paddr + size - 1)
@@ -320,7 +303,7 @@
 	return r;
 }
 
-static int _omap_vram_alloc(int mtype, unsigned pages, unsigned long *paddr)
+static int _omap_vram_alloc(unsigned pages, unsigned long *paddr)
 {
 	struct vram_region *rm;
 	struct vram_alloc *alloc;
@@ -330,9 +313,6 @@
 
 		DBG("checking region %lx %d\n", rm->paddr, rm->pages);
 
-		if (region_mem_type(rm->paddr) != mtype)
-			continue;
-
 		start = rm->paddr;
 
 		list_for_each_entry(alloc, &rm->alloc_list, list) {
@@ -365,21 +345,21 @@
 	return -ENOMEM;
 }
 
-int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr)
+int omap_vram_alloc(size_t size, unsigned long *paddr)
 {
 	unsigned pages;
 	int r;
 
-	BUG_ON(mtype > OMAP_VRAM_MEMTYPE_MAX || !size);
+	BUG_ON(!size);
 
-	DBG("alloc mem type %d size %d\n", mtype, size);
+	DBG("alloc mem size %d\n", size);
 
 	size = PAGE_ALIGN(size);
 	pages = size >> PAGE_SHIFT;
 
 	mutex_lock(&region_mutex);
 
-	r = _omap_vram_alloc(mtype, pages, paddr);
+	r = _omap_vram_alloc(pages, paddr);
 
 	mutex_unlock(&region_mutex);
 
@@ -501,10 +481,6 @@
 /* boottime vram alloc stuff */
 
 /* set from board file */
-static u32 omap_vram_sram_start __initdata;
-static u32 omap_vram_sram_size __initdata;
-
-/* set from board file */
 static u32 omap_vram_sdram_start __initdata;
 static u32 omap_vram_sdram_size __initdata;
 
@@ -587,73 +563,8 @@
 	pr_info("Reserving %u bytes SDRAM for VRAM\n", size);
 }
 
-/*
- * Called at sram init time, before anything is pushed to the SRAM stack.
- * Because of the stack scheme, we will allocate everything from the
- * start of the lowest address region to the end of SRAM. This will also
- * include padding for page alignment and possible holes between regions.
- *
- * As opposed to the SDRAM case, we'll also do any dynamic allocations at
- * this point, since the driver built as a module would have problem with
- * freeing / reallocating the regions.
- */
-unsigned long __init omap_vram_reserve_sram(unsigned long sram_pstart,
-				  unsigned long sram_vstart,
-				  unsigned long sram_size,
-				  unsigned long pstart_avail,
-				  unsigned long size_avail)
-{
-	unsigned long			pend_avail;
-	unsigned long			reserved;
-	u32 paddr;
-	u32 size;
-
-	paddr = omap_vram_sram_start;
-	size = omap_vram_sram_size;
-
-	if (!size)
-		return 0;
-
-	reserved = 0;
-	pend_avail = pstart_avail + size_avail;
-
-	if (!paddr) {
-		/* Dynamic allocation */
-		if ((size_avail & PAGE_MASK) < size) {
-			pr_err("Not enough SRAM for VRAM\n");
-			return 0;
-		}
-		size_avail = (size_avail - size) & PAGE_MASK;
-		paddr = pstart_avail + size_avail;
-	}
-
-	if (paddr < sram_pstart ||
-			paddr + size > sram_pstart + sram_size) {
-		pr_err("Illegal SRAM region for VRAM\n");
-		return 0;
-	}
-
-	/* Reserve everything above the start of the region. */
-	if (pend_avail - paddr > reserved)
-		reserved = pend_avail - paddr;
-	size_avail = pend_avail - reserved - pstart_avail;
-
-	omap_vram_add_region(paddr, size);
-
-	if (reserved)
-		pr_info("Reserving %lu bytes SRAM for VRAM\n", reserved);
-
-	return reserved;
-}
-
 void __init omap_vram_set_sdram_vram(u32 size, u32 start)
 {
 	omap_vram_sdram_start = start;
 	omap_vram_sdram_size = size;
 }
-
-void __init omap_vram_set_sram_vram(u32 size, u32 start)
-{
-	omap_vram_sram_start = start;
-	omap_vram_sram_size = size;
-}
diff --git a/drivers/video/omap2/vrfb.c b/drivers/video/omap2/vrfb.c
index fd22716..4e5b960 100644
--- a/drivers/video/omap2/vrfb.c
+++ b/drivers/video/omap2/vrfb.c
@@ -27,7 +27,6 @@
 #include <linux/bitops.h>
 #include <linux/mutex.h>
 
-#include <mach/io.h>
 #include <plat/vrfb.h>
 #include <plat/sdrc.h>
 
diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c
index 0c69fa2..9b4a60b 100644
--- a/drivers/video/pmag-ba-fb.c
+++ b/drivers/video/pmag-ba-fb.c
@@ -33,7 +33,6 @@
 #include <linux/types.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <video/pmag-ba-fb.h>
 
diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c
index 22fcb9a..4e7a9c4 100644
--- a/drivers/video/pmagb-b-fb.c
+++ b/drivers/video/pmagb-b-fb.c
@@ -29,7 +29,6 @@
 #include <linux/types.h>
 
 #include <asm/io.h>
-#include <asm/system.h>
 
 #include <video/pmagb-b-fb.h>
 
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
index 3a3fdc6..bcd44c3 100644
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -895,7 +895,7 @@
 
 #ifdef CONFIG_PVR2_DMA
 	if (request_dma(pvr2dma, "pvr2") != 0) {
-		free_irq(HW_EVENT_VSYNC, 0);
+		free_irq(HW_EVENT_VSYNC, fb_info);
 		return -EBUSY;
 	}
 #endif
@@ -914,7 +914,7 @@
 		currentpar->mmio_base = 0;
 	}
 
-	free_irq(HW_EVENT_VSYNC, 0);
+	free_irq(HW_EVENT_VSYNC, fb_info);
 #ifdef CONFIG_PVR2_DMA
 	free_dma(pvr2dma);
 #endif
diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c
index 8384b94..f146089 100644
--- a/drivers/video/pxa168fb.c
+++ b/drivers/video/pxa168fb.c
@@ -21,6 +21,7 @@
 #include <linux/fb.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
@@ -670,7 +671,8 @@
 	/*
 	 * Map LCD controller registers.
 	 */
-	fbi->reg_base = ioremap_nocache(res->start, resource_size(res));
+	fbi->reg_base = devm_ioremap_nocache(&pdev->dev, res->start,
+					     resource_size(res));
 	if (fbi->reg_base == NULL) {
 		ret = -ENOMEM;
 		goto failed_free_info;
@@ -739,8 +741,8 @@
 	/*
 	 * Register irq handler.
 	 */
-	ret = request_irq(irq, pxa168fb_handle_irq, IRQF_SHARED,
-					info->fix.id, fbi);
+	ret = devm_request_irq(&pdev->dev, irq, pxa168fb_handle_irq,
+			       IRQF_SHARED, info->fix.id, fbi);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "unable to request IRQ\n");
 		ret = -ENXIO;
@@ -759,14 +761,12 @@
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Failed to register pxa168-fb: %d\n", ret);
 		ret = -ENXIO;
-		goto failed_free_irq;
+		goto failed_free_cmap;
 	}
 
 	platform_set_drvdata(pdev, fbi);
 	return 0;
 
-failed_free_irq:
-	free_irq(irq, fbi);
 failed_free_cmap:
 	fb_dealloc_cmap(&info->cmap);
 failed_free_clk:
@@ -808,13 +808,10 @@
 		fb_dealloc_cmap(&info->cmap);
 
 	irq = platform_get_irq(pdev, 0);
-	free_irq(irq, fbi);
 
 	dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
 				info->screen_base, info->fix.smem_start);
 
-	iounmap(fbi->reg_base);
-
 	clk_disable(fbi->clk);
 	clk_put(fbi->clk);
 
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 1d1e4f1..3f90255 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -54,6 +54,7 @@
 #include <linux/mutex.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
+#include <linux/console.h>
 
 #include <mach/hardware.h>
 #include <asm/io.h>
@@ -730,9 +731,12 @@
 	if (user == 0)
 		return -ENODEV;
 
-	if (ofb->usage++ == 0)
+	if (ofb->usage++ == 0) {
 		/* unblank the base framebuffer */
+		console_lock();
 		fb_blank(&ofb->fbi->fb, FB_BLANK_UNBLANK);
+		console_unlock();
+	}
 
 	return 0;
 }
@@ -1431,7 +1435,7 @@
 	pr_debug("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3);
 
 	/* enable LCD controller clock */
-	clk_enable(fbi->clk);
+	clk_prepare_enable(fbi->clk);
 
 	if (fbi->lccr0 & LCCR0_LCDT)
 		return;
@@ -1471,7 +1475,7 @@
 	wait_for_completion_timeout(&fbi->disable_done, 200 * HZ / 1000);
 
 	/* disable LCD controller clock */
-	clk_disable(fbi->clk);
+	clk_disable_unprepare(fbi->clk);
 }
 
 /*
diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c
index f5a39f5..a104e8c 100644
--- a/drivers/video/q40fb.c
+++ b/drivers/video/q40fb.c
@@ -20,7 +20,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/setup.h>
-#include <asm/system.h>
 #include <asm/q40_master.h>
 #include <linux/fb.h>
 #include <linux/module.h>
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 2f58cf9..90df1a6 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -1816,6 +1816,8 @@
 			     specs->modedb, specs->modedb_len,
 			     NULL, 8);
 	} else if (specs->modedb != NULL) {
+		/* get first mode in database as fallback */
+		modedb = specs->modedb[0];
 		/* get preferred timing */
 		if (info->monspecs.misc & FB_MISC_1ST_DETAIL) {
 			int i;
@@ -1826,9 +1828,6 @@
 					break;
 				}
 			}
-		} else {
-			/* otherwise, get first mode in database */
-			modedb = specs->modedb[0];
 		}
 		var->bits_per_pixel = 8;
 		riva_update_var(var, &modedb);
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index 0c63b69..f310516 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -48,7 +48,8 @@
 #undef writel
 #define writel(v, r) do { \
 	printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \
-	__raw_writel(v, r); } while (0)
+	__raw_writel(v, r); \
+} while (0)
 #endif /* FB_S3C_DEBUG_REGWRITE */
 
 /* irq_flags bits */
@@ -81,12 +82,14 @@
  * @palette: Address of palette memory, or 0 if none.
  * @has_prtcon: Set if has PRTCON register.
  * @has_shadowcon: Set if has SHADOWCON register.
+ * @has_blendcon: Set if has BLENDCON register.
  * @has_clksel: Set if VIDCON0 register has CLKSEL bit.
+ * @has_fixvclk: Set if VIDCON1 register has FIXVCLK bits.
  */
 struct s3c_fb_variant {
 	unsigned int	is_2443:1;
 	unsigned short	nr_windows;
-	unsigned short	vidtcon;
+	unsigned int	vidtcon;
 	unsigned short	wincon;
 	unsigned short	winmap;
 	unsigned short	keycon;
@@ -99,7 +102,9 @@
 
 	unsigned int	has_prtcon:1;
 	unsigned int	has_shadowcon:1;
+	unsigned int	has_blendcon:1;
 	unsigned int	has_clksel:1;
+	unsigned int	has_fixvclk:1;
 };
 
 /**
@@ -186,7 +191,6 @@
  * struct s3c_fb - overall hardware state of the hardware
  * @slock: The spinlock protection for this data sturcture.
  * @dev: The device that we bound to, for printing, etc.
- * @regs_res: The resource we claimed for the IO registers.
  * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
  * @lcd_clk: The clk (sclk) feeding pixclk.
  * @regs: The mapped hardware registers.
@@ -202,7 +206,6 @@
 struct s3c_fb {
 	spinlock_t		slock;
 	struct device		*dev;
-	struct resource		*regs_res;
 	struct clk		*bus_clk;
 	struct clk		*lcd_clk;
 	void __iomem		*regs;
@@ -565,7 +568,9 @@
 		writel(data, regs + sfb->variant.vidtcon + 4);
 
 		data = VIDTCON2_LINEVAL(var->yres - 1) |
-		       VIDTCON2_HOZVAL(var->xres - 1);
+		       VIDTCON2_HOZVAL(var->xres - 1) |
+		       VIDTCON2_LINEVAL_E(var->yres - 1) |
+		       VIDTCON2_HOZVAL_E(var->xres - 1);
 		writel(data, regs + sfb->variant.vidtcon + 8);
 	}
 
@@ -581,17 +586,23 @@
 
 	pagewidth = (var->xres * var->bits_per_pixel) >> 3;
 	data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) |
-	       VIDW_BUF_SIZE_PAGEWIDTH(pagewidth);
+	       VIDW_BUF_SIZE_PAGEWIDTH(pagewidth) |
+	       VIDW_BUF_SIZE_OFFSET_E(info->fix.line_length - pagewidth) |
+	       VIDW_BUF_SIZE_PAGEWIDTH_E(pagewidth);
 	writel(data, regs + sfb->variant.buf_size + (win_no * 4));
 
 	/* write 'OSD' registers to control position of framebuffer */
 
-	data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0);
+	data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0) |
+	       VIDOSDxA_TOPLEFT_X_E(0) | VIDOSDxA_TOPLEFT_Y_E(0);
 	writel(data, regs + VIDOSD_A(win_no, sfb->variant));
 
 	data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
 						     var->xres - 1)) |
-	       VIDOSDxB_BOTRIGHT_Y(var->yres - 1);
+	       VIDOSDxB_BOTRIGHT_Y(var->yres - 1) |
+	       VIDOSDxB_BOTRIGHT_X_E(s3c_fb_align_word(var->bits_per_pixel,
+						     var->xres - 1)) |
+	       VIDOSDxB_BOTRIGHT_Y_E(var->yres - 1);
 
 	writel(data, regs + VIDOSD_B(win_no, sfb->variant));
 
@@ -692,6 +703,17 @@
 	writel(data, regs + sfb->variant.wincon + (win_no * 4));
 	writel(0x0, regs + sfb->variant.winmap + (win_no * 4));
 
+	/* Set alpha value width */
+	if (sfb->variant.has_blendcon) {
+		data = readl(sfb->regs + BLENDCON);
+		data &= ~BLENDCON_NEW_MASK;
+		if (var->transp.length > 4)
+			data |= BLENDCON_NEW_8BIT_ALPHA_VALUE;
+		else
+			data |= BLENDCON_NEW_4BIT_ALPHA_VALUE;
+		writel(data, sfb->regs + BLENDCON);
+	}
+
 	shadow_protect_win(win, 0);
 
 	pm_runtime_put_sync(sfb->dev);
@@ -1346,6 +1368,7 @@
 	struct resource *res;
 	int win;
 	int ret = 0;
+	u32 reg;
 
 	platid = platform_get_device_id(pdev);
 	fbdrv = (struct s3c_fb_driverdata *)platid->driver_data;
@@ -1361,7 +1384,7 @@
 		return -EINVAL;
 	}
 
-	sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL);
+	sfb = devm_kzalloc(dev, sizeof(struct s3c_fb), GFP_KERNEL);
 	if (!sfb) {
 		dev_err(dev, "no memory for framebuffers\n");
 		return -ENOMEM;
@@ -1404,33 +1427,25 @@
 		goto err_lcd_clk;
 	}
 
-	sfb->regs_res = request_mem_region(res->start, resource_size(res),
-					   dev_name(dev));
-	if (!sfb->regs_res) {
-		dev_err(dev, "failed to claim register region\n");
-		ret = -ENOENT;
-		goto err_lcd_clk;
-	}
-
-	sfb->regs = ioremap(res->start, resource_size(res));
+	sfb->regs = devm_request_and_ioremap(dev, res);
 	if (!sfb->regs) {
 		dev_err(dev, "failed to map registers\n");
 		ret = -ENXIO;
-		goto err_req_region;
+		goto err_lcd_clk;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!res) {
 		dev_err(dev, "failed to acquire irq resource\n");
 		ret = -ENOENT;
-		goto err_ioremap;
+		goto err_lcd_clk;
 	}
 	sfb->irq_no = res->start;
-	ret = request_irq(sfb->irq_no, s3c_fb_irq,
+	ret = devm_request_irq(dev, sfb->irq_no, s3c_fb_irq,
 			  0, "s3c_fb", sfb);
 	if (ret) {
 		dev_err(dev, "irq request failed\n");
-		goto err_ioremap;
+		goto err_lcd_clk;
 	}
 
 	dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
@@ -1444,6 +1459,14 @@
 
 	writel(pd->vidcon1, sfb->regs + VIDCON1);
 
+	/* set video clock running at under-run */
+	if (sfb->variant.has_fixvclk) {
+		reg = readl(sfb->regs + VIDCON1);
+		reg &= ~VIDCON1_VCLK_MASK;
+		reg |= VIDCON1_VCLK_RUN;
+		writel(reg, sfb->regs + VIDCON1);
+	}
+
 	/* zero all windows before we do anything */
 
 	for (win = 0; win < fbdrv->variant.nr_windows; win++)
@@ -1484,13 +1507,6 @@
 
 err_pm_runtime:
 	pm_runtime_put_sync(sfb->dev);
-	free_irq(sfb->irq_no, sfb);
-
-err_ioremap:
-	iounmap(sfb->regs);
-
-err_req_region:
-	release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
 
 err_lcd_clk:
 	pm_runtime_disable(sfb->dev);
@@ -1505,7 +1521,6 @@
 	clk_put(sfb->bus_clk);
 
 err_sfb:
-	kfree(sfb);
 	return ret;
 }
 
@@ -1527,10 +1542,6 @@
 		if (sfb->windows[win])
 			s3c_fb_release_win(sfb, sfb->windows[win]);
 
-	free_irq(sfb->irq_no, sfb);
-
-	iounmap(sfb->regs);
-
 	if (!sfb->variant.has_clksel) {
 		clk_disable(sfb->lcd_clk);
 		clk_put(sfb->lcd_clk);
@@ -1539,12 +1550,9 @@
 	clk_disable(sfb->bus_clk);
 	clk_put(sfb->bus_clk);
 
-	release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
-
 	pm_runtime_put_sync(sfb->dev);
 	pm_runtime_disable(sfb->dev);
 
-	kfree(sfb);
 	return 0;
 }
 
@@ -1579,6 +1587,7 @@
 	struct s3c_fb_platdata *pd = sfb->pdata;
 	struct s3c_fb_win *win;
 	int win_no;
+	u32 reg;
 
 	clk_enable(sfb->bus_clk);
 
@@ -1589,6 +1598,14 @@
 	pd->setup_gpio();
 	writel(pd->vidcon1, sfb->regs + VIDCON1);
 
+	/* set video clock running at under-run */
+	if (sfb->variant.has_fixvclk) {
+		reg = readl(sfb->regs + VIDCON1);
+		reg &= ~VIDCON1_VCLK_MASK;
+		reg |= VIDCON1_VCLK_RUN;
+		writel(reg, sfb->regs + VIDCON1);
+	}
+
 	/* zero all windows before we do anything */
 	for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++)
 		s3c_fb_clear_win(sfb, win_no);
@@ -1819,6 +1836,7 @@
 		},
 
 		.has_prtcon	= 1,
+		.has_blendcon	= 1,
 		.has_clksel	= 1,
 	},
 	.win[0]	= &s3c_fb_data_s5p_wins[0],
@@ -1850,7 +1868,9 @@
 		},
 
 		.has_shadowcon	= 1,
+		.has_blendcon	= 1,
 		.has_clksel	= 1,
+		.has_fixvclk	= 1,
 	},
 	.win[0]	= &s3c_fb_data_s5p_wins[0],
 	.win[1]	= &s3c_fb_data_s5p_wins[1],
@@ -1881,6 +1901,39 @@
 		},
 
 		.has_shadowcon	= 1,
+		.has_blendcon	= 1,
+		.has_fixvclk	= 1,
+	},
+	.win[0]	= &s3c_fb_data_s5p_wins[0],
+	.win[1]	= &s3c_fb_data_s5p_wins[1],
+	.win[2]	= &s3c_fb_data_s5p_wins[2],
+	.win[3]	= &s3c_fb_data_s5p_wins[3],
+	.win[4]	= &s3c_fb_data_s5p_wins[4],
+};
+
+static struct s3c_fb_driverdata s3c_fb_data_exynos5 = {
+	.variant = {
+		.nr_windows	= 5,
+		.vidtcon	= VIDTCON0,
+		.wincon		= WINCON(0),
+		.winmap		= WINxMAP(0),
+		.keycon		= WKEYCON,
+		.osd		= VIDOSD_BASE,
+		.osd_stride	= 16,
+		.buf_start	= VIDW_BUF_START(0),
+		.buf_size	= VIDW_BUF_SIZE(0),
+		.buf_end	= VIDW_BUF_END(0),
+
+		.palette = {
+			[0] = 0x2400,
+			[1] = 0x2800,
+			[2] = 0x2c00,
+			[3] = 0x3000,
+			[4] = 0x3400,
+		},
+		.has_shadowcon	= 1,
+		.has_blendcon	= 1,
+		.has_fixvclk	= 1,
 	},
 	.win[0]	= &s3c_fb_data_s5p_wins[0],
 	.win[1]	= &s3c_fb_data_s5p_wins[1],
@@ -1944,6 +1997,9 @@
 			[1] = 0x2800,
 			[2] = 0x2c00,
 		},
+
+		.has_blendcon	= 1,
+		.has_fixvclk	= 1,
 	},
 	.win[0] = &s3c_fb_data_s5p_wins[0],
 	.win[1] = &s3c_fb_data_s5p_wins[1],
@@ -1964,6 +2020,9 @@
 		.name		= "exynos4-fb",
 		.driver_data	= (unsigned long)&s3c_fb_data_exynos4,
 	}, {
+		.name		= "exynos5-fb",
+		.driver_data	= (unsigned long)&s3c_fb_data_exynos5,
+	}, {
 		.name		= "s3c2443-fb",
 		.driver_data	= (unsigned long)&s3c_fb_data_s3c2443,
 	}, {
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index 98d55d0..b632584 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -173,281 +173,47 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/cpufreq.h>
+#include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/mutex.h>
 #include <linux/io.h>
 
+#include <video/sa1100fb.h>
+
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <mach/assabet.h>
 #include <mach/shannon.h>
 
 /*
- * debugging?
- */
-#define DEBUG 0
-/*
  * Complain if VAR is out of range.
  */
 #define DEBUG_VAR 1
 
-#undef ASSABET_PAL_VIDEO
-
 #include "sa1100fb.h"
 
-extern void (*sa1100fb_backlight_power)(int on);
-extern void (*sa1100fb_lcd_power)(int on);
-
-static struct sa1100fb_rgb rgb_4 = {
+static const struct sa1100fb_rgb rgb_4 = {
 	.red	= { .offset = 0,  .length = 4, },
 	.green	= { .offset = 0,  .length = 4, },
 	.blue	= { .offset = 0,  .length = 4, },
 	.transp	= { .offset = 0,  .length = 0, },
 };
 
-static struct sa1100fb_rgb rgb_8 = {
+static const struct sa1100fb_rgb rgb_8 = {
 	.red	= { .offset = 0,  .length = 8, },
 	.green	= { .offset = 0,  .length = 8, },
 	.blue	= { .offset = 0,  .length = 8, },
 	.transp	= { .offset = 0,  .length = 0, },
 };
 
-static struct sa1100fb_rgb def_rgb_16 = {
+static const struct sa1100fb_rgb def_rgb_16 = {
 	.red	= { .offset = 11, .length = 5, },
 	.green	= { .offset = 5,  .length = 6, },
 	.blue	= { .offset = 0,  .length = 5, },
 	.transp	= { .offset = 0,  .length = 0, },
 };
 
-#ifdef CONFIG_SA1100_ASSABET
-#ifndef ASSABET_PAL_VIDEO
-/*
- * The assabet uses a sharp LQ039Q2DS54 LCD module.  It is actually
- * takes an RGB666 signal, but we provide it with an RGB565 signal
- * instead (def_rgb_16).
- */
-static struct sa1100fb_mach_info lq039q2ds54_info __initdata = {
-	.pixclock	= 171521,	.bpp		= 16,
-	.xres		= 320,		.yres		= 240,
 
-	.hsync_len	= 5,		.vsync_len	= 1,
-	.left_margin	= 61,		.upper_margin	= 3,
-	.right_margin	= 9,		.lower_margin	= 0,
-
-	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
-};
-#else
-static struct sa1100fb_mach_info pal_info __initdata = {
-	.pixclock	= 67797,	.bpp		= 16,
-	.xres		= 640,		.yres		= 512,
-
-	.hsync_len	= 64,		.vsync_len	= 6,
-	.left_margin	= 125,		.upper_margin	= 70,
-	.right_margin	= 115,		.lower_margin	= 36,
-
-	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
-};
-#endif
-#endif
-
-#ifdef CONFIG_SA1100_H3600
-static struct sa1100fb_mach_info h3600_info __initdata = {
-	.pixclock	= 174757, 	.bpp		= 16,
-	.xres		= 320,		.yres		= 240,
-
-	.hsync_len	= 3,		.vsync_len	= 3,
-	.left_margin	= 12,		.upper_margin	= 10,
-	.right_margin	= 17,		.lower_margin	= 1,
-
-	.cmap_static	= 1,
-
-	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
-};
-
-static struct sa1100fb_rgb h3600_rgb_16 = {
-	.red	= { .offset = 12, .length = 4, },
-	.green	= { .offset = 7,  .length = 4, },
-	.blue	= { .offset = 1,  .length = 4, },
-	.transp	= { .offset = 0,  .length = 0, },
-};
-#endif
-
-#ifdef CONFIG_SA1100_H3100
-static struct sa1100fb_mach_info h3100_info __initdata = {
-	.pixclock	= 406977, 	.bpp		= 4,
-	.xres		= 320,		.yres		= 240,
-
-	.hsync_len	= 26,		.vsync_len	= 41,
-	.left_margin	= 4,		.upper_margin	= 0,
-	.right_margin	= 4,		.lower_margin	= 0,
-
-	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-	.cmap_greyscale	= 1,
-	.cmap_inverse	= 1,
-
-	.lccr0		= LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
-	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
-};
-#endif
-
-#ifdef CONFIG_SA1100_COLLIE
-static struct sa1100fb_mach_info collie_info __initdata = {
-	.pixclock	= 171521,	.bpp		= 16,
-	.xres		= 320,		.yres		= 240,
-
-	.hsync_len	= 5,		.vsync_len	= 1,
-	.left_margin	= 11,		.upper_margin	= 2,
-	.right_margin	= 30,		.lower_margin	= 0,
-
-	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
-};
-#endif
-
-#ifdef LART_GREY_LCD
-static struct sa1100fb_mach_info lart_grey_info __initdata = {
-	.pixclock	= 150000,	.bpp		= 4,
-	.xres		= 320,		.yres		= 240,
-
-	.hsync_len	= 1,		.vsync_len	= 1,
-	.left_margin	= 4,		.upper_margin	= 0,
-	.right_margin	= 2,		.lower_margin	= 0,
-
-	.cmap_greyscale	= 1,
-	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-	.lccr0		= LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
-	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
-};
-#endif
-#ifdef LART_COLOR_LCD
-static struct sa1100fb_mach_info lart_color_info __initdata = {
-	.pixclock	= 150000,	.bpp		= 16,
-	.xres		= 320,		.yres		= 240,
-
-	.hsync_len	= 2,		.vsync_len	= 3,
-	.left_margin	= 69,		.upper_margin	= 14,
-	.right_margin	= 8,		.lower_margin	= 4,
-
-	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	.lccr3		= LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
-};
-#endif
-#ifdef LART_VIDEO_OUT
-static struct sa1100fb_mach_info lart_video_info __initdata = {
-	.pixclock	= 39721,	.bpp		= 16,
-	.xres		= 640,		.yres		= 480,
-
-	.hsync_len	= 95,		.vsync_len	= 2,
-	.left_margin	= 40,		.upper_margin	= 32,
-	.right_margin	= 24,		.lower_margin	= 11,
-
-	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	.lccr3		= LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
-};
-#endif
-
-#ifdef LART_KIT01_LCD
-static struct sa1100fb_mach_info lart_kit01_info __initdata = {
-	.pixclock	= 63291,	.bpp		= 16,
-	.xres		= 640,		.yres		= 480,
-
-	.hsync_len	= 64,		.vsync_len	= 3,
-	.left_margin	= 122,		.upper_margin	= 45,
-	.right_margin	= 10,		.lower_margin	= 10,
-
-	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	.lccr3		= LCCR3_OutEnH | LCCR3_PixFlEdg
-};
-#endif
-
-#ifdef CONFIG_SA1100_SHANNON
-static struct sa1100fb_mach_info shannon_info __initdata = {
-	.pixclock	= 152500,	.bpp		= 8,
-	.xres		= 640,		.yres		= 480,
-
-	.hsync_len	= 4,		.vsync_len	= 3,
-	.left_margin	= 2,		.upper_margin	= 0,
-	.right_margin	= 1,		.lower_margin	= 0,
-
-	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-	.lccr0		= LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
-	.lccr3		= LCCR3_ACBsDiv(512),
-};
-#endif
-
-
-
-static struct sa1100fb_mach_info * __init
-sa1100fb_get_machine_info(struct sa1100fb_info *fbi)
-{
-	struct sa1100fb_mach_info *inf = NULL;
-
-	/*
-	 *            R        G       B       T
-	 * default  {11,5}, { 5,6}, { 0,5}, { 0,0}
-	 * h3600    {12,4}, { 7,4}, { 1,4}, { 0,0}
-	 * freebird { 8,4}, { 4,4}, { 0,4}, {12,4}
-	 */
-#ifdef CONFIG_SA1100_ASSABET
-	if (machine_is_assabet()) {
-#ifndef ASSABET_PAL_VIDEO
-		inf = &lq039q2ds54_info;
-#else
-		inf = &pal_info;
-#endif
-	}
-#endif
-#ifdef CONFIG_SA1100_H3100
-	if (machine_is_h3100()) {
-		inf = &h3100_info;
-	}
-#endif
-#ifdef CONFIG_SA1100_H3600
-	if (machine_is_h3600()) {
-		inf = &h3600_info;
-		fbi->rgb[RGB_16] = &h3600_rgb_16;
-	}
-#endif
-#ifdef CONFIG_SA1100_COLLIE
-	if (machine_is_collie()) {
-		inf = &collie_info;
-	}
-#endif
-#ifdef CONFIG_SA1100_LART
-	if (machine_is_lart()) {
-#ifdef LART_GREY_LCD
-		inf = &lart_grey_info;
-#endif
-#ifdef LART_COLOR_LCD
-		inf = &lart_color_info;
-#endif
-#ifdef LART_VIDEO_OUT
-		inf = &lart_video_info;
-#endif
-#ifdef LART_KIT01_LCD
-		inf = &lart_kit01_info;
-#endif
-	}
-#endif
-#ifdef CONFIG_SA1100_SHANNON
-	if (machine_is_shannon()) {
-		inf = &shannon_info;
-	}
-#endif
-	return inf;
-}
 
 static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);
 static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);
@@ -533,7 +299,7 @@
 	 * is what you poke into the framebuffer to produce the
 	 * colour you requested.
 	 */
-	if (fbi->cmap_inverse) {
+	if (fbi->inf->cmap_inverse) {
 		red   = 0xffff - red;
 		green = 0xffff - green;
 		blue  = 0xffff - blue;
@@ -607,14 +373,14 @@
 		var->xres = MIN_XRES;
 	if (var->yres < MIN_YRES)
 		var->yres = MIN_YRES;
-	if (var->xres > fbi->max_xres)
-		var->xres = fbi->max_xres;
-	if (var->yres > fbi->max_yres)
-		var->yres = fbi->max_yres;
+	if (var->xres > fbi->inf->xres)
+		var->xres = fbi->inf->xres;
+	if (var->yres > fbi->inf->yres)
+		var->yres = fbi->inf->yres;
 	var->xres_virtual = max(var->xres_virtual, var->xres);
 	var->yres_virtual = max(var->yres_virtual, var->yres);
 
-	DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
+	dev_dbg(fbi->dev, "var->bits_per_pixel=%d\n", var->bits_per_pixel);
 	switch (var->bits_per_pixel) {
 	case 4:
 		rgbidx = RGB_4;
@@ -638,16 +404,16 @@
 	var->blue   = fbi->rgb[rgbidx]->blue;
 	var->transp = fbi->rgb[rgbidx]->transp;
 
-	DPRINTK("RGBT length = %d:%d:%d:%d\n",
+	dev_dbg(fbi->dev, "RGBT length = %d:%d:%d:%d\n",
 		var->red.length, var->green.length, var->blue.length,
 		var->transp.length);
 
-	DPRINTK("RGBT offset = %d:%d:%d:%d\n",
+	dev_dbg(fbi->dev, "RGBT offset = %d:%d:%d:%d\n",
 		var->red.offset, var->green.offset, var->blue.offset,
 		var->transp.offset);
 
 #ifdef CONFIG_CPU_FREQ
-	printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n",
+	dev_dbg(fbi->dev, "dma period = %d ps, clock = %d kHz\n",
 		sa1100fb_display_dma_period(var),
 		cpufreq_get(smp_processor_id()));
 #endif
@@ -655,22 +421,10 @@
 	return 0;
 }
 
-static inline void sa1100fb_set_truecolor(u_int is_true_color)
+static void sa1100fb_set_visual(struct sa1100fb_info *fbi, u32 visual)
 {
-	if (machine_is_assabet()) {
-#if 1		// phase 4 or newer Assabet's
-		if (is_true_color)
-			ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
-		else
-			ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
-#else
-		// older Assabet's
-		if (is_true_color)
-			ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
-		else
-			ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
-#endif
-	}
+	if (fbi->inf->set_visual)
+		fbi->inf->set_visual(visual);
 }
 
 /*
@@ -683,11 +437,11 @@
 	struct fb_var_screeninfo *var = &info->var;
 	unsigned long palette_mem_size;
 
-	DPRINTK("set_par\n");
+	dev_dbg(fbi->dev, "set_par\n");
 
 	if (var->bits_per_pixel == 16)
 		fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
-	else if (!fbi->cmap_static)
+	else if (!fbi->inf->cmap_static)
 		fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
 	else {
 		/*
@@ -704,7 +458,7 @@
 
 	palette_mem_size = fbi->palette_size * sizeof(u16);
 
-	DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
+	dev_dbg(fbi->dev, "palette_mem_size = 0x%08lx\n", palette_mem_size);
 
 	fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
 	fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
@@ -712,7 +466,7 @@
 	/*
 	 * Set (any) board control register to handle new color depth
 	 */
-	sa1100fb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
+	sa1100fb_set_visual(fbi, fbi->fb.fix.visual);
 	sa1100fb_activate_var(var, fbi);
 
 	return 0;
@@ -728,7 +482,7 @@
 	/*
 	 * Make sure the user isn't doing something stupid.
 	 */
-	if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->cmap_static))
+	if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->inf->cmap_static))
 		return -EINVAL;
 
 	return gen_set_cmap(cmap, kspc, con, info);
@@ -775,7 +529,7 @@
 	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
 	int i;
 
-	DPRINTK("sa1100fb_blank: blank=%d\n", blank);
+	dev_dbg(fbi->dev, "sa1100fb_blank: blank=%d\n", blank);
 
 	switch (blank) {
 	case FB_BLANK_POWERDOWN:
@@ -863,43 +617,43 @@
 	u_int half_screen_size, yres, pcd;
 	u_long flags;
 
-	DPRINTK("Configuring SA1100 LCD\n");
+	dev_dbg(fbi->dev, "Configuring SA1100 LCD\n");
 
-	DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n",
+	dev_dbg(fbi->dev, "var: xres=%d hslen=%d lm=%d rm=%d\n",
 		var->xres, var->hsync_len,
 		var->left_margin, var->right_margin);
-	DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n",
+	dev_dbg(fbi->dev, "var: yres=%d vslen=%d um=%d bm=%d\n",
 		var->yres, var->vsync_len,
 		var->upper_margin, var->lower_margin);
 
 #if DEBUG_VAR
 	if (var->xres < 16        || var->xres > 1024)
-		printk(KERN_ERR "%s: invalid xres %d\n",
+		dev_err(fbi->dev, "%s: invalid xres %d\n",
 			fbi->fb.fix.id, var->xres);
 	if (var->hsync_len < 1    || var->hsync_len > 64)
-		printk(KERN_ERR "%s: invalid hsync_len %d\n",
+		dev_err(fbi->dev, "%s: invalid hsync_len %d\n",
 			fbi->fb.fix.id, var->hsync_len);
 	if (var->left_margin < 1  || var->left_margin > 255)
-		printk(KERN_ERR "%s: invalid left_margin %d\n",
+		dev_err(fbi->dev, "%s: invalid left_margin %d\n",
 			fbi->fb.fix.id, var->left_margin);
 	if (var->right_margin < 1 || var->right_margin > 255)
-		printk(KERN_ERR "%s: invalid right_margin %d\n",
+		dev_err(fbi->dev, "%s: invalid right_margin %d\n",
 			fbi->fb.fix.id, var->right_margin);
 	if (var->yres < 1         || var->yres > 1024)
-		printk(KERN_ERR "%s: invalid yres %d\n",
+		dev_err(fbi->dev, "%s: invalid yres %d\n",
 			fbi->fb.fix.id, var->yres);
 	if (var->vsync_len < 1    || var->vsync_len > 64)
-		printk(KERN_ERR "%s: invalid vsync_len %d\n",
+		dev_err(fbi->dev, "%s: invalid vsync_len %d\n",
 			fbi->fb.fix.id, var->vsync_len);
 	if (var->upper_margin < 0 || var->upper_margin > 255)
-		printk(KERN_ERR "%s: invalid upper_margin %d\n",
+		dev_err(fbi->dev, "%s: invalid upper_margin %d\n",
 			fbi->fb.fix.id, var->upper_margin);
 	if (var->lower_margin < 0 || var->lower_margin > 255)
-		printk(KERN_ERR "%s: invalid lower_margin %d\n",
+		dev_err(fbi->dev, "%s: invalid lower_margin %d\n",
 			fbi->fb.fix.id, var->lower_margin);
 #endif
 
-	new_regs.lccr0 = fbi->lccr0 |
+	new_regs.lccr0 = fbi->inf->lccr0 |
 		LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
 		LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
 
@@ -914,7 +668,7 @@
 	 * the YRES parameter.
 	 */
 	yres = var->yres;
-	if (fbi->lccr0 & LCCR0_Dual)
+	if (fbi->inf->lccr0 & LCCR0_Dual)
 		yres /= 2;
 
 	new_regs.lccr2 =
@@ -924,14 +678,14 @@
 		LCCR2_EndFrmDel(var->lower_margin);
 
 	pcd = get_pcd(var->pixclock, cpufreq_get(0));
-	new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->lccr3 |
+	new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->inf->lccr3 |
 		(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
 		(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
 
-	DPRINTK("nlccr0 = 0x%08lx\n", new_regs.lccr0);
-	DPRINTK("nlccr1 = 0x%08lx\n", new_regs.lccr1);
-	DPRINTK("nlccr2 = 0x%08lx\n", new_regs.lccr2);
-	DPRINTK("nlccr3 = 0x%08lx\n", new_regs.lccr3);
+	dev_dbg(fbi->dev, "nlccr0 = 0x%08lx\n", new_regs.lccr0);
+	dev_dbg(fbi->dev, "nlccr1 = 0x%08lx\n", new_regs.lccr1);
+	dev_dbg(fbi->dev, "nlccr2 = 0x%08lx\n", new_regs.lccr2);
+	dev_dbg(fbi->dev, "nlccr3 = 0x%08lx\n", new_regs.lccr3);
 
 	half_screen_size = var->bits_per_pixel;
 	half_screen_size = half_screen_size * var->xres * var->yres / 16;
@@ -951,9 +705,12 @@
 	 * Only update the registers if the controller is enabled
 	 * and something has changed.
 	 */
-	if ((LCCR0 != fbi->reg_lccr0)       || (LCCR1 != fbi->reg_lccr1) ||
-	    (LCCR2 != fbi->reg_lccr2)       || (LCCR3 != fbi->reg_lccr3) ||
-	    (DBAR1 != fbi->dbar1) || (DBAR2 != fbi->dbar2))
+	if (readl_relaxed(fbi->base + LCCR0) != fbi->reg_lccr0 ||
+	    readl_relaxed(fbi->base + LCCR1) != fbi->reg_lccr1 ||
+	    readl_relaxed(fbi->base + LCCR2) != fbi->reg_lccr2 ||
+	    readl_relaxed(fbi->base + LCCR3) != fbi->reg_lccr3 ||
+	    readl_relaxed(fbi->base + DBAR1) != fbi->dbar1 ||
+	    readl_relaxed(fbi->base + DBAR2) != fbi->dbar2)
 		sa1100fb_schedule_work(fbi, C_REENABLE);
 
 	return 0;
@@ -967,18 +724,18 @@
  */
 static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on)
 {
-	DPRINTK("backlight o%s\n", on ? "n" : "ff");
+	dev_dbg(fbi->dev, "backlight o%s\n", on ? "n" : "ff");
 
-	if (sa1100fb_backlight_power)
-		sa1100fb_backlight_power(on);
+	if (fbi->inf->backlight_power)
+		fbi->inf->backlight_power(on);
 }
 
 static inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on)
 {
-	DPRINTK("LCD power o%s\n", on ? "n" : "ff");
+	dev_dbg(fbi->dev, "LCD power o%s\n", on ? "n" : "ff");
 
-	if (sa1100fb_lcd_power)
-		sa1100fb_lcd_power(on);
+	if (fbi->inf->lcd_power)
+		fbi->inf->lcd_power(on);
 }
 
 static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
@@ -1008,14 +765,25 @@
 	}
 
 	if (mask) {
+		unsigned long flags;
+
+		/*
+		 * SA-1100 requires the GPIO direction register set
+		 * appropriately for the alternate function.  Hence
+		 * we set it here via bitmask rather than excessive
+		 * fiddling via the GPIO subsystem - and even then
+		 * we'll still have to deal with GAFR.
+		 */
+		local_irq_save(flags);
 		GPDR |= mask;
 		GAFR |= mask;
+		local_irq_restore(flags);
 	}
 }
 
 static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
 {
-	DPRINTK("Enabling LCD controller\n");
+	dev_dbg(fbi->dev, "Enabling LCD controller\n");
 
 	/*
 	 * Make sure the mode bits are present in the first palette entry
@@ -1024,43 +792,46 @@
 	fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
 
 	/* Sequence from 11.7.10 */
-	LCCR3 = fbi->reg_lccr3;
-	LCCR2 = fbi->reg_lccr2;
-	LCCR1 = fbi->reg_lccr1;
-	LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN;
-	DBAR1 = fbi->dbar1;
-	DBAR2 = fbi->dbar2;
-	LCCR0 |= LCCR0_LEN;
+	writel_relaxed(fbi->reg_lccr3, fbi->base + LCCR3);
+	writel_relaxed(fbi->reg_lccr2, fbi->base + LCCR2);
+	writel_relaxed(fbi->reg_lccr1, fbi->base + LCCR1);
+	writel_relaxed(fbi->reg_lccr0 & ~LCCR0_LEN, fbi->base + LCCR0);
+	writel_relaxed(fbi->dbar1, fbi->base + DBAR1);
+	writel_relaxed(fbi->dbar2, fbi->base + DBAR2);
+	writel_relaxed(fbi->reg_lccr0 | LCCR0_LEN, fbi->base + LCCR0);
 
-	if (machine_is_shannon()) {
-		GPDR |= SHANNON_GPIO_DISP_EN;
-		GPSR |= SHANNON_GPIO_DISP_EN;
-	}
+	if (machine_is_shannon())
+		gpio_set_value(SHANNON_GPIO_DISP_EN, 1);
 
-	DPRINTK("DBAR1 = 0x%08x\n", DBAR1);
-	DPRINTK("DBAR2 = 0x%08x\n", DBAR2);
-	DPRINTK("LCCR0 = 0x%08x\n", LCCR0);
-	DPRINTK("LCCR1 = 0x%08x\n", LCCR1);
-	DPRINTK("LCCR2 = 0x%08x\n", LCCR2);
-	DPRINTK("LCCR3 = 0x%08x\n", LCCR3);
+	dev_dbg(fbi->dev, "DBAR1: 0x%08x\n", readl_relaxed(fbi->base + DBAR1));
+	dev_dbg(fbi->dev, "DBAR2: 0x%08x\n", readl_relaxed(fbi->base + DBAR2));
+	dev_dbg(fbi->dev, "LCCR0: 0x%08x\n", readl_relaxed(fbi->base + LCCR0));
+	dev_dbg(fbi->dev, "LCCR1: 0x%08x\n", readl_relaxed(fbi->base + LCCR1));
+	dev_dbg(fbi->dev, "LCCR2: 0x%08x\n", readl_relaxed(fbi->base + LCCR2));
+	dev_dbg(fbi->dev, "LCCR3: 0x%08x\n", readl_relaxed(fbi->base + LCCR3));
 }
 
 static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
 {
 	DECLARE_WAITQUEUE(wait, current);
+	u32 lccr0;
 
-	DPRINTK("Disabling LCD controller\n");
+	dev_dbg(fbi->dev, "Disabling LCD controller\n");
 
-	if (machine_is_shannon()) {
-		GPCR |= SHANNON_GPIO_DISP_EN;
-	}	
+	if (machine_is_shannon())
+		gpio_set_value(SHANNON_GPIO_DISP_EN, 0);
 
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	add_wait_queue(&fbi->ctrlr_wait, &wait);
 
-	LCSR = 0xffffffff;	/* Clear LCD Status Register */
-	LCCR0 &= ~LCCR0_LDM;	/* Enable LCD Disable Done Interrupt */
-	LCCR0 &= ~LCCR0_LEN;	/* Disable LCD Controller */
+	/* Clear LCD Status Register */
+	writel_relaxed(~0, fbi->base + LCSR);
+
+	lccr0 = readl_relaxed(fbi->base + LCCR0);
+	lccr0 &= ~LCCR0_LDM;	/* Enable LCD Disable Done Interrupt */
+	writel_relaxed(lccr0, fbi->base + LCCR0);
+	lccr0 &= ~LCCR0_LEN;	/* Disable LCD Controller */
+	writel_relaxed(lccr0, fbi->base + LCCR0);
 
 	schedule_timeout(20 * HZ / 1000);
 	remove_wait_queue(&fbi->ctrlr_wait, &wait);
@@ -1072,14 +843,15 @@
 static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id)
 {
 	struct sa1100fb_info *fbi = dev_id;
-	unsigned int lcsr = LCSR;
+	unsigned int lcsr = readl_relaxed(fbi->base + LCSR);
 
 	if (lcsr & LCSR_LDD) {
-		LCCR0 |= LCCR0_LDM;
+		u32 lccr0 = readl_relaxed(fbi->base + LCCR0) | LCCR0_LDM;
+		writel_relaxed(lccr0, fbi->base + LCCR0);
 		wake_up(&fbi->ctrlr_wait);
 	}
 
-	LCSR = lcsr;
+	writel_relaxed(lcsr, fbi->base + LCSR);
 	return IRQ_HANDLED;
 }
 
@@ -1268,7 +1040,7 @@
 	switch (val) {
 	case CPUFREQ_ADJUST:
 	case CPUFREQ_INCOMPATIBLE:
-		printk(KERN_DEBUG "min dma period: %d ps, "
+		dev_dbg(fbi->dev, "min dma period: %d ps, "
 			"new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
 			policy->max);
 		/* todo: fill in min/max values */
@@ -1318,7 +1090,7 @@
  *      cache.  Once this area is remapped, all virtual memory
  *      access to the video memory should occur at the new region.
  */
-static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
+static int __devinit sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
 {
 	/*
 	 * We reserve one page for the palette, plus the size
@@ -1344,7 +1116,7 @@
 }
 
 /* Fake monspecs to fill in fbinfo structure */
-static struct fb_monspecs monspecs __initdata = {
+static struct fb_monspecs monspecs __devinitdata = {
 	.hfmin	= 30000,
 	.hfmax	= 70000,
 	.vfmin	= 50,
@@ -1352,10 +1124,11 @@
 };
 
 
-static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
+static struct sa1100fb_info * __devinit sa1100fb_init_fbinfo(struct device *dev)
 {
-	struct sa1100fb_mach_info *inf;
+	struct sa1100fb_mach_info *inf = dev->platform_data;
 	struct sa1100fb_info *fbi;
+	unsigned i;
 
 	fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(u32) * 16,
 		      GFP_KERNEL);
@@ -1390,8 +1163,6 @@
 	fbi->rgb[RGB_8]		= &rgb_8;
 	fbi->rgb[RGB_16]	= &def_rgb_16;
 
-	inf = sa1100fb_get_machine_info(fbi);
-
 	/*
 	 * People just don't seem to get this.  We don't support
 	 * anything but correct entries now, so panic if someone
@@ -1402,13 +1173,10 @@
 		panic("sa1100fb error: invalid LCCR3 fields set or zero "
 			"pixclock.");
 
-	fbi->max_xres			= inf->xres;
 	fbi->fb.var.xres		= inf->xres;
 	fbi->fb.var.xres_virtual	= inf->xres;
-	fbi->max_yres			= inf->yres;
 	fbi->fb.var.yres		= inf->yres;
 	fbi->fb.var.yres_virtual	= inf->yres;
-	fbi->max_bpp			= inf->bpp;
 	fbi->fb.var.bits_per_pixel	= inf->bpp;
 	fbi->fb.var.pixclock		= inf->pixclock;
 	fbi->fb.var.hsync_len		= inf->hsync_len;
@@ -1419,14 +1187,16 @@
 	fbi->fb.var.lower_margin	= inf->lower_margin;
 	fbi->fb.var.sync		= inf->sync;
 	fbi->fb.var.grayscale		= inf->cmap_greyscale;
-	fbi->cmap_inverse		= inf->cmap_inverse;
-	fbi->cmap_static		= inf->cmap_static;
-	fbi->lccr0			= inf->lccr0;
-	fbi->lccr3			= inf->lccr3;
 	fbi->state			= C_STARTUP;
 	fbi->task_state			= (u_char)-1;
-	fbi->fb.fix.smem_len		= fbi->max_xres * fbi->max_yres *
-					  fbi->max_bpp / 8;
+	fbi->fb.fix.smem_len		= inf->xres * inf->yres *
+					  inf->bpp / 8;
+	fbi->inf			= inf;
+
+	/* Copy the RGB bitfield overrides */
+	for (i = 0; i < NR_RGB; i++)
+		if (inf->rgb[i])
+			fbi->rgb[i] = inf->rgb[i];
 
 	init_waitqueue_head(&fbi->ctrlr_wait);
 	INIT_WORK(&fbi->task, sa1100fb_task);
@@ -1438,13 +1208,20 @@
 static int __devinit sa1100fb_probe(struct platform_device *pdev)
 {
 	struct sa1100fb_info *fbi;
+	struct resource *res;
 	int ret, irq;
 
+	if (!pdev->dev.platform_data) {
+		dev_err(&pdev->dev, "no platform LCD data\n");
+		return -EINVAL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
+	if (irq < 0 || !res)
 		return -EINVAL;
 
-	if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
+	if (!request_mem_region(res->start, resource_size(res), "LCD"))
 		return -EBUSY;
 
 	fbi = sa1100fb_init_fbinfo(&pdev->dev);
@@ -1452,6 +1229,10 @@
 	if (!fbi)
 		goto failed;
 
+	fbi->base = ioremap(res->start, resource_size(res));
+	if (!fbi->base)
+		goto failed;
+
 	/* Initialize video memory */
 	ret = sa1100fb_map_video_memory(fbi);
 	if (ret)
@@ -1459,14 +1240,16 @@
 
 	ret = request_irq(irq, sa1100fb_handle_irq, 0, "LCD", fbi);
 	if (ret) {
-		printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret);
+		dev_err(&pdev->dev, "request_irq failed: %d\n", ret);
 		goto failed;
 	}
 
-#ifdef ASSABET_PAL_VIDEO
-	if (machine_is_assabet())
-		ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
-#endif
+	if (machine_is_shannon()) {
+		ret = gpio_request_one(SHANNON_GPIO_DISP_EN,
+			GPIOF_OUT_INIT_LOW, "display enable");
+		if (ret)
+			goto err_free_irq;
+	}
 
 	/*
 	 * This makes sure that our colour bitfield
@@ -1478,7 +1261,7 @@
 
 	ret = register_framebuffer(&fbi->fb);
 	if (ret < 0)
-		goto err_free_irq;
+		goto err_reg_fb;
 
 #ifdef CONFIG_CPU_FREQ
 	fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
@@ -1490,12 +1273,17 @@
 	/* This driver cannot be unloaded at the moment */
 	return 0;
 
+ err_reg_fb:
+	if (machine_is_shannon())
+		gpio_free(SHANNON_GPIO_DISP_EN);
  err_free_irq:
 	free_irq(irq, fbi);
  failed:
+	if (fbi)
+		iounmap(fbi->base);
 	platform_set_drvdata(pdev, NULL);
 	kfree(fbi);
-	release_mem_region(0xb0100000, 0x10000);
+	release_mem_region(res->start, resource_size(res));
 	return ret;
 }
 
@@ -1505,6 +1293,7 @@
 	.resume		= sa1100fb_resume,
 	.driver		= {
 		.name	= "sa11x0-fb",
+		.owner	= THIS_MODULE,
 	},
 };
 
diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h
index 1c3b459..fc5d429 100644
--- a/drivers/video/sa1100fb.h
+++ b/drivers/video/sa1100fb.h
@@ -10,44 +10,15 @@
  * for more details.
  */
 
-/*
- * These are the bitfields for each
- * display depth that we support.
- */
-struct sa1100fb_rgb {
-	struct fb_bitfield	red;
-	struct fb_bitfield	green;
-	struct fb_bitfield	blue;
-	struct fb_bitfield	transp;
-};
-
-/*
- * This structure describes the machine which we are running on.
- */
-struct sa1100fb_mach_info {
-	u_long		pixclock;
-
-	u_short		xres;
-	u_short		yres;
-
-	u_char		bpp;
-	u_char		hsync_len;
-	u_char		left_margin;
-	u_char		right_margin;
-
-	u_char		vsync_len;
-	u_char		upper_margin;
-	u_char		lower_margin;
-	u_char		sync;
-
-	u_int		cmap_greyscale:1,
-			cmap_inverse:1,
-			cmap_static:1,
-			unused:29;
-
-	u_int		lccr0;
-	u_int		lccr3;
-};
+#define LCCR0           0x0000          /* LCD Control Reg. 0 */
+#define LCSR            0x0004          /* LCD Status Reg. */
+#define DBAR1           0x0010          /* LCD DMA Base Address Reg. channel 1 */
+#define DCAR1           0x0014          /* LCD DMA Current Address Reg. channel 1 */
+#define DBAR2           0x0018          /* LCD DMA Base Address Reg.  channel 2 */
+#define DCAR2           0x001C          /* LCD DMA Current Address Reg. channel 2 */
+#define LCCR1           0x0020          /* LCD Control Reg. 1 */
+#define LCCR2           0x0024          /* LCD Control Reg. 2 */
+#define LCCR3           0x0028          /* LCD Control Reg. 3 */
 
 /* Shadows for LCD controller registers */
 struct sa1100fb_lcd_reg {
@@ -57,19 +28,11 @@
 	unsigned long lccr3;
 };
 
-#define RGB_4	(0)
-#define RGB_8	(1)
-#define RGB_16	(2)
-#define NR_RGB	3
-
 struct sa1100fb_info {
 	struct fb_info		fb;
 	struct device		*dev;
-	struct sa1100fb_rgb	*rgb[NR_RGB];
-
-	u_int			max_bpp;
-	u_int			max_xres;
-	u_int			max_yres;
+	const struct sa1100fb_rgb *rgb[NR_RGB];
+	void __iomem		*base;
 
 	/*
 	 * These are the addresses we mapped
@@ -88,12 +51,6 @@
 	dma_addr_t		dbar1;
 	dma_addr_t		dbar2;
 
-	u_int			lccr0;
-	u_int			lccr3;
-	u_int			cmap_inverse:1,
-				cmap_static:1,
-				unused:30;
-
 	u_int			reg_lccr0;
 	u_int			reg_lccr1;
 	u_int			reg_lccr2;
@@ -109,6 +66,8 @@
 	struct notifier_block	freq_transition;
 	struct notifier_block	freq_policy;
 #endif
+
+	const struct sa1100fb_mach_info *inf;
 };
 
 #define TO_INF(ptr,member)	container_of(ptr,struct sa1100fb_info,member)
@@ -130,15 +89,6 @@
 #define SA1100_NAME	"SA1100"
 
 /*
- *  Debug macros 
- */
-#if DEBUG
-#  define DPRINTK(fmt, args...)	printk("%s: " fmt, __func__ , ## args)
-#else
-#  define DPRINTK(fmt, args...)
-#endif
-
-/*
  * Minimum X and Y resolutions
  */
 #define MIN_XRES	64
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index beb4950..cee7803 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -56,7 +56,6 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
-#include <asm/system.h>
 
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c
index 05151b8..4c6b844 100644
--- a/drivers/video/sh_mipi_dsi.c
+++ b/drivers/video/sh_mipi_dsi.c
@@ -24,6 +24,8 @@
 #include <video/sh_mipi_dsi.h>
 #include <video/sh_mobile_lcdc.h>
 
+#include "sh_mobile_lcdcfb.h"
+
 #define SYSCTRL		0x0000
 #define SYSCONF		0x0004
 #define TIMSET		0x0008
@@ -50,16 +52,16 @@
 #define MAX_SH_MIPI_DSI 2
 
 struct sh_mipi {
+	struct sh_mobile_lcdc_entity entity;
+
 	void __iomem	*base;
 	void __iomem	*linkbase;
 	struct clk	*dsit_clk;
 	struct platform_device *pdev;
-
-	void	*next_board_data;
-	void	(*next_display_on)(void *board_data, struct fb_info *info);
-	void	(*next_display_off)(void *board_data);
 };
 
+#define to_sh_mipi(e)	container_of(e, struct sh_mipi, entity)
+
 static struct sh_mipi *mipi_dsi[MAX_SH_MIPI_DSI];
 
 /* Protect the above array */
@@ -120,7 +122,7 @@
 
 static void sh_mipi_shutdown(struct platform_device *pdev)
 {
-	struct sh_mipi *mipi = platform_get_drvdata(pdev);
+	struct sh_mipi *mipi = to_sh_mipi(platform_get_drvdata(pdev));
 
 	sh_mipi_dsi_enable(mipi, false);
 }
@@ -145,77 +147,77 @@
 		pctype = 0;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
 		pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
-		linelength = ch->lcd_cfg[0].xres * 3;
+		linelength = ch->lcd_modes[0].xres * 3;
 		yuv = false;
 		break;
 	case MIPI_RGB565:
 		pctype = 1;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
 		pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
-		linelength = ch->lcd_cfg[0].xres * 2;
+		linelength = ch->lcd_modes[0].xres * 2;
 		yuv = false;
 		break;
 	case MIPI_RGB666_LP:
 		pctype = 2;
 		datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
 		pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
-		linelength = ch->lcd_cfg[0].xres * 3;
+		linelength = ch->lcd_modes[0].xres * 3;
 		yuv = false;
 		break;
 	case MIPI_RGB666:
 		pctype = 3;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
 		pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
-		linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8;
+		linelength = (ch->lcd_modes[0].xres * 18 + 7) / 8;
 		yuv = false;
 		break;
 	case MIPI_BGR888:
 		pctype = 8;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
 		pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
-		linelength = ch->lcd_cfg[0].xres * 3;
+		linelength = ch->lcd_modes[0].xres * 3;
 		yuv = false;
 		break;
 	case MIPI_BGR565:
 		pctype = 9;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
 		pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
-		linelength = ch->lcd_cfg[0].xres * 2;
+		linelength = ch->lcd_modes[0].xres * 2;
 		yuv = false;
 		break;
 	case MIPI_BGR666_LP:
 		pctype = 0xa;
 		datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
 		pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
-		linelength = ch->lcd_cfg[0].xres * 3;
+		linelength = ch->lcd_modes[0].xres * 3;
 		yuv = false;
 		break;
 	case MIPI_BGR666:
 		pctype = 0xb;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
 		pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
-		linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8;
+		linelength = (ch->lcd_modes[0].xres * 18 + 7) / 8;
 		yuv = false;
 		break;
 	case MIPI_YUYV:
 		pctype = 4;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
 		pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
-		linelength = ch->lcd_cfg[0].xres * 2;
+		linelength = ch->lcd_modes[0].xres * 2;
 		yuv = true;
 		break;
 	case MIPI_UYVY:
 		pctype = 5;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
 		pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
-		linelength = ch->lcd_cfg[0].xres * 2;
+		linelength = ch->lcd_modes[0].xres * 2;
 		yuv = true;
 		break;
 	case MIPI_YUV420_L:
 		pctype = 6;
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
 		pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
-		linelength = (ch->lcd_cfg[0].xres * 12 + 7) / 8;
+		linelength = (ch->lcd_modes[0].xres * 12 + 7) / 8;
 		yuv = true;
 		break;
 	case MIPI_YUV420:
@@ -223,7 +225,7 @@
 		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
 		pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
 		/* Length of U/V line */
-		linelength = (ch->lcd_cfg[0].xres + 1) / 2;
+		linelength = (ch->lcd_modes[0].xres + 1) / 2;
 		yuv = true;
 		break;
 	default:
@@ -271,7 +273,7 @@
 	iowrite32(0x00000001, base + PHYCTRL);
 	udelay(200);
 	/* Deassert resets, power on */
-	iowrite32(0x03070001, base + PHYCTRL);
+	iowrite32(0x03070001 | pdata->phyctrl, base + PHYCTRL);
 
 	/*
 	 * Default = ULPS enable |
@@ -292,7 +294,7 @@
 	 */
 	iowrite32(0x00000006, mipi->linkbase + DTCTR);
 	/* VSYNC width = 2 (<< 17) */
-	iowrite32((ch->lcd_cfg[0].vsync_len << pdata->vsynw_offset) |
+	iowrite32((ch->lcd_modes[0].vsync_len << pdata->vsynw_offset) |
 		  (pdata->clksrc << 16) | (pctype << 12) | datatype,
 		  mipi->linkbase + VMCTR1);
 
@@ -326,7 +328,7 @@
 	top = linelength << 16; /* RGBLEN */
 	bottom = 0x00000001;
 	if (pdata->flags & SH_MIPI_DSI_HSABM) /* HSALEN */
-		bottom = (pdata->lane * ch->lcd_cfg[0].hsync_len) - 10;
+		bottom = (pdata->lane * ch->lcd_modes[0].hsync_len) - 10;
 	iowrite32(top | bottom , mipi->linkbase + VMLEN1);
 
 	/*
@@ -346,18 +348,18 @@
 		div = 2;
 
 	if (pdata->flags & SH_MIPI_DSI_HFPBM) {	/* HBPLEN */
-		top = ch->lcd_cfg[0].hsync_len + ch->lcd_cfg[0].left_margin;
+		top = ch->lcd_modes[0].hsync_len + ch->lcd_modes[0].left_margin;
 		top = ((pdata->lane * top / div) - 10) << 16;
 	}
 	if (pdata->flags & SH_MIPI_DSI_HBPBM) { /* HFPLEN */
-		bottom = ch->lcd_cfg[0].right_margin;
+		bottom = ch->lcd_modes[0].right_margin;
 		bottom = (pdata->lane * bottom / div) - 12;
 	}
 
-	bpp = linelength / ch->lcd_cfg[0].xres; /* byte / pixel */
+	bpp = linelength / ch->lcd_modes[0].xres; /* byte / pixel */
 	if ((pdata->lane / div) > bpp) {
-		tmp = ch->lcd_cfg[0].xres / bpp; /* output cycle */
-		tmp = ch->lcd_cfg[0].xres - tmp; /* (input - output) cycle */
+		tmp = ch->lcd_modes[0].xres / bpp; /* output cycle */
+		tmp = ch->lcd_modes[0].xres - tmp; /* (input - output) cycle */
 		delay = (pdata->lane * tmp);
 	}
 
@@ -392,9 +394,9 @@
 	return 0;
 }
 
-static void mipi_display_on(void *arg, struct fb_info *info)
+static int mipi_display_on(struct sh_mobile_lcdc_entity *entity)
 {
-	struct sh_mipi *mipi = arg;
+	struct sh_mipi *mipi = to_sh_mipi(entity);
 	struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data;
 	int ret;
 
@@ -410,25 +412,21 @@
 
 	sh_mipi_dsi_enable(mipi, true);
 
-	if (mipi->next_display_on)
-		mipi->next_display_on(mipi->next_board_data, info);
-
-	return;
+	return SH_MOBILE_LCDC_DISPLAY_CONNECTED;
 
 mipi_display_on_fail1:
 	pm_runtime_put_sync(&mipi->pdev->dev);
 mipi_display_on_fail2:
 	pdata->set_dot_clock(mipi->pdev, mipi->base, 0);
+
+	return ret;
 }
 
-static void mipi_display_off(void *arg)
+static void mipi_display_off(struct sh_mobile_lcdc_entity *entity)
 {
-	struct sh_mipi *mipi = arg;
+	struct sh_mipi *mipi = to_sh_mipi(entity);
 	struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data;
 
-	if (mipi->next_display_off)
-		mipi->next_display_off(mipi->next_board_data);
-
 	sh_mipi_dsi_enable(mipi, false);
 
 	pdata->set_dot_clock(mipi->pdev, mipi->base, 0);
@@ -436,6 +434,11 @@
 	pm_runtime_put_sync(&mipi->pdev->dev);
 }
 
+static const struct sh_mobile_lcdc_entity_ops mipi_ops = {
+	.display_on = mipi_display_on,
+	.display_off = mipi_display_off,
+};
+
 static int __init sh_mipi_probe(struct platform_device *pdev)
 {
 	struct sh_mipi *mipi;
@@ -467,6 +470,9 @@
 		goto ealloc;
 	}
 
+	mipi->entity.owner = THIS_MODULE;
+	mipi->entity.ops = &mipi_ops;
+
 	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
 		dev_err(&pdev->dev, "MIPI register region already claimed\n");
 		ret = -EBUSY;
@@ -521,18 +527,7 @@
 	pm_runtime_resume(&pdev->dev);
 
 	mutex_unlock(&array_lock);
-	platform_set_drvdata(pdev, mipi);
-
-	/* Save original LCDC callbacks */
-	mipi->next_board_data = pdata->lcd_chan->board_cfg.board_data;
-	mipi->next_display_on = pdata->lcd_chan->board_cfg.display_on;
-	mipi->next_display_off = pdata->lcd_chan->board_cfg.display_off;
-
-	/* Set up LCDC callbacks */
-	pdata->lcd_chan->board_cfg.board_data = mipi;
-	pdata->lcd_chan->board_cfg.display_on = mipi_display_on;
-	pdata->lcd_chan->board_cfg.display_off = mipi_display_off;
-	pdata->lcd_chan->board_cfg.owner = THIS_MODULE;
+	platform_set_drvdata(pdev, &mipi->entity);
 
 	return 0;
 
@@ -558,10 +553,9 @@
 
 static int __exit sh_mipi_remove(struct platform_device *pdev)
 {
-	struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data;
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	struct sh_mipi *mipi = platform_get_drvdata(pdev);
+	struct sh_mipi *mipi = to_sh_mipi(platform_get_drvdata(pdev));
 	int i, ret;
 
 	mutex_lock(&array_lock);
@@ -581,11 +575,6 @@
 	if (ret < 0)
 		return ret;
 
-	pdata->lcd_chan->board_cfg.owner = NULL;
-	pdata->lcd_chan->board_cfg.display_on = NULL;
-	pdata->lcd_chan->board_cfg.display_off = NULL;
-	pdata->lcd_chan->board_cfg.board_data = NULL;
-
 	pm_runtime_disable(&pdev->dev);
 	clk_disable(mipi->dsit_clk);
 	clk_put(mipi->dsit_clk);
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index 647ba98..eafb19d 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -208,6 +208,8 @@
 };
 
 struct sh_hdmi {
+	struct sh_mobile_lcdc_entity entity;
+
 	void __iomem *base;
 	enum hotplug_state hp_state;	/* hot-plug status */
 	u8 preprogrammed_vic;		/* use a pre-programmed VIC or
@@ -217,14 +219,13 @@
 	u8 edid_blocks;
 	struct clk *hdmi_clk;
 	struct device *dev;
-	struct fb_info *info;
-	struct mutex mutex;		/* Protect the info pointer */
 	struct delayed_work edid_work;
-	struct fb_var_screeninfo var;
+	struct fb_videomode mode;
 	struct fb_monspecs monspec;
-	struct notifier_block notifier;
 };
 
+#define entity_to_sh_hdmi(e)	container_of(e, struct sh_hdmi, entity)
+
 static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg)
 {
 	iowrite8(data, hdmi->base + reg);
@@ -290,24 +291,24 @@
 /* External video parameter settings */
 static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi)
 {
-	struct fb_var_screeninfo *var = &hdmi->var;
+	struct fb_videomode *mode = &hdmi->mode;
 	u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset;
 	u8 sync = 0;
 
-	htotal = var->xres + var->right_margin + var->left_margin + var->hsync_len;
-
-	hdelay = var->hsync_len + var->left_margin;
-	hblank = var->right_margin + hdelay;
+	htotal = mode->xres + mode->right_margin + mode->left_margin
+	       + mode->hsync_len;
+	hdelay = mode->hsync_len + mode->left_margin;
+	hblank = mode->right_margin + hdelay;
 
 	/*
 	 * Vertical timing looks a bit different in Figure 18,
 	 * but let's try the same first by setting offset = 0
 	 */
-	vtotal = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
-
-	vdelay = var->vsync_len + var->upper_margin;
-	vblank = var->lower_margin + vdelay;
-	voffset = min(var->upper_margin / 2, 6U);
+	vtotal = mode->yres + mode->upper_margin + mode->lower_margin
+	       + mode->vsync_len;
+	vdelay = mode->vsync_len + mode->upper_margin;
+	vblank = mode->lower_margin + vdelay;
+	voffset = min(mode->upper_margin / 2, 6U);
 
 	/*
 	 * [3]: VSYNC polarity: Positive
@@ -315,14 +316,14 @@
 	 * [1]: Interlace/Progressive: Progressive
 	 * [0]: External video settings enable: used.
 	 */
-	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+	if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
 		sync |= 4;
-	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+	if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
 		sync |= 8;
 
 	dev_dbg(hdmi->dev, "H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n",
-		htotal, hblank, hdelay, var->hsync_len,
-		vtotal, vblank, vdelay, var->vsync_len, sync);
+		htotal, hblank, hdelay, mode->hsync_len,
+		vtotal, vblank, vdelay, mode->vsync_len, sync);
 
 	hdmi_write(hdmi, sync | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS);
 
@@ -335,8 +336,8 @@
 	hdmi_write(hdmi, hdelay, HDMI_EXTERNAL_H_DELAY_7_0);
 	hdmi_write(hdmi, hdelay >> 8, HDMI_EXTERNAL_H_DELAY_9_8);
 
-	hdmi_write(hdmi, var->hsync_len, HDMI_EXTERNAL_H_DURATION_7_0);
-	hdmi_write(hdmi, var->hsync_len >> 8, HDMI_EXTERNAL_H_DURATION_9_8);
+	hdmi_write(hdmi, mode->hsync_len, HDMI_EXTERNAL_H_DURATION_7_0);
+	hdmi_write(hdmi, mode->hsync_len >> 8, HDMI_EXTERNAL_H_DURATION_9_8);
 
 	hdmi_write(hdmi, vtotal, HDMI_EXTERNAL_V_TOTAL_7_0);
 	hdmi_write(hdmi, vtotal >> 8, HDMI_EXTERNAL_V_TOTAL_9_8);
@@ -345,7 +346,7 @@
 
 	hdmi_write(hdmi, vdelay, HDMI_EXTERNAL_V_DELAY);
 
-	hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION);
+	hdmi_write(hdmi, mode->vsync_len, HDMI_EXTERNAL_V_DURATION);
 
 	/* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */
 	if (!hdmi->preprogrammed_vic)
@@ -472,7 +473,7 @@
  */
 static void sh_hdmi_phy_config(struct sh_hdmi *hdmi)
 {
-	if (hdmi->var.pixclock < 10000) {
+	if (hdmi->mode.pixclock < 10000) {
 		/* for 1080p8bit 148MHz */
 		hdmi_write(hdmi, 0x1d, HDMI_SLIPHDMIT_PARAM_SETTINGS_1);
 		hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2);
@@ -483,7 +484,7 @@
 		hdmi_write(hdmi, 0x0e, HDMI_SLIPHDMIT_PARAM_SETTINGS_8);
 		hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9);
 		hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10);
-	} else if (hdmi->var.pixclock < 30000) {
+	} else if (hdmi->mode.pixclock < 30000) {
 		/* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */
 		/*
 		 * [1:0]	Speed_A
@@ -732,14 +733,12 @@
 static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
 			     unsigned long *parent_rate)
 {
-	struct fb_var_screeninfo tmpvar;
-	struct fb_var_screeninfo *var = &tmpvar;
+	struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc;
 	const struct fb_videomode *mode, *found = NULL;
-	struct fb_info *info = hdmi->info;
-	struct fb_modelist *modelist = NULL;
 	unsigned int f_width = 0, f_height = 0, f_refresh = 0;
 	unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */
 	bool scanning = false, preferred_bad = false;
+	bool use_edid_mode = false;
 	u8 edid[128];
 	char *forced;
 	int i;
@@ -854,12 +853,9 @@
 		}
 
 		/* Check if supported: sufficient fb memory, supported clock-rate */
-		fb_videomode_to_var(var, mode);
-
-		var->bits_per_pixel = info->var.bits_per_pixel;
-
-		if (info && info->fbops->fb_check_var &&
-		    info->fbops->fb_check_var(var, info)) {
+		if (ch && ch->notify &&
+		    ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_MODE, mode,
+			       NULL)) {
 			scanning = true;
 			preferred_bad = true;
 			continue;
@@ -867,28 +863,19 @@
 
 		found = mode;
 		found_rate_error = rate_error;
+		use_edid_mode = true;
 	}
 
-	hdmi->var.width = hdmi->monspec.max_x * 10;
-	hdmi->var.height = hdmi->monspec.max_y * 10;
-
 	/*
-	 * TODO 1: if no ->info is present, postpone running the config until
-	 * after ->info first gets registered.
+	 * TODO 1: if no default mode is present, postpone running the config
+	 * until after the LCDC channel is initialized.
 	 * TODO 2: consider registering the HDMI platform device from the LCDC
-	 * driver, and passing ->info with HDMI platform data.
+	 * driver.
 	 */
-	if (info && !found) {
-		modelist = info->modelist.next &&
-			!list_empty(&info->modelist) ?
-			list_entry(info->modelist.next,
-				   struct fb_modelist, list) :
-			NULL;
-
-		if (modelist) {
-			found = &modelist->mode;
-			found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate, parent_rate);
-		}
+	if (!found && hdmi->entity.def_mode.xres != 0) {
+		found = &hdmi->entity.def_mode;
+		found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate,
+						      parent_rate);
 	}
 
 	/* No cookie today */
@@ -912,12 +899,13 @@
 	else
 		hdmi->preprogrammed_vic = 0;
 
-	dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), clock error %luHz\n",
-		modelist ? "default" : "EDID", hdmi->preprogrammed_vic ? "VIC" : "external",
-		found->xres, found->yres, found->refresh,
-		PICOS2KHZ(found->pixclock) * 1000, found_rate_error);
+	dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), "
+		"clock error %luHz\n", use_edid_mode ? "EDID" : "default",
+		hdmi->preprogrammed_vic ? "VIC" : "external", found->xres,
+		found->yres, found->refresh, PICOS2KHZ(found->pixclock) * 1000,
+		found_rate_error);
 
-	fb_videomode_to_var(&hdmi->var, found);
+	hdmi->mode = *found;
 	sh_hdmi_external_video_param(hdmi);
 
 	return 0;
@@ -998,22 +986,12 @@
 	return IRQ_HANDLED;
 }
 
-/* locking:	called with info->lock held, or before register_framebuffer() */
-static void sh_hdmi_display_on(void *arg, struct fb_info *info)
+static int sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity)
 {
-	/*
-	 * info is guaranteed to be valid, when we are called, because our
-	 * FB_EVENT_FB_UNBIND notify is also called with info->lock held
-	 */
-	struct sh_hdmi *hdmi = arg;
-	struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
-	struct sh_mobile_lcdc_chan *ch = info->par;
+	struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity);
 
-	dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__,
-		pdata->lcd_dev, info->state);
-
-	/* No need to lock */
-	hdmi->info = info;
+	dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, hdmi,
+		hdmi->hp_state);
 
 	/*
 	 * hp_state can be set to
@@ -1021,56 +999,30 @@
 	 * HDMI_HOTPLUG_CONNECTED:	on monitor plug-in
 	 * HDMI_HOTPLUG_EDID_DONE:	on EDID read completion
 	 */
-	switch (hdmi->hp_state) {
-	case HDMI_HOTPLUG_EDID_DONE:
+	if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) {
 		/* PS mode d->e. All functions are active */
 		hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL);
 		dev_dbg(hdmi->dev, "HDMI running\n");
-		break;
-	case HDMI_HOTPLUG_DISCONNECTED:
-		info->state = FBINFO_STATE_SUSPENDED;
-	default:
-		hdmi->var = ch->display_var;
 	}
+
+	return hdmi->hp_state == HDMI_HOTPLUG_DISCONNECTED
+		? SH_MOBILE_LCDC_DISPLAY_DISCONNECTED
+		: SH_MOBILE_LCDC_DISPLAY_CONNECTED;
 }
 
-/* locking: called with info->lock held */
-static void sh_hdmi_display_off(void *arg)
+static void sh_hdmi_display_off(struct sh_mobile_lcdc_entity *entity)
 {
-	struct sh_hdmi *hdmi = arg;
-	struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
+	struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity);
 
-	dev_dbg(hdmi->dev, "%s(%p)\n", __func__, pdata->lcd_dev);
+	dev_dbg(hdmi->dev, "%s(%p)\n", __func__, hdmi);
 	/* PS mode e->a */
 	hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL);
 }
 
-static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi)
-{
-	struct fb_info *info = hdmi->info;
-	struct sh_mobile_lcdc_chan *ch = info->par;
-	struct fb_var_screeninfo *new_var = &hdmi->var, *old_var = &ch->display_var;
-	struct fb_videomode mode1, mode2;
-
-	fb_var_to_videomode(&mode1, old_var);
-	fb_var_to_videomode(&mode2, new_var);
-
-	dev_dbg(info->dev, "Old %ux%u, new %ux%u\n",
-		mode1.xres, mode1.yres, mode2.xres, mode2.yres);
-
-	if (fb_mode_is_equal(&mode1, &mode2)) {
-		/* It can be a different monitor with an equal video-mode */
-		old_var->width = new_var->width;
-		old_var->height = new_var->height;
-		return false;
-	}
-
-	dev_dbg(info->dev, "Switching %u -> %u lines\n",
-		mode1.yres, mode2.yres);
-	*old_var = *new_var;
-
-	return true;
-}
+static const struct sh_mobile_lcdc_entity_ops sh_hdmi_ops = {
+	.display_on = sh_hdmi_display_on,
+	.display_off = sh_hdmi_display_off,
+};
 
 /**
  * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock
@@ -1111,20 +1063,11 @@
 static void sh_hdmi_edid_work_fn(struct work_struct *work)
 {
 	struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work);
-	struct fb_info *info;
-	struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
-	struct sh_mobile_lcdc_chan *ch;
+	struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc;
 	int ret;
 
-	dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__,
-		pdata->lcd_dev, hdmi->hp_state);
-
-	if (!pdata->lcd_dev)
-		return;
-
-	mutex_lock(&hdmi->mutex);
-
-	info = hdmi->info;
+	dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, hdmi,
+		hdmi->hp_state);
 
 	if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) {
 		unsigned long parent_rate = 0, hdmi_rate;
@@ -1145,103 +1088,32 @@
 		/* Switched to another (d) power-save mode */
 		msleep(10);
 
-		if (!info)
-			goto out;
-
-		ch = info->par;
-
-		if (lock_fb_info(info)) {
-			console_lock();
-
-			/* HDMI plug in */
-			if (!sh_hdmi_must_reconfigure(hdmi) &&
-			    info->state == FBINFO_STATE_RUNNING) {
-				/*
-				 * First activation with the default monitor - just turn
-				 * on, if we run a resume here, the logo disappears
-				 */
-				info->var.width = hdmi->var.width;
-				info->var.height = hdmi->var.height;
-				sh_hdmi_display_on(hdmi, info);
-			} else {
-				/* New monitor or have to wake up */
-				fb_set_suspend(info, 0);
-			}
-
-			console_unlock();
-			unlock_fb_info(info);
-		}
+		if (ch && ch->notify)
+			ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT,
+				   &hdmi->mode, &hdmi->monspec);
 	} else {
-		ret = 0;
-		if (!info)
-			goto out;
-
 		hdmi->monspec.modedb_len = 0;
 		fb_destroy_modedb(hdmi->monspec.modedb);
 		hdmi->monspec.modedb = NULL;
 
-		if (lock_fb_info(info)) {
-			console_lock();
+		if (ch && ch->notify)
+			ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT,
+				   NULL, NULL);
 
-			/* HDMI disconnect */
-			fb_set_suspend(info, 1);
-
-			console_unlock();
-			unlock_fb_info(info);
-		}
+		ret = 0;
 	}
 
 out:
 	if (ret < 0 && ret != -EAGAIN)
 		hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED;
-	mutex_unlock(&hdmi->mutex);
 
-	dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, pdata->lcd_dev);
-}
-
-static int sh_hdmi_notify(struct notifier_block *nb,
-			  unsigned long action, void *data)
-{
-	struct fb_event *event = data;
-	struct fb_info *info = event->info;
-	struct sh_mobile_lcdc_chan *ch = info->par;
-	struct sh_mobile_lcdc_board_cfg	*board_cfg = &ch->cfg.board_cfg;
-	struct sh_hdmi *hdmi = board_cfg->board_data;
-
-	if (!hdmi || nb != &hdmi->notifier || hdmi->info != info)
-		return NOTIFY_DONE;
-
-	switch(action) {
-	case FB_EVENT_FB_REGISTERED:
-		/* Unneeded, activation taken care by sh_hdmi_display_on() */
-		break;
-	case FB_EVENT_FB_UNREGISTERED:
-		/*
-		 * We are called from unregister_framebuffer() with the
-		 * info->lock held. This is bad for us, because we can race with
-		 * the scheduled work, which has to call fb_set_suspend(), which
-		 * takes info->lock internally, so, sh_hdmi_edid_work_fn()
-		 * cannot take and hold info->lock for the whole function
-		 * duration. Using an additional lock creates a classical AB-BA
-		 * lock up. Therefore, we have to release the info->lock
-		 * temporarily, synchronise with the work queue and re-acquire
-		 * the info->lock.
-		 */
-		unlock_fb_info(info);
-		mutex_lock(&hdmi->mutex);
-		hdmi->info = NULL;
-		mutex_unlock(&hdmi->mutex);
-		lock_fb_info(info);
-		return NOTIFY_OK;
-	}
-	return NOTIFY_DONE;
+	dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, hdmi);
 }
 
 static int __init sh_hdmi_probe(struct platform_device *pdev)
 {
 	struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data;
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	struct sh_mobile_lcdc_board_cfg	*board_cfg;
 	int irq = platform_get_irq(pdev, 0), ret;
 	struct sh_hdmi *hdmi;
 	long rate;
@@ -1255,9 +1127,9 @@
 		return -ENOMEM;
 	}
 
-	mutex_init(&hdmi->mutex);
-
 	hdmi->dev = &pdev->dev;
+	hdmi->entity.owner = THIS_MODULE;
+	hdmi->entity.ops = &sh_hdmi_ops;
 
 	hdmi->hdmi_clk = clk_get(&pdev->dev, "ick");
 	if (IS_ERR(hdmi->hdmi_clk)) {
@@ -1297,14 +1169,7 @@
 		goto emap;
 	}
 
-	platform_set_drvdata(pdev, hdmi);
-
-	/* Set up LCDC callbacks */
-	board_cfg = &pdata->lcd_chan->board_cfg;
-	board_cfg->owner = THIS_MODULE;
-	board_cfg->board_data = hdmi;
-	board_cfg->display_on = sh_hdmi_display_on;
-	board_cfg->display_off = sh_hdmi_display_off;
+	platform_set_drvdata(pdev, &hdmi->entity);
 
 	INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn);
 
@@ -1329,9 +1194,6 @@
 		goto ecodec;
 	}
 
-	hdmi->notifier.notifier_call = sh_hdmi_notify;
-	fb_register_client(&hdmi->notifier);
-
 	return 0;
 
 ecodec:
@@ -1347,7 +1209,6 @@
 erate:
 	clk_put(hdmi->hdmi_clk);
 egetclk:
-	mutex_destroy(&hdmi->mutex);
 	kfree(hdmi);
 
 	return ret;
@@ -1355,21 +1216,12 @@
 
 static int __exit sh_hdmi_remove(struct platform_device *pdev)
 {
-	struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data;
-	struct sh_hdmi *hdmi = platform_get_drvdata(pdev);
+	struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev));
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	struct sh_mobile_lcdc_board_cfg	*board_cfg = &pdata->lcd_chan->board_cfg;
 	int irq = platform_get_irq(pdev, 0);
 
 	snd_soc_unregister_codec(&pdev->dev);
 
-	fb_unregister_client(&hdmi->notifier);
-
-	board_cfg->display_on = NULL;
-	board_cfg->display_off = NULL;
-	board_cfg->board_data = NULL;
-	board_cfg->owner = NULL;
-
 	/* No new work will be scheduled, wait for running ISR */
 	free_irq(irq, hdmi);
 	/* Wait for already scheduled work */
@@ -1380,7 +1232,6 @@
 	clk_put(hdmi->hdmi_clk);
 	iounmap(hdmi->base);
 	release_mem_region(res->start, resource_size(res));
-	mutex_destroy(&hdmi->mutex);
 	kfree(hdmi);
 
 	return 0;
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index aac5b36..7a0b301 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -8,26 +8,27 @@
  * for more details.
  */
 
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/mm.h>
+#include <linux/atomic.h>
+#include <linux/backlight.h>
 #include <linux/clk.h>
-#include <linux/pm_runtime.h>
-#include <linux/platform_device.h>
+#include <linux/console.h>
 #include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <linux/vmalloc.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-#include <linux/console.h>
-#include <linux/backlight.h>
-#include <linux/gpio.h>
-#include <linux/module.h>
+
 #include <video/sh_mobile_lcdc.h>
 #include <video/sh_mobile_meram.h>
-#include <linux/atomic.h>
 
 #include "sh_mobile_lcdcfb.h"
 
@@ -37,6 +38,24 @@
 #define MAX_XRES 1920
 #define MAX_YRES 1080
 
+struct sh_mobile_lcdc_priv {
+	void __iomem *base;
+	int irq;
+	atomic_t hw_usecnt;
+	struct device *dev;
+	struct clk *dot_clk;
+	unsigned long lddckr;
+	struct sh_mobile_lcdc_chan ch[2];
+	struct notifier_block notifier;
+	int started;
+	int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
+	struct sh_mobile_meram_info *meram_dev;
+};
+
+/* -----------------------------------------------------------------------------
+ * Registers access
+ */
+
 static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = {
 	[LDDCKPAT1R] = 0x400,
 	[LDDCKPAT2R] = 0x404,
@@ -75,38 +94,6 @@
 	[LDPMR] = 0x63c,
 };
 
-static const struct fb_videomode default_720p = {
-	.name = "HDMI 720p",
-	.xres = 1280,
-	.yres = 720,
-
-	.left_margin = 220,
-	.right_margin = 110,
-	.hsync_len = 40,
-
-	.upper_margin = 20,
-	.lower_margin = 5,
-	.vsync_len = 5,
-
-	.pixclock = 13468,
-	.refresh = 60,
-	.sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
-};
-
-struct sh_mobile_lcdc_priv {
-	void __iomem *base;
-	int irq;
-	atomic_t hw_usecnt;
-	struct device *dev;
-	struct clk *dot_clk;
-	unsigned long lddckr;
-	struct sh_mobile_lcdc_chan ch[2];
-	struct notifier_block notifier;
-	int started;
-	int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
-	struct sh_mobile_meram_info *meram_dev;
-};
-
 static bool banked(int reg_nr)
 {
 	switch (reg_nr) {
@@ -127,6 +114,11 @@
 	return false;
 }
 
+static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan)
+{
+	return chan->cfg->chan == LCDC_CHAN_SUBLCD;
+}
+
 static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan,
 			    int reg_nr, unsigned long data)
 {
@@ -169,11 +161,72 @@
 		cpu_relax();
 }
 
-static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan)
+/* -----------------------------------------------------------------------------
+ * Clock management
+ */
+
+static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
 {
-	return chan->cfg.chan == LCDC_CHAN_SUBLCD;
+	if (atomic_inc_and_test(&priv->hw_usecnt)) {
+		if (priv->dot_clk)
+			clk_enable(priv->dot_clk);
+		pm_runtime_get_sync(priv->dev);
+		if (priv->meram_dev && priv->meram_dev->pdev)
+			pm_runtime_get_sync(&priv->meram_dev->pdev->dev);
+	}
 }
 
+static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
+{
+	if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {
+		if (priv->meram_dev && priv->meram_dev->pdev)
+			pm_runtime_put_sync(&priv->meram_dev->pdev->dev);
+		pm_runtime_put(priv->dev);
+		if (priv->dot_clk)
+			clk_disable(priv->dot_clk);
+	}
+}
+
+static int sh_mobile_lcdc_setup_clocks(struct sh_mobile_lcdc_priv *priv,
+				       int clock_source)
+{
+	struct clk *clk;
+	char *str;
+
+	switch (clock_source) {
+	case LCDC_CLK_BUS:
+		str = "bus_clk";
+		priv->lddckr = LDDCKR_ICKSEL_BUS;
+		break;
+	case LCDC_CLK_PERIPHERAL:
+		str = "peripheral_clk";
+		priv->lddckr = LDDCKR_ICKSEL_MIPI;
+		break;
+	case LCDC_CLK_EXTERNAL:
+		str = NULL;
+		priv->lddckr = LDDCKR_ICKSEL_HDMI;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (str == NULL)
+		return 0;
+
+	clk = clk_get(priv->dev, str);
+	if (IS_ERR(clk)) {
+		dev_err(priv->dev, "cannot get dot clock %s\n", str);
+		return PTR_ERR(clk);
+	}
+
+	priv->dot_clk = clk;
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Display, panel and deferred I/O
+ */
+
 static void lcdc_sys_write_index(void *handle, unsigned long data)
 {
 	struct sh_mobile_lcdc_chan *ch = handle;
@@ -216,74 +269,11 @@
 	lcdc_sys_read_data,
 };
 
-static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
-{
-	if (var->grayscale > 1)
-		return var->grayscale;
-
-	switch (var->bits_per_pixel) {
-	case 16:
-		return V4L2_PIX_FMT_RGB565;
-	case 24:
-		return V4L2_PIX_FMT_BGR24;
-	case 32:
-		return V4L2_PIX_FMT_BGR32;
-	default:
-		return 0;
-	}
-}
-
-static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
-{
-	return var->grayscale > 1;
-}
-
-static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var)
-{
-	if (var->grayscale <= 1)
-		return false;
-
-	switch (var->grayscale) {
-	case V4L2_PIX_FMT_NV12:
-	case V4L2_PIX_FMT_NV21:
-	case V4L2_PIX_FMT_NV16:
-	case V4L2_PIX_FMT_NV61:
-	case V4L2_PIX_FMT_NV24:
-	case V4L2_PIX_FMT_NV42:
-		return true;
-
-	default:
-		return false;
-	}
-}
-
-static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
-{
-	if (atomic_inc_and_test(&priv->hw_usecnt)) {
-		if (priv->dot_clk)
-			clk_enable(priv->dot_clk);
-		pm_runtime_get_sync(priv->dev);
-		if (priv->meram_dev && priv->meram_dev->pdev)
-			pm_runtime_get_sync(&priv->meram_dev->pdev->dev);
-	}
-}
-
-static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
-{
-	if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {
-		if (priv->meram_dev && priv->meram_dev->pdev)
-			pm_runtime_put_sync(&priv->meram_dev->pdev->dev);
-		pm_runtime_put(priv->dev);
-		if (priv->dot_clk)
-			clk_disable(priv->dot_clk);
-	}
-}
-
 static int sh_mobile_lcdc_sginit(struct fb_info *info,
 				  struct list_head *pagelist)
 {
 	struct sh_mobile_lcdc_chan *ch = info->par;
-	unsigned int nr_pages_max = info->fix.smem_len >> PAGE_SHIFT;
+	unsigned int nr_pages_max = ch->fb_size >> PAGE_SHIFT;
 	struct page *page;
 	int nr_pages = 0;
 
@@ -299,7 +289,7 @@
 				       struct list_head *pagelist)
 {
 	struct sh_mobile_lcdc_chan *ch = info->par;
-	struct sh_mobile_lcdc_board_cfg	*bcfg = &ch->cfg.board_cfg;
+	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
 
 	/* enable clocks before accessing hardware */
 	sh_mobile_lcdc_clk_on(ch->lcdc);
@@ -323,16 +313,15 @@
 		unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagelist);
 
 		/* trigger panel update */
-		dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
-		if (bcfg->start_transfer)
-			bcfg->start_transfer(bcfg->board_data, ch,
-					     &sh_mobile_lcdc_sys_bus_ops);
+		dma_map_sg(ch->lcdc->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
+		if (panel->start_transfer)
+			panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
 		lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
-		dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
+		dma_unmap_sg(ch->lcdc->dev, ch->sglist, nr_pages,
+			     DMA_TO_DEVICE);
 	} else {
-		if (bcfg->start_transfer)
-			bcfg->start_transfer(bcfg->board_data, ch,
-					     &sh_mobile_lcdc_sys_bus_ops);
+		if (panel->start_transfer)
+			panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
 		lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
 	}
 }
@@ -345,6 +334,217 @@
 		schedule_delayed_work(&info->deferred_work, fbdefio->delay);
 }
 
+static void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)
+{
+	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
+
+	if (ch->tx_dev) {
+		int ret;
+
+		ret = ch->tx_dev->ops->display_on(ch->tx_dev);
+		if (ret < 0)
+			return;
+
+		if (ret == SH_MOBILE_LCDC_DISPLAY_DISCONNECTED)
+			ch->info->state = FBINFO_STATE_SUSPENDED;
+	}
+
+	/* HDMI must be enabled before LCDC configuration */
+	if (panel->display_on)
+		panel->display_on();
+}
+
+static void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch)
+{
+	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
+
+	if (panel->display_off)
+		panel->display_off();
+
+	if (ch->tx_dev)
+		ch->tx_dev->ops->display_off(ch->tx_dev);
+}
+
+static bool
+sh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch,
+				const struct fb_videomode *new_mode)
+{
+	dev_dbg(ch->info->dev, "Old %ux%u, new %ux%u\n",
+		ch->display.mode.xres, ch->display.mode.yres,
+		new_mode->xres, new_mode->yres);
+
+	/* It can be a different monitor with an equal video-mode */
+	if (fb_mode_is_equal(&ch->display.mode, new_mode))
+		return false;
+
+	dev_dbg(ch->info->dev, "Switching %u -> %u lines\n",
+		ch->display.mode.yres, new_mode->yres);
+	ch->display.mode = *new_mode;
+
+	return true;
+}
+
+static int sh_mobile_check_var(struct fb_var_screeninfo *var,
+			       struct fb_info *info);
+
+static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
+					 enum sh_mobile_lcdc_entity_event event,
+					 const struct fb_videomode *mode,
+					 const struct fb_monspecs *monspec)
+{
+	struct fb_info *info = ch->info;
+	struct fb_var_screeninfo var;
+	int ret = 0;
+
+	switch (event) {
+	case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT:
+		/* HDMI plug in */
+		if (lock_fb_info(info)) {
+			console_lock();
+
+			ch->display.width = monspec->max_x * 10;
+			ch->display.height = monspec->max_y * 10;
+
+			if (!sh_mobile_lcdc_must_reconfigure(ch, mode) &&
+			    info->state == FBINFO_STATE_RUNNING) {
+				/* First activation with the default monitor.
+				 * Just turn on, if we run a resume here, the
+				 * logo disappears.
+				 */
+				info->var.width = monspec->max_x * 10;
+				info->var.height = monspec->max_y * 10;
+				sh_mobile_lcdc_display_on(ch);
+			} else {
+				/* New monitor or have to wake up */
+				fb_set_suspend(info, 0);
+			}
+
+			console_unlock();
+			unlock_fb_info(info);
+		}
+		break;
+
+	case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT:
+		/* HDMI disconnect */
+		if (lock_fb_info(info)) {
+			console_lock();
+			fb_set_suspend(info, 1);
+			console_unlock();
+			unlock_fb_info(info);
+		}
+		break;
+
+	case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE:
+		/* Validate a proposed new mode */
+		fb_videomode_to_var(&var, mode);
+		var.bits_per_pixel = info->var.bits_per_pixel;
+		var.grayscale = info->var.grayscale;
+		ret = sh_mobile_check_var(&var, info);
+		break;
+	}
+
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Format helpers
+ */
+
+struct sh_mobile_lcdc_format_info {
+	u32 fourcc;
+	unsigned int bpp;
+	bool yuv;
+	u32 lddfr;
+};
+
+static const struct sh_mobile_lcdc_format_info sh_mobile_format_infos[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_RGB565,
+		.bpp = 16,
+		.yuv = false,
+		.lddfr = LDDFR_PKF_RGB16,
+	}, {
+		.fourcc = V4L2_PIX_FMT_BGR24,
+		.bpp = 24,
+		.yuv = false,
+		.lddfr = LDDFR_PKF_RGB24,
+	}, {
+		.fourcc = V4L2_PIX_FMT_BGR32,
+		.bpp = 32,
+		.yuv = false,
+		.lddfr = LDDFR_PKF_ARGB32,
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.bpp = 12,
+		.yuv = true,
+		.lddfr = LDDFR_CC | LDDFR_YF_420,
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV21,
+		.bpp = 12,
+		.yuv = true,
+		.lddfr = LDDFR_CC | LDDFR_YF_420,
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV16,
+		.bpp = 16,
+		.yuv = true,
+		.lddfr = LDDFR_CC | LDDFR_YF_422,
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV61,
+		.bpp = 16,
+		.yuv = true,
+		.lddfr = LDDFR_CC | LDDFR_YF_422,
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV24,
+		.bpp = 24,
+		.yuv = true,
+		.lddfr = LDDFR_CC | LDDFR_YF_444,
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV42,
+		.bpp = 24,
+		.yuv = true,
+		.lddfr = LDDFR_CC | LDDFR_YF_444,
+	},
+};
+
+static const struct sh_mobile_lcdc_format_info *
+sh_mobile_format_info(u32 fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(sh_mobile_format_infos); ++i) {
+		if (sh_mobile_format_infos[i].fourcc == fourcc)
+			return &sh_mobile_format_infos[i];
+	}
+
+	return NULL;
+}
+
+static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
+{
+	if (var->grayscale > 1)
+		return var->grayscale;
+
+	switch (var->bits_per_pixel) {
+	case 16:
+		return V4L2_PIX_FMT_RGB565;
+	case 24:
+		return V4L2_PIX_FMT_BGR24;
+	case 32:
+		return V4L2_PIX_FMT_BGR32;
+	default:
+		return 0;
+	}
+}
+
+static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
+{
+	return var->grayscale > 1;
+}
+
+/* -----------------------------------------------------------------------------
+ * Start, stop and IRQ
+ */
+
 static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
 {
 	struct sh_mobile_lcdc_priv *priv = data;
@@ -385,6 +585,26 @@
 	return IRQ_HANDLED;
 }
 
+static int sh_mobile_wait_for_vsync(struct sh_mobile_lcdc_chan *ch)
+{
+	unsigned long ldintr;
+	int ret;
+
+	/* Enable VSync End interrupt and be careful not to acknowledge any
+	 * pending interrupt.
+	 */
+	ldintr = lcdc_read(ch->lcdc, _LDINTR);
+	ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
+	lcdc_write(ch->lcdc, _LDINTR, ldintr);
+
+	ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
+							msecs_to_jiffies(100));
+	if (!ret)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
 static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
 				      int start)
 {
@@ -416,53 +636,52 @@
 
 static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
 {
-	struct fb_var_screeninfo *var = &ch->info->var, *display_var = &ch->display_var;
+	const struct fb_var_screeninfo *var = &ch->info->var;
+	const struct fb_videomode *mode = &ch->display.mode;
 	unsigned long h_total, hsync_pos, display_h_total;
 	u32 tmp;
 
 	tmp = ch->ldmt1r_value;
 	tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL;
 	tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL;
-	tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;
-	tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;
-	tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;
-	tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;
-	tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;
+	tmp |= (ch->cfg->flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;
+	tmp |= (ch->cfg->flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;
+	tmp |= (ch->cfg->flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;
+	tmp |= (ch->cfg->flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;
+	tmp |= (ch->cfg->flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;
 	lcdc_write_chan(ch, LDMT1R, tmp);
 
 	/* setup SYS bus */
-	lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r);
-	lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r);
+	lcdc_write_chan(ch, LDMT2R, ch->cfg->sys_bus_cfg.ldmt2r);
+	lcdc_write_chan(ch, LDMT3R, ch->cfg->sys_bus_cfg.ldmt3r);
 
 	/* horizontal configuration */
-	h_total = display_var->xres + display_var->hsync_len +
-		display_var->left_margin + display_var->right_margin;
+	h_total = mode->xres + mode->hsync_len + mode->left_margin
+		+ mode->right_margin;
 	tmp = h_total / 8; /* HTCN */
-	tmp |= (min(display_var->xres, var->xres) / 8) << 16; /* HDCN */
+	tmp |= (min(mode->xres, ch->xres) / 8) << 16; /* HDCN */
 	lcdc_write_chan(ch, LDHCNR, tmp);
 
-	hsync_pos = display_var->xres + display_var->right_margin;
+	hsync_pos = mode->xres + mode->right_margin;
 	tmp = hsync_pos / 8; /* HSYNP */
-	tmp |= (display_var->hsync_len / 8) << 16; /* HSYNW */
+	tmp |= (mode->hsync_len / 8) << 16; /* HSYNW */
 	lcdc_write_chan(ch, LDHSYNR, tmp);
 
 	/* vertical configuration */
-	tmp = display_var->yres + display_var->vsync_len +
-		display_var->upper_margin + display_var->lower_margin; /* VTLN */
-	tmp |= min(display_var->yres, var->yres) << 16; /* VDLN */
+	tmp = mode->yres + mode->vsync_len + mode->upper_margin
+	    + mode->lower_margin; /* VTLN */
+	tmp |= min(mode->yres, ch->yres) << 16; /* VDLN */
 	lcdc_write_chan(ch, LDVLNR, tmp);
 
-	tmp = display_var->yres + display_var->lower_margin; /* VSYNP */
-	tmp |= display_var->vsync_len << 16; /* VSYNW */
+	tmp = mode->yres + mode->lower_margin; /* VSYNP */
+	tmp |= mode->vsync_len << 16; /* VSYNW */
 	lcdc_write_chan(ch, LDVSYNR, tmp);
 
 	/* Adjust horizontal synchronisation for HDMI */
-	display_h_total = display_var->xres + display_var->hsync_len +
-		display_var->left_margin + display_var->right_margin;
-	tmp = ((display_var->xres & 7) << 24) |
-		((display_h_total & 7) << 16) |
-		((display_var->hsync_len & 7) << 8) |
-		(hsync_pos & 7);
+	display_h_total = mode->xres + mode->hsync_len + mode->left_margin
+			+ mode->right_margin;
+	tmp = ((mode->xres & 7) << 24) | ((display_h_total & 7) << 16)
+	    | ((mode->hsync_len & 7) << 8) | (hsync_pos & 7);
 	lcdc_write_chan(ch, LDHAJR, tmp);
 }
 
@@ -498,7 +717,7 @@
 		/* Power supply */
 		lcdc_write_chan(ch, LDPMR, 0);
 
-		m = ch->cfg.clock_divider;
+		m = ch->cfg->clock_divider;
 		if (!m)
 			continue;
 
@@ -525,32 +744,10 @@
 
 		sh_mobile_lcdc_geometry(ch);
 
-		switch (sh_mobile_format_fourcc(&ch->info->var)) {
-		case V4L2_PIX_FMT_RGB565:
-			tmp = LDDFR_PKF_RGB16;
-			break;
-		case V4L2_PIX_FMT_BGR24:
-			tmp = LDDFR_PKF_RGB24;
-			break;
-		case V4L2_PIX_FMT_BGR32:
-			tmp = LDDFR_PKF_ARGB32;
-			break;
-		case V4L2_PIX_FMT_NV12:
-		case V4L2_PIX_FMT_NV21:
-			tmp = LDDFR_CC | LDDFR_YF_420;
-			break;
-		case V4L2_PIX_FMT_NV16:
-		case V4L2_PIX_FMT_NV61:
-			tmp = LDDFR_CC | LDDFR_YF_422;
-			break;
-		case V4L2_PIX_FMT_NV24:
-		case V4L2_PIX_FMT_NV42:
-			tmp = LDDFR_CC | LDDFR_YF_444;
-			break;
-		}
+		tmp = ch->format->lddfr;
 
-		if (sh_mobile_format_is_yuv(&ch->info->var)) {
-			switch (ch->info->var.colorspace) {
+		if (ch->format->yuv) {
+			switch (ch->colorspace) {
 			case V4L2_COLORSPACE_REC709:
 				tmp |= LDDFR_CF1;
 				break;
@@ -563,7 +760,7 @@
 		lcdc_write_chan(ch, LDDFR, tmp);
 		lcdc_write_chan(ch, LDMLSR, ch->pitch);
 		lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
-		if (sh_mobile_format_is_yuv(&ch->info->var))
+		if (ch->format->yuv)
 			lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
 
 		/* When using deferred I/O mode, configure the LCDC for one-shot
@@ -571,7 +768,7 @@
 		 * continuous read mode.
 		 */
 		if (ch->ldmt1r_value & LDMT1R_IFM &&
-		    ch->cfg.sys_bus_cfg.deferred_io_msec) {
+		    ch->cfg->sys_bus_cfg.deferred_io_msec) {
 			lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);
 			lcdc_write(priv, _LDINTR, LDINTR_FE);
 		} else {
@@ -580,7 +777,7 @@
 	}
 
 	/* Word and long word swap. */
-	switch (sh_mobile_format_fourcc(&priv->ch[0].info->var)) {
+	switch (priv->ch[0].format->fourcc) {
 	case V4L2_PIX_FMT_RGB565:
 	case V4L2_PIX_FMT_NV21:
 	case V4L2_PIX_FMT_NV61:
@@ -609,7 +806,6 @@
 static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 {
 	struct sh_mobile_meram_info *mdev = priv->meram_dev;
-	struct sh_mobile_lcdc_board_cfg	*board_cfg;
 	struct sh_mobile_lcdc_chan *ch;
 	unsigned long tmp;
 	int ret;
@@ -626,15 +822,15 @@
 	lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);
 
 	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
-		ch = &priv->ch[k];
+		const struct sh_mobile_lcdc_panel_cfg *panel;
 
+		ch = &priv->ch[k];
 		if (!ch->enabled)
 			continue;
 
-		board_cfg = &ch->cfg.board_cfg;
-		if (board_cfg->setup_sys) {
-			ret = board_cfg->setup_sys(board_cfg->board_data, ch,
-						   &sh_mobile_lcdc_sys_bus_ops);
+		panel = &ch->cfg->panel_cfg;
+		if (panel->setup_sys) {
+			ret = panel->setup_sys(ch, &sh_mobile_lcdc_sys_bus_ops);
 			if (ret)
 				return ret;
 		}
@@ -642,33 +838,30 @@
 
 	/* Compute frame buffer base address and pitch for each channel. */
 	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
-		struct sh_mobile_meram_cfg *cfg;
 		int pixelformat;
+		void *meram;
 
 		ch = &priv->ch[k];
 		if (!ch->enabled)
 			continue;
 
-		ch->base_addr_y = ch->info->fix.smem_start;
-		ch->base_addr_c = ch->base_addr_y
-				+ ch->info->var.xres
-				* ch->info->var.yres_virtual;
-		ch->pitch = ch->info->fix.line_length;
+		ch->base_addr_y = ch->dma_handle;
+		ch->base_addr_c = ch->base_addr_y + ch->xres * ch->yres_virtual;
 
 		/* Enable MERAM if possible. */
-		cfg = ch->cfg.meram_cfg;
-		if (mdev == NULL || mdev->ops == NULL || cfg == NULL)
+		if (mdev == NULL || mdev->ops == NULL ||
+		    ch->cfg->meram_cfg == NULL)
 			continue;
 
 		/* we need to de-init configured ICBs before we can
 		 * re-initialize them.
 		 */
-		if (ch->meram_enabled) {
-			mdev->ops->meram_unregister(mdev, cfg);
-			ch->meram_enabled = 0;
+		if (ch->meram) {
+			mdev->ops->meram_unregister(mdev, ch->meram);
+			ch->meram = NULL;
 		}
 
-		switch (sh_mobile_format_fourcc(&ch->info->var)) {
+		switch (ch->format->fourcc) {
 		case V4L2_PIX_FMT_NV12:
 		case V4L2_PIX_FMT_NV21:
 		case V4L2_PIX_FMT_NV16:
@@ -687,13 +880,15 @@
 			break;
 		}
 
-		ret = mdev->ops->meram_register(mdev, cfg, ch->pitch,
-					ch->info->var.yres, pixelformat,
-					ch->base_addr_y, ch->base_addr_c,
-					&ch->base_addr_y, &ch->base_addr_c,
+		meram = mdev->ops->meram_register(mdev, ch->cfg->meram_cfg,
+					ch->pitch, ch->yres, pixelformat,
 					&ch->pitch);
-		if (!ret)
-			ch->meram_enabled = 1;
+		if (!IS_ERR(meram)) {
+			mdev->ops->meram_update(mdev, meram,
+					ch->base_addr_y, ch->base_addr_c,
+					&ch->base_addr_y, &ch->base_addr_c);
+			ch->meram = meram;
+		}
 	}
 
 	/* Start the LCDC. */
@@ -707,7 +902,7 @@
 		if (!ch->enabled)
 			continue;
 
-		tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
+		tmp = ch->cfg->sys_bus_cfg.deferred_io_msec;
 		if (ch->ldmt1r_value & LDMT1R_IFM && tmp) {
 			ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
 			ch->defio.delay = msecs_to_jiffies(tmp);
@@ -715,11 +910,7 @@
 			fb_deferred_io_init(ch->info);
 		}
 
-		board_cfg = &ch->cfg.board_cfg;
-		if (board_cfg->display_on && try_module_get(board_cfg->owner)) {
-			board_cfg->display_on(board_cfg->board_data, ch->info);
-			module_put(board_cfg->owner);
-		}
+		sh_mobile_lcdc_display_on(ch);
 
 		if (ch->bl) {
 			ch->bl->props.power = FB_BLANK_UNBLANK;
@@ -733,7 +924,6 @@
 static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
 {
 	struct sh_mobile_lcdc_chan *ch;
-	struct sh_mobile_lcdc_board_cfg	*board_cfg;
 	int k;
 
 	/* clean up deferred io and ask board code to disable panel */
@@ -760,20 +950,14 @@
 			backlight_update_status(ch->bl);
 		}
 
-		board_cfg = &ch->cfg.board_cfg;
-		if (board_cfg->display_off && try_module_get(board_cfg->owner)) {
-			board_cfg->display_off(board_cfg->board_data);
-			module_put(board_cfg->owner);
-		}
+		sh_mobile_lcdc_display_off(ch);
 
 		/* disable the meram */
-		if (ch->meram_enabled) {
-			struct sh_mobile_meram_cfg *cfg;
+		if (ch->meram) {
 			struct sh_mobile_meram_info *mdev;
-			cfg = ch->cfg.meram_cfg;
 			mdev = priv->meram_dev;
-			mdev->ops->meram_unregister(mdev, cfg);
-			ch->meram_enabled = 0;
+			mdev->ops->meram_unregister(mdev, ch->meram);
+			ch->meram = 0;
 		}
 
 	}
@@ -790,86 +974,9 @@
 			sh_mobile_lcdc_clk_off(priv);
 }
 
-static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
-{
-	int interface_type = ch->cfg.interface_type;
-
-	switch (interface_type) {
-	case RGB8:
-	case RGB9:
-	case RGB12A:
-	case RGB12B:
-	case RGB16:
-	case RGB18:
-	case RGB24:
-	case SYS8A:
-	case SYS8B:
-	case SYS8C:
-	case SYS8D:
-	case SYS9:
-	case SYS12:
-	case SYS16A:
-	case SYS16B:
-	case SYS16C:
-	case SYS18:
-	case SYS24:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* SUBLCD only supports SYS interface */
-	if (lcdc_chan_is_sublcd(ch)) {
-		if (!(interface_type & LDMT1R_IFM))
-			return -EINVAL;
-
-		interface_type &= ~LDMT1R_IFM;
-	}
-
-	ch->ldmt1r_value = interface_type;
-	return 0;
-}
-
-static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
-				       int clock_source,
-				       struct sh_mobile_lcdc_priv *priv)
-{
-	char *str;
-
-	switch (clock_source) {
-	case LCDC_CLK_BUS:
-		str = "bus_clk";
-		priv->lddckr = LDDCKR_ICKSEL_BUS;
-		break;
-	case LCDC_CLK_PERIPHERAL:
-		str = "peripheral_clk";
-		priv->lddckr = LDDCKR_ICKSEL_MIPI;
-		break;
-	case LCDC_CLK_EXTERNAL:
-		str = NULL;
-		priv->lddckr = LDDCKR_ICKSEL_HDMI;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (str) {
-		priv->dot_clk = clk_get(&pdev->dev, str);
-		if (IS_ERR(priv->dot_clk)) {
-			dev_err(&pdev->dev, "cannot get dot clock %s\n", str);
-			return PTR_ERR(priv->dot_clk);
-		}
-	}
-
-	/* Runtime PM support involves two step for this driver:
-	 * 1) Enable Runtime PM
-	 * 2) Force Runtime PM Resume since hardware is accessed from probe()
-	 */
-	priv->dev = &pdev->dev;
-	pm_runtime_enable(priv->dev);
-	pm_runtime_resume(priv->dev);
-	return 0;
-}
+/* -----------------------------------------------------------------------------
+ * Frame buffer operations
+ */
 
 static int sh_mobile_lcdc_setcolreg(u_int regno,
 				    u_int red, u_int green, u_int blue,
@@ -936,14 +1043,12 @@
 	unsigned long new_pan_offset;
 	unsigned long base_addr_y, base_addr_c;
 	unsigned long c_offset;
-	bool yuv = sh_mobile_format_is_yuv(&info->var);
 
-	if (!yuv)
-		new_pan_offset = var->yoffset * info->fix.line_length
-			       + var->xoffset * (info->var.bits_per_pixel / 8);
+	if (!ch->format->yuv)
+		new_pan_offset = var->yoffset * ch->pitch
+			       + var->xoffset * (ch->format->bpp / 8);
 	else
-		new_pan_offset = var->yoffset * info->fix.line_length
-			       + var->xoffset;
+		new_pan_offset = var->yoffset * ch->pitch + var->xoffset;
 
 	if (new_pan_offset == ch->pan_offset)
 		return 0;	/* No change, do nothing */
@@ -952,39 +1057,33 @@
 
 	/* Set the source address for the next refresh */
 	base_addr_y = ch->dma_handle + new_pan_offset;
-	if (yuv) {
+	if (ch->format->yuv) {
 		/* Set y offset */
-		c_offset = var->yoffset * info->fix.line_length
-			 * (info->var.bits_per_pixel - 8) / 8;
-		base_addr_c = ch->dma_handle
-			    + info->var.xres * info->var.yres_virtual
+		c_offset = var->yoffset * ch->pitch
+			 * (ch->format->bpp - 8) / 8;
+		base_addr_c = ch->dma_handle + ch->xres * ch->yres_virtual
 			    + c_offset;
 		/* Set x offset */
-		if (sh_mobile_format_fourcc(&info->var) == V4L2_PIX_FMT_NV24)
+		if (ch->format->fourcc == V4L2_PIX_FMT_NV24)
 			base_addr_c += 2 * var->xoffset;
 		else
 			base_addr_c += var->xoffset;
 	}
 
-	if (ch->meram_enabled) {
-		struct sh_mobile_meram_cfg *cfg;
+	if (ch->meram) {
 		struct sh_mobile_meram_info *mdev;
-		int ret;
 
-		cfg = ch->cfg.meram_cfg;
 		mdev = priv->meram_dev;
-		ret = mdev->ops->meram_update(mdev, cfg,
+		mdev->ops->meram_update(mdev, ch->meram,
 					base_addr_y, base_addr_c,
 					&base_addr_y, &base_addr_c);
-		if (ret)
-			return ret;
 	}
 
 	ch->base_addr_y = base_addr_y;
 	ch->base_addr_c = base_addr_c;
 
 	lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
-	if (yuv)
+	if (ch->format->yuv)
 		lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
 
 	if (lcdc_chan_is_sublcd(ch))
@@ -999,27 +1098,6 @@
 	return 0;
 }
 
-static int sh_mobile_wait_for_vsync(struct fb_info *info)
-{
-	struct sh_mobile_lcdc_chan *ch = info->par;
-	unsigned long ldintr;
-	int ret;
-
-	/* Enable VSync End interrupt and be careful not to acknowledge any
-	 * pending interrupt.
-	 */
-	ldintr = lcdc_read(ch->lcdc, _LDINTR);
-	ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
-	lcdc_write(ch->lcdc, _LDINTR, ldintr);
-
-	ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
-							msecs_to_jiffies(100));
-	if (!ret)
-		return -ETIMEDOUT;
-
-	return 0;
-}
-
 static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd,
 		       unsigned long arg)
 {
@@ -1027,7 +1105,7 @@
 
 	switch (cmd) {
 	case FBIO_WAITFORVSYNC:
-		retval = sh_mobile_wait_for_vsync(info);
+		retval = sh_mobile_wait_for_vsync(info->par);
 		break;
 
 	default:
@@ -1040,7 +1118,8 @@
 static void sh_mobile_fb_reconfig(struct fb_info *info)
 {
 	struct sh_mobile_lcdc_chan *ch = info->par;
-	struct fb_videomode mode1, mode2;
+	struct fb_var_screeninfo var;
+	struct fb_videomode mode;
 	struct fb_event event;
 	int evnt = FB_EVENT_MODE_CHANGE_ALL;
 
@@ -1048,14 +1127,19 @@
 		/* More framebuffer users are active */
 		return;
 
-	fb_var_to_videomode(&mode1, &ch->display_var);
-	fb_var_to_videomode(&mode2, &info->var);
+	fb_var_to_videomode(&mode, &info->var);
 
-	if (fb_mode_is_equal(&mode1, &mode2))
+	if (fb_mode_is_equal(&ch->display.mode, &mode))
 		return;
 
 	/* Display has been re-plugged, framebuffer is free now, reconfigure */
-	if (fb_set_var(info, &ch->display_var) < 0)
+	var = info->var;
+	fb_videomode_to_var(&var, &ch->display.mode);
+	var.width = ch->display.width;
+	var.height = ch->display.height;
+	var.activate = FB_ACTIVATE_NOW;
+
+	if (fb_set_var(info, &var) < 0)
 		/* Couldn't reconfigure, hopefully, can continue as before */
 		return;
 
@@ -1065,7 +1149,7 @@
 	 * user event, we have to call the chain ourselves.
 	 */
 	event.info = info;
-	event.data = &mode1;
+	event.data = &ch->display.mode;
 	fb_notifier_call_chain(evnt, &event);
 }
 
@@ -1124,8 +1208,8 @@
 	 * distance between two modes is defined as the size of the
 	 * non-overlapping parts of the two rectangles.
 	 */
-	for (i = 0; i < ch->cfg.num_cfg; ++i) {
-		const struct fb_videomode *mode = &ch->cfg.lcd_cfg[i];
+	for (i = 0; i < ch->cfg->num_modes; ++i) {
+		const struct fb_videomode *mode = &ch->cfg->lcd_modes[i];
 		unsigned int dist;
 
 		/* We can only round up. */
@@ -1144,7 +1228,7 @@
 	}
 
 	/* If no available mode can be used, return an error. */
-	if (ch->cfg.num_cfg != 0) {
+	if (ch->cfg->num_modes != 0) {
 		if (best_dist == (unsigned int)-1)
 			return -EINVAL;
 
@@ -1161,32 +1245,17 @@
 		var->yres_virtual = var->yres;
 
 	if (sh_mobile_format_is_fourcc(var)) {
-		switch (var->grayscale) {
-		case V4L2_PIX_FMT_NV12:
-		case V4L2_PIX_FMT_NV21:
-			var->bits_per_pixel = 12;
-			break;
-		case V4L2_PIX_FMT_RGB565:
-		case V4L2_PIX_FMT_NV16:
-		case V4L2_PIX_FMT_NV61:
-			var->bits_per_pixel = 16;
-			break;
-		case V4L2_PIX_FMT_BGR24:
-		case V4L2_PIX_FMT_NV24:
-		case V4L2_PIX_FMT_NV42:
-			var->bits_per_pixel = 24;
-			break;
-		case V4L2_PIX_FMT_BGR32:
-			var->bits_per_pixel = 32;
-			break;
-		default:
+		const struct sh_mobile_lcdc_format_info *format;
+
+		format = sh_mobile_format_info(var->grayscale);
+		if (format == NULL)
 			return -EINVAL;
-		}
+		var->bits_per_pixel = format->bpp;
 
 		/* Default to RGB and JPEG color-spaces for RGB and YUV formats
 		 * respectively.
 		 */
-		if (!sh_mobile_format_is_yuv(var))
+		if (!format->yuv)
 			var->colorspace = V4L2_COLORSPACE_SRGB;
 		else if (var->colorspace != V4L2_COLORSPACE_REC709)
 			var->colorspace = V4L2_COLORSPACE_JPEG;
@@ -1246,22 +1315,28 @@
 static int sh_mobile_set_par(struct fb_info *info)
 {
 	struct sh_mobile_lcdc_chan *ch = info->par;
-	u32 line_length = info->fix.line_length;
 	int ret;
 
 	sh_mobile_lcdc_stop(ch->lcdc);
 
-	if (sh_mobile_format_is_yuv(&info->var))
-		info->fix.line_length = info->var.xres;
+	ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
+	ch->colorspace = info->var.colorspace;
+
+	ch->xres = info->var.xres;
+	ch->xres_virtual = info->var.xres_virtual;
+	ch->yres = info->var.yres;
+	ch->yres_virtual = info->var.yres_virtual;
+
+	if (ch->format->yuv)
+		ch->pitch = info->var.xres;
 	else
-		info->fix.line_length = info->var.xres
-				      * info->var.bits_per_pixel / 8;
+		ch->pitch = info->var.xres * ch->format->bpp / 8;
 
 	ret = sh_mobile_lcdc_start(ch->lcdc);
-	if (ret < 0) {
+	if (ret < 0)
 		dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);
-		info->fix.line_length = line_length;
-	}
+
+	info->fix.line_length = ch->pitch;
 
 	if (sh_mobile_format_is_fourcc(&info->var)) {
 		info->fix.type = FB_TYPE_FOURCC;
@@ -1290,8 +1365,8 @@
 	/* blank the screen? */
 	if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) {
 		struct fb_fillrect rect = {
-			.width = info->var.xres,
-			.height = info->var.yres,
+			.width = ch->xres,
+			.height = ch->yres,
 		};
 		sh_mobile_lcdc_fillrect(info, &rect);
 	}
@@ -1307,8 +1382,8 @@
 		 * mode will reenable the clocks and update the screen in time,
 		 * so it does not need this. */
 		if (!info->fbdefio) {
-			sh_mobile_wait_for_vsync(info);
-			sh_mobile_wait_for_vsync(info);
+			sh_mobile_wait_for_vsync(ch);
+			sh_mobile_wait_for_vsync(ch);
 		}
 		sh_mobile_lcdc_clk_off(p);
 	}
@@ -1334,25 +1409,161 @@
 	.fb_set_par	= sh_mobile_set_par,
 };
 
+static void
+sh_mobile_lcdc_channel_fb_unregister(struct sh_mobile_lcdc_chan *ch)
+{
+	if (ch->info && ch->info->dev)
+		unregister_framebuffer(ch->info);
+}
+
+static int __devinit
+sh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch)
+{
+	struct fb_info *info = ch->info;
+	int ret;
+
+	if (info->fbdefio) {
+		ch->sglist = vmalloc(sizeof(struct scatterlist) *
+				     ch->fb_size >> PAGE_SHIFT);
+		if (!ch->sglist) {
+			dev_err(ch->lcdc->dev, "cannot allocate sglist\n");
+			return -ENOMEM;
+		}
+	}
+
+	info->bl_dev = ch->bl;
+
+	ret = register_framebuffer(info);
+	if (ret < 0)
+		return ret;
+
+	dev_info(ch->lcdc->dev, "registered %s/%s as %dx%d %dbpp.\n",
+		 dev_name(ch->lcdc->dev), (ch->cfg->chan == LCDC_CHAN_MAINLCD) ?
+		 "mainlcd" : "sublcd", info->var.xres, info->var.yres,
+		 info->var.bits_per_pixel);
+
+	/* deferred io mode: disable clock to save power */
+	if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)
+		sh_mobile_lcdc_clk_off(ch->lcdc);
+
+	return ret;
+}
+
+static void
+sh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch)
+{
+	struct fb_info *info = ch->info;
+
+	if (!info || !info->device)
+		return;
+
+	if (ch->sglist)
+		vfree(ch->sglist);
+
+	fb_dealloc_cmap(&info->cmap);
+	framebuffer_release(info);
+}
+
+static int __devinit
+sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
+			       const struct fb_videomode *mode,
+			       unsigned int num_modes)
+{
+	struct sh_mobile_lcdc_priv *priv = ch->lcdc;
+	struct fb_var_screeninfo *var;
+	struct fb_info *info;
+	int ret;
+
+	/* Allocate and initialize the frame buffer device. Create the modes
+	 * list and allocate the color map.
+	 */
+	info = framebuffer_alloc(0, priv->dev);
+	if (info == NULL) {
+		dev_err(priv->dev, "unable to allocate fb_info\n");
+		return -ENOMEM;
+	}
+
+	ch->info = info;
+
+	info->flags = FBINFO_FLAG_DEFAULT;
+	info->fbops = &sh_mobile_lcdc_ops;
+	info->device = priv->dev;
+	info->screen_base = ch->fb_mem;
+	info->pseudo_palette = &ch->pseudo_palette;
+	info->par = ch;
+
+	fb_videomode_to_modelist(mode, num_modes, &info->modelist);
+
+	ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
+	if (ret < 0) {
+		dev_err(priv->dev, "unable to allocate cmap\n");
+		return ret;
+	}
+
+	/* Initialize fixed screen information. Restrict pan to 2 lines steps
+	 * for NV12 and NV21.
+	 */
+	info->fix = sh_mobile_lcdc_fix;
+	info->fix.smem_start = ch->dma_handle;
+	info->fix.smem_len = ch->fb_size;
+	info->fix.line_length = ch->pitch;
+
+	if (ch->format->yuv)
+		info->fix.visual = FB_VISUAL_FOURCC;
+	else
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+	if (ch->format->fourcc == V4L2_PIX_FMT_NV12 ||
+	    ch->format->fourcc == V4L2_PIX_FMT_NV21)
+		info->fix.ypanstep = 2;
+
+	/* Initialize variable screen information using the first mode as
+	 * default. The default Y virtual resolution is twice the panel size to
+	 * allow for double-buffering.
+	 */
+	var = &info->var;
+	fb_videomode_to_var(var, mode);
+	var->width = ch->cfg->panel_cfg.width;
+	var->height = ch->cfg->panel_cfg.height;
+	var->yres_virtual = var->yres * 2;
+	var->activate = FB_ACTIVATE_NOW;
+
+	/* Use the legacy API by default for RGB formats, and the FOURCC API
+	 * for YUV formats.
+	 */
+	if (!ch->format->yuv)
+		var->bits_per_pixel = ch->format->bpp;
+	else
+		var->grayscale = ch->format->fourcc;
+
+	ret = sh_mobile_check_var(var, info);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Backlight
+ */
+
 static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev)
 {
 	struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
-	struct sh_mobile_lcdc_board_cfg *cfg = &ch->cfg.board_cfg;
 	int brightness = bdev->props.brightness;
 
 	if (bdev->props.power != FB_BLANK_UNBLANK ||
 	    bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
 		brightness = 0;
 
-	return cfg->set_brightness(cfg->board_data, brightness);
+	return ch->cfg->bl_info.set_brightness(brightness);
 }
 
 static int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev)
 {
 	struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
-	struct sh_mobile_lcdc_board_cfg *cfg = &ch->cfg.board_cfg;
 
-	return cfg->get_brightness(cfg->board_data);
+	return ch->cfg->bl_info.get_brightness();
 }
 
 static int sh_mobile_lcdc_check_fb(struct backlight_device *bdev,
@@ -1373,7 +1584,7 @@
 {
 	struct backlight_device *bl;
 
-	bl = backlight_device_register(ch->cfg.bl_info.name, parent, ch,
+	bl = backlight_device_register(ch->cfg->bl_info.name, parent, ch,
 				       &sh_mobile_lcdc_bl_ops, NULL);
 	if (IS_ERR(bl)) {
 		dev_err(parent, "unable to register backlight device: %ld\n",
@@ -1381,7 +1592,7 @@
 		return NULL;
 	}
 
-	bl->props.max_brightness = ch->cfg.bl_info.max_brightness;
+	bl->props.max_brightness = ch->cfg->bl_info.max_brightness;
 	bl->props.brightness = bl->props.max_brightness;
 	backlight_update_status(bl);
 
@@ -1393,6 +1604,10 @@
 	backlight_device_unregister(bdev);
 }
 
+/* -----------------------------------------------------------------------------
+ * Power management
+ */
+
 static int sh_mobile_lcdc_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
@@ -1436,6 +1651,10 @@
 	.runtime_resume = sh_mobile_lcdc_runtime_resume,
 };
 
+/* -----------------------------------------------------------------------------
+ * Framebuffer notifier
+ */
+
 /* locking: called with info->lock held */
 static int sh_mobile_lcdc_notify(struct notifier_block *nb,
 				 unsigned long action, void *data)
@@ -1443,7 +1662,6 @@
 	struct fb_event *event = data;
 	struct fb_info *info = event->info;
 	struct sh_mobile_lcdc_chan *ch = info->par;
-	struct sh_mobile_lcdc_board_cfg	*board_cfg = &ch->cfg.board_cfg;
 
 	if (&ch->lcdc->notifier != nb)
 		return NOTIFY_DONE;
@@ -1453,10 +1671,7 @@
 
 	switch(action) {
 	case FB_EVENT_SUSPEND:
-		if (board_cfg->display_off && try_module_get(board_cfg->owner)) {
-			board_cfg->display_off(board_cfg->board_data);
-			module_put(board_cfg->owner);
-		}
+		sh_mobile_lcdc_display_off(ch);
 		sh_mobile_lcdc_stop(ch->lcdc);
 		break;
 	case FB_EVENT_RESUME:
@@ -1464,47 +1679,60 @@
 		sh_mobile_fb_reconfig(info);
 		mutex_unlock(&ch->open_lock);
 
-		/* HDMI must be enabled before LCDC configuration */
-		if (board_cfg->display_on && try_module_get(board_cfg->owner)) {
-			board_cfg->display_on(board_cfg->board_data, info);
-			module_put(board_cfg->owner);
-		}
-
+		sh_mobile_lcdc_display_on(ch);
 		sh_mobile_lcdc_start(ch->lcdc);
 	}
 
 	return NOTIFY_OK;
 }
 
+/* -----------------------------------------------------------------------------
+ * Probe/remove and driver init/exit
+ */
+
+static const struct fb_videomode default_720p __devinitconst = {
+	.name = "HDMI 720p",
+	.xres = 1280,
+	.yres = 720,
+
+	.left_margin = 220,
+	.right_margin = 110,
+	.hsync_len = 40,
+
+	.upper_margin = 20,
+	.lower_margin = 5,
+	.vsync_len = 5,
+
+	.pixclock = 13468,
+	.refresh = 60,
+	.sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
+};
+
 static int sh_mobile_lcdc_remove(struct platform_device *pdev)
 {
 	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
-	struct fb_info *info;
 	int i;
 
 	fb_unregister_client(&priv->notifier);
 
 	for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
-		if (priv->ch[i].info && priv->ch[i].info->dev)
-			unregister_framebuffer(priv->ch[i].info);
+		sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]);
 
 	sh_mobile_lcdc_stop(priv);
 
 	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
-		info = priv->ch[i].info;
+		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
 
-		if (!info || !info->device)
-			continue;
+		if (ch->tx_dev) {
+			ch->tx_dev->lcdc = NULL;
+			module_put(ch->cfg->tx_dev->dev.driver->owner);
+		}
 
-		if (priv->ch[i].sglist)
-			vfree(priv->ch[i].sglist);
+		sh_mobile_lcdc_channel_fb_cleanup(ch);
 
-		if (info->screen_base)
-			dma_free_coherent(&pdev->dev, info->fix.smem_len,
-					  info->screen_base,
-					  priv->ch[i].dma_handle);
-		fb_dealloc_cmap(&info->cmap);
-		framebuffer_release(info);
+		if (ch->fb_mem)
+			dma_free_coherent(&pdev->dev, ch->fb_size,
+					  ch->fb_mem, ch->dma_handle);
 	}
 
 	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
@@ -1512,11 +1740,10 @@
 			sh_mobile_lcdc_bl_remove(priv->ch[i].bl);
 	}
 
-	if (priv->dot_clk)
+	if (priv->dot_clk) {
+		pm_runtime_disable(&pdev->dev);
 		clk_put(priv->dot_clk);
-
-	if (priv->dev)
-		pm_runtime_disable(priv->dev);
+	}
 
 	if (priv->base)
 		iounmap(priv->base);
@@ -1527,34 +1754,67 @@
 	return 0;
 }
 
-static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
-						 struct device *dev)
+static int __devinit sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
 {
-	struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
-	const struct fb_videomode *max_mode;
-	const struct fb_videomode *mode;
-	struct fb_var_screeninfo *var;
-	struct fb_info *info;
-	unsigned int max_size;
-	int num_cfg;
-	void *buf;
-	int ret;
-	int i;
+	int interface_type = ch->cfg->interface_type;
 
-	mutex_init(&ch->open_lock);
-
-	/* Allocate the frame buffer device. */
-	ch->info = framebuffer_alloc(0, dev);
-	if (!ch->info) {
-		dev_err(dev, "unable to allocate fb_info\n");
-		return -ENOMEM;
+	switch (interface_type) {
+	case RGB8:
+	case RGB9:
+	case RGB12A:
+	case RGB12B:
+	case RGB16:
+	case RGB18:
+	case RGB24:
+	case SYS8A:
+	case SYS8B:
+	case SYS8C:
+	case SYS8D:
+	case SYS9:
+	case SYS12:
+	case SYS16A:
+	case SYS16B:
+	case SYS16C:
+	case SYS18:
+	case SYS24:
+		break;
+	default:
+		return -EINVAL;
 	}
 
-	info = ch->info;
-	info->fbops = &sh_mobile_lcdc_ops;
-	info->par = ch;
-	info->pseudo_palette = &ch->pseudo_palette;
-	info->flags = FBINFO_FLAG_DEFAULT;
+	/* SUBLCD only supports SYS interface */
+	if (lcdc_chan_is_sublcd(ch)) {
+		if (!(interface_type & LDMT1R_IFM))
+			return -EINVAL;
+
+		interface_type &= ~LDMT1R_IFM;
+	}
+
+	ch->ldmt1r_value = interface_type;
+	return 0;
+}
+
+static int __devinit
+sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
+			    struct sh_mobile_lcdc_chan *ch)
+{
+	const struct sh_mobile_lcdc_format_info *format;
+	const struct sh_mobile_lcdc_chan_cfg *cfg = ch->cfg;
+	const struct fb_videomode *max_mode;
+	const struct fb_videomode *mode;
+	unsigned int num_modes;
+	unsigned int max_size;
+	unsigned int i;
+
+	mutex_init(&ch->open_lock);
+	ch->notify = sh_mobile_lcdc_display_notify;
+
+	/* Validate the format. */
+	format = sh_mobile_format_info(cfg->fourcc);
+	if (format == NULL) {
+		dev_err(priv->dev, "Invalid FOURCC %08x.\n", cfg->fourcc);
+		return -EINVAL;
+	}
 
 	/* Iterate through the modes to validate them and find the highest
 	 * resolution.
@@ -1562,14 +1822,14 @@
 	max_mode = NULL;
 	max_size = 0;
 
-	for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) {
+	for (i = 0, mode = cfg->lcd_modes; i < cfg->num_modes; i++, mode++) {
 		unsigned int size = mode->yres * mode->xres;
 
 		/* NV12/NV21 buffers must have even number of lines */
 		if ((cfg->fourcc == V4L2_PIX_FMT_NV12 ||
 		     cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) {
-			dev_err(dev, "yres must be multiple of 2 for YCbCr420 "
-				"mode.\n");
+			dev_err(priv->dev, "yres must be multiple of 2 for "
+				"YCbCr420 mode.\n");
 			return -EINVAL;
 		}
 
@@ -1582,93 +1842,59 @@
 	if (!max_size)
 		max_size = MAX_XRES * MAX_YRES;
 	else
-		dev_dbg(dev, "Found largest videomode %ux%u\n",
+		dev_dbg(priv->dev, "Found largest videomode %ux%u\n",
 			max_mode->xres, max_mode->yres);
 
-	/* Create the mode list. */
-	if (cfg->lcd_cfg == NULL) {
+	if (cfg->lcd_modes == NULL) {
 		mode = &default_720p;
-		num_cfg = 1;
+		num_modes = 1;
 	} else {
-		mode = cfg->lcd_cfg;
-		num_cfg = cfg->num_cfg;
+		mode = cfg->lcd_modes;
+		num_modes = cfg->num_modes;
 	}
 
-	fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
+	/* Use the first mode as default. */
+	ch->format = format;
+	ch->xres = mode->xres;
+	ch->xres_virtual = mode->xres;
+	ch->yres = mode->yres;
+	ch->yres_virtual = mode->yres * 2;
 
-	/* Initialize variable screen information using the first mode as
-	 * default. The default Y virtual resolution is twice the panel size to
-	 * allow for double-buffering.
-	 */
-	var = &info->var;
-	fb_videomode_to_var(var, mode);
-	var->width = cfg->lcd_size_cfg.width;
-	var->height = cfg->lcd_size_cfg.height;
-	var->yres_virtual = var->yres * 2;
-	var->activate = FB_ACTIVATE_NOW;
-
-	switch (cfg->fourcc) {
-	case V4L2_PIX_FMT_RGB565:
-		var->bits_per_pixel = 16;
-		break;
-	case V4L2_PIX_FMT_BGR24:
-		var->bits_per_pixel = 24;
-		break;
-	case V4L2_PIX_FMT_BGR32:
-		var->bits_per_pixel = 32;
-		break;
-	default:
-		var->grayscale = cfg->fourcc;
-		break;
+	if (!format->yuv) {
+		ch->colorspace = V4L2_COLORSPACE_SRGB;
+		ch->pitch = ch->xres * format->bpp / 8;
+	} else {
+		ch->colorspace = V4L2_COLORSPACE_REC709;
+		ch->pitch = ch->xres;
 	}
 
-	/* Make sure the memory size check won't fail. smem_len is initialized
-	 * later based on var.
-	 */
-	info->fix.smem_len = UINT_MAX;
-	ret = sh_mobile_check_var(var, info);
-	if (ret)
-		return ret;
+	ch->display.width = cfg->panel_cfg.width;
+	ch->display.height = cfg->panel_cfg.height;
+	ch->display.mode = *mode;
 
-	max_size = max_size * var->bits_per_pixel / 8 * 2;
-
-	/* Allocate frame buffer memory and color map. */
-	buf = dma_alloc_coherent(dev, max_size, &ch->dma_handle, GFP_KERNEL);
-	if (!buf) {
-		dev_err(dev, "unable to allocate buffer\n");
+	/* Allocate frame buffer memory. */
+	ch->fb_size = max_size * format->bpp / 8 * 2;
+	ch->fb_mem = dma_alloc_coherent(priv->dev, ch->fb_size, &ch->dma_handle,
+					GFP_KERNEL);
+	if (ch->fb_mem == NULL) {
+		dev_err(priv->dev, "unable to allocate buffer\n");
 		return -ENOMEM;
 	}
 
-	ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
-	if (ret < 0) {
-		dev_err(dev, "unable to allocate cmap\n");
-		dma_free_coherent(dev, max_size, buf, ch->dma_handle);
-		return ret;
+	/* Initialize the transmitter device if present. */
+	if (cfg->tx_dev) {
+		if (!cfg->tx_dev->dev.driver ||
+		    !try_module_get(cfg->tx_dev->dev.driver->owner)) {
+			dev_warn(priv->dev,
+				 "unable to get transmitter device\n");
+			return -EINVAL;
+		}
+		ch->tx_dev = platform_get_drvdata(cfg->tx_dev);
+		ch->tx_dev->lcdc = ch;
+		ch->tx_dev->def_mode = *mode;
 	}
 
-	/* Initialize fixed screen information. Restrict pan to 2 lines steps
-	 * for NV12 and NV21.
-	 */
-	info->fix = sh_mobile_lcdc_fix;
-	info->fix.smem_start = ch->dma_handle;
-	info->fix.smem_len = max_size;
-	if (cfg->fourcc == V4L2_PIX_FMT_NV12 ||
-	    cfg->fourcc == V4L2_PIX_FMT_NV21)
-		info->fix.ypanstep = 2;
-
-	if (sh_mobile_format_is_yuv(var)) {
-		info->fix.line_length = var->xres;
-		info->fix.visual = FB_VISUAL_FOURCC;
-	} else {
-		info->fix.line_length = var->xres * var->bits_per_pixel / 8;
-		info->fix.visual = FB_VISUAL_TRUECOLOR;
-	}
-
-	info->screen_base = buf;
-	info->device = dev;
-	ch->display_var = *var;
-
-	return 0;
+	return sh_mobile_lcdc_channel_fb_init(ch, mode, num_modes);
 }
 
 static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
@@ -1698,6 +1924,8 @@
 		return -ENOMEM;
 	}
 
+	priv->dev = &pdev->dev;
+	priv->meram_dev = pdata->meram_dev;
 	platform_set_drvdata(pdev, priv);
 
 	error = request_irq(i, sh_mobile_lcdc_irq, 0,
@@ -1714,7 +1942,7 @@
 		struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels;
 
 		ch->lcdc = priv;
-		memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i]));
+		ch->cfg = &pdata->ch[i];
 
 		error = sh_mobile_lcdc_check_interface(ch);
 		if (error) {
@@ -1726,7 +1954,7 @@
 		ch->pan_offset = 0;
 
 		/* probe the backlight is there is one defined */
-		if (ch->cfg.bl_info.max_brightness)
+		if (ch->cfg->bl_info.max_brightness)
 			ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch);
 
 		switch (pdata->ch[i].chan) {
@@ -1757,18 +1985,19 @@
 	if (!priv->base)
 		goto err1;
 
-	error = sh_mobile_lcdc_setup_clocks(pdev, pdata->clock_source, priv);
+	error = sh_mobile_lcdc_setup_clocks(priv, pdata->clock_source);
 	if (error) {
 		dev_err(&pdev->dev, "unable to setup clocks\n");
 		goto err1;
 	}
 
-	priv->meram_dev = pdata->meram_dev;
+	/* Enable runtime PM. */
+	pm_runtime_enable(&pdev->dev);
 
 	for (i = 0; i < num_channels; i++) {
 		struct sh_mobile_lcdc_chan *ch = priv->ch + i;
 
-		error = sh_mobile_lcdc_channel_init(ch, &pdev->dev);
+		error = sh_mobile_lcdc_channel_init(priv, ch);
 		if (error)
 			goto err1;
 	}
@@ -1781,31 +2010,10 @@
 
 	for (i = 0; i < num_channels; i++) {
 		struct sh_mobile_lcdc_chan *ch = priv->ch + i;
-		struct fb_info *info = ch->info;
 
-		if (info->fbdefio) {
-			ch->sglist = vmalloc(sizeof(struct scatterlist) *
-					info->fix.smem_len >> PAGE_SHIFT);
-			if (!ch->sglist) {
-				dev_err(&pdev->dev, "cannot allocate sglist\n");
-				goto err1;
-			}
-		}
-
-		info->bl_dev = ch->bl;
-
-		error = register_framebuffer(info);
-		if (error < 0)
+		error = sh_mobile_lcdc_channel_fb_register(ch);
+		if (error)
 			goto err1;
-
-		dev_info(info->dev, "registered %s/%s as %dx%d %dbpp.\n",
-			 pdev->name, (ch->cfg.chan == LCDC_CHAN_MAINLCD) ?
-			 "mainlcd" : "sublcd", info->var.xres, info->var.yres,
-			 info->var.bits_per_pixel);
-
-		/* deferred io mode: disable clock to save power */
-		if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)
-			sh_mobile_lcdc_clk_off(priv);
 	}
 
 	/* Failure ignored */
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index a58a0f3..da1c26e 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -14,9 +14,35 @@
 
 #define PALETTE_NR 16
 
-struct sh_mobile_lcdc_priv;
-struct fb_info;
 struct backlight_device;
+struct fb_info;
+struct module;
+struct sh_mobile_lcdc_chan;
+struct sh_mobile_lcdc_entity;
+struct sh_mobile_lcdc_format_info;
+struct sh_mobile_lcdc_priv;
+
+#define SH_MOBILE_LCDC_DISPLAY_DISCONNECTED	0
+#define SH_MOBILE_LCDC_DISPLAY_CONNECTED	1
+
+struct sh_mobile_lcdc_entity_ops {
+	/* Display */
+	int (*display_on)(struct sh_mobile_lcdc_entity *entity);
+	void (*display_off)(struct sh_mobile_lcdc_entity *entity);
+};
+
+enum sh_mobile_lcdc_entity_event {
+	SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT,
+	SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT,
+	SH_MOBILE_LCDC_EVENT_DISPLAY_MODE,
+};
+
+struct sh_mobile_lcdc_entity {
+	struct module *owner;
+	const struct sh_mobile_lcdc_entity_ops *ops;
+	struct sh_mobile_lcdc_chan *lcdc;
+	struct fb_videomode def_mode;
+};
 
 /*
  * struct sh_mobile_lcdc_chan - LCDC display channel
@@ -27,29 +53,57 @@
  */
 struct sh_mobile_lcdc_chan {
 	struct sh_mobile_lcdc_priv *lcdc;
+	struct sh_mobile_lcdc_entity *tx_dev;
+	const struct sh_mobile_lcdc_chan_cfg *cfg;
+
 	unsigned long *reg_offs;
 	unsigned long ldmt1r_value;
 	unsigned long enabled; /* ME and SE in LDCNT2R */
-	struct sh_mobile_lcdc_chan_cfg cfg;
-	u32 pseudo_palette[PALETTE_NR];
-	struct fb_info *info;
-	struct backlight_device *bl;
+	void *meram;
+
+	struct mutex open_lock;		/* protects the use counter */
+	int use_count;
+
+	void *fb_mem;
+	unsigned long fb_size;
+
 	dma_addr_t dma_handle;
-	struct fb_deferred_io defio;
-	struct scatterlist *sglist;
-	unsigned long frame_end;
 	unsigned long pan_offset;
+
+	unsigned long frame_end;
 	wait_queue_head_t frame_end_wait;
 	struct completion vsync_completion;
-	struct fb_var_screeninfo display_var;
-	int use_count;
-	int blank_status;
-	struct mutex open_lock;		/* protects the use counter */
-	int meram_enabled;
+
+	const struct sh_mobile_lcdc_format_info *format;
+	u32 colorspace;
+	unsigned int xres;
+	unsigned int xres_virtual;
+	unsigned int yres;
+	unsigned int yres_virtual;
+	unsigned int pitch;
 
 	unsigned long base_addr_y;
 	unsigned long base_addr_c;
-	unsigned int pitch;
+
+	int (*notify)(struct sh_mobile_lcdc_chan *ch,
+		      enum sh_mobile_lcdc_entity_event event,
+		      const struct fb_videomode *mode,
+		      const struct fb_monspecs *monspec);
+
+	/* Backlight */
+	struct backlight_device *bl;
+
+	/* FB */
+	struct fb_info *info;
+	u32 pseudo_palette[PALETTE_NR];
+	struct {
+		unsigned int width;
+		unsigned int height;
+		struct fb_videomode mode;
+	} display;
+	struct fb_deferred_io defio;
+	struct scatterlist *sglist;
+	int blank_status;
 };
 
 #endif
diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
index f45d83e..82ba830 100644
--- a/drivers/video/sh_mobile_meram.c
+++ b/drivers/video/sh_mobile_meram.c
@@ -9,16 +9,22 @@
  * for more details.
  */
 
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/genalloc.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/device.h>
-#include <linux/pm_runtime.h>
-#include <linux/io.h>
-#include <linux/slab.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
 #include <video/sh_mobile_meram.h>
 
-/* meram registers */
+/* -----------------------------------------------------------------------------
+ * MERAM registers
+ */
+
 #define MEVCR1			0x4
 #define MEVCR1_RST		(1 << 31)
 #define MEVCR1_WD		(1 << 30)
@@ -81,16 +87,14 @@
 	 ((yszm1) << MExxBSIZE_YSZM1_SHIFT) | \
 	 ((xszm1) << MExxBSIZE_XSZM1_SHIFT))
 
-#define SH_MOBILE_MERAM_ICB_NUM		32
-
-static unsigned long common_regs[] = {
+static const unsigned long common_regs[] = {
 	MEVCR1,
 	MEQSEL1,
 	MEQSEL2,
 };
-#define CMN_REGS_SIZE ARRAY_SIZE(common_regs)
+#define MERAM_REGS_SIZE ARRAY_SIZE(common_regs)
 
-static unsigned long icb_regs[] = {
+static const unsigned long icb_regs[] = {
 	MExxCTL,
 	MExxBSIZE,
 	MExxMNCF,
@@ -100,216 +104,269 @@
 };
 #define ICB_REGS_SIZE ARRAY_SIZE(icb_regs)
 
+/*
+ * sh_mobile_meram_icb - MERAM ICB information
+ * @regs: Registers cache
+ * @index: ICB index
+ * @offset: MERAM block offset
+ * @size: MERAM block size in KiB
+ * @cache_unit: Bytes to cache per ICB
+ * @pixelformat: Video pixel format of the data stored in the ICB
+ * @current_reg: Which of Start Address Register A (0) or B (1) is in use
+ */
+struct sh_mobile_meram_icb {
+	unsigned long regs[ICB_REGS_SIZE];
+	unsigned int index;
+	unsigned long offset;
+	unsigned int size;
+
+	unsigned int cache_unit;
+	unsigned int pixelformat;
+	unsigned int current_reg;
+};
+
+#define MERAM_ICB_NUM			32
+
+struct sh_mobile_meram_fb_plane {
+	struct sh_mobile_meram_icb *marker;
+	struct sh_mobile_meram_icb *cache;
+};
+
+struct sh_mobile_meram_fb_cache {
+	unsigned int nplanes;
+	struct sh_mobile_meram_fb_plane planes[2];
+};
+
+/*
+ * sh_mobile_meram_priv - MERAM device
+ * @base: Registers base address
+ * @meram: MERAM physical address
+ * @regs: Registers cache
+ * @lock: Protects used_icb and icbs
+ * @used_icb: Bitmask of used ICBs
+ * @icbs: ICBs
+ * @pool: Allocation pool to manage the MERAM
+ */
 struct sh_mobile_meram_priv {
-	void __iomem	*base;
-	struct mutex	lock;
-	unsigned long	used_icb;
-	int		used_meram_cache_regions;
-	unsigned long	used_meram_cache[SH_MOBILE_MERAM_ICB_NUM];
-	unsigned long	cmn_saved_regs[CMN_REGS_SIZE];
-	unsigned long	icb_saved_regs[ICB_REGS_SIZE * SH_MOBILE_MERAM_ICB_NUM];
+	void __iomem *base;
+	unsigned long meram;
+	unsigned long regs[MERAM_REGS_SIZE];
+
+	struct mutex lock;
+	unsigned long used_icb;
+	struct sh_mobile_meram_icb icbs[MERAM_ICB_NUM];
+
+	struct gen_pool *pool;
 };
 
 /* settings */
-#define MERAM_SEC_LINE 15
-#define MERAM_LINE_WIDTH 2048
+#define MERAM_GRANULARITY		1024
+#define MERAM_SEC_LINE			15
+#define MERAM_LINE_WIDTH		2048
 
-/*
- * MERAM/ICB access functions
+/* -----------------------------------------------------------------------------
+ * Registers access
  */
 
 #define MERAM_ICB_OFFSET(base, idx, off)	((base) + (off) + (idx) * 0x20)
 
-static inline void meram_write_icb(void __iomem *base, int idx, int off,
-	unsigned long val)
+static inline void meram_write_icb(void __iomem *base, unsigned int idx,
+				   unsigned int off, unsigned long val)
 {
 	iowrite32(val, MERAM_ICB_OFFSET(base, idx, off));
 }
 
-static inline unsigned long meram_read_icb(void __iomem *base, int idx, int off)
+static inline unsigned long meram_read_icb(void __iomem *base, unsigned int idx,
+					   unsigned int off)
 {
 	return ioread32(MERAM_ICB_OFFSET(base, idx, off));
 }
 
-static inline void meram_write_reg(void __iomem *base, int off,
-		unsigned long val)
+static inline void meram_write_reg(void __iomem *base, unsigned int off,
+				   unsigned long val)
 {
 	iowrite32(val, base + off);
 }
 
-static inline unsigned long meram_read_reg(void __iomem *base, int off)
+static inline unsigned long meram_read_reg(void __iomem *base, unsigned int off)
 {
 	return ioread32(base + off);
 }
 
-/*
- * register ICB
+/* -----------------------------------------------------------------------------
+ * Allocation
  */
 
-#define MERAM_CACHE_START(p)	 ((p) >> 16)
-#define MERAM_CACHE_END(p)	 ((p) & 0xffff)
-#define MERAM_CACHE_SET(o, s)	 ((((o) & 0xffff) << 16) | \
-				  (((o) + (s) - 1) & 0xffff))
-
-/*
- * check if there's no overlaps in MERAM allocation.
- */
-
-static inline int meram_check_overlap(struct sh_mobile_meram_priv *priv,
-				      struct sh_mobile_meram_icb *new)
+/* Allocate ICBs and MERAM for a plane. */
+static int __meram_alloc(struct sh_mobile_meram_priv *priv,
+			 struct sh_mobile_meram_fb_plane *plane,
+			 size_t size)
 {
-	int i;
-	int used_start, used_end, meram_start, meram_end;
+	unsigned long mem;
+	unsigned long idx;
 
-	/* valid ICB? */
-	if (new->marker_icb & ~0x1f || new->cache_icb & ~0x1f)
-		return 1;
+	idx = find_first_zero_bit(&priv->used_icb, 28);
+	if (idx == 28)
+		return -ENOMEM;
+	plane->cache = &priv->icbs[idx];
 
-	if (test_bit(new->marker_icb, &priv->used_icb) ||
-			test_bit(new->cache_icb,  &priv->used_icb))
-		return  1;
+	idx = find_next_zero_bit(&priv->used_icb, 32, 28);
+	if (idx == 32)
+		return -ENOMEM;
+	plane->marker = &priv->icbs[idx];
 
-	for (i = 0; i < priv->used_meram_cache_regions; i++) {
-		used_start = MERAM_CACHE_START(priv->used_meram_cache[i]);
-		used_end   = MERAM_CACHE_END(priv->used_meram_cache[i]);
-		meram_start = new->meram_offset;
-		meram_end   = new->meram_offset + new->meram_size;
+	mem = gen_pool_alloc(priv->pool, size * 1024);
+	if (mem == 0)
+		return -ENOMEM;
 
-		if ((meram_start >= used_start && meram_start < used_end) ||
-			(meram_end > used_start && meram_end < used_end))
-			return 1;
-	}
+	__set_bit(plane->marker->index, &priv->used_icb);
+	__set_bit(plane->cache->index, &priv->used_icb);
+
+	plane->marker->offset = mem - priv->meram;
+	plane->marker->size = size;
 
 	return 0;
 }
 
-/*
- * mark the specified ICB as used
- */
-
-static inline void meram_mark(struct sh_mobile_meram_priv *priv,
-			      struct sh_mobile_meram_icb *new)
+/* Free ICBs and MERAM for a plane. */
+static void __meram_free(struct sh_mobile_meram_priv *priv,
+			 struct sh_mobile_meram_fb_plane *plane)
 {
-	int n;
+	gen_pool_free(priv->pool, priv->meram + plane->marker->offset,
+		      plane->marker->size * 1024);
 
-	if (new->marker_icb < 0 || new->cache_icb < 0)
-		return;
-
-	__set_bit(new->marker_icb, &priv->used_icb);
-	__set_bit(new->cache_icb, &priv->used_icb);
-
-	n = priv->used_meram_cache_regions;
-
-	priv->used_meram_cache[n] = MERAM_CACHE_SET(new->meram_offset,
-						    new->meram_size);
-
-	priv->used_meram_cache_regions++;
+	__clear_bit(plane->marker->index, &priv->used_icb);
+	__clear_bit(plane->cache->index, &priv->used_icb);
 }
 
-/*
- * unmark the specified ICB as used
- */
-
-static inline void meram_unmark(struct sh_mobile_meram_priv *priv,
-				struct sh_mobile_meram_icb *icb)
-{
-	int i;
-	unsigned long pattern;
-
-	if (icb->marker_icb < 0 || icb->cache_icb < 0)
-		return;
-
-	__clear_bit(icb->marker_icb, &priv->used_icb);
-	__clear_bit(icb->cache_icb, &priv->used_icb);
-
-	pattern = MERAM_CACHE_SET(icb->meram_offset, icb->meram_size);
-	for (i = 0; i < priv->used_meram_cache_regions; i++) {
-		if (priv->used_meram_cache[i] == pattern) {
-			while (i < priv->used_meram_cache_regions - 1) {
-				priv->used_meram_cache[i] =
-					priv->used_meram_cache[i + 1] ;
-				i++;
-			}
-			priv->used_meram_cache[i] = 0;
-			priv->used_meram_cache_regions--;
-			break;
-		}
-	}
-}
-
-/*
- * is this a YCbCr(NV12, NV16 or NV24) colorspace
- */
-static inline int is_nvcolor(int cspace)
+/* Is this a YCbCr(NV12, NV16 or NV24) colorspace? */
+static int is_nvcolor(int cspace)
 {
 	if (cspace == SH_MOBILE_MERAM_PF_NV ||
-			cspace == SH_MOBILE_MERAM_PF_NV24)
+	    cspace == SH_MOBILE_MERAM_PF_NV24)
 		return 1;
 	return 0;
 }
 
-/*
- * set the next address to fetch
- */
-static inline void meram_set_next_addr(struct sh_mobile_meram_priv *priv,
-				       struct sh_mobile_meram_cfg *cfg,
-				       unsigned long base_addr_y,
-				       unsigned long base_addr_c)
+/* Allocate memory for the ICBs and mark them as used. */
+static struct sh_mobile_meram_fb_cache *
+meram_alloc(struct sh_mobile_meram_priv *priv,
+	    const struct sh_mobile_meram_cfg *cfg,
+	    int pixelformat)
 {
+	struct sh_mobile_meram_fb_cache *cache;
+	unsigned int nplanes = is_nvcolor(pixelformat) ? 2 : 1;
+	int ret;
+
+	if (cfg->icb[0].meram_size == 0)
+		return ERR_PTR(-EINVAL);
+
+	if (nplanes == 2 && cfg->icb[1].meram_size == 0)
+		return ERR_PTR(-EINVAL);
+
+	cache = kzalloc(sizeof(*cache), GFP_KERNEL);
+	if (cache == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	cache->nplanes = nplanes;
+
+	ret = __meram_alloc(priv, &cache->planes[0], cfg->icb[0].meram_size);
+	if (ret < 0)
+		goto error;
+
+	cache->planes[0].marker->current_reg = 1;
+	cache->planes[0].marker->pixelformat = pixelformat;
+
+	if (cache->nplanes == 1)
+		return cache;
+
+	ret = __meram_alloc(priv, &cache->planes[1], cfg->icb[1].meram_size);
+	if (ret < 0) {
+		__meram_free(priv, &cache->planes[0]);
+		goto error;
+	}
+
+	return cache;
+
+error:
+	kfree(cache);
+	return ERR_PTR(-ENOMEM);
+}
+
+/* Unmark the specified ICB as used. */
+static void meram_free(struct sh_mobile_meram_priv *priv,
+		       struct sh_mobile_meram_fb_cache *cache)
+{
+	__meram_free(priv, &cache->planes[0]);
+	if (cache->nplanes == 2)
+		__meram_free(priv, &cache->planes[1]);
+
+	kfree(cache);
+}
+
+/* Set the next address to fetch. */
+static void meram_set_next_addr(struct sh_mobile_meram_priv *priv,
+				struct sh_mobile_meram_fb_cache *cache,
+				unsigned long base_addr_y,
+				unsigned long base_addr_c)
+{
+	struct sh_mobile_meram_icb *icb = cache->planes[0].marker;
 	unsigned long target;
 
-	target = (cfg->current_reg) ? MExxSARA : MExxSARB;
-	cfg->current_reg ^= 1;
+	icb->current_reg ^= 1;
+	target = icb->current_reg ? MExxSARB : MExxSARA;
 
 	/* set the next address to fetch */
-	meram_write_icb(priv->base, cfg->icb[0].cache_icb,  target,
+	meram_write_icb(priv->base, cache->planes[0].cache->index, target,
 			base_addr_y);
-	meram_write_icb(priv->base, cfg->icb[0].marker_icb, target,
-			base_addr_y + cfg->icb[0].cache_unit);
+	meram_write_icb(priv->base, cache->planes[0].marker->index, target,
+			base_addr_y + cache->planes[0].marker->cache_unit);
 
-	if (is_nvcolor(cfg->pixelformat)) {
-		meram_write_icb(priv->base, cfg->icb[1].cache_icb,  target,
-				base_addr_c);
-		meram_write_icb(priv->base, cfg->icb[1].marker_icb, target,
-				base_addr_c + cfg->icb[1].cache_unit);
+	if (cache->nplanes == 2) {
+		meram_write_icb(priv->base, cache->planes[1].cache->index,
+				target, base_addr_c);
+		meram_write_icb(priv->base, cache->planes[1].marker->index,
+				target, base_addr_c +
+				cache->planes[1].marker->cache_unit);
 	}
 }
 
-/*
- * get the next ICB address
- */
-static inline void meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
-					   struct sh_mobile_meram_cfg *cfg,
-					   unsigned long *icb_addr_y,
-					   unsigned long *icb_addr_c)
+/* Get the next ICB address. */
+static void
+meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
+			struct sh_mobile_meram_fb_cache *cache,
+			unsigned long *icb_addr_y, unsigned long *icb_addr_c)
 {
+	struct sh_mobile_meram_icb *icb = cache->planes[0].marker;
 	unsigned long icb_offset;
 
 	if (pdata->addr_mode == SH_MOBILE_MERAM_MODE0)
-		icb_offset = 0x80000000 | (cfg->current_reg << 29);
+		icb_offset = 0x80000000 | (icb->current_reg << 29);
 	else
-		icb_offset = 0xc0000000 | (cfg->current_reg << 23);
+		icb_offset = 0xc0000000 | (icb->current_reg << 23);
 
-	*icb_addr_y = icb_offset | (cfg->icb[0].marker_icb << 24);
-	if (is_nvcolor(cfg->pixelformat))
-		*icb_addr_c = icb_offset | (cfg->icb[1].marker_icb << 24);
+	*icb_addr_y = icb_offset | (cache->planes[0].marker->index << 24);
+	if (cache->nplanes == 2)
+		*icb_addr_c = icb_offset
+			    | (cache->planes[1].marker->index << 24);
 }
 
 #define MERAM_CALC_BYTECOUNT(x, y) \
 	(((x) * (y) + (MERAM_LINE_WIDTH - 1)) & ~(MERAM_LINE_WIDTH - 1))
 
-/*
- * initialize MERAM
- */
-
+/* Initialize MERAM. */
 static int meram_init(struct sh_mobile_meram_priv *priv,
-		      struct sh_mobile_meram_icb *icb,
-		      int xres, int yres, int *out_pitch)
+		      struct sh_mobile_meram_fb_plane *plane,
+		      unsigned int xres, unsigned int yres,
+		      unsigned int *out_pitch)
 {
+	struct sh_mobile_meram_icb *marker = plane->marker;
 	unsigned long total_byte_count = MERAM_CALC_BYTECOUNT(xres, yres);
 	unsigned long bnm;
-	int lcdc_pitch, xpitch, line_cnt;
-	int save_lines;
+	unsigned int lcdc_pitch;
+	unsigned int xpitch;
+	unsigned int line_cnt;
+	unsigned int save_lines;
 
 	/* adjust pitch to 1024, 2048, 4096 or 8192 */
 	lcdc_pitch = (xres - 1) | 1023;
@@ -322,13 +379,13 @@
 		lcdc_pitch = xpitch = MERAM_LINE_WIDTH;
 		line_cnt = total_byte_count >> 11;
 		*out_pitch = xres;
-		save_lines = (icb->meram_size / 16 / MERAM_SEC_LINE);
+		save_lines = plane->marker->size / 16 / MERAM_SEC_LINE;
 		save_lines *= MERAM_SEC_LINE;
 	} else {
 		xpitch = xres;
 		line_cnt = yres;
 		*out_pitch = lcdc_pitch;
-		save_lines = icb->meram_size / (lcdc_pitch >> 10) / 2;
+		save_lines = plane->marker->size / (lcdc_pitch >> 10) / 2;
 		save_lines &= 0xff;
 	}
 	bnm = (save_lines - 1) << 16;
@@ -336,19 +393,20 @@
 	/* TODO: we better to check if we have enough MERAM buffer size */
 
 	/* set up ICB */
-	meram_write_icb(priv->base, icb->cache_icb,  MExxBSIZE,
+	meram_write_icb(priv->base, plane->cache->index,  MExxBSIZE,
 			MERAM_MExxBSIZE_VAL(0x0, line_cnt - 1, xpitch - 1));
-	meram_write_icb(priv->base, icb->marker_icb, MExxBSIZE,
+	meram_write_icb(priv->base, plane->marker->index, MExxBSIZE,
 			MERAM_MExxBSIZE_VAL(0xf, line_cnt - 1, xpitch - 1));
 
-	meram_write_icb(priv->base, icb->cache_icb,  MExxMNCF, bnm);
-	meram_write_icb(priv->base, icb->marker_icb, MExxMNCF, bnm);
+	meram_write_icb(priv->base, plane->cache->index,  MExxMNCF, bnm);
+	meram_write_icb(priv->base, plane->marker->index, MExxMNCF, bnm);
 
-	meram_write_icb(priv->base, icb->cache_icb,  MExxSBSIZE, xpitch);
-	meram_write_icb(priv->base, icb->marker_icb, MExxSBSIZE, xpitch);
+	meram_write_icb(priv->base, plane->cache->index,  MExxSBSIZE, xpitch);
+	meram_write_icb(priv->base, plane->marker->index, MExxSBSIZE, xpitch);
 
 	/* save a cache unit size */
-	icb->cache_unit = xres * save_lines;
+	plane->cache->cache_unit = xres * save_lines;
+	plane->marker->cache_unit = xres * save_lines;
 
 	/*
 	 * Set MERAM for framebuffer
@@ -356,13 +414,13 @@
 	 * we also chain the cache_icb and the marker_icb.
 	 * we also split the allocated MERAM buffer between two ICBs.
 	 */
-	meram_write_icb(priv->base, icb->cache_icb, MExxCTL,
-			MERAM_MExxCTL_VAL(icb->marker_icb, icb->meram_offset) |
-			MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
+	meram_write_icb(priv->base, plane->cache->index, MExxCTL,
+			MERAM_MExxCTL_VAL(plane->marker->index, marker->offset)
+			| MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
 			MExxCTL_MD_FB);
-	meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
-			MERAM_MExxCTL_VAL(icb->cache_icb, icb->meram_offset +
-					  icb->meram_size / 2) |
+	meram_write_icb(priv->base, plane->marker->index, MExxCTL,
+			MERAM_MExxCTL_VAL(plane->cache->index, marker->offset +
+					  plane->marker->size / 2) |
 			MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
 			MExxCTL_MD_FB);
 
@@ -370,221 +428,106 @@
 }
 
 static void meram_deinit(struct sh_mobile_meram_priv *priv,
-			struct sh_mobile_meram_icb *icb)
+			 struct sh_mobile_meram_fb_plane *plane)
 {
 	/* disable ICB */
-	meram_write_icb(priv->base, icb->cache_icb,  MExxCTL,
+	meram_write_icb(priv->base, plane->cache->index,  MExxCTL,
 			MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
-	meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
+	meram_write_icb(priv->base, plane->marker->index, MExxCTL,
 			MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
-	icb->cache_unit = 0;
+
+	plane->cache->cache_unit = 0;
+	plane->marker->cache_unit = 0;
 }
 
-/*
- * register the ICB
+/* -----------------------------------------------------------------------------
+ * Registration/unregistration
  */
 
-static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
-				    struct sh_mobile_meram_cfg *cfg,
-				    int xres, int yres, int pixelformat,
-				    unsigned long base_addr_y,
-				    unsigned long base_addr_c,
-				    unsigned long *icb_addr_y,
-				    unsigned long *icb_addr_c,
-				    int *pitch)
+static void *sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
+				      const struct sh_mobile_meram_cfg *cfg,
+				      unsigned int xres, unsigned int yres,
+				      unsigned int pixelformat,
+				      unsigned int *pitch)
 {
-	struct platform_device *pdev;
-	struct sh_mobile_meram_priv *priv;
-	int n, out_pitch;
-	int error = 0;
-
-	if (!pdata || !pdata->priv || !pdata->pdev || !cfg)
-		return -EINVAL;
+	struct sh_mobile_meram_fb_cache *cache;
+	struct sh_mobile_meram_priv *priv = pdata->priv;
+	struct platform_device *pdev = pdata->pdev;
+	unsigned int out_pitch;
 
 	if (pixelformat != SH_MOBILE_MERAM_PF_NV &&
 	    pixelformat != SH_MOBILE_MERAM_PF_NV24 &&
 	    pixelformat != SH_MOBILE_MERAM_PF_RGB)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
-	priv = pdata->priv;
-	pdev = pdata->pdev;
-
-	dev_dbg(&pdev->dev, "registering %dx%d (%s) (y=%08lx, c=%08lx)",
-		xres, yres, (!pixelformat) ? "yuv" : "rgb",
-		base_addr_y, base_addr_c);
+	dev_dbg(&pdev->dev, "registering %dx%d (%s)", xres, yres,
+		!pixelformat ? "yuv" : "rgb");
 
 	/* we can't handle wider than 8192px */
 	if (xres > 8192) {
 		dev_err(&pdev->dev, "width exceeding the limit (> 8192).");
-		return -EINVAL;
-	}
-
-	/* do we have at least one ICB config? */
-	if (cfg->icb[0].marker_icb < 0 || cfg->icb[0].cache_icb < 0) {
-		dev_err(&pdev->dev, "at least one ICB is required.");
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	mutex_lock(&priv->lock);
 
-	if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) {
-		dev_err(&pdev->dev, "no more ICB available.");
-		error = -EINVAL;
+	/* We now register the ICBs and allocate the MERAM regions. */
+	cache = meram_alloc(priv, cfg, pixelformat);
+	if (IS_ERR(cache)) {
+		dev_err(&pdev->dev, "MERAM allocation failed (%ld).",
+			PTR_ERR(cache));
 		goto err;
 	}
 
-	/* make sure that there's no overlaps */
-	if (meram_check_overlap(priv, &cfg->icb[0])) {
-		dev_err(&pdev->dev, "conflicting config detected.");
-		error = -EINVAL;
-		goto err;
-	}
-	n = 1;
-
-	/* do the same if we have the second ICB set */
-	if (cfg->icb[1].marker_icb >= 0 && cfg->icb[1].cache_icb >= 0) {
-		if (meram_check_overlap(priv, &cfg->icb[1])) {
-			dev_err(&pdev->dev, "conflicting config detected.");
-			error = -EINVAL;
-			goto err;
-		}
-		n = 2;
-	}
-
-	if (is_nvcolor(pixelformat) && n != 2) {
-		dev_err(&pdev->dev, "requires two ICB sets for planar Y/C.");
-		error =  -EINVAL;
-		goto err;
-	}
-
-	/* we now register the ICB */
-	cfg->pixelformat = pixelformat;
-	meram_mark(priv, &cfg->icb[0]);
-	if (is_nvcolor(pixelformat))
-		meram_mark(priv, &cfg->icb[1]);
-
 	/* initialize MERAM */
-	meram_init(priv, &cfg->icb[0], xres, yres, &out_pitch);
+	meram_init(priv, &cache->planes[0], xres, yres, &out_pitch);
 	*pitch = out_pitch;
 	if (pixelformat == SH_MOBILE_MERAM_PF_NV)
-		meram_init(priv, &cfg->icb[1], xres, (yres + 1) / 2,
+		meram_init(priv, &cache->planes[1], xres, (yres + 1) / 2,
 			&out_pitch);
 	else if (pixelformat == SH_MOBILE_MERAM_PF_NV24)
-		meram_init(priv, &cfg->icb[1], 2 * xres, (yres + 1) / 2,
+		meram_init(priv, &cache->planes[1], 2 * xres, (yres + 1) / 2,
 			&out_pitch);
 
-	cfg->current_reg = 1;
-	meram_set_next_addr(priv, cfg, base_addr_y, base_addr_c);
-	meram_get_next_icb_addr(pdata, cfg, icb_addr_y, icb_addr_c);
-
-	dev_dbg(&pdev->dev, "registered - can access via y=%08lx, c=%08lx",
-		*icb_addr_y, *icb_addr_c);
-
 err:
 	mutex_unlock(&priv->lock);
-	return error;
+	return cache;
 }
 
-static int sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata,
-				      struct sh_mobile_meram_cfg *cfg)
+static void
+sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata, void *data)
 {
-	struct sh_mobile_meram_priv *priv;
-
-	if (!pdata || !pdata->priv || !cfg)
-		return -EINVAL;
-
-	priv = pdata->priv;
+	struct sh_mobile_meram_fb_cache *cache = data;
+	struct sh_mobile_meram_priv *priv = pdata->priv;
 
 	mutex_lock(&priv->lock);
 
-	/* deinit & unmark */
-	if (is_nvcolor(cfg->pixelformat)) {
-		meram_deinit(priv, &cfg->icb[1]);
-		meram_unmark(priv, &cfg->icb[1]);
-	}
-	meram_deinit(priv, &cfg->icb[0]);
-	meram_unmark(priv, &cfg->icb[0]);
+	/* deinit & free */
+	meram_deinit(priv, &cache->planes[0]);
+	if (cache->nplanes == 2)
+		meram_deinit(priv, &cache->planes[1]);
+
+	meram_free(priv, cache);
 
 	mutex_unlock(&priv->lock);
-
-	return 0;
 }
 
-static int sh_mobile_meram_update(struct sh_mobile_meram_info *pdata,
-				  struct sh_mobile_meram_cfg *cfg,
-				  unsigned long base_addr_y,
-				  unsigned long base_addr_c,
-				  unsigned long *icb_addr_y,
-				  unsigned long *icb_addr_c)
+static void
+sh_mobile_meram_update(struct sh_mobile_meram_info *pdata, void *data,
+		       unsigned long base_addr_y, unsigned long base_addr_c,
+		       unsigned long *icb_addr_y, unsigned long *icb_addr_c)
 {
-	struct sh_mobile_meram_priv *priv;
-
-	if (!pdata || !pdata->priv || !cfg)
-		return -EINVAL;
-
-	priv = pdata->priv;
+	struct sh_mobile_meram_fb_cache *cache = data;
+	struct sh_mobile_meram_priv *priv = pdata->priv;
 
 	mutex_lock(&priv->lock);
 
-	meram_set_next_addr(priv, cfg, base_addr_y, base_addr_c);
-	meram_get_next_icb_addr(pdata, cfg, icb_addr_y, icb_addr_c);
+	meram_set_next_addr(priv, cache, base_addr_y, base_addr_c);
+	meram_get_next_icb_addr(pdata, cache, icb_addr_y, icb_addr_c);
 
 	mutex_unlock(&priv->lock);
-
-	return 0;
 }
 
-static int sh_mobile_meram_runtime_suspend(struct device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-	struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
-	int k, j;
-
-	for (k = 0; k < CMN_REGS_SIZE; k++)
-		priv->cmn_saved_regs[k] = meram_read_reg(priv->base,
-			common_regs[k]);
-
-	for (j = 0; j < 32; j++) {
-		if (!test_bit(j, &priv->used_icb))
-			continue;
-		for (k = 0; k < ICB_REGS_SIZE; k++) {
-			priv->icb_saved_regs[j * ICB_REGS_SIZE + k] =
-				meram_read_icb(priv->base, j, icb_regs[k]);
-			/* Reset ICB on resume */
-			if (icb_regs[k] == MExxCTL)
-				priv->icb_saved_regs[j * ICB_REGS_SIZE + k] |=
-					MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF;
-		}
-	}
-	return 0;
-}
-
-static int sh_mobile_meram_runtime_resume(struct device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-	struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
-	int k, j;
-
-	for (j = 0; j < 32; j++) {
-		if (!test_bit(j, &priv->used_icb))
-			continue;
-		for (k = 0; k < ICB_REGS_SIZE; k++) {
-			meram_write_icb(priv->base, j, icb_regs[k],
-			priv->icb_saved_regs[j * ICB_REGS_SIZE + k]);
-		}
-	}
-
-	for (k = 0; k < CMN_REGS_SIZE; k++)
-		meram_write_reg(priv->base, common_regs[k],
-			priv->cmn_saved_regs[k]);
-	return 0;
-}
-
-static const struct dev_pm_ops sh_mobile_meram_dev_pm_ops = {
-	.runtime_suspend = sh_mobile_meram_runtime_suspend,
-	.runtime_resume = sh_mobile_meram_runtime_resume,
-};
-
 static struct sh_mobile_meram_ops sh_mobile_meram_ops = {
 	.module			= THIS_MODULE,
 	.meram_register		= sh_mobile_meram_register,
@@ -592,17 +535,68 @@
 	.meram_update		= sh_mobile_meram_update,
 };
 
-/*
- * initialize MERAM
+/* -----------------------------------------------------------------------------
+ * Power management
  */
 
-static int sh_mobile_meram_remove(struct platform_device *pdev);
+static int sh_mobile_meram_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
+	unsigned int i, j;
+
+	for (i = 0; i < MERAM_REGS_SIZE; i++)
+		priv->regs[i] = meram_read_reg(priv->base, common_regs[i]);
+
+	for (i = 0; i < 32; i++) {
+		if (!test_bit(i, &priv->used_icb))
+			continue;
+		for (j = 0; j < ICB_REGS_SIZE; j++) {
+			priv->icbs[i].regs[j] =
+				meram_read_icb(priv->base, i, icb_regs[j]);
+			/* Reset ICB on resume */
+			if (icb_regs[j] == MExxCTL)
+				priv->icbs[i].regs[j] |=
+					MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF;
+		}
+	}
+	return 0;
+}
+
+static int sh_mobile_meram_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
+	unsigned int i, j;
+
+	for (i = 0; i < 32; i++) {
+		if (!test_bit(i, &priv->used_icb))
+			continue;
+		for (j = 0; j < ICB_REGS_SIZE; j++)
+			meram_write_icb(priv->base, i, icb_regs[j],
+					priv->icbs[i].regs[j]);
+	}
+
+	for (i = 0; i < MERAM_REGS_SIZE; i++)
+		meram_write_reg(priv->base, common_regs[i], priv->regs[i]);
+	return 0;
+}
+
+static UNIVERSAL_DEV_PM_OPS(sh_mobile_meram_dev_pm_ops,
+			    sh_mobile_meram_suspend,
+			    sh_mobile_meram_resume, NULL);
+
+/* -----------------------------------------------------------------------------
+ * Probe/remove and driver init/exit
+ */
 
 static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
 {
 	struct sh_mobile_meram_priv *priv;
 	struct sh_mobile_meram_info *pdata = pdev->dev.platform_data;
-	struct resource *res;
+	struct resource *regs;
+	struct resource *meram;
+	unsigned int i;
 	int error;
 
 	if (!pdata) {
@@ -610,8 +604,9 @@
 		return -EINVAL;
 	}
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	meram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (regs == NULL || meram == NULL) {
 		dev_err(&pdev->dev, "cannot get platform resources\n");
 		return -ENOENT;
 	}
@@ -622,32 +617,74 @@
 		return -ENOMEM;
 	}
 
-	platform_set_drvdata(pdev, priv);
-
-	/* initialize private data */
+	/* Initialize private data. */
 	mutex_init(&priv->lock);
-	priv->base = ioremap_nocache(res->start, resource_size(res));
-	if (!priv->base) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		error = -EFAULT;
-		goto err;
-	}
+	priv->used_icb = pdata->reserved_icbs;
+
+	for (i = 0; i < MERAM_ICB_NUM; ++i)
+		priv->icbs[i].index = i;
+
 	pdata->ops = &sh_mobile_meram_ops;
 	pdata->priv = priv;
 	pdata->pdev = pdev;
 
+	/* Request memory regions and remap the registers. */
+	if (!request_mem_region(regs->start, resource_size(regs), pdev->name)) {
+		dev_err(&pdev->dev, "MERAM registers region already claimed\n");
+		error = -EBUSY;
+		goto err_req_regs;
+	}
+
+	if (!request_mem_region(meram->start, resource_size(meram),
+				pdev->name)) {
+		dev_err(&pdev->dev, "MERAM memory region already claimed\n");
+		error = -EBUSY;
+		goto err_req_meram;
+	}
+
+	priv->base = ioremap_nocache(regs->start, resource_size(regs));
+	if (!priv->base) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		error = -EFAULT;
+		goto err_ioremap;
+	}
+
+	priv->meram = meram->start;
+
+	/* Create and initialize the MERAM memory pool. */
+	priv->pool = gen_pool_create(ilog2(MERAM_GRANULARITY), -1);
+	if (priv->pool == NULL) {
+		error = -ENOMEM;
+		goto err_genpool;
+	}
+
+	error = gen_pool_add(priv->pool, meram->start, resource_size(meram),
+			     -1);
+	if (error < 0)
+		goto err_genpool;
+
 	/* initialize ICB addressing mode */
 	if (pdata->addr_mode == SH_MOBILE_MERAM_MODE1)
 		meram_write_reg(priv->base, MEVCR1, MEVCR1_AMD1);
 
+	platform_set_drvdata(pdev, priv);
 	pm_runtime_enable(&pdev->dev);
 
 	dev_info(&pdev->dev, "sh_mobile_meram initialized.");
 
 	return 0;
 
-err:
-	sh_mobile_meram_remove(pdev);
+err_genpool:
+	if (priv->pool)
+		gen_pool_destroy(priv->pool);
+	iounmap(priv->base);
+err_ioremap:
+	release_mem_region(meram->start, resource_size(meram));
+err_req_meram:
+	release_mem_region(regs->start, resource_size(regs));
+err_req_regs:
+	mutex_destroy(&priv->lock);
+	kfree(priv);
 
 	return error;
 }
@@ -656,11 +693,16 @@
 static int sh_mobile_meram_remove(struct platform_device *pdev)
 {
 	struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
+	struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	struct resource *meram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 
 	pm_runtime_disable(&pdev->dev);
 
-	if (priv->base)
-		iounmap(priv->base);
+	gen_pool_destroy(priv->pool);
+
+	iounmap(priv->base);
+	release_mem_region(meram->start, resource_size(meram));
+	release_mem_region(regs->start, resource_size(regs));
 
 	mutex_destroy(&priv->lock);
 
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
index a197731..a159b63 100644
--- a/drivers/video/udlfb.c
+++ b/drivers/video/udlfb.c
@@ -72,6 +72,7 @@
 static bool console = 1; /* Allow fbcon to open framebuffer */
 static bool fb_defio = 1;  /* Detect mmap writes using page faults */
 static bool shadow = 1; /* Optionally disable shadow framebuffer */
+static int pixel_limit; /* Optionally force a pixel resolution limit */
 
 /* dlfb keeps a list of urbs for efficient bulk transfers */
 static void dlfb_urb_completion(struct urb *urb);
@@ -918,10 +919,6 @@
 {
 	struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref);
 
-	/* this function will wait for all in-flight urbs to complete */
-	if (dev->urbs.count > 0)
-		dlfb_free_urb_list(dev);
-
 	if (dev->backing_buffer)
 		vfree(dev->backing_buffer);
 
@@ -940,35 +937,42 @@
 	up(&unode->dev->urbs.limit_sem);
 }
 
-static void dlfb_free_framebuffer_work(struct work_struct *work)
+static void dlfb_free_framebuffer(struct dlfb_data *dev)
 {
-	struct dlfb_data *dev = container_of(work, struct dlfb_data,
-					     free_framebuffer_work.work);
 	struct fb_info *info = dev->info;
-	int node = info->node;
 
-	unregister_framebuffer(info);
+	if (info) {
+		int node = info->node;
 
-	if (info->cmap.len != 0)
-		fb_dealloc_cmap(&info->cmap);
-	if (info->monspecs.modedb)
-		fb_destroy_modedb(info->monspecs.modedb);
-	if (info->screen_base)
-		vfree(info->screen_base);
+		unregister_framebuffer(info);
 
-	fb_destroy_modelist(&info->modelist);
+		if (info->cmap.len != 0)
+			fb_dealloc_cmap(&info->cmap);
+		if (info->monspecs.modedb)
+			fb_destroy_modedb(info->monspecs.modedb);
+		if (info->screen_base)
+			vfree(info->screen_base);
 
-	dev->info = 0;
+		fb_destroy_modelist(&info->modelist);
 
-	/* Assume info structure is freed after this point */
-	framebuffer_release(info);
+		dev->info = NULL;
 
-	pr_warn("fb_info for /dev/fb%d has been freed\n", node);
+		/* Assume info structure is freed after this point */
+		framebuffer_release(info);
+
+		pr_warn("fb_info for /dev/fb%d has been freed\n", node);
+	}
 
 	/* ref taken in probe() as part of registering framebfufer */
 	kref_put(&dev->kref, dlfb_free);
 }
 
+static void dlfb_free_framebuffer_work(struct work_struct *work)
+{
+	struct dlfb_data *dev = container_of(work, struct dlfb_data,
+					     free_framebuffer_work.work);
+	dlfb_free_framebuffer(dev);
+}
 /*
  * Assumes caller is holding info->lock mutex (for open and release at least)
  */
@@ -1012,7 +1016,8 @@
 		return 0;
 	}
 
-	pr_info("%dx%d valid mode\n", mode->xres, mode->yres);
+	pr_info("%dx%d @ %d Hz valid mode\n", mode->xres, mode->yres,
+		mode->refresh);
 
 	return 1;
 }
@@ -1427,19 +1432,22 @@
 	struct device *fbdev = container_of(kobj, struct device, kobj);
 	struct fb_info *fb_info = dev_get_drvdata(fbdev);
 	struct dlfb_data *dev = fb_info->par;
+	int ret;
 
 	/* We only support write of entire EDID at once, no offset*/
 	if ((src_size != EDID_LENGTH) || (src_off != 0))
-		return 0;
+		return -EINVAL;
 
-	dlfb_setup_modes(dev, fb_info, src, src_size);
+	ret = dlfb_setup_modes(dev, fb_info, src, src_size);
+	if (ret)
+		return ret;
 
-	if (dev->edid && (memcmp(src, dev->edid, src_size) == 0)) {
-		pr_info("sysfs written EDID is new default\n");
-		dlfb_ops_set_par(fb_info);
-		return src_size;
-	} else
-		return 0;
+	if (!dev->edid || memcmp(src, dev->edid, src_size))
+		return -EINVAL;
+
+	pr_info("sysfs written EDID is new default\n");
+	dlfb_ops_set_par(fb_info);
+	return src_size;
 }
 
 static ssize_t metrics_reset_store(struct device *fbdev,
@@ -1537,7 +1545,7 @@
 			u8 length;
 			u16 key;
 
-			key = *((u16 *) desc);
+			key = le16_to_cpu(*((u16 *) desc));
 			desc += sizeof(u16);
 			length = *desc;
 			desc++;
@@ -1570,14 +1578,15 @@
 	kfree(buf);
 	return true;
 }
+
+static void dlfb_init_framebuffer_work(struct work_struct *work);
+
 static int dlfb_usb_probe(struct usb_interface *interface,
 			const struct usb_device_id *id)
 {
 	struct usb_device *usbdev;
 	struct dlfb_data *dev = 0;
-	struct fb_info *info = 0;
 	int retval = -ENOMEM;
-	int i;
 
 	/* usb initialization */
 
@@ -1589,9 +1598,7 @@
 		goto error;
 	}
 
-	/* we need to wait for both usb and fbdev to spin down on disconnect */
 	kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */
-	kref_get(&dev->kref); /* matching kref_put in free_framebuffer_work */
 
 	dev->udev = usbdev;
 	dev->gdev = &usbdev->dev; /* our generic struct device * */
@@ -1613,16 +1620,53 @@
 		goto error;
 	}
 
+	if (pixel_limit) {
+		pr_warn("DL chip limit of %d overriden"
+			" by module param to %d\n",
+			dev->sku_pixel_limit, pixel_limit);
+		dev->sku_pixel_limit = pixel_limit;
+	}
+
+
 	if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
 		retval = -ENOMEM;
 		pr_err("dlfb_alloc_urb_list failed\n");
 		goto error;
 	}
 
+	kref_get(&dev->kref); /* matching kref_put in free_framebuffer_work */
+
 	/* We don't register a new USB class. Our client interface is fbdev */
 
+	/* Workitem keep things fast & simple during USB enumeration */
+	INIT_DELAYED_WORK(&dev->init_framebuffer_work,
+			  dlfb_init_framebuffer_work);
+	schedule_delayed_work(&dev->init_framebuffer_work, 0);
+
+	return 0;
+
+error:
+	if (dev) {
+
+		kref_put(&dev->kref, dlfb_free); /* ref for framebuffer */
+		kref_put(&dev->kref, dlfb_free); /* last ref from kref_init */
+
+		/* dev has been deallocated. Do not dereference */
+	}
+
+	return retval;
+}
+
+static void dlfb_init_framebuffer_work(struct work_struct *work)
+{
+	struct dlfb_data *dev = container_of(work, struct dlfb_data,
+					     init_framebuffer_work.work);
+	struct fb_info *info;
+	int retval;
+	int i;
+
 	/* allocates framebuffer driver structure, not framebuffer memory */
-	info = framebuffer_alloc(0, &interface->dev);
+	info = framebuffer_alloc(0, dev->gdev);
 	if (!info) {
 		retval = -ENOMEM;
 		pr_err("framebuffer_alloc failed\n");
@@ -1668,15 +1712,13 @@
 	for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) {
 		retval = device_create_file(info->dev, &fb_device_attrs[i]);
 		if (retval) {
-			pr_err("device_create_file failed %d\n", retval);
-			goto err_del_attrs;
+			pr_warn("device_create_file failed %d\n", retval);
 		}
 	}
 
 	retval = device_create_bin_file(info->dev, &edid_attr);
 	if (retval) {
-		pr_err("device_create_bin_file failed %d\n", retval);
-		goto err_del_attrs;
+		pr_warn("device_create_bin_file failed %d\n", retval);
 	}
 
 	pr_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
@@ -1684,38 +1726,10 @@
 			info->var.xres, info->var.yres,
 			((dev->backing_buffer) ?
 			info->fix.smem_len * 2 : info->fix.smem_len) >> 10);
-	return 0;
-
-err_del_attrs:
-	for (i -= 1; i >= 0; i--)
-		device_remove_file(info->dev, &fb_device_attrs[i]);
+	return;
 
 error:
-	if (dev) {
-
-		if (info) {
-			if (info->cmap.len != 0)
-				fb_dealloc_cmap(&info->cmap);
-			if (info->monspecs.modedb)
-				fb_destroy_modedb(info->monspecs.modedb);
-			if (info->screen_base)
-				vfree(info->screen_base);
-
-			fb_destroy_modelist(&info->modelist);
-
-			framebuffer_release(info);
-		}
-
-		if (dev->backing_buffer)
-			vfree(dev->backing_buffer);
-
-		kref_put(&dev->kref, dlfb_free); /* ref for framebuffer */
-		kref_put(&dev->kref, dlfb_free); /* last ref from kref_init */
-
-		/* dev has been deallocated. Do not dereference */
-	}
-
-	return retval;
+	dlfb_free_framebuffer(dev);
 }
 
 static void dlfb_usb_disconnect(struct usb_interface *interface)
@@ -1735,12 +1749,20 @@
 	/* When non-active we'll update virtual framebuffer, but no new urbs */
 	atomic_set(&dev->usb_active, 0);
 
-	/* remove udlfb's sysfs interfaces */
-	for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
-		device_remove_file(info->dev, &fb_device_attrs[i]);
-	device_remove_bin_file(info->dev, &edid_attr);
+	/* this function will wait for all in-flight urbs to complete */
+	dlfb_free_urb_list(dev);
+
+	if (info) {
+		/* remove udlfb's sysfs interfaces */
+		for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
+			device_remove_file(info->dev, &fb_device_attrs[i]);
+		device_remove_bin_file(info->dev, &edid_attr);
+		unlink_framebuffer(info);
+	}
 
 	usb_set_intfdata(interface, NULL);
+	dev->udev = NULL;
+	dev->gdev = NULL;
 
 	/* if clients still have us open, will be freed on last close */
 	if (dev->fb_count == 0)
@@ -1806,12 +1828,12 @@
 	int ret;
 	unsigned long flags;
 
-	pr_notice("Waiting for completes and freeing all render urbs\n");
+	pr_notice("Freeing all render urbs\n");
 
 	/* keep waiting and freeing, until we've got 'em all */
 	while (count--) {
 
-		/* Getting interrupted means a leak, but ok at shutdown*/
+		/* Getting interrupted means a leak, but ok at disconnect */
 		ret = down_interruptible(&dev->urbs.limit_sem);
 		if (ret)
 			break;
@@ -1833,6 +1855,7 @@
 		kfree(node);
 	}
 
+	dev->urbs.count = 0;
 }
 
 static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
@@ -1948,6 +1971,9 @@
 module_param(shadow, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
 MODULE_PARM_DESC(shadow, "Shadow vid mem. Disable to save mem but lose perf");
 
+module_param(pixel_limit, int, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
+MODULE_PARM_DESC(pixel_limit, "Force limit on max mode (in x*y pixels)");
+
 MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, "
 	      "Jaya Kumar <jayakumar.lkml@gmail.com>, "
 	      "Bernie Thompson <bernie@plugable.com>");
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index e7f69ef..260cca7 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -121,7 +121,7 @@
 		NULL,
 	};
 
-	return call_usermodehelper(v86d_path, argv, envp, 1);
+	return call_usermodehelper(v86d_path, argv, envp, UMH_WAIT_PROC);
 }
 
 /*
@@ -362,7 +362,7 @@
 
 	state = kmalloc(par->vbe_state_size, GFP_KERNEL);
 	if (!state)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	task = uvesafb_prep();
 	if (!task) {
@@ -1172,9 +1172,17 @@
 {
 	struct uvesafb_par *par = info->par;
 	int cnt = atomic_read(&par->ref_count);
+	u8 *buf = NULL;
 
-	if (!cnt && par->vbe_state_size)
-		par->vbe_state_orig = uvesafb_vbe_state_save(par);
+	if (!cnt && par->vbe_state_size) {
+		buf =  uvesafb_vbe_state_save(par);
+		if (IS_ERR(buf)) {
+			printk(KERN_WARNING "uvesafb: save hardware state"
+				"failed, error code is %ld!\n", PTR_ERR(buf));
+		} else {
+			par->vbe_state_orig = buf;
+		}
+	}
 
 	atomic_inc(&par->ref_count);
 	return 0;
diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile
index 5108136..159f26e 100644
--- a/drivers/video/via/Makefile
+++ b/drivers/video/via/Makefile
@@ -6,4 +6,7 @@
 
 viafb-y	:=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o \
 	via_utility.o vt1636.o global.o tblDPASetting.o viamode.o \
-	via-core.o via-gpio.o via_modesetting.o via_clock.o
+	via-core.o via-gpio.o via_modesetting.o via_clock.o \
+	via_aux.o via_aux_edid.o via_aux_vt1636.o via_aux_vt1632.o \
+	via_aux_vt1631.o via_aux_vt1625.o via_aux_vt1622.o via_aux_vt1621.o \
+	via_aux_sii164.o via_aux_ch7301.o
diff --git a/drivers/video/via/chip.h b/drivers/video/via/chip.h
index 3ebf20c..d32a507 100644
--- a/drivers/video/via/chip.h
+++ b/drivers/video/via/chip.h
@@ -146,9 +146,6 @@
 
 struct lvds_setting_information {
 	int iga_path;
-	int h_active;
-	int v_active;
-	int bpp;
 	int lcd_panel_hres;
 	int lcd_panel_vres;
 	int display_method;
diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c
index 9138e51..6be72f0 100644
--- a/drivers/video/via/dvi.c
+++ b/drivers/video/via/dvi.c
@@ -172,10 +172,11 @@
 }
 
 /* DVI Set Mode */
-void viafb_dvi_set_mode(const struct fb_var_screeninfo *var, int iga)
+void viafb_dvi_set_mode(const struct fb_var_screeninfo *var,
+	u16 cxres, u16 cyres, int iga)
 {
 	struct fb_var_screeninfo dvi_var = *var;
-	struct crt_mode_table *rb_mode;
+	const struct fb_videomode *rb_mode;
 	int maxPixelClock;
 
 	maxPixelClock = viaparinfo->shared->tmds_setting_info.max_pixel_clock;
@@ -185,7 +186,7 @@
 			viafb_fill_var_timing_info(&dvi_var, rb_mode);
 	}
 
-	viafb_fill_crtc_timing(&dvi_var, iga);
+	viafb_fill_crtc_timing(&dvi_var, cxres, cyres, iga);
 }
 
 /* Sense DVI Connector */
diff --git a/drivers/video/via/dvi.h b/drivers/video/via/dvi.h
index e2116aa..db75785 100644
--- a/drivers/video/via/dvi.h
+++ b/drivers/video/via/dvi.h
@@ -59,6 +59,7 @@
 bool __devinit viafb_tmds_trasmitter_identify(void);
 void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
 	struct tmds_setting_information *tmds_setting);
-void viafb_dvi_set_mode(const struct fb_var_screeninfo *var, int iga);
+void viafb_dvi_set_mode(const struct fb_var_screeninfo *var,
+	u16 cxres, u16 cyres, int iga);
 
 #endif /* __DVI_H__ */
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index 8497727..898590d 100644
--- a/drivers/video/via/hw.c
+++ b/drivers/video/via/hw.c
@@ -1467,28 +1467,32 @@
 	via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */
 }
 
-static struct display_timing var_to_timing(const struct fb_var_screeninfo *var)
+struct display_timing var_to_timing(const struct fb_var_screeninfo *var,
+	u16 cxres, u16 cyres)
 {
 	struct display_timing timing;
+	u16 dx = (var->xres - cxres) / 2, dy = (var->yres - cyres) / 2;
 
-	timing.hor_addr = var->xres;
-	timing.hor_sync_start = timing.hor_addr + var->right_margin;
+	timing.hor_addr = cxres;
+	timing.hor_sync_start = timing.hor_addr + var->right_margin + dx;
 	timing.hor_sync_end = timing.hor_sync_start + var->hsync_len;
-	timing.hor_total = timing.hor_sync_end + var->left_margin;
-	timing.hor_blank_start = timing.hor_addr;
-	timing.hor_blank_end = timing.hor_total;
-	timing.ver_addr = var->yres;
-	timing.ver_sync_start = timing.ver_addr + var->lower_margin;
+	timing.hor_total = timing.hor_sync_end + var->left_margin + dx;
+	timing.hor_blank_start = timing.hor_addr + dx;
+	timing.hor_blank_end = timing.hor_total - dx;
+	timing.ver_addr = cyres;
+	timing.ver_sync_start = timing.ver_addr + var->lower_margin + dy;
 	timing.ver_sync_end = timing.ver_sync_start + var->vsync_len;
-	timing.ver_total = timing.ver_sync_end + var->upper_margin;
-	timing.ver_blank_start = timing.ver_addr;
-	timing.ver_blank_end = timing.ver_total;
+	timing.ver_total = timing.ver_sync_end + var->upper_margin + dy;
+	timing.ver_blank_start = timing.ver_addr + dy;
+	timing.ver_blank_end = timing.ver_total - dy;
 	return timing;
 }
 
-void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, int iga)
+void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var,
+	u16 cxres, u16 cyres, int iga)
 {
-	struct display_timing crt_reg = var_to_timing(var);
+	struct display_timing crt_reg = var_to_timing(var,
+		cxres ? cxres : var->xres, cyres ? cyres : var->yres);
 
 	if (iga == IGA1)
 		via_set_primary_timing(&crt_reg);
@@ -1526,13 +1530,6 @@
 	if (flag == 0) {
 		viaparinfo->tmds_setting_info->h_active = hres;
 		viaparinfo->tmds_setting_info->v_active = vres;
-
-		viaparinfo->lvds_setting_info->h_active = hres;
-		viaparinfo->lvds_setting_info->v_active = vres;
-		viaparinfo->lvds_setting_info->bpp = bpp;
-		viaparinfo->lvds_setting_info2->h_active = hres;
-		viaparinfo->lvds_setting_info2->v_active = vres;
-		viaparinfo->lvds_setting_info2->bpp = bpp;
 	} else {
 
 		if (viaparinfo->tmds_setting_info->iga_path == IGA2) {
@@ -1540,16 +1537,6 @@
 			viaparinfo->tmds_setting_info->v_active = vres;
 		}
 
-		if (viaparinfo->lvds_setting_info->iga_path == IGA2) {
-			viaparinfo->lvds_setting_info->h_active = hres;
-			viaparinfo->lvds_setting_info->v_active = vres;
-			viaparinfo->lvds_setting_info->bpp = bpp;
-		}
-		if (IGA2 == viaparinfo->lvds_setting_info2->iga_path) {
-			viaparinfo->lvds_setting_info2->h_active = hres;
-			viaparinfo->lvds_setting_info2->v_active = vres;
-			viaparinfo->lvds_setting_info2->bpp = bpp;
-		}
 	}
 }
 
@@ -1758,13 +1745,13 @@
 	}
 }
 
-static u8 get_sync(struct fb_info *info)
+static u8 get_sync(struct fb_var_screeninfo *var)
 {
 	u8 polarity = 0;
 
-	if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+	if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
 		polarity |= VIA_HSYNC_NEGATIVE;
-	if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+	if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
 		polarity |= VIA_VSYNC_NEGATIVE;
 	return polarity;
 }
@@ -1844,9 +1831,9 @@
 	load_fix_bit_crtc_reg();
 }
 
-int viafb_setmode(int video_bpp, int video_bpp1)
+int viafb_setmode(void)
 {
-	int j;
+	int j, cxres = 0, cyres = 0;
 	int port;
 	u32 devices = viaparinfo->shared->iga1_devices
 		| viaparinfo->shared->iga2_devices;
@@ -1895,6 +1882,8 @@
 	} else if (viafb_SAMM_ON) {
 		viafb_fill_var_timing_info(&var2, viafb_get_best_mode(
 			viafb_second_xres, viafb_second_yres, viafb_refresh1));
+		cxres = viafbinfo->var.xres;
+		cyres = viafbinfo->var.yres;
 		var2.bits_per_pixel = viafbinfo->var.bits_per_pixel;
 	}
 
@@ -1902,9 +1891,9 @@
 	if (viafb_CRT_ON) {
 		if (viaparinfo->shared->iga2_devices & VIA_CRT
 			&& viafb_SAMM_ON)
-			viafb_fill_crtc_timing(&var2, IGA2);
+			viafb_fill_crtc_timing(&var2, cxres, cyres, IGA2);
 		else
-			viafb_fill_crtc_timing(&viafbinfo->var,
+			viafb_fill_crtc_timing(&viafbinfo->var, 0, 0,
 				(viaparinfo->shared->iga1_devices & VIA_CRT)
 				? IGA1 : IGA2);
 
@@ -1922,17 +1911,17 @@
 	if (viafb_DVI_ON) {
 		if (viaparinfo->shared->tmds_setting_info.iga_path == IGA2
 			&& viafb_SAMM_ON)
-			viafb_dvi_set_mode(&var2, IGA2);
+			viafb_dvi_set_mode(&var2, cxres, cyres, IGA2);
 		else
-			viafb_dvi_set_mode(&viafbinfo->var,
+			viafb_dvi_set_mode(&viafbinfo->var, 0, 0,
 				viaparinfo->tmds_setting_info->iga_path);
 	}
 
 	if (viafb_LCD_ON) {
 		if (viafb_SAMM_ON &&
 			(viaparinfo->lvds_setting_info->iga_path == IGA2)) {
-			viaparinfo->lvds_setting_info->bpp = video_bpp1;
-			viafb_lcd_set_mode(viaparinfo->lvds_setting_info,
+			viafb_lcd_set_mode(&var2, cxres, cyres,
+				viaparinfo->lvds_setting_info,
 				&viaparinfo->chip_info->lvds_chip_info);
 		} else {
 			/* IGA1 doesn't have LCD scaling, so set it center. */
@@ -1940,16 +1929,16 @@
 				viaparinfo->lvds_setting_info->display_method =
 				    LCD_CENTERING;
 			}
-			viaparinfo->lvds_setting_info->bpp = video_bpp;
-			viafb_lcd_set_mode(viaparinfo->lvds_setting_info,
+			viafb_lcd_set_mode(&viafbinfo->var, 0, 0,
+				viaparinfo->lvds_setting_info,
 				&viaparinfo->chip_info->lvds_chip_info);
 		}
 	}
 	if (viafb_LCD2_ON) {
 		if (viafb_SAMM_ON &&
 			(viaparinfo->lvds_setting_info2->iga_path == IGA2)) {
-			viaparinfo->lvds_setting_info2->bpp = video_bpp1;
-			viafb_lcd_set_mode(viaparinfo->lvds_setting_info2,
+			viafb_lcd_set_mode(&var2, cxres, cyres,
+				viaparinfo->lvds_setting_info2,
 				&viaparinfo->chip_info->lvds_chip_info2);
 		} else {
 			/* IGA1 doesn't have LCD scaling, so set it center. */
@@ -1957,8 +1946,8 @@
 				viaparinfo->lvds_setting_info2->display_method =
 				    LCD_CENTERING;
 			}
-			viaparinfo->lvds_setting_info2->bpp = video_bpp;
-			viafb_lcd_set_mode(viaparinfo->lvds_setting_info2,
+			viafb_lcd_set_mode(&viafbinfo->var, 0, 0,
+				viaparinfo->lvds_setting_info2,
 				&viaparinfo->chip_info->lvds_chip_info2);
 		}
 	}
@@ -1971,7 +1960,7 @@
 	if (!viafb_hotplug) {
 		viafb_hotplug_Xres = viafbinfo->var.xres;
 		viafb_hotplug_Yres = viafbinfo->var.yres;
-		viafb_hotplug_bpp = video_bpp;
+		viafb_hotplug_bpp = viafbinfo->var.bits_per_pixel;
 		viafb_hotplug_refresh = viafb_refresh;
 
 		if (viafb_DVI_ON)
@@ -1980,13 +1969,13 @@
 			viafb_DeviceStatus = CRT_Device;
 	}
 	device_on();
-	if (!viafb_dual_fb)
-		via_set_sync_polarity(devices, get_sync(viafbinfo));
+	if (!viafb_SAMM_ON)
+		via_set_sync_polarity(devices, get_sync(&viafbinfo->var));
 	else {
 		via_set_sync_polarity(viaparinfo->shared->iga1_devices,
-			get_sync(viafbinfo));
+			get_sync(&viafbinfo->var));
 		via_set_sync_polarity(viaparinfo->shared->iga2_devices,
-			get_sync(viafbinfo1));
+			get_sync(&var2));
 	}
 
 	clock.set_engine_pll_state(VIA_STATE_ON);
@@ -2023,20 +2012,20 @@
 
 int viafb_get_refresh(int hres, int vres, u32 long_refresh)
 {
-	struct crt_mode_table *best;
+	const struct fb_videomode *best;
 
 	best = viafb_get_best_mode(hres, vres, long_refresh);
 	if (!best)
 		return 60;
 
-	if (abs(best->refresh_rate - long_refresh) > 3) {
+	if (abs(best->refresh - long_refresh) > 3) {
 		if (hres == 1200 && vres == 900)
 			return 49; /* OLPC DCON only supports 50 Hz */
 		else
 			return 60;
 	}
 
-	return best->refresh_rate;
+	return best->refresh;
 }
 
 static void device_off(void)
@@ -2129,26 +2118,17 @@
 	}
 }
 
-/*According var's xres, yres fill var's other timing information*/
 void viafb_fill_var_timing_info(struct fb_var_screeninfo *var,
-	struct crt_mode_table *mode)
+	const struct fb_videomode *mode)
 {
-	struct display_timing crt_reg;
-
-	crt_reg = mode->crtc;
-	var->pixclock = 1000000000 / (crt_reg.hor_total * crt_reg.ver_total)
-		* 1000 / mode->refresh_rate;
-	var->left_margin =
-	    crt_reg.hor_total - (crt_reg.hor_sync_start + crt_reg.hor_sync_end);
-	var->right_margin = crt_reg.hor_sync_start - crt_reg.hor_addr;
-	var->hsync_len = crt_reg.hor_sync_end;
-	var->upper_margin =
-	    crt_reg.ver_total - (crt_reg.ver_sync_start + crt_reg.ver_sync_end);
-	var->lower_margin = crt_reg.ver_sync_start - crt_reg.ver_addr;
-	var->vsync_len = crt_reg.ver_sync_end;
-	var->sync = 0;
-	if (mode->h_sync_polarity == POSITIVE)
-		var->sync |= FB_SYNC_HOR_HIGH_ACT;
-	if (mode->v_sync_polarity == POSITIVE)
-		var->sync |= FB_SYNC_VERT_HIGH_ACT;
+	var->pixclock = mode->pixclock;
+	var->xres = mode->xres;
+	var->yres = mode->yres;
+	var->left_margin = mode->left_margin;
+	var->right_margin = mode->right_margin;
+	var->hsync_len = mode->hsync_len;
+	var->upper_margin = mode->upper_margin;
+	var->lower_margin = mode->lower_margin;
+	var->vsync_len = mode->vsync_len;
+	var->sync = mode->sync;
 }
diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h
index 4db5b6e..6be243c 100644
--- a/drivers/video/via/hw.h
+++ b/drivers/video/via/hw.h
@@ -637,7 +637,10 @@
 extern int viafb_DVI_ON;
 extern int viafb_hotplug;
 
-void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, int iga);
+struct display_timing var_to_timing(const struct fb_var_screeninfo *var,
+	u16 cxres, u16 cyres);
+void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var,
+	u16 cxres, u16 cyres, int iga);
 void viafb_set_vclock(u32 CLK, int set_iga);
 void viafb_load_reg(int timing_value, int viafb_load_reg_num,
 	struct io_register *reg,
@@ -657,9 +660,9 @@
 void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
 					*p_gfx_dpa_setting);
 
-int viafb_setmode(int video_bpp, int video_bpp1);
+int viafb_setmode(void);
 void viafb_fill_var_timing_info(struct fb_var_screeninfo *var,
-	struct crt_mode_table *mode);
+	const struct fb_videomode *mode);
 void __devinit viafb_init_chip_info(int chip_type);
 void __devinit viafb_init_dac(int set_iga);
 int viafb_get_refresh(int hres, int vres, u32 float_refresh);
diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c
index 5f3b4e3..1650379 100644
--- a/drivers/video/via/lcd.c
+++ b/drivers/video/via/lcd.c
@@ -53,10 +53,6 @@
 static int lvds_register_read(int index);
 static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
 		      int panel_vres);
-static void via_pitch_alignment_patch_lcd(
-	struct lvds_setting_information *plvds_setting_info,
-				   struct lvds_chip_information
-				   *plvds_chip_info);
 static void lcd_patch_skew_dvp0(struct lvds_setting_information
 			 *plvds_setting_info,
 			 struct lvds_chip_information *plvds_chip_info);
@@ -79,9 +75,6 @@
 	struct lvds_chip_information *plvds_chip_info,
 				     struct lvds_setting_information
 				     *plvds_setting_info);
-static struct display_timing lcd_centering_timging(struct display_timing
-					    mode_crt_reg,
-					   struct display_timing panel_crt_reg);
 
 static inline bool check_lvds_chip(int device_id_subaddr, int device_id)
 {
@@ -454,20 +447,17 @@
 	}
 }
 
-static void via_pitch_alignment_patch_lcd(
-	struct lvds_setting_information *plvds_setting_info,
-				   struct lvds_chip_information
-				   *plvds_chip_info)
+static void via_pitch_alignment_patch_lcd(int iga_path, int hres, int bpp)
 {
 	unsigned char cr13, cr35, cr65, cr66, cr67;
 	unsigned long dwScreenPitch = 0;
 	unsigned long dwPitch;
 
-	dwPitch = plvds_setting_info->h_active * (plvds_setting_info->bpp >> 3);
+	dwPitch = hres * (bpp >> 3);
 	if (dwPitch & 0x1F) {
 		dwScreenPitch = ((dwPitch + 31) & ~31) >> 3;
-		if (plvds_setting_info->iga_path == IGA2) {
-			if (plvds_setting_info->bpp > 8) {
+		if (iga_path == IGA2) {
+			if (bpp > 8) {
 				cr66 = (unsigned char)(dwScreenPitch & 0xFF);
 				viafb_write_reg(CR66, VIACR, cr66);
 				cr67 = viafb_read_reg(VIACR, CR67) & 0xFC;
@@ -485,7 +475,7 @@
 			cr65 += 2;
 			viafb_write_reg(CR65, VIACR, cr65);
 		} else {
-			if (plvds_setting_info->bpp > 8) {
+			if (bpp > 8) {
 				cr13 = (unsigned char)(dwScreenPitch & 0xFF);
 				viafb_write_reg(CR13, VIACR, cr13);
 				cr35 = viafb_read_reg(VIACR, CR35) & 0x1F;
@@ -548,49 +538,45 @@
 }
 
 /* LCD Set Mode */
-void viafb_lcd_set_mode(struct lvds_setting_information *plvds_setting_info,
+void viafb_lcd_set_mode(const struct fb_var_screeninfo *var, u16 cxres,
+	u16 cyres, struct lvds_setting_information *plvds_setting_info,
 	struct lvds_chip_information *plvds_chip_info)
 {
 	int set_iga = plvds_setting_info->iga_path;
-	int mode_bpp = plvds_setting_info->bpp;
-	int set_hres = plvds_setting_info->h_active;
-	int set_vres = plvds_setting_info->v_active;
+	int mode_bpp = var->bits_per_pixel;
+	int set_hres = cxres ? cxres : var->xres;
+	int set_vres = cyres ? cyres : var->yres;
 	int panel_hres = plvds_setting_info->lcd_panel_hres;
 	int panel_vres = plvds_setting_info->lcd_panel_vres;
 	u32 clock;
-	struct display_timing mode_crt_reg, panel_crt_reg, timing;
-	struct crt_mode_table *mode_crt_table, *panel_crt_table;
+	struct display_timing timing;
+	struct fb_var_screeninfo panel_var;
+	const struct fb_videomode *mode_crt_table, *panel_crt_table;
 
 	DEBUG_MSG(KERN_INFO "viafb_lcd_set_mode!!\n");
 	/* Get mode table */
 	mode_crt_table = viafb_get_best_mode(set_hres, set_vres, 60);
-	mode_crt_reg = mode_crt_table->crtc;
 	/* Get panel table Pointer */
 	panel_crt_table = viafb_get_best_mode(panel_hres, panel_vres, 60);
-	panel_crt_reg = panel_crt_table->crtc;
+	viafb_fill_var_timing_info(&panel_var, panel_crt_table);
 	DEBUG_MSG(KERN_INFO "bellow viafb_lcd_set_mode!!\n");
 	if (VT1636_LVDS == plvds_chip_info->lvds_chip_name)
 		viafb_init_lvds_vt1636(plvds_setting_info, plvds_chip_info);
-	clock = panel_crt_reg.hor_total * panel_crt_reg.ver_total
-		* panel_crt_table->refresh_rate;
+	clock = PICOS2KHZ(panel_crt_table->pixclock) * 1000;
 	plvds_setting_info->vclk = clock;
 
 	if (set_iga == IGA2 && (set_hres < panel_hres || set_vres < panel_vres)
 		&& plvds_setting_info->display_method == LCD_EXPANDSION) {
-		timing = panel_crt_reg;
+		timing = var_to_timing(&panel_var, panel_hres, panel_vres);
 		load_lcd_scaling(set_hres, set_vres, panel_hres, panel_vres);
 	} else {
-		timing = lcd_centering_timging(mode_crt_reg, panel_crt_reg);
+		timing = var_to_timing(&panel_var, set_hres, set_vres);
 		if (set_iga == IGA2)
 			/* disable scaling */
 			via_write_reg_mask(VIACR, 0x79, 0x00,
 				BIT0 + BIT1 + BIT2);
 	}
 
-	timing.hor_blank_end += timing.hor_blank_start;
-	timing.hor_sync_end += timing.hor_sync_start;
-	timing.ver_blank_end += timing.ver_blank_start;
-	timing.ver_sync_end += timing.ver_sync_start;
 	if (set_iga == IGA1)
 		via_set_primary_timing(&timing);
 	else if (set_iga == IGA2)
@@ -613,7 +599,8 @@
 		viafb_write_reg_mask(CR6A, VIACR, 0x01, BIT0);
 
 	/* Patch for non 32bit alignment mode */
-	via_pitch_alignment_patch_lcd(plvds_setting_info, plvds_chip_info);
+	via_pitch_alignment_patch_lcd(plvds_setting_info->iga_path, set_hres,
+		var->bits_per_pixel);
 }
 
 static void integrated_lvds_disable(struct lvds_setting_information
@@ -973,37 +960,6 @@
 	}
 }
 
-static struct display_timing lcd_centering_timging(struct display_timing
-					    mode_crt_reg,
-					    struct display_timing panel_crt_reg)
-{
-	struct display_timing crt_reg;
-
-	crt_reg.hor_total = panel_crt_reg.hor_total;
-	crt_reg.hor_addr = mode_crt_reg.hor_addr;
-	crt_reg.hor_blank_start =
-	    (panel_crt_reg.hor_addr - mode_crt_reg.hor_addr) / 2 +
-	    crt_reg.hor_addr;
-	crt_reg.hor_blank_end = panel_crt_reg.hor_blank_end;
-	crt_reg.hor_sync_start =
-	    (panel_crt_reg.hor_sync_start -
-	     panel_crt_reg.hor_blank_start) + crt_reg.hor_blank_start;
-	crt_reg.hor_sync_end = panel_crt_reg.hor_sync_end;
-
-	crt_reg.ver_total = panel_crt_reg.ver_total;
-	crt_reg.ver_addr = mode_crt_reg.ver_addr;
-	crt_reg.ver_blank_start =
-	    (panel_crt_reg.ver_addr - mode_crt_reg.ver_addr) / 2 +
-	    crt_reg.ver_addr;
-	crt_reg.ver_blank_end = panel_crt_reg.ver_blank_end;
-	crt_reg.ver_sync_start =
-	    (panel_crt_reg.ver_sync_start -
-	     panel_crt_reg.ver_blank_start) + crt_reg.ver_blank_start;
-	crt_reg.ver_sync_end = panel_crt_reg.ver_sync_end;
-
-	return crt_reg;
-}
-
 bool viafb_lcd_get_mobile_state(bool *mobile)
 {
 	unsigned char __iomem *romptr, *tableptr, *biosptr;
diff --git a/drivers/video/via/lcd.h b/drivers/video/via/lcd.h
index 77ca7b8..8f3e4e0 100644
--- a/drivers/video/via/lcd.h
+++ b/drivers/video/via/lcd.h
@@ -76,7 +76,8 @@
 				*plvds_chip_info,
 				struct lvds_setting_information
 				*plvds_setting_info);
-void viafb_lcd_set_mode(struct lvds_setting_information *plvds_setting_info,
+void viafb_lcd_set_mode(const struct fb_var_screeninfo *var, u16 cxres,
+	u16 cyres, struct lvds_setting_information *plvds_setting_info,
 	struct lvds_chip_information *plvds_chip_info);
 bool __devinit viafb_lvds_trasmitter_identify(void);
 void viafb_init_lvds_output_interface(struct lvds_chip_information
diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h
index c01c1c1..3158dfc 100644
--- a/drivers/video/via/share.h
+++ b/drivers/video/via/share.h
@@ -283,337 +283,6 @@
 #define HW_LAYOUT_LCD1_LCD2     0x04
 #define HW_LAYOUT_LCD_EXTERNAL_LCD2 0x10
 
-/* Definition Refresh Rate */
-#define REFRESH_49      49
-#define REFRESH_50      50
-#define REFRESH_60      60
-#define REFRESH_75      75
-#define REFRESH_85      85
-#define REFRESH_100     100
-#define REFRESH_120     120
-
-/* Definition Sync Polarity*/
-#define NEGATIVE        1
-#define POSITIVE        0
-
-/*480x640@60 Sync Polarity (GTF)
-*/
-#define M480X640_R60_HSP        NEGATIVE
-#define M480X640_R60_VSP        POSITIVE
-
-/*640x480@60 Sync Polarity (VESA Mode)
-*/
-#define M640X480_R60_HSP        NEGATIVE
-#define M640X480_R60_VSP        NEGATIVE
-
-/*640x480@75 Sync Polarity (VESA Mode)
-*/
-#define M640X480_R75_HSP        NEGATIVE
-#define M640X480_R75_VSP        NEGATIVE
-
-/*640x480@85 Sync Polarity (VESA Mode)
-*/
-#define M640X480_R85_HSP        NEGATIVE
-#define M640X480_R85_VSP        NEGATIVE
-
-/*640x480@100 Sync Polarity (GTF Mode)
-*/
-#define M640X480_R100_HSP       NEGATIVE
-#define M640X480_R100_VSP       POSITIVE
-
-/*640x480@120 Sync Polarity (GTF Mode)
-*/
-#define M640X480_R120_HSP       NEGATIVE
-#define M640X480_R120_VSP       POSITIVE
-
-/*720x480@60 Sync Polarity  (GTF Mode)
-*/
-#define M720X480_R60_HSP        NEGATIVE
-#define M720X480_R60_VSP        POSITIVE
-
-/*720x576@60 Sync Polarity  (GTF Mode)
-*/
-#define M720X576_R60_HSP        NEGATIVE
-#define M720X576_R60_VSP        POSITIVE
-
-/*800x600@60 Sync Polarity (VESA Mode)
-*/
-#define M800X600_R60_HSP        POSITIVE
-#define M800X600_R60_VSP        POSITIVE
-
-/*800x600@75 Sync Polarity (VESA Mode)
-*/
-#define M800X600_R75_HSP        POSITIVE
-#define M800X600_R75_VSP        POSITIVE
-
-/*800x600@85 Sync Polarity (VESA Mode)
-*/
-#define M800X600_R85_HSP        POSITIVE
-#define M800X600_R85_VSP        POSITIVE
-
-/*800x600@100 Sync Polarity (GTF Mode)
-*/
-#define M800X600_R100_HSP       NEGATIVE
-#define M800X600_R100_VSP       POSITIVE
-
-/*800x600@120 Sync Polarity (GTF Mode)
-*/
-#define M800X600_R120_HSP       NEGATIVE
-#define M800X600_R120_VSP       POSITIVE
-
-/*800x480@60 Sync Polarity  (CVT Mode)
-*/
-#define M800X480_R60_HSP        NEGATIVE
-#define M800X480_R60_VSP        POSITIVE
-
-/*848x480@60 Sync Polarity  (CVT Mode)
-*/
-#define M848X480_R60_HSP        NEGATIVE
-#define M848X480_R60_VSP        POSITIVE
-
-/*852x480@60 Sync Polarity  (GTF Mode)
-*/
-#define M852X480_R60_HSP        NEGATIVE
-#define M852X480_R60_VSP        POSITIVE
-
-/*1024x512@60 Sync Polarity (GTF Mode)
-*/
-#define M1024X512_R60_HSP       NEGATIVE
-#define M1024X512_R60_VSP       POSITIVE
-
-/*1024x600@60 Sync Polarity (GTF Mode)
-*/
-#define M1024X600_R60_HSP       NEGATIVE
-#define M1024X600_R60_VSP       POSITIVE
-
-/*1024x768@60 Sync Polarity (VESA Mode)
-*/
-#define M1024X768_R60_HSP       NEGATIVE
-#define M1024X768_R60_VSP       NEGATIVE
-
-/*1024x768@75 Sync Polarity (VESA Mode)
-*/
-#define M1024X768_R75_HSP       POSITIVE
-#define M1024X768_R75_VSP       POSITIVE
-
-/*1024x768@85 Sync Polarity (VESA Mode)
-*/
-#define M1024X768_R85_HSP       POSITIVE
-#define M1024X768_R85_VSP       POSITIVE
-
-/*1024x768@100 Sync Polarity (GTF Mode)
-*/
-#define M1024X768_R100_HSP      NEGATIVE
-#define M1024X768_R100_VSP      POSITIVE
-
-/*1152x864@75 Sync Polarity (VESA Mode)
-*/
-#define M1152X864_R75_HSP       POSITIVE
-#define M1152X864_R75_VSP       POSITIVE
-
-/*1280x720@60 Sync Polarity  (GTF Mode)
-*/
-#define M1280X720_R60_HSP       NEGATIVE
-#define M1280X720_R60_VSP       POSITIVE
-
-/* 1280x768@50 Sync Polarity  (GTF Mode) */
-#define M1280X768_R50_HSP       NEGATIVE
-#define M1280X768_R50_VSP       POSITIVE
-
-/*1280x768@60 Sync Polarity  (GTF Mode)
-*/
-#define M1280X768_R60_HSP       NEGATIVE
-#define M1280X768_R60_VSP       POSITIVE
-
-/*1280x800@60 Sync Polarity  (CVT Mode)
-*/
-#define M1280X800_R60_HSP       NEGATIVE
-#define M1280X800_R60_VSP       POSITIVE
-
-/*1280x960@60 Sync Polarity (VESA Mode)
-*/
-#define M1280X960_R60_HSP       POSITIVE
-#define M1280X960_R60_VSP       POSITIVE
-
-/*1280x1024@60 Sync Polarity (VESA Mode)
-*/
-#define M1280X1024_R60_HSP      POSITIVE
-#define M1280X1024_R60_VSP      POSITIVE
-
-/* 1360x768@60 Sync Polarity (CVT Mode) */
-#define M1360X768_R60_HSP       POSITIVE
-#define M1360X768_R60_VSP       POSITIVE
-
-/* 1360x768@60 Sync Polarity (CVT Reduce Blanking Mode) */
-#define M1360X768_RB_R60_HSP       POSITIVE
-#define M1360X768_RB_R60_VSP       NEGATIVE
-
-/* 1368x768@50 Sync Polarity (GTF Mode) */
-#define M1368X768_R50_HSP       NEGATIVE
-#define M1368X768_R50_VSP       POSITIVE
-
-/* 1368x768@60 Sync Polarity (VESA Mode) */
-#define M1368X768_R60_HSP       NEGATIVE
-#define M1368X768_R60_VSP       POSITIVE
-
-/*1280x1024@75 Sync Polarity (VESA Mode)
-*/
-#define M1280X1024_R75_HSP      POSITIVE
-#define M1280X1024_R75_VSP      POSITIVE
-
-/*1280x1024@85 Sync Polarity (VESA Mode)
-*/
-#define M1280X1024_R85_HSP      POSITIVE
-#define M1280X1024_R85_VSP      POSITIVE
-
-/*1440x1050@60 Sync Polarity (GTF Mode)
-*/
-#define M1440X1050_R60_HSP      NEGATIVE
-#define M1440X1050_R60_VSP      POSITIVE
-
-/*1600x1200@60 Sync Polarity (VESA Mode)
-*/
-#define M1600X1200_R60_HSP      POSITIVE
-#define M1600X1200_R60_VSP      POSITIVE
-
-/*1600x1200@75 Sync Polarity (VESA Mode)
-*/
-#define M1600X1200_R75_HSP      POSITIVE
-#define M1600X1200_R75_VSP      POSITIVE
-
-/* 1680x1050@60 Sync Polarity (CVT Mode) */
-#define M1680x1050_R60_HSP      NEGATIVE
-#define M1680x1050_R60_VSP      NEGATIVE
-
-/* 1680x1050@60 Sync Polarity (CVT Reduce Blanking Mode) */
-#define M1680x1050_RB_R60_HSP      POSITIVE
-#define M1680x1050_RB_R60_VSP      NEGATIVE
-
-/* 1680x1050@75 Sync Polarity (CVT Mode) */
-#define M1680x1050_R75_HSP      NEGATIVE
-#define M1680x1050_R75_VSP      POSITIVE
-
-/*1920x1080@60 Sync Polarity (CVT Mode)
-*/
-#define M1920X1080_R60_HSP      NEGATIVE
-#define M1920X1080_R60_VSP      POSITIVE
-
-/* 1920x1080@60 Sync Polarity (CVT Reduce Blanking Mode) */
-#define M1920X1080_RB_R60_HSP  POSITIVE
-#define M1920X1080_RB_R60_VSP  NEGATIVE
-
-/*1920x1440@60 Sync Polarity (VESA Mode)
-*/
-#define M1920X1440_R60_HSP      NEGATIVE
-#define M1920X1440_R60_VSP      POSITIVE
-
-/*1920x1440@75 Sync Polarity (VESA Mode)
-*/
-#define M1920X1440_R75_HSP      NEGATIVE
-#define M1920X1440_R75_VSP      POSITIVE
-
-#if 0
-/* 1400x1050@60 Sync Polarity (VESA Mode) */
-#define M1400X1050_R60_HSP      NEGATIVE
-#define M1400X1050_R60_VSP      NEGATIVE
-#endif
-
-/* 1400x1050@60 Sync Polarity (CVT Mode) */
-#define M1400X1050_R60_HSP      NEGATIVE
-#define M1400X1050_R60_VSP      POSITIVE
-
-/* 1400x1050@60 Sync Polarity (CVT Reduce Blanking Mode) */
-#define M1400X1050_RB_R60_HSP      POSITIVE
-#define M1400X1050_RB_R60_VSP      NEGATIVE
-
-/* 1400x1050@75 Sync Polarity (CVT Mode) */
-#define M1400X1050_R75_HSP      NEGATIVE
-#define M1400X1050_R75_VSP      POSITIVE
-
-/* 960x600@60 Sync Polarity (CVT Mode) */
-#define M960X600_R60_HSP        NEGATIVE
-#define M960X600_R60_VSP        POSITIVE
-
-/* 1000x600@60 Sync Polarity (GTF Mode) */
-#define M1000X600_R60_HSP       NEGATIVE
-#define M1000X600_R60_VSP       POSITIVE
-
-/* 1024x576@60 Sync Polarity (GTF Mode) */
-#define M1024X576_R60_HSP       NEGATIVE
-#define M1024X576_R60_VSP       POSITIVE
-
-/*1024x600@60 Sync Polarity (GTF Mode)*/
-#define M1024X600_R60_HSP       NEGATIVE
-#define M1024X600_R60_VSP       POSITIVE
-
-/* 1088x612@60 Sync Polarity (CVT Mode) */
-#define M1088X612_R60_HSP       NEGATIVE
-#define M1088X612_R60_VSP       POSITIVE
-
-/* 1152x720@60 Sync Polarity (CVT Mode) */
-#define M1152X720_R60_HSP       NEGATIVE
-#define M1152X720_R60_VSP       POSITIVE
-
-/* 1200x720@60 Sync Polarity (GTF Mode) */
-#define M1200X720_R60_HSP       NEGATIVE
-#define M1200X720_R60_VSP       POSITIVE
-
-/* 1200x900@60 Sync Polarity (DCON) */
-#define M1200X900_R60_HSP       POSITIVE
-#define M1200X900_R60_VSP       POSITIVE
-
-/* 1280x600@60 Sync Polarity (GTF Mode) */
-#define M1280x600_R60_HSP       NEGATIVE
-#define M1280x600_R60_VSP       POSITIVE
-
-/* 1280x720@50 Sync Polarity  (GTF Mode) */
-#define M1280X720_R50_HSP       NEGATIVE
-#define M1280X720_R50_VSP       POSITIVE
-
-/* 1440x900@60 Sync Polarity (CVT Mode) */
-#define M1440X900_R60_HSP       NEGATIVE
-#define M1440X900_R60_VSP       POSITIVE
-
-/* 1440x900@75 Sync Polarity (CVT Mode) */
-#define M1440X900_R75_HSP       NEGATIVE
-#define M1440X900_R75_VSP       POSITIVE
-
-/* 1440x900@60 Sync Polarity (CVT Reduce Blanking Mode) */
-#define M1440X900_RB_R60_HSP       POSITIVE
-#define M1440X900_RB_R60_VSP       NEGATIVE
-
-/* 1600x900@60 Sync Polarity (CVT Mode) */
-#define M1600X900_R60_HSP       NEGATIVE
-#define M1600X900_R60_VSP       POSITIVE
-
-/* 1600x900@60 Sync Polarity (CVT Reduce Blanking Mode) */
-#define M1600X900_RB_R60_HSP       POSITIVE
-#define M1600X900_RB_R60_VSP       NEGATIVE
-
-/* 1600x1024@60 Sync Polarity (GTF Mode) */
-#define M1600X1024_R60_HSP      NEGATIVE
-#define M1600X1024_R60_VSP      POSITIVE
-
-/* 1792x1344@60 Sync Polarity (DMT Mode) */
-#define M1792x1344_R60_HSP      NEGATIVE
-#define M1792x1344_R60_VSP      POSITIVE
-
-/* 1856x1392@60 Sync Polarity (DMT Mode) */
-#define M1856x1392_R60_HSP      NEGATIVE
-#define M1856x1392_R60_VSP      POSITIVE
-
-/* 1920x1200@60 Sync Polarity (CVT Mode) */
-#define M1920X1200_R60_HSP      NEGATIVE
-#define M1920X1200_R60_VSP      POSITIVE
-
-/* 1920x1200@60 Sync Polarity (CVT Reduce Blanking Mode) */
-#define M1920X1200_RB_R60_HSP  POSITIVE
-#define M1920X1200_RB_R60_VSP  NEGATIVE
-
-/* 2048x1536@60 Sync Polarity (CVT Mode) */
-#define M2048x1536_R60_HSP      NEGATIVE
-#define M2048x1536_R60_VSP      POSITIVE
-
 /* Definition CRTC Timing Index */
 #define H_TOTAL_INDEX               0
 #define H_ADDR_INDEX                1
diff --git a/drivers/video/via/via_aux.c b/drivers/video/via/via_aux.c
new file mode 100644
index 0000000..4a0a55c
--- /dev/null
+++ b/drivers/video/via/via_aux.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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.
+ */
+/*
+ * infrastructure for devices connected via I2C
+ */
+
+#include <linux/slab.h>
+#include "via_aux.h"
+
+
+struct via_aux_bus *via_aux_probe(struct i2c_adapter *adap)
+{
+	struct via_aux_bus *bus;
+
+	if (!adap)
+		return NULL;
+
+	bus = kmalloc(sizeof(*bus), GFP_KERNEL);
+	if (!bus)
+		return NULL;
+
+	bus->adap = adap;
+	INIT_LIST_HEAD(&bus->drivers);
+
+	via_aux_edid_probe(bus);
+	via_aux_vt1636_probe(bus);
+	via_aux_vt1632_probe(bus);
+	via_aux_vt1631_probe(bus);
+	via_aux_vt1625_probe(bus);
+	via_aux_vt1622_probe(bus);
+	via_aux_vt1621_probe(bus);
+	via_aux_sii164_probe(bus);
+	via_aux_ch7301_probe(bus);
+
+	return bus;
+}
+
+void via_aux_free(struct via_aux_bus *bus)
+{
+	struct via_aux_drv *pos, *n;
+
+	if (!bus)
+		return;
+
+	list_for_each_entry_safe(pos, n, &bus->drivers, chain) {
+		if (pos->cleanup)
+			pos->cleanup(pos);
+
+		list_del(&pos->chain);
+		kfree(pos->data);
+		kfree(pos);
+	}
+
+	kfree(bus);
+}
+
+const struct fb_videomode *via_aux_get_preferred_mode(struct via_aux_bus *bus)
+{
+	struct via_aux_drv *pos;
+	const struct fb_videomode *mode = NULL;
+
+	if (!bus)
+		return NULL;
+
+	list_for_each_entry(pos, &bus->drivers, chain) {
+		if (pos->get_preferred_mode)
+			mode = pos->get_preferred_mode(pos);
+	}
+
+	return mode;
+}
diff --git a/drivers/video/via/via_aux.h b/drivers/video/via/via_aux.h
new file mode 100644
index 0000000..a8de3f0
--- /dev/null
+++ b/drivers/video/via/via_aux.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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.
+ */
+/*
+ * infrastructure for devices connected via I2C
+ */
+
+#ifndef __VIA_AUX_H__
+#define __VIA_AUX_H__
+
+
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/fb.h>
+
+
+struct via_aux_bus {
+	struct i2c_adapter *adap;	/* the I2C device to access the bus */
+	struct list_head drivers;	/* drivers for devices on this bus */
+};
+
+struct via_aux_drv {
+	struct list_head chain;		/* chain to support multiple drivers */
+
+	struct via_aux_bus *bus;	/* the I2C bus used */
+	u8 addr;			/* the I2C slave address */
+
+	const char *name;	/* human readable name of the driver */
+	void *data;		/* private data of this driver */
+
+	void (*cleanup)(struct via_aux_drv *drv);
+	const struct fb_videomode* (*get_preferred_mode)
+		(struct via_aux_drv *drv);
+};
+
+
+struct via_aux_bus *via_aux_probe(struct i2c_adapter *adap);
+void via_aux_free(struct via_aux_bus *bus);
+const struct fb_videomode *via_aux_get_preferred_mode(struct via_aux_bus *bus);
+
+
+static inline bool via_aux_add(struct via_aux_drv *drv)
+{
+	struct via_aux_drv *data = kmalloc(sizeof(*data), GFP_KERNEL);
+
+	if (!data)
+		return false;
+
+	*data = *drv;
+	list_add_tail(&data->chain, &data->bus->drivers);
+	return true;
+}
+
+static inline bool via_aux_read(struct via_aux_drv *drv, u8 start, u8 *buf,
+	u8 len)
+{
+	struct i2c_msg msg[2] = {
+		{.addr = drv->addr, .flags = 0, .len = 1, .buf = &start},
+		{.addr = drv->addr, .flags = I2C_M_RD, .len = len, .buf = buf} };
+
+	return i2c_transfer(drv->bus->adap, msg, 2) == 2;
+}
+
+
+/* probe functions of existing drivers - should only be called in via_aux.c */
+void via_aux_ch7301_probe(struct via_aux_bus *bus);
+void via_aux_edid_probe(struct via_aux_bus *bus);
+void via_aux_sii164_probe(struct via_aux_bus *bus);
+void via_aux_vt1636_probe(struct via_aux_bus *bus);
+void via_aux_vt1632_probe(struct via_aux_bus *bus);
+void via_aux_vt1631_probe(struct via_aux_bus *bus);
+void via_aux_vt1625_probe(struct via_aux_bus *bus);
+void via_aux_vt1622_probe(struct via_aux_bus *bus);
+void via_aux_vt1621_probe(struct via_aux_bus *bus);
+
+
+#endif /* __VIA_AUX_H__ */
diff --git a/drivers/video/via/via_aux_ch7301.c b/drivers/video/via/via_aux_ch7301.c
new file mode 100644
index 0000000..1cbe503
--- /dev/null
+++ b/drivers/video/via/via_aux_ch7301.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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.
+ */
+/*
+ * driver for Chrontel CH7301 DVI Transmitter
+ */
+
+#include <linux/slab.h>
+#include "via_aux.h"
+
+
+static const char *name = "CH7301 DVI Transmitter";
+
+
+static void probe(struct via_aux_bus *bus, u8 addr)
+{
+	struct via_aux_drv drv = {
+		.bus	=	bus,
+		.addr	=	addr,
+		.name	=	name};
+	u8 tmp;
+
+	if (!via_aux_read(&drv, 0x4B, &tmp, 1) || tmp != 0x17)
+		return;
+
+	printk(KERN_INFO "viafb: Found %s at address 0x%x\n", name, addr);
+	via_aux_add(&drv);
+}
+
+void via_aux_ch7301_probe(struct via_aux_bus *bus)
+{
+	probe(bus, 0x75);
+	probe(bus, 0x76);
+}
diff --git a/drivers/video/via/via_aux_edid.c b/drivers/video/via/via_aux_edid.c
new file mode 100644
index 0000000..754d450
--- /dev/null
+++ b/drivers/video/via/via_aux_edid.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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.
+ */
+/*
+ * generic EDID driver
+ */
+
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include "via_aux.h"
+#include "../edid.h"
+
+
+static const char *name = "EDID";
+
+
+static void query_edid(struct via_aux_drv *drv)
+{
+	struct fb_monspecs *spec = drv->data;
+	unsigned char edid[EDID_LENGTH];
+	bool valid = false;
+
+	if (spec) {
+		fb_destroy_modedb(spec->modedb);
+	} else {
+		spec = kmalloc(sizeof(*spec), GFP_KERNEL);
+		if (!spec)
+			return;
+	}
+
+	spec->version = spec->revision = 0;
+	if (via_aux_read(drv, 0x00, edid, EDID_LENGTH)) {
+		fb_edid_to_monspecs(edid, spec);
+		valid = spec->version || spec->revision;
+	}
+
+	if (!valid) {
+		kfree(spec);
+		spec = NULL;
+	} else
+		printk(KERN_DEBUG "EDID: %s %s\n", spec->manufacturer, spec->monitor);
+
+	drv->data = spec;
+}
+
+static const struct fb_videomode *get_preferred_mode(struct via_aux_drv *drv)
+{
+	struct fb_monspecs *spec = drv->data;
+	int i;
+
+	if (!spec || !spec->modedb || !(spec->misc & FB_MISC_1ST_DETAIL))
+		return NULL;
+
+	for (i = 0; i < spec->modedb_len; i++) {
+		if (spec->modedb[i].flag & FB_MODE_IS_FIRST &&
+			spec->modedb[i].flag & FB_MODE_IS_DETAILED)
+			return &spec->modedb[i];
+	}
+
+	return NULL;
+}
+
+static void cleanup(struct via_aux_drv *drv)
+{
+	struct fb_monspecs *spec = drv->data;
+
+	if (spec)
+		fb_destroy_modedb(spec->modedb);
+}
+
+void via_aux_edid_probe(struct via_aux_bus *bus)
+{
+	struct via_aux_drv drv = {
+		.bus	=	bus,
+		.addr	=	0x50,
+		.name	=	name,
+		.cleanup	=	cleanup,
+		.get_preferred_mode	=	get_preferred_mode};
+
+	query_edid(&drv);
+
+	/* as EDID devices can be connected/disconnected just add the driver */
+	via_aux_add(&drv);
+}
diff --git a/drivers/video/via/via_aux_sii164.c b/drivers/video/via/via_aux_sii164.c
new file mode 100644
index 0000000..ca1b35f
--- /dev/null
+++ b/drivers/video/via/via_aux_sii164.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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.
+ */
+/*
+ * driver for Silicon Image SiI 164 PanelLink Transmitter
+ */
+
+#include <linux/slab.h>
+#include "via_aux.h"
+
+
+static const char *name = "SiI 164 PanelLink Transmitter";
+
+
+static void probe(struct via_aux_bus *bus, u8 addr)
+{
+	struct via_aux_drv drv = {
+		.bus	=	bus,
+		.addr	=	addr,
+		.name	=	name};
+	/* check vendor id and device id */
+	const u8 id[] = {0x01, 0x00, 0x06, 0x00}, len = ARRAY_SIZE(id);
+	u8 tmp[len];
+
+	if (!via_aux_read(&drv, 0x00, tmp, len) || memcmp(id, tmp, len))
+		return;
+
+	printk(KERN_INFO "viafb: Found %s at address 0x%x\n", name, addr);
+	via_aux_add(&drv);
+}
+
+void via_aux_sii164_probe(struct via_aux_bus *bus)
+{
+	u8 i;
+
+	for (i = 0x38; i <= 0x3F; i++)
+		probe(bus, i);
+}
diff --git a/drivers/video/via/via_aux_vt1621.c b/drivers/video/via/via_aux_vt1621.c
new file mode 100644
index 0000000..38eca84
--- /dev/null
+++ b/drivers/video/via/via_aux_vt1621.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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.
+ */
+/*
+ * driver for VIA VT1621(M) TV Encoder
+ */
+
+#include <linux/slab.h>
+#include "via_aux.h"
+
+
+static const char *name = "VT1621(M) TV Encoder";
+
+
+void via_aux_vt1621_probe(struct via_aux_bus *bus)
+{
+	struct via_aux_drv drv = {
+		.bus	=	bus,
+		.addr	=	0x20,
+		.name	=	name};
+	u8 tmp;
+
+	if (!via_aux_read(&drv, 0x1B, &tmp, 1) || tmp != 0x02)
+		return;
+
+	printk(KERN_INFO "viafb: Found %s\n", name);
+	via_aux_add(&drv);
+}
diff --git a/drivers/video/via/via_aux_vt1622.c b/drivers/video/via/via_aux_vt1622.c
new file mode 100644
index 0000000..8c79c68
--- /dev/null
+++ b/drivers/video/via/via_aux_vt1622.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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.
+ */
+/*
+ * driver for VIA VT1622(M) Digital TV Encoder
+ */
+
+#include <linux/slab.h>
+#include "via_aux.h"
+
+
+static const char *name = "VT1622(M) Digital TV Encoder";
+
+
+static void probe(struct via_aux_bus *bus, u8 addr)
+{
+	struct via_aux_drv drv = {
+		.bus	=	bus,
+		.addr	=	addr,
+		.name	=	name};
+	u8 tmp;
+
+	if (!via_aux_read(&drv, 0x1B, &tmp, 1) ||  tmp != 0x03)
+		return;
+
+	printk(KERN_INFO "viafb: Found %s at address 0x%x\n", name, addr);
+	via_aux_add(&drv);
+}
+
+void via_aux_vt1622_probe(struct via_aux_bus *bus)
+{
+	probe(bus, 0x20);
+	probe(bus, 0x21);
+}
diff --git a/drivers/video/via/via_aux_vt1625.c b/drivers/video/via/via_aux_vt1625.c
new file mode 100644
index 0000000..03eb301
--- /dev/null
+++ b/drivers/video/via/via_aux_vt1625.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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.
+ */
+/*
+ * driver for VIA VT1625(M) HDTV Encoder
+ */
+
+#include <linux/slab.h>
+#include "via_aux.h"
+
+
+static const char *name = "VT1625(M) HDTV Encoder";
+
+
+static void probe(struct via_aux_bus *bus, u8 addr)
+{
+	struct via_aux_drv drv = {
+		.bus	=	bus,
+		.addr	=	addr,
+		.name	=	name};
+	u8 tmp;
+
+	if (!via_aux_read(&drv, 0x1B, &tmp, 1) || tmp != 0x50)
+		return;
+
+	printk(KERN_INFO "viafb: Found %s at address 0x%x\n", name, addr);
+	via_aux_add(&drv);
+}
+
+void via_aux_vt1625_probe(struct via_aux_bus *bus)
+{
+	probe(bus, 0x20);
+	probe(bus, 0x21);
+}
diff --git a/drivers/video/via/via_aux_vt1631.c b/drivers/video/via/via_aux_vt1631.c
new file mode 100644
index 0000000..06e742f
--- /dev/null
+++ b/drivers/video/via/via_aux_vt1631.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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.
+ */
+/*
+ * driver for VIA VT1631 LVDS Transmitter
+ */
+
+#include <linux/slab.h>
+#include "via_aux.h"
+
+
+static const char *name = "VT1631 LVDS Transmitter";
+
+
+void via_aux_vt1631_probe(struct via_aux_bus *bus)
+{
+	struct via_aux_drv drv = {
+		.bus	=	bus,
+		.addr	=	0x38,
+		.name	=	name};
+	/* check vendor id and device id */
+	const u8 id[] = {0x06, 0x11, 0x91, 0x31}, len = ARRAY_SIZE(id);
+	u8 tmp[len];
+
+	if (!via_aux_read(&drv, 0x00, tmp, len) || memcmp(id, tmp, len))
+		return;
+
+	printk(KERN_INFO "viafb: Found %s\n", name);
+	via_aux_add(&drv);
+}
diff --git a/drivers/video/via/via_aux_vt1632.c b/drivers/video/via/via_aux_vt1632.c
new file mode 100644
index 0000000..d24f4cd
--- /dev/null
+++ b/drivers/video/via/via_aux_vt1632.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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.
+ */
+/*
+ * driver for VIA VT1632 DVI Transmitter
+ */
+
+#include <linux/slab.h>
+#include "via_aux.h"
+
+
+static const char *name = "VT1632 DVI Transmitter";
+
+
+static void probe(struct via_aux_bus *bus, u8 addr)
+{
+	struct via_aux_drv drv = {
+		.bus	=	bus,
+		.addr	=	addr,
+		.name	=	name};
+	/* check vendor id and device id */
+	const u8 id[] = {0x06, 0x11, 0x92, 0x31}, len = ARRAY_SIZE(id);
+	u8 tmp[len];
+
+	if (!via_aux_read(&drv, 0x00, tmp, len) || memcmp(id, tmp, len))
+		return;
+
+	printk(KERN_INFO "viafb: Found %s at address 0x%x\n", name, addr);
+	via_aux_add(&drv);
+}
+
+void via_aux_vt1632_probe(struct via_aux_bus *bus)
+{
+	u8 i;
+
+	for (i = 0x08; i <= 0x0F; i++)
+		probe(bus, i);
+}
diff --git a/drivers/video/via/via_aux_vt1636.c b/drivers/video/via/via_aux_vt1636.c
new file mode 100644
index 0000000..9e015c1
--- /dev/null
+++ b/drivers/video/via/via_aux_vt1636.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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.
+ */
+/*
+ * driver for VIA VT1636 LVDS Transmitter
+ */
+
+#include <linux/slab.h>
+#include "via_aux.h"
+
+
+static const char *name = "VT1636 LVDS Transmitter";
+
+
+void via_aux_vt1636_probe(struct via_aux_bus *bus)
+{
+	struct via_aux_drv drv = {
+		.bus	=	bus,
+		.addr	=	0x40,
+		.name	=	name};
+	/* check vendor id and device id */
+	const u8 id[] = {0x06, 0x11, 0x45, 0x33}, len = ARRAY_SIZE(id);
+	u8 tmp[len];
+
+	if (!via_aux_read(&drv, 0x00, tmp, len) || memcmp(id, tmp, len))
+		return;
+
+	printk(KERN_INFO "viafb: Found %s\n", name);
+	via_aux_add(&drv);
+}
diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c
index 78f1405..dd53058 100644
--- a/drivers/video/via/via_i2c.c
+++ b/drivers/video/via/via_i2c.c
@@ -51,7 +51,7 @@
 		val |= 0x01;
 		break;
 	case VIA_PORT_GPIO:
-		val |= 0x80;
+		val |= 0x82;
 		break;
 	default:
 		printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n");
@@ -67,6 +67,9 @@
 	int ret = 0;
 
 	spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
+	if (adap_data->type == VIA_PORT_GPIO)
+		via_write_reg_mask(adap_data->io_port, adap_data->ioport_index,
+			0, 0x80);
 	if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x08)
 		ret = 1;
 	spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
@@ -80,6 +83,9 @@
 	int ret = 0;
 
 	spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
+	if (adap_data->type == VIA_PORT_GPIO)
+		via_write_reg_mask(adap_data->io_port, adap_data->ioport_index,
+			0, 0x40);
 	if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x04)
 		ret = 1;
 	spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
@@ -103,7 +109,7 @@
 		val |= 0x01;
 		break;
 	case VIA_PORT_GPIO:
-		val |= 0x40;
+		val |= 0x42;
 		break;
 	default:
 		printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n");
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index a13c258..0c88375 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/stat.h>
 #include <linux/via-core.h>
+#include <linux/via_i2c.h>
 #include <asm/olpc.h>
 
 #define _MASTER_FILE
@@ -286,26 +287,22 @@
 			viafb_second_yres, viafb_bpp1, 1);
 	}
 
-	refresh = viafb_get_refresh(info->var.xres, info->var.yres,
-		get_var_refresh(&info->var));
-	if (viafb_get_best_mode(viafbinfo->var.xres, viafbinfo->var.yres,
-		refresh)) {
-		if (viafb_dual_fb && viapar->iga_path == IGA2) {
-			viafb_bpp1 = info->var.bits_per_pixel;
-			viafb_refresh1 = refresh;
-		} else {
-			viafb_bpp = info->var.bits_per_pixel;
-			viafb_refresh = refresh;
-		}
-
-		if (info->var.accel_flags & FB_ACCELF_TEXT)
-			info->flags &= ~FBINFO_HWACCEL_DISABLED;
-		else
-			info->flags |= FBINFO_HWACCEL_DISABLED;
-		viafb_setmode(info->var.bits_per_pixel, viafb_bpp1);
-		viafb_pan_display(&info->var, info);
+	refresh = get_var_refresh(&info->var);
+	if (viafb_dual_fb && viapar->iga_path == IGA2) {
+		viafb_bpp1 = info->var.bits_per_pixel;
+		viafb_refresh1 = refresh;
+	} else {
+		viafb_bpp = info->var.bits_per_pixel;
+		viafb_refresh = refresh;
 	}
 
+	if (info->var.accel_flags & FB_ACCELF_TEXT)
+		info->flags &= ~FBINFO_HWACCEL_DISABLED;
+	else
+		info->flags |= FBINFO_HWACCEL_DISABLED;
+	viafb_setmode();
+	viafb_pan_display(&info->var, info);
+
 	return 0;
 }
 
@@ -1670,12 +1667,23 @@
 }
 #undef IS_VT1636
 
-static int parse_mode(const char *str, u32 *xres, u32 *yres)
+static int parse_mode(const char *str, u32 devices, u32 *xres, u32 *yres)
 {
+	const struct fb_videomode *mode = NULL;
 	char *ptr;
 
 	if (!str) {
-		if (machine_is_olpc()) {
+		if (devices == VIA_CRT)
+			mode = via_aux_get_preferred_mode(
+				viaparinfo->shared->i2c_26);
+		else if (devices == VIA_DVP1)
+			mode = via_aux_get_preferred_mode(
+				viaparinfo->shared->i2c_31);
+
+		if (mode) {
+			*xres = mode->xres;
+			*yres = mode->yres;
+		} else if (machine_is_olpc()) {
 			*xres = 1200;
 			*yres = 900;
 		} else {
@@ -1729,6 +1737,31 @@
 
 #endif
 
+static void __devinit i2c_bus_probe(struct viafb_shared *shared)
+{
+	/* should be always CRT */
+	printk(KERN_INFO "viafb: Probing I2C bus 0x26\n");
+	shared->i2c_26 = via_aux_probe(viafb_find_i2c_adapter(VIA_PORT_26));
+
+	/* seems to be usually DVP1 */
+	printk(KERN_INFO "viafb: Probing I2C bus 0x31\n");
+	shared->i2c_31 = via_aux_probe(viafb_find_i2c_adapter(VIA_PORT_31));
+
+	/* FIXME: what is this? */
+	if (!machine_is_olpc()) {
+		printk(KERN_INFO "viafb: Probing I2C bus 0x2C\n");
+		shared->i2c_2C = via_aux_probe(viafb_find_i2c_adapter(VIA_PORT_2C));
+	}
+
+	printk(KERN_INFO "viafb: Finished I2C bus probing");
+}
+
+static void i2c_bus_free(struct viafb_shared *shared)
+{
+	via_aux_free(shared->i2c_26);
+	via_aux_free(shared->i2c_31);
+	via_aux_free(shared->i2c_2C);
+}
 
 int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
 {
@@ -1762,6 +1795,7 @@
 		&viaparinfo->shared->lvds_setting_info2;
 	viaparinfo->chip_info = &viaparinfo->shared->chip_info;
 
+	i2c_bus_probe(viaparinfo->shared);
 	if (viafb_dual_fb)
 		viafb_SAMM_ON = 1;
 	parse_lcd_port();
@@ -1804,10 +1838,11 @@
 			viafb_second_size * 1024 * 1024;
 	}
 
-	parse_mode(viafb_mode, &default_xres, &default_yres);
+	parse_mode(viafb_mode, viaparinfo->shared->iga1_devices,
+		&default_xres, &default_yres);
 	if (viafb_SAMM_ON == 1)
-		parse_mode(viafb_mode1, &viafb_second_xres,
-			&viafb_second_yres);
+		parse_mode(viafb_mode1, viaparinfo->shared->iga2_devices,
+			&viafb_second_xres, &viafb_second_yres);
 
 	default_var.xres = default_xres;
 	default_var.yres = default_yres;
@@ -1915,6 +1950,7 @@
 	if (viafbinfo1)
 		framebuffer_release(viafbinfo1);
 out_fb_release:
+	i2c_bus_free(viaparinfo->shared);
 	framebuffer_release(viafbinfo);
 	return rc;
 }
@@ -1927,6 +1963,7 @@
 	if (viafb_dual_fb)
 		unregister_framebuffer(viafbinfo1);
 	viafb_remove_proc(viaparinfo->shared);
+	i2c_bus_free(viaparinfo->shared);
 	framebuffer_release(viafbinfo);
 	if (viafb_dual_fb)
 		framebuffer_release(viafbinfo1);
@@ -2033,9 +2070,9 @@
 	if (r < 0)
 		return r;
 #endif
-	if (parse_mode(viafb_mode, &dummy_x, &dummy_y)
+	if (parse_mode(viafb_mode, 0, &dummy_x, &dummy_y)
 		|| !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh)
-		|| parse_mode(viafb_mode1, &dummy_x, &dummy_y)
+		|| parse_mode(viafb_mode1, 0, &dummy_x, &dummy_y)
 		|| !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh1)
 		|| viafb_bpp < 0 || viafb_bpp > 32
 		|| viafb_bpp1 < 0 || viafb_bpp1 > 32
diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h
index d944063..f6b2ddf 100644
--- a/drivers/video/via/viafbdev.h
+++ b/drivers/video/via/viafbdev.h
@@ -26,6 +26,7 @@
 #include <linux/fb.h>
 #include <linux/spinlock.h>
 
+#include "via_aux.h"
 #include "ioctl.h"
 #include "share.h"
 #include "chip.h"
@@ -48,6 +49,11 @@
 	struct proc_dir_entry *iga2_proc_entry;
 	struct viafb_dev *vdev;			/* Global dev info */
 
+	/* I2C busses that may have auxiliary devices */
+	struct via_aux_bus *i2c_26;
+	struct via_aux_bus *i2c_31;
+	struct via_aux_bus *i2c_2C;
+
 	/* All the information will be needed to set engine */
 	struct tmds_setting_information tmds_setting_info;
 	struct lvds_setting_information lvds_setting_info;
diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c
index 0911cac..0666ab0 100644
--- a/drivers/video/via/viamode.c
+++ b/drivers/video/via/viamode.c
@@ -268,591 +268,78 @@
 /* Mode Table       */
 /********************/
 
-/* 480x640 */
-static struct crt_mode_table CRTM480x640[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M480X640_R60_HSP, M480X640_R60_VSP,
-	 {624, 480, 480, 144, 504, 48, 663, 640, 640, 23, 641, 3} }	/* GTF*/
-};
+static const struct fb_videomode viafb_modes[] = {
+	{NULL, 60, 480, 640, 40285, 72, 24, 19, 1, 48, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, 0, 0, 0},
+	{NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3, 0, 0, 0},
+	{NULL, 85, 640, 480, 27780, 80, 56, 25, 1, 56, 3, 0, 0, 0},
+	{NULL, 100, 640, 480, 23167, 104, 40, 25, 1, 64, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 120, 640, 480, 19081, 104, 40, 31, 1, 64, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 720, 480, 37426, 88, 16, 13, 1, 72, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 720, 576, 30611, 96, 24, 17, 1, 72, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 800, 600, 25131, 88, 40, 23, 1, 128, 4, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 75, 800, 600, 20202, 160, 16, 21, 1, 80, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 85, 800, 600, 17790, 152, 32, 27, 1, 64, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 100, 800, 600, 14667, 136, 48, 32, 1, 88, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 120, 800, 600, 11911, 144, 56, 39, 1, 88, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 800, 480, 33602, 96, 24, 10, 3, 72, 7, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 848, 480, 31565, 104, 24, 12, 3, 80, 5, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 856, 480, 31517, 104, 16, 13, 1, 88, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1024, 512, 24218, 136, 32, 15, 1, 104, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1024, 600, 20423, 144, 40, 18, 1, 104, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6, 0, 0, 0},
+	{NULL, 75, 1024, 768, 12703, 176, 16, 28, 1, 96, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 85, 1024, 768, 10581, 208, 48, 36, 1, 96, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 100, 1024, 768, 8825, 184, 72, 42, 1, 112, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1280, 768, 12478, 200, 64, 23, 1, 136, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 50, 1280, 768, 15342, 184, 56, 19, 1, 128, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 960, 600, 21964, 128, 32, 15, 3, 96, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1000, 600, 20803, 144, 40, 18, 1, 104, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1024, 576, 21278, 144, 40, 17, 1, 104, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1088, 612, 18825, 152, 48, 16, 3, 104, 5, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1152, 720, 14974, 168, 56, 19, 3, 112, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1200, 720, 14248, 184, 56, 22, 1, 128, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 49, 1200, 900, 17703, 21, 11, 1, 1, 32, 10, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1280, 600, 16259, 184, 56, 18, 1, 128, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1280, 800, 11938, 200, 72, 22, 3, 128, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1280, 1024, 9262, 248, 48, 38, 1, 112, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 75, 1280, 1024, 7409, 248, 16, 38, 1, 144, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 85, 1280, 1024, 6351, 224, 64, 44, 1, 160, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1360, 768, 11759, 208, 72, 22, 3, 136, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1368, 768, 11646, 216, 72, 23, 1, 144, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 50, 1368, 768, 14301, 200, 56, 19, 1, 144, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1368, 768, 11646, 216, 72, 23, 1, 144, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1440, 900, 9372, 232, 80, 25, 3, 152, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 75, 1440, 900, 7311, 248, 96, 33, 3, 152, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1440, 1040, 7993, 248, 96, 33, 1, 152, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1600, 900, 8449, 256, 88, 26, 3, 168, 5, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1600, 1024, 7333, 272, 104, 32, 1, 168, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1680, 1050, 6832, 280, 104, 30, 3, 176, 6, 0, 0, 0},
+	{NULL, 75, 1680, 1050, 5339, 296, 120, 40, 3, 176, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1792, 1344, 4883, 328, 128, 46, 1, 200, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1856, 1392, 4581, 352, 96, 43, 1, 224, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 208, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 2048, 1536, 3738, 376, 152, 49, 3, 224, 4, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1280, 720, 13484, 216, 112, 20, 5, 40, 5, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 50, 1280, 720, 16538, 176, 48, 17, 1, 128, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1920, 1080, 5776, 328, 128, 32, 3, 200, 5, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1920, 1200, 5164, 336, 136, 36, 3, 200, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 60, 1400, 1050, 8210, 232, 88, 32, 3, 144, 4, FB_SYNC_VERT_HIGH_ACT, 0, 0},
+	{NULL, 75, 1400, 1050, 6398, 248, 104, 42, 3, 144, 4, FB_SYNC_VERT_HIGH_ACT, 0, 0} };
 
-/* 640x480*/
-static struct crt_mode_table CRTM640x480[] = {
-	/*r_rate,hsp,vsp */
-	/*HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M640X480_R60_HSP, M640X480_R60_VSP,
-	 {800, 640, 640, 160, 656, 96, 525, 480, 480, 45, 490, 2} },
-	{REFRESH_75, M640X480_R75_HSP, M640X480_R75_VSP,
-	 {840, 640, 640, 200, 656, 64, 500, 480, 480, 20, 481, 3} },
-	{REFRESH_85, M640X480_R85_HSP, M640X480_R85_VSP,
-	 {832, 640, 640, 192, 696, 56, 509, 480, 480, 29, 481, 3} },
-	{REFRESH_100, M640X480_R100_HSP, M640X480_R100_VSP,
-	 {848, 640, 640, 208, 680, 64, 509, 480, 480, 29, 481, 3} }, /*GTF*/
-	{REFRESH_120, M640X480_R120_HSP, M640X480_R120_VSP,
-	 {848, 640, 640, 208, 680, 64, 515, 480, 480, 35, 481, 3} } /*GTF*/
-};
-
-/*720x480 (GTF)*/
-static struct crt_mode_table CRTM720x480[] = {
-	/*r_rate,hsp,vsp      */
-	/*HT, HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M720X480_R60_HSP, M720X480_R60_VSP,
-	 {896, 720, 720, 176, 736, 72, 497, 480, 480, 17, 481, 3} }
-
-};
-
-/*720x576 (GTF)*/
-static struct crt_mode_table CRTM720x576[] = {
-	/*r_rate,hsp,vsp */
-	/*HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M720X576_R60_HSP, M720X576_R60_VSP,
-	 {912, 720, 720, 192, 744, 72, 597, 576, 576, 21, 577, 3} }
-};
-
-/* 800x480 (CVT) */
-static struct crt_mode_table CRTM800x480[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M800X480_R60_HSP, M800X480_R60_VSP,
-	 {992, 800, 800, 192, 824, 72, 500, 480, 480, 20, 483, 7} }
-};
-
-/* 800x600*/
-static struct crt_mode_table CRTM800x600[] = {
-	/*r_rate,hsp,vsp     */
-	/*HT,   HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M800X600_R60_HSP, M800X600_R60_VSP,
-	 {1056, 800, 800, 256, 840, 128, 628, 600, 600, 28, 601, 4} },
-	{REFRESH_75, M800X600_R75_HSP, M800X600_R75_VSP,
-	 {1056, 800, 800, 256, 816, 80, 625, 600, 600, 25, 601, 3} },
-	{REFRESH_85, M800X600_R85_HSP, M800X600_R85_VSP,
-	 {1048, 800, 800, 248, 832, 64, 631, 600, 600, 31, 601, 3} },
-	{REFRESH_100, M800X600_R100_HSP, M800X600_R100_VSP,
-	 {1072, 800, 800, 272, 848, 88, 636, 600, 600, 36, 601, 3} },
-	{REFRESH_120, M800X600_R120_HSP, M800X600_R120_VSP,
-	 {1088, 800, 800, 288, 856, 88, 643, 600, 600, 43, 601, 3} }
-};
-
-/* 848x480 (CVT) */
-static struct crt_mode_table CRTM848x480[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M848X480_R60_HSP, M848X480_R60_VSP,
-	 {1056, 848, 848, 208, 872, 80, 500, 480, 480, 20, 483, 5} }
-};
-
-/*856x480 (GTF) convert to 852x480*/
-static struct crt_mode_table CRTM852x480[] = {
-	/*r_rate,hsp,vsp     */
-	/*HT,   HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M852X480_R60_HSP, M852X480_R60_VSP,
-	{1064, 856, 856, 208, 872, 88, 497, 480, 480, 17, 481, 3} }
-};
-
-/*1024x512 (GTF)*/
-static struct crt_mode_table CRTM1024x512[] = {
-	/*r_rate,hsp,vsp     */
-	/*HT,   HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1024X512_R60_HSP, M1024X512_R60_VSP,
-	 {1296, 1024, 1024, 272, 1056, 104, 531, 512, 512, 19, 513, 3} }
-
-};
-
-/* 1024x600*/
-static struct crt_mode_table CRTM1024x600[] = {
-	/*r_rate,hsp,vsp */
-	/*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1024X600_R60_HSP, M1024X600_R60_VSP,
-	 {1312, 1024, 1024, 288, 1064, 104, 622, 600, 600, 22, 601, 3} },
-};
-
-/* 1024x768*/
-static struct crt_mode_table CRTM1024x768[] = {
-	/*r_rate,hsp,vsp */
-	/*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1024X768_R60_HSP, M1024X768_R60_VSP,
-	{1344, 1024, 1024, 320, 1048, 136, 806, 768, 768, 38, 771, 6} },
-	{REFRESH_75, M1024X768_R75_HSP, M1024X768_R75_VSP,
-	{1312, 1024, 1024, 288, 1040, 96, 800, 768, 768, 32, 769, 3} },
-	{REFRESH_85, M1024X768_R85_HSP, M1024X768_R85_VSP,
-	{1376, 1024, 1024, 352, 1072, 96, 808, 768, 768, 40, 769, 3} },
-	{REFRESH_100, M1024X768_R100_HSP, M1024X768_R100_VSP,
-	{1392, 1024, 1024, 368, 1096, 112, 814, 768, 768, 46, 769, 3} }
-};
-
-/* 1152x864*/
-static struct crt_mode_table CRTM1152x864[] = {
-	/*r_rate,hsp,vsp      */
-	/*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_75, M1152X864_R75_HSP, M1152X864_R75_VSP,
-	 {1600, 1152, 1152, 448, 1216, 128, 900, 864, 864, 36, 865, 3} }
-
-};
-
-/* 1280x720 (HDMI 720P)*/
-static struct crt_mode_table CRTM1280x720[] = {
-	/*r_rate,hsp,vsp */
-	/*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE      */
-	{REFRESH_60, M1280X720_R60_HSP, M1280X720_R60_VSP,
-	 {1648, 1280, 1280, 368, 1392, 40, 750, 720, 720, 30, 725, 5} },
-	{REFRESH_50, M1280X720_R50_HSP, M1280X720_R50_VSP,
-	 {1632, 1280, 1280, 352, 1328, 128, 741, 720, 720, 21, 721, 3} }
-};
-
-/*1280x768 (GTF)*/
-static struct crt_mode_table CRTM1280x768[] = {
-	/*r_rate,hsp,vsp     */
-	/*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1280X768_R60_HSP, M1280X768_R60_VSP,
-	 {1680, 1280, 1280, 400, 1344, 136, 795, 768, 768, 27, 769, 3} },
-	{REFRESH_50, M1280X768_R50_HSP, M1280X768_R50_VSP,
-	 {1648, 1280, 1280, 368, 1336, 128, 791, 768, 768, 23, 769, 3} }
-};
-
-/* 1280x800 (CVT) */
-static struct crt_mode_table CRTM1280x800[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1280X800_R60_HSP, M1280X800_R60_VSP,
-	 {1680, 1280, 1280, 400, 1352, 128, 831, 800, 800, 31, 803, 6} }
-};
-
-/*1280x960*/
-static struct crt_mode_table CRTM1280x960[] = {
-	/*r_rate,hsp,vsp */
-	/*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1280X960_R60_HSP, M1280X960_R60_VSP,
-	 {1800, 1280, 1280, 520, 1376, 112, 1000, 960, 960, 40, 961, 3} }
-};
-
-/* 1280x1024*/
-static struct crt_mode_table CRTM1280x1024[] = {
-	/*r_rate,hsp,vsp */
-	/*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1280X1024_R60_HSP, M1280X1024_R60_VSP,
-	 {1688, 1280, 1280, 408, 1328, 112, 1066, 1024, 1024, 42, 1025,
-	  3} },
-	{REFRESH_75, M1280X1024_R75_HSP, M1280X1024_R75_VSP,
-	 {1688, 1280, 1280, 408, 1296, 144, 1066, 1024, 1024, 42, 1025,
-	  3} },
-	{REFRESH_85, M1280X1024_R85_HSP, M1280X1024_R85_VSP,
-	 {1728, 1280, 1280, 448, 1344, 160, 1072, 1024, 1024, 48, 1025, 3} }
-};
-
-/* 1368x768 (GTF) */
-static struct crt_mode_table CRTM1368x768[] = {
-	/* r_rate,  hsp, vsp */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1368X768_R60_HSP, M1368X768_R60_VSP,
-	 {1800, 1368, 1368, 432, 1440, 144, 795, 768, 768, 27, 769, 3} }
-};
-
-/*1440x1050 (GTF)*/
-static struct crt_mode_table CRTM1440x1050[] = {
-	/*r_rate,hsp,vsp      */
-	/*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1440X1050_R60_HSP, M1440X1050_R60_VSP,
-	 {1936, 1440, 1440, 496, 1536, 152, 1077, 1040, 1040, 37, 1041, 3} }
-};
-
-/* 1600x1200*/
-static struct crt_mode_table CRTM1600x1200[] = {
-	/*r_rate,hsp,vsp */
-	/*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1600X1200_R60_HSP, M1600X1200_R60_VSP,
-	 {2160, 1600, 1600, 560, 1664, 192, 1250, 1200, 1200, 50, 1201,
-	  3} },
-	{REFRESH_75, M1600X1200_R75_HSP, M1600X1200_R75_VSP,
-	 {2160, 1600, 1600, 560, 1664, 192, 1250, 1200, 1200, 50, 1201, 3} }
-
-};
-
-/* 1680x1050 (CVT) */
-static struct crt_mode_table CRTM1680x1050[] = {
-	/* r_rate,              hsp,             vsp  */
-	/* HT,  HA,  HBS, HBE, HSS, HSE,    VT,  VA,  VBS, VBE,  VSS, VSE */
-	{REFRESH_60, M1680x1050_R60_HSP, M1680x1050_R60_VSP,
-	 {2240, 1680, 1680, 560, 1784, 176, 1089, 1050, 1050, 39, 1053,
-	  6} },
-	{REFRESH_75, M1680x1050_R75_HSP, M1680x1050_R75_VSP,
-	 {2272, 1680, 1680, 592, 1800, 176, 1099, 1050, 1050, 49, 1053, 6} }
-};
-
-/* 1680x1050 (CVT Reduce Blanking) */
-static struct crt_mode_table CRTM1680x1050_RB[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE,    VT,  VA,  VBS, VBE,  VSS, VSE */
-	{REFRESH_60, M1680x1050_RB_R60_HSP, M1680x1050_RB_R60_VSP,
-	 {1840, 1680, 1680, 160, 1728, 32, 1080, 1050, 1050, 30, 1053, 6} }
-};
-
-/* 1920x1080 (CVT)*/
-static struct crt_mode_table CRTM1920x1080[] = {
-	/*r_rate,hsp,vsp */
-	/*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1920X1080_R60_HSP, M1920X1080_R60_VSP,
-	 {2576, 1920, 1920, 656, 2048, 200, 1120, 1080, 1080, 40, 1083, 5} }
-};
-
-/* 1920x1080 (CVT with Reduce Blanking) */
-static struct crt_mode_table CRTM1920x1080_RB[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1920X1080_RB_R60_HSP, M1920X1080_RB_R60_VSP,
-	 {2080, 1920, 1920, 160, 1968, 32, 1111, 1080, 1080, 31, 1083, 5} }
-};
-
-/* 1920x1440*/
-static struct crt_mode_table CRTM1920x1440[] = {
-	/*r_rate,hsp,vsp */
-	/*HT,  HA,   HBS,  HBE, HSS,  HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1920X1440_R60_HSP, M1920X1440_R60_VSP,
-	 {2600, 1920, 1920, 680, 2048, 208, 1500, 1440, 1440, 60, 1441,
-	  3} },
-	{REFRESH_75, M1920X1440_R75_HSP, M1920X1440_R75_VSP,
-	 {2640, 1920, 1920, 720, 2064, 224, 1500, 1440, 1440, 60, 1441, 3} }
-};
-
-/* 1400x1050 (CVT) */
-static struct crt_mode_table CRTM1400x1050[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE,  HSS, HSE,   VT,  VA,  VBS, VBE,  VSS, VSE */
-	{REFRESH_60, M1400X1050_R60_HSP, M1400X1050_R60_VSP,
-	 {1864, 1400, 1400, 464, 1488, 144, 1089, 1050, 1050, 39, 1053,
-	  4} },
-	{REFRESH_75, M1400X1050_R75_HSP, M1400X1050_R75_VSP,
-	 {1896, 1400, 1400, 496, 1504, 144, 1099, 1050, 1050, 49, 1053, 4} }
-};
-
-/* 1400x1050 (CVT Reduce Blanking) */
-static struct crt_mode_table CRTM1400x1050_RB[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE,  HSS, HSE,   VT,  VA,  VBS, VBE,  VSS, VSE */
-	{REFRESH_60, M1400X1050_RB_R60_HSP, M1400X1050_RB_R60_VSP,
-	 {1560, 1400, 1400, 160, 1448, 32, 1080, 1050, 1050, 30, 1053, 4} }
-};
-
-/* 960x600 (CVT) */
-static struct crt_mode_table CRTM960x600[] = {
-	/* r_rate,          hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M960X600_R60_HSP, M960X600_R60_VSP,
-	 {1216, 960, 960, 256, 992, 96, 624, 600, 600, 24, 603, 6} }
-};
-
-/* 1000x600 (GTF) */
-static struct crt_mode_table CRTM1000x600[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1000X600_R60_HSP, M1000X600_R60_VSP,
-	 {1288, 1000, 1000, 288, 1040, 104, 622, 600, 600, 22, 601, 3} }
-};
-
-/* 1024x576 (GTF) */
-static struct crt_mode_table CRTM1024x576[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1024X576_R60_HSP, M1024X576_R60_VSP,
-	 {1312, 1024, 1024, 288, 1064, 104, 597, 576, 576, 21, 577, 3} }
-};
-
-/* 1088x612 (CVT) */
-static struct crt_mode_table CRTM1088x612[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1088X612_R60_HSP, M1088X612_R60_VSP,
-	 {1392, 1088, 1088, 304, 1136, 104, 636, 612, 612, 24, 615, 5} }
-};
-
-/* 1152x720 (CVT) */
-static struct crt_mode_table CRTM1152x720[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1152X720_R60_HSP, M1152X720_R60_VSP,
-	 {1488, 1152, 1152, 336, 1208, 112, 748, 720, 720, 28, 723, 6} }
-};
-
-/* 1200x720 (GTF) */
-static struct crt_mode_table CRTM1200x720[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1200X720_R60_HSP, M1200X720_R60_VSP,
-	 {1568, 1200, 1200, 368, 1256, 128, 746, 720, 720, 26, 721, 3} }
-};
-
-/* 1200x900 (DCON) */
-static struct crt_mode_table DCON1200x900[] = {
-	/* r_rate,               hsp,               vsp   */
-	{REFRESH_49, M1200X900_R60_HSP, M1200X900_R60_VSP,
-	/* The correct htotal is 1240, but this doesn't raster on VX855. */
-	/* Via suggested changing to a multiple of 16, hence 1264.       */
-	/*  HT,   HA,  HBS, HBE,  HSS, HSE,  VT,  VA, VBS, VBE, VSS, VSE */
-	 {1264, 1200, 1200,  64, 1211,  32, 912, 900, 900,  12, 901, 10} }
-};
-
-/* 1280x600 (GTF) */
-static struct crt_mode_table CRTM1280x600[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE,  HSS, HSE, VT,  VA,  VBS, VBE,  VSS, VSE */
-	{REFRESH_60, M1280x600_R60_HSP, M1280x600_R60_VSP,
-	 {1648, 1280, 1280, 368, 1336, 128, 622, 600, 600, 22, 601, 3} }
-};
-
-/* 1360x768 (CVT) */
-static struct crt_mode_table CRTM1360x768[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1360X768_R60_HSP, M1360X768_R60_VSP,
-	 {1776, 1360, 1360, 416, 1432, 136, 798, 768, 768, 30, 771, 5} }
-};
-
-/* 1360x768 (CVT Reduce Blanking) */
-static struct crt_mode_table CRTM1360x768_RB[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1360X768_RB_R60_HSP, M1360X768_RB_R60_VSP,
-	 {1520, 1360, 1360, 160, 1408, 32, 790, 768, 768, 22, 771, 5} }
-};
-
-/* 1366x768 (GTF) */
-static struct crt_mode_table CRTM1366x768[] = {
-	/* r_rate,          hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1368X768_R60_HSP, M1368X768_R60_VSP,
-	 {1800, 1368, 1368, 432, 1440, 144, 795, 768, 768, 27, 769, 3} },
-	{REFRESH_50, M1368X768_R50_HSP, M1368X768_R50_VSP,
-	 {1768, 1368, 1368, 400, 1424, 144, 791, 768, 768, 23, 769, 3} }
-};
-
-/* 1440x900 (CVT) */
-static struct crt_mode_table CRTM1440x900[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1440X900_R60_HSP, M1440X900_R60_VSP,
-	 {1904, 1440, 1440, 464, 1520, 152, 934, 900, 900, 34, 903, 6} },
-	{REFRESH_75, M1440X900_R75_HSP, M1440X900_R75_VSP,
-	 {1936, 1440, 1440, 496, 1536, 152, 942, 900, 900, 42, 903, 6} }
-};
-
-/* 1440x900 (CVT Reduce Blanking) */
-static struct crt_mode_table CRTM1440x900_RB[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1440X900_RB_R60_HSP, M1440X900_RB_R60_VSP,
-	 {1600, 1440, 1440, 160, 1488, 32, 926, 900, 900, 26, 903, 6} }
-};
-
-/* 1600x900 (CVT) */
-static struct crt_mode_table CRTM1600x900[] = {
-	/* r_rate,          hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1600X900_R60_HSP, M1600X900_R60_VSP,
-	 {2112, 1600, 1600, 512, 1688, 168, 934, 900, 900, 34, 903, 5} }
-};
-
-/* 1600x900 (CVT Reduce Blanking) */
-static struct crt_mode_table CRTM1600x900_RB[] = {
-	/* r_rate,           hsp,        vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1600X900_RB_R60_HSP, M1600X900_RB_R60_VSP,
-	 {1760, 1600, 1600, 160, 1648, 32, 926, 900, 900, 26, 903, 5} }
-};
-
-/* 1600x1024 (GTF) */
-static struct crt_mode_table CRTM1600x1024[] = {
-	/* r_rate,          hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE,  HSS, HSE,   VT,  VA,  VBS, VBE,  VSS, VSE */
-	{REFRESH_60, M1600X1024_R60_HSP, M1600X1024_R60_VSP,
-	 {2144, 1600, 1600, 544, 1704, 168, 1060, 1024, 1024, 36, 1025, 3} }
-};
-
-/* 1792x1344 (DMT) */
-static struct crt_mode_table CRTM1792x1344[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE,  HSS, HSE,   VT,  VA,  VBS, VBE,  VSS, VSE */
-	{REFRESH_60, M1792x1344_R60_HSP, M1792x1344_R60_VSP,
-	 {2448, 1792, 1792, 656, 1920, 200, 1394, 1344, 1344, 50, 1345, 3} }
-};
-
-/* 1856x1392 (DMT) */
-static struct crt_mode_table CRTM1856x1392[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE,  HSS, HSE,   VT,  VA,  VBS, VBE,  VSS, VSE */
-	{REFRESH_60, M1856x1392_R60_HSP, M1856x1392_R60_VSP,
-	 {2528, 1856, 1856, 672, 1952, 224, 1439, 1392, 1392, 47, 1393, 3} }
-};
-
-/* 1920x1200 (CVT) */
-static struct crt_mode_table CRTM1920x1200[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1920X1200_R60_HSP, M1920X1200_R60_VSP,
-	 {2592, 1920, 1920, 672, 2056, 200, 1245, 1200, 1200, 45, 1203, 6} }
-};
-
-/* 1920x1200 (CVT with Reduce Blanking) */
-static struct crt_mode_table CRTM1920x1200_RB[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE, HSS, HSE, VT,  VA,  VBS, VBE, VSS, VSE */
-	{REFRESH_60, M1920X1200_RB_R60_HSP, M1920X1200_RB_R60_VSP,
-	 {2080, 1920, 1920, 160, 1968, 32, 1235, 1200, 1200, 35, 1203, 6} }
-};
-
-/* 2048x1536 (CVT) */
-static struct crt_mode_table CRTM2048x1536[] = {
-	/* r_rate,              hsp,             vsp   */
-	/* HT,  HA,  HBS, HBE,  HSS, HSE,   VT,  VA,  VBS, VBE,  VSS, VSE */
-	{REFRESH_60, M2048x1536_R60_HSP, M2048x1536_R60_VSP,
-	 {2800, 2048, 2048, 752, 2200, 224, 1592, 1536, 1536, 56, 1539, 4} }
-};
-
-static struct VideoModeTable viafb_modes[] = {
-	/* Display : 480x640 (GTF) */
-	{CRTM480x640, ARRAY_SIZE(CRTM480x640)},
-
-	/* Display : 640x480 */
-	{CRTM640x480, ARRAY_SIZE(CRTM640x480)},
-
-	/* Display : 720x480 (GTF) */
-	{CRTM720x480, ARRAY_SIZE(CRTM720x480)},
-
-	/* Display : 720x576 (GTF) */
-	{CRTM720x576, ARRAY_SIZE(CRTM720x576)},
-
-	/* Display : 800x600 */
-	{CRTM800x600, ARRAY_SIZE(CRTM800x600)},
-
-	/* Display : 800x480 (CVT) */
-	{CRTM800x480, ARRAY_SIZE(CRTM800x480)},
-
-	/* Display : 848x480 (CVT) */
-	{CRTM848x480, ARRAY_SIZE(CRTM848x480)},
-
-	/* Display : 852x480 (GTF) */
-	{CRTM852x480, ARRAY_SIZE(CRTM852x480)},
-
-	/* Display : 1024x512 (GTF) */
-	{CRTM1024x512, ARRAY_SIZE(CRTM1024x512)},
-
-	/* Display : 1024x600 */
-	{CRTM1024x600, ARRAY_SIZE(CRTM1024x600)},
-
-	/* Display : 1024x768 */
-	{CRTM1024x768, ARRAY_SIZE(CRTM1024x768)},
-
-	/* Display : 1152x864 */
-	{CRTM1152x864, ARRAY_SIZE(CRTM1152x864)},
-
-	/* Display : 1280x768 (GTF) */
-	{CRTM1280x768, ARRAY_SIZE(CRTM1280x768)},
-
-	/* Display : 960x600 (CVT) */
-	{CRTM960x600, ARRAY_SIZE(CRTM960x600)},
-
-	/* Display : 1000x600 (GTF) */
-	{CRTM1000x600, ARRAY_SIZE(CRTM1000x600)},
-
-	/* Display : 1024x576 (GTF) */
-	{CRTM1024x576, ARRAY_SIZE(CRTM1024x576)},
-
-	/* Display : 1088x612 (GTF) */
-	{CRTM1088x612, ARRAY_SIZE(CRTM1088x612)},
-
-	/* Display : 1152x720 (CVT) */
-	{CRTM1152x720, ARRAY_SIZE(CRTM1152x720)},
-
-	/* Display : 1200x720 (GTF) */
-	{CRTM1200x720, ARRAY_SIZE(CRTM1200x720)},
-
-	/* Display : 1200x900 (DCON) */
-	{DCON1200x900, ARRAY_SIZE(DCON1200x900)},
-
-	/* Display : 1280x600 (GTF) */
-	{CRTM1280x600, ARRAY_SIZE(CRTM1280x600)},
-
-	/* Display : 1280x800 (CVT) */
-	{CRTM1280x800, ARRAY_SIZE(CRTM1280x800)},
-
-	/* Display : 1280x960 */
-	{CRTM1280x960, ARRAY_SIZE(CRTM1280x960)},
-
-	/* Display : 1280x1024 */
-	{CRTM1280x1024, ARRAY_SIZE(CRTM1280x1024)},
-
-	/* Display : 1360x768 (CVT) */
-	{CRTM1360x768, ARRAY_SIZE(CRTM1360x768)},
-
-	/* Display : 1366x768 */
-	{CRTM1366x768, ARRAY_SIZE(CRTM1366x768)},
-
-	/* Display : 1368x768 (GTF) */
-	{CRTM1368x768, ARRAY_SIZE(CRTM1368x768)},
-
-	/* Display : 1440x900 (CVT) */
-	{CRTM1440x900, ARRAY_SIZE(CRTM1440x900)},
-
-	/* Display : 1440x1050 (GTF) */
-	{CRTM1440x1050, ARRAY_SIZE(CRTM1440x1050)},
-
-	/* Display : 1600x900 (CVT) */
-	{CRTM1600x900, ARRAY_SIZE(CRTM1600x900)},
-
-	/* Display : 1600x1024 (GTF) */
-	{CRTM1600x1024, ARRAY_SIZE(CRTM1600x1024)},
-
-	/* Display : 1600x1200 */
-	{CRTM1600x1200, ARRAY_SIZE(CRTM1600x1200)},
-
-	/* Display : 1680x1050 (CVT) */
-	{CRTM1680x1050, ARRAY_SIZE(CRTM1680x1050)},
-
-	/* Display : 1792x1344 (DMT) */
-	{CRTM1792x1344, ARRAY_SIZE(CRTM1792x1344)},
-
-	/* Display : 1856x1392 (DMT) */
-	{CRTM1856x1392, ARRAY_SIZE(CRTM1856x1392)},
-
-	/* Display : 1920x1440 */
-	{CRTM1920x1440, ARRAY_SIZE(CRTM1920x1440)},
-
-	/* Display : 2048x1536 */
-	{CRTM2048x1536, ARRAY_SIZE(CRTM2048x1536)},
-
-	/* Display : 1280x720 */
-	{CRTM1280x720, ARRAY_SIZE(CRTM1280x720)},
-
-	/* Display : 1920x1080 (CVT) */
-	{CRTM1920x1080, ARRAY_SIZE(CRTM1920x1080)},
-
-	/* Display : 1920x1200 (CVT) */
-	{CRTM1920x1200, ARRAY_SIZE(CRTM1920x1200)},
-
-	/* Display : 1400x1050 (CVT) */
-	{CRTM1400x1050, ARRAY_SIZE(CRTM1400x1050)}
-};
-
-static struct VideoModeTable viafb_rb_modes[] = {
-	/* Display : 1360x768 (CVT Reduce Blanking) */
-	{CRTM1360x768_RB, ARRAY_SIZE(CRTM1360x768_RB)},
-
-	/* Display : 1440x900 (CVT Reduce Blanking) */
-	{CRTM1440x900_RB, ARRAY_SIZE(CRTM1440x900_RB)},
-
-	/* Display : 1400x1050 (CVT Reduce Blanking) */
-	{CRTM1400x1050_RB, ARRAY_SIZE(CRTM1400x1050_RB)},
-
-	/* Display : 1600x900 (CVT Reduce Blanking) */
-	{CRTM1600x900_RB, ARRAY_SIZE(CRTM1600x900_RB)},
-
-	/* Display : 1680x1050 (CVT Reduce Blanking) */
-	{CRTM1680x1050_RB, ARRAY_SIZE(CRTM1680x1050_RB)},
-
-	/* Display : 1920x1080 (CVT Reduce Blanking) */
-	{CRTM1920x1080_RB, ARRAY_SIZE(CRTM1920x1080_RB)},
-
-	/* Display : 1920x1200 (CVT Reduce Blanking) */
-	{CRTM1920x1200_RB, ARRAY_SIZE(CRTM1920x1200_RB)}
-};
+static const struct fb_videomode viafb_rb_modes[] = {
+	{NULL, 60, 1360, 768, 13879, 80, 48, 14, 3, 32, 5, FB_SYNC_HOR_HIGH_ACT, 0, 0},
+	{NULL, 60, 1440, 900, 11249, 80, 48, 17, 3, 32, 6, FB_SYNC_HOR_HIGH_ACT, 0, 0},
+	{NULL, 60, 1400, 1050, 9892, 80, 48, 23, 3, 32, 4, FB_SYNC_HOR_HIGH_ACT, 0, 0},
+	{NULL, 60, 1600, 900, 10226, 80, 48, 18, 3, 32, 5, FB_SYNC_HOR_HIGH_ACT, 0, 0},
+	{NULL, 60, 1680, 1050, 8387, 80, 48, 21, 3, 32, 6, FB_SYNC_HOR_HIGH_ACT, 0, 0},
+	{NULL, 60, 1920, 1080, 7212, 80, 48, 23, 3, 32, 5, FB_SYNC_HOR_HIGH_ACT, 0, 0},
+	{NULL, 60, 1920, 1200, 6488, 80, 48, 26, 3, 32, 6, FB_SYNC_HOR_HIGH_ACT, 0, 0} };
 
 int NUM_TOTAL_CN400_ModeXregs = ARRAY_SIZE(CN400_ModeXregs);
 int NUM_TOTAL_CN700_ModeXregs = ARRAY_SIZE(CN700_ModeXregs);
@@ -863,56 +350,34 @@
 int NUM_TOTAL_PATCH_MODE = ARRAY_SIZE(res_patch_table);
 
 
-static struct VideoModeTable *get_modes(struct VideoModeTable *vmt, int n,
-	int hres, int vres)
+static const struct fb_videomode *get_best_mode(
+	const struct fb_videomode *modes, int n,
+	int hres, int vres, int refresh)
 {
+	const struct fb_videomode *best = NULL;
 	int i;
 
-	for (i = 0; i < n; i++)
-		if (vmt[i].mode_array &&
-			vmt[i].crtc[0].crtc.hor_addr == hres &&
-			vmt[i].crtc[0].crtc.ver_addr == vres)
-			return &viafb_modes[i];
+	for (i = 0; i < n; i++) {
+		if (modes[i].xres != hres || modes[i].yres != vres)
+			continue;
 
-	return NULL;
-}
-
-static struct crt_mode_table *get_best_mode(struct VideoModeTable *vmt,
-	int refresh)
-{
-	struct crt_mode_table *best;
-	int i;
-
-	if (!vmt)
-		return NULL;
-
-	best = &vmt->crtc[0];
-	for (i = 1; i < vmt->mode_array; i++) {
-		if (abs(vmt->crtc[i].refresh_rate - refresh)
-			< abs(best->refresh_rate - refresh))
-			best = &vmt->crtc[i];
+		if (!best || abs(modes[i].refresh - refresh) <
+			abs(best->refresh - refresh))
+			best = &modes[i];
 	}
 
 	return best;
 }
 
-static struct VideoModeTable *viafb_get_mode(int hres, int vres)
+const struct fb_videomode *viafb_get_best_mode(int hres, int vres, int refresh)
 {
-	return get_modes(viafb_modes, ARRAY_SIZE(viafb_modes), hres, vres);
+	return get_best_mode(viafb_modes, ARRAY_SIZE(viafb_modes),
+		hres, vres, refresh);
 }
 
-struct crt_mode_table *viafb_get_best_mode(int hres, int vres, int refresh)
+const struct fb_videomode *viafb_get_best_rb_mode(int hres, int vres,
+	int refresh)
 {
-	return get_best_mode(viafb_get_mode(hres, vres), refresh);
-}
-
-static struct VideoModeTable *viafb_get_rb_mode(int hres, int vres)
-{
-	return get_modes(viafb_rb_modes, ARRAY_SIZE(viafb_rb_modes), hres,
-		vres);
-}
-
-struct crt_mode_table *viafb_get_best_rb_mode(int hres, int vres, int refresh)
-{
-	return get_best_mode(viafb_get_rb_mode(hres, vres), refresh);
+	return get_best_mode(viafb_rb_modes, ARRAY_SIZE(viafb_rb_modes),
+		hres, vres, refresh);
 }
diff --git a/drivers/video/via/viamode.h b/drivers/video/via/viamode.h
index 5917a2b..dd19106 100644
--- a/drivers/video/via/viamode.h
+++ b/drivers/video/via/viamode.h
@@ -31,11 +31,6 @@
 	unsigned char AR[StdAR];
 };
 
-struct VideoModeTable {
-	struct crt_mode_table *crtc;
-	int mode_array;
-};
-
 struct patch_table {
 	int table_length;
 	struct io_reg *io_reg_table;
@@ -60,7 +55,9 @@
 extern struct patch_table res_patch_table[];
 extern struct VPITTable VPIT;
 
-struct crt_mode_table *viafb_get_best_mode(int hres, int vres, int refresh);
-struct crt_mode_table *viafb_get_best_rb_mode(int hres, int vres, int refresh);
+const struct fb_videomode *viafb_get_best_mode(int hres, int vres,
+	int refresh);
+const struct fb_videomode *viafb_get_best_rb_mode(int hres, int vres,
+	int refresh);
 
 #endif /* __VIAMODE_H__ */
diff --git a/drivers/virtio/config.c b/drivers/virtio/config.c
index 983d482..f70bcd2 100644
--- a/drivers/virtio/config.c
+++ b/drivers/virtio/config.c
@@ -9,5 +9,4 @@
 #include <linux/virtio.h>
 #include <linux/virtio_config.h>
 #include <linux/bug.h>
-#include <asm/system.h>
 
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 958e512..05f0a80 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -398,21 +398,8 @@
 	return 0;
 }
 
-static int virtballoon_thaw(struct virtio_device *vdev)
-{
-	return restore_common(vdev);
-}
-
 static int virtballoon_restore(struct virtio_device *vdev)
 {
-	struct virtio_balloon *vb = vdev->priv;
-
-	/*
-	 * If a request wasn't complete at the time of freezing, this
-	 * could have been set.
-	 */
-	vb->need_stats_update = 0;
-
 	return restore_common(vdev);
 }
 #endif
@@ -434,7 +421,6 @@
 #ifdef CONFIG_PM
 	.freeze	=	virtballoon_freeze,
 	.restore =	virtballoon_restore,
-	.thaw =		virtballoon_thaw,
 #endif
 };
 
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
index 635e1ef..2e03d41 100644
--- a/drivers/virtio/virtio_pci.c
+++ b/drivers/virtio/virtio_pci.c
@@ -720,24 +720,6 @@
 }
 
 #ifdef CONFIG_PM
-static int virtio_pci_suspend(struct device *dev)
-{
-	struct pci_dev *pci_dev = to_pci_dev(dev);
-
-	pci_save_state(pci_dev);
-	pci_set_power_state(pci_dev, PCI_D3hot);
-	return 0;
-}
-
-static int virtio_pci_resume(struct device *dev)
-{
-	struct pci_dev *pci_dev = to_pci_dev(dev);
-
-	pci_restore_state(pci_dev);
-	pci_set_power_state(pci_dev, PCI_D0);
-	return 0;
-}
-
 static int virtio_pci_freeze(struct device *dev)
 {
 	struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -758,47 +740,6 @@
 	return ret;
 }
 
-static int restore_common(struct device *dev)
-{
-	struct pci_dev *pci_dev = to_pci_dev(dev);
-	struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
-	int ret;
-
-	ret = pci_enable_device(pci_dev);
-	if (ret)
-		return ret;
-	pci_set_master(pci_dev);
-	vp_finalize_features(&vp_dev->vdev);
-
-	return ret;
-}
-
-static int virtio_pci_thaw(struct device *dev)
-{
-	struct pci_dev *pci_dev = to_pci_dev(dev);
-	struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
-	struct virtio_driver *drv;
-	int ret;
-
-	ret = restore_common(dev);
-	if (ret)
-		return ret;
-
-	drv = container_of(vp_dev->vdev.dev.driver,
-			   struct virtio_driver, driver);
-
-	if (drv && drv->thaw)
-		ret = drv->thaw(&vp_dev->vdev);
-	else if (drv && drv->restore)
-		ret = drv->restore(&vp_dev->vdev);
-
-	/* Finally, tell the device we're all set */
-	if (!ret)
-		vp_set_status(&vp_dev->vdev, vp_dev->saved_status);
-
-	return ret;
-}
-
 static int virtio_pci_restore(struct device *dev)
 {
 	struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -809,8 +750,14 @@
 	drv = container_of(vp_dev->vdev.dev.driver,
 			   struct virtio_driver, driver);
 
-	ret = restore_common(dev);
-	if (!ret && drv && drv->restore)
+	ret = pci_enable_device(pci_dev);
+	if (ret)
+		return ret;
+
+	pci_set_master(pci_dev);
+	vp_finalize_features(&vp_dev->vdev);
+
+	if (drv && drv->restore)
 		ret = drv->restore(&vp_dev->vdev);
 
 	/* Finally, tell the device we're all set */
@@ -821,12 +768,7 @@
 }
 
 static const struct dev_pm_ops virtio_pci_pm_ops = {
-	.suspend	= virtio_pci_suspend,
-	.resume		= virtio_pci_resume,
-	.freeze		= virtio_pci_freeze,
-	.thaw		= virtio_pci_thaw,
-	.restore	= virtio_pci_restore,
-	.poweroff	= virtio_pci_suspend,
+	SET_SYSTEM_SLEEP_PM_OPS(virtio_pci_freeze, virtio_pci_restore)
 };
 #endif
 
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index df9e8f0..3709624 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -55,6 +55,7 @@
 
 config SOFT_WATCHDOG
 	tristate "Software watchdog"
+	select WATCHDOG_CORE
 	help
 	  A software monitoring watchdog. This will fail to reboot your system
 	  from some situations that the hardware watchdog will recover
@@ -74,6 +75,7 @@
 config WM8350_WATCHDOG
 	tristate "WM8350 watchdog"
 	depends on MFD_WM8350
+	select WATCHDOG_CORE
 	help
 	  Support for the watchdog in the WM8350 AudioPlus PMIC.  When
 	  the watchdog triggers the system will be reset.
@@ -170,7 +172,7 @@
 
 config S3C2410_WATCHDOG
 	tristate "S3C2410 Watchdog"
-	depends on ARCH_S3C2410 || HAVE_S3C2410_WATCHDOG
+	depends on HAVE_S3C2410_WATCHDOG
 	select WATCHDOG_CORE
 	help
 	  Watchdog timer block in the Samsung SoCs. This will reboot
@@ -217,6 +219,7 @@
 config EP93XX_WATCHDOG
 	tristate "EP93xx Watchdog"
 	depends on ARCH_EP93XX
+	select WATCHDOG_CORE
 	help
 	  Say Y here if to include support for the watchdog timer
 	  embedded in the Cirrus Logic EP93xx family of devices.
@@ -234,6 +237,7 @@
 config PNX4008_WATCHDOG
 	tristate "PNX4008 and LPC32XX Watchdog"
 	depends on ARCH_PNX4008 || ARCH_LPC32XX
+	select WATCHDOG_CORE
 	help
 	  Say Y here if to include support for the watchdog timer
 	  in the PNX4008 or LPC32XX processor.
@@ -283,6 +287,7 @@
 	bool "ST-Ericsson COH 901 327 watchdog"
 	depends on ARCH_U300
 	default y if MACH_U300
+	select WATCHDOG_CORE
 	help
 	  Say Y here to include Watchdog timer support for the
 	  watchdog embedded into the ST-Ericsson U300 series platforms.
@@ -328,6 +333,7 @@
 config MAX63XX_WATCHDOG
 	tristate "Max63xx watchdog"
 	depends on ARM && HAS_IOMEM
+	select WATCHDOG_CORE
 	help
 	  Support for memory mapped max63{69,70,71,72,73,74} watchdog timer.
 
@@ -955,6 +961,7 @@
 config JZ4740_WDT
 	tristate "Ingenic jz4740 SoC hardware watchdog"
 	depends on MACH_JZ4740
+	select WATCHDOG_CORE
 	help
 	  Hardware driver for the built-in watchdog timer on Ingenic jz4740 SoCs.
 
@@ -996,6 +1003,7 @@
 config TXX9_WDT
 	tristate "Toshiba TXx9 Watchdog Timer"
 	depends on CPU_TX39XX || CPU_TX49XX
+	select WATCHDOG_CORE
 	help
 	  Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
 
@@ -1039,7 +1047,7 @@
 
 config GEF_WDT
 	tristate "GE Watchdog Timer"
-	depends on GEF_SBC610 || GEF_SBC310 || GEF_PPC9A
+	depends on GE_FPGA
 	---help---
 	  Watchdog timer found in a number of GE single board computers.
 
diff --git a/drivers/watchdog/acquirewdt.c b/drivers/watchdog/acquirewdt.c
index b6a2b58..4397881 100644
--- a/drivers/watchdog/acquirewdt.c
+++ b/drivers/watchdog/acquirewdt.c
@@ -52,6 +52,8 @@
  *	Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 /* Includes */
 #include <linux/module.h>		/* For module specific items */
 #include <linux/moduleparam.h>		/* For new moduleparam's */
@@ -70,7 +72,6 @@
 
 /* Module information */
 #define DRV_NAME "acquirewdt"
-#define PFX DRV_NAME ": "
 #define WATCHDOG_NAME "Acquire WDT"
 /* There is no way to see what the correct time-out period is */
 #define WATCHDOG_HEARTBEAT 0
@@ -92,8 +93,8 @@
 module_param(wdt_start, int, 0);
 MODULE_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 	__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -208,8 +209,7 @@
 	if (expect_close == 42) {
 		acq_stop();
 	} else {
-		printk(KERN_CRIT PFX
-			"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		acq_keepalive();
 	}
 	clear_bit(0, &acq_is_open);
@@ -246,27 +246,24 @@
 
 	if (wdt_stop != wdt_start) {
 		if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
-			printk(KERN_ERR PFX
-			    "I/O address 0x%04x already in use\n", wdt_stop);
+			pr_err("I/O address 0x%04x already in use\n", wdt_stop);
 			ret = -EIO;
 			goto out;
 		}
 	}
 
 	if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
-		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-			wdt_start);
+		pr_err("I/O address 0x%04x already in use\n", wdt_start);
 		ret = -EIO;
 		goto unreg_stop;
 	}
 	ret = misc_register(&acq_miscdev);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-							WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto unreg_regions;
 	}
-	printk(KERN_INFO PFX "initialized. (nowayout=%d)\n", nowayout);
+	pr_info("initialized. (nowayout=%d)\n", nowayout);
 
 	return 0;
 unreg_regions:
@@ -308,8 +305,7 @@
 {
 	int err;
 
-	printk(KERN_INFO
-	      "WDT driver for Acquire single board computer initialising.\n");
+	pr_info("WDT driver for Acquire single board computer initialising\n");
 
 	err = platform_driver_register(&acquirewdt_driver);
 	if (err)
@@ -332,7 +328,7 @@
 {
 	platform_device_unregister(acq_platform_device);
 	platform_driver_unregister(&acquirewdt_driver);
-	printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+	pr_info("Watchdog Module Unloaded\n");
 }
 
 module_init(acq_init);
diff --git a/drivers/watchdog/advantechwdt.c b/drivers/watchdog/advantechwdt.c
index 4d40965..64ae9e9 100644
--- a/drivers/watchdog/advantechwdt.c
+++ b/drivers/watchdog/advantechwdt.c
@@ -28,6 +28,8 @@
  *	    add wdt_start and wdt_stop as parameters.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -40,10 +42,8 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 
 #define DRV_NAME "advantechwdt"
-#define PFX DRV_NAME ": "
 #define WATCHDOG_NAME "Advantech WDT"
 #define WATCHDOG_TIMEOUT 60		/* 60 sec default timeout */
 
@@ -77,8 +77,8 @@
 	"Watchdog timeout in seconds. 1<= timeout <=63, default="
 		__MODULE_STRING(WATCHDOG_TIMEOUT) ".");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 		__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -207,8 +207,7 @@
 	if (adv_expect_close == 42) {
 		advwdt_disable();
 	} else {
-		printk(KERN_CRIT PFX
-				"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		advwdt_ping();
 	}
 	clear_bit(0, &advwdt_is_open);
@@ -245,18 +244,15 @@
 
 	if (wdt_stop != wdt_start) {
 		if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
-			printk(KERN_ERR PFX
-				"I/O address 0x%04x already in use\n",
-								wdt_stop);
+			pr_err("I/O address 0x%04x already in use\n",
+			       wdt_stop);
 			ret = -EIO;
 			goto out;
 		}
 	}
 
 	if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
-		printk(KERN_ERR PFX
-				"I/O address 0x%04x already in use\n",
-								wdt_start);
+		pr_err("I/O address 0x%04x already in use\n", wdt_start);
 		ret = -EIO;
 		goto unreg_stop;
 	}
@@ -265,18 +261,16 @@
 	 * if not reset to the default */
 	if (advwdt_set_heartbeat(timeout)) {
 		advwdt_set_heartbeat(WATCHDOG_TIMEOUT);
-		printk(KERN_INFO PFX
-			"timeout value must be 1<=x<=63, using %d\n", timeout);
+		pr_info("timeout value must be 1<=x<=63, using %d\n", timeout);
 	}
 
 	ret = misc_register(&advwdt_miscdev);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-							WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto unreg_regions;
 	}
-	printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+	pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
 		timeout, nowayout);
 out:
 	return ret;
@@ -318,8 +312,7 @@
 {
 	int err;
 
-	printk(KERN_INFO
-	     "WDT driver for Advantech single board computer initialising.\n");
+	pr_info("WDT driver for Advantech single board computer initialising\n");
 
 	err = platform_driver_register(&advwdt_driver);
 	if (err)
@@ -343,7 +336,7 @@
 {
 	platform_device_unregister(advwdt_platform_device);
 	platform_driver_unregister(&advwdt_driver);
-	printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+	pr_info("Watchdog Module Unloaded\n");
 }
 
 module_init(advwdt_init);
diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c
index f16dcbd..41b8493 100644
--- a/drivers/watchdog/alim1535_wdt.c
+++ b/drivers/watchdog/alim1535_wdt.c
@@ -7,6 +7,8 @@
  *	2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -22,7 +24,6 @@
 #include <linux/io.h>
 
 #define WATCHDOG_NAME "ALi_M1535"
-#define PFX WATCHDOG_NAME ": "
 #define WATCHDOG_TIMEOUT 60	/* 60 sec default timeout */
 
 /* internal variables */
@@ -39,8 +40,8 @@
 		"Watchdog timeout in seconds. (0 < timeout < 18000, default="
 				__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -268,8 +269,7 @@
 	if (ali_expect_release == 42)
 		ali_stop();
 	else {
-		printk(KERN_CRIT PFX
-				"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		ali_keepalive();
 	}
 	clear_bit(0, &ali_is_open);
@@ -399,9 +399,8 @@
 	   if not reset to the default */
 	if (timeout < 1 || timeout >= 18000) {
 		timeout = WATCHDOG_TIMEOUT;
-		printk(KERN_INFO PFX
-		     "timeout value must be 0 < timeout < 18000, using %d\n",
-							timeout);
+		pr_info("timeout value must be 0 < timeout < 18000, using %d\n",
+			timeout);
 	}
 
 	/* Calculate the watchdog's timeout */
@@ -409,20 +408,18 @@
 
 	ret = register_reboot_notifier(&ali_notifier);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", ret);
+		pr_err("cannot register reboot notifier (err=%d)\n", ret);
 		goto out;
 	}
 
 	ret = misc_register(&ali_miscdev);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-						WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto unreg_reboot;
 	}
 
-	printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+	pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
 		timeout, nowayout);
 
 out:
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c
index 46f4b85..5eee550 100644
--- a/drivers/watchdog/alim7101_wdt.c
+++ b/drivers/watchdog/alim7101_wdt.c
@@ -19,6 +19,8 @@
  *                  -- Mike Waychison <michael.waychison@sun.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -34,10 +36,6 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
-
-#define OUR_NAME "alim7101_wdt"
-#define PFX OUR_NAME ": "
 
 #define WDT_ENABLE 0x9C
 #define WDT_DISABLE 0x8C
@@ -79,8 +77,8 @@
 static char wdt_expect_close;
 static struct pci_dev *alim7101_pmu;
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -112,8 +110,7 @@
 					ALI_7101_GPIO_O, tmp & ~0x20);
 		}
 	} else {
-		printk(KERN_WARNING PFX
-			"Heartbeat lost! Will not ping the watchdog\n");
+		pr_warn("Heartbeat lost! Will not ping the watchdog\n");
 	}
 	/* Re-set the timer interval */
 	mod_timer(&timer, jiffies + WDT_INTERVAL);
@@ -162,7 +159,7 @@
 	/* Start the timer */
 	mod_timer(&timer, jiffies + WDT_INTERVAL);
 
-	printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+	pr_info("Watchdog timer is now enabled\n");
 }
 
 static void wdt_turnoff(void)
@@ -170,7 +167,7 @@
 	/* Stop the timer */
 	del_timer_sync(&timer);
 	wdt_change(WDT_DISABLE);
-	printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+	pr_info("Watchdog timer is now disabled...\n");
 }
 
 static void wdt_keepalive(void)
@@ -226,8 +223,7 @@
 		wdt_turnoff();
 	else {
 		/* wim: shouldn't there be a: del_timer(&timer); */
-		printk(KERN_CRIT PFX
-		  "device file closed unexpectedly. Will not stop the WDT!\n");
+		pr_crit("device file closed unexpectedly. Will not stop the WDT!\n");
 	}
 	clear_bit(0, &wdt_is_open);
 	wdt_expect_close = 0;
@@ -322,8 +318,7 @@
 		 * watchdog on reboot with no heartbeat
 		 */
 		wdt_change(WDT_ENABLE);
-		printk(KERN_INFO PFX "Watchdog timer is now enabled "
-			"with no heartbeat - should reboot in ~1 second.\n");
+		pr_info("Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second\n");
 	}
 	return NOTIFY_DONE;
 }
@@ -352,12 +347,11 @@
 	struct pci_dev *ali1543_south;
 	char tmp;
 
-	printk(KERN_INFO PFX "Steve Hill <steve@navaho.co.uk>.\n");
+	pr_info("Steve Hill <steve@navaho.co.uk>\n");
 	alim7101_pmu = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
 		NULL);
 	if (!alim7101_pmu) {
-		printk(KERN_INFO PFX
-			"ALi M7101 PMU not present - WDT not set\n");
+		pr_info("ALi M7101 PMU not present - WDT not set\n");
 		return -EBUSY;
 	}
 
@@ -367,56 +361,46 @@
 	ali1543_south = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
 		NULL);
 	if (!ali1543_south) {
-		printk(KERN_INFO PFX
-			"ALi 1543 South-Bridge not present - WDT not set\n");
+		pr_info("ALi 1543 South-Bridge not present - WDT not set\n");
 		goto err_out;
 	}
 	pci_read_config_byte(ali1543_south, 0x5e, &tmp);
 	pci_dev_put(ali1543_south);
 	if ((tmp & 0x1e) == 0x00) {
 		if (!use_gpio) {
-			printk(KERN_INFO PFX
-				"Detected old alim7101 revision 'a1d'.  "
-				"If this is a cobalt board, set the 'use_gpio' "
-				"module parameter.\n");
+			pr_info("Detected old alim7101 revision 'a1d'.  If this is a cobalt board, set the 'use_gpio' module parameter.\n");
 			goto err_out;
 		}
 		nowayout = 1;
 	} else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) {
-		printk(KERN_INFO PFX
-			"ALi 1543 South-Bridge does not have the correct "
-			"revision number (???1001?) - WDT not set\n");
+		pr_info("ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n");
 		goto err_out;
 	}
 
 	if (timeout < 1 || timeout > 3600) {
 		/* arbitrary upper limit */
 		timeout = WATCHDOG_TIMEOUT;
-		printk(KERN_INFO PFX
-			"timeout value must be 1 <= x <= 3600, using %d\n",
-								timeout);
+		pr_info("timeout value must be 1 <= x <= 3600, using %d\n",
+			timeout);
 	}
 
 	rc = register_reboot_notifier(&wdt_notifier);
 	if (rc) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", rc);
+		pr_err("cannot register reboot notifier (err=%d)\n", rc);
 		goto err_out;
 	}
 
 	rc = misc_register(&wdt_miscdev);
 	if (rc) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-			wdt_miscdev.minor, rc);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       wdt_miscdev.minor, rc);
 		goto err_out_reboot;
 	}
 
 	if (nowayout)
 		__module_get(THIS_MODULE);
 
-	printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. "
-					"timeout=%d sec (nowayout=%d)\n",
+	pr_info("WDT driver for ALi M7101 initialised. timeout=%d sec (nowayout=%d)\n",
 		timeout, nowayout);
 	return 0;
 
diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c
index 502773a..639ae9a 100644
--- a/drivers/watchdog/ar7_wdt.c
+++ b/drivers/watchdog/ar7_wdt.c
@@ -23,6 +23,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/errno.h>
@@ -39,7 +41,6 @@
 #include <asm/addrspace.h>
 #include <asm/mach-ar7/ar7.h>
 
-#define DRVNAME "ar7_wdt"
 #define LONGNAME "TI AR7 Watchdog Timer"
 
 MODULE_AUTHOR("Nicolas Thill <nico@openwrt.org>");
@@ -51,8 +52,8 @@
 module_param(margin, int, 0);
 MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
 
 #define READ_REG(x) readl((void __iomem *)&(x))
@@ -93,7 +94,7 @@
 			return;
 		}
 	}
-	printk(KERN_ERR DRVNAME ": failed to unlock WDT kick reg\n");
+	pr_err("failed to unlock WDT kick reg\n");
 }
 
 static void ar7_wdt_prescale(u32 value)
@@ -106,7 +107,7 @@
 			return;
 		}
 	}
-	printk(KERN_ERR DRVNAME ": failed to unlock WDT prescale reg\n");
+	pr_err("failed to unlock WDT prescale reg\n");
 }
 
 static void ar7_wdt_change(u32 value)
@@ -119,7 +120,7 @@
 			return;
 		}
 	}
-	printk(KERN_ERR DRVNAME ": failed to unlock WDT change reg\n");
+	pr_err("failed to unlock WDT change reg\n");
 }
 
 static void ar7_wdt_disable(u32 value)
@@ -135,7 +136,7 @@
 			}
 		}
 	}
-	printk(KERN_ERR DRVNAME ": failed to unlock WDT disable reg\n");
+	pr_err("failed to unlock WDT disable reg\n");
 }
 
 static void ar7_wdt_update_margin(int new_margin)
@@ -151,21 +152,20 @@
 		change = 0xffff;
 	ar7_wdt_change(change);
 	margin = change * prescale_value / vbus_rate;
-	printk(KERN_INFO DRVNAME
-	       ": timer margin %d seconds (prescale %d, change %d, freq %d)\n",
-	       margin, prescale_value, change, vbus_rate);
+	pr_info("timer margin %d seconds (prescale %d, change %d, freq %d)\n",
+		margin, prescale_value, change, vbus_rate);
 }
 
 static void ar7_wdt_enable_wdt(void)
 {
-	printk(KERN_DEBUG DRVNAME ": enabling watchdog timer\n");
+	pr_debug("enabling watchdog timer\n");
 	ar7_wdt_disable(1);
 	ar7_wdt_kick(1);
 }
 
 static void ar7_wdt_disable_wdt(void)
 {
-	printk(KERN_DEBUG DRVNAME ": disabling watchdog timer\n");
+	pr_debug("disabling watchdog timer\n");
 	ar7_wdt_disable(0);
 }
 
@@ -183,9 +183,7 @@
 static int ar7_wdt_release(struct inode *inode, struct file *file)
 {
 	if (!expect_close)
-		printk(KERN_WARNING DRVNAME
-		": watchdog device closed unexpectedly,"
-		"will not disable the watchdog timer\n");
+		pr_warn("watchdog device closed unexpectedly, will not disable the watchdog timer\n");
 	else if (!nowayout)
 		ar7_wdt_disable_wdt();
 	clear_bit(0, &wdt_is_open);
@@ -283,28 +281,28 @@
 	ar7_regs_wdt =
 		platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
 	if (!ar7_regs_wdt) {
-		printk(KERN_ERR DRVNAME ": could not get registers resource\n");
+		pr_err("could not get registers resource\n");
 		rc = -ENODEV;
 		goto out;
 	}
 
 	if (!request_mem_region(ar7_regs_wdt->start,
 				resource_size(ar7_regs_wdt), LONGNAME)) {
-		printk(KERN_WARNING DRVNAME ": watchdog I/O region busy\n");
+		pr_warn("watchdog I/O region busy\n");
 		rc = -EBUSY;
 		goto out;
 	}
 
 	ar7_wdt = ioremap(ar7_regs_wdt->start, resource_size(ar7_regs_wdt));
 	if (!ar7_wdt) {
-		printk(KERN_ERR DRVNAME ": could not ioremap registers\n");
+		pr_err("could not ioremap registers\n");
 		rc = -ENXIO;
 		goto out_mem_region;
 	}
 
 	vbus_clk = clk_get(NULL, "vbus");
 	if (IS_ERR(vbus_clk)) {
-		printk(KERN_ERR DRVNAME ": could not get vbus clock\n");
+		pr_err("could not get vbus clock\n");
 		rc = PTR_ERR(vbus_clk);
 		goto out_mem_region;
 	}
@@ -315,7 +313,7 @@
 
 	rc = misc_register(&ar7_wdt_miscdev);
 	if (rc) {
-		printk(KERN_ERR DRVNAME ": unable to register misc device\n");
+		pr_err("unable to register misc device\n");
 		goto out_alloc;
 	}
 	goto out;
diff --git a/drivers/watchdog/at32ap700x_wdt.c b/drivers/watchdog/at32ap700x_wdt.c
index 4ca5d40..2896430 100644
--- a/drivers/watchdog/at32ap700x_wdt.c
+++ b/drivers/watchdog/at32ap700x_wdt.c
@@ -45,8 +45,8 @@
 		"Timeout value. Limited to be 1 or 2 seconds. (default="
 		__MODULE_STRING(TIMEOUT_DEFAULT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 		__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c
index b3046dc..7ef99a1 100644
--- a/drivers/watchdog/at91rm9200_wdt.c
+++ b/drivers/watchdog/at91rm9200_wdt.c
@@ -9,6 +9,8 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -28,14 +30,14 @@
 #define WDT_MAX_TIME		256	/* seconds */
 
 static int wdt_time = WDT_DEFAULT_TIME;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 module_param(wdt_time, int, 0);
 MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
 				__MODULE_STRING(WDT_DEFAULT_TIME) ")");
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -51,7 +53,7 @@
  */
 static inline void at91_wdt_stop(void)
 {
-	at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN);
+	at91_st_write(AT91_ST_WDMR, AT91_ST_EXTEN);
 }
 
 /*
@@ -59,9 +61,9 @@
  */
 static inline void at91_wdt_start(void)
 {
-	at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN |
+	at91_st_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN |
 				(((65536 * wdt_time) >> 8) & AT91_ST_WDV));
-	at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
+	at91_st_write(AT91_ST_CR, AT91_ST_WDRST);
 }
 
 /*
@@ -69,7 +71,7 @@
  */
 static inline void at91_wdt_reload(void)
 {
-	at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
+	at91_st_write(AT91_ST_CR, AT91_ST_WDRST);
 }
 
 /* ......................................................................... */
@@ -209,8 +211,8 @@
 	if (res)
 		return res;
 
-	printk(KERN_INFO "AT91 Watchdog Timer enabled (%d seconds%s)\n",
-				wdt_time, nowayout ? ", nowayout" : "");
+	pr_info("AT91 Watchdog Timer enabled (%d seconds%s)\n",
+		wdt_time, nowayout ? ", nowayout" : "");
 	return 0;
 }
 
@@ -268,8 +270,8 @@
 	   if not reset to the default */
 	if (at91_wdt_settimeout(wdt_time)) {
 		at91_wdt_settimeout(WDT_DEFAULT_TIME);
-		pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256"
-						", using %d\n", wdt_time);
+		pr_info("wdt_time value must be 1 <= wdt_time <= 256, using %d\n",
+			wdt_time);
 	}
 
 	return platform_driver_register(&at91wdt_driver);
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 0056256..05e1be8 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -15,6 +15,8 @@
  * bootloader doesn't write to this register.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/init.h>
@@ -60,8 +62,8 @@
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
 	"(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
 	"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -96,7 +98,7 @@
 		at91_wdt_reset();
 		mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
 	} else
-		printk(KERN_CRIT DRV_NAME": I will reset your machine !\n");
+		pr_crit("I will reset your machine !\n");
 }
 
 /*
@@ -140,7 +142,7 @@
 	/* Check if disabled */
 	mr = wdt_read(AT91_WDT_MR);
 	if (mr & AT91_WDT_WDDIS) {
-		printk(KERN_ERR DRV_NAME": sorry, watchdog is disabled\n");
+		pr_err("sorry, watchdog is disabled\n");
 		return -EIO;
 	}
 
@@ -283,7 +285,7 @@
 	setup_timer(&at91wdt_private.timer, at91_ping, 0);
 	mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
 
-	printk(KERN_INFO DRV_NAME " enabled (heartbeat=%d sec, nowayout=%d)\n",
+	pr_info("enabled (heartbeat=%d sec, nowayout=%d)\n",
 		heartbeat, nowayout);
 
 	return 0;
diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c
index 9db8083..1f9371f 100644
--- a/drivers/watchdog/ath79_wdt.c
+++ b/drivers/watchdog/ath79_wdt.c
@@ -17,6 +17,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -45,8 +47,8 @@
 #define WDOG_CTRL_ACTION_NMI	2	/* NMI */
 #define WDOG_CTRL_ACTION_FCR	3	/* full chip reset */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
 			   "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -114,8 +116,7 @@
 	if (test_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags))
 		ath79_wdt_disable();
 	else {
-		pr_crit(DRIVER_NAME ": device closed unexpectedly, "
-			"watchdog timer will not stop!\n");
+		pr_crit("device closed unexpectedly, watchdog timer will not stop!\n");
 		ath79_wdt_keepalive();
 	}
 
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index 5c5f4b1..bc0e91e 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -10,6 +10,8 @@
  *  2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -33,14 +35,14 @@
 #define WDT_MAX_TIME		255	/* seconds */
 
 static int wdt_time = WDT_DEFAULT_TIME;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 module_param(wdt_time, int, 0);
 MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
 				__MODULE_STRING(WDT_DEFAULT_TIME) ")");
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -91,7 +93,7 @@
 		bcm47xx_wdt_hw_start();
 		mod_timer(&wdt_timer, jiffies + HZ);
 	} else {
-		printk(KERN_CRIT DRV_NAME "Watchdog will fire soon!!!\n");
+		pr_crit("Watchdog will fire soon!!!\n");
 	}
 }
 
@@ -140,8 +142,7 @@
 	if (expect_release == 42) {
 		bcm47xx_wdt_stop();
 	} else {
-		printk(KERN_CRIT DRV_NAME
-			": Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		bcm47xx_wdt_start();
 	}
 
@@ -270,8 +271,7 @@
 
 	if (bcm47xx_wdt_settimeout(wdt_time)) {
 		bcm47xx_wdt_settimeout(WDT_DEFAULT_TIME);
-		printk(KERN_INFO DRV_NAME ": "
-			"wdt_time value must be 0 < wdt_time < %d, using %d\n",
+		pr_info("wdt_time value must be 0 < wdt_time < %d, using %d\n",
 			(WDT_MAX_TIME + 1), wdt_time);
 	}
 
@@ -285,8 +285,8 @@
 		return ret;
 	}
 
-	printk(KERN_INFO "BCM47xx Watchdog Timer enabled (%d seconds%s)\n",
-				wdt_time, nowayout ? ", nowayout" : "");
+	pr_info("BCM47xx Watchdog Timer enabled (%d seconds%s)\n",
+		wdt_time, nowayout ? ", nowayout" : "");
 	return 0;
 }
 
diff --git a/drivers/watchdog/bcm63xx_wdt.c b/drivers/watchdog/bcm63xx_wdt.c
index 8dc7de6..8379dc3 100644
--- a/drivers/watchdog/bcm63xx_wdt.c
+++ b/drivers/watchdog/bcm63xx_wdt.c
@@ -10,6 +10,8 @@
  *  2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -50,8 +52,8 @@
 static int expect_close;
 
 static int wdt_time = WDT_DEFAULT_TIME;
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 	__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -82,7 +84,7 @@
 		bcm63xx_wdt_hw_start();
 		mod_timer(&bcm63xx_wdt_device.timer, jiffies + HZ);
 	} else
-		printk(KERN_CRIT PFX ": watchdog will restart system\n");
+		pr_crit("watchdog will restart system\n");
 }
 
 static void bcm63xx_wdt_pet(void)
@@ -126,8 +128,7 @@
 	if (expect_close == 42)
 		bcm63xx_wdt_pause();
 	else {
-		printk(KERN_CRIT PFX
-			": Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		bcm63xx_wdt_start();
 	}
 	clear_bit(0, &bcm63xx_wdt_device.inuse);
diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c
index b9fa9b7..38bc383 100644
--- a/drivers/watchdog/bfin_wdt.c
+++ b/drivers/watchdog/bfin_wdt.c
@@ -11,6 +11,8 @@
  * Licensed under the GPL-2 or later.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -28,15 +30,8 @@
 #define stamp(fmt, args...) \
 	pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
 #define stampit() stamp("here i am")
-#define pr_devinit(fmt, args...) \
-	({ static const __devinitconst char __fmt[] = fmt; \
-	printk(__fmt, ## args); })
-#define pr_init(fmt, args...) \
-	({ static const __initconst char __fmt[] = fmt; \
-	printk(__fmt, ## args); })
 
 #define WATCHDOG_NAME "bfin-wdt"
-#define PFX WATCHDOG_NAME ": "
 
 /* The BF561 has two watchdogs (one per core), but since Linux
  * only runs on core A, we'll just work with that one.
@@ -54,7 +49,7 @@
 #define WATCHDOG_TIMEOUT 20
 
 static unsigned int timeout = WATCHDOG_TIMEOUT;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static const struct watchdog_info bfin_wdt_info;
 static unsigned long open_check;
 static char expect_close;
@@ -126,7 +121,7 @@
 	stamp("maxtimeout=%us newtimeout=%lus (cnt=%#x)", max_t, t, cnt);
 
 	if (t > max_t) {
-		printk(KERN_WARNING PFX "timeout value is too large\n");
+		pr_warn("timeout value is too large\n");
 		return -EINVAL;
 	}
 
@@ -182,8 +177,7 @@
 	if (expect_close == 42)
 		bfin_wdt_stop();
 	else {
-		printk(KERN_CRIT PFX
-			"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		bfin_wdt_keepalive();
 	}
 	expect_close = 0;
@@ -368,14 +362,13 @@
 
 	ret = misc_register(&bfin_wdt_miscdev);
 	if (ret) {
-		pr_devinit(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-				WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		return ret;
 	}
 
-	pr_devinit(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
-	       timeout, nowayout);
+	pr_info("initialized: timeout=%d sec (nowayout=%d)\n",
+		timeout, nowayout);
 
 	return 0;
 }
@@ -439,14 +432,14 @@
 	 */
 	ret = platform_driver_register(&bfin_wdt_driver);
 	if (ret) {
-		pr_init(KERN_ERR PFX "unable to register driver\n");
+		pr_err("unable to register driver\n");
 		return ret;
 	}
 
 	bfin_wdt_device = platform_device_register_simple(WATCHDOG_NAME,
 								-1, NULL, 0);
 	if (IS_ERR(bfin_wdt_device)) {
-		pr_init(KERN_ERR PFX "unable to register device\n");
+		pr_err("unable to register device\n");
 		platform_driver_unregister(&bfin_wdt_driver);
 		return PTR_ERR(bfin_wdt_device);
 	}
@@ -479,7 +472,7 @@
 	"Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default="
 		__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 		__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index 7c0fdfc..ce0ab44 100644
--- a/drivers/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
@@ -12,6 +12,8 @@
  * option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/smp.h>
@@ -21,7 +23,6 @@
 #include <linux/uaccess.h>
 
 #include <asm/reg_booke.h>
-#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/div64.h>
 
@@ -225,8 +226,8 @@
 	if (booke_wdt_enabled == 0) {
 		booke_wdt_enabled = 1;
 		on_each_cpu(__booke_wdt_enable, NULL, 0);
-		pr_debug("booke_wdt: watchdog enabled (timeout = %llu sec)\n",
-			period_to_sec(booke_wdt_period));
+		pr_debug("watchdog enabled (timeout = %llu sec)\n",
+			 period_to_sec(booke_wdt_period));
 	}
 	spin_unlock(&booke_wdt_lock);
 
@@ -243,7 +244,7 @@
 	 */
 	on_each_cpu(__booke_wdt_disable, NULL, 0);
 	booke_wdt_enabled = 0;
-	pr_debug("booke_wdt: watchdog disabled\n");
+	pr_debug("watchdog disabled\n");
 #endif
 
 	clear_bit(0, &wdt_is_active);
@@ -275,19 +276,19 @@
 {
 	int ret = 0;
 
-	pr_info("booke_wdt: powerpc book-e watchdog driver loaded\n");
+	pr_info("powerpc book-e watchdog driver loaded\n");
 	ident.firmware_version = cur_cpu_spec->pvr_value;
 
 	ret = misc_register(&booke_wdt_miscdev);
 	if (ret) {
-		pr_err("booke_wdt: cannot register device (minor=%u, ret=%i)\n",
+		pr_err("cannot register device (minor=%u, ret=%i)\n",
 		       WATCHDOG_MINOR, ret);
 		return ret;
 	}
 
 	spin_lock(&booke_wdt_lock);
 	if (booke_wdt_enabled == 1) {
-		pr_info("booke_wdt: watchdog enabled (timeout = %llu sec)\n",
+		pr_info("watchdog enabled (timeout = %llu sec)\n",
 			period_to_sec(booke_wdt_period));
 		on_each_cpu(__booke_wdt_enable, NULL, 0);
 	}
diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c
index 5b89f7d..6876430 100644
--- a/drivers/watchdog/coh901327_wdt.c
+++ b/drivers/watchdog/coh901327_wdt.c
@@ -8,17 +8,15 @@
  */
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/interrupt.h>
 #include <linux/pm.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/bitops.h>
-#include <linux/uaccess.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/err.h>
 
 #define DRV_NAME "WDOG COH 901 327"
 
@@ -69,13 +67,11 @@
 #define U300_WDOG_IFR_WILL_BARK_IRQ_FORCE_ENABLE			0x0001U
 
 /* Default timeout in seconds = 1 minute */
-static int margin = 60;
+static unsigned int margin = 60;
 static resource_size_t phybase;
 static resource_size_t physize;
 static int irq;
 static void __iomem *virtbase;
-static unsigned long coh901327_users;
-static unsigned long boot_status;
 static struct device *parent;
 
 /*
@@ -155,34 +151,35 @@
 			__func__, val);
 }
 
-static void coh901327_start(void)
+static int coh901327_start(struct watchdog_device *wdt_dev)
 {
-	coh901327_enable(margin * 100);
+	coh901327_enable(wdt_dev->timeout * 100);
+	return 0;
 }
 
-static void coh901327_keepalive(void)
+static int coh901327_stop(struct watchdog_device *wdt_dev)
+{
+	coh901327_disable();
+	return 0;
+}
+
+static int coh901327_ping(struct watchdog_device *wdd)
 {
 	clk_enable(clk);
 	/* Feed the watchdog */
 	writew(U300_WDOG_FR_FEED_RESTART_TIMER,
 	       virtbase + U300_WDOG_FR);
 	clk_disable(clk);
+	return 0;
 }
 
-static int coh901327_settimeout(int time)
+static int coh901327_settimeout(struct watchdog_device *wdt_dev,
+				unsigned int time)
 {
-	/*
-	 * Max margin is 327 since the 10ms
-	 * timeout register is max
-	 * 0x7FFF = 327670ms ~= 327s.
-	 */
-	if (time <= 0 || time > 327)
-		return -EINVAL;
-
-	margin = time;
+	wdt_dev->timeout = time;
 	clk_enable(clk);
 	/* Set new timeout value */
-	writew(margin * 100, virtbase + U300_WDOG_TR);
+	writew(time * 100, virtbase + U300_WDOG_TR);
 	/* Feed the dog */
 	writew(U300_WDOG_FR_FEED_RESTART_TIMER,
 	       virtbase + U300_WDOG_FR);
@@ -190,6 +187,23 @@
 	return 0;
 }
 
+static unsigned int coh901327_gettimeleft(struct watchdog_device *wdt_dev)
+{
+	u16 val;
+
+	clk_enable(clk);
+	/* Read repeatedly until the value is stable! */
+	val = readw(virtbase + U300_WDOG_CR);
+	while (val & U300_WDOG_CR_VALID_IND)
+		val = readw(virtbase + U300_WDOG_CR);
+	val &= U300_WDOG_CR_COUNT_VALUE_MASK;
+	clk_disable(clk);
+	if (val != 0)
+		val /= 100;
+
+	return val;
+}
+
 /*
  * This interrupt occurs 10 ms before the watchdog WILL bark.
  */
@@ -218,130 +232,35 @@
 	return IRQ_HANDLED;
 }
 
-/*
- * Allow only one user (daemon) to open the watchdog
- */
-static int coh901327_open(struct inode *inode, struct file *file)
-{
-	if (test_and_set_bit(1, &coh901327_users))
-		return -EBUSY;
-	coh901327_start();
-	return nonseekable_open(inode, file);
-}
-
-static int coh901327_release(struct inode *inode, struct file *file)
-{
-	clear_bit(1, &coh901327_users);
-	coh901327_disable();
-	return 0;
-}
-
-static ssize_t coh901327_write(struct file *file, const char __user *data,
-			       size_t len, loff_t *ppos)
-{
-	if (len)
-		coh901327_keepalive();
-	return len;
-}
-
-static long coh901327_ioctl(struct file *file, unsigned int cmd,
-			    unsigned long arg)
-{
-	int ret = -ENOTTY;
-	u16 val;
-	int time;
-	int new_options;
-	union {
-		struct watchdog_info __user *ident;
-		int __user *i;
-	} uarg;
-	static const struct watchdog_info ident = {
-		.options		= WDIOF_CARDRESET |
-					  WDIOF_SETTIMEOUT |
-					  WDIOF_KEEPALIVEPING,
-		.identity		= "COH 901 327 Watchdog",
-		.firmware_version	= 1,
-	};
-	uarg.i = (int __user *)arg;
-
-	switch (cmd) {
-	case WDIOC_GETSUPPORT:
-		ret = copy_to_user(uarg.ident, &ident,
-				   sizeof(ident)) ? -EFAULT : 0;
-		break;
-
-	case WDIOC_GETSTATUS:
-		ret = put_user(0, uarg.i);
-		break;
-
-	case WDIOC_GETBOOTSTATUS:
-		ret = put_user(boot_status, uarg.i);
-		break;
-
-	case WDIOC_SETOPTIONS:
-		ret = get_user(new_options, uarg.i);
-		if (ret)
-			break;
-		if (new_options & WDIOS_DISABLECARD)
-			coh901327_disable();
-		if (new_options & WDIOS_ENABLECARD)
-			coh901327_start();
-		ret = 0;
-		break;
-
-	case WDIOC_KEEPALIVE:
-		coh901327_keepalive();
-		ret = 0;
-		break;
-
-	case WDIOC_SETTIMEOUT:
-		ret = get_user(time, uarg.i);
-		if (ret)
-			break;
-
-		ret = coh901327_settimeout(time);
-		if (ret)
-			break;
-		/* Then fall through to return set value */
-
-	case WDIOC_GETTIMEOUT:
-		ret = put_user(margin, uarg.i);
-		break;
-
-	case WDIOC_GETTIMELEFT:
-		clk_enable(clk);
-		/* Read repeatedly until the value is stable! */
-		val = readw(virtbase + U300_WDOG_CR);
-		while (val & U300_WDOG_CR_VALID_IND)
-			val = readw(virtbase + U300_WDOG_CR);
-		val &= U300_WDOG_CR_COUNT_VALUE_MASK;
-		clk_disable(clk);
-		if (val != 0)
-			val /= 100;
-		ret = put_user(val, uarg.i);
-		break;
-	}
-	return ret;
-}
-
-static const struct file_operations coh901327_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.write		= coh901327_write,
-	.unlocked_ioctl	= coh901327_ioctl,
-	.open		= coh901327_open,
-	.release	= coh901327_release,
+static const struct watchdog_info coh901327_ident = {
+	.options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+	.identity = DRV_NAME,
 };
 
-static struct miscdevice coh901327_miscdev = {
-	.minor		= WATCHDOG_MINOR,
-	.name		= "watchdog",
-	.fops		= &coh901327_fops,
+static struct watchdog_ops coh901327_ops = {
+	.owner = THIS_MODULE,
+	.start = coh901327_start,
+	.stop = coh901327_stop,
+	.ping = coh901327_ping,
+	.set_timeout = coh901327_settimeout,
+	.get_timeleft = coh901327_gettimeleft,
+};
+
+static struct watchdog_device coh901327_wdt = {
+	.info = &coh901327_ident,
+	.ops = &coh901327_ops,
+	/*
+	 * Max timeout is 327 since the 10ms
+	 * timeout register is max
+	 * 0x7FFF = 327670ms ~= 327s.
+	 */
+	.min_timeout = 0,
+	.max_timeout = 327,
 };
 
 static int __exit coh901327_remove(struct platform_device *pdev)
 {
-	misc_deregister(&coh901327_miscdev);
+	watchdog_unregister_device(&coh901327_wdt);
 	coh901327_disable();
 	free_irq(irq, pdev);
 	clk_put(clk);
@@ -350,7 +269,6 @@
 	return 0;
 }
 
-
 static int __init coh901327_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -393,7 +311,7 @@
 	case U300_WDOG_SR_STATUS_TIMED_OUT:
 		dev_info(&pdev->dev,
 			"watchdog timed out since last chip reset!\n");
-		boot_status = WDIOF_CARDRESET;
+		coh901327_wdt.bootstatus |= WDIOF_CARDRESET;
 		/* Status will be cleared below */
 		break;
 	case U300_WDOG_SR_STATUS_NORMAL:
@@ -435,7 +353,11 @@
 
 	clk_disable(clk);
 
-	ret = misc_register(&coh901327_miscdev);
+	if (margin < 1 || margin > 327)
+		margin = 60;
+	coh901327_wdt.timeout = margin;
+
+	ret = watchdog_register_device(&coh901327_wdt);
 	if (ret == 0)
 		dev_info(&pdev->dev,
 			 "initialized. timer margin=%d sec\n", margin);
@@ -543,8 +465,8 @@
 MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
 MODULE_DESCRIPTION("COH 901 327 Watchdog");
 
-module_param(margin, int, 0);
+module_param(margin, uint, 0);
 MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
 
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:coh901327-watchdog");
diff --git a/drivers/watchdog/cpu5wdt.c b/drivers/watchdog/cpu5wdt.c
index 251c863..7e88839 100644
--- a/drivers/watchdog/cpu5wdt.c
+++ b/drivers/watchdog/cpu5wdt.c
@@ -19,6 +19,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -71,7 +73,7 @@
 static void cpu5wdt_trigger(unsigned long unused)
 {
 	if (verbose > 2)
-		printk(KERN_DEBUG PFX "trigger at %i ticks\n", ticks);
+		pr_debug("trigger at %i ticks\n", ticks);
 
 	if (cpu5wdt_device.running)
 		ticks--;
@@ -96,7 +98,7 @@
 	ticks = cpu5wdt_device.default_ticks;
 
 	if (verbose)
-		printk(KERN_DEBUG PFX "reset (%i ticks)\n", (int) ticks);
+		pr_debug("reset (%i ticks)\n", (int) ticks);
 
 }
 
@@ -129,7 +131,7 @@
 	ticks = cpu5wdt_device.default_ticks;
 	spin_unlock_irqrestore(&cpu5wdt_lock, flags);
 	if (verbose)
-		printk(KERN_CRIT PFX "stop not possible\n");
+		pr_crit("stop not possible\n");
 	return -EIO;
 }
 
@@ -219,8 +221,7 @@
 	int err;
 
 	if (verbose)
-		printk(KERN_DEBUG PFX
-				"port=0x%x, verbose=%i\n", port, verbose);
+		pr_debug("port=0x%x, verbose=%i\n", port, verbose);
 
 	init_completion(&cpu5wdt_device.stop);
 	cpu5wdt_device.queue = 0;
@@ -228,7 +229,7 @@
 	cpu5wdt_device.default_ticks = ticks;
 
 	if (!request_region(port, CPU5WDT_EXTENT, PFX)) {
-		printk(KERN_ERR PFX "request_region failed\n");
+		pr_err("request_region failed\n");
 		err = -EBUSY;
 		goto no_port;
 	}
@@ -237,16 +238,16 @@
 	val = inb(port + CPU5WDT_STATUS_REG);
 	val = (val >> 2) & 1;
 	if (!val)
-		printk(KERN_INFO PFX "sorry, was my fault\n");
+		pr_info("sorry, was my fault\n");
 
 	err = misc_register(&cpu5wdt_misc);
 	if (err < 0) {
-		printk(KERN_ERR PFX "misc_register failed\n");
+		pr_err("misc_register failed\n");
 		goto no_misc;
 	}
 
 
-	printk(KERN_INFO PFX "init success\n");
+	pr_info("init success\n");
 	return 0;
 
 no_misc:
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
index 1b793df..95b1b95 100644
--- a/drivers/watchdog/cpwd.c
+++ b/drivers/watchdog/cpwd.c
@@ -14,6 +14,8 @@
  * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/fs.h>
@@ -35,7 +37,6 @@
 #include <asm/watchdog.h>
 
 #define DRIVER_NAME	"cpwd"
-#define PFX		DRIVER_NAME ": "
 
 #define WD_OBPNAME	"watchdog"
 #define WD_BADMODEL	"SUNW,501-5336"
@@ -385,8 +386,7 @@
 	if (!p->initialized) {
 		if (request_irq(p->irq, &cpwd_interrupt,
 				IRQF_SHARED, DRIVER_NAME, p)) {
-			printk(KERN_ERR PFX "Cannot register IRQ %d\n",
-				p->irq);
+			pr_err("Cannot register IRQ %d\n", p->irq);
 			mutex_unlock(&cpwd_mutex);
 			return -EBUSY;
 		}
@@ -542,7 +542,7 @@
 	p = kzalloc(sizeof(*p), GFP_KERNEL);
 	err = -ENOMEM;
 	if (!p) {
-		printk(KERN_ERR PFX "Unable to allocate struct cpwd.\n");
+		pr_err("Unable to allocate struct cpwd\n");
 		goto out;
 	}
 
@@ -553,14 +553,14 @@
 	p->regs = of_ioremap(&op->resource[0], 0,
 			     4 * WD_TIMER_REGSZ, DRIVER_NAME);
 	if (!p->regs) {
-		printk(KERN_ERR PFX "Unable to map registers.\n");
+		pr_err("Unable to map registers\n");
 		goto out_free;
 	}
 
 	options = of_find_node_by_path("/options");
 	err = -ENODEV;
 	if (!options) {
-		printk(KERN_ERR PFX "Unable to find /options node.\n");
+		pr_err("Unable to find /options node\n");
 		goto out_iounmap;
 	}
 
@@ -605,8 +605,8 @@
 
 		err = misc_register(&p->devs[i].misc);
 		if (err) {
-			printk(KERN_ERR "Could not register misc device for "
-			       "dev %d\n", i);
+			pr_err("Could not register misc device for dev %d\n",
+			       i);
 			goto out_unregister;
 		}
 	}
@@ -617,8 +617,8 @@
 		cpwd_timer.data		= (unsigned long) p;
 		cpwd_timer.expires	= WD_BTIMEOUT;
 
-		printk(KERN_INFO PFX "PLD defect workaround enabled for "
-		       "model " WD_BADMODEL ".\n");
+		pr_info("PLD defect workaround enabled for model %s\n",
+			WD_BADMODEL);
 	}
 
 	dev_set_drvdata(&op->dev, p);
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index 63d7b58..06de121 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -16,7 +16,8 @@
  * If we receive an expected close for the watchdog then we keep the timer
  * running, otherwise the timer is stopped and the watchdog will expire.
  */
-#define pr_fmt(fmt) "dw_wdt: " fmt
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/bitops.h>
 #include <linux/clk.h>
@@ -45,8 +46,8 @@
 /* The maximum TOP (timeout period) value that can be set in the watchdog. */
 #define DW_WDT_MAX_TOP		15
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
 		 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
diff --git a/drivers/watchdog/ep93xx_wdt.c b/drivers/watchdog/ep93xx_wdt.c
index 726b7df..7705003 100644
--- a/drivers/watchdog/ep93xx_wdt.c
+++ b/drivers/watchdog/ep93xx_wdt.c
@@ -8,6 +8,9 @@
  * Authors: Ray Lehtiniemi <rayl@mail.com>,
  *	Alessandro Zummo <a.zummo@towertech.it>
  *
+ * Copyright (c) 2012 H Hartley Sweeten <hsweeten@visionengravers.com>
+ *	Convert to a platform device and use the watchdog framework API
+ *
  * 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.
@@ -23,232 +26,156 @@
  *	- Add a few missing ioctls
  */
 
+#include <linux/platform_device.h>
 #include <linux/module.h>
-#include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/timer.h>
-#include <linux/uaccess.h>
 #include <linux/io.h>
-#include <mach/hardware.h>
 
-#define WDT_VERSION	"0.3"
-#define PFX		"ep93xx_wdt: "
+#define WDT_VERSION	"0.4"
 
 /* default timeout (secs) */
 #define WDT_TIMEOUT 30
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-static int timeout = WDT_TIMEOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 
+static unsigned int timeout = WDT_TIMEOUT;
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout,
+	"Watchdog timeout in seconds. (1<=timeout<=3600, default="
+				__MODULE_STRING(WDT_TIMEOUT) ")");
+
+static void __iomem *mmio_base;
 static struct timer_list timer;
 static unsigned long next_heartbeat;
-static unsigned long wdt_status;
-static unsigned long boot_status;
 
-#define WDT_IN_USE		0
-#define WDT_OK_TO_CLOSE		1
+#define EP93XX_WATCHDOG		0x00
+#define EP93XX_WDSTATUS		0x04
 
-#define EP93XX_WDT_REG(x)	(EP93XX_WATCHDOG_BASE + (x))
-#define EP93XX_WDT_WATCHDOG	EP93XX_WDT_REG(0x00)
-#define EP93XX_WDT_WDSTATUS	EP93XX_WDT_REG(0x04)
-
-/* reset the wdt every ~200ms */
+/* reset the wdt every ~200ms - the heartbeat of the device is 0.250 seconds*/
 #define WDT_INTERVAL (HZ/5)
 
-static void wdt_enable(void)
-{
-	__raw_writew(0xaaaa, EP93XX_WDT_WATCHDOG);
-}
-
-static void wdt_disable(void)
-{
-	__raw_writew(0xaa55, EP93XX_WDT_WATCHDOG);
-}
-
-static inline void wdt_ping(void)
-{
-	__raw_writew(0x5555, EP93XX_WDT_WATCHDOG);
-}
-
-static void wdt_startup(void)
-{
-	next_heartbeat = jiffies + (timeout * HZ);
-
-	wdt_enable();
-	mod_timer(&timer, jiffies + WDT_INTERVAL);
-}
-
-static void wdt_shutdown(void)
-{
-	del_timer_sync(&timer);
-	wdt_disable();
-}
-
-static void wdt_keepalive(void)
-{
-	/* user land ping */
-	next_heartbeat = jiffies + (timeout * HZ);
-}
-
-static int ep93xx_wdt_open(struct inode *inode, struct file *file)
-{
-	if (test_and_set_bit(WDT_IN_USE, &wdt_status))
-		return -EBUSY;
-
-	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-	wdt_startup();
-
-	return nonseekable_open(inode, file);
-}
-
-static ssize_t
-ep93xx_wdt_write(struct file *file, const char __user *data, size_t len,
-		 loff_t *ppos)
-{
-	if (len) {
-		if (!nowayout) {
-			size_t i;
-
-			clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-			for (i = 0; i != len; i++) {
-				char c;
-
-				if (get_user(c, data + i))
-					return -EFAULT;
-
-				if (c == 'V')
-					set_bit(WDT_OK_TO_CLOSE, &wdt_status);
-				else
-					clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-			}
-		}
-		wdt_keepalive();
-	}
-
-	return len;
-}
-
-static const struct watchdog_info ident = {
-	.options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE,
-	.identity = "EP93xx Watchdog",
-};
-
-static long ep93xx_wdt_ioctl(struct file *file,
-					unsigned int cmd, unsigned long arg)
-{
-	int ret = -ENOTTY;
-
-	switch (cmd) {
-	case WDIOC_GETSUPPORT:
-		ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
-				sizeof(ident)) ? -EFAULT : 0;
-		break;
-
-	case WDIOC_GETSTATUS:
-		ret = put_user(0, (int __user *)arg);
-		break;
-
-	case WDIOC_GETBOOTSTATUS:
-		ret = put_user(boot_status, (int __user *)arg);
-		break;
-
-	case WDIOC_KEEPALIVE:
-		wdt_keepalive();
-		ret = 0;
-		break;
-
-	case WDIOC_GETTIMEOUT:
-		/* actually, it is 0.250 seconds.... */
-		ret = put_user(1, (int __user *)arg);
-		break;
-	}
-	return ret;
-}
-
-static int ep93xx_wdt_release(struct inode *inode, struct file *file)
-{
-	if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
-		wdt_shutdown();
-	else
-		printk(KERN_CRIT PFX
-			"Device closed unexpectedly - timer will not stop\n");
-
-	clear_bit(WDT_IN_USE, &wdt_status);
-	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-	return 0;
-}
-
-static const struct file_operations ep93xx_wdt_fops = {
-	.owner		= THIS_MODULE,
-	.write		= ep93xx_wdt_write,
-	.unlocked_ioctl	= ep93xx_wdt_ioctl,
-	.open		= ep93xx_wdt_open,
-	.release	= ep93xx_wdt_release,
-	.llseek		= no_llseek,
-};
-
-static struct miscdevice ep93xx_wdt_miscdev = {
-	.minor		= WATCHDOG_MINOR,
-	.name		= "watchdog",
-	.fops		= &ep93xx_wdt_fops,
-};
-
-static void ep93xx_timer_ping(unsigned long data)
+static void ep93xx_wdt_timer_ping(unsigned long data)
 {
 	if (time_before(jiffies, next_heartbeat))
-		wdt_ping();
+		writel(0x5555, mmio_base + EP93XX_WATCHDOG);
 
 	/* Re-set the timer interval */
 	mod_timer(&timer, jiffies + WDT_INTERVAL);
 }
 
-static int __init ep93xx_wdt_init(void)
+static int ep93xx_wdt_start(struct watchdog_device *wdd)
 {
+	next_heartbeat = jiffies + (timeout * HZ);
+
+	writel(0xaaaa, mmio_base + EP93XX_WATCHDOG);
+	mod_timer(&timer, jiffies + WDT_INTERVAL);
+
+	return 0;
+}
+
+static int ep93xx_wdt_stop(struct watchdog_device *wdd)
+{
+	del_timer_sync(&timer);
+	writel(0xaa55, mmio_base + EP93XX_WATCHDOG);
+
+	return 0;
+}
+
+static int ep93xx_wdt_keepalive(struct watchdog_device *wdd)
+{
+	/* user land ping */
+	next_heartbeat = jiffies + (timeout * HZ);
+
+	return 0;
+}
+
+static const struct watchdog_info ep93xx_wdt_ident = {
+	.options	= WDIOF_CARDRESET |
+			  WDIOF_MAGICCLOSE |
+			  WDIOF_KEEPALIVEPING,
+	.identity	= "EP93xx Watchdog",
+};
+
+static struct watchdog_ops ep93xx_wdt_ops = {
+	.owner		= THIS_MODULE,
+	.start		= ep93xx_wdt_start,
+	.stop		= ep93xx_wdt_stop,
+	.ping		= ep93xx_wdt_keepalive,
+};
+
+static struct watchdog_device ep93xx_wdt_wdd = {
+	.info		= &ep93xx_wdt_ident,
+	.ops		= &ep93xx_wdt_ops,
+};
+
+static int __devinit ep93xx_wdt_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	unsigned long val;
 	int err;
 
-	err = misc_register(&ep93xx_wdt_miscdev);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
 
-	boot_status = __raw_readl(EP93XX_WDT_WATCHDOG) & 0x01 ? 1 : 0;
+	if (!devm_request_mem_region(&pdev->dev, res->start,
+				     resource_size(res), pdev->name))
+		return -EBUSY;
 
-	printk(KERN_INFO PFX "EP93XX watchdog, driver version "
-		WDT_VERSION "%s\n",
-		(__raw_readl(EP93XX_WDT_WATCHDOG) & 0x08)
-		? " (nCS1 disable detected)" : "");
+	mmio_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!mmio_base)
+		return -ENXIO;
 
 	if (timeout < 1 || timeout > 3600) {
 		timeout = WDT_TIMEOUT;
-		printk(KERN_INFO PFX
+		dev_warn(&pdev->dev,
 			"timeout value must be 1<=x<=3600, using %d\n",
 			timeout);
 	}
 
-	setup_timer(&timer, ep93xx_timer_ping, 1);
-	return err;
+	val = readl(mmio_base + EP93XX_WATCHDOG);
+	ep93xx_wdt_wdd.bootstatus = (val & 0x01) ? WDIOF_CARDRESET : 0;
+	ep93xx_wdt_wdd.timeout = timeout;
+
+	watchdog_set_nowayout(&ep93xx_wdt_wdd, nowayout);
+
+	setup_timer(&timer, ep93xx_wdt_timer_ping, 1);
+
+	err = watchdog_register_device(&ep93xx_wdt_wdd);
+	if (err)
+		return err;
+
+	dev_info(&pdev->dev,
+		"EP93XX watchdog, driver version " WDT_VERSION "%s\n",
+		(val & 0x08) ? " (nCS1 disable detected)" : "");
+
+	return 0;
 }
 
-static void __exit ep93xx_wdt_exit(void)
+static int __devexit ep93xx_wdt_remove(struct platform_device *pdev)
 {
-	wdt_shutdown();
-	misc_deregister(&ep93xx_wdt_miscdev);
+	watchdog_unregister_device(&ep93xx_wdt_wdd);
+	return 0;
 }
 
-module_init(ep93xx_wdt_init);
-module_exit(ep93xx_wdt_exit);
+static struct platform_driver ep93xx_wdt_driver = {
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "ep93xx-wdt",
+	},
+	.probe		= ep93xx_wdt_probe,
+	.remove		= __devexit_p(ep93xx_wdt_remove),
+};
 
-module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
-
-module_param(timeout, int, 0);
-MODULE_PARM_DESC(timeout,
-	"Watchdog timeout in seconds. (1<=timeout<=3600, default="
-				__MODULE_STRING(WDT_TIMEOUT) ")");
+module_platform_driver(ep93xx_wdt_driver);
 
 MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>,"
-		"Alessandro Zummo <a.zummo@towertech.it>");
+		"Alessandro Zummo <a.zummo@towertech.it>,"
+		"H Hartley Sweeten <hsweeten@visionengravers.com>");
 MODULE_DESCRIPTION("EP93xx Watchdog");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(WDT_VERSION);
diff --git a/drivers/watchdog/eurotechwdt.c b/drivers/watchdog/eurotechwdt.c
index 3946c51..cd31b8a 100644
--- a/drivers/watchdog/eurotechwdt.c
+++ b/drivers/watchdog/eurotechwdt.c
@@ -45,6 +45,8 @@
  *	of the on-board SUPER I/O device SMSC FDC 37B782.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -59,7 +61,6 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 
 static unsigned long eurwdt_is_open;
 static int eurwdt_timeout;
@@ -76,8 +77,8 @@
 
 #define WDT_TIMEOUT		60                /* 1 minute */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -144,11 +145,11 @@
 
 	/* Setting interrupt line */
 	if (irq == 2 || irq > 15 || irq < 0) {
-		printk(KERN_ERR ": invalid irq number\n");
+		pr_err("invalid irq number\n");
 		irq = 0;	/* if invalid we disable interrupt */
 	}
 	if (irq == 0)
-		printk(KERN_INFO ": interrupt disabled\n");
+		pr_info("interrupt disabled\n");
 
 	eurwdt_write_reg(WDT_TIMER_CFG, irq << 4);
 
@@ -163,12 +164,12 @@
 
 static irqreturn_t eurwdt_interrupt(int irq, void *dev_id)
 {
-	printk(KERN_CRIT "timeout WDT timeout\n");
+	pr_crit("timeout WDT timeout\n");
 
 #ifdef ONLY_TESTING
-	printk(KERN_CRIT "Would Reboot.\n");
+	pr_crit("Would Reboot\n");
 #else
-	printk(KERN_CRIT "Initiating system reboot.\n");
+	pr_crit("Initiating system reboot\n");
 	emergency_restart();
 #endif
 	return IRQ_HANDLED;
@@ -335,8 +336,7 @@
 	if (eur_expect_close == 42)
 		eurwdt_disable_timer();
 	else {
-		printk(KERN_CRIT
-			"eurwdt: Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		eurwdt_ping();
 	}
 	clear_bit(0, &eurwdt_is_open);
@@ -429,35 +429,32 @@
 
 	ret = request_irq(irq, eurwdt_interrupt, 0, "eurwdt", NULL);
 	if (ret) {
-		printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
+		pr_err("IRQ %d is not free\n", irq);
 		goto out;
 	}
 
 	if (!request_region(io, 2, "eurwdt")) {
-		printk(KERN_ERR "eurwdt: IO %X is not free.\n", io);
+		pr_err("IO %X is not free\n", io);
 		ret = -EBUSY;
 		goto outirq;
 	}
 
 	ret = register_reboot_notifier(&eurwdt_notifier);
 	if (ret) {
-		printk(KERN_ERR
-		    "eurwdt: can't register reboot notifier (err=%d)\n", ret);
+		pr_err("can't register reboot notifier (err=%d)\n", ret);
 		goto outreg;
 	}
 
 	ret = misc_register(&eurwdt_miscdev);
 	if (ret) {
-		printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
-		WATCHDOG_MINOR);
+		pr_err("can't misc_register on minor=%d\n", WATCHDOG_MINOR);
 		goto outreboot;
 	}
 
 	eurwdt_unlock_chip();
 
 	ret = 0;
-	printk(KERN_INFO "Eurotech WDT driver 0.01 at %X (Interrupt %d)"
-		" - timeout event: %s\n",
+	pr_info("Eurotech WDT driver 0.01 at %X (Interrupt %d) - timeout event: %s\n",
 		io, irq, (!strcmp("int", ev) ? "int" : "reboot"));
 
 out:
diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c
index e45ca2b..c65b0a5 100644
--- a/drivers/watchdog/f71808e_wdt.c
+++ b/drivers/watchdog/f71808e_wdt.c
@@ -19,6 +19,8 @@
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/err.h>
 #include <linux/fs.h>
 #include <linux/init.h>
@@ -189,8 +191,7 @@
 {
 	/* Don't step on other drivers' I/O space by accident */
 	if (!request_muxed_region(base, 2, DRVNAME)) {
-		printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
-				(int)base);
+		pr_err("I/O address 0x%04x already in use\n", (int)base);
 		return -EBUSY;
 	}
 
@@ -217,7 +218,7 @@
 {
 	if (timeout <= 0
 	 || timeout >  max_timeout) {
-		printk(KERN_ERR DRVNAME ": watchdog timeout out of range\n");
+		pr_err("watchdog timeout out of range\n");
 		return -EINVAL;
 	}
 
@@ -252,7 +253,7 @@
 	} else if (pw <= 5000) {
 		watchdog.pulse_val = 3;
 	} else {
-		printk(KERN_ERR DRVNAME ": pulse width out of range\n");
+		pr_err("pulse width out of range\n");
 		err = -EINVAL;
 		goto exit_unlock;
 	}
@@ -309,8 +310,7 @@
 		if (ioaddr)
 			superio_set_bit(ioaddr, SIO_REG_MFUNCT1, 1);
 	} else {
-		printk(KERN_ERR DRVNAME ": Invalid argument f71862fg_pin=%d\n",
-				f71862fg_pin);
+		pr_err("Invalid argument f71862fg_pin=%d\n", f71862fg_pin);
 		return -EINVAL;
 	}
 	return 0;
@@ -487,8 +487,7 @@
 
 	if (!watchdog.expect_close) {
 		watchdog_keepalive();
-		printk(KERN_CRIT DRVNAME
-			": Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 	} else if (!nowayout) {
 		watchdog_stop();
 	}
@@ -672,25 +671,22 @@
 
 	err = misc_register(&watchdog_miscdev);
 	if (err) {
-		printk(KERN_ERR DRVNAME
-			": cannot register miscdev on minor=%d\n",
-				watchdog_miscdev.minor);
+		pr_err("cannot register miscdev on minor=%d\n",
+		       watchdog_miscdev.minor);
 		goto exit_reboot;
 	}
 
 	if (start_withtimeout) {
 		if (start_withtimeout <= 0
 		 || start_withtimeout >  max_timeout) {
-			printk(KERN_ERR DRVNAME
-				": starting timeout out of range\n");
+			pr_err("starting timeout out of range\n");
 			err = -EINVAL;
 			goto exit_miscdev;
 		}
 
 		err = watchdog_start();
 		if (err) {
-			printk(KERN_ERR DRVNAME
-				": cannot start watchdog timer\n");
+			pr_err("cannot start watchdog timer\n");
 			goto exit_miscdev;
 		}
 
@@ -720,8 +716,7 @@
 		if (nowayout)
 			__module_get(THIS_MODULE);
 
-		printk(KERN_INFO DRVNAME
-			": watchdog started with initial timeout of %u sec\n",
+		pr_info("watchdog started with initial timeout of %u sec\n",
 			start_withtimeout);
 	}
 
@@ -746,7 +741,7 @@
 
 	devid = superio_inw(sioaddr, SIO_REG_MANID);
 	if (devid != SIO_FINTEK_ID) {
-		pr_debug(DRVNAME ": Not a Fintek device\n");
+		pr_debug("Not a Fintek device\n");
 		err = -ENODEV;
 		goto exit;
 	}
@@ -774,13 +769,13 @@
 		err = -ENODEV;
 		goto exit;
 	default:
-		printk(KERN_INFO DRVNAME ": Unrecognized Fintek device: %04x\n",
-		       (unsigned int)devid);
+		pr_info("Unrecognized Fintek device: %04x\n",
+			(unsigned int)devid);
 		err = -ENODEV;
 		goto exit;
 	}
 
-	printk(KERN_INFO DRVNAME ": Found %s watchdog chip, revision %d\n",
+	pr_info("Found %s watchdog chip, revision %d\n",
 		f71808e_names[watchdog.type],
 		(int)superio_inb(sioaddr, SIO_REG_DEVREV));
 exit:
@@ -808,8 +803,7 @@
 static void __exit f71808e_exit(void)
 {
 	if (watchdog_is_running()) {
-		printk(KERN_WARNING DRVNAME
-			": Watchdog timer still running, stopping it\n");
+		pr_warn("Watchdog timer still running, stopping it\n");
 		watchdog_stop();
 	}
 	misc_deregister(&watchdog_miscdev);
diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c
index b146082..17f4cae 100644
--- a/drivers/watchdog/gef_wdt.c
+++ b/drivers/watchdog/gef_wdt.c
@@ -24,6 +24,8 @@
  * capabilities) a kernel-based watchdog.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/compiler.h>
 #include <linux/init.h>
@@ -68,8 +70,8 @@
 static char expect_close;
 static DEFINE_SPINLOCK(gef_wdt_spinlock);
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 	__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -110,7 +112,7 @@
 	if (gef_wdt_toggle_wdc(GEF_WDC_ENABLED_FALSE,
 				   GEF_WDC_ENABLE_SHIFT)) {
 		gef_wdt_service();
-		printk(KERN_NOTICE "gef_wdt: watchdog activated\n");
+		pr_notice("watchdog activated\n");
 	}
 }
 
@@ -118,7 +120,7 @@
 {
 	if (gef_wdt_toggle_wdc(GEF_WDC_ENABLED_TRUE,
 				   GEF_WDC_ENABLE_SHIFT))
-		printk(KERN_NOTICE "gef_wdt: watchdog deactivated\n");
+		pr_notice("watchdog deactivated\n");
 }
 
 static void gef_wdt_set_timeout(unsigned int timeout)
@@ -234,8 +236,7 @@
 	if (expect_close == 42)
 		gef_wdt_handler_disable();
 	else {
-		printk(KERN_CRIT
-		       "gef_wdt: unexpected close, not stopping timer!\n");
+		pr_crit("unexpected close, not stopping timer!\n");
 		gef_wdt_service();
 	}
 	expect_close = 0;
@@ -313,7 +314,7 @@
 
 static int __init gef_wdt_init(void)
 {
-	printk(KERN_INFO "GE watchdog driver\n");
+	pr_info("GE watchdog driver\n");
 	return platform_driver_register(&gef_wdt_driver);
 }
 
diff --git a/drivers/watchdog/geodewdt.c b/drivers/watchdog/geodewdt.c
index 9b49b12..dc563b6 100644
--- a/drivers/watchdog/geodewdt.c
+++ b/drivers/watchdog/geodewdt.c
@@ -9,6 +9,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -39,8 +40,8 @@
 	"Watchdog timeout in seconds. 1<= timeout <=131, default="
 				__MODULE_STRING(WATCHDOG_TIMEOUT) ".");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -100,7 +101,7 @@
 		geodewdt_disable();
 		module_put(THIS_MODULE);
 	} else {
-		printk(KERN_CRIT "Unexpected close - watchdog is not stopping.\n");
+		pr_crit("Unexpected close - watchdog is not stopping\n");
 		geodewdt_ping();
 
 		set_bit(WDT_FLAGS_ORPHAN, &wdt_flags);
@@ -220,7 +221,7 @@
 
 	wdt_timer = cs5535_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING);
 	if (!wdt_timer) {
-		printk(KERN_ERR "geodewdt:  No timers were available\n");
+		pr_err("No timers were available\n");
 		return -ENODEV;
 	}
 
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 3c166d3..cbc7cee 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -13,6 +13,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/init.h>
@@ -45,7 +47,7 @@
 
 static unsigned int soft_margin = DEFAULT_MARGIN;	/* in seconds */
 static unsigned int reload;			/* the computed soft_margin */
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static char expect_release;
 static unsigned long hpwdt_is_open;
 
@@ -235,8 +237,7 @@
 	asminline_call(&cmn_regs, bios32_entrypoint);
 
 	if (cmn_regs.u1.ral != 0) {
-		printk(KERN_WARNING
-			"hpwdt: Call succeeded but with an error: 0x%x\n",
+		pr_warn("Call succeeded but with an error: 0x%x\n",
 			cmn_regs.u1.ral);
 	} else {
 		physical_bios_base = cmn_regs.u2.rebx;
@@ -256,14 +257,10 @@
 			}
 		}
 
-		printk(KERN_DEBUG "hpwdt: CRU Base Address:   0x%lx\n",
-			physical_bios_base);
-		printk(KERN_DEBUG "hpwdt: CRU Offset Address: 0x%lx\n",
-			physical_bios_offset);
-		printk(KERN_DEBUG "hpwdt: CRU Length:         0x%lx\n",
-			cru_length);
-		printk(KERN_DEBUG "hpwdt: CRU Mapped Address: %p\n",
-			&cru_rom_addr);
+		pr_debug("CRU Base Address:   0x%lx\n", physical_bios_base);
+		pr_debug("CRU Offset Address: 0x%lx\n", physical_bios_offset);
+		pr_debug("CRU Length:         0x%lx\n", cru_length);
+		pr_debug("CRU Mapped Address: %p\n", &cru_rom_addr);
 	}
 	iounmap(bios32_map);
 	return retval;
@@ -458,16 +455,13 @@
 static int hpwdt_change_timer(int new_margin)
 {
 	if (new_margin < 1 || new_margin > HPWDT_MAX_TIMER) {
-		printk(KERN_WARNING
-			"hpwdt: New value passed in is invalid: %d seconds.\n",
+		pr_warn("New value passed in is invalid: %d seconds\n",
 			new_margin);
 		return -EINVAL;
 	}
 
 	soft_margin = new_margin;
-	printk(KERN_DEBUG
-		"hpwdt: New timer passed in is %d seconds.\n",
-		new_margin);
+	pr_debug("New timer passed in is %d seconds\n", new_margin);
 	reload = SECS_TO_TICKS(soft_margin);
 
 	return 0;
@@ -535,8 +529,7 @@
 	if (expect_release == 42) {
 		hpwdt_stop();
 	} else {
-		printk(KERN_CRIT
-			"hpwdt: Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		hpwdt_ping();
 	}
 
@@ -881,7 +874,7 @@
 module_param(soft_margin, int, 0);
 MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 		__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c
index db45091..738032a 100644
--- a/drivers/watchdog/i6300esb.c
+++ b/drivers/watchdog/i6300esb.c
@@ -27,6 +27,8 @@
  *      Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -44,7 +46,6 @@
 #define ESB_VERSION "0.05"
 #define ESB_MODULE_NAME "i6300ESB timer"
 #define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION
-#define PFX ESB_MODULE_NAME ": "
 
 /* PCI configuration registers */
 #define ESB_CONFIG_REG  0x60            /* Config register                   */
@@ -94,8 +95,8 @@
 		"Watchdog heartbeat in seconds. (1<heartbeat<2046, default="
 				__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -213,8 +214,7 @@
 	if (esb_expect_close == 42)
 		esb_timer_stop();
 	else {
-		printk(KERN_CRIT PFX
-				"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		esb_timer_keepalive();
 	}
 	clear_bit(0, &timer_alive);
@@ -347,19 +347,19 @@
 static unsigned char __devinit esb_getdevice(struct pci_dev *pdev)
 {
 	if (pci_enable_device(pdev)) {
-		printk(KERN_ERR PFX "failed to enable device\n");
+		pr_err("failed to enable device\n");
 		goto err_devput;
 	}
 
 	if (pci_request_region(pdev, 0, ESB_MODULE_NAME)) {
-		printk(KERN_ERR PFX "failed to request region\n");
+		pr_err("failed to request region\n");
 		goto err_disable;
 	}
 
 	BASEADDR = pci_ioremap_bar(pdev, 0);
 	if (BASEADDR == NULL) {
 		/* Something's wrong here, BASEADDR has to be set */
-		printk(KERN_ERR PFX "failed to get BASEADDR\n");
+		pr_err("failed to get BASEADDR\n");
 		goto err_release;
 	}
 
@@ -397,7 +397,7 @@
 	/* Check that the WDT isn't already locked */
 	pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1);
 	if (val1 & ESB_WDT_LOCK)
-		printk(KERN_WARNING PFX "nowayout already set\n");
+		pr_warn("nowayout already set\n");
 
 	/* Set the timer to watchdog mode and disable it for now */
 	pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00);
@@ -423,11 +423,11 @@
 
 	cards_found++;
 	if (cards_found == 1)
-		printk(KERN_INFO PFX "Intel 6300ESB WatchDog Timer Driver v%s\n",
+		pr_info("Intel 6300ESB WatchDog Timer Driver v%s\n",
 			ESB_VERSION);
 
 	if (cards_found > 1) {
-		printk(KERN_ERR PFX "This driver only supports 1 device\n");
+		pr_err("This driver only supports 1 device\n");
 		return -ENODEV;
 	}
 
@@ -439,9 +439,8 @@
 	   if not reset to the default */
 	if (heartbeat < 0x1 || heartbeat > 2 * 0x03ff) {
 		heartbeat = WATCHDOG_HEARTBEAT;
-		printk(KERN_INFO PFX
-			"heartbeat value must be 1<heartbeat<2046, using %d\n",
-								heartbeat);
+		pr_info("heartbeat value must be 1<heartbeat<2046, using %d\n",
+			heartbeat);
 	}
 
 	/* Initialize the watchdog and make sure it does not run */
@@ -450,14 +449,12 @@
 	/* Register the watchdog so that userspace has access to it */
 	ret = misc_register(&esb_miscdev);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-							WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto err_unmap;
 	}
-	printk(KERN_INFO PFX
-		"initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
-						BASEADDR, heartbeat, nowayout);
+	pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
+		BASEADDR, heartbeat, nowayout);
 	return 0;
 
 err_unmap:
@@ -503,7 +500,7 @@
 static void __exit watchdog_cleanup(void)
 {
 	pci_unregister_driver(&esb_driver);
-	printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+	pr_info("Watchdog Module Unloaded\n");
 }
 
 module_init(watchdog_init);
diff --git a/drivers/watchdog/iTCO_vendor_support.c b/drivers/watchdog/iTCO_vendor_support.c
index 481d1ad..2721d29 100644
--- a/drivers/watchdog/iTCO_vendor_support.c
+++ b/drivers/watchdog/iTCO_vendor_support.c
@@ -17,10 +17,11 @@
  *	Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 /* Module and version information */
 #define DRV_NAME	"iTCO_vendor_support"
 #define DRV_VERSION	"1.04"
-#define PFX		DRV_NAME ": "
 
 /* Includes */
 #include <linux/module.h>		/* For module specific items */
@@ -355,13 +356,13 @@
 
 static int __init iTCO_vendor_init_module(void)
 {
-	printk(KERN_INFO PFX "vendor-support=%d\n", vendorsupport);
+	pr_info("vendor-support=%d\n", vendorsupport);
 	return 0;
 }
 
 static void __exit iTCO_vendor_exit_module(void)
 {
-	printk(KERN_INFO PFX "Module Unloaded\n");
+	pr_info("Module Unloaded\n");
 }
 
 module_init(iTCO_vendor_init_module);
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index bdf401b..9fecb95 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -43,10 +43,11 @@
  *	Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 /* Module and version information */
 #define DRV_NAME	"iTCO_wdt"
 #define DRV_VERSION	"1.07"
-#define PFX		DRV_NAME ": "
 
 /* Includes */
 #include <linux/module.h>		/* For module specific items */
@@ -413,8 +414,8 @@
 	"5..76 (TCO v1) or 3..614 (TCO v2), default="
 				__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -489,8 +490,7 @@
 	/* disable chipset's NO_REBOOT bit */
 	if (iTCO_wdt_unset_NO_REBOOT_bit()) {
 		spin_unlock(&iTCO_wdt_private.io_lock);
-		printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, "
-					"reboot disabled by hardware/BIOS\n");
+		pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n");
 		return -EIO;
 	}
 
@@ -661,8 +661,7 @@
 	if (expect_release == 42) {
 		iTCO_wdt_stop();
 	} else {
-		printk(KERN_CRIT PFX
-			"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		iTCO_wdt_keepalive();
 	}
 	clear_bit(0, &is_active);
@@ -804,8 +803,7 @@
 	base_address &= 0x0000ff80;
 	if (base_address == 0x00000000) {
 		/* Something's wrong here, ACPIBASE has to be set */
-		printk(KERN_ERR PFX "failed to get TCOBASE address, "
-					"device disabled by hardware/BIOS\n");
+		pr_err("failed to get TCOBASE address, device disabled by hardware/BIOS\n");
 		return -ENODEV;
 	}
 	iTCO_wdt_private.iTCO_version =
@@ -820,8 +818,7 @@
 	if (iTCO_wdt_private.iTCO_version == 2) {
 		pci_read_config_dword(pdev, 0xf0, &base_address);
 		if ((base_address & 1) == 0) {
-			printk(KERN_ERR PFX "RCBA is disabled by hardware"
-						"/BIOS, device disabled\n");
+			pr_err("RCBA is disabled by hardware/BIOS, device disabled\n");
 			ret = -ENODEV;
 			goto out;
 		}
@@ -831,8 +828,7 @@
 
 	/* Check chipset's NO_REBOOT bit */
 	if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
-		printk(KERN_INFO PFX "unable to reset NO_REBOOT flag, "
-					"device disabled by hardware/BIOS\n");
+		pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n");
 		ret = -ENODEV;	/* Cannot reset NO_REBOOT bit */
 		goto out_unmap;
 	}
@@ -842,9 +838,8 @@
 
 	/* The TCO logic uses the TCO_EN bit in the SMI_EN register */
 	if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
-		printk(KERN_ERR PFX
-			"I/O address 0x%04lx already in use, "
-						"device disabled\n", SMI_EN);
+		pr_err("I/O address 0x%04lx already in use, device disabled\n",
+		       SMI_EN);
 		ret = -EIO;
 		goto out_unmap;
 	}
@@ -858,17 +853,16 @@
 	/* The TCO I/O registers reside in a 32-byte range pointed to
 	   by the TCOBASE value */
 	if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) {
-		printk(KERN_ERR PFX "I/O address 0x%04lx already in use "
-						"device disabled\n", TCOBASE);
+		pr_err("I/O address 0x%04lx already in use, device disabled\n",
+		       TCOBASE);
 		ret = -EIO;
 		goto unreg_smi_en;
 	}
 
-	printk(KERN_INFO PFX
-		"Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
-			iTCO_chipset_info[ent->driver_data].name,
-			iTCO_chipset_info[ent->driver_data].iTCO_version,
-			TCOBASE);
+	pr_info("Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
+		iTCO_chipset_info[ent->driver_data].name,
+		iTCO_chipset_info[ent->driver_data].iTCO_version,
+		TCOBASE);
 
 	/* Clear out the (probably old) status */
 	outw(0x0008, TCO1_STS);	/* Clear the Time Out Status bit */
@@ -882,20 +876,18 @@
 	   if not reset to the default */
 	if (iTCO_wdt_set_heartbeat(heartbeat)) {
 		iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
-		printk(KERN_INFO PFX
-			"timeout value out of range, using %d\n", heartbeat);
+		pr_info("timeout value out of range, using %d\n", heartbeat);
 	}
 
 	ret = misc_register(&iTCO_wdt_miscdev);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-							WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto unreg_region;
 	}
 
-	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
-							heartbeat, nowayout);
+	pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
+		heartbeat, nowayout);
 
 	return 0;
 
@@ -947,7 +939,7 @@
 	}
 
 	if (!found)
-		printk(KERN_INFO PFX "No device detected.\n");
+		pr_info("No device detected\n");
 
 	return ret;
 }
@@ -979,8 +971,7 @@
 {
 	int err;
 
-	printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s\n",
-		DRV_VERSION);
+	pr_info("Intel TCO WatchDog Timer Driver v%s\n", DRV_VERSION);
 
 	err = platform_driver_register(&iTCO_wdt_driver);
 	if (err)
@@ -1004,7 +995,7 @@
 {
 	platform_device_unregister(iTCO_wdt_platform_device);
 	platform_driver_unregister(&iTCO_wdt_driver);
-	printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+	pr_info("Watchdog Module Unloaded\n");
 }
 
 module_init(iTCO_wdt_init_module);
diff --git a/drivers/watchdog/ib700wdt.c b/drivers/watchdog/ib700wdt.c
index 0149d8d..184c0bf 100644
--- a/drivers/watchdog/ib700wdt.c
+++ b/drivers/watchdog/ib700wdt.c
@@ -31,6 +31,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/miscdevice.h>
@@ -44,7 +46,6 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 
 static struct platform_device *ibwdt_platform_device;
 static unsigned long ibwdt_is_open;
@@ -53,7 +54,6 @@
 
 /* Module information */
 #define DRV_NAME "ib700wdt"
-#define PFX DRV_NAME ": "
 
 /*
  *
@@ -102,8 +102,8 @@
 	"Watchdog timeout in seconds. 0<= timeout <=30, default="
 		__MODULE_STRING(WATCHDOG_TIMEOUT) ".");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -246,8 +246,7 @@
 	if (expect_close == 42) {
 		ibwdt_disable();
 	} else {
-		printk(KERN_CRIT PFX
-		     "WDT device closed unexpectedly.  WDT will not stop!\n");
+		pr_crit("WDT device closed unexpectedly.  WDT will not stop!\n");
 		ibwdt_ping();
 	}
 	clear_bit(0, &ibwdt_is_open);
@@ -284,16 +283,14 @@
 
 #if WDT_START != WDT_STOP
 	if (!request_region(WDT_STOP, 1, "IB700 WDT")) {
-		printk(KERN_ERR PFX "STOP method I/O %X is not available.\n",
-								WDT_STOP);
+		pr_err("STOP method I/O %X is not available\n", WDT_STOP);
 		res = -EIO;
 		goto out_nostopreg;
 	}
 #endif
 
 	if (!request_region(WDT_START, 1, "IB700 WDT")) {
-		printk(KERN_ERR PFX "START method I/O %X is not available.\n",
-								WDT_START);
+		pr_err("START method I/O %X is not available\n", WDT_START);
 		res = -EIO;
 		goto out_nostartreg;
 	}
@@ -302,13 +299,12 @@
 	 * if not reset to the default */
 	if (ibwdt_set_heartbeat(timeout)) {
 		ibwdt_set_heartbeat(WATCHDOG_TIMEOUT);
-		printk(KERN_INFO PFX
-			"timeout value must be 0<=x<=30, using %d\n", timeout);
+		pr_info("timeout value must be 0<=x<=30, using %d\n", timeout);
 	}
 
 	res = misc_register(&ibwdt_miscdev);
 	if (res) {
-		printk(KERN_ERR PFX "failed to register misc device\n");
+		pr_err("failed to register misc device\n");
 		goto out_nomisc;
 	}
 	return 0;
@@ -353,8 +349,7 @@
 {
 	int err;
 
-	printk(KERN_INFO PFX
-		"WDT driver for IB700 single board computer initialising.\n");
+	pr_info("WDT driver for IB700 single board computer initialising\n");
 
 	err = platform_driver_register(&ibwdt_driver);
 	if (err)
@@ -378,7 +373,7 @@
 {
 	platform_device_unregister(ibwdt_platform_device);
 	platform_driver_unregister(&ibwdt_driver);
-	printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+	pr_info("Watchdog Module Unloaded\n");
 }
 
 module_init(ibwdt_init);
diff --git a/drivers/watchdog/ibmasr.c b/drivers/watchdog/ibmasr.c
index c7481ad..bc3fb8f 100644
--- a/drivers/watchdog/ibmasr.c
+++ b/drivers/watchdog/ibmasr.c
@@ -10,6 +10,8 @@
  * of the GNU Public License, incorporated herein by reference.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -31,8 +33,6 @@
 	ASMTYPE_SPRUCE,
 };
 
-#define PFX "ibmasr: "
-
 #define TOPAZ_ASR_REG_OFFSET	4
 #define TOPAZ_ASR_TOGGLE	0x40
 #define TOPAZ_ASR_DISABLE	0x80
@@ -60,7 +60,7 @@
 #define SPRUCE_ASR_TOGGLE_MASK	0x02	/* bit 0: 0, then 1, then 0 */
 
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 static unsigned long asr_is_open;
 static char asr_expect_close;
@@ -234,12 +234,11 @@
 	}
 
 	if (!request_region(asr_base, asr_length, "ibmasr")) {
-		printk(KERN_ERR PFX "address %#x already in use\n",
-			asr_base);
+		pr_err("address %#x already in use\n", asr_base);
 		return -EBUSY;
 	}
 
-	printk(KERN_INFO PFX "found %sASR @ addr %#x\n", type, asr_base);
+	pr_info("found %sASR @ addr %#x\n", type, asr_base);
 
 	return 0;
 }
@@ -332,8 +331,7 @@
 	if (asr_expect_close == 42)
 		asr_disable();
 	else {
-		printk(KERN_CRIT PFX
-				"unexpected close, not stopping watchdog!\n");
+		pr_crit("unexpected close, not stopping watchdog!\n");
 		asr_toggle();
 	}
 	clear_bit(0, &asr_is_open);
@@ -393,7 +391,7 @@
 	rc = misc_register(&asr_miscdev);
 	if (rc < 0) {
 		release_region(asr_base, asr_length);
-		printk(KERN_ERR PFX "failed to register misc device\n");
+		pr_err("failed to register misc device\n");
 		return rc;
 	}
 
@@ -413,7 +411,7 @@
 module_init(ibmasr_init);
 module_exit(ibmasr_exit);
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index c44c333..7a2b734 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -46,6 +46,9 @@
 #define IMX2_WDT_SEQ1		0x5555		/* -> service sequence 1 */
 #define IMX2_WDT_SEQ2		0xAAAA		/* -> service sequence 2 */
 
+#define IMX2_WDT_WRSR		0x04		/* Reset Status Register */
+#define IMX2_WDT_WRSR_TOUT	(1 << 1)	/* -> Reset due to Timeout */
+
 #define IMX2_WDT_MAX_TIME	128
 #define IMX2_WDT_DEFAULT_TIME	60		/* in seconds */
 
@@ -65,8 +68,8 @@
 
 static struct miscdevice imx2_wdt_miscdev;
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -175,6 +178,7 @@
 	void __user *argp = (void __user *)arg;
 	int __user *p = argp;
 	int new_value;
+	u16 val;
 
 	switch (cmd) {
 	case WDIOC_GETSUPPORT:
@@ -182,9 +186,13 @@
 			sizeof(struct watchdog_info)) ? -EFAULT : 0;
 
 	case WDIOC_GETSTATUS:
-	case WDIOC_GETBOOTSTATUS:
 		return put_user(0, p);
 
+	case WDIOC_GETBOOTSTATUS:
+		val = __raw_readw(imx2_wdt.base + IMX2_WDT_WRSR);
+		new_value = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0;
+		return put_user(new_value, p);
+
 	case WDIOC_KEEPALIVE:
 		imx2_wdt_ping();
 		return 0;
diff --git a/drivers/watchdog/indydog.c b/drivers/watchdog/indydog.c
index 1475e09..6d90f7a 100644
--- a/drivers/watchdog/indydog.c
+++ b/drivers/watchdog/indydog.c
@@ -12,6 +12,8 @@
  *	based on softdog.c by Alan Cox <alan@lxorguk.ukuu.org.uk>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -26,14 +28,13 @@
 #include <linux/uaccess.h>
 #include <asm/sgi/mc.h>
 
-#define PFX "indydog: "
 static unsigned long indydog_alive;
 static DEFINE_SPINLOCK(indydog_lock);
 
 #define WATCHDOG_TIMEOUT 30		/* 30 sec default timeout */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -60,7 +61,7 @@
 	sgimc->cpuctrl0 = mc_ctrl0;
 	spin_unlock(&indydog_lock);
 
-	printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+	pr_info("Stopped watchdog timer\n");
 }
 
 static void indydog_ping(void)
@@ -83,7 +84,7 @@
 	indydog_start();
 	indydog_ping();
 
-	printk(KERN_INFO "Started watchdog timer.\n");
+	pr_info("Started watchdog timer\n");
 
 	return nonseekable_open(inode, file);
 }
@@ -178,30 +179,25 @@
 	.notifier_call = indydog_notify_sys,
 };
 
-static char banner[] __initdata =
-	KERN_INFO PFX "Hardware Watchdog Timer for SGI IP22: 0.3\n";
-
 static int __init watchdog_init(void)
 {
 	int ret;
 
 	ret = register_reboot_notifier(&indydog_notifier);
 	if (ret) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", ret);
+		pr_err("cannot register reboot notifier (err=%d)\n", ret);
 		return ret;
 	}
 
 	ret = misc_register(&indydog_miscdev);
 	if (ret) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-							WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		unregister_reboot_notifier(&indydog_notifier);
 		return ret;
 	}
 
-	printk(banner);
+	pr_info("Hardware Watchdog Timer for SGI IP22: 0.3\n");
 
 	return 0;
 }
diff --git a/drivers/watchdog/intel_scu_watchdog.c b/drivers/watchdog/intel_scu_watchdog.c
index 1abdc04..9dda2d0 100644
--- a/drivers/watchdog/intel_scu_watchdog.c
+++ b/drivers/watchdog/intel_scu_watchdog.c
@@ -22,6 +22,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/compiler.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -96,15 +98,14 @@
 static void watchdog_fire(void)
 {
 	if (force_boot) {
-		printk(KERN_CRIT PFX "Initiating system reboot.\n");
+		pr_crit("Initiating system reboot\n");
 		emergency_restart();
-		printk(KERN_CRIT PFX "Reboot didn't ?????\n");
+		pr_crit("Reboot didn't ?????\n");
 	}
 
 	else {
-		printk(KERN_CRIT PFX "Immediate Reboot Disabled\n");
-		printk(KERN_CRIT PFX
-			"System will reset when watchdog timer times out!\n");
+		pr_crit("Immediate Reboot Disabled\n");
+		pr_crit("System will reset when watchdog timer times out!\n");
 	}
 }
 
@@ -112,8 +113,8 @@
 {
 	if ((new_margin < MIN_TIME_CYCLE) ||
 	    (new_margin > MAX_TIME - timer_set)) {
-		pr_debug("Watchdog timer: value of new_margin %d is out of the range %d to %d\n",
-			  new_margin, MIN_TIME_CYCLE, MAX_TIME - timer_set);
+		pr_debug("value of new_margin %d is out of the range %d to %d\n",
+			 new_margin, MIN_TIME_CYCLE, MAX_TIME - timer_set);
 		return -EINVAL;
 	}
 	return 0;
@@ -156,14 +157,14 @@
 	int int_status;
 	int_status = ioread32(watchdog_device.timer_interrupt_status_addr);
 
-	pr_debug("Watchdog timer: irq, int_status: %x\n", int_status);
+	pr_debug("irq, int_status: %x\n", int_status);
 
 	if (int_status != 0)
 		return IRQ_NONE;
 
 	/* has the timer been started? If not, then this is spurious */
 	if (watchdog_device.timer_started == 0) {
-		pr_debug("Watchdog timer: spurious interrupt received\n");
+		pr_debug("spurious interrupt received\n");
 		return IRQ_HANDLED;
 	}
 
@@ -220,16 +221,15 @@
 		(watchdog_device.timer_set - timer_margin)
 		* watchdog_device.timer_tbl_ptr->freq_hz;
 
-	pr_debug("Watchdog timer: set_heartbeat: timer freq is %d\n",
-		watchdog_device.timer_tbl_ptr->freq_hz);
-	pr_debug("Watchdog timer: set_heartbeat: timer_set is %x (hex)\n",
-		watchdog_device.timer_set);
-	pr_debug("Watchdog timer: set_hearbeat: timer_margin is %x (hex)\n",
-		timer_margin);
-	pr_debug("Watchdog timer: set_heartbeat: threshold is %x (hex)\n",
-		watchdog_device.threshold);
-	pr_debug("Watchdog timer: set_heartbeat: soft_threshold is %x (hex)\n",
-		watchdog_device.soft_threshold);
+	pr_debug("set_heartbeat: timer freq is %d\n",
+		 watchdog_device.timer_tbl_ptr->freq_hz);
+	pr_debug("set_heartbeat: timer_set is %x (hex)\n",
+		 watchdog_device.timer_set);
+	pr_debug("set_hearbeat: timer_margin is %x (hex)\n", timer_margin);
+	pr_debug("set_heartbeat: threshold is %x (hex)\n",
+		 watchdog_device.threshold);
+	pr_debug("set_heartbeat: soft_threshold is %x (hex)\n",
+		 watchdog_device.soft_threshold);
 
 	/* Adjust thresholds by FREQ_ADJUSTMENT factor, to make the */
 	/* watchdog timing come out right. */
@@ -264,7 +264,7 @@
 
 		if (MAX_RETRY < retry_count++) {
 			/* Unable to set timer value */
-			pr_err("Watchdog timer: Unable to set timer\n");
+			pr_err("Unable to set timer\n");
 			return -ENODEV;
 		}
 
@@ -321,18 +321,17 @@
 	 */
 
 	if (!test_and_clear_bit(0, &watchdog_device.driver_open)) {
-		pr_debug("Watchdog timer: intel_scu_release, without open\n");
+		pr_debug("intel_scu_release, without open\n");
 		return -ENOTTY;
 	}
 
 	if (!watchdog_device.timer_started) {
 		/* Just close, since timer has not been started */
-		pr_debug("Watchdog timer: closed, without starting timer\n");
+		pr_debug("closed, without starting timer\n");
 		return 0;
 	}
 
-	printk(KERN_CRIT PFX
-	       "Unexpected close of /dev/watchdog!\n");
+	pr_crit("Unexpected close of /dev/watchdog!\n");
 
 	/* Since the timer was started, prevent future reopens */
 	watchdog_device.driver_closed = 1;
@@ -454,9 +453,8 @@
 	/* Check value of timer_set boot parameter */
 	if ((timer_set < MIN_TIME_CYCLE) ||
 	    (timer_set > MAX_TIME - MIN_TIME_CYCLE)) {
-		pr_err("Watchdog timer: value of timer_set %x (hex) "
-		  "is out of range from %x to %x (hex)\n",
-		  timer_set, MIN_TIME_CYCLE, MAX_TIME - MIN_TIME_CYCLE);
+		pr_err("value of timer_set %x (hex) is out of range from %x to %x (hex)\n",
+		       timer_set, MIN_TIME_CYCLE, MAX_TIME - MIN_TIME_CYCLE);
 		return -EINVAL;
 	}
 
@@ -467,19 +465,18 @@
 	watchdog_device.timer_tbl_ptr = sfi_get_mtmr(sfi_mtimer_num-1);
 
 	if (watchdog_device.timer_tbl_ptr == NULL) {
-		pr_debug("Watchdog timer - Intel SCU watchdog: timer is not available\n");
+		pr_debug("timer is not available\n");
 		return -ENODEV;
 	}
 	/* make sure the timer exists */
 	if (watchdog_device.timer_tbl_ptr->phys_addr == 0) {
-		pr_debug("Watchdog timer - Intel SCU watchdog - timer %d does not have valid physical memory\n",
-								sfi_mtimer_num);
+		pr_debug("timer %d does not have valid physical memory\n",
+			 sfi_mtimer_num);
 		return -ENODEV;
 	}
 
 	if (watchdog_device.timer_tbl_ptr->irq == 0) {
-		pr_debug("Watchdog timer: timer %d invalid irq\n",
-							sfi_mtimer_num);
+		pr_debug("timer %d invalid irq\n", sfi_mtimer_num);
 		return -ENODEV;
 	}
 
@@ -487,7 +484,7 @@
 			20);
 
 	if (tmp_addr == NULL) {
-		pr_debug("Watchdog timer: timer unable to ioremap\n");
+		pr_debug("timer unable to ioremap\n");
 		return -ENOMEM;
 	}
 
@@ -512,7 +509,7 @@
 
 	ret = register_reboot_notifier(&watchdog_device.intel_scu_notifier);
 	if (ret) {
-		pr_err("Watchdog timer: cannot register notifier %d)\n", ret);
+		pr_err("cannot register notifier %d)\n", ret);
 		goto register_reboot_error;
 	}
 
@@ -522,8 +519,8 @@
 
 	ret = misc_register(&watchdog_device.miscdev);
 	if (ret) {
-		pr_err("Watchdog timer: cannot register miscdev %d err =%d\n",
-							WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev %d err =%d\n",
+		       WATCHDOG_MINOR, ret);
 		goto misc_register_error;
 	}
 
@@ -532,7 +529,7 @@
 		IRQF_SHARED, "watchdog",
 		&watchdog_device.timer_load_count_addr);
 	if (ret) {
-		pr_err("Watchdog timer: error requesting irq %d\n", ret);
+		pr_err("error requesting irq %d\n", ret);
 		goto request_irq_error;
 	}
 	/* Make sure timer is disabled before returning */
diff --git a/drivers/watchdog/intel_scu_watchdog.h b/drivers/watchdog/intel_scu_watchdog.h
index d2b074a..f3ac608 100644
--- a/drivers/watchdog/intel_scu_watchdog.h
+++ b/drivers/watchdog/intel_scu_watchdog.h
@@ -25,7 +25,6 @@
 #ifndef __INTEL_SCU_WATCHDOG_H
 #define __INTEL_SCU_WATCHDOG_H
 
-#define PFX "Intel_SCU: "
 #define WDT_VER "0.3"
 
 /* minimum time between interrupts */
diff --git a/drivers/watchdog/iop_wdt.c b/drivers/watchdog/iop_wdt.c
index 82fa7a9..d964faf 100644
--- a/drivers/watchdog/iop_wdt.c
+++ b/drivers/watchdog/iop_wdt.c
@@ -24,6 +24,8 @@
  *	Dan Williams <dan.j.williams@intel.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
@@ -34,7 +36,7 @@
 #include <linux/uaccess.h>
 #include <mach/hardware.h>
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static unsigned long wdt_status;
 static unsigned long boot_status;
 static DEFINE_SPINLOCK(wdt_lock);
@@ -85,7 +87,7 @@
 		write_wdtcr(IOP_WDTCR_DIS);
 		clear_bit(WDT_ENABLED, &wdt_status);
 		spin_unlock(&wdt_lock);
-		printk(KERN_INFO "WATCHDOG: Disabled\n");
+		pr_info("Disabled\n");
 		return 0;
 	} else
 		return 1;
@@ -197,8 +199,8 @@
 	 */
 	if (state != 0) {
 		wdt_enable();
-		printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
-		       "reset in %lu seconds\n", iop_watchdog_timeout());
+		pr_crit("Device closed unexpectedly - reset in %lu seconds\n",
+			iop_watchdog_timeout());
 	}
 
 	clear_bit(WDT_IN_USE, &wdt_status);
@@ -238,8 +240,7 @@
 	   with an open */
 	ret = misc_register(&iop_wdt_miscdev);
 	if (ret == 0)
-		printk(KERN_INFO "iop watchdog timer: timeout %lu sec\n",
-		       iop_watchdog_timeout());
+		pr_info("timeout %lu sec\n", iop_watchdog_timeout());
 
 	return ret;
 }
@@ -252,7 +253,7 @@
 module_init(iop_wdt_init);
 module_exit(iop_wdt_exit);
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 
 MODULE_AUTHOR("Curt E Bruns <curt.e.bruns@intel.com>");
diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c
index 8d2d850..f4cce6d 100644
--- a/drivers/watchdog/it8712f_wdt.c
+++ b/drivers/watchdog/it8712f_wdt.c
@@ -20,6 +20,8 @@
  *	software is provided AS-IS with no warranties.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -33,6 +35,7 @@
 #include <linux/io.h>
 #include <linux/ioport.h>
 
+#define DEBUG
 #define NAME "it8712f_wdt"
 
 MODULE_AUTHOR("Jorge Boncompte - DTI2 <jorge@dti2.net>");
@@ -45,8 +48,8 @@
 module_param(margin, int, 0);
 MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
 
 static unsigned long wdt_open;
@@ -158,10 +161,10 @@
 	 */
 	if (units <= max_units) {
 		config |= WDT_UNIT_SEC; /* else UNIT is MINUTES */
-		printk(KERN_INFO NAME ": timer margin %d seconds\n", units);
+		pr_info("timer margin %d seconds\n", units);
 	} else {
 		units /= 60;
-		printk(KERN_INFO NAME ": timer margin %d minutes\n", units);
+		pr_info("timer margin %d minutes\n", units);
 	}
 	superio_outb(config, WDT_CONFIG);
 
@@ -184,7 +187,7 @@
 	if (ret)
 		return ret;
 
-	printk(KERN_DEBUG NAME ": enabling watchdog timer\n");
+	pr_debug("enabling watchdog timer\n");
 	superio_select(LDN_GPIO);
 
 	superio_outb(wdt_control_reg, WDT_CONTROL);
@@ -204,7 +207,7 @@
 	if (ret)
 		return ret;
 
-	printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
+	pr_debug("disabling watchdog timer\n");
 	superio_select(LDN_GPIO);
 
 	superio_outb(0, WDT_CONFIG);
@@ -331,12 +334,10 @@
 static int it8712f_wdt_release(struct inode *inode, struct file *file)
 {
 	if (expect_close != 42) {
-		printk(KERN_WARNING NAME
-			": watchdog device closed unexpectedly, will not"
-			" disable the watchdog timer\n");
+		pr_warn("watchdog device closed unexpectedly, will not disable the watchdog timer\n");
 	} else if (!nowayout) {
 		if (it8712f_wdt_disable())
-			printk(KERN_WARNING NAME "Watchdog disable failed\n");
+			pr_warn("Watchdog disable failed\n");
 	}
 	expect_close = 0;
 	clear_bit(0, &wdt_open);
@@ -374,13 +375,13 @@
 	superio_select(LDN_GAME);
 	superio_outb(1, ACT_REG);
 	if (!(superio_inb(ACT_REG) & 0x01)) {
-		printk(KERN_ERR NAME ": Device not activated, skipping\n");
+		pr_err("Device not activated, skipping\n");
 		goto exit;
 	}
 
 	*address = superio_inw(BASE_REG);
 	if (*address == 0) {
-		printk(KERN_ERR NAME ": Base address not set, skipping\n");
+		pr_err("Base address not set, skipping\n");
 		goto exit;
 	}
 
@@ -394,8 +395,7 @@
 	if (margin > (max_units * 60))
 		margin = (max_units * 60);
 
-	printk(KERN_INFO NAME ": Found IT%04xF chip revision %d - "
-		"using DogFood address 0x%x\n",
+	pr_info("Found IT%04xF chip revision %d - using DogFood address 0x%x\n",
 		chip_type, revision, *address);
 
 exit:
@@ -411,27 +411,26 @@
 		return -ENODEV;
 
 	if (!request_region(address, 1, "IT8712F Watchdog")) {
-		printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
+		pr_warn("watchdog I/O region busy\n");
 		return -EBUSY;
 	}
 
 	err = it8712f_wdt_disable();
 	if (err) {
-		printk(KERN_ERR NAME ": unable to disable watchdog timer.\n");
+		pr_err("unable to disable watchdog timer\n");
 		goto out;
 	}
 
 	err = register_reboot_notifier(&it8712f_wdt_notifier);
 	if (err) {
-		printk(KERN_ERR NAME ": unable to register reboot notifier\n");
+		pr_err("unable to register reboot notifier\n");
 		goto out;
 	}
 
 	err = misc_register(&it8712f_wdt_miscdev);
 	if (err) {
-		printk(KERN_ERR NAME
-			": cannot register miscdev on minor=%d (err=%d)\n",
-			WATCHDOG_MINOR, err);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, err);
 		goto reboot_out;
 	}
 
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
index a2d9a12..8a741bc 100644
--- a/drivers/watchdog/it87_wdt.c
+++ b/drivers/watchdog/it87_wdt.c
@@ -29,6 +29,8 @@
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -43,11 +45,9 @@
 #include <linux/uaccess.h>
 #include <linux/io.h>
 
-#include <asm/system.h>
 
 #define WATCHDOG_VERSION	"1.14"
 #define WATCHDOG_NAME		"IT87 WDT"
-#define PFX			WATCHDOG_NAME ": "
 #define DRIVER_VERSION		WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
 #define WD_MAGIC		'V'
 
@@ -142,7 +142,7 @@
 static	int exclusive  = DEFAULT_EXCLUSIVE;
 static	int timeout    = DEFAULT_TIMEOUT;
 static	int testmode   = DEFAULT_TESTMODE;
-static	int nowayout   = DEFAULT_NOWAYOUT;
+static	bool nowayout   = DEFAULT_NOWAYOUT;
 
 module_param(nogameport, int, 0);
 MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default="
@@ -156,7 +156,7 @@
 module_param(testmode, int, 0);
 MODULE_PARM_DESC(testmode, "Watchdog test mode (1 = no reboot), default="
 		__MODULE_STRING(DEFAULT_TESTMODE));
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="
 		__MODULE_STRING(WATCHDOG_NOWAYOUT));
 
@@ -428,8 +428,7 @@
 			clear_bit(WDTS_TIMER_RUN, &wdt_status);
 		} else {
 			wdt_keepalive();
-			printk(KERN_CRIT PFX
-			       "unexpected close, not stopping watchdog!\n");
+			pr_crit("unexpected close, not stopping watchdog!\n");
 		}
 	}
 	clear_bit(WDTS_DEV_OPEN, &wdt_status);
@@ -621,16 +620,14 @@
 		try_gameport = 0;
 		break;
 	case IT8705_ID:
-		printk(KERN_ERR PFX
-		       "Unsupported Chip found, Chip %04x Revision %02x\n",
+		pr_err("Unsupported Chip found, Chip %04x Revision %02x\n",
 		       chip_type, chip_rev);
 		return -ENODEV;
 	case NO_DEV_ID:
-		printk(KERN_ERR PFX "no device\n");
+		pr_err("no device\n");
 		return -ENODEV;
 	default:
-		printk(KERN_ERR PFX
-		       "Unknown Chip found, Chip %04x Revision %04x\n",
+		pr_err("Unknown Chip found, Chip %04x Revision %04x\n",
 		       chip_type, chip_rev);
 		return -ENODEV;
 	}
@@ -663,13 +660,11 @@
 	if (!test_bit(WDTS_USE_GP, &wdt_status)) {
 		if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
 			if (gp_rreq_fail)
-				printk(KERN_ERR PFX
-					"I/O Address 0x%04x and 0x%04x"
-					" already in use\n", base, CIR_BASE);
+				pr_err("I/O Address 0x%04x and 0x%04x already in use\n",
+				       base, CIR_BASE);
 			else
-				printk(KERN_ERR PFX
-					"I/O Address 0x%04x already in use\n",
-					CIR_BASE);
+				pr_err("I/O Address 0x%04x already in use\n",
+				       CIR_BASE);
 			rc = -EIO;
 			goto err_out;
 		}
@@ -688,9 +683,8 @@
 
 	if (timeout < 1 || timeout > max_units * 60) {
 		timeout = DEFAULT_TIMEOUT;
-		printk(KERN_WARNING PFX
-		       "Timeout value out of range, use default %d sec\n",
-		       DEFAULT_TIMEOUT);
+		pr_warn("Timeout value out of range, use default %d sec\n",
+			DEFAULT_TIMEOUT);
 	}
 
 	if (timeout > max_units)
@@ -698,16 +692,14 @@
 
 	rc = register_reboot_notifier(&wdt_notifier);
 	if (rc) {
-		printk(KERN_ERR PFX
-		       "Cannot register reboot notifier (err=%d)\n", rc);
+		pr_err("Cannot register reboot notifier (err=%d)\n", rc);
 		goto err_out_region;
 	}
 
 	rc = misc_register(&wdt_miscdev);
 	if (rc) {
-		printk(KERN_ERR PFX
-		       "Cannot register miscdev on minor=%d (err=%d)\n",
-			wdt_miscdev.minor, rc);
+		pr_err("Cannot register miscdev on minor=%d (err=%d)\n",
+		       wdt_miscdev.minor, rc);
 		goto err_out_reboot;
 	}
 
@@ -722,9 +714,8 @@
 		outb(0x09, CIR_IER(base));
 	}
 
-	printk(KERN_INFO PFX "Chip IT%04x revision %d initialized. "
-		"timeout=%d sec (nowayout=%d testmode=%d exclusive=%d "
-		"nogameport=%d)\n", chip_type, chip_rev, timeout,
+	pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d exclusive=%d nogameport=%d)\n",
+		chip_type, chip_rev, timeout,
 		nowayout, testmode, exclusive, nogameport);
 
 	superio_exit();
diff --git a/drivers/watchdog/ixp2000_wdt.c b/drivers/watchdog/ixp2000_wdt.c
index 084f71aa..3f047a5 100644
--- a/drivers/watchdog/ixp2000_wdt.c
+++ b/drivers/watchdog/ixp2000_wdt.c
@@ -16,6 +16,8 @@
  * warranty of any kind, whether express or implied.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -29,7 +31,7 @@
 #include <linux/uaccess.h>
 #include <mach/hardware.h>
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static unsigned int heartbeat = 60;	/* (secs) Default is 1 minute */
 static unsigned long wdt_status;
 static DEFINE_SPINLOCK(wdt_lock);
@@ -158,8 +160,7 @@
 	if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
 		wdt_disable();
 	else
-		printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
-					"timer will not stop\n");
+		pr_crit("Device closed unexpectedly - timer will not stop\n");
 	clear_bit(WDT_IN_USE, &wdt_status);
 	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
 
@@ -185,7 +186,7 @@
 static int __init ixp2000_wdt_init(void)
 {
 	if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) {
-		printk(KERN_INFO "Unable to use IXP2000 watchdog due to IXP2800 erratum #25.\n");
+		pr_info("Unable to use IXP2000 watchdog due to IXP2800 erratum #25\n");
 		return -EIO;
 	}
 	wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256;
@@ -206,7 +207,7 @@
 module_param(heartbeat, int, 0);
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/ixp4xx_wdt.c b/drivers/watchdog/ixp4xx_wdt.c
index 4fc2e9a..5580b4f 100644
--- a/drivers/watchdog/ixp4xx_wdt.c
+++ b/drivers/watchdog/ixp4xx_wdt.c
@@ -13,6 +13,8 @@
  * warranty of any kind, whether express or implied.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -25,7 +27,7 @@
 #include <linux/uaccess.h>
 #include <mach/hardware.h>
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static int heartbeat = 60;	/* (secs) Default is 1 minute */
 static unsigned long wdt_status;
 static unsigned long boot_status;
@@ -147,8 +149,7 @@
 	if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
 		wdt_disable();
 	else
-		printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
-					"timer will not stop\n");
+		pr_crit("Device closed unexpectedly - timer will not stop\n");
 	clear_bit(WDT_IN_USE, &wdt_status);
 	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
 
@@ -176,8 +177,7 @@
 	int ret;
 
 	if (!(read_cpuid_id() & 0xf) && !cpu_is_ixp46x()) {
-		printk(KERN_ERR "IXP4XXX Watchdog: Rev. A0 IXP42x CPU detected"
-			" - watchdog disabled\n");
+		pr_err("Rev. A0 IXP42x CPU detected - watchdog disabled\n");
 
 		return -ENODEV;
 	}
@@ -185,8 +185,7 @@
 			WDIOF_CARDRESET : 0;
 	ret = misc_register(&ixp4xx_wdt_miscdev);
 	if (ret == 0)
-		printk(KERN_INFO "IXP4xx Watchdog Timer: heartbeat %d sec\n",
-			heartbeat);
+		pr_info("timer heartbeat %d sec\n", heartbeat);
 	return ret;
 }
 
@@ -205,7 +204,7 @@
 module_param(heartbeat, int, 0);
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c
index 17ef300..978615e 100644
--- a/drivers/watchdog/jz4740_wdt.c
+++ b/drivers/watchdog/jz4740_wdt.c
@@ -17,18 +17,15 @@
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/init.h>
-#include <linux/bitops.h>
 #include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/device.h>
 #include <linux/clk.h>
 #include <linux/slab.h>
+#include <linux/err.h>
 
 #include <asm/mach-jz4740/timer.h>
 
@@ -41,9 +38,6 @@
 #define JZ_WDT_CLOCK_RTC  0x2
 #define JZ_WDT_CLOCK_EXT  0x4
 
-#define WDT_IN_USE        0
-#define WDT_OK_TO_CLOSE   1
-
 #define JZ_WDT_CLOCK_DIV_SHIFT   3
 
 #define JZ_WDT_CLOCK_DIV_1    (0 << JZ_WDT_CLOCK_DIV_SHIFT)
@@ -56,32 +50,44 @@
 #define DEFAULT_HEARTBEAT 5
 #define MAX_HEARTBEAT     2048
 
-static struct {
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+		 "Watchdog cannot be stopped once started (default="
+		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static unsigned int heartbeat = DEFAULT_HEARTBEAT;
+module_param(heartbeat, uint, 0);
+MODULE_PARM_DESC(heartbeat,
+		"Watchdog heartbeat period in seconds from 1 to "
+		__MODULE_STRING(MAX_HEARTBEAT) ", default "
+		__MODULE_STRING(DEFAULT_HEARTBEAT));
+
+struct jz4740_wdt_drvdata {
+	struct watchdog_device wdt;
 	void __iomem *base;
-	struct resource	*mem;
 	struct clk *rtc_clk;
-	unsigned long status;
-} jz4740_wdt;
+};
 
-static int heartbeat = DEFAULT_HEARTBEAT;
-
-
-static void jz4740_wdt_service(void)
+static int jz4740_wdt_ping(struct watchdog_device *wdt_dev)
 {
-	writew(0x0, jz4740_wdt.base + JZ_REG_WDT_TIMER_COUNTER);
+	struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
+
+	writew(0x0, drvdata->base + JZ_REG_WDT_TIMER_COUNTER);
+	return 0;
 }
 
-static void jz4740_wdt_set_heartbeat(int new_heartbeat)
+static int jz4740_wdt_set_timeout(struct watchdog_device *wdt_dev,
+				    unsigned int new_timeout)
 {
+	struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
 	unsigned int rtc_clk_rate;
 	unsigned int timeout_value;
 	unsigned short clock_div = JZ_WDT_CLOCK_DIV_1;
 
-	heartbeat = new_heartbeat;
+	rtc_clk_rate = clk_get_rate(drvdata->rtc_clk);
 
-	rtc_clk_rate = clk_get_rate(jz4740_wdt.rtc_clk);
-
-	timeout_value = rtc_clk_rate * heartbeat;
+	timeout_value = rtc_clk_rate * new_timeout;
 	while (timeout_value > 0xffff) {
 		if (clock_div == JZ_WDT_CLOCK_DIV_1024) {
 			/* Requested timeout too high;
@@ -93,199 +99,115 @@
 		clock_div += (1 << JZ_WDT_CLOCK_DIV_SHIFT);
 	}
 
-	writeb(0x0, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
-	writew(clock_div, jz4740_wdt.base + JZ_REG_WDT_TIMER_CONTROL);
+	writeb(0x0, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE);
+	writew(clock_div, drvdata->base + JZ_REG_WDT_TIMER_CONTROL);
 
-	writew((u16)timeout_value, jz4740_wdt.base + JZ_REG_WDT_TIMER_DATA);
-	writew(0x0, jz4740_wdt.base + JZ_REG_WDT_TIMER_COUNTER);
+	writew((u16)timeout_value, drvdata->base + JZ_REG_WDT_TIMER_DATA);
+	writew(0x0, drvdata->base + JZ_REG_WDT_TIMER_COUNTER);
 	writew(clock_div | JZ_WDT_CLOCK_RTC,
-		jz4740_wdt.base + JZ_REG_WDT_TIMER_CONTROL);
+		drvdata->base + JZ_REG_WDT_TIMER_CONTROL);
 
-	writeb(0x1, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
-}
+	writeb(0x1, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE);
 
-static void jz4740_wdt_enable(void)
-{
-	jz4740_timer_enable_watchdog();
-	jz4740_wdt_set_heartbeat(heartbeat);
-}
-
-static void jz4740_wdt_disable(void)
-{
-	jz4740_timer_disable_watchdog();
-	writeb(0x0, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
-}
-
-static int jz4740_wdt_open(struct inode *inode, struct file *file)
-{
-	if (test_and_set_bit(WDT_IN_USE, &jz4740_wdt.status))
-		return -EBUSY;
-
-	jz4740_wdt_enable();
-
-	return nonseekable_open(inode, file);
-}
-
-static ssize_t jz4740_wdt_write(struct file *file, const char *data,
-		size_t len, loff_t *ppos)
-{
-	if (len) {
-		size_t i;
-
-		clear_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status);
-		for (i = 0; i != len; i++) {
-			char c;
-
-			if (get_user(c, data + i))
-				return -EFAULT;
-
-			if (c == 'V')
-				set_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status);
-		}
-		jz4740_wdt_service();
-	}
-
-	return len;
-}
-
-static const struct watchdog_info ident = {
-	.options = WDIOF_KEEPALIVEPING,
-	.identity = "jz4740 Watchdog",
-};
-
-static long jz4740_wdt_ioctl(struct file *file,
-					unsigned int cmd, unsigned long arg)
-{
-	int ret = -ENOTTY;
-	int heartbeat_seconds;
-
-	switch (cmd) {
-	case WDIOC_GETSUPPORT:
-		ret = copy_to_user((struct watchdog_info *)arg, &ident,
-				sizeof(ident)) ? -EFAULT : 0;
-		break;
-
-	case WDIOC_GETSTATUS:
-	case WDIOC_GETBOOTSTATUS:
-		ret = put_user(0, (int *)arg);
-		break;
-
-	case WDIOC_KEEPALIVE:
-		jz4740_wdt_service();
-		return 0;
-
-	case WDIOC_SETTIMEOUT:
-		if (get_user(heartbeat_seconds, (int __user *)arg))
-			return -EFAULT;
-
-		jz4740_wdt_set_heartbeat(heartbeat_seconds);
-		return 0;
-
-	case WDIOC_GETTIMEOUT:
-		return put_user(heartbeat, (int *)arg);
-
-	default:
-		break;
-	}
-
-	return ret;
-}
-
-static int jz4740_wdt_release(struct inode *inode, struct file *file)
-{
-	jz4740_wdt_service();
-
-	if (test_and_clear_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status))
-		jz4740_wdt_disable();
-
-	clear_bit(WDT_IN_USE, &jz4740_wdt.status);
+	wdt_dev->timeout = new_timeout;
 	return 0;
 }
 
-static const struct file_operations jz4740_wdt_fops = {
-	.owner = THIS_MODULE,
-	.llseek = no_llseek,
-	.write = jz4740_wdt_write,
-	.unlocked_ioctl = jz4740_wdt_ioctl,
-	.open = jz4740_wdt_open,
-	.release = jz4740_wdt_release,
+static int jz4740_wdt_start(struct watchdog_device *wdt_dev)
+{
+	jz4740_timer_enable_watchdog();
+	jz4740_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
+
+	return 0;
+}
+
+static int jz4740_wdt_stop(struct watchdog_device *wdt_dev)
+{
+	struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
+
+	jz4740_timer_disable_watchdog();
+	writeb(0x0, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE);
+
+	return 0;
+}
+
+static const struct watchdog_info jz4740_wdt_info = {
+	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+	.identity = "jz4740 Watchdog",
 };
 
-static struct miscdevice jz4740_wdt_miscdev = {
-	.minor = WATCHDOG_MINOR,
-	.name = "watchdog",
-	.fops = &jz4740_wdt_fops,
+static const struct watchdog_ops jz4740_wdt_ops = {
+	.owner = THIS_MODULE,
+	.start = jz4740_wdt_start,
+	.stop = jz4740_wdt_stop,
+	.ping = jz4740_wdt_ping,
+	.set_timeout = jz4740_wdt_set_timeout,
 };
 
 static int __devinit jz4740_wdt_probe(struct platform_device *pdev)
 {
-	int ret = 0, size;
-	struct resource *res;
-	struct device *dev = &pdev->dev;
+	struct jz4740_wdt_drvdata *drvdata;
+	struct watchdog_device *jz4740_wdt;
+	struct resource	*res;
+	int ret;
+
+	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct jz4740_wdt_drvdata),
+			       GFP_KERNEL);
+	if (!drvdata) {
+		dev_err(&pdev->dev, "Unable to alloacate watchdog device\n");
+		return -ENOMEM;
+	}
+
+	if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
+		heartbeat = DEFAULT_HEARTBEAT;
+
+	jz4740_wdt = &drvdata->wdt;
+	jz4740_wdt->info = &jz4740_wdt_info;
+	jz4740_wdt->ops = &jz4740_wdt_ops;
+	jz4740_wdt->timeout = heartbeat;
+	jz4740_wdt->min_timeout = 1;
+	jz4740_wdt->max_timeout = MAX_HEARTBEAT;
+	watchdog_set_nowayout(jz4740_wdt, nowayout);
+	watchdog_set_drvdata(jz4740_wdt, drvdata);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL) {
-		dev_err(dev, "failed to get memory region resource\n");
-		return -ENXIO;
-	}
-
-	size = resource_size(res);
-	jz4740_wdt.mem = request_mem_region(res->start, size, pdev->name);
-	if (jz4740_wdt.mem == NULL) {
-		dev_err(dev, "failed to get memory region\n");
-		return -EBUSY;
-	}
-
-	jz4740_wdt.base = ioremap_nocache(res->start, size);
-	if (jz4740_wdt.base == NULL) {
-		dev_err(dev, "failed to map memory region\n");
+	drvdata->base = devm_request_and_ioremap(&pdev->dev, res);
+	if (drvdata->base == NULL) {
 		ret = -EBUSY;
-		goto err_release_region;
+		goto err_out;
 	}
 
-	jz4740_wdt.rtc_clk = clk_get(NULL, "rtc");
-	if (IS_ERR(jz4740_wdt.rtc_clk)) {
-		dev_err(dev, "cannot find RTC clock\n");
-		ret = PTR_ERR(jz4740_wdt.rtc_clk);
-		goto err_iounmap;
+	drvdata->rtc_clk = clk_get(NULL, "rtc");
+	if (IS_ERR(drvdata->rtc_clk)) {
+		dev_err(&pdev->dev, "cannot find RTC clock\n");
+		ret = PTR_ERR(drvdata->rtc_clk);
+		goto err_out;
 	}
 
-	ret = misc_register(&jz4740_wdt_miscdev);
-	if (ret < 0) {
-		dev_err(dev, "cannot register misc device\n");
+	ret = watchdog_register_device(&drvdata->wdt);
+	if (ret < 0)
 		goto err_disable_clk;
-	}
 
+	platform_set_drvdata(pdev, drvdata);
 	return 0;
 
 err_disable_clk:
-	clk_put(jz4740_wdt.rtc_clk);
-err_iounmap:
-	iounmap(jz4740_wdt.base);
-err_release_region:
-	release_mem_region(jz4740_wdt.mem->start,
-			resource_size(jz4740_wdt.mem));
+	clk_put(drvdata->rtc_clk);
+err_out:
 	return ret;
 }
 
-
 static int __devexit jz4740_wdt_remove(struct platform_device *pdev)
 {
-	jz4740_wdt_disable();
-	misc_deregister(&jz4740_wdt_miscdev);
-	clk_put(jz4740_wdt.rtc_clk);
+	struct jz4740_wdt_drvdata *drvdata = platform_get_drvdata(pdev);
 
-	iounmap(jz4740_wdt.base);
-	jz4740_wdt.base = NULL;
-
-	release_mem_region(jz4740_wdt.mem->start,
-				resource_size(jz4740_wdt.mem));
-	jz4740_wdt.mem = NULL;
+	jz4740_wdt_stop(&drvdata->wdt);
+	watchdog_unregister_device(&drvdata->wdt);
+	clk_put(drvdata->rtc_clk);
 
 	return 0;
 }
 
-
 static struct platform_driver jz4740_wdt_driver = {
 	.probe = jz4740_wdt_probe,
 	.remove = __devexit_p(jz4740_wdt_remove),
@@ -299,13 +221,6 @@
 
 MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
 MODULE_DESCRIPTION("jz4740 Watchdog Driver");
-
-module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat,
-		"Watchdog heartbeat period in seconds from 1 to "
-		__MODULE_STRING(MAX_HEARTBEAT) ", default "
-		__MODULE_STRING(DEFAULT_HEARTBEAT));
-
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 MODULE_ALIAS("platform:jz4740-wdt");
diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c
index 51757a5..59e75d9 100644
--- a/drivers/watchdog/ks8695_wdt.c
+++ b/drivers/watchdog/ks8695_wdt.c
@@ -8,6 +8,8 @@
  * published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -28,14 +30,14 @@
 #define WDT_MAX_TIME		171	/* seconds */
 
 static int wdt_time = WDT_DEFAULT_TIME;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 module_param(wdt_time, int, 0);
 MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
 					__MODULE_STRING(WDT_DEFAULT_TIME) ")");
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 #endif
@@ -233,8 +235,8 @@
 	if (res)
 		return res;
 
-	printk(KERN_INFO "KS8695 Watchdog Timer enabled (%d seconds%s)\n",
-				wdt_time, nowayout ? ", nowayout" : "");
+	pr_info("KS8695 Watchdog Timer enabled (%d seconds%s)\n",
+		wdt_time, nowayout ? ", nowayout" : "");
 	return 0;
 }
 
diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c
index d3a63be..a9593a3 100644
--- a/drivers/watchdog/lantiq_wdt.c
+++ b/drivers/watchdog/lantiq_wdt.c
@@ -7,6 +7,8 @@
  *  Based on EP93xx wdt driver
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
@@ -38,7 +40,7 @@
 #define LTQ_WDT_DIVIDER		0x40000
 #define LTQ_MAX_TIMEOUT		((1 << 16) - 1)	/* the reload field is 16 bit */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 static void __iomem *ltq_wdt_membase;
 static unsigned long ltq_io_region_clk_rate;
@@ -160,7 +162,7 @@
 	if (ltq_wdt_ok_to_close)
 		ltq_wdt_disable();
 	else
-		pr_err("ltq_wdt: watchdog closed without warning\n");
+		pr_err("watchdog closed without warning\n");
 	ltq_wdt_ok_to_close = 0;
 	clear_bit(0, &ltq_wdt_in_use);
 
@@ -249,7 +251,7 @@
 module_init(init_ltq_wdt);
 module_exit(exit_ltq_wdt);
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 
 MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
diff --git a/drivers/watchdog/m54xx_wdt.c b/drivers/watchdog/m54xx_wdt.c
index 4d43286..663cad8 100644
--- a/drivers/watchdog/m54xx_wdt.c
+++ b/drivers/watchdog/m54xx_wdt.c
@@ -16,6 +16,8 @@
  * warranty of any kind, whether express or implied.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -32,7 +34,7 @@
 #include <asm/m54xxsim.h>
 #include <asm/m54xxgpt.h>
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static unsigned int heartbeat = 30;	/* (secs) Default is 0.5 minute */
 static unsigned long wdt_status;
 
@@ -166,8 +168,7 @@
 	if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
 		wdt_disable();
 	else {
-		printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
-					"timer will not stop\n");
+		pr_crit("Device closed unexpectedly - timer will not stop\n");
 		wdt_keepalive();
 	}
 	clear_bit(WDT_IN_USE, &wdt_status);
@@ -196,11 +197,10 @@
 {
 	if (!request_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4,
 						"Coldfire M54xx Watchdog")) {
-		printk(KERN_WARNING
-				"Coldfire M54xx Watchdog : I/O region busy\n");
+		pr_warn("I/O region busy\n");
 		return -EBUSY;
 	}
-	printk(KERN_INFO "ColdFire watchdog driver is loaded.\n");
+	pr_info("driver is loaded\n");
 
 	return misc_register(&m54xx_wdt_miscdev);
 }
@@ -220,7 +220,7 @@
 module_param(heartbeat, int, 0);
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 30s)");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/machzwd.c b/drivers/watchdog/machzwd.c
index 1332b83..bf84f78 100644
--- a/drivers/watchdog/machzwd.c
+++ b/drivers/watchdog/machzwd.c
@@ -28,6 +28,8 @@
  *      Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -43,7 +45,6 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 
 /* ports */
 #define ZF_IOBASE	0x218
@@ -93,8 +94,8 @@
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -141,10 +142,10 @@
 #define ZF_CTIMEOUT 0xffff
 
 #ifndef ZF_DEBUG
-#	define dprintk(format, args...)
+#define dprintk(format, args...)
 #else
-#	define dprintk(format, args...) printk(KERN_DEBUG PFX \
-				":%s:%d: " format, __func__, __LINE__ , ## args)
+#define dprintk(format, args...)					\
+	pr_debug(":%s:%d: " format, __func__, __LINE__ , ## args)
 #endif
 
 
@@ -203,7 +204,7 @@
 	zf_set_control(ctrl_reg);
 	spin_unlock_irqrestore(&zf_port_lock, flags);
 
-	printk(KERN_INFO PFX ": Watchdog timer is now disabled\n");
+	pr_info("Watchdog timer is now disabled\n");
 }
 
 
@@ -233,7 +234,7 @@
 	zf_set_control(ctrl_reg);
 	spin_unlock_irqrestore(&zf_port_lock, flags);
 
-	printk(KERN_INFO PFX ": Watchdog timer is now enabled\n");
+	pr_info("Watchdog timer is now enabled\n");
 }
 
 
@@ -263,7 +264,7 @@
 
 		mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO);
 	} else
-		printk(KERN_CRIT PFX ": I will reset your machine\n");
+		pr_crit("I will reset your machine\n");
 }
 
 static ssize_t zf_write(struct file *file, const char __user *buf, size_t count,
@@ -342,8 +343,7 @@
 		zf_timer_off();
 	else {
 		del_timer(&zf_timer);
-		printk(KERN_ERR PFX ": device file closed unexpectedly. "
-						"Will not stop the WDT!\n");
+		pr_err("device file closed unexpectedly. Will not stop the WDT!\n");
 	}
 	clear_bit(0, &zf_is_open);
 	zf_expect_close = 0;
@@ -390,19 +390,18 @@
 {
 	static const char * const str[] = { "RESET", "SMI", "NMI", "SCI" };
 
-	printk(KERN_INFO PFX ": Watchdog using action = %s\n", str[act]);
+	pr_info("Watchdog using action = %s\n", str[act]);
 }
 
 static int __init zf_init(void)
 {
 	int ret;
 
-	printk(KERN_INFO PFX
-		": MachZ ZF-Logic Watchdog driver initializing.\n");
+	pr_info("MachZ ZF-Logic Watchdog driver initializing\n");
 
 	ret = zf_get_ZFL_version();
 	if (!ret || ret == 0xffff) {
-		printk(KERN_WARNING PFX ": no ZF-Logic found\n");
+		pr_warn("no ZF-Logic found\n");
 		return -ENODEV;
 	}
 
@@ -414,23 +413,20 @@
 	zf_show_action(action);
 
 	if (!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")) {
-		printk(KERN_ERR "cannot reserve I/O ports at %d\n",
-							ZF_IOBASE);
+		pr_err("cannot reserve I/O ports at %d\n", ZF_IOBASE);
 		ret = -EBUSY;
 		goto no_region;
 	}
 
 	ret = register_reboot_notifier(&zf_notifier);
 	if (ret) {
-		printk(KERN_ERR "can't register reboot notifier (err=%d)\n",
-									ret);
+		pr_err("can't register reboot notifier (err=%d)\n", ret);
 		goto no_reboot;
 	}
 
 	ret = misc_register(&zf_miscdev);
 	if (ret) {
-		printk(KERN_ERR "can't misc_register on minor=%d\n",
-							WATCHDOG_MINOR);
+		pr_err("can't misc_register on minor=%d\n", WATCHDOG_MINOR);
 		goto no_misc;
 	}
 
diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c
index af63ecf..8f4a74e 100644
--- a/drivers/watchdog/max63xx_wdt.c
+++ b/drivers/watchdog/max63xx_wdt.c
@@ -18,23 +18,20 @@
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
-#include <linux/uaccess.h>
 #include <linux/io.h>
-#include <linux/device.h>
 #include <linux/slab.h>
 
 #define DEFAULT_HEARTBEAT 60
 #define MAX_HEARTBEAT     60
 
-static int heartbeat = DEFAULT_HEARTBEAT;
-static int nowayout  = WATCHDOG_NOWAYOUT;
+static unsigned int heartbeat = DEFAULT_HEARTBEAT;
+static bool nowayout  = WATCHDOG_NOWAYOUT;
 
 /*
  * Memory mapping: a single byte, 3 first lower bits to select bit 3
@@ -45,15 +42,8 @@
 
 static DEFINE_SPINLOCK(io_lock);
 
-static unsigned long wdt_status;
-#define WDT_IN_USE	0
-#define WDT_RUNNING	1
-#define WDT_OK_TO_CLOSE 2
-
 static int nodelay;
-static struct resource	*wdt_mem;
 static void __iomem	*wdt_base;
-static struct platform_device *max63xx_pdev;
 
 /*
  * The timeout values used are actually the absolute minimum the chip
@@ -117,7 +107,7 @@
 	return NULL;
 }
 
-static void max63xx_wdt_ping(void)
+static int max63xx_wdt_ping(struct watchdog_device *wdd)
 {
 	u8 val;
 
@@ -129,15 +119,14 @@
 	__raw_writeb(val & ~MAX6369_WDI, wdt_base);
 
 	spin_unlock(&io_lock);
+	return 0;
 }
 
-static void max63xx_wdt_enable(struct max63xx_timeout *entry)
+static int max63xx_wdt_start(struct watchdog_device *wdd)
 {
+	struct max63xx_timeout *entry = watchdog_get_drvdata(wdd);
 	u8 val;
 
-	if (test_and_set_bit(WDT_RUNNING, &wdt_status))
-		return;
-
 	spin_lock(&io_lock);
 
 	val = __raw_readb(wdt_base);
@@ -149,10 +138,11 @@
 
 	/* check for a edge triggered startup */
 	if (entry->tdelay == 0)
-		max63xx_wdt_ping();
+		max63xx_wdt_ping(wdd);
+	return 0;
 }
 
-static void max63xx_wdt_disable(void)
+static int max63xx_wdt_stop(struct watchdog_device *wdd)
 {
 	u8 val;
 
@@ -164,113 +154,29 @@
 	__raw_writeb(val, wdt_base);
 
 	spin_unlock(&io_lock);
-
-	clear_bit(WDT_RUNNING, &wdt_status);
-}
-
-static int max63xx_wdt_open(struct inode *inode, struct file *file)
-{
-	if (test_and_set_bit(WDT_IN_USE, &wdt_status))
-		return -EBUSY;
-
-	max63xx_wdt_enable(current_timeout);
-	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-	return nonseekable_open(inode, file);
-}
-
-static ssize_t max63xx_wdt_write(struct file *file, const char *data,
-				 size_t len, loff_t *ppos)
-{
-	if (len) {
-		if (!nowayout) {
-			size_t i;
-
-			clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-			for (i = 0; i != len; i++) {
-				char c;
-
-				if (get_user(c, data + i))
-					return -EFAULT;
-
-				if (c == 'V')
-					set_bit(WDT_OK_TO_CLOSE, &wdt_status);
-			}
-		}
-
-		max63xx_wdt_ping();
-	}
-
-	return len;
-}
-
-static const struct watchdog_info ident = {
-	.options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
-	.identity = "max63xx Watchdog",
-};
-
-static long max63xx_wdt_ioctl(struct file *file, unsigned int cmd,
-			      unsigned long arg)
-{
-	int ret = -ENOTTY;
-
-	switch (cmd) {
-	case WDIOC_GETSUPPORT:
-		ret = copy_to_user((struct watchdog_info *)arg, &ident,
-				   sizeof(ident)) ? -EFAULT : 0;
-		break;
-
-	case WDIOC_GETSTATUS:
-	case WDIOC_GETBOOTSTATUS:
-		ret = put_user(0, (int *)arg);
-		break;
-
-	case WDIOC_KEEPALIVE:
-		max63xx_wdt_ping();
-		ret = 0;
-		break;
-
-	case WDIOC_GETTIMEOUT:
-		ret = put_user(heartbeat, (int *)arg);
-		break;
-	}
-	return ret;
-}
-
-static int max63xx_wdt_release(struct inode *inode, struct file *file)
-{
-	if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
-		max63xx_wdt_disable();
-	else
-		dev_crit(&max63xx_pdev->dev,
-			 "device closed unexpectedly - timer will not stop\n");
-
-	clear_bit(WDT_IN_USE, &wdt_status);
-	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
 	return 0;
 }
 
-static const struct file_operations max63xx_wdt_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.write		= max63xx_wdt_write,
-	.unlocked_ioctl	= max63xx_wdt_ioctl,
-	.open		= max63xx_wdt_open,
-	.release	= max63xx_wdt_release,
+static const struct watchdog_info max63xx_wdt_info = {
+	.options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+	.identity = "max63xx Watchdog",
 };
 
-static struct miscdevice max63xx_wdt_miscdev = {
-	.minor	= WATCHDOG_MINOR,
-	.name	= "watchdog",
-	.fops	= &max63xx_wdt_fops,
+static const struct watchdog_ops max63xx_wdt_ops = {
+	.owner = THIS_MODULE,
+	.start = max63xx_wdt_start,
+	.stop = max63xx_wdt_stop,
+	.ping = max63xx_wdt_ping,
+};
+
+static struct watchdog_device max63xx_wdt_dev = {
+	.info = &max63xx_wdt_info,
+	.ops = &max63xx_wdt_ops,
 };
 
 static int __devinit max63xx_wdt_probe(struct platform_device *pdev)
 {
-	int ret = 0;
-	int size;
-	struct device *dev = &pdev->dev;
+	struct resource	*wdt_mem;
 	struct max63xx_timeout *table;
 
 	table = (struct max63xx_timeout *)pdev->id_entry->driver_data;
@@ -278,68 +184,34 @@
 	if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
 		heartbeat = DEFAULT_HEARTBEAT;
 
-	dev_info(dev, "requesting %ds heartbeat\n", heartbeat);
+	dev_info(&pdev->dev, "requesting %ds heartbeat\n", heartbeat);
 	current_timeout = max63xx_select_timeout(table, heartbeat);
 
 	if (!current_timeout) {
-		dev_err(dev, "unable to satisfy heartbeat request\n");
+		dev_err(&pdev->dev, "unable to satisfy heartbeat request\n");
 		return -EINVAL;
 	}
 
-	dev_info(dev, "using %ds heartbeat with %ds initial delay\n",
+	dev_info(&pdev->dev, "using %ds heartbeat with %ds initial delay\n",
 		 current_timeout->twd, current_timeout->tdelay);
 
 	heartbeat = current_timeout->twd;
 
-	max63xx_pdev = pdev;
-
 	wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (wdt_mem == NULL) {
-		dev_err(dev, "failed to get memory region resource\n");
-		return -ENOENT;
-	}
+	wdt_base = devm_request_and_ioremap(&pdev->dev, wdt_mem);
+	if (!wdt_base)
+		return -ENOMEM;
 
-	size = resource_size(wdt_mem);
-	if (!request_mem_region(wdt_mem->start, size, pdev->name)) {
-		dev_err(dev, "failed to get memory region\n");
-		return -ENOENT;
-	}
+	max63xx_wdt_dev.timeout = heartbeat;
+	watchdog_set_nowayout(&max63xx_wdt_dev, nowayout);
+	watchdog_set_drvdata(&max63xx_wdt_dev, current_timeout);
 
-	wdt_base = ioremap(wdt_mem->start, size);
-	if (!wdt_base) {
-		dev_err(dev, "failed to map memory region\n");
-		ret = -ENOMEM;
-		goto out_request;
-	}
-
-	ret = misc_register(&max63xx_wdt_miscdev);
-	if (ret < 0) {
-		dev_err(dev, "cannot register misc device\n");
-		goto out_unmap;
-	}
-
-	return 0;
-
-out_unmap:
-	iounmap(wdt_base);
-out_request:
-	release_mem_region(wdt_mem->start, size);
-	wdt_mem = NULL;
-
-	return ret;
+	return watchdog_register_device(&max63xx_wdt_dev);
 }
 
 static int __devexit max63xx_wdt_remove(struct platform_device *pdev)
 {
-	misc_deregister(&max63xx_wdt_miscdev);
-	if (wdt_mem) {
-		release_mem_region(wdt_mem->start, resource_size(wdt_mem));
-		wdt_mem = NULL;
-	}
-
-	if (wdt_base)
-		iounmap(wdt_base);
-
+	watchdog_unregister_device(&max63xx_wdt_dev);
 	return 0;
 }
 
@@ -375,7 +247,7 @@
 		 __MODULE_STRING(MAX_HEARTBEAT) ", default "
 		 __MODULE_STRING(DEFAULT_HEARTBEAT));
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
diff --git a/drivers/watchdog/mixcomwd.c b/drivers/watchdog/mixcomwd.c
index bc820d1..37e4b52 100644
--- a/drivers/watchdog/mixcomwd.c
+++ b/drivers/watchdog/mixcomwd.c
@@ -39,9 +39,10 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define VERSION "0.6"
 #define WATCHDOG_NAME "mixcomwd"
-#define PFX WATCHDOG_NAME ": "
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -107,8 +108,8 @@
 static DEFINE_TIMER(mixcomwd_timer, mixcomwd_timerfun, 0, 0);
 static char expect_close;
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -156,15 +157,13 @@
 {
 	if (expect_close == 42) {
 		if (mixcomwd_timer_alive) {
-			printk(KERN_ERR PFX
-				"release called while internal timer alive");
+			pr_err("release called while internal timer alive\n");
 			return -EBUSY;
 		}
 		mixcomwd_timer_alive = 1;
 		mod_timer(&mixcomwd_timer, jiffies + 5 * HZ);
 	} else
-		printk(KERN_CRIT PFX
-		    "WDT device closed unexpectedly.  WDT will not stop!\n");
+		pr_crit("WDT device closed unexpectedly.  WDT will not stop!\n");
 
 	clear_bit(0, &mixcomwd_opened);
 	expect_close = 0;
@@ -274,22 +273,19 @@
 	}
 
 	if (!found) {
-		printk(KERN_ERR PFX
-			"No card detected, or port not available.\n");
+		pr_err("No card detected, or port not available\n");
 		return -ENODEV;
 	}
 
 	ret = misc_register(&mixcomwd_miscdev);
 	if (ret) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-					WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto error_misc_register_watchdog;
 	}
 
-	printk(KERN_INFO
-		"MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",
-					VERSION, watchdog_port);
+	pr_info("MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",
+		VERSION, watchdog_port);
 
 	return 0;
 
@@ -303,8 +299,7 @@
 {
 	if (!nowayout) {
 		if (mixcomwd_timer_alive) {
-			printk(KERN_WARNING PFX "I quit now, hardware will"
-			       " probably reboot!\n");
+			pr_warn("I quit now, hardware will probably reboot!\n");
 			del_timer_sync(&mixcomwd_timer);
 			mixcomwd_timer_alive = 0;
 		}
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
index 20feb4d..40f7bf1 100644
--- a/drivers/watchdog/mpc8xxx_wdt.c
+++ b/drivers/watchdog/mpc8xxx_wdt.c
@@ -17,6 +17,8 @@
  * option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -60,8 +62,8 @@
 MODULE_PARM_DESC(reset,
 	"Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
 		 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -96,7 +98,7 @@
 
 static void mpc8xxx_wdt_pr_warn(const char *msg)
 {
-	pr_crit("mpc8xxx_wdt: %s, expect the %s soon!\n", msg,
+	pr_crit("%s, expect the %s soon!\n", msg,
 		reset ? "reset" : "machine check exception");
 }
 
@@ -209,7 +211,7 @@
 
 	enabled = in_be32(&wd_base->swcrr) & SWCRR_SWEN;
 	if (!enabled && wdt_type->hw_enabled) {
-		pr_info("mpc8xxx_wdt: could not be enabled in software\n");
+		pr_info("could not be enabled in software\n");
 		ret = -ENOSYS;
 		goto err_unmap;
 	}
@@ -226,9 +228,8 @@
 		goto err_unmap;
 #endif
 
-	pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d "
-		"(%d seconds)\n", reset ? "reset" : "interrupt", timeout,
-		timeout_sec);
+	pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d (%d seconds)\n",
+		reset ? "reset" : "interrupt", timeout, timeout_sec);
 
 	/*
 	 * If the watchdog was previously enabled or we're running on
@@ -303,7 +304,7 @@
 	ret = misc_register(&mpc8xxx_wdt_miscdev);
 	if (ret) {
 		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
-			WATCHDOG_MINOR, ret);
+		       WATCHDOG_MINOR, ret);
 		return ret;
 	}
 	return 0;
diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c
index 82ccd36..7c741dc 100644
--- a/drivers/watchdog/mpcore_wdt.c
+++ b/drivers/watchdog/mpcore_wdt.c
@@ -19,6 +19,9 @@
  *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -44,7 +47,7 @@
 	char		expect_close;
 };
 
-static struct platform_device *mpcore_wdt_dev;
+static struct platform_device *mpcore_wdt_pdev;
 static DEFINE_SPINLOCK(wdt_lock);
 
 #define TIMER_MARGIN	60
@@ -54,8 +57,8 @@
 	"MPcore timer margin in seconds. (0 < mpcore_margin < 65536, default="
 				__MODULE_STRING(TIMER_MARGIN) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -148,7 +151,7 @@
  */
 static int mpcore_wdt_open(struct inode *inode, struct file *file)
 {
-	struct mpcore_wdt *wdt = platform_get_drvdata(mpcore_wdt_dev);
+	struct mpcore_wdt *wdt = platform_get_drvdata(mpcore_wdt_pdev);
 
 	if (test_and_set_bit(0, &wdt->timer_alive))
 		return -EBUSY;
@@ -298,9 +301,9 @@
  *	System shutdown handler.  Turn off the watchdog if we're
  *	restarting or halting the system.
  */
-static void mpcore_wdt_shutdown(struct platform_device *dev)
+static void mpcore_wdt_shutdown(struct platform_device *pdev)
 {
-	struct mpcore_wdt *wdt = platform_get_drvdata(dev);
+	struct mpcore_wdt *wdt = platform_get_drvdata(pdev);
 
 	if (system_state == SYSTEM_RESTART || system_state == SYSTEM_HALT)
 		mpcore_wdt_stop(wdt);
@@ -324,99 +327,79 @@
 	.fops		= &mpcore_wdt_fops,
 };
 
-static int __devinit mpcore_wdt_probe(struct platform_device *dev)
+static int __devinit mpcore_wdt_probe(struct platform_device *pdev)
 {
 	struct mpcore_wdt *wdt;
 	struct resource *res;
 	int ret;
 
 	/* We only accept one device, and it must have an id of -1 */
-	if (dev->id != -1)
+	if (pdev->id != -1)
 		return -ENODEV;
 
-	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-	if (!res) {
-		ret = -ENODEV;
-		goto err_out;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	wdt = devm_kzalloc(&pdev->dev, sizeof(struct mpcore_wdt), GFP_KERNEL);
+	if (!wdt)
+		return -ENOMEM;
+
+	wdt->dev = &pdev->dev;
+	wdt->irq = platform_get_irq(pdev, 0);
+	if (wdt->irq >= 0) {
+		ret = devm_request_irq(wdt->dev, wdt->irq, mpcore_wdt_fire, 0,
+				"mpcore_wdt", wdt);
+		if (ret) {
+			dev_printk(KERN_ERR, wdt->dev,
+					"cannot register IRQ%d for watchdog\n",
+					wdt->irq);
+			return ret;
+		}
 	}
 
-	wdt = kzalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
-	if (!wdt) {
-		ret = -ENOMEM;
-		goto err_out;
-	}
+	wdt->base = devm_ioremap(wdt->dev, res->start, resource_size(res));
+	if (!wdt->base)
+		return -ENOMEM;
 
-	wdt->dev = &dev->dev;
-	wdt->irq = platform_get_irq(dev, 0);
-	if (wdt->irq < 0) {
-		ret = -ENXIO;
-		goto err_free;
-	}
-	wdt->base = ioremap(res->start, resource_size(res));
-	if (!wdt->base) {
-		ret = -ENOMEM;
-		goto err_free;
-	}
-
-	mpcore_wdt_miscdev.parent = &dev->dev;
+	mpcore_wdt_miscdev.parent = &pdev->dev;
 	ret = misc_register(&mpcore_wdt_miscdev);
 	if (ret) {
 		dev_printk(KERN_ERR, wdt->dev,
 			"cannot register miscdev on minor=%d (err=%d)\n",
 							WATCHDOG_MINOR, ret);
-		goto err_misc;
-	}
-
-	ret = request_irq(wdt->irq, mpcore_wdt_fire, 0, "mpcore_wdt", wdt);
-	if (ret) {
-		dev_printk(KERN_ERR, wdt->dev,
-			"cannot register IRQ%d for watchdog\n", wdt->irq);
-		goto err_irq;
+		return ret;
 	}
 
 	mpcore_wdt_stop(wdt);
-	platform_set_drvdata(dev, wdt);
-	mpcore_wdt_dev = dev;
+	platform_set_drvdata(pdev, wdt);
+	mpcore_wdt_pdev = pdev;
 
 	return 0;
-
-err_irq:
-	misc_deregister(&mpcore_wdt_miscdev);
-err_misc:
-	iounmap(wdt->base);
-err_free:
-	kfree(wdt);
-err_out:
-	return ret;
 }
 
-static int __devexit mpcore_wdt_remove(struct platform_device *dev)
+static int __devexit mpcore_wdt_remove(struct platform_device *pdev)
 {
-	struct mpcore_wdt *wdt = platform_get_drvdata(dev);
-
-	platform_set_drvdata(dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 
 	misc_deregister(&mpcore_wdt_miscdev);
 
-	mpcore_wdt_dev = NULL;
+	mpcore_wdt_pdev = NULL;
 
-	free_irq(wdt->irq, wdt);
-	iounmap(wdt->base);
-	kfree(wdt);
 	return 0;
 }
 
 #ifdef CONFIG_PM
-static int mpcore_wdt_suspend(struct platform_device *dev, pm_message_t msg)
+static int mpcore_wdt_suspend(struct platform_device *pdev, pm_message_t msg)
 {
-	struct mpcore_wdt *wdt = platform_get_drvdata(dev);
+	struct mpcore_wdt *wdt = platform_get_drvdata(pdev);
 	mpcore_wdt_stop(wdt);		/* Turn the WDT off */
 	return 0;
 }
 
-static int mpcore_wdt_resume(struct platform_device *dev)
+static int mpcore_wdt_resume(struct platform_device *pdev)
 {
-	struct mpcore_wdt *wdt = platform_get_drvdata(dev);
+	struct mpcore_wdt *wdt = platform_get_drvdata(pdev);
 	/* re-activate timer */
 	if (test_bit(0, &wdt->timer_alive))
 		mpcore_wdt_start(wdt);
@@ -442,9 +425,6 @@
 	},
 };
 
-static char banner[] __initdata = KERN_INFO "MPcore Watchdog Timer: 0.1. "
-		"mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)\n";
-
 static int __init mpcore_wdt_init(void)
 {
 	/*
@@ -453,11 +433,12 @@
 	 */
 	if (mpcore_wdt_set_heartbeat(mpcore_margin)) {
 		mpcore_wdt_set_heartbeat(TIMER_MARGIN);
-		printk(KERN_INFO "mpcore_margin value must be 0 < mpcore_margin < 65536, using %d\n",
+		pr_info("mpcore_margin value must be 0 < mpcore_margin < 65536, using %d\n",
 			TIMER_MARGIN);
 	}
 
-	printk(banner, mpcore_noboot, mpcore_margin, nowayout);
+	pr_info("MPcore Watchdog Timer: 0.1. mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)\n",
+		mpcore_noboot, mpcore_margin, nowayout);
 
 	return platform_driver_register(&mpcore_wdt_driver);
 }
diff --git a/drivers/watchdog/mv64x60_wdt.c b/drivers/watchdog/mv64x60_wdt.c
index 97f8a48..c53d025 100644
--- a/drivers/watchdog/mv64x60_wdt.c
+++ b/drivers/watchdog/mv64x60_wdt.c
@@ -15,6 +15,8 @@
  * or implied.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -58,8 +60,8 @@
 static char expect_close;
 static DEFINE_SPINLOCK(mv64x60_wdt_spinlock);
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -100,7 +102,7 @@
 	if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_FALSE,
 				   MV64x60_WDC_ENABLE_SHIFT)) {
 		mv64x60_wdt_service();
-		printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");
+		pr_notice("watchdog activated\n");
 	}
 }
 
@@ -108,7 +110,7 @@
 {
 	if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE,
 				   MV64x60_WDC_ENABLE_SHIFT))
-		printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n");
+		pr_notice("watchdog deactivated\n");
 }
 
 static void mv64x60_wdt_set_timeout(unsigned int timeout)
@@ -139,8 +141,7 @@
 	if (expect_close == 42)
 		mv64x60_wdt_handler_disable();
 	else {
-		printk(KERN_CRIT
-		       "mv64x60_wdt: unexpected close, not stopping timer!\n");
+		pr_crit("unexpected close, not stopping timer!\n");
 		mv64x60_wdt_service();
 	}
 	expect_close = 0;
@@ -308,7 +309,7 @@
 
 static int __init mv64x60_wdt_init(void)
 {
-	printk(KERN_INFO "MV64x60 watchdog driver\n");
+	pr_info("MV64x60 watchdog driver\n");
 
 	return platform_driver_register(&mv64x60_wdt_driver);
 }
diff --git a/drivers/watchdog/nuc900_wdt.c b/drivers/watchdog/nuc900_wdt.c
index 529085b..ea4c744 100644
--- a/drivers/watchdog/nuc900_wdt.c
+++ b/drivers/watchdog/nuc900_wdt.c
@@ -55,8 +55,8 @@
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
 	"(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
 	"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
diff --git a/drivers/watchdog/nv_tco.c b/drivers/watchdog/nv_tco.c
index 809f41c..6bbb9ef 100644
--- a/drivers/watchdog/nv_tco.c
+++ b/drivers/watchdog/nv_tco.c
@@ -21,6 +21,8 @@
  *	Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -41,7 +43,6 @@
 #define TCO_VERSION "0.01"
 #define TCO_MODULE_NAME "NV_TCO"
 #define TCO_DRIVER_NAME   TCO_MODULE_NAME ", v" TCO_VERSION
-#define PFX TCO_MODULE_NAME ": "
 
 /* internal variables */
 static unsigned int tcobase;
@@ -60,8 +61,8 @@
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39, "
 			    "default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"
 		" (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -169,8 +170,7 @@
 	if (tco_expect_close == 42) {
 		tco_timer_stop();
 	} else {
-		printk(KERN_CRIT PFX "Unexpected close, not stopping "
-		       "watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		tco_timer_keepalive();
 	}
 	clear_bit(0, &timer_alive);
@@ -323,15 +323,14 @@
 	val &= 0xffff;
 	if (val == 0x0001 || val == 0x0000) {
 		/* Something is wrong here, bar isn't setup */
-		printk(KERN_ERR PFX "failed to get tcobase address\n");
+		pr_err("failed to get tcobase address\n");
 		return 0;
 	}
 	val &= 0xff00;
 	tcobase = val + 0x40;
 
 	if (!request_region(tcobase, 0x10, "NV TCO")) {
-		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-		       tcobase);
+		pr_err("I/O address 0x%04x already in use\n", tcobase);
 		return 0;
 	}
 
@@ -347,7 +346,7 @@
 
 	/* Disable SMI caused by TCO */
 	if (!request_region(MCP51_SMI_EN(tcobase), 4, "NV TCO")) {
-		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+		pr_err("I/O address 0x%04x already in use\n",
 		       MCP51_SMI_EN(tcobase));
 		goto out;
 	}
@@ -357,7 +356,7 @@
 	val = inl(MCP51_SMI_EN(tcobase));
 	release_region(MCP51_SMI_EN(tcobase), 4);
 	if (val & MCP51_SMI_EN_TCO) {
-		printk(KERN_ERR PFX "Could not disable SMI caused by TCO\n");
+		pr_err("Could not disable SMI caused by TCO\n");
 		goto out;
 	}
 
@@ -367,8 +366,7 @@
 	pci_write_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, val);
 	pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val);
 	if (!(val & MCP51_SMBUS_SETUP_B_TCO_REBOOT)) {
-		printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot "
-		       "disabled by hardware\n");
+		pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
 		goto out;
 	}
 
@@ -387,8 +385,8 @@
 		return -ENODEV;
 
 	/* Check to see if last reboot was due to watchdog timeout */
-	printk(KERN_INFO PFX "Watchdog reboot %sdetected.\n",
-	       inl(TCO_STS(tcobase)) & TCO_STS_TCO2TO_STS ? "" : "not ");
+	pr_info("Watchdog reboot %sdetected\n",
+		inl(TCO_STS(tcobase)) & TCO_STS_TCO2TO_STS ? "" : "not ");
 
 	/* Clear out the old status */
 	outl(TCO_STS_RESET, TCO_STS(tcobase));
@@ -400,14 +398,14 @@
 	if (tco_timer_set_heartbeat(heartbeat)) {
 		heartbeat = WATCHDOG_HEARTBEAT;
 		tco_timer_set_heartbeat(heartbeat);
-		printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39, "
-		       "using %d\n", heartbeat);
+		pr_info("heartbeat value must be 2<heartbeat<39, using %d\n",
+			heartbeat);
 	}
 
 	ret = misc_register(&nv_tco_miscdev);
 	if (ret != 0) {
-		printk(KERN_ERR PFX "cannot register miscdev on minor=%d "
-		       "(err=%d)\n", WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto unreg_region;
 	}
 
@@ -415,8 +413,8 @@
 
 	tco_timer_stop();
 
-	printk(KERN_INFO PFX "initialized (0x%04x). heartbeat=%d sec "
-	       "(nowayout=%d)\n", tcobase, heartbeat, nowayout);
+	pr_info("initialized (0x%04x). heartbeat=%d sec (nowayout=%d)\n",
+		tcobase, heartbeat, nowayout);
 
 	return 0;
 
@@ -439,8 +437,7 @@
 	pci_write_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, val);
 	pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val);
 	if (val & MCP51_SMBUS_SETUP_B_TCO_REBOOT) {
-		printk(KERN_CRIT PFX "Couldn't unset REBOOT bit.  Machine may "
-		       "soon reset\n");
+		pr_crit("Couldn't unset REBOOT bit.  Machine may soon reset\n");
 	}
 
 	/* Deregister */
@@ -483,8 +480,7 @@
 {
 	int err;
 
-	printk(KERN_INFO PFX "NV TCO WatchDog Timer Driver v%s\n",
-	       TCO_VERSION);
+	pr_info("NV TCO WatchDog Timer Driver v%s\n", TCO_VERSION);
 
 	err = platform_driver_register(&nv_tco_driver);
 	if (err)
@@ -508,7 +504,7 @@
 {
 	platform_device_unregister(nv_tco_platform_device);
 	platform_driver_unregister(&nv_tco_driver);
-	printk(KERN_INFO PFX "NV TCO Watchdog Module Unloaded.\n");
+	pr_info("NV TCO Watchdog Module Unloaded\n");
 }
 
 module_init(nv_tco_init_module);
diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c
index 7c0d863..4612088 100644
--- a/drivers/watchdog/octeon-wdt-main.c
+++ b/drivers/watchdog/octeon-wdt-main.c
@@ -52,6 +52,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/miscdevice.h>
 #include <linux/interrupt.h>
 #include <linux/watchdog.h>
@@ -95,8 +97,8 @@
 	"Watchdog heartbeat in seconds. (0 < heartbeat, default="
 				__MODULE_STRING(WD_TIMO) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, S_IRUGO);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, S_IRUGO);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -201,7 +203,7 @@
 	uasm_resolve_relocs(relocs, labels);
 
 	len = (int)(p - nmi_stage1_insns);
-	pr_debug("Synthesized NMI stage 1 handler (%d instructions).\n", len);
+	pr_debug("Synthesized NMI stage 1 handler (%d instructions)\n", len);
 
 	pr_debug("\t.set push\n");
 	pr_debug("\t.set noreorder\n");
@@ -627,7 +629,7 @@
 		do_coundown = 0;
 		octeon_wdt_ping();
 	} else {
-		pr_crit("octeon_wdt: WDT device closed unexpectedly.  WDT will not stop!\n");
+		pr_crit("WDT device closed unexpectedly.  WDT will not stop!\n");
 	}
 	clear_bit(0, &octeon_wdt_is_open);
 	expect_close = 0;
@@ -684,12 +686,12 @@
 
 	octeon_wdt_calc_parameters(heartbeat);
 
-	pr_info("octeon_wdt: Initial granularity %d Sec.\n", timeout_sec);
+	pr_info("Initial granularity %d Sec\n", timeout_sec);
 
 	ret = misc_register(&octeon_wdt_miscdev);
 	if (ret) {
-		pr_err("octeon_wdt: cannot register miscdev on minor=%d (err=%d)\n",
-			WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto out;
 	}
 
diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c
index f359ab8..55d2f66 100644
--- a/drivers/watchdog/of_xilinx_wdt.c
+++ b/drivers/watchdog/of_xilinx_wdt.c
@@ -19,6 +19,8 @@
 *		  know the wdt reset interval
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -99,7 +101,7 @@
 	iowrite32(0, xdev.base + XWT_TWCSR1_OFFSET);
 
 	spin_unlock(&spinlock);
-	printk(KERN_INFO PFX "Stopped!\n");
+	pr_info("Stopped!\n");
 }
 
 static void xwdt_keepalive(void)
@@ -165,7 +167,7 @@
 		__module_get(THIS_MODULE);
 
 	xwdt_start();
-	printk(KERN_INFO PFX "Started...\n");
+	pr_info("Started...\n");
 
 	return nonseekable_open(inode, file);
 }
@@ -175,8 +177,7 @@
 	if (expect_close == 42) {
 		xwdt_stop();
 	} else {
-		printk(KERN_CRIT PFX
-			"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		xwdt_keepalive();
 	}
 
@@ -300,22 +301,20 @@
 					"clock-frequency", NULL);
 
 	if (pfreq == NULL) {
-		printk(KERN_WARNING PFX
-			"The watchdog clock frequency cannot be obtained!\n");
+		pr_warn("The watchdog clock frequency cannot be obtained!\n");
 		no_timeout = 1;
 	}
 
 	rc = of_address_to_resource(pdev->dev.of_node, 0, &xdev.res);
 	if (rc) {
-		printk(KERN_WARNING PFX "invalid address!\n");
+		pr_warn("invalid address!\n");
 		return rc;
 	}
 
 	tmptr = (u32 *)of_get_property(pdev->dev.of_node,
 					"xlnx,wdt-interval", NULL);
 	if (tmptr == NULL) {
-		printk(KERN_WARNING PFX "Parameter \"xlnx,wdt-interval\""
-					" not found in device tree!\n");
+		pr_warn("Parameter \"xlnx,wdt-interval\" not found in device tree!\n");
 		no_timeout = 1;
 	} else {
 		xdev.wdt_interval = *tmptr;
@@ -324,8 +323,7 @@
 	tmptr = (u32 *)of_get_property(pdev->dev.of_node,
 					"xlnx,wdt-enable-once", NULL);
 	if (tmptr == NULL) {
-		printk(KERN_WARNING PFX "Parameter \"xlnx,wdt-enable-once\""
-					" not found in device tree!\n");
+		pr_warn("Parameter \"xlnx,wdt-enable-once\" not found in device tree!\n");
 		xdev.nowayout = WATCHDOG_NOWAYOUT;
 	}
 
@@ -339,20 +337,20 @@
 	if (!request_mem_region(xdev.res.start,
 			xdev.res.end - xdev.res.start + 1, WATCHDOG_NAME)) {
 		rc = -ENXIO;
-		printk(KERN_ERR PFX "memory request failure!\n");
+		pr_err("memory request failure!\n");
 		goto err_out;
 	}
 
 	xdev.base = ioremap(xdev.res.start, xdev.res.end - xdev.res.start + 1);
 	if (xdev.base == NULL) {
 		rc = -ENOMEM;
-		printk(KERN_ERR PFX "ioremap failure!\n");
+		pr_err("ioremap failure!\n");
 		goto release_mem;
 	}
 
 	rc = xwdt_selftest();
 	if (rc == XWT_TIMER_FAILED) {
-		printk(KERN_ERR PFX "SelfTest routine error!\n");
+		pr_err("SelfTest routine error!\n");
 		goto unmap_io;
 	}
 
@@ -360,20 +358,17 @@
 
 	rc = misc_register(&xwdt_miscdev);
 	if (rc) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-						xwdt_miscdev.minor, rc);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       xwdt_miscdev.minor, rc);
 		goto unmap_io;
 	}
 
 	if (no_timeout)
-		printk(KERN_INFO PFX
-			"driver loaded (timeout=? sec, nowayout=%d)\n",
-						    xdev.nowayout);
+		pr_info("driver loaded (timeout=? sec, nowayout=%d)\n",
+			xdev.nowayout);
 	else
-		printk(KERN_INFO PFX
-			"driver loaded (timeout=%d sec, nowayout=%d)\n",
-					timeout, xdev.nowayout);
+		pr_info("driver loaded (timeout=%d sec, nowayout=%d)\n",
+			timeout, xdev.nowayout);
 
 	expect_close = 0;
 	clear_bit(0, &driver_open);
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index d19ff51..8285d65 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -26,6 +26,8 @@
  *	Use the driver model and standard identifiers; handle bigger timeouts.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -183,7 +185,7 @@
 
 	pm_runtime_put_sync(wdev->dev);
 #else
-	printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
+	pr_crit("Unexpected close, not stopping!\n");
 #endif
 	wdev->omap_wdt_users = 0;
 
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 4ad78f8..788aa15 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -10,6 +10,8 @@
  * warranty of any kind, whether express or implied.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -28,18 +30,19 @@
 /*
  * Watchdog timer block registers.
  */
-#define TIMER_CTRL		(TIMER_VIRT_BASE + 0x0000)
+#define TIMER_CTRL		0x0000
 #define  WDT_EN			0x0010
-#define WDT_VAL			(TIMER_VIRT_BASE + 0x0024)
+#define WDT_VAL			0x0024
 
 #define WDT_MAX_CYCLE_COUNT	0xffffffff
 #define WDT_IN_USE		0
 #define WDT_OK_TO_CLOSE		1
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static int heartbeat = -1;		/* module parameter (seconds) */
 static unsigned int wdt_max_duration;	/* (seconds) */
 static unsigned int wdt_tclk;
+static void __iomem *wdt_reg;
 static unsigned long wdt_status;
 static DEFINE_SPINLOCK(wdt_lock);
 
@@ -48,7 +51,7 @@
 	spin_lock(&wdt_lock);
 
 	/* Reload watchdog duration */
-	writel(wdt_tclk * heartbeat, WDT_VAL);
+	writel(wdt_tclk * heartbeat, wdt_reg + WDT_VAL);
 
 	spin_unlock(&wdt_lock);
 }
@@ -60,7 +63,7 @@
 	spin_lock(&wdt_lock);
 
 	/* Set watchdog duration */
-	writel(wdt_tclk * heartbeat, WDT_VAL);
+	writel(wdt_tclk * heartbeat, wdt_reg + WDT_VAL);
 
 	/* Clear watchdog timer interrupt */
 	reg = readl(BRIDGE_CAUSE);
@@ -68,9 +71,9 @@
 	writel(reg, BRIDGE_CAUSE);
 
 	/* Enable watchdog timer */
-	reg = readl(TIMER_CTRL);
+	reg = readl(wdt_reg + TIMER_CTRL);
 	reg |= WDT_EN;
-	writel(reg, TIMER_CTRL);
+	writel(reg, wdt_reg + TIMER_CTRL);
 
 	/* Enable reset on watchdog */
 	reg = readl(RSTOUTn_MASK);
@@ -92,9 +95,9 @@
 	writel(reg, RSTOUTn_MASK);
 
 	/* Disable watchdog timer */
-	reg = readl(TIMER_CTRL);
+	reg = readl(wdt_reg + TIMER_CTRL);
 	reg &= ~WDT_EN;
-	writel(reg, TIMER_CTRL);
+	writel(reg, wdt_reg + TIMER_CTRL);
 
 	spin_unlock(&wdt_lock);
 }
@@ -102,7 +105,7 @@
 static int orion_wdt_get_timeleft(int *time_left)
 {
 	spin_lock(&wdt_lock);
-	*time_left = readl(WDT_VAL) / wdt_tclk;
+	*time_left = readl(wdt_reg + WDT_VAL) / wdt_tclk;
 	spin_unlock(&wdt_lock);
 	return 0;
 }
@@ -209,8 +212,7 @@
 	if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
 		orion_wdt_disable();
 	else
-		printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
-					"timer will not stop\n");
+		pr_crit("Device closed unexpectedly - timer will not stop\n");
 	clear_bit(WDT_IN_USE, &wdt_status);
 	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
 
@@ -236,15 +238,20 @@
 static int __devinit orion_wdt_probe(struct platform_device *pdev)
 {
 	struct orion_wdt_platform_data *pdata = pdev->dev.platform_data;
+	struct resource *res;
 	int ret;
 
 	if (pdata) {
 		wdt_tclk = pdata->tclk;
 	} else {
-		printk(KERN_ERR "Orion Watchdog misses platform data\n");
+		pr_err("misses platform data\n");
 		return -ENODEV;
 	}
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	wdt_reg = ioremap(res->start, resource_size(res));
+
 	if (orion_wdt_miscdev.parent)
 		return -EBUSY;
 	orion_wdt_miscdev.parent = &pdev->dev;
@@ -257,8 +264,8 @@
 	if (ret)
 		return ret;
 
-	printk(KERN_INFO "Orion Watchdog Timer: Initial timeout %d sec%s\n",
-				heartbeat, nowayout ? ", nowayout" : "");
+	pr_info("Initial timeout %d sec%s\n",
+		heartbeat, nowayout ? ", nowayout" : "");
 	return 0;
 }
 
@@ -302,7 +309,7 @@
 module_param(heartbeat, int, 0);
 MODULE_PARM_DESC(heartbeat, "Initial watchdog heartbeat in seconds");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
diff --git a/drivers/watchdog/pc87413_wdt.c b/drivers/watchdog/pc87413_wdt.c
index e78d899..5afb89b 100644
--- a/drivers/watchdog/pc87413_wdt.c
+++ b/drivers/watchdog/pc87413_wdt.c
@@ -18,6 +18,8 @@
  *      Release 1.1
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/miscdevice.h>
@@ -33,7 +35,6 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 
 /* #define DEBUG 1 */
 
@@ -42,7 +43,6 @@
 
 #define VERSION             "1.1"
 #define MODNAME             "pc87413 WDT"
-#define PFX                 MODNAME ": "
 #define DPFX                MODNAME " - DEBUG: "
 
 #define WDT_INDEX_IO_PORT   (io+0)	/* I/O port base (index register) */
@@ -65,7 +65,7 @@
 
 static DEFINE_SPINLOCK(io_lock);	/* to guard us from io races */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 /* -- Low level function ----------------------------------------*/
 
@@ -87,7 +87,7 @@
 	outb_p(cr_data, WDT_DATA_IO_PORT);
 
 #ifdef DEBUG
-	printk(KERN_INFO DPFX
+	pr_info(DPFX
 		"Select multiple pin,pin55,as WDT output: Bit7 to 1: %d\n",
 								cr_data);
 #endif
@@ -111,7 +111,7 @@
 	outb_p(cr_data, WDT_DATA_IO_PORT);	/* Index0x30_bit0P1 */
 
 #ifdef DEBUG
-	printk(KERN_INFO DPFX "pc87413 - Enable SWC functions\n");
+	pr_info(DPFX "pc87413 - Enable SWC functions\n");
 #endif
 }
 
@@ -132,7 +132,7 @@
 
 	swc_base_addr = (addr_h << 8) + addr_l;
 #ifdef DEBUG
-	printk(KERN_INFO DPFX
+	pr_info(DPFX
 		"Read SWC I/O Base Address: low %d, high %d, res %d\n",
 						addr_l, addr_h, swc_base_addr);
 #endif
@@ -145,7 +145,7 @@
 	/* Step 4: Select Bank3 of SWC */
 	outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f);
 #ifdef DEBUG
-	printk(KERN_INFO DPFX "Select Bank3 of SWC\n");
+	pr_info(DPFX "Select Bank3 of SWC\n");
 #endif
 }
 
@@ -156,7 +156,7 @@
 	/* Step 5: Programm WDTO, Twd. */
 	outb_p(pc87413_time, swc_base_addr + WDTO);
 #ifdef DEBUG
-	printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time);
+	pr_info(DPFX "Set WDTO to %d minutes\n", pc87413_time);
 #endif
 }
 
@@ -167,7 +167,7 @@
 	/* Step 6: Enable WDEN */
 	outb_p(inb(swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL);
 #ifdef DEBUG
-	printk(KERN_INFO DPFX "Enable WDEN\n");
+	pr_info(DPFX "Enable WDEN\n");
 #endif
 }
 
@@ -177,7 +177,7 @@
 	/* Enable SW_WD_TREN */
 	outb_p(inb(swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG);
 #ifdef DEBUG
-	printk(KERN_INFO DPFX "Enable SW_WD_TREN\n");
+	pr_info(DPFX "Enable SW_WD_TREN\n");
 #endif
 }
 
@@ -188,7 +188,7 @@
 	/* Disable SW_WD_TREN */
 	outb_p(inb(swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG);
 #ifdef DEBUG
-	printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n");
+	pr_info(DPFX "pc87413 - Disable SW_WD_TREN\n");
 #endif
 }
 
@@ -199,7 +199,7 @@
 	/* Enable SW_WD_TRG */
 	outb_p(inb(swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL);
 #ifdef DEBUG
-	printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n");
+	pr_info(DPFX "pc87413 - Enable SW_WD_TRG\n");
 #endif
 }
 
@@ -210,7 +210,7 @@
 	/* Disable SW_WD_TRG */
 	outb_p(inb(swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL);
 #ifdef DEBUG
-	printk(KERN_INFO DPFX "Disable SW_WD_TRG\n");
+	pr_info(DPFX "Disable SW_WD_TRG\n");
 #endif
 }
 
@@ -284,8 +284,7 @@
 	/* Reload and activate timer */
 	pc87413_refresh();
 
-	printk(KERN_INFO MODNAME
-		"Watchdog enabled. Timeout set to %d minute(s).\n", timeout);
+	pr_info("Watchdog enabled. Timeout set to %d minute(s).\n", timeout);
 
 	return nonseekable_open(inode, file);
 }
@@ -308,11 +307,9 @@
 
 	if (expect_close == 42) {
 		pc87413_disable();
-		printk(KERN_INFO MODNAME
-				"Watchdog disabled, sleeping again...\n");
+		pr_info("Watchdog disabled, sleeping again...\n");
 	} else {
-		printk(KERN_CRIT MODNAME
-				"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		pc87413_refresh();
 	}
 	clear_bit(0, &timer_enabled);
@@ -428,7 +425,7 @@
 	case WDIOC_KEEPALIVE:
 		pc87413_refresh();
 #ifdef DEBUG
-		printk(KERN_INFO DPFX "keepalive\n");
+		pr_info(DPFX "keepalive\n");
 #endif
 		return 0;
 	case WDIOC_SETTIMEOUT:
@@ -508,7 +505,7 @@
 {
 	int ret;
 
-	printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n",
+	pr_info("Version " VERSION " at io 0x%X\n",
 							WDT_INDEX_IO_PORT);
 
 	if (!request_muxed_region(io, 2, MODNAME))
@@ -516,26 +513,23 @@
 
 	ret = register_reboot_notifier(&pc87413_notifier);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", ret);
+		pr_err("cannot register reboot notifier (err=%d)\n", ret);
 	}
 
 	ret = misc_register(&pc87413_miscdev);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-			WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto reboot_unreg;
 	}
-	printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout);
+	pr_info("initialized. timeout=%d min\n", timeout);
 
 	pc87413_select_wdt_out();
 	pc87413_enable_swc();
 	pc87413_get_swc_base_addr();
 
 	if (!request_region(swc_base_addr, 0x20, MODNAME)) {
-		printk(KERN_ERR PFX
-			"cannot request SWC region at 0x%x\n", swc_base_addr);
+		pr_err("cannot request SWC region at 0x%x\n", swc_base_addr);
 		ret = -EBUSY;
 		goto misc_unreg;
 	}
@@ -568,14 +562,14 @@
 	/* Stop the timer before we leave */
 	if (!nowayout) {
 		pc87413_disable();
-		printk(KERN_INFO MODNAME "Watchdog disabled.\n");
+		pr_info("Watchdog disabled\n");
 	}
 
 	misc_deregister(&pc87413_miscdev);
 	unregister_reboot_notifier(&pc87413_notifier);
 	release_region(swc_base_addr, 0x20);
 
-	printk(KERN_INFO MODNAME " watchdog component driver removed.\n");
+	pr_info("watchdog component driver removed\n");
 }
 
 module_init(pc87413_init);
@@ -597,7 +591,7 @@
 		"Watchdog timeout in minutes (default="
 				__MODULE_STRING(DEFAULT_TIMEOUT) ").");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/pcwd.c b/drivers/watchdog/pcwd.c
index 06f7922..75694cf 100644
--- a/drivers/watchdog/pcwd.c
+++ b/drivers/watchdog/pcwd.c
@@ -51,6 +51,8 @@
  *	http://www.pcwatchdog.com/
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>	/* For module specific items */
 #include <linux/moduleparam.h>	/* For new moduleparam's */
 #include <linux/types.h>	/* For standard types (like size_t) */
@@ -75,7 +77,6 @@
 #define WATCHDOG_DATE "18 Feb 2007"
 #define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog"
 #define WATCHDOG_NAME "pcwd"
-#define PFX WATCHDOG_NAME ": "
 #define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION "\n"
 
 /*
@@ -203,8 +204,8 @@
 	"(2 <= heartbeat <= 7200 or 0=delay-time from dip-switches, default="
 				__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -220,8 +221,7 @@
 	int port0, last_port0;	/* Double read for stabilising */
 
 	if (debug >= DEBUG)
-		printk(KERN_DEBUG PFX "sending following data cmd=0x%02x\n",
-			cmd);
+		pr_debug("sending following data cmd=0x%02x\n", cmd);
 
 	/* The WCMD bit must be 1 and the command is only 4 bits in size */
 	control_status = (cmd & 0x0F) | WD_WCMD;
@@ -240,9 +240,8 @@
 	}
 
 	if (debug >= DEBUG)
-		printk(KERN_DEBUG PFX "received following data for "
-			"cmd=0x%02x: port0=0x%02x last_port0=0x%02x\n",
-			cmd, port0, last_port0);
+		pr_debug("received following data for cmd=0x%02x: port0=0x%02x last_port0=0x%02x\n",
+			 cmd, port0, last_port0);
 
 	return port0;
 }
@@ -271,8 +270,7 @@
 	pcwd_private.command_mode = found;
 
 	if (debug >= DEBUG)
-		printk(KERN_DEBUG PFX "command_mode=%d\n",
-				pcwd_private.command_mode);
+		pr_debug("command_mode=%d\n", pcwd_private.command_mode);
 
 	return found;
 }
@@ -288,8 +286,7 @@
 	pcwd_private.command_mode = 0;
 
 	if (debug >= DEBUG)
-		printk(KERN_DEBUG PFX "command_mode=%d\n",
-				pcwd_private.command_mode);
+		pr_debug("command_mode=%d\n", pcwd_private.command_mode);
 }
 
 static inline void pcwd_check_temperature_support(void)
@@ -336,17 +333,14 @@
 
 	/* Get some extra info from the hardware (in command/debug/diag mode) */
 	if (pcwd_private.revision == PCWD_REVISION_A)
-		printk(KERN_INFO PFX
-			"ISA-PC Watchdog (REV.A) detected at port 0x%04x\n",
-							pcwd_private.io_addr);
+		pr_info("ISA-PC Watchdog (REV.A) detected at port 0x%04x\n",
+			pcwd_private.io_addr);
 	else if (pcwd_private.revision == PCWD_REVISION_C) {
 		pcwd_get_firmware();
-		printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port "
-			"0x%04x (Firmware version: %s)\n",
+		pr_info("ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",
 			pcwd_private.io_addr, pcwd_private.fw_ver_str);
 		option_switches = pcwd_get_option_switches();
-		printk(KERN_INFO PFX "Option switches (0x%02x): "
-			"Temperature Reset Enable=%s, Power On Delay=%s\n",
+		pr_info("Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
 			option_switches,
 			((option_switches & 0x10) ? "ON" : "OFF"),
 			((option_switches & 0x08) ? "ON" : "OFF"));
@@ -359,22 +353,18 @@
 	}
 
 	if (pcwd_private.supports_temp)
-		printk(KERN_INFO PFX "Temperature Option Detected\n");
+		pr_info("Temperature Option Detected\n");
 
 	if (pcwd_private.boot_status & WDIOF_CARDRESET)
-		printk(KERN_INFO PFX
-			"Previous reboot was caused by the card\n");
+		pr_info("Previous reboot was caused by the card\n");
 
 	if (pcwd_private.boot_status & WDIOF_OVERHEAT) {
-		printk(KERN_EMERG PFX
-			"Card senses a CPU Overheat. Panicking!\n");
-		printk(KERN_EMERG PFX
-			"CPU Overheat\n");
+		pr_emerg("Card senses a CPU Overheat. Panicking!\n");
+		pr_emerg("CPU Overheat\n");
 	}
 
 	if (pcwd_private.boot_status == 0)
-		printk(KERN_INFO PFX
-			"No previous trip detected - Cold boot or reset\n");
+		pr_info("No previous trip detected - Cold boot or reset\n");
 }
 
 static void pcwd_timer_ping(unsigned long data)
@@ -404,8 +394,7 @@
 
 		spin_unlock(&pcwd_private.io_lock);
 	} else {
-		printk(KERN_WARNING PFX
-			"Heartbeat lost! Will not ping the watchdog\n");
+		pr_warn("Heartbeat lost! Will not ping the watchdog\n");
 	}
 }
 
@@ -426,13 +415,13 @@
 		stat_reg = inb_p(pcwd_private.io_addr + 2);
 		spin_unlock(&pcwd_private.io_lock);
 		if (stat_reg & WD_WDIS) {
-			printk(KERN_INFO PFX "Could not start watchdog\n");
+			pr_info("Could not start watchdog\n");
 			return -EIO;
 		}
 	}
 
 	if (debug >= VERBOSE)
-		printk(KERN_DEBUG PFX "Watchdog started\n");
+		pr_debug("Watchdog started\n");
 
 	return 0;
 }
@@ -454,13 +443,13 @@
 		stat_reg = inb_p(pcwd_private.io_addr + 2);
 		spin_unlock(&pcwd_private.io_lock);
 		if ((stat_reg & WD_WDIS) == 0) {
-			printk(KERN_INFO PFX "Could not stop watchdog\n");
+			pr_info("Could not stop watchdog\n");
 			return -EIO;
 		}
 	}
 
 	if (debug >= VERBOSE)
-		printk(KERN_DEBUG PFX "Watchdog stopped\n");
+		pr_debug("Watchdog stopped\n");
 
 	return 0;
 }
@@ -471,7 +460,7 @@
 	pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ);
 
 	if (debug >= DEBUG)
-		printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n");
+		pr_debug("Watchdog keepalive signal send\n");
 
 	return 0;
 }
@@ -484,8 +473,7 @@
 	heartbeat = t;
 
 	if (debug >= VERBOSE)
-		printk(KERN_DEBUG PFX "New heartbeat: %d\n",
-		       heartbeat);
+		pr_debug("New heartbeat: %d\n", heartbeat);
 
 	return 0;
 }
@@ -518,8 +506,7 @@
 		if (control_status & WD_T110) {
 			*status |= WDIOF_OVERHEAT;
 			if (temp_panic) {
-				printk(KERN_INFO PFX
-					"Temperature overheat trip!\n");
+				pr_info("Temperature overheat trip!\n");
 				kernel_power_off();
 			}
 		}
@@ -530,8 +517,7 @@
 		if (control_status & WD_REVC_TTRP) {
 			*status |= WDIOF_OVERHEAT;
 			if (temp_panic) {
-				printk(KERN_INFO PFX
-					"Temperature overheat trip!\n");
+				pr_info("Temperature overheat trip!\n");
 				kernel_power_off();
 			}
 		}
@@ -548,16 +534,14 @@
 		spin_lock(&pcwd_private.io_lock);
 
 		if (debug >= VERBOSE)
-			printk(KERN_INFO PFX
-					"clearing watchdog trip status\n");
+			pr_info("clearing watchdog trip status\n");
 
 		control_status = inb_p(pcwd_private.io_addr + 1);
 
 		if (debug >= DEBUG) {
-			printk(KERN_DEBUG PFX "status was: 0x%02x\n",
-				control_status);
-			printk(KERN_DEBUG PFX "sending: 0x%02x\n",
-				(control_status & WD_REVC_R2DS));
+			pr_debug("status was: 0x%02x\n", control_status);
+			pr_debug("sending: 0x%02x\n",
+				 (control_status & WD_REVC_R2DS));
 		}
 
 		/* clear reset status & Keep Relay 2 disable state as it is */
@@ -588,8 +572,7 @@
 	spin_unlock(&pcwd_private.io_lock);
 
 	if (debug >= DEBUG) {
-		printk(KERN_DEBUG PFX "temperature is: %d F\n",
-			*temperature);
+		pr_debug("temperature is: %d F\n", *temperature);
 	}
 
 	return 0;
@@ -720,8 +703,7 @@
 	if (expect_close == 42)
 		pcwd_stop();
 	else {
-		printk(KERN_CRIT PFX
-			"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		pcwd_keepalive();
 	}
 	expect_close = 0;
@@ -828,11 +810,10 @@
 	int retval;
 
 	if (debug >= DEBUG)
-		printk(KERN_DEBUG PFX "pcwd_isa_match id=%d\n",
-			id);
+		pr_debug("pcwd_isa_match id=%d\n", id);
 
 	if (!request_region(base_addr, 4, "PCWD")) {
-		printk(KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
+		pr_info("Port 0x%04x unavailable\n", base_addr);
 		return 0;
 	}
 
@@ -870,21 +851,20 @@
 	int ret;
 
 	if (debug >= DEBUG)
-		printk(KERN_DEBUG PFX "pcwd_isa_probe id=%d\n",
-			id);
+		pr_debug("pcwd_isa_probe id=%d\n", id);
 
 	cards_found++;
 	if (cards_found == 1)
-		printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n",
+		pr_info("v%s Ken Hollis (kenji@bitgate.com)\n",
 							WATCHDOG_VERSION);
 
 	if (cards_found > 1) {
-		printk(KERN_ERR PFX "This driver only supports 1 device\n");
+		pr_err("This driver only supports 1 device\n");
 		return -ENODEV;
 	}
 
 	if (pcwd_ioports[id] == 0x0000) {
-		printk(KERN_ERR PFX "No I/O-Address for card detected\n");
+		pr_err("No I/O-Address for card detected\n");
 		return -ENODEV;
 	}
 	pcwd_private.io_addr = pcwd_ioports[id];
@@ -896,8 +876,8 @@
 
 	if (!request_region(pcwd_private.io_addr,
 		(pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {
-		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-			pcwd_private.io_addr);
+		pr_err("I/O address 0x%04x already in use\n",
+		       pcwd_private.io_addr);
 		ret = -EIO;
 		goto error_request_region;
 	}
@@ -932,30 +912,27 @@
 	   if not reset to the default */
 	if (pcwd_set_heartbeat(heartbeat)) {
 		pcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
-		printk(KERN_INFO PFX
-		  "heartbeat value must be 2 <= heartbeat <= 7200, using %d\n",
-							WATCHDOG_HEARTBEAT);
+		pr_info("heartbeat value must be 2 <= heartbeat <= 7200, using %d\n",
+			WATCHDOG_HEARTBEAT);
 	}
 
 	if (pcwd_private.supports_temp) {
 		ret = misc_register(&temp_miscdev);
 		if (ret) {
-			printk(KERN_ERR PFX
-			    "cannot register miscdev on minor=%d (err=%d)\n",
-							TEMP_MINOR, ret);
+			pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+			       TEMP_MINOR, ret);
 			goto error_misc_register_temp;
 		}
 	}
 
 	ret = misc_register(&pcwd_miscdev);
 	if (ret) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-					WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto error_misc_register_watchdog;
 	}
 
-	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+	pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
 		heartbeat, nowayout);
 
 	return 0;
@@ -975,8 +952,7 @@
 static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id)
 {
 	if (debug >= DEBUG)
-		printk(KERN_DEBUG PFX "pcwd_isa_remove id=%d\n",
-			id);
+		pr_debug("pcwd_isa_remove id=%d\n", id);
 
 	if (!pcwd_private.io_addr)
 		return 1;
@@ -1000,8 +976,7 @@
 static void pcwd_isa_shutdown(struct device *dev, unsigned int id)
 {
 	if (debug >= DEBUG)
-		printk(KERN_DEBUG PFX "pcwd_isa_shutdown id=%d\n",
-			id);
+		pr_debug("pcwd_isa_shutdown id=%d\n", id);
 
 	pcwd_stop();
 }
@@ -1025,7 +1000,7 @@
 static void __exit pcwd_cleanup_module(void)
 {
 	isa_unregister_driver(&pcwd_isa_driver);
-	printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+	pr_info("Watchdog Module Unloaded\n");
 }
 
 module_init(pcwd_init_module);
diff --git a/drivers/watchdog/pcwd_pci.c b/drivers/watchdog/pcwd_pci.c
index b8d14f8..c891399 100644
--- a/drivers/watchdog/pcwd_pci.c
+++ b/drivers/watchdog/pcwd_pci.c
@@ -32,6 +32,8 @@
  *	Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>	/* For module specific items */
 #include <linux/moduleparam.h>	/* For new moduleparam's */
 #include <linux/types.h>	/* For standard types (like size_t) */
@@ -54,8 +56,7 @@
 #define WATCHDOG_VERSION "1.03"
 #define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
 #define WATCHDOG_NAME "pcwd_pci"
-#define PFX WATCHDOG_NAME ": "
-#define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION "\n"
+#define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION
 
 /* Stuff for the PCI ID's  */
 #ifndef PCI_VENDOR_ID_QUICKLOGIC
@@ -145,8 +146,8 @@
 	"(0<heartbeat<65536 or 0=delay-time from dip-switches, default="
 				__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 					__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -159,8 +160,8 @@
 	int got_response, count;
 
 	if (debug >= DEBUG)
-		printk(KERN_DEBUG PFX "sending following data "
-		"cmd=0x%02x msb=0x%02x lsb=0x%02x\n", cmd, *msb, *lsb);
+		pr_debug("sending following data cmd=0x%02x msb=0x%02x lsb=0x%02x\n",
+			 cmd, *msb, *lsb);
 
 	spin_lock(&pcipcwd_private.io_lock);
 	/* If a command requires data it should be written first.
@@ -185,12 +186,10 @@
 
 	if (debug >= DEBUG) {
 		if (got_response) {
-			printk(KERN_DEBUG PFX
-				"time to process command was: %d ms\n",
-				count);
+			pr_debug("time to process command was: %d ms\n",
+				 count);
 		} else {
-			printk(KERN_DEBUG PFX
-				"card did not respond on command!\n");
+			pr_debug("card did not respond on command!\n");
 		}
 	}
 
@@ -203,9 +202,8 @@
 		inb_p(pcipcwd_private.io_addr + 6);
 
 		if (debug >= DEBUG)
-			printk(KERN_DEBUG PFX "received following data for "
-				"cmd=0x%02x: msb=0x%02x lsb=0x%02x\n",
-				cmd, *msb, *lsb);
+			pr_debug("received following data for cmd=0x%02x: msb=0x%02x lsb=0x%02x\n",
+				 cmd, *msb, *lsb);
 	}
 
 	spin_unlock(&pcipcwd_private.io_lock);
@@ -243,27 +241,23 @@
 	/* Get switch settings */
 	option_switches = pcipcwd_get_option_switches();
 
-	printk(KERN_INFO PFX "Found card at port "
-		"0x%04x (Firmware: %s) %s temp option\n",
+	pr_info("Found card at port 0x%04x (Firmware: %s) %s temp option\n",
 		(int) pcipcwd_private.io_addr, fw_ver_str,
 		(pcipcwd_private.supports_temp ? "with" : "without"));
 
-	printk(KERN_INFO PFX "Option switches (0x%02x): "
-		"Temperature Reset Enable=%s, Power On Delay=%s\n",
+	pr_info("Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
 		option_switches,
 		((option_switches & 0x10) ? "ON" : "OFF"),
 		((option_switches & 0x08) ? "ON" : "OFF"));
 
 	if (pcipcwd_private.boot_status & WDIOF_CARDRESET)
-		printk(KERN_INFO PFX
-			"Previous reset was caused by the Watchdog card\n");
+		pr_info("Previous reset was caused by the Watchdog card\n");
 
 	if (pcipcwd_private.boot_status & WDIOF_OVERHEAT)
-		printk(KERN_INFO PFX "Card sensed a CPU Overheat\n");
+		pr_info("Card sensed a CPU Overheat\n");
 
 	if (pcipcwd_private.boot_status == 0)
-		printk(KERN_INFO PFX
-			"No previous trip detected - Cold boot or reset\n");
+		pr_info("No previous trip detected - Cold boot or reset\n");
 }
 
 static int pcipcwd_start(void)
@@ -278,12 +272,12 @@
 	spin_unlock(&pcipcwd_private.io_lock);
 
 	if (stat_reg & WD_PCI_WDIS) {
-		printk(KERN_ERR PFX "Card timer not enabled\n");
+		pr_err("Card timer not enabled\n");
 		return -1;
 	}
 
 	if (debug >= VERBOSE)
-		printk(KERN_DEBUG PFX "Watchdog started\n");
+		pr_debug("Watchdog started\n");
 
 	return 0;
 }
@@ -303,13 +297,12 @@
 	spin_unlock(&pcipcwd_private.io_lock);
 
 	if (!(stat_reg & WD_PCI_WDIS)) {
-		printk(KERN_ERR PFX
-			"Card did not acknowledge disable attempt\n");
+		pr_err("Card did not acknowledge disable attempt\n");
 		return -1;
 	}
 
 	if (debug >= VERBOSE)
-		printk(KERN_DEBUG PFX "Watchdog stopped\n");
+		pr_debug("Watchdog stopped\n");
 
 	return 0;
 }
@@ -322,7 +315,7 @@
 	spin_unlock(&pcipcwd_private.io_lock);
 
 	if (debug >= DEBUG)
-		printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n");
+		pr_debug("Watchdog keepalive signal send\n");
 
 	return 0;
 }
@@ -340,8 +333,7 @@
 
 	heartbeat = t;
 	if (debug >= VERBOSE)
-		printk(KERN_DEBUG PFX "New heartbeat: %d\n",
-		       heartbeat);
+		pr_debug("New heartbeat: %d\n", heartbeat);
 
 	return 0;
 }
@@ -357,12 +349,11 @@
 	if (control_status & WD_PCI_TTRP) {
 		*status |= WDIOF_OVERHEAT;
 		if (temp_panic)
-			panic(PFX "Temperature overheat trip!\n");
+			panic(KBUILD_MODNAME ": Temperature overheat trip!\n");
 	}
 
 	if (debug >= DEBUG)
-		printk(KERN_DEBUG PFX "Control Status #1: 0x%02x\n",
-		       control_status);
+		pr_debug("Control Status #1: 0x%02x\n", control_status);
 
 	return 0;
 }
@@ -374,14 +365,14 @@
 	int reset_counter;
 
 	if (debug >= VERBOSE)
-		printk(KERN_INFO PFX "clearing watchdog trip status & LED\n");
+		pr_info("clearing watchdog trip status & LED\n");
 
 	control_status = inb_p(pcipcwd_private.io_addr + 1);
 
 	if (debug >= DEBUG) {
-		printk(KERN_DEBUG PFX "status was: 0x%02x\n", control_status);
-		printk(KERN_DEBUG PFX "sending: 0x%02x\n",
-		       (control_status & WD_PCI_R2DS) | WD_PCI_WTRP);
+		pr_debug("status was: 0x%02x\n", control_status);
+		pr_debug("sending: 0x%02x\n",
+			 (control_status & WD_PCI_R2DS) | WD_PCI_WTRP);
 	}
 
 	/* clear trip status & LED and keep mode of relay 2 */
@@ -394,8 +385,7 @@
 	send_command(CMD_GET_CLEAR_RESET_COUNT, &msb, &reset_counter);
 
 	if (debug >= DEBUG) {
-		printk(KERN_DEBUG PFX "reset count was: 0x%02x\n",
-		       reset_counter);
+		pr_debug("reset count was: 0x%02x\n", reset_counter);
 	}
 
 	return 0;
@@ -418,8 +408,7 @@
 	*temperature = (*temperature * 9 / 5) + 32;
 
 	if (debug >= DEBUG) {
-		printk(KERN_DEBUG PFX "temperature is: %d F\n",
-		       *temperature);
+		pr_debug("temperature is: %d F\n", *temperature);
 	}
 
 	return 0;
@@ -437,8 +426,7 @@
 	*time_left = (msb << 8) + lsb;
 
 	if (debug >= VERBOSE)
-		printk(KERN_DEBUG PFX "Time left before next reboot: %d\n",
-		       *time_left);
+		pr_debug("Time left before next reboot: %d\n", *time_left);
 
 	return 0;
 }
@@ -583,8 +571,7 @@
 	/* /dev/watchdog can only be opened once */
 	if (test_and_set_bit(0, &is_active)) {
 		if (debug >= VERBOSE)
-			printk(KERN_ERR PFX
-				"Attempt to open already opened device.\n");
+			pr_err("Attempt to open already opened device\n");
 		return -EBUSY;
 	}
 
@@ -602,8 +589,7 @@
 	if (expect_release == 42) {
 		pcipcwd_stop();
 	} else {
-		printk(KERN_CRIT PFX
-			"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		pcipcwd_keepalive();
 	}
 	expect_release = 0;
@@ -703,20 +689,20 @@
 
 	cards_found++;
 	if (cards_found == 1)
-		printk(KERN_INFO PFX DRIVER_VERSION);
+		pr_info("%s\n", DRIVER_VERSION);
 
 	if (cards_found > 1) {
-		printk(KERN_ERR PFX "This driver only supports 1 device\n");
+		pr_err("This driver only supports 1 device\n");
 		return -ENODEV;
 	}
 
 	if (pci_enable_device(pdev)) {
-		printk(KERN_ERR PFX "Not possible to enable PCI Device\n");
+		pr_err("Not possible to enable PCI Device\n");
 		return -ENODEV;
 	}
 
 	if (pci_resource_start(pdev, 0) == 0x0000) {
-		printk(KERN_ERR PFX "No I/O-Address for card detected\n");
+		pr_err("No I/O-Address for card detected\n");
 		ret = -ENODEV;
 		goto err_out_disable_device;
 	}
@@ -725,8 +711,8 @@
 	pcipcwd_private.io_addr = pci_resource_start(pdev, 0);
 
 	if (pci_request_regions(pdev, WATCHDOG_NAME)) {
-		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-			(int) pcipcwd_private.io_addr);
+		pr_err("I/O address 0x%04x already in use\n",
+		       (int) pcipcwd_private.io_addr);
 		ret = -EIO;
 		goto err_out_disable_device;
 	}
@@ -755,36 +741,33 @@
 	 * if not reset to the default */
 	if (pcipcwd_set_heartbeat(heartbeat)) {
 		pcipcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
-		printk(KERN_INFO PFX
-			"heartbeat value must be 0<heartbeat<65536, using %d\n",
+		pr_info("heartbeat value must be 0<heartbeat<65536, using %d\n",
 			WATCHDOG_HEARTBEAT);
 	}
 
 	ret = register_reboot_notifier(&pcipcwd_notifier);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", ret);
+		pr_err("cannot register reboot notifier (err=%d)\n", ret);
 		goto err_out_release_region;
 	}
 
 	if (pcipcwd_private.supports_temp) {
 		ret = misc_register(&pcipcwd_temp_miscdev);
 		if (ret != 0) {
-			printk(KERN_ERR PFX "cannot register miscdev on "
-				"minor=%d (err=%d)\n", TEMP_MINOR, ret);
+			pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+			       TEMP_MINOR, ret);
 			goto err_out_unregister_reboot;
 		}
 	}
 
 	ret = misc_register(&pcipcwd_miscdev);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-			WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto err_out_misc_deregister;
 	}
 
-	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+	pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
 		heartbeat, nowayout);
 
 	return 0;
@@ -842,7 +825,7 @@
 {
 	pci_unregister_driver(&pcipcwd_driver);
 
-	printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+	pr_info("Watchdog Module Unloaded\n");
 }
 
 module_init(pcipcwd_init_module);
diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c
index d8de1dd..7b14d18 100644
--- a/drivers/watchdog/pcwd_usb.c
+++ b/drivers/watchdog/pcwd_usb.c
@@ -24,6 +24,8 @@
  *	http://www.berkprod.com/ or http://www.pcwatchdog.com/
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>	/* For module specific items */
 #include <linux/moduleparam.h>	/* For new moduleparam's */
 #include <linux/types.h>	/* For standard types (like size_t) */
@@ -42,17 +44,23 @@
 #include <linux/hid.h>		/* For HID_REQ_SET_REPORT & HID_DT_REPORT */
 #include <linux/uaccess.h>	/* For copy_to_user/put_user/... */
 
-
 #ifdef CONFIG_USB_DEBUG
-	static int debug = 1;
+static int debug = 1;
 #else
-	static int debug;
+static int debug;
 #endif
 
 /* Use our own dbg macro */
+
 #undef dbg
-#define dbg(format, arg...) \
-	do { if (debug) printk(KERN_DEBUG PFX format "\n" , ## arg); } while (0)
+#ifndef DEBUG
+#define DEBUG
+#endif
+#define dbg(format, ...)				\
+do {							\
+	if (debug)					\
+		pr_debug(format "\n", ##__VA_ARGS__);	\
+} while (0)
 
 /* Module and Version Information */
 #define DRIVER_VERSION "1.02"
@@ -60,7 +68,6 @@
 #define DRIVER_DESC "Berkshire USB-PC Watchdog driver"
 #define DRIVER_LICENSE "GPL"
 #define DRIVER_NAME "pcwd_usb"
-#define PFX DRIVER_NAME ": "
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -80,8 +87,8 @@
 	"(0<heartbeat<65536 or 0=delay-time from dip-switches, default="
 				__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -220,8 +227,8 @@
 resubmit:
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval)
-		printk(KERN_ERR PFX "can't resubmit intr, "
-			"usb_submit_urb failed with result %d\n", retval);
+		pr_err("can't resubmit intr, usb_submit_urb failed with result %d\n",
+		       retval);
 }
 
 static int usb_pcwd_send_command(struct usb_pcwd_private *usb_pcwd,
@@ -284,8 +291,7 @@
 								&msb, &lsb);
 
 	if ((retval == 0) || (lsb == 0)) {
-		printk(KERN_ERR PFX
-				"Card did not acknowledge enable attempt\n");
+		pr_err("Card did not acknowledge enable attempt\n");
 		return -1;
 	}
 
@@ -303,8 +309,7 @@
 								&msb, &lsb);
 
 	if ((retval == 0) || (lsb != 0)) {
-		printk(KERN_ERR PFX
-			"Card did not acknowledge disable attempt\n");
+		pr_err("Card did not acknowledge disable attempt\n");
 		return -1;
 	}
 
@@ -506,8 +511,7 @@
 	if (expect_release == 42) {
 		usb_pcwd_stop(usb_pcwd_device);
 	} else {
-		printk(KERN_CRIT PFX
-			"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		usb_pcwd_keepalive(usb_pcwd_device);
 	}
 	expect_release = 0;
@@ -627,7 +631,7 @@
 
 	cards_found++;
 	if (cards_found > 1) {
-		printk(KERN_ERR PFX "This driver only supports 1 device\n");
+		pr_err("This driver only supports 1 device\n");
 		return -ENODEV;
 	}
 
@@ -636,8 +640,7 @@
 
 	/* check out that we have a HID device */
 	if (!(iface_desc->desc.bInterfaceClass == USB_CLASS_HID)) {
-		printk(KERN_ERR PFX
-			"The device isn't a Human Interface Device\n");
+		pr_err("The device isn't a Human Interface Device\n");
 		return -ENODEV;
 	}
 
@@ -646,7 +649,7 @@
 
 	if (!usb_endpoint_is_int_in(endpoint)) {
 		/* we didn't find a Interrupt endpoint with direction IN */
-		printk(KERN_ERR PFX "Couldn't find an INTR & IN endpoint\n");
+		pr_err("Couldn't find an INTR & IN endpoint\n");
 		return -ENODEV;
 	}
 
@@ -657,7 +660,7 @@
 	/* allocate memory for our device and initialize it */
 	usb_pcwd = kzalloc(sizeof(struct usb_pcwd_private), GFP_KERNEL);
 	if (usb_pcwd == NULL) {
-		printk(KERN_ERR PFX "Out of memory\n");
+		pr_err("Out of memory\n");
 		goto error;
 	}
 
@@ -674,14 +677,14 @@
 	usb_pcwd->intr_buffer = usb_alloc_coherent(udev, usb_pcwd->intr_size,
 					GFP_ATOMIC, &usb_pcwd->intr_dma);
 	if (!usb_pcwd->intr_buffer) {
-		printk(KERN_ERR PFX "Out of memory\n");
+		pr_err("Out of memory\n");
 		goto error;
 	}
 
 	/* allocate the urb's */
 	usb_pcwd->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!usb_pcwd->intr_urb) {
-		printk(KERN_ERR PFX "Out of memory\n");
+		pr_err("Out of memory\n");
 		goto error;
 	}
 
@@ -694,7 +697,7 @@
 
 	/* register our interrupt URB with the USB system */
 	if (usb_submit_urb(usb_pcwd->intr_urb, GFP_KERNEL)) {
-		printk(KERN_ERR PFX "Problem registering interrupt URB\n");
+		pr_err("Problem registering interrupt URB\n");
 		retval = -EIO; /* failure */
 		goto error;
 	}
@@ -713,15 +716,13 @@
 	else
 		sprintf(fw_ver_str, "<card no answer>");
 
-	printk(KERN_INFO PFX "Found card (Firmware: %s) with temp option\n",
-		fw_ver_str);
+	pr_info("Found card (Firmware: %s) with temp option\n", fw_ver_str);
 
 	/* Get switch settings */
 	usb_pcwd_send_command(usb_pcwd, CMD_GET_DIP_SWITCH_SETTINGS, &dummy,
 							&option_switches);
 
-	printk(KERN_INFO PFX "Option switches (0x%02x): "
-		"Temperature Reset Enable=%s, Power On Delay=%s\n",
+	pr_info("Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
 		option_switches,
 		((option_switches & 0x10) ? "ON" : "OFF"),
 		((option_switches & 0x08) ? "ON" : "OFF"));
@@ -734,39 +735,34 @@
 	 * if not reset to the default */
 	if (usb_pcwd_set_heartbeat(usb_pcwd, heartbeat)) {
 		usb_pcwd_set_heartbeat(usb_pcwd, WATCHDOG_HEARTBEAT);
-		printk(KERN_INFO PFX
-			"heartbeat value must be 0<heartbeat<65536, using %d\n",
+		pr_info("heartbeat value must be 0<heartbeat<65536, using %d\n",
 			WATCHDOG_HEARTBEAT);
 	}
 
 	retval = register_reboot_notifier(&usb_pcwd_notifier);
 	if (retval != 0) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n",
-			retval);
+		pr_err("cannot register reboot notifier (err=%d)\n", retval);
 		goto error;
 	}
 
 	retval = misc_register(&usb_pcwd_temperature_miscdev);
 	if (retval != 0) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-			TEMP_MINOR, retval);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       TEMP_MINOR, retval);
 		goto err_out_unregister_reboot;
 	}
 
 	retval = misc_register(&usb_pcwd_miscdev);
 	if (retval != 0) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-			WATCHDOG_MINOR, retval);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, retval);
 		goto err_out_misc_deregister;
 	}
 
 	/* we can register the device now, as it is ready */
 	usb_set_intfdata(interface, usb_pcwd);
 
-	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+	pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
 		heartbeat, nowayout);
 
 	return 0;
@@ -824,7 +820,7 @@
 
 	mutex_unlock(&disconnect_mutex);
 
-	printk(KERN_INFO PFX "USB PC Watchdog disconnected\n");
+	pr_info("USB PC Watchdog disconnected\n");
 }
 
 module_usb_driver(usb_pcwd_driver);
diff --git a/drivers/watchdog/pika_wdt.c b/drivers/watchdog/pika_wdt.c
index 2d22e99..7d3d471 100644
--- a/drivers/watchdog/pika_wdt.c
+++ b/drivers/watchdog/pika_wdt.c
@@ -5,6 +5,8 @@
  *   Sean MacLennan <smaclennan@pikatech.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/module.h>
@@ -23,7 +25,6 @@
 #include <linux/of_platform.h>
 
 #define DRV_NAME "PIKA-WDT"
-#define PFX DRV_NAME ": "
 
 /* Hardware timeout in seconds */
 #define WDT_HW_TIMEOUT 2
@@ -38,8 +39,8 @@
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
 	"(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
 	"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -90,7 +91,7 @@
 		pikawdt_reset();
 		mod_timer(&pikawdt_private.timer, jiffies + WDT_TIMEOUT);
 	} else
-		printk(KERN_CRIT PFX "I will reset your machine !\n");
+		pr_crit("I will reset your machine !\n");
 }
 
 
@@ -228,14 +229,14 @@
 
 	np = of_find_compatible_node(NULL, NULL, "pika,fpga");
 	if (np == NULL) {
-		printk(KERN_ERR PFX "Unable to find fpga.\n");
+		pr_err("Unable to find fpga\n");
 		return -ENOENT;
 	}
 
 	pikawdt_private.fpga = of_iomap(np, 0);
 	of_node_put(np);
 	if (pikawdt_private.fpga == NULL) {
-		printk(KERN_ERR PFX "Unable to map fpga.\n");
+		pr_err("Unable to map fpga\n");
 		return -ENOMEM;
 	}
 
@@ -244,7 +245,7 @@
 	/* POST information is in the sd area. */
 	np = of_find_compatible_node(NULL, NULL, "pika,fpga-sd");
 	if (np == NULL) {
-		printk(KERN_ERR PFX "Unable to find fpga-sd.\n");
+		pr_err("Unable to find fpga-sd\n");
 		ret = -ENOENT;
 		goto out;
 	}
@@ -252,7 +253,7 @@
 	fpga = of_iomap(np, 0);
 	of_node_put(np);
 	if (fpga == NULL) {
-		printk(KERN_ERR PFX "Unable to map fpga-sd.\n");
+		pr_err("Unable to map fpga-sd\n");
 		ret = -ENOMEM;
 		goto out;
 	}
@@ -271,12 +272,12 @@
 
 	ret = misc_register(&pikawdt_miscdev);
 	if (ret) {
-		printk(KERN_ERR PFX "Unable to register miscdev.\n");
+		pr_err("Unable to register miscdev\n");
 		goto out;
 	}
 
-	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
-							heartbeat, nowayout);
+	pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
+		heartbeat, nowayout);
 	return 0;
 
 out:
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index dfae030..6b8432f 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -8,33 +8,32 @@
  * Based on sa1100 driver,
  * Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
  *
- * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
+ * 2005-2006 (c) MontaVista Software, Inc.
+ *
+ * (C) 2012 Wolfram Sang, Pengutronix
+ *
+ * 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.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/spinlock.h>
-#include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/err.h>
 #include <mach/hardware.h>
 
-#define MODULE_NAME "PNX4008-WDT: "
-
 /* WatchDog Timer - Chapter 23 Page 207 */
 
 #define DEFAULT_HEARTBEAT 19
@@ -77,251 +76,128 @@
 
 #define WDOG_COUNTER_RATE 13000000	/*the counter clock is 13 MHz fixed */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-static int heartbeat = DEFAULT_HEARTBEAT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
+static unsigned int heartbeat = DEFAULT_HEARTBEAT;
 
 static DEFINE_SPINLOCK(io_lock);
-static unsigned long wdt_status;
-#define WDT_IN_USE        0
-#define WDT_OK_TO_CLOSE   1
-#define WDT_REGION_INITED 2
-#define WDT_DEVICE_INITED 3
-
-static unsigned long boot_status;
-
-static struct resource	*wdt_mem;
 static void __iomem	*wdt_base;
 struct clk		*wdt_clk;
 
-static void wdt_enable(void)
+static int pnx4008_wdt_start(struct watchdog_device *wdd)
 {
 	spin_lock(&io_lock);
 
 	/* stop counter, initiate counter reset */
-	__raw_writel(RESET_COUNT, WDTIM_CTRL(wdt_base));
+	writel(RESET_COUNT, WDTIM_CTRL(wdt_base));
 	/*wait for reset to complete. 100% guarantee event */
-	while (__raw_readl(WDTIM_COUNTER(wdt_base)))
+	while (readl(WDTIM_COUNTER(wdt_base)))
 		cpu_relax();
 	/* internal and external reset, stop after that */
-	__raw_writel(M_RES2 | STOP_COUNT0 | RESET_COUNT0,
-		WDTIM_MCTRL(wdt_base));
+	writel(M_RES2 | STOP_COUNT0 | RESET_COUNT0, WDTIM_MCTRL(wdt_base));
 	/* configure match output */
-	__raw_writel(MATCH_OUTPUT_HIGH, WDTIM_EMR(wdt_base));
+	writel(MATCH_OUTPUT_HIGH, WDTIM_EMR(wdt_base));
 	/* clear interrupt, just in case */
-	__raw_writel(MATCH_INT, WDTIM_INT(wdt_base));
+	writel(MATCH_INT, WDTIM_INT(wdt_base));
 	/* the longest pulse period 65541/(13*10^6) seconds ~ 5 ms. */
-	__raw_writel(0xFFFF, WDTIM_PULSE(wdt_base));
-	__raw_writel(heartbeat * WDOG_COUNTER_RATE, WDTIM_MATCH0(wdt_base));
+	writel(0xFFFF, WDTIM_PULSE(wdt_base));
+	writel(wdd->timeout * WDOG_COUNTER_RATE, WDTIM_MATCH0(wdt_base));
 	/*enable counter, stop when debugger active */
-	__raw_writel(COUNT_ENAB | DEBUG_EN, WDTIM_CTRL(wdt_base));
+	writel(COUNT_ENAB | DEBUG_EN, WDTIM_CTRL(wdt_base));
 
 	spin_unlock(&io_lock);
+	return 0;
 }
 
-static void wdt_disable(void)
+static int pnx4008_wdt_stop(struct watchdog_device *wdd)
 {
 	spin_lock(&io_lock);
 
-	__raw_writel(0, WDTIM_CTRL(wdt_base));	/*stop counter */
+	writel(0, WDTIM_CTRL(wdt_base));	/*stop counter */
 
 	spin_unlock(&io_lock);
+	return 0;
 }
 
-static int pnx4008_wdt_open(struct inode *inode, struct file *file)
+static int pnx4008_wdt_set_timeout(struct watchdog_device *wdd,
+				    unsigned int new_timeout)
 {
-	int ret;
-
-	if (test_and_set_bit(WDT_IN_USE, &wdt_status))
-		return -EBUSY;
-
-	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-	ret = clk_enable(wdt_clk);
-	if (ret) {
-		clear_bit(WDT_IN_USE, &wdt_status);
-		return ret;
-	}
-
-	wdt_enable();
-
-	return nonseekable_open(inode, file);
+	wdd->timeout = new_timeout;
+	return 0;
 }
 
-static ssize_t pnx4008_wdt_write(struct file *file, const char *data,
-					size_t len, loff_t *ppos)
-{
-	if (len) {
-		if (!nowayout) {
-			size_t i;
-
-			clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-			for (i = 0; i != len; i++) {
-				char c;
-
-				if (get_user(c, data + i))
-					return -EFAULT;
-				if (c == 'V')
-					set_bit(WDT_OK_TO_CLOSE, &wdt_status);
-			}
-		}
-		wdt_enable();
-	}
-
-	return len;
-}
-
-static const struct watchdog_info ident = {
+static const struct watchdog_info pnx4008_wdt_ident = {
 	.options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
 	    WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
 	.identity = "PNX4008 Watchdog",
 };
 
-static long pnx4008_wdt_ioctl(struct file *file, unsigned int cmd,
-				unsigned long arg)
-{
-	int ret = -ENOTTY;
-	int time;
-
-	switch (cmd) {
-	case WDIOC_GETSUPPORT:
-		ret = copy_to_user((struct watchdog_info *)arg, &ident,
-				   sizeof(ident)) ? -EFAULT : 0;
-		break;
-
-	case WDIOC_GETSTATUS:
-		ret = put_user(0, (int *)arg);
-		break;
-
-	case WDIOC_GETBOOTSTATUS:
-		ret = put_user(boot_status, (int *)arg);
-		break;
-
-	case WDIOC_KEEPALIVE:
-		wdt_enable();
-		ret = 0;
-		break;
-
-	case WDIOC_SETTIMEOUT:
-		ret = get_user(time, (int *)arg);
-		if (ret)
-			break;
-
-		if (time <= 0 || time > MAX_HEARTBEAT) {
-			ret = -EINVAL;
-			break;
-		}
-
-		heartbeat = time;
-		wdt_enable();
-		/* Fall through */
-
-	case WDIOC_GETTIMEOUT:
-		ret = put_user(heartbeat, (int *)arg);
-		break;
-	}
-	return ret;
-}
-
-static int pnx4008_wdt_release(struct inode *inode, struct file *file)
-{
-	if (!test_bit(WDT_OK_TO_CLOSE, &wdt_status))
-		printk(KERN_WARNING "WATCHDOG: Device closed unexpectedly\n");
-
-	wdt_disable();
-	clk_disable(wdt_clk);
-	clear_bit(WDT_IN_USE, &wdt_status);
-	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-	return 0;
-}
-
-static const struct file_operations pnx4008_wdt_fops = {
+static const struct watchdog_ops pnx4008_wdt_ops = {
 	.owner = THIS_MODULE,
-	.llseek = no_llseek,
-	.write = pnx4008_wdt_write,
-	.unlocked_ioctl = pnx4008_wdt_ioctl,
-	.open = pnx4008_wdt_open,
-	.release = pnx4008_wdt_release,
+	.start = pnx4008_wdt_start,
+	.stop = pnx4008_wdt_stop,
+	.set_timeout = pnx4008_wdt_set_timeout,
 };
 
-static struct miscdevice pnx4008_wdt_miscdev = {
-	.minor = WATCHDOG_MINOR,
-	.name = "watchdog",
-	.fops = &pnx4008_wdt_fops,
+static struct watchdog_device pnx4008_wdd = {
+	.info = &pnx4008_wdt_ident,
+	.ops = &pnx4008_wdt_ops,
+	.min_timeout = 1,
+	.max_timeout = MAX_HEARTBEAT,
 };
 
 static int __devinit pnx4008_wdt_probe(struct platform_device *pdev)
 {
-	int ret = 0, size;
+	struct resource *r;
+	int ret = 0;
 
 	if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
 		heartbeat = DEFAULT_HEARTBEAT;
 
-	printk(KERN_INFO MODULE_NAME
-		"PNX4008 Watchdog Timer: heartbeat %d sec\n", heartbeat);
-
-	wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (wdt_mem == NULL) {
-		printk(KERN_INFO MODULE_NAME
-			"failed to get memory region resource\n");
-		return -ENOENT;
-	}
-
-	size = resource_size(wdt_mem);
-
-	if (!request_mem_region(wdt_mem->start, size, pdev->name)) {
-		printk(KERN_INFO MODULE_NAME "failed to get memory region\n");
-		return -ENOENT;
-	}
-	wdt_base = (void __iomem *)IO_ADDRESS(wdt_mem->start);
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	wdt_base = devm_request_and_ioremap(&pdev->dev, r);
+	if (!wdt_base)
+		return -EADDRINUSE;
 
 	wdt_clk = clk_get(&pdev->dev, NULL);
-	if (IS_ERR(wdt_clk)) {
-		ret = PTR_ERR(wdt_clk);
-		release_mem_region(wdt_mem->start, size);
-		wdt_mem = NULL;
-		goto out;
-	}
+	if (IS_ERR(wdt_clk))
+		return PTR_ERR(wdt_clk);
 
 	ret = clk_enable(wdt_clk);
-	if (ret) {
-		release_mem_region(wdt_mem->start, size);
-		wdt_mem = NULL;
-		clk_put(wdt_clk);
+	if (ret)
 		goto out;
-	}
 
-	ret = misc_register(&pnx4008_wdt_miscdev);
+	pnx4008_wdd.timeout = heartbeat;
+	pnx4008_wdd.bootstatus = (readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
+			WDIOF_CARDRESET : 0;
+	watchdog_set_nowayout(&pnx4008_wdd, nowayout);
+
+	pnx4008_wdt_stop(&pnx4008_wdd);	/* disable for now */
+
+	ret = watchdog_register_device(&pnx4008_wdd);
 	if (ret < 0) {
-		printk(KERN_ERR MODULE_NAME "cannot register misc device\n");
-		release_mem_region(wdt_mem->start, size);
-		wdt_mem = NULL;
-		clk_disable(wdt_clk);
-		clk_put(wdt_clk);
-	} else {
-		boot_status = (__raw_readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
-		    WDIOF_CARDRESET : 0;
-		wdt_disable();		/*disable for now */
-		clk_disable(wdt_clk);
-		set_bit(WDT_DEVICE_INITED, &wdt_status);
+		dev_err(&pdev->dev, "cannot register watchdog device\n");
+		goto disable_clk;
 	}
 
+	dev_info(&pdev->dev, "PNX4008 Watchdog Timer: heartbeat %d sec\n",
+			heartbeat);
+
+	return 0;
+
+disable_clk:
+	clk_disable(wdt_clk);
 out:
+	clk_put(wdt_clk);
 	return ret;
 }
 
 static int __devexit pnx4008_wdt_remove(struct platform_device *pdev)
 {
-	misc_deregister(&pnx4008_wdt_miscdev);
+	watchdog_unregister_device(&pnx4008_wdd);
 
 	clk_disable(wdt_clk);
 	clk_put(wdt_clk);
 
-	if (wdt_mem) {
-		release_mem_region(wdt_mem->start, resource_size(wdt_mem));
-		wdt_mem = NULL;
-	}
 	return 0;
 }
 
@@ -337,15 +213,16 @@
 module_platform_driver(platform_wdt_driver);
 
 MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
 MODULE_DESCRIPTION("PNX4008 Watchdog Driver");
 
-module_param(heartbeat, int, 0);
+module_param(heartbeat, uint, 0);
 MODULE_PARM_DESC(heartbeat,
 		 "Watchdog heartbeat period in seconds from 1 to "
 		 __MODULE_STRING(MAX_HEARTBEAT) ", default "
 		 __MODULE_STRING(DEFAULT_HEARTBEAT));
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		 "Set to 1 to keep watchdog running after device release");
 
diff --git a/drivers/watchdog/pnx833x_wdt.c b/drivers/watchdog/pnx833x_wdt.c
index a7b5ad2..1b62a7d 100644
--- a/drivers/watchdog/pnx833x_wdt.c
+++ b/drivers/watchdog/pnx833x_wdt.c
@@ -17,6 +17,8 @@
  * based on softdog.c by Alan Cox <alan@redhat.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -30,7 +32,6 @@
 #include <linux/init.h>
 #include <asm/mach-pnx833x/pnx833x.h>
 
-#define PFX "pnx833x: "
 #define WATCHDOG_TIMEOUT 30		/* 30 sec Maximum timeout */
 #define WATCHDOG_COUNT_FREQUENCY 68000000U /* Watchdog counts at 68MHZ. */
 #define	PNX_WATCHDOG_TIMEOUT	(WATCHDOG_TIMEOUT * WATCHDOG_COUNT_FREQUENCY)
@@ -54,8 +55,8 @@
 MODULE_PARM_DESC(timeout, "Watchdog timeout in Mhz. (68Mhz clock), default="
 			__MODULE_STRING(PNX_TIMEOUT_VALUE) "(30 seconds).");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 					__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -76,7 +77,7 @@
 	PNX833X_REG(PNX833X_CONFIG +
 				PNX833X_CONFIG_CPU_COUNTERS_CONTROL) |= 0x1;
 
-	printk(KERN_INFO PFX "Started watchdog timer.\n");
+	pr_info("Started watchdog timer\n");
 }
 
 static void pnx833x_wdt_stop(void)
@@ -87,7 +88,7 @@
 	PNX833X_REG(PNX833X_CONFIG +
 			PNX833X_CONFIG_CPU_COUNTERS_CONTROL) &= 0xFFFFFFFE;
 
-	printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+	pr_info("Stopped watchdog timer\n");
 }
 
 static void pnx833x_wdt_ping(void)
@@ -113,7 +114,7 @@
 
 	pnx833x_wdt_ping();
 
-	printk(KERN_INFO "Started watchdog timer.\n");
+	pr_info("Started watchdog timer\n");
 
 	return nonseekable_open(inode, file);
 }
@@ -232,9 +233,6 @@
 	.notifier_call = pnx833x_wdt_notify_sys,
 };
 
-static char banner[] __initdata =
-	KERN_INFO PFX "Hardware Watchdog Timer for PNX833x: Version 0.1\n";
-
 static int __init watchdog_init(void)
 {
 	int ret, cause;
@@ -243,27 +241,25 @@
 	cause = PNX833X_REG(PNX833X_RESET);
 	/*If bit 31 is set then watchdog was cause of reset.*/
 	if (cause & 0x80000000) {
-		printk(KERN_INFO PFX "The system was previously reset due to "
-			"the watchdog firing - please investigate...\n");
+		pr_info("The system was previously reset due to the watchdog firing - please investigate...\n");
 	}
 
 	ret = register_reboot_notifier(&pnx833x_wdt_notifier);
 	if (ret) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", ret);
+		pr_err("cannot register reboot notifier (err=%d)\n", ret);
 		return ret;
 	}
 
 	ret = misc_register(&pnx833x_wdt_miscdev);
 	if (ret) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-			WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		unregister_reboot_notifier(&pnx833x_wdt_notifier);
 		return ret;
 	}
 
-	printk(banner);
+	pr_info("Hardware Watchdog Timer for PNX833x: Version 0.1\n");
+
 	if (start_enabled)
 		pnx833x_wdt_start();
 
diff --git a/drivers/watchdog/rc32434_wdt.c b/drivers/watchdog/rc32434_wdt.c
index bf7bc8a..547353a 100644
--- a/drivers/watchdog/rc32434_wdt.c
+++ b/drivers/watchdog/rc32434_wdt.c
@@ -17,6 +17,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>		/* For module specific items */
 #include <linux/moduleparam.h>		/* For new moduleparam's */
 #include <linux/types.h>		/* For standard types (like size_t) */
@@ -33,8 +35,6 @@
 
 #include <asm/mach-rc32434/integ.h>	/* For the Watchdog registers */
 
-#define PFX KBUILD_MODNAME ": "
-
 #define VERSION "1.0"
 
 static struct {
@@ -64,8 +64,8 @@
 MODULE_PARM_DESC(timeout, "Watchdog timeout value, in seconds (default="
 		__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 	__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -78,8 +78,7 @@
 	int max_to = WTCOMP2SEC((u32)-1);
 
 	if (new_timeout < 0 || new_timeout > max_to) {
-		printk(KERN_ERR PFX "timeout value must be between 0 and %d",
-			max_to);
+		pr_err("timeout value must be between 0 and %d\n", max_to);
 		return -EINVAL;
 	}
 	timeout = new_timeout;
@@ -119,7 +118,7 @@
 	SET_BITS(wdt_reg->wtc, or, nand);
 
 	spin_unlock(&rc32434_wdt_device.io_lock);
-	printk(KERN_INFO PFX "Started watchdog timer.\n");
+	pr_info("Started watchdog timer\n");
 }
 
 static void rc32434_wdt_stop(void)
@@ -130,7 +129,7 @@
 	SET_BITS(wdt_reg->wtc, 0, 1 << RC32434_WTC_EN);
 
 	spin_unlock(&rc32434_wdt_device.io_lock);
-	printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+	pr_info("Stopped watchdog timer\n");
 }
 
 static void rc32434_wdt_ping(void)
@@ -160,8 +159,7 @@
 		rc32434_wdt_stop();
 		module_put(THIS_MODULE);
 	} else {
-		printk(KERN_CRIT PFX
-			"device closed unexpectedly. WDT will not stop!\n");
+		pr_crit("device closed unexpectedly. WDT will not stop!\n");
 		rc32434_wdt_ping();
 	}
 	clear_bit(0, &rc32434_wdt_device.inuse);
@@ -262,9 +260,6 @@
 	.fops	= &rc32434_wdt_fops,
 };
 
-static char banner[] __devinitdata = KERN_INFO PFX
-		"Watchdog Timer version " VERSION ", timer margin: %d sec\n";
-
 static int __devinit rc32434_wdt_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -272,13 +267,13 @@
 
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rb532_wdt_res");
 	if (!r) {
-		printk(KERN_ERR PFX "failed to retrieve resources\n");
+		pr_err("failed to retrieve resources\n");
 		return -ENODEV;
 	}
 
 	wdt_reg = ioremap_nocache(r->start, resource_size(r));
 	if (!wdt_reg) {
-		printk(KERN_ERR PFX "failed to remap I/O resources\n");
+		pr_err("failed to remap I/O resources\n");
 		return -ENXIO;
 	}
 
@@ -291,18 +286,18 @@
 	 * if not reset to the default */
 	if (rc32434_wdt_set(timeout)) {
 		rc32434_wdt_set(WATCHDOG_TIMEOUT);
-		printk(KERN_INFO PFX
-			"timeout value must be between 0 and %d\n",
+		pr_info("timeout value must be between 0 and %d\n",
 			WTCOMP2SEC((u32)-1));
 	}
 
 	ret = misc_register(&rc32434_wdt_miscdev);
 	if (ret < 0) {
-		printk(KERN_ERR PFX "failed to register watchdog device\n");
+		pr_err("failed to register watchdog device\n");
 		goto unmap;
 	}
 
-	printk(banner, timeout);
+	pr_info("Watchdog Timer version " VERSION ", timer margin: %d sec\n",
+		timeout);
 
 	return 0;
 
diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c
index c7e17ce..49e1b1c 100644
--- a/drivers/watchdog/riowd.c
+++ b/drivers/watchdog/riowd.c
@@ -3,6 +3,8 @@
  * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -189,7 +191,7 @@
 
 	p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME);
 	if (!p->regs) {
-		printk(KERN_ERR PFX "Cannot map registers.\n");
+		pr_err("Cannot map registers\n");
 		goto out_free;
 	}
 	/* Make miscdev useable right away */
@@ -197,12 +199,12 @@
 
 	err = misc_register(&riowd_miscdev);
 	if (err) {
-		printk(KERN_ERR PFX "Cannot register watchdog misc device.\n");
+		pr_err("Cannot register watchdog misc device\n");
 		goto out_iounmap;
 	}
 
-	printk(KERN_INFO PFX "Hardware watchdog [%i minutes], "
-	       "regs at %p\n", riowd_timeout, p->regs);
+	pr_info("Hardware watchdog [%i minutes], regs at %p\n",
+		riowd_timeout, p->regs);
 
 	dev_set_drvdata(&op->dev, p);
 	return 0;
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 404172f..04e5a6d 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -23,6 +23,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -46,12 +48,10 @@
 
 #include <plat/regs-watchdog.h>
 
-#define PFX "s3c2410-wdt: "
-
 #define CONFIG_S3C2410_WATCHDOG_ATBOOT		(0)
 #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME	(15)
 
-static int nowayout	= WATCHDOG_NOWAYOUT;
+static bool nowayout	= WATCHDOG_NOWAYOUT;
 static int tmr_margin	= CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;
 static int tmr_atboot	= CONFIG_S3C2410_WATCHDOG_ATBOOT;
 static int soft_noboot;
@@ -59,7 +59,7 @@
 
 module_param(tmr_margin,  int, 0);
 module_param(tmr_atboot,  int, 0);
-module_param(nowayout,    int, 0);
+module_param(nowayout,   bool, 0);
 module_param(soft_noboot, int, 0);
 module_param(debug,	  int, 0);
 
@@ -84,10 +84,11 @@
 
 /* watchdog control routines */
 
-#define DBG(msg...) do { \
-	if (debug) \
-		printk(KERN_INFO msg); \
-	} while (0)
+#define DBG(fmt, ...)					\
+do {							\
+	if (debug)					\
+		pr_info(fmt, ##__VA_ARGS__);		\
+} while (0)
 
 /* functions */
 
@@ -200,6 +201,8 @@
 	writel(count, wdt_base + S3C2410_WTDAT);
 	writel(wtcon, wdt_base + S3C2410_WTCON);
 
+	wdd->timeout = timeout;
+
 	return 0;
 }
 
@@ -354,7 +357,7 @@
 
 	ret = s3c2410wdt_cpufreq_register();
 	if (ret < 0) {
-		printk(KERN_ERR PFX "failed to register cpufreq\n");
+		pr_err("failed to register cpufreq\n");
 		goto err_clk;
 	}
 
@@ -483,8 +486,8 @@
 	writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */
 	writel(wtcon_save, wdt_base + S3C2410_WTCON);
 
-	printk(KERN_INFO PFX "watchdog %sabled\n",
-	       (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
+	pr_info("watchdog %sabled\n",
+		(wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
 
 	return 0;
 }
@@ -518,12 +521,10 @@
 };
 
 
-static char banner[] __initdata =
-	KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n";
-
 static int __init watchdog_init(void)
 {
-	printk(banner);
+	pr_info("S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n");
+
 	return platform_driver_register(&s3c2410wdt_driver);
 }
 
diff --git a/drivers/watchdog/sa1100_wdt.c b/drivers/watchdog/sa1100_wdt.c
index 0162454..54984de 100644
--- a/drivers/watchdog/sa1100_wdt.c
+++ b/drivers/watchdog/sa1100_wdt.c
@@ -17,6 +17,9 @@
  *
  *	27/11/2000 Initial release
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -25,6 +28,7 @@
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/bitops.h>
 #include <linux/uaccess.h>
 #include <linux/timex.h>
@@ -66,7 +70,7 @@
  */
 static int sa1100dog_release(struct inode *inode, struct file *file)
 {
-	printk(KERN_CRIT "WATCHDOG: Device closed - timer will not stop\n");
+	pr_crit("Device closed - timer will not stop\n");
 	clear_bit(1, &sa1100wdt_users);
 	return 0;
 }
@@ -169,9 +173,8 @@
 
 	ret = misc_register(&sa1100dog_miscdev);
 	if (ret == 0)
-		printk(KERN_INFO
-			"SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
-						margin);
+		pr_info("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
+			margin);
 	return ret;
 }
 
diff --git a/drivers/watchdog/sb_wdog.c b/drivers/watchdog/sb_wdog.c
index b01a30e..25c7a3f 100644
--- a/drivers/watchdog/sb_wdog.c
+++ b/drivers/watchdog/sb_wdog.c
@@ -43,6 +43,9 @@
  *	version 1 or 2 as published by the Free Software Foundation.
  *
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
@@ -125,9 +128,8 @@
 		__raw_writeb(0, user_dog);
 		module_put(THIS_MODULE);
 	} else {
-		printk(KERN_CRIT
-			"%s: Unexpected close, not stopping watchdog!\n",
-						ident.identity);
+		pr_crit("%s: Unexpected close, not stopping watchdog!\n",
+			ident.identity);
 		sbwdog_pet(user_dog);
 	}
 	clear_bit(0, &sbwdog_gate);
@@ -269,7 +271,7 @@
 	 * if it's the second watchdog timer, it's for those users
 	 */
 	if (wd_cfg_reg == user_dog)
-		printk(KERN_CRIT "%s in danger of initiating system reset "
+		pr_crit("%s in danger of initiating system reset "
 			"in %ld.%01ld seconds\n",
 			ident.identity,
 			wd_init / 1000000, (wd_init / 100000) % 10);
@@ -290,9 +292,8 @@
 	 */
 	ret = register_reboot_notifier(&sbwdog_notifier);
 	if (ret) {
-		printk(KERN_ERR
-			"%s: cannot register reboot notifier (err=%d)\n",
-						ident.identity, ret);
+		pr_err("%s: cannot register reboot notifier (err=%d)\n",
+		       ident.identity, ret);
 		return ret;
 	}
 
@@ -303,16 +304,16 @@
 	ret = request_irq(1, sbwdog_interrupt, IRQF_SHARED,
 		ident.identity, (void *)user_dog);
 	if (ret) {
-		printk(KERN_ERR "%s: failed to request irq 1 - %d\n",
-						ident.identity, ret);
+		pr_err("%s: failed to request irq 1 - %d\n",
+		       ident.identity, ret);
 		goto out;
 	}
 
 	ret = misc_register(&sbwdog_miscdev);
 	if (ret == 0) {
-		printk(KERN_INFO "%s: timeout is %ld.%ld secs\n",
-				ident.identity,
-				timeout / 1000000, (timeout / 100000) % 10);
+		pr_info("%s: timeout is %ld.%ld secs\n",
+			ident.identity,
+			timeout / 1000000, (timeout / 100000) % 10);
 		return 0;
 	}
 	free_irq(1, (void *)user_dog);
@@ -353,8 +354,7 @@
 	ret = request_irq(1, sbwdog_interrupt, IRQF_SHARED,
 		"Kernel Watchdog", IOADDR(A_SCD_WDOG_CFG_0));
 	if (ret) {
-		printk(KERN_CRIT
-		  "Watchdog IRQ zero(0) failed to be requested - %d\n", ret);
+		pr_crit("Watchdog IRQ zero(0) failed to be requested - %d\n", ret);
 	}
 }
 
diff --git a/drivers/watchdog/sbc60xxwdt.c b/drivers/watchdog/sbc60xxwdt.c
index 626d0e8..63632ec 100644
--- a/drivers/watchdog/sbc60xxwdt.c
+++ b/drivers/watchdog/sbc60xxwdt.c
@@ -48,6 +48,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -63,7 +65,6 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 
 #define OUR_NAME "sbc60xxwdt"
 #define PFX OUR_NAME ": "
@@ -105,8 +106,8 @@
 	"Watchdog timeout in seconds. (1<=timeout<=3600, default="
 				__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -132,8 +133,7 @@
 		/* Re-set the timer interval */
 		mod_timer(&timer, jiffies + WDT_INTERVAL);
 	} else
-		printk(KERN_WARNING PFX
-			"Heartbeat lost! Will not ping the watchdog\n");
+		pr_warn("Heartbeat lost! Will not ping the watchdog\n");
 }
 
 /*
@@ -146,7 +146,7 @@
 
 	/* Start the timer */
 	mod_timer(&timer, jiffies + WDT_INTERVAL);
-	printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+	pr_info("Watchdog timer is now enabled\n");
 }
 
 static void wdt_turnoff(void)
@@ -154,7 +154,7 @@
 	/* Stop the timer */
 	del_timer(&timer);
 	inb_p(wdt_stop);
-	printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+	pr_info("Watchdog timer is now disabled...\n");
 }
 
 static void wdt_keepalive(void)
@@ -217,8 +217,7 @@
 		wdt_turnoff();
 	else {
 		del_timer(&timer);
-		printk(KERN_CRIT PFX
-		  "device file closed unexpectedly. Will not stop the WDT!\n");
+		pr_crit("device file closed unexpectedly. Will not stop the WDT!\n");
 	}
 	clear_bit(0, &wdt_is_open);
 	wdt_expect_close = 0;
@@ -335,14 +334,12 @@
 
 	if (timeout < 1 || timeout > 3600) { /* arbitrary upper limit */
 		timeout = WATCHDOG_TIMEOUT;
-		printk(KERN_INFO PFX
-			"timeout value must be 1 <= x <= 3600, using %d\n",
-								timeout);
+		pr_info("timeout value must be 1 <= x <= 3600, using %d\n",
+			timeout);
 	}
 
 	if (!request_region(wdt_start, 1, "SBC 60XX WDT")) {
-		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-			wdt_start);
+		pr_err("I/O address 0x%04x already in use\n", wdt_start);
 		rc = -EIO;
 		goto err_out;
 	}
@@ -350,9 +347,7 @@
 	/* We cannot reserve 0x45 - the kernel already has! */
 	if (wdt_stop != 0x45 && wdt_stop != wdt_start) {
 		if (!request_region(wdt_stop, 1, "SBC 60XX WDT")) {
-			printk(KERN_ERR PFX
-				"I/O address 0x%04x already in use\n",
-							wdt_stop);
+			pr_err("I/O address 0x%04x already in use\n", wdt_stop);
 			rc = -EIO;
 			goto err_out_region1;
 		}
@@ -360,21 +355,18 @@
 
 	rc = register_reboot_notifier(&wdt_notifier);
 	if (rc) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", rc);
+		pr_err("cannot register reboot notifier (err=%d)\n", rc);
 		goto err_out_region2;
 	}
 
 	rc = misc_register(&wdt_miscdev);
 	if (rc) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-						wdt_miscdev.minor, rc);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       wdt_miscdev.minor, rc);
 		goto err_out_reboot;
 	}
-	printk(KERN_INFO PFX
-		"WDT driver for 60XX single board computer initialised. "
-		"timeout=%d sec (nowayout=%d)\n", timeout, nowayout);
+	pr_info("WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n",
+		timeout, nowayout);
 
 	return 0;
 
diff --git a/drivers/watchdog/sbc7240_wdt.c b/drivers/watchdog/sbc7240_wdt.c
index 93ac589..719edc8 100644
--- a/drivers/watchdog/sbc7240_wdt.c
+++ b/drivers/watchdog/sbc7240_wdt.c
@@ -16,6 +16,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
@@ -30,9 +32,6 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 #include <linux/atomic.h>
-#include <asm/system.h>
-
-#define SBC7240_PREFIX "sbc7240_wdt: "
 
 #define SBC7240_ENABLE_PORT		0x443
 #define SBC7240_DISABLE_PORT		0x043
@@ -47,8 +46,8 @@
 		 __MODULE_STRING(SBC7240_MAX_TIMEOUT) ", default="
 		 __MODULE_STRING(SBC7240_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Disable watchdog when closing device file");
 
 #define SBC7240_OPEN_STATUS_BIT		0
@@ -65,8 +64,7 @@
 	/* disable the watchdog */
 	if (test_and_clear_bit(SBC7240_ENABLED_STATUS_BIT, &wdt_status)) {
 		inb_p(SBC7240_DISABLE_PORT);
-		printk(KERN_INFO SBC7240_PREFIX
-		       "Watchdog timer is now disabled.\n");
+		pr_info("Watchdog timer is now disabled\n");
 	}
 }
 
@@ -75,23 +73,20 @@
 	/* enable the watchdog */
 	if (!test_and_set_bit(SBC7240_ENABLED_STATUS_BIT, &wdt_status)) {
 		inb_p(SBC7240_ENABLE_PORT);
-		printk(KERN_INFO SBC7240_PREFIX
-		       "Watchdog timer is now enabled.\n");
+		pr_info("Watchdog timer is now enabled\n");
 	}
 }
 
 static int wdt_set_timeout(int t)
 {
 	if (t < 1 || t > SBC7240_MAX_TIMEOUT) {
-		printk(KERN_ERR SBC7240_PREFIX
-		       "timeout value must be 1<=x<=%d\n",
-		       SBC7240_MAX_TIMEOUT);
+		pr_err("timeout value must be 1<=x<=%d\n", SBC7240_MAX_TIMEOUT);
 		return -1;
 	}
 	/* set the timeout */
 	outb_p((unsigned)t, SBC7240_SET_TIMEOUT_PORT);
 	timeout = t;
-	printk(KERN_INFO SBC7240_PREFIX "timeout set to %d seconds\n", t);
+	pr_info("timeout set to %d seconds\n", t);
 	return 0;
 }
 
@@ -150,8 +145,7 @@
 	    || !nowayout) {
 		wdt_disable();
 	} else {
-		printk(KERN_CRIT SBC7240_PREFIX
-		       "Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		wdt_keepalive();
 	}
 
@@ -252,7 +246,7 @@
 
 static void __exit sbc7240_wdt_unload(void)
 {
-	printk(KERN_INFO SBC7240_PREFIX "Removing watchdog\n");
+	pr_info("Removing watchdog\n");
 	misc_deregister(&wdt_miscdev);
 
 	unregister_reboot_notifier(&wdt_notifier);
@@ -264,8 +258,7 @@
 	int rc = -EBUSY;
 
 	if (!request_region(SBC7240_ENABLE_PORT, 1, "SBC7240 WDT")) {
-		printk(KERN_ERR SBC7240_PREFIX
-		       "I/O address 0x%04x already in use\n",
+		pr_err("I/O address 0x%04x already in use\n",
 		       SBC7240_ENABLE_PORT);
 		rc = -EIO;
 		goto err_out;
@@ -277,31 +270,27 @@
 
 	if (timeout < 1 || timeout > SBC7240_MAX_TIMEOUT) {
 		timeout = SBC7240_TIMEOUT;
-		printk(KERN_INFO SBC7240_PREFIX
-		       "timeout value must be 1<=x<=%d, using %d\n",
-		       SBC7240_MAX_TIMEOUT, timeout);
+		pr_info("timeout value must be 1<=x<=%d, using %d\n",
+			SBC7240_MAX_TIMEOUT, timeout);
 	}
 	wdt_set_timeout(timeout);
 	wdt_disable();
 
 	rc = register_reboot_notifier(&wdt_notifier);
 	if (rc) {
-		printk(KERN_ERR SBC7240_PREFIX
-		       "cannot register reboot notifier (err=%d)\n", rc);
+		pr_err("cannot register reboot notifier (err=%d)\n", rc);
 		goto err_out_region;
 	}
 
 	rc = misc_register(&wdt_miscdev);
 	if (rc) {
-		printk(KERN_ERR SBC7240_PREFIX
-		       "cannot register miscdev on minor=%d (err=%d)\n",
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
 		       wdt_miscdev.minor, rc);
 		goto err_out_reboot_notifier;
 	}
 
-	printk(KERN_INFO SBC7240_PREFIX
-	       "Watchdog driver for SBC7240 initialised (nowayout=%d)\n",
-	       nowayout);
+	pr_info("Watchdog driver for SBC7240 initialised (nowayout=%d)\n",
+		nowayout);
 
 	return 0;
 
diff --git a/drivers/watchdog/sbc8360.c b/drivers/watchdog/sbc8360.c
index 514ec23..d4781e0 100644
--- a/drivers/watchdog/sbc8360.c
+++ b/drivers/watchdog/sbc8360.c
@@ -36,6 +36,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/miscdevice.h>
@@ -51,13 +53,10 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 
 static unsigned long sbc8360_is_open;
 static char expect_close;
 
-#define PFX "sbc8360: "
-
 /*
  *
  * Watchdog Timer Configuration
@@ -197,11 +196,11 @@
 static int timeout = 27;
 static int wd_margin = 0xB;
 static int wd_multiplier = 2;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 module_param(timeout, int, 0);
 MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))");
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		 "Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -280,8 +279,7 @@
 	if (expect_close == 42)
 		sbc8360_stop();
 	else
-		printk(KERN_CRIT PFX "SBC8360 device closed unexpectedly.  "
-						"SBC8360 will not stop!\n");
+		pr_crit("SBC8360 device closed unexpectedly.  SBC8360 will not stop!\n");
 
 	clear_bit(0, &sbc8360_is_open);
 	expect_close = 0;
@@ -334,20 +332,19 @@
 	unsigned long int mseconds = 60000;
 
 	if (timeout < 0 || timeout > 63) {
-		printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n");
+		pr_err("Invalid timeout index (must be 0-63)\n");
 		res = -EINVAL;
 		goto out;
 	}
 
 	if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) {
-		printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n",
+		pr_err("ENABLE method I/O %X is not available\n",
 		       SBC8360_ENABLE);
 		res = -EIO;
 		goto out;
 	}
 	if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) {
-		printk(KERN_ERR PFX
-		       "BASETIME method I/O %X is not available.\n",
+		pr_err("BASETIME method I/O %X is not available\n",
 		       SBC8360_BASETIME);
 		res = -EIO;
 		goto out_nobasetimereg;
@@ -355,13 +352,13 @@
 
 	res = register_reboot_notifier(&sbc8360_notifier);
 	if (res) {
-		printk(KERN_ERR PFX "Failed to register reboot notifier.\n");
+		pr_err("Failed to register reboot notifier\n");
 		goto out_noreboot;
 	}
 
 	res = misc_register(&sbc8360_miscdev);
 	if (res) {
-		printk(KERN_ERR PFX "failed to register misc device\n");
+		pr_err("failed to register misc device\n");
 		goto out_nomisc;
 	}
 
@@ -378,7 +375,7 @@
 		mseconds = (wd_margin + 1) * 100000;
 
 	/* My kingdom for the ability to print "0.5 seconds" in the kernel! */
-	printk(KERN_INFO PFX "Timeout set at %ld ms.\n", mseconds);
+	pr_info("Timeout set at %ld ms\n", mseconds);
 
 	return 0;
 
diff --git a/drivers/watchdog/sbc_epx_c3.c b/drivers/watchdog/sbc_epx_c3.c
index eaca366..0c3e9f6 100644
--- a/drivers/watchdog/sbc_epx_c3.c
+++ b/drivers/watchdog/sbc_epx_c3.c
@@ -13,6 +13,8 @@
  *	based on softdog.c by Alan Cox <alan@lxorguk.ukuu.org.uk>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -28,13 +30,12 @@
 #include <linux/uaccess.h>
 #include <linux/io.h>
 
-#define PFX "epx_c3: "
 static int epx_c3_alive;
 
 #define WATCHDOG_TIMEOUT 1		/* 1 sec default timeout */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 					__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -51,7 +52,7 @@
 
 	outb(0, EPXC3_WATCHDOG_CTL_REG);
 
-	printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+	pr_info("Stopped watchdog timer\n");
 }
 
 static void epx_c3_pet(void)
@@ -75,7 +76,7 @@
 	epx_c3_pet();
 
 	epx_c3_alive = 1;
-	printk(KERN_INFO "Started watchdog timer.\n");
+	pr_info("Started watchdog timer\n");
 
 	return nonseekable_open(inode, file);
 }
@@ -173,9 +174,6 @@
 	.notifier_call = epx_c3_notify_sys,
 };
 
-static const char banner[] __initconst = KERN_INFO PFX
-	"Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n";
-
 static int __init watchdog_init(void)
 {
 	int ret;
@@ -185,20 +183,19 @@
 
 	ret = register_reboot_notifier(&epx_c3_notifier);
 	if (ret) {
-		printk(KERN_ERR PFX "cannot register reboot notifier "
-			"(err=%d)\n", ret);
+		pr_err("cannot register reboot notifier (err=%d)\n", ret);
 		goto out;
 	}
 
 	ret = misc_register(&epx_c3_miscdev);
 	if (ret) {
-		printk(KERN_ERR PFX "cannot register miscdev on minor=%d "
-			"(err=%d)\n", WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		unregister_reboot_notifier(&epx_c3_notifier);
 		goto out;
 	}
 
-	printk(banner);
+	pr_info("Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n");
 
 	return 0;
 
diff --git a/drivers/watchdog/sbc_fitpc2_wdt.c b/drivers/watchdog/sbc_fitpc2_wdt.c
index d5d3994..90d5527 100644
--- a/drivers/watchdog/sbc_fitpc2_wdt.c
+++ b/drivers/watchdog/sbc_fitpc2_wdt.c
@@ -25,9 +25,8 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static unsigned int margin = 60;	/* (secs) Default is 1 minute */
 static unsigned long wdt_status;
 static DEFINE_MUTEX(wdt_lock);
@@ -171,8 +170,7 @@
 		wdt_disable();
 		pr_info("Device disabled\n");
 	} else {
-		pr_warning("Device closed unexpectedly -"
-			" timer will not stop\n");
+		pr_warn("Device closed unexpectedly - timer will not stop\n");
 		wdt_enable();
 	}
 
@@ -222,8 +220,8 @@
 	}
 
 	if (margin < 31 || margin > 255) {
-		pr_err("margin must be in range 31 - 255"
-		       " seconds, you tried to set %d\n", margin);
+		pr_err("margin must be in range 31 - 255 seconds, you tried to set %d\n",
+		       margin);
 		err = -EINVAL;
 		goto err_margin;
 	}
@@ -231,7 +229,7 @@
 	err = misc_register(&fitpc2_wdt_miscdev);
 	if (err) {
 		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
-							WATCHDOG_MINOR, err);
+		       WATCHDOG_MINOR, err);
 		goto err_margin;
 	}
 
@@ -261,7 +259,7 @@
 module_param(margin, int, 0);
 MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/sc1200wdt.c b/drivers/watchdog/sc1200wdt.c
index c01daca..3fb83b0 100644
--- a/drivers/watchdog/sc1200wdt.c
+++ b/drivers/watchdog/sc1200wdt.c
@@ -31,6 +31,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/miscdevice.h>
@@ -48,7 +50,6 @@
 
 #define SC1200_MODULE_VER	"build 20020303"
 #define SC1200_MODULE_NAME	"sc1200wdt"
-#define PFX			SC1200_MODULE_NAME ": "
 
 #define	MAX_TIMEOUT	255	/* 255 minutes */
 #define PMIR		(io)	/* Power Management Index Register */
@@ -71,7 +72,6 @@
 #define UART2_IRQ	0x04	/* Serial1 */
 /* 5 -7 are reserved */
 
-static char banner[] __initdata = PFX SC1200_MODULE_VER;
 static int timeout = 1;
 static int io = -1;
 static int io_len = 2;		/* for non plug and play */
@@ -93,8 +93,8 @@
 module_param(timeout, int, 0);
 MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -176,7 +176,7 @@
 		timeout = MAX_TIMEOUT;
 
 	sc1200wdt_start();
-	printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout);
+	pr_info("Watchdog enabled, timeout = %d min(s)", timeout);
 
 	return nonseekable_open(inode, file);
 }
@@ -254,11 +254,10 @@
 {
 	if (expect_close == 42) {
 		sc1200wdt_stop();
-		printk(KERN_INFO PFX "Watchdog disabled\n");
+		pr_info("Watchdog disabled\n");
 	} else {
 		sc1200wdt_write_data(WDTO, timeout);
-		printk(KERN_CRIT PFX
-			"Unexpected close!, timeout = %d min(s)\n", timeout);
+		pr_crit("Unexpected close!, timeout = %d min(s)\n", timeout);
 	}
 	clear_bit(0, &open_flag);
 	expect_close = 0;
@@ -361,12 +360,11 @@
 	io_len = pnp_port_len(wdt_dev, 0);
 
 	if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
-		printk(KERN_ERR PFX "Unable to register IO port %#x\n", io);
+		pr_err("Unable to register IO port %#x\n", io);
 		return -EBUSY;
 	}
 
-	printk(KERN_INFO "scl200wdt: PnP device found at io port %#x/%d\n",
-								io, io_len);
+	pr_info("PnP device found at io port %#x/%d\n", io, io_len);
 	return 0;
 }
 
@@ -392,7 +390,7 @@
 {
 	int ret;
 
-	printk(KERN_INFO "%s\n", banner);
+	pr_info("%s\n", SC1200_MODULE_VER);
 
 #if defined CONFIG_PNP
 	if (isapnp) {
@@ -403,7 +401,7 @@
 #endif
 
 	if (io == -1) {
-		printk(KERN_ERR PFX "io parameter must be specified\n");
+		pr_err("io parameter must be specified\n");
 		ret = -EINVAL;
 		goto out_pnp;
 	}
@@ -416,7 +414,7 @@
 #endif
 
 	if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
-		printk(KERN_ERR PFX "Unable to register IO port %#x\n", io);
+		pr_err("Unable to register IO port %#x\n", io);
 		ret = -EBUSY;
 		goto out_pnp;
 	}
@@ -427,16 +425,14 @@
 
 	ret = register_reboot_notifier(&sc1200wdt_notifier);
 	if (ret) {
-		printk(KERN_ERR PFX
-			"Unable to register reboot notifier err = %d\n", ret);
+		pr_err("Unable to register reboot notifier err = %d\n", ret);
 		goto out_io;
 	}
 
 	ret = misc_register(&sc1200wdt_miscdev);
 	if (ret) {
-		printk(KERN_ERR PFX
-			"Unable to register miscdev on minor %d\n",
-							WATCHDOG_MINOR);
+		pr_err("Unable to register miscdev on minor %d\n",
+		       WATCHDOG_MINOR);
 		goto out_rbt;
 	}
 
diff --git a/drivers/watchdog/sc520_wdt.c b/drivers/watchdog/sc520_wdt.c
index b284040..707e027 100644
--- a/drivers/watchdog/sc520_wdt.c
+++ b/drivers/watchdog/sc520_wdt.c
@@ -52,6 +52,8 @@
  *  This driver uses memory mapped IO, and spinlock.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -67,10 +69,6 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
-
-#define OUR_NAME "sc520_wdt"
-#define PFX OUR_NAME ": "
 
 /*
  * The AMD Elan SC520 timeout value is 492us times a power of 2 (0-7)
@@ -98,8 +96,8 @@
 	"Watchdog timeout in seconds. (1 <= timeout <= 3600, default="
 				__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -151,8 +149,7 @@
 		/* Re-set the timer interval */
 		mod_timer(&timer, jiffies + WDT_INTERVAL);
 	} else
-		printk(KERN_WARNING PFX
-			"Heartbeat lost! Will not ping the watchdog\n");
+		pr_warn("Heartbeat lost! Will not ping the watchdog\n");
 }
 
 /*
@@ -187,7 +184,7 @@
 	/* Start the watchdog */
 	wdt_config(WDT_ENB | WDT_WRST_ENB | WDT_EXP_SEL_04);
 
-	printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+	pr_info("Watchdog timer is now enabled\n");
 	return 0;
 }
 
@@ -199,7 +196,7 @@
 	/* Stop the watchdog */
 	wdt_config(0);
 
-	printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+	pr_info("Watchdog timer is now disabled...\n");
 	return 0;
 }
 
@@ -270,8 +267,7 @@
 	if (wdt_expect_close == 42)
 		wdt_turnoff();
 	else {
-		printk(KERN_CRIT PFX
-			"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		wdt_keepalive();
 	}
 	clear_bit(0, &wdt_is_open);
@@ -393,36 +389,32 @@
 	   if not reset to the default */
 	if (wdt_set_heartbeat(timeout)) {
 		wdt_set_heartbeat(WATCHDOG_TIMEOUT);
-		printk(KERN_INFO PFX
-		    "timeout value must be 1 <= timeout <= 3600, using %d\n",
-							WATCHDOG_TIMEOUT);
+		pr_info("timeout value must be 1 <= timeout <= 3600, using %d\n",
+			WATCHDOG_TIMEOUT);
 	}
 
 	wdtmrctl = ioremap(MMCR_BASE + OFFS_WDTMRCTL, 2);
 	if (!wdtmrctl) {
-		printk(KERN_ERR PFX "Unable to remap memory\n");
+		pr_err("Unable to remap memory\n");
 		rc = -ENOMEM;
 		goto err_out_region2;
 	}
 
 	rc = register_reboot_notifier(&wdt_notifier);
 	if (rc) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", rc);
+		pr_err("cannot register reboot notifier (err=%d)\n", rc);
 		goto err_out_ioremap;
 	}
 
 	rc = misc_register(&wdt_miscdev);
 	if (rc) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-							WATCHDOG_MINOR, rc);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, rc);
 		goto err_out_notifier;
 	}
 
-	printk(KERN_INFO PFX
-	   "WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n",
-							timeout, nowayout);
+	pr_info("WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n",
+		timeout, nowayout);
 
 	return 0;
 
diff --git a/drivers/watchdog/sch311x_wdt.c b/drivers/watchdog/sch311x_wdt.c
index 029467e..bd86f32 100644
--- a/drivers/watchdog/sch311x_wdt.c
+++ b/drivers/watchdog/sch311x_wdt.c
@@ -18,6 +18,8 @@
  *	Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 /* Includes */
 #include <linux/module.h>		/* For module specific items */
 #include <linux/moduleparam.h>		/* For new moduleparam's */
@@ -37,7 +39,6 @@
 
 /* Module and version information */
 #define DRV_NAME	"sch311x_wdt"
-#define PFX		DRV_NAME ": "
 
 /* Runtime registers */
 #define RESGEN			0x1d
@@ -79,8 +80,8 @@
 	"Watchdog timeout in seconds. 1<= timeout <=15300, default="
 		__MODULE_STRING(WATCHDOG_TIMEOUT) ".");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 		__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -323,8 +324,7 @@
 	if (sch311x_wdt_expect_close == 42) {
 		sch311x_wdt_stop();
 	} else {
-		printk(KERN_CRIT PFX
-				"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		sch311x_wdt_keepalive();
 	}
 	clear_bit(0, &sch311x_wdt_is_open);
@@ -504,20 +504,19 @@
 
 	/* Check if Logical Device Register is currently active */
 	if ((sch311x_sio_inb(sio_config_port, 0x30) & 0x01) == 0)
-		printk(KERN_INFO PFX "Seems that LDN 0x0a is not active...\n");
+		pr_info("Seems that LDN 0x0a is not active...\n");
 
 	/* Get the base address of the runtime registers */
 	base_addr = (sch311x_sio_inb(sio_config_port, 0x60) << 8) |
 			   sch311x_sio_inb(sio_config_port, 0x61);
 	if (!base_addr) {
-		printk(KERN_ERR PFX "Base address not set.\n");
+		pr_err("Base address not set\n");
 		err = -ENODEV;
 		goto exit;
 	}
 	*addr = base_addr;
 
-	printk(KERN_INFO PFX "Found an SMSC SCH311%d chip at 0x%04x\n",
-		dev_id, base_addr);
+	pr_info("Found an SMSC SCH311%d chip at 0x%04x\n", dev_id, base_addr);
 
 exit:
 	sch311x_sio_exit(sio_config_port);
diff --git a/drivers/watchdog/scx200_wdt.c b/drivers/watchdog/scx200_wdt.c
index e67b76c..8ae7c28 100644
--- a/drivers/watchdog/scx200_wdt.c
+++ b/drivers/watchdog/scx200_wdt.c
@@ -17,6 +17,8 @@
    of any nature resulting due to the use of this software. This
    software is provided AS-IS with no warranties. */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -30,7 +32,7 @@
 #include <linux/uaccess.h>
 #include <linux/io.h>
 
-#define NAME "scx200_wdt"
+#define DEBUG
 
 MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
 MODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver");
@@ -41,8 +43,8 @@
 module_param(margin, int, 0);
 MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
 
 static u16 wdto_restart;
@@ -66,14 +68,13 @@
 
 static void scx200_wdt_update_margin(void)
 {
-	printk(KERN_INFO NAME ": timer margin %d seconds\n", margin);
+	pr_info("timer margin %d seconds\n", margin);
 	wdto_restart = margin * W_SCALE;
 }
 
 static void scx200_wdt_enable(void)
 {
-	printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n",
-	       wdto_restart);
+	pr_debug("enabling watchdog timer, wdto_restart = %d\n", wdto_restart);
 
 	spin_lock(&scx_lock);
 	outw(0, scx200_cb_base + SCx200_WDT_WDTO);
@@ -86,7 +87,7 @@
 
 static void scx200_wdt_disable(void)
 {
-	printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
+	pr_debug("disabling watchdog timer\n");
 
 	spin_lock(&scx_lock);
 	outw(0, scx200_cb_base + SCx200_WDT_WDTO);
@@ -108,9 +109,7 @@
 static int scx200_wdt_release(struct inode *inode, struct file *file)
 {
 	if (expect_close != 42)
-		printk(KERN_WARNING NAME
-			": watchdog device closed unexpectedly, "
-			"will not disable the watchdog timer\n");
+		pr_warn("watchdog device closed unexpectedly, will not disable the watchdog timer\n");
 	else if (!nowayout)
 		scx200_wdt_disable();
 	expect_close = 0;
@@ -219,7 +218,7 @@
 {
 	int r;
 
-	printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n");
+	pr_debug("NatSemi SCx200 Watchdog Driver\n");
 
 	/* check that we have found the configuration block */
 	if (!scx200_cb_present())
@@ -228,7 +227,7 @@
 	if (!request_region(scx200_cb_base + SCx200_WDT_OFFSET,
 			    SCx200_WDT_SIZE,
 			    "NatSemi SCx200 Watchdog")) {
-		printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
+		pr_warn("watchdog I/O region busy\n");
 		return -EBUSY;
 	}
 
@@ -237,7 +236,7 @@
 
 	r = register_reboot_notifier(&scx200_wdt_notifier);
 	if (r) {
-		printk(KERN_ERR NAME ": unable to register reboot notifier");
+		pr_err("unable to register reboot notifier\n");
 		release_region(scx200_cb_base + SCx200_WDT_OFFSET,
 				SCx200_WDT_SIZE);
 		return r;
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c
index a267dc0..93958a7 100644
--- a/drivers/watchdog/shwdt.c
+++ b/drivers/watchdog/shwdt.c
@@ -17,6 +17,9 @@
  *     Added expect close support, made emulated timeout runtime changeable
  *     general cleanups, add some ioctls
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
@@ -72,7 +75,7 @@
 
 #define WATCHDOG_HEARTBEAT 30			/* 30 sec default heartbeat */
 static int heartbeat = WATCHDOG_HEARTBEAT;	/* in seconds */
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static unsigned long next_heartbeat;
 
 struct sh_wdt {
@@ -440,20 +443,20 @@
 		     clock_division_ratio > 0x7)) {
 		clock_division_ratio = WTCSR_CKS_4096;
 
-		pr_info("%s: divisor must be 0x5<=x<=0x7, using %d\n",
-			 DRV_NAME, clock_division_ratio);
+		pr_info("divisor must be 0x5<=x<=0x7, using %d\n",
+			clock_division_ratio);
 	}
 
 	rc = sh_wdt_set_heartbeat(heartbeat);
 	if (unlikely(rc)) {
 		heartbeat = WATCHDOG_HEARTBEAT;
 
-		pr_info("%s: heartbeat value must be 1<=x<=3600, using %d\n",
-			DRV_NAME, heartbeat);
+		pr_info("heartbeat value must be 1<=x<=3600, using %d\n",
+			heartbeat);
 	}
 
-	pr_info("%s: configured with heartbeat=%d sec (nowayout=%d)\n",
-		DRV_NAME, heartbeat, nowayout);
+	pr_info("configured with heartbeat=%d sec (nowayout=%d)\n",
+		heartbeat, nowayout);
 
 	return platform_driver_register(&sh_wdt_driver);
 }
@@ -481,7 +484,7 @@
 	"Watchdog heartbeat in seconds. (1 <= heartbeat <= 3600, default="
 				__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/smsc37b787_wdt.c b/drivers/watchdog/smsc37b787_wdt.c
index 97b8184..6d665f9 100644
--- a/drivers/watchdog/smsc37b787_wdt.c
+++ b/drivers/watchdog/smsc37b787_wdt.c
@@ -43,6 +43,8 @@
  *   Documentation/watchdog/wdt.txt
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -58,7 +60,6 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 
 /* enable support for minutes as units? */
 /* (does not always work correctly, so disabled by default!) */
@@ -70,7 +71,6 @@
 #define UNIT_SECOND     0
 #define UNIT_MINUTE     1
 
-#define MODNAME		"smsc37b787_wdt: "
 #define VERSION		"1.1"
 
 #define IOPORT		0x3F0
@@ -85,7 +85,7 @@
 
 static DEFINE_SPINLOCK(io_lock);/* to guard the watchdog from io races */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 /* -- Low level function ----------------------------------------*/
 
@@ -363,8 +363,7 @@
 	/* Reload and activate timer */
 	wb_smsc_wdt_enable();
 
-	printk(KERN_INFO MODNAME
-		"Watchdog enabled. Timeout set to %d %s.\n",
+	pr_info("Watchdog enabled. Timeout set to %d %s\n",
 		timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
 
 	return nonseekable_open(inode, file);
@@ -378,11 +377,9 @@
 
 	if (expect_close == 42) {
 		wb_smsc_wdt_disable();
-		printk(KERN_INFO MODNAME
-				"Watchdog disabled, sleeping again...\n");
+		pr_info("Watchdog disabled, sleeping again...\n");
 	} else {
-		printk(KERN_CRIT MODNAME
-				"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		wb_smsc_wdt_reset_timer();
 	}
 
@@ -534,12 +531,11 @@
 {
 	int ret;
 
-	printk(KERN_INFO "SMsC 37B787 watchdog component driver "
-					VERSION " initialising...\n");
+	pr_info("SMsC 37B787 watchdog component driver "
+		VERSION " initialising...\n");
 
 	if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) {
-		printk(KERN_ERR MODNAME "Unable to register IO port %#x\n",
-								IOPORT);
+		pr_err("Unable to register IO port %#x\n", IOPORT);
 		ret = -EBUSY;
 		goto out_pnp;
 	}
@@ -553,25 +549,22 @@
 
 	ret = register_reboot_notifier(&wb_smsc_wdt_notifier);
 	if (ret) {
-		printk(KERN_ERR MODNAME
-			"Unable to register reboot notifier err = %d\n", ret);
+		pr_err("Unable to register reboot notifier err = %d\n", ret);
 		goto out_io;
 	}
 
 	ret = misc_register(&wb_smsc_wdt_miscdev);
 	if (ret) {
-		printk(KERN_ERR MODNAME
-			"Unable to register miscdev on minor %d\n",
-							WATCHDOG_MINOR);
+		pr_err("Unable to register miscdev on minor %d\n",
+		       WATCHDOG_MINOR);
 		goto out_rbt;
 	}
 
 	/* output info */
-	printk(KERN_INFO MODNAME "Timeout set to %d %s.\n",
+	pr_info("Timeout set to %d %s\n",
 		timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
-	printk(KERN_INFO MODNAME
-		"Watchdog initialized and sleeping (nowayout=%d)...\n",
-								nowayout);
+	pr_info("Watchdog initialized and sleeping (nowayout=%d)...\n",
+		nowayout);
 out_clean:
 	return ret;
 
@@ -592,14 +585,14 @@
 	/* Stop the timer before we leave */
 	if (!nowayout) {
 		wb_smsc_wdt_shutdown();
-		printk(KERN_INFO MODNAME "Watchdog disabled.\n");
+		pr_info("Watchdog disabled\n");
 	}
 
 	misc_deregister(&wb_smsc_wdt_miscdev);
 	unregister_reboot_notifier(&wb_smsc_wdt_notifier);
 	release_region(IOPORT, IOPORT_SIZE);
 
-	printk(KERN_INFO "SMsC 37B787 watchdog component driver removed.\n");
+	pr_info("SMsC 37B787 watchdog component driver removed\n");
 }
 
 module_init(wb_smsc_wdt_init);
@@ -621,7 +614,7 @@
 module_param(timeout, int, 0);
 MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c
index bf16ffb..fe83beb8 100644
--- a/drivers/watchdog/softdog.c
+++ b/drivers/watchdog/softdog.c
@@ -1,5 +1,5 @@
 /*
- *	SoftDog	0.07:	A Software Watchdog Device
+ *	SoftDog:	A Software Watchdog Device
  *
  *	(c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
  *							All Rights Reserved.
@@ -36,45 +36,37 @@
  *	Added Matt Domsch's nowayout module option.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/timer.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
-#include <linux/fs.h>
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/jiffies.h>
-#include <linux/uaccess.h>
 #include <linux/kernel.h>
 
-#define PFX "SoftDog: "
-
 #define TIMER_MARGIN	60		/* Default is 60 seconds */
-static int soft_margin = TIMER_MARGIN;	/* in seconds */
-module_param(soft_margin, int, 0);
+static unsigned int soft_margin = TIMER_MARGIN;	/* in seconds */
+module_param(soft_margin, uint, 0);
 MODULE_PARM_DESC(soft_margin,
 	"Watchdog soft_margin in seconds. (0 < soft_margin < 65536, default="
 					__MODULE_STRING(TIMER_MARGIN) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
-#ifdef ONLY_TESTING
-static int soft_noboot = 1;
-#else
 static int soft_noboot = 0;
-#endif  /* ONLY_TESTING */
-
 module_param(soft_noboot, int, 0);
 MODULE_PARM_DESC(soft_noboot,
-	"Softdog action, set to 1 to ignore reboots, 0 to reboot "
-					"(default depends on ONLY_TESTING)");
+	"Softdog action, set to 1 to ignore reboots, 0 to reboot (default=0)");
 
 static int soft_panic;
 module_param(soft_panic, int, 0);
@@ -89,9 +81,6 @@
 
 static struct timer_list watchdog_ticktock =
 		TIMER_INITIALIZER(watchdog_fire, 0, 0);
-static unsigned long driver_open, orphan_timer;
-static char expect_close;
-
 
 /*
  *	If the timer expires..
@@ -99,18 +88,15 @@
 
 static void watchdog_fire(unsigned long data)
 {
-	if (test_and_clear_bit(0, &orphan_timer))
-		module_put(THIS_MODULE);
-
 	if (soft_noboot)
-		printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n");
+		pr_crit("Triggered - Reboot ignored\n");
 	else if (soft_panic) {
-		printk(KERN_CRIT PFX "Initiating panic.\n");
-		panic("Software Watchdog Timer expired.");
+		pr_crit("Initiating panic\n");
+		panic("Software Watchdog Timer expired");
 	} else {
-		printk(KERN_CRIT PFX "Initiating system reboot.\n");
+		pr_crit("Initiating system reboot\n");
 		emergency_restart();
-		printk(KERN_CRIT PFX "Reboot didn't ?????\n");
+		pr_crit("Reboot didn't ?????\n");
 	}
 }
 
@@ -118,128 +104,25 @@
  *	Softdog operations
  */
 
-static int softdog_keepalive(void)
+static int softdog_ping(struct watchdog_device *w)
 {
-	mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
+	mod_timer(&watchdog_ticktock, jiffies+(w->timeout*HZ));
 	return 0;
 }
 
-static int softdog_stop(void)
+static int softdog_stop(struct watchdog_device *w)
 {
 	del_timer(&watchdog_ticktock);
 	return 0;
 }
 
-static int softdog_set_heartbeat(int t)
+static int softdog_set_timeout(struct watchdog_device *w, unsigned int t)
 {
-	if ((t < 0x0001) || (t > 0xFFFF))
-		return -EINVAL;
-
-	soft_margin = t;
+	w->timeout = t;
 	return 0;
 }
 
 /*
- *	/dev/watchdog handling
- */
-
-static int softdog_open(struct inode *inode, struct file *file)
-{
-	if (test_and_set_bit(0, &driver_open))
-		return -EBUSY;
-	if (!test_and_clear_bit(0, &orphan_timer))
-		__module_get(THIS_MODULE);
-	/*
-	 *	Activate timer
-	 */
-	softdog_keepalive();
-	return nonseekable_open(inode, file);
-}
-
-static int softdog_release(struct inode *inode, struct file *file)
-{
-	/*
-	 *	Shut off the timer.
-	 *	Lock it in if it's a module and we set nowayout
-	 */
-	if (expect_close == 42) {
-		softdog_stop();
-		module_put(THIS_MODULE);
-	} else {
-		printk(KERN_CRIT PFX
-			"Unexpected close, not stopping watchdog!\n");
-		set_bit(0, &orphan_timer);
-		softdog_keepalive();
-	}
-	clear_bit(0, &driver_open);
-	expect_close = 0;
-	return 0;
-}
-
-static ssize_t softdog_write(struct file *file, const char __user *data,
-						size_t len, loff_t *ppos)
-{
-	/*
-	 *	Refresh the timer.
-	 */
-	if (len) {
-		if (!nowayout) {
-			size_t i;
-
-			/* In case it was set long ago */
-			expect_close = 0;
-
-			for (i = 0; i != len; i++) {
-				char c;
-
-				if (get_user(c, data + i))
-					return -EFAULT;
-				if (c == 'V')
-					expect_close = 42;
-			}
-		}
-		softdog_keepalive();
-	}
-	return len;
-}
-
-static long softdog_ioctl(struct file *file, unsigned int cmd,
-							unsigned long arg)
-{
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-	int new_margin;
-	static const struct watchdog_info ident = {
-		.options =		WDIOF_SETTIMEOUT |
-					WDIOF_KEEPALIVEPING |
-					WDIOF_MAGICCLOSE,
-		.firmware_version =	0,
-		.identity =		"Software Watchdog",
-	};
-	switch (cmd) {
-	case WDIOC_GETSUPPORT:
-		return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
-	case WDIOC_GETSTATUS:
-	case WDIOC_GETBOOTSTATUS:
-		return put_user(0, p);
-	case WDIOC_KEEPALIVE:
-		softdog_keepalive();
-		return 0;
-	case WDIOC_SETTIMEOUT:
-		if (get_user(new_margin, p))
-			return -EFAULT;
-		if (softdog_set_heartbeat(new_margin))
-			return -EINVAL;
-		softdog_keepalive();
-		/* Fall */
-	case WDIOC_GETTIMEOUT:
-		return put_user(soft_margin, p);
-	default:
-		return -ENOTTY;
-	}
-}
-
-/*
  *	Notifier for system down
  */
 
@@ -248,7 +131,7 @@
 {
 	if (code == SYS_DOWN || code == SYS_HALT)
 		/* Turn the WDT off */
-		softdog_stop();
+		softdog_stop(NULL);
 	return NOTIFY_DONE;
 }
 
@@ -256,28 +139,29 @@
  *	Kernel Interfaces
  */
 
-static const struct file_operations softdog_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.write		= softdog_write,
-	.unlocked_ioctl	= softdog_ioctl,
-	.open		= softdog_open,
-	.release	= softdog_release,
-};
-
-static struct miscdevice softdog_miscdev = {
-	.minor		= WATCHDOG_MINOR,
-	.name		= "watchdog",
-	.fops		= &softdog_fops,
-};
-
 static struct notifier_block softdog_notifier = {
 	.notifier_call	= softdog_notify_sys,
 };
 
-static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.07 "
-	"initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d "
-	"(nowayout= %d)\n";
+static struct watchdog_info softdog_info = {
+	.identity = "Software Watchdog",
+	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+};
+
+static struct watchdog_ops softdog_ops = {
+	.owner = THIS_MODULE,
+	.start = softdog_ping,
+	.stop = softdog_stop,
+	.ping = softdog_ping,
+	.set_timeout = softdog_set_timeout,
+};
+
+static struct watchdog_device softdog_dev = {
+	.info = &softdog_info,
+	.ops = &softdog_ops,
+	.min_timeout = 1,
+	.max_timeout = 0xFFFF
+};
 
 static int __init watchdog_init(void)
 {
@@ -285,37 +169,36 @@
 
 	/* Check that the soft_margin value is within it's range;
 	   if not reset to the default */
-	if (softdog_set_heartbeat(soft_margin)) {
-		softdog_set_heartbeat(TIMER_MARGIN);
-		printk(KERN_INFO PFX
-		    "soft_margin must be 0 < soft_margin < 65536, using %d\n",
+	if (soft_margin < 1 || soft_margin > 65535) {
+		pr_info("soft_margin must be 0 < soft_margin < 65536, using %d\n",
 			TIMER_MARGIN);
+		return -EINVAL;
 	}
+	softdog_dev.timeout = soft_margin;
+
+	watchdog_set_nowayout(&softdog_dev, nowayout);
 
 	ret = register_reboot_notifier(&softdog_notifier);
 	if (ret) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", ret);
+		pr_err("cannot register reboot notifier (err=%d)\n", ret);
 		return ret;
 	}
 
-	ret = misc_register(&softdog_miscdev);
+	ret = watchdog_register_device(&softdog_dev);
 	if (ret) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-						WATCHDOG_MINOR, ret);
 		unregister_reboot_notifier(&softdog_notifier);
 		return ret;
 	}
 
-	printk(banner, soft_noboot, soft_margin, soft_panic, nowayout);
+	pr_info("Software Watchdog Timer: 0.08 initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d (nowayout=%d)\n",
+		soft_noboot, soft_margin, soft_panic, nowayout);
 
 	return 0;
 }
 
 static void __exit watchdog_exit(void)
 {
-	misc_deregister(&softdog_miscdev);
+	watchdog_unregister_device(&softdog_dev);
 	unregister_reboot_notifier(&softdog_notifier);
 }
 
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
index 87e0527..59108e4 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -20,6 +20,8 @@
  *	Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -39,7 +41,6 @@
 #define TCO_VERSION "0.01"
 #define TCO_MODULE_NAME "SP5100 TCO timer"
 #define TCO_DRIVER_NAME   TCO_MODULE_NAME ", v" TCO_VERSION
-#define PFX TCO_MODULE_NAME ": "
 
 /* internal variables */
 static u32 tcobase_phys;
@@ -61,8 +62,8 @@
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default="
 		 __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"
 		" (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -143,8 +144,7 @@
 	if (tco_expect_close == 42) {
 		tco_timer_stop();
 	} else {
-		printk(KERN_CRIT PFX
-			"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		tco_timer_keepalive();
 	}
 	clear_bit(0, &timer_alive);
@@ -290,8 +290,7 @@
 	/* Request the IO ports used by this driver */
 	pm_iobase = SP5100_IO_PM_INDEX_REG;
 	if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, "SP5100 TCO")) {
-		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-			pm_iobase);
+		pr_err("I/O address 0x%04x already in use\n", pm_iobase);
 		goto exit;
 	}
 
@@ -308,15 +307,14 @@
 
 	if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE,
 								"SP5100 TCO")) {
-		printk(KERN_ERR PFX "mmio address 0x%04x already in use\n",
-			val);
+		pr_err("mmio address 0x%04x already in use\n", val);
 		goto unreg_region;
 	}
 	tcobase_phys = val;
 
 	tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE);
 	if (tcobase == 0) {
-		printk(KERN_ERR PFX "failed to get tcobase address\n");
+		pr_err("failed to get tcobase address\n");
 		goto unreg_mem_region;
 	}
 
@@ -375,9 +373,9 @@
 		return -ENODEV;
 
 	/* Check to see if last reboot was due to watchdog timeout */
-	printk(KERN_INFO PFX "Watchdog reboot %sdetected.\n",
-	       readl(SP5100_WDT_CONTROL(tcobase)) & SP5100_PM_WATCHDOG_FIRED ?
-		      "" : "not ");
+	pr_info("Watchdog reboot %sdetected\n",
+		readl(SP5100_WDT_CONTROL(tcobase)) & SP5100_PM_WATCHDOG_FIRED ?
+		"" : "not ");
 
 	/* Clear out the old status */
 	val = readl(SP5100_WDT_CONTROL(tcobase));
@@ -395,16 +393,14 @@
 
 	ret = misc_register(&sp5100_tco_miscdev);
 	if (ret != 0) {
-		printk(KERN_ERR PFX "cannot register miscdev on minor="
-		       "%d (err=%d)\n",
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
 		       WATCHDOG_MINOR, ret);
 		goto exit;
 	}
 
 	clear_bit(0, &timer_alive);
 
-	printk(KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec"
-		" (nowayout=%d)\n",
+	pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
 		tcobase, heartbeat, nowayout);
 
 	return 0;
@@ -455,8 +451,7 @@
 {
 	int err;
 
-	printk(KERN_INFO PFX "SP5100 TCO WatchDog Timer Driver v%s\n",
-	       TCO_VERSION);
+	pr_info("SP5100 TCO WatchDog Timer Driver v%s\n", TCO_VERSION);
 
 	err = platform_driver_register(&sp5100_tco_driver);
 	if (err)
@@ -480,7 +475,7 @@
 {
 	platform_device_unregister(sp5100_tco_platform_device);
 	platform_driver_unregister(&sp5100_tco_driver);
-	printk(KERN_INFO PFX "SP5100 TCO Watchdog Module Unloaded.\n");
+	pr_info("SP5100 TCO Watchdog Module Unloaded\n");
 }
 
 module_init(sp5100_tco_init_module);
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
index eef1524..bbb170e 100644
--- a/drivers/watchdog/sp805_wdt.c
+++ b/drivers/watchdog/sp805_wdt.c
@@ -25,6 +25,7 @@
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/pm.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
@@ -55,14 +56,13 @@
 
 /**
  * struct sp805_wdt: sp805 wdt device structure
- *
- * lock: spin lock protecting dev structure and io access
- * base: base address of wdt
- * clk: clock structure of wdt
- * dev: amba device structure of wdt
- * status: current status of wdt
- * load_val: load value to be set for current timeout
- * timeout: current programmed timeout
+ * @lock: spin lock protecting dev structure and io access
+ * @base: base address of wdt
+ * @clk: clock structure of wdt
+ * @adev: amba device structure of wdt
+ * @status: current status of wdt
+ * @load_val: load value to be set for current timeout
+ * @timeout: current programmed timeout
  */
 struct sp805_wdt {
 	spinlock_t			lock;
@@ -78,7 +78,7 @@
 
 /* local variables */
 static struct sp805_wdt *wdt;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 /* This routine finds load value that will reset system in required timout */
 static void wdt_setload(unsigned int timeout)
@@ -113,10 +113,10 @@
 	rate = clk_get_rate(wdt->clk);
 
 	spin_lock(&wdt->lock);
-	load = readl(wdt->base + WDTVALUE);
+	load = readl_relaxed(wdt->base + WDTVALUE);
 
 	/*If the interrupt is inactive then time left is WDTValue + WDTLoad. */
-	if (!(readl(wdt->base + WDTRIS) & INT_MASK))
+	if (!(readl_relaxed(wdt->base + WDTRIS) & INT_MASK))
 		load += wdt->load_val + 1;
 	spin_unlock(&wdt->lock);
 
@@ -128,14 +128,14 @@
 {
 	spin_lock(&wdt->lock);
 
-	writel(UNLOCK, wdt->base + WDTLOCK);
-	writel(wdt->load_val, wdt->base + WDTLOAD);
-	writel(INT_MASK, wdt->base + WDTINTCLR);
-	writel(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL);
-	writel(LOCK, wdt->base + WDTLOCK);
+	writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
+	writel_relaxed(wdt->load_val, wdt->base + WDTLOAD);
+	writel_relaxed(INT_MASK, wdt->base + WDTINTCLR);
+	writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL);
+	writel_relaxed(LOCK, wdt->base + WDTLOCK);
 
 	/* Flush posted writes. */
-	readl(wdt->base + WDTLOCK);
+	readl_relaxed(wdt->base + WDTLOCK);
 	spin_unlock(&wdt->lock);
 }
 
@@ -144,12 +144,12 @@
 {
 	spin_lock(&wdt->lock);
 
-	writel(UNLOCK, wdt->base + WDTLOCK);
-	writel(0, wdt->base + WDTCONTROL);
-	writel(LOCK, wdt->base + WDTLOCK);
+	writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
+	writel_relaxed(0, wdt->base + WDTCONTROL);
+	writel_relaxed(LOCK, wdt->base + WDTLOCK);
 
 	/* Flush posted writes. */
-	readl(wdt->base + WDTLOCK);
+	readl_relaxed(wdt->base + WDTLOCK);
 	spin_unlock(&wdt->lock);
 }
 
@@ -285,32 +285,33 @@
 {
 	int ret = 0;
 
-	if (!request_mem_region(adev->res.start, resource_size(&adev->res),
-				"sp805_wdt")) {
+	if (!devm_request_mem_region(&adev->dev, adev->res.start,
+				resource_size(&adev->res), "sp805_wdt")) {
 		dev_warn(&adev->dev, "Failed to get memory region resource\n");
 		ret = -ENOENT;
 		goto err;
 	}
 
-	wdt = kzalloc(sizeof(*wdt), GFP_KERNEL);
+	wdt = devm_kzalloc(&adev->dev, sizeof(*wdt), GFP_KERNEL);
 	if (!wdt) {
 		dev_warn(&adev->dev, "Kzalloc failed\n");
 		ret = -ENOMEM;
-		goto err_kzalloc;
+		goto err;
+	}
+
+	wdt->base = devm_ioremap(&adev->dev, adev->res.start,
+			resource_size(&adev->res));
+	if (!wdt->base) {
+		ret = -ENOMEM;
+		dev_warn(&adev->dev, "ioremap fail\n");
+		goto err;
 	}
 
 	wdt->clk = clk_get(&adev->dev, NULL);
 	if (IS_ERR(wdt->clk)) {
 		dev_warn(&adev->dev, "Clock not found\n");
 		ret = PTR_ERR(wdt->clk);
-		goto err_clk_get;
-	}
-
-	wdt->base = ioremap(adev->res.start, resource_size(&adev->res));
-	if (!wdt->base) {
-		ret = -ENOMEM;
-		dev_warn(&adev->dev, "ioremap fail\n");
-		goto err_ioremap;
+		goto err;
 	}
 
 	wdt->adev = adev;
@@ -327,14 +328,7 @@
 	return 0;
 
 err_misc_register:
-	iounmap(wdt->base);
-err_ioremap:
 	clk_put(wdt->clk);
-err_clk_get:
-	kfree(wdt);
-	wdt = NULL;
-err_kzalloc:
-	release_mem_region(adev->res.start, resource_size(&adev->res));
 err:
 	dev_err(&adev->dev, "Probe Failed!!!\n");
 	return ret;
@@ -343,14 +337,42 @@
 static int __devexit sp805_wdt_remove(struct amba_device *adev)
 {
 	misc_deregister(&sp805_wdt_miscdev);
-	iounmap(wdt->base);
 	clk_put(wdt->clk);
-	kfree(wdt);
-	release_mem_region(adev->res.start, resource_size(&adev->res));
 
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int sp805_wdt_suspend(struct device *dev)
+{
+	if (test_bit(WDT_BUSY, &wdt->status)) {
+		wdt_disable();
+		clk_disable(wdt->clk);
+	}
+
+	return 0;
+}
+
+static int sp805_wdt_resume(struct device *dev)
+{
+	int ret = 0;
+
+	if (test_bit(WDT_BUSY, &wdt->status)) {
+		ret = clk_enable(wdt->clk);
+		if (ret) {
+			dev_err(dev, "clock enable fail");
+			return ret;
+		}
+		wdt_enable();
+	}
+
+	return ret;
+}
+#endif /* CONFIG_PM */
+
+static SIMPLE_DEV_PM_OPS(sp805_wdt_dev_pm_ops, sp805_wdt_suspend,
+		sp805_wdt_resume);
+
 static struct amba_id sp805_wdt_ids[] = {
 	{
 		.id	= 0x00141805,
@@ -364,25 +386,16 @@
 static struct amba_driver sp805_wdt_driver = {
 	.drv = {
 		.name	= MODULE_NAME,
+		.pm	= &sp805_wdt_dev_pm_ops,
 	},
 	.id_table	= sp805_wdt_ids,
 	.probe		= sp805_wdt_probe,
 	.remove = __devexit_p(sp805_wdt_remove),
 };
 
-static int __init sp805_wdt_init(void)
-{
-	return amba_driver_register(&sp805_wdt_driver);
-}
-module_init(sp805_wdt_init);
+module_amba_driver(sp805_wdt_driver);
 
-static void __exit sp805_wdt_exit(void)
-{
-	amba_driver_unregister(&sp805_wdt_driver);
-}
-module_exit(sp805_wdt_exit);
-
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Set to 1 to keep watchdog running after device release");
 
diff --git a/drivers/watchdog/stmp3xxx_wdt.c b/drivers/watchdog/stmp3xxx_wdt.c
index e37d811..21d96b9 100644
--- a/drivers/watchdog/stmp3xxx_wdt.c
+++ b/drivers/watchdog/stmp3xxx_wdt.c
@@ -6,6 +6,9 @@
  * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
  * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
@@ -32,7 +35,7 @@
 
 static DEFINE_SPINLOCK(stmp3xxx_wdt_io_lock);
 static unsigned long wdt_status;
-static const int nowayout = WATCHDOG_NOWAYOUT;
+static const bool nowayout = WATCHDOG_NOWAYOUT;
 static int heartbeat = DEFAULT_HEARTBEAT;
 static unsigned long boot_status;
 
@@ -221,8 +224,7 @@
 		return ret;
 	}
 
-	printk(KERN_INFO "stmp3xxx watchdog: initialized, heartbeat %d sec\n",
-		heartbeat);
+	pr_info("initialized, heartbeat %d sec\n", heartbeat);
 
 	return ret;
 }
diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c
index 1490293..8df050d 100644
--- a/drivers/watchdog/ts72xx_wdt.c
+++ b/drivers/watchdog/ts72xx_wdt.c
@@ -34,8 +34,8 @@
 			  __MODULE_STRING(TS72XX_WDT_DEFAULT_TIMEOUT)
 			  ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
 
 /**
diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c
index 0764c62..249f113 100644
--- a/drivers/watchdog/twl4030_wdt.c
+++ b/drivers/watchdog/twl4030_wdt.c
@@ -42,8 +42,8 @@
 	unsigned long		state;
 };
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
 	"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c
index 9e9ed7b..98e1637 100644
--- a/drivers/watchdog/txx9wdt.c
+++ b/drivers/watchdog/txx9wdt.c
@@ -7,177 +7,99 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
-#include <linux/fs.h>
 #include <linux/init.h>
-#include <linux/uaccess.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <asm/txx9tmr.h>
 
+#define WD_TIMER_CCD	7		/* 1/256 */
+#define WD_TIMER_CLK	(clk_get_rate(txx9_imclk) / (2 << WD_TIMER_CCD))
+#define WD_MAX_TIMEOUT	((0xffffffff >> (32 - TXX9_TIMER_BITS)) / WD_TIMER_CLK)
 #define TIMER_MARGIN	60		/* Default is 60 seconds */
 
-static int timeout = TIMER_MARGIN;	/* in seconds */
-module_param(timeout, int, 0);
+static unsigned int timeout = TIMER_MARGIN;	/* in seconds */
+module_param(timeout, uint, 0);
 MODULE_PARM_DESC(timeout,
 	"Watchdog timeout in seconds. "
 	"(0<timeout<((2^" __MODULE_STRING(TXX9_TIMER_BITS) ")/(IMCLK/256)), "
 	"default=" __MODULE_STRING(TIMER_MARGIN) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started "
 	"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
-#define WD_TIMER_CCD	7	/* 1/256 */
-#define WD_TIMER_CLK	(clk_get_rate(txx9_imclk) / (2 << WD_TIMER_CCD))
-#define WD_MAX_TIMEOUT	((0xffffffff >> (32 - TXX9_TIMER_BITS)) / WD_TIMER_CLK)
-
-static unsigned long txx9wdt_alive;
-static int expect_close;
 static struct txx9_tmr_reg __iomem *txx9wdt_reg;
 static struct clk *txx9_imclk;
 static DEFINE_SPINLOCK(txx9_lock);
 
-static void txx9wdt_ping(void)
+static int txx9wdt_ping(struct watchdog_device *wdt_dev)
 {
 	spin_lock(&txx9_lock);
 	__raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
 	spin_unlock(&txx9_lock);
+	return 0;
 }
 
-static void txx9wdt_start(void)
+static int txx9wdt_start(struct watchdog_device *wdt_dev)
 {
 	spin_lock(&txx9_lock);
-	__raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra);
+	__raw_writel(WD_TIMER_CLK * wdt_dev->timeout, &txx9wdt_reg->cpra);
 	__raw_writel(WD_TIMER_CCD, &txx9wdt_reg->ccdr);
 	__raw_writel(0, &txx9wdt_reg->tisr);	/* clear pending interrupt */
 	__raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG,
 		     &txx9wdt_reg->tcr);
 	__raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
 	spin_unlock(&txx9_lock);
+	return 0;
 }
 
-static void txx9wdt_stop(void)
+static int txx9wdt_stop(struct watchdog_device *wdt_dev)
 {
 	spin_lock(&txx9_lock);
 	__raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr);
 	__raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE,
 		     &txx9wdt_reg->tcr);
 	spin_unlock(&txx9_lock);
-}
-
-static int txx9wdt_open(struct inode *inode, struct file *file)
-{
-	if (test_and_set_bit(0, &txx9wdt_alive))
-		return -EBUSY;
-
-	if (__raw_readl(&txx9wdt_reg->tcr) & TXx9_TMTCR_TCE) {
-		clear_bit(0, &txx9wdt_alive);
-		return -EBUSY;
-	}
-
-	if (nowayout)
-		__module_get(THIS_MODULE);
-
-	txx9wdt_start();
-	return nonseekable_open(inode, file);
-}
-
-static int txx9wdt_release(struct inode *inode, struct file *file)
-{
-	if (expect_close)
-		txx9wdt_stop();
-	else {
-		printk(KERN_CRIT "txx9wdt: "
-		       "Unexpected close, not stopping watchdog!\n");
-		txx9wdt_ping();
-	}
-	clear_bit(0, &txx9wdt_alive);
-	expect_close = 0;
 	return 0;
 }
 
-static ssize_t txx9wdt_write(struct file *file, const char __user *data,
-			     size_t len, loff_t *ppos)
+static int txx9wdt_set_timeout(struct watchdog_device *wdt_dev,
+			       unsigned int new_timeout)
 {
-	if (len) {
-		if (!nowayout) {
-			size_t i;
-
-			expect_close = 0;
-			for (i = 0; i != len; i++) {
-				char c;
-				if (get_user(c, data + i))
-					return -EFAULT;
-				if (c == 'V')
-					expect_close = 1;
-			}
-		}
-		txx9wdt_ping();
-	}
-	return len;
+	wdt_dev->timeout = new_timeout;
+	txx9wdt_stop(wdt_dev);
+	txx9wdt_start(wdt_dev);
+	return 0;
 }
 
-static long txx9wdt_ioctl(struct file *file, unsigned int cmd,
-							unsigned long arg)
-{
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-	int new_timeout;
-	static const struct watchdog_info ident = {
-		.options =		WDIOF_SETTIMEOUT |
-					WDIOF_KEEPALIVEPING |
-					WDIOF_MAGICCLOSE,
-		.firmware_version =	0,
-		.identity =		"Hardware Watchdog for TXx9",
-	};
-
-	switch (cmd) {
-	case WDIOC_GETSUPPORT:
-		return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
-	case WDIOC_GETSTATUS:
-	case WDIOC_GETBOOTSTATUS:
-		return put_user(0, p);
-	case WDIOC_KEEPALIVE:
-		txx9wdt_ping();
-		return 0;
-	case WDIOC_SETTIMEOUT:
-		if (get_user(new_timeout, p))
-			return -EFAULT;
-		if (new_timeout < 1 || new_timeout > WD_MAX_TIMEOUT)
-			return -EINVAL;
-		timeout = new_timeout;
-		txx9wdt_stop();
-		txx9wdt_start();
-		/* Fall */
-	case WDIOC_GETTIMEOUT:
-		return put_user(timeout, p);
-	default:
-		return -ENOTTY;
-	}
-}
-
-static const struct file_operations txx9wdt_fops = {
-	.owner		=	THIS_MODULE,
-	.llseek		=	no_llseek,
-	.write		=	txx9wdt_write,
-	.unlocked_ioctl =	txx9wdt_ioctl,
-	.open		=	txx9wdt_open,
-	.release	=	txx9wdt_release,
+static const struct watchdog_info txx9wdt_info = {
+	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+	.identity = "Hardware Watchdog for TXx9",
 };
 
-static struct miscdevice txx9wdt_miscdev = {
-	.minor	=	WATCHDOG_MINOR,
-	.name	=	"watchdog",
-	.fops	=	&txx9wdt_fops,
+static const struct watchdog_ops txx9wdt_ops = {
+	.owner = THIS_MODULE,
+	.start = txx9wdt_start,
+	.stop = txx9wdt_stop,
+	.ping = txx9wdt_ping,
+	.set_timeout = txx9wdt_set_timeout,
+};
+
+static struct watchdog_device txx9wdt = {
+	.info = &txx9wdt_info,
+	.ops = &txx9wdt_ops,
 };
 
 static int __init txx9wdt_probe(struct platform_device *dev)
@@ -199,27 +121,27 @@
 	}
 
 	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-	if (!res)
-		goto exit_busy;
-	if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res),
-				     "txx9wdt"))
-		goto exit_busy;
-	txx9wdt_reg = devm_ioremap(&dev->dev, res->start, resource_size(res));
-	if (!txx9wdt_reg)
-		goto exit_busy;
-
-	ret = misc_register(&txx9wdt_miscdev);
-	if (ret) {
+	txx9wdt_reg = devm_request_and_ioremap(&dev->dev, res);
+	if (!txx9wdt_reg) {
+		ret = -EBUSY;
 		goto exit;
 	}
 
-	printk(KERN_INFO "Hardware Watchdog Timer for TXx9: "
-	       "timeout=%d sec (max %ld) (nowayout= %d)\n",
-	       timeout, WD_MAX_TIMEOUT, nowayout);
+	if (timeout < 1 || timeout > WD_MAX_TIMEOUT)
+		timeout = TIMER_MARGIN;
+	txx9wdt.timeout = timeout;
+	txx9wdt.min_timeout = 1;
+	txx9wdt.max_timeout = WD_MAX_TIMEOUT;
+	watchdog_set_nowayout(&txx9wdt, nowayout);
+
+	ret = watchdog_register_device(&txx9wdt);
+	if (ret)
+		goto exit;
+
+	pr_info("Hardware Watchdog Timer: timeout=%d sec (max %ld) (nowayout= %d)\n",
+		timeout, WD_MAX_TIMEOUT, nowayout);
 
 	return 0;
-exit_busy:
-	ret = -EBUSY;
 exit:
 	if (txx9_imclk) {
 		clk_disable(txx9_imclk);
@@ -230,7 +152,7 @@
 
 static int __exit txx9wdt_remove(struct platform_device *dev)
 {
-	misc_deregister(&txx9wdt_miscdev);
+	watchdog_unregister_device(&txx9wdt);
 	clk_disable(txx9_imclk);
 	clk_put(txx9_imclk);
 	return 0;
@@ -238,7 +160,7 @@
 
 static void txx9wdt_shutdown(struct platform_device *dev)
 {
-	txx9wdt_stop();
+	txx9wdt_stop(&txx9wdt);
 }
 
 static struct platform_driver txx9wdt_driver = {
diff --git a/drivers/watchdog/via_wdt.c b/drivers/watchdog/via_wdt.c
index 8f07dd4..465e082 100644
--- a/drivers/watchdog/via_wdt.c
+++ b/drivers/watchdog/via_wdt.c
@@ -10,6 +10,9 @@
  * Caveat: PnP must be enabled in BIOS to allow full access to watchdog
  * control registers. If not, the watchdog must be configured in BIOS manually.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/device.h>
 #include <linux/io.h>
 #include <linux/jiffies.h>
@@ -55,8 +58,8 @@
 MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, between 1 and 1023 "
 	"(default = " __MODULE_STRING(WDT_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
 	"(default = " __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -98,7 +101,7 @@
 static int wdt_ping(struct watchdog_device *wdd)
 {
 	/* calculate when the next userspace timeout will be */
-	next_heartbeat = jiffies + timeout * HZ;
+	next_heartbeat = jiffies + wdd->timeout * HZ;
 	return 0;
 }
 
@@ -106,7 +109,7 @@
 {
 	unsigned int ctl = readl(wdt_mem);
 
-	writel(timeout, wdt_mem + VIA_WDT_COUNT);
+	writel(wdd->timeout, wdt_mem + VIA_WDT_COUNT);
 	writel(ctl | VIA_WDT_RUNNING | VIA_WDT_TRIGGER, wdt_mem);
 	wdt_ping(wdd);
 	mod_timer(&timer, jiffies + WDT_HEARTBEAT);
@@ -125,7 +128,7 @@
 			   unsigned int new_timeout)
 {
 	writel(new_timeout, wdt_mem + VIA_WDT_COUNT);
-	timeout = new_timeout;
+	wdd->timeout = new_timeout;
 	return 0;
 }
 
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
index 576a388..92f1326 100644
--- a/drivers/watchdog/w83627hf_wdt.c
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -26,6 +26,8 @@
  *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -40,10 +42,8 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 
 #define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT"
-#define PFX WATCHDOG_NAME ": "
 #define WATCHDOG_TIMEOUT 60		/* 60 sec default timeout */
 
 static unsigned long wdt_is_open;
@@ -61,8 +61,8 @@
 		"Watchdog timeout in seconds. 1 <= timeout <= 255, default="
 				__MODULE_STRING(WATCHDOG_TIMEOUT) ".");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -119,9 +119,8 @@
 	outb_p(0xF6, WDT_EFER); /* Select CRF6 */
 	t = inb_p(WDT_EFDR);      /* read CRF6 */
 	if (t != 0) {
-		printk(KERN_INFO PFX
-		     "Watchdog already running. Resetting timeout to %d sec\n",
-								timeout);
+		pr_info("Watchdog already running. Resetting timeout to %d sec\n",
+			timeout);
 		outb_p(timeout, WDT_EFDR);    /* Write back to CRF6 */
 	}
 
@@ -290,8 +289,7 @@
 	if (expect_close == 42)
 		wdt_disable();
 	else {
-		printk(KERN_CRIT PFX
-			"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		wdt_ping();
 	}
 	expect_close = 0;
@@ -344,18 +342,16 @@
 {
 	int ret;
 
-	printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising.\n");
+	pr_info("WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising\n");
 
 	if (wdt_set_heartbeat(timeout)) {
 		wdt_set_heartbeat(WATCHDOG_TIMEOUT);
-		printk(KERN_INFO PFX
-		     "timeout value must be 1 <= timeout <= 255, using %d\n",
-				WATCHDOG_TIMEOUT);
+		pr_info("timeout value must be 1 <= timeout <= 255, using %d\n",
+			WATCHDOG_TIMEOUT);
 	}
 
 	if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
-		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-			wdt_io);
+		pr_err("I/O address 0x%04x already in use\n", wdt_io);
 		ret = -EIO;
 		goto out;
 	}
@@ -364,22 +360,19 @@
 
 	ret = register_reboot_notifier(&wdt_notifier);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", ret);
+		pr_err("cannot register reboot notifier (err=%d)\n", ret);
 		goto unreg_regions;
 	}
 
 	ret = misc_register(&wdt_miscdev);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-							WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto unreg_reboot;
 	}
 
-	printk(KERN_INFO PFX
-			"initialized. timeout=%d sec (nowayout=%d)\n",
-							timeout, nowayout);
+	pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
+		timeout, nowayout);
 
 out:
 	return ret;
diff --git a/drivers/watchdog/w83697hf_wdt.c b/drivers/watchdog/w83697hf_wdt.c
index af08972..cd9f3c1 100644
--- a/drivers/watchdog/w83697hf_wdt.c
+++ b/drivers/watchdog/w83697hf_wdt.c
@@ -25,6 +25,8 @@
  *	"AS-IS" and at no charge.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -39,10 +41,8 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 
 #define WATCHDOG_NAME "w83697hf/hg WDT"
-#define PFX WATCHDOG_NAME ": "
 #define WATCHDOG_TIMEOUT 60		/* 60 sec default timeout */
 #define WATCHDOG_EARLY_DISABLE 1	/* Disable until userland kicks in */
 
@@ -62,8 +62,8 @@
 	"Watchdog timeout in seconds. 1<= timeout <=255 (default="
 				__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -309,8 +309,7 @@
 	if (expect_close == 42)
 		wdt_disable();
 	else {
-		printk(KERN_CRIT PFX
-			"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		wdt_ping();
 	}
 	expect_close = 0;
@@ -362,24 +361,21 @@
 static int w83697hf_check_wdt(void)
 {
 	if (!request_region(wdt_io, 2, WATCHDOG_NAME)) {
-		printk(KERN_ERR PFX
-			"I/O address 0x%x already in use\n", wdt_io);
+		pr_err("I/O address 0x%x already in use\n", wdt_io);
 		return -EIO;
 	}
 
-	printk(KERN_DEBUG PFX
-			"Looking for watchdog at address 0x%x\n", wdt_io);
+	pr_debug("Looking for watchdog at address 0x%x\n", wdt_io);
 	w83697hf_unlock();
 	if (w83697hf_get_reg(0x20) == 0x60) {
-		printk(KERN_INFO PFX
-			"watchdog found at address 0x%x\n", wdt_io);
+		pr_info("watchdog found at address 0x%x\n", wdt_io);
 		w83697hf_lock();
 		return 0;
 	}
 	/* Reprotect in case it was a compatible device */
 	w83697hf_lock();
 
-	printk(KERN_INFO PFX "watchdog not found at address 0x%x\n", wdt_io);
+	pr_info("watchdog not found at address 0x%x\n", wdt_io);
 	release_region(wdt_io, 2);
 	return -EIO;
 }
@@ -390,7 +386,7 @@
 {
 	int ret, i, found = 0;
 
-	printk(KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n");
+	pr_info("WDT driver for W83697HF/HG initializing\n");
 
 	if (wdt_io == 0) {
 		/* we will autodetect the W83697HF/HG watchdog */
@@ -405,7 +401,7 @@
 	}
 
 	if (!found) {
-		printk(KERN_ERR PFX "No W83697HF/HG could be found\n");
+		pr_err("No W83697HF/HG could be found\n");
 		ret = -EIO;
 		goto out;
 	}
@@ -413,34 +409,30 @@
 	w83697hf_init();
 	if (early_disable) {
 		if (wdt_running())
-			printk(KERN_WARNING PFX "Stopping previously enabled "
-					"watchdog until userland kicks in\n");
+			pr_warn("Stopping previously enabled watchdog until userland kicks in\n");
 		wdt_disable();
 	}
 
 	if (wdt_set_heartbeat(timeout)) {
 		wdt_set_heartbeat(WATCHDOG_TIMEOUT);
-		printk(KERN_INFO PFX
-		     "timeout value must be 1 <= timeout <= 255, using %d\n",
-							WATCHDOG_TIMEOUT);
+		pr_info("timeout value must be 1 <= timeout <= 255, using %d\n",
+			WATCHDOG_TIMEOUT);
 	}
 
 	ret = register_reboot_notifier(&wdt_notifier);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", ret);
+		pr_err("cannot register reboot notifier (err=%d)\n", ret);
 		goto unreg_regions;
 	}
 
 	ret = misc_register(&wdt_miscdev);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-						WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto unreg_reboot;
 	}
 
-	printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+	pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
 		timeout, nowayout);
 
 out:
diff --git a/drivers/watchdog/w83697ug_wdt.c b/drivers/watchdog/w83697ug_wdt.c
index be9c4d8..274be0b 100644
--- a/drivers/watchdog/w83697ug_wdt.c
+++ b/drivers/watchdog/w83697ug_wdt.c
@@ -30,6 +30,8 @@
  *	(c) Copyright 1995    Alan Cox <alan@redhat.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -44,10 +46,8 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 
 #define WATCHDOG_NAME "w83697ug/uf WDT"
-#define PFX WATCHDOG_NAME ": "
 #define WATCHDOG_TIMEOUT 60		/* 60 sec default timeout */
 
 static unsigned long wdt_is_open;
@@ -64,8 +64,8 @@
 	"Watchdog timeout in seconds. 1<= timeout <=255 (default="
 				__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -91,8 +91,8 @@
 	version = inb(WDT_EFDR);
 
 	if (version == 0x68) {	/* W83697UG		*/
-		printk(KERN_INFO PFX "Watchdog chip version 0x%02x = "
-			"W83697UG/UF found at 0x%04x\n", version, wdt_io);
+		pr_info("Watchdog chip version 0x%02x = W83697UG/UF found at 0x%04x\n",
+			version, wdt_io);
 
 		outb_p(0x2b, WDT_EFER);
 		c = inb_p(WDT_EFDR);    /* select WDT0 */
@@ -101,7 +101,7 @@
 		outb_p(c, WDT_EFDR);	/* set pin118 to WDT0 */
 
 	} else {
-		printk(KERN_ERR PFX "No W83697UG/UF could be found\n");
+		pr_err("No W83697UG/UF could be found\n");
 		return -ENODEV;
 	}
 
@@ -131,8 +131,8 @@
 	outb_p(0xF6, WDT_EFER); /* Select CRF6 */
 	t = inb_p(WDT_EFDR);    /* read CRF6 */
 	if (t != 0) {
-		printk(KERN_INFO PFX "Watchdog already running."
-			" Resetting timeout to %d sec\n", timeout);
+		pr_info("Watchdog already running. Resetting timeout to %d sec\n",
+			timeout);
 		outb_p(timeout, WDT_EFDR);    /* Write back to CRF6 */
 	}
 	outb_p(0xF5, WDT_EFER); /* Select CRF5 */
@@ -286,8 +286,7 @@
 	if (expect_close == 42)
 		wdt_disable();
 	else {
-		printk(KERN_CRIT PFX
-			"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 		wdt_ping();
 	}
 	expect_close = 0;
@@ -340,18 +339,16 @@
 {
 	int ret;
 
-	printk(KERN_INFO "WDT driver for the Winbond(TM) W83697UG/UF Super I/O chip initialising.\n");
+	pr_info("WDT driver for the Winbond(TM) W83697UG/UF Super I/O chip initialising\n");
 
 	if (wdt_set_heartbeat(timeout)) {
 		wdt_set_heartbeat(WATCHDOG_TIMEOUT);
-		printk(KERN_INFO PFX
-			"timeout value must be 1<=timeout<=255, using %d\n",
+		pr_info("timeout value must be 1<=timeout<=255, using %d\n",
 			WATCHDOG_TIMEOUT);
 	}
 
 	if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
-		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-			wdt_io);
+		pr_err("I/O address 0x%04x already in use\n", wdt_io);
 		ret = -EIO;
 		goto out;
 	}
@@ -362,20 +359,18 @@
 
 	ret = register_reboot_notifier(&wdt_notifier);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", ret);
+		pr_err("cannot register reboot notifier (err=%d)\n", ret);
 		goto unreg_regions;
 	}
 
 	ret = misc_register(&wdt_miscdev);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-			WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto unreg_reboot;
 	}
 
-	printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+	pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
 		timeout, nowayout);
 
 out:
diff --git a/drivers/watchdog/w83877f_wdt.c b/drivers/watchdog/w83877f_wdt.c
index 24587d2..7874ae0 100644
--- a/drivers/watchdog/w83877f_wdt.c
+++ b/drivers/watchdog/w83877f_wdt.c
@@ -42,6 +42,8 @@
  *  daemon always getting scheduled within that time frame.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -56,10 +58,8 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
-#include <asm/system.h>
 
 #define OUR_NAME "w83877f_wdt"
-#define PFX OUR_NAME ": "
 
 #define ENABLE_W83877F_PORT 0x3F0
 #define ENABLE_W83877F 0x87
@@ -91,8 +91,8 @@
 				__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -126,8 +126,7 @@
 		spin_unlock(&wdt_spinlock);
 
 	} else
-		printk(KERN_WARNING PFX
-			"Heartbeat lost! Will not ping the watchdog\n");
+		pr_warn("Heartbeat lost! Will not ping the watchdog\n");
 }
 
 /*
@@ -165,7 +164,7 @@
 
 	wdt_change(WDT_ENABLE);
 
-	printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+	pr_info("Watchdog timer is now enabled\n");
 }
 
 static void wdt_turnoff(void)
@@ -175,7 +174,7 @@
 
 	wdt_change(WDT_DISABLE);
 
-	printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+	pr_info("Watchdog timer is now disabled...\n");
 }
 
 static void wdt_keepalive(void)
@@ -234,8 +233,7 @@
 		wdt_turnoff();
 	else {
 		del_timer(&timer);
-		printk(KERN_CRIT PFX
-		  "device file closed unexpectedly. Will not stop the WDT!\n");
+		pr_crit("device file closed unexpectedly. Will not stop the WDT!\n");
 	}
 	clear_bit(0, &wdt_is_open);
 	wdt_expect_close = 0;
@@ -357,42 +355,37 @@
 
 	if (timeout < 1 || timeout > 3600) { /* arbitrary upper limit */
 		timeout = WATCHDOG_TIMEOUT;
-		printk(KERN_INFO PFX
-			"timeout value must be 1 <= x <= 3600, using %d\n",
-							timeout);
+		pr_info("timeout value must be 1 <= x <= 3600, using %d\n",
+			timeout);
 	}
 
 	if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT")) {
-		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-			ENABLE_W83877F_PORT);
+		pr_err("I/O address 0x%04x already in use\n",
+		       ENABLE_W83877F_PORT);
 		rc = -EIO;
 		goto err_out;
 	}
 
 	if (!request_region(WDT_PING, 1, "W8387FF WDT")) {
-		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-			WDT_PING);
+		pr_err("I/O address 0x%04x already in use\n", WDT_PING);
 		rc = -EIO;
 		goto err_out_region1;
 	}
 
 	rc = register_reboot_notifier(&wdt_notifier);
 	if (rc) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", rc);
+		pr_err("cannot register reboot notifier (err=%d)\n", rc);
 		goto err_out_region2;
 	}
 
 	rc = misc_register(&wdt_miscdev);
 	if (rc) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-							wdt_miscdev.minor, rc);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       wdt_miscdev.minor, rc);
 		goto err_out_reboot;
 	}
 
-	printk(KERN_INFO PFX
-	  "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n",
+	pr_info("WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n",
 		timeout, nowayout);
 
 	return 0;
diff --git a/drivers/watchdog/w83977f_wdt.c b/drivers/watchdog/w83977f_wdt.c
index 6e6743d..5d2c902 100644
--- a/drivers/watchdog/w83977f_wdt.c
+++ b/drivers/watchdog/w83977f_wdt.c
@@ -15,6 +15,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -29,12 +31,9 @@
 #include <linux/uaccess.h>
 #include <linux/io.h>
 
-#include <asm/system.h>
 
 #define WATCHDOG_VERSION  "1.00"
 #define WATCHDOG_NAME     "W83977F WDT"
-#define PFX WATCHDOG_NAME ": "
-#define DRIVER_VERSION    WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
 
 #define IO_INDEX_PORT     0x3F0
 #define IO_DATA_PORT      (IO_INDEX_PORT+1)
@@ -59,8 +58,8 @@
 module_param(testmode, int, 0);
 MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -131,7 +130,7 @@
 
 	spin_unlock_irqrestore(&spinlock, flags);
 
-	printk(KERN_INFO PFX "activated.\n");
+	pr_info("activated\n");
 
 	return 0;
 }
@@ -185,7 +184,7 @@
 
 	spin_unlock_irqrestore(&spinlock, flags);
 
-	printk(KERN_INFO PFX "shutdown.\n");
+	pr_info("shutdown\n");
 
 	return 0;
 }
@@ -313,8 +312,7 @@
 		clear_bit(0, &timer_alive);
 	} else {
 		wdt_keepalive();
-		printk(KERN_CRIT PFX
-			"unexpected close, not stopping watchdog!\n");
+		pr_crit("unexpected close, not stopping watchdog!\n");
 	}
 	expect_close = 0;
 	return 0;
@@ -471,7 +469,7 @@
 {
 	int rc;
 
-	printk(KERN_INFO PFX DRIVER_VERSION);
+	pr_info("driver v%s\n", WATCHDOG_VERSION);
 
 	/*
 	 * Check that the timeout value is within it's range;
@@ -479,36 +477,31 @@
 	 */
 	if (wdt_set_timeout(timeout)) {
 		wdt_set_timeout(DEFAULT_TIMEOUT);
-		printk(KERN_INFO PFX
-		    "timeout value must be 15 <= timeout <= 7635, using %d\n",
-							DEFAULT_TIMEOUT);
+		pr_info("timeout value must be 15 <= timeout <= 7635, using %d\n",
+			DEFAULT_TIMEOUT);
 	}
 
 	if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) {
-		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-			IO_INDEX_PORT);
+		pr_err("I/O address 0x%04x already in use\n", IO_INDEX_PORT);
 		rc = -EIO;
 		goto err_out;
 	}
 
 	rc = register_reboot_notifier(&wdt_notifier);
 	if (rc) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", rc);
+		pr_err("cannot register reboot notifier (err=%d)\n", rc);
 		goto err_out_region;
 	}
 
 	rc = misc_register(&wdt_miscdev);
 	if (rc) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-						wdt_miscdev.minor, rc);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       wdt_miscdev.minor, rc);
 		goto err_out_reboot;
 	}
 
-	printk(KERN_INFO PFX
-		"initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
-					timeout, nowayout, testmode);
+	pr_info("initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
+		timeout, nowayout, testmode);
 
 	return 0;
 
diff --git a/drivers/watchdog/wafer5823wdt.c b/drivers/watchdog/wafer5823wdt.c
index c3c3188..25aba6e 100644
--- a/drivers/watchdog/wafer5823wdt.c
+++ b/drivers/watchdog/wafer5823wdt.c
@@ -26,6 +26,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/miscdevice.h>
@@ -65,8 +67,8 @@
 		"Watchdog timeout in seconds. 1 <= timeout <= 255, default="
 				__MODULE_STRING(WD_TIMO) ".");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -203,8 +205,7 @@
 	if (expect_close == 42)
 		wafwdt_stop();
 	else {
-		printk(KERN_CRIT PFX
-		    "WDT device closed unexpectedly.  WDT will not stop!\n");
+		pr_crit("WDT device closed unexpectedly.  WDT will not stop!\n");
 		wafwdt_ping();
 	}
 	clear_bit(0, &wafwdt_is_open);
@@ -256,49 +257,42 @@
 {
 	int ret;
 
-	printk(KERN_INFO
-	  "WDT driver for Wafer 5823 single board computer initialising.\n");
+	pr_info("WDT driver for Wafer 5823 single board computer initialising\n");
 
 	if (timeout < 1 || timeout > 255) {
 		timeout = WD_TIMO;
-		printk(KERN_INFO PFX
-			"timeout value must be 1 <= x <= 255, using %d\n",
-								timeout);
+		pr_info("timeout value must be 1 <= x <= 255, using %d\n",
+			timeout);
 	}
 
 	if (wdt_stop != wdt_start) {
 		if (!request_region(wdt_stop, 1, "Wafer 5823 WDT")) {
-			printk(KERN_ERR PFX
-				"I/O address 0x%04x already in use\n",
-								wdt_stop);
+			pr_err("I/O address 0x%04x already in use\n", wdt_stop);
 			ret = -EIO;
 			goto error;
 		}
 	}
 
 	if (!request_region(wdt_start, 1, "Wafer 5823 WDT")) {
-		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-			wdt_start);
+		pr_err("I/O address 0x%04x already in use\n", wdt_start);
 		ret = -EIO;
 		goto error2;
 	}
 
 	ret = register_reboot_notifier(&wafwdt_notifier);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", ret);
+		pr_err("cannot register reboot notifier (err=%d)\n", ret);
 		goto error3;
 	}
 
 	ret = misc_register(&wafwdt_miscdev);
 	if (ret != 0) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-						WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto error4;
 	}
 
-	printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+	pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
 		timeout, nowayout);
 
 	return ret;
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
index cfa1a15..14d768b 100644
--- a/drivers/watchdog/watchdog_core.c
+++ b/drivers/watchdog/watchdog_core.c
@@ -77,7 +77,7 @@
 	/* We only support 1 watchdog device via the /dev/watchdog interface */
 	ret = watchdog_dev_register(wdd);
 	if (ret) {
-		pr_err("error registering /dev/watchdog (err=%d).\n", ret);
+		pr_err("error registering /dev/watchdog (err=%d)\n", ret);
 		return ret;
 	}
 
@@ -101,7 +101,7 @@
 
 	ret = watchdog_dev_unregister(wdd);
 	if (ret)
-		pr_err("error unregistering /dev/watchdog (err=%d).\n", ret);
+		pr_err("error unregistering /dev/watchdog (err=%d)\n", ret);
 }
 EXPORT_SYMBOL_GPL(watchdog_unregister_device);
 
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 1199da0..8558da9 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -226,7 +226,6 @@
 		err = wdd->ops->set_timeout(wdd, val);
 		if (err < 0)
 			return err;
-		wdd->timeout = val;
 		/* If the watchdog is active then we send a keepalive ping
 		 * to make sure that the watchdog keep's running (and if
 		 * possible that it takes the new timeout) */
@@ -237,6 +236,11 @@
 		if (wdd->timeout == 0)
 			return -EOPNOTSUPP;
 		return put_user(wdd->timeout, p);
+	case WDIOC_GETTIMELEFT:
+		if (!wdd->ops->get_timeleft)
+			return -EOPNOTSUPP;
+
+		return put_user(wdd->ops->get_timeleft(wdd), p);
 	default:
 		return -ENOTTY;
 	}
@@ -347,7 +351,7 @@
 
 	/* Only one device can register for /dev/watchdog */
 	if (test_and_set_bit(0, &watchdog_dev_busy)) {
-		pr_err("only one watchdog can use /dev/watchdog.\n");
+		pr_err("only one watchdog can use /dev/watchdog\n");
 		return -EBUSY;
 	}
 
@@ -355,8 +359,8 @@
 
 	err = misc_register(&watchdog_miscdev);
 	if (err != 0) {
-		pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n",
-			watchdog->info->identity, WATCHDOG_MINOR, err);
+		pr_err("%s: cannot register miscdev on minor=%d (err=%d)\n",
+		       watchdog->info->identity, WATCHDOG_MINOR, err);
 		goto out;
 	}
 
@@ -383,8 +387,8 @@
 
 	/* We can only unregister the watchdog device that was registered */
 	if (watchdog != wdd) {
-		pr_err("%s: watchdog was not registered as /dev/watchdog.\n",
-			watchdog->info->identity);
+		pr_err("%s: watchdog was not registered as /dev/watchdog\n",
+		       watchdog->info->identity);
 		return -ENODEV;
 	}
 
diff --git a/drivers/watchdog/wdrtas.c b/drivers/watchdog/wdrtas.c
index 94ec22b..0a77655 100644
--- a/drivers/watchdog/wdrtas.c
+++ b/drivers/watchdog/wdrtas.c
@@ -26,6 +26,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -49,7 +51,7 @@
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 MODULE_ALIAS_MISCDEV(TEMP_MINOR);
 
-static int wdrtas_nowayout = WATCHDOG_NOWAYOUT;
+static bool wdrtas_nowayout = WATCHDOG_NOWAYOUT;
 static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0);
 static char wdrtas_expect_close;
 
@@ -93,8 +95,8 @@
 	result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL,
 			   WDRTAS_SURVEILLANCE_IND, 0, interval);
 	if (result < 0 && print_msg) {
-		printk(KERN_ERR "wdrtas: setting the watchdog to %i "
-		       "timeout failed: %li\n", interval, result);
+		pr_err("setting the watchdog to %i timeout failed: %li\n",
+		       interval, result);
 		print_msg--;
 	}
 
@@ -128,8 +130,8 @@
 	spin_unlock(&rtas_data_buf_lock);
 
 	if (value[0] != 0 || value[1] != 2 || value[3] != 0 || result < 0) {
-		printk(KERN_WARNING "wdrtas: could not get sp_spi watchdog "
-		       "timeout (%li). Continuing\n", result);
+		pr_warn("could not get sp_spi watchdog timeout (%li). Continuing\n",
+			result);
 		return fallback_value;
 	}
 
@@ -170,18 +172,18 @@
 	int i;
 
 	for (i = 0; i < WDRTAS_LOGBUFFER_LEN; i += 16)
-		printk(KERN_INFO "wdrtas: dumping event (line %i/%i), data = "
-		       "%02x %02x %02x %02x  %02x %02x %02x %02x   "
-		       "%02x %02x %02x %02x  %02x %02x %02x %02x\n",
-		       (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16),
-		       wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1],
-		       wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3],
-		       wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5],
-		       wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7],
-		       wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9],
-		       wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11],
-		       wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13],
-		       wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]);
+		pr_info("dumping event (line %i/%i), data = "
+			"%02x %02x %02x %02x  %02x %02x %02x %02x   "
+			"%02x %02x %02x %02x  %02x %02x %02x %02x\n",
+			(i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16),
+			wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1],
+			wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3],
+			wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5],
+			wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7],
+			wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9],
+			wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11],
+			wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13],
+			wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]);
 }
 
 /**
@@ -201,8 +203,7 @@
 				   (void *)__pa(wdrtas_logbuffer),
 				   WDRTAS_LOGBUFFER_LEN);
 		if (result < 0)
-			printk(KERN_ERR "wdrtas: event-scan failed: %li\n",
-			       result);
+			pr_err("event-scan failed: %li\n", result);
 		if (result == 0)
 			wdrtas_log_scanned_event();
 	} while (result == 0);
@@ -224,8 +225,7 @@
 	result = rtas_get_sensor(WDRTAS_THERMAL_SENSOR, 0, &temperature);
 
 	if (result < 0)
-		printk(KERN_WARNING "wdrtas: reading the thermal sensor "
-		       "failed: %i\n", result);
+		pr_warn("reading the thermal sensor failed: %i\n", result);
 	else
 		temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */
 
@@ -419,8 +419,7 @@
 	if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR)
 		wdrtas_timer_stop();
 	else {
-		printk(KERN_WARNING "wdrtas: got unexpected close. Watchdog "
-		       "not stopped.\n");
+		pr_warn("got unexpected close. Watchdog not stopped.\n");
 		wdrtas_timer_keepalive();
 	}
 
@@ -552,30 +551,24 @@
 {
 	wdrtas_token_get_sensor_state = rtas_token("get-sensor-state");
 	if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) {
-		printk(KERN_WARNING "wdrtas: couldn't get token for "
-		       "get-sensor-state. Trying to continue without "
-		       "temperature support.\n");
+		pr_warn("couldn't get token for get-sensor-state. Trying to continue without temperature support.\n");
 	}
 
 	wdrtas_token_get_sp = rtas_token("ibm,get-system-parameter");
 	if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) {
-		printk(KERN_WARNING "wdrtas: couldn't get token for "
-		       "ibm,get-system-parameter. Trying to continue with "
-		       "a default timeout value of %i seconds.\n",
-		       WDRTAS_DEFAULT_INTERVAL);
+		pr_warn("couldn't get token for ibm,get-system-parameter. Trying to continue with a default timeout value of %i seconds.\n",
+			WDRTAS_DEFAULT_INTERVAL);
 	}
 
 	wdrtas_token_set_indicator = rtas_token("set-indicator");
 	if (wdrtas_token_set_indicator == RTAS_UNKNOWN_SERVICE) {
-		printk(KERN_ERR "wdrtas: couldn't get token for "
-		       "set-indicator. Terminating watchdog code.\n");
+		pr_err("couldn't get token for set-indicator. Terminating watchdog code.\n");
 		return -EIO;
 	}
 
 	wdrtas_token_event_scan = rtas_token("event-scan");
 	if (wdrtas_token_event_scan == RTAS_UNKNOWN_SERVICE) {
-		printk(KERN_ERR "wdrtas: couldn't get token for event-scan. "
-		       "Terminating watchdog code.\n");
+		pr_err("couldn't get token for event-scan. Terminating watchdog code.\n");
 		return -EIO;
 	}
 
@@ -609,17 +602,14 @@
 
 	result = misc_register(&wdrtas_miscdev);
 	if (result) {
-		printk(KERN_ERR "wdrtas: couldn't register watchdog misc "
-		       "device. Terminating watchdog code.\n");
+		pr_err("couldn't register watchdog misc device. Terminating watchdog code.\n");
 		return result;
 	}
 
 	if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) {
 		result = misc_register(&wdrtas_tempdev);
 		if (result) {
-			printk(KERN_WARNING "wdrtas: couldn't register "
-			       "watchdog temperature misc device. Continuing "
-			       "without temperature support.\n");
+			pr_warn("couldn't register watchdog temperature misc device. Continuing without temperature support.\n");
 			wdrtas_token_get_sensor_state = RTAS_UNKNOWN_SERVICE;
 		}
 	}
@@ -643,8 +633,7 @@
 		return -ENODEV;
 
 	if (register_reboot_notifier(&wdrtas_notifier)) {
-		printk(KERN_ERR "wdrtas: could not register reboot notifier. "
-		       "Terminating watchdog code.\n");
+		pr_err("could not register reboot notifier. Terminating watchdog code.\n");
 		wdrtas_unregister_devs();
 		return -ENODEV;
 	}
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c
index d2ef002..ee4333c 100644
--- a/drivers/watchdog/wdt.c
+++ b/drivers/watchdog/wdt.c
@@ -32,6 +32,8 @@
  *		Matt Domsch	:	Added nowayout module option
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -46,7 +48,6 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 #include "wd501p.h"
 
 static unsigned long wdt_is_open;
@@ -65,8 +66,8 @@
 	"Watchdog heartbeat in seconds. (0 < heartbeat < 65536, default="
 				__MODULE_STRING(WD_TIMO) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -252,11 +253,11 @@
 static void wdt_decode_501(int status)
 {
 	if (!(status & WDC_SR_TGOOD))
-		printk(KERN_CRIT "Overheat alarm.(%d)\n", inb_p(WDT_RT));
+		pr_crit("Overheat alarm (%d)\n", inb_p(WDT_RT));
 	if (!(status & WDC_SR_PSUOVER))
-		printk(KERN_CRIT "PSU over voltage.\n");
+		pr_crit("PSU over voltage\n");
 	if (!(status & WDC_SR_PSUUNDR))
-		printk(KERN_CRIT "PSU under voltage.\n");
+		pr_crit("PSU under voltage\n");
 }
 
 /**
@@ -280,25 +281,25 @@
 	spin_lock(&wdt_lock);
 	status = inb_p(WDT_SR);
 
-	printk(KERN_CRIT "WDT status %d\n", status);
+	pr_crit("WDT status %d\n", status);
 
 	if (type == 501) {
 		wdt_decode_501(status);
 		if (tachometer) {
 			if (!(status & WDC_SR_FANGOOD))
-				printk(KERN_CRIT "Possible fan fault.\n");
+				pr_crit("Possible fan fault\n");
 		}
 	}
 	if (!(status & WDC_SR_WCCR)) {
 #ifdef SOFTWARE_REBOOT
 #ifdef ONLY_TESTING
-		printk(KERN_CRIT "Would Reboot.\n");
+		pr_crit("Would Reboot\n");
 #else
-		printk(KERN_CRIT "Initiating system reboot.\n");
+		pr_crit("Initiating system reboot\n");
 		emergency_restart();
 #endif
 #else
-		printk(KERN_CRIT "Reset in 5ms.\n");
+		pr_crit("Reset in 5ms\n");
 #endif
 	}
 	spin_unlock(&wdt_lock);
@@ -441,8 +442,7 @@
 		wdt_stop();
 		clear_bit(0, &wdt_is_open);
 	} else {
-		printk(KERN_CRIT
-		 "wdt: WDT device closed unexpectedly.  WDT will not stop!\n");
+		pr_crit("WDT device closed unexpectedly.  WDT will not stop!\n");
 		wdt_ping();
 	}
 	expect_close = 0;
@@ -593,7 +593,7 @@
 	int ret;
 
 	if (type != 500 && type != 501) {
-		printk(KERN_ERR "wdt: unknown card type '%d'.\n", type);
+		pr_err("unknown card type '%d'\n", type);
 		return -ENODEV;
 	}
 
@@ -601,53 +601,49 @@
 	   if not reset to the default */
 	if (wdt_set_heartbeat(heartbeat)) {
 		wdt_set_heartbeat(WD_TIMO);
-		printk(KERN_INFO "wdt: heartbeat value must be "
-			"0 < heartbeat < 65536, using %d\n", WD_TIMO);
+		pr_info("heartbeat value must be 0 < heartbeat < 65536, using %d\n",
+			WD_TIMO);
 	}
 
 	if (!request_region(io, 8, "wdt501p")) {
-		printk(KERN_ERR
-			"wdt: I/O address 0x%04x already in use\n", io);
+		pr_err("I/O address 0x%04x already in use\n", io);
 		ret = -EBUSY;
 		goto out;
 	}
 
 	ret = request_irq(irq, wdt_interrupt, 0, "wdt501p", NULL);
 	if (ret) {
-		printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq);
+		pr_err("IRQ %d is not free\n", irq);
 		goto outreg;
 	}
 
 	ret = register_reboot_notifier(&wdt_notifier);
 	if (ret) {
-		printk(KERN_ERR
-		      "wdt: cannot register reboot notifier (err=%d)\n", ret);
+		pr_err("cannot register reboot notifier (err=%d)\n", ret);
 		goto outirq;
 	}
 
 	if (type == 501) {
 		ret = misc_register(&temp_miscdev);
 		if (ret) {
-			printk(KERN_ERR "wdt: cannot register miscdev "
-				"on minor=%d (err=%d)\n", TEMP_MINOR, ret);
+			pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+			       TEMP_MINOR, ret);
 			goto outrbt;
 		}
 	}
 
 	ret = misc_register(&wdt_miscdev);
 	if (ret) {
-		printk(KERN_ERR
-			"wdt: cannot register miscdev on minor=%d (err=%d)\n",
-							WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto outmisc;
 	}
 
-	printk(KERN_INFO "WDT500/501-P driver 0.10 "
-		"at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n",
+	pr_info("WDT500/501-P driver 0.10 at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n",
 		io, irq, heartbeat, nowayout);
 	if (type == 501)
-		printk(KERN_INFO "wdt: Fan Tachometer is %s\n",
-				(tachometer ? "Enabled" : "Disabled"));
+		pr_info("Fan Tachometer is %s\n",
+			tachometer ? "Enabled" : "Disabled");
 	return 0;
 
 outmisc:
diff --git a/drivers/watchdog/wdt285.c b/drivers/watchdog/wdt285.c
index f551356..5eec740 100644
--- a/drivers/watchdog/wdt285.c
+++ b/drivers/watchdog/wdt285.c
@@ -16,6 +16,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -32,6 +34,7 @@
 #include <mach/hardware.h>
 
 #include <asm/mach-types.h>
+#include <asm/system_info.h>
 #include <asm/hardware/dec21285.h>
 
 /*
@@ -49,7 +52,7 @@
  */
 static void watchdog_fire(int irq, void *dev_id)
 {
-	printk(KERN_CRIT "Watchdog: Would Reboot.\n");
+	pr_crit("Would Reboot\n");
 	*CSR_TIMER4_CNTL = 0;
 	*CSR_TIMER4_CLR = 0;
 }
@@ -205,13 +208,11 @@
 	if (retval < 0)
 		return retval;
 
-	printk(KERN_INFO
-		"Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n",
-								soft_margin);
+	pr_info("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n",
+		soft_margin);
 
 	if (machine_is_cats())
-		printk(KERN_WARNING
-		  "Warning: Watchdog reset may not work on this machine.\n");
+		pr_warn("Warning: Watchdog reset may not work on this machine\n");
 	return 0;
 }
 
diff --git a/drivers/watchdog/wdt977.c b/drivers/watchdog/wdt977.c
index a2f01c9..65a4023 100644
--- a/drivers/watchdog/wdt977.c
+++ b/drivers/watchdog/wdt977.c
@@ -23,6 +23,8 @@
  *				    Netwinders only
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -37,13 +39,10 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 #include <asm/mach-types.h>
 
 #define WATCHDOG_VERSION  "0.04"
 #define WATCHDOG_NAME     "Wdt977"
-#define PFX WATCHDOG_NAME ": "
-#define DRIVER_VERSION    WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
 
 #define IO_INDEX_PORT	0x370		/* on some systems it can be 0x3F0 */
 #define IO_DATA_PORT	(IO_INDEX_PORT + 1)
@@ -68,8 +67,8 @@
 module_param(testmode, int, 0);
 MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -119,7 +118,7 @@
 	outb_p(LOCK_DATA, IO_INDEX_PORT);
 
 	spin_unlock_irqrestore(&spinlock, flags);
-	printk(KERN_INFO PFX "activated.\n");
+	pr_info("activated\n");
 
 	return 0;
 }
@@ -164,7 +163,7 @@
 	outb_p(LOCK_DATA, IO_INDEX_PORT);
 
 	spin_unlock_irqrestore(&spinlock, flags);
-	printk(KERN_INFO PFX "shutdown.\n");
+	pr_info("shutdown\n");
 
 	return 0;
 }
@@ -288,8 +287,7 @@
 		clear_bit(0, &timer_alive);
 	} else {
 		wdt977_keepalive();
-		printk(KERN_CRIT PFX
-			"Unexpected close, not stopping watchdog!\n");
+		pr_crit("Unexpected close, not stopping watchdog!\n");
 	}
 	expect_close = 0;
 	return 0;
@@ -446,15 +444,14 @@
 {
 	int rc;
 
-	printk(KERN_INFO PFX DRIVER_VERSION);
+	pr_info("driver v%s\n", WATCHDOG_VERSION);
 
 	/* Check that the timeout value is within its range;
 	   if not reset to the default */
 	if (wdt977_set_timeout(timeout)) {
 		wdt977_set_timeout(DEFAULT_TIMEOUT);
-		printk(KERN_INFO PFX
-		      "timeout value must be 60 < timeout < 15300, using %d\n",
-							DEFAULT_TIMEOUT);
+		pr_info("timeout value must be 60 < timeout < 15300, using %d\n",
+			DEFAULT_TIMEOUT);
 	}
 
 	/* on Netwinder the IOports are already reserved by
@@ -462,9 +459,8 @@
 	 */
 	if (!machine_is_netwinder()) {
 		if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) {
-			printk(KERN_ERR PFX
-				"I/O address 0x%04x already in use\n",
-								IO_INDEX_PORT);
+			pr_err("I/O address 0x%04x already in use\n",
+			       IO_INDEX_PORT);
 			rc = -EIO;
 			goto err_out;
 		}
@@ -472,22 +468,19 @@
 
 	rc = register_reboot_notifier(&wdt977_notifier);
 	if (rc) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", rc);
+		pr_err("cannot register reboot notifier (err=%d)\n", rc);
 		goto err_out_region;
 	}
 
 	rc = misc_register(&wdt977_miscdev);
 	if (rc) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-						wdt977_miscdev.minor, rc);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       wdt977_miscdev.minor, rc);
 		goto err_out_reboot;
 	}
 
-	printk(KERN_INFO PFX
-		"initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
-						timeout, nowayout, testmode);
+	pr_info("initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
+		timeout, nowayout, testmode);
 
 	return 0;
 
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c
index e0fc3baa..1c888c7 100644
--- a/drivers/watchdog/wdt_pci.c
+++ b/drivers/watchdog/wdt_pci.c
@@ -37,6 +37,8 @@
  *		Matt Domsch	:	nowayout module option
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -53,13 +55,10 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <asm/system.h>
 
 #define WDT_IS_PCI
 #include "wd501p.h"
 
-#define PFX "wdt_pci: "
-
 /* We can only use 1 card due to the /dev/watchdog restriction */
 static int dev_count;
 
@@ -80,8 +79,8 @@
 		"Watchdog heartbeat in seconds. (0<heartbeat<65536, default="
 				__MODULE_STRING(WD_TIMO) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -312,33 +311,32 @@
 	status = inb(WDT_SR);
 	udelay(8);
 
-	printk(KERN_CRIT PFX "status %d\n", status);
+	pr_crit("status %d\n", status);
 
 	if (type == 501) {
 		if (!(status & WDC_SR_TGOOD)) {
-			printk(KERN_CRIT PFX "Overheat alarm.(%d)\n",
-								inb(WDT_RT));
+			pr_crit("Overheat alarm (%d)\n", inb(WDT_RT));
 			udelay(8);
 		}
 		if (!(status & WDC_SR_PSUOVER))
-			printk(KERN_CRIT PFX "PSU over voltage.\n");
+			pr_crit("PSU over voltage\n");
 		if (!(status & WDC_SR_PSUUNDR))
-			printk(KERN_CRIT PFX "PSU under voltage.\n");
+			pr_crit("PSU under voltage\n");
 		if (tachometer) {
 			if (!(status & WDC_SR_FANGOOD))
-				printk(KERN_CRIT PFX "Possible fan fault.\n");
+				pr_crit("Possible fan fault\n");
 		}
 	}
 	if (!(status & WDC_SR_WCCR)) {
 #ifdef SOFTWARE_REBOOT
 #ifdef ONLY_TESTING
-		printk(KERN_CRIT PFX "Would Reboot.\n");
+		pr_crit("Would Reboot\n");
 #else
-		printk(KERN_CRIT PFX "Initiating system reboot.\n");
+		pr_crit("Initiating system reboot\n");
 		emergency_restart(NULL);
 #endif
 #else
-		printk(KERN_CRIT PFX "Reset in 5ms.\n");
+		pr_crit("Reset in 5ms\n");
 #endif
 	}
 	spin_unlock(&wdtpci_lock);
@@ -484,7 +482,7 @@
 	if (expect_close == 42) {
 		wdtpci_stop();
 	} else {
-		printk(KERN_CRIT PFX "Unexpected close, not stopping timer!");
+		pr_crit("Unexpected close, not stopping timer!\n");
 		wdtpci_ping();
 	}
 	expect_close = 0;
@@ -614,29 +612,29 @@
 
 	dev_count++;
 	if (dev_count > 1) {
-		printk(KERN_ERR PFX "This driver only supports one device\n");
+		pr_err("This driver only supports one device\n");
 		return -ENODEV;
 	}
 
 	if (type != 500 && type != 501) {
-		printk(KERN_ERR PFX "unknown card type '%d'.\n", type);
+		pr_err("unknown card type '%d'\n", type);
 		return -ENODEV;
 	}
 
 	if (pci_enable_device(dev)) {
-		printk(KERN_ERR PFX "Not possible to enable PCI Device\n");
+		pr_err("Not possible to enable PCI Device\n");
 		return -ENODEV;
 	}
 
 	if (pci_resource_start(dev, 2) == 0x0000) {
-		printk(KERN_ERR PFX "No I/O-Address for card detected\n");
+		pr_err("No I/O-Address for card detected\n");
 		ret = -ENODEV;
 		goto out_pci;
 	}
 
 	if (pci_request_region(dev, 2, "wdt_pci")) {
-		printk(KERN_ERR PFX "I/O address 0x%llx already in use\n",
-			(unsigned long long)pci_resource_start(dev, 2));
+		pr_err("I/O address 0x%llx already in use\n",
+		       (unsigned long long)pci_resource_start(dev, 2));
 		goto out_pci;
 	}
 
@@ -645,53 +643,48 @@
 
 	if (request_irq(irq, wdtpci_interrupt, IRQF_SHARED,
 			 "wdt_pci", &wdtpci_miscdev)) {
-		printk(KERN_ERR PFX "IRQ %d is not free\n", irq);
+		pr_err("IRQ %d is not free\n", irq);
 		goto out_reg;
 	}
 
-	printk(KERN_INFO
-	 "PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%llx (Interrupt %d)\n",
-					(unsigned long long)io, irq);
+	pr_info("PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%llx (Interrupt %d)\n",
+		(unsigned long long)io, irq);
 
 	/* Check that the heartbeat value is within its range;
 	   if not reset to the default */
 	if (wdtpci_set_heartbeat(heartbeat)) {
 		wdtpci_set_heartbeat(WD_TIMO);
-		printk(KERN_INFO PFX
-		  "heartbeat value must be 0 < heartbeat < 65536, using %d\n",
-								WD_TIMO);
+		pr_info("heartbeat value must be 0 < heartbeat < 65536, using %d\n",
+			WD_TIMO);
 	}
 
 	ret = register_reboot_notifier(&wdtpci_notifier);
 	if (ret) {
-		printk(KERN_ERR PFX
-			"cannot register reboot notifier (err=%d)\n", ret);
+		pr_err("cannot register reboot notifier (err=%d)\n", ret);
 		goto out_irq;
 	}
 
 	if (type == 501) {
 		ret = misc_register(&temp_miscdev);
 		if (ret) {
-			printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-							TEMP_MINOR, ret);
+			pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+			       TEMP_MINOR, ret);
 			goto out_rbt;
 		}
 	}
 
 	ret = misc_register(&wdtpci_miscdev);
 	if (ret) {
-		printk(KERN_ERR PFX
-			"cannot register miscdev on minor=%d (err=%d)\n",
-						WATCHDOG_MINOR, ret);
+		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
 		goto out_misc;
 	}
 
-	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+	pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
 		heartbeat, nowayout);
 	if (type == 501)
-		printk(KERN_INFO "wdt: Fan Tachometer is %s\n",
-				(tachometer ? "Enabled" : "Disabled"));
+		pr_info("Fan Tachometer is %s\n",
+			tachometer ? "Enabled" : "Disabled");
 
 	ret = 0;
 out:
diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c
index 263c883..b1815c5 100644
--- a/drivers/watchdog/wm831x_wdt.c
+++ b/drivers/watchdog/wm831x_wdt.c
@@ -22,8 +22,8 @@
 #include <linux/mfd/wm831x/pdata.h>
 #include <linux/mfd/wm831x/watchdog.h>
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		 "Watchdog cannot be stopped once started (default="
 		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -163,6 +163,8 @@
 			ret);
 	}
 
+	wdt_dev->timeout = timeout;
+
 	return ret;
 }
 
diff --git a/drivers/watchdog/wm8350_wdt.c b/drivers/watchdog/wm8350_wdt.c
index 5d7113c..3c76693 100644
--- a/drivers/watchdog/wm8350_wdt.c
+++ b/drivers/watchdog/wm8350_wdt.c
@@ -8,63 +8,65 @@
  * as published by the Free Software Foundation
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
 #include <linux/platform_device.h>
 #include <linux/watchdog.h>
 #include <linux/uaccess.h>
 #include <linux/mfd/wm8350/core.h>
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		 "Watchdog cannot be stopped once started (default="
 		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
-static unsigned long wm8350_wdt_users;
-static struct miscdevice wm8350_wdt_miscdev;
-static int wm8350_wdt_expect_close;
 static DEFINE_MUTEX(wdt_mutex);
 
 static struct {
-	int time;  /* Seconds */
-	u16 val;   /* To be set in WM8350_SYSTEM_CONTROL_2 */
+	unsigned int time;  /* Seconds */
+	u16 val;	    /* To be set in WM8350_SYSTEM_CONTROL_2 */
 } wm8350_wdt_cfgs[] = {
 	{ 1, 0x02 },
 	{ 2, 0x04 },
 	{ 4, 0x05 },
 };
 
-static struct wm8350 *get_wm8350(void)
+static int wm8350_wdt_set_timeout(struct watchdog_device *wdt_dev,
+				  unsigned int timeout)
 {
-	return dev_get_drvdata(wm8350_wdt_miscdev.parent);
-}
-
-static int wm8350_wdt_set_timeout(struct wm8350 *wm8350, u16 value)
-{
-	int ret;
+	struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
+	int ret, i;
 	u16 reg;
 
+	for (i = 0; i < ARRAY_SIZE(wm8350_wdt_cfgs); i++)
+		if (wm8350_wdt_cfgs[i].time == timeout)
+			break;
+	if (i == ARRAY_SIZE(wm8350_wdt_cfgs))
+		return -EINVAL;
+
 	mutex_lock(&wdt_mutex);
 	wm8350_reg_unlock(wm8350);
 
 	reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
 	reg &= ~WM8350_WDOG_TO_MASK;
-	reg |= value;
+	reg |= wm8350_wdt_cfgs[i].val;
 	ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);
 
 	wm8350_reg_lock(wm8350);
 	mutex_unlock(&wdt_mutex);
 
+	wdt_dev->timeout = timeout;
 	return ret;
 }
 
-static int wm8350_wdt_start(struct wm8350 *wm8350)
+static int wm8350_wdt_start(struct watchdog_device *wdt_dev)
 {
+	struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
 	int ret;
 	u16 reg;
 
@@ -82,8 +84,9 @@
 	return ret;
 }
 
-static int wm8350_wdt_stop(struct wm8350 *wm8350)
+static int wm8350_wdt_stop(struct watchdog_device *wdt_dev)
 {
+	struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
 	int ret;
 	u16 reg;
 
@@ -100,8 +103,9 @@
 	return ret;
 }
 
-static int wm8350_wdt_kick(struct wm8350 *wm8350)
+static int wm8350_wdt_ping(struct watchdog_device *wdt_dev)
 {
+	struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
 	int ret;
 	u16 reg;
 
@@ -115,168 +119,25 @@
 	return ret;
 }
 
-static int wm8350_wdt_open(struct inode *inode, struct file *file)
-{
-	struct wm8350 *wm8350 = get_wm8350();
-	int ret;
-
-	if (!wm8350)
-		return -ENODEV;
-
-	if (test_and_set_bit(0, &wm8350_wdt_users))
-		return -EBUSY;
-
-	ret = wm8350_wdt_start(wm8350);
-	if (ret != 0)
-		return ret;
-
-	return nonseekable_open(inode, file);
-}
-
-static int wm8350_wdt_release(struct inode *inode, struct file *file)
-{
-	struct wm8350 *wm8350 = get_wm8350();
-
-	if (wm8350_wdt_expect_close)
-		wm8350_wdt_stop(wm8350);
-	else {
-		dev_warn(wm8350->dev, "Watchdog device closed uncleanly\n");
-		wm8350_wdt_kick(wm8350);
-	}
-
-	clear_bit(0, &wm8350_wdt_users);
-
-	return 0;
-}
-
-static ssize_t wm8350_wdt_write(struct file *file,
-				const char __user *data, size_t count,
-				loff_t *ppos)
-{
-	struct wm8350 *wm8350 = get_wm8350();
-	size_t i;
-
-	if (count) {
-		wm8350_wdt_kick(wm8350);
-
-		if (!nowayout) {
-			/* In case it was set long ago */
-			wm8350_wdt_expect_close = 0;
-
-			/* scan to see whether or not we got the magic
-			   character */
-			for (i = 0; i != count; i++) {
-				char c;
-				if (get_user(c, data + i))
-					return -EFAULT;
-				if (c == 'V')
-					wm8350_wdt_expect_close = 42;
-			}
-		}
-	}
-	return count;
-}
-
-static const struct watchdog_info ident = {
+static const struct watchdog_info wm8350_wdt_info = {
 	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
 	.identity = "WM8350 Watchdog",
 };
 
-static long wm8350_wdt_ioctl(struct file *file, unsigned int cmd,
-			     unsigned long arg)
-{
-	struct wm8350 *wm8350 = get_wm8350();
-	int ret = -ENOTTY, time, i;
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-	u16 reg;
-
-	switch (cmd) {
-	case WDIOC_GETSUPPORT:
-		ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
-		break;
-
-	case WDIOC_GETSTATUS:
-	case WDIOC_GETBOOTSTATUS:
-		ret = put_user(0, p);
-		break;
-
-	case WDIOC_SETOPTIONS:
-	{
-		int options;
-
-		if (get_user(options, p))
-			return -EFAULT;
-
-		ret = -EINVAL;
-
-		/* Setting both simultaneously means at least one must fail */
-		if (options == WDIOS_DISABLECARD)
-			ret = wm8350_wdt_stop(wm8350);
-
-		if (options == WDIOS_ENABLECARD)
-			ret = wm8350_wdt_start(wm8350);
-		break;
-	}
-
-	case WDIOC_KEEPALIVE:
-		ret = wm8350_wdt_kick(wm8350);
-		break;
-
-	case WDIOC_SETTIMEOUT:
-		ret = get_user(time, p);
-		if (ret)
-			break;
-
-		if (time == 0) {
-			if (nowayout)
-				ret = -EINVAL;
-			else
-				wm8350_wdt_stop(wm8350);
-			break;
-		}
-
-		for (i = 0; i < ARRAY_SIZE(wm8350_wdt_cfgs); i++)
-			if (wm8350_wdt_cfgs[i].time == time)
-				break;
-		if (i == ARRAY_SIZE(wm8350_wdt_cfgs))
-			ret = -EINVAL;
-		else
-			ret = wm8350_wdt_set_timeout(wm8350,
-						     wm8350_wdt_cfgs[i].val);
-		break;
-
-	case WDIOC_GETTIMEOUT:
-		reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
-		reg &= WM8350_WDOG_TO_MASK;
-		for (i = 0; i < ARRAY_SIZE(wm8350_wdt_cfgs); i++)
-			if (wm8350_wdt_cfgs[i].val == reg)
-				break;
-		if (i == ARRAY_SIZE(wm8350_wdt_cfgs)) {
-			dev_warn(wm8350->dev,
-				 "Unknown watchdog configuration: %x\n", reg);
-			ret = -EINVAL;
-		} else
-			ret = put_user(wm8350_wdt_cfgs[i].time, p);
-
-	}
-
-	return ret;
-}
-
-static const struct file_operations wm8350_wdt_fops = {
+static const struct watchdog_ops wm8350_wdt_ops = {
 	.owner = THIS_MODULE,
-	.llseek = no_llseek,
-	.write = wm8350_wdt_write,
-	.unlocked_ioctl = wm8350_wdt_ioctl,
-	.open = wm8350_wdt_open,
-	.release = wm8350_wdt_release,
+	.start = wm8350_wdt_start,
+	.stop = wm8350_wdt_stop,
+	.ping = wm8350_wdt_ping,
+	.set_timeout = wm8350_wdt_set_timeout,
 };
 
-static struct miscdevice wm8350_wdt_miscdev = {
-	.minor = WATCHDOG_MINOR,
-	.name = "watchdog",
-	.fops = &wm8350_wdt_fops,
+static struct watchdog_device wm8350_wdt = {
+	.info = &wm8350_wdt_info,
+	.ops = &wm8350_wdt_ops,
+	.timeout = 4,
+	.min_timeout = 1,
+	.max_timeout = 4,
 };
 
 static int __devinit wm8350_wdt_probe(struct platform_device *pdev)
@@ -288,18 +149,18 @@
 		return -ENODEV;
 	}
 
+	watchdog_set_nowayout(&wm8350_wdt, nowayout);
+	watchdog_set_drvdata(&wm8350_wdt, wm8350);
+
 	/* Default to 4s timeout */
-	wm8350_wdt_set_timeout(wm8350, 0x05);
+	wm8350_wdt_set_timeout(&wm8350_wdt, 4);
 
-	wm8350_wdt_miscdev.parent = &pdev->dev;
-
-	return misc_register(&wm8350_wdt_miscdev);
+	return watchdog_register_device(&wm8350_wdt);
 }
 
 static int __devexit wm8350_wdt_remove(struct platform_device *pdev)
 {
-	misc_deregister(&wm8350_wdt_miscdev);
-
+	watchdog_unregister_device(&wm8350_wdt);
 	return 0;
 }
 
diff --git a/drivers/watchdog/xen_wdt.c b/drivers/watchdog/xen_wdt.c
index 49bd9d3..e4a25b5 100644
--- a/drivers/watchdog/xen_wdt.c
+++ b/drivers/watchdog/xen_wdt.c
@@ -9,9 +9,10 @@
  *	2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define DRV_NAME	"wdt"
 #define DRV_VERSION	"0.01"
-#define PFX		DRV_NAME ": "
 
 #include <linux/bug.h>
 #include <linux/errno.h>
@@ -131,16 +132,17 @@
 
 static int xen_wdt_release(struct inode *inode, struct file *file)
 {
+	int err = 0;
+
 	if (expect_release)
-		xen_wdt_stop();
+		err = xen_wdt_stop();
 	else {
-		printk(KERN_CRIT PFX
-		       "unexpected close, not stopping watchdog!\n");
+		pr_crit("unexpected close, not stopping watchdog!\n");
 		xen_wdt_kick();
 	}
-	is_active = false;
+	is_active = err;
 	expect_release = false;
-	return 0;
+	return err;
 }
 
 static ssize_t xen_wdt_write(struct file *file, const char __user *data,
@@ -251,30 +253,27 @@
 	case -EINVAL:
 		if (!timeout) {
 			timeout = WATCHDOG_TIMEOUT;
-			printk(KERN_INFO PFX
-			       "timeout value invalid, using %d\n", timeout);
+			pr_info("timeout value invalid, using %d\n", timeout);
 		}
 
 		ret = misc_register(&xen_wdt_miscdev);
 		if (ret) {
-			printk(KERN_ERR PFX
-			       "cannot register miscdev on minor=%d (%d)\n",
+			pr_err("cannot register miscdev on minor=%d (%d)\n",
 			       WATCHDOG_MINOR, ret);
 			break;
 		}
 
-		printk(KERN_INFO PFX
-		       "initialized (timeout=%ds, nowayout=%d)\n",
-		       timeout, nowayout);
+		pr_info("initialized (timeout=%ds, nowayout=%d)\n",
+			timeout, nowayout);
 		break;
 
 	case -ENOSYS:
-		printk(KERN_INFO PFX "not supported\n");
+		pr_info("not supported\n");
 		ret = -ENODEV;
 		break;
 
 	default:
-		printk(KERN_INFO PFX "bogus return value %d\n", ret);
+		pr_info("bogus return value %d\n", ret);
 		break;
 	}
 
@@ -299,11 +298,18 @@
 
 static int xen_wdt_suspend(struct platform_device *dev, pm_message_t state)
 {
-	return xen_wdt_stop();
+	typeof(wdt.id) id = wdt.id;
+	int rc = xen_wdt_stop();
+
+	wdt.id = id;
+	return rc;
 }
 
 static int xen_wdt_resume(struct platform_device *dev)
 {
+	if (!wdt.id)
+		return 0;
+	wdt.id = 0;
 	return xen_wdt_start();
 }
 
@@ -326,7 +332,7 @@
 	if (!xen_domain())
 		return -ENODEV;
 
-	printk(KERN_INFO PFX "Xen WatchDog Timer Driver v%s\n", DRV_VERSION);
+	pr_info("Xen WatchDog Timer Driver v%s\n", DRV_VERSION);
 
 	err = platform_driver_register(&xen_wdt_driver);
 	if (err)
@@ -346,7 +352,7 @@
 {
 	platform_device_unregister(platform_device);
 	platform_driver_unregister(&xen_wdt_driver);
-	printk(KERN_INFO PFX "module unloaded\n");
+	pr_info("module unloaded\n");
 }
 
 module_init(xen_wdt_init_module);
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index a1ced52..9424313 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -178,4 +178,20 @@
 	depends on XEN
 	default m
 
+config XEN_ACPI_PROCESSOR
+	tristate "Xen ACPI processor"
+	depends on XEN && X86 && ACPI_PROCESSOR && CPU_FREQ
+	default m
+	help
+          This ACPI processor uploads Power Management information to the Xen hypervisor.
+
+	  To do that the driver parses the Power Management data and uploads said
+	  information to the Xen hypervisor. Then the Xen hypervisor can select the
+          proper Cx and Pxx states. It also registers itslef as the SMM so that
+          other drivers (such as ACPI cpufreq scaling driver) will not load.
+
+          To compile this driver as a module, choose M here: the
+          module will be called xen_acpi_processor  If you do not know what to choose,
+          select M here. If the CPUFREQ drivers are built in, select Y here.
+
 endmenu
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index aa31337..9adc5be 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -20,7 +20,7 @@
 obj-$(CONFIG_XEN_DOM0)			+= pci.o
 obj-$(CONFIG_XEN_PCIDEV_BACKEND)	+= xen-pciback/
 obj-$(CONFIG_XEN_PRIVCMD)		+= xen-privcmd.o
-
+obj-$(CONFIG_XEN_ACPI_PROCESSOR)	+= xen-acpi-processor.o
 xen-evtchn-y				:= evtchn.o
 xen-gntdev-y				:= gntdev.o
 xen-gntalloc-y				:= gntalloc.o
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index e5e5812..4b33acd 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -37,6 +37,7 @@
 #include <asm/idle.h>
 #include <asm/io_apic.h>
 #include <asm/sync_bitops.h>
+#include <asm/xen/page.h>
 #include <asm/xen/pci.h>
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
@@ -109,6 +110,8 @@
 #define PIRQ_SHAREABLE	(1 << 1)
 
 static int *evtchn_to_irq;
+static unsigned long *pirq_eoi_map;
+static bool (*pirq_needs_eoi)(unsigned irq);
 
 static DEFINE_PER_CPU(unsigned long [NR_EVENT_CHANNELS/BITS_PER_LONG],
 		      cpu_evtchn_mask);
@@ -269,10 +272,14 @@
 	return ret;
 }
 
-static bool pirq_needs_eoi(unsigned irq)
+static bool pirq_check_eoi_map(unsigned irq)
+{
+	return test_bit(irq, pirq_eoi_map);
+}
+
+static bool pirq_needs_eoi_flag(unsigned irq)
 {
 	struct irq_info *info = info_for_irq(irq);
-
 	BUG_ON(info->type != IRQT_PIRQ);
 
 	return info->u.pirq.flags & PIRQ_NEEDS_EOI;
@@ -1768,7 +1775,7 @@
 
 void __init xen_init_IRQ(void)
 {
-	int i;
+	int i, rc;
 
 	evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq),
 				    GFP_KERNEL);
@@ -1782,6 +1789,8 @@
 	for (i = 0; i < NR_EVENT_CHANNELS; i++)
 		mask_evtchn(i);
 
+	pirq_needs_eoi = pirq_needs_eoi_flag;
+
 	if (xen_hvm_domain()) {
 		xen_callback_vector();
 		native_init_IRQ();
@@ -1789,8 +1798,19 @@
 		 * __acpi_register_gsi can point at the right function */
 		pci_xen_hvm_init();
 	} else {
+		struct physdev_pirq_eoi_gmfn eoi_gmfn;
+
 		irq_ctx_init(smp_processor_id());
 		if (xen_initial_domain())
 			pci_xen_initial_domain();
+
+		pirq_eoi_map = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
+		eoi_gmfn.gmfn = virt_to_mfn(pirq_eoi_map);
+		rc = HYPERVISOR_physdev_op(PHYSDEVOP_pirq_eoi_gmfn_v2, &eoi_gmfn);
+		if (rc != 0) {
+			free_page((unsigned long) pirq_eoi_map);
+			pirq_eoi_map = NULL;
+		} else
+			pirq_needs_eoi = pirq_check_eoi_map;
 	}
 }
diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c
index 319dd0a..2389e58 100644
--- a/drivers/xen/platform-pci.c
+++ b/drivers/xen/platform-pci.c
@@ -186,11 +186,6 @@
 
 static int __init platform_pci_module_init(void)
 {
-	/* no unplug has been done, IGNORE hasn't been specified: just
-	 * return now */
-	if (!xen_platform_pci_unplug)
-		return -ENODEV;
-
 	return pci_register_driver(&platform_driver);
 }
 
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index 19e6a20..1afb4fb 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -204,7 +204,8 @@
 
 void *
 xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
-			   dma_addr_t *dma_handle, gfp_t flags)
+			   dma_addr_t *dma_handle, gfp_t flags,
+			   struct dma_attrs *attrs)
 {
 	void *ret;
 	int order = get_order(size);
@@ -253,7 +254,7 @@
 
 void
 xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
-			  dma_addr_t dev_addr)
+			  dma_addr_t dev_addr, struct dma_attrs *attrs)
 {
 	int order = get_order(size);
 	phys_addr_t phys;
diff --git a/drivers/xen/sys-hypervisor.c b/drivers/xen/sys-hypervisor.c
index 1e0fe01..fdb6d22 100644
--- a/drivers/xen/sys-hypervisor.c
+++ b/drivers/xen/sys-hypervisor.c
@@ -97,7 +97,7 @@
 	NULL
 };
 
-static struct attribute_group version_group = {
+static const struct attribute_group version_group = {
 	.name = "version",
 	.attrs = version_attrs,
 };
@@ -210,7 +210,7 @@
 	NULL
 };
 
-static struct attribute_group xen_compilation_group = {
+static const struct attribute_group xen_compilation_group = {
 	.name = "compilation",
 	.attrs = xen_compile_attrs,
 };
@@ -340,7 +340,7 @@
 	NULL
 };
 
-static struct attribute_group xen_properties_group = {
+static const struct attribute_group xen_properties_group = {
 	.name = "properties",
 	.attrs = xen_properties_attrs,
 };
diff --git a/drivers/xen/tmem.c b/drivers/xen/tmem.c
index d369965..dcb79521 100644
--- a/drivers/xen/tmem.c
+++ b/drivers/xen/tmem.c
@@ -9,7 +9,6 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/pagemap.h>
-#include <linux/module.h>
 #include <linux/cleancache.h>
 
 /* temporary ifdef until include/linux/frontswap.h is upstream */
@@ -128,15 +127,13 @@
 	return xen_tmem_op(TMEM_FLUSH_OBJECT, pool_id, oid, 0, 0, 0, 0, 0);
 }
 
-int tmem_enabled __read_mostly;
-EXPORT_SYMBOL(tmem_enabled);
+bool __read_mostly tmem_enabled = false;
 
 static int __init enable_tmem(char *s)
 {
-	tmem_enabled = 1;
+	tmem_enabled = true;
 	return 1;
 }
-
 __setup("tmem", enable_tmem);
 
 #ifdef CONFIG_CLEANCACHE
@@ -229,22 +226,21 @@
 	return xen_tmem_new_pool(shared_uuid, TMEM_POOL_SHARED, pagesize);
 }
 
-static int use_cleancache = 1;
+static bool __initdata use_cleancache = true;
 
 static int __init no_cleancache(char *s)
 {
-	use_cleancache = 0;
+	use_cleancache = false;
 	return 1;
 }
-
 __setup("nocleancache", no_cleancache);
 
-static struct cleancache_ops tmem_cleancache_ops = {
+static struct cleancache_ops __initdata tmem_cleancache_ops = {
 	.put_page = tmem_cleancache_put_page,
 	.get_page = tmem_cleancache_get_page,
-	.flush_page = tmem_cleancache_flush_page,
-	.flush_inode = tmem_cleancache_flush_inode,
-	.flush_fs = tmem_cleancache_flush_fs,
+	.invalidate_page = tmem_cleancache_flush_page,
+	.invalidate_inode = tmem_cleancache_flush_inode,
+	.invalidate_fs = tmem_cleancache_flush_fs,
 	.init_shared_fs = tmem_cleancache_init_shared_fs,
 	.init_fs = tmem_cleancache_init_fs
 };
@@ -356,21 +352,20 @@
 		    xen_tmem_new_pool(private, TMEM_POOL_PERSIST, PAGE_SIZE);
 }
 
-static int __initdata use_frontswap = 1;
+static bool __initdata use_frontswap = true;
 
 static int __init no_frontswap(char *s)
 {
-	use_frontswap = 0;
+	use_frontswap = false;
 	return 1;
 }
-
 __setup("nofrontswap", no_frontswap);
 
-static struct frontswap_ops tmem_frontswap_ops = {
+static struct frontswap_ops __initdata tmem_frontswap_ops = {
 	.put_page = tmem_frontswap_put_page,
 	.get_page = tmem_frontswap_get_page,
-	.flush_page = tmem_frontswap_flush_page,
-	.flush_area = tmem_frontswap_flush_area,
+	.invalidate_page = tmem_frontswap_flush_page,
+	.invalidate_area = tmem_frontswap_flush_area,
 	.init = tmem_frontswap_init
 };
 #endif
diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c
new file mode 100644
index 0000000..174b565
--- /dev/null
+++ b/drivers/xen/xen-acpi-processor.c
@@ -0,0 +1,562 @@
+/*
+ * Copyright 2012 by Oracle Inc
+ * Author: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+ *
+ * This code borrows ideas from https://lkml.org/lkml/2011/11/30/249
+ * so many thanks go to Kevin Tian <kevin.tian@intel.com>
+ * and Yu Ke <ke.yu@intel.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/cpumask.h>
+#include <linux/cpufreq.h>
+#include <linux/freezer.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/processor.h>
+
+#include <xen/interface/platform.h>
+#include <asm/xen/hypercall.h>
+
+#define DRV_NAME "xen-acpi-processor: "
+
+static int no_hypercall;
+MODULE_PARM_DESC(off, "Inhibit the hypercall.");
+module_param_named(off, no_hypercall, int, 0400);
+
+/*
+ * Note: Do not convert the acpi_id* below to cpumask_var_t or use cpumask_bit
+ * - as those shrink to nr_cpu_bits (which is dependent on possible_cpu), which
+ * can be less than what we want to put in. Instead use the 'nr_acpi_bits'
+ * which is dynamically computed based on the MADT or x2APIC table.
+ */
+static unsigned int nr_acpi_bits;
+/* Mutex to protect the acpi_ids_done - for CPU hotplug use. */
+static DEFINE_MUTEX(acpi_ids_mutex);
+/* Which ACPI ID we have processed from 'struct acpi_processor'. */
+static unsigned long *acpi_ids_done;
+/* Which ACPI ID exist in the SSDT/DSDT processor definitions. */
+static unsigned long __initdata *acpi_id_present;
+/* And if there is an _CST definition (or a PBLK) for the ACPI IDs */
+static unsigned long __initdata *acpi_id_cst_present;
+
+static int push_cxx_to_hypervisor(struct acpi_processor *_pr)
+{
+	struct xen_platform_op op = {
+		.cmd			= XENPF_set_processor_pminfo,
+		.interface_version	= XENPF_INTERFACE_VERSION,
+		.u.set_pminfo.id	= _pr->acpi_id,
+		.u.set_pminfo.type	= XEN_PM_CX,
+	};
+	struct xen_processor_cx *dst_cx, *dst_cx_states = NULL;
+	struct acpi_processor_cx *cx;
+	unsigned int i, ok;
+	int ret = 0;
+
+	dst_cx_states = kcalloc(_pr->power.count,
+				sizeof(struct xen_processor_cx), GFP_KERNEL);
+	if (!dst_cx_states)
+		return -ENOMEM;
+
+	for (ok = 0, i = 1; i <= _pr->power.count; i++) {
+		cx = &_pr->power.states[i];
+		if (!cx->valid)
+			continue;
+
+		dst_cx = &(dst_cx_states[ok++]);
+
+		dst_cx->reg.space_id = ACPI_ADR_SPACE_SYSTEM_IO;
+		if (cx->entry_method == ACPI_CSTATE_SYSTEMIO) {
+			dst_cx->reg.bit_width = 8;
+			dst_cx->reg.bit_offset = 0;
+			dst_cx->reg.access_size = 1;
+		} else {
+			dst_cx->reg.space_id = ACPI_ADR_SPACE_FIXED_HARDWARE;
+			if (cx->entry_method == ACPI_CSTATE_FFH) {
+				/* NATIVE_CSTATE_BEYOND_HALT */
+				dst_cx->reg.bit_offset = 2;
+				dst_cx->reg.bit_width = 1; /* VENDOR_INTEL */
+			}
+			dst_cx->reg.access_size = 0;
+		}
+		dst_cx->reg.address = cx->address;
+
+		dst_cx->type = cx->type;
+		dst_cx->latency = cx->latency;
+		dst_cx->power = cx->power;
+
+		dst_cx->dpcnt = 0;
+		set_xen_guest_handle(dst_cx->dp, NULL);
+	}
+	if (!ok) {
+		pr_debug(DRV_NAME "No _Cx for ACPI CPU %u\n", _pr->acpi_id);
+		kfree(dst_cx_states);
+		return -EINVAL;
+	}
+	op.u.set_pminfo.power.count = ok;
+	op.u.set_pminfo.power.flags.bm_control = _pr->flags.bm_control;
+	op.u.set_pminfo.power.flags.bm_check = _pr->flags.bm_check;
+	op.u.set_pminfo.power.flags.has_cst = _pr->flags.has_cst;
+	op.u.set_pminfo.power.flags.power_setup_done =
+		_pr->flags.power_setup_done;
+
+	set_xen_guest_handle(op.u.set_pminfo.power.states, dst_cx_states);
+
+	if (!no_hypercall)
+		ret = HYPERVISOR_dom0_op(&op);
+
+	if (!ret) {
+		pr_debug("ACPI CPU%u - C-states uploaded.\n", _pr->acpi_id);
+		for (i = 1; i <= _pr->power.count; i++) {
+			cx = &_pr->power.states[i];
+			if (!cx->valid)
+				continue;
+			pr_debug("     C%d: %s %d uS\n",
+				 cx->type, cx->desc, (u32)cx->latency);
+		}
+	} else
+		pr_err(DRV_NAME "(CX): Hypervisor error (%d) for ACPI CPU%u\n",
+		       ret, _pr->acpi_id);
+
+	kfree(dst_cx_states);
+
+	return ret;
+}
+static struct xen_processor_px *
+xen_copy_pss_data(struct acpi_processor *_pr,
+		  struct xen_processor_performance *dst_perf)
+{
+	struct xen_processor_px *dst_states = NULL;
+	unsigned int i;
+
+	BUILD_BUG_ON(sizeof(struct xen_processor_px) !=
+		     sizeof(struct acpi_processor_px));
+
+	dst_states = kcalloc(_pr->performance->state_count,
+			     sizeof(struct xen_processor_px), GFP_KERNEL);
+	if (!dst_states)
+		return ERR_PTR(-ENOMEM);
+
+	dst_perf->state_count = _pr->performance->state_count;
+	for (i = 0; i < _pr->performance->state_count; i++) {
+		/* Fortunatly for us, they are both the same size */
+		memcpy(&(dst_states[i]), &(_pr->performance->states[i]),
+		       sizeof(struct acpi_processor_px));
+	}
+	return dst_states;
+}
+static int xen_copy_psd_data(struct acpi_processor *_pr,
+			     struct xen_processor_performance *dst)
+{
+	struct acpi_psd_package *pdomain;
+
+	BUILD_BUG_ON(sizeof(struct xen_psd_package) !=
+		     sizeof(struct acpi_psd_package));
+
+	/* This information is enumerated only if acpi_processor_preregister_performance
+	 * has been called.
+	 */
+	dst->shared_type = _pr->performance->shared_type;
+
+	pdomain = &(_pr->performance->domain_info);
+
+	/* 'acpi_processor_preregister_performance' does not parse if the
+	 * num_processors <= 1, but Xen still requires it. Do it manually here.
+	 */
+	if (pdomain->num_processors <= 1) {
+		if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL)
+			dst->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+		else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL)
+			dst->shared_type = CPUFREQ_SHARED_TYPE_HW;
+		else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
+			dst->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+
+	}
+	memcpy(&(dst->domain_info), pdomain, sizeof(struct acpi_psd_package));
+	return 0;
+}
+static int xen_copy_pct_data(struct acpi_pct_register *pct,
+			     struct xen_pct_register *dst_pct)
+{
+	/* It would be nice if you could just do 'memcpy(pct, dst_pct') but
+	 * sadly the Xen structure did not have the proper padding so the
+	 * descriptor field takes two (dst_pct) bytes instead of one (pct).
+	 */
+	dst_pct->descriptor = pct->descriptor;
+	dst_pct->length = pct->length;
+	dst_pct->space_id = pct->space_id;
+	dst_pct->bit_width = pct->bit_width;
+	dst_pct->bit_offset = pct->bit_offset;
+	dst_pct->reserved = pct->reserved;
+	dst_pct->address = pct->address;
+	return 0;
+}
+static int push_pxx_to_hypervisor(struct acpi_processor *_pr)
+{
+	int ret = 0;
+	struct xen_platform_op op = {
+		.cmd			= XENPF_set_processor_pminfo,
+		.interface_version	= XENPF_INTERFACE_VERSION,
+		.u.set_pminfo.id	= _pr->acpi_id,
+		.u.set_pminfo.type	= XEN_PM_PX,
+	};
+	struct xen_processor_performance *dst_perf;
+	struct xen_processor_px *dst_states = NULL;
+
+	dst_perf = &op.u.set_pminfo.perf;
+
+	dst_perf->platform_limit = _pr->performance_platform_limit;
+	dst_perf->flags |= XEN_PX_PPC;
+	xen_copy_pct_data(&(_pr->performance->control_register),
+			  &dst_perf->control_register);
+	xen_copy_pct_data(&(_pr->performance->status_register),
+			  &dst_perf->status_register);
+	dst_perf->flags |= XEN_PX_PCT;
+	dst_states = xen_copy_pss_data(_pr, dst_perf);
+	if (!IS_ERR_OR_NULL(dst_states)) {
+		set_xen_guest_handle(dst_perf->states, dst_states);
+		dst_perf->flags |= XEN_PX_PSS;
+	}
+	if (!xen_copy_psd_data(_pr, dst_perf))
+		dst_perf->flags |= XEN_PX_PSD;
+
+	if (dst_perf->flags != (XEN_PX_PSD | XEN_PX_PSS | XEN_PX_PCT | XEN_PX_PPC)) {
+		pr_warn(DRV_NAME "ACPI CPU%u missing some P-state data (%x), skipping.\n",
+			_pr->acpi_id, dst_perf->flags);
+		ret = -ENODEV;
+		goto err_free;
+	}
+
+	if (!no_hypercall)
+		ret = HYPERVISOR_dom0_op(&op);
+
+	if (!ret) {
+		struct acpi_processor_performance *perf;
+		unsigned int i;
+
+		perf = _pr->performance;
+		pr_debug("ACPI CPU%u - P-states uploaded.\n", _pr->acpi_id);
+		for (i = 0; i < perf->state_count; i++) {
+			pr_debug("     %cP%d: %d MHz, %d mW, %d uS\n",
+			(i == perf->state ? '*' : ' '), i,
+			(u32) perf->states[i].core_frequency,
+			(u32) perf->states[i].power,
+			(u32) perf->states[i].transition_latency);
+		}
+	} else if (ret != -EINVAL)
+		/* EINVAL means the ACPI ID is incorrect - meaning the ACPI
+		 * table is referencing a non-existing CPU - which can happen
+		 * with broken ACPI tables. */
+		pr_warn(DRV_NAME "(_PXX): Hypervisor error (%d) for ACPI CPU%u\n",
+		       ret, _pr->acpi_id);
+err_free:
+	if (!IS_ERR_OR_NULL(dst_states))
+		kfree(dst_states);
+
+	return ret;
+}
+static int upload_pm_data(struct acpi_processor *_pr)
+{
+	int err = 0;
+
+	mutex_lock(&acpi_ids_mutex);
+	if (__test_and_set_bit(_pr->acpi_id, acpi_ids_done)) {
+		mutex_unlock(&acpi_ids_mutex);
+		return -EBUSY;
+	}
+	if (_pr->flags.power)
+		err = push_cxx_to_hypervisor(_pr);
+
+	if (_pr->performance && _pr->performance->states)
+		err |= push_pxx_to_hypervisor(_pr);
+
+	mutex_unlock(&acpi_ids_mutex);
+	return err;
+}
+static unsigned int __init get_max_acpi_id(void)
+{
+	struct xenpf_pcpuinfo *info;
+	struct xen_platform_op op = {
+		.cmd = XENPF_get_cpuinfo,
+		.interface_version = XENPF_INTERFACE_VERSION,
+	};
+	int ret = 0;
+	unsigned int i, last_cpu, max_acpi_id = 0;
+
+	info = &op.u.pcpu_info;
+	info->xen_cpuid = 0;
+
+	ret = HYPERVISOR_dom0_op(&op);
+	if (ret)
+		return NR_CPUS;
+
+	/* The max_present is the same irregardless of the xen_cpuid */
+	last_cpu = op.u.pcpu_info.max_present;
+	for (i = 0; i <= last_cpu; i++) {
+		info->xen_cpuid = i;
+		ret = HYPERVISOR_dom0_op(&op);
+		if (ret)
+			continue;
+		max_acpi_id = max(info->acpi_id, max_acpi_id);
+	}
+	max_acpi_id *= 2; /* Slack for CPU hotplug support. */
+	pr_debug(DRV_NAME "Max ACPI ID: %u\n", max_acpi_id);
+	return max_acpi_id;
+}
+/*
+ * The read_acpi_id and check_acpi_ids are there to support the Xen
+ * oddity of virtual CPUs != physical CPUs in the initial domain.
+ * The user can supply 'xen_max_vcpus=X' on the Xen hypervisor line
+ * which will band the amount of CPUs the initial domain can see.
+ * In general that is OK, except it plays havoc with any of the
+ * for_each_[present|online]_cpu macros which are banded to the virtual
+ * CPU amount.
+ */
+static acpi_status __init
+read_acpi_id(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	u32 acpi_id;
+	acpi_status status;
+	acpi_object_type acpi_type;
+	unsigned long long tmp;
+	union acpi_object object = { 0 };
+	struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
+	acpi_io_address pblk = 0;
+
+	status = acpi_get_type(handle, &acpi_type);
+	if (ACPI_FAILURE(status))
+		return AE_OK;
+
+	switch (acpi_type) {
+	case ACPI_TYPE_PROCESSOR:
+		status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
+		if (ACPI_FAILURE(status))
+			return AE_OK;
+		acpi_id = object.processor.proc_id;
+		pblk = object.processor.pblk_address;
+		break;
+	case ACPI_TYPE_DEVICE:
+		status = acpi_evaluate_integer(handle, "_UID", NULL, &tmp);
+		if (ACPI_FAILURE(status))
+			return AE_OK;
+		acpi_id = tmp;
+		break;
+	default:
+		return AE_OK;
+	}
+	/* There are more ACPI Processor objects than in x2APIC or MADT.
+	 * This can happen with incorrect ACPI SSDT declerations. */
+	if (acpi_id > nr_acpi_bits) {
+		pr_debug(DRV_NAME "We only have %u, trying to set %u\n",
+			 nr_acpi_bits, acpi_id);
+		return AE_OK;
+	}
+	/* OK, There is a ACPI Processor object */
+	__set_bit(acpi_id, acpi_id_present);
+
+	pr_debug(DRV_NAME "ACPI CPU%u w/ PBLK:0x%lx\n", acpi_id,
+		 (unsigned long)pblk);
+
+	status = acpi_evaluate_object(handle, "_CST", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		if (!pblk)
+			return AE_OK;
+	}
+	/* .. and it has a C-state */
+	__set_bit(acpi_id, acpi_id_cst_present);
+
+	return AE_OK;
+}
+static int __init check_acpi_ids(struct acpi_processor *pr_backup)
+{
+
+	if (!pr_backup)
+		return -ENODEV;
+
+	/* All online CPUs have been processed at this stage. Now verify
+	 * whether in fact "online CPUs" == physical CPUs.
+	 */
+	acpi_id_present = kcalloc(BITS_TO_LONGS(nr_acpi_bits), sizeof(unsigned long), GFP_KERNEL);
+	if (!acpi_id_present)
+		return -ENOMEM;
+
+	acpi_id_cst_present = kcalloc(BITS_TO_LONGS(nr_acpi_bits), sizeof(unsigned long), GFP_KERNEL);
+	if (!acpi_id_cst_present) {
+		kfree(acpi_id_present);
+		return -ENOMEM;
+	}
+
+	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
+			    ACPI_UINT32_MAX,
+			    read_acpi_id, NULL, NULL, NULL);
+	acpi_get_devices("ACPI0007", read_acpi_id, NULL, NULL);
+
+	if (!bitmap_equal(acpi_id_present, acpi_ids_done, nr_acpi_bits)) {
+		unsigned int i;
+		for_each_set_bit(i, acpi_id_present, nr_acpi_bits) {
+			pr_backup->acpi_id = i;
+			/* Mask out C-states if there are no _CST or PBLK */
+			pr_backup->flags.power = test_bit(i, acpi_id_cst_present);
+			(void)upload_pm_data(pr_backup);
+		}
+	}
+	kfree(acpi_id_present);
+	acpi_id_present = NULL;
+	kfree(acpi_id_cst_present);
+	acpi_id_cst_present = NULL;
+	return 0;
+}
+static int __init check_prereq(void)
+{
+	struct cpuinfo_x86 *c = &cpu_data(0);
+
+	if (!xen_initial_domain())
+		return -ENODEV;
+
+	if (!acpi_gbl_FADT.smi_command)
+		return -ENODEV;
+
+	if (c->x86_vendor == X86_VENDOR_INTEL) {
+		if (!cpu_has(c, X86_FEATURE_EST))
+			return -ENODEV;
+
+		return 0;
+	}
+	if (c->x86_vendor == X86_VENDOR_AMD) {
+		/* Copied from powernow-k8.h, can't include ../cpufreq/powernow
+		 * as we get compile warnings for the static functions.
+		 */
+#define CPUID_FREQ_VOLT_CAPABILITIES    0x80000007
+#define USE_HW_PSTATE                   0x00000080
+		u32 eax, ebx, ecx, edx;
+		cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
+		if ((edx & USE_HW_PSTATE) != USE_HW_PSTATE)
+			return -ENODEV;
+		return 0;
+	}
+	return -ENODEV;
+}
+/* acpi_perf_data is a pointer to percpu data. */
+static struct acpi_processor_performance __percpu *acpi_perf_data;
+
+static void free_acpi_perf_data(void)
+{
+	unsigned int i;
+
+	/* Freeing a NULL pointer is OK, and alloc_percpu zeroes. */
+	for_each_possible_cpu(i)
+		free_cpumask_var(per_cpu_ptr(acpi_perf_data, i)
+				 ->shared_cpu_map);
+	free_percpu(acpi_perf_data);
+}
+
+static int __init xen_acpi_processor_init(void)
+{
+	struct acpi_processor *pr_backup = NULL;
+	unsigned int i;
+	int rc = check_prereq();
+
+	if (rc)
+		return rc;
+
+	nr_acpi_bits = get_max_acpi_id() + 1;
+	acpi_ids_done = kcalloc(BITS_TO_LONGS(nr_acpi_bits), sizeof(unsigned long), GFP_KERNEL);
+	if (!acpi_ids_done)
+		return -ENOMEM;
+
+	acpi_perf_data = alloc_percpu(struct acpi_processor_performance);
+	if (!acpi_perf_data) {
+		pr_debug(DRV_NAME "Memory allocation error for acpi_perf_data.\n");
+		kfree(acpi_ids_done);
+		return -ENOMEM;
+	}
+	for_each_possible_cpu(i) {
+		if (!zalloc_cpumask_var_node(
+			&per_cpu_ptr(acpi_perf_data, i)->shared_cpu_map,
+			GFP_KERNEL, cpu_to_node(i))) {
+			rc = -ENOMEM;
+			goto err_out;
+		}
+	}
+
+	/* Do initialization in ACPI core. It is OK to fail here. */
+	(void)acpi_processor_preregister_performance(acpi_perf_data);
+
+	for_each_possible_cpu(i) {
+		struct acpi_processor_performance *perf;
+
+		perf = per_cpu_ptr(acpi_perf_data, i);
+		rc = acpi_processor_register_performance(perf, i);
+		if (rc)
+			goto err_out;
+	}
+	rc = acpi_processor_notify_smm(THIS_MODULE);
+	if (rc)
+		goto err_unregister;
+
+	for_each_possible_cpu(i) {
+		struct acpi_processor *_pr;
+		_pr = per_cpu(processors, i /* APIC ID */);
+		if (!_pr)
+			continue;
+
+		if (!pr_backup) {
+			pr_backup = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
+			memcpy(pr_backup, _pr, sizeof(struct acpi_processor));
+		}
+		(void)upload_pm_data(_pr);
+	}
+	rc = check_acpi_ids(pr_backup);
+	if (rc)
+		goto err_unregister;
+
+	kfree(pr_backup);
+
+	return 0;
+err_unregister:
+	for_each_possible_cpu(i) {
+		struct acpi_processor_performance *perf;
+		perf = per_cpu_ptr(acpi_perf_data, i);
+		acpi_processor_unregister_performance(perf, i);
+	}
+err_out:
+	/* Freeing a NULL pointer is OK: alloc_percpu zeroes. */
+	free_acpi_perf_data();
+	kfree(acpi_ids_done);
+	return rc;
+}
+static void __exit xen_acpi_processor_exit(void)
+{
+	int i;
+
+	kfree(acpi_ids_done);
+	for_each_possible_cpu(i) {
+		struct acpi_processor_performance *perf;
+		perf = per_cpu_ptr(acpi_perf_data, i);
+		acpi_processor_unregister_performance(perf, i);
+	}
+	free_acpi_perf_data();
+}
+
+MODULE_AUTHOR("Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>");
+MODULE_DESCRIPTION("Xen ACPI Processor P-states (and Cx) driver which uploads PM data to Xen hypervisor");
+MODULE_LICENSE("GPL");
+
+/* We want to be loaded before the CPU freq scaling drivers are loaded.
+ * They are loaded in late_initcall. */
+device_initcall(xen_acpi_processor_init);
+module_exit(xen_acpi_processor_exit);
diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c
index 596e6a7..8f37e23 100644
--- a/drivers/xen/xen-balloon.c
+++ b/drivers/xen/xen-balloon.c
@@ -207,7 +207,7 @@
 	NULL
 };
 
-static struct attribute_group balloon_info_group = {
+static const struct attribute_group balloon_info_group = {
 	.name = "info",
 	.attrs = balloon_info_attrs
 };
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c
index 19834d1..097e536 100644
--- a/drivers/xen/xen-pciback/pci_stub.c
+++ b/drivers/xen/xen-pciback/pci_stub.c
@@ -85,19 +85,34 @@
 static void pcistub_device_release(struct kref *kref)
 {
 	struct pcistub_device *psdev;
+	struct xen_pcibk_dev_data *dev_data;
 
 	psdev = container_of(kref, struct pcistub_device, kref);
+	dev_data = pci_get_drvdata(psdev->dev);
 
 	dev_dbg(&psdev->dev->dev, "pcistub_device_release\n");
 
 	xen_unregister_device_domain_owner(psdev->dev);
 
-	/* Clean-up the device */
+	/* Call the reset function which does not take lock as this
+	 * is called from "unbind" which takes a device_lock mutex.
+	 */
+	__pci_reset_function_locked(psdev->dev);
+	if (pci_load_and_free_saved_state(psdev->dev,
+					  &dev_data->pci_saved_state)) {
+		dev_dbg(&psdev->dev->dev, "Could not reload PCI state\n");
+	} else
+		pci_restore_state(psdev->dev);
+
+	/* Disable the device */
 	xen_pcibk_reset_device(psdev->dev);
+
+	kfree(dev_data);
+	pci_set_drvdata(psdev->dev, NULL);
+
+	/* Clean-up the device */
 	xen_pcibk_config_free_dyn_fields(psdev->dev);
 	xen_pcibk_config_free_dev(psdev->dev);
-	kfree(pci_get_drvdata(psdev->dev));
-	pci_set_drvdata(psdev->dev, NULL);
 
 	psdev->dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED;
 	pci_dev_put(psdev->dev);
@@ -231,7 +246,17 @@
 	/* Cleanup our device
 	 * (so it's ready for the next domain)
 	 */
+
+	/* This is OK - we are running from workqueue context
+	 * and want to inhibit the user from fiddling with 'reset'
+	 */
+	pci_reset_function(dev);
+	pci_restore_state(psdev->dev);
+
+	/* This disables the device. */
 	xen_pcibk_reset_device(found_psdev->dev);
+
+	/* And cleanup up our emulated fields. */
 	xen_pcibk_config_free_dyn_fields(found_psdev->dev);
 	xen_pcibk_config_reset_dev(found_psdev->dev);
 
@@ -328,6 +353,16 @@
 	if (err)
 		goto config_release;
 
+	dev_dbg(&dev->dev, "reseting (FLR, D3, etc) the device\n");
+	__pci_reset_function_locked(dev);
+
+	/* We need the device active to save the state. */
+	dev_dbg(&dev->dev, "save state of device\n");
+	pci_save_state(dev);
+	dev_data->pci_saved_state = pci_store_saved_state(dev);
+	if (!dev_data->pci_saved_state)
+		dev_err(&dev->dev, "Could not store PCI conf saved state!\n");
+
 	/* Now disable the device (this also ensures some private device
 	 * data is setup before we export)
 	 */
diff --git a/drivers/xen/xen-pciback/pciback.h b/drivers/xen/xen-pciback/pciback.h
index e9b4011..a7def01 100644
--- a/drivers/xen/xen-pciback/pciback.h
+++ b/drivers/xen/xen-pciback/pciback.h
@@ -41,6 +41,7 @@
 
 struct xen_pcibk_dev_data {
 	struct list_head config_fields;
+	struct pci_saved_state *pci_saved_state;
 	unsigned int permissive:1;
 	unsigned int warned_on_write:1;
 	unsigned int enable_intx:1;
diff --git a/drivers/xen/xen-selfballoon.c b/drivers/xen/xen-selfballoon.c
index 767ff65..146c948 100644
--- a/drivers/xen/xen-selfballoon.c
+++ b/drivers/xen/xen-selfballoon.c
@@ -488,7 +488,7 @@
 	NULL
 };
 
-static struct attribute_group selfballoon_group = {
+static const struct attribute_group selfballoon_group = {
 	.name = "selfballoon",
 	.attrs = selfballoon_attrs
 };
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
index 566d2ad..b3e146e 100644
--- a/drivers/xen/xenbus/xenbus_client.c
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -569,7 +569,7 @@
 {
 	struct gnttab_map_grant_ref op;
 
-	gnttab_set_map_op(&op, (phys_addr_t)vaddr, GNTMAP_host_map, gnt_ref,
+	gnttab_set_map_op(&op, (unsigned long)vaddr, GNTMAP_host_map, gnt_ref,
 			  dev->otherend_id);
 
 	if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
@@ -662,7 +662,7 @@
 			goto found;
 		}
 	}
-	node = NULL;
+	node = addr = NULL;
  found:
 	spin_unlock(&xenbus_valloc_lock);
 
@@ -698,7 +698,7 @@
 {
 	struct gnttab_unmap_grant_ref op;
 
-	gnttab_set_unmap_op(&op, (phys_addr_t)vaddr, GNTMAP_host_map, handle);
+	gnttab_set_unmap_op(&op, (unsigned long)vaddr, GNTMAP_host_map, handle);
 
 	if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
 		BUG();
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index 3864967..b793723 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -257,11 +257,12 @@
 	DPRINTK("%s", dev->nodename);
 
 	free_otherend_watch(dev);
-	free_otherend_details(dev);
 
 	if (drv->remove)
 		drv->remove(dev);
 
+	free_otherend_details(dev);
+
 	xenbus_switch_state(dev, XenbusStateClosed);
 	return 0;
 }
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c
index 9c57819..f20c5f1 100644
--- a/drivers/xen/xenbus/xenbus_probe_frontend.c
+++ b/drivers/xen/xenbus/xenbus_probe_frontend.c
@@ -53,6 +53,12 @@
 	char *nodename;
 	int err;
 
+	/* ignore console/0 */
+	if (!strncmp(type, "console", 7) && !strncmp(name, "0", 1)) {
+		DPRINTK("Ignoring buggy device entry console/0");
+		return 0;
+	}
+
 	nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", bus->root, type, name);
 	if (!nodename)
 		return -ENOMEM;
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 1964f98..b85efa7 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -594,21 +594,21 @@
 	int err;
 	pr_info("Installing v9fs 9p2000 file system support\n");
 	/* TODO: Setup list of registered trasnport modules */
-	err = register_filesystem(&v9fs_fs_type);
-	if (err < 0) {
-		pr_err("Failed to register filesystem\n");
-		return err;
-	}
 
 	err = v9fs_cache_register();
 	if (err < 0) {
 		pr_err("Failed to register v9fs for caching\n");
-		goto out_fs_unreg;
+		return err;
 	}
 
 	err = v9fs_sysfs_init();
 	if (err < 0) {
 		pr_err("Failed to register with sysfs\n");
+		goto out_cache;
+	}
+	err = register_filesystem(&v9fs_fs_type);
+	if (err < 0) {
+		pr_err("Failed to register filesystem\n");
 		goto out_sysfs_cleanup;
 	}
 
@@ -617,8 +617,8 @@
 out_sysfs_cleanup:
 	v9fs_sysfs_cleanup();
 
-out_fs_unreg:
-	unregister_filesystem(&v9fs_fs_type);
+out_cache:
+	v9fs_cache_unregister();
 
 	return err;
 }
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 7b0cd87..8c92a9b 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -155,9 +155,8 @@
 		goto release_sb;
 	}
 
-	root = d_alloc_root(inode);
+	root = d_make_root(inode);
 	if (!root) {
-		iput(inode);
 		retval = -ENOMEM;
 		goto release_sb;
 	}
@@ -260,7 +259,7 @@
 	if (v9fs_proto_dotl(v9ses)) {
 		res = p9_client_statfs(fid, &rs);
 		if (res == 0) {
-			buf->f_type = V9FS_MAGIC;
+			buf->f_type = rs.type;
 			buf->f_bsize = rs.bsize;
 			buf->f_blocks = rs.blocks;
 			buf->f_bfree = rs.bfree;
diff --git a/fs/Kconfig b/fs/Kconfig
index aa19526..f95ae3a 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -214,6 +214,7 @@
 source "fs/omfs/Kconfig"
 source "fs/hpfs/Kconfig"
 source "fs/qnx4/Kconfig"
+source "fs/qnx6/Kconfig"
 source "fs/romfs/Kconfig"
 source "fs/pstore/Kconfig"
 source "fs/sysv/Kconfig"
diff --git a/fs/Makefile b/fs/Makefile
index 93804d4..2fb9779 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -102,6 +102,7 @@
 obj-$(CONFIG_AFFS_FS)		+= affs/
 obj-$(CONFIG_ROMFS_FS)		+= romfs/
 obj-$(CONFIG_QNX4FS_FS)		+= qnx4/
+obj-$(CONFIG_QNX6FS_FS)		+= qnx6/
 obj-$(CONFIG_AUTOFS4_FS)	+= autofs4/
 obj-$(CONFIG_ADFS_FS)		+= adfs/
 obj-$(CONFIG_FUSE_FS)		+= fuse/
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 8e3b36a..06fdcc9 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -483,10 +483,9 @@
 
 	sb->s_d_op = &adfs_dentry_operations;
 	root = adfs_iget(sb, &root_obj);
-	sb->s_root = d_alloc_root(root);
+	sb->s_root = d_make_root(root);
 	if (!sb->s_root) {
 		int i;
-		iput(root);
 		for (i = 0; i < asb->s_map_size; i++)
 			brelse(asb->s_map[i].dm_bh);
 		kfree(asb->s_map);
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 8ba73fe..0782653 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -473,7 +473,7 @@
 	root_inode = affs_iget(sb, root_block);
 	if (IS_ERR(root_inode)) {
 		ret = PTR_ERR(root_inode);
-		goto out_error_noinode;
+		goto out_error;
 	}
 
 	if (AFFS_SB(sb)->s_flags & SF_INTL)
@@ -481,7 +481,7 @@
 	else
 		sb->s_d_op = &affs_dentry_operations;
 
-	sb->s_root = d_alloc_root(root_inode);
+	sb->s_root = d_make_root(root_inode);
 	if (!sb->s_root) {
 		printk(KERN_ERR "AFFS: Get root inode failed\n");
 		goto out_error;
@@ -494,9 +494,6 @@
 	 * Begin the cascaded cleanup ...
 	 */
 out_error:
-	if (root_inode)
-		iput(root_inode);
-out_error_noinode:
 	kfree(sbi->s_bitmap);
 	affs_brelse(root_bh);
 	kfree(sbi->s_prefix);
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 983ec59..f02b31e 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -301,7 +301,6 @@
 {
 	struct afs_super_info *as = sb->s_fs_info;
 	struct afs_fid fid;
-	struct dentry *root = NULL;
 	struct inode *inode = NULL;
 	int ret;
 
@@ -327,18 +326,16 @@
 		set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags);
 
 	ret = -ENOMEM;
-	root = d_alloc_root(inode);
-	if (!root)
+	sb->s_root = d_make_root(inode);
+	if (!sb->s_root)
 		goto error;
 
 	sb->s_d_op = &afs_fs_dentry_operations;
-	sb->s_root = root;
 
 	_leave(" = 0");
 	return 0;
 
 error:
-	iput(inode);
 	_leave(" = %d", ret);
 	return ret;
 }
diff --git a/fs/aio.c b/fs/aio.c
index 5b600cb..da88760 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -13,7 +13,7 @@
 #include <linux/errno.h>
 #include <linux/time.h>
 #include <linux/aio_abi.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/syscalls.h>
 #include <linux/backing-dev.h>
 #include <linux/uio.h>
@@ -199,16 +199,7 @@
 static void ctx_rcu_free(struct rcu_head *head)
 {
 	struct kioctx *ctx = container_of(head, struct kioctx, rcu_head);
-	unsigned nr_events = ctx->max_reqs;
-
 	kmem_cache_free(kioctx_cachep, ctx);
-
-	if (nr_events) {
-		spin_lock(&aio_nr_lock);
-		BUG_ON(aio_nr - nr_events > aio_nr);
-		aio_nr -= nr_events;
-		spin_unlock(&aio_nr_lock);
-	}
 }
 
 /* __put_ioctx
@@ -217,13 +208,19 @@
  */
 static void __put_ioctx(struct kioctx *ctx)
 {
+	unsigned nr_events = ctx->max_reqs;
 	BUG_ON(ctx->reqs_active);
 
-	cancel_delayed_work(&ctx->wq);
-	cancel_work_sync(&ctx->wq.work);
+	cancel_delayed_work_sync(&ctx->wq);
 	aio_free_ring(ctx);
 	mmdrop(ctx->mm);
 	ctx->mm = NULL;
+	if (nr_events) {
+		spin_lock(&aio_nr_lock);
+		BUG_ON(aio_nr - nr_events > aio_nr);
+		aio_nr -= nr_events;
+		spin_unlock(&aio_nr_lock);
+	}
 	pr_debug("__put_ioctx: freeing %p\n", ctx);
 	call_rcu(&ctx->rcu_head, ctx_rcu_free);
 }
@@ -247,7 +244,7 @@
 {
 	struct mm_struct *mm;
 	struct kioctx *ctx;
-	int did_sync = 0;
+	int err = -ENOMEM;
 
 	/* Prevent overflows */
 	if ((nr_events > (0x10000000U / sizeof(struct io_event))) ||
@@ -256,7 +253,7 @@
 		return ERR_PTR(-EINVAL);
 	}
 
-	if ((unsigned long)nr_events > aio_max_nr)
+	if (!nr_events || (unsigned long)nr_events > aio_max_nr)
 		return ERR_PTR(-EAGAIN);
 
 	ctx = kmem_cache_zalloc(kioctx_cachep, GFP_KERNEL);
@@ -280,25 +277,14 @@
 		goto out_freectx;
 
 	/* limit the number of system wide aios */
-	do {
-		spin_lock_bh(&aio_nr_lock);
-		if (aio_nr + nr_events > aio_max_nr ||
-		    aio_nr + nr_events < aio_nr)
-			ctx->max_reqs = 0;
-		else
-			aio_nr += ctx->max_reqs;
-		spin_unlock_bh(&aio_nr_lock);
-		if (ctx->max_reqs || did_sync)
-			break;
-
-		/* wait for rcu callbacks to have completed before giving up */
-		synchronize_rcu();
-		did_sync = 1;
-		ctx->max_reqs = nr_events;
-	} while (1);
-
-	if (ctx->max_reqs == 0)
+	spin_lock(&aio_nr_lock);
+	if (aio_nr + nr_events > aio_max_nr ||
+	    aio_nr + nr_events < aio_nr) {
+		spin_unlock(&aio_nr_lock);
 		goto out_cleanup;
+	}
+	aio_nr += ctx->max_reqs;
+	spin_unlock(&aio_nr_lock);
 
 	/* now link into global list. */
 	spin_lock(&mm->ioctx_lock);
@@ -310,27 +296,27 @@
 	return ctx;
 
 out_cleanup:
-	__put_ioctx(ctx);
-	return ERR_PTR(-EAGAIN);
-
+	err = -EAGAIN;
+	aio_free_ring(ctx);
 out_freectx:
 	mmdrop(mm);
 	kmem_cache_free(kioctx_cachep, ctx);
-	ctx = ERR_PTR(-ENOMEM);
-
-	dprintk("aio: error allocating ioctx %p\n", ctx);
-	return ctx;
+	dprintk("aio: error allocating ioctx %d\n", err);
+	return ERR_PTR(err);
 }
 
-/* aio_cancel_all
+/* kill_ctx
  *	Cancels all outstanding aio requests on an aio context.  Used 
  *	when the processes owning a context have all exited to encourage 
  *	the rapid destruction of the kioctx.
  */
-static void aio_cancel_all(struct kioctx *ctx)
+static void kill_ctx(struct kioctx *ctx)
 {
 	int (*cancel)(struct kiocb *, struct io_event *);
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
 	struct io_event res;
+
 	spin_lock_irq(&ctx->ctx_lock);
 	ctx->dead = 1;
 	while (!list_empty(&ctx->active_reqs)) {
@@ -346,15 +332,7 @@
 			spin_lock_irq(&ctx->ctx_lock);
 		}
 	}
-	spin_unlock_irq(&ctx->ctx_lock);
-}
 
-static void wait_for_all_aios(struct kioctx *ctx)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	spin_lock_irq(&ctx->ctx_lock);
 	if (!ctx->reqs_active)
 		goto out;
 
@@ -404,13 +382,7 @@
 		ctx = hlist_entry(mm->ioctx_list.first, struct kioctx, list);
 		hlist_del_rcu(&ctx->list);
 
-		aio_cancel_all(ctx);
-
-		wait_for_all_aios(ctx);
-		/*
-		 * Ensure we don't leave the ctx on the aio_wq
-		 */
-		cancel_work_sync(&ctx->wq.work);
+		kill_ctx(ctx);
 
 		if (1 != atomic_read(&ctx->users))
 			printk(KERN_DEBUG
@@ -920,7 +892,7 @@
  	unuse_mm(mm);
 	set_fs(oldfs);
 	/*
-	 * we're in a worker thread already, don't use queue_delayed_work,
+	 * we're in a worker thread already; no point using non-zero delay
 	 */
 	if (requeue)
 		queue_delayed_work(aio_wq, &ctx->wq, 0);
@@ -1290,8 +1262,7 @@
 	if (likely(!was_dead))
 		put_ioctx(ioctx);	/* twice for the list */
 
-	aio_cancel_all(ioctx);
-	wait_for_all_aios(ioctx);
+	kill_ctx(ioctx);
 
 	/*
 	 * Wake up any waiters.  The setting of ctx->dead must be seen
@@ -1299,7 +1270,6 @@
 	 * locking done by the above calls to ensure this consistency.
 	 */
 	wake_up_all(&ioctx->wait);
-	put_ioctx(ioctx);	/* once for the lookup */
 }
 
 /* sys_io_setup:
@@ -1336,11 +1306,9 @@
 	ret = PTR_ERR(ioctx);
 	if (!IS_ERR(ioctx)) {
 		ret = put_user(ioctx->user_id, ctxp);
-		if (!ret) {
-			put_ioctx(ioctx);
-			return 0;
-		}
-		io_destroy(ioctx);
+		if (ret)
+			io_destroy(ioctx);
+		put_ioctx(ioctx);
 	}
 
 out:
@@ -1358,6 +1326,7 @@
 	struct kioctx *ioctx = lookup_ioctx(ctx);
 	if (likely(NULL != ioctx)) {
 		io_destroy(ioctx);
+		put_ioctx(ioctx);
 		return 0;
 	}
 	pr_debug("EINVAL: io_destroy: invalid context id\n");
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index f11e43e..28d39fb 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -39,19 +39,6 @@
 	.d_dname	= anon_inodefs_dname,
 };
 
-static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type,
-				int flags, const char *dev_name, void *data)
-{
-	return mount_pseudo(fs_type, "anon_inode:", NULL,
-			&anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC);
-}
-
-static struct file_system_type anon_inode_fs_type = {
-	.name		= "anon_inodefs",
-	.mount		= anon_inodefs_mount,
-	.kill_sb	= kill_anon_super,
-};
-
 /*
  * nop .set_page_dirty method so that people can use .page_mkwrite on
  * anon inodes.
@@ -65,6 +52,62 @@
 	.set_page_dirty = anon_set_page_dirty,
 };
 
+/*
+ * A single inode exists for all anon_inode files. Contrary to pipes,
+ * anon_inode inodes have no associated per-instance data, so we need
+ * only allocate one of them.
+ */
+static struct inode *anon_inode_mkinode(struct super_block *s)
+{
+	struct inode *inode = new_inode_pseudo(s);
+
+	if (!inode)
+		return ERR_PTR(-ENOMEM);
+
+	inode->i_ino = get_next_ino();
+	inode->i_fop = &anon_inode_fops;
+
+	inode->i_mapping->a_ops = &anon_aops;
+
+	/*
+	 * Mark the inode dirty from the very beginning,
+	 * that way it will never be moved to the dirty
+	 * list because mark_inode_dirty() will think
+	 * that it already _is_ on the dirty list.
+	 */
+	inode->i_state = I_DIRTY;
+	inode->i_mode = S_IRUSR | S_IWUSR;
+	inode->i_uid = current_fsuid();
+	inode->i_gid = current_fsgid();
+	inode->i_flags |= S_PRIVATE;
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	return inode;
+}
+
+static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type,
+				int flags, const char *dev_name, void *data)
+{
+	struct dentry *root;
+	root = mount_pseudo(fs_type, "anon_inode:", NULL,
+			&anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC);
+	if (!IS_ERR(root)) {
+		struct super_block *s = root->d_sb;
+		anon_inode_inode = anon_inode_mkinode(s);
+		if (IS_ERR(anon_inode_inode)) {
+			dput(root);
+			deactivate_locked_super(s);
+			root = ERR_CAST(anon_inode_inode);
+		}
+	}
+	return root;
+}
+
+static struct file_system_type anon_inode_fs_type = {
+	.name		= "anon_inodefs",
+	.mount		= anon_inodefs_mount,
+	.kill_sb	= kill_anon_super,
+};
+
 /**
  * anon_inode_getfile - creates a new file instance by hooking it up to an
  *                      anonymous inode, and a dentry that describe the "class"
@@ -180,38 +223,6 @@
 }
 EXPORT_SYMBOL_GPL(anon_inode_getfd);
 
-/*
- * A single inode exists for all anon_inode files. Contrary to pipes,
- * anon_inode inodes have no associated per-instance data, so we need
- * only allocate one of them.
- */
-static struct inode *anon_inode_mkinode(void)
-{
-	struct inode *inode = new_inode_pseudo(anon_inode_mnt->mnt_sb);
-
-	if (!inode)
-		return ERR_PTR(-ENOMEM);
-
-	inode->i_ino = get_next_ino();
-	inode->i_fop = &anon_inode_fops;
-
-	inode->i_mapping->a_ops = &anon_aops;
-
-	/*
-	 * Mark the inode dirty from the very beginning,
-	 * that way it will never be moved to the dirty
-	 * list because mark_inode_dirty() will think
-	 * that it already _is_ on the dirty list.
-	 */
-	inode->i_state = I_DIRTY;
-	inode->i_mode = S_IRUSR | S_IWUSR;
-	inode->i_uid = current_fsuid();
-	inode->i_gid = current_fsgid();
-	inode->i_flags |= S_PRIVATE;
-	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	return inode;
-}
-
 static int __init anon_inode_init(void)
 {
 	int error;
@@ -224,16 +235,8 @@
 		error = PTR_ERR(anon_inode_mnt);
 		goto err_unregister_filesystem;
 	}
-	anon_inode_inode = anon_inode_mkinode();
-	if (IS_ERR(anon_inode_inode)) {
-		error = PTR_ERR(anon_inode_inode);
-		goto err_mntput;
-	}
-
 	return 0;
 
-err_mntput:
-	kern_unmount(anon_inode_mnt);
 err_unregister_filesystem:
 	unregister_filesystem(&anon_inode_fs_type);
 err_exit:
diff --git a/fs/attr.c b/fs/attr.c
index 95053ad..73f69a6 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -5,7 +5,7 @@
  *  changes by Thomas Schoebel-Theuer
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/string.h>
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c
index 85f1fcd..9dacb85 100644
--- a/fs/autofs4/dev-ioctl.c
+++ b/fs/autofs4/dev-ioctl.c
@@ -230,7 +230,7 @@
 	fdt = files_fdtable(files);
 	BUG_ON(fdt->fd[fd] != NULL);
 	rcu_assign_pointer(fdt->fd[fd], file);
-	FD_SET(fd, fdt->close_on_exec);
+	__set_close_on_exec(fd, fdt);
 	spin_unlock(&files->file_lock);
 }
 
diff --git a/fs/autofs4/init.c b/fs/autofs4/init.c
index c038727..cddc74b 100644
--- a/fs/autofs4/init.c
+++ b/fs/autofs4/init.c
@@ -31,11 +31,11 @@
 {
 	int err;
 
+	autofs_dev_ioctl_init();
+
 	err = register_filesystem(&autofs_fs_type);
 	if (err)
-		return err;
-
-	autofs_dev_ioctl_init();
+		autofs_dev_ioctl_exit();
 
 	return err;
 }
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 06858d9..d8dc002 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -247,12 +247,9 @@
 	if (!ino)
 		goto fail_free;
 	root_inode = autofs4_get_inode(s, S_IFDIR | 0755);
-	if (!root_inode)
-		goto fail_ino;
-
-	root = d_alloc_root(root_inode);
+	root = d_make_root(root_inode);
 	if (!root)
-		goto fail_iput;
+		goto fail_ino;
 	pipe = NULL;
 
 	root->d_fsdata = ino;
@@ -317,9 +314,6 @@
 fail_dput:
 	dput(root);
 	goto fail_free;
-fail_iput:
-	printk("autofs: get root dentry failed\n");
-	iput(root_inode);
 fail_ino:
 	kfree(ino);
 fail_free:
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index 22e9a78..37268c5 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -9,7 +9,7 @@
  */
 
 #include <linux/fs.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/stat.h>
 #include <linux/time.h>
 #include <linux/namei.h>
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 6e6d536..e18da23 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -852,9 +852,8 @@
 		ret = PTR_ERR(root);
 		goto unacquire_priv_sbp;
 	}
-	sb->s_root = d_alloc_root(root);
+	sb->s_root = d_make_root(root);
 	if (!sb->s_root) {
-		iput(root);
 		befs_error(sb, "get root inode failed");
 		goto unacquire_priv_sbp;
 	}
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index b0391bc..e23dc7c 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -367,9 +367,8 @@
 		ret = PTR_ERR(inode);
 		goto out2;
 	}
-	s->s_root = d_alloc_root(inode);
+	s->s_root = d_make_root(inode);
 	if (!s->s_root) {
-		iput(inode);
 		ret = -ENOMEM;
 		goto out2;
 	}
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 1ff9405..2eb12f1 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -26,7 +26,6 @@
 #include <linux/coredump.h>
 #include <linux/slab.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
 #include <asm/a.out-core.h>
@@ -267,7 +266,6 @@
 	}
 
 	install_exec_creds(bprm);
- 	current->flags &= ~PF_FORKNOEXEC;
 
 	if (N_MAGIC(ex) == OMAGIC) {
 		unsigned long text_addr, map_size;
@@ -454,7 +452,8 @@
 
 static int __init init_aout_binfmt(void)
 {
-	return register_binfmt(&aout_format);
+	register_binfmt(&aout_format);
+	return 0;
 }
 
 static void __exit exit_aout_binfmt(void)
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 07d096c..48ffb3d 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -35,6 +35,7 @@
 #include <asm/uaccess.h>
 #include <asm/param.h>
 #include <asm/page.h>
+#include <asm/exec.h>
 
 static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs);
 static int load_elf_library(struct file *);
@@ -712,7 +713,6 @@
 		goto out_free_dentry;
 
 	/* OK, This is the point of no return */
-	current->flags &= ~PF_FORKNOEXEC;
 	current->mm->def_flags = def_flags;
 
 	/* Do this immediately, since STACK_TOP as used in setup_arg_pages
@@ -934,7 +934,6 @@
 #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
 
 	install_exec_creds(bprm);
-	current->flags &= ~PF_FORKNOEXEC;
 	retval = create_elf_tables(bprm, &loc->elf_ex,
 			  load_addr, interp_load_addr);
 	if (retval < 0) {
@@ -1095,6 +1094,29 @@
  */
 
 /*
+ * The purpose of always_dump_vma() is to make sure that special kernel mappings
+ * that are useful for post-mortem analysis are included in every core dump.
+ * In that way we ensure that the core dump is fully interpretable later
+ * without matching up the same kernel and hardware config to see what PC values
+ * meant. These special mappings include - vDSO, vsyscall, and other
+ * architecture specific mappings
+ */
+static bool always_dump_vma(struct vm_area_struct *vma)
+{
+	/* Any vsyscall mappings? */
+	if (vma == get_gate_vma(vma->vm_mm))
+		return true;
+	/*
+	 * arch_vma_name() returns non-NULL for special architecture mappings,
+	 * such as vDSO sections.
+	 */
+	if (arch_vma_name(vma))
+		return true;
+
+	return false;
+}
+
+/*
  * Decide what to dump of a segment, part, all or none.
  */
 static unsigned long vma_dump_size(struct vm_area_struct *vma,
@@ -1102,10 +1124,13 @@
 {
 #define FILTER(type)	(mm_flags & (1UL << MMF_DUMP_##type))
 
-	/* The vma can be set up to tell us the answer directly.  */
-	if (vma->vm_flags & VM_ALWAYSDUMP)
+	/* always dump the vdso and vsyscall sections */
+	if (always_dump_vma(vma))
 		goto whole;
 
+	if (vma->vm_flags & VM_NODUMP)
+		return 0;
+
 	/* Hugetlb memory check */
 	if (vma->vm_flags & VM_HUGETLB) {
 		if ((vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_SHARED))
@@ -1390,6 +1415,22 @@
 		regset->writeback(task, regset, 1);
 }
 
+#ifndef PR_REG_SIZE
+#define PR_REG_SIZE(S) sizeof(S)
+#endif
+
+#ifndef PRSTATUS_SIZE
+#define PRSTATUS_SIZE(S) sizeof(S)
+#endif
+
+#ifndef PR_REG_PTR
+#define PR_REG_PTR(S) (&((S)->pr_reg))
+#endif
+
+#ifndef SET_PR_FPVALID
+#define SET_PR_FPVALID(S, V) ((S)->pr_fpvalid = (V))
+#endif
+
 static int fill_thread_core_info(struct elf_thread_core_info *t,
 				 const struct user_regset_view *view,
 				 long signr, size_t *total)
@@ -1404,11 +1445,11 @@
 	 */
 	fill_prstatus(&t->prstatus, t->task, signr);
 	(void) view->regsets[0].get(t->task, &view->regsets[0],
-				    0, sizeof(t->prstatus.pr_reg),
-				    &t->prstatus.pr_reg, NULL);
+				    0, PR_REG_SIZE(t->prstatus.pr_reg),
+				    PR_REG_PTR(&t->prstatus), NULL);
 
 	fill_note(&t->notes[0], "CORE", NT_PRSTATUS,
-		  sizeof(t->prstatus), &t->prstatus);
+		  PRSTATUS_SIZE(t->prstatus), &t->prstatus);
 	*total += notesize(&t->notes[0]);
 
 	do_thread_regset_writeback(t->task, &view->regsets[0]);
@@ -1438,7 +1479,7 @@
 						  regset->core_note_type,
 						  size, data);
 				else {
-					t->prstatus.pr_fpvalid = 1;
+					SET_PR_FPVALID(&t->prstatus, 1);
 					fill_note(&t->notes[i], "CORE",
 						  NT_PRFPREG, size, data);
 				}
@@ -2077,7 +2118,8 @@
 
 static int __init init_elf_binfmt(void)
 {
-	return register_binfmt(&elf_format);
+	register_binfmt(&elf_format);
+	return 0;
 }
 
 static void __exit exit_elf_binfmt(void)
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 30745f4..9bd5612 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -39,6 +39,7 @@
 #include <asm/uaccess.h>
 #include <asm/param.h>
 #include <asm/pgalloc.h>
+#include <asm/exec.h>
 
 typedef char *elf_caddr_t;
 
@@ -91,7 +92,8 @@
 
 static int __init init_elf_fdpic_binfmt(void)
 {
-	return register_binfmt(&elf_fdpic_format);
+	register_binfmt(&elf_fdpic_format);
+	return 0;
 }
 
 static void __exit exit_elf_fdpic_binfmt(void)
@@ -334,8 +336,6 @@
 	current->mm->context.exec_fdpic_loadmap = 0;
 	current->mm->context.interp_fdpic_loadmap = 0;
 
-	current->flags &= ~PF_FORKNOEXEC;
-
 #ifdef CONFIG_MMU
 	elf_fdpic_arch_lay_out_mm(&exec_params,
 				  &interp_params,
@@ -413,7 +413,6 @@
 #endif
 
 	install_exec_creds(bprm);
-	current->flags &= ~PF_FORKNOEXEC;
 	if (create_elf_fdpic_tables(bprm, current->mm,
 				    &exec_params, &interp_params) < 0)
 		goto error_kill;
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
index b8e8b0a..2790c7e 100644
--- a/fs/binfmt_em86.c
+++ b/fs/binfmt_em86.c
@@ -100,7 +100,8 @@
 
 static int __init init_em86_binfmt(void)
 {
-	return register_binfmt(&em86_format);
+	register_binfmt(&em86_format);
+	return 0;
 }
 
 static void __exit exit_em86_binfmt(void)
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index 1bffbe0..024d20e 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -15,7 +15,7 @@
  *	JAN/99 -- coded full program relocation (gerg@snapgear.com)
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -37,7 +37,6 @@
 #include <linux/syscalls.h>
 
 #include <asm/byteorder.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 #include <asm/cacheflush.h>
@@ -902,7 +901,6 @@
 						libinfo.lib_list[j].start_data:UNLOADED_LIB;
 
 	install_exec_creds(bprm);
- 	current->flags &= ~PF_FORKNOEXEC;
 
 	set_binfmt(&flat_format);
 
@@ -950,7 +948,8 @@
 
 static int __init init_flat_binfmt(void)
 {
-	return register_binfmt(&flat_format);
+	register_binfmt(&flat_format);
+	return 0;
 }
 
 /****************************************************************************/
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index a9198df..613aa06 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/magic.h>
 #include <linux/binfmts.h>
 #include <linux/slab.h>
 #include <linux/ctype.h>
@@ -699,7 +700,7 @@
 		[3] = {"register", &bm_register_operations, S_IWUSR},
 		/* last one */ {""}
 	};
-	int err = simple_fill_super(sb, 0x42494e4d, bm_files);
+	int err = simple_fill_super(sb, BINFMTFS_MAGIC, bm_files);
 	if (!err)
 		sb->s_op = &s_ops;
 	return err;
@@ -726,11 +727,8 @@
 static int __init init_misc_binfmt(void)
 {
 	int err = register_filesystem(&bm_fs_type);
-	if (!err) {
-		err = insert_binfmt(&misc_format);
-		if (err)
-			unregister_filesystem(&bm_fs_type);
-	}
+	if (!err)
+		insert_binfmt(&misc_format);
 	return err;
 }
 
diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c
index 396a988..d3b8c1f 100644
--- a/fs/binfmt_script.c
+++ b/fs/binfmt_script.c
@@ -105,7 +105,8 @@
 
 static int __init init_script_binfmt(void)
 {
-	return register_binfmt(&script_format);
+	register_binfmt(&script_format);
+	return 0;
 }
 
 static void __exit exit_script_binfmt(void)
diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c
index cc8560f..e4fc746 100644
--- a/fs/binfmt_som.c
+++ b/fs/binfmt_som.c
@@ -225,7 +225,6 @@
 		goto out_free;
 
 	/* OK, This is the point of no return */
-	current->flags &= ~PF_FORKNOEXEC;
 	current->personality = PER_HPUX;
 	setup_new_exec(bprm);
 
@@ -289,7 +288,8 @@
 
 static int __init init_som_binfmt(void)
 {
-	return register_binfmt(&som_format);
+	register_binfmt(&som_format);
+	return 0;
 }
 
 static void __exit exit_som_binfmt(void)
diff --git a/fs/bio.c b/fs/bio.c
index b980ecd..e453924 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -22,7 +22,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/mempool.h>
 #include <linux/workqueue.h>
 #include <scsi/sg.h>		/* for struct sg_iovec */
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 5e9f198f..e08f6a20 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -16,6 +16,7 @@
 #include <linux/blkdev.h>
 #include <linux/module.h>
 #include <linux/blkpg.h>
+#include <linux/magic.h>
 #include <linux/buffer_head.h>
 #include <linux/swap.h>
 #include <linux/pagevec.h>
@@ -109,7 +110,7 @@
 	/* 99% of the time, we don't need to flush the cleancache on the bdev.
 	 * But, for the strange corners, lets be cautious
 	 */
-	cleancache_flush_inode(mapping);
+	cleancache_invalidate_inode(mapping);
 }
 EXPORT_SYMBOL(invalidate_bdev);
 
@@ -506,7 +507,7 @@
 static struct dentry *bd_mount(struct file_system_type *fs_type,
 	int flags, const char *dev_name, void *data)
 {
-	return mount_pseudo(fs_type, "bdev:", &bdev_sops, NULL, 0x62646576);
+	return mount_pseudo(fs_type, "bdev:", &bdev_sops, NULL, BDEVFS_MAGIC);
 }
 
 static struct file_system_type bd_type = {
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c
index 0cc20b3..4270414 100644
--- a/fs/btrfs/async-thread.c
+++ b/fs/btrfs/async-thread.c
@@ -171,11 +171,11 @@
 	spin_unlock_irqrestore(&workers->lock, flags);
 }
 
-static noinline int run_ordered_completions(struct btrfs_workers *workers,
+static noinline void run_ordered_completions(struct btrfs_workers *workers,
 					    struct btrfs_work *work)
 {
 	if (!workers->ordered)
-		return 0;
+		return;
 
 	set_bit(WORK_DONE_BIT, &work->flags);
 
@@ -213,7 +213,6 @@
 	}
 
 	spin_unlock(&workers->order_lock);
-	return 0;
 }
 
 static void put_worker(struct btrfs_worker_thread *worker)
@@ -399,7 +398,7 @@
 /*
  * this will wait for all the worker threads to shutdown
  */
-int btrfs_stop_workers(struct btrfs_workers *workers)
+void btrfs_stop_workers(struct btrfs_workers *workers)
 {
 	struct list_head *cur;
 	struct btrfs_worker_thread *worker;
@@ -427,7 +426,6 @@
 		put_worker(worker);
 	}
 	spin_unlock_irq(&workers->lock);
-	return 0;
 }
 
 /*
@@ -615,14 +613,14 @@
  * it was taken from.  It is intended for use with long running work functions
  * that make some progress and want to give the cpu up for others.
  */
-int btrfs_requeue_work(struct btrfs_work *work)
+void btrfs_requeue_work(struct btrfs_work *work)
 {
 	struct btrfs_worker_thread *worker = work->worker;
 	unsigned long flags;
 	int wake = 0;
 
 	if (test_and_set_bit(WORK_QUEUED_BIT, &work->flags))
-		goto out;
+		return;
 
 	spin_lock_irqsave(&worker->lock, flags);
 	if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags))
@@ -649,9 +647,6 @@
 	if (wake)
 		wake_up_process(worker->task);
 	spin_unlock_irqrestore(&worker->lock, flags);
-out:
-
-	return 0;
 }
 
 void btrfs_set_work_high_prio(struct btrfs_work *work)
diff --git a/fs/btrfs/async-thread.h b/fs/btrfs/async-thread.h
index f34cc31..063698b 100644
--- a/fs/btrfs/async-thread.h
+++ b/fs/btrfs/async-thread.h
@@ -111,9 +111,9 @@
 
 void btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work);
 int btrfs_start_workers(struct btrfs_workers *workers);
-int btrfs_stop_workers(struct btrfs_workers *workers);
+void btrfs_stop_workers(struct btrfs_workers *workers);
 void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max,
 			struct btrfs_workers *async_starter);
-int btrfs_requeue_work(struct btrfs_work *work);
+void btrfs_requeue_work(struct btrfs_work *work);
 void btrfs_set_work_high_prio(struct btrfs_work *work);
 #endif
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 0436c12..f4e9074 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -116,6 +116,7 @@
  * to a logical address
  */
 static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
+					int search_commit_root,
 					struct __prelim_ref *ref,
 					struct ulist *parents)
 {
@@ -131,6 +132,7 @@
 	path = btrfs_alloc_path();
 	if (!path)
 		return -ENOMEM;
+	path->search_commit_root = !!search_commit_root;
 
 	root_key.objectid = ref->root_id;
 	root_key.type = BTRFS_ROOT_ITEM_KEY;
@@ -188,6 +190,7 @@
  * resolve all indirect backrefs from the list
  */
 static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
+				   int search_commit_root,
 				   struct list_head *head)
 {
 	int err;
@@ -212,7 +215,8 @@
 			continue;
 		if (ref->count == 0)
 			continue;
-		err = __resolve_indirect_ref(fs_info, ref, parents);
+		err = __resolve_indirect_ref(fs_info, search_commit_root,
+					     ref, parents);
 		if (err) {
 			if (ret == 0)
 				ret = err;
@@ -586,6 +590,7 @@
 	struct btrfs_delayed_ref_head *head;
 	int info_level = 0;
 	int ret;
+	int search_commit_root = (trans == BTRFS_BACKREF_SEARCH_COMMIT_ROOT);
 	struct list_head prefs_delayed;
 	struct list_head prefs;
 	struct __prelim_ref *ref;
@@ -600,6 +605,7 @@
 	path = btrfs_alloc_path();
 	if (!path)
 		return -ENOMEM;
+	path->search_commit_root = !!search_commit_root;
 
 	/*
 	 * grab both a lock on the path and a lock on the delayed ref head.
@@ -614,35 +620,39 @@
 		goto out;
 	BUG_ON(ret == 0);
 
-	/*
-	 * look if there are updates for this ref queued and lock the head
-	 */
-	delayed_refs = &trans->transaction->delayed_refs;
-	spin_lock(&delayed_refs->lock);
-	head = btrfs_find_delayed_ref_head(trans, bytenr);
-	if (head) {
-		if (!mutex_trylock(&head->mutex)) {
-			atomic_inc(&head->node.refs);
-			spin_unlock(&delayed_refs->lock);
+	if (trans != BTRFS_BACKREF_SEARCH_COMMIT_ROOT) {
+		/*
+		 * look if there are updates for this ref queued and lock the
+		 * head
+		 */
+		delayed_refs = &trans->transaction->delayed_refs;
+		spin_lock(&delayed_refs->lock);
+		head = btrfs_find_delayed_ref_head(trans, bytenr);
+		if (head) {
+			if (!mutex_trylock(&head->mutex)) {
+				atomic_inc(&head->node.refs);
+				spin_unlock(&delayed_refs->lock);
 
-			btrfs_release_path(path);
+				btrfs_release_path(path);
 
-			/*
-			 * Mutex was contended, block until it's
-			 * released and try again
-			 */
-			mutex_lock(&head->mutex);
-			mutex_unlock(&head->mutex);
-			btrfs_put_delayed_ref(&head->node);
-			goto again;
+				/*
+				 * Mutex was contended, block until it's
+				 * released and try again
+				 */
+				mutex_lock(&head->mutex);
+				mutex_unlock(&head->mutex);
+				btrfs_put_delayed_ref(&head->node);
+				goto again;
+			}
+			ret = __add_delayed_refs(head, seq, &info_key,
+						 &prefs_delayed);
+			if (ret) {
+				spin_unlock(&delayed_refs->lock);
+				goto out;
+			}
 		}
-		ret = __add_delayed_refs(head, seq, &info_key, &prefs_delayed);
-		if (ret) {
-			spin_unlock(&delayed_refs->lock);
-			goto out;
-		}
+		spin_unlock(&delayed_refs->lock);
 	}
-	spin_unlock(&delayed_refs->lock);
 
 	if (path->slots[0]) {
 		struct extent_buffer *leaf;
@@ -679,7 +689,7 @@
 	if (ret)
 		goto out;
 
-	ret = __resolve_indirect_refs(fs_info, &prefs);
+	ret = __resolve_indirect_refs(fs_info, search_commit_root, &prefs);
 	if (ret)
 		goto out;
 
@@ -1074,8 +1084,7 @@
 	return 0;
 }
 
-static int iterate_leaf_refs(struct btrfs_fs_info *fs_info,
-				struct btrfs_path *path, u64 logical,
+static int iterate_leaf_refs(struct btrfs_fs_info *fs_info, u64 logical,
 				u64 orig_extent_item_objectid,
 				u64 extent_item_pos, u64 root,
 				iterate_extent_inodes_t *iterate, void *ctx)
@@ -1143,35 +1152,38 @@
  * calls iterate() for every inode that references the extent identified by
  * the given parameters.
  * when the iterator function returns a non-zero value, iteration stops.
- * path is guaranteed to be in released state when iterate() is called.
  */
 int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
-				struct btrfs_path *path,
 				u64 extent_item_objectid, u64 extent_item_pos,
+				int search_commit_root,
 				iterate_extent_inodes_t *iterate, void *ctx)
 {
 	int ret;
 	struct list_head data_refs = LIST_HEAD_INIT(data_refs);
 	struct list_head shared_refs = LIST_HEAD_INIT(shared_refs);
 	struct btrfs_trans_handle *trans;
-	struct ulist *refs;
-	struct ulist *roots;
+	struct ulist *refs = NULL;
+	struct ulist *roots = NULL;
 	struct ulist_node *ref_node = NULL;
 	struct ulist_node *root_node = NULL;
 	struct seq_list seq_elem;
-	struct btrfs_delayed_ref_root *delayed_refs;
-
-	trans = btrfs_join_transaction(fs_info->extent_root);
-	if (IS_ERR(trans))
-		return PTR_ERR(trans);
+	struct btrfs_delayed_ref_root *delayed_refs = NULL;
 
 	pr_debug("resolving all inodes for extent %llu\n",
 			extent_item_objectid);
 
-	delayed_refs = &trans->transaction->delayed_refs;
-	spin_lock(&delayed_refs->lock);
-	btrfs_get_delayed_seq(delayed_refs, &seq_elem);
-	spin_unlock(&delayed_refs->lock);
+	if (search_commit_root) {
+		trans = BTRFS_BACKREF_SEARCH_COMMIT_ROOT;
+	} else {
+		trans = btrfs_join_transaction(fs_info->extent_root);
+		if (IS_ERR(trans))
+			return PTR_ERR(trans);
+
+		delayed_refs = &trans->transaction->delayed_refs;
+		spin_lock(&delayed_refs->lock);
+		btrfs_get_delayed_seq(delayed_refs, &seq_elem);
+		spin_unlock(&delayed_refs->lock);
+	}
 
 	ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid,
 				   extent_item_pos, seq_elem.seq,
@@ -1188,7 +1200,7 @@
 		while (!ret && (root_node = ulist_next(roots, root_node))) {
 			pr_debug("root %llu references leaf %llu\n",
 					root_node->val, ref_node->val);
-			ret = iterate_leaf_refs(fs_info, path, ref_node->val,
+			ret = iterate_leaf_refs(fs_info, ref_node->val,
 						extent_item_objectid,
 						extent_item_pos, root_node->val,
 						iterate, ctx);
@@ -1198,8 +1210,11 @@
 	ulist_free(refs);
 	ulist_free(roots);
 out:
-	btrfs_put_delayed_seq(delayed_refs, &seq_elem);
-	btrfs_end_transaction(trans, fs_info->extent_root);
+	if (!search_commit_root) {
+		btrfs_put_delayed_seq(delayed_refs, &seq_elem);
+		btrfs_end_transaction(trans, fs_info->extent_root);
+	}
+
 	return ret;
 }
 
@@ -1210,6 +1225,7 @@
 	int ret;
 	u64 extent_item_pos;
 	struct btrfs_key found_key;
+	int search_commit_root = path->search_commit_root;
 
 	ret = extent_from_logical(fs_info, logical, path,
 					&found_key);
@@ -1220,8 +1236,9 @@
 		return ret;
 
 	extent_item_pos = logical - found_key.objectid;
-	ret = iterate_extent_inodes(fs_info, path, found_key.objectid,
-					extent_item_pos, iterate, ctx);
+	ret = iterate_extent_inodes(fs_info, found_key.objectid,
+					extent_item_pos, search_commit_root,
+					iterate, ctx);
 
 	return ret;
 }
@@ -1342,12 +1359,6 @@
 				inode_to_path, ipath);
 }
 
-/*
- * allocates space to return multiple file system paths for an inode.
- * total_bytes to allocate are passed, note that space usable for actual path
- * information will be total_bytes - sizeof(struct inode_fs_paths).
- * the returned pointer must be freed with free_ipath() in the end.
- */
 struct btrfs_data_container *init_data_container(u32 total_bytes)
 {
 	struct btrfs_data_container *data;
@@ -1403,5 +1414,6 @@
 
 void free_ipath(struct inode_fs_paths *ipath)
 {
+	kfree(ipath->fspath);
 	kfree(ipath);
 }
diff --git a/fs/btrfs/backref.h b/fs/btrfs/backref.h
index d00dfa9..57ea2e9 100644
--- a/fs/btrfs/backref.h
+++ b/fs/btrfs/backref.h
@@ -22,6 +22,8 @@
 #include "ioctl.h"
 #include "ulist.h"
 
+#define BTRFS_BACKREF_SEARCH_COMMIT_ROOT ((struct btrfs_trans_handle *)0)
+
 struct inode_fs_paths {
 	struct btrfs_path		*btrfs_path;
 	struct btrfs_root		*fs_root;
@@ -44,9 +46,8 @@
 				u64 *out_root, u8 *out_level);
 
 int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
-				struct btrfs_path *path,
 				u64 extent_item_objectid,
-				u64 extent_offset,
+				u64 extent_offset, int search_commit_root,
 				iterate_extent_inodes_t *iterate, void *ctx);
 
 int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index b805afb..d286b40 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -226,8 +226,8 @@
  * Clear the writeback bits on all of the file
  * pages for a compressed write
  */
-static noinline int end_compressed_writeback(struct inode *inode, u64 start,
-					     unsigned long ram_size)
+static noinline void end_compressed_writeback(struct inode *inode, u64 start,
+					      unsigned long ram_size)
 {
 	unsigned long index = start >> PAGE_CACHE_SHIFT;
 	unsigned long end_index = (start + ram_size - 1) >> PAGE_CACHE_SHIFT;
@@ -253,7 +253,6 @@
 		index += ret;
 	}
 	/* the inode may be gone now */
-	return 0;
 }
 
 /*
@@ -392,16 +391,16 @@
 			 */
 			atomic_inc(&cb->pending_bios);
 			ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM */
 
 			if (!skip_sum) {
 				ret = btrfs_csum_one_bio(root, inode, bio,
 							 start, 1);
-				BUG_ON(ret);
+				BUG_ON(ret); /* -ENOMEM */
 			}
 
 			ret = btrfs_map_bio(root, WRITE, bio, 0, 1);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM */
 
 			bio_put(bio);
 
@@ -421,15 +420,15 @@
 	bio_get(bio);
 
 	ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
-	BUG_ON(ret);
+	BUG_ON(ret); /* -ENOMEM */
 
 	if (!skip_sum) {
 		ret = btrfs_csum_one_bio(root, inode, bio, start, 1);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 	}
 
 	ret = btrfs_map_bio(root, WRITE, bio, 0, 1);
-	BUG_ON(ret);
+	BUG_ON(ret); /* -ENOMEM */
 
 	bio_put(bio);
 	return 0;
@@ -497,7 +496,7 @@
 		 * sure they map to this compressed extent on disk.
 		 */
 		set_page_extent_mapped(page);
-		lock_extent(tree, last_offset, end, GFP_NOFS);
+		lock_extent(tree, last_offset, end);
 		read_lock(&em_tree->lock);
 		em = lookup_extent_mapping(em_tree, last_offset,
 					   PAGE_CACHE_SIZE);
@@ -507,7 +506,7 @@
 		    (last_offset + PAGE_CACHE_SIZE > extent_map_end(em)) ||
 		    (em->block_start >> 9) != cb->orig_bio->bi_sector) {
 			free_extent_map(em);
-			unlock_extent(tree, last_offset, end, GFP_NOFS);
+			unlock_extent(tree, last_offset, end);
 			unlock_page(page);
 			page_cache_release(page);
 			break;
@@ -535,7 +534,7 @@
 			nr_pages++;
 			page_cache_release(page);
 		} else {
-			unlock_extent(tree, last_offset, end, GFP_NOFS);
+			unlock_extent(tree, last_offset, end);
 			unlock_page(page);
 			page_cache_release(page);
 			break;
@@ -662,7 +661,7 @@
 			bio_get(comp_bio);
 
 			ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM */
 
 			/*
 			 * inc the count before we submit the bio so
@@ -675,14 +674,14 @@
 			if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
 				ret = btrfs_lookup_bio_sums(root, inode,
 							comp_bio, sums);
-				BUG_ON(ret);
+				BUG_ON(ret); /* -ENOMEM */
 			}
 			sums += (comp_bio->bi_size + root->sectorsize - 1) /
 				root->sectorsize;
 
 			ret = btrfs_map_bio(root, READ, comp_bio,
 					    mirror_num, 0);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM */
 
 			bio_put(comp_bio);
 
@@ -698,15 +697,15 @@
 	bio_get(comp_bio);
 
 	ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0);
-	BUG_ON(ret);
+	BUG_ON(ret); /* -ENOMEM */
 
 	if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
 		ret = btrfs_lookup_bio_sums(root, inode, comp_bio, sums);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 	}
 
 	ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0);
-	BUG_ON(ret);
+	BUG_ON(ret); /* -ENOMEM */
 
 	bio_put(comp_bio);
 	return 0;
@@ -734,7 +733,7 @@
 	&btrfs_lzo_compress,
 };
 
-int __init btrfs_init_compress(void)
+void __init btrfs_init_compress(void)
 {
 	int i;
 
@@ -744,7 +743,6 @@
 		atomic_set(&comp_alloc_workspace[i], 0);
 		init_waitqueue_head(&comp_workspace_wait[i]);
 	}
-	return 0;
 }
 
 /*
diff --git a/fs/btrfs/compression.h b/fs/btrfs/compression.h
index a12059f..9afb0a6 100644
--- a/fs/btrfs/compression.h
+++ b/fs/btrfs/compression.h
@@ -19,7 +19,7 @@
 #ifndef __BTRFS_COMPRESSION_
 #define __BTRFS_COMPRESSION_
 
-int btrfs_init_compress(void);
+void btrfs_init_compress(void);
 void btrfs_exit_compress(void);
 
 int btrfs_compress_pages(int type, struct address_space *mapping,
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 0639a55..e801f22 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -36,7 +36,7 @@
 			      struct btrfs_root *root,
 			      struct extent_buffer *dst_buf,
 			      struct extent_buffer *src_buf);
-static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		   struct btrfs_path *path, int level, int slot);
 
 struct btrfs_path *btrfs_alloc_path(void)
@@ -156,10 +156,23 @@
 {
 	struct extent_buffer *eb;
 
-	rcu_read_lock();
-	eb = rcu_dereference(root->node);
-	extent_buffer_get(eb);
-	rcu_read_unlock();
+	while (1) {
+		rcu_read_lock();
+		eb = rcu_dereference(root->node);
+
+		/*
+		 * RCU really hurts here, we could free up the root node because
+		 * it was cow'ed but we may not get the new root node yet so do
+		 * the inc_not_zero dance and if it doesn't work then
+		 * synchronize_rcu and try again.
+		 */
+		if (atomic_inc_not_zero(&eb->refs)) {
+			rcu_read_unlock();
+			break;
+		}
+		rcu_read_unlock();
+		synchronize_rcu();
+	}
 	return eb;
 }
 
@@ -331,8 +344,13 @@
 	if (btrfs_block_can_be_shared(root, buf)) {
 		ret = btrfs_lookup_extent_info(trans, root, buf->start,
 					       buf->len, &refs, &flags);
-		BUG_ON(ret);
-		BUG_ON(refs == 0);
+		if (ret)
+			return ret;
+		if (refs == 0) {
+			ret = -EROFS;
+			btrfs_std_error(root->fs_info, ret);
+			return ret;
+		}
 	} else {
 		refs = 1;
 		if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID ||
@@ -351,14 +369,14 @@
 		     root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) &&
 		    !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) {
 			ret = btrfs_inc_ref(trans, root, buf, 1, 1);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM */
 
 			if (root->root_key.objectid ==
 			    BTRFS_TREE_RELOC_OBJECTID) {
 				ret = btrfs_dec_ref(trans, root, buf, 0, 1);
-				BUG_ON(ret);
+				BUG_ON(ret); /* -ENOMEM */
 				ret = btrfs_inc_ref(trans, root, cow, 1, 1);
-				BUG_ON(ret);
+				BUG_ON(ret); /* -ENOMEM */
 			}
 			new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
 		} else {
@@ -368,14 +386,15 @@
 				ret = btrfs_inc_ref(trans, root, cow, 1, 1);
 			else
 				ret = btrfs_inc_ref(trans, root, cow, 0, 1);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM */
 		}
 		if (new_flags != 0) {
 			ret = btrfs_set_disk_extent_flags(trans, root,
 							  buf->start,
 							  buf->len,
 							  new_flags, 0);
-			BUG_ON(ret);
+			if (ret)
+				return ret;
 		}
 	} else {
 		if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
@@ -384,9 +403,9 @@
 				ret = btrfs_inc_ref(trans, root, cow, 1, 1);
 			else
 				ret = btrfs_inc_ref(trans, root, cow, 0, 1);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM */
 			ret = btrfs_dec_ref(trans, root, buf, 1, 1);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM */
 		}
 		clean_tree_block(trans, root, buf);
 		*last_ref = 1;
@@ -415,7 +434,7 @@
 {
 	struct btrfs_disk_key disk_key;
 	struct extent_buffer *cow;
-	int level;
+	int level, ret;
 	int last_ref = 0;
 	int unlock_orig = 0;
 	u64 parent_start;
@@ -467,7 +486,11 @@
 			    (unsigned long)btrfs_header_fsid(cow),
 			    BTRFS_FSID_SIZE);
 
-	update_ref_for_cow(trans, root, buf, cow, &last_ref);
+	ret = update_ref_for_cow(trans, root, buf, cow, &last_ref);
+	if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
+		return ret;
+	}
 
 	if (root->ref_cows)
 		btrfs_reloc_cow_block(trans, root, buf, cow);
@@ -504,7 +527,7 @@
 	}
 	if (unlock_orig)
 		btrfs_tree_unlock(buf);
-	free_extent_buffer(buf);
+	free_extent_buffer_stale(buf);
 	btrfs_mark_buffer_dirty(cow);
 	*cow_ret = cow;
 	return 0;
@@ -934,7 +957,12 @@
 
 		/* promote the child to a root */
 		child = read_node_slot(root, mid, 0);
-		BUG_ON(!child);
+		if (!child) {
+			ret = -EROFS;
+			btrfs_std_error(root->fs_info, ret);
+			goto enospc;
+		}
+
 		btrfs_tree_lock(child);
 		btrfs_set_lock_blocking(child);
 		ret = btrfs_cow_block(trans, root, child, mid, 0, &child);
@@ -959,7 +987,7 @@
 		root_sub_used(root, mid->len);
 		btrfs_free_tree_block(trans, root, mid, 0, 1, 0);
 		/* once for the root ptr */
-		free_extent_buffer(mid);
+		free_extent_buffer_stale(mid);
 		return 0;
 	}
 	if (btrfs_header_nritems(mid) >
@@ -1010,13 +1038,10 @@
 		if (btrfs_header_nritems(right) == 0) {
 			clean_tree_block(trans, root, right);
 			btrfs_tree_unlock(right);
-			wret = del_ptr(trans, root, path, level + 1, pslot +
-				       1);
-			if (wret)
-				ret = wret;
+			del_ptr(trans, root, path, level + 1, pslot + 1);
 			root_sub_used(root, right->len);
 			btrfs_free_tree_block(trans, root, right, 0, 1, 0);
-			free_extent_buffer(right);
+			free_extent_buffer_stale(right);
 			right = NULL;
 		} else {
 			struct btrfs_disk_key right_key;
@@ -1035,7 +1060,11 @@
 		 * otherwise we would have pulled some pointers from the
 		 * right
 		 */
-		BUG_ON(!left);
+		if (!left) {
+			ret = -EROFS;
+			btrfs_std_error(root->fs_info, ret);
+			goto enospc;
+		}
 		wret = balance_node_right(trans, root, mid, left);
 		if (wret < 0) {
 			ret = wret;
@@ -1051,12 +1080,10 @@
 	if (btrfs_header_nritems(mid) == 0) {
 		clean_tree_block(trans, root, mid);
 		btrfs_tree_unlock(mid);
-		wret = del_ptr(trans, root, path, level + 1, pslot);
-		if (wret)
-			ret = wret;
+		del_ptr(trans, root, path, level + 1, pslot);
 		root_sub_used(root, mid->len);
 		btrfs_free_tree_block(trans, root, mid, 0, 1, 0);
-		free_extent_buffer(mid);
+		free_extent_buffer_stale(mid);
 		mid = NULL;
 	} else {
 		/* update the parent key to reflect our changes */
@@ -1382,7 +1409,8 @@
  * if lowest_unlock is 1, level 0 won't be unlocked
  */
 static noinline void unlock_up(struct btrfs_path *path, int level,
-			       int lowest_unlock)
+			       int lowest_unlock, int min_write_lock_level,
+			       int *write_lock_level)
 {
 	int i;
 	int skip_level = level;
@@ -1414,6 +1442,11 @@
 		if (i >= lowest_unlock && i > skip_level && path->locks[i]) {
 			btrfs_tree_unlock_rw(t, path->locks[i]);
 			path->locks[i] = 0;
+			if (write_lock_level &&
+			    i > min_write_lock_level &&
+			    i <= *write_lock_level) {
+				*write_lock_level = i - 1;
+			}
 		}
 	}
 }
@@ -1637,6 +1670,7 @@
 	/* everything at write_lock_level or lower must be write locked */
 	int write_lock_level = 0;
 	u8 lowest_level = 0;
+	int min_write_lock_level;
 
 	lowest_level = p->lowest_level;
 	WARN_ON(lowest_level && ins_len > 0);
@@ -1664,6 +1698,8 @@
 	if (cow && (p->keep_locks || p->lowest_level))
 		write_lock_level = BTRFS_MAX_LEVEL;
 
+	min_write_lock_level = write_lock_level;
+
 again:
 	/*
 	 * we try very hard to do read locks on the root
@@ -1795,7 +1831,8 @@
 				goto again;
 			}
 
-			unlock_up(p, level, lowest_unlock);
+			unlock_up(p, level, lowest_unlock,
+				  min_write_lock_level, &write_lock_level);
 
 			if (level == lowest_level) {
 				if (dec)
@@ -1857,7 +1894,8 @@
 				}
 			}
 			if (!p->search_for_split)
-				unlock_up(p, level, lowest_unlock);
+				unlock_up(p, level, lowest_unlock,
+					  min_write_lock_level, &write_lock_level);
 			goto done;
 		}
 	}
@@ -1881,15 +1919,12 @@
  * fixing up pointers when a given leaf/node is not in slot 0 of the
  * higher levels
  *
- * If this fails to write a tree block, it returns -1, but continues
- * fixing up the blocks in ram so the tree is consistent.
  */
-static int fixup_low_keys(struct btrfs_trans_handle *trans,
-			  struct btrfs_root *root, struct btrfs_path *path,
-			  struct btrfs_disk_key *key, int level)
+static void fixup_low_keys(struct btrfs_trans_handle *trans,
+			   struct btrfs_root *root, struct btrfs_path *path,
+			   struct btrfs_disk_key *key, int level)
 {
 	int i;
-	int ret = 0;
 	struct extent_buffer *t;
 
 	for (i = level; i < BTRFS_MAX_LEVEL; i++) {
@@ -1902,7 +1937,6 @@
 		if (tslot != 0)
 			break;
 	}
-	return ret;
 }
 
 /*
@@ -1911,9 +1945,9 @@
  * This function isn't completely safe. It's the caller's responsibility
  * that the new key won't break the order
  */
-int btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
-			    struct btrfs_root *root, struct btrfs_path *path,
-			    struct btrfs_key *new_key)
+void btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
+			     struct btrfs_root *root, struct btrfs_path *path,
+			     struct btrfs_key *new_key)
 {
 	struct btrfs_disk_key disk_key;
 	struct extent_buffer *eb;
@@ -1923,13 +1957,11 @@
 	slot = path->slots[0];
 	if (slot > 0) {
 		btrfs_item_key(eb, &disk_key, slot - 1);
-		if (comp_keys(&disk_key, new_key) >= 0)
-			return -1;
+		BUG_ON(comp_keys(&disk_key, new_key) >= 0);
 	}
 	if (slot < btrfs_header_nritems(eb) - 1) {
 		btrfs_item_key(eb, &disk_key, slot + 1);
-		if (comp_keys(&disk_key, new_key) <= 0)
-			return -1;
+		BUG_ON(comp_keys(&disk_key, new_key) <= 0);
 	}
 
 	btrfs_cpu_key_to_disk(&disk_key, new_key);
@@ -1937,7 +1969,6 @@
 	btrfs_mark_buffer_dirty(eb);
 	if (slot == 0)
 		fixup_low_keys(trans, root, path, &disk_key, 1);
-	return 0;
 }
 
 /*
@@ -2140,12 +2171,11 @@
  *
  * slot and level indicate where you want the key to go, and
  * blocknr is the block the key points to.
- *
- * returns zero on success and < 0 on any error
  */
-static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root
-		      *root, struct btrfs_path *path, struct btrfs_disk_key
-		      *key, u64 bytenr, int slot, int level)
+static void insert_ptr(struct btrfs_trans_handle *trans,
+		       struct btrfs_root *root, struct btrfs_path *path,
+		       struct btrfs_disk_key *key, u64 bytenr,
+		       int slot, int level)
 {
 	struct extent_buffer *lower;
 	int nritems;
@@ -2155,8 +2185,7 @@
 	lower = path->nodes[level];
 	nritems = btrfs_header_nritems(lower);
 	BUG_ON(slot > nritems);
-	if (nritems == BTRFS_NODEPTRS_PER_BLOCK(root))
-		BUG();
+	BUG_ON(nritems == BTRFS_NODEPTRS_PER_BLOCK(root));
 	if (slot != nritems) {
 		memmove_extent_buffer(lower,
 			      btrfs_node_key_ptr_offset(slot + 1),
@@ -2169,7 +2198,6 @@
 	btrfs_set_node_ptr_generation(lower, slot, trans->transid);
 	btrfs_set_header_nritems(lower, nritems + 1);
 	btrfs_mark_buffer_dirty(lower);
-	return 0;
 }
 
 /*
@@ -2190,7 +2218,6 @@
 	struct btrfs_disk_key disk_key;
 	int mid;
 	int ret;
-	int wret;
 	u32 c_nritems;
 
 	c = path->nodes[level];
@@ -2247,11 +2274,8 @@
 	btrfs_mark_buffer_dirty(c);
 	btrfs_mark_buffer_dirty(split);
 
-	wret = insert_ptr(trans, root, path, &disk_key, split->start,
-			  path->slots[level + 1] + 1,
-			  level + 1);
-	if (wret)
-		ret = wret;
+	insert_ptr(trans, root, path, &disk_key, split->start,
+		   path->slots[level + 1] + 1, level + 1);
 
 	if (path->slots[level] >= mid) {
 		path->slots[level] -= mid;
@@ -2320,6 +2344,7 @@
 {
 	struct extent_buffer *left = path->nodes[0];
 	struct extent_buffer *upper = path->nodes[1];
+	struct btrfs_map_token token;
 	struct btrfs_disk_key disk_key;
 	int slot;
 	u32 i;
@@ -2331,6 +2356,8 @@
 	u32 data_end;
 	u32 this_item_size;
 
+	btrfs_init_map_token(&token);
+
 	if (empty)
 		nr = 0;
 	else
@@ -2408,8 +2435,8 @@
 	push_space = BTRFS_LEAF_DATA_SIZE(root);
 	for (i = 0; i < right_nritems; i++) {
 		item = btrfs_item_nr(right, i);
-		push_space -= btrfs_item_size(right, item);
-		btrfs_set_item_offset(right, item, push_space);
+		push_space -= btrfs_token_item_size(right, item, &token);
+		btrfs_set_token_item_offset(right, item, push_space, &token);
 	}
 
 	left_nritems -= push_items;
@@ -2537,9 +2564,11 @@
 	u32 old_left_nritems;
 	u32 nr;
 	int ret = 0;
-	int wret;
 	u32 this_item_size;
 	u32 old_left_item_size;
+	struct btrfs_map_token token;
+
+	btrfs_init_map_token(&token);
 
 	if (empty)
 		nr = min(right_nritems, max_slot);
@@ -2600,9 +2629,10 @@
 
 		item = btrfs_item_nr(left, i);
 
-		ioff = btrfs_item_offset(left, item);
-		btrfs_set_item_offset(left, item,
-		      ioff - (BTRFS_LEAF_DATA_SIZE(root) - old_left_item_size));
+		ioff = btrfs_token_item_offset(left, item, &token);
+		btrfs_set_token_item_offset(left, item,
+		      ioff - (BTRFS_LEAF_DATA_SIZE(root) - old_left_item_size),
+		      &token);
 	}
 	btrfs_set_header_nritems(left, old_left_nritems + push_items);
 
@@ -2632,8 +2662,9 @@
 	for (i = 0; i < right_nritems; i++) {
 		item = btrfs_item_nr(right, i);
 
-		push_space = push_space - btrfs_item_size(right, item);
-		btrfs_set_item_offset(right, item, push_space);
+		push_space = push_space - btrfs_token_item_size(right,
+								item, &token);
+		btrfs_set_token_item_offset(right, item, push_space, &token);
 	}
 
 	btrfs_mark_buffer_dirty(left);
@@ -2643,9 +2674,7 @@
 		clean_tree_block(trans, root, right);
 
 	btrfs_item_key(right, &disk_key, 0);
-	wret = fixup_low_keys(trans, root, path, &disk_key, 1);
-	if (wret)
-		ret = wret;
+	fixup_low_keys(trans, root, path, &disk_key, 1);
 
 	/* then fixup the leaf pointer in the path */
 	if (path->slots[0] < push_items) {
@@ -2716,7 +2745,8 @@
 			      path->nodes[1], slot - 1, &left);
 	if (ret) {
 		/* we hit -ENOSPC, but it isn't fatal here */
-		ret = 1;
+		if (ret == -ENOSPC)
+			ret = 1;
 		goto out;
 	}
 
@@ -2738,22 +2768,21 @@
 /*
  * split the path's leaf in two, making sure there is at least data_size
  * available for the resulting leaf level of the path.
- *
- * returns 0 if all went well and < 0 on failure.
  */
-static noinline int copy_for_split(struct btrfs_trans_handle *trans,
-			       struct btrfs_root *root,
-			       struct btrfs_path *path,
-			       struct extent_buffer *l,
-			       struct extent_buffer *right,
-			       int slot, int mid, int nritems)
+static noinline void copy_for_split(struct btrfs_trans_handle *trans,
+				    struct btrfs_root *root,
+				    struct btrfs_path *path,
+				    struct extent_buffer *l,
+				    struct extent_buffer *right,
+				    int slot, int mid, int nritems)
 {
 	int data_copy_size;
 	int rt_data_off;
 	int i;
-	int ret = 0;
-	int wret;
 	struct btrfs_disk_key disk_key;
+	struct btrfs_map_token token;
+
+	btrfs_init_map_token(&token);
 
 	nritems = nritems - mid;
 	btrfs_set_header_nritems(right, nritems);
@@ -2775,17 +2804,15 @@
 		struct btrfs_item *item = btrfs_item_nr(right, i);
 		u32 ioff;
 
-		ioff = btrfs_item_offset(right, item);
-		btrfs_set_item_offset(right, item, ioff + rt_data_off);
+		ioff = btrfs_token_item_offset(right, item, &token);
+		btrfs_set_token_item_offset(right, item,
+					    ioff + rt_data_off, &token);
 	}
 
 	btrfs_set_header_nritems(l, mid);
-	ret = 0;
 	btrfs_item_key(right, &disk_key, 0);
-	wret = insert_ptr(trans, root, path, &disk_key, right->start,
-			  path->slots[1] + 1, 1);
-	if (wret)
-		ret = wret;
+	insert_ptr(trans, root, path, &disk_key, right->start,
+		   path->slots[1] + 1, 1);
 
 	btrfs_mark_buffer_dirty(right);
 	btrfs_mark_buffer_dirty(l);
@@ -2803,8 +2830,6 @@
 	}
 
 	BUG_ON(path->slots[0] < 0);
-
-	return ret;
 }
 
 /*
@@ -2993,12 +3018,8 @@
 	if (split == 0) {
 		if (mid <= slot) {
 			btrfs_set_header_nritems(right, 0);
-			wret = insert_ptr(trans, root, path,
-					  &disk_key, right->start,
-					  path->slots[1] + 1, 1);
-			if (wret)
-				ret = wret;
-
+			insert_ptr(trans, root, path, &disk_key, right->start,
+				   path->slots[1] + 1, 1);
 			btrfs_tree_unlock(path->nodes[0]);
 			free_extent_buffer(path->nodes[0]);
 			path->nodes[0] = right;
@@ -3006,29 +3027,21 @@
 			path->slots[1] += 1;
 		} else {
 			btrfs_set_header_nritems(right, 0);
-			wret = insert_ptr(trans, root, path,
-					  &disk_key,
-					  right->start,
+			insert_ptr(trans, root, path, &disk_key, right->start,
 					  path->slots[1], 1);
-			if (wret)
-				ret = wret;
 			btrfs_tree_unlock(path->nodes[0]);
 			free_extent_buffer(path->nodes[0]);
 			path->nodes[0] = right;
 			path->slots[0] = 0;
-			if (path->slots[1] == 0) {
-				wret = fixup_low_keys(trans, root,
-						path, &disk_key, 1);
-				if (wret)
-					ret = wret;
-			}
+			if (path->slots[1] == 0)
+				fixup_low_keys(trans, root, path,
+					       &disk_key, 1);
 		}
 		btrfs_mark_buffer_dirty(right);
 		return ret;
 	}
 
-	ret = copy_for_split(trans, root, path, l, right, slot, mid, nritems);
-	BUG_ON(ret);
+	copy_for_split(trans, root, path, l, right, slot, mid, nritems);
 
 	if (split == 2) {
 		BUG_ON(num_doubles != 0);
@@ -3036,7 +3049,7 @@
 		goto again;
 	}
 
-	return ret;
+	return 0;
 
 push_for_double:
 	push_for_double_split(trans, root, path, data_size);
@@ -3238,11 +3251,9 @@
 		return ret;
 
 	path->slots[0]++;
-	ret = setup_items_for_insert(trans, root, path, new_key, &item_size,
-				     item_size, item_size +
-				     sizeof(struct btrfs_item), 1);
-	BUG_ON(ret);
-
+	setup_items_for_insert(trans, root, path, new_key, &item_size,
+			       item_size, item_size +
+			       sizeof(struct btrfs_item), 1);
 	leaf = path->nodes[0];
 	memcpy_extent_buffer(leaf,
 			     btrfs_item_ptr_offset(leaf, path->slots[0]),
@@ -3257,10 +3268,10 @@
  * off the end of the item or if we shift the item to chop bytes off
  * the front.
  */
-int btrfs_truncate_item(struct btrfs_trans_handle *trans,
-			struct btrfs_root *root,
-			struct btrfs_path *path,
-			u32 new_size, int from_end)
+void btrfs_truncate_item(struct btrfs_trans_handle *trans,
+			 struct btrfs_root *root,
+			 struct btrfs_path *path,
+			 u32 new_size, int from_end)
 {
 	int slot;
 	struct extent_buffer *leaf;
@@ -3271,13 +3282,16 @@
 	unsigned int old_size;
 	unsigned int size_diff;
 	int i;
+	struct btrfs_map_token token;
+
+	btrfs_init_map_token(&token);
 
 	leaf = path->nodes[0];
 	slot = path->slots[0];
 
 	old_size = btrfs_item_size_nr(leaf, slot);
 	if (old_size == new_size)
-		return 0;
+		return;
 
 	nritems = btrfs_header_nritems(leaf);
 	data_end = leaf_data_end(root, leaf);
@@ -3297,8 +3311,9 @@
 		u32 ioff;
 		item = btrfs_item_nr(leaf, i);
 
-		ioff = btrfs_item_offset(leaf, item);
-		btrfs_set_item_offset(leaf, item, ioff + size_diff);
+		ioff = btrfs_token_item_offset(leaf, item, &token);
+		btrfs_set_token_item_offset(leaf, item,
+					    ioff + size_diff, &token);
 	}
 
 	/* shift the data */
@@ -3350,15 +3365,14 @@
 		btrfs_print_leaf(root, leaf);
 		BUG();
 	}
-	return 0;
 }
 
 /*
  * make the item pointed to by the path bigger, data_size is the new size.
  */
-int btrfs_extend_item(struct btrfs_trans_handle *trans,
-		      struct btrfs_root *root, struct btrfs_path *path,
-		      u32 data_size)
+void btrfs_extend_item(struct btrfs_trans_handle *trans,
+		       struct btrfs_root *root, struct btrfs_path *path,
+		       u32 data_size)
 {
 	int slot;
 	struct extent_buffer *leaf;
@@ -3368,6 +3382,9 @@
 	unsigned int old_data;
 	unsigned int old_size;
 	int i;
+	struct btrfs_map_token token;
+
+	btrfs_init_map_token(&token);
 
 	leaf = path->nodes[0];
 
@@ -3397,8 +3414,9 @@
 		u32 ioff;
 		item = btrfs_item_nr(leaf, i);
 
-		ioff = btrfs_item_offset(leaf, item);
-		btrfs_set_item_offset(leaf, item, ioff - data_size);
+		ioff = btrfs_token_item_offset(leaf, item, &token);
+		btrfs_set_token_item_offset(leaf, item,
+					    ioff - data_size, &token);
 	}
 
 	/* shift the data */
@@ -3416,7 +3434,6 @@
 		btrfs_print_leaf(root, leaf);
 		BUG();
 	}
-	return 0;
 }
 
 /*
@@ -3441,6 +3458,9 @@
 	unsigned int data_end;
 	struct btrfs_disk_key disk_key;
 	struct btrfs_key found_key;
+	struct btrfs_map_token token;
+
+	btrfs_init_map_token(&token);
 
 	for (i = 0; i < nr; i++) {
 		if (total_size + data_size[i] + sizeof(struct btrfs_item) >
@@ -3506,8 +3526,9 @@
 			u32 ioff;
 
 			item = btrfs_item_nr(leaf, i);
-			ioff = btrfs_item_offset(leaf, item);
-			btrfs_set_item_offset(leaf, item, ioff - total_data);
+			ioff = btrfs_token_item_offset(leaf, item, &token);
+			btrfs_set_token_item_offset(leaf, item,
+						    ioff - total_data, &token);
 		}
 		/* shift the items */
 		memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + nr),
@@ -3534,9 +3555,10 @@
 		btrfs_cpu_key_to_disk(&disk_key, cpu_key + i);
 		btrfs_set_item_key(leaf, &disk_key, slot + i);
 		item = btrfs_item_nr(leaf, slot + i);
-		btrfs_set_item_offset(leaf, item, data_end - data_size[i]);
+		btrfs_set_token_item_offset(leaf, item,
+					    data_end - data_size[i], &token);
 		data_end -= data_size[i];
-		btrfs_set_item_size(leaf, item, data_size[i]);
+		btrfs_set_token_item_size(leaf, item, data_size[i], &token);
 	}
 	btrfs_set_header_nritems(leaf, nritems + nr);
 	btrfs_mark_buffer_dirty(leaf);
@@ -3544,7 +3566,7 @@
 	ret = 0;
 	if (slot == 0) {
 		btrfs_cpu_key_to_disk(&disk_key, cpu_key);
-		ret = fixup_low_keys(trans, root, path, &disk_key, 1);
+		fixup_low_keys(trans, root, path, &disk_key, 1);
 	}
 
 	if (btrfs_leaf_free_space(root, leaf) < 0) {
@@ -3562,19 +3584,21 @@
  * to save stack depth by doing the bulk of the work in a function
  * that doesn't call btrfs_search_slot
  */
-int setup_items_for_insert(struct btrfs_trans_handle *trans,
-			   struct btrfs_root *root, struct btrfs_path *path,
-			   struct btrfs_key *cpu_key, u32 *data_size,
-			   u32 total_data, u32 total_size, int nr)
+void setup_items_for_insert(struct btrfs_trans_handle *trans,
+			    struct btrfs_root *root, struct btrfs_path *path,
+			    struct btrfs_key *cpu_key, u32 *data_size,
+			    u32 total_data, u32 total_size, int nr)
 {
 	struct btrfs_item *item;
 	int i;
 	u32 nritems;
 	unsigned int data_end;
 	struct btrfs_disk_key disk_key;
-	int ret;
 	struct extent_buffer *leaf;
 	int slot;
+	struct btrfs_map_token token;
+
+	btrfs_init_map_token(&token);
 
 	leaf = path->nodes[0];
 	slot = path->slots[0];
@@ -3606,8 +3630,9 @@
 			u32 ioff;
 
 			item = btrfs_item_nr(leaf, i);
-			ioff = btrfs_item_offset(leaf, item);
-			btrfs_set_item_offset(leaf, item, ioff - total_data);
+			ioff = btrfs_token_item_offset(leaf, item, &token);
+			btrfs_set_token_item_offset(leaf, item,
+						    ioff - total_data, &token);
 		}
 		/* shift the items */
 		memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + nr),
@@ -3626,17 +3651,17 @@
 		btrfs_cpu_key_to_disk(&disk_key, cpu_key + i);
 		btrfs_set_item_key(leaf, &disk_key, slot + i);
 		item = btrfs_item_nr(leaf, slot + i);
-		btrfs_set_item_offset(leaf, item, data_end - data_size[i]);
+		btrfs_set_token_item_offset(leaf, item,
+					    data_end - data_size[i], &token);
 		data_end -= data_size[i];
-		btrfs_set_item_size(leaf, item, data_size[i]);
+		btrfs_set_token_item_size(leaf, item, data_size[i], &token);
 	}
 
 	btrfs_set_header_nritems(leaf, nritems + nr);
 
-	ret = 0;
 	if (slot == 0) {
 		btrfs_cpu_key_to_disk(&disk_key, cpu_key);
-		ret = fixup_low_keys(trans, root, path, &disk_key, 1);
+		fixup_low_keys(trans, root, path, &disk_key, 1);
 	}
 	btrfs_unlock_up_safe(path, 1);
 	btrfs_mark_buffer_dirty(leaf);
@@ -3645,7 +3670,6 @@
 		btrfs_print_leaf(root, leaf);
 		BUG();
 	}
-	return ret;
 }
 
 /*
@@ -3672,16 +3696,14 @@
 	if (ret == 0)
 		return -EEXIST;
 	if (ret < 0)
-		goto out;
+		return ret;
 
 	slot = path->slots[0];
 	BUG_ON(slot < 0);
 
-	ret = setup_items_for_insert(trans, root, path, cpu_key, data_size,
+	setup_items_for_insert(trans, root, path, cpu_key, data_size,
 			       total_data, total_size, nr);
-
-out:
-	return ret;
+	return 0;
 }
 
 /*
@@ -3717,13 +3739,11 @@
  * the tree should have been previously balanced so the deletion does not
  * empty a node.
  */
-static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-		   struct btrfs_path *path, int level, int slot)
+static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+		    struct btrfs_path *path, int level, int slot)
 {
 	struct extent_buffer *parent = path->nodes[level];
 	u32 nritems;
-	int ret = 0;
-	int wret;
 
 	nritems = btrfs_header_nritems(parent);
 	if (slot != nritems - 1) {
@@ -3743,12 +3763,9 @@
 		struct btrfs_disk_key disk_key;
 
 		btrfs_node_key(parent, &disk_key, 0);
-		wret = fixup_low_keys(trans, root, path, &disk_key, level + 1);
-		if (wret)
-			ret = wret;
+		fixup_low_keys(trans, root, path, &disk_key, level + 1);
 	}
 	btrfs_mark_buffer_dirty(parent);
-	return ret;
 }
 
 /*
@@ -3761,17 +3778,13 @@
  * The path must have already been setup for deleting the leaf, including
  * all the proper balancing.  path->nodes[1] must be locked.
  */
-static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans,
-				   struct btrfs_root *root,
-				   struct btrfs_path *path,
-				   struct extent_buffer *leaf)
+static noinline void btrfs_del_leaf(struct btrfs_trans_handle *trans,
+				    struct btrfs_root *root,
+				    struct btrfs_path *path,
+				    struct extent_buffer *leaf)
 {
-	int ret;
-
 	WARN_ON(btrfs_header_generation(leaf) != trans->transid);
-	ret = del_ptr(trans, root, path, 1, path->slots[1]);
-	if (ret)
-		return ret;
+	del_ptr(trans, root, path, 1, path->slots[1]);
 
 	/*
 	 * btrfs_free_extent is expensive, we want to make sure we
@@ -3781,8 +3794,9 @@
 
 	root_sub_used(root, leaf->len);
 
+	extent_buffer_get(leaf);
 	btrfs_free_tree_block(trans, root, leaf, 0, 1, 0);
-	return 0;
+	free_extent_buffer_stale(leaf);
 }
 /*
  * delete the item at the leaf level in path.  If that empties
@@ -3799,6 +3813,9 @@
 	int wret;
 	int i;
 	u32 nritems;
+	struct btrfs_map_token token;
+
+	btrfs_init_map_token(&token);
 
 	leaf = path->nodes[0];
 	last_off = btrfs_item_offset_nr(leaf, slot + nr - 1);
@@ -3820,8 +3837,9 @@
 			u32 ioff;
 
 			item = btrfs_item_nr(leaf, i);
-			ioff = btrfs_item_offset(leaf, item);
-			btrfs_set_item_offset(leaf, item, ioff + dsize);
+			ioff = btrfs_token_item_offset(leaf, item, &token);
+			btrfs_set_token_item_offset(leaf, item,
+						    ioff + dsize, &token);
 		}
 
 		memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot),
@@ -3839,8 +3857,7 @@
 		} else {
 			btrfs_set_path_blocking(path);
 			clean_tree_block(trans, root, leaf);
-			ret = btrfs_del_leaf(trans, root, path, leaf);
-			BUG_ON(ret);
+			btrfs_del_leaf(trans, root, path, leaf);
 		}
 	} else {
 		int used = leaf_space_used(leaf, 0, nritems);
@@ -3848,10 +3865,7 @@
 			struct btrfs_disk_key disk_key;
 
 			btrfs_item_key(leaf, &disk_key, 0);
-			wret = fixup_low_keys(trans, root, path,
-					      &disk_key, 1);
-			if (wret)
-				ret = wret;
+			fixup_low_keys(trans, root, path, &disk_key, 1);
 		}
 
 		/* delete the leaf if it is mostly empty */
@@ -3879,9 +3893,9 @@
 
 			if (btrfs_header_nritems(leaf) == 0) {
 				path->slots[1] = slot;
-				ret = btrfs_del_leaf(trans, root, path, leaf);
-				BUG_ON(ret);
+				btrfs_del_leaf(trans, root, path, leaf);
 				free_extent_buffer(leaf);
+				ret = 0;
 			} else {
 				/* if we're still in the path, make sure
 				 * we're dirty.  Otherwise, one of the
@@ -4059,18 +4073,18 @@
 		path->slots[level] = slot;
 		if (level == path->lowest_level) {
 			ret = 0;
-			unlock_up(path, level, 1);
+			unlock_up(path, level, 1, 0, NULL);
 			goto out;
 		}
 		btrfs_set_path_blocking(path);
 		cur = read_node_slot(root, cur, slot);
-		BUG_ON(!cur);
+		BUG_ON(!cur); /* -ENOMEM */
 
 		btrfs_tree_read_lock(cur);
 
 		path->locks[level - 1] = BTRFS_READ_LOCK;
 		path->nodes[level - 1] = cur;
-		unlock_up(path, level, 1);
+		unlock_up(path, level, 1, 0, NULL);
 		btrfs_clear_path_blocking(path, NULL, 0);
 	}
 out:
@@ -4306,7 +4320,7 @@
 	}
 	ret = 0;
 done:
-	unlock_up(path, 0, 1);
+	unlock_up(path, 0, 1, 0, NULL);
 	path->leave_spinning = old_spinning;
 	if (!old_spinning)
 		btrfs_set_path_blocking(path);
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 80b6486..5b8ef8e 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -48,6 +48,8 @@
 
 #define BTRFS_MAGIC "_BHRfS_M"
 
+#define BTRFS_MAX_MIRRORS 2
+
 #define BTRFS_MAX_LEVEL 8
 
 #define BTRFS_COMPAT_EXTENT_TREE_V0
@@ -138,6 +140,12 @@
 #define BTRFS_EMPTY_SUBVOL_DIR_OBJECTID 2
 
 /*
+ * the max metadata block size.  This limit is somewhat artificial,
+ * but the memmove costs go through the roof for larger blocks.
+ */
+#define BTRFS_MAX_METADATA_BLOCKSIZE 65536
+
+/*
  * we can actually store much bigger names, but lets not confuse the rest
  * of linux
  */
@@ -461,6 +469,19 @@
 #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL	(1ULL << 1)
 #define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS	(1ULL << 2)
 #define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO	(1ULL << 3)
+/*
+ * some patches floated around with a second compression method
+ * lets save that incompat here for when they do get in
+ * Note we don't actually support it, we're just reserving the
+ * number
+ */
+#define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZOv2	(1ULL << 4)
+
+/*
+ * older kernels tried to do bigger metadata blocks, but the
+ * code was pretty buggy.  Lets not let them try anymore.
+ */
+#define BTRFS_FEATURE_INCOMPAT_BIG_METADATA	(1ULL << 5)
 
 #define BTRFS_FEATURE_COMPAT_SUPP		0ULL
 #define BTRFS_FEATURE_COMPAT_RO_SUPP		0ULL
@@ -468,6 +489,7 @@
 	(BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF |		\
 	 BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL |	\
 	 BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS |		\
+	 BTRFS_FEATURE_INCOMPAT_BIG_METADATA |		\
 	 BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO)
 
 /*
@@ -829,6 +851,21 @@
  */
 #define BTRFS_AVAIL_ALLOC_BIT_SINGLE	(1ULL << 48)
 
+#define BTRFS_EXTENDED_PROFILE_MASK	(BTRFS_BLOCK_GROUP_PROFILE_MASK | \
+					 BTRFS_AVAIL_ALLOC_BIT_SINGLE)
+
+static inline u64 chunk_to_extended(u64 flags)
+{
+	if ((flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0)
+		flags |= BTRFS_AVAIL_ALLOC_BIT_SINGLE;
+
+	return flags;
+}
+static inline u64 extended_to_chunk(u64 flags)
+{
+	return flags & ~BTRFS_AVAIL_ALLOC_BIT_SINGLE;
+}
+
 struct btrfs_block_group_item {
 	__le64 used;
 	__le64 chunk_objectid;
@@ -1503,6 +1540,7 @@
 #define BTRFS_MOUNT_SKIP_BALANCE	(1 << 19)
 #define BTRFS_MOUNT_CHECK_INTEGRITY	(1 << 20)
 #define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21)
+#define BTRFS_MOUNT_PANIC_ON_FATAL_ERROR	(1 << 22)
 
 #define btrfs_clear_opt(o, opt)		((o) &= ~BTRFS_MOUNT_##opt)
 #define btrfs_set_opt(o, opt)		((o) |= BTRFS_MOUNT_##opt)
@@ -1526,6 +1564,17 @@
 
 #define BTRFS_INODE_ROOT_ITEM_INIT	(1 << 31)
 
+struct btrfs_map_token {
+	struct extent_buffer *eb;
+	char *kaddr;
+	unsigned long offset;
+};
+
+static inline void btrfs_init_map_token (struct btrfs_map_token *token)
+{
+	memset(token, 0, sizeof(*token));
+}
+
 /* some macros to generate set/get funcs for the struct fields.  This
  * assumes there is a lefoo_to_cpu for every type, so lets make a simple
  * one for u8:
@@ -1549,20 +1598,22 @@
 #ifndef BTRFS_SETGET_FUNCS
 #define BTRFS_SETGET_FUNCS(name, type, member, bits)			\
 u##bits btrfs_##name(struct extent_buffer *eb, type *s);		\
+u##bits btrfs_token_##name(struct extent_buffer *eb, type *s, struct btrfs_map_token *token);		\
+void btrfs_set_token_##name(struct extent_buffer *eb, type *s, u##bits val, struct btrfs_map_token *token);\
 void btrfs_set_##name(struct extent_buffer *eb, type *s, u##bits val);
 #endif
 
 #define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits)		\
 static inline u##bits btrfs_##name(struct extent_buffer *eb)		\
 {									\
-	type *p = page_address(eb->first_page);				\
+	type *p = page_address(eb->pages[0]);				\
 	u##bits res = le##bits##_to_cpu(p->member);			\
 	return res;							\
 }									\
 static inline void btrfs_set_##name(struct extent_buffer *eb,		\
 				    u##bits val)			\
 {									\
-	type *p = page_address(eb->first_page);				\
+	type *p = page_address(eb->pages[0]);				\
 	p->member = cpu_to_le##bits(val);				\
 }
 
@@ -2466,8 +2517,7 @@
 				  struct btrfs_root *root,
 				  u64 num_bytes, u64 min_alloc_size,
 				  u64 empty_size, u64 hint_byte,
-				  u64 search_end, struct btrfs_key *ins,
-				  u64 data);
+				  struct btrfs_key *ins, u64 data);
 int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		  struct extent_buffer *buf, int full_backref, int for_cow);
 int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
@@ -2484,8 +2534,8 @@
 int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len);
 int btrfs_free_and_pin_reserved_extent(struct btrfs_root *root,
 				       u64 start, u64 len);
-int btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans,
-				struct btrfs_root *root);
+void btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans,
+				 struct btrfs_root *root);
 int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
 			       struct btrfs_root *root);
 int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
@@ -2548,8 +2598,8 @@
 			     u64 num_bytes);
 int btrfs_set_block_group_ro(struct btrfs_root *root,
 			     struct btrfs_block_group_cache *cache);
-int btrfs_set_block_group_rw(struct btrfs_root *root,
-			     struct btrfs_block_group_cache *cache);
+void btrfs_set_block_group_rw(struct btrfs_root *root,
+			      struct btrfs_block_group_cache *cache);
 void btrfs_put_block_group_cache(struct btrfs_fs_info *info);
 u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo);
 int btrfs_error_unpin_extent_range(struct btrfs_root *root,
@@ -2568,9 +2618,9 @@
 int btrfs_previous_item(struct btrfs_root *root,
 			struct btrfs_path *path, u64 min_objectid,
 			int type);
-int btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
-			    struct btrfs_root *root, struct btrfs_path *path,
-			    struct btrfs_key *new_key);
+void btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
+			     struct btrfs_root *root, struct btrfs_path *path,
+			     struct btrfs_key *new_key);
 struct extent_buffer *btrfs_root_node(struct btrfs_root *root);
 struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root);
 int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
@@ -2590,12 +2640,13 @@
 		      struct extent_buffer **cow_ret, u64 new_root_objectid);
 int btrfs_block_can_be_shared(struct btrfs_root *root,
 			      struct extent_buffer *buf);
-int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root
-		      *root, struct btrfs_path *path, u32 data_size);
-int btrfs_truncate_item(struct btrfs_trans_handle *trans,
-			struct btrfs_root *root,
-			struct btrfs_path *path,
-			u32 new_size, int from_end);
+void btrfs_extend_item(struct btrfs_trans_handle *trans,
+		       struct btrfs_root *root, struct btrfs_path *path,
+		       u32 data_size);
+void btrfs_truncate_item(struct btrfs_trans_handle *trans,
+			 struct btrfs_root *root,
+			 struct btrfs_path *path,
+			 u32 new_size, int from_end);
 int btrfs_split_item(struct btrfs_trans_handle *trans,
 		     struct btrfs_root *root,
 		     struct btrfs_path *path,
@@ -2629,10 +2680,10 @@
 	return btrfs_del_items(trans, root, path, path->slots[0], 1);
 }
 
-int setup_items_for_insert(struct btrfs_trans_handle *trans,
-			   struct btrfs_root *root, struct btrfs_path *path,
-			   struct btrfs_key *cpu_key, u32 *data_size,
-			   u32 total_data, u32 total_size, int nr);
+void setup_items_for_insert(struct btrfs_trans_handle *trans,
+			    struct btrfs_root *root, struct btrfs_path *path,
+			    struct btrfs_key *cpu_key, u32 *data_size,
+			    u32 total_data, u32 total_size, int nr);
 int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
 		      *root, struct btrfs_key *key, void *data, u32 data_size);
 int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
@@ -2659,9 +2710,9 @@
 }
 int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
 int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
-void btrfs_drop_snapshot(struct btrfs_root *root,
-			 struct btrfs_block_rsv *block_rsv, int update_ref,
-			 int for_reloc);
+int __must_check btrfs_drop_snapshot(struct btrfs_root *root,
+				     struct btrfs_block_rsv *block_rsv,
+				     int update_ref, int for_reloc);
 int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
 			struct btrfs_root *root,
 			struct extent_buffer *node,
@@ -2687,24 +2738,6 @@
 	kfree(fs_info->super_for_commit);
 	kfree(fs_info);
 }
-/**
- * profile_is_valid - tests whether a given profile is valid and reduced
- * @flags: profile to validate
- * @extended: if true @flags is treated as an extended profile
- */
-static inline int profile_is_valid(u64 flags, int extended)
-{
-	u64 mask = ~BTRFS_BLOCK_GROUP_PROFILE_MASK;
-
-	flags &= ~BTRFS_BLOCK_GROUP_TYPE_MASK;
-	if (extended)
-		mask &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE;
-
-	if (flags & mask)
-		return 0;
-	/* true if zero or exactly one bit set */
-	return (flags & (~flags + 1)) == flags;
-}
 
 /* root-item.c */
 int btrfs_find_root_ref(struct btrfs_root *tree_root,
@@ -2723,9 +2756,10 @@
 int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
 		      *root, struct btrfs_key *key, struct btrfs_root_item
 		      *item);
-int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
-		      *root, struct btrfs_key *key, struct btrfs_root_item
-		      *item);
+int __must_check btrfs_update_root(struct btrfs_trans_handle *trans,
+				   struct btrfs_root *root,
+				   struct btrfs_key *key,
+				   struct btrfs_root_item *item);
 int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct
 			 btrfs_root_item *item, struct btrfs_key *key);
 int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid);
@@ -2909,7 +2943,7 @@
 void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans,
 			      struct btrfs_root *root);
 int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size);
-int btrfs_invalidate_inodes(struct btrfs_root *root);
+void btrfs_invalidate_inodes(struct btrfs_root *root);
 void btrfs_add_delayed_iput(struct inode *inode);
 void btrfs_run_delayed_iputs(struct btrfs_root *root);
 int btrfs_prealloc_file_range(struct inode *inode, int mode,
@@ -2961,13 +2995,41 @@
 /* super.c */
 int btrfs_parse_options(struct btrfs_root *root, char *options);
 int btrfs_sync_fs(struct super_block *sb, int wait);
+void btrfs_printk(struct btrfs_fs_info *fs_info, const char *fmt, ...);
 void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
-		     unsigned int line, int errno);
+		     unsigned int line, int errno, const char *fmt, ...);
+
+void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
+			       struct btrfs_root *root, const char *function,
+			       unsigned int line, int errno);
+
+#define btrfs_abort_transaction(trans, root, errno)		\
+do {								\
+	__btrfs_abort_transaction(trans, root, __func__,	\
+				  __LINE__, errno);		\
+} while (0)
 
 #define btrfs_std_error(fs_info, errno)				\
 do {								\
 	if ((errno))						\
-		__btrfs_std_error((fs_info), __func__, __LINE__, (errno));\
+		__btrfs_std_error((fs_info), __func__,		\
+				   __LINE__, (errno), NULL);	\
+} while (0)
+
+#define btrfs_error(fs_info, errno, fmt, args...)		\
+do {								\
+	__btrfs_std_error((fs_info), __func__, __LINE__,	\
+			  (errno), fmt, ##args);		\
+} while (0)
+
+void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function,
+		   unsigned int line, int errno, const char *fmt, ...);
+
+#define btrfs_panic(fs_info, errno, fmt, args...)			\
+do {									\
+	struct btrfs_fs_info *_i = (fs_info);				\
+	__btrfs_panic(_i, __func__, __LINE__, errno, fmt, ##args);	\
+	BUG_ON(!(_i->mount_opt & BTRFS_MOUNT_PANIC_ON_FATAL_ERROR));	\
 } while (0)
 
 /* acl.c */
@@ -3003,16 +3065,17 @@
 void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans,
 			      struct btrfs_pending_snapshot *pending,
 			      u64 *bytes_to_reserve);
-void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
+int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
 			      struct btrfs_pending_snapshot *pending);
 
 /* scrub.c */
 int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end,
 		    struct btrfs_scrub_progress *progress, int readonly);
-int btrfs_scrub_pause(struct btrfs_root *root);
-int btrfs_scrub_pause_super(struct btrfs_root *root);
-int btrfs_scrub_continue(struct btrfs_root *root);
-int btrfs_scrub_continue_super(struct btrfs_root *root);
+void btrfs_scrub_pause(struct btrfs_root *root);
+void btrfs_scrub_pause_super(struct btrfs_root *root);
+void btrfs_scrub_continue(struct btrfs_root *root);
+void btrfs_scrub_continue_super(struct btrfs_root *root);
+int __btrfs_scrub_cancel(struct btrfs_fs_info *info);
 int btrfs_scrub_cancel(struct btrfs_root *root);
 int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev);
 int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid);
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index fe4cd0f..03e3748 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -115,6 +115,7 @@
 	return NULL;
 }
 
+/* Will return either the node or PTR_ERR(-ENOMEM) */
 static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node(
 							struct inode *inode)
 {
@@ -836,10 +837,8 @@
 	btrfs_clear_path_blocking(path, NULL, 0);
 
 	/* insert the keys of the items */
-	ret = setup_items_for_insert(trans, root, path, keys, data_size,
-				     total_data_size, total_size, nitems);
-	if (ret)
-		goto error;
+	setup_items_for_insert(trans, root, path, keys, data_size,
+			       total_data_size, total_size, nitems);
 
 	/* insert the dir index items */
 	slot = path->slots[0];
@@ -1108,16 +1107,25 @@
 	return 0;
 }
 
-/* Called when committing the transaction. */
+/*
+ * Called when committing the transaction.
+ * Returns 0 on success.
+ * Returns < 0 on error and returns with an aborted transaction with any
+ * outstanding delayed items cleaned up.
+ */
 int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
 			    struct btrfs_root *root)
 {
+	struct btrfs_root *curr_root = root;
 	struct btrfs_delayed_root *delayed_root;
 	struct btrfs_delayed_node *curr_node, *prev_node;
 	struct btrfs_path *path;
 	struct btrfs_block_rsv *block_rsv;
 	int ret = 0;
 
+	if (trans->aborted)
+		return -EIO;
+
 	path = btrfs_alloc_path();
 	if (!path)
 		return -ENOMEM;
@@ -1130,17 +1138,18 @@
 
 	curr_node = btrfs_first_delayed_node(delayed_root);
 	while (curr_node) {
-		root = curr_node->root;
-		ret = btrfs_insert_delayed_items(trans, path, root,
+		curr_root = curr_node->root;
+		ret = btrfs_insert_delayed_items(trans, path, curr_root,
 						 curr_node);
 		if (!ret)
-			ret = btrfs_delete_delayed_items(trans, path, root,
-							 curr_node);
+			ret = btrfs_delete_delayed_items(trans, path,
+						curr_root, curr_node);
 		if (!ret)
-			ret = btrfs_update_delayed_inode(trans, root, path,
-							 curr_node);
+			ret = btrfs_update_delayed_inode(trans, curr_root,
+						path, curr_node);
 		if (ret) {
 			btrfs_release_delayed_node(curr_node);
+			btrfs_abort_transaction(trans, root, ret);
 			break;
 		}
 
@@ -1151,6 +1160,7 @@
 
 	btrfs_free_path(path);
 	trans->block_rsv = block_rsv;
+
 	return ret;
 }
 
@@ -1371,6 +1381,7 @@
 	btrfs_wq_run_delayed_node(delayed_root, root, 0);
 }
 
+/* Will return 0 or -ENOMEM */
 int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
 				   struct btrfs_root *root, const char *name,
 				   int name_len, struct inode *dir,
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c
index 66e4f29..69f22e3 100644
--- a/fs/btrfs/delayed-ref.c
+++ b/fs/btrfs/delayed-ref.c
@@ -420,7 +420,7 @@
  * this does all the dirty work in terms of maintaining the correct
  * overall modification count.
  */
-static noinline int add_delayed_ref_head(struct btrfs_fs_info *fs_info,
+static noinline void add_delayed_ref_head(struct btrfs_fs_info *fs_info,
 					struct btrfs_trans_handle *trans,
 					struct btrfs_delayed_ref_node *ref,
 					u64 bytenr, u64 num_bytes,
@@ -487,20 +487,19 @@
 		 * we've updated the existing ref, free the newly
 		 * allocated ref
 		 */
-		kfree(ref);
+		kfree(head_ref);
 	} else {
 		delayed_refs->num_heads++;
 		delayed_refs->num_heads_ready++;
 		delayed_refs->num_entries++;
 		trans->delayed_ref_updates++;
 	}
-	return 0;
 }
 
 /*
  * helper to insert a delayed tree ref into the rbtree.
  */
-static noinline int add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
+static noinline void add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
 					 struct btrfs_trans_handle *trans,
 					 struct btrfs_delayed_ref_node *ref,
 					 u64 bytenr, u64 num_bytes, u64 parent,
@@ -549,18 +548,17 @@
 		 * we've updated the existing ref, free the newly
 		 * allocated ref
 		 */
-		kfree(ref);
+		kfree(full_ref);
 	} else {
 		delayed_refs->num_entries++;
 		trans->delayed_ref_updates++;
 	}
-	return 0;
 }
 
 /*
  * helper to insert a delayed data ref into the rbtree.
  */
-static noinline int add_delayed_data_ref(struct btrfs_fs_info *fs_info,
+static noinline void add_delayed_data_ref(struct btrfs_fs_info *fs_info,
 					 struct btrfs_trans_handle *trans,
 					 struct btrfs_delayed_ref_node *ref,
 					 u64 bytenr, u64 num_bytes, u64 parent,
@@ -611,12 +609,11 @@
 		 * we've updated the existing ref, free the newly
 		 * allocated ref
 		 */
-		kfree(ref);
+		kfree(full_ref);
 	} else {
 		delayed_refs->num_entries++;
 		trans->delayed_ref_updates++;
 	}
-	return 0;
 }
 
 /*
@@ -634,7 +631,6 @@
 	struct btrfs_delayed_tree_ref *ref;
 	struct btrfs_delayed_ref_head *head_ref;
 	struct btrfs_delayed_ref_root *delayed_refs;
-	int ret;
 
 	BUG_ON(extent_op && extent_op->is_data);
 	ref = kmalloc(sizeof(*ref), GFP_NOFS);
@@ -656,14 +652,12 @@
 	 * insert both the head node and the new ref without dropping
 	 * the spin lock
 	 */
-	ret = add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr,
+	add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr,
 				   num_bytes, action, 0);
-	BUG_ON(ret);
 
-	ret = add_delayed_tree_ref(fs_info, trans, &ref->node, bytenr,
+	add_delayed_tree_ref(fs_info, trans, &ref->node, bytenr,
 				   num_bytes, parent, ref_root, level, action,
 				   for_cow);
-	BUG_ON(ret);
 	if (!need_ref_seq(for_cow, ref_root) &&
 	    waitqueue_active(&delayed_refs->seq_wait))
 		wake_up(&delayed_refs->seq_wait);
@@ -685,7 +679,6 @@
 	struct btrfs_delayed_data_ref *ref;
 	struct btrfs_delayed_ref_head *head_ref;
 	struct btrfs_delayed_ref_root *delayed_refs;
-	int ret;
 
 	BUG_ON(extent_op && !extent_op->is_data);
 	ref = kmalloc(sizeof(*ref), GFP_NOFS);
@@ -707,14 +700,12 @@
 	 * insert both the head node and the new ref without dropping
 	 * the spin lock
 	 */
-	ret = add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr,
+	add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr,
 				   num_bytes, action, 1);
-	BUG_ON(ret);
 
-	ret = add_delayed_data_ref(fs_info, trans, &ref->node, bytenr,
+	add_delayed_data_ref(fs_info, trans, &ref->node, bytenr,
 				   num_bytes, parent, ref_root, owner, offset,
 				   action, for_cow);
-	BUG_ON(ret);
 	if (!need_ref_seq(for_cow, ref_root) &&
 	    waitqueue_active(&delayed_refs->seq_wait))
 		wake_up(&delayed_refs->seq_wait);
@@ -729,7 +720,6 @@
 {
 	struct btrfs_delayed_ref_head *head_ref;
 	struct btrfs_delayed_ref_root *delayed_refs;
-	int ret;
 
 	head_ref = kmalloc(sizeof(*head_ref), GFP_NOFS);
 	if (!head_ref)
@@ -740,10 +730,9 @@
 	delayed_refs = &trans->transaction->delayed_refs;
 	spin_lock(&delayed_refs->lock);
 
-	ret = add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr,
+	add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr,
 				   num_bytes, BTRFS_UPDATE_DELAYED_HEAD,
 				   extent_op->is_data);
-	BUG_ON(ret);
 
 	if (waitqueue_active(&delayed_refs->seq_wait))
 		wake_up(&delayed_refs->seq_wait);
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c
index 31d84e7..c1a074d 100644
--- a/fs/btrfs/dir-item.c
+++ b/fs/btrfs/dir-item.c
@@ -49,9 +49,8 @@
 		di = btrfs_match_dir_item_name(root, path, name, name_len);
 		if (di)
 			return ERR_PTR(-EEXIST);
-		ret = btrfs_extend_item(trans, root, path, data_size);
-	}
-	if (ret < 0)
+		btrfs_extend_item(trans, root, path, data_size);
+	} else if (ret < 0)
 		return ERR_PTR(ret);
 	WARN_ON(ret > 0);
 	leaf = path->nodes[0];
@@ -116,6 +115,7 @@
  * 'location' is the key to stuff into the directory item, 'type' is the
  * type of the inode we're pointing to, and 'index' is the sequence number
  * to use for the second index (if one is created).
+ * Will return 0 or -ENOMEM
  */
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
 			  *root, const char *name, int name_len,
@@ -383,8 +383,8 @@
 		start = btrfs_item_ptr_offset(leaf, path->slots[0]);
 		memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
 			item_len - (ptr + sub_item_len - start));
-		ret = btrfs_truncate_item(trans, root, path,
-					  item_len - sub_item_len, 1);
+		btrfs_truncate_item(trans, root, path,
+				    item_len - sub_item_len, 1);
 	}
 	return ret;
 }
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 534266f..20196f4 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -48,20 +48,19 @@
 static struct extent_io_ops btree_extent_io_ops;
 static void end_workqueue_fn(struct btrfs_work *work);
 static void free_fs_root(struct btrfs_root *root);
-static void btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
+static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
 				    int read_only);
-static int btrfs_destroy_ordered_operations(struct btrfs_root *root);
-static int btrfs_destroy_ordered_extents(struct btrfs_root *root);
+static void btrfs_destroy_ordered_operations(struct btrfs_root *root);
+static void btrfs_destroy_ordered_extents(struct btrfs_root *root);
 static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
 				      struct btrfs_root *root);
-static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t);
-static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root);
+static void btrfs_destroy_pending_snapshots(struct btrfs_transaction *t);
+static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root);
 static int btrfs_destroy_marked_extents(struct btrfs_root *root,
 					struct extent_io_tree *dirty_pages,
 					int mark);
 static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
 				       struct extent_io_tree *pinned_extents);
-static int btrfs_cleanup_transaction(struct btrfs_root *root);
 
 /*
  * end_io_wq structs are used to do processing in task context when an IO is
@@ -99,6 +98,7 @@
 	 */
 	u64 bio_offset;
 	struct btrfs_work work;
+	int error;
 };
 
 /*
@@ -332,8 +332,8 @@
 		return 0;
 
 	lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,
-			 0, &cached_state, GFP_NOFS);
-	if (extent_buffer_uptodate(io_tree, eb, cached_state) &&
+			 0, &cached_state);
+	if (extent_buffer_uptodate(eb) &&
 	    btrfs_header_generation(eb) == parent_transid) {
 		ret = 0;
 		goto out;
@@ -344,7 +344,7 @@
 		       (unsigned long long)parent_transid,
 		       (unsigned long long)btrfs_header_generation(eb));
 	ret = 1;
-	clear_extent_buffer_uptodate(io_tree, eb, &cached_state);
+	clear_extent_buffer_uptodate(eb);
 out:
 	unlock_extent_cached(io_tree, eb->start, eb->start + eb->len - 1,
 			     &cached_state, GFP_NOFS);
@@ -360,9 +360,11 @@
 					  u64 start, u64 parent_transid)
 {
 	struct extent_io_tree *io_tree;
+	int failed = 0;
 	int ret;
 	int num_copies = 0;
 	int mirror_num = 0;
+	int failed_mirror = 0;
 
 	clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
 	io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree;
@@ -370,9 +372,8 @@
 		ret = read_extent_buffer_pages(io_tree, eb, start,
 					       WAIT_COMPLETE,
 					       btree_get_extent, mirror_num);
-		if (!ret &&
-		    !verify_parent_transid(io_tree, eb, parent_transid))
-			return ret;
+		if (!ret && !verify_parent_transid(io_tree, eb, parent_transid))
+			break;
 
 		/*
 		 * This buffer's crc is fine, but its contents are corrupted, so
@@ -380,18 +381,31 @@
 		 * any less wrong.
 		 */
 		if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags))
-			return ret;
+			break;
+
+		if (!failed_mirror) {
+			failed = 1;
+			printk(KERN_ERR "failed mirror was %d\n", eb->failed_mirror);
+			failed_mirror = eb->failed_mirror;
+		}
 
 		num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
 					      eb->start, eb->len);
 		if (num_copies == 1)
-			return ret;
+			break;
 
 		mirror_num++;
+		if (mirror_num == failed_mirror)
+			mirror_num++;
+
 		if (mirror_num > num_copies)
-			return ret;
+			break;
 	}
-	return -EIO;
+
+	if (failed && !ret)
+		repair_eb_io_failure(root, eb, failed_mirror);
+
+	return ret;
 }
 
 /*
@@ -404,50 +418,27 @@
 	struct extent_io_tree *tree;
 	u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
 	u64 found_start;
-	unsigned long len;
 	struct extent_buffer *eb;
-	int ret;
 
 	tree = &BTRFS_I(page->mapping->host)->io_tree;
 
-	if (page->private == EXTENT_PAGE_PRIVATE) {
-		WARN_ON(1);
-		goto out;
-	}
-	if (!page->private) {
-		WARN_ON(1);
-		goto out;
-	}
-	len = page->private >> 2;
-	WARN_ON(len == 0);
-
-	eb = alloc_extent_buffer(tree, start, len, page);
-	if (eb == NULL) {
-		WARN_ON(1);
-		goto out;
-	}
-	ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE,
-					     btrfs_header_generation(eb));
-	BUG_ON(ret);
-	WARN_ON(!btrfs_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN));
-
+	eb = (struct extent_buffer *)page->private;
+	if (page != eb->pages[0])
+		return 0;
 	found_start = btrfs_header_bytenr(eb);
 	if (found_start != start) {
 		WARN_ON(1);
-		goto err;
+		return 0;
 	}
-	if (eb->first_page != page) {
+	if (eb->pages[0] != page) {
 		WARN_ON(1);
-		goto err;
+		return 0;
 	}
 	if (!PageUptodate(page)) {
 		WARN_ON(1);
-		goto err;
+		return 0;
 	}
 	csum_tree_block(root, eb, 0);
-err:
-	free_extent_buffer(eb);
-out:
 	return 0;
 }
 
@@ -537,34 +528,74 @@
 	return 0;
 }
 
+struct extent_buffer *find_eb_for_page(struct extent_io_tree *tree,
+				       struct page *page, int max_walk)
+{
+	struct extent_buffer *eb;
+	u64 start = page_offset(page);
+	u64 target = start;
+	u64 min_start;
+
+	if (start < max_walk)
+		min_start = 0;
+	else
+		min_start = start - max_walk;
+
+	while (start >= min_start) {
+		eb = find_extent_buffer(tree, start, 0);
+		if (eb) {
+			/*
+			 * we found an extent buffer and it contains our page
+			 * horray!
+			 */
+			if (eb->start <= target &&
+			    eb->start + eb->len > target)
+				return eb;
+
+			/* we found an extent buffer that wasn't for us */
+			free_extent_buffer(eb);
+			return NULL;
+		}
+		if (start == 0)
+			break;
+		start -= PAGE_CACHE_SIZE;
+	}
+	return NULL;
+}
+
 static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
 			       struct extent_state *state)
 {
 	struct extent_io_tree *tree;
 	u64 found_start;
 	int found_level;
-	unsigned long len;
 	struct extent_buffer *eb;
 	struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
 	int ret = 0;
+	int reads_done;
 
-	tree = &BTRFS_I(page->mapping->host)->io_tree;
-	if (page->private == EXTENT_PAGE_PRIVATE)
-		goto out;
 	if (!page->private)
 		goto out;
 
-	len = page->private >> 2;
-	WARN_ON(len == 0);
+	tree = &BTRFS_I(page->mapping->host)->io_tree;
+	eb = (struct extent_buffer *)page->private;
 
-	eb = alloc_extent_buffer(tree, start, len, page);
-	if (eb == NULL) {
+	/* the pending IO might have been the only thing that kept this buffer
+	 * in memory.  Make sure we have a ref for all this other checks
+	 */
+	extent_buffer_get(eb);
+
+	reads_done = atomic_dec_and_test(&eb->io_pages);
+	if (!reads_done)
+		goto err;
+
+	if (test_bit(EXTENT_BUFFER_IOERR, &eb->bflags)) {
 		ret = -EIO;
-		goto out;
+		goto err;
 	}
 
 	found_start = btrfs_header_bytenr(eb);
-	if (found_start != start) {
+	if (found_start != eb->start) {
 		printk_ratelimited(KERN_INFO "btrfs bad tree block start "
 			       "%llu %llu\n",
 			       (unsigned long long)found_start,
@@ -572,13 +603,6 @@
 		ret = -EIO;
 		goto err;
 	}
-	if (eb->first_page != page) {
-		printk(KERN_INFO "btrfs bad first page %lu %lu\n",
-		       eb->first_page->index, page->index);
-		WARN_ON(1);
-		ret = -EIO;
-		goto err;
-	}
 	if (check_tree_block_fsid(root, eb)) {
 		printk_ratelimited(KERN_INFO "btrfs bad fsid on block %llu\n",
 			       (unsigned long long)eb->start);
@@ -606,48 +630,31 @@
 		ret = -EIO;
 	}
 
-	end = min_t(u64, eb->len, PAGE_CACHE_SIZE);
-	end = eb->start + end - 1;
+	if (!ret)
+		set_extent_buffer_uptodate(eb);
 err:
 	if (test_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) {
 		clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags);
 		btree_readahead_hook(root, eb, eb->start, ret);
 	}
 
+	if (ret)
+		clear_extent_buffer_uptodate(eb);
 	free_extent_buffer(eb);
 out:
 	return ret;
 }
 
-static int btree_io_failed_hook(struct bio *failed_bio,
-			 struct page *page, u64 start, u64 end,
-			 int mirror_num, struct extent_state *state)
+static int btree_io_failed_hook(struct page *page, int failed_mirror)
 {
-	struct extent_io_tree *tree;
-	unsigned long len;
 	struct extent_buffer *eb;
 	struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
 
-	tree = &BTRFS_I(page->mapping->host)->io_tree;
-	if (page->private == EXTENT_PAGE_PRIVATE)
-		goto out;
-	if (!page->private)
-		goto out;
-
-	len = page->private >> 2;
-	WARN_ON(len == 0);
-
-	eb = alloc_extent_buffer(tree, start, len, page);
-	if (eb == NULL)
-		goto out;
-
-	if (test_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) {
-		clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags);
+	eb = (struct extent_buffer *)page->private;
+	set_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
+	eb->failed_mirror = failed_mirror;
+	if (test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags))
 		btree_readahead_hook(root, eb, eb->start, -EIO);
-	}
-	free_extent_buffer(eb);
-
-out:
 	return -EIO;	/* we fixed nothing */
 }
 
@@ -719,11 +726,14 @@
 static void run_one_async_start(struct btrfs_work *work)
 {
 	struct async_submit_bio *async;
+	int ret;
 
 	async = container_of(work, struct  async_submit_bio, work);
-	async->submit_bio_start(async->inode, async->rw, async->bio,
-			       async->mirror_num, async->bio_flags,
-			       async->bio_offset);
+	ret = async->submit_bio_start(async->inode, async->rw, async->bio,
+				      async->mirror_num, async->bio_flags,
+				      async->bio_offset);
+	if (ret)
+		async->error = ret;
 }
 
 static void run_one_async_done(struct btrfs_work *work)
@@ -744,6 +754,12 @@
 	    waitqueue_active(&fs_info->async_submit_wait))
 		wake_up(&fs_info->async_submit_wait);
 
+	/* If an error occured we just want to clean up the bio and move on */
+	if (async->error) {
+		bio_endio(async->bio, async->error);
+		return;
+	}
+
 	async->submit_bio_done(async->inode, async->rw, async->bio,
 			       async->mirror_num, async->bio_flags,
 			       async->bio_offset);
@@ -785,6 +801,8 @@
 	async->bio_flags = bio_flags;
 	async->bio_offset = bio_offset;
 
+	async->error = 0;
+
 	atomic_inc(&fs_info->nr_async_submits);
 
 	if (rw & REQ_SYNC)
@@ -806,15 +824,18 @@
 	struct bio_vec *bvec = bio->bi_io_vec;
 	int bio_index = 0;
 	struct btrfs_root *root;
+	int ret = 0;
 
 	WARN_ON(bio->bi_vcnt <= 0);
 	while (bio_index < bio->bi_vcnt) {
 		root = BTRFS_I(bvec->bv_page->mapping->host)->root;
-		csum_dirty_buffer(root, bvec->bv_page);
+		ret = csum_dirty_buffer(root, bvec->bv_page);
+		if (ret)
+			break;
 		bio_index++;
 		bvec++;
 	}
-	return 0;
+	return ret;
 }
 
 static int __btree_submit_bio_start(struct inode *inode, int rw,
@@ -826,8 +847,7 @@
 	 * when we're called for a write, we're already in the async
 	 * submission context.  Just jump into btrfs_map_bio
 	 */
-	btree_csum_one_bio(bio);
-	return 0;
+	return btree_csum_one_bio(bio);
 }
 
 static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
@@ -847,15 +867,16 @@
 {
 	int ret;
 
-	ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info,
-					  bio, 1);
-	BUG_ON(ret);
-
 	if (!(rw & REQ_WRITE)) {
+
 		/*
 		 * called for a read, do the setup so that checksum validation
 		 * can happen in the async kernel threads
 		 */
+		ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info,
+					  bio, 1);
+		if (ret)
+			return ret;
 		return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
 				     mirror_num, 0);
 	}
@@ -893,34 +914,6 @@
 }
 #endif
 
-static int btree_writepage(struct page *page, struct writeback_control *wbc)
-{
-	struct extent_io_tree *tree;
-	struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
-	struct extent_buffer *eb;
-	int was_dirty;
-
-	tree = &BTRFS_I(page->mapping->host)->io_tree;
-	if (!(current->flags & PF_MEMALLOC)) {
-		return extent_write_full_page(tree, page,
-					      btree_get_extent, wbc);
-	}
-
-	redirty_page_for_writepage(wbc, page);
-	eb = btrfs_find_tree_block(root, page_offset(page), PAGE_CACHE_SIZE);
-	WARN_ON(!eb);
-
-	was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags);
-	if (!was_dirty) {
-		spin_lock(&root->fs_info->delalloc_lock);
-		root->fs_info->dirty_metadata_bytes += PAGE_CACHE_SIZE;
-		spin_unlock(&root->fs_info->delalloc_lock);
-	}
-	free_extent_buffer(eb);
-
-	unlock_page(page);
-	return 0;
-}
 
 static int btree_writepages(struct address_space *mapping,
 			    struct writeback_control *wbc)
@@ -940,7 +933,7 @@
 		if (num_dirty < thresh)
 			return 0;
 	}
-	return extent_writepages(tree, mapping, btree_get_extent, wbc);
+	return btree_write_cache_pages(mapping, wbc);
 }
 
 static int btree_readpage(struct file *file, struct page *page)
@@ -952,16 +945,8 @@
 
 static int btree_releasepage(struct page *page, gfp_t gfp_flags)
 {
-	struct extent_io_tree *tree;
-	struct extent_map_tree *map;
-	int ret;
-
 	if (PageWriteback(page) || PageDirty(page))
 		return 0;
-
-	tree = &BTRFS_I(page->mapping->host)->io_tree;
-	map = &BTRFS_I(page->mapping->host)->extent_tree;
-
 	/*
 	 * We need to mask out eg. __GFP_HIGHMEM and __GFP_DMA32 as we're doing
 	 * slab allocation from alloc_extent_state down the callchain where
@@ -969,18 +954,7 @@
 	 */
 	gfp_flags &= ~GFP_SLAB_BUG_MASK;
 
-	ret = try_release_extent_state(map, tree, page, gfp_flags);
-	if (!ret)
-		return 0;
-
-	ret = try_release_extent_buffer(tree, page);
-	if (ret == 1) {
-		ClearPagePrivate(page);
-		set_page_private(page, 0);
-		page_cache_release(page);
-	}
-
-	return ret;
+	return try_release_extent_buffer(page, gfp_flags);
 }
 
 static void btree_invalidatepage(struct page *page, unsigned long offset)
@@ -998,15 +972,28 @@
 	}
 }
 
+static int btree_set_page_dirty(struct page *page)
+{
+	struct extent_buffer *eb;
+
+	BUG_ON(!PagePrivate(page));
+	eb = (struct extent_buffer *)page->private;
+	BUG_ON(!eb);
+	BUG_ON(!test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags));
+	BUG_ON(!atomic_read(&eb->refs));
+	btrfs_assert_tree_locked(eb);
+	return __set_page_dirty_nobuffers(page);
+}
+
 static const struct address_space_operations btree_aops = {
 	.readpage	= btree_readpage,
-	.writepage	= btree_writepage,
 	.writepages	= btree_writepages,
 	.releasepage	= btree_releasepage,
 	.invalidatepage = btree_invalidatepage,
 #ifdef CONFIG_MIGRATION
 	.migratepage	= btree_migratepage,
 #endif
+	.set_page_dirty = btree_set_page_dirty,
 };
 
 int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize,
@@ -1049,7 +1036,7 @@
 	if (test_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags)) {
 		free_extent_buffer(buf);
 		return -EIO;
-	} else if (extent_buffer_uptodate(io_tree, buf, NULL)) {
+	} else if (extent_buffer_uptodate(buf)) {
 		*eb = buf;
 	} else {
 		free_extent_buffer(buf);
@@ -1074,20 +1061,20 @@
 	struct extent_buffer *eb;
 
 	eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->io_tree,
-				 bytenr, blocksize, NULL);
+				 bytenr, blocksize);
 	return eb;
 }
 
 
 int btrfs_write_tree_block(struct extent_buffer *buf)
 {
-	return filemap_fdatawrite_range(buf->first_page->mapping, buf->start,
+	return filemap_fdatawrite_range(buf->pages[0]->mapping, buf->start,
 					buf->start + buf->len - 1);
 }
 
 int btrfs_wait_tree_block_writeback(struct extent_buffer *buf)
 {
-	return filemap_fdatawait_range(buf->first_page->mapping,
+	return filemap_fdatawait_range(buf->pages[0]->mapping,
 				       buf->start, buf->start + buf->len - 1);
 }
 
@@ -1102,17 +1089,13 @@
 		return NULL;
 
 	ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
-
-	if (ret == 0)
-		set_bit(EXTENT_BUFFER_UPTODATE, &buf->bflags);
 	return buf;
 
 }
 
-int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-		     struct extent_buffer *buf)
+void clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+		      struct extent_buffer *buf)
 {
-	struct inode *btree_inode = root->fs_info->btree_inode;
 	if (btrfs_header_generation(buf) ==
 	    root->fs_info->running_transaction->transid) {
 		btrfs_assert_tree_locked(buf);
@@ -1121,23 +1104,27 @@
 			spin_lock(&root->fs_info->delalloc_lock);
 			if (root->fs_info->dirty_metadata_bytes >= buf->len)
 				root->fs_info->dirty_metadata_bytes -= buf->len;
-			else
-				WARN_ON(1);
+			else {
+				spin_unlock(&root->fs_info->delalloc_lock);
+				btrfs_panic(root->fs_info, -EOVERFLOW,
+					  "Can't clear %lu bytes from "
+					  " dirty_mdatadata_bytes (%lu)",
+					  buf->len,
+					  root->fs_info->dirty_metadata_bytes);
+			}
 			spin_unlock(&root->fs_info->delalloc_lock);
 		}
 
 		/* ugh, clear_extent_buffer_dirty needs to lock the page */
 		btrfs_set_lock_blocking(buf);
-		clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree,
-					  buf);
+		clear_extent_buffer_dirty(buf);
 	}
-	return 0;
 }
 
-static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
-			u32 stripesize, struct btrfs_root *root,
-			struct btrfs_fs_info *fs_info,
-			u64 objectid)
+static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
+			 u32 stripesize, struct btrfs_root *root,
+			 struct btrfs_fs_info *fs_info,
+			 u64 objectid)
 {
 	root->node = NULL;
 	root->commit_root = NULL;
@@ -1189,13 +1176,12 @@
 	root->defrag_running = 0;
 	root->root_key.objectid = objectid;
 	root->anon_dev = 0;
-	return 0;
 }
 
-static int find_and_setup_root(struct btrfs_root *tree_root,
-			       struct btrfs_fs_info *fs_info,
-			       u64 objectid,
-			       struct btrfs_root *root)
+static int __must_check find_and_setup_root(struct btrfs_root *tree_root,
+					    struct btrfs_fs_info *fs_info,
+					    u64 objectid,
+					    struct btrfs_root *root)
 {
 	int ret;
 	u32 blocksize;
@@ -1208,7 +1194,8 @@
 				   &root->root_item, &root->root_key);
 	if (ret > 0)
 		return -ENOENT;
-	BUG_ON(ret);
+	else if (ret < 0)
+		return ret;
 
 	generation = btrfs_root_generation(&root->root_item);
 	blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
@@ -1377,7 +1364,7 @@
 	root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
 				     blocksize, generation);
 	root->commit_root = btrfs_root_node(root);
-	BUG_ON(!root->node);
+	BUG_ON(!root->node); /* -ENOMEM */
 out:
 	if (location->objectid != BTRFS_TREE_LOG_OBJECTID) {
 		root->ref_cows = 1;
@@ -1513,41 +1500,6 @@
 	return 0;
 }
 
-static int bio_ready_for_csum(struct bio *bio)
-{
-	u64 length = 0;
-	u64 buf_len = 0;
-	u64 start = 0;
-	struct page *page;
-	struct extent_io_tree *io_tree = NULL;
-	struct bio_vec *bvec;
-	int i;
-	int ret;
-
-	bio_for_each_segment(bvec, bio, i) {
-		page = bvec->bv_page;
-		if (page->private == EXTENT_PAGE_PRIVATE) {
-			length += bvec->bv_len;
-			continue;
-		}
-		if (!page->private) {
-			length += bvec->bv_len;
-			continue;
-		}
-		length = bvec->bv_len;
-		buf_len = page->private >> 2;
-		start = page_offset(page) + bvec->bv_offset;
-		io_tree = &BTRFS_I(page->mapping->host)->io_tree;
-	}
-	/* are we fully contained in this bio? */
-	if (buf_len <= length)
-		return 1;
-
-	ret = extent_range_uptodate(io_tree, start + length,
-				    start + buf_len - 1);
-	return ret;
-}
-
 /*
  * called by the kthread helper functions to finally call the bio end_io
  * functions.  This is where read checksum verification actually happens
@@ -1563,17 +1515,6 @@
 	bio = end_io_wq->bio;
 	fs_info = end_io_wq->info;
 
-	/* metadata bio reads are special because the whole tree block must
-	 * be checksummed at once.  This makes sure the entire block is in
-	 * ram and up to date before trying to verify things.  For
-	 * blocksize <= pagesize, it is basically a noop
-	 */
-	if (!(bio->bi_rw & REQ_WRITE) && end_io_wq->metadata &&
-	    !bio_ready_for_csum(bio)) {
-		btrfs_queue_worker(&fs_info->endio_meta_workers,
-				   &end_io_wq->work);
-		return;
-	}
 	error = end_io_wq->error;
 	bio->bi_private = end_io_wq->private;
 	bio->bi_end_io = end_io_wq->end_io;
@@ -1614,9 +1555,10 @@
 	u64 transid;
 	unsigned long now;
 	unsigned long delay;
-	int ret;
+	bool cannot_commit;
 
 	do {
+		cannot_commit = false;
 		delay = HZ * 30;
 		vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE);
 		mutex_lock(&root->fs_info->transaction_kthread_mutex);
@@ -1638,11 +1580,14 @@
 		transid = cur->transid;
 		spin_unlock(&root->fs_info->trans_lock);
 
+		/* If the file system is aborted, this will always fail. */
 		trans = btrfs_join_transaction(root);
-		BUG_ON(IS_ERR(trans));
+		if (IS_ERR(trans)) {
+			cannot_commit = true;
+			goto sleep;
+		}
 		if (transid == trans->transid) {
-			ret = btrfs_commit_transaction(trans, root);
-			BUG_ON(ret);
+			btrfs_commit_transaction(trans, root);
 		} else {
 			btrfs_end_transaction(trans, root);
 		}
@@ -1653,7 +1598,8 @@
 		if (!try_to_freeze()) {
 			set_current_state(TASK_INTERRUPTIBLE);
 			if (!kthread_should_stop() &&
-			    !btrfs_transaction_blocked(root->fs_info))
+			    (!btrfs_transaction_blocked(root->fs_info) ||
+			     cannot_commit))
 				schedule_timeout(delay);
 			__set_current_state(TASK_RUNNING);
 		}
@@ -2042,6 +1988,7 @@
 	RB_CLEAR_NODE(&BTRFS_I(fs_info->btree_inode)->rb_node);
 	extent_io_tree_init(&BTRFS_I(fs_info->btree_inode)->io_tree,
 			     fs_info->btree_inode->i_mapping);
+	BTRFS_I(fs_info->btree_inode)->io_tree.track_uptodate = 0;
 	extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree);
 
 	BTRFS_I(fs_info->btree_inode)->io_tree.ops = &btree_extent_io_ops;
@@ -2084,6 +2031,7 @@
 	__setup_root(4096, 4096, 4096, 4096, tree_root,
 		     fs_info, BTRFS_ROOT_TREE_OBJECTID);
 
+	invalidate_bdev(fs_devices->latest_bdev);
 	bh = btrfs_read_dev_super(fs_devices->latest_bdev);
 	if (!bh) {
 		err = -EINVAL;
@@ -2104,7 +2052,12 @@
 	/* check FS state, whether FS is broken. */
 	fs_info->fs_state |= btrfs_super_flags(disk_super);
 
-	btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY);
+	ret = btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY);
+	if (ret) {
+		printk(KERN_ERR "btrfs: superblock contains fatal errors\n");
+		err = ret;
+		goto fail_alloc;
+	}
 
 	/*
 	 * run through our array of backup supers and setup
@@ -2135,10 +2088,55 @@
 		goto fail_alloc;
 	}
 
+	if (btrfs_super_leafsize(disk_super) !=
+	    btrfs_super_nodesize(disk_super)) {
+		printk(KERN_ERR "BTRFS: couldn't mount because metadata "
+		       "blocksizes don't match.  node %d leaf %d\n",
+		       btrfs_super_nodesize(disk_super),
+		       btrfs_super_leafsize(disk_super));
+		err = -EINVAL;
+		goto fail_alloc;
+	}
+	if (btrfs_super_leafsize(disk_super) > BTRFS_MAX_METADATA_BLOCKSIZE) {
+		printk(KERN_ERR "BTRFS: couldn't mount because metadata "
+		       "blocksize (%d) was too large\n",
+		       btrfs_super_leafsize(disk_super));
+		err = -EINVAL;
+		goto fail_alloc;
+	}
+
 	features = btrfs_super_incompat_flags(disk_super);
 	features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF;
 	if (tree_root->fs_info->compress_type & BTRFS_COMPRESS_LZO)
 		features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO;
+
+	/*
+	 * flag our filesystem as having big metadata blocks if
+	 * they are bigger than the page size
+	 */
+	if (btrfs_super_leafsize(disk_super) > PAGE_CACHE_SIZE) {
+		if (!(features & BTRFS_FEATURE_INCOMPAT_BIG_METADATA))
+			printk(KERN_INFO "btrfs flagging fs with big metadata feature\n");
+		features |= BTRFS_FEATURE_INCOMPAT_BIG_METADATA;
+	}
+
+	nodesize = btrfs_super_nodesize(disk_super);
+	leafsize = btrfs_super_leafsize(disk_super);
+	sectorsize = btrfs_super_sectorsize(disk_super);
+	stripesize = btrfs_super_stripesize(disk_super);
+
+	/*
+	 * mixed block groups end up with duplicate but slightly offset
+	 * extent buffers for the same range.  It leads to corruptions
+	 */
+	if ((features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) &&
+	    (sectorsize != leafsize)) {
+		printk(KERN_WARNING "btrfs: unequal leaf/node/sector sizes "
+				"are not allowed for mixed block groups on %s\n",
+				sb->s_id);
+		goto fail_alloc;
+	}
+
 	btrfs_set_super_incompat_flags(disk_super, features);
 
 	features = btrfs_super_compat_ro_flags(disk_super) &
@@ -2242,10 +2240,6 @@
 	fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages,
 				    4 * 1024 * 1024 / PAGE_CACHE_SIZE);
 
-	nodesize = btrfs_super_nodesize(disk_super);
-	leafsize = btrfs_super_leafsize(disk_super);
-	sectorsize = btrfs_super_sectorsize(disk_super);
-	stripesize = btrfs_super_stripesize(disk_super);
 	tree_root->nodesize = nodesize;
 	tree_root->leafsize = leafsize;
 	tree_root->sectorsize = sectorsize;
@@ -2285,7 +2279,7 @@
 	chunk_root->node = read_tree_block(chunk_root,
 					   btrfs_super_chunk_root(disk_super),
 					   blocksize, generation);
-	BUG_ON(!chunk_root->node);
+	BUG_ON(!chunk_root->node); /* -ENOMEM */
 	if (!test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) {
 		printk(KERN_WARNING "btrfs: failed to read chunk root on %s\n",
 		       sb->s_id);
@@ -2425,21 +2419,31 @@
 		log_tree_root->node = read_tree_block(tree_root, bytenr,
 						      blocksize,
 						      generation + 1);
+		/* returns with log_tree_root freed on success */
 		ret = btrfs_recover_log_trees(log_tree_root);
-		BUG_ON(ret);
+		if (ret) {
+			btrfs_error(tree_root->fs_info, ret,
+				    "Failed to recover log tree");
+			free_extent_buffer(log_tree_root->node);
+			kfree(log_tree_root);
+			goto fail_trans_kthread;
+		}
 
 		if (sb->s_flags & MS_RDONLY) {
-			ret =  btrfs_commit_super(tree_root);
-			BUG_ON(ret);
+			ret = btrfs_commit_super(tree_root);
+			if (ret)
+				goto fail_trans_kthread;
 		}
 	}
 
 	ret = btrfs_find_orphan_roots(tree_root);
-	BUG_ON(ret);
+	if (ret)
+		goto fail_trans_kthread;
 
 	if (!(sb->s_flags & MS_RDONLY)) {
 		ret = btrfs_cleanup_fs_roots(fs_info);
-		BUG_ON(ret);
+		if (ret) {
+			}
 
 		ret = btrfs_recover_relocation(tree_root);
 		if (ret < 0) {
@@ -2859,6 +2863,8 @@
 	if (total_errors > max_errors) {
 		printk(KERN_ERR "btrfs: %d errors while writing supers\n",
 		       total_errors);
+
+		/* This shouldn't happen. FUA is masked off if unsupported */
 		BUG();
 	}
 
@@ -2875,9 +2881,9 @@
 	}
 	mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
 	if (total_errors > max_errors) {
-		printk(KERN_ERR "btrfs: %d errors while writing supers\n",
-		       total_errors);
-		BUG();
+		btrfs_error(root->fs_info, -EIO,
+			    "%d errors while writing supers", total_errors);
+		return -EIO;
 	}
 	return 0;
 }
@@ -2891,7 +2897,20 @@
 	return ret;
 }
 
-int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
+/* Kill all outstanding I/O */
+void btrfs_abort_devices(struct btrfs_root *root)
+{
+	struct list_head *head;
+	struct btrfs_device *dev;
+	mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
+	head = &root->fs_info->fs_devices->devices;
+	list_for_each_entry_rcu(dev, head, dev_list) {
+		blk_abort_queue(dev->bdev->bd_disk->queue);
+	}
+	mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+}
+
+void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
 {
 	spin_lock(&fs_info->fs_roots_radix_lock);
 	radix_tree_delete(&fs_info->fs_roots_radix,
@@ -2904,7 +2923,6 @@
 	__btrfs_remove_free_space_cache(root->free_ino_pinned);
 	__btrfs_remove_free_space_cache(root->free_ino_ctl);
 	free_fs_root(root);
-	return 0;
 }
 
 static void free_fs_root(struct btrfs_root *root)
@@ -2921,7 +2939,7 @@
 	kfree(root);
 }
 
-static int del_fs_roots(struct btrfs_fs_info *fs_info)
+static void del_fs_roots(struct btrfs_fs_info *fs_info)
 {
 	int ret;
 	struct btrfs_root *gang[8];
@@ -2950,7 +2968,6 @@
 		for (i = 0; i < ret; i++)
 			btrfs_free_fs_root(fs_info, gang[i]);
 	}
-	return 0;
 }
 
 int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
@@ -2999,14 +3016,21 @@
 	if (IS_ERR(trans))
 		return PTR_ERR(trans);
 	ret = btrfs_commit_transaction(trans, root);
-	BUG_ON(ret);
+	if (ret)
+		return ret;
 	/* run commit again to drop the original snapshot */
 	trans = btrfs_join_transaction(root);
 	if (IS_ERR(trans))
 		return PTR_ERR(trans);
-	btrfs_commit_transaction(trans, root);
+	ret = btrfs_commit_transaction(trans, root);
+	if (ret)
+		return ret;
 	ret = btrfs_write_and_wait_transaction(NULL, root);
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_error(root->fs_info, ret,
+			    "Failed to sync btree inode to disk.");
+		return ret;
+	}
 
 	ret = write_ctree_super(NULL, root, 0);
 	return ret;
@@ -3122,10 +3146,9 @@
 int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid)
 {
 	int ret;
-	struct inode *btree_inode = buf->first_page->mapping->host;
+	struct inode *btree_inode = buf->pages[0]->mapping->host;
 
-	ret = extent_buffer_uptodate(&BTRFS_I(btree_inode)->io_tree, buf,
-				     NULL);
+	ret = extent_buffer_uptodate(buf);
 	if (!ret)
 		return ret;
 
@@ -3136,16 +3159,13 @@
 
 int btrfs_set_buffer_uptodate(struct extent_buffer *buf)
 {
-	struct inode *btree_inode = buf->first_page->mapping->host;
-	return set_extent_buffer_uptodate(&BTRFS_I(btree_inode)->io_tree,
-					  buf);
+	return set_extent_buffer_uptodate(buf);
 }
 
 void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
 {
-	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
+	struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
 	u64 transid = btrfs_header_generation(buf);
-	struct inode *btree_inode = root->fs_info->btree_inode;
 	int was_dirty;
 
 	btrfs_assert_tree_locked(buf);
@@ -3157,8 +3177,7 @@
 			(unsigned long long)root->fs_info->generation);
 		WARN_ON(1);
 	}
-	was_dirty = set_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree,
-					    buf);
+	was_dirty = set_extent_buffer_dirty(buf);
 	if (!was_dirty) {
 		spin_lock(&root->fs_info->delalloc_lock);
 		root->fs_info->dirty_metadata_bytes += buf->len;
@@ -3212,12 +3231,8 @@
 
 int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
 {
-	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
-	int ret;
-	ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
-	if (ret == 0)
-		set_bit(EXTENT_BUFFER_UPTODATE, &buf->bflags);
-	return ret;
+	struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
+	return btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
 }
 
 static int btree_lock_page_hook(struct page *page, void *data,
@@ -3225,17 +3240,21 @@
 {
 	struct inode *inode = page->mapping->host;
 	struct btrfs_root *root = BTRFS_I(inode)->root;
-	struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
 	struct extent_buffer *eb;
-	unsigned long len;
-	u64 bytenr = page_offset(page);
 
-	if (page->private == EXTENT_PAGE_PRIVATE)
+	/*
+	 * We culled this eb but the page is still hanging out on the mapping,
+	 * carry on.
+	 */
+	if (!PagePrivate(page))
 		goto out;
 
-	len = page->private >> 2;
-	eb = find_extent_buffer(io_tree, bytenr, len);
-	if (!eb)
+	eb = (struct extent_buffer *)page->private;
+	if (!eb) {
+		WARN_ON(1);
+		goto out;
+	}
+	if (page != eb->pages[0])
 		goto out;
 
 	if (!btrfs_try_tree_write_lock(eb)) {
@@ -3254,7 +3273,6 @@
 	}
 
 	btrfs_tree_unlock(eb);
-	free_extent_buffer(eb);
 out:
 	if (!trylock_page(page)) {
 		flush_fn(data);
@@ -3263,15 +3281,23 @@
 	return 0;
 }
 
-static void btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
+static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
 			      int read_only)
 {
-	if (read_only)
-		return;
+	if (btrfs_super_csum_type(fs_info->super_copy) >= ARRAY_SIZE(btrfs_csum_sizes)) {
+		printk(KERN_ERR "btrfs: unsupported checksum algorithm\n");
+		return -EINVAL;
+	}
 
-	if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
+	if (read_only)
+		return 0;
+
+	if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
 		printk(KERN_WARNING "warning: mount fs with errors, "
 		       "running btrfsck is recommended\n");
+	}
+
+	return 0;
 }
 
 int btrfs_error_commit_super(struct btrfs_root *root)
@@ -3293,7 +3319,7 @@
 	return ret;
 }
 
-static int btrfs_destroy_ordered_operations(struct btrfs_root *root)
+static void btrfs_destroy_ordered_operations(struct btrfs_root *root)
 {
 	struct btrfs_inode *btrfs_inode;
 	struct list_head splice;
@@ -3315,11 +3341,9 @@
 
 	spin_unlock(&root->fs_info->ordered_extent_lock);
 	mutex_unlock(&root->fs_info->ordered_operations_mutex);
-
-	return 0;
 }
 
-static int btrfs_destroy_ordered_extents(struct btrfs_root *root)
+static void btrfs_destroy_ordered_extents(struct btrfs_root *root)
 {
 	struct list_head splice;
 	struct btrfs_ordered_extent *ordered;
@@ -3351,12 +3375,10 @@
 	}
 
 	spin_unlock(&root->fs_info->ordered_extent_lock);
-
-	return 0;
 }
 
-static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
-				      struct btrfs_root *root)
+int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
+			       struct btrfs_root *root)
 {
 	struct rb_node *node;
 	struct btrfs_delayed_ref_root *delayed_refs;
@@ -3365,6 +3387,7 @@
 
 	delayed_refs = &trans->delayed_refs;
 
+again:
 	spin_lock(&delayed_refs->lock);
 	if (delayed_refs->num_entries == 0) {
 		spin_unlock(&delayed_refs->lock);
@@ -3386,6 +3409,7 @@
 			struct btrfs_delayed_ref_head *head;
 
 			head = btrfs_delayed_node_to_head(ref);
+			spin_unlock(&delayed_refs->lock);
 			mutex_lock(&head->mutex);
 			kfree(head->extent_op);
 			delayed_refs->num_heads--;
@@ -3393,8 +3417,9 @@
 				delayed_refs->num_heads_ready--;
 			list_del_init(&head->cluster);
 			mutex_unlock(&head->mutex);
+			btrfs_put_delayed_ref(ref);
+			goto again;
 		}
-
 		spin_unlock(&delayed_refs->lock);
 		btrfs_put_delayed_ref(ref);
 
@@ -3407,7 +3432,7 @@
 	return ret;
 }
 
-static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t)
+static void btrfs_destroy_pending_snapshots(struct btrfs_transaction *t)
 {
 	struct btrfs_pending_snapshot *snapshot;
 	struct list_head splice;
@@ -3425,11 +3450,9 @@
 
 		kfree(snapshot);
 	}
-
-	return 0;
 }
 
-static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
+static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
 {
 	struct btrfs_inode *btrfs_inode;
 	struct list_head splice;
@@ -3449,8 +3472,6 @@
 	}
 
 	spin_unlock(&root->fs_info->delalloc_lock);
-
-	return 0;
 }
 
 static int btrfs_destroy_marked_extents(struct btrfs_root *root,
@@ -3541,13 +3562,43 @@
 	return 0;
 }
 
-static int btrfs_cleanup_transaction(struct btrfs_root *root)
+void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
+				   struct btrfs_root *root)
+{
+	btrfs_destroy_delayed_refs(cur_trans, root);
+	btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv,
+				cur_trans->dirty_pages.dirty_bytes);
+
+	/* FIXME: cleanup wait for commit */
+	cur_trans->in_commit = 1;
+	cur_trans->blocked = 1;
+	if (waitqueue_active(&root->fs_info->transaction_blocked_wait))
+		wake_up(&root->fs_info->transaction_blocked_wait);
+
+	cur_trans->blocked = 0;
+	if (waitqueue_active(&root->fs_info->transaction_wait))
+		wake_up(&root->fs_info->transaction_wait);
+
+	cur_trans->commit_done = 1;
+	if (waitqueue_active(&cur_trans->commit_wait))
+		wake_up(&cur_trans->commit_wait);
+
+	btrfs_destroy_pending_snapshots(cur_trans);
+
+	btrfs_destroy_marked_extents(root, &cur_trans->dirty_pages,
+				     EXTENT_DIRTY);
+
+	/*
+	memset(cur_trans, 0, sizeof(*cur_trans));
+	kmem_cache_free(btrfs_transaction_cachep, cur_trans);
+	*/
+}
+
+int btrfs_cleanup_transaction(struct btrfs_root *root)
 {
 	struct btrfs_transaction *t;
 	LIST_HEAD(list);
 
-	WARN_ON(1);
-
 	mutex_lock(&root->fs_info->transaction_kthread_mutex);
 
 	spin_lock(&root->fs_info->trans_lock);
@@ -3612,6 +3663,17 @@
 	return 0;
 }
 
+static int btree_writepage_io_failed_hook(struct bio *bio, struct page *page,
+					  u64 start, u64 end,
+					  struct extent_state *state)
+{
+	struct super_block *sb = page->mapping->host->i_sb;
+	struct btrfs_fs_info *fs_info = btrfs_sb(sb);
+	btrfs_error(fs_info, -EIO,
+		    "Error occured while writing out btree at %llu", start);
+	return -EIO;
+}
+
 static struct extent_io_ops btree_extent_io_ops = {
 	.write_cache_pages_lock_hook = btree_lock_page_hook,
 	.readpage_end_io_hook = btree_readpage_end_io_hook,
@@ -3619,4 +3681,5 @@
 	.submit_bio_hook = btree_submit_bio_hook,
 	/* note we're sharing with inode.c for the merge bio hook */
 	.merge_bio_hook = btrfs_merge_bio_hook,
+	.writepage_io_failed_hook = btree_writepage_io_failed_hook,
 };
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index e4bc474..a7ace1a 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -44,8 +44,8 @@
 			 int mirror_num, struct extent_buffer **eb);
 struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
 						   u64 bytenr, u32 blocksize);
-int clean_tree_block(struct btrfs_trans_handle *trans,
-		     struct btrfs_root *root, struct extent_buffer *buf);
+void clean_tree_block(struct btrfs_trans_handle *trans,
+		      struct btrfs_root *root, struct extent_buffer *buf);
 int open_ctree(struct super_block *sb,
 	       struct btrfs_fs_devices *fs_devices,
 	       char *options);
@@ -64,7 +64,7 @@
 int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info);
 void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
 void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
-int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
+void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
 void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
 int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid);
 int btrfs_set_buffer_uptodate(struct extent_buffer *buf);
@@ -85,6 +85,10 @@
 			     struct btrfs_fs_info *fs_info);
 int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
 		       struct btrfs_root *root);
+int btrfs_cleanup_transaction(struct btrfs_root *root);
+void btrfs_cleanup_one_transaction(struct btrfs_transaction *trans,
+				  struct btrfs_root *root);
+void btrfs_abort_devices(struct btrfs_root *root);
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 void btrfs_init_lockdep(void);
diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c
index 5f77166..e887ee6 100644
--- a/fs/btrfs/export.c
+++ b/fs/btrfs/export.c
@@ -193,7 +193,7 @@
 	if (ret < 0)
 		goto fail;
 
-	BUG_ON(ret == 0);
+	BUG_ON(ret == 0); /* Key with offset of -1 found */
 	if (path->slots[0] == 0) {
 		ret = -ENOENT;
 		goto fail;
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 37e0a80..a844204 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -245,7 +245,7 @@
 		cache->bytes_super += stripe_len;
 		ret = add_excluded_extent(root, cache->key.objectid,
 					  stripe_len);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 	}
 
 	for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
@@ -253,13 +253,13 @@
 		ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
 				       cache->key.objectid, bytenr,
 				       0, &logical, &nr, &stripe_len);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 
 		while (nr--) {
 			cache->bytes_super += stripe_len;
 			ret = add_excluded_extent(root, logical[nr],
 						  stripe_len);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM */
 		}
 
 		kfree(logical);
@@ -321,7 +321,7 @@
 			total_added += size;
 			ret = btrfs_add_free_space(block_group, start,
 						   size);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM or logic error */
 			start = extent_end + 1;
 		} else {
 			break;
@@ -332,7 +332,7 @@
 		size = end - start;
 		total_added += size;
 		ret = btrfs_add_free_space(block_group, start, size);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM or logic error */
 	}
 
 	return total_added;
@@ -474,7 +474,8 @@
 	int ret = 0;
 
 	caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_NOFS);
-	BUG_ON(!caching_ctl);
+	if (!caching_ctl)
+		return -ENOMEM;
 
 	INIT_LIST_HEAD(&caching_ctl->list);
 	mutex_init(&caching_ctl->mutex);
@@ -982,7 +983,7 @@
 				ret = btrfs_next_leaf(root, path);
 				if (ret < 0)
 					return ret;
-				BUG_ON(ret > 0);
+				BUG_ON(ret > 0); /* Corruption */
 				leaf = path->nodes[0];
 			}
 			btrfs_item_key_to_cpu(leaf, &found_key,
@@ -1008,9 +1009,9 @@
 				new_size + extra_size, 1);
 	if (ret < 0)
 		return ret;
-	BUG_ON(ret);
+	BUG_ON(ret); /* Corruption */
 
-	ret = btrfs_extend_item(trans, root, path, new_size);
+	btrfs_extend_item(trans, root, path, new_size);
 
 	leaf = path->nodes[0];
 	item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
@@ -1478,7 +1479,11 @@
 		err = ret;
 		goto out;
 	}
-	BUG_ON(ret);
+	if (ret && !insert) {
+		err = -ENOENT;
+		goto out;
+	}
+	BUG_ON(ret); /* Corruption */
 
 	leaf = path->nodes[0];
 	item_size = btrfs_item_size_nr(leaf, path->slots[0]);
@@ -1592,13 +1597,13 @@
  * helper to add new inline back ref
  */
 static noinline_for_stack
-int setup_inline_extent_backref(struct btrfs_trans_handle *trans,
-				struct btrfs_root *root,
-				struct btrfs_path *path,
-				struct btrfs_extent_inline_ref *iref,
-				u64 parent, u64 root_objectid,
-				u64 owner, u64 offset, int refs_to_add,
-				struct btrfs_delayed_extent_op *extent_op)
+void setup_inline_extent_backref(struct btrfs_trans_handle *trans,
+				 struct btrfs_root *root,
+				 struct btrfs_path *path,
+				 struct btrfs_extent_inline_ref *iref,
+				 u64 parent, u64 root_objectid,
+				 u64 owner, u64 offset, int refs_to_add,
+				 struct btrfs_delayed_extent_op *extent_op)
 {
 	struct extent_buffer *leaf;
 	struct btrfs_extent_item *ei;
@@ -1608,7 +1613,6 @@
 	u64 refs;
 	int size;
 	int type;
-	int ret;
 
 	leaf = path->nodes[0];
 	ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
@@ -1617,7 +1621,7 @@
 	type = extent_ref_type(parent, owner);
 	size = btrfs_extent_inline_ref_size(type);
 
-	ret = btrfs_extend_item(trans, root, path, size);
+	btrfs_extend_item(trans, root, path, size);
 
 	ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
 	refs = btrfs_extent_refs(leaf, ei);
@@ -1652,7 +1656,6 @@
 		btrfs_set_extent_inline_ref_offset(leaf, iref, root_objectid);
 	}
 	btrfs_mark_buffer_dirty(leaf);
-	return 0;
 }
 
 static int lookup_extent_backref(struct btrfs_trans_handle *trans,
@@ -1687,12 +1690,12 @@
  * helper to update/remove inline back ref
  */
 static noinline_for_stack
-int update_inline_extent_backref(struct btrfs_trans_handle *trans,
-				 struct btrfs_root *root,
-				 struct btrfs_path *path,
-				 struct btrfs_extent_inline_ref *iref,
-				 int refs_to_mod,
-				 struct btrfs_delayed_extent_op *extent_op)
+void update_inline_extent_backref(struct btrfs_trans_handle *trans,
+				  struct btrfs_root *root,
+				  struct btrfs_path *path,
+				  struct btrfs_extent_inline_ref *iref,
+				  int refs_to_mod,
+				  struct btrfs_delayed_extent_op *extent_op)
 {
 	struct extent_buffer *leaf;
 	struct btrfs_extent_item *ei;
@@ -1703,7 +1706,6 @@
 	u32 item_size;
 	int size;
 	int type;
-	int ret;
 	u64 refs;
 
 	leaf = path->nodes[0];
@@ -1745,10 +1747,9 @@
 			memmove_extent_buffer(leaf, ptr, ptr + size,
 					      end - ptr - size);
 		item_size -= size;
-		ret = btrfs_truncate_item(trans, root, path, item_size, 1);
+		btrfs_truncate_item(trans, root, path, item_size, 1);
 	}
 	btrfs_mark_buffer_dirty(leaf);
-	return 0;
 }
 
 static noinline_for_stack
@@ -1768,13 +1769,13 @@
 					   root_objectid, owner, offset, 1);
 	if (ret == 0) {
 		BUG_ON(owner < BTRFS_FIRST_FREE_OBJECTID);
-		ret = update_inline_extent_backref(trans, root, path, iref,
-						   refs_to_add, extent_op);
+		update_inline_extent_backref(trans, root, path, iref,
+					     refs_to_add, extent_op);
 	} else if (ret == -ENOENT) {
-		ret = setup_inline_extent_backref(trans, root, path, iref,
-						  parent, root_objectid,
-						  owner, offset, refs_to_add,
-						  extent_op);
+		setup_inline_extent_backref(trans, root, path, iref, parent,
+					    root_objectid, owner, offset,
+					    refs_to_add, extent_op);
+		ret = 0;
 	}
 	return ret;
 }
@@ -1804,12 +1805,12 @@
 				 struct btrfs_extent_inline_ref *iref,
 				 int refs_to_drop, int is_data)
 {
-	int ret;
+	int ret = 0;
 
 	BUG_ON(!is_data && refs_to_drop != 1);
 	if (iref) {
-		ret = update_inline_extent_backref(trans, root, path, iref,
-						   -refs_to_drop, NULL);
+		update_inline_extent_backref(trans, root, path, iref,
+					     -refs_to_drop, NULL);
 	} else if (is_data) {
 		ret = remove_extent_data_ref(trans, root, path, refs_to_drop);
 	} else {
@@ -1835,6 +1836,7 @@
 	/* Tell the block device(s) that the sectors can be discarded */
 	ret = btrfs_map_block(&root->fs_info->mapping_tree, REQ_DISCARD,
 			      bytenr, &num_bytes, &bbio, 0);
+	/* Error condition is -ENOMEM */
 	if (!ret) {
 		struct btrfs_bio_stripe *stripe = bbio->stripes;
 		int i;
@@ -1850,7 +1852,7 @@
 			if (!ret)
 				discarded_bytes += stripe->length;
 			else if (ret != -EOPNOTSUPP)
-				break;
+				break; /* Logic errors or -ENOMEM, or -EIO but I don't know how that could happen JDM */
 
 			/*
 			 * Just in case we get back EOPNOTSUPP for some reason,
@@ -1869,6 +1871,7 @@
 	return ret;
 }
 
+/* Can return -ENOMEM */
 int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
 			 struct btrfs_root *root,
 			 u64 bytenr, u64 num_bytes, u64 parent,
@@ -1944,7 +1947,8 @@
 	ret = insert_extent_backref(trans, root->fs_info->extent_root,
 				    path, bytenr, parent, root_objectid,
 				    owner, offset, refs_to_add);
-	BUG_ON(ret);
+	if (ret)
+		btrfs_abort_transaction(trans, root, ret);
 out:
 	btrfs_free_path(path);
 	return err;
@@ -2031,6 +2035,9 @@
 	int ret;
 	int err = 0;
 
+	if (trans->aborted)
+		return 0;
+
 	path = btrfs_alloc_path();
 	if (!path)
 		return -ENOMEM;
@@ -2128,7 +2135,11 @@
 			       struct btrfs_delayed_extent_op *extent_op,
 			       int insert_reserved)
 {
-	int ret;
+	int ret = 0;
+
+	if (trans->aborted)
+		return 0;
+
 	if (btrfs_delayed_ref_is_head(node)) {
 		struct btrfs_delayed_ref_head *head;
 		/*
@@ -2146,11 +2157,10 @@
 				ret = btrfs_del_csums(trans, root,
 						      node->bytenr,
 						      node->num_bytes);
-				BUG_ON(ret);
 			}
 		}
 		mutex_unlock(&head->mutex);
-		return 0;
+		return ret;
 	}
 
 	if (node->type == BTRFS_TREE_BLOCK_REF_KEY ||
@@ -2197,6 +2207,10 @@
 	return NULL;
 }
 
+/*
+ * Returns 0 on success or if called with an already aborted transaction.
+ * Returns -ENOMEM or -EIO on failure and will abort the transaction.
+ */
 static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
 				       struct btrfs_root *root,
 				       struct list_head *cluster)
@@ -2285,9 +2299,13 @@
 
 				ret = run_delayed_extent_op(trans, root,
 							    ref, extent_op);
-				BUG_ON(ret);
 				kfree(extent_op);
 
+				if (ret) {
+					printk(KERN_DEBUG "btrfs: run_delayed_extent_op returned %d\n", ret);
+					return ret;
+				}
+
 				goto next;
 			}
 
@@ -2308,11 +2326,16 @@
 
 		ret = run_one_delayed_ref(trans, root, ref, extent_op,
 					  must_insert_reserved);
-		BUG_ON(ret);
 
 		btrfs_put_delayed_ref(ref);
 		kfree(extent_op);
 		count++;
+
+		if (ret) {
+			printk(KERN_DEBUG "btrfs: run_one_delayed_ref returned %d\n", ret);
+			return ret;
+		}
+
 next:
 		do_chunk_alloc(trans, root->fs_info->extent_root,
 			       2 * 1024 * 1024,
@@ -2347,6 +2370,9 @@
  * 0, which means to process everything in the tree at the start
  * of the run (but not newly added entries), or it can be some target
  * number you'd like to process.
+ *
+ * Returns 0 on success or if called with an aborted transaction
+ * Returns <0 on error and aborts the transaction
  */
 int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
 			   struct btrfs_root *root, unsigned long count)
@@ -2362,6 +2388,10 @@
 	unsigned long num_refs = 0;
 	int consider_waiting;
 
+	/* We'll clean this up in btrfs_cleanup_transaction */
+	if (trans->aborted)
+		return 0;
+
 	if (root == root->fs_info->extent_root)
 		root = root->fs_info->tree_root;
 
@@ -2419,7 +2449,11 @@
 		}
 
 		ret = run_clustered_refs(trans, root, &cluster);
-		BUG_ON(ret < 0);
+		if (ret < 0) {
+			spin_unlock(&delayed_refs->lock);
+			btrfs_abort_transaction(trans, root, ret);
+			return ret;
+		}
 
 		count -= min_t(unsigned long, ret, count);
 
@@ -2584,7 +2618,7 @@
 	ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
 	if (ret < 0)
 		goto out;
-	BUG_ON(ret == 0);
+	BUG_ON(ret == 0); /* Corruption */
 
 	ret = -ENOENT;
 	if (path->slots[0] == 0)
@@ -2738,7 +2772,6 @@
 	}
 	return 0;
 fail:
-	BUG();
 	return ret;
 }
 
@@ -2767,7 +2800,7 @@
 	ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1);
 	if (ret < 0)
 		goto fail;
-	BUG_ON(ret);
+	BUG_ON(ret); /* Corruption */
 
 	leaf = path->nodes[0];
 	bi = btrfs_item_ptr_offset(leaf, path->slots[0]);
@@ -2775,8 +2808,10 @@
 	btrfs_mark_buffer_dirty(leaf);
 	btrfs_release_path(path);
 fail:
-	if (ret)
+	if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
 		return ret;
+	}
 	return 0;
 
 }
@@ -2949,7 +2984,8 @@
 		if (last == 0) {
 			err = btrfs_run_delayed_refs(trans, root,
 						     (unsigned long)-1);
-			BUG_ON(err);
+			if (err) /* File system offline */
+				goto out;
 		}
 
 		cache = btrfs_lookup_first_block_group(root->fs_info, last);
@@ -2976,7 +3012,9 @@
 		last = cache->key.objectid + cache->key.offset;
 
 		err = write_one_cache_group(trans, root, path, cache);
-		BUG_ON(err);
+		if (err) /* File system offline */
+			goto out;
+
 		btrfs_put_block_group(cache);
 	}
 
@@ -2989,7 +3027,8 @@
 		if (last == 0) {
 			err = btrfs_run_delayed_refs(trans, root,
 						     (unsigned long)-1);
-			BUG_ON(err);
+			if (err) /* File system offline */
+				goto out;
 		}
 
 		cache = btrfs_lookup_first_block_group(root->fs_info, last);
@@ -3014,20 +3053,21 @@
 			continue;
 		}
 
-		btrfs_write_out_cache(root, trans, cache, path);
+		err = btrfs_write_out_cache(root, trans, cache, path);
 
 		/*
 		 * If we didn't have an error then the cache state is still
 		 * NEED_WRITE, so we can set it to WRITTEN.
 		 */
-		if (cache->disk_cache_state == BTRFS_DC_NEED_WRITE)
+		if (!err && cache->disk_cache_state == BTRFS_DC_NEED_WRITE)
 			cache->disk_cache_state = BTRFS_DC_WRITTEN;
 		last = cache->key.objectid + cache->key.offset;
 		btrfs_put_block_group(cache);
 	}
+out:
 
 	btrfs_free_path(path);
-	return 0;
+	return err;
 }
 
 int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr)
@@ -3098,11 +3138,8 @@
 
 static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
 {
-	u64 extra_flags = flags & BTRFS_BLOCK_GROUP_PROFILE_MASK;
-
-	/* chunk -> extended profile */
-	if (extra_flags == 0)
-		extra_flags = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
+	u64 extra_flags = chunk_to_extended(flags) &
+				BTRFS_EXTENDED_PROFILE_MASK;
 
 	if (flags & BTRFS_BLOCK_GROUP_DATA)
 		fs_info->avail_data_alloc_bits |= extra_flags;
@@ -3113,6 +3150,35 @@
 }
 
 /*
+ * returns target flags in extended format or 0 if restripe for this
+ * chunk_type is not in progress
+ */
+static u64 get_restripe_target(struct btrfs_fs_info *fs_info, u64 flags)
+{
+	struct btrfs_balance_control *bctl = fs_info->balance_ctl;
+	u64 target = 0;
+
+	BUG_ON(!mutex_is_locked(&fs_info->volume_mutex) &&
+	       !spin_is_locked(&fs_info->balance_lock));
+
+	if (!bctl)
+		return 0;
+
+	if (flags & BTRFS_BLOCK_GROUP_DATA &&
+	    bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) {
+		target = BTRFS_BLOCK_GROUP_DATA | bctl->data.target;
+	} else if (flags & BTRFS_BLOCK_GROUP_SYSTEM &&
+		   bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {
+		target = BTRFS_BLOCK_GROUP_SYSTEM | bctl->sys.target;
+	} else if (flags & BTRFS_BLOCK_GROUP_METADATA &&
+		   bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) {
+		target = BTRFS_BLOCK_GROUP_METADATA | bctl->meta.target;
+	}
+
+	return target;
+}
+
+/*
  * @flags: available profiles in extended format (see ctree.h)
  *
  * Returns reduced profile in chunk format.  If profile changing is in
@@ -3128,31 +3194,19 @@
 	 */
 	u64 num_devices = root->fs_info->fs_devices->rw_devices +
 		root->fs_info->fs_devices->missing_devices;
+	u64 target;
 
-	/* pick restriper's target profile if it's available */
+	/*
+	 * see if restripe for this chunk_type is in progress, if so
+	 * try to reduce to the target profile
+	 */
 	spin_lock(&root->fs_info->balance_lock);
-	if (root->fs_info->balance_ctl) {
-		struct btrfs_balance_control *bctl = root->fs_info->balance_ctl;
-		u64 tgt = 0;
-
-		if ((flags & BTRFS_BLOCK_GROUP_DATA) &&
-		    (bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
-		    (flags & bctl->data.target)) {
-			tgt = BTRFS_BLOCK_GROUP_DATA | bctl->data.target;
-		} else if ((flags & BTRFS_BLOCK_GROUP_SYSTEM) &&
-			   (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
-			   (flags & bctl->sys.target)) {
-			tgt = BTRFS_BLOCK_GROUP_SYSTEM | bctl->sys.target;
-		} else if ((flags & BTRFS_BLOCK_GROUP_METADATA) &&
-			   (bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
-			   (flags & bctl->meta.target)) {
-			tgt = BTRFS_BLOCK_GROUP_METADATA | bctl->meta.target;
-		}
-
-		if (tgt) {
+	target = get_restripe_target(root->fs_info, flags);
+	if (target) {
+		/* pick target profile only if it's already available */
+		if ((flags & target) & BTRFS_EXTENDED_PROFILE_MASK) {
 			spin_unlock(&root->fs_info->balance_lock);
-			flags = tgt;
-			goto out;
+			return extended_to_chunk(target);
 		}
 	}
 	spin_unlock(&root->fs_info->balance_lock);
@@ -3180,10 +3234,7 @@
 		flags &= ~BTRFS_BLOCK_GROUP_RAID0;
 	}
 
-out:
-	/* extended -> chunk profile */
-	flags &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE;
-	return flags;
+	return extended_to_chunk(flags);
 }
 
 static u64 get_alloc_profile(struct btrfs_root *root, u64 flags)
@@ -3312,8 +3363,7 @@
 	}
 	data_sinfo->bytes_may_use += bytes;
 	trace_btrfs_space_reservation(root->fs_info, "space_info",
-				      (u64)(unsigned long)data_sinfo,
-				      bytes, 1);
+				      data_sinfo->flags, bytes, 1);
 	spin_unlock(&data_sinfo->lock);
 
 	return 0;
@@ -3334,8 +3384,7 @@
 	spin_lock(&data_sinfo->lock);
 	data_sinfo->bytes_may_use -= bytes;
 	trace_btrfs_space_reservation(root->fs_info, "space_info",
-				      (u64)(unsigned long)data_sinfo,
-				      bytes, 0);
+				      data_sinfo->flags, bytes, 0);
 	spin_unlock(&data_sinfo->lock);
 }
 
@@ -3396,6 +3445,50 @@
 	return 1;
 }
 
+static u64 get_system_chunk_thresh(struct btrfs_root *root, u64 type)
+{
+	u64 num_dev;
+
+	if (type & BTRFS_BLOCK_GROUP_RAID10 ||
+	    type & BTRFS_BLOCK_GROUP_RAID0)
+		num_dev = root->fs_info->fs_devices->rw_devices;
+	else if (type & BTRFS_BLOCK_GROUP_RAID1)
+		num_dev = 2;
+	else
+		num_dev = 1;	/* DUP or single */
+
+	/* metadata for updaing devices and chunk tree */
+	return btrfs_calc_trans_metadata_size(root, num_dev + 1);
+}
+
+static void check_system_chunk(struct btrfs_trans_handle *trans,
+			       struct btrfs_root *root, u64 type)
+{
+	struct btrfs_space_info *info;
+	u64 left;
+	u64 thresh;
+
+	info = __find_space_info(root->fs_info, BTRFS_BLOCK_GROUP_SYSTEM);
+	spin_lock(&info->lock);
+	left = info->total_bytes - info->bytes_used - info->bytes_pinned -
+		info->bytes_reserved - info->bytes_readonly;
+	spin_unlock(&info->lock);
+
+	thresh = get_system_chunk_thresh(root, type);
+	if (left < thresh && btrfs_test_opt(root, ENOSPC_DEBUG)) {
+		printk(KERN_INFO "left=%llu, need=%llu, flags=%llu\n",
+		       left, thresh, type);
+		dump_space_info(info, 0, 0);
+	}
+
+	if (left < thresh) {
+		u64 flags;
+
+		flags = btrfs_get_alloc_profile(root->fs_info->chunk_root, 0);
+		btrfs_alloc_chunk(trans, root, flags);
+	}
+}
+
 static int do_chunk_alloc(struct btrfs_trans_handle *trans,
 			  struct btrfs_root *extent_root, u64 alloc_bytes,
 			  u64 flags, int force)
@@ -3405,15 +3498,13 @@
 	int wait_for_alloc = 0;
 	int ret = 0;
 
-	BUG_ON(!profile_is_valid(flags, 0));
-
 	space_info = __find_space_info(extent_root->fs_info, flags);
 	if (!space_info) {
 		ret = update_space_info(extent_root->fs_info, flags,
 					0, 0, &space_info);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 	}
-	BUG_ON(!space_info);
+	BUG_ON(!space_info); /* Logic error */
 
 again:
 	spin_lock(&space_info->lock);
@@ -3468,6 +3559,12 @@
 			force_metadata_allocation(fs_info);
 	}
 
+	/*
+	 * Check if we have enough space in SYSTEM chunk because we may need
+	 * to update devices.
+	 */
+	check_system_chunk(trans, extent_root, flags);
+
 	ret = btrfs_alloc_chunk(trans, extent_root, flags);
 	if (ret < 0 && ret != -ENOSPC)
 		goto out;
@@ -3678,8 +3775,10 @@
 		ret = wait_event_interruptible(space_info->wait,
 					       !space_info->flush);
 		/* Must have been interrupted, return */
-		if (ret)
+		if (ret) {
+			printk(KERN_DEBUG "btrfs: %s returning -EINTR\n", __func__);
 			return -EINTR;
+		}
 
 		spin_lock(&space_info->lock);
 	}
@@ -3700,9 +3799,7 @@
 		if (used + orig_bytes <= space_info->total_bytes) {
 			space_info->bytes_may_use += orig_bytes;
 			trace_btrfs_space_reservation(root->fs_info,
-					      "space_info",
-					      (u64)(unsigned long)space_info,
-					      orig_bytes, 1);
+				"space_info", space_info->flags, orig_bytes, 1);
 			ret = 0;
 		} else {
 			/*
@@ -3771,9 +3868,7 @@
 		if (used + num_bytes < space_info->total_bytes + avail) {
 			space_info->bytes_may_use += orig_bytes;
 			trace_btrfs_space_reservation(root->fs_info,
-					      "space_info",
-					      (u64)(unsigned long)space_info,
-					      orig_bytes, 1);
+				"space_info", space_info->flags, orig_bytes, 1);
 			ret = 0;
 		} else {
 			wait_ordered = true;
@@ -3836,8 +3931,9 @@
 	return ret;
 }
 
-static struct btrfs_block_rsv *get_block_rsv(struct btrfs_trans_handle *trans,
-					     struct btrfs_root *root)
+static struct btrfs_block_rsv *get_block_rsv(
+					const struct btrfs_trans_handle *trans,
+					const struct btrfs_root *root)
 {
 	struct btrfs_block_rsv *block_rsv = NULL;
 
@@ -3918,8 +4014,7 @@
 			spin_lock(&space_info->lock);
 			space_info->bytes_may_use -= num_bytes;
 			trace_btrfs_space_reservation(fs_info, "space_info",
-					      (u64)(unsigned long)space_info,
-					      num_bytes, 0);
+					space_info->flags, num_bytes, 0);
 			space_info->reservation_progress++;
 			spin_unlock(&space_info->lock);
 		}
@@ -4137,14 +4232,14 @@
 		block_rsv->reserved += num_bytes;
 		sinfo->bytes_may_use += num_bytes;
 		trace_btrfs_space_reservation(fs_info, "space_info",
-				      (u64)(unsigned long)sinfo, num_bytes, 1);
+				      sinfo->flags, num_bytes, 1);
 	}
 
 	if (block_rsv->reserved >= block_rsv->size) {
 		num_bytes = block_rsv->reserved - block_rsv->size;
 		sinfo->bytes_may_use -= num_bytes;
 		trace_btrfs_space_reservation(fs_info, "space_info",
-				      (u64)(unsigned long)sinfo, num_bytes, 0);
+				      sinfo->flags, num_bytes, 0);
 		sinfo->reservation_progress++;
 		block_rsv->reserved = block_rsv->size;
 		block_rsv->full = 1;
@@ -4198,12 +4293,12 @@
 		return;
 
 	trace_btrfs_space_reservation(root->fs_info, "transaction",
-				      (u64)(unsigned long)trans,
-				      trans->bytes_reserved, 0);
+				      trans->transid, trans->bytes_reserved, 0);
 	btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved);
 	trans->bytes_reserved = 0;
 }
 
+/* Can only return 0 or -ENOSPC */
 int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
 				  struct inode *inode)
 {
@@ -4540,7 +4635,7 @@
 	while (total) {
 		cache = btrfs_lookup_block_group(info, bytenr);
 		if (!cache)
-			return -1;
+			return -ENOENT;
 		if (cache->flags & (BTRFS_BLOCK_GROUP_DUP |
 				    BTRFS_BLOCK_GROUP_RAID1 |
 				    BTRFS_BLOCK_GROUP_RAID10))
@@ -4643,7 +4738,7 @@
 	struct btrfs_block_group_cache *cache;
 
 	cache = btrfs_lookup_block_group(root->fs_info, bytenr);
-	BUG_ON(!cache);
+	BUG_ON(!cache); /* Logic error */
 
 	pin_down_extent(root, cache, bytenr, num_bytes, reserved);
 
@@ -4661,7 +4756,7 @@
 	struct btrfs_block_group_cache *cache;
 
 	cache = btrfs_lookup_block_group(root->fs_info, bytenr);
-	BUG_ON(!cache);
+	BUG_ON(!cache); /* Logic error */
 
 	/*
 	 * pull in the free space cache (if any) so that our pin
@@ -4706,6 +4801,7 @@
 {
 	struct btrfs_space_info *space_info = cache->space_info;
 	int ret = 0;
+
 	spin_lock(&space_info->lock);
 	spin_lock(&cache->lock);
 	if (reserve != RESERVE_FREE) {
@@ -4716,9 +4812,8 @@
 			space_info->bytes_reserved += num_bytes;
 			if (reserve == RESERVE_ALLOC) {
 				trace_btrfs_space_reservation(cache->fs_info,
-					      "space_info",
-					      (u64)(unsigned long)space_info,
-					      num_bytes, 0);
+						"space_info", space_info->flags,
+						num_bytes, 0);
 				space_info->bytes_may_use -= num_bytes;
 			}
 		}
@@ -4734,7 +4829,7 @@
 	return ret;
 }
 
-int btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans,
+void btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans,
 				struct btrfs_root *root)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
@@ -4764,7 +4859,6 @@
 	up_write(&fs_info->extent_commit_sem);
 
 	update_global_block_rsv(fs_info);
-	return 0;
 }
 
 static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
@@ -4779,7 +4873,7 @@
 			if (cache)
 				btrfs_put_block_group(cache);
 			cache = btrfs_lookup_block_group(fs_info, start);
-			BUG_ON(!cache);
+			BUG_ON(!cache); /* Logic error */
 		}
 
 		len = cache->key.objectid + cache->key.offset - start;
@@ -4816,6 +4910,9 @@
 	u64 end;
 	int ret;
 
+	if (trans->aborted)
+		return 0;
+
 	if (fs_info->pinned_extents == &fs_info->freed_extents[0])
 		unpin = &fs_info->freed_extents[1];
 	else
@@ -4901,7 +4998,8 @@
 			ret = remove_extent_backref(trans, extent_root, path,
 						    NULL, refs_to_drop,
 						    is_data);
-			BUG_ON(ret);
+			if (ret)
+				goto abort;
 			btrfs_release_path(path);
 			path->leave_spinning = 1;
 
@@ -4919,10 +5017,11 @@
 					btrfs_print_leaf(extent_root,
 							 path->nodes[0]);
 			}
-			BUG_ON(ret);
+			if (ret < 0)
+				goto abort;
 			extent_slot = path->slots[0];
 		}
-	} else {
+	} else if (ret == -ENOENT) {
 		btrfs_print_leaf(extent_root, path->nodes[0]);
 		WARN_ON(1);
 		printk(KERN_ERR "btrfs unable to find ref byte nr %llu "
@@ -4932,6 +5031,8 @@
 		       (unsigned long long)root_objectid,
 		       (unsigned long long)owner_objectid,
 		       (unsigned long long)owner_offset);
+	} else {
+		goto abort;
 	}
 
 	leaf = path->nodes[0];
@@ -4941,7 +5042,8 @@
 		BUG_ON(found_extent || extent_slot != path->slots[0]);
 		ret = convert_extent_item_v0(trans, extent_root, path,
 					     owner_objectid, 0);
-		BUG_ON(ret < 0);
+		if (ret < 0)
+			goto abort;
 
 		btrfs_release_path(path);
 		path->leave_spinning = 1;
@@ -4958,7 +5060,8 @@
 			       (unsigned long long)bytenr);
 			btrfs_print_leaf(extent_root, path->nodes[0]);
 		}
-		BUG_ON(ret);
+		if (ret < 0)
+			goto abort;
 		extent_slot = path->slots[0];
 		leaf = path->nodes[0];
 		item_size = btrfs_item_size_nr(leaf, extent_slot);
@@ -4995,7 +5098,8 @@
 			ret = remove_extent_backref(trans, extent_root, path,
 						    iref, refs_to_drop,
 						    is_data);
-			BUG_ON(ret);
+			if (ret)
+				goto abort;
 		}
 	} else {
 		if (found_extent) {
@@ -5012,23 +5116,27 @@
 
 		ret = btrfs_del_items(trans, extent_root, path, path->slots[0],
 				      num_to_del);
-		BUG_ON(ret);
+		if (ret)
+			goto abort;
 		btrfs_release_path(path);
 
 		if (is_data) {
 			ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
-			BUG_ON(ret);
-		} else {
-			invalidate_mapping_pages(info->btree_inode->i_mapping,
-			     bytenr >> PAGE_CACHE_SHIFT,
-			     (bytenr + num_bytes - 1) >> PAGE_CACHE_SHIFT);
+			if (ret)
+				goto abort;
 		}
 
 		ret = update_block_group(trans, root, bytenr, num_bytes, 0);
-		BUG_ON(ret);
+		if (ret)
+			goto abort;
 	}
+out:
 	btrfs_free_path(path);
 	return ret;
+
+abort:
+	btrfs_abort_transaction(trans, extent_root, ret);
+	goto out;
 }
 
 /*
@@ -5124,7 +5232,7 @@
 					parent, root->root_key.objectid,
 					btrfs_header_level(buf),
 					BTRFS_DROP_DELAYED_REF, NULL, for_cow);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 	}
 
 	if (!last_ref)
@@ -5158,6 +5266,7 @@
 	btrfs_put_block_group(cache);
 }
 
+/* Can return -ENOMEM */
 int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		      u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid,
 		      u64 owner, u64 offset, int for_cow)
@@ -5179,14 +5288,12 @@
 					num_bytes,
 					parent, root_objectid, (int)owner,
 					BTRFS_DROP_DELAYED_REF, NULL, for_cow);
-		BUG_ON(ret);
 	} else {
 		ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
 						num_bytes,
 						parent, root_objectid, owner,
 						offset, BTRFS_DROP_DELAYED_REF,
 						NULL, for_cow);
-		BUG_ON(ret);
 	}
 	return ret;
 }
@@ -5243,28 +5350,34 @@
 	return 0;
 }
 
-static int get_block_group_index(struct btrfs_block_group_cache *cache)
+static int __get_block_group_index(u64 flags)
 {
 	int index;
-	if (cache->flags & BTRFS_BLOCK_GROUP_RAID10)
+
+	if (flags & BTRFS_BLOCK_GROUP_RAID10)
 		index = 0;
-	else if (cache->flags & BTRFS_BLOCK_GROUP_RAID1)
+	else if (flags & BTRFS_BLOCK_GROUP_RAID1)
 		index = 1;
-	else if (cache->flags & BTRFS_BLOCK_GROUP_DUP)
+	else if (flags & BTRFS_BLOCK_GROUP_DUP)
 		index = 2;
-	else if (cache->flags & BTRFS_BLOCK_GROUP_RAID0)
+	else if (flags & BTRFS_BLOCK_GROUP_RAID0)
 		index = 3;
 	else
 		index = 4;
+
 	return index;
 }
 
+static int get_block_group_index(struct btrfs_block_group_cache *cache)
+{
+	return __get_block_group_index(cache->flags);
+}
+
 enum btrfs_loop_type {
-	LOOP_FIND_IDEAL = 0,
-	LOOP_CACHING_NOWAIT = 1,
-	LOOP_CACHING_WAIT = 2,
-	LOOP_ALLOC_CHUNK = 3,
-	LOOP_NO_EMPTY_SIZE = 4,
+	LOOP_CACHING_NOWAIT = 0,
+	LOOP_CACHING_WAIT = 1,
+	LOOP_ALLOC_CHUNK = 2,
+	LOOP_NO_EMPTY_SIZE = 3,
 };
 
 /*
@@ -5278,7 +5391,6 @@
 static noinline int find_free_extent(struct btrfs_trans_handle *trans,
 				     struct btrfs_root *orig_root,
 				     u64 num_bytes, u64 empty_size,
-				     u64 search_start, u64 search_end,
 				     u64 hint_byte, struct btrfs_key *ins,
 				     u64 data)
 {
@@ -5287,6 +5399,7 @@
 	struct btrfs_free_cluster *last_ptr = NULL;
 	struct btrfs_block_group_cache *block_group = NULL;
 	struct btrfs_block_group_cache *used_block_group;
+	u64 search_start = 0;
 	int empty_cluster = 2 * 1024 * 1024;
 	int allowed_chunk_alloc = 0;
 	int done_chunk_alloc = 0;
@@ -5300,8 +5413,6 @@
 	bool failed_alloc = false;
 	bool use_cluster = true;
 	bool have_caching_bg = false;
-	u64 ideal_cache_percent = 0;
-	u64 ideal_cache_offset = 0;
 
 	WARN_ON(num_bytes < root->sectorsize);
 	btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
@@ -5351,7 +5462,6 @@
 		empty_cluster = 0;
 
 	if (search_start == hint_byte) {
-ideal_cache:
 		block_group = btrfs_lookup_block_group(root->fs_info,
 						       search_start);
 		used_block_group = block_group;
@@ -5363,8 +5473,7 @@
 		 * picked out then we don't care that the block group is cached.
 		 */
 		if (block_group && block_group_bits(block_group, data) &&
-		    (block_group->cached != BTRFS_CACHE_NO ||
-		     search_start == ideal_cache_offset)) {
+		    block_group->cached != BTRFS_CACHE_NO) {
 			down_read(&space_info->groups_sem);
 			if (list_empty(&block_group->list) ||
 			    block_group->ro) {
@@ -5418,44 +5527,13 @@
 have_block_group:
 		cached = block_group_cache_done(block_group);
 		if (unlikely(!cached)) {
-			u64 free_percent;
-
 			found_uncached_bg = true;
 			ret = cache_block_group(block_group, trans,
-						orig_root, 1);
-			if (block_group->cached == BTRFS_CACHE_FINISHED)
-				goto alloc;
-
-			free_percent = btrfs_block_group_used(&block_group->item);
-			free_percent *= 100;
-			free_percent = div64_u64(free_percent,
-						 block_group->key.offset);
-			free_percent = 100 - free_percent;
-			if (free_percent > ideal_cache_percent &&
-			    likely(!block_group->ro)) {
-				ideal_cache_offset = block_group->key.objectid;
-				ideal_cache_percent = free_percent;
-			}
-
-			/*
-			 * The caching workers are limited to 2 threads, so we
-			 * can queue as much work as we care to.
-			 */
-			if (loop > LOOP_FIND_IDEAL) {
-				ret = cache_block_group(block_group, trans,
-							orig_root, 0);
-				BUG_ON(ret);
-			}
-
-			/*
-			 * If loop is set for cached only, try the next block
-			 * group.
-			 */
-			if (loop == LOOP_FIND_IDEAL)
-				goto loop;
+						orig_root, 0);
+			BUG_ON(ret < 0);
+			ret = 0;
 		}
 
-alloc:
 		if (unlikely(block_group->ro))
 			goto loop;
 
@@ -5606,11 +5684,6 @@
 		}
 checks:
 		search_start = stripe_align(root, offset);
-		/* move on to the next group */
-		if (search_start + num_bytes >= search_end) {
-			btrfs_add_free_space(used_block_group, offset, num_bytes);
-			goto loop;
-		}
 
 		/* move on to the next group */
 		if (search_start + num_bytes >
@@ -5661,9 +5734,7 @@
 	if (!ins->objectid && ++index < BTRFS_NR_RAID_TYPES)
 		goto search;
 
-	/* LOOP_FIND_IDEAL, only search caching/cached bg's, and don't wait for
-	 *			for them to make caching progress.  Also
-	 *			determine the best possible bg to cache
+	/*
 	 * LOOP_CACHING_NOWAIT, search partially cached block groups, kicking
 	 *			caching kthreads as we move along
 	 * LOOP_CACHING_WAIT, search everything, and wait if our bg is caching
@@ -5673,50 +5744,17 @@
 	 */
 	if (!ins->objectid && loop < LOOP_NO_EMPTY_SIZE) {
 		index = 0;
-		if (loop == LOOP_FIND_IDEAL && found_uncached_bg) {
-			found_uncached_bg = false;
-			loop++;
-			if (!ideal_cache_percent)
-				goto search;
-
-			/*
-			 * 1 of the following 2 things have happened so far
-			 *
-			 * 1) We found an ideal block group for caching that
-			 * is mostly full and will cache quickly, so we might
-			 * as well wait for it.
-			 *
-			 * 2) We searched for cached only and we didn't find
-			 * anything, and we didn't start any caching kthreads
-			 * either, so chances are we will loop through and
-			 * start a couple caching kthreads, and then come back
-			 * around and just wait for them.  This will be slower
-			 * because we will have 2 caching kthreads reading at
-			 * the same time when we could have just started one
-			 * and waited for it to get far enough to give us an
-			 * allocation, so go ahead and go to the wait caching
-			 * loop.
-			 */
-			loop = LOOP_CACHING_WAIT;
-			search_start = ideal_cache_offset;
-			ideal_cache_percent = 0;
-			goto ideal_cache;
-		} else if (loop == LOOP_FIND_IDEAL) {
-			/*
-			 * Didn't find a uncached bg, wait on anything we find
-			 * next.
-			 */
-			loop = LOOP_CACHING_WAIT;
-			goto search;
-		}
-
 		loop++;
-
 		if (loop == LOOP_ALLOC_CHUNK) {
 		       if (allowed_chunk_alloc) {
 				ret = do_chunk_alloc(trans, root, num_bytes +
 						     2 * 1024 * 1024, data,
 						     CHUNK_ALLOC_LIMITED);
+				if (ret < 0) {
+					btrfs_abort_transaction(trans,
+								root, ret);
+					goto out;
+				}
 				allowed_chunk_alloc = 0;
 				if (ret == 1)
 					done_chunk_alloc = 1;
@@ -5745,6 +5783,7 @@
 	} else if (ins->objectid) {
 		ret = 0;
 	}
+out:
 
 	return ret;
 }
@@ -5798,12 +5837,10 @@
 			 struct btrfs_root *root,
 			 u64 num_bytes, u64 min_alloc_size,
 			 u64 empty_size, u64 hint_byte,
-			 u64 search_end, struct btrfs_key *ins,
-			 u64 data)
+			 struct btrfs_key *ins, u64 data)
 {
 	bool final_tried = false;
 	int ret;
-	u64 search_start = 0;
 
 	data = btrfs_get_alloc_profile(root, data);
 again:
@@ -5811,23 +5848,31 @@
 	 * the only place that sets empty_size is btrfs_realloc_node, which
 	 * is not called recursively on allocations
 	 */
-	if (empty_size || root->ref_cows)
+	if (empty_size || root->ref_cows) {
 		ret = do_chunk_alloc(trans, root->fs_info->extent_root,
 				     num_bytes + 2 * 1024 * 1024, data,
 				     CHUNK_ALLOC_NO_FORCE);
+		if (ret < 0 && ret != -ENOSPC) {
+			btrfs_abort_transaction(trans, root, ret);
+			return ret;
+		}
+	}
 
 	WARN_ON(num_bytes < root->sectorsize);
 	ret = find_free_extent(trans, root, num_bytes, empty_size,
-			       search_start, search_end, hint_byte,
-			       ins, data);
+			       hint_byte, ins, data);
 
 	if (ret == -ENOSPC) {
 		if (!final_tried) {
 			num_bytes = num_bytes >> 1;
 			num_bytes = num_bytes & ~(root->sectorsize - 1);
 			num_bytes = max(num_bytes, min_alloc_size);
-			do_chunk_alloc(trans, root->fs_info->extent_root,
+			ret = do_chunk_alloc(trans, root->fs_info->extent_root,
 				       num_bytes, data, CHUNK_ALLOC_FORCE);
+			if (ret < 0 && ret != -ENOSPC) {
+				btrfs_abort_transaction(trans, root, ret);
+				return ret;
+			}
 			if (num_bytes == min_alloc_size)
 				final_tried = true;
 			goto again;
@@ -5838,7 +5883,8 @@
 			printk(KERN_ERR "btrfs allocation failed flags %llu, "
 			       "wanted %llu\n", (unsigned long long)data,
 			       (unsigned long long)num_bytes);
-			dump_space_info(sinfo, num_bytes, 1);
+			if (sinfo)
+				dump_space_info(sinfo, num_bytes, 1);
 		}
 	}
 
@@ -5917,7 +5963,10 @@
 	path->leave_spinning = 1;
 	ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
 				      ins, size);
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_free_path(path);
+		return ret;
+	}
 
 	leaf = path->nodes[0];
 	extent_item = btrfs_item_ptr(leaf, path->slots[0],
@@ -5947,7 +5996,7 @@
 	btrfs_free_path(path);
 
 	ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
-	if (ret) {
+	if (ret) { /* -ENOENT, logic error */
 		printk(KERN_ERR "btrfs update block group failed for %llu "
 		       "%llu\n", (unsigned long long)ins->objectid,
 		       (unsigned long long)ins->offset);
@@ -5978,7 +6027,10 @@
 	path->leave_spinning = 1;
 	ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
 				      ins, size);
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_free_path(path);
+		return ret;
+	}
 
 	leaf = path->nodes[0];
 	extent_item = btrfs_item_ptr(leaf, path->slots[0],
@@ -6008,7 +6060,7 @@
 	btrfs_free_path(path);
 
 	ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
-	if (ret) {
+	if (ret) { /* -ENOENT, logic error */
 		printk(KERN_ERR "btrfs update block group failed for %llu "
 		       "%llu\n", (unsigned long long)ins->objectid,
 		       (unsigned long long)ins->offset);
@@ -6056,28 +6108,28 @@
 	if (!caching_ctl) {
 		BUG_ON(!block_group_cache_done(block_group));
 		ret = btrfs_remove_free_space(block_group, start, num_bytes);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 	} else {
 		mutex_lock(&caching_ctl->mutex);
 
 		if (start >= caching_ctl->progress) {
 			ret = add_excluded_extent(root, start, num_bytes);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM */
 		} else if (start + num_bytes <= caching_ctl->progress) {
 			ret = btrfs_remove_free_space(block_group,
 						      start, num_bytes);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM */
 		} else {
 			num_bytes = caching_ctl->progress - start;
 			ret = btrfs_remove_free_space(block_group,
 						      start, num_bytes);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM */
 
 			start = caching_ctl->progress;
 			num_bytes = ins->objectid + ins->offset -
 				    caching_ctl->progress;
 			ret = add_excluded_extent(root, start, num_bytes);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM */
 		}
 
 		mutex_unlock(&caching_ctl->mutex);
@@ -6086,7 +6138,7 @@
 
 	ret = btrfs_update_reserved_bytes(block_group, ins->offset,
 					  RESERVE_ALLOC_NO_ACCOUNT);
-	BUG_ON(ret);
+	BUG_ON(ret); /* logic error */
 	btrfs_put_block_group(block_group);
 	ret = alloc_reserved_file_extent(trans, root, 0, root_objectid,
 					 0, owner, offset, ins, 1);
@@ -6107,6 +6159,7 @@
 	btrfs_set_buffer_lockdep_class(root->root_key.objectid, buf, level);
 	btrfs_tree_lock(buf);
 	clean_tree_block(trans, root, buf);
+	clear_bit(EXTENT_BUFFER_STALE, &buf->bflags);
 
 	btrfs_set_lock_blocking(buf);
 	btrfs_set_buffer_uptodate(buf);
@@ -6214,7 +6267,7 @@
 		return ERR_CAST(block_rsv);
 
 	ret = btrfs_reserve_extent(trans, root, blocksize, blocksize,
-				   empty_size, hint, (u64)-1, &ins, 0);
+				   empty_size, hint, &ins, 0);
 	if (ret) {
 		unuse_block_rsv(root->fs_info, block_rsv, blocksize);
 		return ERR_PTR(ret);
@@ -6222,7 +6275,7 @@
 
 	buf = btrfs_init_new_buffer(trans, root, ins.objectid,
 				    blocksize, level);
-	BUG_ON(IS_ERR(buf));
+	BUG_ON(IS_ERR(buf)); /* -ENOMEM */
 
 	if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) {
 		if (parent == 0)
@@ -6234,7 +6287,7 @@
 	if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
 		struct btrfs_delayed_extent_op *extent_op;
 		extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS);
-		BUG_ON(!extent_op);
+		BUG_ON(!extent_op); /* -ENOMEM */
 		if (key)
 			memcpy(&extent_op->key, key, sizeof(extent_op->key));
 		else
@@ -6249,7 +6302,7 @@
 					ins.offset, parent, root_objectid,
 					level, BTRFS_ADD_DELAYED_EXTENT,
 					extent_op, for_cow);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 	}
 	return buf;
 }
@@ -6319,7 +6372,9 @@
 		/* We don't lock the tree block, it's OK to be racy here */
 		ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
 					       &refs, &flags);
-		BUG_ON(ret);
+		/* We don't care about errors in readahead. */
+		if (ret < 0)
+			continue;
 		BUG_ON(refs == 0);
 
 		if (wc->stage == DROP_REFERENCE) {
@@ -6386,7 +6441,9 @@
 					       eb->start, eb->len,
 					       &wc->refs[level],
 					       &wc->flags[level]);
-		BUG_ON(ret);
+		BUG_ON(ret == -ENOMEM);
+		if (ret)
+			return ret;
 		BUG_ON(wc->refs[level] == 0);
 	}
 
@@ -6405,12 +6462,12 @@
 	if (!(wc->flags[level] & flag)) {
 		BUG_ON(!path->locks[level]);
 		ret = btrfs_inc_ref(trans, root, eb, 1, wc->for_reloc);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 		ret = btrfs_dec_ref(trans, root, eb, 0, wc->for_reloc);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 		ret = btrfs_set_disk_extent_flags(trans, root, eb->start,
 						  eb->len, flag, 0);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 		wc->flags[level] |= flag;
 	}
 
@@ -6482,7 +6539,11 @@
 	ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
 				       &wc->refs[level - 1],
 				       &wc->flags[level - 1]);
-	BUG_ON(ret);
+	if (ret < 0) {
+		btrfs_tree_unlock(next);
+		return ret;
+	}
+
 	BUG_ON(wc->refs[level - 1] == 0);
 	*lookup_info = 0;
 
@@ -6551,7 +6612,7 @@
 
 		ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
 				root->root_key.objectid, level - 1, 0, 0);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 	}
 	btrfs_tree_unlock(next);
 	free_extent_buffer(next);
@@ -6609,7 +6670,10 @@
 						       eb->start, eb->len,
 						       &wc->refs[level],
 						       &wc->flags[level]);
-			BUG_ON(ret);
+			if (ret < 0) {
+				btrfs_tree_unlock_rw(eb, path->locks[level]);
+				return ret;
+			}
 			BUG_ON(wc->refs[level] == 0);
 			if (wc->refs[level] == 1) {
 				btrfs_tree_unlock_rw(eb, path->locks[level]);
@@ -6629,7 +6693,7 @@
 			else
 				ret = btrfs_dec_ref(trans, root, eb, 0,
 						    wc->for_reloc);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM */
 		}
 		/* make block locked assertion in clean_tree_block happy */
 		if (!path->locks[level] &&
@@ -6738,7 +6802,7 @@
  * also make sure backrefs for the shared block and all lower level
  * blocks are properly updated.
  */
-void btrfs_drop_snapshot(struct btrfs_root *root,
+int btrfs_drop_snapshot(struct btrfs_root *root,
 			 struct btrfs_block_rsv *block_rsv, int update_ref,
 			 int for_reloc)
 {
@@ -6766,7 +6830,10 @@
 	}
 
 	trans = btrfs_start_transaction(tree_root, 0);
-	BUG_ON(IS_ERR(trans));
+	if (IS_ERR(trans)) {
+		err = PTR_ERR(trans);
+		goto out_free;
+	}
 
 	if (block_rsv)
 		trans->block_rsv = block_rsv;
@@ -6791,7 +6858,7 @@
 		path->lowest_level = 0;
 		if (ret < 0) {
 			err = ret;
-			goto out_free;
+			goto out_end_trans;
 		}
 		WARN_ON(ret > 0);
 
@@ -6811,7 +6878,10 @@
 						path->nodes[level]->len,
 						&wc->refs[level],
 						&wc->flags[level]);
-			BUG_ON(ret);
+			if (ret < 0) {
+				err = ret;
+				goto out_end_trans;
+			}
 			BUG_ON(wc->refs[level] == 0);
 
 			if (level == root_item->drop_level)
@@ -6862,26 +6932,40 @@
 			ret = btrfs_update_root(trans, tree_root,
 						&root->root_key,
 						root_item);
-			BUG_ON(ret);
+			if (ret) {
+				btrfs_abort_transaction(trans, tree_root, ret);
+				err = ret;
+				goto out_end_trans;
+			}
 
 			btrfs_end_transaction_throttle(trans, tree_root);
 			trans = btrfs_start_transaction(tree_root, 0);
-			BUG_ON(IS_ERR(trans));
+			if (IS_ERR(trans)) {
+				err = PTR_ERR(trans);
+				goto out_free;
+			}
 			if (block_rsv)
 				trans->block_rsv = block_rsv;
 		}
 	}
 	btrfs_release_path(path);
-	BUG_ON(err);
+	if (err)
+		goto out_end_trans;
 
 	ret = btrfs_del_root(trans, tree_root, &root->root_key);
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_abort_transaction(trans, tree_root, ret);
+		goto out_end_trans;
+	}
 
 	if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) {
 		ret = btrfs_find_last_root(tree_root, root->root_key.objectid,
 					   NULL, NULL);
-		BUG_ON(ret < 0);
-		if (ret > 0) {
+		if (ret < 0) {
+			btrfs_abort_transaction(trans, tree_root, ret);
+			err = ret;
+			goto out_end_trans;
+		} else if (ret > 0) {
 			/* if we fail to delete the orphan item this time
 			 * around, it'll get picked up the next time.
 			 *
@@ -6899,14 +6983,15 @@
 		free_extent_buffer(root->commit_root);
 		kfree(root);
 	}
-out_free:
+out_end_trans:
 	btrfs_end_transaction_throttle(trans, tree_root);
+out_free:
 	kfree(wc);
 	btrfs_free_path(path);
 out:
 	if (err)
 		btrfs_std_error(root->fs_info, err);
-	return;
+	return err;
 }
 
 /*
@@ -6983,31 +7068,15 @@
 static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
 {
 	u64 num_devices;
-	u64 stripped = BTRFS_BLOCK_GROUP_RAID0 |
-		BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
+	u64 stripped;
 
-	if (root->fs_info->balance_ctl) {
-		struct btrfs_balance_control *bctl = root->fs_info->balance_ctl;
-		u64 tgt = 0;
-
-		/* pick restriper's target profile and return */
-		if (flags & BTRFS_BLOCK_GROUP_DATA &&
-		    bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) {
-			tgt = BTRFS_BLOCK_GROUP_DATA | bctl->data.target;
-		} else if (flags & BTRFS_BLOCK_GROUP_SYSTEM &&
-			   bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {
-			tgt = BTRFS_BLOCK_GROUP_SYSTEM | bctl->sys.target;
-		} else if (flags & BTRFS_BLOCK_GROUP_METADATA &&
-			   bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) {
-			tgt = BTRFS_BLOCK_GROUP_METADATA | bctl->meta.target;
-		}
-
-		if (tgt) {
-			/* extended -> chunk profile */
-			tgt &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE;
-			return tgt;
-		}
-	}
+	/*
+	 * if restripe for this chunk_type is on pick target profile and
+	 * return, otherwise do the usual balance
+	 */
+	stripped = get_restripe_target(root->fs_info, flags);
+	if (stripped)
+		return extended_to_chunk(stripped);
 
 	/*
 	 * we add in the count of missing devices because we want
@@ -7017,6 +7086,9 @@
 	num_devices = root->fs_info->fs_devices->rw_devices +
 		root->fs_info->fs_devices->missing_devices;
 
+	stripped = BTRFS_BLOCK_GROUP_RAID0 |
+		BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
+
 	if (num_devices == 1) {
 		stripped |= BTRFS_BLOCK_GROUP_DUP;
 		stripped = flags & ~stripped;
@@ -7029,7 +7101,6 @@
 		if (flags & (BTRFS_BLOCK_GROUP_RAID1 |
 			     BTRFS_BLOCK_GROUP_RAID10))
 			return stripped | BTRFS_BLOCK_GROUP_DUP;
-		return flags;
 	} else {
 		/* they already had raid on here, just return */
 		if (flags & stripped)
@@ -7042,9 +7113,9 @@
 		if (flags & BTRFS_BLOCK_GROUP_DUP)
 			return stripped | BTRFS_BLOCK_GROUP_RAID1;
 
-		/* turn single device chunks into raid0 */
-		return stripped | BTRFS_BLOCK_GROUP_RAID0;
+		/* this is drive concat, leave it alone */
 	}
+
 	return flags;
 }
 
@@ -7103,12 +7174,16 @@
 	BUG_ON(cache->ro);
 
 	trans = btrfs_join_transaction(root);
-	BUG_ON(IS_ERR(trans));
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
 
 	alloc_flags = update_block_group_flags(root, cache->flags);
-	if (alloc_flags != cache->flags)
-		do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
-			       CHUNK_ALLOC_FORCE);
+	if (alloc_flags != cache->flags) {
+		ret = do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
+				     CHUNK_ALLOC_FORCE);
+		if (ret < 0)
+			goto out;
+	}
 
 	ret = set_block_group_ro(cache, 0);
 	if (!ret)
@@ -7188,7 +7263,7 @@
 	return free_bytes;
 }
 
-int btrfs_set_block_group_rw(struct btrfs_root *root,
+void btrfs_set_block_group_rw(struct btrfs_root *root,
 			      struct btrfs_block_group_cache *cache)
 {
 	struct btrfs_space_info *sinfo = cache->space_info;
@@ -7204,7 +7279,6 @@
 	cache->ro = 0;
 	spin_unlock(&cache->lock);
 	spin_unlock(&sinfo->lock);
-	return 0;
 }
 
 /*
@@ -7222,6 +7296,7 @@
 	u64 min_free;
 	u64 dev_min = 1;
 	u64 dev_nr = 0;
+	u64 target;
 	int index;
 	int full = 0;
 	int ret = 0;
@@ -7262,13 +7337,11 @@
 	/*
 	 * ok we don't have enough space, but maybe we have free space on our
 	 * devices to allocate new chunks for relocation, so loop through our
-	 * alloc devices and guess if we have enough space.  However, if we
-	 * were marked as full, then we know there aren't enough chunks, and we
-	 * can just return.
+	 * alloc devices and guess if we have enough space.  if this block
+	 * group is going to be restriped, run checks against the target
+	 * profile instead of the current one.
 	 */
 	ret = -1;
-	if (full)
-		goto out;
 
 	/*
 	 * index:
@@ -7278,7 +7351,20 @@
 	 *      3: raid0
 	 *      4: single
 	 */
-	index = get_block_group_index(block_group);
+	target = get_restripe_target(root->fs_info, block_group->flags);
+	if (target) {
+		index = __get_block_group_index(extended_to_chunk(target));
+	} else {
+		/*
+		 * this is just a balance, so if we were marked as full
+		 * we know there is no space for a new chunk
+		 */
+		if (full)
+			goto out;
+
+		index = get_block_group_index(block_group);
+	}
+
 	if (index == 0) {
 		dev_min = 4;
 		/* Divide by 2 */
@@ -7572,7 +7658,7 @@
 		ret = update_space_info(info, cache->flags, found_key.offset,
 					btrfs_block_group_used(&cache->item),
 					&space_info);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 		cache->space_info = space_info;
 		spin_lock(&cache->space_info->lock);
 		cache->space_info->bytes_readonly += cache->bytes_super;
@@ -7581,7 +7667,7 @@
 		__link_block_group(space_info, cache);
 
 		ret = btrfs_add_block_group_cache(root->fs_info, cache);
-		BUG_ON(ret);
+		BUG_ON(ret); /* Logic error */
 
 		set_avail_alloc_bits(root->fs_info, cache->flags);
 		if (btrfs_chunk_readonly(root, cache->key.objectid))
@@ -7663,7 +7749,7 @@
 
 	ret = update_space_info(root->fs_info, cache->flags, size, bytes_used,
 				&cache->space_info);
-	BUG_ON(ret);
+	BUG_ON(ret); /* -ENOMEM */
 	update_global_block_rsv(root->fs_info);
 
 	spin_lock(&cache->space_info->lock);
@@ -7673,11 +7759,14 @@
 	__link_block_group(cache->space_info, cache);
 
 	ret = btrfs_add_block_group_cache(root->fs_info, cache);
-	BUG_ON(ret);
+	BUG_ON(ret); /* Logic error */
 
 	ret = btrfs_insert_item(trans, extent_root, &cache->key, &cache->item,
 				sizeof(cache->item));
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_abort_transaction(trans, extent_root, ret);
+		return ret;
+	}
 
 	set_avail_alloc_bits(extent_root->fs_info, type);
 
@@ -7686,11 +7775,8 @@
 
 static void clear_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
 {
-	u64 extra_flags = flags & BTRFS_BLOCK_GROUP_PROFILE_MASK;
-
-	/* chunk -> extended profile */
-	if (extra_flags == 0)
-		extra_flags = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
+	u64 extra_flags = chunk_to_extended(flags) &
+				BTRFS_EXTENDED_PROFILE_MASK;
 
 	if (flags & BTRFS_BLOCK_GROUP_DATA)
 		fs_info->avail_data_alloc_bits &= ~extra_flags;
@@ -7758,7 +7844,10 @@
 	inode = lookup_free_space_inode(tree_root, block_group, path);
 	if (!IS_ERR(inode)) {
 		ret = btrfs_orphan_add(trans, inode);
-		BUG_ON(ret);
+		if (ret) {
+			btrfs_add_delayed_iput(inode);
+			goto out;
+		}
 		clear_nlink(inode);
 		/* One for the block groups ref */
 		spin_lock(&block_group->lock);
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 2862454..8d904dd 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -19,6 +19,7 @@
 #include "btrfs_inode.h"
 #include "volumes.h"
 #include "check-integrity.h"
+#include "locking.h"
 
 static struct kmem_cache *extent_state_cache;
 static struct kmem_cache *extent_buffer_cache;
@@ -53,6 +54,13 @@
 	unsigned int sync_io:1;
 };
 
+static noinline void flush_write_bio(void *data);
+static inline struct btrfs_fs_info *
+tree_fs_info(struct extent_io_tree *tree)
+{
+	return btrfs_sb(tree->mapping->host->i_sb);
+}
+
 int __init extent_io_init(void)
 {
 	extent_state_cache = kmem_cache_create("extent_state",
@@ -136,6 +144,7 @@
 #endif
 	atomic_set(&state->refs, 1);
 	init_waitqueue_head(&state->wq);
+	trace_alloc_extent_state(state, mask, _RET_IP_);
 	return state;
 }
 
@@ -153,6 +162,7 @@
 		list_del(&state->leak_list);
 		spin_unlock_irqrestore(&leak_lock, flags);
 #endif
+		trace_free_extent_state(state, _RET_IP_);
 		kmem_cache_free(extent_state_cache, state);
 	}
 }
@@ -439,6 +449,13 @@
 	return prealloc;
 }
 
+void extent_io_tree_panic(struct extent_io_tree *tree, int err)
+{
+	btrfs_panic(tree_fs_info(tree), err, "Locking error: "
+		    "Extent tree was modified by another "
+		    "thread while locked.");
+}
+
 /*
  * clear some bits on a range in the tree.  This may require splitting
  * or inserting elements in the tree, so the gfp mask is used to
@@ -449,8 +466,7 @@
  *
  * the range [start, end] is inclusive.
  *
- * This takes the tree lock, and returns < 0 on error, > 0 if any of the
- * bits were already set, or zero if none of the bits were already set.
+ * This takes the tree lock, and returns 0 on success and < 0 on error.
  */
 int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
 		     int bits, int wake, int delete,
@@ -464,7 +480,6 @@
 	struct rb_node *node;
 	u64 last_end;
 	int err;
-	int set = 0;
 	int clear = 0;
 
 	if (delete)
@@ -542,12 +557,14 @@
 		prealloc = alloc_extent_state_atomic(prealloc);
 		BUG_ON(!prealloc);
 		err = split_state(tree, state, prealloc, start);
-		BUG_ON(err == -EEXIST);
+		if (err)
+			extent_io_tree_panic(tree, err);
+
 		prealloc = NULL;
 		if (err)
 			goto out;
 		if (state->end <= end) {
-			set |= clear_state_bit(tree, state, &bits, wake);
+			clear_state_bit(tree, state, &bits, wake);
 			if (last_end == (u64)-1)
 				goto out;
 			start = last_end + 1;
@@ -564,17 +581,19 @@
 		prealloc = alloc_extent_state_atomic(prealloc);
 		BUG_ON(!prealloc);
 		err = split_state(tree, state, prealloc, end + 1);
-		BUG_ON(err == -EEXIST);
+		if (err)
+			extent_io_tree_panic(tree, err);
+
 		if (wake)
 			wake_up(&state->wq);
 
-		set |= clear_state_bit(tree, prealloc, &bits, wake);
+		clear_state_bit(tree, prealloc, &bits, wake);
 
 		prealloc = NULL;
 		goto out;
 	}
 
-	set |= clear_state_bit(tree, state, &bits, wake);
+	clear_state_bit(tree, state, &bits, wake);
 next:
 	if (last_end == (u64)-1)
 		goto out;
@@ -591,7 +610,7 @@
 	if (prealloc)
 		free_extent_state(prealloc);
 
-	return set;
+	return 0;
 
 search_again:
 	if (start > end)
@@ -602,8 +621,8 @@
 	goto again;
 }
 
-static int wait_on_state(struct extent_io_tree *tree,
-			 struct extent_state *state)
+static void wait_on_state(struct extent_io_tree *tree,
+			  struct extent_state *state)
 		__releases(tree->lock)
 		__acquires(tree->lock)
 {
@@ -613,7 +632,6 @@
 	schedule();
 	spin_lock(&tree->lock);
 	finish_wait(&state->wq, &wait);
-	return 0;
 }
 
 /*
@@ -621,7 +639,7 @@
  * The range [start, end] is inclusive.
  * The tree lock is taken by this function
  */
-int wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits)
+void wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits)
 {
 	struct extent_state *state;
 	struct rb_node *node;
@@ -658,7 +676,6 @@
 	}
 out:
 	spin_unlock(&tree->lock);
-	return 0;
 }
 
 static void set_state_bits(struct extent_io_tree *tree,
@@ -706,9 +723,10 @@
  * [start, end] is inclusive This takes the tree lock.
  */
 
-int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
-		   int bits, int exclusive_bits, u64 *failed_start,
-		   struct extent_state **cached_state, gfp_t mask)
+static int __must_check
+__set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
+		 int bits, int exclusive_bits, u64 *failed_start,
+		 struct extent_state **cached_state, gfp_t mask)
 {
 	struct extent_state *state;
 	struct extent_state *prealloc = NULL;
@@ -742,8 +760,10 @@
 		prealloc = alloc_extent_state_atomic(prealloc);
 		BUG_ON(!prealloc);
 		err = insert_state(tree, prealloc, start, end, &bits);
+		if (err)
+			extent_io_tree_panic(tree, err);
+
 		prealloc = NULL;
-		BUG_ON(err == -EEXIST);
 		goto out;
 	}
 	state = rb_entry(node, struct extent_state, rb_node);
@@ -809,7 +829,9 @@
 		prealloc = alloc_extent_state_atomic(prealloc);
 		BUG_ON(!prealloc);
 		err = split_state(tree, state, prealloc, start);
-		BUG_ON(err == -EEXIST);
+		if (err)
+			extent_io_tree_panic(tree, err);
+
 		prealloc = NULL;
 		if (err)
 			goto out;
@@ -846,12 +868,9 @@
 		 */
 		err = insert_state(tree, prealloc, start, this_end,
 				   &bits);
-		BUG_ON(err == -EEXIST);
-		if (err) {
-			free_extent_state(prealloc);
-			prealloc = NULL;
-			goto out;
-		}
+		if (err)
+			extent_io_tree_panic(tree, err);
+
 		cache_state(prealloc, cached_state);
 		prealloc = NULL;
 		start = this_end + 1;
@@ -873,7 +892,8 @@
 		prealloc = alloc_extent_state_atomic(prealloc);
 		BUG_ON(!prealloc);
 		err = split_state(tree, state, prealloc, end + 1);
-		BUG_ON(err == -EEXIST);
+		if (err)
+			extent_io_tree_panic(tree, err);
 
 		set_state_bits(tree, prealloc, &bits);
 		cache_state(prealloc, cached_state);
@@ -900,6 +920,15 @@
 	goto again;
 }
 
+int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits,
+		   u64 *failed_start, struct extent_state **cached_state,
+		   gfp_t mask)
+{
+	return __set_extent_bit(tree, start, end, bits, 0, failed_start,
+				cached_state, mask);
+}
+
+
 /**
  * convert_extent - convert all bits in a given range from one bit to another
  * @tree:	the io tree to search
@@ -946,7 +975,8 @@
 		}
 		err = insert_state(tree, prealloc, start, end, &bits);
 		prealloc = NULL;
-		BUG_ON(err == -EEXIST);
+		if (err)
+			extent_io_tree_panic(tree, err);
 		goto out;
 	}
 	state = rb_entry(node, struct extent_state, rb_node);
@@ -1002,7 +1032,8 @@
 			goto out;
 		}
 		err = split_state(tree, state, prealloc, start);
-		BUG_ON(err == -EEXIST);
+		if (err)
+			extent_io_tree_panic(tree, err);
 		prealloc = NULL;
 		if (err)
 			goto out;
@@ -1041,12 +1072,8 @@
 		 */
 		err = insert_state(tree, prealloc, start, this_end,
 				   &bits);
-		BUG_ON(err == -EEXIST);
-		if (err) {
-			free_extent_state(prealloc);
-			prealloc = NULL;
-			goto out;
-		}
+		if (err)
+			extent_io_tree_panic(tree, err);
 		prealloc = NULL;
 		start = this_end + 1;
 		goto search_again;
@@ -1065,7 +1092,8 @@
 		}
 
 		err = split_state(tree, state, prealloc, end + 1);
-		BUG_ON(err == -EEXIST);
+		if (err)
+			extent_io_tree_panic(tree, err);
 
 		set_state_bits(tree, prealloc, &bits);
 		clear_state_bit(tree, prealloc, &clear_bits, 0);
@@ -1095,14 +1123,14 @@
 int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
 		     gfp_t mask)
 {
-	return set_extent_bit(tree, start, end, EXTENT_DIRTY, 0, NULL,
+	return set_extent_bit(tree, start, end, EXTENT_DIRTY, NULL,
 			      NULL, mask);
 }
 
 int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
 		    int bits, gfp_t mask)
 {
-	return set_extent_bit(tree, start, end, bits, 0, NULL,
+	return set_extent_bit(tree, start, end, bits, NULL,
 			      NULL, mask);
 }
 
@@ -1117,7 +1145,7 @@
 {
 	return set_extent_bit(tree, start, end,
 			      EXTENT_DELALLOC | EXTENT_UPTODATE,
-			      0, NULL, cached_state, mask);
+			      NULL, cached_state, mask);
 }
 
 int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
@@ -1131,7 +1159,7 @@
 int set_extent_new(struct extent_io_tree *tree, u64 start, u64 end,
 		     gfp_t mask)
 {
-	return set_extent_bit(tree, start, end, EXTENT_NEW, 0, NULL,
+	return set_extent_bit(tree, start, end, EXTENT_NEW, NULL,
 			      NULL, mask);
 }
 
@@ -1139,7 +1167,7 @@
 			struct extent_state **cached_state, gfp_t mask)
 {
 	return set_extent_bit(tree, start, end, EXTENT_UPTODATE, 0,
-			      NULL, cached_state, mask);
+			      cached_state, mask);
 }
 
 static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start,
@@ -1155,42 +1183,40 @@
  * us if waiting is desired.
  */
 int lock_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
-		     int bits, struct extent_state **cached_state, gfp_t mask)
+		     int bits, struct extent_state **cached_state)
 {
 	int err;
 	u64 failed_start;
 	while (1) {
-		err = set_extent_bit(tree, start, end, EXTENT_LOCKED | bits,
-				     EXTENT_LOCKED, &failed_start,
-				     cached_state, mask);
-		if (err == -EEXIST && (mask & __GFP_WAIT)) {
+		err = __set_extent_bit(tree, start, end, EXTENT_LOCKED | bits,
+				       EXTENT_LOCKED, &failed_start,
+				       cached_state, GFP_NOFS);
+		if (err == -EEXIST) {
 			wait_extent_bit(tree, failed_start, end, EXTENT_LOCKED);
 			start = failed_start;
-		} else {
+		} else
 			break;
-		}
 		WARN_ON(start > end);
 	}
 	return err;
 }
 
-int lock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask)
+int lock_extent(struct extent_io_tree *tree, u64 start, u64 end)
 {
-	return lock_extent_bits(tree, start, end, 0, NULL, mask);
+	return lock_extent_bits(tree, start, end, 0, NULL);
 }
 
-int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
-		    gfp_t mask)
+int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end)
 {
 	int err;
 	u64 failed_start;
 
-	err = set_extent_bit(tree, start, end, EXTENT_LOCKED, EXTENT_LOCKED,
-			     &failed_start, NULL, mask);
+	err = __set_extent_bit(tree, start, end, EXTENT_LOCKED, EXTENT_LOCKED,
+			       &failed_start, NULL, GFP_NOFS);
 	if (err == -EEXIST) {
 		if (failed_start > start)
 			clear_extent_bit(tree, start, failed_start - 1,
-					 EXTENT_LOCKED, 1, 0, NULL, mask);
+					 EXTENT_LOCKED, 1, 0, NULL, GFP_NOFS);
 		return 0;
 	}
 	return 1;
@@ -1203,10 +1229,10 @@
 				mask);
 }
 
-int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask)
+int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end)
 {
 	return clear_extent_bit(tree, start, end, EXTENT_LOCKED, 1, 0, NULL,
-				mask);
+				GFP_NOFS);
 }
 
 /*
@@ -1220,7 +1246,7 @@
 
 	while (index <= end_index) {
 		page = find_get_page(tree->mapping, index);
-		BUG_ON(!page);
+		BUG_ON(!page); /* Pages should be in the extent_io_tree */
 		set_page_writeback(page);
 		page_cache_release(page);
 		index++;
@@ -1343,9 +1369,9 @@
 	return found;
 }
 
-static noinline int __unlock_for_delalloc(struct inode *inode,
-					  struct page *locked_page,
-					  u64 start, u64 end)
+static noinline void __unlock_for_delalloc(struct inode *inode,
+					   struct page *locked_page,
+					   u64 start, u64 end)
 {
 	int ret;
 	struct page *pages[16];
@@ -1355,7 +1381,7 @@
 	int i;
 
 	if (index == locked_page->index && end_index == index)
-		return 0;
+		return;
 
 	while (nr_pages > 0) {
 		ret = find_get_pages_contig(inode->i_mapping, index,
@@ -1370,7 +1396,6 @@
 		index += ret;
 		cond_resched();
 	}
-	return 0;
 }
 
 static noinline int lock_delalloc_pages(struct inode *inode,
@@ -1500,11 +1525,10 @@
 			goto out_failed;
 		}
 	}
-	BUG_ON(ret);
+	BUG_ON(ret); /* Only valid values are 0 and -EAGAIN */
 
 	/* step three, lock the state bits for the whole range */
-	lock_extent_bits(tree, delalloc_start, delalloc_end,
-			 0, &cached_state, GFP_NOFS);
+	lock_extent_bits(tree, delalloc_start, delalloc_end, 0, &cached_state);
 
 	/* then test to make sure it is all still delalloc */
 	ret = test_range_bit(tree, delalloc_start, delalloc_end,
@@ -1761,39 +1785,34 @@
  * helper function to set a given page up to date if all the
  * extents in the tree for that page are up to date
  */
-static int check_page_uptodate(struct extent_io_tree *tree,
-			       struct page *page)
+static void check_page_uptodate(struct extent_io_tree *tree, struct page *page)
 {
 	u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
 	u64 end = start + PAGE_CACHE_SIZE - 1;
 	if (test_range_bit(tree, start, end, EXTENT_UPTODATE, 1, NULL))
 		SetPageUptodate(page);
-	return 0;
 }
 
 /*
  * helper function to unlock a page if all the extents in the tree
  * for that page are unlocked
  */
-static int check_page_locked(struct extent_io_tree *tree,
-			     struct page *page)
+static void check_page_locked(struct extent_io_tree *tree, struct page *page)
 {
 	u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
 	u64 end = start + PAGE_CACHE_SIZE - 1;
 	if (!test_range_bit(tree, start, end, EXTENT_LOCKED, 0, NULL))
 		unlock_page(page);
-	return 0;
 }
 
 /*
  * helper function to end page writeback if all the extents
  * in the tree for that page are done with writeback
  */
-static int check_page_writeback(struct extent_io_tree *tree,
-			     struct page *page)
+static void check_page_writeback(struct extent_io_tree *tree,
+				 struct page *page)
 {
 	end_page_writeback(page);
-	return 0;
 }
 
 /*
@@ -1912,6 +1931,26 @@
 	return 0;
 }
 
+int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb,
+			 int mirror_num)
+{
+	struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree;
+	u64 start = eb->start;
+	unsigned long i, num_pages = num_extent_pages(eb->start, eb->len);
+	int ret;
+
+	for (i = 0; i < num_pages; i++) {
+		struct page *p = extent_buffer_page(eb, i);
+		ret = repair_io_failure(map_tree, start, PAGE_CACHE_SIZE,
+					start, p, mirror_num);
+		if (ret)
+			break;
+		start += PAGE_CACHE_SIZE;
+	}
+
+	return ret;
+}
+
 /*
  * each time an IO finishes, we do a fast check in the IO failure tree
  * to see if we need to process or clean up an io_failure_record
@@ -2258,6 +2297,7 @@
 	u64 start;
 	u64 end;
 	int whole_page;
+	int failed_mirror;
 	int ret;
 
 	if (err)
@@ -2304,9 +2344,16 @@
 			else
 				clean_io_failure(start, page);
 		}
-		if (!uptodate) {
-			int failed_mirror;
+
+		if (!uptodate)
 			failed_mirror = (int)(unsigned long)bio->bi_bdev;
+
+		if (!uptodate && tree->ops && tree->ops->readpage_io_failed_hook) {
+			ret = tree->ops->readpage_io_failed_hook(page, failed_mirror);
+			if (!ret && !err &&
+			    test_bit(BIO_UPTODATE, &bio->bi_flags))
+				uptodate = 1;
+		} else if (!uptodate) {
 			/*
 			 * The generic bio_readpage_error handles errors the
 			 * following way: If possible, new read requests are
@@ -2320,7 +2367,6 @@
 			ret = bio_readpage_error(bio, page, start, end,
 							failed_mirror, NULL);
 			if (ret == 0) {
-error_handled:
 				uptodate =
 					test_bit(BIO_UPTODATE, &bio->bi_flags);
 				if (err)
@@ -2328,16 +2374,9 @@
 				uncache_state(&cached);
 				continue;
 			}
-			if (tree->ops && tree->ops->readpage_io_failed_hook) {
-				ret = tree->ops->readpage_io_failed_hook(
-							bio, page, start, end,
-							failed_mirror, state);
-				if (ret == 0)
-					goto error_handled;
-			}
 		}
 
-		if (uptodate) {
+		if (uptodate && tree->track_uptodate) {
 			set_extent_uptodate(tree, start, end, &cached,
 					    GFP_ATOMIC);
 		}
@@ -2386,8 +2425,12 @@
 	return bio;
 }
 
-static int submit_one_bio(int rw, struct bio *bio, int mirror_num,
-			  unsigned long bio_flags)
+/*
+ * Since writes are async, they will only return -ENOMEM.
+ * Reads can return the full range of I/O error conditions.
+ */
+static int __must_check submit_one_bio(int rw, struct bio *bio,
+				       int mirror_num, unsigned long bio_flags)
 {
 	int ret = 0;
 	struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
@@ -2413,6 +2456,19 @@
 	return ret;
 }
 
+static int merge_bio(struct extent_io_tree *tree, struct page *page,
+		     unsigned long offset, size_t size, struct bio *bio,
+		     unsigned long bio_flags)
+{
+	int ret = 0;
+	if (tree->ops && tree->ops->merge_bio_hook)
+		ret = tree->ops->merge_bio_hook(page, offset, size, bio,
+						bio_flags);
+	BUG_ON(ret < 0);
+	return ret;
+
+}
+
 static int submit_extent_page(int rw, struct extent_io_tree *tree,
 			      struct page *page, sector_t sector,
 			      size_t size, unsigned long offset,
@@ -2441,12 +2497,12 @@
 				sector;
 
 		if (prev_bio_flags != bio_flags || !contig ||
-		    (tree->ops && tree->ops->merge_bio_hook &&
-		     tree->ops->merge_bio_hook(page, offset, page_size, bio,
-					       bio_flags)) ||
+		    merge_bio(tree, page, offset, page_size, bio, bio_flags) ||
 		    bio_add_page(bio, page, page_size, offset) < page_size) {
 			ret = submit_one_bio(rw, bio, mirror_num,
 					     prev_bio_flags);
+			if (ret < 0)
+				return ret;
 			bio = NULL;
 		} else {
 			return 0;
@@ -2473,6 +2529,17 @@
 	return ret;
 }
 
+void attach_extent_buffer_page(struct extent_buffer *eb, struct page *page)
+{
+	if (!PagePrivate(page)) {
+		SetPagePrivate(page);
+		page_cache_get(page);
+		set_page_private(page, (unsigned long)eb);
+	} else {
+		WARN_ON(page->private != (unsigned long)eb);
+	}
+}
+
 void set_page_extent_mapped(struct page *page)
 {
 	if (!PagePrivate(page)) {
@@ -2482,16 +2549,11 @@
 	}
 }
 
-static void set_page_extent_head(struct page *page, unsigned long len)
-{
-	WARN_ON(!PagePrivate(page));
-	set_page_private(page, EXTENT_PAGE_PRIVATE_FIRST_PAGE | len << 2);
-}
-
 /*
  * basic readpage implementation.  Locked extent state structs are inserted
  * into the tree that are removed when the IO is done (by the end_io
  * handlers)
+ * XXX JDM: This needs looking at to ensure proper page locking
  */
 static int __extent_read_full_page(struct extent_io_tree *tree,
 				   struct page *page,
@@ -2531,11 +2593,11 @@
 
 	end = page_end;
 	while (1) {
-		lock_extent(tree, start, end, GFP_NOFS);
+		lock_extent(tree, start, end);
 		ordered = btrfs_lookup_ordered_extent(inode, start);
 		if (!ordered)
 			break;
-		unlock_extent(tree, start, end, GFP_NOFS);
+		unlock_extent(tree, start, end);
 		btrfs_start_ordered_extent(inode, ordered, 1);
 		btrfs_put_ordered_extent(ordered);
 	}
@@ -2572,7 +2634,7 @@
 				end - cur + 1, 0);
 		if (IS_ERR_OR_NULL(em)) {
 			SetPageError(page);
-			unlock_extent(tree, cur, end, GFP_NOFS);
+			unlock_extent(tree, cur, end);
 			break;
 		}
 		extent_offset = cur - em->start;
@@ -2624,7 +2686,7 @@
 		if (test_range_bit(tree, cur, cur_end,
 				   EXTENT_UPTODATE, 1, NULL)) {
 			check_page_uptodate(tree, page);
-			unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS);
+			unlock_extent(tree, cur, cur + iosize - 1);
 			cur = cur + iosize;
 			pg_offset += iosize;
 			continue;
@@ -2634,7 +2696,7 @@
 		 */
 		if (block_start == EXTENT_MAP_INLINE) {
 			SetPageError(page);
-			unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS);
+			unlock_extent(tree, cur, cur + iosize - 1);
 			cur = cur + iosize;
 			pg_offset += iosize;
 			continue;
@@ -2654,6 +2716,7 @@
 					 end_bio_extent_readpage, mirror_num,
 					 *bio_flags,
 					 this_bio_flag);
+			BUG_ON(ret == -ENOMEM);
 			nr++;
 			*bio_flags = this_bio_flag;
 		}
@@ -2795,7 +2858,11 @@
 						       delalloc_end,
 						       &page_started,
 						       &nr_written);
-			BUG_ON(ret);
+			/* File system has been set read-only */
+			if (ret) {
+				SetPageError(page);
+				goto done;
+			}
 			/*
 			 * delalloc_end is already one less than the total
 			 * length, so we don't subtract one from
@@ -2968,6 +3035,275 @@
 	return 0;
 }
 
+static int eb_wait(void *word)
+{
+	io_schedule();
+	return 0;
+}
+
+static void wait_on_extent_buffer_writeback(struct extent_buffer *eb)
+{
+	wait_on_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK, eb_wait,
+		    TASK_UNINTERRUPTIBLE);
+}
+
+static int lock_extent_buffer_for_io(struct extent_buffer *eb,
+				     struct btrfs_fs_info *fs_info,
+				     struct extent_page_data *epd)
+{
+	unsigned long i, num_pages;
+	int flush = 0;
+	int ret = 0;
+
+	if (!btrfs_try_tree_write_lock(eb)) {
+		flush = 1;
+		flush_write_bio(epd);
+		btrfs_tree_lock(eb);
+	}
+
+	if (test_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags)) {
+		btrfs_tree_unlock(eb);
+		if (!epd->sync_io)
+			return 0;
+		if (!flush) {
+			flush_write_bio(epd);
+			flush = 1;
+		}
+		while (1) {
+			wait_on_extent_buffer_writeback(eb);
+			btrfs_tree_lock(eb);
+			if (!test_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags))
+				break;
+			btrfs_tree_unlock(eb);
+		}
+	}
+
+	if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) {
+		set_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags);
+		btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
+		spin_lock(&fs_info->delalloc_lock);
+		if (fs_info->dirty_metadata_bytes >= eb->len)
+			fs_info->dirty_metadata_bytes -= eb->len;
+		else
+			WARN_ON(1);
+		spin_unlock(&fs_info->delalloc_lock);
+		ret = 1;
+	}
+
+	btrfs_tree_unlock(eb);
+
+	if (!ret)
+		return ret;
+
+	num_pages = num_extent_pages(eb->start, eb->len);
+	for (i = 0; i < num_pages; i++) {
+		struct page *p = extent_buffer_page(eb, i);
+
+		if (!trylock_page(p)) {
+			if (!flush) {
+				flush_write_bio(epd);
+				flush = 1;
+			}
+			lock_page(p);
+		}
+	}
+
+	return ret;
+}
+
+static void end_extent_buffer_writeback(struct extent_buffer *eb)
+{
+	clear_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags);
+	smp_mb__after_clear_bit();
+	wake_up_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK);
+}
+
+static void end_bio_extent_buffer_writepage(struct bio *bio, int err)
+{
+	int uptodate = err == 0;
+	struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+	struct extent_buffer *eb;
+	int done;
+
+	do {
+		struct page *page = bvec->bv_page;
+
+		bvec--;
+		eb = (struct extent_buffer *)page->private;
+		BUG_ON(!eb);
+		done = atomic_dec_and_test(&eb->io_pages);
+
+		if (!uptodate || test_bit(EXTENT_BUFFER_IOERR, &eb->bflags)) {
+			set_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
+			ClearPageUptodate(page);
+			SetPageError(page);
+		}
+
+		end_page_writeback(page);
+
+		if (!done)
+			continue;
+
+		end_extent_buffer_writeback(eb);
+	} while (bvec >= bio->bi_io_vec);
+
+	bio_put(bio);
+
+}
+
+static int write_one_eb(struct extent_buffer *eb,
+			struct btrfs_fs_info *fs_info,
+			struct writeback_control *wbc,
+			struct extent_page_data *epd)
+{
+	struct block_device *bdev = fs_info->fs_devices->latest_bdev;
+	u64 offset = eb->start;
+	unsigned long i, num_pages;
+	int rw = (epd->sync_io ? WRITE_SYNC : WRITE);
+	int ret;
+
+	clear_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
+	num_pages = num_extent_pages(eb->start, eb->len);
+	atomic_set(&eb->io_pages, num_pages);
+	for (i = 0; i < num_pages; i++) {
+		struct page *p = extent_buffer_page(eb, i);
+
+		clear_page_dirty_for_io(p);
+		set_page_writeback(p);
+		ret = submit_extent_page(rw, eb->tree, p, offset >> 9,
+					 PAGE_CACHE_SIZE, 0, bdev, &epd->bio,
+					 -1, end_bio_extent_buffer_writepage,
+					 0, 0, 0);
+		if (ret) {
+			set_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
+			SetPageError(p);
+			if (atomic_sub_and_test(num_pages - i, &eb->io_pages))
+				end_extent_buffer_writeback(eb);
+			ret = -EIO;
+			break;
+		}
+		offset += PAGE_CACHE_SIZE;
+		update_nr_written(p, wbc, 1);
+		unlock_page(p);
+	}
+
+	if (unlikely(ret)) {
+		for (; i < num_pages; i++) {
+			struct page *p = extent_buffer_page(eb, i);
+			unlock_page(p);
+		}
+	}
+
+	return ret;
+}
+
+int btree_write_cache_pages(struct address_space *mapping,
+				   struct writeback_control *wbc)
+{
+	struct extent_io_tree *tree = &BTRFS_I(mapping->host)->io_tree;
+	struct btrfs_fs_info *fs_info = BTRFS_I(mapping->host)->root->fs_info;
+	struct extent_buffer *eb, *prev_eb = NULL;
+	struct extent_page_data epd = {
+		.bio = NULL,
+		.tree = tree,
+		.extent_locked = 0,
+		.sync_io = wbc->sync_mode == WB_SYNC_ALL,
+	};
+	int ret = 0;
+	int done = 0;
+	int nr_to_write_done = 0;
+	struct pagevec pvec;
+	int nr_pages;
+	pgoff_t index;
+	pgoff_t end;		/* Inclusive */
+	int scanned = 0;
+	int tag;
+
+	pagevec_init(&pvec, 0);
+	if (wbc->range_cyclic) {
+		index = mapping->writeback_index; /* Start from prev offset */
+		end = -1;
+	} else {
+		index = wbc->range_start >> PAGE_CACHE_SHIFT;
+		end = wbc->range_end >> PAGE_CACHE_SHIFT;
+		scanned = 1;
+	}
+	if (wbc->sync_mode == WB_SYNC_ALL)
+		tag = PAGECACHE_TAG_TOWRITE;
+	else
+		tag = PAGECACHE_TAG_DIRTY;
+retry:
+	if (wbc->sync_mode == WB_SYNC_ALL)
+		tag_pages_for_writeback(mapping, index, end);
+	while (!done && !nr_to_write_done && (index <= end) &&
+	       (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag,
+			min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
+		unsigned i;
+
+		scanned = 1;
+		for (i = 0; i < nr_pages; i++) {
+			struct page *page = pvec.pages[i];
+
+			if (!PagePrivate(page))
+				continue;
+
+			if (!wbc->range_cyclic && page->index > end) {
+				done = 1;
+				break;
+			}
+
+			eb = (struct extent_buffer *)page->private;
+			if (!eb) {
+				WARN_ON(1);
+				continue;
+			}
+
+			if (eb == prev_eb)
+				continue;
+
+			if (!atomic_inc_not_zero(&eb->refs)) {
+				WARN_ON(1);
+				continue;
+			}
+
+			prev_eb = eb;
+			ret = lock_extent_buffer_for_io(eb, fs_info, &epd);
+			if (!ret) {
+				free_extent_buffer(eb);
+				continue;
+			}
+
+			ret = write_one_eb(eb, fs_info, wbc, &epd);
+			if (ret) {
+				done = 1;
+				free_extent_buffer(eb);
+				break;
+			}
+			free_extent_buffer(eb);
+
+			/*
+			 * the filesystem may choose to bump up nr_to_write.
+			 * We have to make sure to honor the new nr_to_write
+			 * at any time
+			 */
+			nr_to_write_done = wbc->nr_to_write <= 0;
+		}
+		pagevec_release(&pvec);
+		cond_resched();
+	}
+	if (!scanned && !done) {
+		/*
+		 * We hit the last page and there is more work to be done: wrap
+		 * back to the start of the file
+		 */
+		scanned = 1;
+		index = 0;
+		goto retry;
+	}
+	flush_write_bio(&epd);
+	return ret;
+}
+
 /**
  * write_cache_pages - walk the list of dirty pages of the given address space and write all of them.
  * @mapping: address space structure to write
@@ -3099,10 +3435,14 @@
 static void flush_epd_write_bio(struct extent_page_data *epd)
 {
 	if (epd->bio) {
+		int rw = WRITE;
+		int ret;
+
 		if (epd->sync_io)
-			submit_one_bio(WRITE_SYNC, epd->bio, 0, 0);
-		else
-			submit_one_bio(WRITE, epd->bio, 0, 0);
+			rw = WRITE_SYNC;
+
+		ret = submit_one_bio(rw, epd->bio, 0, 0);
+		BUG_ON(ret < 0); /* -ENOMEM */
 		epd->bio = NULL;
 	}
 }
@@ -3219,7 +3559,7 @@
 	}
 	BUG_ON(!list_empty(pages));
 	if (bio)
-		submit_one_bio(READ, bio, 0, bio_flags);
+		return submit_one_bio(READ, bio, 0, bio_flags);
 	return 0;
 }
 
@@ -3240,7 +3580,7 @@
 	if (start > end)
 		return 0;
 
-	lock_extent_bits(tree, start, end, 0, &cached_state, GFP_NOFS);
+	lock_extent_bits(tree, start, end, 0, &cached_state);
 	wait_on_page_writeback(page);
 	clear_extent_bit(tree, start, end,
 			 EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC |
@@ -3454,7 +3794,7 @@
 	}
 
 	lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0,
-			 &cached_state, GFP_NOFS);
+			 &cached_state);
 
 	em = get_extent_skip_holes(inode, start, last_for_get_extent,
 				   get_extent);
@@ -3548,26 +3888,7 @@
 inline struct page *extent_buffer_page(struct extent_buffer *eb,
 					      unsigned long i)
 {
-	struct page *p;
-	struct address_space *mapping;
-
-	if (i == 0)
-		return eb->first_page;
-	i += eb->start >> PAGE_CACHE_SHIFT;
-	mapping = eb->first_page->mapping;
-	if (!mapping)
-		return NULL;
-
-	/*
-	 * extent_buffer_page is only called after pinning the page
-	 * by increasing the reference count.  So we know the page must
-	 * be in the radix tree.
-	 */
-	rcu_read_lock();
-	p = radix_tree_lookup(&mapping->page_tree, i);
-	rcu_read_unlock();
-
-	return p;
+	return eb->pages[i];
 }
 
 inline unsigned long num_extent_pages(u64 start, u64 len)
@@ -3576,6 +3897,19 @@
 		(start >> PAGE_CACHE_SHIFT);
 }
 
+static void __free_extent_buffer(struct extent_buffer *eb)
+{
+#if LEAK_DEBUG
+	unsigned long flags;
+	spin_lock_irqsave(&leak_lock, flags);
+	list_del(&eb->leak_list);
+	spin_unlock_irqrestore(&leak_lock, flags);
+#endif
+	if (eb->pages && eb->pages != eb->inline_pages)
+		kfree(eb->pages);
+	kmem_cache_free(extent_buffer_cache, eb);
+}
+
 static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree,
 						   u64 start,
 						   unsigned long len,
@@ -3591,6 +3925,7 @@
 		return NULL;
 	eb->start = start;
 	eb->len = len;
+	eb->tree = tree;
 	rwlock_init(&eb->lock);
 	atomic_set(&eb->write_locks, 0);
 	atomic_set(&eb->read_locks, 0);
@@ -3607,20 +3942,32 @@
 	list_add(&eb->leak_list, &buffers);
 	spin_unlock_irqrestore(&leak_lock, flags);
 #endif
+	spin_lock_init(&eb->refs_lock);
 	atomic_set(&eb->refs, 1);
+	atomic_set(&eb->io_pages, 0);
+
+	if (len > MAX_INLINE_EXTENT_BUFFER_SIZE) {
+		struct page **pages;
+		int num_pages = (len + PAGE_CACHE_SIZE - 1) >>
+			PAGE_CACHE_SHIFT;
+		pages = kzalloc(num_pages, mask);
+		if (!pages) {
+			__free_extent_buffer(eb);
+			return NULL;
+		}
+		eb->pages = pages;
+	} else {
+		eb->pages = eb->inline_pages;
+	}
 
 	return eb;
 }
 
-static void __free_extent_buffer(struct extent_buffer *eb)
+static int extent_buffer_under_io(struct extent_buffer *eb)
 {
-#if LEAK_DEBUG
-	unsigned long flags;
-	spin_lock_irqsave(&leak_lock, flags);
-	list_del(&eb->leak_list);
-	spin_unlock_irqrestore(&leak_lock, flags);
-#endif
-	kmem_cache_free(extent_buffer_cache, eb);
+	return (atomic_read(&eb->io_pages) ||
+		test_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags) ||
+		test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags));
 }
 
 /*
@@ -3632,8 +3979,7 @@
 	unsigned long index;
 	struct page *page;
 
-	if (!eb->first_page)
-		return;
+	BUG_ON(extent_buffer_under_io(eb));
 
 	index = num_extent_pages(eb->start, eb->len);
 	if (start_idx >= index)
@@ -3642,8 +3988,34 @@
 	do {
 		index--;
 		page = extent_buffer_page(eb, index);
-		if (page)
+		if (page) {
+			spin_lock(&page->mapping->private_lock);
+			/*
+			 * We do this since we'll remove the pages after we've
+			 * removed the eb from the radix tree, so we could race
+			 * and have this page now attached to the new eb.  So
+			 * only clear page_private if it's still connected to
+			 * this eb.
+			 */
+			if (PagePrivate(page) &&
+			    page->private == (unsigned long)eb) {
+				BUG_ON(test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags));
+				BUG_ON(PageDirty(page));
+				BUG_ON(PageWriteback(page));
+				/*
+				 * We need to make sure we haven't be attached
+				 * to a new eb.
+				 */
+				ClearPagePrivate(page);
+				set_page_private(page, 0);
+				/* One for the page private */
+				page_cache_release(page);
+			}
+			spin_unlock(&page->mapping->private_lock);
+
+			/* One for when we alloced the page */
 			page_cache_release(page);
+		}
 	} while (index != start_idx);
 }
 
@@ -3656,9 +4028,50 @@
 	__free_extent_buffer(eb);
 }
 
+static void check_buffer_tree_ref(struct extent_buffer *eb)
+{
+	/* the ref bit is tricky.  We have to make sure it is set
+	 * if we have the buffer dirty.   Otherwise the
+	 * code to free a buffer can end up dropping a dirty
+	 * page
+	 *
+	 * Once the ref bit is set, it won't go away while the
+	 * buffer is dirty or in writeback, and it also won't
+	 * go away while we have the reference count on the
+	 * eb bumped.
+	 *
+	 * We can't just set the ref bit without bumping the
+	 * ref on the eb because free_extent_buffer might
+	 * see the ref bit and try to clear it.  If this happens
+	 * free_extent_buffer might end up dropping our original
+	 * ref by mistake and freeing the page before we are able
+	 * to add one more ref.
+	 *
+	 * So bump the ref count first, then set the bit.  If someone
+	 * beat us to it, drop the ref we added.
+	 */
+	if (!test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)) {
+		atomic_inc(&eb->refs);
+		if (test_and_set_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
+			atomic_dec(&eb->refs);
+	}
+}
+
+static void mark_extent_buffer_accessed(struct extent_buffer *eb)
+{
+	unsigned long num_pages, i;
+
+	check_buffer_tree_ref(eb);
+
+	num_pages = num_extent_pages(eb->start, eb->len);
+	for (i = 0; i < num_pages; i++) {
+		struct page *p = extent_buffer_page(eb, i);
+		mark_page_accessed(p);
+	}
+}
+
 struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
-					  u64 start, unsigned long len,
-					  struct page *page0)
+					  u64 start, unsigned long len)
 {
 	unsigned long num_pages = num_extent_pages(start, len);
 	unsigned long i;
@@ -3674,7 +4087,7 @@
 	eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT);
 	if (eb && atomic_inc_not_zero(&eb->refs)) {
 		rcu_read_unlock();
-		mark_page_accessed(eb->first_page);
+		mark_extent_buffer_accessed(eb);
 		return eb;
 	}
 	rcu_read_unlock();
@@ -3683,32 +4096,43 @@
 	if (!eb)
 		return NULL;
 
-	if (page0) {
-		eb->first_page = page0;
-		i = 1;
-		index++;
-		page_cache_get(page0);
-		mark_page_accessed(page0);
-		set_page_extent_mapped(page0);
-		set_page_extent_head(page0, len);
-		uptodate = PageUptodate(page0);
-	} else {
-		i = 0;
-	}
-	for (; i < num_pages; i++, index++) {
+	for (i = 0; i < num_pages; i++, index++) {
 		p = find_or_create_page(mapping, index, GFP_NOFS);
 		if (!p) {
 			WARN_ON(1);
 			goto free_eb;
 		}
-		set_page_extent_mapped(p);
-		mark_page_accessed(p);
-		if (i == 0) {
-			eb->first_page = p;
-			set_page_extent_head(p, len);
-		} else {
-			set_page_private(p, EXTENT_PAGE_PRIVATE);
+
+		spin_lock(&mapping->private_lock);
+		if (PagePrivate(p)) {
+			/*
+			 * We could have already allocated an eb for this page
+			 * and attached one so lets see if we can get a ref on
+			 * the existing eb, and if we can we know it's good and
+			 * we can just return that one, else we know we can just
+			 * overwrite page->private.
+			 */
+			exists = (struct extent_buffer *)p->private;
+			if (atomic_inc_not_zero(&exists->refs)) {
+				spin_unlock(&mapping->private_lock);
+				unlock_page(p);
+				mark_extent_buffer_accessed(exists);
+				goto free_eb;
+			}
+
+			/*
+			 * Do this so attach doesn't complain and we need to
+			 * drop the ref the old guy had.
+			 */
+			ClearPagePrivate(p);
+			WARN_ON(PageDirty(p));
+			page_cache_release(p);
 		}
+		attach_extent_buffer_page(eb, p);
+		spin_unlock(&mapping->private_lock);
+		WARN_ON(PageDirty(p));
+		mark_page_accessed(p);
+		eb->pages[i] = p;
 		if (!PageUptodate(p))
 			uptodate = 0;
 
@@ -3716,12 +4140,10 @@
 		 * see below about how we avoid a nasty race with release page
 		 * and why we unlock later
 		 */
-		if (i != 0)
-			unlock_page(p);
 	}
 	if (uptodate)
 		set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
-
+again:
 	ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM);
 	if (ret)
 		goto free_eb;
@@ -3731,14 +4153,21 @@
 	if (ret == -EEXIST) {
 		exists = radix_tree_lookup(&tree->buffer,
 						start >> PAGE_CACHE_SHIFT);
-		/* add one reference for the caller */
-		atomic_inc(&exists->refs);
+		if (!atomic_inc_not_zero(&exists->refs)) {
+			spin_unlock(&tree->buffer_lock);
+			radix_tree_preload_end();
+			exists = NULL;
+			goto again;
+		}
 		spin_unlock(&tree->buffer_lock);
 		radix_tree_preload_end();
+		mark_extent_buffer_accessed(exists);
 		goto free_eb;
 	}
 	/* add one reference for the tree */
-	atomic_inc(&eb->refs);
+	spin_lock(&eb->refs_lock);
+	check_buffer_tree_ref(eb);
+	spin_unlock(&eb->refs_lock);
 	spin_unlock(&tree->buffer_lock);
 	radix_tree_preload_end();
 
@@ -3751,15 +4180,20 @@
 	 * after the extent buffer is in the radix tree so
 	 * it doesn't get lost
 	 */
-	set_page_extent_mapped(eb->first_page);
-	set_page_extent_head(eb->first_page, eb->len);
-	if (!page0)
-		unlock_page(eb->first_page);
+	SetPageChecked(eb->pages[0]);
+	for (i = 1; i < num_pages; i++) {
+		p = extent_buffer_page(eb, i);
+		ClearPageChecked(p);
+		unlock_page(p);
+	}
+	unlock_page(eb->pages[0]);
 	return eb;
 
 free_eb:
-	if (eb->first_page && !page0)
-		unlock_page(eb->first_page);
+	for (i = 0; i < num_pages; i++) {
+		if (eb->pages[i])
+			unlock_page(eb->pages[i]);
+	}
 
 	if (!atomic_dec_and_test(&eb->refs))
 		return exists;
@@ -3776,7 +4210,7 @@
 	eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT);
 	if (eb && atomic_inc_not_zero(&eb->refs)) {
 		rcu_read_unlock();
-		mark_page_accessed(eb->first_page);
+		mark_extent_buffer_accessed(eb);
 		return eb;
 	}
 	rcu_read_unlock();
@@ -3784,19 +4218,71 @@
 	return NULL;
 }
 
+static inline void btrfs_release_extent_buffer_rcu(struct rcu_head *head)
+{
+	struct extent_buffer *eb =
+			container_of(head, struct extent_buffer, rcu_head);
+
+	__free_extent_buffer(eb);
+}
+
+/* Expects to have eb->eb_lock already held */
+static void release_extent_buffer(struct extent_buffer *eb, gfp_t mask)
+{
+	WARN_ON(atomic_read(&eb->refs) == 0);
+	if (atomic_dec_and_test(&eb->refs)) {
+		struct extent_io_tree *tree = eb->tree;
+
+		spin_unlock(&eb->refs_lock);
+
+		spin_lock(&tree->buffer_lock);
+		radix_tree_delete(&tree->buffer,
+				  eb->start >> PAGE_CACHE_SHIFT);
+		spin_unlock(&tree->buffer_lock);
+
+		/* Should be safe to release our pages at this point */
+		btrfs_release_extent_buffer_page(eb, 0);
+
+		call_rcu(&eb->rcu_head, btrfs_release_extent_buffer_rcu);
+		return;
+	}
+	spin_unlock(&eb->refs_lock);
+}
+
 void free_extent_buffer(struct extent_buffer *eb)
 {
 	if (!eb)
 		return;
 
-	if (!atomic_dec_and_test(&eb->refs))
-		return;
+	spin_lock(&eb->refs_lock);
+	if (atomic_read(&eb->refs) == 2 &&
+	    test_bit(EXTENT_BUFFER_STALE, &eb->bflags) &&
+	    !extent_buffer_under_io(eb) &&
+	    test_and_clear_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
+		atomic_dec(&eb->refs);
 
-	WARN_ON(1);
+	/*
+	 * I know this is terrible, but it's temporary until we stop tracking
+	 * the uptodate bits and such for the extent buffers.
+	 */
+	release_extent_buffer(eb, GFP_ATOMIC);
 }
 
-int clear_extent_buffer_dirty(struct extent_io_tree *tree,
-			      struct extent_buffer *eb)
+void free_extent_buffer_stale(struct extent_buffer *eb)
+{
+	if (!eb)
+		return;
+
+	spin_lock(&eb->refs_lock);
+	set_bit(EXTENT_BUFFER_STALE, &eb->bflags);
+
+	if (atomic_read(&eb->refs) == 2 && !extent_buffer_under_io(eb) &&
+	    test_and_clear_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
+		atomic_dec(&eb->refs);
+	release_extent_buffer(eb, GFP_NOFS);
+}
+
+void clear_extent_buffer_dirty(struct extent_buffer *eb)
 {
 	unsigned long i;
 	unsigned long num_pages;
@@ -3812,10 +4298,6 @@
 		lock_page(page);
 		WARN_ON(!PagePrivate(page));
 
-		set_page_extent_mapped(page);
-		if (i == 0)
-			set_page_extent_head(page, eb->len);
-
 		clear_page_dirty_for_io(page);
 		spin_lock_irq(&page->mapping->tree_lock);
 		if (!PageDirty(page)) {
@@ -3827,24 +4309,29 @@
 		ClearPageError(page);
 		unlock_page(page);
 	}
-	return 0;
+	WARN_ON(atomic_read(&eb->refs) == 0);
 }
 
-int set_extent_buffer_dirty(struct extent_io_tree *tree,
-			     struct extent_buffer *eb)
+int set_extent_buffer_dirty(struct extent_buffer *eb)
 {
 	unsigned long i;
 	unsigned long num_pages;
 	int was_dirty = 0;
 
+	check_buffer_tree_ref(eb);
+
 	was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags);
+
 	num_pages = num_extent_pages(eb->start, eb->len);
+	WARN_ON(atomic_read(&eb->refs) == 0);
+	WARN_ON(!test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags));
+
 	for (i = 0; i < num_pages; i++)
-		__set_page_dirty_nobuffers(extent_buffer_page(eb, i));
+		set_page_dirty(extent_buffer_page(eb, i));
 	return was_dirty;
 }
 
-static int __eb_straddles_pages(u64 start, u64 len)
+static int range_straddles_pages(u64 start, u64 len)
 {
 	if (len < PAGE_CACHE_SIZE)
 		return 1;
@@ -3855,25 +4342,14 @@
 	return 0;
 }
 
-static int eb_straddles_pages(struct extent_buffer *eb)
-{
-	return __eb_straddles_pages(eb->start, eb->len);
-}
-
-int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
-				struct extent_buffer *eb,
-				struct extent_state **cached_state)
+int clear_extent_buffer_uptodate(struct extent_buffer *eb)
 {
 	unsigned long i;
 	struct page *page;
 	unsigned long num_pages;
 
-	num_pages = num_extent_pages(eb->start, eb->len);
 	clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
-
-	clear_extent_uptodate(tree, eb->start, eb->start + eb->len - 1,
-			      cached_state, GFP_NOFS);
-
+	num_pages = num_extent_pages(eb->start, eb->len);
 	for (i = 0; i < num_pages; i++) {
 		page = extent_buffer_page(eb, i);
 		if (page)
@@ -3882,27 +4358,16 @@
 	return 0;
 }
 
-int set_extent_buffer_uptodate(struct extent_io_tree *tree,
-				struct extent_buffer *eb)
+int set_extent_buffer_uptodate(struct extent_buffer *eb)
 {
 	unsigned long i;
 	struct page *page;
 	unsigned long num_pages;
 
+	set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
 	num_pages = num_extent_pages(eb->start, eb->len);
-
-	if (eb_straddles_pages(eb)) {
-		set_extent_uptodate(tree, eb->start, eb->start + eb->len - 1,
-				    NULL, GFP_NOFS);
-	}
 	for (i = 0; i < num_pages; i++) {
 		page = extent_buffer_page(eb, i);
-		if ((i == 0 && (eb->start & (PAGE_CACHE_SIZE - 1))) ||
-		    ((i == num_pages - 1) &&
-		     ((eb->start + eb->len) & (PAGE_CACHE_SIZE - 1)))) {
-			check_page_uptodate(tree, page);
-			continue;
-		}
 		SetPageUptodate(page);
 	}
 	return 0;
@@ -3917,7 +4382,7 @@
 	int uptodate;
 	unsigned long index;
 
-	if (__eb_straddles_pages(start, end - start + 1)) {
+	if (range_straddles_pages(start, end - start + 1)) {
 		ret = test_range_bit(tree, start, end,
 				     EXTENT_UPTODATE, 1, NULL);
 		if (ret)
@@ -3939,35 +4404,9 @@
 	return pg_uptodate;
 }
 
-int extent_buffer_uptodate(struct extent_io_tree *tree,
-			   struct extent_buffer *eb,
-			   struct extent_state *cached_state)
+int extent_buffer_uptodate(struct extent_buffer *eb)
 {
-	int ret = 0;
-	unsigned long num_pages;
-	unsigned long i;
-	struct page *page;
-	int pg_uptodate = 1;
-
-	if (test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags))
-		return 1;
-
-	if (eb_straddles_pages(eb)) {
-		ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1,
-				   EXTENT_UPTODATE, 1, cached_state);
-		if (ret)
-			return ret;
-	}
-
-	num_pages = num_extent_pages(eb->start, eb->len);
-	for (i = 0; i < num_pages; i++) {
-		page = extent_buffer_page(eb, i);
-		if (!PageUptodate(page)) {
-			pg_uptodate = 0;
-			break;
-		}
-	}
-	return pg_uptodate;
+	return test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
 }
 
 int read_extent_buffer_pages(struct extent_io_tree *tree,
@@ -3981,21 +4420,14 @@
 	int ret = 0;
 	int locked_pages = 0;
 	int all_uptodate = 1;
-	int inc_all_pages = 0;
 	unsigned long num_pages;
+	unsigned long num_reads = 0;
 	struct bio *bio = NULL;
 	unsigned long bio_flags = 0;
 
 	if (test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags))
 		return 0;
 
-	if (eb_straddles_pages(eb)) {
-		if (test_range_bit(tree, eb->start, eb->start + eb->len - 1,
-				   EXTENT_UPTODATE, 1, NULL)) {
-			return 0;
-		}
-	}
-
 	if (start) {
 		WARN_ON(start < eb->start);
 		start_i = (start >> PAGE_CACHE_SHIFT) -
@@ -4014,8 +4446,10 @@
 			lock_page(page);
 		}
 		locked_pages++;
-		if (!PageUptodate(page))
+		if (!PageUptodate(page)) {
+			num_reads++;
 			all_uptodate = 0;
+		}
 	}
 	if (all_uptodate) {
 		if (start_i == 0)
@@ -4023,20 +4457,12 @@
 		goto unlock_exit;
 	}
 
+	clear_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
+	eb->failed_mirror = 0;
+	atomic_set(&eb->io_pages, num_reads);
 	for (i = start_i; i < num_pages; i++) {
 		page = extent_buffer_page(eb, i);
-
-		WARN_ON(!PagePrivate(page));
-
-		set_page_extent_mapped(page);
-		if (i == 0)
-			set_page_extent_head(page, eb->len);
-
-		if (inc_all_pages)
-			page_cache_get(page);
 		if (!PageUptodate(page)) {
-			if (start_i == 0)
-				inc_all_pages = 1;
 			ClearPageError(page);
 			err = __extent_read_full_page(tree, page,
 						      get_extent, &bio,
@@ -4048,8 +4474,11 @@
 		}
 	}
 
-	if (bio)
-		submit_one_bio(READ, bio, mirror_num, bio_flags);
+	if (bio) {
+		err = submit_one_bio(READ, bio, mirror_num, bio_flags);
+		if (err)
+			return err;
+	}
 
 	if (ret || wait != WAIT_COMPLETE)
 		return ret;
@@ -4061,8 +4490,6 @@
 			ret = -EIO;
 	}
 
-	if (!ret)
-		set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
 	return ret;
 
 unlock_exit:
@@ -4304,15 +4731,20 @@
 {
 	char *dst_kaddr = page_address(dst_page);
 	char *src_kaddr;
+	int must_memmove = 0;
 
 	if (dst_page != src_page) {
 		src_kaddr = page_address(src_page);
 	} else {
 		src_kaddr = dst_kaddr;
-		BUG_ON(areas_overlap(src_off, dst_off, len));
+		if (areas_overlap(src_off, dst_off, len))
+			must_memmove = 1;
 	}
 
-	memcpy(dst_kaddr + dst_off, src_kaddr + src_off, len);
+	if (must_memmove)
+		memmove(dst_kaddr + dst_off, src_kaddr + src_off, len);
+	else
+		memcpy(dst_kaddr + dst_off, src_kaddr + src_off, len);
 }
 
 void memcpy_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
@@ -4382,7 +4814,7 @@
 		       "len %lu len %lu\n", dst_offset, len, dst->len);
 		BUG_ON(1);
 	}
-	if (!areas_overlap(src_offset, dst_offset, len)) {
+	if (dst_offset < src_offset) {
 		memcpy_extent_buffer(dst, dst_offset, src_offset, len);
 		return;
 	}
@@ -4408,47 +4840,48 @@
 	}
 }
 
-static inline void btrfs_release_extent_buffer_rcu(struct rcu_head *head)
+int try_release_extent_buffer(struct page *page, gfp_t mask)
 {
-	struct extent_buffer *eb =
-			container_of(head, struct extent_buffer, rcu_head);
-
-	btrfs_release_extent_buffer(eb);
-}
-
-int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page)
-{
-	u64 start = page_offset(page);
 	struct extent_buffer *eb;
-	int ret = 1;
-
-	spin_lock(&tree->buffer_lock);
-	eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT);
-	if (!eb) {
-		spin_unlock(&tree->buffer_lock);
-		return ret;
-	}
-
-	if (test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) {
-		ret = 0;
-		goto out;
-	}
 
 	/*
-	 * set @eb->refs to 0 if it is already 1, and then release the @eb.
-	 * Or go back.
+	 * We need to make sure noboody is attaching this page to an eb right
+	 * now.
 	 */
-	if (atomic_cmpxchg(&eb->refs, 1, 0) != 1) {
-		ret = 0;
-		goto out;
+	spin_lock(&page->mapping->private_lock);
+	if (!PagePrivate(page)) {
+		spin_unlock(&page->mapping->private_lock);
+		return 1;
 	}
 
-	radix_tree_delete(&tree->buffer, start >> PAGE_CACHE_SHIFT);
-out:
-	spin_unlock(&tree->buffer_lock);
+	eb = (struct extent_buffer *)page->private;
+	BUG_ON(!eb);
 
-	/* at this point we can safely release the extent buffer */
-	if (atomic_read(&eb->refs) == 0)
-		call_rcu(&eb->rcu_head, btrfs_release_extent_buffer_rcu);
-	return ret;
+	/*
+	 * This is a little awful but should be ok, we need to make sure that
+	 * the eb doesn't disappear out from under us while we're looking at
+	 * this page.
+	 */
+	spin_lock(&eb->refs_lock);
+	if (atomic_read(&eb->refs) != 1 || extent_buffer_under_io(eb)) {
+		spin_unlock(&eb->refs_lock);
+		spin_unlock(&page->mapping->private_lock);
+		return 0;
+	}
+	spin_unlock(&page->mapping->private_lock);
+
+	if ((mask & GFP_NOFS) == GFP_NOFS)
+		mask = GFP_NOFS;
+
+	/*
+	 * If tree ref isn't set then we know the ref on this eb is a real ref,
+	 * so just return, this page will likely be freed soon anyway.
+	 */
+	if (!test_and_clear_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)) {
+		spin_unlock(&eb->refs_lock);
+		return 0;
+	}
+	release_extent_buffer(eb, mask);
+
+	return 1;
 }
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index cecc351..faf10eb5 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -35,6 +35,10 @@
 #define EXTENT_BUFFER_DIRTY 2
 #define EXTENT_BUFFER_CORRUPT 3
 #define EXTENT_BUFFER_READAHEAD 4	/* this got triggered by readahead */
+#define EXTENT_BUFFER_TREE_REF 5
+#define EXTENT_BUFFER_STALE 6
+#define EXTENT_BUFFER_WRITEBACK 7
+#define EXTENT_BUFFER_IOERR 8
 
 /* these are flags for extent_clear_unlock_delalloc */
 #define EXTENT_CLEAR_UNLOCK_PAGE 0x1
@@ -54,6 +58,7 @@
 #define EXTENT_PAGE_PRIVATE_FIRST_PAGE 3
 
 struct extent_state;
+struct btrfs_root;
 
 typedef	int (extent_submit_bio_hook_t)(struct inode *inode, int rw,
 				       struct bio *bio, int mirror_num,
@@ -69,9 +74,7 @@
 			      size_t size, struct bio *bio,
 			      unsigned long bio_flags);
 	int (*readpage_io_hook)(struct page *page, u64 start, u64 end);
-	int (*readpage_io_failed_hook)(struct bio *bio, struct page *page,
-				       u64 start, u64 end, int failed_mirror,
-				       struct extent_state *state);
+	int (*readpage_io_failed_hook)(struct page *page, int failed_mirror);
 	int (*writepage_io_failed_hook)(struct bio *bio, struct page *page,
 					u64 start, u64 end,
 				       struct extent_state *state);
@@ -97,6 +100,7 @@
 	struct radix_tree_root buffer;
 	struct address_space *mapping;
 	u64 dirty_bytes;
+	int track_uptodate;
 	spinlock_t lock;
 	spinlock_t buffer_lock;
 	struct extent_io_ops *ops;
@@ -119,16 +123,21 @@
 	struct list_head leak_list;
 };
 
+#define INLINE_EXTENT_BUFFER_PAGES 16
+#define MAX_INLINE_EXTENT_BUFFER_SIZE (INLINE_EXTENT_BUFFER_PAGES * PAGE_CACHE_SIZE)
 struct extent_buffer {
 	u64 start;
 	unsigned long len;
 	unsigned long map_start;
 	unsigned long map_len;
-	struct page *first_page;
 	unsigned long bflags;
+	struct extent_io_tree *tree;
+	spinlock_t refs_lock;
+	atomic_t refs;
+	atomic_t io_pages;
+	int failed_mirror;
 	struct list_head leak_list;
 	struct rcu_head rcu_head;
-	atomic_t refs;
 	pid_t lock_owner;
 
 	/* count of read lock holders on the extent buffer */
@@ -152,6 +161,9 @@
 	 * to unlock
 	 */
 	wait_queue_head_t read_lock_wq;
+	wait_queue_head_t lock_wq;
+	struct page *inline_pages[INLINE_EXTENT_BUFFER_PAGES];
+	struct page **pages;
 };
 
 static inline void extent_set_compress_type(unsigned long *bio_flags,
@@ -178,18 +190,17 @@
 int try_release_extent_mapping(struct extent_map_tree *map,
 			       struct extent_io_tree *tree, struct page *page,
 			       gfp_t mask);
-int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page);
+int try_release_extent_buffer(struct page *page, gfp_t mask);
 int try_release_extent_state(struct extent_map_tree *map,
 			     struct extent_io_tree *tree, struct page *page,
 			     gfp_t mask);
-int lock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask);
+int lock_extent(struct extent_io_tree *tree, u64 start, u64 end);
 int lock_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
-		     int bits, struct extent_state **cached, gfp_t mask);
-int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask);
+		     int bits, struct extent_state **cached);
+int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end);
 int unlock_extent_cached(struct extent_io_tree *tree, u64 start, u64 end,
 			 struct extent_state **cached, gfp_t mask);
-int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
-		    gfp_t mask);
+int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end);
 int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
 			  get_extent_t *get_extent, int mirror_num);
 int __init extent_io_init(void);
@@ -210,7 +221,7 @@
 int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
 		    int bits, gfp_t mask);
 int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
-		   int bits, int exclusive_bits, u64 *failed_start,
+		   int bits, u64 *failed_start,
 		   struct extent_state **cached_state, gfp_t mask);
 int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
 			struct extent_state **cached_state, gfp_t mask);
@@ -240,6 +251,8 @@
 		      struct address_space *mapping,
 		      get_extent_t *get_extent,
 		      struct writeback_control *wbc);
+int btree_write_cache_pages(struct address_space *mapping,
+			    struct writeback_control *wbc);
 int extent_readpages(struct extent_io_tree *tree,
 		     struct address_space *mapping,
 		     struct list_head *pages, unsigned nr_pages,
@@ -251,11 +264,11 @@
 void set_page_extent_mapped(struct page *page);
 
 struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
-					  u64 start, unsigned long len,
-					  struct page *page0);
+					  u64 start, unsigned long len);
 struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
 					 u64 start, unsigned long len);
 void free_extent_buffer(struct extent_buffer *eb);
+void free_extent_buffer_stale(struct extent_buffer *eb);
 #define WAIT_NONE	0
 #define WAIT_COMPLETE	1
 #define WAIT_PAGE_LOCK	2
@@ -287,19 +300,12 @@
 			   unsigned long src_offset, unsigned long len);
 void memset_extent_buffer(struct extent_buffer *eb, char c,
 			  unsigned long start, unsigned long len);
-int wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits);
-int clear_extent_buffer_dirty(struct extent_io_tree *tree,
-			      struct extent_buffer *eb);
-int set_extent_buffer_dirty(struct extent_io_tree *tree,
-			     struct extent_buffer *eb);
-int set_extent_buffer_uptodate(struct extent_io_tree *tree,
-			       struct extent_buffer *eb);
-int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
-				struct extent_buffer *eb,
-				struct extent_state **cached_state);
-int extent_buffer_uptodate(struct extent_io_tree *tree,
-			   struct extent_buffer *eb,
-			   struct extent_state *cached_state);
+void wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits);
+void clear_extent_buffer_dirty(struct extent_buffer *eb);
+int set_extent_buffer_dirty(struct extent_buffer *eb);
+int set_extent_buffer_uptodate(struct extent_buffer *eb);
+int clear_extent_buffer_uptodate(struct extent_buffer *eb);
+int extent_buffer_uptodate(struct extent_buffer *eb);
 int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset,
 		      unsigned long min_len, char **map,
 		      unsigned long *map_start,
@@ -320,4 +326,6 @@
 			u64 length, u64 logical, struct page *page,
 			int mirror_num);
 int end_extent_writepage(struct page *page, int err, u64 start, u64 end);
+int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb,
+			 int mirror_num);
 #endif
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index 078b4fd..5d158d3 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -25,10 +25,12 @@
 #include "transaction.h"
 #include "print-tree.h"
 
-#define MAX_CSUM_ITEMS(r, size) ((((BTRFS_LEAF_DATA_SIZE(r) - \
+#define __MAX_CSUM_ITEMS(r, size) ((((BTRFS_LEAF_DATA_SIZE(r) - \
 				   sizeof(struct btrfs_item) * 2) / \
 				  size) - 1))
 
+#define MAX_CSUM_ITEMS(r, size) (min(__MAX_CSUM_ITEMS(r, size), PAGE_CACHE_SIZE))
+
 #define MAX_ORDERED_SUM_BYTES(r) ((PAGE_SIZE - \
 				   sizeof(struct btrfs_ordered_sum)) / \
 				   sizeof(struct btrfs_sector_sum) * \
@@ -59,7 +61,7 @@
 				      sizeof(*item));
 	if (ret < 0)
 		goto out;
-	BUG_ON(ret);
+	BUG_ON(ret); /* Can't happen */
 	leaf = path->nodes[0];
 	item = btrfs_item_ptr(leaf, path->slots[0],
 			      struct btrfs_file_extent_item);
@@ -284,6 +286,7 @@
 	struct btrfs_ordered_sum *sums;
 	struct btrfs_sector_sum *sector_sum;
 	struct btrfs_csum_item *item;
+	LIST_HEAD(tmplist);
 	unsigned long offset;
 	int ret;
 	size_t size;
@@ -358,7 +361,10 @@
 					MAX_ORDERED_SUM_BYTES(root));
 			sums = kzalloc(btrfs_ordered_sum_size(root, size),
 					GFP_NOFS);
-			BUG_ON(!sums);
+			if (!sums) {
+				ret = -ENOMEM;
+				goto fail;
+			}
 
 			sector_sum = sums->sums;
 			sums->bytenr = start;
@@ -380,12 +386,19 @@
 				offset += csum_size;
 				sector_sum++;
 			}
-			list_add_tail(&sums->list, list);
+			list_add_tail(&sums->list, &tmplist);
 		}
 		path->slots[0]++;
 	}
 	ret = 0;
 fail:
+	while (ret < 0 && !list_empty(&tmplist)) {
+		sums = list_entry(&tmplist, struct btrfs_ordered_sum, list);
+		list_del(&sums->list);
+		kfree(sums);
+	}
+	list_splice_tail(&tmplist, list);
+
 	btrfs_free_path(path);
 	return ret;
 }
@@ -420,7 +433,7 @@
 		offset = page_offset(bvec->bv_page) + bvec->bv_offset;
 
 	ordered = btrfs_lookup_ordered_extent(inode, offset);
-	BUG_ON(!ordered);
+	BUG_ON(!ordered); /* Logic error */
 	sums->bytenr = ordered->start;
 
 	while (bio_index < bio->bi_vcnt) {
@@ -439,11 +452,11 @@
 
 			sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left),
 				       GFP_NOFS);
-			BUG_ON(!sums);
+			BUG_ON(!sums); /* -ENOMEM */
 			sector_sum = sums->sums;
 			sums->len = bytes_left;
 			ordered = btrfs_lookup_ordered_extent(inode, offset);
-			BUG_ON(!ordered);
+			BUG_ON(!ordered); /* Logic error */
 			sums->bytenr = ordered->start;
 		}
 
@@ -483,18 +496,17 @@
  * This calls btrfs_truncate_item with the correct args based on the
  * overlap, and fixes up the key as required.
  */
-static noinline int truncate_one_csum(struct btrfs_trans_handle *trans,
-				      struct btrfs_root *root,
-				      struct btrfs_path *path,
-				      struct btrfs_key *key,
-				      u64 bytenr, u64 len)
+static noinline void truncate_one_csum(struct btrfs_trans_handle *trans,
+				       struct btrfs_root *root,
+				       struct btrfs_path *path,
+				       struct btrfs_key *key,
+				       u64 bytenr, u64 len)
 {
 	struct extent_buffer *leaf;
 	u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
 	u64 csum_end;
 	u64 end_byte = bytenr + len;
 	u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits;
-	int ret;
 
 	leaf = path->nodes[0];
 	csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size;
@@ -510,7 +522,7 @@
 		 */
 		u32 new_size = (bytenr - key->offset) >> blocksize_bits;
 		new_size *= csum_size;
-		ret = btrfs_truncate_item(trans, root, path, new_size, 1);
+		btrfs_truncate_item(trans, root, path, new_size, 1);
 	} else if (key->offset >= bytenr && csum_end > end_byte &&
 		   end_byte > key->offset) {
 		/*
@@ -522,15 +534,13 @@
 		u32 new_size = (csum_end - end_byte) >> blocksize_bits;
 		new_size *= csum_size;
 
-		ret = btrfs_truncate_item(trans, root, path, new_size, 0);
+		btrfs_truncate_item(trans, root, path, new_size, 0);
 
 		key->offset = end_byte;
-		ret = btrfs_set_item_key_safe(trans, root, path, key);
-		BUG_ON(ret);
+		btrfs_set_item_key_safe(trans, root, path, key);
 	} else {
 		BUG();
 	}
-	return 0;
 }
 
 /*
@@ -635,13 +645,14 @@
 			 * item changed size or key
 			 */
 			ret = btrfs_split_item(trans, root, path, &key, offset);
-			BUG_ON(ret && ret != -EAGAIN);
+			if (ret && ret != -EAGAIN) {
+				btrfs_abort_transaction(trans, root, ret);
+				goto out;
+			}
 
 			key.offset = end_byte - 1;
 		} else {
-			ret = truncate_one_csum(trans, root, path,
-						&key, bytenr, len);
-			BUG_ON(ret);
+			truncate_one_csum(trans, root, path, &key, bytenr, len);
 			if (key.offset < bytenr)
 				break;
 		}
@@ -772,7 +783,7 @@
 		if (diff != csum_size)
 			goto insert;
 
-		ret = btrfs_extend_item(trans, root, path, diff);
+		btrfs_extend_item(trans, root, path, diff);
 		goto csum;
 	}
 
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index e8d06b6..d83260d 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -452,7 +452,7 @@
 			split = alloc_extent_map();
 		if (!split2)
 			split2 = alloc_extent_map();
-		BUG_ON(!split || !split2);
+		BUG_ON(!split || !split2); /* -ENOMEM */
 
 		write_lock(&em_tree->lock);
 		em = lookup_extent_mapping(em_tree, start, len);
@@ -494,7 +494,7 @@
 			split->flags = flags;
 			split->compress_type = em->compress_type;
 			ret = add_extent_mapping(em_tree, split);
-			BUG_ON(ret);
+			BUG_ON(ret); /* Logic error */
 			free_extent_map(split);
 			split = split2;
 			split2 = NULL;
@@ -520,7 +520,7 @@
 			}
 
 			ret = add_extent_mapping(em_tree, split);
-			BUG_ON(ret);
+			BUG_ON(ret); /* Logic error */
 			free_extent_map(split);
 			split = NULL;
 		}
@@ -679,7 +679,7 @@
 						root->root_key.objectid,
 						new_key.objectid,
 						start - extent_offset, 0);
-				BUG_ON(ret);
+				BUG_ON(ret); /* -ENOMEM */
 				*hint_byte = disk_bytenr;
 			}
 			key.offset = start;
@@ -754,7 +754,7 @@
 						root->root_key.objectid,
 						key.objectid, key.offset -
 						extent_offset, 0);
-				BUG_ON(ret);
+				BUG_ON(ret); /* -ENOMEM */
 				inode_sub_bytes(inode,
 						extent_end - key.offset);
 				*hint_byte = disk_bytenr;
@@ -770,7 +770,10 @@
 
 			ret = btrfs_del_items(trans, root, path, del_slot,
 					      del_nr);
-			BUG_ON(ret);
+			if (ret) {
+				btrfs_abort_transaction(trans, root, ret);
+				goto out;
+			}
 
 			del_nr = 0;
 			del_slot = 0;
@@ -782,11 +785,13 @@
 		BUG_ON(1);
 	}
 
-	if (del_nr > 0) {
+	if (!ret && del_nr > 0) {
 		ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
-		BUG_ON(ret);
+		if (ret)
+			btrfs_abort_transaction(trans, root, ret);
 	}
 
+out:
 	btrfs_free_path(path);
 	return ret;
 }
@@ -944,7 +949,10 @@
 			btrfs_release_path(path);
 			goto again;
 		}
-		BUG_ON(ret < 0);
+		if (ret < 0) {
+			btrfs_abort_transaction(trans, root, ret);
+			goto out;
+		}
 
 		leaf = path->nodes[0];
 		fi = btrfs_item_ptr(leaf, path->slots[0] - 1,
@@ -963,7 +971,7 @@
 		ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
 					   root->root_key.objectid,
 					   ino, orig_offset, 0);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 
 		if (split == start) {
 			key.offset = start;
@@ -990,7 +998,7 @@
 		ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
 					0, root->root_key.objectid,
 					ino, orig_offset, 0);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 	}
 	other_start = 0;
 	other_end = start;
@@ -1007,7 +1015,7 @@
 		ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
 					0, root->root_key.objectid,
 					ino, orig_offset, 0);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 	}
 	if (del_nr == 0) {
 		fi = btrfs_item_ptr(leaf, path->slots[0],
@@ -1025,7 +1033,10 @@
 		btrfs_mark_buffer_dirty(leaf);
 
 		ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
-		BUG_ON(ret);
+		if (ret < 0) {
+			btrfs_abort_transaction(trans, root, ret);
+			goto out;
+		}
 	}
 out:
 	btrfs_free_path(path);
@@ -1105,8 +1116,7 @@
 	if (start_pos < inode->i_size) {
 		struct btrfs_ordered_extent *ordered;
 		lock_extent_bits(&BTRFS_I(inode)->io_tree,
-				 start_pos, last_pos - 1, 0, &cached_state,
-				 GFP_NOFS);
+				 start_pos, last_pos - 1, 0, &cached_state);
 		ordered = btrfs_lookup_first_ordered_extent(inode,
 							    last_pos - 1);
 		if (ordered &&
@@ -1638,7 +1648,7 @@
 		 * transaction
 		 */
 		lock_extent_bits(&BTRFS_I(inode)->io_tree, alloc_start,
-				 locked_end, 0, &cached_state, GFP_NOFS);
+				 locked_end, 0, &cached_state);
 		ordered = btrfs_lookup_first_ordered_extent(inode,
 							    alloc_end - 1);
 		if (ordered &&
@@ -1667,7 +1677,13 @@
 
 		em = btrfs_get_extent(inode, NULL, 0, cur_offset,
 				      alloc_end - cur_offset, 0);
-		BUG_ON(IS_ERR_OR_NULL(em));
+		if (IS_ERR_OR_NULL(em)) {
+			if (!em)
+				ret = -ENOMEM;
+			else
+				ret = PTR_ERR(em);
+			break;
+		}
 		last_byte = min(extent_map_end(em), alloc_end);
 		actual_end = min_t(u64, extent_map_end(em), offset + len);
 		last_byte = (last_byte + mask) & ~mask;
@@ -1737,7 +1753,7 @@
 		return -ENXIO;
 
 	lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, 0,
-			 &cached_state, GFP_NOFS);
+			 &cached_state);
 
 	/*
 	 * Delalloc is such a pain.  If we have a hole and we have pending
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index b02e379..e88330d3 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -230,11 +230,13 @@
 
 	if (ret) {
 		trans->block_rsv = rsv;
-		WARN_ON(1);
+		btrfs_abort_transaction(trans, root, ret);
 		return ret;
 	}
 
 	ret = btrfs_update_inode(trans, root, inode);
+	if (ret)
+		btrfs_abort_transaction(trans, root, ret);
 	trans->block_rsv = rsv;
 
 	return ret;
@@ -869,7 +871,7 @@
 	io_ctl_prepare_pages(&io_ctl, inode, 0);
 
 	lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
-			 0, &cached_state, GFP_NOFS);
+			 0, &cached_state);
 
 	node = rb_first(&ctl->free_space_offset);
 	if (!node && cluster) {
@@ -1948,14 +1950,14 @@
 		 */
 		ret = btrfs_add_free_space(block_group, old_start,
 					   offset - old_start);
-		WARN_ON(ret);
+		WARN_ON(ret); /* -ENOMEM */
 		goto out;
 	}
 
 	ret = remove_from_bitmap(ctl, info, &offset, &bytes);
 	if (ret == -EAGAIN)
 		goto again;
-	BUG_ON(ret);
+	BUG_ON(ret); /* logic error */
 out_lock:
 	spin_unlock(&ctl->tree_lock);
 out:
@@ -2346,7 +2348,7 @@
 	rb_erase(&entry->offset_index, &ctl->free_space_offset);
 	ret = tree_insert_offset(&cluster->root, entry->offset,
 				 &entry->offset_index, 1);
-	BUG_ON(ret);
+	BUG_ON(ret); /* -EEXIST; Logic error */
 
 	trace_btrfs_setup_cluster(block_group, cluster,
 				  total_found * block_group->sectorsize, 1);
@@ -2439,7 +2441,7 @@
 		ret = tree_insert_offset(&cluster->root, entry->offset,
 					 &entry->offset_index, 0);
 		total_size += entry->bytes;
-		BUG_ON(ret);
+		BUG_ON(ret); /* -EEXIST; Logic error */
 	} while (node && entry != last);
 
 	cluster->max_size = max_extent;
@@ -2830,6 +2832,7 @@
 		int ret;
 
 		ret = search_bitmap(ctl, entry, &offset, &count);
+		/* Logic error; Should be empty if it can't find anything */
 		BUG_ON(ret);
 
 		ino = offset;
diff --git a/fs/btrfs/inode-item.c b/fs/btrfs/inode-item.c
index baa74f3..a13cf1a 100644
--- a/fs/btrfs/inode-item.c
+++ b/fs/btrfs/inode-item.c
@@ -19,6 +19,7 @@
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
+#include "print-tree.h"
 
 static int find_name_in_backref(struct btrfs_path *path, const char *name,
 			 int name_len, struct btrfs_inode_ref **ref_ret)
@@ -128,13 +129,14 @@
 	item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
 	memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
 			      item_size - (ptr + sub_item_len - item_start));
-	ret = btrfs_truncate_item(trans, root, path,
+	btrfs_truncate_item(trans, root, path,
 				  item_size - sub_item_len, 1);
 out:
 	btrfs_free_path(path);
 	return ret;
 }
 
+/* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */
 int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
 			   struct btrfs_root *root,
 			   const char *name, int name_len,
@@ -165,7 +167,7 @@
 			goto out;
 
 		old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
-		ret = btrfs_extend_item(trans, root, path, ins_len);
+		btrfs_extend_item(trans, root, path, ins_len);
 		ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
 				     struct btrfs_inode_ref);
 		ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size);
diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c
index ee15d88..b1a1c92 100644
--- a/fs/btrfs/inode-map.c
+++ b/fs/btrfs/inode-map.c
@@ -178,7 +178,7 @@
 
 	tsk = kthread_run(caching_kthread, root, "btrfs-ino-cache-%llu\n",
 			  root->root_key.objectid);
-	BUG_ON(IS_ERR(tsk));
+	BUG_ON(IS_ERR(tsk)); /* -ENOMEM */
 }
 
 int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid)
@@ -271,7 +271,7 @@
 			break;
 
 		info = rb_entry(n, struct btrfs_free_space, offset_index);
-		BUG_ON(info->bitmap);
+		BUG_ON(info->bitmap); /* Logic error */
 
 		if (info->offset > root->cache_progress)
 			goto free;
@@ -439,17 +439,16 @@
 	if (ret)
 		goto out;
 	trace_btrfs_space_reservation(root->fs_info, "ino_cache",
-				      (u64)(unsigned long)trans,
-				      trans->bytes_reserved, 1);
+				      trans->transid, trans->bytes_reserved, 1);
 again:
 	inode = lookup_free_ino_inode(root, path);
-	if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
+	if (IS_ERR(inode) && (PTR_ERR(inode) != -ENOENT || retry)) {
 		ret = PTR_ERR(inode);
 		goto out_release;
 	}
 
 	if (IS_ERR(inode)) {
-		BUG_ON(retry);
+		BUG_ON(retry); /* Logic error */
 		retry = true;
 
 		ret = create_free_ino_inode(root, trans, path);
@@ -460,12 +459,17 @@
 
 	BTRFS_I(inode)->generation = 0;
 	ret = btrfs_update_inode(trans, root, inode);
-	WARN_ON(ret);
+	if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
+		goto out_put;
+	}
 
 	if (i_size_read(inode) > 0) {
 		ret = btrfs_truncate_free_space_cache(root, trans, path, inode);
-		if (ret)
+		if (ret) {
+			btrfs_abort_transaction(trans, root, ret);
 			goto out_put;
+		}
 	}
 
 	spin_lock(&root->cache_lock);
@@ -502,8 +506,7 @@
 	iput(inode);
 out_release:
 	trace_btrfs_space_reservation(root->fs_info, "ino_cache",
-				      (u64)(unsigned long)trans,
-				      trans->bytes_reserved, 0);
+				      trans->transid, trans->bytes_reserved, 0);
 	btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved);
 out:
 	trans->block_rsv = rsv;
@@ -532,7 +535,7 @@
 	ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
 	if (ret < 0)
 		goto error;
-	BUG_ON(ret == 0);
+	BUG_ON(ret == 0); /* Corruption */
 	if (path->slots[0] > 0) {
 		slot = path->slots[0] - 1;
 		l = path->nodes[0];
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 3a0b5c1..115bc05 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -150,7 +150,6 @@
 	inode_add_bytes(inode, size);
 	ret = btrfs_insert_empty_item(trans, root, path, &key,
 				      datasize);
-	BUG_ON(ret);
 	if (ret) {
 		err = ret;
 		goto fail;
@@ -206,9 +205,9 @@
 	 * could end up racing with unlink.
 	 */
 	BTRFS_I(inode)->disk_i_size = inode->i_size;
-	btrfs_update_inode(trans, root, inode);
+	ret = btrfs_update_inode(trans, root, inode);
 
-	return 0;
+	return ret;
 fail:
 	btrfs_free_path(path);
 	return err;
@@ -250,14 +249,18 @@
 
 	ret = btrfs_drop_extents(trans, inode, start, aligned_end,
 				 &hint_byte, 1);
-	BUG_ON(ret);
+	if (ret)
+		return ret;
 
 	if (isize > actual_end)
 		inline_len = min_t(u64, isize, actual_end);
 	ret = insert_inline_extent(trans, root, inode, start,
 				   inline_len, compressed_size,
 				   compress_type, compressed_pages);
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
+		return ret;
+	}
 	btrfs_delalloc_release_metadata(inode, end + 1 - start);
 	btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0);
 	return 0;
@@ -293,7 +296,7 @@
 	struct async_extent *async_extent;
 
 	async_extent = kmalloc(sizeof(*async_extent), GFP_NOFS);
-	BUG_ON(!async_extent);
+	BUG_ON(!async_extent); /* -ENOMEM */
 	async_extent->start = start;
 	async_extent->ram_size = ram_size;
 	async_extent->compressed_size = compressed_size;
@@ -344,8 +347,9 @@
 	int will_compress;
 	int compress_type = root->fs_info->compress_type;
 
-	/* if this is a small write inside eof, kick off a defragbot */
-	if (end <= BTRFS_I(inode)->disk_i_size && (end - start + 1) < 16 * 1024)
+	/* if this is a small write inside eof, kick off a defrag */
+	if ((end - start + 1) < 16 * 1024 &&
+	    (start > 0 || end + 1 < BTRFS_I(inode)->disk_i_size))
 		btrfs_add_inode_defrag(NULL, inode);
 
 	actual_end = min_t(u64, isize, end + 1);
@@ -433,7 +437,11 @@
 cont:
 	if (start == 0) {
 		trans = btrfs_join_transaction(root);
-		BUG_ON(IS_ERR(trans));
+		if (IS_ERR(trans)) {
+			ret = PTR_ERR(trans);
+			trans = NULL;
+			goto cleanup_and_out;
+		}
 		trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
 		/* lets try to make an inline extent */
@@ -450,11 +458,11 @@
 						    total_compressed,
 						    compress_type, pages);
 		}
-		if (ret == 0) {
+		if (ret <= 0) {
 			/*
-			 * inline extent creation worked, we don't need
-			 * to create any more async work items.  Unlock
-			 * and free up our temp pages.
+			 * inline extent creation worked or returned error,
+			 * we don't need to create any more async work items.
+			 * Unlock and free up our temp pages.
 			 */
 			extent_clear_unlock_delalloc(inode,
 			     &BTRFS_I(inode)->io_tree,
@@ -547,7 +555,7 @@
 	}
 
 out:
-	return 0;
+	return ret;
 
 free_pages_out:
 	for (i = 0; i < nr_pages_ret; i++) {
@@ -557,6 +565,20 @@
 	kfree(pages);
 
 	goto out;
+
+cleanup_and_out:
+	extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
+				     start, end, NULL,
+				     EXTENT_CLEAR_UNLOCK_PAGE |
+				     EXTENT_CLEAR_DIRTY |
+				     EXTENT_CLEAR_DELALLOC |
+				     EXTENT_SET_WRITEBACK |
+				     EXTENT_END_WRITEBACK);
+	if (!trans || IS_ERR(trans))
+		btrfs_error(root->fs_info, ret, "Failed to join transaction");
+	else
+		btrfs_abort_transaction(trans, root, ret);
+	goto free_pages_out;
 }
 
 /*
@@ -597,7 +619,7 @@
 
 			lock_extent(io_tree, async_extent->start,
 					 async_extent->start +
-					 async_extent->ram_size - 1, GFP_NOFS);
+					 async_extent->ram_size - 1);
 
 			/* allocate blocks */
 			ret = cow_file_range(inode, async_cow->locked_page,
@@ -606,6 +628,8 @@
 					     async_extent->ram_size - 1,
 					     &page_started, &nr_written, 0);
 
+			/* JDM XXX */
+
 			/*
 			 * if page_started, cow_file_range inserted an
 			 * inline extent and took care of all the unlocking
@@ -625,18 +649,21 @@
 		}
 
 		lock_extent(io_tree, async_extent->start,
-			    async_extent->start + async_extent->ram_size - 1,
-			    GFP_NOFS);
+			    async_extent->start + async_extent->ram_size - 1);
 
 		trans = btrfs_join_transaction(root);
-		BUG_ON(IS_ERR(trans));
-		trans->block_rsv = &root->fs_info->delalloc_block_rsv;
-		ret = btrfs_reserve_extent(trans, root,
+		if (IS_ERR(trans)) {
+			ret = PTR_ERR(trans);
+		} else {
+			trans->block_rsv = &root->fs_info->delalloc_block_rsv;
+			ret = btrfs_reserve_extent(trans, root,
 					   async_extent->compressed_size,
 					   async_extent->compressed_size,
-					   0, alloc_hint,
-					   (u64)-1, &ins, 1);
-		btrfs_end_transaction(trans, root);
+					   0, alloc_hint, &ins, 1);
+			if (ret)
+				btrfs_abort_transaction(trans, root, ret);
+			btrfs_end_transaction(trans, root);
+		}
 
 		if (ret) {
 			int i;
@@ -649,8 +676,10 @@
 			async_extent->pages = NULL;
 			unlock_extent(io_tree, async_extent->start,
 				      async_extent->start +
-				      async_extent->ram_size - 1, GFP_NOFS);
-			goto retry;
+				      async_extent->ram_size - 1);
+			if (ret == -ENOSPC)
+				goto retry;
+			goto out_free; /* JDM: Requeue? */
 		}
 
 		/*
@@ -662,7 +691,7 @@
 					async_extent->ram_size - 1, 0);
 
 		em = alloc_extent_map();
-		BUG_ON(!em);
+		BUG_ON(!em); /* -ENOMEM */
 		em->start = async_extent->start;
 		em->len = async_extent->ram_size;
 		em->orig_start = em->start;
@@ -694,7 +723,7 @@
 						ins.offset,
 						BTRFS_ORDERED_COMPRESSED,
 						async_extent->compress_type);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 
 		/*
 		 * clear dirty, set writeback and unlock the pages.
@@ -716,13 +745,17 @@
 				    ins.offset, async_extent->pages,
 				    async_extent->nr_pages);
 
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 		alloc_hint = ins.objectid + ins.offset;
 		kfree(async_extent);
 		cond_resched();
 	}
-
-	return 0;
+	ret = 0;
+out:
+	return ret;
+out_free:
+	kfree(async_extent);
+	goto out;
 }
 
 static u64 get_extent_allocation_hint(struct inode *inode, u64 start,
@@ -791,7 +824,18 @@
 
 	BUG_ON(btrfs_is_free_space_inode(root, inode));
 	trans = btrfs_join_transaction(root);
-	BUG_ON(IS_ERR(trans));
+	if (IS_ERR(trans)) {
+		extent_clear_unlock_delalloc(inode,
+			     &BTRFS_I(inode)->io_tree,
+			     start, end, NULL,
+			     EXTENT_CLEAR_UNLOCK_PAGE |
+			     EXTENT_CLEAR_UNLOCK |
+			     EXTENT_CLEAR_DELALLOC |
+			     EXTENT_CLEAR_DIRTY |
+			     EXTENT_SET_WRITEBACK |
+			     EXTENT_END_WRITEBACK);
+		return PTR_ERR(trans);
+	}
 	trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
 	num_bytes = (end - start + blocksize) & ~(blocksize - 1);
@@ -800,7 +844,8 @@
 	ret = 0;
 
 	/* if this is a small write inside eof, kick off defrag */
-	if (end <= BTRFS_I(inode)->disk_i_size && num_bytes < 64 * 1024)
+	if (num_bytes < 64 * 1024 &&
+	    (start > 0 || end + 1 < BTRFS_I(inode)->disk_i_size))
 		btrfs_add_inode_defrag(trans, inode);
 
 	if (start == 0) {
@@ -821,8 +866,10 @@
 			*nr_written = *nr_written +
 			     (end - start + PAGE_CACHE_SIZE) / PAGE_CACHE_SIZE;
 			*page_started = 1;
-			ret = 0;
 			goto out;
+		} else if (ret < 0) {
+			btrfs_abort_transaction(trans, root, ret);
+			goto out_unlock;
 		}
 	}
 
@@ -838,11 +885,14 @@
 		cur_alloc_size = disk_num_bytes;
 		ret = btrfs_reserve_extent(trans, root, cur_alloc_size,
 					   root->sectorsize, 0, alloc_hint,
-					   (u64)-1, &ins, 1);
-		BUG_ON(ret);
+					   &ins, 1);
+		if (ret < 0) {
+			btrfs_abort_transaction(trans, root, ret);
+			goto out_unlock;
+		}
 
 		em = alloc_extent_map();
-		BUG_ON(!em);
+		BUG_ON(!em); /* -ENOMEM */
 		em->start = start;
 		em->orig_start = em->start;
 		ram_size = ins.offset;
@@ -868,13 +918,16 @@
 		cur_alloc_size = ins.offset;
 		ret = btrfs_add_ordered_extent(inode, start, ins.objectid,
 					       ram_size, cur_alloc_size, 0);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 
 		if (root->root_key.objectid ==
 		    BTRFS_DATA_RELOC_TREE_OBJECTID) {
 			ret = btrfs_reloc_clone_csums(inode, start,
 						      cur_alloc_size);
-			BUG_ON(ret);
+			if (ret) {
+				btrfs_abort_transaction(trans, root, ret);
+				goto out_unlock;
+			}
 		}
 
 		if (disk_num_bytes < cur_alloc_size)
@@ -899,11 +952,23 @@
 		alloc_hint = ins.objectid + ins.offset;
 		start += cur_alloc_size;
 	}
-out:
 	ret = 0;
+out:
 	btrfs_end_transaction(trans, root);
 
 	return ret;
+out_unlock:
+	extent_clear_unlock_delalloc(inode,
+		     &BTRFS_I(inode)->io_tree,
+		     start, end, NULL,
+		     EXTENT_CLEAR_UNLOCK_PAGE |
+		     EXTENT_CLEAR_UNLOCK |
+		     EXTENT_CLEAR_DELALLOC |
+		     EXTENT_CLEAR_DIRTY |
+		     EXTENT_SET_WRITEBACK |
+		     EXTENT_END_WRITEBACK);
+
+	goto out;
 }
 
 /*
@@ -969,7 +1034,7 @@
 			 1, 0, NULL, GFP_NOFS);
 	while (start < end) {
 		async_cow = kmalloc(sizeof(*async_cow), GFP_NOFS);
-		BUG_ON(!async_cow);
+		BUG_ON(!async_cow); /* -ENOMEM */
 		async_cow->inode = inode;
 		async_cow->root = root;
 		async_cow->locked_page = locked_page;
@@ -1060,7 +1125,7 @@
 	u64 disk_bytenr;
 	u64 num_bytes;
 	int extent_type;
-	int ret;
+	int ret, err;
 	int type;
 	int nocow;
 	int check_prev = 1;
@@ -1078,7 +1143,11 @@
 	else
 		trans = btrfs_join_transaction(root);
 
-	BUG_ON(IS_ERR(trans));
+	if (IS_ERR(trans)) {
+		btrfs_free_path(path);
+		return PTR_ERR(trans);
+	}
+
 	trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
 	cow_start = (u64)-1;
@@ -1086,7 +1155,10 @@
 	while (1) {
 		ret = btrfs_lookup_file_extent(trans, root, path, ino,
 					       cur_offset, 0);
-		BUG_ON(ret < 0);
+		if (ret < 0) {
+			btrfs_abort_transaction(trans, root, ret);
+			goto error;
+		}
 		if (ret > 0 && path->slots[0] > 0 && check_prev) {
 			leaf = path->nodes[0];
 			btrfs_item_key_to_cpu(leaf, &found_key,
@@ -1100,8 +1172,10 @@
 		leaf = path->nodes[0];
 		if (path->slots[0] >= btrfs_header_nritems(leaf)) {
 			ret = btrfs_next_leaf(root, path);
-			if (ret < 0)
-				BUG_ON(1);
+			if (ret < 0) {
+				btrfs_abort_transaction(trans, root, ret);
+				goto error;
+			}
 			if (ret > 0)
 				break;
 			leaf = path->nodes[0];
@@ -1189,7 +1263,10 @@
 			ret = cow_file_range(inode, locked_page, cow_start,
 					found_key.offset - 1, page_started,
 					nr_written, 1);
-			BUG_ON(ret);
+			if (ret) {
+				btrfs_abort_transaction(trans, root, ret);
+				goto error;
+			}
 			cow_start = (u64)-1;
 		}
 
@@ -1198,7 +1275,7 @@
 			struct extent_map_tree *em_tree;
 			em_tree = &BTRFS_I(inode)->extent_tree;
 			em = alloc_extent_map();
-			BUG_ON(!em);
+			BUG_ON(!em); /* -ENOMEM */
 			em->start = cur_offset;
 			em->orig_start = em->start;
 			em->len = num_bytes;
@@ -1224,13 +1301,16 @@
 
 		ret = btrfs_add_ordered_extent(inode, cur_offset, disk_bytenr,
 					       num_bytes, num_bytes, type);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 
 		if (root->root_key.objectid ==
 		    BTRFS_DATA_RELOC_TREE_OBJECTID) {
 			ret = btrfs_reloc_clone_csums(inode, cur_offset,
 						      num_bytes);
-			BUG_ON(ret);
+			if (ret) {
+				btrfs_abort_transaction(trans, root, ret);
+				goto error;
+			}
 		}
 
 		extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
@@ -1249,18 +1329,23 @@
 	if (cow_start != (u64)-1) {
 		ret = cow_file_range(inode, locked_page, cow_start, end,
 				     page_started, nr_written, 1);
-		BUG_ON(ret);
+		if (ret) {
+			btrfs_abort_transaction(trans, root, ret);
+			goto error;
+		}
 	}
 
+error:
 	if (nolock) {
-		ret = btrfs_end_transaction_nolock(trans, root);
-		BUG_ON(ret);
+		err = btrfs_end_transaction_nolock(trans, root);
 	} else {
-		ret = btrfs_end_transaction(trans, root);
-		BUG_ON(ret);
+		err = btrfs_end_transaction(trans, root);
 	}
+	if (!ret)
+		ret = err;
+
 	btrfs_free_path(path);
-	return 0;
+	return ret;
 }
 
 /*
@@ -1425,10 +1510,11 @@
 	map_length = length;
 	ret = btrfs_map_block(map_tree, READ, logical,
 			      &map_length, NULL, 0);
-
+	/* Will always return 0 or 1 with map_multi == NULL */
+	BUG_ON(ret < 0);
 	if (map_length < length + size)
 		return 1;
-	return ret;
+	return 0;
 }
 
 /*
@@ -1448,7 +1534,7 @@
 	int ret = 0;
 
 	ret = btrfs_csum_one_bio(root, inode, bio, 0, 0);
-	BUG_ON(ret);
+	BUG_ON(ret); /* -ENOMEM */
 	return 0;
 }
 
@@ -1479,14 +1565,16 @@
 	struct btrfs_root *root = BTRFS_I(inode)->root;
 	int ret = 0;
 	int skip_sum;
+	int metadata = 0;
 
 	skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
 
 	if (btrfs_is_free_space_inode(root, inode))
-		ret = btrfs_bio_wq_end_io(root->fs_info, bio, 2);
-	else
-		ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
-	BUG_ON(ret);
+		metadata = 2;
+
+	ret = btrfs_bio_wq_end_io(root->fs_info, bio, metadata);
+	if (ret)
+		return ret;
 
 	if (!(rw & REQ_WRITE)) {
 		if (bio_flags & EXTENT_BIO_COMPRESSED) {
@@ -1571,7 +1659,7 @@
 	page_end = page_offset(page) + PAGE_CACHE_SIZE - 1;
 
 	lock_extent_bits(&BTRFS_I(inode)->io_tree, page_start, page_end, 0,
-			 &cached_state, GFP_NOFS);
+			 &cached_state);
 
 	/* already ordered? We're done */
 	if (PagePrivate2(page))
@@ -1675,13 +1763,15 @@
 	 */
 	ret = btrfs_drop_extents(trans, inode, file_pos, file_pos + num_bytes,
 				 &hint, 0);
-	BUG_ON(ret);
+	if (ret)
+		goto out;
 
 	ins.objectid = btrfs_ino(inode);
 	ins.offset = file_pos;
 	ins.type = BTRFS_EXTENT_DATA_KEY;
 	ret = btrfs_insert_empty_item(trans, root, path, &ins, sizeof(*fi));
-	BUG_ON(ret);
+	if (ret)
+		goto out;
 	leaf = path->nodes[0];
 	fi = btrfs_item_ptr(leaf, path->slots[0],
 			    struct btrfs_file_extent_item);
@@ -1709,10 +1799,10 @@
 	ret = btrfs_alloc_reserved_file_extent(trans, root,
 					root->root_key.objectid,
 					btrfs_ino(inode), file_pos, &ins);
-	BUG_ON(ret);
+out:
 	btrfs_free_path(path);
 
-	return 0;
+	return ret;
 }
 
 /*
@@ -1740,35 +1830,41 @@
 					     end - start + 1);
 	if (!ret)
 		return 0;
-	BUG_ON(!ordered_extent);
+	BUG_ON(!ordered_extent); /* Logic error */
 
 	nolock = btrfs_is_free_space_inode(root, inode);
 
 	if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) {
-		BUG_ON(!list_empty(&ordered_extent->list));
+		BUG_ON(!list_empty(&ordered_extent->list)); /* Logic error */
 		ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
 		if (!ret) {
 			if (nolock)
 				trans = btrfs_join_transaction_nolock(root);
 			else
 				trans = btrfs_join_transaction(root);
-			BUG_ON(IS_ERR(trans));
+			if (IS_ERR(trans))
+				return PTR_ERR(trans);
 			trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 			ret = btrfs_update_inode_fallback(trans, root, inode);
-			BUG_ON(ret);
+			if (ret) /* -ENOMEM or corruption */
+				btrfs_abort_transaction(trans, root, ret);
 		}
 		goto out;
 	}
 
 	lock_extent_bits(io_tree, ordered_extent->file_offset,
 			 ordered_extent->file_offset + ordered_extent->len - 1,
-			 0, &cached_state, GFP_NOFS);
+			 0, &cached_state);
 
 	if (nolock)
 		trans = btrfs_join_transaction_nolock(root);
 	else
 		trans = btrfs_join_transaction(root);
-	BUG_ON(IS_ERR(trans));
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
+		trans = NULL;
+		goto out_unlock;
+	}
 	trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
 	if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags))
@@ -1779,7 +1875,6 @@
 						ordered_extent->file_offset,
 						ordered_extent->file_offset +
 						ordered_extent->len);
-		BUG_ON(ret);
 	} else {
 		BUG_ON(root == root->fs_info->tree_root);
 		ret = insert_reserved_file_extent(trans, inode,
@@ -1793,11 +1888,14 @@
 		unpin_extent_cache(&BTRFS_I(inode)->extent_tree,
 				   ordered_extent->file_offset,
 				   ordered_extent->len);
-		BUG_ON(ret);
 	}
 	unlock_extent_cached(io_tree, ordered_extent->file_offset,
 			     ordered_extent->file_offset +
 			     ordered_extent->len - 1, &cached_state, GFP_NOFS);
+	if (ret < 0) {
+		btrfs_abort_transaction(trans, root, ret);
+		goto out;
+	}
 
 	add_pending_csums(trans, inode, ordered_extent->file_offset,
 			  &ordered_extent->list);
@@ -1805,7 +1903,10 @@
 	ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
 	if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) {
 		ret = btrfs_update_inode_fallback(trans, root, inode);
-		BUG_ON(ret);
+		if (ret) { /* -ENOMEM or corruption */
+			btrfs_abort_transaction(trans, root, ret);
+			goto out;
+		}
 	}
 	ret = 0;
 out:
@@ -1824,6 +1925,11 @@
 	btrfs_put_ordered_extent(ordered_extent);
 
 	return 0;
+out_unlock:
+	unlock_extent_cached(io_tree, ordered_extent->file_offset,
+			     ordered_extent->file_offset +
+			     ordered_extent->len - 1, &cached_state, GFP_NOFS);
+	goto out;
 }
 
 static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,
@@ -1905,6 +2011,8 @@
 	struct inode *inode;
 };
 
+/* JDM: If this is fs-wide, why can't we add a pointer to
+ * btrfs_inode instead and avoid the allocation? */
 void btrfs_add_delayed_iput(struct inode *inode)
 {
 	struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
@@ -2051,20 +2159,27 @@
 	/* grab metadata reservation from transaction handle */
 	if (reserve) {
 		ret = btrfs_orphan_reserve_metadata(trans, inode);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOSPC in reservation; Logic error? JDM */
 	}
 
 	/* insert an orphan item to track this unlinked/truncated file */
 	if (insert >= 1) {
 		ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
-		BUG_ON(ret && ret != -EEXIST);
+		if (ret && ret != -EEXIST) {
+			btrfs_abort_transaction(trans, root, ret);
+			return ret;
+		}
+		ret = 0;
 	}
 
 	/* insert an orphan item to track subvolume contains orphan files */
 	if (insert >= 2) {
 		ret = btrfs_insert_orphan_item(trans, root->fs_info->tree_root,
 					       root->root_key.objectid);
-		BUG_ON(ret);
+		if (ret && ret != -EEXIST) {
+			btrfs_abort_transaction(trans, root, ret);
+			return ret;
+		}
 	}
 	return 0;
 }
@@ -2094,7 +2209,7 @@
 
 	if (trans && delete_item) {
 		ret = btrfs_del_orphan_item(trans, root, btrfs_ino(inode));
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM or corruption (JDM: Recheck) */
 	}
 
 	if (release_rsv)
@@ -2228,7 +2343,7 @@
 			}
 			ret = btrfs_del_orphan_item(trans, root,
 						    found_key.objectid);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM or corruption (JDM: Recheck) */
 			btrfs_end_transaction(trans, root);
 			continue;
 		}
@@ -2610,16 +2725,22 @@
 		printk(KERN_INFO "btrfs failed to delete reference to %.*s, "
 		       "inode %llu parent %llu\n", name_len, name,
 		       (unsigned long long)ino, (unsigned long long)dir_ino);
+		btrfs_abort_transaction(trans, root, ret);
 		goto err;
 	}
 
 	ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
-	if (ret)
+	if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
 		goto err;
+	}
 
 	ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len,
 					 inode, dir_ino);
-	BUG_ON(ret != 0 && ret != -ENOENT);
+	if (ret != 0 && ret != -ENOENT) {
+		btrfs_abort_transaction(trans, root, ret);
+		goto err;
+	}
 
 	ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len,
 					   dir, index);
@@ -2777,7 +2898,7 @@
 			err = ret;
 			goto out;
 		}
-		BUG_ON(ret == 0);
+		BUG_ON(ret == 0); /* Corruption */
 		if (check_path_shared(root, path))
 			goto out;
 		btrfs_release_path(path);
@@ -2810,7 +2931,7 @@
 		err = PTR_ERR(ref);
 		goto out;
 	}
-	BUG_ON(!ref);
+	BUG_ON(!ref); /* Logic error */
 	if (check_path_shared(root, path))
 		goto out;
 	index = btrfs_inode_ref_index(path->nodes[0], ref);
@@ -2917,23 +3038,42 @@
 
 	di = btrfs_lookup_dir_item(trans, root, path, dir_ino,
 				   name, name_len, -1);
-	BUG_ON(IS_ERR_OR_NULL(di));
+	if (IS_ERR_OR_NULL(di)) {
+		if (!di)
+			ret = -ENOENT;
+		else
+			ret = PTR_ERR(di);
+		goto out;
+	}
 
 	leaf = path->nodes[0];
 	btrfs_dir_item_key_to_cpu(leaf, di, &key);
 	WARN_ON(key.type != BTRFS_ROOT_ITEM_KEY || key.objectid != objectid);
 	ret = btrfs_delete_one_dir_name(trans, root, path, di);
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
+		goto out;
+	}
 	btrfs_release_path(path);
 
 	ret = btrfs_del_root_ref(trans, root->fs_info->tree_root,
 				 objectid, root->root_key.objectid,
 				 dir_ino, &index, name, name_len);
 	if (ret < 0) {
-		BUG_ON(ret != -ENOENT);
+		if (ret != -ENOENT) {
+			btrfs_abort_transaction(trans, root, ret);
+			goto out;
+		}
 		di = btrfs_search_dir_index_item(root, path, dir_ino,
 						 name, name_len);
-		BUG_ON(IS_ERR_OR_NULL(di));
+		if (IS_ERR_OR_NULL(di)) {
+			if (!di)
+				ret = -ENOENT;
+			else
+				ret = PTR_ERR(di);
+			btrfs_abort_transaction(trans, root, ret);
+			goto out;
+		}
 
 		leaf = path->nodes[0];
 		btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
@@ -2943,15 +3083,19 @@
 	btrfs_release_path(path);
 
 	ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
+		goto out;
+	}
 
 	btrfs_i_size_write(dir, dir->i_size - name_len * 2);
 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 	ret = btrfs_update_inode(trans, root, dir);
-	BUG_ON(ret);
-
+	if (ret)
+		btrfs_abort_transaction(trans, root, ret);
+out:
 	btrfs_free_path(path);
-	return 0;
+	return ret;
 }
 
 static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
@@ -3161,8 +3305,8 @@
 				}
 				size =
 				    btrfs_file_extent_calc_inline_size(size);
-				ret = btrfs_truncate_item(trans, root, path,
-							  size, 1);
+				btrfs_truncate_item(trans, root, path,
+						    size, 1);
 			} else if (root->ref_cows) {
 				inode_sub_bytes(inode, item_end + 1 -
 						found_key.offset);
@@ -3210,7 +3354,11 @@
 				ret = btrfs_del_items(trans, root, path,
 						pending_del_slot,
 						pending_del_nr);
-				BUG_ON(ret);
+				if (ret) {
+					btrfs_abort_transaction(trans,
+								root, ret);
+					goto error;
+				}
 				pending_del_nr = 0;
 			}
 			btrfs_release_path(path);
@@ -3223,8 +3371,10 @@
 	if (pending_del_nr) {
 		ret = btrfs_del_items(trans, root, path, pending_del_slot,
 				      pending_del_nr);
-		BUG_ON(ret);
+		if (ret)
+			btrfs_abort_transaction(trans, root, ret);
 	}
+error:
 	btrfs_free_path(path);
 	return err;
 }
@@ -3282,8 +3432,7 @@
 	}
 	wait_on_page_writeback(page);
 
-	lock_extent_bits(io_tree, page_start, page_end, 0, &cached_state,
-			 GFP_NOFS);
+	lock_extent_bits(io_tree, page_start, page_end, 0, &cached_state);
 	set_page_extent_mapped(page);
 
 	ordered = btrfs_lookup_ordered_extent(inode, page_start);
@@ -3359,7 +3508,7 @@
 		btrfs_wait_ordered_range(inode, hole_start,
 					 block_end - hole_start);
 		lock_extent_bits(io_tree, hole_start, block_end - 1, 0,
-				 &cached_state, GFP_NOFS);
+				 &cached_state);
 		ordered = btrfs_lookup_ordered_extent(inode, hole_start);
 		if (!ordered)
 			break;
@@ -3372,7 +3521,10 @@
 	while (1) {
 		em = btrfs_get_extent(inode, NULL, 0, cur_offset,
 				block_end - cur_offset, 0);
-		BUG_ON(IS_ERR_OR_NULL(em));
+		if (IS_ERR(em)) {
+			err = PTR_ERR(em);
+			break;
+		}
 		last_byte = min(extent_map_end(em), block_end);
 		last_byte = (last_byte + mask) & ~mask;
 		if (!test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
@@ -3389,7 +3541,7 @@
 						 cur_offset + hole_size,
 						 &hint_byte, 1);
 			if (err) {
-				btrfs_update_inode(trans, root, inode);
+				btrfs_abort_transaction(trans, root, err);
 				btrfs_end_transaction(trans, root);
 				break;
 			}
@@ -3399,7 +3551,7 @@
 					0, hole_size, 0, hole_size,
 					0, 0, 0);
 			if (err) {
-				btrfs_update_inode(trans, root, inode);
+				btrfs_abort_transaction(trans, root, err);
 				btrfs_end_transaction(trans, root);
 				break;
 			}
@@ -3779,7 +3931,7 @@
 	}
 }
 
-int btrfs_invalidate_inodes(struct btrfs_root *root)
+void btrfs_invalidate_inodes(struct btrfs_root *root)
 {
 	struct rb_node *node;
 	struct rb_node *prev;
@@ -3839,7 +3991,6 @@
 		node = rb_next(node);
 	}
 	spin_unlock(&root->inode_lock);
-	return 0;
 }
 
 static int btrfs_init_locked_inode(struct inode *inode, void *p)
@@ -4581,18 +4732,26 @@
 					     parent_ino, index);
 	}
 
-	if (ret == 0) {
-		ret = btrfs_insert_dir_item(trans, root, name, name_len,
-					    parent_inode, &key,
-					    btrfs_inode_type(inode), index);
-		if (ret)
-			goto fail_dir_item;
+	/* Nothing to clean up yet */
+	if (ret)
+		return ret;
 
-		btrfs_i_size_write(parent_inode, parent_inode->i_size +
-				   name_len * 2);
-		parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
-		ret = btrfs_update_inode(trans, root, parent_inode);
+	ret = btrfs_insert_dir_item(trans, root, name, name_len,
+				    parent_inode, &key,
+				    btrfs_inode_type(inode), index);
+	if (ret == -EEXIST)
+		goto fail_dir_item;
+	else if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
+		return ret;
 	}
+
+	btrfs_i_size_write(parent_inode, parent_inode->i_size +
+			   name_len * 2);
+	parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
+	ret = btrfs_update_inode(trans, root, parent_inode);
+	if (ret)
+		btrfs_abort_transaction(trans, root, ret);
 	return ret;
 
 fail_dir_item:
@@ -4806,7 +4965,8 @@
 	} else {
 		struct dentry *parent = dentry->d_parent;
 		err = btrfs_update_inode(trans, root, inode);
-		BUG_ON(err);
+		if (err)
+			goto fail;
 		d_instantiate(dentry, inode);
 		btrfs_log_new_name(trans, inode, NULL, parent);
 	}
@@ -5137,7 +5297,7 @@
 				ret = uncompress_inline(path, inode, page,
 							pg_offset,
 							extent_offset, item);
-				BUG_ON(ret);
+				BUG_ON(ret); /* -ENOMEM */
 			} else {
 				map = kmap(page);
 				read_extent_buffer(leaf, map + pg_offset, ptr,
@@ -5252,6 +5412,7 @@
 		free_extent_map(em);
 		return ERR_PTR(err);
 	}
+	BUG_ON(!em); /* Error is always set */
 	return em;
 }
 
@@ -5414,7 +5575,7 @@
 
 	alloc_hint = get_extent_allocation_hint(inode, start, len);
 	ret = btrfs_reserve_extent(trans, root, len, root->sectorsize, 0,
-				   alloc_hint, (u64)-1, &ins, 1);
+				   alloc_hint, &ins, 1);
 	if (ret) {
 		em = ERR_PTR(ret);
 		goto out;
@@ -5602,7 +5763,7 @@
 		free_extent_map(em);
 		/* DIO will do one hole at a time, so just unlock a sector */
 		unlock_extent(&BTRFS_I(inode)->io_tree, start,
-			      start + root->sectorsize - 1, GFP_NOFS);
+			      start + root->sectorsize - 1);
 		return 0;
 	}
 
@@ -5743,7 +5904,7 @@
 	} while (bvec <= bvec_end);
 
 	unlock_extent(&BTRFS_I(inode)->io_tree, dip->logical_offset,
-		      dip->logical_offset + dip->bytes - 1, GFP_NOFS);
+		      dip->logical_offset + dip->bytes - 1);
 	bio->bi_private = dip->private;
 
 	kfree(dip->csums);
@@ -5794,7 +5955,7 @@
 
 	lock_extent_bits(&BTRFS_I(inode)->io_tree, ordered->file_offset,
 			 ordered->file_offset + ordered->len - 1, 0,
-			 &cached_state, GFP_NOFS);
+			 &cached_state);
 
 	if (test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags)) {
 		ret = btrfs_mark_extent_written(trans, inode,
@@ -5868,7 +6029,7 @@
 	int ret;
 	struct btrfs_root *root = BTRFS_I(inode)->root;
 	ret = btrfs_csum_one_bio(root, inode, bio, offset, 1);
-	BUG_ON(ret);
+	BUG_ON(ret); /* -ENOMEM */
 	return 0;
 }
 
@@ -6209,7 +6370,7 @@
 
 	while (1) {
 		lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend,
-				 0, &cached_state, GFP_NOFS);
+				 0, &cached_state);
 		/*
 		 * We're concerned with the entire range that we're going to be
 		 * doing DIO to, so we need to make sure theres no ordered
@@ -6233,7 +6394,7 @@
 	if (writing) {
 		write_bits = EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING;
 		ret = set_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend,
-				     EXTENT_DELALLOC, 0, NULL, &cached_state,
+				     EXTENT_DELALLOC, NULL, &cached_state,
 				     GFP_NOFS);
 		if (ret) {
 			clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart,
@@ -6363,8 +6524,7 @@
 		btrfs_releasepage(page, GFP_NOFS);
 		return;
 	}
-	lock_extent_bits(tree, page_start, page_end, 0, &cached_state,
-			 GFP_NOFS);
+	lock_extent_bits(tree, page_start, page_end, 0, &cached_state);
 	ordered = btrfs_lookup_ordered_extent(page->mapping->host,
 					   page_offset(page));
 	if (ordered) {
@@ -6386,8 +6546,7 @@
 		}
 		btrfs_put_ordered_extent(ordered);
 		cached_state = NULL;
-		lock_extent_bits(tree, page_start, page_end, 0, &cached_state,
-				 GFP_NOFS);
+		lock_extent_bits(tree, page_start, page_end, 0, &cached_state);
 	}
 	clear_extent_bit(tree, page_start, page_end,
 		 EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC |
@@ -6462,8 +6621,7 @@
 	}
 	wait_on_page_writeback(page);
 
-	lock_extent_bits(io_tree, page_start, page_end, 0, &cached_state,
-			 GFP_NOFS);
+	lock_extent_bits(io_tree, page_start, page_end, 0, &cached_state);
 	set_page_extent_mapped(page);
 
 	/*
@@ -6737,10 +6895,9 @@
 	btrfs_i_size_write(inode, 0);
 
 	err = btrfs_update_inode(trans, new_root, inode);
-	BUG_ON(err);
 
 	iput(inode);
-	return 0;
+	return err;
 }
 
 struct inode *btrfs_alloc_inode(struct super_block *sb)
@@ -6783,6 +6940,8 @@
 	extent_map_tree_init(&ei->extent_tree);
 	extent_io_tree_init(&ei->io_tree, &inode->i_data);
 	extent_io_tree_init(&ei->io_failure_tree, &inode->i_data);
+	ei->io_tree.track_uptodate = 1;
+	ei->io_failure_tree.track_uptodate = 1;
 	mutex_init(&ei->log_mutex);
 	mutex_init(&ei->delalloc_mutex);
 	btrfs_ordered_inode_tree_init(&ei->ordered_tree);
@@ -7072,7 +7231,10 @@
 		if (!ret)
 			ret = btrfs_update_inode(trans, root, old_inode);
 	}
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
+		goto out_fail;
+	}
 
 	if (new_inode) {
 		new_inode->i_ctime = CURRENT_TIME;
@@ -7090,11 +7252,14 @@
 						 new_dentry->d_name.name,
 						 new_dentry->d_name.len);
 		}
-		BUG_ON(ret);
-		if (new_inode->i_nlink == 0) {
+		if (!ret && new_inode->i_nlink == 0) {
 			ret = btrfs_orphan_add(trans, new_dentry->d_inode);
 			BUG_ON(ret);
 		}
+		if (ret) {
+			btrfs_abort_transaction(trans, root, ret);
+			goto out_fail;
+		}
 	}
 
 	fixup_inode_flags(new_dir, old_inode);
@@ -7102,7 +7267,10 @@
 	ret = btrfs_add_link(trans, new_dir, old_inode,
 			     new_dentry->d_name.name,
 			     new_dentry->d_name.len, 0, index);
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
+		goto out_fail;
+	}
 
 	if (old_ino != BTRFS_FIRST_FREE_OBJECTID) {
 		struct dentry *parent = new_dentry->d_parent;
@@ -7315,7 +7483,7 @@
 		}
 
 		ret = btrfs_reserve_extent(trans, root, num_bytes, min_size,
-					   0, *alloc_hint, (u64)-1, &ins, 1);
+					   0, *alloc_hint, &ins, 1);
 		if (ret) {
 			if (own_trans)
 				btrfs_end_transaction(trans, root);
@@ -7327,7 +7495,12 @@
 						  ins.offset, ins.offset,
 						  ins.offset, 0, 0, 0,
 						  BTRFS_FILE_EXTENT_PREALLOC);
-		BUG_ON(ret);
+		if (ret) {
+			btrfs_abort_transaction(trans, root, ret);
+			if (own_trans)
+				btrfs_end_transaction(trans, root);
+			break;
+		}
 		btrfs_drop_extent_cache(inode, cur_offset,
 					cur_offset + ins.offset -1, 0);
 
@@ -7349,7 +7522,13 @@
 		}
 
 		ret = btrfs_update_inode(trans, root, inode);
-		BUG_ON(ret);
+
+		if (ret) {
+			btrfs_abort_transaction(trans, root, ret);
+			if (own_trans)
+				btrfs_end_transaction(trans, root);
+			break;
+		}
 
 		if (own_trans)
 			btrfs_end_transaction(trans, root);
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index d8b5471..18cc23d 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -425,22 +425,37 @@
 
 	key.offset = (u64)-1;
 	new_root = btrfs_read_fs_root_no_name(root->fs_info, &key);
-	BUG_ON(IS_ERR(new_root));
+	if (IS_ERR(new_root)) {
+		btrfs_abort_transaction(trans, root, PTR_ERR(new_root));
+		ret = PTR_ERR(new_root);
+		goto fail;
+	}
 
 	btrfs_record_root_in_trans(trans, new_root);
 
 	ret = btrfs_create_subvol_root(trans, new_root, new_dirid);
+	if (ret) {
+		/* We potentially lose an unused inode item here */
+		btrfs_abort_transaction(trans, root, ret);
+		goto fail;
+	}
+
 	/*
 	 * insert the directory item
 	 */
 	ret = btrfs_set_inode_index(dir, &index);
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
+		goto fail;
+	}
 
 	ret = btrfs_insert_dir_item(trans, root,
 				    name, namelen, dir, &key,
 				    BTRFS_FT_DIR, index);
-	if (ret)
+	if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
 		goto fail;
+	}
 
 	btrfs_i_size_write(dir, dir->i_size + namelen * 2);
 	ret = btrfs_update_inode(trans, root, dir);
@@ -769,6 +784,31 @@
 	return -ENOENT;
 }
 
+/*
+ * Validaty check of prev em and next em:
+ * 1) no prev/next em
+ * 2) prev/next em is an hole/inline extent
+ */
+static int check_adjacent_extents(struct inode *inode, struct extent_map *em)
+{
+	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+	struct extent_map *prev = NULL, *next = NULL;
+	int ret = 0;
+
+	read_lock(&em_tree->lock);
+	prev = lookup_extent_mapping(em_tree, em->start - 1, (u64)-1);
+	next = lookup_extent_mapping(em_tree, em->start + em->len, (u64)-1);
+	read_unlock(&em_tree->lock);
+
+	if ((!prev || prev->block_start >= EXTENT_MAP_LAST_BYTE) &&
+	    (!next || next->block_start >= EXTENT_MAP_LAST_BYTE))
+		ret = 1;
+	free_extent_map(prev);
+	free_extent_map(next);
+
+	return ret;
+}
+
 static int should_defrag_range(struct inode *inode, u64 start, u64 len,
 			       int thresh, u64 *last_len, u64 *skip,
 			       u64 *defrag_end)
@@ -797,17 +837,25 @@
 
 	if (!em) {
 		/* get the big lock and read metadata off disk */
-		lock_extent(io_tree, start, start + len - 1, GFP_NOFS);
+		lock_extent(io_tree, start, start + len - 1);
 		em = btrfs_get_extent(inode, NULL, 0, start, len, 0);
-		unlock_extent(io_tree, start, start + len - 1, GFP_NOFS);
+		unlock_extent(io_tree, start, start + len - 1);
 
 		if (IS_ERR(em))
 			return 0;
 	}
 
 	/* this will cover holes, and inline extents */
-	if (em->block_start >= EXTENT_MAP_LAST_BYTE)
+	if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
 		ret = 0;
+		goto out;
+	}
+
+	/* If we have nothing to merge with us, just skip. */
+	if (check_adjacent_extents(inode, em)) {
+		ret = 0;
+		goto out;
+	}
 
 	/*
 	 * we hit a real extent, if it is big don't bother defragging it again
@@ -815,6 +863,7 @@
 	if ((*last_len == 0 || *last_len >= thresh) && em->len >= thresh)
 		ret = 0;
 
+out:
 	/*
 	 * last_len ends up being a counter of how many bytes we've defragged.
 	 * every time we choose not to defrag an extent, we reset *last_len
@@ -856,6 +905,7 @@
 	u64 isize = i_size_read(inode);
 	u64 page_start;
 	u64 page_end;
+	u64 page_cnt;
 	int ret;
 	int i;
 	int i_done;
@@ -864,19 +914,21 @@
 	struct extent_io_tree *tree;
 	gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping);
 
-	if (isize == 0)
-		return 0;
 	file_end = (isize - 1) >> PAGE_CACHE_SHIFT;
+	if (!isize || start_index > file_end)
+		return 0;
+
+	page_cnt = min_t(u64, (u64)num_pages, (u64)file_end - start_index + 1);
 
 	ret = btrfs_delalloc_reserve_space(inode,
-					   num_pages << PAGE_CACHE_SHIFT);
+					   page_cnt << PAGE_CACHE_SHIFT);
 	if (ret)
 		return ret;
 	i_done = 0;
 	tree = &BTRFS_I(inode)->io_tree;
 
 	/* step one, lock all the pages */
-	for (i = 0; i < num_pages; i++) {
+	for (i = 0; i < page_cnt; i++) {
 		struct page *page;
 again:
 		page = find_or_create_page(inode->i_mapping,
@@ -887,10 +939,10 @@
 		page_start = page_offset(page);
 		page_end = page_start + PAGE_CACHE_SIZE - 1;
 		while (1) {
-			lock_extent(tree, page_start, page_end, GFP_NOFS);
+			lock_extent(tree, page_start, page_end);
 			ordered = btrfs_lookup_ordered_extent(inode,
 							      page_start);
-			unlock_extent(tree, page_start, page_end, GFP_NOFS);
+			unlock_extent(tree, page_start, page_end);
 			if (!ordered)
 				break;
 
@@ -898,6 +950,15 @@
 			btrfs_start_ordered_extent(inode, ordered, 1);
 			btrfs_put_ordered_extent(ordered);
 			lock_page(page);
+			/*
+			 * we unlocked the page above, so we need check if
+			 * it was released or not.
+			 */
+			if (page->mapping != inode->i_mapping) {
+				unlock_page(page);
+				page_cache_release(page);
+				goto again;
+			}
 		}
 
 		if (!PageUptodate(page)) {
@@ -911,15 +972,6 @@
 			}
 		}
 
-		isize = i_size_read(inode);
-		file_end = (isize - 1) >> PAGE_CACHE_SHIFT;
-		if (!isize || page->index > file_end) {
-			/* whoops, we blew past eof, skip this page */
-			unlock_page(page);
-			page_cache_release(page);
-			break;
-		}
-
 		if (page->mapping != inode->i_mapping) {
 			unlock_page(page);
 			page_cache_release(page);
@@ -946,19 +998,18 @@
 	page_end = page_offset(pages[i_done - 1]) + PAGE_CACHE_SIZE;
 
 	lock_extent_bits(&BTRFS_I(inode)->io_tree,
-			 page_start, page_end - 1, 0, &cached_state,
-			 GFP_NOFS);
+			 page_start, page_end - 1, 0, &cached_state);
 	clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start,
 			  page_end - 1, EXTENT_DIRTY | EXTENT_DELALLOC |
 			  EXTENT_DO_ACCOUNTING, 0, 0, &cached_state,
 			  GFP_NOFS);
 
-	if (i_done != num_pages) {
+	if (i_done != page_cnt) {
 		spin_lock(&BTRFS_I(inode)->lock);
 		BTRFS_I(inode)->outstanding_extents++;
 		spin_unlock(&BTRFS_I(inode)->lock);
 		btrfs_delalloc_release_space(inode,
-				     (num_pages - i_done) << PAGE_CACHE_SHIFT);
+				     (page_cnt - i_done) << PAGE_CACHE_SHIFT);
 	}
 
 
@@ -983,7 +1034,7 @@
 		unlock_page(pages[i]);
 		page_cache_release(pages[i]);
 	}
-	btrfs_delalloc_release_space(inode, num_pages << PAGE_CACHE_SHIFT);
+	btrfs_delalloc_release_space(inode, page_cnt << PAGE_CACHE_SHIFT);
 	return ret;
 
 }
@@ -1089,12 +1140,9 @@
 		if (!(inode->i_sb->s_flags & MS_ACTIVE))
 			break;
 
-		if (!newer_than &&
-		    !should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT,
-					PAGE_CACHE_SIZE,
-					extent_thresh,
-					&last_len, &skip,
-					&defrag_end)) {
+		if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT,
+					 PAGE_CACHE_SIZE, extent_thresh,
+					 &last_len, &skip, &defrag_end)) {
 			unsigned long next;
 			/*
 			 * the should_defrag function tells us how much to skip
@@ -1123,17 +1171,24 @@
 			ra_index += max_cluster;
 		}
 
+		mutex_lock(&inode->i_mutex);
 		ret = cluster_pages_for_defrag(inode, pages, i, cluster);
-		if (ret < 0)
+		if (ret < 0) {
+			mutex_unlock(&inode->i_mutex);
 			goto out_ra;
+		}
 
 		defrag_count += ret;
 		balance_dirty_pages_ratelimited_nr(inode->i_mapping, ret);
+		mutex_unlock(&inode->i_mutex);
 
 		if (newer_than) {
 			if (newer_off == (u64)-1)
 				break;
 
+			if (ret > 0)
+				i += ret;
+
 			newer_off = max(newer_off + 1,
 					(u64)i << PAGE_CACHE_SHIFT);
 
@@ -1966,7 +2021,11 @@
 				dest->root_key.objectid,
 				dentry->d_name.name,
 				dentry->d_name.len);
-	BUG_ON(ret);
+	if (ret) {
+		err = ret;
+		btrfs_abort_transaction(trans, root, ret);
+		goto out_end_trans;
+	}
 
 	btrfs_record_root_in_trans(trans, dest);
 
@@ -1979,11 +2038,16 @@
 		ret = btrfs_insert_orphan_item(trans,
 					root->fs_info->tree_root,
 					dest->root_key.objectid);
-		BUG_ON(ret);
+		if (ret) {
+			btrfs_abort_transaction(trans, root, ret);
+			err = ret;
+			goto out_end_trans;
+		}
 	}
-
+out_end_trans:
 	ret = btrfs_end_transaction(trans, root);
-	BUG_ON(ret);
+	if (ret && !err)
+		err = ret;
 	inode->i_flags |= S_DEAD;
 out_up_write:
 	up_write(&root->fs_info->subvol_sem);
@@ -2326,13 +2390,13 @@
 	   another, and lock file content */
 	while (1) {
 		struct btrfs_ordered_extent *ordered;
-		lock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS);
+		lock_extent(&BTRFS_I(src)->io_tree, off, off+len);
 		ordered = btrfs_lookup_first_ordered_extent(src, off+len);
 		if (!ordered &&
 		    !test_range_bit(&BTRFS_I(src)->io_tree, off, off+len,
 				   EXTENT_DELALLOC, 0, NULL))
 			break;
-		unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS);
+		unlock_extent(&BTRFS_I(src)->io_tree, off, off+len);
 		if (ordered)
 			btrfs_put_ordered_extent(ordered);
 		btrfs_wait_ordered_range(src, off, len);
@@ -2447,11 +2511,21 @@
 							 new_key.offset,
 							 new_key.offset + datal,
 							 &hint_byte, 1);
-				BUG_ON(ret);
+				if (ret) {
+					btrfs_abort_transaction(trans, root,
+								ret);
+					btrfs_end_transaction(trans, root);
+					goto out;
+				}
 
 				ret = btrfs_insert_empty_item(trans, root, path,
 							      &new_key, size);
-				BUG_ON(ret);
+				if (ret) {
+					btrfs_abort_transaction(trans, root,
+								ret);
+					btrfs_end_transaction(trans, root);
+					goto out;
+				}
 
 				leaf = path->nodes[0];
 				slot = path->slots[0];
@@ -2478,7 +2552,15 @@
 							btrfs_ino(inode),
 							new_key.offset - datao,
 							0);
-					BUG_ON(ret);
+					if (ret) {
+						btrfs_abort_transaction(trans,
+									root,
+									ret);
+						btrfs_end_transaction(trans,
+								      root);
+						goto out;
+
+					}
 				}
 			} else if (type == BTRFS_FILE_EXTENT_INLINE) {
 				u64 skip = 0;
@@ -2503,11 +2585,21 @@
 							 new_key.offset,
 							 new_key.offset + datal,
 							 &hint_byte, 1);
-				BUG_ON(ret);
+				if (ret) {
+					btrfs_abort_transaction(trans, root,
+								ret);
+					btrfs_end_transaction(trans, root);
+					goto out;
+				}
 
 				ret = btrfs_insert_empty_item(trans, root, path,
 							      &new_key, size);
-				BUG_ON(ret);
+				if (ret) {
+					btrfs_abort_transaction(trans, root,
+								ret);
+					btrfs_end_transaction(trans, root);
+					goto out;
+				}
 
 				if (skip) {
 					u32 start =
@@ -2541,8 +2633,12 @@
 				btrfs_i_size_write(inode, endoff);
 
 			ret = btrfs_update_inode(trans, root, inode);
-			BUG_ON(ret);
-			btrfs_end_transaction(trans, root);
+			if (ret) {
+				btrfs_abort_transaction(trans, root, ret);
+				btrfs_end_transaction(trans, root);
+				goto out;
+			}
+			ret = btrfs_end_transaction(trans, root);
 		}
 next:
 		btrfs_release_path(path);
@@ -2551,7 +2647,7 @@
 	ret = 0;
 out:
 	btrfs_release_path(path);
-	unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS);
+	unlock_extent(&BTRFS_I(src)->io_tree, off, off+len);
 out_unlock:
 	mutex_unlock(&src->i_mutex);
 	mutex_unlock(&inode->i_mutex);
@@ -3066,8 +3162,8 @@
 		goto out;
 
 	extent_item_pos = loi->logical - key.objectid;
-	ret = iterate_extent_inodes(root->fs_info, path, key.objectid,
-					extent_item_pos, build_ino_list,
+	ret = iterate_extent_inodes(root->fs_info, key.objectid,
+					extent_item_pos, 0, build_ino_list,
 					inodes);
 
 	if (ret < 0)
diff --git a/fs/btrfs/locking.c b/fs/btrfs/locking.c
index 5e178d8..272f911 100644
--- a/fs/btrfs/locking.c
+++ b/fs/btrfs/locking.c
@@ -208,7 +208,7 @@
  * take a spinning write lock.  This will wait for both
  * blocking readers or writers
  */
-int btrfs_tree_lock(struct extent_buffer *eb)
+void btrfs_tree_lock(struct extent_buffer *eb)
 {
 again:
 	wait_event(eb->read_lock_wq, atomic_read(&eb->blocking_readers) == 0);
@@ -230,13 +230,12 @@
 	atomic_inc(&eb->spinning_writers);
 	atomic_inc(&eb->write_locks);
 	eb->lock_owner = current->pid;
-	return 0;
 }
 
 /*
  * drop a spinning or a blocking write lock.
  */
-int btrfs_tree_unlock(struct extent_buffer *eb)
+void btrfs_tree_unlock(struct extent_buffer *eb)
 {
 	int blockers = atomic_read(&eb->blocking_writers);
 
@@ -255,7 +254,6 @@
 		atomic_dec(&eb->spinning_writers);
 		write_unlock(&eb->lock);
 	}
-	return 0;
 }
 
 void btrfs_assert_tree_locked(struct extent_buffer *eb)
diff --git a/fs/btrfs/locking.h b/fs/btrfs/locking.h
index 17247dd..ca52681 100644
--- a/fs/btrfs/locking.h
+++ b/fs/btrfs/locking.h
@@ -24,8 +24,8 @@
 #define BTRFS_WRITE_LOCK_BLOCKING 3
 #define BTRFS_READ_LOCK_BLOCKING 4
 
-int btrfs_tree_lock(struct extent_buffer *eb);
-int btrfs_tree_unlock(struct extent_buffer *eb);
+void btrfs_tree_lock(struct extent_buffer *eb);
+void btrfs_tree_unlock(struct extent_buffer *eb);
 int btrfs_try_spin_lock(struct extent_buffer *eb);
 
 void btrfs_tree_read_lock(struct extent_buffer *eb);
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index a1c9404..bbf6d0d 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -59,6 +59,14 @@
 	return NULL;
 }
 
+static void ordered_data_tree_panic(struct inode *inode, int errno,
+					       u64 offset)
+{
+	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+	btrfs_panic(fs_info, errno, "Inconsistency in ordered tree at offset "
+		    "%llu\n", (unsigned long long)offset);
+}
+
 /*
  * look for a given offset in the tree, and if it can't be found return the
  * first lesser offset
@@ -207,7 +215,8 @@
 	spin_lock(&tree->lock);
 	node = tree_insert(&tree->tree, file_offset,
 			   &entry->rb_node);
-	BUG_ON(node);
+	if (node)
+		ordered_data_tree_panic(inode, -EEXIST, file_offset);
 	spin_unlock(&tree->lock);
 
 	spin_lock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
@@ -215,7 +224,6 @@
 		      &BTRFS_I(inode)->root->fs_info->ordered_extents);
 	spin_unlock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
 
-	BUG_ON(node);
 	return 0;
 }
 
@@ -249,9 +257,9 @@
  * when an ordered extent is finished.  If the list covers more than one
  * ordered extent, it is split across multiples.
  */
-int btrfs_add_ordered_sum(struct inode *inode,
-			  struct btrfs_ordered_extent *entry,
-			  struct btrfs_ordered_sum *sum)
+void btrfs_add_ordered_sum(struct inode *inode,
+			   struct btrfs_ordered_extent *entry,
+			   struct btrfs_ordered_sum *sum)
 {
 	struct btrfs_ordered_inode_tree *tree;
 
@@ -259,7 +267,6 @@
 	spin_lock(&tree->lock);
 	list_add_tail(&sum->list, &entry->list);
 	spin_unlock(&tree->lock);
-	return 0;
 }
 
 /*
@@ -384,7 +391,7 @@
  * used to drop a reference on an ordered extent.  This will free
  * the extent if the last reference is dropped
  */
-int btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry)
+void btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry)
 {
 	struct list_head *cur;
 	struct btrfs_ordered_sum *sum;
@@ -400,7 +407,6 @@
 		}
 		kfree(entry);
 	}
-	return 0;
 }
 
 /*
@@ -408,8 +414,8 @@
  * and you must wake_up entry->wait.  You must hold the tree lock
  * while you call this function.
  */
-static int __btrfs_remove_ordered_extent(struct inode *inode,
-				struct btrfs_ordered_extent *entry)
+static void __btrfs_remove_ordered_extent(struct inode *inode,
+					  struct btrfs_ordered_extent *entry)
 {
 	struct btrfs_ordered_inode_tree *tree;
 	struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -436,35 +442,30 @@
 		list_del_init(&BTRFS_I(inode)->ordered_operations);
 	}
 	spin_unlock(&root->fs_info->ordered_extent_lock);
-
-	return 0;
 }
 
 /*
  * remove an ordered extent from the tree.  No references are dropped
  * but any waiters are woken.
  */
-int btrfs_remove_ordered_extent(struct inode *inode,
-				struct btrfs_ordered_extent *entry)
+void btrfs_remove_ordered_extent(struct inode *inode,
+				 struct btrfs_ordered_extent *entry)
 {
 	struct btrfs_ordered_inode_tree *tree;
-	int ret;
 
 	tree = &BTRFS_I(inode)->ordered_tree;
 	spin_lock(&tree->lock);
-	ret = __btrfs_remove_ordered_extent(inode, entry);
+	__btrfs_remove_ordered_extent(inode, entry);
 	spin_unlock(&tree->lock);
 	wake_up(&entry->wait);
-
-	return ret;
 }
 
 /*
  * wait for all the ordered extents in a root.  This is done when balancing
  * space between drives.
  */
-int btrfs_wait_ordered_extents(struct btrfs_root *root,
-			       int nocow_only, int delay_iput)
+void btrfs_wait_ordered_extents(struct btrfs_root *root,
+				int nocow_only, int delay_iput)
 {
 	struct list_head splice;
 	struct list_head *cur;
@@ -512,7 +513,6 @@
 		spin_lock(&root->fs_info->ordered_extent_lock);
 	}
 	spin_unlock(&root->fs_info->ordered_extent_lock);
-	return 0;
 }
 
 /*
@@ -525,7 +525,7 @@
  * extra check to make sure the ordered operation list really is empty
  * before we return
  */
-int btrfs_run_ordered_operations(struct btrfs_root *root, int wait)
+void btrfs_run_ordered_operations(struct btrfs_root *root, int wait)
 {
 	struct btrfs_inode *btrfs_inode;
 	struct inode *inode;
@@ -573,8 +573,6 @@
 
 	spin_unlock(&root->fs_info->ordered_extent_lock);
 	mutex_unlock(&root->fs_info->ordered_operations_mutex);
-
-	return 0;
 }
 
 /*
@@ -609,7 +607,7 @@
 /*
  * Used to wait on ordered extents across a large range of bytes.
  */
-int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
+void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
 {
 	u64 end;
 	u64 orig_end;
@@ -664,7 +662,6 @@
 		schedule_timeout(1);
 		goto again;
 	}
-	return 0;
 }
 
 /*
@@ -948,9 +945,8 @@
  * If trans is not null, we'll do a friendly check for a transaction that
  * is already flushing things and force the IO down ourselves.
  */
-int btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
-				struct btrfs_root *root,
-				struct inode *inode)
+void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
+				 struct btrfs_root *root, struct inode *inode)
 {
 	u64 last_mod;
 
@@ -961,7 +957,7 @@
 	 * commit, we can safely return without doing anything
 	 */
 	if (last_mod < root->fs_info->last_trans_committed)
-		return 0;
+		return;
 
 	/*
 	 * the transaction is already committing.  Just start the IO and
@@ -969,7 +965,7 @@
 	 */
 	if (trans && root->fs_info->running_transaction->blocked) {
 		btrfs_wait_ordered_range(inode, 0, (u64)-1);
-		return 0;
+		return;
 	}
 
 	spin_lock(&root->fs_info->ordered_extent_lock);
@@ -978,6 +974,4 @@
 			      &root->fs_info->ordered_operations);
 	}
 	spin_unlock(&root->fs_info->ordered_extent_lock);
-
-	return 0;
 }
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
index ff1f69a..c355ad4 100644
--- a/fs/btrfs/ordered-data.h
+++ b/fs/btrfs/ordered-data.h
@@ -138,8 +138,8 @@
 	t->last = NULL;
 }
 
-int btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry);
-int btrfs_remove_ordered_extent(struct inode *inode,
+void btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry);
+void btrfs_remove_ordered_extent(struct inode *inode,
 				struct btrfs_ordered_extent *entry);
 int btrfs_dec_test_ordered_pending(struct inode *inode,
 				   struct btrfs_ordered_extent **cached,
@@ -154,14 +154,14 @@
 int btrfs_add_ordered_extent_compress(struct inode *inode, u64 file_offset,
 				      u64 start, u64 len, u64 disk_len,
 				      int type, int compress_type);
-int btrfs_add_ordered_sum(struct inode *inode,
-			  struct btrfs_ordered_extent *entry,
-			  struct btrfs_ordered_sum *sum);
+void btrfs_add_ordered_sum(struct inode *inode,
+			   struct btrfs_ordered_extent *entry,
+			   struct btrfs_ordered_sum *sum);
 struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode,
 							 u64 file_offset);
 void btrfs_start_ordered_extent(struct inode *inode,
 				struct btrfs_ordered_extent *entry, int wait);
-int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len);
+void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len);
 struct btrfs_ordered_extent *
 btrfs_lookup_first_ordered_extent(struct inode * inode, u64 file_offset);
 struct btrfs_ordered_extent *btrfs_lookup_ordered_range(struct inode *inode,
@@ -170,10 +170,10 @@
 int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
 				struct btrfs_ordered_extent *ordered);
 int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, u32 *sum);
-int btrfs_run_ordered_operations(struct btrfs_root *root, int wait);
-int btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
-				struct btrfs_root *root,
-				struct inode *inode);
-int btrfs_wait_ordered_extents(struct btrfs_root *root,
-			       int nocow_only, int delay_iput);
+void btrfs_run_ordered_operations(struct btrfs_root *root, int wait);
+void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
+				 struct btrfs_root *root,
+				 struct inode *inode);
+void btrfs_wait_ordered_extents(struct btrfs_root *root,
+				int nocow_only, int delay_iput);
 #endif
diff --git a/fs/btrfs/orphan.c b/fs/btrfs/orphan.c
index f8be250..24cad16 100644
--- a/fs/btrfs/orphan.c
+++ b/fs/btrfs/orphan.c
@@ -58,7 +58,7 @@
 	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
 	if (ret < 0)
 		goto out;
-	if (ret) {
+	if (ret) { /* JDM: Really? */
 		ret = -ENOENT;
 		goto out;
 	}
diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c
index 22db045..dc5d331 100644
--- a/fs/btrfs/reada.c
+++ b/fs/btrfs/reada.c
@@ -54,7 +54,6 @@
  * than the 2 started one after another.
  */
 
-#define MAX_MIRRORS 2
 #define MAX_IN_FLIGHT 6
 
 struct reada_extctl {
@@ -71,7 +70,7 @@
 	struct list_head	extctl;
 	struct kref		refcnt;
 	spinlock_t		lock;
-	struct reada_zone	*zones[MAX_MIRRORS];
+	struct reada_zone	*zones[BTRFS_MAX_MIRRORS];
 	int			nzones;
 	struct btrfs_device	*scheduled_for;
 };
@@ -84,7 +83,8 @@
 	spinlock_t		lock;
 	int			locked;
 	struct btrfs_device	*device;
-	struct btrfs_device	*devs[MAX_MIRRORS]; /* full list, incl self */
+	struct btrfs_device	*devs[BTRFS_MAX_MIRRORS]; /* full list, incl
+							   * self */
 	int			ndevs;
 	struct kref		refcnt;
 };
@@ -365,9 +365,9 @@
 	if (ret || !bbio || length < blocksize)
 		goto error;
 
-	if (bbio->num_stripes > MAX_MIRRORS) {
+	if (bbio->num_stripes > BTRFS_MAX_MIRRORS) {
 		printk(KERN_ERR "btrfs readahead: more than %d copies not "
-				"supported", MAX_MIRRORS);
+				"supported", BTRFS_MAX_MIRRORS);
 		goto error;
 	}
 
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 8c1aae2..017281d 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -326,6 +326,19 @@
 	return NULL;
 }
 
+void backref_tree_panic(struct rb_node *rb_node, int errno,
+					  u64 bytenr)
+{
+
+	struct btrfs_fs_info *fs_info = NULL;
+	struct backref_node *bnode = rb_entry(rb_node, struct backref_node,
+					      rb_node);
+	if (bnode->root)
+		fs_info = bnode->root->fs_info;
+	btrfs_panic(fs_info, errno, "Inconsistency in backref cache "
+		    "found at offset %llu\n", (unsigned long long)bytenr);
+}
+
 /*
  * walk up backref nodes until reach node presents tree root
  */
@@ -452,7 +465,8 @@
 	rb_erase(&node->rb_node, &cache->rb_root);
 	node->bytenr = bytenr;
 	rb_node = tree_insert(&cache->rb_root, node->bytenr, &node->rb_node);
-	BUG_ON(rb_node);
+	if (rb_node)
+		backref_tree_panic(rb_node, -EEXIST, bytenr);
 }
 
 /*
@@ -999,7 +1013,8 @@
 	if (!cowonly) {
 		rb_node = tree_insert(&cache->rb_root, node->bytenr,
 				      &node->rb_node);
-		BUG_ON(rb_node);
+		if (rb_node)
+			backref_tree_panic(rb_node, -EEXIST, node->bytenr);
 		list_add_tail(&node->lower, &cache->leaves);
 	}
 
@@ -1034,7 +1049,9 @@
 		if (!cowonly) {
 			rb_node = tree_insert(&cache->rb_root, upper->bytenr,
 					      &upper->rb_node);
-			BUG_ON(rb_node);
+			if (rb_node)
+				backref_tree_panic(rb_node, -EEXIST,
+						   upper->bytenr);
 		}
 
 		list_add_tail(&edge->list[UPPER], &upper->lower);
@@ -1180,7 +1197,8 @@
 
 	rb_node = tree_insert(&cache->rb_root, new_node->bytenr,
 			      &new_node->rb_node);
-	BUG_ON(rb_node);
+	if (rb_node)
+		backref_tree_panic(rb_node, -EEXIST, new_node->bytenr);
 
 	if (!new_node->lowest) {
 		list_for_each_entry(new_edge, &new_node->lower, list[UPPER]) {
@@ -1203,14 +1221,15 @@
 /*
  * helper to add 'address of tree root -> reloc tree' mapping
  */
-static int __add_reloc_root(struct btrfs_root *root)
+static int __must_check __add_reloc_root(struct btrfs_root *root)
 {
 	struct rb_node *rb_node;
 	struct mapping_node *node;
 	struct reloc_control *rc = root->fs_info->reloc_ctl;
 
 	node = kmalloc(sizeof(*node), GFP_NOFS);
-	BUG_ON(!node);
+	if (!node)
+		return -ENOMEM;
 
 	node->bytenr = root->node->start;
 	node->data = root;
@@ -1219,7 +1238,12 @@
 	rb_node = tree_insert(&rc->reloc_root_tree.rb_root,
 			      node->bytenr, &node->rb_node);
 	spin_unlock(&rc->reloc_root_tree.lock);
-	BUG_ON(rb_node);
+	if (rb_node) {
+		kfree(node);
+		btrfs_panic(root->fs_info, -EEXIST, "Duplicate root found "
+			    "for start=%llu while inserting into relocation "
+			    "tree\n");
+	}
 
 	list_add_tail(&root->root_list, &rc->reloc_roots);
 	return 0;
@@ -1252,7 +1276,8 @@
 		rb_node = tree_insert(&rc->reloc_root_tree.rb_root,
 				      node->bytenr, &node->rb_node);
 		spin_unlock(&rc->reloc_root_tree.lock);
-		BUG_ON(rb_node);
+		if (rb_node)
+			backref_tree_panic(rb_node, -EEXIST, node->bytenr);
 	} else {
 		list_del_init(&root->root_list);
 		kfree(node);
@@ -1334,6 +1359,7 @@
 	struct btrfs_root *reloc_root;
 	struct reloc_control *rc = root->fs_info->reloc_ctl;
 	int clear_rsv = 0;
+	int ret;
 
 	if (root->reloc_root) {
 		reloc_root = root->reloc_root;
@@ -1353,7 +1379,8 @@
 	if (clear_rsv)
 		trans->block_rsv = NULL;
 
-	__add_reloc_root(reloc_root);
+	ret = __add_reloc_root(reloc_root);
+	BUG_ON(ret < 0);
 	root->reloc_root = reloc_root;
 	return 0;
 }
@@ -1577,15 +1604,14 @@
 				WARN_ON(!IS_ALIGNED(end, root->sectorsize));
 				end--;
 				ret = try_lock_extent(&BTRFS_I(inode)->io_tree,
-						      key.offset, end,
-						      GFP_NOFS);
+						      key.offset, end);
 				if (!ret)
 					continue;
 
 				btrfs_drop_extent_cache(inode, key.offset, end,
 							1);
 				unlock_extent(&BTRFS_I(inode)->io_tree,
-					      key.offset, end, GFP_NOFS);
+					      key.offset, end);
 			}
 		}
 
@@ -1956,9 +1982,9 @@
 		}
 
 		/* the lock_extent waits for readpage to complete */
-		lock_extent(&BTRFS_I(inode)->io_tree, start, end, GFP_NOFS);
+		lock_extent(&BTRFS_I(inode)->io_tree, start, end);
 		btrfs_drop_extent_cache(inode, start, end, 1);
-		unlock_extent(&BTRFS_I(inode)->io_tree, start, end, GFP_NOFS);
+		unlock_extent(&BTRFS_I(inode)->io_tree, start, end);
 	}
 	return 0;
 }
@@ -2246,7 +2272,8 @@
 		} else {
 			list_del_init(&reloc_root->root_list);
 		}
-		btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0, 1);
+		ret = btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0, 1);
+		BUG_ON(ret < 0);
 	}
 
 	if (found) {
@@ -2862,12 +2889,12 @@
 		else
 			end = cluster->end - offset;
 
-		lock_extent(&BTRFS_I(inode)->io_tree, start, end, GFP_NOFS);
+		lock_extent(&BTRFS_I(inode)->io_tree, start, end);
 		num_bytes = end + 1 - start;
 		ret = btrfs_prealloc_file_range(inode, 0, start,
 						num_bytes, num_bytes,
 						end + 1, &alloc_hint);
-		unlock_extent(&BTRFS_I(inode)->io_tree, start, end, GFP_NOFS);
+		unlock_extent(&BTRFS_I(inode)->io_tree, start, end);
 		if (ret)
 			break;
 		nr++;
@@ -2899,7 +2926,7 @@
 	em->bdev = root->fs_info->fs_devices->latest_bdev;
 	set_bit(EXTENT_FLAG_PINNED, &em->flags);
 
-	lock_extent(&BTRFS_I(inode)->io_tree, start, end, GFP_NOFS);
+	lock_extent(&BTRFS_I(inode)->io_tree, start, end);
 	while (1) {
 		write_lock(&em_tree->lock);
 		ret = add_extent_mapping(em_tree, em);
@@ -2910,7 +2937,7 @@
 		}
 		btrfs_drop_extent_cache(inode, start, end, 0);
 	}
-	unlock_extent(&BTRFS_I(inode)->io_tree, start, end, GFP_NOFS);
+	unlock_extent(&BTRFS_I(inode)->io_tree, start, end);
 	return ret;
 }
 
@@ -2990,8 +3017,7 @@
 		page_start = (u64)page->index << PAGE_CACHE_SHIFT;
 		page_end = page_start + PAGE_CACHE_SIZE - 1;
 
-		lock_extent(&BTRFS_I(inode)->io_tree,
-			    page_start, page_end, GFP_NOFS);
+		lock_extent(&BTRFS_I(inode)->io_tree, page_start, page_end);
 
 		set_page_extent_mapped(page);
 
@@ -3007,7 +3033,7 @@
 		set_page_dirty(page);
 
 		unlock_extent(&BTRFS_I(inode)->io_tree,
-			      page_start, page_end, GFP_NOFS);
+			      page_start, page_end);
 		unlock_page(page);
 		page_cache_release(page);
 
@@ -3154,7 +3180,8 @@
 	block->key_ready = 0;
 
 	rb_node = tree_insert(blocks, block->bytenr, &block->rb_node);
-	BUG_ON(rb_node);
+	if (rb_node)
+		backref_tree_panic(rb_node, -EEXIST, block->bytenr);
 
 	return 0;
 }
@@ -3426,7 +3453,9 @@
 			block->key_ready = 1;
 			rb_node = tree_insert(blocks, block->bytenr,
 					      &block->rb_node);
-			BUG_ON(rb_node);
+			if (rb_node)
+				backref_tree_panic(rb_node, -EEXIST,
+						   block->bytenr);
 		}
 		if (counted)
 			added = 1;
@@ -4073,10 +4102,11 @@
 static noinline_for_stack int mark_garbage_root(struct btrfs_root *root)
 {
 	struct btrfs_trans_handle *trans;
-	int ret;
+	int ret, err;
 
 	trans = btrfs_start_transaction(root->fs_info->tree_root, 0);
-	BUG_ON(IS_ERR(trans));
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
 
 	memset(&root->root_item.drop_progress, 0,
 		sizeof(root->root_item.drop_progress));
@@ -4084,11 +4114,11 @@
 	btrfs_set_root_refs(&root->root_item, 0);
 	ret = btrfs_update_root(trans, root->fs_info->tree_root,
 				&root->root_key, &root->root_item);
-	BUG_ON(ret);
 
-	ret = btrfs_end_transaction(trans, root->fs_info->tree_root);
-	BUG_ON(ret);
-	return 0;
+	err = btrfs_end_transaction(trans, root->fs_info->tree_root);
+	if (err)
+		return err;
+	return ret;
 }
 
 /*
@@ -4156,7 +4186,11 @@
 					err = ret;
 					goto out;
 				}
-				mark_garbage_root(reloc_root);
+				ret = mark_garbage_root(reloc_root);
+				if (ret < 0) {
+					err = ret;
+					goto out;
+				}
 			}
 		}
 
@@ -4202,13 +4236,19 @@
 
 		fs_root = read_fs_root(root->fs_info,
 				       reloc_root->root_key.offset);
-		BUG_ON(IS_ERR(fs_root));
+		if (IS_ERR(fs_root)) {
+			err = PTR_ERR(fs_root);
+			goto out_free;
+		}
 
-		__add_reloc_root(reloc_root);
+		err = __add_reloc_root(reloc_root);
+		BUG_ON(err < 0); /* -ENOMEM or logic error */
 		fs_root->reloc_root = reloc_root;
 	}
 
-	btrfs_commit_transaction(trans, rc->extent_root);
+	err = btrfs_commit_transaction(trans, rc->extent_root);
+	if (err)
+		goto out_free;
 
 	merge_reloc_roots(rc);
 
@@ -4218,7 +4258,7 @@
 	if (IS_ERR(trans))
 		err = PTR_ERR(trans);
 	else
-		btrfs_commit_transaction(trans, rc->extent_root);
+		err = btrfs_commit_transaction(trans, rc->extent_root);
 out_free:
 	kfree(rc);
 out:
@@ -4267,6 +4307,8 @@
 	disk_bytenr = file_pos + BTRFS_I(inode)->index_cnt;
 	ret = btrfs_lookup_csums_range(root->fs_info->csum_root, disk_bytenr,
 				       disk_bytenr + len - 1, &list, 0);
+	if (ret)
+		goto out;
 
 	while (!list_empty(&list)) {
 		sums = list_entry(list.next, struct btrfs_ordered_sum, list);
@@ -4284,6 +4326,7 @@
 
 		btrfs_add_ordered_sum(inode, ordered, sums);
 	}
+out:
 	btrfs_put_ordered_extent(ordered);
 	return ret;
 }
@@ -4380,7 +4423,7 @@
  * called after snapshot is created. migrate block reservation
  * and create reloc root for the newly created snapshot
  */
-void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
+int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
 			       struct btrfs_pending_snapshot *pending)
 {
 	struct btrfs_root *root = pending->root;
@@ -4390,7 +4433,7 @@
 	int ret;
 
 	if (!root->reloc_root)
-		return;
+		return 0;
 
 	rc = root->fs_info->reloc_ctl;
 	rc->merging_rsv_size += rc->nodes_relocated;
@@ -4399,18 +4442,21 @@
 		ret = btrfs_block_rsv_migrate(&pending->block_rsv,
 					      rc->block_rsv,
 					      rc->nodes_relocated);
-		BUG_ON(ret);
+		if (ret)
+			return ret;
 	}
 
 	new_root = pending->snap;
 	reloc_root = create_reloc_root(trans, root->reloc_root,
 				       new_root->root_key.objectid);
+	if (IS_ERR(reloc_root))
+		return PTR_ERR(reloc_root);
 
-	__add_reloc_root(reloc_root);
+	ret = __add_reloc_root(reloc_root);
+	BUG_ON(ret < 0);
 	new_root->reloc_root = reloc_root;
 
-	if (rc->create_reloc_tree) {
+	if (rc->create_reloc_tree)
 		ret = clone_backref_node(trans, rc, root, reloc_root);
-		BUG_ON(ret);
-	}
+	return ret;
 }
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c
index f409990..24fb8ce 100644
--- a/fs/btrfs/root-tree.c
+++ b/fs/btrfs/root-tree.c
@@ -93,10 +93,14 @@
 	unsigned long ptr;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	if (!path)
+		return -ENOMEM;
+
 	ret = btrfs_search_slot(trans, root, key, path, 0, 1);
-	if (ret < 0)
+	if (ret < 0) {
+		btrfs_abort_transaction(trans, root, ret);
 		goto out;
+	}
 
 	if (ret != 0) {
 		btrfs_print_leaf(root, path->nodes[0]);
@@ -116,13 +120,10 @@
 	return ret;
 }
 
-int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
-		      *root, struct btrfs_key *key, struct btrfs_root_item
-		      *item)
+int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+		      struct btrfs_key *key, struct btrfs_root_item *item)
 {
-	int ret;
-	ret = btrfs_insert_item(trans, root, key, item, sizeof(*item));
-	return ret;
+	return btrfs_insert_item(trans, root, key, item, sizeof(*item));
 }
 
 /*
@@ -384,6 +385,8 @@
  *
  * For a back ref the root_id is the id of the subvol or snapshot and
  * ref_id is the id of the tree referencing it.
+ *
+ * Will return 0, -ENOMEM, or anything from the CoW path
  */
 int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
 		       struct btrfs_root *tree_root,
@@ -407,7 +410,11 @@
 again:
 	ret = btrfs_insert_empty_item(trans, tree_root, path, &key,
 				      sizeof(*ref) + name_len);
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_abort_transaction(trans, tree_root, ret);
+		btrfs_free_path(path);
+		return ret;
+	}
 
 	leaf = path->nodes[0];
 	ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 390e710..90acc82 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -36,37 +36,30 @@
  * Future enhancements:
  *  - In case an unrepairable extent is encountered, track which files are
  *    affected and report them
- *  - In case of a read error on files with nodatasum, map the file and read
- *    the extent to trigger a writeback of the good copy
  *  - track and record media errors, throw out bad devices
  *  - add a mode to also read unallocated space
  */
 
-struct scrub_bio;
-struct scrub_page;
+struct scrub_block;
 struct scrub_dev;
-static void scrub_bio_end_io(struct bio *bio, int err);
-static void scrub_checksum(struct btrfs_work *work);
-static int scrub_checksum_data(struct scrub_dev *sdev,
-			       struct scrub_page *spag, void *buffer);
-static int scrub_checksum_tree_block(struct scrub_dev *sdev,
-				     struct scrub_page *spag, u64 logical,
-				     void *buffer);
-static int scrub_checksum_super(struct scrub_bio *sbio, void *buffer);
-static int scrub_fixup_check(struct scrub_bio *sbio, int ix);
-static void scrub_fixup_end_io(struct bio *bio, int err);
-static int scrub_fixup_io(int rw, struct block_device *bdev, sector_t sector,
-			  struct page *page);
-static void scrub_fixup(struct scrub_bio *sbio, int ix);
 
 #define SCRUB_PAGES_PER_BIO	16	/* 64k per bio */
 #define SCRUB_BIOS_PER_DEV	16	/* 1 MB per device in flight */
+#define SCRUB_MAX_PAGES_PER_BLOCK	16	/* 64k per node/leaf/sector */
 
 struct scrub_page {
+	struct scrub_block	*sblock;
+	struct page		*page;
+	struct block_device	*bdev;
 	u64			flags;  /* extent flags */
 	u64			generation;
-	int			mirror_num;
-	int			have_csum;
+	u64			logical;
+	u64			physical;
+	struct {
+		unsigned int	mirror_num:8;
+		unsigned int	have_csum:1;
+		unsigned int	io_error:1;
+	};
 	u8			csum[BTRFS_CSUM_SIZE];
 };
 
@@ -77,12 +70,25 @@
 	int			err;
 	u64			logical;
 	u64			physical;
-	struct scrub_page	spag[SCRUB_PAGES_PER_BIO];
-	u64			count;
+	struct scrub_page	*pagev[SCRUB_PAGES_PER_BIO];
+	int			page_count;
 	int			next_free;
 	struct btrfs_work	work;
 };
 
+struct scrub_block {
+	struct scrub_page	pagev[SCRUB_MAX_PAGES_PER_BLOCK];
+	int			page_count;
+	atomic_t		outstanding_pages;
+	atomic_t		ref_count; /* free mem on transition to zero */
+	struct scrub_dev	*sdev;
+	struct {
+		unsigned int	header_error:1;
+		unsigned int	checksum_error:1;
+		unsigned int	no_io_error_seen:1;
+	};
+};
+
 struct scrub_dev {
 	struct scrub_bio	*bios[SCRUB_BIOS_PER_DEV];
 	struct btrfs_device	*dev;
@@ -96,6 +102,10 @@
 	struct list_head	csum_list;
 	atomic_t		cancel_req;
 	int			readonly;
+	int			pages_per_bio; /* <= SCRUB_PAGES_PER_BIO */
+	u32			sectorsize;
+	u32			nodesize;
+	u32			leafsize;
 	/*
 	 * statistics
 	 */
@@ -124,6 +134,43 @@
 	int			scratch_bufsize;
 };
 
+
+static int scrub_handle_errored_block(struct scrub_block *sblock_to_check);
+static int scrub_setup_recheck_block(struct scrub_dev *sdev,
+				     struct btrfs_mapping_tree *map_tree,
+				     u64 length, u64 logical,
+				     struct scrub_block *sblock);
+static int scrub_recheck_block(struct btrfs_fs_info *fs_info,
+			       struct scrub_block *sblock, int is_metadata,
+			       int have_csum, u8 *csum, u64 generation,
+			       u16 csum_size);
+static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
+					 struct scrub_block *sblock,
+					 int is_metadata, int have_csum,
+					 const u8 *csum, u64 generation,
+					 u16 csum_size);
+static void scrub_complete_bio_end_io(struct bio *bio, int err);
+static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad,
+					     struct scrub_block *sblock_good,
+					     int force_write);
+static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
+					    struct scrub_block *sblock_good,
+					    int page_num, int force_write);
+static int scrub_checksum_data(struct scrub_block *sblock);
+static int scrub_checksum_tree_block(struct scrub_block *sblock);
+static int scrub_checksum_super(struct scrub_block *sblock);
+static void scrub_block_get(struct scrub_block *sblock);
+static void scrub_block_put(struct scrub_block *sblock);
+static int scrub_add_page_to_bio(struct scrub_dev *sdev,
+				 struct scrub_page *spage);
+static int scrub_pages(struct scrub_dev *sdev, u64 logical, u64 len,
+		       u64 physical, u64 flags, u64 gen, int mirror_num,
+		       u8 *csum, int force);
+static void scrub_bio_end_io(struct bio *bio, int err);
+static void scrub_bio_end_io_worker(struct btrfs_work *work);
+static void scrub_block_complete(struct scrub_block *sblock);
+
+
 static void scrub_free_csums(struct scrub_dev *sdev)
 {
 	while (!list_empty(&sdev->csum_list)) {
@@ -135,23 +182,6 @@
 	}
 }
 
-static void scrub_free_bio(struct bio *bio)
-{
-	int i;
-	struct page *last_page = NULL;
-
-	if (!bio)
-		return;
-
-	for (i = 0; i < bio->bi_vcnt; ++i) {
-		if (bio->bi_io_vec[i].bv_page == last_page)
-			continue;
-		last_page = bio->bi_io_vec[i].bv_page;
-		__free_page(last_page);
-	}
-	bio_put(bio);
-}
-
 static noinline_for_stack void scrub_free_dev(struct scrub_dev *sdev)
 {
 	int i;
@@ -159,13 +189,23 @@
 	if (!sdev)
 		return;
 
+	/* this can happen when scrub is cancelled */
+	if (sdev->curr != -1) {
+		struct scrub_bio *sbio = sdev->bios[sdev->curr];
+
+		for (i = 0; i < sbio->page_count; i++) {
+			BUG_ON(!sbio->pagev[i]);
+			BUG_ON(!sbio->pagev[i]->page);
+			scrub_block_put(sbio->pagev[i]->sblock);
+		}
+		bio_put(sbio->bio);
+	}
+
 	for (i = 0; i < SCRUB_BIOS_PER_DEV; ++i) {
 		struct scrub_bio *sbio = sdev->bios[i];
 
 		if (!sbio)
 			break;
-
-		scrub_free_bio(sbio->bio);
 		kfree(sbio);
 	}
 
@@ -179,11 +219,16 @@
 	struct scrub_dev *sdev;
 	int		i;
 	struct btrfs_fs_info *fs_info = dev->dev_root->fs_info;
+	int pages_per_bio;
 
+	pages_per_bio = min_t(int, SCRUB_PAGES_PER_BIO,
+			      bio_get_nr_vecs(dev->bdev));
 	sdev = kzalloc(sizeof(*sdev), GFP_NOFS);
 	if (!sdev)
 		goto nomem;
 	sdev->dev = dev;
+	sdev->pages_per_bio = pages_per_bio;
+	sdev->curr = -1;
 	for (i = 0; i < SCRUB_BIOS_PER_DEV; ++i) {
 		struct scrub_bio *sbio;
 
@@ -194,8 +239,8 @@
 
 		sbio->index = i;
 		sbio->sdev = sdev;
-		sbio->count = 0;
-		sbio->work.func = scrub_checksum;
+		sbio->page_count = 0;
+		sbio->work.func = scrub_bio_end_io_worker;
 
 		if (i != SCRUB_BIOS_PER_DEV-1)
 			sdev->bios[i]->next_free = i + 1;
@@ -203,7 +248,9 @@
 			sdev->bios[i]->next_free = -1;
 	}
 	sdev->first_free = 0;
-	sdev->curr = -1;
+	sdev->nodesize = dev->dev_root->nodesize;
+	sdev->leafsize = dev->dev_root->leafsize;
+	sdev->sectorsize = dev->dev_root->sectorsize;
 	atomic_set(&sdev->in_flight, 0);
 	atomic_set(&sdev->fixup_cnt, 0);
 	atomic_set(&sdev->cancel_req, 0);
@@ -294,10 +341,9 @@
 	return 0;
 }
 
-static void scrub_print_warning(const char *errstr, struct scrub_bio *sbio,
-				int ix)
+static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
 {
-	struct btrfs_device *dev = sbio->sdev->dev;
+	struct btrfs_device *dev = sblock->sdev->dev;
 	struct btrfs_fs_info *fs_info = dev->dev_root->fs_info;
 	struct btrfs_path *path;
 	struct btrfs_key found_key;
@@ -316,8 +362,9 @@
 
 	swarn.scratch_buf = kmalloc(bufsize, GFP_NOFS);
 	swarn.msg_buf = kmalloc(bufsize, GFP_NOFS);
-	swarn.sector = (sbio->physical + ix * PAGE_SIZE) >> 9;
-	swarn.logical = sbio->logical + ix * PAGE_SIZE;
+	BUG_ON(sblock->page_count < 1);
+	swarn.sector = (sblock->pagev[0].physical) >> 9;
+	swarn.logical = sblock->pagev[0].logical;
 	swarn.errstr = errstr;
 	swarn.dev = dev;
 	swarn.msg_bufsize = bufsize;
@@ -342,7 +389,8 @@
 		do {
 			ret = tree_backref_for_extent(&ptr, eb, ei, item_size,
 							&ref_root, &ref_level);
-			printk(KERN_WARNING "%s at logical %llu on dev %s, "
+			printk(KERN_WARNING
+				"btrfs: %s at logical %llu on dev %s, "
 				"sector %llu: metadata %s (level %d) in tree "
 				"%llu\n", errstr, swarn.logical, dev->name,
 				(unsigned long long)swarn.sector,
@@ -352,8 +400,8 @@
 		} while (ret != 1);
 	} else {
 		swarn.path = path;
-		iterate_extent_inodes(fs_info, path, found_key.objectid,
-					extent_item_pos,
+		iterate_extent_inodes(fs_info, found_key.objectid,
+					extent_item_pos, 1,
 					scrub_print_warning_inode, &swarn);
 	}
 
@@ -531,9 +579,9 @@
 		spin_lock(&sdev->stat_lock);
 		++sdev->stat.uncorrectable_errors;
 		spin_unlock(&sdev->stat_lock);
-		printk_ratelimited(KERN_ERR "btrfs: unable to fixup "
-					"(nodatasum) error at logical %llu\n",
-					fixup->logical);
+		printk_ratelimited(KERN_ERR
+			"btrfs: unable to fixup (nodatasum) error at logical %llu on dev %s\n",
+			(unsigned long long)fixup->logical, sdev->dev->name);
 	}
 
 	btrfs_free_path(path);
@@ -550,91 +598,168 @@
 }
 
 /*
- * scrub_recheck_error gets called when either verification of the page
- * failed or the bio failed to read, e.g. with EIO. In the latter case,
- * recheck_error gets called for every page in the bio, even though only
- * one may be bad
+ * scrub_handle_errored_block gets called when either verification of the
+ * pages failed or the bio failed to read, e.g. with EIO. In the latter
+ * case, this function handles all pages in the bio, even though only one
+ * may be bad.
+ * The goal of this function is to repair the errored block by using the
+ * contents of one of the mirrors.
  */
-static int scrub_recheck_error(struct scrub_bio *sbio, int ix)
+static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
 {
-	struct scrub_dev *sdev = sbio->sdev;
-	u64 sector = (sbio->physical + ix * PAGE_SIZE) >> 9;
-	static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
-					DEFAULT_RATELIMIT_BURST);
-
-	if (sbio->err) {
-		if (scrub_fixup_io(READ, sbio->sdev->dev->bdev, sector,
-				   sbio->bio->bi_io_vec[ix].bv_page) == 0) {
-			if (scrub_fixup_check(sbio, ix) == 0)
-				return 0;
-		}
-		if (__ratelimit(&_rs))
-			scrub_print_warning("i/o error", sbio, ix);
-	} else {
-		if (__ratelimit(&_rs))
-			scrub_print_warning("checksum error", sbio, ix);
-	}
-
-	spin_lock(&sdev->stat_lock);
-	++sdev->stat.read_errors;
-	spin_unlock(&sdev->stat_lock);
-
-	scrub_fixup(sbio, ix);
-	return 1;
-}
-
-static int scrub_fixup_check(struct scrub_bio *sbio, int ix)
-{
-	int ret = 1;
-	struct page *page;
-	void *buffer;
-	u64 flags = sbio->spag[ix].flags;
-
-	page = sbio->bio->bi_io_vec[ix].bv_page;
-	buffer = kmap_atomic(page);
-	if (flags & BTRFS_EXTENT_FLAG_DATA) {
-		ret = scrub_checksum_data(sbio->sdev,
-					  sbio->spag + ix, buffer);
-	} else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
-		ret = scrub_checksum_tree_block(sbio->sdev,
-						sbio->spag + ix,
-						sbio->logical + ix * PAGE_SIZE,
-						buffer);
-	} else {
-		WARN_ON(1);
-	}
-	kunmap_atomic(buffer);
-
-	return ret;
-}
-
-static void scrub_fixup_end_io(struct bio *bio, int err)
-{
-	complete((struct completion *)bio->bi_private);
-}
-
-static void scrub_fixup(struct scrub_bio *sbio, int ix)
-{
-	struct scrub_dev *sdev = sbio->sdev;
-	struct btrfs_fs_info *fs_info = sdev->dev->dev_root->fs_info;
-	struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
-	struct btrfs_bio *bbio = NULL;
-	struct scrub_fixup_nodatasum *fixup;
-	u64 logical = sbio->logical + ix * PAGE_SIZE;
+	struct scrub_dev *sdev = sblock_to_check->sdev;
+	struct btrfs_fs_info *fs_info;
 	u64 length;
-	int i;
+	u64 logical;
+	u64 generation;
+	unsigned int failed_mirror_index;
+	unsigned int is_metadata;
+	unsigned int have_csum;
+	u8 *csum;
+	struct scrub_block *sblocks_for_recheck; /* holds one for each mirror */
+	struct scrub_block *sblock_bad;
 	int ret;
-	DECLARE_COMPLETION_ONSTACK(complete);
+	int mirror_index;
+	int page_num;
+	int success;
+	static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
+				      DEFAULT_RATELIMIT_BURST);
 
-	if ((sbio->spag[ix].flags & BTRFS_EXTENT_FLAG_DATA) &&
-	    (sbio->spag[ix].have_csum == 0)) {
-		fixup = kzalloc(sizeof(*fixup), GFP_NOFS);
-		if (!fixup)
-			goto uncorrectable;
-		fixup->sdev = sdev;
-		fixup->logical = logical;
-		fixup->root = fs_info->extent_root;
-		fixup->mirror_num = sbio->spag[ix].mirror_num;
+	BUG_ON(sblock_to_check->page_count < 1);
+	fs_info = sdev->dev->dev_root->fs_info;
+	length = sblock_to_check->page_count * PAGE_SIZE;
+	logical = sblock_to_check->pagev[0].logical;
+	generation = sblock_to_check->pagev[0].generation;
+	BUG_ON(sblock_to_check->pagev[0].mirror_num < 1);
+	failed_mirror_index = sblock_to_check->pagev[0].mirror_num - 1;
+	is_metadata = !(sblock_to_check->pagev[0].flags &
+			BTRFS_EXTENT_FLAG_DATA);
+	have_csum = sblock_to_check->pagev[0].have_csum;
+	csum = sblock_to_check->pagev[0].csum;
+
+	/*
+	 * read all mirrors one after the other. This includes to
+	 * re-read the extent or metadata block that failed (that was
+	 * the cause that this fixup code is called) another time,
+	 * page by page this time in order to know which pages
+	 * caused I/O errors and which ones are good (for all mirrors).
+	 * It is the goal to handle the situation when more than one
+	 * mirror contains I/O errors, but the errors do not
+	 * overlap, i.e. the data can be repaired by selecting the
+	 * pages from those mirrors without I/O error on the
+	 * particular pages. One example (with blocks >= 2 * PAGE_SIZE)
+	 * would be that mirror #1 has an I/O error on the first page,
+	 * the second page is good, and mirror #2 has an I/O error on
+	 * the second page, but the first page is good.
+	 * Then the first page of the first mirror can be repaired by
+	 * taking the first page of the second mirror, and the
+	 * second page of the second mirror can be repaired by
+	 * copying the contents of the 2nd page of the 1st mirror.
+	 * One more note: if the pages of one mirror contain I/O
+	 * errors, the checksum cannot be verified. In order to get
+	 * the best data for repairing, the first attempt is to find
+	 * a mirror without I/O errors and with a validated checksum.
+	 * Only if this is not possible, the pages are picked from
+	 * mirrors with I/O errors without considering the checksum.
+	 * If the latter is the case, at the end, the checksum of the
+	 * repaired area is verified in order to correctly maintain
+	 * the statistics.
+	 */
+
+	sblocks_for_recheck = kzalloc(BTRFS_MAX_MIRRORS *
+				     sizeof(*sblocks_for_recheck),
+				     GFP_NOFS);
+	if (!sblocks_for_recheck) {
+		spin_lock(&sdev->stat_lock);
+		sdev->stat.malloc_errors++;
+		sdev->stat.read_errors++;
+		sdev->stat.uncorrectable_errors++;
+		spin_unlock(&sdev->stat_lock);
+		goto out;
+	}
+
+	/* setup the context, map the logical blocks and alloc the pages */
+	ret = scrub_setup_recheck_block(sdev, &fs_info->mapping_tree, length,
+					logical, sblocks_for_recheck);
+	if (ret) {
+		spin_lock(&sdev->stat_lock);
+		sdev->stat.read_errors++;
+		sdev->stat.uncorrectable_errors++;
+		spin_unlock(&sdev->stat_lock);
+		goto out;
+	}
+	BUG_ON(failed_mirror_index >= BTRFS_MAX_MIRRORS);
+	sblock_bad = sblocks_for_recheck + failed_mirror_index;
+
+	/* build and submit the bios for the failed mirror, check checksums */
+	ret = scrub_recheck_block(fs_info, sblock_bad, is_metadata, have_csum,
+				  csum, generation, sdev->csum_size);
+	if (ret) {
+		spin_lock(&sdev->stat_lock);
+		sdev->stat.read_errors++;
+		sdev->stat.uncorrectable_errors++;
+		spin_unlock(&sdev->stat_lock);
+		goto out;
+	}
+
+	if (!sblock_bad->header_error && !sblock_bad->checksum_error &&
+	    sblock_bad->no_io_error_seen) {
+		/*
+		 * the error disappeared after reading page by page, or
+		 * the area was part of a huge bio and other parts of the
+		 * bio caused I/O errors, or the block layer merged several
+		 * read requests into one and the error is caused by a
+		 * different bio (usually one of the two latter cases is
+		 * the cause)
+		 */
+		spin_lock(&sdev->stat_lock);
+		sdev->stat.unverified_errors++;
+		spin_unlock(&sdev->stat_lock);
+
+		goto out;
+	}
+
+	if (!sblock_bad->no_io_error_seen) {
+		spin_lock(&sdev->stat_lock);
+		sdev->stat.read_errors++;
+		spin_unlock(&sdev->stat_lock);
+		if (__ratelimit(&_rs))
+			scrub_print_warning("i/o error", sblock_to_check);
+	} else if (sblock_bad->checksum_error) {
+		spin_lock(&sdev->stat_lock);
+		sdev->stat.csum_errors++;
+		spin_unlock(&sdev->stat_lock);
+		if (__ratelimit(&_rs))
+			scrub_print_warning("checksum error", sblock_to_check);
+	} else if (sblock_bad->header_error) {
+		spin_lock(&sdev->stat_lock);
+		sdev->stat.verify_errors++;
+		spin_unlock(&sdev->stat_lock);
+		if (__ratelimit(&_rs))
+			scrub_print_warning("checksum/header error",
+					    sblock_to_check);
+	}
+
+	if (sdev->readonly)
+		goto did_not_correct_error;
+
+	if (!is_metadata && !have_csum) {
+		struct scrub_fixup_nodatasum *fixup_nodatasum;
+
+		/*
+		 * !is_metadata and !have_csum, this means that the data
+		 * might not be COW'ed, that it might be modified
+		 * concurrently. The general strategy to work on the
+		 * commit root does not help in the case when COW is not
+		 * used.
+		 */
+		fixup_nodatasum = kzalloc(sizeof(*fixup_nodatasum), GFP_NOFS);
+		if (!fixup_nodatasum)
+			goto did_not_correct_error;
+		fixup_nodatasum->sdev = sdev;
+		fixup_nodatasum->logical = logical;
+		fixup_nodatasum->root = fs_info->extent_root;
+		fixup_nodatasum->mirror_num = failed_mirror_index + 1;
 		/*
 		 * increment scrubs_running to prevent cancel requests from
 		 * completing as long as a fixup worker is running. we must also
@@ -649,235 +774,528 @@
 		atomic_inc(&fs_info->scrubs_paused);
 		mutex_unlock(&fs_info->scrub_lock);
 		atomic_inc(&sdev->fixup_cnt);
-		fixup->work.func = scrub_fixup_nodatasum;
-		btrfs_queue_worker(&fs_info->scrub_workers, &fixup->work);
-		return;
-	}
-
-	length = PAGE_SIZE;
-	ret = btrfs_map_block(map_tree, REQ_WRITE, logical, &length,
-			      &bbio, 0);
-	if (ret || !bbio || length < PAGE_SIZE) {
-		printk(KERN_ERR
-		       "scrub_fixup: btrfs_map_block failed us for %llu\n",
-		       (unsigned long long)logical);
-		WARN_ON(1);
-		kfree(bbio);
-		return;
-	}
-
-	if (bbio->num_stripes == 1)
-		/* there aren't any replicas */
-		goto uncorrectable;
-
-	/*
-	 * first find a good copy
-	 */
-	for (i = 0; i < bbio->num_stripes; ++i) {
-		if (i + 1 == sbio->spag[ix].mirror_num)
-			continue;
-
-		if (scrub_fixup_io(READ, bbio->stripes[i].dev->bdev,
-				   bbio->stripes[i].physical >> 9,
-				   sbio->bio->bi_io_vec[ix].bv_page)) {
-			/* I/O-error, this is not a good copy */
-			continue;
-		}
-
-		if (scrub_fixup_check(sbio, ix) == 0)
-			break;
-	}
-	if (i == bbio->num_stripes)
-		goto uncorrectable;
-
-	if (!sdev->readonly) {
-		/*
-		 * bi_io_vec[ix].bv_page now contains good data, write it back
-		 */
-		if (scrub_fixup_io(WRITE, sdev->dev->bdev,
-				   (sbio->physical + ix * PAGE_SIZE) >> 9,
-				   sbio->bio->bi_io_vec[ix].bv_page)) {
-			/* I/O-error, writeback failed, give up */
-			goto uncorrectable;
-		}
-	}
-
-	kfree(bbio);
-	spin_lock(&sdev->stat_lock);
-	++sdev->stat.corrected_errors;
-	spin_unlock(&sdev->stat_lock);
-
-	printk_ratelimited(KERN_ERR "btrfs: fixed up error at logical %llu\n",
-			       (unsigned long long)logical);
-	return;
-
-uncorrectable:
-	kfree(bbio);
-	spin_lock(&sdev->stat_lock);
-	++sdev->stat.uncorrectable_errors;
-	spin_unlock(&sdev->stat_lock);
-
-	printk_ratelimited(KERN_ERR "btrfs: unable to fixup (regular) error at "
-				"logical %llu\n", (unsigned long long)logical);
-}
-
-static int scrub_fixup_io(int rw, struct block_device *bdev, sector_t sector,
-			 struct page *page)
-{
-	struct bio *bio = NULL;
-	int ret;
-	DECLARE_COMPLETION_ONSTACK(complete);
-
-	bio = bio_alloc(GFP_NOFS, 1);
-	bio->bi_bdev = bdev;
-	bio->bi_sector = sector;
-	bio_add_page(bio, page, PAGE_SIZE, 0);
-	bio->bi_end_io = scrub_fixup_end_io;
-	bio->bi_private = &complete;
-	btrfsic_submit_bio(rw, bio);
-
-	/* this will also unplug the queue */
-	wait_for_completion(&complete);
-
-	ret = !test_bit(BIO_UPTODATE, &bio->bi_flags);
-	bio_put(bio);
-	return ret;
-}
-
-static void scrub_bio_end_io(struct bio *bio, int err)
-{
-	struct scrub_bio *sbio = bio->bi_private;
-	struct scrub_dev *sdev = sbio->sdev;
-	struct btrfs_fs_info *fs_info = sdev->dev->dev_root->fs_info;
-
-	sbio->err = err;
-	sbio->bio = bio;
-
-	btrfs_queue_worker(&fs_info->scrub_workers, &sbio->work);
-}
-
-static void scrub_checksum(struct btrfs_work *work)
-{
-	struct scrub_bio *sbio = container_of(work, struct scrub_bio, work);
-	struct scrub_dev *sdev = sbio->sdev;
-	struct page *page;
-	void *buffer;
-	int i;
-	u64 flags;
-	u64 logical;
-	int ret;
-
-	if (sbio->err) {
-		ret = 0;
-		for (i = 0; i < sbio->count; ++i)
-			ret |= scrub_recheck_error(sbio, i);
-		if (!ret) {
-			spin_lock(&sdev->stat_lock);
-			++sdev->stat.unverified_errors;
-			spin_unlock(&sdev->stat_lock);
-		}
-
-		sbio->bio->bi_flags &= ~(BIO_POOL_MASK - 1);
-		sbio->bio->bi_flags |= 1 << BIO_UPTODATE;
-		sbio->bio->bi_phys_segments = 0;
-		sbio->bio->bi_idx = 0;
-
-		for (i = 0; i < sbio->count; i++) {
-			struct bio_vec *bi;
-			bi = &sbio->bio->bi_io_vec[i];
-			bi->bv_offset = 0;
-			bi->bv_len = PAGE_SIZE;
-		}
+		fixup_nodatasum->work.func = scrub_fixup_nodatasum;
+		btrfs_queue_worker(&fs_info->scrub_workers,
+				   &fixup_nodatasum->work);
 		goto out;
 	}
-	for (i = 0; i < sbio->count; ++i) {
-		page = sbio->bio->bi_io_vec[i].bv_page;
-		buffer = kmap_atomic(page);
-		flags = sbio->spag[i].flags;
-		logical = sbio->logical + i * PAGE_SIZE;
-		ret = 0;
-		if (flags & BTRFS_EXTENT_FLAG_DATA) {
-			ret = scrub_checksum_data(sdev, sbio->spag + i, buffer);
-		} else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
-			ret = scrub_checksum_tree_block(sdev, sbio->spag + i,
-							logical, buffer);
-		} else if (flags & BTRFS_EXTENT_FLAG_SUPER) {
-			BUG_ON(i);
-			(void)scrub_checksum_super(sbio, buffer);
-		} else {
-			WARN_ON(1);
+
+	/*
+	 * now build and submit the bios for the other mirrors, check
+	 * checksums
+	 */
+	for (mirror_index = 0;
+	     mirror_index < BTRFS_MAX_MIRRORS &&
+	     sblocks_for_recheck[mirror_index].page_count > 0;
+	     mirror_index++) {
+		if (mirror_index == failed_mirror_index)
+			continue;
+
+		/* build and submit the bios, check checksums */
+		ret = scrub_recheck_block(fs_info,
+					  sblocks_for_recheck + mirror_index,
+					  is_metadata, have_csum, csum,
+					  generation, sdev->csum_size);
+		if (ret)
+			goto did_not_correct_error;
+	}
+
+	/*
+	 * first try to pick the mirror which is completely without I/O
+	 * errors and also does not have a checksum error.
+	 * If one is found, and if a checksum is present, the full block
+	 * that is known to contain an error is rewritten. Afterwards
+	 * the block is known to be corrected.
+	 * If a mirror is found which is completely correct, and no
+	 * checksum is present, only those pages are rewritten that had
+	 * an I/O error in the block to be repaired, since it cannot be
+	 * determined, which copy of the other pages is better (and it
+	 * could happen otherwise that a correct page would be
+	 * overwritten by a bad one).
+	 */
+	for (mirror_index = 0;
+	     mirror_index < BTRFS_MAX_MIRRORS &&
+	     sblocks_for_recheck[mirror_index].page_count > 0;
+	     mirror_index++) {
+		struct scrub_block *sblock_other = sblocks_for_recheck +
+						   mirror_index;
+
+		if (!sblock_other->header_error &&
+		    !sblock_other->checksum_error &&
+		    sblock_other->no_io_error_seen) {
+			int force_write = is_metadata || have_csum;
+
+			ret = scrub_repair_block_from_good_copy(sblock_bad,
+								sblock_other,
+								force_write);
+			if (0 == ret)
+				goto corrected_error;
 		}
-		kunmap_atomic(buffer);
-		if (ret) {
-			ret = scrub_recheck_error(sbio, i);
-			if (!ret) {
-				spin_lock(&sdev->stat_lock);
-				++sdev->stat.unverified_errors;
-				spin_unlock(&sdev->stat_lock);
+	}
+
+	/*
+	 * in case of I/O errors in the area that is supposed to be
+	 * repaired, continue by picking good copies of those pages.
+	 * Select the good pages from mirrors to rewrite bad pages from
+	 * the area to fix. Afterwards verify the checksum of the block
+	 * that is supposed to be repaired. This verification step is
+	 * only done for the purpose of statistic counting and for the
+	 * final scrub report, whether errors remain.
+	 * A perfect algorithm could make use of the checksum and try
+	 * all possible combinations of pages from the different mirrors
+	 * until the checksum verification succeeds. For example, when
+	 * the 2nd page of mirror #1 faces I/O errors, and the 2nd page
+	 * of mirror #2 is readable but the final checksum test fails,
+	 * then the 2nd page of mirror #3 could be tried, whether now
+	 * the final checksum succeedes. But this would be a rare
+	 * exception and is therefore not implemented. At least it is
+	 * avoided that the good copy is overwritten.
+	 * A more useful improvement would be to pick the sectors
+	 * without I/O error based on sector sizes (512 bytes on legacy
+	 * disks) instead of on PAGE_SIZE. Then maybe 512 byte of one
+	 * mirror could be repaired by taking 512 byte of a different
+	 * mirror, even if other 512 byte sectors in the same PAGE_SIZE
+	 * area are unreadable.
+	 */
+
+	/* can only fix I/O errors from here on */
+	if (sblock_bad->no_io_error_seen)
+		goto did_not_correct_error;
+
+	success = 1;
+	for (page_num = 0; page_num < sblock_bad->page_count; page_num++) {
+		struct scrub_page *page_bad = sblock_bad->pagev + page_num;
+
+		if (!page_bad->io_error)
+			continue;
+
+		for (mirror_index = 0;
+		     mirror_index < BTRFS_MAX_MIRRORS &&
+		     sblocks_for_recheck[mirror_index].page_count > 0;
+		     mirror_index++) {
+			struct scrub_block *sblock_other = sblocks_for_recheck +
+							   mirror_index;
+			struct scrub_page *page_other = sblock_other->pagev +
+							page_num;
+
+			if (!page_other->io_error) {
+				ret = scrub_repair_page_from_good_copy(
+					sblock_bad, sblock_other, page_num, 0);
+				if (0 == ret) {
+					page_bad->io_error = 0;
+					break; /* succeeded for this page */
+				}
 			}
 		}
+
+		if (page_bad->io_error) {
+			/* did not find a mirror to copy the page from */
+			success = 0;
+		}
+	}
+
+	if (success) {
+		if (is_metadata || have_csum) {
+			/*
+			 * need to verify the checksum now that all
+			 * sectors on disk are repaired (the write
+			 * request for data to be repaired is on its way).
+			 * Just be lazy and use scrub_recheck_block()
+			 * which re-reads the data before the checksum
+			 * is verified, but most likely the data comes out
+			 * of the page cache.
+			 */
+			ret = scrub_recheck_block(fs_info, sblock_bad,
+						  is_metadata, have_csum, csum,
+						  generation, sdev->csum_size);
+			if (!ret && !sblock_bad->header_error &&
+			    !sblock_bad->checksum_error &&
+			    sblock_bad->no_io_error_seen)
+				goto corrected_error;
+			else
+				goto did_not_correct_error;
+		} else {
+corrected_error:
+			spin_lock(&sdev->stat_lock);
+			sdev->stat.corrected_errors++;
+			spin_unlock(&sdev->stat_lock);
+			printk_ratelimited(KERN_ERR
+				"btrfs: fixed up error at logical %llu on dev %s\n",
+				(unsigned long long)logical, sdev->dev->name);
+		}
+	} else {
+did_not_correct_error:
+		spin_lock(&sdev->stat_lock);
+		sdev->stat.uncorrectable_errors++;
+		spin_unlock(&sdev->stat_lock);
+		printk_ratelimited(KERN_ERR
+			"btrfs: unable to fixup (regular) error at logical %llu on dev %s\n",
+			(unsigned long long)logical, sdev->dev->name);
 	}
 
 out:
-	scrub_free_bio(sbio->bio);
-	sbio->bio = NULL;
-	spin_lock(&sdev->list_lock);
-	sbio->next_free = sdev->first_free;
-	sdev->first_free = sbio->index;
-	spin_unlock(&sdev->list_lock);
-	atomic_dec(&sdev->in_flight);
-	wake_up(&sdev->list_wait);
+	if (sblocks_for_recheck) {
+		for (mirror_index = 0; mirror_index < BTRFS_MAX_MIRRORS;
+		     mirror_index++) {
+			struct scrub_block *sblock = sblocks_for_recheck +
+						     mirror_index;
+			int page_index;
+
+			for (page_index = 0; page_index < SCRUB_PAGES_PER_BIO;
+			     page_index++)
+				if (sblock->pagev[page_index].page)
+					__free_page(
+						sblock->pagev[page_index].page);
+		}
+		kfree(sblocks_for_recheck);
+	}
+
+	return 0;
 }
 
-static int scrub_checksum_data(struct scrub_dev *sdev,
-			       struct scrub_page *spag, void *buffer)
+static int scrub_setup_recheck_block(struct scrub_dev *sdev,
+				     struct btrfs_mapping_tree *map_tree,
+				     u64 length, u64 logical,
+				     struct scrub_block *sblocks_for_recheck)
 {
+	int page_index;
+	int mirror_index;
+	int ret;
+
+	/*
+	 * note: the three members sdev, ref_count and outstanding_pages
+	 * are not used (and not set) in the blocks that are used for
+	 * the recheck procedure
+	 */
+
+	page_index = 0;
+	while (length > 0) {
+		u64 sublen = min_t(u64, length, PAGE_SIZE);
+		u64 mapped_length = sublen;
+		struct btrfs_bio *bbio = NULL;
+
+		/*
+		 * with a length of PAGE_SIZE, each returned stripe
+		 * represents one mirror
+		 */
+		ret = btrfs_map_block(map_tree, WRITE, logical, &mapped_length,
+				      &bbio, 0);
+		if (ret || !bbio || mapped_length < sublen) {
+			kfree(bbio);
+			return -EIO;
+		}
+
+		BUG_ON(page_index >= SCRUB_PAGES_PER_BIO);
+		for (mirror_index = 0; mirror_index < (int)bbio->num_stripes;
+		     mirror_index++) {
+			struct scrub_block *sblock;
+			struct scrub_page *page;
+
+			if (mirror_index >= BTRFS_MAX_MIRRORS)
+				continue;
+
+			sblock = sblocks_for_recheck + mirror_index;
+			page = sblock->pagev + page_index;
+			page->logical = logical;
+			page->physical = bbio->stripes[mirror_index].physical;
+			page->bdev = bbio->stripes[mirror_index].dev->bdev;
+			page->mirror_num = mirror_index + 1;
+			page->page = alloc_page(GFP_NOFS);
+			if (!page->page) {
+				spin_lock(&sdev->stat_lock);
+				sdev->stat.malloc_errors++;
+				spin_unlock(&sdev->stat_lock);
+				return -ENOMEM;
+			}
+			sblock->page_count++;
+		}
+		kfree(bbio);
+		length -= sublen;
+		logical += sublen;
+		page_index++;
+	}
+
+	return 0;
+}
+
+/*
+ * this function will check the on disk data for checksum errors, header
+ * errors and read I/O errors. If any I/O errors happen, the exact pages
+ * which are errored are marked as being bad. The goal is to enable scrub
+ * to take those pages that are not errored from all the mirrors so that
+ * the pages that are errored in the just handled mirror can be repaired.
+ */
+static int scrub_recheck_block(struct btrfs_fs_info *fs_info,
+			       struct scrub_block *sblock, int is_metadata,
+			       int have_csum, u8 *csum, u64 generation,
+			       u16 csum_size)
+{
+	int page_num;
+
+	sblock->no_io_error_seen = 1;
+	sblock->header_error = 0;
+	sblock->checksum_error = 0;
+
+	for (page_num = 0; page_num < sblock->page_count; page_num++) {
+		struct bio *bio;
+		int ret;
+		struct scrub_page *page = sblock->pagev + page_num;
+		DECLARE_COMPLETION_ONSTACK(complete);
+
+		BUG_ON(!page->page);
+		bio = bio_alloc(GFP_NOFS, 1);
+		bio->bi_bdev = page->bdev;
+		bio->bi_sector = page->physical >> 9;
+		bio->bi_end_io = scrub_complete_bio_end_io;
+		bio->bi_private = &complete;
+
+		ret = bio_add_page(bio, page->page, PAGE_SIZE, 0);
+		if (PAGE_SIZE != ret) {
+			bio_put(bio);
+			return -EIO;
+		}
+		btrfsic_submit_bio(READ, bio);
+
+		/* this will also unplug the queue */
+		wait_for_completion(&complete);
+
+		page->io_error = !test_bit(BIO_UPTODATE, &bio->bi_flags);
+		if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
+			sblock->no_io_error_seen = 0;
+		bio_put(bio);
+	}
+
+	if (sblock->no_io_error_seen)
+		scrub_recheck_block_checksum(fs_info, sblock, is_metadata,
+					     have_csum, csum, generation,
+					     csum_size);
+
+	return 0;
+}
+
+static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
+					 struct scrub_block *sblock,
+					 int is_metadata, int have_csum,
+					 const u8 *csum, u64 generation,
+					 u16 csum_size)
+{
+	int page_num;
+	u8 calculated_csum[BTRFS_CSUM_SIZE];
+	u32 crc = ~(u32)0;
+	struct btrfs_root *root = fs_info->extent_root;
+	void *mapped_buffer;
+
+	BUG_ON(!sblock->pagev[0].page);
+	if (is_metadata) {
+		struct btrfs_header *h;
+
+		mapped_buffer = kmap_atomic(sblock->pagev[0].page);
+		h = (struct btrfs_header *)mapped_buffer;
+
+		if (sblock->pagev[0].logical != le64_to_cpu(h->bytenr) ||
+		    generation != le64_to_cpu(h->generation) ||
+		    memcmp(h->fsid, fs_info->fsid, BTRFS_UUID_SIZE) ||
+		    memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid,
+			   BTRFS_UUID_SIZE))
+			sblock->header_error = 1;
+		csum = h->csum;
+	} else {
+		if (!have_csum)
+			return;
+
+		mapped_buffer = kmap_atomic(sblock->pagev[0].page);
+	}
+
+	for (page_num = 0;;) {
+		if (page_num == 0 && is_metadata)
+			crc = btrfs_csum_data(root,
+				((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE,
+				crc, PAGE_SIZE - BTRFS_CSUM_SIZE);
+		else
+			crc = btrfs_csum_data(root, mapped_buffer, crc,
+					      PAGE_SIZE);
+
+		kunmap_atomic(mapped_buffer);
+		page_num++;
+		if (page_num >= sblock->page_count)
+			break;
+		BUG_ON(!sblock->pagev[page_num].page);
+
+		mapped_buffer = kmap_atomic(sblock->pagev[page_num].page);
+	}
+
+	btrfs_csum_final(crc, calculated_csum);
+	if (memcmp(calculated_csum, csum, csum_size))
+		sblock->checksum_error = 1;
+}
+
+static void scrub_complete_bio_end_io(struct bio *bio, int err)
+{
+	complete((struct completion *)bio->bi_private);
+}
+
+static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad,
+					     struct scrub_block *sblock_good,
+					     int force_write)
+{
+	int page_num;
+	int ret = 0;
+
+	for (page_num = 0; page_num < sblock_bad->page_count; page_num++) {
+		int ret_sub;
+
+		ret_sub = scrub_repair_page_from_good_copy(sblock_bad,
+							   sblock_good,
+							   page_num,
+							   force_write);
+		if (ret_sub)
+			ret = ret_sub;
+	}
+
+	return ret;
+}
+
+static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
+					    struct scrub_block *sblock_good,
+					    int page_num, int force_write)
+{
+	struct scrub_page *page_bad = sblock_bad->pagev + page_num;
+	struct scrub_page *page_good = sblock_good->pagev + page_num;
+
+	BUG_ON(sblock_bad->pagev[page_num].page == NULL);
+	BUG_ON(sblock_good->pagev[page_num].page == NULL);
+	if (force_write || sblock_bad->header_error ||
+	    sblock_bad->checksum_error || page_bad->io_error) {
+		struct bio *bio;
+		int ret;
+		DECLARE_COMPLETION_ONSTACK(complete);
+
+		bio = bio_alloc(GFP_NOFS, 1);
+		bio->bi_bdev = page_bad->bdev;
+		bio->bi_sector = page_bad->physical >> 9;
+		bio->bi_end_io = scrub_complete_bio_end_io;
+		bio->bi_private = &complete;
+
+		ret = bio_add_page(bio, page_good->page, PAGE_SIZE, 0);
+		if (PAGE_SIZE != ret) {
+			bio_put(bio);
+			return -EIO;
+		}
+		btrfsic_submit_bio(WRITE, bio);
+
+		/* this will also unplug the queue */
+		wait_for_completion(&complete);
+		bio_put(bio);
+	}
+
+	return 0;
+}
+
+static void scrub_checksum(struct scrub_block *sblock)
+{
+	u64 flags;
+	int ret;
+
+	BUG_ON(sblock->page_count < 1);
+	flags = sblock->pagev[0].flags;
+	ret = 0;
+	if (flags & BTRFS_EXTENT_FLAG_DATA)
+		ret = scrub_checksum_data(sblock);
+	else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)
+		ret = scrub_checksum_tree_block(sblock);
+	else if (flags & BTRFS_EXTENT_FLAG_SUPER)
+		(void)scrub_checksum_super(sblock);
+	else
+		WARN_ON(1);
+	if (ret)
+		scrub_handle_errored_block(sblock);
+}
+
+static int scrub_checksum_data(struct scrub_block *sblock)
+{
+	struct scrub_dev *sdev = sblock->sdev;
 	u8 csum[BTRFS_CSUM_SIZE];
+	u8 *on_disk_csum;
+	struct page *page;
+	void *buffer;
 	u32 crc = ~(u32)0;
 	int fail = 0;
 	struct btrfs_root *root = sdev->dev->dev_root;
+	u64 len;
+	int index;
 
-	if (!spag->have_csum)
+	BUG_ON(sblock->page_count < 1);
+	if (!sblock->pagev[0].have_csum)
 		return 0;
 
-	crc = btrfs_csum_data(root, buffer, crc, PAGE_SIZE);
+	on_disk_csum = sblock->pagev[0].csum;
+	page = sblock->pagev[0].page;
+	buffer = kmap_atomic(page);
+
+	len = sdev->sectorsize;
+	index = 0;
+	for (;;) {
+		u64 l = min_t(u64, len, PAGE_SIZE);
+
+		crc = btrfs_csum_data(root, buffer, crc, l);
+		kunmap_atomic(buffer);
+		len -= l;
+		if (len == 0)
+			break;
+		index++;
+		BUG_ON(index >= sblock->page_count);
+		BUG_ON(!sblock->pagev[index].page);
+		page = sblock->pagev[index].page;
+		buffer = kmap_atomic(page);
+	}
+
 	btrfs_csum_final(crc, csum);
-	if (memcmp(csum, spag->csum, sdev->csum_size))
+	if (memcmp(csum, on_disk_csum, sdev->csum_size))
 		fail = 1;
 
-	spin_lock(&sdev->stat_lock);
-	++sdev->stat.data_extents_scrubbed;
-	sdev->stat.data_bytes_scrubbed += PAGE_SIZE;
-	if (fail)
+	if (fail) {
+		spin_lock(&sdev->stat_lock);
 		++sdev->stat.csum_errors;
-	spin_unlock(&sdev->stat_lock);
+		spin_unlock(&sdev->stat_lock);
+	}
 
 	return fail;
 }
 
-static int scrub_checksum_tree_block(struct scrub_dev *sdev,
-				     struct scrub_page *spag, u64 logical,
-				     void *buffer)
+static int scrub_checksum_tree_block(struct scrub_block *sblock)
 {
+	struct scrub_dev *sdev = sblock->sdev;
 	struct btrfs_header *h;
 	struct btrfs_root *root = sdev->dev->dev_root;
 	struct btrfs_fs_info *fs_info = root->fs_info;
-	u8 csum[BTRFS_CSUM_SIZE];
+	u8 calculated_csum[BTRFS_CSUM_SIZE];
+	u8 on_disk_csum[BTRFS_CSUM_SIZE];
+	struct page *page;
+	void *mapped_buffer;
+	u64 mapped_size;
+	void *p;
 	u32 crc = ~(u32)0;
 	int fail = 0;
 	int crc_fail = 0;
+	u64 len;
+	int index;
+
+	BUG_ON(sblock->page_count < 1);
+	page = sblock->pagev[0].page;
+	mapped_buffer = kmap_atomic(page);
+	h = (struct btrfs_header *)mapped_buffer;
+	memcpy(on_disk_csum, h->csum, sdev->csum_size);
 
 	/*
 	 * we don't use the getter functions here, as we
 	 * a) don't have an extent buffer and
 	 * b) the page is already kmapped
 	 */
-	h = (struct btrfs_header *)buffer;
 
-	if (logical != le64_to_cpu(h->bytenr))
+	if (sblock->pagev[0].logical != le64_to_cpu(h->bytenr))
 		++fail;
 
-	if (spag->generation != le64_to_cpu(h->generation))
+	if (sblock->pagev[0].generation != le64_to_cpu(h->generation))
 		++fail;
 
 	if (memcmp(h->fsid, fs_info->fsid, BTRFS_UUID_SIZE))
@@ -887,51 +1305,99 @@
 		   BTRFS_UUID_SIZE))
 		++fail;
 
-	crc = btrfs_csum_data(root, buffer + BTRFS_CSUM_SIZE, crc,
-			      PAGE_SIZE - BTRFS_CSUM_SIZE);
-	btrfs_csum_final(crc, csum);
-	if (memcmp(csum, h->csum, sdev->csum_size))
+	BUG_ON(sdev->nodesize != sdev->leafsize);
+	len = sdev->nodesize - BTRFS_CSUM_SIZE;
+	mapped_size = PAGE_SIZE - BTRFS_CSUM_SIZE;
+	p = ((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE;
+	index = 0;
+	for (;;) {
+		u64 l = min_t(u64, len, mapped_size);
+
+		crc = btrfs_csum_data(root, p, crc, l);
+		kunmap_atomic(mapped_buffer);
+		len -= l;
+		if (len == 0)
+			break;
+		index++;
+		BUG_ON(index >= sblock->page_count);
+		BUG_ON(!sblock->pagev[index].page);
+		page = sblock->pagev[index].page;
+		mapped_buffer = kmap_atomic(page);
+		mapped_size = PAGE_SIZE;
+		p = mapped_buffer;
+	}
+
+	btrfs_csum_final(crc, calculated_csum);
+	if (memcmp(calculated_csum, on_disk_csum, sdev->csum_size))
 		++crc_fail;
 
-	spin_lock(&sdev->stat_lock);
-	++sdev->stat.tree_extents_scrubbed;
-	sdev->stat.tree_bytes_scrubbed += PAGE_SIZE;
-	if (crc_fail)
-		++sdev->stat.csum_errors;
-	if (fail)
-		++sdev->stat.verify_errors;
-	spin_unlock(&sdev->stat_lock);
+	if (crc_fail || fail) {
+		spin_lock(&sdev->stat_lock);
+		if (crc_fail)
+			++sdev->stat.csum_errors;
+		if (fail)
+			++sdev->stat.verify_errors;
+		spin_unlock(&sdev->stat_lock);
+	}
 
 	return fail || crc_fail;
 }
 
-static int scrub_checksum_super(struct scrub_bio *sbio, void *buffer)
+static int scrub_checksum_super(struct scrub_block *sblock)
 {
 	struct btrfs_super_block *s;
-	u64 logical;
-	struct scrub_dev *sdev = sbio->sdev;
+	struct scrub_dev *sdev = sblock->sdev;
 	struct btrfs_root *root = sdev->dev->dev_root;
 	struct btrfs_fs_info *fs_info = root->fs_info;
-	u8 csum[BTRFS_CSUM_SIZE];
+	u8 calculated_csum[BTRFS_CSUM_SIZE];
+	u8 on_disk_csum[BTRFS_CSUM_SIZE];
+	struct page *page;
+	void *mapped_buffer;
+	u64 mapped_size;
+	void *p;
 	u32 crc = ~(u32)0;
 	int fail = 0;
+	u64 len;
+	int index;
 
-	s = (struct btrfs_super_block *)buffer;
-	logical = sbio->logical;
+	BUG_ON(sblock->page_count < 1);
+	page = sblock->pagev[0].page;
+	mapped_buffer = kmap_atomic(page);
+	s = (struct btrfs_super_block *)mapped_buffer;
+	memcpy(on_disk_csum, s->csum, sdev->csum_size);
 
-	if (logical != le64_to_cpu(s->bytenr))
+	if (sblock->pagev[0].logical != le64_to_cpu(s->bytenr))
 		++fail;
 
-	if (sbio->spag[0].generation != le64_to_cpu(s->generation))
+	if (sblock->pagev[0].generation != le64_to_cpu(s->generation))
 		++fail;
 
 	if (memcmp(s->fsid, fs_info->fsid, BTRFS_UUID_SIZE))
 		++fail;
 
-	crc = btrfs_csum_data(root, buffer + BTRFS_CSUM_SIZE, crc,
-			      PAGE_SIZE - BTRFS_CSUM_SIZE);
-	btrfs_csum_final(crc, csum);
-	if (memcmp(csum, s->csum, sbio->sdev->csum_size))
+	len = BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE;
+	mapped_size = PAGE_SIZE - BTRFS_CSUM_SIZE;
+	p = ((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE;
+	index = 0;
+	for (;;) {
+		u64 l = min_t(u64, len, mapped_size);
+
+		crc = btrfs_csum_data(root, p, crc, l);
+		kunmap_atomic(mapped_buffer);
+		len -= l;
+		if (len == 0)
+			break;
+		index++;
+		BUG_ON(index >= sblock->page_count);
+		BUG_ON(!sblock->pagev[index].page);
+		page = sblock->pagev[index].page;
+		mapped_buffer = kmap_atomic(page);
+		mapped_size = PAGE_SIZE;
+		p = mapped_buffer;
+	}
+
+	btrfs_csum_final(crc, calculated_csum);
+	if (memcmp(calculated_csum, on_disk_csum, sdev->csum_size))
 		++fail;
 
 	if (fail) {
@@ -948,29 +1414,42 @@
 	return fail;
 }
 
-static int scrub_submit(struct scrub_dev *sdev)
+static void scrub_block_get(struct scrub_block *sblock)
+{
+	atomic_inc(&sblock->ref_count);
+}
+
+static void scrub_block_put(struct scrub_block *sblock)
+{
+	if (atomic_dec_and_test(&sblock->ref_count)) {
+		int i;
+
+		for (i = 0; i < sblock->page_count; i++)
+			if (sblock->pagev[i].page)
+				__free_page(sblock->pagev[i].page);
+		kfree(sblock);
+	}
+}
+
+static void scrub_submit(struct scrub_dev *sdev)
 {
 	struct scrub_bio *sbio;
 
 	if (sdev->curr == -1)
-		return 0;
+		return;
 
 	sbio = sdev->bios[sdev->curr];
-	sbio->err = 0;
 	sdev->curr = -1;
 	atomic_inc(&sdev->in_flight);
 
 	btrfsic_submit_bio(READ, sbio->bio);
-
-	return 0;
 }
 
-static int scrub_page(struct scrub_dev *sdev, u64 logical, u64 len,
-		      u64 physical, u64 flags, u64 gen, int mirror_num,
-		      u8 *csum, int force)
+static int scrub_add_page_to_bio(struct scrub_dev *sdev,
+				 struct scrub_page *spage)
 {
+	struct scrub_block *sblock = spage->sblock;
 	struct scrub_bio *sbio;
-	struct page *page;
 	int ret;
 
 again:
@@ -983,7 +1462,7 @@
 		if (sdev->curr != -1) {
 			sdev->first_free = sdev->bios[sdev->curr]->next_free;
 			sdev->bios[sdev->curr]->next_free = -1;
-			sdev->bios[sdev->curr]->count = 0;
+			sdev->bios[sdev->curr]->page_count = 0;
 			spin_unlock(&sdev->list_lock);
 		} else {
 			spin_unlock(&sdev->list_lock);
@@ -991,62 +1470,200 @@
 		}
 	}
 	sbio = sdev->bios[sdev->curr];
-	if (sbio->count == 0) {
+	if (sbio->page_count == 0) {
 		struct bio *bio;
 
-		sbio->physical = physical;
-		sbio->logical = logical;
-		bio = bio_alloc(GFP_NOFS, SCRUB_PAGES_PER_BIO);
-		if (!bio)
-			return -ENOMEM;
+		sbio->physical = spage->physical;
+		sbio->logical = spage->logical;
+		bio = sbio->bio;
+		if (!bio) {
+			bio = bio_alloc(GFP_NOFS, sdev->pages_per_bio);
+			if (!bio)
+				return -ENOMEM;
+			sbio->bio = bio;
+		}
 
 		bio->bi_private = sbio;
 		bio->bi_end_io = scrub_bio_end_io;
 		bio->bi_bdev = sdev->dev->bdev;
-		bio->bi_sector = sbio->physical >> 9;
+		bio->bi_sector = spage->physical >> 9;
 		sbio->err = 0;
-		sbio->bio = bio;
-	} else if (sbio->physical + sbio->count * PAGE_SIZE != physical ||
-		   sbio->logical + sbio->count * PAGE_SIZE != logical) {
-		ret = scrub_submit(sdev);
-		if (ret)
-			return ret;
-		goto again;
-	}
-	sbio->spag[sbio->count].flags = flags;
-	sbio->spag[sbio->count].generation = gen;
-	sbio->spag[sbio->count].have_csum = 0;
-	sbio->spag[sbio->count].mirror_num = mirror_num;
-
-	page = alloc_page(GFP_NOFS);
-	if (!page)
-		return -ENOMEM;
-
-	ret = bio_add_page(sbio->bio, page, PAGE_SIZE, 0);
-	if (!ret) {
-		__free_page(page);
-		ret = scrub_submit(sdev);
-		if (ret)
-			return ret;
+	} else if (sbio->physical + sbio->page_count * PAGE_SIZE !=
+		   spage->physical ||
+		   sbio->logical + sbio->page_count * PAGE_SIZE !=
+		   spage->logical) {
+		scrub_submit(sdev);
 		goto again;
 	}
 
-	if (csum) {
-		sbio->spag[sbio->count].have_csum = 1;
-		memcpy(sbio->spag[sbio->count].csum, csum, sdev->csum_size);
+	sbio->pagev[sbio->page_count] = spage;
+	ret = bio_add_page(sbio->bio, spage->page, PAGE_SIZE, 0);
+	if (ret != PAGE_SIZE) {
+		if (sbio->page_count < 1) {
+			bio_put(sbio->bio);
+			sbio->bio = NULL;
+			return -EIO;
+		}
+		scrub_submit(sdev);
+		goto again;
 	}
-	++sbio->count;
-	if (sbio->count == SCRUB_PAGES_PER_BIO || force) {
-		int ret;
 
-		ret = scrub_submit(sdev);
-		if (ret)
-			return ret;
-	}
+	scrub_block_get(sblock); /* one for the added page */
+	atomic_inc(&sblock->outstanding_pages);
+	sbio->page_count++;
+	if (sbio->page_count == sdev->pages_per_bio)
+		scrub_submit(sdev);
 
 	return 0;
 }
 
+static int scrub_pages(struct scrub_dev *sdev, u64 logical, u64 len,
+		       u64 physical, u64 flags, u64 gen, int mirror_num,
+		       u8 *csum, int force)
+{
+	struct scrub_block *sblock;
+	int index;
+
+	sblock = kzalloc(sizeof(*sblock), GFP_NOFS);
+	if (!sblock) {
+		spin_lock(&sdev->stat_lock);
+		sdev->stat.malloc_errors++;
+		spin_unlock(&sdev->stat_lock);
+		return -ENOMEM;
+	}
+
+	/* one ref inside this function, plus one for each page later on */
+	atomic_set(&sblock->ref_count, 1);
+	sblock->sdev = sdev;
+	sblock->no_io_error_seen = 1;
+
+	for (index = 0; len > 0; index++) {
+		struct scrub_page *spage = sblock->pagev + index;
+		u64 l = min_t(u64, len, PAGE_SIZE);
+
+		BUG_ON(index >= SCRUB_MAX_PAGES_PER_BLOCK);
+		spage->page = alloc_page(GFP_NOFS);
+		if (!spage->page) {
+			spin_lock(&sdev->stat_lock);
+			sdev->stat.malloc_errors++;
+			spin_unlock(&sdev->stat_lock);
+			while (index > 0) {
+				index--;
+				__free_page(sblock->pagev[index].page);
+			}
+			kfree(sblock);
+			return -ENOMEM;
+		}
+		spage->sblock = sblock;
+		spage->bdev = sdev->dev->bdev;
+		spage->flags = flags;
+		spage->generation = gen;
+		spage->logical = logical;
+		spage->physical = physical;
+		spage->mirror_num = mirror_num;
+		if (csum) {
+			spage->have_csum = 1;
+			memcpy(spage->csum, csum, sdev->csum_size);
+		} else {
+			spage->have_csum = 0;
+		}
+		sblock->page_count++;
+		len -= l;
+		logical += l;
+		physical += l;
+	}
+
+	BUG_ON(sblock->page_count == 0);
+	for (index = 0; index < sblock->page_count; index++) {
+		struct scrub_page *spage = sblock->pagev + index;
+		int ret;
+
+		ret = scrub_add_page_to_bio(sdev, spage);
+		if (ret) {
+			scrub_block_put(sblock);
+			return ret;
+		}
+	}
+
+	if (force)
+		scrub_submit(sdev);
+
+	/* last one frees, either here or in bio completion for last page */
+	scrub_block_put(sblock);
+	return 0;
+}
+
+static void scrub_bio_end_io(struct bio *bio, int err)
+{
+	struct scrub_bio *sbio = bio->bi_private;
+	struct scrub_dev *sdev = sbio->sdev;
+	struct btrfs_fs_info *fs_info = sdev->dev->dev_root->fs_info;
+
+	sbio->err = err;
+	sbio->bio = bio;
+
+	btrfs_queue_worker(&fs_info->scrub_workers, &sbio->work);
+}
+
+static void scrub_bio_end_io_worker(struct btrfs_work *work)
+{
+	struct scrub_bio *sbio = container_of(work, struct scrub_bio, work);
+	struct scrub_dev *sdev = sbio->sdev;
+	int i;
+
+	BUG_ON(sbio->page_count > SCRUB_PAGES_PER_BIO);
+	if (sbio->err) {
+		for (i = 0; i < sbio->page_count; i++) {
+			struct scrub_page *spage = sbio->pagev[i];
+
+			spage->io_error = 1;
+			spage->sblock->no_io_error_seen = 0;
+		}
+	}
+
+	/* now complete the scrub_block items that have all pages completed */
+	for (i = 0; i < sbio->page_count; i++) {
+		struct scrub_page *spage = sbio->pagev[i];
+		struct scrub_block *sblock = spage->sblock;
+
+		if (atomic_dec_and_test(&sblock->outstanding_pages))
+			scrub_block_complete(sblock);
+		scrub_block_put(sblock);
+	}
+
+	if (sbio->err) {
+		/* what is this good for??? */
+		sbio->bio->bi_flags &= ~(BIO_POOL_MASK - 1);
+		sbio->bio->bi_flags |= 1 << BIO_UPTODATE;
+		sbio->bio->bi_phys_segments = 0;
+		sbio->bio->bi_idx = 0;
+
+		for (i = 0; i < sbio->page_count; i++) {
+			struct bio_vec *bi;
+			bi = &sbio->bio->bi_io_vec[i];
+			bi->bv_offset = 0;
+			bi->bv_len = PAGE_SIZE;
+		}
+	}
+
+	bio_put(sbio->bio);
+	sbio->bio = NULL;
+	spin_lock(&sdev->list_lock);
+	sbio->next_free = sdev->first_free;
+	sdev->first_free = sbio->index;
+	spin_unlock(&sdev->list_lock);
+	atomic_dec(&sdev->in_flight);
+	wake_up(&sdev->list_wait);
+}
+
+static void scrub_block_complete(struct scrub_block *sblock)
+{
+	if (!sblock->no_io_error_seen)
+		scrub_handle_errored_block(sblock);
+	else
+		scrub_checksum(sblock);
+}
+
 static int scrub_find_csum(struct scrub_dev *sdev, u64 logical, u64 len,
 			   u8 *csum)
 {
@@ -1054,7 +1671,6 @@
 	int ret = 0;
 	unsigned long i;
 	unsigned long num_sectors;
-	u32 sectorsize = sdev->dev->dev_root->sectorsize;
 
 	while (!list_empty(&sdev->csum_list)) {
 		sum = list_first_entry(&sdev->csum_list,
@@ -1072,7 +1688,7 @@
 	if (!sum)
 		return 0;
 
-	num_sectors = sum->len / sectorsize;
+	num_sectors = sum->len / sdev->sectorsize;
 	for (i = 0; i < num_sectors; ++i) {
 		if (sum->sums[i].bytenr == logical) {
 			memcpy(csum, &sum->sums[i].sum, sdev->csum_size);
@@ -1093,9 +1709,28 @@
 {
 	int ret;
 	u8 csum[BTRFS_CSUM_SIZE];
+	u32 blocksize;
+
+	if (flags & BTRFS_EXTENT_FLAG_DATA) {
+		blocksize = sdev->sectorsize;
+		spin_lock(&sdev->stat_lock);
+		sdev->stat.data_extents_scrubbed++;
+		sdev->stat.data_bytes_scrubbed += len;
+		spin_unlock(&sdev->stat_lock);
+	} else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
+		BUG_ON(sdev->nodesize != sdev->leafsize);
+		blocksize = sdev->nodesize;
+		spin_lock(&sdev->stat_lock);
+		sdev->stat.tree_extents_scrubbed++;
+		sdev->stat.tree_bytes_scrubbed += len;
+		spin_unlock(&sdev->stat_lock);
+	} else {
+		blocksize = sdev->sectorsize;
+		BUG_ON(1);
+	}
 
 	while (len) {
-		u64 l = min_t(u64, len, PAGE_SIZE);
+		u64 l = min_t(u64, len, blocksize);
 		int have_csum = 0;
 
 		if (flags & BTRFS_EXTENT_FLAG_DATA) {
@@ -1104,8 +1739,8 @@
 			if (have_csum == 0)
 				++sdev->stat.no_csum;
 		}
-		ret = scrub_page(sdev, logical, l, physical, flags, gen,
-				 mirror_num, have_csum ? csum : NULL, 0);
+		ret = scrub_pages(sdev, logical, l, physical, flags, gen,
+				  mirror_num, have_csum ? csum : NULL, 0);
 		if (ret)
 			return ret;
 		len -= l;
@@ -1170,6 +1805,11 @@
 	if (!path)
 		return -ENOMEM;
 
+	/*
+	 * work on commit root. The related disk blocks are static as
+	 * long as COW is applied. This means, it is save to rewrite
+	 * them to repair disk errors without any race conditions
+	 */
 	path->search_commit_root = 1;
 	path->skip_locking = 1;
 
@@ -1516,15 +2156,18 @@
 	struct btrfs_device *device = sdev->dev;
 	struct btrfs_root *root = device->dev_root;
 
+	if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
+		return -EIO;
+
 	gen = root->fs_info->last_trans_committed;
 
 	for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
 		bytenr = btrfs_sb_offset(i);
-		if (bytenr + BTRFS_SUPER_INFO_SIZE >= device->total_bytes)
+		if (bytenr + BTRFS_SUPER_INFO_SIZE > device->total_bytes)
 			break;
 
-		ret = scrub_page(sdev, bytenr, PAGE_SIZE, bytenr,
-				 BTRFS_EXTENT_FLAG_SUPER, gen, i, NULL, 1);
+		ret = scrub_pages(sdev, bytenr, BTRFS_SUPER_INFO_SIZE, bytenr,
+				     BTRFS_EXTENT_FLAG_SUPER, gen, i, NULL, 1);
 		if (ret)
 			return ret;
 	}
@@ -1583,10 +2226,30 @@
 	/*
 	 * check some assumptions
 	 */
-	if (root->sectorsize != PAGE_SIZE ||
-	    root->sectorsize != root->leafsize ||
-	    root->sectorsize != root->nodesize) {
-		printk(KERN_ERR "btrfs_scrub: size assumptions fail\n");
+	if (root->nodesize != root->leafsize) {
+		printk(KERN_ERR
+		       "btrfs_scrub: size assumption nodesize == leafsize (%d == %d) fails\n",
+		       root->nodesize, root->leafsize);
+		return -EINVAL;
+	}
+
+	if (root->nodesize > BTRFS_STRIPE_LEN) {
+		/*
+		 * in this case scrub is unable to calculate the checksum
+		 * the way scrub is implemented. Do not handle this
+		 * situation at all because it won't ever happen.
+		 */
+		printk(KERN_ERR
+		       "btrfs_scrub: size assumption nodesize <= BTRFS_STRIPE_LEN (%d <= %d) fails\n",
+		       root->nodesize, BTRFS_STRIPE_LEN);
+		return -EINVAL;
+	}
+
+	if (root->sectorsize != PAGE_SIZE) {
+		/* not supported for data w/o checksums */
+		printk(KERN_ERR
+		       "btrfs_scrub: size assumption sectorsize != PAGE_SIZE (%d != %lld) fails\n",
+		       root->sectorsize, (unsigned long long)PAGE_SIZE);
 		return -EINVAL;
 	}
 
@@ -1656,7 +2319,7 @@
 	return ret;
 }
 
-int btrfs_scrub_pause(struct btrfs_root *root)
+void btrfs_scrub_pause(struct btrfs_root *root)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
 
@@ -1671,34 +2334,28 @@
 		mutex_lock(&fs_info->scrub_lock);
 	}
 	mutex_unlock(&fs_info->scrub_lock);
-
-	return 0;
 }
 
-int btrfs_scrub_continue(struct btrfs_root *root)
+void btrfs_scrub_continue(struct btrfs_root *root)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
 
 	atomic_dec(&fs_info->scrub_pause_req);
 	wake_up(&fs_info->scrub_pause_wait);
-	return 0;
 }
 
-int btrfs_scrub_pause_super(struct btrfs_root *root)
+void btrfs_scrub_pause_super(struct btrfs_root *root)
 {
 	down_write(&root->fs_info->scrub_super_lock);
-	return 0;
 }
 
-int btrfs_scrub_continue_super(struct btrfs_root *root)
+void btrfs_scrub_continue_super(struct btrfs_root *root)
 {
 	up_write(&root->fs_info->scrub_super_lock);
-	return 0;
 }
 
-int btrfs_scrub_cancel(struct btrfs_root *root)
+int __btrfs_scrub_cancel(struct btrfs_fs_info *fs_info)
 {
-	struct btrfs_fs_info *fs_info = root->fs_info;
 
 	mutex_lock(&fs_info->scrub_lock);
 	if (!atomic_read(&fs_info->scrubs_running)) {
@@ -1719,6 +2376,11 @@
 	return 0;
 }
 
+int btrfs_scrub_cancel(struct btrfs_root *root)
+{
+	return __btrfs_scrub_cancel(root->fs_info);
+}
+
 int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
@@ -1741,6 +2403,7 @@
 
 	return 0;
 }
+
 int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
diff --git a/fs/btrfs/struct-funcs.c b/fs/btrfs/struct-funcs.c
index bc1f6ad..c6ffa58 100644
--- a/fs/btrfs/struct-funcs.c
+++ b/fs/btrfs/struct-funcs.c
@@ -44,8 +44,9 @@
 #define BTRFS_SETGET_FUNCS(name, type, member, bits)			\
 u##bits btrfs_##name(struct extent_buffer *eb, type *s);		\
 void btrfs_set_##name(struct extent_buffer *eb, type *s, u##bits val);	\
-u##bits btrfs_##name(struct extent_buffer *eb,				\
-				   type *s)				\
+void btrfs_set_token_##name(struct extent_buffer *eb, type *s, u##bits val, struct btrfs_map_token *token);	\
+u##bits btrfs_token_##name(struct extent_buffer *eb,				\
+			   type *s, struct btrfs_map_token *token)	\
 {									\
 	unsigned long part_offset = (unsigned long)s;			\
 	unsigned long offset = part_offset + offsetof(type, member);	\
@@ -54,9 +55,18 @@
 	char *kaddr;						\
 	unsigned long map_start;				\
 	unsigned long map_len;					\
+	unsigned long mem_len = sizeof(((type *)0)->member);	\
 	u##bits res;						\
+	if (token && token->kaddr && token->offset <= offset &&	\
+	    token->eb == eb &&					\
+	   (token->offset + PAGE_CACHE_SIZE >= offset + mem_len)) { \
+		kaddr = token->kaddr;				\
+		p = (type *)(kaddr + part_offset - token->offset);  \
+		res = le##bits##_to_cpu(p->member);		\
+		return res;					\
+	}							\
 	err = map_private_extent_buffer(eb, offset,		\
-			sizeof(((type *)0)->member),		\
+			mem_len,				\
 			&kaddr, &map_start, &map_len);		\
 	if (err) {						\
 		__le##bits leres;				\
@@ -65,10 +75,15 @@
 	}							\
 	p = (type *)(kaddr + part_offset - map_start);		\
 	res = le##bits##_to_cpu(p->member);			\
+	if (token) {						\
+		token->kaddr = kaddr;				\
+		token->offset = map_start;			\
+		token->eb = eb;					\
+	}							\
 	return res;						\
 }									\
-void btrfs_set_##name(struct extent_buffer *eb,				\
-				    type *s, u##bits val)		\
+void btrfs_set_token_##name(struct extent_buffer *eb,				\
+			    type *s, u##bits val, struct btrfs_map_token *token)		\
 {									\
 	unsigned long part_offset = (unsigned long)s;			\
 	unsigned long offset = part_offset + offsetof(type, member);	\
@@ -77,8 +92,17 @@
 	char *kaddr;						\
 	unsigned long map_start;				\
 	unsigned long map_len;					\
+	unsigned long mem_len = sizeof(((type *)0)->member);	\
+	if (token && token->kaddr && token->offset <= offset &&	\
+	    token->eb == eb &&					\
+	   (token->offset + PAGE_CACHE_SIZE >= offset + mem_len)) { \
+		kaddr = token->kaddr;				\
+		p = (type *)(kaddr + part_offset - token->offset);  \
+		p->member = cpu_to_le##bits(val);		\
+		return;						\
+	}							\
 	err = map_private_extent_buffer(eb, offset,		\
-			sizeof(((type *)0)->member),		\
+			mem_len,				\
 			&kaddr, &map_start, &map_len);		\
 	if (err) {						\
 		__le##bits val2;				\
@@ -88,7 +112,22 @@
 	}							\
 	p = (type *)(kaddr + part_offset - map_start);		\
 	p->member = cpu_to_le##bits(val);			\
-}
+	if (token) {						\
+		token->kaddr = kaddr;				\
+		token->offset = map_start;			\
+		token->eb = eb;					\
+	}							\
+}								\
+void btrfs_set_##name(struct extent_buffer *eb,			\
+		      type *s, u##bits val)			\
+{								\
+	btrfs_set_token_##name(eb, s, val, NULL);		\
+}								\
+u##bits btrfs_##name(struct extent_buffer *eb,			\
+		      type *s)					\
+{								\
+	return btrfs_token_##name(eb, s, NULL);			\
+}								\
 
 #include "ctree.h"
 
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 3ce97b2..8d5d380 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -76,6 +76,9 @@
 	case -EROFS:
 		errstr = "Readonly filesystem";
 		break;
+	case -EEXIST:
+		errstr = "Object already exists";
+		break;
 	default:
 		if (nbuf) {
 			if (snprintf(nbuf, 16, "error %d", -errno) >= 0)
@@ -116,6 +119,8 @@
 	if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
 		sb->s_flags |= MS_RDONLY;
 		printk(KERN_INFO "btrfs is forced readonly\n");
+		__btrfs_scrub_cancel(fs_info);
+//		WARN_ON(1);
 	}
 }
 
@@ -124,25 +129,132 @@
  * invokes the approciate error response.
  */
 void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
-		     unsigned int line, int errno)
+		       unsigned int line, int errno, const char *fmt, ...)
 {
 	struct super_block *sb = fs_info->sb;
 	char nbuf[16];
 	const char *errstr;
+	va_list args;
+	va_start(args, fmt);
 
 	/*
 	 * Special case: if the error is EROFS, and we're already
 	 * under MS_RDONLY, then it is safe here.
 	 */
 	if (errno == -EROFS && (sb->s_flags & MS_RDONLY))
+  		return;
+
+  	errstr = btrfs_decode_error(fs_info, errno, nbuf);
+	if (fmt) {
+		struct va_format vaf = {
+			.fmt = fmt,
+			.va = &args,
+		};
+
+		printk(KERN_CRIT "BTRFS error (device %s) in %s:%d: %s (%pV)\n",
+			sb->s_id, function, line, errstr, &vaf);
+	} else {
+		printk(KERN_CRIT "BTRFS error (device %s) in %s:%d: %s\n",
+			sb->s_id, function, line, errstr);
+	}
+
+	/* Don't go through full error handling during mount */
+	if (sb->s_flags & MS_BORN) {
+		save_error_info(fs_info);
+		btrfs_handle_error(fs_info);
+	}
+	va_end(args);
+}
+
+const char *logtypes[] = {
+	"emergency",
+	"alert",
+	"critical",
+	"error",
+	"warning",
+	"notice",
+	"info",
+	"debug",
+};
+
+void btrfs_printk(struct btrfs_fs_info *fs_info, const char *fmt, ...)
+{
+	struct super_block *sb = fs_info->sb;
+	char lvl[4];
+	struct va_format vaf;
+	va_list args;
+	const char *type = logtypes[4];
+
+	va_start(args, fmt);
+
+	if (fmt[0] == '<' && isdigit(fmt[1]) && fmt[2] == '>') {
+		strncpy(lvl, fmt, 3);
+		fmt += 3;
+		type = logtypes[fmt[1] - '0'];
+	} else
+		*lvl = '\0';
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+	printk("%sBTRFS %s (device %s): %pV", lvl, type, sb->s_id, &vaf);
+}
+
+/*
+ * We only mark the transaction aborted and then set the file system read-only.
+ * This will prevent new transactions from starting or trying to join this
+ * one.
+ *
+ * This means that error recovery at the call site is limited to freeing
+ * any local memory allocations and passing the error code up without
+ * further cleanup. The transaction should complete as it normally would
+ * in the call path but will return -EIO.
+ *
+ * We'll complete the cleanup in btrfs_end_transaction and
+ * btrfs_commit_transaction.
+ */
+void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
+			       struct btrfs_root *root, const char *function,
+			       unsigned int line, int errno)
+{
+	WARN_ONCE(1, KERN_DEBUG "btrfs: Transaction aborted");
+	trans->aborted = errno;
+	/* Nothing used. The other threads that have joined this
+	 * transaction may be able to continue. */
+	if (!trans->blocks_used) {
+		btrfs_printk(root->fs_info, "Aborting unused transaction.\n");
 		return;
+	}
+	trans->transaction->aborted = errno;
+	__btrfs_std_error(root->fs_info, function, line, errno, NULL);
+}
+/*
+ * __btrfs_panic decodes unexpected, fatal errors from the caller,
+ * issues an alert, and either panics or BUGs, depending on mount options.
+ */
+void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function,
+		   unsigned int line, int errno, const char *fmt, ...)
+{
+	char nbuf[16];
+	char *s_id = "<unknown>";
+	const char *errstr;
+	struct va_format vaf = { .fmt = fmt };
+	va_list args;
+
+	if (fs_info)
+		s_id = fs_info->sb->s_id;
+
+	va_start(args, fmt);
+	vaf.va = &args;
 
 	errstr = btrfs_decode_error(fs_info, errno, nbuf);
-	printk(KERN_CRIT "BTRFS error (device %s) in %s:%d: %s\n",
-		sb->s_id, function, line, errstr);
-	save_error_info(fs_info);
+	if (fs_info->mount_opt & BTRFS_MOUNT_PANIC_ON_FATAL_ERROR)
+		panic(KERN_CRIT "BTRFS panic (device %s) in %s:%d: %pV (%s)\n",
+			s_id, function, line, &vaf, errstr);
 
-	btrfs_handle_error(fs_info);
+	printk(KERN_CRIT "BTRFS panic (device %s) in %s:%d: %pV (%s)\n",
+	       s_id, function, line, &vaf, errstr);
+	va_end(args);
+	/* Caller calls BUG() */
 }
 
 static void btrfs_put_super(struct super_block *sb)
@@ -166,7 +278,7 @@
 	Opt_enospc_debug, Opt_subvolrootid, Opt_defrag, Opt_inode_cache,
 	Opt_no_space_cache, Opt_recovery, Opt_skip_balance,
 	Opt_check_integrity, Opt_check_integrity_including_extent_data,
-	Opt_check_integrity_print_mask,
+	Opt_check_integrity_print_mask, Opt_fatal_errors,
 	Opt_err,
 };
 
@@ -206,12 +318,14 @@
 	{Opt_check_integrity, "check_int"},
 	{Opt_check_integrity_including_extent_data, "check_int_data"},
 	{Opt_check_integrity_print_mask, "check_int_print_mask=%d"},
+	{Opt_fatal_errors, "fatal_errors=%s"},
 	{Opt_err, NULL},
 };
 
 /*
  * Regular mount options parser.  Everything that is needed only when
  * reading in a new superblock is parsed here.
+ * XXX JDM: This needs to be cleaned up for remount.
  */
 int btrfs_parse_options(struct btrfs_root *root, char *options)
 {
@@ -438,6 +552,18 @@
 			ret = -EINVAL;
 			goto out;
 #endif
+		case Opt_fatal_errors:
+			if (strcmp(args[0].from, "panic") == 0)
+				btrfs_set_opt(info->mount_opt,
+					      PANIC_ON_FATAL_ERROR);
+			else if (strcmp(args[0].from, "bug") == 0)
+				btrfs_clear_opt(info->mount_opt,
+					      PANIC_ON_FATAL_ERROR);
+			else {
+				ret = -EINVAL;
+				goto out;
+			}
+			break;
 		case Opt_err:
 			printk(KERN_INFO "btrfs: unrecognized mount option "
 			       "'%s'\n", p);
@@ -629,7 +755,6 @@
 			    void *data, int silent)
 {
 	struct inode *inode;
-	struct dentry *root_dentry;
 	struct btrfs_fs_info *fs_info = btrfs_sb(sb);
 	struct btrfs_key key;
 	int err;
@@ -660,15 +785,12 @@
 		goto fail_close;
 	}
 
-	root_dentry = d_alloc_root(inode);
-	if (!root_dentry) {
-		iput(inode);
+	sb->s_root = d_make_root(inode);
+	if (!sb->s_root) {
 		err = -ENOMEM;
 		goto fail_close;
 	}
 
-	sb->s_root = root_dentry;
-
 	save_mount_options(sb, data);
 	cleancache_init_fs(sb);
 	sb->s_flags |= MS_ACTIVE;
@@ -766,6 +888,8 @@
 		seq_puts(seq, ",inode_cache");
 	if (btrfs_test_opt(root, SKIP_BALANCE))
 		seq_puts(seq, ",skip_balance");
+	if (btrfs_test_opt(root, PANIC_ON_FATAL_ERROR))
+		seq_puts(seq, ",fatal_errors=panic");
 	return 0;
 }
 
@@ -999,11 +1123,20 @@
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(sb);
 	struct btrfs_root *root = fs_info->tree_root;
+	unsigned old_flags = sb->s_flags;
+	unsigned long old_opts = fs_info->mount_opt;
+	unsigned long old_compress_type = fs_info->compress_type;
+	u64 old_max_inline = fs_info->max_inline;
+	u64 old_alloc_start = fs_info->alloc_start;
+	int old_thread_pool_size = fs_info->thread_pool_size;
+	unsigned int old_metadata_ratio = fs_info->metadata_ratio;
 	int ret;
 
 	ret = btrfs_parse_options(root, data);
-	if (ret)
-		return -EINVAL;
+	if (ret) {
+		ret = -EINVAL;
+		goto restore;
+	}
 
 	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
 		return 0;
@@ -1011,26 +1144,44 @@
 	if (*flags & MS_RDONLY) {
 		sb->s_flags |= MS_RDONLY;
 
-		ret =  btrfs_commit_super(root);
-		WARN_ON(ret);
+		ret = btrfs_commit_super(root);
+		if (ret)
+			goto restore;
 	} else {
 		if (fs_info->fs_devices->rw_devices == 0)
-			return -EACCES;
+			ret = -EACCES;
+			goto restore;
 
 		if (btrfs_super_log_root(fs_info->super_copy) != 0)
-			return -EINVAL;
+			ret = -EINVAL;
+			goto restore;
 
 		ret = btrfs_cleanup_fs_roots(fs_info);
-		WARN_ON(ret);
+		if (ret)
+			goto restore;
 
 		/* recover relocation */
 		ret = btrfs_recover_relocation(root);
-		WARN_ON(ret);
+		if (ret)
+			goto restore;
 
 		sb->s_flags &= ~MS_RDONLY;
 	}
 
 	return 0;
+
+restore:
+	/* We've hit an error - don't reset MS_RDONLY */
+	if (sb->s_flags & MS_RDONLY)
+		old_flags |= MS_RDONLY;
+	sb->s_flags = old_flags;
+	fs_info->mount_opt = old_opts;
+	fs_info->compress_type = old_compress_type;
+	fs_info->max_inline = old_max_inline;
+	fs_info->alloc_start = old_alloc_start;
+	fs_info->thread_pool_size = old_thread_pool_size;
+	fs_info->metadata_ratio = old_metadata_ratio;
+	return ret;
 }
 
 /* Used to sort the devices by max_avail(descending sort) */
@@ -1360,9 +1511,7 @@
 	if (err)
 		return err;
 
-	err = btrfs_init_compress();
-	if (err)
-		goto free_sysfs;
+	btrfs_init_compress();
 
 	err = btrfs_init_cachep();
 	if (err)
@@ -1388,6 +1537,8 @@
 	if (err)
 		goto unregister_ioctl;
 
+	btrfs_init_lockdep();
+
 	printk(KERN_INFO "%s loaded\n", BTRFS_BUILD_VERSION);
 	return 0;
 
@@ -1403,7 +1554,6 @@
 	btrfs_destroy_cachep();
 free_compress:
 	btrfs_exit_compress();
-free_sysfs:
 	btrfs_exit_sysfs();
 	return err;
 }
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 04b77e3..8da29e8 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -31,7 +31,7 @@
 
 #define BTRFS_ROOT_TRANS_TAG 0
 
-static noinline void put_transaction(struct btrfs_transaction *transaction)
+void put_transaction(struct btrfs_transaction *transaction)
 {
 	WARN_ON(atomic_read(&transaction->use_count) == 0);
 	if (atomic_dec_and_test(&transaction->use_count)) {
@@ -58,6 +58,12 @@
 
 	spin_lock(&root->fs_info->trans_lock);
 loop:
+	/* The file system has been taken offline. No new transactions. */
+	if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
+		spin_unlock(&root->fs_info->trans_lock);
+		return -EROFS;
+	}
+
 	if (root->fs_info->trans_no_join) {
 		if (!nofail) {
 			spin_unlock(&root->fs_info->trans_lock);
@@ -67,6 +73,8 @@
 
 	cur_trans = root->fs_info->running_transaction;
 	if (cur_trans) {
+		if (cur_trans->aborted)
+			return cur_trans->aborted;
 		atomic_inc(&cur_trans->use_count);
 		atomic_inc(&cur_trans->num_writers);
 		cur_trans->num_joined++;
@@ -123,6 +131,7 @@
 	root->fs_info->generation++;
 	cur_trans->transid = root->fs_info->generation;
 	root->fs_info->running_transaction = cur_trans;
+	cur_trans->aborted = 0;
 	spin_unlock(&root->fs_info->trans_lock);
 
 	return 0;
@@ -318,6 +327,7 @@
 	h->use_count = 1;
 	h->block_rsv = NULL;
 	h->orig_rsv = NULL;
+	h->aborted = 0;
 
 	smp_mb();
 	if (cur_trans->blocked && may_wait_transaction(root, type)) {
@@ -327,8 +337,7 @@
 
 	if (num_bytes) {
 		trace_btrfs_space_reservation(root->fs_info, "transaction",
-					      (u64)(unsigned long)h,
-					      num_bytes, 1);
+					      h->transid, num_bytes, 1);
 		h->block_rsv = &root->fs_info->trans_block_rsv;
 		h->bytes_reserved = num_bytes;
 	}
@@ -440,6 +449,7 @@
 	struct btrfs_transaction *cur_trans = trans->transaction;
 	struct btrfs_block_rsv *rsv = trans->block_rsv;
 	int updates;
+	int err;
 
 	smp_mb();
 	if (cur_trans->blocked || cur_trans->delayed_refs.flushing)
@@ -453,8 +463,11 @@
 
 	updates = trans->delayed_ref_updates;
 	trans->delayed_ref_updates = 0;
-	if (updates)
-		btrfs_run_delayed_refs(trans, root, updates);
+	if (updates) {
+		err = btrfs_run_delayed_refs(trans, root, updates);
+		if (err) /* Error code will also eval true */
+			return err;
+	}
 
 	trans->block_rsv = rsv;
 
@@ -525,6 +538,11 @@
 	if (throttle)
 		btrfs_run_delayed_iputs(root);
 
+	if (trans->aborted ||
+	    root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
+		return -EIO;
+	}
+
 	return 0;
 }
 
@@ -690,11 +708,13 @@
 		ret = btrfs_update_root(trans, tree_root,
 					&root->root_key,
 					&root->root_item);
-		BUG_ON(ret);
+		if (ret)
+			return ret;
 
 		old_root_used = btrfs_root_used(&root->root_item);
 		ret = btrfs_write_dirty_block_groups(trans, root);
-		BUG_ON(ret);
+		if (ret)
+			return ret;
 	}
 
 	if (root != root->fs_info->extent_root)
@@ -705,6 +725,10 @@
 
 /*
  * update all the cowonly tree roots on disk
+ *
+ * The error handling in this function may not be obvious. Any of the
+ * failures will cause the file system to go offline. We still need
+ * to clean up the delayed refs.
  */
 static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
 					 struct btrfs_root *root)
@@ -715,22 +739,30 @@
 	int ret;
 
 	ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
-	BUG_ON(ret);
+	if (ret)
+		return ret;
 
 	eb = btrfs_lock_root_node(fs_info->tree_root);
-	btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb);
+	ret = btrfs_cow_block(trans, fs_info->tree_root, eb, NULL,
+			      0, &eb);
 	btrfs_tree_unlock(eb);
 	free_extent_buffer(eb);
 
+	if (ret)
+		return ret;
+
 	ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
-	BUG_ON(ret);
+	if (ret)
+		return ret;
 
 	while (!list_empty(&fs_info->dirty_cowonly_roots)) {
 		next = fs_info->dirty_cowonly_roots.next;
 		list_del_init(next);
 		root = list_entry(next, struct btrfs_root, dirty_list);
 
-		update_cowonly_root(trans, root);
+		ret = update_cowonly_root(trans, root);
+		if (ret)
+			return ret;
 	}
 
 	down_write(&fs_info->extent_commit_sem);
@@ -874,7 +906,7 @@
 
 	new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS);
 	if (!new_root_item) {
-		pending->error = -ENOMEM;
+		ret = pending->error = -ENOMEM;
 		goto fail;
 	}
 
@@ -911,21 +943,24 @@
 	 * insert the directory item
 	 */
 	ret = btrfs_set_inode_index(parent_inode, &index);
-	BUG_ON(ret);
+	BUG_ON(ret); /* -ENOMEM */
 	ret = btrfs_insert_dir_item(trans, parent_root,
 				dentry->d_name.name, dentry->d_name.len,
 				parent_inode, &key,
 				BTRFS_FT_DIR, index);
-	if (ret) {
+	if (ret == -EEXIST) {
 		pending->error = -EEXIST;
 		dput(parent);
 		goto fail;
+	} else if (ret) {
+		goto abort_trans_dput;
 	}
 
 	btrfs_i_size_write(parent_inode, parent_inode->i_size +
 					 dentry->d_name.len * 2);
 	ret = btrfs_update_inode(trans, parent_root, parent_inode);
-	BUG_ON(ret);
+	if (ret)
+		goto abort_trans_dput;
 
 	/*
 	 * pull in the delayed directory update
@@ -934,7 +969,10 @@
 	 * snapshot
 	 */
 	ret = btrfs_run_delayed_items(trans, root);
-	BUG_ON(ret);
+	if (ret) { /* Transaction aborted */
+		dput(parent);
+		goto fail;
+	}
 
 	record_root_in_trans(trans, root);
 	btrfs_set_root_last_snapshot(&root->root_item, trans->transid);
@@ -949,12 +987,21 @@
 	btrfs_set_root_flags(new_root_item, root_flags);
 
 	old = btrfs_lock_root_node(root);
-	btrfs_cow_block(trans, root, old, NULL, 0, &old);
+	ret = btrfs_cow_block(trans, root, old, NULL, 0, &old);
+	if (ret) {
+		btrfs_tree_unlock(old);
+		free_extent_buffer(old);
+		goto abort_trans_dput;
+	}
+
 	btrfs_set_lock_blocking(old);
 
-	btrfs_copy_root(trans, root, old, &tmp, objectid);
+	ret = btrfs_copy_root(trans, root, old, &tmp, objectid);
+	/* clean up in any case */
 	btrfs_tree_unlock(old);
 	free_extent_buffer(old);
+	if (ret)
+		goto abort_trans_dput;
 
 	/* see comments in should_cow_block() */
 	root->force_cow = 1;
@@ -966,7 +1013,8 @@
 	ret = btrfs_insert_root(trans, tree_root, &key, new_root_item);
 	btrfs_tree_unlock(tmp);
 	free_extent_buffer(tmp);
-	BUG_ON(ret);
+	if (ret)
+		goto abort_trans_dput;
 
 	/*
 	 * insert root back/forward references
@@ -975,19 +1023,32 @@
 				 parent_root->root_key.objectid,
 				 btrfs_ino(parent_inode), index,
 				 dentry->d_name.name, dentry->d_name.len);
-	BUG_ON(ret);
 	dput(parent);
+	if (ret)
+		goto fail;
 
 	key.offset = (u64)-1;
 	pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key);
-	BUG_ON(IS_ERR(pending->snap));
+	if (IS_ERR(pending->snap)) {
+		ret = PTR_ERR(pending->snap);
+		goto abort_trans;
+	}
 
-	btrfs_reloc_post_snapshot(trans, pending);
+	ret = btrfs_reloc_post_snapshot(trans, pending);
+	if (ret)
+		goto abort_trans;
+	ret = 0;
 fail:
 	kfree(new_root_item);
 	trans->block_rsv = rsv;
 	btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1);
-	return 0;
+	return ret;
+
+abort_trans_dput:
+	dput(parent);
+abort_trans:
+	btrfs_abort_transaction(trans, root, ret);
+	goto fail;
 }
 
 /*
@@ -1124,6 +1185,33 @@
 	return 0;
 }
 
+
+static void cleanup_transaction(struct btrfs_trans_handle *trans,
+				struct btrfs_root *root)
+{
+	struct btrfs_transaction *cur_trans = trans->transaction;
+
+	WARN_ON(trans->use_count > 1);
+
+	spin_lock(&root->fs_info->trans_lock);
+	list_del_init(&cur_trans->list);
+	spin_unlock(&root->fs_info->trans_lock);
+
+	btrfs_cleanup_one_transaction(trans->transaction, root);
+
+	put_transaction(cur_trans);
+	put_transaction(cur_trans);
+
+	trace_btrfs_transaction_commit(root);
+
+	btrfs_scrub_continue(root);
+
+	if (current->journal_info == trans)
+		current->journal_info = NULL;
+
+	kmem_cache_free(btrfs_trans_handle_cachep, trans);
+}
+
 /*
  * btrfs_transaction state sequence:
  *    in_commit = 0, blocked = 0  (initial)
@@ -1135,10 +1223,10 @@
 			     struct btrfs_root *root)
 {
 	unsigned long joined = 0;
-	struct btrfs_transaction *cur_trans;
+	struct btrfs_transaction *cur_trans = trans->transaction;
 	struct btrfs_transaction *prev_trans = NULL;
 	DEFINE_WAIT(wait);
-	int ret;
+	int ret = -EIO;
 	int should_grow = 0;
 	unsigned long now = get_seconds();
 	int flush_on_commit = btrfs_test_opt(root, FLUSHONCOMMIT);
@@ -1148,13 +1236,18 @@
 	btrfs_trans_release_metadata(trans, root);
 	trans->block_rsv = NULL;
 
+	if (cur_trans->aborted)
+		goto cleanup_transaction;
+
 	/* make a pass through all the delayed refs we have so far
 	 * any runnings procs may add more while we are here
 	 */
 	ret = btrfs_run_delayed_refs(trans, root, 0);
-	BUG_ON(ret);
+	if (ret)
+		goto cleanup_transaction;
 
 	cur_trans = trans->transaction;
+
 	/*
 	 * set the flushing flag so procs in this transaction have to
 	 * start sending their work down.
@@ -1162,19 +1255,20 @@
 	cur_trans->delayed_refs.flushing = 1;
 
 	ret = btrfs_run_delayed_refs(trans, root, 0);
-	BUG_ON(ret);
+	if (ret)
+		goto cleanup_transaction;
 
 	spin_lock(&cur_trans->commit_lock);
 	if (cur_trans->in_commit) {
 		spin_unlock(&cur_trans->commit_lock);
 		atomic_inc(&cur_trans->use_count);
-		btrfs_end_transaction(trans, root);
+		ret = btrfs_end_transaction(trans, root);
 
 		wait_for_commit(root, cur_trans);
 
 		put_transaction(cur_trans);
 
-		return 0;
+		return ret;
 	}
 
 	trans->transaction->in_commit = 1;
@@ -1214,12 +1308,12 @@
 
 		if (flush_on_commit || snap_pending) {
 			btrfs_start_delalloc_inodes(root, 1);
-			ret = btrfs_wait_ordered_extents(root, 0, 1);
-			BUG_ON(ret);
+			btrfs_wait_ordered_extents(root, 0, 1);
 		}
 
 		ret = btrfs_run_delayed_items(trans, root);
-		BUG_ON(ret);
+		if (ret)
+			goto cleanup_transaction;
 
 		/*
 		 * rename don't use btrfs_join_transaction, so, once we
@@ -1261,13 +1355,22 @@
 	mutex_lock(&root->fs_info->reloc_mutex);
 
 	ret = btrfs_run_delayed_items(trans, root);
-	BUG_ON(ret);
+	if (ret) {
+		mutex_unlock(&root->fs_info->reloc_mutex);
+		goto cleanup_transaction;
+	}
 
 	ret = create_pending_snapshots(trans, root->fs_info);
-	BUG_ON(ret);
+	if (ret) {
+		mutex_unlock(&root->fs_info->reloc_mutex);
+		goto cleanup_transaction;
+	}
 
 	ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
-	BUG_ON(ret);
+	if (ret) {
+		mutex_unlock(&root->fs_info->reloc_mutex);
+		goto cleanup_transaction;
+	}
 
 	/*
 	 * make sure none of the code above managed to slip in a
@@ -1294,7 +1397,10 @@
 	mutex_lock(&root->fs_info->tree_log_mutex);
 
 	ret = commit_fs_roots(trans, root);
-	BUG_ON(ret);
+	if (ret) {
+		mutex_unlock(&root->fs_info->tree_log_mutex);
+		goto cleanup_transaction;
+	}
 
 	/* commit_fs_roots gets rid of all the tree log roots, it is now
 	 * safe to free the root of tree log roots
@@ -1302,7 +1408,10 @@
 	btrfs_free_log_root_tree(trans, root->fs_info);
 
 	ret = commit_cowonly_roots(trans, root);
-	BUG_ON(ret);
+	if (ret) {
+		mutex_unlock(&root->fs_info->tree_log_mutex);
+		goto cleanup_transaction;
+	}
 
 	btrfs_prepare_extent_commit(trans, root);
 
@@ -1336,8 +1445,18 @@
 	wake_up(&root->fs_info->transaction_wait);
 
 	ret = btrfs_write_and_wait_transaction(trans, root);
-	BUG_ON(ret);
-	write_ctree_super(trans, root, 0);
+	if (ret) {
+		btrfs_error(root->fs_info, ret,
+			    "Error while writing out transaction.");
+		mutex_unlock(&root->fs_info->tree_log_mutex);
+		goto cleanup_transaction;
+	}
+
+	ret = write_ctree_super(trans, root, 0);
+	if (ret) {
+		mutex_unlock(&root->fs_info->tree_log_mutex);
+		goto cleanup_transaction;
+	}
 
 	/*
 	 * the super is written, we can safely allow the tree-loggers
@@ -1373,6 +1492,15 @@
 		btrfs_run_delayed_iputs(root);
 
 	return ret;
+
+cleanup_transaction:
+	btrfs_printk(root->fs_info, "Skipping commit of aborted transaction.\n");
+//	WARN_ON(1);
+	if (current->journal_info == trans)
+		current->journal_info = NULL;
+	cleanup_transaction(trans, root);
+
+	return ret;
 }
 
 /*
@@ -1388,6 +1516,8 @@
 	spin_unlock(&fs_info->trans_lock);
 
 	while (!list_empty(&list)) {
+		int ret;
+
 		root = list_entry(list.next, struct btrfs_root, root_list);
 		list_del(&root->root_list);
 
@@ -1395,9 +1525,10 @@
 
 		if (btrfs_header_backref_rev(root->node) <
 		    BTRFS_MIXED_BACKREF_REV)
-			btrfs_drop_snapshot(root, NULL, 0, 0);
+			ret = btrfs_drop_snapshot(root, NULL, 0, 0);
 		else
-			btrfs_drop_snapshot(root, NULL, 1, 0);
+			ret =btrfs_drop_snapshot(root, NULL, 1, 0);
+		BUG_ON(ret < 0);
 	}
 	return 0;
 }
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index 02564e6..fe27379 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -43,6 +43,7 @@
 	wait_queue_head_t commit_wait;
 	struct list_head pending_snapshots;
 	struct btrfs_delayed_ref_root delayed_refs;
+	int aborted;
 };
 
 struct btrfs_trans_handle {
@@ -55,6 +56,7 @@
 	struct btrfs_transaction *transaction;
 	struct btrfs_block_rsv *block_rsv;
 	struct btrfs_block_rsv *orig_rsv;
+	int aborted;
 };
 
 struct btrfs_pending_snapshot {
@@ -114,4 +116,5 @@
 				struct extent_io_tree *dirty_pages, int mark);
 int btrfs_transaction_blocked(struct btrfs_fs_info *info);
 int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
+void put_transaction(struct btrfs_transaction *transaction);
 #endif
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 966cc74..d017283 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -212,14 +212,13 @@
  * indicate we're done making changes to the log tree
  * and wake up anyone waiting to do a sync
  */
-int btrfs_end_log_trans(struct btrfs_root *root)
+void btrfs_end_log_trans(struct btrfs_root *root)
 {
 	if (atomic_dec_and_test(&root->log_writers)) {
 		smp_mb();
 		if (waitqueue_active(&root->log_writer_wait))
 			wake_up(&root->log_writer_wait);
 	}
-	return 0;
 }
 
 
@@ -378,12 +377,11 @@
 		u32 found_size;
 		found_size = btrfs_item_size_nr(path->nodes[0],
 						path->slots[0]);
-		if (found_size > item_size) {
+		if (found_size > item_size)
 			btrfs_truncate_item(trans, root, path, item_size, 1);
-		} else if (found_size < item_size) {
-			ret = btrfs_extend_item(trans, root, path,
-						item_size - found_size);
-		}
+		else if (found_size < item_size)
+			btrfs_extend_item(trans, root, path,
+					  item_size - found_size);
 	} else if (ret) {
 		return ret;
 	}
@@ -1763,7 +1761,7 @@
 					BTRFS_TREE_LOG_OBJECTID);
 				ret = btrfs_free_and_pin_reserved_extent(root,
 							 bytenr, blocksize);
-				BUG_ON(ret);
+				BUG_ON(ret); /* -ENOMEM or logic errors */
 			}
 			free_extent_buffer(next);
 			continue;
@@ -1871,20 +1869,26 @@
 		wret = walk_down_log_tree(trans, log, path, &level, wc);
 		if (wret > 0)
 			break;
-		if (wret < 0)
+		if (wret < 0) {
 			ret = wret;
+			goto out;
+		}
 
 		wret = walk_up_log_tree(trans, log, path, &level, wc);
 		if (wret > 0)
 			break;
-		if (wret < 0)
+		if (wret < 0) {
 			ret = wret;
+			goto out;
+		}
 	}
 
 	/* was the root node processed? if not, catch it here */
 	if (path->nodes[orig_level]) {
-		wc->process_func(log, path->nodes[orig_level], wc,
+		ret = wc->process_func(log, path->nodes[orig_level], wc,
 			 btrfs_header_generation(path->nodes[orig_level]));
+		if (ret)
+			goto out;
 		if (wc->free) {
 			struct extent_buffer *next;
 
@@ -1900,10 +1904,11 @@
 				BTRFS_TREE_LOG_OBJECTID);
 			ret = btrfs_free_and_pin_reserved_extent(log, next->start,
 							 next->len);
-			BUG_ON(ret);
+			BUG_ON(ret); /* -ENOMEM or logic errors */
 		}
 	}
 
+out:
 	for (i = 0; i <= orig_level; i++) {
 		if (path->nodes[i]) {
 			free_extent_buffer(path->nodes[i]);
@@ -1963,8 +1968,8 @@
 	return 0;
 }
 
-static int wait_for_writer(struct btrfs_trans_handle *trans,
-			   struct btrfs_root *root)
+static void wait_for_writer(struct btrfs_trans_handle *trans,
+			    struct btrfs_root *root)
 {
 	DEFINE_WAIT(wait);
 	while (root->fs_info->last_trans_log_full_commit !=
@@ -1978,7 +1983,6 @@
 		mutex_lock(&root->log_mutex);
 		finish_wait(&root->log_writer_wait, &wait);
 	}
-	return 0;
 }
 
 /*
@@ -2046,7 +2050,11 @@
 	 * wait for them until later.
 	 */
 	ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark);
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
+		mutex_unlock(&root->log_mutex);
+		goto out;
+	}
 
 	btrfs_set_root_node(&log->root_item, log->node);
 
@@ -2077,7 +2085,11 @@
 	}
 
 	if (ret) {
-		BUG_ON(ret != -ENOSPC);
+		if (ret != -ENOSPC) {
+			btrfs_abort_transaction(trans, root, ret);
+			mutex_unlock(&log_root_tree->log_mutex);
+			goto out;
+		}
 		root->fs_info->last_trans_log_full_commit = trans->transid;
 		btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
 		mutex_unlock(&log_root_tree->log_mutex);
@@ -2117,7 +2129,11 @@
 	ret = btrfs_write_and_wait_marked_extents(log_root_tree,
 				&log_root_tree->dirty_log_pages,
 				EXTENT_DIRTY | EXTENT_NEW);
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_abort_transaction(trans, root, ret);
+		mutex_unlock(&log_root_tree->log_mutex);
+		goto out_wake_log_root;
+	}
 	btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
 
 	btrfs_set_super_log_root(root->fs_info->super_for_commit,
@@ -2326,7 +2342,9 @@
 	if (ret == -ENOSPC) {
 		root->fs_info->last_trans_log_full_commit = trans->transid;
 		ret = 0;
-	}
+	} else if (ret < 0)
+		btrfs_abort_transaction(trans, root, ret);
+
 	btrfs_end_log_trans(root);
 
 	return err;
@@ -2357,7 +2375,8 @@
 	if (ret == -ENOSPC) {
 		root->fs_info->last_trans_log_full_commit = trans->transid;
 		ret = 0;
-	}
+	} else if (ret < 0 && ret != -ENOENT)
+		btrfs_abort_transaction(trans, root, ret);
 	btrfs_end_log_trans(root);
 
 	return ret;
@@ -3169,13 +3188,20 @@
 	fs_info->log_root_recovering = 1;
 
 	trans = btrfs_start_transaction(fs_info->tree_root, 0);
-	BUG_ON(IS_ERR(trans));
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
+		goto error;
+	}
 
 	wc.trans = trans;
 	wc.pin = 1;
 
 	ret = walk_log_tree(trans, log_root_tree, &wc);
-	BUG_ON(ret);
+	if (ret) {
+		btrfs_error(fs_info, ret, "Failed to pin buffers while "
+			    "recovering log root tree.");
+		goto error;
+	}
 
 again:
 	key.objectid = BTRFS_TREE_LOG_OBJECTID;
@@ -3184,8 +3210,12 @@
 
 	while (1) {
 		ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0);
-		if (ret < 0)
-			break;
+
+		if (ret < 0) {
+			btrfs_error(fs_info, ret,
+				    "Couldn't find tree log root.");
+			goto error;
+		}
 		if (ret > 0) {
 			if (path->slots[0] == 0)
 				break;
@@ -3199,14 +3229,24 @@
 
 		log = btrfs_read_fs_root_no_radix(log_root_tree,
 						  &found_key);
-		BUG_ON(IS_ERR(log));
+		if (IS_ERR(log)) {
+			ret = PTR_ERR(log);
+			btrfs_error(fs_info, ret,
+				    "Couldn't read tree log root.");
+			goto error;
+		}
 
 		tmp_key.objectid = found_key.offset;
 		tmp_key.type = BTRFS_ROOT_ITEM_KEY;
 		tmp_key.offset = (u64)-1;
 
 		wc.replay_dest = btrfs_read_fs_root_no_name(fs_info, &tmp_key);
-		BUG_ON(IS_ERR_OR_NULL(wc.replay_dest));
+		if (IS_ERR(wc.replay_dest)) {
+			ret = PTR_ERR(wc.replay_dest);
+			btrfs_error(fs_info, ret, "Couldn't read target root "
+				    "for tree log recovery.");
+			goto error;
+		}
 
 		wc.replay_dest->log_root = log;
 		btrfs_record_root_in_trans(trans, wc.replay_dest);
@@ -3254,6 +3294,10 @@
 
 	kfree(log_root_tree);
 	return 0;
+
+error:
+	btrfs_free_path(path);
+	return ret;
 }
 
 /*
diff --git a/fs/btrfs/tree-log.h b/fs/btrfs/tree-log.h
index 2270ac5..862ac81 100644
--- a/fs/btrfs/tree-log.h
+++ b/fs/btrfs/tree-log.h
@@ -38,7 +38,7 @@
 			       struct btrfs_root *root,
 			       const char *name, int name_len,
 			       struct inode *inode, u64 dirid);
-int btrfs_end_log_trans(struct btrfs_root *root);
+void btrfs_end_log_trans(struct btrfs_root *root);
 int btrfs_pin_log_trans(struct btrfs_root *root);
 int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
 		    struct btrfs_root *root, struct inode *inode,
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index ef41f28..a872b48 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -67,7 +67,7 @@
 	kfree(fs_devices);
 }
 
-int btrfs_cleanup_fs_uuids(void)
+void btrfs_cleanup_fs_uuids(void)
 {
 	struct btrfs_fs_devices *fs_devices;
 
@@ -77,7 +77,6 @@
 		list_del(&fs_devices->list);
 		free_fs_devices(fs_devices);
 	}
-	return 0;
 }
 
 static noinline struct btrfs_device *__find_device(struct list_head *head,
@@ -130,7 +129,7 @@
  * the list if the block device is congested.  This way, multiple devices
  * can make progress from a single worker thread.
  */
-static noinline int run_scheduled_bios(struct btrfs_device *device)
+static noinline void run_scheduled_bios(struct btrfs_device *device)
 {
 	struct bio *pending;
 	struct backing_dev_info *bdi;
@@ -316,7 +315,6 @@
 
 done:
 	blk_finish_plug(&plug);
-	return 0;
 }
 
 static void pending_bios_fn(struct btrfs_work *work)
@@ -455,7 +453,7 @@
 	return ERR_PTR(-ENOMEM);
 }
 
-int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices)
+void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices)
 {
 	struct btrfs_device *device, *next;
 
@@ -503,7 +501,6 @@
 	fs_devices->latest_trans = latest_transid;
 
 	mutex_unlock(&uuid_mutex);
-	return 0;
 }
 
 static void __free_device(struct work_struct *work)
@@ -552,10 +549,10 @@
 			fs_devices->num_can_discard--;
 
 		new_device = kmalloc(sizeof(*new_device), GFP_NOFS);
-		BUG_ON(!new_device);
+		BUG_ON(!new_device); /* -ENOMEM */
 		memcpy(new_device, device, sizeof(*new_device));
 		new_device->name = kstrdup(device->name, GFP_NOFS);
-		BUG_ON(device->name && !new_device->name);
+		BUG_ON(device->name && !new_device->name); /* -ENOMEM */
 		new_device->bdev = NULL;
 		new_device->writeable = 0;
 		new_device->in_fs_metadata = 0;
@@ -625,6 +622,8 @@
 			printk(KERN_INFO "open %s failed\n", device->name);
 			goto error;
 		}
+		filemap_write_and_wait(bdev->bd_inode->i_mapping);
+		invalidate_bdev(bdev);
 		set_blocksize(bdev, 4096);
 
 		bh = btrfs_read_dev_super(bdev);
@@ -1039,8 +1038,10 @@
 		leaf = path->nodes[0];
 		extent = btrfs_item_ptr(leaf, path->slots[0],
 					struct btrfs_dev_extent);
+	} else {
+		btrfs_error(root->fs_info, ret, "Slot search failed");
+		goto out;
 	}
-	BUG_ON(ret);
 
 	if (device->bytes_used > 0) {
 		u64 len = btrfs_dev_extent_length(leaf, extent);
@@ -1050,7 +1051,10 @@
 		spin_unlock(&root->fs_info->free_chunk_lock);
 	}
 	ret = btrfs_del_item(trans, root, path);
-
+	if (ret) {
+		btrfs_error(root->fs_info, ret,
+			    "Failed to remove dev extent item");
+	}
 out:
 	btrfs_free_path(path);
 	return ret;
@@ -1078,7 +1082,8 @@
 	key.type = BTRFS_DEV_EXTENT_KEY;
 	ret = btrfs_insert_empty_item(trans, root, path, &key,
 				      sizeof(*extent));
-	BUG_ON(ret);
+	if (ret)
+		goto out;
 
 	leaf = path->nodes[0];
 	extent = btrfs_item_ptr(leaf, path->slots[0],
@@ -1093,6 +1098,7 @@
 
 	btrfs_set_dev_extent_length(leaf, extent, num_bytes);
 	btrfs_mark_buffer_dirty(leaf);
+out:
 	btrfs_free_path(path);
 	return ret;
 }
@@ -1118,7 +1124,7 @@
 	if (ret < 0)
 		goto error;
 
-	BUG_ON(ret == 0);
+	BUG_ON(ret == 0); /* Corruption */
 
 	ret = btrfs_previous_item(root, path, 0, BTRFS_CHUNK_ITEM_KEY);
 	if (ret) {
@@ -1162,7 +1168,7 @@
 	if (ret < 0)
 		goto error;
 
-	BUG_ON(ret == 0);
+	BUG_ON(ret == 0); /* Corruption */
 
 	ret = btrfs_previous_item(root, path, BTRFS_DEV_ITEMS_OBJECTID,
 				  BTRFS_DEV_ITEM_KEY);
@@ -1350,6 +1356,7 @@
 		}
 
 		set_blocksize(bdev, 4096);
+		invalidate_bdev(bdev);
 		bh = btrfs_read_dev_super(bdev);
 		if (!bh) {
 			ret = -EINVAL;
@@ -1596,7 +1603,7 @@
 				   (unsigned long)btrfs_device_fsid(dev_item),
 				   BTRFS_UUID_SIZE);
 		device = btrfs_find_device(root, devid, dev_uuid, fs_uuid);
-		BUG_ON(!device);
+		BUG_ON(!device); /* Logic error */
 
 		if (device->fs_devices->seeding) {
 			btrfs_set_device_generation(leaf, dev_item,
@@ -1706,7 +1713,7 @@
 	if (seeding_dev) {
 		sb->s_flags &= ~MS_RDONLY;
 		ret = btrfs_prepare_sprout(root);
-		BUG_ON(ret);
+		BUG_ON(ret); /* -ENOMEM */
 	}
 
 	device->fs_devices = root->fs_info->fs_devices;
@@ -1744,11 +1751,15 @@
 
 	if (seeding_dev) {
 		ret = init_first_rw_device(trans, root, device);
-		BUG_ON(ret);
+		if (ret)
+			goto error_trans;
 		ret = btrfs_finish_sprout(trans, root);
-		BUG_ON(ret);
+		if (ret)
+			goto error_trans;
 	} else {
 		ret = btrfs_add_device(trans, root, device);
+		if (ret)
+			goto error_trans;
 	}
 
 	/*
@@ -1758,17 +1769,31 @@
 	btrfs_clear_space_info_full(root->fs_info);
 
 	unlock_chunks(root);
-	btrfs_commit_transaction(trans, root);
+	ret = btrfs_commit_transaction(trans, root);
 
 	if (seeding_dev) {
 		mutex_unlock(&uuid_mutex);
 		up_write(&sb->s_umount);
 
+		if (ret) /* transaction commit */
+			return ret;
+
 		ret = btrfs_relocate_sys_chunks(root);
-		BUG_ON(ret);
+		if (ret < 0)
+			btrfs_error(root->fs_info, ret,
+				    "Failed to relocate sys chunks after "
+				    "device initialization. This can be fixed "
+				    "using the \"btrfs balance\" command.");
 	}
 
 	return ret;
+
+error_trans:
+	unlock_chunks(root);
+	btrfs_abort_transaction(trans, root, ret);
+	btrfs_end_transaction(trans, root);
+	kfree(device->name);
+	kfree(device);
 error:
 	blkdev_put(bdev, FMODE_EXCL);
 	if (seeding_dev) {
@@ -1876,10 +1901,20 @@
 	key.type = BTRFS_CHUNK_ITEM_KEY;
 
 	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
-	BUG_ON(ret);
+	if (ret < 0)
+		goto out;
+	else if (ret > 0) { /* Logic error or corruption */
+		btrfs_error(root->fs_info, -ENOENT,
+			    "Failed lookup while freeing chunk.");
+		ret = -ENOENT;
+		goto out;
+	}
 
 	ret = btrfs_del_item(trans, root, path);
-
+	if (ret < 0)
+		btrfs_error(root->fs_info, ret,
+			    "Failed to delete chunk item.");
+out:
 	btrfs_free_path(path);
 	return ret;
 }
@@ -2041,7 +2076,7 @@
 		ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0);
 		if (ret < 0)
 			goto error;
-		BUG_ON(ret == 0);
+		BUG_ON(ret == 0); /* Corruption */
 
 		ret = btrfs_previous_item(chunk_root, path, key.objectid,
 					  key.type);
@@ -2250,15 +2285,13 @@
  * Balance filters.  Return 1 if chunk should be filtered out
  * (should not be balanced).
  */
-static int chunk_profiles_filter(u64 chunk_profile,
+static int chunk_profiles_filter(u64 chunk_type,
 				 struct btrfs_balance_args *bargs)
 {
-	chunk_profile &= BTRFS_BLOCK_GROUP_PROFILE_MASK;
+	chunk_type = chunk_to_extended(chunk_type) &
+				BTRFS_EXTENDED_PROFILE_MASK;
 
-	if (chunk_profile == 0)
-		chunk_profile = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
-
-	if (bargs->profiles & chunk_profile)
+	if (bargs->profiles & chunk_type)
 		return 0;
 
 	return 1;
@@ -2365,18 +2398,16 @@
 	return 1;
 }
 
-static int chunk_soft_convert_filter(u64 chunk_profile,
+static int chunk_soft_convert_filter(u64 chunk_type,
 				     struct btrfs_balance_args *bargs)
 {
 	if (!(bargs->flags & BTRFS_BALANCE_ARGS_CONVERT))
 		return 0;
 
-	chunk_profile &= BTRFS_BLOCK_GROUP_PROFILE_MASK;
+	chunk_type = chunk_to_extended(chunk_type) &
+				BTRFS_EXTENDED_PROFILE_MASK;
 
-	if (chunk_profile == 0)
-		chunk_profile = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
-
-	if (bargs->target & chunk_profile)
+	if (bargs->target == chunk_type)
 		return 1;
 
 	return 0;
@@ -2602,6 +2633,30 @@
 	return ret;
 }
 
+/**
+ * alloc_profile_is_valid - see if a given profile is valid and reduced
+ * @flags: profile to validate
+ * @extended: if true @flags is treated as an extended profile
+ */
+static int alloc_profile_is_valid(u64 flags, int extended)
+{
+	u64 mask = (extended ? BTRFS_EXTENDED_PROFILE_MASK :
+			       BTRFS_BLOCK_GROUP_PROFILE_MASK);
+
+	flags &= ~BTRFS_BLOCK_GROUP_TYPE_MASK;
+
+	/* 1) check that all other bits are zeroed */
+	if (flags & ~mask)
+		return 0;
+
+	/* 2) see if profile is reduced */
+	if (flags == 0)
+		return !extended; /* "0" is valid for usual profiles */
+
+	/* true if exactly one bit set */
+	return (flags & (flags - 1)) == 0;
+}
+
 static inline int balance_need_close(struct btrfs_fs_info *fs_info)
 {
 	/* cancel requested || normal exit path */
@@ -2630,6 +2685,7 @@
 {
 	struct btrfs_fs_info *fs_info = bctl->fs_info;
 	u64 allowed;
+	int mixed = 0;
 	int ret;
 
 	if (btrfs_fs_closing(fs_info) ||
@@ -2639,13 +2695,16 @@
 		goto out;
 	}
 
+	allowed = btrfs_super_incompat_flags(fs_info->super_copy);
+	if (allowed & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS)
+		mixed = 1;
+
 	/*
 	 * In case of mixed groups both data and meta should be picked,
 	 * and identical options should be given for both of them.
 	 */
-	allowed = btrfs_super_incompat_flags(fs_info->super_copy);
-	if ((allowed & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) &&
-	    (bctl->flags & (BTRFS_BALANCE_DATA | BTRFS_BALANCE_METADATA))) {
+	allowed = BTRFS_BALANCE_DATA | BTRFS_BALANCE_METADATA;
+	if (mixed && (bctl->flags & allowed)) {
 		if (!(bctl->flags & BTRFS_BALANCE_DATA) ||
 		    !(bctl->flags & BTRFS_BALANCE_METADATA) ||
 		    memcmp(&bctl->data, &bctl->meta, sizeof(bctl->data))) {
@@ -2656,14 +2715,6 @@
 		}
 	}
 
-	/*
-	 * Profile changing sanity checks.  Skip them if a simple
-	 * balance is requested.
-	 */
-	if (!((bctl->data.flags | bctl->sys.flags | bctl->meta.flags) &
-	      BTRFS_BALANCE_ARGS_CONVERT))
-		goto do_balance;
-
 	allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
 	if (fs_info->fs_devices->num_devices == 1)
 		allowed |= BTRFS_BLOCK_GROUP_DUP;
@@ -2673,24 +2724,27 @@
 		allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
 				BTRFS_BLOCK_GROUP_RAID10);
 
-	if (!profile_is_valid(bctl->data.target, 1) ||
-	    bctl->data.target & ~allowed) {
+	if ((bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
+	    (!alloc_profile_is_valid(bctl->data.target, 1) ||
+	     (bctl->data.target & ~allowed))) {
 		printk(KERN_ERR "btrfs: unable to start balance with target "
 		       "data profile %llu\n",
 		       (unsigned long long)bctl->data.target);
 		ret = -EINVAL;
 		goto out;
 	}
-	if (!profile_is_valid(bctl->meta.target, 1) ||
-	    bctl->meta.target & ~allowed) {
+	if ((bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
+	    (!alloc_profile_is_valid(bctl->meta.target, 1) ||
+	     (bctl->meta.target & ~allowed))) {
 		printk(KERN_ERR "btrfs: unable to start balance with target "
 		       "metadata profile %llu\n",
 		       (unsigned long long)bctl->meta.target);
 		ret = -EINVAL;
 		goto out;
 	}
-	if (!profile_is_valid(bctl->sys.target, 1) ||
-	    bctl->sys.target & ~allowed) {
+	if ((bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
+	    (!alloc_profile_is_valid(bctl->sys.target, 1) ||
+	     (bctl->sys.target & ~allowed))) {
 		printk(KERN_ERR "btrfs: unable to start balance with target "
 		       "system profile %llu\n",
 		       (unsigned long long)bctl->sys.target);
@@ -2698,7 +2752,9 @@
 		goto out;
 	}
 
-	if (bctl->data.target & BTRFS_BLOCK_GROUP_DUP) {
+	/* allow dup'ed data chunks only in mixed mode */
+	if (!mixed && (bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
+	    (bctl->data.target & BTRFS_BLOCK_GROUP_DUP)) {
 		printk(KERN_ERR "btrfs: dup for data is not allowed\n");
 		ret = -EINVAL;
 		goto out;
@@ -2724,7 +2780,6 @@
 		}
 	}
 
-do_balance:
 	ret = insert_balance_item(fs_info->tree_root, bctl);
 	if (ret && ret != -EEXIST)
 		goto out;
@@ -2967,7 +3022,7 @@
 	key.offset = (u64)-1;
 	key.type = BTRFS_DEV_EXTENT_KEY;
 
-	while (1) {
+	do {
 		ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 		if (ret < 0)
 			goto done;
@@ -3009,8 +3064,7 @@
 			goto done;
 		if (ret == -ENOSPC)
 			failed++;
-		key.offset -= 1;
-	}
+	} while (key.offset-- > 0);
 
 	if (failed && !retried) {
 		failed = 0;
@@ -3128,11 +3182,7 @@
 	int i;
 	int j;
 
-	if ((type & BTRFS_BLOCK_GROUP_RAID1) &&
-	    (type & BTRFS_BLOCK_GROUP_DUP)) {
-		WARN_ON(1);
-		type &= ~BTRFS_BLOCK_GROUP_DUP;
-	}
+	BUG_ON(!alloc_profile_is_valid(type, 0));
 
 	if (list_empty(&fs_devices->alloc_list))
 		return -ENOSPC;
@@ -3328,13 +3378,15 @@
 	write_lock(&em_tree->lock);
 	ret = add_extent_mapping(em_tree, em);
 	write_unlock(&em_tree->lock);
-	BUG_ON(ret);
 	free_extent_map(em);
+	if (ret)
+		goto error;
 
 	ret = btrfs_make_block_group(trans, extent_root, 0, type,
 				     BTRFS_FIRST_CHUNK_TREE_OBJECTID,
 				     start, num_bytes);
-	BUG_ON(ret);
+	if (ret)
+		goto error;
 
 	for (i = 0; i < map->num_stripes; ++i) {
 		struct btrfs_device *device;
@@ -3347,7 +3399,10 @@
 				info->chunk_root->root_key.objectid,
 				BTRFS_FIRST_CHUNK_TREE_OBJECTID,
 				start, dev_offset, stripe_size);
-		BUG_ON(ret);
+		if (ret) {
+			btrfs_abort_transaction(trans, extent_root, ret);
+			goto error;
+		}
 	}
 
 	kfree(devices_info);
@@ -3383,7 +3438,8 @@
 		device = map->stripes[index].dev;
 		device->bytes_used += stripe_size;
 		ret = btrfs_update_device(trans, device);
-		BUG_ON(ret);
+		if (ret)
+			goto out_free;
 		index++;
 	}
 
@@ -3420,16 +3476,19 @@
 	key.offset = chunk_offset;
 
 	ret = btrfs_insert_item(trans, chunk_root, &key, chunk, item_size);
-	BUG_ON(ret);
 
-	if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) {
+	if (ret == 0 && map->type & BTRFS_BLOCK_GROUP_SYSTEM) {
+		/*
+		 * TODO: Cleanup of inserted chunk root in case of
+		 * failure.
+		 */
 		ret = btrfs_add_system_chunk(chunk_root, &key, chunk,
 					     item_size);
-		BUG_ON(ret);
 	}
 
+out_free:
 	kfree(chunk);
-	return 0;
+	return ret;
 }
 
 /*
@@ -3461,7 +3520,8 @@
 
 	ret = __finish_chunk_alloc(trans, extent_root, map, chunk_offset,
 				   chunk_size, stripe_size);
-	BUG_ON(ret);
+	if (ret)
+		return ret;
 	return 0;
 }
 
@@ -3493,7 +3553,8 @@
 
 	ret = __btrfs_alloc_chunk(trans, extent_root, &map, &chunk_size,
 				  &stripe_size, chunk_offset, alloc_profile);
-	BUG_ON(ret);
+	if (ret)
+		return ret;
 
 	sys_chunk_offset = chunk_offset + chunk_size;
 
@@ -3504,10 +3565,12 @@
 	ret = __btrfs_alloc_chunk(trans, extent_root, &sys_map,
 				  &sys_chunk_size, &sys_stripe_size,
 				  sys_chunk_offset, alloc_profile);
-	BUG_ON(ret);
+	if (ret)
+		goto abort;
 
 	ret = btrfs_add_device(trans, fs_info->chunk_root, device);
-	BUG_ON(ret);
+	if (ret)
+		goto abort;
 
 	/*
 	 * Modifying chunk tree needs allocating new blocks from both
@@ -3517,13 +3580,20 @@
 	 */
 	ret = __finish_chunk_alloc(trans, extent_root, map, chunk_offset,
 				   chunk_size, stripe_size);
-	BUG_ON(ret);
+	if (ret)
+		goto abort;
 
 	ret = __finish_chunk_alloc(trans, extent_root, sys_map,
 				   sys_chunk_offset, sys_chunk_size,
 				   sys_stripe_size);
-	BUG_ON(ret);
+	if (ret)
+		goto abort;
+
 	return 0;
+
+abort:
+	btrfs_abort_transaction(trans, root, ret);
+	return ret;
 }
 
 int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset)
@@ -3874,7 +3944,7 @@
 		do_div(length, map->num_stripes);
 
 	buf = kzalloc(sizeof(u64) * map->num_stripes, GFP_NOFS);
-	BUG_ON(!buf);
+	BUG_ON(!buf); /* -ENOMEM */
 
 	for (i = 0; i < map->num_stripes; i++) {
 		if (devid && map->stripes[i].dev->devid != devid)
@@ -3967,7 +4037,7 @@
  * This will add one bio to the pending list for a device and make sure
  * the work struct is scheduled.
  */
-static noinline int schedule_bio(struct btrfs_root *root,
+static noinline void schedule_bio(struct btrfs_root *root,
 				 struct btrfs_device *device,
 				 int rw, struct bio *bio)
 {
@@ -3979,7 +4049,7 @@
 		bio_get(bio);
 		btrfsic_submit_bio(rw, bio);
 		bio_put(bio);
-		return 0;
+		return;
 	}
 
 	/*
@@ -4013,7 +4083,6 @@
 	if (should_queue)
 		btrfs_queue_worker(&root->fs_info->submit_workers,
 				   &device->work);
-	return 0;
 }
 
 int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
@@ -4036,7 +4105,8 @@
 
 	ret = btrfs_map_block(map_tree, rw, logical, &map_length, &bbio,
 			      mirror_num);
-	BUG_ON(ret);
+	if (ret) /* -ENOMEM */
+		return ret;
 
 	total_devs = bbio->num_stripes;
 	if (map_length < length) {
@@ -4055,7 +4125,7 @@
 	while (dev_nr < total_devs) {
 		if (dev_nr < total_devs - 1) {
 			bio = bio_clone(first_bio, GFP_NOFS);
-			BUG_ON(!bio);
+			BUG_ON(!bio); /* -ENOMEM */
 		} else {
 			bio = first_bio;
 		}
@@ -4209,13 +4279,13 @@
 	write_lock(&map_tree->map_tree.lock);
 	ret = add_extent_mapping(&map_tree->map_tree, em);
 	write_unlock(&map_tree->map_tree.lock);
-	BUG_ON(ret);
+	BUG_ON(ret); /* Tree corruption */
 	free_extent_map(em);
 
 	return 0;
 }
 
-static int fill_device_from_item(struct extent_buffer *leaf,
+static void fill_device_from_item(struct extent_buffer *leaf,
 				 struct btrfs_dev_item *dev_item,
 				 struct btrfs_device *device)
 {
@@ -4232,8 +4302,6 @@
 
 	ptr = (unsigned long)btrfs_device_uuid(dev_item);
 	read_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE);
-
-	return 0;
 }
 
 static int open_seed_devices(struct btrfs_root *root, u8 *fsid)
@@ -4384,7 +4452,7 @@
 	 * to silence the warning eg. on PowerPC 64.
 	 */
 	if (PAGE_CACHE_SIZE > BTRFS_SUPER_INFO_SIZE)
-		SetPageUptodate(sb->first_page);
+		SetPageUptodate(sb->pages[0]);
 
 	write_extent_buffer(sb, super_copy, 0, BTRFS_SUPER_INFO_SIZE);
 	array_size = btrfs_super_sys_array_size(super_copy);
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 19ac950..bb6b03f 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -260,12 +260,12 @@
 int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
 			  struct btrfs_fs_devices **fs_devices_ret);
 int btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
-int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices);
+void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices);
 int btrfs_add_device(struct btrfs_trans_handle *trans,
 		     struct btrfs_root *root,
 		     struct btrfs_device *device);
 int btrfs_rm_device(struct btrfs_root *root, char *device_path);
-int btrfs_cleanup_fs_uuids(void);
+void btrfs_cleanup_fs_uuids(void);
 int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len);
 int btrfs_grow_device(struct btrfs_trans_handle *trans,
 		      struct btrfs_device *device, u64 new_size);
diff --git a/fs/buffer.c b/fs/buffer.c
index 1a30db7..36d6665 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -29,7 +29,7 @@
 #include <linux/file.h>
 #include <linux/quotaops.h>
 #include <linux/highmem.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/writeback.h>
 #include <linux/hash.h>
 #include <linux/suspend.h>
@@ -1384,10 +1384,23 @@
 	}
 	put_cpu_var(bh_lrus);
 }
+
+static bool has_bh_in_lru(int cpu, void *dummy)
+{
+	struct bh_lru *b = per_cpu_ptr(&bh_lrus, cpu);
+	int i;
 	
+	for (i = 0; i < BH_LRU_SIZE; i++) {
+		if (b->bhs[i])
+			return 1;
+	}
+
+	return 0;
+}
+
 void invalidate_bh_lrus(void)
 {
-	on_each_cpu(invalidate_bh_lru, NULL, 1);
+	on_each_cpu_cond(has_bh_in_lru, invalidate_bh_lru, NULL, 1, GFP_KERNEL);
 }
 EXPORT_SYMBOL_GPL(invalidate_bh_lrus);
 
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index a0358c2..7f0771d 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -646,7 +646,8 @@
 		 * (this is used to keep track of culling, and atimes are only
 		 * updated by read, write and readdir but not lookup or
 		 * open) */
-		touch_atime(cache->mnt, next);
+		path.dentry = next;
+		touch_atime(&path);
 	}
 
 	/* open a file interface onto a data file */
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 2c48937..9fff9f3 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -677,18 +677,19 @@
 	case S_IFLNK:
 		inode->i_op = &ceph_symlink_iops;
 		if (!ci->i_symlink) {
-			int symlen = iinfo->symlink_len;
+			u32 symlen = iinfo->symlink_len;
 			char *sym;
 
-			BUG_ON(symlen != inode->i_size);
 			spin_unlock(&ci->i_ceph_lock);
 
+			err = -EINVAL;
+			if (WARN_ON(symlen != inode->i_size))
+				goto out;
+
 			err = -ENOMEM;
-			sym = kmalloc(symlen+1, GFP_NOFS);
+			sym = kstrndup(iinfo->symlink, symlen, GFP_NOFS);
 			if (!sym)
 				goto out;
-			memcpy(sym, iinfo->symlink, symlen);
-			sym[symlen] = 0;
 
 			spin_lock(&ci->i_ceph_lock);
 			if (!ci->i_symlink)
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 866e8d7..89971e1 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -402,7 +402,7 @@
 
 	spin_lock_init(&s->s_gen_ttl_lock);
 	s->s_cap_gen = 0;
-	s->s_cap_ttl = 0;
+	s->s_cap_ttl = jiffies - 1;
 
 	spin_lock_init(&s->s_cap_lock);
 	s->s_renew_requested = 0;
@@ -1083,8 +1083,7 @@
 	int wake = 0;
 
 	spin_lock(&session->s_cap_lock);
-	was_stale = is_renew && (session->s_cap_ttl == 0 ||
-				 time_after_eq(jiffies, session->s_cap_ttl));
+	was_stale = is_renew && time_after_eq(jiffies, session->s_cap_ttl);
 
 	session->s_cap_ttl = session->s_renew_requested +
 		mdsc->mdsmap->m_session_timeout*HZ;
@@ -2332,7 +2331,7 @@
 			session->s_mds);
 		spin_lock(&session->s_gen_ttl_lock);
 		session->s_cap_gen++;
-		session->s_cap_ttl = 0;
+		session->s_cap_ttl = jiffies - 1;
 		spin_unlock(&session->s_gen_ttl_lock);
 		send_renew_caps(mdsc, session);
 		break;
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c
index a559c80..f04c096 100644
--- a/fs/ceph/snap.c
+++ b/fs/ceph/snap.c
@@ -331,7 +331,7 @@
 
 	/* alloc new snap context */
 	err = -ENOMEM;
-	if (num > ULONG_MAX / sizeof(u64) - sizeof(*snapc))
+	if (num > (ULONG_MAX - sizeof(*snapc)) / sizeof(u64))
 		goto fail;
 	snapc = kzalloc(sizeof(*snapc) + num*sizeof(u64), GFP_NOFS);
 	if (!snapc)
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index 00de2c9..1e67dd7 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -130,10 +130,12 @@
 	Opt_nodirstat,
 	Opt_rbytes,
 	Opt_norbytes,
+	Opt_asyncreaddir,
 	Opt_noasyncreaddir,
 	Opt_dcache,
 	Opt_nodcache,
 	Opt_ino32,
+	Opt_noino32,
 };
 
 static match_table_t fsopt_tokens = {
@@ -153,10 +155,12 @@
 	{Opt_nodirstat, "nodirstat"},
 	{Opt_rbytes, "rbytes"},
 	{Opt_norbytes, "norbytes"},
+	{Opt_asyncreaddir, "asyncreaddir"},
 	{Opt_noasyncreaddir, "noasyncreaddir"},
 	{Opt_dcache, "dcache"},
 	{Opt_nodcache, "nodcache"},
 	{Opt_ino32, "ino32"},
+	{Opt_noino32, "noino32"},
 	{-1, NULL}
 };
 
@@ -232,6 +236,9 @@
 	case Opt_norbytes:
 		fsopt->flags &= ~CEPH_MOUNT_OPT_RBYTES;
 		break;
+	case Opt_asyncreaddir:
+		fsopt->flags &= ~CEPH_MOUNT_OPT_NOASYNCREADDIR;
+		break;
 	case Opt_noasyncreaddir:
 		fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR;
 		break;
@@ -244,6 +251,9 @@
 	case Opt_ino32:
 		fsopt->flags |= CEPH_MOUNT_OPT_INO32;
 		break;
+	case Opt_noino32:
+		fsopt->flags &= ~CEPH_MOUNT_OPT_INO32;
+		break;
 	default:
 		BUG_ON(token);
 	}
@@ -334,10 +344,12 @@
 	*path += 2;
 	dout("server path '%s'\n", *path);
 
-	err = ceph_parse_options(popt, options, dev_name, dev_name_end,
+	*popt = ceph_parse_options(options, dev_name, dev_name_end,
 				 parse_fsopt_token, (void *)fsopt);
-	if (err)
+	if (IS_ERR(*popt)) {
+		err = PTR_ERR(*popt);
 		goto out;
+	}
 
 	/* success */
 	*pfsopt = fsopt;
@@ -655,9 +667,8 @@
 		dout("open_root_inode success\n");
 		if (ceph_ino(inode) == CEPH_INO_ROOT &&
 		    fsc->sb->s_root == NULL) {
-			root = d_alloc_root(inode);
+			root = d_make_root(inode);
 			if (!root) {
-				iput(inode);
 				root = ERR_PTR(-ENOMEM);
 				goto out;
 			}
@@ -927,6 +938,7 @@
 	if (ret)
 		goto out;
 
+	ceph_xattr_init();
 	ret = register_filesystem(&ceph_fs_type);
 	if (ret)
 		goto out_icache;
@@ -936,6 +948,7 @@
 	return 0;
 
 out_icache:
+	ceph_xattr_exit();
 	destroy_caches();
 out:
 	return ret;
@@ -945,6 +958,7 @@
 {
 	dout("exit_ceph\n");
 	unregister_filesystem(&ceph_fs_type);
+	ceph_xattr_exit();
 	destroy_caches();
 }
 
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 1421f3d..fc35036 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -367,7 +367,7 @@
 	u32 ino = vino & 0xffffffff;
 	ino ^= vino >> 32;
 	if (!ino)
-		ino = 1;
+		ino = 2;
 	return ino;
 }
 
@@ -733,6 +733,8 @@
 extern int ceph_removexattr(struct dentry *, const char *);
 extern void __ceph_build_xattrs_blob(struct ceph_inode_info *ci);
 extern void __ceph_destroy_xattrs(struct ceph_inode_info *ci);
+extern void __init ceph_xattr_init(void);
+extern void ceph_xattr_exit(void);
 
 /* caps.c */
 extern const char *ceph_cap_string(int c);
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
index a76f697..35b8633 100644
--- a/fs/ceph/xattr.c
+++ b/fs/ceph/xattr.c
@@ -8,9 +8,12 @@
 #include <linux/xattr.h>
 #include <linux/slab.h>
 
+#define XATTR_CEPH_PREFIX "ceph."
+#define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1)
+
 static bool ceph_is_valid_xattr(const char *name)
 {
-	return !strncmp(name, "ceph.", 5) ||
+	return !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) ||
 	       !strncmp(name, XATTR_SECURITY_PREFIX,
 			XATTR_SECURITY_PREFIX_LEN) ||
 	       !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
@@ -21,79 +24,91 @@
  * These define virtual xattrs exposing the recursive directory
  * statistics and layout metadata.
  */
-struct ceph_vxattr_cb {
-	bool readonly;
+struct ceph_vxattr {
 	char *name;
+	size_t name_size;	/* strlen(name) + 1 (for '\0') */
 	size_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val,
 			      size_t size);
+	bool readonly;
 };
 
 /* directories */
 
-static size_t ceph_vxattrcb_entries(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_entries(struct ceph_inode_info *ci, char *val,
 					size_t size)
 {
 	return snprintf(val, size, "%lld", ci->i_files + ci->i_subdirs);
 }
 
-static size_t ceph_vxattrcb_files(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_files(struct ceph_inode_info *ci, char *val,
 				      size_t size)
 {
 	return snprintf(val, size, "%lld", ci->i_files);
 }
 
-static size_t ceph_vxattrcb_subdirs(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_subdirs(struct ceph_inode_info *ci, char *val,
 					size_t size)
 {
 	return snprintf(val, size, "%lld", ci->i_subdirs);
 }
 
-static size_t ceph_vxattrcb_rentries(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_rentries(struct ceph_inode_info *ci, char *val,
 					 size_t size)
 {
 	return snprintf(val, size, "%lld", ci->i_rfiles + ci->i_rsubdirs);
 }
 
-static size_t ceph_vxattrcb_rfiles(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_rfiles(struct ceph_inode_info *ci, char *val,
 				       size_t size)
 {
 	return snprintf(val, size, "%lld", ci->i_rfiles);
 }
 
-static size_t ceph_vxattrcb_rsubdirs(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_rsubdirs(struct ceph_inode_info *ci, char *val,
 					 size_t size)
 {
 	return snprintf(val, size, "%lld", ci->i_rsubdirs);
 }
 
-static size_t ceph_vxattrcb_rbytes(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_rbytes(struct ceph_inode_info *ci, char *val,
 				       size_t size)
 {
 	return snprintf(val, size, "%lld", ci->i_rbytes);
 }
 
-static size_t ceph_vxattrcb_rctime(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_rctime(struct ceph_inode_info *ci, char *val,
 				       size_t size)
 {
-	return snprintf(val, size, "%ld.%ld", (long)ci->i_rctime.tv_sec,
+	return snprintf(val, size, "%ld.09%ld", (long)ci->i_rctime.tv_sec,
 			(long)ci->i_rctime.tv_nsec);
 }
 
-static struct ceph_vxattr_cb ceph_dir_vxattrs[] = {
-	{ true, "ceph.dir.entries", ceph_vxattrcb_entries},
-	{ true, "ceph.dir.files", ceph_vxattrcb_files},
-	{ true, "ceph.dir.subdirs", ceph_vxattrcb_subdirs},
-	{ true, "ceph.dir.rentries", ceph_vxattrcb_rentries},
-	{ true, "ceph.dir.rfiles", ceph_vxattrcb_rfiles},
-	{ true, "ceph.dir.rsubdirs", ceph_vxattrcb_rsubdirs},
-	{ true, "ceph.dir.rbytes", ceph_vxattrcb_rbytes},
-	{ true, "ceph.dir.rctime", ceph_vxattrcb_rctime},
-	{ true, NULL, NULL }
+#define CEPH_XATTR_NAME(_type, _name)	XATTR_CEPH_PREFIX #_type "." #_name
+
+#define XATTR_NAME_CEPH(_type, _name) \
+		{ \
+			.name = CEPH_XATTR_NAME(_type, _name), \
+			.name_size = sizeof (CEPH_XATTR_NAME(_type, _name)), \
+			.getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name, \
+			.readonly = true, \
+		}
+
+static struct ceph_vxattr ceph_dir_vxattrs[] = {
+	XATTR_NAME_CEPH(dir, entries),
+	XATTR_NAME_CEPH(dir, files),
+	XATTR_NAME_CEPH(dir, subdirs),
+	XATTR_NAME_CEPH(dir, rentries),
+	XATTR_NAME_CEPH(dir, rfiles),
+	XATTR_NAME_CEPH(dir, rsubdirs),
+	XATTR_NAME_CEPH(dir, rbytes),
+	XATTR_NAME_CEPH(dir, rctime),
+	{ 0 }	/* Required table terminator */
 };
+static size_t ceph_dir_vxattrs_name_size;	/* total size of all names */
 
 /* files */
 
-static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_file_layout(struct ceph_inode_info *ci, char *val,
 				   size_t size)
 {
 	int ret;
@@ -103,21 +118,32 @@
 		(unsigned long long)ceph_file_layout_su(ci->i_layout),
 		(unsigned long long)ceph_file_layout_stripe_count(ci->i_layout),
 		(unsigned long long)ceph_file_layout_object_size(ci->i_layout));
-	if (ceph_file_layout_pg_preferred(ci->i_layout))
-		ret += snprintf(val + ret, size, "preferred_osd=%lld\n",
+
+	if (ceph_file_layout_pg_preferred(ci->i_layout) >= 0) {
+		val += ret;
+		size -= ret;
+		ret += snprintf(val, size, "preferred_osd=%lld\n",
 			    (unsigned long long)ceph_file_layout_pg_preferred(
 				    ci->i_layout));
+	}
+
 	return ret;
 }
 
-static struct ceph_vxattr_cb ceph_file_vxattrs[] = {
-	{ true, "ceph.file.layout", ceph_vxattrcb_layout},
+static struct ceph_vxattr ceph_file_vxattrs[] = {
+	XATTR_NAME_CEPH(file, layout),
 	/* The following extended attribute name is deprecated */
-	{ true, "ceph.layout", ceph_vxattrcb_layout},
-	{ true, NULL, NULL }
+	{
+		.name = XATTR_CEPH_PREFIX "layout",
+		.name_size = sizeof (XATTR_CEPH_PREFIX "layout"),
+		.getxattr_cb = ceph_vxattrcb_file_layout,
+		.readonly = true,
+	},
+	{ 0 }	/* Required table terminator */
 };
+static size_t ceph_file_vxattrs_name_size;	/* total size of all names */
 
-static struct ceph_vxattr_cb *ceph_inode_vxattrs(struct inode *inode)
+static struct ceph_vxattr *ceph_inode_vxattrs(struct inode *inode)
 {
 	if (S_ISDIR(inode->i_mode))
 		return ceph_dir_vxattrs;
@@ -126,14 +152,59 @@
 	return NULL;
 }
 
-static struct ceph_vxattr_cb *ceph_match_vxattr(struct ceph_vxattr_cb *vxattr,
+static size_t ceph_vxattrs_name_size(struct ceph_vxattr *vxattrs)
+{
+	if (vxattrs == ceph_dir_vxattrs)
+		return ceph_dir_vxattrs_name_size;
+	if (vxattrs == ceph_file_vxattrs)
+		return ceph_file_vxattrs_name_size;
+	BUG();
+
+	return 0;
+}
+
+/*
+ * Compute the aggregate size (including terminating '\0') of all
+ * virtual extended attribute names in the given vxattr table.
+ */
+static size_t __init vxattrs_name_size(struct ceph_vxattr *vxattrs)
+{
+	struct ceph_vxattr *vxattr;
+	size_t size = 0;
+
+	for (vxattr = vxattrs; vxattr->name; vxattr++)
+		size += vxattr->name_size;
+
+	return size;
+}
+
+/* Routines called at initialization and exit time */
+
+void __init ceph_xattr_init(void)
+{
+	ceph_dir_vxattrs_name_size = vxattrs_name_size(ceph_dir_vxattrs);
+	ceph_file_vxattrs_name_size = vxattrs_name_size(ceph_file_vxattrs);
+}
+
+void ceph_xattr_exit(void)
+{
+	ceph_dir_vxattrs_name_size = 0;
+	ceph_file_vxattrs_name_size = 0;
+}
+
+static struct ceph_vxattr *ceph_match_vxattr(struct inode *inode,
 						const char *name)
 {
-	do {
-		if (strcmp(vxattr->name, name) == 0)
-			return vxattr;
-		vxattr++;
-	} while (vxattr->name);
+	struct ceph_vxattr *vxattr = ceph_inode_vxattrs(inode);
+
+	if (vxattr) {
+		while (vxattr->name) {
+			if (!strcmp(vxattr->name, name))
+				return vxattr;
+			vxattr++;
+		}
+	}
+
 	return NULL;
 }
 
@@ -502,17 +573,15 @@
 {
 	struct inode *inode = dentry->d_inode;
 	struct ceph_inode_info *ci = ceph_inode(inode);
-	struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
 	int err;
 	struct ceph_inode_xattr *xattr;
-	struct ceph_vxattr_cb *vxattr = NULL;
+	struct ceph_vxattr *vxattr = NULL;
 
 	if (!ceph_is_valid_xattr(name))
 		return -ENODATA;
 
 	/* let's see if a virtual xattr was requested */
-	if (vxattrs)
-		vxattr = ceph_match_vxattr(vxattrs, name);
+	vxattr = ceph_match_vxattr(inode, name);
 
 	spin_lock(&ci->i_ceph_lock);
 	dout("getxattr %p ver=%lld index_ver=%lld\n", inode,
@@ -568,7 +637,7 @@
 {
 	struct inode *inode = dentry->d_inode;
 	struct ceph_inode_info *ci = ceph_inode(inode);
-	struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
+	struct ceph_vxattr *vxattrs = ceph_inode_vxattrs(inode);
 	u32 vir_namelen = 0;
 	u32 namelen;
 	int err;
@@ -596,11 +665,12 @@
 		goto out;
 
 list_xattr:
-	vir_namelen = 0;
-	/* include virtual dir xattrs */
-	if (vxattrs)
-		for (i = 0; vxattrs[i].name; i++)
-			vir_namelen += strlen(vxattrs[i].name) + 1;
+	/*
+	 * Start with virtual dir xattr names (if any) (including
+	 * terminating '\0' characters for each).
+	 */
+	vir_namelen = ceph_vxattrs_name_size(vxattrs);
+
 	/* adding 1 byte per each variable due to the null termination */
 	namelen = vir_namelen + ci->i_xattrs.names_size + ci->i_xattrs.count;
 	err = -ERANGE;
@@ -698,17 +768,17 @@
 		  const void *value, size_t size, int flags)
 {
 	struct inode *inode = dentry->d_inode;
+	struct ceph_vxattr *vxattr;
 	struct ceph_inode_info *ci = ceph_inode(inode);
-	struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
+	int issued;
 	int err;
+	int dirty;
 	int name_len = strlen(name);
 	int val_len = size;
 	char *newname = NULL;
 	char *newval = NULL;
 	struct ceph_inode_xattr *xattr = NULL;
-	int issued;
 	int required_blob_size;
-	int dirty;
 
 	if (ceph_snap(inode) != CEPH_NOSNAP)
 		return -EROFS;
@@ -716,12 +786,9 @@
 	if (!ceph_is_valid_xattr(name))
 		return -EOPNOTSUPP;
 
-	if (vxattrs) {
-		struct ceph_vxattr_cb *vxattr =
-			ceph_match_vxattr(vxattrs, name);
-		if (vxattr && vxattr->readonly)
-			return -EOPNOTSUPP;
-	}
+	vxattr = ceph_match_vxattr(inode, name);
+	if (vxattr && vxattr->readonly)
+		return -EOPNOTSUPP;
 
 	/* preallocate memory for xattr name, value, index node */
 	err = -ENOMEM;
@@ -730,11 +797,9 @@
 		goto out;
 
 	if (val_len) {
-		newval = kmalloc(val_len + 1, GFP_NOFS);
+		newval = kmemdup(value, val_len, GFP_NOFS);
 		if (!newval)
 			goto out;
-		memcpy(newval, value, val_len);
-		newval[val_len] = '\0';
 	}
 
 	xattr = kmalloc(sizeof(struct ceph_inode_xattr), GFP_NOFS);
@@ -744,6 +809,7 @@
 	spin_lock(&ci->i_ceph_lock);
 retry:
 	issued = __ceph_caps_issued(ci, NULL);
+	dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued));
 	if (!(issued & CEPH_CAP_XATTR_EXCL))
 		goto do_sync;
 	__build_xattrs(inode);
@@ -752,7 +818,7 @@
 
 	if (!ci->i_xattrs.prealloc_blob ||
 	    required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {
-		struct ceph_buffer *blob = NULL;
+		struct ceph_buffer *blob;
 
 		spin_unlock(&ci->i_ceph_lock);
 		dout(" preaallocating new blob size=%d\n", required_blob_size);
@@ -766,12 +832,13 @@
 		goto retry;
 	}
 
-	dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued));
 	err = __set_xattr(ci, newname, name_len, newval,
 			  val_len, 1, 1, 1, &xattr);
+
 	dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
 	ci->i_xattrs.dirty = true;
 	inode->i_ctime = CURRENT_TIME;
+
 	spin_unlock(&ci->i_ceph_lock);
 	if (dirty)
 		__mark_inode_dirty(inode, dirty);
@@ -816,8 +883,8 @@
 int ceph_removexattr(struct dentry *dentry, const char *name)
 {
 	struct inode *inode = dentry->d_inode;
+	struct ceph_vxattr *vxattr;
 	struct ceph_inode_info *ci = ceph_inode(inode);
-	struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
 	int issued;
 	int err;
 	int required_blob_size;
@@ -829,22 +896,19 @@
 	if (!ceph_is_valid_xattr(name))
 		return -EOPNOTSUPP;
 
-	if (vxattrs) {
-		struct ceph_vxattr_cb *vxattr =
-			ceph_match_vxattr(vxattrs, name);
-		if (vxattr && vxattr->readonly)
-			return -EOPNOTSUPP;
-	}
+	vxattr = ceph_match_vxattr(inode, name);
+	if (vxattr && vxattr->readonly)
+		return -EOPNOTSUPP;
 
 	err = -ENOMEM;
 	spin_lock(&ci->i_ceph_lock);
-	__build_xattrs(inode);
 retry:
 	issued = __ceph_caps_issued(ci, NULL);
 	dout("removexattr %p issued %s\n", inode, ceph_cap_string(issued));
 
 	if (!(issued & CEPH_CAP_XATTR_EXCL))
 		goto do_sync;
+	__build_xattrs(inode);
 
 	required_blob_size = __get_required_blob_size(ci, 0, 0);
 
@@ -865,10 +929,10 @@
 	}
 
 	err = __remove_xattr_by_name(ceph_inode(inode), name);
+
 	dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
 	ci->i_xattrs.dirty = true;
 	inode->i_ctime = CURRENT_TIME;
-
 	spin_unlock(&ci->i_ceph_lock);
 	if (dirty)
 		__mark_inode_dirty(inode, dirty);
diff --git a/fs/cifs/README b/fs/cifs/README
index 895da1d..b7d782b 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -753,10 +753,6 @@
 
 i.e. echo "value" > /sys/module/cifs/parameters/<param>
 
-1. echo_retries - The number of echo attempts before giving up and
-		  reconnecting to the server. The default is 5. The value 0
-		  means never reconnect.
-
-2. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default.
+1. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default.
 		    [Y/y/1]. To disable use any of [N/n/0].
 
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 24b3dfc..2704646 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -58,15 +58,16 @@
 }
 
 #ifdef CONFIG_CIFS_DEBUG2
-void cifs_dump_detail(struct smb_hdr *smb)
+void cifs_dump_detail(void *buf)
 {
+	struct smb_hdr *smb = (struct smb_hdr *)buf;
+
 	cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d",
 		  smb->Command, smb->Status.CifsError,
 		  smb->Flags, smb->Flags2, smb->Mid, smb->Pid);
 	cERROR(1, "smb buf %p len %d", smb, smbCalcSize(smb));
 }
 
-
 void cifs_dump_mids(struct TCP_Server_Info *server)
 {
 	struct list_head *tmp;
@@ -79,15 +80,15 @@
 	spin_lock(&GlobalMid_Lock);
 	list_for_each(tmp, &server->pending_mid_q) {
 		mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-		cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %d",
-			mid_entry->midState,
-			(int)mid_entry->command,
+		cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %llu",
+			mid_entry->mid_state,
+			le16_to_cpu(mid_entry->command),
 			mid_entry->pid,
 			mid_entry->callback_data,
 			mid_entry->mid);
 #ifdef CONFIG_CIFS_STATS2
 		cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld",
-			mid_entry->largeBuf,
+			mid_entry->large_buf,
 			mid_entry->resp_buf,
 			mid_entry->when_received,
 			jiffies);
@@ -171,8 +172,7 @@
 			seq_printf(m, "TCP status: %d\n\tLocal Users To "
 				   "Server: %d SecMode: 0x%x Req On Wire: %d",
 				   server->tcpStatus, server->srv_count,
-				   server->sec_mode,
-				   atomic_read(&server->inFlight));
+				   server->sec_mode, in_flight(server));
 
 #ifdef CONFIG_CIFS_STATS2
 			seq_printf(m, " In Send: %d In MaxReq Wait: %d",
@@ -218,12 +218,12 @@
 				mid_entry = list_entry(tmp3, struct mid_q_entry,
 					qhead);
 				seq_printf(m, "\tState: %d com: %d pid:"
-						" %d cbdata: %p mid %d\n",
-						mid_entry->midState,
-						(int)mid_entry->command,
-						mid_entry->pid,
-						mid_entry->callback_data,
-						mid_entry->mid);
+					      " %d cbdata: %p mid %llu\n",
+					      mid_entry->mid_state,
+					      le16_to_cpu(mid_entry->command),
+					      mid_entry->pid,
+					      mid_entry->callback_data,
+					      mid_entry->mid);
 			}
 			spin_unlock(&GlobalMid_Lock);
 		}
@@ -418,7 +418,6 @@
 
 static struct proc_dir_entry *proc_fs_cifs;
 static const struct file_operations cifsFYI_proc_fops;
-static const struct file_operations cifs_oplock_proc_fops;
 static const struct file_operations cifs_lookup_cache_proc_fops;
 static const struct file_operations traceSMB_proc_fops;
 static const struct file_operations cifs_multiuser_mount_proc_fops;
@@ -439,7 +438,6 @@
 #endif /* STATS */
 	proc_create("cifsFYI", 0, proc_fs_cifs, &cifsFYI_proc_fops);
 	proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops);
-	proc_create("OplockEnabled", 0, proc_fs_cifs, &cifs_oplock_proc_fops);
 	proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs,
 		    &cifs_linux_ext_proc_fops);
 	proc_create("MultiuserMount", 0, proc_fs_cifs,
@@ -463,7 +461,6 @@
 	remove_proc_entry("Stats", proc_fs_cifs);
 #endif
 	remove_proc_entry("MultiuserMount", proc_fs_cifs);
-	remove_proc_entry("OplockEnabled", proc_fs_cifs);
 	remove_proc_entry("SecurityFlags", proc_fs_cifs);
 	remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
 	remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
@@ -509,46 +506,6 @@
 	.write		= cifsFYI_proc_write,
 };
 
-static int cifs_oplock_proc_show(struct seq_file *m, void *v)
-{
-	seq_printf(m, "%d\n", enable_oplocks);
-	return 0;
-}
-
-static int cifs_oplock_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, cifs_oplock_proc_show, NULL);
-}
-
-static ssize_t cifs_oplock_proc_write(struct file *file,
-		const char __user *buffer, size_t count, loff_t *ppos)
-{
-	char c;
-	int rc;
-
-	printk(KERN_WARNING "CIFS: The /proc/fs/cifs/OplockEnabled interface "
-	       "will be removed in kernel version 3.4. Please migrate to "
-	       "using the 'enable_oplocks' module parameter in cifs.ko.\n");
-	rc = get_user(c, buffer);
-	if (rc)
-		return rc;
-	if (c == '0' || c == 'n' || c == 'N')
-		enable_oplocks = false;
-	else if (c == '1' || c == 'y' || c == 'Y')
-		enable_oplocks = true;
-
-	return count;
-}
-
-static const struct file_operations cifs_oplock_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= cifs_oplock_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-	.write		= cifs_oplock_proc_write,
-};
-
 static int cifs_linux_ext_proc_show(struct seq_file *m, void *v)
 {
 	seq_printf(m, "%d\n", linuxExtEnabled);
diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h
index 8942b28..566e0ae 100644
--- a/fs/cifs/cifs_debug.h
+++ b/fs/cifs/cifs_debug.h
@@ -26,13 +26,13 @@
 void cifs_dump_mem(char *label, void *data, int length);
 #ifdef CONFIG_CIFS_DEBUG2
 #define DBG2 2
-void cifs_dump_detail(struct smb_hdr *);
+void cifs_dump_detail(void *);
 void cifs_dump_mids(struct TCP_Server_Info *);
 #else
 #define DBG2 0
 #endif
 extern int traceSMB;		/* flag which enables the function below */
-void dump_smb(struct smb_hdr *, int);
+void dump_smb(void *, int);
 #define CIFS_INFO	0x01
 #define CIFS_RC		0x02
 #define CIFS_TIMER	0x04
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index b1fd382..d342128 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -76,12 +76,7 @@
 unsigned int cifs_max_pending = CIFS_MAX_REQ;
 module_param(cifs_max_pending, int, 0444);
 MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
-				   "Default: 50 Range: 2 to 256");
-unsigned short echo_retries = 5;
-module_param(echo_retries, ushort, 0644);
-MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and "
-			       "reconnecting server. Default: 5. 0 means "
-			       "never reconnect.");
+				   "Default: 32767 Range: 2 to 32767.");
 module_param(enable_oplocks, bool, 0644);
 MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:"
 				 "y/Y/1");
@@ -90,6 +85,8 @@
 extern mempool_t *cifs_req_poolp;
 extern mempool_t *cifs_mid_poolp;
 
+struct workqueue_struct	*cifsiod_wq;
+
 static int
 cifs_read_super(struct super_block *sb)
 {
@@ -119,12 +116,10 @@
 
 	if (IS_ERR(inode)) {
 		rc = PTR_ERR(inode);
-		inode = NULL;
 		goto out_no_root;
 	}
 
-	sb->s_root = d_alloc_root(inode);
-
+	sb->s_root = d_make_root(inode);
 	if (!sb->s_root) {
 		rc = -ENOMEM;
 		goto out_no_root;
@@ -147,9 +142,6 @@
 
 out_no_root:
 	cERROR(1, "cifs_read_super: get root inode failed");
-	if (inode)
-		iput(inode);
-
 	return rc;
 }
 
@@ -1116,14 +1108,20 @@
 	if (cifs_max_pending < 2) {
 		cifs_max_pending = 2;
 		cFYI(1, "cifs_max_pending set to min of 2");
-	} else if (cifs_max_pending > 256) {
-		cifs_max_pending = 256;
-		cFYI(1, "cifs_max_pending set to max of 256");
+	} else if (cifs_max_pending > CIFS_MAX_REQ) {
+		cifs_max_pending = CIFS_MAX_REQ;
+		cFYI(1, "cifs_max_pending set to max of %u", CIFS_MAX_REQ);
+	}
+
+	cifsiod_wq = alloc_workqueue("cifsiod", WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
+	if (!cifsiod_wq) {
+		rc = -ENOMEM;
+		goto out_clean_proc;
 	}
 
 	rc = cifs_fscache_register();
 	if (rc)
-		goto out_clean_proc;
+		goto out_destroy_wq;
 
 	rc = cifs_init_inodecache();
 	if (rc)
@@ -1171,6 +1169,8 @@
 	cifs_destroy_inodecache();
 out_unreg_fscache:
 	cifs_fscache_unregister();
+out_destroy_wq:
+	destroy_workqueue(cifsiod_wq);
 out_clean_proc:
 	cifs_proc_clean();
 	return rc;
@@ -1180,11 +1180,8 @@
 exit_cifs(void)
 {
 	cFYI(DBG2, "exit_cifs");
-	cifs_proc_clean();
-	cifs_fscache_unregister();
-#ifdef CONFIG_CIFS_DFS_UPCALL
+	unregister_filesystem(&cifs_fs_type);
 	cifs_dfs_release_automount_timer();
-#endif
 #ifdef CONFIG_CIFS_ACL
 	cifs_destroy_idmaptrees();
 	exit_cifs_idmap();
@@ -1192,10 +1189,12 @@
 #ifdef CONFIG_CIFS_UPCALL
 	unregister_key_type(&cifs_spnego_key_type);
 #endif
-	unregister_filesystem(&cifs_fs_type);
-	cifs_destroy_inodecache();
-	cifs_destroy_mids();
 	cifs_destroy_request_bufs();
+	cifs_destroy_mids();
+	cifs_destroy_inodecache();
+	cifs_fscache_unregister();
+	destroy_workqueue(cifsiod_wq);
+	cifs_proc_clean();
 }
 
 MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index fe5ecf1..d1389bb 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -125,5 +125,5 @@
 extern const struct export_operations cifs_export_ops;
 #endif /* CONFIG_CIFS_NFSD_EXPORT */
 
-#define CIFS_VERSION   "1.76"
+#define CIFS_VERSION   "1.77"
 #endif				/* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 76e7d8b..4ff6313 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -55,14 +55,9 @@
 
 /*
  * MAX_REQ is the maximum number of requests that WE will send
- * on one socket concurrently. It also matches the most common
- * value of max multiplex returned by servers.  We may
- * eventually want to use the negotiated value (in case
- * future servers can handle more) when we are more confident that
- * we will not have problems oveloading the socket with pending
- * write data.
+ * on one socket concurrently.
  */
-#define CIFS_MAX_REQ 50
+#define CIFS_MAX_REQ 32767
 
 #define RFC1001_NAME_LEN 15
 #define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1)
@@ -235,6 +230,12 @@
 	int flags;
 };
 
+static inline unsigned int
+get_rfc1002_length(void *buf)
+{
+	return be32_to_cpu(*((__be32 *)buf));
+}
+
 struct TCP_Server_Info {
 	struct list_head tcp_ses_list;
 	struct list_head smb_ses_list;
@@ -255,7 +256,9 @@
 	bool noblocksnd;		/* use blocking sendmsg */
 	bool noautotune;		/* do not autotune send buf sizes */
 	bool tcp_nodelay;
-	atomic_t inFlight;  /* number of requests on the wire to server */
+	int credits;  /* send no more requests at once */
+	unsigned int in_flight;  /* number of requests on the wire to server */
+	spinlock_t req_lock;  /* protect the two values above */
 	struct mutex srv_mutex;
 	struct task_struct *tsk;
 	char server_GUID[16];
@@ -263,6 +266,7 @@
 	bool session_estab; /* mark when very first sess is established */
 	u16 dialect; /* dialect index that server chose */
 	enum securityEnum secType;
+	bool oplocks:1; /* enable oplocks */
 	unsigned int maxReq;	/* Clients should submit no more */
 	/* than maxReq distinct unanswered SMBs to the server when using  */
 	/* multiplexed reads or writes */
@@ -278,7 +282,7 @@
 				   vcnumbers */
 	int capabilities; /* allow selective disabling of caps by smb sess */
 	int timeAdj;  /* Adjust for difference in server time zone in sec */
-	__u16 CurrentMid;         /* multiplex id - rotating counter */
+	__u64 CurrentMid;         /* multiplex id - rotating counter */
 	char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */
 	/* 16th byte of RFC1001 workstation name is always null */
 	char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
@@ -307,6 +311,48 @@
 #endif
 };
 
+static inline unsigned int
+in_flight(struct TCP_Server_Info *server)
+{
+	unsigned int num;
+	spin_lock(&server->req_lock);
+	num = server->in_flight;
+	spin_unlock(&server->req_lock);
+	return num;
+}
+
+static inline int*
+get_credits_field(struct TCP_Server_Info *server)
+{
+	/*
+	 * This will change to switch statement when we reserve slots for echos
+	 * and oplock breaks.
+	 */
+	return &server->credits;
+}
+
+static inline bool
+has_credits(struct TCP_Server_Info *server, int *credits)
+{
+	int num;
+	spin_lock(&server->req_lock);
+	num = *credits;
+	spin_unlock(&server->req_lock);
+	return num > 0;
+}
+
+static inline size_t
+header_size(void)
+{
+	return sizeof(struct smb_hdr);
+}
+
+static inline size_t
+max_header_size(void)
+{
+	return MAX_CIFS_HDR_SIZE;
+}
+
 /*
  * Macros to allow the TCP_Server_Info->net field and related code to drop out
  * when CONFIG_NET_NS isn't set.
@@ -555,9 +601,11 @@
  * Take a reference on the file private data. Must be called with
  * cifs_file_list_lock held.
  */
-static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file)
+static inline
+struct cifsFileInfo *cifsFileInfo_get(struct cifsFileInfo *cifs_file)
 {
 	++cifs_file->count;
+	return cifs_file;
 }
 
 void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
@@ -578,7 +626,7 @@
 	bool delete_pending;		/* DELETE_ON_CLOSE is set */
 	bool invalid_mapping;		/* pagecache is invalid */
 	unsigned long time;		/* jiffies of last update of inode */
-	u64  server_eof;		/* current file size on server */
+	u64  server_eof;		/* current file size on server -- protected by i_lock */
 	u64  uniqueid;			/* server inode number */
 	u64  createtime;		/* creation time on server */
 #ifdef CONFIG_CIFS_FSCACHE
@@ -685,8 +733,8 @@
 /* one of these for every pending CIFS request to the server */
 struct mid_q_entry {
 	struct list_head qhead;	/* mids waiting on reply from this server */
-	__u16 mid;		/* multiplex id */
-	__u16 pid;		/* process id */
+	__u64 mid;		/* multiplex id */
+	__u32 pid;		/* process id */
 	__u32 sequence_number;  /* for CIFS signing */
 	unsigned long when_alloc;  /* when mid was created */
 #ifdef CONFIG_CIFS_STATS2
@@ -696,10 +744,10 @@
 	mid_receive_t *receive; /* call receive callback */
 	mid_callback_t *callback; /* call completion callback */
 	void *callback_data;	  /* general purpose pointer for callback */
-	struct smb_hdr *resp_buf;	/* pointer to received SMB header */
-	int midState;	/* wish this were enum but can not pass to wait_event */
-	__u8 command;	/* smb command code */
-	bool largeBuf:1;	/* if valid response, is pointer to large buf */
+	void *resp_buf;		/* pointer to received SMB header */
+	int mid_state;	/* wish this were enum but can not pass to wait_event */
+	__le16 command;		/* smb command code */
+	bool large_buf:1;	/* if valid response, is pointer to large buf */
 	bool multiRsp:1;	/* multiple trans2 responses for one request  */
 	bool multiEnd:1;	/* both received */
 };
@@ -1010,9 +1058,6 @@
 GLOBAL_EXTERN unsigned int cifs_min_small;  /* min size of small buf pool */
 GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
 
-/* reconnect after this many failed echo attempts */
-GLOBAL_EXTERN unsigned short echo_retries;
-
 #ifdef CONFIG_CIFS_ACL
 GLOBAL_EXTERN struct rb_root uidtree;
 GLOBAL_EXTERN struct rb_root gidtree;
@@ -1027,5 +1072,6 @@
 void cifs_oplock_break(struct work_struct *work);
 
 extern const struct slow_work_ops cifs_oplock_break_ops;
+extern struct workqueue_struct *cifsiod_wq;
 
 #endif	/* _CIFS_GLOB_H */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 6f4e243..96192c1 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -77,7 +77,7 @@
 			struct smb_hdr * /* out */ ,
 			int * /* bytes returned */ , const int long_op);
 extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
-			struct smb_hdr *in_buf, int flags);
+			    char *in_buf, int flags);
 extern int cifs_check_receive(struct mid_q_entry *mid,
 			struct TCP_Server_Info *server, bool log_error);
 extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
@@ -88,9 +88,11 @@
 			struct smb_hdr *in_buf ,
 			struct smb_hdr *out_buf,
 			int *bytes_returned);
-extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
-extern bool is_valid_oplock_break(struct smb_hdr *smb,
-				  struct TCP_Server_Info *);
+extern void cifs_add_credits(struct TCP_Server_Info *server,
+			     const unsigned int add);
+extern void cifs_set_credits(struct TCP_Server_Info *server, const int val);
+extern int checkSMB(char *buf, unsigned int length);
+extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *);
 extern bool backup_cred(struct cifs_sb_info *);
 extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
 extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
@@ -104,7 +106,7 @@
 extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port);
 extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
 				const unsigned short int port);
-extern int map_smb_to_linux_error(struct smb_hdr *smb, bool logErr);
+extern int map_smb_to_linux_error(char *buf, bool logErr);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
 			    const struct cifs_tcon *, int /* length of
 			    fixed section (word count) in two byte units */);
@@ -113,7 +115,7 @@
 				void **request_buf);
 extern int CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses,
 			     const struct nls_table *nls_cp);
-extern __u16 GetNextMid(struct TCP_Server_Info *server);
+extern __u64 GetNextMid(struct TCP_Server_Info *server);
 extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
 extern u64 cifs_UnixTimeToNT(struct timespec);
 extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
@@ -168,7 +170,13 @@
 					    const char *devname);
 extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *);
 extern void cifs_umount(struct cifs_sb_info *);
+
+#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
 extern void cifs_dfs_release_automount_timer(void);
+#else /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */
+#define cifs_dfs_release_automount_timer()	do { } while (0)
+#endif /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */
+
 void cifs_proc_init(void);
 void cifs_proc_clean(void);
 
@@ -475,18 +483,25 @@
 /* asynchronous write support */
 struct cifs_writedata {
 	struct kref			refcount;
+	struct list_head		list;
+	struct completion		done;
 	enum writeback_sync_modes	sync_mode;
 	struct work_struct		work;
 	struct cifsFileInfo		*cfile;
 	__u64				offset;
+	pid_t				pid;
 	unsigned int			bytes;
 	int				result;
+	void (*marshal_iov) (struct kvec *iov,
+			     struct cifs_writedata *wdata);
 	unsigned int			nr_pages;
 	struct page			*pages[1];
 };
 
 int cifs_async_writev(struct cifs_writedata *wdata);
-struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages);
+void cifs_writev_complete(struct work_struct *work);
+struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
+						work_func_t complete);
 void cifs_writedata_release(struct kref *refcount);
 
 #endif			/* _CIFSPROTO_H */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 8b7794c..f52c5ab 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -458,7 +458,10 @@
 			goto neg_err_exit;
 		}
 		server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
-		server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
+		server->maxReq = min_t(unsigned int,
+				       le16_to_cpu(rsp->MaxMpxCount),
+				       cifs_max_pending);
+		cifs_set_credits(server, server->maxReq);
 		server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
 		server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
 		/* even though we do not use raw we might as well set this
@@ -564,7 +567,9 @@
 
 	/* one byte, so no need to convert this or EncryptionKeyLen from
 	   little endian */
-	server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
+	server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
+			       cifs_max_pending);
+	cifs_set_credits(server, server->maxReq);
 	/* probably no need to store and check maxvcs */
 	server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
 	server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
@@ -691,7 +696,7 @@
 	if (rc)
 		return rc;
 
-	rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
 	if (rc)
 		cFYI(1, "Tree disconnect failed %d", rc);
 
@@ -716,8 +721,7 @@
 	struct TCP_Server_Info *server = mid->callback_data;
 
 	DeleteMidQEntry(mid);
-	atomic_dec(&server->inFlight);
-	wake_up(&server->request_q);
+	cifs_add_credits(server, 1);
 }
 
 int
@@ -788,7 +792,7 @@
 	pSMB->hdr.Uid = ses->Suid;
 
 	pSMB->AndXCommand = 0xFF;
-	rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
 session_already_dead:
 	mutex_unlock(&ses->session_mutex);
 
@@ -1410,8 +1414,7 @@
 static int
 cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 {
-	READ_RSP *rsp = (READ_RSP *)server->smallbuf;
-	unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length);
+	unsigned int rfclen = get_rfc1002_length(server->smallbuf);
 	int remaining = rfclen + 4 - server->total_read;
 	struct cifs_readdata *rdata = mid->callback_data;
 
@@ -1420,7 +1423,7 @@
 
 		length = cifs_read_from_socket(server, server->bigbuf,
 				min_t(unsigned int, remaining,
-					CIFSMaxBufSize + MAX_CIFS_HDR_SIZE));
+					CIFSMaxBufSize + max_header_size()));
 		if (length < 0)
 			return length;
 		server->total_read += length;
@@ -1431,19 +1434,40 @@
 	return 0;
 }
 
+static inline size_t
+read_rsp_size(void)
+{
+	return sizeof(READ_RSP);
+}
+
+static inline unsigned int
+read_data_offset(char *buf)
+{
+	READ_RSP *rsp = (READ_RSP *)buf;
+	return le16_to_cpu(rsp->DataOffset);
+}
+
+static inline unsigned int
+read_data_length(char *buf)
+{
+	READ_RSP *rsp = (READ_RSP *)buf;
+	return (le16_to_cpu(rsp->DataLengthHigh) << 16) +
+	       le16_to_cpu(rsp->DataLength);
+}
+
 static int
 cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 {
 	int length, len;
 	unsigned int data_offset, remaining, data_len;
 	struct cifs_readdata *rdata = mid->callback_data;
-	READ_RSP *rsp = (READ_RSP *)server->smallbuf;
-	unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length) + 4;
+	char *buf = server->smallbuf;
+	unsigned int buflen = get_rfc1002_length(buf) + 4;
 	u64 eof;
 	pgoff_t eof_index;
 	struct page *page, *tpage;
 
-	cFYI(1, "%s: mid=%u offset=%llu bytes=%u", __func__,
+	cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
 		mid->mid, rdata->offset, rdata->bytes);
 
 	/*
@@ -1451,10 +1475,9 @@
 	 * can if there's not enough data. At this point, we've read down to
 	 * the Mid.
 	 */
-	len = min_t(unsigned int, rfclen, sizeof(*rsp)) -
-			sizeof(struct smb_hdr) + 1;
+	len = min_t(unsigned int, buflen, read_rsp_size()) - header_size() + 1;
 
-	rdata->iov[0].iov_base = server->smallbuf + sizeof(struct smb_hdr) - 1;
+	rdata->iov[0].iov_base = buf + header_size() - 1;
 	rdata->iov[0].iov_len = len;
 
 	length = cifs_readv_from_socket(server, rdata->iov, 1, len);
@@ -1463,7 +1486,7 @@
 	server->total_read += length;
 
 	/* Was the SMB read successful? */
-	rdata->result = map_smb_to_linux_error(&rsp->hdr, false);
+	rdata->result = map_smb_to_linux_error(buf, false);
 	if (rdata->result != 0) {
 		cFYI(1, "%s: server returned error %d", __func__,
 			rdata->result);
@@ -1471,14 +1494,14 @@
 	}
 
 	/* Is there enough to get to the rest of the READ_RSP header? */
-	if (server->total_read < sizeof(READ_RSP)) {
+	if (server->total_read < read_rsp_size()) {
 		cFYI(1, "%s: server returned short header. got=%u expected=%zu",
-			__func__, server->total_read, sizeof(READ_RSP));
+			__func__, server->total_read, read_rsp_size());
 		rdata->result = -EIO;
 		return cifs_readv_discard(server, mid);
 	}
 
-	data_offset = le16_to_cpu(rsp->DataOffset) + 4;
+	data_offset = read_data_offset(buf) + 4;
 	if (data_offset < server->total_read) {
 		/*
 		 * win2k8 sometimes sends an offset of 0 when the read
@@ -1502,7 +1525,7 @@
 	len = data_offset - server->total_read;
 	if (len > 0) {
 		/* read any junk before data into the rest of smallbuf */
-		rdata->iov[0].iov_base = server->smallbuf + server->total_read;
+		rdata->iov[0].iov_base = buf + server->total_read;
 		rdata->iov[0].iov_len = len;
 		length = cifs_readv_from_socket(server, rdata->iov, 1, len);
 		if (length < 0)
@@ -1511,15 +1534,14 @@
 	}
 
 	/* set up first iov for signature check */
-	rdata->iov[0].iov_base = server->smallbuf;
+	rdata->iov[0].iov_base = buf;
 	rdata->iov[0].iov_len = server->total_read;
 	cFYI(1, "0: iov_base=%p iov_len=%zu",
 		rdata->iov[0].iov_base, rdata->iov[0].iov_len);
 
 	/* how much data is in the response? */
-	data_len = le16_to_cpu(rsp->DataLengthHigh) << 16;
-	data_len += le16_to_cpu(rsp->DataLength);
-	if (data_offset + data_len > rfclen) {
+	data_len = read_data_length(buf);
+	if (data_offset + data_len > buflen) {
 		/* data_len is corrupt -- discard frame */
 		rdata->result = -EIO;
 		return cifs_readv_discard(server, mid);
@@ -1598,11 +1620,11 @@
 
 	rdata->bytes = length;
 
-	cFYI(1, "total_read=%u rfclen=%u remaining=%u", server->total_read,
-		rfclen, remaining);
+	cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
+		buflen, remaining);
 
 	/* discard anything left over */
-	if (server->total_read < rfclen)
+	if (server->total_read < buflen)
 		return cifs_readv_discard(server, mid);
 
 	dequeue_mid(mid, false);
@@ -1643,10 +1665,10 @@
 	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
 	struct TCP_Server_Info *server = tcon->ses->server;
 
-	cFYI(1, "%s: mid=%u state=%d result=%d bytes=%u", __func__,
-		mid->mid, mid->midState, rdata->result, rdata->bytes);
+	cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
+		mid->mid, mid->mid_state, rdata->result, rdata->bytes);
 
-	switch (mid->midState) {
+	switch (mid->mid_state) {
 	case MID_RESPONSE_RECEIVED:
 		/* result already set, check signature */
 		if (server->sec_mode &
@@ -1667,10 +1689,9 @@
 		rdata->result = -EIO;
 	}
 
-	queue_work(system_nrt_wq, &rdata->work);
+	queue_work(cifsiod_wq, &rdata->work);
 	DeleteMidQEntry(mid);
-	atomic_dec(&server->inFlight);
-	wake_up(&server->request_q);
+	cifs_add_credits(server, 1);
 }
 
 /* cifs_async_readv - send an async write, and set up mid to handle result */
@@ -2014,7 +2035,7 @@
 	kref_put(&wdata->refcount, cifs_writedata_release);
 }
 
-static void
+void
 cifs_writev_complete(struct work_struct *work)
 {
 	struct cifs_writedata *wdata = container_of(work,
@@ -2023,7 +2044,9 @@
 	int i = 0;
 
 	if (wdata->result == 0) {
+		spin_lock(&inode->i_lock);
 		cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
+		spin_unlock(&inode->i_lock);
 		cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
 					 wdata->bytes);
 	} else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
@@ -2044,7 +2067,7 @@
 }
 
 struct cifs_writedata *
-cifs_writedata_alloc(unsigned int nr_pages)
+cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
 {
 	struct cifs_writedata *wdata;
 
@@ -2058,14 +2081,16 @@
 	wdata = kzalloc(sizeof(*wdata) +
 			sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
 	if (wdata != NULL) {
-		INIT_WORK(&wdata->work, cifs_writev_complete);
 		kref_init(&wdata->refcount);
+		INIT_LIST_HEAD(&wdata->list);
+		init_completion(&wdata->done);
+		INIT_WORK(&wdata->work, complete);
 	}
 	return wdata;
 }
 
 /*
- * Check the midState and signature on received buffer (if any), and queue the
+ * Check the mid_state and signature on received buffer (if any), and queue the
  * workqueue completion task.
  */
 static void
@@ -2076,7 +2101,7 @@
 	unsigned int written;
 	WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
 
-	switch (mid->midState) {
+	switch (mid->mid_state) {
 	case MID_RESPONSE_RECEIVED:
 		wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
 		if (wdata->result != 0)
@@ -2108,10 +2133,9 @@
 		break;
 	}
 
-	queue_work(system_nrt_wq, &wdata->work);
+	queue_work(cifsiod_wq, &wdata->work);
 	DeleteMidQEntry(mid);
-	atomic_dec(&tcon->ses->server->inFlight);
-	wake_up(&tcon->ses->server->request_q);
+	cifs_add_credits(tcon->ses->server, 1);
 }
 
 /* cifs_async_writev - send an async write, and set up mid to handle result */
@@ -2122,7 +2146,6 @@
 	WRITE_REQ *smb = NULL;
 	int wct;
 	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
-	struct inode *inode = wdata->cfile->dentry->d_inode;
 	struct kvec *iov = NULL;
 
 	if (tcon->ses->capabilities & CAP_LARGE_FILES) {
@@ -2146,8 +2169,8 @@
 		goto async_writev_out;
 	}
 
-	smb->hdr.Pid = cpu_to_le16((__u16)wdata->cfile->pid);
-	smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->cfile->pid >> 16));
+	smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
+	smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
 
 	smb->AndXCommand = 0xFF;	/* none */
 	smb->Fid = wdata->cfile->netfid;
@@ -2165,15 +2188,13 @@
 	iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
 	iov[0].iov_base = smb;
 
-	/* marshal up the pages into iov array */
-	wdata->bytes = 0;
-	for (i = 0; i < wdata->nr_pages; i++) {
-		iov[i + 1].iov_len = min(inode->i_size -
-				      page_offset(wdata->pages[i]),
-					(loff_t)PAGE_CACHE_SIZE);
-		iov[i + 1].iov_base = kmap(wdata->pages[i]);
-		wdata->bytes += iov[i + 1].iov_len;
-	}
+	/*
+	 * This function should marshal up the page array into the kvec
+	 * array, reserving [0] for the header. It should kmap the pages
+	 * and set the iov_len properly for each one. It may also set
+	 * wdata->bytes too.
+	 */
+	wdata->marshal_iov(iov, wdata);
 
 	cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
 
@@ -2418,8 +2439,7 @@
 			(struct smb_hdr *) pSMB, &bytes_returned);
 		cifs_small_buf_release(pSMB);
 	} else {
-		rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
-				      timeout);
+		rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, timeout);
 		/* SMB buffer freed by function above */
 	}
 	cifs_stats_inc(&tcon->num_locks);
@@ -2586,7 +2606,7 @@
 	pSMB->FileID = (__u16) smb_file_id;
 	pSMB->LastWriteTime = 0xFFFFFFFF;
 	pSMB->ByteCount = 0;
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 	cifs_stats_inc(&tcon->num_closes);
 	if (rc) {
 		if (rc != -EINTR) {
@@ -2615,7 +2635,7 @@
 
 	pSMB->FileID = (__u16) smb_file_id;
 	pSMB->ByteCount = 0;
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 	cifs_stats_inc(&tcon->num_flushes);
 	if (rc)
 		cERROR(1, "Send error in Flush = %d", rc);
@@ -3872,13 +3892,12 @@
 	int rc = 0;
 	int bytes_returned = 0;
 	SET_SEC_DESC_REQ *pSMB = NULL;
-	NTRANSACT_RSP *pSMBr = NULL;
+	void *pSMBr;
 
 setCifsAclRetry:
-	rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
-			(void **) &pSMBr);
+	rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
 	if (rc)
-			return (rc);
+		return rc;
 
 	pSMB->MaxSetupCount = 0;
 	pSMB->Reserved = 0;
@@ -3906,9 +3925,8 @@
 	pSMB->AclFlags = cpu_to_le32(aclflag);
 
 	if (pntsd && acllen) {
-		memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
-			(char *) pntsd,
-			acllen);
+		memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
+				data_offset, pntsd, acllen);
 		inc_rfc1001_len(pSMB, byte_count + data_count);
 	} else
 		inc_rfc1001_len(pSMB, byte_count);
@@ -4623,7 +4641,7 @@
 
 	pSMB->FileID = searchHandle;
 	pSMB->ByteCount = 0;
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 	if (rc)
 		cERROR(1, "Send error in FindClose = %d", rc);
 
@@ -5644,7 +5662,7 @@
 	pSMB->Reserved4 = 0;
 	inc_rfc1001_len(pSMB, byte_count);
 	pSMB->ByteCount = cpu_to_le16(byte_count);
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 	if (rc) {
 		cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
 	}
@@ -5688,7 +5706,8 @@
 	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
 	offset = param_offset + params;
 
-	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+	data_offset = (char *)pSMB +
+			offsetof(struct smb_hdr, Protocol) + offset;
 
 	count = sizeof(FILE_BASIC_INFO);
 	pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -5713,7 +5732,7 @@
 	inc_rfc1001_len(pSMB, byte_count);
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 	if (rc)
 		cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
 
@@ -5772,7 +5791,7 @@
 	inc_rfc1001_len(pSMB, byte_count);
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	*data_offset = delete_file ? 1 : 0;
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 	if (rc)
 		cFYI(1, "Send error in SetFileDisposition = %d", rc);
 
@@ -5957,7 +5976,7 @@
 		       u16 fid, u32 pid_of_opener)
 {
 	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
-	FILE_UNIX_BASIC_INFO *data_offset;
+	char *data_offset;
 	int rc = 0;
 	u16 params, param_offset, offset, byte_count, count;
 
@@ -5979,8 +5998,9 @@
 	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
 	offset = param_offset + params;
 
-	data_offset = (FILE_UNIX_BASIC_INFO *)
-				((char *)(&pSMB->hdr.Protocol) + offset);
+	data_offset = (char *)pSMB +
+			offsetof(struct smb_hdr, Protocol) + offset;
+
 	count = sizeof(FILE_UNIX_BASIC_INFO);
 
 	pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -6002,9 +6022,9 @@
 	inc_rfc1001_len(pSMB, byte_count);
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 
-	cifs_fill_unix_set_info(data_offset, args);
+	cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
 
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 	if (rc)
 		cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
 
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 602f77c..d81e933 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -40,6 +40,8 @@
 #include <linux/module.h>
 #include <keys/user-type.h>
 #include <net/ipv6.h>
+#include <linux/parser.h>
+
 #include "cifspdu.h"
 #include "cifsglob.h"
 #include "cifsproto.h"
@@ -63,6 +65,193 @@
 #define TLINK_ERROR_EXPIRE	(1 * HZ)
 #define TLINK_IDLE_EXPIRE	(600 * HZ)
 
+enum {
+
+	/* Mount options that take no arguments */
+	Opt_user_xattr, Opt_nouser_xattr,
+	Opt_forceuid, Opt_noforceuid,
+	Opt_noblocksend, Opt_noautotune,
+	Opt_hard, Opt_soft, Opt_perm, Opt_noperm,
+	Opt_mapchars, Opt_nomapchars, Opt_sfu,
+	Opt_nosfu, Opt_nodfs, Opt_posixpaths,
+	Opt_noposixpaths, Opt_nounix,
+	Opt_nocase,
+	Opt_brl, Opt_nobrl,
+	Opt_forcemandatorylock, Opt_setuids,
+	Opt_nosetuids, Opt_dynperm, Opt_nodynperm,
+	Opt_nohard, Opt_nosoft,
+	Opt_nointr, Opt_intr,
+	Opt_nostrictsync, Opt_strictsync,
+	Opt_serverino, Opt_noserverino,
+	Opt_rwpidforward, Opt_cifsacl, Opt_nocifsacl,
+	Opt_acl, Opt_noacl, Opt_locallease,
+	Opt_sign, Opt_seal, Opt_direct,
+	Opt_strictcache, Opt_noac,
+	Opt_fsc, Opt_mfsymlinks,
+	Opt_multiuser, Opt_sloppy,
+
+	/* Mount options which take numeric value */
+	Opt_backupuid, Opt_backupgid, Opt_uid,
+	Opt_cruid, Opt_gid, Opt_file_mode,
+	Opt_dirmode, Opt_port,
+	Opt_rsize, Opt_wsize, Opt_actimeo,
+
+	/* Mount options which take string value */
+	Opt_user, Opt_pass, Opt_ip,
+	Opt_unc, Opt_domain,
+	Opt_srcaddr, Opt_prefixpath,
+	Opt_iocharset, Opt_sockopt,
+	Opt_netbiosname, Opt_servern,
+	Opt_ver, Opt_sec,
+
+	/* Mount options to be ignored */
+	Opt_ignore,
+
+	/* Options which could be blank */
+	Opt_blank_pass,
+
+	Opt_err
+};
+
+static const match_table_t cifs_mount_option_tokens = {
+
+	{ Opt_user_xattr, "user_xattr" },
+	{ Opt_nouser_xattr, "nouser_xattr" },
+	{ Opt_forceuid, "forceuid" },
+	{ Opt_noforceuid, "noforceuid" },
+	{ Opt_noblocksend, "noblocksend" },
+	{ Opt_noautotune, "noautotune" },
+	{ Opt_hard, "hard" },
+	{ Opt_soft, "soft" },
+	{ Opt_perm, "perm" },
+	{ Opt_noperm, "noperm" },
+	{ Opt_mapchars, "mapchars" },
+	{ Opt_nomapchars, "nomapchars" },
+	{ Opt_sfu, "sfu" },
+	{ Opt_nosfu, "nosfu" },
+	{ Opt_nodfs, "nodfs" },
+	{ Opt_posixpaths, "posixpaths" },
+	{ Opt_noposixpaths, "noposixpaths" },
+	{ Opt_nounix, "nounix" },
+	{ Opt_nounix, "nolinux" },
+	{ Opt_nocase, "nocase" },
+	{ Opt_nocase, "ignorecase" },
+	{ Opt_brl, "brl" },
+	{ Opt_nobrl, "nobrl" },
+	{ Opt_nobrl, "nolock" },
+	{ Opt_forcemandatorylock, "forcemandatorylock" },
+	{ Opt_forcemandatorylock, "forcemand" },
+	{ Opt_setuids, "setuids" },
+	{ Opt_nosetuids, "nosetuids" },
+	{ Opt_dynperm, "dynperm" },
+	{ Opt_nodynperm, "nodynperm" },
+	{ Opt_nohard, "nohard" },
+	{ Opt_nosoft, "nosoft" },
+	{ Opt_nointr, "nointr" },
+	{ Opt_intr, "intr" },
+	{ Opt_nostrictsync, "nostrictsync" },
+	{ Opt_strictsync, "strictsync" },
+	{ Opt_serverino, "serverino" },
+	{ Opt_noserverino, "noserverino" },
+	{ Opt_rwpidforward, "rwpidforward" },
+	{ Opt_cifsacl, "cifsacl" },
+	{ Opt_nocifsacl, "nocifsacl" },
+	{ Opt_acl, "acl" },
+	{ Opt_noacl, "noacl" },
+	{ Opt_locallease, "locallease" },
+	{ Opt_sign, "sign" },
+	{ Opt_seal, "seal" },
+	{ Opt_direct, "direct" },
+	{ Opt_direct, "forceddirectio" },
+	{ Opt_strictcache, "strictcache" },
+	{ Opt_noac, "noac" },
+	{ Opt_fsc, "fsc" },
+	{ Opt_mfsymlinks, "mfsymlinks" },
+	{ Opt_multiuser, "multiuser" },
+	{ Opt_sloppy, "sloppy" },
+
+	{ Opt_backupuid, "backupuid=%s" },
+	{ Opt_backupgid, "backupgid=%s" },
+	{ Opt_uid, "uid=%s" },
+	{ Opt_cruid, "cruid=%s" },
+	{ Opt_gid, "gid=%s" },
+	{ Opt_file_mode, "file_mode=%s" },
+	{ Opt_dirmode, "dirmode=%s" },
+	{ Opt_dirmode, "dir_mode=%s" },
+	{ Opt_port, "port=%s" },
+	{ Opt_rsize, "rsize=%s" },
+	{ Opt_wsize, "wsize=%s" },
+	{ Opt_actimeo, "actimeo=%s" },
+
+	{ Opt_user, "user=%s" },
+	{ Opt_user, "username=%s" },
+	{ Opt_blank_pass, "pass=" },
+	{ Opt_pass, "pass=%s" },
+	{ Opt_pass, "password=%s" },
+	{ Opt_ip, "ip=%s" },
+	{ Opt_ip, "addr=%s" },
+	{ Opt_unc, "unc=%s" },
+	{ Opt_unc, "target=%s" },
+	{ Opt_unc, "path=%s" },
+	{ Opt_domain, "dom=%s" },
+	{ Opt_domain, "domain=%s" },
+	{ Opt_domain, "workgroup=%s" },
+	{ Opt_srcaddr, "srcaddr=%s" },
+	{ Opt_prefixpath, "prefixpath=%s" },
+	{ Opt_iocharset, "iocharset=%s" },
+	{ Opt_sockopt, "sockopt=%s" },
+	{ Opt_netbiosname, "netbiosname=%s" },
+	{ Opt_servern, "servern=%s" },
+	{ Opt_ver, "ver=%s" },
+	{ Opt_ver, "vers=%s" },
+	{ Opt_ver, "version=%s" },
+	{ Opt_sec, "sec=%s" },
+
+	{ Opt_ignore, "cred" },
+	{ Opt_ignore, "credentials" },
+	{ Opt_ignore, "guest" },
+	{ Opt_ignore, "rw" },
+	{ Opt_ignore, "ro" },
+	{ Opt_ignore, "suid" },
+	{ Opt_ignore, "nosuid" },
+	{ Opt_ignore, "exec" },
+	{ Opt_ignore, "noexec" },
+	{ Opt_ignore, "nodev" },
+	{ Opt_ignore, "noauto" },
+	{ Opt_ignore, "dev" },
+	{ Opt_ignore, "mand" },
+	{ Opt_ignore, "nomand" },
+	{ Opt_ignore, "_netdev" },
+
+	{ Opt_err, NULL }
+};
+
+enum {
+	Opt_sec_krb5, Opt_sec_krb5i, Opt_sec_krb5p,
+	Opt_sec_ntlmsspi, Opt_sec_ntlmssp,
+	Opt_ntlm, Opt_sec_ntlmi, Opt_sec_ntlmv2i,
+	Opt_sec_nontlm, Opt_sec_lanman,
+	Opt_sec_none,
+
+	Opt_sec_err
+};
+
+static const match_table_t cifs_secflavor_tokens = {
+	{ Opt_sec_krb5, "krb5" },
+	{ Opt_sec_krb5i, "krb5i" },
+	{ Opt_sec_krb5p, "krb5p" },
+	{ Opt_sec_ntlmsspi, "ntlmsspi" },
+	{ Opt_sec_ntlmssp, "ntlmssp" },
+	{ Opt_ntlm, "ntlm" },
+	{ Opt_sec_ntlmi, "ntlmi" },
+	{ Opt_sec_ntlmv2i, "ntlmv2i" },
+	{ Opt_sec_nontlm, "nontlm" },
+	{ Opt_sec_lanman, "lanman" },
+	{ Opt_sec_none, "none" },
+
+	{ Opt_sec_err, NULL }
+};
+
 static int ip_connect(struct TCP_Server_Info *server);
 static int generic_ip_connect(struct TCP_Server_Info *server);
 static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
@@ -143,8 +332,8 @@
 	spin_lock(&GlobalMid_Lock);
 	list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
 		mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-		if (mid_entry->midState == MID_REQUEST_SUBMITTED)
-			mid_entry->midState = MID_RETRY_NEEDED;
+		if (mid_entry->mid_state == MID_REQUEST_SUBMITTED)
+			mid_entry->mid_state = MID_RETRY_NEEDED;
 		list_move(&mid_entry->qhead, &retry_list);
 	}
 	spin_unlock(&GlobalMid_Lock);
@@ -183,8 +372,9 @@
 		-EINVAL = invalid transact2
 
  */
-static int check2ndT2(struct smb_hdr *pSMB)
+static int check2ndT2(char *buf)
 {
+	struct smb_hdr *pSMB = (struct smb_hdr *)buf;
 	struct smb_t2_rsp *pSMBt;
 	int remaining;
 	__u16 total_data_size, data_in_this_rsp;
@@ -224,10 +414,10 @@
 	return remaining;
 }
 
-static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
+static int coalesce_t2(char *second_buf, struct smb_hdr *target_hdr)
 {
-	struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)psecond;
-	struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)pTargetSMB;
+	struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf;
+	struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)target_hdr;
 	char *data_area_of_tgt;
 	char *data_area_of_src;
 	int remaining;
@@ -280,23 +470,23 @@
 	put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount);
 
 	/* fix up the BCC */
-	byte_count = get_bcc(pTargetSMB);
+	byte_count = get_bcc(target_hdr);
 	byte_count += total_in_src;
 	/* is the result too big for the field? */
 	if (byte_count > USHRT_MAX) {
 		cFYI(1, "coalesced BCC too large (%u)", byte_count);
 		return -EPROTO;
 	}
-	put_bcc(byte_count, pTargetSMB);
+	put_bcc(byte_count, target_hdr);
 
-	byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
+	byte_count = be32_to_cpu(target_hdr->smb_buf_length);
 	byte_count += total_in_src;
 	/* don't allow buffer to overflow */
 	if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
 		cFYI(1, "coalesced BCC exceeds buffer size (%u)", byte_count);
 		return -ENOBUFS;
 	}
-	pTargetSMB->smb_buf_length = cpu_to_be32(byte_count);
+	target_hdr->smb_buf_length = cpu_to_be32(byte_count);
 
 	/* copy second buffer into end of first buffer */
 	memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
@@ -334,7 +524,7 @@
 			server->hostname);
 
 requeue_echo:
-	queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL);
+	queue_delayed_work(cifsiod_wq, &server->echo, SMB_ECHO_INTERVAL);
 }
 
 static bool
@@ -350,7 +540,7 @@
 		}
 	} else if (server->large_buf) {
 		/* we are reusing a dirty large buf, clear its start */
-		memset(server->bigbuf, 0, sizeof(struct smb_hdr));
+		memset(server->bigbuf, 0, header_size());
 	}
 
 	if (!server->smallbuf) {
@@ -364,7 +554,7 @@
 		/* beginning of smb buffer is cleared in our buf_get */
 	} else {
 		/* if existing small buf clear beginning */
-		memset(server->smallbuf, 0, sizeof(struct smb_hdr));
+		memset(server->smallbuf, 0, header_size());
 	}
 
 	return true;
@@ -373,12 +563,22 @@
 static bool
 server_unresponsive(struct TCP_Server_Info *server)
 {
-	if (echo_retries > 0 && server->tcpStatus == CifsGood &&
-	    time_after(jiffies, server->lstrp +
-				(echo_retries * SMB_ECHO_INTERVAL))) {
+	/*
+	 * We need to wait 2 echo intervals to make sure we handle such
+	 * situations right:
+	 * 1s  client sends a normal SMB request
+	 * 2s  client gets a response
+	 * 30s echo workqueue job pops, and decides we got a response recently
+	 *     and don't need to send another
+	 * ...
+	 * 65s kernel_recvmsg times out, and we see that we haven't gotten
+	 *     a response in >60s.
+	 */
+	if (server->tcpStatus == CifsGood &&
+	    time_after(jiffies, server->lstrp + 2 * SMB_ECHO_INTERVAL)) {
 		cERROR(1, "Server %s has not responded in %d seconds. "
 			  "Reconnecting...", server->hostname,
-			  (echo_retries * SMB_ECHO_INTERVAL / HZ));
+			  (2 * SMB_ECHO_INTERVAL) / HZ);
 		cifs_reconnect(server);
 		wake_up(&server->response_q);
 		return true;
@@ -556,15 +756,16 @@
 }
 
 static struct mid_q_entry *
-find_mid(struct TCP_Server_Info *server, struct smb_hdr *buf)
+find_mid(struct TCP_Server_Info *server, char *buffer)
 {
+	struct smb_hdr *buf = (struct smb_hdr *)buffer;
 	struct mid_q_entry *mid;
 
 	spin_lock(&GlobalMid_Lock);
 	list_for_each_entry(mid, &server->pending_mid_q, qhead) {
 		if (mid->mid == buf->Mid &&
-		    mid->midState == MID_REQUEST_SUBMITTED &&
-		    mid->command == buf->Command) {
+		    mid->mid_state == MID_REQUEST_SUBMITTED &&
+		    le16_to_cpu(mid->command) == buf->Command) {
 			spin_unlock(&GlobalMid_Lock);
 			return mid;
 		}
@@ -581,16 +782,16 @@
 #endif
 	spin_lock(&GlobalMid_Lock);
 	if (!malformed)
-		mid->midState = MID_RESPONSE_RECEIVED;
+		mid->mid_state = MID_RESPONSE_RECEIVED;
 	else
-		mid->midState = MID_RESPONSE_MALFORMED;
+		mid->mid_state = MID_RESPONSE_MALFORMED;
 	list_del_init(&mid->qhead);
 	spin_unlock(&GlobalMid_Lock);
 }
 
 static void
 handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
-	   struct smb_hdr *buf, int malformed)
+	   char *buf, int malformed)
 {
 	if (malformed == 0 && check2ndT2(buf) > 0) {
 		mid->multiRsp = true;
@@ -610,13 +811,13 @@
 		} else {
 			/* Have first buffer */
 			mid->resp_buf = buf;
-			mid->largeBuf = true;
+			mid->large_buf = true;
 			server->bigbuf = NULL;
 		}
 		return;
 	}
 	mid->resp_buf = buf;
-	mid->largeBuf = server->large_buf;
+	mid->large_buf = server->large_buf;
 	/* Was previous buf put in mpx struct for multi-rsp? */
 	if (!mid->multiRsp) {
 		/* smb buffer will be freed by user thread */
@@ -642,19 +843,11 @@
 	spin_unlock(&GlobalMid_Lock);
 	wake_up_all(&server->response_q);
 
-	/*
-	 * Check if we have blocked requests that need to free. Note that
-	 * cifs_max_pending is normally 50, but can be set at module install
-	 * time to as little as two.
-	 */
-	spin_lock(&GlobalMid_Lock);
-	if (atomic_read(&server->inFlight) >= cifs_max_pending)
-		atomic_set(&server->inFlight, cifs_max_pending - 1);
-	/*
-	 * We do not want to set the max_pending too low or we could end up
-	 * with the counter going negative.
-	 */
-	spin_unlock(&GlobalMid_Lock);
+	/* check if we have blocked requests that need to free */
+	spin_lock(&server->req_lock);
+	if (server->credits <= 0)
+		server->credits = 1;
+	spin_unlock(&server->req_lock);
 	/*
 	 * Although there should not be any requests blocked on this queue it
 	 * can not hurt to be paranoid and try to wake up requests that may
@@ -680,8 +873,8 @@
 		spin_lock(&GlobalMid_Lock);
 		list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
 			mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-			cFYI(1, "Clearing mid 0x%x", mid_entry->mid);
-			mid_entry->midState = MID_SHUTDOWN;
+			cFYI(1, "Clearing mid 0x%llx", mid_entry->mid);
+			mid_entry->mid_state = MID_SHUTDOWN;
 			list_move(&mid_entry->qhead, &dispose_list);
 		}
 		spin_unlock(&GlobalMid_Lock);
@@ -689,7 +882,7 @@
 		/* now walk dispose list and issue callbacks */
 		list_for_each_safe(tmp, tmp2, &dispose_list) {
 			mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-			cFYI(1, "Callback mid 0x%x", mid_entry->mid);
+			cFYI(1, "Callback mid 0x%llx", mid_entry->mid);
 			list_del_init(&mid_entry->qhead);
 			mid_entry->callback(mid_entry);
 		}
@@ -729,11 +922,10 @@
 {
 	int length;
 	char *buf = server->smallbuf;
-	struct smb_hdr *smb_buffer = (struct smb_hdr *)buf;
-	unsigned int pdu_length = be32_to_cpu(smb_buffer->smb_buf_length);
+	unsigned int pdu_length = get_rfc1002_length(buf);
 
 	/* make sure this will fit in a large buffer */
-	if (pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+	if (pdu_length > CIFSMaxBufSize + max_header_size() - 4) {
 		cERROR(1, "SMB response too long (%u bytes)",
 			pdu_length);
 		cifs_reconnect(server);
@@ -744,20 +936,18 @@
 	/* switch to large buffer if too big for a small one */
 	if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
 		server->large_buf = true;
-		memcpy(server->bigbuf, server->smallbuf, server->total_read);
+		memcpy(server->bigbuf, buf, server->total_read);
 		buf = server->bigbuf;
-		smb_buffer = (struct smb_hdr *)buf;
 	}
 
 	/* now read the rest */
-	length = cifs_read_from_socket(server,
-			  buf + sizeof(struct smb_hdr) - 1,
-			  pdu_length - sizeof(struct smb_hdr) + 1 + 4);
+	length = cifs_read_from_socket(server, buf + header_size() - 1,
+				       pdu_length - header_size() + 1 + 4);
 	if (length < 0)
 		return length;
 	server->total_read += length;
 
-	dump_smb(smb_buffer, server->total_read);
+	dump_smb(buf, server->total_read);
 
 	/*
 	 * We know that we received enough to get to the MID as we
@@ -768,7 +958,7 @@
 	 * 48 bytes is enough to display the header and a little bit
 	 * into the payload for debugging purposes.
 	 */
-	length = checkSMB(smb_buffer, smb_buffer->Mid, server->total_read);
+	length = checkSMB(buf, server->total_read);
 	if (length != 0)
 		cifs_dump_mem("Bad SMB: ", buf,
 			min_t(unsigned int, server->total_read, 48));
@@ -776,7 +966,7 @@
 	if (!mid)
 		return length;
 
-	handle_mid(mid, server, smb_buffer, length);
+	handle_mid(mid, server, buf, length);
 	return 0;
 }
 
@@ -787,7 +977,6 @@
 	struct TCP_Server_Info *server = p;
 	unsigned int pdu_length;
 	char *buf = NULL;
-	struct smb_hdr *smb_buffer = NULL;
 	struct task_struct *task_to_wake = NULL;
 	struct mid_q_entry *mid_entry;
 
@@ -808,7 +997,6 @@
 			continue;
 
 		server->large_buf = false;
-		smb_buffer = (struct smb_hdr *)server->smallbuf;
 		buf = server->smallbuf;
 		pdu_length = 4; /* enough to get RFC1001 header */
 
@@ -821,14 +1009,14 @@
 		 * The right amount was read from socket - 4 bytes,
 		 * so we can now interpret the length field.
 		 */
-		pdu_length = be32_to_cpu(smb_buffer->smb_buf_length);
+		pdu_length = get_rfc1002_length(buf);
 
 		cFYI(1, "RFC1002 header 0x%x", pdu_length);
 		if (!is_smb_response(server, buf[0]))
 			continue;
 
 		/* make sure we have enough to get to the MID */
-		if (pdu_length < sizeof(struct smb_hdr) - 1 - 4) {
+		if (pdu_length < header_size() - 1 - 4) {
 			cERROR(1, "SMB response too short (%u bytes)",
 				pdu_length);
 			cifs_reconnect(server);
@@ -838,12 +1026,12 @@
 
 		/* read down to the MID */
 		length = cifs_read_from_socket(server, buf + 4,
-					sizeof(struct smb_hdr) - 1 - 4);
+					       header_size() - 1 - 4);
 		if (length < 0)
 			continue;
 		server->total_read += length;
 
-		mid_entry = find_mid(server, smb_buffer);
+		mid_entry = find_mid(server, buf);
 
 		if (!mid_entry || !mid_entry->receive)
 			length = standard_receive3(server, mid_entry);
@@ -853,22 +1041,19 @@
 		if (length < 0)
 			continue;
 
-		if (server->large_buf) {
+		if (server->large_buf)
 			buf = server->bigbuf;
-			smb_buffer = (struct smb_hdr *)buf;
-		}
 
 		server->lstrp = jiffies;
 		if (mid_entry != NULL) {
 			if (!mid_entry->multiRsp || mid_entry->multiEnd)
 				mid_entry->callback(mid_entry);
-		} else if (!is_valid_oplock_break(smb_buffer, server)) {
+		} else if (!is_valid_oplock_break(buf, server)) {
 			cERROR(1, "No task to wake, unknown frame received! "
 				   "NumMids %d", atomic_read(&midCount));
-			cifs_dump_mem("Received Data is: ", buf,
-				      sizeof(struct smb_hdr));
+			cifs_dump_mem("Received Data is: ", buf, header_size());
 #ifdef CONFIG_CIFS_DEBUG2
-			cifs_dump_detail(smb_buffer);
+			cifs_dump_detail(buf);
 			cifs_dump_mids(server);
 #endif /* CIFS_DEBUG2 */
 
@@ -924,23 +1109,95 @@
 	return dst;
 }
 
+static int get_option_ul(substring_t args[], unsigned long *option)
+{
+	int rc;
+	char *string;
+
+	string = match_strdup(args);
+	if (string == NULL)
+		return -ENOMEM;
+	rc = kstrtoul(string, 10, option);
+	kfree(string);
+
+	return rc;
+}
+
+
+static int cifs_parse_security_flavors(char *value,
+				       struct smb_vol *vol)
+{
+
+	substring_t args[MAX_OPT_ARGS];
+
+	switch (match_token(value, cifs_secflavor_tokens, args)) {
+	case Opt_sec_krb5:
+		vol->secFlg |= CIFSSEC_MAY_KRB5;
+		break;
+	case Opt_sec_krb5i:
+		vol->secFlg |= CIFSSEC_MAY_KRB5 | CIFSSEC_MUST_SIGN;
+		break;
+	case Opt_sec_krb5p:
+		/* vol->secFlg |= CIFSSEC_MUST_SEAL | CIFSSEC_MAY_KRB5; */
+		cERROR(1, "Krb5 cifs privacy not supported");
+		break;
+	case Opt_sec_ntlmssp:
+		vol->secFlg |= CIFSSEC_MAY_NTLMSSP;
+		break;
+	case Opt_sec_ntlmsspi:
+		vol->secFlg |= CIFSSEC_MAY_NTLMSSP | CIFSSEC_MUST_SIGN;
+		break;
+	case Opt_ntlm:
+		/* ntlm is default so can be turned off too */
+		vol->secFlg |= CIFSSEC_MAY_NTLM;
+		break;
+	case Opt_sec_ntlmi:
+		vol->secFlg |= CIFSSEC_MAY_NTLM | CIFSSEC_MUST_SIGN;
+		break;
+	case Opt_sec_nontlm:
+		vol->secFlg |= CIFSSEC_MAY_NTLMV2;
+		break;
+	case Opt_sec_ntlmv2i:
+		vol->secFlg |= CIFSSEC_MAY_NTLMV2 | CIFSSEC_MUST_SIGN;
+		break;
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+	case Opt_sec_lanman:
+		vol->secFlg |= CIFSSEC_MAY_LANMAN;
+		break;
+#endif
+	case Opt_sec_none:
+		vol->nullauth = 1;
+		break;
+	default:
+		cERROR(1, "bad security option: %s", value);
+		return 1;
+	}
+
+	return 0;
+}
+
 static int
 cifs_parse_mount_options(const char *mountdata, const char *devname,
 			 struct smb_vol *vol)
 {
-	char *value, *data, *end;
+	char *data, *end;
 	char *mountdata_copy = NULL, *options;
-	int err;
 	unsigned int  temp_len, i, j;
 	char separator[2];
 	short int override_uid = -1;
 	short int override_gid = -1;
 	bool uid_specified = false;
 	bool gid_specified = false;
+	bool sloppy = false;
+	char *invalid = NULL;
 	char *nodename = utsname()->nodename;
+	char *string = NULL;
+	char *tmp_end, *value;
+	char delim;
 
 	separator[0] = ',';
 	separator[1] = 0;
+	delim = separator[0];
 
 	/*
 	 * does not have to be perfect mapping since field is
@@ -979,6 +1236,7 @@
 
 	options = mountdata_copy;
 	end = options + strlen(options);
+
 	if (strncmp(options, "sep=", 4) == 0) {
 		if (options[4] != 0) {
 			separator[0] = options[4];
@@ -991,609 +1249,651 @@
 	vol->backupgid_specified = false; /* no backup intent for a group */
 
 	while ((data = strsep(&options, separator)) != NULL) {
+		substring_t args[MAX_OPT_ARGS];
+		unsigned long option;
+		int token;
+
 		if (!*data)
 			continue;
-		if ((value = strchr(data, '=')) != NULL)
-			*value++ = '\0';
 
-		/* Have to parse this before we parse for "user" */
-		if (strnicmp(data, "user_xattr", 10) == 0) {
+		token = match_token(data, cifs_mount_option_tokens, args);
+
+		switch (token) {
+
+		/* Ingnore the following */
+		case Opt_ignore:
+			break;
+
+		/* Boolean values */
+		case Opt_user_xattr:
 			vol->no_xattr = 0;
-		} else if (strnicmp(data, "nouser_xattr", 12) == 0) {
+			break;
+		case Opt_nouser_xattr:
 			vol->no_xattr = 1;
-		} else if (strnicmp(data, "user", 4) == 0) {
-			if (!value) {
-				printk(KERN_WARNING
-				       "CIFS: invalid or missing username\n");
-				goto cifs_parse_mount_err;
-			} else if (!*value) {
-				/* null user, ie anonymous, authentication */
-				vol->nullauth = 1;
-			}
-			if (strnlen(value, MAX_USERNAME_SIZE) <
-						MAX_USERNAME_SIZE) {
-				vol->username = kstrdup(value, GFP_KERNEL);
-				if (!vol->username) {
-					printk(KERN_WARNING "CIFS: no memory "
-							    "for username\n");
-					goto cifs_parse_mount_err;
-				}
-			} else {
-				printk(KERN_WARNING "CIFS: username too long\n");
-				goto cifs_parse_mount_err;
-			}
-		} else if (strnicmp(data, "pass", 4) == 0) {
-			if (!value) {
-				vol->password = NULL;
-				continue;
-			} else if (value[0] == 0) {
-				/* check if string begins with double comma
-				   since that would mean the password really
-				   does start with a comma, and would not
-				   indicate an empty string */
-				if (value[1] != separator[0]) {
-					vol->password = NULL;
-					continue;
-				}
-			}
-			temp_len = strlen(value);
-			/* removed password length check, NTLM passwords
-				can be arbitrarily long */
-
-			/* if comma in password, the string will be
-			prematurely null terminated.  Commas in password are
-			specified across the cifs mount interface by a double
-			comma ie ,, and a comma used as in other cases ie ','
-			as a parameter delimiter/separator is single and due
-			to the strsep above is temporarily zeroed. */
-
-			/* NB: password legally can have multiple commas and
-			the only illegal character in a password is null */
-
-			if ((value[temp_len] == 0) &&
-			    (value + temp_len < end) &&
-			    (value[temp_len+1] == separator[0])) {
-				/* reinsert comma */
-				value[temp_len] = separator[0];
-				temp_len += 2;  /* move after second comma */
-				while (value[temp_len] != 0)  {
-					if (value[temp_len] == separator[0]) {
-						if (value[temp_len+1] ==
-						     separator[0]) {
-						/* skip second comma */
-							temp_len++;
-						} else {
-						/* single comma indicating start
-							 of next parm */
-							break;
-						}
-					}
-					temp_len++;
-				}
-				if (value[temp_len] == 0) {
-					options = NULL;
-				} else {
-					value[temp_len] = 0;
-					/* point option to start of next parm */
-					options = value + temp_len + 1;
-				}
-				/* go from value to value + temp_len condensing
-				double commas to singles. Note that this ends up
-				allocating a few bytes too many, which is ok */
-				vol->password = kzalloc(temp_len, GFP_KERNEL);
-				if (vol->password == NULL) {
-					printk(KERN_WARNING "CIFS: no memory "
-							    "for password\n");
-					goto cifs_parse_mount_err;
-				}
-				for (i = 0, j = 0; i < temp_len; i++, j++) {
-					vol->password[j] = value[i];
-					if (value[i] == separator[0]
-						&& value[i+1] == separator[0]) {
-						/* skip second comma */
-						i++;
-					}
-				}
-				vol->password[j] = 0;
-			} else {
-				vol->password = kzalloc(temp_len+1, GFP_KERNEL);
-				if (vol->password == NULL) {
-					printk(KERN_WARNING "CIFS: no memory "
-							    "for password\n");
-					goto cifs_parse_mount_err;
-				}
-				strcpy(vol->password, value);
-			}
-		} else if (!strnicmp(data, "ip", 2) ||
-			   !strnicmp(data, "addr", 4)) {
-			if (!value || !*value) {
-				vol->UNCip = NULL;
-			} else if (strnlen(value, INET6_ADDRSTRLEN) <
-							INET6_ADDRSTRLEN) {
-				vol->UNCip = kstrdup(value, GFP_KERNEL);
-				if (!vol->UNCip) {
-					printk(KERN_WARNING "CIFS: no memory "
-							    "for UNC IP\n");
-					goto cifs_parse_mount_err;
-				}
-			} else {
-				printk(KERN_WARNING "CIFS: ip address "
-						    "too long\n");
-				goto cifs_parse_mount_err;
-			}
-		} else if (strnicmp(data, "sec", 3) == 0) {
-			if (!value || !*value) {
-				cERROR(1, "no security value specified");
-				continue;
-			} else if (strnicmp(value, "krb5i", 5) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_KRB5 |
-					CIFSSEC_MUST_SIGN;
-			} else if (strnicmp(value, "krb5p", 5) == 0) {
-				/* vol->secFlg |= CIFSSEC_MUST_SEAL |
-					CIFSSEC_MAY_KRB5; */
-				cERROR(1, "Krb5 cifs privacy not supported");
-				goto cifs_parse_mount_err;
-			} else if (strnicmp(value, "krb5", 4) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_KRB5;
-			} else if (strnicmp(value, "ntlmsspi", 8) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_NTLMSSP |
-					CIFSSEC_MUST_SIGN;
-			} else if (strnicmp(value, "ntlmssp", 7) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_NTLMSSP;
-			} else if (strnicmp(value, "ntlmv2i", 7) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
-					CIFSSEC_MUST_SIGN;
-			} else if (strnicmp(value, "ntlmv2", 6) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_NTLMV2;
-			} else if (strnicmp(value, "ntlmi", 5) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_NTLM |
-					CIFSSEC_MUST_SIGN;
-			} else if (strnicmp(value, "ntlm", 4) == 0) {
-				/* ntlm is default so can be turned off too */
-				vol->secFlg |= CIFSSEC_MAY_NTLM;
-			} else if (strnicmp(value, "nontlm", 6) == 0) {
-				/* BB is there a better way to do this? */
-				vol->secFlg |= CIFSSEC_MAY_NTLMV2;
-#ifdef CONFIG_CIFS_WEAK_PW_HASH
-			} else if (strnicmp(value, "lanman", 6) == 0) {
-				vol->secFlg |= CIFSSEC_MAY_LANMAN;
-#endif
-			} else if (strnicmp(value, "none", 4) == 0) {
-				vol->nullauth = 1;
-			} else {
-				cERROR(1, "bad security option: %s", value);
-				goto cifs_parse_mount_err;
-			}
-		} else if (strnicmp(data, "vers", 3) == 0) {
-			if (!value || !*value) {
-				cERROR(1, "no protocol version specified"
-					  " after vers= mount option");
-			} else if ((strnicmp(value, "cifs", 4) == 0) ||
-				   (strnicmp(value, "1", 1) == 0)) {
-				/* this is the default */
-				continue;
-			}
-		} else if ((strnicmp(data, "unc", 3) == 0)
-			   || (strnicmp(data, "target", 6) == 0)
-			   || (strnicmp(data, "path", 4) == 0)) {
-			if (!value || !*value) {
-				printk(KERN_WARNING "CIFS: invalid path to "
-						    "network resource\n");
-				goto cifs_parse_mount_err;
-			}
-			if ((temp_len = strnlen(value, 300)) < 300) {
-				vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
-				if (vol->UNC == NULL)
-					goto cifs_parse_mount_err;
-				strcpy(vol->UNC, value);
-				if (strncmp(vol->UNC, "//", 2) == 0) {
-					vol->UNC[0] = '\\';
-					vol->UNC[1] = '\\';
-				} else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
-					printk(KERN_WARNING
-					       "CIFS: UNC Path does not begin "
-					       "with // or \\\\ \n");
-					goto cifs_parse_mount_err;
-				}
-			} else {
-				printk(KERN_WARNING "CIFS: UNC name too long\n");
-				goto cifs_parse_mount_err;
-			}
-		} else if ((strnicmp(data, "domain", 3) == 0)
-			   || (strnicmp(data, "workgroup", 5) == 0)) {
-			if (!value || !*value) {
-				printk(KERN_WARNING "CIFS: invalid domain name\n");
-				goto cifs_parse_mount_err;
-			}
-			/* BB are there cases in which a comma can be valid in
-			a domain name and need special handling? */
-			if (strnlen(value, 256) < 256) {
-				vol->domainname = kstrdup(value, GFP_KERNEL);
-				if (!vol->domainname) {
-					printk(KERN_WARNING "CIFS: no memory "
-							    "for domainname\n");
-					goto cifs_parse_mount_err;
-				}
-				cFYI(1, "Domain name set");
-			} else {
-				printk(KERN_WARNING "CIFS: domain name too "
-						    "long\n");
-				goto cifs_parse_mount_err;
-			}
-		} else if (strnicmp(data, "srcaddr", 7) == 0) {
-			vol->srcaddr.ss_family = AF_UNSPEC;
-
-			if (!value || !*value) {
-				printk(KERN_WARNING "CIFS: srcaddr value"
-				       " not specified.\n");
-				goto cifs_parse_mount_err;
-			}
-			i = cifs_convert_address((struct sockaddr *)&vol->srcaddr,
-						 value, strlen(value));
-			if (i == 0) {
-				printk(KERN_WARNING "CIFS:  Could not parse"
-				       " srcaddr: %s\n",
-				       value);
-				goto cifs_parse_mount_err;
-			}
-		} else if (strnicmp(data, "prefixpath", 10) == 0) {
-			if (!value || !*value) {
-				printk(KERN_WARNING
-					"CIFS: invalid path prefix\n");
-				goto cifs_parse_mount_err;
-			}
-			if ((temp_len = strnlen(value, 1024)) < 1024) {
-				if (value[0] != '/')
-					temp_len++;  /* missing leading slash */
-				vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
-				if (vol->prepath == NULL)
-					goto cifs_parse_mount_err;
-				if (value[0] != '/') {
-					vol->prepath[0] = '/';
-					strcpy(vol->prepath+1, value);
-				} else
-					strcpy(vol->prepath, value);
-				cFYI(1, "prefix path %s", vol->prepath);
-			} else {
-				printk(KERN_WARNING "CIFS: prefix too long\n");
-				goto cifs_parse_mount_err;
-			}
-		} else if (strnicmp(data, "iocharset", 9) == 0) {
-			if (!value || !*value) {
-				printk(KERN_WARNING "CIFS: invalid iocharset "
-						    "specified\n");
-				goto cifs_parse_mount_err;
-			}
-			if (strnlen(value, 65) < 65) {
-				if (strnicmp(value, "default", 7)) {
-					vol->iocharset = kstrdup(value,
-								 GFP_KERNEL);
-
-					if (!vol->iocharset) {
-						printk(KERN_WARNING "CIFS: no "
-								   "memory for"
-								   "charset\n");
-						goto cifs_parse_mount_err;
-					}
-				}
-				/* if iocharset not set then load_nls_default
-				   is used by caller */
-				cFYI(1, "iocharset set to %s", value);
-			} else {
-				printk(KERN_WARNING "CIFS: iocharset name "
-						    "too long.\n");
-				goto cifs_parse_mount_err;
-			}
-		} else if (!strnicmp(data, "uid", 3) && value && *value) {
-			vol->linux_uid = simple_strtoul(value, &value, 0);
-			uid_specified = true;
-		} else if (!strnicmp(data, "cruid", 5) && value && *value) {
-			vol->cred_uid = simple_strtoul(value, &value, 0);
-		} else if (!strnicmp(data, "forceuid", 8)) {
+			break;
+		case Opt_forceuid:
 			override_uid = 1;
-		} else if (!strnicmp(data, "noforceuid", 10)) {
+			break;
+		case Opt_noforceuid:
 			override_uid = 0;
-		} else if (!strnicmp(data, "gid", 3) && value && *value) {
-			vol->linux_gid = simple_strtoul(value, &value, 0);
-			gid_specified = true;
-		} else if (!strnicmp(data, "forcegid", 8)) {
-			override_gid = 1;
-		} else if (!strnicmp(data, "noforcegid", 10)) {
-			override_gid = 0;
-		} else if (strnicmp(data, "file_mode", 4) == 0) {
-			if (value && *value) {
-				vol->file_mode =
-					simple_strtoul(value, &value, 0);
-			}
-		} else if (strnicmp(data, "dir_mode", 4) == 0) {
-			if (value && *value) {
-				vol->dir_mode =
-					simple_strtoul(value, &value, 0);
-			}
-		} else if (strnicmp(data, "dirmode", 4) == 0) {
-			if (value && *value) {
-				vol->dir_mode =
-					simple_strtoul(value, &value, 0);
-			}
-		} else if (strnicmp(data, "port", 4) == 0) {
-			if (value && *value) {
-				vol->port =
-					simple_strtoul(value, &value, 0);
-			}
-		} else if (strnicmp(data, "rsize", 5) == 0) {
-			if (value && *value) {
-				vol->rsize =
-					simple_strtoul(value, &value, 0);
-			}
-		} else if (strnicmp(data, "wsize", 5) == 0) {
-			if (value && *value) {
-				vol->wsize =
-					simple_strtoul(value, &value, 0);
-			}
-		} else if (strnicmp(data, "sockopt", 5) == 0) {
-			if (!value || !*value) {
-				cERROR(1, "no socket option specified");
-				continue;
-			} else if (strnicmp(value, "TCP_NODELAY", 11) == 0) {
-				vol->sockopt_tcp_nodelay = 1;
-			}
-		} else if (strnicmp(data, "netbiosname", 4) == 0) {
-			if (!value || !*value || (*value == ' ')) {
-				cFYI(1, "invalid (empty) netbiosname");
-			} else {
-				memset(vol->source_rfc1001_name, 0x20,
-					RFC1001_NAME_LEN);
-				/*
-				 * FIXME: are there cases in which a comma can
-				 * be valid in workstation netbios name (and
-				 * need special handling)?
-				 */
-				for (i = 0; i < RFC1001_NAME_LEN; i++) {
-					/* don't ucase netbiosname for user */
-					if (value[i] == 0)
-						break;
-					vol->source_rfc1001_name[i] = value[i];
-				}
-				/* The string has 16th byte zero still from
-				set at top of the function  */
-				if (i == RFC1001_NAME_LEN && value[i] != 0)
-					printk(KERN_WARNING "CIFS: netbiosname"
-						" longer than 15 truncated.\n");
-			}
-		} else if (strnicmp(data, "servern", 7) == 0) {
-			/* servernetbiosname specified override *SMBSERVER */
-			if (!value || !*value || (*value == ' ')) {
-				cFYI(1, "empty server netbiosname specified");
-			} else {
-				/* last byte, type, is 0x20 for servr type */
-				memset(vol->target_rfc1001_name, 0x20,
-					RFC1001_NAME_LEN_WITH_NULL);
-
-				for (i = 0; i < 15; i++) {
-				/* BB are there cases in which a comma can be
-				   valid in this workstation netbios name
-				   (and need special handling)? */
-
-				/* user or mount helper must uppercase
-				   the netbiosname */
-					if (value[i] == 0)
-						break;
-					else
-						vol->target_rfc1001_name[i] =
-								value[i];
-				}
-				/* The string has 16th byte zero still from
-				   set at top of the function  */
-				if (i == RFC1001_NAME_LEN && value[i] != 0)
-					printk(KERN_WARNING "CIFS: server net"
-					"biosname longer than 15 truncated.\n");
-			}
-		} else if (strnicmp(data, "actimeo", 7) == 0) {
-			if (value && *value) {
-				vol->actimeo = HZ * simple_strtoul(value,
-								   &value, 0);
-				if (vol->actimeo > CIFS_MAX_ACTIMEO) {
-					cERROR(1, "CIFS: attribute cache"
-							"timeout too large");
-					goto cifs_parse_mount_err;
-				}
-			}
-		} else if (strnicmp(data, "credentials", 4) == 0) {
-			/* ignore */
-		} else if (strnicmp(data, "version", 3) == 0) {
-			/* ignore */
-		} else if (strnicmp(data, "guest", 5) == 0) {
-			/* ignore */
-		} else if (strnicmp(data, "rw", 2) == 0 && strlen(data) == 2) {
-			/* ignore */
-		} else if (strnicmp(data, "ro", 2) == 0) {
-			/* ignore */
-		} else if (strnicmp(data, "noblocksend", 11) == 0) {
+			break;
+		case Opt_noblocksend:
 			vol->noblocksnd = 1;
-		} else if (strnicmp(data, "noautotune", 10) == 0) {
+			break;
+		case Opt_noautotune:
 			vol->noautotune = 1;
-		} else if ((strnicmp(data, "suid", 4) == 0) ||
-				   (strnicmp(data, "nosuid", 6) == 0) ||
-				   (strnicmp(data, "exec", 4) == 0) ||
-				   (strnicmp(data, "noexec", 6) == 0) ||
-				   (strnicmp(data, "nodev", 5) == 0) ||
-				   (strnicmp(data, "noauto", 6) == 0) ||
-				   (strnicmp(data, "dev", 3) == 0)) {
-			/*  The mount tool or mount.cifs helper (if present)
-			    uses these opts to set flags, and the flags are read
-			    by the kernel vfs layer before we get here (ie
-			    before read super) so there is no point trying to
-			    parse these options again and set anything and it
-			    is ok to just ignore them */
-			continue;
-		} else if (strnicmp(data, "hard", 4) == 0) {
+			break;
+		case Opt_hard:
 			vol->retry = 1;
-		} else if (strnicmp(data, "soft", 4) == 0) {
+			break;
+		case Opt_soft:
 			vol->retry = 0;
-		} else if (strnicmp(data, "perm", 4) == 0) {
+			break;
+		case Opt_perm:
 			vol->noperm = 0;
-		} else if (strnicmp(data, "noperm", 6) == 0) {
+			break;
+		case Opt_noperm:
 			vol->noperm = 1;
-		} else if (strnicmp(data, "mapchars", 8) == 0) {
+			break;
+		case Opt_mapchars:
 			vol->remap = 1;
-		} else if (strnicmp(data, "nomapchars", 10) == 0) {
+			break;
+		case Opt_nomapchars:
 			vol->remap = 0;
-		} else if (strnicmp(data, "sfu", 3) == 0) {
+			break;
+		case Opt_sfu:
 			vol->sfu_emul = 1;
-		} else if (strnicmp(data, "nosfu", 5) == 0) {
+			break;
+		case Opt_nosfu:
 			vol->sfu_emul = 0;
-		} else if (strnicmp(data, "nodfs", 5) == 0) {
+			break;
+		case Opt_nodfs:
 			vol->nodfs = 1;
-		} else if (strnicmp(data, "posixpaths", 10) == 0) {
+			break;
+		case Opt_posixpaths:
 			vol->posix_paths = 1;
-		} else if (strnicmp(data, "noposixpaths", 12) == 0) {
+			break;
+		case Opt_noposixpaths:
 			vol->posix_paths = 0;
-		} else if (strnicmp(data, "nounix", 6) == 0) {
+			break;
+		case Opt_nounix:
 			vol->no_linux_ext = 1;
-		} else if (strnicmp(data, "nolinux", 7) == 0) {
-			vol->no_linux_ext = 1;
-		} else if ((strnicmp(data, "nocase", 6) == 0) ||
-			   (strnicmp(data, "ignorecase", 10)  == 0)) {
+			break;
+		case Opt_nocase:
 			vol->nocase = 1;
-		} else if (strnicmp(data, "mand", 4) == 0) {
-			/* ignore */
-		} else if (strnicmp(data, "nomand", 6) == 0) {
-			/* ignore */
-		} else if (strnicmp(data, "_netdev", 7) == 0) {
-			/* ignore */
-		} else if (strnicmp(data, "brl", 3) == 0) {
+			break;
+		case Opt_brl:
 			vol->nobrl =  0;
-		} else if ((strnicmp(data, "nobrl", 5) == 0) ||
-			   (strnicmp(data, "nolock", 6) == 0)) {
+			break;
+		case Opt_nobrl:
 			vol->nobrl =  1;
-			/* turn off mandatory locking in mode
-			if remote locking is turned off since the
-			local vfs will do advisory */
+			/*
+			 * turn off mandatory locking in mode
+			 * if remote locking is turned off since the
+			 * local vfs will do advisory
+			 */
 			if (vol->file_mode ==
 				(S_IALLUGO & ~(S_ISUID | S_IXGRP)))
 				vol->file_mode = S_IALLUGO;
-		} else if (strnicmp(data, "forcemandatorylock", 9) == 0) {
-			/* will take the shorter form "forcemand" as well */
-			/* This mount option will force use of mandatory
-			  (DOS/Windows style) byte range locks, instead of
-			  using posix advisory byte range locks, even if the
-			  Unix extensions are available and posix locks would
-			  be supported otherwise. If Unix extensions are not
-			  negotiated this has no effect since mandatory locks
-			  would be used (mandatory locks is all that those
-			  those servers support) */
+			break;
+		case Opt_forcemandatorylock:
 			vol->mand_lock = 1;
-		} else if (strnicmp(data, "setuids", 7) == 0) {
+			break;
+		case Opt_setuids:
 			vol->setuids = 1;
-		} else if (strnicmp(data, "nosetuids", 9) == 0) {
+			break;
+		case Opt_nosetuids:
 			vol->setuids = 0;
-		} else if (strnicmp(data, "dynperm", 7) == 0) {
+			break;
+		case Opt_dynperm:
 			vol->dynperm = true;
-		} else if (strnicmp(data, "nodynperm", 9) == 0) {
+			break;
+		case Opt_nodynperm:
 			vol->dynperm = false;
-		} else if (strnicmp(data, "nohard", 6) == 0) {
+			break;
+		case Opt_nohard:
 			vol->retry = 0;
-		} else if (strnicmp(data, "nosoft", 6) == 0) {
+			break;
+		case Opt_nosoft:
 			vol->retry = 1;
-		} else if (strnicmp(data, "nointr", 6) == 0) {
+			break;
+		case Opt_nointr:
 			vol->intr = 0;
-		} else if (strnicmp(data, "intr", 4) == 0) {
+			break;
+		case Opt_intr:
 			vol->intr = 1;
-		} else if (strnicmp(data, "nostrictsync", 12) == 0) {
+			break;
+		case Opt_nostrictsync:
 			vol->nostrictsync = 1;
-		} else if (strnicmp(data, "strictsync", 10) == 0) {
+			break;
+		case Opt_strictsync:
 			vol->nostrictsync = 0;
-		} else if (strnicmp(data, "serverino", 7) == 0) {
+			break;
+		case Opt_serverino:
 			vol->server_ino = 1;
-		} else if (strnicmp(data, "noserverino", 9) == 0) {
+			break;
+		case Opt_noserverino:
 			vol->server_ino = 0;
-		} else if (strnicmp(data, "rwpidforward", 12) == 0) {
+			break;
+		case Opt_rwpidforward:
 			vol->rwpidforward = 1;
-		} else if (strnicmp(data, "cifsacl", 7) == 0) {
+			break;
+		case Opt_cifsacl:
 			vol->cifs_acl = 1;
-		} else if (strnicmp(data, "nocifsacl", 9) == 0) {
+			break;
+		case Opt_nocifsacl:
 			vol->cifs_acl = 0;
-		} else if (strnicmp(data, "acl", 3) == 0) {
+			break;
+		case Opt_acl:
 			vol->no_psx_acl = 0;
-		} else if (strnicmp(data, "noacl", 5) == 0) {
+			break;
+		case Opt_noacl:
 			vol->no_psx_acl = 1;
-		} else if (strnicmp(data, "locallease", 6) == 0) {
+			break;
+		case Opt_locallease:
 			vol->local_lease = 1;
-		} else if (strnicmp(data, "sign", 4) == 0) {
+			break;
+		case Opt_sign:
 			vol->secFlg |= CIFSSEC_MUST_SIGN;
-		} else if (strnicmp(data, "seal", 4) == 0) {
+			break;
+		case Opt_seal:
 			/* we do not do the following in secFlags because seal
-			   is a per tree connection (mount) not a per socket
-			   or per-smb connection option in the protocol */
-			/* vol->secFlg |= CIFSSEC_MUST_SEAL; */
+			 * is a per tree connection (mount) not a per socket
+			 * or per-smb connection option in the protocol
+			 * vol->secFlg |= CIFSSEC_MUST_SEAL;
+			 */
 			vol->seal = 1;
-		} else if (strnicmp(data, "direct", 6) == 0) {
+			break;
+		case Opt_direct:
 			vol->direct_io = 1;
-		} else if (strnicmp(data, "forcedirectio", 13) == 0) {
-			vol->direct_io = 1;
-		} else if (strnicmp(data, "strictcache", 11) == 0) {
+			break;
+		case Opt_strictcache:
 			vol->strict_io = 1;
-		} else if (strnicmp(data, "noac", 4) == 0) {
+			break;
+		case Opt_noac:
 			printk(KERN_WARNING "CIFS: Mount option noac not "
 				"supported. Instead set "
 				"/proc/fs/cifs/LookupCacheEnabled to 0\n");
-		} else if (strnicmp(data, "fsc", 3) == 0) {
+			break;
+		case Opt_fsc:
 #ifndef CONFIG_CIFS_FSCACHE
 			cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE "
 				  "kernel config option set");
 			goto cifs_parse_mount_err;
 #endif
 			vol->fsc = true;
-		} else if (strnicmp(data, "mfsymlinks", 10) == 0) {
+			break;
+		case Opt_mfsymlinks:
 			vol->mfsymlinks = true;
-		} else if (strnicmp(data, "multiuser", 8) == 0) {
+			break;
+		case Opt_multiuser:
 			vol->multiuser = true;
-		} else if (!strnicmp(data, "backupuid", 9) && value && *value) {
-			err = kstrtouint(value, 0, &vol->backupuid);
-			if (err < 0) {
+			break;
+		case Opt_sloppy:
+			sloppy = true;
+			break;
+
+		/* Numeric Values */
+		case Opt_backupuid:
+			if (get_option_ul(args, &option)) {
 				cERROR(1, "%s: Invalid backupuid value",
 					__func__);
 				goto cifs_parse_mount_err;
 			}
+			vol->backupuid = option;
 			vol->backupuid_specified = true;
-		} else if (!strnicmp(data, "backupgid", 9) && value && *value) {
-			err = kstrtouint(value, 0, &vol->backupgid);
-			if (err < 0) {
+			break;
+		case Opt_backupgid:
+			if (get_option_ul(args, &option)) {
 				cERROR(1, "%s: Invalid backupgid value",
 					__func__);
 				goto cifs_parse_mount_err;
 			}
+			vol->backupgid = option;
 			vol->backupgid_specified = true;
-		} else
-			printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
-						data);
-	}
-	if (vol->UNC == NULL) {
-		if (devname == NULL) {
-			printk(KERN_WARNING "CIFS: Missing UNC name for mount "
-						"target\n");
-			goto cifs_parse_mount_err;
-		}
-		if ((temp_len = strnlen(devname, 300)) < 300) {
-			vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
-			if (vol->UNC == NULL)
-				goto cifs_parse_mount_err;
-			strcpy(vol->UNC, devname);
-			if (strncmp(vol->UNC, "//", 2) == 0) {
-				vol->UNC[0] = '\\';
-				vol->UNC[1] = '\\';
-			} else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
-				printk(KERN_WARNING "CIFS: UNC Path does not "
-						    "begin with // or \\\\ \n");
+			break;
+		case Opt_uid:
+			if (get_option_ul(args, &option)) {
+				cERROR(1, "%s: Invalid uid value",
+					__func__);
 				goto cifs_parse_mount_err;
 			}
-			value = strpbrk(vol->UNC+2, "/\\");
-			if (value)
-				*value = '\\';
-		} else {
-			printk(KERN_WARNING "CIFS: UNC name too long\n");
+			vol->linux_uid = option;
+			uid_specified = true;
+			break;
+		case Opt_cruid:
+			if (get_option_ul(args, &option)) {
+				cERROR(1, "%s: Invalid cruid value",
+					__func__);
+				goto cifs_parse_mount_err;
+			}
+			vol->cred_uid = option;
+			break;
+		case Opt_gid:
+			if (get_option_ul(args, &option)) {
+				cERROR(1, "%s: Invalid gid value",
+						__func__);
+				goto cifs_parse_mount_err;
+			}
+			vol->linux_gid = option;
+			gid_specified = true;
+			break;
+		case Opt_file_mode:
+			if (get_option_ul(args, &option)) {
+				cERROR(1, "%s: Invalid file_mode value",
+					__func__);
+				goto cifs_parse_mount_err;
+			}
+			vol->file_mode = option;
+			break;
+		case Opt_dirmode:
+			if (get_option_ul(args, &option)) {
+				cERROR(1, "%s: Invalid dir_mode value",
+					__func__);
+				goto cifs_parse_mount_err;
+			}
+			vol->dir_mode = option;
+			break;
+		case Opt_port:
+			if (get_option_ul(args, &option)) {
+				cERROR(1, "%s: Invalid port value",
+					__func__);
+				goto cifs_parse_mount_err;
+			}
+			vol->port = option;
+			break;
+		case Opt_rsize:
+			if (get_option_ul(args, &option)) {
+				cERROR(1, "%s: Invalid rsize value",
+					__func__);
+				goto cifs_parse_mount_err;
+			}
+			vol->rsize = option;
+			break;
+		case Opt_wsize:
+			if (get_option_ul(args, &option)) {
+				cERROR(1, "%s: Invalid wsize value",
+					__func__);
+				goto cifs_parse_mount_err;
+			}
+			vol->wsize = option;
+			break;
+		case Opt_actimeo:
+			if (get_option_ul(args, &option)) {
+				cERROR(1, "%s: Invalid actimeo value",
+					__func__);
+				goto cifs_parse_mount_err;
+			}
+			vol->actimeo = HZ * option;
+			if (vol->actimeo > CIFS_MAX_ACTIMEO) {
+				cERROR(1, "CIFS: attribute cache"
+					  "timeout too large");
+				goto cifs_parse_mount_err;
+			}
+			break;
+
+		/* String Arguments */
+
+		case Opt_user:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+
+			if (!*string) {
+				/* null user, ie. anonymous authentication */
+				vol->nullauth = 1;
+			} else if (strnlen(string, MAX_USERNAME_SIZE) >
+							MAX_USERNAME_SIZE) {
+				printk(KERN_WARNING "CIFS: username too long\n");
+				goto cifs_parse_mount_err;
+			}
+			vol->username = kstrdup(string, GFP_KERNEL);
+			if (!vol->username) {
+				printk(KERN_WARNING "CIFS: no memory "
+						    "for username\n");
+				goto cifs_parse_mount_err;
+			}
+			break;
+		case Opt_blank_pass:
+			vol->password = NULL;
+			break;
+		case Opt_pass:
+			/* passwords have to be handled differently
+			 * to allow the character used for deliminator
+			 * to be passed within them
+			 */
+
+			/* Obtain the value string */
+			value = strchr(data, '=');
+			value++;
+
+			/* Set tmp_end to end of the string */
+			tmp_end = (char *) value + strlen(value);
+
+			/* Check if following character is the deliminator
+			 * If yes, we have encountered a double deliminator
+			 * reset the NULL character to the deliminator
+			 */
+			if (tmp_end < end && tmp_end[1] == delim)
+				tmp_end[0] = delim;
+
+			/* Keep iterating until we get to a single deliminator
+			 * OR the end
+			 */
+			while ((tmp_end = strchr(tmp_end, delim)) != NULL &&
+			       (tmp_end[1] == delim)) {
+				tmp_end = (char *) &tmp_end[2];
+			}
+
+			/* Reset var options to point to next element */
+			if (tmp_end) {
+				tmp_end[0] = '\0';
+				options = (char *) &tmp_end[1];
+			} else
+				/* Reached the end of the mount option string */
+				options = end;
+
+			/* Now build new password string */
+			temp_len = strlen(value);
+			vol->password = kzalloc(temp_len+1, GFP_KERNEL);
+			if (vol->password == NULL) {
+				printk(KERN_WARNING "CIFS: no memory "
+						    "for password\n");
+				goto cifs_parse_mount_err;
+			}
+
+			for (i = 0, j = 0; i < temp_len; i++, j++) {
+				vol->password[j] = value[i];
+				if ((value[i] == delim) &&
+				     value[i+1] == delim)
+					/* skip the second deliminator */
+					i++;
+			}
+			vol->password[j] = '\0';
+			break;
+		case Opt_ip:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+
+			if (!*string) {
+				vol->UNCip = NULL;
+			} else if (strnlen(string, INET6_ADDRSTRLEN) >
+						INET6_ADDRSTRLEN) {
+				printk(KERN_WARNING "CIFS: ip address "
+						    "too long\n");
+				goto cifs_parse_mount_err;
+			}
+			vol->UNCip = kstrdup(string, GFP_KERNEL);
+			if (!vol->UNCip) {
+				printk(KERN_WARNING "CIFS: no memory "
+						    "for UNC IP\n");
+				goto cifs_parse_mount_err;
+			}
+			break;
+		case Opt_unc:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+
+			if (!*string) {
+				printk(KERN_WARNING "CIFS: invalid path to "
+						    "network resource\n");
+				goto cifs_parse_mount_err;
+			}
+
+			temp_len = strnlen(string, 300);
+			if (temp_len  == 300) {
+				printk(KERN_WARNING "CIFS: UNC name too long\n");
+				goto cifs_parse_mount_err;
+			}
+
+			vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
+			if (vol->UNC == NULL) {
+				printk(KERN_WARNING "CIFS: no memory for UNC\n");
+				goto cifs_parse_mount_err;
+			}
+			strcpy(vol->UNC, string);
+
+			if (strncmp(string, "//", 2) == 0) {
+				vol->UNC[0] = '\\';
+				vol->UNC[1] = '\\';
+			} else if (strncmp(string, "\\\\", 2) != 0) {
+				printk(KERN_WARNING "CIFS: UNC Path does not "
+						    "begin with // or \\\\\n");
+				goto cifs_parse_mount_err;
+			}
+
+			break;
+		case Opt_domain:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+
+			if (!*string) {
+				printk(KERN_WARNING "CIFS: invalid domain"
+						    " name\n");
+				goto cifs_parse_mount_err;
+			} else if (strnlen(string, 256) == 256) {
+				printk(KERN_WARNING "CIFS: domain name too"
+						    " long\n");
+				goto cifs_parse_mount_err;
+			}
+
+			vol->domainname = kstrdup(string, GFP_KERNEL);
+			if (!vol->domainname) {
+				printk(KERN_WARNING "CIFS: no memory "
+						    "for domainname\n");
+				goto cifs_parse_mount_err;
+			}
+			cFYI(1, "Domain name set");
+			break;
+		case Opt_srcaddr:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+
+			if (!*string) {
+				printk(KERN_WARNING "CIFS: srcaddr value not"
+						    " specified\n");
+				goto cifs_parse_mount_err;
+			} else if (!cifs_convert_address(
+					(struct sockaddr *)&vol->srcaddr,
+					string, strlen(string))) {
+				printk(KERN_WARNING "CIFS:  Could not parse"
+						    " srcaddr: %s\n", string);
+				goto cifs_parse_mount_err;
+			}
+			break;
+		case Opt_prefixpath:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+
+			if (!*string) {
+				printk(KERN_WARNING "CIFS: Invalid path"
+						    " prefix\n");
+				goto cifs_parse_mount_err;
+			}
+			temp_len = strnlen(string, 1024);
+			if (string[0] != '/')
+				temp_len++; /* missing leading slash */
+			if (temp_len > 1024) {
+				printk(KERN_WARNING "CIFS: prefix too long\n");
+				goto cifs_parse_mount_err;
+			}
+
+			vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
+			if (vol->prepath == NULL) {
+				printk(KERN_WARNING "CIFS: no memory "
+						    "for path prefix\n");
+				goto cifs_parse_mount_err;
+			}
+
+			if (string[0] != '/') {
+				vol->prepath[0] = '/';
+				strcpy(vol->prepath+1, string);
+			} else
+				strcpy(vol->prepath, string);
+
+			break;
+		case Opt_iocharset:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+
+			if (!*string) {
+				printk(KERN_WARNING "CIFS: Invalid iocharset"
+						    " specified\n");
+				goto cifs_parse_mount_err;
+			} else if (strnlen(string, 1024) >= 65) {
+				printk(KERN_WARNING "CIFS: iocharset name "
+						    "too long.\n");
+				goto cifs_parse_mount_err;
+			}
+
+			 if (strnicmp(string, "default", 7) != 0) {
+				vol->iocharset = kstrdup(string,
+							 GFP_KERNEL);
+				if (!vol->iocharset) {
+					printk(KERN_WARNING "CIFS: no memory"
+							    "for charset\n");
+					goto cifs_parse_mount_err;
+				}
+			}
+			/* if iocharset not set then load_nls_default
+			 * is used by caller
+			 */
+			cFYI(1, "iocharset set to %s", string);
+			break;
+		case Opt_sockopt:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+
+			if (!*string) {
+				printk(KERN_WARNING "CIFS: No socket option"
+						    " specified\n");
+				goto cifs_parse_mount_err;
+			}
+			if (strnicmp(string, "TCP_NODELAY", 11) == 0)
+				vol->sockopt_tcp_nodelay = 1;
+			break;
+		case Opt_netbiosname:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+
+			if (!*string) {
+				printk(KERN_WARNING "CIFS: Invalid (empty)"
+						    " netbiosname\n");
+				break;
+			}
+
+			memset(vol->source_rfc1001_name, 0x20,
+				RFC1001_NAME_LEN);
+			/*
+			 * FIXME: are there cases in which a comma can
+			 * be valid in workstation netbios name (and
+			 * need special handling)?
+			 */
+			for (i = 0; i < RFC1001_NAME_LEN; i++) {
+				/* don't ucase netbiosname for user */
+				if (string[i] == 0)
+					break;
+				vol->source_rfc1001_name[i] = string[i];
+			}
+			/* The string has 16th byte zero still from
+			 * set at top of the function
+			 */
+			if (i == RFC1001_NAME_LEN && string[i] != 0)
+				printk(KERN_WARNING "CIFS: netbiosname"
+				       " longer than 15 truncated.\n");
+
+			break;
+		case Opt_servern:
+			/* servernetbiosname specified override *SMBSERVER */
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+
+			if (!*string) {
+				printk(KERN_WARNING "CIFS: Empty server"
+					" netbiosname specified\n");
+				break;
+			}
+			/* last byte, type, is 0x20 for servr type */
+			memset(vol->target_rfc1001_name, 0x20,
+				RFC1001_NAME_LEN_WITH_NULL);
+
+			/* BB are there cases in which a comma can be
+			   valid in this workstation netbios name
+			   (and need special handling)? */
+
+			/* user or mount helper must uppercase the
+			   netbios name */
+			for (i = 0; i < 15; i++) {
+				if (string[i] == 0)
+					break;
+				vol->target_rfc1001_name[i] = string[i];
+			}
+			/* The string has 16th byte zero still from
+			   set at top of the function  */
+			if (i == RFC1001_NAME_LEN && string[i] != 0)
+				printk(KERN_WARNING "CIFS: server net"
+				       "biosname longer than 15 truncated.\n");
+			break;
+		case Opt_ver:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+
+			if (!*string) {
+				cERROR(1, "no protocol version specified"
+					  " after vers= mount option");
+				goto cifs_parse_mount_err;
+			}
+
+			if (strnicmp(string, "cifs", 4) == 0 ||
+			    strnicmp(string, "1", 1) == 0) {
+				/* This is the default */
+				break;
+			}
+			/* For all other value, error */
+			printk(KERN_WARNING "CIFS: Invalid version"
+					    " specified\n");
 			goto cifs_parse_mount_err;
+		case Opt_sec:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+
+			if (!*string) {
+				printk(KERN_WARNING "CIFS: no security flavor"
+						    " specified\n");
+				break;
+			}
+
+			if (cifs_parse_security_flavors(string, vol) != 0)
+				goto cifs_parse_mount_err;
+			break;
+		default:
+			/*
+			 * An option we don't recognize. Save it off for later
+			 * if we haven't already found one
+			 */
+			if (!invalid)
+				invalid = data;
+			break;
 		}
+		/* Free up any allocated string */
+		kfree(string);
+		string = NULL;
+	}
+
+	if (!sloppy && invalid) {
+		printk(KERN_ERR "CIFS: Unknown mount option \"%s\"\n", invalid);
+		goto cifs_parse_mount_err;
 	}
 
 #ifndef CONFIG_KEYS
@@ -1623,7 +1923,10 @@
 	kfree(mountdata_copy);
 	return 0;
 
+out_nomem:
+	printk(KERN_WARNING "Could not allocate temporary buffer\n");
 cifs_parse_mount_err:
+	kfree(string);
 	kfree(mountdata_copy);
 	return 1;
 }
@@ -1909,7 +2212,8 @@
 	tcp_ses->noblocksnd = volume_info->noblocksnd;
 	tcp_ses->noautotune = volume_info->noautotune;
 	tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
-	atomic_set(&tcp_ses->inFlight, 0);
+	tcp_ses->in_flight = 0;
+	tcp_ses->credits = 1;
 	init_waitqueue_head(&tcp_ses->response_q);
 	init_waitqueue_head(&tcp_ses->request_q);
 	INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
@@ -1974,7 +2278,7 @@
 	cifs_fscache_get_client_cookie(tcp_ses);
 
 	/* queue echo request delayed work */
-	queue_delayed_work(system_nrt_wq, &tcp_ses->echo, SMB_ECHO_INTERVAL);
+	queue_delayed_work(cifsiod_wq, &tcp_ses->echo, SMB_ECHO_INTERVAL);
 
 	return tcp_ses;
 
@@ -3371,7 +3675,7 @@
 int
 cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
 {
-	int rc = 0;
+	int rc;
 	int xid;
 	struct cifs_ses *pSesInfo;
 	struct cifs_tcon *tcon;
@@ -3398,6 +3702,7 @@
 		FreeXid(xid);
 	}
 #endif
+	rc = 0;
 	tcon = NULL;
 	pSesInfo = NULL;
 	srvTcp = NULL;
@@ -3539,7 +3844,7 @@
 	tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
 	spin_unlock(&cifs_sb->tlink_tree_lock);
 
-	queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
+	queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
 				TLINK_IDLE_EXPIRE);
 
 mount_fail_check:
@@ -3759,9 +4064,11 @@
 	if (server->maxBuf != 0)
 		return 0;
 
+	cifs_set_credits(server, 1);
 	rc = CIFSSMBNegotiate(xid, ses);
 	if (rc == -EAGAIN) {
 		/* retry only once on 1st time connection */
+		cifs_set_credits(server, 1);
 		rc = CIFSSMBNegotiate(xid, ses);
 		if (rc == -EAGAIN)
 			rc = -EHOSTDOWN;
@@ -4091,6 +4398,6 @@
 	}
 	spin_unlock(&cifs_sb->tlink_tree_lock);
 
-	queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
+	queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
 				TLINK_IDLE_EXPIRE);
 }
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index bc7e244..d172c8e 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -171,7 +171,7 @@
 	}
 	tcon = tlink_tcon(tlink);
 
-	if (enable_oplocks)
+	if (tcon->ses->server->oplocks)
 		oplock = REQ_OPLOCK;
 
 	if (nd)
@@ -492,7 +492,7 @@
 {
 	int xid;
 	int rc = 0; /* to get around spurious gcc warning, set to zero here */
-	__u32 oplock = enable_oplocks ? REQ_OPLOCK : 0;
+	__u32 oplock;
 	__u16 fileHandle = 0;
 	bool posix_open = false;
 	struct cifs_sb_info *cifs_sb;
@@ -518,6 +518,8 @@
 	}
 	pTcon = tlink_tcon(tlink);
 
+	oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0;
+
 	/*
 	 * Don't allow the separator character in a path component.
 	 * The VFS will not allow "/", but "\" is allowed by posix.
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 5e64748..fae765d 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -380,7 +380,7 @@
 	cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
 		 inode, file->f_flags, full_path);
 
-	if (enable_oplocks)
+	if (tcon->ses->server->oplocks)
 		oplock = REQ_OPLOCK;
 	else
 		oplock = 0;
@@ -505,7 +505,7 @@
 	cFYI(1, "inode = 0x%p file flags 0x%x for %s",
 		 inode, pCifsFile->f_flags, full_path);
 
-	if (enable_oplocks)
+	if (tcon->ses->server->oplocks)
 		oplock = REQ_OPLOCK;
 	else
 		oplock = 0;
@@ -835,13 +835,21 @@
 	if ((flock->fl_flags & FL_POSIX) == 0)
 		return rc;
 
+try_again:
 	mutex_lock(&cinode->lock_mutex);
 	if (!cinode->can_cache_brlcks) {
 		mutex_unlock(&cinode->lock_mutex);
 		return rc;
 	}
-	rc = posix_lock_file_wait(file, flock);
+
+	rc = posix_lock_file(file, flock, NULL);
 	mutex_unlock(&cinode->lock_mutex);
+	if (rc == FILE_LOCK_DEFERRED) {
+		rc = wait_event_interruptible(flock->fl_wait, !flock->fl_next);
+		if (!rc)
+			goto try_again;
+		locks_delete_block(flock);
+	}
 	return rc;
 }
 
@@ -960,9 +968,9 @@
 	INIT_LIST_HEAD(&locks_to_send);
 
 	/*
-	 * Allocating count locks is enough because no locks can be added to
-	 * the list while we are holding cinode->lock_mutex that protects
-	 * locking operations of this inode.
+	 * Allocating count locks is enough because no FL_POSIX locks can be
+	 * added to the list while we are holding cinode->lock_mutex that
+	 * protects locking operations of this inode.
 	 */
 	for (; i < count; i++) {
 		lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL);
@@ -973,18 +981,20 @@
 		list_add_tail(&lck->llist, &locks_to_send);
 	}
 
-	i = 0;
 	el = locks_to_send.next;
 	lock_flocks();
 	cifs_for_each_lock(cfile->dentry->d_inode, before) {
-		if (el == &locks_to_send) {
-			/* something is really wrong */
-			cERROR(1, "Can't push all brlocks!");
-			break;
-		}
 		flock = *before;
 		if ((flock->fl_flags & FL_POSIX) == 0)
 			continue;
+		if (el == &locks_to_send) {
+			/*
+			 * The list ended. We don't have enough allocated
+			 * structures - something is really wrong.
+			 */
+			cERROR(1, "Can't push all brlocks!");
+			break;
+		}
 		length = 1 + flock->fl_end - flock->fl_start;
 		if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK)
 			type = CIFS_RDLCK;
@@ -996,7 +1006,6 @@
 		lck->length = length;
 		lck->type = type;
 		lck->offset = flock->fl_start;
-		i++;
 		el = el->next;
 	}
 	unlock_flocks();
@@ -1398,7 +1407,10 @@
 	return rc;
 }
 
-/* update the file size (if needed) after a write */
+/*
+ * update the file size (if needed) after a write. Should be called with
+ * the inode->i_lock held
+ */
 void
 cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
 		      unsigned int bytes_written)
@@ -1470,7 +1482,9 @@
 				return rc;
 			}
 		} else {
+			spin_lock(&dentry->d_inode->i_lock);
 			cifs_update_eof(cifsi, *poffset, bytes_written);
+			spin_unlock(&dentry->d_inode->i_lock);
 			*poffset += bytes_written;
 		}
 	}
@@ -1647,6 +1661,27 @@
 	return rc;
 }
 
+/*
+ * Marshal up the iov array, reserving the first one for the header. Also,
+ * set wdata->bytes.
+ */
+static void
+cifs_writepages_marshal_iov(struct kvec *iov, struct cifs_writedata *wdata)
+{
+	int i;
+	struct inode *inode = wdata->cfile->dentry->d_inode;
+	loff_t size = i_size_read(inode);
+
+	/* marshal up the pages into iov array */
+	wdata->bytes = 0;
+	for (i = 0; i < wdata->nr_pages; i++) {
+		iov[i + 1].iov_len = min(size - page_offset(wdata->pages[i]),
+					(loff_t)PAGE_CACHE_SIZE);
+		iov[i + 1].iov_base = kmap(wdata->pages[i]);
+		wdata->bytes += iov[i + 1].iov_len;
+	}
+}
+
 static int cifs_writepages(struct address_space *mapping,
 			   struct writeback_control *wbc)
 {
@@ -1683,7 +1718,8 @@
 		tofind = min((cifs_sb->wsize / PAGE_CACHE_SIZE) - 1,
 				end - index) + 1;
 
-		wdata = cifs_writedata_alloc((unsigned int)tofind);
+		wdata = cifs_writedata_alloc((unsigned int)tofind,
+					     cifs_writev_complete);
 		if (!wdata) {
 			rc = -ENOMEM;
 			break;
@@ -1790,6 +1826,7 @@
 		wdata->sync_mode = wbc->sync_mode;
 		wdata->nr_pages = nr_pages;
 		wdata->offset = page_offset(wdata->pages[0]);
+		wdata->marshal_iov = cifs_writepages_marshal_iov;
 
 		do {
 			if (wdata->cfile != NULL)
@@ -1801,6 +1838,7 @@
 				rc = -EBADF;
 				break;
 			}
+			wdata->pid = wdata->cfile->pid;
 			rc = cifs_async_writev(wdata);
 		} while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
 
@@ -2042,7 +2080,7 @@
 	unsigned long i;
 
 	for (i = 0; i < num_pages; i++) {
-		pages[i] = alloc_page(__GFP_HIGHMEM);
+		pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
 		if (!pages[i]) {
 			/*
 			 * save number of pages we have already allocated and
@@ -2050,15 +2088,14 @@
 			 */
 			num_pages = i;
 			rc = -ENOMEM;
-			goto error;
+			break;
 		}
 	}
 
-	return rc;
-
-error:
-	for (i = 0; i < num_pages; i++)
-		put_page(pages[i]);
+	if (rc) {
+		for (i = 0; i < num_pages; i++)
+			put_page(pages[i]);
+	}
 	return rc;
 }
 
@@ -2069,9 +2106,7 @@
 	size_t clen;
 
 	clen = min_t(const size_t, len, wsize);
-	num_pages = clen / PAGE_CACHE_SIZE;
-	if (clen % PAGE_CACHE_SIZE)
-		num_pages++;
+	num_pages = DIV_ROUND_UP(clen, PAGE_SIZE);
 
 	if (cur_len)
 		*cur_len = clen;
@@ -2079,24 +2114,79 @@
 	return num_pages;
 }
 
+static void
+cifs_uncached_marshal_iov(struct kvec *iov, struct cifs_writedata *wdata)
+{
+	int i;
+	size_t bytes = wdata->bytes;
+
+	/* marshal up the pages into iov array */
+	for (i = 0; i < wdata->nr_pages; i++) {
+		iov[i + 1].iov_len = min_t(size_t, bytes, PAGE_SIZE);
+		iov[i + 1].iov_base = kmap(wdata->pages[i]);
+		bytes -= iov[i + 1].iov_len;
+	}
+}
+
+static void
+cifs_uncached_writev_complete(struct work_struct *work)
+{
+	int i;
+	struct cifs_writedata *wdata = container_of(work,
+					struct cifs_writedata, work);
+	struct inode *inode = wdata->cfile->dentry->d_inode;
+	struct cifsInodeInfo *cifsi = CIFS_I(inode);
+
+	spin_lock(&inode->i_lock);
+	cifs_update_eof(cifsi, wdata->offset, wdata->bytes);
+	if (cifsi->server_eof > inode->i_size)
+		i_size_write(inode, cifsi->server_eof);
+	spin_unlock(&inode->i_lock);
+
+	complete(&wdata->done);
+
+	if (wdata->result != -EAGAIN) {
+		for (i = 0; i < wdata->nr_pages; i++)
+			put_page(wdata->pages[i]);
+	}
+
+	kref_put(&wdata->refcount, cifs_writedata_release);
+}
+
+/* attempt to send write to server, retry on any -EAGAIN errors */
+static int
+cifs_uncached_retry_writev(struct cifs_writedata *wdata)
+{
+	int rc;
+
+	do {
+		if (wdata->cfile->invalidHandle) {
+			rc = cifs_reopen_file(wdata->cfile, false);
+			if (rc != 0)
+				continue;
+		}
+		rc = cifs_async_writev(wdata);
+	} while (rc == -EAGAIN);
+
+	return rc;
+}
+
 static ssize_t
 cifs_iovec_write(struct file *file, const struct iovec *iov,
 		 unsigned long nr_segs, loff_t *poffset)
 {
-	unsigned int written;
-	unsigned long num_pages, npages, i;
+	unsigned long nr_pages, i;
 	size_t copied, len, cur_len;
 	ssize_t total_written = 0;
-	struct kvec *to_send;
-	struct page **pages;
+	loff_t offset = *poffset;
 	struct iov_iter it;
-	struct inode *inode;
 	struct cifsFileInfo *open_file;
-	struct cifs_tcon *pTcon;
+	struct cifs_tcon *tcon;
 	struct cifs_sb_info *cifs_sb;
-	struct cifs_io_parms io_parms;
-	int xid, rc;
-	__u32 pid;
+	struct cifs_writedata *wdata, *tmp;
+	struct list_head wdata_list;
+	int rc;
+	pid_t pid;
 
 	len = iov_length(iov, nr_segs);
 	if (!len)
@@ -2106,103 +2196,103 @@
 	if (rc)
 		return rc;
 
+	INIT_LIST_HEAD(&wdata_list);
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	num_pages = get_numpages(cifs_sb->wsize, len, &cur_len);
-
-	pages = kmalloc(sizeof(struct pages *)*num_pages, GFP_KERNEL);
-	if (!pages)
-		return -ENOMEM;
-
-	to_send = kmalloc(sizeof(struct kvec)*(num_pages + 1), GFP_KERNEL);
-	if (!to_send) {
-		kfree(pages);
-		return -ENOMEM;
-	}
-
-	rc = cifs_write_allocate_pages(pages, num_pages);
-	if (rc) {
-		kfree(pages);
-		kfree(to_send);
-		return rc;
-	}
-
-	xid = GetXid();
 	open_file = file->private_data;
+	tcon = tlink_tcon(open_file->tlink);
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
 		pid = open_file->pid;
 	else
 		pid = current->tgid;
 
-	pTcon = tlink_tcon(open_file->tlink);
-	inode = file->f_path.dentry->d_inode;
-
 	iov_iter_init(&it, iov, nr_segs, len, 0);
-	npages = num_pages;
-
 	do {
-		size_t save_len = cur_len;
-		for (i = 0; i < npages; i++) {
-			copied = min_t(const size_t, cur_len, PAGE_CACHE_SIZE);
-			copied = iov_iter_copy_from_user(pages[i], &it, 0,
-							 copied);
-			cur_len -= copied;
-			iov_iter_advance(&it, copied);
-			to_send[i+1].iov_base = kmap(pages[i]);
-			to_send[i+1].iov_len = copied;
-		}
+		size_t save_len;
 
-		cur_len = save_len - cur_len;
-
-		do {
-			if (open_file->invalidHandle) {
-				rc = cifs_reopen_file(open_file, false);
-				if (rc != 0)
-					break;
-			}
-			io_parms.netfid = open_file->netfid;
-			io_parms.pid = pid;
-			io_parms.tcon = pTcon;
-			io_parms.offset = *poffset;
-			io_parms.length = cur_len;
-			rc = CIFSSMBWrite2(xid, &io_parms, &written, to_send,
-					   npages, 0);
-		} while (rc == -EAGAIN);
-
-		for (i = 0; i < npages; i++)
-			kunmap(pages[i]);
-
-		if (written) {
-			len -= written;
-			total_written += written;
-			cifs_update_eof(CIFS_I(inode), *poffset, written);
-			*poffset += written;
-		} else if (rc < 0) {
-			if (!total_written)
-				total_written = rc;
+		nr_pages = get_numpages(cifs_sb->wsize, len, &cur_len);
+		wdata = cifs_writedata_alloc(nr_pages,
+					     cifs_uncached_writev_complete);
+		if (!wdata) {
+			rc = -ENOMEM;
 			break;
 		}
 
-		/* get length and number of kvecs of the next write */
-		npages = get_numpages(cifs_sb->wsize, len, &cur_len);
+		rc = cifs_write_allocate_pages(wdata->pages, nr_pages);
+		if (rc) {
+			kfree(wdata);
+			break;
+		}
+
+		save_len = cur_len;
+		for (i = 0; i < nr_pages; i++) {
+			copied = min_t(const size_t, cur_len, PAGE_SIZE);
+			copied = iov_iter_copy_from_user(wdata->pages[i], &it,
+							 0, copied);
+			cur_len -= copied;
+			iov_iter_advance(&it, copied);
+		}
+		cur_len = save_len - cur_len;
+
+		wdata->sync_mode = WB_SYNC_ALL;
+		wdata->nr_pages = nr_pages;
+		wdata->offset = (__u64)offset;
+		wdata->cfile = cifsFileInfo_get(open_file);
+		wdata->pid = pid;
+		wdata->bytes = cur_len;
+		wdata->marshal_iov = cifs_uncached_marshal_iov;
+		rc = cifs_uncached_retry_writev(wdata);
+		if (rc) {
+			kref_put(&wdata->refcount, cifs_writedata_release);
+			break;
+		}
+
+		list_add_tail(&wdata->list, &wdata_list);
+		offset += cur_len;
+		len -= cur_len;
 	} while (len > 0);
 
-	if (total_written > 0) {
-		spin_lock(&inode->i_lock);
-		if (*poffset > inode->i_size)
-			i_size_write(inode, *poffset);
-		spin_unlock(&inode->i_lock);
+	/*
+	 * If at least one write was successfully sent, then discard any rc
+	 * value from the later writes. If the other write succeeds, then
+	 * we'll end up returning whatever was written. If it fails, then
+	 * we'll get a new rc value from that.
+	 */
+	if (!list_empty(&wdata_list))
+		rc = 0;
+
+	/*
+	 * Wait for and collect replies for any successful sends in order of
+	 * increasing offset. Once an error is hit or we get a fatal signal
+	 * while waiting, then return without waiting for any more replies.
+	 */
+restart_loop:
+	list_for_each_entry_safe(wdata, tmp, &wdata_list, list) {
+		if (!rc) {
+			/* FIXME: freezable too? */
+			rc = wait_for_completion_killable(&wdata->done);
+			if (rc)
+				rc = -EINTR;
+			else if (wdata->result)
+				rc = wdata->result;
+			else
+				total_written += wdata->bytes;
+
+			/* resend call if it's a retryable error */
+			if (rc == -EAGAIN) {
+				rc = cifs_uncached_retry_writev(wdata);
+				goto restart_loop;
+			}
+		}
+		list_del_init(&wdata->list);
+		kref_put(&wdata->refcount, cifs_writedata_release);
 	}
 
-	cifs_stats_bytes_written(pTcon, total_written);
-	mark_inode_dirty_sync(inode);
+	if (total_written > 0)
+		*poffset += total_written;
 
-	for (i = 0; i < num_pages; i++)
-		put_page(pages[i]);
-	kfree(to_send);
-	kfree(pages);
-	FreeXid(xid);
-	return total_written;
+	cifs_stats_bytes_written(tcon, total_written);
+	return total_written ? total_written : (ssize_t)rc;
 }
 
 ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 703ef5c..c29d1aa 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -213,55 +213,62 @@
 }
 
 /*
-	Find a free multiplex id (SMB mid). Otherwise there could be
-	mid collisions which might cause problems, demultiplexing the
-	wrong response to this request. Multiplex ids could collide if
-	one of a series requests takes much longer than the others, or
-	if a very large number of long lived requests (byte range
-	locks or FindNotify requests) are pending.  No more than
-	64K-1 requests can be outstanding at one time.  If no
-	mids are available, return zero.  A future optimization
-	could make the combination of mids and uid the key we use
-	to demultiplex on (rather than mid alone).
-	In addition to the above check, the cifs demultiplex
-	code already used the command code as a secondary
-	check of the frame and if signing is negotiated the
-	response would be discarded if the mid were the same
-	but the signature was wrong.  Since the mid is not put in the
-	pending queue until later (when it is about to be dispatched)
-	we do have to limit the number of outstanding requests
-	to somewhat less than 64K-1 although it is hard to imagine
-	so many threads being in the vfs at one time.
-*/
-__u16 GetNextMid(struct TCP_Server_Info *server)
+ * Find a free multiplex id (SMB mid). Otherwise there could be
+ * mid collisions which might cause problems, demultiplexing the
+ * wrong response to this request. Multiplex ids could collide if
+ * one of a series requests takes much longer than the others, or
+ * if a very large number of long lived requests (byte range
+ * locks or FindNotify requests) are pending. No more than
+ * 64K-1 requests can be outstanding at one time. If no
+ * mids are available, return zero. A future optimization
+ * could make the combination of mids and uid the key we use
+ * to demultiplex on (rather than mid alone).
+ * In addition to the above check, the cifs demultiplex
+ * code already used the command code as a secondary
+ * check of the frame and if signing is negotiated the
+ * response would be discarded if the mid were the same
+ * but the signature was wrong. Since the mid is not put in the
+ * pending queue until later (when it is about to be dispatched)
+ * we do have to limit the number of outstanding requests
+ * to somewhat less than 64K-1 although it is hard to imagine
+ * so many threads being in the vfs at one time.
+ */
+__u64 GetNextMid(struct TCP_Server_Info *server)
 {
-	__u16 mid = 0;
-	__u16 last_mid;
+	__u64 mid = 0;
+	__u16 last_mid, cur_mid;
 	bool collision;
 
 	spin_lock(&GlobalMid_Lock);
-	last_mid = server->CurrentMid; /* we do not want to loop forever */
-	server->CurrentMid++;
-	/* This nested loop looks more expensive than it is.
-	In practice the list of pending requests is short,
-	fewer than 50, and the mids are likely to be unique
-	on the first pass through the loop unless some request
-	takes longer than the 64 thousand requests before it
-	(and it would also have to have been a request that
-	 did not time out) */
-	while (server->CurrentMid != last_mid) {
+
+	/* mid is 16 bit only for CIFS/SMB */
+	cur_mid = (__u16)((server->CurrentMid) & 0xffff);
+	/* we do not want to loop forever */
+	last_mid = cur_mid;
+	cur_mid++;
+
+	/*
+	 * This nested loop looks more expensive than it is.
+	 * In practice the list of pending requests is short,
+	 * fewer than 50, and the mids are likely to be unique
+	 * on the first pass through the loop unless some request
+	 * takes longer than the 64 thousand requests before it
+	 * (and it would also have to have been a request that
+	 * did not time out).
+	 */
+	while (cur_mid != last_mid) {
 		struct mid_q_entry *mid_entry;
 		unsigned int num_mids;
 
 		collision = false;
-		if (server->CurrentMid == 0)
-			server->CurrentMid++;
+		if (cur_mid == 0)
+			cur_mid++;
 
 		num_mids = 0;
 		list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
 			++num_mids;
-			if (mid_entry->mid == server->CurrentMid &&
-			    mid_entry->midState == MID_REQUEST_SUBMITTED) {
+			if (mid_entry->mid == cur_mid &&
+			    mid_entry->mid_state == MID_REQUEST_SUBMITTED) {
 				/* This mid is in use, try a different one */
 				collision = true;
 				break;
@@ -282,10 +289,11 @@
 			server->tcpStatus = CifsNeedReconnect;
 
 		if (!collision) {
-			mid = server->CurrentMid;
+			mid = (__u64)cur_mid;
+			server->CurrentMid = mid;
 			break;
 		}
-		server->CurrentMid++;
+		cur_mid++;
 	}
 	spin_unlock(&GlobalMid_Lock);
 	return mid;
@@ -420,8 +428,10 @@
 }
 
 int
-checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int total_read)
+checkSMB(char *buf, unsigned int total_read)
 {
+	struct smb_hdr *smb = (struct smb_hdr *)buf;
+	__u16 mid = smb->Mid;
 	__u32 rfclen = be32_to_cpu(smb->smb_buf_length);
 	__u32 clc_len;  /* calculated length */
 	cFYI(0, "checkSMB Length: 0x%x, smb_buf_length: 0x%x",
@@ -502,8 +512,9 @@
 }
 
 bool
-is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
+is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
 {
+	struct smb_hdr *buf = (struct smb_hdr *)buffer;
 	struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
 	struct list_head *tmp, *tmp1, *tmp2;
 	struct cifs_ses *ses;
@@ -584,7 +595,7 @@
 
 				cifs_set_oplock_level(pCifsInode,
 					pSMB->OplockLevel ? OPLOCK_READ : 0);
-				queue_work(system_nrt_wq,
+				queue_work(cifsiod_wq,
 					   &netfile->oplock_break);
 				netfile->oplock_break_cancelled = false;
 
@@ -604,16 +615,15 @@
 }
 
 void
-dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
+dump_smb(void *buf, int smb_buf_length)
 {
 	int i, j;
 	char debug_line[17];
-	unsigned char *buffer;
+	unsigned char *buffer = buf;
 
 	if (traceSMB == 0)
 		return;
 
-	buffer = (unsigned char *) smb_buf;
 	for (i = 0, j = 0; i < smb_buf_length; i++, j++) {
 		if (i % 8 == 0) {
 			/* have reached the beginning of line */
@@ -690,3 +700,22 @@
 
 	return false;
 }
+
+void
+cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add)
+{
+	spin_lock(&server->req_lock);
+	server->credits += add;
+	server->in_flight--;
+	spin_unlock(&server->req_lock);
+	wake_up(&server->request_q);
+}
+
+void
+cifs_set_credits(struct TCP_Server_Info *server, const int val)
+{
+	spin_lock(&server->req_lock);
+	server->credits = val;
+	server->oplocks = val > 1 ? enable_oplocks : false;
+	spin_unlock(&server->req_lock);
+}
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 73e47e8..581c225 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -197,8 +197,7 @@
 		memcpy(scope_id, pct + 1, slen);
 		scope_id[slen] = '\0';
 
-		rc = strict_strtoul(scope_id, 0,
-					(unsigned long *)&s6->sin6_scope_id);
+		rc = kstrtouint(scope_id, 0, &s6->sin6_scope_id);
 		rc = (rc == 0) ? 1 : 0;
 	}
 
@@ -836,8 +835,9 @@
 }
 
 int
-map_smb_to_linux_error(struct smb_hdr *smb, bool logErr)
+map_smb_to_linux_error(char *buf, bool logErr)
 {
+	struct smb_hdr *smb = (struct smb_hdr *)buf;
 	unsigned int i;
 	int rc = -EIO;	/* if transport error smb error may not be set */
 	__u8 smberrclass;
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 0cc9584..0961336 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -60,8 +60,8 @@
 		memset(temp, 0, sizeof(struct mid_q_entry));
 		temp->mid = smb_buffer->Mid;	/* always LE */
 		temp->pid = current->pid;
-		temp->command = smb_buffer->Command;
-		cFYI(1, "For smb_command %d", temp->command);
+		temp->command = cpu_to_le16(smb_buffer->Command);
+		cFYI(1, "For smb_command %d", smb_buffer->Command);
 	/*	do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
 		/* when mid allocated can be before when sent */
 		temp->when_alloc = jiffies;
@@ -75,7 +75,7 @@
 	}
 
 	atomic_inc(&midCount);
-	temp->midState = MID_REQUEST_ALLOCATED;
+	temp->mid_state = MID_REQUEST_ALLOCATED;
 	return temp;
 }
 
@@ -85,9 +85,9 @@
 #ifdef CONFIG_CIFS_STATS2
 	unsigned long now;
 #endif
-	midEntry->midState = MID_FREE;
+	midEntry->mid_state = MID_FREE;
 	atomic_dec(&midCount);
-	if (midEntry->largeBuf)
+	if (midEntry->large_buf)
 		cifs_buf_release(midEntry->resp_buf);
 	else
 		cifs_small_buf_release(midEntry->resp_buf);
@@ -97,8 +97,8 @@
 	   something is wrong, unless it is quite a slow link or server */
 	if ((now - midEntry->when_alloc) > HZ) {
 		if ((cifsFYI & CIFS_TIMER) &&
-		   (midEntry->command != SMB_COM_LOCKING_ANDX)) {
-			printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
+		    (midEntry->command != cpu_to_le16(SMB_COM_LOCKING_ANDX))) {
+			printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %llu",
 			       midEntry->command, midEntry->mid);
 			printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
 			       now - midEntry->when_alloc,
@@ -126,11 +126,11 @@
 	int rc = 0;
 	int i = 0;
 	struct msghdr smb_msg;
-	struct smb_hdr *smb_buffer = iov[0].iov_base;
+	__be32 *buf_len = (__be32 *)(iov[0].iov_base);
 	unsigned int len = iov[0].iov_len;
 	unsigned int total_len;
 	int first_vec = 0;
-	unsigned int smb_buf_length = be32_to_cpu(smb_buffer->smb_buf_length);
+	unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
 	struct socket *ssocket = server->ssocket;
 
 	if (ssocket == NULL)
@@ -150,7 +150,7 @@
 		total_len += iov[i].iov_len;
 
 	cFYI(1, "Sending smb:  total_len %d", total_len);
-	dump_smb(smb_buffer, len);
+	dump_smb(iov[0].iov_base, len);
 
 	i = 0;
 	while (total_len) {
@@ -158,24 +158,24 @@
 				    n_vec - first_vec, total_len);
 		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
 			i++;
-			/* if blocking send we try 3 times, since each can block
-			   for 5 seconds. For nonblocking  we have to try more
-			   but wait increasing amounts of time allowing time for
-			   socket to clear.  The overall time we wait in either
-			   case to send on the socket is about 15 seconds.
-			   Similarly we wait for 15 seconds for
-			   a response from the server in SendReceive[2]
-			   for the server to send a response back for
-			   most types of requests (except SMB Write
-			   past end of file which can be slow, and
-			   blocking lock operations). NFS waits slightly longer
-			   than CIFS, but this can make it take longer for
-			   nonresponsive servers to be detected and 15 seconds
-			   is more than enough time for modern networks to
-			   send a packet.  In most cases if we fail to send
-			   after the retries we will kill the socket and
-			   reconnect which may clear the network problem.
-			*/
+			/*
+			 * If blocking send we try 3 times, since each can block
+			 * for 5 seconds. For nonblocking  we have to try more
+			 * but wait increasing amounts of time allowing time for
+			 * socket to clear.  The overall time we wait in either
+			 * case to send on the socket is about 15 seconds.
+			 * Similarly we wait for 15 seconds for a response from
+			 * the server in SendReceive[2] for the server to send
+			 * a response back for most types of requests (except
+			 * SMB Write past end of file which can be slow, and
+			 * blocking lock operations). NFS waits slightly longer
+			 * than CIFS, but this can make it take longer for
+			 * nonresponsive servers to be detected and 15 seconds
+			 * is more than enough time for modern networks to
+			 * send a packet.  In most cases if we fail to send
+			 * after the retries we will kill the socket and
+			 * reconnect which may clear the network problem.
+			 */
 			if ((i >= 14) || (!server->noblocksnd && (i > 2))) {
 				cERROR(1, "sends on sock %p stuck for 15 seconds",
 				    ssocket);
@@ -235,9 +235,8 @@
 	else
 		rc = 0;
 
-	/* Don't want to modify the buffer as a
-	   side effect of this call. */
-	smb_buffer->smb_buf_length = cpu_to_be32(smb_buf_length);
+	/* Don't want to modify the buffer as a side effect of this call. */
+	*buf_len = cpu_to_be32(smb_buf_length);
 
 	return rc;
 }
@@ -254,44 +253,60 @@
 	return smb_sendv(server, &iov, 1);
 }
 
-static int wait_for_free_request(struct TCP_Server_Info *server,
-				 const int long_op)
+static int
+wait_for_free_credits(struct TCP_Server_Info *server, const int optype,
+		      int *credits)
 {
-	if (long_op == CIFS_ASYNC_OP) {
+	int rc;
+
+	spin_lock(&server->req_lock);
+	if (optype == CIFS_ASYNC_OP) {
 		/* oplock breaks must not be held up */
-		atomic_inc(&server->inFlight);
+		server->in_flight++;
+		*credits -= 1;
+		spin_unlock(&server->req_lock);
 		return 0;
 	}
 
-	spin_lock(&GlobalMid_Lock);
 	while (1) {
-		if (atomic_read(&server->inFlight) >= cifs_max_pending) {
-			spin_unlock(&GlobalMid_Lock);
+		if (*credits <= 0) {
+			spin_unlock(&server->req_lock);
 			cifs_num_waiters_inc(server);
-			wait_event(server->request_q,
-				   atomic_read(&server->inFlight)
-				     < cifs_max_pending);
+			rc = wait_event_killable(server->request_q,
+						 has_credits(server, credits));
 			cifs_num_waiters_dec(server);
-			spin_lock(&GlobalMid_Lock);
+			if (rc)
+				return rc;
+			spin_lock(&server->req_lock);
 		} else {
 			if (server->tcpStatus == CifsExiting) {
-				spin_unlock(&GlobalMid_Lock);
+				spin_unlock(&server->req_lock);
 				return -ENOENT;
 			}
 
-			/* can not count locking commands against total
-			   as they are allowed to block on server */
+			/*
+			 * Can not count locking commands against total
+			 * as they are allowed to block on server.
+			 */
 
 			/* update # of requests on the wire to server */
-			if (long_op != CIFS_BLOCKING_OP)
-				atomic_inc(&server->inFlight);
-			spin_unlock(&GlobalMid_Lock);
+			if (optype != CIFS_BLOCKING_OP) {
+				*credits -= 1;
+				server->in_flight++;
+			}
+			spin_unlock(&server->req_lock);
 			break;
 		}
 	}
 	return 0;
 }
 
+static int
+wait_for_free_request(struct TCP_Server_Info *server, const int optype)
+{
+	return wait_for_free_credits(server, optype, get_credits_field(server));
+}
+
 static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
 			struct mid_q_entry **ppmidQ)
 {
@@ -326,13 +341,40 @@
 	int error;
 
 	error = wait_event_freezekillable(server->response_q,
-				    midQ->midState != MID_REQUEST_SUBMITTED);
+				    midQ->mid_state != MID_REQUEST_SUBMITTED);
 	if (error < 0)
 		return -ERESTARTSYS;
 
 	return 0;
 }
 
+static int
+cifs_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov,
+			 unsigned int nvec, struct mid_q_entry **ret_mid)
+{
+	int rc;
+	struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
+	struct mid_q_entry *mid;
+
+	/* enable signing if server requires it */
+	if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+		hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+	mid = AllocMidQEntry(hdr, server);
+	if (mid == NULL)
+		return -ENOMEM;
+
+	/* put it on the pending_mid_q */
+	spin_lock(&GlobalMid_Lock);
+	list_add_tail(&mid->qhead, &server->pending_mid_q);
+	spin_unlock(&GlobalMid_Lock);
+
+	rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number);
+	if (rc)
+		delete_mid(mid);
+	*ret_mid = mid;
+	return rc;
+}
 
 /*
  * Send a SMB request and set the callback function in the mid to handle
@@ -345,40 +387,24 @@
 {
 	int rc;
 	struct mid_q_entry *mid;
-	struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
 
 	rc = wait_for_free_request(server, ignore_pend ? CIFS_ASYNC_OP : 0);
 	if (rc)
 		return rc;
 
-	/* enable signing if server requires it */
-	if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-		hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-
 	mutex_lock(&server->srv_mutex);
-	mid = AllocMidQEntry(hdr, server);
-	if (mid == NULL) {
-		mutex_unlock(&server->srv_mutex);
-		atomic_dec(&server->inFlight);
-		wake_up(&server->request_q);
-		return -ENOMEM;
-	}
-
-	/* put it on the pending_mid_q */
-	spin_lock(&GlobalMid_Lock);
-	list_add_tail(&mid->qhead, &server->pending_mid_q);
-	spin_unlock(&GlobalMid_Lock);
-
-	rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number);
+	rc = cifs_setup_async_request(server, iov, nvec, &mid);
 	if (rc) {
 		mutex_unlock(&server->srv_mutex);
-		goto out_err;
+		cifs_add_credits(server, 1);
+		wake_up(&server->request_q);
+		return rc;
 	}
 
 	mid->receive = receive;
 	mid->callback = callback;
 	mid->callback_data = cbdata;
-	mid->midState = MID_REQUEST_SUBMITTED;
+	mid->mid_state = MID_REQUEST_SUBMITTED;
 
 	cifs_in_send_inc(server);
 	rc = smb_sendv(server, iov, nvec);
@@ -392,7 +418,7 @@
 	return rc;
 out_err:
 	delete_mid(mid);
-	atomic_dec(&server->inFlight);
+	cifs_add_credits(server, 1);
 	wake_up(&server->request_q);
 	return rc;
 }
@@ -408,14 +434,14 @@
  */
 int
 SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
-		struct smb_hdr *in_buf, int flags)
+		 char *in_buf, int flags)
 {
 	int rc;
 	struct kvec iov[1];
 	int resp_buf_type;
 
-	iov[0].iov_base = (char *)in_buf;
-	iov[0].iov_len = be32_to_cpu(in_buf->smb_buf_length) + 4;
+	iov[0].iov_base = in_buf;
+	iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
 	flags |= CIFS_NO_RESP;
 	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
 	cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc);
@@ -428,11 +454,11 @@
 {
 	int rc = 0;
 
-	cFYI(1, "%s: cmd=%d mid=%d state=%d", __func__, mid->command,
-		mid->mid, mid->midState);
+	cFYI(1, "%s: cmd=%d mid=%llu state=%d", __func__,
+	     le16_to_cpu(mid->command), mid->mid, mid->mid_state);
 
 	spin_lock(&GlobalMid_Lock);
-	switch (mid->midState) {
+	switch (mid->mid_state) {
 	case MID_RESPONSE_RECEIVED:
 		spin_unlock(&GlobalMid_Lock);
 		return rc;
@@ -447,8 +473,8 @@
 		break;
 	default:
 		list_del_init(&mid->qhead);
-		cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__,
-			mid->mid, mid->midState);
+		cERROR(1, "%s: invalid mid state mid=%llu state=%d", __func__,
+		       mid->mid, mid->mid_state);
 		rc = -EIO;
 	}
 	spin_unlock(&GlobalMid_Lock);
@@ -498,7 +524,7 @@
 cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 		   bool log_error)
 {
-	unsigned int len = be32_to_cpu(mid->resp_buf->smb_buf_length) + 4;
+	unsigned int len = get_rfc1002_length(mid->resp_buf) + 4;
 
 	dump_smb(mid->resp_buf, min_t(u32, 92, len));
 
@@ -518,6 +544,24 @@
 	return map_smb_to_linux_error(mid->resp_buf, log_error);
 }
 
+static int
+cifs_setup_request(struct cifs_ses *ses, struct kvec *iov,
+		   unsigned int nvec, struct mid_q_entry **ret_mid)
+{
+	int rc;
+	struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
+	struct mid_q_entry *mid;
+
+	rc = allocate_mid(ses, hdr, &mid);
+	if (rc)
+		return rc;
+	rc = cifs_sign_smb2(iov, nvec, ses->server, &mid->sequence_number);
+	if (rc)
+		delete_mid(mid);
+	*ret_mid = mid;
+	return rc;
+}
+
 int
 SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 	     struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
@@ -526,56 +570,53 @@
 	int rc = 0;
 	int long_op;
 	struct mid_q_entry *midQ;
-	struct smb_hdr *in_buf = iov[0].iov_base;
+	char *buf = iov[0].iov_base;
 
 	long_op = flags & CIFS_TIMEOUT_MASK;
 
 	*pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */
 
 	if ((ses == NULL) || (ses->server == NULL)) {
-		cifs_small_buf_release(in_buf);
+		cifs_small_buf_release(buf);
 		cERROR(1, "Null session");
 		return -EIO;
 	}
 
 	if (ses->server->tcpStatus == CifsExiting) {
-		cifs_small_buf_release(in_buf);
+		cifs_small_buf_release(buf);
 		return -ENOENT;
 	}
 
-	/* Ensure that we do not send more than 50 overlapping requests
-	   to the same server. We may make this configurable later or
-	   use ses->maxReq */
+	/*
+	 * Ensure that we do not send more than 50 overlapping requests
+	 * to the same server. We may make this configurable later or
+	 * use ses->maxReq.
+	 */
 
 	rc = wait_for_free_request(ses->server, long_op);
 	if (rc) {
-		cifs_small_buf_release(in_buf);
+		cifs_small_buf_release(buf);
 		return rc;
 	}
 
-	/* make sure that we sign in the same order that we send on this socket
-	   and avoid races inside tcp sendmsg code that could cause corruption
-	   of smb data */
+	/*
+	 * Make sure that we sign in the same order that we send on this socket
+	 * and avoid races inside tcp sendmsg code that could cause corruption
+	 * of smb data.
+	 */
 
 	mutex_lock(&ses->server->srv_mutex);
 
-	rc = allocate_mid(ses, in_buf, &midQ);
+	rc = cifs_setup_request(ses, iov, n_vec, &midQ);
 	if (rc) {
 		mutex_unlock(&ses->server->srv_mutex);
-		cifs_small_buf_release(in_buf);
+		cifs_small_buf_release(buf);
 		/* Update # of requests on wire to server */
-		atomic_dec(&ses->server->inFlight);
-		wake_up(&ses->server->request_q);
+		cifs_add_credits(ses->server, 1);
 		return rc;
 	}
-	rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
-	if (rc) {
-		mutex_unlock(&ses->server->srv_mutex);
-		cifs_small_buf_release(in_buf);
-		goto out;
-	}
 
-	midQ->midState = MID_REQUEST_SUBMITTED;
+	midQ->mid_state = MID_REQUEST_SUBMITTED;
 	cifs_in_send_inc(ses->server);
 	rc = smb_sendv(ses->server, iov, n_vec);
 	cifs_in_send_dec(ses->server);
@@ -584,48 +625,47 @@
 	mutex_unlock(&ses->server->srv_mutex);
 
 	if (rc < 0) {
-		cifs_small_buf_release(in_buf);
+		cifs_small_buf_release(buf);
 		goto out;
 	}
 
 	if (long_op == CIFS_ASYNC_OP) {
-		cifs_small_buf_release(in_buf);
+		cifs_small_buf_release(buf);
 		goto out;
 	}
 
 	rc = wait_for_response(ses->server, midQ);
 	if (rc != 0) {
-		send_nt_cancel(ses->server, in_buf, midQ);
+		send_nt_cancel(ses->server, (struct smb_hdr *)buf, midQ);
 		spin_lock(&GlobalMid_Lock);
-		if (midQ->midState == MID_REQUEST_SUBMITTED) {
+		if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
 			midQ->callback = DeleteMidQEntry;
 			spin_unlock(&GlobalMid_Lock);
-			cifs_small_buf_release(in_buf);
-			atomic_dec(&ses->server->inFlight);
-			wake_up(&ses->server->request_q);
+			cifs_small_buf_release(buf);
+			cifs_add_credits(ses->server, 1);
 			return rc;
 		}
 		spin_unlock(&GlobalMid_Lock);
 	}
 
-	cifs_small_buf_release(in_buf);
+	cifs_small_buf_release(buf);
 
 	rc = cifs_sync_mid_result(midQ, ses->server);
 	if (rc != 0) {
-		atomic_dec(&ses->server->inFlight);
-		wake_up(&ses->server->request_q);
+		cifs_add_credits(ses->server, 1);
 		return rc;
 	}
 
-	if (!midQ->resp_buf || midQ->midState != MID_RESPONSE_RECEIVED) {
+	if (!midQ->resp_buf || midQ->mid_state != MID_RESPONSE_RECEIVED) {
 		rc = -EIO;
 		cFYI(1, "Bad MID state?");
 		goto out;
 	}
 
-	iov[0].iov_base = (char *)midQ->resp_buf;
-	iov[0].iov_len = be32_to_cpu(midQ->resp_buf->smb_buf_length) + 4;
-	if (midQ->largeBuf)
+	buf = (char *)midQ->resp_buf;
+	iov[0].iov_base = buf;
+	iov[0].iov_len = get_rfc1002_length(buf) + 4;
+	if (midQ->large_buf)
 		*pRespBufType = CIFS_LARGE_BUFFER;
 	else
 		*pRespBufType = CIFS_SMALL_BUFFER;
@@ -637,8 +677,7 @@
 		midQ->resp_buf = NULL;
 out:
 	delete_mid(midQ);
-	atomic_dec(&ses->server->inFlight);
-	wake_up(&ses->server->request_q);
+	cifs_add_credits(ses->server, 1);
 
 	return rc;
 }
@@ -688,8 +727,7 @@
 	if (rc) {
 		mutex_unlock(&ses->server->srv_mutex);
 		/* Update # of requests on wire to server */
-		atomic_dec(&ses->server->inFlight);
-		wake_up(&ses->server->request_q);
+		cifs_add_credits(ses->server, 1);
 		return rc;
 	}
 
@@ -699,7 +737,7 @@
 		goto out;
 	}
 
-	midQ->midState = MID_REQUEST_SUBMITTED;
+	midQ->mid_state = MID_REQUEST_SUBMITTED;
 
 	cifs_in_send_inc(ses->server);
 	rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
@@ -717,12 +755,11 @@
 	if (rc != 0) {
 		send_nt_cancel(ses->server, in_buf, midQ);
 		spin_lock(&GlobalMid_Lock);
-		if (midQ->midState == MID_REQUEST_SUBMITTED) {
+		if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
 			/* no longer considered to be "in-flight" */
 			midQ->callback = DeleteMidQEntry;
 			spin_unlock(&GlobalMid_Lock);
-			atomic_dec(&ses->server->inFlight);
-			wake_up(&ses->server->request_q);
+			cifs_add_credits(ses->server, 1);
 			return rc;
 		}
 		spin_unlock(&GlobalMid_Lock);
@@ -730,25 +767,23 @@
 
 	rc = cifs_sync_mid_result(midQ, ses->server);
 	if (rc != 0) {
-		atomic_dec(&ses->server->inFlight);
-		wake_up(&ses->server->request_q);
+		cifs_add_credits(ses->server, 1);
 		return rc;
 	}
 
 	if (!midQ->resp_buf || !out_buf ||
-	    midQ->midState != MID_RESPONSE_RECEIVED) {
+	    midQ->mid_state != MID_RESPONSE_RECEIVED) {
 		rc = -EIO;
 		cERROR(1, "Bad MID state?");
 		goto out;
 	}
 
-	*pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
+	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
 	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
 	rc = cifs_check_receive(midQ, ses->server, 0);
 out:
 	delete_mid(midQ);
-	atomic_dec(&ses->server->inFlight);
-	wake_up(&ses->server->request_q);
+	cifs_add_credits(ses->server, 1);
 
 	return rc;
 }
@@ -836,7 +871,7 @@
 		return rc;
 	}
 
-	midQ->midState = MID_REQUEST_SUBMITTED;
+	midQ->mid_state = MID_REQUEST_SUBMITTED;
 	cifs_in_send_inc(ses->server);
 	rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
 	cifs_in_send_dec(ses->server);
@@ -850,13 +885,13 @@
 
 	/* Wait for a reply - allow signals to interrupt. */
 	rc = wait_event_interruptible(ses->server->response_q,
-		(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
+		(!(midQ->mid_state == MID_REQUEST_SUBMITTED)) ||
 		((ses->server->tcpStatus != CifsGood) &&
 		 (ses->server->tcpStatus != CifsNew)));
 
 	/* Were we interrupted by a signal ? */
 	if ((rc == -ERESTARTSYS) &&
-		(midQ->midState == MID_REQUEST_SUBMITTED) &&
+		(midQ->mid_state == MID_REQUEST_SUBMITTED) &&
 		((ses->server->tcpStatus == CifsGood) ||
 		 (ses->server->tcpStatus == CifsNew))) {
 
@@ -886,7 +921,7 @@
 		if (rc) {
 			send_nt_cancel(ses->server, in_buf, midQ);
 			spin_lock(&GlobalMid_Lock);
-			if (midQ->midState == MID_REQUEST_SUBMITTED) {
+			if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
 				/* no longer considered to be "in-flight" */
 				midQ->callback = DeleteMidQEntry;
 				spin_unlock(&GlobalMid_Lock);
@@ -904,13 +939,13 @@
 		return rc;
 
 	/* rcvd frame is ok */
-	if (out_buf == NULL || midQ->midState != MID_RESPONSE_RECEIVED) {
+	if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_RECEIVED) {
 		rc = -EIO;
 		cERROR(1, "Bad MID state?");
 		goto out;
 	}
 
-	*pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
+	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
 	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
 	rc = cifs_check_receive(midQ, ses->server, 0);
 out:
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 5e2e1b3..2870597 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -21,7 +21,6 @@
 #include <linux/vfs.h>
 #include <linux/slab.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 #include <linux/fs.h>
@@ -208,13 +207,12 @@
         if (IS_ERR(root)) {
 		error = PTR_ERR(root);
 		printk("Failure of coda_cnode_make for root: error %d\n", error);
-		root = NULL;
 		goto error;
 	} 
 
 	printk("coda_read_super: rootinode is %ld dev %s\n", 
 	       root->i_ino, root->i_sb->s_id);
-	sb->s_root = d_alloc_root(root);
+	sb->s_root = d_make_root(root);
 	if (!sb->s_root) {
 		error = -EINVAL;
 		goto error;
@@ -222,9 +220,6 @@
 	return 0;
 
 error:
-	if (root)
-		iput(root);
-
 	mutex_lock(&vc->vc_mutex);
 	bdi_destroy(&vc->bdi);
 	vc->vc_sb = NULL;
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index 8f616e0..761d5b3 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -38,7 +38,6 @@
 #include <linux/mutex.h>
 #include <linux/device.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/poll.h>
 #include <asm/uaccess.h>
 
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index 9727e0c..0c68fd3 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -14,7 +14,6 @@
  * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
  */
 
-#include <asm/system.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/types.h>
diff --git a/fs/compat.c b/fs/compat.c
index 07880ba..f2944ac 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -33,7 +33,6 @@
 #include <linux/nfs4_mount.h>
 #include <linux/syscalls.h>
 #include <linux/ctype.h>
-#include <linux/module.h>
 #include <linux/dirent.h>
 #include <linux/fsnotify.h>
 #include <linux/highuid.h>
@@ -1171,10 +1170,9 @@
 }
 
 asmlinkage ssize_t
-compat_sys_preadv(unsigned long fd, const struct compat_iovec __user *vec,
-		  unsigned long vlen, u32 pos_low, u32 pos_high)
+compat_sys_preadv64(unsigned long fd, const struct compat_iovec __user *vec,
+		    unsigned long vlen, loff_t pos)
 {
-	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
 	struct file *file;
 	int fput_needed;
 	ssize_t ret;
@@ -1191,6 +1189,14 @@
 	return ret;
 }
 
+asmlinkage ssize_t
+compat_sys_preadv(unsigned long fd, const struct compat_iovec __user *vec,
+		  unsigned long vlen, u32 pos_low, u32 pos_high)
+{
+	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
+	return compat_sys_preadv64(fd, vec, vlen, pos);
+}
+
 static size_t compat_writev(struct file *file,
 			    const struct compat_iovec __user *vec,
 			    unsigned long vlen, loff_t *pos)
@@ -1230,10 +1236,9 @@
 }
 
 asmlinkage ssize_t
-compat_sys_pwritev(unsigned long fd, const struct compat_iovec __user *vec,
-		   unsigned long vlen, u32 pos_low, u32 pos_high)
+compat_sys_pwritev64(unsigned long fd, const struct compat_iovec __user *vec,
+		     unsigned long vlen, loff_t pos)
 {
-	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
 	struct file *file;
 	int fput_needed;
 	ssize_t ret;
@@ -1250,6 +1255,14 @@
 	return ret;
 }
 
+asmlinkage ssize_t
+compat_sys_pwritev(unsigned long fd, const struct compat_iovec __user *vec,
+		   unsigned long vlen, u32 pos_low, u32 pos_high)
+{
+	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
+	return compat_sys_pwritev64(fd, vec, vlen, pos);
+}
+
 asmlinkage long
 compat_sys_vmsplice(int fd, const struct compat_iovec __user *iov32,
 		    unsigned int nr_segs, unsigned int flags)
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 10d8cd9..debdfe0 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -49,7 +49,6 @@
 #include <linux/elevator.h>
 #include <linux/rtc.h>
 #include <linux/pci.h>
-#include <linux/module.h>
 #include <linux/serial.h>
 #include <linux/if_tun.h>
 #include <linux/ctype.h>
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h
index ede857d..b5f0a3b 100644
--- a/fs/configfs/configfs_internal.h
+++ b/fs/configfs/configfs_internal.h
@@ -58,12 +58,11 @@
 extern struct mutex configfs_symlink_mutex;
 extern spinlock_t configfs_dirent_lock;
 
-extern struct vfsmount * configfs_mount;
 extern struct kmem_cache *configfs_dir_cachep;
 
 extern int configfs_is_root(struct config_item *item);
 
-extern struct inode * configfs_new_inode(umode_t mode, struct configfs_dirent *);
+extern struct inode * configfs_new_inode(umode_t mode, struct configfs_dirent *, struct super_block *);
 extern int configfs_create(struct dentry *, umode_t mode, int (*init)(struct inode *));
 extern int configfs_inode_init(void);
 extern void configfs_inode_exit(void);
@@ -80,15 +79,15 @@
 extern void configfs_drop_dentry(struct configfs_dirent *sd, struct dentry *parent);
 extern int configfs_setattr(struct dentry *dentry, struct iattr *iattr);
 
-extern int configfs_pin_fs(void);
+extern struct dentry *configfs_pin_fs(void);
 extern void configfs_release_fs(void);
 
 extern struct rw_semaphore configfs_rename_sem;
-extern struct super_block * configfs_sb;
 extern const struct file_operations configfs_dir_operations;
 extern const struct file_operations configfs_file_operations;
 extern const struct file_operations bin_fops;
 extern const struct inode_operations configfs_dir_inode_operations;
+extern const struct inode_operations configfs_root_inode_operations;
 extern const struct inode_operations configfs_symlink_inode_operations;
 extern const struct dentry_operations configfs_dentry_ops;
 
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 5ddd7eb..7e6c52d 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -264,11 +264,13 @@
 	return 0;
 }
 
-static int create_dir(struct config_item * k, struct dentry * p,
-		      struct dentry * d)
+static int create_dir(struct config_item *k, struct dentry *d)
 {
 	int error;
 	umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
+	struct dentry *p = d->d_parent;
+
+	BUG_ON(!k);
 
 	error = configfs_dirent_exists(p->d_fsdata, d->d_name.name);
 	if (!error)
@@ -304,19 +306,7 @@
 
 static int configfs_create_dir(struct config_item * item, struct dentry *dentry)
 {
-	struct dentry * parent;
-	int error = 0;
-
-	BUG_ON(!item);
-
-	if (item->ci_parent)
-		parent = item->ci_parent->ci_dentry;
-	else if (configfs_mount)
-		parent = configfs_mount->mnt_root;
-	else
-		return -EFAULT;
-
-	error = create_dir(item,parent,dentry);
+	int error = create_dir(item, dentry);
 	if (!error)
 		item->ci_dentry = dentry;
 	return error;
@@ -1079,23 +1069,24 @@
 	int ret;
 	struct configfs_dirent *p, *root_sd, *subsys_sd = NULL;
 	struct config_item *s_item = &subsys->su_group.cg_item;
+	struct dentry *root;
 
 	/*
 	 * Pin the configfs filesystem.  This means we can safely access
 	 * the root of the configfs filesystem.
 	 */
-	ret = configfs_pin_fs();
-	if (ret)
-		return ret;
+	root = configfs_pin_fs();
+	if (IS_ERR(root))
+		return PTR_ERR(root);
 
 	/*
 	 * Next, lock the root directory.  We're going to check that the
 	 * subsystem is really registered, and so we need to lock out
 	 * configfs_[un]register_subsystem().
 	 */
-	mutex_lock(&configfs_sb->s_root->d_inode->i_mutex);
+	mutex_lock(&root->d_inode->i_mutex);
 
-	root_sd = configfs_sb->s_root->d_fsdata;
+	root_sd = root->d_fsdata;
 
 	list_for_each_entry(p, &root_sd->s_children, s_sibling) {
 		if (p->s_type & CONFIGFS_DIR) {
@@ -1129,7 +1120,7 @@
 out_unlock_dirent_lock:
 	spin_unlock(&configfs_dirent_lock);
 out_unlock_fs:
-	mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex);
+	mutex_unlock(&root->d_inode->i_mutex);
 
 	/*
 	 * If we succeeded, the fs is pinned via other methods.  If not,
@@ -1183,11 +1174,6 @@
 	struct module *subsys_owner = NULL, *new_item_owner = NULL;
 	char *name;
 
-	if (dentry->d_parent == configfs_sb->s_root) {
-		ret = -EPERM;
-		goto out;
-	}
-
 	sd = dentry->d_parent->d_fsdata;
 
 	/*
@@ -1359,9 +1345,6 @@
 	struct module *subsys_owner = NULL, *dead_item_owner = NULL;
 	int ret;
 
-	if (dentry->d_parent == configfs_sb->s_root)
-		return -EPERM;
-
 	sd = dentry->d_fsdata;
 	if (sd->s_type & CONFIGFS_USET_DEFAULT)
 		return -EPERM;
@@ -1459,6 +1442,11 @@
 	.setattr	= configfs_setattr,
 };
 
+const struct inode_operations configfs_root_inode_operations = {
+	.lookup		= configfs_lookup,
+	.setattr	= configfs_setattr,
+};
+
 #if 0
 int configfs_rename_dir(struct config_item * item, const char *new_name)
 {
@@ -1546,6 +1534,7 @@
 static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
 	struct dentry *dentry = filp->f_path.dentry;
+	struct super_block *sb = dentry->d_sb;
 	struct configfs_dirent * parent_sd = dentry->d_fsdata;
 	struct configfs_dirent *cursor = filp->private_data;
 	struct list_head *p, *q = &cursor->s_sibling;
@@ -1608,7 +1597,7 @@
 					ino = inode->i_ino;
 				spin_unlock(&configfs_dirent_lock);
 				if (!inode)
-					ino = iunique(configfs_sb, 2);
+					ino = iunique(sb, 2);
 
 				if (filldir(dirent, name, len, filp->f_pos, ino,
 						 dt_type(next)) < 0)
@@ -1680,27 +1669,27 @@
 	struct config_group *group = &subsys->su_group;
 	struct qstr name;
 	struct dentry *dentry;
+	struct dentry *root;
 	struct configfs_dirent *sd;
 
-	err = configfs_pin_fs();
-	if (err)
-		return err;
+	root = configfs_pin_fs();
+	if (IS_ERR(root))
+		return PTR_ERR(root);
 
 	if (!group->cg_item.ci_name)
 		group->cg_item.ci_name = group->cg_item.ci_namebuf;
 
-	sd = configfs_sb->s_root->d_fsdata;
+	sd = root->d_fsdata;
 	link_group(to_config_group(sd->s_element), group);
 
-	mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex,
-			I_MUTEX_PARENT);
+	mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT);
 
 	name.name = group->cg_item.ci_name;
 	name.len = strlen(name.name);
 	name.hash = full_name_hash(name.name, name.len);
 
 	err = -ENOMEM;
-	dentry = d_alloc(configfs_sb->s_root, &name);
+	dentry = d_alloc(root, &name);
 	if (dentry) {
 		d_add(dentry, NULL);
 
@@ -1717,7 +1706,7 @@
 		}
 	}
 
-	mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex);
+	mutex_unlock(&root->d_inode->i_mutex);
 
 	if (err) {
 		unlink_group(group);
@@ -1731,13 +1720,14 @@
 {
 	struct config_group *group = &subsys->su_group;
 	struct dentry *dentry = group->cg_item.ci_dentry;
+	struct dentry *root = dentry->d_sb->s_root;
 
-	if (dentry->d_parent != configfs_sb->s_root) {
+	if (dentry->d_parent != root) {
 		printk(KERN_ERR "configfs: Tried to unregister non-subsystem!\n");
 		return;
 	}
 
-	mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex,
+	mutex_lock_nested(&root->d_inode->i_mutex,
 			  I_MUTEX_PARENT);
 	mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
 	mutex_lock(&configfs_symlink_mutex);
@@ -1754,7 +1744,7 @@
 
 	d_delete(dentry);
 
-	mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex);
+	mutex_unlock(&root->d_inode->i_mutex);
 
 	dput(dentry);
 
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c
index 3ee36d4..0074362 100644
--- a/fs/configfs/inode.c
+++ b/fs/configfs/inode.c
@@ -44,8 +44,6 @@
 static struct lock_class_key default_group_class[MAX_LOCK_DEPTH];
 #endif
 
-extern struct super_block * configfs_sb;
-
 static const struct address_space_operations configfs_aops = {
 	.readpage	= simple_readpage,
 	.write_begin	= simple_write_begin,
@@ -132,9 +130,10 @@
 	inode->i_ctime = iattr->ia_ctime;
 }
 
-struct inode *configfs_new_inode(umode_t mode, struct configfs_dirent * sd)
+struct inode *configfs_new_inode(umode_t mode, struct configfs_dirent *sd,
+				 struct super_block *s)
 {
-	struct inode * inode = new_inode(configfs_sb);
+	struct inode * inode = new_inode(s);
 	if (inode) {
 		inode->i_ino = get_next_ino();
 		inode->i_mapping->a_ops = &configfs_aops;
@@ -188,36 +187,35 @@
 int configfs_create(struct dentry * dentry, umode_t mode, int (*init)(struct inode *))
 {
 	int error = 0;
-	struct inode * inode = NULL;
-	if (dentry) {
-		if (!dentry->d_inode) {
-			struct configfs_dirent *sd = dentry->d_fsdata;
-			if ((inode = configfs_new_inode(mode, sd))) {
-				if (dentry->d_parent && dentry->d_parent->d_inode) {
-					struct inode *p_inode = dentry->d_parent->d_inode;
-					p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME;
-				}
-				configfs_set_inode_lock_class(sd, inode);
-				goto Proceed;
-			}
-			else
-				error = -ENOMEM;
-		} else
-			error = -EEXIST;
-	} else
-		error = -ENOENT;
-	goto Done;
+	struct inode *inode = NULL;
+	struct configfs_dirent *sd;
+	struct inode *p_inode;
 
- Proceed:
-	if (init)
+	if (!dentry)
+		return -ENOENT;
+
+	if (dentry->d_inode)
+		return -EEXIST;
+
+	sd = dentry->d_fsdata;
+	inode = configfs_new_inode(mode, sd, dentry->d_sb);
+	if (!inode)
+		return -ENOMEM;
+
+	p_inode = dentry->d_parent->d_inode;
+	p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME;
+	configfs_set_inode_lock_class(sd, inode);
+
+	if (init) {
 		error = init(inode);
-	if (!error) {
-		d_instantiate(dentry, inode);
-		if (S_ISDIR(mode) || S_ISLNK(mode))
-			dget(dentry);  /* pin link and directory dentries in core */
-	} else
-		iput(inode);
- Done:
+		if (error) {
+			iput(inode);
+			return error;
+		}
+	}
+	d_instantiate(dentry, inode);
+	if (S_ISDIR(mode) || S_ISLNK(mode))
+		dget(dentry);  /* pin link and directory dentries in core */
 	return error;
 }
 
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
index 276e15c..aee0a7e 100644
--- a/fs/configfs/mount.c
+++ b/fs/configfs/mount.c
@@ -37,8 +37,7 @@
 /* Random magic number */
 #define CONFIGFS_MAGIC 0x62656570
 
-struct vfsmount * configfs_mount = NULL;
-struct super_block * configfs_sb = NULL;
+static struct vfsmount *configfs_mount = NULL;
 struct kmem_cache *configfs_dir_cachep;
 static int configfs_mnt_count = 0;
 
@@ -77,12 +76,11 @@
 	sb->s_magic = CONFIGFS_MAGIC;
 	sb->s_op = &configfs_ops;
 	sb->s_time_gran = 1;
-	configfs_sb = sb;
 
 	inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
-				   &configfs_root);
+				   &configfs_root, sb);
 	if (inode) {
-		inode->i_op = &configfs_dir_inode_operations;
+		inode->i_op = &configfs_root_inode_operations;
 		inode->i_fop = &configfs_dir_operations;
 		/* directory inodes start off with i_nlink == 2 (for "." entry) */
 		inc_nlink(inode);
@@ -91,10 +89,9 @@
 		return -ENOMEM;
 	}
 
-	root = d_alloc_root(inode);
+	root = d_make_root(inode);
 	if (!root) {
 		pr_debug("%s: could not get root dentry!\n",__func__);
-		iput(inode);
 		return -ENOMEM;
 	}
 	config_group_init(&configfs_root_group);
@@ -118,10 +115,11 @@
 	.kill_sb	= kill_litter_super,
 };
 
-int configfs_pin_fs(void)
+struct dentry *configfs_pin_fs(void)
 {
-	return simple_pin_fs(&configfs_fs_type, &configfs_mount,
+	int err = simple_pin_fs(&configfs_fs_type, &configfs_mount,
 			     &configfs_mnt_count);
+	return err ? ERR_PTR(err) : configfs_mount->mnt_root;
 }
 
 void configfs_release_fs(void)
diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c
index 0f3eb41..cc9f254 100644
--- a/fs/configfs/symlink.c
+++ b/fs/configfs/symlink.c
@@ -110,13 +110,13 @@
 
 
 static int get_target(const char *symname, struct path *path,
-		      struct config_item **target)
+		      struct config_item **target, struct super_block *sb)
 {
 	int ret;
 
 	ret = kern_path(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, path);
 	if (!ret) {
-		if (path->dentry->d_sb == configfs_sb) {
+		if (path->dentry->d_sb == sb) {
 			*target = configfs_get_config_item(path->dentry);
 			if (!*target) {
 				ret = -ENOENT;
@@ -141,10 +141,6 @@
 	struct config_item *target_item = NULL;
 	struct config_item_type *type;
 
-	ret = -EPERM;  /* What lack-of-symlink returns */
-	if (dentry->d_parent == configfs_sb->s_root)
-		goto out;
-
 	sd = dentry->d_parent->d_fsdata;
 	/*
 	 * Fake invisibility if dir belongs to a group/default groups hierarchy
@@ -162,7 +158,7 @@
 	    !type->ct_item_ops->allow_link)
 		goto out_put;
 
-	ret = get_target(symname, &path, &target_item);
+	ret = get_target(symname, &path, &target_item, dentry->d_sb);
 	if (ret)
 		goto out_put;
 
@@ -198,8 +194,6 @@
 	if (!(sd->s_type & CONFIGFS_ITEM_LINK))
 		goto out;
 
-	BUG_ON(dentry->d_parent == configfs_sb->s_root);
-
 	sl = sd->s_element;
 
 	parent_item = configfs_get_config_item(dentry->d_parent);
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 04d51f9..d013c46 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -318,11 +318,9 @@
 	root = get_cramfs_inode(sb, &super.root, 0);
 	if (IS_ERR(root))
 		goto out;
-	sb->s_root = d_alloc_root(root);
-	if (!sb->s_root) {
-		iput(root);
+	sb->s_root = d_make_root(root);
+	if (!sb->s_root)
 		goto out;
-	}
 	return 0;
 out:
 	kfree(sbi);
diff --git a/fs/dcache.c b/fs/dcache.c
index 11828de..b60ddc4 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -23,7 +23,7 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/cache.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/mount.h>
 #include <linux/file.h>
 #include <asm/uaccess.h>
@@ -1466,30 +1466,6 @@
 
 EXPORT_SYMBOL(d_instantiate_unique);
 
-/**
- * d_alloc_root - allocate root dentry
- * @root_inode: inode to allocate the root for
- *
- * Allocate a root ("/") dentry for the inode given. The inode is
- * instantiated and returned. %NULL is returned if there is insufficient
- * memory or the inode passed is %NULL.
- */
- 
-struct dentry * d_alloc_root(struct inode * root_inode)
-{
-	struct dentry *res = NULL;
-
-	if (root_inode) {
-		static const struct qstr name = { .name = "/", .len = 1 };
-
-		res = __d_alloc(root_inode->i_sb, &name);
-		if (res)
-			d_instantiate(res, root_inode);
-	}
-	return res;
-}
-EXPORT_SYMBOL(d_alloc_root);
-
 struct dentry *d_make_root(struct inode *root_inode)
 {
 	struct dentry *res = NULL;
@@ -1737,7 +1713,7 @@
  * __d_lookup_rcu - search for a dentry (racy, store-free)
  * @parent: parent dentry
  * @name: qstr of name we wish to find
- * @seq: returns d_seq value at the point where the dentry was found
+ * @seqp: returns d_seq value at the point where the dentry was found
  * @inode: returns dentry->d_inode when the inode was found valid.
  * Returns: dentry, or NULL
  *
@@ -2428,6 +2404,7 @@
 			if (d_ancestor(alias, dentry)) {
 				/* Check for loops */
 				actual = ERR_PTR(-ELOOP);
+				spin_unlock(&inode->i_lock);
 			} else if (IS_ROOT(alias)) {
 				/* Is this an anonymous mountpoint that we
 				 * could splice into our tree? */
@@ -2437,7 +2414,7 @@
 				goto found;
 			} else {
 				/* Nope, but we must(!) avoid directory
-				 * aliasing */
+				 * aliasing. This drops inode->i_lock */
 				actual = __d_unalias(inode, dentry, alias);
 			}
 			write_sequnlock(&rename_lock);
diff --git a/fs/dcookies.c b/fs/dcookies.c
index dda0dc7..17c7799 100644
--- a/fs/dcookies.c
+++ b/fs/dcookies.c
@@ -13,7 +13,7 @@
  */
 
 #include <linux/syscalls.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/mount.h>
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index ef023ee..5dfafdd 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -33,18 +33,10 @@
 	return count;
 }
 
-static int default_open(struct inode *inode, struct file *file)
-{
-	if (inode->i_private)
-		file->private_data = inode->i_private;
-
-	return 0;
-}
-
 const struct file_operations debugfs_file_operations = {
 	.read =		default_read_file,
 	.write =	default_write_file,
-	.open =		default_open,
+	.open =		simple_open,
 	.llseek =	noop_llseek,
 };
 
@@ -447,7 +439,7 @@
 static const struct file_operations fops_bool = {
 	.read =		read_file_bool,
 	.write =	write_file_bool,
-	.open =		default_open,
+	.open =		simple_open,
 	.llseek =	default_llseek,
 };
 
@@ -492,7 +484,7 @@
 
 static const struct file_operations fops_blob = {
 	.read =		read_file_blob,
-	.open =		default_open,
+	.open =		simple_open,
 	.llseek =	default_llseek,
 };
 
@@ -611,7 +603,7 @@
  * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
  * code.
  */
-struct dentry *debugfs_create_regset32(const char *name, mode_t mode,
+struct dentry *debugfs_create_regset32(const char *name, umode_t mode,
 				       struct dentry *parent,
 				       struct debugfs_regset32 *regset)
 {
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 1c6f908..10f5e0b 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -374,12 +374,11 @@
 	inode->i_fop = &simple_dir_operations;
 	set_nlink(inode, 2);
 
-	s->s_root = d_alloc_root(inode);
+	s->s_root = d_make_root(inode);
 	if (s->s_root)
 		return 0;
 
 	printk(KERN_ERR "devpts: get root dentry failed\n");
-	iput(inode);
 
 fail:
 	return -ENOMEM;
diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c
index 3dca2b3..1c9b080 100644
--- a/fs/dlm/debug_fs.c
+++ b/fs/dlm/debug_fs.c
@@ -609,13 +609,6 @@
 /*
  * dump lkb's on the ls_waiters list
  */
-
-static int waiters_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t waiters_read(struct file *file, char __user *userbuf,
 			    size_t count, loff_t *ppos)
 {
@@ -644,7 +637,7 @@
 
 static const struct file_operations waiters_fops = {
 	.owner   = THIS_MODULE,
-	.open    = waiters_open,
+	.open    = simple_open,
 	.read    = waiters_read,
 	.llseek  = default_llseek,
 };
diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c
index 8364157..dc5eb59 100644
--- a/fs/dlm/dir.c
+++ b/fs/dlm/dir.c
@@ -351,11 +351,28 @@
 static struct dlm_rsb *find_rsb_root(struct dlm_ls *ls, char *name, int len)
 {
 	struct dlm_rsb *r;
+	uint32_t hash, bucket;
+	int rv;
+
+	hash = jhash(name, len, 0);
+	bucket = hash & (ls->ls_rsbtbl_size - 1);
+
+	spin_lock(&ls->ls_rsbtbl[bucket].lock);
+	rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[bucket].keep, name, len, 0, &r);
+	if (rv)
+		rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[bucket].toss,
+					 name, len, 0, &r);
+	spin_unlock(&ls->ls_rsbtbl[bucket].lock);
+
+	if (!rv)
+		return r;
 
 	down_read(&ls->ls_root_sem);
 	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
 		if (len == r->res_length && !memcmp(name, r->res_name, len)) {
 			up_read(&ls->ls_root_sem);
+			log_error(ls, "find_rsb_root revert to root_list %s",
+				  r->res_name);
 			return r;
 		}
 	}
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index d471830..fa5c07d 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -411,8 +411,8 @@
 	return memcmp(r->res_name, maxname, DLM_RESNAME_MAXLEN);
 }
 
-static int search_rsb_tree(struct rb_root *tree, char *name, int len,
-			   unsigned int flags, struct dlm_rsb **r_ret)
+int dlm_search_rsb_tree(struct rb_root *tree, char *name, int len,
+			unsigned int flags, struct dlm_rsb **r_ret)
 {
 	struct rb_node *node = tree->rb_node;
 	struct dlm_rsb *r;
@@ -474,12 +474,12 @@
 	struct dlm_rsb *r;
 	int error;
 
-	error = search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, flags, &r);
+	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, flags, &r);
 	if (!error) {
 		kref_get(&r->res_ref);
 		goto out;
 	}
-	error = search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, flags, &r);
+	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, flags, &r);
 	if (error)
 		goto out;
 
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h
index 265017a..1a25530 100644
--- a/fs/dlm/lock.h
+++ b/fs/dlm/lock.h
@@ -28,6 +28,9 @@
 void dlm_scan_timeout(struct dlm_ls *ls);
 void dlm_adjust_timeouts(struct dlm_ls *ls);
 
+int dlm_search_rsb_tree(struct rb_root *tree, char *name, int len,
+			unsigned int flags, struct dlm_rsb **r_ret);
+
 int dlm_purge_locks(struct dlm_ls *ls);
 void dlm_purge_mstcpy_locks(struct dlm_rsb *r);
 void dlm_grant_after_purge(struct dlm_ls *ls);
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index ca0c59a..133ef6d 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -1076,7 +1076,7 @@
 	int i;
 
 	dlm_local_count = 0;
-	for (i = 0; i < DLM_MAX_ADDR_COUNT - 1; i++) {
+	for (i = 0; i < DLM_MAX_ADDR_COUNT; i++) {
 		if (dlm_our_addr(&sas, i))
 			break;
 
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index d3f95f9..2b17f2f 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -48,8 +48,7 @@
 				unsigned long nr_segs, loff_t pos)
 {
 	ssize_t rc;
-	struct dentry *lower_dentry;
-	struct vfsmount *lower_vfsmount;
+	struct path lower;
 	struct file *file = iocb->ki_filp;
 
 	rc = generic_file_aio_read(iocb, iov, nr_segs, pos);
@@ -60,9 +59,9 @@
 	if (-EIOCBQUEUED == rc)
 		rc = wait_on_sync_kiocb(iocb);
 	if (rc >= 0) {
-		lower_dentry = ecryptfs_dentry_to_lower(file->f_path.dentry);
-		lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_path.dentry);
-		touch_atime(lower_vfsmount, lower_dentry);
+		lower.dentry = ecryptfs_dentry_to_lower(file->f_path.dentry);
+		lower.mnt = ecryptfs_dentry_to_lower_mnt(file->f_path.dentry);
+		touch_atime(&lower);
 	}
 	return rc;
 }
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index b4a6bef..6895493 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -550,9 +550,8 @@
 	if (IS_ERR(inode))
 		goto out_free;
 
-	s->s_root = d_alloc_root(inode);
+	s->s_root = d_make_root(inode);
 	if (!s->s_root) {
-		iput(inode);
 		rc = -ENOMEM;
 		goto out_free;
 	}
@@ -795,15 +794,10 @@
 		       "Failed to allocate one or more kmem_cache objects\n");
 		goto out;
 	}
-	rc = register_filesystem(&ecryptfs_fs_type);
-	if (rc) {
-		printk(KERN_ERR "Failed to register filesystem\n");
-		goto out_free_kmem_caches;
-	}
 	rc = do_sysfs_registration();
 	if (rc) {
 		printk(KERN_ERR "sysfs registration failed\n");
-		goto out_unregister_filesystem;
+		goto out_free_kmem_caches;
 	}
 	rc = ecryptfs_init_kthread();
 	if (rc) {
@@ -824,19 +818,24 @@
 		       "rc = [%d]\n", rc);
 		goto out_release_messaging;
 	}
+	rc = register_filesystem(&ecryptfs_fs_type);
+	if (rc) {
+		printk(KERN_ERR "Failed to register filesystem\n");
+		goto out_destroy_crypto;
+	}
 	if (ecryptfs_verbosity > 0)
 		printk(KERN_CRIT "eCryptfs verbosity set to %d. Secret values "
 			"will be written to the syslog!\n", ecryptfs_verbosity);
 
 	goto out;
+out_destroy_crypto:
+	ecryptfs_destroy_crypto();
 out_release_messaging:
 	ecryptfs_release_messaging();
 out_destroy_kthread:
 	ecryptfs_destroy_kthread();
 out_do_sysfs_unregistration:
 	do_sysfs_unregistration();
-out_unregister_filesystem:
-	unregister_filesystem(&ecryptfs_fs_type);
 out_free_kmem_caches:
 	ecryptfs_free_kmem_caches();
 out:
diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c
index cf15282..2dd946b 100644
--- a/fs/ecryptfs/super.c
+++ b/fs/ecryptfs/super.c
@@ -184,7 +184,6 @@
 const struct super_operations ecryptfs_sops = {
 	.alloc_inode = ecryptfs_alloc_inode,
 	.destroy_inode = ecryptfs_destroy_inode,
-	.drop_inode = generic_drop_inode,
 	.statfs = ecryptfs_statfs,
 	.remount_fs = NULL,
 	.evict_inode = ecryptfs_evict_inode,
diff --git a/fs/efs/super.c b/fs/efs/super.c
index 9811064..e755ec7 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -317,10 +317,9 @@
 		goto out_no_fs;
 	}
 
-	s->s_root = d_alloc_root(root);
+	s->s_root = d_make_root(root);
 	if (!(s->s_root)) {
 		printk(KERN_ERR "EFS: get root dentry failed\n");
-		iput(root);
 		ret = -ENOMEM;
 		goto out_no_fs;
 	}
diff --git a/fs/eventfd.c b/fs/eventfd.c
index d9a5917..dba15fe 100644
--- a/fs/eventfd.c
+++ b/fs/eventfd.c
@@ -16,7 +16,7 @@
 #include <linux/spinlock.h>
 #include <linux/anon_inodes.h>
 #include <linux/syscalls.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kref.h>
 #include <linux/eventfd.h>
 
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 4d9d3a4..739b098 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -34,7 +34,6 @@
 #include <linux/mutex.h>
 #include <linux/anon_inodes.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/mman.h>
 #include <linux/atomic.h>
@@ -427,6 +426,31 @@
 	return error;
 }
 
+/*
+ * As described in commit 0ccf831cb lockdep: annotate epoll
+ * the use of wait queues used by epoll is done in a very controlled
+ * manner. Wake ups can nest inside each other, but are never done
+ * with the same locking. For example:
+ *
+ *   dfd = socket(...);
+ *   efd1 = epoll_create();
+ *   efd2 = epoll_create();
+ *   epoll_ctl(efd1, EPOLL_CTL_ADD, dfd, ...);
+ *   epoll_ctl(efd2, EPOLL_CTL_ADD, efd1, ...);
+ *
+ * When a packet arrives to the device underneath "dfd", the net code will
+ * issue a wake_up() on its poll wake list. Epoll (efd1) has installed a
+ * callback wakeup entry on that queue, and the wake_up() performed by the
+ * "dfd" net code will end up in ep_poll_callback(). At this point epoll
+ * (efd1) notices that it may have some event ready, so it needs to wake up
+ * the waiters on its poll wait list (efd2). So it calls ep_poll_safewake()
+ * that ends up in another wake_up(), after having checked about the
+ * recursion constraints. That are, no more than EP_MAX_POLLWAKE_NESTS, to
+ * avoid stack blasting.
+ *
+ * When CONFIG_DEBUG_LOCK_ALLOC is enabled, make sure lockdep can handle
+ * this special case of epoll.
+ */
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 static inline void ep_wake_up_nested(wait_queue_head_t *wqueue,
 				     unsigned long events, int subclass)
@@ -699,9 +723,12 @@
 			       void *priv)
 {
 	struct epitem *epi, *tmp;
+	poll_table pt;
 
+	init_poll_funcptr(&pt, NULL);
 	list_for_each_entry_safe(epi, tmp, head, rdllink) {
-		if (epi->ffd.file->f_op->poll(epi->ffd.file, NULL) &
+		pt._key = epi->event.events;
+		if (epi->ffd.file->f_op->poll(epi->ffd.file, &pt) &
 		    epi->event.events)
 			return POLLIN | POLLRDNORM;
 		else {
@@ -1049,13 +1076,11 @@
  */
 static int reverse_path_check(void)
 {
-	int length = 0;
 	int error = 0;
 	struct file *current_file;
 
 	/* let's call this for all tfiles */
 	list_for_each_entry(current_file, &tfile_check_list, f_tfile_llink) {
-		length++;
 		path_count_init();
 		error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
 					reverse_path_check_proc, current_file,
@@ -1097,6 +1122,7 @@
 	/* Initialize the poll table using the queue callback */
 	epq.epi = epi;
 	init_poll_funcptr(&epq.pt, ep_ptable_queue_proc);
+	epq.pt._key = event->events;
 
 	/*
 	 * Attach the item to the poll hooks and get current event bits.
@@ -1191,6 +1217,9 @@
 {
 	int pwake = 0;
 	unsigned int revents;
+	poll_table pt;
+
+	init_poll_funcptr(&pt, NULL);
 
 	/*
 	 * Set the new event interest mask before calling f_op->poll();
@@ -1198,13 +1227,14 @@
 	 * f_op->poll() call and the new event set registering.
 	 */
 	epi->event.events = event->events;
+	pt._key = event->events;
 	epi->event.data = event->data; /* protected by mtx */
 
 	/*
 	 * Get current event bits. We can safely use the file* here because
 	 * its usage count has been increased by the caller of this function.
 	 */
-	revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL);
+	revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt);
 
 	/*
 	 * If the item is "hot" and it is not registered inside the ready
@@ -1239,6 +1269,9 @@
 	unsigned int revents;
 	struct epitem *epi;
 	struct epoll_event __user *uevent;
+	poll_table pt;
+
+	init_poll_funcptr(&pt, NULL);
 
 	/*
 	 * We can loop without lock because we are passed a task private list.
@@ -1251,7 +1284,8 @@
 
 		list_del_init(&epi->rdllink);
 
-		revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL) &
+		pt._key = epi->event.events;
+		revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt) &
 			epi->event.events;
 
 		/*
diff --git a/fs/exec.c b/fs/exec.c
index 3908544..b1fd202 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -59,6 +59,7 @@
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/tlb.h>
+#include <asm/exec.h>
 
 #include <trace/events/task.h>
 #include "internal.h"
@@ -81,15 +82,13 @@
 static LIST_HEAD(formats);
 static DEFINE_RWLOCK(binfmt_lock);
 
-int __register_binfmt(struct linux_binfmt * fmt, int insert)
+void __register_binfmt(struct linux_binfmt * fmt, int insert)
 {
-	if (!fmt)
-		return -EINVAL;
+	BUG_ON(!fmt);
 	write_lock(&binfmt_lock);
 	insert ? list_add(&fmt->lh, &formats) :
 		 list_add_tail(&fmt->lh, &formats);
 	write_unlock(&binfmt_lock);
-	return 0;	
 }
 
 EXPORT_SYMBOL(__register_binfmt);
@@ -824,7 +823,7 @@
 	/* Notify parent that we're no longer interested in the old VM */
 	tsk = current;
 	old_mm = current->mm;
-	sync_mm_rss(tsk, old_mm);
+	sync_mm_rss(old_mm);
 	mm_release(tsk, old_mm);
 
 	if (old_mm) {
@@ -1029,10 +1028,10 @@
 		fdt = files_fdtable(files);
 		if (i >= fdt->max_fds)
 			break;
-		set = fdt->close_on_exec->fds_bits[j];
+		set = fdt->close_on_exec[j];
 		if (!set)
 			continue;
-		fdt->close_on_exec->fds_bits[j] = 0;
+		fdt->close_on_exec[j] = 0;
 		spin_unlock(&files->file_lock);
 		for ( ; set ; i++,set >>= 1) {
 			if (set & 1) {
@@ -1115,7 +1114,7 @@
 	bprm->mm = NULL;		/* We're using it now */
 
 	set_fs(USER_DS);
-	current->flags &= ~(PF_RANDOMIZE | PF_KTHREAD);
+	current->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD);
 	flush_thread();
 	current->personality &= ~bprm->per_clear;
 
@@ -1372,7 +1371,7 @@
 	unsigned int depth = bprm->recursion_depth;
 	int try,retval;
 	struct linux_binfmt *fmt;
-	pid_t old_pid;
+	pid_t old_pid, old_vpid;
 
 	retval = security_bprm_check(bprm);
 	if (retval)
@@ -1383,8 +1382,9 @@
 		return retval;
 
 	/* Need to fetch pid before load_binary changes it */
+	old_pid = current->pid;
 	rcu_read_lock();
-	old_pid = task_pid_nr_ns(current, task_active_pid_ns(current->parent));
+	old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent));
 	rcu_read_unlock();
 
 	retval = -ENOENT;
@@ -1407,7 +1407,7 @@
 			if (retval >= 0) {
 				if (depth == 0) {
 					trace_sched_process_exec(current, old_pid, bprm);
-					ptrace_event(PTRACE_EVENT_EXEC, old_pid);
+					ptrace_event(PTRACE_EVENT_EXEC, old_vpid);
 				}
 				put_binfmt(fmt);
 				allow_write_access(bprm->file);
@@ -2068,8 +2068,8 @@
 	fd_install(0, rp);
 	spin_lock(&cf->file_lock);
 	fdt = files_fdtable(cf);
-	FD_SET(0, fdt->open_fds);
-	FD_CLR(0, fdt->close_on_exec);
+	__set_open_fd(0, fdt);
+	__clear_close_on_exec(0, fdt);
 	spin_unlock(&cf->file_lock);
 
 	/* and disallow core files too */
diff --git a/fs/exofs/namei.c b/fs/exofs/namei.c
index 9dbf0c3..fc7161d 100644
--- a/fs/exofs/namei.c
+++ b/fs/exofs/namei.c
@@ -143,9 +143,6 @@
 {
 	struct inode *inode = old_dentry->d_inode;
 
-	if (inode->i_nlink >= EXOFS_LINK_MAX)
-		return -EMLINK;
-
 	inode->i_ctime = CURRENT_TIME;
 	inode_inc_link_count(inode);
 	ihold(inode);
@@ -156,10 +153,7 @@
 static int exofs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
 	struct inode *inode;
-	int err = -EMLINK;
-
-	if (dir->i_nlink >= EXOFS_LINK_MAX)
-		goto out;
+	int err;
 
 	inode_inc_link_count(dir);
 
@@ -275,11 +269,6 @@
 		if (err)
 			goto out_dir;
 	} else {
-		if (dir_de) {
-			err = -EMLINK;
-			if (new_dir->i_nlink >= EXOFS_LINK_MAX)
-				goto out_dir;
-		}
 		err = exofs_add_link(new_dentry, old_inode);
 		if (err)
 			goto out_dir;
diff --git a/fs/exofs/super.c b/fs/exofs/super.c
index d22cd16..735ca06 100644
--- a/fs/exofs/super.c
+++ b/fs/exofs/super.c
@@ -389,7 +389,7 @@
 	ios->length = offsetof(struct exofs_fscb, s_dev_table_oid);
 	memset(fscb, 0, ios->length);
 	fscb->s_nextid = cpu_to_le64(sbi->s_nextid);
-	fscb->s_numfiles = cpu_to_le32(sbi->s_numfiles);
+	fscb->s_numfiles = cpu_to_le64(sbi->s_numfiles);
 	fscb->s_magic = cpu_to_le16(sb->s_magic);
 	fscb->s_newfs = 0;
 	fscb->s_version = EXOFS_FSCB_VER;
@@ -529,7 +529,8 @@
 			     struct osd_dev_info *odi)
 {
 	odi->systemid_len = le32_to_cpu(dt_dev->systemid_len);
-	memcpy(odi->systemid, dt_dev->systemid, odi->systemid_len);
+	if (likely(odi->systemid_len))
+		memcpy(odi->systemid, dt_dev->systemid, OSD_SYSTEMID_LEN);
 
 	odi->osdname_len = le32_to_cpu(dt_dev->osdname_len);
 	odi->osdname = dt_dev->osdname;
@@ -565,7 +566,7 @@
 
 	aoded = kzalloc(sizeof(*aoded), GFP_KERNEL);
 	if (unlikely(!aoded)) {
-		EXOFS_ERR("ERROR: faild allocating Device array[%d]\n",
+		EXOFS_ERR("ERROR: failed allocating Device array[%d]\n",
 			  numdevs);
 		return -ENOMEM;
 	}
@@ -754,6 +755,7 @@
 	sb->s_blocksize = EXOFS_BLKSIZE;
 	sb->s_blocksize_bits = EXOFS_BLKSHIFT;
 	sb->s_maxbytes = MAX_LFS_FILESIZE;
+	sb->s_max_links = EXOFS_LINK_MAX;
 	atomic_set(&sbi->s_curr_pending, 0);
 	sb->s_bdev = NULL;
 	sb->s_dev = 0;
@@ -818,9 +820,8 @@
 		ret = PTR_ERR(root);
 		goto free_sbi;
 	}
-	sb->s_root = d_alloc_root(root);
+	sb->s_root = d_make_root(root);
 	if (!sb->s_root) {
-		iput(root);
 		EXOFS_ERR("ERROR: get root inode failed\n");
 		ret = -ENOMEM;
 		goto free_sbi;
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 75ad433..0b2b4db 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -1,5 +1,636 @@
+/*
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/include/linux/minix_fs.h
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
+#include <linux/blockgroup_lock.h>
+#include <linux/percpu_counter.h>
+#include <linux/rbtree.h>
+
+/* XXX Here for now... not interested in restructing headers JUST now */
+
+/* data type for block offset of block group */
+typedef int ext2_grpblk_t;
+
+/* data type for filesystem-wide blocks number */
+typedef unsigned long ext2_fsblk_t;
+
+#define E2FSBLK "%lu"
+
+struct ext2_reserve_window {
+	ext2_fsblk_t		_rsv_start;	/* First byte reserved */
+	ext2_fsblk_t		_rsv_end;	/* Last byte reserved or 0 */
+};
+
+struct ext2_reserve_window_node {
+	struct rb_node	 	rsv_node;
+	__u32			rsv_goal_size;
+	__u32			rsv_alloc_hit;
+	struct ext2_reserve_window	rsv_window;
+};
+
+struct ext2_block_alloc_info {
+	/* information about reservation window */
+	struct ext2_reserve_window_node	rsv_window_node;
+	/*
+	 * was i_next_alloc_block in ext2_inode_info
+	 * is the logical (file-relative) number of the
+	 * most-recently-allocated block in this file.
+	 * We use this for detecting linearly ascending allocation requests.
+	 */
+	__u32			last_alloc_logical_block;
+	/*
+	 * Was i_next_alloc_goal in ext2_inode_info
+	 * is the *physical* companion to i_next_alloc_block.
+	 * it the the physical block number of the block which was most-recentl
+	 * allocated to this file.  This give us the goal (target) for the next
+	 * allocation when we detect linearly ascending requests.
+	 */
+	ext2_fsblk_t		last_alloc_physical_block;
+};
+
+#define rsv_start rsv_window._rsv_start
+#define rsv_end rsv_window._rsv_end
+
+/*
+ * second extended-fs super-block data in memory
+ */
+struct ext2_sb_info {
+	unsigned long s_frag_size;	/* Size of a fragment in bytes */
+	unsigned long s_frags_per_block;/* Number of fragments per block */
+	unsigned long s_inodes_per_block;/* Number of inodes per block */
+	unsigned long s_frags_per_group;/* Number of fragments in a group */
+	unsigned long s_blocks_per_group;/* Number of blocks in a group */
+	unsigned long s_inodes_per_group;/* Number of inodes in a group */
+	unsigned long s_itb_per_group;	/* Number of inode table blocks per group */
+	unsigned long s_gdb_count;	/* Number of group descriptor blocks */
+	unsigned long s_desc_per_block;	/* Number of group descriptors per block */
+	unsigned long s_groups_count;	/* Number of groups in the fs */
+	unsigned long s_overhead_last;  /* Last calculated overhead */
+	unsigned long s_blocks_last;    /* Last seen block count */
+	struct buffer_head * s_sbh;	/* Buffer containing the super block */
+	struct ext2_super_block * s_es;	/* Pointer to the super block in the buffer */
+	struct buffer_head ** s_group_desc;
+	unsigned long  s_mount_opt;
+	unsigned long s_sb_block;
+	uid_t s_resuid;
+	gid_t s_resgid;
+	unsigned short s_mount_state;
+	unsigned short s_pad;
+	int s_addr_per_block_bits;
+	int s_desc_per_block_bits;
+	int s_inode_size;
+	int s_first_ino;
+	spinlock_t s_next_gen_lock;
+	u32 s_next_generation;
+	unsigned long s_dir_count;
+	u8 *s_debts;
+	struct percpu_counter s_freeblocks_counter;
+	struct percpu_counter s_freeinodes_counter;
+	struct percpu_counter s_dirs_counter;
+	struct blockgroup_lock *s_blockgroup_lock;
+	/* root of the per fs reservation window tree */
+	spinlock_t s_rsv_window_lock;
+	struct rb_root s_rsv_window_root;
+	struct ext2_reserve_window_node s_rsv_window_head;
+	/*
+	 * s_lock protects against concurrent modifications of s_mount_state,
+	 * s_blocks_last, s_overhead_last and the content of superblock's
+	 * buffer pointed to by sbi->s_es.
+	 *
+	 * Note: It is used in ext2_show_options() to provide a consistent view
+	 * of the mount options.
+	 */
+	spinlock_t s_lock;
+};
+
+static inline spinlock_t *
+sb_bgl_lock(struct ext2_sb_info *sbi, unsigned int block_group)
+{
+	return bgl_lock_ptr(sbi->s_blockgroup_lock, block_group);
+}
+
+/*
+ * Define EXT2FS_DEBUG to produce debug messages
+ */
+#undef EXT2FS_DEBUG
+
+/*
+ * Define EXT2_RESERVATION to reserve data blocks for expanding files
+ */
+#define EXT2_DEFAULT_RESERVE_BLOCKS     8
+/*max window size: 1024(direct blocks) + 3([t,d]indirect blocks) */
+#define EXT2_MAX_RESERVE_BLOCKS         1027
+#define EXT2_RESERVE_WINDOW_NOT_ALLOCATED 0
+/*
+ * The second extended file system version
+ */
+#define EXT2FS_DATE		"95/08/09"
+#define EXT2FS_VERSION		"0.5b"
+
+/*
+ * Debug code
+ */
+#ifdef EXT2FS_DEBUG
+#	define ext2_debug(f, a...)	{ \
+					printk ("EXT2-fs DEBUG (%s, %d): %s:", \
+						__FILE__, __LINE__, __func__); \
+				  	printk (f, ## a); \
+					}
+#else
+#	define ext2_debug(f, a...)	/**/
+#endif
+
+/*
+ * Special inode numbers
+ */
+#define	EXT2_BAD_INO		 1	/* Bad blocks inode */
+#define EXT2_ROOT_INO		 2	/* Root inode */
+#define EXT2_BOOT_LOADER_INO	 5	/* Boot loader inode */
+#define EXT2_UNDEL_DIR_INO	 6	/* Undelete directory inode */
+
+/* First non-reserved inode for old ext2 filesystems */
+#define EXT2_GOOD_OLD_FIRST_INO	11
+
+static inline struct ext2_sb_info *EXT2_SB(struct super_block *sb)
+{
+	return sb->s_fs_info;
+}
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT2_MIN_BLOCK_SIZE		1024
+#define	EXT2_MAX_BLOCK_SIZE		4096
+#define EXT2_MIN_BLOCK_LOG_SIZE		  10
+#define EXT2_BLOCK_SIZE(s)		((s)->s_blocksize)
+#define	EXT2_ADDR_PER_BLOCK(s)		(EXT2_BLOCK_SIZE(s) / sizeof (__u32))
+#define EXT2_BLOCK_SIZE_BITS(s)		((s)->s_blocksize_bits)
+#define	EXT2_ADDR_PER_BLOCK_BITS(s)	(EXT2_SB(s)->s_addr_per_block_bits)
+#define EXT2_INODE_SIZE(s)		(EXT2_SB(s)->s_inode_size)
+#define EXT2_FIRST_INO(s)		(EXT2_SB(s)->s_first_ino)
+
+/*
+ * Macro-instructions used to manage fragments
+ */
+#define EXT2_MIN_FRAG_SIZE		1024
+#define	EXT2_MAX_FRAG_SIZE		4096
+#define EXT2_MIN_FRAG_LOG_SIZE		  10
+#define EXT2_FRAG_SIZE(s)		(EXT2_SB(s)->s_frag_size)
+#define EXT2_FRAGS_PER_BLOCK(s)		(EXT2_SB(s)->s_frags_per_block)
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext2_group_desc
+{
+	__le32	bg_block_bitmap;		/* Blocks bitmap block */
+	__le32	bg_inode_bitmap;		/* Inodes bitmap block */
+	__le32	bg_inode_table;		/* Inodes table block */
+	__le16	bg_free_blocks_count;	/* Free blocks count */
+	__le16	bg_free_inodes_count;	/* Free inodes count */
+	__le16	bg_used_dirs_count;	/* Directories count */
+	__le16	bg_pad;
+	__le32	bg_reserved[3];
+};
+
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+#define EXT2_BLOCKS_PER_GROUP(s)	(EXT2_SB(s)->s_blocks_per_group)
+#define EXT2_DESC_PER_BLOCK(s)		(EXT2_SB(s)->s_desc_per_block)
+#define EXT2_INODES_PER_GROUP(s)	(EXT2_SB(s)->s_inodes_per_group)
+#define EXT2_DESC_PER_BLOCK_BITS(s)	(EXT2_SB(s)->s_desc_per_block_bits)
+
+/*
+ * Constants relative to the data blocks
+ */
+#define	EXT2_NDIR_BLOCKS		12
+#define	EXT2_IND_BLOCK			EXT2_NDIR_BLOCKS
+#define	EXT2_DIND_BLOCK			(EXT2_IND_BLOCK + 1)
+#define	EXT2_TIND_BLOCK			(EXT2_DIND_BLOCK + 1)
+#define	EXT2_N_BLOCKS			(EXT2_TIND_BLOCK + 1)
+
+/*
+ * Inode flags (GETFLAGS/SETFLAGS)
+ */
+#define	EXT2_SECRM_FL			FS_SECRM_FL	/* Secure deletion */
+#define	EXT2_UNRM_FL			FS_UNRM_FL	/* Undelete */
+#define	EXT2_COMPR_FL			FS_COMPR_FL	/* Compress file */
+#define EXT2_SYNC_FL			FS_SYNC_FL	/* Synchronous updates */
+#define EXT2_IMMUTABLE_FL		FS_IMMUTABLE_FL	/* Immutable file */
+#define EXT2_APPEND_FL			FS_APPEND_FL	/* writes to file may only append */
+#define EXT2_NODUMP_FL			FS_NODUMP_FL	/* do not dump file */
+#define EXT2_NOATIME_FL			FS_NOATIME_FL	/* do not update atime */
+/* Reserved for compression usage... */
+#define EXT2_DIRTY_FL			FS_DIRTY_FL
+#define EXT2_COMPRBLK_FL		FS_COMPRBLK_FL	/* One or more compressed clusters */
+#define EXT2_NOCOMP_FL			FS_NOCOMP_FL	/* Don't compress */
+#define EXT2_ECOMPR_FL			FS_ECOMPR_FL	/* Compression error */
+/* End compression flags --- maybe not all used */	
+#define EXT2_BTREE_FL			FS_BTREE_FL	/* btree format dir */
+#define EXT2_INDEX_FL			FS_INDEX_FL	/* hash-indexed directory */
+#define EXT2_IMAGIC_FL			FS_IMAGIC_FL	/* AFS directory */
+#define EXT2_JOURNAL_DATA_FL		FS_JOURNAL_DATA_FL /* Reserved for ext3 */
+#define EXT2_NOTAIL_FL			FS_NOTAIL_FL	/* file tail should not be merged */
+#define EXT2_DIRSYNC_FL			FS_DIRSYNC_FL	/* dirsync behaviour (directories only) */
+#define EXT2_TOPDIR_FL			FS_TOPDIR_FL	/* Top of directory hierarchies*/
+#define EXT2_RESERVED_FL		FS_RESERVED_FL	/* reserved for ext2 lib */
+
+#define EXT2_FL_USER_VISIBLE		FS_FL_USER_VISIBLE	/* User visible flags */
+#define EXT2_FL_USER_MODIFIABLE		FS_FL_USER_MODIFIABLE	/* User modifiable flags */
+
+/* Flags that should be inherited by new inodes from their parent. */
+#define EXT2_FL_INHERITED (EXT2_SECRM_FL | EXT2_UNRM_FL | EXT2_COMPR_FL |\
+			   EXT2_SYNC_FL | EXT2_NODUMP_FL |\
+			   EXT2_NOATIME_FL | EXT2_COMPRBLK_FL |\
+			   EXT2_NOCOMP_FL | EXT2_JOURNAL_DATA_FL |\
+			   EXT2_NOTAIL_FL | EXT2_DIRSYNC_FL)
+
+/* Flags that are appropriate for regular files (all but dir-specific ones). */
+#define EXT2_REG_FLMASK (~(EXT2_DIRSYNC_FL | EXT2_TOPDIR_FL))
+
+/* Flags that are appropriate for non-directories/regular files. */
+#define EXT2_OTHER_FLMASK (EXT2_NODUMP_FL | EXT2_NOATIME_FL)
+
+/* Mask out flags that are inappropriate for the given type of inode. */
+static inline __u32 ext2_mask_flags(umode_t mode, __u32 flags)
+{
+	if (S_ISDIR(mode))
+		return flags;
+	else if (S_ISREG(mode))
+		return flags & EXT2_REG_FLMASK;
+	else
+		return flags & EXT2_OTHER_FLMASK;
+}
+
+/*
+ * ioctl commands
+ */
+#define	EXT2_IOC_GETFLAGS		FS_IOC_GETFLAGS
+#define	EXT2_IOC_SETFLAGS		FS_IOC_SETFLAGS
+#define	EXT2_IOC_GETVERSION		FS_IOC_GETVERSION
+#define	EXT2_IOC_SETVERSION		FS_IOC_SETVERSION
+#define	EXT2_IOC_GETRSVSZ		_IOR('f', 5, long)
+#define	EXT2_IOC_SETRSVSZ		_IOW('f', 6, long)
+
+/*
+ * ioctl commands in 32 bit emulation
+ */
+#define EXT2_IOC32_GETFLAGS		FS_IOC32_GETFLAGS
+#define EXT2_IOC32_SETFLAGS		FS_IOC32_SETFLAGS
+#define EXT2_IOC32_GETVERSION		FS_IOC32_GETVERSION
+#define EXT2_IOC32_SETVERSION		FS_IOC32_SETVERSION
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext2_inode {
+	__le16	i_mode;		/* File mode */
+	__le16	i_uid;		/* Low 16 bits of Owner Uid */
+	__le32	i_size;		/* Size in bytes */
+	__le32	i_atime;	/* Access time */
+	__le32	i_ctime;	/* Creation time */
+	__le32	i_mtime;	/* Modification time */
+	__le32	i_dtime;	/* Deletion Time */
+	__le16	i_gid;		/* Low 16 bits of Group Id */
+	__le16	i_links_count;	/* Links count */
+	__le32	i_blocks;	/* Blocks count */
+	__le32	i_flags;	/* File flags */
+	union {
+		struct {
+			__le32  l_i_reserved1;
+		} linux1;
+		struct {
+			__le32  h_i_translator;
+		} hurd1;
+		struct {
+			__le32  m_i_reserved1;
+		} masix1;
+	} osd1;				/* OS dependent 1 */
+	__le32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+	__le32	i_generation;	/* File version (for NFS) */
+	__le32	i_file_acl;	/* File ACL */
+	__le32	i_dir_acl;	/* Directory ACL */
+	__le32	i_faddr;	/* Fragment address */
+	union {
+		struct {
+			__u8	l_i_frag;	/* Fragment number */
+			__u8	l_i_fsize;	/* Fragment size */
+			__u16	i_pad1;
+			__le16	l_i_uid_high;	/* these 2 fields    */
+			__le16	l_i_gid_high;	/* were reserved2[0] */
+			__u32	l_i_reserved2;
+		} linux2;
+		struct {
+			__u8	h_i_frag;	/* Fragment number */
+			__u8	h_i_fsize;	/* Fragment size */
+			__le16	h_i_mode_high;
+			__le16	h_i_uid_high;
+			__le16	h_i_gid_high;
+			__le32	h_i_author;
+		} hurd2;
+		struct {
+			__u8	m_i_frag;	/* Fragment number */
+			__u8	m_i_fsize;	/* Fragment size */
+			__u16	m_pad1;
+			__u32	m_i_reserved2[2];
+		} masix2;
+	} osd2;				/* OS dependent 2 */
+};
+
+#define i_size_high	i_dir_acl
+
+#define i_reserved1	osd1.linux1.l_i_reserved1
+#define i_frag		osd2.linux2.l_i_frag
+#define i_fsize		osd2.linux2.l_i_fsize
+#define i_uid_low	i_uid
+#define i_gid_low	i_gid
+#define i_uid_high	osd2.linux2.l_i_uid_high
+#define i_gid_high	osd2.linux2.l_i_gid_high
+#define i_reserved2	osd2.linux2.l_i_reserved2
+
+/*
+ * File system states
+ */
+#define	EXT2_VALID_FS			0x0001	/* Unmounted cleanly */
+#define	EXT2_ERROR_FS			0x0002	/* Errors detected */
+
+/*
+ * Mount flags
+ */
+#define EXT2_MOUNT_CHECK		0x000001  /* Do mount-time checks */
+#define EXT2_MOUNT_OLDALLOC		0x000002  /* Don't use the new Orlov allocator */
+#define EXT2_MOUNT_GRPID		0x000004  /* Create files with directory's group */
+#define EXT2_MOUNT_DEBUG		0x000008  /* Some debugging messages */
+#define EXT2_MOUNT_ERRORS_CONT		0x000010  /* Continue on errors */
+#define EXT2_MOUNT_ERRORS_RO		0x000020  /* Remount fs ro on errors */
+#define EXT2_MOUNT_ERRORS_PANIC		0x000040  /* Panic on errors */
+#define EXT2_MOUNT_MINIX_DF		0x000080  /* Mimics the Minix statfs */
+#define EXT2_MOUNT_NOBH			0x000100  /* No buffer_heads */
+#define EXT2_MOUNT_NO_UID32		0x000200  /* Disable 32-bit UIDs */
+#define EXT2_MOUNT_XATTR_USER		0x004000  /* Extended user attributes */
+#define EXT2_MOUNT_POSIX_ACL		0x008000  /* POSIX Access Control Lists */
+#define EXT2_MOUNT_XIP			0x010000  /* Execute in place */
+#define EXT2_MOUNT_USRQUOTA		0x020000  /* user quota */
+#define EXT2_MOUNT_GRPQUOTA		0x040000  /* group quota */
+#define EXT2_MOUNT_RESERVATION		0x080000  /* Preallocation */
+
+
+#define clear_opt(o, opt)		o &= ~EXT2_MOUNT_##opt
+#define set_opt(o, opt)			o |= EXT2_MOUNT_##opt
+#define test_opt(sb, opt)		(EXT2_SB(sb)->s_mount_opt & \
+					 EXT2_MOUNT_##opt)
+/*
+ * Maximal mount counts between two filesystem checks
+ */
+#define EXT2_DFL_MAX_MNT_COUNT		20	/* Allow 20 mounts */
+#define EXT2_DFL_CHECKINTERVAL		0	/* Don't use interval check */
+
+/*
+ * Behaviour when detecting errors
+ */
+#define EXT2_ERRORS_CONTINUE		1	/* Continue execution */
+#define EXT2_ERRORS_RO			2	/* Remount fs read-only */
+#define EXT2_ERRORS_PANIC		3	/* Panic */
+#define EXT2_ERRORS_DEFAULT		EXT2_ERRORS_CONTINUE
+
+/*
+ * Structure of the super block
+ */
+struct ext2_super_block {
+	__le32	s_inodes_count;		/* Inodes count */
+	__le32	s_blocks_count;		/* Blocks count */
+	__le32	s_r_blocks_count;	/* Reserved blocks count */
+	__le32	s_free_blocks_count;	/* Free blocks count */
+	__le32	s_free_inodes_count;	/* Free inodes count */
+	__le32	s_first_data_block;	/* First Data Block */
+	__le32	s_log_block_size;	/* Block size */
+	__le32	s_log_frag_size;	/* Fragment size */
+	__le32	s_blocks_per_group;	/* # Blocks per group */
+	__le32	s_frags_per_group;	/* # Fragments per group */
+	__le32	s_inodes_per_group;	/* # Inodes per group */
+	__le32	s_mtime;		/* Mount time */
+	__le32	s_wtime;		/* Write time */
+	__le16	s_mnt_count;		/* Mount count */
+	__le16	s_max_mnt_count;	/* Maximal mount count */
+	__le16	s_magic;		/* Magic signature */
+	__le16	s_state;		/* File system state */
+	__le16	s_errors;		/* Behaviour when detecting errors */
+	__le16	s_minor_rev_level; 	/* minor revision level */
+	__le32	s_lastcheck;		/* time of last check */
+	__le32	s_checkinterval;	/* max. time between checks */
+	__le32	s_creator_os;		/* OS */
+	__le32	s_rev_level;		/* Revision level */
+	__le16	s_def_resuid;		/* Default uid for reserved blocks */
+	__le16	s_def_resgid;		/* Default gid for reserved blocks */
+	/*
+	 * These fields are for EXT2_DYNAMIC_REV superblocks only.
+	 *
+	 * Note: the difference between the compatible feature set and
+	 * the incompatible feature set is that if there is a bit set
+	 * in the incompatible feature set that the kernel doesn't
+	 * know about, it should refuse to mount the filesystem.
+	 * 
+	 * e2fsck's requirements are more strict; if it doesn't know
+	 * about a feature in either the compatible or incompatible
+	 * feature set, it must abort and not try to meddle with
+	 * things it doesn't understand...
+	 */
+	__le32	s_first_ino; 		/* First non-reserved inode */
+	__le16   s_inode_size; 		/* size of inode structure */
+	__le16	s_block_group_nr; 	/* block group # of this superblock */
+	__le32	s_feature_compat; 	/* compatible feature set */
+	__le32	s_feature_incompat; 	/* incompatible feature set */
+	__le32	s_feature_ro_compat; 	/* readonly-compatible feature set */
+	__u8	s_uuid[16];		/* 128-bit uuid for volume */
+	char	s_volume_name[16]; 	/* volume name */
+	char	s_last_mounted[64]; 	/* directory where last mounted */
+	__le32	s_algorithm_usage_bitmap; /* For compression */
+	/*
+	 * Performance hints.  Directory preallocation should only
+	 * happen if the EXT2_COMPAT_PREALLOC flag is on.
+	 */
+	__u8	s_prealloc_blocks;	/* Nr of blocks to try to preallocate*/
+	__u8	s_prealloc_dir_blocks;	/* Nr to preallocate for dirs */
+	__u16	s_padding1;
+	/*
+	 * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
+	 */
+	__u8	s_journal_uuid[16];	/* uuid of journal superblock */
+	__u32	s_journal_inum;		/* inode number of journal file */
+	__u32	s_journal_dev;		/* device number of journal file */
+	__u32	s_last_orphan;		/* start of list of inodes to delete */
+	__u32	s_hash_seed[4];		/* HTREE hash seed */
+	__u8	s_def_hash_version;	/* Default hash version to use */
+	__u8	s_reserved_char_pad;
+	__u16	s_reserved_word_pad;
+	__le32	s_default_mount_opts;
+ 	__le32	s_first_meta_bg; 	/* First metablock block group */
+	__u32	s_reserved[190];	/* Padding to the end of the block */
+};
+
+/*
+ * Codes for operating systems
+ */
+#define EXT2_OS_LINUX		0
+#define EXT2_OS_HURD		1
+#define EXT2_OS_MASIX		2
+#define EXT2_OS_FREEBSD		3
+#define EXT2_OS_LITES		4
+
+/*
+ * Revision levels
+ */
+#define EXT2_GOOD_OLD_REV	0	/* The good old (original) format */
+#define EXT2_DYNAMIC_REV	1 	/* V2 format w/ dynamic inode sizes */
+
+#define EXT2_CURRENT_REV	EXT2_GOOD_OLD_REV
+#define EXT2_MAX_SUPP_REV	EXT2_DYNAMIC_REV
+
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Feature set definitions
+ */
+
+#define EXT2_HAS_COMPAT_FEATURE(sb,mask)			\
+	( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
+#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask)			\
+	( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
+#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask)			\
+	( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
+#define EXT2_SET_COMPAT_FEATURE(sb,mask)			\
+	EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
+#define EXT2_SET_RO_COMPAT_FEATURE(sb,mask)			\
+	EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
+#define EXT2_SET_INCOMPAT_FEATURE(sb,mask)			\
+	EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
+#define EXT2_CLEAR_COMPAT_FEATURE(sb,mask)			\
+	EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
+#define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask)			\
+	EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
+#define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask)			\
+	EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
+
+#define EXT2_FEATURE_COMPAT_DIR_PREALLOC	0x0001
+#define EXT2_FEATURE_COMPAT_IMAGIC_INODES	0x0002
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL		0x0004
+#define EXT2_FEATURE_COMPAT_EXT_ATTR		0x0008
+#define EXT2_FEATURE_COMPAT_RESIZE_INO		0x0010
+#define EXT2_FEATURE_COMPAT_DIR_INDEX		0x0020
+#define EXT2_FEATURE_COMPAT_ANY			0xffffffff
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
+#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR	0x0004
+#define EXT2_FEATURE_RO_COMPAT_ANY		0xffffffff
+
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION	0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE		0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER		0x0004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008
+#define EXT2_FEATURE_INCOMPAT_META_BG		0x0010
+#define EXT2_FEATURE_INCOMPAT_ANY		0xffffffff
+
+#define EXT2_FEATURE_COMPAT_SUPP	EXT2_FEATURE_COMPAT_EXT_ATTR
+#define EXT2_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE| \
+					 EXT2_FEATURE_INCOMPAT_META_BG)
+#define EXT2_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+					 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED	~EXT2_FEATURE_RO_COMPAT_SUPP
+#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED	~EXT2_FEATURE_INCOMPAT_SUPP
+
+/*
+ * Default values for user and/or group using reserved blocks
+ */
+#define	EXT2_DEF_RESUID		0
+#define	EXT2_DEF_RESGID		0
+
+/*
+ * Default mount options
+ */
+#define EXT2_DEFM_DEBUG		0x0001
+#define EXT2_DEFM_BSDGROUPS	0x0002
+#define EXT2_DEFM_XATTR_USER	0x0004
+#define EXT2_DEFM_ACL		0x0008
+#define EXT2_DEFM_UID16		0x0010
+    /* Not used by ext2, but reserved for use by ext3 */
+#define EXT3_DEFM_JMODE		0x0060 
+#define EXT3_DEFM_JMODE_DATA	0x0020
+#define EXT3_DEFM_JMODE_ORDERED	0x0040
+#define EXT3_DEFM_JMODE_WBACK	0x0060
+
+/*
+ * Structure of a directory entry
+ */
+
+struct ext2_dir_entry {
+	__le32	inode;			/* Inode number */
+	__le16	rec_len;		/* Directory entry length */
+	__le16	name_len;		/* Name length */
+	char	name[];			/* File name, up to EXT2_NAME_LEN */
+};
+
+/*
+ * The new version of the directory entry.  Since EXT2 structures are
+ * stored in intel byte order, and the name_len field could never be
+ * bigger than 255 chars, it's safe to reclaim the extra byte for the
+ * file_type field.
+ */
+struct ext2_dir_entry_2 {
+	__le32	inode;			/* Inode number */
+	__le16	rec_len;		/* Directory entry length */
+	__u8	name_len;		/* Name length */
+	__u8	file_type;
+	char	name[];			/* File name, up to EXT2_NAME_LEN */
+};
+
+/*
+ * Ext2 directory file types.  Only the low 3 bits are used.  The
+ * other bits are reserved for now.
+ */
+enum {
+	EXT2_FT_UNKNOWN		= 0,
+	EXT2_FT_REG_FILE	= 1,
+	EXT2_FT_DIR		= 2,
+	EXT2_FT_CHRDEV		= 3,
+	EXT2_FT_BLKDEV		= 4,
+	EXT2_FT_FIFO		= 5,
+	EXT2_FT_SOCK		= 6,
+	EXT2_FT_SYMLINK		= 7,
+	EXT2_FT_MAX
+};
+
+/*
+ * EXT2_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 4
+ */
+#define EXT2_DIR_PAD		 	4
+#define EXT2_DIR_ROUND 			(EXT2_DIR_PAD - 1)
+#define EXT2_DIR_REC_LEN(name_len)	(((name_len) + 8 + EXT2_DIR_ROUND) & \
+					 ~EXT2_DIR_ROUND)
+#define EXT2_MAX_REC_LEN		((1<<16)-1)
+
+static inline void verify_offsets(void)
+{
+#define A(x,y) BUILD_BUG_ON(x != offsetof(struct ext2_super_block, y));
+	A(EXT2_SB_MAGIC_OFFSET, s_magic);
+	A(EXT2_SB_BLOCKS_OFFSET, s_blocks_count);
+	A(EXT2_SB_BSIZE_OFFSET, s_log_block_size);
+#undef A
+}
 
 /*
  * ext2 mount options
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 0804198..dffb865 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -195,9 +195,6 @@
 	struct inode *inode = old_dentry->d_inode;
 	int err;
 
-	if (inode->i_nlink >= EXT2_LINK_MAX)
-		return -EMLINK;
-
 	dquot_initialize(dir);
 
 	inode->i_ctime = CURRENT_TIME_SEC;
@@ -217,10 +214,7 @@
 static int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
 {
 	struct inode * inode;
-	int err = -EMLINK;
-
-	if (dir->i_nlink >= EXT2_LINK_MAX)
-		goto out;
+	int err;
 
 	dquot_initialize(dir);
 
@@ -346,11 +340,6 @@
 			drop_nlink(new_inode);
 		inode_dec_link_count(new_inode);
 	} else {
-		if (dir_de) {
-			err = -EMLINK;
-			if (new_dir->i_nlink >= EXT2_LINK_MAX)
-				goto out_dir;
-		}
 		err = ext2_add_link(new_dentry, old_inode);
 		if (err)
 			goto out_dir;
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 0090595..e1025c7 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -919,6 +919,7 @@
 	}
 
 	sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits);
+	sb->s_max_links = EXT2_LINK_MAX;
 
 	if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) {
 		sbi->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
@@ -1087,9 +1088,8 @@
 		goto failed_mount3;
 	}
 
-	sb->s_root = d_alloc_root(root);
+	sb->s_root = d_make_root(root);
 	if (!sb->s_root) {
-		iput(root);
 		ext2_msg(sb, KERN_ERR, "error: get root inode failed");
 		ret = -ENOMEM;
 		goto failed_mount3;
diff --git a/fs/ext2/xattr_security.c b/fs/ext2/xattr_security.c
index be7a8d0..cfedb2c 100644
--- a/fs/ext2/xattr_security.c
+++ b/fs/ext2/xattr_security.c
@@ -3,10 +3,7 @@
  * Handler for storing security labels as extended attributes.
  */
 
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
 #include <linux/security.h>
 #include "xattr.h"
 
diff --git a/fs/ext2/xattr_trusted.c b/fs/ext2/xattr_trusted.c
index 2989467..7e19257 100644
--- a/fs/ext2/xattr_trusted.c
+++ b/fs/ext2/xattr_trusted.c
@@ -5,10 +5,7 @@
  * Copyright (C) 2003 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
  */
 
-#include <linux/string.h>
-#include <linux/capability.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+#include "ext2.h"
 #include "xattr.h"
 
 static size_t
diff --git a/fs/ext2/xip.c b/fs/ext2/xip.c
index 322a56b..1c33128 100644
--- a/fs/ext2/xip.c
+++ b/fs/ext2/xip.c
@@ -9,8 +9,6 @@
 #include <linux/fs.h>
 #include <linux/genhd.h>
 #include <linux/buffer_head.h>
-#include <linux/ext2_fs_sb.h>
-#include <linux/ext2_fs.h>
 #include <linux/blkdev.h>
 #include "ext2.h"
 #include "xip.h"
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
index 3091f62..c76832c 100644
--- a/fs/ext3/acl.c
+++ b/fs/ext3/acl.c
@@ -4,13 +4,7 @@
  * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
  */
 
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/capability.h>
-#include <linux/fs.h>
-#include <linux/ext3_jbd.h>
-#include <linux/ext3_fs.h>
+#include "ext3.h"
 #include "xattr.h"
 #include "acl.h"
 
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index a203892..baac1b1 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -11,17 +11,9 @@
  *        David S. Miller (davem@caip.rutgers.edu), 1995
  */
 
-#include <linux/time.h>
-#include <linux/capability.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/jbd.h>
-#include <linux/ext3_fs.h>
-#include <linux/ext3_jbd.h>
 #include <linux/quotaops.h>
-#include <linux/buffer_head.h>
 #include <linux/blkdev.h>
-#include <trace/events/ext3.h>
+#include "ext3.h"
 
 /*
  * balloc.c contains the blocks allocation and deallocation routines
@@ -1743,8 +1735,11 @@
 
 	*errp = 0;
 	brelse(bitmap_bh);
-	dquot_free_block(inode, *count-num);
-	*count = num;
+
+	if (num < *count) {
+		dquot_free_block(inode, *count-num);
+		*count = num;
+	}
 
 	trace_ext3_allocate_blocks(inode, goal, num,
 				   (unsigned long long)ret_block);
@@ -1970,7 +1965,7 @@
 	sbi = EXT3_SB(sb);
 
 	 /* Walk through the whole group */
-	while (start < max) {
+	while (start <= max) {
 		start = bitmap_search_next_usable_block(start, bitmap_bh, max);
 		if (start < 0)
 			break;
@@ -1980,7 +1975,7 @@
 		 * Allocate contiguous free extents by setting bits in the
 		 * block bitmap
 		 */
-		while (next < max
+		while (next <= max
 			&& claim_block(sb_bgl_lock(sbi, group),
 					next, bitmap_bh)) {
 			next++;
@@ -2091,73 +2086,74 @@
  */
 int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range)
 {
-	ext3_grpblk_t last_block, first_block, free_blocks;
-	unsigned long first_group, last_group;
-	unsigned long group, ngroups;
+	ext3_grpblk_t last_block, first_block;
+	unsigned long group, first_group, last_group;
 	struct ext3_group_desc *gdp;
 	struct ext3_super_block *es = EXT3_SB(sb)->s_es;
-	uint64_t start, len, minlen, trimmed;
+	uint64_t start, minlen, end, trimmed = 0;
+	ext3_fsblk_t first_data_blk =
+			le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block);
 	ext3_fsblk_t max_blks = le32_to_cpu(es->s_blocks_count);
 	int ret = 0;
 
-	start = (range->start >> sb->s_blocksize_bits) +
-		le32_to_cpu(es->s_first_data_block);
-	len = range->len >> sb->s_blocksize_bits;
+	start = range->start >> sb->s_blocksize_bits;
+	end = start + (range->len >> sb->s_blocksize_bits) - 1;
 	minlen = range->minlen >> sb->s_blocksize_bits;
-	trimmed = 0;
 
-	if (unlikely(minlen > EXT3_BLOCKS_PER_GROUP(sb)))
+	if (unlikely(minlen > EXT3_BLOCKS_PER_GROUP(sb)) ||
+	    unlikely(start >= max_blks))
 		return -EINVAL;
-	if (start >= max_blks)
-		return -EINVAL;
-	if (start + len > max_blks)
-		len = max_blks - start;
+	if (end >= max_blks)
+		end = max_blks - 1;
+	if (end <= first_data_blk)
+		goto out;
+	if (start < first_data_blk)
+		start = first_data_blk;
 
-	ngroups = EXT3_SB(sb)->s_groups_count;
 	smp_rmb();
 
 	/* Determine first and last group to examine based on start and len */
 	ext3_get_group_no_and_offset(sb, (ext3_fsblk_t) start,
 				     &first_group, &first_block);
-	ext3_get_group_no_and_offset(sb, (ext3_fsblk_t) (start + len),
+	ext3_get_group_no_and_offset(sb, (ext3_fsblk_t) end,
 				     &last_group, &last_block);
-	last_group = (last_group > ngroups - 1) ? ngroups - 1 : last_group;
-	last_block = EXT3_BLOCKS_PER_GROUP(sb);
 
-	if (first_group > last_group)
-		return -EINVAL;
+	/* end now represents the last block to discard in this group */
+	end = EXT3_BLOCKS_PER_GROUP(sb) - 1;
 
 	for (group = first_group; group <= last_group; group++) {
 		gdp = ext3_get_group_desc(sb, group, NULL);
 		if (!gdp)
 			break;
 
-		free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
-		if (free_blocks < minlen)
-			continue;
-
 		/*
 		 * For all the groups except the last one, last block will
-		 * always be EXT3_BLOCKS_PER_GROUP(sb), so we only need to
-		 * change it for the last group in which case first_block +
-		 * len < EXT3_BLOCKS_PER_GROUP(sb).
+		 * always be EXT3_BLOCKS_PER_GROUP(sb)-1, so we only need to
+		 * change it for the last group, note that last_block is
+		 * already computed earlier by ext3_get_group_no_and_offset()
 		 */
-		if (first_block + len < EXT3_BLOCKS_PER_GROUP(sb))
-			last_block = first_block + len;
-		len -= last_block - first_block;
+		if (group == last_group)
+			end = last_block;
 
-		ret = ext3_trim_all_free(sb, group, first_block,
-					last_block, minlen);
-		if (ret < 0)
-			break;
+		if (le16_to_cpu(gdp->bg_free_blocks_count) >= minlen) {
+			ret = ext3_trim_all_free(sb, group, first_block,
+						 end, minlen);
+			if (ret < 0)
+				break;
+			trimmed += ret;
+		}
 
-		trimmed += ret;
+		/*
+		 * For every group except the first one, we are sure
+		 * that the first block to discard will be block #0.
+		 */
 		first_block = 0;
 	}
 
-	if (ret >= 0)
+	if (ret > 0)
 		ret = 0;
-	range->len = trimmed * sb->s_blocksize;
 
+out:
+	range->len = trimmed * sb->s_blocksize;
 	return ret;
 }
diff --git a/fs/ext3/bitmap.c b/fs/ext3/bitmap.c
index 6afc39d..909d13e 100644
--- a/fs/ext3/bitmap.c
+++ b/fs/ext3/bitmap.c
@@ -7,9 +7,7 @@
  * Universite Pierre et Marie Curie (Paris VI)
  */
 
-#include <linux/buffer_head.h>
-#include <linux/jbd.h>
-#include <linux/ext3_fs.h>
+#include "ext3.h"
 
 #ifdef EXT3FS_DEBUG
 
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index 34f0a07..cc761ad8 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -21,12 +21,7 @@
  *
  */
 
-#include <linux/fs.h>
-#include <linux/jbd.h>
-#include <linux/ext3_fs.h>
-#include <linux/buffer_head.h>
-#include <linux/slab.h>
-#include <linux/rbtree.h>
+#include "ext3.h"
 
 static unsigned char ext3_filetype_table[] = {
 	DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
diff --git a/fs/ext3/ext3.h b/fs/ext3/ext3.h
new file mode 100644
index 0000000..b6515fd
--- /dev/null
+++ b/fs/ext3/ext3.h
@@ -0,0 +1,1322 @@
+/*
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
+ *
+ * Copyright 1998--1999 Red Hat corp --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/include/linux/minix_fs.h
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#include <linux/fs.h>
+#include <linux/jbd.h>
+#include <linux/magic.h>
+#include <linux/bug.h>
+#include <linux/blockgroup_lock.h>
+
+/*
+ * The second extended filesystem constants/structures
+ */
+
+/*
+ * Define EXT3FS_DEBUG to produce debug messages
+ */
+#undef EXT3FS_DEBUG
+
+/*
+ * Define EXT3_RESERVATION to reserve data blocks for expanding files
+ */
+#define EXT3_DEFAULT_RESERVE_BLOCKS     8
+/*max window size: 1024(direct blocks) + 3([t,d]indirect blocks) */
+#define EXT3_MAX_RESERVE_BLOCKS         1027
+#define EXT3_RESERVE_WINDOW_NOT_ALLOCATED 0
+
+/*
+ * Debug code
+ */
+#ifdef EXT3FS_DEBUG
+#define ext3_debug(f, a...)						\
+	do {								\
+		printk (KERN_DEBUG "EXT3-fs DEBUG (%s, %d): %s:",	\
+			__FILE__, __LINE__, __func__);		\
+		printk (KERN_DEBUG f, ## a);				\
+	} while (0)
+#else
+#define ext3_debug(f, a...)	do {} while (0)
+#endif
+
+/*
+ * Special inodes numbers
+ */
+#define	EXT3_BAD_INO		 1	/* Bad blocks inode */
+#define EXT3_ROOT_INO		 2	/* Root inode */
+#define EXT3_BOOT_LOADER_INO	 5	/* Boot loader inode */
+#define EXT3_UNDEL_DIR_INO	 6	/* Undelete directory inode */
+#define EXT3_RESIZE_INO		 7	/* Reserved group descriptors inode */
+#define EXT3_JOURNAL_INO	 8	/* Journal inode */
+
+/* First non-reserved inode for old ext3 filesystems */
+#define EXT3_GOOD_OLD_FIRST_INO	11
+
+/*
+ * Maximal count of links to a file
+ */
+#define EXT3_LINK_MAX		32000
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT3_MIN_BLOCK_SIZE		1024
+#define	EXT3_MAX_BLOCK_SIZE		65536
+#define EXT3_MIN_BLOCK_LOG_SIZE		10
+#define EXT3_BLOCK_SIZE(s)		((s)->s_blocksize)
+#define	EXT3_ADDR_PER_BLOCK(s)		(EXT3_BLOCK_SIZE(s) / sizeof (__u32))
+#define EXT3_BLOCK_SIZE_BITS(s)	((s)->s_blocksize_bits)
+#define	EXT3_ADDR_PER_BLOCK_BITS(s)	(EXT3_SB(s)->s_addr_per_block_bits)
+#define EXT3_INODE_SIZE(s)		(EXT3_SB(s)->s_inode_size)
+#define EXT3_FIRST_INO(s)		(EXT3_SB(s)->s_first_ino)
+
+/*
+ * Macro-instructions used to manage fragments
+ */
+#define EXT3_MIN_FRAG_SIZE		1024
+#define	EXT3_MAX_FRAG_SIZE		4096
+#define EXT3_MIN_FRAG_LOG_SIZE		  10
+#define EXT3_FRAG_SIZE(s)		(EXT3_SB(s)->s_frag_size)
+#define EXT3_FRAGS_PER_BLOCK(s)		(EXT3_SB(s)->s_frags_per_block)
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext3_group_desc
+{
+	__le32	bg_block_bitmap;		/* Blocks bitmap block */
+	__le32	bg_inode_bitmap;		/* Inodes bitmap block */
+	__le32	bg_inode_table;		/* Inodes table block */
+	__le16	bg_free_blocks_count;	/* Free blocks count */
+	__le16	bg_free_inodes_count;	/* Free inodes count */
+	__le16	bg_used_dirs_count;	/* Directories count */
+	__u16	bg_pad;
+	__le32	bg_reserved[3];
+};
+
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+#define EXT3_BLOCKS_PER_GROUP(s)	(EXT3_SB(s)->s_blocks_per_group)
+#define EXT3_DESC_PER_BLOCK(s)		(EXT3_SB(s)->s_desc_per_block)
+#define EXT3_INODES_PER_GROUP(s)	(EXT3_SB(s)->s_inodes_per_group)
+#define EXT3_DESC_PER_BLOCK_BITS(s)	(EXT3_SB(s)->s_desc_per_block_bits)
+
+/*
+ * Constants relative to the data blocks
+ */
+#define	EXT3_NDIR_BLOCKS		12
+#define	EXT3_IND_BLOCK			EXT3_NDIR_BLOCKS
+#define	EXT3_DIND_BLOCK			(EXT3_IND_BLOCK + 1)
+#define	EXT3_TIND_BLOCK			(EXT3_DIND_BLOCK + 1)
+#define	EXT3_N_BLOCKS			(EXT3_TIND_BLOCK + 1)
+
+/*
+ * Inode flags
+ */
+#define	EXT3_SECRM_FL			0x00000001 /* Secure deletion */
+#define	EXT3_UNRM_FL			0x00000002 /* Undelete */
+#define	EXT3_COMPR_FL			0x00000004 /* Compress file */
+#define EXT3_SYNC_FL			0x00000008 /* Synchronous updates */
+#define EXT3_IMMUTABLE_FL		0x00000010 /* Immutable file */
+#define EXT3_APPEND_FL			0x00000020 /* writes to file may only append */
+#define EXT3_NODUMP_FL			0x00000040 /* do not dump file */
+#define EXT3_NOATIME_FL			0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define EXT3_DIRTY_FL			0x00000100
+#define EXT3_COMPRBLK_FL		0x00000200 /* One or more compressed clusters */
+#define EXT3_NOCOMPR_FL			0x00000400 /* Don't compress */
+#define EXT3_ECOMPR_FL			0x00000800 /* Compression error */
+/* End compression flags --- maybe not all used */
+#define EXT3_INDEX_FL			0x00001000 /* hash-indexed directory */
+#define EXT3_IMAGIC_FL			0x00002000 /* AFS directory */
+#define EXT3_JOURNAL_DATA_FL		0x00004000 /* file data should be journaled */
+#define EXT3_NOTAIL_FL			0x00008000 /* file tail should not be merged */
+#define EXT3_DIRSYNC_FL			0x00010000 /* dirsync behaviour (directories only) */
+#define EXT3_TOPDIR_FL			0x00020000 /* Top of directory hierarchies*/
+#define EXT3_RESERVED_FL		0x80000000 /* reserved for ext3 lib */
+
+#define EXT3_FL_USER_VISIBLE		0x0003DFFF /* User visible flags */
+#define EXT3_FL_USER_MODIFIABLE		0x000380FF /* User modifiable flags */
+
+/* Flags that should be inherited by new inodes from their parent. */
+#define EXT3_FL_INHERITED (EXT3_SECRM_FL | EXT3_UNRM_FL | EXT3_COMPR_FL |\
+			   EXT3_SYNC_FL | EXT3_NODUMP_FL |\
+			   EXT3_NOATIME_FL | EXT3_COMPRBLK_FL |\
+			   EXT3_NOCOMPR_FL | EXT3_JOURNAL_DATA_FL |\
+			   EXT3_NOTAIL_FL | EXT3_DIRSYNC_FL)
+
+/* Flags that are appropriate for regular files (all but dir-specific ones). */
+#define EXT3_REG_FLMASK (~(EXT3_DIRSYNC_FL | EXT3_TOPDIR_FL))
+
+/* Flags that are appropriate for non-directories/regular files. */
+#define EXT3_OTHER_FLMASK (EXT3_NODUMP_FL | EXT3_NOATIME_FL)
+
+/* Mask out flags that are inappropriate for the given type of inode. */
+static inline __u32 ext3_mask_flags(umode_t mode, __u32 flags)
+{
+	if (S_ISDIR(mode))
+		return flags;
+	else if (S_ISREG(mode))
+		return flags & EXT3_REG_FLMASK;
+	else
+		return flags & EXT3_OTHER_FLMASK;
+}
+
+/* Used to pass group descriptor data when online resize is done */
+struct ext3_new_group_input {
+	__u32 group;            /* Group number for this data */
+	__u32 block_bitmap;     /* Absolute block number of block bitmap */
+	__u32 inode_bitmap;     /* Absolute block number of inode bitmap */
+	__u32 inode_table;      /* Absolute block number of inode table start */
+	__u32 blocks_count;     /* Total number of blocks in this group */
+	__u16 reserved_blocks;  /* Number of reserved blocks in this group */
+	__u16 unused;
+};
+
+/* The struct ext3_new_group_input in kernel space, with free_blocks_count */
+struct ext3_new_group_data {
+	__u32 group;
+	__u32 block_bitmap;
+	__u32 inode_bitmap;
+	__u32 inode_table;
+	__u32 blocks_count;
+	__u16 reserved_blocks;
+	__u16 unused;
+	__u32 free_blocks_count;
+};
+
+
+/*
+ * ioctl commands
+ */
+#define	EXT3_IOC_GETFLAGS		FS_IOC_GETFLAGS
+#define	EXT3_IOC_SETFLAGS		FS_IOC_SETFLAGS
+#define	EXT3_IOC_GETVERSION		_IOR('f', 3, long)
+#define	EXT3_IOC_SETVERSION		_IOW('f', 4, long)
+#define EXT3_IOC_GROUP_EXTEND		_IOW('f', 7, unsigned long)
+#define EXT3_IOC_GROUP_ADD		_IOW('f', 8,struct ext3_new_group_input)
+#define	EXT3_IOC_GETVERSION_OLD		FS_IOC_GETVERSION
+#define	EXT3_IOC_SETVERSION_OLD		FS_IOC_SETVERSION
+#ifdef CONFIG_JBD_DEBUG
+#define EXT3_IOC_WAIT_FOR_READONLY	_IOR('f', 99, long)
+#endif
+#define EXT3_IOC_GETRSVSZ		_IOR('f', 5, long)
+#define EXT3_IOC_SETRSVSZ		_IOW('f', 6, long)
+
+/*
+ * ioctl commands in 32 bit emulation
+ */
+#define EXT3_IOC32_GETFLAGS		FS_IOC32_GETFLAGS
+#define EXT3_IOC32_SETFLAGS		FS_IOC32_SETFLAGS
+#define EXT3_IOC32_GETVERSION		_IOR('f', 3, int)
+#define EXT3_IOC32_SETVERSION		_IOW('f', 4, int)
+#define EXT3_IOC32_GETRSVSZ		_IOR('f', 5, int)
+#define EXT3_IOC32_SETRSVSZ		_IOW('f', 6, int)
+#define EXT3_IOC32_GROUP_EXTEND		_IOW('f', 7, unsigned int)
+#ifdef CONFIG_JBD_DEBUG
+#define EXT3_IOC32_WAIT_FOR_READONLY	_IOR('f', 99, int)
+#endif
+#define EXT3_IOC32_GETVERSION_OLD	FS_IOC32_GETVERSION
+#define EXT3_IOC32_SETVERSION_OLD	FS_IOC32_SETVERSION
+
+
+/*
+ *  Mount options
+ */
+struct ext3_mount_options {
+	unsigned long s_mount_opt;
+	uid_t s_resuid;
+	gid_t s_resgid;
+	unsigned long s_commit_interval;
+#ifdef CONFIG_QUOTA
+	int s_jquota_fmt;
+	char *s_qf_names[MAXQUOTAS];
+#endif
+};
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext3_inode {
+	__le16	i_mode;		/* File mode */
+	__le16	i_uid;		/* Low 16 bits of Owner Uid */
+	__le32	i_size;		/* Size in bytes */
+	__le32	i_atime;	/* Access time */
+	__le32	i_ctime;	/* Creation time */
+	__le32	i_mtime;	/* Modification time */
+	__le32	i_dtime;	/* Deletion Time */
+	__le16	i_gid;		/* Low 16 bits of Group Id */
+	__le16	i_links_count;	/* Links count */
+	__le32	i_blocks;	/* Blocks count */
+	__le32	i_flags;	/* File flags */
+	union {
+		struct {
+			__u32  l_i_reserved1;
+		} linux1;
+		struct {
+			__u32  h_i_translator;
+		} hurd1;
+		struct {
+			__u32  m_i_reserved1;
+		} masix1;
+	} osd1;				/* OS dependent 1 */
+	__le32	i_block[EXT3_N_BLOCKS];/* Pointers to blocks */
+	__le32	i_generation;	/* File version (for NFS) */
+	__le32	i_file_acl;	/* File ACL */
+	__le32	i_dir_acl;	/* Directory ACL */
+	__le32	i_faddr;	/* Fragment address */
+	union {
+		struct {
+			__u8	l_i_frag;	/* Fragment number */
+			__u8	l_i_fsize;	/* Fragment size */
+			__u16	i_pad1;
+			__le16	l_i_uid_high;	/* these 2 fields    */
+			__le16	l_i_gid_high;	/* were reserved2[0] */
+			__u32	l_i_reserved2;
+		} linux2;
+		struct {
+			__u8	h_i_frag;	/* Fragment number */
+			__u8	h_i_fsize;	/* Fragment size */
+			__u16	h_i_mode_high;
+			__u16	h_i_uid_high;
+			__u16	h_i_gid_high;
+			__u32	h_i_author;
+		} hurd2;
+		struct {
+			__u8	m_i_frag;	/* Fragment number */
+			__u8	m_i_fsize;	/* Fragment size */
+			__u16	m_pad1;
+			__u32	m_i_reserved2[2];
+		} masix2;
+	} osd2;				/* OS dependent 2 */
+	__le16	i_extra_isize;
+	__le16	i_pad1;
+};
+
+#define i_size_high	i_dir_acl
+
+#define i_reserved1	osd1.linux1.l_i_reserved1
+#define i_frag		osd2.linux2.l_i_frag
+#define i_fsize		osd2.linux2.l_i_fsize
+#define i_uid_low	i_uid
+#define i_gid_low	i_gid
+#define i_uid_high	osd2.linux2.l_i_uid_high
+#define i_gid_high	osd2.linux2.l_i_gid_high
+#define i_reserved2	osd2.linux2.l_i_reserved2
+
+/*
+ * File system states
+ */
+#define	EXT3_VALID_FS			0x0001	/* Unmounted cleanly */
+#define	EXT3_ERROR_FS			0x0002	/* Errors detected */
+#define	EXT3_ORPHAN_FS			0x0004	/* Orphans being recovered */
+
+/*
+ * Misc. filesystem flags
+ */
+#define EXT2_FLAGS_SIGNED_HASH		0x0001  /* Signed dirhash in use */
+#define EXT2_FLAGS_UNSIGNED_HASH	0x0002  /* Unsigned dirhash in use */
+#define EXT2_FLAGS_TEST_FILESYS		0x0004	/* to test development code */
+
+/*
+ * Mount flags
+ */
+#define EXT3_MOUNT_CHECK		0x00001	/* Do mount-time checks */
+/* EXT3_MOUNT_OLDALLOC was there */
+#define EXT3_MOUNT_GRPID		0x00004	/* Create files with directory's group */
+#define EXT3_MOUNT_DEBUG		0x00008	/* Some debugging messages */
+#define EXT3_MOUNT_ERRORS_CONT		0x00010	/* Continue on errors */
+#define EXT3_MOUNT_ERRORS_RO		0x00020	/* Remount fs ro on errors */
+#define EXT3_MOUNT_ERRORS_PANIC		0x00040	/* Panic on errors */
+#define EXT3_MOUNT_MINIX_DF		0x00080	/* Mimics the Minix statfs */
+#define EXT3_MOUNT_NOLOAD		0x00100	/* Don't use existing journal*/
+#define EXT3_MOUNT_ABORT		0x00200	/* Fatal error detected */
+#define EXT3_MOUNT_DATA_FLAGS		0x00C00	/* Mode for data writes: */
+#define EXT3_MOUNT_JOURNAL_DATA		0x00400	/* Write data to journal */
+#define EXT3_MOUNT_ORDERED_DATA		0x00800	/* Flush data before commit */
+#define EXT3_MOUNT_WRITEBACK_DATA	0x00C00	/* No data ordering */
+#define EXT3_MOUNT_UPDATE_JOURNAL	0x01000	/* Update the journal format */
+#define EXT3_MOUNT_NO_UID32		0x02000  /* Disable 32-bit UIDs */
+#define EXT3_MOUNT_XATTR_USER		0x04000	/* Extended user attributes */
+#define EXT3_MOUNT_POSIX_ACL		0x08000	/* POSIX Access Control Lists */
+#define EXT3_MOUNT_RESERVATION		0x10000	/* Preallocation */
+#define EXT3_MOUNT_BARRIER		0x20000 /* Use block barriers */
+#define EXT3_MOUNT_QUOTA		0x80000 /* Some quota option set */
+#define EXT3_MOUNT_USRQUOTA		0x100000 /* "old" user quota */
+#define EXT3_MOUNT_GRPQUOTA		0x200000 /* "old" group quota */
+#define EXT3_MOUNT_DATA_ERR_ABORT	0x400000 /* Abort on file data write
+						  * error in ordered mode */
+
+/* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
+#ifndef _LINUX_EXT2_FS_H
+#define clear_opt(o, opt)		o &= ~EXT3_MOUNT_##opt
+#define set_opt(o, opt)			o |= EXT3_MOUNT_##opt
+#define test_opt(sb, opt)		(EXT3_SB(sb)->s_mount_opt & \
+					 EXT3_MOUNT_##opt)
+#else
+#define EXT2_MOUNT_NOLOAD		EXT3_MOUNT_NOLOAD
+#define EXT2_MOUNT_ABORT		EXT3_MOUNT_ABORT
+#define EXT2_MOUNT_DATA_FLAGS		EXT3_MOUNT_DATA_FLAGS
+#endif
+
+#define ext3_set_bit			__set_bit_le
+#define ext3_set_bit_atomic		ext2_set_bit_atomic
+#define ext3_clear_bit			__clear_bit_le
+#define ext3_clear_bit_atomic		ext2_clear_bit_atomic
+#define ext3_test_bit			test_bit_le
+#define ext3_find_next_zero_bit		find_next_zero_bit_le
+
+/*
+ * Maximal mount counts between two filesystem checks
+ */
+#define EXT3_DFL_MAX_MNT_COUNT		20	/* Allow 20 mounts */
+#define EXT3_DFL_CHECKINTERVAL		0	/* Don't use interval check */
+
+/*
+ * Behaviour when detecting errors
+ */
+#define EXT3_ERRORS_CONTINUE		1	/* Continue execution */
+#define EXT3_ERRORS_RO			2	/* Remount fs read-only */
+#define EXT3_ERRORS_PANIC		3	/* Panic */
+#define EXT3_ERRORS_DEFAULT		EXT3_ERRORS_CONTINUE
+
+/*
+ * Structure of the super block
+ */
+struct ext3_super_block {
+/*00*/	__le32	s_inodes_count;		/* Inodes count */
+	__le32	s_blocks_count;		/* Blocks count */
+	__le32	s_r_blocks_count;	/* Reserved blocks count */
+	__le32	s_free_blocks_count;	/* Free blocks count */
+/*10*/	__le32	s_free_inodes_count;	/* Free inodes count */
+	__le32	s_first_data_block;	/* First Data Block */
+	__le32	s_log_block_size;	/* Block size */
+	__le32	s_log_frag_size;	/* Fragment size */
+/*20*/	__le32	s_blocks_per_group;	/* # Blocks per group */
+	__le32	s_frags_per_group;	/* # Fragments per group */
+	__le32	s_inodes_per_group;	/* # Inodes per group */
+	__le32	s_mtime;		/* Mount time */
+/*30*/	__le32	s_wtime;		/* Write time */
+	__le16	s_mnt_count;		/* Mount count */
+	__le16	s_max_mnt_count;	/* Maximal mount count */
+	__le16	s_magic;		/* Magic signature */
+	__le16	s_state;		/* File system state */
+	__le16	s_errors;		/* Behaviour when detecting errors */
+	__le16	s_minor_rev_level;	/* minor revision level */
+/*40*/	__le32	s_lastcheck;		/* time of last check */
+	__le32	s_checkinterval;	/* max. time between checks */
+	__le32	s_creator_os;		/* OS */
+	__le32	s_rev_level;		/* Revision level */
+/*50*/	__le16	s_def_resuid;		/* Default uid for reserved blocks */
+	__le16	s_def_resgid;		/* Default gid for reserved blocks */
+	/*
+	 * These fields are for EXT3_DYNAMIC_REV superblocks only.
+	 *
+	 * Note: the difference between the compatible feature set and
+	 * the incompatible feature set is that if there is a bit set
+	 * in the incompatible feature set that the kernel doesn't
+	 * know about, it should refuse to mount the filesystem.
+	 *
+	 * e2fsck's requirements are more strict; if it doesn't know
+	 * about a feature in either the compatible or incompatible
+	 * feature set, it must abort and not try to meddle with
+	 * things it doesn't understand...
+	 */
+	__le32	s_first_ino;		/* First non-reserved inode */
+	__le16   s_inode_size;		/* size of inode structure */
+	__le16	s_block_group_nr;	/* block group # of this superblock */
+	__le32	s_feature_compat;	/* compatible feature set */
+/*60*/	__le32	s_feature_incompat;	/* incompatible feature set */
+	__le32	s_feature_ro_compat;	/* readonly-compatible feature set */
+/*68*/	__u8	s_uuid[16];		/* 128-bit uuid for volume */
+/*78*/	char	s_volume_name[16];	/* volume name */
+/*88*/	char	s_last_mounted[64];	/* directory where last mounted */
+/*C8*/	__le32	s_algorithm_usage_bitmap; /* For compression */
+	/*
+	 * Performance hints.  Directory preallocation should only
+	 * happen if the EXT3_FEATURE_COMPAT_DIR_PREALLOC flag is on.
+	 */
+	__u8	s_prealloc_blocks;	/* Nr of blocks to try to preallocate*/
+	__u8	s_prealloc_dir_blocks;	/* Nr to preallocate for dirs */
+	__le16	s_reserved_gdt_blocks;	/* Per group desc for online growth */
+	/*
+	 * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
+	 */
+/*D0*/	__u8	s_journal_uuid[16];	/* uuid of journal superblock */
+/*E0*/	__le32	s_journal_inum;		/* inode number of journal file */
+	__le32	s_journal_dev;		/* device number of journal file */
+	__le32	s_last_orphan;		/* start of list of inodes to delete */
+	__le32	s_hash_seed[4];		/* HTREE hash seed */
+	__u8	s_def_hash_version;	/* Default hash version to use */
+	__u8	s_reserved_char_pad;
+	__u16	s_reserved_word_pad;
+	__le32	s_default_mount_opts;
+	__le32	s_first_meta_bg;	/* First metablock block group */
+	__le32	s_mkfs_time;		/* When the filesystem was created */
+	__le32	s_jnl_blocks[17];	/* Backup of the journal inode */
+	/* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
+/*150*/	__le32	s_blocks_count_hi;	/* Blocks count */
+	__le32	s_r_blocks_count_hi;	/* Reserved blocks count */
+	__le32	s_free_blocks_count_hi;	/* Free blocks count */
+	__le16	s_min_extra_isize;	/* All inodes have at least # bytes */
+	__le16	s_want_extra_isize; 	/* New inodes should reserve # bytes */
+	__le32	s_flags;		/* Miscellaneous flags */
+	__le16  s_raid_stride;		/* RAID stride */
+	__le16  s_mmp_interval;         /* # seconds to wait in MMP checking */
+	__le64  s_mmp_block;            /* Block for multi-mount protection */
+	__le32  s_raid_stripe_width;    /* blocks on all data disks (N*stride)*/
+	__u8	s_log_groups_per_flex;  /* FLEX_BG group size */
+	__u8	s_reserved_char_pad2;
+	__le16  s_reserved_pad;
+	__u32   s_reserved[162];        /* Padding to the end of the block */
+};
+
+/* data type for block offset of block group */
+typedef int ext3_grpblk_t;
+
+/* data type for filesystem-wide blocks number */
+typedef unsigned long ext3_fsblk_t;
+
+#define E3FSBLK "%lu"
+
+struct ext3_reserve_window {
+	ext3_fsblk_t	_rsv_start;	/* First byte reserved */
+	ext3_fsblk_t	_rsv_end;	/* Last byte reserved or 0 */
+};
+
+struct ext3_reserve_window_node {
+	struct rb_node		rsv_node;
+	__u32			rsv_goal_size;
+	__u32			rsv_alloc_hit;
+	struct ext3_reserve_window	rsv_window;
+};
+
+struct ext3_block_alloc_info {
+	/* information about reservation window */
+	struct ext3_reserve_window_node	rsv_window_node;
+	/*
+	 * was i_next_alloc_block in ext3_inode_info
+	 * is the logical (file-relative) number of the
+	 * most-recently-allocated block in this file.
+	 * We use this for detecting linearly ascending allocation requests.
+	 */
+	__u32                   last_alloc_logical_block;
+	/*
+	 * Was i_next_alloc_goal in ext3_inode_info
+	 * is the *physical* companion to i_next_alloc_block.
+	 * it the physical block number of the block which was most-recentl
+	 * allocated to this file.  This give us the goal (target) for the next
+	 * allocation when we detect linearly ascending requests.
+	 */
+	ext3_fsblk_t		last_alloc_physical_block;
+};
+
+#define rsv_start rsv_window._rsv_start
+#define rsv_end rsv_window._rsv_end
+
+/*
+ * third extended file system inode data in memory
+ */
+struct ext3_inode_info {
+	__le32	i_data[15];	/* unconverted */
+	__u32	i_flags;
+#ifdef EXT3_FRAGMENTS
+	__u32	i_faddr;
+	__u8	i_frag_no;
+	__u8	i_frag_size;
+#endif
+	ext3_fsblk_t	i_file_acl;
+	__u32	i_dir_acl;
+	__u32	i_dtime;
+
+	/*
+	 * i_block_group is the number of the block group which contains
+	 * this file's inode.  Constant across the lifetime of the inode,
+	 * it is ued for making block allocation decisions - we try to
+	 * place a file's data blocks near its inode block, and new inodes
+	 * near to their parent directory's inode.
+	 */
+	__u32	i_block_group;
+	unsigned long	i_state_flags;	/* Dynamic state flags for ext3 */
+
+	/* block reservation info */
+	struct ext3_block_alloc_info *i_block_alloc_info;
+
+	__u32	i_dir_start_lookup;
+#ifdef CONFIG_EXT3_FS_XATTR
+	/*
+	 * Extended attributes can be read independently of the main file
+	 * data. Taking i_mutex even when reading would cause contention
+	 * between readers of EAs and writers of regular file data, so
+	 * instead we synchronize on xattr_sem when reading or changing
+	 * EAs.
+	 */
+	struct rw_semaphore xattr_sem;
+#endif
+
+	struct list_head i_orphan;	/* unlinked but open inodes */
+
+	/*
+	 * i_disksize keeps track of what the inode size is ON DISK, not
+	 * in memory.  During truncate, i_size is set to the new size by
+	 * the VFS prior to calling ext3_truncate(), but the filesystem won't
+	 * set i_disksize to 0 until the truncate is actually under way.
+	 *
+	 * The intent is that i_disksize always represents the blocks which
+	 * are used by this file.  This allows recovery to restart truncate
+	 * on orphans if we crash during truncate.  We actually write i_disksize
+	 * into the on-disk inode when writing inodes out, instead of i_size.
+	 *
+	 * The only time when i_disksize and i_size may be different is when
+	 * a truncate is in progress.  The only things which change i_disksize
+	 * are ext3_get_block (growth) and ext3_truncate (shrinkth).
+	 */
+	loff_t	i_disksize;
+
+	/* on-disk additional length */
+	__u16 i_extra_isize;
+
+	/*
+	 * truncate_mutex is for serialising ext3_truncate() against
+	 * ext3_getblock().  In the 2.4 ext2 design, great chunks of inode's
+	 * data tree are chopped off during truncate. We can't do that in
+	 * ext3 because whenever we perform intermediate commits during
+	 * truncate, the inode and all the metadata blocks *must* be in a
+	 * consistent state which allows truncation of the orphans to restart
+	 * during recovery.  Hence we must fix the get_block-vs-truncate race
+	 * by other means, so we have truncate_mutex.
+	 */
+	struct mutex truncate_mutex;
+
+	/*
+	 * Transactions that contain inode's metadata needed to complete
+	 * fsync and fdatasync, respectively.
+	 */
+	atomic_t i_sync_tid;
+	atomic_t i_datasync_tid;
+
+	struct inode vfs_inode;
+};
+
+/*
+ * third extended-fs super-block data in memory
+ */
+struct ext3_sb_info {
+	unsigned long s_frag_size;	/* Size of a fragment in bytes */
+	unsigned long s_frags_per_block;/* Number of fragments per block */
+	unsigned long s_inodes_per_block;/* Number of inodes per block */
+	unsigned long s_frags_per_group;/* Number of fragments in a group */
+	unsigned long s_blocks_per_group;/* Number of blocks in a group */
+	unsigned long s_inodes_per_group;/* Number of inodes in a group */
+	unsigned long s_itb_per_group;	/* Number of inode table blocks per group */
+	unsigned long s_gdb_count;	/* Number of group descriptor blocks */
+	unsigned long s_desc_per_block;	/* Number of group descriptors per block */
+	unsigned long s_groups_count;	/* Number of groups in the fs */
+	unsigned long s_overhead_last;  /* Last calculated overhead */
+	unsigned long s_blocks_last;    /* Last seen block count */
+	struct buffer_head * s_sbh;	/* Buffer containing the super block */
+	struct ext3_super_block * s_es;	/* Pointer to the super block in the buffer */
+	struct buffer_head ** s_group_desc;
+	unsigned long  s_mount_opt;
+	ext3_fsblk_t s_sb_block;
+	uid_t s_resuid;
+	gid_t s_resgid;
+	unsigned short s_mount_state;
+	unsigned short s_pad;
+	int s_addr_per_block_bits;
+	int s_desc_per_block_bits;
+	int s_inode_size;
+	int s_first_ino;
+	spinlock_t s_next_gen_lock;
+	u32 s_next_generation;
+	u32 s_hash_seed[4];
+	int s_def_hash_version;
+	int s_hash_unsigned;	/* 3 if hash should be signed, 0 if not */
+	struct percpu_counter s_freeblocks_counter;
+	struct percpu_counter s_freeinodes_counter;
+	struct percpu_counter s_dirs_counter;
+	struct blockgroup_lock *s_blockgroup_lock;
+
+	/* root of the per fs reservation window tree */
+	spinlock_t s_rsv_window_lock;
+	struct rb_root s_rsv_window_root;
+	struct ext3_reserve_window_node s_rsv_window_head;
+
+	/* Journaling */
+	struct inode * s_journal_inode;
+	struct journal_s * s_journal;
+	struct list_head s_orphan;
+	struct mutex s_orphan_lock;
+	struct mutex s_resize_lock;
+	unsigned long s_commit_interval;
+	struct block_device *journal_bdev;
+#ifdef CONFIG_QUOTA
+	char *s_qf_names[MAXQUOTAS];		/* Names of quota files with journalled quota */
+	int s_jquota_fmt;			/* Format of quota to use */
+#endif
+};
+
+static inline spinlock_t *
+sb_bgl_lock(struct ext3_sb_info *sbi, unsigned int block_group)
+{
+	return bgl_lock_ptr(sbi->s_blockgroup_lock, block_group);
+}
+
+static inline struct ext3_sb_info * EXT3_SB(struct super_block *sb)
+{
+	return sb->s_fs_info;
+}
+static inline struct ext3_inode_info *EXT3_I(struct inode *inode)
+{
+	return container_of(inode, struct ext3_inode_info, vfs_inode);
+}
+
+static inline int ext3_valid_inum(struct super_block *sb, unsigned long ino)
+{
+	return ino == EXT3_ROOT_INO ||
+		ino == EXT3_JOURNAL_INO ||
+		ino == EXT3_RESIZE_INO ||
+		(ino >= EXT3_FIRST_INO(sb) &&
+		 ino <= le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count));
+}
+
+/*
+ * Inode dynamic state flags
+ */
+enum {
+	EXT3_STATE_JDATA,		/* journaled data exists */
+	EXT3_STATE_NEW,			/* inode is newly created */
+	EXT3_STATE_XATTR,		/* has in-inode xattrs */
+	EXT3_STATE_FLUSH_ON_CLOSE,	/* flush dirty pages on close */
+};
+
+static inline int ext3_test_inode_state(struct inode *inode, int bit)
+{
+	return test_bit(bit, &EXT3_I(inode)->i_state_flags);
+}
+
+static inline void ext3_set_inode_state(struct inode *inode, int bit)
+{
+	set_bit(bit, &EXT3_I(inode)->i_state_flags);
+}
+
+static inline void ext3_clear_inode_state(struct inode *inode, int bit)
+{
+	clear_bit(bit, &EXT3_I(inode)->i_state_flags);
+}
+
+#define NEXT_ORPHAN(inode) EXT3_I(inode)->i_dtime
+
+/*
+ * Codes for operating systems
+ */
+#define EXT3_OS_LINUX		0
+#define EXT3_OS_HURD		1
+#define EXT3_OS_MASIX		2
+#define EXT3_OS_FREEBSD		3
+#define EXT3_OS_LITES		4
+
+/*
+ * Revision levels
+ */
+#define EXT3_GOOD_OLD_REV	0	/* The good old (original) format */
+#define EXT3_DYNAMIC_REV	1	/* V2 format w/ dynamic inode sizes */
+
+#define EXT3_CURRENT_REV	EXT3_GOOD_OLD_REV
+#define EXT3_MAX_SUPP_REV	EXT3_DYNAMIC_REV
+
+#define EXT3_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Feature set definitions
+ */
+
+#define EXT3_HAS_COMPAT_FEATURE(sb,mask)			\
+	( EXT3_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
+#define EXT3_HAS_RO_COMPAT_FEATURE(sb,mask)			\
+	( EXT3_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
+#define EXT3_HAS_INCOMPAT_FEATURE(sb,mask)			\
+	( EXT3_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
+#define EXT3_SET_COMPAT_FEATURE(sb,mask)			\
+	EXT3_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
+#define EXT3_SET_RO_COMPAT_FEATURE(sb,mask)			\
+	EXT3_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
+#define EXT3_SET_INCOMPAT_FEATURE(sb,mask)			\
+	EXT3_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
+#define EXT3_CLEAR_COMPAT_FEATURE(sb,mask)			\
+	EXT3_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
+#define EXT3_CLEAR_RO_COMPAT_FEATURE(sb,mask)			\
+	EXT3_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
+#define EXT3_CLEAR_INCOMPAT_FEATURE(sb,mask)			\
+	EXT3_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
+
+#define EXT3_FEATURE_COMPAT_DIR_PREALLOC	0x0001
+#define EXT3_FEATURE_COMPAT_IMAGIC_INODES	0x0002
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL		0x0004
+#define EXT3_FEATURE_COMPAT_EXT_ATTR		0x0008
+#define EXT3_FEATURE_COMPAT_RESIZE_INODE	0x0010
+#define EXT3_FEATURE_COMPAT_DIR_INDEX		0x0020
+
+#define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
+#define EXT3_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
+#define EXT3_FEATURE_RO_COMPAT_BTREE_DIR	0x0004
+
+#define EXT3_FEATURE_INCOMPAT_COMPRESSION	0x0001
+#define EXT3_FEATURE_INCOMPAT_FILETYPE		0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER		0x0004 /* Needs recovery */
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008 /* Journal device */
+#define EXT3_FEATURE_INCOMPAT_META_BG		0x0010
+
+#define EXT3_FEATURE_COMPAT_SUPP	EXT2_FEATURE_COMPAT_EXT_ATTR
+#define EXT3_FEATURE_INCOMPAT_SUPP	(EXT3_FEATURE_INCOMPAT_FILETYPE| \
+					 EXT3_FEATURE_INCOMPAT_RECOVER| \
+					 EXT3_FEATURE_INCOMPAT_META_BG)
+#define EXT3_FEATURE_RO_COMPAT_SUPP	(EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+					 EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \
+					 EXT3_FEATURE_RO_COMPAT_BTREE_DIR)
+
+/*
+ * Default values for user and/or group using reserved blocks
+ */
+#define	EXT3_DEF_RESUID		0
+#define	EXT3_DEF_RESGID		0
+
+/*
+ * Default mount options
+ */
+#define EXT3_DEFM_DEBUG		0x0001
+#define EXT3_DEFM_BSDGROUPS	0x0002
+#define EXT3_DEFM_XATTR_USER	0x0004
+#define EXT3_DEFM_ACL		0x0008
+#define EXT3_DEFM_UID16		0x0010
+#define EXT3_DEFM_JMODE		0x0060
+#define EXT3_DEFM_JMODE_DATA	0x0020
+#define EXT3_DEFM_JMODE_ORDERED	0x0040
+#define EXT3_DEFM_JMODE_WBACK	0x0060
+
+/*
+ * Structure of a directory entry
+ */
+#define EXT3_NAME_LEN 255
+
+struct ext3_dir_entry {
+	__le32	inode;			/* Inode number */
+	__le16	rec_len;		/* Directory entry length */
+	__le16	name_len;		/* Name length */
+	char	name[EXT3_NAME_LEN];	/* File name */
+};
+
+/*
+ * The new version of the directory entry.  Since EXT3 structures are
+ * stored in intel byte order, and the name_len field could never be
+ * bigger than 255 chars, it's safe to reclaim the extra byte for the
+ * file_type field.
+ */
+struct ext3_dir_entry_2 {
+	__le32	inode;			/* Inode number */
+	__le16	rec_len;		/* Directory entry length */
+	__u8	name_len;		/* Name length */
+	__u8	file_type;
+	char	name[EXT3_NAME_LEN];	/* File name */
+};
+
+/*
+ * Ext3 directory file types.  Only the low 3 bits are used.  The
+ * other bits are reserved for now.
+ */
+#define EXT3_FT_UNKNOWN		0
+#define EXT3_FT_REG_FILE	1
+#define EXT3_FT_DIR		2
+#define EXT3_FT_CHRDEV		3
+#define EXT3_FT_BLKDEV		4
+#define EXT3_FT_FIFO		5
+#define EXT3_FT_SOCK		6
+#define EXT3_FT_SYMLINK		7
+
+#define EXT3_FT_MAX		8
+
+/*
+ * EXT3_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 4
+ */
+#define EXT3_DIR_PAD			4
+#define EXT3_DIR_ROUND			(EXT3_DIR_PAD - 1)
+#define EXT3_DIR_REC_LEN(name_len)	(((name_len) + 8 + EXT3_DIR_ROUND) & \
+					 ~EXT3_DIR_ROUND)
+#define EXT3_MAX_REC_LEN		((1<<16)-1)
+
+/*
+ * Tests against MAX_REC_LEN etc were put in place for 64k block
+ * sizes; if that is not possible on this arch, we can skip
+ * those tests and speed things up.
+ */
+static inline unsigned ext3_rec_len_from_disk(__le16 dlen)
+{
+	unsigned len = le16_to_cpu(dlen);
+
+#if (PAGE_CACHE_SIZE >= 65536)
+	if (len == EXT3_MAX_REC_LEN)
+		return 1 << 16;
+#endif
+	return len;
+}
+
+static inline __le16 ext3_rec_len_to_disk(unsigned len)
+{
+#if (PAGE_CACHE_SIZE >= 65536)
+	if (len == (1 << 16))
+		return cpu_to_le16(EXT3_MAX_REC_LEN);
+	else if (len > (1 << 16))
+		BUG();
+#endif
+	return cpu_to_le16(len);
+}
+
+/*
+ * Hash Tree Directory indexing
+ * (c) Daniel Phillips, 2001
+ */
+
+#define is_dx(dir) (EXT3_HAS_COMPAT_FEATURE(dir->i_sb, \
+				      EXT3_FEATURE_COMPAT_DIR_INDEX) && \
+		      (EXT3_I(dir)->i_flags & EXT3_INDEX_FL))
+#define EXT3_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT3_LINK_MAX)
+#define EXT3_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1)
+
+/* Legal values for the dx_root hash_version field: */
+
+#define DX_HASH_LEGACY		0
+#define DX_HASH_HALF_MD4	1
+#define DX_HASH_TEA		2
+#define DX_HASH_LEGACY_UNSIGNED	3
+#define DX_HASH_HALF_MD4_UNSIGNED	4
+#define DX_HASH_TEA_UNSIGNED		5
+
+/* hash info structure used by the directory hash */
+struct dx_hash_info
+{
+	u32		hash;
+	u32		minor_hash;
+	int		hash_version;
+	u32		*seed;
+};
+
+#define EXT3_HTREE_EOF	0x7fffffff
+
+/*
+ * Control parameters used by ext3_htree_next_block
+ */
+#define HASH_NB_ALWAYS		1
+
+
+/*
+ * Describe an inode's exact location on disk and in memory
+ */
+struct ext3_iloc
+{
+	struct buffer_head *bh;
+	unsigned long offset;
+	unsigned long block_group;
+};
+
+static inline struct ext3_inode *ext3_raw_inode(struct ext3_iloc *iloc)
+{
+	return (struct ext3_inode *) (iloc->bh->b_data + iloc->offset);
+}
+
+/*
+ * This structure is stuffed into the struct file's private_data field
+ * for directories.  It is where we put information so that we can do
+ * readdir operations in hash tree order.
+ */
+struct dir_private_info {
+	struct rb_root	root;
+	struct rb_node	*curr_node;
+	struct fname	*extra_fname;
+	loff_t		last_pos;
+	__u32		curr_hash;
+	__u32		curr_minor_hash;
+	__u32		next_hash;
+};
+
+/* calculate the first block number of the group */
+static inline ext3_fsblk_t
+ext3_group_first_block_no(struct super_block *sb, unsigned long group_no)
+{
+	return group_no * (ext3_fsblk_t)EXT3_BLOCKS_PER_GROUP(sb) +
+		le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block);
+}
+
+/*
+ * Special error return code only used by dx_probe() and its callers.
+ */
+#define ERR_BAD_DX_DIR	-75000
+
+/*
+ * Function prototypes
+ */
+
+/*
+ * Ok, these declarations are also in <linux/kernel.h> but none of the
+ * ext3 source programs needs to include it so they are duplicated here.
+ */
+# define NORET_TYPE    /**/
+# define ATTRIB_NORET  __attribute__((noreturn))
+# define NORET_AND     noreturn,
+
+/* balloc.c */
+extern int ext3_bg_has_super(struct super_block *sb, int group);
+extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group);
+extern ext3_fsblk_t ext3_new_block (handle_t *handle, struct inode *inode,
+			ext3_fsblk_t goal, int *errp);
+extern ext3_fsblk_t ext3_new_blocks (handle_t *handle, struct inode *inode,
+			ext3_fsblk_t goal, unsigned long *count, int *errp);
+extern void ext3_free_blocks (handle_t *handle, struct inode *inode,
+			ext3_fsblk_t block, unsigned long count);
+extern void ext3_free_blocks_sb (handle_t *handle, struct super_block *sb,
+				 ext3_fsblk_t block, unsigned long count,
+				unsigned long *pdquot_freed_blocks);
+extern ext3_fsblk_t ext3_count_free_blocks (struct super_block *);
+extern void ext3_check_blocks_bitmap (struct super_block *);
+extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
+						    unsigned int block_group,
+						    struct buffer_head ** bh);
+extern int ext3_should_retry_alloc(struct super_block *sb, int *retries);
+extern void ext3_init_block_alloc_info(struct inode *);
+extern void ext3_rsv_window_add(struct super_block *sb, struct ext3_reserve_window_node *rsv);
+extern int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range);
+
+/* dir.c */
+extern int ext3_check_dir_entry(const char *, struct inode *,
+				struct ext3_dir_entry_2 *,
+				struct buffer_head *, unsigned long);
+extern int ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
+				    __u32 minor_hash,
+				    struct ext3_dir_entry_2 *dirent);
+extern void ext3_htree_free_dir_info(struct dir_private_info *p);
+
+/* fsync.c */
+extern int ext3_sync_file(struct file *, loff_t, loff_t, int);
+
+/* hash.c */
+extern int ext3fs_dirhash(const char *name, int len, struct
+			  dx_hash_info *hinfo);
+
+/* ialloc.c */
+extern struct inode * ext3_new_inode (handle_t *, struct inode *,
+				      const struct qstr *, umode_t);
+extern void ext3_free_inode (handle_t *, struct inode *);
+extern struct inode * ext3_orphan_get (struct super_block *, unsigned long);
+extern unsigned long ext3_count_free_inodes (struct super_block *);
+extern unsigned long ext3_count_dirs (struct super_block *);
+extern void ext3_check_inodes_bitmap (struct super_block *);
+extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
+
+
+/* inode.c */
+int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode,
+		struct buffer_head *bh, ext3_fsblk_t blocknr);
+struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
+struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
+int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
+	sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result,
+	int create);
+
+extern struct inode *ext3_iget(struct super_block *, unsigned long);
+extern int  ext3_write_inode (struct inode *, struct writeback_control *);
+extern int  ext3_setattr (struct dentry *, struct iattr *);
+extern void ext3_evict_inode (struct inode *);
+extern int  ext3_sync_inode (handle_t *, struct inode *);
+extern void ext3_discard_reservation (struct inode *);
+extern void ext3_dirty_inode(struct inode *, int);
+extern int ext3_change_inode_journal_flag(struct inode *, int);
+extern int ext3_get_inode_loc(struct inode *, struct ext3_iloc *);
+extern int ext3_can_truncate(struct inode *inode);
+extern void ext3_truncate(struct inode *inode);
+extern void ext3_set_inode_flags(struct inode *);
+extern void ext3_get_inode_flags(struct ext3_inode_info *);
+extern void ext3_set_aops(struct inode *inode);
+extern int ext3_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+		       u64 start, u64 len);
+
+/* ioctl.c */
+extern long ext3_ioctl(struct file *, unsigned int, unsigned long);
+extern long ext3_compat_ioctl(struct file *, unsigned int, unsigned long);
+
+/* namei.c */
+extern int ext3_orphan_add(handle_t *, struct inode *);
+extern int ext3_orphan_del(handle_t *, struct inode *);
+extern int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash,
+				__u32 start_minor_hash, __u32 *next_hash);
+
+/* resize.c */
+extern int ext3_group_add(struct super_block *sb,
+				struct ext3_new_group_data *input);
+extern int ext3_group_extend(struct super_block *sb,
+				struct ext3_super_block *es,
+				ext3_fsblk_t n_blocks_count);
+
+/* super.c */
+extern __printf(3, 4)
+void ext3_error(struct super_block *, const char *, const char *, ...);
+extern void __ext3_std_error (struct super_block *, const char *, int);
+extern __printf(3, 4)
+void ext3_abort(struct super_block *, const char *, const char *, ...);
+extern __printf(3, 4)
+void ext3_warning(struct super_block *, const char *, const char *, ...);
+extern __printf(3, 4)
+void ext3_msg(struct super_block *, const char *, const char *, ...);
+extern void ext3_update_dynamic_rev (struct super_block *sb);
+
+#define ext3_std_error(sb, errno)				\
+do {								\
+	if ((errno))						\
+		__ext3_std_error((sb), __func__, (errno));	\
+} while (0)
+
+/*
+ * Inodes and files operations
+ */
+
+/* dir.c */
+extern const struct file_operations ext3_dir_operations;
+
+/* file.c */
+extern const struct inode_operations ext3_file_inode_operations;
+extern const struct file_operations ext3_file_operations;
+
+/* namei.c */
+extern const struct inode_operations ext3_dir_inode_operations;
+extern const struct inode_operations ext3_special_inode_operations;
+
+/* symlink.c */
+extern const struct inode_operations ext3_symlink_inode_operations;
+extern const struct inode_operations ext3_fast_symlink_inode_operations;
+
+#define EXT3_JOURNAL(inode)	(EXT3_SB((inode)->i_sb)->s_journal)
+
+/* Define the number of blocks we need to account to a transaction to
+ * modify one block of data.
+ *
+ * We may have to touch one inode, one bitmap buffer, up to three
+ * indirection blocks, the group and superblock summaries, and the data
+ * block to complete the transaction.  */
+
+#define EXT3_SINGLEDATA_TRANS_BLOCKS	8U
+
+/* Extended attribute operations touch at most two data buffers,
+ * two bitmap buffers, and two group summaries, in addition to the inode
+ * and the superblock, which are already accounted for. */
+
+#define EXT3_XATTR_TRANS_BLOCKS		6U
+
+/* Define the minimum size for a transaction which modifies data.  This
+ * needs to take into account the fact that we may end up modifying two
+ * quota files too (one for the group, one for the user quota).  The
+ * superblock only gets updated once, of course, so don't bother
+ * counting that again for the quota updates. */
+
+#define EXT3_DATA_TRANS_BLOCKS(sb)	(EXT3_SINGLEDATA_TRANS_BLOCKS + \
+					 EXT3_XATTR_TRANS_BLOCKS - 2 + \
+					 EXT3_MAXQUOTAS_TRANS_BLOCKS(sb))
+
+/* Delete operations potentially hit one directory's namespace plus an
+ * entire inode, plus arbitrary amounts of bitmap/indirection data.  Be
+ * generous.  We can grow the delete transaction later if necessary. */
+
+#define EXT3_DELETE_TRANS_BLOCKS(sb)   (EXT3_MAXQUOTAS_TRANS_BLOCKS(sb) + 64)
+
+/* Define an arbitrary limit for the amount of data we will anticipate
+ * writing to any given transaction.  For unbounded transactions such as
+ * write(2) and truncate(2) we can write more than this, but we always
+ * start off at the maximum transaction size and grow the transaction
+ * optimistically as we go. */
+
+#define EXT3_MAX_TRANS_DATA		64U
+
+/* We break up a large truncate or write transaction once the handle's
+ * buffer credits gets this low, we need either to extend the
+ * transaction or to start a new one.  Reserve enough space here for
+ * inode, bitmap, superblock, group and indirection updates for at least
+ * one block, plus two quota updates.  Quota allocations are not
+ * needed. */
+
+#define EXT3_RESERVE_TRANS_BLOCKS	12U
+
+#define EXT3_INDEX_EXTRA_TRANS_BLOCKS	8
+
+#ifdef CONFIG_QUOTA
+/* Amount of blocks needed for quota update - we know that the structure was
+ * allocated so we need to update only inode+data */
+#define EXT3_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 2 : 0)
+/* Amount of blocks needed for quota insert/delete - we do some block writes
+ * but inode, sb and group updates are done only once */
+#define EXT3_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\
+		(EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_INIT_REWRITE) : 0)
+#define EXT3_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\
+		(EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_DEL_REWRITE) : 0)
+#else
+#define EXT3_QUOTA_TRANS_BLOCKS(sb) 0
+#define EXT3_QUOTA_INIT_BLOCKS(sb) 0
+#define EXT3_QUOTA_DEL_BLOCKS(sb) 0
+#endif
+#define EXT3_MAXQUOTAS_TRANS_BLOCKS(sb) (MAXQUOTAS*EXT3_QUOTA_TRANS_BLOCKS(sb))
+#define EXT3_MAXQUOTAS_INIT_BLOCKS(sb) (MAXQUOTAS*EXT3_QUOTA_INIT_BLOCKS(sb))
+#define EXT3_MAXQUOTAS_DEL_BLOCKS(sb) (MAXQUOTAS*EXT3_QUOTA_DEL_BLOCKS(sb))
+
+int
+ext3_mark_iloc_dirty(handle_t *handle,
+		     struct inode *inode,
+		     struct ext3_iloc *iloc);
+
+/*
+ * On success, We end up with an outstanding reference count against
+ * iloc->bh.  This _must_ be cleaned up later.
+ */
+
+int ext3_reserve_inode_write(handle_t *handle, struct inode *inode,
+			struct ext3_iloc *iloc);
+
+int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode);
+
+/*
+ * Wrapper functions with which ext3 calls into JBD.  The intent here is
+ * to allow these to be turned into appropriate stubs so ext3 can control
+ * ext2 filesystems, so ext2+ext3 systems only nee one fs.  This work hasn't
+ * been done yet.
+ */
+
+static inline void ext3_journal_release_buffer(handle_t *handle,
+						struct buffer_head *bh)
+{
+	journal_release_buffer(handle, bh);
+}
+
+void ext3_journal_abort_handle(const char *caller, const char *err_fn,
+		struct buffer_head *bh, handle_t *handle, int err);
+
+int __ext3_journal_get_undo_access(const char *where, handle_t *handle,
+				struct buffer_head *bh);
+
+int __ext3_journal_get_write_access(const char *where, handle_t *handle,
+				struct buffer_head *bh);
+
+int __ext3_journal_forget(const char *where, handle_t *handle,
+				struct buffer_head *bh);
+
+int __ext3_journal_revoke(const char *where, handle_t *handle,
+				unsigned long blocknr, struct buffer_head *bh);
+
+int __ext3_journal_get_create_access(const char *where,
+				handle_t *handle, struct buffer_head *bh);
+
+int __ext3_journal_dirty_metadata(const char *where,
+				handle_t *handle, struct buffer_head *bh);
+
+#define ext3_journal_get_undo_access(handle, bh) \
+	__ext3_journal_get_undo_access(__func__, (handle), (bh))
+#define ext3_journal_get_write_access(handle, bh) \
+	__ext3_journal_get_write_access(__func__, (handle), (bh))
+#define ext3_journal_revoke(handle, blocknr, bh) \
+	__ext3_journal_revoke(__func__, (handle), (blocknr), (bh))
+#define ext3_journal_get_create_access(handle, bh) \
+	__ext3_journal_get_create_access(__func__, (handle), (bh))
+#define ext3_journal_dirty_metadata(handle, bh) \
+	__ext3_journal_dirty_metadata(__func__, (handle), (bh))
+#define ext3_journal_forget(handle, bh) \
+	__ext3_journal_forget(__func__, (handle), (bh))
+
+int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh);
+
+handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks);
+int __ext3_journal_stop(const char *where, handle_t *handle);
+
+static inline handle_t *ext3_journal_start(struct inode *inode, int nblocks)
+{
+	return ext3_journal_start_sb(inode->i_sb, nblocks);
+}
+
+#define ext3_journal_stop(handle) \
+	__ext3_journal_stop(__func__, (handle))
+
+static inline handle_t *ext3_journal_current_handle(void)
+{
+	return journal_current_handle();
+}
+
+static inline int ext3_journal_extend(handle_t *handle, int nblocks)
+{
+	return journal_extend(handle, nblocks);
+}
+
+static inline int ext3_journal_restart(handle_t *handle, int nblocks)
+{
+	return journal_restart(handle, nblocks);
+}
+
+static inline int ext3_journal_blocks_per_page(struct inode *inode)
+{
+	return journal_blocks_per_page(inode);
+}
+
+static inline int ext3_journal_force_commit(journal_t *journal)
+{
+	return journal_force_commit(journal);
+}
+
+/* super.c */
+int ext3_force_commit(struct super_block *sb);
+
+static inline int ext3_should_journal_data(struct inode *inode)
+{
+	if (!S_ISREG(inode->i_mode))
+		return 1;
+	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA)
+		return 1;
+	if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL)
+		return 1;
+	return 0;
+}
+
+static inline int ext3_should_order_data(struct inode *inode)
+{
+	if (!S_ISREG(inode->i_mode))
+		return 0;
+	if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL)
+		return 0;
+	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA)
+		return 1;
+	return 0;
+}
+
+static inline int ext3_should_writeback_data(struct inode *inode)
+{
+	if (!S_ISREG(inode->i_mode))
+		return 0;
+	if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL)
+		return 0;
+	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)
+		return 1;
+	return 0;
+}
+
+#include <trace/events/ext3.h>
diff --git a/fs/ext3/ext3_jbd.c b/fs/ext3/ext3_jbd.c
index d401f14..785a326 100644
--- a/fs/ext3/ext3_jbd.c
+++ b/fs/ext3/ext3_jbd.c
@@ -2,7 +2,7 @@
  * Interface between ext3 and JBD
  */
 
-#include <linux/ext3_jbd.h>
+#include "ext3.h"
 
 int __ext3_journal_get_undo_access(const char *where, handle_t *handle,
 				struct buffer_head *bh)
diff --git a/fs/ext3/file.c b/fs/ext3/file.c
index 724df69..25cb413 100644
--- a/fs/ext3/file.c
+++ b/fs/ext3/file.c
@@ -18,12 +18,8 @@
  *	(jj@sunsite.ms.mff.cuni.cz)
  */
 
-#include <linux/time.h>
-#include <linux/fs.h>
-#include <linux/jbd.h>
 #include <linux/quotaops.h>
-#include <linux/ext3_fs.h>
-#include <linux/ext3_jbd.h>
+#include "ext3.h"
 #include "xattr.h"
 #include "acl.h"
 
diff --git a/fs/ext3/fsync.c b/fs/ext3/fsync.c
index 1860ed3..d4dff27 100644
--- a/fs/ext3/fsync.c
+++ b/fs/ext3/fsync.c
@@ -22,15 +22,9 @@
  * we can depend on generic_block_fdatasync() to sync the data blocks.
  */
 
-#include <linux/time.h>
 #include <linux/blkdev.h>
-#include <linux/fs.h>
-#include <linux/sched.h>
 #include <linux/writeback.h>
-#include <linux/jbd.h>
-#include <linux/ext3_fs.h>
-#include <linux/ext3_jbd.h>
-#include <trace/events/ext3.h>
+#include "ext3.h"
 
 /*
  * akpm: A new design for ext3_sync_file().
diff --git a/fs/ext3/hash.c b/fs/ext3/hash.c
index 7d215b4..d10231d 100644
--- a/fs/ext3/hash.c
+++ b/fs/ext3/hash.c
@@ -9,9 +9,7 @@
  * License.
  */
 
-#include <linux/fs.h>
-#include <linux/jbd.h>
-#include <linux/ext3_fs.h>
+#include "ext3.h"
 #include <linux/cryptohash.h>
 
 #define DELTA 0x9E3779B9
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index 1cde284..e3c39e4 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -12,21 +12,10 @@
  *        David S. Miller (davem@caip.rutgers.edu), 1995
  */
 
-#include <linux/time.h>
-#include <linux/fs.h>
-#include <linux/jbd.h>
-#include <linux/ext3_fs.h>
-#include <linux/ext3_jbd.h>
-#include <linux/stat.h>
-#include <linux/string.h>
 #include <linux/quotaops.h>
-#include <linux/buffer_head.h>
 #include <linux/random.h>
-#include <linux/bitops.h>
-#include <trace/events/ext3.h>
 
-#include <asm/byteorder.h>
-
+#include "ext3.h"
 #include "xattr.h"
 #include "acl.h"
 
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 2d0afec..10d7812 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -22,22 +22,12 @@
  *  Assorted race fixes, rewrite of ext3_get_block() by Al Viro, 2000
  */
 
-#include <linux/fs.h>
-#include <linux/time.h>
-#include <linux/ext3_jbd.h>
-#include <linux/jbd.h>
 #include <linux/highuid.h>
-#include <linux/pagemap.h>
 #include <linux/quotaops.h>
-#include <linux/string.h>
-#include <linux/buffer_head.h>
 #include <linux/writeback.h>
 #include <linux/mpage.h>
-#include <linux/uio.h>
-#include <linux/bio.h>
-#include <linux/fiemap.h>
 #include <linux/namei.h>
-#include <trace/events/ext3.h>
+#include "ext3.h"
 #include "xattr.h"
 #include "acl.h"
 
@@ -756,6 +746,7 @@
 	struct ext3_block_alloc_info *block_i;
 	ext3_fsblk_t current_block;
 	struct ext3_inode_info *ei = EXT3_I(inode);
+	struct timespec now;
 
 	block_i = ei->i_block_alloc_info;
 	/*
@@ -795,9 +786,11 @@
 	}
 
 	/* We are done with atomic stuff, now do the rest of housekeeping */
-
-	inode->i_ctime = CURRENT_TIME_SEC;
-	ext3_mark_inode_dirty(handle, inode);
+	now = CURRENT_TIME_SEC;
+	if (!timespec_equal(&inode->i_ctime, &now) || !where->bh) {
+		inode->i_ctime = now;
+		ext3_mark_inode_dirty(handle, inode);
+	}
 	/* ext3_mark_inode_dirty already updated i_sync_tid */
 	atomic_set(&ei->i_datasync_tid, handle->h_transaction->t_tid);
 
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
index 4af574c..677a5c2 100644
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -7,15 +7,10 @@
  * Universite Pierre et Marie Curie (Paris VI)
  */
 
-#include <linux/fs.h>
-#include <linux/jbd.h>
-#include <linux/capability.h>
-#include <linux/ext3_fs.h>
-#include <linux/ext3_jbd.h>
 #include <linux/mount.h>
-#include <linux/time.h>
 #include <linux/compat.h>
 #include <asm/uaccess.h>
+#include "ext3.h"
 
 long ext3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index e8e2117..d7940b2 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -24,20 +24,8 @@
  *	Theodore Ts'o, 2002
  */
 
-#include <linux/fs.h>
-#include <linux/pagemap.h>
-#include <linux/jbd.h>
-#include <linux/time.h>
-#include <linux/ext3_fs.h>
-#include <linux/ext3_jbd.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
-#include <linux/string.h>
 #include <linux/quotaops.h>
-#include <linux/buffer_head.h>
-#include <linux/bio.h>
-#include <trace/events/ext3.h>
-
+#include "ext3.h"
 #include "namei.h"
 #include "xattr.h"
 #include "acl.h"
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c
index 7916e4ce..0f814f3 100644
--- a/fs/ext3/resize.c
+++ b/fs/ext3/resize.c
@@ -11,10 +11,7 @@
 
 #define EXT3FS_DEBUG
 
-#include <linux/ext3_jbd.h>
-
-#include <linux/errno.h>
-#include <linux/slab.h>
+#include "ext3.h"
 
 
 #define outside(b, first, last)	((b) < (first) || (b) >= (last))
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 726c7ef..cf0b592 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -17,22 +17,12 @@
  */
 
 #include <linux/module.h>
-#include <linux/string.h>
-#include <linux/fs.h>
-#include <linux/time.h>
-#include <linux/jbd.h>
-#include <linux/ext3_fs.h>
-#include <linux/ext3_jbd.h>
-#include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/parser.h>
-#include <linux/buffer_head.h>
 #include <linux/exportfs.h>
-#include <linux/vfs.h>
+#include <linux/statfs.h>
 #include <linux/random.h>
 #include <linux/mount.h>
-#include <linux/namei.h>
 #include <linux/quotaops.h>
 #include <linux/seq_file.h>
 #include <linux/log2.h>
@@ -40,13 +30,13 @@
 
 #include <asm/uaccess.h>
 
+#define CREATE_TRACE_POINTS
+
+#include "ext3.h"
 #include "xattr.h"
 #include "acl.h"
 #include "namei.h"
 
-#define CREATE_TRACE_POINTS
-#include <trace/events/ext3.h>
-
 #ifdef CONFIG_EXT3_DEFAULTS_TO_ORDERED
   #define EXT3_MOUNT_DEFAULT_DATA_MODE EXT3_MOUNT_ORDERED_DATA
 #else
@@ -2046,10 +2036,9 @@
 		ext3_msg(sb, KERN_ERR, "error: corrupt root inode, run e2fsck");
 		goto failed_mount3;
 	}
-	sb->s_root = d_alloc_root(root);
+	sb->s_root = d_make_root(root);
 	if (!sb->s_root) {
 		ext3_msg(sb, KERN_ERR, "error: get root dentry failed");
-		iput(root);
 		ret = -ENOMEM;
 		goto failed_mount3;
 	}
diff --git a/fs/ext3/symlink.c b/fs/ext3/symlink.c
index 7c48982..6b01c3e 100644
--- a/fs/ext3/symlink.c
+++ b/fs/ext3/symlink.c
@@ -17,10 +17,8 @@
  *  ext3 symlink handling code
  */
 
-#include <linux/fs.h>
-#include <linux/jbd.h>
-#include <linux/ext3_fs.h>
 #include <linux/namei.h>
+#include "ext3.h"
 #include "xattr.h"
 
 static void * ext3_follow_link(struct dentry *dentry, struct nameidata *nd)
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c
index d565759..d22ebb7 100644
--- a/fs/ext3/xattr.c
+++ b/fs/ext3/xattr.c
@@ -50,14 +50,9 @@
  * by the buffer lock.
  */
 
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/ext3_jbd.h>
-#include <linux/ext3_fs.h>
+#include "ext3.h"
 #include <linux/mbcache.h>
 #include <linux/quotaops.h>
-#include <linux/rwsem.h>
 #include "xattr.h"
 #include "acl.h"
 
diff --git a/fs/ext3/xattr_security.c b/fs/ext3/xattr_security.c
index ea26f2a..3387664 100644
--- a/fs/ext3/xattr_security.c
+++ b/fs/ext3/xattr_security.c
@@ -3,12 +3,8 @@
  * Handler for storing security labels as extended attributes.
  */
 
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/fs.h>
-#include <linux/ext3_jbd.h>
-#include <linux/ext3_fs.h>
 #include <linux/security.h>
+#include "ext3.h"
 #include "xattr.h"
 
 static size_t
diff --git a/fs/ext3/xattr_trusted.c b/fs/ext3/xattr_trusted.c
index 2526a88..d75727c 100644
--- a/fs/ext3/xattr_trusted.c
+++ b/fs/ext3/xattr_trusted.c
@@ -5,11 +5,7 @@
  * Copyright (C) 2003 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
  */
 
-#include <linux/string.h>
-#include <linux/capability.h>
-#include <linux/fs.h>
-#include <linux/ext3_jbd.h>
-#include <linux/ext3_fs.h>
+#include "ext3.h"
 #include "xattr.h"
 
 static size_t
diff --git a/fs/ext3/xattr_user.c b/fs/ext3/xattr_user.c
index b32e473..5612af3 100644
--- a/fs/ext3/xattr_user.c
+++ b/fs/ext3/xattr_user.c
@@ -5,10 +5,7 @@
  * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
  */
 
-#include <linux/string.h>
-#include <linux/fs.h>
-#include <linux/ext3_jbd.h>
-#include <linux/ext3_fs.h>
+#include "ext3.h"
 #include "xattr.h"
 
 static size_t
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index f9e2cd8..4bbd07a 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -336,10 +336,10 @@
  * Return buffer_head on success or NULL in case of failure.
  */
 struct buffer_head *
-ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
+ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
 {
 	struct ext4_group_desc *desc;
-	struct buffer_head *bh = NULL;
+	struct buffer_head *bh;
 	ext4_fsblk_t bitmap_blk;
 
 	desc = ext4_get_group_desc(sb, block_group, NULL);
@@ -348,9 +348,9 @@
 	bitmap_blk = ext4_block_bitmap(sb, desc);
 	bh = sb_getblk(sb, bitmap_blk);
 	if (unlikely(!bh)) {
-		ext4_error(sb, "Cannot read block bitmap - "
-			    "block_group = %u, block_bitmap = %llu",
-			    block_group, bitmap_blk);
+		ext4_error(sb, "Cannot get buffer for block bitmap - "
+			   "block_group = %u, block_bitmap = %llu",
+			   block_group, bitmap_blk);
 		return NULL;
 	}
 
@@ -382,25 +382,50 @@
 		return bh;
 	}
 	/*
-	 * submit the buffer_head for read. We can
-	 * safely mark the bitmap as uptodate now.
-	 * We do it here so the bitmap uptodate bit
-	 * get set with buffer lock held.
+	 * submit the buffer_head for reading
 	 */
+	set_buffer_new(bh);
 	trace_ext4_read_block_bitmap_load(sb, block_group);
-	set_bitmap_uptodate(bh);
-	if (bh_submit_read(bh) < 0) {
-		put_bh(bh);
+	bh->b_end_io = ext4_end_bitmap_read;
+	get_bh(bh);
+	submit_bh(READ, bh);
+	return bh;
+}
+
+/* Returns 0 on success, 1 on error */
+int ext4_wait_block_bitmap(struct super_block *sb, ext4_group_t block_group,
+			   struct buffer_head *bh)
+{
+	struct ext4_group_desc *desc;
+
+	if (!buffer_new(bh))
+		return 0;
+	desc = ext4_get_group_desc(sb, block_group, NULL);
+	if (!desc)
+		return 1;
+	wait_on_buffer(bh);
+	if (!buffer_uptodate(bh)) {
 		ext4_error(sb, "Cannot read block bitmap - "
-			    "block_group = %u, block_bitmap = %llu",
-			    block_group, bitmap_blk);
+			   "block_group = %u, block_bitmap = %llu",
+			   block_group, (unsigned long long) bh->b_blocknr);
+		return 1;
+	}
+	clear_buffer_new(bh);
+	/* Panic or remount fs read-only if block bitmap is invalid */
+	ext4_valid_block_bitmap(sb, desc, block_group, bh);
+	return 0;
+}
+
+struct buffer_head *
+ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
+{
+	struct buffer_head *bh;
+
+	bh = ext4_read_block_bitmap_nowait(sb, block_group);
+	if (ext4_wait_block_bitmap(sb, block_group, bh)) {
+		put_bh(bh);
 		return NULL;
 	}
-	ext4_valid_block_bitmap(sb, desc, block_group, bh);
-	/*
-	 * file system mounted not to panic on error,
-	 * continue with corrupt bitmap
-	 */
 	return bh;
 }
 
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index 164c560..b867862 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -32,24 +32,8 @@
 	DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
 };
 
-static int ext4_readdir(struct file *, void *, filldir_t);
 static int ext4_dx_readdir(struct file *filp,
 			   void *dirent, filldir_t filldir);
-static int ext4_release_dir(struct inode *inode,
-				struct file *filp);
-
-const struct file_operations ext4_dir_operations = {
-	.llseek		= ext4_llseek,
-	.read		= generic_read_dir,
-	.readdir	= ext4_readdir,		/* we take BKL. needed?*/
-	.unlocked_ioctl = ext4_ioctl,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl	= ext4_compat_ioctl,
-#endif
-	.fsync		= ext4_sync_file,
-	.release	= ext4_release_dir,
-};
-
 
 static unsigned char get_dtype(struct super_block *sb, int filetype)
 {
@@ -60,6 +44,26 @@
 	return (ext4_filetype_table[filetype]);
 }
 
+/**
+ * Check if the given dir-inode refers to an htree-indexed directory
+ * (or a directory which chould potentially get coverted to use htree
+ * indexing).
+ *
+ * Return 1 if it is a dx dir, 0 if not
+ */
+static int is_dx_dir(struct inode *inode)
+{
+	struct super_block *sb = inode->i_sb;
+
+	if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
+		     EXT4_FEATURE_COMPAT_DIR_INDEX) &&
+	    ((ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) ||
+	     ((inode->i_size >> sb->s_blocksize_bits) == 1)))
+		return 1;
+
+	return 0;
+}
+
 /*
  * Return 0 if the directory entry is OK, and 1 if there is a problem
  *
@@ -91,17 +95,17 @@
 		return 0;
 
 	if (filp)
-		ext4_error_file(filp, function, line, bh ? bh->b_blocknr : 0,
+		ext4_error_file(filp, function, line, bh->b_blocknr,
 				"bad entry in directory: %s - offset=%u(%u), "
 				"inode=%u, rec_len=%d, name_len=%d",
-				error_msg, (unsigned) (offset%bh->b_size),
+				error_msg, (unsigned) (offset % bh->b_size),
 				offset, le32_to_cpu(de->inode),
 				rlen, de->name_len);
 	else
-		ext4_error_inode(dir, function, line, bh ? bh->b_blocknr : 0,
+		ext4_error_inode(dir, function, line, bh->b_blocknr,
 				"bad entry in directory: %s - offset=%u(%u), "
 				"inode=%u, rec_len=%d, name_len=%d",
-				error_msg, (unsigned) (offset%bh->b_size),
+				error_msg, (unsigned) (offset % bh->b_size),
 				offset, le32_to_cpu(de->inode),
 				rlen, de->name_len);
 
@@ -115,18 +119,13 @@
 	unsigned int offset;
 	int i, stored;
 	struct ext4_dir_entry_2 *de;
-	struct super_block *sb;
 	int err;
 	struct inode *inode = filp->f_path.dentry->d_inode;
+	struct super_block *sb = inode->i_sb;
 	int ret = 0;
 	int dir_has_error = 0;
 
-	sb = inode->i_sb;
-
-	if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
-				    EXT4_FEATURE_COMPAT_DIR_INDEX) &&
-	    ((ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) ||
-	     ((inode->i_size >> sb->s_blocksize_bits) == 1))) {
+	if (is_dx_dir(inode)) {
 		err = ext4_dx_readdir(filp, dirent, filldir);
 		if (err != ERR_BAD_DX_DIR) {
 			ret = err;
@@ -254,22 +253,134 @@
 	return ret;
 }
 
+static inline int is_32bit_api(void)
+{
+#ifdef CONFIG_COMPAT
+	return is_compat_task();
+#else
+	return (BITS_PER_LONG == 32);
+#endif
+}
+
 /*
  * These functions convert from the major/minor hash to an f_pos
- * value.
+ * value for dx directories
  *
- * Currently we only use major hash numer.  This is unfortunate, but
- * on 32-bit machines, the same VFS interface is used for lseek and
- * llseek, so if we use the 64 bit offset, then the 32-bit versions of
- * lseek/telldir/seekdir will blow out spectacularly, and from within
- * the ext2 low-level routine, we don't know if we're being called by
- * a 64-bit version of the system call or the 32-bit version of the
- * system call.  Worse yet, NFSv2 only allows for a 32-bit readdir
- * cookie.  Sigh.
+ * Upper layer (for example NFS) should specify FMODE_32BITHASH or
+ * FMODE_64BITHASH explicitly. On the other hand, we allow ext4 to be mounted
+ * directly on both 32-bit and 64-bit nodes, under such case, neither
+ * FMODE_32BITHASH nor FMODE_64BITHASH is specified.
  */
-#define hash2pos(major, minor)	(major >> 1)
-#define pos2maj_hash(pos)	((pos << 1) & 0xffffffff)
-#define pos2min_hash(pos)	(0)
+static inline loff_t hash2pos(struct file *filp, __u32 major, __u32 minor)
+{
+	if ((filp->f_mode & FMODE_32BITHASH) ||
+	    (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
+		return major >> 1;
+	else
+		return ((__u64)(major >> 1) << 32) | (__u64)minor;
+}
+
+static inline __u32 pos2maj_hash(struct file *filp, loff_t pos)
+{
+	if ((filp->f_mode & FMODE_32BITHASH) ||
+	    (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
+		return (pos << 1) & 0xffffffff;
+	else
+		return ((pos >> 32) << 1) & 0xffffffff;
+}
+
+static inline __u32 pos2min_hash(struct file *filp, loff_t pos)
+{
+	if ((filp->f_mode & FMODE_32BITHASH) ||
+	    (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
+		return 0;
+	else
+		return pos & 0xffffffff;
+}
+
+/*
+ * Return 32- or 64-bit end-of-file for dx directories
+ */
+static inline loff_t ext4_get_htree_eof(struct file *filp)
+{
+	if ((filp->f_mode & FMODE_32BITHASH) ||
+	    (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
+		return EXT4_HTREE_EOF_32BIT;
+	else
+		return EXT4_HTREE_EOF_64BIT;
+}
+
+
+/*
+ * ext4_dir_llseek() based on generic_file_llseek() to handle both
+ * non-htree and htree directories, where the "offset" is in terms
+ * of the filename hash value instead of the byte offset.
+ *
+ * NOTE: offsets obtained *before* ext4_set_inode_flag(dir, EXT4_INODE_INDEX)
+ *       will be invalid once the directory was converted into a dx directory
+ */
+loff_t ext4_dir_llseek(struct file *file, loff_t offset, int origin)
+{
+	struct inode *inode = file->f_mapping->host;
+	loff_t ret = -EINVAL;
+	int dx_dir = is_dx_dir(inode);
+
+	mutex_lock(&inode->i_mutex);
+
+	/* NOTE: relative offsets with dx directories might not work
+	 *       as expected, as it is difficult to figure out the
+	 *       correct offset between dx hashes */
+
+	switch (origin) {
+	case SEEK_END:
+		if (unlikely(offset > 0))
+			goto out_err; /* not supported for directories */
+
+		/* so only negative offsets are left, does that have a
+		 * meaning for directories at all? */
+		if (dx_dir)
+			offset += ext4_get_htree_eof(file);
+		else
+			offset += inode->i_size;
+		break;
+	case SEEK_CUR:
+		/*
+		 * Here we special-case the lseek(fd, 0, SEEK_CUR)
+		 * position-querying operation.  Avoid rewriting the "same"
+		 * f_pos value back to the file because a concurrent read(),
+		 * write() or lseek() might have altered it
+		 */
+		if (offset == 0) {
+			offset = file->f_pos;
+			goto out_ok;
+		}
+
+		offset += file->f_pos;
+		break;
+	}
+
+	if (unlikely(offset < 0))
+		goto out_err;
+
+	if (!dx_dir) {
+		if (offset > inode->i_sb->s_maxbytes)
+			goto out_err;
+	} else if (offset > ext4_get_htree_eof(file))
+		goto out_err;
+
+	/* Special lock needed here? */
+	if (offset != file->f_pos) {
+		file->f_pos = offset;
+		file->f_version = 0;
+	}
+
+out_ok:
+	ret = offset;
+out_err:
+	mutex_unlock(&inode->i_mutex);
+
+	return ret;
+}
 
 /*
  * This structure holds the nodes of the red-black tree used to store
@@ -330,15 +441,16 @@
 }
 
 
-static struct dir_private_info *ext4_htree_create_dir_info(loff_t pos)
+static struct dir_private_info *ext4_htree_create_dir_info(struct file *filp,
+							   loff_t pos)
 {
 	struct dir_private_info *p;
 
 	p = kzalloc(sizeof(struct dir_private_info), GFP_KERNEL);
 	if (!p)
 		return NULL;
-	p->curr_hash = pos2maj_hash(pos);
-	p->curr_minor_hash = pos2min_hash(pos);
+	p->curr_hash = pos2maj_hash(filp, pos);
+	p->curr_minor_hash = pos2min_hash(filp, pos);
 	return p;
 }
 
@@ -425,11 +537,12 @@
 	sb = inode->i_sb;
 
 	if (!fname) {
-		printk(KERN_ERR "EXT4-fs: call_filldir: called with "
-		       "null fname?!?\n");
+		ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: comm %s: "
+			 "called with null fname?!?", __func__, __LINE__,
+			 inode->i_ino, current->comm);
 		return 0;
 	}
-	curr_pos = hash2pos(fname->hash, fname->minor_hash);
+	curr_pos = hash2pos(filp, fname->hash, fname->minor_hash);
 	while (fname) {
 		error = filldir(dirent, fname->name,
 				fname->name_len, curr_pos,
@@ -454,13 +567,13 @@
 	int	ret;
 
 	if (!info) {
-		info = ext4_htree_create_dir_info(filp->f_pos);
+		info = ext4_htree_create_dir_info(filp, filp->f_pos);
 		if (!info)
 			return -ENOMEM;
 		filp->private_data = info;
 	}
 
-	if (filp->f_pos == EXT4_HTREE_EOF)
+	if (filp->f_pos == ext4_get_htree_eof(filp))
 		return 0;	/* EOF */
 
 	/* Some one has messed with f_pos; reset the world */
@@ -468,8 +581,8 @@
 		free_rb_tree_fname(&info->root);
 		info->curr_node = NULL;
 		info->extra_fname = NULL;
-		info->curr_hash = pos2maj_hash(filp->f_pos);
-		info->curr_minor_hash = pos2min_hash(filp->f_pos);
+		info->curr_hash = pos2maj_hash(filp, filp->f_pos);
+		info->curr_minor_hash = pos2min_hash(filp, filp->f_pos);
 	}
 
 	/*
@@ -501,7 +614,7 @@
 			if (ret < 0)
 				return ret;
 			if (ret == 0) {
-				filp->f_pos = EXT4_HTREE_EOF;
+				filp->f_pos = ext4_get_htree_eof(filp);
 				break;
 			}
 			info->curr_node = rb_first(&info->root);
@@ -521,7 +634,7 @@
 			info->curr_minor_hash = fname->minor_hash;
 		} else {
 			if (info->next_hash == ~0) {
-				filp->f_pos = EXT4_HTREE_EOF;
+				filp->f_pos = ext4_get_htree_eof(filp);
 				break;
 			}
 			info->curr_hash = info->next_hash;
@@ -540,3 +653,15 @@
 
 	return 0;
 }
+
+const struct file_operations ext4_dir_operations = {
+	.llseek		= ext4_dir_llseek,
+	.read		= generic_read_dir,
+	.readdir	= ext4_readdir,
+	.unlocked_ioctl = ext4_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= ext4_compat_ioctl,
+#endif
+	.fsync		= ext4_sync_file,
+	.release	= ext4_release_dir,
+};
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 513004f..ab2594a 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -53,7 +53,7 @@
 		printk(KERN_DEBUG f, ## a);				\
 	} while (0)
 #else
-#define ext4_debug(f, a...)	do {} while (0)
+#define ext4_debug(fmt, ...)	no_printk(fmt, ##__VA_ARGS__)
 #endif
 
 #define EXT4_ERROR_INODE(inode, fmt, a...) \
@@ -184,6 +184,8 @@
 #define	EXT4_IO_END_UNWRITTEN	0x0001
 #define EXT4_IO_END_ERROR	0x0002
 #define EXT4_IO_END_QUEUED	0x0004
+#define EXT4_IO_END_DIRECT	0x0008
+#define EXT4_IO_END_IN_FSYNC	0x0010
 
 struct ext4_io_page {
 	struct page	*p_page;
@@ -192,18 +194,25 @@
 
 #define MAX_IO_PAGES 128
 
+/*
+ * For converting uninitialized extents on a work queue.
+ *
+ * 'page' is only used from the writepage() path; 'pages' is only used for
+ * buffered writes; they are used to keep page references until conversion
+ * takes place.  For AIO/DIO, neither field is filled in.
+ */
 typedef struct ext4_io_end {
 	struct list_head	list;		/* per-file finished IO list */
 	struct inode		*inode;		/* file being written to */
 	unsigned int		flag;		/* unwritten or not */
-	struct page		*page;		/* page struct for buffer write */
+	struct page		*page;		/* for writepage() path */
 	loff_t			offset;		/* offset in the file */
 	ssize_t			size;		/* size of the extent */
 	struct work_struct	work;		/* data work queue */
 	struct kiocb		*iocb;		/* iocb struct for AIO */
 	int			result;		/* error value for AIO */
-	int			num_io_pages;
-	struct ext4_io_page	*pages[MAX_IO_PAGES];
+	int			num_io_pages;   /* for writepages() */
+	struct ext4_io_page	*pages[MAX_IO_PAGES]; /* for writepages() */
 } ext4_io_end_t;
 
 struct ext4_io_submit {
@@ -923,6 +932,7 @@
 #define EXT4_MOUNT_ERRORS_CONT		0x00010	/* Continue on errors */
 #define EXT4_MOUNT_ERRORS_RO		0x00020	/* Remount fs ro on errors */
 #define EXT4_MOUNT_ERRORS_PANIC		0x00040	/* Panic on errors */
+#define EXT4_MOUNT_ERRORS_MASK		0x00070
 #define EXT4_MOUNT_MINIX_DF		0x00080	/* Mimics the Minix statfs */
 #define EXT4_MOUNT_NOLOAD		0x00100	/* Don't use existing journal*/
 #define EXT4_MOUNT_DATA_FLAGS		0x00C00	/* Mode for data writes: */
@@ -941,7 +951,6 @@
 #define EXT4_MOUNT_DIOREAD_NOLOCK	0x400000 /* Enable support for dio read nolocking */
 #define EXT4_MOUNT_JOURNAL_CHECKSUM	0x800000 /* Journal checksums */
 #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT	0x1000000 /* Journal Async Commit */
-#define EXT4_MOUNT_I_VERSION            0x2000000 /* i_version support */
 #define EXT4_MOUNT_MBLK_IO_SUBMIT	0x4000000 /* multi-block io submits */
 #define EXT4_MOUNT_DELALLOC		0x8000000 /* Delalloc support */
 #define EXT4_MOUNT_DATA_ERR_ABORT	0x10000000 /* Abort on file data write */
@@ -1142,6 +1151,7 @@
 	unsigned int s_mount_opt;
 	unsigned int s_mount_opt2;
 	unsigned int s_mount_flags;
+	unsigned int s_def_mount_opt;
 	ext4_fsblk_t s_sb_block;
 	uid_t s_resuid;
 	gid_t s_resgid;
@@ -1420,8 +1430,9 @@
 #define EXT4_FEATURE_INCOMPAT_FLEX_BG		0x0200
 #define EXT4_FEATURE_INCOMPAT_EA_INODE		0x0400 /* EA in inode */
 #define EXT4_FEATURE_INCOMPAT_DIRDATA		0x1000 /* data in dirent */
-#define EXT4_FEATURE_INCOMPAT_INLINEDATA	0x2000 /* data in inode */
+#define EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM	0x2000 /* use crc32c for bg */
 #define EXT4_FEATURE_INCOMPAT_LARGEDIR		0x4000 /* >2GB or 3-lvl htree */
+#define EXT4_FEATURE_INCOMPAT_INLINEDATA	0x8000 /* data in inode */
 
 #define EXT2_FEATURE_COMPAT_SUPP	EXT4_FEATURE_COMPAT_EXT_ATTR
 #define EXT2_FEATURE_INCOMPAT_SUPP	(EXT4_FEATURE_INCOMPAT_FILETYPE| \
@@ -1612,7 +1623,11 @@
 	u32		*seed;
 };
 
-#define EXT4_HTREE_EOF	0x7fffffff
+
+/* 32 and 64 bit signed EOF for dx directories */
+#define EXT4_HTREE_EOF_32BIT   ((1UL  << (32 - 1)) - 1)
+#define EXT4_HTREE_EOF_64BIT   ((1ULL << (64 - 1)) - 1)
+
 
 /*
  * Control parameters used by ext4_htree_next_block
@@ -1794,8 +1809,14 @@
 						    ext4_group_t block_group,
 						    struct buffer_head ** bh);
 extern int ext4_should_retry_alloc(struct super_block *sb, int *retries);
-struct buffer_head *ext4_read_block_bitmap(struct super_block *sb,
-				      ext4_group_t block_group);
+
+extern struct buffer_head *ext4_read_block_bitmap_nowait(struct super_block *sb,
+						ext4_group_t block_group);
+extern int ext4_wait_block_bitmap(struct super_block *sb,
+				  ext4_group_t block_group,
+				  struct buffer_head *bh);
+extern struct buffer_head *ext4_read_block_bitmap(struct super_block *sb,
+						  ext4_group_t block_group);
 extern void ext4_init_block_bitmap(struct super_block *sb,
 				   struct buffer_head *bh,
 				   ext4_group_t group,
@@ -1841,6 +1862,7 @@
 extern void ext4_mark_bitmap_end(int start_bit, int end_bit, char *bitmap);
 extern int ext4_init_inode_table(struct super_block *sb,
 				 ext4_group_t group, int barrier);
+extern void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate);
 
 /* mballoc.c */
 extern long ext4_mb_stats;
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h
index a52db3a..0f58b86 100644
--- a/fs/ext4/ext4_extents.h
+++ b/fs/ext4/ext4_extents.h
@@ -47,9 +47,9 @@
  */
 #define EXT_DEBUG__
 #ifdef EXT_DEBUG
-#define ext_debug(a...)		printk(a)
+#define ext_debug(fmt, ...)	printk(fmt, ##__VA_ARGS__)
 #else
-#define ext_debug(a...)
+#define ext_debug(fmt, ...)	no_printk(fmt, ##__VA_ARGS__)
 #endif
 
 /*
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
index 5802fa1..83b20fc 100644
--- a/fs/ext4/ext4_jbd2.h
+++ b/fs/ext4/ext4_jbd2.h
@@ -104,6 +104,78 @@
 #define EXT4_MAXQUOTAS_INIT_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_INIT_BLOCKS(sb))
 #define EXT4_MAXQUOTAS_DEL_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_DEL_BLOCKS(sb))
 
+/**
+ *   struct ext4_journal_cb_entry - Base structure for callback information.
+ *
+ *   This struct is a 'seed' structure for a using with your own callback
+ *   structs. If you are using callbacks you must allocate one of these
+ *   or another struct of your own definition which has this struct
+ *   as it's first element and pass it to ext4_journal_callback_add().
+ */
+struct ext4_journal_cb_entry {
+	/* list information for other callbacks attached to the same handle */
+	struct list_head jce_list;
+
+	/*  Function to call with this callback structure */
+	void (*jce_func)(struct super_block *sb,
+			 struct ext4_journal_cb_entry *jce, int error);
+
+	/* user data goes here */
+};
+
+/**
+ * ext4_journal_callback_add: add a function to call after transaction commit
+ * @handle: active journal transaction handle to register callback on
+ * @func: callback function to call after the transaction has committed:
+ *        @sb: superblock of current filesystem for transaction
+ *        @jce: returned journal callback data
+ *        @rc: journal state at commit (0 = transaction committed properly)
+ * @jce: journal callback data (internal and function private data struct)
+ *
+ * The registered function will be called in the context of the journal thread
+ * after the transaction for which the handle was created has completed.
+ *
+ * No locks are held when the callback function is called, so it is safe to
+ * call blocking functions from within the callback, but the callback should
+ * not block or run for too long, or the filesystem will be blocked waiting for
+ * the next transaction to commit. No journaling functions can be used, or
+ * there is a risk of deadlock.
+ *
+ * There is no guaranteed calling order of multiple registered callbacks on
+ * the same transaction.
+ */
+static inline void ext4_journal_callback_add(handle_t *handle,
+			void (*func)(struct super_block *sb,
+				     struct ext4_journal_cb_entry *jce,
+				     int rc),
+			struct ext4_journal_cb_entry *jce)
+{
+	struct ext4_sb_info *sbi =
+			EXT4_SB(handle->h_transaction->t_journal->j_private);
+
+	/* Add the jce to transaction's private list */
+	jce->jce_func = func;
+	spin_lock(&sbi->s_md_lock);
+	list_add_tail(&jce->jce_list, &handle->h_transaction->t_private_list);
+	spin_unlock(&sbi->s_md_lock);
+}
+
+/**
+ * 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
+ */
+static inline void ext4_journal_callback_del(handle_t *handle,
+					     struct ext4_journal_cb_entry *jce)
+{
+	struct ext4_sb_info *sbi =
+			EXT4_SB(handle->h_transaction->t_journal->j_private);
+
+	spin_lock(&sbi->s_md_lock);
+	list_del_init(&jce->jce_list);
+	spin_unlock(&sbi->s_md_lock);
+}
+
 int
 ext4_mark_iloc_dirty(handle_t *handle,
 		     struct inode *inode,
@@ -261,43 +333,45 @@
 /* super.c */
 int ext4_force_commit(struct super_block *sb);
 
-static inline int ext4_should_journal_data(struct inode *inode)
+/*
+ * Ext4 inode journal modes
+ */
+#define EXT4_INODE_JOURNAL_DATA_MODE	0x01 /* journal data mode */
+#define EXT4_INODE_ORDERED_DATA_MODE	0x02 /* ordered data mode */
+#define EXT4_INODE_WRITEBACK_DATA_MODE	0x04 /* writeback data mode */
+
+static inline int ext4_inode_journal_mode(struct inode *inode)
 {
 	if (EXT4_JOURNAL(inode) == NULL)
-		return 0;
-	if (!S_ISREG(inode->i_mode))
-		return 1;
-	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
-		return 1;
-	if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
-		return 1;
-	return 0;
+		return EXT4_INODE_WRITEBACK_DATA_MODE;	/* writeback */
+	/* We do not support data journalling with delayed allocation */
+	if (!S_ISREG(inode->i_mode) ||
+	    test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
+		return EXT4_INODE_JOURNAL_DATA_MODE;	/* journal data */
+	if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) &&
+	    !test_opt(inode->i_sb, DELALLOC))
+		return EXT4_INODE_JOURNAL_DATA_MODE;	/* journal data */
+	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
+		return EXT4_INODE_ORDERED_DATA_MODE;	/* ordered */
+	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
+		return EXT4_INODE_WRITEBACK_DATA_MODE;	/* writeback */
+	else
+		BUG();
+}
+
+static inline int ext4_should_journal_data(struct inode *inode)
+{
+	return ext4_inode_journal_mode(inode) & EXT4_INODE_JOURNAL_DATA_MODE;
 }
 
 static inline int ext4_should_order_data(struct inode *inode)
 {
-	if (EXT4_JOURNAL(inode) == NULL)
-		return 0;
-	if (!S_ISREG(inode->i_mode))
-		return 0;
-	if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
-		return 0;
-	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
-		return 1;
-	return 0;
+	return ext4_inode_journal_mode(inode) & EXT4_INODE_ORDERED_DATA_MODE;
 }
 
 static inline int ext4_should_writeback_data(struct inode *inode)
 {
-	if (EXT4_JOURNAL(inode) == NULL)
-		return 1;
-	if (!S_ISREG(inode->i_mode))
-		return 0;
-	if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
-		return 0;
-	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
-		return 1;
-	return 0;
+	return ext4_inode_journal_mode(inode) & EXT4_INODE_WRITEBACK_DATA_MODE;
 }
 
 /*
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 74f23c2..1421938 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -44,6 +44,14 @@
 
 #include <trace/events/ext4.h>
 
+/*
+ * used by extent splitting.
+ */
+#define EXT4_EXT_MAY_ZEROOUT	0x1  /* safe to zeroout if split fails \
+					due to ENOSPC */
+#define EXT4_EXT_MARK_UNINIT1	0x2  /* mark first half uninitialized */
+#define EXT4_EXT_MARK_UNINIT2	0x4  /* mark second half uninitialized */
+
 static int ext4_split_extent(handle_t *handle,
 				struct inode *inode,
 				struct ext4_ext_path *path,
@@ -51,6 +59,13 @@
 				int split_flag,
 				int flags);
 
+static int ext4_split_extent_at(handle_t *handle,
+			     struct inode *inode,
+			     struct ext4_ext_path *path,
+			     ext4_lblk_t split,
+			     int split_flag,
+			     int flags);
+
 static int ext4_ext_truncate_extend_restart(handle_t *handle,
 					    struct inode *inode,
 					    int needed)
@@ -300,6 +315,8 @@
 	ext4_fsblk_t block = ext4_ext_pblock(ext);
 	int len = ext4_ext_get_actual_len(ext);
 
+	if (len == 0)
+		return 0;
 	return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len);
 }
 
@@ -2308,7 +2325,7 @@
 	struct ext4_extent *ex;
 
 	/* the header must be checked already in ext4_ext_remove_space() */
-	ext_debug("truncate since %u in leaf\n", start);
+	ext_debug("truncate since %u in leaf to %u\n", start, end);
 	if (!path[depth].p_hdr)
 		path[depth].p_hdr = ext_block_hdr(path[depth].p_bh);
 	eh = path[depth].p_hdr;
@@ -2343,14 +2360,17 @@
 		ext_debug("  border %u:%u\n", a, b);
 
 		/* If this extent is beyond the end of the hole, skip it */
-		if (end <= ex_ee_block) {
+		if (end < ex_ee_block) {
 			ex--;
 			ex_ee_block = le32_to_cpu(ex->ee_block);
 			ex_ee_len = ext4_ext_get_actual_len(ex);
 			continue;
 		} else if (b != ex_ee_block + ex_ee_len - 1) {
-			EXT4_ERROR_INODE(inode,"  bad truncate %u:%u\n",
-					 start, end);
+			EXT4_ERROR_INODE(inode,
+					 "can not handle truncate %u:%u "
+					 "on extent %u:%u",
+					 start, end, ex_ee_block,
+					 ex_ee_block + ex_ee_len - 1);
 			err = -EIO;
 			goto out;
 		} else if (a != ex_ee_block) {
@@ -2482,7 +2502,8 @@
 	return 1;
 }
 
-static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
+static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
+				 ext4_lblk_t end)
 {
 	struct super_block *sb = inode->i_sb;
 	int depth = ext_depth(inode);
@@ -2491,7 +2512,7 @@
 	handle_t *handle;
 	int i, err;
 
-	ext_debug("truncate since %u\n", start);
+	ext_debug("truncate since %u to %u\n", start, end);
 
 	/* probably first extent we're gonna free will be last in block */
 	handle = ext4_journal_start(inode, depth + 1);
@@ -2504,6 +2525,61 @@
 	trace_ext4_ext_remove_space(inode, start, depth);
 
 	/*
+	 * Check if we are removing extents inside the extent tree. If that
+	 * is the case, we are going to punch a hole inside the extent tree
+	 * so we have to check whether we need to split the extent covering
+	 * the last block to remove so we can easily remove the part of it
+	 * in ext4_ext_rm_leaf().
+	 */
+	if (end < EXT_MAX_BLOCKS - 1) {
+		struct ext4_extent *ex;
+		ext4_lblk_t ee_block;
+
+		/* find extent for this block */
+		path = ext4_ext_find_extent(inode, end, NULL);
+		if (IS_ERR(path)) {
+			ext4_journal_stop(handle);
+			return PTR_ERR(path);
+		}
+		depth = ext_depth(inode);
+		ex = path[depth].p_ext;
+		if (!ex)
+			goto cont;
+
+		ee_block = le32_to_cpu(ex->ee_block);
+
+		/*
+		 * See if the last block is inside the extent, if so split
+		 * the extent at 'end' block so we can easily remove the
+		 * tail of the first part of the split extent in
+		 * ext4_ext_rm_leaf().
+		 */
+		if (end >= ee_block &&
+		    end < ee_block + ext4_ext_get_actual_len(ex) - 1) {
+			int split_flag = 0;
+
+			if (ext4_ext_is_uninitialized(ex))
+				split_flag = EXT4_EXT_MARK_UNINIT1 |
+					     EXT4_EXT_MARK_UNINIT2;
+
+			/*
+			 * Split the extent in two so that 'end' is the last
+			 * block in the first new extent
+			 */
+			err = ext4_split_extent_at(handle, inode, path,
+						end + 1, split_flag,
+						EXT4_GET_BLOCKS_PRE_IO |
+						EXT4_GET_BLOCKS_PUNCH_OUT_EXT);
+
+			if (err < 0)
+				goto out;
+		}
+		ext4_ext_drop_refs(path);
+		kfree(path);
+	}
+cont:
+
+	/*
 	 * We start scanning from right side, freeing all the blocks
 	 * after i_size and walking into the tree depth-wise.
 	 */
@@ -2515,6 +2591,7 @@
 	}
 	path[0].p_depth = depth;
 	path[0].p_hdr = ext_inode_hdr(inode);
+
 	if (ext4_ext_check(inode, path[0].p_hdr, depth)) {
 		err = -EIO;
 		goto out;
@@ -2526,7 +2603,7 @@
 			/* this is leaf block */
 			err = ext4_ext_rm_leaf(handle, inode, path,
 					       &partial_cluster, start,
-					       EXT_MAX_BLOCKS - 1);
+					       end);
 			/* root level has p_bh == NULL, brelse() eats this */
 			brelse(path[i].p_bh);
 			path[i].p_bh = NULL;
@@ -2651,17 +2728,17 @@
 
 	if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
 #if defined(AGGRESSIVE_TEST) || defined(CHECK_BINSEARCH) || defined(EXTENTS_STATS)
-		printk(KERN_INFO "EXT4-fs: file extents enabled");
+		printk(KERN_INFO "EXT4-fs: file extents enabled"
 #ifdef AGGRESSIVE_TEST
-		printk(", aggressive tests");
+		       ", aggressive tests"
 #endif
 #ifdef CHECK_BINSEARCH
-		printk(", check binsearch");
+		       ", check binsearch"
 #endif
 #ifdef EXTENTS_STATS
-		printk(", stats");
+		       ", stats"
 #endif
-		printk("\n");
+		       "\n");
 #endif
 #ifdef EXTENTS_STATS
 		spin_lock_init(&EXT4_SB(sb)->s_ext_stats_lock);
@@ -2709,14 +2786,6 @@
 }
 
 /*
- * used by extent splitting.
- */
-#define EXT4_EXT_MAY_ZEROOUT	0x1  /* safe to zeroout if split fails \
-					due to ENOSPC */
-#define EXT4_EXT_MARK_UNINIT1	0x2  /* mark first half uninitialized */
-#define EXT4_EXT_MARK_UNINIT2	0x4  /* mark second half uninitialized */
-
-/*
  * ext4_split_extent_at() splits an extent at given block.
  *
  * @handle: the journal handle
@@ -3224,11 +3293,13 @@
 	depth = ext_depth(inode);
 	eh = path[depth].p_hdr;
 
-	if (unlikely(!eh->eh_entries)) {
-		EXT4_ERROR_INODE(inode, "eh->eh_entries == 0 and "
-				 "EOFBLOCKS_FL set");
-		return -EIO;
-	}
+	/*
+	 * We're going to remove EOFBLOCKS_FL entirely in future so we
+	 * do not care for this case anymore. Simply remove the flag
+	 * if there are no extents.
+	 */
+	if (unlikely(!eh->eh_entries))
+		goto out;
 	last_ex = EXT_LAST_EXTENT(eh);
 	/*
 	 * We should clear the EOFBLOCKS_FL flag if we are writing the
@@ -3252,6 +3323,7 @@
 	for (i = depth-1; i >= 0; i--)
 		if (path[i].p_idx != EXT_LAST_INDEX(path[i].p_hdr))
 			return 0;
+out:
 	ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
 	return ext4_mark_inode_dirty(handle, inode);
 }
@@ -3710,8 +3782,6 @@
 	int free_on_err = 0, err = 0, depth, ret;
 	unsigned int allocated = 0, offset = 0;
 	unsigned int allocated_clusters = 0;
-	unsigned int punched_out = 0;
-	unsigned int result = 0;
 	struct ext4_allocation_request ar;
 	ext4_io_end_t *io = EXT4_I(inode)->cur_aio_dio;
 	ext4_lblk_t cluster_offset;
@@ -3721,8 +3791,7 @@
 	trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
 
 	/* check in cache */
-	if (!(flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) &&
-		ext4_ext_in_cache(inode, map->m_lblk, &newex)) {
+	if (ext4_ext_in_cache(inode, map->m_lblk, &newex)) {
 		if (!newex.ee_start_lo && !newex.ee_start_hi) {
 			if ((sbi->s_cluster_ratio > 1) &&
 			    ext4_find_delalloc_cluster(inode, map->m_lblk, 0))
@@ -3790,113 +3859,25 @@
 
 		/* if found extent covers block, simply return it */
 		if (in_range(map->m_lblk, ee_block, ee_len)) {
-			struct ext4_map_blocks punch_map;
-			ext4_fsblk_t partial_cluster = 0;
-
 			newblock = map->m_lblk - ee_block + ee_start;
 			/* number of remaining blocks in the extent */
 			allocated = ee_len - (map->m_lblk - ee_block);
 			ext_debug("%u fit into %u:%d -> %llu\n", map->m_lblk,
 				  ee_block, ee_len, newblock);
 
-			if ((flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) == 0) {
-				/*
-				 * Do not put uninitialized extent
-				 * in the cache
-				 */
-				if (!ext4_ext_is_uninitialized(ex)) {
-					ext4_ext_put_in_cache(inode, ee_block,
-						ee_len, ee_start);
-					goto out;
-				}
-				ret = ext4_ext_handle_uninitialized_extents(
-					handle, inode, map, path, flags,
-					allocated, newblock);
-				return ret;
-			}
-
 			/*
-			 * Punch out the map length, but only to the
-			 * end of the extent
+			 * Do not put uninitialized extent
+			 * in the cache
 			 */
-			punched_out = allocated < map->m_len ?
-				allocated : map->m_len;
-
-			/*
-			 * Sense extents need to be converted to
-			 * uninitialized, they must fit in an
-			 * uninitialized extent
-			 */
-			if (punched_out > EXT_UNINIT_MAX_LEN)
-				punched_out = EXT_UNINIT_MAX_LEN;
-
-			punch_map.m_lblk = map->m_lblk;
-			punch_map.m_pblk = newblock;
-			punch_map.m_len = punched_out;
-			punch_map.m_flags = 0;
-
-			/* Check to see if the extent needs to be split */
-			if (punch_map.m_len != ee_len ||
-				punch_map.m_lblk != ee_block) {
-
-				ret = ext4_split_extent(handle, inode,
-				path, &punch_map, 0,
-				EXT4_GET_BLOCKS_PUNCH_OUT_EXT |
-				EXT4_GET_BLOCKS_PRE_IO);
-
-				if (ret < 0) {
-					err = ret;
-					goto out2;
-				}
-				/*
-				 * find extent for the block at
-				 * the start of the hole
-				 */
-				ext4_ext_drop_refs(path);
-				kfree(path);
-
-				path = ext4_ext_find_extent(inode,
-				map->m_lblk, NULL);
-				if (IS_ERR(path)) {
-					err = PTR_ERR(path);
-					path = NULL;
-					goto out2;
-				}
-
-				depth = ext_depth(inode);
-				ex = path[depth].p_ext;
-				ee_len = ext4_ext_get_actual_len(ex);
-				ee_block = le32_to_cpu(ex->ee_block);
-				ee_start = ext4_ext_pblock(ex);
-
+			if (!ext4_ext_is_uninitialized(ex)) {
+				ext4_ext_put_in_cache(inode, ee_block,
+					ee_len, ee_start);
+				goto out;
 			}
-
-			ext4_ext_mark_uninitialized(ex);
-
-			ext4_ext_invalidate_cache(inode);
-
-			err = ext4_ext_rm_leaf(handle, inode, path,
-					       &partial_cluster, map->m_lblk,
-					       map->m_lblk + punched_out);
-
-			if (!err && path->p_hdr->eh_entries == 0) {
-				/*
-				 * Punch hole freed all of this sub tree,
-				 * so we need to correct eh_depth
-				 */
-				err = ext4_ext_get_access(handle, inode, path);
-				if (err == 0) {
-					ext_inode_hdr(inode)->eh_depth = 0;
-					ext_inode_hdr(inode)->eh_max =
-					cpu_to_le16(ext4_ext_space_root(
-						inode, 0));
-
-					err = ext4_ext_dirty(
-						handle, inode, path);
-				}
-			}
-
-			goto out2;
+			ret = ext4_ext_handle_uninitialized_extents(
+				handle, inode, map, path, flags,
+				allocated, newblock);
+			return ret;
 		}
 	}
 
@@ -4165,13 +4146,11 @@
 		ext4_ext_drop_refs(path);
 		kfree(path);
 	}
-	result = (flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) ?
-			punched_out : allocated;
 
 	trace_ext4_ext_map_blocks_exit(inode, map->m_lblk,
-		newblock, map->m_len, err ? err : result);
+		newblock, map->m_len, err ? err : allocated);
 
-	return err ? err : result;
+	return err ? err : allocated;
 }
 
 void ext4_ext_truncate(struct inode *inode)
@@ -4228,7 +4207,7 @@
 
 	last_block = (inode->i_size + sb->s_blocksize - 1)
 			>> EXT4_BLOCK_SIZE_BITS(sb);
-	err = ext4_ext_remove_space(inode, last_block);
+	err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1);
 
 	/* In a multi-transaction truncate, we only make the final
 	 * transaction synchronous.
@@ -4436,10 +4415,11 @@
 				      EXT4_GET_BLOCKS_IO_CONVERT_EXT);
 		if (ret <= 0) {
 			WARN_ON(ret <= 0);
-			printk(KERN_ERR "%s: ext4_ext_map_blocks "
-				    "returned error inode#%lu, block=%u, "
-				    "max_blocks=%u", __func__,
-				    inode->i_ino, map.m_lblk, map.m_len);
+			ext4_msg(inode->i_sb, KERN_ERR,
+				 "%s:%d: inode #%lu: block %u: len %u: "
+				 "ext4_ext_map_blocks returned %d",
+				 __func__, __LINE__, inode->i_ino, map.m_lblk,
+				 map.m_len, ret);
 		}
 		ext4_mark_inode_dirty(handle, inode);
 		ret2 = ext4_journal_stop(handle);
@@ -4705,14 +4685,12 @@
 {
 	struct inode *inode = file->f_path.dentry->d_inode;
 	struct super_block *sb = inode->i_sb;
-	struct ext4_ext_cache cache_ex;
-	ext4_lblk_t first_block, last_block, num_blocks, iblock, max_blocks;
+	ext4_lblk_t first_block, stop_block;
 	struct address_space *mapping = inode->i_mapping;
-	struct ext4_map_blocks map;
 	handle_t *handle;
 	loff_t first_page, last_page, page_len;
 	loff_t first_page_offset, last_page_offset;
-	int ret, credits, blocks_released, err = 0;
+	int credits, err = 0;
 
 	/* No need to punch hole beyond i_size */
 	if (offset >= inode->i_size)
@@ -4728,10 +4706,6 @@
 		   offset;
 	}
 
-	first_block = (offset + sb->s_blocksize - 1) >>
-		EXT4_BLOCK_SIZE_BITS(sb);
-	last_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb);
-
 	first_page = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 	last_page = (offset + length) >> PAGE_CACHE_SHIFT;
 
@@ -4810,7 +4784,6 @@
 		}
 	}
 
-
 	/*
 	 * If i_size is contained in the last page, we need to
 	 * unmap and zero the partial page after i_size
@@ -4830,73 +4803,22 @@
 		}
 	}
 
+	first_block = (offset + sb->s_blocksize - 1) >>
+		EXT4_BLOCK_SIZE_BITS(sb);
+	stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb);
+
 	/* If there are no blocks to remove, return now */
-	if (first_block >= last_block)
+	if (first_block >= stop_block)
 		goto out;
 
 	down_write(&EXT4_I(inode)->i_data_sem);
 	ext4_ext_invalidate_cache(inode);
 	ext4_discard_preallocations(inode);
 
-	/*
-	 * Loop over all the blocks and identify blocks
-	 * that need to be punched out
-	 */
-	iblock = first_block;
-	blocks_released = 0;
-	while (iblock < last_block) {
-		max_blocks = last_block - iblock;
-		num_blocks = 1;
-		memset(&map, 0, sizeof(map));
-		map.m_lblk = iblock;
-		map.m_len = max_blocks;
-		ret = ext4_ext_map_blocks(handle, inode, &map,
-			EXT4_GET_BLOCKS_PUNCH_OUT_EXT);
+	err = ext4_ext_remove_space(inode, first_block, stop_block - 1);
 
-		if (ret > 0) {
-			blocks_released += ret;
-			num_blocks = ret;
-		} else if (ret == 0) {
-			/*
-			 * If map blocks could not find the block,
-			 * then it is in a hole.  If the hole was
-			 * not already cached, then map blocks should
-			 * put it in the cache.  So we can get the hole
-			 * out of the cache
-			 */
-			memset(&cache_ex, 0, sizeof(cache_ex));
-			if ((ext4_ext_check_cache(inode, iblock, &cache_ex)) &&
-				!cache_ex.ec_start) {
-
-				/* The hole is cached */
-				num_blocks = cache_ex.ec_block +
-				cache_ex.ec_len - iblock;
-
-			} else {
-				/* The block could not be identified */
-				err = -EIO;
-				break;
-			}
-		} else {
-			/* Map blocks error */
-			err = ret;
-			break;
-		}
-
-		if (num_blocks == 0) {
-			/* This condition should never happen */
-			ext_debug("Block lookup failed");
-			err = -EIO;
-			break;
-		}
-
-		iblock += num_blocks;
-	}
-
-	if (blocks_released > 0) {
-		ext4_ext_invalidate_cache(inode);
-		ext4_discard_preallocations(inode);
-	}
+	ext4_ext_invalidate_cache(inode);
+	ext4_discard_preallocations(inode);
 
 	if (IS_SYNC(inode))
 		ext4_handle_sync(handle);
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
index 00a2cb7..bb6c7d8 100644
--- a/fs/ext4/fsync.c
+++ b/fs/ext4/fsync.c
@@ -89,6 +89,7 @@
 		io = list_entry(ei->i_completed_io_list.next,
 				ext4_io_end_t, list);
 		list_del_init(&io->list);
+		io->flag |= EXT4_IO_END_IN_FSYNC;
 		/*
 		 * Calling ext4_end_io_nolock() to convert completed
 		 * IO to written.
@@ -108,6 +109,7 @@
 		if (ret < 0)
 			ret2 = ret;
 		spin_lock_irqsave(&ei->i_completed_io_lock, flags);
+		io->flag &= ~EXT4_IO_END_IN_FSYNC;
 	}
 	spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
 	return (ret2 < 0) ? ret2 : 0;
diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c
index ac8f168..fa8e491 100644
--- a/fs/ext4/hash.c
+++ b/fs/ext4/hash.c
@@ -200,8 +200,8 @@
 		return -1;
 	}
 	hash = hash & ~1;
-	if (hash == (EXT4_HTREE_EOF << 1))
-		hash = (EXT4_HTREE_EOF-1) << 1;
+	if (hash == (EXT4_HTREE_EOF_32BIT << 1))
+		hash = (EXT4_HTREE_EOF_32BIT - 1) << 1;
 	hinfo->hash = hash;
 	hinfo->minor_hash = minor_hash;
 	return 0;
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 25d8c97..409c2ee 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -92,6 +92,16 @@
 	return EXT4_INODES_PER_GROUP(sb);
 }
 
+void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate)
+{
+	if (uptodate) {
+		set_buffer_uptodate(bh);
+		set_bitmap_uptodate(bh);
+	}
+	unlock_buffer(bh);
+	put_bh(bh);
+}
+
 /*
  * Read the inode allocation bitmap for a given block_group, reading
  * into the specified slot in the superblock's bitmap cache.
@@ -147,18 +157,18 @@
 		return bh;
 	}
 	/*
-	 * submit the buffer_head for read. We can
-	 * safely mark the bitmap as uptodate now.
-	 * We do it here so the bitmap uptodate bit
-	 * get set with buffer lock held.
+	 * submit the buffer_head for reading
 	 */
 	trace_ext4_load_inode_bitmap(sb, block_group);
-	set_bitmap_uptodate(bh);
-	if (bh_submit_read(bh) < 0) {
+	bh->b_end_io = ext4_end_bitmap_read;
+	get_bh(bh);
+	submit_bh(READ, bh);
+	wait_on_buffer(bh);
+	if (!buffer_uptodate(bh)) {
 		put_bh(bh);
 		ext4_error(sb, "Cannot read inode bitmap - "
-			    "block_group = %u, inode_bitmap = %llu",
-			    block_group, bitmap_blk);
+			   "block_group = %u, inode_bitmap = %llu",
+			   block_group, bitmap_blk);
 		return NULL;
 	}
 	return bh;
@@ -194,19 +204,20 @@
 	struct ext4_sb_info *sbi;
 	int fatal = 0, err, count, cleared;
 
+	if (!sb) {
+		printk(KERN_ERR "EXT4-fs: %s:%d: inode on "
+		       "nonexistent device\n", __func__, __LINE__);
+		return;
+	}
 	if (atomic_read(&inode->i_count) > 1) {
-		printk(KERN_ERR "ext4_free_inode: inode has count=%d\n",
-		       atomic_read(&inode->i_count));
+		ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: count=%d",
+			 __func__, __LINE__, inode->i_ino,
+			 atomic_read(&inode->i_count));
 		return;
 	}
 	if (inode->i_nlink) {
-		printk(KERN_ERR "ext4_free_inode: inode has nlink=%d\n",
-		       inode->i_nlink);
-		return;
-	}
-	if (!sb) {
-		printk(KERN_ERR "ext4_free_inode: inode on "
-		       "nonexistent device\n");
+		ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: nlink=%d\n",
+			 __func__, __LINE__, inode->i_ino, inode->i_nlink);
 		return;
 	}
 	sbi = EXT4_SB(sb);
@@ -593,94 +604,6 @@
 }
 
 /*
- * claim the inode from the inode bitmap. If the group
- * is uninit we need to take the groups's ext4_group_lock
- * and clear the uninit flag. The inode bitmap update
- * and group desc uninit flag clear should be done
- * after holding ext4_group_lock so that ext4_read_inode_bitmap
- * doesn't race with the ext4_claim_inode
- */
-static int ext4_claim_inode(struct super_block *sb,
-			struct buffer_head *inode_bitmap_bh,
-			unsigned long ino, ext4_group_t group, umode_t mode)
-{
-	int free = 0, retval = 0, count;
-	struct ext4_sb_info *sbi = EXT4_SB(sb);
-	struct ext4_group_info *grp = ext4_get_group_info(sb, group);
-	struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL);
-
-	/*
-	 * We have to be sure that new inode allocation does not race with
-	 * inode table initialization, because otherwise we may end up
-	 * allocating and writing new inode right before sb_issue_zeroout
-	 * takes place and overwriting our new inode with zeroes. So we
-	 * take alloc_sem to prevent it.
-	 */
-	down_read(&grp->alloc_sem);
-	ext4_lock_group(sb, group);
-	if (ext4_test_and_set_bit(ino, inode_bitmap_bh->b_data)) {
-		/* not a free inode */
-		retval = 1;
-		goto err_ret;
-	}
-	ino++;
-	if ((group == 0 && ino < EXT4_FIRST_INO(sb)) ||
-			ino > EXT4_INODES_PER_GROUP(sb)) {
-		ext4_unlock_group(sb, group);
-		up_read(&grp->alloc_sem);
-		ext4_error(sb, "reserved inode or inode > inodes count - "
-			   "block_group = %u, inode=%lu", group,
-			   ino + group * EXT4_INODES_PER_GROUP(sb));
-		return 1;
-	}
-	/* If we didn't allocate from within the initialized part of the inode
-	 * table then we need to initialize up to this inode. */
-	if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
-
-		if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
-			gdp->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
-			/* When marking the block group with
-			 * ~EXT4_BG_INODE_UNINIT we don't want to depend
-			 * on the value of bg_itable_unused even though
-			 * mke2fs could have initialized the same for us.
-			 * Instead we calculated the value below
-			 */
-
-			free = 0;
-		} else {
-			free = EXT4_INODES_PER_GROUP(sb) -
-				ext4_itable_unused_count(sb, gdp);
-		}
-
-		/*
-		 * Check the relative inode number against the last used
-		 * relative inode number in this group. if it is greater
-		 * we need to  update the bg_itable_unused count
-		 *
-		 */
-		if (ino > free)
-			ext4_itable_unused_set(sb, gdp,
-					(EXT4_INODES_PER_GROUP(sb) - ino));
-	}
-	count = ext4_free_inodes_count(sb, gdp) - 1;
-	ext4_free_inodes_set(sb, gdp, count);
-	if (S_ISDIR(mode)) {
-		count = ext4_used_dirs_count(sb, gdp) + 1;
-		ext4_used_dirs_set(sb, gdp, count);
-		if (sbi->s_log_groups_per_flex) {
-			ext4_group_t f = ext4_flex_group(sbi, group);
-
-			atomic_inc(&sbi->s_flex_groups[f].used_dirs);
-		}
-	}
-	gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp);
-err_ret:
-	ext4_unlock_group(sb, group);
-	up_read(&grp->alloc_sem);
-	return retval;
-}
-
-/*
  * 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
@@ -741,6 +664,11 @@
 	if (ret2 == -1)
 		goto out;
 
+	/*
+	 * Normally we will only go through one pass of this loop,
+	 * unless we get unlucky and it turns out the group we selected
+	 * had its last inode grabbed by someone else.
+	 */
 	for (i = 0; i < ngroups; i++, ino = 0) {
 		err = -EIO;
 
@@ -757,51 +685,24 @@
 		ino = ext4_find_next_zero_bit((unsigned long *)
 					      inode_bitmap_bh->b_data,
 					      EXT4_INODES_PER_GROUP(sb), ino);
-
-		if (ino < EXT4_INODES_PER_GROUP(sb)) {
-
-			BUFFER_TRACE(inode_bitmap_bh, "get_write_access");
-			err = ext4_journal_get_write_access(handle,
-							    inode_bitmap_bh);
-			if (err)
-				goto fail;
-
-			BUFFER_TRACE(group_desc_bh, "get_write_access");
-			err = ext4_journal_get_write_access(handle,
-								group_desc_bh);
-			if (err)
-				goto fail;
-			if (!ext4_claim_inode(sb, inode_bitmap_bh,
-						ino, group, mode)) {
-				/* we won it */
-				BUFFER_TRACE(inode_bitmap_bh,
-					"call ext4_handle_dirty_metadata");
-				err = ext4_handle_dirty_metadata(handle,
-								 NULL,
-							inode_bitmap_bh);
-				if (err)
-					goto fail;
-				/* zero bit is inode number 1*/
-				ino++;
-				goto got;
-			}
-			/* we lost it */
-			ext4_handle_release_buffer(handle, inode_bitmap_bh);
-			ext4_handle_release_buffer(handle, group_desc_bh);
-
-			if (++ino < EXT4_INODES_PER_GROUP(sb))
-				goto repeat_in_this_group;
+		if (ino >= EXT4_INODES_PER_GROUP(sb)) {
+			if (++group == ngroups)
+				group = 0;
+			continue;
 		}
-
-		/*
-		 * This case is possible in concurrent environment.  It is very
-		 * rare.  We cannot repeat the find_group_xxx() call because
-		 * that will simply return the same blockgroup, because the
-		 * group descriptor metadata has not yet been updated.
-		 * So we just go onto the next blockgroup.
-		 */
-		if (++group == ngroups)
-			group = 0;
+		if (group == 0 && (ino+1) < EXT4_FIRST_INO(sb)) {
+			ext4_error(sb, "reserved inode found cleared - "
+				   "inode=%lu", ino + 1);
+			continue;
+		}
+		ext4_lock_group(sb, group);
+		ret2 = ext4_test_and_set_bit(ino, inode_bitmap_bh->b_data);
+		ext4_unlock_group(sb, group);
+		ino++;		/* the inode bitmap is zero-based */
+		if (!ret2)
+			goto got; /* we grabbed the inode! */
+		if (ino < EXT4_INODES_PER_GROUP(sb))
+			goto repeat_in_this_group;
 	}
 	err = -ENOSPC;
 	goto out;
@@ -838,6 +739,59 @@
 		if (err)
 			goto fail;
 	}
+
+	BUFFER_TRACE(inode_bitmap_bh, "get_write_access");
+	err = ext4_journal_get_write_access(handle, inode_bitmap_bh);
+	if (err)
+		goto fail;
+
+	BUFFER_TRACE(group_desc_bh, "get_write_access");
+	err = ext4_journal_get_write_access(handle, group_desc_bh);
+	if (err)
+		goto fail;
+
+	/* Update the relevant bg descriptor fields */
+	if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+		int free;
+		struct ext4_group_info *grp = ext4_get_group_info(sb, group);
+
+		down_read(&grp->alloc_sem); /* protect vs itable lazyinit */
+		ext4_lock_group(sb, group); /* while we modify the bg desc */
+		free = EXT4_INODES_PER_GROUP(sb) -
+			ext4_itable_unused_count(sb, gdp);
+		if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
+			gdp->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
+			free = 0;
+		}
+		/*
+		 * Check the relative inode number against the last used
+		 * relative inode number in this group. if it is greater
+		 * we need to update the bg_itable_unused count
+		 */
+		if (ino > free)
+			ext4_itable_unused_set(sb, gdp,
+					(EXT4_INODES_PER_GROUP(sb) - ino));
+		up_read(&grp->alloc_sem);
+	}
+	ext4_free_inodes_set(sb, gdp, ext4_free_inodes_count(sb, gdp) - 1);
+	if (S_ISDIR(mode)) {
+		ext4_used_dirs_set(sb, gdp, ext4_used_dirs_count(sb, gdp) + 1);
+		if (sbi->s_log_groups_per_flex) {
+			ext4_group_t f = ext4_flex_group(sbi, group);
+
+			atomic_inc(&sbi->s_flex_groups[f].used_dirs);
+		}
+	}
+	if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+		gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp);
+		ext4_unlock_group(sb, group);
+	}
+
+	BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata");
+	err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh);
+	if (err)
+		goto fail;
+
 	BUFFER_TRACE(group_desc_bh, "call ext4_handle_dirty_metadata");
 	err = ext4_handle_dirty_metadata(handle, NULL, group_desc_bh);
 	if (err)
@@ -1101,7 +1055,7 @@
  * where it is called from on active part of filesystem is ext4lazyinit
  * thread, so we do not need any special locks, however we have to prevent
  * inode allocation from the current group, so we take alloc_sem lock, to
- * block ext4_claim_inode until we are finished.
+ * block ext4_new_inode() until we are finished.
  */
 int ext4_init_inode_table(struct super_block *sb, ext4_group_t group,
 				 int barrier)
@@ -1149,9 +1103,9 @@
 			    sbi->s_inodes_per_block);
 
 	if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group)) {
-		ext4_error(sb, "Something is wrong with group %u\n"
-			   "Used itable blocks: %d"
-			   "itable unused count: %u\n",
+		ext4_error(sb, "Something is wrong with group %u: "
+			   "used itable blocks: %d; "
+			   "itable unused count: %u",
 			   group, used_blks,
 			   ext4_itable_unused_count(sb, gdp));
 		ret = 1;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index feaa82f..c77b0bd 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -272,7 +272,7 @@
 	trace_ext4_da_update_reserve_space(inode, used, quota_claim);
 	if (unlikely(used > ei->i_reserved_data_blocks)) {
 		ext4_msg(inode->i_sb, KERN_NOTICE, "%s: ino %lu, used %d "
-			 "with only %d reserved data blocks\n",
+			 "with only %d reserved data blocks",
 			 __func__, inode->i_ino, used,
 			 ei->i_reserved_data_blocks);
 		WARN_ON(1);
@@ -1165,7 +1165,7 @@
 		 */
 		ext4_msg(inode->i_sb, KERN_NOTICE, "ext4_da_release_space: "
 			 "ino %lu, to_free %d with only %d reserved "
-			 "data blocks\n", inode->i_ino, to_free,
+			 "data blocks", inode->i_ino, to_free,
 			 ei->i_reserved_data_blocks);
 		WARN_ON(1);
 		to_free = ei->i_reserved_data_blocks;
@@ -1428,20 +1428,22 @@
 static void ext4_print_free_blocks(struct inode *inode)
 {
 	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
-	printk(KERN_CRIT "Total free blocks count %lld\n",
+	struct super_block *sb = inode->i_sb;
+
+	ext4_msg(sb, KERN_CRIT, "Total free blocks count %lld",
 	       EXT4_C2B(EXT4_SB(inode->i_sb),
 			ext4_count_free_clusters(inode->i_sb)));
-	printk(KERN_CRIT "Free/Dirty block details\n");
-	printk(KERN_CRIT "free_blocks=%lld\n",
+	ext4_msg(sb, KERN_CRIT, "Free/Dirty block details");
+	ext4_msg(sb, KERN_CRIT, "free_blocks=%lld",
 	       (long long) EXT4_C2B(EXT4_SB(inode->i_sb),
 		percpu_counter_sum(&sbi->s_freeclusters_counter)));
-	printk(KERN_CRIT "dirty_blocks=%lld\n",
+	ext4_msg(sb, KERN_CRIT, "dirty_blocks=%lld",
 	       (long long) EXT4_C2B(EXT4_SB(inode->i_sb),
 		percpu_counter_sum(&sbi->s_dirtyclusters_counter)));
-	printk(KERN_CRIT "Block reservation details\n");
-	printk(KERN_CRIT "i_reserved_data_blocks=%u\n",
-	       EXT4_I(inode)->i_reserved_data_blocks);
-	printk(KERN_CRIT "i_reserved_meta_blocks=%u\n",
+	ext4_msg(sb, KERN_CRIT, "Block reservation details");
+	ext4_msg(sb, KERN_CRIT, "i_reserved_data_blocks=%u",
+		 EXT4_I(inode)->i_reserved_data_blocks);
+	ext4_msg(sb, KERN_CRIT, "i_reserved_meta_blocks=%u",
 	       EXT4_I(inode)->i_reserved_meta_blocks);
 	return;
 }
@@ -2482,13 +2484,14 @@
 	int write_mode = (int)(unsigned long)fsdata;
 
 	if (write_mode == FALL_BACK_TO_NONDELALLOC) {
-		if (ext4_should_order_data(inode)) {
+		switch (ext4_inode_journal_mode(inode)) {
+		case EXT4_INODE_ORDERED_DATA_MODE:
 			return ext4_ordered_write_end(file, mapping, pos,
 					len, copied, page, fsdata);
-		} else if (ext4_should_writeback_data(inode)) {
+		case EXT4_INODE_WRITEBACK_DATA_MODE:
 			return ext4_writeback_write_end(file, mapping, pos,
 					len, copied, page, fsdata);
-		} else {
+		default:
 			BUG();
 		}
 	}
@@ -2763,7 +2766,7 @@
 		goto out;
 
 	ext_debug("ext4_end_io_dio(): io_end 0x%p "
-		  "for inode %lu, iocb 0x%p, offset %llu, size %llu\n",
+		  "for inode %lu, iocb 0x%p, offset %llu, size %zd\n",
  		  iocb->private, io_end->inode->i_ino, iocb, offset,
 		  size);
 
@@ -2795,9 +2798,6 @@
 
 	/* queue the work to convert unwritten extents to written */
 	queue_work(wq, &io_end->work);
-
-	/* XXX: probably should move into the real I/O completion handler */
-	inode_dio_done(inode);
 }
 
 static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate)
@@ -2811,8 +2811,9 @@
 		goto out;
 
 	if (!(io_end->inode->i_sb->s_flags & MS_ACTIVE)) {
-		printk("sb umounted, discard end_io request for inode %lu\n",
-			io_end->inode->i_ino);
+		ext4_msg(io_end->inode->i_sb, KERN_INFO,
+			 "sb umounted, discard end_io request for inode %lu",
+			 io_end->inode->i_ino);
 		ext4_free_io_end(io_end);
 		goto out;
 	}
@@ -2921,9 +2922,12 @@
 		iocb->private = NULL;
 		EXT4_I(inode)->cur_aio_dio = NULL;
 		if (!is_sync_kiocb(iocb)) {
-			iocb->private = ext4_init_io_end(inode, GFP_NOFS);
-			if (!iocb->private)
+			ext4_io_end_t *io_end =
+				ext4_init_io_end(inode, GFP_NOFS);
+			if (!io_end)
 				return -ENOMEM;
+			io_end->flag |= EXT4_IO_END_DIRECT;
+			iocb->private = io_end;
 			/*
 			 * we save the io structure for current async
 			 * direct IO, so that later ext4_map_blocks()
@@ -2940,7 +2944,7 @@
 					 ext4_get_block_write,
 					 ext4_end_io_dio,
 					 NULL,
-					 DIO_LOCKING | DIO_SKIP_HOLES);
+					 DIO_LOCKING);
 		if (iocb->private)
 			EXT4_I(inode)->cur_aio_dio = NULL;
 		/*
@@ -3086,18 +3090,25 @@
 
 void ext4_set_aops(struct inode *inode)
 {
-	if (ext4_should_order_data(inode) &&
-		test_opt(inode->i_sb, DELALLOC))
-		inode->i_mapping->a_ops = &ext4_da_aops;
-	else if (ext4_should_order_data(inode))
-		inode->i_mapping->a_ops = &ext4_ordered_aops;
-	else if (ext4_should_writeback_data(inode) &&
-		 test_opt(inode->i_sb, DELALLOC))
-		inode->i_mapping->a_ops = &ext4_da_aops;
-	else if (ext4_should_writeback_data(inode))
-		inode->i_mapping->a_ops = &ext4_writeback_aops;
-	else
+	switch (ext4_inode_journal_mode(inode)) {
+	case EXT4_INODE_ORDERED_DATA_MODE:
+		if (test_opt(inode->i_sb, DELALLOC))
+			inode->i_mapping->a_ops = &ext4_da_aops;
+		else
+			inode->i_mapping->a_ops = &ext4_ordered_aops;
+		break;
+	case EXT4_INODE_WRITEBACK_DATA_MODE:
+		if (test_opt(inode->i_sb, DELALLOC))
+			inode->i_mapping->a_ops = &ext4_da_aops;
+		else
+			inode->i_mapping->a_ops = &ext4_writeback_aops;
+		break;
+	case EXT4_INODE_JOURNAL_DATA_MODE:
 		inode->i_mapping->a_ops = &ext4_journalled_aops;
+		break;
+	default:
+		BUG();
+	}
 }
 
 
@@ -3329,16 +3340,16 @@
 {
 	struct inode *inode = file->f_path.dentry->d_inode;
 	if (!S_ISREG(inode->i_mode))
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 
 	if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
 		/* TODO: Add support for non extent hole punching */
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 	}
 
 	if (EXT4_SB(inode->i_sb)->s_cluster_ratio > 1) {
 		/* TODO: Add support for bigalloc file systems */
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 	}
 
 	return ext4_ext_punch_hole(file, offset, length);
@@ -3924,10 +3935,8 @@
 			ext4_update_dynamic_rev(sb);
 			EXT4_SET_RO_COMPAT_FEATURE(sb,
 					EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
-			sb->s_dirt = 1;
 			ext4_handle_sync(handle);
-			err = ext4_handle_dirty_metadata(handle, NULL,
-					EXT4_SB(sb)->s_sbh);
+			err = ext4_handle_dirty_super(handle, sb);
 		}
 	}
 	raw_inode->i_generation = cpu_to_le32(inode->i_generation);
@@ -4152,11 +4161,9 @@
 	}
 
 	if (attr->ia_valid & ATTR_SIZE) {
-		if (attr->ia_size != i_size_read(inode)) {
+		if (attr->ia_size != i_size_read(inode))
 			truncate_setsize(inode, attr->ia_size);
-			ext4_truncate(inode);
-		} else if (ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS))
-			ext4_truncate(inode);
+		ext4_truncate(inode);
 	}
 
 	if (!rc) {
@@ -4314,7 +4321,7 @@
 {
 	int err = 0;
 
-	if (test_opt(inode->i_sb, I_VERSION))
+	if (IS_I_VERSION(inode))
 		inode_inc_iversion(inode);
 
 	/* the do_update_inode consumes one bh->b_count */
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index cb990b2..99ab428 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -21,6 +21,7 @@
  * mballoc.c contains the multiblocks allocation routines
  */
 
+#include "ext4_jbd2.h"
 #include "mballoc.h"
 #include <linux/debugfs.h>
 #include <linux/slab.h>
@@ -339,7 +340,7 @@
  */
 static struct kmem_cache *ext4_pspace_cachep;
 static struct kmem_cache *ext4_ac_cachep;
-static struct kmem_cache *ext4_free_ext_cachep;
+static struct kmem_cache *ext4_free_data_cachep;
 
 /* We create slab caches for groupinfo data structures based on the
  * superblock block size.  There will be one per mounted filesystem for
@@ -357,7 +358,8 @@
 					ext4_group_t group);
 static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
 						ext4_group_t group);
-static void release_blocks_on_commit(journal_t *journal, transaction_t *txn);
+static void ext4_free_data_callback(struct super_block *sb,
+				struct ext4_journal_cb_entry *jce, int rc);
 
 static inline void *mb_correct_addr_and_bit(int *bit, void *addr)
 {
@@ -425,7 +427,7 @@
 {
 	char *bb;
 
-	BUG_ON(EXT4_MB_BITMAP(e4b) == EXT4_MB_BUDDY(e4b));
+	BUG_ON(e4b->bd_bitmap == e4b->bd_buddy);
 	BUG_ON(max == NULL);
 
 	if (order > e4b->bd_blkbits + 1) {
@@ -436,10 +438,10 @@
 	/* at order 0 we see each particular block */
 	if (order == 0) {
 		*max = 1 << (e4b->bd_blkbits + 3);
-		return EXT4_MB_BITMAP(e4b);
+		return e4b->bd_bitmap;
 	}
 
-	bb = EXT4_MB_BUDDY(e4b) + EXT4_SB(e4b->bd_sb)->s_mb_offsets[order];
+	bb = e4b->bd_buddy + EXT4_SB(e4b->bd_sb)->s_mb_offsets[order];
 	*max = EXT4_SB(e4b->bd_sb)->s_mb_maxs[order];
 
 	return bb;
@@ -588,7 +590,7 @@
 			for (j = 0; j < (1 << order); j++) {
 				k = (i * (1 << order)) + j;
 				MB_CHECK_ASSERT(
-					!mb_test_bit(k, EXT4_MB_BITMAP(e4b)));
+					!mb_test_bit(k, e4b->bd_bitmap));
 			}
 			count++;
 		}
@@ -782,7 +784,7 @@
 	int groups_per_page;
 	int err = 0;
 	int i;
-	ext4_group_t first_group;
+	ext4_group_t first_group, group;
 	int first_block;
 	struct super_block *sb;
 	struct buffer_head *bhs;
@@ -806,24 +808,23 @@
 
 	/* allocate buffer_heads to read bitmaps */
 	if (groups_per_page > 1) {
-		err = -ENOMEM;
 		i = sizeof(struct buffer_head *) * groups_per_page;
 		bh = kzalloc(i, GFP_NOFS);
-		if (bh == NULL)
+		if (bh == NULL) {
+			err = -ENOMEM;
 			goto out;
+		}
 	} else
 		bh = &bhs;
 
 	first_group = page->index * blocks_per_page / 2;
 
 	/* read all groups the page covers into the cache */
-	for (i = 0; i < groups_per_page; i++) {
-		struct ext4_group_desc *desc;
-
-		if (first_group + i >= ngroups)
+	for (i = 0, group = first_group; i < groups_per_page; i++, group++) {
+		if (group >= ngroups)
 			break;
 
-		grinfo = ext4_get_group_info(sb, first_group + i);
+		grinfo = ext4_get_group_info(sb, group);
 		/*
 		 * If page is uptodate then we came here after online resize
 		 * which added some new uninitialized group info structs, so
@@ -834,69 +835,21 @@
 			bh[i] = NULL;
 			continue;
 		}
-
-		err = -EIO;
-		desc = ext4_get_group_desc(sb, first_group + i, NULL);
-		if (desc == NULL)
+		if (!(bh[i] = ext4_read_block_bitmap_nowait(sb, group))) {
+			err = -ENOMEM;
 			goto out;
-
-		err = -ENOMEM;
-		bh[i] = sb_getblk(sb, ext4_block_bitmap(sb, desc));
-		if (bh[i] == NULL)
-			goto out;
-
-		if (bitmap_uptodate(bh[i]))
-			continue;
-
-		lock_buffer(bh[i]);
-		if (bitmap_uptodate(bh[i])) {
-			unlock_buffer(bh[i]);
-			continue;
 		}
-		ext4_lock_group(sb, first_group + i);
-		if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
-			ext4_init_block_bitmap(sb, bh[i],
-						first_group + i, desc);
-			set_bitmap_uptodate(bh[i]);
-			set_buffer_uptodate(bh[i]);
-			ext4_unlock_group(sb, first_group + i);
-			unlock_buffer(bh[i]);
-			continue;
-		}
-		ext4_unlock_group(sb, first_group + i);
-		if (buffer_uptodate(bh[i])) {
-			/*
-			 * if not uninit if bh is uptodate,
-			 * bitmap is also uptodate
-			 */
-			set_bitmap_uptodate(bh[i]);
-			unlock_buffer(bh[i]);
-			continue;
-		}
-		get_bh(bh[i]);
-		/*
-		 * submit the buffer_head for read. We can
-		 * safely mark the bitmap as uptodate now.
-		 * We do it here so the bitmap uptodate bit
-		 * get set with buffer lock held.
-		 */
-		set_bitmap_uptodate(bh[i]);
-		bh[i]->b_end_io = end_buffer_read_sync;
-		submit_bh(READ, bh[i]);
-		mb_debug(1, "read bitmap for group %u\n", first_group + i);
+		mb_debug(1, "read bitmap for group %u\n", group);
 	}
 
 	/* wait for I/O completion */
-	for (i = 0; i < groups_per_page; i++)
-		if (bh[i])
-			wait_on_buffer(bh[i]);
-
-	err = -EIO;
-	for (i = 0; i < groups_per_page; i++)
-		if (bh[i] && !buffer_uptodate(bh[i]))
+	for (i = 0, group = first_group; i < groups_per_page; i++, group++) {
+		if (bh[i] && ext4_wait_block_bitmap(sb, group, bh[i])) {
+			err = -EIO;
 			goto out;
+		}
+	}
 
-	err = 0;
 	first_block = page->index * blocks_per_page;
 	for (i = 0; i < blocks_per_page; i++) {
 		int group;
@@ -1250,10 +1203,10 @@
 	int order = 1;
 	void *bb;
 
-	BUG_ON(EXT4_MB_BITMAP(e4b) == EXT4_MB_BUDDY(e4b));
+	BUG_ON(e4b->bd_bitmap == e4b->bd_buddy);
 	BUG_ON(block >= (1 << (e4b->bd_blkbits + 3)));
 
-	bb = EXT4_MB_BUDDY(e4b);
+	bb = e4b->bd_buddy;
 	while (order <= e4b->bd_blkbits + 1) {
 		block = block >> 1;
 		if (!mb_test_bit(block, bb)) {
@@ -1323,9 +1276,9 @@
 
 	/* let's maintain fragments counter */
 	if (first != 0)
-		block = !mb_test_bit(first - 1, EXT4_MB_BITMAP(e4b));
+		block = !mb_test_bit(first - 1, e4b->bd_bitmap);
 	if (first + count < EXT4_SB(sb)->s_mb_maxs[0])
-		max = !mb_test_bit(first + count, EXT4_MB_BITMAP(e4b));
+		max = !mb_test_bit(first + count, e4b->bd_bitmap);
 	if (block && max)
 		e4b->bd_info->bb_fragments--;
 	else if (!block && !max)
@@ -1336,7 +1289,7 @@
 		block = first++;
 		order = 0;
 
-		if (!mb_test_bit(block, EXT4_MB_BITMAP(e4b))) {
+		if (!mb_test_bit(block, e4b->bd_bitmap)) {
 			ext4_fsblk_t blocknr;
 
 			blocknr = ext4_group_first_block_no(sb, e4b->bd_group);
@@ -1347,7 +1300,7 @@
 					      "freeing already freed block "
 					      "(bit %u)", block);
 		}
-		mb_clear_bit(block, EXT4_MB_BITMAP(e4b));
+		mb_clear_bit(block, e4b->bd_bitmap);
 		e4b->bd_info->bb_counters[order]++;
 
 		/* start of the buddy */
@@ -1429,7 +1382,7 @@
 			break;
 
 		next = (block + 1) * (1 << order);
-		if (mb_test_bit(next, EXT4_MB_BITMAP(e4b)))
+		if (mb_test_bit(next, e4b->bd_bitmap))
 			break;
 
 		order = mb_find_order_for_block(e4b, next);
@@ -1466,9 +1419,9 @@
 
 	/* let's maintain fragments counter */
 	if (start != 0)
-		mlen = !mb_test_bit(start - 1, EXT4_MB_BITMAP(e4b));
+		mlen = !mb_test_bit(start - 1, e4b->bd_bitmap);
 	if (start + len < EXT4_SB(e4b->bd_sb)->s_mb_maxs[0])
-		max = !mb_test_bit(start + len, EXT4_MB_BITMAP(e4b));
+		max = !mb_test_bit(start + len, e4b->bd_bitmap);
 	if (mlen && max)
 		e4b->bd_info->bb_fragments++;
 	else if (!mlen && !max)
@@ -1511,7 +1464,7 @@
 	}
 	mb_set_largest_free_order(e4b->bd_sb, e4b->bd_info);
 
-	ext4_set_bits(EXT4_MB_BITMAP(e4b), ex->fe_start, len0);
+	ext4_set_bits(e4b->bd_bitmap, ex->fe_start, len0);
 	mb_check_buddy(e4b);
 
 	return ret;
@@ -1810,7 +1763,7 @@
 					struct ext4_buddy *e4b)
 {
 	struct super_block *sb = ac->ac_sb;
-	void *bitmap = EXT4_MB_BITMAP(e4b);
+	void *bitmap = e4b->bd_bitmap;
 	struct ext4_free_extent ex;
 	int i;
 	int free;
@@ -1870,7 +1823,7 @@
 {
 	struct super_block *sb = ac->ac_sb;
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
-	void *bitmap = EXT4_MB_BITMAP(e4b);
+	void *bitmap = e4b->bd_bitmap;
 	struct ext4_free_extent ex;
 	ext4_fsblk_t first_group_block;
 	ext4_fsblk_t a;
@@ -2224,7 +2177,7 @@
 			EXT4_DESC_PER_BLOCK_BITS(sb);
 		meta_group_info = kmalloc(metalen, GFP_KERNEL);
 		if (meta_group_info == NULL) {
-			ext4_msg(sb, KERN_ERR, "EXT4-fs: can't allocate mem "
+			ext4_msg(sb, KERN_ERR, "can't allocate mem "
 				 "for a buddy group");
 			goto exit_meta_group_info;
 		}
@@ -2238,7 +2191,7 @@
 
 	meta_group_info[i] = kmem_cache_alloc(cachep, GFP_KERNEL);
 	if (meta_group_info[i] == NULL) {
-		ext4_msg(sb, KERN_ERR, "EXT4-fs: can't allocate buddy mem");
+		ext4_msg(sb, KERN_ERR, "can't allocate buddy mem");
 		goto exit_group_info;
 	}
 	memset(meta_group_info[i], 0, kmem_cache_size(cachep));
@@ -2522,9 +2475,6 @@
 		proc_create_data("mb_groups", S_IRUGO, sbi->s_proc,
 				 &ext4_mb_seq_groups_fops, sb);
 
-	if (sbi->s_journal)
-		sbi->s_journal->j_commit_callback = release_blocks_on_commit;
-
 	return 0;
 
 out_free_locality_groups:
@@ -2637,58 +2587,55 @@
  * This function is called by the jbd2 layer once the commit has finished,
  * so we know we can free the blocks that were released with that commit.
  */
-static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
+static void ext4_free_data_callback(struct super_block *sb,
+				    struct ext4_journal_cb_entry *jce,
+				    int rc)
 {
-	struct super_block *sb = journal->j_private;
+	struct ext4_free_data *entry = (struct ext4_free_data *)jce;
 	struct ext4_buddy e4b;
 	struct ext4_group_info *db;
 	int err, count = 0, count2 = 0;
-	struct ext4_free_data *entry;
-	struct list_head *l, *ltmp;
 
-	list_for_each_safe(l, ltmp, &txn->t_private_list) {
-		entry = list_entry(l, struct ext4_free_data, list);
+	mb_debug(1, "gonna free %u blocks in group %u (0x%p):",
+		 entry->efd_count, entry->efd_group, entry);
 
-		mb_debug(1, "gonna free %u blocks in group %u (0x%p):",
-			 entry->count, entry->group, entry);
+	if (test_opt(sb, DISCARD))
+		ext4_issue_discard(sb, entry->efd_group,
+				   entry->efd_start_cluster, entry->efd_count);
 
-		if (test_opt(sb, DISCARD))
-			ext4_issue_discard(sb, entry->group,
-					   entry->start_cluster, entry->count);
+	err = ext4_mb_load_buddy(sb, entry->efd_group, &e4b);
+	/* we expect to find existing buddy because it's pinned */
+	BUG_ON(err != 0);
 
-		err = ext4_mb_load_buddy(sb, entry->group, &e4b);
-		/* we expect to find existing buddy because it's pinned */
-		BUG_ON(err != 0);
 
-		db = e4b.bd_info;
-		/* there are blocks to put in buddy to make them really free */
-		count += entry->count;
-		count2++;
-		ext4_lock_group(sb, entry->group);
-		/* Take it out of per group rb tree */
-		rb_erase(&entry->node, &(db->bb_free_root));
-		mb_free_blocks(NULL, &e4b, entry->start_cluster, entry->count);
+	db = e4b.bd_info;
+	/* there are blocks to put in buddy to make them really free */
+	count += entry->efd_count;
+	count2++;
+	ext4_lock_group(sb, entry->efd_group);
+	/* Take it out of per group rb tree */
+	rb_erase(&entry->efd_node, &(db->bb_free_root));
+	mb_free_blocks(NULL, &e4b, entry->efd_start_cluster, entry->efd_count);
 
-		/*
-		 * Clear the trimmed flag for the group so that the next
-		 * ext4_trim_fs can trim it.
-		 * If the volume is mounted with -o discard, online discard
-		 * is supported and the free blocks will be trimmed online.
+	/*
+	 * Clear the trimmed flag for the group so that the next
+	 * ext4_trim_fs can trim it.
+	 * If the volume is mounted with -o discard, online discard
+	 * is supported and the free blocks will be trimmed online.
+	 */
+	if (!test_opt(sb, DISCARD))
+		EXT4_MB_GRP_CLEAR_TRIMMED(db);
+
+	if (!db->bb_free_root.rb_node) {
+		/* No more items in the per group rb tree
+		 * balance refcounts from ext4_mb_free_metadata()
 		 */
-		if (!test_opt(sb, DISCARD))
-			EXT4_MB_GRP_CLEAR_TRIMMED(db);
-
-		if (!db->bb_free_root.rb_node) {
-			/* No more items in the per group rb tree
-			 * balance refcounts from ext4_mb_free_metadata()
-			 */
-			page_cache_release(e4b.bd_buddy_page);
-			page_cache_release(e4b.bd_bitmap_page);
-		}
-		ext4_unlock_group(sb, entry->group);
-		kmem_cache_free(ext4_free_ext_cachep, entry);
-		ext4_mb_unload_buddy(&e4b);
+		page_cache_release(e4b.bd_buddy_page);
+		page_cache_release(e4b.bd_bitmap_page);
 	}
+	ext4_unlock_group(sb, entry->efd_group);
+	kmem_cache_free(ext4_free_data_cachep, entry);
+	ext4_mb_unload_buddy(&e4b);
 
 	mb_debug(1, "freed %u blocks in %u structures\n", count, count2);
 }
@@ -2741,9 +2688,9 @@
 		return -ENOMEM;
 	}
 
-	ext4_free_ext_cachep = KMEM_CACHE(ext4_free_data,
-					  SLAB_RECLAIM_ACCOUNT);
-	if (ext4_free_ext_cachep == NULL) {
+	ext4_free_data_cachep = KMEM_CACHE(ext4_free_data,
+					   SLAB_RECLAIM_ACCOUNT);
+	if (ext4_free_data_cachep == NULL) {
 		kmem_cache_destroy(ext4_pspace_cachep);
 		kmem_cache_destroy(ext4_ac_cachep);
 		return -ENOMEM;
@@ -2761,7 +2708,7 @@
 	rcu_barrier();
 	kmem_cache_destroy(ext4_pspace_cachep);
 	kmem_cache_destroy(ext4_ac_cachep);
-	kmem_cache_destroy(ext4_free_ext_cachep);
+	kmem_cache_destroy(ext4_free_data_cachep);
 	ext4_groupinfo_destroy_slabs();
 	ext4_remove_debugfs_entry();
 }
@@ -2815,7 +2762,7 @@
 	len = EXT4_C2B(sbi, ac->ac_b_ex.fe_len);
 	if (!ext4_data_block_valid(sbi, block, len)) {
 		ext4_error(sb, "Allocating blocks %llu-%llu which overlap "
-			   "fs metadata\n", block, block+len);
+			   "fs metadata", block, block+len);
 		/* File system mounted not to panic on error
 		 * Fix the bitmap and repeat the block allocation
 		 * We leak some of the blocks here.
@@ -2911,7 +2858,8 @@
 	struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb);
 	int bsbits, max;
 	ext4_lblk_t end;
-	loff_t size, orig_size, start_off;
+	loff_t size, start_off;
+	loff_t orig_size __maybe_unused;
 	ext4_lblk_t start;
 	struct ext4_inode_info *ei = EXT4_I(ac->ac_inode);
 	struct ext4_prealloc_space *pa;
@@ -3321,8 +3269,8 @@
 	n = rb_first(&(grp->bb_free_root));
 
 	while (n) {
-		entry = rb_entry(n, struct ext4_free_data, node);
-		ext4_set_bits(bitmap, entry->start_cluster, entry->count);
+		entry = rb_entry(n, struct ext4_free_data, efd_node);
+		ext4_set_bits(bitmap, entry->efd_start_cluster, entry->efd_count);
 		n = rb_next(n);
 	}
 	return;
@@ -3916,11 +3864,11 @@
 	    (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED))
 		return;
 
-	ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: Can't allocate:"
+	ext4_msg(ac->ac_sb, KERN_ERR, "Can't allocate:"
 			" Allocation context details:");
-	ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: status %d flags %d",
+	ext4_msg(ac->ac_sb, KERN_ERR, "status %d flags %d",
 			ac->ac_status, ac->ac_flags);
-	ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: orig %lu/%lu/%lu@%lu, "
+	ext4_msg(ac->ac_sb, KERN_ERR, "orig %lu/%lu/%lu@%lu, "
 		 	"goal %lu/%lu/%lu@%lu, "
 			"best %lu/%lu/%lu@%lu cr %d",
 			(unsigned long)ac->ac_o_ex.fe_group,
@@ -3936,9 +3884,9 @@
 			(unsigned long)ac->ac_b_ex.fe_len,
 			(unsigned long)ac->ac_b_ex.fe_logical,
 			(int)ac->ac_criteria);
-	ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: %lu scanned, %d found",
+	ext4_msg(ac->ac_sb, KERN_ERR, "%lu scanned, %d found",
 		 ac->ac_ex_scanned, ac->ac_found);
-	ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: groups: ");
+	ext4_msg(ac->ac_sb, KERN_ERR, "groups: ");
 	ngroups = ext4_get_groups_count(sb);
 	for (i = 0; i < ngroups; i++) {
 		struct ext4_group_info *grp = ext4_get_group_info(sb, i);
@@ -4428,9 +4376,9 @@
 static int can_merge(struct ext4_free_data *entry1,
 			struct ext4_free_data *entry2)
 {
-	if ((entry1->t_tid == entry2->t_tid) &&
-	    (entry1->group == entry2->group) &&
-	    ((entry1->start_cluster + entry1->count) == entry2->start_cluster))
+	if ((entry1->efd_tid == entry2->efd_tid) &&
+	    (entry1->efd_group == entry2->efd_group) &&
+	    ((entry1->efd_start_cluster + entry1->efd_count) == entry2->efd_start_cluster))
 		return 1;
 	return 0;
 }
@@ -4452,8 +4400,8 @@
 	BUG_ON(e4b->bd_bitmap_page == NULL);
 	BUG_ON(e4b->bd_buddy_page == NULL);
 
-	new_node = &new_entry->node;
-	cluster = new_entry->start_cluster;
+	new_node = &new_entry->efd_node;
+	cluster = new_entry->efd_start_cluster;
 
 	if (!*n) {
 		/* first free block exent. We need to
@@ -4466,10 +4414,10 @@
 	}
 	while (*n) {
 		parent = *n;
-		entry = rb_entry(parent, struct ext4_free_data, node);
-		if (cluster < entry->start_cluster)
+		entry = rb_entry(parent, struct ext4_free_data, efd_node);
+		if (cluster < entry->efd_start_cluster)
 			n = &(*n)->rb_left;
-		else if (cluster >= (entry->start_cluster + entry->count))
+		else if (cluster >= (entry->efd_start_cluster + entry->efd_count))
 			n = &(*n)->rb_right;
 		else {
 			ext4_grp_locked_error(sb, group, 0,
@@ -4486,34 +4434,29 @@
 	/* Now try to see the extent can be merged to left and right */
 	node = rb_prev(new_node);
 	if (node) {
-		entry = rb_entry(node, struct ext4_free_data, node);
+		entry = rb_entry(node, struct ext4_free_data, efd_node);
 		if (can_merge(entry, new_entry)) {
-			new_entry->start_cluster = entry->start_cluster;
-			new_entry->count += entry->count;
+			new_entry->efd_start_cluster = entry->efd_start_cluster;
+			new_entry->efd_count += entry->efd_count;
 			rb_erase(node, &(db->bb_free_root));
-			spin_lock(&sbi->s_md_lock);
-			list_del(&entry->list);
-			spin_unlock(&sbi->s_md_lock);
-			kmem_cache_free(ext4_free_ext_cachep, entry);
+			ext4_journal_callback_del(handle, &entry->efd_jce);
+			kmem_cache_free(ext4_free_data_cachep, entry);
 		}
 	}
 
 	node = rb_next(new_node);
 	if (node) {
-		entry = rb_entry(node, struct ext4_free_data, node);
+		entry = rb_entry(node, struct ext4_free_data, efd_node);
 		if (can_merge(new_entry, entry)) {
-			new_entry->count += entry->count;
+			new_entry->efd_count += entry->efd_count;
 			rb_erase(node, &(db->bb_free_root));
-			spin_lock(&sbi->s_md_lock);
-			list_del(&entry->list);
-			spin_unlock(&sbi->s_md_lock);
-			kmem_cache_free(ext4_free_ext_cachep, entry);
+			ext4_journal_callback_del(handle, &entry->efd_jce);
+			kmem_cache_free(ext4_free_data_cachep, entry);
 		}
 	}
 	/* Add the extent to transaction's private list */
-	spin_lock(&sbi->s_md_lock);
-	list_add(&new_entry->list, &handle->h_transaction->t_private_list);
-	spin_unlock(&sbi->s_md_lock);
+	ext4_journal_callback_add(handle, ext4_free_data_callback,
+				  &new_entry->efd_jce);
 	return 0;
 }
 
@@ -4691,15 +4634,15 @@
 		 * blocks being freed are metadata. these blocks shouldn't
 		 * be used until this transaction is committed
 		 */
-		new_entry = kmem_cache_alloc(ext4_free_ext_cachep, GFP_NOFS);
+		new_entry = kmem_cache_alloc(ext4_free_data_cachep, GFP_NOFS);
 		if (!new_entry) {
 			err = -ENOMEM;
 			goto error_return;
 		}
-		new_entry->start_cluster = bit;
-		new_entry->group  = block_group;
-		new_entry->count = count_clusters;
-		new_entry->t_tid = handle->h_transaction->t_tid;
+		new_entry->efd_start_cluster = bit;
+		new_entry->efd_group = block_group;
+		new_entry->efd_count = count_clusters;
+		new_entry->efd_tid = handle->h_transaction->t_tid;
 
 		ext4_lock_group(sb, block_group);
 		mb_clear_bits(bitmap_bh->b_data, bit, count_clusters);
@@ -4971,11 +4914,11 @@
 	start = (e4b.bd_info->bb_first_free > start) ?
 		e4b.bd_info->bb_first_free : start;
 
-	while (start < max) {
-		start = mb_find_next_zero_bit(bitmap, max, start);
-		if (start >= max)
+	while (start <= max) {
+		start = mb_find_next_zero_bit(bitmap, max + 1, start);
+		if (start > max)
 			break;
-		next = mb_find_next_bit(bitmap, max, start);
+		next = mb_find_next_bit(bitmap, max + 1, start);
 
 		if ((next - start) >= minblocks) {
 			ext4_trim_extent(sb, start,
@@ -5027,37 +4970,36 @@
 int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
 {
 	struct ext4_group_info *grp;
-	ext4_group_t first_group, last_group;
-	ext4_group_t group, ngroups = ext4_get_groups_count(sb);
+	ext4_group_t group, first_group, last_group;
 	ext4_grpblk_t cnt = 0, first_cluster, last_cluster;
-	uint64_t start, len, minlen, trimmed = 0;
+	uint64_t start, end, minlen, trimmed = 0;
 	ext4_fsblk_t first_data_blk =
 			le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
+	ext4_fsblk_t max_blks = ext4_blocks_count(EXT4_SB(sb)->s_es);
 	int ret = 0;
 
 	start = range->start >> sb->s_blocksize_bits;
-	len = range->len >> sb->s_blocksize_bits;
+	end = start + (range->len >> sb->s_blocksize_bits) - 1;
 	minlen = range->minlen >> sb->s_blocksize_bits;
 
-	if (unlikely(minlen > EXT4_CLUSTERS_PER_GROUP(sb)))
+	if (unlikely(minlen > EXT4_CLUSTERS_PER_GROUP(sb)) ||
+	    unlikely(start >= max_blks))
 		return -EINVAL;
-	if (start + len <= first_data_blk)
+	if (end >= max_blks)
+		end = max_blks - 1;
+	if (end <= first_data_blk)
 		goto out;
-	if (start < first_data_blk) {
-		len -= first_data_blk - start;
+	if (start < first_data_blk)
 		start = first_data_blk;
-	}
 
-	/* Determine first and last group to examine based on start and len */
+	/* Determine first and last group to examine based on start and end */
 	ext4_get_group_no_and_offset(sb, (ext4_fsblk_t) start,
 				     &first_group, &first_cluster);
-	ext4_get_group_no_and_offset(sb, (ext4_fsblk_t) (start + len),
+	ext4_get_group_no_and_offset(sb, (ext4_fsblk_t) end,
 				     &last_group, &last_cluster);
-	last_group = (last_group > ngroups - 1) ? ngroups - 1 : last_group;
-	last_cluster = EXT4_CLUSTERS_PER_GROUP(sb);
 
-	if (first_group > last_group)
-		return -EINVAL;
+	/* end now represents the last cluster to discard in this group */
+	end = EXT4_CLUSTERS_PER_GROUP(sb) - 1;
 
 	for (group = first_group; group <= last_group; group++) {
 		grp = ext4_get_group_info(sb, group);
@@ -5069,31 +5011,35 @@
 		}
 
 		/*
-		 * For all the groups except the last one, last block will
-		 * always be EXT4_BLOCKS_PER_GROUP(sb), so we only need to
-		 * change it for the last group in which case start +
-		 * len < EXT4_BLOCKS_PER_GROUP(sb).
+		 * For all the groups except the last one, last cluster will
+		 * always be EXT4_CLUSTERS_PER_GROUP(sb)-1, so we only need to
+		 * change it for the last group, note that last_cluster is
+		 * already computed earlier by ext4_get_group_no_and_offset()
 		 */
-		if (first_cluster + len < EXT4_CLUSTERS_PER_GROUP(sb))
-			last_cluster = first_cluster + len;
-		len -= last_cluster - first_cluster;
+		if (group == last_group)
+			end = last_cluster;
 
 		if (grp->bb_free >= minlen) {
 			cnt = ext4_trim_all_free(sb, group, first_cluster,
-						last_cluster, minlen);
+						end, minlen);
 			if (cnt < 0) {
 				ret = cnt;
 				break;
 			}
+			trimmed += cnt;
 		}
-		trimmed += cnt;
+
+		/*
+		 * For every group except the first one, we are sure
+		 * that the first cluster to discard will be cluster #0.
+		 */
 		first_cluster = 0;
 	}
-	range->len = trimmed * sb->s_blocksize;
 
 	if (!ret)
 		atomic_set(&EXT4_SB(sb)->s_last_trim_minblks, minlen);
 
 out:
+	range->len = trimmed * sb->s_blocksize;
 	return ret;
 }
diff --git a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h
index 47705f3..c070618 100644
--- a/fs/ext4/mballoc.h
+++ b/fs/ext4/mballoc.h
@@ -96,21 +96,23 @@
 
 
 struct ext4_free_data {
-	/* this links the free block information from group_info */
-	struct rb_node node;
+	/* MUST be the first member */
+	struct ext4_journal_cb_entry	efd_jce;
 
-	/* this links the free block information from ext4_sb_info */
-	struct list_head list;
+	/* ext4_free_data private data starts from here */
+
+	/* this links the free block information from group_info */
+	struct rb_node			efd_node;
 
 	/* group which free block extent belongs */
-	ext4_group_t group;
+	ext4_group_t			efd_group;
 
 	/* free block extent */
-	ext4_grpblk_t start_cluster;
-	ext4_grpblk_t count;
+	ext4_grpblk_t			efd_start_cluster;
+	ext4_grpblk_t			efd_count;
 
 	/* transaction which freed this extent */
-	tid_t	t_tid;
+	tid_t				efd_tid;
 };
 
 struct ext4_prealloc_space {
@@ -210,8 +212,6 @@
 	__u16 bd_blkbits;
 	ext4_group_t bd_group;
 };
-#define EXT4_MB_BITMAP(e4b)	((e4b)->bd_bitmap)
-#define EXT4_MB_BUDDY(e4b)	((e4b)->bd_buddy)
 
 static inline ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb,
 					struct ext4_free_extent *fex)
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
index e7d6bb0..f39f80f 100644
--- a/fs/ext4/migrate.c
+++ b/fs/ext4/migrate.c
@@ -471,7 +471,7 @@
 	tmp_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode,
 				   S_IFREG, NULL, goal, owner);
 	if (IS_ERR(tmp_inode)) {
-		retval = PTR_ERR(inode);
+		retval = PTR_ERR(tmp_inode);
 		ext4_journal_stop(handle);
 		return retval;
 	}
diff --git a/fs/ext4/mmp.c b/fs/ext4/mmp.c
index 7ea4ba4..ed6548d 100644
--- a/fs/ext4/mmp.c
+++ b/fs/ext4/mmp.c
@@ -257,8 +257,8 @@
 	 * If check_interval in MMP block is larger, use that instead of
 	 * update_interval from the superblock.
 	 */
-	if (mmp->mmp_check_interval > mmp_check_interval)
-		mmp_check_interval = mmp->mmp_check_interval;
+	if (le16_to_cpu(mmp->mmp_check_interval) > mmp_check_interval)
+		mmp_check_interval = le16_to_cpu(mmp->mmp_check_interval);
 
 	seq = le32_to_cpu(mmp->mmp_seq);
 	if (seq == EXT4_MMP_SEQ_CLEAN)
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 2043f48..349d7b3 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -468,7 +468,7 @@
 fail:
 	if (*err == ERR_BAD_DX_DIR)
 		ext4_warning(dir->i_sb,
-			     "Corrupt dir inode %ld, running e2fsck is "
+			     "Corrupt dir inode %lu, running e2fsck is "
 			     "recommended.", dir->i_ino);
 	return NULL;
 }
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 4758518..dcdeef1 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -110,6 +110,8 @@
 	if (io->iocb)
 		aio_complete(io->iocb, io->result, 0);
 
+	if (io->flag & EXT4_IO_END_DIRECT)
+		inode_dio_done(inode);
 	/* Wake up anyone waiting on unwritten extent conversion */
 	if (atomic_dec_and_test(&EXT4_I(inode)->i_aiodio_unwritten))
 		wake_up_all(ext4_ioend_wq(io->inode));
@@ -127,12 +129,18 @@
 	unsigned long		flags;
 
 	spin_lock_irqsave(&ei->i_completed_io_lock, flags);
+	if (io->flag & EXT4_IO_END_IN_FSYNC)
+		goto requeue;
 	if (list_empty(&io->list)) {
 		spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
 		goto free;
 	}
 
 	if (!mutex_trylock(&inode->i_mutex)) {
+		bool was_queued;
+requeue:
+		was_queued = !!(io->flag & EXT4_IO_END_QUEUED);
+		io->flag |= EXT4_IO_END_QUEUED;
 		spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
 		/*
 		 * Requeue the work instead of waiting so that the work
@@ -145,9 +153,8 @@
 		 * yield the cpu if it sees an end_io request that has already
 		 * been requeued.
 		 */
-		if (io->flag & EXT4_IO_END_QUEUED)
+		if (was_queued)
 			yield();
-		io->flag |= EXT4_IO_END_QUEUED;
 		return;
 	}
 	list_del_init(&io->list);
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index f9d948f..59fa0be 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -1163,8 +1163,11 @@
 	do_div(reserved_blocks, 100);
 
 	ext4_blocks_count_set(es, ext4_blocks_count(es) + blocks_count);
+	ext4_free_blocks_count_set(es, ext4_free_blocks_count(es) + free_blocks);
 	le32_add_cpu(&es->s_inodes_count, EXT4_INODES_PER_GROUP(sb) *
 		     flex_gd->count);
+	le32_add_cpu(&es->s_free_inodes_count, EXT4_INODES_PER_GROUP(sb) *
+		     flex_gd->count);
 
 	/*
 	 * We need to protect s_groups_count against other CPUs seeing
@@ -1465,6 +1468,7 @@
 	}
 
 	ext4_blocks_count_set(es, o_blocks_count + add);
+	ext4_free_blocks_count_set(es, ext4_free_blocks_count(es) + add);
 	ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count,
 		   o_blocks_count + add);
 	/* We add the blocks to the bitmap and set the group need init bit */
@@ -1512,16 +1516,17 @@
 	o_blocks_count = ext4_blocks_count(es);
 
 	if (test_opt(sb, DEBUG))
-		printk(KERN_DEBUG "EXT4-fs: extending last group from %llu to %llu blocks\n",
-		       o_blocks_count, n_blocks_count);
+		ext4_msg(sb, KERN_DEBUG,
+			 "extending last group from %llu to %llu blocks",
+			 o_blocks_count, n_blocks_count);
 
 	if (n_blocks_count == 0 || n_blocks_count == o_blocks_count)
 		return 0;
 
 	if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
-		printk(KERN_ERR "EXT4-fs: filesystem on %s:"
-			" too large to resize to %llu blocks safely\n",
-			sb->s_id, n_blocks_count);
+		ext4_msg(sb, KERN_ERR,
+			 "filesystem too large to resize to %llu blocks safely",
+			 n_blocks_count);
 		if (sizeof(sector_t) < 8)
 			ext4_warning(sb, "CONFIG_LBDAF not enabled");
 		return -EINVAL;
@@ -1582,7 +1587,7 @@
 	ext4_fsblk_t o_blocks_count;
 	ext4_group_t o_group;
 	ext4_group_t n_group;
-	ext4_grpblk_t offset;
+	ext4_grpblk_t offset, add;
 	unsigned long n_desc_blocks;
 	unsigned long o_desc_blocks;
 	unsigned long desc_blocks;
@@ -1591,8 +1596,8 @@
 	o_blocks_count = ext4_blocks_count(es);
 
 	if (test_opt(sb, DEBUG))
-		printk(KERN_DEBUG "EXT4-fs: resizing filesystem from %llu "
-		       "upto %llu blocks\n", o_blocks_count, n_blocks_count);
+		ext4_msg(sb, KERN_DEBUG, "resizing filesystem from %llu "
+		       "to %llu blocks", o_blocks_count, n_blocks_count);
 
 	if (n_blocks_count < o_blocks_count) {
 		/* On-line shrinking not supported */
@@ -1605,7 +1610,7 @@
 		return 0;
 
 	ext4_get_group_no_and_offset(sb, n_blocks_count - 1, &n_group, &offset);
-	ext4_get_group_no_and_offset(sb, o_blocks_count, &o_group, &offset);
+	ext4_get_group_no_and_offset(sb, o_blocks_count - 1, &o_group, &offset);
 
 	n_desc_blocks = (n_group + EXT4_DESC_PER_BLOCK(sb)) /
 			EXT4_DESC_PER_BLOCK(sb);
@@ -1634,10 +1639,12 @@
 	}
 	brelse(bh);
 
-	if (offset != 0) {
-		/* extend the last group */
-		ext4_grpblk_t add;
-		add = EXT4_BLOCKS_PER_GROUP(sb) - offset;
+	/* extend the last group */
+	if (n_group == o_group)
+		add = n_blocks_count - o_blocks_count;
+	else
+		add = EXT4_BLOCKS_PER_GROUP(sb) - (offset + 1);
+	if (add > 0) {
 		err = ext4_group_extend_no_check(sb, o_blocks_count, add);
 		if (err)
 			goto out;
@@ -1674,7 +1681,7 @@
 
 	iput(resize_inode);
 	if (test_opt(sb, DEBUG))
-		printk(KERN_DEBUG "EXT4-fs: resized filesystem from %llu "
-		       "upto %llu blocks\n", o_blocks_count, n_blocks_count);
+		ext4_msg(sb, KERN_DEBUG, "resized filesystem from %llu "
+		       "upto %llu blocks", o_blocks_count, n_blocks_count);
 	return err;
 }
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 502c61f..ceebaf8 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -62,6 +62,7 @@
 
 static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
 			     unsigned long journal_devnum);
+static int ext4_show_options(struct seq_file *seq, struct dentry *root);
 static int ext4_commit_super(struct super_block *sb, int sync);
 static void ext4_mark_recovery_complete(struct super_block *sb,
 					struct ext4_super_block *es);
@@ -375,7 +376,7 @@
 	if (is_handle_aborted(handle))
 		return;
 
-	printk(KERN_ERR "%s:%d: aborting transaction: %s in %s\n",
+	printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n",
 	       caller, line, errstr, err_fn);
 
 	jbd2_journal_abort_handle(handle);
@@ -431,6 +432,22 @@
 	return bdi->dev == NULL;
 }
 
+static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn)
+{
+	struct super_block		*sb = journal->j_private;
+	struct ext4_sb_info		*sbi = EXT4_SB(sb);
+	int				error = is_journal_aborted(journal);
+	struct ext4_journal_cb_entry	*jce, *tmp;
+
+	spin_lock(&sbi->s_md_lock);
+	list_for_each_entry_safe(jce, tmp, &txn->t_private_list, jce_list) {
+		list_del_init(&jce->jce_list);
+		spin_unlock(&sbi->s_md_lock);
+		jce->jce_func(sb, jce, error);
+		spin_lock(&sbi->s_md_lock);
+	}
+	spin_unlock(&sbi->s_md_lock);
+}
 
 /* Deal with the reporting of failure conditions on a filesystem such as
  * inconsistencies detected or read IO failures.
@@ -498,11 +515,16 @@
 	va_start(args, fmt);
 	vaf.fmt = fmt;
 	vaf.va = &args;
-	printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: inode #%lu: ",
-	       inode->i_sb->s_id, function, line, inode->i_ino);
 	if (block)
-		printk(KERN_CONT "block %llu: ", block);
-	printk(KERN_CONT "comm %s: %pV\n", current->comm, &vaf);
+		printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: "
+		       "inode #%lu: block %llu: comm %s: %pV\n",
+		       inode->i_sb->s_id, function, line, inode->i_ino,
+		       block, current->comm, &vaf);
+	else
+		printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: "
+		       "inode #%lu: comm %s: %pV\n",
+		       inode->i_sb->s_id, function, line, inode->i_ino,
+		       current->comm, &vaf);
 	va_end(args);
 
 	ext4_handle_error(inode->i_sb);
@@ -524,15 +546,21 @@
 	path = d_path(&(file->f_path), pathname, sizeof(pathname));
 	if (IS_ERR(path))
 		path = "(unknown)";
-	printk(KERN_CRIT
-	       "EXT4-fs error (device %s): %s:%d: inode #%lu: ",
-	       inode->i_sb->s_id, function, line, inode->i_ino);
-	if (block)
-		printk(KERN_CONT "block %llu: ", block);
 	va_start(args, fmt);
 	vaf.fmt = fmt;
 	vaf.va = &args;
-	printk(KERN_CONT "comm %s: path %s: %pV\n", current->comm, path, &vaf);
+	if (block)
+		printk(KERN_CRIT
+		       "EXT4-fs error (device %s): %s:%d: inode #%lu: "
+		       "block %llu: comm %s: path %s: %pV\n",
+		       inode->i_sb->s_id, function, line, inode->i_ino,
+		       block, current->comm, path, &vaf);
+	else
+		printk(KERN_CRIT
+		       "EXT4-fs error (device %s): %s:%d: inode #%lu: "
+		       "comm %s: path %s: %pV\n",
+		       inode->i_sb->s_id, function, line, inode->i_ino,
+		       current->comm, path, &vaf);
 	va_end(args);
 
 	ext4_handle_error(inode->i_sb);
@@ -808,9 +836,6 @@
 	destroy_workqueue(sbi->dio_unwritten_wq);
 
 	lock_super(sb);
-	if (sb->s_dirt)
-		ext4_commit_super(sb, 1);
-
 	if (sbi->s_journal) {
 		err = jbd2_journal_destroy(sbi->s_journal);
 		sbi->s_journal = NULL;
@@ -827,9 +852,12 @@
 	if (!(sb->s_flags & MS_RDONLY)) {
 		EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
 		es->s_state = cpu_to_le16(sbi->s_mount_state);
-		ext4_commit_super(sb, 1);
 	}
+	if (sb->s_dirt || !(sb->s_flags & MS_RDONLY))
+		ext4_commit_super(sb, 1);
+
 	if (sbi->s_proc) {
+		remove_proc_entry("options", sbi->s_proc);
 		remove_proc_entry(sb->s_id, ext4_proc_root);
 	}
 	kobject_del(&sbi->s_kobj);
@@ -990,180 +1018,6 @@
 	}
 }
 
-static inline void ext4_show_quota_options(struct seq_file *seq,
-					   struct super_block *sb)
-{
-#if defined(CONFIG_QUOTA)
-	struct ext4_sb_info *sbi = EXT4_SB(sb);
-
-	if (sbi->s_jquota_fmt) {
-		char *fmtname = "";
-
-		switch (sbi->s_jquota_fmt) {
-		case QFMT_VFS_OLD:
-			fmtname = "vfsold";
-			break;
-		case QFMT_VFS_V0:
-			fmtname = "vfsv0";
-			break;
-		case QFMT_VFS_V1:
-			fmtname = "vfsv1";
-			break;
-		}
-		seq_printf(seq, ",jqfmt=%s", fmtname);
-	}
-
-	if (sbi->s_qf_names[USRQUOTA])
-		seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]);
-
-	if (sbi->s_qf_names[GRPQUOTA])
-		seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
-
-	if (test_opt(sb, USRQUOTA))
-		seq_puts(seq, ",usrquota");
-
-	if (test_opt(sb, GRPQUOTA))
-		seq_puts(seq, ",grpquota");
-#endif
-}
-
-/*
- * Show an option if
- *  - it's set to a non-default value OR
- *  - if the per-sb default is different from the global default
- */
-static int ext4_show_options(struct seq_file *seq, struct dentry *root)
-{
-	int def_errors;
-	unsigned long def_mount_opts;
-	struct super_block *sb = root->d_sb;
-	struct ext4_sb_info *sbi = EXT4_SB(sb);
-	struct ext4_super_block *es = sbi->s_es;
-
-	def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
-	def_errors     = le16_to_cpu(es->s_errors);
-
-	if (sbi->s_sb_block != 1)
-		seq_printf(seq, ",sb=%llu", sbi->s_sb_block);
-	if (test_opt(sb, MINIX_DF))
-		seq_puts(seq, ",minixdf");
-	if (test_opt(sb, GRPID) && !(def_mount_opts & EXT4_DEFM_BSDGROUPS))
-		seq_puts(seq, ",grpid");
-	if (!test_opt(sb, GRPID) && (def_mount_opts & EXT4_DEFM_BSDGROUPS))
-		seq_puts(seq, ",nogrpid");
-	if (sbi->s_resuid != EXT4_DEF_RESUID ||
-	    le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID) {
-		seq_printf(seq, ",resuid=%u", sbi->s_resuid);
-	}
-	if (sbi->s_resgid != EXT4_DEF_RESGID ||
-	    le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID) {
-		seq_printf(seq, ",resgid=%u", sbi->s_resgid);
-	}
-	if (test_opt(sb, ERRORS_RO)) {
-		if (def_errors == EXT4_ERRORS_PANIC ||
-		    def_errors == EXT4_ERRORS_CONTINUE) {
-			seq_puts(seq, ",errors=remount-ro");
-		}
-	}
-	if (test_opt(sb, ERRORS_CONT) && def_errors != EXT4_ERRORS_CONTINUE)
-		seq_puts(seq, ",errors=continue");
-	if (test_opt(sb, ERRORS_PANIC) && def_errors != EXT4_ERRORS_PANIC)
-		seq_puts(seq, ",errors=panic");
-	if (test_opt(sb, NO_UID32) && !(def_mount_opts & EXT4_DEFM_UID16))
-		seq_puts(seq, ",nouid32");
-	if (test_opt(sb, DEBUG) && !(def_mount_opts & EXT4_DEFM_DEBUG))
-		seq_puts(seq, ",debug");
-#ifdef CONFIG_EXT4_FS_XATTR
-	if (test_opt(sb, XATTR_USER))
-		seq_puts(seq, ",user_xattr");
-	if (!test_opt(sb, XATTR_USER))
-		seq_puts(seq, ",nouser_xattr");
-#endif
-#ifdef CONFIG_EXT4_FS_POSIX_ACL
-	if (test_opt(sb, POSIX_ACL) && !(def_mount_opts & EXT4_DEFM_ACL))
-		seq_puts(seq, ",acl");
-	if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT4_DEFM_ACL))
-		seq_puts(seq, ",noacl");
-#endif
-	if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) {
-		seq_printf(seq, ",commit=%u",
-			   (unsigned) (sbi->s_commit_interval / HZ));
-	}
-	if (sbi->s_min_batch_time != EXT4_DEF_MIN_BATCH_TIME) {
-		seq_printf(seq, ",min_batch_time=%u",
-			   (unsigned) sbi->s_min_batch_time);
-	}
-	if (sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME) {
-		seq_printf(seq, ",max_batch_time=%u",
-			   (unsigned) sbi->s_max_batch_time);
-	}
-
-	/*
-	 * We're changing the default of barrier mount option, so
-	 * let's always display its mount state so it's clear what its
-	 * status is.
-	 */
-	seq_puts(seq, ",barrier=");
-	seq_puts(seq, test_opt(sb, BARRIER) ? "1" : "0");
-	if (test_opt(sb, JOURNAL_ASYNC_COMMIT))
-		seq_puts(seq, ",journal_async_commit");
-	else if (test_opt(sb, JOURNAL_CHECKSUM))
-		seq_puts(seq, ",journal_checksum");
-	if (test_opt(sb, I_VERSION))
-		seq_puts(seq, ",i_version");
-	if (!test_opt(sb, DELALLOC) &&
-	    !(def_mount_opts & EXT4_DEFM_NODELALLOC))
-		seq_puts(seq, ",nodelalloc");
-
-	if (!test_opt(sb, MBLK_IO_SUBMIT))
-		seq_puts(seq, ",nomblk_io_submit");
-	if (sbi->s_stripe)
-		seq_printf(seq, ",stripe=%lu", sbi->s_stripe);
-	/*
-	 * journal mode get enabled in different ways
-	 * So just print the value even if we didn't specify it
-	 */
-	if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
-		seq_puts(seq, ",data=journal");
-	else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
-		seq_puts(seq, ",data=ordered");
-	else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
-		seq_puts(seq, ",data=writeback");
-
-	if (sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS)
-		seq_printf(seq, ",inode_readahead_blks=%u",
-			   sbi->s_inode_readahead_blks);
-
-	if (test_opt(sb, DATA_ERR_ABORT))
-		seq_puts(seq, ",data_err=abort");
-
-	if (test_opt(sb, NO_AUTO_DA_ALLOC))
-		seq_puts(seq, ",noauto_da_alloc");
-
-	if (test_opt(sb, DISCARD) && !(def_mount_opts & EXT4_DEFM_DISCARD))
-		seq_puts(seq, ",discard");
-
-	if (test_opt(sb, NOLOAD))
-		seq_puts(seq, ",norecovery");
-
-	if (test_opt(sb, DIOREAD_NOLOCK))
-		seq_puts(seq, ",dioread_nolock");
-
-	if (test_opt(sb, BLOCK_VALIDITY) &&
-	    !(def_mount_opts & EXT4_DEFM_BLOCK_VALIDITY))
-		seq_puts(seq, ",block_validity");
-
-	if (!test_opt(sb, INIT_INODE_TABLE))
-		seq_puts(seq, ",noinit_itable");
-	else if (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT)
-		seq_printf(seq, ",init_itable=%u",
-			   (unsigned) sbi->s_li_wait_mult);
-
-	ext4_show_quota_options(seq, sb);
-
-	return 0;
-}
-
 static struct inode *ext4_nfs_get_inode(struct super_block *sb,
 					u64 ino, u32 generation)
 {
@@ -1316,18 +1170,17 @@
 enum {
 	Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
 	Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
-	Opt_nouid32, Opt_debug, Opt_oldalloc, Opt_orlov,
+	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_nobh, Opt_bh,
+	Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload,
 	Opt_commit, Opt_min_batch_time, Opt_max_batch_time,
-	Opt_journal_update, Opt_journal_dev,
-	Opt_journal_checksum, Opt_journal_async_commit,
+	Opt_journal_dev, 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,
 	Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
-	Opt_noquota, Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err,
-	Opt_resize, Opt_usrquota, Opt_grpquota, Opt_i_version,
+	Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
+	Opt_usrquota, Opt_grpquota, Opt_i_version,
 	Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit,
 	Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
 	Opt_inode_readahead_blks, Opt_journal_ioprio,
@@ -1350,20 +1203,19 @@
 	{Opt_err_ro, "errors=remount-ro"},
 	{Opt_nouid32, "nouid32"},
 	{Opt_debug, "debug"},
-	{Opt_oldalloc, "oldalloc"},
-	{Opt_orlov, "orlov"},
+	{Opt_removed, "oldalloc"},
+	{Opt_removed, "orlov"},
 	{Opt_user_xattr, "user_xattr"},
 	{Opt_nouser_xattr, "nouser_xattr"},
 	{Opt_acl, "acl"},
 	{Opt_noacl, "noacl"},
-	{Opt_noload, "noload"},
 	{Opt_noload, "norecovery"},
-	{Opt_nobh, "nobh"},
-	{Opt_bh, "bh"},
+	{Opt_noload, "noload"},
+	{Opt_removed, "nobh"},
+	{Opt_removed, "bh"},
 	{Opt_commit, "commit=%u"},
 	{Opt_min_batch_time, "min_batch_time=%u"},
 	{Opt_max_batch_time, "max_batch_time=%u"},
-	{Opt_journal_update, "journal=update"},
 	{Opt_journal_dev, "journal_dev=%u"},
 	{Opt_journal_checksum, "journal_checksum"},
 	{Opt_journal_async_commit, "journal_async_commit"},
@@ -1389,7 +1241,6 @@
 	{Opt_nobarrier, "nobarrier"},
 	{Opt_i_version, "i_version"},
 	{Opt_stripe, "stripe=%u"},
-	{Opt_resize, "resize"},
 	{Opt_delalloc, "delalloc"},
 	{Opt_nodelalloc, "nodelalloc"},
 	{Opt_mblk_io_submit, "mblk_io_submit"},
@@ -1408,6 +1259,11 @@
 	{Opt_init_itable, "init_itable=%u"},
 	{Opt_init_itable, "init_itable"},
 	{Opt_noinit_itable, "noinit_itable"},
+	{Opt_removed, "check=none"},	/* mount option from ext2/3 */
+	{Opt_removed, "nocheck"},	/* mount option from ext2/3 */
+	{Opt_removed, "reservation"},	/* mount option from ext2/3 */
+	{Opt_removed, "noreservation"}, /* mount option from ext2/3 */
+	{Opt_removed, "journal=%u"},	/* mount option from ext2/3 */
 	{Opt_err, NULL},
 };
 
@@ -1496,420 +1352,273 @@
 }
 #endif
 
+#define MOPT_SET	0x0001
+#define MOPT_CLEAR	0x0002
+#define MOPT_NOSUPPORT	0x0004
+#define MOPT_EXPLICIT	0x0008
+#define MOPT_CLEAR_ERR	0x0010
+#define MOPT_GTE0	0x0020
+#ifdef CONFIG_QUOTA
+#define MOPT_Q		0
+#define MOPT_QFMT	0x0040
+#else
+#define MOPT_Q		MOPT_NOSUPPORT
+#define MOPT_QFMT	MOPT_NOSUPPORT
+#endif
+#define MOPT_DATAJ	0x0080
+
+static const struct mount_opts {
+	int	token;
+	int	mount_opt;
+	int	flags;
+} ext4_mount_opts[] = {
+	{Opt_minix_df, EXT4_MOUNT_MINIX_DF, MOPT_SET},
+	{Opt_bsd_df, EXT4_MOUNT_MINIX_DF, MOPT_CLEAR},
+	{Opt_grpid, EXT4_MOUNT_GRPID, MOPT_SET},
+	{Opt_nogrpid, EXT4_MOUNT_GRPID, MOPT_CLEAR},
+	{Opt_mblk_io_submit, EXT4_MOUNT_MBLK_IO_SUBMIT, MOPT_SET},
+	{Opt_nomblk_io_submit, EXT4_MOUNT_MBLK_IO_SUBMIT, MOPT_CLEAR},
+	{Opt_block_validity, EXT4_MOUNT_BLOCK_VALIDITY, MOPT_SET},
+	{Opt_noblock_validity, EXT4_MOUNT_BLOCK_VALIDITY, MOPT_CLEAR},
+	{Opt_dioread_nolock, EXT4_MOUNT_DIOREAD_NOLOCK, MOPT_SET},
+	{Opt_dioread_lock, EXT4_MOUNT_DIOREAD_NOLOCK, MOPT_CLEAR},
+	{Opt_discard, EXT4_MOUNT_DISCARD, MOPT_SET},
+	{Opt_nodiscard, EXT4_MOUNT_DISCARD, MOPT_CLEAR},
+	{Opt_delalloc, EXT4_MOUNT_DELALLOC, MOPT_SET | MOPT_EXPLICIT},
+	{Opt_nodelalloc, EXT4_MOUNT_DELALLOC, MOPT_CLEAR | MOPT_EXPLICIT},
+	{Opt_journal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM, MOPT_SET},
+	{Opt_journal_async_commit, (EXT4_MOUNT_JOURNAL_ASYNC_COMMIT |
+				    EXT4_MOUNT_JOURNAL_CHECKSUM), MOPT_SET},
+	{Opt_noload, EXT4_MOUNT_NOLOAD, MOPT_SET},
+	{Opt_err_panic, EXT4_MOUNT_ERRORS_PANIC, MOPT_SET | MOPT_CLEAR_ERR},
+	{Opt_err_ro, EXT4_MOUNT_ERRORS_RO, MOPT_SET | MOPT_CLEAR_ERR},
+	{Opt_err_cont, EXT4_MOUNT_ERRORS_CONT, MOPT_SET | MOPT_CLEAR_ERR},
+	{Opt_data_err_abort, EXT4_MOUNT_DATA_ERR_ABORT, MOPT_SET},
+	{Opt_data_err_ignore, EXT4_MOUNT_DATA_ERR_ABORT, MOPT_CLEAR},
+	{Opt_barrier, EXT4_MOUNT_BARRIER, MOPT_SET},
+	{Opt_nobarrier, EXT4_MOUNT_BARRIER, MOPT_CLEAR},
+	{Opt_noauto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_SET},
+	{Opt_auto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_CLEAR},
+	{Opt_noinit_itable, EXT4_MOUNT_INIT_INODE_TABLE, MOPT_CLEAR},
+	{Opt_commit, 0, MOPT_GTE0},
+	{Opt_max_batch_time, 0, MOPT_GTE0},
+	{Opt_min_batch_time, 0, MOPT_GTE0},
+	{Opt_inode_readahead_blks, 0, MOPT_GTE0},
+	{Opt_init_itable, 0, MOPT_GTE0},
+	{Opt_stripe, 0, MOPT_GTE0},
+	{Opt_data_journal, EXT4_MOUNT_JOURNAL_DATA, MOPT_DATAJ},
+	{Opt_data_ordered, EXT4_MOUNT_ORDERED_DATA, MOPT_DATAJ},
+	{Opt_data_writeback, EXT4_MOUNT_WRITEBACK_DATA, MOPT_DATAJ},
+#ifdef CONFIG_EXT4_FS_XATTR
+	{Opt_user_xattr, EXT4_MOUNT_XATTR_USER, MOPT_SET},
+	{Opt_nouser_xattr, EXT4_MOUNT_XATTR_USER, MOPT_CLEAR},
+#else
+	{Opt_user_xattr, 0, MOPT_NOSUPPORT},
+	{Opt_nouser_xattr, 0, MOPT_NOSUPPORT},
+#endif
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
+	{Opt_acl, EXT4_MOUNT_POSIX_ACL, MOPT_SET},
+	{Opt_noacl, EXT4_MOUNT_POSIX_ACL, MOPT_CLEAR},
+#else
+	{Opt_acl, 0, MOPT_NOSUPPORT},
+	{Opt_noacl, 0, MOPT_NOSUPPORT},
+#endif
+	{Opt_nouid32, EXT4_MOUNT_NO_UID32, MOPT_SET},
+	{Opt_debug, EXT4_MOUNT_DEBUG, MOPT_SET},
+	{Opt_quota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA, MOPT_SET | MOPT_Q},
+	{Opt_usrquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA,
+							MOPT_SET | MOPT_Q},
+	{Opt_grpquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_GRPQUOTA,
+							MOPT_SET | MOPT_Q},
+	{Opt_noquota, (EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA |
+		       EXT4_MOUNT_GRPQUOTA), MOPT_CLEAR | MOPT_Q},
+	{Opt_usrjquota, 0, MOPT_Q},
+	{Opt_grpjquota, 0, MOPT_Q},
+	{Opt_offusrjquota, 0, MOPT_Q},
+	{Opt_offgrpjquota, 0, MOPT_Q},
+	{Opt_jqfmt_vfsold, QFMT_VFS_OLD, MOPT_QFMT},
+	{Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT},
+	{Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT},
+	{Opt_err, 0, 0}
+};
+
+static int handle_mount_opt(struct super_block *sb, char *opt, int token,
+			    substring_t *args, unsigned long *journal_devnum,
+			    unsigned int *journal_ioprio, int is_remount)
+{
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
+	const struct mount_opts *m;
+	int arg = 0;
+
+	if (args->from && match_int(args, &arg))
+		return -1;
+	switch (token) {
+	case Opt_noacl:
+	case Opt_nouser_xattr:
+		ext4_msg(sb, KERN_WARNING, deprecated_msg, opt, "3.5");
+		break;
+	case Opt_sb:
+		return 1;	/* handled by get_sb_block() */
+	case Opt_removed:
+		ext4_msg(sb, KERN_WARNING,
+			 "Ignoring removed %s option", opt);
+		return 1;
+	case Opt_resuid:
+		sbi->s_resuid = arg;
+		return 1;
+	case Opt_resgid:
+		sbi->s_resgid = arg;
+		return 1;
+	case Opt_abort:
+		sbi->s_mount_flags |= EXT4_MF_FS_ABORTED;
+		return 1;
+	case Opt_i_version:
+		sb->s_flags |= MS_I_VERSION;
+		return 1;
+	case Opt_journal_dev:
+		if (is_remount) {
+			ext4_msg(sb, KERN_ERR,
+				 "Cannot specify journal on remount");
+			return -1;
+		}
+		*journal_devnum = arg;
+		return 1;
+	case Opt_journal_ioprio:
+		if (arg < 0 || arg > 7)
+			return -1;
+		*journal_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, arg);
+		return 1;
+	}
+
+	for (m = ext4_mount_opts; m->token != Opt_err; m++) {
+		if (token != m->token)
+			continue;
+		if (args->from && (m->flags & MOPT_GTE0) && (arg < 0))
+			return -1;
+		if (m->flags & MOPT_EXPLICIT)
+			set_opt2(sb, EXPLICIT_DELALLOC);
+		if (m->flags & MOPT_CLEAR_ERR)
+			clear_opt(sb, ERRORS_MASK);
+		if (token == Opt_noquota && sb_any_quota_loaded(sb)) {
+			ext4_msg(sb, KERN_ERR, "Cannot change quota "
+				 "options when quota turned on");
+			return -1;
+		}
+
+		if (m->flags & MOPT_NOSUPPORT) {
+			ext4_msg(sb, KERN_ERR, "%s option not supported", opt);
+		} else if (token == Opt_commit) {
+			if (arg == 0)
+				arg = JBD2_DEFAULT_MAX_COMMIT_AGE;
+			sbi->s_commit_interval = HZ * arg;
+		} else if (token == Opt_max_batch_time) {
+			if (arg == 0)
+				arg = EXT4_DEF_MAX_BATCH_TIME;
+			sbi->s_max_batch_time = arg;
+		} else if (token == Opt_min_batch_time) {
+			sbi->s_min_batch_time = arg;
+		} else if (token == Opt_inode_readahead_blks) {
+			if (arg > (1 << 30))
+				return -1;
+			if (arg && !is_power_of_2(arg)) {
+				ext4_msg(sb, KERN_ERR,
+					 "EXT4-fs: inode_readahead_blks"
+					 " must be a power of 2");
+				return -1;
+			}
+			sbi->s_inode_readahead_blks = arg;
+		} else if (token == Opt_init_itable) {
+			set_opt(sb, INIT_INODE_TABLE);
+			if (!args->from)
+				arg = EXT4_DEF_LI_WAIT_MULT;
+			sbi->s_li_wait_mult = arg;
+		} else if (token == Opt_stripe) {
+			sbi->s_stripe = arg;
+		} else if (m->flags & MOPT_DATAJ) {
+			if (is_remount) {
+				if (!sbi->s_journal)
+					ext4_msg(sb, KERN_WARNING, "Remounting file system with no journal so ignoring journalled data option");
+				else if (test_opt(sb, DATA_FLAGS) !=
+					 m->mount_opt) {
+					ext4_msg(sb, KERN_ERR,
+					 "Cannot change data mode on remount");
+					return -1;
+				}
+			} else {
+				clear_opt(sb, DATA_FLAGS);
+				sbi->s_mount_opt |= m->mount_opt;
+			}
+#ifdef CONFIG_QUOTA
+		} else if (token == Opt_usrjquota) {
+			if (!set_qf_name(sb, USRQUOTA, &args[0]))
+				return -1;
+		} else if (token == Opt_grpjquota) {
+			if (!set_qf_name(sb, GRPQUOTA, &args[0]))
+				return -1;
+		} else if (token == Opt_offusrjquota) {
+			if (!clear_qf_name(sb, USRQUOTA))
+				return -1;
+		} else if (token == Opt_offgrpjquota) {
+			if (!clear_qf_name(sb, GRPQUOTA))
+				return -1;
+		} else if (m->flags & MOPT_QFMT) {
+			if (sb_any_quota_loaded(sb) &&
+			    sbi->s_jquota_fmt != m->mount_opt) {
+				ext4_msg(sb, KERN_ERR, "Cannot "
+					 "change journaled quota options "
+					 "when quota turned on");
+				return -1;
+			}
+			sbi->s_jquota_fmt = m->mount_opt;
+#endif
+		} else {
+			if (!args->from)
+				arg = 1;
+			if (m->flags & MOPT_CLEAR)
+				arg = !arg;
+			else if (unlikely(!(m->flags & MOPT_SET))) {
+				ext4_msg(sb, KERN_WARNING,
+					 "buggy handling of option %s", opt);
+				WARN_ON(1);
+				return -1;
+			}
+			if (arg != 0)
+				sbi->s_mount_opt |= m->mount_opt;
+			else
+				sbi->s_mount_opt &= ~m->mount_opt;
+		}
+		return 1;
+	}
+	ext4_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" "
+		 "or missing value", opt);
+	return -1;
+}
+
 static int parse_options(char *options, struct super_block *sb,
 			 unsigned long *journal_devnum,
 			 unsigned int *journal_ioprio,
-			 ext4_fsblk_t *n_blocks_count, int is_remount)
+			 int is_remount)
 {
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	char *p;
 	substring_t args[MAX_OPT_ARGS];
-	int data_opt = 0;
-	int option;
-#ifdef CONFIG_QUOTA
-	int qfmt;
-#endif
+	int token;
 
 	if (!options)
 		return 1;
 
 	while ((p = strsep(&options, ",")) != NULL) {
-		int token;
 		if (!*p)
 			continue;
-
 		/*
 		 * Initialize args struct so we know whether arg was
 		 * found; some options take optional arguments.
 		 */
-		args[0].to = args[0].from = NULL;
+		args[0].to = args[0].from = 0;
 		token = match_token(p, tokens, args);
-		switch (token) {
-		case Opt_bsd_df:
-			ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
-			clear_opt(sb, MINIX_DF);
-			break;
-		case Opt_minix_df:
-			ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
-			set_opt(sb, MINIX_DF);
-
-			break;
-		case Opt_grpid:
-			ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
-			set_opt(sb, GRPID);
-
-			break;
-		case Opt_nogrpid:
-			ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
-			clear_opt(sb, GRPID);
-
-			break;
-		case Opt_resuid:
-			if (match_int(&args[0], &option))
-				return 0;
-			sbi->s_resuid = option;
-			break;
-		case Opt_resgid:
-			if (match_int(&args[0], &option))
-				return 0;
-			sbi->s_resgid = option;
-			break;
-		case Opt_sb:
-			/* handled by get_sb_block() instead of here */
-			/* *sb_block = match_int(&args[0]); */
-			break;
-		case Opt_err_panic:
-			clear_opt(sb, ERRORS_CONT);
-			clear_opt(sb, ERRORS_RO);
-			set_opt(sb, ERRORS_PANIC);
-			break;
-		case Opt_err_ro:
-			clear_opt(sb, ERRORS_CONT);
-			clear_opt(sb, ERRORS_PANIC);
-			set_opt(sb, ERRORS_RO);
-			break;
-		case Opt_err_cont:
-			clear_opt(sb, ERRORS_RO);
-			clear_opt(sb, ERRORS_PANIC);
-			set_opt(sb, ERRORS_CONT);
-			break;
-		case Opt_nouid32:
-			set_opt(sb, NO_UID32);
-			break;
-		case Opt_debug:
-			set_opt(sb, DEBUG);
-			break;
-		case Opt_oldalloc:
-			ext4_msg(sb, KERN_WARNING,
-				 "Ignoring deprecated oldalloc option");
-			break;
-		case Opt_orlov:
-			ext4_msg(sb, KERN_WARNING,
-				 "Ignoring deprecated orlov option");
-			break;
-#ifdef CONFIG_EXT4_FS_XATTR
-		case Opt_user_xattr:
-			set_opt(sb, XATTR_USER);
-			break;
-		case Opt_nouser_xattr:
-			clear_opt(sb, XATTR_USER);
-			break;
-#else
-		case Opt_user_xattr:
-		case Opt_nouser_xattr:
-			ext4_msg(sb, KERN_ERR, "(no)user_xattr options not supported");
-			break;
-#endif
-#ifdef CONFIG_EXT4_FS_POSIX_ACL
-		case Opt_acl:
-			set_opt(sb, POSIX_ACL);
-			break;
-		case Opt_noacl:
-			clear_opt(sb, POSIX_ACL);
-			break;
-#else
-		case Opt_acl:
-		case Opt_noacl:
-			ext4_msg(sb, KERN_ERR, "(no)acl options not supported");
-			break;
-#endif
-		case Opt_journal_update:
-			/* @@@ FIXME */
-			/* Eventually we will want to be able to create
-			   a journal file here.  For now, only allow the
-			   user to specify an existing inode to be the
-			   journal file. */
-			if (is_remount) {
-				ext4_msg(sb, KERN_ERR,
-					 "Cannot specify journal on remount");
-				return 0;
-			}
-			set_opt(sb, UPDATE_JOURNAL);
-			break;
-		case Opt_journal_dev:
-			if (is_remount) {
-				ext4_msg(sb, KERN_ERR,
-					"Cannot specify journal on remount");
-				return 0;
-			}
-			if (match_int(&args[0], &option))
-				return 0;
-			*journal_devnum = option;
-			break;
-		case Opt_journal_checksum:
-			set_opt(sb, JOURNAL_CHECKSUM);
-			break;
-		case Opt_journal_async_commit:
-			set_opt(sb, JOURNAL_ASYNC_COMMIT);
-			set_opt(sb, JOURNAL_CHECKSUM);
-			break;
-		case Opt_noload:
-			set_opt(sb, NOLOAD);
-			break;
-		case Opt_commit:
-			if (match_int(&args[0], &option))
-				return 0;
-			if (option < 0)
-				return 0;
-			if (option == 0)
-				option = JBD2_DEFAULT_MAX_COMMIT_AGE;
-			sbi->s_commit_interval = HZ * option;
-			break;
-		case Opt_max_batch_time:
-			if (match_int(&args[0], &option))
-				return 0;
-			if (option < 0)
-				return 0;
-			if (option == 0)
-				option = EXT4_DEF_MAX_BATCH_TIME;
-			sbi->s_max_batch_time = option;
-			break;
-		case Opt_min_batch_time:
-			if (match_int(&args[0], &option))
-				return 0;
-			if (option < 0)
-				return 0;
-			sbi->s_min_batch_time = option;
-			break;
-		case Opt_data_journal:
-			data_opt = EXT4_MOUNT_JOURNAL_DATA;
-			goto datacheck;
-		case Opt_data_ordered:
-			data_opt = EXT4_MOUNT_ORDERED_DATA;
-			goto datacheck;
-		case Opt_data_writeback:
-			data_opt = EXT4_MOUNT_WRITEBACK_DATA;
-		datacheck:
-			if (is_remount) {
-				if (!sbi->s_journal)
-					ext4_msg(sb, KERN_WARNING, "Remounting file system with no journal so ignoring journalled data option");
-				else if (test_opt(sb, DATA_FLAGS) != data_opt) {
-					ext4_msg(sb, KERN_ERR,
-						"Cannot change data mode on remount");
-					return 0;
-				}
-			} else {
-				clear_opt(sb, DATA_FLAGS);
-				sbi->s_mount_opt |= data_opt;
-			}
-			break;
-		case Opt_data_err_abort:
-			set_opt(sb, DATA_ERR_ABORT);
-			break;
-		case Opt_data_err_ignore:
-			clear_opt(sb, DATA_ERR_ABORT);
-			break;
-#ifdef CONFIG_QUOTA
-		case Opt_usrjquota:
-			if (!set_qf_name(sb, USRQUOTA, &args[0]))
-				return 0;
-			break;
-		case Opt_grpjquota:
-			if (!set_qf_name(sb, GRPQUOTA, &args[0]))
-				return 0;
-			break;
-		case Opt_offusrjquota:
-			if (!clear_qf_name(sb, USRQUOTA))
-				return 0;
-			break;
-		case Opt_offgrpjquota:
-			if (!clear_qf_name(sb, GRPQUOTA))
-				return 0;
-			break;
-
-		case Opt_jqfmt_vfsold:
-			qfmt = QFMT_VFS_OLD;
-			goto set_qf_format;
-		case Opt_jqfmt_vfsv0:
-			qfmt = QFMT_VFS_V0;
-			goto set_qf_format;
-		case Opt_jqfmt_vfsv1:
-			qfmt = QFMT_VFS_V1;
-set_qf_format:
-			if (sb_any_quota_loaded(sb) &&
-			    sbi->s_jquota_fmt != qfmt) {
-				ext4_msg(sb, KERN_ERR, "Cannot change "
-					"journaled quota options when "
-					"quota turned on");
-				return 0;
-			}
-			sbi->s_jquota_fmt = qfmt;
-			break;
-		case Opt_quota:
-		case Opt_usrquota:
-			set_opt(sb, QUOTA);
-			set_opt(sb, USRQUOTA);
-			break;
-		case Opt_grpquota:
-			set_opt(sb, QUOTA);
-			set_opt(sb, GRPQUOTA);
-			break;
-		case Opt_noquota:
-			if (sb_any_quota_loaded(sb)) {
-				ext4_msg(sb, KERN_ERR, "Cannot change quota "
-					"options when quota turned on");
-				return 0;
-			}
-			clear_opt(sb, QUOTA);
-			clear_opt(sb, USRQUOTA);
-			clear_opt(sb, GRPQUOTA);
-			break;
-#else
-		case Opt_quota:
-		case Opt_usrquota:
-		case Opt_grpquota:
-			ext4_msg(sb, KERN_ERR,
-				"quota options not supported");
-			break;
-		case Opt_usrjquota:
-		case Opt_grpjquota:
-		case Opt_offusrjquota:
-		case Opt_offgrpjquota:
-		case Opt_jqfmt_vfsold:
-		case Opt_jqfmt_vfsv0:
-		case Opt_jqfmt_vfsv1:
-			ext4_msg(sb, KERN_ERR,
-				"journaled quota options not supported");
-			break;
-		case Opt_noquota:
-			break;
-#endif
-		case Opt_abort:
-			sbi->s_mount_flags |= EXT4_MF_FS_ABORTED;
-			break;
-		case Opt_nobarrier:
-			clear_opt(sb, BARRIER);
-			break;
-		case Opt_barrier:
-			if (args[0].from) {
-				if (match_int(&args[0], &option))
-					return 0;
-			} else
-				option = 1;	/* No argument, default to 1 */
-			if (option)
-				set_opt(sb, BARRIER);
-			else
-				clear_opt(sb, BARRIER);
-			break;
-		case Opt_ignore:
-			break;
-		case Opt_resize:
-			if (!is_remount) {
-				ext4_msg(sb, KERN_ERR,
-					"resize option only available "
-					"for remount");
-				return 0;
-			}
-			if (match_int(&args[0], &option) != 0)
-				return 0;
-			*n_blocks_count = option;
-			break;
-		case Opt_nobh:
-			ext4_msg(sb, KERN_WARNING,
-				 "Ignoring deprecated nobh option");
-			break;
-		case Opt_bh:
-			ext4_msg(sb, KERN_WARNING,
-				 "Ignoring deprecated bh option");
-			break;
-		case Opt_i_version:
-			set_opt(sb, I_VERSION);
-			sb->s_flags |= MS_I_VERSION;
-			break;
-		case Opt_nodelalloc:
-			clear_opt(sb, DELALLOC);
-			clear_opt2(sb, EXPLICIT_DELALLOC);
-			break;
-		case Opt_mblk_io_submit:
-			set_opt(sb, MBLK_IO_SUBMIT);
-			break;
-		case Opt_nomblk_io_submit:
-			clear_opt(sb, MBLK_IO_SUBMIT);
-			break;
-		case Opt_stripe:
-			if (match_int(&args[0], &option))
-				return 0;
-			if (option < 0)
-				return 0;
-			sbi->s_stripe = option;
-			break;
-		case Opt_delalloc:
-			set_opt(sb, DELALLOC);
-			set_opt2(sb, EXPLICIT_DELALLOC);
-			break;
-		case Opt_block_validity:
-			set_opt(sb, BLOCK_VALIDITY);
-			break;
-		case Opt_noblock_validity:
-			clear_opt(sb, BLOCK_VALIDITY);
-			break;
-		case Opt_inode_readahead_blks:
-			if (match_int(&args[0], &option))
-				return 0;
-			if (option < 0 || option > (1 << 30))
-				return 0;
-			if (option && !is_power_of_2(option)) {
-				ext4_msg(sb, KERN_ERR,
-					 "EXT4-fs: inode_readahead_blks"
-					 " must be a power of 2");
-				return 0;
-			}
-			sbi->s_inode_readahead_blks = option;
-			break;
-		case Opt_journal_ioprio:
-			if (match_int(&args[0], &option))
-				return 0;
-			if (option < 0 || option > 7)
-				break;
-			*journal_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE,
-							    option);
-			break;
-		case Opt_noauto_da_alloc:
-			set_opt(sb, NO_AUTO_DA_ALLOC);
-			break;
-		case Opt_auto_da_alloc:
-			if (args[0].from) {
-				if (match_int(&args[0], &option))
-					return 0;
-			} else
-				option = 1;	/* No argument, default to 1 */
-			if (option)
-				clear_opt(sb, NO_AUTO_DA_ALLOC);
-			else
-				set_opt(sb,NO_AUTO_DA_ALLOC);
-			break;
-		case Opt_discard:
-			set_opt(sb, DISCARD);
-			break;
-		case Opt_nodiscard:
-			clear_opt(sb, DISCARD);
-			break;
-		case Opt_dioread_nolock:
-			set_opt(sb, DIOREAD_NOLOCK);
-			break;
-		case Opt_dioread_lock:
-			clear_opt(sb, DIOREAD_NOLOCK);
-			break;
-		case Opt_init_itable:
-			set_opt(sb, INIT_INODE_TABLE);
-			if (args[0].from) {
-				if (match_int(&args[0], &option))
-					return 0;
-			} else
-				option = EXT4_DEF_LI_WAIT_MULT;
-			if (option < 0)
-				return 0;
-			sbi->s_li_wait_mult = option;
-			break;
-		case Opt_noinit_itable:
-			clear_opt(sb, INIT_INODE_TABLE);
-			break;
-		default:
-			ext4_msg(sb, KERN_ERR,
-			       "Unrecognized mount option \"%s\" "
-			       "or missing value", p);
+		if (handle_mount_opt(sb, p, token, args, journal_devnum,
+				     journal_ioprio, is_remount) < 0)
 			return 0;
-		}
 	}
 #ifdef CONFIG_QUOTA
 	if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
@@ -1942,6 +1651,160 @@
 	return 1;
 }
 
+static inline void ext4_show_quota_options(struct seq_file *seq,
+					   struct super_block *sb)
+{
+#if defined(CONFIG_QUOTA)
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+	if (sbi->s_jquota_fmt) {
+		char *fmtname = "";
+
+		switch (sbi->s_jquota_fmt) {
+		case QFMT_VFS_OLD:
+			fmtname = "vfsold";
+			break;
+		case QFMT_VFS_V0:
+			fmtname = "vfsv0";
+			break;
+		case QFMT_VFS_V1:
+			fmtname = "vfsv1";
+			break;
+		}
+		seq_printf(seq, ",jqfmt=%s", fmtname);
+	}
+
+	if (sbi->s_qf_names[USRQUOTA])
+		seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]);
+
+	if (sbi->s_qf_names[GRPQUOTA])
+		seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
+
+	if (test_opt(sb, USRQUOTA))
+		seq_puts(seq, ",usrquota");
+
+	if (test_opt(sb, GRPQUOTA))
+		seq_puts(seq, ",grpquota");
+#endif
+}
+
+static const char *token2str(int token)
+{
+	static const struct match_token *t;
+
+	for (t = tokens; t->token != Opt_err; t++)
+		if (t->token == token && !strchr(t->pattern, '='))
+			break;
+	return t->pattern;
+}
+
+/*
+ * Show an option if
+ *  - it's set to a non-default value OR
+ *  - if the per-sb default is different from the global default
+ */
+static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
+			      int nodefs)
+{
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
+	struct ext4_super_block *es = sbi->s_es;
+	int def_errors, def_mount_opt = nodefs ? 0 : sbi->s_def_mount_opt;
+	const struct mount_opts *m;
+	char sep = nodefs ? '\n' : ',';
+
+#define SEQ_OPTS_PUTS(str) seq_printf(seq, "%c" str, sep)
+#define SEQ_OPTS_PRINT(str, arg) seq_printf(seq, "%c" str, sep, arg)
+
+	if (sbi->s_sb_block != 1)
+		SEQ_OPTS_PRINT("sb=%llu", sbi->s_sb_block);
+
+	for (m = ext4_mount_opts; m->token != Opt_err; m++) {
+		int want_set = m->flags & MOPT_SET;
+		if (((m->flags & (MOPT_SET|MOPT_CLEAR)) == 0) ||
+		    (m->flags & MOPT_CLEAR_ERR))
+			continue;
+		if (!(m->mount_opt & (sbi->s_mount_opt ^ def_mount_opt)))
+			continue; /* skip if same as the default */
+		if ((want_set &&
+		     (sbi->s_mount_opt & m->mount_opt) != m->mount_opt) ||
+		    (!want_set && (sbi->s_mount_opt & m->mount_opt)))
+			continue; /* select Opt_noFoo vs Opt_Foo */
+		SEQ_OPTS_PRINT("%s", token2str(m->token));
+	}
+
+	if (nodefs || sbi->s_resuid != EXT4_DEF_RESUID ||
+	    le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID)
+		SEQ_OPTS_PRINT("resuid=%u", sbi->s_resuid);
+	if (nodefs || sbi->s_resgid != EXT4_DEF_RESGID ||
+	    le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID)
+		SEQ_OPTS_PRINT("resgid=%u", sbi->s_resgid);
+	def_errors = nodefs ? -1 : le16_to_cpu(es->s_errors);
+	if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO)
+		SEQ_OPTS_PUTS("errors=remount-ro");
+	if (test_opt(sb, ERRORS_CONT) && def_errors != EXT4_ERRORS_CONTINUE)
+		SEQ_OPTS_PUTS("errors=continue");
+	if (test_opt(sb, ERRORS_PANIC) && def_errors != EXT4_ERRORS_PANIC)
+		SEQ_OPTS_PUTS("errors=panic");
+	if (nodefs || sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ)
+		SEQ_OPTS_PRINT("commit=%lu", sbi->s_commit_interval / HZ);
+	if (nodefs || sbi->s_min_batch_time != EXT4_DEF_MIN_BATCH_TIME)
+		SEQ_OPTS_PRINT("min_batch_time=%u", sbi->s_min_batch_time);
+	if (nodefs || sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME)
+		SEQ_OPTS_PRINT("max_batch_time=%u", sbi->s_max_batch_time);
+	if (sb->s_flags & MS_I_VERSION)
+		SEQ_OPTS_PUTS("i_version");
+	if (nodefs || sbi->s_stripe)
+		SEQ_OPTS_PRINT("stripe=%lu", sbi->s_stripe);
+	if (EXT4_MOUNT_DATA_FLAGS & (sbi->s_mount_opt ^ def_mount_opt)) {
+		if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
+			SEQ_OPTS_PUTS("data=journal");
+		else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
+			SEQ_OPTS_PUTS("data=ordered");
+		else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
+			SEQ_OPTS_PUTS("data=writeback");
+	}
+	if (nodefs ||
+	    sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS)
+		SEQ_OPTS_PRINT("inode_readahead_blks=%u",
+			       sbi->s_inode_readahead_blks);
+
+	if (nodefs || (test_opt(sb, INIT_INODE_TABLE) &&
+		       (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT)))
+		SEQ_OPTS_PRINT("init_itable=%u", sbi->s_li_wait_mult);
+
+	ext4_show_quota_options(seq, sb);
+	return 0;
+}
+
+static int ext4_show_options(struct seq_file *seq, struct dentry *root)
+{
+	return _ext4_show_options(seq, root->d_sb, 0);
+}
+
+static int options_seq_show(struct seq_file *seq, void *offset)
+{
+	struct super_block *sb = seq->private;
+	int rc;
+
+	seq_puts(seq, (sb->s_flags & MS_RDONLY) ? "ro" : "rw");
+	rc = _ext4_show_options(seq, sb, 1);
+	seq_puts(seq, "\n");
+	return rc;
+}
+
+static int options_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, options_seq_show, PDE(inode)->data);
+}
+
+static const struct file_operations ext4_seq_options_fops = {
+	.owner = THIS_MODULE,
+	.open = options_open_fs,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
 static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
 			    int read_only)
 {
@@ -2945,7 +2808,7 @@
 		ext4_clear_request_list();
 		kfree(ext4_li_info);
 		ext4_li_info = NULL;
-		printk(KERN_CRIT "EXT4: error %d creating inode table "
+		printk(KERN_CRIT "EXT4-fs: error %d creating inode table "
 				 "initialization thread\n",
 				 err);
 		return err;
@@ -3183,11 +3046,8 @@
 	set_opt(sb, INIT_INODE_TABLE);
 	if (def_mount_opts & EXT4_DEFM_DEBUG)
 		set_opt(sb, DEBUG);
-	if (def_mount_opts & EXT4_DEFM_BSDGROUPS) {
-		ext4_msg(sb, KERN_WARNING, deprecated_msg, "bsdgroups",
-			"2.6.38");
+	if (def_mount_opts & EXT4_DEFM_BSDGROUPS)
 		set_opt(sb, GRPID);
-	}
 	if (def_mount_opts & EXT4_DEFM_UID16)
 		set_opt(sb, NO_UID32);
 	/* xattr user namespace & acls are now defaulted on */
@@ -3240,13 +3100,14 @@
 	sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT;
 
 	if (!parse_options((char *) sbi->s_es->s_mount_opts, sb,
-			   &journal_devnum, &journal_ioprio, NULL, 0)) {
+			   &journal_devnum, &journal_ioprio, 0)) {
 		ext4_msg(sb, KERN_WARNING,
 			 "failed to parse options in superblock: %s",
 			 sbi->s_es->s_mount_opts);
 	}
+	sbi->s_def_mount_opt = sbi->s_mount_opt;
 	if (!parse_options((char *) data, sb, &journal_devnum,
-			   &journal_ioprio, NULL, 0))
+			   &journal_ioprio, 0))
 		goto failed_mount;
 
 	if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
@@ -3416,7 +3277,6 @@
 #else
 		es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH);
 #endif
-		sb->s_dirt = 1;
 	}
 
 	/* Handle clustersize */
@@ -3540,6 +3400,10 @@
 	if (ext4_proc_root)
 		sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root);
 
+	if (sbi->s_proc)
+		proc_create_data("options", S_IRUGO, sbi->s_proc,
+				 &ext4_seq_options_fops, sb);
+
 	bgl_lock_init(sbi->s_blockgroup_lock);
 
 	for (i = 0; i < db_count; i++) {
@@ -3694,6 +3558,8 @@
 	}
 	set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);
 
+	sbi->s_journal->j_commit_callback = ext4_journal_commit_callback;
+
 	/*
 	 * The journal may have updated the bg summary counts, so we
 	 * need to update the global counters.
@@ -3735,9 +3601,8 @@
 		iput(root);
 		goto failed_mount4;
 	}
-	sb->s_root = d_alloc_root(root);
+	sb->s_root = d_make_root(root);
 	if (!sb->s_root) {
-		iput(root);
 		ext4_msg(sb, KERN_ERR, "get root dentry failed");
 		ret = -ENOMEM;
 		goto failed_mount4;
@@ -3862,6 +3727,7 @@
 	ext4_kvfree(sbi->s_group_desc);
 failed_mount:
 	if (sbi->s_proc) {
+		remove_proc_entry("options", sbi->s_proc);
 		remove_proc_entry(sb->s_id, ext4_proc_root);
 	}
 #ifdef CONFIG_QUOTA
@@ -4091,15 +3957,6 @@
 	if (!(journal->j_flags & JBD2_BARRIER))
 		ext4_msg(sb, KERN_INFO, "barriers disabled");
 
-	if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) {
-		err = jbd2_journal_update_format(journal);
-		if (err)  {
-			ext4_msg(sb, KERN_ERR, "error updating journal");
-			jbd2_journal_destroy(journal);
-			return err;
-		}
-	}
-
 	if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER))
 		err = jbd2_journal_wipe(journal, !really_read_only);
 	if (!err) {
@@ -4386,7 +4243,6 @@
 {
 	struct ext4_super_block *es;
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
-	ext4_fsblk_t n_blocks_count = 0;
 	unsigned long old_sb_flags;
 	struct ext4_mount_options old_opts;
 	int enable_quota = 0;
@@ -4419,8 +4275,7 @@
 	/*
 	 * Allow the "check" option to be passed as a remount option.
 	 */
-	if (!parse_options(data, sb, NULL, &journal_ioprio,
-			   &n_blocks_count, 1)) {
+	if (!parse_options(data, sb, NULL, &journal_ioprio, 1)) {
 		err = -EINVAL;
 		goto restore_opts;
 	}
@@ -4438,8 +4293,7 @@
 		set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);
 	}
 
-	if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) ||
-		n_blocks_count > ext4_blocks_count(es)) {
+	if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
 		if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) {
 			err = -EROFS;
 			goto restore_opts;
@@ -4514,8 +4368,6 @@
 			if (sbi->s_journal)
 				ext4_clear_journal_err(sb, es);
 			sbi->s_mount_state = le16_to_cpu(es->s_state);
-			if ((err = ext4_group_extend(sb, es, n_blocks_count)))
-				goto restore_opts;
 			if (!ext4_setup_super(sb, es, 0))
 				sb->s_flags &= ~MS_RDONLY;
 			if (EXT4_HAS_INCOMPAT_FEATURE(sb,
@@ -5056,6 +4908,9 @@
 {
 	int i, err;
 
+	ext4_li_info = NULL;
+	mutex_init(&ext4_li_mtx);
+
 	ext4_check_flag_values();
 
 	for (i = 0; i < EXT4_WQ_HASH_SZ; i++) {
@@ -5094,8 +4949,6 @@
 	if (err)
 		goto out;
 
-	ext4_li_info = NULL;
-	mutex_init(&ext4_li_mtx);
 	return 0;
 out:
 	unregister_as_ext2();
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 93a00d8..e88748e 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -82,8 +82,8 @@
 		printk("\n"); \
 	} while (0)
 #else
-# define ea_idebug(f...)
-# define ea_bdebug(f...)
+# define ea_idebug(inode, fmt, ...)	no_printk(fmt, ##__VA_ARGS__)
+# define ea_bdebug(bh, fmt, ...)	no_printk(fmt, ##__VA_ARGS__)
 #endif
 
 static void ext4_xattr_cache_insert(struct buffer_head *);
@@ -158,13 +158,10 @@
 static inline int
 ext4_xattr_check_block(struct buffer_head *bh)
 {
-	int error;
-
 	if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
 	    BHDR(bh)->h_blocks != cpu_to_le32(1))
 		return -EIO;
-	error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size);
-	return error;
+	return ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size);
 }
 
 static inline int
@@ -220,7 +217,8 @@
 	error = -ENODATA;
 	if (!EXT4_I(inode)->i_file_acl)
 		goto cleanup;
-	ea_idebug(inode, "reading block %u", EXT4_I(inode)->i_file_acl);
+	ea_idebug(inode, "reading block %llu",
+		  (unsigned long long)EXT4_I(inode)->i_file_acl);
 	bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
 	if (!bh)
 		goto cleanup;
@@ -363,7 +361,8 @@
 	error = 0;
 	if (!EXT4_I(inode)->i_file_acl)
 		goto cleanup;
-	ea_idebug(inode, "reading block %u", EXT4_I(inode)->i_file_acl);
+	ea_idebug(inode, "reading block %llu",
+		  (unsigned long long)EXT4_I(inode)->i_file_acl);
 	bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
 	error = -EIO;
 	if (!bh)
@@ -487,18 +486,19 @@
 		ext4_free_blocks(handle, inode, bh, 0, 1,
 				 EXT4_FREE_BLOCKS_METADATA |
 				 EXT4_FREE_BLOCKS_FORGET);
+		unlock_buffer(bh);
 	} else {
 		le32_add_cpu(&BHDR(bh)->h_refcount, -1);
+		if (ce)
+			mb_cache_entry_release(ce);
+		unlock_buffer(bh);
 		error = ext4_handle_dirty_metadata(handle, inode, bh);
 		if (IS_SYNC(inode))
 			ext4_handle_sync(handle);
 		dquot_free_block(inode, 1);
 		ea_bdebug(bh, "refcount now=%d; releasing",
 			  le32_to_cpu(BHDR(bh)->h_refcount));
-		if (ce)
-			mb_cache_entry_release(ce);
 	}
-	unlock_buffer(bh);
 out:
 	ext4_std_error(inode->i_sb, error);
 	return;
@@ -834,7 +834,8 @@
 			if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
 				BUG_ON(block > EXT4_MAX_BLOCK_FILE_PHYS);
 
-			ea_idebug(inode, "creating block %d", block);
+			ea_idebug(inode, "creating block %llu",
+				  (unsigned long long)block);
 
 			new_bh = sb_getblk(sb, block);
 			if (!new_bh) {
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 3ab8410..21687e3 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -1496,11 +1496,13 @@
 	root_inode->i_ino = MSDOS_ROOT_INO;
 	root_inode->i_version = 1;
 	error = fat_read_root(root_inode);
-	if (error < 0)
+	if (error < 0) {
+		iput(root_inode);
 		goto out_fail;
+	}
 	error = -ENOMEM;
 	insert_inode_hash(root_inode);
-	sb->s_root = d_alloc_root(root_inode);
+	sb->s_root = d_make_root(root_inode);
 	if (!sb->s_root) {
 		fat_msg(sb, KERN_ERR, "get root inode failed");
 		goto out_fail;
@@ -1516,8 +1518,6 @@
 out_fail:
 	if (fat_inode)
 		iput(fat_inode);
-	if (root_inode)
-		iput(root_inode);
 	unload_nls(sbi->nls_io);
 	unload_nls(sbi->nls_disk);
 	if (sbi->options.iocharset != fat_default_iocharset)
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index a81eb23..98ae804 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -521,57 +521,46 @@
 
 		op = &outname[*outlen * sizeof(wchar_t)];
 	} else {
-		if (nls) {
-			for (i = 0, ip = name, op = outname, *outlen = 0;
-			     i < len && *outlen <= FAT_LFN_LEN;
-			     *outlen += 1)
-			{
-				if (escape && (*ip == ':')) {
-					if (i > len - 5)
-						return -EINVAL;
-					ec = 0;
-					for (k = 1; k < 5; k++) {
-						nc = ip[k];
-						ec <<= 4;
-						if (nc >= '0' && nc <= '9') {
-							ec |= nc - '0';
-							continue;
-						}
-						if (nc >= 'a' && nc <= 'f') {
-							ec |= nc - ('a' - 10);
-							continue;
-						}
-						if (nc >= 'A' && nc <= 'F') {
-							ec |= nc - ('A' - 10);
-							continue;
-						}
-						return -EINVAL;
+		for (i = 0, ip = name, op = outname, *outlen = 0;
+			 i < len && *outlen < FAT_LFN_LEN;
+			 *outlen += 1) {
+			if (escape && (*ip == ':')) {
+				if (i > len - 5)
+					return -EINVAL;
+				ec = 0;
+				for (k = 1; k < 5; k++) {
+					nc = ip[k];
+					ec <<= 4;
+					if (nc >= '0' && nc <= '9') {
+						ec |= nc - '0';
+						continue;
 					}
-					*op++ = ec & 0xFF;
-					*op++ = ec >> 8;
-					ip += 5;
-					i += 5;
-				} else {
-					if ((charlen = nls->char2uni(ip, len - i, (wchar_t *)op)) < 0)
-						return -EINVAL;
-					ip += charlen;
-					i += charlen;
-					op += 2;
+					if (nc >= 'a' && nc <= 'f') {
+						ec |= nc - ('a' - 10);
+						continue;
+					}
+					if (nc >= 'A' && nc <= 'F') {
+						ec |= nc - ('A' - 10);
+						continue;
+					}
+					return -EINVAL;
 				}
+				*op++ = ec & 0xFF;
+				*op++ = ec >> 8;
+				ip += 5;
+				i += 5;
+			} else {
+				charlen = nls->char2uni(ip, len - i,
+									(wchar_t *)op);
+				if (charlen < 0)
+					return -EINVAL;
+				ip += charlen;
+				i += charlen;
+				op += 2;
 			}
-			if (i < len)
-				return -ENAMETOOLONG;
-		} else {
-			for (i = 0, ip = name, op = outname, *outlen = 0;
-			     i < len && *outlen <= FAT_LFN_LEN;
-			     i++, *outlen += 1)
-			{
-				*op++ = *ip++;
-				*op++ = 0;
-			}
-			if (i < len)
-				return -ENAMETOOLONG;
 		}
+		if (i < len)
+			return -ENAMETOOLONG;
 	}
 
 	*longlen = *outlen;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 22764c7..75e7c1f 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -32,20 +32,20 @@
 	spin_lock(&files->file_lock);
 	fdt = files_fdtable(files);
 	if (flag)
-		FD_SET(fd, fdt->close_on_exec);
+		__set_close_on_exec(fd, fdt);
 	else
-		FD_CLR(fd, fdt->close_on_exec);
+		__clear_close_on_exec(fd, fdt);
 	spin_unlock(&files->file_lock);
 }
 
-static int get_close_on_exec(unsigned int fd)
+static bool get_close_on_exec(unsigned int fd)
 {
 	struct files_struct *files = current->files;
 	struct fdtable *fdt;
-	int res;
+	bool res;
 	rcu_read_lock();
 	fdt = files_fdtable(files);
-	res = FD_ISSET(fd, fdt->close_on_exec);
+	res = close_on_exec(fd, fdt);
 	rcu_read_unlock();
 	return res;
 }
@@ -90,15 +90,15 @@
 	err = -EBUSY;
 	fdt = files_fdtable(files);
 	tofree = fdt->fd[newfd];
-	if (!tofree && FD_ISSET(newfd, fdt->open_fds))
+	if (!tofree && fd_is_open(newfd, fdt))
 		goto out_unlock;
 	get_file(file);
 	rcu_assign_pointer(fdt->fd[newfd], file);
-	FD_SET(newfd, fdt->open_fds);
+	__set_open_fd(newfd, fdt);
 	if (flags & O_CLOEXEC)
-		FD_SET(newfd, fdt->close_on_exec);
+		__set_close_on_exec(newfd, fdt);
 	else
-		FD_CLR(newfd, fdt->close_on_exec);
+		__clear_close_on_exec(newfd, fdt);
 	spin_unlock(&files->file_lock);
 
 	if (tofree)
diff --git a/fs/file.c b/fs/file.c
index 4c6992d..ba3f605 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -6,7 +6,7 @@
  *  Manage the dynamic fd arrays in the process files_struct.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/mmzone.h>
@@ -40,7 +40,7 @@
  */
 static DEFINE_PER_CPU(struct fdtable_defer, fdtable_defer_list);
 
-static void *alloc_fdmem(unsigned int size)
+static void *alloc_fdmem(size_t size)
 {
 	/*
 	 * Very large allocations can stress page reclaim, so fall back to
@@ -142,7 +142,7 @@
 static struct fdtable * alloc_fdtable(unsigned int nr)
 {
 	struct fdtable *fdt;
-	char *data;
+	void *data;
 
 	/*
 	 * Figure out how many fds we actually want to support in this fdtable.
@@ -172,14 +172,15 @@
 	data = alloc_fdmem(nr * sizeof(struct file *));
 	if (!data)
 		goto out_fdt;
-	fdt->fd = (struct file **)data;
-	data = alloc_fdmem(max_t(unsigned int,
+	fdt->fd = data;
+
+	data = alloc_fdmem(max_t(size_t,
 				 2 * nr / BITS_PER_BYTE, L1_CACHE_BYTES));
 	if (!data)
 		goto out_arr;
-	fdt->open_fds = (fd_set *)data;
+	fdt->open_fds = data;
 	data += nr / BITS_PER_BYTE;
-	fdt->close_on_exec = (fd_set *)data;
+	fdt->close_on_exec = data;
 	fdt->next = NULL;
 
 	return fdt;
@@ -275,11 +276,11 @@
 	int i;
 
 	/* Find the last open fd */
-	for (i = size/(8*sizeof(long)); i > 0; ) {
-		if (fdt->open_fds->fds_bits[--i])
+	for (i = size / BITS_PER_LONG; i > 0; ) {
+		if (fdt->open_fds[--i])
 			break;
 	}
-	i = (i+1) * 8 * sizeof(long);
+	i = (i + 1) * BITS_PER_LONG;
 	return i;
 }
 
@@ -306,8 +307,8 @@
 	newf->next_fd = 0;
 	new_fdt = &newf->fdtab;
 	new_fdt->max_fds = NR_OPEN_DEFAULT;
-	new_fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init;
-	new_fdt->open_fds = (fd_set *)&newf->open_fds_init;
+	new_fdt->close_on_exec = newf->close_on_exec_init;
+	new_fdt->open_fds = newf->open_fds_init;
 	new_fdt->fd = &newf->fd_array[0];
 	new_fdt->next = NULL;
 
@@ -350,10 +351,8 @@
 	old_fds = old_fdt->fd;
 	new_fds = new_fdt->fd;
 
-	memcpy(new_fdt->open_fds->fds_bits,
-		old_fdt->open_fds->fds_bits, open_files/8);
-	memcpy(new_fdt->close_on_exec->fds_bits,
-		old_fdt->close_on_exec->fds_bits, open_files/8);
+	memcpy(new_fdt->open_fds, old_fdt->open_fds, open_files / 8);
+	memcpy(new_fdt->close_on_exec, old_fdt->close_on_exec, open_files / 8);
 
 	for (i = open_files; i != 0; i--) {
 		struct file *f = *old_fds++;
@@ -366,7 +365,7 @@
 			 * is partway through open().  So make sure that this
 			 * fd is available to the new process.
 			 */
-			FD_CLR(open_files - i, new_fdt->open_fds);
+			__clear_open_fd(open_files - i, new_fdt);
 		}
 		rcu_assign_pointer(*new_fds++, f);
 	}
@@ -379,11 +378,11 @@
 	memset(new_fds, 0, size);
 
 	if (new_fdt->max_fds > open_files) {
-		int left = (new_fdt->max_fds-open_files)/8;
-		int start = open_files / (8 * sizeof(unsigned long));
+		int left = (new_fdt->max_fds - open_files) / 8;
+		int start = open_files / BITS_PER_LONG;
 
-		memset(&new_fdt->open_fds->fds_bits[start], 0, left);
-		memset(&new_fdt->close_on_exec->fds_bits[start], 0, left);
+		memset(&new_fdt->open_fds[start], 0, left);
+		memset(&new_fdt->close_on_exec[start], 0, left);
 	}
 
 	rcu_assign_pointer(newf->fdt, new_fdt);
@@ -419,8 +418,8 @@
 	.fdtab		= {
 		.max_fds	= NR_OPEN_DEFAULT,
 		.fd		= &init_files.fd_array[0],
-		.close_on_exec	= (fd_set *)&init_files.close_on_exec_init,
-		.open_fds	= (fd_set *)&init_files.open_fds_init,
+		.close_on_exec	= init_files.close_on_exec_init,
+		.open_fds	= init_files.open_fds_init,
 	},
 	.file_lock	= __SPIN_LOCK_UNLOCKED(init_task.file_lock),
 };
@@ -443,8 +442,7 @@
 		fd = files->next_fd;
 
 	if (fd < fdt->max_fds)
-		fd = find_next_zero_bit(fdt->open_fds->fds_bits,
-					   fdt->max_fds, fd);
+		fd = find_next_zero_bit(fdt->open_fds, fdt->max_fds, fd);
 
 	error = expand_files(files, fd);
 	if (error < 0)
@@ -460,11 +458,11 @@
 	if (start <= files->next_fd)
 		files->next_fd = fd + 1;
 
-	FD_SET(fd, fdt->open_fds);
+	__set_open_fd(fd, fdt);
 	if (flags & O_CLOEXEC)
-		FD_SET(fd, fdt->close_on_exec);
+		__set_close_on_exec(fd, fdt);
 	else
-		FD_CLR(fd, fdt->close_on_exec);
+		__clear_close_on_exec(fd, fdt);
 	error = fd;
 #if 1
 	/* Sanity check */
diff --git a/fs/file_table.c b/fs/file_table.c
index 20002e3..70f2a0f 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -204,7 +204,7 @@
  * to write to @file, along with access to write through
  * its vfsmount.
  */
-void drop_file_write_access(struct file *file)
+static void drop_file_write_access(struct file *file)
 {
 	struct vfsmount *mnt = file->f_path.mnt;
 	struct dentry *dentry = file->f_path.dentry;
@@ -219,7 +219,6 @@
 	mnt_drop_write(mnt);
 	file_release_write(file);
 }
-EXPORT_SYMBOL_GPL(drop_file_write_access);
 
 /* the real guts of fput() - releasing the last reference to file
  */
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
index 9d1c995..d4fabd2 100644
--- a/fs/freevxfs/vxfs_super.c
+++ b/fs/freevxfs/vxfs_super.c
@@ -224,9 +224,8 @@
 		ret = PTR_ERR(root);
 		goto out;
 	}
-	sbp->s_root = d_alloc_root(root);
+	sbp->s_root = d_make_root(root);
 	if (!sbp->s_root) {
-		iput(root);
 		printk(KERN_WARNING "vxfs: unable to get root dentry.\n");
 		goto out_free_ilist;
 	}
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 77b535a..539f36c 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -14,7 +14,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
@@ -256,7 +256,8 @@
 }
 
 /*
- * Move expired dirty inodes from @delaying_queue to @dispatch_queue.
+ * Move expired (dirtied after work->older_than_this) dirty inodes from
+ * @delaying_queue to @dispatch_queue.
  */
 static int move_expired_inodes(struct list_head *delaying_queue,
 			       struct list_head *dispatch_queue,
@@ -1148,23 +1149,6 @@
 }
 EXPORT_SYMBOL(__mark_inode_dirty);
 
-/*
- * Write out a superblock's list of dirty inodes.  A wait will be performed
- * upon no inodes, all inodes or the final one, depending upon sync_mode.
- *
- * If older_than_this is non-NULL, then only write out inodes which
- * had their first dirtying at a time earlier than *older_than_this.
- *
- * If `bdi' is non-zero then we're being asked to writeback a specific queue.
- * This function assumes that the blockdev superblock's inodes are backed by
- * a variety of queues, so all inodes are searched.  For other superblocks,
- * assume that all inodes are backed by the same queue.
- *
- * The inodes to be written are parked on bdi->b_io.  They are moved back onto
- * bdi->b_dirty as they are selected for writing.  This way, none can be missed
- * on the writer throttling path, and we get decent balancing between many
- * throttled threads: we don't want them all piling up on inode_sync_wait.
- */
 static void wait_sb_inodes(struct super_block *sb)
 {
 	struct inode *inode, *old_inode = NULL;
@@ -1364,8 +1348,6 @@
 	ret = writeback_single_inode(inode, wb, &wbc);
 	spin_unlock(&inode->i_lock);
 	spin_unlock(&wb->list_lock);
-	if (sync)
-		inode_sync_wait(inode);
 	return ret;
 }
 EXPORT_SYMBOL(write_inode_now);
diff --git a/fs/fs_struct.c b/fs/fs_struct.c
index 78b519c..e159e68 100644
--- a/fs/fs_struct.c
+++ b/fs/fs_struct.c
@@ -1,4 +1,4 @@
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/path.h>
@@ -26,11 +26,11 @@
 {
 	struct path old_root;
 
+	path_get_longterm(path);
 	spin_lock(&fs->lock);
 	write_seqcount_begin(&fs->seq);
 	old_root = fs->root;
 	fs->root = *path;
-	path_get_longterm(path);
 	write_seqcount_end(&fs->seq);
 	spin_unlock(&fs->lock);
 	if (old_root.dentry)
@@ -45,11 +45,11 @@
 {
 	struct path old_pwd;
 
+	path_get_longterm(path);
 	spin_lock(&fs->lock);
 	write_seqcount_begin(&fs->seq);
 	old_pwd = fs->pwd;
 	fs->pwd = *path;
-	path_get_longterm(path);
 	write_seqcount_end(&fs->seq);
 	spin_unlock(&fs->lock);
 
@@ -57,6 +57,14 @@
 		path_put_longterm(&old_pwd);
 }
 
+static inline int replace_path(struct path *p, const struct path *old, const struct path *new)
+{
+	if (likely(p->dentry != old->dentry || p->mnt != old->mnt))
+		return 0;
+	*p = *new;
+	return 1;
+}
+
 void chroot_fs_refs(struct path *old_root, struct path *new_root)
 {
 	struct task_struct *g, *p;
@@ -68,21 +76,16 @@
 		task_lock(p);
 		fs = p->fs;
 		if (fs) {
+			int hits = 0;
 			spin_lock(&fs->lock);
 			write_seqcount_begin(&fs->seq);
-			if (fs->root.dentry == old_root->dentry
-			    && fs->root.mnt == old_root->mnt) {
-				path_get_longterm(new_root);
-				fs->root = *new_root;
-				count++;
-			}
-			if (fs->pwd.dentry == old_root->dentry
-			    && fs->pwd.mnt == old_root->mnt) {
-				path_get_longterm(new_root);
-				fs->pwd = *new_root;
-				count++;
-			}
+			hits += replace_path(&fs->root, old_root, new_root);
+			hits += replace_path(&fs->pwd, old_root, new_root);
 			write_seqcount_end(&fs->seq);
+			while (hits--) {
+				count++;
+				path_get_longterm(new_root);
+			}
 			spin_unlock(&fs->lock);
 		}
 		task_unlock(p);
@@ -107,10 +110,8 @@
 		int kill;
 		task_lock(tsk);
 		spin_lock(&fs->lock);
-		write_seqcount_begin(&fs->seq);
 		tsk->fs = NULL;
 		kill = !--fs->users;
-		write_seqcount_end(&fs->seq);
 		spin_unlock(&fs->lock);
 		task_unlock(tsk);
 		if (kill)
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 64cf8d0..4aec599 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -988,14 +988,9 @@
 
 	err = -ENOMEM;
 	root = fuse_get_root_inode(sb, d.rootmode);
-	if (!root)
+	root_dentry = d_make_root(root);
+	if (!root_dentry)
 		goto err_put_conn;
-
-	root_dentry = d_alloc_root(root);
-	if (!root_dentry) {
-		iput(root);
-		goto err_put_conn;
-	}
 	/* only now - we want root dentry with NULL ->d_op */
 	sb->s_d_op = &fuse_dentry_operations;
 
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 14a7040..197c5c4 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -60,7 +60,7 @@
 	int release = 0;
 
 	if (!page || page->index) {
-		page = grab_cache_page(inode->i_mapping, 0);
+		page = find_or_create_page(inode->i_mapping, 0, GFP_NOFS);
 		if (!page)
 			return -ENOMEM;
 		release = 1;
@@ -930,7 +930,7 @@
 	struct page *page;
 	int err;
 
-	page = grab_cache_page(mapping, index);
+	page = find_or_create_page(mapping, index, GFP_NOFS);
 	if (!page)
 		return 0;
 
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index c5fb359..a3d2c9e 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -18,7 +18,6 @@
 #include <linux/mount.h>
 #include <linux/fs.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/ext2_fs.h>
 #include <linux/falloc.h>
 #include <linux/swap.h>
 #include <linux/crc32.h>
@@ -313,6 +312,8 @@
 		return gfs2_get_flags(filp, (u32 __user *)arg);
 	case FS_IOC_SETFLAGS:
 		return gfs2_set_flags(filp, (u32 __user *)arg);
+	case FITRIM:
+		return gfs2_fitrim(filp, (void __user *)arg);
 	}
 	return -ENOTTY;
 }
@@ -674,6 +675,7 @@
 	struct gfs2_inode *ip = GFS2_I(inode);
 	struct buffer_head *dibh;
 	int error;
+	loff_t size = len;
 	unsigned int nr_blks;
 	sector_t lblock = offset >> inode->i_blkbits;
 
@@ -707,8 +709,8 @@
 			goto out;
 		}
 	}
-	if (offset + len > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE))
-		i_size_write(inode, offset + len);
+	if (offset + size > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE))
+		i_size_write(inode, offset + size);
 
 	mark_inode_dirty(inode);
 
@@ -777,12 +779,14 @@
 	if (unlikely(error))
 		goto out_uninit;
 
-	if (!gfs2_write_alloc_required(ip, offset, len))
-		goto out_unlock;
-
 	while (len > 0) {
 		if (len < bytes)
 			bytes = len;
+		if (!gfs2_write_alloc_required(ip, offset, bytes)) {
+			len -= bytes;
+			offset += bytes;
+			continue;
+		}
 		qa = gfs2_qadata_get(ip);
 		if (!qa) {
 			error = -ENOMEM;
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 351a3e7..dab2526 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -29,6 +29,7 @@
 #include <linux/rcupdate.h>
 #include <linux/rculist_bl.h>
 #include <linux/bit_spinlock.h>
+#include <linux/percpu.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -543,6 +544,11 @@
 		do_error(gl, 0); /* Fail queued try locks */
 	}
 	gl->gl_req = target;
+	set_bit(GLF_BLOCKING, &gl->gl_flags);
+	if ((gl->gl_req == LM_ST_UNLOCKED) ||
+	    (gl->gl_state == LM_ST_EXCLUSIVE) ||
+	    (lck_flags & (LM_FLAG_TRY|LM_FLAG_TRY_1CB)))
+		clear_bit(GLF_BLOCKING, &gl->gl_flags);
 	spin_unlock(&gl->gl_spin);
 	if (glops->go_xmote_th)
 		glops->go_xmote_th(gl);
@@ -744,6 +750,7 @@
 		return -ENOMEM;
 
 	atomic_inc(&sdp->sd_glock_disposal);
+	gl->gl_sbd = sdp;
 	gl->gl_flags = 0;
 	gl->gl_name = name;
 	atomic_set(&gl->gl_ref, 1);
@@ -752,12 +759,17 @@
 	gl->gl_demote_state = LM_ST_EXCLUSIVE;
 	gl->gl_hash = hash;
 	gl->gl_ops = glops;
-	snprintf(gl->gl_strname, GDLM_STRNAME_BYTES, "%8x%16llx", name.ln_type, (unsigned long long)number);
+	gl->gl_dstamp = ktime_set(0, 0);
+	preempt_disable();
+	/* We use the global stats to estimate the initial per-glock stats */
+	gl->gl_stats = this_cpu_ptr(sdp->sd_lkstats)->lkstats[glops->go_type];
+	preempt_enable();
+	gl->gl_stats.stats[GFS2_LKS_DCOUNT] = 0;
+	gl->gl_stats.stats[GFS2_LKS_QCOUNT] = 0;
 	memset(&gl->gl_lksb, 0, sizeof(struct dlm_lksb));
 	gl->gl_lksb.sb_lvbptr = gl->gl_lvb;
 	gl->gl_tchange = jiffies;
 	gl->gl_object = NULL;
-	gl->gl_sbd = sdp;
 	gl->gl_hold_time = GL_GLOCK_DFT_HOLD;
 	INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
 	INIT_WORK(&gl->gl_delete, delete_work_func);
@@ -999,6 +1011,8 @@
 	}
 	set_bit(GLF_QUEUED, &gl->gl_flags);
 	trace_gfs2_glock_queue(gh, 1);
+	gfs2_glstats_inc(gl, GFS2_LKS_QCOUNT);
+	gfs2_sbstats_inc(gl, GFS2_LKS_QCOUNT);
 	if (likely(insert_pt == NULL)) {
 		list_add_tail(&gh->gh_list, &gl->gl_holders);
 		if (unlikely(gh->gh_flags & LM_FLAG_PRIORITY))
@@ -1658,6 +1672,8 @@
 		*p++ = 'L';
 	if (gl->gl_object)
 		*p++ = 'o';
+	if (test_bit(GLF_BLOCKING, gflags))
+		*p++ = 'b';
 	*p = 0;
 	return buf;
 }
@@ -1714,8 +1730,78 @@
 	return error;
 }
 
+static int gfs2_glstats_seq_show(struct seq_file *seq, void *iter_ptr)
+{
+	struct gfs2_glock *gl = iter_ptr;
 
+	seq_printf(seq, "G: n:%u/%llx rtt:%lld/%lld rttb:%lld/%lld irt:%lld/%lld dcnt: %lld qcnt: %lld\n",
+		   gl->gl_name.ln_type,
+		   (unsigned long long)gl->gl_name.ln_number,
+		   (long long)gl->gl_stats.stats[GFS2_LKS_SRTT],
+		   (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVAR],
+		   (long long)gl->gl_stats.stats[GFS2_LKS_SRTTB],
+		   (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVARB],
+		   (long long)gl->gl_stats.stats[GFS2_LKS_SIRT],
+		   (long long)gl->gl_stats.stats[GFS2_LKS_SIRTVAR],
+		   (long long)gl->gl_stats.stats[GFS2_LKS_DCOUNT],
+		   (long long)gl->gl_stats.stats[GFS2_LKS_QCOUNT]);
+	return 0;
+}
 
+static const char *gfs2_gltype[] = {
+	"type",
+	"reserved",
+	"nondisk",
+	"inode",
+	"rgrp",
+	"meta",
+	"iopen",
+	"flock",
+	"plock",
+	"quota",
+	"journal",
+};
+
+static const char *gfs2_stype[] = {
+	[GFS2_LKS_SRTT]		= "srtt",
+	[GFS2_LKS_SRTTVAR]	= "srttvar",
+	[GFS2_LKS_SRTTB]	= "srttb",
+	[GFS2_LKS_SRTTVARB]	= "srttvarb",
+	[GFS2_LKS_SIRT]		= "sirt",
+	[GFS2_LKS_SIRTVAR]	= "sirtvar",
+	[GFS2_LKS_DCOUNT]	= "dlm",
+	[GFS2_LKS_QCOUNT]	= "queue",
+};
+
+#define GFS2_NR_SBSTATS (ARRAY_SIZE(gfs2_gltype) * ARRAY_SIZE(gfs2_stype))
+
+static int gfs2_sbstats_seq_show(struct seq_file *seq, void *iter_ptr)
+{
+	struct gfs2_glock_iter *gi = seq->private;
+	struct gfs2_sbd *sdp = gi->sdp;
+	unsigned index = gi->hash >> 3;
+	unsigned subindex = gi->hash & 0x07;
+	s64 value;
+	int i;
+
+	if (index == 0 && subindex != 0)
+		return 0;
+
+	seq_printf(seq, "%-10s %8s:", gfs2_gltype[index],
+		   (index == 0) ? "cpu": gfs2_stype[subindex]);
+
+	for_each_possible_cpu(i) {
+                const struct gfs2_pcpu_lkstats *lkstats = per_cpu_ptr(sdp->sd_lkstats, i);
+		if (index == 0) {
+			value = i;
+		} else {
+			value = lkstats->lkstats[index - 1].stats[subindex];
+		}
+		seq_printf(seq, " %15lld", (long long)value);
+	}
+	seq_putc(seq, '\n');
+	return 0;
+}
 
 int __init gfs2_glock_init(void)
 {
@@ -1828,6 +1914,35 @@
 	return dump_glock(seq, iter_ptr);
 }
 
+static void *gfs2_sbstats_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	struct gfs2_glock_iter *gi = seq->private;
+
+	gi->hash = *pos;
+	if (*pos >= GFS2_NR_SBSTATS)
+		return NULL;
+	preempt_disable();
+	return SEQ_START_TOKEN;
+}
+
+static void *gfs2_sbstats_seq_next(struct seq_file *seq, void *iter_ptr,
+				   loff_t *pos)
+{
+	struct gfs2_glock_iter *gi = seq->private;
+	(*pos)++;
+	gi->hash++;
+	if (gi->hash >= GFS2_NR_SBSTATS) {
+		preempt_enable();
+		return NULL;
+	}
+	return SEQ_START_TOKEN;
+}
+
+static void gfs2_sbstats_seq_stop(struct seq_file *seq, void *iter_ptr)
+{
+	preempt_enable();
+}
+
 static const struct seq_operations gfs2_glock_seq_ops = {
 	.start = gfs2_glock_seq_start,
 	.next  = gfs2_glock_seq_next,
@@ -1835,7 +1950,21 @@
 	.show  = gfs2_glock_seq_show,
 };
 
-static int gfs2_debugfs_open(struct inode *inode, struct file *file)
+static const struct seq_operations gfs2_glstats_seq_ops = {
+	.start = gfs2_glock_seq_start,
+	.next  = gfs2_glock_seq_next,
+	.stop  = gfs2_glock_seq_stop,
+	.show  = gfs2_glstats_seq_show,
+};
+
+static const struct seq_operations gfs2_sbstats_seq_ops = {
+	.start = gfs2_sbstats_seq_start,
+	.next  = gfs2_sbstats_seq_next,
+	.stop  = gfs2_sbstats_seq_stop,
+	.show  = gfs2_sbstats_seq_show,
+};
+
+static int gfs2_glocks_open(struct inode *inode, struct file *file)
 {
 	int ret = seq_open_private(file, &gfs2_glock_seq_ops,
 				   sizeof(struct gfs2_glock_iter));
@@ -1847,9 +1976,49 @@
 	return ret;
 }
 
-static const struct file_operations gfs2_debug_fops = {
+static int gfs2_glstats_open(struct inode *inode, struct file *file)
+{
+	int ret = seq_open_private(file, &gfs2_glstats_seq_ops,
+				   sizeof(struct gfs2_glock_iter));
+	if (ret == 0) {
+		struct seq_file *seq = file->private_data;
+		struct gfs2_glock_iter *gi = seq->private;
+		gi->sdp = inode->i_private;
+	}
+	return ret;
+}
+
+static int gfs2_sbstats_open(struct inode *inode, struct file *file)
+{
+	int ret = seq_open_private(file, &gfs2_sbstats_seq_ops,
+				   sizeof(struct gfs2_glock_iter));
+	if (ret == 0) {
+		struct seq_file *seq = file->private_data;
+		struct gfs2_glock_iter *gi = seq->private;
+		gi->sdp = inode->i_private;
+	}
+	return ret;
+}
+
+static const struct file_operations gfs2_glocks_fops = {
 	.owner   = THIS_MODULE,
-	.open    = gfs2_debugfs_open,
+	.open    = gfs2_glocks_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release_private,
+};
+
+static const struct file_operations gfs2_glstats_fops = {
+	.owner   = THIS_MODULE,
+	.open    = gfs2_glstats_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release_private,
+};
+
+static const struct file_operations gfs2_sbstats_fops = {
+	.owner   = THIS_MODULE,
+	.open	 = gfs2_sbstats_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
 	.release = seq_release_private,
@@ -1863,20 +2032,45 @@
 	sdp->debugfs_dentry_glocks = debugfs_create_file("glocks",
 							 S_IFREG | S_IRUGO,
 							 sdp->debugfs_dir, sdp,
-							 &gfs2_debug_fops);
+							 &gfs2_glocks_fops);
 	if (!sdp->debugfs_dentry_glocks)
-		return -ENOMEM;
+		goto fail;
+
+	sdp->debugfs_dentry_glstats = debugfs_create_file("glstats",
+							S_IFREG | S_IRUGO,
+							sdp->debugfs_dir, sdp,
+							&gfs2_glstats_fops);
+	if (!sdp->debugfs_dentry_glstats)
+		goto fail;
+
+	sdp->debugfs_dentry_sbstats = debugfs_create_file("sbstats",
+							S_IFREG | S_IRUGO,
+							sdp->debugfs_dir, sdp,
+							&gfs2_sbstats_fops);
+	if (!sdp->debugfs_dentry_sbstats)
+		goto fail;
 
 	return 0;
+fail:
+	gfs2_delete_debugfs_file(sdp);
+	return -ENOMEM;
 }
 
 void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp)
 {
-	if (sdp && sdp->debugfs_dir) {
+	if (sdp->debugfs_dir) {
 		if (sdp->debugfs_dentry_glocks) {
 			debugfs_remove(sdp->debugfs_dentry_glocks);
 			sdp->debugfs_dentry_glocks = NULL;
 		}
+		if (sdp->debugfs_dentry_glstats) {
+			debugfs_remove(sdp->debugfs_dentry_glstats);
+			sdp->debugfs_dentry_glstats = NULL;
+		}
+		if (sdp->debugfs_dentry_sbstats) {
+			debugfs_remove(sdp->debugfs_dentry_sbstats);
+			sdp->debugfs_dentry_sbstats = NULL;
+		}
 		debugfs_remove(sdp->debugfs_dir);
 		sdp->debugfs_dir = NULL;
 	}
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 97742a7..47d0bda 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -19,6 +19,8 @@
 #include <linux/rculist_bl.h>
 #include <linux/completion.h>
 #include <linux/rbtree.h>
+#include <linux/ktime.h>
+#include <linux/percpu.h>
 
 #define DIO_WAIT	0x00000010
 #define DIO_METADATA	0x00000020
@@ -205,6 +207,22 @@
 };
 
 enum {
+	GFS2_LKS_SRTT = 0,	/* Non blocking smoothed round trip time */
+	GFS2_LKS_SRTTVAR = 1,	/* Non blocking smoothed variance */
+	GFS2_LKS_SRTTB = 2,	/* Blocking smoothed round trip time */
+	GFS2_LKS_SRTTVARB = 3,	/* Blocking smoothed variance */
+	GFS2_LKS_SIRT = 4,	/* Smoothed Inter-request time */
+	GFS2_LKS_SIRTVAR = 5,	/* Smoothed Inter-request variance */
+	GFS2_LKS_DCOUNT = 6,	/* Count of dlm requests */
+	GFS2_LKS_QCOUNT = 7,	/* Count of gfs2_holder queues */
+	GFS2_NR_LKSTATS
+};
+
+struct gfs2_lkstats {
+	s64 stats[GFS2_NR_LKSTATS];
+};
+
+enum {
 	/* States */
 	HIF_HOLDER		= 6,  /* Set for gh that "holds" the glock */
 	HIF_FIRST		= 7,
@@ -238,10 +256,12 @@
 	GLF_QUEUED			= 12,
 	GLF_LRU				= 13,
 	GLF_OBJECT			= 14, /* Used only for tracing */
+	GLF_BLOCKING			= 15,
 };
 
 struct gfs2_glock {
 	struct hlist_bl_node gl_list;
+	struct gfs2_sbd *gl_sbd;
 	unsigned long gl_flags;		/* GLF_... */
 	struct lm_lockname gl_name;
 	atomic_t gl_ref;
@@ -261,16 +281,14 @@
 	struct list_head gl_holders;
 
 	const struct gfs2_glock_operations *gl_ops;
-	char gl_strname[GDLM_STRNAME_BYTES];
+	ktime_t gl_dstamp;
+	struct gfs2_lkstats gl_stats;
 	struct dlm_lksb gl_lksb;
 	char gl_lvb[32];
 	unsigned long gl_tchange;
 	void *gl_object;
 
 	struct list_head gl_lru;
-
-	struct gfs2_sbd *gl_sbd;
-
 	struct list_head gl_ail_list;
 	atomic_t gl_ail_count;
 	atomic_t gl_revokes;
@@ -560,8 +578,14 @@
 	uint32_t *ls_recover_result; /* result of last jid recovery */
 };
 
+struct gfs2_pcpu_lkstats {
+	/* One struct for each glock type */
+	struct gfs2_lkstats lkstats[10];
+};
+
 struct gfs2_sbd {
 	struct super_block *sd_vfs;
+	struct gfs2_pcpu_lkstats __percpu *sd_lkstats;
 	struct kobject sd_kobj;
 	unsigned long sd_flags;	/* SDF_... */
 	struct gfs2_sb_host sd_sb;
@@ -620,7 +644,6 @@
 
 	int sd_rindex_uptodate;
 	spinlock_t sd_rindex_spin;
-	struct mutex sd_rindex_mutex;
 	struct rb_root sd_rindex_tree;
 	unsigned int sd_rgrps;
 	unsigned int sd_max_rg_data;
@@ -725,8 +748,23 @@
 
 	unsigned long sd_last_warning;
 	struct dentry *debugfs_dir;    /* debugfs directory */
-	struct dentry *debugfs_dentry_glocks; /* for debugfs */
+	struct dentry *debugfs_dentry_glocks;
+	struct dentry *debugfs_dentry_glstats;
+	struct dentry *debugfs_dentry_sbstats;
 };
 
+static inline void gfs2_glstats_inc(struct gfs2_glock *gl, int which)
+{
+	gl->gl_stats.stats[which]++;
+}
+
+static inline void gfs2_sbstats_inc(const struct gfs2_glock *gl, int which)
+{
+	const struct gfs2_sbd *sdp = gl->gl_sbd;
+	preempt_disable();
+	this_cpu_ptr(sdp->sd_lkstats)->lkstats[gl->gl_name.ln_type].stats[which]++;
+	preempt_enable();
+}
+
 #endif /* __INCORE_DOT_H__ */
 
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 5698746..c98a60e 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -1036,7 +1036,7 @@
 	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
 	gfs2_holder_init(ip->i_gl,  LM_ST_EXCLUSIVE, 0, ghs + 1);
 
-	rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);
+	rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr, 1);
 	if (!rgd)
 		goto out_inodes;
 
@@ -1255,7 +1255,7 @@
 		 * this is the case of the target file already existing
 		 * so we unlink before doing the rename
 		 */
-		nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr);
+		nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr, 1);
 		if (nrgd)
 			gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++);
 	}
diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c
index 8944d1e..f8411bd 100644
--- a/fs/gfs2/lock_dlm.c
+++ b/fs/gfs2/lock_dlm.c
@@ -18,14 +18,106 @@
 #include "glock.h"
 #include "util.h"
 #include "sys.h"
+#include "trace_gfs2.h"
 
 extern struct workqueue_struct *gfs2_control_wq;
 
+/**
+ * gfs2_update_stats - Update time based stats
+ * @mv: Pointer to mean/variance structure to update
+ * @sample: New data to include
+ *
+ * @delta is the difference between the current rtt sample and the
+ * running average srtt. We add 1/8 of that to the srtt in order to
+ * update the current srtt estimate. The varience estimate is a bit
+ * more complicated. We subtract the abs value of the @delta from
+ * the current variance estimate and add 1/4 of that to the running
+ * total.
+ *
+ * Note that the index points at the array entry containing the smoothed
+ * mean value, and the variance is always in the following entry
+ *
+ * Reference: TCP/IP Illustrated, vol 2, p. 831,832
+ * All times are in units of integer nanoseconds. Unlike the TCP/IP case,
+ * they are not scaled fixed point.
+ */
+
+static inline void gfs2_update_stats(struct gfs2_lkstats *s, unsigned index,
+				     s64 sample)
+{
+	s64 delta = sample - s->stats[index];
+	s->stats[index] += (delta >> 3);
+	index++;
+	s->stats[index] += ((abs64(delta) - s->stats[index]) >> 2);
+}
+
+/**
+ * gfs2_update_reply_times - Update locking statistics
+ * @gl: The glock to update
+ *
+ * This assumes that gl->gl_dstamp has been set earlier.
+ *
+ * The rtt (lock round trip time) is an estimate of the time
+ * taken to perform a dlm lock request. We update it on each
+ * reply from the dlm.
+ *
+ * The blocking flag is set on the glock for all dlm requests
+ * which may potentially block due to lock requests from other nodes.
+ * DLM requests where the current lock state is exclusive, the
+ * requested state is null (or unlocked) or where the TRY or
+ * TRY_1CB flags are set are classified as non-blocking. All
+ * other DLM requests are counted as (potentially) blocking.
+ */
+static inline void gfs2_update_reply_times(struct gfs2_glock *gl)
+{
+	struct gfs2_pcpu_lkstats *lks;
+	const unsigned gltype = gl->gl_name.ln_type;
+	unsigned index = test_bit(GLF_BLOCKING, &gl->gl_flags) ?
+			 GFS2_LKS_SRTTB : GFS2_LKS_SRTT;
+	s64 rtt;
+
+	preempt_disable();
+	rtt = ktime_to_ns(ktime_sub(ktime_get_real(), gl->gl_dstamp));
+	lks = this_cpu_ptr(gl->gl_sbd->sd_lkstats);
+	gfs2_update_stats(&gl->gl_stats, index, rtt);		/* Local */
+	gfs2_update_stats(&lks->lkstats[gltype], index, rtt);	/* Global */
+	preempt_enable();
+
+	trace_gfs2_glock_lock_time(gl, rtt);
+}
+
+/**
+ * gfs2_update_request_times - Update locking statistics
+ * @gl: The glock to update
+ *
+ * The irt (lock inter-request times) measures the average time
+ * between requests to the dlm. It is updated immediately before
+ * each dlm call.
+ */
+
+static inline void gfs2_update_request_times(struct gfs2_glock *gl)
+{
+	struct gfs2_pcpu_lkstats *lks;
+	const unsigned gltype = gl->gl_name.ln_type;
+	ktime_t dstamp;
+	s64 irt;
+
+	preempt_disable();
+	dstamp = gl->gl_dstamp;
+	gl->gl_dstamp = ktime_get_real();
+	irt = ktime_to_ns(ktime_sub(gl->gl_dstamp, dstamp));
+	lks = this_cpu_ptr(gl->gl_sbd->sd_lkstats);
+	gfs2_update_stats(&gl->gl_stats, GFS2_LKS_SIRT, irt);		/* Local */
+	gfs2_update_stats(&lks->lkstats[gltype], GFS2_LKS_SIRT, irt);	/* Global */
+	preempt_enable();
+}
+ 
 static void gdlm_ast(void *arg)
 {
 	struct gfs2_glock *gl = arg;
 	unsigned ret = gl->gl_state;
 
+	gfs2_update_reply_times(gl);
 	BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED);
 
 	if (gl->gl_lksb.sb_flags & DLM_SBF_VALNOTVALID)
@@ -111,7 +203,7 @@
 static u32 make_flags(const u32 lkid, const unsigned int gfs_flags,
 		      const int req)
 {
-	u32 lkf = 0;
+	u32 lkf = DLM_LKF_VALBLK;
 
 	if (gfs_flags & LM_FLAG_TRY)
 		lkf |= DLM_LKF_NOQUEUE;
@@ -138,26 +230,43 @@
 	if (lkid != 0) 
 		lkf |= DLM_LKF_CONVERT;
 
-	lkf |= DLM_LKF_VALBLK;
-
 	return lkf;
 }
 
+static void gfs2_reverse_hex(char *c, u64 value)
+{
+	while (value) {
+		*c-- = hex_asc[value & 0x0f];
+		value >>= 4;
+	}
+}
+
 static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
 		     unsigned int flags)
 {
 	struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
 	int req;
 	u32 lkf;
+	char strname[GDLM_STRNAME_BYTES] = "";
 
 	req = make_mode(req_state);
 	lkf = make_flags(gl->gl_lksb.sb_lkid, flags, req);
-
+	gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT);
+	gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT);
+	if (gl->gl_lksb.sb_lkid) {
+		gfs2_update_request_times(gl);
+	} else {
+		memset(strname, ' ', GDLM_STRNAME_BYTES - 1);
+		strname[GDLM_STRNAME_BYTES - 1] = '\0';
+		gfs2_reverse_hex(strname + 7, gl->gl_name.ln_type);
+		gfs2_reverse_hex(strname + 23, gl->gl_name.ln_number);
+		gl->gl_dstamp = ktime_get_real();
+	}
 	/*
 	 * Submit the actual lock request.
 	 */
 
-	return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, gl->gl_strname,
+	return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname,
 			GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast);
 }
 
@@ -172,6 +281,10 @@
 		return;
 	}
 
+	clear_bit(GLF_BLOCKING, &gl->gl_flags);
+	gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT);
+	gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT);
+	gfs2_update_request_times(gl);
 	error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK,
 			   NULL, gl);
 	if (error) {
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 756fae9..4752ead 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -19,6 +19,7 @@
 #include <linux/freezer.h>
 #include <linux/bio.h>
 #include <linux/writeback.h>
+#include <linux/list_sort.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -358,7 +359,7 @@
 	return 0;
 }
 
-static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
+u64 gfs2_log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
 {
 	struct gfs2_journal_extent *je;
 
@@ -467,8 +468,8 @@
 
 void gfs2_log_incr_head(struct gfs2_sbd *sdp)
 {
-	if (sdp->sd_log_flush_head == sdp->sd_log_tail)
-		BUG_ON(sdp->sd_log_flush_head != sdp->sd_log_head);
+	BUG_ON((sdp->sd_log_flush_head == sdp->sd_log_tail) &&
+	       (sdp->sd_log_flush_head != sdp->sd_log_head));
 
 	if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) {
 		sdp->sd_log_flush_head = 0;
@@ -476,99 +477,6 @@
 	}
 }
 
-/**
- * gfs2_log_write_endio - End of I/O for a log buffer
- * @bh: The buffer head
- * @uptodate: I/O Status
- *
- */
-
-static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate)
-{
-	struct gfs2_sbd *sdp = bh->b_private;
-	bh->b_private = NULL;
-
-	end_buffer_write_sync(bh, uptodate);
-	if (atomic_dec_and_test(&sdp->sd_log_in_flight))
-		wake_up(&sdp->sd_log_flush_wait);
-}
-
-/**
- * gfs2_log_get_buf - Get and initialize a buffer to use for log control data
- * @sdp: The GFS2 superblock
- *
- * Returns: the buffer_head
- */
-
-struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp)
-{
-	u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
-	struct buffer_head *bh;
-
-	bh = sb_getblk(sdp->sd_vfs, blkno);
-	lock_buffer(bh);
-	memset(bh->b_data, 0, bh->b_size);
-	set_buffer_uptodate(bh);
-	clear_buffer_dirty(bh);
-	gfs2_log_incr_head(sdp);
-	atomic_inc(&sdp->sd_log_in_flight);
-	bh->b_private = sdp;
-	bh->b_end_io = gfs2_log_write_endio;
-
-	return bh;
-}
-
-/**
- * gfs2_fake_write_endio - 
- * @bh: The buffer head
- * @uptodate: The I/O Status
- *
- */
-
-static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate)
-{
-	struct buffer_head *real_bh = bh->b_private;
-	struct gfs2_bufdata *bd = real_bh->b_private;
-	struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd;
-
-	end_buffer_write_sync(bh, uptodate);
-	free_buffer_head(bh);
-	unlock_buffer(real_bh);
-	brelse(real_bh);
-	if (atomic_dec_and_test(&sdp->sd_log_in_flight))
-		wake_up(&sdp->sd_log_flush_wait);
-}
-
-/**
- * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log
- * @sdp: the filesystem
- * @data: the data the buffer_head should point to
- *
- * Returns: the log buffer descriptor
- */
-
-struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
-				      struct buffer_head *real)
-{
-	u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
-	struct buffer_head *bh;
-
-	bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL);
-	atomic_set(&bh->b_count, 1);
-	bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock);
-	set_bh_page(bh, real->b_page, bh_offset(real));
-	bh->b_blocknr = blkno;
-	bh->b_size = sdp->sd_sb.sb_bsize;
-	bh->b_bdev = sdp->sd_vfs->s_bdev;
-	bh->b_private = real;
-	bh->b_end_io = gfs2_fake_write_endio;
-
-	gfs2_log_incr_head(sdp);
-	atomic_inc(&sdp->sd_log_in_flight);
-
-	return bh;
-}
-
 static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail)
 {
 	unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail);
@@ -583,66 +491,8 @@
 	sdp->sd_log_tail = new_tail;
 }
 
-/**
- * log_write_header - Get and initialize a journal header buffer
- * @sdp: The GFS2 superblock
- *
- * Returns: the initialized log buffer descriptor
- */
 
-static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
-{
-	u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
-	struct buffer_head *bh;
-	struct gfs2_log_header *lh;
-	unsigned int tail;
-	u32 hash;
-
-	bh = sb_getblk(sdp->sd_vfs, blkno);
-	lock_buffer(bh);
-	memset(bh->b_data, 0, bh->b_size);
-	set_buffer_uptodate(bh);
-	clear_buffer_dirty(bh);
-
-	gfs2_ail1_empty(sdp);
-	tail = current_tail(sdp);
-
-	lh = (struct gfs2_log_header *)bh->b_data;
-	memset(lh, 0, sizeof(struct gfs2_log_header));
-	lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
-	lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
-	lh->lh_header.__pad0 = cpu_to_be64(0);
-	lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
-	lh->lh_header.mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid);
-	lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++);
-	lh->lh_flags = cpu_to_be32(flags);
-	lh->lh_tail = cpu_to_be32(tail);
-	lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head);
-	hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header));
-	lh->lh_hash = cpu_to_be32(hash);
-
-	bh->b_end_io = end_buffer_write_sync;
-	get_bh(bh);
-	if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags))
-		submit_bh(WRITE_SYNC | REQ_META | REQ_PRIO, bh);
-	else
-		submit_bh(WRITE_FLUSH_FUA | REQ_META, bh);
-	wait_on_buffer(bh);
-
-	if (!buffer_uptodate(bh))
-		gfs2_io_error_bh(sdp, bh);
-	brelse(bh);
-
-	if (sdp->sd_log_tail != tail)
-		log_pull_tail(sdp, tail);
-	else
-		gfs2_assert_withdraw(sdp, !pull);
-
-	sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
-	gfs2_log_incr_head(sdp);
-}
-
-static void log_flush_commit(struct gfs2_sbd *sdp)
+static void log_flush_wait(struct gfs2_sbd *sdp)
 {
 	DEFINE_WAIT(wait);
 
@@ -655,8 +505,20 @@
 		} while(atomic_read(&sdp->sd_log_in_flight));
 		finish_wait(&sdp->sd_log_flush_wait, &wait);
 	}
+}
 
-	log_write_header(sdp, 0, 0);
+static int bd_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+	struct gfs2_bufdata *bda, *bdb;
+
+	bda = list_entry(a, struct gfs2_bufdata, bd_le.le_list);
+	bdb = list_entry(b, struct gfs2_bufdata, bd_le.le_list);
+
+	if (bda->bd_bh->b_blocknr < bdb->bd_bh->b_blocknr)
+		return -1;
+	if (bda->bd_bh->b_blocknr > bdb->bd_bh->b_blocknr)
+		return 1;
+	return 0;
 }
 
 static void gfs2_ordered_write(struct gfs2_sbd *sdp)
@@ -666,6 +528,7 @@
 	LIST_HEAD(written);
 
 	gfs2_log_lock(sdp);
+	list_sort(NULL, &sdp->sd_log_le_ordered, &bd_cmp);
 	while (!list_empty(&sdp->sd_log_le_ordered)) {
 		bd = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_bufdata, bd_le.le_list);
 		list_move(&bd->bd_le.le_list, &written);
@@ -711,6 +574,68 @@
 }
 
 /**
+ * log_write_header - Get and initialize a journal header buffer
+ * @sdp: The GFS2 superblock
+ *
+ * Returns: the initialized log buffer descriptor
+ */
+
+static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
+{
+	u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head);
+	struct buffer_head *bh;
+	struct gfs2_log_header *lh;
+	unsigned int tail;
+	u32 hash;
+
+	bh = sb_getblk(sdp->sd_vfs, blkno);
+	lock_buffer(bh);
+	memset(bh->b_data, 0, bh->b_size);
+	set_buffer_uptodate(bh);
+	clear_buffer_dirty(bh);
+
+	gfs2_ail1_empty(sdp);
+	tail = current_tail(sdp);
+
+	lh = (struct gfs2_log_header *)bh->b_data;
+	memset(lh, 0, sizeof(struct gfs2_log_header));
+	lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
+	lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
+	lh->lh_header.__pad0 = cpu_to_be64(0);
+	lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
+	lh->lh_header.mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid);
+	lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++);
+	lh->lh_flags = cpu_to_be32(flags);
+	lh->lh_tail = cpu_to_be32(tail);
+	lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head);
+	hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header));
+	lh->lh_hash = cpu_to_be32(hash);
+
+	bh->b_end_io = end_buffer_write_sync;
+	get_bh(bh);
+	if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) {
+		gfs2_ordered_wait(sdp);
+		log_flush_wait(sdp);
+		submit_bh(WRITE_SYNC | REQ_META | REQ_PRIO, bh);
+	} else {
+		submit_bh(WRITE_FLUSH_FUA | REQ_META, bh);
+	}
+	wait_on_buffer(bh);
+
+	if (!buffer_uptodate(bh))
+		gfs2_io_error_bh(sdp, bh);
+	brelse(bh);
+
+	if (sdp->sd_log_tail != tail)
+		log_pull_tail(sdp, tail);
+	else
+		gfs2_assert_withdraw(sdp, !pull);
+
+	sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
+	gfs2_log_incr_head(sdp);
+}
+
+/**
  * gfs2_log_flush - flush incore transaction(s)
  * @sdp: the filesystem
  * @gl: The glock structure to flush.  If NULL, flush the whole incore log
@@ -753,11 +678,10 @@
 
 	gfs2_ordered_write(sdp);
 	lops_before_commit(sdp);
-	gfs2_ordered_wait(sdp);
 
-	if (sdp->sd_log_head != sdp->sd_log_flush_head)
-		log_flush_commit(sdp);
-	else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
+	if (sdp->sd_log_head != sdp->sd_log_flush_head) {
+		log_write_header(sdp, 0, 0);
+	} else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
 		gfs2_log_lock(sdp);
 		atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */
 		trace_gfs2_log_blocks(sdp, -1);
diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h
index ab06216..ff07454 100644
--- a/fs/gfs2/log.h
+++ b/fs/gfs2/log.h
@@ -53,10 +53,7 @@
 
 extern int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
 extern void gfs2_log_incr_head(struct gfs2_sbd *sdp);
-
-extern struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
-extern struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
-				      struct buffer_head *real);
+extern u64 gfs2_log_bmap(struct gfs2_sbd *sdp, unsigned int lbn);
 extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
 extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
 extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd);
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index df7c6e8..6b1efb5 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -12,6 +12,7 @@
 #include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/buffer_head.h>
+#include <linux/mempool.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/bio.h>
 #include <linux/fs.h>
@@ -76,7 +77,7 @@
 	if (bi->bi_clone == 0)
 		return;
 	if (sdp->sd_args.ar_discard)
-		gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi);
+		gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi, 1, NULL);
 	memcpy(bi->bi_clone + bi->bi_offset,
 	       bd->bd_bh->b_data + bi->bi_offset, bi->bi_len);
 	clear_bit(GBF_FULL, &bi->bi_flags);
@@ -143,6 +144,98 @@
 	return (__force __be64 *)(bh->b_data + bh->b_size);
 }
 
+/**
+ * gfs2_log_write_endio - End of I/O for a log buffer
+ * @bh: The buffer head
+ * @uptodate: I/O Status
+ *
+ */
+
+static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate)
+{
+	struct gfs2_sbd *sdp = bh->b_private;
+	bh->b_private = NULL;
+
+	end_buffer_write_sync(bh, uptodate);
+	if (atomic_dec_and_test(&sdp->sd_log_in_flight))
+		wake_up(&sdp->sd_log_flush_wait);
+}
+
+/**
+ * gfs2_log_get_buf - Get and initialize a buffer to use for log control data
+ * @sdp: The GFS2 superblock
+ *
+ * tReturns: the buffer_head
+ */
+
+static struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp)
+{
+	u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head);
+	struct buffer_head *bh;
+
+	bh = sb_getblk(sdp->sd_vfs, blkno);
+	lock_buffer(bh);
+	memset(bh->b_data, 0, bh->b_size);
+	set_buffer_uptodate(bh);
+	clear_buffer_dirty(bh);
+	gfs2_log_incr_head(sdp);
+	atomic_inc(&sdp->sd_log_in_flight);
+	bh->b_private = sdp;
+	bh->b_end_io = gfs2_log_write_endio;
+
+	return bh;
+}
+
+/**
+ * gfs2_fake_write_endio - 
+ * @bh: The buffer head
+ * @uptodate: The I/O Status
+ *
+ */
+
+static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate)
+{
+	struct buffer_head *real_bh = bh->b_private;
+	struct gfs2_bufdata *bd = real_bh->b_private;
+	struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd;
+
+	end_buffer_write_sync(bh, uptodate);
+	mempool_free(bh, gfs2_bh_pool);
+	unlock_buffer(real_bh);
+	brelse(real_bh);
+	if (atomic_dec_and_test(&sdp->sd_log_in_flight))
+		wake_up(&sdp->sd_log_flush_wait);
+}
+
+/**
+ * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log
+ * @sdp: the filesystem
+ * @data: the data the buffer_head should point to
+ *
+ * Returns: the log buffer descriptor
+ */
+
+static struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
+				      struct buffer_head *real)
+{
+	u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head);
+	struct buffer_head *bh;
+
+	bh = mempool_alloc(gfs2_bh_pool, GFP_NOFS);
+	atomic_set(&bh->b_count, 1);
+	bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock);
+	set_bh_page(bh, real->b_page, bh_offset(real));
+	bh->b_blocknr = blkno;
+	bh->b_size = sdp->sd_sb.sb_bsize;
+	bh->b_bdev = sdp->sd_vfs->s_bdev;
+	bh->b_private = real;
+	bh->b_end_io = gfs2_fake_write_endio;
+
+	gfs2_log_incr_head(sdp);
+	atomic_inc(&sdp->sd_log_in_flight);
+
+	return bh;
+}
 
 static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type)
 {
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index a8d9bcd0..754426b 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -17,6 +17,7 @@
 #include <linux/rcupdate.h>
 #include <linux/rculist_bl.h>
 #include <linux/atomic.h>
+#include <linux/mempool.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -69,6 +70,16 @@
 	address_space_init_once(mapping);
 }
 
+static void *gfs2_bh_alloc(gfp_t mask, void *data)
+{
+	return alloc_buffer_head(mask);
+}
+
+static void gfs2_bh_free(void *ptr, void *data)
+{
+	return free_buffer_head(ptr);
+}
+
 /**
  * init_gfs2_fs - Register GFS2 as a filesystem
  *
@@ -151,6 +162,10 @@
 	gfs2_control_wq = alloc_workqueue("gfs2_control",
 			       WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE, 0);
 	if (!gfs2_control_wq)
+		goto fail_recovery;
+
+	gfs2_bh_pool = mempool_create(1024, gfs2_bh_alloc, gfs2_bh_free, NULL);
+	if (!gfs2_bh_pool)
 		goto fail_control;
 
 	gfs2_register_debugfs();
@@ -160,6 +175,8 @@
 	return 0;
 
 fail_control:
+	destroy_workqueue(gfs2_control_wq);
+fail_recovery:
 	destroy_workqueue(gfs_recovery_wq);
 fail_wq:
 	unregister_filesystem(&gfs2meta_fs_type);
@@ -208,6 +225,7 @@
 
 	rcu_barrier();
 
+	mempool_destroy(gfs2_bh_pool);
 	kmem_cache_destroy(gfs2_quotad_cachep);
 	kmem_cache_destroy(gfs2_rgrpd_cachep);
 	kmem_cache_destroy(gfs2_bufdata_cachep);
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 24f609c..6f3a18f 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -68,6 +68,12 @@
 
 	sb->s_fs_info = sdp;
 	sdp->sd_vfs = sb;
+	sdp->sd_lkstats = alloc_percpu(struct gfs2_pcpu_lkstats);
+	if (!sdp->sd_lkstats) {
+		kfree(sdp);
+		return NULL;
+	}
+
 	set_bit(SDF_NOJOURNALID, &sdp->sd_flags);
 	gfs2_tune_init(&sdp->sd_tune);
 
@@ -77,7 +83,6 @@
 	spin_lock_init(&sdp->sd_statfs_spin);
 
 	spin_lock_init(&sdp->sd_rindex_spin);
-	mutex_init(&sdp->sd_rindex_mutex);
 	sdp->sd_rindex_tree.rb_node = NULL;
 
 	INIT_LIST_HEAD(&sdp->sd_jindex_list);
@@ -431,10 +436,9 @@
 		fs_err(sdp, "can't read in %s inode: %ld\n", name, PTR_ERR(inode));
 		return PTR_ERR(inode);
 	}
-	dentry = d_alloc_root(inode);
+	dentry = d_make_root(inode);
 	if (!dentry) {
 		fs_err(sdp, "can't alloc %s dentry\n", name);
-		iput(inode);
 		return -ENOMEM;
 	}
 	*dptr = dentry;
@@ -1221,6 +1225,7 @@
 	gfs2_sys_fs_del(sdp);
 fail:
 	gfs2_delete_debugfs_file(sdp);
+	free_percpu(sdp->sd_lkstats);
 	kfree(sdp);
 	sb->s_fs_info = NULL;
 	return error;
@@ -1393,6 +1398,7 @@
 	shrink_dcache_sb(sb);
 	kill_block_super(sb);
 	gfs2_delete_debugfs_file(sdp);
+	free_percpu(sdp->sd_lkstats);
 	kfree(sdp);
 }
 
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index c0f8904..6019da3 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -681,7 +681,7 @@
 	ptr = qp;
 	nbytes = sizeof(struct gfs2_quota);
 get_a_page:
-	page = grab_cache_page(mapping, index);
+	page = find_or_create_page(mapping, index, GFP_NOFS);
 	if (!page)
 		return -ENOMEM;
 
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 49ada95..19bde40 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -327,23 +327,34 @@
  * Returns: The resource group, or NULL if not found
  */
 
-struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk)
+struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk, bool exact)
 {
-	struct rb_node **newn;
+	struct rb_node *n, *next;
 	struct gfs2_rgrpd *cur;
 
+	if (gfs2_rindex_update(sdp))
+		return NULL;
+
 	spin_lock(&sdp->sd_rindex_spin);
-	newn = &sdp->sd_rindex_tree.rb_node;
-	while (*newn) {
-		cur = rb_entry(*newn, struct gfs2_rgrpd, rd_node);
+	n = sdp->sd_rindex_tree.rb_node;
+	while (n) {
+		cur = rb_entry(n, struct gfs2_rgrpd, rd_node);
+		next = NULL;
 		if (blk < cur->rd_addr)
-			newn = &((*newn)->rb_left);
+			next = n->rb_left;
 		else if (blk >= cur->rd_data0 + cur->rd_data)
-			newn = &((*newn)->rb_right);
-		else {
+			next = n->rb_right;
+		if (next == NULL) {
 			spin_unlock(&sdp->sd_rindex_spin);
+			if (exact) {
+				if (blk < cur->rd_addr)
+					return NULL;
+				if (blk >= cur->rd_data0 + cur->rd_data)
+					return NULL;
+			}
 			return cur;
 		}
+		n = next;
 	}
 	spin_unlock(&sdp->sd_rindex_spin);
 
@@ -532,7 +543,6 @@
 	struct file_ra_state ra_state;
 	int error, rgrps;
 
-	mutex_lock(&sdp->sd_rindex_mutex);
 	file_ra_state_init(&ra_state, inode->i_mapping);
 	for (rgrps = 0;; rgrps++) {
 		loff_t pos = rgrps * sizeof(struct gfs2_rindex);
@@ -545,11 +555,10 @@
 			break;
 		total_data += be32_to_cpu(((struct gfs2_rindex *)buf)->ri_data);
 	}
-	mutex_unlock(&sdp->sd_rindex_mutex);
 	return total_data;
 }
 
-static void rgd_insert(struct gfs2_rgrpd *rgd)
+static int rgd_insert(struct gfs2_rgrpd *rgd)
 {
 	struct gfs2_sbd *sdp = rgd->rd_sbd;
 	struct rb_node **newn = &sdp->sd_rindex_tree.rb_node, *parent = NULL;
@@ -565,11 +574,13 @@
 		else if (rgd->rd_addr > cur->rd_addr)
 			newn = &((*newn)->rb_right);
 		else
-			return;
+			return -EEXIST;
 	}
 
 	rb_link_node(&rgd->rd_node, parent, newn);
 	rb_insert_color(&rgd->rd_node, &sdp->sd_rindex_tree);
+	sdp->sd_rgrps++;
+	return 0;
 }
 
 /**
@@ -623,10 +634,12 @@
 	if (rgd->rd_data > sdp->sd_max_rg_data)
 		sdp->sd_max_rg_data = rgd->rd_data;
 	spin_lock(&sdp->sd_rindex_spin);
-	rgd_insert(rgd);
-	sdp->sd_rgrps++;
+	error = rgd_insert(rgd);
 	spin_unlock(&sdp->sd_rindex_spin);
-	return error;
+	if (!error)
+		return 0;
+
+	error = 0; /* someone else read in the rgrp; free it and ignore it */
 
 fail:
 	kfree(rgd->rd_bits);
@@ -687,7 +700,6 @@
 
 	/* Read new copy from disk if we don't have the latest */
 	if (!sdp->sd_rindex_uptodate) {
-		mutex_lock(&sdp->sd_rindex_mutex);
 		if (!gfs2_glock_is_locked_by_me(gl)) {
 			error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, &ri_gh);
 			if (error)
@@ -698,10 +710,8 @@
 			error = gfs2_ri_update(ip);
 		if (unlock_required)
 			gfs2_glock_dq_uninit(&ri_gh);
-		mutex_unlock(&sdp->sd_rindex_mutex);
 	}
 
-
 	return error;
 }
 
@@ -810,9 +820,9 @@
 
 }
 
-void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
+int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
 			     struct buffer_head *bh,
-			     const struct gfs2_bitmap *bi)
+			     const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed)
 {
 	struct super_block *sb = sdp->sd_vfs;
 	struct block_device *bdev = sb->s_bdev;
@@ -823,11 +833,19 @@
 	sector_t nr_sects = 0;
 	int rv;
 	unsigned int x;
+	u32 trimmed = 0;
+	u8 diff;
 
 	for (x = 0; x < bi->bi_len; x++) {
-		const u8 *orig = bh->b_data + bi->bi_offset + x;
-		const u8 *clone = bi->bi_clone + bi->bi_offset + x;
-		u8 diff = ~(*orig | (*orig >> 1)) & (*clone | (*clone >> 1));
+		const u8 *clone = bi->bi_clone ? bi->bi_clone : bi->bi_bh->b_data;
+		clone += bi->bi_offset;
+		clone += x;
+		if (bh) {
+			const u8 *orig = bh->b_data + bi->bi_offset + x;
+			diff = ~(*orig | (*orig >> 1)) & (*clone | (*clone >> 1));
+		} else {
+			diff = ~(*clone | (*clone >> 1));
+		}
 		diff &= 0x55;
 		if (diff == 0)
 			continue;
@@ -838,11 +856,14 @@
 				if (nr_sects == 0)
 					goto start_new_extent;
 				if ((start + nr_sects) != blk) {
-					rv = blkdev_issue_discard(bdev, start,
-							    nr_sects, GFP_NOFS,
-							    0);
-					if (rv)
-						goto fail;
+					if (nr_sects >= minlen) {
+						rv = blkdev_issue_discard(bdev,
+							start, nr_sects,
+							GFP_NOFS, 0);
+						if (rv)
+							goto fail;
+						trimmed += nr_sects;
+					}
 					nr_sects = 0;
 start_new_extent:
 					start = blk;
@@ -853,15 +874,104 @@
 			blk += sects_per_blk;
 		}
 	}
-	if (nr_sects) {
+	if (nr_sects >= minlen) {
 		rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS, 0);
 		if (rv)
 			goto fail;
+		trimmed += nr_sects;
 	}
-	return;
+	if (ptrimmed)
+		*ptrimmed = trimmed;
+	return 0;
+
 fail:
-	fs_warn(sdp, "error %d on discard request, turning discards off for this filesystem", rv);
+	if (sdp->sd_args.ar_discard)
+		fs_warn(sdp, "error %d on discard request, turning discards off for this filesystem", rv);
 	sdp->sd_args.ar_discard = 0;
+	return -EIO;
+}
+
+/**
+ * gfs2_fitrim - Generate discard requests for unused bits of the filesystem
+ * @filp: Any file on the filesystem
+ * @argp: Pointer to the arguments (also used to pass result)
+ *
+ * Returns: 0 on success, otherwise error code
+ */
+
+int gfs2_fitrim(struct file *filp, void __user *argp)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+	struct request_queue *q = bdev_get_queue(sdp->sd_vfs->s_bdev);
+	struct buffer_head *bh;
+	struct gfs2_rgrpd *rgd;
+	struct gfs2_rgrpd *rgd_end;
+	struct gfs2_holder gh;
+	struct fstrim_range r;
+	int ret = 0;
+	u64 amt;
+	u64 trimmed = 0;
+	unsigned int x;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (!blk_queue_discard(q))
+		return -EOPNOTSUPP;
+
+	if (argp == NULL) {
+		r.start = 0;
+		r.len = ULLONG_MAX;
+		r.minlen = 0;
+	} else if (copy_from_user(&r, argp, sizeof(r)))
+		return -EFAULT;
+
+	rgd = gfs2_blk2rgrpd(sdp, r.start, 0);
+	rgd_end = gfs2_blk2rgrpd(sdp, r.start + r.len, 0);
+
+	while (1) {
+
+		ret = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &gh);
+		if (ret)
+			goto out;
+
+		if (!(rgd->rd_flags & GFS2_RGF_TRIMMED)) {
+			/* Trim each bitmap in the rgrp */
+			for (x = 0; x < rgd->rd_length; x++) {
+				struct gfs2_bitmap *bi = rgd->rd_bits + x;
+				ret = gfs2_rgrp_send_discards(sdp, rgd->rd_data0, NULL, bi, r.minlen, &amt);
+				if (ret) {
+					gfs2_glock_dq_uninit(&gh);
+					goto out;
+				}
+				trimmed += amt;
+			}
+
+			/* Mark rgrp as having been trimmed */
+			ret = gfs2_trans_begin(sdp, RES_RG_HDR, 0);
+			if (ret == 0) {
+				bh = rgd->rd_bits[0].bi_bh;
+				rgd->rd_flags |= GFS2_RGF_TRIMMED;
+				gfs2_trans_add_bh(rgd->rd_gl, bh, 1);
+				gfs2_rgrp_out(rgd, bh->b_data);
+				gfs2_trans_end(sdp);
+			}
+		}
+		gfs2_glock_dq_uninit(&gh);
+
+		if (rgd == rgd_end)
+			break;
+
+		rgd = gfs2_rgrpd_get_next(rgd);
+	}
+
+out:
+	r.len = trimmed << 9;
+	if (argp && copy_to_user(argp, &r, sizeof(r)))
+		return -EFAULT;
+
+	return ret;
 }
 
 /**
@@ -1008,7 +1118,7 @@
 	if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, ip->i_goal))
 		rgd = begin = ip->i_rgd;
 	else
-		rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal);
+		rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal, 1);
 
 	if (rgd == NULL)
 		return -EBADSLT;
@@ -1293,7 +1403,7 @@
 	u32 length, rgrp_blk, buf_blk;
 	unsigned int buf;
 
-	rgd = gfs2_blk2rgrpd(sdp, bstart);
+	rgd = gfs2_blk2rgrpd(sdp, bstart, 1);
 	if (!rgd) {
 		if (gfs2_consist(sdp))
 			fs_err(sdp, "block = %llu\n", (unsigned long long)bstart);
@@ -1474,7 +1584,7 @@
 		return;
 	trace_gfs2_block_alloc(ip, bstart, blen, GFS2_BLKST_FREE);
 	rgd->rd_free += blen;
-
+	rgd->rd_flags &= ~GFS2_RGF_TRIMMED;
 	gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
 	gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
 
@@ -1560,14 +1670,9 @@
 {
 	struct gfs2_rgrpd *rgd;
 	struct gfs2_holder rgd_gh;
-	int error;
+	int error = -EINVAL;
 
-	error = gfs2_rindex_update(sdp);
-	if (error)
-		return error;
-
-	error = -EINVAL;
-	rgd = gfs2_blk2rgrpd(sdp, no_addr);
+	rgd = gfs2_blk2rgrpd(sdp, no_addr, 1);
 	if (!rgd)
 		goto fail;
 
@@ -1610,7 +1715,7 @@
 	if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, block))
 		rgd = ip->i_rgd;
 	else
-		rgd = gfs2_blk2rgrpd(sdp, block);
+		rgd = gfs2_blk2rgrpd(sdp, block, 1);
 	if (!rgd) {
 		fs_err(sdp, "rlist_add: no rgrp for block %llu\n", (unsigned long long)block);
 		return;
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h
index ceec910..b4b10f4 100644
--- a/fs/gfs2/rgrp.h
+++ b/fs/gfs2/rgrp.h
@@ -11,6 +11,7 @@
 #define __RGRP_DOT_H__
 
 #include <linux/slab.h>
+#include <linux/uaccess.h>
 
 struct gfs2_rgrpd;
 struct gfs2_sbd;
@@ -18,7 +19,7 @@
 
 extern void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd);
 
-extern struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk);
+extern struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk, bool exact);
 extern struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp);
 extern struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd);
 
@@ -62,8 +63,9 @@
 extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist);
 extern u64 gfs2_ri_total(struct gfs2_sbd *sdp);
 extern int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl);
-extern void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
-				    struct buffer_head *bh,
-				    const struct gfs2_bitmap *bi);
+extern int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
+				   struct buffer_head *bh,
+				   const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed);
+extern int gfs2_fitrim(struct file *filp, void __user *argp);
 
 #endif /* __RGRP_DOT_H__ */
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 4553ce5..6172fa7 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1417,7 +1417,7 @@
 	if (error)
 		goto out;
 
-	rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);
+	rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr, 1);
 	if (!rgd) {
 		gfs2_consist_inode(ip);
 		error = -EIO;
@@ -1557,6 +1557,7 @@
 	end_writeback(inode);
 	gfs2_dir_hash_inval(ip);
 	ip->i_gl->gl_object = NULL;
+	flush_delayed_work_sync(&ip->i_gl->gl_work);
 	gfs2_glock_add_to_lru(ip->i_gl);
 	gfs2_glock_put(ip->i_gl);
 	ip->i_gl = NULL;
diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h
index 5d07609..dfa89cd 100644
--- a/fs/gfs2/trace_gfs2.h
+++ b/fs/gfs2/trace_gfs2.h
@@ -11,6 +11,7 @@
 #include <linux/dlmconstants.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/writeback.h>
+#include <linux/ktime.h>
 #include "incore.h"
 #include "glock.h"
 
@@ -43,7 +44,8 @@
 	{(1UL << GLF_FROZEN),			"F" },		\
 	{(1UL << GLF_QUEUED),			"q" },		\
 	{(1UL << GLF_LRU),			"L" },		\
-	{(1UL << GLF_OBJECT),			"o" })
+	{(1UL << GLF_OBJECT),			"o" },		\
+	{(1UL << GLF_BLOCKING),			"b" })
 
 #ifndef NUMPTY
 #define NUMPTY
@@ -236,6 +238,62 @@
 		  glock_trace_name(__entry->state))
 );
 
+/* DLM sends a reply to GFS2 */
+TRACE_EVENT(gfs2_glock_lock_time,
+
+	TP_PROTO(const struct gfs2_glock *gl, s64 tdiff),
+
+	TP_ARGS(gl, tdiff),
+
+	TP_STRUCT__entry(
+		__field(	dev_t,	dev		)
+		__field(	u64,	glnum		)
+		__field(	u32,	gltype		)
+		__field(	int,	status		)
+		__field(	char,	flags		)
+		__field(	s64,	tdiff		)
+		__field(	s64,	srtt		)
+		__field(	s64,	srttvar		)
+		__field(	s64,	srttb		)
+		__field(	s64,	srttvarb	)
+		__field(	s64,	sirt		)
+		__field(	s64,	sirtvar		)
+		__field(	s64,	dcount		)
+		__field(	s64,	qcount		)
+	),
+
+	TP_fast_assign(
+		__entry->dev            = gl->gl_sbd->sd_vfs->s_dev;
+		__entry->glnum          = gl->gl_name.ln_number;
+		__entry->gltype         = gl->gl_name.ln_type;
+		__entry->status		= gl->gl_lksb.sb_status;
+		__entry->flags		= gl->gl_lksb.sb_flags;
+		__entry->tdiff		= tdiff;
+		__entry->srtt		= gl->gl_stats.stats[GFS2_LKS_SRTT];
+		__entry->srttvar	= gl->gl_stats.stats[GFS2_LKS_SRTTVAR];
+		__entry->srttb		= gl->gl_stats.stats[GFS2_LKS_SRTTB];
+		__entry->srttvarb	= gl->gl_stats.stats[GFS2_LKS_SRTTVARB];
+		__entry->sirt		= gl->gl_stats.stats[GFS2_LKS_SIRT];
+		__entry->sirtvar	= gl->gl_stats.stats[GFS2_LKS_SIRTVAR];
+		__entry->dcount		= gl->gl_stats.stats[GFS2_LKS_DCOUNT];
+		__entry->qcount		= gl->gl_stats.stats[GFS2_LKS_QCOUNT];
+	),
+
+	TP_printk("%u,%u glock %d:%lld status:%d flags:%02x tdiff:%lld srtt:%lld/%lld srttb:%lld/%lld sirt:%lld/%lld dcnt:%lld qcnt:%lld",
+		  MAJOR(__entry->dev), MINOR(__entry->dev), __entry->gltype,
+		  (unsigned long long)__entry->glnum,
+		  __entry->status, __entry->flags,
+		  (long long)__entry->tdiff,
+		  (long long)__entry->srtt,
+		  (long long)__entry->srttvar,
+		  (long long)__entry->srttb,
+		  (long long)__entry->srttvarb,
+		  (long long)__entry->sirt,
+		  (long long)__entry->sirtvar,
+		  (long long)__entry->dcount,
+		  (long long)__entry->qcount)
+);
+
 /* Section 2 - Log/journal
  *
  * Objectives:
diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c
index 5351129..9e7765e 100644
--- a/fs/gfs2/util.c
+++ b/fs/gfs2/util.c
@@ -25,6 +25,7 @@
 struct kmem_cache *gfs2_bufdata_cachep __read_mostly;
 struct kmem_cache *gfs2_rgrpd_cachep __read_mostly;
 struct kmem_cache *gfs2_quotad_cachep __read_mostly;
+mempool_t *gfs2_bh_pool __read_mostly;
 
 void gfs2_assert_i(struct gfs2_sbd *sdp)
 {
diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h
index b432e04..a4ce76c 100644
--- a/fs/gfs2/util.h
+++ b/fs/gfs2/util.h
@@ -10,6 +10,8 @@
 #ifndef __UTIL_DOT_H__
 #define __UTIL_DOT_H__
 
+#include <linux/mempool.h>
+
 #include "incore.h"
 
 #define fs_printk(level, fs, fmt, arg...) \
@@ -150,6 +152,7 @@
 extern struct kmem_cache *gfs2_bufdata_cachep;
 extern struct kmem_cache *gfs2_rgrpd_cachep;
 extern struct kmem_cache *gfs2_quotad_cachep;
+extern mempool_t *gfs2_bh_pool;
 
 static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt,
 					   unsigned int *p)
diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c
index e963659..2e5ba42 100644
--- a/fs/gfs2/xattr.c
+++ b/fs/gfs2/xattr.c
@@ -251,7 +251,7 @@
 	if (!blks)
 		return 0;
 
-	rgd = gfs2_blk2rgrpd(sdp, bn);
+	rgd = gfs2_blk2rgrpd(sdp, bn, 1);
 	if (!rgd) {
 		gfs2_consist_inode(ip);
 		return -EIO;
@@ -1439,7 +1439,7 @@
 	struct gfs2_holder gh;
 	int error;
 
-	rgd = gfs2_blk2rgrpd(sdp, ip->i_eattr);
+	rgd = gfs2_blk2rgrpd(sdp, ip->i_eattr, 1);
 	if (!rgd) {
 		gfs2_consist_inode(ip);
 		return -EIO;
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 8137fb3..7b4c537 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -430,15 +430,13 @@
 
 	sb->s_d_op = &hfs_dentry_operations;
 	res = -ENOMEM;
-	sb->s_root = d_alloc_root(root_inode);
+	sb->s_root = d_make_root(root_inode);
 	if (!sb->s_root)
-		goto bail_iput;
+		goto bail_no_root;
 
 	/* everything's okay */
 	return 0;
 
-bail_iput:
-	iput(root_inode);
 bail_no_root:
 	printk(KERN_ERR "hfs: get root inode failed.\n");
 bail:
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index 21a5b7f..4e75ac6 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -317,6 +317,11 @@
 
 
 /*
+ * hfs+-specific ioctl for making the filesystem bootable
+ */
+#define HFSPLUS_IOC_BLESS _IO('h', 0x80)
+
+/*
  * Functions in any *.c used in other files
  */
 
diff --git a/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h
index 927cdd6..921967e 100644
--- a/fs/hfsplus/hfsplus_raw.h
+++ b/fs/hfsplus/hfsplus_raw.h
@@ -117,7 +117,7 @@
 	__be32 write_count;
 	__be64 encodings_bmp;
 
-	u8 finder_info[32];
+	u32 finder_info[8];
 
 	struct hfsplus_fork_raw alloc_file;
 	struct hfsplus_fork_raw ext_file;
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 6643b24..82b69ee 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -193,6 +193,7 @@
 	mutex_init(&hip->extents_lock);
 	hip->extent_state = 0;
 	hip->flags = 0;
+	hip->userflags = 0;
 	set_bit(HFSPLUS_I_RSRC, &hip->flags);
 
 	err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
@@ -400,6 +401,7 @@
 	atomic_set(&hip->opencnt, 0);
 	hip->extent_state = 0;
 	hip->flags = 0;
+	hip->userflags = 0;
 	memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
 	memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
 	hip->alloc_blocks = 0;
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c
index f66c765..c640ba5 100644
--- a/fs/hfsplus/ioctl.c
+++ b/fs/hfsplus/ioctl.c
@@ -20,6 +20,38 @@
 #include <asm/uaccess.h>
 #include "hfsplus_fs.h"
 
+/*
+ * "Blessing" an HFS+ filesystem writes metadata to the superblock informing
+ * the platform firmware which file to boot from
+ */
+static int hfsplus_ioctl_bless(struct file *file, int __user *user_flags)
+{
+	struct dentry *dentry = file->f_path.dentry;
+	struct inode *inode = dentry->d_inode;
+	struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
+	struct hfsplus_vh *vh = sbi->s_vhdr;
+	struct hfsplus_vh *bvh = sbi->s_backup_vhdr;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	mutex_lock(&sbi->vh_mutex);
+
+	/* Directory containing the bootable system */
+	vh->finder_info[0] = bvh->finder_info[0] =
+		cpu_to_be32(parent_ino(dentry));
+
+	/* Bootloader */
+	vh->finder_info[1] = bvh->finder_info[1] = cpu_to_be32(inode->i_ino);
+
+	/* Per spec, the OS X system folder - same as finder_info[0] here */
+	vh->finder_info[5] = bvh->finder_info[5] =
+		cpu_to_be32(parent_ino(dentry));
+
+	mutex_unlock(&sbi->vh_mutex);
+	return 0;
+}
+
 static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
 {
 	struct inode *inode = file->f_path.dentry->d_inode;
@@ -108,6 +140,8 @@
 		return hfsplus_ioctl_getflags(file, argp);
 	case HFSPLUS_IOC_EXT2_SETFLAGS:
 		return hfsplus_ioctl_setflags(file, argp);
+	case HFSPLUS_IOC_BLESS:
+		return hfsplus_ioctl_bless(file, argp);
 	default:
 		return -ENOTTY;
 	}
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 427682c..ceb1c28 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -465,6 +465,13 @@
 		goto out_put_alloc_file;
 	}
 
+	sb->s_d_op = &hfsplus_dentry_operations;
+	sb->s_root = d_make_root(root);
+	if (!sb->s_root) {
+		err = -ENOMEM;
+		goto out_put_alloc_file;
+	}
+
 	str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
 	str.name = HFSP_HIDDENDIR_NAME;
 	err = hfs_find_init(sbi->cat_tree, &fd);
@@ -515,13 +522,6 @@
 		}
 	}
 
-	sb->s_d_op = &hfsplus_dentry_operations;
-	sb->s_root = d_alloc_root(root);
-	if (!sb->s_root) {
-		err = -ENOMEM;
-		goto out_put_hidden_dir;
-	}
-
 	unload_nls(sbi->nls);
 	sbi->nls = nls;
 	return 0;
@@ -529,7 +529,8 @@
 out_put_hidden_dir:
 	iput(sbi->hidden_dir);
 out_put_root:
-	iput(root);
+	dput(sb->s_root);
+	sb->s_root = NULL;
 out_put_alloc_file:
 	iput(sbi->alloc_file);
 out_close_cat_tree:
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
index 3cbfa93..1fe7313 100644
--- a/fs/hostfs/hostfs.h
+++ b/fs/hostfs/hostfs.h
@@ -67,7 +67,8 @@
 extern int open_file(char *path, int r, int w, int append);
 extern void *open_dir(char *path, int *err_out);
 extern char *read_dir(void *stream, unsigned long long *pos,
-		      unsigned long long *ino_out, int *len_out);
+		      unsigned long long *ino_out, int *len_out,
+		      unsigned int *type_out);
 extern void close_file(void *stream);
 extern int replace_file(int oldfd, int fd);
 extern void close_dir(void *stream);
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index e130bd4..07c516b 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -283,6 +283,7 @@
 	char *name;
 	unsigned long long next, ino;
 	int error, len;
+	unsigned int type;
 
 	name = dentry_name(file->f_path.dentry);
 	if (name == NULL)
@@ -292,9 +293,9 @@
 	if (dir == NULL)
 		return -error;
 	next = file->f_pos;
-	while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
+	while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
 		error = (*filldir)(ent, name, len, file->f_pos,
-				   ino, DT_UNKNOWN);
+				   ino, type);
 		if (error) break;
 		file->f_pos = next;
 	}
@@ -966,9 +967,9 @@
 	}
 
 	err = -ENOMEM;
-	sb->s_root = d_alloc_root(root_inode);
+	sb->s_root = d_make_root(root_inode);
 	if (sb->s_root == NULL)
-		goto out_put;
+		goto out;
 
 	return 0;
 
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
index dd7bc38..a74ad0d 100644
--- a/fs/hostfs/hostfs_user.c
+++ b/fs/hostfs/hostfs_user.c
@@ -98,7 +98,8 @@
 }
 
 char *read_dir(void *stream, unsigned long long *pos,
-	       unsigned long long *ino_out, int *len_out)
+	       unsigned long long *ino_out, int *len_out,
+	       unsigned int *type_out)
 {
 	DIR *dir = stream;
 	struct dirent *ent;
@@ -109,6 +110,7 @@
 		return NULL;
 	*len_out = strlen(ent->d_name);
 	*ino_out = ent->d_ino;
+	*type_out = ent->d_type;
 	*pos = telldir(dir);
 	return ent->d_name;
 }
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index 3690467c9..54f6ecc 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -625,11 +625,9 @@
 	hpfs_init_inode(root);
 	hpfs_read_inode(root);
 	unlock_new_inode(root);
-	s->s_root = d_alloc_root(root);
-	if (!s->s_root) {
-		iput(root);
+	s->s_root = d_make_root(root);
+	if (!s->s_root)
 		goto bail0;
-	}
 
 	/*
 	 * find the root directory's . pointer & finish filling in the inode
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c
index d92f4ce..a80e45a 100644
--- a/fs/hppfs/hppfs.c
+++ b/fs/hppfs/hppfs.c
@@ -726,17 +726,12 @@
 
 	err = -ENOMEM;
 	root_inode = get_inode(sb, dget(proc_mnt->mnt_root));
-	if (!root_inode)
-		goto out_mntput;
-
-	sb->s_root = d_alloc_root(root_inode);
+	sb->s_root = d_make_root(root_inode);
 	if (!sb->s_root)
-		goto out_iput;
+		goto out_mntput;
 
 	return 0;
 
- out_iput:
-	iput(root_inode);
  out_mntput:
 	mntput(proc_mnt);
  out:
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 1e85a7a..28cf06e 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -41,6 +41,25 @@
 static const struct inode_operations hugetlbfs_dir_inode_operations;
 static const struct inode_operations hugetlbfs_inode_operations;
 
+struct hugetlbfs_config {
+	uid_t   uid;
+	gid_t   gid;
+	umode_t mode;
+	long	nr_blocks;
+	long	nr_inodes;
+	struct hstate *hstate;
+};
+
+struct hugetlbfs_inode_info {
+	struct shared_policy policy;
+	struct inode vfs_inode;
+};
+
+static inline struct hugetlbfs_inode_info *HUGETLBFS_I(struct inode *inode)
+{
+	return container_of(inode, struct hugetlbfs_inode_info, vfs_inode);
+}
+
 static struct backing_dev_info hugetlbfs_backing_dev_info = {
 	.name		= "hugetlbfs",
 	.ra_pages	= 0,	/* No readahead */
@@ -154,10 +173,12 @@
 			return addr;
 	}
 
-	start_addr = mm->free_area_cache;
-
-	if (len <= mm->cached_hole_size)
+	if (len > mm->cached_hole_size)
+		start_addr = mm->free_area_cache;
+	else {
 		start_addr = TASK_UNMAPPED_BASE;
+		mm->cached_hole_size = 0;
+	}
 
 full_search:
 	addr = ALIGN(start_addr, huge_page_size(h));
@@ -171,13 +192,18 @@
 			 */
 			if (start_addr != TASK_UNMAPPED_BASE) {
 				start_addr = TASK_UNMAPPED_BASE;
+				mm->cached_hole_size = 0;
 				goto full_search;
 			}
 			return -ENOMEM;
 		}
 
-		if (!vma || addr + len <= vma->vm_start)
+		if (!vma || addr + len <= vma->vm_start) {
+			mm->free_area_cache = addr + len;
 			return addr;
+		}
+		if (addr + mm->cached_hole_size < vma->vm_start)
+			mm->cached_hole_size = vma->vm_start - addr;
 		addr = ALIGN(vma->vm_end, huge_page_size(h));
 	}
 }
@@ -238,17 +264,10 @@
 	loff_t isize;
 	ssize_t retval = 0;
 
-	mutex_lock(&inode->i_mutex);
-
 	/* validate length */
 	if (len == 0)
 		goto out;
 
-	isize = i_size_read(inode);
-	if (!isize)
-		goto out;
-
-	end_index = (isize - 1) >> huge_page_shift(h);
 	for (;;) {
 		struct page *page;
 		unsigned long nr, ret;
@@ -256,18 +275,21 @@
 
 		/* nr is the maximum number of bytes to copy from this page */
 		nr = huge_page_size(h);
+		isize = i_size_read(inode);
+		if (!isize)
+			goto out;
+		end_index = (isize - 1) >> huge_page_shift(h);
 		if (index >= end_index) {
 			if (index > end_index)
 				goto out;
 			nr = ((isize - 1) & ~huge_page_mask(h)) + 1;
-			if (nr <= offset) {
+			if (nr <= offset)
 				goto out;
-			}
 		}
 		nr = nr - offset;
 
 		/* Find the page */
-		page = find_get_page(mapping, index);
+		page = find_lock_page(mapping, index);
 		if (unlikely(page == NULL)) {
 			/*
 			 * We have a HOLE, zero out the user-buffer for the
@@ -279,17 +301,18 @@
 			else
 				ra = 0;
 		} else {
+			unlock_page(page);
+
 			/*
 			 * We have the page, copy it to user space buffer.
 			 */
 			ra = hugetlbfs_read_actor(page, offset, buf, len, nr);
 			ret = ra;
+			page_cache_release(page);
 		}
 		if (ra < 0) {
 			if (retval == 0)
 				retval = ra;
-			if (page)
-				page_cache_release(page);
 			goto out;
 		}
 
@@ -299,16 +322,12 @@
 		index += offset >> huge_page_shift(h);
 		offset &= ~huge_page_mask(h);
 
-		if (page)
-			page_cache_release(page);
-
 		/* short read or no more work */
 		if ((ret != nr) || (len == 0))
 			break;
 	}
 out:
 	*ppos = ((loff_t)index << huge_page_shift(h)) + offset;
-	mutex_unlock(&inode->i_mutex);
 	return retval;
 }
 
@@ -607,9 +626,15 @@
 		spin_lock(&sbinfo->stat_lock);
 		/* If no limits set, just report 0 for max/free/used
 		 * blocks, like simple_statfs() */
-		if (sbinfo->max_blocks >= 0) {
-			buf->f_blocks = sbinfo->max_blocks;
-			buf->f_bavail = buf->f_bfree = sbinfo->free_blocks;
+		if (sbinfo->spool) {
+			long free_pages;
+
+			spin_lock(&sbinfo->spool->lock);
+			buf->f_blocks = sbinfo->spool->max_hpages;
+			free_pages = sbinfo->spool->max_hpages
+				- sbinfo->spool->used_hpages;
+			buf->f_bavail = buf->f_bfree = free_pages;
+			spin_unlock(&sbinfo->spool->lock);
 			buf->f_files = sbinfo->max_inodes;
 			buf->f_ffree = sbinfo->free_inodes;
 		}
@@ -625,6 +650,10 @@
 
 	if (sbi) {
 		sb->s_fs_info = NULL;
+
+		if (sbi->spool)
+			hugepage_put_subpool(sbi->spool);
+
 		kfree(sbi);
 	}
 }
@@ -831,8 +860,6 @@
 static int
 hugetlbfs_fill_super(struct super_block *sb, void *data, int silent)
 {
-	struct inode * inode;
-	struct dentry * root;
 	int ret;
 	struct hugetlbfs_config config;
 	struct hugetlbfs_sb_info *sbinfo;
@@ -855,60 +882,31 @@
 	sb->s_fs_info = sbinfo;
 	sbinfo->hstate = config.hstate;
 	spin_lock_init(&sbinfo->stat_lock);
-	sbinfo->max_blocks = config.nr_blocks;
-	sbinfo->free_blocks = config.nr_blocks;
 	sbinfo->max_inodes = config.nr_inodes;
 	sbinfo->free_inodes = config.nr_inodes;
+	sbinfo->spool = NULL;
+	if (config.nr_blocks != -1) {
+		sbinfo->spool = hugepage_new_subpool(config.nr_blocks);
+		if (!sbinfo->spool)
+			goto out_free;
+	}
 	sb->s_maxbytes = MAX_LFS_FILESIZE;
 	sb->s_blocksize = huge_page_size(config.hstate);
 	sb->s_blocksize_bits = huge_page_shift(config.hstate);
 	sb->s_magic = HUGETLBFS_MAGIC;
 	sb->s_op = &hugetlbfs_ops;
 	sb->s_time_gran = 1;
-	inode = hugetlbfs_get_root(sb, &config);
-	if (!inode)
+	sb->s_root = d_make_root(hugetlbfs_get_root(sb, &config));
+	if (!sb->s_root)
 		goto out_free;
-
-	root = d_alloc_root(inode);
-	if (!root) {
-		iput(inode);
-		goto out_free;
-	}
-	sb->s_root = root;
 	return 0;
 out_free:
+	if (sbinfo->spool)
+		kfree(sbinfo->spool);
 	kfree(sbinfo);
 	return -ENOMEM;
 }
 
-int hugetlb_get_quota(struct address_space *mapping, long delta)
-{
-	int ret = 0;
-	struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(mapping->host->i_sb);
-
-	if (sbinfo->free_blocks > -1) {
-		spin_lock(&sbinfo->stat_lock);
-		if (sbinfo->free_blocks - delta >= 0)
-			sbinfo->free_blocks -= delta;
-		else
-			ret = -ENOMEM;
-		spin_unlock(&sbinfo->stat_lock);
-	}
-
-	return ret;
-}
-
-void hugetlb_put_quota(struct address_space *mapping, long delta)
-{
-	struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(mapping->host->i_sb);
-
-	if (sbinfo->free_blocks > -1) {
-		spin_lock(&sbinfo->stat_lock);
-		sbinfo->free_blocks += delta;
-		spin_unlock(&sbinfo->stat_lock);
-	}
-}
-
 static struct dentry *hugetlbfs_mount(struct file_system_type *fs_type,
 	int flags, const char *dev_name, void *data)
 {
@@ -928,8 +926,8 @@
 	return capable(CAP_IPC_LOCK) || in_group_p(sysctl_hugetlb_shm_group);
 }
 
-struct file *hugetlb_file_setup(const char *name, size_t size,
-				vm_flags_t acctflag,
+struct file *hugetlb_file_setup(const char *name, unsigned long addr,
+				size_t size, vm_flags_t acctflag,
 				struct user_struct **user, int creat_flags)
 {
 	int error = -ENOMEM;
@@ -938,6 +936,8 @@
 	struct path path;
 	struct dentry *root;
 	struct qstr quick_string;
+	struct hstate *hstate;
+	unsigned long num_pages;
 
 	*user = NULL;
 	if (!hugetlbfs_vfsmount)
@@ -946,7 +946,11 @@
 	if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) {
 		*user = current_user();
 		if (user_shm_lock(size, *user)) {
-			printk_once(KERN_WARNING "Using mlock ulimits for SHM_HUGETLB is deprecated\n");
+			task_lock(current);
+			printk_once(KERN_WARNING
+				"%s (%d): Using mlock ulimits for SHM_HUGETLB is deprecated\n",
+				current->comm, current->pid);
+			task_unlock(current);
 		} else {
 			*user = NULL;
 			return ERR_PTR(-EPERM);
@@ -967,10 +971,12 @@
 	if (!inode)
 		goto out_dentry;
 
+	hstate = hstate_inode(inode);
+	size += addr & ~huge_page_mask(hstate);
+	num_pages = ALIGN(size, huge_page_size(hstate)) >>
+			huge_page_shift(hstate);
 	error = -ENOMEM;
-	if (hugetlb_reserve_pages(inode, 0,
-			size >> huge_page_shift(hstate_inode(inode)), NULL,
-			acctflag))
+	if (hugetlb_reserve_pages(inode, 0, num_pages, NULL, acctflag))
 		goto out_inode;
 
 	d_instantiate(path.dentry, inode);
@@ -1006,6 +1012,7 @@
 	if (error)
 		return error;
 
+	error = -ENOMEM;
 	hugetlbfs_inode_cachep = kmem_cache_create("hugetlbfs_inode_cache",
 					sizeof(struct hugetlbfs_inode_info),
 					0, 0, init_once);
@@ -1026,8 +1033,7 @@
 	error = PTR_ERR(vfsmount);
 
  out:
-	if (error)
-		kmem_cache_destroy(hugetlbfs_inode_cachep);
+	kmem_cache_destroy(hugetlbfs_inode_cachep);
  out2:
 	bdi_destroy(&hugetlbfs_backing_dev_info);
 	return error;
diff --git a/fs/inode.c b/fs/inode.c
index 83ab215..9f4f5fe 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -2,29 +2,19 @@
  * (C) 1997 Linus Torvalds
  * (C) 1999 Andrea Arcangeli <andrea@suse.de> (dynamic inode allocation)
  */
+#include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
-#include <linux/dcache.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/writeback.h>
-#include <linux/module.h>
 #include <linux/backing-dev.h>
-#include <linux/wait.h>
-#include <linux/rwsem.h>
 #include <linux/hash.h>
 #include <linux/swap.h>
 #include <linux/security.h>
-#include <linux/pagemap.h>
 #include <linux/cdev.h>
 #include <linux/bootmem.h>
 #include <linux/fsnotify.h>
 #include <linux/mount.h>
-#include <linux/async.h>
 #include <linux/posix_acl.h>
 #include <linux/prefetch.h>
-#include <linux/ima.h>
-#include <linux/cred.h>
 #include <linux/buffer_head.h> /* for inode_has_buffers */
 #include <linux/ratelimit.h>
 #include "internal.h"
@@ -1369,17 +1359,6 @@
 EXPORT_SYMBOL(generic_delete_inode);
 
 /*
- * Normal UNIX filesystem behaviour: delete the
- * inode when the usage count drops to zero, and
- * i_nlink is zero.
- */
-int generic_drop_inode(struct inode *inode)
-{
-	return !inode->i_nlink || inode_unhashed(inode);
-}
-EXPORT_SYMBOL_GPL(generic_drop_inode);
-
-/*
  * Called when we're dropping the last reference
  * to an inode.
  *
@@ -1510,9 +1489,10 @@
  *	This function automatically handles read only file systems and media,
  *	as well as the "noatime" flag and inode specific "noatime" markers.
  */
-void touch_atime(struct vfsmount *mnt, struct dentry *dentry)
+void touch_atime(struct path *path)
 {
-	struct inode *inode = dentry->d_inode;
+	struct vfsmount *mnt = path->mnt;
+	struct inode *inode = path->dentry->d_inode;
 	struct timespec now;
 
 	if (inode->i_flags & S_NOATIME)
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 066836e..29167be 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -10,7 +10,7 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/security.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/uaccess.h>
 #include <linux/writeback.h>
 #include <linux/buffer_head.h>
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index bd62c76..29037c3 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -947,9 +947,8 @@
 	s->s_d_op = &isofs_dentry_ops[table];
 
 	/* get the root dentry */
-	s->s_root = d_alloc_root(inode);
+	s->s_root = d_make_root(inode);
 	if (!(s->s_root)) {
-		iput(inode);
 		error = -ENOMEM;
 		goto out_no_inode;
 	}
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
index d49d202..c78841e 100644
--- a/fs/jbd2/checkpoint.c
+++ b/fs/jbd2/checkpoint.c
@@ -88,14 +88,13 @@
  * whole transaction.
  *
  * Requires j_list_lock
- * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
  */
 static int __try_to_free_cp_buf(struct journal_head *jh)
 {
 	int ret = 0;
 	struct buffer_head *bh = jh2bh(jh);
 
-	if (jh->b_jlist == BJ_None && !buffer_locked(bh) &&
+	if (jh->b_transaction == NULL && !buffer_locked(bh) &&
 	    !buffer_dirty(bh) && !buffer_write_io_error(bh)) {
 		/*
 		 * Get our reference so that bh cannot be freed before
@@ -104,11 +103,8 @@
 		get_bh(bh);
 		JBUFFER_TRACE(jh, "remove from checkpoint list");
 		ret = __jbd2_journal_remove_checkpoint(jh) + 1;
-		jbd_unlock_bh_state(bh);
 		BUFFER_TRACE(bh, "release");
 		__brelse(bh);
-	} else {
-		jbd_unlock_bh_state(bh);
 	}
 	return ret;
 }
@@ -180,21 +176,6 @@
 }
 
 /*
- * We were unable to perform jbd_trylock_bh_state() inside j_list_lock.
- * The caller must restart a list walk.  Wait for someone else to run
- * jbd_unlock_bh_state().
- */
-static void jbd_sync_bh(journal_t *journal, struct buffer_head *bh)
-	__releases(journal->j_list_lock)
-{
-	get_bh(bh);
-	spin_unlock(&journal->j_list_lock);
-	jbd_lock_bh_state(bh);
-	jbd_unlock_bh_state(bh);
-	put_bh(bh);
-}
-
-/*
  * Clean up transaction's list of buffers submitted for io.
  * We wait for any pending IO to complete and remove any clean
  * buffers. Note that we take the buffers in the opposite ordering
@@ -222,15 +203,9 @@
 	while (!released && transaction->t_checkpoint_io_list) {
 		jh = transaction->t_checkpoint_io_list;
 		bh = jh2bh(jh);
-		if (!jbd_trylock_bh_state(bh)) {
-			jbd_sync_bh(journal, bh);
-			spin_lock(&journal->j_list_lock);
-			goto restart;
-		}
 		get_bh(bh);
 		if (buffer_locked(bh)) {
 			spin_unlock(&journal->j_list_lock);
-			jbd_unlock_bh_state(bh);
 			wait_on_buffer(bh);
 			/* the journal_head may have gone by now */
 			BUFFER_TRACE(bh, "brelse");
@@ -246,7 +221,6 @@
 		 * it has been written out and so we can drop it from the list
 		 */
 		released = __jbd2_journal_remove_checkpoint(jh);
-		jbd_unlock_bh_state(bh);
 		__brelse(bh);
 	}
 
@@ -266,7 +240,6 @@
 
 	for (i = 0; i < *batch_count; i++) {
 		struct buffer_head *bh = journal->j_chkpt_bhs[i];
-		clear_buffer_jwrite(bh);
 		BUFFER_TRACE(bh, "brelse");
 		__brelse(bh);
 	}
@@ -281,7 +254,6 @@
  * be written out.
  *
  * Called with j_list_lock held and drops it if 1 is returned
- * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
  */
 static int __process_buffer(journal_t *journal, struct journal_head *jh,
 			    int *batch_count, transaction_t *transaction)
@@ -292,7 +264,6 @@
 	if (buffer_locked(bh)) {
 		get_bh(bh);
 		spin_unlock(&journal->j_list_lock);
-		jbd_unlock_bh_state(bh);
 		wait_on_buffer(bh);
 		/* the journal_head may have gone by now */
 		BUFFER_TRACE(bh, "brelse");
@@ -304,7 +275,6 @@
 
 		transaction->t_chp_stats.cs_forced_to_close++;
 		spin_unlock(&journal->j_list_lock);
-		jbd_unlock_bh_state(bh);
 		if (unlikely(journal->j_flags & JBD2_UNMOUNT))
 			/*
 			 * The journal thread is dead; so starting and
@@ -323,11 +293,9 @@
 		if (unlikely(buffer_write_io_error(bh)))
 			ret = -EIO;
 		get_bh(bh);
-		J_ASSERT_JH(jh, !buffer_jbddirty(bh));
 		BUFFER_TRACE(bh, "remove from checkpoint");
 		__jbd2_journal_remove_checkpoint(jh);
 		spin_unlock(&journal->j_list_lock);
-		jbd_unlock_bh_state(bh);
 		__brelse(bh);
 	} else {
 		/*
@@ -340,10 +308,8 @@
 		BUFFER_TRACE(bh, "queue");
 		get_bh(bh);
 		J_ASSERT_BH(bh, !buffer_jwrite(bh));
-		set_buffer_jwrite(bh);
 		journal->j_chkpt_bhs[*batch_count] = bh;
 		__buffer_relink_io(jh);
-		jbd_unlock_bh_state(bh);
 		transaction->t_chp_stats.cs_written++;
 		(*batch_count)++;
 		if (*batch_count == JBD2_NR_BATCH) {
@@ -407,15 +373,7 @@
 		int retry = 0, err;
 
 		while (!retry && transaction->t_checkpoint_list) {
-			struct buffer_head *bh;
-
 			jh = transaction->t_checkpoint_list;
-			bh = jh2bh(jh);
-			if (!jbd_trylock_bh_state(bh)) {
-				jbd_sync_bh(journal, bh);
-				retry = 1;
-				break;
-			}
 			retry = __process_buffer(journal, jh, &batch_count,
 						 transaction);
 			if (retry < 0 && !result)
@@ -478,79 +436,28 @@
 
 int jbd2_cleanup_journal_tail(journal_t *journal)
 {
-	transaction_t * transaction;
 	tid_t		first_tid;
-	unsigned long	blocknr, freed;
+	unsigned long	blocknr;
 
 	if (is_journal_aborted(journal))
 		return 1;
 
-	/* OK, work out the oldest transaction remaining in the log, and
-	 * the log block it starts at.
-	 *
-	 * If the log is now empty, we need to work out which is the
-	 * next transaction ID we will write, and where it will
-	 * start. */
-
-	write_lock(&journal->j_state_lock);
-	spin_lock(&journal->j_list_lock);
-	transaction = journal->j_checkpoint_transactions;
-	if (transaction) {
-		first_tid = transaction->t_tid;
-		blocknr = transaction->t_log_start;
-	} else if ((transaction = journal->j_committing_transaction) != NULL) {
-		first_tid = transaction->t_tid;
-		blocknr = transaction->t_log_start;
-	} else if ((transaction = journal->j_running_transaction) != NULL) {
-		first_tid = transaction->t_tid;
-		blocknr = journal->j_head;
-	} else {
-		first_tid = journal->j_transaction_sequence;
-		blocknr = journal->j_head;
-	}
-	spin_unlock(&journal->j_list_lock);
+	if (!jbd2_journal_get_log_tail(journal, &first_tid, &blocknr))
+		return 1;
 	J_ASSERT(blocknr != 0);
 
-	/* If the oldest pinned transaction is at the tail of the log
-           already then there's not much we can do right now. */
-	if (journal->j_tail_sequence == first_tid) {
-		write_unlock(&journal->j_state_lock);
-		return 1;
-	}
-
-	/* OK, update the superblock to recover the freed space.
-	 * Physical blocks come first: have we wrapped beyond the end of
-	 * the log?  */
-	freed = blocknr - journal->j_tail;
-	if (blocknr < journal->j_tail)
-		freed = freed + journal->j_last - journal->j_first;
-
-	trace_jbd2_cleanup_journal_tail(journal, first_tid, blocknr, freed);
-	jbd_debug(1,
-		  "Cleaning journal tail from %d to %d (offset %lu), "
-		  "freeing %lu\n",
-		  journal->j_tail_sequence, first_tid, blocknr, freed);
-
-	journal->j_free += freed;
-	journal->j_tail_sequence = first_tid;
-	journal->j_tail = blocknr;
-	write_unlock(&journal->j_state_lock);
-
 	/*
-	 * If there is an external journal, we need to make sure that
-	 * any data blocks that were recently written out --- perhaps
-	 * by jbd2_log_do_checkpoint() --- are flushed out before we
-	 * drop the transactions from the external journal.  It's
-	 * unlikely this will be necessary, especially with a
-	 * appropriately sized journal, but we need this to guarantee
-	 * correctness.  Fortunately jbd2_cleanup_journal_tail()
-	 * doesn't get called all that often.
+	 * We need to make sure that any blocks that were recently written out
+	 * --- perhaps by jbd2_log_do_checkpoint() --- are flushed out before
+	 * we drop the transactions from the journal. It's unlikely this will
+	 * be necessary, especially with an appropriately sized journal, but we
+	 * need this to guarantee correctness.  Fortunately
+	 * jbd2_cleanup_journal_tail() doesn't get called all that often.
 	 */
-	if ((journal->j_fs_dev != journal->j_dev) &&
-	    (journal->j_flags & JBD2_BARRIER))
+	if (journal->j_flags & JBD2_BARRIER)
 		blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL);
-	if (!(journal->j_flags & JBD2_ABORT))
-		jbd2_journal_update_superblock(journal, 1);
+
+	__jbd2_update_log_tail(journal, first_tid, blocknr);
 	return 0;
 }
 
@@ -582,15 +489,12 @@
 	do {
 		jh = next_jh;
 		next_jh = jh->b_cpnext;
-		/* Use trylock because of the ranking */
-		if (jbd_trylock_bh_state(jh2bh(jh))) {
-			ret = __try_to_free_cp_buf(jh);
-			if (ret) {
-				freed++;
-				if (ret == 2) {
-					*released = 1;
-					return freed;
-				}
+		ret = __try_to_free_cp_buf(jh);
+		if (ret) {
+			freed++;
+			if (ret == 2) {
+				*released = 1;
+				return freed;
 			}
 		}
 		/*
@@ -673,9 +577,7 @@
  * The function can free jh and bh.
  *
  * This function is called with j_list_lock held.
- * This function is called with jbd_lock_bh_state(jh2bh(jh))
  */
-
 int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
 {
 	struct transaction_chp_stats_s *stats;
@@ -722,7 +624,7 @@
 				    transaction->t_tid, stats);
 
 	__jbd2_journal_drop_transaction(journal, transaction);
-	kfree(transaction);
+	jbd2_journal_free_transaction(transaction);
 
 	/* Just in case anybody was waiting for more transactions to be
            checkpointed... */
@@ -797,5 +699,7 @@
 	J_ASSERT(journal->j_committing_transaction != transaction);
 	J_ASSERT(journal->j_running_transaction != transaction);
 
+	trace_jbd2_drop_transaction(journal, transaction);
+
 	jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid);
 }
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index c067a8c..806525a 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -28,7 +28,6 @@
 #include <linux/blkdev.h>
 #include <linux/bitops.h>
 #include <trace/events/jbd2.h>
-#include <asm/system.h>
 
 /*
  * Default IO end handler for temporary BJ_IO buffer_heads.
@@ -331,6 +330,10 @@
 	struct buffer_head *cbh = NULL; /* For transactional checksums */
 	__u32 crc32_sum = ~0;
 	struct blk_plug plug;
+	/* Tail of the journal */
+	unsigned long first_block;
+	tid_t first_tid;
+	int update_tail;
 
 	/*
 	 * First job: lock down the current transaction and wait for
@@ -340,7 +343,18 @@
 	/* Do we need to erase the effects of a prior jbd2_journal_flush? */
 	if (journal->j_flags & JBD2_FLUSHED) {
 		jbd_debug(3, "super block updated\n");
-		jbd2_journal_update_superblock(journal, 1);
+		mutex_lock(&journal->j_checkpoint_mutex);
+		/*
+		 * We hold j_checkpoint_mutex so tail cannot change under us.
+		 * We don't need any special data guarantees for writing sb
+		 * since journal is empty and it is ok for write to be
+		 * flushed only with transaction commit.
+		 */
+		jbd2_journal_update_sb_log_tail(journal,
+						journal->j_tail_sequence,
+						journal->j_tail,
+						WRITE_SYNC);
+		mutex_unlock(&journal->j_checkpoint_mutex);
 	} else {
 		jbd_debug(3, "superblock not updated\n");
 	}
@@ -677,10 +691,30 @@
 		err = 0;
 	}
 
+	/*
+	 * Get current oldest transaction in the log before we issue flush
+	 * to the filesystem device. After the flush we can be sure that
+	 * blocks of all older transactions are checkpointed to persistent
+	 * storage and we will be safe to update journal start in the
+	 * superblock with the numbers we get here.
+	 */
+	update_tail =
+		jbd2_journal_get_log_tail(journal, &first_tid, &first_block);
+
 	write_lock(&journal->j_state_lock);
+	if (update_tail) {
+		long freed = first_block - journal->j_tail;
+
+		if (first_block < journal->j_tail)
+			freed += journal->j_last - journal->j_first;
+		/* Update tail only if we free significant amount of space */
+		if (freed < journal->j_maxlen / 4)
+			update_tail = 0;
+	}
 	J_ASSERT(commit_transaction->t_state == T_COMMIT);
 	commit_transaction->t_state = T_COMMIT_DFLUSH;
 	write_unlock(&journal->j_state_lock);
+
 	/* 
 	 * If the journal is not located on the file system device,
 	 * then we must flush the file system device before we issue
@@ -831,6 +865,14 @@
 	if (err)
 		jbd2_journal_abort(journal, err);
 
+	/*
+	 * Now disk caches for filesystem device are flushed so we are safe to
+	 * erase checkpointed transactions from the log by updating journal
+	 * superblock.
+	 */
+	if (update_tail)
+		jbd2_update_log_tail(journal, first_tid, first_block);
+
 	/* End of a transaction!  Finally, we can do checkpoint
            processing: any buffers committed as a result of this
            transaction can be removed from any checkpoint list it was on
@@ -1048,7 +1090,7 @@
 	jbd_debug(1, "JBD2: commit %d complete, head %d\n",
 		  journal->j_commit_sequence, journal->j_tail_sequence);
 	if (to_free)
-		kfree(commit_transaction);
+		jbd2_journal_free_transaction(commit_transaction);
 
 	wake_up(&journal->j_wait_done_commit);
 }
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 839377e..1afb701 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -50,7 +50,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
-#include <asm/system.h>
 
 EXPORT_SYMBOL(jbd2_journal_extend);
 EXPORT_SYMBOL(jbd2_journal_stop);
@@ -71,7 +70,6 @@
 
 EXPORT_SYMBOL(jbd2_journal_init_dev);
 EXPORT_SYMBOL(jbd2_journal_init_inode);
-EXPORT_SYMBOL(jbd2_journal_update_format);
 EXPORT_SYMBOL(jbd2_journal_check_used_features);
 EXPORT_SYMBOL(jbd2_journal_check_available_features);
 EXPORT_SYMBOL(jbd2_journal_set_features);
@@ -96,7 +94,6 @@
 EXPORT_SYMBOL(jbd2_journal_begin_ordered_truncate);
 EXPORT_SYMBOL(jbd2_inode_cache);
 
-static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
 static void __journal_abort_soft (journal_t *journal, int errno);
 static int jbd2_journal_create_slab(size_t slab_size);
 
@@ -746,6 +743,98 @@
 	return jbd2_journal_add_journal_head(bh);
 }
 
+/*
+ * Return tid of the oldest transaction in the journal and block in the journal
+ * where the transaction starts.
+ *
+ * If the journal is now empty, return which will be the next transaction ID
+ * we will write and where will that transaction start.
+ *
+ * The return value is 0 if journal tail cannot be pushed any further, 1 if
+ * it can.
+ */
+int jbd2_journal_get_log_tail(journal_t *journal, tid_t *tid,
+			      unsigned long *block)
+{
+	transaction_t *transaction;
+	int ret;
+
+	read_lock(&journal->j_state_lock);
+	spin_lock(&journal->j_list_lock);
+	transaction = journal->j_checkpoint_transactions;
+	if (transaction) {
+		*tid = transaction->t_tid;
+		*block = transaction->t_log_start;
+	} else if ((transaction = journal->j_committing_transaction) != NULL) {
+		*tid = transaction->t_tid;
+		*block = transaction->t_log_start;
+	} else if ((transaction = journal->j_running_transaction) != NULL) {
+		*tid = transaction->t_tid;
+		*block = journal->j_head;
+	} else {
+		*tid = journal->j_transaction_sequence;
+		*block = journal->j_head;
+	}
+	ret = tid_gt(*tid, journal->j_tail_sequence);
+	spin_unlock(&journal->j_list_lock);
+	read_unlock(&journal->j_state_lock);
+
+	return ret;
+}
+
+/*
+ * Update information in journal structure and in on disk journal superblock
+ * about log tail. This function does not check whether information passed in
+ * really pushes log tail further. It's responsibility of the caller to make
+ * sure provided log tail information is valid (e.g. by holding
+ * j_checkpoint_mutex all the time between computing log tail and calling this
+ * function as is the case with jbd2_cleanup_journal_tail()).
+ *
+ * Requires j_checkpoint_mutex
+ */
+void __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block)
+{
+	unsigned long freed;
+
+	BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex));
+
+	/*
+	 * We cannot afford for write to remain in drive's caches since as
+	 * soon as we update j_tail, next transaction can start reusing journal
+	 * space and if we lose sb update during power failure we'd replay
+	 * old transaction with possibly newly overwritten data.
+	 */
+	jbd2_journal_update_sb_log_tail(journal, tid, block, WRITE_FUA);
+	write_lock(&journal->j_state_lock);
+	freed = block - journal->j_tail;
+	if (block < journal->j_tail)
+		freed += journal->j_last - journal->j_first;
+
+	trace_jbd2_update_log_tail(journal, tid, block, freed);
+	jbd_debug(1,
+		  "Cleaning journal tail from %d to %d (offset %lu), "
+		  "freeing %lu\n",
+		  journal->j_tail_sequence, tid, block, freed);
+
+	journal->j_free += freed;
+	journal->j_tail_sequence = tid;
+	journal->j_tail = block;
+	write_unlock(&journal->j_state_lock);
+}
+
+/*
+ * This is a variaon of __jbd2_update_log_tail which checks for validity of
+ * provided log tail and locks j_checkpoint_mutex. So it is safe against races
+ * with other threads updating log tail.
+ */
+void jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block)
+{
+	mutex_lock(&journal->j_checkpoint_mutex);
+	if (tid_gt(tid, journal->j_tail_sequence))
+		__jbd2_update_log_tail(journal, tid, block);
+	mutex_unlock(&journal->j_checkpoint_mutex);
+}
+
 struct jbd2_stats_proc_session {
 	journal_t *journal;
 	struct transaction_stats_s *stats;
@@ -1114,40 +1203,45 @@
 
 	journal->j_max_transaction_buffers = journal->j_maxlen / 4;
 
-	/* Add the dynamic fields and write it to disk. */
-	jbd2_journal_update_superblock(journal, 1);
-	return jbd2_journal_start_thread(journal);
-}
-
-/**
- * void jbd2_journal_update_superblock() - Update journal sb on disk.
- * @journal: The journal to update.
- * @wait: Set to '0' if you don't want to wait for IO completion.
- *
- * Update a journal's dynamic superblock fields and write it to disk,
- * optionally waiting for the IO to complete.
- */
-void jbd2_journal_update_superblock(journal_t *journal, int wait)
-{
-	journal_superblock_t *sb = journal->j_superblock;
-	struct buffer_head *bh = journal->j_sb_buffer;
-
 	/*
 	 * As a special case, if the on-disk copy is already marked as needing
-	 * no recovery (s_start == 0) and there are no outstanding transactions
-	 * in the filesystem, then we can safely defer the superblock update
-	 * until the next commit by setting JBD2_FLUSHED.  This avoids
+	 * no recovery (s_start == 0), then we can safely defer the superblock
+	 * update until the next commit by setting JBD2_FLUSHED.  This avoids
 	 * attempting a write to a potential-readonly device.
 	 */
-	if (sb->s_start == 0 && journal->j_tail_sequence ==
-				journal->j_transaction_sequence) {
+	if (sb->s_start == 0) {
 		jbd_debug(1, "JBD2: Skipping superblock update on recovered sb "
 			"(start %ld, seq %d, errno %d)\n",
 			journal->j_tail, journal->j_tail_sequence,
 			journal->j_errno);
-		goto out;
+		journal->j_flags |= JBD2_FLUSHED;
+	} else {
+		/* Lock here to make assertions happy... */
+		mutex_lock(&journal->j_checkpoint_mutex);
+		/*
+		 * Update log tail information. We use WRITE_FUA since new
+		 * transaction will start reusing journal space and so we
+		 * must make sure information about current log tail is on
+		 * disk before that.
+		 */
+		jbd2_journal_update_sb_log_tail(journal,
+						journal->j_tail_sequence,
+						journal->j_tail,
+						WRITE_FUA);
+		mutex_unlock(&journal->j_checkpoint_mutex);
 	}
+	return jbd2_journal_start_thread(journal);
+}
 
+static void jbd2_write_superblock(journal_t *journal, int write_op)
+{
+	struct buffer_head *bh = journal->j_sb_buffer;
+	int ret;
+
+	trace_jbd2_write_superblock(journal, write_op);
+	if (!(journal->j_flags & JBD2_BARRIER))
+		write_op &= ~(REQ_FUA | REQ_FLUSH);
+	lock_buffer(bh);
 	if (buffer_write_io_error(bh)) {
 		/*
 		 * Oh, dear.  A previous attempt to write the journal
@@ -1163,48 +1257,106 @@
 		clear_buffer_write_io_error(bh);
 		set_buffer_uptodate(bh);
 	}
+	get_bh(bh);
+	bh->b_end_io = end_buffer_write_sync;
+	ret = submit_bh(write_op, bh);
+	wait_on_buffer(bh);
+	if (buffer_write_io_error(bh)) {
+		clear_buffer_write_io_error(bh);
+		set_buffer_uptodate(bh);
+		ret = -EIO;
+	}
+	if (ret) {
+		printk(KERN_ERR "JBD2: Error %d detected when updating "
+		       "journal superblock for %s.\n", ret,
+		       journal->j_devname);
+	}
+}
 
+/**
+ * jbd2_journal_update_sb_log_tail() - Update log tail in journal sb on disk.
+ * @journal: The journal to update.
+ * @tail_tid: TID of the new transaction at the tail of the log
+ * @tail_block: The first block of the transaction at the tail of the log
+ * @write_op: With which operation should we write the journal sb
+ *
+ * Update a journal's superblock information about log tail and write it to
+ * disk, waiting for the IO to complete.
+ */
+void jbd2_journal_update_sb_log_tail(journal_t *journal, tid_t tail_tid,
+				     unsigned long tail_block, int write_op)
+{
+	journal_superblock_t *sb = journal->j_superblock;
+
+	BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex));
+	jbd_debug(1, "JBD2: updating superblock (start %lu, seq %u)\n",
+		  tail_block, tail_tid);
+
+	sb->s_sequence = cpu_to_be32(tail_tid);
+	sb->s_start    = cpu_to_be32(tail_block);
+
+	jbd2_write_superblock(journal, write_op);
+
+	/* Log is no longer empty */
+	write_lock(&journal->j_state_lock);
+	WARN_ON(!sb->s_sequence);
+	journal->j_flags &= ~JBD2_FLUSHED;
+	write_unlock(&journal->j_state_lock);
+}
+
+/**
+ * jbd2_mark_journal_empty() - Mark on disk journal as empty.
+ * @journal: The journal to update.
+ *
+ * Update a journal's dynamic superblock fields to show that journal is empty.
+ * Write updated superblock to disk waiting for IO to complete.
+ */
+static void jbd2_mark_journal_empty(journal_t *journal)
+{
+	journal_superblock_t *sb = journal->j_superblock;
+
+	BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex));
 	read_lock(&journal->j_state_lock);
-	jbd_debug(1, "JBD2: updating superblock (start %ld, seq %d, errno %d)\n",
-		  journal->j_tail, journal->j_tail_sequence, journal->j_errno);
+	jbd_debug(1, "JBD2: Marking journal as empty (seq %d)\n",
+		  journal->j_tail_sequence);
 
 	sb->s_sequence = cpu_to_be32(journal->j_tail_sequence);
-	sb->s_start    = cpu_to_be32(journal->j_tail);
+	sb->s_start    = cpu_to_be32(0);
+	read_unlock(&journal->j_state_lock);
+
+	jbd2_write_superblock(journal, WRITE_FUA);
+
+	/* Log is no longer empty */
+	write_lock(&journal->j_state_lock);
+	journal->j_flags |= JBD2_FLUSHED;
+	write_unlock(&journal->j_state_lock);
+}
+
+
+/**
+ * jbd2_journal_update_sb_errno() - Update error in the journal.
+ * @journal: The journal to update.
+ *
+ * Update a journal's errno.  Write updated superblock to disk waiting for IO
+ * to complete.
+ */
+static void jbd2_journal_update_sb_errno(journal_t *journal)
+{
+	journal_superblock_t *sb = journal->j_superblock;
+
+	read_lock(&journal->j_state_lock);
+	jbd_debug(1, "JBD2: updating superblock error (errno %d)\n",
+		  journal->j_errno);
 	sb->s_errno    = cpu_to_be32(journal->j_errno);
 	read_unlock(&journal->j_state_lock);
 
-	BUFFER_TRACE(bh, "marking dirty");
-	mark_buffer_dirty(bh);
-	if (wait) {
-		sync_dirty_buffer(bh);
-		if (buffer_write_io_error(bh)) {
-			printk(KERN_ERR "JBD2: I/O error detected "
-			       "when updating journal superblock for %s.\n",
-			       journal->j_devname);
-			clear_buffer_write_io_error(bh);
-			set_buffer_uptodate(bh);
-		}
-	} else
-		write_dirty_buffer(bh, WRITE);
-
-out:
-	/* If we have just flushed the log (by marking s_start==0), then
-	 * any future commit will have to be careful to update the
-	 * superblock again to re-record the true start of the log. */
-
-	write_lock(&journal->j_state_lock);
-	if (sb->s_start)
-		journal->j_flags &= ~JBD2_FLUSHED;
-	else
-		journal->j_flags |= JBD2_FLUSHED;
-	write_unlock(&journal->j_state_lock);
+	jbd2_write_superblock(journal, WRITE_SYNC);
 }
 
 /*
  * Read the superblock for a given journal, performing initial
  * validation of the format.
  */
-
 static int journal_get_superblock(journal_t *journal)
 {
 	struct buffer_head *bh;
@@ -1398,14 +1550,11 @@
 
 	if (journal->j_sb_buffer) {
 		if (!is_journal_aborted(journal)) {
-			/* We can now mark the journal as empty. */
-			journal->j_tail = 0;
-			journal->j_tail_sequence =
-				++journal->j_transaction_sequence;
-			jbd2_journal_update_superblock(journal, 1);
-		} else {
+			mutex_lock(&journal->j_checkpoint_mutex);
+			jbd2_mark_journal_empty(journal);
+			mutex_unlock(&journal->j_checkpoint_mutex);
+		} else
 			err = -EIO;
-		}
 		brelse(journal->j_sb_buffer);
 	}
 
@@ -1552,61 +1701,6 @@
 EXPORT_SYMBOL(jbd2_journal_clear_features);
 
 /**
- * int jbd2_journal_update_format () - Update on-disk journal structure.
- * @journal: Journal to act on.
- *
- * Given an initialised but unloaded journal struct, poke about in the
- * on-disk structure to update it to the most recent supported version.
- */
-int jbd2_journal_update_format (journal_t *journal)
-{
-	journal_superblock_t *sb;
-	int err;
-
-	err = journal_get_superblock(journal);
-	if (err)
-		return err;
-
-	sb = journal->j_superblock;
-
-	switch (be32_to_cpu(sb->s_header.h_blocktype)) {
-	case JBD2_SUPERBLOCK_V2:
-		return 0;
-	case JBD2_SUPERBLOCK_V1:
-		return journal_convert_superblock_v1(journal, sb);
-	default:
-		break;
-	}
-	return -EINVAL;
-}
-
-static int journal_convert_superblock_v1(journal_t *journal,
-					 journal_superblock_t *sb)
-{
-	int offset, blocksize;
-	struct buffer_head *bh;
-
-	printk(KERN_WARNING
-		"JBD2: Converting superblock from version 1 to 2.\n");
-
-	/* Pre-initialise new fields to zero */
-	offset = ((char *) &(sb->s_feature_compat)) - ((char *) sb);
-	blocksize = be32_to_cpu(sb->s_blocksize);
-	memset(&sb->s_feature_compat, 0, blocksize-offset);
-
-	sb->s_nr_users = cpu_to_be32(1);
-	sb->s_header.h_blocktype = cpu_to_be32(JBD2_SUPERBLOCK_V2);
-	journal->j_format_version = 2;
-
-	bh = journal->j_sb_buffer;
-	BUFFER_TRACE(bh, "marking dirty");
-	mark_buffer_dirty(bh);
-	sync_dirty_buffer(bh);
-	return 0;
-}
-
-
-/**
  * int jbd2_journal_flush () - Flush journal
  * @journal: Journal to act on.
  *
@@ -1619,7 +1713,6 @@
 {
 	int err = 0;
 	transaction_t *transaction = NULL;
-	unsigned long old_tail;
 
 	write_lock(&journal->j_state_lock);
 
@@ -1654,6 +1747,7 @@
 	if (is_journal_aborted(journal))
 		return -EIO;
 
+	mutex_lock(&journal->j_checkpoint_mutex);
 	jbd2_cleanup_journal_tail(journal);
 
 	/* Finally, mark the journal as really needing no recovery.
@@ -1661,14 +1755,9 @@
 	 * the magic code for a fully-recovered superblock.  Any future
 	 * commits of data to the journal will restore the current
 	 * s_start value. */
+	jbd2_mark_journal_empty(journal);
+	mutex_unlock(&journal->j_checkpoint_mutex);
 	write_lock(&journal->j_state_lock);
-	old_tail = journal->j_tail;
-	journal->j_tail = 0;
-	write_unlock(&journal->j_state_lock);
-	jbd2_journal_update_superblock(journal, 1);
-	write_lock(&journal->j_state_lock);
-	journal->j_tail = old_tail;
-
 	J_ASSERT(!journal->j_running_transaction);
 	J_ASSERT(!journal->j_committing_transaction);
 	J_ASSERT(!journal->j_checkpoint_transactions);
@@ -1708,8 +1797,12 @@
 		write ? "Clearing" : "Ignoring");
 
 	err = jbd2_journal_skip_recovery(journal);
-	if (write)
-		jbd2_journal_update_superblock(journal, 1);
+	if (write) {
+		/* Lock to make assertions happy... */
+		mutex_lock(&journal->j_checkpoint_mutex);
+		jbd2_mark_journal_empty(journal);
+		mutex_unlock(&journal->j_checkpoint_mutex);
+	}
 
  no_recovery:
 	return err;
@@ -1759,7 +1852,7 @@
 	__jbd2_journal_abort_hard(journal);
 
 	if (errno)
-		jbd2_journal_update_superblock(journal, 1);
+		jbd2_journal_update_sb_errno(journal);
 }
 
 /**
@@ -2017,7 +2110,7 @@
 static atomic_t nr_journal_heads = ATOMIC_INIT(0);
 #endif
 
-static int journal_init_jbd2_journal_head_cache(void)
+static int jbd2_journal_init_journal_head_cache(void)
 {
 	int retval;
 
@@ -2035,7 +2128,7 @@
 	return retval;
 }
 
-static void jbd2_journal_destroy_jbd2_journal_head_cache(void)
+static void jbd2_journal_destroy_journal_head_cache(void)
 {
 	if (jbd2_journal_head_cache) {
 		kmem_cache_destroy(jbd2_journal_head_cache);
@@ -2323,7 +2416,7 @@
 
 struct kmem_cache *jbd2_handle_cache, *jbd2_inode_cache;
 
-static int __init journal_init_handle_cache(void)
+static int __init jbd2_journal_init_handle_cache(void)
 {
 	jbd2_handle_cache = KMEM_CACHE(jbd2_journal_handle, SLAB_TEMPORARY);
 	if (jbd2_handle_cache == NULL) {
@@ -2358,17 +2451,20 @@
 
 	ret = jbd2_journal_init_revoke_caches();
 	if (ret == 0)
-		ret = journal_init_jbd2_journal_head_cache();
+		ret = jbd2_journal_init_journal_head_cache();
 	if (ret == 0)
-		ret = journal_init_handle_cache();
+		ret = jbd2_journal_init_handle_cache();
+	if (ret == 0)
+		ret = jbd2_journal_init_transaction_cache();
 	return ret;
 }
 
 static void jbd2_journal_destroy_caches(void)
 {
 	jbd2_journal_destroy_revoke_caches();
-	jbd2_journal_destroy_jbd2_journal_head_cache();
+	jbd2_journal_destroy_journal_head_cache();
 	jbd2_journal_destroy_handle_cache();
+	jbd2_journal_destroy_transaction_cache();
 	jbd2_journal_destroy_slabs();
 }
 
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
index da6d7ba..c1a0335 100644
--- a/fs/jbd2/recovery.c
+++ b/fs/jbd2/recovery.c
@@ -21,6 +21,7 @@
 #include <linux/jbd2.h>
 #include <linux/errno.h>
 #include <linux/crc32.h>
+#include <linux/blkdev.h>
 #endif
 
 /*
@@ -265,7 +266,9 @@
 	err2 = sync_blockdev(journal->j_fs_dev);
 	if (!err)
 		err = err2;
-
+	/* Make sure all replayed data is on permanent storage */
+	if (journal->j_flags & JBD2_BARRIER)
+		blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL);
 	return err;
 }
 
diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c
index 30b2867..6973705 100644
--- a/fs/jbd2/revoke.c
+++ b/fs/jbd2/revoke.c
@@ -208,17 +208,13 @@
 	J_ASSERT(!jbd2_revoke_record_cache);
 	J_ASSERT(!jbd2_revoke_table_cache);
 
-	jbd2_revoke_record_cache = kmem_cache_create("jbd2_revoke_record",
-					   sizeof(struct jbd2_revoke_record_s),
-					   0,
-					   SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY,
-					   NULL);
+	jbd2_revoke_record_cache = KMEM_CACHE(jbd2_revoke_record_s,
+					SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY);
 	if (!jbd2_revoke_record_cache)
 		goto record_cache_failure;
 
-	jbd2_revoke_table_cache = kmem_cache_create("jbd2_revoke_table",
-					   sizeof(struct jbd2_revoke_table_s),
-					   0, SLAB_TEMPORARY, NULL);
+	jbd2_revoke_table_cache = KMEM_CACHE(jbd2_revoke_table_s,
+					     SLAB_TEMPORARY);
 	if (!jbd2_revoke_table_cache)
 		goto table_cache_failure;
 	return 0;
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index e5aba56..ddcd354 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -33,6 +33,35 @@
 static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh);
 static void __jbd2_journal_unfile_buffer(struct journal_head *jh);
 
+static struct kmem_cache *transaction_cache;
+int __init jbd2_journal_init_transaction_cache(void)
+{
+	J_ASSERT(!transaction_cache);
+	transaction_cache = kmem_cache_create("jbd2_transaction_s",
+					sizeof(transaction_t),
+					0,
+					SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY,
+					NULL);
+	if (transaction_cache)
+		return 0;
+	return -ENOMEM;
+}
+
+void jbd2_journal_destroy_transaction_cache(void)
+{
+	if (transaction_cache) {
+		kmem_cache_destroy(transaction_cache);
+		transaction_cache = NULL;
+	}
+}
+
+void jbd2_journal_free_transaction(transaction_t *transaction)
+{
+	if (unlikely(ZERO_OR_NULL_PTR(transaction)))
+		return;
+	kmem_cache_free(transaction_cache, transaction);
+}
+
 /*
  * jbd2_get_transaction: obtain a new transaction_t object.
  *
@@ -133,7 +162,8 @@
 
 alloc_transaction:
 	if (!journal->j_running_transaction) {
-		new_transaction = kzalloc(sizeof(*new_transaction), gfp_mask);
+		new_transaction = kmem_cache_alloc(transaction_cache,
+						   gfp_mask | __GFP_ZERO);
 		if (!new_transaction) {
 			/*
 			 * If __GFP_FS is not present, then we may be
@@ -162,7 +192,7 @@
 	if (is_journal_aborted(journal) ||
 	    (journal->j_errno != 0 && !(journal->j_flags & JBD2_ACK_ERR))) {
 		read_unlock(&journal->j_state_lock);
-		kfree(new_transaction);
+		jbd2_journal_free_transaction(new_transaction);
 		return -EROFS;
 	}
 
@@ -284,7 +314,7 @@
 	read_unlock(&journal->j_state_lock);
 
 	lock_map_acquire(&handle->h_lockdep_map);
-	kfree(new_transaction);
+	jbd2_journal_free_transaction(new_transaction);
 	return 0;
 }
 
@@ -1549,9 +1579,9 @@
  * of these pointers, it could go bad.  Generally the caller needs to re-read
  * the pointer from the transaction_t.
  *
- * Called under j_list_lock.  The journal may not be locked.
+ * Called under j_list_lock.
  */
-void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh)
+static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh)
 {
 	struct journal_head **list = NULL;
 	transaction_t *transaction;
@@ -1646,10 +1676,8 @@
 	spin_lock(&journal->j_list_lock);
 	if (jh->b_cp_transaction != NULL && jh->b_transaction == NULL) {
 		/* written-back checkpointed metadata buffer */
-		if (jh->b_jlist == BJ_None) {
-			JBUFFER_TRACE(jh, "remove from checkpoint list");
-			__jbd2_journal_remove_checkpoint(jh);
-		}
+		JBUFFER_TRACE(jh, "remove from checkpoint list");
+		__jbd2_journal_remove_checkpoint(jh);
 	}
 	spin_unlock(&journal->j_list_lock);
 out:
@@ -1949,6 +1977,8 @@
 	clear_buffer_mapped(bh);
 	clear_buffer_req(bh);
 	clear_buffer_new(bh);
+	clear_buffer_delay(bh);
+	clear_buffer_unwritten(bh);
 	bh->b_bdev = NULL;
 	return may_free;
 }
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
index 926d020..922f146 100644
--- a/fs/jffs2/acl.c
+++ b/fs/jffs2/acl.c
@@ -9,6 +9,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c
index 404111b..2b60ce1 100644
--- a/fs/jffs2/background.c
+++ b/fs/jffs2/background.c
@@ -10,6 +10,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/jffs2.h>
 #include <linux/mtd/mtd.h>
@@ -42,12 +44,13 @@
 
 	tsk = kthread_run(jffs2_garbage_collect_thread, c, "jffs2_gcd_mtd%d", c->mtd->index);
 	if (IS_ERR(tsk)) {
-		printk(KERN_WARNING "fork failed for JFFS2 garbage collect thread: %ld\n", -PTR_ERR(tsk));
+		pr_warn("fork failed for JFFS2 garbage collect thread: %ld\n",
+			-PTR_ERR(tsk));
 		complete(&c->gc_thread_exit);
 		ret = PTR_ERR(tsk);
 	} else {
 		/* Wait for it... */
-		D1(printk(KERN_DEBUG "JFFS2: Garbage collect thread is pid %d\n", tsk->pid));
+		jffs2_dbg(1, "Garbage collect thread is pid %d\n", tsk->pid);
 		wait_for_completion(&c->gc_thread_start);
 		ret = tsk->pid;
 	}
@@ -60,7 +63,7 @@
 	int wait = 0;
 	spin_lock(&c->erase_completion_lock);
 	if (c->gc_task) {
-		D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid));
+		jffs2_dbg(1, "Killing GC task %d\n", c->gc_task->pid);
 		send_sig(SIGKILL, c->gc_task, 1);
 		wait = 1;
 	}
@@ -90,7 +93,7 @@
 		if (!jffs2_thread_should_wake(c)) {
 			set_current_state (TASK_INTERRUPTIBLE);
 			spin_unlock(&c->erase_completion_lock);
-			D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n"));
+			jffs2_dbg(1, "%s(): sleeping...\n", __func__);
 			schedule();
 		} else
 			spin_unlock(&c->erase_completion_lock);
@@ -109,7 +112,7 @@
 		schedule_timeout_interruptible(msecs_to_jiffies(50));
 
 		if (kthread_should_stop()) {
-			D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread():  kthread_stop() called.\n"));
+			jffs2_dbg(1, "%s(): kthread_stop() called\n", __func__);
 			goto die;
 		}
 
@@ -126,28 +129,32 @@
 
 			switch(signr) {
 			case SIGSTOP:
-				D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGSTOP received.\n"));
+				jffs2_dbg(1, "%s(): SIGSTOP received\n",
+					  __func__);
 				set_current_state(TASK_STOPPED);
 				schedule();
 				break;
 
 			case SIGKILL:
-				D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGKILL received.\n"));
+				jffs2_dbg(1, "%s(): SIGKILL received\n",
+					  __func__);
 				goto die;
 
 			case SIGHUP:
-				D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGHUP received.\n"));
+				jffs2_dbg(1, "%s(): SIGHUP received\n",
+					  __func__);
 				break;
 			default:
-				D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): signal %ld received\n", signr));
+				jffs2_dbg(1, "%s(): signal %ld received\n",
+					  __func__, signr);
 			}
 		}
 		/* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
 		disallow_signal(SIGHUP);
 
-		D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): pass\n"));
+		jffs2_dbg(1, "%s(): pass\n", __func__);
 		if (jffs2_garbage_collect_pass(c) == -ENOSPC) {
-			printk(KERN_NOTICE "No space for garbage collection. Aborting GC thread\n");
+			pr_notice("No space for garbage collection. Aborting GC thread\n");
 			goto die;
 		}
 	}
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index 3005ec4..a3750f9 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -10,6 +10,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -307,8 +309,8 @@
 	   trying to GC to make more space. It'll be a fruitless task */
 	c->nospc_dirty_size = c->sector_size + (c->flash_size / 100);
 
-	dbg_fsbuild("JFFS2 trigger levels (size %d KiB, block size %d KiB, %d blocks)\n",
-		  c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks);
+	dbg_fsbuild("trigger levels (size %d KiB, block size %d KiB, %d blocks)\n",
+		    c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks);
 	dbg_fsbuild("Blocks required to allow deletion:    %d (%d KiB)\n",
 		  c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024);
 	dbg_fsbuild("Blocks required to allow writes:      %d (%d KiB)\n",
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c
index 96ed3c9..4849a4c 100644
--- a/fs/jffs2/compr.c
+++ b/fs/jffs2/compr.c
@@ -12,6 +12,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "compr.h"
 
 static DEFINE_SPINLOCK(jffs2_compressor_list_lock);
@@ -79,7 +81,7 @@
 
 	output_buf = kmalloc(*cdatalen, GFP_KERNEL);
 	if (!output_buf) {
-		printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
+		pr_warn("No memory for compressor allocation. Compression failed.\n");
 		return ret;
 	}
 	orig_slen = *datalen;
@@ -188,7 +190,8 @@
 				tmp_buf = kmalloc(orig_slen, GFP_KERNEL);
 				spin_lock(&jffs2_compressor_list_lock);
 				if (!tmp_buf) {
-					printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n", orig_slen);
+					pr_warn("No memory for compressor allocation. (%d bytes)\n",
+						orig_slen);
 					continue;
 				}
 				else {
@@ -235,7 +238,7 @@
 				cpage_out, datalen, cdatalen);
 		break;
 	default:
-		printk(KERN_ERR "JFFS2: unknown compression mode.\n");
+		pr_err("unknown compression mode\n");
 	}
 
 	if (ret == JFFS2_COMPR_NONE) {
@@ -277,7 +280,8 @@
 				ret = this->decompress(cdata_in, data_out, cdatalen, datalen);
 				spin_lock(&jffs2_compressor_list_lock);
 				if (ret) {
-					printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret);
+					pr_warn("Decompressor \"%s\" returned %d\n",
+						this->name, ret);
 				}
 				else {
 					this->stat_decompr_blocks++;
@@ -287,7 +291,7 @@
 				return ret;
 			}
 		}
-		printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype);
+		pr_warn("compression type 0x%02x not available\n", comprtype);
 		spin_unlock(&jffs2_compressor_list_lock);
 		return -EIO;
 	}
@@ -299,7 +303,7 @@
 	struct jffs2_compressor *this;
 
 	if (!comp->name) {
-		printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
+		pr_warn("NULL compressor name at registering JFFS2 compressor. Failed.\n");
 		return -1;
 	}
 	comp->compr_buf_size=0;
@@ -309,7 +313,7 @@
 	comp->stat_compr_new_size=0;
 	comp->stat_compr_blocks=0;
 	comp->stat_decompr_blocks=0;
-	D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
+	jffs2_dbg(1, "Registering JFFS2 compressor \"%s\"\n", comp->name);
 
 	spin_lock(&jffs2_compressor_list_lock);
 
@@ -332,15 +336,15 @@
 
 int jffs2_unregister_compressor(struct jffs2_compressor *comp)
 {
-	D2(struct jffs2_compressor *this;)
+	D2(struct jffs2_compressor *this);
 
-	D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
+	jffs2_dbg(1, "Unregistering JFFS2 compressor \"%s\"\n", comp->name);
 
 	spin_lock(&jffs2_compressor_list_lock);
 
 	if (comp->usecount) {
 		spin_unlock(&jffs2_compressor_list_lock);
-		printk(KERN_WARNING "JFFS2: Compressor module is in use. Unregister failed.\n");
+		pr_warn("Compressor module is in use. Unregister failed.\n");
 		return -1;
 	}
 	list_del(&comp->list);
@@ -377,17 +381,17 @@
 /* Setting default compression mode */
 #ifdef CONFIG_JFFS2_CMODE_NONE
 	jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
-	D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");)
+	jffs2_dbg(1, "default compression mode: none\n");
 #else
 #ifdef CONFIG_JFFS2_CMODE_SIZE
 	jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
-	D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");)
+	jffs2_dbg(1, "default compression mode: size\n");
 #else
 #ifdef CONFIG_JFFS2_CMODE_FAVOURLZO
 	jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO;
-	D1(printk(KERN_INFO "JFFS2: default compression mode: favourlzo\n");)
+	jffs2_dbg(1, "default compression mode: favourlzo\n");
 #else
-	D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");)
+	jffs2_dbg(1, "default compression mode: priority\n");
 #endif
 #endif
 #endif
diff --git a/fs/jffs2/compr_lzo.c b/fs/jffs2/compr_lzo.c
index af186ee..c553bd6 100644
--- a/fs/jffs2/compr_lzo.c
+++ b/fs/jffs2/compr_lzo.c
@@ -33,7 +33,6 @@
 	lzo_compress_buf = vmalloc(lzo1x_worst_compress(PAGE_SIZE));
 
 	if (!lzo_mem || !lzo_compress_buf) {
-		printk(KERN_WARNING "Failed to allocate lzo deflate workspace\n");
 		free_workspace();
 		return -ENOMEM;
 	}
diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c
index 9e7cec8..92e0644b 100644
--- a/fs/jffs2/compr_rubin.c
+++ b/fs/jffs2/compr_rubin.c
@@ -10,6 +10,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/jffs2.h>
diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c
index 5a00102..0b9a1e4 100644
--- a/fs/jffs2/compr_zlib.c
+++ b/fs/jffs2/compr_zlib.c
@@ -14,6 +14,8 @@
 #error "The userspace support got too messy and was removed. Update your mkfs.jffs2"
 #endif
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/zlib.h>
 #include <linux/zutil.h>
@@ -42,18 +44,18 @@
 {
 	def_strm.workspace = vmalloc(zlib_deflate_workspacesize(MAX_WBITS,
 							MAX_MEM_LEVEL));
-	if (!def_strm.workspace) {
-		printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL));
+	if (!def_strm.workspace)
 		return -ENOMEM;
-	}
-	D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL)));
+
+	jffs2_dbg(1, "Allocated %d bytes for deflate workspace\n",
+		  zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL));
 	inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
 	if (!inf_strm.workspace) {
-		printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize());
 		vfree(def_strm.workspace);
 		return -ENOMEM;
 	}
-	D1(printk(KERN_DEBUG "Allocated %d bytes for inflate workspace\n", zlib_inflate_workspacesize()));
+	jffs2_dbg(1, "Allocated %d bytes for inflate workspace\n",
+		  zlib_inflate_workspacesize());
 	return 0;
 }
 
@@ -79,7 +81,7 @@
 	mutex_lock(&deflate_mutex);
 
 	if (Z_OK != zlib_deflateInit(&def_strm, 3)) {
-		printk(KERN_WARNING "deflateInit failed\n");
+		pr_warn("deflateInit failed\n");
 		mutex_unlock(&deflate_mutex);
 		return -1;
 	}
@@ -93,13 +95,14 @@
 	while (def_strm.total_out < *dstlen - STREAM_END_SPACE && def_strm.total_in < *sourcelen) {
 		def_strm.avail_out = *dstlen - (def_strm.total_out + STREAM_END_SPACE);
 		def_strm.avail_in = min((unsigned)(*sourcelen-def_strm.total_in), def_strm.avail_out);
-		D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n",
-			  def_strm.avail_in, def_strm.avail_out));
+		jffs2_dbg(1, "calling deflate with avail_in %d, avail_out %d\n",
+			  def_strm.avail_in, def_strm.avail_out);
 		ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH);
-		D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n",
-			  def_strm.avail_in, def_strm.avail_out, def_strm.total_in, def_strm.total_out));
+		jffs2_dbg(1, "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n",
+			  def_strm.avail_in, def_strm.avail_out,
+			  def_strm.total_in, def_strm.total_out);
 		if (ret != Z_OK) {
-			D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret));
+			jffs2_dbg(1, "deflate in loop returned %d\n", ret);
 			zlib_deflateEnd(&def_strm);
 			mutex_unlock(&deflate_mutex);
 			return -1;
@@ -111,20 +114,20 @@
 	zlib_deflateEnd(&def_strm);
 
 	if (ret != Z_STREAM_END) {
-		D1(printk(KERN_DEBUG "final deflate returned %d\n", ret));
+		jffs2_dbg(1, "final deflate returned %d\n", ret);
 		ret = -1;
 		goto out;
 	}
 
 	if (def_strm.total_out >= def_strm.total_in) {
-		D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld; failing\n",
-			  def_strm.total_in, def_strm.total_out));
+		jffs2_dbg(1, "zlib compressed %ld bytes into %ld; failing\n",
+			  def_strm.total_in, def_strm.total_out);
 		ret = -1;
 		goto out;
 	}
 
-	D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n",
-		  def_strm.total_in, def_strm.total_out));
+	jffs2_dbg(1, "zlib compressed %ld bytes into %ld\n",
+		  def_strm.total_in, def_strm.total_out);
 
 	*dstlen = def_strm.total_out;
 	*sourcelen = def_strm.total_in;
@@ -157,18 +160,18 @@
 	    ((data_in[0] & 0x0f) == Z_DEFLATED) &&
 	    !(((data_in[0]<<8) + data_in[1]) % 31)) {
 
-		D2(printk(KERN_DEBUG "inflate skipping adler32\n"));
+		jffs2_dbg(2, "inflate skipping adler32\n");
 		wbits = -((data_in[0] >> 4) + 8);
 		inf_strm.next_in += 2;
 		inf_strm.avail_in -= 2;
 	} else {
 		/* Let this remain D1 for now -- it should never happen */
-		D1(printk(KERN_DEBUG "inflate not skipping adler32\n"));
+		jffs2_dbg(1, "inflate not skipping adler32\n");
 	}
 
 
 	if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) {
-		printk(KERN_WARNING "inflateInit failed\n");
+		pr_warn("inflateInit failed\n");
 		mutex_unlock(&inflate_mutex);
 		return 1;
 	}
@@ -176,7 +179,7 @@
 	while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK)
 		;
 	if (ret != Z_STREAM_END) {
-		printk(KERN_NOTICE "inflate returned %d\n", ret);
+		pr_notice("inflate returned %d\n", ret);
 	}
 	zlib_inflateEnd(&inf_strm);
 	mutex_unlock(&inflate_mutex);
diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c
index e0b76c8..1090eb6 100644
--- a/fs/jffs2/debug.c
+++ b/fs/jffs2/debug.c
@@ -10,6 +10,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pagemap.h>
@@ -261,12 +263,15 @@
 		bad += c->sector_size;
 	}
 
-#define check(sz) \
-	if (sz != c->sz##_size) {			\
-		printk(KERN_WARNING #sz "_size mismatch counted 0x%x, c->" #sz "_size 0x%x\n", \
-		       sz, c->sz##_size);		\
-		dump = 1;				\
-	}
+#define check(sz)							\
+do {									\
+	if (sz != c->sz##_size) {					\
+		pr_warn("%s_size mismatch counted 0x%x, c->%s_size 0x%x\n", \
+			#sz, sz, #sz, c->sz##_size);			\
+		dump = 1;						\
+	}								\
+} while (0)
+
 	check(free);
 	check(dirty);
 	check(used);
@@ -274,11 +279,12 @@
 	check(unchecked);
 	check(bad);
 	check(erasing);
+
 #undef check
 
 	if (nr_counted != c->nr_blocks) {
-		printk(KERN_WARNING "%s counted only 0x%x blocks of 0x%x. Where are the others?\n",
-		       __func__, nr_counted, c->nr_blocks);
+		pr_warn("%s counted only 0x%x blocks of 0x%x. Where are the others?\n",
+			__func__, nr_counted, c->nr_blocks);
 		dump = 1;
 	}
 
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h
index c4f8eef..4fd9be4 100644
--- a/fs/jffs2/debug.h
+++ b/fs/jffs2/debug.h
@@ -51,6 +51,7 @@
  * superseded by nicer dbg_xxx() macros...
  */
 #if CONFIG_JFFS2_FS_DEBUG > 0
+#define DEBUG
 #define D1(x) x
 #else
 #define D1(x)
@@ -62,50 +63,33 @@
 #define D2(x)
 #endif
 
+#define jffs2_dbg(level, fmt, ...)		\
+do {						\
+	if (CONFIG_JFFS2_FS_DEBUG >= level)	\
+		pr_debug(fmt, ##__VA_ARGS__);	\
+} while (0)
+
 /* The prefixes of JFFS2 messages */
+#define JFFS2_DBG		KERN_DEBUG
 #define JFFS2_DBG_PREFIX	"[JFFS2 DBG]"
-#define JFFS2_ERR_PREFIX	"JFFS2 error:"
-#define JFFS2_WARN_PREFIX	"JFFS2 warning:"
-#define JFFS2_NOTICE_PREFIX	"JFFS2 notice:"
-
-#define JFFS2_ERR	KERN_ERR
-#define JFFS2_WARN	KERN_WARNING
-#define JFFS2_NOT	KERN_NOTICE
-#define JFFS2_DBG	KERN_DEBUG
-
 #define JFFS2_DBG_MSG_PREFIX	JFFS2_DBG JFFS2_DBG_PREFIX
-#define JFFS2_ERR_MSG_PREFIX	JFFS2_ERR JFFS2_ERR_PREFIX
-#define JFFS2_WARN_MSG_PREFIX	JFFS2_WARN JFFS2_WARN_PREFIX
-#define JFFS2_NOTICE_MSG_PREFIX	JFFS2_NOT JFFS2_NOTICE_PREFIX
 
 /* JFFS2 message macros */
-#define JFFS2_ERROR(fmt, ...)						\
-	do {								\
-		printk(JFFS2_ERR_MSG_PREFIX				\
-			" (%d) %s: " fmt, task_pid_nr(current),		\
-			__func__ , ##__VA_ARGS__);			\
-	} while(0)
+#define JFFS2_ERROR(fmt, ...)					\
+	pr_err("error: (%d) %s: " fmt,				\
+	       task_pid_nr(current), __func__, ##__VA_ARGS__)
 
 #define JFFS2_WARNING(fmt, ...)						\
-	do {								\
-		printk(JFFS2_WARN_MSG_PREFIX				\
-			" (%d) %s: " fmt, task_pid_nr(current),		\
-			__func__ , ##__VA_ARGS__);			\
-	} while(0)
+	pr_warn("warning: (%d) %s: " fmt,				\
+		task_pid_nr(current), __func__, ##__VA_ARGS__)
 
 #define JFFS2_NOTICE(fmt, ...)						\
-	do {								\
-		printk(JFFS2_NOTICE_MSG_PREFIX				\
-			" (%d) %s: " fmt, task_pid_nr(current),		\
-			__func__ , ##__VA_ARGS__);			\
-	} while(0)
+	pr_notice("notice: (%d) %s: " fmt,				\
+		  task_pid_nr(current), __func__, ##__VA_ARGS__)
 
 #define JFFS2_DEBUG(fmt, ...)						\
-	do {								\
-		printk(JFFS2_DBG_MSG_PREFIX				\
-			" (%d) %s: " fmt, task_pid_nr(current),		\
-			__func__ , ##__VA_ARGS__);			\
-	} while(0)
+	printk(KERN_DEBUG "[JFFS2 DBG] (%d) %s: " fmt,			\
+	       task_pid_nr(current), __func__, ##__VA_ARGS__)
 
 /*
  * We split our debugging messages on several parts, depending on the JFFS2
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 973ac58..b560188 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -10,6 +10,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
@@ -79,7 +81,7 @@
 	uint32_t ino = 0;
 	struct inode *inode = NULL;
 
-	D1(printk(KERN_DEBUG "jffs2_lookup()\n"));
+	jffs2_dbg(1, "jffs2_lookup()\n");
 
 	if (target->d_name.len > JFFS2_MAX_NAME_LEN)
 		return ERR_PTR(-ENAMETOOLONG);
@@ -103,7 +105,7 @@
 	if (ino) {
 		inode = jffs2_iget(dir_i->i_sb, ino);
 		if (IS_ERR(inode))
-			printk(KERN_WARNING "iget() failed for ino #%u\n", ino);
+			pr_warn("iget() failed for ino #%u\n", ino);
 	}
 
 	return d_splice_alias(inode, target);
@@ -119,21 +121,22 @@
 	struct jffs2_full_dirent *fd;
 	unsigned long offset, curofs;
 
-	D1(printk(KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", filp->f_path.dentry->d_inode->i_ino));
+	jffs2_dbg(1, "jffs2_readdir() for dir_i #%lu\n",
+		  filp->f_path.dentry->d_inode->i_ino);
 
 	f = JFFS2_INODE_INFO(inode);
 
 	offset = filp->f_pos;
 
 	if (offset == 0) {
-		D1(printk(KERN_DEBUG "Dirent 0: \".\", ino #%lu\n", inode->i_ino));
+		jffs2_dbg(1, "Dirent 0: \".\", ino #%lu\n", inode->i_ino);
 		if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
 			goto out;
 		offset++;
 	}
 	if (offset == 1) {
 		unsigned long pino = parent_ino(filp->f_path.dentry);
-		D1(printk(KERN_DEBUG "Dirent 1: \"..\", ino #%lu\n", pino));
+		jffs2_dbg(1, "Dirent 1: \"..\", ino #%lu\n", pino);
 		if (filldir(dirent, "..", 2, 1, pino, DT_DIR) < 0)
 			goto out;
 		offset++;
@@ -146,16 +149,18 @@
 		curofs++;
 		/* First loop: curofs = 2; offset = 2 */
 		if (curofs < offset) {
-			D2(printk(KERN_DEBUG "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n",
-				  fd->name, fd->ino, fd->type, curofs, offset));
+			jffs2_dbg(2, "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n",
+				  fd->name, fd->ino, fd->type, curofs, offset);
 			continue;
 		}
 		if (!fd->ino) {
-			D2(printk(KERN_DEBUG "Skipping deletion dirent \"%s\"\n", fd->name));
+			jffs2_dbg(2, "Skipping deletion dirent \"%s\"\n",
+				  fd->name);
 			offset++;
 			continue;
 		}
-		D2(printk(KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d\n", offset, fd->name, fd->ino, fd->type));
+		jffs2_dbg(2, "Dirent %ld: \"%s\", ino #%u, type %d\n",
+			  offset, fd->name, fd->ino, fd->type);
 		if (filldir(dirent, fd->name, strlen(fd->name), offset, fd->ino, fd->type) < 0)
 			break;
 		offset++;
@@ -184,12 +189,12 @@
 
 	c = JFFS2_SB_INFO(dir_i->i_sb);
 
-	D1(printk(KERN_DEBUG "jffs2_create()\n"));
+	jffs2_dbg(1, "%s()\n", __func__);
 
 	inode = jffs2_new_inode(dir_i, mode, ri);
 
 	if (IS_ERR(inode)) {
-		D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n"));
+		jffs2_dbg(1, "jffs2_new_inode() failed\n");
 		jffs2_free_raw_inode(ri);
 		return PTR_ERR(inode);
 	}
@@ -217,9 +222,9 @@
 
 	jffs2_free_raw_inode(ri);
 
-	D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n",
-		  inode->i_ino, inode->i_mode, inode->i_nlink,
-		  f->inocache->pino_nlink, inode->i_mapping->nrpages));
+	jffs2_dbg(1, "%s(): Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n",
+		  __func__, inode->i_ino, inode->i_mode, inode->i_nlink,
+		  f->inocache->pino_nlink, inode->i_mapping->nrpages);
 
 	d_instantiate(dentry, inode);
 	unlock_new_inode(inode);
@@ -362,14 +367,15 @@
 	/* We use f->target field to store the target path. */
 	f->target = kmemdup(target, targetlen + 1, GFP_KERNEL);
 	if (!f->target) {
-		printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1);
+		pr_warn("Can't allocate %d bytes of memory\n", targetlen + 1);
 		mutex_unlock(&f->sem);
 		jffs2_complete_reservation(c);
 		ret = -ENOMEM;
 		goto fail;
 	}
 
-	D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->target));
+	jffs2_dbg(1, "%s(): symlink's target '%s' cached\n",
+		  __func__, (char *)f->target);
 
 	/* No data here. Only a metadata node, which will be
 	   obsoleted by the first data write
@@ -856,7 +862,8 @@
 			f->inocache->pino_nlink++;
 		mutex_unlock(&f->sem);
 
-		printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
+		pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link\n",
+			  __func__, ret);
 		/* Might as well let the VFS know */
 		d_instantiate(new_dentry, old_dentry->d_inode);
 		ihold(old_dentry->d_inode);
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index eafb8d3..4a6cf28 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -10,6 +10,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
@@ -46,11 +48,12 @@
 #else /* Linux */
 	struct erase_info *instr;
 
-	D1(printk(KERN_DEBUG "jffs2_erase_block(): erase block %#08x (range %#08x-%#08x)\n",
-				jeb->offset, jeb->offset, jeb->offset + c->sector_size));
+	jffs2_dbg(1, "%s(): erase block %#08x (range %#08x-%#08x)\n",
+		  __func__,
+		  jeb->offset, jeb->offset, jeb->offset + c->sector_size);
 	instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL);
 	if (!instr) {
-		printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
+		pr_warn("kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
 		mutex_lock(&c->erase_free_sem);
 		spin_lock(&c->erase_completion_lock);
 		list_move(&jeb->list, &c->erase_pending_list);
@@ -69,7 +72,6 @@
 	instr->len = c->sector_size;
 	instr->callback = jffs2_erase_callback;
 	instr->priv = (unsigned long)(&instr[1]);
-	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
 
 	((struct erase_priv_struct *)instr->priv)->jeb = jeb;
 	((struct erase_priv_struct *)instr->priv)->c = c;
@@ -84,7 +86,8 @@
 
 	if (ret == -ENOMEM || ret == -EAGAIN) {
 		/* Erase failed immediately. Refile it on the list */
-		D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret));
+		jffs2_dbg(1, "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n",
+			  jeb->offset, ret);
 		mutex_lock(&c->erase_free_sem);
 		spin_lock(&c->erase_completion_lock);
 		list_move(&jeb->list, &c->erase_pending_list);
@@ -97,9 +100,11 @@
 	}
 
 	if (ret == -EROFS)
-		printk(KERN_WARNING "Erase at 0x%08x failed immediately: -EROFS. Is the sector locked?\n", jeb->offset);
+		pr_warn("Erase at 0x%08x failed immediately: -EROFS. Is the sector locked?\n",
+			jeb->offset);
 	else
-		printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret);
+		pr_warn("Erase at 0x%08x failed immediately: errno %d\n",
+			jeb->offset, ret);
 
 	jffs2_erase_failed(c, jeb, bad_offset);
 }
@@ -125,13 +130,14 @@
 
 			work_done++;
 			if (!--count) {
-				D1(printk(KERN_DEBUG "Count reached. jffs2_erase_pending_blocks leaving\n"));
+				jffs2_dbg(1, "Count reached. jffs2_erase_pending_blocks leaving\n");
 				goto done;
 			}
 
 		} else if (!list_empty(&c->erase_pending_list)) {
 			jeb = list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list);
-			D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset));
+			jffs2_dbg(1, "Starting erase of pending block 0x%08x\n",
+				  jeb->offset);
 			list_del(&jeb->list);
 			c->erasing_size += c->sector_size;
 			c->wasted_size -= jeb->wasted_size;
@@ -159,13 +165,13 @@
 	spin_unlock(&c->erase_completion_lock);
 	mutex_unlock(&c->erase_free_sem);
  done:
-	D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n"));
+	jffs2_dbg(1, "jffs2_erase_pending_blocks completed\n");
 	return work_done;
 }
 
 static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
-	D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset));
+	jffs2_dbg(1, "Erase completed successfully at 0x%08x\n", jeb->offset);
 	mutex_lock(&c->erase_free_sem);
 	spin_lock(&c->erase_completion_lock);
 	list_move_tail(&jeb->list, &c->erase_complete_list);
@@ -214,7 +220,7 @@
 	struct erase_priv_struct *priv = (void *)instr->priv;
 
 	if(instr->state != MTD_ERASE_DONE) {
-		printk(KERN_WARNING "Erase at 0x%08llx finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n",
+		pr_warn("Erase at 0x%08llx finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n",
 			(unsigned long long)instr->addr, instr->state);
 		jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr);
 	} else {
@@ -269,8 +275,8 @@
 		return;
 	}
 
-	D1(printk(KERN_DEBUG "Removed nodes in range 0x%08x-0x%08x from ino #%u\n",
-		  jeb->offset, jeb->offset + c->sector_size, ic->ino));
+	jffs2_dbg(1, "Removed nodes in range 0x%08x-0x%08x from ino #%u\n",
+		  jeb->offset, jeb->offset + c->sector_size, ic->ino);
 
 	D2({
 		int i=0;
@@ -281,7 +287,7 @@
 
 		printk(KERN_DEBUG);
 		while(this) {
-			printk(KERN_CONT "0x%08x(%d)->",
+			pr_cont("0x%08x(%d)->",
 			       ref_offset(this), ref_flags(this));
 			if (++i == 5) {
 				printk(KERN_DEBUG);
@@ -289,7 +295,7 @@
 			}
 			this = this->next_in_ino;
 		}
-		printk(KERN_CONT "\n");
+		pr_cont("\n");
 	});
 
 	switch (ic->class) {
@@ -310,7 +316,8 @@
 void jffs2_free_jeb_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
 	struct jffs2_raw_node_ref *block, *ref;
-	D1(printk(KERN_DEBUG "Freeing all node refs for eraseblock offset 0x%08x\n", jeb->offset));
+	jffs2_dbg(1, "Freeing all node refs for eraseblock offset 0x%08x\n",
+		  jeb->offset);
 
 	block = ref = jeb->first_node;
 
@@ -342,12 +349,13 @@
 			&ebuf, NULL);
 	if (ret != -EOPNOTSUPP) {
 		if (ret) {
-			D1(printk(KERN_DEBUG "MTD point failed %d\n", ret));
+			jffs2_dbg(1, "MTD point failed %d\n", ret);
 			goto do_flash_read;
 		}
 		if (retlen < c->sector_size) {
 			/* Don't muck about if it won't let us point to the whole erase sector */
-			D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen));
+			jffs2_dbg(1, "MTD point returned len too short: 0x%zx\n",
+				  retlen);
 			mtd_unpoint(c->mtd, jeb->offset, retlen);
 			goto do_flash_read;
 		}
@@ -359,8 +367,10 @@
 		} while(--retlen);
 		mtd_unpoint(c->mtd, jeb->offset, c->sector_size);
 		if (retlen) {
-			printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n",
-			       *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf));
+			pr_warn("Newly-erased block contained word 0x%lx at offset 0x%08tx\n",
+				*wordebuf,
+				jeb->offset +
+				c->sector_size-retlen * sizeof(*wordebuf));
 			return -EIO;
 		}
 		return 0;
@@ -368,11 +378,12 @@
  do_flash_read:
 	ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 	if (!ebuf) {
-		printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", jeb->offset);
+		pr_warn("Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n",
+			jeb->offset);
 		return -EAGAIN;
 	}
 
-	D1(printk(KERN_DEBUG "Verifying erase at 0x%08x\n", jeb->offset));
+	jffs2_dbg(1, "Verifying erase at 0x%08x\n", jeb->offset);
 
 	for (ofs = jeb->offset; ofs < jeb->offset + c->sector_size; ) {
 		uint32_t readlen = min((uint32_t)PAGE_SIZE, jeb->offset + c->sector_size - ofs);
@@ -382,12 +393,14 @@
 
 		ret = mtd_read(c->mtd, ofs, readlen, &retlen, ebuf);
 		if (ret) {
-			printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
+			pr_warn("Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n",
+				ofs, ret);
 			ret = -EIO;
 			goto fail;
 		}
 		if (retlen != readlen) {
-			printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen);
+			pr_warn("Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n",
+				ofs, readlen, retlen);
 			ret = -EIO;
 			goto fail;
 		}
@@ -396,7 +409,8 @@
 			unsigned long *datum = ebuf + i;
 			if (*datum + 1) {
 				*bad_offset += i;
-				printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", *datum, *bad_offset);
+				pr_warn("Newly-erased block contained word 0x%lx at offset 0x%08x\n",
+					*datum, *bad_offset);
 				ret = -EIO;
 				goto fail;
 			}
@@ -422,7 +436,7 @@
 	}
 
 	/* Write the erase complete marker */
-	D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset));
+	jffs2_dbg(1, "Writing erased marker to block at 0x%08x\n", jeb->offset);
 	bad_offset = jeb->offset;
 
 	/* Cleanmarker in oob area or no cleanmarker at all ? */
@@ -451,10 +465,10 @@
 
 		if (ret || retlen != sizeof(marker)) {
 			if (ret)
-				printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
+				pr_warn("Write clean marker to block at 0x%08x failed: %d\n",
 				       jeb->offset, ret);
 			else
-				printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %zd, got %zd\n",
+				pr_warn("Short write to newly-erased block at 0x%08x: Wanted %zd, got %zd\n",
 				       jeb->offset, sizeof(marker), retlen);
 
 			goto filebad;
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index 61e6723..db3889b 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -10,6 +10,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/time.h>
@@ -85,7 +87,8 @@
 	unsigned char *pg_buf;
 	int ret;
 
-	D2(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT));
+	jffs2_dbg(2, "%s(): ino #%lu, page at offset 0x%lx\n",
+		  __func__, inode->i_ino, pg->index << PAGE_CACHE_SHIFT);
 
 	BUG_ON(!PageLocked(pg));
 
@@ -105,7 +108,7 @@
 	flush_dcache_page(pg);
 	kunmap(pg);
 
-	D2(printk(KERN_DEBUG "readpage finished\n"));
+	jffs2_dbg(2, "readpage finished\n");
 	return ret;
 }
 
@@ -144,7 +147,7 @@
 		return -ENOMEM;
 	*pagep = pg;
 
-	D1(printk(KERN_DEBUG "jffs2_write_begin()\n"));
+	jffs2_dbg(1, "%s()\n", __func__);
 
 	if (pageofs > inode->i_size) {
 		/* Make new hole frag from old EOF to new page */
@@ -153,8 +156,8 @@
 		struct jffs2_full_dnode *fn;
 		uint32_t alloc_len;
 
-		D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
-			  (unsigned int)inode->i_size, pageofs));
+		jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
+			  (unsigned int)inode->i_size, pageofs);
 
 		ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len,
 					  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
@@ -198,7 +201,8 @@
 			f->metadata = NULL;
 		}
 		if (ret) {
-			D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in write_begin, returned %d\n", ret));
+			jffs2_dbg(1, "Eep. add_full_dnode_to_inode() failed in write_begin, returned %d\n",
+				  ret);
 			jffs2_mark_node_obsolete(c, fn->raw);
 			jffs2_free_full_dnode(fn);
 			jffs2_complete_reservation(c);
@@ -222,7 +226,7 @@
 		if (ret)
 			goto out_page;
 	}
-	D1(printk(KERN_DEBUG "end write_begin(). pg->flags %lx\n", pg->flags));
+	jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags);
 	return ret;
 
 out_page:
@@ -248,8 +252,9 @@
 	int ret = 0;
 	uint32_t writtenlen = 0;
 
-	D1(printk(KERN_DEBUG "jffs2_write_end(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n",
-		  inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags));
+	jffs2_dbg(1, "%s(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n",
+		  __func__, inode->i_ino, pg->index << PAGE_CACHE_SHIFT,
+		  start, end, pg->flags);
 
 	/* We need to avoid deadlock with page_cache_read() in
 	   jffs2_garbage_collect_pass(). So the page must be
@@ -268,7 +273,8 @@
 	ri = jffs2_alloc_raw_inode();
 
 	if (!ri) {
-		D1(printk(KERN_DEBUG "jffs2_write_end(): Allocation of raw inode failed\n"));
+		jffs2_dbg(1, "%s(): Allocation of raw inode failed\n",
+			  __func__);
 		unlock_page(pg);
 		page_cache_release(pg);
 		return -ENOMEM;
@@ -315,13 +321,14 @@
 		/* generic_file_write has written more to the page cache than we've
 		   actually written to the medium. Mark the page !Uptodate so that
 		   it gets reread */
-		D1(printk(KERN_DEBUG "jffs2_write_end(): Not all bytes written. Marking page !uptodate\n"));
+		jffs2_dbg(1, "%s(): Not all bytes written. Marking page !uptodate\n",
+			__func__);
 		SetPageError(pg);
 		ClearPageUptodate(pg);
 	}
 
-	D1(printk(KERN_DEBUG "jffs2_write_end() returning %d\n",
-					writtenlen > 0 ? writtenlen : ret));
+	jffs2_dbg(1, "%s() returning %d\n",
+		  __func__, writtenlen > 0 ? writtenlen : ret);
 	unlock_page(pg);
 	page_cache_release(pg);
 	return writtenlen > 0 ? writtenlen : ret;
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 2e01238..bb6f993 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -10,6 +10,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/capability.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -39,7 +41,7 @@
 	int ret;
 	int alloc_type = ALLOC_NORMAL;
 
-	D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino));
+	jffs2_dbg(1, "%s(): ino #%lu\n", __func__, inode->i_ino);
 
 	/* Special cases - we don't want more than one data node
 	   for these types on the medium at any time. So setattr
@@ -50,7 +52,8 @@
 		/* For these, we don't actually need to read the old node */
 		mdatalen = jffs2_encode_dev(&dev, inode->i_rdev);
 		mdata = (char *)&dev;
-		D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
+		jffs2_dbg(1, "%s(): Writing %d bytes of kdev_t\n",
+			  __func__, mdatalen);
 	} else if (S_ISLNK(inode->i_mode)) {
 		mutex_lock(&f->sem);
 		mdatalen = f->metadata->size;
@@ -66,7 +69,8 @@
 			return ret;
 		}
 		mutex_unlock(&f->sem);
-		D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen));
+		jffs2_dbg(1, "%s(): Writing %d bytes of symlink target\n",
+			  __func__, mdatalen);
 	}
 
 	ri = jffs2_alloc_raw_inode();
@@ -233,7 +237,8 @@
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
 
-	D1(printk(KERN_DEBUG "jffs2_evict_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
+	jffs2_dbg(1, "%s(): ino #%lu mode %o\n",
+		  __func__, inode->i_ino, inode->i_mode);
 	truncate_inode_pages(&inode->i_data, 0);
 	end_writeback(inode);
 	jffs2_do_clear_inode(c, f);
@@ -249,7 +254,7 @@
 	dev_t rdev = 0;
 	int ret;
 
-	D1(printk(KERN_DEBUG "jffs2_iget(): ino == %lu\n", ino));
+	jffs2_dbg(1, "%s(): ino == %lu\n", __func__, ino);
 
 	inode = iget_locked(sb, ino);
 	if (!inode)
@@ -317,14 +322,16 @@
 		/* Read the device numbers from the media */
 		if (f->metadata->size != sizeof(jdev.old_id) &&
 		    f->metadata->size != sizeof(jdev.new_id)) {
-			printk(KERN_NOTICE "Device node has strange size %d\n", f->metadata->size);
+			pr_notice("Device node has strange size %d\n",
+				  f->metadata->size);
 			goto error_io;
 		}
-		D1(printk(KERN_DEBUG "Reading device numbers from flash\n"));
+		jffs2_dbg(1, "Reading device numbers from flash\n");
 		ret = jffs2_read_dnode(c, f, f->metadata, (char *)&jdev, 0, f->metadata->size);
 		if (ret < 0) {
 			/* Eep */
-			printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino);
+			pr_notice("Read device numbers for inode %lu failed\n",
+				  (unsigned long)inode->i_ino);
 			goto error;
 		}
 		if (f->metadata->size == sizeof(jdev.old_id))
@@ -339,12 +346,13 @@
 		break;
 
 	default:
-		printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu\n", inode->i_mode, (unsigned long)inode->i_ino);
+		pr_warn("%s(): Bogus i_mode %o for ino %lu\n",
+			__func__, inode->i_mode, (unsigned long)inode->i_ino);
 	}
 
 	mutex_unlock(&f->sem);
 
-	D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
+	jffs2_dbg(1, "jffs2_read_inode() returning\n");
 	unlock_new_inode(inode);
 	return inode;
 
@@ -362,11 +370,13 @@
 	struct iattr iattr;
 
 	if (!(inode->i_state & I_DIRTY_DATASYNC)) {
-		D2(printk(KERN_DEBUG "jffs2_dirty_inode() not calling setattr() for ino #%lu\n", inode->i_ino));
+		jffs2_dbg(2, "%s(): not calling setattr() for ino #%lu\n",
+			  __func__, inode->i_ino);
 		return;
 	}
 
-	D1(printk(KERN_DEBUG "jffs2_dirty_inode() calling setattr() for ino #%lu\n", inode->i_ino));
+	jffs2_dbg(1, "%s(): calling setattr() for ino #%lu\n",
+		  __func__, inode->i_ino);
 
 	iattr.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME;
 	iattr.ia_mode = inode->i_mode;
@@ -414,7 +424,8 @@
 	struct jffs2_inode_info *f;
 	int ret;
 
-	D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));
+	jffs2_dbg(1, "%s(): dir_i %ld, mode 0x%x\n",
+		  __func__, dir_i->i_ino, mode);
 
 	c = JFFS2_SB_INFO(sb);
 
@@ -504,11 +515,11 @@
 
 #ifndef CONFIG_JFFS2_FS_WRITEBUFFER
 	if (c->mtd->type == MTD_NANDFLASH) {
-		printk(KERN_ERR "jffs2: Cannot operate on NAND flash unless jffs2 NAND support is compiled in.\n");
+		pr_err("Cannot operate on NAND flash unless jffs2 NAND support is compiled in\n");
 		return -EINVAL;
 	}
 	if (c->mtd->type == MTD_DATAFLASH) {
-		printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.\n");
+		pr_err("Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in\n");
 		return -EINVAL;
 	}
 #endif
@@ -522,12 +533,13 @@
 	 */
 	if ((c->sector_size * blocks) != c->flash_size) {
 		c->flash_size = c->sector_size * blocks;
-		printk(KERN_INFO "jffs2: Flash size not aligned to erasesize, reducing to %dKiB\n",
+		pr_info("Flash size not aligned to erasesize, reducing to %dKiB\n",
 			c->flash_size / 1024);
 	}
 
 	if (c->flash_size < 5*c->sector_size) {
-		printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n", c->flash_size / c->sector_size);
+		pr_err("Too few erase blocks (%d)\n",
+		       c->flash_size / c->sector_size);
 		return -EINVAL;
 	}
 
@@ -550,20 +562,20 @@
 	if ((ret = jffs2_do_mount_fs(c)))
 		goto out_inohash;
 
-	D1(printk(KERN_DEBUG "jffs2_do_fill_super(): Getting root inode\n"));
+	jffs2_dbg(1, "%s(): Getting root inode\n", __func__);
 	root_i = jffs2_iget(sb, 1);
 	if (IS_ERR(root_i)) {
-		D1(printk(KERN_WARNING "get root inode failed\n"));
+		jffs2_dbg(1, "get root inode failed\n");
 		ret = PTR_ERR(root_i);
 		goto out_root;
 	}
 
 	ret = -ENOMEM;
 
-	D1(printk(KERN_DEBUG "jffs2_do_fill_super(): d_alloc_root()\n"));
-	sb->s_root = d_alloc_root(root_i);
+	jffs2_dbg(1, "%s(): d_make_root()\n", __func__);
+	sb->s_root = d_make_root(root_i);
 	if (!sb->s_root)
-		goto out_root_i;
+		goto out_root;
 
 	sb->s_maxbytes = 0xFFFFFFFF;
 	sb->s_blocksize = PAGE_CACHE_SIZE;
@@ -573,8 +585,6 @@
 		jffs2_start_garbage_collect_thread(c);
 	return 0;
 
- out_root_i:
-	iput(root_i);
 out_root:
 	jffs2_free_ino_caches(c);
 	jffs2_free_raw_node_refs(c);
@@ -620,20 +630,21 @@
 		*/
 		inode = ilookup(OFNI_BS_2SFFJ(c), inum);
 		if (!inode) {
-			D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n",
-				  inum));
+			jffs2_dbg(1, "ilookup() failed for ino #%u; inode is probably deleted.\n",
+				  inum);
 
 			spin_lock(&c->inocache_lock);
 			ic = jffs2_get_ino_cache(c, inum);
 			if (!ic) {
-				D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum));
+				jffs2_dbg(1, "Inode cache for ino #%u is gone\n",
+					  inum);
 				spin_unlock(&c->inocache_lock);
 				return NULL;
 			}
 			if (ic->state != INO_STATE_CHECKEDABSENT) {
 				/* Wait for progress. Don't just loop */
-				D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n",
-					  ic->ino, ic->state));
+				jffs2_dbg(1, "Waiting for ino #%u in state %d\n",
+					  ic->ino, ic->state);
 				sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
 			} else {
 				spin_unlock(&c->inocache_lock);
@@ -651,8 +662,8 @@
 			return ERR_CAST(inode);
 	}
 	if (is_bad_inode(inode)) {
-		printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. unlinked %d\n",
-		       inum, unlinked);
+		pr_notice("Eep. read_inode() failed for ino #%u. unlinked %d\n",
+			  inum, unlinked);
 		/* NB. This will happen again. We need to do something appropriate here. */
 		iput(inode);
 		return ERR_PTR(-EIO);
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index 31dce61133..ad271c7 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -10,6 +10,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/mtd/mtd.h>
 #include <linux/slab.h>
@@ -51,44 +53,44 @@
 	   number of free blocks is low. */
 again:
 	if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) {
-		D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n"));
+		jffs2_dbg(1, "Picking block from bad_used_list to GC next\n");
 		nextlist = &c->bad_used_list;
 	} else if (n < 50 && !list_empty(&c->erasable_list)) {
 		/* Note that most of them will have gone directly to be erased.
 		   So don't favour the erasable_list _too_ much. */
-		D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next\n"));
+		jffs2_dbg(1, "Picking block from erasable_list to GC next\n");
 		nextlist = &c->erasable_list;
 	} else if (n < 110 && !list_empty(&c->very_dirty_list)) {
 		/* Most of the time, pick one off the very_dirty list */
-		D1(printk(KERN_DEBUG "Picking block from very_dirty_list to GC next\n"));
+		jffs2_dbg(1, "Picking block from very_dirty_list to GC next\n");
 		nextlist = &c->very_dirty_list;
 	} else if (n < 126 && !list_empty(&c->dirty_list)) {
-		D1(printk(KERN_DEBUG "Picking block from dirty_list to GC next\n"));
+		jffs2_dbg(1, "Picking block from dirty_list to GC next\n");
 		nextlist = &c->dirty_list;
 	} else if (!list_empty(&c->clean_list)) {
-		D1(printk(KERN_DEBUG "Picking block from clean_list to GC next\n"));
+		jffs2_dbg(1, "Picking block from clean_list to GC next\n");
 		nextlist = &c->clean_list;
 	} else if (!list_empty(&c->dirty_list)) {
-		D1(printk(KERN_DEBUG "Picking block from dirty_list to GC next (clean_list was empty)\n"));
+		jffs2_dbg(1, "Picking block from dirty_list to GC next (clean_list was empty)\n");
 
 		nextlist = &c->dirty_list;
 	} else if (!list_empty(&c->very_dirty_list)) {
-		D1(printk(KERN_DEBUG "Picking block from very_dirty_list to GC next (clean_list and dirty_list were empty)\n"));
+		jffs2_dbg(1, "Picking block from very_dirty_list to GC next (clean_list and dirty_list were empty)\n");
 		nextlist = &c->very_dirty_list;
 	} else if (!list_empty(&c->erasable_list)) {
-		D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n"));
+		jffs2_dbg(1, "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n");
 
 		nextlist = &c->erasable_list;
 	} else if (!list_empty(&c->erasable_pending_wbuf_list)) {
 		/* There are blocks are wating for the wbuf sync */
-		D1(printk(KERN_DEBUG "Synching wbuf in order to reuse erasable_pending_wbuf_list blocks\n"));
+		jffs2_dbg(1, "Synching wbuf in order to reuse erasable_pending_wbuf_list blocks\n");
 		spin_unlock(&c->erase_completion_lock);
 		jffs2_flush_wbuf_pad(c);
 		spin_lock(&c->erase_completion_lock);
 		goto again;
 	} else {
 		/* Eep. All were empty */
-		D1(printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n"));
+		jffs2_dbg(1, "No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n");
 		return NULL;
 	}
 
@@ -97,13 +99,15 @@
 	c->gcblock = ret;
 	ret->gc_node = ret->first_node;
 	if (!ret->gc_node) {
-		printk(KERN_WARNING "Eep. ret->gc_node for block at 0x%08x is NULL\n", ret->offset);
+		pr_warn("Eep. ret->gc_node for block at 0x%08x is NULL\n",
+			ret->offset);
 		BUG();
 	}
 
 	/* Have we accidentally picked a clean block with wasted space ? */
 	if (ret->wasted_size) {
-		D1(printk(KERN_DEBUG "Converting wasted_size %08x to dirty_size\n", ret->wasted_size));
+		jffs2_dbg(1, "Converting wasted_size %08x to dirty_size\n",
+			  ret->wasted_size);
 		ret->dirty_size += ret->wasted_size;
 		c->wasted_size -= ret->wasted_size;
 		c->dirty_size += ret->wasted_size;
@@ -140,8 +144,8 @@
 
 		/* checked_ino is protected by the alloc_sem */
 		if (c->checked_ino > c->highest_ino && xattr) {
-			printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n",
-			       c->unchecked_size);
+			pr_crit("Checked all inodes but still 0x%x bytes of unchecked space?\n",
+				c->unchecked_size);
 			jffs2_dbg_dump_block_lists_nolock(c);
 			spin_unlock(&c->erase_completion_lock);
 			mutex_unlock(&c->alloc_sem);
@@ -163,8 +167,8 @@
 		}
 
 		if (!ic->pino_nlink) {
-			D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink/pino zero\n",
-				  ic->ino));
+			jffs2_dbg(1, "Skipping check of ino #%d with nlink/pino zero\n",
+				  ic->ino);
 			spin_unlock(&c->inocache_lock);
 			jffs2_xattr_delete_inode(c, ic);
 			continue;
@@ -172,13 +176,15 @@
 		switch(ic->state) {
 		case INO_STATE_CHECKEDABSENT:
 		case INO_STATE_PRESENT:
-			D1(printk(KERN_DEBUG "Skipping ino #%u already checked\n", ic->ino));
+			jffs2_dbg(1, "Skipping ino #%u already checked\n",
+				  ic->ino);
 			spin_unlock(&c->inocache_lock);
 			continue;
 
 		case INO_STATE_GC:
 		case INO_STATE_CHECKING:
-			printk(KERN_WARNING "Inode #%u is in state %d during CRC check phase!\n", ic->ino, ic->state);
+			pr_warn("Inode #%u is in state %d during CRC check phase!\n",
+				ic->ino, ic->state);
 			spin_unlock(&c->inocache_lock);
 			BUG();
 
@@ -186,7 +192,8 @@
 			/* We need to wait for it to finish, lest we move on
 			   and trigger the BUG() above while we haven't yet
 			   finished checking all its nodes */
-			D1(printk(KERN_DEBUG "Waiting for ino #%u to finish reading\n", ic->ino));
+			jffs2_dbg(1, "Waiting for ino #%u to finish reading\n",
+				  ic->ino);
 			/* We need to come back again for the _same_ inode. We've
 			 made no progress in this case, but that should be OK */
 			c->checked_ino--;
@@ -204,11 +211,13 @@
 		ic->state = INO_STATE_CHECKING;
 		spin_unlock(&c->inocache_lock);
 
-		D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%u\n", ic->ino));
+		jffs2_dbg(1, "%s(): triggering inode scan of ino#%u\n",
+			  __func__, ic->ino);
 
 		ret = jffs2_do_crccheck_inode(c, ic);
 		if (ret)
-			printk(KERN_WARNING "Returned error for crccheck of ino #%u. Expect badness...\n", ic->ino);
+			pr_warn("Returned error for crccheck of ino #%u. Expect badness...\n",
+				ic->ino);
 
 		jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT);
 		mutex_unlock(&c->alloc_sem);
@@ -220,11 +229,11 @@
 	    !list_empty(&c->erase_pending_list)) {
 		spin_unlock(&c->erase_completion_lock);
 		mutex_unlock(&c->alloc_sem);
-		D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() erasing pending blocks\n"));
+		jffs2_dbg(1, "%s(): erasing pending blocks\n", __func__);
 		if (jffs2_erase_pending_blocks(c, 1))
 			return 0;
 
-		D1(printk(KERN_DEBUG "No progress from erasing blocks; doing GC anyway\n"));
+		jffs2_dbg(1, "No progress from erasing block; doing GC anyway\n");
 		spin_lock(&c->erase_completion_lock);
 		mutex_lock(&c->alloc_sem);
 	}
@@ -242,13 +251,14 @@
 			mutex_unlock(&c->alloc_sem);
 			return -EAGAIN;
 		}
-		D1(printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n"));
+		jffs2_dbg(1, "Couldn't find erase block to garbage collect!\n");
 		spin_unlock(&c->erase_completion_lock);
 		mutex_unlock(&c->alloc_sem);
 		return -EIO;
 	}
 
-	D1(printk(KERN_DEBUG "GC from block %08x, used_size %08x, dirty_size %08x, free_size %08x\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size));
+	jffs2_dbg(1, "GC from block %08x, used_size %08x, dirty_size %08x, free_size %08x\n",
+		  jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size);
 	D1(if (c->nextblock)
 	   printk(KERN_DEBUG "Nextblock at  %08x, used_size %08x, dirty_size %08x, wasted_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->free_size));
 
@@ -261,12 +271,14 @@
 	gcblock_dirty = jeb->dirty_size;
 
 	while(ref_obsolete(raw)) {
-		D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw)));
+		jffs2_dbg(1, "Node at 0x%08x is obsolete... skipping\n",
+			  ref_offset(raw));
 		raw = ref_next(raw);
 		if (unlikely(!raw)) {
-			printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n");
-			printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n",
-			       jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size);
+			pr_warn("eep. End of raw list while still supposedly nodes to GC\n");
+			pr_warn("erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n",
+				jeb->offset, jeb->free_size,
+				jeb->dirty_size, jeb->used_size);
 			jeb->gc_node = raw;
 			spin_unlock(&c->erase_completion_lock);
 			mutex_unlock(&c->alloc_sem);
@@ -275,7 +287,8 @@
 	}
 	jeb->gc_node = raw;
 
-	D1(printk(KERN_DEBUG "Going to garbage collect node at 0x%08x\n", ref_offset(raw)));
+	jffs2_dbg(1, "Going to garbage collect node at 0x%08x\n",
+		  ref_offset(raw));
 
 	if (!raw->next_in_ino) {
 		/* Inode-less node. Clean marker, snapshot or something like that */
@@ -316,7 +329,9 @@
 
 	spin_unlock(&c->erase_completion_lock);
 
-	D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n", jeb->offset, ref_offset(raw), ref_flags(raw), ic->ino));
+	jffs2_dbg(1, "%s(): collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n",
+		  __func__, jeb->offset, ref_offset(raw), ref_flags(raw),
+		  ic->ino);
 
 	/* Three possibilities:
 	   1. Inode is already in-core. We must iget it and do proper
@@ -336,8 +351,8 @@
 		if (ref_flags(raw) == REF_PRISTINE)
 			ic->state = INO_STATE_GC;
 		else {
-			D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n",
-				  ic->ino));
+			jffs2_dbg(1, "Ino #%u is absent but node not REF_PRISTINE. Reading.\n",
+				  ic->ino);
 		}
 		break;
 
@@ -353,8 +368,8 @@
 		   we're holding the alloc_sem, no other garbage collection
 		   can happen.
 		*/
-		printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n",
-		       ic->ino, ic->state);
+		pr_crit("Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n",
+			ic->ino, ic->state);
 		mutex_unlock(&c->alloc_sem);
 		spin_unlock(&c->inocache_lock);
 		BUG();
@@ -367,8 +382,8 @@
 		   drop the alloc_sem before sleeping. */
 
 		mutex_unlock(&c->alloc_sem);
-		D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n",
-			  ic->ino, ic->state));
+		jffs2_dbg(1, "%s(): waiting for ino #%u in state %d\n",
+			  __func__, ic->ino, ic->state);
 		sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
 		/* And because we dropped the alloc_sem we must start again from the
 		   beginning. Ponder chance of livelock here -- we're returning success
@@ -433,7 +448,8 @@
  test_gcnode:
 	if (jeb->dirty_size == gcblock_dirty && !ref_obsolete(jeb->gc_node)) {
 		/* Eep. This really should never happen. GC is broken */
-		printk(KERN_ERR "Error garbage collecting node at %08x!\n", ref_offset(jeb->gc_node));
+		pr_err("Error garbage collecting node at %08x!\n",
+		       ref_offset(jeb->gc_node));
 		ret = -ENOSPC;
 	}
  release_sem:
@@ -445,7 +461,8 @@
 
  eraseit:
 	if (c->gcblock && !c->gcblock->used_size) {
-		D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset));
+		jffs2_dbg(1, "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n",
+			  c->gcblock->offset);
 		/* We're GC'ing an empty block? */
 		list_add_tail(&c->gcblock->list, &c->erase_pending_list);
 		c->gcblock = NULL;
@@ -475,12 +492,12 @@
 
 	if (c->gcblock != jeb) {
 		spin_unlock(&c->erase_completion_lock);
-		D1(printk(KERN_DEBUG "GC block is no longer gcblock. Restart\n"));
+		jffs2_dbg(1, "GC block is no longer gcblock. Restart\n");
 		goto upnout;
 	}
 	if (ref_obsolete(raw)) {
 		spin_unlock(&c->erase_completion_lock);
-		D1(printk(KERN_DEBUG "node to be GC'd was obsoleted in the meantime.\n"));
+		jffs2_dbg(1, "node to be GC'd was obsoleted in the meantime.\n");
 		/* They'll call again */
 		goto upnout;
 	}
@@ -536,10 +553,10 @@
 	} else if (fd) {
 		ret = jffs2_garbage_collect_deletion_dirent(c, jeb, f, fd);
 	} else {
-		printk(KERN_WARNING "Raw node at 0x%08x wasn't in node lists for ino #%u\n",
-		       ref_offset(raw), f->inocache->ino);
+		pr_warn("Raw node at 0x%08x wasn't in node lists for ino #%u\n",
+			ref_offset(raw), f->inocache->ino);
 		if (ref_obsolete(raw)) {
-			printk(KERN_WARNING "But it's obsolete so we don't mind too much\n");
+			pr_warn("But it's obsolete so we don't mind too much\n");
 		} else {
 			jffs2_dbg_dump_node(c, ref_offset(raw));
 			BUG();
@@ -562,7 +579,8 @@
 	uint32_t crc, rawlen;
 	int retried = 0;
 
-	D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw)));
+	jffs2_dbg(1, "Going to GC REF_PRISTINE node at 0x%08x\n",
+		  ref_offset(raw));
 
 	alloclen = rawlen = ref_totlen(c, c->gcblock, raw);
 
@@ -595,8 +613,8 @@
 
 	crc = crc32(0, node, sizeof(struct jffs2_unknown_node)-4);
 	if (je32_to_cpu(node->u.hdr_crc) != crc) {
-		printk(KERN_WARNING "Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-		       ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc);
+		pr_warn("Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+			ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc);
 		goto bail;
 	}
 
@@ -604,16 +622,18 @@
 	case JFFS2_NODETYPE_INODE:
 		crc = crc32(0, node, sizeof(node->i)-8);
 		if (je32_to_cpu(node->i.node_crc) != crc) {
-			printk(KERN_WARNING "Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-			       ref_offset(raw), je32_to_cpu(node->i.node_crc), crc);
+			pr_warn("Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+				ref_offset(raw), je32_to_cpu(node->i.node_crc),
+				crc);
 			goto bail;
 		}
 
 		if (je32_to_cpu(node->i.dsize)) {
 			crc = crc32(0, node->i.data, je32_to_cpu(node->i.csize));
 			if (je32_to_cpu(node->i.data_crc) != crc) {
-				printk(KERN_WARNING "Data CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-				       ref_offset(raw), je32_to_cpu(node->i.data_crc), crc);
+				pr_warn("Data CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+					ref_offset(raw),
+					je32_to_cpu(node->i.data_crc), crc);
 				goto bail;
 			}
 		}
@@ -622,21 +642,24 @@
 	case JFFS2_NODETYPE_DIRENT:
 		crc = crc32(0, node, sizeof(node->d)-8);
 		if (je32_to_cpu(node->d.node_crc) != crc) {
-			printk(KERN_WARNING "Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-			       ref_offset(raw), je32_to_cpu(node->d.node_crc), crc);
+			pr_warn("Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+				ref_offset(raw),
+				je32_to_cpu(node->d.node_crc), crc);
 			goto bail;
 		}
 
 		if (strnlen(node->d.name, node->d.nsize) != node->d.nsize) {
-			printk(KERN_WARNING "Name in dirent node at 0x%08x contains zeroes\n", ref_offset(raw));
+			pr_warn("Name in dirent node at 0x%08x contains zeroes\n",
+				ref_offset(raw));
 			goto bail;
 		}
 
 		if (node->d.nsize) {
 			crc = crc32(0, node->d.name, node->d.nsize);
 			if (je32_to_cpu(node->d.name_crc) != crc) {
-				printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-				       ref_offset(raw), je32_to_cpu(node->d.name_crc), crc);
+				pr_warn("Name CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+					ref_offset(raw),
+					je32_to_cpu(node->d.name_crc), crc);
 				goto bail;
 			}
 		}
@@ -644,8 +667,8 @@
 	default:
 		/* If it's inode-less, we don't _know_ what it is. Just copy it intact */
 		if (ic) {
-			printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n",
-			       ref_offset(raw), je16_to_cpu(node->u.nodetype));
+			pr_warn("Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n",
+				ref_offset(raw), je16_to_cpu(node->u.nodetype));
 			goto bail;
 		}
 	}
@@ -657,12 +680,13 @@
 	ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node);
 
 	if (ret || (retlen != rawlen)) {
-		printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n",
-		       rawlen, phys_ofs, ret, retlen);
+		pr_notice("Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n",
+			  rawlen, phys_ofs, ret, retlen);
 		if (retlen) {
 			jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL);
 		} else {
-			printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", phys_ofs);
+			pr_notice("Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n",
+				  phys_ofs);
 		}
 		if (!retried) {
 			/* Try to reallocate space and retry */
@@ -671,7 +695,7 @@
 
 			retried = 1;
 
-			D1(printk(KERN_DEBUG "Retrying failed write of REF_PRISTINE node.\n"));
+			jffs2_dbg(1, "Retrying failed write of REF_PRISTINE node.\n");
 
 			jffs2_dbg_acct_sanity_check(c,jeb);
 			jffs2_dbg_acct_paranoia_check(c, jeb);
@@ -681,14 +705,16 @@
 							it is only an upper estimation */
 
 			if (!ret) {
-				D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs));
+				jffs2_dbg(1, "Allocated space at 0x%08x to retry failed write.\n",
+					  phys_ofs);
 
 				jffs2_dbg_acct_sanity_check(c,jeb);
 				jffs2_dbg_acct_paranoia_check(c, jeb);
 
 				goto retry;
 			}
-			D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
+			jffs2_dbg(1, "Failed to allocate space to retry failed write: %d!\n",
+				  ret);
 		}
 
 		if (!ret)
@@ -698,7 +724,8 @@
 	jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, rawlen, ic);
 
 	jffs2_mark_node_obsolete(c, raw);
-	D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw)));
+	jffs2_dbg(1, "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n",
+		  ref_offset(raw));
 
  out_node:
 	kfree(node);
@@ -725,29 +752,32 @@
 		/* For these, we don't actually need to read the old node */
 		mdatalen = jffs2_encode_dev(&dev, JFFS2_F_I_RDEV(f));
 		mdata = (char *)&dev;
-		D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen));
+		jffs2_dbg(1, "%s(): Writing %d bytes of kdev_t\n",
+			  __func__, mdatalen);
 	} else if (S_ISLNK(JFFS2_F_I_MODE(f))) {
 		mdatalen = fn->size;
 		mdata = kmalloc(fn->size, GFP_KERNEL);
 		if (!mdata) {
-			printk(KERN_WARNING "kmalloc of mdata failed in jffs2_garbage_collect_metadata()\n");
+			pr_warn("kmalloc of mdata failed in jffs2_garbage_collect_metadata()\n");
 			return -ENOMEM;
 		}
 		ret = jffs2_read_dnode(c, f, fn, mdata, 0, mdatalen);
 		if (ret) {
-			printk(KERN_WARNING "read of old metadata failed in jffs2_garbage_collect_metadata(): %d\n", ret);
+			pr_warn("read of old metadata failed in jffs2_garbage_collect_metadata(): %d\n",
+				ret);
 			kfree(mdata);
 			return ret;
 		}
-		D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bites of symlink target\n", mdatalen));
+		jffs2_dbg(1, "%s(): Writing %d bites of symlink target\n",
+			  __func__, mdatalen);
 
 	}
 
 	ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &alloclen,
 				JFFS2_SUMMARY_INODE_SIZE);
 	if (ret) {
-		printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n",
-		       sizeof(ri)+ mdatalen, ret);
+		pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n",
+			sizeof(ri) + mdatalen, ret);
 		goto out;
 	}
 
@@ -784,7 +814,7 @@
 	new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, ALLOC_GC);
 
 	if (IS_ERR(new_fn)) {
-		printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));
+		pr_warn("Error writing new dnode: %ld\n", PTR_ERR(new_fn));
 		ret = PTR_ERR(new_fn);
 		goto out;
 	}
@@ -827,14 +857,15 @@
 	ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &alloclen,
 				JFFS2_SUMMARY_DIRENT_SIZE(rd.nsize));
 	if (ret) {
-		printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n",
-		       sizeof(rd)+rd.nsize, ret);
+		pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n",
+			sizeof(rd)+rd.nsize, ret);
 		return ret;
 	}
 	new_fd = jffs2_write_dirent(c, f, &rd, fd->name, rd.nsize, ALLOC_GC);
 
 	if (IS_ERR(new_fd)) {
-		printk(KERN_WARNING "jffs2_write_dirent in garbage_collect_dirent failed: %ld\n", PTR_ERR(new_fd));
+		pr_warn("jffs2_write_dirent in garbage_collect_dirent failed: %ld\n",
+			PTR_ERR(new_fd));
 		return PTR_ERR(new_fd);
 	}
 	jffs2_add_fd_to_list(c, new_fd, &f->dents);
@@ -887,19 +918,22 @@
 			if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset))
 				continue;
 
-			D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw)));
+			jffs2_dbg(1, "Check potential deletion dirent at %08x\n",
+				  ref_offset(raw));
 
 			/* This is an obsolete node belonging to the same directory, and it's of the right
 			   length. We need to take a closer look...*/
 			ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)rd);
 			if (ret) {
-				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading obsolete node at %08x\n", ret, ref_offset(raw));
+				pr_warn("%s(): Read error (%d) reading obsolete node at %08x\n",
+					__func__, ret, ref_offset(raw));
 				/* If we can't read it, we don't need to continue to obsolete it. Continue */
 				continue;
 			}
 			if (retlen != rawlen) {
-				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %u) reading header from obsolete node at %08x\n",
-				       retlen, rawlen, ref_offset(raw));
+				pr_warn("%s(): Short read (%zd not %u) reading header from obsolete node at %08x\n",
+					__func__, retlen, rawlen,
+					ref_offset(raw));
 				continue;
 			}
 
@@ -923,8 +957,9 @@
 			   a new deletion dirent to replace it */
 			mutex_unlock(&c->erase_free_sem);
 
-			D1(printk(KERN_DEBUG "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n",
-				  ref_offset(fd->raw), fd->name, ref_offset(raw), je32_to_cpu(rd->ino)));
+			jffs2_dbg(1, "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n",
+				  ref_offset(fd->raw), fd->name,
+				  ref_offset(raw), je32_to_cpu(rd->ino));
 			kfree(rd);
 
 			return jffs2_garbage_collect_dirent(c, jeb, f, fd);
@@ -947,7 +982,8 @@
 		fdp = &(*fdp)->next;
 	}
 	if (!found) {
-		printk(KERN_WARNING "Deletion dirent \"%s\" not found in list for ino #%u\n", fd->name, f->inocache->ino);
+		pr_warn("Deletion dirent \"%s\" not found in list for ino #%u\n",
+			fd->name, f->inocache->ino);
 	}
 	jffs2_mark_node_obsolete(c, fd->raw);
 	jffs2_free_full_dirent(fd);
@@ -964,8 +1000,8 @@
 	uint32_t alloclen, ilen;
 	int ret;
 
-	D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n",
-		  f->inocache->ino, start, end));
+	jffs2_dbg(1, "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n",
+		  f->inocache->ino, start, end);
 
 	memset(&ri, 0, sizeof(ri));
 
@@ -976,35 +1012,37 @@
 		   write it out again with the _same_ version as before */
 		ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri);
 		if (readlen != sizeof(ri) || ret) {
-			printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %zd. Data will be lost by writing new hole node\n", ret, readlen);
+			pr_warn("Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %zd. Data will be lost by writing new hole node\n",
+				ret, readlen);
 			goto fill;
 		}
 		if (je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE) {
-			printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x)\n",
-			       ref_offset(fn->raw),
-			       je16_to_cpu(ri.nodetype), JFFS2_NODETYPE_INODE);
+			pr_warn("%s(): Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x)\n",
+				__func__, ref_offset(fn->raw),
+				je16_to_cpu(ri.nodetype), JFFS2_NODETYPE_INODE);
 			return -EIO;
 		}
 		if (je32_to_cpu(ri.totlen) != sizeof(ri)) {
-			printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%zx\n",
-			       ref_offset(fn->raw),
-			       je32_to_cpu(ri.totlen), sizeof(ri));
+			pr_warn("%s(): Node at 0x%08x had totlen 0x%x instead of expected 0x%zx\n",
+				__func__, ref_offset(fn->raw),
+				je32_to_cpu(ri.totlen), sizeof(ri));
 			return -EIO;
 		}
 		crc = crc32(0, &ri, sizeof(ri)-8);
 		if (crc != je32_to_cpu(ri.node_crc)) {
-			printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n",
-			       ref_offset(fn->raw),
-			       je32_to_cpu(ri.node_crc), crc);
+			pr_warn("%s: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n",
+				__func__, ref_offset(fn->raw),
+				je32_to_cpu(ri.node_crc), crc);
 			/* FIXME: We could possibly deal with this by writing new holes for each frag */
-			printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n",
-			       start, end, f->inocache->ino);
+			pr_warn("Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n",
+				start, end, f->inocache->ino);
 			goto fill;
 		}
 		if (ri.compr != JFFS2_COMPR_ZERO) {
-			printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", ref_offset(fn->raw));
-			printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n",
-			       start, end, f->inocache->ino);
+			pr_warn("%s(): Node 0x%08x wasn't a hole node!\n",
+				__func__, ref_offset(fn->raw));
+			pr_warn("Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n",
+				start, end, f->inocache->ino);
 			goto fill;
 		}
 	} else {
@@ -1043,14 +1081,14 @@
 	ret = jffs2_reserve_space_gc(c, sizeof(ri), &alloclen,
 				     JFFS2_SUMMARY_INODE_SIZE);
 	if (ret) {
-		printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n",
-		       sizeof(ri), ret);
+		pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n",
+			sizeof(ri), ret);
 		return ret;
 	}
 	new_fn = jffs2_write_dnode(c, f, &ri, NULL, 0, ALLOC_GC);
 
 	if (IS_ERR(new_fn)) {
-		printk(KERN_WARNING "Error writing new hole node: %ld\n", PTR_ERR(new_fn));
+		pr_warn("Error writing new hole node: %ld\n", PTR_ERR(new_fn));
 		return PTR_ERR(new_fn);
 	}
 	if (je32_to_cpu(ri.version) == f->highest_version) {
@@ -1070,9 +1108,9 @@
 	 * above.)
 	 */
 	D1(if(unlikely(fn->frags <= 1)) {
-		printk(KERN_WARNING "jffs2_garbage_collect_hole: Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d\n",
-		       fn->frags, je32_to_cpu(ri.version), f->highest_version,
-		       je32_to_cpu(ri.ino));
+			pr_warn("%s(): Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d\n",
+				__func__, fn->frags, je32_to_cpu(ri.version),
+				f->highest_version, je32_to_cpu(ri.ino));
 	});
 
 	/* This is a partially-overlapped hole node. Mark it REF_NORMAL not REF_PRISTINE */
@@ -1089,11 +1127,11 @@
 		}
 	}
 	if (fn->frags) {
-		printk(KERN_WARNING "jffs2_garbage_collect_hole: Old node still has frags!\n");
+		pr_warn("%s(): Old node still has frags!\n", __func__);
 		BUG();
 	}
 	if (!new_fn->frags) {
-		printk(KERN_WARNING "jffs2_garbage_collect_hole: New node has no frags!\n");
+		pr_warn("%s(): New node has no frags!\n", __func__);
 		BUG();
 	}
 
@@ -1117,8 +1155,8 @@
 
 	memset(&ri, 0, sizeof(ri));
 
-	D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n",
-		  f->inocache->ino, start, end));
+	jffs2_dbg(1, "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n",
+		  f->inocache->ino, start, end);
 
 	orig_end = end;
 	orig_start = start;
@@ -1149,15 +1187,15 @@
 			/* If the previous frag doesn't even reach the beginning, there's
 			   excessive fragmentation. Just merge. */
 			if (frag->ofs > min) {
-				D1(printk(KERN_DEBUG "Expanding down to cover partial frag (0x%x-0x%x)\n",
-					  frag->ofs, frag->ofs+frag->size));
+				jffs2_dbg(1, "Expanding down to cover partial frag (0x%x-0x%x)\n",
+					  frag->ofs, frag->ofs+frag->size);
 				start = frag->ofs;
 				continue;
 			}
 			/* OK. This frag holds the first byte of the page. */
 			if (!frag->node || !frag->node->raw) {
-				D1(printk(KERN_DEBUG "First frag in page is hole (0x%x-0x%x). Not expanding down.\n",
-					  frag->ofs, frag->ofs+frag->size));
+				jffs2_dbg(1, "First frag in page is hole (0x%x-0x%x). Not expanding down.\n",
+					  frag->ofs, frag->ofs+frag->size);
 				break;
 			} else {
 
@@ -1171,19 +1209,25 @@
 				jeb = &c->blocks[raw->flash_offset / c->sector_size];
 
 				if (jeb == c->gcblock) {
-					D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in gcblock at %08x\n",
-						  frag->ofs, frag->ofs+frag->size, ref_offset(raw)));
+					jffs2_dbg(1, "Expanding down to cover frag (0x%x-0x%x) in gcblock at %08x\n",
+						  frag->ofs,
+						  frag->ofs + frag->size,
+						  ref_offset(raw));
 					start = frag->ofs;
 					break;
 				}
 				if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) {
-					D1(printk(KERN_DEBUG "Not expanding down to cover frag (0x%x-0x%x) in clean block %08x\n",
-						  frag->ofs, frag->ofs+frag->size, jeb->offset));
+					jffs2_dbg(1, "Not expanding down to cover frag (0x%x-0x%x) in clean block %08x\n",
+						  frag->ofs,
+						  frag->ofs + frag->size,
+						  jeb->offset);
 					break;
 				}
 
-				D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in dirty block %08x\n",
-						  frag->ofs, frag->ofs+frag->size, jeb->offset));
+				jffs2_dbg(1, "Expanding down to cover frag (0x%x-0x%x) in dirty block %08x\n",
+					  frag->ofs,
+					  frag->ofs + frag->size,
+					  jeb->offset);
 				start = frag->ofs;
 				break;
 			}
@@ -1199,15 +1243,15 @@
 			/* If the previous frag doesn't even reach the beginning, there's lots
 			   of fragmentation. Just merge. */
 			if (frag->ofs+frag->size < max) {
-				D1(printk(KERN_DEBUG "Expanding up to cover partial frag (0x%x-0x%x)\n",
-					  frag->ofs, frag->ofs+frag->size));
+				jffs2_dbg(1, "Expanding up to cover partial frag (0x%x-0x%x)\n",
+					  frag->ofs, frag->ofs+frag->size);
 				end = frag->ofs + frag->size;
 				continue;
 			}
 
 			if (!frag->node || !frag->node->raw) {
-				D1(printk(KERN_DEBUG "Last frag in page is hole (0x%x-0x%x). Not expanding up.\n",
-					  frag->ofs, frag->ofs+frag->size));
+				jffs2_dbg(1, "Last frag in page is hole (0x%x-0x%x). Not expanding up.\n",
+					  frag->ofs, frag->ofs+frag->size);
 				break;
 			} else {
 
@@ -1221,25 +1265,31 @@
 				jeb = &c->blocks[raw->flash_offset / c->sector_size];
 
 				if (jeb == c->gcblock) {
-					D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in gcblock at %08x\n",
-						  frag->ofs, frag->ofs+frag->size, ref_offset(raw)));
+					jffs2_dbg(1, "Expanding up to cover frag (0x%x-0x%x) in gcblock at %08x\n",
+						  frag->ofs,
+						  frag->ofs + frag->size,
+						  ref_offset(raw));
 					end = frag->ofs + frag->size;
 					break;
 				}
 				if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) {
-					D1(printk(KERN_DEBUG "Not expanding up to cover frag (0x%x-0x%x) in clean block %08x\n",
-						  frag->ofs, frag->ofs+frag->size, jeb->offset));
+					jffs2_dbg(1, "Not expanding up to cover frag (0x%x-0x%x) in clean block %08x\n",
+						  frag->ofs,
+						  frag->ofs + frag->size,
+						  jeb->offset);
 					break;
 				}
 
-				D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in dirty block %08x\n",
-						  frag->ofs, frag->ofs+frag->size, jeb->offset));
+				jffs2_dbg(1, "Expanding up to cover frag (0x%x-0x%x) in dirty block %08x\n",
+					  frag->ofs,
+					  frag->ofs + frag->size,
+					  jeb->offset);
 				end = frag->ofs + frag->size;
 				break;
 			}
 		}
-		D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n",
-			  orig_start, orig_end, start, end));
+		jffs2_dbg(1, "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n",
+			  orig_start, orig_end, start, end);
 
 		D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size));
 		BUG_ON(end < orig_end);
@@ -1256,7 +1306,8 @@
 	pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg);
 
 	if (IS_ERR(pg_ptr)) {
-		printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg_ptr));
+		pr_warn("read_cache_page() returned error: %ld\n",
+			PTR_ERR(pg_ptr));
 		return PTR_ERR(pg_ptr);
 	}
 
@@ -1270,8 +1321,8 @@
 					&alloclen, JFFS2_SUMMARY_INODE_SIZE);
 
 		if (ret) {
-			printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n",
-			       sizeof(ri)+ JFFS2_MIN_DATA_LEN, ret);
+			pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n",
+				sizeof(ri) + JFFS2_MIN_DATA_LEN, ret);
 			break;
 		}
 		cdatalen = min_t(uint32_t, alloclen - sizeof(ri), end - offset);
@@ -1308,7 +1359,8 @@
 		jffs2_free_comprbuf(comprbuf, writebuf);
 
 		if (IS_ERR(new_fn)) {
-			printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));
+			pr_warn("Error writing new dnode: %ld\n",
+				PTR_ERR(new_fn));
 			ret = PTR_ERR(new_fn);
 			break;
 		}
diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c
index c082868..4f47aa2 100644
--- a/fs/jffs2/malloc.c
+++ b/fs/jffs2/malloc.c
@@ -9,6 +9,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/init.h>
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
index 5e03233..975a1f5 100644
--- a/fs/jffs2/nodelist.c
+++ b/fs/jffs2/nodelist.c
@@ -9,6 +9,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
@@ -687,8 +689,8 @@
 	if (!size)
 		return 0;
 	if (unlikely(size > jeb->free_size)) {
-		printk(KERN_CRIT "Dirty space 0x%x larger then free_size 0x%x (wasted 0x%x)\n",
-		       size, jeb->free_size, jeb->wasted_size);
+		pr_crit("Dirty space 0x%x larger then free_size 0x%x (wasted 0x%x)\n",
+			size, jeb->free_size, jeb->wasted_size);
 		BUG();
 	}
 	/* REF_EMPTY_NODE is !obsolete, so that works OK */
@@ -726,8 +728,10 @@
 
 		/* Last node in block. Use free_space */
 		if (unlikely(ref != jeb->last_node)) {
-			printk(KERN_CRIT "ref %p @0x%08x is not jeb->last_node (%p @0x%08x)\n",
-			       ref, ref_offset(ref), jeb->last_node, jeb->last_node?ref_offset(jeb->last_node):0);
+			pr_crit("ref %p @0x%08x is not jeb->last_node (%p @0x%08x)\n",
+				ref, ref_offset(ref), jeb->last_node,
+				jeb->last_node ?
+				ref_offset(jeb->last_node) : 0);
 			BUG();
 		}
 		ref_end = jeb->offset + c->sector_size - jeb->free_size;
@@ -747,16 +751,20 @@
 		if (!jeb)
 			jeb = &c->blocks[ref->flash_offset / c->sector_size];
 
-		printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n",
-		       ref, ref_offset(ref), ref_offset(ref)+ref->__totlen,
-		       ret, ref->__totlen);
+		pr_crit("Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n",
+			ref, ref_offset(ref), ref_offset(ref) + ref->__totlen,
+			ret, ref->__totlen);
 		if (ref_next(ref)) {
-			printk(KERN_CRIT "next %p (0x%08x-0x%08x)\n", ref_next(ref), ref_offset(ref_next(ref)),
-			       ref_offset(ref_next(ref))+ref->__totlen);
+			pr_crit("next %p (0x%08x-0x%08x)\n",
+				ref_next(ref), ref_offset(ref_next(ref)),
+				ref_offset(ref_next(ref)) + ref->__totlen);
 		} else 
-			printk(KERN_CRIT "No next ref. jeb->last_node is %p\n", jeb->last_node);
+			pr_crit("No next ref. jeb->last_node is %p\n",
+				jeb->last_node);
 
-		printk(KERN_CRIT "jeb->wasted_size %x, dirty_size %x, used_size %x, free_size %x\n", jeb->wasted_size, jeb->dirty_size, jeb->used_size, jeb->free_size);
+		pr_crit("jeb->wasted_size %x, dirty_size %x, used_size %x, free_size %x\n",
+			jeb->wasted_size, jeb->dirty_size, jeb->used_size,
+			jeb->free_size);
 
 #if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
 		__jffs2_dbg_dump_node_refs_nolock(c, jeb);
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index 694aa5b..6784d1e 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -9,6 +9,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/mtd/mtd.h>
 #include <linux/compiler.h>
@@ -46,10 +48,10 @@
 	/* align it */
 	minsize = PAD(minsize);
 
-	D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize));
+	jffs2_dbg(1, "%s(): Requested 0x%x bytes\n", __func__, minsize);
 	mutex_lock(&c->alloc_sem);
 
-	D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n"));
+	jffs2_dbg(1, "%s(): alloc sem got\n", __func__);
 
 	spin_lock(&c->erase_completion_lock);
 
@@ -73,11 +75,13 @@
 			dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size;
 			if (dirty < c->nospc_dirty_size) {
 				if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
-					D1(printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n"));
+					jffs2_dbg(1, "%s(): Low on dirty space to GC, but it's a deletion. Allowing...\n",
+						  __func__);
 					break;
 				}
-				D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n",
-					  dirty, c->unchecked_size, c->sector_size));
+				jffs2_dbg(1, "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n",
+					  dirty, c->unchecked_size,
+					  c->sector_size);
 
 				spin_unlock(&c->erase_completion_lock);
 				mutex_unlock(&c->alloc_sem);
@@ -96,12 +100,13 @@
 			avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size;
 			if ( (avail / c->sector_size) <= blocksneeded) {
 				if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
-					D1(printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n"));
+					jffs2_dbg(1, "%s(): Low on possibly available space, but it's a deletion. Allowing...\n",
+						  __func__);
 					break;
 				}
 
-				D1(printk(KERN_DEBUG "max. available size 0x%08x  < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n",
-					  avail, blocksneeded * c->sector_size));
+				jffs2_dbg(1, "max. available size 0x%08x  < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n",
+					  avail, blocksneeded * c->sector_size);
 				spin_unlock(&c->erase_completion_lock);
 				mutex_unlock(&c->alloc_sem);
 				return -ENOSPC;
@@ -109,9 +114,14 @@
 
 			mutex_unlock(&c->alloc_sem);
 
-			D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
-				  c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size,
-				  c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size));
+			jffs2_dbg(1, "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
+				  c->nr_free_blocks, c->nr_erasing_blocks,
+				  c->free_size, c->dirty_size, c->wasted_size,
+				  c->used_size, c->erasing_size, c->bad_size,
+				  c->free_size + c->dirty_size +
+				  c->wasted_size + c->used_size +
+				  c->erasing_size + c->bad_size,
+				  c->flash_size);
 			spin_unlock(&c->erase_completion_lock);
 
 			ret = jffs2_garbage_collect_pass(c);
@@ -124,7 +134,8 @@
 					DECLARE_WAITQUEUE(wait, current);
 					set_current_state(TASK_UNINTERRUPTIBLE);
 					add_wait_queue(&c->erase_wait, &wait);
-					D1(printk(KERN_DEBUG "%s waiting for erase to complete\n", __func__));
+					jffs2_dbg(1, "%s waiting for erase to complete\n",
+						  __func__);
 					spin_unlock(&c->erase_completion_lock);
 
 					schedule();
@@ -144,7 +155,7 @@
 
 		ret = jffs2_do_reserve_space(c, minsize, len, sumsize);
 		if (ret) {
-			D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret));
+			jffs2_dbg(1, "%s(): ret is %d\n", __func__, ret);
 		}
 	}
 	spin_unlock(&c->erase_completion_lock);
@@ -161,13 +172,14 @@
 	int ret = -EAGAIN;
 	minsize = PAD(minsize);
 
-	D1(printk(KERN_DEBUG "jffs2_reserve_space_gc(): Requested 0x%x bytes\n", minsize));
+	jffs2_dbg(1, "%s(): Requested 0x%x bytes\n", __func__, minsize);
 
 	spin_lock(&c->erase_completion_lock);
 	while(ret == -EAGAIN) {
 		ret = jffs2_do_reserve_space(c, minsize, len, sumsize);
 		if (ret) {
-			D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
+			jffs2_dbg(1, "%s(): looping, ret is %d\n",
+				  __func__, ret);
 		}
 	}
 	spin_unlock(&c->erase_completion_lock);
@@ -184,8 +196,8 @@
 {
 
 	if (c->nextblock == NULL) {
-		D1(printk(KERN_DEBUG "jffs2_close_nextblock: Erase block at 0x%08x has already been placed in a list\n",
-		  jeb->offset));
+		jffs2_dbg(1, "%s(): Erase block at 0x%08x has already been placed in a list\n",
+			  __func__, jeb->offset);
 		return;
 	}
 	/* Check, if we have a dirty block now, or if it was dirty already */
@@ -195,17 +207,20 @@
 		jeb->dirty_size += jeb->wasted_size;
 		jeb->wasted_size = 0;
 		if (VERYDIRTY(c, jeb->dirty_size)) {
-			D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
-			  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
+			jffs2_dbg(1, "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
+				  jeb->offset, jeb->free_size, jeb->dirty_size,
+				  jeb->used_size);
 			list_add_tail(&jeb->list, &c->very_dirty_list);
 		} else {
-			D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
-			  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
+			jffs2_dbg(1, "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
+				  jeb->offset, jeb->free_size, jeb->dirty_size,
+				  jeb->used_size);
 			list_add_tail(&jeb->list, &c->dirty_list);
 		}
 	} else {
-		D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
-		  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
+		jffs2_dbg(1, "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
+			  jeb->offset, jeb->free_size, jeb->dirty_size,
+			  jeb->used_size);
 		list_add_tail(&jeb->list, &c->clean_list);
 	}
 	c->nextblock = NULL;
@@ -230,13 +245,14 @@
 			list_move_tail(&ejeb->list, &c->erase_pending_list);
 			c->nr_erasing_blocks++;
 			jffs2_garbage_collect_trigger(c);
-			D1(printk(KERN_DEBUG "jffs2_find_nextblock: Triggering erase of erasable block at 0x%08x\n",
-				  ejeb->offset));
+			jffs2_dbg(1, "%s(): Triggering erase of erasable block at 0x%08x\n",
+				  __func__, ejeb->offset);
 		}
 
 		if (!c->nr_erasing_blocks &&
 			!list_empty(&c->erasable_pending_wbuf_list)) {
-			D1(printk(KERN_DEBUG "jffs2_find_nextblock: Flushing write buffer\n"));
+			jffs2_dbg(1, "%s(): Flushing write buffer\n",
+				  __func__);
 			/* c->nextblock is NULL, no update to c->nextblock allowed */
 			spin_unlock(&c->erase_completion_lock);
 			jffs2_flush_wbuf_pad(c);
@@ -248,9 +264,11 @@
 		if (!c->nr_erasing_blocks) {
 			/* Ouch. We're in GC, or we wouldn't have got here.
 			   And there's no space left. At all. */
-			printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n",
-				   c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no",
-				   list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
+			pr_crit("Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n",
+				c->nr_erasing_blocks, c->nr_free_blocks,
+				list_empty(&c->erasable_list) ? "yes" : "no",
+				list_empty(&c->erasing_list) ? "yes" : "no",
+				list_empty(&c->erase_pending_list) ? "yes" : "no");
 			return -ENOSPC;
 		}
 
@@ -278,7 +296,8 @@
 		c->wbuf_ofs = 0xffffffff;
 #endif
 
-	D1(printk(KERN_DEBUG "jffs2_find_nextblock(): new nextblock = 0x%08x\n", c->nextblock->offset));
+	jffs2_dbg(1, "%s(): new nextblock = 0x%08x\n",
+		  __func__, c->nextblock->offset);
 
 	return 0;
 }
@@ -345,7 +364,8 @@
 
 			if (jffs2_wbuf_dirty(c)) {
 				spin_unlock(&c->erase_completion_lock);
-				D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
+				jffs2_dbg(1, "%s(): Flushing write buffer\n",
+					  __func__);
 				jffs2_flush_wbuf_pad(c);
 				spin_lock(&c->erase_completion_lock);
 				jeb = c->nextblock;
@@ -387,7 +407,8 @@
 		jeb = c->nextblock;
 
 		if (jeb->free_size != c->sector_size - c->cleanmarker_size) {
-			printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
+			pr_warn("Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n",
+				jeb->offset, jeb->free_size);
 			goto restart;
 		}
 	}
@@ -408,8 +429,9 @@
 		spin_lock(&c->erase_completion_lock);
 	}
 
-	D1(printk(KERN_DEBUG "jffs2_do_reserve_space(): Giving 0x%x bytes at 0x%x\n",
-		  *len, jeb->offset + (c->sector_size - jeb->free_size)));
+	jffs2_dbg(1, "%s(): Giving 0x%x bytes at 0x%x\n",
+		  __func__,
+		  *len, jeb->offset + (c->sector_size - jeb->free_size));
 	return 0;
 }
 
@@ -434,20 +456,22 @@
 
 	jeb = &c->blocks[ofs / c->sector_size];
 
-	D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n",
-		  ofs & ~3, ofs & 3, len));
+	jffs2_dbg(1, "%s(): Node at 0x%x(%d), size 0x%x\n",
+		  __func__, ofs & ~3, ofs & 3, len);
 #if 1
 	/* Allow non-obsolete nodes only to be added at the end of c->nextblock, 
 	   if c->nextblock is set. Note that wbuf.c will file obsolete nodes
 	   even after refiling c->nextblock */
 	if ((c->nextblock || ((ofs & 3) != REF_OBSOLETE))
 	    && (jeb != c->nextblock || (ofs & ~3) != jeb->offset + (c->sector_size - jeb->free_size))) {
-		printk(KERN_WARNING "argh. node added in wrong place at 0x%08x(%d)\n", ofs & ~3, ofs & 3);
+		pr_warn("argh. node added in wrong place at 0x%08x(%d)\n",
+			ofs & ~3, ofs & 3);
 		if (c->nextblock)
-			printk(KERN_WARNING "nextblock 0x%08x", c->nextblock->offset);
+			pr_warn("nextblock 0x%08x", c->nextblock->offset);
 		else
-			printk(KERN_WARNING "No nextblock");
-		printk(", expected at %08x\n", jeb->offset + (c->sector_size - jeb->free_size));
+			pr_warn("No nextblock");
+		pr_cont(", expected at %08x\n",
+			jeb->offset + (c->sector_size - jeb->free_size));
 		return ERR_PTR(-EINVAL);
 	}
 #endif
@@ -457,8 +481,9 @@
 
 	if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) {
 		/* If it lives on the dirty_list, jffs2_reserve_space will put it there */
-		D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
-			  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
+		jffs2_dbg(1, "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
+			  jeb->offset, jeb->free_size, jeb->dirty_size,
+			  jeb->used_size);
 		if (jffs2_wbuf_dirty(c)) {
 			/* Flush the last write in the block if it's outstanding */
 			spin_unlock(&c->erase_completion_lock);
@@ -480,7 +505,7 @@
 
 void jffs2_complete_reservation(struct jffs2_sb_info *c)
 {
-	D1(printk(KERN_DEBUG "jffs2_complete_reservation()\n"));
+	jffs2_dbg(1, "jffs2_complete_reservation()\n");
 	spin_lock(&c->erase_completion_lock);
 	jffs2_garbage_collect_trigger(c);
 	spin_unlock(&c->erase_completion_lock);
@@ -493,7 +518,7 @@
 
 	list_for_each(this, head) {
 		if (this == obj) {
-			D1(printk("%p is on list at %p\n", obj, head));
+			jffs2_dbg(1, "%p is on list at %p\n", obj, head);
 			return 1;
 
 		}
@@ -511,16 +536,18 @@
 	uint32_t freed_len;
 
 	if(unlikely(!ref)) {
-		printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n");
+		pr_notice("EEEEEK. jffs2_mark_node_obsolete called with NULL node\n");
 		return;
 	}
 	if (ref_obsolete(ref)) {
-		D1(printk(KERN_DEBUG "jffs2_mark_node_obsolete called with already obsolete node at 0x%08x\n", ref_offset(ref)));
+		jffs2_dbg(1, "%s(): called with already obsolete node at 0x%08x\n",
+			  __func__, ref_offset(ref));
 		return;
 	}
 	blocknr = ref->flash_offset / c->sector_size;
 	if (blocknr >= c->nr_blocks) {
-		printk(KERN_NOTICE "raw node at 0x%08x is off the end of device!\n", ref->flash_offset);
+		pr_notice("raw node at 0x%08x is off the end of device!\n",
+			  ref->flash_offset);
 		BUG();
 	}
 	jeb = &c->blocks[blocknr];
@@ -542,27 +569,31 @@
 
 	if (ref_flags(ref) == REF_UNCHECKED) {
 		D1(if (unlikely(jeb->unchecked_size < freed_len)) {
-			printk(KERN_NOTICE "raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x\n",
-			       freed_len, blocknr, ref->flash_offset, jeb->used_size);
+				pr_notice("raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x\n",
+					  freed_len, blocknr,
+					  ref->flash_offset, jeb->used_size);
 			BUG();
 		})
-		D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), freed_len));
+			jffs2_dbg(1, "Obsoleting previously unchecked node at 0x%08x of len %x\n",
+				  ref_offset(ref), freed_len);
 		jeb->unchecked_size -= freed_len;
 		c->unchecked_size -= freed_len;
 	} else {
 		D1(if (unlikely(jeb->used_size < freed_len)) {
-			printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n",
-			       freed_len, blocknr, ref->flash_offset, jeb->used_size);
+				pr_notice("raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n",
+					  freed_len, blocknr,
+					  ref->flash_offset, jeb->used_size);
 			BUG();
 		})
-		D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %#x: ", ref_offset(ref), freed_len));
+			jffs2_dbg(1, "Obsoleting node at 0x%08x of len %#x: ",
+				  ref_offset(ref), freed_len);
 		jeb->used_size -= freed_len;
 		c->used_size -= freed_len;
 	}
 
 	// Take care, that wasted size is taken into concern
 	if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + freed_len)) && jeb != c->nextblock) {
-		D1(printk("Dirtying\n"));
+		jffs2_dbg(1, "Dirtying\n");
 		addedsize = freed_len;
 		jeb->dirty_size += freed_len;
 		c->dirty_size += freed_len;
@@ -570,12 +601,12 @@
 		/* Convert wasted space to dirty, if not a bad block */
 		if (jeb->wasted_size) {
 			if (on_list(&jeb->list, &c->bad_used_list)) {
-				D1(printk(KERN_DEBUG "Leaving block at %08x on the bad_used_list\n",
-					  jeb->offset));
+				jffs2_dbg(1, "Leaving block at %08x on the bad_used_list\n",
+					  jeb->offset);
 				addedsize = 0; /* To fool the refiling code later */
 			} else {
-				D1(printk(KERN_DEBUG "Converting %d bytes of wasted space to dirty in block at %08x\n",
-					  jeb->wasted_size, jeb->offset));
+				jffs2_dbg(1, "Converting %d bytes of wasted space to dirty in block at %08x\n",
+					  jeb->wasted_size, jeb->offset);
 				addedsize += jeb->wasted_size;
 				jeb->dirty_size += jeb->wasted_size;
 				c->dirty_size += jeb->wasted_size;
@@ -584,7 +615,7 @@
 			}
 		}
 	} else {
-		D1(printk("Wasting\n"));
+		jffs2_dbg(1, "Wasting\n");
 		addedsize = 0;
 		jeb->wasted_size += freed_len;
 		c->wasted_size += freed_len;
@@ -606,50 +637,57 @@
 	}
 
 	if (jeb == c->nextblock) {
-		D2(printk(KERN_DEBUG "Not moving nextblock 0x%08x to dirty/erase_pending list\n", jeb->offset));
+		jffs2_dbg(2, "Not moving nextblock 0x%08x to dirty/erase_pending list\n",
+			  jeb->offset);
 	} else if (!jeb->used_size && !jeb->unchecked_size) {
 		if (jeb == c->gcblock) {
-			D1(printk(KERN_DEBUG "gcblock at 0x%08x completely dirtied. Clearing gcblock...\n", jeb->offset));
+			jffs2_dbg(1, "gcblock at 0x%08x completely dirtied. Clearing gcblock...\n",
+				  jeb->offset);
 			c->gcblock = NULL;
 		} else {
-			D1(printk(KERN_DEBUG "Eraseblock at 0x%08x completely dirtied. Removing from (dirty?) list...\n", jeb->offset));
+			jffs2_dbg(1, "Eraseblock at 0x%08x completely dirtied. Removing from (dirty?) list...\n",
+				  jeb->offset);
 			list_del(&jeb->list);
 		}
 		if (jffs2_wbuf_dirty(c)) {
-			D1(printk(KERN_DEBUG "...and adding to erasable_pending_wbuf_list\n"));
+			jffs2_dbg(1, "...and adding to erasable_pending_wbuf_list\n");
 			list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list);
 		} else {
 			if (jiffies & 127) {
 				/* Most of the time, we just erase it immediately. Otherwise we
 				   spend ages scanning it on mount, etc. */
-				D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n"));
+				jffs2_dbg(1, "...and adding to erase_pending_list\n");
 				list_add_tail(&jeb->list, &c->erase_pending_list);
 				c->nr_erasing_blocks++;
 				jffs2_garbage_collect_trigger(c);
 			} else {
 				/* Sometimes, however, we leave it elsewhere so it doesn't get
 				   immediately reused, and we spread the load a bit. */
-				D1(printk(KERN_DEBUG "...and adding to erasable_list\n"));
+				jffs2_dbg(1, "...and adding to erasable_list\n");
 				list_add_tail(&jeb->list, &c->erasable_list);
 			}
 		}
-		D1(printk(KERN_DEBUG "Done OK\n"));
+		jffs2_dbg(1, "Done OK\n");
 	} else if (jeb == c->gcblock) {
-		D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty_list\n", jeb->offset));
+		jffs2_dbg(2, "Not moving gcblock 0x%08x to dirty_list\n",
+			  jeb->offset);
 	} else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - addedsize)) {
-		D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", jeb->offset));
+		jffs2_dbg(1, "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n",
+			  jeb->offset);
 		list_del(&jeb->list);
-		D1(printk(KERN_DEBUG "...and adding to dirty_list\n"));
+		jffs2_dbg(1, "...and adding to dirty_list\n");
 		list_add_tail(&jeb->list, &c->dirty_list);
 	} else if (VERYDIRTY(c, jeb->dirty_size) &&
 		   !VERYDIRTY(c, jeb->dirty_size - addedsize)) {
-		D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is now very dirty. Removing from dirty list...\n", jeb->offset));
+		jffs2_dbg(1, "Eraseblock at 0x%08x is now very dirty. Removing from dirty list...\n",
+			  jeb->offset);
 		list_del(&jeb->list);
-		D1(printk(KERN_DEBUG "...and adding to very_dirty_list\n"));
+		jffs2_dbg(1, "...and adding to very_dirty_list\n");
 		list_add_tail(&jeb->list, &c->very_dirty_list);
 	} else {
-		D1(printk(KERN_DEBUG "Eraseblock at 0x%08x not moved anywhere. (free 0x%08x, dirty 0x%08x, used 0x%08x)\n",
-			  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
+		jffs2_dbg(1, "Eraseblock at 0x%08x not moved anywhere. (free 0x%08x, dirty 0x%08x, used 0x%08x)\n",
+			  jeb->offset, jeb->free_size, jeb->dirty_size,
+			  jeb->used_size);
 	}
 
 	spin_unlock(&c->erase_completion_lock);
@@ -665,33 +703,40 @@
 	   the block hasn't _already_ been erased, and that 'ref' itself hasn't been freed yet
 	   by jffs2_free_jeb_node_refs() in erase.c. Which is nice. */
 
-	D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref_offset(ref)));
+	jffs2_dbg(1, "obliterating obsoleted node at 0x%08x\n",
+		  ref_offset(ref));
 	ret = jffs2_flash_read(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n);
 	if (ret) {
-		printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret);
+		pr_warn("Read error reading from obsoleted node at 0x%08x: %d\n",
+			ref_offset(ref), ret);
 		goto out_erase_sem;
 	}
 	if (retlen != sizeof(n)) {
-		printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
+		pr_warn("Short read from obsoleted node at 0x%08x: %zd\n",
+			ref_offset(ref), retlen);
 		goto out_erase_sem;
 	}
 	if (PAD(je32_to_cpu(n.totlen)) != PAD(freed_len)) {
-		printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), freed_len);
+		pr_warn("Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n",
+			je32_to_cpu(n.totlen), freed_len);
 		goto out_erase_sem;
 	}
 	if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) {
-		D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x)\n", ref_offset(ref), je16_to_cpu(n.nodetype)));
+		jffs2_dbg(1, "Node at 0x%08x was already marked obsolete (nodetype 0x%04x)\n",
+			  ref_offset(ref), je16_to_cpu(n.nodetype));
 		goto out_erase_sem;
 	}
 	/* XXX FIXME: This is ugly now */
 	n.nodetype = cpu_to_je16(je16_to_cpu(n.nodetype) & ~JFFS2_NODE_ACCURATE);
 	ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n);
 	if (ret) {
-		printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret);
+		pr_warn("Write error in obliterating obsoleted node at 0x%08x: %d\n",
+			ref_offset(ref), ret);
 		goto out_erase_sem;
 	}
 	if (retlen != sizeof(n)) {
-		printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
+		pr_warn("Short write in obliterating obsoleted node at 0x%08x: %zd\n",
+			ref_offset(ref), retlen);
 		goto out_erase_sem;
 	}
 
@@ -751,8 +796,8 @@
 		return 1;
 
 	if (c->unchecked_size) {
-		D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
-			  c->unchecked_size, c->checked_ino));
+		jffs2_dbg(1, "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
+			  c->unchecked_size, c->checked_ino);
 		return 1;
 	}
 
@@ -780,8 +825,9 @@
 		}
 	}
 
-	D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x, vdirty_blocks %d: %s\n",
-		  c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, nr_very_dirty, ret?"yes":"no"));
+	jffs2_dbg(1, "%s(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x, vdirty_blocks %d: %s\n",
+		  __func__, c->nr_free_blocks, c->nr_erasing_blocks,
+		  c->dirty_size, nr_very_dirty, ret ? "yes" : "no");
 
 	return ret;
 }
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index ab65ee3..1cd3aec 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -76,7 +76,7 @@
 #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
 
 #define jffs2_flash_write(c, ofs, len, retlen, buf) jffs2_flash_direct_write(c, ofs, len, retlen, buf)
-#define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf))
+#define jffs2_flash_read(c, ofs, len, retlen, buf) (mtd_read((c)->mtd, ofs, len, retlen, buf))
 #define jffs2_flush_wbuf_pad(c) ({ do{} while(0); (void)(c), 0; })
 #define jffs2_flush_wbuf_gc(c, i) ({ do{} while(0); (void)(c), (void) i, 0; })
 #define jffs2_write_nand_badblock(c,jeb,bad_offset) (1)
@@ -108,8 +108,6 @@
 
 #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH)
 
-#define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
-#define jffs2_flash_read_oob(c, ofs, len, retlen, buf) ((c)->mtd->read_oob((c)->mtd, ofs, len, retlen, buf))
 #define jffs2_wbuf_dirty(c) (!!(c)->wbuf_len)
 
 /* wbuf.c */
diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c
index 3f39be1..0b042b1 100644
--- a/fs/jffs2/read.c
+++ b/fs/jffs2/read.c
@@ -9,6 +9,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/crc32.h>
@@ -36,24 +38,25 @@
 	ret = jffs2_flash_read(c, ref_offset(fd->raw), sizeof(*ri), &readlen, (char *)ri);
 	if (ret) {
 		jffs2_free_raw_inode(ri);
-		printk(KERN_WARNING "Error reading node from 0x%08x: %d\n", ref_offset(fd->raw), ret);
+		pr_warn("Error reading node from 0x%08x: %d\n",
+			ref_offset(fd->raw), ret);
 		return ret;
 	}
 	if (readlen != sizeof(*ri)) {
 		jffs2_free_raw_inode(ri);
-		printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n",
-		       ref_offset(fd->raw), sizeof(*ri), readlen);
+		pr_warn("Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n",
+			ref_offset(fd->raw), sizeof(*ri), readlen);
 		return -EIO;
 	}
 	crc = crc32(0, ri, sizeof(*ri)-8);
 
-	D1(printk(KERN_DEBUG "Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p\n",
+	jffs2_dbg(1, "Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p\n",
 		  ref_offset(fd->raw), je32_to_cpu(ri->node_crc),
 		  crc, je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize),
-		  je32_to_cpu(ri->offset), buf));
+		  je32_to_cpu(ri->offset), buf);
 	if (crc != je32_to_cpu(ri->node_crc)) {
-		printk(KERN_WARNING "Node CRC %08x != calculated CRC %08x for node at %08x\n",
-		       je32_to_cpu(ri->node_crc), crc, ref_offset(fd->raw));
+		pr_warn("Node CRC %08x != calculated CRC %08x for node at %08x\n",
+			je32_to_cpu(ri->node_crc), crc, ref_offset(fd->raw));
 		ret = -EIO;
 		goto out_ri;
 	}
@@ -66,8 +69,8 @@
 	}
 
 	D1(if(ofs + len > je32_to_cpu(ri->dsize)) {
-		printk(KERN_WARNING "jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n",
-		       len, ofs, je32_to_cpu(ri->dsize));
+			pr_warn("jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n",
+				len, ofs, je32_to_cpu(ri->dsize));
 		ret = -EINVAL;
 		goto out_ri;
 	});
@@ -107,8 +110,8 @@
 		decomprbuf = readbuf;
 	}
 
-	D2(printk(KERN_DEBUG "Read %d bytes to %p\n", je32_to_cpu(ri->csize),
-		  readbuf));
+	jffs2_dbg(2, "Read %d bytes to %p\n", je32_to_cpu(ri->csize),
+		  readbuf);
 	ret = jffs2_flash_read(c, (ref_offset(fd->raw)) + sizeof(*ri),
 			       je32_to_cpu(ri->csize), &readlen, readbuf);
 
@@ -119,18 +122,19 @@
 
 	crc = crc32(0, readbuf, je32_to_cpu(ri->csize));
 	if (crc != je32_to_cpu(ri->data_crc)) {
-		printk(KERN_WARNING "Data CRC %08x != calculated CRC %08x for node at %08x\n",
-		       je32_to_cpu(ri->data_crc), crc, ref_offset(fd->raw));
+		pr_warn("Data CRC %08x != calculated CRC %08x for node at %08x\n",
+			je32_to_cpu(ri->data_crc), crc, ref_offset(fd->raw));
 		ret = -EIO;
 		goto out_decomprbuf;
 	}
-	D2(printk(KERN_DEBUG "Data CRC matches calculated CRC %08x\n", crc));
+	jffs2_dbg(2, "Data CRC matches calculated CRC %08x\n", crc);
 	if (ri->compr != JFFS2_COMPR_NONE) {
-		D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n",
-			  je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf));
+		jffs2_dbg(2, "Decompress %d bytes from %p to %d bytes at %p\n",
+			  je32_to_cpu(ri->csize), readbuf,
+			  je32_to_cpu(ri->dsize), decomprbuf);
 		ret = jffs2_decompress(c, f, ri->compr | (ri->usercompr << 8), readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize));
 		if (ret) {
-			printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret);
+			pr_warn("Error: jffs2_decompress returned %d\n", ret);
 			goto out_decomprbuf;
 		}
 	}
@@ -157,8 +161,8 @@
 	struct jffs2_node_frag *frag;
 	int ret;
 
-	D1(printk(KERN_DEBUG "jffs2_read_inode_range: ino #%u, range 0x%08x-0x%08x\n",
-		  f->inocache->ino, offset, offset+len));
+	jffs2_dbg(1, "%s(): ino #%u, range 0x%08x-0x%08x\n",
+		  __func__, f->inocache->ino, offset, offset + len);
 
 	frag = jffs2_lookup_node_frag(&f->fragtree, offset);
 
@@ -168,22 +172,27 @@
 	 * (or perhaps is before it, if we've been asked to read off the
 	 * end of the file). */
 	while(offset < end) {
-		D2(printk(KERN_DEBUG "jffs2_read_inode_range: offset %d, end %d\n", offset, end));
+		jffs2_dbg(2, "%s(): offset %d, end %d\n",
+			  __func__, offset, end);
 		if (unlikely(!frag || frag->ofs > offset ||
 			     frag->ofs + frag->size <= offset)) {
 			uint32_t holesize = end - offset;
 			if (frag && frag->ofs > offset) {
-				D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset));
+				jffs2_dbg(1, "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n",
+					  f->inocache->ino, frag->ofs, offset);
 				holesize = min(holesize, frag->ofs - offset);
 			}
-			D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize));
+			jffs2_dbg(1, "Filling non-frag hole from %d-%d\n",
+				  offset, offset + holesize);
 			memset(buf, 0, holesize);
 			buf += holesize;
 			offset += holesize;
 			continue;
 		} else if (unlikely(!frag->node)) {
 			uint32_t holeend = min(end, frag->ofs + frag->size);
-			D1(printk(KERN_DEBUG "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size));
+			jffs2_dbg(1, "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n",
+				  offset, holeend, frag->ofs,
+				  frag->ofs + frag->size);
 			memset(buf, 0, holeend - offset);
 			buf += holeend - offset;
 			offset = holeend;
@@ -195,20 +204,23 @@
 
 			fragofs = offset - frag->ofs;
 			readlen = min(frag->size - fragofs, end - offset);
-			D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n",
-				  frag->ofs+fragofs, frag->ofs+fragofs+readlen,
-				  ref_offset(frag->node->raw), ref_flags(frag->node->raw)));
+			jffs2_dbg(1, "Reading %d-%d from node at 0x%08x (%d)\n",
+				  frag->ofs+fragofs,
+				  frag->ofs + fragofs+readlen,
+				  ref_offset(frag->node->raw),
+				  ref_flags(frag->node->raw));
 			ret = jffs2_read_dnode(c, f, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen);
-			D2(printk(KERN_DEBUG "node read done\n"));
+			jffs2_dbg(2, "node read done\n");
 			if (ret) {
-				D1(printk(KERN_DEBUG"jffs2_read_inode_range error %d\n",ret));
+				jffs2_dbg(1, "%s(): error %d\n",
+					  __func__, ret);
 				memset(buf, 0, readlen);
 				return ret;
 			}
 			buf += readlen;
 			offset += readlen;
 			frag = frag_next(frag);
-			D2(printk(KERN_DEBUG "node read was OK. Looping\n"));
+			jffs2_dbg(2, "node read was OK. Looping\n");
 		}
 	}
 	return 0;
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 3093ac4..dc0437e 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -9,6 +9,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index f994648..7654e87 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -9,6 +9,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -22,15 +24,15 @@
 
 #define DEFAULT_EMPTY_SCAN_SIZE 256
 
-#define noisy_printk(noise, args...) do { \
-	if (*(noise)) { \
-		printk(KERN_NOTICE args); \
-		 (*(noise))--; \
-		 if (!(*(noise))) { \
-			 printk(KERN_NOTICE "Further such events for this erase block will not be printed\n"); \
-		 } \
-	} \
-} while(0)
+#define noisy_printk(noise, fmt, ...)					\
+do {									\
+	if (*(noise)) {							\
+		pr_notice(fmt, ##__VA_ARGS__);				\
+		(*(noise))--;						\
+		if (!(*(noise)))					\
+			pr_notice("Further such events for this erase block will not be printed\n"); \
+	}								\
+} while (0)
 
 static uint32_t pseudo_random;
 
@@ -96,18 +98,17 @@
 #ifndef __ECOS
 	size_t pointlen, try_size;
 
-	if (c->mtd->point) {
-		ret = mtd_point(c->mtd, 0, c->mtd->size, &pointlen,
-				(void **)&flashbuf, NULL);
-		if (!ret && pointlen < c->mtd->size) {
-			/* Don't muck about if it won't let us point to the whole flash */
-			D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen));
-			mtd_unpoint(c->mtd, 0, pointlen);
-			flashbuf = NULL;
-		}
-		if (ret && ret != -EOPNOTSUPP)
-			D1(printk(KERN_DEBUG "MTD point failed %d\n", ret));
+	ret = mtd_point(c->mtd, 0, c->mtd->size, &pointlen,
+			(void **)&flashbuf, NULL);
+	if (!ret && pointlen < c->mtd->size) {
+		/* Don't muck about if it won't let us point to the whole flash */
+		jffs2_dbg(1, "MTD point returned len too short: 0x%zx\n",
+			  pointlen);
+		mtd_unpoint(c->mtd, 0, pointlen);
+		flashbuf = NULL;
 	}
+	if (ret && ret != -EOPNOTSUPP)
+		jffs2_dbg(1, "MTD point failed %d\n", ret);
 #endif
 	if (!flashbuf) {
 		/* For NAND it's quicker to read a whole eraseblock at a time,
@@ -117,15 +118,15 @@
 		else
 			try_size = PAGE_SIZE;
 
-		D1(printk(KERN_DEBUG "Trying to allocate readbuf of %zu "
-			"bytes\n", try_size));
+		jffs2_dbg(1, "Trying to allocate readbuf of %zu "
+			  "bytes\n", try_size);
 
 		flashbuf = mtd_kmalloc_up_to(c->mtd, &try_size);
 		if (!flashbuf)
 			return -ENOMEM;
 
-		D1(printk(KERN_DEBUG "Allocated readbuf of %zu bytes\n",
-			try_size));
+		jffs2_dbg(1, "Allocated readbuf of %zu bytes\n",
+			  try_size);
 
 		buf_size = (uint32_t)try_size;
 	}
@@ -178,7 +179,8 @@
 				c->nr_free_blocks++;
 			} else {
 				/* Dirt */
-				D1(printk(KERN_DEBUG "Adding all-dirty block at 0x%08x to erase_pending_list\n", jeb->offset));
+				jffs2_dbg(1, "Adding all-dirty block at 0x%08x to erase_pending_list\n",
+					  jeb->offset);
 				list_add(&jeb->list, &c->erase_pending_list);
 				c->nr_erasing_blocks++;
 			}
@@ -205,7 +207,8 @@
 				}
 				/* update collected summary information for the current nextblock */
 				jffs2_sum_move_collected(c, s);
-				D1(printk(KERN_DEBUG "jffs2_scan_medium(): new nextblock = 0x%08x\n", jeb->offset));
+				jffs2_dbg(1, "%s(): new nextblock = 0x%08x\n",
+					  __func__, jeb->offset);
 				c->nextblock = jeb;
 			} else {
 				ret = file_dirty(c, jeb);
@@ -217,20 +220,21 @@
 		case BLK_STATE_ALLDIRTY:
 			/* Nothing valid - not even a clean marker. Needs erasing. */
 			/* For now we just put it on the erasing list. We'll start the erases later */
-			D1(printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset));
+			jffs2_dbg(1, "Erase block at 0x%08x is not formatted. It will be erased\n",
+				  jeb->offset);
 			list_add(&jeb->list, &c->erase_pending_list);
 			c->nr_erasing_blocks++;
 			break;
 
 		case BLK_STATE_BADBLOCK:
-			D1(printk(KERN_NOTICE "JFFS2: Block at 0x%08x is bad\n", jeb->offset));
+			jffs2_dbg(1, "Block at 0x%08x is bad\n", jeb->offset);
 			list_add(&jeb->list, &c->bad_list);
 			c->bad_size += c->sector_size;
 			c->free_size -= c->sector_size;
 			bad_blocks++;
 			break;
 		default:
-			printk(KERN_WARNING "jffs2_scan_medium(): unknown block state\n");
+			pr_warn("%s(): unknown block state\n", __func__);
 			BUG();
 		}
 	}
@@ -250,16 +254,17 @@
 
 		uint32_t skip = c->nextblock->free_size % c->wbuf_pagesize;
 
-		D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n",
-			  skip));
+		jffs2_dbg(1, "%s(): Skipping %d bytes in nextblock to ensure page alignment\n",
+			  __func__, skip);
 		jffs2_prealloc_raw_node_refs(c, c->nextblock, 1);
 		jffs2_scan_dirty_space(c, c->nextblock, skip);
 	}
 #endif
 	if (c->nr_erasing_blocks) {
 		if ( !c->used_size && ((c->nr_free_blocks+empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) {
-			printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n");
-			printk(KERN_NOTICE "empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n",empty_blocks,bad_blocks,c->nr_blocks);
+			pr_notice("Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n");
+			pr_notice("empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n",
+				  empty_blocks, bad_blocks, c->nr_blocks);
 			ret = -EIO;
 			goto out;
 		}
@@ -287,11 +292,13 @@
 
 	ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
 	if (ret) {
-		D1(printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%x) returned %d\n", len, ofs, ret));
+		jffs2_dbg(1, "mtd->read(0x%x bytes from 0x%x) returned %d\n",
+			  len, ofs, ret);
 		return ret;
 	}
 	if (retlen < len) {
-		D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%zx bytes\n", ofs, retlen));
+		jffs2_dbg(1, "Read at 0x%x gave only 0x%zx bytes\n",
+			  ofs, retlen);
 		return -EIO;
 	}
 	return 0;
@@ -368,7 +375,7 @@
 
 	if (jffs2_sum_active())
 		jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset);
-	dbg_xattr("scaning xdatum at %#08x (xid=%u, version=%u)\n",
+	dbg_xattr("scanning xdatum at %#08x (xid=%u, version=%u)\n",
 		  ofs, xd->xid, xd->version);
 	return 0;
 }
@@ -449,7 +456,7 @@
 	ofs = jeb->offset;
 	prevofs = jeb->offset - 1;
 
-	D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs));
+	jffs2_dbg(1, "%s(): Scanning block at 0x%x\n", __func__, ofs);
 
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
 	if (jffs2_cleanmarker_oob(c)) {
@@ -459,7 +466,7 @@
 			return BLK_STATE_BADBLOCK;
 
 		ret = jffs2_check_nand_cleanmarker(c, jeb);
-		D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret));
+		jffs2_dbg(2, "jffs_check_nand_cleanmarker returned %d\n", ret);
 
 		/* Even if it's not found, we still scan to see
 		   if the block is empty. We use this information
@@ -561,7 +568,8 @@
 		if (jffs2_cleanmarker_oob(c)) {
 			/* scan oob, take care of cleanmarker */
 			int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound);
-			D2(printk(KERN_NOTICE "jffs2_check_oob_empty returned %d\n",ret));
+			jffs2_dbg(2, "jffs2_check_oob_empty returned %d\n",
+				  ret);
 			switch (ret) {
 			case 0:		return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF;
 			case 1: 	return BLK_STATE_ALLDIRTY;
@@ -569,15 +577,16 @@
 			}
 		}
 #endif
-		D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset));
+		jffs2_dbg(1, "Block at 0x%08x is empty (erased)\n",
+			  jeb->offset);
 		if (c->cleanmarker_size == 0)
 			return BLK_STATE_CLEANMARKER;	/* don't bother with re-erase */
 		else
 			return BLK_STATE_ALLFF;	/* OK to erase if all blocks are like this */
 	}
 	if (ofs) {
-		D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
-			  jeb->offset + ofs));
+		jffs2_dbg(1, "Free space at %08x ends at %08x\n", jeb->offset,
+			  jeb->offset + ofs);
 		if ((err = jffs2_prealloc_raw_node_refs(c, jeb, 1)))
 			return err;
 		if ((err = jffs2_scan_dirty_space(c, jeb, ofs)))
@@ -604,12 +613,13 @@
 		cond_resched();
 
 		if (ofs & 3) {
-			printk(KERN_WARNING "Eep. ofs 0x%08x not word-aligned!\n", ofs);
+			pr_warn("Eep. ofs 0x%08x not word-aligned!\n", ofs);
 			ofs = PAD(ofs);
 			continue;
 		}
 		if (ofs == prevofs) {
-			printk(KERN_WARNING "ofs 0x%08x has already been seen. Skipping\n", ofs);
+			pr_warn("ofs 0x%08x has already been seen. Skipping\n",
+				ofs);
 			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
 				return err;
 			ofs += 4;
@@ -618,8 +628,10 @@
 		prevofs = ofs;
 
 		if (jeb->offset + c->sector_size < ofs + sizeof(*node)) {
-			D1(printk(KERN_DEBUG "Fewer than %zd bytes left to end of block. (%x+%x<%x+%zx) Not reading\n", sizeof(struct jffs2_unknown_node),
-				  jeb->offset, c->sector_size, ofs, sizeof(*node)));
+			jffs2_dbg(1, "Fewer than %zd bytes left to end of block. (%x+%x<%x+%zx) Not reading\n",
+				  sizeof(struct jffs2_unknown_node),
+				  jeb->offset, c->sector_size, ofs,
+				  sizeof(*node));
 			if ((err = jffs2_scan_dirty_space(c, jeb, (jeb->offset + c->sector_size)-ofs)))
 				return err;
 			break;
@@ -627,8 +639,9 @@
 
 		if (buf_ofs + buf_len < ofs + sizeof(*node)) {
 			buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
-			D1(printk(KERN_DEBUG "Fewer than %zd bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n",
-				  sizeof(struct jffs2_unknown_node), buf_len, ofs));
+			jffs2_dbg(1, "Fewer than %zd bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n",
+				  sizeof(struct jffs2_unknown_node),
+				  buf_len, ofs);
 			err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
 			if (err)
 				return err;
@@ -645,13 +658,13 @@
 			ofs += 4;
 			scan_end = min_t(uint32_t, EMPTY_SCAN_SIZE(c->sector_size)/8, buf_len);
 
-			D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs));
+			jffs2_dbg(1, "Found empty flash at 0x%08x\n", ofs);
 		more_empty:
 			inbuf_ofs = ofs - buf_ofs;
 			while (inbuf_ofs < scan_end) {
 				if (unlikely(*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff)) {
-					printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n",
-					       empty_start, ofs);
+					pr_warn("Empty flash at 0x%08x ends at 0x%08x\n",
+						empty_start, ofs);
 					if ((err = jffs2_scan_dirty_space(c, jeb, ofs-empty_start)))
 						return err;
 					goto scan_more;
@@ -661,13 +674,15 @@
 				ofs += 4;
 			}
 			/* Ran off end. */
-			D1(printk(KERN_DEBUG "Empty flash to end of buffer at 0x%08x\n", ofs));
+			jffs2_dbg(1, "Empty flash to end of buffer at 0x%08x\n",
+				  ofs);
 
 			/* If we're only checking the beginning of a block with a cleanmarker,
 			   bail now */
 			if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) &&
 			    c->cleanmarker_size && !jeb->dirty_size && !ref_next(jeb->first_node)) {
-				D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size)));
+				jffs2_dbg(1, "%d bytes at start of block seems clean... assuming all clean\n",
+					  EMPTY_SCAN_SIZE(c->sector_size));
 				return BLK_STATE_CLEANMARKER;
 			}
 			if (!buf_size && (scan_end != buf_len)) {/* XIP/point case */
@@ -680,13 +695,14 @@
 			if (!buf_len) {
 				/* No more to read. Break out of main loop without marking
 				   this range of empty space as dirty (because it's not) */
-				D1(printk(KERN_DEBUG "Empty flash at %08x runs to end of block. Treating as free_space\n",
-					  empty_start));
+				jffs2_dbg(1, "Empty flash at %08x runs to end of block. Treating as free_space\n",
+					  empty_start);
 				break;
 			}
 			/* point never reaches here */
 			scan_end = buf_len;
-			D1(printk(KERN_DEBUG "Reading another 0x%x at 0x%08x\n", buf_len, ofs));
+			jffs2_dbg(1, "Reading another 0x%x at 0x%08x\n",
+				  buf_len, ofs);
 			err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
 			if (err)
 				return err;
@@ -695,22 +711,23 @@
 		}
 
 		if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) {
-			printk(KERN_WARNING "Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?\n", ofs);
+			pr_warn("Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?\n",
+				ofs);
 			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
 				return err;
 			ofs += 4;
 			continue;
 		}
 		if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) {
-			D1(printk(KERN_DEBUG "Dirty bitmask at 0x%08x\n", ofs));
+			jffs2_dbg(1, "Dirty bitmask at 0x%08x\n", ofs);
 			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
 				return err;
 			ofs += 4;
 			continue;
 		}
 		if (je16_to_cpu(node->magic) == JFFS2_OLD_MAGIC_BITMASK) {
-			printk(KERN_WARNING "Old JFFS2 bitmask found at 0x%08x\n", ofs);
-			printk(KERN_WARNING "You cannot use older JFFS2 filesystems with newer kernels\n");
+			pr_warn("Old JFFS2 bitmask found at 0x%08x\n", ofs);
+			pr_warn("You cannot use older JFFS2 filesystems with newer kernels\n");
 			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
 				return err;
 			ofs += 4;
@@ -718,7 +735,8 @@
 		}
 		if (je16_to_cpu(node->magic) != JFFS2_MAGIC_BITMASK) {
 			/* OK. We're out of possibilities. Whinge and move on */
-			noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n",
+			noisy_printk(&noise, "%s(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n",
+				     __func__,
 				     JFFS2_MAGIC_BITMASK, ofs,
 				     je16_to_cpu(node->magic));
 			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
@@ -733,7 +751,8 @@
 		hdr_crc = crc32(0, &crcnode, sizeof(crcnode)-4);
 
 		if (hdr_crc != je32_to_cpu(node->hdr_crc)) {
-			noisy_printk(&noise, "jffs2_scan_eraseblock(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n",
+			noisy_printk(&noise, "%s(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n",
+				     __func__,
 				     ofs, je16_to_cpu(node->magic),
 				     je16_to_cpu(node->nodetype),
 				     je32_to_cpu(node->totlen),
@@ -747,9 +766,9 @@
 
 		if (ofs + je32_to_cpu(node->totlen) > jeb->offset + c->sector_size) {
 			/* Eep. Node goes over the end of the erase block. */
-			printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
-			       ofs, je32_to_cpu(node->totlen));
-			printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n");
+			pr_warn("Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
+				ofs, je32_to_cpu(node->totlen));
+			pr_warn("Perhaps the file system was created with the wrong erase size?\n");
 			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
 				return err;
 			ofs += 4;
@@ -758,7 +777,8 @@
 
 		if (!(je16_to_cpu(node->nodetype) & JFFS2_NODE_ACCURATE)) {
 			/* Wheee. This is an obsoleted node */
-			D2(printk(KERN_DEBUG "Node at 0x%08x is obsolete. Skipping\n", ofs));
+			jffs2_dbg(2, "Node at 0x%08x is obsolete. Skipping\n",
+				  ofs);
 			if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
 				return err;
 			ofs += PAD(je32_to_cpu(node->totlen));
@@ -769,8 +789,9 @@
 		case JFFS2_NODETYPE_INODE:
 			if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) {
 				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
-				D1(printk(KERN_DEBUG "Fewer than %zd bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n",
-					  sizeof(struct jffs2_raw_inode), buf_len, ofs));
+				jffs2_dbg(1, "Fewer than %zd bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n",
+					  sizeof(struct jffs2_raw_inode),
+					  buf_len, ofs);
 				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
 				if (err)
 					return err;
@@ -785,8 +806,9 @@
 		case JFFS2_NODETYPE_DIRENT:
 			if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
 				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
-				D1(printk(KERN_DEBUG "Fewer than %d bytes (dirent node) left to end of buf. Reading 0x%x at 0x%08x\n",
-					  je32_to_cpu(node->totlen), buf_len, ofs));
+				jffs2_dbg(1, "Fewer than %d bytes (dirent node) left to end of buf. Reading 0x%x at 0x%08x\n",
+					  je32_to_cpu(node->totlen), buf_len,
+					  ofs);
 				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
 				if (err)
 					return err;
@@ -802,9 +824,9 @@
 		case JFFS2_NODETYPE_XATTR:
 			if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
 				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
-				D1(printk(KERN_DEBUG "Fewer than %d bytes (xattr node)"
-					  " left to end of buf. Reading 0x%x at 0x%08x\n",
-					  je32_to_cpu(node->totlen), buf_len, ofs));
+				jffs2_dbg(1, "Fewer than %d bytes (xattr node) left to end of buf. Reading 0x%x at 0x%08x\n",
+					  je32_to_cpu(node->totlen), buf_len,
+					  ofs);
 				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
 				if (err)
 					return err;
@@ -819,9 +841,9 @@
 		case JFFS2_NODETYPE_XREF:
 			if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
 				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
-				D1(printk(KERN_DEBUG "Fewer than %d bytes (xref node)"
-					  " left to end of buf. Reading 0x%x at 0x%08x\n",
-					  je32_to_cpu(node->totlen), buf_len, ofs));
+				jffs2_dbg(1, "Fewer than %d bytes (xref node) left to end of buf. Reading 0x%x at 0x%08x\n",
+					  je32_to_cpu(node->totlen), buf_len,
+					  ofs);
 				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
 				if (err)
 					return err;
@@ -836,15 +858,17 @@
 #endif	/* CONFIG_JFFS2_FS_XATTR */
 
 		case JFFS2_NODETYPE_CLEANMARKER:
-			D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs));
+			jffs2_dbg(1, "CLEANMARKER node found at 0x%08x\n", ofs);
 			if (je32_to_cpu(node->totlen) != c->cleanmarker_size) {
-				printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n",
-				       ofs, je32_to_cpu(node->totlen), c->cleanmarker_size);
+				pr_notice("CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n",
+					  ofs, je32_to_cpu(node->totlen),
+					  c->cleanmarker_size);
 				if ((err = jffs2_scan_dirty_space(c, jeb, PAD(sizeof(struct jffs2_unknown_node)))))
 					return err;
 				ofs += PAD(sizeof(struct jffs2_unknown_node));
 			} else if (jeb->first_node) {
-				printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)\n", ofs, jeb->offset);
+				pr_notice("CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)\n",
+					  ofs, jeb->offset);
 				if ((err = jffs2_scan_dirty_space(c, jeb, PAD(sizeof(struct jffs2_unknown_node)))))
 					return err;
 				ofs += PAD(sizeof(struct jffs2_unknown_node));
@@ -866,7 +890,8 @@
 		default:
 			switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) {
 			case JFFS2_FEATURE_ROCOMPAT:
-				printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
+				pr_notice("Read-only compatible feature node (0x%04x) found at offset 0x%08x\n",
+					  je16_to_cpu(node->nodetype), ofs);
 				c->flags |= JFFS2_SB_FLAG_RO;
 				if (!(jffs2_is_readonly(c)))
 					return -EROFS;
@@ -876,18 +901,21 @@
 				break;
 
 			case JFFS2_FEATURE_INCOMPAT:
-				printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
+				pr_notice("Incompatible feature node (0x%04x) found at offset 0x%08x\n",
+					  je16_to_cpu(node->nodetype), ofs);
 				return -EINVAL;
 
 			case JFFS2_FEATURE_RWCOMPAT_DELETE:
-				D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
+				jffs2_dbg(1, "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n",
+					  je16_to_cpu(node->nodetype), ofs);
 				if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
 					return err;
 				ofs += PAD(je32_to_cpu(node->totlen));
 				break;
 
 			case JFFS2_FEATURE_RWCOMPAT_COPY: {
-				D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
+				jffs2_dbg(1, "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n",
+					  je16_to_cpu(node->nodetype), ofs);
 
 				jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(node->totlen)), NULL);
 
@@ -908,8 +936,9 @@
 		}
 	}
 
-	D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x, wasted 0x%08x\n",
-		  jeb->offset,jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size, jeb->wasted_size));
+	jffs2_dbg(1, "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x, wasted 0x%08x\n",
+		  jeb->offset, jeb->free_size, jeb->dirty_size,
+		  jeb->unchecked_size, jeb->used_size, jeb->wasted_size);
 	
 	/* mark_node_obsolete can add to wasted !! */
 	if (jeb->wasted_size) {
@@ -935,7 +964,7 @@
 
 	ic = jffs2_alloc_inode_cache();
 	if (!ic) {
-		printk(KERN_NOTICE "jffs2_scan_make_inode_cache(): allocation of inode cache failed\n");
+		pr_notice("%s(): allocation of inode cache failed\n", __func__);
 		return NULL;
 	}
 	memset(ic, 0, sizeof(*ic));
@@ -954,7 +983,7 @@
 	struct jffs2_inode_cache *ic;
 	uint32_t crc, ino = je32_to_cpu(ri->ino);
 
-	D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs));
+	jffs2_dbg(1, "%s(): Node at 0x%08x\n", __func__, ofs);
 
 	/* We do very little here now. Just check the ino# to which we should attribute
 	   this node; we can do all the CRC checking etc. later. There's a tradeoff here --
@@ -968,9 +997,8 @@
 	/* Check the node CRC in any case. */
 	crc = crc32(0, ri, sizeof(*ri)-8);
 	if (crc != je32_to_cpu(ri->node_crc)) {
-		printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on "
-		       "node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-		       ofs, je32_to_cpu(ri->node_crc), crc);
+		pr_notice("%s(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+			  __func__, ofs, je32_to_cpu(ri->node_crc), crc);
 		/*
 		 * We believe totlen because the CRC on the node
 		 * _header_ was OK, just the node itself failed.
@@ -989,10 +1017,10 @@
 	/* Wheee. It worked */
 	jffs2_link_node_ref(c, jeb, ofs | REF_UNCHECKED, PAD(je32_to_cpu(ri->totlen)), ic);
 
-	D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n",
+	jffs2_dbg(1, "Node is ino #%u, version %d. Range 0x%x-0x%x\n",
 		  je32_to_cpu(ri->ino), je32_to_cpu(ri->version),
 		  je32_to_cpu(ri->offset),
-		  je32_to_cpu(ri->offset)+je32_to_cpu(ri->dsize)));
+		  je32_to_cpu(ri->offset)+je32_to_cpu(ri->dsize));
 
 	pseudo_random += je32_to_cpu(ri->version);
 
@@ -1012,15 +1040,15 @@
 	uint32_t crc;
 	int err;
 
-	D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", ofs));
+	jffs2_dbg(1, "%s(): Node at 0x%08x\n", __func__, ofs);
 
 	/* We don't get here unless the node is still valid, so we don't have to
 	   mask in the ACCURATE bit any more. */
 	crc = crc32(0, rd, sizeof(*rd)-8);
 
 	if (crc != je32_to_cpu(rd->node_crc)) {
-		printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-		       ofs, je32_to_cpu(rd->node_crc), crc);
+		pr_notice("%s(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+			  __func__, ofs, je32_to_cpu(rd->node_crc), crc);
 		/* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
 		if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rd->totlen)))))
 			return err;
@@ -1032,7 +1060,7 @@
 	/* Should never happen. Did. (OLPC trac #4184)*/
 	checkedlen = strnlen(rd->name, rd->nsize);
 	if (checkedlen < rd->nsize) {
-		printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n",
+		pr_err("Dirent at %08x has zeroes in name. Truncating to %d chars\n",
 		       ofs, checkedlen);
 	}
 	fd = jffs2_alloc_full_dirent(checkedlen+1);
@@ -1044,9 +1072,10 @@
 
 	crc = crc32(0, fd->name, rd->nsize);
 	if (crc != je32_to_cpu(rd->name_crc)) {
-		printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-		       ofs, je32_to_cpu(rd->name_crc), crc);
-		D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino)));
+		pr_notice("%s(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+			  __func__, ofs, je32_to_cpu(rd->name_crc), crc);
+		jffs2_dbg(1, "Name for which CRC failed is (now) '%s', ino #%d\n",
+			  fd->name, je32_to_cpu(rd->ino));
 		jffs2_free_full_dirent(fd);
 		/* FIXME: Why do we believe totlen? */
 		/* We believe totlen because the CRC on the node _header_ was OK, just the name failed. */
diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c
index 0f20208..aca97f3 100644
--- a/fs/jffs2/security.c
+++ b/fs/jffs2/security.c
@@ -23,8 +23,8 @@
 #include "nodelist.h"
 
 /* ---- Initial Security Label(s) Attachment callback --- */
-int jffs2_initxattrs(struct inode *inode, const struct xattr *xattr_array,
-		     void *fs_info)
+static int jffs2_initxattrs(struct inode *inode,
+			    const struct xattr *xattr_array, void *fs_info)
 {
 	const struct xattr *xattr;
 	int err = 0;
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c
index e537fb0..c522d09 100644
--- a/fs/jffs2/summary.c
+++ b/fs/jffs2/summary.c
@@ -11,6 +11,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
@@ -442,13 +444,16 @@
 				/* This should never happen, but https://dev.laptop.org/ticket/4184 */
 				checkedlen = strnlen(spd->name, spd->nsize);
 				if (!checkedlen) {
-					printk(KERN_ERR "Dirent at %08x has zero at start of name. Aborting mount.\n",
-					       jeb->offset + je32_to_cpu(spd->offset));
+					pr_err("Dirent at %08x has zero at start of name. Aborting mount.\n",
+					       jeb->offset +
+					       je32_to_cpu(spd->offset));
 					return -EIO;
 				}
 				if (checkedlen < spd->nsize) {
-					printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n",
-					       jeb->offset + je32_to_cpu(spd->offset), checkedlen);
+					pr_err("Dirent at %08x has zeroes in name. Truncating to %d chars\n",
+					       jeb->offset +
+					       je32_to_cpu(spd->offset),
+					       checkedlen);
 				}
 
 
@@ -808,8 +813,7 @@
 
 	sum_ofs = jeb->offset + c->sector_size - jeb->free_size;
 
-	dbg_summary("JFFS2: writing out data to flash to pos : 0x%08x\n",
-		    sum_ofs);
+	dbg_summary("writing out data to flash to pos : 0x%08x\n", sum_ofs);
 
 	ret = jffs2_flash_writev(c, vecs, 2, sum_ofs, &retlen, 0);
 
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index f2d96b5..f9916f3 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -9,6 +9,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -69,7 +71,7 @@
 	sb->s_dirt = 0;
 
 	if (!(sb->s_flags & MS_RDONLY)) {
-		D1(printk(KERN_DEBUG "jffs2_write_super()\n"));
+		jffs2_dbg(1, "%s()\n", __func__);
 		jffs2_flush_wbuf_gc(c, 0);
 	}
 
@@ -214,8 +216,8 @@
 						JFFS2_COMPR_MODE_FORCEZLIB;
 #endif
 			else {
-				printk(KERN_ERR "JFFS2 Error: unknown compressor \"%s\"",
-						name);
+				pr_err("Error: unknown compressor \"%s\"\n",
+				       name);
 				kfree(name);
 				return -EINVAL;
 			}
@@ -223,8 +225,8 @@
 			c->mount_opts.override_compr = true;
 			break;
 		default:
-			printk(KERN_ERR "JFFS2 Error: unrecognized mount option '%s' or missing value\n",
-					p);
+			pr_err("Error: unrecognized mount option '%s' or missing value\n",
+			       p);
 			return -EINVAL;
 		}
 	}
@@ -266,9 +268,9 @@
 	struct jffs2_sb_info *c;
 	int ret;
 
-	D1(printk(KERN_DEBUG "jffs2_get_sb_mtd():"
+	jffs2_dbg(1, "jffs2_get_sb_mtd():"
 		  " New superblock for device %d (\"%s\")\n",
-		  sb->s_mtd->index, sb->s_mtd->name));
+		  sb->s_mtd->index, sb->s_mtd->name);
 
 	c = kzalloc(sizeof(*c), GFP_KERNEL);
 	if (!c)
@@ -315,7 +317,7 @@
 {
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
 
-	D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
+	jffs2_dbg(2, "%s()\n", __func__);
 
 	if (sb->s_dirt)
 		jffs2_write_super(sb);
@@ -336,7 +338,7 @@
 	kfree(c->inocache_list);
 	jffs2_clear_xattr_subsystem(c);
 	mtd_sync(c->mtd);
-	D1(printk(KERN_DEBUG "jffs2_put_super returning\n"));
+	jffs2_dbg(1, "%s(): returning\n", __func__);
 }
 
 static void jffs2_kill_sb(struct super_block *sb)
@@ -371,7 +373,7 @@
 	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
 	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
 
-	printk(KERN_INFO "JFFS2 version 2.2."
+	pr_info("version 2.2."
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
 	       " (NAND)"
 #endif
@@ -386,22 +388,22 @@
 						SLAB_MEM_SPREAD),
 					     jffs2_i_init_once);
 	if (!jffs2_inode_cachep) {
-		printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
+		pr_err("error: Failed to initialise inode cache\n");
 		return -ENOMEM;
 	}
 	ret = jffs2_compressors_init();
 	if (ret) {
-		printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n");
+		pr_err("error: Failed to initialise compressors\n");
 		goto out;
 	}
 	ret = jffs2_create_slab_caches();
 	if (ret) {
-		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
+		pr_err("error: Failed to initialise slab caches\n");
 		goto out_compressors;
 	}
 	ret = register_filesystem(&jffs2_fs_type);
 	if (ret) {
-		printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n");
+		pr_err("error: Failed to register filesystem\n");
 		goto out_slab;
 	}
 	return 0;
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
index e3035af..6e56333 100644
--- a/fs/jffs2/symlink.c
+++ b/fs/jffs2/symlink.c
@@ -9,6 +9,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/namei.h>
@@ -47,10 +49,11 @@
 	 */
 
 	if (!p) {
-		printk(KERN_ERR "jffs2_follow_link(): can't find symlink target\n");
+		pr_err("%s(): can't find symlink target\n", __func__);
 		p = ERR_PTR(-EIO);
 	}
-	D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->target));
+	jffs2_dbg(1, "%s(): target path is '%s'\n",
+		  __func__, (char *)f->target);
 
 	nd_set_link(nd, p);
 
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index 30e8f47..74d9be1 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -11,6 +11,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
@@ -91,7 +93,7 @@
 
 	new = kmalloc(sizeof(*new), GFP_KERNEL);
 	if (!new) {
-		D1(printk(KERN_DEBUG "No memory to allocate inodirty. Fallback to all considered dirty\n"));
+		jffs2_dbg(1, "No memory to allocate inodirty. Fallback to all considered dirty\n");
 		jffs2_clear_wbuf_ino_list(c);
 		c->wbuf_inodes = &inodirty_nomem;
 		return;
@@ -113,19 +115,20 @@
 	list_for_each_safe(this, next, &c->erasable_pending_wbuf_list) {
 		struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
 
-		D1(printk(KERN_DEBUG "Removing eraseblock at 0x%08x from erasable_pending_wbuf_list...\n", jeb->offset));
+		jffs2_dbg(1, "Removing eraseblock at 0x%08x from erasable_pending_wbuf_list...\n",
+			  jeb->offset);
 		list_del(this);
 		if ((jiffies + (n++)) & 127) {
 			/* Most of the time, we just erase it immediately. Otherwise we
 			   spend ages scanning it on mount, etc. */
-			D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n"));
+			jffs2_dbg(1, "...and adding to erase_pending_list\n");
 			list_add_tail(&jeb->list, &c->erase_pending_list);
 			c->nr_erasing_blocks++;
 			jffs2_garbage_collect_trigger(c);
 		} else {
 			/* Sometimes, however, we leave it elsewhere so it doesn't get
 			   immediately reused, and we spread the load a bit. */
-			D1(printk(KERN_DEBUG "...and adding to erasable_list\n"));
+			jffs2_dbg(1, "...and adding to erasable_list\n");
 			list_add_tail(&jeb->list, &c->erasable_list);
 		}
 	}
@@ -136,7 +139,7 @@
 
 static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int allow_empty)
 {
-	D1(printk("About to refile bad block at %08x\n", jeb->offset));
+	jffs2_dbg(1, "About to refile bad block at %08x\n", jeb->offset);
 
 	/* File the existing block on the bad_used_list.... */
 	if (c->nextblock == jeb)
@@ -144,12 +147,14 @@
 	else /* Not sure this should ever happen... need more coffee */
 		list_del(&jeb->list);
 	if (jeb->first_node) {
-		D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset));
+		jffs2_dbg(1, "Refiling block at %08x to bad_used_list\n",
+			  jeb->offset);
 		list_add(&jeb->list, &c->bad_used_list);
 	} else {
 		BUG_ON(allow_empty == REFILE_NOTEMPTY);
 		/* It has to have had some nodes or we couldn't be here */
-		D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset));
+		jffs2_dbg(1, "Refiling block at %08x to erase_pending_list\n",
+			  jeb->offset);
 		list_add(&jeb->list, &c->erase_pending_list);
 		c->nr_erasing_blocks++;
 		jffs2_garbage_collect_trigger(c);
@@ -230,10 +235,12 @@
 
 	ret = mtd_read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify);
 	if (ret && ret != -EUCLEAN && ret != -EBADMSG) {
-		printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x failed: %d\n", c->wbuf_ofs, ret);
+		pr_warn("%s(): Read back of page at %08x failed: %d\n",
+			__func__, c->wbuf_ofs, ret);
 		return ret;
 	} else if (retlen != c->wbuf_pagesize) {
-		printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x gave short read: %zd not %d.\n", ofs, retlen, c->wbuf_pagesize);
+		pr_warn("%s(): Read back of page at %08x gave short read: %zd not %d\n",
+			__func__, ofs, retlen, c->wbuf_pagesize);
 		return -EIO;
 	}
 	if (!memcmp(buf, c->wbuf_verify, c->wbuf_pagesize))
@@ -246,12 +253,12 @@
 	else
 		eccstr = "OK or unused";
 
-	printk(KERN_WARNING "Write verify error (ECC %s) at %08x. Wrote:\n",
-	       eccstr, c->wbuf_ofs);
+	pr_warn("Write verify error (ECC %s) at %08x. Wrote:\n",
+		eccstr, c->wbuf_ofs);
 	print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
 		       c->wbuf, c->wbuf_pagesize, 0);
 
-	printk(KERN_WARNING "Read back:\n");
+	pr_warn("Read back:\n");
 	print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
 		       c->wbuf_verify, c->wbuf_pagesize, 0);
 
@@ -308,7 +315,7 @@
 
 	if (!first_raw) {
 		/* All nodes were obsolete. Nothing to recover. */
-		D1(printk(KERN_DEBUG "No non-obsolete nodes to be recovered. Just filing block bad\n"));
+		jffs2_dbg(1, "No non-obsolete nodes to be recovered. Just filing block bad\n");
 		c->wbuf_len = 0;
 		return;
 	}
@@ -331,7 +338,7 @@
 
 		buf = kmalloc(end - start, GFP_KERNEL);
 		if (!buf) {
-			printk(KERN_CRIT "Malloc failure in wbuf recovery. Data loss ensues.\n");
+			pr_crit("Malloc failure in wbuf recovery. Data loss ensues.\n");
 
 			goto read_failed;
 		}
@@ -346,7 +353,7 @@
 			ret = 0;
 
 		if (ret || retlen != c->wbuf_ofs - start) {
-			printk(KERN_CRIT "Old data are already lost in wbuf recovery. Data loss ensues.\n");
+			pr_crit("Old data are already lost in wbuf recovery. Data loss ensues.\n");
 
 			kfree(buf);
 			buf = NULL;
@@ -380,7 +387,7 @@
 	/* ... and get an allocation of space from a shiny new block instead */
 	ret = jffs2_reserve_space_gc(c, end-start, &len, JFFS2_SUMMARY_NOSUM_SIZE);
 	if (ret) {
-		printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
+		pr_warn("Failed to allocate space for wbuf recovery. Data loss ensues.\n");
 		kfree(buf);
 		return;
 	}
@@ -390,7 +397,7 @@
 
 	ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile);
 	if (ret) {
-		printk(KERN_WARNING "Failed to allocate node refs for wbuf recovery. Data loss ensues.\n");
+		pr_warn("Failed to allocate node refs for wbuf recovery. Data loss ensues.\n");
 		kfree(buf);
 		return;
 	}
@@ -406,13 +413,13 @@
 		unsigned char *rewrite_buf = buf?:c->wbuf;
 		uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize);
 
-		D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n",
-			  towrite, ofs));
+		jffs2_dbg(1, "Write 0x%x bytes at 0x%08x in wbuf recover\n",
+			  towrite, ofs);
 
 #ifdef BREAKMEHEADER
 		static int breakme;
 		if (breakme++ == 20) {
-			printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs);
+			pr_notice("Faking write error at 0x%08x\n", ofs);
 			breakme = 0;
 			mtd_write(c->mtd, ofs, towrite, &retlen, brokenbuf);
 			ret = -EIO;
@@ -423,7 +430,7 @@
 
 		if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) {
 			/* Argh. We tried. Really we did. */
-			printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n");
+			pr_crit("Recovery of wbuf failed due to a second write error\n");
 			kfree(buf);
 
 			if (retlen)
@@ -431,7 +438,7 @@
 
 			return;
 		}
-		printk(KERN_NOTICE "Recovery of wbuf succeeded to %08x\n", ofs);
+		pr_notice("Recovery of wbuf succeeded to %08x\n", ofs);
 
 		c->wbuf_len = (end - start) - towrite;
 		c->wbuf_ofs = ofs + towrite;
@@ -459,8 +466,8 @@
 		struct jffs2_raw_node_ref **adjust_ref = NULL;
 		struct jffs2_inode_info *f = NULL;
 
-		D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n",
-			  rawlen, ref_offset(raw), ref_flags(raw), ofs));
+		jffs2_dbg(1, "Refiling block of %08x at %08x(%d) to %08x\n",
+			  rawlen, ref_offset(raw), ref_flags(raw), ofs);
 
 		ic = jffs2_raw_ref_to_ic(raw);
 
@@ -540,7 +547,8 @@
 
 	/* Fix up the original jeb now it's on the bad_list */
 	if (first_raw == jeb->first_node) {
-		D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset));
+		jffs2_dbg(1, "Failing block at %08x is now empty. Moving to erase_pending_list\n",
+			  jeb->offset);
 		list_move(&jeb->list, &c->erase_pending_list);
 		c->nr_erasing_blocks++;
 		jffs2_garbage_collect_trigger(c);
@@ -554,7 +562,8 @@
 
 	spin_unlock(&c->erase_completion_lock);
 
-	D1(printk(KERN_DEBUG "wbuf recovery completed OK. wbuf_ofs 0x%08x, len 0x%x\n", c->wbuf_ofs, c->wbuf_len));
+	jffs2_dbg(1, "wbuf recovery completed OK. wbuf_ofs 0x%08x, len 0x%x\n",
+		  c->wbuf_ofs, c->wbuf_len);
 
 }
 
@@ -579,7 +588,7 @@
 		return 0;
 
 	if (!mutex_is_locked(&c->alloc_sem)) {
-		printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n");
+		pr_crit("jffs2_flush_wbuf() called with alloc_sem not locked!\n");
 		BUG();
 	}
 
@@ -617,7 +626,7 @@
 #ifdef BREAKME
 	static int breakme;
 	if (breakme++ == 20) {
-		printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs);
+		pr_notice("Faking write error at 0x%08x\n", c->wbuf_ofs);
 		breakme = 0;
 		mtd_write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen,
 			  brokenbuf);
@@ -629,11 +638,11 @@
 				&retlen, c->wbuf);
 
 	if (ret) {
-		printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n", ret);
+		pr_warn("jffs2_flush_wbuf(): Write failed with %d\n", ret);
 		goto wfail;
 	} else if (retlen != c->wbuf_pagesize) {
-		printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
-		       retlen, c->wbuf_pagesize);
+		pr_warn("jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
+			retlen, c->wbuf_pagesize);
 		ret = -EIO;
 		goto wfail;
 	} else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) {
@@ -647,17 +656,18 @@
 	if (pad) {
 		uint32_t waste = c->wbuf_pagesize - c->wbuf_len;
 
-		D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n",
-			  (wbuf_jeb==c->nextblock)?"next":"", wbuf_jeb->offset));
+		jffs2_dbg(1, "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n",
+			  (wbuf_jeb == c->nextblock) ? "next" : "",
+			  wbuf_jeb->offset);
 
 		/* wbuf_pagesize - wbuf_len is the amount of space that's to be
 		   padded. If there is less free space in the block than that,
 		   something screwed up */
 		if (wbuf_jeb->free_size < waste) {
-			printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n",
-			       c->wbuf_ofs, c->wbuf_len, waste);
-			printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n",
-			       wbuf_jeb->offset, wbuf_jeb->free_size);
+			pr_crit("jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n",
+				c->wbuf_ofs, c->wbuf_len, waste);
+			pr_crit("jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n",
+				wbuf_jeb->offset, wbuf_jeb->free_size);
 			BUG();
 		}
 
@@ -694,14 +704,14 @@
 	uint32_t old_wbuf_len;
 	int ret = 0;
 
-	D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino));
+	jffs2_dbg(1, "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino);
 
 	if (!c->wbuf)
 		return 0;
 
 	mutex_lock(&c->alloc_sem);
 	if (!jffs2_wbuf_pending_for_ino(c, ino)) {
-		D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino));
+		jffs2_dbg(1, "Ino #%d not pending in wbuf. Returning\n", ino);
 		mutex_unlock(&c->alloc_sem);
 		return 0;
 	}
@@ -711,7 +721,8 @@
 
 	if (c->unchecked_size) {
 		/* GC won't make any progress for a while */
-		D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n"));
+		jffs2_dbg(1, "%s(): padding. Not finished checking\n",
+			  __func__);
 		down_write(&c->wbuf_sem);
 		ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
 		/* retry flushing wbuf in case jffs2_wbuf_recover
@@ -724,7 +735,7 @@
 
 		mutex_unlock(&c->alloc_sem);
 
-		D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() calls gc pass\n"));
+		jffs2_dbg(1, "%s(): calls gc pass\n", __func__);
 
 		ret = jffs2_garbage_collect_pass(c);
 		if (ret) {
@@ -742,7 +753,7 @@
 		mutex_lock(&c->alloc_sem);
 	}
 
-	D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() ends...\n"));
+	jffs2_dbg(1, "%s(): ends...\n", __func__);
 
 	mutex_unlock(&c->alloc_sem);
 	return ret;
@@ -811,9 +822,8 @@
 	if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) {
 		/* It's a write to a new block */
 		if (c->wbuf_len) {
-			D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx "
-				  "causes flush of wbuf at 0x%08x\n",
-				  (unsigned long)to, c->wbuf_ofs));
+			jffs2_dbg(1, "%s(): to 0x%lx causes flush of wbuf at 0x%08x\n",
+				  __func__, (unsigned long)to, c->wbuf_ofs);
 			ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
 			if (ret)
 				goto outerr;
@@ -825,11 +835,11 @@
 
 	if (to != PAD(c->wbuf_ofs + c->wbuf_len)) {
 		/* We're not writing immediately after the writebuffer. Bad. */
-		printk(KERN_CRIT "jffs2_flash_writev(): Non-contiguous write "
-		       "to %08lx\n", (unsigned long)to);
+		pr_crit("%s(): Non-contiguous write to %08lx\n",
+			__func__, (unsigned long)to);
 		if (c->wbuf_len)
-			printk(KERN_CRIT "wbuf was previously %08x-%08x\n",
-			       c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len);
+			pr_crit("wbuf was previously %08x-%08x\n",
+				c->wbuf_ofs, c->wbuf_ofs + c->wbuf_len);
 		BUG();
 	}
 
@@ -957,8 +967,8 @@
 
 	if ( (ret == -EBADMSG || ret == -EUCLEAN) && (*retlen == len) ) {
 		if (ret == -EBADMSG)
-			printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx)"
-			       " returned ECC error\n", len, ofs);
+			pr_warn("mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
+				len, ofs);
 		/*
 		 * We have the raw data without ECC correction in the buffer,
 		 * maybe we are lucky and all data or parts are correct. We
@@ -1034,9 +1044,8 @@
 
 	ret = mtd_read_oob(c->mtd, jeb->offset, &ops);
 	if (ret || ops.oobretlen != ops.ooblen) {
-		printk(KERN_ERR "cannot read OOB for EB at %08x, requested %zd"
-				" bytes, read %zd bytes, error %d\n",
-				jeb->offset, ops.ooblen, ops.oobretlen, ret);
+		pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n",
+		       jeb->offset, ops.ooblen, ops.oobretlen, ret);
 		if (!ret)
 			ret = -EIO;
 		return ret;
@@ -1048,8 +1057,8 @@
 			continue;
 
 		if (ops.oobbuf[i] != 0xFF) {
-			D2(printk(KERN_DEBUG "Found %02x at %x in OOB for "
-				  "%08x\n", ops.oobbuf[i], i, jeb->offset));
+			jffs2_dbg(2, "Found %02x at %x in OOB for "
+				  "%08x\n", ops.oobbuf[i], i, jeb->offset);
 			return 1;
 		}
 	}
@@ -1077,9 +1086,8 @@
 
 	ret = mtd_read_oob(c->mtd, jeb->offset, &ops);
 	if (ret || ops.oobretlen != ops.ooblen) {
-		printk(KERN_ERR "cannot read OOB for EB at %08x, requested %zd"
-				" bytes, read %zd bytes, error %d\n",
-				jeb->offset, ops.ooblen, ops.oobretlen, ret);
+		pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n",
+		       jeb->offset, ops.ooblen, ops.oobretlen, ret);
 		if (!ret)
 			ret = -EIO;
 		return ret;
@@ -1103,9 +1111,8 @@
 
 	ret = mtd_write_oob(c->mtd, jeb->offset, &ops);
 	if (ret || ops.oobretlen != ops.ooblen) {
-		printk(KERN_ERR "cannot write OOB for EB at %08x, requested %zd"
-				" bytes, read %zd bytes, error %d\n",
-				jeb->offset, ops.ooblen, ops.oobretlen, ret);
+		pr_err("cannot write OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n",
+		       jeb->offset, ops.ooblen, ops.oobretlen, ret);
 		if (!ret)
 			ret = -EIO;
 		return ret;
@@ -1130,11 +1137,12 @@
 	if( ++jeb->bad_count < MAX_ERASE_FAILURES)
 		return 0;
 
-	printk(KERN_WARNING "JFFS2: marking eraseblock at %08x\n as bad", bad_offset);
+	pr_warn("marking eraseblock at %08x as bad\n", bad_offset);
 	ret = mtd_block_markbad(c->mtd, bad_offset);
 
 	if (ret) {
-		D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
+		jffs2_dbg(1, "%s(): Write failed for block at %08x: error %d\n",
+			  __func__, jeb->offset, ret);
 		return ret;
 	}
 	return 1;
@@ -1151,11 +1159,11 @@
 	c->cleanmarker_size = 0;
 
 	if (!oinfo || oinfo->oobavail == 0) {
-		printk(KERN_ERR "inconsistent device description\n");
+		pr_err("inconsistent device description\n");
 		return -EINVAL;
 	}
 
-	D1(printk(KERN_DEBUG "JFFS2 using OOB on NAND\n"));
+	jffs2_dbg(1, "using OOB on NAND\n");
 
 	c->oobavail = oinfo->oobavail;
 
@@ -1222,7 +1230,7 @@
 
 	if ((c->flash_size % c->sector_size) != 0) {
 		c->flash_size = (c->flash_size / c->sector_size) * c->sector_size;
-		printk(KERN_WARNING "JFFS2 flash size adjusted to %dKiB\n", c->flash_size);
+		pr_warn("flash size adjusted to %dKiB\n", c->flash_size);
 	};
 
 	c->wbuf_ofs = 0xFFFFFFFF;
@@ -1239,7 +1247,8 @@
 	}
 #endif
 
-	printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size);
+	pr_info("write-buffering enabled buffer (%d) erasesize (%d)\n",
+		c->wbuf_pagesize, c->sector_size);
 
 	return 0;
 }
@@ -1297,7 +1306,8 @@
 	if (!c->wbuf)
 		return -ENOMEM;
 
-	printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size);
+	pr_info("write-buffering enabled buffer (%d) erasesize (%d)\n",
+		c->wbuf_pagesize, c->sector_size);
 
 	return 0;
 }
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index 30d175b..b634de4c 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -9,6 +9,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/crc32.h>
@@ -36,7 +38,7 @@
 	f->inocache->state = INO_STATE_PRESENT;
 
 	jffs2_add_ino_cache(c, f->inocache);
-	D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
+	jffs2_dbg(1, "%s(): Assigned ino# %d\n", __func__, f->inocache->ino);
 	ri->ino = cpu_to_je32(f->inocache->ino);
 
 	ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -68,7 +70,7 @@
 	unsigned long cnt = 2;
 
 	D1(if(je32_to_cpu(ri->hdr_crc) != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) {
-		printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dnode()\n");
+		pr_crit("Eep. CRC not correct in jffs2_write_dnode()\n");
 		BUG();
 	}
 	   );
@@ -78,7 +80,9 @@
 	vecs[1].iov_len = datalen;
 
 	if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) {
-		printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen);
+		pr_warn("%s(): ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n",
+			__func__, je32_to_cpu(ri->totlen),
+			sizeof(*ri), datalen);
 	}
 
 	fn = jffs2_alloc_full_dnode();
@@ -95,9 +99,9 @@
 
 	if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) {
 		BUG_ON(!retried);
-		D1(printk(KERN_DEBUG "jffs2_write_dnode : dnode_version %d, "
-				"highest version %d -> updating dnode\n",
-				je32_to_cpu(ri->version), f->highest_version));
+		jffs2_dbg(1, "%s(): dnode_version %d, highest version %d -> updating dnode\n",
+			  __func__,
+			  je32_to_cpu(ri->version), f->highest_version);
 		ri->version = cpu_to_je32(++f->highest_version);
 		ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
 	}
@@ -106,8 +110,8 @@
 				 (alloc_mode==ALLOC_GC)?0:f->inocache->ino);
 
 	if (ret || (retlen != sizeof(*ri) + datalen)) {
-		printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
-		       sizeof(*ri)+datalen, flash_ofs, ret, retlen);
+		pr_notice("Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
+			  sizeof(*ri) + datalen, flash_ofs, ret, retlen);
 
 		/* Mark the space as dirtied */
 		if (retlen) {
@@ -118,7 +122,8 @@
 			   this node */
 			jffs2_add_physical_node_ref(c, flash_ofs | REF_OBSOLETE, PAD(sizeof(*ri)+datalen), NULL);
 		} else {
-			printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", flash_ofs);
+			pr_notice("Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n",
+				  flash_ofs);
 		}
 		if (!retried && alloc_mode != ALLOC_NORETRY) {
 			/* Try to reallocate space and retry */
@@ -127,7 +132,7 @@
 
 			retried = 1;
 
-			D1(printk(KERN_DEBUG "Retrying failed write.\n"));
+			jffs2_dbg(1, "Retrying failed write.\n");
 
 			jffs2_dbg_acct_sanity_check(c,jeb);
 			jffs2_dbg_acct_paranoia_check(c, jeb);
@@ -147,14 +152,16 @@
 
 			if (!ret) {
 				flash_ofs = write_ofs(c);
-				D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs));
+				jffs2_dbg(1, "Allocated space at 0x%08x to retry failed write.\n",
+					  flash_ofs);
 
 				jffs2_dbg_acct_sanity_check(c,jeb);
 				jffs2_dbg_acct_paranoia_check(c, jeb);
 
 				goto retry;
 			}
-			D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
+			jffs2_dbg(1, "Failed to allocate space to retry failed write: %d!\n",
+				  ret);
 		}
 		/* Release the full_dnode which is now useless, and return */
 		jffs2_free_full_dnode(fn);
@@ -183,10 +190,10 @@
 	fn->size = je32_to_cpu(ri->dsize);
 	fn->frags = 0;
 
-	D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n",
+	jffs2_dbg(1, "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n",
 		  flash_ofs & ~3, flash_ofs & 3, je32_to_cpu(ri->dsize),
 		  je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc),
-		  je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen)));
+		  je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen));
 
 	if (retried) {
 		jffs2_dbg_acct_sanity_check(c,NULL);
@@ -206,22 +213,23 @@
 	int retried = 0;
 	int ret;
 
-	D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n",
+	jffs2_dbg(1, "%s(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n",
+		  __func__,
 		  je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino),
-		  je32_to_cpu(rd->name_crc)));
+		  je32_to_cpu(rd->name_crc));
 
 	D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) {
-		printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n");
+		pr_crit("Eep. CRC not correct in jffs2_write_dirent()\n");
 		BUG();
 	   });
 
 	if (strnlen(name, namelen) != namelen) {
 		/* This should never happen, but seems to have done on at least one
 		   occasion: https://dev.laptop.org/ticket/4184 */
-		printk(KERN_CRIT "Error in jffs2_write_dirent() -- name contains zero bytes!\n");
-		printk(KERN_CRIT "Directory inode #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x\n",
-		       je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino),
-		       je32_to_cpu(rd->name_crc));
+		pr_crit("Error in jffs2_write_dirent() -- name contains zero bytes!\n");
+		pr_crit("Directory inode #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x\n",
+			je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino),
+			je32_to_cpu(rd->name_crc));
 		WARN_ON(1);
 		return ERR_PTR(-EIO);
 	}
@@ -249,9 +257,9 @@
 
 	if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) {
 		BUG_ON(!retried);
-		D1(printk(KERN_DEBUG "jffs2_write_dirent : dirent_version %d, "
-				     "highest version %d -> updating dirent\n",
-				     je32_to_cpu(rd->version), f->highest_version));
+		jffs2_dbg(1, "%s(): dirent_version %d, highest version %d -> updating dirent\n",
+			  __func__,
+			  je32_to_cpu(rd->version), f->highest_version);
 		rd->version = cpu_to_je32(++f->highest_version);
 		fd->version = je32_to_cpu(rd->version);
 		rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
@@ -260,13 +268,14 @@
 	ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen,
 				 (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino));
 	if (ret || (retlen != sizeof(*rd) + namelen)) {
-		printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
-			       sizeof(*rd)+namelen, flash_ofs, ret, retlen);
+		pr_notice("Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
+			  sizeof(*rd) + namelen, flash_ofs, ret, retlen);
 		/* Mark the space as dirtied */
 		if (retlen) {
 			jffs2_add_physical_node_ref(c, flash_ofs | REF_OBSOLETE, PAD(sizeof(*rd)+namelen), NULL);
 		} else {
-			printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", flash_ofs);
+			pr_notice("Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n",
+				  flash_ofs);
 		}
 		if (!retried) {
 			/* Try to reallocate space and retry */
@@ -275,7 +284,7 @@
 
 			retried = 1;
 
-			D1(printk(KERN_DEBUG "Retrying failed write.\n"));
+			jffs2_dbg(1, "Retrying failed write.\n");
 
 			jffs2_dbg_acct_sanity_check(c,jeb);
 			jffs2_dbg_acct_paranoia_check(c, jeb);
@@ -295,12 +304,14 @@
 
 			if (!ret) {
 				flash_ofs = write_ofs(c);
-				D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs));
+				jffs2_dbg(1, "Allocated space at 0x%08x to retry failed write\n",
+					  flash_ofs);
 				jffs2_dbg_acct_sanity_check(c,jeb);
 				jffs2_dbg_acct_paranoia_check(c, jeb);
 				goto retry;
 			}
-			D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
+			jffs2_dbg(1, "Failed to allocate space to retry failed write: %d!\n",
+				  ret);
 		}
 		/* Release the full_dnode which is now useless, and return */
 		jffs2_free_full_dirent(fd);
@@ -333,8 +344,8 @@
 	int ret = 0;
 	uint32_t writtenlen = 0;
 
-       	D1(printk(KERN_DEBUG "jffs2_write_inode_range(): Ino #%u, ofs 0x%x, len 0x%x\n",
-		  f->inocache->ino, offset, writelen));
+	jffs2_dbg(1, "%s(): Ino #%u, ofs 0x%x, len 0x%x\n",
+		  __func__, f->inocache->ino, offset, writelen);
 
 	while(writelen) {
 		struct jffs2_full_dnode *fn;
@@ -345,12 +356,13 @@
 		int retried = 0;
 
 	retry:
-		D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset));
+		jffs2_dbg(2, "jffs2_commit_write() loop: 0x%x to write to 0x%x\n",
+			  writelen, offset);
 
 		ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN,
 					&alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
 		if (ret) {
-			D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret));
+			jffs2_dbg(1, "jffs2_reserve_space returned %d\n", ret);
 			break;
 		}
 		mutex_lock(&f->sem);
@@ -386,7 +398,7 @@
 			if (!retried) {
 				/* Write error to be retried */
 				retried = 1;
-				D1(printk(KERN_DEBUG "Retrying node write in jffs2_write_inode_range()\n"));
+				jffs2_dbg(1, "Retrying node write in jffs2_write_inode_range()\n");
 				goto retry;
 			}
 			break;
@@ -399,7 +411,8 @@
 		}
 		if (ret) {
 			/* Eep */
-			D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in commit_write, returned %d\n", ret));
+			jffs2_dbg(1, "Eep. add_full_dnode_to_inode() failed in commit_write, returned %d\n",
+				  ret);
 			jffs2_mark_node_obsolete(c, fn->raw);
 			jffs2_free_full_dnode(fn);
 
@@ -410,11 +423,11 @@
 		mutex_unlock(&f->sem);
 		jffs2_complete_reservation(c);
 		if (!datalen) {
-			printk(KERN_WARNING "Eep. We didn't actually write any data in jffs2_write_inode_range()\n");
+			pr_warn("Eep. We didn't actually write any data in jffs2_write_inode_range()\n");
 			ret = -EIO;
 			break;
 		}
-		D1(printk(KERN_DEBUG "increasing writtenlen by %d\n", datalen));
+		jffs2_dbg(1, "increasing writtenlen by %d\n", datalen);
 		writtenlen += datalen;
 		offset += datalen;
 		writelen -= datalen;
@@ -439,7 +452,7 @@
 	 */
 	ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL,
 				JFFS2_SUMMARY_INODE_SIZE);
-	D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen));
+	jffs2_dbg(1, "%s(): reserved 0x%x bytes\n", __func__, alloclen);
 	if (ret)
 		return ret;
 
@@ -450,11 +463,11 @@
 
 	fn = jffs2_write_dnode(c, f, ri, NULL, 0, ALLOC_NORMAL);
 
-	D1(printk(KERN_DEBUG "jffs2_do_create created file with mode 0x%x\n",
-		  jemode_to_cpu(ri->mode)));
+	jffs2_dbg(1, "jffs2_do_create created file with mode 0x%x\n",
+		  jemode_to_cpu(ri->mode));
 
 	if (IS_ERR(fn)) {
-		D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n"));
+		jffs2_dbg(1, "jffs2_write_dnode() failed\n");
 		/* Eeek. Wave bye bye */
 		mutex_unlock(&f->sem);
 		jffs2_complete_reservation(c);
@@ -480,7 +493,7 @@
 
 	if (ret) {
 		/* Eep. */
-		D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n"));
+		jffs2_dbg(1, "jffs2_reserve_space() for dirent failed\n");
 		return ret;
 	}
 
@@ -597,8 +610,8 @@
 			    !memcmp(fd->name, name, namelen) &&
 			    !fd->name[namelen]) {
 
-				D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) @%08x obsolete\n",
-					  fd->ino, ref_offset(fd->raw)));
+				jffs2_dbg(1, "Marking old dirent node (ino #%u) @%08x obsolete\n",
+					  fd->ino, ref_offset(fd->raw));
 				jffs2_mark_node_obsolete(c, fd->raw);
 				/* We don't want to remove it from the list immediately,
 				   because that screws up getdents()/seek() semantics even
@@ -627,11 +640,13 @@
 				dead_f->dents = fd->next;
 
 				if (fd->ino) {
-					printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
-					       dead_f->inocache->ino, fd->name, fd->ino);
+					pr_warn("Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
+						dead_f->inocache->ino,
+						fd->name, fd->ino);
 				} else {
-					D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n",
-						fd->name, dead_f->inocache->ino));
+					jffs2_dbg(1, "Removing deletion dirent for \"%s\" from dir ino #%u\n",
+						  fd->name,
+						  dead_f->inocache->ino);
 				}
 				if (fd->raw)
 					jffs2_mark_node_obsolete(c, fd->raw);
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
index 3e93cdd..b55b803 100644
--- a/fs/jffs2/xattr.c
+++ b/fs/jffs2/xattr.c
@@ -9,6 +9,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 5f7c160..07c91ca 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -220,12 +220,6 @@
 
 	dquot_initialize(dip);
 
-	/* link count overflow on parent directory ? */
-	if (dip->i_nlink == JFS_LINK_MAX) {
-		rc = -EMLINK;
-		goto out1;
-	}
-
 	/*
 	 * search parent directory for entry/freespace
 	 * (dtSearch() returns parent directory page pinned)
@@ -806,9 +800,6 @@
 	jfs_info("jfs_link: %s %s", old_dentry->d_name.name,
 		 dentry->d_name.name);
 
-	if (ip->i_nlink == JFS_LINK_MAX)
-		return -EMLINK;
-
 	dquot_initialize(dir);
 
 	tid = txBegin(ip->i_sb, 0);
@@ -1138,10 +1129,6 @@
 				rc = -ENOTEMPTY;
 				goto out3;
 			}
-		} else if ((new_dir != old_dir) &&
-			   (new_dir->i_nlink == JFS_LINK_MAX)) {
-			rc = -EMLINK;
-			goto out3;
 		}
 	} else if (new_ip) {
 		IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 682bca6..4a82950 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -441,6 +441,7 @@
 		return -ENOMEM;
 
 	sb->s_fs_info = sbi;
+	sb->s_max_links = JFS_LINK_MAX;
 	sbi->sb = sb;
 	sbi->uid = sbi->gid = sbi->umask = -1;
 
@@ -521,7 +522,7 @@
 		ret = PTR_ERR(inode);
 		goto out_no_rw;
 	}
-	sb->s_root = d_alloc_root(inode);
+	sb->s_root = d_make_root(inode);
 	if (!sb->s_root)
 		goto out_no_root;
 
@@ -539,7 +540,6 @@
 
 out_no_root:
 	jfs_err("jfs_read_super: get root dentry failed");
-	iput(inode);
 
 out_no_rw:
 	rc = jfs_umount(sb);
@@ -860,8 +860,14 @@
 	jfs_proc_init();
 #endif
 
-	return register_filesystem(&jfs_fs_type);
+	rc = register_filesystem(&jfs_fs_type);
+	if (!rc)
+		return 0;
 
+#ifdef PROC_FS_JFS
+	jfs_proc_clean();
+#endif
+	kthread_stop(jfsSyncThread);
 kill_committask:
 	for (i = 0; i < commit_threads; i++)
 		kthread_stop(jfsCommitThread[i]);
diff --git a/fs/libfs.c b/fs/libfs.c
index 5b2dbb3..358094f 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -3,7 +3,7 @@
  *	Library for filesystems writers.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/mount.h>
@@ -264,6 +264,13 @@
 	return ERR_PTR(-ENOMEM);
 }
 
+int simple_open(struct inode *inode, struct file *file)
+{
+	if (inode->i_private)
+		file->private_data = inode->i_private;
+	return 0;
+}
+
 int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = old_dentry->d_inode;
@@ -491,11 +498,9 @@
 	inode->i_op = &simple_dir_inode_operations;
 	inode->i_fop = &simple_dir_operations;
 	set_nlink(inode, 2);
-	root = d_alloc_root(inode);
-	if (!root) {
-		iput(inode);
+	root = d_make_root(inode);
+	if (!root)
 		return -ENOMEM;
-	}
 	for (i = 0; !files->name || files->name[0]; i++, files++) {
 		if (!files->name)
 			continue;
@@ -536,7 +541,7 @@
 	spin_lock(&pin_fs_lock);
 	if (unlikely(!*mount)) {
 		spin_unlock(&pin_fs_lock);
-		mnt = vfs_kern_mount(type, 0, type->name, NULL);
+		mnt = vfs_kern_mount(type, MS_KERNMOUNT, type->name, NULL);
 		if (IS_ERR(mnt))
 			return PTR_ERR(mnt);
 		spin_lock(&pin_fs_lock);
@@ -986,6 +991,7 @@
 EXPORT_SYMBOL(simple_empty);
 EXPORT_SYMBOL(simple_fill_super);
 EXPORT_SYMBOL(simple_getattr);
+EXPORT_SYMBOL(simple_open);
 EXPORT_SYMBOL(simple_link);
 EXPORT_SYMBOL(simple_lookup);
 EXPORT_SYMBOL(simple_pin_fs);
diff --git a/fs/lockd/clnt4xdr.c b/fs/lockd/clnt4xdr.c
index f848b52..3ddcbb1 100644
--- a/fs/lockd/clnt4xdr.c
+++ b/fs/lockd/clnt4xdr.c
@@ -598,7 +598,7 @@
 	PROC(GRANTED_RES,	res,		norep),
 };
 
-struct rpc_version	nlm_version4 = {
+const struct rpc_version nlm_version4 = {
 	.number		= 4,
 	.nrprocs	= ARRAY_SIZE(nlm4_procedures),
 	.procs		= nlm4_procedures,
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 8d4ea83..ba1dc2e 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -62,7 +62,8 @@
 
 	host = nlmclnt_lookup_host(nlm_init->address, nlm_init->addrlen,
 				   nlm_init->protocol, nlm_version,
-				   nlm_init->hostname, nlm_init->noresvport);
+				   nlm_init->hostname, nlm_init->noresvport,
+				   nlm_init->net);
 	if (host == NULL) {
 		lockd_down();
 		return ERR_PTR(-ENOLCK);
diff --git a/fs/lockd/clntxdr.c b/fs/lockd/clntxdr.c
index 180ac34..3d35e3e 100644
--- a/fs/lockd/clntxdr.c
+++ b/fs/lockd/clntxdr.c
@@ -596,19 +596,19 @@
 	PROC(GRANTED_RES,	res,		norep),
 };
 
-static struct rpc_version	nlm_version1 = {
+static const struct rpc_version	nlm_version1 = {
 		.number		= 1,
 		.nrprocs	= ARRAY_SIZE(nlm_procedures),
 		.procs		= nlm_procedures,
 };
 
-static struct rpc_version	nlm_version3 = {
+static const struct rpc_version	nlm_version3 = {
 		.number		= 3,
 		.nrprocs	= ARRAY_SIZE(nlm_procedures),
 		.procs		= nlm_procedures,
 };
 
-static struct rpc_version	*nlm_versions[] = {
+static const struct rpc_version	*nlm_versions[] = {
 	[1] = &nlm_version1,
 	[3] = &nlm_version3,
 #ifdef CONFIG_LOCKD_V4
@@ -618,7 +618,7 @@
 
 static struct rpc_stat		nlm_rpc_stats;
 
-struct rpc_program		nlm_program = {
+const struct rpc_program	nlm_program = {
 		.name		= "lockd",
 		.number		= NLM_PROGRAM,
 		.nrvers		= ARRAY_SIZE(nlm_versions),
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 6f29836..eb75ca7 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -17,6 +17,8 @@
 #include <linux/lockd/lockd.h>
 #include <linux/mutex.h>
 
+#include <linux/sunrpc/svc_xprt.h>
+
 #include <net/ipv6.h>
 
 #define NLMDBG_FACILITY		NLMDBG_HOSTCACHE
@@ -54,6 +56,7 @@
 	const char		*hostname;	/* remote's hostname */
 	const size_t		hostname_len;	/* it's length */
 	const int		noresvport;	/* use non-priv port */
+	struct net		*net;		/* network namespace to bind */
 };
 
 /*
@@ -155,6 +158,7 @@
 	INIT_LIST_HEAD(&host->h_reclaim);
 	host->h_nsmhandle  = nsm;
 	host->h_addrbuf    = nsm->sm_addrbuf;
+	host->net	   = ni->net;
 
 out:
 	return host;
@@ -206,7 +210,8 @@
 				     const unsigned short protocol,
 				     const u32 version,
 				     const char *hostname,
-				     int noresvport)
+				     int noresvport,
+				     struct net *net)
 {
 	struct nlm_lookup_host_info ni = {
 		.server		= 0,
@@ -217,6 +222,7 @@
 		.hostname	= hostname,
 		.hostname_len	= strlen(hostname),
 		.noresvport	= noresvport,
+		.net		= net,
 	};
 	struct hlist_head *chain;
 	struct hlist_node *pos;
@@ -231,6 +237,8 @@
 
 	chain = &nlm_client_hosts[nlm_hash_address(sap)];
 	hlist_for_each_entry(host, pos, chain, h_hash) {
+		if (host->net != net)
+			continue;
 		if (!rpc_cmp_addr(nlm_addr(host), sap))
 			continue;
 
@@ -318,6 +326,7 @@
 	struct nsm_handle *nsm = NULL;
 	struct sockaddr *src_sap = svc_daddr(rqstp);
 	size_t src_len = rqstp->rq_daddrlen;
+	struct net *net = rqstp->rq_xprt->xpt_net;
 	struct nlm_lookup_host_info ni = {
 		.server		= 1,
 		.sap		= svc_addr(rqstp),
@@ -326,6 +335,7 @@
 		.version	= rqstp->rq_vers,
 		.hostname	= hostname,
 		.hostname_len	= hostname_len,
+		.net		= net,
 	};
 
 	dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
@@ -339,6 +349,8 @@
 
 	chain = &nlm_server_hosts[nlm_hash_address(ni.sap)];
 	hlist_for_each_entry(host, pos, chain, h_hash) {
+		if (host->net != net)
+			continue;
 		if (!rpc_cmp_addr(nlm_addr(host), ni.sap))
 			continue;
 
@@ -431,7 +443,7 @@
 			.to_retries	= 5U,
 		};
 		struct rpc_create_args args = {
-			.net		= &init_net,
+			.net		= host->net,
 			.protocol	= host->h_proto,
 			.address	= nlm_addr(host),
 			.addrsize	= host->h_addrlen,
@@ -553,12 +565,8 @@
 	nsm_release(nsm);
 }
 
-/*
- * Shut down the hosts module.
- * Note that this routine is called only at server shutdown time.
- */
 void
-nlm_shutdown_hosts(void)
+nlm_shutdown_hosts_net(struct net *net)
 {
 	struct hlist_head *chain;
 	struct hlist_node *pos;
@@ -570,6 +578,8 @@
 	/* First, make all hosts eligible for gc */
 	dprintk("lockd: nuking all hosts...\n");
 	for_each_host(host, pos, chain, nlm_server_hosts) {
+		if (net && host->net != net)
+			continue;
 		host->h_expires = jiffies - 1;
 		if (host->h_rpcclnt) {
 			rpc_shutdown_client(host->h_rpcclnt);
@@ -580,15 +590,29 @@
 	/* Then, perform a garbage collection pass */
 	nlm_gc_hosts();
 	mutex_unlock(&nlm_host_mutex);
+}
+
+/*
+ * Shut down the hosts module.
+ * Note that this routine is called only at server shutdown time.
+ */
+void
+nlm_shutdown_hosts(void)
+{
+	struct hlist_head *chain;
+	struct hlist_node *pos;
+	struct nlm_host	*host;
+
+	nlm_shutdown_hosts_net(NULL);
 
 	/* complain if any hosts are left */
 	if (nrhosts != 0) {
 		printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
 		dprintk("lockd: %lu hosts left:\n", nrhosts);
 		for_each_host(host, pos, chain, nlm_server_hosts) {
-			dprintk("       %s (cnt %d use %d exp %ld)\n",
+			dprintk("       %s (cnt %d use %d exp %ld net %p)\n",
 				host->h_name, atomic_read(&host->h_count),
-				host->h_inuse, host->h_expires);
+				host->h_inuse, host->h_expires, host->net);
 		}
 	}
 }
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index 65ba36b..7ef14b3 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -47,7 +47,7 @@
 	u32			state;
 };
 
-static struct rpc_program	nsm_program;
+static const struct rpc_program	nsm_program;
 static				LIST_HEAD(nsm_handles);
 static				DEFINE_SPINLOCK(nsm_lock);
 
@@ -62,14 +62,14 @@
 	return (struct sockaddr *)&nsm->sm_addr;
 }
 
-static struct rpc_clnt *nsm_create(void)
+static struct rpc_clnt *nsm_create(struct net *net)
 {
 	struct sockaddr_in sin = {
 		.sin_family		= AF_INET,
 		.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
 	};
 	struct rpc_create_args args = {
-		.net			= &init_net,
+		.net			= net,
 		.protocol		= XPRT_TRANSPORT_UDP,
 		.address		= (struct sockaddr *)&sin,
 		.addrsize		= sizeof(sin),
@@ -83,7 +83,8 @@
 	return rpc_create(&args);
 }
 
-static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
+static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
+			 struct net *net)
 {
 	struct rpc_clnt	*clnt;
 	int		status;
@@ -99,7 +100,7 @@
 		.rpc_resp	= res,
 	};
 
-	clnt = nsm_create();
+	clnt = nsm_create(net);
 	if (IS_ERR(clnt)) {
 		status = PTR_ERR(clnt);
 		dprintk("lockd: failed to create NSM upcall transport, "
@@ -149,7 +150,7 @@
 	 */
 	nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
 
-	status = nsm_mon_unmon(nsm, NSMPROC_MON, &res);
+	status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, host->net);
 	if (unlikely(res.status != 0))
 		status = -EIO;
 	if (unlikely(status < 0)) {
@@ -183,7 +184,7 @@
 	 && nsm->sm_monitored && !nsm->sm_sticky) {
 		dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);
 
-		status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res);
+		status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, host->net);
 		if (res.status != 0)
 			status = -EIO;
 		if (status < 0)
@@ -534,19 +535,19 @@
 	},
 };
 
-static struct rpc_version	nsm_version1 = {
+static const struct rpc_version nsm_version1 = {
 		.number		= 1,
 		.nrprocs	= ARRAY_SIZE(nsm_procedures),
 		.procs		= nsm_procedures
 };
 
-static struct rpc_version *	nsm_version[] = {
+static const struct rpc_version *nsm_version[] = {
 	[1] = &nsm_version1,
 };
 
 static struct rpc_stat		nsm_stats;
 
-static struct rpc_program	nsm_program = {
+static const struct rpc_program nsm_program = {
 		.name		= "statd",
 		.number		= NSM_PROGRAM,
 		.nrvers		= ARRAY_SIZE(nsm_version),
diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h
new file mode 100644
index 0000000..ce227e0
--- /dev/null
+++ b/fs/lockd/netns.h
@@ -0,0 +1,12 @@
+#ifndef __LOCKD_NETNS_H__
+#define __LOCKD_NETNS_H__
+
+#include <net/netns/generic.h>
+
+struct lockd_net {
+	unsigned int nlmsvc_users;
+};
+
+extern int lockd_net_id;
+
+#endif
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index c061b9a..f49b9af 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -35,6 +35,8 @@
 #include <linux/lockd/lockd.h>
 #include <linux/nfs.h>
 
+#include "netns.h"
+
 #define NLMDBG_FACILITY		NLMDBG_SVC
 #define LOCKD_BUFSIZE		(1024 + NLMSVC_XDRSIZE)
 #define ALLOWED_SIGS		(sigmask(SIGKILL))
@@ -50,6 +52,8 @@
 static struct svc_rqst		*nlmsvc_rqst;
 unsigned long			nlmsvc_timeout;
 
+int lockd_net_id;
+
 /*
  * These can be set at insmod time (useful for NFS as root filesystem),
  * and also changed through the sysctl interface.  -- Jamie Lokier, Aug 2003
@@ -189,27 +193,29 @@
 }
 
 static int create_lockd_listener(struct svc_serv *serv, const char *name,
-				 const int family, const unsigned short port)
+				 struct net *net, const int family,
+				 const unsigned short port)
 {
 	struct svc_xprt *xprt;
 
-	xprt = svc_find_xprt(serv, name, family, 0);
+	xprt = svc_find_xprt(serv, name, net, family, 0);
 	if (xprt == NULL)
-		return svc_create_xprt(serv, name, &init_net, family, port,
+		return svc_create_xprt(serv, name, net, family, port,
 						SVC_SOCK_DEFAULTS);
 	svc_xprt_put(xprt);
 	return 0;
 }
 
-static int create_lockd_family(struct svc_serv *serv, const int family)
+static int create_lockd_family(struct svc_serv *serv, struct net *net,
+			       const int family)
 {
 	int err;
 
-	err = create_lockd_listener(serv, "udp", family, nlm_udpport);
+	err = create_lockd_listener(serv, "udp", net, family, nlm_udpport);
 	if (err < 0)
 		return err;
 
-	return create_lockd_listener(serv, "tcp", family, nlm_tcpport);
+	return create_lockd_listener(serv, "tcp", net, family, nlm_tcpport);
 }
 
 /*
@@ -222,16 +228,16 @@
  * Returns zero if all listeners are available; otherwise a
  * negative errno value is returned.
  */
-static int make_socks(struct svc_serv *serv)
+static int make_socks(struct svc_serv *serv, struct net *net)
 {
 	static int warned;
 	int err;
 
-	err = create_lockd_family(serv, PF_INET);
+	err = create_lockd_family(serv, net, PF_INET);
 	if (err < 0)
 		goto out_err;
 
-	err = create_lockd_family(serv, PF_INET6);
+	err = create_lockd_family(serv, net, PF_INET6);
 	if (err < 0 && err != -EAFNOSUPPORT)
 		goto out_err;
 
@@ -245,6 +251,47 @@
 	return err;
 }
 
+static int lockd_up_net(struct net *net)
+{
+	struct lockd_net *ln = net_generic(net, lockd_net_id);
+	struct svc_serv *serv = nlmsvc_rqst->rq_server;
+	int error;
+
+	if (ln->nlmsvc_users)
+		return 0;
+
+	error = svc_rpcb_setup(serv, net);
+	if (error)
+		goto err_rpcb;
+
+	error = make_socks(serv, net);
+	if (error < 0)
+		goto err_socks;
+	return 0;
+
+err_socks:
+	svc_rpcb_cleanup(serv, net);
+err_rpcb:
+	return error;
+}
+
+static void lockd_down_net(struct net *net)
+{
+	struct lockd_net *ln = net_generic(net, lockd_net_id);
+	struct svc_serv *serv = nlmsvc_rqst->rq_server;
+
+	if (ln->nlmsvc_users) {
+		if (--ln->nlmsvc_users == 0) {
+			nlm_shutdown_hosts_net(net);
+			svc_shutdown_net(serv, net);
+		}
+	} else {
+		printk(KERN_ERR "lockd_down_net: no users! task=%p, net=%p\n",
+				nlmsvc_task, net);
+		BUG();
+	}
+}
+
 /*
  * Bring up the lockd process if it's not already up.
  */
@@ -252,13 +299,16 @@
 {
 	struct svc_serv *serv;
 	int		error = 0;
+	struct net *net = current->nsproxy->net_ns;
 
 	mutex_lock(&nlmsvc_mutex);
 	/*
 	 * Check whether we're already up and running.
 	 */
-	if (nlmsvc_rqst)
+	if (nlmsvc_rqst) {
+		error = lockd_up_net(net);
 		goto out;
+	}
 
 	/*
 	 * Sanity check: if there's no pid,
@@ -275,7 +325,7 @@
 		goto out;
 	}
 
-	error = make_socks(serv);
+	error = make_socks(serv, net);
 	if (error < 0)
 		goto destroy_and_out;
 
@@ -313,8 +363,12 @@
 destroy_and_out:
 	svc_destroy(serv);
 out:
-	if (!error)
+	if (!error) {
+		struct lockd_net *ln = net_generic(net, lockd_net_id);
+
+		ln->nlmsvc_users++;
 		nlmsvc_users++;
+	}
 	mutex_unlock(&nlmsvc_mutex);
 	return error;
 }
@@ -328,8 +382,10 @@
 {
 	mutex_lock(&nlmsvc_mutex);
 	if (nlmsvc_users) {
-		if (--nlmsvc_users)
+		if (--nlmsvc_users) {
+			lockd_down_net(current->nsproxy->net_ns);
 			goto out;
+		}
 	} else {
 		printk(KERN_ERR "lockd_down: no users! task=%p\n",
 			nlmsvc_task);
@@ -440,7 +496,7 @@
 	__typeof__(type) num = which_strtol(val, &endp, 0);		\
 	if (endp == val || *endp || num < (min) || num > (max))		\
 		return -EINVAL;						\
-	*((int *) kp->arg) = num;					\
+	*((type *) kp->arg) = num;					\
 	return 0;							\
 }
 
@@ -497,24 +553,55 @@
 module_param(nsm_use_hostnames, bool, 0644);
 module_param(nlm_max_connections, uint, 0644);
 
+static int lockd_init_net(struct net *net)
+{
+	return 0;
+}
+
+static void lockd_exit_net(struct net *net)
+{
+}
+
+static struct pernet_operations lockd_net_ops = {
+	.init = lockd_init_net,
+	.exit = lockd_exit_net,
+	.id = &lockd_net_id,
+	.size = sizeof(struct lockd_net),
+};
+
+
 /*
  * Initialising and terminating the module.
  */
 
 static int __init init_nlm(void)
 {
+	int err;
+
 #ifdef CONFIG_SYSCTL
+	err = -ENOMEM;
 	nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root);
-	return nlm_sysctl_table ? 0 : -ENOMEM;
-#else
-	return 0;
+	if (nlm_sysctl_table == NULL)
+		goto err_sysctl;
 #endif
+	err = register_pernet_subsys(&lockd_net_ops);
+	if (err)
+		goto err_pernet;
+	return 0;
+
+err_pernet:
+#ifdef CONFIG_SYSCTL
+	unregister_sysctl_table(nlm_sysctl_table);
+#endif
+err_sysctl:
+	return err;
 }
 
 static void __exit exit_nlm(void)
 {
 	/* FIXME: delete all NLM clients */
 	nlm_shutdown_hosts();
+	unregister_pernet_subsys(&lockd_net_ops);
 #ifdef CONFIG_SYSCTL
 	unregister_sysctl_table(nlm_sysctl_table);
 #endif
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index f0179c3..e46353f 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -46,7 +46,6 @@
 static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
 static void nlmsvc_freegrantargs(struct nlm_rqst *call);
 static const struct rpc_call_ops nlmsvc_grant_ops;
-static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie);
 
 /*
  * The list of blocked locks to retry
@@ -54,6 +53,35 @@
 static LIST_HEAD(nlm_blocked);
 static DEFINE_SPINLOCK(nlm_blocked_lock);
 
+#ifdef LOCKD_DEBUG
+static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
+{
+	/*
+	 * We can get away with a static buffer because we're only
+	 * called with BKL held.
+	 */
+	static char buf[2*NLM_MAXCOOKIELEN+1];
+	unsigned int i, len = sizeof(buf);
+	char *p = buf;
+
+	len--;	/* allow for trailing \0 */
+	if (len < 3)
+		return "???";
+	for (i = 0 ; i < cookie->len ; i++) {
+		if (len < 2) {
+			strcpy(p-3, "...");
+			break;
+		}
+		sprintf(p, "%02x", cookie->data[i]);
+		p += 2;
+		len -= 2;
+	}
+	*p = '\0';
+
+	return buf;
+}
+#endif
+
 /*
  * Insert a blocked lock into the global list
  */
@@ -935,32 +963,3 @@
 
 	return timeout;
 }
-
-#ifdef RPC_DEBUG
-static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
-{
-	/*
-	 * We can get away with a static buffer because we're only
-	 * called with BKL held.
-	 */
-	static char buf[2*NLM_MAXCOOKIELEN+1];
-	unsigned int i, len = sizeof(buf);
-	char *p = buf;
-
-	len--;	/* allow for trailing \0 */
-	if (len < 3)
-		return "???";
-	for (i = 0 ; i < cookie->len ; i++) {
-		if (len < 2) {
-			strcpy(p-3, "...");
-			break;
-		}
-		sprintf(p, "%02x", cookie->data[i]);
-		p += 2;
-		len -= 2;
-	}
-	*p = '\0';
-
-	return buf;
-}
-#endif
diff --git a/fs/locks.c b/fs/locks.c
index 637694b..0d68f1f 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -510,12 +510,13 @@
 
 /*
  */
-static void locks_delete_block(struct file_lock *waiter)
+void locks_delete_block(struct file_lock *waiter)
 {
 	lock_flocks();
 	__locks_delete_block(waiter);
 	unlock_flocks();
 }
+EXPORT_SYMBOL(locks_delete_block);
 
 /* Insert waiter into blocker's block list.
  * We use a circular list so that processes can be easily woken up in
diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c
index 1b6e21d..bea5d1b 100644
--- a/fs/logfs/dir.c
+++ b/fs/logfs/dir.c
@@ -558,9 +558,6 @@
 {
 	struct inode *inode = old_dentry->d_inode;
 
-	if (inode->i_nlink >= LOGFS_LINK_MAX)
-		return -EMLINK;
-
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	ihold(inode);
 	inc_nlink(inode);
diff --git a/fs/logfs/super.c b/fs/logfs/super.c
index c9ee7f5..97bca62 100644
--- a/fs/logfs/super.c
+++ b/fs/logfs/super.c
@@ -315,11 +315,9 @@
 	if (IS_ERR(rootdir))
 		goto fail;
 
-	sb->s_root = d_alloc_root(rootdir);
-	if (!sb->s_root) {
-		iput(rootdir);
+	sb->s_root = d_make_root(rootdir);
+	if (!sb->s_root)
 		goto fail;
-	}
 
 	/* at that point we know that ->put_super() will be called */
 	super->s_erase_page = alloc_pages(GFP_KERNEL, 0);
@@ -542,6 +540,7 @@
 	 * the filesystem incompatible with 32bit systems.
 	 */
 	sb->s_maxbytes	= (1ull << 43) - 1;
+	sb->s_max_links = LOGFS_LINK_MAX;
 	sb->s_op	= &logfs_super_operations;
 	sb->s_flags	= flags | MS_NOATIME;
 
@@ -627,7 +626,10 @@
 	if (ret)
 		goto out2;
 
-	return register_filesystem(&logfs_fs_type);
+	ret = register_filesystem(&logfs_fs_type);
+	if (!ret)
+		return 0;
+	logfs_destroy_inode_cache();
 out2:
 	logfs_compr_exit();
 out1:
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index fa8b612..fcb05d2 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -190,24 +190,24 @@
 		sbi->s_version = MINIX_V1;
 		sbi->s_dirsize = 16;
 		sbi->s_namelen = 14;
-		sbi->s_link_max = MINIX_LINK_MAX;
+		s->s_max_links = MINIX_LINK_MAX;
 	} else if (s->s_magic == MINIX_SUPER_MAGIC2) {
 		sbi->s_version = MINIX_V1;
 		sbi->s_dirsize = 32;
 		sbi->s_namelen = 30;
-		sbi->s_link_max = MINIX_LINK_MAX;
+		s->s_max_links = MINIX_LINK_MAX;
 	} else if (s->s_magic == MINIX2_SUPER_MAGIC) {
 		sbi->s_version = MINIX_V2;
 		sbi->s_nzones = ms->s_zones;
 		sbi->s_dirsize = 16;
 		sbi->s_namelen = 14;
-		sbi->s_link_max = MINIX2_LINK_MAX;
+		s->s_max_links = MINIX2_LINK_MAX;
 	} else if (s->s_magic == MINIX2_SUPER_MAGIC2) {
 		sbi->s_version = MINIX_V2;
 		sbi->s_nzones = ms->s_zones;
 		sbi->s_dirsize = 32;
 		sbi->s_namelen = 30;
-		sbi->s_link_max = MINIX2_LINK_MAX;
+		s->s_max_links = MINIX2_LINK_MAX;
 	} else if ( *(__u16 *)(bh->b_data + 24) == MINIX3_SUPER_MAGIC) {
 		m3s = (struct minix3_super_block *) bh->b_data;
 		s->s_magic = m3s->s_magic;
@@ -221,9 +221,9 @@
 		sbi->s_dirsize = 64;
 		sbi->s_namelen = 60;
 		sbi->s_version = MINIX_V3;
-		sbi->s_link_max = MINIX2_LINK_MAX;
 		sbi->s_mount_state = MINIX_VALID_FS;
 		sb_set_blocksize(s, m3s->s_blocksize);
+		s->s_max_links = MINIX2_LINK_MAX;
 	} else
 		goto out_no_fs;
 
@@ -254,14 +254,6 @@
 	minix_set_bit(0,sbi->s_imap[0]->b_data);
 	minix_set_bit(0,sbi->s_zmap[0]->b_data);
 
-	/* set up enough so that it can read an inode */
-	s->s_op = &minix_sops;
-	root_inode = minix_iget(s, MINIX_ROOT_INO);
-	if (IS_ERR(root_inode)) {
-		ret = PTR_ERR(root_inode);
-		goto out_no_root;
-	}
-
 	/* Apparently minix can create filesystems that allocate more blocks for
 	 * the bitmaps than needed.  We simply ignore that, but verify it didn't
 	 * create one with not enough blocks and bail out if so.
@@ -270,7 +262,7 @@
 	if (sbi->s_imap_blocks < block) {
 		printk("MINIX-fs: file system does not have enough "
 				"imap blocks allocated.  Refusing to mount\n");
-		goto out_iput;
+		goto out_no_bitmap;
 	}
 
 	block = minix_blocks_needed(
@@ -279,13 +271,21 @@
 	if (sbi->s_zmap_blocks < block) {
 		printk("MINIX-fs: file system does not have enough "
 				"zmap blocks allocated.  Refusing to mount.\n");
-		goto out_iput;
+		goto out_no_bitmap;
+	}
+
+	/* set up enough so that it can read an inode */
+	s->s_op = &minix_sops;
+	root_inode = minix_iget(s, MINIX_ROOT_INO);
+	if (IS_ERR(root_inode)) {
+		ret = PTR_ERR(root_inode);
+		goto out_no_root;
 	}
 
 	ret = -ENOMEM;
-	s->s_root = d_alloc_root(root_inode);
+	s->s_root = d_make_root(root_inode);
 	if (!s->s_root)
-		goto out_iput;
+		goto out_no_root;
 
 	if (!(s->s_flags & MS_RDONLY)) {
 		if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */
@@ -301,10 +301,6 @@
 
 	return 0;
 
-out_iput:
-	iput(root_inode);
-	goto out_freemap;
-
 out_no_root:
 	if (!silent)
 		printk("MINIX-fs: get root inode failed\n");
diff --git a/fs/minix/minix.h b/fs/minix/minix.h
index c889ef0..1ebd118 100644
--- a/fs/minix/minix.h
+++ b/fs/minix/minix.h
@@ -34,7 +34,6 @@
 	unsigned long s_max_size;
 	int s_dirsize;
 	int s_namelen;
-	int s_link_max;
 	struct buffer_head ** s_imap;
 	struct buffer_head ** s_zmap;
 	struct buffer_head * s_sbh;
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index 2f76e38..2d0ee17 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -94,9 +94,6 @@
 {
 	struct inode *inode = old_dentry->d_inode;
 
-	if (inode->i_nlink >= minix_sb(inode->i_sb)->s_link_max)
-		return -EMLINK;
-
 	inode->i_ctime = CURRENT_TIME_SEC;
 	inode_inc_link_count(inode);
 	ihold(inode);
@@ -106,10 +103,7 @@
 static int minix_mkdir(struct inode * dir, struct dentry *dentry, umode_t mode)
 {
 	struct inode * inode;
-	int err = -EMLINK;
-
-	if (dir->i_nlink >= minix_sb(dir->i_sb)->s_link_max)
-		goto out;
+	int err;
 
 	inode_inc_link_count(dir);
 
@@ -181,7 +175,6 @@
 static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
 			   struct inode * new_dir, struct dentry *new_dentry)
 {
-	struct minix_sb_info * info = minix_sb(old_dir->i_sb);
 	struct inode * old_inode = old_dentry->d_inode;
 	struct inode * new_inode = new_dentry->d_inode;
 	struct page * dir_page = NULL;
@@ -219,11 +212,6 @@
 			drop_nlink(new_inode);
 		inode_dec_link_count(new_inode);
 	} else {
-		if (dir_de) {
-			err = -EMLINK;
-			if (new_dir->i_nlink >= info->s_link_max)
-				goto out_dir;
-		}
 		err = minix_add_link(new_dentry, old_inode);
 		if (err)
 			goto out_dir;
diff --git a/fs/mpage.c b/fs/mpage.c
index 643e9f5..0face1c 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -13,7 +13,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/mm.h>
 #include <linux/kdev_t.h>
 #include <linux/gfp.h>
diff --git a/fs/namei.c b/fs/namei.c
index 20a4fcf..0062dd1 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -15,7 +15,7 @@
  */
 
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/namei.h>
@@ -161,7 +161,7 @@
 
 char *getname(const char __user * filename)
 {
-	return getname_flags(filename, 0, 0);
+	return getname_flags(filename, 0, NULL);
 }
 
 #ifdef CONFIG_AUDITSYSCALL
@@ -642,7 +642,7 @@
 	cond_resched();
 	current->total_link_count++;
 
-	touch_atime(link->mnt, dentry);
+	touch_atime(link);
 	nd_set_link(nd, NULL);
 
 	error = security_inode_follow_link(link->dentry, nd);
@@ -1054,27 +1054,65 @@
 }
 
 /*
- * Allocate a dentry with name and parent, and perform a parent
- * directory ->lookup on it. Returns the new dentry, or ERR_PTR
- * on error. parent->d_inode->i_mutex must be held. d_lookup must
- * have verified that no child exists while under i_mutex.
+ * This looks up the name in dcache, possibly revalidates the old dentry and
+ * allocates a new one if not found or not valid.  In the need_lookup argument
+ * returns whether i_op->lookup is necessary.
+ *
+ * dir->d_inode->i_mutex must be held
  */
-static struct dentry *d_alloc_and_lookup(struct dentry *parent,
-				struct qstr *name, struct nameidata *nd)
+static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir,
+				    struct nameidata *nd, bool *need_lookup)
 {
-	struct inode *inode = parent->d_inode;
 	struct dentry *dentry;
+	int error;
+
+	*need_lookup = false;
+	dentry = d_lookup(dir, name);
+	if (dentry) {
+		if (d_need_lookup(dentry)) {
+			*need_lookup = true;
+		} else if (dentry->d_flags & DCACHE_OP_REVALIDATE) {
+			error = d_revalidate(dentry, nd);
+			if (unlikely(error <= 0)) {
+				if (error < 0) {
+					dput(dentry);
+					return ERR_PTR(error);
+				} else if (!d_invalidate(dentry)) {
+					dput(dentry);
+					dentry = NULL;
+				}
+			}
+		}
+	}
+
+	if (!dentry) {
+		dentry = d_alloc(dir, name);
+		if (unlikely(!dentry))
+			return ERR_PTR(-ENOMEM);
+
+		*need_lookup = true;
+	}
+	return dentry;
+}
+
+/*
+ * Call i_op->lookup on the dentry.  The dentry must be negative but may be
+ * hashed if it was pouplated with DCACHE_NEED_LOOKUP.
+ *
+ * dir->d_inode->i_mutex must be held
+ */
+static struct dentry *lookup_real(struct inode *dir, struct dentry *dentry,
+				  struct nameidata *nd)
+{
 	struct dentry *old;
 
 	/* Don't create child dentry for a dead directory. */
-	if (unlikely(IS_DEADDIR(inode)))
+	if (unlikely(IS_DEADDIR(dir))) {
+		dput(dentry);
 		return ERR_PTR(-ENOENT);
+	}
 
-	dentry = d_alloc(parent, name);
-	if (unlikely(!dentry))
-		return ERR_PTR(-ENOMEM);
-
-	old = inode->i_op->lookup(inode, dentry, nd);
+	old = dir->i_op->lookup(dir, dentry, nd);
 	if (unlikely(old)) {
 		dput(dentry);
 		dentry = old;
@@ -1082,30 +1120,17 @@
 	return dentry;
 }
 
-/*
- * We already have a dentry, but require a lookup to be performed on the parent
- * directory to fill in d_inode. Returns the new dentry, or ERR_PTR on error.
- * parent->d_inode->i_mutex must be held. d_lookup must have verified that no
- * child exists while under i_mutex.
- */
-static struct dentry *d_inode_lookup(struct dentry *parent, struct dentry *dentry,
-				     struct nameidata *nd)
+static struct dentry *__lookup_hash(struct qstr *name,
+		struct dentry *base, struct nameidata *nd)
 {
-	struct inode *inode = parent->d_inode;
-	struct dentry *old;
+	bool need_lookup;
+	struct dentry *dentry;
 
-	/* Don't create child dentry for a dead directory. */
-	if (unlikely(IS_DEADDIR(inode))) {
-		dput(dentry);
-		return ERR_PTR(-ENOENT);
-	}
+	dentry = lookup_dcache(name, base, nd, &need_lookup);
+	if (!need_lookup)
+		return dentry;
 
-	old = inode->i_op->lookup(inode, dentry, nd);
-	if (unlikely(old)) {
-		dput(dentry);
-		dentry = old;
-	}
-	return dentry;
+	return lookup_real(base->d_inode, dentry, nd);
 }
 
 /*
@@ -1139,6 +1164,8 @@
 			return -ECHILD;
 		nd->seq = seq;
 
+		if (unlikely(d_need_lookup(dentry)))
+			goto unlazy;
 		if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
 			status = d_revalidate(dentry, nd);
 			if (unlikely(status <= 0)) {
@@ -1147,8 +1174,6 @@
 				goto unlazy;
 			}
 		}
-		if (unlikely(d_need_lookup(dentry)))
-			goto unlazy;
 		path->mnt = mnt;
 		path->dentry = dentry;
 		if (unlikely(!__follow_mount_rcu(nd, path, inode)))
@@ -1163,38 +1188,14 @@
 		dentry = __d_lookup(parent, name);
 	}
 
-	if (dentry && unlikely(d_need_lookup(dentry))) {
-		dput(dentry);
-		dentry = NULL;
-	}
-retry:
-	if (unlikely(!dentry)) {
-		struct inode *dir = parent->d_inode;
-		BUG_ON(nd->inode != dir);
+	if (unlikely(!dentry))
+		goto need_lookup;
 
-		mutex_lock(&dir->i_mutex);
-		dentry = d_lookup(parent, name);
-		if (likely(!dentry)) {
-			dentry = d_alloc_and_lookup(parent, name, nd);
-			if (IS_ERR(dentry)) {
-				mutex_unlock(&dir->i_mutex);
-				return PTR_ERR(dentry);
-			}
-			/* known good */
-			need_reval = 0;
-			status = 1;
-		} else if (unlikely(d_need_lookup(dentry))) {
-			dentry = d_inode_lookup(parent, dentry, nd);
-			if (IS_ERR(dentry)) {
-				mutex_unlock(&dir->i_mutex);
-				return PTR_ERR(dentry);
-			}
-			/* known good */
-			need_reval = 0;
-			status = 1;
-		}
-		mutex_unlock(&dir->i_mutex);
+	if (unlikely(d_need_lookup(dentry))) {
+		dput(dentry);
+		goto need_lookup;
 	}
+
 	if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE) && need_reval)
 		status = d_revalidate(dentry, nd);
 	if (unlikely(status <= 0)) {
@@ -1204,12 +1205,10 @@
 		}
 		if (!d_invalidate(dentry)) {
 			dput(dentry);
-			dentry = NULL;
-			need_reval = 1;
-			goto retry;
+			goto need_lookup;
 		}
 	}
-
+done:
 	path->mnt = mnt;
 	path->dentry = dentry;
 	err = follow_managed(path, nd->flags);
@@ -1221,6 +1220,16 @@
 		nd->flags |= LOOKUP_JUMPED;
 	*inode = path->dentry->d_inode;
 	return 0;
+
+need_lookup:
+	BUG_ON(nd->inode != parent->d_inode);
+
+	mutex_lock(&parent->d_inode->i_mutex);
+	dentry = __lookup_hash(name, parent, nd);
+	mutex_unlock(&parent->d_inode->i_mutex);
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
+	goto done;
 }
 
 static inline int may_lookup(struct nameidata *nd)
@@ -1398,18 +1407,9 @@
  */
 #ifdef CONFIG_DCACHE_WORD_ACCESS
 
-#ifdef CONFIG_64BIT
+#include <asm/word-at-a-time.h>
 
-/*
- * Jan Achrenius on G+: microoptimized version of
- * the simpler "(mask & ONEBYTES) * ONEBYTES >> 56"
- * that works for the bytemasks without having to
- * mask them first.
- */
-static inline long count_masked_bytes(unsigned long mask)
-{
-	return mask*0x0001020304050608 >> 56;
-}
+#ifdef CONFIG_64BIT
 
 static inline unsigned int fold_hash(unsigned long hash)
 {
@@ -1419,15 +1419,6 @@
 
 #else	/* 32-bit case */
 
-/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
-static inline long count_masked_bytes(long mask)
-{
-	/* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
-	long a = (0x0ff0001+mask) >> 23;
-	/* Fix the 1 for 00 case */
-	return a & mask;
-}
-
 #define fold_hash(x) (x)
 
 #endif
@@ -1439,10 +1430,10 @@
 
 	for (;;) {
 		a = *(unsigned long *)name;
-		hash *= 9;
 		if (len < sizeof(unsigned long))
 			break;
 		hash += a;
+		hash *= 9;
 		name += sizeof(unsigned long);
 		len -= sizeof(unsigned long);
 		if (!len)
@@ -1455,16 +1446,6 @@
 }
 EXPORT_SYMBOL(full_name_hash);
 
-#define ONEBYTES	0x0101010101010101ul
-#define SLASHBYTES	0x2f2f2f2f2f2f2f2ful
-#define HIGHBITS	0x8080808080808080ul
-
-/* Return the high bit set in the first byte that is a zero */
-static inline unsigned long has_zero(unsigned long a)
-{
-	return ((a - ONEBYTES) & ~a) & HIGHBITS;
-}
-
 /*
  * Calculate the length and hash of the path component, and
  * return the length of the component;
@@ -1480,7 +1461,7 @@
 		len += sizeof(unsigned long);
 		a = *(unsigned long *)(name+len);
 		/* Do we have any NUL or '/' bytes in this word? */
-		mask = has_zero(a) | has_zero(a ^ SLASHBYTES);
+		mask = has_zero(a) | has_zero(a ^ REPEAT_BYTE('/'));
 	} while (!mask);
 
 	/* The mask *below* the first high bit set */
@@ -1845,59 +1826,6 @@
 	return err;
 }
 
-static struct dentry *__lookup_hash(struct qstr *name,
-		struct dentry *base, struct nameidata *nd)
-{
-	struct inode *inode = base->d_inode;
-	struct dentry *dentry;
-	int err;
-
-	err = inode_permission(inode, MAY_EXEC);
-	if (err)
-		return ERR_PTR(err);
-
-	/*
-	 * Don't bother with __d_lookup: callers are for creat as
-	 * well as unlink, so a lot of the time it would cost
-	 * a double lookup.
-	 */
-	dentry = d_lookup(base, name);
-
-	if (dentry && d_need_lookup(dentry)) {
-		/*
-		 * __lookup_hash is called with the parent dir's i_mutex already
-		 * held, so we are good to go here.
-		 */
-		dentry = d_inode_lookup(base, dentry, nd);
-		if (IS_ERR(dentry))
-			return dentry;
-	}
-
-	if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) {
-		int status = d_revalidate(dentry, nd);
-		if (unlikely(status <= 0)) {
-			/*
-			 * The dentry failed validation.
-			 * If d_revalidate returned 0 attempt to invalidate
-			 * the dentry otherwise d_revalidate is asking us
-			 * to return a fail status.
-			 */
-			if (status < 0) {
-				dput(dentry);
-				return ERR_PTR(status);
-			} else if (!d_invalidate(dentry)) {
-				dput(dentry);
-				dentry = NULL;
-			}
-		}
-	}
-
-	if (!dentry)
-		dentry = d_alloc_and_lookup(base, name, nd);
-
-	return dentry;
-}
-
 /*
  * Restricted form of lookup. Doesn't follow links, single-component only,
  * needs parent already locked. Doesn't follow mounts.
@@ -1923,6 +1851,7 @@
 {
 	struct qstr this;
 	unsigned int c;
+	int err;
 
 	WARN_ON_ONCE(!mutex_is_locked(&base->d_inode->i_mutex));
 
@@ -1947,6 +1876,10 @@
 			return ERR_PTR(err);
 	}
 
+	err = inode_permission(base->d_inode, MAY_EXEC);
+	if (err)
+		return ERR_PTR(err);
+
 	return __lookup_hash(&this, base, NULL);
 }
 
@@ -1971,7 +1904,7 @@
 int user_path_at(int dfd, const char __user *name, unsigned flags,
 		 struct path *path)
 {
-	return user_path_at_empty(dfd, name, flags, path, 0);
+	return user_path_at_empty(dfd, name, flags, path, NULL);
 }
 
 static int user_path_parent(int dfd, const char __user *path,
@@ -2691,6 +2624,7 @@
 int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
 	int error = may_create(dir, dentry);
+	unsigned max_links = dir->i_sb->s_max_links;
 
 	if (error)
 		return error;
@@ -2703,6 +2637,9 @@
 	if (error)
 		return error;
 
+	if (max_links && dir->i_nlink >= max_links)
+		return -EMLINK;
+
 	error = dir->i_op->mkdir(dir, dentry, mode);
 	if (!error)
 		fsnotify_mkdir(dir, dentry);
@@ -2744,7 +2681,7 @@
 
 /*
  * The dentry_unhash() helper will try to drop the dentry early: we
- * should have a usage count of 2 if we're the only user of this
+ * should have a usage count of 1 if we're the only user of this
  * dentry, and if that is true (possibly after pruning the dcache),
  * then we drop the dentry now.
  *
@@ -3033,6 +2970,7 @@
 int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
 {
 	struct inode *inode = old_dentry->d_inode;
+	unsigned max_links = dir->i_sb->s_max_links;
 	int error;
 
 	if (!inode)
@@ -3063,6 +3001,8 @@
 	/* Make sure we don't allow creating hardlink to an unlinked file */
 	if (inode->i_nlink == 0)
 		error =  -ENOENT;
+	else if (max_links && inode->i_nlink >= max_links)
+		error = -EMLINK;
 	else
 		error = dir->i_op->link(old_dentry, dir, new_dentry);
 	mutex_unlock(&inode->i_mutex);
@@ -3172,6 +3112,7 @@
 {
 	int error = 0;
 	struct inode *target = new_dentry->d_inode;
+	unsigned max_links = new_dir->i_sb->s_max_links;
 
 	/*
 	 * If we are going to change the parent - check write permissions,
@@ -3195,6 +3136,11 @@
 	if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry))
 		goto out;
 
+	error = -EMLINK;
+	if (max_links && !target && new_dir != old_dir &&
+	    new_dir->i_nlink >= max_links)
+		goto out;
+
 	if (target)
 		shrink_dcache_parent(new_dentry);
 	error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index 64a3264..3ff5fcc 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -7,7 +7,6 @@
  */
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #include <linux/time.h>
 #include <linux/kernel.h>
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 3d1e34f..87484fb 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -11,7 +11,6 @@
 
 #include <linux/module.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 
@@ -716,13 +715,11 @@
         if (!root_inode)
 		goto out_disconnect;
 	DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
-	sb->s_root = d_alloc_root(root_inode);
+	sb->s_root = d_make_root(root_inode);
         if (!sb->s_root)
-		goto out_no_root;
+		goto out_disconnect;
 	return 0;
 
-out_no_root:
-	iput(root_inode);
 out_disconnect:
 	ncp_lock_server(server);
 	ncp_disconnect(server);
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index e5d71b2..be20a7e 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -19,7 +19,6 @@
 #include <linux/memcontrol.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #include "ncp_fs.h"
 
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index dbcd821..2a0e6c5 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -64,6 +64,7 @@
 	bool "NFS client support for NFS version 4"
 	depends on NFS_FS
 	select SUNRPC_GSS
+	select KEYS
 	help
 	  This option enables support for version 4 of the NFS protocol
 	  (RFC 3530) in the kernel's NFS client.
@@ -98,6 +99,18 @@
 	depends on NFS_FS && NFS_V4_1 && SCSI_OSD_ULD
 	default m
 
+config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN
+	string "NFSv4.1 Implementation ID Domain"
+	depends on NFS_V4_1
+	default "kernel.org"
+	help
+	  This option defines the domain portion of the implementation ID that
+	  may be sent in the NFS exchange_id operation.  The value must be in
+	  the format of a DNS domain name and should be set to the DNS domain
+	  name of the distribution.
+	  If the NFS client is unchanged from the upstream kernel, this
+	  option should be set to the default "kernel.org".
+
 config ROOT_NFS
 	bool "Root file system on NFS"
 	depends on NFS_FS=y && IP_PNP
@@ -130,16 +143,10 @@
 	bool
 	depends on NFS_V4 && !NFS_USE_LEGACY_DNS
 	select DNS_RESOLVER
-	select KEYS
 	default y
 
-config NFS_USE_NEW_IDMAPPER
-	bool "Use the new idmapper upcall routine"
-	depends on NFS_V4 && KEYS
-	help
-	  Say Y here if you want NFS to use the new idmapper upcall functions.
-	  You will need /sbin/request-key (usually provided by the keyutils
-	  package).  For details, read
-	  <file:Documentation/filesystems/nfs/idmapper.txt>.
-
-	  If you are unsure, say N.
+config NFS_DEBUG
+	bool
+	depends on NFS_FS && SUNRPC_DEBUG
+	select CRC32
+	default y
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
index 48cfac3..9c94297 100644
--- a/fs/nfs/blocklayout/blocklayout.c
+++ b/fs/nfs/blocklayout/blocklayout.c
@@ -46,9 +46,6 @@
 MODULE_AUTHOR("Andy Adamson <andros@citi.umich.edu>");
 MODULE_DESCRIPTION("The NFSv4.1 pNFS Block layout driver");
 
-struct dentry *bl_device_pipe;
-wait_queue_head_t bl_wq;
-
 static void print_page(struct page *page)
 {
 	dprintk("PRINTPAGE page %p\n", page);
@@ -236,12 +233,11 @@
 	sector_t isect, extent_length = 0;
 	struct parallel_io *par;
 	loff_t f_offset = rdata->args.offset;
-	size_t count = rdata->args.count;
 	struct page **pages = rdata->args.pages;
 	int pg_index = rdata->args.pgbase >> PAGE_CACHE_SHIFT;
 
-	dprintk("%s enter nr_pages %u offset %lld count %Zd\n", __func__,
-	       rdata->npages, f_offset, count);
+	dprintk("%s enter nr_pages %u offset %lld count %u\n", __func__,
+	       rdata->npages, f_offset, (unsigned int)rdata->args.count);
 
 	par = alloc_parallel(rdata);
 	if (!par)
@@ -1025,10 +1021,128 @@
 	.destroy_msg	= bl_pipe_destroy_msg,
 };
 
+static struct dentry *nfs4blocklayout_register_sb(struct super_block *sb,
+					    struct rpc_pipe *pipe)
+{
+	struct dentry *dir, *dentry;
+
+	dir = rpc_d_lookup_sb(sb, NFS_PIPE_DIRNAME);
+	if (dir == NULL)
+		return ERR_PTR(-ENOENT);
+	dentry = rpc_mkpipe_dentry(dir, "blocklayout", NULL, pipe);
+	dput(dir);
+	return dentry;
+}
+
+static void nfs4blocklayout_unregister_sb(struct super_block *sb,
+					  struct rpc_pipe *pipe)
+{
+	if (pipe->dentry)
+		rpc_unlink(pipe->dentry);
+}
+
+static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
+			   void *ptr)
+{
+	struct super_block *sb = ptr;
+	struct net *net = sb->s_fs_info;
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
+	struct dentry *dentry;
+	int ret = 0;
+
+	if (!try_module_get(THIS_MODULE))
+		return 0;
+
+	if (nn->bl_device_pipe == NULL) {
+		module_put(THIS_MODULE);
+		return 0;
+	}
+
+	switch (event) {
+	case RPC_PIPEFS_MOUNT:
+		dentry = nfs4blocklayout_register_sb(sb, nn->bl_device_pipe);
+		if (IS_ERR(dentry)) {
+			ret = PTR_ERR(dentry);
+			break;
+		}
+		nn->bl_device_pipe->dentry = dentry;
+		break;
+	case RPC_PIPEFS_UMOUNT:
+		if (nn->bl_device_pipe->dentry)
+			nfs4blocklayout_unregister_sb(sb, nn->bl_device_pipe);
+		break;
+	default:
+		ret = -ENOTSUPP;
+		break;
+	}
+	module_put(THIS_MODULE);
+	return ret;
+}
+
+static struct notifier_block nfs4blocklayout_block = {
+	.notifier_call = rpc_pipefs_event,
+};
+
+static struct dentry *nfs4blocklayout_register_net(struct net *net,
+						   struct rpc_pipe *pipe)
+{
+	struct super_block *pipefs_sb;
+	struct dentry *dentry;
+
+	pipefs_sb = rpc_get_sb_net(net);
+	if (!pipefs_sb)
+		return NULL;
+	dentry = nfs4blocklayout_register_sb(pipefs_sb, pipe);
+	rpc_put_sb_net(net);
+	return dentry;
+}
+
+static void nfs4blocklayout_unregister_net(struct net *net,
+					   struct rpc_pipe *pipe)
+{
+	struct super_block *pipefs_sb;
+
+	pipefs_sb = rpc_get_sb_net(net);
+	if (pipefs_sb) {
+		nfs4blocklayout_unregister_sb(pipefs_sb, pipe);
+		rpc_put_sb_net(net);
+	}
+}
+
+static int nfs4blocklayout_net_init(struct net *net)
+{
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
+	struct dentry *dentry;
+
+	init_waitqueue_head(&nn->bl_wq);
+	nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0);
+	if (IS_ERR(nn->bl_device_pipe))
+		return PTR_ERR(nn->bl_device_pipe);
+	dentry = nfs4blocklayout_register_net(net, nn->bl_device_pipe);
+	if (IS_ERR(dentry)) {
+		rpc_destroy_pipe_data(nn->bl_device_pipe);
+		return PTR_ERR(dentry);
+	}
+	nn->bl_device_pipe->dentry = dentry;
+	return 0;
+}
+
+static void nfs4blocklayout_net_exit(struct net *net)
+{
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
+
+	nfs4blocklayout_unregister_net(net, nn->bl_device_pipe);
+	rpc_destroy_pipe_data(nn->bl_device_pipe);
+	nn->bl_device_pipe = NULL;
+}
+
+static struct pernet_operations nfs4blocklayout_net_ops = {
+	.init = nfs4blocklayout_net_init,
+	.exit = nfs4blocklayout_net_exit,
+};
+
 static int __init nfs4blocklayout_init(void)
 {
-	struct vfsmount *mnt;
-	struct path path;
 	int ret;
 
 	dprintk("%s: NFSv4 Block Layout Driver Registering...\n", __func__);
@@ -1037,32 +1151,17 @@
 	if (ret)
 		goto out;
 
-	init_waitqueue_head(&bl_wq);
-
-	mnt = rpc_get_mount();
-	if (IS_ERR(mnt)) {
-		ret = PTR_ERR(mnt);
-		goto out_remove;
-	}
-
-	ret = vfs_path_lookup(mnt->mnt_root,
-			      mnt,
-			      NFS_PIPE_DIRNAME, 0, &path);
+	ret = rpc_pipefs_notifier_register(&nfs4blocklayout_block);
 	if (ret)
-		goto out_putrpc;
-
-	bl_device_pipe = rpc_mkpipe(path.dentry, "blocklayout", NULL,
-				    &bl_upcall_ops, 0);
-	path_put(&path);
-	if (IS_ERR(bl_device_pipe)) {
-		ret = PTR_ERR(bl_device_pipe);
-		goto out_putrpc;
-	}
+		goto out_remove;
+	ret = register_pernet_subsys(&nfs4blocklayout_net_ops);
+	if (ret)
+		goto out_notifier;
 out:
 	return ret;
 
-out_putrpc:
-	rpc_put_mount();
+out_notifier:
+	rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
 out_remove:
 	pnfs_unregister_layoutdriver(&blocklayout_type);
 	return ret;
@@ -1073,9 +1172,9 @@
 	dprintk("%s: NFSv4 Block Layout Driver Unregistering...\n",
 	       __func__);
 
+	rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
+	unregister_pernet_subsys(&nfs4blocklayout_net_ops);
 	pnfs_unregister_layoutdriver(&blocklayout_type);
-	rpc_unlink(bl_device_pipe);
-	rpc_put_mount();
 }
 
 MODULE_ALIAS("nfs-layouttype4-3");
diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h
index e31a2df..0335069 100644
--- a/fs/nfs/blocklayout/blocklayout.h
+++ b/fs/nfs/blocklayout/blocklayout.h
@@ -37,6 +37,7 @@
 #include <linux/sunrpc/rpc_pipe_fs.h>
 
 #include "../pnfs.h"
+#include "../netns.h"
 
 #define PAGE_CACHE_SECTORS (PAGE_CACHE_SIZE >> SECTOR_SHIFT)
 #define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT)
@@ -50,6 +51,7 @@
 	struct list_head		bm_node;
 	struct nfs4_deviceid		bm_mdevid;    /* associated devid */
 	struct block_device		*bm_mdev;     /* meta device itself */
+	struct net			*net;
 };
 
 enum exstate4 {
@@ -151,9 +153,9 @@
 	return BLK_LO2EXT(lseg->pls_layout);
 }
 
-struct bl_dev_msg {
-	int32_t status;
-	uint32_t major, minor;
+struct bl_pipe_msg {
+	struct rpc_pipe_msg msg;
+	wait_queue_head_t *bl_wq;
 };
 
 struct bl_msg_hdr {
@@ -161,9 +163,6 @@
 	u16 totallen; /* length of entire message, including hdr itself */
 };
 
-extern struct dentry *bl_device_pipe;
-extern wait_queue_head_t bl_wq;
-
 #define BL_DEVICE_UMOUNT               0x0 /* Umount--delete devices */
 #define BL_DEVICE_MOUNT                0x1 /* Mount--create devices*/
 #define BL_DEVICE_REQUEST_INIT         0x0 /* Start request */
diff --git a/fs/nfs/blocklayout/blocklayoutdev.c b/fs/nfs/blocklayout/blocklayoutdev.c
index d08ba91..a5c88a5 100644
--- a/fs/nfs/blocklayout/blocklayoutdev.c
+++ b/fs/nfs/blocklayout/blocklayoutdev.c
@@ -46,7 +46,7 @@
 
 	*rp = xdr_decode_hyper(*rp, &s);
 	if (s & 0x1ff) {
-		printk(KERN_WARNING "%s: sector not aligned\n", __func__);
+		printk(KERN_WARNING "NFS: %s: sector not aligned\n", __func__);
 		return -1;
 	}
 	*sp = s >> SECTOR_SHIFT;
@@ -79,27 +79,30 @@
 	return blkdev_put(bdev, FMODE_READ);
 }
 
-static struct bl_dev_msg bl_mount_reply;
-
 ssize_t bl_pipe_downcall(struct file *filp, const char __user *src,
 			 size_t mlen)
 {
+	struct nfs_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info,
+					 nfs_net_id);
+
 	if (mlen != sizeof (struct bl_dev_msg))
 		return -EINVAL;
 
-	if (copy_from_user(&bl_mount_reply, src, mlen) != 0)
+	if (copy_from_user(&nn->bl_mount_reply, src, mlen) != 0)
 		return -EFAULT;
 
-	wake_up(&bl_wq);
+	wake_up(&nn->bl_wq);
 
 	return mlen;
 }
 
 void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg)
 {
+	struct bl_pipe_msg *bl_pipe_msg = container_of(msg, struct bl_pipe_msg, msg);
+
 	if (msg->errno >= 0)
 		return;
-	wake_up(&bl_wq);
+	wake_up(bl_pipe_msg->bl_wq);
 }
 
 /*
@@ -111,29 +114,33 @@
 {
 	struct pnfs_block_dev *rv;
 	struct block_device *bd = NULL;
-	struct rpc_pipe_msg msg;
+	struct bl_pipe_msg bl_pipe_msg;
+	struct rpc_pipe_msg *msg = &bl_pipe_msg.msg;
 	struct bl_msg_hdr bl_msg = {
 		.type = BL_DEVICE_MOUNT,
 		.totallen = dev->mincount,
 	};
 	uint8_t *dataptr;
 	DECLARE_WAITQUEUE(wq, current);
-	struct bl_dev_msg *reply = &bl_mount_reply;
 	int offset, len, i, rc;
+	struct net *net = server->nfs_client->net;
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
+	struct bl_dev_msg *reply = &nn->bl_mount_reply;
 
 	dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
 	dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data,
 		dev->mincount);
 
-	memset(&msg, 0, sizeof(msg));
-	msg.data = kzalloc(sizeof(bl_msg) + dev->mincount, GFP_NOFS);
-	if (!msg.data) {
+	bl_pipe_msg.bl_wq = &nn->bl_wq;
+	memset(msg, 0, sizeof(*msg));
+	msg->data = kzalloc(sizeof(bl_msg) + dev->mincount, GFP_NOFS);
+	if (!msg->data) {
 		rv = ERR_PTR(-ENOMEM);
 		goto out;
 	}
 
-	memcpy(msg.data, &bl_msg, sizeof(bl_msg));
-	dataptr = (uint8_t *) msg.data;
+	memcpy(msg->data, &bl_msg, sizeof(bl_msg));
+	dataptr = (uint8_t *) msg->data;
 	len = dev->mincount;
 	offset = sizeof(bl_msg);
 	for (i = 0; len > 0; i++) {
@@ -142,13 +149,13 @@
 		len -= PAGE_CACHE_SIZE;
 		offset += PAGE_CACHE_SIZE;
 	}
-	msg.len = sizeof(bl_msg) + dev->mincount;
+	msg->len = sizeof(bl_msg) + dev->mincount;
 
 	dprintk("%s CALLING USERSPACE DAEMON\n", __func__);
-	add_wait_queue(&bl_wq, &wq);
-	rc = rpc_queue_upcall(bl_device_pipe->d_inode, &msg);
+	add_wait_queue(&nn->bl_wq, &wq);
+	rc = rpc_queue_upcall(nn->bl_device_pipe, msg);
 	if (rc < 0) {
-		remove_wait_queue(&bl_wq, &wq);
+		remove_wait_queue(&nn->bl_wq, &wq);
 		rv = ERR_PTR(rc);
 		goto out;
 	}
@@ -156,7 +163,7 @@
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule();
 	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&bl_wq, &wq);
+	remove_wait_queue(&nn->bl_wq, &wq);
 
 	if (reply->status != BL_DEVICE_REQUEST_PROC) {
 		dprintk("%s failed to open device: %d\n",
@@ -181,13 +188,14 @@
 
 	rv->bm_mdev = bd;
 	memcpy(&rv->bm_mdevid, &dev->dev_id, sizeof(struct nfs4_deviceid));
+	rv->net = net;
 	dprintk("%s Created device %s with bd_block_size %u\n",
 		__func__,
 		bd->bd_disk->disk_name,
 		bd->bd_block_size);
 
 out:
-	kfree(msg.data);
+	kfree(msg->data);
 	return rv;
 }
 
diff --git a/fs/nfs/blocklayout/blocklayoutdm.c b/fs/nfs/blocklayout/blocklayoutdm.c
index d055c75..737d839 100644
--- a/fs/nfs/blocklayout/blocklayoutdm.c
+++ b/fs/nfs/blocklayout/blocklayoutdm.c
@@ -38,9 +38,10 @@
 
 #define NFSDBG_FACILITY         NFSDBG_PNFS_LD
 
-static void dev_remove(dev_t dev)
+static void dev_remove(struct net *net, dev_t dev)
 {
-	struct rpc_pipe_msg msg;
+	struct bl_pipe_msg bl_pipe_msg;
+	struct rpc_pipe_msg *msg = &bl_pipe_msg.msg;
 	struct bl_dev_msg bl_umount_request;
 	struct bl_msg_hdr bl_msg = {
 		.type = BL_DEVICE_UMOUNT,
@@ -48,36 +49,38 @@
 	};
 	uint8_t *dataptr;
 	DECLARE_WAITQUEUE(wq, current);
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
 
 	dprintk("Entering %s\n", __func__);
 
-	memset(&msg, 0, sizeof(msg));
-	msg.data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS);
-	if (!msg.data)
+	bl_pipe_msg.bl_wq = &nn->bl_wq;
+	memset(msg, 0, sizeof(*msg));
+	msg->data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS);
+	if (!msg->data)
 		goto out;
 
 	memset(&bl_umount_request, 0, sizeof(bl_umount_request));
 	bl_umount_request.major = MAJOR(dev);
 	bl_umount_request.minor = MINOR(dev);
 
-	memcpy(msg.data, &bl_msg, sizeof(bl_msg));
-	dataptr = (uint8_t *) msg.data;
+	memcpy(msg->data, &bl_msg, sizeof(bl_msg));
+	dataptr = (uint8_t *) msg->data;
 	memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request));
-	msg.len = sizeof(bl_msg) + bl_msg.totallen;
+	msg->len = sizeof(bl_msg) + bl_msg.totallen;
 
-	add_wait_queue(&bl_wq, &wq);
-	if (rpc_queue_upcall(bl_device_pipe->d_inode, &msg) < 0) {
-		remove_wait_queue(&bl_wq, &wq);
+	add_wait_queue(&nn->bl_wq, &wq);
+	if (rpc_queue_upcall(nn->bl_device_pipe, msg) < 0) {
+		remove_wait_queue(&nn->bl_wq, &wq);
 		goto out;
 	}
 
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule();
 	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&bl_wq, &wq);
+	remove_wait_queue(&nn->bl_wq, &wq);
 
 out:
-	kfree(msg.data);
+	kfree(msg->data);
 }
 
 /*
@@ -90,10 +93,10 @@
 	dprintk("%s Releasing\n", __func__);
 	rv = nfs4_blkdev_put(bdev->bm_mdev);
 	if (rv)
-		printk(KERN_ERR "%s nfs4_blkdev_put returns %d\n",
+		printk(KERN_ERR "NFS: %s nfs4_blkdev_put returns %d\n",
 				__func__, rv);
 
-	dev_remove(bdev->bm_mdev->bd_dev);
+	dev_remove(bdev->net, bdev->bm_mdev->bd_dev);
 }
 
 void bl_free_block_dev(struct pnfs_block_dev *bdev)
diff --git a/fs/nfs/blocklayout/extents.c b/fs/nfs/blocklayout/extents.c
index 1abac09..1f9a603 100644
--- a/fs/nfs/blocklayout/extents.c
+++ b/fs/nfs/blocklayout/extents.c
@@ -147,7 +147,7 @@
 	count = (int)(end - start) / (int)tree->mtt_step_size;
 
 	/* Pre-malloc what memory we might need */
-	storage = kmalloc(sizeof(*storage) * count, GFP_NOFS);
+	storage = kcalloc(count, sizeof(*storage), GFP_NOFS);
 	if (!storage)
 		return -ENOMEM;
 	for (i = 0; i < count; i++) {
diff --git a/fs/nfs/cache_lib.c b/fs/nfs/cache_lib.c
index c98b439..dded263 100644
--- a/fs/nfs/cache_lib.c
+++ b/fs/nfs/cache_lib.c
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/sunrpc/cache.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
+#include <net/net_namespace.h>
 
 #include "cache_lib.h"
 
@@ -111,30 +112,54 @@
 	return 0;
 }
 
-int nfs_cache_register(struct cache_detail *cd)
+int nfs_cache_register_sb(struct super_block *sb, struct cache_detail *cd)
 {
-	struct vfsmount *mnt;
-	struct path path;
 	int ret;
+	struct dentry *dir;
 
-	mnt = rpc_get_mount();
-	if (IS_ERR(mnt))
-		return PTR_ERR(mnt);
-	ret = vfs_path_lookup(mnt->mnt_root, mnt, "/cache", 0, &path);
-	if (ret)
-		goto err;
-	ret = sunrpc_cache_register_pipefs(path.dentry, cd->name, 0600, cd);
-	path_put(&path);
-	if (!ret)
-		return ret;
-err:
-	rpc_put_mount();
+	dir = rpc_d_lookup_sb(sb, "cache");
+	BUG_ON(dir == NULL);
+	ret = sunrpc_cache_register_pipefs(dir, cd->name, 0600, cd);
+	dput(dir);
 	return ret;
 }
 
-void nfs_cache_unregister(struct cache_detail *cd)
+int nfs_cache_register_net(struct net *net, struct cache_detail *cd)
 {
-	sunrpc_cache_unregister_pipefs(cd);
-	rpc_put_mount();
+	struct super_block *pipefs_sb;
+	int ret = 0;
+
+	pipefs_sb = rpc_get_sb_net(net);
+	if (pipefs_sb) {
+		ret = nfs_cache_register_sb(pipefs_sb, cd);
+		rpc_put_sb_net(net);
+	}
+	return ret;
 }
 
+void nfs_cache_unregister_sb(struct super_block *sb, struct cache_detail *cd)
+{
+	if (cd->u.pipefs.dir)
+		sunrpc_cache_unregister_pipefs(cd);
+}
+
+void nfs_cache_unregister_net(struct net *net, struct cache_detail *cd)
+{
+	struct super_block *pipefs_sb;
+
+	pipefs_sb = rpc_get_sb_net(net);
+	if (pipefs_sb) {
+		nfs_cache_unregister_sb(pipefs_sb, cd);
+		rpc_put_sb_net(net);
+	}
+}
+
+void nfs_cache_init(struct cache_detail *cd)
+{
+	sunrpc_init_cache_detail(cd);
+}
+
+void nfs_cache_destroy(struct cache_detail *cd)
+{
+	sunrpc_destroy_cache_detail(cd);
+}
diff --git a/fs/nfs/cache_lib.h b/fs/nfs/cache_lib.h
index 7cf6caf..317db95 100644
--- a/fs/nfs/cache_lib.h
+++ b/fs/nfs/cache_lib.h
@@ -23,5 +23,11 @@
 extern void nfs_cache_defer_req_put(struct nfs_cache_defer_req *dreq);
 extern int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq);
 
-extern int nfs_cache_register(struct cache_detail *cd);
-extern void nfs_cache_unregister(struct cache_detail *cd);
+extern void nfs_cache_init(struct cache_detail *cd);
+extern void nfs_cache_destroy(struct cache_detail *cd);
+extern int nfs_cache_register_net(struct net *net, struct cache_detail *cd);
+extern void nfs_cache_unregister_net(struct net *net, struct cache_detail *cd);
+extern int nfs_cache_register_sb(struct super_block *sb,
+				 struct cache_detail *cd);
+extern void nfs_cache_unregister_sb(struct super_block *sb,
+				    struct cache_detail *cd);
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 516f337..eb95f50 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -85,7 +85,7 @@
 		}
 		if (err < 0) {
 			if (err != preverr) {
-				printk(KERN_WARNING "%s: unexpected error "
+				printk(KERN_WARNING "NFS: %s: unexpected error "
 					"from svc_recv (%d)\n", __func__, err);
 				preverr = err;
 			}
@@ -101,12 +101,12 @@
 /*
  * Prepare to bring up the NFSv4 callback service
  */
-struct svc_rqst *
-nfs4_callback_up(struct svc_serv *serv)
+static struct svc_rqst *
+nfs4_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
 {
 	int ret;
 
-	ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET,
+	ret = svc_create_xprt(serv, "tcp", xprt->xprt_net, PF_INET,
 				nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
 	if (ret <= 0)
 		goto out_err;
@@ -114,7 +114,7 @@
 	dprintk("NFS: Callback listener port = %u (af %u)\n",
 			nfs_callback_tcpport, PF_INET);
 
-	ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET6,
+	ret = svc_create_xprt(serv, "tcp", xprt->xprt_net, PF_INET6,
 				nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
 	if (ret > 0) {
 		nfs_callback_tcpport6 = ret;
@@ -172,7 +172,7 @@
 /*
  * Bring up the NFSv4.1 callback service
  */
-struct svc_rqst *
+static struct svc_rqst *
 nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
 {
 	struct svc_rqst *rqstp;
@@ -183,7 +183,7 @@
 	 * fore channel connection.
 	 * Returns the input port (0) and sets the svc_serv bc_xprt on success
 	 */
-	ret = svc_create_xprt(serv, "tcp-bc", &init_net, PF_INET, 0,
+	ret = svc_create_xprt(serv, "tcp-bc", xprt->xprt_net, PF_INET, 0,
 			      SVC_SOCK_ANONYMOUS);
 	if (ret < 0) {
 		rqstp = ERR_PTR(ret);
@@ -269,7 +269,7 @@
 					serv, xprt, &rqstp, &callback_svc);
 	if (!minorversion_setup) {
 		/* v4.0 callback setup */
-		rqstp = nfs4_callback_up(serv);
+		rqstp = nfs4_callback_up(serv, xprt);
 		callback_svc = nfs4_callback_svc;
 	}
 
@@ -332,7 +332,6 @@
 int
 check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
 {
-	struct rpc_clnt *r = clp->cl_rpcclient;
 	char *p = svc_gss_principal(rqstp);
 
 	if (rqstp->rq_authop->flavour != RPC_AUTH_GSS)
@@ -353,7 +352,7 @@
 	if (memcmp(p, "nfs@", 4) != 0)
 		return 0;
 	p += 4;
-	if (strcmp(p, r->cl_server) != 0)
+	if (strcmp(p, clp->cl_hostname) != 0)
 		return 0;
 	return 1;
 }
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h
index c89d3b9..a5527c9 100644
--- a/fs/nfs/callback.h
+++ b/fs/nfs/callback.h
@@ -38,7 +38,8 @@
 struct cb_process_state {
 	__be32			drc_status;
 	struct nfs_client	*clp;
-	int			slotid;
+	u32			slotid;
+	struct net		*net;
 };
 
 struct cb_compound_hdr_arg {
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 54cea8a..1b5d809 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -8,6 +8,7 @@
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
 #include <linux/slab.h>
+#include <linux/rcupdate.h>
 #include "nfs4_fs.h"
 #include "callback.h"
 #include "delegation.h"
@@ -33,7 +34,7 @@
 	res->bitmap[0] = res->bitmap[1] = 0;
 	res->status = htonl(NFS4ERR_BADHANDLE);
 
-	dprintk("NFS: GETATTR callback request from %s\n",
+	dprintk_rcu("NFS: GETATTR callback request from %s\n",
 		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 
 	inode = nfs_delegation_find_inode(cps->clp, &args->fh);
@@ -73,7 +74,7 @@
 	if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */
 		goto out;
 
-	dprintk("NFS: RECALL callback request from %s\n",
+	dprintk_rcu("NFS: RECALL callback request from %s\n",
 		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 
 	res = htonl(NFS4ERR_BADHANDLE);
@@ -86,8 +87,7 @@
 		res = 0;
 		break;
 	case -ENOENT:
-		if (res != 0)
-			res = htonl(NFS4ERR_BAD_STATEID);
+		res = htonl(NFS4ERR_BAD_STATEID);
 		break;
 	default:
 		res = htonl(NFS4ERR_RESOURCE);
@@ -98,52 +98,64 @@
 	return res;
 }
 
-int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
-{
-	if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data,
-					 sizeof(delegation->stateid.data)) != 0)
-		return 0;
-	return 1;
-}
-
 #if defined(CONFIG_NFS_V4_1)
 
-static u32 initiate_file_draining(struct nfs_client *clp,
-				  struct cb_layoutrecallargs *args)
+/*
+ * Lookup a layout by filehandle.
+ *
+ * Note: gets a refcount on the layout hdr and on its respective inode.
+ * Caller must put the layout hdr and the inode.
+ *
+ * TODO: keep track of all layouts (and delegations) in a hash table
+ * hashed by filehandle.
+ */
+static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, struct nfs_fh *fh)
 {
 	struct nfs_server *server;
-	struct pnfs_layout_hdr *lo;
 	struct inode *ino;
-	bool found = false;
-	u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
-	LIST_HEAD(free_me_list);
+	struct pnfs_layout_hdr *lo;
 
-	spin_lock(&clp->cl_lock);
-	rcu_read_lock();
 	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
 		list_for_each_entry(lo, &server->layouts, plh_layouts) {
-			if (nfs_compare_fh(&args->cbl_fh,
-					   &NFS_I(lo->plh_inode)->fh))
+			if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh))
 				continue;
 			ino = igrab(lo->plh_inode);
 			if (!ino)
 				continue;
-			found = true;
-			/* Without this, layout can be freed as soon
-			 * as we release cl_lock.
-			 */
 			get_layout_hdr(lo);
-			break;
+			return lo;
 		}
-		if (found)
-			break;
 	}
+
+	return NULL;
+}
+
+static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, struct nfs_fh *fh)
+{
+	struct pnfs_layout_hdr *lo;
+
+	spin_lock(&clp->cl_lock);
+	rcu_read_lock();
+	lo = get_layout_by_fh_locked(clp, fh);
 	rcu_read_unlock();
 	spin_unlock(&clp->cl_lock);
 
-	if (!found)
+	return lo;
+}
+
+static u32 initiate_file_draining(struct nfs_client *clp,
+				  struct cb_layoutrecallargs *args)
+{
+	struct inode *ino;
+	struct pnfs_layout_hdr *lo;
+	u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
+	LIST_HEAD(free_me_list);
+
+	lo = get_layout_by_fh(clp, &args->cbl_fh);
+	if (!lo)
 		return NFS4ERR_NOMATCHING_LAYOUT;
 
+	ino = lo->plh_inode;
 	spin_lock(&ino->i_lock);
 	if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
 	    mark_matching_lsegs_invalid(lo, &free_me_list,
@@ -213,17 +225,13 @@
 static u32 do_callback_layoutrecall(struct nfs_client *clp,
 				    struct cb_layoutrecallargs *args)
 {
-	u32 res = NFS4ERR_DELAY;
+	u32 res;
 
 	dprintk("%s enter, type=%i\n", __func__, args->cbl_recall_type);
-	if (test_and_set_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state))
-		goto out;
 	if (args->cbl_recall_type == RETURN_FILE)
 		res = initiate_file_draining(clp, args);
 	else
 		res = initiate_bulk_draining(clp, args);
-	clear_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state);
-out:
 	dprintk("%s returning %i\n", __func__, res);
 	return res;
 
@@ -303,21 +311,6 @@
 	return res;
 }
 
-int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
-{
-	if (delegation == NULL)
-		return 0;
-
-	if (stateid->stateid.seqid != 0)
-		return 0;
-	if (memcmp(&delegation->stateid.stateid.other,
-		   &stateid->stateid.other,
-		   NFS4_STATEID_OTHER_SIZE))
-		return 0;
-
-	return 1;
-}
-
 /*
  * Validate the sequenceID sent by the server.
  * Return success if the sequenceID is one more than what we last saw on
@@ -441,7 +434,7 @@
 	int i;
 	__be32 status = htonl(NFS4ERR_BADSESSION);
 
-	clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid);
+	clp = nfs4_find_client_sessionid(cps->net, args->csa_addr, &args->csa_sessionid);
 	if (clp == NULL)
 		goto out;
 
@@ -517,7 +510,7 @@
 	if (!cps->clp) /* set in cb_sequence */
 		goto out;
 
-	dprintk("NFS: RECALL_ANY callback request from %s\n",
+	dprintk_rcu("NFS: RECALL_ANY callback request from %s\n",
 		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 
 	status = cpu_to_be32(NFS4ERR_INVAL);
@@ -552,7 +545,7 @@
 	if (!cps->clp) /* set in cb_sequence */
 		goto out;
 
-	dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d\n",
+	dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target max slots %d\n",
 		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR),
 		args->crsa_target_max_slots);
 
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index d50b274..95bfc24 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -9,6 +9,8 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
+#include <linux/ratelimit.h>
+#include <linux/printk.h>
 #include <linux/slab.h>
 #include <linux/sunrpc/bc_xprt.h>
 #include "nfs4_fs.h"
@@ -73,7 +75,7 @@
 
 	p = xdr_inline_decode(xdr, nbytes);
 	if (unlikely(p == NULL))
-		printk(KERN_WARNING "NFSv4 callback reply buffer overflowed!\n");
+		printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed!\n");
 	return p;
 }
 
@@ -138,10 +140,10 @@
 {
 	__be32 *p;
 
-	p = read_buf(xdr, 16);
+	p = read_buf(xdr, NFS4_STATEID_SIZE);
 	if (unlikely(p == NULL))
 		return htonl(NFS4ERR_RESOURCE);
-	memcpy(stateid->data, p, 16);
+	memcpy(stateid, p, NFS4_STATEID_SIZE);
 	return 0;
 }
 
@@ -155,7 +157,7 @@
 		return status;
 	/* We do not like overly long tags! */
 	if (hdr->taglen > CB_OP_TAGLEN_MAXSZ - 12) {
-		printk("NFSv4 CALLBACK %s: client sent tag of length %u\n",
+		printk("NFS: NFSv4 CALLBACK %s: client sent tag of length %u\n",
 				__func__, hdr->taglen);
 		return htonl(NFS4ERR_RESOURCE);
 	}
@@ -167,7 +169,7 @@
 	if (hdr->minorversion <= 1) {
 		hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 */
 	} else {
-		printk(KERN_WARNING "%s: NFSv4 server callback with "
+		pr_warn_ratelimited("NFS: %s: NFSv4 server callback with "
 			"illegal minor version %u!\n",
 			__func__, hdr->minorversion);
 		return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
@@ -759,14 +761,14 @@
 	 * Let the state manager know callback processing done.
 	 * A single slot, so highest used slotid is either 0 or -1
 	 */
-	tbl->highest_used_slotid = -1;
+	tbl->highest_used_slotid = NFS4_NO_SLOT;
 	nfs4_check_drain_bc_complete(session);
 	spin_unlock(&tbl->slot_tbl_lock);
 }
 
 static void nfs4_cb_free_slot(struct cb_process_state *cps)
 {
-	if (cps->slotid != -1)
+	if (cps->slotid != NFS4_NO_SLOT)
 		nfs4_callback_free_slot(cps->clp->cl_session);
 }
 
@@ -860,7 +862,8 @@
 	struct cb_process_state cps = {
 		.drc_status = 0,
 		.clp = NULL,
-		.slotid = -1,
+		.slotid = NFS4_NO_SLOT,
+		.net = rqstp->rq_xprt->xpt_net,
 	};
 	unsigned int nops = 0;
 
@@ -876,7 +879,7 @@
 		return rpc_garbage_args;
 
 	if (hdr_arg.minorversion == 0) {
-		cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident);
+		cps.clp = nfs4_find_client_ident(rqstp->rq_xprt->xpt_net, hdr_arg.cb_ident);
 		if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
 			return rpc_drop_reply;
 	}
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index d4f772e..da7b5e4 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -40,8 +40,9 @@
 #include <net/ipv6.h>
 #include <linux/nfs_xdr.h>
 #include <linux/sunrpc/bc_xprt.h>
+#include <linux/nsproxy.h>
+#include <linux/pid_namespace.h>
 
-#include <asm/system.h>
 
 #include "nfs4_fs.h"
 #include "callback.h"
@@ -50,15 +51,12 @@
 #include "internal.h"
 #include "fscache.h"
 #include "pnfs.h"
+#include "netns.h"
 
 #define NFSDBG_FACILITY		NFSDBG_CLIENT
 
-static DEFINE_SPINLOCK(nfs_client_lock);
-static LIST_HEAD(nfs_client_list);
-static LIST_HEAD(nfs_volume_list);
 static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
 #ifdef CONFIG_NFS_V4
-static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */
 
 /*
  * Get a unique NFSv4.0 callback identifier which will be used
@@ -67,15 +65,16 @@
 static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
 {
 	int ret = 0;
+	struct nfs_net *nn = net_generic(clp->net, nfs_net_id);
 
 	if (clp->rpc_ops->version != 4 || minorversion != 0)
 		return ret;
 retry:
-	if (!idr_pre_get(&cb_ident_idr, GFP_KERNEL))
+	if (!idr_pre_get(&nn->cb_ident_idr, GFP_KERNEL))
 		return -ENOMEM;
-	spin_lock(&nfs_client_lock);
-	ret = idr_get_new(&cb_ident_idr, clp, &clp->cl_cb_ident);
-	spin_unlock(&nfs_client_lock);
+	spin_lock(&nn->nfs_client_lock);
+	ret = idr_get_new(&nn->cb_ident_idr, clp, &clp->cl_cb_ident);
+	spin_unlock(&nn->nfs_client_lock);
 	if (ret == -EAGAIN)
 		goto retry;
 	return ret;
@@ -90,7 +89,7 @@
 /*
  * RPC cruft for NFS
  */
-static struct rpc_version *nfs_version[5] = {
+static const struct rpc_version *nfs_version[5] = {
 	[2]			= &nfs_version2,
 #ifdef CONFIG_NFS_V3
 	[3]			= &nfs_version3,
@@ -100,7 +99,7 @@
 #endif
 };
 
-struct rpc_program nfs_program = {
+const struct rpc_program nfs_program = {
 	.name			= "nfs",
 	.number			= NFS_PROGRAM,
 	.nrvers			= ARRAY_SIZE(nfs_version),
@@ -116,11 +115,11 @@
 
 #ifdef CONFIG_NFS_V3_ACL
 static struct rpc_stat		nfsacl_rpcstat = { &nfsacl_program };
-static struct rpc_version *	nfsacl_version[] = {
+static const struct rpc_version *nfsacl_version[] = {
 	[3]			= &nfsacl_version3,
 };
 
-struct rpc_program		nfsacl_program = {
+const struct rpc_program nfsacl_program = {
 	.name			= "nfsacl",
 	.number			= NFS_ACL_PROGRAM,
 	.nrvers			= ARRAY_SIZE(nfsacl_version),
@@ -136,6 +135,7 @@
 	const struct nfs_rpc_ops *rpc_ops;
 	int proto;
 	u32 minorversion;
+	struct net *net;
 };
 
 /*
@@ -172,6 +172,7 @@
 	clp->cl_rpcclient = ERR_PTR(-EINVAL);
 
 	clp->cl_proto = cl_init->proto;
+	clp->net = get_net(cl_init->net);
 
 #ifdef CONFIG_NFS_V4
 	err = nfs_get_cb_ident_idr(clp, cl_init->minorversion);
@@ -203,8 +204,11 @@
 #ifdef CONFIG_NFS_V4_1
 static void nfs4_shutdown_session(struct nfs_client *clp)
 {
-	if (nfs4_has_session(clp))
+	if (nfs4_has_session(clp)) {
+		nfs4_deviceid_purge_client(clp);
 		nfs4_destroy_session(clp->cl_session);
+	}
+
 }
 #else /* CONFIG_NFS_V4_1 */
 static void nfs4_shutdown_session(struct nfs_client *clp)
@@ -234,16 +238,20 @@
 }
 
 /* idr_remove_all is not needed as all id's are removed by nfs_put_client */
-void nfs_cleanup_cb_ident_idr(void)
+void nfs_cleanup_cb_ident_idr(struct net *net)
 {
-	idr_destroy(&cb_ident_idr);
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
+
+	idr_destroy(&nn->cb_ident_idr);
 }
 
 /* nfs_client_lock held */
 static void nfs_cb_idr_remove_locked(struct nfs_client *clp)
 {
+	struct nfs_net *nn = net_generic(clp->net, nfs_net_id);
+
 	if (clp->cl_cb_ident)
-		idr_remove(&cb_ident_idr, clp->cl_cb_ident);
+		idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident);
 }
 
 static void pnfs_init_server(struct nfs_server *server)
@@ -261,7 +269,7 @@
 {
 }
 
-void nfs_cleanup_cb_ident_idr(void)
+void nfs_cleanup_cb_ident_idr(struct net *net)
 {
 }
 
@@ -293,10 +301,10 @@
 	if (clp->cl_machine_cred != NULL)
 		put_rpccred(clp->cl_machine_cred);
 
-	nfs4_deviceid_purge_client(clp);
-
+	put_net(clp->net);
 	kfree(clp->cl_hostname);
 	kfree(clp->server_scope);
+	kfree(clp->impl_id);
 	kfree(clp);
 
 	dprintk("<-- nfs_free_client()\n");
@@ -307,15 +315,18 @@
  */
 void nfs_put_client(struct nfs_client *clp)
 {
+	struct nfs_net *nn;
+
 	if (!clp)
 		return;
 
 	dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count));
+	nn = net_generic(clp->net, nfs_net_id);
 
-	if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) {
+	if (atomic_dec_and_lock(&clp->cl_count, &nn->nfs_client_lock)) {
 		list_del(&clp->cl_share_link);
 		nfs_cb_idr_remove_locked(clp);
-		spin_unlock(&nfs_client_lock);
+		spin_unlock(&nn->nfs_client_lock);
 
 		BUG_ON(!list_empty(&clp->cl_superblocks));
 
@@ -393,6 +404,7 @@
 		(sin1->sin_port == sin2->sin_port);
 }
 
+#if defined(CONFIG_NFS_V4_1)
 /*
  * Test if two socket addresses represent the same actual socket,
  * by comparing (only) relevant fields, excluding the port number.
@@ -411,6 +423,7 @@
 	}
 	return 0;
 }
+#endif /* CONFIG_NFS_V4_1 */
 
 /*
  * Test if two socket addresses represent the same actual socket,
@@ -431,10 +444,10 @@
 	return 0;
 }
 
+#if defined(CONFIG_NFS_V4_1)
 /* Common match routine for v4.0 and v4.1 callback services */
-bool
-nfs4_cb_match_client(const struct sockaddr *addr, struct nfs_client *clp,
-		     u32 minorversion)
+static bool nfs4_cb_match_client(const struct sockaddr *addr,
+		struct nfs_client *clp, u32 minorversion)
 {
 	struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
 
@@ -454,6 +467,7 @@
 
 	return true;
 }
+#endif /* CONFIG_NFS_V4_1 */
 
 /*
  * Find an nfs_client on the list that matches the initialisation data
@@ -463,8 +477,9 @@
 {
 	struct nfs_client *clp;
 	const struct sockaddr *sap = data->addr;
+	struct nfs_net *nn = net_generic(data->net, nfs_net_id);
 
-	list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
+	list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
 	        const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
 		/* Don't match clients that failed to initialise properly */
 		if (clp->cl_cons_state < 0)
@@ -502,13 +517,14 @@
 {
 	struct nfs_client *clp, *new = NULL;
 	int error;
+	struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id);
 
 	dprintk("--> nfs_get_client(%s,v%u)\n",
 		cl_init->hostname ?: "", cl_init->rpc_ops->version);
 
 	/* see if the client already exists */
 	do {
-		spin_lock(&nfs_client_lock);
+		spin_lock(&nn->nfs_client_lock);
 
 		clp = nfs_match_client(cl_init);
 		if (clp)
@@ -516,7 +532,7 @@
 		if (new)
 			goto install_client;
 
-		spin_unlock(&nfs_client_lock);
+		spin_unlock(&nn->nfs_client_lock);
 
 		new = nfs_alloc_client(cl_init);
 	} while (!IS_ERR(new));
@@ -527,8 +543,8 @@
 	/* install a new client and return with it unready */
 install_client:
 	clp = new;
-	list_add(&clp->cl_share_link, &nfs_client_list);
-	spin_unlock(&nfs_client_lock);
+	list_add(&clp->cl_share_link, &nn->nfs_client_list);
+	spin_unlock(&nn->nfs_client_lock);
 
 	error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr,
 					      authflavour, noresvport);
@@ -543,7 +559,7 @@
 	 * - make sure it's ready before returning
 	 */
 found_client:
-	spin_unlock(&nfs_client_lock);
+	spin_unlock(&nn->nfs_client_lock);
 
 	if (new)
 		nfs_free_client(new);
@@ -643,7 +659,7 @@
 {
 	struct rpc_clnt		*clnt = NULL;
 	struct rpc_create_args args = {
-		.net		= &init_net,
+		.net		= clp->net,
 		.protocol	= clp->cl_proto,
 		.address	= (struct sockaddr *)&clp->cl_addr,
 		.addrsize	= clp->cl_addrlen,
@@ -697,6 +713,7 @@
 		.nfs_version	= clp->rpc_ops->version,
 		.noresvport	= server->flags & NFS_MOUNT_NORESVPORT ?
 					1 : 0,
+		.net		= clp->net,
 	};
 
 	if (nlm_init.nfs_version > 3)
@@ -832,6 +849,7 @@
 		.addrlen = data->nfs_server.addrlen,
 		.rpc_ops = &nfs_v2_clientops,
 		.proto = data->nfs_server.protocol,
+		.net = data->net,
 	};
 	struct rpc_timeout timeparms;
 	struct nfs_client *clp;
@@ -1030,25 +1048,30 @@
 static void nfs_server_insert_lists(struct nfs_server *server)
 {
 	struct nfs_client *clp = server->nfs_client;
+	struct nfs_net *nn = net_generic(clp->net, nfs_net_id);
 
-	spin_lock(&nfs_client_lock);
+	spin_lock(&nn->nfs_client_lock);
 	list_add_tail_rcu(&server->client_link, &clp->cl_superblocks);
-	list_add_tail(&server->master_link, &nfs_volume_list);
+	list_add_tail(&server->master_link, &nn->nfs_volume_list);
 	clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
-	spin_unlock(&nfs_client_lock);
+	spin_unlock(&nn->nfs_client_lock);
 
 }
 
 static void nfs_server_remove_lists(struct nfs_server *server)
 {
 	struct nfs_client *clp = server->nfs_client;
+	struct nfs_net *nn;
 
-	spin_lock(&nfs_client_lock);
+	if (clp == NULL)
+		return;
+	nn = net_generic(clp->net, nfs_net_id);
+	spin_lock(&nn->nfs_client_lock);
 	list_del_rcu(&server->client_link);
-	if (clp && list_empty(&clp->cl_superblocks))
+	if (list_empty(&clp->cl_superblocks))
 		set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
 	list_del(&server->master_link);
-	spin_unlock(&nfs_client_lock);
+	spin_unlock(&nn->nfs_client_lock);
 
 	synchronize_rcu();
 }
@@ -1087,6 +1110,8 @@
 		return NULL;
 	}
 
+	ida_init(&server->openowner_id);
+	ida_init(&server->lockowner_id);
 	pnfs_init_server(server);
 
 	return server;
@@ -1112,6 +1137,8 @@
 
 	nfs_put_client(server->nfs_client);
 
+	ida_destroy(&server->lockowner_id);
+	ida_destroy(&server->openowner_id);
 	nfs_free_iostats(server->io_stats);
 	bdi_destroy(&server->backing_dev_info);
 	kfree(server);
@@ -1190,45 +1217,19 @@
 /*
  * NFSv4.0 callback thread helper
  *
- * Find a client by IP address, protocol version, and minorversion
- *
- * Called from the pg_authenticate method. The callback identifier
- * is not used as it has not been decoded.
- *
- * Returns NULL if no such client
- */
-struct nfs_client *
-nfs4_find_client_no_ident(const struct sockaddr *addr)
-{
-	struct nfs_client *clp;
-
-	spin_lock(&nfs_client_lock);
-	list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
-		if (nfs4_cb_match_client(addr, clp, 0) == false)
-			continue;
-		atomic_inc(&clp->cl_count);
-		spin_unlock(&nfs_client_lock);
-		return clp;
-	}
-	spin_unlock(&nfs_client_lock);
-	return NULL;
-}
-
-/*
- * NFSv4.0 callback thread helper
- *
  * Find a client by callback identifier
  */
 struct nfs_client *
-nfs4_find_client_ident(int cb_ident)
+nfs4_find_client_ident(struct net *net, int cb_ident)
 {
 	struct nfs_client *clp;
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
 
-	spin_lock(&nfs_client_lock);
-	clp = idr_find(&cb_ident_idr, cb_ident);
+	spin_lock(&nn->nfs_client_lock);
+	clp = idr_find(&nn->cb_ident_idr, cb_ident);
 	if (clp)
 		atomic_inc(&clp->cl_count);
-	spin_unlock(&nfs_client_lock);
+	spin_unlock(&nn->nfs_client_lock);
 	return clp;
 }
 
@@ -1241,13 +1242,14 @@
  * Returns NULL if no such client
  */
 struct nfs_client *
-nfs4_find_client_sessionid(const struct sockaddr *addr,
+nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
 			   struct nfs4_sessionid *sid)
 {
 	struct nfs_client *clp;
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
 
-	spin_lock(&nfs_client_lock);
-	list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
+	spin_lock(&nn->nfs_client_lock);
+	list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
 		if (nfs4_cb_match_client(addr, clp, 1) == false)
 			continue;
 
@@ -1260,17 +1262,17 @@
 			continue;
 
 		atomic_inc(&clp->cl_count);
-		spin_unlock(&nfs_client_lock);
+		spin_unlock(&nn->nfs_client_lock);
 		return clp;
 	}
-	spin_unlock(&nfs_client_lock);
+	spin_unlock(&nn->nfs_client_lock);
 	return NULL;
 }
 
 #else /* CONFIG_NFS_V4_1 */
 
 struct nfs_client *
-nfs4_find_client_sessionid(const struct sockaddr *addr,
+nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
 			   struct nfs4_sessionid *sid)
 {
 	return NULL;
@@ -1285,16 +1287,18 @@
 	int error;
 
 	if (clp->rpc_ops->version == 4) {
+		struct rpc_xprt *xprt;
+
+		xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt);
+
 		if (nfs4_has_session(clp)) {
-			error = xprt_setup_backchannel(
-						clp->cl_rpcclient->cl_xprt,
+			error = xprt_setup_backchannel(xprt,
 						NFS41_BC_MIN_CALLBACKS);
 			if (error < 0)
 				return error;
 		}
 
-		error = nfs_callback_up(clp->cl_mvops->minor_version,
-					clp->cl_rpcclient->cl_xprt);
+		error = nfs_callback_up(clp->cl_mvops->minor_version, xprt);
 		if (error < 0) {
 			dprintk("%s: failed to start callback. Error = %d\n",
 				__func__, error);
@@ -1345,6 +1349,7 @@
 		     rpc_authflavor_t authflavour,
 		     int noresvport)
 {
+	char buf[INET6_ADDRSTRLEN + 1];
 	int error;
 
 	if (clp->cl_cons_state == NFS_CS_READY) {
@@ -1360,6 +1365,20 @@
 				      1, noresvport);
 	if (error < 0)
 		goto error;
+
+	/* If no clientaddr= option was specified, find a usable cb address */
+	if (ip_addr == NULL) {
+		struct sockaddr_storage cb_addr;
+		struct sockaddr *sap = (struct sockaddr *)&cb_addr;
+
+		error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr));
+		if (error < 0)
+			goto error;
+		error = rpc_ntop(sap, buf, sizeof(buf));
+		if (error < 0)
+			goto error;
+		ip_addr = (const char *)buf;
+	}
 	strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
 
 	error = nfs_idmap_new(clp);
@@ -1394,7 +1413,7 @@
 		const char *ip_addr,
 		rpc_authflavor_t authflavour,
 		int proto, const struct rpc_timeout *timeparms,
-		u32 minorversion)
+		u32 minorversion, struct net *net)
 {
 	struct nfs_client_initdata cl_init = {
 		.hostname = hostname,
@@ -1403,6 +1422,7 @@
 		.rpc_ops = &nfs_v4_clientops,
 		.proto = proto,
 		.minorversion = minorversion,
+		.net = net,
 	};
 	struct nfs_client *clp;
 	int error;
@@ -1454,6 +1474,7 @@
 		.rpc_ops = &nfs_v4_clientops,
 		.proto = ds_proto,
 		.minorversion = mds_clp->cl_minorversion,
+		.net = mds_clp->net,
 	};
 	struct rpc_timeout ds_timeout = {
 		.to_initval = 15 * HZ,
@@ -1581,7 +1602,8 @@
 			data->auth_flavors[0],
 			data->nfs_server.protocol,
 			&timeparms,
-			data->minorversion);
+			data->minorversion,
+			data->net);
 	if (error < 0)
 		goto error;
 
@@ -1676,9 +1698,10 @@
 				data->addrlen,
 				parent_client->cl_ipaddr,
 				data->authflavor,
-				parent_server->client->cl_xprt->prot,
+				rpc_protocol(parent_server->client),
 				parent_server->client->cl_timeout,
-				parent_client->cl_mvops->minor_version);
+				parent_client->cl_mvops->minor_version,
+				parent_client->net);
 	if (error < 0)
 		goto error;
 
@@ -1771,6 +1794,18 @@
 	return ERR_PTR(error);
 }
 
+void nfs_clients_init(struct net *net)
+{
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
+
+	INIT_LIST_HEAD(&nn->nfs_client_list);
+	INIT_LIST_HEAD(&nn->nfs_volume_list);
+#ifdef CONFIG_NFS_V4
+	idr_init(&nn->cb_ident_idr);
+#endif
+	spin_lock_init(&nn->nfs_client_lock);
+}
+
 #ifdef CONFIG_PROC_FS
 static struct proc_dir_entry *proc_fs_nfs;
 
@@ -1824,13 +1859,15 @@
 {
 	struct seq_file *m;
 	int ret;
+	struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info;
+	struct net *net = pid_ns->child_reaper->nsproxy->net_ns;
 
 	ret = seq_open(file, &nfs_server_list_ops);
 	if (ret < 0)
 		return ret;
 
 	m = file->private_data;
-	m->private = PDE(inode)->data;
+	m->private = net;
 
 	return 0;
 }
@@ -1840,9 +1877,11 @@
  */
 static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
 {
+	struct nfs_net *nn = net_generic(m->private, nfs_net_id);
+
 	/* lock the list against modification */
-	spin_lock(&nfs_client_lock);
-	return seq_list_start_head(&nfs_client_list, *_pos);
+	spin_lock(&nn->nfs_client_lock);
+	return seq_list_start_head(&nn->nfs_client_list, *_pos);
 }
 
 /*
@@ -1850,7 +1889,9 @@
  */
 static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
 {
-	return seq_list_next(v, &nfs_client_list, pos);
+	struct nfs_net *nn = net_generic(p->private, nfs_net_id);
+
+	return seq_list_next(v, &nn->nfs_client_list, pos);
 }
 
 /*
@@ -1858,7 +1899,9 @@
  */
 static void nfs_server_list_stop(struct seq_file *p, void *v)
 {
-	spin_unlock(&nfs_client_lock);
+	struct nfs_net *nn = net_generic(p->private, nfs_net_id);
+
+	spin_unlock(&nn->nfs_client_lock);
 }
 
 /*
@@ -1867,9 +1910,10 @@
 static int nfs_server_list_show(struct seq_file *m, void *v)
 {
 	struct nfs_client *clp;
+	struct nfs_net *nn = net_generic(m->private, nfs_net_id);
 
 	/* display header on line 1 */
-	if (v == &nfs_client_list) {
+	if (v == &nn->nfs_client_list) {
 		seq_puts(m, "NV SERVER   PORT USE HOSTNAME\n");
 		return 0;
 	}
@@ -1881,12 +1925,14 @@
 	if (clp->cl_cons_state != NFS_CS_READY)
 		return 0;
 
+	rcu_read_lock();
 	seq_printf(m, "v%u %s %s %3d %s\n",
 		   clp->rpc_ops->version,
 		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
 		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
 		   atomic_read(&clp->cl_count),
 		   clp->cl_hostname);
+	rcu_read_unlock();
 
 	return 0;
 }
@@ -1898,13 +1944,15 @@
 {
 	struct seq_file *m;
 	int ret;
+	struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info;
+	struct net *net = pid_ns->child_reaper->nsproxy->net_ns;
 
 	ret = seq_open(file, &nfs_volume_list_ops);
 	if (ret < 0)
 		return ret;
 
 	m = file->private_data;
-	m->private = PDE(inode)->data;
+	m->private = net;
 
 	return 0;
 }
@@ -1914,9 +1962,11 @@
  */
 static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
 {
+	struct nfs_net *nn = net_generic(m->private, nfs_net_id);
+
 	/* lock the list against modification */
-	spin_lock(&nfs_client_lock);
-	return seq_list_start_head(&nfs_volume_list, *_pos);
+	spin_lock(&nn->nfs_client_lock);
+	return seq_list_start_head(&nn->nfs_volume_list, *_pos);
 }
 
 /*
@@ -1924,7 +1974,9 @@
  */
 static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
 {
-	return seq_list_next(v, &nfs_volume_list, pos);
+	struct nfs_net *nn = net_generic(p->private, nfs_net_id);
+
+	return seq_list_next(v, &nn->nfs_volume_list, pos);
 }
 
 /*
@@ -1932,7 +1984,9 @@
  */
 static void nfs_volume_list_stop(struct seq_file *p, void *v)
 {
-	spin_unlock(&nfs_client_lock);
+	struct nfs_net *nn = net_generic(p->private, nfs_net_id);
+
+	spin_unlock(&nn->nfs_client_lock);
 }
 
 /*
@@ -1943,9 +1997,10 @@
 	struct nfs_server *server;
 	struct nfs_client *clp;
 	char dev[8], fsid[17];
+	struct nfs_net *nn = net_generic(m->private, nfs_net_id);
 
 	/* display header on line 1 */
-	if (v == &nfs_volume_list) {
+	if (v == &nn->nfs_volume_list) {
 		seq_puts(m, "NV SERVER   PORT DEV     FSID              FSC\n");
 		return 0;
 	}
@@ -1960,6 +2015,7 @@
 		 (unsigned long long) server->fsid.major,
 		 (unsigned long long) server->fsid.minor);
 
+	rcu_read_lock();
 	seq_printf(m, "v%u %s %s %-7s %-17s %s\n",
 		   clp->rpc_ops->version,
 		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
@@ -1967,6 +2023,7 @@
 		   dev,
 		   fsid,
 		   nfs_server_fscache_state(server));
+	rcu_read_unlock();
 
 	return 0;
 }
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 7f26540..89af1d2 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -105,7 +105,7 @@
 			continue;
 		if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
 			continue;
-		if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0)
+		if (!nfs4_stateid_match(&state->stateid, stateid))
 			continue;
 		get_nfs_open_context(ctx);
 		spin_unlock(&inode->i_lock);
@@ -139,8 +139,7 @@
 	if (delegation != NULL) {
 		spin_lock(&delegation->lock);
 		if (delegation->inode != NULL) {
-			memcpy(delegation->stateid.data, res->delegation.data,
-			       sizeof(delegation->stateid.data));
+			nfs4_stateid_copy(&delegation->stateid, &res->delegation);
 			delegation->type = res->delegation_type;
 			delegation->maxsize = res->maxsize;
 			oldcred = delegation->cred;
@@ -236,8 +235,7 @@
 	delegation = kmalloc(sizeof(*delegation), GFP_NOFS);
 	if (delegation == NULL)
 		return -ENOMEM;
-	memcpy(delegation->stateid.data, res->delegation.data,
-			sizeof(delegation->stateid.data));
+	nfs4_stateid_copy(&delegation->stateid, &res->delegation);
 	delegation->type = res->delegation_type;
 	delegation->maxsize = res->maxsize;
 	delegation->change_attr = inode->i_version;
@@ -250,19 +248,22 @@
 	old_delegation = rcu_dereference_protected(nfsi->delegation,
 					lockdep_is_held(&clp->cl_lock));
 	if (old_delegation != NULL) {
-		if (memcmp(&delegation->stateid, &old_delegation->stateid,
-					sizeof(old_delegation->stateid)) == 0 &&
+		if (nfs4_stateid_match(&delegation->stateid,
+					&old_delegation->stateid) &&
 				delegation->type == old_delegation->type) {
 			goto out;
 		}
 		/*
 		 * Deal with broken servers that hand out two
 		 * delegations for the same file.
+		 * Allow for upgrades to a WRITE delegation, but
+		 * nothing else.
 		 */
 		dfprintk(FILE, "%s: server %s handed out "
 				"a duplicate delegation!\n",
 				__func__, clp->cl_hostname);
-		if (delegation->type <= old_delegation->type) {
+		if (delegation->type == old_delegation->type ||
+		    !(delegation->type & FMODE_WRITE)) {
 			freeme = delegation;
 			delegation = NULL;
 			goto out;
@@ -455,17 +456,24 @@
 	rcu_read_unlock();
 }
 
-static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
-{
-	nfs_client_mark_return_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
-}
-
 static void nfs_delegation_run_state_manager(struct nfs_client *clp)
 {
 	if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
 		nfs4_schedule_state_manager(clp);
 }
 
+void nfs_remove_bad_delegation(struct inode *inode)
+{
+	struct nfs_delegation *delegation;
+
+	delegation = nfs_detach_delegation(NFS_I(inode), NFS_SERVER(inode));
+	if (delegation) {
+		nfs_inode_find_state_and_recover(inode, &delegation->stateid);
+		nfs_free_delegation(delegation);
+	}
+}
+EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
+
 /**
  * nfs_expire_all_delegation_types
  * @clp: client to process
@@ -488,18 +496,6 @@
 	nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
 }
 
-/**
- * nfs_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
- * @clp: client to process
- *
- */
-void nfs_handle_cb_pathdown(struct nfs_client *clp)
-{
-	if (clp == NULL)
-		return;
-	nfs_client_mark_return_all_delegations(clp);
-}
-
 static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
 {
 	struct nfs_delegation *delegation;
@@ -531,7 +527,7 @@
 /**
  * nfs_async_inode_return_delegation - asynchronously return a delegation
  * @inode: inode to process
- * @stateid: state ID information from CB_RECALL arguments
+ * @stateid: state ID information
  *
  * Returns zero on success, or a negative errno value.
  */
@@ -545,7 +541,7 @@
 	rcu_read_lock();
 	delegation = rcu_dereference(NFS_I(inode)->delegation);
 
-	if (!clp->cl_mvops->validate_stateid(delegation, stateid)) {
+	if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) {
 		rcu_read_unlock();
 		return -ENOENT;
 	}
@@ -684,21 +680,25 @@
  * nfs4_copy_delegation_stateid - Copy inode's state ID information
  * @dst: stateid data structure to fill in
  * @inode: inode to check
+ * @flags: delegation type requirement
  *
- * Returns one and fills in "dst->data" * if inode had a delegation,
- * otherwise zero is returned.
+ * Returns "true" and fills in "dst->data" * if inode had a delegation,
+ * otherwise "false" is returned.
  */
-int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
+bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode,
+		fmode_t flags)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 	struct nfs_delegation *delegation;
-	int ret = 0;
+	bool ret;
 
+	flags &= FMODE_READ|FMODE_WRITE;
 	rcu_read_lock();
 	delegation = rcu_dereference(nfsi->delegation);
-	if (delegation != NULL) {
-		memcpy(dst->data, delegation->stateid.data, sizeof(dst->data));
-		ret = 1;
+	ret = (delegation != NULL && (delegation->type & flags) == flags);
+	if (ret) {
+		nfs4_stateid_copy(dst, &delegation->stateid);
+		nfs_mark_delegation_referenced(delegation);
 	}
 	rcu_read_unlock();
 	return ret;
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
index d9322e4..cd6a7a8 100644
--- a/fs/nfs/delegation.h
+++ b/fs/nfs/delegation.h
@@ -42,9 +42,9 @@
 void nfs_expire_all_delegations(struct nfs_client *clp);
 void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags);
 void nfs_expire_unreferenced_delegations(struct nfs_client *clp);
-void nfs_handle_cb_pathdown(struct nfs_client *clp);
 int nfs_client_return_marked_delegations(struct nfs_client *clp);
 int nfs_delegations_present(struct nfs_client *clp);
+void nfs_remove_bad_delegation(struct inode *inode);
 
 void nfs_delegation_mark_reclaim(struct nfs_client *clp);
 void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
@@ -53,7 +53,7 @@
 int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync);
 int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid);
 int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl);
-int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
+bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_t flags);
 
 void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
 int nfs_have_delegation(struct inode *inode, fmode_t flags);
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 32aa691..4aaf031 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -207,7 +207,7 @@
 };
 
 struct nfs_cache_array {
-	unsigned int size;
+	int size;
 	int eof_index;
 	u64 last_cookie;
 	struct nfs_cache_array_entry array[0];
@@ -1429,6 +1429,7 @@
 	}
 
 	open_flags = nd->intent.open.flags;
+	attr.ia_valid = 0;
 
 	ctx = create_nfs_open_context(dentry, open_flags);
 	res = ERR_CAST(ctx);
@@ -1437,11 +1438,14 @@
 
 	if (nd->flags & LOOKUP_CREATE) {
 		attr.ia_mode = nd->intent.open.create_mode;
-		attr.ia_valid = ATTR_MODE;
+		attr.ia_valid |= ATTR_MODE;
 		attr.ia_mode &= ~current_umask();
-	} else {
+	} else
 		open_flags &= ~(O_EXCL | O_CREAT);
-		attr.ia_valid = 0;
+
+	if (open_flags & O_TRUNC) {
+		attr.ia_valid |= ATTR_SIZE;
+		attr.ia_size = 0;
 	}
 
 	/* Open the file on the server */
@@ -1495,6 +1499,7 @@
 	struct inode *inode;
 	struct inode *dir;
 	struct nfs_open_context *ctx;
+	struct iattr attr;
 	int openflags, ret = 0;
 
 	if (nd->flags & LOOKUP_RCU)
@@ -1523,19 +1528,27 @@
 	/* We cannot do exclusive creation on a positive dentry */
 	if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
 		goto no_open_dput;
-	/* We can't create new files, or truncate existing ones here */
-	openflags &= ~(O_CREAT|O_EXCL|O_TRUNC);
+	/* We can't create new files here */
+	openflags &= ~(O_CREAT|O_EXCL);
 
 	ctx = create_nfs_open_context(dentry, openflags);
 	ret = PTR_ERR(ctx);
 	if (IS_ERR(ctx))
 		goto out;
+
+	attr.ia_valid = 0;
+	if (openflags & O_TRUNC) {
+		attr.ia_valid |= ATTR_SIZE;
+		attr.ia_size = 0;
+		nfs_wb_all(inode);
+	}
+
 	/*
 	 * Note: we're not holding inode->i_mutex and so may be racing with
 	 * operations that change the directory. We therefore save the
 	 * change attribute *before* we do the RPC call.
 	 */
-	inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, NULL);
+	inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr);
 	if (IS_ERR(inode)) {
 		ret = PTR_ERR(inode);
 		switch (ret) {
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 1940f1a..481be7f 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -51,7 +51,6 @@
 #include <linux/nfs_page.h>
 #include <linux/sunrpc/clnt.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/atomic.h>
 
@@ -265,9 +264,7 @@
 }
 
 static const struct rpc_call_ops nfs_read_direct_ops = {
-#if defined(CONFIG_NFS_V4_1)
 	.rpc_call_prepare = nfs_read_prepare,
-#endif /* CONFIG_NFS_V4_1 */
 	.rpc_call_done = nfs_direct_read_result,
 	.rpc_release = nfs_direct_read_release,
 };
@@ -554,9 +551,7 @@
 }
 
 static const struct rpc_call_ops nfs_commit_direct_ops = {
-#if defined(CONFIG_NFS_V4_1)
 	.rpc_call_prepare = nfs_write_prepare,
-#endif /* CONFIG_NFS_V4_1 */
 	.rpc_call_done = nfs_direct_commit_result,
 	.rpc_release = nfs_direct_commit_release,
 };
@@ -696,9 +691,7 @@
 }
 
 static const struct rpc_call_ops nfs_write_direct_ops = {
-#if defined(CONFIG_NFS_V4_1)
 	.rpc_call_prepare = nfs_write_prepare,
-#endif /* CONFIG_NFS_V4_1 */
 	.rpc_call_done = nfs_direct_write_result,
 	.rpc_release = nfs_direct_write_release,
 };
diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c
index a6e711a..b3924b8 100644
--- a/fs/nfs/dns_resolve.c
+++ b/fs/nfs/dns_resolve.c
@@ -10,8 +10,9 @@
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/dns_resolver.h>
+#include "dns_resolve.h"
 
-ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
+ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen,
 		struct sockaddr *sa, size_t salen)
 {
 	ssize_t ret;
@@ -20,7 +21,7 @@
 
 	ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL);
 	if (ip_len > 0)
-		ret = rpc_pton(ip_addr, ip_len, sa, salen);
+		ret = rpc_pton(net, ip_addr, ip_len, sa, salen);
 	else
 		ret = -ESRCH;
 	kfree(ip_addr);
@@ -40,15 +41,15 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/cache.h>
 #include <linux/sunrpc/svcauth.h>
+#include <linux/sunrpc/rpc_pipe_fs.h>
 
 #include "dns_resolve.h"
 #include "cache_lib.h"
+#include "netns.h"
 
 #define NFS_DNS_HASHBITS 4
 #define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS)
 
-static struct cache_head *nfs_dns_table[NFS_DNS_HASHTBL_SIZE];
-
 struct nfs_dns_ent {
 	struct cache_head h;
 
@@ -224,7 +225,7 @@
 	len = qword_get(&buf, buf1, sizeof(buf1));
 	if (len <= 0)
 		goto out;
-	key.addrlen = rpc_pton(buf1, len,
+	key.addrlen = rpc_pton(cd->net, buf1, len,
 			(struct sockaddr *)&key.addr,
 			sizeof(key.addr));
 
@@ -259,21 +260,6 @@
 	return ret;
 }
 
-static struct cache_detail nfs_dns_resolve = {
-	.owner = THIS_MODULE,
-	.hash_size = NFS_DNS_HASHTBL_SIZE,
-	.hash_table = nfs_dns_table,
-	.name = "dns_resolve",
-	.cache_put = nfs_dns_ent_put,
-	.cache_upcall = nfs_dns_upcall,
-	.cache_parse = nfs_dns_parse,
-	.cache_show = nfs_dns_show,
-	.match = nfs_dns_match,
-	.init = nfs_dns_ent_init,
-	.update = nfs_dns_ent_update,
-	.alloc = nfs_dns_ent_alloc,
-};
-
 static int do_cache_lookup(struct cache_detail *cd,
 		struct nfs_dns_ent *key,
 		struct nfs_dns_ent **item,
@@ -336,8 +322,8 @@
 	return ret;
 }
 
-ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
-		struct sockaddr *sa, size_t salen)
+ssize_t nfs_dns_resolve_name(struct net *net, char *name,
+		size_t namelen, struct sockaddr *sa, size_t salen)
 {
 	struct nfs_dns_ent key = {
 		.hostname = name,
@@ -345,28 +331,118 @@
 	};
 	struct nfs_dns_ent *item = NULL;
 	ssize_t ret;
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
 
-	ret = do_cache_lookup_wait(&nfs_dns_resolve, &key, &item);
+	ret = do_cache_lookup_wait(nn->nfs_dns_resolve, &key, &item);
 	if (ret == 0) {
 		if (salen >= item->addrlen) {
 			memcpy(sa, &item->addr, item->addrlen);
 			ret = item->addrlen;
 		} else
 			ret = -EOVERFLOW;
-		cache_put(&item->h, &nfs_dns_resolve);
+		cache_put(&item->h, nn->nfs_dns_resolve);
 	} else if (ret == -ENOENT)
 		ret = -ESRCH;
 	return ret;
 }
 
+int nfs_dns_resolver_cache_init(struct net *net)
+{
+	int err = -ENOMEM;
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
+	struct cache_detail *cd;
+	struct cache_head **tbl;
+
+	cd = kzalloc(sizeof(struct cache_detail), GFP_KERNEL);
+	if (cd == NULL)
+		goto err_cd;
+
+	tbl = kzalloc(NFS_DNS_HASHTBL_SIZE * sizeof(struct cache_head *),
+			GFP_KERNEL);
+	if (tbl == NULL)
+		goto err_tbl;
+
+	cd->owner = THIS_MODULE,
+	cd->hash_size = NFS_DNS_HASHTBL_SIZE,
+	cd->hash_table = tbl,
+	cd->name = "dns_resolve",
+	cd->cache_put = nfs_dns_ent_put,
+	cd->cache_upcall = nfs_dns_upcall,
+	cd->cache_parse = nfs_dns_parse,
+	cd->cache_show = nfs_dns_show,
+	cd->match = nfs_dns_match,
+	cd->init = nfs_dns_ent_init,
+	cd->update = nfs_dns_ent_update,
+	cd->alloc = nfs_dns_ent_alloc,
+
+	nfs_cache_init(cd);
+	err = nfs_cache_register_net(net, cd);
+	if (err)
+		goto err_reg;
+	nn->nfs_dns_resolve = cd;
+	return 0;
+
+err_reg:
+	nfs_cache_destroy(cd);
+	kfree(cd->hash_table);
+err_tbl:
+	kfree(cd);
+err_cd:
+	return err;
+}
+
+void nfs_dns_resolver_cache_destroy(struct net *net)
+{
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
+	struct cache_detail *cd = nn->nfs_dns_resolve;
+
+	nfs_cache_unregister_net(net, cd);
+	nfs_cache_destroy(cd);
+	kfree(cd->hash_table);
+	kfree(cd);
+}
+
+static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
+			   void *ptr)
+{
+	struct super_block *sb = ptr;
+	struct net *net = sb->s_fs_info;
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
+	struct cache_detail *cd = nn->nfs_dns_resolve;
+	int ret = 0;
+
+	if (cd == NULL)
+		return 0;
+
+	if (!try_module_get(THIS_MODULE))
+		return 0;
+
+	switch (event) {
+	case RPC_PIPEFS_MOUNT:
+		ret = nfs_cache_register_sb(sb, cd);
+		break;
+	case RPC_PIPEFS_UMOUNT:
+		nfs_cache_unregister_sb(sb, cd);
+		break;
+	default:
+		ret = -ENOTSUPP;
+		break;
+	}
+	module_put(THIS_MODULE);
+	return ret;
+}
+
+static struct notifier_block nfs_dns_resolver_block = {
+	.notifier_call	= rpc_pipefs_event,
+};
+
 int nfs_dns_resolver_init(void)
 {
-	return nfs_cache_register(&nfs_dns_resolve);
+	return rpc_pipefs_notifier_register(&nfs_dns_resolver_block);
 }
 
 void nfs_dns_resolver_destroy(void)
 {
-	nfs_cache_unregister(&nfs_dns_resolve);
+	rpc_pipefs_notifier_unregister(&nfs_dns_resolver_block);
 }
-
 #endif
diff --git a/fs/nfs/dns_resolve.h b/fs/nfs/dns_resolve.h
index 199bb55..2e4f596 100644
--- a/fs/nfs/dns_resolve.h
+++ b/fs/nfs/dns_resolve.h
@@ -15,12 +15,22 @@
 
 static inline void nfs_dns_resolver_destroy(void)
 {}
+
+static inline int nfs_dns_resolver_cache_init(struct net *net)
+{
+	return 0;
+}
+
+static inline void nfs_dns_resolver_cache_destroy(struct net *net)
+{}
 #else
 extern int nfs_dns_resolver_init(void);
 extern void nfs_dns_resolver_destroy(void);
+extern int nfs_dns_resolver_cache_init(struct net *net);
+extern void nfs_dns_resolver_cache_destroy(struct net *net);
 #endif
 
-extern ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
-		struct sockaddr *sa, size_t salen);
+extern ssize_t nfs_dns_resolve_name(struct net *net, char *name,
+		size_t namelen,	struct sockaddr *sa, size_t salen);
 
 #endif
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index c43a452..aa9b709 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -30,7 +30,6 @@
 #include <linux/swap.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #include "delegation.h"
 #include "internal.h"
@@ -530,6 +529,8 @@
 	if (mapping != dentry->d_inode->i_mapping)
 		goto out_unlock;
 
+	wait_on_page_writeback(page);
+
 	pagelen = nfs_page_length(page);
 	if (pagelen == 0)
 		goto out_unlock;
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c
index 419119c..ae65c16 100644
--- a/fs/nfs/fscache.c
+++ b/fs/nfs/fscache.c
@@ -327,7 +327,7 @@
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 	struct nfs_server *nfss = NFS_SERVER(inode);
-	struct fscache_cookie *old = nfsi->fscache;
+	NFS_IFDEBUG(struct fscache_cookie *old = nfsi->fscache);
 
 	nfs_fscache_inode_lock(inode);
 	if (nfsi->fscache) {
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index dcb6154..4ca6f5c 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -32,7 +32,6 @@
 #include <linux/namei.h>
 #include <linux/security.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 #include "nfs4_fs.h"
@@ -49,11 +48,9 @@
 {
 	/* The mntroot acts as the dummy root dentry for this superblock */
 	if (sb->s_root == NULL) {
-		sb->s_root = d_alloc_root(inode);
-		if (sb->s_root == NULL) {
-			iput(inode);
+		sb->s_root = d_make_root(inode);
+		if (sb->s_root == NULL)
 			return -ENOMEM;
-		}
 		ihold(inode);
 		/*
 		 * Ensure that this dentry is invisible to d_find_alias().
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index a1bbf77..b7f348b 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -34,11 +34,29 @@
  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
+#include <linux/parser.h>
+#include <linux/fs.h>
 #include <linux/nfs_idmap.h>
+#include <net/net_namespace.h>
+#include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfs_fs_sb.h>
+#include <linux/key.h>
+#include <linux/keyctl.h>
+#include <linux/key-type.h>
+#include <keys/user-type.h>
+#include <linux/module.h>
+
+#include "internal.h"
+#include "netns.h"
+
+#define NFS_UINT_MAXLEN 11
+
+/* Default cache timeout is 10 minutes */
+unsigned int nfs_idmap_cache_timeout = 600;
+static const struct cred *id_resolver_cache;
+static struct key_type key_type_id_resolver_legacy;
+
 
 /**
  * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
@@ -142,24 +160,7 @@
 	return snprintf(buf, buflen, "%u", id);
 }
 
-#ifdef CONFIG_NFS_USE_NEW_IDMAPPER
-
-#include <linux/cred.h>
-#include <linux/sunrpc/sched.h>
-#include <linux/nfs4.h>
-#include <linux/nfs_fs_sb.h>
-#include <linux/keyctl.h>
-#include <linux/key-type.h>
-#include <linux/rcupdate.h>
-#include <linux/err.h>
-
-#include <keys/user-type.h>
-
-#define NFS_UINT_MAXLEN 11
-
-const struct cred *id_resolver_cache;
-
-struct key_type key_type_id_resolver = {
+static struct key_type key_type_id_resolver = {
 	.name		= "id_resolver",
 	.instantiate	= user_instantiate,
 	.match		= user_match,
@@ -169,13 +170,14 @@
 	.read		= user_read,
 };
 
-int nfs_idmap_init(void)
+static int nfs_idmap_init_keyring(void)
 {
 	struct cred *cred;
 	struct key *keyring;
 	int ret = 0;
 
-	printk(KERN_NOTICE "Registering the %s key type\n", key_type_id_resolver.name);
+	printk(KERN_NOTICE "NFS: Registering the %s key type\n",
+		key_type_id_resolver.name);
 
 	cred = prepare_kernel_cred(NULL);
 	if (!cred)
@@ -211,7 +213,7 @@
 	return ret;
 }
 
-void nfs_idmap_quit(void)
+static void nfs_idmap_quit_keyring(void)
 {
 	key_revoke(id_resolver_cache->thread_keyring);
 	unregister_key_type(&key_type_id_resolver);
@@ -246,8 +248,10 @@
 	return desclen;
 }
 
-static ssize_t nfs_idmap_request_key(const char *name, size_t namelen,
-		const char *type, void *data, size_t data_size)
+static ssize_t nfs_idmap_request_key(struct key_type *key_type,
+				     const char *name, size_t namelen,
+				     const char *type, void *data,
+				     size_t data_size, struct idmap *idmap)
 {
 	const struct cred *saved_cred;
 	struct key *rkey;
@@ -260,8 +264,12 @@
 		goto out;
 
 	saved_cred = override_creds(id_resolver_cache);
-	rkey = request_key(&key_type_id_resolver, desc, "");
+	if (idmap)
+		rkey = request_key_with_auxdata(key_type, desc, "", 0, idmap);
+	else
+		rkey = request_key(&key_type_id_resolver, desc, "");
 	revert_creds(saved_cred);
+
 	kfree(desc);
 	if (IS_ERR(rkey)) {
 		ret = PTR_ERR(rkey);
@@ -294,31 +302,46 @@
 	return ret;
 }
 
+static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
+				 const char *type, void *data,
+				 size_t data_size, struct idmap *idmap)
+{
+	ssize_t ret = nfs_idmap_request_key(&key_type_id_resolver,
+					    name, namelen, type, data,
+					    data_size, NULL);
+	if (ret < 0) {
+		ret = nfs_idmap_request_key(&key_type_id_resolver_legacy,
+					    name, namelen, type, data,
+					    data_size, idmap);
+	}
+	return ret;
+}
 
 /* ID -> Name */
-static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, size_t buflen)
+static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf,
+				     size_t buflen, struct idmap *idmap)
 {
 	char id_str[NFS_UINT_MAXLEN];
 	int id_len;
 	ssize_t ret;
 
 	id_len = snprintf(id_str, sizeof(id_str), "%u", id);
-	ret = nfs_idmap_request_key(id_str, id_len, type, buf, buflen);
+	ret = nfs_idmap_get_key(id_str, id_len, type, buf, buflen, idmap);
 	if (ret < 0)
 		return -EINVAL;
 	return ret;
 }
 
 /* Name -> ID */
-static int nfs_idmap_lookup_id(const char *name, size_t namelen,
-				const char *type, __u32 *id)
+static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *type,
+			       __u32 *id, struct idmap *idmap)
 {
 	char id_str[NFS_UINT_MAXLEN];
 	long id_long;
 	ssize_t data_size;
 	int ret = 0;
 
-	data_size = nfs_idmap_request_key(name, namelen, type, id_str, NFS_UINT_MAXLEN);
+	data_size = nfs_idmap_get_key(name, namelen, type, id_str, NFS_UINT_MAXLEN, idmap);
 	if (data_size <= 0) {
 		ret = -EINVAL;
 	} else {
@@ -328,114 +351,103 @@
 	return ret;
 }
 
-int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
-{
-	if (nfs_map_string_to_numeric(name, namelen, uid))
-		return 0;
-	return nfs_idmap_lookup_id(name, namelen, "uid", uid);
-}
-
-int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid)
-{
-	if (nfs_map_string_to_numeric(name, namelen, gid))
-		return 0;
-	return nfs_idmap_lookup_id(name, namelen, "gid", gid);
-}
-
-int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
-{
-	int ret = -EINVAL;
-
-	if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
-		ret = nfs_idmap_lookup_name(uid, "user", buf, buflen);
-	if (ret < 0)
-		ret = nfs_map_numeric_to_string(uid, buf, buflen);
-	return ret;
-}
-int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen)
-{
-	int ret = -EINVAL;
-
-	if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
-		ret = nfs_idmap_lookup_name(gid, "group", buf, buflen);
-	if (ret < 0)
-		ret = nfs_map_numeric_to_string(gid, buf, buflen);
-	return ret;
-}
-
-#else  /* CONFIG_NFS_USE_NEW_IDMAPPER not defined */
-
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/init.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/sched.h>
-#include <linux/sunrpc/clnt.h>
-#include <linux/workqueue.h>
-#include <linux/sunrpc/rpc_pipe_fs.h>
-
-#include <linux/nfs_fs.h>
-
-#include "nfs4_fs.h"
-
-#define IDMAP_HASH_SZ          128
-
-/* Default cache timeout is 10 minutes */
-unsigned int nfs_idmap_cache_timeout = 600 * HZ;
-
-static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
-{
-	char *endp;
-	int num = simple_strtol(val, &endp, 0);
-	int jif = num * HZ;
-	if (endp == val || *endp || num < 0 || jif < num)
-		return -EINVAL;
-	*((int *)kp->arg) = jif;
-	return 0;
-}
-
-module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
-		 &nfs_idmap_cache_timeout, 0644);
-
-struct idmap_hashent {
-	unsigned long		ih_expires;
-	__u32			ih_id;
-	size_t			ih_namelen;
-	char			ih_name[IDMAP_NAMESZ];
-};
-
-struct idmap_hashtable {
-	__u8			h_type;
-	struct idmap_hashent	h_entries[IDMAP_HASH_SZ];
-};
+/* idmap classic begins here */
+module_param(nfs_idmap_cache_timeout, int, 0644);
 
 struct idmap {
-	struct dentry		*idmap_dentry;
-	wait_queue_head_t	idmap_wq;
-	struct idmap_msg	idmap_im;
-	struct mutex		idmap_lock;	/* Serializes upcalls */
-	struct mutex		idmap_im_lock;	/* Protects the hashtable */
-	struct idmap_hashtable	idmap_user_hash;
-	struct idmap_hashtable	idmap_group_hash;
+	struct rpc_pipe		*idmap_pipe;
+	struct key_construction	*idmap_key_cons;
 };
 
+enum {
+	Opt_find_uid, Opt_find_gid, Opt_find_user, Opt_find_group, Opt_find_err
+};
+
+static const match_table_t nfs_idmap_tokens = {
+	{ Opt_find_uid, "uid:%s" },
+	{ Opt_find_gid, "gid:%s" },
+	{ Opt_find_user, "user:%s" },
+	{ Opt_find_group, "group:%s" },
+	{ Opt_find_err, NULL }
+};
+
+static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *);
 static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
 				   size_t);
 static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
 
-static unsigned int fnvhash32(const void *, size_t);
-
 static const struct rpc_pipe_ops idmap_upcall_ops = {
 	.upcall		= rpc_pipe_generic_upcall,
 	.downcall	= idmap_pipe_downcall,
 	.destroy_msg	= idmap_pipe_destroy_msg,
 };
 
+static struct key_type key_type_id_resolver_legacy = {
+	.name		= "id_resolver",
+	.instantiate	= user_instantiate,
+	.match		= user_match,
+	.revoke		= user_revoke,
+	.destroy	= user_destroy,
+	.describe	= user_describe,
+	.read		= user_read,
+	.request_key	= nfs_idmap_legacy_upcall,
+};
+
+static void __nfs_idmap_unregister(struct rpc_pipe *pipe)
+{
+	if (pipe->dentry)
+		rpc_unlink(pipe->dentry);
+}
+
+static int __nfs_idmap_register(struct dentry *dir,
+				     struct idmap *idmap,
+				     struct rpc_pipe *pipe)
+{
+	struct dentry *dentry;
+
+	dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe);
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
+	pipe->dentry = dentry;
+	return 0;
+}
+
+static void nfs_idmap_unregister(struct nfs_client *clp,
+				      struct rpc_pipe *pipe)
+{
+	struct net *net = clp->net;
+	struct super_block *pipefs_sb;
+
+	pipefs_sb = rpc_get_sb_net(net);
+	if (pipefs_sb) {
+		__nfs_idmap_unregister(pipe);
+		rpc_put_sb_net(net);
+	}
+}
+
+static int nfs_idmap_register(struct nfs_client *clp,
+				   struct idmap *idmap,
+				   struct rpc_pipe *pipe)
+{
+	struct net *net = clp->net;
+	struct super_block *pipefs_sb;
+	int err = 0;
+
+	pipefs_sb = rpc_get_sb_net(net);
+	if (pipefs_sb) {
+		if (clp->cl_rpcclient->cl_dentry)
+			err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry,
+						   idmap, pipe);
+		rpc_put_sb_net(net);
+	}
+	return err;
+}
+
 int
 nfs_idmap_new(struct nfs_client *clp)
 {
 	struct idmap *idmap;
+	struct rpc_pipe *pipe;
 	int error;
 
 	BUG_ON(clp->cl_idmap != NULL);
@@ -444,19 +456,19 @@
 	if (idmap == NULL)
 		return -ENOMEM;
 
-	idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry,
-			"idmap", idmap, &idmap_upcall_ops, 0);
-	if (IS_ERR(idmap->idmap_dentry)) {
-		error = PTR_ERR(idmap->idmap_dentry);
+	pipe = rpc_mkpipe_data(&idmap_upcall_ops, 0);
+	if (IS_ERR(pipe)) {
+		error = PTR_ERR(pipe);
 		kfree(idmap);
 		return error;
 	}
-
-	mutex_init(&idmap->idmap_lock);
-	mutex_init(&idmap->idmap_im_lock);
-	init_waitqueue_head(&idmap->idmap_wq);
-	idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER;
-	idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP;
+	error = nfs_idmap_register(clp, idmap, pipe);
+	if (error) {
+		rpc_destroy_pipe_data(pipe);
+		kfree(idmap);
+		return error;
+	}
+	idmap->idmap_pipe = pipe;
 
 	clp->cl_idmap = idmap;
 	return 0;
@@ -469,211 +481,220 @@
 
 	if (!idmap)
 		return;
-	rpc_unlink(idmap->idmap_dentry);
+	nfs_idmap_unregister(clp, idmap->idmap_pipe);
+	rpc_destroy_pipe_data(idmap->idmap_pipe);
 	clp->cl_idmap = NULL;
 	kfree(idmap);
 }
 
-/*
- * Helper routines for manipulating the hashtable
- */
-static inline struct idmap_hashent *
-idmap_name_hash(struct idmap_hashtable* h, const char *name, size_t len)
+static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event,
+			      struct super_block *sb)
 {
-	return &h->h_entries[fnvhash32(name, len) % IDMAP_HASH_SZ];
+	int err = 0;
+
+	switch (event) {
+	case RPC_PIPEFS_MOUNT:
+		BUG_ON(clp->cl_rpcclient->cl_dentry == NULL);
+		err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry,
+						clp->cl_idmap,
+						clp->cl_idmap->idmap_pipe);
+		break;
+	case RPC_PIPEFS_UMOUNT:
+		if (clp->cl_idmap->idmap_pipe) {
+			struct dentry *parent;
+
+			parent = clp->cl_idmap->idmap_pipe->dentry->d_parent;
+			__nfs_idmap_unregister(clp->cl_idmap->idmap_pipe);
+			/*
+			 * Note: This is a dirty hack. SUNRPC hook has been
+			 * called already but simple_rmdir() call for the
+			 * directory returned with error because of idmap pipe
+			 * inside. Thus now we have to remove this directory
+			 * here.
+			 */
+			if (rpc_rmdir(parent))
+				printk(KERN_ERR "NFS: %s: failed to remove "
+					"clnt dir!\n", __func__);
+		}
+		break;
+	default:
+		printk(KERN_ERR "NFS: %s: unknown event: %ld\n", __func__,
+			event);
+		return -ENOTSUPP;
+	}
+	return err;
 }
 
-static struct idmap_hashent *
-idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len)
+static struct nfs_client *nfs_get_client_for_event(struct net *net, int event)
 {
-	struct idmap_hashent *he = idmap_name_hash(h, name, len);
+	struct nfs_net *nn = net_generic(net, nfs_net_id);
+	struct dentry *cl_dentry;
+	struct nfs_client *clp;
 
-	if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0)
-		return NULL;
-	if (time_after(jiffies, he->ih_expires))
-		return NULL;
-	return he;
+	spin_lock(&nn->nfs_client_lock);
+	list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
+		if (clp->rpc_ops != &nfs_v4_clientops)
+			continue;
+		cl_dentry = clp->cl_idmap->idmap_pipe->dentry;
+		if (((event == RPC_PIPEFS_MOUNT) && cl_dentry) ||
+		    ((event == RPC_PIPEFS_UMOUNT) && !cl_dentry))
+			continue;
+		atomic_inc(&clp->cl_count);
+		spin_unlock(&nn->nfs_client_lock);
+		return clp;
+	}
+	spin_unlock(&nn->nfs_client_lock);
+	return NULL;
 }
 
-static inline struct idmap_hashent *
-idmap_id_hash(struct idmap_hashtable* h, __u32 id)
+static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
+			    void *ptr)
 {
-	return &h->h_entries[fnvhash32(&id, sizeof(id)) % IDMAP_HASH_SZ];
-}
+	struct super_block *sb = ptr;
+	struct nfs_client *clp;
+	int error = 0;
 
-static struct idmap_hashent *
-idmap_lookup_id(struct idmap_hashtable *h, __u32 id)
-{
-	struct idmap_hashent *he = idmap_id_hash(h, id);
-	if (he->ih_id != id || he->ih_namelen == 0)
-		return NULL;
-	if (time_after(jiffies, he->ih_expires))
-		return NULL;
-	return he;
-}
-
-/*
- * Routines for allocating new entries in the hashtable.
- * For now, we just have 1 entry per bucket, so it's all
- * pretty trivial.
- */
-static inline struct idmap_hashent *
-idmap_alloc_name(struct idmap_hashtable *h, char *name, size_t len)
-{
-	return idmap_name_hash(h, name, len);
-}
-
-static inline struct idmap_hashent *
-idmap_alloc_id(struct idmap_hashtable *h, __u32 id)
-{
-	return idmap_id_hash(h, id);
-}
-
-static void
-idmap_update_entry(struct idmap_hashent *he, const char *name,
-		size_t namelen, __u32 id)
-{
-	he->ih_id = id;
-	memcpy(he->ih_name, name, namelen);
-	he->ih_name[namelen] = '\0';
-	he->ih_namelen = namelen;
-	he->ih_expires = jiffies + nfs_idmap_cache_timeout;
-}
-
-/*
- * Name -> ID
- */
-static int
-nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h,
-		const char *name, size_t namelen, __u32 *id)
-{
-	struct rpc_pipe_msg msg;
-	struct idmap_msg *im;
-	struct idmap_hashent *he;
-	DECLARE_WAITQUEUE(wq, current);
-	int ret = -EIO;
-
-	im = &idmap->idmap_im;
-
-	/*
-	 * String sanity checks
-	 * Note that the userland daemon expects NUL terminated strings
-	 */
-	for (;;) {
-		if (namelen == 0)
-			return -EINVAL;
-		if (name[namelen-1] != '\0')
+	while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) {
+		error = __rpc_pipefs_event(clp, event, sb);
+		nfs_put_client(clp);
+		if (error)
 			break;
-		namelen--;
 	}
-	if (namelen >= IDMAP_NAMESZ)
-		return -EINVAL;
+	return error;
+}
 
-	mutex_lock(&idmap->idmap_lock);
-	mutex_lock(&idmap->idmap_im_lock);
+#define PIPEFS_NFS_PRIO		1
 
-	he = idmap_lookup_name(h, name, namelen);
-	if (he != NULL) {
-		*id = he->ih_id;
-		ret = 0;
+static struct notifier_block nfs_idmap_block = {
+	.notifier_call	= rpc_pipefs_event,
+	.priority	= SUNRPC_PIPEFS_NFS_PRIO,
+};
+
+int nfs_idmap_init(void)
+{
+	int ret;
+	ret = nfs_idmap_init_keyring();
+	if (ret != 0)
 		goto out;
-	}
-
-	memset(im, 0, sizeof(*im));
-	memcpy(im->im_name, name, namelen);
-
-	im->im_type = h->h_type;
-	im->im_conv = IDMAP_CONV_NAMETOID;
-
-	memset(&msg, 0, sizeof(msg));
-	msg.data = im;
-	msg.len = sizeof(*im);
-
-	add_wait_queue(&idmap->idmap_wq, &wq);
-	if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) {
-		remove_wait_queue(&idmap->idmap_wq, &wq);
-		goto out;
-	}
-
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	mutex_unlock(&idmap->idmap_im_lock);
-	schedule();
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&idmap->idmap_wq, &wq);
-	mutex_lock(&idmap->idmap_im_lock);
-
-	if (im->im_status & IDMAP_STATUS_SUCCESS) {
-		*id = im->im_id;
-		ret = 0;
-	}
-
- out:
-	memset(im, 0, sizeof(*im));
-	mutex_unlock(&idmap->idmap_im_lock);
-	mutex_unlock(&idmap->idmap_lock);
+	ret = rpc_pipefs_notifier_register(&nfs_idmap_block);
+	if (ret != 0)
+		nfs_idmap_quit_keyring();
+out:
 	return ret;
 }
 
-/*
- * ID -> Name
- */
-static int
-nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h,
-		__u32 id, char *name)
+void nfs_idmap_quit(void)
 {
-	struct rpc_pipe_msg msg;
+	rpc_pipefs_notifier_unregister(&nfs_idmap_block);
+	nfs_idmap_quit_keyring();
+}
+
+static int nfs_idmap_prepare_message(char *desc, struct idmap_msg *im,
+				     struct rpc_pipe_msg *msg)
+{
+	substring_t substr;
+	int token, ret;
+
+	memset(im,  0, sizeof(*im));
+	memset(msg, 0, sizeof(*msg));
+
+	im->im_type = IDMAP_TYPE_GROUP;
+	token = match_token(desc, nfs_idmap_tokens, &substr);
+
+	switch (token) {
+	case Opt_find_uid:
+		im->im_type = IDMAP_TYPE_USER;
+	case Opt_find_gid:
+		im->im_conv = IDMAP_CONV_NAMETOID;
+		ret = match_strlcpy(im->im_name, &substr, IDMAP_NAMESZ);
+		break;
+
+	case Opt_find_user:
+		im->im_type = IDMAP_TYPE_USER;
+	case Opt_find_group:
+		im->im_conv = IDMAP_CONV_IDTONAME;
+		ret = match_int(&substr, &im->im_id);
+		break;
+
+	default:
+		ret = -EINVAL;
+		goto out;
+	}
+
+	msg->data = im;
+	msg->len  = sizeof(struct idmap_msg);
+
+out:
+	return ret;
+}
+
+static int nfs_idmap_legacy_upcall(struct key_construction *cons,
+				   const char *op,
+				   void *aux)
+{
+	struct rpc_pipe_msg *msg;
 	struct idmap_msg *im;
-	struct idmap_hashent *he;
-	DECLARE_WAITQUEUE(wq, current);
-	int ret = -EIO;
-	unsigned int len;
+	struct idmap *idmap = (struct idmap *)aux;
+	struct key *key = cons->key;
+	int ret;
 
-	im = &idmap->idmap_im;
-
-	mutex_lock(&idmap->idmap_lock);
-	mutex_lock(&idmap->idmap_im_lock);
-
-	he = idmap_lookup_id(h, id);
-	if (he) {
-		memcpy(name, he->ih_name, he->ih_namelen);
-		ret = he->ih_namelen;
-		goto out;
+	/* msg and im are freed in idmap_pipe_destroy_msg */
+	msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+	if (IS_ERR(msg)) {
+		ret = PTR_ERR(msg);
+		goto out0;
 	}
 
-	memset(im, 0, sizeof(*im));
-	im->im_type = h->h_type;
-	im->im_conv = IDMAP_CONV_IDTONAME;
-	im->im_id = id;
-
-	memset(&msg, 0, sizeof(msg));
-	msg.data = im;
-	msg.len = sizeof(*im);
-
-	add_wait_queue(&idmap->idmap_wq, &wq);
-
-	if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) {
-		remove_wait_queue(&idmap->idmap_wq, &wq);
-		goto out;
+	im = kmalloc(sizeof(*im), GFP_KERNEL);
+	if (IS_ERR(im)) {
+		ret = PTR_ERR(im);
+		goto out1;
 	}
 
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	mutex_unlock(&idmap->idmap_im_lock);
-	schedule();
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&idmap->idmap_wq, &wq);
-	mutex_lock(&idmap->idmap_im_lock);
+	ret = nfs_idmap_prepare_message(key->description, im, msg);
+	if (ret < 0)
+		goto out2;
 
-	if (im->im_status & IDMAP_STATUS_SUCCESS) {
-		if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0)
-			goto out;
-		memcpy(name, im->im_name, len);
-		ret = len;
+	idmap->idmap_key_cons = cons;
+
+	ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
+	if (ret < 0)
+		goto out2;
+
+	return ret;
+
+out2:
+	kfree(im);
+out1:
+	kfree(msg);
+out0:
+	key_revoke(cons->key);
+	key_revoke(cons->authkey);
+	return ret;
+}
+
+static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data)
+{
+	return key_instantiate_and_link(key, data, strlen(data) + 1,
+					id_resolver_cache->thread_keyring,
+					authkey);
+}
+
+static int nfs_idmap_read_message(struct idmap_msg *im, struct key *key, struct key *authkey)
+{
+	char id_str[NFS_UINT_MAXLEN];
+	int ret = -EINVAL;
+
+	switch (im->im_conv) {
+	case IDMAP_CONV_NAMETOID:
+		sprintf(id_str, "%d", im->im_id);
+		ret = nfs_idmap_instantiate(key, authkey, id_str);
+		break;
+	case IDMAP_CONV_IDTONAME:
+		ret = nfs_idmap_instantiate(key, authkey, im->im_name);
+		break;
 	}
 
- out:
-	memset(im, 0, sizeof(*im));
-	mutex_unlock(&idmap->idmap_im_lock);
-	mutex_unlock(&idmap->idmap_lock);
 	return ret;
 }
 
@@ -682,115 +703,51 @@
 {
 	struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode);
 	struct idmap *idmap = (struct idmap *)rpci->private;
-	struct idmap_msg im_in, *im = &idmap->idmap_im;
-	struct idmap_hashtable *h;
-	struct idmap_hashent *he = NULL;
+	struct key_construction *cons = idmap->idmap_key_cons;
+	struct idmap_msg im;
 	size_t namelen_in;
 	int ret;
 
-	if (mlen != sizeof(im_in))
-		return -ENOSPC;
-
-	if (copy_from_user(&im_in, src, mlen) != 0)
-		return -EFAULT;
-
-	mutex_lock(&idmap->idmap_im_lock);
-
-	ret = mlen;
-	im->im_status = im_in.im_status;
-	/* If we got an error, terminate now, and wake up pending upcalls */
-	if (!(im_in.im_status & IDMAP_STATUS_SUCCESS)) {
-		wake_up(&idmap->idmap_wq);
+	if (mlen != sizeof(im)) {
+		ret = -ENOSPC;
 		goto out;
 	}
 
-	/* Sanity checking of strings */
-	ret = -EINVAL;
-	namelen_in = strnlen(im_in.im_name, IDMAP_NAMESZ);
-	if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ)
-		goto out;
-
-	switch (im_in.im_type) {
-		case IDMAP_TYPE_USER:
-			h = &idmap->idmap_user_hash;
-			break;
-		case IDMAP_TYPE_GROUP:
-			h = &idmap->idmap_group_hash;
-			break;
-		default:
-			goto out;
-	}
-
-	switch (im_in.im_conv) {
-	case IDMAP_CONV_IDTONAME:
-		/* Did we match the current upcall? */
-		if (im->im_conv == IDMAP_CONV_IDTONAME
-				&& im->im_type == im_in.im_type
-				&& im->im_id == im_in.im_id) {
-			/* Yes: copy string, including the terminating '\0'  */
-			memcpy(im->im_name, im_in.im_name, namelen_in);
-			im->im_name[namelen_in] = '\0';
-			wake_up(&idmap->idmap_wq);
-		}
-		he = idmap_alloc_id(h, im_in.im_id);
-		break;
-	case IDMAP_CONV_NAMETOID:
-		/* Did we match the current upcall? */
-		if (im->im_conv == IDMAP_CONV_NAMETOID
-				&& im->im_type == im_in.im_type
-				&& strnlen(im->im_name, IDMAP_NAMESZ) == namelen_in
-				&& memcmp(im->im_name, im_in.im_name, namelen_in) == 0) {
-			im->im_id = im_in.im_id;
-			wake_up(&idmap->idmap_wq);
-		}
-		he = idmap_alloc_name(h, im_in.im_name, namelen_in);
-		break;
-	default:
+	if (copy_from_user(&im, src, mlen) != 0) {
+		ret = -EFAULT;
 		goto out;
 	}
 
-	/* If the entry is valid, also copy it to the cache */
-	if (he != NULL)
-		idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id);
-	ret = mlen;
+	if (!(im.im_status & IDMAP_STATUS_SUCCESS)) {
+		ret = mlen;
+		complete_request_key(idmap->idmap_key_cons, -ENOKEY);
+		goto out_incomplete;
+	}
+
+	namelen_in = strnlen(im.im_name, IDMAP_NAMESZ);
+	if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = nfs_idmap_read_message(&im, cons->key, cons->authkey);
+	if (ret >= 0) {
+		key_set_timeout(cons->key, nfs_idmap_cache_timeout);
+		ret = mlen;
+	}
+
 out:
-	mutex_unlock(&idmap->idmap_im_lock);
+	complete_request_key(idmap->idmap_key_cons, ret);
+out_incomplete:
 	return ret;
 }
 
 static void
 idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
 {
-	struct idmap_msg *im = msg->data;
-	struct idmap *idmap = container_of(im, struct idmap, idmap_im); 
-
-	if (msg->errno >= 0)
-		return;
-	mutex_lock(&idmap->idmap_im_lock);
-	im->im_status = IDMAP_STATUS_LOOKUPFAIL;
-	wake_up(&idmap->idmap_wq);
-	mutex_unlock(&idmap->idmap_im_lock);
-}
-
-/* 
- * Fowler/Noll/Vo hash
- *    http://www.isthe.com/chongo/tech/comp/fnv/
- */
-
-#define FNV_P_32 ((unsigned int)0x01000193) /* 16777619 */
-#define FNV_1_32 ((unsigned int)0x811c9dc5) /* 2166136261 */
-
-static unsigned int fnvhash32(const void *buf, size_t buflen)
-{
-	const unsigned char *p, *end = (const unsigned char *)buf + buflen;
-	unsigned int hash = FNV_1_32;
-
-	for (p = buf; p < end; p++) {
-		hash *= FNV_P_32;
-		hash ^= (unsigned int)*p;
-	}
-
-	return hash;
+	/* Free memory allocated in nfs_idmap_legacy_upcall() */
+	kfree(msg->data);
+	kfree(msg);
 }
 
 int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
@@ -799,16 +756,16 @@
 
 	if (nfs_map_string_to_numeric(name, namelen, uid))
 		return 0;
-	return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid);
+	return nfs_idmap_lookup_id(name, namelen, "uid", uid, idmap);
 }
 
-int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
+int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid)
 {
 	struct idmap *idmap = server->nfs_client->cl_idmap;
 
-	if (nfs_map_string_to_numeric(name, namelen, uid))
+	if (nfs_map_string_to_numeric(name, namelen, gid))
 		return 0;
-	return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid);
+	return nfs_idmap_lookup_id(name, namelen, "gid", gid, idmap);
 }
 
 int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
@@ -817,21 +774,19 @@
 	int ret = -EINVAL;
 
 	if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
-		ret = nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
+		ret = nfs_idmap_lookup_name(uid, "user", buf, buflen, idmap);
 	if (ret < 0)
 		ret = nfs_map_numeric_to_string(uid, buf, buflen);
 	return ret;
 }
-int nfs_map_gid_to_group(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
+int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen)
 {
 	struct idmap *idmap = server->nfs_client->cl_idmap;
 	int ret = -EINVAL;
 
 	if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
-		ret = nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf);
+		ret = nfs_idmap_lookup_name(gid, "group", buf, buflen, idmap);
 	if (ret < 0)
-		ret = nfs_map_numeric_to_string(uid, buf, buflen);
+		ret = nfs_map_numeric_to_string(gid, buf, buflen);
 	return ret;
 }
-
-#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index f649fba..e8bbfa5 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -39,8 +39,8 @@
 #include <linux/slab.h>
 #include <linux/compat.h>
 #include <linux/freezer.h>
+#include <linux/crc32.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 #include "nfs4_fs.h"
@@ -51,6 +51,7 @@
 #include "fscache.h"
 #include "dns_resolve.h"
 #include "pnfs.h"
+#include "netns.h"
 
 #define NFSDBG_FACILITY		NFSDBG_VFS
 
@@ -388,9 +389,10 @@
 		unlock_new_inode(inode);
 	} else
 		nfs_refresh_inode(inode, fattr);
-	dprintk("NFS: nfs_fhget(%s/%Ld ct=%d)\n",
+	dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n",
 		inode->i_sb->s_id,
 		(long long)NFS_FILEID(inode),
+		nfs_display_fhandle_hash(fh),
 		atomic_read(&inode->i_count));
 
 out:
@@ -401,7 +403,7 @@
 	goto out;
 }
 
-#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE)
+#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE|ATTR_OPEN)
 
 int
 nfs_setattr(struct dentry *dentry, struct iattr *attr)
@@ -423,7 +425,7 @@
 
 	/* Optimization: if the end result is no change, don't RPC */
 	attr->ia_valid &= NFS_VALID_ATTRS;
-	if ((attr->ia_valid & ~ATTR_FILE) == 0)
+	if ((attr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
 		return 0;
 
 	/* Write all dirty data */
@@ -1044,6 +1046,67 @@
 	return fh;
 }
 
+#ifdef NFS_DEBUG
+/*
+ * _nfs_display_fhandle_hash - calculate the crc32 hash for the filehandle
+ *                             in the same way that wireshark does
+ *
+ * @fh: file handle
+ *
+ * For debugging only.
+ */
+u32 _nfs_display_fhandle_hash(const struct nfs_fh *fh)
+{
+	/* wireshark uses 32-bit AUTODIN crc and does a bitwise
+	 * not on the result */
+	return ~crc32(0xFFFFFFFF, &fh->data[0], fh->size);
+}
+
+/*
+ * _nfs_display_fhandle - display an NFS file handle on the console
+ *
+ * @fh: file handle to display
+ * @caption: display caption
+ *
+ * For debugging only.
+ */
+void _nfs_display_fhandle(const struct nfs_fh *fh, const char *caption)
+{
+	unsigned short i;
+
+	if (fh == NULL || fh->size == 0) {
+		printk(KERN_DEFAULT "%s at %p is empty\n", caption, fh);
+		return;
+	}
+
+	printk(KERN_DEFAULT "%s at %p is %u bytes, crc: 0x%08x:\n",
+	       caption, fh, fh->size, _nfs_display_fhandle_hash(fh));
+	for (i = 0; i < fh->size; i += 16) {
+		__be32 *pos = (__be32 *)&fh->data[i];
+
+		switch ((fh->size - i - 1) >> 2) {
+		case 0:
+			printk(KERN_DEFAULT " %08x\n",
+				be32_to_cpup(pos));
+			break;
+		case 1:
+			printk(KERN_DEFAULT " %08x %08x\n",
+				be32_to_cpup(pos), be32_to_cpup(pos + 1));
+			break;
+		case 2:
+			printk(KERN_DEFAULT " %08x %08x %08x\n",
+				be32_to_cpup(pos), be32_to_cpup(pos + 1),
+				be32_to_cpup(pos + 2));
+			break;
+		default:
+			printk(KERN_DEFAULT " %08x %08x %08x %08x\n",
+				be32_to_cpup(pos), be32_to_cpup(pos + 1),
+				be32_to_cpup(pos + 2), be32_to_cpup(pos + 3));
+		}
+	}
+}
+#endif
+
 /**
  * nfs_inode_attrs_need_update - check if the inode attributes need updating
  * @inode - pointer to inode
@@ -1211,8 +1274,9 @@
 	unsigned long now = jiffies;
 	unsigned long save_cache_validity;
 
-	dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
+	dfprintk(VFS, "NFS: %s(%s/%ld fh_crc=0x%08x ct=%d info=0x%x)\n",
 			__func__, inode->i_sb->s_id, inode->i_ino,
+			nfs_display_fhandle_hash(NFS_FH(inode)),
 			atomic_read(&inode->i_count), fattr->valid);
 
 	if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
@@ -1406,7 +1470,7 @@
 	/*
 	 * Big trouble! The inode has become a different object.
 	 */
-	printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n",
+	printk(KERN_DEBUG "NFS: %s: inode %ld mode changed, %07o to %07o\n",
 			__func__, inode->i_ino, inode->i_mode, fattr->mode);
  out_err:
 	/*
@@ -1495,7 +1559,7 @@
 	INIT_LIST_HEAD(&nfsi->open_files);
 	INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
 	INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
-	INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
+	INIT_LIST_HEAD(&nfsi->commit_list);
 	nfsi->npages = 0;
 	nfsi->ncommit = 0;
 	atomic_set(&nfsi->silly_count, 1);
@@ -1552,6 +1616,28 @@
 	destroy_workqueue(wq);
 }
 
+int nfs_net_id;
+EXPORT_SYMBOL_GPL(nfs_net_id);
+
+static int nfs_net_init(struct net *net)
+{
+	nfs_clients_init(net);
+	return nfs_dns_resolver_cache_init(net);
+}
+
+static void nfs_net_exit(struct net *net)
+{
+	nfs_dns_resolver_cache_destroy(net);
+	nfs_cleanup_cb_ident_idr(net);
+}
+
+static struct pernet_operations nfs_net_ops = {
+	.init = nfs_net_init,
+	.exit = nfs_net_exit,
+	.id   = &nfs_net_id,
+	.size = sizeof(struct nfs_net),
+};
+
 /*
  * Initialize NFS
  */
@@ -1561,10 +1647,14 @@
 
 	err = nfs_idmap_init();
 	if (err < 0)
-		goto out9;
+		goto out10;
 
 	err = nfs_dns_resolver_init();
 	if (err < 0)
+		goto out9;
+
+	err = register_pernet_subsys(&nfs_net_ops);
+	if (err < 0)
 		goto out8;
 
 	err = nfs_fscache_register();
@@ -1600,14 +1690,14 @@
 		goto out0;
 
 #ifdef CONFIG_PROC_FS
-	rpc_proc_register(&nfs_rpcstat);
+	rpc_proc_register(&init_net, &nfs_rpcstat);
 #endif
 	if ((err = register_nfs_fs()) != 0)
 		goto out;
 	return 0;
 out:
 #ifdef CONFIG_PROC_FS
-	rpc_proc_unregister("nfs");
+	rpc_proc_unregister(&init_net, "nfs");
 #endif
 	nfs_destroy_directcache();
 out0:
@@ -1625,10 +1715,12 @@
 out6:
 	nfs_fscache_unregister();
 out7:
-	nfs_dns_resolver_destroy();
+	unregister_pernet_subsys(&nfs_net_ops);
 out8:
-	nfs_idmap_quit();
+	nfs_dns_resolver_destroy();
 out9:
+	nfs_idmap_quit();
+out10:
 	return err;
 }
 
@@ -1640,12 +1732,12 @@
 	nfs_destroy_inodecache();
 	nfs_destroy_nfspagecache();
 	nfs_fscache_unregister();
+	unregister_pernet_subsys(&nfs_net_ops);
 	nfs_dns_resolver_destroy();
 	nfs_idmap_quit();
 #ifdef CONFIG_PROC_FS
-	rpc_proc_unregister("nfs");
+	rpc_proc_unregister(&init_net, "nfs");
 #endif
-	nfs_cleanup_cb_ident_idr();
 	unregister_nfs_fs();
 	nfs_fs_proc_exit();
 	nfsiod_stop();
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 8102db9..2476dc6 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -123,6 +123,7 @@
 	} nfs_server;
 
 	struct security_mnt_opts lsm_opts;
+	struct net		*net;
 };
 
 /* mount_clnt.c */
@@ -137,20 +138,22 @@
 	int			noresvport;
 	unsigned int		*auth_flav_len;
 	rpc_authflavor_t	*auth_flavs;
+	struct net		*net;
 };
 
 extern int nfs_mount(struct nfs_mount_request *info);
 extern void nfs_umount(const struct nfs_mount_request *info);
 
 /* client.c */
-extern struct rpc_program nfs_program;
+extern const struct rpc_program nfs_program;
+extern void nfs_clients_init(struct net *net);
 
-extern void nfs_cleanup_cb_ident_idr(void);
+extern void nfs_cleanup_cb_ident_idr(struct net *);
 extern void nfs_put_client(struct nfs_client *);
-extern struct nfs_client *nfs4_find_client_no_ident(const struct sockaddr *);
-extern struct nfs_client *nfs4_find_client_ident(int);
+extern struct nfs_client *nfs4_find_client_ident(struct net *, int);
 extern struct nfs_client *
-nfs4_find_client_sessionid(const struct sockaddr *, struct nfs4_sessionid *);
+nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
+				struct nfs4_sessionid *);
 extern struct nfs_server *nfs_create_server(
 					const struct nfs_parsed_mount_data *,
 					struct nfs_fh *);
@@ -329,6 +332,8 @@
 void nfs_commit_clear_lock(struct nfs_inode *nfsi);
 void nfs_commitdata_release(void *data);
 void nfs_commit_release_pages(struct nfs_write_data *data);
+void nfs_request_add_commit_list(struct nfs_page *req, struct list_head *head);
+void nfs_request_remove_commit_list(struct nfs_page *req);
 
 #ifdef CONFIG_MIGRATION
 extern int nfs_migrate_page(struct address_space *,
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
index d4c2d6b..8e65c7f 100644
--- a/fs/nfs/mount_clnt.c
+++ b/fs/nfs/mount_clnt.c
@@ -16,7 +16,7 @@
 #include <linux/nfs_fs.h>
 #include "internal.h"
 
-#ifdef RPC_DEBUG
+#ifdef NFS_DEBUG
 # define NFSDBG_FACILITY	NFSDBG_MOUNT
 #endif
 
@@ -67,7 +67,7 @@
 	MOUNTPROC3_EXPORT	= 5,
 };
 
-static struct rpc_program	mnt_program;
+static const struct rpc_program mnt_program;
 
 /*
  * Defined by OpenGroup XNFS Version 3W, chapter 8
@@ -153,7 +153,7 @@
 		.rpc_resp	= &result,
 	};
 	struct rpc_create_args args = {
-		.net		= &init_net,
+		.net		= info->net,
 		.protocol	= info->protocol,
 		.address	= info->sap,
 		.addrsize	= info->salen,
@@ -225,7 +225,7 @@
 		.to_retries = 2,
 	};
 	struct rpc_create_args args = {
-		.net		= &init_net,
+		.net		= info->net,
 		.protocol	= IPPROTO_UDP,
 		.address	= info->sap,
 		.addrsize	= info->salen,
@@ -488,19 +488,19 @@
 };
 
 
-static struct rpc_version mnt_version1 = {
+static const struct rpc_version mnt_version1 = {
 	.number		= 1,
 	.nrprocs	= ARRAY_SIZE(mnt_procedures),
 	.procs		= mnt_procedures,
 };
 
-static struct rpc_version mnt_version3 = {
+static const struct rpc_version mnt_version3 = {
 	.number		= 3,
 	.nrprocs	= ARRAY_SIZE(mnt3_procedures),
 	.procs		= mnt3_procedures,
 };
 
-static struct rpc_version *mnt_version[] = {
+static const struct rpc_version *mnt_version[] = {
 	NULL,
 	&mnt_version1,
 	NULL,
@@ -509,7 +509,7 @@
 
 static struct rpc_stat mnt_stats;
 
-static struct rpc_program mnt_program = {
+static const struct rpc_program mnt_program = {
 	.name		= "mount",
 	.number		= NFS_MNT_PROGRAM,
 	.nrvers		= ARRAY_SIZE(mnt_version),
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 8102391..1807866 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -276,7 +276,10 @@
 	nfs_free_fattr(fattr);
 	nfs_free_fhandle(fh);
 out_nofree:
-	dprintk("<-- nfs_follow_mountpoint() = %p\n", mnt);
+	if (IS_ERR(mnt))
+		dprintk("<-- %s(): error %ld\n", __func__, PTR_ERR(mnt));
+	else
+		dprintk("<-- %s() = %p\n", __func__, mnt);
 	return mnt;
 }
 
diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h
new file mode 100644
index 0000000..aa14ec3
--- /dev/null
+++ b/fs/nfs/netns.h
@@ -0,0 +1,27 @@
+#ifndef __NFS_NETNS_H__
+#define __NFS_NETNS_H__
+
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+
+struct bl_dev_msg {
+	int32_t status;
+	uint32_t major, minor;
+};
+
+struct nfs_net {
+	struct cache_detail *nfs_dns_resolve;
+	struct rpc_pipe *bl_device_pipe;
+	struct bl_dev_msg bl_mount_reply;
+	wait_queue_head_t bl_wq;
+	struct list_head nfs_client_list;
+	struct list_head nfs_volume_list;
+#ifdef CONFIG_NFS_V4
+	struct idr cb_ident_idr; /* Protected by nfs_client_lock */
+#endif
+	spinlock_t nfs_client_lock;
+};
+
+extern int nfs_net_id;
+
+#endif
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 792cb13..1f56000 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -1150,7 +1150,7 @@
 	PROC(STATFS,	fhandle,	statfsres,	0),
 };
 
-struct rpc_version		nfs_version2 = {
+const struct rpc_version nfs_version2 = {
 	.number			= 2,
 	.nrprocs		= ARRAY_SIZE(nfs_procedures),
 	.procs			= nfs_procedures
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 7ef2397..e4498dc 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -192,7 +192,7 @@
 		.pages = pages,
 	};
 	struct nfs3_getaclres res = {
-		0
+		NULL,
 	};
 	struct rpc_message msg = {
 		.rpc_argp	= &args,
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 91943953..5242eae 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -428,6 +428,11 @@
 	msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE];
 }
 
+static void nfs3_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
+{
+	rpc_call_start(task);
+}
+
 static int
 nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 {
@@ -445,6 +450,11 @@
 	msg->rpc_proc = &nfs3_procedures[NFS3PROC_RENAME];
 }
 
+static void nfs3_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
+{
+	rpc_call_start(task);
+}
+
 static int
 nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
 		      struct inode *new_dir)
@@ -814,6 +824,11 @@
 	msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ];
 }
 
+static void nfs3_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
+{
+	rpc_call_start(task);
+}
+
 static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data)
 {
 	if (nfs3_async_handle_jukebox(task, data->inode))
@@ -828,6 +843,11 @@
 	msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE];
 }
 
+static void nfs3_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
+{
+	rpc_call_start(task);
+}
+
 static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data)
 {
 	if (nfs3_async_handle_jukebox(task, data->inode))
@@ -864,9 +884,11 @@
 	.create		= nfs3_proc_create,
 	.remove		= nfs3_proc_remove,
 	.unlink_setup	= nfs3_proc_unlink_setup,
+	.unlink_rpc_prepare = nfs3_proc_unlink_rpc_prepare,
 	.unlink_done	= nfs3_proc_unlink_done,
 	.rename		= nfs3_proc_rename,
 	.rename_setup	= nfs3_proc_rename_setup,
+	.rename_rpc_prepare = nfs3_proc_rename_rpc_prepare,
 	.rename_done	= nfs3_proc_rename_done,
 	.link		= nfs3_proc_link,
 	.symlink	= nfs3_proc_symlink,
@@ -879,8 +901,10 @@
 	.pathconf	= nfs3_proc_pathconf,
 	.decode_dirent	= nfs3_decode_dirent,
 	.read_setup	= nfs3_proc_read_setup,
+	.read_rpc_prepare = nfs3_proc_read_rpc_prepare,
 	.read_done	= nfs3_read_done,
 	.write_setup	= nfs3_proc_write_setup,
+	.write_rpc_prepare = nfs3_proc_write_rpc_prepare,
 	.write_done	= nfs3_write_done,
 	.commit_setup	= nfs3_proc_commit_setup,
 	.commit_done	= nfs3_commit_done,
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 183c6b1..a77cc9a 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -2461,7 +2461,7 @@
 	PROC(COMMIT,		commit,		commit,		5),
 };
 
-struct rpc_version		nfs_version3 = {
+const struct rpc_version nfs_version3 = {
 	.number			= 3,
 	.nrprocs		= ARRAY_SIZE(nfs3_procedures),
 	.procs			= nfs3_procedures
@@ -2489,7 +2489,7 @@
 	},
 };
 
-struct rpc_version		nfsacl_version3 = {
+const struct rpc_version nfsacl_version3 = {
 	.number			= 3,
 	.nrprocs		= sizeof(nfs3_acl_procedures)/
 				  sizeof(nfs3_acl_procedures[0]),
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 4d7d0ae..97ecc86 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -20,7 +20,6 @@
 	NFS4CLNT_RECLAIM_REBOOT,
 	NFS4CLNT_RECLAIM_NOGRACE,
 	NFS4CLNT_DELEGRETURN,
-	NFS4CLNT_LAYOUTRECALL,
 	NFS4CLNT_SESSION_RESET,
 	NFS4CLNT_RECALL_SLOT,
 	NFS4CLNT_LEASE_CONFIRM,
@@ -44,7 +43,7 @@
 			struct nfs4_sequence_args *args,
 			struct nfs4_sequence_res *res,
 			int cache_reply);
-	int	(*validate_stateid)(struct nfs_delegation *,
+	bool	(*match_stateid)(const nfs4_stateid *,
 			const nfs4_stateid *);
 	int	(*find_root_sec)(struct nfs_server *, struct nfs_fh *,
 			struct nfs_fsinfo *);
@@ -53,26 +52,25 @@
 	const struct nfs4_state_maintenance_ops *state_renewal_ops;
 };
 
-/*
- * struct rpc_sequence ensures that RPC calls are sent in the exact
- * order that they appear on the list.
- */
-struct rpc_sequence {
-	struct rpc_wait_queue	wait;	/* RPC call delay queue */
-	spinlock_t lock;		/* Protects the list */
-	struct list_head list;		/* Defines sequence of RPC calls */
+struct nfs_unique_id {
+	struct rb_node rb_node;
+	__u64 id;
 };
 
 #define NFS_SEQID_CONFIRMED 1
 struct nfs_seqid_counter {
-	struct rpc_sequence *sequence;
+	int owner_id;
 	int flags;
 	u32 counter;
+	spinlock_t lock;		/* Protects the list */
+	struct list_head list;		/* Defines sequence of RPC calls */
+	struct rpc_wait_queue	wait;	/* RPC call delay queue */
 };
 
 struct nfs_seqid {
 	struct nfs_seqid_counter *sequence;
 	struct list_head list;
+	struct rpc_task *task;
 };
 
 static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status)
@@ -81,18 +79,12 @@
 		seqid->flags |= NFS_SEQID_CONFIRMED;
 }
 
-struct nfs_unique_id {
-	struct rb_node rb_node;
-	__u64 id;
-};
-
 /*
  * NFS4 state_owners and lock_owners are simply labels for ordered
  * sequences of RPC calls. Their sole purpose is to provide once-only
  * semantics by allowing the server to identify replayed requests.
  */
 struct nfs4_state_owner {
-	struct nfs_unique_id so_owner_id;
 	struct nfs_server    *so_server;
 	struct list_head     so_lru;
 	unsigned long        so_expires;
@@ -105,7 +97,6 @@
 	unsigned long	     so_flags;
 	struct list_head     so_states;
 	struct nfs_seqid_counter so_seqid;
-	struct rpc_sequence  so_sequence;
 };
 
 enum {
@@ -146,8 +137,6 @@
 #define NFS_LOCK_INITIALIZED 1
 	int			ls_flags;
 	struct nfs_seqid_counter	ls_seqid;
-	struct rpc_sequence	ls_sequence;
-	struct nfs_unique_id	ls_id;
 	nfs4_stateid		ls_stateid;
 	atomic_t		ls_count;
 	struct nfs4_lock_owner	ls_owner;
@@ -193,6 +182,7 @@
 	long timeout;
 	int retry;
 	struct nfs4_state *state;
+	struct inode *inode;
 };
 
 struct nfs4_state_recovery_ops {
@@ -224,7 +214,7 @@
 extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
 extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
 		struct nfs4_fs_locations *fs_locations, struct page *page);
-extern void nfs4_release_lockowner(const struct nfs4_lock_state *);
+extern int nfs4_release_lockowner(struct nfs4_lock_state *);
 extern const struct xattr_handler *nfs4_xattr_handlers[];
 
 #if defined(CONFIG_NFS_V4_1)
@@ -233,12 +223,13 @@
 	return server->nfs_client->cl_session;
 }
 
+extern bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy);
 extern int nfs4_setup_sequence(const struct nfs_server *server,
 		struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
-		int cache_reply, struct rpc_task *task);
+		struct rpc_task *task);
 extern int nfs41_setup_sequence(struct nfs4_session *session,
 		struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
-		int cache_reply, struct rpc_task *task);
+		struct rpc_task *task);
 extern void nfs4_destroy_session(struct nfs4_session *session);
 extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp);
 extern int nfs4_proc_create_session(struct nfs_client *);
@@ -269,7 +260,7 @@
 
 static inline int nfs4_setup_sequence(const struct nfs_server *server,
 		struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
-		int cache_reply, struct rpc_task *task)
+		struct rpc_task *task)
 {
 	return 0;
 }
@@ -319,7 +310,7 @@
 }
 #endif /* CONFIG_NFS_V4_1 */
 
-extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
+extern struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *, gfp_t);
 extern void nfs4_put_state_owner(struct nfs4_state_owner *);
 extern void nfs4_purge_state_owners(struct nfs_server *);
 extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
@@ -327,6 +318,8 @@
 extern void nfs4_close_state(struct nfs4_state *, fmode_t);
 extern void nfs4_close_sync(struct nfs4_state *, fmode_t);
 extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
+extern void nfs_inode_find_state_and_recover(struct inode *inode,
+		const nfs4_stateid *stateid);
 extern void nfs4_schedule_lease_recovery(struct nfs_client *);
 extern void nfs4_schedule_state_manager(struct nfs_client *);
 extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp);
@@ -337,7 +330,8 @@
 				      struct server_scope **);
 extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
 extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
-extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t, pid_t);
+extern void nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *,
+		fmode_t, fl_owner_t, pid_t);
 
 extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask);
 extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
@@ -346,6 +340,8 @@
 extern void nfs_release_seqid(struct nfs_seqid *seqid);
 extern void nfs_free_seqid(struct nfs_seqid *seqid);
 
+extern void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp);
+
 extern const nfs4_stateid zero_stateid;
 
 /* nfs4xdr.c */
@@ -357,6 +353,16 @@
 extern struct svc_version nfs4_callback_version1;
 extern struct svc_version nfs4_callback_version4;
 
+static inline void nfs4_stateid_copy(nfs4_stateid *dst, const nfs4_stateid *src)
+{
+	memcpy(dst, src, sizeof(*dst));
+}
+
+static inline bool nfs4_stateid_match(const nfs4_stateid *dst, const nfs4_stateid *src)
+{
+	return memcmp(dst, src, sizeof(*dst)) == 0;
+}
+
 #else
 
 #define nfs4_close_state(a, b) do { } while (0)
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index 71ec086..5acfd9e 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -33,7 +33,10 @@
 #include <linux/nfs_page.h>
 #include <linux/module.h>
 
+#include <linux/sunrpc/metrics.h>
+
 #include "internal.h"
+#include "delegation.h"
 #include "nfs4filelayout.h"
 
 #define NFSDBG_FACILITY         NFSDBG_PNFS_LD
@@ -84,12 +87,27 @@
 					 struct nfs_client *clp,
 					 int *reset)
 {
+	struct nfs_server *mds_server = NFS_SERVER(state->inode);
+	struct nfs_client *mds_client = mds_server->nfs_client;
+
 	if (task->tk_status >= 0)
 		return 0;
-
 	*reset = 0;
 
 	switch (task->tk_status) {
+	/* MDS state errors */
+	case -NFS4ERR_DELEG_REVOKED:
+	case -NFS4ERR_ADMIN_REVOKED:
+	case -NFS4ERR_BAD_STATEID:
+		nfs_remove_bad_delegation(state->inode);
+	case -NFS4ERR_OPENMODE:
+		nfs4_schedule_stateid_recovery(mds_server, state);
+		goto wait_on_recovery;
+	case -NFS4ERR_EXPIRED:
+		nfs4_schedule_stateid_recovery(mds_server, state);
+		nfs4_schedule_lease_recovery(mds_client);
+		goto wait_on_recovery;
+	/* DS session errors */
 	case -NFS4ERR_BADSESSION:
 	case -NFS4ERR_BADSLOT:
 	case -NFS4ERR_BAD_HIGH_SLOT:
@@ -115,8 +133,14 @@
 		*reset = 1;
 		break;
 	}
+out:
 	task->tk_status = 0;
 	return -EAGAIN;
+wait_on_recovery:
+	rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL);
+	if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0)
+		rpc_wake_up_queued_task(&mds_client->cl_rpcwaitq, task);
+	goto out;
 }
 
 /* NFS_PROTO call done callback routines */
@@ -173,7 +197,7 @@
 
 	if (nfs41_setup_sequence(rdata->ds_clp->cl_session,
 				&rdata->args.seq_args, &rdata->res.seq_res,
-				0, task))
+				task))
 		return;
 
 	rpc_call_start(task);
@@ -189,10 +213,18 @@
 	rdata->mds_ops->rpc_call_done(task, data);
 }
 
+static void filelayout_read_count_stats(struct rpc_task *task, void *data)
+{
+	struct nfs_read_data *rdata = (struct nfs_read_data *)data;
+
+	rpc_count_iostats(task, NFS_SERVER(rdata->inode)->client->cl_metrics);
+}
+
 static void filelayout_read_release(void *data)
 {
 	struct nfs_read_data *rdata = (struct nfs_read_data *)data;
 
+	put_lseg(rdata->lseg);
 	rdata->mds_ops->rpc_release(data);
 }
 
@@ -254,7 +286,7 @@
 
 	if (nfs41_setup_sequence(wdata->ds_clp->cl_session,
 				&wdata->args.seq_args, &wdata->res.seq_res,
-				0, task))
+				task))
 		return;
 
 	rpc_call_start(task);
@@ -268,10 +300,18 @@
 	wdata->mds_ops->rpc_call_done(task, data);
 }
 
+static void filelayout_write_count_stats(struct rpc_task *task, void *data)
+{
+	struct nfs_write_data *wdata = (struct nfs_write_data *)data;
+
+	rpc_count_iostats(task, NFS_SERVER(wdata->inode)->client->cl_metrics);
+}
+
 static void filelayout_write_release(void *data)
 {
 	struct nfs_write_data *wdata = (struct nfs_write_data *)data;
 
+	put_lseg(wdata->lseg);
 	wdata->mds_ops->rpc_release(data);
 }
 
@@ -282,24 +322,28 @@
 	nfs_commit_release_pages(wdata);
 	if (atomic_dec_and_test(&NFS_I(wdata->inode)->commits_outstanding))
 		nfs_commit_clear_lock(NFS_I(wdata->inode));
+	put_lseg(wdata->lseg);
 	nfs_commitdata_release(wdata);
 }
 
-struct rpc_call_ops filelayout_read_call_ops = {
+static const struct rpc_call_ops filelayout_read_call_ops = {
 	.rpc_call_prepare = filelayout_read_prepare,
 	.rpc_call_done = filelayout_read_call_done,
+	.rpc_count_stats = filelayout_read_count_stats,
 	.rpc_release = filelayout_read_release,
 };
 
-struct rpc_call_ops filelayout_write_call_ops = {
+static const struct rpc_call_ops filelayout_write_call_ops = {
 	.rpc_call_prepare = filelayout_write_prepare,
 	.rpc_call_done = filelayout_write_call_done,
+	.rpc_count_stats = filelayout_write_count_stats,
 	.rpc_release = filelayout_write_release,
 };
 
-struct rpc_call_ops filelayout_commit_call_ops = {
+static const struct rpc_call_ops filelayout_commit_call_ops = {
 	.rpc_call_prepare = filelayout_write_prepare,
 	.rpc_call_done = filelayout_write_call_done,
+	.rpc_count_stats = filelayout_write_count_stats,
 	.rpc_release = filelayout_commit_release,
 };
 
@@ -367,7 +411,8 @@
 	idx = nfs4_fl_calc_ds_index(lseg, j);
 	ds = nfs4_fl_prepare_ds(lseg, idx);
 	if (!ds) {
-		printk(KERN_ERR "%s: prepare_ds failed, use MDS\n", __func__);
+		printk(KERN_ERR "NFS: %s: prepare_ds failed, use MDS\n",
+			__func__);
 		set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
 		set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
 		return PNFS_NOT_ATTEMPTED;
@@ -575,7 +620,7 @@
 			goto out_err_free;
 		fl->fh_array[i]->size = be32_to_cpup(p++);
 		if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) {
-			printk(KERN_ERR "Too big fh %d received %d\n",
+			printk(KERN_ERR "NFS: Too big fh %d received %d\n",
 			       i, fl->fh_array[i]->size);
 			goto out_err_free;
 		}
@@ -640,14 +685,16 @@
 		int size = (fl->stripe_type == STRIPE_SPARSE) ?
 			fl->dsaddr->ds_num : fl->dsaddr->stripe_count;
 
-		fl->commit_buckets = kcalloc(size, sizeof(struct list_head), gfp_flags);
+		fl->commit_buckets = kcalloc(size, sizeof(struct nfs4_fl_commit_bucket), gfp_flags);
 		if (!fl->commit_buckets) {
 			filelayout_free_lseg(&fl->generic_hdr);
 			return NULL;
 		}
 		fl->number_of_buckets = size;
-		for (i = 0; i < size; i++)
-			INIT_LIST_HEAD(&fl->commit_buckets[i]);
+		for (i = 0; i < size; i++) {
+			INIT_LIST_HEAD(&fl->commit_buckets[i].written);
+			INIT_LIST_HEAD(&fl->commit_buckets[i].committing);
+		}
 	}
 	return &fl->generic_hdr;
 }
@@ -679,7 +726,7 @@
 	return (p_stripe == r_stripe);
 }
 
-void
+static void
 filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
 			struct nfs_page *req)
 {
@@ -696,7 +743,7 @@
 		nfs_pageio_reset_read_mds(pgio);
 }
 
-void
+static void
 filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
 			 struct nfs_page *req)
 {
@@ -725,11 +772,6 @@
 	.pg_doio = pnfs_generic_pg_writepages,
 };
 
-static bool filelayout_mark_pnfs_commit(struct pnfs_layout_segment *lseg)
-{
-	return !FILELAYOUT_LSEG(lseg)->commit_through_mds;
-}
-
 static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j)
 {
 	if (fl->stripe_type == STRIPE_SPARSE)
@@ -738,13 +780,48 @@
 		return j;
 }
 
-struct list_head *filelayout_choose_commit_list(struct nfs_page *req)
+/* The generic layer is about to remove the req from the commit list.
+ * If this will make the bucket empty, it will need to put the lseg reference.
+ */
+static void
+filelayout_clear_request_commit(struct nfs_page *req)
 {
-	struct pnfs_layout_segment *lseg = req->wb_commit_lseg;
+	struct pnfs_layout_segment *freeme = NULL;
+	struct inode *inode = req->wb_context->dentry->d_inode;
+
+	spin_lock(&inode->i_lock);
+	if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags))
+		goto out;
+	if (list_is_singular(&req->wb_list)) {
+		struct pnfs_layout_segment *lseg;
+
+		/* From here we can find the bucket, but for the moment,
+		 * since there is only one relevant lseg...
+		 */
+		list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {
+			if (lseg->pls_range.iomode == IOMODE_RW) {
+				freeme = lseg;
+				break;
+			}
+		}
+	}
+out:
+	nfs_request_remove_commit_list(req);
+	spin_unlock(&inode->i_lock);
+	put_lseg(freeme);
+}
+
+static struct list_head *
+filelayout_choose_commit_list(struct nfs_page *req,
+			      struct pnfs_layout_segment *lseg)
+{
 	struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
 	u32 i, j;
 	struct list_head *list;
 
+	if (fl->commit_through_mds)
+		return &NFS_I(req->wb_context->dentry->d_inode)->commit_list;
+
 	/* Note that we are calling nfs4_fl_calc_j_index on each page
 	 * that ends up being committed to a data server.  An attractive
 	 * alternative is to add a field to nfs_write_data and nfs_page
@@ -754,14 +831,30 @@
 	j = nfs4_fl_calc_j_index(lseg,
 				 (loff_t)req->wb_index << PAGE_CACHE_SHIFT);
 	i = select_bucket_index(fl, j);
-	list = &fl->commit_buckets[i];
+	list = &fl->commit_buckets[i].written;
 	if (list_empty(list)) {
-		/* Non-empty buckets hold a reference on the lseg */
+		/* Non-empty buckets hold a reference on the lseg.  That ref
+		 * is normally transferred to the COMMIT call and released
+		 * there.  It could also be released if the last req is pulled
+		 * off due to a rewrite, in which case it will be done in
+		 * filelayout_remove_commit_req
+		 */
 		get_lseg(lseg);
 	}
+	set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
 	return list;
 }
 
+static void
+filelayout_mark_request_commit(struct nfs_page *req,
+		struct pnfs_layout_segment *lseg)
+{
+	struct list_head *list;
+
+	list = filelayout_choose_commit_list(req, lseg);
+	nfs_request_add_commit_list(req, list);
+}
+
 static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i)
 {
 	struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
@@ -797,11 +890,12 @@
 	idx = calc_ds_index_from_commit(lseg, data->ds_commit_index);
 	ds = nfs4_fl_prepare_ds(lseg, idx);
 	if (!ds) {
-		printk(KERN_ERR "%s: prepare_ds failed, use MDS\n", __func__);
+		printk(KERN_ERR "NFS: %s: prepare_ds failed, use MDS\n",
+			__func__);
 		set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
 		set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
 		prepare_to_resend_writes(data);
-		data->mds_ops->rpc_release(data);
+		filelayout_commit_release(data);
 		return -EAGAIN;
 	}
 	dprintk("%s ino %lu, how %d\n", __func__, data->inode->i_ino, how);
@@ -817,24 +911,87 @@
 /*
  * This is only useful while we are using whole file layouts.
  */
-static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode)
+static struct pnfs_layout_segment *
+find_only_write_lseg_locked(struct inode *inode)
 {
-	struct pnfs_layout_segment *lseg, *rv = NULL;
+	struct pnfs_layout_segment *lseg;
 
-	spin_lock(&inode->i_lock);
 	list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list)
 		if (lseg->pls_range.iomode == IOMODE_RW)
-			rv = get_lseg(lseg);
+			return lseg;
+	return NULL;
+}
+
+static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode)
+{
+	struct pnfs_layout_segment *rv;
+
+	spin_lock(&inode->i_lock);
+	rv = find_only_write_lseg_locked(inode);
+	if (rv)
+		get_lseg(rv);
 	spin_unlock(&inode->i_lock);
 	return rv;
 }
 
-static int alloc_ds_commits(struct inode *inode, struct list_head *list)
+static int
+filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max,
+		spinlock_t *lock)
+{
+	struct list_head *src = &bucket->written;
+	struct list_head *dst = &bucket->committing;
+	struct nfs_page *req, *tmp;
+	int ret = 0;
+
+	list_for_each_entry_safe(req, tmp, src, wb_list) {
+		if (!nfs_lock_request(req))
+			continue;
+		if (cond_resched_lock(lock))
+			list_safe_reset_next(req, tmp, wb_list);
+		nfs_request_remove_commit_list(req);
+		clear_bit(PG_COMMIT_TO_DS, &req->wb_flags);
+		nfs_list_add_request(req, dst);
+		ret++;
+		if (ret == max)
+			break;
+	}
+	return ret;
+}
+
+/* Move reqs from written to committing lists, returning count of number moved.
+ * Note called with i_lock held.
+ */
+static int filelayout_scan_commit_lists(struct inode *inode, int max,
+		spinlock_t *lock)
+{
+	struct pnfs_layout_segment *lseg;
+	struct nfs4_filelayout_segment *fl;
+	int i, rv = 0, cnt;
+
+	lseg = find_only_write_lseg_locked(inode);
+	if (!lseg)
+		goto out_done;
+	fl = FILELAYOUT_LSEG(lseg);
+	if (fl->commit_through_mds)
+		goto out_done;
+	for (i = 0; i < fl->number_of_buckets && max != 0; i++) {
+		cnt = filelayout_scan_ds_commit_list(&fl->commit_buckets[i],
+				max, lock);
+		max -= cnt;
+		rv += cnt;
+	}
+out_done:
+	return rv;
+}
+
+static unsigned int
+alloc_ds_commits(struct inode *inode, struct list_head *list)
 {
 	struct pnfs_layout_segment *lseg;
 	struct nfs4_filelayout_segment *fl;
 	struct nfs_write_data *data;
 	int i, j;
+	unsigned int nreq = 0;
 
 	/* Won't need this when non-whole file layout segments are supported
 	 * instead we will use a pnfs_layout_hdr structure */
@@ -843,28 +1000,27 @@
 		return 0;
 	fl = FILELAYOUT_LSEG(lseg);
 	for (i = 0; i < fl->number_of_buckets; i++) {
-		if (list_empty(&fl->commit_buckets[i]))
+		if (list_empty(&fl->commit_buckets[i].committing))
 			continue;
 		data = nfs_commitdata_alloc();
 		if (!data)
-			goto out_bad;
+			break;
 		data->ds_commit_index = i;
 		data->lseg = lseg;
 		list_add(&data->pages, list);
+		nreq++;
 	}
-	put_lseg(lseg);
-	return 0;
 
-out_bad:
+	/* Clean up on error */
 	for (j = i; j < fl->number_of_buckets; j++) {
-		if (list_empty(&fl->commit_buckets[i]))
+		if (list_empty(&fl->commit_buckets[i].committing))
 			continue;
-		nfs_retry_commit(&fl->commit_buckets[i], lseg);
+		nfs_retry_commit(&fl->commit_buckets[i].committing, lseg);
 		put_lseg(lseg);  /* associated with emptying bucket */
 	}
 	put_lseg(lseg);
 	/* Caller will clean up entries put on list */
-	return -ENOMEM;
+	return nreq;
 }
 
 /* This follows nfs_commit_list pretty closely */
@@ -874,40 +1030,40 @@
 {
 	struct nfs_write_data	*data, *tmp;
 	LIST_HEAD(list);
+	unsigned int nreq = 0;
 
 	if (!list_empty(mds_pages)) {
 		data = nfs_commitdata_alloc();
-		if (!data)
-			goto out_bad;
-		data->lseg = NULL;
-		list_add(&data->pages, &list);
+		if (data != NULL) {
+			data->lseg = NULL;
+			list_add(&data->pages, &list);
+			nreq++;
+		} else
+			nfs_retry_commit(mds_pages, NULL);
 	}
 
-	if (alloc_ds_commits(inode, &list))
-		goto out_bad;
+	nreq += alloc_ds_commits(inode, &list);
+
+	if (nreq == 0) {
+		nfs_commit_clear_lock(NFS_I(inode));
+		goto out;
+	}
+
+	atomic_add(nreq, &NFS_I(inode)->commits_outstanding);
 
 	list_for_each_entry_safe(data, tmp, &list, pages) {
 		list_del_init(&data->pages);
-		atomic_inc(&NFS_I(inode)->commits_outstanding);
 		if (!data->lseg) {
 			nfs_init_commit(data, mds_pages, NULL);
 			nfs_initiate_commit(data, NFS_CLIENT(inode),
 					    data->mds_ops, how);
 		} else {
-			nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index], data->lseg);
+			nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index].committing, data->lseg);
 			filelayout_initiate_commit(data, how);
 		}
 	}
-	return 0;
- out_bad:
-	list_for_each_entry_safe(data, tmp, &list, pages) {
-		nfs_retry_commit(&data->pages, data->lseg);
-		list_del_init(&data->pages);
-		nfs_commit_free(data);
-	}
-	nfs_retry_commit(mds_pages, NULL);
-	nfs_commit_clear_lock(NFS_I(inode));
-	return -ENOMEM;
+out:
+	return PNFS_ATTEMPTED;
 }
 
 static void
@@ -924,8 +1080,9 @@
 	.free_lseg		= filelayout_free_lseg,
 	.pg_read_ops		= &filelayout_pg_read_ops,
 	.pg_write_ops		= &filelayout_pg_write_ops,
-	.mark_pnfs_commit	= filelayout_mark_pnfs_commit,
-	.choose_commit_list	= filelayout_choose_commit_list,
+	.mark_request_commit	= filelayout_mark_request_commit,
+	.clear_request_commit	= filelayout_clear_request_commit,
+	.scan_commit_lists	= filelayout_scan_commit_lists,
 	.commit_pagelist	= filelayout_commit_pagelist,
 	.read_pagelist		= filelayout_read_pagelist,
 	.write_pagelist		= filelayout_write_pagelist,
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h
index 2e42284..21190bb 100644
--- a/fs/nfs/nfs4filelayout.h
+++ b/fs/nfs/nfs4filelayout.h
@@ -74,6 +74,11 @@
 	struct nfs4_pnfs_ds		*ds_list[1];
 };
 
+struct nfs4_fl_commit_bucket {
+	struct list_head written;
+	struct list_head committing;
+};
+
 struct nfs4_filelayout_segment {
 	struct pnfs_layout_segment generic_hdr;
 	u32 stripe_type;
@@ -84,7 +89,7 @@
 	struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */
 	unsigned int num_fh;
 	struct nfs_fh **fh_array;
-	struct list_head *commit_buckets; /* Sort commits to ds */
+	struct nfs4_fl_commit_bucket *commit_buckets; /* Sort commits to ds */
 	int number_of_buckets;
 };
 
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c
index 8ae9190..a866bbd 100644
--- a/fs/nfs/nfs4filelayoutdev.c
+++ b/fs/nfs/nfs4filelayoutdev.c
@@ -45,7 +45,7 @@
  *   - incremented when a device id maps a data server already in the cache.
  *   - decremented when deviceid is removed from the cache.
  */
-DEFINE_SPINLOCK(nfs4_ds_cache_lock);
+static DEFINE_SPINLOCK(nfs4_ds_cache_lock);
 static LIST_HEAD(nfs4_data_server_cache);
 
 /* Debug routines */
@@ -108,58 +108,40 @@
 	return false;
 }
 
-/*
- * Lookup DS by addresses.  The first matching address returns true.
- * nfs4_ds_cache_lock is held
- */
-static struct nfs4_pnfs_ds *
-_data_server_lookup_locked(struct list_head *dsaddrs)
+static bool
+_same_data_server_addrs_locked(const struct list_head *dsaddrs1,
+			       const struct list_head *dsaddrs2)
 {
-	struct nfs4_pnfs_ds *ds;
 	struct nfs4_pnfs_ds_addr *da1, *da2;
 
-	list_for_each_entry(da1, dsaddrs, da_node) {
-		list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) {
-			list_for_each_entry(da2, &ds->ds_addrs, da_node) {
-				if (same_sockaddr(
-					(struct sockaddr *)&da1->da_addr,
-					(struct sockaddr *)&da2->da_addr))
-					return ds;
-			}
-		}
+	/* step through both lists, comparing as we go */
+	for (da1 = list_first_entry(dsaddrs1, typeof(*da1), da_node),
+	     da2 = list_first_entry(dsaddrs2, typeof(*da2), da_node);
+	     da1 != NULL && da2 != NULL;
+	     da1 = list_entry(da1->da_node.next, typeof(*da1), da_node),
+	     da2 = list_entry(da2->da_node.next, typeof(*da2), da_node)) {
+		if (!same_sockaddr((struct sockaddr *)&da1->da_addr,
+				   (struct sockaddr *)&da2->da_addr))
+			return false;
 	}
-	return NULL;
+	if (da1 == NULL && da2 == NULL)
+		return true;
+
+	return false;
 }
 
 /*
- * Compare two lists of addresses.
+ * Lookup DS by addresses.  nfs4_ds_cache_lock is held
  */
-static bool
-_data_server_match_all_addrs_locked(struct list_head *dsaddrs1,
-				    struct list_head *dsaddrs2)
+static struct nfs4_pnfs_ds *
+_data_server_lookup_locked(const struct list_head *dsaddrs)
 {
-	struct nfs4_pnfs_ds_addr *da1, *da2;
-	size_t count1 = 0,
-	       count2 = 0;
+	struct nfs4_pnfs_ds *ds;
 
-	list_for_each_entry(da1, dsaddrs1, da_node)
-		count1++;
-
-	list_for_each_entry(da2, dsaddrs2, da_node) {
-		bool found = false;
-		count2++;
-		list_for_each_entry(da1, dsaddrs1, da_node) {
-			if (same_sockaddr((struct sockaddr *)&da1->da_addr,
-				(struct sockaddr *)&da2->da_addr)) {
-				found = true;
-				break;
-			}
-		}
-		if (!found)
-			return false;
-	}
-
-	return (count1 == count2);
+	list_for_each_entry(ds, &nfs4_data_server_cache, ds_node)
+		if (_same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs))
+			return ds;
+	return NULL;
 }
 
 /*
@@ -356,11 +338,6 @@
 		dprintk("%s add new data server %s\n", __func__,
 			ds->ds_remotestr);
 	} else {
-		if (!_data_server_match_all_addrs_locked(&tmp_ds->ds_addrs,
-							 dsaddrs)) {
-			dprintk("%s:  multipath address mismatch: %s != %s",
-				__func__, tmp_ds->ds_remotestr, remotestr);
-		}
 		kfree(remotestr);
 		kfree(ds);
 		atomic_inc(&tmp_ds->ds_count);
@@ -378,7 +355,7 @@
  * Currently only supports ipv4, ipv6 and one multi-path address.
  */
 static struct nfs4_pnfs_ds_addr *
-decode_ds_addr(struct xdr_stream *streamp, gfp_t gfp_flags)
+decode_ds_addr(struct net *net, struct xdr_stream *streamp, gfp_t gfp_flags)
 {
 	struct nfs4_pnfs_ds_addr *da = NULL;
 	char *buf, *portstr;
@@ -457,7 +434,7 @@
 
 	INIT_LIST_HEAD(&da->da_node);
 
-	if (!rpc_pton(buf, portstr-buf, (struct sockaddr *)&da->da_addr,
+	if (!rpc_pton(net, buf, portstr-buf, (struct sockaddr *)&da->da_addr,
 		      sizeof(da->da_addr))) {
 		dprintk("%s: error parsing address %s\n", __func__, buf);
 		goto out_free_da;
@@ -554,7 +531,7 @@
 	cnt = be32_to_cpup(p);
 	dprintk("%s stripe count  %d\n", __func__, cnt);
 	if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) {
-		printk(KERN_WARNING "%s: stripe count %d greater than "
+		printk(KERN_WARNING "NFS: %s: stripe count %d greater than "
 		       "supported maximum %d\n", __func__,
 			cnt, NFS4_PNFS_MAX_STRIPE_CNT);
 		goto out_err_free_scratch;
@@ -585,7 +562,7 @@
 	num = be32_to_cpup(p);
 	dprintk("%s ds_num %u\n", __func__, num);
 	if (num > NFS4_PNFS_MAX_MULTI_CNT) {
-		printk(KERN_WARNING "%s: multipath count %d greater than "
+		printk(KERN_WARNING "NFS: %s: multipath count %d greater than "
 			"supported maximum %d\n", __func__,
 			num, NFS4_PNFS_MAX_MULTI_CNT);
 		goto out_err_free_stripe_indices;
@@ -593,7 +570,7 @@
 
 	/* validate stripe indices are all < num */
 	if (max_stripe_index >= num) {
-		printk(KERN_WARNING "%s: stripe index %u >= num ds %u\n",
+		printk(KERN_WARNING "NFS: %s: stripe index %u >= num ds %u\n",
 			__func__, max_stripe_index, num);
 		goto out_err_free_stripe_indices;
 	}
@@ -625,7 +602,8 @@
 
 		mp_count = be32_to_cpup(p); /* multipath count */
 		for (j = 0; j < mp_count; j++) {
-			da = decode_ds_addr(&stream, gfp_flags);
+			da = decode_ds_addr(NFS_SERVER(ino)->nfs_client->net,
+					    &stream, gfp_flags);
 			if (da)
 				list_add_tail(&da->da_node, &dsaddrs);
 		}
@@ -686,7 +664,7 @@
 
 	new = decode_device(inode, dev, gfp_flags);
 	if (!new) {
-		printk(KERN_WARNING "%s: Could not decode or add device\n",
+		printk(KERN_WARNING "NFS: %s: Could not decode or add device\n",
 			__func__);
 		return NULL;
 	}
@@ -835,7 +813,7 @@
 	struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
 
 	if (ds == NULL) {
-		printk(KERN_ERR "%s: No data server for offset index %d\n",
+		printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
 			__func__, ds_idx);
 		return NULL;
 	}
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index bb80c49..9c8eca31 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -94,13 +94,14 @@
 }
 
 static size_t nfs_parse_server_name(char *string, size_t len,
-		struct sockaddr *sa, size_t salen)
+		struct sockaddr *sa, size_t salen, struct nfs_server *server)
 {
+	struct net *net = rpc_net_ns(server->client);
 	ssize_t ret;
 
-	ret = rpc_pton(string, len, sa, salen);
+	ret = rpc_pton(net, string, len, sa, salen);
 	if (ret == 0) {
-		ret = nfs_dns_resolve_name(string, len, sa, salen);
+		ret = nfs_dns_resolve_name(net, string, len, sa, salen);
 		if (ret < 0)
 			ret = 0;
 	}
@@ -137,7 +138,8 @@
 			continue;
 
 		mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len,
-				mountdata->addr, addr_bufsize);
+				mountdata->addr, addr_bufsize,
+				NFS_SB(mountdata->sb));
 		if (mountdata->addrlen == 0)
 			continue;
 
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index caf92d0..f82bde0 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -72,18 +72,21 @@
 
 #define NFS4_MAX_LOOP_ON_RECOVER (10)
 
+static unsigned short max_session_slots = NFS4_DEF_SLOT_TABLE_SIZE;
+
 struct nfs4_opendata;
 static int _nfs4_proc_open(struct nfs4_opendata *data);
 static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
 static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
 static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *);
+static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
 static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
 static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 			    struct nfs_fattr *fattr, struct iattr *sattr,
 			    struct nfs4_state *state);
 #ifdef CONFIG_NFS_V4_1
-static int nfs41_test_stateid(struct nfs_server *, struct nfs4_state *);
-static int nfs41_free_stateid(struct nfs_server *, struct nfs4_state *);
+static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *);
+static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *);
 #endif
 /* Prevent leaks of NFSv4 errors into userland */
 static int nfs4_map_errors(int err)
@@ -259,19 +262,31 @@
 {
 	struct nfs_client *clp = server->nfs_client;
 	struct nfs4_state *state = exception->state;
+	struct inode *inode = exception->inode;
 	int ret = errorcode;
 
 	exception->retry = 0;
 	switch(errorcode) {
 		case 0:
 			return 0;
-		case -NFS4ERR_ADMIN_REVOKED:
-		case -NFS4ERR_BAD_STATEID:
 		case -NFS4ERR_OPENMODE:
+			if (inode && nfs_have_delegation(inode, FMODE_READ)) {
+				nfs_inode_return_delegation(inode);
+				exception->retry = 1;
+				return 0;
+			}
 			if (state == NULL)
 				break;
 			nfs4_schedule_stateid_recovery(server, state);
 			goto wait_on_recovery;
+		case -NFS4ERR_DELEG_REVOKED:
+		case -NFS4ERR_ADMIN_REVOKED:
+		case -NFS4ERR_BAD_STATEID:
+			if (state == NULL)
+				break;
+			nfs_remove_bad_delegation(state->inode);
+			nfs4_schedule_stateid_recovery(server, state);
+			goto wait_on_recovery;
 		case -NFS4ERR_EXPIRED:
 			if (state != NULL)
 				nfs4_schedule_stateid_recovery(server, state);
@@ -360,16 +375,14 @@
  * When updating highest_used_slotid there may be "holes" in the bitmap
  * so we need to scan down from highest_used_slotid to 0 looking for the now
  * highest slotid in use.
- * If none found, highest_used_slotid is set to -1.
+ * If none found, highest_used_slotid is set to NFS4_NO_SLOT.
  *
  * Must be called while holding tbl->slot_tbl_lock
  */
 static void
-nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid)
+nfs4_free_slot(struct nfs4_slot_table *tbl, u32 slotid)
 {
-	int slotid = free_slotid;
-
-	BUG_ON(slotid < 0 || slotid >= NFS4_MAX_SLOT_TABLE);
+	BUG_ON(slotid >= NFS4_MAX_SLOT_TABLE);
 	/* clear used bit in bitmap */
 	__clear_bit(slotid, tbl->used_slots);
 
@@ -379,10 +392,16 @@
 		if (slotid < tbl->max_slots)
 			tbl->highest_used_slotid = slotid;
 		else
-			tbl->highest_used_slotid = -1;
+			tbl->highest_used_slotid = NFS4_NO_SLOT;
 	}
-	dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__,
-		free_slotid, tbl->highest_used_slotid);
+	dprintk("%s: slotid %u highest_used_slotid %d\n", __func__,
+		slotid, tbl->highest_used_slotid);
+}
+
+bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy)
+{
+	rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
+	return true;
 }
 
 /*
@@ -390,16 +409,13 @@
  */
 static void nfs4_check_drain_fc_complete(struct nfs4_session *ses)
 {
-	struct rpc_task *task;
-
 	if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
-		task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq);
-		if (task)
-			rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
+		rpc_wake_up_first(&ses->fc_slot_table.slot_tbl_waitq,
+				nfs4_set_task_privileged, NULL);
 		return;
 	}
 
-	if (ses->fc_slot_table.highest_used_slotid != -1)
+	if (ses->fc_slot_table.highest_used_slotid != NFS4_NO_SLOT)
 		return;
 
 	dprintk("%s COMPLETE: Session Fore Channel Drained\n", __func__);
@@ -412,7 +428,7 @@
 void nfs4_check_drain_bc_complete(struct nfs4_session *ses)
 {
 	if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state) ||
-	    ses->bc_slot_table.highest_used_slotid != -1)
+	    ses->bc_slot_table.highest_used_slotid != NFS4_NO_SLOT)
 		return;
 	dprintk("%s COMPLETE: Session Back Channel Drained\n", __func__);
 	complete(&ses->bc_slot_table.complete);
@@ -507,25 +523,25 @@
  * nfs4_find_slot looks for an unset bit in the used_slots bitmap.
  * If found, we mark the slot as used, update the highest_used_slotid,
  * and respectively set up the sequence operation args.
- * The slot number is returned if found, or NFS4_MAX_SLOT_TABLE otherwise.
+ * The slot number is returned if found, or NFS4_NO_SLOT otherwise.
  *
  * Note: must be called with under the slot_tbl_lock.
  */
-static u8
+static u32
 nfs4_find_slot(struct nfs4_slot_table *tbl)
 {
-	int slotid;
-	u8 ret_id = NFS4_MAX_SLOT_TABLE;
-	BUILD_BUG_ON((u8)NFS4_MAX_SLOT_TABLE != (int)NFS4_MAX_SLOT_TABLE);
+	u32 slotid;
+	u32 ret_id = NFS4_NO_SLOT;
 
-	dprintk("--> %s used_slots=%04lx highest_used=%d max_slots=%d\n",
+	dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n",
 		__func__, tbl->used_slots[0], tbl->highest_used_slotid,
 		tbl->max_slots);
 	slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slots);
 	if (slotid >= tbl->max_slots)
 		goto out;
 	__set_bit(slotid, tbl->used_slots);
-	if (slotid > tbl->highest_used_slotid)
+	if (slotid > tbl->highest_used_slotid ||
+			tbl->highest_used_slotid == NFS4_NO_SLOT)
 		tbl->highest_used_slotid = slotid;
 	ret_id = slotid;
 out:
@@ -534,15 +550,25 @@
 	return ret_id;
 }
 
+static void nfs41_init_sequence(struct nfs4_sequence_args *args,
+		struct nfs4_sequence_res *res, int cache_reply)
+{
+	args->sa_session = NULL;
+	args->sa_cache_this = 0;
+	if (cache_reply)
+		args->sa_cache_this = 1;
+	res->sr_session = NULL;
+	res->sr_slot = NULL;
+}
+
 int nfs41_setup_sequence(struct nfs4_session *session,
 				struct nfs4_sequence_args *args,
 				struct nfs4_sequence_res *res,
-				int cache_reply,
 				struct rpc_task *task)
 {
 	struct nfs4_slot *slot;
 	struct nfs4_slot_table *tbl;
-	u8 slotid;
+	u32 slotid;
 
 	dprintk("--> %s\n", __func__);
 	/* slot already allocated? */
@@ -570,7 +596,7 @@
 	}
 
 	slotid = nfs4_find_slot(tbl);
-	if (slotid == NFS4_MAX_SLOT_TABLE) {
+	if (slotid == NFS4_NO_SLOT) {
 		rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
 		spin_unlock(&tbl->slot_tbl_lock);
 		dprintk("<-- %s: no free slots\n", __func__);
@@ -582,7 +608,6 @@
 	slot = tbl->slots + slotid;
 	args->sa_session = session;
 	args->sa_slotid = slotid;
-	args->sa_cache_this = cache_reply;
 
 	dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr);
 
@@ -602,24 +627,19 @@
 int nfs4_setup_sequence(const struct nfs_server *server,
 			struct nfs4_sequence_args *args,
 			struct nfs4_sequence_res *res,
-			int cache_reply,
 			struct rpc_task *task)
 {
 	struct nfs4_session *session = nfs4_get_session(server);
 	int ret = 0;
 
-	if (session == NULL) {
-		args->sa_session = NULL;
-		res->sr_session = NULL;
+	if (session == NULL)
 		goto out;
-	}
 
 	dprintk("--> %s clp %p session %p sr_slot %td\n",
 		__func__, session->clp, session, res->sr_slot ?
 			res->sr_slot - session->fc_slot_table.slots : -1);
 
-	ret = nfs41_setup_sequence(session, args, res, cache_reply,
-				   task);
+	ret = nfs41_setup_sequence(session, args, res, task);
 out:
 	dprintk("<-- %s status=%d\n", __func__, ret);
 	return ret;
@@ -629,7 +649,6 @@
 	const struct nfs_server *seq_server;
 	struct nfs4_sequence_args *seq_args;
 	struct nfs4_sequence_res *seq_res;
-	int cache_reply;
 };
 
 static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
@@ -639,7 +658,7 @@
 	dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server);
 
 	if (nfs4_setup_sequence(data->seq_server, data->seq_args,
-				data->seq_res, data->cache_reply, task))
+				data->seq_res, task))
 		return;
 	rpc_call_start(task);
 }
@@ -657,12 +676,12 @@
 	nfs41_sequence_done(task, data->seq_res);
 }
 
-struct rpc_call_ops nfs41_call_sync_ops = {
+static const struct rpc_call_ops nfs41_call_sync_ops = {
 	.rpc_call_prepare = nfs41_call_sync_prepare,
 	.rpc_call_done = nfs41_call_sync_done,
 };
 
-struct rpc_call_ops nfs41_call_priv_sync_ops = {
+static const struct rpc_call_ops nfs41_call_priv_sync_ops = {
 	.rpc_call_prepare = nfs41_call_priv_sync_prepare,
 	.rpc_call_done = nfs41_call_sync_done,
 };
@@ -672,7 +691,6 @@
 				   struct rpc_message *msg,
 				   struct nfs4_sequence_args *args,
 				   struct nfs4_sequence_res *res,
-				   int cache_reply,
 				   int privileged)
 {
 	int ret;
@@ -681,7 +699,6 @@
 		.seq_server = server,
 		.seq_args = args,
 		.seq_res = res,
-		.cache_reply = cache_reply,
 	};
 	struct rpc_task_setup task_setup = {
 		.rpc_client = clnt,
@@ -690,7 +707,6 @@
 		.callback_data = &data
 	};
 
-	res->sr_slot = NULL;
 	if (privileged)
 		task_setup.callback_ops = &nfs41_call_priv_sync_ops;
 	task = rpc_run_task(&task_setup);
@@ -710,10 +726,17 @@
 			    struct nfs4_sequence_res *res,
 			    int cache_reply)
 {
-	return nfs4_call_sync_sequence(clnt, server, msg, args, res, cache_reply, 0);
+	nfs41_init_sequence(args, res, cache_reply);
+	return nfs4_call_sync_sequence(clnt, server, msg, args, res, 0);
 }
 
 #else
+static inline
+void nfs41_init_sequence(struct nfs4_sequence_args *args,
+		struct nfs4_sequence_res *res, int cache_reply)
+{
+}
+
 static int nfs4_sequence_done(struct rpc_task *task,
 			       struct nfs4_sequence_res *res)
 {
@@ -728,7 +751,7 @@
 		    struct nfs4_sequence_res *res,
 		    int cache_reply)
 {
-	args->sa_session = res->sr_session = NULL;
+	nfs41_init_sequence(args, res, cache_reply);
 	return rpc_call_sync(clnt, msg, 0);
 }
 
@@ -815,20 +838,22 @@
 	p->o_arg.open_flags = flags;
 	p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
 	p->o_arg.clientid = server->nfs_client->cl_clientid;
-	p->o_arg.id = sp->so_owner_id.id;
+	p->o_arg.id = sp->so_seqid.owner_id;
 	p->o_arg.name = &dentry->d_name;
 	p->o_arg.server = server;
 	p->o_arg.bitmask = server->attr_bitmask;
 	p->o_arg.dir_bitmask = server->cache_consistency_bitmask;
 	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
-	if (flags & O_CREAT) {
-		u32 *s;
+	if (attrs != NULL && attrs->ia_valid != 0) {
+		__be32 verf[2];
 
 		p->o_arg.u.attrs = &p->attrs;
 		memcpy(&p->attrs, attrs, sizeof(p->attrs));
-		s = (u32 *) p->o_arg.u.verifier.data;
-		s[0] = jiffies;
-		s[1] = current->pid;
+
+		verf[0] = jiffies;
+		verf[1] = current->pid;
+		memcpy(p->o_arg.u.verifier.data, verf,
+				sizeof(p->o_arg.u.verifier.data));
 	}
 	p->c_arg.fh = &p->o_res.fh;
 	p->c_arg.stateid = &p->o_res.stateid;
@@ -878,7 +903,7 @@
 {
 	int ret = 0;
 
-	if (open_mode & O_EXCL)
+	if (open_mode & (O_EXCL|O_TRUNC))
 		goto out;
 	switch (mode & (FMODE_READ|FMODE_WRITE)) {
 		case FMODE_READ:
@@ -927,8 +952,8 @@
 static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
 {
 	if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
-		memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data));
-	memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data));
+		nfs4_stateid_copy(&state->stateid, stateid);
+	nfs4_stateid_copy(&state->open_stateid, stateid);
 	switch (fmode) {
 		case FMODE_READ:
 			set_bit(NFS_O_RDONLY_STATE, &state->flags);
@@ -956,7 +981,7 @@
 	 */
 	write_seqlock(&state->seqlock);
 	if (deleg_stateid != NULL) {
-		memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data));
+		nfs4_stateid_copy(&state->stateid, deleg_stateid);
 		set_bit(NFS_DELEGATED_STATE, &state->flags);
 	}
 	if (open_stateid != NULL)
@@ -987,7 +1012,7 @@
 
 	if (delegation == NULL)
 		delegation = &deleg_cur->stateid;
-	else if (memcmp(deleg_cur->stateid.data, delegation->data, NFS4_STATEID_SIZE) != 0)
+	else if (!nfs4_stateid_match(&deleg_cur->stateid, delegation))
 		goto no_delegation_unlock;
 
 	nfs_mark_delegation_referenced(deleg_cur);
@@ -1026,7 +1051,7 @@
 	struct nfs4_state *state = opendata->state;
 	struct nfs_inode *nfsi = NFS_I(state->inode);
 	struct nfs_delegation *delegation;
-	int open_mode = opendata->o_arg.open_flags & O_EXCL;
+	int open_mode = opendata->o_arg.open_flags & (O_EXCL|O_TRUNC);
 	fmode_t fmode = opendata->o_arg.fmode;
 	nfs4_stateid stateid;
 	int ret = -EAGAIN;
@@ -1048,7 +1073,7 @@
 			break;
 		}
 		/* Save the delegation */
-		memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data));
+		nfs4_stateid_copy(&stateid, &delegation->stateid);
 		rcu_read_unlock();
 		ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
 		if (ret != 0)
@@ -1090,6 +1115,7 @@
 	if (state == NULL)
 		goto err_put_inode;
 	if (data->o_res.delegation_type != 0) {
+		struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
 		int delegation_flags = 0;
 
 		rcu_read_lock();
@@ -1101,7 +1127,7 @@
 			pr_err_ratelimited("NFS: Broken NFSv4 server %s is "
 					"returning a delegation for "
 					"OPEN(CLAIM_DELEGATE_CUR)\n",
-					NFS_CLIENT(inode)->cl_server);
+					clp->cl_hostname);
 		} else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
 			nfs_inode_set_delegation(state->inode,
 					data->owner->so_cred,
@@ -1210,10 +1236,10 @@
 	 * Check if we need to update the current stateid.
 	 */
 	if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 &&
-	    memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) {
+	    !nfs4_stateid_match(&state->stateid, &state->open_stateid)) {
 		write_seqlock(&state->seqlock);
 		if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
-			memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data));
+			nfs4_stateid_copy(&state->stateid, &state->open_stateid);
 		write_sequnlock(&state->seqlock);
 	}
 	return 0;
@@ -1282,8 +1308,7 @@
 	if (IS_ERR(opendata))
 		return PTR_ERR(opendata);
 	opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR;
-	memcpy(opendata->o_arg.u.delegation.data, stateid->data,
-			sizeof(opendata->o_arg.u.delegation.data));
+	nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
 	ret = nfs4_open_recover(opendata, state);
 	nfs4_opendata_put(opendata);
 	return ret;
@@ -1319,8 +1344,11 @@
 				 * The show must go on: exit, but mark the
 				 * stateid as needing recovery.
 				 */
+			case -NFS4ERR_DELEG_REVOKED:
 			case -NFS4ERR_ADMIN_REVOKED:
 			case -NFS4ERR_BAD_STATEID:
+				nfs_inode_find_state_and_recover(state->inode,
+						stateid);
 				nfs4_schedule_stateid_recovery(server, state);
 			case -EKEYEXPIRED:
 				/*
@@ -1345,8 +1373,7 @@
 
 	data->rpc_status = task->tk_status;
 	if (data->rpc_status == 0) {
-		memcpy(data->o_res.stateid.data, data->c_res.stateid.data,
-				sizeof(data->o_res.stateid.data));
+		nfs4_stateid_copy(&data->o_res.stateid, &data->c_res.stateid);
 		nfs_confirm_seqid(&data->owner->so_seqid, 0);
 		renew_lease(data->o_res.server, data->timestamp);
 		data->rpc_done = 1;
@@ -1440,7 +1467,7 @@
 		rcu_read_unlock();
 	}
 	/* Update sequence id. */
-	data->o_arg.id = sp->so_owner_id.id;
+	data->o_arg.id = sp->so_seqid.owner_id;
 	data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;
 	if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
 		task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
@@ -1449,7 +1476,7 @@
 	data->timestamp = jiffies;
 	if (nfs4_setup_sequence(data->o_arg.server,
 				&data->o_arg.seq_args,
-				&data->o_res.seq_res, 1, task))
+				&data->o_res.seq_res, task))
 		return;
 	rpc_call_start(task);
 	return;
@@ -1551,6 +1578,7 @@
 	};
 	int status;
 
+	nfs41_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1);
 	kref_get(&data->kref);
 	data->rpc_done = 0;
 	data->rpc_status = 0;
@@ -1712,15 +1740,32 @@
 }
 
 #if defined(CONFIG_NFS_V4_1)
-static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
+static int nfs41_check_expired_stateid(struct nfs4_state *state, nfs4_stateid *stateid, unsigned int flags)
 {
-	int status;
+	int status = NFS_OK;
 	struct nfs_server *server = NFS_SERVER(state->inode);
 
-	status = nfs41_test_stateid(server, state);
-	if (status == NFS_OK)
-		return 0;
-	nfs41_free_stateid(server, state);
+	if (state->flags & flags) {
+		status = nfs41_test_stateid(server, stateid);
+		if (status != NFS_OK) {
+			nfs41_free_stateid(server, stateid);
+			state->flags &= ~flags;
+		}
+	}
+	return status;
+}
+
+static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
+{
+	int deleg_status, open_status;
+	int deleg_flags = 1 << NFS_DELEGATED_STATE;
+	int open_flags = (1 << NFS_O_RDONLY_STATE) | (1 << NFS_O_WRONLY_STATE) | (1 << NFS_O_RDWR_STATE);
+
+	deleg_status = nfs41_check_expired_stateid(state, &state->stateid, deleg_flags);
+	open_status = nfs41_check_expired_stateid(state,  &state->open_stateid, open_flags);
+
+	if ((deleg_status == NFS_OK) && (open_status == NFS_OK))
+		return NFS_OK;
 	return nfs4_open_expired(sp, state);
 }
 #endif
@@ -1754,7 +1799,8 @@
 
 	/* Protect against reboot recovery conflicts */
 	status = -ENOMEM;
-	if (!(sp = nfs4_get_state_owner(server, cred))) {
+	sp = nfs4_get_state_owner(server, cred, GFP_KERNEL);
+	if (sp == NULL) {
 		dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n");
 		goto out_err;
 	}
@@ -1829,7 +1875,7 @@
 		 * the user though...
 		 */
 		if (status == -NFS4ERR_BAD_SEQID) {
-			printk(KERN_WARNING "NFS: v4 server %s "
+			pr_warn_ratelimited("NFS: v4 server %s "
 					" returned a bad sequence-id error!\n",
 					NFS_SERVER(dir)->nfs_client->cl_hostname);
 			exception.retry = 1;
@@ -1882,12 +1928,14 @@
 
 	nfs_fattr_init(fattr);
 
-	if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) {
+	if (state != NULL) {
+		nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
+				current->files, current->tgid);
+	} else if (nfs4_copy_delegation_stateid(&arg.stateid, inode,
+				FMODE_WRITE)) {
 		/* Use that stateid */
-	} else if (state != NULL) {
-		nfs4_copy_stateid(&arg.stateid, state, current->files, current->tgid);
 	} else
-		memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));
+		nfs4_stateid_copy(&arg.stateid, &zero_stateid);
 
 	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
 	if (status == 0 && state != NULL)
@@ -1900,7 +1948,10 @@
 			   struct nfs4_state *state)
 {
 	struct nfs_server *server = NFS_SERVER(inode);
-	struct nfs4_exception exception = { };
+	struct nfs4_exception exception = {
+		.state = state,
+		.inode = inode,
+	};
 	int err;
 	do {
 		err = nfs4_handle_exception(server,
@@ -1954,6 +2005,7 @@
 	struct nfs4_state *state = calldata->state;
 	struct nfs_server *server = NFS_SERVER(calldata->inode);
 
+	dprintk("%s: begin!\n", __func__);
 	if (!nfs4_sequence_done(task, &calldata->res.seq_res))
 		return;
         /* hmm. we are done with the inode, and in the process of freeing
@@ -1981,6 +2033,7 @@
 	}
 	nfs_release_seqid(calldata->arg.seqid);
 	nfs_refresh_inode(calldata->inode, calldata->res.fattr);
+	dprintk("%s: done, ret = %d!\n", __func__, task->tk_status);
 }
 
 static void nfs4_close_prepare(struct rpc_task *task, void *data)
@@ -1989,6 +2042,7 @@
 	struct nfs4_state *state = calldata->state;
 	int call_close = 0;
 
+	dprintk("%s: begin!\n", __func__);
 	if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
 		return;
 
@@ -2013,7 +2067,7 @@
 	if (!call_close) {
 		/* Note: exit _without_ calling nfs4_close_done */
 		task->tk_action = NULL;
-		return;
+		goto out;
 	}
 
 	if (calldata->arg.fmode == 0) {
@@ -2022,17 +2076,20 @@
 		    pnfs_roc_drain(calldata->inode, &calldata->roc_barrier)) {
 			rpc_sleep_on(&NFS_SERVER(calldata->inode)->roc_rpcwaitq,
 				     task, NULL);
-			return;
+			goto out;
 		}
 	}
 
 	nfs_fattr_init(calldata->res.fattr);
 	calldata->timestamp = jiffies;
 	if (nfs4_setup_sequence(NFS_SERVER(calldata->inode),
-				&calldata->arg.seq_args, &calldata->res.seq_res,
-				1, task))
-		return;
+				&calldata->arg.seq_args,
+				&calldata->res.seq_res,
+				task))
+		goto out;
 	rpc_call_start(task);
+out:
+	dprintk("%s: done!\n", __func__);
 }
 
 static const struct rpc_call_ops nfs4_close_ops = {
@@ -2074,6 +2131,7 @@
 	calldata = kzalloc(sizeof(*calldata), gfp_mask);
 	if (calldata == NULL)
 		goto out;
+	nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 1);
 	calldata->inode = state->inode;
 	calldata->state = state;
 	calldata->arg.fh = NFS_FH(state->inode);
@@ -2182,6 +2240,7 @@
 		server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
 		server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
 		server->acl_bitmask = res.acl_bitmask;
+		server->fh_expire_type = res.fh_expire_type;
 	}
 
 	return status;
@@ -2230,11 +2289,12 @@
 		switch (err) {
 		case 0:
 		case -NFS4ERR_WRONGSEC:
-			break;
+			goto out;
 		default:
 			err = nfs4_handle_exception(server, err, &exception);
 		}
 	} while (exception.retry);
+out:
 	return err;
 }
 
@@ -2303,7 +2363,6 @@
 	return nfs4_map_errors(status);
 }
 
-static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
 /*
  * Get locations and (maybe) other attributes of a referral.
  * Note that we'll actually follow the referral later when
@@ -2420,6 +2479,10 @@
 		}
 	}
 
+	/* Deal with open(O_TRUNC) */
+	if (sattr->ia_valid & ATTR_OPEN)
+		sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
+
 	status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
 	if (status == 0)
 		nfs_setattr_update_inode(inode, sattr);
@@ -2494,7 +2557,7 @@
 	struct nfs_server *server = NFS_SERVER(inode);
 	struct nfs4_accessargs args = {
 		.fh = NFS_FH(inode),
-		.bitmask = server->attr_bitmask,
+		.bitmask = server->cache_consistency_bitmask,
 	};
 	struct nfs4_accessres res = {
 		.server = server,
@@ -2712,8 +2775,18 @@
 
 	args->bitmask = server->cache_consistency_bitmask;
 	res->server = server;
-	res->seq_res.sr_slot = NULL;
 	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
+	nfs41_init_sequence(&args->seq_args, &res->seq_res, 1);
+}
+
+static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
+{
+	if (nfs4_setup_sequence(NFS_SERVER(data->dir),
+				&data->args.seq_args,
+				&data->res.seq_res,
+				task))
+		return;
+	rpc_call_start(task);
 }
 
 static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
@@ -2738,6 +2811,17 @@
 	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
 	arg->bitmask = server->attr_bitmask;
 	res->server = server;
+	nfs41_init_sequence(&arg->seq_args, &res->seq_res, 1);
+}
+
+static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
+{
+	if (nfs4_setup_sequence(NFS_SERVER(data->old_dir),
+				&data->args.seq_args,
+				&data->res.seq_res,
+				task))
+		return;
+	rpc_call_start(task);
 }
 
 static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
@@ -3232,6 +3316,17 @@
 	data->timestamp   = jiffies;
 	data->read_done_cb = nfs4_read_done_cb;
 	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ];
+	nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
+}
+
+static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
+{
+	if (nfs4_setup_sequence(NFS_SERVER(data->inode),
+				&data->args.seq_args,
+				&data->res.seq_res,
+				task))
+		return;
+	rpc_call_start(task);
 }
 
 /* Reset the the nfs_read_data to send the read to the MDS. */
@@ -3305,6 +3400,17 @@
 	data->timestamp   = jiffies;
 
 	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE];
+	nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+}
+
+static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
+{
+	if (nfs4_setup_sequence(NFS_SERVER(data->inode),
+				&data->args.seq_args,
+				&data->res.seq_res,
+				task))
+		return;
+	rpc_call_start(task);
 }
 
 static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_write_data *data)
@@ -3339,6 +3445,7 @@
 		data->write_done_cb = nfs4_commit_done_cb;
 	data->res.server = server;
 	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
+	nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
 }
 
 struct nfs4_renewdata {
@@ -3605,7 +3712,7 @@
 		if (acl_len > buflen)
 			goto out_free;
 		_copy_from_pages(buf, pages, res.acl_data_offset,
-				res.acl_len);
+				acl_len);
 	}
 	ret = acl_len;
 out_free:
@@ -3714,8 +3821,12 @@
 	if (task->tk_status >= 0)
 		return 0;
 	switch(task->tk_status) {
+		case -NFS4ERR_DELEG_REVOKED:
 		case -NFS4ERR_ADMIN_REVOKED:
 		case -NFS4ERR_BAD_STATEID:
+			if (state == NULL)
+				break;
+			nfs_remove_bad_delegation(state->inode);
 		case -NFS4ERR_OPENMODE:
 			if (state == NULL)
 				break;
@@ -3764,6 +3875,16 @@
 	return -EAGAIN;
 }
 
+static void nfs4_construct_boot_verifier(struct nfs_client *clp,
+					 nfs4_verifier *bootverf)
+{
+	__be32 verf[2];
+
+	verf[0] = htonl((u32)clp->cl_boot_time.tv_sec);
+	verf[1] = htonl((u32)clp->cl_boot_time.tv_nsec);
+	memcpy(bootverf->data, verf, sizeof(bootverf->data));
+}
+
 int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
 		unsigned short port, struct rpc_cred *cred,
 		struct nfs4_setclientid_res *res)
@@ -3780,15 +3901,13 @@
 		.rpc_resp = res,
 		.rpc_cred = cred,
 	};
-	__be32 *p;
 	int loop = 0;
 	int status;
 
-	p = (__be32*)sc_verifier.data;
-	*p++ = htonl((u32)clp->cl_boot_time.tv_sec);
-	*p = htonl((u32)clp->cl_boot_time.tv_nsec);
+	nfs4_construct_boot_verifier(clp, &sc_verifier);
 
 	for(;;) {
+		rcu_read_lock();
 		setclientid.sc_name_len = scnprintf(setclientid.sc_name,
 				sizeof(setclientid.sc_name), "%s/%s %s %s %u",
 				clp->cl_ipaddr,
@@ -3805,6 +3924,7 @@
 		setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
 				sizeof(setclientid.sc_uaddr), "%s.%u.%u",
 				clp->cl_ipaddr, port >> 8, port & 255);
+		rcu_read_unlock();
 
 		status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
 		if (status != -NFS4ERR_CLID_INUSE)
@@ -3891,7 +4011,7 @@
 
 	if (nfs4_setup_sequence(d_data->res.server,
 				&d_data->args.seq_args,
-				&d_data->res.seq_res, 1, task))
+				&d_data->res.seq_res, task))
 		return;
 	rpc_call_start(task);
 }
@@ -3925,11 +4045,12 @@
 	data = kzalloc(sizeof(*data), GFP_NOFS);
 	if (data == NULL)
 		return -ENOMEM;
+	nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
 	data->args.fhandle = &data->fh;
 	data->args.stateid = &data->stateid;
 	data->args.bitmask = server->attr_bitmask;
 	nfs_copy_fh(&data->fh, NFS_FH(inode));
-	memcpy(&data->stateid, stateid, sizeof(data->stateid));
+	nfs4_stateid_copy(&data->stateid, stateid);
 	data->res.fattr = &data->fattr;
 	data->res.server = server;
 	nfs_fattr_init(data->res.fattr);
@@ -4016,7 +4137,7 @@
 	if (status != 0)
 		goto out;
 	lsp = request->fl_u.nfs4_fl.owner;
-	arg.lock_owner.id = lsp->ls_id.id;
+	arg.lock_owner.id = lsp->ls_seqid.owner_id;
 	arg.lock_owner.s_dev = server->s_dev;
 	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
 	switch (status) {
@@ -4112,9 +4233,8 @@
 		return;
 	switch (task->tk_status) {
 		case 0:
-			memcpy(calldata->lsp->ls_stateid.data,
-					calldata->res.stateid.data,
-					sizeof(calldata->lsp->ls_stateid.data));
+			nfs4_stateid_copy(&calldata->lsp->ls_stateid,
+					&calldata->res.stateid);
 			renew_lease(calldata->server, calldata->timestamp);
 			break;
 		case -NFS4ERR_BAD_STATEID:
@@ -4142,7 +4262,7 @@
 	calldata->timestamp = jiffies;
 	if (nfs4_setup_sequence(calldata->server,
 				&calldata->arg.seq_args,
-				&calldata->res.seq_res, 1, task))
+				&calldata->res.seq_res, task))
 		return;
 	rpc_call_start(task);
 }
@@ -4182,6 +4302,7 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
+	nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
 	msg.rpc_argp = &data->arg;
 	msg.rpc_resp = &data->res;
 	task_setup_data.callback_data = data;
@@ -4261,7 +4382,7 @@
 		goto out_free_seqid;
 	p->arg.lock_stateid = &lsp->ls_stateid;
 	p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
-	p->arg.lock_owner.id = lsp->ls_id.id;
+	p->arg.lock_owner.id = lsp->ls_seqid.owner_id;
 	p->arg.lock_owner.s_dev = server->s_dev;
 	p->res.lock_seqid = p->arg.lock_seqid;
 	p->lsp = lsp;
@@ -4297,7 +4418,7 @@
 	data->timestamp = jiffies;
 	if (nfs4_setup_sequence(data->server,
 				&data->arg.seq_args,
-				&data->res.seq_res, 1, task))
+				&data->res.seq_res, task))
 		return;
 	rpc_call_start(task);
 	dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
@@ -4326,8 +4447,7 @@
 			goto out;
 	}
 	if (data->rpc_status == 0) {
-		memcpy(data->lsp->ls_stateid.data, data->res.stateid.data,
-					sizeof(data->lsp->ls_stateid.data));
+		nfs4_stateid_copy(&data->lsp->ls_stateid, &data->res.stateid);
 		data->lsp->ls_flags |= NFS_LOCK_INITIALIZED;
 		renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp);
 	}
@@ -4415,6 +4535,7 @@
 			data->arg.reclaim = NFS_LOCK_RECLAIM;
 		task_setup_data.callback_ops = &nfs4_recover_lock_ops;
 	}
+	nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
 	msg.rpc_argp = &data->arg;
 	msg.rpc_resp = &data->res;
 	task_setup_data.callback_data = data;
@@ -4479,15 +4600,34 @@
 }
 
 #if defined(CONFIG_NFS_V4_1)
-static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
+static int nfs41_check_expired_locks(struct nfs4_state *state)
 {
-	int status;
+	int status, ret = NFS_OK;
+	struct nfs4_lock_state *lsp;
 	struct nfs_server *server = NFS_SERVER(state->inode);
 
-	status = nfs41_test_stateid(server, state);
+	list_for_each_entry(lsp, &state->lock_states, ls_locks) {
+		if (lsp->ls_flags & NFS_LOCK_INITIALIZED) {
+			status = nfs41_test_stateid(server, &lsp->ls_stateid);
+			if (status != NFS_OK) {
+				nfs41_free_stateid(server, &lsp->ls_stateid);
+				lsp->ls_flags &= ~NFS_LOCK_INITIALIZED;
+				ret = status;
+			}
+		}
+	};
+
+	return ret;
+}
+
+static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
+{
+	int status = NFS_OK;
+
+	if (test_bit(LK_STATE_IN_USE, &state->flags))
+		status = nfs41_check_expired_locks(state);
 	if (status == NFS_OK)
-		return 0;
-	nfs41_free_stateid(server, state);
+		return status;
 	return nfs4_lock_expired(state, request);
 }
 #endif
@@ -4523,7 +4663,8 @@
 	/* Note: we always want to sleep here! */
 	request->fl_flags = fl_flags | FL_SLEEP;
 	if (do_vfs_lock(request->fl_file, request) < 0)
-		printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __func__);
+		printk(KERN_WARNING "NFS: %s: VFS is out of sync with lock "
+			"manager!\n", __func__);
 out_unlock:
 	up_read(&nfsi->rwsem);
 out:
@@ -4533,7 +4674,9 @@
 
 static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
 {
-	struct nfs4_exception exception = { };
+	struct nfs4_exception exception = {
+		.state = state,
+	};
 	int err;
 
 	do {
@@ -4603,8 +4746,8 @@
 		err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
 		switch (err) {
 			default:
-				printk(KERN_ERR "%s: unhandled error %d.\n",
-						__func__, err);
+				printk(KERN_ERR "NFS: %s: unhandled error "
+					"%d.\n", __func__, err);
 			case 0:
 			case -ESTALE:
 				goto out;
@@ -4626,6 +4769,7 @@
 				 * The show must go on: exit, but mark the
 				 * stateid as needing recovery.
 				 */
+			case -NFS4ERR_DELEG_REVOKED:
 			case -NFS4ERR_ADMIN_REVOKED:
 			case -NFS4ERR_BAD_STATEID:
 			case -NFS4ERR_OPENMODE:
@@ -4655,33 +4799,44 @@
 	return err;
 }
 
+struct nfs_release_lockowner_data {
+	struct nfs4_lock_state *lsp;
+	struct nfs_server *server;
+	struct nfs_release_lockowner_args args;
+};
+
 static void nfs4_release_lockowner_release(void *calldata)
 {
+	struct nfs_release_lockowner_data *data = calldata;
+	nfs4_free_lock_state(data->server, data->lsp);
 	kfree(calldata);
 }
 
-const struct rpc_call_ops nfs4_release_lockowner_ops = {
+static const struct rpc_call_ops nfs4_release_lockowner_ops = {
 	.rpc_release = nfs4_release_lockowner_release,
 };
 
-void nfs4_release_lockowner(const struct nfs4_lock_state *lsp)
+int nfs4_release_lockowner(struct nfs4_lock_state *lsp)
 {
 	struct nfs_server *server = lsp->ls_state->owner->so_server;
-	struct nfs_release_lockowner_args *args;
+	struct nfs_release_lockowner_data *data;
 	struct rpc_message msg = {
 		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER],
 	};
 
 	if (server->nfs_client->cl_mvops->minor_version != 0)
-		return;
-	args = kmalloc(sizeof(*args), GFP_NOFS);
-	if (!args)
-		return;
-	args->lock_owner.clientid = server->nfs_client->cl_clientid;
-	args->lock_owner.id = lsp->ls_id.id;
-	args->lock_owner.s_dev = server->s_dev;
-	msg.rpc_argp = args;
-	rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args);
+		return -EINVAL;
+	data = kmalloc(sizeof(*data), GFP_NOFS);
+	if (!data)
+		return -ENOMEM;
+	data->lsp = lsp;
+	data->server = server;
+	data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
+	data->args.lock_owner.id = lsp->ls_seqid.owner_id;
+	data->args.lock_owner.s_dev = server->s_dev;
+	msg.rpc_argp = &data->args;
+	rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
+	return 0;
 }
 
 #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
@@ -4727,11 +4882,11 @@
 	if (!(((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) ||
 	       (fattr->valid & NFS_ATTR_FATTR_FILEID)) &&
 	      (fattr->valid & NFS_ATTR_FATTR_FSID) &&
-	      (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)))
+	      (fattr->valid & NFS_ATTR_FATTR_V4_LOCATIONS)))
 		return;
 
 	fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
-		NFS_ATTR_FATTR_NLINK;
+		NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_V4_REFERRAL;
 	fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
 	fattr->nlink = 2;
 }
@@ -4798,7 +4953,8 @@
 	return status;
 }
 
-int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors)
+static int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name,
+		struct nfs4_secinfo_flavors *flavors)
 {
 	struct nfs4_exception exception = { };
 	int err;
@@ -4852,6 +5008,7 @@
 {
 	nfs4_verifier verifier;
 	struct nfs41_exchange_id_args args = {
+		.verifier = &verifier,
 		.client = clp,
 		.flags = EXCHGID4_FLAG_SUPP_MOVED_REFER,
 	};
@@ -4865,15 +5022,11 @@
 		.rpc_resp = &res,
 		.rpc_cred = cred,
 	};
-	__be32 *p;
 
 	dprintk("--> %s\n", __func__);
 	BUG_ON(clp == NULL);
 
-	p = (u32 *)verifier.data;
-	*p++ = htonl((u32)clp->cl_boot_time.tv_sec);
-	*p = htonl((u32)clp->cl_boot_time.tv_nsec);
-	args.verifier = &verifier;
+	nfs4_construct_boot_verifier(clp, &verifier);
 
 	args.id_len = scnprintf(args.id, sizeof(args.id),
 				"%s/%s.%s/%u",
@@ -4888,11 +5041,24 @@
 		goto out;
 	}
 
+	res.impl_id = kzalloc(sizeof(struct nfs41_impl_id), GFP_KERNEL);
+	if (unlikely(!res.impl_id)) {
+		status = -ENOMEM;
+		goto out_server_scope;
+	}
+
 	status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
 	if (!status)
 		status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);
 
 	if (!status) {
+		/* use the most recent implementation id */
+		kfree(clp->impl_id);
+		clp->impl_id = res.impl_id;
+	} else
+		kfree(res.impl_id);
+
+	if (!status) {
 		if (clp->server_scope &&
 		    !nfs41_same_server_scope(clp->server_scope,
 					     res.server_scope)) {
@@ -4908,8 +5074,16 @@
 			goto out;
 		}
 	}
+
+out_server_scope:
 	kfree(res.server_scope);
 out:
+	if (clp->impl_id)
+		dprintk("%s: Server Implementation ID: "
+			"domain: %s, name: %s, date: %llu,%u\n",
+			__func__, clp->impl_id->domain, clp->impl_id->name,
+			clp->impl_id->date.seconds,
+			clp->impl_id->date.nseconds);
 	dprintk("<-- %s status= %d\n", __func__, status);
 	return status;
 }
@@ -4933,7 +5107,7 @@
 	   since we're invoked within one */
 	ret = nfs41_setup_sequence(data->clp->cl_session,
 				   &data->args->la_seq_args,
-				   &data->res->lr_seq_res, 0, task);
+				   &data->res->lr_seq_res, task);
 
 	BUG_ON(ret == -EAGAIN);
 	rpc_call_start(task);
@@ -4966,7 +5140,7 @@
 	dprintk("<-- %s\n", __func__);
 }
 
-struct rpc_call_ops nfs4_get_lease_time_ops = {
+static const struct rpc_call_ops nfs4_get_lease_time_ops = {
 	.rpc_call_prepare = nfs4_get_lease_time_prepare,
 	.rpc_call_done = nfs4_get_lease_time_done,
 };
@@ -4997,6 +5171,7 @@
 	};
 	int status;
 
+	nfs41_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0);
 	dprintk("--> %s\n", __func__);
 	task = rpc_run_task(&task_setup);
 
@@ -5113,13 +5288,13 @@
 		return NULL;
 
 	tbl = &session->fc_slot_table;
-	tbl->highest_used_slotid = -1;
+	tbl->highest_used_slotid = NFS4_NO_SLOT;
 	spin_lock_init(&tbl->slot_tbl_lock);
 	rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table");
 	init_completion(&tbl->complete);
 
 	tbl = &session->bc_slot_table;
-	tbl->highest_used_slotid = -1;
+	tbl->highest_used_slotid = NFS4_NO_SLOT;
 	spin_lock_init(&tbl->slot_tbl_lock);
 	rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
 	init_completion(&tbl->complete);
@@ -5132,11 +5307,16 @@
 
 void nfs4_destroy_session(struct nfs4_session *session)
 {
+	struct rpc_xprt *xprt;
+
 	nfs4_proc_destroy_session(session);
+
+	rcu_read_lock();
+	xprt = rcu_dereference(session->clp->cl_rpcclient->cl_xprt);
+	rcu_read_unlock();
 	dprintk("%s Destroy backchannel for xprt %p\n",
-		__func__, session->clp->cl_rpcclient->cl_xprt);
-	xprt_destroy_backchannel(session->clp->cl_rpcclient->cl_xprt,
-				NFS41_BC_MIN_CALLBACKS);
+		__func__, xprt);
+	xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS);
 	nfs4_destroy_slot_tables(session);
 	kfree(session);
 }
@@ -5164,7 +5344,7 @@
 	args->fc_attrs.max_rqst_sz = mxrqst_sz;
 	args->fc_attrs.max_resp_sz = mxresp_sz;
 	args->fc_attrs.max_ops = NFS4_MAX_OPS;
-	args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs;
+	args->fc_attrs.max_reqs = max_session_slots;
 
 	dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u "
 		"max_ops=%u max_reqs=%u\n",
@@ -5204,6 +5384,8 @@
 		return -EINVAL;
 	if (rcvd->max_reqs == 0)
 		return -EINVAL;
+	if (rcvd->max_reqs > NFS4_MAX_SLOT_TABLE)
+		rcvd->max_reqs = NFS4_MAX_SLOT_TABLE;
 	return 0;
 }
 
@@ -5219,9 +5401,9 @@
 	if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached)
 		return -EINVAL;
 	/* These would render the backchannel useless: */
-	if (rcvd->max_ops  == 0)
+	if (rcvd->max_ops != sent->max_ops)
 		return -EINVAL;
-	if (rcvd->max_reqs == 0)
+	if (rcvd->max_reqs != sent->max_reqs)
 		return -EINVAL;
 	return 0;
 }
@@ -5324,7 +5506,7 @@
 
 	if (status)
 		printk(KERN_WARNING
-			"Got error %d from the server on DESTROY_SESSION. "
+			"NFS: Got error %d from the server on DESTROY_SESSION. "
 			"Session has been destroyed regardless...\n", status);
 
 	dprintk("<-- nfs4_proc_destroy_session\n");
@@ -5447,7 +5629,7 @@
 	args = task->tk_msg.rpc_argp;
 	res = task->tk_msg.rpc_resp;
 
-	if (nfs41_setup_sequence(clp->cl_session, args, res, 0, task))
+	if (nfs41_setup_sequence(clp->cl_session, args, res, task))
 		return;
 	rpc_call_start(task);
 }
@@ -5479,6 +5661,7 @@
 		nfs_put_client(clp);
 		return ERR_PTR(-ENOMEM);
 	}
+	nfs41_init_sequence(&calldata->args, &calldata->res, 0);
 	msg.rpc_argp = &calldata->args;
 	msg.rpc_resp = &calldata->res;
 	calldata->clp = clp;
@@ -5540,7 +5723,7 @@
 	rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
 	if (nfs41_setup_sequence(calldata->clp->cl_session,
 				&calldata->arg.seq_args,
-				&calldata->res.seq_res, 0, task))
+				&calldata->res.seq_res, task))
 		return;
 
 	rpc_call_start(task);
@@ -5619,6 +5802,7 @@
 	calldata->clp = clp;
 	calldata->arg.one_fs = 0;
 
+	nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0);
 	msg.rpc_argp = &calldata->arg;
 	msg.rpc_resp = &calldata->res;
 	task_setup_data.callback_data = calldata;
@@ -5650,7 +5834,7 @@
 	 * to be no way to prevent it completely.
 	 */
 	if (nfs4_setup_sequence(server, &lgp->args.seq_args,
-				&lgp->res.seq_res, 0, task))
+				&lgp->res.seq_res, task))
 		return;
 	if (pnfs_choose_layoutget_stateid(&lgp->args.stateid,
 					  NFS_I(lgp->args.inode)->layout,
@@ -5725,6 +5909,7 @@
 
 	lgp->res.layoutp = &lgp->args.layout;
 	lgp->res.seq_res.sr_slot = NULL;
+	nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
 	task = rpc_run_task(&task_setup_data);
 	if (IS_ERR(task))
 		return PTR_ERR(task);
@@ -5745,7 +5930,7 @@
 
 	dprintk("--> %s\n", __func__);
 	if (nfs41_setup_sequence(lrp->clp->cl_session, &lrp->args.seq_args,
-				&lrp->res.seq_res, 0, task))
+				&lrp->res.seq_res, task))
 		return;
 	rpc_call_start(task);
 }
@@ -5811,6 +5996,7 @@
 	int status;
 
 	dprintk("--> %s\n", __func__);
+	nfs41_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1);
 	task = rpc_run_task(&task_setup_data);
 	if (IS_ERR(task))
 		return PTR_ERR(task);
@@ -5911,7 +6097,7 @@
 	struct nfs_server *server = NFS_SERVER(data->args.inode);
 
 	if (nfs4_setup_sequence(server, &data->args.seq_args,
-				&data->res.seq_res, 1, task))
+				&data->res.seq_res, task))
 		return;
 	rpc_call_start(task);
 }
@@ -5926,21 +6112,22 @@
 		return;
 
 	switch (task->tk_status) { /* Just ignore these failures */
-	case NFS4ERR_DELEG_REVOKED: /* layout was recalled */
-	case NFS4ERR_BADIOMODE:     /* no IOMODE_RW layout for range */
-	case NFS4ERR_BADLAYOUT:     /* no layout */
-	case NFS4ERR_GRACE:	    /* loca_recalim always false */
+	case -NFS4ERR_DELEG_REVOKED: /* layout was recalled */
+	case -NFS4ERR_BADIOMODE:     /* no IOMODE_RW layout for range */
+	case -NFS4ERR_BADLAYOUT:     /* no layout */
+	case -NFS4ERR_GRACE:	    /* loca_recalim always false */
 		task->tk_status = 0;
-	}
-
-	if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
-		rpc_restart_call_prepare(task);
-		return;
-	}
-
-	if (task->tk_status == 0)
+		break;
+	case 0:
 		nfs_post_op_update_inode_force_wcc(data->args.inode,
 						   data->res.fattr);
+		break;
+	default:
+		if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
+			rpc_restart_call_prepare(task);
+			return;
+		}
+	}
 }
 
 static void nfs4_layoutcommit_release(void *calldata)
@@ -5998,6 +6185,7 @@
 		data->args.lastbytewritten,
 		data->args.inode->i_ino);
 
+	nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
 	task = rpc_run_task(&task_setup_data);
 	if (IS_ERR(task))
 		return PTR_ERR(task);
@@ -6043,11 +6231,12 @@
 		case 0:
 		case -NFS4ERR_WRONGSEC:
 		case -NFS4ERR_NOTSUPP:
-			break;
+			goto out;
 		default:
 			err = nfs4_handle_exception(server, err, &exception);
 		}
 	} while (exception.retry);
+out:
 	return err;
 }
 
@@ -6091,11 +6280,12 @@
 out:
 	return err;
 }
-static int _nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state)
+
+static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 {
 	int status;
 	struct nfs41_test_stateid_args args = {
-		.stateid = &state->stateid,
+		.stateid = stateid,
 	};
 	struct nfs41_test_stateid_res res;
 	struct rpc_message msg = {
@@ -6103,28 +6293,31 @@
 		.rpc_argp = &args,
 		.rpc_resp = &res,
 	};
-	args.seq_args.sa_session = res.seq_res.sr_session = NULL;
-	status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1);
+
+	nfs41_init_sequence(&args.seq_args, &res.seq_res, 0);
+	status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
+
+	if (status == NFS_OK)
+		return res.status;
 	return status;
 }
 
-static int nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state)
+static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 {
 	struct nfs4_exception exception = { };
 	int err;
 	do {
 		err = nfs4_handle_exception(server,
-				_nfs41_test_stateid(server, state),
+				_nfs41_test_stateid(server, stateid),
 				&exception);
 	} while (exception.retry);
 	return err;
 }
 
-static int _nfs4_free_stateid(struct nfs_server *server, struct nfs4_state *state)
+static int _nfs4_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 {
-	int status;
 	struct nfs41_free_stateid_args args = {
-		.stateid = &state->stateid,
+		.stateid = stateid,
 	};
 	struct nfs41_free_stateid_res res;
 	struct rpc_message msg = {
@@ -6133,25 +6326,46 @@
 		.rpc_resp = &res,
 	};
 
-	args.seq_args.sa_session = res.seq_res.sr_session = NULL;
-	status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1);
-	return status;
+	nfs41_init_sequence(&args.seq_args, &res.seq_res, 0);
+	return nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
 }
 
-static int nfs41_free_stateid(struct nfs_server *server, struct nfs4_state *state)
+static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 {
 	struct nfs4_exception exception = { };
 	int err;
 	do {
 		err = nfs4_handle_exception(server,
-				_nfs4_free_stateid(server, state),
+				_nfs4_free_stateid(server, stateid),
 				&exception);
 	} while (exception.retry);
 	return err;
 }
+
+static bool nfs41_match_stateid(const nfs4_stateid *s1,
+		const nfs4_stateid *s2)
+{
+	if (memcmp(s1->other, s2->other, sizeof(s1->other)) != 0)
+		return false;
+
+	if (s1->seqid == s2->seqid)
+		return true;
+	if (s1->seqid == 0 || s2->seqid == 0)
+		return true;
+
+	return false;
+}
+
 #endif /* CONFIG_NFS_V4_1 */
 
-struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
+static bool nfs4_match_stateid(const nfs4_stateid *s1,
+		const nfs4_stateid *s2)
+{
+	return nfs4_stateid_match(s1, s2);
+}
+
+
+static const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
 	.owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
 	.state_flag_bit	= NFS_STATE_RECLAIM_REBOOT,
 	.recover_open	= nfs4_open_reclaim,
@@ -6161,7 +6375,7 @@
 };
 
 #if defined(CONFIG_NFS_V4_1)
-struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
+static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
 	.owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
 	.state_flag_bit	= NFS_STATE_RECLAIM_REBOOT,
 	.recover_open	= nfs4_open_reclaim,
@@ -6172,7 +6386,7 @@
 };
 #endif /* CONFIG_NFS_V4_1 */
 
-struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
+static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
 	.owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
 	.state_flag_bit	= NFS_STATE_RECLAIM_NOGRACE,
 	.recover_open	= nfs4_open_expired,
@@ -6182,7 +6396,7 @@
 };
 
 #if defined(CONFIG_NFS_V4_1)
-struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {
+static const struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {
 	.owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
 	.state_flag_bit	= NFS_STATE_RECLAIM_NOGRACE,
 	.recover_open	= nfs41_open_expired,
@@ -6192,14 +6406,14 @@
 };
 #endif /* CONFIG_NFS_V4_1 */
 
-struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = {
+static const struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = {
 	.sched_state_renewal = nfs4_proc_async_renew,
 	.get_state_renewal_cred_locked = nfs4_get_renew_cred_locked,
 	.renew_lease = nfs4_proc_renew,
 };
 
 #if defined(CONFIG_NFS_V4_1)
-struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
+static const struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
 	.sched_state_renewal = nfs41_proc_async_sequence,
 	.get_state_renewal_cred_locked = nfs4_get_machine_cred_locked,
 	.renew_lease = nfs4_proc_sequence,
@@ -6209,7 +6423,7 @@
 static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
 	.minor_version = 0,
 	.call_sync = _nfs4_call_sync,
-	.validate_stateid = nfs4_validate_delegation_stateid,
+	.match_stateid = nfs4_match_stateid,
 	.find_root_sec = nfs4_find_root_sec,
 	.reboot_recovery_ops = &nfs40_reboot_recovery_ops,
 	.nograce_recovery_ops = &nfs40_nograce_recovery_ops,
@@ -6220,7 +6434,7 @@
 static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
 	.minor_version = 1,
 	.call_sync = _nfs4_call_sync_session,
-	.validate_stateid = nfs41_validate_delegation_stateid,
+	.match_stateid = nfs41_match_stateid,
 	.find_root_sec = nfs41_find_root_sec,
 	.reboot_recovery_ops = &nfs41_reboot_recovery_ops,
 	.nograce_recovery_ops = &nfs41_nograce_recovery_ops,
@@ -6260,9 +6474,11 @@
 	.create		= nfs4_proc_create,
 	.remove		= nfs4_proc_remove,
 	.unlink_setup	= nfs4_proc_unlink_setup,
+	.unlink_rpc_prepare = nfs4_proc_unlink_rpc_prepare,
 	.unlink_done	= nfs4_proc_unlink_done,
 	.rename		= nfs4_proc_rename,
 	.rename_setup	= nfs4_proc_rename_setup,
+	.rename_rpc_prepare = nfs4_proc_rename_rpc_prepare,
 	.rename_done	= nfs4_proc_rename_done,
 	.link		= nfs4_proc_link,
 	.symlink	= nfs4_proc_symlink,
@@ -6276,8 +6492,10 @@
 	.set_capabilities = nfs4_server_capabilities,
 	.decode_dirent	= nfs4_decode_dirent,
 	.read_setup	= nfs4_proc_read_setup,
+	.read_rpc_prepare = nfs4_proc_read_rpc_prepare,
 	.read_done	= nfs4_read_done,
 	.write_setup	= nfs4_proc_write_setup,
+	.write_rpc_prepare = nfs4_proc_write_rpc_prepare,
 	.write_done	= nfs4_write_done,
 	.commit_setup	= nfs4_proc_commit_setup,
 	.commit_done	= nfs4_commit_done,
@@ -6301,6 +6519,10 @@
 	NULL
 };
 
+module_param(max_session_slots, ushort, 0644);
+MODULE_PARM_DESC(max_session_slots, "Maximum number of outstanding NFSv4.1 "
+		"requests the client will negotiate");
+
 /*
  * Local variables:
  *  c-basic-offset: 8
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 4539203..0f43414 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -146,6 +146,11 @@
 	struct rpc_cred *cred = NULL;
 	struct nfs_server *server;
 
+	/* Use machine credentials if available */
+	cred = nfs4_get_machine_cred_locked(clp);
+	if (cred != NULL)
+		goto out;
+
 	rcu_read_lock();
 	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
 		cred = nfs4_get_renew_cred_server_locked(server);
@@ -153,6 +158,8 @@
 			break;
 	}
 	rcu_read_unlock();
+
+out:
 	return cred;
 }
 
@@ -190,30 +197,29 @@
 static void nfs4_end_drain_session(struct nfs_client *clp)
 {
 	struct nfs4_session *ses = clp->cl_session;
+	struct nfs4_slot_table *tbl;
 	int max_slots;
 
 	if (ses == NULL)
 		return;
+	tbl = &ses->fc_slot_table;
 	if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
-		spin_lock(&ses->fc_slot_table.slot_tbl_lock);
-		max_slots = ses->fc_slot_table.max_slots;
+		spin_lock(&tbl->slot_tbl_lock);
+		max_slots = tbl->max_slots;
 		while (max_slots--) {
-			struct rpc_task *task;
-
-			task = rpc_wake_up_next(&ses->fc_slot_table.
-						slot_tbl_waitq);
-			if (!task)
+			if (rpc_wake_up_first(&tbl->slot_tbl_waitq,
+						nfs4_set_task_privileged,
+						NULL) == NULL)
 				break;
-			rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
 		}
-		spin_unlock(&ses->fc_slot_table.slot_tbl_lock);
+		spin_unlock(&tbl->slot_tbl_lock);
 	}
 }
 
 static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl)
 {
 	spin_lock(&tbl->slot_tbl_lock);
-	if (tbl->highest_used_slotid != -1) {
+	if (tbl->highest_used_slotid != NFS4_NO_SLOT) {
 		INIT_COMPLETION(tbl->complete);
 		spin_unlock(&tbl->slot_tbl_lock);
 		return wait_for_completion_interruptible(&tbl->complete);
@@ -317,62 +323,6 @@
 	return cred;
 }
 
-static void nfs_alloc_unique_id_locked(struct rb_root *root,
-				       struct nfs_unique_id *new,
-				       __u64 minval, int maxbits)
-{
-	struct rb_node **p, *parent;
-	struct nfs_unique_id *pos;
-	__u64 mask = ~0ULL;
-
-	if (maxbits < 64)
-		mask = (1ULL << maxbits) - 1ULL;
-
-	/* Ensure distribution is more or less flat */
-	get_random_bytes(&new->id, sizeof(new->id));
-	new->id &= mask;
-	if (new->id < minval)
-		new->id += minval;
-retry:
-	p = &root->rb_node;
-	parent = NULL;
-
-	while (*p != NULL) {
-		parent = *p;
-		pos = rb_entry(parent, struct nfs_unique_id, rb_node);
-
-		if (new->id < pos->id)
-			p = &(*p)->rb_left;
-		else if (new->id > pos->id)
-			p = &(*p)->rb_right;
-		else
-			goto id_exists;
-	}
-	rb_link_node(&new->rb_node, parent, p);
-	rb_insert_color(&new->rb_node, root);
-	return;
-id_exists:
-	for (;;) {
-		new->id++;
-		if (new->id < minval || (new->id & mask) != new->id) {
-			new->id = minval;
-			break;
-		}
-		parent = rb_next(parent);
-		if (parent == NULL)
-			break;
-		pos = rb_entry(parent, struct nfs_unique_id, rb_node);
-		if (new->id < pos->id)
-			break;
-	}
-	goto retry;
-}
-
-static void nfs_free_unique_id(struct rb_root *root, struct nfs_unique_id *id)
-{
-	rb_erase(&id->rb_node, root);
-}
-
 static struct nfs4_state_owner *
 nfs4_find_state_owner_locked(struct nfs_server *server, struct rpc_cred *cred)
 {
@@ -405,6 +355,7 @@
 	struct rb_node **p = &server->state_owners.rb_node,
 		       *parent = NULL;
 	struct nfs4_state_owner *sp;
+	int err;
 
 	while (*p != NULL) {
 		parent = *p;
@@ -421,8 +372,9 @@
 			return sp;
 		}
 	}
-	nfs_alloc_unique_id_locked(&server->openowner_id,
-					&new->so_owner_id, 1, 64);
+	err = ida_get_new(&server->openowner_id, &new->so_seqid.owner_id);
+	if (err)
+		return ERR_PTR(err);
 	rb_link_node(&new->so_server_node, parent, p);
 	rb_insert_color(&new->so_server_node, &server->state_owners);
 	return new;
@@ -435,7 +387,23 @@
 
 	if (!RB_EMPTY_NODE(&sp->so_server_node))
 		rb_erase(&sp->so_server_node, &server->state_owners);
-	nfs_free_unique_id(&server->openowner_id, &sp->so_owner_id);
+	ida_remove(&server->openowner_id, sp->so_seqid.owner_id);
+}
+
+static void
+nfs4_init_seqid_counter(struct nfs_seqid_counter *sc)
+{
+	sc->flags = 0;
+	sc->counter = 0;
+	spin_lock_init(&sc->lock);
+	INIT_LIST_HEAD(&sc->list);
+	rpc_init_wait_queue(&sc->wait, "Seqid_waitqueue");
+}
+
+static void
+nfs4_destroy_seqid_counter(struct nfs_seqid_counter *sc)
+{
+	rpc_destroy_wait_queue(&sc->wait);
 }
 
 /*
@@ -444,19 +412,20 @@
  *
  */
 static struct nfs4_state_owner *
-nfs4_alloc_state_owner(void)
+nfs4_alloc_state_owner(struct nfs_server *server,
+		struct rpc_cred *cred,
+		gfp_t gfp_flags)
 {
 	struct nfs4_state_owner *sp;
 
-	sp = kzalloc(sizeof(*sp),GFP_NOFS);
+	sp = kzalloc(sizeof(*sp), gfp_flags);
 	if (!sp)
 		return NULL;
+	sp->so_server = server;
+	sp->so_cred = get_rpccred(cred);
 	spin_lock_init(&sp->so_lock);
 	INIT_LIST_HEAD(&sp->so_states);
-	rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue");
-	sp->so_seqid.sequence = &sp->so_sequence;
-	spin_lock_init(&sp->so_sequence.lock);
-	INIT_LIST_HEAD(&sp->so_sequence.list);
+	nfs4_init_seqid_counter(&sp->so_seqid);
 	atomic_set(&sp->so_count, 1);
 	INIT_LIST_HEAD(&sp->so_lru);
 	return sp;
@@ -478,7 +447,7 @@
 
 static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
 {
-	rpc_destroy_wait_queue(&sp->so_sequence.wait);
+	nfs4_destroy_seqid_counter(&sp->so_seqid);
 	put_rpccred(sp->so_cred);
 	kfree(sp);
 }
@@ -516,7 +485,8 @@
  * Returns a pointer to an instantiated nfs4_state_owner struct, or NULL.
  */
 struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
-					      struct rpc_cred *cred)
+					      struct rpc_cred *cred,
+					      gfp_t gfp_flags)
 {
 	struct nfs_client *clp = server->nfs_client;
 	struct nfs4_state_owner *sp, *new;
@@ -526,20 +496,18 @@
 	spin_unlock(&clp->cl_lock);
 	if (sp != NULL)
 		goto out;
-	new = nfs4_alloc_state_owner();
+	new = nfs4_alloc_state_owner(server, cred, gfp_flags);
 	if (new == NULL)
 		goto out;
-	new->so_server = server;
-	new->so_cred = cred;
-	spin_lock(&clp->cl_lock);
-	sp = nfs4_insert_state_owner_locked(new);
-	spin_unlock(&clp->cl_lock);
-	if (sp == new)
-		get_rpccred(cred);
-	else {
-		rpc_destroy_wait_queue(&new->so_sequence.wait);
-		kfree(new);
-	}
+	do {
+		if (ida_pre_get(&server->openowner_id, gfp_flags) == 0)
+			break;
+		spin_lock(&clp->cl_lock);
+		sp = nfs4_insert_state_owner_locked(new);
+		spin_unlock(&clp->cl_lock);
+	} while (sp == ERR_PTR(-EAGAIN));
+	if (sp != new)
+		nfs4_free_state_owner(new);
 out:
 	nfs4_gc_state_owners(server);
 	return sp;
@@ -795,15 +763,11 @@
 {
 	struct nfs4_lock_state *lsp;
 	struct nfs_server *server = state->owner->so_server;
-	struct nfs_client *clp = server->nfs_client;
 
 	lsp = kzalloc(sizeof(*lsp), GFP_NOFS);
 	if (lsp == NULL)
 		return NULL;
-	rpc_init_wait_queue(&lsp->ls_sequence.wait, "lock_seqid_waitqueue");
-	spin_lock_init(&lsp->ls_sequence.lock);
-	INIT_LIST_HEAD(&lsp->ls_sequence.list);
-	lsp->ls_seqid.sequence = &lsp->ls_sequence;
+	nfs4_init_seqid_counter(&lsp->ls_seqid);
 	atomic_set(&lsp->ls_count, 1);
 	lsp->ls_state = state;
 	lsp->ls_owner.lo_type = type;
@@ -815,25 +779,22 @@
 		lsp->ls_owner.lo_u.posix_owner = fl_owner;
 		break;
 	default:
-		kfree(lsp);
-		return NULL;
+		goto out_free;
 	}
-	spin_lock(&clp->cl_lock);
-	nfs_alloc_unique_id_locked(&server->lockowner_id, &lsp->ls_id, 1, 64);
-	spin_unlock(&clp->cl_lock);
+	lsp->ls_seqid.owner_id = ida_simple_get(&server->lockowner_id, 0, 0, GFP_NOFS);
+	if (lsp->ls_seqid.owner_id < 0)
+		goto out_free;
 	INIT_LIST_HEAD(&lsp->ls_locks);
 	return lsp;
+out_free:
+	kfree(lsp);
+	return NULL;
 }
 
-static void nfs4_free_lock_state(struct nfs4_lock_state *lsp)
+void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
 {
-	struct nfs_server *server = lsp->ls_state->owner->so_server;
-	struct nfs_client *clp = server->nfs_client;
-
-	spin_lock(&clp->cl_lock);
-	nfs_free_unique_id(&server->lockowner_id, &lsp->ls_id);
-	spin_unlock(&clp->cl_lock);
-	rpc_destroy_wait_queue(&lsp->ls_sequence.wait);
+	ida_simple_remove(&server->lockowner_id, lsp->ls_seqid.owner_id);
+	nfs4_destroy_seqid_counter(&lsp->ls_seqid);
 	kfree(lsp);
 }
 
@@ -865,7 +826,7 @@
 	}
 	spin_unlock(&state->state_lock);
 	if (new != NULL)
-		nfs4_free_lock_state(new);
+		nfs4_free_lock_state(state->owner->so_server, new);
 	return lsp;
 }
 
@@ -886,9 +847,11 @@
 	if (list_empty(&state->lock_states))
 		clear_bit(LK_STATE_IN_USE, &state->flags);
 	spin_unlock(&state->state_lock);
-	if (lsp->ls_flags & NFS_LOCK_INITIALIZED)
-		nfs4_release_lockowner(lsp);
-	nfs4_free_lock_state(lsp);
+	if (lsp->ls_flags & NFS_LOCK_INITIALIZED) {
+		if (nfs4_release_lockowner(lsp) == 0)
+			return;
+	}
+	nfs4_free_lock_state(lsp->ls_state->owner->so_server, lsp);
 }
 
 static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
@@ -918,7 +881,8 @@
 	if (fl->fl_flags & FL_POSIX)
 		lsp = nfs4_get_lock_state(state, fl->fl_owner, 0, NFS4_POSIX_LOCK_TYPE);
 	else if (fl->fl_flags & FL_FLOCK)
-		lsp = nfs4_get_lock_state(state, 0, fl->fl_pid, NFS4_FLOCK_LOCK_TYPE);
+		lsp = nfs4_get_lock_state(state, NULL, fl->fl_pid,
+				NFS4_FLOCK_LOCK_TYPE);
 	else
 		return -EINVAL;
 	if (lsp == NULL)
@@ -928,28 +892,49 @@
 	return 0;
 }
 
-/*
- * Byte-range lock aware utility to initialize the stateid of read/write
- * requests.
- */
-void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid)
+static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state,
+		fl_owner_t fl_owner, pid_t fl_pid)
 {
 	struct nfs4_lock_state *lsp;
+	bool ret = false;
+
+	if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
+		goto out;
+
+	spin_lock(&state->state_lock);
+	lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
+	if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) {
+		nfs4_stateid_copy(dst, &lsp->ls_stateid);
+		ret = true;
+	}
+	spin_unlock(&state->state_lock);
+	nfs4_put_lock_state(lsp);
+out:
+	return ret;
+}
+
+static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
+{
 	int seq;
 
 	do {
 		seq = read_seqbegin(&state->seqlock);
-		memcpy(dst, &state->stateid, sizeof(*dst));
+		nfs4_stateid_copy(dst, &state->stateid);
 	} while (read_seqretry(&state->seqlock, seq));
-	if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
-		return;
+}
 
-	spin_lock(&state->state_lock);
-	lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
-	if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
-		memcpy(dst, &lsp->ls_stateid, sizeof(*dst));
-	spin_unlock(&state->state_lock);
-	nfs4_put_lock_state(lsp);
+/*
+ * Byte-range lock aware utility to initialize the stateid of read/write
+ * requests.
+ */
+void nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
+		fmode_t fmode, fl_owner_t fl_owner, pid_t fl_pid)
+{
+	if (nfs4_copy_delegation_stateid(dst, state->inode, fmode))
+		return;
+	if (nfs4_copy_lock_stateid(dst, state, fl_owner, fl_pid))
+		return;
+	nfs4_copy_open_stateid(dst, state);
 }
 
 struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)
@@ -960,20 +945,28 @@
 	if (new != NULL) {
 		new->sequence = counter;
 		INIT_LIST_HEAD(&new->list);
+		new->task = NULL;
 	}
 	return new;
 }
 
 void nfs_release_seqid(struct nfs_seqid *seqid)
 {
-	if (!list_empty(&seqid->list)) {
-		struct rpc_sequence *sequence = seqid->sequence->sequence;
+	struct nfs_seqid_counter *sequence;
 
-		spin_lock(&sequence->lock);
-		list_del_init(&seqid->list);
-		spin_unlock(&sequence->lock);
-		rpc_wake_up(&sequence->wait);
+	if (list_empty(&seqid->list))
+		return;
+	sequence = seqid->sequence;
+	spin_lock(&sequence->lock);
+	list_del_init(&seqid->list);
+	if (!list_empty(&sequence->list)) {
+		struct nfs_seqid *next;
+
+		next = list_first_entry(&sequence->list,
+				struct nfs_seqid, list);
+		rpc_wake_up_queued_task(&sequence->wait, next->task);
 	}
+	spin_unlock(&sequence->lock);
 }
 
 void nfs_free_seqid(struct nfs_seqid *seqid)
@@ -989,14 +982,14 @@
  */
 static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
 {
-	BUG_ON(list_first_entry(&seqid->sequence->sequence->list, struct nfs_seqid, list) != seqid);
+	BUG_ON(list_first_entry(&seqid->sequence->list, struct nfs_seqid, list) != seqid);
 	switch (status) {
 		case 0:
 			break;
 		case -NFS4ERR_BAD_SEQID:
 			if (seqid->sequence->flags & NFS_SEQID_CONFIRMED)
 				return;
-			printk(KERN_WARNING "NFS: v4 server returned a bad"
+			pr_warn_ratelimited("NFS: v4 server returned a bad"
 					" sequence-id error on an"
 					" unconfirmed sequence %p!\n",
 					seqid->sequence);
@@ -1040,10 +1033,11 @@
 
 int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
 {
-	struct rpc_sequence *sequence = seqid->sequence->sequence;
+	struct nfs_seqid_counter *sequence = seqid->sequence;
 	int status = 0;
 
 	spin_lock(&sequence->lock);
+	seqid->task = task;
 	if (list_empty(&seqid->list))
 		list_add_tail(&seqid->list, &sequence->list);
 	if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid)
@@ -1072,19 +1066,28 @@
 void nfs4_schedule_state_manager(struct nfs_client *clp)
 {
 	struct task_struct *task;
+	char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];
 
 	if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
 		return;
 	__module_get(THIS_MODULE);
 	atomic_inc(&clp->cl_count);
-	task = kthread_run(nfs4_run_state_manager, clp, "%s-manager",
-				rpc_peeraddr2str(clp->cl_rpcclient,
-							RPC_DISPLAY_ADDR));
-	if (!IS_ERR(task))
-		return;
-	nfs4_clear_state_manager_bit(clp);
-	nfs_put_client(clp);
-	module_put(THIS_MODULE);
+
+	/* The rcu_read_lock() is not strictly necessary, as the state
+	 * manager is the only thread that ever changes the rpc_xprt
+	 * after it's initialized.  At this point, we're single threaded. */
+	rcu_read_lock();
+	snprintf(buf, sizeof(buf), "%s-manager",
+			rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
+	rcu_read_unlock();
+	task = kthread_run(nfs4_run_state_manager, clp, buf);
+	if (IS_ERR(task)) {
+		printk(KERN_ERR "%s: kthread_run: %ld\n",
+			__func__, PTR_ERR(task));
+		nfs4_clear_state_manager_bit(clp);
+		nfs_put_client(clp);
+		module_put(THIS_MODULE);
+	}
 }
 
 /*
@@ -1098,10 +1101,25 @@
 		set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
 	nfs4_schedule_state_manager(clp);
 }
+EXPORT_SYMBOL_GPL(nfs4_schedule_lease_recovery);
+
+/*
+ * nfs40_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
+ * @clp: client to process
+ *
+ * Set the NFS4CLNT_LEASE_EXPIRED state in order to force a
+ * resend of the SETCLIENTID and hence re-establish the
+ * callback channel. Then return all existing delegations.
+ */
+static void nfs40_handle_cb_pathdown(struct nfs_client *clp)
+{
+	set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+	nfs_expire_all_delegations(clp);
+}
 
 void nfs4_schedule_path_down_recovery(struct nfs_client *clp)
 {
-	nfs_handle_cb_pathdown(clp);
+	nfs40_handle_cb_pathdown(clp);
 	nfs4_schedule_state_manager(clp);
 }
 
@@ -1132,11 +1150,37 @@
 {
 	struct nfs_client *clp = server->nfs_client;
 
-	if (test_and_clear_bit(NFS_DELEGATED_STATE, &state->flags))
-		nfs_async_inode_return_delegation(state->inode, &state->stateid);
 	nfs4_state_mark_reclaim_nograce(clp, state);
 	nfs4_schedule_state_manager(clp);
 }
+EXPORT_SYMBOL_GPL(nfs4_schedule_stateid_recovery);
+
+void nfs_inode_find_state_and_recover(struct inode *inode,
+		const nfs4_stateid *stateid)
+{
+	struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
+	struct nfs_inode *nfsi = NFS_I(inode);
+	struct nfs_open_context *ctx;
+	struct nfs4_state *state;
+	bool found = false;
+
+	spin_lock(&inode->i_lock);
+	list_for_each_entry(ctx, &nfsi->open_files, list) {
+		state = ctx->state;
+		if (state == NULL)
+			continue;
+		if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
+			continue;
+		if (!nfs4_stateid_match(&state->stateid, stateid))
+			continue;
+		nfs4_state_mark_reclaim_nograce(clp, state);
+		found = true;
+	}
+	spin_unlock(&inode->i_lock);
+	if (found)
+		nfs4_schedule_state_manager(clp);
+}
+
 
 static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
 {
@@ -1175,8 +1219,8 @@
 			case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
 				goto out;
 			default:
-				printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
-						__func__, status);
+				printk(KERN_ERR "NFS: %s: unhandled error %d. "
+					"Zeroing state\n", __func__, status);
 			case -ENOMEM:
 			case -NFS4ERR_DENIED:
 			case -NFS4ERR_RECLAIM_BAD:
@@ -1222,8 +1266,9 @@
 				spin_lock(&state->state_lock);
 				list_for_each_entry(lock, &state->lock_states, ls_locks) {
 					if (!(lock->ls_flags & NFS_LOCK_INITIALIZED))
-						printk("%s: Lock reclaim failed!\n",
-							__func__);
+						pr_warn_ratelimited("NFS: "
+							"%s: Lock reclaim "
+							"failed!\n", __func__);
 				}
 				spin_unlock(&state->state_lock);
 				nfs4_put_open_state(state);
@@ -1232,8 +1277,8 @@
 		}
 		switch (status) {
 			default:
-				printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
-						__func__, status);
+				printk(KERN_ERR "NFS: %s: unhandled error %d. "
+					"Zeroing state\n", __func__, status);
 			case -ENOENT:
 			case -ENOMEM:
 			case -ESTALE:
@@ -1241,8 +1286,8 @@
 				 * Open state on this file cannot be recovered
 				 * All we can do is revert to using the zero stateid.
 				 */
-				memset(state->stateid.data, 0,
-					sizeof(state->stateid.data));
+				memset(&state->stateid, 0,
+					sizeof(state->stateid));
 				/* Mark the file as being 'closed' */
 				state->state = 0;
 				break;
@@ -1420,7 +1465,7 @@
 		case 0:
 			break;
 		case -NFS4ERR_CB_PATH_DOWN:
-			nfs_handle_cb_pathdown(clp);
+			nfs40_handle_cb_pathdown(clp);
 			break;
 		case -NFS4ERR_NO_GRACE:
 			nfs4_state_end_reclaim_reboot(clp);
@@ -1801,7 +1846,7 @@
 	} while (atomic_read(&clp->cl_count) > 1);
 	return;
 out_error:
-	printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s"
+	pr_warn_ratelimited("NFS: state manager failed on NFSv4 server %s"
 			" with error %d\n", clp->cl_hostname, -status);
 	nfs4_end_drain_session(clp);
 	nfs4_clear_state_manager_bit(clp);
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 33bd8d0..c74fdb1 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -44,6 +44,8 @@
 #include <linux/pagemap.h>
 #include <linux/proc_fs.h>
 #include <linux/kdev_t.h>
+#include <linux/module.h>
+#include <linux/utsname.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/msg_prot.h>
 #include <linux/sunrpc/gss_api.h>
@@ -271,7 +273,12 @@
 				1 /* flags */ + \
 				1 /* spa_how */ + \
 				0 /* SP4_NONE (for now) */ + \
-				1 /* zero implemetation id array */)
+				1 /* implementation id array of size 1 */ + \
+				1 /* nii_domain */ + \
+				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
+				1 /* nii_name */ + \
+				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
+				3 /* nii_date */)
 #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \
 				2 /* eir_clientid */ + \
 				1 /* eir_sequenceid */ + \
@@ -284,7 +291,11 @@
 				/* eir_server_scope<> */ \
 				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
 				1 /* eir_server_impl_id array length */ + \
-				0 /* ignored eir_server_impl_id contents */)
+				1 /* nii_domain */ + \
+				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
+				1 /* nii_name */ + \
+				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
+				3 /* nii_date */)
 #define encode_channel_attrs_maxsz  (6 + 1 /* ca_rdma_ird.len (0) */)
 #define decode_channel_attrs_maxsz  (6 + \
 				     1 /* ca_rdma_ird.len */ + \
@@ -838,6 +849,12 @@
 				    XDR_UNIT);
 #endif /* CONFIG_NFS_V4_1 */
 
+static unsigned short send_implementation_id = 1;
+
+module_param(send_implementation_id, ushort, 0644);
+MODULE_PARM_DESC(send_implementation_id,
+		"Send implementation ID with NFSv4.1 exchange_id");
+
 static const umode_t nfs_type2fmt[] = {
 	[NF4BAD] = 0,
 	[NF4REG] = S_IFREG,
@@ -868,15 +885,44 @@
 	return p;
 }
 
+static void encode_opaque_fixed(struct xdr_stream *xdr, const void *buf, size_t len)
+{
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, len);
+	xdr_encode_opaque_fixed(p, buf, len);
+}
+
 static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
 {
 	__be32 *p;
 
-	p = xdr_reserve_space(xdr, 4 + len);
-	BUG_ON(p == NULL);
+	p = reserve_space(xdr, 4 + len);
 	xdr_encode_opaque(p, str, len);
 }
 
+static void encode_uint32(struct xdr_stream *xdr, u32 n)
+{
+	__be32 *p;
+
+	p = reserve_space(xdr, 4);
+	*p = cpu_to_be32(n);
+}
+
+static void encode_uint64(struct xdr_stream *xdr, u64 n)
+{
+	__be32 *p;
+
+	p = reserve_space(xdr, 8);
+	xdr_encode_hyper(p, n);
+}
+
+static void encode_nfs4_seqid(struct xdr_stream *xdr,
+		const struct nfs_seqid *seqid)
+{
+	encode_uint32(xdr, seqid->sequence->counter);
+}
+
 static void encode_compound_hdr(struct xdr_stream *xdr,
 				struct rpc_rqst *req,
 				struct compound_hdr *hdr)
@@ -889,28 +935,37 @@
 	 * but this is not required as a MUST for the server to do so. */
 	hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen;
 
-	dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
 	BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
-	p = reserve_space(xdr, 4 + hdr->taglen + 8);
-	p = xdr_encode_opaque(p, hdr->tag, hdr->taglen);
+	encode_string(xdr, hdr->taglen, hdr->tag);
+	p = reserve_space(xdr, 8);
 	*p++ = cpu_to_be32(hdr->minorversion);
 	hdr->nops_p = p;
 	*p = cpu_to_be32(hdr->nops);
 }
 
+static void encode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 op,
+		uint32_t replen,
+		struct compound_hdr *hdr)
+{
+	encode_uint32(xdr, op);
+	hdr->nops++;
+	hdr->replen += replen;
+}
+
 static void encode_nops(struct compound_hdr *hdr)
 {
 	BUG_ON(hdr->nops > NFS4_MAX_OPS);
 	*hdr->nops_p = htonl(hdr->nops);
 }
 
+static void encode_nfs4_stateid(struct xdr_stream *xdr, const nfs4_stateid *stateid)
+{
+	encode_opaque_fixed(xdr, stateid, NFS4_STATEID_SIZE);
+}
+
 static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
 {
-	__be32 *p;
-
-	p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
-	BUG_ON(p == NULL);
-	xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
+	encode_opaque_fixed(xdr, verf->data, NFS4_VERIFIER_SIZE);
 }
 
 static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
@@ -1023,7 +1078,7 @@
 	 * Now we backfill the bitmap and the attribute buffer length.
 	 */
 	if (len != ((char *)p - (char *)q) + 4) {
-		printk(KERN_ERR "nfs: Attr length error, %u != %Zu\n",
+		printk(KERN_ERR "NFS: Attr length error, %u != %Zu\n",
 				len, ((char *)p - (char *)q) + 4);
 		BUG();
 	}
@@ -1037,46 +1092,33 @@
 
 static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 8);
-	*p++ = cpu_to_be32(OP_ACCESS);
-	*p = cpu_to_be32(access);
-	hdr->nops++;
-	hdr->replen += decode_access_maxsz;
+	encode_op_hdr(xdr, OP_ACCESS, decode_access_maxsz, hdr);
+	encode_uint32(xdr, access);
 }
 
 static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 8+NFS4_STATEID_SIZE);
-	*p++ = cpu_to_be32(OP_CLOSE);
-	*p++ = cpu_to_be32(arg->seqid->sequence->counter);
-	xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
-	hdr->nops++;
-	hdr->replen += decode_close_maxsz;
+	encode_op_hdr(xdr, OP_CLOSE, decode_close_maxsz, hdr);
+	encode_nfs4_seqid(xdr, arg->seqid);
+	encode_nfs4_stateid(xdr, arg->stateid);
 }
 
 static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 16);
-	*p++ = cpu_to_be32(OP_COMMIT);
+	encode_op_hdr(xdr, OP_COMMIT, decode_commit_maxsz, hdr);
+	p = reserve_space(xdr, 12);
 	p = xdr_encode_hyper(p, args->offset);
 	*p = cpu_to_be32(args->count);
-	hdr->nops++;
-	hdr->replen += decode_commit_maxsz;
 }
 
 static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr)
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 8);
-	*p++ = cpu_to_be32(OP_CREATE);
-	*p = cpu_to_be32(create->ftype);
+	encode_op_hdr(xdr, OP_CREATE, decode_create_maxsz, hdr);
+	encode_uint32(xdr, create->ftype);
 
 	switch (create->ftype) {
 	case NF4LNK:
@@ -1096,9 +1138,6 @@
 	}
 
 	encode_string(xdr, create->name->len, create->name->name);
-	hdr->nops++;
-	hdr->replen += decode_create_maxsz;
-
 	encode_attrs(xdr, create->attrs, create->server);
 }
 
@@ -1106,25 +1145,21 @@
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 12);
-	*p++ = cpu_to_be32(OP_GETATTR);
+	encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr);
+	p = reserve_space(xdr, 8);
 	*p++ = cpu_to_be32(1);
 	*p = cpu_to_be32(bitmap);
-	hdr->nops++;
-	hdr->replen += decode_getattr_maxsz;
 }
 
 static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr)
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 16);
-	*p++ = cpu_to_be32(OP_GETATTR);
+	encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr);
+	p = reserve_space(xdr, 12);
 	*p++ = cpu_to_be32(2);
 	*p++ = cpu_to_be32(bm0);
 	*p = cpu_to_be32(bm1);
-	hdr->nops++;
-	hdr->replen += decode_getattr_maxsz;
 }
 
 static void
@@ -1134,8 +1169,7 @@
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 4);
-	*p = cpu_to_be32(OP_GETATTR);
+	encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr);
 	if (bm2) {
 		p = reserve_space(xdr, 16);
 		*p++ = cpu_to_be32(3);
@@ -1152,8 +1186,6 @@
 		*p++ = cpu_to_be32(1);
 		*p = cpu_to_be32(bm0);
 	}
-	hdr->nops++;
-	hdr->replen += decode_getattr_maxsz;
 }
 
 static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
@@ -1179,23 +1211,13 @@
 
 static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 4);
-	*p = cpu_to_be32(OP_GETFH);
-	hdr->nops++;
-	hdr->replen += decode_getfh_maxsz;
+	encode_op_hdr(xdr, OP_GETFH, decode_getfh_maxsz, hdr);
 }
 
 static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 8 + name->len);
-	*p++ = cpu_to_be32(OP_LINK);
-	xdr_encode_opaque(p, name->name, name->len);
-	hdr->nops++;
-	hdr->replen += decode_link_maxsz;
+	encode_op_hdr(xdr, OP_LINK, decode_link_maxsz, hdr);
+	encode_string(xdr, name->len, name->name);
 }
 
 static inline int nfs4_lock_type(struct file_lock *fl, int block)
@@ -1232,79 +1254,60 @@
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 32);
-	*p++ = cpu_to_be32(OP_LOCK);
+	encode_op_hdr(xdr, OP_LOCK, decode_lock_maxsz, hdr);
+	p = reserve_space(xdr, 28);
 	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, args->block));
 	*p++ = cpu_to_be32(args->reclaim);
 	p = xdr_encode_hyper(p, args->fl->fl_start);
 	p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
 	*p = cpu_to_be32(args->new_lock_owner);
 	if (args->new_lock_owner){
-		p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
-		*p++ = cpu_to_be32(args->open_seqid->sequence->counter);
-		p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE);
-		*p++ = cpu_to_be32(args->lock_seqid->sequence->counter);
+		encode_nfs4_seqid(xdr, args->open_seqid);
+		encode_nfs4_stateid(xdr, args->open_stateid);
+		encode_nfs4_seqid(xdr, args->lock_seqid);
 		encode_lockowner(xdr, &args->lock_owner);
 	}
 	else {
-		p = reserve_space(xdr, NFS4_STATEID_SIZE+4);
-		p = xdr_encode_opaque_fixed(p, args->lock_stateid->data, NFS4_STATEID_SIZE);
-		*p = cpu_to_be32(args->lock_seqid->sequence->counter);
+		encode_nfs4_stateid(xdr, args->lock_stateid);
+		encode_nfs4_seqid(xdr, args->lock_seqid);
 	}
-	hdr->nops++;
-	hdr->replen += decode_lock_maxsz;
 }
 
 static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr)
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 24);
-	*p++ = cpu_to_be32(OP_LOCKT);
+	encode_op_hdr(xdr, OP_LOCKT, decode_lockt_maxsz, hdr);
+	p = reserve_space(xdr, 20);
 	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
 	p = xdr_encode_hyper(p, args->fl->fl_start);
 	p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
 	encode_lockowner(xdr, &args->lock_owner);
-	hdr->nops++;
-	hdr->replen += decode_lockt_maxsz;
 }
 
 static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr)
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 12+NFS4_STATEID_SIZE+16);
-	*p++ = cpu_to_be32(OP_LOCKU);
-	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
-	*p++ = cpu_to_be32(args->seqid->sequence->counter);
-	p = xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
+	encode_op_hdr(xdr, OP_LOCKU, decode_locku_maxsz, hdr);
+	encode_uint32(xdr, nfs4_lock_type(args->fl, 0));
+	encode_nfs4_seqid(xdr, args->seqid);
+	encode_nfs4_stateid(xdr, args->stateid);
+	p = reserve_space(xdr, 16);
 	p = xdr_encode_hyper(p, args->fl->fl_start);
 	xdr_encode_hyper(p, nfs4_lock_length(args->fl));
-	hdr->nops++;
-	hdr->replen += decode_locku_maxsz;
 }
 
 static void encode_release_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 4);
-	*p = cpu_to_be32(OP_RELEASE_LOCKOWNER);
+	encode_op_hdr(xdr, OP_RELEASE_LOCKOWNER, decode_release_lockowner_maxsz, hdr);
 	encode_lockowner(xdr, lowner);
-	hdr->nops++;
-	hdr->replen += decode_release_lockowner_maxsz;
 }
 
 static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
 {
-	int len = name->len;
-	__be32 *p;
-
-	p = reserve_space(xdr, 8 + len);
-	*p++ = cpu_to_be32(OP_LOOKUP);
-	xdr_encode_opaque(p, name->name, len);
-	hdr->nops++;
-	hdr->replen += decode_lookup_maxsz;
+	encode_op_hdr(xdr, OP_LOOKUP, decode_lookup_maxsz, hdr);
+	encode_string(xdr, name->len, name->name);
 }
 
 static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode)
@@ -1335,9 +1338,7 @@
  * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
  * owner 4 = 32
  */
-	p = reserve_space(xdr, 8);
-	*p++ = cpu_to_be32(OP_OPEN);
-	*p = cpu_to_be32(arg->seqid->sequence->counter);
+	encode_nfs4_seqid(xdr, arg->seqid);
 	encode_share_access(xdr, arg->fmode);
 	p = reserve_space(xdr, 32);
 	p = xdr_encode_hyper(p, arg->clientid);
@@ -1437,14 +1438,15 @@
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
-	*p++ = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
-	xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
+	p = reserve_space(xdr, 4);
+	*p = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
+	encode_nfs4_stateid(xdr, stateid);
 	encode_string(xdr, name->len, name->name);
 }
 
 static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr)
 {
+	encode_op_hdr(xdr, OP_OPEN, decode_open_maxsz, hdr);
 	encode_openhdr(xdr, arg);
 	encode_opentype(xdr, arg);
 	switch (arg->claim) {
@@ -1460,88 +1462,64 @@
 	default:
 		BUG();
 	}
-	hdr->nops++;
-	hdr->replen += decode_open_maxsz;
 }
 
 static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
-	*p++ = cpu_to_be32(OP_OPEN_CONFIRM);
-	p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
-	*p = cpu_to_be32(arg->seqid->sequence->counter);
-	hdr->nops++;
-	hdr->replen += decode_open_confirm_maxsz;
+	encode_op_hdr(xdr, OP_OPEN_CONFIRM, decode_open_confirm_maxsz, hdr);
+	encode_nfs4_stateid(xdr, arg->stateid);
+	encode_nfs4_seqid(xdr, arg->seqid);
 }
 
 static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
-	*p++ = cpu_to_be32(OP_OPEN_DOWNGRADE);
-	p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
-	*p = cpu_to_be32(arg->seqid->sequence->counter);
+	encode_op_hdr(xdr, OP_OPEN_DOWNGRADE, decode_open_downgrade_maxsz, hdr);
+	encode_nfs4_stateid(xdr, arg->stateid);
+	encode_nfs4_seqid(xdr, arg->seqid);
 	encode_share_access(xdr, arg->fmode);
-	hdr->nops++;
-	hdr->replen += decode_open_downgrade_maxsz;
 }
 
 static void
 encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hdr *hdr)
 {
-	int len = fh->size;
-	__be32 *p;
-
-	p = reserve_space(xdr, 8 + len);
-	*p++ = cpu_to_be32(OP_PUTFH);
-	xdr_encode_opaque(p, fh->data, len);
-	hdr->nops++;
-	hdr->replen += decode_putfh_maxsz;
+	encode_op_hdr(xdr, OP_PUTFH, decode_putfh_maxsz, hdr);
+	encode_string(xdr, fh->size, fh->data);
 }
 
 static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 4);
-	*p = cpu_to_be32(OP_PUTROOTFH);
-	hdr->nops++;
-	hdr->replen += decode_putrootfh_maxsz;
+	encode_op_hdr(xdr, OP_PUTROOTFH, decode_putrootfh_maxsz, hdr);
 }
 
-static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx, const struct nfs_lock_context *l_ctx, int zero_seqid)
+static void encode_open_stateid(struct xdr_stream *xdr,
+		const struct nfs_open_context *ctx,
+		const struct nfs_lock_context *l_ctx,
+		fmode_t fmode,
+		int zero_seqid)
 {
 	nfs4_stateid stateid;
-	__be32 *p;
 
-	p = reserve_space(xdr, NFS4_STATEID_SIZE);
 	if (ctx->state != NULL) {
-		nfs4_copy_stateid(&stateid, ctx->state, l_ctx->lockowner, l_ctx->pid);
+		nfs4_select_rw_stateid(&stateid, ctx->state,
+				fmode, l_ctx->lockowner, l_ctx->pid);
 		if (zero_seqid)
-			stateid.stateid.seqid = 0;
-		xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE);
+			stateid.seqid = 0;
+		encode_nfs4_stateid(xdr, &stateid);
 	} else
-		xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
+		encode_nfs4_stateid(xdr, &zero_stateid);
 }
 
 static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr)
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 4);
-	*p = cpu_to_be32(OP_READ);
-
-	encode_stateid(xdr, args->context, args->lock_context,
-		       hdr->minorversion);
+	encode_op_hdr(xdr, OP_READ, decode_read_maxsz, hdr);
+	encode_open_stateid(xdr, args->context, args->lock_context,
+			FMODE_READ, hdr->minorversion);
 
 	p = reserve_space(xdr, 12);
 	p = xdr_encode_hyper(p, args->offset);
 	*p = cpu_to_be32(args->count);
-	hdr->nops++;
-	hdr->replen += decode_read_maxsz;
 }
 
 static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
@@ -1551,7 +1529,7 @@
 		FATTR4_WORD1_MOUNTED_ON_FILEID,
 	};
 	uint32_t dircount = readdir->count >> 1;
-	__be32 *p;
+	__be32 *p, verf[2];
 
 	if (readdir->plus) {
 		attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
@@ -1566,80 +1544,54 @@
 	if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
 		attrs[0] |= FATTR4_WORD0_FILEID;
 
-	p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
-	*p++ = cpu_to_be32(OP_READDIR);
-	p = xdr_encode_hyper(p, readdir->cookie);
-	p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE);
+	encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr);
+	encode_uint64(xdr, readdir->cookie);
+	encode_nfs4_verifier(xdr, &readdir->verifier);
+	p = reserve_space(xdr, 20);
 	*p++ = cpu_to_be32(dircount);
 	*p++ = cpu_to_be32(readdir->count);
 	*p++ = cpu_to_be32(2);
 
 	*p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]);
 	*p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
-	hdr->nops++;
-	hdr->replen += decode_readdir_maxsz;
+	memcpy(verf, readdir->verifier.data, sizeof(verf));
 	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
 			__func__,
 			(unsigned long long)readdir->cookie,
-			((u32 *)readdir->verifier.data)[0],
-			((u32 *)readdir->verifier.data)[1],
+			verf[0], verf[1],
 			attrs[0] & readdir->bitmask[0],
 			attrs[1] & readdir->bitmask[1]);
 }
 
 static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 4);
-	*p = cpu_to_be32(OP_READLINK);
-	hdr->nops++;
-	hdr->replen += decode_readlink_maxsz;
+	encode_op_hdr(xdr, OP_READLINK, decode_readlink_maxsz, hdr);
 }
 
 static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 8 + name->len);
-	*p++ = cpu_to_be32(OP_REMOVE);
-	xdr_encode_opaque(p, name->name, name->len);
-	hdr->nops++;
-	hdr->replen += decode_remove_maxsz;
+	encode_op_hdr(xdr, OP_REMOVE, decode_remove_maxsz, hdr);
+	encode_string(xdr, name->len, name->name);
 }
 
 static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 4);
-	*p = cpu_to_be32(OP_RENAME);
+	encode_op_hdr(xdr, OP_RENAME, decode_rename_maxsz, hdr);
 	encode_string(xdr, oldname->len, oldname->name);
 	encode_string(xdr, newname->len, newname->name);
-	hdr->nops++;
-	hdr->replen += decode_rename_maxsz;
 }
 
-static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr)
+static void encode_renew(struct xdr_stream *xdr, clientid4 clid,
+			 struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 12);
-	*p++ = cpu_to_be32(OP_RENEW);
-	xdr_encode_hyper(p, client_stateid->cl_clientid);
-	hdr->nops++;
-	hdr->replen += decode_renew_maxsz;
+	encode_op_hdr(xdr, OP_RENEW, decode_renew_maxsz, hdr);
+	encode_uint64(xdr, clid);
 }
 
 static void
 encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 4);
-	*p = cpu_to_be32(OP_RESTOREFH);
-	hdr->nops++;
-	hdr->replen += decode_restorefh_maxsz;
+	encode_op_hdr(xdr, OP_RESTOREFH, decode_restorefh_maxsz, hdr);
 }
 
 static void
@@ -1647,9 +1599,8 @@
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
-	*p++ = cpu_to_be32(OP_SETATTR);
-	xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
+	encode_op_hdr(xdr, OP_SETATTR, decode_setacl_maxsz, hdr);
+	encode_nfs4_stateid(xdr, &zero_stateid);
 	p = reserve_space(xdr, 2*4);
 	*p++ = cpu_to_be32(1);
 	*p = cpu_to_be32(FATTR4_WORD0_ACL);
@@ -1657,30 +1608,18 @@
 	p = reserve_space(xdr, 4);
 	*p = cpu_to_be32(arg->acl_len);
 	xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
-	hdr->nops++;
-	hdr->replen += decode_setacl_maxsz;
 }
 
 static void
 encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 4);
-	*p = cpu_to_be32(OP_SAVEFH);
-	hdr->nops++;
-	hdr->replen += decode_savefh_maxsz;
+	encode_op_hdr(xdr, OP_SAVEFH, decode_savefh_maxsz, hdr);
 }
 
 static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
-	*p++ = cpu_to_be32(OP_SETATTR);
-	xdr_encode_opaque_fixed(p, arg->stateid.data, NFS4_STATEID_SIZE);
-	hdr->nops++;
-	hdr->replen += decode_setattr_maxsz;
+	encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr);
+	encode_nfs4_stateid(xdr, &arg->stateid);
 	encode_attrs(xdr, arg->iap, server);
 }
 
@@ -1688,9 +1627,8 @@
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 4 + NFS4_VERIFIER_SIZE);
-	*p++ = cpu_to_be32(OP_SETCLIENTID);
-	xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE);
+	encode_op_hdr(xdr, OP_SETCLIENTID, decode_setclientid_maxsz, hdr);
+	encode_nfs4_verifier(xdr, setclientid->sc_verifier);
 
 	encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
 	p = reserve_space(xdr, 4);
@@ -1699,31 +1637,23 @@
 	encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
 	p = reserve_space(xdr, 4);
 	*p = cpu_to_be32(setclientid->sc_cb_ident);
-	hdr->nops++;
-	hdr->replen += decode_setclientid_maxsz;
 }
 
 static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_setclientid_res *arg, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE);
-	*p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM);
-	p = xdr_encode_hyper(p, arg->clientid);
-	xdr_encode_opaque_fixed(p, arg->confirm.data, NFS4_VERIFIER_SIZE);
-	hdr->nops++;
-	hdr->replen += decode_setclientid_confirm_maxsz;
+	encode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM,
+			decode_setclientid_confirm_maxsz, hdr);
+	encode_uint64(xdr, arg->clientid);
+	encode_nfs4_verifier(xdr, &arg->confirm);
 }
 
 static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 4);
-	*p = cpu_to_be32(OP_WRITE);
-
-	encode_stateid(xdr, args->context, args->lock_context,
-		       hdr->minorversion);
+	encode_op_hdr(xdr, OP_WRITE, decode_write_maxsz, hdr);
+	encode_open_stateid(xdr, args->context, args->lock_context,
+			FMODE_WRITE, hdr->minorversion);
 
 	p = reserve_space(xdr, 16);
 	p = xdr_encode_hyper(p, args->offset);
@@ -1731,32 +1661,18 @@
 	*p = cpu_to_be32(args->count);
 
 	xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
-	hdr->nops++;
-	hdr->replen += decode_write_maxsz;
 }
 
 static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
-
-	*p++ = cpu_to_be32(OP_DELEGRETURN);
-	xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
-	hdr->nops++;
-	hdr->replen += decode_delegreturn_maxsz;
+	encode_op_hdr(xdr, OP_DELEGRETURN, decode_delegreturn_maxsz, hdr);
+	encode_nfs4_stateid(xdr, stateid);
 }
 
 static void encode_secinfo(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
 {
-	int len = name->len;
-	__be32 *p;
-
-	p = reserve_space(xdr, 8 + len);
-	*p++ = cpu_to_be32(OP_SECINFO);
-	xdr_encode_opaque(p, name->name, len);
-	hdr->nops++;
-	hdr->replen += decode_secinfo_maxsz;
+	encode_op_hdr(xdr, OP_SECINFO, decode_secinfo_maxsz, hdr);
+	encode_string(xdr, name->len, name->name);
 }
 
 #if defined(CONFIG_NFS_V4_1)
@@ -1766,19 +1682,39 @@
 			       struct compound_hdr *hdr)
 {
 	__be32 *p;
+	char impl_name[NFS4_OPAQUE_LIMIT];
+	int len = 0;
 
-	p = reserve_space(xdr, 4 + sizeof(args->verifier->data));
-	*p++ = cpu_to_be32(OP_EXCHANGE_ID);
-	xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data));
+	encode_op_hdr(xdr, OP_EXCHANGE_ID, decode_exchange_id_maxsz, hdr);
+	encode_nfs4_verifier(xdr, args->verifier);
 
 	encode_string(xdr, args->id_len, args->id);
 
 	p = reserve_space(xdr, 12);
 	*p++ = cpu_to_be32(args->flags);
 	*p++ = cpu_to_be32(0);	/* zero length state_protect4_a */
-	*p = cpu_to_be32(0);	/* zero length implementation id array */
-	hdr->nops++;
-	hdr->replen += decode_exchange_id_maxsz;
+
+	if (send_implementation_id &&
+	    sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) > 1 &&
+	    sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN)
+		<= NFS4_OPAQUE_LIMIT + 1)
+		len = snprintf(impl_name, sizeof(impl_name), "%s %s %s %s",
+			       utsname()->sysname, utsname()->release,
+			       utsname()->version, utsname()->machine);
+
+	if (len > 0) {
+		*p = cpu_to_be32(1);	/* implementation id array length=1 */
+
+		encode_string(xdr,
+			sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) - 1,
+			CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN);
+		encode_string(xdr, len, impl_name);
+		/* just send zeros for nii_date - the date is in nii_name */
+		p = reserve_space(xdr, 12);
+		p = xdr_encode_hyper(p, 0);
+		*p = cpu_to_be32(0);
+	} else
+		*p = cpu_to_be32(0);	/* implementation id array length=0 */
 }
 
 static void encode_create_session(struct xdr_stream *xdr,
@@ -1801,8 +1737,8 @@
 	len = scnprintf(machine_name, sizeof(machine_name), "%s",
 			clp->cl_ipaddr);
 
-	p = reserve_space(xdr, 20 + 2*28 + 20 + len + 12);
-	*p++ = cpu_to_be32(OP_CREATE_SESSION);
+	encode_op_hdr(xdr, OP_CREATE_SESSION, decode_create_session_maxsz, hdr);
+	p = reserve_space(xdr, 16 + 2*28 + 20 + len + 12);
 	p = xdr_encode_hyper(p, clp->cl_clientid);
 	*p++ = cpu_to_be32(clp->cl_seqid);			/*Sequence id */
 	*p++ = cpu_to_be32(args->flags);			/*flags */
@@ -1835,33 +1771,22 @@
 	*p++ = cpu_to_be32(0);				/* UID */
 	*p++ = cpu_to_be32(0);				/* GID */
 	*p = cpu_to_be32(0);				/* No more gids */
-	hdr->nops++;
-	hdr->replen += decode_create_session_maxsz;
 }
 
 static void encode_destroy_session(struct xdr_stream *xdr,
 				   struct nfs4_session *session,
 				   struct compound_hdr *hdr)
 {
-	__be32 *p;
-	p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN);
-	*p++ = cpu_to_be32(OP_DESTROY_SESSION);
-	xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
-	hdr->nops++;
-	hdr->replen += decode_destroy_session_maxsz;
+	encode_op_hdr(xdr, OP_DESTROY_SESSION, decode_destroy_session_maxsz, hdr);
+	encode_opaque_fixed(xdr, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
 }
 
 static void encode_reclaim_complete(struct xdr_stream *xdr,
 				    struct nfs41_reclaim_complete_args *args,
 				    struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 8);
-	*p++ = cpu_to_be32(OP_RECLAIM_COMPLETE);
-	*p++ = cpu_to_be32(args->one_fs);
-	hdr->nops++;
-	hdr->replen += decode_reclaim_complete_maxsz;
+	encode_op_hdr(xdr, OP_RECLAIM_COMPLETE, decode_reclaim_complete_maxsz, hdr);
+	encode_uint32(xdr, args->one_fs);
 }
 #endif /* CONFIG_NFS_V4_1 */
 
@@ -1883,8 +1808,7 @@
 	WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE);
 	slot = tp->slots + args->sa_slotid;
 
-	p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN + 16);
-	*p++ = cpu_to_be32(OP_SEQUENCE);
+	encode_op_hdr(xdr, OP_SEQUENCE, decode_sequence_maxsz, hdr);
 
 	/*
 	 * Sessionid + seqid + slotid + max slotid + cache_this
@@ -1898,13 +1822,12 @@
 		((u32 *)session->sess_id.data)[3],
 		slot->seq_nr, args->sa_slotid,
 		tp->highest_used_slotid, args->sa_cache_this);
+	p = reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 16);
 	p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
 	*p++ = cpu_to_be32(slot->seq_nr);
 	*p++ = cpu_to_be32(args->sa_slotid);
 	*p++ = cpu_to_be32(tp->highest_used_slotid);
 	*p = cpu_to_be32(args->sa_cache_this);
-	hdr->nops++;
-	hdr->replen += decode_sequence_maxsz;
 #endif /* CONFIG_NFS_V4_1 */
 }
 
@@ -1919,14 +1842,12 @@
 		.data = "dummmmmy",
 	};
 
-	p = reserve_space(xdr, 20);
-	*p++ = cpu_to_be32(OP_GETDEVICELIST);
+	encode_op_hdr(xdr, OP_GETDEVICELIST, decode_getdevicelist_maxsz, hdr);
+	p = reserve_space(xdr, 16);
 	*p++ = cpu_to_be32(args->layoutclass);
 	*p++ = cpu_to_be32(NFS4_PNFS_GETDEVLIST_MAXNUM);
 	xdr_encode_hyper(p, 0ULL);                          /* cookie */
 	encode_nfs4_verifier(xdr, &dummy);
-	hdr->nops++;
-	hdr->replen += decode_getdevicelist_maxsz;
 }
 
 static void
@@ -1936,15 +1857,13 @@
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 16 + NFS4_DEVICEID4_SIZE);
-	*p++ = cpu_to_be32(OP_GETDEVICEINFO);
+	encode_op_hdr(xdr, OP_GETDEVICEINFO, decode_getdeviceinfo_maxsz, hdr);
+	p = reserve_space(xdr, 12 + NFS4_DEVICEID4_SIZE);
 	p = xdr_encode_opaque_fixed(p, args->pdev->dev_id.data,
 				    NFS4_DEVICEID4_SIZE);
 	*p++ = cpu_to_be32(args->pdev->layout_type);
 	*p++ = cpu_to_be32(args->pdev->pglen);		/* gdia_maxcount */
 	*p++ = cpu_to_be32(0);				/* bitmap length 0 */
-	hdr->nops++;
-	hdr->replen += decode_getdeviceinfo_maxsz;
 }
 
 static void
@@ -1954,16 +1873,16 @@
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE);
-	*p++ = cpu_to_be32(OP_LAYOUTGET);
+	encode_op_hdr(xdr, OP_LAYOUTGET, decode_layoutget_maxsz, hdr);
+	p = reserve_space(xdr, 36);
 	*p++ = cpu_to_be32(0);     /* Signal layout available */
 	*p++ = cpu_to_be32(args->type);
 	*p++ = cpu_to_be32(args->range.iomode);
 	p = xdr_encode_hyper(p, args->range.offset);
 	p = xdr_encode_hyper(p, args->range.length);
 	p = xdr_encode_hyper(p, args->minlength);
-	p = xdr_encode_opaque_fixed(p, &args->stateid.data, NFS4_STATEID_SIZE);
-	*p = cpu_to_be32(args->maxcount);
+	encode_nfs4_stateid(xdr, &args->stateid);
+	encode_uint32(xdr, args->maxcount);
 
 	dprintk("%s: 1st type:0x%x iomode:%d off:%lu len:%lu mc:%d\n",
 		__func__,
@@ -1972,8 +1891,6 @@
 		(unsigned long)args->range.offset,
 		(unsigned long)args->range.length,
 		args->maxcount);
-	hdr->nops++;
-	hdr->replen += decode_layoutget_maxsz;
 }
 
 static int
@@ -1987,13 +1904,14 @@
 	dprintk("%s: lbw: %llu type: %d\n", __func__, args->lastbytewritten,
 		NFS_SERVER(args->inode)->pnfs_curr_ld->id);
 
-	p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE);
-	*p++ = cpu_to_be32(OP_LAYOUTCOMMIT);
+	encode_op_hdr(xdr, OP_LAYOUTCOMMIT, decode_layoutcommit_maxsz, hdr);
+	p = reserve_space(xdr, 20);
 	/* Only whole file layouts */
 	p = xdr_encode_hyper(p, 0); /* offset */
 	p = xdr_encode_hyper(p, args->lastbytewritten + 1);	/* length */
-	*p++ = cpu_to_be32(0); /* reclaim */
-	p = xdr_encode_opaque_fixed(p, args->stateid.data, NFS4_STATEID_SIZE);
+	*p = cpu_to_be32(0); /* reclaim */
+	encode_nfs4_stateid(xdr, &args->stateid);
+	p = reserve_space(xdr, 20);
 	*p++ = cpu_to_be32(1); /* newoffset = TRUE */
 	p = xdr_encode_hyper(p, args->lastbytewritten);
 	*p++ = cpu_to_be32(0); /* Never send time_modify_changed */
@@ -2002,13 +1920,9 @@
 	if (NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit)
 		NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit(
 			NFS_I(inode)->layout, xdr, args);
-	else {
-		p = reserve_space(xdr, 4);
-		*p = cpu_to_be32(0); /* no layout-type payload */
-	}
+	else
+		encode_uint32(xdr, 0); /* no layout-type payload */
 
-	hdr->nops++;
-	hdr->replen += decode_layoutcommit_maxsz;
 	return 0;
 }
 
@@ -2019,27 +1933,23 @@
 {
 	__be32 *p;
 
-	p = reserve_space(xdr, 20);
-	*p++ = cpu_to_be32(OP_LAYOUTRETURN);
+	encode_op_hdr(xdr, OP_LAYOUTRETURN, decode_layoutreturn_maxsz, hdr);
+	p = reserve_space(xdr, 16);
 	*p++ = cpu_to_be32(0);		/* reclaim. always 0 for now */
 	*p++ = cpu_to_be32(args->layout_type);
 	*p++ = cpu_to_be32(IOMODE_ANY);
 	*p = cpu_to_be32(RETURN_FILE);
-	p = reserve_space(xdr, 16 + NFS4_STATEID_SIZE);
+	p = reserve_space(xdr, 16);
 	p = xdr_encode_hyper(p, 0);
 	p = xdr_encode_hyper(p, NFS4_MAX_UINT64);
 	spin_lock(&args->inode->i_lock);
-	xdr_encode_opaque_fixed(p, &args->stateid.data, NFS4_STATEID_SIZE);
+	encode_nfs4_stateid(xdr, &args->stateid);
 	spin_unlock(&args->inode->i_lock);
 	if (NFS_SERVER(args->inode)->pnfs_curr_ld->encode_layoutreturn) {
 		NFS_SERVER(args->inode)->pnfs_curr_ld->encode_layoutreturn(
 			NFS_I(args->inode)->layout, xdr, args);
-	} else {
-		p = reserve_space(xdr, 4);
-		*p = cpu_to_be32(0);
-	}
-	hdr->nops++;
-	hdr->replen += decode_layoutreturn_maxsz;
+	} else
+		encode_uint32(xdr, 0);
 }
 
 static int
@@ -2047,12 +1957,8 @@
 		       const struct nfs41_secinfo_no_name_args *args,
 		       struct compound_hdr *hdr)
 {
-	__be32 *p;
-	p = reserve_space(xdr, 8);
-	*p++ = cpu_to_be32(OP_SECINFO_NO_NAME);
-	*p++ = cpu_to_be32(args->style);
-	hdr->nops++;
-	hdr->replen += decode_secinfo_no_name_maxsz;
+	encode_op_hdr(xdr, OP_SECINFO_NO_NAME, decode_secinfo_no_name_maxsz, hdr);
+	encode_uint32(xdr, args->style);
 	return 0;
 }
 
@@ -2060,26 +1966,17 @@
 				struct nfs41_test_stateid_args *args,
 				struct compound_hdr *hdr)
 {
-	__be32 *p;
-
-	p = reserve_space(xdr, 8 + NFS4_STATEID_SIZE);
-	*p++ = cpu_to_be32(OP_TEST_STATEID);
-	*p++ = cpu_to_be32(1);
-	xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
-	hdr->nops++;
-	hdr->replen += decode_test_stateid_maxsz;
+	encode_op_hdr(xdr, OP_TEST_STATEID, decode_test_stateid_maxsz, hdr);
+	encode_uint32(xdr, 1);
+	encode_nfs4_stateid(xdr, args->stateid);
 }
 
 static void encode_free_stateid(struct xdr_stream *xdr,
 				struct nfs41_free_stateid_args *args,
 				struct compound_hdr *hdr)
 {
-	__be32 *p;
-	p = reserve_space(xdr, 4 + NFS4_STATEID_SIZE);
-	*p++ = cpu_to_be32(OP_FREE_STATEID);
-	xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
-	hdr->nops++;
-	hdr->replen += decode_free_stateid_maxsz;
+	encode_op_hdr(xdr, OP_FREE_STATEID, decode_free_stateid_maxsz, hdr);
+	encode_nfs4_stateid(xdr, args->stateid);
 }
 #endif /* CONFIG_NFS_V4_1 */
 
@@ -2633,6 +2530,7 @@
 	encode_sequence(xdr, &args->seq_args, &hdr);
 	encode_putfh(xdr, args->fhandle, &hdr);
 	encode_getattr_one(xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
+			   FATTR4_WORD0_FH_EXPIRE_TYPE|
 			   FATTR4_WORD0_LINK_SUPPORT|
 			   FATTR4_WORD0_SYMLINK_SUPPORT|
 			   FATTR4_WORD0_ACLSUPPORT, &hdr);
@@ -2650,7 +2548,7 @@
 	};
 
 	encode_compound_hdr(xdr, req, &hdr);
-	encode_renew(xdr, clp, &hdr);
+	encode_renew(xdr, clp->cl_clientid, &hdr);
 	encode_nops(&hdr);
 }
 
@@ -3180,6 +3078,28 @@
 	return -EIO;
 }
 
+static int decode_attr_fh_expire_type(struct xdr_stream *xdr,
+				      uint32_t *bitmap, uint32_t *type)
+{
+	__be32 *p;
+
+	*type = 0;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_FH_EXPIRE_TYPE - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_FH_EXPIRE_TYPE)) {
+		p = xdr_inline_decode(xdr, 4);
+		if (unlikely(!p))
+			goto out_overflow;
+		*type = be32_to_cpup(p);
+		bitmap[0] &= ~FATTR4_WORD0_FH_EXPIRE_TYPE;
+	}
+	dprintk("%s: expire type=0x%x\n", __func__, *type);
+	return 0;
+out_overflow:
+	print_overflow_msg(__func__, xdr);
+	return -EIO;
+}
+
 static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
 {
 	__be32 *p;
@@ -3513,16 +3433,17 @@
 	n = be32_to_cpup(p);
 	if (n == 0)
 		goto root_path;
-	dprintk("path ");
+	dprintk("pathname4: ");
 	path->ncomponents = 0;
 	while (path->ncomponents < n) {
 		struct nfs4_string *component = &path->components[path->ncomponents];
 		status = decode_opaque_inline(xdr, &component->len, &component->data);
 		if (unlikely(status != 0))
 			goto out_eio;
-		if (path->ncomponents != n)
-			dprintk("/");
-		dprintk("%s", component->data);
+		ifdebug (XDR)
+			pr_cont("%s%.*s ",
+				(path->ncomponents != n ? "/ " : ""),
+				component->len, component->data);
 		if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS)
 			path->ncomponents++;
 		else {
@@ -3531,14 +3452,13 @@
 		}
 	}
 out:
-	dprintk("\n");
 	return status;
 root_path:
 /* a root pathname is sent as a zero component4 */
 	path->ncomponents = 1;
 	path->components[0].len=0;
 	path->components[0].data=NULL;
-	dprintk("path /\n");
+	dprintk("pathname4: /\n");
 	goto out;
 out_eio:
 	dprintk(" status %d", status);
@@ -3560,7 +3480,11 @@
 	status = 0;
 	if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
 		goto out;
-	dprintk("%s: fsroot ", __func__);
+	status = -EIO;
+	/* Ignore borken servers that return unrequested attrs */
+	if (unlikely(res == NULL))
+		goto out;
+	dprintk("%s: fsroot:\n", __func__);
 	status = decode_pathname(xdr, &res->fs_path);
 	if (unlikely(status != 0))
 		goto out;
@@ -3581,7 +3505,7 @@
 		m = be32_to_cpup(p);
 
 		loc->nservers = 0;
-		dprintk("%s: servers ", __func__);
+		dprintk("%s: servers:\n", __func__);
 		while (loc->nservers < m) {
 			struct nfs4_string *server = &loc->servers[loc->nservers];
 			status = decode_opaque_inline(xdr, &server->len, &server->data);
@@ -3613,7 +3537,7 @@
 			res->nlocations++;
 	}
 	if (res->nlocations != 0)
-		status = NFS_ATTR_FATTR_V4_REFERRAL;
+		status = NFS_ATTR_FATTR_V4_LOCATIONS;
 out:
 	dprintk("%s: fs_locations done, error = %d\n", __func__, status);
 	return status;
@@ -4157,7 +4081,7 @@
 
 static int decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
 {
-	return decode_opaque_fixed(xdr, stateid->data, NFS4_STATEID_SIZE);
+	return decode_opaque_fixed(xdr, stateid, NFS4_STATEID_SIZE);
 }
 
 static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
@@ -4174,7 +4098,7 @@
 
 static int decode_verifier(struct xdr_stream *xdr, void *verifier)
 {
-	return decode_opaque_fixed(xdr, verifier, 8);
+	return decode_opaque_fixed(xdr, verifier, NFS4_VERIFIER_SIZE);
 }
 
 static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
@@ -4224,6 +4148,9 @@
 		goto xdr_error;
 	if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0)
 		goto xdr_error;
+	if ((status = decode_attr_fh_expire_type(xdr, bitmap,
+						 &res->fh_expire_type)) != 0)
+		goto xdr_error;
 	if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0)
 		goto xdr_error;
 	if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0)
@@ -4294,6 +4221,7 @@
 
 static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
 		struct nfs_fattr *fattr, struct nfs_fh *fh,
+		struct nfs4_fs_locations *fs_loc,
 		const struct nfs_server *server)
 {
 	int status;
@@ -4341,9 +4269,7 @@
 		goto xdr_error;
 	fattr->valid |= status;
 
-	status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
-						struct nfs4_fs_locations,
-						fattr));
+	status = decode_attr_fs_locations(xdr, bitmap, fs_loc);
 	if (status < 0)
 		goto xdr_error;
 	fattr->valid |= status;
@@ -4407,7 +4333,8 @@
 }
 
 static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr,
-		struct nfs_fh *fh, const struct nfs_server *server)
+		struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc,
+		const struct nfs_server *server)
 {
 	__be32 *savep;
 	uint32_t attrlen,
@@ -4426,7 +4353,7 @@
 	if (status < 0)
 		goto xdr_error;
 
-	status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server);
+	status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc, server);
 	if (status < 0)
 		goto xdr_error;
 
@@ -4439,7 +4366,7 @@
 static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
 		const struct nfs_server *server)
 {
-	return decode_getfattr_generic(xdr, fattr, NULL, server);
+	return decode_getfattr_generic(xdr, fattr, NULL, NULL, server);
 }
 
 /*
@@ -4463,8 +4390,8 @@
 		return 0;
 	}
 	if (num > 1)
-		printk(KERN_INFO "%s: Warning: Multiple pNFS layout drivers "
-			"per filesystem not supported\n", __func__);
+		printk(KERN_INFO "NFS: %s: Warning: Multiple pNFS layout "
+			"drivers per filesystem not supported\n", __func__);
 
 	/* Decode and set first layout type, move xdr->p past unused types */
 	p = xdr_inline_decode(xdr, num * 4);
@@ -4863,17 +4790,16 @@
 	size_t		hdrlen;
 	u32		recvd, pglen = rcvbuf->page_len;
 	int		status;
+	__be32		verf[2];
 
 	status = decode_op_hdr(xdr, OP_READDIR);
 	if (!status)
 		status = decode_verifier(xdr, readdir->verifier.data);
 	if (unlikely(status))
 		return status;
+	memcpy(verf, readdir->verifier.data, sizeof(verf));
 	dprintk("%s: verifier = %08x:%08x\n",
-			__func__,
-			((u32 *)readdir->verifier.data)[0],
-			((u32 *)readdir->verifier.data)[1]);
-
+			__func__, verf[0], verf[1]);
 
 	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
 	recvd = rcvbuf->len - hdrlen;
@@ -5120,7 +5046,7 @@
 		goto out_overflow;
 	res->count = be32_to_cpup(p++);
 	res->verf->committed = be32_to_cpup(p++);
-	memcpy(res->verf->verifier, p, 8);
+	memcpy(res->verf->verifier, p, NFS4_VERIFIER_SIZE);
 	return 0;
 out_overflow:
 	print_overflow_msg(__func__, xdr);
@@ -5214,6 +5140,7 @@
 	char *dummy_str;
 	int status;
 	struct nfs_client *clp = res->client;
+	uint32_t impl_id_count;
 
 	status = decode_op_hdr(xdr, OP_EXCHANGE_ID);
 	if (status)
@@ -5255,11 +5182,38 @@
 	memcpy(res->server_scope->server_scope, dummy_str, dummy);
 	res->server_scope->server_scope_sz = dummy;
 
-	/* Throw away Implementation id array */
-	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
-	if (unlikely(status))
-		return status;
+	/* Implementation Id */
+	p = xdr_inline_decode(xdr, 4);
+	if (unlikely(!p))
+		goto out_overflow;
+	impl_id_count = be32_to_cpup(p++);
 
+	if (impl_id_count) {
+		/* nii_domain */
+		status = decode_opaque_inline(xdr, &dummy, &dummy_str);
+		if (unlikely(status))
+			return status;
+		if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
+			return -EIO;
+		memcpy(res->impl_id->domain, dummy_str, dummy);
+
+		/* nii_name */
+		status = decode_opaque_inline(xdr, &dummy, &dummy_str);
+		if (unlikely(status))
+			return status;
+		if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
+			return -EIO;
+		memcpy(res->impl_id->name, dummy_str, dummy);
+
+		/* nii_date */
+		p = xdr_inline_decode(xdr, 12);
+		if (unlikely(!p))
+			goto out_overflow;
+		p = xdr_decode_hyper(p, &res->impl_id->date.seconds);
+		res->impl_id->date.nseconds = be32_to_cpup(p);
+
+		/* if there's more than one entry, ignore the rest */
+	}
 	return 0;
 out_overflow:
 	print_overflow_msg(__func__, xdr);
@@ -5285,8 +5239,8 @@
 	attrs->max_reqs = be32_to_cpup(p++);
 	nr_attrs = be32_to_cpup(p);
 	if (unlikely(nr_attrs > 1)) {
-		printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n",
-			__func__, nr_attrs);
+		printk(KERN_WARNING "NFS: %s: Invalid rdma channel attrs "
+			"count %u\n", __func__, nr_attrs);
 		return -EINVAL;
 	}
 	if (nr_attrs == 1) {
@@ -5436,14 +5390,14 @@
 	p += 2;
 
 	/* Read verifier */
-	p = xdr_decode_opaque_fixed(p, verftemp.verifier, 8);
+	p = xdr_decode_opaque_fixed(p, verftemp.verifier, NFS4_VERIFIER_SIZE);
 
 	res->num_devs = be32_to_cpup(p);
 
 	dprintk("%s: num_dev %d\n", __func__, res->num_devs);
 
 	if (res->num_devs > NFS4_PNFS_GETDEVLIST_MAXNUM) {
-		printk(KERN_ERR "%s too many result dev_num %u\n",
+		printk(KERN_ERR "NFS: %s too many result dev_num %u\n",
 				__func__, res->num_devs);
 		return -EIO;
 	}
@@ -5537,11 +5491,14 @@
 	status = decode_op_hdr(xdr, OP_LAYOUTGET);
 	if (status)
 		return status;
-	p = xdr_inline_decode(xdr, 8 + NFS4_STATEID_SIZE);
+	p = xdr_inline_decode(xdr, 4);
 	if (unlikely(!p))
 		goto out_overflow;
-	res->return_on_close = be32_to_cpup(p++);
-	p = xdr_decode_opaque_fixed(p, res->stateid.data, NFS4_STATEID_SIZE);
+	res->return_on_close = be32_to_cpup(p);
+	decode_stateid(xdr, &res->stateid);
+	p = xdr_inline_decode(xdr, 4);
+	if (unlikely(!p))
+		goto out_overflow;
 	layout_count = be32_to_cpup(p);
 	if (!layout_count) {
 		dprintk("%s: server responded with empty layout array\n",
@@ -5666,7 +5623,8 @@
 	if (unlikely(!p))
 		goto out_overflow;
 	res->status = be32_to_cpup(p++);
-	return res->status;
+
+	return status;
 out_overflow:
 	print_overflow_msg(__func__, xdr);
 out:
@@ -6583,8 +6541,9 @@
 	if (status)
 		goto out;
 	xdr_enter_page(xdr, PAGE_SIZE);
-	status = decode_getfattr(xdr, &res->fs_locations->fattr,
-				 res->fs_locations->server);
+	status = decode_getfattr_generic(xdr, &res->fs_locations->fattr,
+					 NULL, res->fs_locations,
+					 res->fs_locations->server);
 out:
 	return status;
 }
@@ -6964,7 +6923,7 @@
 		goto out_overflow;
 
 	if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
-					entry->server) < 0)
+				  NULL, entry->server) < 0)
 		goto out_overflow;
 	if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
 		entry->ino = entry->fattr->mounted_on_fileid;
@@ -7112,7 +7071,7 @@
 #endif /* CONFIG_NFS_V4_1 */
 };
 
-struct rpc_version		nfs_version4 = {
+const struct rpc_version nfs_version4 = {
 	.number			= 4,
 	.nrprocs		= ARRAY_SIZE(nfs4_procedures),
 	.procs			= nfs4_procedures
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index c4744e1..cd3c910 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -104,7 +104,7 @@
 /* server:export path string passed to super.c */
 static char nfs_root_device[NFS_MAXPATHLEN + 1] __initdata = "";
 
-#ifdef RPC_DEBUG
+#ifdef NFS_DEBUG
 /*
  * When the "nfsrootdebug" kernel command line option is specified,
  * enable debugging messages for NFSROOT.
diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c
index 55d0128..4bff4a3 100644
--- a/fs/nfs/objlayout/objio_osd.c
+++ b/fs/nfs/objlayout/objio_osd.c
@@ -137,6 +137,7 @@
 	struct objio_dev_ent *ode;
 	struct osd_dev *od;
 	struct osd_dev_info odi;
+	bool retry_flag = true;
 	int err;
 
 	ode = _dev_list_find(NFS_SERVER(pnfslay->plh_inode), d_id);
@@ -171,10 +172,18 @@
 		goto out;
 	}
 
+retry_lookup:
 	od = osduld_info_lookup(&odi);
 	if (unlikely(IS_ERR(od))) {
 		err = PTR_ERR(od);
 		dprintk("%s: osduld_info_lookup => %d\n", __func__, err);
+		if (err == -ENODEV && retry_flag) {
+			err = objlayout_autologin(deviceaddr);
+			if (likely(!err)) {
+				retry_flag = false;
+				goto retry_lookup;
+			}
+		}
 		goto out;
 	}
 
@@ -205,25 +214,36 @@
 int __alloc_objio_seg(unsigned numdevs, gfp_t gfp_flags,
 		       struct objio_segment **pseg)
 {
-	struct __alloc_objio_segment {
-		struct objio_segment olseg;
-		struct ore_dev *ods[numdevs];
-		struct ore_comp	comps[numdevs];
-	} *aolseg;
+/*	This is the in memory structure of the objio_segment
+ *
+ *	struct __alloc_objio_segment {
+ *		struct objio_segment olseg;
+ *		struct ore_dev *ods[numdevs];
+ *		struct ore_comp	comps[numdevs];
+ *	} *aolseg;
+ *	NOTE: The code as above compiles and runs perfectly. It is elegant,
+ *	type safe and compact. At some Past time Linus has decided he does not
+ *	like variable length arrays, For the sake of this principal we uglify
+ *	the code as below.
+ */
+	struct objio_segment *lseg;
+	size_t lseg_size = sizeof(*lseg) +
+			numdevs * sizeof(lseg->oc.ods[0]) +
+			numdevs * sizeof(*lseg->oc.comps);
 
-	aolseg = kzalloc(sizeof(*aolseg), gfp_flags);
-	if (unlikely(!aolseg)) {
+	lseg = kzalloc(lseg_size, gfp_flags);
+	if (unlikely(!lseg)) {
 		dprintk("%s: Faild allocation numdevs=%d size=%zd\n", __func__,
-			numdevs, sizeof(*aolseg));
+			numdevs, lseg_size);
 		return -ENOMEM;
 	}
 
-	aolseg->olseg.oc.numdevs = numdevs;
-	aolseg->olseg.oc.single_comp = EC_MULTPLE_COMPS;
-	aolseg->olseg.oc.comps = aolseg->comps;
-	aolseg->olseg.oc.ods = aolseg->ods;
+	lseg->oc.numdevs = numdevs;
+	lseg->oc.single_comp = EC_MULTPLE_COMPS;
+	lseg->oc.ods = (void *)(lseg + 1);
+	lseg->oc.comps = (void *)(lseg->oc.ods + numdevs);
 
-	*pseg = &aolseg->olseg;
+	*pseg = lseg;
 	return 0;
 }
 
@@ -582,10 +602,10 @@
 
 	if (ret)
 		printk(KERN_INFO
-			"%s: Registering OSD pNFS Layout Driver failed: error=%d\n",
+			"NFS: %s: Registering OSD pNFS Layout Driver failed: error=%d\n",
 			__func__, ret);
 	else
-		printk(KERN_INFO "%s: Registered OSD pNFS Layout Driver\n",
+		printk(KERN_INFO "NFS: %s: Registered OSD pNFS Layout Driver\n",
 			__func__);
 	return ret;
 }
@@ -594,7 +614,7 @@
 objlayout_exit(void)
 {
 	pnfs_unregister_layoutdriver(&objlayout_type);
-	printk(KERN_INFO "%s: Unregistered OSD pNFS Layout Driver\n",
+	printk(KERN_INFO "NFS: %s: Unregistered OSD pNFS Layout Driver\n",
 	       __func__);
 }
 
diff --git a/fs/nfs/objlayout/objlayout.c b/fs/nfs/objlayout/objlayout.c
index b3c2903..8d45f1c 100644
--- a/fs/nfs/objlayout/objlayout.c
+++ b/fs/nfs/objlayout/objlayout.c
@@ -37,6 +37,9 @@
  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <linux/kmod.h>
+#include <linux/moduleparam.h>
+#include <linux/ratelimit.h>
 #include <scsi/osd_initiator.h>
 #include "objlayout.h"
 
@@ -156,7 +159,7 @@
 	return end > start ? end - 1 : NFS4_MAX_UINT64;
 }
 
-void _fix_verify_io_params(struct pnfs_layout_segment *lseg,
+static void _fix_verify_io_params(struct pnfs_layout_segment *lseg,
 			   struct page ***p_pages, unsigned *p_pgbase,
 			   u64 offset, unsigned long count)
 {
@@ -490,9 +493,9 @@
 			if (!ioerr->oer_errno)
 				continue;
 
-			printk(KERN_ERR "%s: err[%d]: errno=%d is_write=%d "
-				"dev(%llx:%llx) par=0x%llx obj=0x%llx "
-				"offset=0x%llx length=0x%llx\n",
+			printk(KERN_ERR "NFS: %s: err[%d]: errno=%d "
+				"is_write=%d dev(%llx:%llx) par=0x%llx "
+				"obj=0x%llx offset=0x%llx length=0x%llx\n",
 				__func__, i, ioerr->oer_errno,
 				ioerr->oer_iswrite,
 				_DEVID_LO(&ioerr->oer_component.oid_device_id),
@@ -651,3 +654,134 @@
 	__free_page(odi->page);
 	kfree(odi);
 }
+
+enum {
+	OBJLAYOUT_MAX_URI_LEN = 256, OBJLAYOUT_MAX_OSDNAME_LEN = 64,
+	OBJLAYOUT_MAX_SYSID_HEX_LEN = OSD_SYSTEMID_LEN * 2 + 1,
+	OSD_LOGIN_UPCALL_PATHLEN  = 256
+};
+
+static char osd_login_prog[OSD_LOGIN_UPCALL_PATHLEN] = "/sbin/osd_login";
+
+module_param_string(osd_login_prog, osd_login_prog, sizeof(osd_login_prog),
+		    0600);
+MODULE_PARM_DESC(osd_login_prog, "Path to the osd_login upcall program");
+
+struct __auto_login {
+	char uri[OBJLAYOUT_MAX_URI_LEN];
+	char osdname[OBJLAYOUT_MAX_OSDNAME_LEN];
+	char systemid_hex[OBJLAYOUT_MAX_SYSID_HEX_LEN];
+};
+
+static int __objlayout_upcall(struct __auto_login *login)
+{
+	static char *envp[] = { "HOME=/",
+		"TERM=linux",
+		"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+		NULL
+	};
+	char *argv[8];
+	int ret;
+
+	if (unlikely(!osd_login_prog[0])) {
+		dprintk("%s: osd_login_prog is disabled\n", __func__);
+		return -EACCES;
+	}
+
+	dprintk("%s uri: %s\n", __func__, login->uri);
+	dprintk("%s osdname %s\n", __func__, login->osdname);
+	dprintk("%s systemid_hex %s\n", __func__, login->systemid_hex);
+
+	argv[0] = (char *)osd_login_prog;
+	argv[1] = "-u";
+	argv[2] = login->uri;
+	argv[3] = "-o";
+	argv[4] = login->osdname;
+	argv[5] = "-s";
+	argv[6] = login->systemid_hex;
+	argv[7] = NULL;
+
+	ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
+	/*
+	 * Disable the upcall mechanism if we're getting an ENOENT or
+	 * EACCES error. The admin can re-enable it on the fly by using
+	 * sysfs to set the objlayoutdriver.osd_login_prog module parameter once
+	 * the problem has been fixed.
+	 */
+	if (ret == -ENOENT || ret == -EACCES) {
+		printk(KERN_ERR "PNFS-OBJ: %s was not found please set "
+			"objlayoutdriver.osd_login_prog kernel parameter!\n",
+			osd_login_prog);
+		osd_login_prog[0] = '\0';
+	}
+	dprintk("%s %s return value: %d\n", __func__, osd_login_prog, ret);
+
+	return ret;
+}
+
+/* Assume dest is all zeros */
+static void __copy_nfsS_and_zero_terminate(struct nfs4_string s,
+					   char *dest, int max_len,
+					   const char *var_name)
+{
+	if (!s.len)
+		return;
+
+	if (s.len >= max_len) {
+		pr_warn_ratelimited(
+			"objlayout_autologin: %s: s.len(%d) >= max_len(%d)",
+			var_name, s.len, max_len);
+		s.len = max_len - 1; /* space for null terminator */
+	}
+
+	memcpy(dest, s.data, s.len);
+}
+
+/* Assume sysid is all zeros */
+static void _sysid_2_hex(struct nfs4_string s,
+		  char sysid[OBJLAYOUT_MAX_SYSID_HEX_LEN])
+{
+	int i;
+	char *cur;
+
+	if (!s.len)
+		return;
+
+	if (s.len != OSD_SYSTEMID_LEN) {
+		pr_warn_ratelimited(
+		    "objlayout_autologin: systemid_len(%d) != OSD_SYSTEMID_LEN",
+		    s.len);
+		if (s.len > OSD_SYSTEMID_LEN)
+			s.len = OSD_SYSTEMID_LEN;
+	}
+
+	cur = sysid;
+	for (i = 0; i < s.len; i++)
+		cur = hex_byte_pack(cur, s.data[i]);
+}
+
+int objlayout_autologin(struct pnfs_osd_deviceaddr *deviceaddr)
+{
+	int rc;
+	struct __auto_login login;
+
+	if (!deviceaddr->oda_targetaddr.ota_netaddr.r_addr.len)
+		return -ENODEV;
+
+	memset(&login, 0, sizeof(login));
+	__copy_nfsS_and_zero_terminate(
+		deviceaddr->oda_targetaddr.ota_netaddr.r_addr,
+		login.uri, sizeof(login.uri), "URI");
+
+	__copy_nfsS_and_zero_terminate(
+		deviceaddr->oda_osdname,
+		login.osdname, sizeof(login.osdname), "OSDNAME");
+
+	_sysid_2_hex(deviceaddr->oda_systemid, login.systemid_hex);
+
+	rc = __objlayout_upcall(&login);
+	if (rc > 0) /* script returns positive values */
+		rc = -ENODEV;
+
+	return rc;
+}
diff --git a/fs/nfs/objlayout/objlayout.h b/fs/nfs/objlayout/objlayout.h
index 8ec3472..880ba08 100644
--- a/fs/nfs/objlayout/objlayout.h
+++ b/fs/nfs/objlayout/objlayout.h
@@ -184,4 +184,6 @@
 	struct xdr_stream *,
 	const struct nfs4_layoutreturn_args *);
 
+extern int objlayout_autologin(struct pnfs_osd_deviceaddr *deviceaddr);
+
 #endif /* _OBJLAYOUT_H */
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 5668f7c..d21fcea 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -13,6 +13,7 @@
 #include <linux/file.h>
 #include <linux/sched.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
 #include <linux/nfs3.h>
 #include <linux/nfs4.h>
 #include <linux/nfs_page.h>
@@ -106,36 +107,6 @@
 	nfs_release_request(req);
 }
 
-/**
- * nfs_set_page_tag_locked - Tag a request as locked
- * @req:
- */
-int nfs_set_page_tag_locked(struct nfs_page *req)
-{
-	if (!nfs_lock_request_dontget(req))
-		return 0;
-	if (test_bit(PG_MAPPED, &req->wb_flags))
-		radix_tree_tag_set(&NFS_I(req->wb_context->dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
-	return 1;
-}
-
-/**
- * nfs_clear_page_tag_locked - Clear request tag and wake up sleepers
- */
-void nfs_clear_page_tag_locked(struct nfs_page *req)
-{
-	if (test_bit(PG_MAPPED, &req->wb_flags)) {
-		struct inode *inode = req->wb_context->dentry->d_inode;
-		struct nfs_inode *nfsi = NFS_I(inode);
-
-		spin_lock(&inode->i_lock);
-		radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
-		nfs_unlock_request(req);
-		spin_unlock(&inode->i_lock);
-	} else
-		nfs_unlock_request(req);
-}
-
 /*
  * nfs_clear_request - Free up all resources allocated to the request
  * @req:
@@ -425,67 +396,6 @@
 	}
 }
 
-#define NFS_SCAN_MAXENTRIES 16
-/**
- * nfs_scan_list - Scan a list for matching requests
- * @nfsi: NFS inode
- * @dst: Destination list
- * @idx_start: lower bound of page->index to scan
- * @npages: idx_start + npages sets the upper bound to scan.
- * @tag: tag to scan for
- *
- * Moves elements from one of the inode request lists.
- * If the number of requests is set to 0, the entire address_space
- * starting at index idx_start, is scanned.
- * The requests are *not* checked to ensure that they form a contiguous set.
- * You must be holding the inode's i_lock when calling this function
- */
-int nfs_scan_list(struct nfs_inode *nfsi,
-		struct list_head *dst, pgoff_t idx_start,
-		unsigned int npages, int tag)
-{
-	struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
-	struct nfs_page *req;
-	pgoff_t idx_end;
-	int found, i;
-	int res;
-	struct list_head *list;
-
-	res = 0;
-	if (npages == 0)
-		idx_end = ~0;
-	else
-		idx_end = idx_start + npages - 1;
-
-	for (;;) {
-		found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree,
-				(void **)&pgvec[0], idx_start,
-				NFS_SCAN_MAXENTRIES, tag);
-		if (found <= 0)
-			break;
-		for (i = 0; i < found; i++) {
-			req = pgvec[i];
-			if (req->wb_index > idx_end)
-				goto out;
-			idx_start = req->wb_index + 1;
-			if (nfs_set_page_tag_locked(req)) {
-				kref_get(&req->wb_kref);
-				radix_tree_tag_clear(&nfsi->nfs_page_tree,
-						req->wb_index, tag);
-				list = pnfs_choose_commit_list(req, dst);
-				nfs_list_add_request(req, list);
-				res++;
-				if (res == INT_MAX)
-					goto out;
-			}
-		}
-		/* for latency reduction */
-		cond_resched_lock(&nfsi->vfs_inode.i_lock);
-	}
-out:
-	return res;
-}
-
 int __init nfs_init_nfspagecache(void)
 {
 	nfs_page_cachep = kmem_cache_create("nfs_page",
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 17149a4..b5d4515 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -101,8 +101,8 @@
 		goto out_no_driver;
 	if (!(server->nfs_client->cl_exchange_flags &
 		 (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))) {
-		printk(KERN_ERR "%s: id %u cl_exchange_flags 0x%x\n", __func__,
-		       id, server->nfs_client->cl_exchange_flags);
+		printk(KERN_ERR "NFS: %s: id %u cl_exchange_flags 0x%x\n",
+			__func__, id, server->nfs_client->cl_exchange_flags);
 		goto out_no_driver;
 	}
 	ld_type = find_pnfs_driver(id);
@@ -122,8 +122,8 @@
 	server->pnfs_curr_ld = ld_type;
 	if (ld_type->set_layoutdriver
 	    && ld_type->set_layoutdriver(server, mntfh)) {
-		printk(KERN_ERR "%s: Error initializing pNFS layout driver %u.\n",
-				__func__, id);
+		printk(KERN_ERR "NFS: %s: Error initializing pNFS layout "
+			"driver %u.\n", __func__, id);
 		module_put(ld_type->owner);
 		goto out_no_driver;
 	}
@@ -143,11 +143,11 @@
 	struct pnfs_layoutdriver_type *tmp;
 
 	if (ld_type->id == 0) {
-		printk(KERN_ERR "%s id 0 is reserved\n", __func__);
+		printk(KERN_ERR "NFS: %s id 0 is reserved\n", __func__);
 		return status;
 	}
 	if (!ld_type->alloc_lseg || !ld_type->free_lseg) {
-		printk(KERN_ERR "%s Layout driver must provide "
+		printk(KERN_ERR "NFS: %s Layout driver must provide "
 		       "alloc_lseg and free_lseg.\n", __func__);
 		return status;
 	}
@@ -160,7 +160,7 @@
 		dprintk("%s Registering id:%u name:%s\n", __func__, ld_type->id,
 			ld_type->name);
 	} else {
-		printk(KERN_ERR "%s Module with id %d already loaded!\n",
+		printk(KERN_ERR "NFS: %s Module with id %d already loaded!\n",
 			__func__, ld_type->id);
 	}
 	spin_unlock(&pnfs_spinlock);
@@ -496,12 +496,12 @@
 {
 	u32 oldseq, newseq;
 
-	oldseq = be32_to_cpu(lo->plh_stateid.stateid.seqid);
-	newseq = be32_to_cpu(new->stateid.seqid);
+	oldseq = be32_to_cpu(lo->plh_stateid.seqid);
+	newseq = be32_to_cpu(new->seqid);
 	if ((int)(newseq - oldseq) > 0) {
-		memcpy(&lo->plh_stateid, &new->stateid, sizeof(new->stateid));
+		nfs4_stateid_copy(&lo->plh_stateid, new);
 		if (update_barrier) {
-			u32 new_barrier = be32_to_cpu(new->stateid.seqid);
+			u32 new_barrier = be32_to_cpu(new->seqid);
 
 			if ((int)(new_barrier - lo->plh_barrier))
 				lo->plh_barrier = new_barrier;
@@ -525,7 +525,7 @@
 			int lget)
 {
 	if ((stateid) &&
-	    (int)(lo->plh_barrier - be32_to_cpu(stateid->stateid.seqid)) >= 0)
+	    (int)(lo->plh_barrier - be32_to_cpu(stateid->seqid)) >= 0)
 		return true;
 	return lo->plh_block_lgets ||
 		test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags) ||
@@ -549,11 +549,10 @@
 
 		do {
 			seq = read_seqbegin(&open_state->seqlock);
-			memcpy(dst->data, open_state->stateid.data,
-			       sizeof(open_state->stateid.data));
+			nfs4_stateid_copy(dst, &open_state->stateid);
 		} while (read_seqretry(&open_state->seqlock, seq));
 	} else
-		memcpy(dst->data, lo->plh_stateid.data, sizeof(lo->plh_stateid.data));
+		nfs4_stateid_copy(dst, &lo->plh_stateid);
 	spin_unlock(&lo->plh_inode->i_lock);
 	dprintk("<-- %s\n", __func__);
 	return status;
@@ -590,7 +589,7 @@
 	max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
 	max_pages = max_resp_sz >> PAGE_SHIFT;
 
-	pages = kzalloc(max_pages * sizeof(struct page *), gfp_flags);
+	pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags);
 	if (!pages)
 		goto out_err_free;
 
@@ -760,7 +759,7 @@
 		}
 	if (!found) {
 		struct pnfs_layout_hdr *lo = nfsi->layout;
-		u32 current_seqid = be32_to_cpu(lo->plh_stateid.stateid.seqid);
+		u32 current_seqid = be32_to_cpu(lo->plh_stateid.seqid);
 
 		/* Since close does not return a layout stateid for use as
 		 * a barrier, we choose the worst-case barrier.
@@ -966,8 +965,7 @@
 	}
 
 	/* Do we even need to bother with this? */
-	if (test_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state) ||
-	    test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
+	if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
 		dprintk("%s matches recall, use MDS\n", __func__);
 		goto out_unlock;
 	}
@@ -1032,7 +1030,6 @@
 	struct nfs4_layoutget_res *res = &lgp->res;
 	struct pnfs_layout_segment *lseg;
 	struct inode *ino = lo->plh_inode;
-	struct nfs_client *clp = NFS_SERVER(ino)->nfs_client;
 	int status = 0;
 
 	/* Inject layout blob into I/O device driver */
@@ -1048,8 +1045,7 @@
 	}
 
 	spin_lock(&ino->i_lock);
-	if (test_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state) ||
-	    test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
+	if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
 		dprintk("%s forget reply due to recall\n", __func__);
 		goto out_forget_reply;
 	}
@@ -1214,6 +1210,7 @@
 		}
 		data->task.tk_status = pnfs_write_done_resend_to_mds(data->inode, &data->pages);
 	}
+	put_lseg(data->lseg);
 	data->mds_ops->rpc_release(data);
 }
 EXPORT_SYMBOL_GPL(pnfs_ld_write_done);
@@ -1227,6 +1224,7 @@
 		nfs_list_add_request(data->req, &desc->pg_list);
 	nfs_pageio_reset_write_mds(desc);
 	desc->pg_recoalesce = 1;
+	put_lseg(data->lseg);
 	nfs_writedata_release(data);
 }
 
@@ -1327,6 +1325,7 @@
 		data->mds_ops->rpc_call_done(&data->task, data);
 	} else
 		pnfs_ld_handle_read_error(data);
+	put_lseg(data->lseg);
 	data->mds_ops->rpc_release(data);
 }
 EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
@@ -1530,8 +1529,7 @@
 	end_pos = nfsi->layout->plh_lwb;
 	nfsi->layout->plh_lwb = 0;
 
-	memcpy(&data->args.stateid.data, nfsi->layout->plh_stateid.data,
-		sizeof(nfsi->layout->plh_stateid.data));
+	nfs4_stateid_copy(&data->args.stateid, &nfsi->layout->plh_stateid);
 	spin_unlock(&inode->i_lock);
 
 	data->args.inode = inode;
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 53d593a..442ebf6 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -94,11 +94,10 @@
 	const struct nfs_pageio_ops *pg_read_ops;
 	const struct nfs_pageio_ops *pg_write_ops;
 
-	/* Returns true if layoutdriver wants to divert this request to
-	 * driver's commit routine.
-	 */
-	bool (*mark_pnfs_commit)(struct pnfs_layout_segment *lseg);
-	struct list_head * (*choose_commit_list) (struct nfs_page *req);
+	void (*mark_request_commit) (struct nfs_page *req,
+					struct pnfs_layout_segment *lseg);
+	void (*clear_request_commit) (struct nfs_page *req);
+	int (*scan_commit_lists) (struct inode *inode, int max, spinlock_t *lock);
 	int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how);
 
 	/*
@@ -229,7 +228,6 @@
 	atomic_t			ref;
 };
 
-void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id);
 struct nfs4_deviceid_node *nfs4_find_get_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *);
 void nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *);
 void nfs4_init_deviceid_node(struct nfs4_deviceid_node *,
@@ -262,20 +260,6 @@
 	return nfss->pnfs_curr_ld != NULL;
 }
 
-static inline void
-pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
-{
-	if (lseg) {
-		struct pnfs_layoutdriver_type *ld;
-
-		ld = NFS_SERVER(req->wb_page->mapping->host)->pnfs_curr_ld;
-		if (ld->mark_pnfs_commit && ld->mark_pnfs_commit(lseg)) {
-			set_bit(PG_PNFS_COMMIT, &req->wb_flags);
-			req->wb_commit_lseg = get_lseg(lseg);
-		}
-	}
-}
-
 static inline int
 pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
 {
@@ -284,27 +268,42 @@
 	return NFS_SERVER(inode)->pnfs_curr_ld->commit_pagelist(inode, mds_pages, how);
 }
 
-static inline struct list_head *
-pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds)
+static inline bool
+pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 {
-	struct list_head *rv;
+	struct inode *inode = req->wb_context->dentry->d_inode;
+	struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
 
-	if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags)) {
-		struct inode *inode = req->wb_commit_lseg->pls_layout->plh_inode;
-
-		set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags);
-		rv = NFS_SERVER(inode)->pnfs_curr_ld->choose_commit_list(req);
-		/* matched by ref taken when PG_PNFS_COMMIT is set */
-		put_lseg(req->wb_commit_lseg);
-	} else
-		rv = mds;
-	return rv;
+	if (lseg == NULL || ld->mark_request_commit == NULL)
+		return false;
+	ld->mark_request_commit(req, lseg);
+	return true;
 }
 
-static inline void pnfs_clear_request_commit(struct nfs_page *req)
+static inline bool
+pnfs_clear_request_commit(struct nfs_page *req)
 {
-	if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags))
-		put_lseg(req->wb_commit_lseg);
+	struct inode *inode = req->wb_context->dentry->d_inode;
+	struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
+
+	if (ld == NULL || ld->clear_request_commit == NULL)
+		return false;
+	ld->clear_request_commit(req);
+	return true;
+}
+
+static inline int
+pnfs_scan_commit_lists(struct inode *inode, int max, spinlock_t *lock)
+{
+	struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
+	int ret;
+
+	if (ld == NULL || ld->scan_commit_lists == NULL)
+		return 0;
+	ret = ld->scan_commit_lists(inode, max, lock);
+	if (ret != 0)
+		set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags);
+	return ret;
 }
 
 /* Should the pNFS client commit and return the layout upon a setattr */
@@ -328,6 +327,13 @@
 	return 0;
 }
 
+#ifdef NFS_DEBUG
+void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id);
+#else
+static inline void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id)
+{
+}
+#endif /* NFS_DEBUG */
 #else  /* CONFIG_NFS_V4_1 */
 
 static inline void pnfs_destroy_all_layouts(struct nfs_client *clp)
@@ -400,25 +406,28 @@
 	return false;
 }
 
-static inline void
-pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
-{
-}
-
 static inline int
 pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
 {
 	return PNFS_NOT_ATTEMPTED;
 }
 
-static inline struct list_head *
-pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds)
+static inline bool
+pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 {
-	return mds;
+	return false;
 }
 
-static inline void pnfs_clear_request_commit(struct nfs_page *req)
+static inline bool
+pnfs_clear_request_commit(struct nfs_page *req)
 {
+	return false;
+}
+
+static inline int
+pnfs_scan_commit_lists(struct inode *inode, int max, spinlock_t *lock)
+{
+	return 0;
 }
 
 static inline int pnfs_layoutcommit_inode(struct inode *inode, bool sync)
@@ -426,9 +435,6 @@
 	return 0;
 }
 
-static inline void nfs4_deviceid_purge_client(struct nfs_client *ncl)
-{
-}
 #endif /* CONFIG_NFS_V4_1 */
 
 #endif /* FS_NFS_PNFS_H */
diff --git a/fs/nfs/pnfs_dev.c b/fs/nfs/pnfs_dev.c
index 4f359d2..73f701f 100644
--- a/fs/nfs/pnfs_dev.c
+++ b/fs/nfs/pnfs_dev.c
@@ -43,6 +43,7 @@
 static struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE];
 static DEFINE_SPINLOCK(nfs4_deviceid_lock);
 
+#ifdef NFS_DEBUG
 void
 nfs4_print_deviceid(const struct nfs4_deviceid *id)
 {
@@ -52,6 +53,7 @@
 		p[0], p[1], p[2], p[3]);
 }
 EXPORT_SYMBOL_GPL(nfs4_print_deviceid);
+#endif
 
 static inline u32
 nfs4_deviceid_hash(const struct nfs4_deviceid *id)
@@ -92,7 +94,7 @@
  * @clp nfs_client associated with deviceid
  * @id deviceid to look up
  */
-struct nfs4_deviceid_node *
+static struct nfs4_deviceid_node *
 _find_get_deviceid(const struct pnfs_layoutdriver_type *ld,
 		   const struct nfs_client *clp, const struct nfs4_deviceid *id,
 		   long hash)
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 0c672588..b63b6f4 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -358,6 +358,11 @@
 	msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE];
 }
 
+static void nfs_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
+{
+	rpc_call_start(task);
+}
+
 static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 {
 	if (nfs_async_handle_expired_key(task))
@@ -372,6 +377,11 @@
 	msg->rpc_proc = &nfs_procedures[NFSPROC_RENAME];
 }
 
+static void nfs_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
+{
+	rpc_call_start(task);
+}
+
 static int
 nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
 		     struct inode *new_dir)
@@ -651,6 +661,11 @@
 	msg->rpc_proc = &nfs_procedures[NFSPROC_READ];
 }
 
+static void nfs_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
+{
+	rpc_call_start(task);
+}
+
 static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
 {
 	if (nfs_async_handle_expired_key(task))
@@ -668,6 +683,11 @@
 	msg->rpc_proc = &nfs_procedures[NFSPROC_WRITE];
 }
 
+static void nfs_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
+{
+	rpc_call_start(task);
+}
+
 static void
 nfs_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg)
 {
@@ -721,9 +741,11 @@
 	.create		= nfs_proc_create,
 	.remove		= nfs_proc_remove,
 	.unlink_setup	= nfs_proc_unlink_setup,
+	.unlink_rpc_prepare = nfs_proc_unlink_rpc_prepare,
 	.unlink_done	= nfs_proc_unlink_done,
 	.rename		= nfs_proc_rename,
 	.rename_setup	= nfs_proc_rename_setup,
+	.rename_rpc_prepare = nfs_proc_rename_rpc_prepare,
 	.rename_done	= nfs_proc_rename_done,
 	.link		= nfs_proc_link,
 	.symlink	= nfs_proc_symlink,
@@ -736,8 +758,10 @@
 	.pathconf	= nfs_proc_pathconf,
 	.decode_dirent	= nfs2_decode_dirent,
 	.read_setup	= nfs_proc_read_setup,
+	.read_rpc_prepare = nfs_proc_read_rpc_prepare,
 	.read_done	= nfs_read_done,
 	.write_setup	= nfs_proc_write_setup,
+	.write_rpc_prepare = nfs_proc_write_rpc_prepare,
 	.write_done	= nfs_write_done,
 	.commit_setup	= nfs_proc_commit_setup,
 	.lock		= nfs_proc_lock,
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index cfa175c..9a0e8ef4 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -20,7 +20,6 @@
 #include <linux/nfs_page.h>
 #include <linux/module.h>
 
-#include <asm/system.h>
 #include "pnfs.h"
 
 #include "nfs4_fs.h"
@@ -66,7 +65,6 @@
 
 void nfs_readdata_release(struct nfs_read_data *rdata)
 {
-	put_lseg(rdata->lseg);
 	put_nfs_open_context(rdata->args.context);
 	nfs_readdata_free(rdata);
 }
@@ -465,23 +463,14 @@
 	nfs_readdata_release(calldata);
 }
 
-#if defined(CONFIG_NFS_V4_1)
 void nfs_read_prepare(struct rpc_task *task, void *calldata)
 {
 	struct nfs_read_data *data = calldata;
-
-	if (nfs4_setup_sequence(NFS_SERVER(data->inode),
-				&data->args.seq_args, &data->res.seq_res,
-				0, task))
-		return;
-	rpc_call_start(task);
+	NFS_PROTO(data->inode)->read_rpc_prepare(task, data);
 }
-#endif /* CONFIG_NFS_V4_1 */
 
 static const struct rpc_call_ops nfs_read_partial_ops = {
-#if defined(CONFIG_NFS_V4_1)
 	.rpc_call_prepare = nfs_read_prepare,
-#endif /* CONFIG_NFS_V4_1 */
 	.rpc_call_done = nfs_readpage_result_partial,
 	.rpc_release = nfs_readpage_release_partial,
 };
@@ -545,9 +534,7 @@
 }
 
 static const struct rpc_call_ops nfs_read_full_ops = {
-#if defined(CONFIG_NFS_V4_1)
 	.rpc_call_prepare = nfs_read_prepare,
-#endif /* CONFIG_NFS_V4_1 */
 	.rpc_call_done = nfs_readpage_result_full,
 	.rpc_release = nfs_readpage_release_full,
 };
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 3dfa4f1..37412f7 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -52,8 +52,9 @@
 #include <linux/nfs_xdr.h>
 #include <linux/magic.h>
 #include <linux/parser.h>
+#include <linux/nsproxy.h>
+#include <linux/rcupdate.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 #include "nfs4_fs.h"
@@ -79,7 +80,6 @@
 	Opt_cto, Opt_nocto,
 	Opt_ac, Opt_noac,
 	Opt_lock, Opt_nolock,
-	Opt_v2, Opt_v3, Opt_v4,
 	Opt_udp, Opt_tcp, Opt_rdma,
 	Opt_acl, Opt_noacl,
 	Opt_rdirplus, Opt_nordirplus,
@@ -97,10 +97,10 @@
 	Opt_namelen,
 	Opt_mountport,
 	Opt_mountvers,
-	Opt_nfsvers,
 	Opt_minorversion,
 
 	/* Mount options that take string arguments */
+	Opt_nfsvers,
 	Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
 	Opt_addr, Opt_mountaddr, Opt_clientaddr,
 	Opt_lookupcache,
@@ -132,9 +132,6 @@
 	{ Opt_noac, "noac" },
 	{ Opt_lock, "lock" },
 	{ Opt_nolock, "nolock" },
-	{ Opt_v2, "v2" },
-	{ Opt_v3, "v3" },
-	{ Opt_v4, "v4" },
 	{ Opt_udp, "udp" },
 	{ Opt_tcp, "tcp" },
 	{ Opt_rdma, "rdma" },
@@ -163,9 +160,10 @@
 	{ Opt_namelen, "namlen=%s" },
 	{ Opt_mountport, "mountport=%s" },
 	{ Opt_mountvers, "mountvers=%s" },
+	{ Opt_minorversion, "minorversion=%s" },
+
 	{ Opt_nfsvers, "nfsvers=%s" },
 	{ Opt_nfsvers, "vers=%s" },
-	{ Opt_minorversion, "minorversion=%s" },
 
 	{ Opt_sec, "sec=%s" },
 	{ Opt_proto, "proto=%s" },
@@ -179,6 +177,9 @@
 	{ Opt_fscache_uniq, "fsc=%s" },
 	{ Opt_local_lock, "local_lock=%s" },
 
+	/* The following needs to be listed after all other options */
+	{ Opt_nfsvers, "v%s" },
+
 	{ Opt_err, NULL }
 };
 
@@ -259,6 +260,22 @@
 	{ Opt_local_lock_err, NULL }
 };
 
+enum {
+	Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0,
+	Opt_vers_4_1,
+
+	Opt_vers_err
+};
+
+static match_table_t nfs_vers_tokens = {
+	{ Opt_vers_2, "2" },
+	{ Opt_vers_3, "3" },
+	{ Opt_vers_4, "4" },
+	{ Opt_vers_4_0, "4.0" },
+	{ Opt_vers_4_1, "4.1" },
+
+	{ Opt_vers_err, NULL }
+};
 
 static void nfs_umount_begin(struct super_block *);
 static int  nfs_statfs(struct dentry *, struct kstatfs *);
@@ -620,7 +637,6 @@
 	struct nfs_client *clp = nfss->nfs_client;
 
 	seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
-	seq_printf(m, ",minorversion=%u", clp->cl_minorversion);
 }
 #else
 static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
@@ -629,6 +645,15 @@
 }
 #endif
 
+static void nfs_show_nfs_version(struct seq_file *m,
+		unsigned int version,
+		unsigned int minorversion)
+{
+	seq_printf(m, ",vers=%u", version);
+	if (version == 4)
+		seq_printf(m, ".%u", minorversion);
+}
+
 /*
  * Describe the mount options in force on this server representation
  */
@@ -656,7 +681,7 @@
 	u32 version = clp->rpc_ops->version;
 	int local_flock, local_fcntl;
 
-	seq_printf(m, ",vers=%u", version);
+	nfs_show_nfs_version(m, version, clp->cl_minorversion);
 	seq_printf(m, ",rsize=%u", nfss->rsize);
 	seq_printf(m, ",wsize=%u", nfss->wsize);
 	if (nfss->bsize != 0)
@@ -676,8 +701,10 @@
 		else
 			seq_puts(m, nfs_infop->nostr);
 	}
+	rcu_read_lock();
 	seq_printf(m, ",proto=%s",
 		   rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID));
+	rcu_read_unlock();
 	if (version == 4) {
 		if (nfss->port != NFS_PORT)
 			seq_printf(m, ",port=%u", nfss->port);
@@ -726,9 +753,11 @@
 
 	nfs_show_mount_options(m, nfss, 0);
 
+	rcu_read_lock();
 	seq_printf(m, ",addr=%s",
 			rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient,
 							RPC_DISPLAY_ADDR));
+	rcu_read_unlock();
 
 	return 0;
 }
@@ -745,7 +774,6 @@
 #endif
 #endif
 
-#ifdef CONFIG_NFS_V4
 #ifdef CONFIG_NFS_V4_1
 static void show_pnfs(struct seq_file *m, struct nfs_server *server)
 {
@@ -755,9 +783,26 @@
 	else
 		seq_printf(m, "not configured");
 }
+
+static void show_implementation_id(struct seq_file *m, struct nfs_server *nfss)
+{
+	if (nfss->nfs_client && nfss->nfs_client->impl_id) {
+		struct nfs41_impl_id *impl_id = nfss->nfs_client->impl_id;
+		seq_printf(m, "\n\timpl_id:\tname='%s',domain='%s',"
+			   "date='%llu,%u'",
+			   impl_id->name, impl_id->domain,
+			   impl_id->date.seconds, impl_id->date.nseconds);
+	}
+}
 #else
-static void show_pnfs(struct seq_file *m, struct nfs_server *server) {}
+#ifdef CONFIG_NFS_V4
+static void show_pnfs(struct seq_file *m, struct nfs_server *server)
+{
+}
 #endif
+static void show_implementation_id(struct seq_file *m, struct nfs_server *nfss)
+{
+}
 #endif
 
 static int nfs_show_devname(struct seq_file *m, struct dentry *root)
@@ -806,6 +851,8 @@
 
 	seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ);
 
+	show_implementation_id(m, nfss);
+
 	seq_printf(m, "\n\tcaps:\t");
 	seq_printf(m, "caps=0x%x", nfss->caps);
 	seq_printf(m, ",wtmult=%u", nfss->wtmult);
@@ -908,6 +955,7 @@
 		data->auth_flavor_len	= 1;
 		data->version		= version;
 		data->minorversion	= 0;
+		data->net		= current->nsproxy->net_ns;
 		security_init_mnt_opts(&data->lsm_opts);
 	}
 	return data;
@@ -1052,6 +1100,40 @@
 	return 1;
 }
 
+static int nfs_parse_version_string(char *string,
+		struct nfs_parsed_mount_data *mnt,
+		substring_t *args)
+{
+	mnt->flags &= ~NFS_MOUNT_VER3;
+	switch (match_token(string, nfs_vers_tokens, args)) {
+	case Opt_vers_2:
+		mnt->version = 2;
+		break;
+	case Opt_vers_3:
+		mnt->flags |= NFS_MOUNT_VER3;
+		mnt->version = 3;
+		break;
+	case Opt_vers_4:
+		/* Backward compatibility option. In future,
+		 * the mount program should always supply
+		 * a NFSv4 minor version number.
+		 */
+		mnt->version = 4;
+		break;
+	case Opt_vers_4_0:
+		mnt->version = 4;
+		mnt->minorversion = 0;
+		break;
+	case Opt_vers_4_1:
+		mnt->version = 4;
+		mnt->minorversion = 1;
+		break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
 static int nfs_get_option_str(substring_t args[], char **option)
 {
 	kfree(*option);
@@ -1157,18 +1239,6 @@
 			mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
 				       NFS_MOUNT_LOCAL_FCNTL);
 			break;
-		case Opt_v2:
-			mnt->flags &= ~NFS_MOUNT_VER3;
-			mnt->version = 2;
-			break;
-		case Opt_v3:
-			mnt->flags |= NFS_MOUNT_VER3;
-			mnt->version = 3;
-			break;
-		case Opt_v4:
-			mnt->flags &= ~NFS_MOUNT_VER3;
-			mnt->version = 4;
-			break;
 		case Opt_udp:
 			mnt->flags &= ~NFS_MOUNT_TCP;
 			mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
@@ -1295,26 +1365,6 @@
 				goto out_invalid_value;
 			mnt->mount_server.version = option;
 			break;
-		case Opt_nfsvers:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			switch (option) {
-			case NFS2_VERSION:
-				mnt->flags &= ~NFS_MOUNT_VER3;
-				mnt->version = 2;
-				break;
-			case NFS3_VERSION:
-				mnt->flags |= NFS_MOUNT_VER3;
-				mnt->version = 3;
-				break;
-			case NFS4_VERSION:
-				mnt->flags &= ~NFS_MOUNT_VER3;
-				mnt->version = 4;
-				break;
-			default:
-				goto out_invalid_value;
-			}
-			break;
 		case Opt_minorversion:
 			if (nfs_get_option_ul(args, &option))
 				goto out_invalid_value;
@@ -1326,6 +1376,15 @@
 		/*
 		 * options that take text values
 		 */
+		case Opt_nfsvers:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+			rc = nfs_parse_version_string(string, mnt, args);
+			kfree(string);
+			if (!rc)
+				goto out_invalid_value;
+			break;
 		case Opt_sec:
 			string = match_strdup(args);
 			if (string == NULL)
@@ -1405,7 +1464,7 @@
 			if (string == NULL)
 				goto out_nomem;
 			mnt->nfs_server.addrlen =
-				rpc_pton(string, strlen(string),
+				rpc_pton(mnt->net, string, strlen(string),
 					(struct sockaddr *)
 					&mnt->nfs_server.address,
 					sizeof(mnt->nfs_server.address));
@@ -1427,7 +1486,7 @@
 			if (string == NULL)
 				goto out_nomem;
 			mnt->mount_server.addrlen =
-				rpc_pton(string, strlen(string),
+				rpc_pton(mnt->net, string, strlen(string),
 					(struct sockaddr *)
 					&mnt->mount_server.address,
 					sizeof(mnt->mount_server.address));
@@ -1516,6 +1575,9 @@
 	if (!sloppy && invalid_option)
 		return 0;
 
+	if (mnt->minorversion && mnt->version != 4)
+		goto out_minorversion_mismatch;
+
 	/*
 	 * verify that any proto=/mountproto= options match the address
 	 * familiies in the addr=/mountaddr= options.
@@ -1549,6 +1611,10 @@
 out_invalid_value:
 	printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p);
 	return 0;
+out_minorversion_mismatch:
+	printk(KERN_INFO "NFS: mount option vers=%u does not support "
+			 "minorversion=%u\n", mnt->version, mnt->minorversion);
+	return 0;
 out_nomem:
 	printk(KERN_INFO "NFS: not enough memory to parse option\n");
 	return 0;
@@ -1622,6 +1688,7 @@
 		.noresvport	= args->flags & NFS_MOUNT_NORESVPORT,
 		.auth_flav_len	= &server_authlist_len,
 		.auth_flavs	= server_authlist,
+		.net		= args->net,
 	};
 	int status;
 
@@ -2047,7 +2114,7 @@
 
 	/* We probably want something more informative here */
 	snprintf(sb->s_id, sizeof(sb->s_id),
-		 "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
+		 "%u:%u", MAJOR(sb->s_dev), MINOR(sb->s_dev));
 
 	if (sb->s_blocksize == 0)
 		sb->s_blocksize = nfs_block_bits(server->wsize,
@@ -2499,12 +2566,6 @@
 		return -EINVAL;
 	}
 
-	if (args->client_address == NULL) {
-		dfprintk(MOUNT,
-			 "NFS4: mount program didn't pass callback address\n");
-		return -EINVAL;
-	}
-
 	return nfs_parse_devname(dev_name,
 				   &args->nfs_server.hostname,
 				   NFS4_MAXNAMLEN,
@@ -2663,8 +2724,7 @@
 	if (!s->s_root) {
 		/* initial superblock/root creation */
 		nfs4_fill_super(s);
-		nfs_fscache_get_super_cookie(
-			s, data ? data->fscache_uniq : NULL, NULL);
+		nfs_fscache_get_super_cookie(s, data->fscache_uniq, NULL);
 	}
 
 	mntroot = nfs4_get_root(s, mntfh, dev_name);
diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c
index 978aaeb..ad4d2e7 100644
--- a/fs/nfs/sysctl.c
+++ b/fs/nfs/sysctl.c
@@ -32,7 +32,6 @@
 		.extra1 = (int *)&nfs_set_port_min,
 		.extra2 = (int *)&nfs_set_port_max,
 	},
-#ifndef CONFIG_NFS_USE_NEW_IDMAPPER
 	{
 		.procname = "idmap_cache_timeout",
 		.data = &nfs_idmap_cache_timeout,
@@ -40,7 +39,6 @@
 		.mode = 0644,
 		.proc_handler = proc_dointvec_jiffies,
 	},
-#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
 #endif
 	{
 		.procname	= "nfs_mountpoint_timeout",
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c
index 4f9319a..3210a03 100644
--- a/fs/nfs/unlink.c
+++ b/fs/nfs/unlink.c
@@ -20,15 +20,6 @@
 #include "iostat.h"
 #include "delegation.h"
 
-struct nfs_unlinkdata {
-	struct hlist_node list;
-	struct nfs_removeargs args;
-	struct nfs_removeres res;
-	struct inode *dir;
-	struct rpc_cred	*cred;
-	struct nfs_fattr dir_attr;
-};
-
 /**
  * nfs_free_unlinkdata - release data from a sillydelete operation.
  * @data: pointer to unlink structure.
@@ -107,25 +98,16 @@
 	nfs_sb_deactive(sb);
 }
 
-#if defined(CONFIG_NFS_V4_1)
-void nfs_unlink_prepare(struct rpc_task *task, void *calldata)
+static void nfs_unlink_prepare(struct rpc_task *task, void *calldata)
 {
 	struct nfs_unlinkdata *data = calldata;
-	struct nfs_server *server = NFS_SERVER(data->dir);
-
-	if (nfs4_setup_sequence(server, &data->args.seq_args,
-				&data->res.seq_res, 1, task))
-		return;
-	rpc_call_start(task);
+	NFS_PROTO(data->dir)->unlink_rpc_prepare(task, data);
 }
-#endif /* CONFIG_NFS_V4_1 */
 
 static const struct rpc_call_ops nfs_unlink_ops = {
 	.rpc_call_done = nfs_async_unlink_done,
 	.rpc_release = nfs_async_unlink_release,
-#if defined(CONFIG_NFS_V4_1)
 	.rpc_call_prepare = nfs_unlink_prepare,
-#endif /* CONFIG_NFS_V4_1 */
 };
 
 static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data)
@@ -341,18 +323,6 @@
 	spin_unlock(&dentry->d_lock);
 }
 
-struct nfs_renamedata {
-	struct nfs_renameargs	args;
-	struct nfs_renameres	res;
-	struct rpc_cred		*cred;
-	struct inode		*old_dir;
-	struct dentry		*old_dentry;
-	struct nfs_fattr	old_fattr;
-	struct inode		*new_dir;
-	struct dentry		*new_dentry;
-	struct nfs_fattr	new_fattr;
-};
-
 /**
  * nfs_async_rename_done - Sillyrename post-processing
  * @task: rpc_task of the sillyrename
@@ -403,25 +373,16 @@
 	kfree(data);
 }
 
-#if defined(CONFIG_NFS_V4_1)
 static void nfs_rename_prepare(struct rpc_task *task, void *calldata)
 {
 	struct nfs_renamedata *data = calldata;
-	struct nfs_server *server = NFS_SERVER(data->old_dir);
-
-	if (nfs4_setup_sequence(server, &data->args.seq_args,
-				&data->res.seq_res, 1, task))
-		return;
-	rpc_call_start(task);
+	NFS_PROTO(data->old_dir)->rename_rpc_prepare(task, data);
 }
-#endif /* CONFIG_NFS_V4_1 */
 
 static const struct rpc_call_ops nfs_rename_ops = {
 	.rpc_call_done = nfs_async_rename_done,
 	.rpc_release = nfs_async_rename_release,
-#if defined(CONFIG_NFS_V4_1)
 	.rpc_call_prepare = nfs_rename_prepare,
-#endif /* CONFIG_NFS_V4_1 */
 };
 
 /**
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 834f0fe..2c68818 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -100,7 +100,6 @@
 
 void nfs_writedata_release(struct nfs_write_data *wdata)
 {
-	put_lseg(wdata->lseg);
 	put_nfs_open_context(wdata->args.context);
 	nfs_writedata_free(wdata);
 }
@@ -236,10 +235,10 @@
 		req = nfs_page_find_request_locked(page);
 		if (req == NULL)
 			break;
-		if (nfs_set_page_tag_locked(req))
+		if (nfs_lock_request_dontget(req))
 			break;
 		/* Note: If we hold the page lock, as is the case in nfs_writepage,
-		 *	 then the call to nfs_set_page_tag_locked() will always
+		 *	 then the call to nfs_lock_request_dontget() will always
 		 *	 succeed provided that someone hasn't already marked the
 		 *	 request as dirty (in which case we don't care).
 		 */
@@ -375,21 +374,14 @@
 /*
  * Insert a write request into an inode
  */
-static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
+static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
-	int error;
-
-	error = radix_tree_preload(GFP_NOFS);
-	if (error != 0)
-		goto out;
 
 	/* Lock the request! */
 	nfs_lock_request_dontget(req);
 
 	spin_lock(&inode->i_lock);
-	error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req);
-	BUG_ON(error);
 	if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE))
 		inode->i_version++;
 	set_bit(PG_MAPPED, &req->wb_flags);
@@ -397,12 +389,7 @@
 	set_page_private(req->wb_page, (unsigned long)req);
 	nfsi->npages++;
 	kref_get(&req->wb_kref);
-	radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index,
-				NFS_PAGE_TAG_LOCKED);
 	spin_unlock(&inode->i_lock);
-	radix_tree_preload_end();
-out:
-	return error;
 }
 
 /*
@@ -419,7 +406,6 @@
 	set_page_private(req->wb_page, 0);
 	ClearPagePrivate(req->wb_page);
 	clear_bit(PG_MAPPED, &req->wb_flags);
-	radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
 	nfsi->npages--;
 	spin_unlock(&inode->i_lock);
 	nfs_release_request(req);
@@ -432,6 +418,57 @@
 }
 
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
+/**
+ * nfs_request_add_commit_list - add request to a commit list
+ * @req: pointer to a struct nfs_page
+ * @head: commit list head
+ *
+ * This sets the PG_CLEAN bit, updates the inode global count of
+ * number of outstanding requests requiring a commit as well as
+ * the MM page stats.
+ *
+ * The caller must _not_ hold the inode->i_lock, but must be
+ * holding the nfs_page lock.
+ */
+void
+nfs_request_add_commit_list(struct nfs_page *req, struct list_head *head)
+{
+	struct inode *inode = req->wb_context->dentry->d_inode;
+
+	set_bit(PG_CLEAN, &(req)->wb_flags);
+	spin_lock(&inode->i_lock);
+	nfs_list_add_request(req, head);
+	NFS_I(inode)->ncommit++;
+	spin_unlock(&inode->i_lock);
+	inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
+	inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE);
+	__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
+}
+EXPORT_SYMBOL_GPL(nfs_request_add_commit_list);
+
+/**
+ * nfs_request_remove_commit_list - Remove request from a commit list
+ * @req: pointer to a nfs_page
+ *
+ * This clears the PG_CLEAN bit, and updates the inode global count of
+ * number of outstanding requests requiring a commit
+ * It does not update the MM page stats.
+ *
+ * The caller _must_ hold the inode->i_lock and the nfs_page lock.
+ */
+void
+nfs_request_remove_commit_list(struct nfs_page *req)
+{
+	struct inode *inode = req->wb_context->dentry->d_inode;
+
+	if (!test_and_clear_bit(PG_CLEAN, &(req)->wb_flags))
+		return;
+	nfs_list_remove_request(req);
+	NFS_I(inode)->ncommit--;
+}
+EXPORT_SYMBOL_GPL(nfs_request_remove_commit_list);
+
+
 /*
  * Add a request to the inode's commit list.
  */
@@ -439,32 +476,32 @@
 nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 {
 	struct inode *inode = req->wb_context->dentry->d_inode;
-	struct nfs_inode *nfsi = NFS_I(inode);
 
-	spin_lock(&inode->i_lock);
-	set_bit(PG_CLEAN, &(req)->wb_flags);
-	radix_tree_tag_set(&nfsi->nfs_page_tree,
-			req->wb_index,
-			NFS_PAGE_TAG_COMMIT);
-	nfsi->ncommit++;
-	spin_unlock(&inode->i_lock);
-	pnfs_mark_request_commit(req, lseg);
-	inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
-	inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE);
-	__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
+	if (pnfs_mark_request_commit(req, lseg))
+		return;
+	nfs_request_add_commit_list(req, &NFS_I(inode)->commit_list);
 }
 
-static int
+static void
+nfs_clear_page_commit(struct page *page)
+{
+	dec_zone_page_state(page, NR_UNSTABLE_NFS);
+	dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE);
+}
+
+static void
 nfs_clear_request_commit(struct nfs_page *req)
 {
-	struct page *page = req->wb_page;
+	if (test_bit(PG_CLEAN, &req->wb_flags)) {
+		struct inode *inode = req->wb_context->dentry->d_inode;
 
-	if (test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) {
-		dec_zone_page_state(page, NR_UNSTABLE_NFS);
-		dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE);
-		return 1;
+		if (!pnfs_clear_request_commit(req)) {
+			spin_lock(&inode->i_lock);
+			nfs_request_remove_commit_list(req);
+			spin_unlock(&inode->i_lock);
+		}
+		nfs_clear_page_commit(req->wb_page);
 	}
-	return 0;
 }
 
 static inline
@@ -491,15 +528,14 @@
 	return 0;
 }
 #else
-static inline void
+static void
 nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 {
 }
 
-static inline int
+static void
 nfs_clear_request_commit(struct nfs_page *req)
 {
-	return 0;
 }
 
 static inline
@@ -520,46 +556,65 @@
 static int
 nfs_need_commit(struct nfs_inode *nfsi)
 {
-	return radix_tree_tagged(&nfsi->nfs_page_tree, NFS_PAGE_TAG_COMMIT);
+	return nfsi->ncommit > 0;
+}
+
+/* i_lock held by caller */
+static int
+nfs_scan_commit_list(struct list_head *src, struct list_head *dst, int max,
+		spinlock_t *lock)
+{
+	struct nfs_page *req, *tmp;
+	int ret = 0;
+
+	list_for_each_entry_safe(req, tmp, src, wb_list) {
+		if (!nfs_lock_request(req))
+			continue;
+		if (cond_resched_lock(lock))
+			list_safe_reset_next(req, tmp, wb_list);
+		nfs_request_remove_commit_list(req);
+		nfs_list_add_request(req, dst);
+		ret++;
+		if (ret == max)
+			break;
+	}
+	return ret;
 }
 
 /*
  * nfs_scan_commit - Scan an inode for commit requests
  * @inode: NFS inode to scan
  * @dst: destination list
- * @idx_start: lower bound of page->index to scan.
- * @npages: idx_start + npages sets the upper bound to scan.
  *
  * Moves requests from the inode's 'commit' request list.
  * The requests are *not* checked to ensure that they form a contiguous set.
  */
 static int
-nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
+nfs_scan_commit(struct inode *inode, struct list_head *dst)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
-	int ret;
-
-	if (!nfs_need_commit(nfsi))
-		return 0;
+	int ret = 0;
 
 	spin_lock(&inode->i_lock);
-	ret = nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT);
-	if (ret > 0)
-		nfsi->ncommit -= ret;
+	if (nfsi->ncommit > 0) {
+		const int max = INT_MAX;
+
+		ret = nfs_scan_commit_list(&nfsi->commit_list, dst, max,
+				&inode->i_lock);
+		ret += pnfs_scan_commit_lists(inode, max - ret,
+				&inode->i_lock);
+	}
 	spin_unlock(&inode->i_lock);
-
-	if (nfs_need_commit(NFS_I(inode)))
-		__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
-
 	return ret;
 }
+
 #else
 static inline int nfs_need_commit(struct nfs_inode *nfsi)
 {
 	return 0;
 }
 
-static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
+static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst)
 {
 	return 0;
 }
@@ -604,7 +659,7 @@
 		    || end < req->wb_offset)
 			goto out_flushme;
 
-		if (nfs_set_page_tag_locked(req))
+		if (nfs_lock_request_dontget(req))
 			break;
 
 		/* The request is locked, so wait and then retry */
@@ -616,13 +671,6 @@
 		spin_lock(&inode->i_lock);
 	}
 
-	if (nfs_clear_request_commit(req) &&
-	    radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree,
-				 req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) {
-		NFS_I(inode)->ncommit--;
-		pnfs_clear_request_commit(req);
-	}
-
 	/* Okay, the request matches. Update the region */
 	if (offset < req->wb_offset) {
 		req->wb_offset = offset;
@@ -634,6 +682,7 @@
 		req->wb_bytes = rqend - req->wb_offset;
 out_unlock:
 	spin_unlock(&inode->i_lock);
+	nfs_clear_request_commit(req);
 	return req;
 out_flushme:
 	spin_unlock(&inode->i_lock);
@@ -655,7 +704,6 @@
 {
 	struct inode *inode = page->mapping->host;
 	struct nfs_page	*req;
-	int error;
 
 	req = nfs_try_to_update_request(inode, page, offset, bytes);
 	if (req != NULL)
@@ -663,11 +711,7 @@
 	req = nfs_create_request(ctx, inode, page, offset, bytes);
 	if (IS_ERR(req))
 		goto out;
-	error = nfs_inode_add_request(inode, req);
-	if (error != 0) {
-		nfs_release_request(req);
-		req = ERR_PTR(error);
-	}
+	nfs_inode_add_request(inode, req);
 out:
 	return req;
 }
@@ -684,7 +728,7 @@
 	nfs_grow_file(page, offset, count);
 	nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
 	nfs_mark_request_dirty(req);
-	nfs_clear_page_tag_locked(req);
+	nfs_unlock_request(req);
 	return 0;
 }
 
@@ -777,7 +821,7 @@
 
 	if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req, data))
 		nfs_inode_remove_request(req);
-	nfs_clear_page_tag_locked(req);
+	nfs_unlock_request(req);
 	nfs_end_page_writeback(page);
 }
 
@@ -925,7 +969,7 @@
 	struct page *page = req->wb_page;
 
 	nfs_mark_request_dirty(req);
-	nfs_clear_page_tag_locked(req);
+	nfs_unlock_request(req);
 	nfs_end_page_writeback(page);
 }
 
@@ -1128,23 +1172,14 @@
 	nfs_writedata_release(calldata);
 }
 
-#if defined(CONFIG_NFS_V4_1)
 void nfs_write_prepare(struct rpc_task *task, void *calldata)
 {
 	struct nfs_write_data *data = calldata;
-
-	if (nfs4_setup_sequence(NFS_SERVER(data->inode),
-				&data->args.seq_args,
-				&data->res.seq_res, 1, task))
-		return;
-	rpc_call_start(task);
+	NFS_PROTO(data->inode)->write_rpc_prepare(task, data);
 }
-#endif /* CONFIG_NFS_V4_1 */
 
 static const struct rpc_call_ops nfs_write_partial_ops = {
-#if defined(CONFIG_NFS_V4_1)
 	.rpc_call_prepare = nfs_write_prepare,
-#endif /* CONFIG_NFS_V4_1 */
 	.rpc_call_done = nfs_writeback_done_partial,
 	.rpc_release = nfs_writeback_release_partial,
 };
@@ -1199,16 +1234,14 @@
 remove_request:
 		nfs_inode_remove_request(req);
 	next:
-		nfs_clear_page_tag_locked(req);
+		nfs_unlock_request(req);
 		nfs_end_page_writeback(page);
 	}
 	nfs_writedata_release(calldata);
 }
 
 static const struct rpc_call_ops nfs_write_full_ops = {
-#if defined(CONFIG_NFS_V4_1)
 	.rpc_call_prepare = nfs_write_prepare,
-#endif /* CONFIG_NFS_V4_1 */
 	.rpc_call_done = nfs_writeback_done_full,
 	.rpc_release = nfs_writeback_release_full,
 };
@@ -1325,7 +1358,6 @@
 {
 	struct nfs_write_data *wdata = data;
 
-	put_lseg(wdata->lseg);
 	put_nfs_open_context(wdata->args.context);
 	nfs_commit_free(wdata);
 }
@@ -1411,7 +1443,7 @@
 		dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
 		dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
 			     BDI_RECLAIMABLE);
-		nfs_clear_page_tag_locked(req);
+		nfs_unlock_request(req);
 	}
 }
 EXPORT_SYMBOL_GPL(nfs_retry_commit);
@@ -1460,7 +1492,7 @@
 	while (!list_empty(&data->pages)) {
 		req = nfs_list_entry(data->pages.next);
 		nfs_list_remove_request(req);
-		nfs_clear_request_commit(req);
+		nfs_clear_page_commit(req->wb_page);
 
 		dprintk("NFS:       commit (%s/%lld %d@%lld)",
 			req->wb_context->dentry->d_sb->s_id,
@@ -1486,7 +1518,7 @@
 		dprintk(" mismatch\n");
 		nfs_mark_request_dirty(req);
 	next:
-		nfs_clear_page_tag_locked(req);
+		nfs_unlock_request(req);
 	}
 }
 EXPORT_SYMBOL_GPL(nfs_commit_release_pages);
@@ -1501,9 +1533,7 @@
 }
 
 static const struct rpc_call_ops nfs_commit_ops = {
-#if defined(CONFIG_NFS_V4_1)
 	.rpc_call_prepare = nfs_write_prepare,
-#endif /* CONFIG_NFS_V4_1 */
 	.rpc_call_done = nfs_commit_done,
 	.rpc_release = nfs_commit_release,
 };
@@ -1517,7 +1547,7 @@
 	res = nfs_commit_set_lock(NFS_I(inode), may_wait);
 	if (res <= 0)
 		goto out_mark_dirty;
-	res = nfs_scan_commit(inode, &head, 0, 0);
+	res = nfs_scan_commit(inode, &head);
 	if (res) {
 		int error;
 
@@ -1635,6 +1665,7 @@
 		if (req == NULL)
 			break;
 		if (nfs_lock_request_dontget(req)) {
+			nfs_clear_request_commit(req);
 			nfs_inode_remove_request(req);
 			/*
 			 * In case nfs_inode_remove_request has marked the
diff --git a/fs/nfsd/current_stateid.h b/fs/nfsd/current_stateid.h
new file mode 100644
index 0000000..4123551
--- /dev/null
+++ b/fs/nfsd/current_stateid.h
@@ -0,0 +1,28 @@
+#ifndef _NFSD4_CURRENT_STATE_H
+#define _NFSD4_CURRENT_STATE_H
+
+#include "state.h"
+#include "xdr4.h"
+
+extern void clear_current_stateid(struct nfsd4_compound_state *cstate);
+/*
+ * functions to set current state id
+ */
+extern void nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *);
+extern void nfsd4_set_openstateid(struct nfsd4_compound_state *, struct nfsd4_open *);
+extern void nfsd4_set_lockstateid(struct nfsd4_compound_state *, struct nfsd4_lock *);
+extern void nfsd4_set_closestateid(struct nfsd4_compound_state *, struct nfsd4_close *);
+
+/*
+ * functions to consume current state id
+ */
+extern void nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *);
+extern void nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *, struct nfsd4_delegreturn *);
+extern void nfsd4_get_freestateid(struct nfsd4_compound_state *, struct nfsd4_free_stateid *);
+extern void nfsd4_get_setattrstateid(struct nfsd4_compound_state *, struct nfsd4_setattr *);
+extern void nfsd4_get_closestateid(struct nfsd4_compound_state *, struct nfsd4_close *);
+extern void nfsd4_get_lockustateid(struct nfsd4_compound_state *, struct nfsd4_locku *);
+extern void nfsd4_get_readstateid(struct nfsd4_compound_state *, struct nfsd4_read *);
+extern void nfsd4_get_writestateid(struct nfsd4_compound_state *, struct nfsd4_write *);
+
+#endif   /* _NFSD4_CURRENT_STATE_H */
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index cf8a6bd..8e9689a 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -87,7 +87,7 @@
 	struct svc_expkey key;
 	struct svc_expkey *ek = NULL;
 
-	if (mlen < 1 || mesg[mlen-1] != '\n')
+	if (mesg[mlen - 1] != '\n')
 		return -EINVAL;
 	mesg[mlen-1] = 0;
 
diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c
index ce7f075..9559ce4 100644
--- a/fs/nfsd/fault_inject.c
+++ b/fs/nfsd/fault_inject.c
@@ -72,7 +72,7 @@
 {
 	unsigned int i;
 	struct nfsd_fault_inject_op *op;
-	mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
+	umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
 
 	debug_dir = debugfs_create_dir("nfsd", NULL);
 	if (!debug_dir)
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
new file mode 100644
index 0000000..12e0cff
--- /dev/null
+++ b/fs/nfsd/netns.h
@@ -0,0 +1,34 @@
+/*
+ * per net namespace data structures for nfsd
+ *
+ * Copyright (C) 2012, Jeff Layton <jlayton@redhat.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.
+ */
+
+#ifndef __NFSD_NETNS_H__
+#define __NFSD_NETNS_H__
+
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+
+struct cld_net;
+
+struct nfsd_net {
+	struct cld_net *cld_net;
+};
+
+extern int nfsd_net_id;
+#endif /* __NFSD_NETNS_H__ */
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 6f3ebb4..c8e9f63 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -605,24 +605,24 @@
 	.procs			= nfs4_cb_procedures
 };
 
-static struct rpc_version *nfs_cb_version[] = {
+static const struct rpc_version *nfs_cb_version[] = {
 	&nfs_cb_version4,
 };
 
-static struct rpc_program cb_program;
+static const struct rpc_program cb_program;
 
 static struct rpc_stat cb_stats = {
 	.program		= &cb_program
 };
 
 #define NFS4_CALLBACK 0x40000000
-static struct rpc_program cb_program = {
+static const struct rpc_program cb_program = {
 	.name			= "nfs4_cb",
 	.number			= NFS4_CALLBACK,
 	.nrvers			= ARRAY_SIZE(nfs_cb_version),
 	.version		= nfs_cb_version,
 	.stats			= &cb_stats,
-	.pipe_dir_name		= "/nfsd4_cb",
+	.pipe_dir_name		= "nfsd4_cb",
 };
 
 static int max_cb_time(void)
@@ -645,7 +645,6 @@
 		.timeout	= &timeparms,
 		.program	= &cb_program,
 		.version	= 0,
-		.authflavor	= clp->cl_flavor,
 		.flags		= (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
 	};
 	struct rpc_clnt *client;
@@ -656,6 +655,7 @@
 		args.client_name = clp->cl_principal;
 		args.prognumber	= conn->cb_prog,
 		args.protocol = XPRT_TRANSPORT_TCP;
+		args.authflavor = clp->cl_flavor;
 		clp->cl_cb_ident = conn->cb_ident;
 	} else {
 		if (!conn->cb_xprt)
@@ -665,6 +665,7 @@
 		args.bc_xprt = conn->cb_xprt;
 		args.prognumber = clp->cl_cb_session->se_cb_prog;
 		args.protocol = XPRT_TRANSPORT_BC_TCP;
+		args.authflavor = RPC_AUTH_UNIX;
 	}
 	/* Create RPC client */
 	client = rpc_create(&args);
@@ -754,9 +755,9 @@
  */
 void nfsd4_probe_callback(struct nfs4_client *clp)
 {
-	/* XXX: atomicity?  Also, should we be using cl_cb_flags? */
+	/* XXX: atomicity?  Also, should we be using cl_flags? */
 	clp->cl_cb_state = NFSD4_CB_UNKNOWN;
-	set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
+	set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags);
 	do_probe_callback(clp);
 }
 
@@ -915,7 +916,7 @@
 /* must be called under the state lock */
 void nfsd4_shutdown_callback(struct nfs4_client *clp)
 {
-	set_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags);
+	set_bit(NFSD4_CLIENT_CB_KILL, &clp->cl_flags);
 	/*
 	 * Note this won't actually result in a null callback;
 	 * instead, nfsd4_do_callback_rpc() will detect the killed
@@ -966,15 +967,15 @@
 		svc_xprt_put(clp->cl_cb_conn.cb_xprt);
 		clp->cl_cb_conn.cb_xprt = NULL;
 	}
-	if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags))
+	if (test_bit(NFSD4_CLIENT_CB_KILL, &clp->cl_flags))
 		return;
 	spin_lock(&clp->cl_lock);
 	/*
 	 * Only serialized callback code is allowed to clear these
 	 * flags; main nfsd code can only set them:
 	 */
-	BUG_ON(!clp->cl_cb_flags);
-	clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
+	BUG_ON(!(clp->cl_flags & NFSD4_CLIENT_CB_FLAG_MASK));
+	clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags);
 	memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn));
 	c = __nfsd4_find_backchannel(clp);
 	if (c) {
@@ -986,7 +987,7 @@
 
 	err = setup_callback_client(clp, &conn, ses);
 	if (err) {
-		warn_no_callback_path(clp, err);
+		nfsd4_mark_cb_down(clp, err);
 		return;
 	}
 	/* Yay, the callback channel's back! Restart any callbacks: */
@@ -1000,7 +1001,7 @@
 	struct nfs4_client *clp = cb->cb_clp;
 	struct rpc_clnt *clnt;
 
-	if (clp->cl_cb_flags)
+	if (clp->cl_flags & NFSD4_CLIENT_CB_FLAG_MASK)
 		nfsd4_process_cb_update(cb);
 
 	clnt = clp->cl_cb_client;
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 9409627..322d11c 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -41,6 +41,14 @@
 #include "nfsd.h"
 
 /*
+ * Turn off idmapping when using AUTH_SYS.
+ */
+static bool nfs4_disable_idmapping = true;
+module_param(nfs4_disable_idmapping, bool, 0644);
+MODULE_PARM_DESC(nfs4_disable_idmapping,
+		"Turn off server's NFSv4 idmapping when using 'sec=sys'");
+
+/*
  * Cache entry
  */
 
@@ -561,28 +569,65 @@
 	return ret;
 }
 
+static bool
+numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, uid_t *id)
+{
+	int ret;
+	char buf[11];
+
+	if (namelen + 1 > sizeof(buf))
+		/* too long to represent a 32-bit id: */
+		return false;
+	/* Just to make sure it's null-terminated: */
+	memcpy(buf, name, namelen);
+	buf[namelen] = '\0';
+	ret = kstrtouint(name, 10, id);
+	return ret == 0;
+}
+
+static __be32
+do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, uid_t *id)
+{
+	if (nfs4_disable_idmapping && rqstp->rq_flavor < RPC_AUTH_GSS)
+		if (numeric_name_to_id(rqstp, type, name, namelen, id))
+			return 0;
+		/*
+		 * otherwise, fall through and try idmapping, for
+		 * backwards compatibility with clients sending names:
+		 */
+	return idmap_name_to_id(rqstp, type, name, namelen, id);
+}
+
+static int
+do_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
+{
+	if (nfs4_disable_idmapping && rqstp->rq_flavor < RPC_AUTH_GSS)
+		return sprintf(name, "%u", id);
+	return idmap_id_to_name(rqstp, type, id, name);
+}
+
 __be32
 nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
 		__u32 *id)
 {
-	return idmap_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id);
+	return do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id);
 }
 
 __be32
 nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
 		__u32 *id)
 {
-	return idmap_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, id);
+	return do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, id);
 }
 
 int
 nfsd_map_uid_to_name(struct svc_rqst *rqstp, __u32 id, char *name)
 {
-	return idmap_id_to_name(rqstp, IDMAP_TYPE_USER, id, name);
+	return do_id_to_name(rqstp, IDMAP_TYPE_USER, id, name);
 }
 
 int
 nfsd_map_gid_to_name(struct svc_rqst *rqstp, __u32 id, char *name)
 {
-	return idmap_id_to_name(rqstp, IDMAP_TYPE_GROUP, id, name);
+	return do_id_to_name(rqstp, IDMAP_TYPE_GROUP, id, name);
 }
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 896da74..2ed14df 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -39,6 +39,7 @@
 #include "cache.h"
 #include "xdr4.h"
 #include "vfs.h"
+#include "current_stateid.h"
 
 #define NFSDDBG_FACILITY		NFSDDBG_PROC
 
@@ -192,10 +193,13 @@
 static __be32
 do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
-	struct svc_fh resfh;
+	struct svc_fh *resfh;
 	__be32 status;
 
-	fh_init(&resfh, NFS4_FHSIZE);
+	resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
+	if (!resfh)
+		return nfserr_jukebox;
+	fh_init(resfh, NFS4_FHSIZE);
 	open->op_truncate = 0;
 
 	if (open->op_create) {
@@ -220,7 +224,7 @@
 		 */
 		status = do_nfsd_create(rqstp, current_fh, open->op_fname.data,
 					open->op_fname.len, &open->op_iattr,
-					&resfh, open->op_createmode,
+					resfh, open->op_createmode,
 					(u32 *)open->op_verf.data,
 					&open->op_truncate, &open->op_created);
 
@@ -234,30 +238,29 @@
 						FATTR4_WORD1_TIME_MODIFY);
 	} else {
 		status = nfsd_lookup(rqstp, current_fh,
-				     open->op_fname.data, open->op_fname.len, &resfh);
+				     open->op_fname.data, open->op_fname.len, resfh);
 		fh_unlock(current_fh);
 		if (status)
 			goto out;
-		status = nfsd_check_obj_isreg(&resfh);
+		status = nfsd_check_obj_isreg(resfh);
 	}
 	if (status)
 		goto out;
 
 	if (is_create_with_attrs(open) && open->op_acl != NULL)
-		do_set_nfs4_acl(rqstp, &resfh, open->op_acl, open->op_bmval);
-
-	set_change_info(&open->op_cinfo, current_fh);
-	fh_dup2(current_fh, &resfh);
+		do_set_nfs4_acl(rqstp, resfh, open->op_acl, open->op_bmval);
 
 	/* set reply cache */
 	fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh,
-			&resfh.fh_handle);
+			&resfh->fh_handle);
 	if (!open->op_created)
-		status = do_open_permission(rqstp, current_fh, open,
+		status = do_open_permission(rqstp, resfh, open,
 					    NFSD_MAY_NOP);
-
+	set_change_info(&open->op_cinfo, current_fh);
+	fh_dup2(current_fh, resfh);
 out:
-	fh_put(&resfh);
+	fh_put(resfh);
+	kfree(resfh);
 	return status;
 }
 
@@ -310,16 +313,14 @@
 	if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
 		return nfserr_inval;
 
-	/* We don't yet support WANT bits: */
-	open->op_share_access &= NFS4_SHARE_ACCESS_MASK;
-
 	open->op_created = 0;
 	/*
 	 * RFC5661 18.51.3
 	 * Before RECLAIM_COMPLETE done, server should deny new lock
 	 */
 	if (nfsd4_has_session(cstate) &&
-	    !cstate->session->se_client->cl_firststate &&
+	    !test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE,
+		      &cstate->session->se_client->cl_flags) &&
 	    open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
 		return nfserr_grace;
 
@@ -452,6 +453,10 @@
 		return nfserr_restorefh;
 
 	fh_dup2(&cstate->current_fh, &cstate->save_fh);
+	if (HAS_STATE_ID(cstate, SAVED_STATE_ID_FLAG)) {
+		memcpy(&cstate->current_stateid, &cstate->save_stateid, sizeof(stateid_t));
+		SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
+	}
 	return nfs_ok;
 }
 
@@ -463,6 +468,10 @@
 		return nfserr_nofilehandle;
 
 	fh_dup2(&cstate->save_fh, &cstate->current_fh);
+	if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG)) {
+		memcpy(&cstate->save_stateid, &cstate->current_stateid, sizeof(stateid_t));
+		SET_STATE_ID(cstate, SAVED_STATE_ID_FLAG);
+	}
 	return nfs_ok;
 }
 
@@ -481,14 +490,20 @@
 			   &access->ac_supported);
 }
 
+static void gen_boot_verifier(nfs4_verifier *verifier)
+{
+	__be32 verf[2];
+
+	verf[0] = (__be32)nfssvc_boot.tv_sec;
+	verf[1] = (__be32)nfssvc_boot.tv_usec;
+	memcpy(verifier->data, verf, sizeof(verifier->data));
+}
+
 static __be32
 nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	     struct nfsd4_commit *commit)
 {
-	u32 *p = (u32 *)commit->co_verf.data;
-	*p++ = nfssvc_boot.tv_sec;
-	*p++ = nfssvc_boot.tv_usec;
-
+	gen_boot_verifier(&commit->co_verf);
 	return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
 			     commit->co_count);
 }
@@ -865,7 +880,6 @@
 {
 	stateid_t *stateid = &write->wr_stateid;
 	struct file *filp = NULL;
-	u32 *p;
 	__be32 status = nfs_ok;
 	unsigned long cnt;
 
@@ -887,9 +901,7 @@
 
 	cnt = write->wr_buflen;
 	write->wr_how_written = write->wr_stable_how;
-	p = (u32 *)write->wr_verifier.data;
-	*p++ = nfssvc_boot.tv_sec;
-	*p++ = nfssvc_boot.tv_usec;
+	gen_boot_verifier(&write->wr_verifier);
 
 	status =  nfsd_write(rqstp, &cstate->current_fh, filp,
 			     write->wr_offset, rqstp->rq_vec, write->wr_vlen,
@@ -1000,6 +1012,8 @@
 typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
 			      void *);
 typedef u32(*nfsd4op_rsize)(struct svc_rqst *, struct nfsd4_op *op);
+typedef void(*stateid_setter)(struct nfsd4_compound_state *, void *);
+typedef void(*stateid_getter)(struct nfsd4_compound_state *, void *);
 
 enum nfsd4_op_flags {
 	ALLOWED_WITHOUT_FH = 1 << 0,	/* No current filehandle required */
@@ -1025,6 +1039,10 @@
 	 * the v4.0 case).
 	 */
 	OP_CACHEME = 1 << 6,
+	/*
+	 * These are ops which clear current state id.
+	 */
+	OP_CLEAR_STATEID = 1 << 7,
 };
 
 struct nfsd4_operation {
@@ -1033,11 +1051,15 @@
 	char *op_name;
 	/* Try to get response size before operation */
 	nfsd4op_rsize op_rsize_bop;
+	stateid_setter op_get_currentstateid;
+	stateid_getter op_set_currentstateid;
 };
 
 static struct nfsd4_operation nfsd4_ops[];
 
+#ifdef NFSD_DEBUG
 static const char *nfsd4_op_name(unsigned opnum);
+#endif
 
 /*
  * Enforce NFSv4.1 COMPOUND ordering rules:
@@ -1215,13 +1237,23 @@
 		if (op->status)
 			goto encode_op;
 
-		if (opdesc->op_func)
+		if (opdesc->op_func) {
+			if (opdesc->op_get_currentstateid)
+				opdesc->op_get_currentstateid(cstate, &op->u);
 			op->status = opdesc->op_func(rqstp, cstate, &op->u);
-		else
+		} else
 			BUG_ON(op->status == nfs_ok);
 
-		if (!op->status && need_wrongsec_check(rqstp))
-			op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp);
+		if (!op->status) {
+			if (opdesc->op_set_currentstateid)
+				opdesc->op_set_currentstateid(cstate, &op->u);
+
+			if (opdesc->op_flags & OP_CLEAR_STATEID)
+				clear_current_stateid(cstate);
+
+			if (need_wrongsec_check(rqstp))
+				op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp);
+		}
 
 encode_op:
 		/* Only from SEQUENCE */
@@ -1413,6 +1445,8 @@
 		.op_flags = OP_MODIFIES_SOMETHING,
 		.op_name = "OP_CLOSE",
 		.op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
+		.op_get_currentstateid = (stateid_getter)nfsd4_get_closestateid,
+		.op_set_currentstateid = (stateid_setter)nfsd4_set_closestateid,
 	},
 	[OP_COMMIT] = {
 		.op_func = (nfsd4op_func)nfsd4_commit,
@@ -1422,7 +1456,7 @@
 	},
 	[OP_CREATE] = {
 		.op_func = (nfsd4op_func)nfsd4_create,
-		.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
+		.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME | OP_CLEAR_STATEID,
 		.op_name = "OP_CREATE",
 		.op_rsize_bop = (nfsd4op_rsize)nfsd4_create_rsize,
 	},
@@ -1431,6 +1465,7 @@
 		.op_flags = OP_MODIFIES_SOMETHING,
 		.op_name = "OP_DELEGRETURN",
 		.op_rsize_bop = nfsd4_only_status_rsize,
+		.op_get_currentstateid = (stateid_getter)nfsd4_get_delegreturnstateid,
 	},
 	[OP_GETATTR] = {
 		.op_func = (nfsd4op_func)nfsd4_getattr,
@@ -1453,6 +1488,7 @@
 		.op_flags = OP_MODIFIES_SOMETHING,
 		.op_name = "OP_LOCK",
 		.op_rsize_bop = (nfsd4op_rsize)nfsd4_lock_rsize,
+		.op_set_currentstateid = (stateid_setter)nfsd4_set_lockstateid,
 	},
 	[OP_LOCKT] = {
 		.op_func = (nfsd4op_func)nfsd4_lockt,
@@ -1463,15 +1499,16 @@
 		.op_flags = OP_MODIFIES_SOMETHING,
 		.op_name = "OP_LOCKU",
 		.op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
+		.op_get_currentstateid = (stateid_getter)nfsd4_get_lockustateid,
 	},
 	[OP_LOOKUP] = {
 		.op_func = (nfsd4op_func)nfsd4_lookup,
-		.op_flags = OP_HANDLES_WRONGSEC,
+		.op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID,
 		.op_name = "OP_LOOKUP",
 	},
 	[OP_LOOKUPP] = {
 		.op_func = (nfsd4op_func)nfsd4_lookupp,
-		.op_flags = OP_HANDLES_WRONGSEC,
+		.op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID,
 		.op_name = "OP_LOOKUPP",
 	},
 	[OP_NVERIFY] = {
@@ -1483,6 +1520,7 @@
 		.op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING,
 		.op_name = "OP_OPEN",
 		.op_rsize_bop = (nfsd4op_rsize)nfsd4_open_rsize,
+		.op_set_currentstateid = (stateid_setter)nfsd4_set_openstateid,
 	},
 	[OP_OPEN_CONFIRM] = {
 		.op_func = (nfsd4op_func)nfsd4_open_confirm,
@@ -1495,25 +1533,30 @@
 		.op_flags = OP_MODIFIES_SOMETHING,
 		.op_name = "OP_OPEN_DOWNGRADE",
 		.op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
+		.op_get_currentstateid = (stateid_getter)nfsd4_get_opendowngradestateid,
+		.op_set_currentstateid = (stateid_setter)nfsd4_set_opendowngradestateid,
 	},
 	[OP_PUTFH] = {
 		.op_func = (nfsd4op_func)nfsd4_putfh,
 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
-				| OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING,
+				| OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING
+				| OP_CLEAR_STATEID,
 		.op_name = "OP_PUTFH",
 		.op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
 	},
 	[OP_PUTPUBFH] = {
 		.op_func = (nfsd4op_func)nfsd4_putrootfh,
 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
-				| OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING,
+				| OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING
+				| OP_CLEAR_STATEID,
 		.op_name = "OP_PUTPUBFH",
 		.op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
 	},
 	[OP_PUTROOTFH] = {
 		.op_func = (nfsd4op_func)nfsd4_putrootfh,
 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
-				| OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING,
+				| OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING
+				| OP_CLEAR_STATEID,
 		.op_name = "OP_PUTROOTFH",
 		.op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
 	},
@@ -1522,6 +1565,7 @@
 		.op_flags = OP_MODIFIES_SOMETHING,
 		.op_name = "OP_READ",
 		.op_rsize_bop = (nfsd4op_rsize)nfsd4_read_rsize,
+		.op_get_currentstateid = (stateid_getter)nfsd4_get_readstateid,
 	},
 	[OP_READDIR] = {
 		.op_func = (nfsd4op_func)nfsd4_readdir,
@@ -1576,6 +1620,7 @@
 		.op_name = "OP_SETATTR",
 		.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
 		.op_rsize_bop = (nfsd4op_rsize)nfsd4_setattr_rsize,
+		.op_get_currentstateid = (stateid_getter)nfsd4_get_setattrstateid,
 	},
 	[OP_SETCLIENTID] = {
 		.op_func = (nfsd4op_func)nfsd4_setclientid,
@@ -1600,6 +1645,7 @@
 		.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
 		.op_name = "OP_WRITE",
 		.op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize,
+		.op_get_currentstateid = (stateid_getter)nfsd4_get_writestateid,
 	},
 	[OP_RELEASE_LOCKOWNER] = {
 		.op_func = (nfsd4op_func)nfsd4_release_lockowner,
@@ -1674,12 +1720,14 @@
 	},
 };
 
+#ifdef NFSD_DEBUG
 static const char *nfsd4_op_name(unsigned opnum)
 {
 	if (opnum < ARRAY_SIZE(nfsd4_ops))
 		return nfsd4_ops[opnum].op_name;
 	return "unknown_operation";
 }
+#endif
 
 #define nfsd4_voidres			nfsd4_voidargs
 struct nfsd4_voidargs { int dummy; };
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 0b3e875..4767429 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -1,5 +1,6 @@
 /*
 *  Copyright (c) 2004 The Regents of the University of Michigan.
+*  Copyright (c) 2012 Jeff Layton <jlayton@redhat.com>
 *  All rights reserved.
 *
 *  Andy Adamson <andros@citi.umich.edu>
@@ -36,16 +37,34 @@
 #include <linux/namei.h>
 #include <linux/crypto.h>
 #include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <net/net_namespace.h>
+#include <linux/sunrpc/rpc_pipe_fs.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/nfsd/cld.h>
 
 #include "nfsd.h"
 #include "state.h"
 #include "vfs.h"
+#include "netns.h"
 
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
+/* Declarations */
+struct nfsd4_client_tracking_ops {
+	int (*init)(struct net *);
+	void (*exit)(struct net *);
+	void (*create)(struct nfs4_client *);
+	void (*remove)(struct nfs4_client *);
+	int (*check)(struct nfs4_client *);
+	void (*grace_done)(struct net *, time_t);
+};
+
 /* Globals */
 static struct file *rec_file;
 static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
+static struct nfsd4_client_tracking_ops *client_tracking_ops;
 
 static int
 nfs4_save_creds(const struct cred **original_creds)
@@ -117,7 +136,8 @@
 	return status;
 }
 
-void nfsd4_create_clid_dir(struct nfs4_client *clp)
+static void
+nfsd4_create_clid_dir(struct nfs4_client *clp)
 {
 	const struct cred *original_cred;
 	char *dname = clp->cl_recdir;
@@ -126,9 +146,8 @@
 
 	dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
 
-	if (clp->cl_firststate)
+	if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
 		return;
-	clp->cl_firststate = 1;
 	if (!rec_file)
 		return;
 	status = nfs4_save_creds(&original_cred);
@@ -265,19 +284,19 @@
 	return status;
 }
 
-void
+static void
 nfsd4_remove_clid_dir(struct nfs4_client *clp)
 {
 	const struct cred *original_cred;
 	int status;
 
-	if (!rec_file || !clp->cl_firststate)
+	if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
 		return;
 
 	status = mnt_want_write_file(rec_file);
 	if (status)
 		goto out;
-	clp->cl_firststate = 0;
+	clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
 
 	status = nfs4_save_creds(&original_cred);
 	if (status < 0)
@@ -292,7 +311,6 @@
 	if (status)
 		printk("NFSD: Failed to remove expired client state directory"
 				" %.*s\n", HEXDIR_LEN, clp->cl_recdir);
-	return;
 }
 
 static int
@@ -311,8 +329,9 @@
 	return 0;
 }
 
-void
-nfsd4_recdir_purge_old(void) {
+static void
+nfsd4_recdir_purge_old(struct net *net, time_t boot_time)
+{
 	int status;
 
 	if (!rec_file)
@@ -343,7 +362,7 @@
 	return 0;
 }
 
-int
+static int
 nfsd4_recdir_load(void) {
 	int status;
 
@@ -361,8 +380,8 @@
  * Hold reference to the recovery directory.
  */
 
-void
-nfsd4_init_recdir()
+static int
+nfsd4_init_recdir(void)
 {
 	const struct cred *original_cred;
 	int status;
@@ -377,20 +396,44 @@
 		printk("NFSD: Unable to change credentials to find recovery"
 		       " directory: error %d\n",
 		       status);
-		return;
+		return status;
 	}
 
 	rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0);
 	if (IS_ERR(rec_file)) {
 		printk("NFSD: unable to find recovery directory %s\n",
 				user_recovery_dirname);
+		status = PTR_ERR(rec_file);
 		rec_file = NULL;
 	}
 
 	nfs4_reset_creds(original_cred);
+	return status;
 }
 
-void
+static int
+nfsd4_load_reboot_recovery_data(struct net *net)
+{
+	int status;
+
+	/* XXX: The legacy code won't work in a container */
+	if (net != &init_net) {
+		WARN(1, KERN_ERR "NFSD: attempt to initialize legacy client "
+			"tracking in a container!\n");
+		return -EINVAL;
+	}
+
+	nfs4_lock_state();
+	status = nfsd4_init_recdir();
+	if (!status)
+		status = nfsd4_recdir_load();
+	nfs4_unlock_state();
+	if (status)
+		printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n");
+	return status;
+}
+
+static void
 nfsd4_shutdown_recdir(void)
 {
 	if (!rec_file)
@@ -399,6 +442,13 @@
 	rec_file = NULL;
 }
 
+static void
+nfsd4_legacy_tracking_exit(struct net *net)
+{
+	nfs4_release_reclaim();
+	nfsd4_shutdown_recdir();
+}
+
 /*
  * Change the NFSv4 recovery directory to recdir.
  */
@@ -425,3 +475,572 @@
 {
 	return user_recovery_dirname;
 }
+
+static int
+nfsd4_check_legacy_client(struct nfs4_client *clp)
+{
+	/* did we already find that this client is stable? */
+	if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
+		return 0;
+
+	/* look for it in the reclaim hashtable otherwise */
+	if (nfsd4_find_reclaim_client(clp)) {
+		set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
+		return 0;
+	}
+
+	return -ENOENT;
+}
+
+static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
+	.init		= nfsd4_load_reboot_recovery_data,
+	.exit		= nfsd4_legacy_tracking_exit,
+	.create		= nfsd4_create_clid_dir,
+	.remove		= nfsd4_remove_clid_dir,
+	.check		= nfsd4_check_legacy_client,
+	.grace_done	= nfsd4_recdir_purge_old,
+};
+
+/* Globals */
+#define NFSD_PIPE_DIR		"nfsd"
+#define NFSD_CLD_PIPE		"cld"
+
+/* per-net-ns structure for holding cld upcall info */
+struct cld_net {
+	struct rpc_pipe		*cn_pipe;
+	spinlock_t		 cn_lock;
+	struct list_head	 cn_list;
+	unsigned int		 cn_xid;
+};
+
+struct cld_upcall {
+	struct list_head	 cu_list;
+	struct cld_net		*cu_net;
+	struct task_struct	*cu_task;
+	struct cld_msg		 cu_msg;
+};
+
+static int
+__cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
+{
+	int ret;
+	struct rpc_pipe_msg msg;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.data = cmsg;
+	msg.len = sizeof(*cmsg);
+
+	/*
+	 * Set task state before we queue the upcall. That prevents
+	 * wake_up_process in the downcall from racing with schedule.
+	 */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	ret = rpc_queue_upcall(pipe, &msg);
+	if (ret < 0) {
+		set_current_state(TASK_RUNNING);
+		goto out;
+	}
+
+	schedule();
+	set_current_state(TASK_RUNNING);
+
+	if (msg.errno < 0)
+		ret = msg.errno;
+out:
+	return ret;
+}
+
+static int
+cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
+{
+	int ret;
+
+	/*
+	 * -EAGAIN occurs when pipe is closed and reopened while there are
+	 *  upcalls queued.
+	 */
+	do {
+		ret = __cld_pipe_upcall(pipe, cmsg);
+	} while (ret == -EAGAIN);
+
+	return ret;
+}
+
+static ssize_t
+cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
+{
+	struct cld_upcall *tmp, *cup;
+	struct cld_msg *cmsg = (struct cld_msg *)src;
+	uint32_t xid;
+	struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info,
+						nfsd_net_id);
+	struct cld_net *cn = nn->cld_net;
+
+	if (mlen != sizeof(*cmsg)) {
+		dprintk("%s: got %lu bytes, expected %lu\n", __func__, mlen,
+			sizeof(*cmsg));
+		return -EINVAL;
+	}
+
+	/* copy just the xid so we can try to find that */
+	if (copy_from_user(&xid, &cmsg->cm_xid, sizeof(xid)) != 0) {
+		dprintk("%s: error when copying xid from userspace", __func__);
+		return -EFAULT;
+	}
+
+	/* walk the list and find corresponding xid */
+	cup = NULL;
+	spin_lock(&cn->cn_lock);
+	list_for_each_entry(tmp, &cn->cn_list, cu_list) {
+		if (get_unaligned(&tmp->cu_msg.cm_xid) == xid) {
+			cup = tmp;
+			list_del_init(&cup->cu_list);
+			break;
+		}
+	}
+	spin_unlock(&cn->cn_lock);
+
+	/* couldn't find upcall? */
+	if (!cup) {
+		dprintk("%s: couldn't find upcall -- xid=%u\n", __func__, xid);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&cup->cu_msg, src, mlen) != 0)
+		return -EFAULT;
+
+	wake_up_process(cup->cu_task);
+	return mlen;
+}
+
+static void
+cld_pipe_destroy_msg(struct rpc_pipe_msg *msg)
+{
+	struct cld_msg *cmsg = msg->data;
+	struct cld_upcall *cup = container_of(cmsg, struct cld_upcall,
+						 cu_msg);
+
+	/* errno >= 0 means we got a downcall */
+	if (msg->errno >= 0)
+		return;
+
+	wake_up_process(cup->cu_task);
+}
+
+static const struct rpc_pipe_ops cld_upcall_ops = {
+	.upcall		= rpc_pipe_generic_upcall,
+	.downcall	= cld_pipe_downcall,
+	.destroy_msg	= cld_pipe_destroy_msg,
+};
+
+static struct dentry *
+nfsd4_cld_register_sb(struct super_block *sb, struct rpc_pipe *pipe)
+{
+	struct dentry *dir, *dentry;
+
+	dir = rpc_d_lookup_sb(sb, NFSD_PIPE_DIR);
+	if (dir == NULL)
+		return ERR_PTR(-ENOENT);
+	dentry = rpc_mkpipe_dentry(dir, NFSD_CLD_PIPE, NULL, pipe);
+	dput(dir);
+	return dentry;
+}
+
+static void
+nfsd4_cld_unregister_sb(struct rpc_pipe *pipe)
+{
+	if (pipe->dentry)
+		rpc_unlink(pipe->dentry);
+}
+
+static struct dentry *
+nfsd4_cld_register_net(struct net *net, struct rpc_pipe *pipe)
+{
+	struct super_block *sb;
+	struct dentry *dentry;
+
+	sb = rpc_get_sb_net(net);
+	if (!sb)
+		return NULL;
+	dentry = nfsd4_cld_register_sb(sb, pipe);
+	rpc_put_sb_net(net);
+	return dentry;
+}
+
+static void
+nfsd4_cld_unregister_net(struct net *net, struct rpc_pipe *pipe)
+{
+	struct super_block *sb;
+
+	sb = rpc_get_sb_net(net);
+	if (sb) {
+		nfsd4_cld_unregister_sb(pipe);
+		rpc_put_sb_net(net);
+	}
+}
+
+/* Initialize rpc_pipefs pipe for communication with client tracking daemon */
+static int
+nfsd4_init_cld_pipe(struct net *net)
+{
+	int ret;
+	struct dentry *dentry;
+	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+	struct cld_net *cn;
+
+	if (nn->cld_net)
+		return 0;
+
+	cn = kzalloc(sizeof(*cn), GFP_KERNEL);
+	if (!cn) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	cn->cn_pipe = rpc_mkpipe_data(&cld_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
+	if (IS_ERR(cn->cn_pipe)) {
+		ret = PTR_ERR(cn->cn_pipe);
+		goto err;
+	}
+	spin_lock_init(&cn->cn_lock);
+	INIT_LIST_HEAD(&cn->cn_list);
+
+	dentry = nfsd4_cld_register_net(net, cn->cn_pipe);
+	if (IS_ERR(dentry)) {
+		ret = PTR_ERR(dentry);
+		goto err_destroy_data;
+	}
+
+	cn->cn_pipe->dentry = dentry;
+	nn->cld_net = cn;
+	return 0;
+
+err_destroy_data:
+	rpc_destroy_pipe_data(cn->cn_pipe);
+err:
+	kfree(cn);
+	printk(KERN_ERR "NFSD: unable to create nfsdcld upcall pipe (%d)\n",
+			ret);
+	return ret;
+}
+
+static void
+nfsd4_remove_cld_pipe(struct net *net)
+{
+	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+	struct cld_net *cn = nn->cld_net;
+
+	nfsd4_cld_unregister_net(net, cn->cn_pipe);
+	rpc_destroy_pipe_data(cn->cn_pipe);
+	kfree(nn->cld_net);
+	nn->cld_net = NULL;
+}
+
+static struct cld_upcall *
+alloc_cld_upcall(struct cld_net *cn)
+{
+	struct cld_upcall *new, *tmp;
+
+	new = kzalloc(sizeof(*new), GFP_KERNEL);
+	if (!new)
+		return new;
+
+	/* FIXME: hard cap on number in flight? */
+restart_search:
+	spin_lock(&cn->cn_lock);
+	list_for_each_entry(tmp, &cn->cn_list, cu_list) {
+		if (tmp->cu_msg.cm_xid == cn->cn_xid) {
+			cn->cn_xid++;
+			spin_unlock(&cn->cn_lock);
+			goto restart_search;
+		}
+	}
+	new->cu_task = current;
+	new->cu_msg.cm_vers = CLD_UPCALL_VERSION;
+	put_unaligned(cn->cn_xid++, &new->cu_msg.cm_xid);
+	new->cu_net = cn;
+	list_add(&new->cu_list, &cn->cn_list);
+	spin_unlock(&cn->cn_lock);
+
+	dprintk("%s: allocated xid %u\n", __func__, new->cu_msg.cm_xid);
+
+	return new;
+}
+
+static void
+free_cld_upcall(struct cld_upcall *victim)
+{
+	struct cld_net *cn = victim->cu_net;
+
+	spin_lock(&cn->cn_lock);
+	list_del(&victim->cu_list);
+	spin_unlock(&cn->cn_lock);
+	kfree(victim);
+}
+
+/* Ask daemon to create a new record */
+static void
+nfsd4_cld_create(struct nfs4_client *clp)
+{
+	int ret;
+	struct cld_upcall *cup;
+	/* FIXME: determine net from clp */
+	struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+	struct cld_net *cn = nn->cld_net;
+
+	/* Don't upcall if it's already stored */
+	if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
+		return;
+
+	cup = alloc_cld_upcall(cn);
+	if (!cup) {
+		ret = -ENOMEM;
+		goto out_err;
+	}
+
+	cup->cu_msg.cm_cmd = Cld_Create;
+	cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
+	memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
+			clp->cl_name.len);
+
+	ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
+	if (!ret) {
+		ret = cup->cu_msg.cm_status;
+		set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
+	}
+
+	free_cld_upcall(cup);
+out_err:
+	if (ret)
+		printk(KERN_ERR "NFSD: Unable to create client "
+				"record on stable storage: %d\n", ret);
+}
+
+/* Ask daemon to create a new record */
+static void
+nfsd4_cld_remove(struct nfs4_client *clp)
+{
+	int ret;
+	struct cld_upcall *cup;
+	/* FIXME: determine net from clp */
+	struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+	struct cld_net *cn = nn->cld_net;
+
+	/* Don't upcall if it's already removed */
+	if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
+		return;
+
+	cup = alloc_cld_upcall(cn);
+	if (!cup) {
+		ret = -ENOMEM;
+		goto out_err;
+	}
+
+	cup->cu_msg.cm_cmd = Cld_Remove;
+	cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
+	memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
+			clp->cl_name.len);
+
+	ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
+	if (!ret) {
+		ret = cup->cu_msg.cm_status;
+		clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
+	}
+
+	free_cld_upcall(cup);
+out_err:
+	if (ret)
+		printk(KERN_ERR "NFSD: Unable to remove client "
+				"record from stable storage: %d\n", ret);
+}
+
+/* Check for presence of a record, and update its timestamp */
+static int
+nfsd4_cld_check(struct nfs4_client *clp)
+{
+	int ret;
+	struct cld_upcall *cup;
+	/* FIXME: determine net from clp */
+	struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+	struct cld_net *cn = nn->cld_net;
+
+	/* Don't upcall if one was already stored during this grace pd */
+	if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
+		return 0;
+
+	cup = alloc_cld_upcall(cn);
+	if (!cup) {
+		printk(KERN_ERR "NFSD: Unable to check client record on "
+				"stable storage: %d\n", -ENOMEM);
+		return -ENOMEM;
+	}
+
+	cup->cu_msg.cm_cmd = Cld_Check;
+	cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
+	memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
+			clp->cl_name.len);
+
+	ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
+	if (!ret) {
+		ret = cup->cu_msg.cm_status;
+		set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
+	}
+
+	free_cld_upcall(cup);
+	return ret;
+}
+
+static void
+nfsd4_cld_grace_done(struct net *net, time_t boot_time)
+{
+	int ret;
+	struct cld_upcall *cup;
+	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+	struct cld_net *cn = nn->cld_net;
+
+	cup = alloc_cld_upcall(cn);
+	if (!cup) {
+		ret = -ENOMEM;
+		goto out_err;
+	}
+
+	cup->cu_msg.cm_cmd = Cld_GraceDone;
+	cup->cu_msg.cm_u.cm_gracetime = (int64_t)boot_time;
+	ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
+	if (!ret)
+		ret = cup->cu_msg.cm_status;
+
+	free_cld_upcall(cup);
+out_err:
+	if (ret)
+		printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret);
+}
+
+static struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
+	.init		= nfsd4_init_cld_pipe,
+	.exit		= nfsd4_remove_cld_pipe,
+	.create		= nfsd4_cld_create,
+	.remove		= nfsd4_cld_remove,
+	.check		= nfsd4_cld_check,
+	.grace_done	= nfsd4_cld_grace_done,
+};
+
+int
+nfsd4_client_tracking_init(struct net *net)
+{
+	int status;
+	struct path path;
+
+	if (!client_tracking_ops) {
+		client_tracking_ops = &nfsd4_cld_tracking_ops;
+		status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path);
+		if (!status) {
+			if (S_ISDIR(path.dentry->d_inode->i_mode))
+				client_tracking_ops =
+						&nfsd4_legacy_tracking_ops;
+			path_put(&path);
+		}
+	}
+
+	status = client_tracking_ops->init(net);
+	if (status) {
+		printk(KERN_WARNING "NFSD: Unable to initialize client "
+				    "recovery tracking! (%d)\n", status);
+		client_tracking_ops = NULL;
+	}
+	return status;
+}
+
+void
+nfsd4_client_tracking_exit(struct net *net)
+{
+	if (client_tracking_ops) {
+		client_tracking_ops->exit(net);
+		client_tracking_ops = NULL;
+	}
+}
+
+void
+nfsd4_client_record_create(struct nfs4_client *clp)
+{
+	if (client_tracking_ops)
+		client_tracking_ops->create(clp);
+}
+
+void
+nfsd4_client_record_remove(struct nfs4_client *clp)
+{
+	if (client_tracking_ops)
+		client_tracking_ops->remove(clp);
+}
+
+int
+nfsd4_client_record_check(struct nfs4_client *clp)
+{
+	if (client_tracking_ops)
+		return client_tracking_ops->check(clp);
+
+	return -EOPNOTSUPP;
+}
+
+void
+nfsd4_record_grace_done(struct net *net, time_t boot_time)
+{
+	if (client_tracking_ops)
+		client_tracking_ops->grace_done(net, boot_time);
+}
+
+static int
+rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr)
+{
+	struct super_block *sb = ptr;
+	struct net *net = sb->s_fs_info;
+	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+	struct cld_net *cn = nn->cld_net;
+	struct dentry *dentry;
+	int ret = 0;
+
+	if (!try_module_get(THIS_MODULE))
+		return 0;
+
+	if (!cn) {
+		module_put(THIS_MODULE);
+		return 0;
+	}
+
+	switch (event) {
+	case RPC_PIPEFS_MOUNT:
+		dentry = nfsd4_cld_register_sb(sb, cn->cn_pipe);
+		if (IS_ERR(dentry)) {
+			ret = PTR_ERR(dentry);
+			break;
+		}
+		cn->cn_pipe->dentry = dentry;
+		break;
+	case RPC_PIPEFS_UMOUNT:
+		if (cn->cn_pipe->dentry)
+			nfsd4_cld_unregister_sb(cn->cn_pipe);
+		break;
+	default:
+		ret = -ENOTSUPP;
+		break;
+	}
+	module_put(THIS_MODULE);
+	return ret;
+}
+
+struct notifier_block nfsd4_cld_block = {
+	.notifier_call = rpc_pipefs_event,
+};
+
+int
+register_cld_notifier(void)
+{
+	return rpc_pipefs_notifier_register(&nfsd4_cld_block);
+}
+
+void
+unregister_cld_notifier(void)
+{
+	rpc_pipefs_notifier_unregister(&nfsd4_cld_block);
+}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index e8c98f0..1841f8b 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -58,11 +58,15 @@
 static const stateid_t zero_stateid = {
 	/* all fields zero */
 };
+static const stateid_t currentstateid = {
+	.si_generation = 1,
+};
 
 static u64 current_sessionid = 1;
 
 #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))
 #define ONE_STATEID(stateid)  (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))
+#define CURRENT_STATEID(stateid) (!memcmp((stateid), &currentstateid, sizeof(stateid_t)))
 
 /* forward declarations */
 static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);
@@ -91,6 +95,19 @@
 	mutex_lock(&client_mutex);
 }
 
+static void free_session(struct kref *);
+
+/* Must be called under the client_lock */
+static void nfsd4_put_session_locked(struct nfsd4_session *ses)
+{
+	kref_put(&ses->se_ref, free_session);
+}
+
+static void nfsd4_get_session(struct nfsd4_session *ses)
+{
+	kref_get(&ses->se_ref);
+}
+
 void
 nfs4_unlock_state(void)
 {
@@ -605,12 +622,20 @@
 	return sid->sequence % SESSION_HASH_SIZE;
 }
 
+#ifdef NFSD_DEBUG
 static inline void
 dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
 {
 	u32 *ptr = (u32 *)(&sessionid->data[0]);
 	dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]);
 }
+#else
+static inline void
+dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
+{
+}
+#endif
+
 
 static void
 gen_sessionid(struct nfsd4_session *ses)
@@ -832,11 +857,12 @@
 	spin_unlock(&clp->cl_lock);
 }
 
-void free_session(struct kref *kref)
+static void free_session(struct kref *kref)
 {
 	struct nfsd4_session *ses;
 	int mem;
 
+	BUG_ON(!spin_is_locked(&client_lock));
 	ses = container_of(kref, struct nfsd4_session, se_ref);
 	nfsd4_del_conns(ses);
 	spin_lock(&nfsd_drc_lock);
@@ -847,6 +873,13 @@
 	kfree(ses);
 }
 
+void nfsd4_put_session(struct nfsd4_session *ses)
+{
+	spin_lock(&client_lock);
+	nfsd4_put_session_locked(ses);
+	spin_unlock(&client_lock);
+}
+
 static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses)
 {
 	struct nfsd4_session *new;
@@ -894,7 +927,9 @@
 	status = nfsd4_new_conn_from_crses(rqstp, new);
 	/* whoops: benny points out, status is ignored! (err, or bogus) */
 	if (status) {
+		spin_lock(&client_lock);
 		free_session(&new->se_ref);
+		spin_unlock(&client_lock);
 		return NULL;
 	}
 	if (cses->flags & SESSION4_BACK_CHAN) {
@@ -1006,12 +1041,13 @@
 static inline void
 free_client(struct nfs4_client *clp)
 {
+	BUG_ON(!spin_is_locked(&client_lock));
 	while (!list_empty(&clp->cl_sessions)) {
 		struct nfsd4_session *ses;
 		ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
 				se_perclnt);
 		list_del(&ses->se_perclnt);
-		nfsd4_put_session(ses);
+		nfsd4_put_session_locked(ses);
 	}
 	if (clp->cl_cred.cr_group_info)
 		put_group_info(clp->cl_cred.cr_group_info);
@@ -1138,12 +1174,12 @@
 
 static void gen_confirm(struct nfs4_client *clp)
 {
+	__be32 verf[2];
 	static u32 i;
-	u32 *p;
 
-	p = (u32 *)clp->cl_confirm.data;
-	*p++ = get_seconds();
-	*p++ = i++;
+	verf[0] = (__be32)get_seconds();
+	verf[1] = (__be32)i++;
+	memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
 }
 
 static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)
@@ -1180,7 +1216,9 @@
 	if (princ) {
 		clp->cl_principal = kstrdup(princ, GFP_KERNEL);
 		if (clp->cl_principal == NULL) {
+			spin_lock(&client_lock);
 			free_client(clp);
+			spin_unlock(&client_lock);
 			return NULL;
 		}
 	}
@@ -1308,7 +1346,7 @@
 	else
 		goto out_err;
 
-	conn->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val,
+	conn->cb_addrlen = rpc_uaddr2sockaddr(&init_net, se->se_callback_addr_val,
 					    se->se_callback_addr_len,
 					    (struct sockaddr *)&conn->cb_addr,
 					    sizeof(conn->cb_addr));
@@ -1347,6 +1385,7 @@
 	slot->sl_opcnt = resp->opcnt;
 	slot->sl_status = resp->cstate.status;
 
+	slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
 	if (nfsd4_not_cached(resp)) {
 		slot->sl_datalen = 0;
 		return;
@@ -1374,15 +1413,12 @@
 	struct nfsd4_op *op;
 	struct nfsd4_slot *slot = resp->cstate.slot;
 
-	dprintk("--> %s resp->opcnt %d cachethis %u \n", __func__,
-		resp->opcnt, resp->cstate.slot->sl_cachethis);
-
 	/* Encode the replayed sequence operation */
 	op = &args->ops[resp->opcnt - 1];
 	nfsd4_encode_operation(resp, op);
 
 	/* Return nfserr_retry_uncached_rep in next operation. */
-	if (args->opcnt > 1 && slot->sl_cachethis == 0) {
+	if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) {
 		op = &args->ops[resp->opcnt++];
 		op->status = nfserr_retry_uncached_rep;
 		nfsd4_encode_operation(resp, op);
@@ -1575,16 +1611,11 @@
 		else
 			return nfserr_seq_misordered;
 	}
-	/* Normal */
+	/* Note unsigned 32-bit arithmetic handles wraparound: */
 	if (likely(seqid == slot_seqid + 1))
 		return nfs_ok;
-	/* Replay */
 	if (seqid == slot_seqid)
 		return nfserr_replay_cache;
-	/* Wraparound */
-	if (seqid == 1 && (slot_seqid + 1) == 0)
-		return nfs_ok;
-	/* Misordered replay or misordered new request */
 	return nfserr_seq_misordered;
 }
 
@@ -1815,9 +1846,10 @@
 	nfsd4_probe_callback_sync(ses->se_client);
 	nfs4_unlock_state();
 
+	spin_lock(&client_lock);
 	nfsd4_del_conns(ses);
-
-	nfsd4_put_session(ses);
+	nfsd4_put_session_locked(ses);
+	spin_unlock(&client_lock);
 	status = nfs_ok;
 out:
 	dprintk("%s returns %d\n", __func__, ntohl(status));
@@ -1921,8 +1953,12 @@
 	 * sr_highest_slotid and the sr_target_slot id to maxslots */
 	seq->maxslots = session->se_fchannel.maxreqs;
 
-	status = check_slot_seqid(seq->seqid, slot->sl_seqid, slot->sl_inuse);
+	status = check_slot_seqid(seq->seqid, slot->sl_seqid,
+					slot->sl_flags & NFSD4_SLOT_INUSE);
 	if (status == nfserr_replay_cache) {
+		status = nfserr_seq_misordered;
+		if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED))
+			goto out;
 		cstate->slot = slot;
 		cstate->session = session;
 		/* Return the cached reply status and set cstate->status
@@ -1938,9 +1974,12 @@
 	conn = NULL;
 
 	/* Success! bump slot seqid */
-	slot->sl_inuse = true;
 	slot->sl_seqid = seq->seqid;
-	slot->sl_cachethis = seq->cachethis;
+	slot->sl_flags |= NFSD4_SLOT_INUSE;
+	if (seq->cachethis)
+		slot->sl_flags |= NFSD4_SLOT_CACHETHIS;
+	else
+		slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS;
 
 	cstate->slot = slot;
 	cstate->session = session;
@@ -2030,7 +2069,8 @@
 
 	nfs4_lock_state();
 	status = nfserr_complete_already;
-	if (cstate->session->se_client->cl_firststate)
+	if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE,
+			     &cstate->session->se_client->cl_flags))
 		goto out;
 
 	status = nfserr_stale_clientid;
@@ -2045,7 +2085,7 @@
 		goto out;
 
 	status = nfs_ok;
-	nfsd4_create_clid_dir(cstate->session->se_client);
+	nfsd4_client_record_create(cstate->session->se_client);
 out:
 	nfs4_unlock_state();
 	return status;
@@ -2240,7 +2280,7 @@
 			conf = find_confirmed_client_by_str(unconf->cl_recdir,
 							    hash);
 			if (conf) {
-				nfsd4_remove_clid_dir(conf);
+				nfsd4_client_record_remove(conf);
 				expire_client(conf);
 			}
 			move_to_confirmed(unconf);
@@ -2633,8 +2673,6 @@
 
 static int share_access_to_flags(u32 share_access)
 {
-	share_access &= ~NFS4_SHARE_WANT_MASK;
-
 	return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
 }
 
@@ -2776,10 +2814,9 @@
 
 
 static void
-nfs4_set_claim_prev(struct nfsd4_open *open)
+nfs4_set_claim_prev(struct nfsd4_open *open, bool has_session)
 {
 	open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
-	open->op_openowner->oo_owner.so_client->cl_firststate = 1;
 }
 
 /* Should we give out recallable state?: */
@@ -2855,6 +2892,27 @@
 	return 0;
 }
 
+static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
+{
+	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
+	if (status == -EAGAIN)
+		open->op_why_no_deleg = WND4_CONTENTION;
+	else {
+		open->op_why_no_deleg = WND4_RESOURCE;
+		switch (open->op_deleg_want) {
+		case NFS4_SHARE_WANT_READ_DELEG:
+		case NFS4_SHARE_WANT_WRITE_DELEG:
+		case NFS4_SHARE_WANT_ANY_DELEG:
+			break;
+		case NFS4_SHARE_WANT_CANCEL:
+			open->op_why_no_deleg = WND4_CANCELLED;
+			break;
+		case NFS4_SHARE_WANT_NO_DELEG:
+			BUG();	/* not supposed to get here */
+		}
+	}
+}
+
 /*
  * Attempt to hand out a delegation.
  */
@@ -2864,7 +2922,7 @@
 	struct nfs4_delegation *dp;
 	struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner);
 	int cb_up;
-	int status, flag = 0;
+	int status = 0, flag = 0;
 
 	cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
 	flag = NFS4_OPEN_DELEGATE_NONE;
@@ -2905,11 +2963,16 @@
 	dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
 		STATEID_VAL(&dp->dl_stid.sc_stateid));
 out:
-	if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS
-			&& flag == NFS4_OPEN_DELEGATE_NONE
-			&& open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
-		dprintk("NFSD: WARNING: refusing delegation reclaim\n");
 	open->op_delegate_type = flag;
+	if (flag == NFS4_OPEN_DELEGATE_NONE) {
+		if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
+		    open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
+			dprintk("NFSD: WARNING: refusing delegation reclaim\n");
+
+		/* 4.1 client asking for a delegation? */
+		if (open->op_deleg_want)
+			nfsd4_open_deleg_none_ext(open, status);
+	}
 	return;
 out_free:
 	nfs4_put_delegation(dp);
@@ -2918,6 +2981,24 @@
 	goto out;
 }
 
+static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,
+					struct nfs4_delegation *dp)
+{
+	if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG &&
+	    dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
+		open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
+		open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE;
+	} else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG &&
+		   dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
+		open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
+		open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE;
+	}
+	/* Otherwise the client must be confused wanting a delegation
+	 * it already has, therefore we don't return
+	 * NFS4_OPEN_DELEGATE_NONE_EXT and reason.
+	 */
+}
+
 /*
  * called with nfs4_lock_state() held.
  */
@@ -2979,24 +3060,36 @@
 	update_stateid(&stp->st_stid.sc_stateid);
 	memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
 
-	if (nfsd4_has_session(&resp->cstate))
+	if (nfsd4_has_session(&resp->cstate)) {
 		open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
 
+		if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
+			open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
+			open->op_why_no_deleg = WND4_NOT_WANTED;
+			goto nodeleg;
+		}
+	}
+
 	/*
 	* Attempt to hand out a delegation. No error return, because the
 	* OPEN succeeds even if we fail.
 	*/
 	nfs4_open_delegation(current_fh, open, stp);
-
+nodeleg:
 	status = nfs_ok;
 
 	dprintk("%s: stateid=" STATEID_FMT "\n", __func__,
 		STATEID_VAL(&stp->st_stid.sc_stateid));
 out:
+	/* 4.1 client trying to upgrade/downgrade delegation? */
+	if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp &&
+	    open->op_deleg_want)
+		nfsd4_deleg_xgrade_none_ext(open, dp);
+
 	if (fp)
 		put_nfs4_file(fp);
 	if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
-		nfs4_set_claim_prev(open);
+		nfs4_set_claim_prev(open, nfsd4_has_session(&resp->cstate));
 	/*
 	* To finish the open response, we just need to set the rflags.
 	*/
@@ -3066,7 +3159,7 @@
 nfsd4_end_grace(void)
 {
 	dprintk("NFSD: end of grace period\n");
-	nfsd4_recdir_purge_old();
+	nfsd4_record_grace_done(&init_net, boot_time);
 	locks_end_grace(&nfsd4_manager);
 	/*
 	 * Now that every NFSv4 client has had the chance to recover and
@@ -3115,7 +3208,7 @@
 		clp = list_entry(pos, struct nfs4_client, cl_lru);
 		dprintk("NFSD: purging unused client (clientid %08x)\n",
 			clp->cl_clientid.cl_id);
-		nfsd4_remove_clid_dir(clp);
+		nfsd4_client_record_remove(clp);
 		expire_client(clp);
 	}
 	spin_lock(&recall_lock);
@@ -3400,7 +3493,14 @@
 nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		   struct nfsd4_test_stateid *test_stateid)
 {
-	/* real work is done during encoding */
+	struct nfsd4_test_stateid_id *stateid;
+	struct nfs4_client *cl = cstate->session->se_client;
+
+	nfs4_lock_state();
+	list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list)
+		stateid->ts_id_status = nfs4_validate_stateid(cl, &stateid->ts_id_stateid);
+	nfs4_unlock_state();
+
 	return nfs_ok;
 }
 
@@ -3539,7 +3639,7 @@
 	dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
 		__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
 
-	nfsd4_create_clid_dir(oo->oo_owner.so_client);
+	nfsd4_client_record_create(oo->oo_owner.so_client);
 	status = nfs_ok;
 out:
 	if (!cstate->replay_owner)
@@ -3596,7 +3696,9 @@
 			cstate->current_fh.fh_dentry->d_name.name);
 
 	/* We don't yet support WANT bits: */
-	od->od_share_access &= NFS4_SHARE_ACCESS_MASK;
+	if (od->od_deleg_want)
+		dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__,
+			od->od_deleg_want);
 
 	nfs4_lock_state();
 	status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid,
@@ -4353,7 +4455,9 @@
 	struct nfs4_client *clp;
 
 	clp = find_confirmed_client_by_str(name, strhashval);
-	return clp ? 1 : 0;
+	if (!clp)
+		return 0;
+	return test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
 }
 
 /*
@@ -4377,7 +4481,7 @@
 	return 1;
 }
 
-static void
+void
 nfs4_release_reclaim(void)
 {
 	struct nfs4_client_reclaim *crp = NULL;
@@ -4397,19 +4501,12 @@
 
 /*
  * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
-static struct nfs4_client_reclaim *
-nfs4_find_reclaim_client(clientid_t *clid)
+struct nfs4_client_reclaim *
+nfsd4_find_reclaim_client(struct nfs4_client *clp)
 {
 	unsigned int strhashval;
-	struct nfs4_client *clp;
 	struct nfs4_client_reclaim *crp = NULL;
 
-
-	/* find clientid in conf_id_hashtbl */
-	clp = find_confirmed_client(clid);
-	if (clp == NULL)
-		return NULL;
-
 	dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s\n",
 		            clp->cl_name.len, clp->cl_name.data,
 			    clp->cl_recdir);
@@ -4430,7 +4527,14 @@
 __be32
 nfs4_check_open_reclaim(clientid_t *clid)
 {
-	return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad;
+	struct nfs4_client *clp;
+
+	/* find clientid in conf_id_hashtbl */
+	clp = find_confirmed_client(clid);
+	if (clp == NULL)
+		return nfserr_reclaim_bad;
+
+	return nfsd4_client_record_check(clp) ? nfserr_reclaim_bad : nfs_ok;
 }
 
 #ifdef CONFIG_NFSD_FAULT_INJECTION
@@ -4442,7 +4546,7 @@
 
 	nfs4_lock_state();
 	list_for_each_entry_safe(clp, next, &client_lru, cl_lru) {
-		nfsd4_remove_clid_dir(clp);
+		nfsd4_client_record_remove(clp);
 		expire_client(clp);
 		if (++count == num)
 			break;
@@ -4577,19 +4681,6 @@
 	reclaim_str_hashtbl_size = 0;
 }
 
-static void
-nfsd4_load_reboot_recovery_data(void)
-{
-	int status;
-
-	nfs4_lock_state();
-	nfsd4_init_recdir();
-	status = nfsd4_recdir_load();
-	nfs4_unlock_state();
-	if (status)
-		printk("NFSD: Failure reading reboot recovery data\n");
-}
-
 /*
  * Since the lifetime of a delegation isn't limited to that of an open, a
  * client may quite reasonably hang on to a delegation as long as it has
@@ -4613,21 +4704,34 @@
 
 /* initialization to perform when the nfsd service is started: */
 
-static int
-__nfs4_state_start(void)
+int
+nfs4_state_start(void)
 {
 	int ret;
 
+	/*
+	 * FIXME: For now, we hang most of the pernet global stuff off of
+	 * init_net until nfsd is fully containerized. Eventually, we'll
+	 * need to pass a net pointer into this function, take a reference
+	 * to that instead and then do most of the rest of this on a per-net
+	 * basis.
+	 */
+	get_net(&init_net);
+	nfsd4_client_tracking_init(&init_net);
 	boot_time = get_seconds();
 	locks_start_grace(&nfsd4_manager);
 	printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
 	       nfsd4_grace);
 	ret = set_callback_cred();
-	if (ret)
-		return -ENOMEM;
+	if (ret) {
+		ret = -ENOMEM;
+		goto out_recovery;
+	}
 	laundry_wq = create_singlethread_workqueue("nfsd4");
-	if (laundry_wq == NULL)
-		return -ENOMEM;
+	if (laundry_wq == NULL) {
+		ret = -ENOMEM;
+		goto out_recovery;
+	}
 	ret = nfsd4_create_callback_queue();
 	if (ret)
 		goto out_free_laundry;
@@ -4636,16 +4740,12 @@
 	return 0;
 out_free_laundry:
 	destroy_workqueue(laundry_wq);
+out_recovery:
+	nfsd4_client_tracking_exit(&init_net);
+	put_net(&init_net);
 	return ret;
 }
 
-int
-nfs4_state_start(void)
-{
-	nfsd4_load_reboot_recovery_data();
-	return __nfs4_state_start();
-}
-
 static void
 __nfs4_state_shutdown(void)
 {
@@ -4676,7 +4776,8 @@
 		unhash_delegation(dp);
 	}
 
-	nfsd4_shutdown_recdir();
+	nfsd4_client_tracking_exit(&init_net);
+	put_net(&init_net);
 }
 
 void
@@ -4686,8 +4787,108 @@
 	destroy_workqueue(laundry_wq);
 	locks_end_grace(&nfsd4_manager);
 	nfs4_lock_state();
-	nfs4_release_reclaim();
 	__nfs4_state_shutdown();
 	nfs4_unlock_state();
 	nfsd4_destroy_callback_queue();
 }
+
+static void
+get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
+{
+	if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid))
+		memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t));
+}
+
+static void
+put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
+{
+	if (cstate->minorversion) {
+		memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t));
+		SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
+	}
+}
+
+void
+clear_current_stateid(struct nfsd4_compound_state *cstate)
+{
+	CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
+}
+
+/*
+ * functions to set current state id
+ */
+void
+nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
+{
+	put_stateid(cstate, &odp->od_stateid);
+}
+
+void
+nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
+{
+	put_stateid(cstate, &open->op_stateid);
+}
+
+void
+nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
+{
+	put_stateid(cstate, &close->cl_stateid);
+}
+
+void
+nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lock)
+{
+	put_stateid(cstate, &lock->lk_resp_stateid);
+}
+
+/*
+ * functions to consume current state id
+ */
+
+void
+nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
+{
+	get_stateid(cstate, &odp->od_stateid);
+}
+
+void
+nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *drp)
+{
+	get_stateid(cstate, &drp->dr_stateid);
+}
+
+void
+nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *fsp)
+{
+	get_stateid(cstate, &fsp->fr_stateid);
+}
+
+void
+nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr)
+{
+	get_stateid(cstate, &setattr->sa_stateid);
+}
+
+void
+nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
+{
+	get_stateid(cstate, &close->cl_stateid);
+}
+
+void
+nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, struct nfsd4_locku *locku)
+{
+	get_stateid(cstate, &locku->lu_stateid);
+}
+
+void
+nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, struct nfsd4_read *read)
+{
+	get_stateid(cstate, &read->rd_stateid);
+}
+
+void
+nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, struct nfsd4_write *write)
+{
+	get_stateid(cstate, &write->wr_stateid);
+}
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 0ec5a1b..bcd8904 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -133,22 +133,6 @@
 	}					\
 } while (0)
 
-static void save_buf(struct nfsd4_compoundargs *argp, struct nfsd4_saved_compoundargs *savep)
-{
-	savep->p        = argp->p;
-	savep->end      = argp->end;
-	savep->pagelen  = argp->pagelen;
-	savep->pagelist = argp->pagelist;
-}
-
-static void restore_buf(struct nfsd4_compoundargs *argp, struct nfsd4_saved_compoundargs *savep)
-{
-	argp->p        = savep->p;
-	argp->end      = savep->end;
-	argp->pagelen  = savep->pagelen;
-	argp->pagelist = savep->pagelist;
-}
-
 static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
 {
 	/* We want more bytes than seem to be available.
@@ -638,14 +622,18 @@
 	DECODE_TAIL;
 }
 
-static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *x)
+static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *share_access, u32 *deleg_want, u32 *deleg_when)
 {
 	__be32 *p;
 	u32 w;
 
 	READ_BUF(4);
 	READ32(w);
-	*x = w;
+	*share_access = w & NFS4_SHARE_ACCESS_MASK;
+	*deleg_want = w & NFS4_SHARE_WANT_MASK;
+	if (deleg_when)
+		*deleg_when = w & NFS4_SHARE_WHEN_MASK;
+
 	switch (w & NFS4_SHARE_ACCESS_MASK) {
 	case NFS4_SHARE_ACCESS_READ:
 	case NFS4_SHARE_ACCESS_WRITE:
@@ -673,6 +661,9 @@
 	w &= ~NFS4_SHARE_WANT_MASK;
 	if (!w)
 		return nfs_ok;
+
+	if (!deleg_when)	/* open_downgrade */
+		return nfserr_inval;
 	switch (w) {
 	case NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL:
 	case NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED:
@@ -719,6 +710,7 @@
 nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
 {
 	DECODE_HEAD;
+	u32 dummy;
 
 	memset(open->op_bmval, 0, sizeof(open->op_bmval));
 	open->op_iattr.ia_valid = 0;
@@ -727,7 +719,9 @@
 	/* seqid, share_access, share_deny, clientid, ownerlen */
 	READ_BUF(4);
 	READ32(open->op_seqid);
-	status = nfsd4_decode_share_access(argp, &open->op_share_access);
+	/* decode, yet ignore deleg_when until supported */
+	status = nfsd4_decode_share_access(argp, &open->op_share_access,
+					   &open->op_deleg_want, &dummy);
 	if (status)
 		goto xdr_error;
 	status = nfsd4_decode_share_deny(argp, &open->op_share_deny);
@@ -755,14 +749,14 @@
 				goto out;
 			break;
 		case NFS4_CREATE_EXCLUSIVE:
-			READ_BUF(8);
-			COPYMEM(open->op_verf.data, 8);
+			READ_BUF(NFS4_VERIFIER_SIZE);
+			COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
 			break;
 		case NFS4_CREATE_EXCLUSIVE4_1:
 			if (argp->minorversion < 1)
 				goto xdr_error;
-			READ_BUF(8);
-			COPYMEM(open->op_verf.data, 8);
+			READ_BUF(NFS4_VERIFIER_SIZE);
+			COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
 			status = nfsd4_decode_fattr(argp, open->op_bmval,
 				&open->op_iattr, &open->op_acl);
 			if (status)
@@ -848,7 +842,8 @@
 		return status;
 	READ_BUF(4);
 	READ32(open_down->od_seqid);
-	status = nfsd4_decode_share_access(argp, &open_down->od_share_access);
+	status = nfsd4_decode_share_access(argp, &open_down->od_share_access,
+					   &open_down->od_deleg_want, NULL);
 	if (status)
 		return status;
 	status = nfsd4_decode_share_deny(argp, &open_down->od_share_deny);
@@ -994,8 +989,8 @@
 {
 	DECODE_HEAD;
 
-	READ_BUF(8);
-	COPYMEM(setclientid->se_verf.data, 8);
+	READ_BUF(NFS4_VERIFIER_SIZE);
+	COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE);
 
 	status = nfsd4_decode_opaque(argp, &setclientid->se_name);
 	if (status)
@@ -1020,9 +1015,9 @@
 {
 	DECODE_HEAD;
 
-	READ_BUF(8 + sizeof(nfs4_verifier));
+	READ_BUF(8 + NFS4_VERIFIER_SIZE);
 	COPYMEM(&scd_c->sc_clientid, 8);
-	COPYMEM(&scd_c->sc_confirm, sizeof(nfs4_verifier));
+	COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE);
 
 	DECODE_TAIL;
 }
@@ -1385,26 +1380,29 @@
 static __be32
 nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid)
 {
-	unsigned int nbytes;
-	stateid_t si;
 	int i;
-	__be32 *p;
-	__be32 status;
+	__be32 *p, status;
+	struct nfsd4_test_stateid_id *stateid;
 
 	READ_BUF(4);
 	test_stateid->ts_num_ids = ntohl(*p++);
 
-	nbytes = test_stateid->ts_num_ids * sizeof(stateid_t);
-	if (nbytes > (u32)((char *)argp->end - (char *)argp->p))
-		goto xdr_error;
-
-	test_stateid->ts_saved_args = argp;
-	save_buf(argp, &test_stateid->ts_savedp);
+	INIT_LIST_HEAD(&test_stateid->ts_stateid_list);
 
 	for (i = 0; i < test_stateid->ts_num_ids; i++) {
-		status = nfsd4_decode_stateid(argp, &si);
+		stateid = kmalloc(sizeof(struct nfsd4_test_stateid_id), GFP_KERNEL);
+		if (!stateid) {
+			status = PTR_ERR(stateid);
+			goto out;
+		}
+
+		defer_free(argp, kfree, stateid);
+		INIT_LIST_HEAD(&stateid->ts_id_list);
+		list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list);
+
+		status = nfsd4_decode_stateid(argp, &stateid->ts_id_stateid);
 		if (status)
-			return status;
+			goto out;
 	}
 
 	status = 0;
@@ -2661,8 +2659,8 @@
 	__be32 *p;
 
 	if (!nfserr) {
-		RESERVE_SPACE(8);
-		WRITEMEM(commit->co_verf.data, 8);
+		RESERVE_SPACE(NFS4_VERIFIER_SIZE);
+		WRITEMEM(commit->co_verf.data, NFS4_VERIFIER_SIZE);
 		ADJUST_ARGS();
 	}
 	return nfserr;
@@ -2851,6 +2849,20 @@
 		WRITE32(0);   /* XXX: is NULL principal ok? */
 		ADJUST_ARGS();
 		break;
+	case NFS4_OPEN_DELEGATE_NONE_EXT: /* 4.1 */
+		switch (open->op_why_no_deleg) {
+		case WND4_CONTENTION:
+		case WND4_RESOURCE:
+			RESERVE_SPACE(8);
+			WRITE32(open->op_why_no_deleg);
+			WRITE32(0);	/* deleg signaling not supported yet */
+			break;
+		default:
+			RESERVE_SPACE(4);
+			WRITE32(open->op_why_no_deleg);
+		}
+		ADJUST_ARGS();
+		break;
 	default:
 		BUG();
 	}
@@ -3008,7 +3020,7 @@
 	if (resp->xbuf->page_len)
 		return nfserr_resource;
 
-	RESERVE_SPACE(8);  /* verifier */
+	RESERVE_SPACE(NFS4_VERIFIER_SIZE);
 	savep = p;
 
 	/* XXX: Following NFSv3, we ignore the READDIR verifier for now. */
@@ -3209,9 +3221,9 @@
 	__be32 *p;
 
 	if (!nfserr) {
-		RESERVE_SPACE(8 + sizeof(nfs4_verifier));
+		RESERVE_SPACE(8 + NFS4_VERIFIER_SIZE);
 		WRITEMEM(&scd->se_clientid, 8);
-		WRITEMEM(&scd->se_confirm, sizeof(nfs4_verifier));
+		WRITEMEM(&scd->se_confirm, NFS4_VERIFIER_SIZE);
 		ADJUST_ARGS();
 	}
 	else if (nfserr == nfserr_clid_inuse) {
@@ -3232,7 +3244,7 @@
 		RESERVE_SPACE(16);
 		WRITE32(write->wr_bytes_written);
 		WRITE32(write->wr_how_written);
-		WRITEMEM(write->wr_verifier.data, 8);
+		WRITEMEM(write->wr_verifier.data, NFS4_VERIFIER_SIZE);
 		ADJUST_ARGS();
 	}
 	return nfserr;
@@ -3391,30 +3403,17 @@
 nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr,
 			  struct nfsd4_test_stateid *test_stateid)
 {
-	struct nfsd4_compoundargs *argp;
-	struct nfs4_client *cl = resp->cstate.session->se_client;
-	stateid_t si;
+	struct nfsd4_test_stateid_id *stateid, *next;
 	__be32 *p;
-	int i;
-	int valid;
 
-	restore_buf(test_stateid->ts_saved_args, &test_stateid->ts_savedp);
-	argp = test_stateid->ts_saved_args;
-
-	RESERVE_SPACE(4);
+	RESERVE_SPACE(4 + (4 * test_stateid->ts_num_ids));
 	*p++ = htonl(test_stateid->ts_num_ids);
-	resp->p = p;
 
-	nfs4_lock_state();
-	for (i = 0; i < test_stateid->ts_num_ids; i++) {
-		nfsd4_decode_stateid(argp, &si);
-		valid = nfs4_validate_stateid(cl, &si);
-		RESERVE_SPACE(4);
-		*p++ = htonl(valid);
-		resp->p = p;
+	list_for_each_entry_safe(stateid, next, &test_stateid->ts_stateid_list, ts_id_list) {
+		*p++ = htonl(stateid->ts_id_status);
 	}
-	nfs4_unlock_state();
 
+	ADJUST_ARGS();
 	return nfserr;
 }
 
@@ -3532,7 +3531,7 @@
 	if (length > session->se_fchannel.maxresp_sz)
 		return nfserr_rep_too_big;
 
-	if (slot->sl_cachethis == 1 &&
+	if ((slot->sl_flags & NFSD4_SLOT_CACHETHIS) &&
 	    length > session->se_fchannel.maxresp_cached)
 		return nfserr_rep_too_big_to_cache;
 
@@ -3656,8 +3655,7 @@
 	if (nfsd4_has_session(cs)) {
 		if (cs->status != nfserr_replay_cache) {
 			nfsd4_store_cache_entry(resp);
-			dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__);
-			cs->slot->sl_inuse = false;
+			cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE;
 		}
 		/* Renew the clientid on success and on replay */
 		release_session_client(cs->session);
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 748eda9..2c53be6 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -13,12 +13,14 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/gss_api.h>
 #include <linux/sunrpc/gss_krb5_enctypes.h>
+#include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/module.h>
 
 #include "idmap.h"
 #include "nfsd.h"
 #include "cache.h"
 #include "fault_inject.h"
+#include "netns.h"
 
 /*
  *	We have a single directory with several nodes in it.
@@ -223,7 +225,7 @@
 	if (qword_get(&buf, fo_path, size) < 0)
 		return -EINVAL;
 
-	if (rpc_pton(fo_path, size, sap, salen) == 0)
+	if (rpc_pton(&init_net, fo_path, size, sap, salen) == 0)
 		return -EINVAL;
 
 	return nlmsvc_unlock_all_by_ip(sap);
@@ -722,7 +724,7 @@
 	nfsd_serv->sv_nrthreads--;
 	return 0;
 out_close:
-	xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port);
+	xprt = svc_find_xprt(nfsd_serv, transport, &init_net, PF_INET, port);
 	if (xprt != NULL) {
 		svc_close_xprt(xprt);
 		svc_xprt_put(xprt);
@@ -748,7 +750,7 @@
 	if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL)
 		return -EINVAL;
 
-	xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port);
+	xprt = svc_find_xprt(nfsd_serv, transport, &init_net, AF_UNSPEC, port);
 	if (xprt == NULL)
 		return -ENOTCONN;
 
@@ -1124,14 +1126,26 @@
 }
 #endif
 
+int nfsd_net_id;
+static struct pernet_operations nfsd_net_ops = {
+	.id   = &nfsd_net_id,
+	.size = sizeof(struct nfsd_net),
+};
+
 static int __init init_nfsd(void)
 {
 	int retval;
 	printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
 
-	retval = nfsd4_init_slabs();
+	retval = register_cld_notifier();
 	if (retval)
 		return retval;
+	retval = register_pernet_subsys(&nfsd_net_ops);
+	if (retval < 0)
+		goto out_unregister_notifier;
+	retval = nfsd4_init_slabs();
+	if (retval)
+		goto out_unregister_pernet;
 	nfs4_state_init();
 	retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */
 	if (retval)
@@ -1169,6 +1183,10 @@
 	nfsd_fault_inject_cleanup();
 out_free_slabs:
 	nfsd4_free_slabs();
+out_unregister_pernet:
+	unregister_pernet_subsys(&nfsd_net_ops);
+out_unregister_notifier:
+	unregister_cld_notifier();
 	return retval;
 }
 
@@ -1184,6 +1202,8 @@
 	nfsd4_free_slabs();
 	nfsd_fault_inject_cleanup();
 	unregister_filesystem(&nfsd_fs_type);
+	unregister_pernet_subsys(&nfsd_net_ops);
+	unregister_cld_notifier();
 }
 
 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 1d1e858..1671429 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -364,12 +364,17 @@
 	NFSD_WRITEABLE_ATTRS_WORD2
 
 extern int nfsd4_is_junction(struct dentry *dentry);
-#else
+extern int register_cld_notifier(void);
+extern void unregister_cld_notifier(void);
+#else /* CONFIG_NFSD_V4 */
 static inline int nfsd4_is_junction(struct dentry *dentry)
 {
 	return 0;
 }
 
+#define register_cld_notifier() 0
+#define unregister_cld_notifier() do { } while(0)
+
 #endif /* CONFIG_NFSD_V4 */
 
 #endif /* LINUX_NFSD_NFSD_H */
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index eda7d7e..28dfad3 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -251,13 +251,13 @@
 	nfsd_up = false;
 }
 
-static void nfsd_last_thread(struct svc_serv *serv)
+static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
 {
 	/* When last nfsd thread exits we need to do some clean-up */
 	nfsd_serv = NULL;
 	nfsd_shutdown();
 
-	svc_rpcb_cleanup(serv);
+	svc_rpcb_cleanup(serv, net);
 
 	printk(KERN_WARNING "nfsd: last server has exited, flushing export "
 			    "cache\n");
@@ -307,33 +307,37 @@
 	dprintk("%s nfsd_drc_max_mem %u \n", __func__, nfsd_drc_max_mem);
 }
 
+static int nfsd_get_default_max_blksize(void)
+{
+	struct sysinfo i;
+	unsigned long long target;
+	unsigned long ret;
+
+	si_meminfo(&i);
+	target = (i.totalram - i.totalhigh) << PAGE_SHIFT;
+	/*
+	 * Aim for 1/4096 of memory per thread This gives 1MB on 4Gig
+	 * machines, but only uses 32K on 128M machines.  Bottom out at
+	 * 8K on 32M and smaller.  Of course, this is only a default.
+	 */
+	target >>= 12;
+
+	ret = NFSSVC_MAXBLKSIZE;
+	while (ret > target && ret >= 8*1024*2)
+		ret /= 2;
+	return ret;
+}
+
 int nfsd_create_serv(void)
 {
-	int err = 0;
-
 	WARN_ON(!mutex_is_locked(&nfsd_mutex));
 	if (nfsd_serv) {
 		svc_get(nfsd_serv);
 		return 0;
 	}
-	if (nfsd_max_blksize == 0) {
-		/* choose a suitable default */
-		struct sysinfo i;
-		si_meminfo(&i);
-		/* Aim for 1/4096 of memory per thread
-		 * This gives 1MB on 4Gig machines
-		 * But only uses 32K on 128M machines.
-		 * Bottom out at 8K on 32M and smaller.
-		 * Of course, this is only a default.
-		 */
-		nfsd_max_blksize = NFSSVC_MAXBLKSIZE;
-		i.totalram <<= PAGE_SHIFT - 12;
-		while (nfsd_max_blksize > i.totalram &&
-		       nfsd_max_blksize >= 8*1024*2)
-			nfsd_max_blksize /= 2;
-	}
+	if (nfsd_max_blksize == 0)
+		nfsd_max_blksize = nfsd_get_default_max_blksize();
 	nfsd_reset_versions();
-
 	nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
 				      nfsd_last_thread, nfsd, THIS_MODULE);
 	if (nfsd_serv == NULL)
@@ -341,7 +345,7 @@
 
 	set_max_drc();
 	do_gettimeofday(&nfssvc_boot);		/* record boot time */
-	return err;
+	return 0;
 }
 
 int nfsd_nrpools(void)
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index ffb5df1..89ab137 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -128,12 +128,14 @@
 		(NFSD_CACHE_SIZE_SLOTS_PER_SESSION * NFSD_SLOT_CACHE_SIZE)
 
 struct nfsd4_slot {
-	bool	sl_inuse;
-	bool	sl_cachethis;
-	u16	sl_opcnt;
 	u32	sl_seqid;
 	__be32	sl_status;
 	u32	sl_datalen;
+	u16	sl_opcnt;
+#define NFSD4_SLOT_INUSE	(1 << 0)
+#define NFSD4_SLOT_CACHETHIS	(1 << 1)
+#define NFSD4_SLOT_INITIALIZED	(1 << 2)
+	u8	sl_flags;
 	char	sl_data[];
 };
 
@@ -196,18 +198,7 @@
 	struct nfsd4_slot	*se_slots[];	/* forward channel slots */
 };
 
-static inline void
-nfsd4_put_session(struct nfsd4_session *ses)
-{
-	extern void free_session(struct kref *kref);
-	kref_put(&ses->se_ref, free_session);
-}
-
-static inline void
-nfsd4_get_session(struct nfsd4_session *ses)
-{
-	kref_get(&ses->se_ref);
-}
+extern void nfsd4_put_session(struct nfsd4_session *ses);
 
 /* formatted contents of nfs4_sessionid */
 struct nfsd4_sessionid {
@@ -245,14 +236,17 @@
 	struct svc_cred		cl_cred; 	/* setclientid principal */
 	clientid_t		cl_clientid;	/* generated by server */
 	nfs4_verifier		cl_confirm;	/* generated by server */
-	u32			cl_firststate;	/* recovery dir creation */
 	u32			cl_minorversion;
 
 	/* for v4.0 and v4.1 callbacks: */
 	struct nfs4_cb_conn	cl_cb_conn;
-#define NFSD4_CLIENT_CB_UPDATE	1
-#define NFSD4_CLIENT_KILL	2
-	unsigned long		cl_cb_flags;
+#define NFSD4_CLIENT_CB_UPDATE		(0)
+#define NFSD4_CLIENT_CB_KILL		(1)
+#define NFSD4_CLIENT_STABLE		(2)	/* client on stable storage */
+#define NFSD4_CLIENT_RECLAIM_COMPLETE	(3)	/* reclaim_complete done */
+#define NFSD4_CLIENT_CB_FLAG_MASK	(1 << NFSD4_CLIENT_CB_UPDATE | \
+					 1 << NFSD4_CLIENT_CB_KILL)
+	unsigned long		cl_flags;
 	struct rpc_clnt		*cl_cb_client;
 	u32			cl_cb_ident;
 #define NFSD4_CB_UP		0
@@ -463,6 +457,8 @@
 extern void nfs4_lock_state(void);
 extern void nfs4_unlock_state(void);
 extern int nfs4_in_grace(void);
+extern void nfs4_release_reclaim(void);
+extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct nfs4_client *crp);
 extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
 extern void nfs4_free_openowner(struct nfs4_openowner *);
 extern void nfs4_free_lockowner(struct nfs4_lockowner *);
@@ -477,16 +473,17 @@
 extern void nfsd4_shutdown_callback(struct nfs4_client *);
 extern void nfs4_put_delegation(struct nfs4_delegation *dp);
 extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
-extern void nfsd4_init_recdir(void);
-extern int nfsd4_recdir_load(void);
-extern void nfsd4_shutdown_recdir(void);
 extern int nfs4_client_to_reclaim(const char *name);
 extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id);
-extern void nfsd4_recdir_purge_old(void);
-extern void nfsd4_create_clid_dir(struct nfs4_client *clp);
-extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
 extern void release_session_client(struct nfsd4_session *);
 extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *);
 extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
 
+/* nfs4recover operations */
+extern int nfsd4_client_tracking_init(struct net *net);
+extern void nfsd4_client_tracking_exit(struct net *net);
+extern void nfsd4_client_record_create(struct nfs4_client *clp);
+extern void nfsd4_client_record_remove(struct nfs4_client *clp);
+extern int nfsd4_client_record_check(struct nfs4_client *clp);
+extern void nfsd4_record_grace_done(struct net *net, time_t boot_time);
 #endif   /* NFSD4_STATE_H */
diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c
index a2e2402..6d4521f 100644
--- a/fs/nfsd/stats.c
+++ b/fs/nfsd/stats.c
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/sunrpc/stats.h>
 #include <linux/nfsd/stats.h>
+#include <net/net_namespace.h>
 
 #include "nfsd.h"
 
@@ -94,11 +95,11 @@
 void
 nfsd_stat_init(void)
 {
-	svc_proc_register(&nfsd_svcstats, &nfsd_proc_fops);
+	svc_proc_register(&init_net, &nfsd_svcstats, &nfsd_proc_fops);
 }
 
 void
 nfsd_stat_shutdown(void)
 {
-	svc_proc_unregister("nfsd");
+	svc_proc_unregister(&init_net, "nfsd");
 }
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index edf6d3e..296d671 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -737,12 +737,13 @@
 
 /*
  * Open an existing file or directory.
- * The access argument indicates the type of open (read/write/lock)
+ * The may_flags argument indicates the type of open (read/write/lock)
+ * and additional flags.
  * N.B. After this call fhp needs an fh_put
  */
 __be32
 nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
-			int access, struct file **filp)
+			int may_flags, struct file **filp)
 {
 	struct dentry	*dentry;
 	struct inode	*inode;
@@ -757,7 +758,7 @@
 	 * and (hopefully) checked permission - so allow OWNER_OVERRIDE
 	 * in case a chmod has now revoked permission.
 	 */
-	err = fh_verify(rqstp, fhp, type, access | NFSD_MAY_OWNER_OVERRIDE);
+	err = fh_verify(rqstp, fhp, type, may_flags | NFSD_MAY_OWNER_OVERRIDE);
 	if (err)
 		goto out;
 
@@ -768,7 +769,7 @@
 	 * or any access when mandatory locking enabled
 	 */
 	err = nfserr_perm;
-	if (IS_APPEND(inode) && (access & NFSD_MAY_WRITE))
+	if (IS_APPEND(inode) && (may_flags & NFSD_MAY_WRITE))
 		goto out;
 	/*
 	 * We must ignore files (but only files) which might have mandatory
@@ -781,12 +782,12 @@
 	if (!inode->i_fop)
 		goto out;
 
-	host_err = nfsd_open_break_lease(inode, access);
+	host_err = nfsd_open_break_lease(inode, may_flags);
 	if (host_err) /* NOMEM or WOULDBLOCK */
 		goto out_nfserr;
 
-	if (access & NFSD_MAY_WRITE) {
-		if (access & NFSD_MAY_READ)
+	if (may_flags & NFSD_MAY_WRITE) {
+		if (may_flags & NFSD_MAY_READ)
 			flags = O_RDWR|O_LARGEFILE;
 		else
 			flags = O_WRONLY|O_LARGEFILE;
@@ -795,8 +796,15 @@
 			    flags, current_cred());
 	if (IS_ERR(*filp))
 		host_err = PTR_ERR(*filp);
-	else
-		host_err = ima_file_check(*filp, access);
+	else {
+		host_err = ima_file_check(*filp, may_flags);
+
+		if (may_flags & NFSD_MAY_64BIT_COOKIE)
+			(*filp)->f_mode |= FMODE_64BITHASH;
+		else
+			(*filp)->f_mode |= FMODE_32BITHASH;
+	}
+
 out_nfserr:
 	err = nfserrno(host_err);
 out:
@@ -1541,30 +1549,31 @@
 __be32
 nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
 {
-	struct dentry	*dentry;
 	struct inode	*inode;
 	mm_segment_t	oldfs;
 	__be32		err;
 	int		host_err;
+	struct path path;
 
 	err = fh_verify(rqstp, fhp, S_IFLNK, NFSD_MAY_NOP);
 	if (err)
 		goto out;
 
-	dentry = fhp->fh_dentry;
-	inode = dentry->d_inode;
+	path.mnt = fhp->fh_export->ex_path.mnt;
+	path.dentry = fhp->fh_dentry;
+	inode = path.dentry->d_inode;
 
 	err = nfserr_inval;
 	if (!inode->i_op->readlink)
 		goto out;
 
-	touch_atime(fhp->fh_export->ex_path.mnt, dentry);
+	touch_atime(&path);
 	/* N.B. Why does this call need a get_fs()??
 	 * Remove the set_fs and watch the fireworks:-) --okir
 	 */
 
 	oldfs = get_fs(); set_fs(KERNEL_DS);
-	host_err = inode->i_op->readlink(dentry, buf, *lenp);
+	host_err = inode->i_op->readlink(path.dentry, buf, *lenp);
 	set_fs(oldfs);
 
 	if (host_err < 0)
@@ -2020,8 +2029,13 @@
 	__be32		err;
 	struct file	*file;
 	loff_t		offset = *offsetp;
+	int             may_flags = NFSD_MAY_READ;
 
-	err = nfsd_open(rqstp, fhp, S_IFDIR, NFSD_MAY_READ, &file);
+	/* NFSv2 only supports 32 bit cookies */
+	if (rqstp->rq_vers > 2)
+		may_flags |= NFSD_MAY_64BIT_COOKIE;
+
+	err = nfsd_open(rqstp, fhp, S_IFDIR, may_flags, &file);
 	if (err)
 		goto out;
 
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index 1dcd238..ec0611b 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -27,6 +27,8 @@
 #define NFSD_MAY_BYPASS_GSS		0x400
 #define NFSD_MAY_READ_IF_EXEC		0x800
 
+#define NFSD_MAY_64BIT_COOKIE		0x1000 /* 64 bit readdir cookies for >= NFSv3 */
+
 #define NFSD_MAY_CREATE		(NFSD_MAY_EXEC|NFSD_MAY_WRITE)
 #define NFSD_MAY_REMOVE		(NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC)
 
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 2364747..1b35015 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -43,6 +43,13 @@
 #define NFSD4_MAX_TAGLEN	128
 #define XDR_LEN(n)                     (((n) + 3) & ~3)
 
+#define CURRENT_STATE_ID_FLAG (1<<0)
+#define SAVED_STATE_ID_FLAG (1<<1)
+
+#define SET_STATE_ID(c, f) ((c)->sid_flags |= (f))
+#define HAS_STATE_ID(c, f) ((c)->sid_flags & (f))
+#define CLEAR_STATE_ID(c, f) ((c)->sid_flags &= ~(f))
+
 struct nfsd4_compound_state {
 	struct svc_fh		current_fh;
 	struct svc_fh		save_fh;
@@ -54,6 +61,10 @@
 	size_t			iovlen;
 	u32			minorversion;
 	u32			status;
+	stateid_t	current_stateid;
+	stateid_t	save_stateid;
+	/* to indicate current and saved state id presents */
+	u32		sid_flags;
 };
 
 static inline bool nfsd4_has_session(struct nfsd4_compound_state *cs)
@@ -212,16 +223,19 @@
 	struct xdr_netobj op_fname;	    /* request - everything but CLAIM_PREV */
 	u32		op_delegate_type;   /* request - CLAIM_PREV only */
 	stateid_t       op_delegate_stateid; /* request - response */
+	u32		op_why_no_deleg;    /* response - DELEG_NONE_EXT only */
 	u32		op_create;     	    /* request */
 	u32		op_createmode;      /* request */
 	u32		op_bmval[3];        /* request */
 	struct iattr	iattr;              /* UNCHECKED4, GUARDED4, EXCLUSIVE4_1 */
-	nfs4_verifier	verf;               /* EXCLUSIVE4 */
+	nfs4_verifier	op_verf __attribute__((aligned(32)));
+					    /* EXCLUSIVE4 */
 	clientid_t	op_clientid;        /* request */
 	struct xdr_netobj op_owner;           /* request */
 	u32		op_seqid;           /* request */
 	u32		op_share_access;    /* request */
 	u32		op_share_deny;      /* request */
+	u32		op_deleg_want;      /* request */
 	stateid_t	op_stateid;         /* response */
 	u32		op_recall;          /* recall */
 	struct nfsd4_change_info  op_cinfo; /* response */
@@ -234,7 +248,6 @@
 	struct nfs4_acl *op_acl;
 };
 #define op_iattr	iattr
-#define op_verf		verf
 
 struct nfsd4_open_confirm {
 	stateid_t	oc_req_stateid		/* request */;
@@ -245,8 +258,9 @@
 struct nfsd4_open_downgrade {
 	stateid_t       od_stateid;
 	u32             od_seqid;
-	u32             od_share_access;
-	u32             od_share_deny;
+	u32             od_share_access;	/* request */
+	u32		od_deleg_want;		/* request */
+	u32             od_share_deny;		/* request */
 };
 
 
@@ -343,10 +357,15 @@
 	struct page **pagelist;
 };
 
+struct nfsd4_test_stateid_id {
+	__be32			ts_id_status;
+	stateid_t		ts_id_stateid;
+	struct list_head	ts_id_list;
+};
+
 struct nfsd4_test_stateid {
 	__be32		ts_num_ids;
-	struct nfsd4_compoundargs *ts_saved_args;
-	struct nfsd4_saved_compoundargs ts_savedp;
+	struct list_head ts_stateid_list;
 };
 
 struct nfsd4_free_stateid {
@@ -503,7 +522,8 @@
 
 static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp)
 {
-	return !resp->cstate.slot->sl_cachethis || nfsd4_is_solo_sequence(resp);
+	return !(resp->cstate.slot->sl_flags & NFSD4_SLOT_CACHETHIS)
+		|| nfsd4_is_solo_sequence(resp);
 }
 
 #define NFS4_SVC_XDRSIZE		sizeof(struct nfsd4_compoundargs)
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
index 1cd3f62..fce2bbe 100644
--- a/fs/nilfs2/namei.c
+++ b/fs/nilfs2/namei.c
@@ -193,9 +193,6 @@
 	struct nilfs_transaction_info ti;
 	int err;
 
-	if (inode->i_nlink >= NILFS_LINK_MAX)
-		return -EMLINK;
-
 	err = nilfs_transaction_begin(dir->i_sb, &ti, 1);
 	if (err)
 		return err;
@@ -219,9 +216,6 @@
 	struct nilfs_transaction_info ti;
 	int err;
 
-	if (dir->i_nlink >= NILFS_LINK_MAX)
-		return -EMLINK;
-
 	err = nilfs_transaction_begin(dir->i_sb, &ti, 1);
 	if (err)
 		return err;
@@ -400,11 +394,6 @@
 		drop_nlink(new_inode);
 		nilfs_mark_inode_dirty(new_inode);
 	} else {
-		if (dir_de) {
-			err = -EMLINK;
-			if (new_dir->i_nlink >= NILFS_LINK_MAX)
-				goto out_dir;
-		}
 		err = nilfs_add_link(new_dentry, old_inode);
 		if (err)
 			goto out_dir;
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index 08e3d4f..1099a76 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -917,9 +917,8 @@
 	if (root->cno == NILFS_CPTREE_CURRENT_CNO) {
 		dentry = d_find_alias(inode);
 		if (!dentry) {
-			dentry = d_alloc_root(inode);
+			dentry = d_make_root(inode);
 			if (!dentry) {
-				iput(inode);
 				ret = -ENOMEM;
 				goto failed_dentry;
 			}
@@ -1059,6 +1058,7 @@
 	sb->s_export_op = &nilfs_export_ops;
 	sb->s_root = NULL;
 	sb->s_time_gran = 1;
+	sb->s_max_links = NILFS_LINK_MAX;
 
 	bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
 	sb->s_bdi = bdi ? : &default_backing_dev_info;
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index ee18815..c887b13 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -447,7 +447,7 @@
 	return event;
 }
 
-__init int fsnotify_notification_init(void)
+static __init int fsnotify_notification_init(void)
 {
 	fsnotify_event_cachep = KMEM_CACHE(fsnotify_event, SLAB_PANIC);
 	fsnotify_event_holder_cachep = KMEM_CACHE(fsnotify_event_holder, SLAB_PANIC);
@@ -461,4 +461,3 @@
 	return 0;
 }
 subsys_initcall(fsnotify_notification_init);
-
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 28d4e6a..b341492 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -2908,9 +2908,10 @@
 		ntfs_error(sb, "Failed to load system files.");
 		goto unl_upcase_iput_tmp_ino_err_out_now;
 	}
-	if ((sb->s_root = d_alloc_root(vol->root_ino))) {
-		/* We grab a reference, simulating an ntfs_iget(). */
-		ihold(vol->root_ino);
+
+	/* We grab a reference, simulating an ntfs_iget(). */
+	ihold(vol->root_ino);
+	if ((sb->s_root = d_make_root(vol->root_ino))) {
 		ntfs_debug("Exiting, status successful.");
 		/* Release the default upcase if it has no users. */
 		mutex_lock(&ntfs_lock);
@@ -3158,6 +3159,8 @@
 	}
 	printk(KERN_CRIT "NTFS: Failed to register NTFS filesystem driver!\n");
 
+	/* Unregister the ntfs sysctls. */
+	ntfs_sysctl(0);
 sysctl_err_out:
 	kmem_cache_destroy(ntfs_big_inode_cache);
 big_inode_err_out:
diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c
index abfac0d..3b5825e 100644
--- a/fs/ocfs2/dlmfs/dlmfs.c
+++ b/fs/ocfs2/dlmfs/dlmfs.c
@@ -582,24 +582,14 @@
 			    void * data,
 			    int silent)
 {
-	struct inode * inode;
-	struct dentry * root;
-
 	sb->s_maxbytes = MAX_LFS_FILESIZE;
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
 	sb->s_magic = DLMFS_MAGIC;
 	sb->s_op = &dlmfs_ops;
-	inode = dlmfs_get_root_inode(sb);
-	if (!inode)
+	sb->s_root = d_make_root(dlmfs_get_root_inode(sb));
+	if (!sb->s_root)
 		return -ENOMEM;
-
-	root = d_alloc_root(inode);
-	if (!root) {
-		iput(inode);
-		return -ENOMEM;
-	}
-	sb->s_root = root;
 	return 0;
 }
 
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
index a6fda3c..a1a1bfd 100644
--- a/fs/ocfs2/ioctl.c
+++ b/fs/ocfs2/ioctl.c
@@ -28,8 +28,6 @@
 #include "suballoc.h"
 #include "move_extents.h"
 
-#include <linux/ext2_fs.h>
-
 #define o2info_from_user(a, b)	\
 		copy_from_user(&(a), (b), sizeof(a))
 #define o2info_to_user(a, b)	\
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 604e12c..68f4541 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -1154,19 +1154,19 @@
 	}
 
 	status = ocfs2_mount_volume(sb);
-	if (osb->root_inode)
-		inode = igrab(osb->root_inode);
-
 	if (status < 0)
 		goto read_super_error;
 
+	if (osb->root_inode)
+		inode = igrab(osb->root_inode);
+
 	if (!inode) {
 		status = -EIO;
 		mlog_errno(status);
 		goto read_super_error;
 	}
 
-	root = d_alloc_root(inode);
+	root = d_make_root(inode);
 	if (!root) {
 		status = -ENOMEM;
 		mlog_errno(status);
@@ -1220,9 +1220,6 @@
 read_super_error:
 	brelse(bh);
 
-	if (inode)
-		iput(inode);
-
 	if (osb) {
 		atomic_set(&osb->vol_state, VOLUME_DISABLED);
 		wake_up(&osb->osb_mount_event);
@@ -1627,21 +1624,17 @@
 		init_waitqueue_head(&ocfs2__ioend_wq[i]);
 
 	status = init_ocfs2_uptodate_cache();
-	if (status < 0) {
-		mlog_errno(status);
-		goto leave;
-	}
+	if (status < 0)
+		goto out1;
 
 	status = ocfs2_initialize_mem_caches();
-	if (status < 0) {
-		mlog_errno(status);
-		goto leave;
-	}
+	if (status < 0)
+		goto out2;
 
 	ocfs2_wq = create_singlethread_workqueue("ocfs2_wq");
 	if (!ocfs2_wq) {
 		status = -ENOMEM;
-		goto leave;
+		goto out3;
 	}
 
 	ocfs2_debugfs_root = debugfs_create_dir("ocfs2", NULL);
@@ -1653,17 +1646,23 @@
 	ocfs2_set_locking_protocol();
 
 	status = register_quota_format(&ocfs2_quota_format);
-leave:
-	if (status < 0) {
-		ocfs2_free_mem_caches();
-		exit_ocfs2_uptodate_cache();
-		mlog_errno(status);
-	}
+	if (status < 0)
+		goto out4;
+	status = register_filesystem(&ocfs2_fs_type);
+	if (!status)
+		return 0;
 
-	if (status >= 0) {
-		return register_filesystem(&ocfs2_fs_type);
-	} else
-		return -1;
+	unregister_quota_format(&ocfs2_quota_format);
+out4:
+	destroy_workqueue(ocfs2_wq);
+	debugfs_remove(ocfs2_debugfs_root);
+out3:
+	ocfs2_free_mem_caches();
+out2:
+	exit_ocfs2_uptodate_cache();
+out1:
+	mlog_errno(status);
+	return status;
 }
 
 static void __exit ocfs2_exit(void)
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
index 6065bb0..dbc8422 100644
--- a/fs/omfs/inode.c
+++ b/fs/omfs/inode.c
@@ -539,11 +539,9 @@
 		goto out_brelse_bh2;
 	}
 
-	sb->s_root = d_alloc_root(root);
-	if (!sb->s_root) {
-		iput(root);
+	sb->s_root = d_make_root(root);
+	if (!sb->s_root)
 		goto out_brelse_bh2;
-	}
 	printk(KERN_DEBUG "omfs: Mounted volume %s\n", omfs_rb->r_name);
 
 	ret = 0;
diff --git a/fs/open.c b/fs/open.c
index 77becc0..5720854 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -836,7 +836,7 @@
 static void __put_unused_fd(struct files_struct *files, unsigned int fd)
 {
 	struct fdtable *fdt = files_fdtable(files);
-	__FD_CLR(fd, fdt->open_fds);
+	__clear_open_fd(fd, fdt);
 	if (fd < files->next_fd)
 		files->next_fd = fd;
 }
@@ -1080,7 +1080,7 @@
 	if (!filp)
 		goto out_unlock;
 	rcu_assign_pointer(fdt->fd[fd], NULL);
-	FD_CLR(fd, fdt->close_on_exec);
+	__clear_close_on_exec(fd, fdt);
 	__put_unused_fd(files, fd);
 	spin_unlock(&files->file_lock);
 	retval = filp_close(filp, files);
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index a88c03b..bc49c975d 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -408,13 +408,12 @@
 	oi->type = op_inode_node;
 	oi->u.node = of_find_node_by_path("/");
 
-	s->s_root = d_alloc_root(root_inode);
+	s->s_root = d_make_root(root_inode);
 	if (!s->s_root)
 		goto out_no_root_dentry;
 	return 0;
 
 out_no_root_dentry:
-	iput(root_inode);
 	ret = -ENOMEM;
 out_no_root:
 	printk("openprom_fill_super: get root inode failed\n");
diff --git a/fs/pipe.c b/fs/pipe.c
index fe0502f..25feaa3 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -13,6 +13,7 @@
 #include <linux/fs.h>
 #include <linux/log2.h>
 #include <linux/mount.h>
+#include <linux/magic.h>
 #include <linux/pipe_fs_i.h>
 #include <linux/uio.h>
 #include <linux/highmem.h>
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index cea4623..5e325a42 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -18,7 +18,7 @@
 #include <linux/fs.h>
 #include <linux/sched.h>
 #include <linux/posix_acl.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 #include <linux/errno.h>
 
diff --git a/fs/proc/array.c b/fs/proc/array.c
index c602b8d..f9bd395 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -462,59 +462,56 @@
 	/* convert nsec -> ticks */
 	start_time = nsec_to_clock_t(start_time);
 
-	seq_printf(m, "%d (%s) %c %d %d %d %d %d %u %lu \
-%lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld %lu %lu %lu\n",
-		pid_nr_ns(pid, ns),
-		tcomm,
-		state,
-		ppid,
-		pgid,
-		sid,
-		tty_nr,
-		tty_pgrp,
-		task->flags,
-		min_flt,
-		cmin_flt,
-		maj_flt,
-		cmaj_flt,
-		cputime_to_clock_t(utime),
-		cputime_to_clock_t(stime),
-		cputime_to_clock_t(cutime),
-		cputime_to_clock_t(cstime),
-		priority,
-		nice,
-		num_threads,
-		start_time,
-		vsize,
-		mm ? get_mm_rss(mm) : 0,
-		rsslim,
-		mm ? (permitted ? mm->start_code : 1) : 0,
-		mm ? (permitted ? mm->end_code : 1) : 0,
-		(permitted && mm) ? mm->start_stack : 0,
-		esp,
-		eip,
-		/* The signal information here is obsolete.
-		 * It must be decimal for Linux 2.0 compatibility.
-		 * Use /proc/#/status for real-time signals.
-		 */
-		task->pending.signal.sig[0] & 0x7fffffffUL,
-		task->blocked.sig[0] & 0x7fffffffUL,
-		sigign      .sig[0] & 0x7fffffffUL,
-		sigcatch    .sig[0] & 0x7fffffffUL,
-		wchan,
-		0UL,
-		0UL,
-		task->exit_signal,
-		task_cpu(task),
-		task->rt_priority,
-		task->policy,
-		(unsigned long long)delayacct_blkio_ticks(task),
-		cputime_to_clock_t(gtime),
-		cputime_to_clock_t(cgtime),
-		(mm && permitted) ? mm->start_data : 0,
-		(mm && permitted) ? mm->end_data : 0,
-		(mm && permitted) ? mm->start_brk : 0);
+	seq_printf(m, "%d (%s) %c", pid_nr_ns(pid, ns), tcomm, state);
+	seq_put_decimal_ll(m, ' ', ppid);
+	seq_put_decimal_ll(m, ' ', pgid);
+	seq_put_decimal_ll(m, ' ', sid);
+	seq_put_decimal_ll(m, ' ', tty_nr);
+	seq_put_decimal_ll(m, ' ', tty_pgrp);
+	seq_put_decimal_ull(m, ' ', task->flags);
+	seq_put_decimal_ull(m, ' ', min_flt);
+	seq_put_decimal_ull(m, ' ', cmin_flt);
+	seq_put_decimal_ull(m, ' ', maj_flt);
+	seq_put_decimal_ull(m, ' ', cmaj_flt);
+	seq_put_decimal_ull(m, ' ', cputime_to_clock_t(utime));
+	seq_put_decimal_ull(m, ' ', cputime_to_clock_t(stime));
+	seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cutime));
+	seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cstime));
+	seq_put_decimal_ll(m, ' ', priority);
+	seq_put_decimal_ll(m, ' ', nice);
+	seq_put_decimal_ll(m, ' ', num_threads);
+	seq_put_decimal_ull(m, ' ', 0);
+	seq_put_decimal_ull(m, ' ', start_time);
+	seq_put_decimal_ull(m, ' ', vsize);
+	seq_put_decimal_ll(m, ' ', mm ? get_mm_rss(mm) : 0);
+	seq_put_decimal_ull(m, ' ', rsslim);
+	seq_put_decimal_ull(m, ' ', mm ? (permitted ? mm->start_code : 1) : 0);
+	seq_put_decimal_ull(m, ' ', mm ? (permitted ? mm->end_code : 1) : 0);
+	seq_put_decimal_ull(m, ' ', (permitted && mm) ? mm->start_stack : 0);
+	seq_put_decimal_ull(m, ' ', esp);
+	seq_put_decimal_ull(m, ' ', eip);
+	/* The signal information here is obsolete.
+	 * It must be decimal for Linux 2.0 compatibility.
+	 * Use /proc/#/status for real-time signals.
+	 */
+	seq_put_decimal_ull(m, ' ', task->pending.signal.sig[0] & 0x7fffffffUL);
+	seq_put_decimal_ull(m, ' ', task->blocked.sig[0] & 0x7fffffffUL);
+	seq_put_decimal_ull(m, ' ', sigign.sig[0] & 0x7fffffffUL);
+	seq_put_decimal_ull(m, ' ', sigcatch.sig[0] & 0x7fffffffUL);
+	seq_put_decimal_ull(m, ' ', wchan);
+	seq_put_decimal_ull(m, ' ', 0);
+	seq_put_decimal_ull(m, ' ', 0);
+	seq_put_decimal_ll(m, ' ', task->exit_signal);
+	seq_put_decimal_ll(m, ' ', task_cpu(task));
+	seq_put_decimal_ull(m, ' ', task->rt_priority);
+	seq_put_decimal_ull(m, ' ', task->policy);
+	seq_put_decimal_ull(m, ' ', delayacct_blkio_ticks(task));
+	seq_put_decimal_ull(m, ' ', cputime_to_clock_t(gtime));
+	seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cgtime));
+	seq_put_decimal_ull(m, ' ', (mm && permitted) ? mm->start_data : 0);
+	seq_put_decimal_ull(m, ' ', (mm && permitted) ? mm->end_data : 0);
+	seq_put_decimal_ull(m, ' ', (mm && permitted) ? mm->start_brk : 0);
+	seq_putc(m, '\n');
 	if (mm)
 		mmput(mm);
 	return 0;
@@ -542,8 +539,20 @@
 		size = task_statm(mm, &shared, &text, &data, &resident);
 		mmput(mm);
 	}
-	seq_printf(m, "%lu %lu %lu %lu 0 %lu 0\n",
-			size, resident, shared, text, data);
+	/*
+	 * For quick read, open code by putting numbers directly
+	 * expected format is
+	 * seq_printf(m, "%lu %lu %lu %lu 0 %lu 0\n",
+	 *               size, resident, shared, text, data);
+	 */
+	seq_put_decimal_ull(m, 0, size);
+	seq_put_decimal_ull(m, ' ', resident);
+	seq_put_decimal_ull(m, ' ', shared);
+	seq_put_decimal_ull(m, ' ', text);
+	seq_put_decimal_ull(m, ' ', 0);
+	seq_put_decimal_ull(m, ' ', data);
+	seq_put_decimal_ull(m, ' ', 0);
+	seq_putc(m, '\n');
 
 	return 0;
 }
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 965d4bd..1c8b280 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1753,7 +1753,7 @@
 
 			fdt = files_fdtable(files);
 			f_flags = file->f_flags & ~O_CLOEXEC;
-			if (FD_ISSET(fd, fdt->close_on_exec))
+			if (close_on_exec(fd, fdt))
 				f_flags |= O_CLOEXEC;
 
 			if (path) {
@@ -2989,9 +2989,9 @@
 	INF("cmdline",    S_IRUGO, proc_pid_cmdline),
 	ONE("stat",       S_IRUGO, proc_tgid_stat),
 	ONE("statm",      S_IRUGO, proc_pid_statm),
-	REG("maps",       S_IRUGO, proc_maps_operations),
+	REG("maps",       S_IRUGO, proc_pid_maps_operations),
 #ifdef CONFIG_NUMA
-	REG("numa_maps",  S_IRUGO, proc_numa_maps_operations),
+	REG("numa_maps",  S_IRUGO, proc_pid_numa_maps_operations),
 #endif
 	REG("mem",        S_IRUSR|S_IWUSR, proc_mem_operations),
 	LNK("cwd",        proc_cwd_link),
@@ -3002,7 +3002,7 @@
 	REG("mountstats", S_IRUSR, proc_mountstats_operations),
 #ifdef CONFIG_PROC_PAGE_MONITOR
 	REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
-	REG("smaps",      S_IRUGO, proc_smaps_operations),
+	REG("smaps",      S_IRUGO, proc_pid_smaps_operations),
 	REG("pagemap",    S_IRUGO, proc_pagemap_operations),
 #endif
 #ifdef CONFIG_SECURITY
@@ -3348,9 +3348,9 @@
 	INF("cmdline",   S_IRUGO, proc_pid_cmdline),
 	ONE("stat",      S_IRUGO, proc_tid_stat),
 	ONE("statm",     S_IRUGO, proc_pid_statm),
-	REG("maps",      S_IRUGO, proc_maps_operations),
+	REG("maps",      S_IRUGO, proc_tid_maps_operations),
 #ifdef CONFIG_NUMA
-	REG("numa_maps", S_IRUGO, proc_numa_maps_operations),
+	REG("numa_maps", S_IRUGO, proc_tid_numa_maps_operations),
 #endif
 	REG("mem",       S_IRUSR|S_IWUSR, proc_mem_operations),
 	LNK("cwd",       proc_cwd_link),
@@ -3360,7 +3360,7 @@
 	REG("mountinfo",  S_IRUGO, proc_mountinfo_operations),
 #ifdef CONFIG_PROC_PAGE_MONITOR
 	REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
-	REG("smaps",     S_IRUGO, proc_smaps_operations),
+	REG("smaps",     S_IRUGO, proc_tid_smaps_operations),
 	REG("pagemap",    S_IRUGO, proc_pagemap_operations),
 #endif
 #ifdef CONFIG_SECURITY
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 84fd323..205c922 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -22,7 +22,6 @@
 #include <linux/slab.h>
 #include <linux/mount.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 #include "internal.h"
@@ -486,8 +485,6 @@
 
 int proc_fill_super(struct super_block *s)
 {
-	struct inode * root_inode;
-
 	s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC;
 	s->s_blocksize = 1024;
 	s->s_blocksize_bits = 10;
@@ -496,19 +493,11 @@
 	s->s_time_gran = 1;
 	
 	pde_get(&proc_root);
-	root_inode = proc_get_inode(s, &proc_root);
-	if (!root_inode)
-		goto out_no_root;
-	root_inode->i_uid = 0;
-	root_inode->i_gid = 0;
-	s->s_root = d_alloc_root(root_inode);
-	if (!s->s_root)
-		goto out_no_root;
-	return 0;
+	s->s_root = d_make_root(proc_get_inode(s, &proc_root));
+	if (s->s_root)
+		return 0;
 
-out_no_root:
 	printk("proc_read_super: get root inode failed\n");
-	iput(root_inode);
 	pde_put(&proc_root);
 	return -ENOMEM;
 }
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 2925775..5f79bb8 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -10,12 +10,15 @@
  */
 
 #include <linux/proc_fs.h>
+struct  ctl_table_header;
 
 extern struct proc_dir_entry proc_root;
 #ifdef CONFIG_PROC_SYSCTL
 extern int proc_sys_init(void);
+extern void sysctl_head_put(struct ctl_table_header *head);
 #else
 static inline void proc_sys_init(void) { }
+static inline void sysctl_head_put(struct ctl_table_header *head) { }
 #endif
 #ifdef CONFIG_NET
 extern int proc_net_init(void);
@@ -53,9 +56,12 @@
 				struct pid *pid, struct task_struct *task);
 extern loff_t mem_lseek(struct file *file, loff_t offset, int orig);
 
-extern const struct file_operations proc_maps_operations;
-extern const struct file_operations proc_numa_maps_operations;
-extern const struct file_operations proc_smaps_operations;
+extern const struct file_operations proc_pid_maps_operations;
+extern const struct file_operations proc_tid_maps_operations;
+extern const struct file_operations proc_pid_numa_maps_operations;
+extern const struct file_operations proc_tid_numa_maps_operations;
+extern const struct file_operations proc_pid_smaps_operations;
+extern const struct file_operations proc_tid_smaps_operations;
 extern const struct file_operations proc_clear_refs_operations;
 extern const struct file_operations proc_pagemap_operations;
 extern const struct file_operations proc_net_operations;
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index e5e69af..86c67ee 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -157,7 +157,8 @@
 
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
 /* calculate vmemmap's address from given system ram pfn and register it */
-int get_sparsemem_vmemmap_info(struct kcore_list *ent, struct list_head *head)
+static int
+get_sparsemem_vmemmap_info(struct kcore_list *ent, struct list_head *head)
 {
 	unsigned long pfn = __pa(ent->addr) >> PAGE_SHIFT;
 	unsigned long nr_pages = ent->size >> PAGE_SHIFT;
@@ -189,7 +190,8 @@
 
 }
 #else
-int get_sparsemem_vmemmap_info(struct kcore_list *ent, struct list_head *head)
+static int
+get_sparsemem_vmemmap_info(struct kcore_list *ent, struct list_head *head)
 {
 	return 1;
 }
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index 27da860..0d9e23a 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -53,7 +53,7 @@
 	ei->ns_ops    = ns_ops;
 	ei->ns	      = ns;
 
-	dentry->d_op = &pid_dentry_operations;
+	d_set_d_op(dentry, &pid_dentry_operations);
 	d_add(dentry, inode);
 	/* Close the race of the process dying before we return the dentry */
 	if (pid_revalidate(dentry, NULL))
@@ -156,15 +156,15 @@
 	if (!ptrace_may_access(task, PTRACE_MODE_READ))
 		goto out;
 
-	last = &ns_entries[ARRAY_SIZE(ns_entries) - 1];
-	for (entry = ns_entries; entry <= last; entry++) {
+	last = &ns_entries[ARRAY_SIZE(ns_entries)];
+	for (entry = ns_entries; entry < last; entry++) {
 		if (strlen((*entry)->name) != len)
 			continue;
 		if (!memcmp(dentry->d_name.name, (*entry)->name, len))
 			break;
 	}
 	error = ERR_PTR(-ENOENT);
-	if (entry > last)
+	if (entry == last)
 		goto out;
 
 	error = proc_ns_instantiate(dir, dentry, task, *entry);
diff --git a/fs/proc/page.c b/fs/proc/page.c
index 6d8e6a9..7fcd0d6 100644
--- a/fs/proc/page.c
+++ b/fs/proc/page.c
@@ -115,6 +115,8 @@
 		u |= 1 << KPF_COMPOUND_TAIL;
 	if (PageHuge(page))
 		u |= 1 << KPF_HUGE;
+	else if (PageTransCompound(page))
+		u |= 1 << KPF_THP;
 
 	/*
 	 * Caveats on high order pages: page->_count will only be set
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 67bbf6e..21d836f 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -9,6 +9,7 @@
 #include <linux/sched.h>
 #include <linux/namei.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 #include "internal.h"
 
 static const struct dentry_operations proc_sys_dentry_operations;
@@ -26,6 +27,371 @@
 	wake_up_interruptible(&poll->wait);
 }
 
+static struct ctl_table root_table[] = {
+	{
+		.procname = "",
+		.mode = S_IFDIR|S_IRUGO|S_IXUGO,
+	},
+	{ }
+};
+static struct ctl_table_root sysctl_table_root = {
+	.default_set.dir.header = {
+		{{.count = 1,
+		  .nreg = 1,
+		  .ctl_table = root_table }},
+		.ctl_table_arg = root_table,
+		.root = &sysctl_table_root,
+		.set = &sysctl_table_root.default_set,
+	},
+};
+
+static DEFINE_SPINLOCK(sysctl_lock);
+
+static void drop_sysctl_table(struct ctl_table_header *header);
+static int sysctl_follow_link(struct ctl_table_header **phead,
+	struct ctl_table **pentry, struct nsproxy *namespaces);
+static int insert_links(struct ctl_table_header *head);
+static void put_links(struct ctl_table_header *header);
+
+static void sysctl_print_dir(struct ctl_dir *dir)
+{
+	if (dir->header.parent)
+		sysctl_print_dir(dir->header.parent);
+	printk(KERN_CONT "%s/", dir->header.ctl_table[0].procname);
+}
+
+static int namecmp(const char *name1, int len1, const char *name2, int len2)
+{
+	int minlen;
+	int cmp;
+
+	minlen = len1;
+	if (minlen > len2)
+		minlen = len2;
+
+	cmp = memcmp(name1, name2, minlen);
+	if (cmp == 0)
+		cmp = len1 - len2;
+	return cmp;
+}
+
+/* Called under sysctl_lock */
+static struct ctl_table *find_entry(struct ctl_table_header **phead,
+	struct ctl_dir *dir, const char *name, int namelen)
+{
+	struct ctl_table_header *head;
+	struct ctl_table *entry;
+	struct rb_node *node = dir->root.rb_node;
+
+	while (node)
+	{
+		struct ctl_node *ctl_node;
+		const char *procname;
+		int cmp;
+
+		ctl_node = rb_entry(node, struct ctl_node, node);
+		head = ctl_node->header;
+		entry = &head->ctl_table[ctl_node - head->node];
+		procname = entry->procname;
+
+		cmp = namecmp(name, namelen, procname, strlen(procname));
+		if (cmp < 0)
+			node = node->rb_left;
+		else if (cmp > 0)
+			node = node->rb_right;
+		else {
+			*phead = head;
+			return entry;
+		}
+	}
+	return NULL;
+}
+
+static int insert_entry(struct ctl_table_header *head, struct ctl_table *entry)
+{
+	struct rb_node *node = &head->node[entry - head->ctl_table].node;
+	struct rb_node **p = &head->parent->root.rb_node;
+	struct rb_node *parent = NULL;
+	const char *name = entry->procname;
+	int namelen = strlen(name);
+
+	while (*p) {
+		struct ctl_table_header *parent_head;
+		struct ctl_table *parent_entry;
+		struct ctl_node *parent_node;
+		const char *parent_name;
+		int cmp;
+
+		parent = *p;
+		parent_node = rb_entry(parent, struct ctl_node, node);
+		parent_head = parent_node->header;
+		parent_entry = &parent_head->ctl_table[parent_node - parent_head->node];
+		parent_name = parent_entry->procname;
+
+		cmp = namecmp(name, namelen, parent_name, strlen(parent_name));
+		if (cmp < 0)
+			p = &(*p)->rb_left;
+		else if (cmp > 0)
+			p = &(*p)->rb_right;
+		else {
+			printk(KERN_ERR "sysctl duplicate entry: ");
+			sysctl_print_dir(head->parent);
+			printk(KERN_CONT "/%s\n", entry->procname);
+			return -EEXIST;
+		}
+	}
+
+	rb_link_node(node, parent, p);
+	return 0;
+}
+
+static void erase_entry(struct ctl_table_header *head, struct ctl_table *entry)
+{
+	struct rb_node *node = &head->node[entry - head->ctl_table].node;
+
+	rb_erase(node, &head->parent->root);
+}
+
+static void init_header(struct ctl_table_header *head,
+	struct ctl_table_root *root, struct ctl_table_set *set,
+	struct ctl_node *node, struct ctl_table *table)
+{
+	head->ctl_table = table;
+	head->ctl_table_arg = table;
+	head->used = 0;
+	head->count = 1;
+	head->nreg = 1;
+	head->unregistering = NULL;
+	head->root = root;
+	head->set = set;
+	head->parent = NULL;
+	head->node = node;
+	if (node) {
+		struct ctl_table *entry;
+		for (entry = table; entry->procname; entry++, node++) {
+			rb_init_node(&node->node);
+			node->header = head;
+		}
+	}
+}
+
+static void erase_header(struct ctl_table_header *head)
+{
+	struct ctl_table *entry;
+	for (entry = head->ctl_table; entry->procname; entry++)
+		erase_entry(head, entry);
+}
+
+static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
+{
+	struct ctl_table *entry;
+	int err;
+
+	dir->header.nreg++;
+	header->parent = dir;
+	err = insert_links(header);
+	if (err)
+		goto fail_links;
+	for (entry = header->ctl_table; entry->procname; entry++) {
+		err = insert_entry(header, entry);
+		if (err)
+			goto fail;
+	}
+	return 0;
+fail:
+	erase_header(header);
+	put_links(header);
+fail_links:
+	header->parent = NULL;
+	drop_sysctl_table(&dir->header);
+	return err;
+}
+
+/* called under sysctl_lock */
+static int use_table(struct ctl_table_header *p)
+{
+	if (unlikely(p->unregistering))
+		return 0;
+	p->used++;
+	return 1;
+}
+
+/* called under sysctl_lock */
+static void unuse_table(struct ctl_table_header *p)
+{
+	if (!--p->used)
+		if (unlikely(p->unregistering))
+			complete(p->unregistering);
+}
+
+/* called under sysctl_lock, will reacquire if has to wait */
+static void start_unregistering(struct ctl_table_header *p)
+{
+	/*
+	 * if p->used is 0, nobody will ever touch that entry again;
+	 * we'll eliminate all paths to it before dropping sysctl_lock
+	 */
+	if (unlikely(p->used)) {
+		struct completion wait;
+		init_completion(&wait);
+		p->unregistering = &wait;
+		spin_unlock(&sysctl_lock);
+		wait_for_completion(&wait);
+		spin_lock(&sysctl_lock);
+	} else {
+		/* anything non-NULL; we'll never dereference it */
+		p->unregistering = ERR_PTR(-EINVAL);
+	}
+	/*
+	 * do not remove from the list until nobody holds it; walking the
+	 * list in do_sysctl() relies on that.
+	 */
+	erase_header(p);
+}
+
+static void sysctl_head_get(struct ctl_table_header *head)
+{
+	spin_lock(&sysctl_lock);
+	head->count++;
+	spin_unlock(&sysctl_lock);
+}
+
+void sysctl_head_put(struct ctl_table_header *head)
+{
+	spin_lock(&sysctl_lock);
+	if (!--head->count)
+		kfree_rcu(head, rcu);
+	spin_unlock(&sysctl_lock);
+}
+
+static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head)
+{
+	if (!head)
+		BUG();
+	spin_lock(&sysctl_lock);
+	if (!use_table(head))
+		head = ERR_PTR(-ENOENT);
+	spin_unlock(&sysctl_lock);
+	return head;
+}
+
+static void sysctl_head_finish(struct ctl_table_header *head)
+{
+	if (!head)
+		return;
+	spin_lock(&sysctl_lock);
+	unuse_table(head);
+	spin_unlock(&sysctl_lock);
+}
+
+static struct ctl_table_set *
+lookup_header_set(struct ctl_table_root *root, struct nsproxy *namespaces)
+{
+	struct ctl_table_set *set = &root->default_set;
+	if (root->lookup)
+		set = root->lookup(root, namespaces);
+	return set;
+}
+
+static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
+				      struct ctl_dir *dir,
+				      const char *name, int namelen)
+{
+	struct ctl_table_header *head;
+	struct ctl_table *entry;
+
+	spin_lock(&sysctl_lock);
+	entry = find_entry(&head, dir, name, namelen);
+	if (entry && use_table(head))
+		*phead = head;
+	else
+		entry = NULL;
+	spin_unlock(&sysctl_lock);
+	return entry;
+}
+
+static struct ctl_node *first_usable_entry(struct rb_node *node)
+{
+	struct ctl_node *ctl_node;
+
+	for (;node; node = rb_next(node)) {
+		ctl_node = rb_entry(node, struct ctl_node, node);
+		if (use_table(ctl_node->header))
+			return ctl_node;
+	}
+	return NULL;
+}
+
+static void first_entry(struct ctl_dir *dir,
+	struct ctl_table_header **phead, struct ctl_table **pentry)
+{
+	struct ctl_table_header *head = NULL;
+	struct ctl_table *entry = NULL;
+	struct ctl_node *ctl_node;
+
+	spin_lock(&sysctl_lock);
+	ctl_node = first_usable_entry(rb_first(&dir->root));
+	spin_unlock(&sysctl_lock);
+	if (ctl_node) {
+		head = ctl_node->header;
+		entry = &head->ctl_table[ctl_node - head->node];
+	}
+	*phead = head;
+	*pentry = entry;
+}
+
+static void next_entry(struct ctl_table_header **phead, struct ctl_table **pentry)
+{
+	struct ctl_table_header *head = *phead;
+	struct ctl_table *entry = *pentry;
+	struct ctl_node *ctl_node = &head->node[entry - head->ctl_table];
+
+	spin_lock(&sysctl_lock);
+	unuse_table(head);
+
+	ctl_node = first_usable_entry(rb_next(&ctl_node->node));
+	spin_unlock(&sysctl_lock);
+	head = NULL;
+	if (ctl_node) {
+		head = ctl_node->header;
+		entry = &head->ctl_table[ctl_node - head->node];
+	}
+	*phead = head;
+	*pentry = entry;
+}
+
+void register_sysctl_root(struct ctl_table_root *root)
+{
+}
+
+/*
+ * sysctl_perm does NOT grant the superuser all rights automatically, because
+ * some sysctl variables are readonly even to root.
+ */
+
+static int test_perm(int mode, int op)
+{
+	if (!current_euid())
+		mode >>= 6;
+	else if (in_egroup_p(0))
+		mode >>= 3;
+	if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0)
+		return 0;
+	return -EACCES;
+}
+
+static int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
+{
+	int mode;
+
+	if (root->permissions)
+		mode = root->permissions(root, current->nsproxy, table);
+	else
+		mode = table->mode;
+
+	return test_perm(mode, op);
+}
+
 static struct inode *proc_sys_make_inode(struct super_block *sb,
 		struct ctl_table_header *head, struct ctl_table *table)
 {
@@ -45,13 +411,12 @@
 
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_mode = table->mode;
-	if (!table->child) {
+	if (!S_ISDIR(table->mode)) {
 		inode->i_mode |= S_IFREG;
 		inode->i_op = &proc_sys_inode_operations;
 		inode->i_fop = &proc_sys_file_operations;
 	} else {
 		inode->i_mode |= S_IFDIR;
-		clear_nlink(inode);
 		inode->i_op = &proc_sys_dir_operations;
 		inode->i_fop = &proc_sys_dir_file_operations;
 	}
@@ -59,70 +424,42 @@
 	return inode;
 }
 
-static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name)
-{
-	int len;
-	for ( ; p->procname; p++) {
-
-		if (!p->procname)
-			continue;
-
-		len = strlen(p->procname);
-		if (len != name->len)
-			continue;
-
-		if (memcmp(p->procname, name->name, len) != 0)
-			continue;
-
-		/* I have a match */
-		return p;
-	}
-	return NULL;
-}
-
 static struct ctl_table_header *grab_header(struct inode *inode)
 {
-	if (PROC_I(inode)->sysctl)
-		return sysctl_head_grab(PROC_I(inode)->sysctl);
-	else
-		return sysctl_head_next(NULL);
+	struct ctl_table_header *head = PROC_I(inode)->sysctl;
+	if (!head)
+		head = &sysctl_table_root.default_set.dir.header;
+	return sysctl_head_grab(head);
 }
 
 static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
 					struct nameidata *nd)
 {
 	struct ctl_table_header *head = grab_header(dir);
-	struct ctl_table *table = PROC_I(dir)->sysctl_entry;
 	struct ctl_table_header *h = NULL;
 	struct qstr *name = &dentry->d_name;
 	struct ctl_table *p;
 	struct inode *inode;
 	struct dentry *err = ERR_PTR(-ENOENT);
+	struct ctl_dir *ctl_dir;
+	int ret;
 
 	if (IS_ERR(head))
 		return ERR_CAST(head);
 
-	if (table && !table->child) {
-		WARN_ON(1);
-		goto out;
-	}
+	ctl_dir = container_of(head, struct ctl_dir, header);
 
-	table = table ? table->child : head->ctl_table;
-
-	p = find_in_table(table, name);
-	if (!p) {
-		for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) {
-			if (h->attached_to != table)
-				continue;
-			p = find_in_table(h->attached_by, name);
-			if (p)
-				break;
-		}
-	}
-
+	p = lookup_entry(&h, ctl_dir, name->name, name->len);
 	if (!p)
 		goto out;
 
+	if (S_ISLNK(p->mode)) {
+		ret = sysctl_follow_link(&h, &p, current->nsproxy);
+		err = ERR_PTR(ret);
+		if (ret)
+			goto out;
+	}
+
 	err = ERR_PTR(-ENOMEM);
 	inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p);
 	if (h)
@@ -190,20 +527,32 @@
 
 static int proc_sys_open(struct inode *inode, struct file *filp)
 {
+	struct ctl_table_header *head = grab_header(inode);
 	struct ctl_table *table = PROC_I(inode)->sysctl_entry;
 
+	/* sysctl was unregistered */
+	if (IS_ERR(head))
+		return PTR_ERR(head);
+
 	if (table->poll)
 		filp->private_data = proc_sys_poll_event(table->poll);
 
+	sysctl_head_finish(head);
+
 	return 0;
 }
 
 static unsigned int proc_sys_poll(struct file *filp, poll_table *wait)
 {
 	struct inode *inode = filp->f_path.dentry->d_inode;
+	struct ctl_table_header *head = grab_header(inode);
 	struct ctl_table *table = PROC_I(inode)->sysctl_entry;
-	unsigned long event = (unsigned long)filp->private_data;
 	unsigned int ret = DEFAULT_POLLMASK;
+	unsigned long event;
+
+	/* sysctl was unregistered */
+	if (IS_ERR(head))
+		return POLLERR | POLLHUP;
 
 	if (!table->proc_handler)
 		goto out;
@@ -211,6 +560,7 @@
 	if (!table->poll)
 		goto out;
 
+	event = (unsigned long)filp->private_data;
 	poll_wait(filp, &table->poll->wait, wait);
 
 	if (event != atomic_read(&table->poll->event)) {
@@ -219,6 +569,8 @@
 	}
 
 out:
+	sysctl_head_finish(head);
+
 	return ret;
 }
 
@@ -260,28 +612,45 @@
 	return !!filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type);
 }
 
+static int proc_sys_link_fill_cache(struct file *filp, void *dirent,
+				    filldir_t filldir,
+				    struct ctl_table_header *head,
+				    struct ctl_table *table)
+{
+	int err, ret = 0;
+	head = sysctl_head_grab(head);
+
+	if (S_ISLNK(table->mode)) {
+		/* It is not an error if we can not follow the link ignore it */
+		err = sysctl_follow_link(&head, &table, current->nsproxy);
+		if (err)
+			goto out;
+	}
+
+	ret = proc_sys_fill_cache(filp, dirent, filldir, head, table);
+out:
+	sysctl_head_finish(head);
+	return ret;
+}
+
 static int scan(struct ctl_table_header *head, ctl_table *table,
 		unsigned long *pos, struct file *file,
 		void *dirent, filldir_t filldir)
 {
+	int res;
 
-	for (; table->procname; table++, (*pos)++) {
-		int res;
+	if ((*pos)++ < file->f_pos)
+		return 0;
 
-		/* Can't do anything without a proc name */
-		if (!table->procname)
-			continue;
-
-		if (*pos < file->f_pos)
-			continue;
-
+	if (unlikely(S_ISLNK(table->mode)))
+		res = proc_sys_link_fill_cache(file, dirent, filldir, head, table);
+	else
 		res = proc_sys_fill_cache(file, dirent, filldir, head, table);
-		if (res)
-			return res;
 
-		file->f_pos = *pos + 1;
-	}
-	return 0;
+	if (res == 0)
+		file->f_pos = *pos;
+
+	return res;
 }
 
 static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
@@ -289,20 +658,16 @@
 	struct dentry *dentry = filp->f_path.dentry;
 	struct inode *inode = dentry->d_inode;
 	struct ctl_table_header *head = grab_header(inode);
-	struct ctl_table *table = PROC_I(inode)->sysctl_entry;
 	struct ctl_table_header *h = NULL;
+	struct ctl_table *entry;
+	struct ctl_dir *ctl_dir;
 	unsigned long pos;
 	int ret = -EINVAL;
 
 	if (IS_ERR(head))
 		return PTR_ERR(head);
 
-	if (table && !table->child) {
-		WARN_ON(1);
-		goto out;
-	}
-
-	table = table ? table->child : head->ctl_table;
+	ctl_dir = container_of(head, struct ctl_dir, header);
 
 	ret = 0;
 	/* Avoid a switch here: arm builds fail with missing __cmpdi2 */
@@ -320,14 +685,8 @@
 	}
 	pos = 2;
 
-	ret = scan(head, table, &pos, filp, dirent, filldir);
-	if (ret)
-		goto out;
-
-	for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) {
-		if (h->attached_to != table)
-			continue;
-		ret = scan(h, h->attached_by, &pos, filp, dirent, filldir);
+	for (first_entry(ctl_dir, &h, &entry); h; next_entry(&h, &entry)) {
+		ret = scan(h, entry, &pos, filp, dirent, filldir);
 		if (ret) {
 			sysctl_head_finish(h);
 			break;
@@ -447,6 +806,21 @@
 	return !!PROC_I(dentry->d_inode)->sysctl->unregistering;
 }
 
+static int sysctl_is_seen(struct ctl_table_header *p)
+{
+	struct ctl_table_set *set = p->set;
+	int res;
+	spin_lock(&sysctl_lock);
+	if (p->unregistering)
+		res = 0;
+	else if (!set->is_seen)
+		res = 1;
+	else
+		res = set->is_seen(set);
+	spin_unlock(&sysctl_lock);
+	return res;
+}
+
 static int proc_sys_compare(const struct dentry *parent,
 		const struct inode *pinode,
 		const struct dentry *dentry, const struct inode *inode,
@@ -472,6 +846,753 @@
 	.d_compare	= proc_sys_compare,
 };
 
+static struct ctl_dir *find_subdir(struct ctl_dir *dir,
+				   const char *name, int namelen)
+{
+	struct ctl_table_header *head;
+	struct ctl_table *entry;
+
+	entry = find_entry(&head, dir, name, namelen);
+	if (!entry)
+		return ERR_PTR(-ENOENT);
+	if (!S_ISDIR(entry->mode))
+		return ERR_PTR(-ENOTDIR);
+	return container_of(head, struct ctl_dir, header);
+}
+
+static struct ctl_dir *new_dir(struct ctl_table_set *set,
+			       const char *name, int namelen)
+{
+	struct ctl_table *table;
+	struct ctl_dir *new;
+	struct ctl_node *node;
+	char *new_name;
+
+	new = kzalloc(sizeof(*new) + sizeof(struct ctl_node) +
+		      sizeof(struct ctl_table)*2 +  namelen + 1,
+		      GFP_KERNEL);
+	if (!new)
+		return NULL;
+
+	node = (struct ctl_node *)(new + 1);
+	table = (struct ctl_table *)(node + 1);
+	new_name = (char *)(table + 2);
+	memcpy(new_name, name, namelen);
+	new_name[namelen] = '\0';
+	table[0].procname = new_name;
+	table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO;
+	init_header(&new->header, set->dir.header.root, set, node, table);
+
+	return new;
+}
+
+/**
+ * get_subdir - find or create a subdir with the specified name.
+ * @dir:  Directory to create the subdirectory in
+ * @name: The name of the subdirectory to find or create
+ * @namelen: The length of name
+ *
+ * Takes a directory with an elevated reference count so we know that
+ * if we drop the lock the directory will not go away.  Upon success
+ * the reference is moved from @dir to the returned subdirectory.
+ * Upon error an error code is returned and the reference on @dir is
+ * simply dropped.
+ */
+static struct ctl_dir *get_subdir(struct ctl_dir *dir,
+				  const char *name, int namelen)
+{
+	struct ctl_table_set *set = dir->header.set;
+	struct ctl_dir *subdir, *new = NULL;
+	int err;
+
+	spin_lock(&sysctl_lock);
+	subdir = find_subdir(dir, name, namelen);
+	if (!IS_ERR(subdir))
+		goto found;
+	if (PTR_ERR(subdir) != -ENOENT)
+		goto failed;
+
+	spin_unlock(&sysctl_lock);
+	new = new_dir(set, name, namelen);
+	spin_lock(&sysctl_lock);
+	subdir = ERR_PTR(-ENOMEM);
+	if (!new)
+		goto failed;
+
+	/* Was the subdir added while we dropped the lock? */
+	subdir = find_subdir(dir, name, namelen);
+	if (!IS_ERR(subdir))
+		goto found;
+	if (PTR_ERR(subdir) != -ENOENT)
+		goto failed;
+
+	/* Nope.  Use the our freshly made directory entry. */
+	err = insert_header(dir, &new->header);
+	subdir = ERR_PTR(err);
+	if (err)
+		goto failed;
+	subdir = new;
+found:
+	subdir->header.nreg++;
+failed:
+	if (unlikely(IS_ERR(subdir))) {
+		printk(KERN_ERR "sysctl could not get directory: ");
+		sysctl_print_dir(dir);
+		printk(KERN_CONT "/%*.*s %ld\n",
+			namelen, namelen, name, PTR_ERR(subdir));
+	}
+	drop_sysctl_table(&dir->header);
+	if (new)
+		drop_sysctl_table(&new->header);
+	spin_unlock(&sysctl_lock);
+	return subdir;
+}
+
+static struct ctl_dir *xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir)
+{
+	struct ctl_dir *parent;
+	const char *procname;
+	if (!dir->header.parent)
+		return &set->dir;
+	parent = xlate_dir(set, dir->header.parent);
+	if (IS_ERR(parent))
+		return parent;
+	procname = dir->header.ctl_table[0].procname;
+	return find_subdir(parent, procname, strlen(procname));
+}
+
+static int sysctl_follow_link(struct ctl_table_header **phead,
+	struct ctl_table **pentry, struct nsproxy *namespaces)
+{
+	struct ctl_table_header *head;
+	struct ctl_table_root *root;
+	struct ctl_table_set *set;
+	struct ctl_table *entry;
+	struct ctl_dir *dir;
+	int ret;
+
+	ret = 0;
+	spin_lock(&sysctl_lock);
+	root = (*pentry)->data;
+	set = lookup_header_set(root, namespaces);
+	dir = xlate_dir(set, (*phead)->parent);
+	if (IS_ERR(dir))
+		ret = PTR_ERR(dir);
+	else {
+		const char *procname = (*pentry)->procname;
+		head = NULL;
+		entry = find_entry(&head, dir, procname, strlen(procname));
+		ret = -ENOENT;
+		if (entry && use_table(head)) {
+			unuse_table(*phead);
+			*phead = head;
+			*pentry = entry;
+			ret = 0;
+		}
+	}
+
+	spin_unlock(&sysctl_lock);
+	return ret;
+}
+
+static int sysctl_err(const char *path, struct ctl_table *table, char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+
+	va_start(args, fmt);
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	printk(KERN_ERR "sysctl table check failed: %s/%s %pV\n",
+		path, table->procname, &vaf);
+
+	va_end(args);
+	return -EINVAL;
+}
+
+static int sysctl_check_table(const char *path, struct ctl_table *table)
+{
+	int err = 0;
+	for (; table->procname; table++) {
+		if (table->child)
+			err = sysctl_err(path, table, "Not a file");
+
+		if ((table->proc_handler == proc_dostring) ||
+		    (table->proc_handler == proc_dointvec) ||
+		    (table->proc_handler == proc_dointvec_minmax) ||
+		    (table->proc_handler == proc_dointvec_jiffies) ||
+		    (table->proc_handler == proc_dointvec_userhz_jiffies) ||
+		    (table->proc_handler == proc_dointvec_ms_jiffies) ||
+		    (table->proc_handler == proc_doulongvec_minmax) ||
+		    (table->proc_handler == proc_doulongvec_ms_jiffies_minmax)) {
+			if (!table->data)
+				err = sysctl_err(path, table, "No data");
+			if (!table->maxlen)
+				err = sysctl_err(path, table, "No maxlen");
+		}
+		if (!table->proc_handler)
+			err = sysctl_err(path, table, "No proc_handler");
+
+		if ((table->mode & (S_IRUGO|S_IWUGO)) != table->mode)
+			err = sysctl_err(path, table, "bogus .mode 0%o",
+				table->mode);
+	}
+	return err;
+}
+
+static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table *table,
+	struct ctl_table_root *link_root)
+{
+	struct ctl_table *link_table, *entry, *link;
+	struct ctl_table_header *links;
+	struct ctl_node *node;
+	char *link_name;
+	int nr_entries, name_bytes;
+
+	name_bytes = 0;
+	nr_entries = 0;
+	for (entry = table; entry->procname; entry++) {
+		nr_entries++;
+		name_bytes += strlen(entry->procname) + 1;
+	}
+
+	links = kzalloc(sizeof(struct ctl_table_header) +
+			sizeof(struct ctl_node)*nr_entries +
+			sizeof(struct ctl_table)*(nr_entries + 1) +
+			name_bytes,
+			GFP_KERNEL);
+
+	if (!links)
+		return NULL;
+
+	node = (struct ctl_node *)(links + 1);
+	link_table = (struct ctl_table *)(node + nr_entries);
+	link_name = (char *)&link_table[nr_entries + 1];
+
+	for (link = link_table, entry = table; entry->procname; link++, entry++) {
+		int len = strlen(entry->procname) + 1;
+		memcpy(link_name, entry->procname, len);
+		link->procname = link_name;
+		link->mode = S_IFLNK|S_IRWXUGO;
+		link->data = link_root;
+		link_name += len;
+	}
+	init_header(links, dir->header.root, dir->header.set, node, link_table);
+	links->nreg = nr_entries;
+
+	return links;
+}
+
+static bool get_links(struct ctl_dir *dir,
+	struct ctl_table *table, struct ctl_table_root *link_root)
+{
+	struct ctl_table_header *head;
+	struct ctl_table *entry, *link;
+
+	/* Are there links available for every entry in table? */
+	for (entry = table; entry->procname; entry++) {
+		const char *procname = entry->procname;
+		link = find_entry(&head, dir, procname, strlen(procname));
+		if (!link)
+			return false;
+		if (S_ISDIR(link->mode) && S_ISDIR(entry->mode))
+			continue;
+		if (S_ISLNK(link->mode) && (link->data == link_root))
+			continue;
+		return false;
+	}
+
+	/* The checks passed.  Increase the registration count on the links */
+	for (entry = table; entry->procname; entry++) {
+		const char *procname = entry->procname;
+		link = find_entry(&head, dir, procname, strlen(procname));
+		head->nreg++;
+	}
+	return true;
+}
+
+static int insert_links(struct ctl_table_header *head)
+{
+	struct ctl_table_set *root_set = &sysctl_table_root.default_set;
+	struct ctl_dir *core_parent = NULL;
+	struct ctl_table_header *links;
+	int err;
+
+	if (head->set == root_set)
+		return 0;
+
+	core_parent = xlate_dir(root_set, head->parent);
+	if (IS_ERR(core_parent))
+		return 0;
+
+	if (get_links(core_parent, head->ctl_table, head->root))
+		return 0;
+
+	core_parent->header.nreg++;
+	spin_unlock(&sysctl_lock);
+
+	links = new_links(core_parent, head->ctl_table, head->root);
+
+	spin_lock(&sysctl_lock);
+	err = -ENOMEM;
+	if (!links)
+		goto out;
+
+	err = 0;
+	if (get_links(core_parent, head->ctl_table, head->root)) {
+		kfree(links);
+		goto out;
+	}
+
+	err = insert_header(core_parent, links);
+	if (err)
+		kfree(links);
+out:
+	drop_sysctl_table(&core_parent->header);
+	return err;
+}
+
+/**
+ * __register_sysctl_table - register a leaf sysctl table
+ * @set: Sysctl tree to register on
+ * @path: The path to the directory the sysctl table is in.
+ * @table: the top-level table structure
+ *
+ * Register a sysctl table hierarchy. @table should be a filled in ctl_table
+ * array. A completely 0 filled entry terminates the table.
+ *
+ * The members of the &struct ctl_table structure are used as follows:
+ *
+ * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
+ *            enter a sysctl file
+ *
+ * data - a pointer to data for use by proc_handler
+ *
+ * maxlen - the maximum size in bytes of the data
+ *
+ * mode - the file permissions for the /proc/sys file
+ *
+ * child - must be %NULL.
+ *
+ * proc_handler - the text handler routine (described below)
+ *
+ * extra1, extra2 - extra pointers usable by the proc handler routines
+ *
+ * Leaf nodes in the sysctl tree will be represented by a single file
+ * under /proc; non-leaf nodes will be represented by directories.
+ *
+ * There must be a proc_handler routine for any terminal nodes.
+ * Several default handlers are available to cover common cases -
+ *
+ * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
+ * proc_dointvec_userhz_jiffies(), proc_dointvec_minmax(),
+ * proc_doulongvec_ms_jiffies_minmax(), proc_doulongvec_minmax()
+ *
+ * It is the handler's job to read the input buffer from user memory
+ * and process it. The handler should return 0 on success.
+ *
+ * This routine returns %NULL on a failure to register, and a pointer
+ * to the table header on success.
+ */
+struct ctl_table_header *__register_sysctl_table(
+	struct ctl_table_set *set,
+	const char *path, struct ctl_table *table)
+{
+	struct ctl_table_root *root = set->dir.header.root;
+	struct ctl_table_header *header;
+	const char *name, *nextname;
+	struct ctl_dir *dir;
+	struct ctl_table *entry;
+	struct ctl_node *node;
+	int nr_entries = 0;
+
+	for (entry = table; entry->procname; entry++)
+		nr_entries++;
+
+	header = kzalloc(sizeof(struct ctl_table_header) +
+			 sizeof(struct ctl_node)*nr_entries, GFP_KERNEL);
+	if (!header)
+		return NULL;
+
+	node = (struct ctl_node *)(header + 1);
+	init_header(header, root, set, node, table);
+	if (sysctl_check_table(path, table))
+		goto fail;
+
+	spin_lock(&sysctl_lock);
+	dir = &set->dir;
+	/* Reference moved down the diretory tree get_subdir */
+	dir->header.nreg++;
+	spin_unlock(&sysctl_lock);
+
+	/* Find the directory for the ctl_table */
+	for (name = path; name; name = nextname) {
+		int namelen;
+		nextname = strchr(name, '/');
+		if (nextname) {
+			namelen = nextname - name;
+			nextname++;
+		} else {
+			namelen = strlen(name);
+		}
+		if (namelen == 0)
+			continue;
+
+		dir = get_subdir(dir, name, namelen);
+		if (IS_ERR(dir))
+			goto fail;
+	}
+
+	spin_lock(&sysctl_lock);
+	if (insert_header(dir, header))
+		goto fail_put_dir_locked;
+
+	drop_sysctl_table(&dir->header);
+	spin_unlock(&sysctl_lock);
+
+	return header;
+
+fail_put_dir_locked:
+	drop_sysctl_table(&dir->header);
+	spin_unlock(&sysctl_lock);
+fail:
+	kfree(header);
+	dump_stack();
+	return NULL;
+}
+
+/**
+ * register_sysctl - register a sysctl table
+ * @path: The path to the directory the sysctl table is in.
+ * @table: the table structure
+ *
+ * Register a sysctl table. @table should be a filled in ctl_table
+ * array. A completely 0 filled entry terminates the table.
+ *
+ * See __register_sysctl_table for more details.
+ */
+struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table)
+{
+	return __register_sysctl_table(&sysctl_table_root.default_set,
+					path, table);
+}
+EXPORT_SYMBOL(register_sysctl);
+
+static char *append_path(const char *path, char *pos, const char *name)
+{
+	int namelen;
+	namelen = strlen(name);
+	if (((pos - path) + namelen + 2) >= PATH_MAX)
+		return NULL;
+	memcpy(pos, name, namelen);
+	pos[namelen] = '/';
+	pos[namelen + 1] = '\0';
+	pos += namelen + 1;
+	return pos;
+}
+
+static int count_subheaders(struct ctl_table *table)
+{
+	int has_files = 0;
+	int nr_subheaders = 0;
+	struct ctl_table *entry;
+
+	/* special case: no directory and empty directory */
+	if (!table || !table->procname)
+		return 1;
+
+	for (entry = table; entry->procname; entry++) {
+		if (entry->child)
+			nr_subheaders += count_subheaders(entry->child);
+		else
+			has_files = 1;
+	}
+	return nr_subheaders + has_files;
+}
+
+static int register_leaf_sysctl_tables(const char *path, char *pos,
+	struct ctl_table_header ***subheader, struct ctl_table_set *set,
+	struct ctl_table *table)
+{
+	struct ctl_table *ctl_table_arg = NULL;
+	struct ctl_table *entry, *files;
+	int nr_files = 0;
+	int nr_dirs = 0;
+	int err = -ENOMEM;
+
+	for (entry = table; entry->procname; entry++) {
+		if (entry->child)
+			nr_dirs++;
+		else
+			nr_files++;
+	}
+
+	files = table;
+	/* If there are mixed files and directories we need a new table */
+	if (nr_dirs && nr_files) {
+		struct ctl_table *new;
+		files = kzalloc(sizeof(struct ctl_table) * (nr_files + 1),
+				GFP_KERNEL);
+		if (!files)
+			goto out;
+
+		ctl_table_arg = files;
+		for (new = files, entry = table; entry->procname; entry++) {
+			if (entry->child)
+				continue;
+			*new = *entry;
+			new++;
+		}
+	}
+
+	/* Register everything except a directory full of subdirectories */
+	if (nr_files || !nr_dirs) {
+		struct ctl_table_header *header;
+		header = __register_sysctl_table(set, path, files);
+		if (!header) {
+			kfree(ctl_table_arg);
+			goto out;
+		}
+
+		/* Remember if we need to free the file table */
+		header->ctl_table_arg = ctl_table_arg;
+		**subheader = header;
+		(*subheader)++;
+	}
+
+	/* Recurse into the subdirectories. */
+	for (entry = table; entry->procname; entry++) {
+		char *child_pos;
+
+		if (!entry->child)
+			continue;
+
+		err = -ENAMETOOLONG;
+		child_pos = append_path(path, pos, entry->procname);
+		if (!child_pos)
+			goto out;
+
+		err = register_leaf_sysctl_tables(path, child_pos, subheader,
+						  set, entry->child);
+		pos[0] = '\0';
+		if (err)
+			goto out;
+	}
+	err = 0;
+out:
+	/* On failure our caller will unregister all registered subheaders */
+	return err;
+}
+
+/**
+ * __register_sysctl_paths - register a sysctl table hierarchy
+ * @set: Sysctl tree to register on
+ * @path: The path to the directory the sysctl table is in.
+ * @table: the top-level table structure
+ *
+ * Register a sysctl table hierarchy. @table should be a filled in ctl_table
+ * array. A completely 0 filled entry terminates the table.
+ *
+ * See __register_sysctl_table for more details.
+ */
+struct ctl_table_header *__register_sysctl_paths(
+	struct ctl_table_set *set,
+	const struct ctl_path *path, struct ctl_table *table)
+{
+	struct ctl_table *ctl_table_arg = table;
+	int nr_subheaders = count_subheaders(table);
+	struct ctl_table_header *header = NULL, **subheaders, **subheader;
+	const struct ctl_path *component;
+	char *new_path, *pos;
+
+	pos = new_path = kmalloc(PATH_MAX, GFP_KERNEL);
+	if (!new_path)
+		return NULL;
+
+	pos[0] = '\0';
+	for (component = path; component->procname; component++) {
+		pos = append_path(new_path, pos, component->procname);
+		if (!pos)
+			goto out;
+	}
+	while (table->procname && table->child && !table[1].procname) {
+		pos = append_path(new_path, pos, table->procname);
+		if (!pos)
+			goto out;
+		table = table->child;
+	}
+	if (nr_subheaders == 1) {
+		header = __register_sysctl_table(set, new_path, table);
+		if (header)
+			header->ctl_table_arg = ctl_table_arg;
+	} else {
+		header = kzalloc(sizeof(*header) +
+				 sizeof(*subheaders)*nr_subheaders, GFP_KERNEL);
+		if (!header)
+			goto out;
+
+		subheaders = (struct ctl_table_header **) (header + 1);
+		subheader = subheaders;
+		header->ctl_table_arg = ctl_table_arg;
+
+		if (register_leaf_sysctl_tables(new_path, pos, &subheader,
+						set, table))
+			goto err_register_leaves;
+	}
+
+out:
+	kfree(new_path);
+	return header;
+
+err_register_leaves:
+	while (subheader > subheaders) {
+		struct ctl_table_header *subh = *(--subheader);
+		struct ctl_table *table = subh->ctl_table_arg;
+		unregister_sysctl_table(subh);
+		kfree(table);
+	}
+	kfree(header);
+	header = NULL;
+	goto out;
+}
+
+/**
+ * register_sysctl_table_path - register a sysctl table hierarchy
+ * @path: The path to the directory the sysctl table is in.
+ * @table: the top-level table structure
+ *
+ * Register a sysctl table hierarchy. @table should be a filled in ctl_table
+ * array. A completely 0 filled entry terminates the table.
+ *
+ * See __register_sysctl_paths for more details.
+ */
+struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
+						struct ctl_table *table)
+{
+	return __register_sysctl_paths(&sysctl_table_root.default_set,
+					path, table);
+}
+EXPORT_SYMBOL(register_sysctl_paths);
+
+/**
+ * register_sysctl_table - register a sysctl table hierarchy
+ * @table: the top-level table structure
+ *
+ * Register a sysctl table hierarchy. @table should be a filled in ctl_table
+ * array. A completely 0 filled entry terminates the table.
+ *
+ * See register_sysctl_paths for more details.
+ */
+struct ctl_table_header *register_sysctl_table(struct ctl_table *table)
+{
+	static const struct ctl_path null_path[] = { {} };
+
+	return register_sysctl_paths(null_path, table);
+}
+EXPORT_SYMBOL(register_sysctl_table);
+
+static void put_links(struct ctl_table_header *header)
+{
+	struct ctl_table_set *root_set = &sysctl_table_root.default_set;
+	struct ctl_table_root *root = header->root;
+	struct ctl_dir *parent = header->parent;
+	struct ctl_dir *core_parent;
+	struct ctl_table *entry;
+
+	if (header->set == root_set)
+		return;
+
+	core_parent = xlate_dir(root_set, parent);
+	if (IS_ERR(core_parent))
+		return;
+
+	for (entry = header->ctl_table; entry->procname; entry++) {
+		struct ctl_table_header *link_head;
+		struct ctl_table *link;
+		const char *name = entry->procname;
+
+		link = find_entry(&link_head, core_parent, name, strlen(name));
+		if (link &&
+		    ((S_ISDIR(link->mode) && S_ISDIR(entry->mode)) ||
+		     (S_ISLNK(link->mode) && (link->data == root)))) {
+			drop_sysctl_table(link_head);
+		}
+		else {
+			printk(KERN_ERR "sysctl link missing during unregister: ");
+			sysctl_print_dir(parent);
+			printk(KERN_CONT "/%s\n", name);
+		}
+	}
+}
+
+static void drop_sysctl_table(struct ctl_table_header *header)
+{
+	struct ctl_dir *parent = header->parent;
+
+	if (--header->nreg)
+		return;
+
+	put_links(header);
+	start_unregistering(header);
+	if (!--header->count)
+		kfree_rcu(header, rcu);
+
+	if (parent)
+		drop_sysctl_table(&parent->header);
+}
+
+/**
+ * unregister_sysctl_table - unregister a sysctl table hierarchy
+ * @header: the header returned from register_sysctl_table
+ *
+ * Unregisters the sysctl table and all children. proc entries may not
+ * actually be removed until they are no longer used by anyone.
+ */
+void unregister_sysctl_table(struct ctl_table_header * header)
+{
+	int nr_subheaders;
+	might_sleep();
+
+	if (header == NULL)
+		return;
+
+	nr_subheaders = count_subheaders(header->ctl_table_arg);
+	if (unlikely(nr_subheaders > 1)) {
+		struct ctl_table_header **subheaders;
+		int i;
+
+		subheaders = (struct ctl_table_header **)(header + 1);
+		for (i = nr_subheaders -1; i >= 0; i--) {
+			struct ctl_table_header *subh = subheaders[i];
+			struct ctl_table *table = subh->ctl_table_arg;
+			unregister_sysctl_table(subh);
+			kfree(table);
+		}
+		kfree(header);
+		return;
+	}
+
+	spin_lock(&sysctl_lock);
+	drop_sysctl_table(header);
+	spin_unlock(&sysctl_lock);
+}
+EXPORT_SYMBOL(unregister_sysctl_table);
+
+void setup_sysctl_set(struct ctl_table_set *set,
+	struct ctl_table_root *root,
+	int (*is_seen)(struct ctl_table_set *))
+{
+	memset(set, 0, sizeof(*set));
+	set->is_seen = is_seen;
+	init_header(&set->dir.header, root, set, NULL, root_table);
+}
+
+void retire_sysctl_set(struct ctl_table_set *set)
+{
+	WARN_ON(!RB_EMPTY_ROOT(&set->dir.root));
+}
+
 int __init proc_sys_init(void)
 {
 	struct proc_dir_entry *proc_sys_root;
@@ -480,5 +1601,6 @@
 	proc_sys_root->proc_iops = &proc_sys_dir_operations;
 	proc_sys_root->proc_fops = &proc_sys_dir_file_operations;
 	proc_sys_root->nlink = 0;
-	return 0;
+
+	return sysctl_init();
 }
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 46a15d8..eed44bf 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -115,12 +115,13 @@
 	if (IS_ERR(sb))
 		return ERR_CAST(sb);
 
+	if (!proc_parse_options(options, ns)) {
+		deactivate_locked_super(sb);
+		return ERR_PTR(-EINVAL);
+	}
+
 	if (!sb->s_root) {
 		sb->s_flags = flags;
-		if (!proc_parse_options(options, ns)) {
-			deactivate_locked_super(sb);
-			return ERR_PTR(-EINVAL);
-		}
 		err = proc_fill_super(sb);
 		if (err) {
 			deactivate_locked_super(sb);
diff --git a/fs/proc/stat.c b/fs/proc/stat.c
index 121f77c..6a0c62d 100644
--- a/fs/proc/stat.c
+++ b/fs/proc/stat.c
@@ -89,18 +89,19 @@
 	}
 	sum += arch_irq_stat();
 
-	seq_printf(p, "cpu  %llu %llu %llu %llu %llu %llu %llu %llu %llu "
-		"%llu\n",
-		(unsigned long long)cputime64_to_clock_t(user),
-		(unsigned long long)cputime64_to_clock_t(nice),
-		(unsigned long long)cputime64_to_clock_t(system),
-		(unsigned long long)cputime64_to_clock_t(idle),
-		(unsigned long long)cputime64_to_clock_t(iowait),
-		(unsigned long long)cputime64_to_clock_t(irq),
-		(unsigned long long)cputime64_to_clock_t(softirq),
-		(unsigned long long)cputime64_to_clock_t(steal),
-		(unsigned long long)cputime64_to_clock_t(guest),
-		(unsigned long long)cputime64_to_clock_t(guest_nice));
+	seq_puts(p, "cpu ");
+	seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(user));
+	seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(nice));
+	seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(system));
+	seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(idle));
+	seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(iowait));
+	seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(irq));
+	seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(softirq));
+	seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(steal));
+	seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest));
+	seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest_nice));
+	seq_putc(p, '\n');
+
 	for_each_online_cpu(i) {
 		/* Copy values here to work around gcc-2.95.3, gcc-2.96 */
 		user = kcpustat_cpu(i).cpustat[CPUTIME_USER];
@@ -113,26 +114,24 @@
 		steal = kcpustat_cpu(i).cpustat[CPUTIME_STEAL];
 		guest = kcpustat_cpu(i).cpustat[CPUTIME_GUEST];
 		guest_nice = kcpustat_cpu(i).cpustat[CPUTIME_GUEST_NICE];
-		seq_printf(p,
-			"cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu "
-			"%llu\n",
-			i,
-			(unsigned long long)cputime64_to_clock_t(user),
-			(unsigned long long)cputime64_to_clock_t(nice),
-			(unsigned long long)cputime64_to_clock_t(system),
-			(unsigned long long)cputime64_to_clock_t(idle),
-			(unsigned long long)cputime64_to_clock_t(iowait),
-			(unsigned long long)cputime64_to_clock_t(irq),
-			(unsigned long long)cputime64_to_clock_t(softirq),
-			(unsigned long long)cputime64_to_clock_t(steal),
-			(unsigned long long)cputime64_to_clock_t(guest),
-			(unsigned long long)cputime64_to_clock_t(guest_nice));
+		seq_printf(p, "cpu%d", i);
+		seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(user));
+		seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(nice));
+		seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(system));
+		seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(idle));
+		seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(iowait));
+		seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(irq));
+		seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(softirq));
+		seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(steal));
+		seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest));
+		seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest_nice));
+		seq_putc(p, '\n');
 	}
 	seq_printf(p, "intr %llu", (unsigned long long)sum);
 
 	/* sum again ? it could be updated? */
 	for_each_irq_nr(j)
-		seq_printf(p, " %u", kstat_irqs(j));
+		seq_put_decimal_ull(p, ' ', kstat_irqs(j));
 
 	seq_printf(p,
 		"\nctxt %llu\n"
@@ -149,7 +148,7 @@
 	seq_printf(p, "softirq %llu", (unsigned long long)sum_softirq);
 
 	for (i = 0; i < NR_SOFTIRQS; i++)
-		seq_printf(p, " %u", per_softirq_sums[i]);
+		seq_put_decimal_ull(p, ' ', per_softirq_sums[i]);
 	seq_putc(p, '\n');
 
 	return 0;
@@ -157,11 +156,14 @@
 
 static int stat_open(struct inode *inode, struct file *file)
 {
-	unsigned size = 4096 * (1 + num_possible_cpus() / 32);
+	unsigned size = 1024 + 128 * num_possible_cpus();
 	char *buf;
 	struct seq_file *m;
 	int res;
 
+	/* minimum size to display an interrupt count : 2 bytes */
+	size += 2 * nr_irqs;
+
 	/* don't ask for more than the kmalloc() max size */
 	if (size > KMALLOC_MAX_SIZE)
 		size = KMALLOC_MAX_SIZE;
@@ -173,7 +175,7 @@
 	if (!res) {
 		m = file->private_data;
 		m->buf = buf;
-		m->size = size;
+		m->size = ksize(buf);
 	} else
 		kfree(buf);
 	return res;
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 7dcd2a2..2b9a760 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -209,16 +209,20 @@
 	return ret;
 }
 
-static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
+static void
+show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 {
 	struct mm_struct *mm = vma->vm_mm;
 	struct file *file = vma->vm_file;
+	struct proc_maps_private *priv = m->private;
+	struct task_struct *task = priv->task;
 	vm_flags_t flags = vma->vm_flags;
 	unsigned long ino = 0;
 	unsigned long long pgoff = 0;
 	unsigned long start, end;
 	dev_t dev = 0;
 	int len;
+	const char *name = NULL;
 
 	if (file) {
 		struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
@@ -252,36 +256,57 @@
 	if (file) {
 		pad_len_spaces(m, len);
 		seq_path(m, &file->f_path, "\n");
-	} else {
-		const char *name = arch_vma_name(vma);
-		if (!name) {
-			if (mm) {
-				if (vma->vm_start <= mm->brk &&
-						vma->vm_end >= mm->start_brk) {
-					name = "[heap]";
-				} else if (vma->vm_start <= mm->start_stack &&
-					   vma->vm_end >= mm->start_stack) {
-					name = "[stack]";
-				}
+		goto done;
+	}
+
+	name = arch_vma_name(vma);
+	if (!name) {
+		pid_t tid;
+
+		if (!mm) {
+			name = "[vdso]";
+			goto done;
+		}
+
+		if (vma->vm_start <= mm->brk &&
+		    vma->vm_end >= mm->start_brk) {
+			name = "[heap]";
+			goto done;
+		}
+
+		tid = vm_is_stack(task, vma, is_pid);
+
+		if (tid != 0) {
+			/*
+			 * Thread stack in /proc/PID/task/TID/maps or
+			 * the main process stack.
+			 */
+			if (!is_pid || (vma->vm_start <= mm->start_stack &&
+			    vma->vm_end >= mm->start_stack)) {
+				name = "[stack]";
 			} else {
-				name = "[vdso]";
+				/* Thread stack in /proc/PID/maps */
+				pad_len_spaces(m, len);
+				seq_printf(m, "[stack:%d]", tid);
 			}
 		}
-		if (name) {
-			pad_len_spaces(m, len);
-			seq_puts(m, name);
-		}
+	}
+
+done:
+	if (name) {
+		pad_len_spaces(m, len);
+		seq_puts(m, name);
 	}
 	seq_putc(m, '\n');
 }
 
-static int show_map(struct seq_file *m, void *v)
+static int show_map(struct seq_file *m, void *v, int is_pid)
 {
 	struct vm_area_struct *vma = v;
 	struct proc_maps_private *priv = m->private;
 	struct task_struct *task = priv->task;
 
-	show_map_vma(m, vma);
+	show_map_vma(m, vma, is_pid);
 
 	if (m->count < m->size)  /* vma is copied successfully */
 		m->version = (vma != get_gate_vma(task->mm))
@@ -289,20 +314,49 @@
 	return 0;
 }
 
+static int show_pid_map(struct seq_file *m, void *v)
+{
+	return show_map(m, v, 1);
+}
+
+static int show_tid_map(struct seq_file *m, void *v)
+{
+	return show_map(m, v, 0);
+}
+
 static const struct seq_operations proc_pid_maps_op = {
 	.start	= m_start,
 	.next	= m_next,
 	.stop	= m_stop,
-	.show	= show_map
+	.show	= show_pid_map
 };
 
-static int maps_open(struct inode *inode, struct file *file)
+static const struct seq_operations proc_tid_maps_op = {
+	.start	= m_start,
+	.next	= m_next,
+	.stop	= m_stop,
+	.show	= show_tid_map
+};
+
+static int pid_maps_open(struct inode *inode, struct file *file)
 {
 	return do_maps_open(inode, file, &proc_pid_maps_op);
 }
 
-const struct file_operations proc_maps_operations = {
-	.open		= maps_open,
+static int tid_maps_open(struct inode *inode, struct file *file)
+{
+	return do_maps_open(inode, file, &proc_tid_maps_op);
+}
+
+const struct file_operations proc_pid_maps_operations = {
+	.open		= pid_maps_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release_private,
+};
+
+const struct file_operations proc_tid_maps_operations = {
+	.open		= tid_maps_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
 	.release	= seq_release_private,
@@ -394,21 +448,15 @@
 	pte_t *pte;
 	spinlock_t *ptl;
 
-	spin_lock(&walk->mm->page_table_lock);
-	if (pmd_trans_huge(*pmd)) {
-		if (pmd_trans_splitting(*pmd)) {
-			spin_unlock(&walk->mm->page_table_lock);
-			wait_split_huge_page(vma->anon_vma, pmd);
-		} else {
-			smaps_pte_entry(*(pte_t *)pmd, addr,
-					HPAGE_PMD_SIZE, walk);
-			spin_unlock(&walk->mm->page_table_lock);
-			mss->anonymous_thp += HPAGE_PMD_SIZE;
-			return 0;
-		}
-	} else {
+	if (pmd_trans_huge_lock(pmd, vma) == 1) {
+		smaps_pte_entry(*(pte_t *)pmd, addr, HPAGE_PMD_SIZE, walk);
 		spin_unlock(&walk->mm->page_table_lock);
+		mss->anonymous_thp += HPAGE_PMD_SIZE;
+		return 0;
 	}
+
+	if (pmd_trans_unstable(pmd))
+		return 0;
 	/*
 	 * The mmap_sem held all the way back in m_start() is what
 	 * keeps khugepaged out of here and from collapsing things
@@ -422,7 +470,7 @@
 	return 0;
 }
 
-static int show_smap(struct seq_file *m, void *v)
+static int show_smap(struct seq_file *m, void *v, int is_pid)
 {
 	struct proc_maps_private *priv = m->private;
 	struct task_struct *task = priv->task;
@@ -440,7 +488,7 @@
 	if (vma->vm_mm && !is_vm_hugetlb_page(vma))
 		walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk);
 
-	show_map_vma(m, vma);
+	show_map_vma(m, vma, is_pid);
 
 	seq_printf(m,
 		   "Size:           %8lu kB\n"
@@ -479,20 +527,49 @@
 	return 0;
 }
 
+static int show_pid_smap(struct seq_file *m, void *v)
+{
+	return show_smap(m, v, 1);
+}
+
+static int show_tid_smap(struct seq_file *m, void *v)
+{
+	return show_smap(m, v, 0);
+}
+
 static const struct seq_operations proc_pid_smaps_op = {
 	.start	= m_start,
 	.next	= m_next,
 	.stop	= m_stop,
-	.show	= show_smap
+	.show	= show_pid_smap
 };
 
-static int smaps_open(struct inode *inode, struct file *file)
+static const struct seq_operations proc_tid_smaps_op = {
+	.start	= m_start,
+	.next	= m_next,
+	.stop	= m_stop,
+	.show	= show_tid_smap
+};
+
+static int pid_smaps_open(struct inode *inode, struct file *file)
 {
 	return do_maps_open(inode, file, &proc_pid_smaps_op);
 }
 
-const struct file_operations proc_smaps_operations = {
-	.open		= smaps_open,
+static int tid_smaps_open(struct inode *inode, struct file *file)
+{
+	return do_maps_open(inode, file, &proc_tid_smaps_op);
+}
+
+const struct file_operations proc_pid_smaps_operations = {
+	.open		= pid_smaps_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release_private,
+};
+
+const struct file_operations proc_tid_smaps_operations = {
+	.open		= tid_smaps_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
 	.release	= seq_release_private,
@@ -507,6 +584,8 @@
 	struct page *page;
 
 	split_huge_page_pmd(walk->mm, pmd);
+	if (pmd_trans_unstable(pmd))
+		return 0;
 
 	pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
 	for (; addr != end; pte++, addr += PAGE_SIZE) {
@@ -598,11 +677,18 @@
 	.llseek		= noop_llseek,
 };
 
+typedef struct {
+	u64 pme;
+} pagemap_entry_t;
+
 struct pagemapread {
 	int pos, len;
-	u64 *buffer;
+	pagemap_entry_t *buffer;
 };
 
+#define PAGEMAP_WALK_SIZE	(PMD_SIZE)
+#define PAGEMAP_WALK_MASK	(PMD_MASK)
+
 #define PM_ENTRY_BYTES      sizeof(u64)
 #define PM_STATUS_BITS      3
 #define PM_STATUS_OFFSET    (64 - PM_STATUS_BITS)
@@ -620,10 +706,15 @@
 #define PM_NOT_PRESENT      PM_PSHIFT(PAGE_SHIFT)
 #define PM_END_OF_BUFFER    1
 
-static int add_to_pagemap(unsigned long addr, u64 pfn,
+static inline pagemap_entry_t make_pme(u64 val)
+{
+	return (pagemap_entry_t) { .pme = val };
+}
+
+static int add_to_pagemap(unsigned long addr, pagemap_entry_t *pme,
 			  struct pagemapread *pm)
 {
-	pm->buffer[pm->pos++] = pfn;
+	pm->buffer[pm->pos++] = *pme;
 	if (pm->pos >= pm->len)
 		return PM_END_OF_BUFFER;
 	return 0;
@@ -635,8 +726,10 @@
 	struct pagemapread *pm = walk->private;
 	unsigned long addr;
 	int err = 0;
+	pagemap_entry_t pme = make_pme(PM_NOT_PRESENT);
+
 	for (addr = start; addr < end; addr += PAGE_SIZE) {
-		err = add_to_pagemap(addr, PM_NOT_PRESENT, pm);
+		err = add_to_pagemap(addr, &pme, pm);
 		if (err)
 			break;
 	}
@@ -649,18 +742,36 @@
 	return swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT);
 }
 
-static u64 pte_to_pagemap_entry(pte_t pte)
+static void pte_to_pagemap_entry(pagemap_entry_t *pme, pte_t pte)
 {
-	u64 pme = 0;
 	if (is_swap_pte(pte))
-		pme = PM_PFRAME(swap_pte_to_pagemap_entry(pte))
-			| PM_PSHIFT(PAGE_SHIFT) | PM_SWAP;
+		*pme = make_pme(PM_PFRAME(swap_pte_to_pagemap_entry(pte))
+				| PM_PSHIFT(PAGE_SHIFT) | PM_SWAP);
 	else if (pte_present(pte))
-		pme = PM_PFRAME(pte_pfn(pte))
-			| PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT;
-	return pme;
+		*pme = make_pme(PM_PFRAME(pte_pfn(pte))
+				| PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT);
 }
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme,
+					pmd_t pmd, int offset)
+{
+	/*
+	 * Currently pmd for thp is always present because thp can not be
+	 * swapped-out, migrated, or HWPOISONed (split in such cases instead.)
+	 * This if-check is just to prepare for future implementation.
+	 */
+	if (pmd_present(pmd))
+		*pme = make_pme(PM_PFRAME(pmd_pfn(pmd) + offset)
+				| PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT);
+}
+#else
+static inline void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme,
+						pmd_t pmd, int offset)
+{
+}
+#endif
+
 static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
 			     struct mm_walk *walk)
 {
@@ -668,13 +779,28 @@
 	struct pagemapread *pm = walk->private;
 	pte_t *pte;
 	int err = 0;
-
-	split_huge_page_pmd(walk->mm, pmd);
+	pagemap_entry_t pme = make_pme(PM_NOT_PRESENT);
 
 	/* find the first VMA at or above 'addr' */
 	vma = find_vma(walk->mm, addr);
+	if (pmd_trans_huge_lock(pmd, vma) == 1) {
+		for (; addr != end; addr += PAGE_SIZE) {
+			unsigned long offset;
+
+			offset = (addr & ~PAGEMAP_WALK_MASK) >>
+					PAGE_SHIFT;
+			thp_pmd_to_pagemap_entry(&pme, *pmd, offset);
+			err = add_to_pagemap(addr, &pme, pm);
+			if (err)
+				break;
+		}
+		spin_unlock(&walk->mm->page_table_lock);
+		return err;
+	}
+
+	if (pmd_trans_unstable(pmd))
+		return 0;
 	for (; addr != end; addr += PAGE_SIZE) {
-		u64 pfn = PM_NOT_PRESENT;
 
 		/* check to see if we've left 'vma' behind
 		 * and need a new, higher one */
@@ -686,11 +812,11 @@
 		if (vma && (vma->vm_start <= addr) &&
 		    !is_vm_hugetlb_page(vma)) {
 			pte = pte_offset_map(pmd, addr);
-			pfn = pte_to_pagemap_entry(*pte);
+			pte_to_pagemap_entry(&pme, *pte);
 			/* unmap before userspace copy */
 			pte_unmap(pte);
 		}
-		err = add_to_pagemap(addr, pfn, pm);
+		err = add_to_pagemap(addr, &pme, pm);
 		if (err)
 			return err;
 	}
@@ -701,13 +827,12 @@
 }
 
 #ifdef CONFIG_HUGETLB_PAGE
-static u64 huge_pte_to_pagemap_entry(pte_t pte, int offset)
+static void huge_pte_to_pagemap_entry(pagemap_entry_t *pme,
+					pte_t pte, int offset)
 {
-	u64 pme = 0;
 	if (pte_present(pte))
-		pme = PM_PFRAME(pte_pfn(pte) + offset)
-			| PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT;
-	return pme;
+		*pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset)
+				| PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT);
 }
 
 /* This function walks within one hugetlb entry in the single call */
@@ -717,12 +842,12 @@
 {
 	struct pagemapread *pm = walk->private;
 	int err = 0;
-	u64 pfn;
+	pagemap_entry_t pme = make_pme(PM_NOT_PRESENT);
 
 	for (; addr != end; addr += PAGE_SIZE) {
 		int offset = (addr & ~hmask) >> PAGE_SHIFT;
-		pfn = huge_pte_to_pagemap_entry(*pte, offset);
-		err = add_to_pagemap(addr, pfn, pm);
+		huge_pte_to_pagemap_entry(&pme, *pte, offset);
+		err = add_to_pagemap(addr, &pme, pm);
 		if (err)
 			return err;
 	}
@@ -757,8 +882,6 @@
  * determine which areas of memory are actually mapped and llseek to
  * skip over unmapped regions.
  */
-#define PAGEMAP_WALK_SIZE	(PMD_SIZE)
-#define PAGEMAP_WALK_MASK	(PMD_MASK)
 static ssize_t pagemap_read(struct file *file, char __user *buf,
 			    size_t count, loff_t *ppos)
 {
@@ -941,26 +1064,21 @@
 	pte_t *pte;
 
 	md = walk->private;
-	spin_lock(&walk->mm->page_table_lock);
-	if (pmd_trans_huge(*pmd)) {
-		if (pmd_trans_splitting(*pmd)) {
-			spin_unlock(&walk->mm->page_table_lock);
-			wait_split_huge_page(md->vma->anon_vma, pmd);
-		} else {
-			pte_t huge_pte = *(pte_t *)pmd;
-			struct page *page;
 
-			page = can_gather_numa_stats(huge_pte, md->vma, addr);
-			if (page)
-				gather_stats(page, md, pte_dirty(huge_pte),
-						HPAGE_PMD_SIZE/PAGE_SIZE);
-			spin_unlock(&walk->mm->page_table_lock);
-			return 0;
-		}
-	} else {
+	if (pmd_trans_huge_lock(pmd, md->vma) == 1) {
+		pte_t huge_pte = *(pte_t *)pmd;
+		struct page *page;
+
+		page = can_gather_numa_stats(huge_pte, md->vma, addr);
+		if (page)
+			gather_stats(page, md, pte_dirty(huge_pte),
+				     HPAGE_PMD_SIZE/PAGE_SIZE);
 		spin_unlock(&walk->mm->page_table_lock);
+		return 0;
 	}
 
+	if (pmd_trans_unstable(pmd))
+		return 0;
 	orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
 	do {
 		struct page *page = can_gather_numa_stats(*pte, md->vma, addr);
@@ -1002,7 +1120,7 @@
 /*
  * Display pages allocated per node and memory policy via /proc.
  */
-static int show_numa_map(struct seq_file *m, void *v)
+static int show_numa_map(struct seq_file *m, void *v, int is_pid)
 {
 	struct numa_maps_private *numa_priv = m->private;
 	struct proc_maps_private *proc_priv = &numa_priv->proc_maps;
@@ -1039,9 +1157,19 @@
 		seq_path(m, &file->f_path, "\n\t= ");
 	} else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
 		seq_printf(m, " heap");
-	} else if (vma->vm_start <= mm->start_stack &&
-			vma->vm_end >= mm->start_stack) {
-		seq_printf(m, " stack");
+	} else {
+		pid_t tid = vm_is_stack(proc_priv->task, vma, is_pid);
+		if (tid != 0) {
+			/*
+			 * Thread stack in /proc/PID/task/TID/maps or
+			 * the main process stack.
+			 */
+			if (!is_pid || (vma->vm_start <= mm->start_stack &&
+			    vma->vm_end >= mm->start_stack))
+				seq_printf(m, " stack");
+			else
+				seq_printf(m, " stack:%d", tid);
+		}
 	}
 
 	if (is_vm_hugetlb_page(vma))
@@ -1084,21 +1212,39 @@
 	return 0;
 }
 
+static int show_pid_numa_map(struct seq_file *m, void *v)
+{
+	return show_numa_map(m, v, 1);
+}
+
+static int show_tid_numa_map(struct seq_file *m, void *v)
+{
+	return show_numa_map(m, v, 0);
+}
+
 static const struct seq_operations proc_pid_numa_maps_op = {
-        .start  = m_start,
-        .next   = m_next,
-        .stop   = m_stop,
-        .show   = show_numa_map,
+	.start  = m_start,
+	.next   = m_next,
+	.stop   = m_stop,
+	.show   = show_pid_numa_map,
 };
 
-static int numa_maps_open(struct inode *inode, struct file *file)
+static const struct seq_operations proc_tid_numa_maps_op = {
+	.start  = m_start,
+	.next   = m_next,
+	.stop   = m_stop,
+	.show   = show_tid_numa_map,
+};
+
+static int numa_maps_open(struct inode *inode, struct file *file,
+			  const struct seq_operations *ops)
 {
 	struct numa_maps_private *priv;
 	int ret = -ENOMEM;
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (priv) {
 		priv->proc_maps.pid = proc_pid(inode);
-		ret = seq_open(file, &proc_pid_numa_maps_op);
+		ret = seq_open(file, ops);
 		if (!ret) {
 			struct seq_file *m = file->private_data;
 			m->private = priv;
@@ -1109,8 +1255,25 @@
 	return ret;
 }
 
-const struct file_operations proc_numa_maps_operations = {
-	.open		= numa_maps_open,
+static int pid_numa_maps_open(struct inode *inode, struct file *file)
+{
+	return numa_maps_open(inode, file, &proc_pid_numa_maps_op);
+}
+
+static int tid_numa_maps_open(struct inode *inode, struct file *file)
+{
+	return numa_maps_open(inode, file, &proc_tid_numa_maps_op);
+}
+
+const struct file_operations proc_pid_numa_maps_operations = {
+	.open		= pid_numa_maps_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release_private,
+};
+
+const struct file_operations proc_tid_numa_maps_operations = {
+	.open		= tid_numa_maps_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
 	.release	= seq_release_private,
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 980de54..74fe164 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -134,9 +134,11 @@
 /*
  * display a single VMA to a sequenced file
  */
-static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
+static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
+			  int is_pid)
 {
 	struct mm_struct *mm = vma->vm_mm;
+	struct proc_maps_private *priv = m->private;
 	unsigned long ino = 0;
 	struct file *file;
 	dev_t dev = 0;
@@ -168,10 +170,19 @@
 		pad_len_spaces(m, len);
 		seq_path(m, &file->f_path, "");
 	} else if (mm) {
-		if (vma->vm_start <= mm->start_stack &&
-			vma->vm_end >= mm->start_stack) {
+		pid_t tid = vm_is_stack(priv->task, vma, is_pid);
+
+		if (tid != 0) {
 			pad_len_spaces(m, len);
-			seq_puts(m, "[stack]");
+			/*
+			 * Thread stack in /proc/PID/task/TID/maps or
+			 * the main process stack.
+			 */
+			if (!is_pid || (vma->vm_start <= mm->start_stack &&
+			    vma->vm_end >= mm->start_stack))
+				seq_printf(m, "[stack]");
+			else
+				seq_printf(m, "[stack:%d]", tid);
 		}
 	}
 
@@ -182,11 +193,22 @@
 /*
  * display mapping lines for a particular process's /proc/pid/maps
  */
-static int show_map(struct seq_file *m, void *_p)
+static int show_map(struct seq_file *m, void *_p, int is_pid)
 {
 	struct rb_node *p = _p;
 
-	return nommu_vma_show(m, rb_entry(p, struct vm_area_struct, vm_rb));
+	return nommu_vma_show(m, rb_entry(p, struct vm_area_struct, vm_rb),
+			      is_pid);
+}
+
+static int show_pid_map(struct seq_file *m, void *_p)
+{
+	return show_map(m, _p, 1);
+}
+
+static int show_tid_map(struct seq_file *m, void *_p)
+{
+	return show_map(m, _p, 0);
 }
 
 static void *m_start(struct seq_file *m, loff_t *pos)
@@ -240,10 +262,18 @@
 	.start	= m_start,
 	.next	= m_next,
 	.stop	= m_stop,
-	.show	= show_map
+	.show	= show_pid_map
 };
 
-static int maps_open(struct inode *inode, struct file *file)
+static const struct seq_operations proc_tid_maps_ops = {
+	.start	= m_start,
+	.next	= m_next,
+	.stop	= m_stop,
+	.show	= show_tid_map
+};
+
+static int maps_open(struct inode *inode, struct file *file,
+		     const struct seq_operations *ops)
 {
 	struct proc_maps_private *priv;
 	int ret = -ENOMEM;
@@ -251,7 +281,7 @@
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (priv) {
 		priv->pid = proc_pid(inode);
-		ret = seq_open(file, &proc_pid_maps_ops);
+		ret = seq_open(file, ops);
 		if (!ret) {
 			struct seq_file *m = file->private_data;
 			m->private = priv;
@@ -262,8 +292,25 @@
 	return ret;
 }
 
-const struct file_operations proc_maps_operations = {
-	.open		= maps_open,
+static int pid_maps_open(struct inode *inode, struct file *file)
+{
+	return maps_open(inode, file, &proc_pid_maps_ops);
+}
+
+static int tid_maps_open(struct inode *inode, struct file *file)
+{
+	return maps_open(inode, file, &proc_tid_maps_ops);
+}
+
+const struct file_operations proc_pid_maps_operations = {
+	.open		= pid_maps_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release_private,
+};
+
+const struct file_operations proc_tid_maps_operations = {
+	.open		= tid_maps_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
 	.release	= seq_release_private,
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index b0f450a..0d5071d 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -700,3 +700,26 @@
 	return 0;
 }
 module_init(vmcore_init)
+
+/* Cleanup function for vmcore module. */
+void vmcore_cleanup(void)
+{
+	struct list_head *pos, *next;
+
+	if (proc_vmcore) {
+		remove_proc_entry(proc_vmcore->name, proc_vmcore->parent);
+		proc_vmcore = NULL;
+	}
+
+	/* clear the vmcore list. */
+	list_for_each_safe(pos, next, &vmcore_list) {
+		struct vmcore *m;
+
+		m = list_entry(pos, struct vmcore, list);
+		list_del(&m->list);
+		kfree(m);
+	}
+	kfree(elfcorebuf);
+	elfcorebuf = NULL;
+}
+EXPORT_SYMBOL_GPL(vmcore_cleanup);
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index b3b426e..1950788 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -52,12 +52,6 @@
 	char	data[];
 };
 
-static int pstore_file_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t pstore_file_read(struct file *file, char __user *userbuf,
 						size_t count, loff_t *ppos)
 {
@@ -67,7 +61,7 @@
 }
 
 static const struct file_operations pstore_file_operations = {
-	.open	= pstore_file_open,
+	.open	= simple_open,
 	.read	= pstore_file_read,
 	.llseek	= default_llseek,
 };
@@ -105,26 +99,12 @@
 	.unlink		= pstore_unlink,
 };
 
-static struct inode *pstore_get_inode(struct super_block *sb,
-					const struct inode *dir, int mode, dev_t dev)
+static struct inode *pstore_get_inode(struct super_block *sb)
 {
 	struct inode *inode = new_inode(sb);
-
 	if (inode) {
 		inode->i_ino = get_next_ino();
-		inode->i_uid = inode->i_gid = 0;
-		inode->i_mode = mode;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-		switch (mode & S_IFMT) {
-		case S_IFREG:
-			inode->i_fop = &pstore_file_operations;
-			break;
-		case S_IFDIR:
-			inode->i_op = &pstore_dir_inode_operations;
-			inode->i_fop = &simple_dir_operations;
-			inc_nlink(inode);
-			break;
-		}
 	}
 	return inode;
 }
@@ -216,9 +196,11 @@
 		return rc;
 
 	rc = -ENOMEM;
-	inode = pstore_get_inode(pstore_sb, root->d_inode, S_IFREG | 0444, 0);
+	inode = pstore_get_inode(pstore_sb);
 	if (!inode)
 		goto fail;
+	inode->i_mode = S_IFREG | 0444;
+	inode->i_fop = &pstore_file_operations;
 	private = kmalloc(sizeof *private + size, GFP_KERNEL);
 	if (!private)
 		goto fail_alloc;
@@ -278,9 +260,7 @@
 
 int pstore_fill_super(struct super_block *sb, void *data, int silent)
 {
-	struct inode *inode = NULL;
-	struct dentry *root;
-	int err;
+	struct inode *inode;
 
 	save_mount_options(sb, data);
 
@@ -295,27 +275,20 @@
 
 	parse_options(data);
 
-	inode = pstore_get_inode(sb, NULL, S_IFDIR | 0755, 0);
-	if (!inode) {
-		err = -ENOMEM;
-		goto fail;
+	inode = pstore_get_inode(sb);
+	if (inode) {
+		inode->i_mode = S_IFDIR | 0755;
+		inode->i_op = &pstore_dir_inode_operations;
+		inode->i_fop = &simple_dir_operations;
+		inc_nlink(inode);
 	}
-	/* override ramfs "dir" options so we catch unlink(2) */
-	inode->i_op = &pstore_dir_inode_operations;
-
-	root = d_alloc_root(inode);
-	sb->s_root = root;
-	if (!root) {
-		err = -ENOMEM;
-		goto fail;
-	}
+	sb->s_root = d_make_root(inode);
+	if (!sb->s_root)
+		return -ENOMEM;
 
 	pstore_get_records(0);
 
 	return 0;
-fail:
-	iput(inode);
-	return err;
 }
 
 static struct dentry *pstore_mount(struct file_system_type *fs_type,
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 9ec22d3..82c585f 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -68,9 +68,25 @@
 /* Tag each group of saved records with a sequence number */
 static int	oopscount;
 
-static char *reason_str[] = {
-	"Oops", "Panic", "Kexec", "Restart", "Halt", "Poweroff", "Emergency"
-};
+static const char *get_reason_str(enum kmsg_dump_reason reason)
+{
+	switch (reason) {
+	case KMSG_DUMP_PANIC:
+		return "Panic";
+	case KMSG_DUMP_OOPS:
+		return "Oops";
+	case KMSG_DUMP_EMERG:
+		return "Emergency";
+	case KMSG_DUMP_RESTART:
+		return "Restart";
+	case KMSG_DUMP_HALT:
+		return "Halt";
+	case KMSG_DUMP_POWEROFF:
+		return "Poweroff";
+	default:
+		return "Unknown";
+	}
+}
 
 /*
  * callback from kmsg_dump. (s2,l2) has the most recently
@@ -85,17 +101,15 @@
 	unsigned long	s1_start, s2_start;
 	unsigned long	l1_cpy, l2_cpy;
 	unsigned long	size, total = 0;
-	char		*dst, *why;
+	char		*dst;
+	const char	*why;
 	u64		id;
 	int		hsize, ret;
 	unsigned int	part = 1;
 	unsigned long	flags = 0;
 	int		is_locked = 0;
 
-	if (reason < ARRAY_SIZE(reason_str))
-		why = reason_str[reason];
-	else
-		why = "Unknown";
+	why = get_reason_str(reason);
 
 	if (in_nmi()) {
 		is_locked = spin_trylock(&psinfo->buf_lock);
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 6b00954..552e994 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -52,38 +52,6 @@
 	return 0;
 }
 
-static struct buffer_head *qnx4_getblk(struct inode *inode, int nr,
-				       int create)
-{
-	struct buffer_head *result = NULL;
-
-	if ( nr >= 0 )
-		nr = qnx4_block_map( inode, nr );
-	if (nr) {
-		result = sb_getblk(inode->i_sb, nr);
-		return result;
-	}
-	return NULL;
-}
-
-struct buffer_head *qnx4_bread(struct inode *inode, int block, int create)
-{
-	struct buffer_head *bh;
-
-	bh = qnx4_getblk(inode, block, create);
-	if (!bh || buffer_uptodate(bh)) {
-		return bh;
-	}
-	ll_rw_block(READ, 1, &bh);
-	wait_on_buffer(bh);
-	if (buffer_uptodate(bh)) {
-		return bh;
-	}
-	brelse(bh);
-
-	return NULL;
-}
-
 static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_head *bh, int create )
 {
 	unsigned long phys;
@@ -98,23 +66,31 @@
 	return 0;
 }
 
+static inline u32 try_extent(qnx4_xtnt_t *extent, u32 *offset)
+{
+	u32 size = le32_to_cpu(extent->xtnt_size);
+	if (*offset < size)
+		return le32_to_cpu(extent->xtnt_blk) + *offset - 1;
+	*offset -= size;
+	return 0;
+}
+
 unsigned long qnx4_block_map( struct inode *inode, long iblock )
 {
 	int ix;
-	long offset, i_xblk;
-	unsigned long block = 0;
+	long i_xblk;
 	struct buffer_head *bh = NULL;
 	struct qnx4_xblk *xblk = NULL;
 	struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode);
 	u16 nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts);
+	u32 offset = iblock;
+	u32 block = try_extent(&qnx4_inode->di_first_xtnt, &offset);
 
-	if ( iblock < le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size) ) {
+	if (block) {
 		// iblock is in the first extent. This is easy.
-		block = le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_blk) + iblock - 1;
 	} else {
 		// iblock is beyond first extent. We have to follow the extent chain.
 		i_xblk = le32_to_cpu(qnx4_inode->di_xblk);
-		offset = iblock - le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size);
 		ix = 0;
 		while ( --nxtnt > 0 ) {
 			if ( ix == 0 ) {
@@ -130,12 +106,11 @@
 					return -EIO;
 				}
 			}
-			if ( offset < le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size) ) {
+			block = try_extent(&xblk->xblk_xtnts[ix], &offset);
+			if (block) {
 				// got it!
-				block = le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_blk) + offset - 1;
 				break;
 			}
-			offset -= le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size);
 			if ( ++ix >= xblk->xblk_num_xtnts ) {
 				i_xblk = le32_to_cpu(xblk->xblk_next_xblk);
 				ix = 0;
@@ -260,15 +235,13 @@
  	}
 
 	ret = -ENOMEM;
- 	s->s_root = d_alloc_root(root);
+ 	s->s_root = d_make_root(root);
  	if (s->s_root == NULL)
- 		goto outi;
+ 		goto outb;
 
 	brelse(bh);
 	return 0;
 
-      outi:
-	iput(root);
       outb:
 	kfree(qs->BitMap);
       out:
@@ -288,44 +261,17 @@
 	return;
 }
 
-static int qnx4_writepage(struct page *page, struct writeback_control *wbc)
-{
-	return block_write_full_page(page,qnx4_get_block, wbc);
-}
-
 static int qnx4_readpage(struct file *file, struct page *page)
 {
 	return block_read_full_page(page,qnx4_get_block);
 }
 
-static int qnx4_write_begin(struct file *file, struct address_space *mapping,
-			loff_t pos, unsigned len, unsigned flags,
-			struct page **pagep, void **fsdata)
-{
-	struct qnx4_inode_info *qnx4_inode = qnx4_i(mapping->host);
-	int ret;
-
-	*pagep = NULL;
-	ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-				qnx4_get_block,
-				&qnx4_inode->mmu_private);
-	if (unlikely(ret)) {
-		loff_t isize = mapping->host->i_size;
-		if (pos + len > isize)
-			vmtruncate(mapping->host, isize);
-	}
-
-	return ret;
-}
 static sector_t qnx4_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping,block,qnx4_get_block);
 }
 static const struct address_space_operations qnx4_aops = {
 	.readpage	= qnx4_readpage,
-	.writepage	= qnx4_writepage,
-	.write_begin	= qnx4_write_begin,
-	.write_end	= generic_write_end,
 	.bmap		= qnx4_bmap
 };
 
diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c
index 275327b..a512c0b 100644
--- a/fs/qnx4/namei.c
+++ b/fs/qnx4/namei.c
@@ -39,10 +39,6 @@
 	} else {
 		namelen = QNX4_SHORT_NAME_MAX;
 	}
-	/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
-	if (!len && (de->di_fname[0] == '.') && (de->di_fname[1] == '\0')) {
-		return 1;
-	}
 	thislen = strlen( de->di_fname );
 	if ( thislen > namelen )
 		thislen = namelen;
@@ -72,7 +68,9 @@
 	block = offset = blkofs = 0;
 	while (blkofs * QNX4_BLOCK_SIZE + offset < dir->i_size) {
 		if (!bh) {
-			bh = qnx4_bread(dir, blkofs, 0);
+			block = qnx4_block_map(dir, blkofs);
+			if (block)
+				bh = sb_bread(dir->i_sb, block);
 			if (!bh) {
 				blkofs++;
 				continue;
@@ -80,7 +78,6 @@
 		}
 		*res_dir = (struct qnx4_inode_entry *) (bh->b_data + offset);
 		if (qnx4_match(len, name, bh, &offset)) {
-			block = qnx4_block_map( dir, blkofs );
 			*ino = block * QNX4_INODES_PER_BLOCK +
 			    (offset / QNX4_DIR_ENTRY_SIZE) - 1;
 			return bh;
diff --git a/fs/qnx4/qnx4.h b/fs/qnx4/qnx4.h
index 33a6085..244d462 100644
--- a/fs/qnx4/qnx4.h
+++ b/fs/qnx4/qnx4.h
@@ -27,8 +27,6 @@
 extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
 extern unsigned long qnx4_block_map(struct inode *inode, long iblock);
 
-extern struct buffer_head *qnx4_bread(struct inode *, int, int);
-
 extern const struct inode_operations qnx4_dir_inode_operations;
 extern const struct file_operations qnx4_dir_operations;
 extern int qnx4_is_free(struct super_block *sb, long block);
diff --git a/fs/qnx6/Kconfig b/fs/qnx6/Kconfig
new file mode 100644
index 0000000..edbba5c
--- /dev/null
+++ b/fs/qnx6/Kconfig
@@ -0,0 +1,26 @@
+config QNX6FS_FS
+	tristate "QNX6 file system support (read only)"
+	depends on BLOCK && CRC32
+	help
+	  This is the file system used by the real-time operating systems
+	  QNX 6 (also called QNX RTP).
+	  Further information is available at <http://www.qnx.com/>.
+	  Say Y if you intend to mount QNX hard disks or floppies formatted
+          with a mkqnx6fs.
+	  However, keep in mind that this currently is a readonly driver!
+
+	  To compile this file system support as a module, choose M here: the
+	  module will be called qnx6.
+
+	  If you don't know whether you need it, then you don't need it:
+	  answer N.
+
+config QNX6FS_DEBUG
+	bool "QNX6 debugging information"
+	depends on QNX6FS_FS
+	help
+	  Turns on extended debugging output.
+
+	  If you are not a developer working on the QNX6FS, you probably don't
+	  want this:
+	  answer N.
diff --git a/fs/qnx6/Makefile b/fs/qnx6/Makefile
new file mode 100644
index 0000000..9dd0619
--- /dev/null
+++ b/fs/qnx6/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the linux qnx4-filesystem routines.
+#
+
+obj-$(CONFIG_QNX6FS_FS) += qnx6.o
+
+qnx6-objs := inode.o dir.o namei.o super_mmi.o
diff --git a/fs/qnx6/README b/fs/qnx6/README
new file mode 100644
index 0000000..116d622
--- /dev/null
+++ b/fs/qnx6/README
@@ -0,0 +1,8 @@
+
+  This is a snapshot of the QNX6 filesystem for Linux.
+  Please send diffs and remarks to <chaosman@ontika.net> .
+
+Credits :
+
+Al Viro		<viro@ZenIV.linux.org.uk> (endless patience with me & support ;))
+Kai Bankett	<chaosman@ontika.net> (Maintainer)
diff --git a/fs/qnx6/dir.c b/fs/qnx6/dir.c
new file mode 100644
index 0000000..dc59735
--- /dev/null
+++ b/fs/qnx6/dir.c
@@ -0,0 +1,291 @@
+/*
+ * QNX6 file system, Linux implementation.
+ *
+ * Version : 1.0.0
+ *
+ * History :
+ *
+ * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
+ * 16-02-2012 pagemap extension by Al Viro
+ *
+ */
+
+#include "qnx6.h"
+
+static unsigned qnx6_lfile_checksum(char *name, unsigned size)
+{
+	unsigned crc = 0;
+	char *end = name + size;
+	while (name < end) {
+		crc = ((crc >> 1) + *(name++)) ^
+			((crc & 0x00000001) ? 0x80000000 : 0);
+	}
+	return crc;
+}
+
+static struct page *qnx6_get_page(struct inode *dir, unsigned long n)
+{
+	struct address_space *mapping = dir->i_mapping;
+	struct page *page = read_mapping_page(mapping, n, NULL);
+	if (!IS_ERR(page))
+		kmap(page);
+	return page;
+}
+
+static inline unsigned long dir_pages(struct inode *inode)
+{
+	return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
+}
+
+static unsigned last_entry(struct inode *inode, unsigned long page_nr)
+{
+	unsigned long last_byte = inode->i_size;
+	last_byte -= page_nr << PAGE_CACHE_SHIFT;
+	if (last_byte > PAGE_CACHE_SIZE)
+		last_byte = PAGE_CACHE_SIZE;
+	return last_byte / QNX6_DIR_ENTRY_SIZE;
+}
+
+static struct qnx6_long_filename *qnx6_longname(struct super_block *sb,
+					 struct qnx6_long_dir_entry *de,
+					 struct page **p)
+{
+	struct qnx6_sb_info *sbi = QNX6_SB(sb);
+	u32 s = fs32_to_cpu(sbi, de->de_long_inode); /* in block units */
+	u32 n = s >> (PAGE_CACHE_SHIFT - sb->s_blocksize_bits); /* in pages */
+	/* within page */
+	u32 offs = (s << sb->s_blocksize_bits) & ~PAGE_CACHE_MASK;
+	struct address_space *mapping = sbi->longfile->i_mapping;
+	struct page *page = read_mapping_page(mapping, n, NULL);
+	if (IS_ERR(page))
+		return ERR_CAST(page);
+	kmap(*p = page);
+	return (struct qnx6_long_filename *)(page_address(page) + offs);
+}
+
+static int qnx6_dir_longfilename(struct inode *inode,
+			struct qnx6_long_dir_entry *de,
+			void *dirent, loff_t pos,
+			unsigned de_inode, filldir_t filldir)
+{
+	struct qnx6_long_filename *lf;
+	struct super_block *s = inode->i_sb;
+	struct qnx6_sb_info *sbi = QNX6_SB(s);
+	struct page *page;
+	int lf_size;
+
+	if (de->de_size != 0xff) {
+		/* error - long filename entries always have size 0xff
+		   in direntry */
+		printk(KERN_ERR "qnx6: invalid direntry size (%i).\n",
+				de->de_size);
+		return 0;
+	}
+	lf = qnx6_longname(s, de, &page);
+	if (IS_ERR(lf)) {
+		printk(KERN_ERR "qnx6:Error reading longname\n");
+		return 0;
+	}
+
+	lf_size = fs16_to_cpu(sbi, lf->lf_size);
+
+	if (lf_size > QNX6_LONG_NAME_MAX) {
+		QNX6DEBUG((KERN_INFO "file %s\n", lf->lf_fname));
+		printk(KERN_ERR "qnx6:Filename too long (%i)\n", lf_size);
+		qnx6_put_page(page);
+		return 0;
+	}
+
+	/* calc & validate longfilename checksum
+	   mmi 3g filesystem does not have that checksum */
+	if (!test_opt(s, MMI_FS) && fs32_to_cpu(sbi, de->de_checksum) !=
+			qnx6_lfile_checksum(lf->lf_fname, lf_size))
+		printk(KERN_INFO "qnx6: long filename checksum error.\n");
+
+	QNX6DEBUG((KERN_INFO "qnx6_readdir:%.*s inode:%u\n",
+					lf_size, lf->lf_fname, de_inode));
+	if (filldir(dirent, lf->lf_fname, lf_size, pos, de_inode,
+			DT_UNKNOWN) < 0) {
+		qnx6_put_page(page);
+		return 0;
+	}
+
+	qnx6_put_page(page);
+	/* success */
+	return 1;
+}
+
+static int qnx6_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+	struct inode *inode = filp->f_path.dentry->d_inode;
+	struct super_block *s = inode->i_sb;
+	struct qnx6_sb_info *sbi = QNX6_SB(s);
+	loff_t pos = filp->f_pos & (QNX6_DIR_ENTRY_SIZE - 1);
+	unsigned long npages = dir_pages(inode);
+	unsigned long n = pos >> PAGE_CACHE_SHIFT;
+	unsigned start = (pos & ~PAGE_CACHE_MASK) / QNX6_DIR_ENTRY_SIZE;
+	bool done = false;
+
+	if (filp->f_pos >= inode->i_size)
+		return 0;
+
+	for ( ; !done && n < npages; n++, start = 0) {
+		struct page *page = qnx6_get_page(inode, n);
+		int limit = last_entry(inode, n);
+		struct qnx6_dir_entry *de;
+		int i = start;
+
+		if (IS_ERR(page)) {
+			printk(KERN_ERR "qnx6_readdir: read failed\n");
+			filp->f_pos = (n + 1) << PAGE_CACHE_SHIFT;
+			return PTR_ERR(page);
+		}
+		de = ((struct qnx6_dir_entry *)page_address(page)) + start;
+		for (; i < limit; i++, de++, pos += QNX6_DIR_ENTRY_SIZE) {
+			int size = de->de_size;
+			u32 no_inode = fs32_to_cpu(sbi, de->de_inode);
+
+			if (!no_inode || !size)
+				continue;
+
+			if (size > QNX6_SHORT_NAME_MAX) {
+				/* long filename detected
+				   get the filename from long filename
+				   structure / block */
+				if (!qnx6_dir_longfilename(inode,
+					(struct qnx6_long_dir_entry *)de,
+					dirent, pos, no_inode,
+					filldir)) {
+					done = true;
+					break;
+				}
+			} else {
+				QNX6DEBUG((KERN_INFO "qnx6_readdir:%.*s"
+				   " inode:%u\n", size, de->de_fname,
+							no_inode));
+				if (filldir(dirent, de->de_fname, size,
+				      pos, no_inode, DT_UNKNOWN)
+					< 0) {
+					done = true;
+					break;
+				}
+			}
+		}
+		qnx6_put_page(page);
+	}
+	filp->f_pos = pos;
+	return 0;
+}
+
+/*
+ * check if the long filename is correct.
+ */
+static unsigned qnx6_long_match(int len, const char *name,
+			struct qnx6_long_dir_entry *de, struct inode *dir)
+{
+	struct super_block *s = dir->i_sb;
+	struct qnx6_sb_info *sbi = QNX6_SB(s);
+	struct page *page;
+	int thislen;
+	struct qnx6_long_filename *lf = qnx6_longname(s, de, &page);
+
+	if (IS_ERR(lf))
+		return 0;
+
+	thislen = fs16_to_cpu(sbi, lf->lf_size);
+	if (len != thislen) {
+		qnx6_put_page(page);
+		return 0;
+	}
+	if (memcmp(name, lf->lf_fname, len) == 0) {
+		qnx6_put_page(page);
+		return fs32_to_cpu(sbi, de->de_inode);
+	}
+	qnx6_put_page(page);
+	return 0;
+}
+
+/*
+ * check if the filename is correct.
+ */
+static unsigned qnx6_match(struct super_block *s, int len, const char *name,
+			struct qnx6_dir_entry *de)
+{
+	struct qnx6_sb_info *sbi = QNX6_SB(s);
+	if (memcmp(name, de->de_fname, len) == 0)
+		return fs32_to_cpu(sbi, de->de_inode);
+	return 0;
+}
+
+
+unsigned qnx6_find_entry(int len, struct inode *dir, const char *name,
+			 struct page **res_page)
+{
+	struct super_block *s = dir->i_sb;
+	struct qnx6_inode_info *ei = QNX6_I(dir);
+	struct page *page = NULL;
+	unsigned long start, n;
+	unsigned long npages = dir_pages(dir);
+	unsigned ino;
+	struct qnx6_dir_entry *de;
+	struct qnx6_long_dir_entry *lde;
+
+	*res_page = NULL;
+
+	if (npages == 0)
+		return 0;
+	start = ei->i_dir_start_lookup;
+	if (start >= npages)
+		start = 0;
+	n = start;
+
+	do {
+		page = qnx6_get_page(dir, n);
+		if (!IS_ERR(page)) {
+			int limit = last_entry(dir, n);
+			int i;
+
+			de = (struct qnx6_dir_entry *)page_address(page);
+			for (i = 0; i < limit; i++, de++) {
+				if (len <= QNX6_SHORT_NAME_MAX) {
+					/* short filename */
+					if (len != de->de_size)
+						continue;
+					ino = qnx6_match(s, len, name, de);
+					if (ino)
+						goto found;
+				} else if (de->de_size == 0xff) {
+					/* deal with long filename */
+					lde = (struct qnx6_long_dir_entry *)de;
+					ino = qnx6_long_match(len,
+								name, lde, dir);
+					if (ino)
+						goto found;
+				} else
+					printk(KERN_ERR "qnx6: undefined "
+						"filename size in inode.\n");
+			}
+			qnx6_put_page(page);
+		}
+
+		if (++n >= npages)
+			n = 0;
+	} while (n != start);
+	return 0;
+
+found:
+	*res_page = page;
+	ei->i_dir_start_lookup = n;
+	return ino;
+}
+
+const struct file_operations qnx6_dir_operations = {
+	.llseek		= generic_file_llseek,
+	.read		= generic_read_dir,
+	.readdir	= qnx6_readdir,
+	.fsync		= generic_file_fsync,
+};
+
+const struct inode_operations qnx6_dir_inode_operations = {
+	.lookup		= qnx6_lookup,
+};
diff --git a/fs/qnx6/inode.c b/fs/qnx6/inode.c
new file mode 100644
index 0000000..e44012d
--- /dev/null
+++ b/fs/qnx6/inode.c
@@ -0,0 +1,698 @@
+/*
+ * QNX6 file system, Linux implementation.
+ *
+ * Version : 1.0.0
+ *
+ * History :
+ *
+ * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
+ * 16-02-2012 pagemap extension by Al Viro
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/highuid.h>
+#include <linux/pagemap.h>
+#include <linux/buffer_head.h>
+#include <linux/writeback.h>
+#include <linux/statfs.h>
+#include <linux/parser.h>
+#include <linux/seq_file.h>
+#include <linux/mount.h>
+#include <linux/crc32.h>
+#include <linux/mpage.h>
+#include "qnx6.h"
+
+static const struct super_operations qnx6_sops;
+
+static void qnx6_put_super(struct super_block *sb);
+static struct inode *qnx6_alloc_inode(struct super_block *sb);
+static void qnx6_destroy_inode(struct inode *inode);
+static int qnx6_remount(struct super_block *sb, int *flags, char *data);
+static int qnx6_statfs(struct dentry *dentry, struct kstatfs *buf);
+static int qnx6_show_options(struct seq_file *seq, struct dentry *root);
+
+static const struct super_operations qnx6_sops = {
+	.alloc_inode	= qnx6_alloc_inode,
+	.destroy_inode	= qnx6_destroy_inode,
+	.put_super	= qnx6_put_super,
+	.statfs		= qnx6_statfs,
+	.remount_fs	= qnx6_remount,
+	.show_options	= qnx6_show_options,
+};
+
+static int qnx6_show_options(struct seq_file *seq, struct dentry *root)
+{
+	struct super_block *sb = root->d_sb;
+	struct qnx6_sb_info *sbi = QNX6_SB(sb);
+
+	if (sbi->s_mount_opt & QNX6_MOUNT_MMI_FS)
+		seq_puts(seq, ",mmi_fs");
+	return 0;
+}
+
+static int qnx6_remount(struct super_block *sb, int *flags, char *data)
+{
+	*flags |= MS_RDONLY;
+	return 0;
+}
+
+static unsigned qnx6_get_devblock(struct super_block *sb, __fs32 block)
+{
+	struct qnx6_sb_info *sbi = QNX6_SB(sb);
+	return fs32_to_cpu(sbi, block) + sbi->s_blks_off;
+}
+
+static unsigned qnx6_block_map(struct inode *inode, unsigned iblock);
+
+static int qnx6_get_block(struct inode *inode, sector_t iblock,
+			struct buffer_head *bh, int create)
+{
+	unsigned phys;
+
+	QNX6DEBUG((KERN_INFO "qnx6: qnx6_get_block inode=[%ld] iblock=[%ld]\n",
+			inode->i_ino, (unsigned long)iblock));
+
+	phys = qnx6_block_map(inode, iblock);
+	if (phys) {
+		/* logical block is before EOF */
+		map_bh(bh, inode->i_sb, phys);
+	}
+	return 0;
+}
+
+static int qnx6_check_blockptr(__fs32 ptr)
+{
+	if (ptr == ~(__fs32)0) {
+		printk(KERN_ERR "qnx6: hit unused blockpointer.\n");
+		return 0;
+	}
+	return 1;
+}
+
+static int qnx6_readpage(struct file *file, struct page *page)
+{
+	return mpage_readpage(page, qnx6_get_block);
+}
+
+static int qnx6_readpages(struct file *file, struct address_space *mapping,
+		   struct list_head *pages, unsigned nr_pages)
+{
+	return mpage_readpages(mapping, pages, nr_pages, qnx6_get_block);
+}
+
+/*
+ * returns the block number for the no-th element in the tree
+ * inodebits requred as there are multiple inodes in one inode block
+ */
+static unsigned qnx6_block_map(struct inode *inode, unsigned no)
+{
+	struct super_block *s = inode->i_sb;
+	struct qnx6_sb_info *sbi = QNX6_SB(s);
+	struct qnx6_inode_info *ei = QNX6_I(inode);
+	unsigned block = 0;
+	struct buffer_head *bh;
+	__fs32 ptr;
+	int levelptr;
+	int ptrbits = sbi->s_ptrbits;
+	int bitdelta;
+	u32 mask = (1 << ptrbits) - 1;
+	int depth = ei->di_filelevels;
+	int i;
+
+	bitdelta = ptrbits * depth;
+	levelptr = no >> bitdelta;
+
+	if (levelptr > QNX6_NO_DIRECT_POINTERS - 1) {
+		printk(KERN_ERR "qnx6:Requested file block number (%u) too big.",
+				no);
+		return 0;
+	}
+
+	block = qnx6_get_devblock(s, ei->di_block_ptr[levelptr]);
+
+	for (i = 0; i < depth; i++) {
+		bh = sb_bread(s, block);
+		if (!bh) {
+			printk(KERN_ERR "qnx6:Error reading block (%u)\n",
+					block);
+			return 0;
+		}
+		bitdelta -= ptrbits;
+		levelptr = (no >> bitdelta) & mask;
+		ptr = ((__fs32 *)bh->b_data)[levelptr];
+
+		if (!qnx6_check_blockptr(ptr))
+			return 0;
+
+		block = qnx6_get_devblock(s, ptr);
+		brelse(bh);
+	}
+	return block;
+}
+
+static int qnx6_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+	struct super_block *sb = dentry->d_sb;
+	struct qnx6_sb_info *sbi = QNX6_SB(sb);
+	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
+
+	buf->f_type    = sb->s_magic;
+	buf->f_bsize   = sb->s_blocksize;
+	buf->f_blocks  = fs32_to_cpu(sbi, sbi->sb->sb_num_blocks);
+	buf->f_bfree   = fs32_to_cpu(sbi, sbi->sb->sb_free_blocks);
+	buf->f_files   = fs32_to_cpu(sbi, sbi->sb->sb_num_inodes);
+	buf->f_ffree   = fs32_to_cpu(sbi, sbi->sb->sb_free_inodes);
+	buf->f_bavail  = buf->f_bfree;
+	buf->f_namelen = QNX6_LONG_NAME_MAX;
+	buf->f_fsid.val[0] = (u32)id;
+	buf->f_fsid.val[1] = (u32)(id >> 32);
+
+	return 0;
+}
+
+/*
+ * Check the root directory of the filesystem to make sure
+ * it really _is_ a qnx6 filesystem, and to check the size
+ * of the directory entry.
+ */
+static const char *qnx6_checkroot(struct super_block *s)
+{
+	static char match_root[2][3] = {".\0\0", "..\0"};
+	int i, error = 0;
+	struct qnx6_dir_entry *dir_entry;
+	struct inode *root = s->s_root->d_inode;
+	struct address_space *mapping = root->i_mapping;
+	struct page *page = read_mapping_page(mapping, 0, NULL);
+	if (IS_ERR(page))
+		return "error reading root directory";
+	kmap(page);
+	dir_entry = page_address(page);
+	for (i = 0; i < 2; i++) {
+		/* maximum 3 bytes - due to match_root limitation */
+		if (strncmp(dir_entry[i].de_fname, match_root[i], 3))
+			error = 1;
+	}
+	qnx6_put_page(page);
+	if (error)
+		return "error reading root directory.";
+	return NULL;
+}
+
+#ifdef CONFIG_QNX6FS_DEBUG
+void qnx6_superblock_debug(struct qnx6_super_block *sb, struct super_block *s)
+{
+	struct qnx6_sb_info *sbi = QNX6_SB(s);
+
+	QNX6DEBUG((KERN_INFO "magic: %08x\n",
+				fs32_to_cpu(sbi, sb->sb_magic)));
+	QNX6DEBUG((KERN_INFO "checksum: %08x\n",
+				fs32_to_cpu(sbi, sb->sb_checksum)));
+	QNX6DEBUG((KERN_INFO "serial: %llx\n",
+				fs64_to_cpu(sbi, sb->sb_serial)));
+	QNX6DEBUG((KERN_INFO "flags: %08x\n",
+				fs32_to_cpu(sbi, sb->sb_flags)));
+	QNX6DEBUG((KERN_INFO "blocksize: %08x\n",
+				fs32_to_cpu(sbi, sb->sb_blocksize)));
+	QNX6DEBUG((KERN_INFO "num_inodes: %08x\n",
+				fs32_to_cpu(sbi, sb->sb_num_inodes)));
+	QNX6DEBUG((KERN_INFO "free_inodes: %08x\n",
+				fs32_to_cpu(sbi, sb->sb_free_inodes)));
+	QNX6DEBUG((KERN_INFO "num_blocks: %08x\n",
+				fs32_to_cpu(sbi, sb->sb_num_blocks)));
+	QNX6DEBUG((KERN_INFO "free_blocks: %08x\n",
+				fs32_to_cpu(sbi, sb->sb_free_blocks)));
+	QNX6DEBUG((KERN_INFO "inode_levels: %02x\n",
+				sb->Inode.levels));
+}
+#endif
+
+enum {
+	Opt_mmifs,
+	Opt_err
+};
+
+static const match_table_t tokens = {
+	{Opt_mmifs, "mmi_fs"},
+	{Opt_err, NULL}
+};
+
+static int qnx6_parse_options(char *options, struct super_block *sb)
+{
+	char *p;
+	struct qnx6_sb_info *sbi = QNX6_SB(sb);
+	substring_t args[MAX_OPT_ARGS];
+
+	if (!options)
+		return 1;
+
+	while ((p = strsep(&options, ",")) != NULL) {
+		int token;
+		if (!*p)
+			continue;
+
+		token = match_token(p, tokens, args);
+		switch (token) {
+		case Opt_mmifs:
+			set_opt(sbi->s_mount_opt, MMI_FS);
+			break;
+		default:
+			return 0;
+		}
+	}
+	return 1;
+}
+
+static struct buffer_head *qnx6_check_first_superblock(struct super_block *s,
+				int offset, int silent)
+{
+	struct qnx6_sb_info *sbi = QNX6_SB(s);
+	struct buffer_head *bh;
+	struct qnx6_super_block *sb;
+
+	/* Check the superblock signatures
+	   start with the first superblock */
+	bh = sb_bread(s, offset);
+	if (!bh) {
+		printk(KERN_ERR "qnx6: unable to read the first superblock\n");
+		return NULL;
+	}
+	sb = (struct qnx6_super_block *)bh->b_data;
+	if (fs32_to_cpu(sbi, sb->sb_magic) != QNX6_SUPER_MAGIC) {
+		sbi->s_bytesex = BYTESEX_BE;
+		if (fs32_to_cpu(sbi, sb->sb_magic) == QNX6_SUPER_MAGIC) {
+			/* we got a big endian fs */
+			QNX6DEBUG((KERN_INFO "qnx6: fs got different"
+					" endianess.\n"));
+			return bh;
+		} else
+			sbi->s_bytesex = BYTESEX_LE;
+		if (!silent) {
+			if (offset == 0) {
+				printk(KERN_ERR "qnx6: wrong signature (magic)"
+					" in superblock #1.\n");
+			} else {
+				printk(KERN_INFO "qnx6: wrong signature (magic)"
+					" at position (0x%lx) - will try"
+					" alternative position (0x0000).\n",
+						offset * s->s_blocksize);
+			}
+		}
+		brelse(bh);
+		return NULL;
+	}
+	return bh;
+}
+
+static struct inode *qnx6_private_inode(struct super_block *s,
+					struct qnx6_root_node *p);
+
+static int qnx6_fill_super(struct super_block *s, void *data, int silent)
+{
+	struct buffer_head *bh1 = NULL, *bh2 = NULL;
+	struct qnx6_super_block *sb1 = NULL, *sb2 = NULL;
+	struct qnx6_sb_info *sbi;
+	struct inode *root;
+	const char *errmsg;
+	struct qnx6_sb_info *qs;
+	int ret = -EINVAL;
+	u64 offset;
+	int bootblock_offset = QNX6_BOOTBLOCK_SIZE;
+
+	qs = kzalloc(sizeof(struct qnx6_sb_info), GFP_KERNEL);
+	if (!qs)
+		return -ENOMEM;
+	s->s_fs_info = qs;
+
+	/* Superblock always is 512 Byte long */
+	if (!sb_set_blocksize(s, QNX6_SUPERBLOCK_SIZE)) {
+		printk(KERN_ERR "qnx6: unable to set blocksize\n");
+		goto outnobh;
+	}
+
+	/* parse the mount-options */
+	if (!qnx6_parse_options((char *) data, s)) {
+		printk(KERN_ERR "qnx6: invalid mount options.\n");
+		goto outnobh;
+	}
+	if (test_opt(s, MMI_FS)) {
+		sb1 = qnx6_mmi_fill_super(s, silent);
+		if (sb1)
+			goto mmi_success;
+		else
+			goto outnobh;
+	}
+	sbi = QNX6_SB(s);
+	sbi->s_bytesex = BYTESEX_LE;
+	/* Check the superblock signatures
+	   start with the first superblock */
+	bh1 = qnx6_check_first_superblock(s,
+		bootblock_offset / QNX6_SUPERBLOCK_SIZE, silent);
+	if (!bh1) {
+		/* try again without bootblock offset */
+		bh1 = qnx6_check_first_superblock(s, 0, silent);
+		if (!bh1) {
+			printk(KERN_ERR "qnx6: unable to read the first superblock\n");
+			goto outnobh;
+		}
+		/* seems that no bootblock at partition start */
+		bootblock_offset = 0;
+	}
+	sb1 = (struct qnx6_super_block *)bh1->b_data;
+
+#ifdef CONFIG_QNX6FS_DEBUG
+	qnx6_superblock_debug(sb1, s);
+#endif
+
+	/* checksum check - start at byte 8 and end at byte 512 */
+	if (fs32_to_cpu(sbi, sb1->sb_checksum) !=
+			crc32_be(0, (char *)(bh1->b_data + 8), 504)) {
+		printk(KERN_ERR "qnx6: superblock #1 checksum error\n");
+		goto out;
+	}
+
+	/* set new blocksize */
+	if (!sb_set_blocksize(s, fs32_to_cpu(sbi, sb1->sb_blocksize))) {
+		printk(KERN_ERR "qnx6: unable to set blocksize\n");
+		goto out;
+	}
+	/* blocksize invalidates bh - pull it back in */
+	brelse(bh1);
+	bh1 = sb_bread(s, bootblock_offset >> s->s_blocksize_bits);
+	if (!bh1)
+		goto outnobh;
+	sb1 = (struct qnx6_super_block *)bh1->b_data;
+
+	/* calculate second superblock blocknumber */
+	offset = fs32_to_cpu(sbi, sb1->sb_num_blocks) +
+		(bootblock_offset >> s->s_blocksize_bits) +
+		(QNX6_SUPERBLOCK_AREA >> s->s_blocksize_bits);
+
+	/* set bootblock offset */
+	sbi->s_blks_off = (bootblock_offset >> s->s_blocksize_bits) +
+			  (QNX6_SUPERBLOCK_AREA >> s->s_blocksize_bits);
+
+	/* next the second superblock */
+	bh2 = sb_bread(s, offset);
+	if (!bh2) {
+		printk(KERN_ERR "qnx6: unable to read the second superblock\n");
+		goto out;
+	}
+	sb2 = (struct qnx6_super_block *)bh2->b_data;
+	if (fs32_to_cpu(sbi, sb2->sb_magic) != QNX6_SUPER_MAGIC) {
+		if (!silent)
+			printk(KERN_ERR "qnx6: wrong signature (magic)"
+					" in superblock #2.\n");
+		goto out;
+	}
+
+	/* checksum check - start at byte 8 and end at byte 512 */
+	if (fs32_to_cpu(sbi, sb2->sb_checksum) !=
+				crc32_be(0, (char *)(bh2->b_data + 8), 504)) {
+		printk(KERN_ERR "qnx6: superblock #2 checksum error\n");
+		goto out;
+	}
+
+	if (fs64_to_cpu(sbi, sb1->sb_serial) >=
+					fs64_to_cpu(sbi, sb2->sb_serial)) {
+		/* superblock #1 active */
+		sbi->sb_buf = bh1;
+		sbi->sb = (struct qnx6_super_block *)bh1->b_data;
+		brelse(bh2);
+		printk(KERN_INFO "qnx6: superblock #1 active\n");
+	} else {
+		/* superblock #2 active */
+		sbi->sb_buf = bh2;
+		sbi->sb = (struct qnx6_super_block *)bh2->b_data;
+		brelse(bh1);
+		printk(KERN_INFO "qnx6: superblock #2 active\n");
+	}
+mmi_success:
+	/* sanity check - limit maximum indirect pointer levels */
+	if (sb1->Inode.levels > QNX6_PTR_MAX_LEVELS) {
+		printk(KERN_ERR "qnx6: too many inode levels (max %i, sb %i)\n",
+			QNX6_PTR_MAX_LEVELS, sb1->Inode.levels);
+		goto out;
+	}
+	if (sb1->Longfile.levels > QNX6_PTR_MAX_LEVELS) {
+		printk(KERN_ERR "qnx6: too many longfilename levels"
+				" (max %i, sb %i)\n",
+			QNX6_PTR_MAX_LEVELS, sb1->Longfile.levels);
+		goto out;
+	}
+	s->s_op = &qnx6_sops;
+	s->s_magic = QNX6_SUPER_MAGIC;
+	s->s_flags |= MS_RDONLY;        /* Yup, read-only yet */
+
+	/* ease the later tree level calculations */
+	sbi = QNX6_SB(s);
+	sbi->s_ptrbits = ilog2(s->s_blocksize / 4);
+	sbi->inodes = qnx6_private_inode(s, &sb1->Inode);
+	if (!sbi->inodes)
+		goto out;
+	sbi->longfile = qnx6_private_inode(s, &sb1->Longfile);
+	if (!sbi->longfile)
+		goto out1;
+
+	/* prefetch root inode */
+	root = qnx6_iget(s, QNX6_ROOT_INO);
+	if (IS_ERR(root)) {
+		printk(KERN_ERR "qnx6: get inode failed\n");
+		ret = PTR_ERR(root);
+		goto out2;
+	}
+
+	ret = -ENOMEM;
+	s->s_root = d_make_root(root);
+	if (!s->s_root)
+		goto out2;
+
+	ret = -EINVAL;
+	errmsg = qnx6_checkroot(s);
+	if (errmsg != NULL) {
+		if (!silent)
+			printk(KERN_ERR "qnx6: %s\n", errmsg);
+		goto out3;
+	}
+	return 0;
+
+out3:
+	dput(s->s_root);
+	s->s_root = NULL;
+out2:
+	iput(sbi->longfile);
+out1:
+	iput(sbi->inodes);
+out:
+	if (bh1)
+		brelse(bh1);
+	if (bh2)
+		brelse(bh2);
+outnobh:
+	kfree(qs);
+	s->s_fs_info = NULL;
+	return ret;
+}
+
+static void qnx6_put_super(struct super_block *sb)
+{
+	struct qnx6_sb_info *qs = QNX6_SB(sb);
+	brelse(qs->sb_buf);
+	iput(qs->longfile);
+	iput(qs->inodes);
+	kfree(qs);
+	sb->s_fs_info = NULL;
+	return;
+}
+
+static sector_t qnx6_bmap(struct address_space *mapping, sector_t block)
+{
+	return generic_block_bmap(mapping, block, qnx6_get_block);
+}
+static const struct address_space_operations qnx6_aops = {
+	.readpage	= qnx6_readpage,
+	.readpages	= qnx6_readpages,
+	.bmap		= qnx6_bmap
+};
+
+static struct inode *qnx6_private_inode(struct super_block *s,
+					struct qnx6_root_node *p)
+{
+	struct inode *inode = new_inode(s);
+	if (inode) {
+		struct qnx6_inode_info *ei = QNX6_I(inode);
+		struct qnx6_sb_info *sbi = QNX6_SB(s);
+		inode->i_size = fs64_to_cpu(sbi, p->size);
+		memcpy(ei->di_block_ptr, p->ptr, sizeof(p->ptr));
+		ei->di_filelevels = p->levels;
+		inode->i_mode = S_IFREG | S_IRUSR; /* probably wrong */
+		inode->i_mapping->a_ops = &qnx6_aops;
+	}
+	return inode;
+}
+
+struct inode *qnx6_iget(struct super_block *sb, unsigned ino)
+{
+	struct qnx6_sb_info *sbi = QNX6_SB(sb);
+	struct qnx6_inode_entry *raw_inode;
+	struct inode *inode;
+	struct qnx6_inode_info	*ei;
+	struct address_space *mapping;
+	struct page *page;
+	u32 n, offs;
+
+	inode = iget_locked(sb, ino);
+	if (!inode)
+		return ERR_PTR(-ENOMEM);
+	if (!(inode->i_state & I_NEW))
+		return inode;
+
+	ei = QNX6_I(inode);
+
+	inode->i_mode = 0;
+
+	if (ino == 0) {
+		printk(KERN_ERR "qnx6: bad inode number on dev %s: %u is "
+				"out of range\n",
+		       sb->s_id, ino);
+		iget_failed(inode);
+		return ERR_PTR(-EIO);
+	}
+	n = (ino - 1) >> (PAGE_CACHE_SHIFT - QNX6_INODE_SIZE_BITS);
+	offs = (ino - 1) & (~PAGE_CACHE_MASK >> QNX6_INODE_SIZE_BITS);
+	mapping = sbi->inodes->i_mapping;
+	page = read_mapping_page(mapping, n, NULL);
+	if (IS_ERR(page)) {
+		printk(KERN_ERR "qnx6: major problem: unable to read inode from "
+		       "dev %s\n", sb->s_id);
+		iget_failed(inode);
+		return ERR_CAST(page);
+	}
+	kmap(page);
+	raw_inode = ((struct qnx6_inode_entry *)page_address(page)) + offs;
+
+	inode->i_mode    = fs16_to_cpu(sbi, raw_inode->di_mode);
+	inode->i_uid     = (uid_t)fs32_to_cpu(sbi, raw_inode->di_uid);
+	inode->i_gid     = (gid_t)fs32_to_cpu(sbi, raw_inode->di_gid);
+	inode->i_size    = fs64_to_cpu(sbi, raw_inode->di_size);
+	inode->i_mtime.tv_sec   = fs32_to_cpu(sbi, raw_inode->di_mtime);
+	inode->i_mtime.tv_nsec = 0;
+	inode->i_atime.tv_sec   = fs32_to_cpu(sbi, raw_inode->di_atime);
+	inode->i_atime.tv_nsec = 0;
+	inode->i_ctime.tv_sec   = fs32_to_cpu(sbi, raw_inode->di_ctime);
+	inode->i_ctime.tv_nsec = 0;
+
+	/* calc blocks based on 512 byte blocksize */
+	inode->i_blocks = (inode->i_size + 511) >> 9;
+
+	memcpy(&ei->di_block_ptr, &raw_inode->di_block_ptr,
+				sizeof(raw_inode->di_block_ptr));
+	ei->di_filelevels = raw_inode->di_filelevels;
+
+	if (S_ISREG(inode->i_mode)) {
+		inode->i_fop = &generic_ro_fops;
+		inode->i_mapping->a_ops = &qnx6_aops;
+	} else if (S_ISDIR(inode->i_mode)) {
+		inode->i_op = &qnx6_dir_inode_operations;
+		inode->i_fop = &qnx6_dir_operations;
+		inode->i_mapping->a_ops = &qnx6_aops;
+	} else if (S_ISLNK(inode->i_mode)) {
+		inode->i_op = &page_symlink_inode_operations;
+		inode->i_mapping->a_ops = &qnx6_aops;
+	} else
+		init_special_inode(inode, inode->i_mode, 0);
+	qnx6_put_page(page);
+	unlock_new_inode(inode);
+	return inode;
+}
+
+static struct kmem_cache *qnx6_inode_cachep;
+
+static struct inode *qnx6_alloc_inode(struct super_block *sb)
+{
+	struct qnx6_inode_info *ei;
+	ei = kmem_cache_alloc(qnx6_inode_cachep, GFP_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void qnx6_i_callback(struct rcu_head *head)
+{
+	struct inode *inode = container_of(head, struct inode, i_rcu);
+	INIT_LIST_HEAD(&inode->i_dentry);
+	kmem_cache_free(qnx6_inode_cachep, QNX6_I(inode));
+}
+
+static void qnx6_destroy_inode(struct inode *inode)
+{
+	call_rcu(&inode->i_rcu, qnx6_i_callback);
+}
+
+static void init_once(void *foo)
+{
+	struct qnx6_inode_info *ei = (struct qnx6_inode_info *) foo;
+
+	inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+	qnx6_inode_cachep = kmem_cache_create("qnx6_inode_cache",
+					     sizeof(struct qnx6_inode_info),
+					     0, (SLAB_RECLAIM_ACCOUNT|
+						SLAB_MEM_SPREAD),
+					     init_once);
+	if (!qnx6_inode_cachep)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	kmem_cache_destroy(qnx6_inode_cachep);
+}
+
+static struct dentry *qnx6_mount(struct file_system_type *fs_type,
+	int flags, const char *dev_name, void *data)
+{
+	return mount_bdev(fs_type, flags, dev_name, data, qnx6_fill_super);
+}
+
+static struct file_system_type qnx6_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "qnx6",
+	.mount		= qnx6_mount,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
+};
+
+static int __init init_qnx6_fs(void)
+{
+	int err;
+
+	err = init_inodecache();
+	if (err)
+		return err;
+
+	err = register_filesystem(&qnx6_fs_type);
+	if (err) {
+		destroy_inodecache();
+		return err;
+	}
+
+	printk(KERN_INFO "QNX6 filesystem 1.0.0 registered.\n");
+	return 0;
+}
+
+static void __exit exit_qnx6_fs(void)
+{
+	unregister_filesystem(&qnx6_fs_type);
+	destroy_inodecache();
+}
+
+module_init(init_qnx6_fs)
+module_exit(exit_qnx6_fs)
+MODULE_LICENSE("GPL");
diff --git a/fs/qnx6/namei.c b/fs/qnx6/namei.c
new file mode 100644
index 0000000..8a97289
--- /dev/null
+++ b/fs/qnx6/namei.c
@@ -0,0 +1,42 @@
+/*
+ * QNX6 file system, Linux implementation.
+ *
+ * Version : 1.0.0
+ *
+ * History :
+ *
+ * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
+ * 16-02-2012 pagemap extension by Al Viro
+ *
+ */
+
+#include "qnx6.h"
+
+struct dentry *qnx6_lookup(struct inode *dir, struct dentry *dentry,
+				struct nameidata *nd)
+{
+	unsigned ino;
+	struct page *page;
+	struct inode *foundinode = NULL;
+	const char *name = dentry->d_name.name;
+	int len = dentry->d_name.len;
+
+	if (len > QNX6_LONG_NAME_MAX)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	ino = qnx6_find_entry(len, dir, name, &page);
+	if (ino) {
+		foundinode = qnx6_iget(dir->i_sb, ino);
+		qnx6_put_page(page);
+		if (IS_ERR(foundinode)) {
+			QNX6DEBUG((KERN_ERR "qnx6: lookup->iget -> "
+				" error %ld\n", PTR_ERR(foundinode)));
+			return ERR_CAST(foundinode);
+		}
+	} else {
+		QNX6DEBUG((KERN_INFO "qnx6_lookup: not found %s\n", name));
+		return NULL;
+	}
+	d_add(dentry, foundinode);
+	return NULL;
+}
diff --git a/fs/qnx6/qnx6.h b/fs/qnx6/qnx6.h
new file mode 100644
index 0000000..6c5e02a
--- /dev/null
+++ b/fs/qnx6/qnx6.h
@@ -0,0 +1,135 @@
+/*
+ * QNX6 file system, Linux implementation.
+ *
+ * Version : 1.0.0
+ *
+ * History :
+ *
+ * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
+ * 16-02-2012 page map extension by Al Viro
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+
+typedef __u16 __bitwise __fs16;
+typedef __u32 __bitwise __fs32;
+typedef __u64 __bitwise __fs64;
+
+#include <linux/qnx6_fs.h>
+
+#ifdef CONFIG_QNX6FS_DEBUG
+#define QNX6DEBUG(X) printk X
+#else
+#define QNX6DEBUG(X) (void) 0
+#endif
+
+struct qnx6_sb_info {
+	struct buffer_head	*sb_buf;	/* superblock buffer */
+	struct qnx6_super_block	*sb;		/* our superblock */
+	int			s_blks_off;	/* blkoffset fs-startpoint */
+	int			s_ptrbits;	/* indirect pointer bitfield */
+	unsigned long		s_mount_opt;	/* all mount options */
+	int			s_bytesex;	/* holds endianess info */
+	struct inode *		inodes;
+	struct inode *		longfile;
+};
+
+struct qnx6_inode_info {
+	__fs32			di_block_ptr[QNX6_NO_DIRECT_POINTERS];
+	__u8			di_filelevels;
+	__u32			i_dir_start_lookup;
+	struct inode		vfs_inode;
+};
+
+extern struct inode *qnx6_iget(struct super_block *sb, unsigned ino);
+extern struct dentry *qnx6_lookup(struct inode *dir, struct dentry *dentry,
+					struct nameidata *nd);
+
+#ifdef CONFIG_QNX6FS_DEBUG
+extern void qnx6_superblock_debug(struct qnx6_super_block *,
+						struct super_block *);
+#endif
+
+extern const struct inode_operations qnx6_dir_inode_operations;
+extern const struct file_operations qnx6_dir_operations;
+
+static inline struct qnx6_sb_info *QNX6_SB(struct super_block *sb)
+{
+	return sb->s_fs_info;
+}
+
+static inline struct qnx6_inode_info *QNX6_I(struct inode *inode)
+{
+	return container_of(inode, struct qnx6_inode_info, vfs_inode);
+}
+
+#define clear_opt(o, opt)		(o &= ~(QNX6_MOUNT_##opt))
+#define set_opt(o, opt)			(o |= (QNX6_MOUNT_##opt))
+#define test_opt(sb, opt)		(QNX6_SB(sb)->s_mount_opt & \
+					 QNX6_MOUNT_##opt)
+enum {
+	BYTESEX_LE,
+	BYTESEX_BE,
+};
+
+static inline __u64 fs64_to_cpu(struct qnx6_sb_info *sbi, __fs64 n)
+{
+	if (sbi->s_bytesex == BYTESEX_LE)
+		return le64_to_cpu((__force __le64)n);
+	else
+		return be64_to_cpu((__force __be64)n);
+}
+
+static inline __fs64 cpu_to_fs64(struct qnx6_sb_info *sbi, __u64 n)
+{
+	if (sbi->s_bytesex == BYTESEX_LE)
+		return (__force __fs64)cpu_to_le64(n);
+	else
+		return (__force __fs64)cpu_to_be64(n);
+}
+
+static inline __u32 fs32_to_cpu(struct qnx6_sb_info *sbi, __fs32 n)
+{
+	if (sbi->s_bytesex == BYTESEX_LE)
+		return le32_to_cpu((__force __le32)n);
+	else
+		return be32_to_cpu((__force __be32)n);
+}
+
+static inline __fs32 cpu_to_fs32(struct qnx6_sb_info *sbi, __u32 n)
+{
+	if (sbi->s_bytesex == BYTESEX_LE)
+		return (__force __fs32)cpu_to_le32(n);
+	else
+		return (__force __fs32)cpu_to_be32(n);
+}
+
+static inline __u16 fs16_to_cpu(struct qnx6_sb_info *sbi, __fs16 n)
+{
+	if (sbi->s_bytesex == BYTESEX_LE)
+		return le16_to_cpu((__force __le16)n);
+	else
+		return be16_to_cpu((__force __be16)n);
+}
+
+static inline __fs16 cpu_to_fs16(struct qnx6_sb_info *sbi, __u16 n)
+{
+	if (sbi->s_bytesex == BYTESEX_LE)
+		return (__force __fs16)cpu_to_le16(n);
+	else
+		return (__force __fs16)cpu_to_be16(n);
+}
+
+extern struct qnx6_super_block *qnx6_mmi_fill_super(struct super_block *s,
+						    int silent);
+
+static inline void qnx6_put_page(struct page *page)
+{
+	kunmap(page);
+	page_cache_release(page);
+}
+
+extern unsigned qnx6_find_entry(int len, struct inode *dir, const char *name,
+				struct page **res_page);
diff --git a/fs/qnx6/super_mmi.c b/fs/qnx6/super_mmi.c
new file mode 100644
index 0000000..29c32cb
--- /dev/null
+++ b/fs/qnx6/super_mmi.c
@@ -0,0 +1,150 @@
+/*
+ * QNX6 file system, Linux implementation.
+ *
+ * Version : 1.0.0
+ *
+ * History :
+ *
+ * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
+ *
+ */
+
+#include <linux/buffer_head.h>
+#include <linux/slab.h>
+#include <linux/crc32.h>
+#include "qnx6.h"
+
+static void qnx6_mmi_copy_sb(struct qnx6_super_block *qsb,
+		struct qnx6_mmi_super_block *sb)
+{
+	qsb->sb_magic = sb->sb_magic;
+	qsb->sb_checksum = sb->sb_checksum;
+	qsb->sb_serial = sb->sb_serial;
+	qsb->sb_blocksize = sb->sb_blocksize;
+	qsb->sb_num_inodes = sb->sb_num_inodes;
+	qsb->sb_free_inodes = sb->sb_free_inodes;
+	qsb->sb_num_blocks = sb->sb_num_blocks;
+	qsb->sb_free_blocks = sb->sb_free_blocks;
+
+	/* the rest of the superblock is the same */
+	memcpy(&qsb->Inode, &sb->Inode, sizeof(sb->Inode));
+	memcpy(&qsb->Bitmap, &sb->Bitmap, sizeof(sb->Bitmap));
+	memcpy(&qsb->Longfile, &sb->Longfile, sizeof(sb->Longfile));
+}
+
+struct qnx6_super_block *qnx6_mmi_fill_super(struct super_block *s, int silent)
+{
+	struct buffer_head *bh1, *bh2 = NULL;
+	struct qnx6_mmi_super_block *sb1, *sb2;
+	struct qnx6_super_block *qsb = NULL;
+	struct qnx6_sb_info *sbi;
+	__u64 offset;
+
+	/* Check the superblock signatures
+	   start with the first superblock */
+	bh1 = sb_bread(s, 0);
+	if (!bh1) {
+		printk(KERN_ERR "qnx6: Unable to read first mmi superblock\n");
+		return NULL;
+	}
+	sb1 = (struct qnx6_mmi_super_block *)bh1->b_data;
+	sbi = QNX6_SB(s);
+	if (fs32_to_cpu(sbi, sb1->sb_magic) != QNX6_SUPER_MAGIC) {
+		if (!silent) {
+			printk(KERN_ERR "qnx6: wrong signature (magic) in"
+					" superblock #1.\n");
+			goto out;
+		}
+	}
+
+	/* checksum check - start at byte 8 and end at byte 512 */
+	if (fs32_to_cpu(sbi, sb1->sb_checksum) !=
+				crc32_be(0, (char *)(bh1->b_data + 8), 504)) {
+		printk(KERN_ERR "qnx6: superblock #1 checksum error\n");
+		goto out;
+	}
+
+	/* calculate second superblock blocknumber */
+	offset = fs32_to_cpu(sbi, sb1->sb_num_blocks) + QNX6_SUPERBLOCK_AREA /
+					fs32_to_cpu(sbi, sb1->sb_blocksize);
+
+	/* set new blocksize */
+	if (!sb_set_blocksize(s, fs32_to_cpu(sbi, sb1->sb_blocksize))) {
+		printk(KERN_ERR "qnx6: unable to set blocksize\n");
+		goto out;
+	}
+	/* blocksize invalidates bh - pull it back in */
+	brelse(bh1);
+	bh1 = sb_bread(s, 0);
+	if (!bh1)
+		goto out;
+	sb1 = (struct qnx6_mmi_super_block *)bh1->b_data;
+
+	/* read second superblock */
+	bh2 = sb_bread(s, offset);
+	if (!bh2) {
+		printk(KERN_ERR "qnx6: unable to read the second superblock\n");
+		goto out;
+	}
+	sb2 = (struct qnx6_mmi_super_block *)bh2->b_data;
+	if (fs32_to_cpu(sbi, sb2->sb_magic) != QNX6_SUPER_MAGIC) {
+		if (!silent)
+			printk(KERN_ERR "qnx6: wrong signature (magic) in"
+					" superblock #2.\n");
+		goto out;
+	}
+
+	/* checksum check - start at byte 8 and end at byte 512 */
+	if (fs32_to_cpu(sbi, sb2->sb_checksum)
+			!= crc32_be(0, (char *)(bh2->b_data + 8), 504)) {
+		printk(KERN_ERR "qnx6: superblock #1 checksum error\n");
+		goto out;
+	}
+
+	qsb = kmalloc(sizeof(*qsb), GFP_KERNEL);
+	if (!qsb) {
+		printk(KERN_ERR "qnx6: unable to allocate memory.\n");
+		goto out;
+	}
+
+	if (fs64_to_cpu(sbi, sb1->sb_serial) >
+					fs64_to_cpu(sbi, sb2->sb_serial)) {
+		/* superblock #1 active */
+		qnx6_mmi_copy_sb(qsb, sb1);
+#ifdef CONFIG_QNX6FS_DEBUG
+		qnx6_superblock_debug(qsb, s);
+#endif
+		memcpy(bh1->b_data, qsb, sizeof(struct qnx6_super_block));
+
+		sbi->sb_buf = bh1;
+		sbi->sb = (struct qnx6_super_block *)bh1->b_data;
+		brelse(bh2);
+		printk(KERN_INFO "qnx6: superblock #1 active\n");
+	} else {
+		/* superblock #2 active */
+		qnx6_mmi_copy_sb(qsb, sb2);
+#ifdef CONFIG_QNX6FS_DEBUG
+		qnx6_superblock_debug(qsb, s);
+#endif
+		memcpy(bh2->b_data, qsb, sizeof(struct qnx6_super_block));
+
+		sbi->sb_buf = bh2;
+		sbi->sb = (struct qnx6_super_block *)bh2->b_data;
+		brelse(bh1);
+		printk(KERN_INFO "qnx6: superblock #2 active\n");
+	}
+	kfree(qsb);
+
+	/* offset for mmi_fs is just SUPERBLOCK_AREA bytes */
+	sbi->s_blks_off = QNX6_SUPERBLOCK_AREA / s->s_blocksize;
+
+	/* success */
+	return sbi->sb;
+
+out:
+	if (bh1 != NULL)
+		brelse(bh1);
+	if (bh2 != NULL)
+		brelse(bh2);
+	return NULL;
+}
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 8b4f12b..d69a1d1 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -1110,6 +1110,13 @@
 	clear_bit(DQ_BLKS_B, &dquot->dq_flags);
 }
 
+struct dquot_warn {
+	struct super_block *w_sb;
+	qid_t w_dq_id;
+	short w_dq_type;
+	short w_type;
+};
+
 static int warning_issued(struct dquot *dquot, const int warntype)
 {
 	int flag = (warntype == QUOTA_NL_BHARDWARN ||
@@ -1125,41 +1132,42 @@
 #ifdef CONFIG_PRINT_QUOTA_WARNING
 static int flag_print_warnings = 1;
 
-static int need_print_warning(struct dquot *dquot)
+static int need_print_warning(struct dquot_warn *warn)
 {
 	if (!flag_print_warnings)
 		return 0;
 
-	switch (dquot->dq_type) {
+	switch (warn->w_dq_type) {
 		case USRQUOTA:
-			return current_fsuid() == dquot->dq_id;
+			return current_fsuid() == warn->w_dq_id;
 		case GRPQUOTA:
-			return in_group_p(dquot->dq_id);
+			return in_group_p(warn->w_dq_id);
 	}
 	return 0;
 }
 
 /* Print warning to user which exceeded quota */
-static void print_warning(struct dquot *dquot, const int warntype)
+static void print_warning(struct dquot_warn *warn)
 {
 	char *msg = NULL;
 	struct tty_struct *tty;
+	int warntype = warn->w_type;
 
 	if (warntype == QUOTA_NL_IHARDBELOW ||
 	    warntype == QUOTA_NL_ISOFTBELOW ||
 	    warntype == QUOTA_NL_BHARDBELOW ||
-	    warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(dquot))
+	    warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(warn))
 		return;
 
 	tty = get_current_tty();
 	if (!tty)
 		return;
-	tty_write_message(tty, dquot->dq_sb->s_id);
+	tty_write_message(tty, warn->w_sb->s_id);
 	if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN)
 		tty_write_message(tty, ": warning, ");
 	else
 		tty_write_message(tty, ": write failed, ");
-	tty_write_message(tty, quotatypes[dquot->dq_type]);
+	tty_write_message(tty, quotatypes[warn->w_dq_type]);
 	switch (warntype) {
 		case QUOTA_NL_IHARDWARN:
 			msg = " file limit reached.\r\n";
@@ -1185,26 +1193,34 @@
 }
 #endif
 
+static void prepare_warning(struct dquot_warn *warn, struct dquot *dquot,
+			    int warntype)
+{
+	if (warning_issued(dquot, warntype))
+		return;
+	warn->w_type = warntype;
+	warn->w_sb = dquot->dq_sb;
+	warn->w_dq_id = dquot->dq_id;
+	warn->w_dq_type = dquot->dq_type;
+}
+
 /*
  * Write warnings to the console and send warning messages over netlink.
  *
- * Note that this function can sleep.
+ * Note that this function can call into tty and networking code.
  */
-static void flush_warnings(struct dquot *const *dquots, char *warntype)
+static void flush_warnings(struct dquot_warn *warn)
 {
-	struct dquot *dq;
 	int i;
 
 	for (i = 0; i < MAXQUOTAS; i++) {
-		dq = dquots[i];
-		if (dq && warntype[i] != QUOTA_NL_NOWARN &&
-		    !warning_issued(dq, warntype[i])) {
+		if (warn[i].w_type == QUOTA_NL_NOWARN)
+			continue;
 #ifdef CONFIG_PRINT_QUOTA_WARNING
-			print_warning(dq, warntype[i]);
+		print_warning(&warn[i]);
 #endif
-			quota_send_warning(dq->dq_type, dq->dq_id,
-					   dq->dq_sb->s_dev, warntype[i]);
-		}
+		quota_send_warning(warn[i].w_dq_type, warn[i].w_dq_id,
+				   warn[i].w_sb->s_dev, warn[i].w_type);
 	}
 }
 
@@ -1218,11 +1234,11 @@
 }
 
 /* needs dq_data_lock */
-static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
+static int check_idq(struct dquot *dquot, qsize_t inodes,
+		     struct dquot_warn *warn)
 {
 	qsize_t newinodes = dquot->dq_dqb.dqb_curinodes + inodes;
 
-	*warntype = QUOTA_NL_NOWARN;
 	if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
 	    test_bit(DQ_FAKE_B, &dquot->dq_flags))
 		return 0;
@@ -1230,7 +1246,7 @@
 	if (dquot->dq_dqb.dqb_ihardlimit &&
 	    newinodes > dquot->dq_dqb.dqb_ihardlimit &&
             !ignore_hardlimit(dquot)) {
-		*warntype = QUOTA_NL_IHARDWARN;
+		prepare_warning(warn, dquot, QUOTA_NL_IHARDWARN);
 		return -EDQUOT;
 	}
 
@@ -1239,14 +1255,14 @@
 	    dquot->dq_dqb.dqb_itime &&
 	    get_seconds() >= dquot->dq_dqb.dqb_itime &&
             !ignore_hardlimit(dquot)) {
-		*warntype = QUOTA_NL_ISOFTLONGWARN;
+		prepare_warning(warn, dquot, QUOTA_NL_ISOFTLONGWARN);
 		return -EDQUOT;
 	}
 
 	if (dquot->dq_dqb.dqb_isoftlimit &&
 	    newinodes > dquot->dq_dqb.dqb_isoftlimit &&
 	    dquot->dq_dqb.dqb_itime == 0) {
-		*warntype = QUOTA_NL_ISOFTWARN;
+		prepare_warning(warn, dquot, QUOTA_NL_ISOFTWARN);
 		dquot->dq_dqb.dqb_itime = get_seconds() +
 		    sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
 	}
@@ -1255,12 +1271,12 @@
 }
 
 /* needs dq_data_lock */
-static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype)
+static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
+		     struct dquot_warn *warn)
 {
 	qsize_t tspace;
 	struct super_block *sb = dquot->dq_sb;
 
-	*warntype = QUOTA_NL_NOWARN;
 	if (!sb_has_quota_limits_enabled(sb, dquot->dq_type) ||
 	    test_bit(DQ_FAKE_B, &dquot->dq_flags))
 		return 0;
@@ -1272,7 +1288,7 @@
 	    tspace > dquot->dq_dqb.dqb_bhardlimit &&
             !ignore_hardlimit(dquot)) {
 		if (!prealloc)
-			*warntype = QUOTA_NL_BHARDWARN;
+			prepare_warning(warn, dquot, QUOTA_NL_BHARDWARN);
 		return -EDQUOT;
 	}
 
@@ -1282,7 +1298,7 @@
 	    get_seconds() >= dquot->dq_dqb.dqb_btime &&
             !ignore_hardlimit(dquot)) {
 		if (!prealloc)
-			*warntype = QUOTA_NL_BSOFTLONGWARN;
+			prepare_warning(warn, dquot, QUOTA_NL_BSOFTLONGWARN);
 		return -EDQUOT;
 	}
 
@@ -1290,7 +1306,7 @@
 	    tspace > dquot->dq_dqb.dqb_bsoftlimit &&
 	    dquot->dq_dqb.dqb_btime == 0) {
 		if (!prealloc) {
-			*warntype = QUOTA_NL_BSOFTWARN;
+			prepare_warning(warn, dquot, QUOTA_NL_BSOFTWARN);
 			dquot->dq_dqb.dqb_btime = get_seconds() +
 			    sb_dqopt(sb)->info[dquot->dq_type].dqi_bgrace;
 		}
@@ -1543,10 +1559,9 @@
 int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
 {
 	int cnt, ret = 0;
-	char warntype[MAXQUOTAS];
-	int warn = flags & DQUOT_SPACE_WARN;
+	struct dquot_warn warn[MAXQUOTAS];
+	struct dquot **dquots = inode->i_dquot;
 	int reserve = flags & DQUOT_SPACE_RESERVE;
-	int nofail = flags & DQUOT_SPACE_NOFAIL;
 
 	/*
 	 * First test before acquiring mutex - solves deadlocks when we
@@ -1559,36 +1574,36 @@
 
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-		warntype[cnt] = QUOTA_NL_NOWARN;
+		warn[cnt].w_type = QUOTA_NL_NOWARN;
 
 	spin_lock(&dq_data_lock);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-		if (!inode->i_dquot[cnt])
+		if (!dquots[cnt])
 			continue;
-		ret = check_bdq(inode->i_dquot[cnt], number, !warn,
-				warntype+cnt);
-		if (ret && !nofail) {
+		ret = check_bdq(dquots[cnt], number,
+				!(flags & DQUOT_SPACE_WARN), &warn[cnt]);
+		if (ret && !(flags & DQUOT_SPACE_NOFAIL)) {
 			spin_unlock(&dq_data_lock);
 			goto out_flush_warn;
 		}
 	}
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-		if (!inode->i_dquot[cnt])
+		if (!dquots[cnt])
 			continue;
 		if (reserve)
-			dquot_resv_space(inode->i_dquot[cnt], number);
+			dquot_resv_space(dquots[cnt], number);
 		else
-			dquot_incr_space(inode->i_dquot[cnt], number);
+			dquot_incr_space(dquots[cnt], number);
 	}
 	inode_incr_space(inode, number, reserve);
 	spin_unlock(&dq_data_lock);
 
 	if (reserve)
 		goto out_flush_warn;
-	mark_all_dquot_dirty(inode->i_dquot);
+	mark_all_dquot_dirty(dquots);
 out_flush_warn:
-	flush_warnings(inode->i_dquot, warntype);
 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	flush_warnings(warn);
 out:
 	return ret;
 }
@@ -1600,36 +1615,37 @@
 int dquot_alloc_inode(const struct inode *inode)
 {
 	int cnt, ret = 0;
-	char warntype[MAXQUOTAS];
+	struct dquot_warn warn[MAXQUOTAS];
+	struct dquot * const *dquots = inode->i_dquot;
 
 	/* First test before acquiring mutex - solves deadlocks when we
          * re-enter the quota code and are already holding the mutex */
 	if (!dquot_active(inode))
 		return 0;
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-		warntype[cnt] = QUOTA_NL_NOWARN;
+		warn[cnt].w_type = QUOTA_NL_NOWARN;
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	spin_lock(&dq_data_lock);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-		if (!inode->i_dquot[cnt])
+		if (!dquots[cnt])
 			continue;
-		ret = check_idq(inode->i_dquot[cnt], 1, warntype + cnt);
+		ret = check_idq(dquots[cnt], 1, &warn[cnt]);
 		if (ret)
 			goto warn_put_all;
 	}
 
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-		if (!inode->i_dquot[cnt])
+		if (!dquots[cnt])
 			continue;
-		dquot_incr_inodes(inode->i_dquot[cnt], 1);
+		dquot_incr_inodes(dquots[cnt], 1);
 	}
 
 warn_put_all:
 	spin_unlock(&dq_data_lock);
 	if (ret == 0)
-		mark_all_dquot_dirty(inode->i_dquot);
-	flush_warnings(inode->i_dquot, warntype);
+		mark_all_dquot_dirty(dquots);
 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	flush_warnings(warn);
 	return ret;
 }
 EXPORT_SYMBOL(dquot_alloc_inode);
@@ -1669,7 +1685,8 @@
 void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
 {
 	unsigned int cnt;
-	char warntype[MAXQUOTAS];
+	struct dquot_warn warn[MAXQUOTAS];
+	struct dquot **dquots = inode->i_dquot;
 	int reserve = flags & DQUOT_SPACE_RESERVE;
 
 	/* First test before acquiring mutex - solves deadlocks when we
@@ -1682,23 +1699,28 @@
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	spin_lock(&dq_data_lock);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-		if (!inode->i_dquot[cnt])
+		int wtype;
+
+		warn[cnt].w_type = QUOTA_NL_NOWARN;
+		if (!dquots[cnt])
 			continue;
-		warntype[cnt] = info_bdq_free(inode->i_dquot[cnt], number);
+		wtype = info_bdq_free(dquots[cnt], number);
+		if (wtype != QUOTA_NL_NOWARN)
+			prepare_warning(&warn[cnt], dquots[cnt], wtype);
 		if (reserve)
-			dquot_free_reserved_space(inode->i_dquot[cnt], number);
+			dquot_free_reserved_space(dquots[cnt], number);
 		else
-			dquot_decr_space(inode->i_dquot[cnt], number);
+			dquot_decr_space(dquots[cnt], number);
 	}
 	inode_decr_space(inode, number, reserve);
 	spin_unlock(&dq_data_lock);
 
 	if (reserve)
 		goto out_unlock;
-	mark_all_dquot_dirty(inode->i_dquot);
+	mark_all_dquot_dirty(dquots);
 out_unlock:
-	flush_warnings(inode->i_dquot, warntype);
 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	flush_warnings(warn);
 }
 EXPORT_SYMBOL(__dquot_free_space);
 
@@ -1708,7 +1730,8 @@
 void dquot_free_inode(const struct inode *inode)
 {
 	unsigned int cnt;
-	char warntype[MAXQUOTAS];
+	struct dquot_warn warn[MAXQUOTAS];
+	struct dquot * const *dquots = inode->i_dquot;
 
 	/* First test before acquiring mutex - solves deadlocks when we
          * re-enter the quota code and are already holding the mutex */
@@ -1718,15 +1741,20 @@
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	spin_lock(&dq_data_lock);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-		if (!inode->i_dquot[cnt])
+		int wtype;
+
+		warn[cnt].w_type = QUOTA_NL_NOWARN;
+		if (!dquots[cnt])
 			continue;
-		warntype[cnt] = info_idq_free(inode->i_dquot[cnt], 1);
-		dquot_decr_inodes(inode->i_dquot[cnt], 1);
+		wtype = info_idq_free(dquots[cnt], 1);
+		if (wtype != QUOTA_NL_NOWARN)
+			prepare_warning(&warn[cnt], dquots[cnt], wtype);
+		dquot_decr_inodes(dquots[cnt], 1);
 	}
 	spin_unlock(&dq_data_lock);
-	mark_all_dquot_dirty(inode->i_dquot);
-	flush_warnings(inode->i_dquot, warntype);
+	mark_all_dquot_dirty(dquots);
 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	flush_warnings(warn);
 }
 EXPORT_SYMBOL(dquot_free_inode);
 
@@ -1747,16 +1775,20 @@
 	struct dquot *transfer_from[MAXQUOTAS] = {};
 	int cnt, ret = 0;
 	char is_valid[MAXQUOTAS] = {};
-	char warntype_to[MAXQUOTAS];
-	char warntype_from_inodes[MAXQUOTAS], warntype_from_space[MAXQUOTAS];
+	struct dquot_warn warn_to[MAXQUOTAS];
+	struct dquot_warn warn_from_inodes[MAXQUOTAS];
+	struct dquot_warn warn_from_space[MAXQUOTAS];
 
 	/* First test before acquiring mutex - solves deadlocks when we
          * re-enter the quota code and are already holding the mutex */
 	if (IS_NOQUOTA(inode))
 		return 0;
 	/* Initialize the arrays */
-	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-		warntype_to[cnt] = QUOTA_NL_NOWARN;
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		warn_to[cnt].w_type = QUOTA_NL_NOWARN;
+		warn_from_inodes[cnt].w_type = QUOTA_NL_NOWARN;
+		warn_from_space[cnt].w_type = QUOTA_NL_NOWARN;
+	}
 	down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	if (IS_NOQUOTA(inode)) {	/* File without quota accounting? */
 		up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
@@ -1778,10 +1810,10 @@
 			continue;
 		is_valid[cnt] = 1;
 		transfer_from[cnt] = inode->i_dquot[cnt];
-		ret = check_idq(transfer_to[cnt], 1, warntype_to + cnt);
+		ret = check_idq(transfer_to[cnt], 1, &warn_to[cnt]);
 		if (ret)
 			goto over_quota;
-		ret = check_bdq(transfer_to[cnt], space, 0, warntype_to + cnt);
+		ret = check_bdq(transfer_to[cnt], space, 0, &warn_to[cnt]);
 		if (ret)
 			goto over_quota;
 	}
@@ -1794,10 +1826,15 @@
 			continue;
 		/* Due to IO error we might not have transfer_from[] structure */
 		if (transfer_from[cnt]) {
-			warntype_from_inodes[cnt] =
-				info_idq_free(transfer_from[cnt], 1);
-			warntype_from_space[cnt] =
-				info_bdq_free(transfer_from[cnt], space);
+			int wtype;
+			wtype = info_idq_free(transfer_from[cnt], 1);
+			if (wtype != QUOTA_NL_NOWARN)
+				prepare_warning(&warn_from_inodes[cnt],
+						transfer_from[cnt], wtype);
+			wtype = info_bdq_free(transfer_from[cnt], space);
+			if (wtype != QUOTA_NL_NOWARN)
+				prepare_warning(&warn_from_space[cnt],
+						transfer_from[cnt], wtype);
 			dquot_decr_inodes(transfer_from[cnt], 1);
 			dquot_decr_space(transfer_from[cnt], cur_space);
 			dquot_free_reserved_space(transfer_from[cnt],
@@ -1815,9 +1852,9 @@
 
 	mark_all_dquot_dirty(transfer_from);
 	mark_all_dquot_dirty(transfer_to);
-	flush_warnings(transfer_to, warntype_to);
-	flush_warnings(transfer_from, warntype_from_inodes);
-	flush_warnings(transfer_from, warntype_from_space);
+	flush_warnings(warn_to);
+	flush_warnings(warn_from_inodes);
+	flush_warnings(warn_from_space);
 	/* Pass back references to put */
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
 		if (is_valid[cnt])
@@ -1826,7 +1863,7 @@
 over_quota:
 	spin_unlock(&dq_data_lock);
 	up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
-	flush_warnings(transfer_to, warntype_to);
+	flush_warnings(warn_to);
 	return ret;
 }
 EXPORT_SYMBOL(__dquot_transfer);
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index fc2c438..9a39120 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -282,10 +282,9 @@
 	case Q_XGETQUOTA:
 		return quota_getxquota(sb, type, id, addr);
 	case Q_XQUOTASYNC:
-		/* caller already holds s_umount */
 		if (sb->s_flags & MS_RDONLY)
 			return -EROFS;
-		writeback_inodes_sb(sb, WB_REASON_SYNC);
+		/* XFS quotas are fully coherent now, making this call a noop */
 		return 0;
 	default:
 		return -EINVAL;
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index aec766a..a1fdabe 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -209,22 +209,19 @@
 int ramfs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct ramfs_fs_info *fsi;
-	struct inode *inode = NULL;
-	struct dentry *root;
+	struct inode *inode;
 	int err;
 
 	save_mount_options(sb, data);
 
 	fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL);
 	sb->s_fs_info = fsi;
-	if (!fsi) {
-		err = -ENOMEM;
-		goto fail;
-	}
+	if (!fsi)
+		return -ENOMEM;
 
 	err = ramfs_parse_options(data, &fsi->mount_opts);
 	if (err)
-		goto fail;
+		return err;
 
 	sb->s_maxbytes		= MAX_LFS_FILESIZE;
 	sb->s_blocksize		= PAGE_CACHE_SIZE;
@@ -234,24 +231,11 @@
 	sb->s_time_gran		= 1;
 
 	inode = ramfs_get_inode(sb, NULL, S_IFDIR | fsi->mount_opts.mode, 0);
-	if (!inode) {
-		err = -ENOMEM;
-		goto fail;
-	}
-
-	root = d_alloc_root(inode);
-	sb->s_root = root;
-	if (!root) {
-		err = -ENOMEM;
-		goto fail;
-	}
+	sb->s_root = d_make_root(inode);
+	if (!sb->s_root)
+		return -ENOMEM;
 
 	return 0;
-fail:
-	kfree(fsi);
-	sb->s_fs_info = NULL;
-	iput(inode);
-	return err;
 }
 
 struct dentry *ramfs_mount(struct file_system_type *fs_type,
diff --git a/fs/read_write.c b/fs/read_write.c
index 5ad4248..ffc99d2 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -11,7 +11,7 @@
 #include <linux/uio.h>
 #include <linux/fsnotify.h>
 #include <linux/security.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/syscalls.h>
 #include <linux/pagemap.h>
 #include <linux/splice.h>
diff --git a/fs/readdir.c b/fs/readdir.c
index 356f715..cc0a822 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -6,7 +6,7 @@
 
 #include <linux/stddef.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
diff --git a/include/linux/reiserfs_acl.h b/fs/reiserfs/acl.h
similarity index 100%
rename from include/linux/reiserfs_acl.h
rename to fs/reiserfs/acl.h
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
index 70de42f..4c0c7d1 100644
--- a/fs/reiserfs/bitmap.c
+++ b/fs/reiserfs/bitmap.c
@@ -4,14 +4,12 @@
 /* Reiserfs block (de)allocator, bitmap-based. */
 
 #include <linux/time.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/errno.h>
 #include <linux/buffer_head.h>
 #include <linux/kernel.h>
 #include <linux/pagemap.h>
 #include <linux/vmalloc.h>
-#include <linux/reiserfs_fs_sb.h>
-#include <linux/reiserfs_fs_i.h>
 #include <linux/quotaops.h>
 #include <linux/seq_file.h>
 
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
index 133e935..66c53b6 100644
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -5,7 +5,7 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/stat.h>
 #include <linux/buffer_head.h>
 #include <linux/slab.h>
diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c
index 60c0804..2b7882b 100644
--- a/fs/reiserfs/do_balan.c
+++ b/fs/reiserfs/do_balan.c
@@ -17,7 +17,7 @@
 
 #include <asm/uaccess.h>
 #include <linux/time.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/buffer_head.h>
 #include <linux/kernel.h>
 
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index ace6350..8375c92 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -3,9 +3,9 @@
  */
 
 #include <linux/time.h>
-#include <linux/reiserfs_fs.h>
-#include <linux/reiserfs_acl.h>
-#include <linux/reiserfs_xattr.h>
+#include "reiserfs.h"
+#include "acl.h"
+#include "xattr.h"
 #include <asm/uaccess.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
diff --git a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c
index 1e4250b..430e065 100644
--- a/fs/reiserfs/fix_node.c
+++ b/fs/reiserfs/fix_node.c
@@ -37,7 +37,7 @@
 #include <linux/time.h>
 #include <linux/slab.h>
 #include <linux/string.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/buffer_head.h>
 
 /* To make any changes in the tree we find a node, that contains item
diff --git a/fs/reiserfs/hashes.c b/fs/reiserfs/hashes.c
index 6471c67..91b0cc1 100644
--- a/fs/reiserfs/hashes.c
+++ b/fs/reiserfs/hashes.c
@@ -19,7 +19,7 @@
 //
 
 #include <linux/kernel.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <asm/types.h>
 
 #define DELTA 0x9E3779B9
diff --git a/fs/reiserfs/ibalance.c b/fs/reiserfs/ibalance.c
index 2074fd9..e1978fd 100644
--- a/fs/reiserfs/ibalance.c
+++ b/fs/reiserfs/ibalance.c
@@ -5,7 +5,7 @@
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #include <linux/time.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/buffer_head.h>
 
 /* this is one and only function that is used outside (do_balance.c) */
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 9e8cd5a..494c315 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -4,9 +4,9 @@
 
 #include <linux/time.h>
 #include <linux/fs.h>
-#include <linux/reiserfs_fs.h>
-#include <linux/reiserfs_acl.h>
-#include <linux/reiserfs_xattr.h>
+#include "reiserfs.h"
+#include "acl.h"
+#include "xattr.h"
 #include <linux/exportfs.h>
 #include <linux/pagemap.h>
 #include <linux/highmem.h>
diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
index 950e3d1..0c21850 100644
--- a/fs/reiserfs/ioctl.c
+++ b/fs/reiserfs/ioctl.c
@@ -5,7 +5,7 @@
 #include <linux/capability.h>
 #include <linux/fs.h>
 #include <linux/mount.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/time.h>
 #include <asm/uaccess.h>
 #include <linux/pagemap.h>
diff --git a/fs/reiserfs/item_ops.c b/fs/reiserfs/item_ops.c
index 72cb1cc..ee382ef 100644
--- a/fs/reiserfs/item_ops.c
+++ b/fs/reiserfs/item_ops.c
@@ -3,7 +3,7 @@
  */
 
 #include <linux/time.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 
 // this contains item handlers for old item types: sd, direct,
 // indirect, directory
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index c3cf54f..b1a0857 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -37,7 +37,7 @@
 #include <linux/time.h>
 #include <linux/semaphore.h>
 #include <linux/vmalloc.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/fcntl.h>
@@ -51,7 +51,6 @@
 #include <linux/uaccess.h>
 #include <linux/slab.h>
 
-#include <asm/system.h>
 
 /* gets a struct reiserfs_journal_list * from a list head */
 #define JOURNAL_LIST_ENTRY(h) (list_entry((h), struct reiserfs_journal_list, \
diff --git a/fs/reiserfs/lbalance.c b/fs/reiserfs/lbalance.c
index b43d015..79e5a8b 100644
--- a/fs/reiserfs/lbalance.c
+++ b/fs/reiserfs/lbalance.c
@@ -5,7 +5,7 @@
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #include <linux/time.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/buffer_head.h>
 
 /* these are used in do_balance.c */
diff --git a/fs/reiserfs/lock.c b/fs/reiserfs/lock.c
index 7df1ce4..d735bc8 100644
--- a/fs/reiserfs/lock.c
+++ b/fs/reiserfs/lock.c
@@ -1,4 +1,4 @@
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/mutex.h>
 
 /*
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index 1463788..84e8a69 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -14,9 +14,9 @@
 #include <linux/time.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
-#include <linux/reiserfs_fs.h>
-#include <linux/reiserfs_acl.h>
-#include <linux/reiserfs_xattr.h>
+#include "reiserfs.h"
+#include "acl.h"
+#include "xattr.h"
 #include <linux/quotaops.h>
 
 #define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { inc_nlink(i); if (i->i_nlink >= REISERFS_LINK_MAX) set_nlink(i, 1); }
diff --git a/fs/reiserfs/objectid.c b/fs/reiserfs/objectid.c
index 3a6de81..f732d6a 100644
--- a/fs/reiserfs/objectid.c
+++ b/fs/reiserfs/objectid.c
@@ -5,8 +5,7 @@
 #include <linux/string.h>
 #include <linux/random.h>
 #include <linux/time.h>
-#include <linux/reiserfs_fs.h>
-#include <linux/reiserfs_fs_sb.h>
+#include "reiserfs.h"
 
 // find where objectid map starts
 #define objectid_map(s,rs) (old_format_only (s) ? \
diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c
index 45de98b..c0b1112 100644
--- a/fs/reiserfs/prints.c
+++ b/fs/reiserfs/prints.c
@@ -4,7 +4,7 @@
 
 #include <linux/time.h>
 #include <linux/fs.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/string.h>
 #include <linux/buffer_head.h>
 
@@ -329,7 +329,7 @@
     Numbering scheme for panic used by Vladimir and Anatoly( Hans completely ignores this scheme, and considers it
     pointless complexity):
 
-    panics in reiserfs_fs.h have numbers from 1000 to 1999
+    panics in reiserfs.h have numbers from 1000 to 1999
     super.c				        2000 to 2999
     preserve.c (unused)			    3000 to 3999
     bitmap.c				    4000 to 4999
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
index 7a99811..2c1ade6 100644
--- a/fs/reiserfs/procfs.c
+++ b/fs/reiserfs/procfs.c
@@ -12,8 +12,7 @@
 #include <linux/time.h>
 #include <linux/seq_file.h>
 #include <asm/uaccess.h>
-#include <linux/reiserfs_fs.h>
-#include <linux/reiserfs_fs_sb.h>
+#include "reiserfs.h"
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 
diff --git a/fs/reiserfs/reiserfs.h b/fs/reiserfs/reiserfs.h
new file mode 100644
index 0000000..a59d271
--- /dev/null
+++ b/fs/reiserfs/reiserfs.h
@@ -0,0 +1,2923 @@
+/*
+ * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details
+ */
+
+#include <linux/reiserfs_fs.h>
+
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/bug.h>
+#include <linux/workqueue.h>
+#include <asm/unaligned.h>
+#include <linux/bitops.h>
+#include <linux/proc_fs.h>
+#include <linux/buffer_head.h>
+
+/* the 32 bit compat definitions with int argument */
+#define REISERFS_IOC32_UNPACK		_IOW(0xCD, 1, int)
+#define REISERFS_IOC32_GETFLAGS		FS_IOC32_GETFLAGS
+#define REISERFS_IOC32_SETFLAGS		FS_IOC32_SETFLAGS
+#define REISERFS_IOC32_GETVERSION	FS_IOC32_GETVERSION
+#define REISERFS_IOC32_SETVERSION	FS_IOC32_SETVERSION
+
+struct reiserfs_journal_list;
+
+/** bitmasks for i_flags field in reiserfs-specific part of inode */
+typedef enum {
+    /** this says what format of key do all items (but stat data) of
+      an object have.  If this is set, that format is 3.6 otherwise
+      - 3.5 */
+	i_item_key_version_mask = 0x0001,
+    /** If this is unset, object has 3.5 stat data, otherwise, it has
+      3.6 stat data with 64bit size, 32bit nlink etc. */
+	i_stat_data_version_mask = 0x0002,
+    /** file might need tail packing on close */
+	i_pack_on_close_mask = 0x0004,
+    /** don't pack tail of file */
+	i_nopack_mask = 0x0008,
+    /** If those is set, "safe link" was created for this file during
+      truncate or unlink. Safe link is used to avoid leakage of disk
+      space on crash with some files open, but unlinked. */
+	i_link_saved_unlink_mask = 0x0010,
+	i_link_saved_truncate_mask = 0x0020,
+	i_has_xattr_dir = 0x0040,
+	i_data_log = 0x0080,
+} reiserfs_inode_flags;
+
+struct reiserfs_inode_info {
+	__u32 i_key[4];		/* key is still 4 32 bit integers */
+    /** transient inode flags that are never stored on disk. Bitmasks
+      for this field are defined above. */
+	__u32 i_flags;
+
+	__u32 i_first_direct_byte;	// offset of first byte stored in direct item.
+
+	/* copy of persistent inode flags read from sd_attrs. */
+	__u32 i_attrs;
+
+	int i_prealloc_block;	/* first unused block of a sequence of unused blocks */
+	int i_prealloc_count;	/* length of that sequence */
+	struct list_head i_prealloc_list;	/* per-transaction list of inodes which
+						 * have preallocated blocks */
+
+	unsigned new_packing_locality:1;	/* new_packig_locality is created; new blocks
+						 * for the contents of this directory should be
+						 * displaced */
+
+	/* we use these for fsync or O_SYNC to decide which transaction
+	 ** needs to be committed in order for this inode to be properly
+	 ** flushed */
+	unsigned int i_trans_id;
+	struct reiserfs_journal_list *i_jl;
+	atomic_t openers;
+	struct mutex tailpack;
+#ifdef CONFIG_REISERFS_FS_XATTR
+	struct rw_semaphore i_xattr_sem;
+#endif
+	struct inode vfs_inode;
+};
+
+typedef enum {
+	reiserfs_attrs_cleared = 0x00000001,
+} reiserfs_super_block_flags;
+
+/* struct reiserfs_super_block accessors/mutators
+ * since this is a disk structure, it will always be in
+ * little endian format. */
+#define sb_block_count(sbp)         (le32_to_cpu((sbp)->s_v1.s_block_count))
+#define set_sb_block_count(sbp,v)   ((sbp)->s_v1.s_block_count = cpu_to_le32(v))
+#define sb_free_blocks(sbp)         (le32_to_cpu((sbp)->s_v1.s_free_blocks))
+#define set_sb_free_blocks(sbp,v)   ((sbp)->s_v1.s_free_blocks = cpu_to_le32(v))
+#define sb_root_block(sbp)          (le32_to_cpu((sbp)->s_v1.s_root_block))
+#define set_sb_root_block(sbp,v)    ((sbp)->s_v1.s_root_block = cpu_to_le32(v))
+
+#define sb_jp_journal_1st_block(sbp)  \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_1st_block))
+#define set_sb_jp_journal_1st_block(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_1st_block = cpu_to_le32(v))
+#define sb_jp_journal_dev(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_dev))
+#define set_sb_jp_journal_dev(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_dev = cpu_to_le32(v))
+#define sb_jp_journal_size(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_size))
+#define set_sb_jp_journal_size(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_size = cpu_to_le32(v))
+#define sb_jp_journal_trans_max(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_trans_max))
+#define set_sb_jp_journal_trans_max(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_trans_max = cpu_to_le32(v))
+#define sb_jp_journal_magic(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_magic))
+#define set_sb_jp_journal_magic(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_magic = cpu_to_le32(v))
+#define sb_jp_journal_max_batch(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_max_batch))
+#define set_sb_jp_journal_max_batch(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_max_batch = cpu_to_le32(v))
+#define sb_jp_jourmal_max_commit_age(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_max_commit_age))
+#define set_sb_jp_journal_max_commit_age(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_max_commit_age = cpu_to_le32(v))
+
+#define sb_blocksize(sbp)          (le16_to_cpu((sbp)->s_v1.s_blocksize))
+#define set_sb_blocksize(sbp,v)    ((sbp)->s_v1.s_blocksize = cpu_to_le16(v))
+#define sb_oid_maxsize(sbp)        (le16_to_cpu((sbp)->s_v1.s_oid_maxsize))
+#define set_sb_oid_maxsize(sbp,v)  ((sbp)->s_v1.s_oid_maxsize = cpu_to_le16(v))
+#define sb_oid_cursize(sbp)        (le16_to_cpu((sbp)->s_v1.s_oid_cursize))
+#define set_sb_oid_cursize(sbp,v)  ((sbp)->s_v1.s_oid_cursize = cpu_to_le16(v))
+#define sb_umount_state(sbp)       (le16_to_cpu((sbp)->s_v1.s_umount_state))
+#define set_sb_umount_state(sbp,v) ((sbp)->s_v1.s_umount_state = cpu_to_le16(v))
+#define sb_fs_state(sbp)           (le16_to_cpu((sbp)->s_v1.s_fs_state))
+#define set_sb_fs_state(sbp,v)     ((sbp)->s_v1.s_fs_state = cpu_to_le16(v))
+#define sb_hash_function_code(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_hash_function_code))
+#define set_sb_hash_function_code(sbp,v) \
+              ((sbp)->s_v1.s_hash_function_code = cpu_to_le32(v))
+#define sb_tree_height(sbp)        (le16_to_cpu((sbp)->s_v1.s_tree_height))
+#define set_sb_tree_height(sbp,v)  ((sbp)->s_v1.s_tree_height = cpu_to_le16(v))
+#define sb_bmap_nr(sbp)            (le16_to_cpu((sbp)->s_v1.s_bmap_nr))
+#define set_sb_bmap_nr(sbp,v)      ((sbp)->s_v1.s_bmap_nr = cpu_to_le16(v))
+#define sb_version(sbp)            (le16_to_cpu((sbp)->s_v1.s_version))
+#define set_sb_version(sbp,v)      ((sbp)->s_v1.s_version = cpu_to_le16(v))
+
+#define sb_mnt_count(sbp)	   (le16_to_cpu((sbp)->s_mnt_count))
+#define set_sb_mnt_count(sbp, v)   ((sbp)->s_mnt_count = cpu_to_le16(v))
+
+#define sb_reserved_for_journal(sbp) \
+              (le16_to_cpu((sbp)->s_v1.s_reserved_for_journal))
+#define set_sb_reserved_for_journal(sbp,v) \
+              ((sbp)->s_v1.s_reserved_for_journal = cpu_to_le16(v))
+
+/* LOGGING -- */
+
+/* These all interelate for performance.
+**
+** If the journal block count is smaller than n transactions, you lose speed.
+** I don't know what n is yet, I'm guessing 8-16.
+**
+** typical transaction size depends on the application, how often fsync is
+** called, and how many metadata blocks you dirty in a 30 second period.
+** The more small files (<16k) you use, the larger your transactions will
+** be.
+**
+** If your journal fills faster than dirty buffers get flushed to disk, it must flush them before allowing the journal
+** to wrap, which slows things down.  If you need high speed meta data updates, the journal should be big enough
+** to prevent wrapping before dirty meta blocks get to disk.
+**
+** If the batch max is smaller than the transaction max, you'll waste space at the end of the journal
+** because journal_end sets the next transaction to start at 0 if the next transaction has any chance of wrapping.
+**
+** The large the batch max age, the better the speed, and the more meta data changes you'll lose after a crash.
+**
+*/
+
+/* don't mess with these for a while */
+				/* we have a node size define somewhere in reiserfs_fs.h. -Hans */
+#define JOURNAL_BLOCK_SIZE  4096	/* BUG gotta get rid of this */
+#define JOURNAL_MAX_CNODE   1500	/* max cnodes to allocate. */
+#define JOURNAL_HASH_SIZE 8192
+#define JOURNAL_NUM_BITMAPS 5	/* number of copies of the bitmaps to have floating.  Must be >= 2 */
+
+/* One of these for every block in every transaction
+** Each one is in two hash tables.  First, a hash of the current transaction, and after journal_end, a
+** hash of all the in memory transactions.
+** next and prev are used by the current transaction (journal_hash).
+** hnext and hprev are used by journal_list_hash.  If a block is in more than one transaction, the journal_list_hash
+** links it in multiple times.  This allows flush_journal_list to remove just the cnode belonging
+** to a given transaction.
+*/
+struct reiserfs_journal_cnode {
+	struct buffer_head *bh;	/* real buffer head */
+	struct super_block *sb;	/* dev of real buffer head */
+	__u32 blocknr;		/* block number of real buffer head, == 0 when buffer on disk */
+	unsigned long state;
+	struct reiserfs_journal_list *jlist;	/* journal list this cnode lives in */
+	struct reiserfs_journal_cnode *next;	/* next in transaction list */
+	struct reiserfs_journal_cnode *prev;	/* prev in transaction list */
+	struct reiserfs_journal_cnode *hprev;	/* prev in hash list */
+	struct reiserfs_journal_cnode *hnext;	/* next in hash list */
+};
+
+struct reiserfs_bitmap_node {
+	int id;
+	char *data;
+	struct list_head list;
+};
+
+struct reiserfs_list_bitmap {
+	struct reiserfs_journal_list *journal_list;
+	struct reiserfs_bitmap_node **bitmaps;
+};
+
+/*
+** one of these for each transaction.  The most important part here is the j_realblock.
+** this list of cnodes is used to hash all the blocks in all the commits, to mark all the
+** real buffer heads dirty once all the commits hit the disk,
+** and to make sure every real block in a transaction is on disk before allowing the log area
+** to be overwritten */
+struct reiserfs_journal_list {
+	unsigned long j_start;
+	unsigned long j_state;
+	unsigned long j_len;
+	atomic_t j_nonzerolen;
+	atomic_t j_commit_left;
+	atomic_t j_older_commits_done;	/* all commits older than this on disk */
+	struct mutex j_commit_mutex;
+	unsigned int j_trans_id;
+	time_t j_timestamp;
+	struct reiserfs_list_bitmap *j_list_bitmap;
+	struct buffer_head *j_commit_bh;	/* commit buffer head */
+	struct reiserfs_journal_cnode *j_realblock;
+	struct reiserfs_journal_cnode *j_freedlist;	/* list of buffers that were freed during this trans.  free each of these on flush */
+	/* time ordered list of all active transactions */
+	struct list_head j_list;
+
+	/* time ordered list of all transactions we haven't tried to flush yet */
+	struct list_head j_working_list;
+
+	/* list of tail conversion targets in need of flush before commit */
+	struct list_head j_tail_bh_list;
+	/* list of data=ordered buffers in need of flush before commit */
+	struct list_head j_bh_list;
+	int j_refcount;
+};
+
+struct reiserfs_journal {
+	struct buffer_head **j_ap_blocks;	/* journal blocks on disk */
+	struct reiserfs_journal_cnode *j_last;	/* newest journal block */
+	struct reiserfs_journal_cnode *j_first;	/*  oldest journal block.  start here for traverse */
+
+	struct block_device *j_dev_bd;
+	fmode_t j_dev_mode;
+	int j_1st_reserved_block;	/* first block on s_dev of reserved area journal */
+
+	unsigned long j_state;
+	unsigned int j_trans_id;
+	unsigned long j_mount_id;
+	unsigned long j_start;	/* start of current waiting commit (index into j_ap_blocks) */
+	unsigned long j_len;	/* length of current waiting commit */
+	unsigned long j_len_alloc;	/* number of buffers requested by journal_begin() */
+	atomic_t j_wcount;	/* count of writers for current commit */
+	unsigned long j_bcount;	/* batch count. allows turning X transactions into 1 */
+	unsigned long j_first_unflushed_offset;	/* first unflushed transactions offset */
+	unsigned j_last_flush_trans_id;	/* last fully flushed journal timestamp */
+	struct buffer_head *j_header_bh;
+
+	time_t j_trans_start_time;	/* time this transaction started */
+	struct mutex j_mutex;
+	struct mutex j_flush_mutex;
+	wait_queue_head_t j_join_wait;	/* wait for current transaction to finish before starting new one */
+	atomic_t j_jlock;	/* lock for j_join_wait */
+	int j_list_bitmap_index;	/* number of next list bitmap to use */
+	int j_must_wait;	/* no more journal begins allowed. MUST sleep on j_join_wait */
+	int j_next_full_flush;	/* next journal_end will flush all journal list */
+	int j_next_async_flush;	/* next journal_end will flush all async commits */
+
+	int j_cnode_used;	/* number of cnodes on the used list */
+	int j_cnode_free;	/* number of cnodes on the free list */
+
+	unsigned int j_trans_max;	/* max number of blocks in a transaction.  */
+	unsigned int j_max_batch;	/* max number of blocks to batch into a trans */
+	unsigned int j_max_commit_age;	/* in seconds, how old can an async commit be */
+	unsigned int j_max_trans_age;	/* in seconds, how old can a transaction be */
+	unsigned int j_default_max_commit_age;	/* the default for the max commit age */
+
+	struct reiserfs_journal_cnode *j_cnode_free_list;
+	struct reiserfs_journal_cnode *j_cnode_free_orig;	/* orig pointer returned from vmalloc */
+
+	struct reiserfs_journal_list *j_current_jl;
+	int j_free_bitmap_nodes;
+	int j_used_bitmap_nodes;
+
+	int j_num_lists;	/* total number of active transactions */
+	int j_num_work_lists;	/* number that need attention from kreiserfsd */
+
+	/* debugging to make sure things are flushed in order */
+	unsigned int j_last_flush_id;
+
+	/* debugging to make sure things are committed in order */
+	unsigned int j_last_commit_id;
+
+	struct list_head j_bitmap_nodes;
+	struct list_head j_dirty_buffers;
+	spinlock_t j_dirty_buffers_lock;	/* protects j_dirty_buffers */
+
+	/* list of all active transactions */
+	struct list_head j_journal_list;
+	/* lists that haven't been touched by writeback attempts */
+	struct list_head j_working_list;
+
+	struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS];	/* array of bitmaps to record the deleted blocks */
+	struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE];	/* hash table for real buffer heads in current trans */
+	struct reiserfs_journal_cnode *j_list_hash_table[JOURNAL_HASH_SIZE];	/* hash table for all the real buffer heads in all
+										   the transactions */
+	struct list_head j_prealloc_list;	/* list of inodes which have preallocated blocks */
+	int j_persistent_trans;
+	unsigned long j_max_trans_size;
+	unsigned long j_max_batch_size;
+
+	int j_errno;
+
+	/* when flushing ordered buffers, throttle new ordered writers */
+	struct delayed_work j_work;
+	struct super_block *j_work_sb;
+	atomic_t j_async_throttle;
+};
+
+enum journal_state_bits {
+	J_WRITERS_BLOCKED = 1,	/* set when new writers not allowed */
+	J_WRITERS_QUEUED,	/* set when log is full due to too many writers */
+	J_ABORTED,		/* set when log is aborted */
+};
+
+#define JOURNAL_DESC_MAGIC "ReIsErLB"	/* ick.  magic string to find desc blocks in the journal */
+
+typedef __u32(*hashf_t) (const signed char *, int);
+
+struct reiserfs_bitmap_info {
+	__u32 free_count;
+};
+
+struct proc_dir_entry;
+
+#if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO )
+typedef unsigned long int stat_cnt_t;
+typedef struct reiserfs_proc_info_data {
+	spinlock_t lock;
+	int exiting;
+	int max_hash_collisions;
+
+	stat_cnt_t breads;
+	stat_cnt_t bread_miss;
+	stat_cnt_t search_by_key;
+	stat_cnt_t search_by_key_fs_changed;
+	stat_cnt_t search_by_key_restarted;
+
+	stat_cnt_t insert_item_restarted;
+	stat_cnt_t paste_into_item_restarted;
+	stat_cnt_t cut_from_item_restarted;
+	stat_cnt_t delete_solid_item_restarted;
+	stat_cnt_t delete_item_restarted;
+
+	stat_cnt_t leaked_oid;
+	stat_cnt_t leaves_removable;
+
+	/* balances per level. Use explicit 5 as MAX_HEIGHT is not visible yet. */
+	stat_cnt_t balance_at[5];	/* XXX */
+	/* sbk == search_by_key */
+	stat_cnt_t sbk_read_at[5];	/* XXX */
+	stat_cnt_t sbk_fs_changed[5];
+	stat_cnt_t sbk_restarted[5];
+	stat_cnt_t items_at[5];	/* XXX */
+	stat_cnt_t free_at[5];	/* XXX */
+	stat_cnt_t can_node_be_removed[5];	/* XXX */
+	long int lnum[5];	/* XXX */
+	long int rnum[5];	/* XXX */
+	long int lbytes[5];	/* XXX */
+	long int rbytes[5];	/* XXX */
+	stat_cnt_t get_neighbors[5];
+	stat_cnt_t get_neighbors_restart[5];
+	stat_cnt_t need_l_neighbor[5];
+	stat_cnt_t need_r_neighbor[5];
+
+	stat_cnt_t free_block;
+	struct __scan_bitmap_stats {
+		stat_cnt_t call;
+		stat_cnt_t wait;
+		stat_cnt_t bmap;
+		stat_cnt_t retry;
+		stat_cnt_t in_journal_hint;
+		stat_cnt_t in_journal_nohint;
+		stat_cnt_t stolen;
+	} scan_bitmap;
+	struct __journal_stats {
+		stat_cnt_t in_journal;
+		stat_cnt_t in_journal_bitmap;
+		stat_cnt_t in_journal_reusable;
+		stat_cnt_t lock_journal;
+		stat_cnt_t lock_journal_wait;
+		stat_cnt_t journal_being;
+		stat_cnt_t journal_relock_writers;
+		stat_cnt_t journal_relock_wcount;
+		stat_cnt_t mark_dirty;
+		stat_cnt_t mark_dirty_already;
+		stat_cnt_t mark_dirty_notjournal;
+		stat_cnt_t restore_prepared;
+		stat_cnt_t prepare;
+		stat_cnt_t prepare_retry;
+	} journal;
+} reiserfs_proc_info_data_t;
+#else
+typedef struct reiserfs_proc_info_data {
+} reiserfs_proc_info_data_t;
+#endif
+
+/* reiserfs union of in-core super block data */
+struct reiserfs_sb_info {
+	struct buffer_head *s_sbh;	/* Buffer containing the super block */
+	/* both the comment and the choice of
+	   name are unclear for s_rs -Hans */
+	struct reiserfs_super_block *s_rs;	/* Pointer to the super block in the buffer */
+	struct reiserfs_bitmap_info *s_ap_bitmap;
+	struct reiserfs_journal *s_journal;	/* pointer to journal information */
+	unsigned short s_mount_state;	/* reiserfs state (valid, invalid) */
+
+	/* Serialize writers access, replace the old bkl */
+	struct mutex lock;
+	/* Owner of the lock (can be recursive) */
+	struct task_struct *lock_owner;
+	/* Depth of the lock, start from -1 like the bkl */
+	int lock_depth;
+
+	/* Comment? -Hans */
+	void (*end_io_handler) (struct buffer_head *, int);
+	hashf_t s_hash_function;	/* pointer to function which is used
+					   to sort names in directory. Set on
+					   mount */
+	unsigned long s_mount_opt;	/* reiserfs's mount options are set
+					   here (currently - NOTAIL, NOLOG,
+					   REPLAYONLY) */
+
+	struct {		/* This is a structure that describes block allocator options */
+		unsigned long bits;	/* Bitfield for enable/disable kind of options */
+		unsigned long large_file_size;	/* size started from which we consider file to be a large one(in blocks) */
+		int border;	/* percentage of disk, border takes */
+		int preallocmin;	/* Minimal file size (in blocks) starting from which we do preallocations */
+		int preallocsize;	/* Number of blocks we try to prealloc when file
+					   reaches preallocmin size (in blocks) or
+					   prealloc_list is empty. */
+	} s_alloc_options;
+
+	/* Comment? -Hans */
+	wait_queue_head_t s_wait;
+	/* To be obsoleted soon by per buffer seals.. -Hans */
+	atomic_t s_generation_counter;	// increased by one every time the
+	// tree gets re-balanced
+	unsigned long s_properties;	/* File system properties. Currently holds
+					   on-disk FS format */
+
+	/* session statistics */
+	int s_disk_reads;
+	int s_disk_writes;
+	int s_fix_nodes;
+	int s_do_balance;
+	int s_unneeded_left_neighbor;
+	int s_good_search_by_key_reada;
+	int s_bmaps;
+	int s_bmaps_without_search;
+	int s_direct2indirect;
+	int s_indirect2direct;
+	/* set up when it's ok for reiserfs_read_inode2() to read from
+	   disk inode with nlink==0. Currently this is only used during
+	   finish_unfinished() processing at mount time */
+	int s_is_unlinked_ok;
+	reiserfs_proc_info_data_t s_proc_info_data;
+	struct proc_dir_entry *procdir;
+	int reserved_blocks;	/* amount of blocks reserved for further allocations */
+	spinlock_t bitmap_lock;	/* this lock on now only used to protect reserved_blocks variable */
+	struct dentry *priv_root;	/* root of /.reiserfs_priv */
+	struct dentry *xattr_root;	/* root of /.reiserfs_priv/xattrs */
+	int j_errno;
+#ifdef CONFIG_QUOTA
+	char *s_qf_names[MAXQUOTAS];
+	int s_jquota_fmt;
+#endif
+	char *s_jdev;		/* Stored jdev for mount option showing */
+#ifdef CONFIG_REISERFS_CHECK
+
+	struct tree_balance *cur_tb;	/*
+					 * Detects whether more than one
+					 * copy of tb exists per superblock
+					 * as a means of checking whether
+					 * do_balance is executing concurrently
+					 * against another tree reader/writer
+					 * on a same mount point.
+					 */
+#endif
+};
+
+/* Definitions of reiserfs on-disk properties: */
+#define REISERFS_3_5 0
+#define REISERFS_3_6 1
+#define REISERFS_OLD_FORMAT 2
+
+enum reiserfs_mount_options {
+/* Mount options */
+	REISERFS_LARGETAIL,	/* large tails will be created in a session */
+	REISERFS_SMALLTAIL,	/* small (for files less than block size) tails will be created in a session */
+	REPLAYONLY,		/* replay journal and return 0. Use by fsck */
+	REISERFS_CONVERT,	/* -o conv: causes conversion of old
+				   format super block to the new
+				   format. If not specified - old
+				   partition will be dealt with in a
+				   manner of 3.5.x */
+
+/* -o hash={tea, rupasov, r5, detect} is meant for properly mounting
+** reiserfs disks from 3.5.19 or earlier.  99% of the time, this option
+** is not required.  If the normal autodection code can't determine which
+** hash to use (because both hashes had the same value for a file)
+** use this option to force a specific hash.  It won't allow you to override
+** the existing hash on the FS, so if you have a tea hash disk, and mount
+** with -o hash=rupasov, the mount will fail.
+*/
+	FORCE_TEA_HASH,		/* try to force tea hash on mount */
+	FORCE_RUPASOV_HASH,	/* try to force rupasov hash on mount */
+	FORCE_R5_HASH,		/* try to force rupasov hash on mount */
+	FORCE_HASH_DETECT,	/* try to detect hash function on mount */
+
+	REISERFS_DATA_LOG,
+	REISERFS_DATA_ORDERED,
+	REISERFS_DATA_WRITEBACK,
+
+/* used for testing experimental features, makes benchmarking new
+   features with and without more convenient, should never be used by
+   users in any code shipped to users (ideally) */
+
+	REISERFS_NO_BORDER,
+	REISERFS_NO_UNHASHED_RELOCATION,
+	REISERFS_HASHED_RELOCATION,
+	REISERFS_ATTRS,
+	REISERFS_XATTRS_USER,
+	REISERFS_POSIXACL,
+	REISERFS_EXPOSE_PRIVROOT,
+	REISERFS_BARRIER_NONE,
+	REISERFS_BARRIER_FLUSH,
+
+	/* Actions on error */
+	REISERFS_ERROR_PANIC,
+	REISERFS_ERROR_RO,
+	REISERFS_ERROR_CONTINUE,
+
+	REISERFS_USRQUOTA,	/* User quota option specified */
+	REISERFS_GRPQUOTA,	/* Group quota option specified */
+
+	REISERFS_TEST1,
+	REISERFS_TEST2,
+	REISERFS_TEST3,
+	REISERFS_TEST4,
+	REISERFS_UNSUPPORTED_OPT,
+};
+
+#define reiserfs_r5_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_R5_HASH))
+#define reiserfs_rupasov_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_RUPASOV_HASH))
+#define reiserfs_tea_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_TEA_HASH))
+#define reiserfs_hash_detect(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_HASH_DETECT))
+#define reiserfs_no_border(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_NO_BORDER))
+#define reiserfs_no_unhashed_relocation(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_NO_UNHASHED_RELOCATION))
+#define reiserfs_hashed_relocation(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_HASHED_RELOCATION))
+#define reiserfs_test4(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_TEST4))
+
+#define have_large_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_LARGETAIL))
+#define have_small_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_SMALLTAIL))
+#define replay_only(s) (REISERFS_SB(s)->s_mount_opt & (1 << REPLAYONLY))
+#define reiserfs_attrs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ATTRS))
+#define old_format_only(s) (REISERFS_SB(s)->s_properties & (1 << REISERFS_3_5))
+#define convert_reiserfs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_CONVERT))
+#define reiserfs_data_log(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_LOG))
+#define reiserfs_data_ordered(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_ORDERED))
+#define reiserfs_data_writeback(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_WRITEBACK))
+#define reiserfs_xattrs_user(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS_USER))
+#define reiserfs_posixacl(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_POSIXACL))
+#define reiserfs_expose_privroot(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_EXPOSE_PRIVROOT))
+#define reiserfs_xattrs_optional(s) (reiserfs_xattrs_user(s) || reiserfs_posixacl(s))
+#define reiserfs_barrier_none(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_NONE))
+#define reiserfs_barrier_flush(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_FLUSH))
+
+#define reiserfs_error_panic(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_PANIC))
+#define reiserfs_error_ro(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_RO))
+
+void reiserfs_file_buffer(struct buffer_head *bh, int list);
+extern struct file_system_type reiserfs_fs_type;
+int reiserfs_resize(struct super_block *, unsigned long);
+
+#define CARRY_ON                0
+#define SCHEDULE_OCCURRED       1
+
+#define SB_BUFFER_WITH_SB(s) (REISERFS_SB(s)->s_sbh)
+#define SB_JOURNAL(s) (REISERFS_SB(s)->s_journal)
+#define SB_JOURNAL_1st_RESERVED_BLOCK(s) (SB_JOURNAL(s)->j_1st_reserved_block)
+#define SB_JOURNAL_LEN_FREE(s) (SB_JOURNAL(s)->j_journal_len_free)
+#define SB_AP_BITMAP(s) (REISERFS_SB(s)->s_ap_bitmap)
+
+#define SB_DISK_JOURNAL_HEAD(s) (SB_JOURNAL(s)->j_header_bh->)
+
+/* A safe version of the "bdevname", which returns the "s_id" field of
+ * a superblock or else "Null superblock" if the super block is NULL.
+ */
+static inline char *reiserfs_bdevname(struct super_block *s)
+{
+	return (s == NULL) ? "Null superblock" : s->s_id;
+}
+
+#define reiserfs_is_journal_aborted(journal) (unlikely (__reiserfs_is_journal_aborted (journal)))
+static inline int __reiserfs_is_journal_aborted(struct reiserfs_journal
+						*journal)
+{
+	return test_bit(J_ABORTED, &journal->j_state);
+}
+
+/*
+ * Locking primitives. The write lock is a per superblock
+ * special mutex that has properties close to the Big Kernel Lock
+ * which was used in the previous locking scheme.
+ */
+void reiserfs_write_lock(struct super_block *s);
+void reiserfs_write_unlock(struct super_block *s);
+int reiserfs_write_lock_once(struct super_block *s);
+void reiserfs_write_unlock_once(struct super_block *s, int lock_depth);
+
+#ifdef CONFIG_REISERFS_CHECK
+void reiserfs_lock_check_recursive(struct super_block *s);
+#else
+static inline void reiserfs_lock_check_recursive(struct super_block *s) { }
+#endif
+
+/*
+ * Several mutexes depend on the write lock.
+ * However sometimes we want to relax the write lock while we hold
+ * these mutexes, according to the release/reacquire on schedule()
+ * properties of the Bkl that were used.
+ * Reiserfs performances and locking were based on this scheme.
+ * Now that the write lock is a mutex and not the bkl anymore, doing so
+ * may result in a deadlock:
+ *
+ * A acquire write_lock
+ * A acquire j_commit_mutex
+ * A release write_lock and wait for something
+ * B acquire write_lock
+ * B can't acquire j_commit_mutex and sleep
+ * A can't acquire write lock anymore
+ * deadlock
+ *
+ * What we do here is avoiding such deadlock by playing the same game
+ * than the Bkl: if we can't acquire a mutex that depends on the write lock,
+ * we release the write lock, wait a bit and then retry.
+ *
+ * The mutexes concerned by this hack are:
+ * - The commit mutex of a journal list
+ * - The flush mutex
+ * - The journal lock
+ * - The inode mutex
+ */
+static inline void reiserfs_mutex_lock_safe(struct mutex *m,
+			       struct super_block *s)
+{
+	reiserfs_lock_check_recursive(s);
+	reiserfs_write_unlock(s);
+	mutex_lock(m);
+	reiserfs_write_lock(s);
+}
+
+static inline void
+reiserfs_mutex_lock_nested_safe(struct mutex *m, unsigned int subclass,
+			       struct super_block *s)
+{
+	reiserfs_lock_check_recursive(s);
+	reiserfs_write_unlock(s);
+	mutex_lock_nested(m, subclass);
+	reiserfs_write_lock(s);
+}
+
+static inline void
+reiserfs_down_read_safe(struct rw_semaphore *sem, struct super_block *s)
+{
+	reiserfs_lock_check_recursive(s);
+	reiserfs_write_unlock(s);
+	down_read(sem);
+	reiserfs_write_lock(s);
+}
+
+/*
+ * When we schedule, we usually want to also release the write lock,
+ * according to the previous bkl based locking scheme of reiserfs.
+ */
+static inline void reiserfs_cond_resched(struct super_block *s)
+{
+	if (need_resched()) {
+		reiserfs_write_unlock(s);
+		schedule();
+		reiserfs_write_lock(s);
+	}
+}
+
+struct fid;
+
+/* in reading the #defines, it may help to understand that they employ
+   the following abbreviations:
+
+   B = Buffer
+   I = Item header
+   H = Height within the tree (should be changed to LEV)
+   N = Number of the item in the node
+   STAT = stat data
+   DEH = Directory Entry Header
+   EC = Entry Count
+   E = Entry number
+   UL = Unsigned Long
+   BLKH = BLocK Header
+   UNFM = UNForMatted node
+   DC = Disk Child
+   P = Path
+
+   These #defines are named by concatenating these abbreviations,
+   where first comes the arguments, and last comes the return value,
+   of the macro.
+
+*/
+
+#define USE_INODE_GENERATION_COUNTER
+
+#define REISERFS_PREALLOCATE
+#define DISPLACE_NEW_PACKING_LOCALITIES
+#define PREALLOCATION_SIZE 9
+
+/* n must be power of 2 */
+#define _ROUND_UP(x,n) (((x)+(n)-1u) & ~((n)-1u))
+
+// to be ok for alpha and others we have to align structures to 8 byte
+// boundary.
+// FIXME: do not change 4 by anything else: there is code which relies on that
+#define ROUND_UP(x) _ROUND_UP(x,8LL)
+
+/* debug levels.  Right now, CONFIG_REISERFS_CHECK means print all debug
+** messages.
+*/
+#define REISERFS_DEBUG_CODE 5	/* extra messages to help find/debug errors */
+
+void __reiserfs_warning(struct super_block *s, const char *id,
+			 const char *func, const char *fmt, ...);
+#define reiserfs_warning(s, id, fmt, args...) \
+	 __reiserfs_warning(s, id, __func__, fmt, ##args)
+/* assertions handling */
+
+/** always check a condition and panic if it's false. */
+#define __RASSERT(cond, scond, format, args...)			\
+do {									\
+	if (!(cond))							\
+		reiserfs_panic(NULL, "assertion failure", "(" #cond ") at " \
+			       __FILE__ ":%i:%s: " format "\n",		\
+			       in_interrupt() ? -1 : task_pid_nr(current), \
+			       __LINE__, __func__ , ##args);		\
+} while (0)
+
+#define RASSERT(cond, format, args...) __RASSERT(cond, #cond, format, ##args)
+
+#if defined( CONFIG_REISERFS_CHECK )
+#define RFALSE(cond, format, args...) __RASSERT(!(cond), "!(" #cond ")", format, ##args)
+#else
+#define RFALSE( cond, format, args... ) do {;} while( 0 )
+#endif
+
+#define CONSTF __attribute_const__
+/*
+ * Disk Data Structures
+ */
+
+/***************************************************************************/
+/*                             SUPER BLOCK                                 */
+/***************************************************************************/
+
+/*
+ * Structure of super block on disk, a version of which in RAM is often accessed as REISERFS_SB(s)->s_rs
+ * the version in RAM is part of a larger structure containing fields never written to disk.
+ */
+#define UNSET_HASH 0		// read_super will guess about, what hash names
+		     // in directories were sorted with
+#define TEA_HASH  1
+#define YURA_HASH 2
+#define R5_HASH   3
+#define DEFAULT_HASH R5_HASH
+
+struct journal_params {
+	__le32 jp_journal_1st_block;	/* where does journal start from on its
+					 * device */
+	__le32 jp_journal_dev;	/* journal device st_rdev */
+	__le32 jp_journal_size;	/* size of the journal */
+	__le32 jp_journal_trans_max;	/* max number of blocks in a transaction. */
+	__le32 jp_journal_magic;	/* random value made on fs creation (this
+					 * was sb_journal_block_count) */
+	__le32 jp_journal_max_batch;	/* max number of blocks to batch into a
+					 * trans */
+	__le32 jp_journal_max_commit_age;	/* in seconds, how old can an async
+						 * commit be */
+	__le32 jp_journal_max_trans_age;	/* in seconds, how old can a transaction
+						 * be */
+};
+
+/* this is the super from 3.5.X, where X >= 10 */
+struct reiserfs_super_block_v1 {
+	__le32 s_block_count;	/* blocks count         */
+	__le32 s_free_blocks;	/* free blocks count    */
+	__le32 s_root_block;	/* root block number    */
+	struct journal_params s_journal;
+	__le16 s_blocksize;	/* block size */
+	__le16 s_oid_maxsize;	/* max size of object id array, see
+				 * get_objectid() commentary  */
+	__le16 s_oid_cursize;	/* current size of object id array */
+	__le16 s_umount_state;	/* this is set to 1 when filesystem was
+				 * umounted, to 2 - when not */
+	char s_magic[10];	/* reiserfs magic string indicates that
+				 * file system is reiserfs:
+				 * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
+	__le16 s_fs_state;	/* it is set to used by fsck to mark which
+				 * phase of rebuilding is done */
+	__le32 s_hash_function_code;	/* indicate, what hash function is being use
+					 * to sort names in a directory*/
+	__le16 s_tree_height;	/* height of disk tree */
+	__le16 s_bmap_nr;	/* amount of bitmap blocks needed to address
+				 * each block of file system */
+	__le16 s_version;	/* this field is only reliable on filesystem
+				 * with non-standard journal */
+	__le16 s_reserved_for_journal;	/* size in blocks of journal area on main
+					 * device, we need to keep after
+					 * making fs with non-standard journal */
+} __attribute__ ((__packed__));
+
+#define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1))
+
+/* this is the on disk super block */
+struct reiserfs_super_block {
+	struct reiserfs_super_block_v1 s_v1;
+	__le32 s_inode_generation;
+	__le32 s_flags;		/* Right now used only by inode-attributes, if enabled */
+	unsigned char s_uuid[16];	/* filesystem unique identifier */
+	unsigned char s_label[16];	/* filesystem volume label */
+	__le16 s_mnt_count;		/* Count of mounts since last fsck */
+	__le16 s_max_mnt_count;		/* Maximum mounts before check */
+	__le32 s_lastcheck;		/* Timestamp of last fsck */
+	__le32 s_check_interval;	/* Interval between checks */
+	char s_unused[76];	/* zero filled by mkreiserfs and
+				 * reiserfs_convert_objectid_map_v1()
+				 * so any additions must be updated
+				 * there as well. */
+} __attribute__ ((__packed__));
+
+#define SB_SIZE (sizeof(struct reiserfs_super_block))
+
+#define REISERFS_VERSION_1 0
+#define REISERFS_VERSION_2 2
+
+// on-disk super block fields converted to cpu form
+#define SB_DISK_SUPER_BLOCK(s) (REISERFS_SB(s)->s_rs)
+#define SB_V1_DISK_SUPER_BLOCK(s) (&(SB_DISK_SUPER_BLOCK(s)->s_v1))
+#define SB_BLOCKSIZE(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_blocksize))
+#define SB_BLOCK_COUNT(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_block_count))
+#define SB_FREE_BLOCKS(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks))
+#define SB_REISERFS_MAGIC(s) \
+        (SB_V1_DISK_SUPER_BLOCK(s)->s_magic)
+#define SB_ROOT_BLOCK(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_root_block))
+#define SB_TREE_HEIGHT(s) \
+        le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height))
+#define SB_REISERFS_STATE(s) \
+        le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state))
+#define SB_VERSION(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_version))
+#define SB_BMAP_NR(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr))
+
+#define PUT_SB_BLOCK_COUNT(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_block_count = cpu_to_le32(val); } while (0)
+#define PUT_SB_FREE_BLOCKS(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks = cpu_to_le32(val); } while (0)
+#define PUT_SB_ROOT_BLOCK(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_root_block = cpu_to_le32(val); } while (0)
+#define PUT_SB_TREE_HEIGHT(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height = cpu_to_le16(val); } while (0)
+#define PUT_SB_REISERFS_STATE(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state = cpu_to_le16(val); } while (0)
+#define PUT_SB_VERSION(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_version = cpu_to_le16(val); } while (0)
+#define PUT_SB_BMAP_NR(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr = cpu_to_le16 (val); } while (0)
+
+#define SB_ONDISK_JP(s) (&SB_V1_DISK_SUPER_BLOCK(s)->s_journal)
+#define SB_ONDISK_JOURNAL_SIZE(s) \
+         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_size))
+#define SB_ONDISK_JOURNAL_1st_BLOCK(s) \
+         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_1st_block))
+#define SB_ONDISK_JOURNAL_DEVICE(s) \
+         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_dev))
+#define SB_ONDISK_RESERVED_FOR_JOURNAL(s) \
+         le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal))
+
+#define is_block_in_log_or_reserved_area(s, block) \
+         block >= SB_JOURNAL_1st_RESERVED_BLOCK(s) \
+         && block < SB_JOURNAL_1st_RESERVED_BLOCK(s) +  \
+         ((!is_reiserfs_jr(SB_DISK_SUPER_BLOCK(s)) ? \
+         SB_ONDISK_JOURNAL_SIZE(s) + 1 : SB_ONDISK_RESERVED_FOR_JOURNAL(s)))
+
+int is_reiserfs_3_5(struct reiserfs_super_block *rs);
+int is_reiserfs_3_6(struct reiserfs_super_block *rs);
+int is_reiserfs_jr(struct reiserfs_super_block *rs);
+
+/* ReiserFS leaves the first 64k unused, so that partition labels have
+   enough space.  If someone wants to write a fancy bootloader that
+   needs more than 64k, let us know, and this will be increased in size.
+   This number must be larger than than the largest block size on any
+   platform, or code will break.  -Hans */
+#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
+#define REISERFS_FIRST_BLOCK unused_define
+#define REISERFS_JOURNAL_OFFSET_IN_BYTES REISERFS_DISK_OFFSET_IN_BYTES
+
+/* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */
+#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
+
+/* reiserfs internal error code (used by search_by_key and fix_nodes)) */
+#define CARRY_ON      0
+#define REPEAT_SEARCH -1
+#define IO_ERROR      -2
+#define NO_DISK_SPACE -3
+#define NO_BALANCING_NEEDED  (-4)
+#define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5)
+#define QUOTA_EXCEEDED -6
+
+typedef __u32 b_blocknr_t;
+typedef __le32 unp_t;
+
+struct unfm_nodeinfo {
+	unp_t unfm_nodenum;
+	unsigned short unfm_freespace;
+};
+
+/* there are two formats of keys: 3.5 and 3.6
+ */
+#define KEY_FORMAT_3_5 0
+#define KEY_FORMAT_3_6 1
+
+/* there are two stat datas */
+#define STAT_DATA_V1 0
+#define STAT_DATA_V2 1
+
+static inline struct reiserfs_inode_info *REISERFS_I(const struct inode *inode)
+{
+	return container_of(inode, struct reiserfs_inode_info, vfs_inode);
+}
+
+static inline struct reiserfs_sb_info *REISERFS_SB(const struct super_block *sb)
+{
+	return sb->s_fs_info;
+}
+
+/* Don't trust REISERFS_SB(sb)->s_bmap_nr, it's a u16
+ * which overflows on large file systems. */
+static inline __u32 reiserfs_bmap_count(struct super_block *sb)
+{
+	return (SB_BLOCK_COUNT(sb) - 1) / (sb->s_blocksize * 8) + 1;
+}
+
+static inline int bmap_would_wrap(unsigned bmap_nr)
+{
+	return bmap_nr > ((1LL << 16) - 1);
+}
+
+/** this says about version of key of all items (but stat data) the
+    object consists of */
+#define get_inode_item_key_version( inode )                                    \
+    ((REISERFS_I(inode)->i_flags & i_item_key_version_mask) ? KEY_FORMAT_3_6 : KEY_FORMAT_3_5)
+
+#define set_inode_item_key_version( inode, version )                           \
+         ({ if((version)==KEY_FORMAT_3_6)                                      \
+                REISERFS_I(inode)->i_flags |= i_item_key_version_mask;      \
+            else                                                               \
+                REISERFS_I(inode)->i_flags &= ~i_item_key_version_mask; })
+
+#define get_inode_sd_version(inode)                                            \
+    ((REISERFS_I(inode)->i_flags & i_stat_data_version_mask) ? STAT_DATA_V2 : STAT_DATA_V1)
+
+#define set_inode_sd_version(inode, version)                                   \
+         ({ if((version)==STAT_DATA_V2)                                        \
+                REISERFS_I(inode)->i_flags |= i_stat_data_version_mask;     \
+            else                                                               \
+                REISERFS_I(inode)->i_flags &= ~i_stat_data_version_mask; })
+
+/* This is an aggressive tail suppression policy, I am hoping it
+   improves our benchmarks. The principle behind it is that percentage
+   space saving is what matters, not absolute space saving.  This is
+   non-intuitive, but it helps to understand it if you consider that the
+   cost to access 4 blocks is not much more than the cost to access 1
+   block, if you have to do a seek and rotate.  A tail risks a
+   non-linear disk access that is significant as a percentage of total
+   time cost for a 4 block file and saves an amount of space that is
+   less significant as a percentage of space, or so goes the hypothesis.
+   -Hans */
+#define STORE_TAIL_IN_UNFM_S1(n_file_size,n_tail_size,n_block_size) \
+(\
+  (!(n_tail_size)) || \
+  (((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \
+   ( (n_file_size) >= (n_block_size) * 4 ) || \
+   ( ( (n_file_size) >= (n_block_size) * 3 ) && \
+     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size))/4) ) || \
+   ( ( (n_file_size) >= (n_block_size) * 2 ) && \
+     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size))/2) ) || \
+   ( ( (n_file_size) >= (n_block_size) ) && \
+     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) \
+)
+
+/* Another strategy for tails, this one means only create a tail if all the
+   file would fit into one DIRECT item.
+   Primary intention for this one is to increase performance by decreasing
+   seeking.
+*/
+#define STORE_TAIL_IN_UNFM_S2(n_file_size,n_tail_size,n_block_size) \
+(\
+  (!(n_tail_size)) || \
+  (((n_file_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) ) \
+)
+
+/*
+ * values for s_umount_state field
+ */
+#define REISERFS_VALID_FS    1
+#define REISERFS_ERROR_FS    2
+
+//
+// there are 5 item types currently
+//
+#define TYPE_STAT_DATA 0
+#define TYPE_INDIRECT 1
+#define TYPE_DIRECT 2
+#define TYPE_DIRENTRY 3
+#define TYPE_MAXTYPE 3
+#define TYPE_ANY 15		// FIXME: comment is required
+
+/***************************************************************************/
+/*                       KEY & ITEM HEAD                                   */
+/***************************************************************************/
+
+//
+// directories use this key as well as old files
+//
+struct offset_v1 {
+	__le32 k_offset;
+	__le32 k_uniqueness;
+} __attribute__ ((__packed__));
+
+struct offset_v2 {
+	__le64 v;
+} __attribute__ ((__packed__));
+
+static inline __u16 offset_v2_k_type(const struct offset_v2 *v2)
+{
+	__u8 type = le64_to_cpu(v2->v) >> 60;
+	return (type <= TYPE_MAXTYPE) ? type : TYPE_ANY;
+}
+
+static inline void set_offset_v2_k_type(struct offset_v2 *v2, int type)
+{
+	v2->v =
+	    (v2->v & cpu_to_le64(~0ULL >> 4)) | cpu_to_le64((__u64) type << 60);
+}
+
+static inline loff_t offset_v2_k_offset(const struct offset_v2 *v2)
+{
+	return le64_to_cpu(v2->v) & (~0ULL >> 4);
+}
+
+static inline void set_offset_v2_k_offset(struct offset_v2 *v2, loff_t offset)
+{
+	offset &= (~0ULL >> 4);
+	v2->v = (v2->v & cpu_to_le64(15ULL << 60)) | cpu_to_le64(offset);
+}
+
+/* Key of an item determines its location in the S+tree, and
+   is composed of 4 components */
+struct reiserfs_key {
+	__le32 k_dir_id;	/* packing locality: by default parent
+				   directory object id */
+	__le32 k_objectid;	/* object identifier */
+	union {
+		struct offset_v1 k_offset_v1;
+		struct offset_v2 k_offset_v2;
+	} __attribute__ ((__packed__)) u;
+} __attribute__ ((__packed__));
+
+struct in_core_key {
+	__u32 k_dir_id;		/* packing locality: by default parent
+				   directory object id */
+	__u32 k_objectid;	/* object identifier */
+	__u64 k_offset;
+	__u8 k_type;
+};
+
+struct cpu_key {
+	struct in_core_key on_disk_key;
+	int version;
+	int key_length;		/* 3 in all cases but direct2indirect and
+				   indirect2direct conversion */
+};
+
+/* Our function for comparing keys can compare keys of different
+   lengths.  It takes as a parameter the length of the keys it is to
+   compare.  These defines are used in determining what is to be passed
+   to it as that parameter. */
+#define REISERFS_FULL_KEY_LEN     4
+#define REISERFS_SHORT_KEY_LEN    2
+
+/* The result of the key compare */
+#define FIRST_GREATER 1
+#define SECOND_GREATER -1
+#define KEYS_IDENTICAL 0
+#define KEY_FOUND 1
+#define KEY_NOT_FOUND 0
+
+#define KEY_SIZE (sizeof(struct reiserfs_key))
+#define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32))
+
+/* return values for search_by_key and clones */
+#define ITEM_FOUND 1
+#define ITEM_NOT_FOUND 0
+#define ENTRY_FOUND 1
+#define ENTRY_NOT_FOUND 0
+#define DIRECTORY_NOT_FOUND -1
+#define REGULAR_FILE_FOUND -2
+#define DIRECTORY_FOUND -3
+#define BYTE_FOUND 1
+#define BYTE_NOT_FOUND 0
+#define FILE_NOT_FOUND -1
+
+#define POSITION_FOUND 1
+#define POSITION_NOT_FOUND 0
+
+// return values for reiserfs_find_entry and search_by_entry_key
+#define NAME_FOUND 1
+#define NAME_NOT_FOUND 0
+#define GOTO_PREVIOUS_ITEM 2
+#define NAME_FOUND_INVISIBLE 3
+
+/*  Everything in the filesystem is stored as a set of items.  The
+    item head contains the key of the item, its free space (for
+    indirect items) and specifies the location of the item itself
+    within the block.  */
+
+struct item_head {
+	/* Everything in the tree is found by searching for it based on
+	 * its key.*/
+	struct reiserfs_key ih_key;
+	union {
+		/* The free space in the last unformatted node of an
+		   indirect item if this is an indirect item.  This
+		   equals 0xFFFF iff this is a direct item or stat data
+		   item. Note that the key, not this field, is used to
+		   determine the item type, and thus which field this
+		   union contains. */
+		__le16 ih_free_space_reserved;
+		/* Iff this is a directory item, this field equals the
+		   number of directory entries in the directory item. */
+		__le16 ih_entry_count;
+	} __attribute__ ((__packed__)) u;
+	__le16 ih_item_len;	/* total size of the item body */
+	__le16 ih_item_location;	/* an offset to the item body
+					 * within the block */
+	__le16 ih_version;	/* 0 for all old items, 2 for new
+				   ones. Highest bit is set by fsck
+				   temporary, cleaned after all
+				   done */
+} __attribute__ ((__packed__));
+/* size of item header     */
+#define IH_SIZE (sizeof(struct item_head))
+
+#define ih_free_space(ih)            le16_to_cpu((ih)->u.ih_free_space_reserved)
+#define ih_version(ih)               le16_to_cpu((ih)->ih_version)
+#define ih_entry_count(ih)           le16_to_cpu((ih)->u.ih_entry_count)
+#define ih_location(ih)              le16_to_cpu((ih)->ih_item_location)
+#define ih_item_len(ih)              le16_to_cpu((ih)->ih_item_len)
+
+#define put_ih_free_space(ih, val)   do { (ih)->u.ih_free_space_reserved = cpu_to_le16(val); } while(0)
+#define put_ih_version(ih, val)      do { (ih)->ih_version = cpu_to_le16(val); } while (0)
+#define put_ih_entry_count(ih, val)  do { (ih)->u.ih_entry_count = cpu_to_le16(val); } while (0)
+#define put_ih_location(ih, val)     do { (ih)->ih_item_location = cpu_to_le16(val); } while (0)
+#define put_ih_item_len(ih, val)     do { (ih)->ih_item_len = cpu_to_le16(val); } while (0)
+
+#define unreachable_item(ih) (ih_version(ih) & (1 << 15))
+
+#define get_ih_free_space(ih) (ih_version (ih) == KEY_FORMAT_3_6 ? 0 : ih_free_space (ih))
+#define set_ih_free_space(ih,val) put_ih_free_space((ih), ((ih_version(ih) == KEY_FORMAT_3_6) ? 0 : (val)))
+
+/* these operate on indirect items, where you've got an array of ints
+** at a possibly unaligned location.  These are a noop on ia32
+** 
+** p is the array of __u32, i is the index into the array, v is the value
+** to store there.
+*/
+#define get_block_num(p, i) get_unaligned_le32((p) + (i))
+#define put_block_num(p, i, v) put_unaligned_le32((v), (p) + (i))
+
+//
+// in old version uniqueness field shows key type
+//
+#define V1_SD_UNIQUENESS 0
+#define V1_INDIRECT_UNIQUENESS 0xfffffffe
+#define V1_DIRECT_UNIQUENESS 0xffffffff
+#define V1_DIRENTRY_UNIQUENESS 500
+#define V1_ANY_UNIQUENESS 555	// FIXME: comment is required
+
+//
+// here are conversion routines
+//
+static inline int uniqueness2type(__u32 uniqueness) CONSTF;
+static inline int uniqueness2type(__u32 uniqueness)
+{
+	switch ((int)uniqueness) {
+	case V1_SD_UNIQUENESS:
+		return TYPE_STAT_DATA;
+	case V1_INDIRECT_UNIQUENESS:
+		return TYPE_INDIRECT;
+	case V1_DIRECT_UNIQUENESS:
+		return TYPE_DIRECT;
+	case V1_DIRENTRY_UNIQUENESS:
+		return TYPE_DIRENTRY;
+	case V1_ANY_UNIQUENESS:
+	default:
+		return TYPE_ANY;
+	}
+}
+
+static inline __u32 type2uniqueness(int type) CONSTF;
+static inline __u32 type2uniqueness(int type)
+{
+	switch (type) {
+	case TYPE_STAT_DATA:
+		return V1_SD_UNIQUENESS;
+	case TYPE_INDIRECT:
+		return V1_INDIRECT_UNIQUENESS;
+	case TYPE_DIRECT:
+		return V1_DIRECT_UNIQUENESS;
+	case TYPE_DIRENTRY:
+		return V1_DIRENTRY_UNIQUENESS;
+	case TYPE_ANY:
+	default:
+		return V1_ANY_UNIQUENESS;
+	}
+}
+
+//
+// key is pointer to on disk key which is stored in le, result is cpu,
+// there is no way to get version of object from key, so, provide
+// version to these defines
+//
+static inline loff_t le_key_k_offset(int version,
+				     const struct reiserfs_key *key)
+{
+	return (version == KEY_FORMAT_3_5) ?
+	    le32_to_cpu(key->u.k_offset_v1.k_offset) :
+	    offset_v2_k_offset(&(key->u.k_offset_v2));
+}
+
+static inline loff_t le_ih_k_offset(const struct item_head *ih)
+{
+	return le_key_k_offset(ih_version(ih), &(ih->ih_key));
+}
+
+static inline loff_t le_key_k_type(int version, const struct reiserfs_key *key)
+{
+	return (version == KEY_FORMAT_3_5) ?
+	    uniqueness2type(le32_to_cpu(key->u.k_offset_v1.k_uniqueness)) :
+	    offset_v2_k_type(&(key->u.k_offset_v2));
+}
+
+static inline loff_t le_ih_k_type(const struct item_head *ih)
+{
+	return le_key_k_type(ih_version(ih), &(ih->ih_key));
+}
+
+static inline void set_le_key_k_offset(int version, struct reiserfs_key *key,
+				       loff_t offset)
+{
+	(version == KEY_FORMAT_3_5) ? (void)(key->u.k_offset_v1.k_offset = cpu_to_le32(offset)) :	/* jdm check */
+	    (void)(set_offset_v2_k_offset(&(key->u.k_offset_v2), offset));
+}
+
+static inline void set_le_ih_k_offset(struct item_head *ih, loff_t offset)
+{
+	set_le_key_k_offset(ih_version(ih), &(ih->ih_key), offset);
+}
+
+static inline void set_le_key_k_type(int version, struct reiserfs_key *key,
+				     int type)
+{
+	(version == KEY_FORMAT_3_5) ?
+	    (void)(key->u.k_offset_v1.k_uniqueness =
+		   cpu_to_le32(type2uniqueness(type)))
+	    : (void)(set_offset_v2_k_type(&(key->u.k_offset_v2), type));
+}
+
+static inline void set_le_ih_k_type(struct item_head *ih, int type)
+{
+	set_le_key_k_type(ih_version(ih), &(ih->ih_key), type);
+}
+
+static inline int is_direntry_le_key(int version, struct reiserfs_key *key)
+{
+	return le_key_k_type(version, key) == TYPE_DIRENTRY;
+}
+
+static inline int is_direct_le_key(int version, struct reiserfs_key *key)
+{
+	return le_key_k_type(version, key) == TYPE_DIRECT;
+}
+
+static inline int is_indirect_le_key(int version, struct reiserfs_key *key)
+{
+	return le_key_k_type(version, key) == TYPE_INDIRECT;
+}
+
+static inline int is_statdata_le_key(int version, struct reiserfs_key *key)
+{
+	return le_key_k_type(version, key) == TYPE_STAT_DATA;
+}
+
+//
+// item header has version.
+//
+static inline int is_direntry_le_ih(struct item_head *ih)
+{
+	return is_direntry_le_key(ih_version(ih), &ih->ih_key);
+}
+
+static inline int is_direct_le_ih(struct item_head *ih)
+{
+	return is_direct_le_key(ih_version(ih), &ih->ih_key);
+}
+
+static inline int is_indirect_le_ih(struct item_head *ih)
+{
+	return is_indirect_le_key(ih_version(ih), &ih->ih_key);
+}
+
+static inline int is_statdata_le_ih(struct item_head *ih)
+{
+	return is_statdata_le_key(ih_version(ih), &ih->ih_key);
+}
+
+//
+// key is pointer to cpu key, result is cpu
+//
+static inline loff_t cpu_key_k_offset(const struct cpu_key *key)
+{
+	return key->on_disk_key.k_offset;
+}
+
+static inline loff_t cpu_key_k_type(const struct cpu_key *key)
+{
+	return key->on_disk_key.k_type;
+}
+
+static inline void set_cpu_key_k_offset(struct cpu_key *key, loff_t offset)
+{
+	key->on_disk_key.k_offset = offset;
+}
+
+static inline void set_cpu_key_k_type(struct cpu_key *key, int type)
+{
+	key->on_disk_key.k_type = type;
+}
+
+static inline void cpu_key_k_offset_dec(struct cpu_key *key)
+{
+	key->on_disk_key.k_offset--;
+}
+
+#define is_direntry_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRENTRY)
+#define is_direct_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRECT)
+#define is_indirect_cpu_key(key) (cpu_key_k_type (key) == TYPE_INDIRECT)
+#define is_statdata_cpu_key(key) (cpu_key_k_type (key) == TYPE_STAT_DATA)
+
+/* are these used ? */
+#define is_direntry_cpu_ih(ih) (is_direntry_cpu_key (&((ih)->ih_key)))
+#define is_direct_cpu_ih(ih) (is_direct_cpu_key (&((ih)->ih_key)))
+#define is_indirect_cpu_ih(ih) (is_indirect_cpu_key (&((ih)->ih_key)))
+#define is_statdata_cpu_ih(ih) (is_statdata_cpu_key (&((ih)->ih_key)))
+
+#define I_K_KEY_IN_ITEM(ih, key, n_blocksize) \
+    (!COMP_SHORT_KEYS(ih, key) && \
+	  I_OFF_BYTE_IN_ITEM(ih, k_offset(key), n_blocksize))
+
+/* maximal length of item */
+#define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE)
+#define MIN_ITEM_LEN 1
+
+/* object identifier for root dir */
+#define REISERFS_ROOT_OBJECTID 2
+#define REISERFS_ROOT_PARENT_OBJECTID 1
+
+extern struct reiserfs_key root_key;
+
+/* 
+ * Picture represents a leaf of the S+tree
+ *  ______________________________________________________
+ * |      |  Array of     |                   |           |
+ * |Block |  Object-Item  |      F r e e      |  Objects- |
+ * | head |  Headers      |     S p a c e     |   Items   |
+ * |______|_______________|___________________|___________|
+ */
+
+/* Header of a disk block.  More precisely, header of a formatted leaf
+   or internal node, and not the header of an unformatted node. */
+struct block_head {
+	__le16 blk_level;	/* Level of a block in the tree. */
+	__le16 blk_nr_item;	/* Number of keys/items in a block. */
+	__le16 blk_free_space;	/* Block free space in bytes. */
+	__le16 blk_reserved;
+	/* dump this in v4/planA */
+	struct reiserfs_key blk_right_delim_key;	/* kept only for compatibility */
+};
+
+#define BLKH_SIZE                     (sizeof(struct block_head))
+#define blkh_level(p_blkh)            (le16_to_cpu((p_blkh)->blk_level))
+#define blkh_nr_item(p_blkh)          (le16_to_cpu((p_blkh)->blk_nr_item))
+#define blkh_free_space(p_blkh)       (le16_to_cpu((p_blkh)->blk_free_space))
+#define blkh_reserved(p_blkh)         (le16_to_cpu((p_blkh)->blk_reserved))
+#define set_blkh_level(p_blkh,val)    ((p_blkh)->blk_level = cpu_to_le16(val))
+#define set_blkh_nr_item(p_blkh,val)  ((p_blkh)->blk_nr_item = cpu_to_le16(val))
+#define set_blkh_free_space(p_blkh,val) ((p_blkh)->blk_free_space = cpu_to_le16(val))
+#define set_blkh_reserved(p_blkh,val) ((p_blkh)->blk_reserved = cpu_to_le16(val))
+#define blkh_right_delim_key(p_blkh)  ((p_blkh)->blk_right_delim_key)
+#define set_blkh_right_delim_key(p_blkh,val)  ((p_blkh)->blk_right_delim_key = val)
+
+/*
+ * values for blk_level field of the struct block_head
+ */
+
+#define FREE_LEVEL 0		/* when node gets removed from the tree its
+				   blk_level is set to FREE_LEVEL. It is then
+				   used to see whether the node is still in the
+				   tree */
+
+#define DISK_LEAF_NODE_LEVEL  1	/* Leaf node level. */
+
+/* Given the buffer head of a formatted node, resolve to the block head of that node. */
+#define B_BLK_HEAD(bh)			((struct block_head *)((bh)->b_data))
+/* Number of items that are in buffer. */
+#define B_NR_ITEMS(bh)			(blkh_nr_item(B_BLK_HEAD(bh)))
+#define B_LEVEL(bh)			(blkh_level(B_BLK_HEAD(bh)))
+#define B_FREE_SPACE(bh)		(blkh_free_space(B_BLK_HEAD(bh)))
+
+#define PUT_B_NR_ITEMS(bh, val)		do { set_blkh_nr_item(B_BLK_HEAD(bh), val); } while (0)
+#define PUT_B_LEVEL(bh, val)		do { set_blkh_level(B_BLK_HEAD(bh), val); } while (0)
+#define PUT_B_FREE_SPACE(bh, val)	do { set_blkh_free_space(B_BLK_HEAD(bh), val); } while (0)
+
+/* Get right delimiting key. -- little endian */
+#define B_PRIGHT_DELIM_KEY(bh)		(&(blk_right_delim_key(B_BLK_HEAD(bh))))
+
+/* Does the buffer contain a disk leaf. */
+#define B_IS_ITEMS_LEVEL(bh)		(B_LEVEL(bh) == DISK_LEAF_NODE_LEVEL)
+
+/* Does the buffer contain a disk internal node */
+#define B_IS_KEYS_LEVEL(bh)      (B_LEVEL(bh) > DISK_LEAF_NODE_LEVEL \
+					    && B_LEVEL(bh) <= MAX_HEIGHT)
+
+/***************************************************************************/
+/*                             STAT DATA                                   */
+/***************************************************************************/
+
+//
+// old stat data is 32 bytes long. We are going to distinguish new one by
+// different size
+//
+struct stat_data_v1 {
+	__le16 sd_mode;		/* file type, permissions */
+	__le16 sd_nlink;	/* number of hard links */
+	__le16 sd_uid;		/* owner */
+	__le16 sd_gid;		/* group */
+	__le32 sd_size;		/* file size */
+	__le32 sd_atime;	/* time of last access */
+	__le32 sd_mtime;	/* time file was last modified  */
+	__le32 sd_ctime;	/* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
+	union {
+		__le32 sd_rdev;
+		__le32 sd_blocks;	/* number of blocks file uses */
+	} __attribute__ ((__packed__)) u;
+	__le32 sd_first_direct_byte;	/* first byte of file which is stored
+					   in a direct item: except that if it
+					   equals 1 it is a symlink and if it
+					   equals ~(__u32)0 there is no
+					   direct item.  The existence of this
+					   field really grates on me. Let's
+					   replace it with a macro based on
+					   sd_size and our tail suppression
+					   policy.  Someday.  -Hans */
+} __attribute__ ((__packed__));
+
+#define SD_V1_SIZE              (sizeof(struct stat_data_v1))
+#define stat_data_v1(ih)        (ih_version (ih) == KEY_FORMAT_3_5)
+#define sd_v1_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
+#define set_sd_v1_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
+#define sd_v1_nlink(sdp)        (le16_to_cpu((sdp)->sd_nlink))
+#define set_sd_v1_nlink(sdp,v)  ((sdp)->sd_nlink = cpu_to_le16(v))
+#define sd_v1_uid(sdp)          (le16_to_cpu((sdp)->sd_uid))
+#define set_sd_v1_uid(sdp,v)    ((sdp)->sd_uid = cpu_to_le16(v))
+#define sd_v1_gid(sdp)          (le16_to_cpu((sdp)->sd_gid))
+#define set_sd_v1_gid(sdp,v)    ((sdp)->sd_gid = cpu_to_le16(v))
+#define sd_v1_size(sdp)         (le32_to_cpu((sdp)->sd_size))
+#define set_sd_v1_size(sdp,v)   ((sdp)->sd_size = cpu_to_le32(v))
+#define sd_v1_atime(sdp)        (le32_to_cpu((sdp)->sd_atime))
+#define set_sd_v1_atime(sdp,v)  ((sdp)->sd_atime = cpu_to_le32(v))
+#define sd_v1_mtime(sdp)        (le32_to_cpu((sdp)->sd_mtime))
+#define set_sd_v1_mtime(sdp,v)  ((sdp)->sd_mtime = cpu_to_le32(v))
+#define sd_v1_ctime(sdp)        (le32_to_cpu((sdp)->sd_ctime))
+#define set_sd_v1_ctime(sdp,v)  ((sdp)->sd_ctime = cpu_to_le32(v))
+#define sd_v1_rdev(sdp)         (le32_to_cpu((sdp)->u.sd_rdev))
+#define set_sd_v1_rdev(sdp,v)   ((sdp)->u.sd_rdev = cpu_to_le32(v))
+#define sd_v1_blocks(sdp)       (le32_to_cpu((sdp)->u.sd_blocks))
+#define set_sd_v1_blocks(sdp,v) ((sdp)->u.sd_blocks = cpu_to_le32(v))
+#define sd_v1_first_direct_byte(sdp) \
+                                (le32_to_cpu((sdp)->sd_first_direct_byte))
+#define set_sd_v1_first_direct_byte(sdp,v) \
+                                ((sdp)->sd_first_direct_byte = cpu_to_le32(v))
+
+/* inode flags stored in sd_attrs (nee sd_reserved) */
+
+/* we want common flags to have the same values as in ext2,
+   so chattr(1) will work without problems */
+#define REISERFS_IMMUTABLE_FL FS_IMMUTABLE_FL
+#define REISERFS_APPEND_FL    FS_APPEND_FL
+#define REISERFS_SYNC_FL      FS_SYNC_FL
+#define REISERFS_NOATIME_FL   FS_NOATIME_FL
+#define REISERFS_NODUMP_FL    FS_NODUMP_FL
+#define REISERFS_SECRM_FL     FS_SECRM_FL
+#define REISERFS_UNRM_FL      FS_UNRM_FL
+#define REISERFS_COMPR_FL     FS_COMPR_FL
+#define REISERFS_NOTAIL_FL    FS_NOTAIL_FL
+
+/* persistent flags that file inherits from the parent directory */
+#define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL |	\
+				REISERFS_SYNC_FL |	\
+				REISERFS_NOATIME_FL |	\
+				REISERFS_NODUMP_FL |	\
+				REISERFS_SECRM_FL |	\
+				REISERFS_COMPR_FL |	\
+				REISERFS_NOTAIL_FL )
+
+/* Stat Data on disk (reiserfs version of UFS disk inode minus the
+   address blocks) */
+struct stat_data {
+	__le16 sd_mode;		/* file type, permissions */
+	__le16 sd_attrs;	/* persistent inode flags */
+	__le32 sd_nlink;	/* number of hard links */
+	__le64 sd_size;		/* file size */
+	__le32 sd_uid;		/* owner */
+	__le32 sd_gid;		/* group */
+	__le32 sd_atime;	/* time of last access */
+	__le32 sd_mtime;	/* time file was last modified  */
+	__le32 sd_ctime;	/* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
+	__le32 sd_blocks;
+	union {
+		__le32 sd_rdev;
+		__le32 sd_generation;
+		//__le32 sd_first_direct_byte;
+		/* first byte of file which is stored in a
+		   direct item: except that if it equals 1
+		   it is a symlink and if it equals
+		   ~(__u32)0 there is no direct item.  The
+		   existence of this field really grates
+		   on me. Let's replace it with a macro
+		   based on sd_size and our tail
+		   suppression policy? */
+	} __attribute__ ((__packed__)) u;
+} __attribute__ ((__packed__));
+//
+// this is 44 bytes long
+//
+#define SD_SIZE (sizeof(struct stat_data))
+#define SD_V2_SIZE              SD_SIZE
+#define stat_data_v2(ih)        (ih_version (ih) == KEY_FORMAT_3_6)
+#define sd_v2_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
+#define set_sd_v2_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
+/* sd_reserved */
+/* set_sd_reserved */
+#define sd_v2_nlink(sdp)        (le32_to_cpu((sdp)->sd_nlink))
+#define set_sd_v2_nlink(sdp,v)  ((sdp)->sd_nlink = cpu_to_le32(v))
+#define sd_v2_size(sdp)         (le64_to_cpu((sdp)->sd_size))
+#define set_sd_v2_size(sdp,v)   ((sdp)->sd_size = cpu_to_le64(v))
+#define sd_v2_uid(sdp)          (le32_to_cpu((sdp)->sd_uid))
+#define set_sd_v2_uid(sdp,v)    ((sdp)->sd_uid = cpu_to_le32(v))
+#define sd_v2_gid(sdp)          (le32_to_cpu((sdp)->sd_gid))
+#define set_sd_v2_gid(sdp,v)    ((sdp)->sd_gid = cpu_to_le32(v))
+#define sd_v2_atime(sdp)        (le32_to_cpu((sdp)->sd_atime))
+#define set_sd_v2_atime(sdp,v)  ((sdp)->sd_atime = cpu_to_le32(v))
+#define sd_v2_mtime(sdp)        (le32_to_cpu((sdp)->sd_mtime))
+#define set_sd_v2_mtime(sdp,v)  ((sdp)->sd_mtime = cpu_to_le32(v))
+#define sd_v2_ctime(sdp)        (le32_to_cpu((sdp)->sd_ctime))
+#define set_sd_v2_ctime(sdp,v)  ((sdp)->sd_ctime = cpu_to_le32(v))
+#define sd_v2_blocks(sdp)       (le32_to_cpu((sdp)->sd_blocks))
+#define set_sd_v2_blocks(sdp,v) ((sdp)->sd_blocks = cpu_to_le32(v))
+#define sd_v2_rdev(sdp)         (le32_to_cpu((sdp)->u.sd_rdev))
+#define set_sd_v2_rdev(sdp,v)   ((sdp)->u.sd_rdev = cpu_to_le32(v))
+#define sd_v2_generation(sdp)   (le32_to_cpu((sdp)->u.sd_generation))
+#define set_sd_v2_generation(sdp,v) ((sdp)->u.sd_generation = cpu_to_le32(v))
+#define sd_v2_attrs(sdp)         (le16_to_cpu((sdp)->sd_attrs))
+#define set_sd_v2_attrs(sdp,v)   ((sdp)->sd_attrs = cpu_to_le16(v))
+
+/***************************************************************************/
+/*                      DIRECTORY STRUCTURE                                */
+/***************************************************************************/
+/* 
+   Picture represents the structure of directory items
+   ________________________________________________
+   |  Array of     |   |     |        |       |   |
+   | directory     |N-1| N-2 | ....   |   1st |0th|
+   | entry headers |   |     |        |       |   |
+   |_______________|___|_____|________|_______|___|
+                    <----   directory entries         ------>
+
+ First directory item has k_offset component 1. We store "." and ".."
+ in one item, always, we never split "." and ".." into differing
+ items.  This makes, among other things, the code for removing
+ directories simpler. */
+#define SD_OFFSET  0
+#define SD_UNIQUENESS 0
+#define DOT_OFFSET 1
+#define DOT_DOT_OFFSET 2
+#define DIRENTRY_UNIQUENESS 500
+
+/* */
+#define FIRST_ITEM_OFFSET 1
+
+/*
+   Q: How to get key of object pointed to by entry from entry?  
+
+   A: Each directory entry has its header. This header has deh_dir_id and deh_objectid fields, those are key
+      of object, entry points to */
+
+/* NOT IMPLEMENTED:   
+   Directory will someday contain stat data of object */
+
+struct reiserfs_de_head {
+	__le32 deh_offset;	/* third component of the directory entry key */
+	__le32 deh_dir_id;	/* objectid of the parent directory of the object, that is referenced
+				   by directory entry */
+	__le32 deh_objectid;	/* objectid of the object, that is referenced by directory entry */
+	__le16 deh_location;	/* offset of name in the whole item */
+	__le16 deh_state;	/* whether 1) entry contains stat data (for future), and 2) whether
+				   entry is hidden (unlinked) */
+} __attribute__ ((__packed__));
+#define DEH_SIZE                  sizeof(struct reiserfs_de_head)
+#define deh_offset(p_deh)         (le32_to_cpu((p_deh)->deh_offset))
+#define deh_dir_id(p_deh)         (le32_to_cpu((p_deh)->deh_dir_id))
+#define deh_objectid(p_deh)       (le32_to_cpu((p_deh)->deh_objectid))
+#define deh_location(p_deh)       (le16_to_cpu((p_deh)->deh_location))
+#define deh_state(p_deh)          (le16_to_cpu((p_deh)->deh_state))
+
+#define put_deh_offset(p_deh,v)   ((p_deh)->deh_offset = cpu_to_le32((v)))
+#define put_deh_dir_id(p_deh,v)   ((p_deh)->deh_dir_id = cpu_to_le32((v)))
+#define put_deh_objectid(p_deh,v) ((p_deh)->deh_objectid = cpu_to_le32((v)))
+#define put_deh_location(p_deh,v) ((p_deh)->deh_location = cpu_to_le16((v)))
+#define put_deh_state(p_deh,v)    ((p_deh)->deh_state = cpu_to_le16((v)))
+
+/* empty directory contains two entries "." and ".." and their headers */
+#define EMPTY_DIR_SIZE \
+(DEH_SIZE * 2 + ROUND_UP (strlen (".")) + ROUND_UP (strlen ("..")))
+
+/* old format directories have this size when empty */
+#define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3)
+
+#define DEH_Statdata 0		/* not used now */
+#define DEH_Visible 2
+
+/* 64 bit systems (and the S/390) need to be aligned explicitly -jdm */
+#if BITS_PER_LONG == 64 || defined(__s390__) || defined(__hppa__)
+#   define ADDR_UNALIGNED_BITS  (3)
+#endif
+
+/* These are only used to manipulate deh_state.
+ * Because of this, we'll use the ext2_ bit routines,
+ * since they are little endian */
+#ifdef ADDR_UNALIGNED_BITS
+
+#   define aligned_address(addr)           ((void *)((long)(addr) & ~((1UL << ADDR_UNALIGNED_BITS) - 1)))
+#   define unaligned_offset(addr)          (((int)((long)(addr) & ((1 << ADDR_UNALIGNED_BITS) - 1))) << 3)
+
+#   define set_bit_unaligned(nr, addr)	\
+	__test_and_set_bit_le((nr) + unaligned_offset(addr), aligned_address(addr))
+#   define clear_bit_unaligned(nr, addr)	\
+	__test_and_clear_bit_le((nr) + unaligned_offset(addr), aligned_address(addr))
+#   define test_bit_unaligned(nr, addr)	\
+	test_bit_le((nr) + unaligned_offset(addr), aligned_address(addr))
+
+#else
+
+#   define set_bit_unaligned(nr, addr)	__test_and_set_bit_le(nr, addr)
+#   define clear_bit_unaligned(nr, addr)	__test_and_clear_bit_le(nr, addr)
+#   define test_bit_unaligned(nr, addr)	test_bit_le(nr, addr)
+
+#endif
+
+#define mark_de_with_sd(deh)        set_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
+#define mark_de_without_sd(deh)     clear_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
+#define mark_de_visible(deh)	    set_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+#define mark_de_hidden(deh)	    clear_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+
+#define de_with_sd(deh)		    test_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
+#define de_visible(deh)	    	    test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+#define de_hidden(deh)	    	    !test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+
+extern void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid,
+				   __le32 par_dirid, __le32 par_objid);
+extern void make_empty_dir_item(char *body, __le32 dirid, __le32 objid,
+				__le32 par_dirid, __le32 par_objid);
+
+/* array of the entry headers */
+ /* get item body */
+#define B_I_PITEM(bh,ih) ( (bh)->b_data + ih_location(ih) )
+#define B_I_DEH(bh,ih) ((struct reiserfs_de_head *)(B_I_PITEM(bh,ih)))
+
+/* length of the directory entry in directory item. This define
+   calculates length of i-th directory entry using directory entry
+   locations from dir entry head. When it calculates length of 0-th
+   directory entry, it uses length of whole item in place of entry
+   location of the non-existent following entry in the calculation.
+   See picture above.*/
+/*
+#define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \
+((i) ? (deh_location((deh)-1) - deh_location((deh))) : (ih_item_len((ih)) - deh_location((deh))))
+*/
+static inline int entry_length(const struct buffer_head *bh,
+			       const struct item_head *ih, int pos_in_item)
+{
+	struct reiserfs_de_head *deh;
+
+	deh = B_I_DEH(bh, ih) + pos_in_item;
+	if (pos_in_item)
+		return deh_location(deh - 1) - deh_location(deh);
+
+	return ih_item_len(ih) - deh_location(deh);
+}
+
+/* number of entries in the directory item, depends on ENTRY_COUNT being at the start of directory dynamic data. */
+#define I_ENTRY_COUNT(ih) (ih_entry_count((ih)))
+
+/* name by bh, ih and entry_num */
+#define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih_location(ih) + deh_location(B_I_DEH(bh,ih)+(entry_num))))
+
+// two entries per block (at least)
+#define REISERFS_MAX_NAME(block_size) 255
+
+/* this structure is used for operations on directory entries. It is
+   not a disk structure. */
+/* When reiserfs_find_entry or search_by_entry_key find directory
+   entry, they return filled reiserfs_dir_entry structure */
+struct reiserfs_dir_entry {
+	struct buffer_head *de_bh;
+	int de_item_num;
+	struct item_head *de_ih;
+	int de_entry_num;
+	struct reiserfs_de_head *de_deh;
+	int de_entrylen;
+	int de_namelen;
+	char *de_name;
+	unsigned long *de_gen_number_bit_string;
+
+	__u32 de_dir_id;
+	__u32 de_objectid;
+
+	struct cpu_key de_entry_key;
+};
+
+/* these defines are useful when a particular member of a reiserfs_dir_entry is needed */
+
+/* pointer to file name, stored in entry */
+#define B_I_DEH_ENTRY_FILE_NAME(bh,ih,deh) (B_I_PITEM (bh, ih) + deh_location(deh))
+
+/* length of name */
+#define I_DEH_N_ENTRY_FILE_NAME_LENGTH(ih,deh,entry_num) \
+(I_DEH_N_ENTRY_LENGTH (ih, deh, entry_num) - (de_with_sd (deh) ? SD_SIZE : 0))
+
+/* hash value occupies bits from 7 up to 30 */
+#define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80LL)
+/* generation number occupies 7 bits starting from 0 up to 6 */
+#define GET_GENERATION_NUMBER(offset) ((offset) & 0x7fLL)
+#define MAX_GENERATION_NUMBER  127
+
+#define SET_GENERATION_NUMBER(offset,gen_number) (GET_HASH_VALUE(offset)|(gen_number))
+
+/*
+ * Picture represents an internal node of the reiserfs tree
+ *  ______________________________________________________
+ * |      |  Array of     |  Array of         |  Free     |
+ * |block |    keys       |  pointers         | space     |
+ * | head |      N        |      N+1          |           |
+ * |______|_______________|___________________|___________|
+ */
+
+/***************************************************************************/
+/*                      DISK CHILD                                         */
+/***************************************************************************/
+/* Disk child pointer: The pointer from an internal node of the tree
+   to a node that is on disk. */
+struct disk_child {
+	__le32 dc_block_number;	/* Disk child's block number. */
+	__le16 dc_size;		/* Disk child's used space.   */
+	__le16 dc_reserved;
+};
+
+#define DC_SIZE (sizeof(struct disk_child))
+#define dc_block_number(dc_p)	(le32_to_cpu((dc_p)->dc_block_number))
+#define dc_size(dc_p)		(le16_to_cpu((dc_p)->dc_size))
+#define put_dc_block_number(dc_p, val)   do { (dc_p)->dc_block_number = cpu_to_le32(val); } while(0)
+#define put_dc_size(dc_p, val)   do { (dc_p)->dc_size = cpu_to_le16(val); } while(0)
+
+/* Get disk child by buffer header and position in the tree node. */
+#define B_N_CHILD(bh, n_pos)  ((struct disk_child *)\
+((bh)->b_data + BLKH_SIZE + B_NR_ITEMS(bh) * KEY_SIZE + DC_SIZE * (n_pos)))
+
+/* Get disk child number by buffer header and position in the tree node. */
+#define B_N_CHILD_NUM(bh, n_pos) (dc_block_number(B_N_CHILD(bh, n_pos)))
+#define PUT_B_N_CHILD_NUM(bh, n_pos, val) \
+				(put_dc_block_number(B_N_CHILD(bh, n_pos), val))
+
+ /* maximal value of field child_size in structure disk_child */
+ /* child size is the combined size of all items and their headers */
+#define MAX_CHILD_SIZE(bh) ((int)( (bh)->b_size - BLKH_SIZE ))
+
+/* amount of used space in buffer (not including block head) */
+#define B_CHILD_SIZE(cur) (MAX_CHILD_SIZE(cur)-(B_FREE_SPACE(cur)))
+
+/* max and min number of keys in internal node */
+#define MAX_NR_KEY(bh) ( (MAX_CHILD_SIZE(bh)-DC_SIZE)/(KEY_SIZE+DC_SIZE) )
+#define MIN_NR_KEY(bh)    (MAX_NR_KEY(bh)/2)
+
+/***************************************************************************/
+/*                      PATH STRUCTURES AND DEFINES                        */
+/***************************************************************************/
+
+/* Search_by_key fills up the path from the root to the leaf as it descends the tree looking for the
+   key.  It uses reiserfs_bread to try to find buffers in the cache given their block number.  If it
+   does not find them in the cache it reads them from disk.  For each node search_by_key finds using
+   reiserfs_bread it then uses bin_search to look through that node.  bin_search will find the
+   position of the block_number of the next node if it is looking through an internal node.  If it
+   is looking through a leaf node bin_search will find the position of the item which has key either
+   equal to given key, or which is the maximal key less than the given key. */
+
+struct path_element {
+	struct buffer_head *pe_buffer;	/* Pointer to the buffer at the path in the tree. */
+	int pe_position;	/* Position in the tree node which is placed in the */
+	/* buffer above.                                  */
+};
+
+#define MAX_HEIGHT 5		/* maximal height of a tree. don't change this without changing JOURNAL_PER_BALANCE_CNT */
+#define EXTENDED_MAX_HEIGHT         7	/* Must be equals MAX_HEIGHT + FIRST_PATH_ELEMENT_OFFSET */
+#define FIRST_PATH_ELEMENT_OFFSET   2	/* Must be equal to at least 2. */
+
+#define ILLEGAL_PATH_ELEMENT_OFFSET 1	/* Must be equal to FIRST_PATH_ELEMENT_OFFSET - 1 */
+#define MAX_FEB_SIZE 6		/* this MUST be MAX_HEIGHT + 1. See about FEB below */
+
+/* We need to keep track of who the ancestors of nodes are.  When we
+   perform a search we record which nodes were visited while
+   descending the tree looking for the node we searched for. This list
+   of nodes is called the path.  This information is used while
+   performing balancing.  Note that this path information may become
+   invalid, and this means we must check it when using it to see if it
+   is still valid. You'll need to read search_by_key and the comments
+   in it, especially about decrement_counters_in_path(), to understand
+   this structure.  
+
+Paths make the code so much harder to work with and debug.... An
+enormous number of bugs are due to them, and trying to write or modify
+code that uses them just makes my head hurt.  They are based on an
+excessive effort to avoid disturbing the precious VFS code.:-( The
+gods only know how we are going to SMP the code that uses them.
+znodes are the way! */
+
+#define PATH_READA	0x1	/* do read ahead */
+#define PATH_READA_BACK 0x2	/* read backwards */
+
+struct treepath {
+	int path_length;	/* Length of the array above.   */
+	int reada;
+	struct path_element path_elements[EXTENDED_MAX_HEIGHT];	/* Array of the path elements.  */
+	int pos_in_item;
+};
+
+#define pos_in_item(path) ((path)->pos_in_item)
+
+#define INITIALIZE_PATH(var) \
+struct treepath var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
+
+/* Get path element by path and path position. */
+#define PATH_OFFSET_PELEMENT(path, n_offset)  ((path)->path_elements + (n_offset))
+
+/* Get buffer header at the path by path and path position. */
+#define PATH_OFFSET_PBUFFER(path, n_offset)   (PATH_OFFSET_PELEMENT(path, n_offset)->pe_buffer)
+
+/* Get position in the element at the path by path and path position. */
+#define PATH_OFFSET_POSITION(path, n_offset) (PATH_OFFSET_PELEMENT(path, n_offset)->pe_position)
+
+#define PATH_PLAST_BUFFER(path) (PATH_OFFSET_PBUFFER((path), (path)->path_length))
+				/* you know, to the person who didn't
+				   write this the macro name does not
+				   at first suggest what it does.
+				   Maybe POSITION_FROM_PATH_END? Or
+				   maybe we should just focus on
+				   dumping paths... -Hans */
+#define PATH_LAST_POSITION(path) (PATH_OFFSET_POSITION((path), (path)->path_length))
+
+#define PATH_PITEM_HEAD(path)    B_N_PITEM_HEAD(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION(path))
+
+/* in do_balance leaf has h == 0 in contrast with path structure,
+   where root has level == 0. That is why we need these defines */
+#define PATH_H_PBUFFER(path, h) PATH_OFFSET_PBUFFER (path, path->path_length - (h))	/* tb->S[h] */
+#define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1)	/* tb->F[h] or tb->S[0]->b_parent */
+#define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h))
+#define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1)	/* tb->S[h]->b_item_order */
+
+#define PATH_H_PATH_OFFSET(path, n_h) ((path)->path_length - (n_h))
+
+#define get_last_bh(path) PATH_PLAST_BUFFER(path)
+#define get_ih(path) PATH_PITEM_HEAD(path)
+#define get_item_pos(path) PATH_LAST_POSITION(path)
+#define get_item(path) ((void *)B_N_PITEM(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION (path)))
+#define item_moved(ih,path) comp_items(ih, path)
+#define path_changed(ih,path) comp_items (ih, path)
+
+/***************************************************************************/
+/*                       MISC                                              */
+/***************************************************************************/
+
+/* Size of pointer to the unformatted node. */
+#define UNFM_P_SIZE (sizeof(unp_t))
+#define UNFM_P_SHIFT 2
+
+// in in-core inode key is stored on le form
+#define INODE_PKEY(inode) ((struct reiserfs_key *)(REISERFS_I(inode)->i_key))
+
+#define MAX_UL_INT 0xffffffff
+#define MAX_INT    0x7ffffff
+#define MAX_US_INT 0xffff
+
+// reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
+#define U32_MAX (~(__u32)0)
+
+static inline loff_t max_reiserfs_offset(struct inode *inode)
+{
+	if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5)
+		return (loff_t) U32_MAX;
+
+	return (loff_t) ((~(__u64) 0) >> 4);
+}
+
+/*#define MAX_KEY_UNIQUENESS	MAX_UL_INT*/
+#define MAX_KEY_OBJECTID	MAX_UL_INT
+
+#define MAX_B_NUM  MAX_UL_INT
+#define MAX_FC_NUM MAX_US_INT
+
+/* the purpose is to detect overflow of an unsigned short */
+#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
+
+/* The following defines are used in reiserfs_insert_item and reiserfs_append_item  */
+#define REISERFS_KERNEL_MEM		0	/* reiserfs kernel memory mode  */
+#define REISERFS_USER_MEM		1	/* reiserfs user memory mode            */
+
+#define fs_generation(s) (REISERFS_SB(s)->s_generation_counter)
+#define get_generation(s) atomic_read (&fs_generation(s))
+#define FILESYSTEM_CHANGED_TB(tb)  (get_generation((tb)->tb_sb) != (tb)->fs_gen)
+#define __fs_changed(gen,s) (gen != get_generation (s))
+#define fs_changed(gen,s)		\
+({					\
+	reiserfs_cond_resched(s);	\
+	__fs_changed(gen, s);		\
+})
+
+/***************************************************************************/
+/*                  FIXATE NODES                                           */
+/***************************************************************************/
+
+#define VI_TYPE_LEFT_MERGEABLE 1
+#define VI_TYPE_RIGHT_MERGEABLE 2
+
+/* To make any changes in the tree we always first find node, that
+   contains item to be changed/deleted or place to insert a new
+   item. We call this node S. To do balancing we need to decide what
+   we will shift to left/right neighbor, or to a new node, where new
+   item will be etc. To make this analysis simpler we build virtual
+   node. Virtual node is an array of items, that will replace items of
+   node S. (For instance if we are going to delete an item, virtual
+   node does not contain it). Virtual node keeps information about
+   item sizes and types, mergeability of first and last items, sizes
+   of all entries in directory item. We use this array of items when
+   calculating what we can shift to neighbors and how many nodes we
+   have to have if we do not any shiftings, if we shift to left/right
+   neighbor or to both. */
+struct virtual_item {
+	int vi_index;		// index in the array of item operations
+	unsigned short vi_type;	// left/right mergeability
+	unsigned short vi_item_len;	/* length of item that it will have after balancing */
+	struct item_head *vi_ih;
+	const char *vi_item;	// body of item (old or new)
+	const void *vi_new_data;	// 0 always but paste mode
+	void *vi_uarea;		// item specific area
+};
+
+struct virtual_node {
+	char *vn_free_ptr;	/* this is a pointer to the free space in the buffer */
+	unsigned short vn_nr_item;	/* number of items in virtual node */
+	short vn_size;		/* size of node , that node would have if it has unlimited size and no balancing is performed */
+	short vn_mode;		/* mode of balancing (paste, insert, delete, cut) */
+	short vn_affected_item_num;
+	short vn_pos_in_item;
+	struct item_head *vn_ins_ih;	/* item header of inserted item, 0 for other modes */
+	const void *vn_data;
+	struct virtual_item *vn_vi;	/* array of items (including a new one, excluding item to be deleted) */
+};
+
+/* used by directory items when creating virtual nodes */
+struct direntry_uarea {
+	int flags;
+	__u16 entry_count;
+	__u16 entry_sizes[1];
+} __attribute__ ((__packed__));
+
+/***************************************************************************/
+/*                  TREE BALANCE                                           */
+/***************************************************************************/
+
+/* This temporary structure is used in tree balance algorithms, and
+   constructed as we go to the extent that its various parts are
+   needed.  It contains arrays of nodes that can potentially be
+   involved in the balancing of node S, and parameters that define how
+   each of the nodes must be balanced.  Note that in these algorithms
+   for balancing the worst case is to need to balance the current node
+   S and the left and right neighbors and all of their parents plus
+   create a new node.  We implement S1 balancing for the leaf nodes
+   and S0 balancing for the internal nodes (S1 and S0 are defined in
+   our papers.)*/
+
+#define MAX_FREE_BLOCK 7	/* size of the array of buffers to free at end of do_balance */
+
+/* maximum number of FEB blocknrs on a single level */
+#define MAX_AMOUNT_NEEDED 2
+
+/* someday somebody will prefix every field in this struct with tb_ */
+struct tree_balance {
+	int tb_mode;
+	int need_balance_dirty;
+	struct super_block *tb_sb;
+	struct reiserfs_transaction_handle *transaction_handle;
+	struct treepath *tb_path;
+	struct buffer_head *L[MAX_HEIGHT];	/* array of left neighbors of nodes in the path */
+	struct buffer_head *R[MAX_HEIGHT];	/* array of right neighbors of nodes in the path */
+	struct buffer_head *FL[MAX_HEIGHT];	/* array of fathers of the left  neighbors      */
+	struct buffer_head *FR[MAX_HEIGHT];	/* array of fathers of the right neighbors      */
+	struct buffer_head *CFL[MAX_HEIGHT];	/* array of common parents of center node and its left neighbor  */
+	struct buffer_head *CFR[MAX_HEIGHT];	/* array of common parents of center node and its right neighbor */
+
+	struct buffer_head *FEB[MAX_FEB_SIZE];	/* array of empty buffers. Number of buffers in array equals
+						   cur_blknum. */
+	struct buffer_head *used[MAX_FEB_SIZE];
+	struct buffer_head *thrown[MAX_FEB_SIZE];
+	int lnum[MAX_HEIGHT];	/* array of number of items which must be
+				   shifted to the left in order to balance the
+				   current node; for leaves includes item that
+				   will be partially shifted; for internal
+				   nodes, it is the number of child pointers
+				   rather than items. It includes the new item
+				   being created. The code sometimes subtracts
+				   one to get the number of wholly shifted
+				   items for other purposes. */
+	int rnum[MAX_HEIGHT];	/* substitute right for left in comment above */
+	int lkey[MAX_HEIGHT];	/* array indexed by height h mapping the key delimiting L[h] and
+				   S[h] to its item number within the node CFL[h] */
+	int rkey[MAX_HEIGHT];	/* substitute r for l in comment above */
+	int insert_size[MAX_HEIGHT];	/* the number of bytes by we are trying to add or remove from
+					   S[h]. A negative value means removing.  */
+	int blknum[MAX_HEIGHT];	/* number of nodes that will replace node S[h] after
+				   balancing on the level h of the tree.  If 0 then S is
+				   being deleted, if 1 then S is remaining and no new nodes
+				   are being created, if 2 or 3 then 1 or 2 new nodes is
+				   being created */
+
+	/* fields that are used only for balancing leaves of the tree */
+	int cur_blknum;		/* number of empty blocks having been already allocated                 */
+	int s0num;		/* number of items that fall into left most  node when S[0] splits     */
+	int s1num;		/* number of items that fall into first  new node when S[0] splits     */
+	int s2num;		/* number of items that fall into second new node when S[0] splits     */
+	int lbytes;		/* number of bytes which can flow to the left neighbor from the        left    */
+	/* most liquid item that cannot be shifted from S[0] entirely         */
+	/* if -1 then nothing will be partially shifted */
+	int rbytes;		/* number of bytes which will flow to the right neighbor from the right        */
+	/* most liquid item that cannot be shifted from S[0] entirely         */
+	/* if -1 then nothing will be partially shifted                           */
+	int s1bytes;		/* number of bytes which flow to the first  new node when S[0] splits   */
+	/* note: if S[0] splits into 3 nodes, then items do not need to be cut  */
+	int s2bytes;
+	struct buffer_head *buf_to_free[MAX_FREE_BLOCK];	/* buffers which are to be freed after do_balance finishes by unfix_nodes */
+	char *vn_buf;		/* kmalloced memory. Used to create
+				   virtual node and keep map of
+				   dirtied bitmap blocks */
+	int vn_buf_size;	/* size of the vn_buf */
+	struct virtual_node *tb_vn;	/* VN starts after bitmap of bitmap blocks */
+
+	int fs_gen;		/* saved value of `reiserfs_generation' counter
+				   see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+	struct in_core_key key;	/* key pointer, to pass to block allocator or
+				   another low-level subsystem */
+#endif
+};
+
+/* These are modes of balancing */
+
+/* When inserting an item. */
+#define M_INSERT	'i'
+/* When inserting into (directories only) or appending onto an already
+   existent item. */
+#define M_PASTE		'p'
+/* When deleting an item. */
+#define M_DELETE	'd'
+/* When truncating an item or removing an entry from a (directory) item. */
+#define M_CUT 		'c'
+
+/* used when balancing on leaf level skipped (in reiserfsck) */
+#define M_INTERNAL	'n'
+
+/* When further balancing is not needed, then do_balance does not need
+   to be called. */
+#define M_SKIP_BALANCING 		's'
+#define M_CONVERT	'v'
+
+/* modes of leaf_move_items */
+#define LEAF_FROM_S_TO_L 0
+#define LEAF_FROM_S_TO_R 1
+#define LEAF_FROM_R_TO_L 2
+#define LEAF_FROM_L_TO_R 3
+#define LEAF_FROM_S_TO_SNEW 4
+
+#define FIRST_TO_LAST 0
+#define LAST_TO_FIRST 1
+
+/* used in do_balance for passing parent of node information that has
+   been gotten from tb struct */
+struct buffer_info {
+	struct tree_balance *tb;
+	struct buffer_head *bi_bh;
+	struct buffer_head *bi_parent;
+	int bi_position;
+};
+
+static inline struct super_block *sb_from_tb(struct tree_balance *tb)
+{
+	return tb ? tb->tb_sb : NULL;
+}
+
+static inline struct super_block *sb_from_bi(struct buffer_info *bi)
+{
+	return bi ? sb_from_tb(bi->tb) : NULL;
+}
+
+/* there are 4 types of items: stat data, directory item, indirect, direct.
++-------------------+------------+--------------+------------+
+|	            |  k_offset  | k_uniqueness | mergeable? |
++-------------------+------------+--------------+------------+
+|     stat data     |	0        |      0       |   no       |
++-------------------+------------+--------------+------------+
+| 1st directory item| DOT_OFFSET |DIRENTRY_UNIQUENESS|   no       | 
+| non 1st directory | hash value |              |   yes      |
+|     item          |            |              |            |
++-------------------+------------+--------------+------------+
+| indirect item     | offset + 1 |TYPE_INDIRECT |   if this is not the first indirect item of the object
++-------------------+------------+--------------+------------+
+| direct item       | offset + 1 |TYPE_DIRECT   | if not this is not the first direct item of the object
++-------------------+------------+--------------+------------+
+*/
+
+struct item_operations {
+	int (*bytes_number) (struct item_head * ih, int block_size);
+	void (*decrement_key) (struct cpu_key *);
+	int (*is_left_mergeable) (struct reiserfs_key * ih,
+				  unsigned long bsize);
+	void (*print_item) (struct item_head *, char *item);
+	void (*check_item) (struct item_head *, char *item);
+
+	int (*create_vi) (struct virtual_node * vn, struct virtual_item * vi,
+			  int is_affected, int insert_size);
+	int (*check_left) (struct virtual_item * vi, int free,
+			   int start_skip, int end_skip);
+	int (*check_right) (struct virtual_item * vi, int free);
+	int (*part_size) (struct virtual_item * vi, int from, int to);
+	int (*unit_num) (struct virtual_item * vi);
+	void (*print_vi) (struct virtual_item * vi);
+};
+
+extern struct item_operations *item_ops[TYPE_ANY + 1];
+
+#define op_bytes_number(ih,bsize)                    item_ops[le_ih_k_type (ih)]->bytes_number (ih, bsize)
+#define op_is_left_mergeable(key,bsize)              item_ops[le_key_k_type (le_key_version (key), key)]->is_left_mergeable (key, bsize)
+#define op_print_item(ih,item)                       item_ops[le_ih_k_type (ih)]->print_item (ih, item)
+#define op_check_item(ih,item)                       item_ops[le_ih_k_type (ih)]->check_item (ih, item)
+#define op_create_vi(vn,vi,is_affected,insert_size)  item_ops[le_ih_k_type ((vi)->vi_ih)]->create_vi (vn,vi,is_affected,insert_size)
+#define op_check_left(vi,free,start_skip,end_skip) item_ops[(vi)->vi_index]->check_left (vi, free, start_skip, end_skip)
+#define op_check_right(vi,free)                      item_ops[(vi)->vi_index]->check_right (vi, free)
+#define op_part_size(vi,from,to)                     item_ops[(vi)->vi_index]->part_size (vi, from, to)
+#define op_unit_num(vi)				     item_ops[(vi)->vi_index]->unit_num (vi)
+#define op_print_vi(vi)                              item_ops[(vi)->vi_index]->print_vi (vi)
+
+#define COMP_SHORT_KEYS comp_short_keys
+
+/* number of blocks pointed to by the indirect item */
+#define I_UNFM_NUM(ih)	(ih_item_len(ih) / UNFM_P_SIZE)
+
+/* the used space within the unformatted node corresponding to pos within the item pointed to by ih */
+#define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - ih_free_space(ih) : (size))
+
+/* number of bytes contained by the direct item or the unformatted nodes the indirect item points to */
+
+/* get the item header */
+#define B_N_PITEM_HEAD(bh,item_num) ( (struct item_head * )((bh)->b_data + BLKH_SIZE) + (item_num) )
+
+/* get key */
+#define B_N_PDELIM_KEY(bh,item_num) ( (struct reiserfs_key * )((bh)->b_data + BLKH_SIZE) + (item_num) )
+
+/* get the key */
+#define B_N_PKEY(bh,item_num) ( &(B_N_PITEM_HEAD(bh,item_num)->ih_key) )
+
+/* get item body */
+#define B_N_PITEM(bh,item_num) ( (bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(item_num))))
+
+/* get the stat data by the buffer header and the item order */
+#define B_N_STAT_DATA(bh,nr) \
+( (struct stat_data *)((bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(nr))) ) )
+
+    /* following defines use reiserfs buffer header and item header */
+
+/* get stat-data */
+#define B_I_STAT_DATA(bh, ih) ( (struct stat_data * )((bh)->b_data + ih_location(ih)) )
+
+// this is 3976 for size==4096
+#define MAX_DIRECT_ITEM_LEN(size) ((size) - BLKH_SIZE - 2*IH_SIZE - SD_SIZE - UNFM_P_SIZE)
+
+/* indirect items consist of entries which contain blocknrs, pos
+   indicates which entry, and B_I_POS_UNFM_POINTER resolves to the
+   blocknr contained by the entry pos points to */
+#define B_I_POS_UNFM_POINTER(bh,ih,pos) le32_to_cpu(*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)))
+#define PUT_B_I_POS_UNFM_POINTER(bh,ih,pos, val) do {*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)) = cpu_to_le32(val); } while (0)
+
+struct reiserfs_iget_args {
+	__u32 objectid;
+	__u32 dirid;
+};
+
+/***************************************************************************/
+/*                    FUNCTION DECLARATIONS                                */
+/***************************************************************************/
+
+#define get_journal_desc_magic(bh) (bh->b_data + bh->b_size - 12)
+
+#define journal_trans_half(blocksize) \
+	((blocksize - sizeof (struct reiserfs_journal_desc) + sizeof (__u32) - 12) / sizeof (__u32))
+
+/* journal.c see journal.c for all the comments here */
+
+/* first block written in a commit.  */
+struct reiserfs_journal_desc {
+	__le32 j_trans_id;	/* id of commit */
+	__le32 j_len;		/* length of commit. len +1 is the commit block */
+	__le32 j_mount_id;	/* mount id of this trans */
+	__le32 j_realblock[1];	/* real locations for each block */
+};
+
+#define get_desc_trans_id(d)   le32_to_cpu((d)->j_trans_id)
+#define get_desc_trans_len(d)  le32_to_cpu((d)->j_len)
+#define get_desc_mount_id(d)   le32_to_cpu((d)->j_mount_id)
+
+#define set_desc_trans_id(d,val)       do { (d)->j_trans_id = cpu_to_le32 (val); } while (0)
+#define set_desc_trans_len(d,val)      do { (d)->j_len = cpu_to_le32 (val); } while (0)
+#define set_desc_mount_id(d,val)       do { (d)->j_mount_id = cpu_to_le32 (val); } while (0)
+
+/* last block written in a commit */
+struct reiserfs_journal_commit {
+	__le32 j_trans_id;	/* must match j_trans_id from the desc block */
+	__le32 j_len;		/* ditto */
+	__le32 j_realblock[1];	/* real locations for each block */
+};
+
+#define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id)
+#define get_commit_trans_len(c)        le32_to_cpu((c)->j_len)
+#define get_commit_mount_id(c) le32_to_cpu((c)->j_mount_id)
+
+#define set_commit_trans_id(c,val)     do { (c)->j_trans_id = cpu_to_le32 (val); } while (0)
+#define set_commit_trans_len(c,val)    do { (c)->j_len = cpu_to_le32 (val); } while (0)
+
+/* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the
+** last fully flushed transaction.  fully flushed means all the log blocks and all the real blocks are on disk,
+** and this transaction does not need to be replayed.
+*/
+struct reiserfs_journal_header {
+	__le32 j_last_flush_trans_id;	/* id of last fully flushed transaction */
+	__le32 j_first_unflushed_offset;	/* offset in the log of where to start replay after a crash */
+	__le32 j_mount_id;
+	/* 12 */ struct journal_params jh_journal;
+};
+
+/* biggest tunable defines are right here */
+#define JOURNAL_BLOCK_COUNT 8192	/* number of blocks in the journal */
+#define JOURNAL_TRANS_MAX_DEFAULT 1024	/* biggest possible single transaction, don't change for now (8/3/99) */
+#define JOURNAL_TRANS_MIN_DEFAULT 256
+#define JOURNAL_MAX_BATCH_DEFAULT   900	/* max blocks to batch into one transaction, don't make this any bigger than 900 */
+#define JOURNAL_MIN_RATIO 2
+#define JOURNAL_MAX_COMMIT_AGE 30
+#define JOURNAL_MAX_TRANS_AGE 30
+#define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9)
+#define JOURNAL_BLOCKS_PER_OBJECT(sb)  (JOURNAL_PER_BALANCE_CNT * 3 + \
+					 2 * (REISERFS_QUOTA_INIT_BLOCKS(sb) + \
+					      REISERFS_QUOTA_TRANS_BLOCKS(sb)))
+
+#ifdef CONFIG_QUOTA
+#define REISERFS_QUOTA_OPTS ((1 << REISERFS_USRQUOTA) | (1 << REISERFS_GRPQUOTA))
+/* We need to update data and inode (atime) */
+#define REISERFS_QUOTA_TRANS_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? 2 : 0)
+/* 1 balancing, 1 bitmap, 1 data per write + stat data update */
+#define REISERFS_QUOTA_INIT_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? \
+(DQUOT_INIT_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_INIT_REWRITE+1) : 0)
+/* same as with INIT */
+#define REISERFS_QUOTA_DEL_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? \
+(DQUOT_DEL_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_DEL_REWRITE+1) : 0)
+#else
+#define REISERFS_QUOTA_TRANS_BLOCKS(s) 0
+#define REISERFS_QUOTA_INIT_BLOCKS(s) 0
+#define REISERFS_QUOTA_DEL_BLOCKS(s) 0
+#endif
+
+/* both of these can be as low as 1, or as high as you want.  The min is the
+** number of 4k bitmap nodes preallocated on mount. New nodes are allocated
+** as needed, and released when transactions are committed.  On release, if 
+** the current number of nodes is > max, the node is freed, otherwise, 
+** it is put on a free list for faster use later.
+*/
+#define REISERFS_MIN_BITMAP_NODES 10
+#define REISERFS_MAX_BITMAP_NODES 100
+
+#define JBH_HASH_SHIFT 13	/* these are based on journal hash size of 8192 */
+#define JBH_HASH_MASK 8191
+
+#define _jhashfn(sb,block)	\
+	(((unsigned long)sb>>L1_CACHE_SHIFT) ^ \
+	 (((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12))))
+#define journal_hash(t,sb,block) ((t)[_jhashfn((sb),(block)) & JBH_HASH_MASK])
+
+// We need these to make journal.c code more readable
+#define journal_find_get_block(s, block) __find_get_block(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
+#define journal_getblk(s, block) __getblk(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
+#define journal_bread(s, block) __bread(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
+
+enum reiserfs_bh_state_bits {
+	BH_JDirty = BH_PrivateStart,	/* buffer is in current transaction */
+	BH_JDirty_wait,
+	BH_JNew,		/* disk block was taken off free list before
+				 * being in a finished transaction, or
+				 * written to disk. Can be reused immed. */
+	BH_JPrepared,
+	BH_JRestore_dirty,
+	BH_JTest,		// debugging only will go away
+};
+
+BUFFER_FNS(JDirty, journaled);
+TAS_BUFFER_FNS(JDirty, journaled);
+BUFFER_FNS(JDirty_wait, journal_dirty);
+TAS_BUFFER_FNS(JDirty_wait, journal_dirty);
+BUFFER_FNS(JNew, journal_new);
+TAS_BUFFER_FNS(JNew, journal_new);
+BUFFER_FNS(JPrepared, journal_prepared);
+TAS_BUFFER_FNS(JPrepared, journal_prepared);
+BUFFER_FNS(JRestore_dirty, journal_restore_dirty);
+TAS_BUFFER_FNS(JRestore_dirty, journal_restore_dirty);
+BUFFER_FNS(JTest, journal_test);
+TAS_BUFFER_FNS(JTest, journal_test);
+
+/*
+** transaction handle which is passed around for all journal calls
+*/
+struct reiserfs_transaction_handle {
+	struct super_block *t_super;	/* super for this FS when journal_begin was
+					   called. saves calls to reiserfs_get_super
+					   also used by nested transactions to make
+					   sure they are nesting on the right FS
+					   _must_ be first in the handle
+					 */
+	int t_refcount;
+	int t_blocks_logged;	/* number of blocks this writer has logged */
+	int t_blocks_allocated;	/* number of blocks this writer allocated */
+	unsigned int t_trans_id;	/* sanity check, equals the current trans id */
+	void *t_handle_save;	/* save existing current->journal_info */
+	unsigned displace_new_blocks:1;	/* if new block allocation occurres, that block
+					   should be displaced from others */
+	struct list_head t_list;
+};
+
+/* used to keep track of ordered and tail writes, attached to the buffer
+ * head through b_journal_head.
+ */
+struct reiserfs_jh {
+	struct reiserfs_journal_list *jl;
+	struct buffer_head *bh;
+	struct list_head list;
+};
+
+void reiserfs_free_jh(struct buffer_head *bh);
+int reiserfs_add_tail_list(struct inode *inode, struct buffer_head *bh);
+int reiserfs_add_ordered_list(struct inode *inode, struct buffer_head *bh);
+int journal_mark_dirty(struct reiserfs_transaction_handle *,
+		       struct super_block *, struct buffer_head *bh);
+
+static inline int reiserfs_file_data_log(struct inode *inode)
+{
+	if (reiserfs_data_log(inode->i_sb) ||
+	    (REISERFS_I(inode)->i_flags & i_data_log))
+		return 1;
+	return 0;
+}
+
+static inline int reiserfs_transaction_running(struct super_block *s)
+{
+	struct reiserfs_transaction_handle *th = current->journal_info;
+	if (th && th->t_super == s)
+		return 1;
+	if (th && th->t_super == NULL)
+		BUG();
+	return 0;
+}
+
+static inline int reiserfs_transaction_free_space(struct reiserfs_transaction_handle *th)
+{
+	return th->t_blocks_allocated - th->t_blocks_logged;
+}
+
+struct reiserfs_transaction_handle *reiserfs_persistent_transaction(struct
+								    super_block
+								    *,
+								    int count);
+int reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *);
+int reiserfs_commit_page(struct inode *inode, struct page *page,
+			 unsigned from, unsigned to);
+int reiserfs_flush_old_commits(struct super_block *);
+int reiserfs_commit_for_inode(struct inode *);
+int reiserfs_inode_needs_commit(struct inode *);
+void reiserfs_update_inode_transaction(struct inode *);
+void reiserfs_wait_on_write_block(struct super_block *s);
+void reiserfs_block_writes(struct reiserfs_transaction_handle *th);
+void reiserfs_allow_writes(struct super_block *s);
+void reiserfs_check_lock_depth(struct super_block *s, char *caller);
+int reiserfs_prepare_for_journal(struct super_block *, struct buffer_head *bh,
+				 int wait);
+void reiserfs_restore_prepared_buffer(struct super_block *,
+				      struct buffer_head *bh);
+int journal_init(struct super_block *, const char *j_dev_name, int old_format,
+		 unsigned int);
+int journal_release(struct reiserfs_transaction_handle *, struct super_block *);
+int journal_release_error(struct reiserfs_transaction_handle *,
+			  struct super_block *);
+int journal_end(struct reiserfs_transaction_handle *, struct super_block *,
+		unsigned long);
+int journal_end_sync(struct reiserfs_transaction_handle *, struct super_block *,
+		     unsigned long);
+int journal_mark_freed(struct reiserfs_transaction_handle *,
+		       struct super_block *, b_blocknr_t blocknr);
+int journal_transaction_should_end(struct reiserfs_transaction_handle *, int);
+int reiserfs_in_journal(struct super_block *sb, unsigned int bmap_nr,
+			 int bit_nr, int searchall, b_blocknr_t *next);
+int journal_begin(struct reiserfs_transaction_handle *,
+		  struct super_block *sb, unsigned long);
+int journal_join_abort(struct reiserfs_transaction_handle *,
+		       struct super_block *sb, unsigned long);
+void reiserfs_abort_journal(struct super_block *sb, int errno);
+void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...);
+int reiserfs_allocate_list_bitmaps(struct super_block *s,
+				   struct reiserfs_list_bitmap *, unsigned int);
+
+void add_save_link(struct reiserfs_transaction_handle *th,
+		   struct inode *inode, int truncate);
+int remove_save_link(struct inode *inode, int truncate);
+
+/* objectid.c */
+__u32 reiserfs_get_unused_objectid(struct reiserfs_transaction_handle *th);
+void reiserfs_release_objectid(struct reiserfs_transaction_handle *th,
+			       __u32 objectid_to_release);
+int reiserfs_convert_objectid_map_v1(struct super_block *);
+
+/* stree.c */
+int B_IS_IN_TREE(const struct buffer_head *);
+extern void copy_item_head(struct item_head *to,
+			   const struct item_head *from);
+
+// first key is in cpu form, second - le
+extern int comp_short_keys(const struct reiserfs_key *le_key,
+			   const struct cpu_key *cpu_key);
+extern void le_key2cpu_key(struct cpu_key *to, const struct reiserfs_key *from);
+
+// both are in le form
+extern int comp_le_keys(const struct reiserfs_key *,
+			const struct reiserfs_key *);
+extern int comp_short_le_keys(const struct reiserfs_key *,
+			      const struct reiserfs_key *);
+
+//
+// get key version from on disk key - kludge
+//
+static inline int le_key_version(const struct reiserfs_key *key)
+{
+	int type;
+
+	type = offset_v2_k_type(&(key->u.k_offset_v2));
+	if (type != TYPE_DIRECT && type != TYPE_INDIRECT
+	    && type != TYPE_DIRENTRY)
+		return KEY_FORMAT_3_5;
+
+	return KEY_FORMAT_3_6;
+
+}
+
+static inline void copy_key(struct reiserfs_key *to,
+			    const struct reiserfs_key *from)
+{
+	memcpy(to, from, KEY_SIZE);
+}
+
+int comp_items(const struct item_head *stored_ih, const struct treepath *path);
+const struct reiserfs_key *get_rkey(const struct treepath *chk_path,
+				    const struct super_block *sb);
+int search_by_key(struct super_block *, const struct cpu_key *,
+		  struct treepath *, int);
+#define search_item(s,key,path) search_by_key (s, key, path, DISK_LEAF_NODE_LEVEL)
+int search_for_position_by_key(struct super_block *sb,
+			       const struct cpu_key *cpu_key,
+			       struct treepath *search_path);
+extern void decrement_bcount(struct buffer_head *bh);
+void decrement_counters_in_path(struct treepath *search_path);
+void pathrelse(struct treepath *search_path);
+int reiserfs_check_path(struct treepath *p);
+void pathrelse_and_restore(struct super_block *s, struct treepath *search_path);
+
+int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
+			 struct treepath *path,
+			 const struct cpu_key *key,
+			 struct item_head *ih,
+			 struct inode *inode, const char *body);
+
+int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th,
+			     struct treepath *path,
+			     const struct cpu_key *key,
+			     struct inode *inode,
+			     const char *body, int paste_size);
+
+int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th,
+			   struct treepath *path,
+			   struct cpu_key *key,
+			   struct inode *inode,
+			   struct page *page, loff_t new_file_size);
+
+int reiserfs_delete_item(struct reiserfs_transaction_handle *th,
+			 struct treepath *path,
+			 const struct cpu_key *key,
+			 struct inode *inode, struct buffer_head *un_bh);
+
+void reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th,
+				struct inode *inode, struct reiserfs_key *key);
+int reiserfs_delete_object(struct reiserfs_transaction_handle *th,
+			   struct inode *inode);
+int reiserfs_do_truncate(struct reiserfs_transaction_handle *th,
+			 struct inode *inode, struct page *,
+			 int update_timestamps);
+
+#define i_block_size(inode) ((inode)->i_sb->s_blocksize)
+#define file_size(inode) ((inode)->i_size)
+#define tail_size(inode) (file_size (inode) & (i_block_size (inode) - 1))
+
+#define tail_has_to_be_packed(inode) (have_large_tails ((inode)->i_sb)?\
+!STORE_TAIL_IN_UNFM_S1(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):have_small_tails ((inode)->i_sb)?!STORE_TAIL_IN_UNFM_S2(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):0 )
+
+void padd_item(char *item, int total_length, int length);
+
+/* inode.c */
+/* args for the create parameter of reiserfs_get_block */
+#define GET_BLOCK_NO_CREATE 0	/* don't create new blocks or convert tails */
+#define GET_BLOCK_CREATE 1	/* add anything you need to find block */
+#define GET_BLOCK_NO_HOLE 2	/* return -ENOENT for file holes */
+#define GET_BLOCK_READ_DIRECT 4	/* read the tail if indirect item not found */
+#define GET_BLOCK_NO_IMUX     8	/* i_mutex is not held, don't preallocate */
+#define GET_BLOCK_NO_DANGLE   16	/* don't leave any transactions running */
+
+void reiserfs_read_locked_inode(struct inode *inode,
+				struct reiserfs_iget_args *args);
+int reiserfs_find_actor(struct inode *inode, void *p);
+int reiserfs_init_locked_inode(struct inode *inode, void *p);
+void reiserfs_evict_inode(struct inode *inode);
+int reiserfs_write_inode(struct inode *inode, struct writeback_control *wbc);
+int reiserfs_get_block(struct inode *inode, sector_t block,
+		       struct buffer_head *bh_result, int create);
+struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
+				     int fh_len, int fh_type);
+struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid,
+				     int fh_len, int fh_type);
+int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp,
+		       int connectable);
+
+int reiserfs_truncate_file(struct inode *, int update_timestamps);
+void make_cpu_key(struct cpu_key *cpu_key, struct inode *inode, loff_t offset,
+		  int type, int key_length);
+void make_le_item_head(struct item_head *ih, const struct cpu_key *key,
+		       int version,
+		       loff_t offset, int type, int length, int entry_count);
+struct inode *reiserfs_iget(struct super_block *s, const struct cpu_key *key);
+
+struct reiserfs_security_handle;
+int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
+		       struct inode *dir, umode_t mode,
+		       const char *symname, loff_t i_size,
+		       struct dentry *dentry, struct inode *inode,
+		       struct reiserfs_security_handle *security);
+
+void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th,
+			     struct inode *inode, loff_t size);
+
+static inline void reiserfs_update_sd(struct reiserfs_transaction_handle *th,
+				      struct inode *inode)
+{
+	reiserfs_update_sd_size(th, inode, inode->i_size);
+}
+
+void sd_attrs_to_i_attrs(__u16 sd_attrs, struct inode *inode);
+void i_attrs_to_sd_attrs(struct inode *inode, __u16 * sd_attrs);
+int reiserfs_setattr(struct dentry *dentry, struct iattr *attr);
+
+int __reiserfs_write_begin(struct page *page, unsigned from, unsigned len);
+
+/* namei.c */
+void set_de_name_and_namelen(struct reiserfs_dir_entry *de);
+int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
+			struct treepath *path, struct reiserfs_dir_entry *de);
+struct dentry *reiserfs_get_parent(struct dentry *);
+
+#ifdef CONFIG_REISERFS_PROC_INFO
+int reiserfs_proc_info_init(struct super_block *sb);
+int reiserfs_proc_info_done(struct super_block *sb);
+int reiserfs_proc_info_global_init(void);
+int reiserfs_proc_info_global_done(void);
+
+#define PROC_EXP( e )   e
+
+#define __PINFO( sb ) REISERFS_SB(sb) -> s_proc_info_data
+#define PROC_INFO_MAX( sb, field, value )								\
+    __PINFO( sb ).field =												\
+        max( REISERFS_SB( sb ) -> s_proc_info_data.field, value )
+#define PROC_INFO_INC( sb, field ) ( ++ ( __PINFO( sb ).field ) )
+#define PROC_INFO_ADD( sb, field, val ) ( __PINFO( sb ).field += ( val ) )
+#define PROC_INFO_BH_STAT( sb, bh, level )							\
+    PROC_INFO_INC( sb, sbk_read_at[ ( level ) ] );						\
+    PROC_INFO_ADD( sb, free_at[ ( level ) ], B_FREE_SPACE( bh ) );	\
+    PROC_INFO_ADD( sb, items_at[ ( level ) ], B_NR_ITEMS( bh ) )
+#else
+static inline int reiserfs_proc_info_init(struct super_block *sb)
+{
+	return 0;
+}
+
+static inline int reiserfs_proc_info_done(struct super_block *sb)
+{
+	return 0;
+}
+
+static inline int reiserfs_proc_info_global_init(void)
+{
+	return 0;
+}
+
+static inline int reiserfs_proc_info_global_done(void)
+{
+	return 0;
+}
+
+#define PROC_EXP( e )
+#define VOID_V ( ( void ) 0 )
+#define PROC_INFO_MAX( sb, field, value ) VOID_V
+#define PROC_INFO_INC( sb, field ) VOID_V
+#define PROC_INFO_ADD( sb, field, val ) VOID_V
+#define PROC_INFO_BH_STAT(sb, bh, n_node_level) VOID_V
+#endif
+
+/* dir.c */
+extern const struct inode_operations reiserfs_dir_inode_operations;
+extern const struct inode_operations reiserfs_symlink_inode_operations;
+extern const struct inode_operations reiserfs_special_inode_operations;
+extern const struct file_operations reiserfs_dir_operations;
+int reiserfs_readdir_dentry(struct dentry *, void *, filldir_t, loff_t *);
+
+/* tail_conversion.c */
+int direct2indirect(struct reiserfs_transaction_handle *, struct inode *,
+		    struct treepath *, struct buffer_head *, loff_t);
+int indirect2direct(struct reiserfs_transaction_handle *, struct inode *,
+		    struct page *, struct treepath *, const struct cpu_key *,
+		    loff_t, char *);
+void reiserfs_unmap_buffer(struct buffer_head *);
+
+/* file.c */
+extern const struct inode_operations reiserfs_file_inode_operations;
+extern const struct file_operations reiserfs_file_operations;
+extern const struct address_space_operations reiserfs_address_space_operations;
+
+/* fix_nodes.c */
+
+int fix_nodes(int n_op_mode, struct tree_balance *tb,
+	      struct item_head *ins_ih, const void *);
+void unfix_nodes(struct tree_balance *);
+
+/* prints.c */
+void __reiserfs_panic(struct super_block *s, const char *id,
+		      const char *function, const char *fmt, ...)
+    __attribute__ ((noreturn));
+#define reiserfs_panic(s, id, fmt, args...) \
+	__reiserfs_panic(s, id, __func__, fmt, ##args)
+void __reiserfs_error(struct super_block *s, const char *id,
+		      const char *function, const char *fmt, ...);
+#define reiserfs_error(s, id, fmt, args...) \
+	 __reiserfs_error(s, id, __func__, fmt, ##args)
+void reiserfs_info(struct super_block *s, const char *fmt, ...);
+void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...);
+void print_indirect_item(struct buffer_head *bh, int item_num);
+void store_print_tb(struct tree_balance *tb);
+void print_cur_tb(char *mes);
+void print_de(struct reiserfs_dir_entry *de);
+void print_bi(struct buffer_info *bi, char *mes);
+#define PRINT_LEAF_ITEMS 1	/* print all items */
+#define PRINT_DIRECTORY_ITEMS 2	/* print directory items */
+#define PRINT_DIRECT_ITEMS 4	/* print contents of direct items */
+void print_block(struct buffer_head *bh, ...);
+void print_bmap(struct super_block *s, int silent);
+void print_bmap_block(int i, char *data, int size, int silent);
+/*void print_super_block (struct super_block * s, char * mes);*/
+void print_objectid_map(struct super_block *s);
+void print_block_head(struct buffer_head *bh, char *mes);
+void check_leaf(struct buffer_head *bh);
+void check_internal(struct buffer_head *bh);
+void print_statistics(struct super_block *s);
+char *reiserfs_hashname(int code);
+
+/* lbalance.c */
+int leaf_move_items(int shift_mode, struct tree_balance *tb, int mov_num,
+		    int mov_bytes, struct buffer_head *Snew);
+int leaf_shift_left(struct tree_balance *tb, int shift_num, int shift_bytes);
+int leaf_shift_right(struct tree_balance *tb, int shift_num, int shift_bytes);
+void leaf_delete_items(struct buffer_info *cur_bi, int last_first, int first,
+		       int del_num, int del_bytes);
+void leaf_insert_into_buf(struct buffer_info *bi, int before,
+			  struct item_head *inserted_item_ih,
+			  const char *inserted_item_body, int zeros_number);
+void leaf_paste_in_buffer(struct buffer_info *bi, int pasted_item_num,
+			  int pos_in_item, int paste_size, const char *body,
+			  int zeros_number);
+void leaf_cut_from_buffer(struct buffer_info *bi, int cut_item_num,
+			  int pos_in_item, int cut_size);
+void leaf_paste_entries(struct buffer_info *bi, int item_num, int before,
+			int new_entry_count, struct reiserfs_de_head *new_dehs,
+			const char *records, int paste_size);
+/* ibalance.c */
+int balance_internal(struct tree_balance *, int, int, struct item_head *,
+		     struct buffer_head **);
+
+/* do_balance.c */
+void do_balance_mark_leaf_dirty(struct tree_balance *tb,
+				struct buffer_head *bh, int flag);
+#define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty
+#define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty
+
+void do_balance(struct tree_balance *tb, struct item_head *ih,
+		const char *body, int flag);
+void reiserfs_invalidate_buffer(struct tree_balance *tb,
+				struct buffer_head *bh);
+
+int get_left_neighbor_position(struct tree_balance *tb, int h);
+int get_right_neighbor_position(struct tree_balance *tb, int h);
+void replace_key(struct tree_balance *tb, struct buffer_head *, int,
+		 struct buffer_head *, int);
+void make_empty_node(struct buffer_info *);
+struct buffer_head *get_FEB(struct tree_balance *);
+
+/* bitmap.c */
+
+/* structure contains hints for block allocator, and it is a container for
+ * arguments, such as node, search path, transaction_handle, etc. */
+struct __reiserfs_blocknr_hint {
+	struct inode *inode;	/* inode passed to allocator, if we allocate unf. nodes */
+	sector_t block;		/* file offset, in blocks */
+	struct in_core_key key;
+	struct treepath *path;	/* search path, used by allocator to deternine search_start by
+				 * various ways */
+	struct reiserfs_transaction_handle *th;	/* transaction handle is needed to log super blocks and
+						 * bitmap blocks changes  */
+	b_blocknr_t beg, end;
+	b_blocknr_t search_start;	/* a field used to transfer search start value (block number)
+					 * between different block allocator procedures
+					 * (determine_search_start() and others) */
+	int prealloc_size;	/* is set in determine_prealloc_size() function, used by underlayed
+				 * function that do actual allocation */
+
+	unsigned formatted_node:1;	/* the allocator uses different polices for getting disk space for
+					 * formatted/unformatted blocks with/without preallocation */
+	unsigned preallocate:1;
+};
+
+typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t;
+
+int reiserfs_parse_alloc_options(struct super_block *, char *);
+void reiserfs_init_alloc_options(struct super_block *s);
+
+/*
+ * given a directory, this will tell you what packing locality
+ * to use for a new object underneat it.  The locality is returned
+ * in disk byte order (le).
+ */
+__le32 reiserfs_choose_packing(struct inode *dir);
+
+int reiserfs_init_bitmap_cache(struct super_block *sb);
+void reiserfs_free_bitmap_cache(struct super_block *sb);
+void reiserfs_cache_bitmap_metadata(struct super_block *sb, struct buffer_head *bh, struct reiserfs_bitmap_info *info);
+struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, unsigned int bitmap);
+int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value);
+void reiserfs_free_block(struct reiserfs_transaction_handle *th, struct inode *,
+			 b_blocknr_t, int for_unformatted);
+int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t *, int,
+			       int);
+static inline int reiserfs_new_form_blocknrs(struct tree_balance *tb,
+					     b_blocknr_t * new_blocknrs,
+					     int amount_needed)
+{
+	reiserfs_blocknr_hint_t hint = {
+		.th = tb->transaction_handle,
+		.path = tb->tb_path,
+		.inode = NULL,
+		.key = tb->key,
+		.block = 0,
+		.formatted_node = 1
+	};
+	return reiserfs_allocate_blocknrs(&hint, new_blocknrs, amount_needed,
+					  0);
+}
+
+static inline int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle
+					    *th, struct inode *inode,
+					    b_blocknr_t * new_blocknrs,
+					    struct treepath *path,
+					    sector_t block)
+{
+	reiserfs_blocknr_hint_t hint = {
+		.th = th,
+		.path = path,
+		.inode = inode,
+		.block = block,
+		.formatted_node = 0,
+		.preallocate = 0
+	};
+	return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
+}
+
+#ifdef REISERFS_PREALLOCATE
+static inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle
+					     *th, struct inode *inode,
+					     b_blocknr_t * new_blocknrs,
+					     struct treepath *path,
+					     sector_t block)
+{
+	reiserfs_blocknr_hint_t hint = {
+		.th = th,
+		.path = path,
+		.inode = inode,
+		.block = block,
+		.formatted_node = 0,
+		.preallocate = 1
+	};
+	return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
+}
+
+void reiserfs_discard_prealloc(struct reiserfs_transaction_handle *th,
+			       struct inode *inode);
+void reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle *th);
+#endif
+
+/* hashes.c */
+__u32 keyed_hash(const signed char *msg, int len);
+__u32 yura_hash(const signed char *msg, int len);
+__u32 r5_hash(const signed char *msg, int len);
+
+#define reiserfs_set_le_bit		__set_bit_le
+#define reiserfs_test_and_set_le_bit	__test_and_set_bit_le
+#define reiserfs_clear_le_bit		__clear_bit_le
+#define reiserfs_test_and_clear_le_bit	__test_and_clear_bit_le
+#define reiserfs_test_le_bit		test_bit_le
+#define reiserfs_find_next_zero_le_bit	find_next_zero_bit_le
+
+/* sometimes reiserfs_truncate may require to allocate few new blocks
+   to perform indirect2direct conversion. People probably used to
+   think, that truncate should work without problems on a filesystem
+   without free disk space. They may complain that they can not
+   truncate due to lack of free disk space. This spare space allows us
+   to not worry about it. 500 is probably too much, but it should be
+   absolutely safe */
+#define SPARE_SPACE 500
+
+/* prototypes from ioctl.c */
+long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+long reiserfs_compat_ioctl(struct file *filp,
+		   unsigned int cmd, unsigned long arg);
+int reiserfs_unpack(struct inode *inode, struct file *filp);
diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c
index 7483279..9a17f63 100644
--- a/fs/reiserfs/resize.c
+++ b/fs/reiserfs/resize.c
@@ -13,8 +13,7 @@
 #include <linux/vmalloc.h>
 #include <linux/string.h>
 #include <linux/errno.h>
-#include <linux/reiserfs_fs.h>
-#include <linux/reiserfs_fs_sb.h>
+#include "reiserfs.h"
 #include <linux/buffer_head.h>
 
 int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
index 77df82f..f8afa4b 100644
--- a/fs/reiserfs/stree.c
+++ b/fs/reiserfs/stree.c
@@ -51,7 +51,7 @@
 #include <linux/time.h>
 #include <linux/string.h>
 #include <linux/pagemap.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/buffer_head.h>
 #include <linux/quotaops.h>
 
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index e12d8b9..8b7616e 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -16,9 +16,9 @@
 #include <linux/vmalloc.h>
 #include <linux/time.h>
 #include <asm/uaccess.h>
-#include <linux/reiserfs_fs.h>
-#include <linux/reiserfs_acl.h>
-#include <linux/reiserfs_xattr.h>
+#include "reiserfs.h"
+#include "acl.h"
+#include "xattr.h"
 #include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/buffer_head.h>
@@ -1874,11 +1874,9 @@
 		unlock_new_inode(root_inode);
 	}
 
-	s->s_root = d_alloc_root(root_inode);
-	if (!s->s_root) {
-		iput(root_inode);
+	s->s_root = d_make_root(root_inode);
+	if (!s->s_root)
 		goto error;
-	}
 	// define and initialize hash function
 	sbi->s_hash_function = hash_function(s);
 	if (sbi->s_hash_function == NULL) {
diff --git a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c
index 8f546bd..5e2624d 100644
--- a/fs/reiserfs/tail_conversion.c
+++ b/fs/reiserfs/tail_conversion.c
@@ -5,7 +5,7 @@
 #include <linux/time.h>
 #include <linux/pagemap.h>
 #include <linux/buffer_head.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 
 /* access to tail : when one is going to read tail it must make sure, that is not running.
  direct2indirect and indirect2direct can not run concurrently */
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index c24deda..46fc1c2 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -33,7 +33,7 @@
  * The xattrs themselves are protected by the xattr_sem.
  */
 
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/capability.h>
 #include <linux/dcache.h>
 #include <linux/namei.h>
@@ -43,8 +43,8 @@
 #include <linux/file.h>
 #include <linux/pagemap.h>
 #include <linux/xattr.h>
-#include <linux/reiserfs_xattr.h>
-#include <linux/reiserfs_acl.h>
+#include "xattr.h"
+#include "acl.h"
 #include <asm/uaccess.h>
 #include <net/checksum.h>
 #include <linux/stat.h>
diff --git a/fs/reiserfs/xattr.h b/fs/reiserfs/xattr.h
new file mode 100644
index 0000000..f59626c
--- /dev/null
+++ b/fs/reiserfs/xattr.h
@@ -0,0 +1,122 @@
+#include <linux/reiserfs_xattr.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/rwsem.h>
+
+struct inode;
+struct dentry;
+struct iattr;
+struct super_block;
+struct nameidata;
+
+int reiserfs_xattr_register_handlers(void) __init;
+void reiserfs_xattr_unregister_handlers(void);
+int reiserfs_xattr_init(struct super_block *sb, int mount_flags);
+int reiserfs_lookup_privroot(struct super_block *sb);
+int reiserfs_delete_xattrs(struct inode *inode);
+int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs);
+int reiserfs_permission(struct inode *inode, int mask);
+
+#ifdef CONFIG_REISERFS_FS_XATTR
+#define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
+ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name,
+			  void *buffer, size_t size);
+int reiserfs_setxattr(struct dentry *dentry, const char *name,
+		      const void *value, size_t size, int flags);
+ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
+int reiserfs_removexattr(struct dentry *dentry, const char *name);
+
+int reiserfs_xattr_get(struct inode *, const char *, void *, size_t);
+int reiserfs_xattr_set(struct inode *, const char *, const void *, size_t, int);
+int reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *,
+			      struct inode *, const char *, const void *,
+			      size_t, int);
+
+extern const struct xattr_handler reiserfs_xattr_user_handler;
+extern const struct xattr_handler reiserfs_xattr_trusted_handler;
+extern const struct xattr_handler reiserfs_xattr_security_handler;
+#ifdef CONFIG_REISERFS_FS_SECURITY
+int reiserfs_security_init(struct inode *dir, struct inode *inode,
+			   const struct qstr *qstr,
+			   struct reiserfs_security_handle *sec);
+int reiserfs_security_write(struct reiserfs_transaction_handle *th,
+			    struct inode *inode,
+			    struct reiserfs_security_handle *sec);
+void reiserfs_security_free(struct reiserfs_security_handle *sec);
+#endif
+
+static inline int reiserfs_xattrs_initialized(struct super_block *sb)
+{
+	return REISERFS_SB(sb)->priv_root != NULL;
+}
+
+#define xattr_size(size) ((size) + sizeof(struct reiserfs_xattr_header))
+static inline loff_t reiserfs_xattr_nblocks(struct inode *inode, loff_t size)
+{
+	loff_t ret = 0;
+	if (reiserfs_file_data_log(inode)) {
+		ret = _ROUND_UP(xattr_size(size), inode->i_sb->s_blocksize);
+		ret >>= inode->i_sb->s_blocksize_bits;
+	}
+	return ret;
+}
+
+/* We may have to create up to 3 objects: xattr root, xattr dir, xattr file.
+ * Let's try to be smart about it.
+ * xattr root: We cache it. If it's not cached, we may need to create it.
+ * xattr dir: If anything has been loaded for this inode, we can set a flag
+ *            saying so.
+ * xattr file: Since we don't cache xattrs, we can't tell. We always include
+ *             blocks for it.
+ *
+ * However, since root and dir can be created between calls - YOU MUST SAVE
+ * THIS VALUE.
+ */
+static inline size_t reiserfs_xattr_jcreate_nblocks(struct inode *inode)
+{
+	size_t nblocks = JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
+
+	if ((REISERFS_I(inode)->i_flags & i_has_xattr_dir) == 0) {
+		nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
+		if (!REISERFS_SB(inode->i_sb)->xattr_root->d_inode)
+			nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
+	}
+
+	return nblocks;
+}
+
+static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
+{
+	init_rwsem(&REISERFS_I(inode)->i_xattr_sem);
+}
+
+#else
+
+#define reiserfs_getxattr NULL
+#define reiserfs_setxattr NULL
+#define reiserfs_listxattr NULL
+#define reiserfs_removexattr NULL
+
+static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
+{
+}
+#endif  /*  CONFIG_REISERFS_FS_XATTR  */
+
+#ifndef CONFIG_REISERFS_FS_SECURITY
+static inline int reiserfs_security_init(struct inode *dir,
+					 struct inode *inode,
+					 const struct qstr *qstr,
+					 struct reiserfs_security_handle *sec)
+{
+	return 0;
+}
+static inline int
+reiserfs_security_write(struct reiserfs_transaction_handle *th,
+			struct inode *inode,
+			struct reiserfs_security_handle *sec)
+{
+	return 0;
+}
+static inline void reiserfs_security_free(struct reiserfs_security_handle *sec)
+{}
+#endif
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
index 6da0396e..44474f9 100644
--- a/fs/reiserfs/xattr_acl.c
+++ b/fs/reiserfs/xattr_acl.c
@@ -1,14 +1,14 @@
 #include <linux/capability.h>
 #include <linux/fs.h>
 #include <linux/posix_acl.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/errno.h>
 #include <linux/pagemap.h>
 #include <linux/xattr.h>
 #include <linux/slab.h>
 #include <linux/posix_acl_xattr.h>
-#include <linux/reiserfs_xattr.h>
-#include <linux/reiserfs_acl.h>
+#include "xattr.h"
+#include "acl.h"
 #include <asm/uaccess.h>
 
 static int reiserfs_set_acl(struct reiserfs_transaction_handle *th,
diff --git a/fs/reiserfs/xattr_security.c b/fs/reiserfs/xattr_security.c
index 534668f..800a3ce 100644
--- a/fs/reiserfs/xattr_security.c
+++ b/fs/reiserfs/xattr_security.c
@@ -1,10 +1,10 @@
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/xattr.h>
 #include <linux/slab.h>
-#include <linux/reiserfs_xattr.h>
+#include "xattr.h"
 #include <linux/security.h>
 #include <asm/uaccess.h>
 
diff --git a/fs/reiserfs/xattr_trusted.c b/fs/reiserfs/xattr_trusted.c
index 9883736..a003571 100644
--- a/fs/reiserfs/xattr_trusted.c
+++ b/fs/reiserfs/xattr_trusted.c
@@ -1,10 +1,10 @@
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/xattr.h>
-#include <linux/reiserfs_xattr.h>
+#include "xattr.h"
 #include <asm/uaccess.h>
 
 static int
diff --git a/fs/reiserfs/xattr_user.c b/fs/reiserfs/xattr_user.c
index 45ae1a0..8667491 100644
--- a/fs/reiserfs/xattr_user.c
+++ b/fs/reiserfs/xattr_user.c
@@ -1,9 +1,9 @@
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/xattr.h>
-#include <linux/reiserfs_xattr.h>
+#include "xattr.h"
 #include <asm/uaccess.h>
 
 static int
diff --git a/fs/romfs/storage.c b/fs/romfs/storage.c
index 71e2b4d..f86f51f 100644
--- a/fs/romfs/storage.c
+++ b/fs/romfs/storage.c
@@ -19,7 +19,7 @@
 #endif
 
 #ifdef CONFIG_ROMFS_ON_MTD
-#define ROMFS_MTD_READ(sb, ...) ((sb)->s_mtd->read((sb)->s_mtd, ##__VA_ARGS__))
+#define ROMFS_MTD_READ(sb, ...) mtd_read((sb)->s_mtd, ##__VA_ARGS__)
 
 /*
  * read data from an romfs image on an MTD device
diff --git a/fs/romfs/super.c b/fs/romfs/super.c
index bb36ab7..e64f6b5 100644
--- a/fs/romfs/super.c
+++ b/fs/romfs/super.c
@@ -538,14 +538,12 @@
 	if (IS_ERR(root))
 		goto error;
 
-	sb->s_root = d_alloc_root(root);
+	sb->s_root = d_make_root(root);
 	if (!sb->s_root)
-		goto error_i;
+		goto error;
 
 	return 0;
 
-error_i:
-	iput(root);
 error:
 	return -EINVAL;
 error_rsb_inval:
diff --git a/fs/select.c b/fs/select.c
index e782258..17d33d0 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -17,7 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/syscalls.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/personality.h> /* for STICKY_TIMEOUTS */
@@ -223,7 +223,7 @@
 	get_file(filp);
 	entry->filp = filp;
 	entry->wait_address = wait_address;
-	entry->key = p->key;
+	entry->key = p->_key;
 	init_waitqueue_func_entry(&entry->wait, pollwake);
 	entry->wait.private = pwq;
 	add_wait_queue(wait_address, &entry->wait);
@@ -348,7 +348,7 @@
 	set = ~(~0UL << (n & (__NFDBITS-1)));
 	n /= __NFDBITS;
 	fdt = files_fdtable(current->files);
-	open_fds = fdt->open_fds->fds_bits+n;
+	open_fds = fdt->open_fds + n;
 	max = 0;
 	if (set) {
 		set &= BITS(fds, n);
@@ -386,13 +386,11 @@
 static inline void wait_key_set(poll_table *wait, unsigned long in,
 				unsigned long out, unsigned long bit)
 {
-	if (wait) {
-		wait->key = POLLEX_SET;
-		if (in & bit)
-			wait->key |= POLLIN_SET;
-		if (out & bit)
-			wait->key |= POLLOUT_SET;
-	}
+	wait->_key = POLLEX_SET;
+	if (in & bit)
+		wait->_key |= POLLIN_SET;
+	if (out & bit)
+		wait->_key |= POLLOUT_SET;
 }
 
 int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
@@ -414,7 +412,7 @@
 	poll_initwait(&table);
 	wait = &table.pt;
 	if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {
-		wait = NULL;
+		wait->_qproc = NULL;
 		timed_out = 1;
 	}
 
@@ -459,17 +457,17 @@
 					if ((mask & POLLIN_SET) && (in & bit)) {
 						res_in |= bit;
 						retval++;
-						wait = NULL;
+						wait->_qproc = NULL;
 					}
 					if ((mask & POLLOUT_SET) && (out & bit)) {
 						res_out |= bit;
 						retval++;
-						wait = NULL;
+						wait->_qproc = NULL;
 					}
 					if ((mask & POLLEX_SET) && (ex & bit)) {
 						res_ex |= bit;
 						retval++;
-						wait = NULL;
+						wait->_qproc = NULL;
 					}
 				}
 			}
@@ -481,7 +479,7 @@
 				*rexp = res_ex;
 			cond_resched();
 		}
-		wait = NULL;
+		wait->_qproc = NULL;
 		if (retval || timed_out || signal_pending(current))
 			break;
 		if (table.error) {
@@ -720,7 +718,7 @@
  * interested in events matching the pollfd->events mask, and the result
  * matching that mask is both recorded in pollfd->revents and returned. The
  * pwait poll_table will be used by the fd-provided poll handler for waiting,
- * if non-NULL.
+ * if pwait->_qproc is non-NULL.
  */
 static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
 {
@@ -738,9 +736,7 @@
 		if (file != NULL) {
 			mask = DEFAULT_POLLMASK;
 			if (file->f_op && file->f_op->poll) {
-				if (pwait)
-					pwait->key = pollfd->events |
-							POLLERR | POLLHUP;
+				pwait->_key = pollfd->events|POLLERR|POLLHUP;
 				mask = file->f_op->poll(file, pwait);
 			}
 			/* Mask out unneeded events. */
@@ -763,7 +759,7 @@
 
 	/* Optimise the no-wait case */
 	if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {
-		pt = NULL;
+		pt->_qproc = NULL;
 		timed_out = 1;
 	}
 
@@ -781,22 +777,22 @@
 			for (; pfd != pfd_end; pfd++) {
 				/*
 				 * Fish for events. If we found one, record it
-				 * and kill the poll_table, so we don't
+				 * and kill poll_table->_qproc, so we don't
 				 * needlessly register any other waiters after
 				 * this. They'll get immediately deregistered
 				 * when we break out and return.
 				 */
 				if (do_pollfd(pfd, pt)) {
 					count++;
-					pt = NULL;
+					pt->_qproc = NULL;
 				}
 			}
 		}
 		/*
 		 * All waiters have already been registered, so don't provide
-		 * a poll_table to them on the next loop iteration.
+		 * a poll_table->_qproc to them on the next loop iteration.
 		 */
-		pt = NULL;
+		pt->_qproc = NULL;
 		if (!count) {
 			count = wait->error;
 			if (signal_pending(current))
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 4023d6b..0cbd049 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -6,13 +6,29 @@
  */
 
 #include <linux/fs.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
 
+
+/*
+ * seq_files have a buffer which can may overflow. When this happens a larger
+ * buffer is reallocated and all the data will be printed again.
+ * The overflow state is true when m->count == m->size.
+ */
+static bool seq_overflow(struct seq_file *m)
+{
+	return m->count == m->size;
+}
+
+static void seq_set_overflow(struct seq_file *m)
+{
+	m->count = m->size;
+}
+
 /**
  *	seq_open -	initialize sequential file
  *	@file: file we initialize
@@ -92,7 +108,7 @@
 			error = 0;
 			m->count = 0;
 		}
-		if (m->count == m->size)
+		if (seq_overflow(m))
 			goto Eoverflow;
 		if (pos + m->count > offset) {
 			m->from = offset - pos;
@@ -140,21 +156,6 @@
 
 	mutex_lock(&m->lock);
 
-	/* Don't assume *ppos is where we left it */
-	if (unlikely(*ppos != m->read_pos)) {
-		m->read_pos = *ppos;
-		while ((err = traverse(m, *ppos)) == -EAGAIN)
-			;
-		if (err) {
-			/* With prejudice... */
-			m->read_pos = 0;
-			m->version = 0;
-			m->index = 0;
-			m->count = 0;
-			goto Done;
-		}
-	}
-
 	/*
 	 * seq_file->op->..m_start/m_stop/m_next may do special actions
 	 * or optimisations based on the file->f_version, so we want to
@@ -167,6 +168,23 @@
 	 * need of passing another argument to all the seq_file methods.
 	 */
 	m->version = file->f_version;
+
+	/* Don't assume *ppos is where we left it */
+	if (unlikely(*ppos != m->read_pos)) {
+		while ((err = traverse(m, *ppos)) == -EAGAIN)
+			;
+		if (err) {
+			/* With prejudice... */
+			m->read_pos = 0;
+			m->version = 0;
+			m->index = 0;
+			m->count = 0;
+			goto Done;
+		} else {
+			m->read_pos = *ppos;
+		}
+	}
+
 	/* grab buffer if we didn't have one */
 	if (!m->buf) {
 		m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
@@ -232,7 +250,7 @@
 			break;
 		}
 		err = m->op->show(m, p);
-		if (m->count == m->size || err) {
+		if (seq_overflow(m) || err) {
 			m->count = offs;
 			if (likely(err <= 0))
 				break;
@@ -359,7 +377,7 @@
 			*p++ = '0' + (c & 07);
 			continue;
 		}
-		m->count = m->size;
+		seq_set_overflow(m);
 		return -1;
         }
 	m->count = p - m->buf;
@@ -381,7 +399,7 @@
 			return 0;
 		}
 	}
-	m->count = m->size;
+	seq_set_overflow(m);
 	return -1;
 }
 EXPORT_SYMBOL(seq_printf);
@@ -510,7 +528,7 @@
 			return 0;
 		}
 	}
-	m->count = m->size;
+	seq_set_overflow(m);
 	return -1;
 }
 EXPORT_SYMBOL(seq_bitmap);
@@ -526,7 +544,7 @@
 			return 0;
 		}
 	}
-	m->count = m->size;
+	seq_set_overflow(m);
 	return -1;
 }
 EXPORT_SYMBOL(seq_bitmap_list);
@@ -637,11 +655,63 @@
 		m->count += len;
 		return 0;
 	}
-	m->count = m->size;
+	seq_set_overflow(m);
 	return -1;
 }
 EXPORT_SYMBOL(seq_puts);
 
+/*
+ * A helper routine for putting decimal numbers without rich format of printf().
+ * only 'unsigned long long' is supported.
+ * This routine will put one byte delimiter + number into seq_file.
+ * This routine is very quick when you show lots of numbers.
+ * In usual cases, it will be better to use seq_printf(). It's easier to read.
+ */
+int seq_put_decimal_ull(struct seq_file *m, char delimiter,
+			unsigned long long num)
+{
+	int len;
+
+	if (m->count + 2 >= m->size) /* we'll write 2 bytes at least */
+		goto overflow;
+
+	if (delimiter)
+		m->buf[m->count++] = delimiter;
+
+	if (num < 10) {
+		m->buf[m->count++] = num + '0';
+		return 0;
+	}
+
+	len = num_to_str(m->buf + m->count, m->size - m->count, num);
+	if (!len)
+		goto overflow;
+	m->count += len;
+	return 0;
+overflow:
+	seq_set_overflow(m);
+	return -1;
+}
+EXPORT_SYMBOL(seq_put_decimal_ull);
+
+int seq_put_decimal_ll(struct seq_file *m, char delimiter,
+			long long num)
+{
+	if (num < 0) {
+		if (m->count + 3 >= m->size) {
+			seq_set_overflow(m);
+			return -1;
+		}
+		if (delimiter)
+			m->buf[m->count++] = delimiter;
+		num = -num;
+		delimiter = '-';
+	}
+	return seq_put_decimal_ull(m, delimiter, num);
+
+}
+EXPORT_SYMBOL(seq_put_decimal_ll);
+
 /**
  * seq_write - write arbitrary data to buffer
  * @seq: seq_file identifying the buffer to which data should be written
@@ -657,7 +727,7 @@
 		seq->count += len;
 		return 0;
 	}
-	seq->count = seq->size;
+	seq_set_overflow(seq);
 	return -1;
 }
 EXPORT_SYMBOL(seq_write);
diff --git a/fs/splice.c b/fs/splice.c
index f16402e..f847684 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -25,11 +25,12 @@
 #include <linux/mm_inline.h>
 #include <linux/swap.h>
 #include <linux/writeback.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/syscalls.h>
 #include <linux/uio.h>
 #include <linux/security.h>
 #include <linux/gfp.h>
+#include <linux/socket.h>
 
 /*
  * Attempt to steal a page from a pipe buffer. This should perhaps go into
@@ -690,7 +691,9 @@
 	if (!likely(file->f_op && file->f_op->sendpage))
 		return -EINVAL;
 
-	more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len;
+	more = (sd->flags & SPLICE_F_MORE) ? MSG_MORE : 0;
+	if (sd->len < sd->total_len)
+		more |= MSG_SENDPAGE_NOTLAST;
 	return file->f_op->sendpage(file, buf->page, buf->offset,
 				    sd->len, &pos, more);
 }
diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
index ed0eb2a..fb50652 100644
--- a/fs/squashfs/block.c
+++ b/fs/squashfs/block.c
@@ -83,7 +83,8 @@
  * filesystem), otherwise the length is obtained from the first two bytes of
  * the metadata block.  A bit in the length field indicates if the block
  * is stored uncompressed in the filesystem (usually because compression
- * generated a larger block - this does occasionally happen with zlib).
+ * generated a larger block - this does occasionally happen with compression
+ * algorithms).
  */
 int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
 			int length, u64 *next_index, int srclength, int pages)
diff --git a/fs/squashfs/dir.c b/fs/squashfs/dir.c
index 9dfe2ce..b381305 100644
--- a/fs/squashfs/dir.c
+++ b/fs/squashfs/dir.c
@@ -64,7 +64,7 @@
 	 * is offset by 3 because we invent "." and ".." entries which are
 	 * not actually stored in the directory.
 	 */
-	if (f_pos < 3)
+	if (f_pos <= 3)
 		return f_pos;
 	f_pos -= 3;
 
@@ -105,7 +105,7 @@
 	struct inode *inode = file->f_dentry->d_inode;
 	struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
 	u64 block = squashfs_i(inode)->start + msblk->directory_table;
-	int offset = squashfs_i(inode)->offset, length = 0, dir_count, size,
+	int offset = squashfs_i(inode)->offset, length, dir_count, size,
 				type, err;
 	unsigned int inode_number;
 	struct squashfs_dir_header dirh;
@@ -173,8 +173,7 @@
 
 		dir_count = le32_to_cpu(dirh.count) + 1;
 
-		/* dir_count should never be larger than 256 */
-		if (dir_count > 256)
+		if (dir_count > SQUASHFS_DIR_COUNT)
 			goto failed_read;
 
 		while (dir_count--) {
diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c
index 0682b38..abcc58f 100644
--- a/fs/squashfs/namei.c
+++ b/fs/squashfs/namei.c
@@ -144,7 +144,7 @@
 	struct squashfs_dir_entry *dire;
 	u64 block = squashfs_i(dir)->start + msblk->directory_table;
 	int offset = squashfs_i(dir)->offset;
-	int err, length = 0, dir_count, size;
+	int err, length, dir_count, size;
 
 	TRACE("Entered squashfs_lookup [%llx:%x]\n", block, offset);
 
@@ -177,8 +177,7 @@
 
 		dir_count = le32_to_cpu(dirh.count) + 1;
 
-		/* dir_count should never be larger than 256 */
-		if (dir_count > 256)
+		if (dir_count > SQUASHFS_DIR_COUNT)
 			goto data_error;
 
 		while (dir_count--) {
diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h
index e8e1464..9e2349d 100644
--- a/fs/squashfs/squashfs_fs.h
+++ b/fs/squashfs/squashfs_fs.h
@@ -30,11 +30,6 @@
 
 /* size of metadata (inode and directory) blocks */
 #define SQUASHFS_METADATA_SIZE		8192
-#define SQUASHFS_METADATA_LOG		13
-
-/* default size of data blocks */
-#define SQUASHFS_FILE_SIZE		131072
-#define SQUASHFS_FILE_LOG		17
 
 /* default size of block device I/O */
 #ifdef CONFIG_SQUASHFS_4K_DEVBLK_SIZE
@@ -46,12 +41,12 @@
 #define SQUASHFS_FILE_MAX_SIZE		1048576
 #define SQUASHFS_FILE_MAX_LOG		20
 
-/* Max number of uids and gids */
-#define SQUASHFS_IDS			65536
-
 /* Max length of filename (not 255) */
 #define SQUASHFS_NAME_LEN		256
 
+/* Max value for directory header count*/
+#define SQUASHFS_DIR_COUNT		256
+
 #define SQUASHFS_INVALID_FRAG		(0xffffffffU)
 #define SQUASHFS_INVALID_XATTR		(0xffffffffU)
 #define SQUASHFS_INVALID_BLK		(-1LL)
@@ -142,9 +137,6 @@
 #define SQUASHFS_MKINODE(A, B)		((long long)(((long long) (A)\
 					<< 16) + (B)))
 
-/* Translate between VFS mode and squashfs mode */
-#define SQUASHFS_MODE(A)		((A) & 0xfff)
-
 /* fragment and fragment table defines */
 #define SQUASHFS_FRAGMENT_BYTES(A)	\
 				((A) * sizeof(struct squashfs_fragment_entry))
@@ -215,11 +207,6 @@
 /* cached data constants for filesystem */
 #define SQUASHFS_CACHED_BLKS		8
 
-#define SQUASHFS_MAX_FILE_SIZE_LOG	64
-
-#define SQUASHFS_MAX_FILE_SIZE		(1LL << \
-					(SQUASHFS_MAX_FILE_SIZE_LOG - 2))
-
 /* meta index cache */
 #define SQUASHFS_META_INDEXES	(SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
 #define SQUASHFS_META_ENTRIES	127
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
index ecaa2f7..29cd014 100644
--- a/fs/squashfs/super.c
+++ b/fs/squashfs/super.c
@@ -158,10 +158,15 @@
 		goto failed_mount;
 	}
 
+	/* Check block log for sanity */
 	msblk->block_log = le16_to_cpu(sblk->block_log);
 	if (msblk->block_log > SQUASHFS_FILE_MAX_LOG)
 		goto failed_mount;
 
+	/* Check that block_size and block_log match */
+	if (msblk->block_size != (1 << msblk->block_log))
+		goto failed_mount;
+
 	/* Check the root inode for sanity */
 	root_inode = le64_to_cpu(sblk->root_inode);
 	if (SQUASHFS_INODE_OFFSET(root_inode) > SQUASHFS_METADATA_SIZE)
@@ -316,11 +321,10 @@
 	}
 	insert_inode_hash(root);
 
-	sb->s_root = d_alloc_root(root);
+	sb->s_root = d_make_root(root);
 	if (sb->s_root == NULL) {
 		ERROR("Root inode create failed\n");
 		err = -ENOMEM;
-		iput(root);
 		goto failed_mount;
 	}
 
diff --git a/fs/stack.c b/fs/stack.c
index 9c11519..5b53882 100644
--- a/fs/stack.c
+++ b/fs/stack.c
@@ -1,4 +1,4 @@
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/fs_stack.h>
 
diff --git a/fs/stat.c b/fs/stat.c
index 8806b89..c733dc5 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -4,7 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/file.h>
@@ -307,7 +307,7 @@
 		if (inode->i_op->readlink) {
 			error = security_inode_readlink(path.dentry);
 			if (!error) {
-				touch_atime(path.mnt, path.dentry);
+				touch_atime(&path);
 				error = inode->i_op->readlink(path.dentry,
 							      buf, bufsiz);
 			}
diff --git a/fs/statfs.c b/fs/statfs.c
index 2aa6a22..43e6b6f 100644
--- a/fs/statfs.c
+++ b/fs/statfs.c
@@ -1,5 +1,5 @@
 #include <linux/syscalls.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/file.h>
 #include <linux/mount.h>
diff --git a/fs/super.c b/fs/super.c
index d90e900..cf00177 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -20,7 +20,7 @@
  *  Heavily rewritten for 'one fs - one tree' dcache architecture. AV, Mar 2000
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/acct.h>
 #include <linux/blkdev.h>
@@ -251,7 +251,7 @@
 {
 	struct file_system_type *fs = s->s_type;
 	if (atomic_dec_and_test(&s->s_active)) {
-		cleancache_flush_fs(s);
+		cleancache_invalidate_fs(s);
 		fs->kill_sb(s);
 
 		/* caches are now gone, we can safely kill the shrinker now */
diff --git a/fs/sync.c b/fs/sync.c
index f3501ef..0e8db93 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -6,7 +6,7 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/namei.h>
 #include <linux/sched.h>
 #include <linux/writeback.h>
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 140f26a..52c3bdb 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -61,10 +61,9 @@
 	}
 
 	/* instantiate and link root dentry */
-	root = d_alloc_root(inode);
+	root = d_make_root(inode);
 	if (!root) {
 		pr_debug("%s: could not get root dentry!\n",__func__);
-		iput(inode);
 		return -ENOMEM;
 	}
 	root->d_fsdata = &sysfs_root;
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index b217797..d7466e2 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -121,9 +121,6 @@
 {
 	struct inode *inode = old_dentry->d_inode;
 
-	if (inode->i_nlink >= SYSV_SB(inode->i_sb)->s_link_max)
-		return -EMLINK;
-
 	inode->i_ctime = CURRENT_TIME_SEC;
 	inode_inc_link_count(inode);
 	ihold(inode);
@@ -134,10 +131,8 @@
 static int sysv_mkdir(struct inode * dir, struct dentry *dentry, umode_t mode)
 {
 	struct inode * inode;
-	int err = -EMLINK;
+	int err;
 
-	if (dir->i_nlink >= SYSV_SB(dir->i_sb)->s_link_max) 
-		goto out;
 	inode_inc_link_count(dir);
 
 	inode = sysv_new_inode(dir, S_IFDIR|mode);
@@ -251,11 +246,6 @@
 			drop_nlink(new_inode);
 		inode_dec_link_count(new_inode);
 	} else {
-		if (dir_de) {
-			err = -EMLINK;
-			if (new_dir->i_nlink >= SYSV_SB(new_dir->i_sb)->s_link_max)
-				goto out_dir;
-		}
 		err = sysv_add_link(new_dentry, old_inode);
 		if (err)
 			goto out_dir;
diff --git a/fs/sysv/super.c b/fs/sysv/super.c
index f60c196..7491c33 100644
--- a/fs/sysv/super.c
+++ b/fs/sysv/super.c
@@ -44,7 +44,7 @@
 	JAN_1_1980 = (10*365 + 2) * 24 * 60 * 60
 };
 
-static void detected_xenix(struct sysv_sb_info *sbi)
+static void detected_xenix(struct sysv_sb_info *sbi, unsigned *max_links)
 {
 	struct buffer_head *bh1 = sbi->s_bh1;
 	struct buffer_head *bh2 = sbi->s_bh2;
@@ -59,7 +59,7 @@
 		sbd2 = (struct xenix_super_block *) (bh2->b_data - 512);
 	}
 
-	sbi->s_link_max = XENIX_LINK_MAX;
+	*max_links = XENIX_LINK_MAX;
 	sbi->s_fic_size = XENIX_NICINOD;
 	sbi->s_flc_size = XENIX_NICFREE;
 	sbi->s_sbd1 = (char *)sbd1;
@@ -75,7 +75,7 @@
 	sbi->s_nzones = fs32_to_cpu(sbi, sbd1->s_fsize);
 }
 
-static void detected_sysv4(struct sysv_sb_info *sbi)
+static void detected_sysv4(struct sysv_sb_info *sbi, unsigned *max_links)
 {
 	struct sysv4_super_block * sbd;
 	struct buffer_head *bh1 = sbi->s_bh1;
@@ -86,7 +86,7 @@
 	else
 		sbd = (struct sysv4_super_block *) bh2->b_data;
 
-	sbi->s_link_max = SYSV_LINK_MAX;
+	*max_links = SYSV_LINK_MAX;
 	sbi->s_fic_size = SYSV_NICINOD;
 	sbi->s_flc_size = SYSV_NICFREE;
 	sbi->s_sbd1 = (char *)sbd;
@@ -103,7 +103,7 @@
 	sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);
 }
 
-static void detected_sysv2(struct sysv_sb_info *sbi)
+static void detected_sysv2(struct sysv_sb_info *sbi, unsigned *max_links)
 {
 	struct sysv2_super_block *sbd;
 	struct buffer_head *bh1 = sbi->s_bh1;
@@ -114,7 +114,7 @@
 	else
 		sbd = (struct sysv2_super_block *) bh2->b_data;
 
-	sbi->s_link_max = SYSV_LINK_MAX;
+	*max_links = SYSV_LINK_MAX;
 	sbi->s_fic_size = SYSV_NICINOD;
 	sbi->s_flc_size = SYSV_NICFREE;
 	sbi->s_sbd1 = (char *)sbd;
@@ -131,14 +131,14 @@
 	sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);
 }
 
-static void detected_coherent(struct sysv_sb_info *sbi)
+static void detected_coherent(struct sysv_sb_info *sbi, unsigned *max_links)
 {
 	struct coh_super_block * sbd;
 	struct buffer_head *bh1 = sbi->s_bh1;
 
 	sbd = (struct coh_super_block *) bh1->b_data;
 
-	sbi->s_link_max = COH_LINK_MAX;
+	*max_links = COH_LINK_MAX;
 	sbi->s_fic_size = COH_NICINOD;
 	sbi->s_flc_size = COH_NICFREE;
 	sbi->s_sbd1 = (char *)sbd;
@@ -154,12 +154,12 @@
 	sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);
 }
 
-static void detected_v7(struct sysv_sb_info *sbi)
+static void detected_v7(struct sysv_sb_info *sbi, unsigned *max_links)
 {
 	struct buffer_head *bh2 = sbi->s_bh2;
 	struct v7_super_block *sbd = (struct v7_super_block *)bh2->b_data;
 
-	sbi->s_link_max = V7_LINK_MAX;
+	*max_links = V7_LINK_MAX;
 	sbi->s_fic_size = V7_NICINOD;
 	sbi->s_flc_size = V7_NICFREE;
 	sbi->s_sbd1 = (char *)sbd;
@@ -290,7 +290,7 @@
 	[FSTYPE_AFS]	= "AFS",
 };
 
-static void (*flavour_setup[])(struct sysv_sb_info *) = {
+static void (*flavour_setup[])(struct sysv_sb_info *, unsigned *) = {
 	[FSTYPE_XENIX]	= detected_xenix,
 	[FSTYPE_SYSV4]	= detected_sysv4,
 	[FSTYPE_SYSV2]	= detected_sysv2,
@@ -310,7 +310,7 @@
 
 	sbi->s_firstinodezone = 2;
 
-	flavour_setup[sbi->s_type](sbi);
+	flavour_setup[sbi->s_type](sbi, &sb->s_max_links);
 	
 	sbi->s_truncate = 1;
 	sbi->s_ndatazones = sbi->s_nzones - sbi->s_firstdatazone;
@@ -341,9 +341,8 @@
 		printk("SysV FS: get root inode failed\n");
 		return 0;
 	}
-	sb->s_root = d_alloc_root(root_inode);
+	sb->s_root = d_make_root(root_inode);
 	if (!sb->s_root) {
-		iput(root_inode);
 		printk("SysV FS: get root dentry failed\n");
 		return 0;
 	}
diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h
index 0e4b821..11b0767 100644
--- a/fs/sysv/sysv.h
+++ b/fs/sysv/sysv.h
@@ -24,7 +24,6 @@
 	char	       s_bytesex;	/* bytesex (le/be/pdp) */
 	char	       s_truncate;	/* if 1: names > SYSV_NAMELEN chars are truncated */
 					/* if 0: they are disallowed (ENAMETOOLONG) */
-	nlink_t        s_link_max;	/* max number of hard links to a file */
 	unsigned int   s_inodes_per_block;	/* number of inodes per block */
 	unsigned int   s_inodes_per_block_1;	/* inodes_per_block - 1 */
 	unsigned int   s_inodes_per_block_bits;	/* log2(inodes_per_block) */
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index f922cba..1934084 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -36,7 +36,7 @@
 
 #ifdef CONFIG_UBIFS_FS_DEBUG
 
-DEFINE_SPINLOCK(dbg_lock);
+static DEFINE_SPINLOCK(dbg_lock);
 
 static const char *get_key_fmt(int fmt)
 {
@@ -221,15 +221,15 @@
 
 static void dump_ch(const struct ubifs_ch *ch)
 {
-	printk(KERN_DEBUG "\tmagic          %#x\n", le32_to_cpu(ch->magic));
-	printk(KERN_DEBUG "\tcrc            %#x\n", le32_to_cpu(ch->crc));
-	printk(KERN_DEBUG "\tnode_type      %d (%s)\n", ch->node_type,
+	printk(KERN_ERR "\tmagic          %#x\n", le32_to_cpu(ch->magic));
+	printk(KERN_ERR "\tcrc            %#x\n", le32_to_cpu(ch->crc));
+	printk(KERN_ERR "\tnode_type      %d (%s)\n", ch->node_type,
 	       dbg_ntype(ch->node_type));
-	printk(KERN_DEBUG "\tgroup_type     %d (%s)\n", ch->group_type,
+	printk(KERN_ERR "\tgroup_type     %d (%s)\n", ch->group_type,
 	       dbg_gtype(ch->group_type));
-	printk(KERN_DEBUG "\tsqnum          %llu\n",
+	printk(KERN_ERR "\tsqnum          %llu\n",
 	       (unsigned long long)le64_to_cpu(ch->sqnum));
-	printk(KERN_DEBUG "\tlen            %u\n", le32_to_cpu(ch->len));
+	printk(KERN_ERR "\tlen            %u\n", le32_to_cpu(ch->len));
 }
 
 void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode)
@@ -240,43 +240,43 @@
 	struct ubifs_dent_node *dent, *pdent = NULL;
 	int count = 2;
 
-	printk(KERN_DEBUG "Dump in-memory inode:");
-	printk(KERN_DEBUG "\tinode          %lu\n", inode->i_ino);
-	printk(KERN_DEBUG "\tsize           %llu\n",
+	printk(KERN_ERR "Dump in-memory inode:");
+	printk(KERN_ERR "\tinode          %lu\n", inode->i_ino);
+	printk(KERN_ERR "\tsize           %llu\n",
 	       (unsigned long long)i_size_read(inode));
-	printk(KERN_DEBUG "\tnlink          %u\n", inode->i_nlink);
-	printk(KERN_DEBUG "\tuid            %u\n", (unsigned int)inode->i_uid);
-	printk(KERN_DEBUG "\tgid            %u\n", (unsigned int)inode->i_gid);
-	printk(KERN_DEBUG "\tatime          %u.%u\n",
+	printk(KERN_ERR "\tnlink          %u\n", inode->i_nlink);
+	printk(KERN_ERR "\tuid            %u\n", (unsigned int)inode->i_uid);
+	printk(KERN_ERR "\tgid            %u\n", (unsigned int)inode->i_gid);
+	printk(KERN_ERR "\tatime          %u.%u\n",
 	       (unsigned int)inode->i_atime.tv_sec,
 	       (unsigned int)inode->i_atime.tv_nsec);
-	printk(KERN_DEBUG "\tmtime          %u.%u\n",
+	printk(KERN_ERR "\tmtime          %u.%u\n",
 	       (unsigned int)inode->i_mtime.tv_sec,
 	       (unsigned int)inode->i_mtime.tv_nsec);
-	printk(KERN_DEBUG "\tctime          %u.%u\n",
+	printk(KERN_ERR "\tctime          %u.%u\n",
 	       (unsigned int)inode->i_ctime.tv_sec,
 	       (unsigned int)inode->i_ctime.tv_nsec);
-	printk(KERN_DEBUG "\tcreat_sqnum    %llu\n", ui->creat_sqnum);
-	printk(KERN_DEBUG "\txattr_size     %u\n", ui->xattr_size);
-	printk(KERN_DEBUG "\txattr_cnt      %u\n", ui->xattr_cnt);
-	printk(KERN_DEBUG "\txattr_names    %u\n", ui->xattr_names);
-	printk(KERN_DEBUG "\tdirty          %u\n", ui->dirty);
-	printk(KERN_DEBUG "\txattr          %u\n", ui->xattr);
-	printk(KERN_DEBUG "\tbulk_read      %u\n", ui->xattr);
-	printk(KERN_DEBUG "\tsynced_i_size  %llu\n",
+	printk(KERN_ERR "\tcreat_sqnum    %llu\n", ui->creat_sqnum);
+	printk(KERN_ERR "\txattr_size     %u\n", ui->xattr_size);
+	printk(KERN_ERR "\txattr_cnt      %u\n", ui->xattr_cnt);
+	printk(KERN_ERR "\txattr_names    %u\n", ui->xattr_names);
+	printk(KERN_ERR "\tdirty          %u\n", ui->dirty);
+	printk(KERN_ERR "\txattr          %u\n", ui->xattr);
+	printk(KERN_ERR "\tbulk_read      %u\n", ui->xattr);
+	printk(KERN_ERR "\tsynced_i_size  %llu\n",
 	       (unsigned long long)ui->synced_i_size);
-	printk(KERN_DEBUG "\tui_size        %llu\n",
+	printk(KERN_ERR "\tui_size        %llu\n",
 	       (unsigned long long)ui->ui_size);
-	printk(KERN_DEBUG "\tflags          %d\n", ui->flags);
-	printk(KERN_DEBUG "\tcompr_type     %d\n", ui->compr_type);
-	printk(KERN_DEBUG "\tlast_page_read %lu\n", ui->last_page_read);
-	printk(KERN_DEBUG "\tread_in_a_row  %lu\n", ui->read_in_a_row);
-	printk(KERN_DEBUG "\tdata_len       %d\n", ui->data_len);
+	printk(KERN_ERR "\tflags          %d\n", ui->flags);
+	printk(KERN_ERR "\tcompr_type     %d\n", ui->compr_type);
+	printk(KERN_ERR "\tlast_page_read %lu\n", ui->last_page_read);
+	printk(KERN_ERR "\tread_in_a_row  %lu\n", ui->read_in_a_row);
+	printk(KERN_ERR "\tdata_len       %d\n", ui->data_len);
 
 	if (!S_ISDIR(inode->i_mode))
 		return;
 
-	printk(KERN_DEBUG "List of directory entries:\n");
+	printk(KERN_ERR "List of directory entries:\n");
 	ubifs_assert(!mutex_is_locked(&c->tnc_mutex));
 
 	lowest_dent_key(c, &key, inode->i_ino);
@@ -284,11 +284,11 @@
 		dent = ubifs_tnc_next_ent(c, &key, &nm);
 		if (IS_ERR(dent)) {
 			if (PTR_ERR(dent) != -ENOENT)
-				printk(KERN_DEBUG "error %ld\n", PTR_ERR(dent));
+				printk(KERN_ERR "error %ld\n", PTR_ERR(dent));
 			break;
 		}
 
-		printk(KERN_DEBUG "\t%d: %s (%s)\n",
+		printk(KERN_ERR "\t%d: %s (%s)\n",
 		       count++, dent->name, get_dent_type(dent->type));
 
 		nm.name = dent->name;
@@ -312,8 +312,8 @@
 
 	/* If the magic is incorrect, just hexdump the first bytes */
 	if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) {
-		printk(KERN_DEBUG "Not a node, first %zu bytes:", UBIFS_CH_SZ);
-		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+		printk(KERN_ERR "Not a node, first %zu bytes:", UBIFS_CH_SZ);
+		print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 32, 1,
 			       (void *)node, UBIFS_CH_SZ, 1);
 		return;
 	}
@@ -326,7 +326,7 @@
 	{
 		const struct ubifs_pad_node *pad = node;
 
-		printk(KERN_DEBUG "\tpad_len        %u\n",
+		printk(KERN_ERR "\tpad_len        %u\n",
 		       le32_to_cpu(pad->pad_len));
 		break;
 	}
@@ -335,50 +335,50 @@
 		const struct ubifs_sb_node *sup = node;
 		unsigned int sup_flags = le32_to_cpu(sup->flags);
 
-		printk(KERN_DEBUG "\tkey_hash       %d (%s)\n",
+		printk(KERN_ERR "\tkey_hash       %d (%s)\n",
 		       (int)sup->key_hash, get_key_hash(sup->key_hash));
-		printk(KERN_DEBUG "\tkey_fmt        %d (%s)\n",
+		printk(KERN_ERR "\tkey_fmt        %d (%s)\n",
 		       (int)sup->key_fmt, get_key_fmt(sup->key_fmt));
-		printk(KERN_DEBUG "\tflags          %#x\n", sup_flags);
-		printk(KERN_DEBUG "\t  big_lpt      %u\n",
+		printk(KERN_ERR "\tflags          %#x\n", sup_flags);
+		printk(KERN_ERR "\t  big_lpt      %u\n",
 		       !!(sup_flags & UBIFS_FLG_BIGLPT));
-		printk(KERN_DEBUG "\t  space_fixup  %u\n",
+		printk(KERN_ERR "\t  space_fixup  %u\n",
 		       !!(sup_flags & UBIFS_FLG_SPACE_FIXUP));
-		printk(KERN_DEBUG "\tmin_io_size    %u\n",
+		printk(KERN_ERR "\tmin_io_size    %u\n",
 		       le32_to_cpu(sup->min_io_size));
-		printk(KERN_DEBUG "\tleb_size       %u\n",
+		printk(KERN_ERR "\tleb_size       %u\n",
 		       le32_to_cpu(sup->leb_size));
-		printk(KERN_DEBUG "\tleb_cnt        %u\n",
+		printk(KERN_ERR "\tleb_cnt        %u\n",
 		       le32_to_cpu(sup->leb_cnt));
-		printk(KERN_DEBUG "\tmax_leb_cnt    %u\n",
+		printk(KERN_ERR "\tmax_leb_cnt    %u\n",
 		       le32_to_cpu(sup->max_leb_cnt));
-		printk(KERN_DEBUG "\tmax_bud_bytes  %llu\n",
+		printk(KERN_ERR "\tmax_bud_bytes  %llu\n",
 		       (unsigned long long)le64_to_cpu(sup->max_bud_bytes));
-		printk(KERN_DEBUG "\tlog_lebs       %u\n",
+		printk(KERN_ERR "\tlog_lebs       %u\n",
 		       le32_to_cpu(sup->log_lebs));
-		printk(KERN_DEBUG "\tlpt_lebs       %u\n",
+		printk(KERN_ERR "\tlpt_lebs       %u\n",
 		       le32_to_cpu(sup->lpt_lebs));
-		printk(KERN_DEBUG "\torph_lebs      %u\n",
+		printk(KERN_ERR "\torph_lebs      %u\n",
 		       le32_to_cpu(sup->orph_lebs));
-		printk(KERN_DEBUG "\tjhead_cnt      %u\n",
+		printk(KERN_ERR "\tjhead_cnt      %u\n",
 		       le32_to_cpu(sup->jhead_cnt));
-		printk(KERN_DEBUG "\tfanout         %u\n",
+		printk(KERN_ERR "\tfanout         %u\n",
 		       le32_to_cpu(sup->fanout));
-		printk(KERN_DEBUG "\tlsave_cnt      %u\n",
+		printk(KERN_ERR "\tlsave_cnt      %u\n",
 		       le32_to_cpu(sup->lsave_cnt));
-		printk(KERN_DEBUG "\tdefault_compr  %u\n",
+		printk(KERN_ERR "\tdefault_compr  %u\n",
 		       (int)le16_to_cpu(sup->default_compr));
-		printk(KERN_DEBUG "\trp_size        %llu\n",
+		printk(KERN_ERR "\trp_size        %llu\n",
 		       (unsigned long long)le64_to_cpu(sup->rp_size));
-		printk(KERN_DEBUG "\trp_uid         %u\n",
+		printk(KERN_ERR "\trp_uid         %u\n",
 		       le32_to_cpu(sup->rp_uid));
-		printk(KERN_DEBUG "\trp_gid         %u\n",
+		printk(KERN_ERR "\trp_gid         %u\n",
 		       le32_to_cpu(sup->rp_gid));
-		printk(KERN_DEBUG "\tfmt_version    %u\n",
+		printk(KERN_ERR "\tfmt_version    %u\n",
 		       le32_to_cpu(sup->fmt_version));
-		printk(KERN_DEBUG "\ttime_gran      %u\n",
+		printk(KERN_ERR "\ttime_gran      %u\n",
 		       le32_to_cpu(sup->time_gran));
-		printk(KERN_DEBUG "\tUUID           %pUB\n",
+		printk(KERN_ERR "\tUUID           %pUB\n",
 		       sup->uuid);
 		break;
 	}
@@ -386,61 +386,61 @@
 	{
 		const struct ubifs_mst_node *mst = node;
 
-		printk(KERN_DEBUG "\thighest_inum   %llu\n",
+		printk(KERN_ERR "\thighest_inum   %llu\n",
 		       (unsigned long long)le64_to_cpu(mst->highest_inum));
-		printk(KERN_DEBUG "\tcommit number  %llu\n",
+		printk(KERN_ERR "\tcommit number  %llu\n",
 		       (unsigned long long)le64_to_cpu(mst->cmt_no));
-		printk(KERN_DEBUG "\tflags          %#x\n",
+		printk(KERN_ERR "\tflags          %#x\n",
 		       le32_to_cpu(mst->flags));
-		printk(KERN_DEBUG "\tlog_lnum       %u\n",
+		printk(KERN_ERR "\tlog_lnum       %u\n",
 		       le32_to_cpu(mst->log_lnum));
-		printk(KERN_DEBUG "\troot_lnum      %u\n",
+		printk(KERN_ERR "\troot_lnum      %u\n",
 		       le32_to_cpu(mst->root_lnum));
-		printk(KERN_DEBUG "\troot_offs      %u\n",
+		printk(KERN_ERR "\troot_offs      %u\n",
 		       le32_to_cpu(mst->root_offs));
-		printk(KERN_DEBUG "\troot_len       %u\n",
+		printk(KERN_ERR "\troot_len       %u\n",
 		       le32_to_cpu(mst->root_len));
-		printk(KERN_DEBUG "\tgc_lnum        %u\n",
+		printk(KERN_ERR "\tgc_lnum        %u\n",
 		       le32_to_cpu(mst->gc_lnum));
-		printk(KERN_DEBUG "\tihead_lnum     %u\n",
+		printk(KERN_ERR "\tihead_lnum     %u\n",
 		       le32_to_cpu(mst->ihead_lnum));
-		printk(KERN_DEBUG "\tihead_offs     %u\n",
+		printk(KERN_ERR "\tihead_offs     %u\n",
 		       le32_to_cpu(mst->ihead_offs));
-		printk(KERN_DEBUG "\tindex_size     %llu\n",
+		printk(KERN_ERR "\tindex_size     %llu\n",
 		       (unsigned long long)le64_to_cpu(mst->index_size));
-		printk(KERN_DEBUG "\tlpt_lnum       %u\n",
+		printk(KERN_ERR "\tlpt_lnum       %u\n",
 		       le32_to_cpu(mst->lpt_lnum));
-		printk(KERN_DEBUG "\tlpt_offs       %u\n",
+		printk(KERN_ERR "\tlpt_offs       %u\n",
 		       le32_to_cpu(mst->lpt_offs));
-		printk(KERN_DEBUG "\tnhead_lnum     %u\n",
+		printk(KERN_ERR "\tnhead_lnum     %u\n",
 		       le32_to_cpu(mst->nhead_lnum));
-		printk(KERN_DEBUG "\tnhead_offs     %u\n",
+		printk(KERN_ERR "\tnhead_offs     %u\n",
 		       le32_to_cpu(mst->nhead_offs));
-		printk(KERN_DEBUG "\tltab_lnum      %u\n",
+		printk(KERN_ERR "\tltab_lnum      %u\n",
 		       le32_to_cpu(mst->ltab_lnum));
-		printk(KERN_DEBUG "\tltab_offs      %u\n",
+		printk(KERN_ERR "\tltab_offs      %u\n",
 		       le32_to_cpu(mst->ltab_offs));
-		printk(KERN_DEBUG "\tlsave_lnum     %u\n",
+		printk(KERN_ERR "\tlsave_lnum     %u\n",
 		       le32_to_cpu(mst->lsave_lnum));
-		printk(KERN_DEBUG "\tlsave_offs     %u\n",
+		printk(KERN_ERR "\tlsave_offs     %u\n",
 		       le32_to_cpu(mst->lsave_offs));
-		printk(KERN_DEBUG "\tlscan_lnum     %u\n",
+		printk(KERN_ERR "\tlscan_lnum     %u\n",
 		       le32_to_cpu(mst->lscan_lnum));
-		printk(KERN_DEBUG "\tleb_cnt        %u\n",
+		printk(KERN_ERR "\tleb_cnt        %u\n",
 		       le32_to_cpu(mst->leb_cnt));
-		printk(KERN_DEBUG "\tempty_lebs     %u\n",
+		printk(KERN_ERR "\tempty_lebs     %u\n",
 		       le32_to_cpu(mst->empty_lebs));
-		printk(KERN_DEBUG "\tidx_lebs       %u\n",
+		printk(KERN_ERR "\tidx_lebs       %u\n",
 		       le32_to_cpu(mst->idx_lebs));
-		printk(KERN_DEBUG "\ttotal_free     %llu\n",
+		printk(KERN_ERR "\ttotal_free     %llu\n",
 		       (unsigned long long)le64_to_cpu(mst->total_free));
-		printk(KERN_DEBUG "\ttotal_dirty    %llu\n",
+		printk(KERN_ERR "\ttotal_dirty    %llu\n",
 		       (unsigned long long)le64_to_cpu(mst->total_dirty));
-		printk(KERN_DEBUG "\ttotal_used     %llu\n",
+		printk(KERN_ERR "\ttotal_used     %llu\n",
 		       (unsigned long long)le64_to_cpu(mst->total_used));
-		printk(KERN_DEBUG "\ttotal_dead     %llu\n",
+		printk(KERN_ERR "\ttotal_dead     %llu\n",
 		       (unsigned long long)le64_to_cpu(mst->total_dead));
-		printk(KERN_DEBUG "\ttotal_dark     %llu\n",
+		printk(KERN_ERR "\ttotal_dark     %llu\n",
 		       (unsigned long long)le64_to_cpu(mst->total_dark));
 		break;
 	}
@@ -448,11 +448,11 @@
 	{
 		const struct ubifs_ref_node *ref = node;
 
-		printk(KERN_DEBUG "\tlnum           %u\n",
+		printk(KERN_ERR "\tlnum           %u\n",
 		       le32_to_cpu(ref->lnum));
-		printk(KERN_DEBUG "\toffs           %u\n",
+		printk(KERN_ERR "\toffs           %u\n",
 		       le32_to_cpu(ref->offs));
-		printk(KERN_DEBUG "\tjhead          %u\n",
+		printk(KERN_ERR "\tjhead          %u\n",
 		       le32_to_cpu(ref->jhead));
 		break;
 	}
@@ -461,40 +461,40 @@
 		const struct ubifs_ino_node *ino = node;
 
 		key_read(c, &ino->key, &key);
-		printk(KERN_DEBUG "\tkey            %s\n",
+		printk(KERN_ERR "\tkey            %s\n",
 		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
-		printk(KERN_DEBUG "\tcreat_sqnum    %llu\n",
+		printk(KERN_ERR "\tcreat_sqnum    %llu\n",
 		       (unsigned long long)le64_to_cpu(ino->creat_sqnum));
-		printk(KERN_DEBUG "\tsize           %llu\n",
+		printk(KERN_ERR "\tsize           %llu\n",
 		       (unsigned long long)le64_to_cpu(ino->size));
-		printk(KERN_DEBUG "\tnlink          %u\n",
+		printk(KERN_ERR "\tnlink          %u\n",
 		       le32_to_cpu(ino->nlink));
-		printk(KERN_DEBUG "\tatime          %lld.%u\n",
+		printk(KERN_ERR "\tatime          %lld.%u\n",
 		       (long long)le64_to_cpu(ino->atime_sec),
 		       le32_to_cpu(ino->atime_nsec));
-		printk(KERN_DEBUG "\tmtime          %lld.%u\n",
+		printk(KERN_ERR "\tmtime          %lld.%u\n",
 		       (long long)le64_to_cpu(ino->mtime_sec),
 		       le32_to_cpu(ino->mtime_nsec));
-		printk(KERN_DEBUG "\tctime          %lld.%u\n",
+		printk(KERN_ERR "\tctime          %lld.%u\n",
 		       (long long)le64_to_cpu(ino->ctime_sec),
 		       le32_to_cpu(ino->ctime_nsec));
-		printk(KERN_DEBUG "\tuid            %u\n",
+		printk(KERN_ERR "\tuid            %u\n",
 		       le32_to_cpu(ino->uid));
-		printk(KERN_DEBUG "\tgid            %u\n",
+		printk(KERN_ERR "\tgid            %u\n",
 		       le32_to_cpu(ino->gid));
-		printk(KERN_DEBUG "\tmode           %u\n",
+		printk(KERN_ERR "\tmode           %u\n",
 		       le32_to_cpu(ino->mode));
-		printk(KERN_DEBUG "\tflags          %#x\n",
+		printk(KERN_ERR "\tflags          %#x\n",
 		       le32_to_cpu(ino->flags));
-		printk(KERN_DEBUG "\txattr_cnt      %u\n",
+		printk(KERN_ERR "\txattr_cnt      %u\n",
 		       le32_to_cpu(ino->xattr_cnt));
-		printk(KERN_DEBUG "\txattr_size     %u\n",
+		printk(KERN_ERR "\txattr_size     %u\n",
 		       le32_to_cpu(ino->xattr_size));
-		printk(KERN_DEBUG "\txattr_names    %u\n",
+		printk(KERN_ERR "\txattr_names    %u\n",
 		       le32_to_cpu(ino->xattr_names));
-		printk(KERN_DEBUG "\tcompr_type     %#x\n",
+		printk(KERN_ERR "\tcompr_type     %#x\n",
 		       (int)le16_to_cpu(ino->compr_type));
-		printk(KERN_DEBUG "\tdata len       %u\n",
+		printk(KERN_ERR "\tdata len       %u\n",
 		       le32_to_cpu(ino->data_len));
 		break;
 	}
@@ -505,16 +505,16 @@
 		int nlen = le16_to_cpu(dent->nlen);
 
 		key_read(c, &dent->key, &key);
-		printk(KERN_DEBUG "\tkey            %s\n",
+		printk(KERN_ERR "\tkey            %s\n",
 		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
-		printk(KERN_DEBUG "\tinum           %llu\n",
+		printk(KERN_ERR "\tinum           %llu\n",
 		       (unsigned long long)le64_to_cpu(dent->inum));
-		printk(KERN_DEBUG "\ttype           %d\n", (int)dent->type);
-		printk(KERN_DEBUG "\tnlen           %d\n", nlen);
-		printk(KERN_DEBUG "\tname           ");
+		printk(KERN_ERR "\ttype           %d\n", (int)dent->type);
+		printk(KERN_ERR "\tnlen           %d\n", nlen);
+		printk(KERN_ERR "\tname           ");
 
 		if (nlen > UBIFS_MAX_NLEN)
-			printk(KERN_DEBUG "(bad name length, not printing, "
+			printk(KERN_ERR "(bad name length, not printing, "
 					  "bad or corrupted node)");
 		else {
 			for (i = 0; i < nlen && dent->name[i]; i++)
@@ -530,16 +530,16 @@
 		int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ;
 
 		key_read(c, &dn->key, &key);
-		printk(KERN_DEBUG "\tkey            %s\n",
+		printk(KERN_ERR "\tkey            %s\n",
 		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
-		printk(KERN_DEBUG "\tsize           %u\n",
+		printk(KERN_ERR "\tsize           %u\n",
 		       le32_to_cpu(dn->size));
-		printk(KERN_DEBUG "\tcompr_typ      %d\n",
+		printk(KERN_ERR "\tcompr_typ      %d\n",
 		       (int)le16_to_cpu(dn->compr_type));
-		printk(KERN_DEBUG "\tdata size      %d\n",
+		printk(KERN_ERR "\tdata size      %d\n",
 		       dlen);
-		printk(KERN_DEBUG "\tdata:\n");
-		print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_OFFSET, 32, 1,
+		printk(KERN_ERR "\tdata:\n");
+		print_hex_dump(KERN_ERR, "\t", DUMP_PREFIX_OFFSET, 32, 1,
 			       (void *)&dn->data, dlen, 0);
 		break;
 	}
@@ -547,11 +547,11 @@
 	{
 		const struct ubifs_trun_node *trun = node;
 
-		printk(KERN_DEBUG "\tinum           %u\n",
+		printk(KERN_ERR "\tinum           %u\n",
 		       le32_to_cpu(trun->inum));
-		printk(KERN_DEBUG "\told_size       %llu\n",
+		printk(KERN_ERR "\told_size       %llu\n",
 		       (unsigned long long)le64_to_cpu(trun->old_size));
-		printk(KERN_DEBUG "\tnew_size       %llu\n",
+		printk(KERN_ERR "\tnew_size       %llu\n",
 		       (unsigned long long)le64_to_cpu(trun->new_size));
 		break;
 	}
@@ -560,17 +560,17 @@
 		const struct ubifs_idx_node *idx = node;
 
 		n = le16_to_cpu(idx->child_cnt);
-		printk(KERN_DEBUG "\tchild_cnt      %d\n", n);
-		printk(KERN_DEBUG "\tlevel          %d\n",
+		printk(KERN_ERR "\tchild_cnt      %d\n", n);
+		printk(KERN_ERR "\tlevel          %d\n",
 		       (int)le16_to_cpu(idx->level));
-		printk(KERN_DEBUG "\tBranches:\n");
+		printk(KERN_ERR "\tBranches:\n");
 
 		for (i = 0; i < n && i < c->fanout - 1; i++) {
 			const struct ubifs_branch *br;
 
 			br = ubifs_idx_branch(c, idx, i);
 			key_read(c, &br->key, &key);
-			printk(KERN_DEBUG "\t%d: LEB %d:%d len %d key %s\n",
+			printk(KERN_ERR "\t%d: LEB %d:%d len %d key %s\n",
 			       i, le32_to_cpu(br->lnum), le32_to_cpu(br->offs),
 			       le32_to_cpu(br->len),
 			       dbg_snprintf_key(c, &key, key_buf,
@@ -584,20 +584,20 @@
 	{
 		const struct ubifs_orph_node *orph = node;
 
-		printk(KERN_DEBUG "\tcommit number  %llu\n",
+		printk(KERN_ERR "\tcommit number  %llu\n",
 		       (unsigned long long)
 				le64_to_cpu(orph->cmt_no) & LLONG_MAX);
-		printk(KERN_DEBUG "\tlast node flag %llu\n",
+		printk(KERN_ERR "\tlast node flag %llu\n",
 		       (unsigned long long)(le64_to_cpu(orph->cmt_no)) >> 63);
 		n = (le32_to_cpu(ch->len) - UBIFS_ORPH_NODE_SZ) >> 3;
-		printk(KERN_DEBUG "\t%d orphan inode numbers:\n", n);
+		printk(KERN_ERR "\t%d orphan inode numbers:\n", n);
 		for (i = 0; i < n; i++)
-			printk(KERN_DEBUG "\t  ino %llu\n",
+			printk(KERN_ERR "\t  ino %llu\n",
 			       (unsigned long long)le64_to_cpu(orph->inos[i]));
 		break;
 	}
 	default:
-		printk(KERN_DEBUG "node type %d was not recognized\n",
+		printk(KERN_ERR "node type %d was not recognized\n",
 		       (int)ch->node_type);
 	}
 	spin_unlock(&dbg_lock);
@@ -606,16 +606,16 @@
 void dbg_dump_budget_req(const struct ubifs_budget_req *req)
 {
 	spin_lock(&dbg_lock);
-	printk(KERN_DEBUG "Budgeting request: new_ino %d, dirtied_ino %d\n",
+	printk(KERN_ERR "Budgeting request: new_ino %d, dirtied_ino %d\n",
 	       req->new_ino, req->dirtied_ino);
-	printk(KERN_DEBUG "\tnew_ino_d   %d, dirtied_ino_d %d\n",
+	printk(KERN_ERR "\tnew_ino_d   %d, dirtied_ino_d %d\n",
 	       req->new_ino_d, req->dirtied_ino_d);
-	printk(KERN_DEBUG "\tnew_page    %d, dirtied_page %d\n",
+	printk(KERN_ERR "\tnew_page    %d, dirtied_page %d\n",
 	       req->new_page, req->dirtied_page);
-	printk(KERN_DEBUG "\tnew_dent    %d, mod_dent     %d\n",
+	printk(KERN_ERR "\tnew_dent    %d, mod_dent     %d\n",
 	       req->new_dent, req->mod_dent);
-	printk(KERN_DEBUG "\tidx_growth  %d\n", req->idx_growth);
-	printk(KERN_DEBUG "\tdata_growth %d dd_growth     %d\n",
+	printk(KERN_ERR "\tidx_growth  %d\n", req->idx_growth);
+	printk(KERN_ERR "\tdata_growth %d dd_growth     %d\n",
 	       req->data_growth, req->dd_growth);
 	spin_unlock(&dbg_lock);
 }
@@ -623,12 +623,12 @@
 void dbg_dump_lstats(const struct ubifs_lp_stats *lst)
 {
 	spin_lock(&dbg_lock);
-	printk(KERN_DEBUG "(pid %d) Lprops statistics: empty_lebs %d, "
+	printk(KERN_ERR "(pid %d) Lprops statistics: empty_lebs %d, "
 	       "idx_lebs  %d\n", current->pid, lst->empty_lebs, lst->idx_lebs);
-	printk(KERN_DEBUG "\ttaken_empty_lebs %d, total_free %lld, "
+	printk(KERN_ERR "\ttaken_empty_lebs %d, total_free %lld, "
 	       "total_dirty %lld\n", lst->taken_empty_lebs, lst->total_free,
 	       lst->total_dirty);
-	printk(KERN_DEBUG "\ttotal_used %lld, total_dark %lld, "
+	printk(KERN_ERR "\ttotal_used %lld, total_dark %lld, "
 	       "total_dead %lld\n", lst->total_used, lst->total_dark,
 	       lst->total_dead);
 	spin_unlock(&dbg_lock);
@@ -644,21 +644,21 @@
 
 	spin_lock(&c->space_lock);
 	spin_lock(&dbg_lock);
-	printk(KERN_DEBUG "(pid %d) Budgeting info: data budget sum %lld, "
+	printk(KERN_ERR "(pid %d) Budgeting info: data budget sum %lld, "
 	       "total budget sum %lld\n", current->pid,
 	       bi->data_growth + bi->dd_growth,
 	       bi->data_growth + bi->dd_growth + bi->idx_growth);
-	printk(KERN_DEBUG "\tbudg_data_growth %lld, budg_dd_growth %lld, "
+	printk(KERN_ERR "\tbudg_data_growth %lld, budg_dd_growth %lld, "
 	       "budg_idx_growth %lld\n", bi->data_growth, bi->dd_growth,
 	       bi->idx_growth);
-	printk(KERN_DEBUG "\tmin_idx_lebs %d, old_idx_sz %llu, "
+	printk(KERN_ERR "\tmin_idx_lebs %d, old_idx_sz %llu, "
 	       "uncommitted_idx %lld\n", bi->min_idx_lebs, bi->old_idx_sz,
 	       bi->uncommitted_idx);
-	printk(KERN_DEBUG "\tpage_budget %d, inode_budget %d, dent_budget %d\n",
+	printk(KERN_ERR "\tpage_budget %d, inode_budget %d, dent_budget %d\n",
 	       bi->page_budget, bi->inode_budget, bi->dent_budget);
-	printk(KERN_DEBUG "\tnospace %u, nospace_rp %u\n",
+	printk(KERN_ERR "\tnospace %u, nospace_rp %u\n",
 	       bi->nospace, bi->nospace_rp);
-	printk(KERN_DEBUG "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
+	printk(KERN_ERR "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
 	       c->dark_wm, c->dead_wm, c->max_idx_node_sz);
 
 	if (bi != &c->bi)
@@ -669,38 +669,38 @@
 		 */
 		goto out_unlock;
 
-	printk(KERN_DEBUG "\tfreeable_cnt %d, calc_idx_sz %lld, idx_gc_cnt %d\n",
+	printk(KERN_ERR "\tfreeable_cnt %d, calc_idx_sz %lld, idx_gc_cnt %d\n",
 	       c->freeable_cnt, c->calc_idx_sz, c->idx_gc_cnt);
-	printk(KERN_DEBUG "\tdirty_pg_cnt %ld, dirty_zn_cnt %ld, "
+	printk(KERN_ERR "\tdirty_pg_cnt %ld, dirty_zn_cnt %ld, "
 	       "clean_zn_cnt %ld\n", atomic_long_read(&c->dirty_pg_cnt),
 	       atomic_long_read(&c->dirty_zn_cnt),
 	       atomic_long_read(&c->clean_zn_cnt));
-	printk(KERN_DEBUG "\tgc_lnum %d, ihead_lnum %d\n",
+	printk(KERN_ERR "\tgc_lnum %d, ihead_lnum %d\n",
 	       c->gc_lnum, c->ihead_lnum);
 
 	/* If we are in R/O mode, journal heads do not exist */
 	if (c->jheads)
 		for (i = 0; i < c->jhead_cnt; i++)
-			printk(KERN_DEBUG "\tjhead %s\t LEB %d\n",
+			printk(KERN_ERR "\tjhead %s\t LEB %d\n",
 			       dbg_jhead(c->jheads[i].wbuf.jhead),
 			       c->jheads[i].wbuf.lnum);
 	for (rb = rb_first(&c->buds); rb; rb = rb_next(rb)) {
 		bud = rb_entry(rb, struct ubifs_bud, rb);
-		printk(KERN_DEBUG "\tbud LEB %d\n", bud->lnum);
+		printk(KERN_ERR "\tbud LEB %d\n", bud->lnum);
 	}
 	list_for_each_entry(bud, &c->old_buds, list)
-		printk(KERN_DEBUG "\told bud LEB %d\n", bud->lnum);
+		printk(KERN_ERR "\told bud LEB %d\n", bud->lnum);
 	list_for_each_entry(idx_gc, &c->idx_gc, list)
-		printk(KERN_DEBUG "\tGC'ed idx LEB %d unmap %d\n",
+		printk(KERN_ERR "\tGC'ed idx LEB %d unmap %d\n",
 		       idx_gc->lnum, idx_gc->unmap);
-	printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state);
+	printk(KERN_ERR "\tcommit state %d\n", c->cmt_state);
 
 	/* Print budgeting predictions */
 	available = ubifs_calc_available(c, c->bi.min_idx_lebs);
 	outstanding = c->bi.data_growth + c->bi.dd_growth;
 	free = ubifs_get_free_space_nolock(c);
-	printk(KERN_DEBUG "Budgeting predictions:\n");
-	printk(KERN_DEBUG "\tavailable: %lld, outstanding %lld, free %lld\n",
+	printk(KERN_ERR "Budgeting predictions:\n");
+	printk(KERN_ERR "\tavailable: %lld, outstanding %lld, free %lld\n",
 	       available, outstanding, free);
 out_unlock:
 	spin_unlock(&dbg_lock);
@@ -720,11 +720,11 @@
 		dark = ubifs_calc_dark(c, spc);
 
 	if (lp->flags & LPROPS_INDEX)
-		printk(KERN_DEBUG "LEB %-7d free %-8d dirty %-8d used %-8d "
+		printk(KERN_ERR "LEB %-7d free %-8d dirty %-8d used %-8d "
 		       "free + dirty %-8d flags %#x (", lp->lnum, lp->free,
 		       lp->dirty, c->leb_size - spc, spc, lp->flags);
 	else
-		printk(KERN_DEBUG "LEB %-7d free %-8d dirty %-8d used %-8d "
+		printk(KERN_ERR "LEB %-7d free %-8d dirty %-8d used %-8d "
 		       "free + dirty %-8d dark %-4d dead %-4d nodes fit %-3d "
 		       "flags %#-4x (", lp->lnum, lp->free, lp->dirty,
 		       c->leb_size - spc, spc, dark, dead,
@@ -807,7 +807,7 @@
 	struct ubifs_lprops lp;
 	struct ubifs_lp_stats lst;
 
-	printk(KERN_DEBUG "(pid %d) start dumping LEB properties\n",
+	printk(KERN_ERR "(pid %d) start dumping LEB properties\n",
 	       current->pid);
 	ubifs_get_lp_stats(c, &lst);
 	dbg_dump_lstats(&lst);
@@ -819,7 +819,7 @@
 
 		dbg_dump_lprop(c, &lp);
 	}
-	printk(KERN_DEBUG "(pid %d) finish dumping LEB properties\n",
+	printk(KERN_ERR "(pid %d) finish dumping LEB properties\n",
 	       current->pid);
 }
 
@@ -828,35 +828,35 @@
 	int i;
 
 	spin_lock(&dbg_lock);
-	printk(KERN_DEBUG "(pid %d) dumping LPT information\n", current->pid);
-	printk(KERN_DEBUG "\tlpt_sz:        %lld\n", c->lpt_sz);
-	printk(KERN_DEBUG "\tpnode_sz:      %d\n", c->pnode_sz);
-	printk(KERN_DEBUG "\tnnode_sz:      %d\n", c->nnode_sz);
-	printk(KERN_DEBUG "\tltab_sz:       %d\n", c->ltab_sz);
-	printk(KERN_DEBUG "\tlsave_sz:      %d\n", c->lsave_sz);
-	printk(KERN_DEBUG "\tbig_lpt:       %d\n", c->big_lpt);
-	printk(KERN_DEBUG "\tlpt_hght:      %d\n", c->lpt_hght);
-	printk(KERN_DEBUG "\tpnode_cnt:     %d\n", c->pnode_cnt);
-	printk(KERN_DEBUG "\tnnode_cnt:     %d\n", c->nnode_cnt);
-	printk(KERN_DEBUG "\tdirty_pn_cnt:  %d\n", c->dirty_pn_cnt);
-	printk(KERN_DEBUG "\tdirty_nn_cnt:  %d\n", c->dirty_nn_cnt);
-	printk(KERN_DEBUG "\tlsave_cnt:     %d\n", c->lsave_cnt);
-	printk(KERN_DEBUG "\tspace_bits:    %d\n", c->space_bits);
-	printk(KERN_DEBUG "\tlpt_lnum_bits: %d\n", c->lpt_lnum_bits);
-	printk(KERN_DEBUG "\tlpt_offs_bits: %d\n", c->lpt_offs_bits);
-	printk(KERN_DEBUG "\tlpt_spc_bits:  %d\n", c->lpt_spc_bits);
-	printk(KERN_DEBUG "\tpcnt_bits:     %d\n", c->pcnt_bits);
-	printk(KERN_DEBUG "\tlnum_bits:     %d\n", c->lnum_bits);
-	printk(KERN_DEBUG "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs);
-	printk(KERN_DEBUG "\tLPT head is at %d:%d\n",
+	printk(KERN_ERR "(pid %d) dumping LPT information\n", current->pid);
+	printk(KERN_ERR "\tlpt_sz:        %lld\n", c->lpt_sz);
+	printk(KERN_ERR "\tpnode_sz:      %d\n", c->pnode_sz);
+	printk(KERN_ERR "\tnnode_sz:      %d\n", c->nnode_sz);
+	printk(KERN_ERR "\tltab_sz:       %d\n", c->ltab_sz);
+	printk(KERN_ERR "\tlsave_sz:      %d\n", c->lsave_sz);
+	printk(KERN_ERR "\tbig_lpt:       %d\n", c->big_lpt);
+	printk(KERN_ERR "\tlpt_hght:      %d\n", c->lpt_hght);
+	printk(KERN_ERR "\tpnode_cnt:     %d\n", c->pnode_cnt);
+	printk(KERN_ERR "\tnnode_cnt:     %d\n", c->nnode_cnt);
+	printk(KERN_ERR "\tdirty_pn_cnt:  %d\n", c->dirty_pn_cnt);
+	printk(KERN_ERR "\tdirty_nn_cnt:  %d\n", c->dirty_nn_cnt);
+	printk(KERN_ERR "\tlsave_cnt:     %d\n", c->lsave_cnt);
+	printk(KERN_ERR "\tspace_bits:    %d\n", c->space_bits);
+	printk(KERN_ERR "\tlpt_lnum_bits: %d\n", c->lpt_lnum_bits);
+	printk(KERN_ERR "\tlpt_offs_bits: %d\n", c->lpt_offs_bits);
+	printk(KERN_ERR "\tlpt_spc_bits:  %d\n", c->lpt_spc_bits);
+	printk(KERN_ERR "\tpcnt_bits:     %d\n", c->pcnt_bits);
+	printk(KERN_ERR "\tlnum_bits:     %d\n", c->lnum_bits);
+	printk(KERN_ERR "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs);
+	printk(KERN_ERR "\tLPT head is at %d:%d\n",
 	       c->nhead_lnum, c->nhead_offs);
-	printk(KERN_DEBUG "\tLPT ltab is at %d:%d\n",
+	printk(KERN_ERR "\tLPT ltab is at %d:%d\n",
 	       c->ltab_lnum, c->ltab_offs);
 	if (c->big_lpt)
-		printk(KERN_DEBUG "\tLPT lsave is at %d:%d\n",
+		printk(KERN_ERR "\tLPT lsave is at %d:%d\n",
 		       c->lsave_lnum, c->lsave_offs);
 	for (i = 0; i < c->lpt_lebs; i++)
-		printk(KERN_DEBUG "\tLPT LEB %d free %d dirty %d tgc %d "
+		printk(KERN_ERR "\tLPT LEB %d free %d dirty %d tgc %d "
 		       "cmt %d\n", i + c->lpt_first, c->ltab[i].free,
 		       c->ltab[i].dirty, c->ltab[i].tgc, c->ltab[i].cmt);
 	spin_unlock(&dbg_lock);
@@ -867,12 +867,12 @@
 {
 	struct ubifs_scan_node *snod;
 
-	printk(KERN_DEBUG "(pid %d) start dumping scanned data from LEB %d:%d\n",
+	printk(KERN_ERR "(pid %d) start dumping scanned data from LEB %d:%d\n",
 	       current->pid, sleb->lnum, offs);
 
 	list_for_each_entry(snod, &sleb->nodes, list) {
 		cond_resched();
-		printk(KERN_DEBUG "Dumping node at LEB %d:%d len %d\n", sleb->lnum,
+		printk(KERN_ERR "Dumping node at LEB %d:%d len %d\n", sleb->lnum,
 		       snod->offs, snod->len);
 		dbg_dump_node(c, snod->node);
 	}
@@ -887,7 +887,7 @@
 	if (dbg_is_tst_rcvry(c))
 		return;
 
-	printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
+	printk(KERN_ERR "(pid %d) start dumping LEB %d\n",
 	       current->pid, lnum);
 
 	buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
@@ -902,17 +902,17 @@
 		goto out;
 	}
 
-	printk(KERN_DEBUG "LEB %d has %d nodes ending at %d\n", lnum,
+	printk(KERN_ERR "LEB %d has %d nodes ending at %d\n", lnum,
 	       sleb->nodes_cnt, sleb->endpt);
 
 	list_for_each_entry(snod, &sleb->nodes, list) {
 		cond_resched();
-		printk(KERN_DEBUG "Dumping node at LEB %d:%d len %d\n", lnum,
+		printk(KERN_ERR "Dumping node at LEB %d:%d len %d\n", lnum,
 		       snod->offs, snod->len);
 		dbg_dump_node(c, snod->node);
 	}
 
-	printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n",
+	printk(KERN_ERR "(pid %d) finish dumping LEB %d\n",
 	       current->pid, lnum);
 	ubifs_scan_destroy(sleb);
 
@@ -934,7 +934,7 @@
 	else
 		zbr = &c->zroot;
 
-	printk(KERN_DEBUG "znode %p, LEB %d:%d len %d parent %p iip %d level %d"
+	printk(KERN_ERR "znode %p, LEB %d:%d len %d parent %p iip %d level %d"
 	       " child_cnt %d flags %lx\n", znode, zbr->lnum, zbr->offs,
 	       zbr->len, znode->parent, znode->iip, znode->level,
 	       znode->child_cnt, znode->flags);
@@ -944,18 +944,18 @@
 		return;
 	}
 
-	printk(KERN_DEBUG "zbranches:\n");
+	printk(KERN_ERR "zbranches:\n");
 	for (n = 0; n < znode->child_cnt; n++) {
 		zbr = &znode->zbranch[n];
 		if (znode->level > 0)
-			printk(KERN_DEBUG "\t%d: znode %p LEB %d:%d len %d key "
+			printk(KERN_ERR "\t%d: znode %p LEB %d:%d len %d key "
 					  "%s\n", n, zbr->znode, zbr->lnum,
 					  zbr->offs, zbr->len,
 					  dbg_snprintf_key(c, &zbr->key,
 							   key_buf,
 							   DBG_KEY_BUF_LEN));
 		else
-			printk(KERN_DEBUG "\t%d: LNC %p LEB %d:%d len %d key "
+			printk(KERN_ERR "\t%d: LNC %p LEB %d:%d len %d key "
 					  "%s\n", n, zbr->znode, zbr->lnum,
 					  zbr->offs, zbr->len,
 					  dbg_snprintf_key(c, &zbr->key,
@@ -969,16 +969,16 @@
 {
 	int i;
 
-	printk(KERN_DEBUG "(pid %d) start dumping heap cat %d (%d elements)\n",
+	printk(KERN_ERR "(pid %d) start dumping heap cat %d (%d elements)\n",
 	       current->pid, cat, heap->cnt);
 	for (i = 0; i < heap->cnt; i++) {
 		struct ubifs_lprops *lprops = heap->arr[i];
 
-		printk(KERN_DEBUG "\t%d. LEB %d hpos %d free %d dirty %d "
+		printk(KERN_ERR "\t%d. LEB %d hpos %d free %d dirty %d "
 		       "flags %d\n", i, lprops->lnum, lprops->hpos,
 		       lprops->free, lprops->dirty, lprops->flags);
 	}
-	printk(KERN_DEBUG "(pid %d) finish dumping heap\n", current->pid);
+	printk(KERN_ERR "(pid %d) finish dumping heap\n", current->pid);
 }
 
 void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
@@ -986,15 +986,15 @@
 {
 	int i;
 
-	printk(KERN_DEBUG "(pid %d) dumping pnode:\n", current->pid);
-	printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n",
+	printk(KERN_ERR "(pid %d) dumping pnode:\n", current->pid);
+	printk(KERN_ERR "\taddress %zx parent %zx cnext %zx\n",
 	       (size_t)pnode, (size_t)parent, (size_t)pnode->cnext);
-	printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n",
+	printk(KERN_ERR "\tflags %lu iip %d level %d num %d\n",
 	       pnode->flags, iip, pnode->level, pnode->num);
 	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
 		struct ubifs_lprops *lp = &pnode->lprops[i];
 
-		printk(KERN_DEBUG "\t%d: free %d dirty %d flags %d lnum %d\n",
+		printk(KERN_ERR "\t%d: free %d dirty %d flags %d lnum %d\n",
 		       i, lp->free, lp->dirty, lp->flags, lp->lnum);
 	}
 }
@@ -1004,20 +1004,20 @@
 	struct ubifs_znode *znode;
 	int level;
 
-	printk(KERN_DEBUG "\n");
-	printk(KERN_DEBUG "(pid %d) start dumping TNC tree\n", current->pid);
+	printk(KERN_ERR "\n");
+	printk(KERN_ERR "(pid %d) start dumping TNC tree\n", current->pid);
 	znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL);
 	level = znode->level;
-	printk(KERN_DEBUG "== Level %d ==\n", level);
+	printk(KERN_ERR "== Level %d ==\n", level);
 	while (znode) {
 		if (level != znode->level) {
 			level = znode->level;
-			printk(KERN_DEBUG "== Level %d ==\n", level);
+			printk(KERN_ERR "== Level %d ==\n", level);
 		}
 		dbg_dump_znode(c, znode);
 		znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode);
 	}
-	printk(KERN_DEBUG "(pid %d) finish dumping TNC tree\n", current->pid);
+	printk(KERN_ERR "(pid %d) finish dumping TNC tree\n", current->pid);
 }
 
 static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode,
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
index ad1a6fe..9f71765 100644
--- a/fs/ubifs/debug.h
+++ b/fs/ubifs/debug.h
@@ -164,9 +164,7 @@
 #define dbg_dump_stack() dump_stack()
 
 #define dbg_err(fmt, ...) do {                                                 \
-	spin_lock(&dbg_lock);                                                  \
 	ubifs_err(fmt, ##__VA_ARGS__);                                         \
-	spin_unlock(&dbg_lock);                                                \
 } while (0)
 
 #define ubifs_dbg_msg(type, fmt, ...) \
@@ -217,7 +215,6 @@
 /* Additional recovery messages */
 #define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__)
 
-extern spinlock_t dbg_lock;
 extern struct ubifs_global_debug_info ubifs_dbg;
 
 static inline int dbg_is_chk_gen(const struct ubifs_info *c)
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index d6fe1c7..ec9f187 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -566,6 +566,7 @@
 	int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
 	int err, budgeted = 1;
 	struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
+	unsigned int saved_nlink = inode->i_nlink;
 
 	/*
 	 * Budget request settings: deletion direntry, deletion inode (+1 for
@@ -613,7 +614,7 @@
 out_cancel:
 	dir->i_size += sz_change;
 	dir_ui->ui_size = dir->i_size;
-	inc_nlink(inode);
+	set_nlink(inode, saved_nlink);
 	unlock_2_inodes(dir, inode);
 	if (budgeted)
 		ubifs_release_budget(c, &req);
@@ -704,8 +705,7 @@
 	dir->i_size += sz_change;
 	dir_ui->ui_size = dir->i_size;
 	inc_nlink(dir);
-	inc_nlink(inode);
-	inc_nlink(inode);
+	set_nlink(inode, 2);
 	unlock_2_inodes(dir, inode);
 	if (budgeted)
 		ubifs_release_budget(c, &req);
@@ -977,6 +977,7 @@
 	struct ubifs_budget_req ino_req = { .dirtied_ino = 1,
 			.dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
 	struct timespec time;
+	unsigned int saved_nlink;
 
 	/*
 	 * Budget request settings: deletion direntry, new direntry, removing
@@ -1059,13 +1060,14 @@
 	if (unlink) {
 		/*
 		 * Directories cannot have hard-links, so if this is a
-		 * directory, decrement its @i_nlink twice because an empty
-		 * directory has @i_nlink 2.
+		 * directory, just clear @i_nlink.
 		 */
+		saved_nlink = new_inode->i_nlink;
 		if (is_dir)
+			clear_nlink(new_inode);
+		else
 			drop_nlink(new_inode);
 		new_inode->i_ctime = time;
-		drop_nlink(new_inode);
 	} else {
 		new_dir->i_size += new_sz;
 		ubifs_inode(new_dir)->ui_size = new_dir->i_size;
@@ -1102,9 +1104,7 @@
 
 out_cancel:
 	if (unlink) {
-		if (is_dir)
-			inc_nlink(new_inode);
-		inc_nlink(new_inode);
+		set_nlink(new_inode, saved_nlink);
 	} else {
 		new_dir->i_size -= new_sz;
 		ubifs_inode(new_dir)->ui_size = new_dir->i_size;
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index ee4f43f..2a935b3 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -679,7 +679,8 @@
 			   ret == SCANNED_GARBAGE     ||
 			   ret == SCANNED_A_BAD_PAD_NODE ||
 			   ret == SCANNED_A_CORRUPT_NODE) {
-			dbg_rcvry("found corruption - %d", ret);
+			dbg_rcvry("found corruption (%d) at %d:%d",
+				  ret, lnum, offs);
 			break;
 		} else {
 			dbg_err("unexpected return value %d", ret);
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index 6094c5a..771f7fb 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -410,13 +410,23 @@
 	}
 
 	if (c->main_lebs < UBIFS_MIN_MAIN_LEBS) {
-		err = 7;
+		ubifs_err("too few main LEBs count %d, must be at least %d",
+			  c->main_lebs, UBIFS_MIN_MAIN_LEBS);
 		goto failed;
 	}
 
-	if (c->max_bud_bytes < (long long)c->leb_size * UBIFS_MIN_BUD_LEBS ||
-	    c->max_bud_bytes > (long long)c->leb_size * c->main_lebs) {
-		err = 8;
+	max_bytes = (long long)c->leb_size * UBIFS_MIN_BUD_LEBS;
+	if (c->max_bud_bytes < max_bytes) {
+		ubifs_err("too small journal (%lld bytes), must be at least "
+			  "%lld bytes",  c->max_bud_bytes, max_bytes);
+		goto failed;
+	}
+
+	max_bytes = (long long)c->leb_size * c->main_lebs;
+	if (c->max_bud_bytes > max_bytes) {
+		ubifs_err("too large journal size (%lld bytes), only %lld bytes"
+			  "available in the main area",
+			  c->max_bud_bytes, max_bytes);
 		goto failed;
 	}
 
@@ -450,7 +460,6 @@
 		goto failed;
 	}
 
-	max_bytes = c->main_lebs * (long long)c->leb_size;
 	if (c->rp_size < 0 || max_bytes < c->rp_size) {
 		err = 14;
 		goto failed;
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 63765d5..76e4e05 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -2076,15 +2076,13 @@
 		goto out_umount;
 	}
 
-	sb->s_root = d_alloc_root(root);
+	sb->s_root = d_make_root(root);
 	if (!sb->s_root)
-		goto out_iput;
+		goto out_umount;
 
 	mutex_unlock(&c->umount_mutex);
 	return 0;
 
-out_iput:
-	iput(root);
 out_umount:
 	ubifs_umount(c);
 out_unlock:
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 12e9477..93d59ac 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -84,9 +84,6 @@
 #define INUM_WARN_WATERMARK 0xFFF00000
 #define INUM_WATERMARK      0xFFFFFF00
 
-/* Largest key size supported in this implementation */
-#define CUR_MAX_KEY_LEN UBIFS_SK_LEN
-
 /* Maximum number of entries in each LPT (LEB category) heap */
 #define LPT_HEAP_SZ 256
 
@@ -277,10 +274,10 @@
 
 /* The below union makes it easier to deal with keys */
 union ubifs_key {
-	uint8_t u8[CUR_MAX_KEY_LEN];
-	uint32_t u32[CUR_MAX_KEY_LEN/4];
-	uint64_t u64[CUR_MAX_KEY_LEN/8];
-	__le32 j32[CUR_MAX_KEY_LEN/4];
+	uint8_t u8[UBIFS_SK_LEN];
+	uint32_t u32[UBIFS_SK_LEN/4];
+	uint64_t u64[UBIFS_SK_LEN/8];
+	__le32 j32[UBIFS_SK_LEN/4];
 };
 
 /**
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
index 987585b..1ba2baa 100644
--- a/fs/udf/balloc.c
+++ b/fs/udf/balloc.c
@@ -105,7 +105,6 @@
 }
 
 static void udf_bitmap_free_blocks(struct super_block *sb,
-				   struct inode *inode,
 				   struct udf_bitmap *bitmap,
 				   struct kernel_lb_addr *bloc,
 				   uint32_t offset,
@@ -172,7 +171,6 @@
 }
 
 static int udf_bitmap_prealloc_blocks(struct super_block *sb,
-				      struct inode *inode,
 				      struct udf_bitmap *bitmap,
 				      uint16_t partition, uint32_t first_block,
 				      uint32_t block_count)
@@ -223,7 +221,6 @@
 }
 
 static int udf_bitmap_new_block(struct super_block *sb,
-				struct inode *inode,
 				struct udf_bitmap *bitmap, uint16_t partition,
 				uint32_t goal, int *err)
 {
@@ -349,7 +346,6 @@
 }
 
 static void udf_table_free_blocks(struct super_block *sb,
-				  struct inode *inode,
 				  struct inode *table,
 				  struct kernel_lb_addr *bloc,
 				  uint32_t offset,
@@ -581,7 +577,6 @@
 }
 
 static int udf_table_prealloc_blocks(struct super_block *sb,
-				     struct inode *inode,
 				     struct inode *table, uint16_t partition,
 				     uint32_t first_block, uint32_t block_count)
 {
@@ -643,7 +638,6 @@
 }
 
 static int udf_table_new_block(struct super_block *sb,
-			       struct inode *inode,
 			       struct inode *table, uint16_t partition,
 			       uint32_t goal, int *err)
 {
@@ -743,18 +737,23 @@
 	struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
 
 	if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) {
-		udf_bitmap_free_blocks(sb, inode, map->s_uspace.s_bitmap,
+		udf_bitmap_free_blocks(sb, map->s_uspace.s_bitmap,
 				       bloc, offset, count);
 	} else if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) {
-		udf_table_free_blocks(sb, inode, map->s_uspace.s_table,
+		udf_table_free_blocks(sb, map->s_uspace.s_table,
 				      bloc, offset, count);
 	} else if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) {
-		udf_bitmap_free_blocks(sb, inode, map->s_fspace.s_bitmap,
+		udf_bitmap_free_blocks(sb, map->s_fspace.s_bitmap,
 				       bloc, offset, count);
 	} else if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) {
-		udf_table_free_blocks(sb, inode, map->s_fspace.s_table,
+		udf_table_free_blocks(sb, map->s_fspace.s_table,
 				      bloc, offset, count);
 	}
+
+	if (inode) {
+		inode_sub_bytes(inode,
+				((sector_t)count) << sb->s_blocksize_bits);
+	}
 }
 
 inline int udf_prealloc_blocks(struct super_block *sb,
@@ -763,29 +762,34 @@
 			       uint32_t block_count)
 {
 	struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
+	sector_t allocated;
 
 	if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
-		return udf_bitmap_prealloc_blocks(sb, inode,
-						  map->s_uspace.s_bitmap,
-						  partition, first_block,
-						  block_count);
+		allocated = udf_bitmap_prealloc_blocks(sb,
+						       map->s_uspace.s_bitmap,
+						       partition, first_block,
+						       block_count);
 	else if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
-		return udf_table_prealloc_blocks(sb, inode,
-						 map->s_uspace.s_table,
-						 partition, first_block,
-						 block_count);
+		allocated = udf_table_prealloc_blocks(sb,
+						      map->s_uspace.s_table,
+						      partition, first_block,
+						      block_count);
 	else if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
-		return udf_bitmap_prealloc_blocks(sb, inode,
-						  map->s_fspace.s_bitmap,
-						  partition, first_block,
-						  block_count);
+		allocated = udf_bitmap_prealloc_blocks(sb,
+						       map->s_fspace.s_bitmap,
+						       partition, first_block,
+						       block_count);
 	else if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE)
-		return udf_table_prealloc_blocks(sb, inode,
-						 map->s_fspace.s_table,
-						 partition, first_block,
-						 block_count);
+		allocated = udf_table_prealloc_blocks(sb,
+						      map->s_fspace.s_table,
+						      partition, first_block,
+						      block_count);
 	else
 		return 0;
+
+	if (inode && allocated > 0)
+		inode_add_bytes(inode, allocated << sb->s_blocksize_bits);
+	return allocated;
 }
 
 inline int udf_new_block(struct super_block *sb,
@@ -793,25 +797,29 @@
 			 uint16_t partition, uint32_t goal, int *err)
 {
 	struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
+	int block;
 
 	if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
-		return udf_bitmap_new_block(sb, inode,
-					   map->s_uspace.s_bitmap,
-					   partition, goal, err);
+		block = udf_bitmap_new_block(sb,
+					     map->s_uspace.s_bitmap,
+					     partition, goal, err);
 	else if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
-		return udf_table_new_block(sb, inode,
-					   map->s_uspace.s_table,
-					   partition, goal, err);
-	else if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
-		return udf_bitmap_new_block(sb, inode,
-					    map->s_fspace.s_bitmap,
+		block = udf_table_new_block(sb,
+					    map->s_uspace.s_table,
 					    partition, goal, err);
+	else if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
+		block = udf_bitmap_new_block(sb,
+					     map->s_fspace.s_bitmap,
+					     partition, goal, err);
 	else if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE)
-		return udf_table_new_block(sb, inode,
-					   map->s_fspace.s_table,
-					   partition, goal, err);
+		block = udf_table_new_block(sb,
+					    map->s_fspace.s_table,
+					    partition, goal, err);
 	else {
 		*err = -EIO;
 		return 0;
 	}
+	if (inode && block)
+		inode_add_bytes(inode, sb->s_blocksize);
+	return block;
 }
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
index 05ab481..7e5aae4 100644
--- a/fs/udf/ialloc.c
+++ b/fs/udf/ialloc.c
@@ -116,6 +116,7 @@
 	iinfo->i_lenEAttr = 0;
 	iinfo->i_lenAlloc = 0;
 	iinfo->i_use = 0;
+	iinfo->i_checkpoint = 1;
 	if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_AD_IN_ICB))
 		iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
 	else if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 7699df7..7d75280 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1358,6 +1358,7 @@
 		iinfo->i_unique = le64_to_cpu(fe->uniqueID);
 		iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr);
 		iinfo->i_lenAlloc = le32_to_cpu(fe->lengthAllocDescs);
+		iinfo->i_checkpoint = le32_to_cpu(fe->checkpoint);
 		offset = sizeof(struct fileEntry) + iinfo->i_lenEAttr;
 	} else {
 		inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
@@ -1379,6 +1380,7 @@
 		iinfo->i_unique = le64_to_cpu(efe->uniqueID);
 		iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr);
 		iinfo->i_lenAlloc = le32_to_cpu(efe->lengthAllocDescs);
+		iinfo->i_checkpoint = le32_to_cpu(efe->checkpoint);
 		offset = sizeof(struct extendedFileEntry) +
 							iinfo->i_lenEAttr;
 	}
@@ -1495,6 +1497,7 @@
 	struct buffer_head *bh = NULL;
 	struct fileEntry *fe;
 	struct extendedFileEntry *efe;
+	uint64_t lb_recorded;
 	uint32_t udfperms;
 	uint16_t icbflags;
 	uint16_t crclen;
@@ -1589,13 +1592,18 @@
 		dsea->minorDeviceIdent = cpu_to_le32(iminor(inode));
 	}
 
+	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+		lb_recorded = 0; /* No extents => no blocks! */
+	else
+		lb_recorded =
+			(inode->i_blocks + (1 << (blocksize_bits - 9)) - 1) >>
+			(blocksize_bits - 9);
+
 	if (iinfo->i_efe == 0) {
 		memcpy(bh->b_data + sizeof(struct fileEntry),
 		       iinfo->i_ext.i_data,
 		       inode->i_sb->s_blocksize - sizeof(struct fileEntry));
-		fe->logicalBlocksRecorded = cpu_to_le64(
-			(inode->i_blocks + (1 << (blocksize_bits - 9)) - 1) >>
-			(blocksize_bits - 9));
+		fe->logicalBlocksRecorded = cpu_to_le64(lb_recorded);
 
 		udf_time_to_disk_stamp(&fe->accessTime, inode->i_atime);
 		udf_time_to_disk_stamp(&fe->modificationTime, inode->i_mtime);
@@ -1607,6 +1615,7 @@
 		fe->uniqueID = cpu_to_le64(iinfo->i_unique);
 		fe->lengthExtendedAttr = cpu_to_le32(iinfo->i_lenEAttr);
 		fe->lengthAllocDescs = cpu_to_le32(iinfo->i_lenAlloc);
+		fe->checkpoint = cpu_to_le32(iinfo->i_checkpoint);
 		fe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_FE);
 		crclen = sizeof(struct fileEntry);
 	} else {
@@ -1615,9 +1624,7 @@
 		       inode->i_sb->s_blocksize -
 					sizeof(struct extendedFileEntry));
 		efe->objectSize = cpu_to_le64(inode->i_size);
-		efe->logicalBlocksRecorded = cpu_to_le64(
-			(inode->i_blocks + (1 << (blocksize_bits - 9)) - 1) >>
-			(blocksize_bits - 9));
+		efe->logicalBlocksRecorded = cpu_to_le64(lb_recorded);
 
 		if (iinfo->i_crtime.tv_sec > inode->i_atime.tv_sec ||
 		    (iinfo->i_crtime.tv_sec == inode->i_atime.tv_sec &&
@@ -1646,6 +1653,7 @@
 		efe->uniqueID = cpu_to_le64(iinfo->i_unique);
 		efe->lengthExtendedAttr = cpu_to_le32(iinfo->i_lenEAttr);
 		efe->lengthAllocDescs = cpu_to_le32(iinfo->i_lenAlloc);
+		efe->checkpoint = cpu_to_le32(iinfo->i_checkpoint);
 		efe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EFE);
 		crclen = sizeof(struct extendedFileEntry);
 	}
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 08bf46e..38de8f2 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -32,8 +32,6 @@
 #include <linux/crc-itu-t.h>
 #include <linux/exportfs.h>
 
-enum { UDF_MAX_LINKS = 0xffff };
-
 static inline int udf_match(int len1, const unsigned char *name1, int len2,
 			    const unsigned char *name2)
 {
@@ -649,10 +647,6 @@
 	struct udf_inode_info *dinfo = UDF_I(dir);
 	struct udf_inode_info *iinfo;
 
-	err = -EMLINK;
-	if (dir->i_nlink >= UDF_MAX_LINKS)
-		goto out;
-
 	err = -EIO;
 	inode = udf_new_inode(dir, S_IFDIR | mode, &err);
 	if (!inode)
@@ -1032,9 +1026,6 @@
 	struct fileIdentDesc cfi, *fi;
 	int err;
 
-	if (inode->i_nlink >= UDF_MAX_LINKS)
-		return -EMLINK;
-
 	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
 	if (!fi) {
 		return err;
@@ -1126,10 +1117,6 @@
 		if (udf_get_lb_pblock(old_inode->i_sb, &tloc, 0) !=
 				old_dir->i_ino)
 			goto end_rename;
-
-		retval = -EMLINK;
-		if (!new_inode && new_dir->i_nlink >= UDF_MAX_LINKS)
-			goto end_rename;
 	}
 	if (!nfi) {
 		nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi,
diff --git a/fs/udf/super.c b/fs/udf/super.c
index c09a84da..ac8a348 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -75,6 +75,8 @@
 
 #define UDF_DEFAULT_BLOCKSIZE 2048
 
+enum { UDF_MAX_LINKS = 0xffff };
+
 /* These are the "meat" - everything else is stuffing */
 static int udf_fill_super(struct super_block *, void *, int);
 static void udf_put_super(struct super_block *);
@@ -948,11 +950,8 @@
 	else
 		bitmap = vzalloc(size); /* TODO: get rid of vzalloc */
 
-	if (bitmap == NULL) {
-		udf_err(sb, "Unable to allocate space for bitmap and %d buffer_head pointers\n",
-			nr_groups);
+	if (bitmap == NULL)
 		return NULL;
-	}
 
 	bitmap->s_block_bitmap = (struct buffer_head **)(bitmap + 1);
 	bitmap->s_nr_groups = nr_groups;
@@ -2035,13 +2034,13 @@
 	}
 
 	/* Allocate a dentry for the root inode */
-	sb->s_root = d_alloc_root(inode);
+	sb->s_root = d_make_root(inode);
 	if (!sb->s_root) {
 		udf_err(sb, "Couldn't allocate root dentry\n");
-		iput(inode);
 		goto error_out;
 	}
 	sb->s_maxbytes = MAX_LFS_FILESIZE;
+	sb->s_max_links = UDF_MAX_LINKS;
 	return 0;
 
 error_out:
diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h
index d1bd31e..bb8309d 100644
--- a/fs/udf/udf_i.h
+++ b/fs/udf/udf_i.h
@@ -23,6 +23,7 @@
 	__u64			i_lenExtents;
 	__u32			i_next_alloc_block;
 	__u32			i_next_alloc_goal;
+	__u32			i_checkpoint;
 	unsigned		i_alloc_type : 3;
 	unsigned		i_efe : 1;	/* extendedFileEntry */
 	unsigned		i_use : 1;	/* unallocSpaceEntry */
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 9094e1d..7cdd395 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -26,7 +26,6 @@
  */
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #include <linux/errno.h>
 #include <linux/fs.h>
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index 38cac19..a2281ca 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -166,10 +166,6 @@
 	int error;
 
 	lock_ufs(dir->i_sb);
-	if (inode->i_nlink >= UFS_LINK_MAX) {
-		unlock_ufs(dir->i_sb);
-		return -EMLINK;
-	}
 
 	inode->i_ctime = CURRENT_TIME_SEC;
 	inode_inc_link_count(inode);
@@ -183,10 +179,7 @@
 static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
 {
 	struct inode * inode;
-	int err = -EMLINK;
-
-	if (dir->i_nlink >= UFS_LINK_MAX)
-		goto out;
+	int err;
 
 	lock_ufs(dir->i_sb);
 	inode_inc_link_count(dir);
@@ -305,11 +298,6 @@
 			drop_nlink(new_inode);
 		inode_dec_link_count(new_inode);
 	} else {
-		if (dir_de) {
-			err = -EMLINK;
-			if (new_dir->i_nlink >= UFS_LINK_MAX)
-				goto out_dir;
-		}
 		err = ufs_add_link(new_dentry, old_inode);
 		if (err)
 			goto out_dir;
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 5246ee3..ac8e279 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -73,7 +73,6 @@
 #include <stdarg.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -1157,16 +1156,17 @@
 			    "fast symlink size (%u)\n", uspi->s_maxsymlinklen);
 		uspi->s_maxsymlinklen = maxsymlen;
 	}
+	sb->s_max_links = UFS_LINK_MAX;
 
 	inode = ufs_iget(sb, UFS_ROOTINO);
 	if (IS_ERR(inode)) {
 		ret = PTR_ERR(inode);
 		goto failed;
 	}
-	sb->s_root = d_alloc_root(inode);
+	sb->s_root = d_make_root(inode);
 	if (!sb->s_root) {
 		ret = -ENOMEM;
-		goto dalloc_failed;
+		goto failed;
 	}
 
 	ufs_setup_cstotal(sb);
@@ -1180,8 +1180,6 @@
 	UFSD("EXIT\n");
 	return 0;
 
-dalloc_failed:
-	iput(inode);
 failed:
 	if (ubh)
 		ubh_brelse_uspi (uspi);
diff --git a/fs/xattr.c b/fs/xattr.c
index 82f4337..3c8c1cc 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -16,11 +16,12 @@
 #include <linux/security.h>
 #include <linux/evm.h>
 #include <linux/syscalls.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/fsnotify.h>
 #include <linux/audit.h>
-#include <asm/uaccess.h>
+#include <linux/vmalloc.h>
 
+#include <asm/uaccess.h>
 
 /*
  * Check permissions for extended attribute access.  This is a bit complicated
@@ -320,6 +321,7 @@
 {
 	int error;
 	void *kvalue = NULL;
+	void *vvalue = NULL;	/* If non-NULL, we used vmalloc() */
 	char kname[XATTR_NAME_MAX + 1];
 
 	if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
@@ -334,13 +336,25 @@
 	if (size) {
 		if (size > XATTR_SIZE_MAX)
 			return -E2BIG;
-		kvalue = memdup_user(value, size);
-		if (IS_ERR(kvalue))
-			return PTR_ERR(kvalue);
+		kvalue = kmalloc(size, GFP_KERNEL | __GFP_NOWARN);
+		if (!kvalue) {
+			vvalue = vmalloc(size);
+			if (!vvalue)
+				return -ENOMEM;
+			kvalue = vvalue;
+		}
+		if (copy_from_user(kvalue, value, size)) {
+			error = -EFAULT;
+			goto out;
+		}
 	}
 
 	error = vfs_setxattr(d, kname, kvalue, size, flags);
-	kfree(kvalue);
+out:
+	if (vvalue)
+		vfree(vvalue);
+	else
+		kfree(kvalue);
 	return error;
 }
 
@@ -492,13 +506,18 @@
 {
 	ssize_t error;
 	char *klist = NULL;
+	char *vlist = NULL;	/* If non-NULL, we used vmalloc() */
 
 	if (size) {
 		if (size > XATTR_LIST_MAX)
 			size = XATTR_LIST_MAX;
-		klist = kmalloc(size, GFP_KERNEL);
-		if (!klist)
-			return -ENOMEM;
+		klist = kmalloc(size, __GFP_NOWARN | GFP_KERNEL);
+		if (!klist) {
+			vlist = vmalloc(size);
+			if (!vlist)
+				return -ENOMEM;
+			klist = vlist;
+		}
 	}
 
 	error = vfs_listxattr(d, klist, size);
@@ -510,7 +529,10 @@
 		   than XATTR_LIST_MAX bytes. Not possible. */
 		error = -E2BIG;
 	}
-	kfree(klist);
+	if (vlist)
+		vfree(vlist);
+	else
+		kfree(klist);
 	return error;
 }
 
diff --git a/fs/xattr_acl.c b/fs/xattr_acl.c
index 8d5a506..69d06b0 100644
--- a/fs/xattr_acl.c
+++ b/fs/xattr_acl.c
@@ -5,7 +5,7 @@
  * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/posix_acl_xattr.h>
 #include <linux/gfp.h>
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 427a4e8..0a99779 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -96,9 +96,6 @@
 				   xfs_qm_bhv.o \
 				   xfs_qm.o \
 				   xfs_quotaops.o
-ifeq ($(CONFIG_XFS_QUOTA),y)
-xfs-$(CONFIG_PROC_FS)		+= xfs_qm_stats.o
-endif
 xfs-$(CONFIG_XFS_RT)		+= xfs_rtalloc.o
 xfs-$(CONFIG_XFS_POSIX_ACL)	+= xfs_acl.o
 xfs-$(CONFIG_PROC_FS)		+= xfs_stats.o
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
index ce84ffd..0f0df27 100644
--- a/fs/xfs/xfs_alloc.c
+++ b/fs/xfs/xfs_alloc.c
@@ -35,6 +35,7 @@
 #include "xfs_error.h"
 #include "xfs_trace.h"
 
+struct workqueue_struct *xfs_alloc_wq;
 
 #define XFS_ABSDIFF(a,b)	(((a) <= (b)) ? ((b) - (a)) : ((a) - (b)))
 
@@ -68,7 +69,7 @@
  * Lookup the first record greater than or equal to [bno, len]
  * in the btree given by cur.
  */
-STATIC int				/* error */
+int				/* error */
 xfs_alloc_lookup_ge(
 	struct xfs_btree_cur	*cur,	/* btree cursor */
 	xfs_agblock_t		bno,	/* starting block of extent */
@@ -2207,7 +2208,7 @@
  * group or loop over the allocation groups to find the result.
  */
 int				/* error */
-xfs_alloc_vextent(
+__xfs_alloc_vextent(
 	xfs_alloc_arg_t	*args)	/* allocation argument structure */
 {
 	xfs_agblock_t	agsize;	/* allocation group size */
@@ -2417,6 +2418,37 @@
 	return error;
 }
 
+static void
+xfs_alloc_vextent_worker(
+	struct work_struct	*work)
+{
+	struct xfs_alloc_arg	*args = container_of(work,
+						struct xfs_alloc_arg, work);
+	unsigned long		pflags;
+
+	/* we are in a transaction context here */
+	current_set_flags_nested(&pflags, PF_FSTRANS);
+
+	args->result = __xfs_alloc_vextent(args);
+	complete(args->done);
+
+	current_restore_flags_nested(&pflags, PF_FSTRANS);
+}
+
+
+int				/* error */
+xfs_alloc_vextent(
+	xfs_alloc_arg_t	*args)	/* allocation argument structure */
+{
+	DECLARE_COMPLETION_ONSTACK(done);
+
+	args->done = &done;
+	INIT_WORK(&args->work, xfs_alloc_vextent_worker);
+	queue_work(xfs_alloc_wq, &args->work);
+	wait_for_completion(&done);
+	return args->result;
+}
+
 /*
  * Free an extent.
  * Just break up the extent address and hand off to xfs_free_ag_extent
diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h
index 2f52b92..3a7e7d8 100644
--- a/fs/xfs/xfs_alloc.h
+++ b/fs/xfs/xfs_alloc.h
@@ -25,6 +25,8 @@
 struct xfs_trans;
 struct xfs_busy_extent;
 
+extern struct workqueue_struct *xfs_alloc_wq;
+
 /*
  * Freespace allocation types.  Argument to xfs_alloc_[v]extent.
  */
@@ -119,6 +121,9 @@
 	char		isfl;		/* set if is freelist blocks - !acctg */
 	char		userdata;	/* set if this is user data */
 	xfs_fsblock_t	firstblock;	/* io first block allocated */
+	struct completion *done;
+	struct work_struct work;
+	int		result;
 } xfs_alloc_arg_t;
 
 /*
@@ -243,6 +248,13 @@
 	xfs_extlen_t		len,	/* length of extent */
 	int			*stat);	/* success/failure */
 
+int				/* error */
+xfs_alloc_lookup_ge(
+	struct xfs_btree_cur	*cur,	/* btree cursor */
+	xfs_agblock_t		bno,	/* starting block of extent */
+	xfs_extlen_t		len,	/* length of extent */
+	int			*stat);	/* success/failure */
+
 int					/* error */
 xfs_alloc_get_rec(
 	struct xfs_btree_cur	*cur,	/* btree cursor */
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 74b9baf..0dbb9e7 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -26,6 +26,7 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
+#include "xfs_inode_item.h"
 #include "xfs_alloc.h"
 #include "xfs_error.h"
 #include "xfs_rw.h"
@@ -99,23 +100,6 @@
 }
 
 /*
- * If the end of the current ioend is beyond the current EOF,
- * return the new EOF value, otherwise zero.
- */
-STATIC xfs_fsize_t
-xfs_ioend_new_eof(
-	xfs_ioend_t		*ioend)
-{
-	xfs_inode_t		*ip = XFS_I(ioend->io_inode);
-	xfs_fsize_t		isize;
-	xfs_fsize_t		bsize;
-
-	bsize = ioend->io_offset + ioend->io_size;
-	isize = MIN(i_size_read(VFS_I(ip)), bsize);
-	return isize > ip->i_d.di_size ? isize : 0;
-}
-
-/*
  * Fast and loose check if this write could update the on-disk inode size.
  */
 static inline bool xfs_ioend_is_append(struct xfs_ioend *ioend)
@@ -124,32 +108,65 @@
 		XFS_I(ioend->io_inode)->i_d.di_size;
 }
 
+STATIC int
+xfs_setfilesize_trans_alloc(
+	struct xfs_ioend	*ioend)
+{
+	struct xfs_mount	*mp = XFS_I(ioend->io_inode)->i_mount;
+	struct xfs_trans	*tp;
+	int			error;
+
+	tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
+
+	error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
+	if (error) {
+		xfs_trans_cancel(tp, 0);
+		return error;
+	}
+
+	ioend->io_append_trans = tp;
+
+	/*
+	 * We hand off the transaction to the completion thread now, so
+	 * clear the flag here.
+	 */
+	current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
+	return 0;
+}
+
 /*
  * Update on-disk file size now that data has been written to disk.
- *
- * This function does not block as blocking on the inode lock in IO completion
- * can lead to IO completion order dependency deadlocks.. If it can't get the
- * inode ilock it will return EAGAIN. Callers must handle this.
  */
 STATIC int
 xfs_setfilesize(
-	xfs_ioend_t		*ioend)
+	struct xfs_ioend	*ioend)
 {
-	xfs_inode_t		*ip = XFS_I(ioend->io_inode);
+	struct xfs_inode	*ip = XFS_I(ioend->io_inode);
+	struct xfs_trans	*tp = ioend->io_append_trans;
 	xfs_fsize_t		isize;
 
-	if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL))
-		return EAGAIN;
+	/*
+	 * The transaction was allocated in the I/O submission thread,
+	 * thus we need to mark ourselves as beeing in a transaction
+	 * manually.
+	 */
+	current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);
 
-	isize = xfs_ioend_new_eof(ioend);
-	if (isize) {
-		trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size);
-		ip->i_d.di_size = isize;
-		xfs_mark_inode_dirty(ip);
+	xfs_ilock(ip, XFS_ILOCK_EXCL);
+	isize = xfs_new_eof(ip, ioend->io_offset + ioend->io_size);
+	if (!isize) {
+		xfs_iunlock(ip, XFS_ILOCK_EXCL);
+		xfs_trans_cancel(tp, 0);
+		return 0;
 	}
 
-	xfs_iunlock(ip, XFS_ILOCK_EXCL);
-	return 0;
+	trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size);
+
+	ip->i_d.di_size = isize;
+	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+	return xfs_trans_commit(tp, 0);
 }
 
 /*
@@ -163,10 +180,12 @@
 	struct xfs_ioend	*ioend)
 {
 	if (atomic_dec_and_test(&ioend->io_remaining)) {
+		struct xfs_mount	*mp = XFS_I(ioend->io_inode)->i_mount;
+
 		if (ioend->io_type == IO_UNWRITTEN)
-			queue_work(xfsconvertd_workqueue, &ioend->io_work);
-		else if (xfs_ioend_is_append(ioend))
-			queue_work(xfsdatad_workqueue, &ioend->io_work);
+			queue_work(mp->m_unwritten_workqueue, &ioend->io_work);
+		else if (ioend->io_append_trans)
+			queue_work(mp->m_data_workqueue, &ioend->io_work);
 		else
 			xfs_destroy_ioend(ioend);
 	}
@@ -195,35 +214,36 @@
 	 * range to normal written extens after the data I/O has finished.
 	 */
 	if (ioend->io_type == IO_UNWRITTEN) {
+		/*
+		 * For buffered I/O we never preallocate a transaction when
+		 * doing the unwritten extent conversion, but for direct I/O
+		 * we do not know if we are converting an unwritten extent
+		 * or not at the point where we preallocate the transaction.
+		 */
+		if (ioend->io_append_trans) {
+			ASSERT(ioend->io_isdirect);
+
+			current_set_flags_nested(
+				&ioend->io_append_trans->t_pflags, PF_FSTRANS);
+			xfs_trans_cancel(ioend->io_append_trans, 0);
+		}
+
 		error = xfs_iomap_write_unwritten(ip, ioend->io_offset,
 						 ioend->io_size);
 		if (error) {
 			ioend->io_error = -error;
 			goto done;
 		}
+	} else if (ioend->io_append_trans) {
+		error = xfs_setfilesize(ioend);
+		if (error)
+			ioend->io_error = -error;
+	} else {
+		ASSERT(!xfs_ioend_is_append(ioend));
 	}
 
-	/*
-	 * We might have to update the on-disk file size after extending
-	 * writes.
-	 */
-	error = xfs_setfilesize(ioend);
-	ASSERT(!error || error == EAGAIN);
-
 done:
-	/*
-	 * If we didn't complete processing of the ioend, requeue it to the
-	 * tail of the workqueue for another attempt later. Otherwise destroy
-	 * it.
-	 */
-	if (error == EAGAIN) {
-		atomic_inc(&ioend->io_remaining);
-		xfs_finish_ioend(ioend);
-		/* ensure we don't spin on blocked ioends */
-		delay(1);
-	} else {
-		xfs_destroy_ioend(ioend);
-	}
+	xfs_destroy_ioend(ioend);
 }
 
 /*
@@ -259,6 +279,7 @@
 	 */
 	atomic_set(&ioend->io_remaining, 1);
 	ioend->io_isasync = 0;
+	ioend->io_isdirect = 0;
 	ioend->io_error = 0;
 	ioend->io_list = NULL;
 	ioend->io_type = type;
@@ -269,6 +290,7 @@
 	ioend->io_size = 0;
 	ioend->io_iocb = NULL;
 	ioend->io_result = 0;
+	ioend->io_append_trans = NULL;
 
 	INIT_WORK(&ioend->io_work, xfs_end_io);
 	return ioend;
@@ -379,14 +401,6 @@
 	atomic_inc(&ioend->io_remaining);
 	bio->bi_private = ioend;
 	bio->bi_end_io = xfs_end_bio;
-
-	/*
-	 * If the I/O is beyond EOF we mark the inode dirty immediately
-	 * but don't update the inode size until I/O completion.
-	 */
-	if (xfs_ioend_new_eof(ioend))
-		xfs_mark_inode_dirty(XFS_I(ioend->io_inode));
-
 	submit_bio(wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE, bio);
 }
 
@@ -1033,8 +1047,20 @@
 				  wbc, end_index);
 	}
 
-	if (iohead)
+	if (iohead) {
+		/*
+		 * Reserve log space if we might write beyond the on-disk
+		 * inode size.
+		 */
+		if (ioend->io_type != IO_UNWRITTEN &&
+		    xfs_ioend_is_append(ioend)) {
+			err = xfs_setfilesize_trans_alloc(ioend);
+			if (err)
+				goto error;
+		}
+
 		xfs_submit_ioend(wbc, iohead);
+	}
 
 	return 0;
 
@@ -1314,17 +1340,32 @@
 {
 	struct inode		*inode = iocb->ki_filp->f_mapping->host;
 	struct block_device	*bdev = xfs_find_bdev_for_inode(inode);
+	struct xfs_ioend	*ioend = NULL;
 	ssize_t			ret;
 
 	if (rw & WRITE) {
-		iocb->private = xfs_alloc_ioend(inode, IO_DIRECT);
+		size_t size = iov_length(iov, nr_segs);
+
+		/*
+		 * We need to preallocate a transaction for a size update
+		 * here.  In the case that this write both updates the size
+		 * and converts at least on unwritten extent we will cancel
+		 * the still clean transaction after the I/O has finished.
+		 */
+		iocb->private = ioend = xfs_alloc_ioend(inode, IO_DIRECT);
+		if (offset + size > XFS_I(inode)->i_d.di_size) {
+			ret = xfs_setfilesize_trans_alloc(ioend);
+			if (ret)
+				goto out_destroy_ioend;
+			ioend->io_isdirect = 1;
+		}
 
 		ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov,
 					    offset, nr_segs,
 					    xfs_get_blocks_direct,
 					    xfs_end_io_direct_write, NULL, 0);
 		if (ret != -EIOCBQUEUED && iocb->private)
-			xfs_destroy_ioend(iocb->private);
+			goto out_trans_cancel;
 	} else {
 		ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov,
 					    offset, nr_segs,
@@ -1333,6 +1374,16 @@
 	}
 
 	return ret;
+
+out_trans_cancel:
+	if (ioend->io_append_trans) {
+		current_set_flags_nested(&ioend->io_append_trans->t_pflags,
+					 PF_FSTRANS);
+		xfs_trans_cancel(ioend->io_append_trans, 0);
+	}
+out_destroy_ioend:
+	xfs_destroy_ioend(ioend);
+	return ret;
 }
 
 STATIC void
diff --git a/fs/xfs/xfs_aops.h b/fs/xfs/xfs_aops.h
index 116dd5c..84eafbc 100644
--- a/fs/xfs/xfs_aops.h
+++ b/fs/xfs/xfs_aops.h
@@ -18,8 +18,6 @@
 #ifndef __XFS_AOPS_H__
 #define __XFS_AOPS_H__
 
-extern struct workqueue_struct *xfsdatad_workqueue;
-extern struct workqueue_struct *xfsconvertd_workqueue;
 extern mempool_t *xfs_ioend_pool;
 
 /*
@@ -48,12 +46,14 @@
 	int			io_error;	/* I/O error code */
 	atomic_t		io_remaining;	/* hold count */
 	unsigned int		io_isasync : 1;	/* needs aio_complete */
+	unsigned int		io_isdirect : 1;/* direct I/O */
 	struct inode		*io_inode;	/* file being written to */
 	struct buffer_head	*io_buffer_head;/* buffer linked list head */
 	struct buffer_head	*io_buffer_tail;/* buffer linked list tail */
 	size_t			io_size;	/* size of the extent */
 	xfs_off_t		io_offset;	/* offset in the file */
 	struct work_struct	io_work;	/* xfsdatad work queue */
+	struct xfs_trans	*io_append_trans;/* xact. for size update */
 	struct kiocb		*io_iocb;
 	int			io_result;
 } xfs_ioend_t;
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
index 08b9ac6..65d61b9 100644
--- a/fs/xfs/xfs_attr.c
+++ b/fs/xfs/xfs_attr.c
@@ -853,6 +853,8 @@
 {
 	int newsize, forkoff, retval;
 
+	trace_xfs_attr_sf_addname(args);
+
 	retval = xfs_attr_shortform_lookup(args);
 	if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
 		return(retval);
@@ -896,6 +898,8 @@
 	xfs_dabuf_t *bp;
 	int retval, error, committed, forkoff;
 
+	trace_xfs_attr_leaf_addname(args);
+
 	/*
 	 * Read the (only) block in the attribute list in.
 	 */
@@ -920,6 +924,9 @@
 			xfs_da_brelse(args->trans, bp);
 			return(retval);
 		}
+
+		trace_xfs_attr_leaf_replace(args);
+
 		args->op_flags |= XFS_DA_OP_RENAME;	/* an atomic rename */
 		args->blkno2 = args->blkno;		/* set 2nd entry info*/
 		args->index2 = args->index;
@@ -1090,6 +1097,8 @@
 	xfs_dabuf_t *bp;
 	int error, committed, forkoff;
 
+	trace_xfs_attr_leaf_removename(args);
+
 	/*
 	 * Remove the attribute.
 	 */
@@ -1223,6 +1232,8 @@
 	xfs_mount_t *mp;
 	int committed, retval, error;
 
+	trace_xfs_attr_node_addname(args);
+
 	/*
 	 * Fill in bucket of arguments/results/context to carry around.
 	 */
@@ -1249,6 +1260,9 @@
 	} else if (retval == EEXIST) {
 		if (args->flags & ATTR_CREATE)
 			goto out;
+
+		trace_xfs_attr_node_replace(args);
+
 		args->op_flags |= XFS_DA_OP_RENAME;	/* atomic rename op */
 		args->blkno2 = args->blkno;		/* set 2nd entry info*/
 		args->index2 = args->index;
@@ -1480,6 +1494,8 @@
 	xfs_dabuf_t *bp;
 	int retval, error, committed, forkoff;
 
+	trace_xfs_attr_node_removename(args);
+
 	/*
 	 * Tie a string around our finger to remind us where we are.
 	 */
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
index d25eafd..76d93dc 100644
--- a/fs/xfs/xfs_attr_leaf.c
+++ b/fs/xfs/xfs_attr_leaf.c
@@ -235,6 +235,8 @@
 	xfs_inode_t *dp;
 	xfs_ifork_t *ifp;
 
+	trace_xfs_attr_sf_create(args);
+
 	dp = args->dp;
 	ASSERT(dp != NULL);
 	ifp = dp->i_afp;
@@ -268,6 +270,8 @@
 	xfs_inode_t *dp;
 	xfs_ifork_t *ifp;
 
+	trace_xfs_attr_sf_add(args);
+
 	dp = args->dp;
 	mp = dp->i_mount;
 	dp->i_d.di_forkoff = forkoff;
@@ -337,6 +341,8 @@
 	xfs_mount_t *mp;
 	xfs_inode_t *dp;
 
+	trace_xfs_attr_sf_remove(args);
+
 	dp = args->dp;
 	mp = dp->i_mount;
 	base = sizeof(xfs_attr_sf_hdr_t);
@@ -405,6 +411,8 @@
 	int i;
 	xfs_ifork_t *ifp;
 
+	trace_xfs_attr_sf_lookup(args);
+
 	ifp = args->dp->i_afp;
 	ASSERT(ifp->if_flags & XFS_IFINLINE);
 	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
@@ -476,6 +484,8 @@
 	xfs_dabuf_t *bp;
 	xfs_ifork_t *ifp;
 
+	trace_xfs_attr_sf_to_leaf(args);
+
 	dp = args->dp;
 	ifp = dp->i_afp;
 	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
@@ -775,6 +785,8 @@
 	char *tmpbuffer;
 	int error, i;
 
+	trace_xfs_attr_leaf_to_sf(args);
+
 	dp = args->dp;
 	tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP);
 	ASSERT(tmpbuffer != NULL);
@@ -848,6 +860,8 @@
 	xfs_dablk_t blkno;
 	int error;
 
+	trace_xfs_attr_leaf_to_node(args);
+
 	dp = args->dp;
 	bp1 = bp2 = NULL;
 	error = xfs_da_grow_inode(args, &blkno);
@@ -911,6 +925,8 @@
 	xfs_dabuf_t *bp;
 	int error;
 
+	trace_xfs_attr_leaf_create(args);
+
 	dp = args->dp;
 	ASSERT(dp != NULL);
 	error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp,
@@ -948,6 +964,8 @@
 	xfs_dablk_t blkno;
 	int error;
 
+	trace_xfs_attr_leaf_split(state->args);
+
 	/*
 	 * Allocate space for a new leaf node.
 	 */
@@ -977,10 +995,13 @@
 	 *
 	 * Insert the "new" entry in the correct block.
 	 */
-	if (state->inleaf)
+	if (state->inleaf) {
+		trace_xfs_attr_leaf_add_old(state->args);
 		error = xfs_attr_leaf_add(oldblk->bp, state->args);
-	else
+	} else {
+		trace_xfs_attr_leaf_add_new(state->args);
 		error = xfs_attr_leaf_add(newblk->bp, state->args);
+	}
 
 	/*
 	 * Update last hashval in each block since we added the name.
@@ -1001,6 +1022,8 @@
 	xfs_attr_leaf_map_t *map;
 	int tablesize, entsize, sum, tmp, i;
 
+	trace_xfs_attr_leaf_add(args);
+
 	leaf = bp->data;
 	ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
 	ASSERT((args->index >= 0)
@@ -1128,8 +1151,6 @@
 	       (be32_to_cpu(entry->hashval) <= be32_to_cpu((entry+1)->hashval)));
 
 	/*
-	 * Copy the attribute name and value into the new space.
-	 *
 	 * For "remote" attribute values, simply note that we need to
 	 * allocate space for the "remote" value.  We can't actually
 	 * allocate the extents in this transaction, and we can't decide
@@ -1265,6 +1286,8 @@
 	ASSERT(leaf2->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
 	args = state->args;
 
+	trace_xfs_attr_leaf_rebalance(args);
+
 	/*
 	 * Check ordering of blocks, reverse if it makes things simpler.
 	 *
@@ -1810,6 +1833,8 @@
 	xfs_mount_t *mp;
 	char *tmpbuffer;
 
+	trace_xfs_attr_leaf_unbalance(state->args);
+
 	/*
 	 * Set up environment.
 	 */
@@ -1919,6 +1944,8 @@
 	int probe, span;
 	xfs_dahash_t hashval;
 
+	trace_xfs_attr_leaf_lookup(args);
+
 	leaf = bp->data;
 	ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
 	ASSERT(be16_to_cpu(leaf->hdr.count)
@@ -2445,6 +2472,7 @@
 	char *name;
 #endif /* DEBUG */
 
+	trace_xfs_attr_leaf_clearflag(args);
 	/*
 	 * Set up the operation.
 	 */
@@ -2509,6 +2537,8 @@
 	xfs_dabuf_t *bp;
 	int error;
 
+	trace_xfs_attr_leaf_setflag(args);
+
 	/*
 	 * Set up the operation.
 	 */
@@ -2565,6 +2595,8 @@
 	char *name1, *name2;
 #endif /* DEBUG */
 
+	trace_xfs_attr_leaf_flipflags(args);
+
 	/*
 	 * Read the block containing the "old" attr
 	 */
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 188ef2f..85e7e32 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -5124,6 +5124,15 @@
 		cur->bc_private.b.flags = 0;
 	} else
 		cur = NULL;
+
+	if (isrt) {
+		/*
+		 * Synchronize by locking the bitmap inode.
+		 */
+		xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
+		xfs_trans_ijoin(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
+	}
+
 	extno = 0;
 	while (bno != (xfs_fileoff_t)-1 && bno >= start && lastx >= 0 &&
 	       (nexts == 0 || extno < nexts)) {
@@ -5536,8 +5545,12 @@
 	if (bmv->bmv_count > ULONG_MAX / sizeof(struct getbmapx))
 		return XFS_ERROR(ENOMEM);
 	out = kmem_zalloc(bmv->bmv_count * sizeof(struct getbmapx), KM_MAYFAIL);
-	if (!out)
-		return XFS_ERROR(ENOMEM);
+	if (!out) {
+		out = kmem_zalloc_large(bmv->bmv_count *
+					sizeof(struct getbmapx));
+		if (!out)
+			return XFS_ERROR(ENOMEM);
+	}
 
 	xfs_ilock(ip, XFS_IOLOCK_SHARED);
 	if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) {
@@ -5661,7 +5674,10 @@
 			break;
 	}
 
-	kmem_free(out);
+	if (is_vmalloc_addr(out))
+		kmem_free_large(out);
+	else
+		kmem_free(out);
 	return error;
 }
 
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 4dff85c..6819b51 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -45,8 +45,6 @@
 STATIC int xfsbufd(void *);
 
 static struct workqueue_struct *xfslogd_workqueue;
-struct workqueue_struct *xfsdatad_workqueue;
-struct workqueue_struct *xfsconvertd_workqueue;
 
 #ifdef XFS_BUF_LOCK_TRACKING
 # define XB_SET_OWNER(bp)	((bp)->b_last_holder = current->pid)
@@ -1793,21 +1791,8 @@
 	if (!xfslogd_workqueue)
 		goto out_free_buf_zone;
 
-	xfsdatad_workqueue = alloc_workqueue("xfsdatad", WQ_MEM_RECLAIM, 1);
-	if (!xfsdatad_workqueue)
-		goto out_destroy_xfslogd_workqueue;
-
-	xfsconvertd_workqueue = alloc_workqueue("xfsconvertd",
-						WQ_MEM_RECLAIM, 1);
-	if (!xfsconvertd_workqueue)
-		goto out_destroy_xfsdatad_workqueue;
-
 	return 0;
 
- out_destroy_xfsdatad_workqueue:
-	destroy_workqueue(xfsdatad_workqueue);
- out_destroy_xfslogd_workqueue:
-	destroy_workqueue(xfslogd_workqueue);
  out_free_buf_zone:
 	kmem_zone_destroy(xfs_buf_zone);
  out:
@@ -1817,8 +1802,6 @@
 void
 xfs_buf_terminate(void)
 {
-	destroy_workqueue(xfsconvertd_workqueue);
-	destroy_workqueue(xfsdatad_workqueue);
 	destroy_workqueue(xfslogd_workqueue);
 	kmem_zone_destroy(xfs_buf_zone);
 }
diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
index df7ffb0..5bf3be4 100644
--- a/fs/xfs/xfs_buf.h
+++ b/fs/xfs/xfs_buf.h
@@ -21,7 +21,6 @@
 #include <linux/list.h>
 #include <linux/types.h>
 #include <linux/spinlock.h>
-#include <asm/system.h>
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c
index 77c7425..7f1a6f5 100644
--- a/fs/xfs/xfs_da_btree.c
+++ b/fs/xfs/xfs_da_btree.c
@@ -108,6 +108,8 @@
 	int error;
 	xfs_trans_t *tp;
 
+	trace_xfs_da_node_create(args);
+
 	tp = args->trans;
 	error = xfs_da_get_buf(tp, args->dp, blkno, -1, &bp, whichfork);
 	if (error)
@@ -140,6 +142,8 @@
 	xfs_dabuf_t *bp;
 	int max, action, error, i;
 
+	trace_xfs_da_split(state->args);
+
 	/*
 	 * Walk back up the tree splitting/inserting/adjusting as necessary.
 	 * If we need to insert and there isn't room, split the node, then
@@ -178,10 +182,12 @@
 			state->extravalid = 1;
 			if (state->inleaf) {
 				state->extraafter = 0;	/* before newblk */
+				trace_xfs_attr_leaf_split_before(state->args);
 				error = xfs_attr_leaf_split(state, oldblk,
 							    &state->extrablk);
 			} else {
 				state->extraafter = 1;	/* after newblk */
+				trace_xfs_attr_leaf_split_after(state->args);
 				error = xfs_attr_leaf_split(state, newblk,
 							    &state->extrablk);
 			}
@@ -300,6 +306,8 @@
 	xfs_mount_t *mp;
 	xfs_dir2_leaf_t *leaf;
 
+	trace_xfs_da_root_split(state->args);
+
 	/*
 	 * Copy the existing (incorrect) block from the root node position
 	 * to a free space somewhere.
@@ -380,6 +388,8 @@
 	int newcount, error;
 	int useextra;
 
+	trace_xfs_da_node_split(state->args);
+
 	node = oldblk->bp->data;
 	ASSERT(node->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
 
@@ -466,6 +476,8 @@
 	int count, tmp;
 	xfs_trans_t *tp;
 
+	trace_xfs_da_node_rebalance(state->args);
+
 	node1 = blk1->bp->data;
 	node2 = blk2->bp->data;
 	/*
@@ -574,6 +586,8 @@
 	xfs_da_node_entry_t *btree;
 	int tmp;
 
+	trace_xfs_da_node_add(state->args);
+
 	node = oldblk->bp->data;
 	ASSERT(node->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
 	ASSERT((oldblk->index >= 0) && (oldblk->index <= be16_to_cpu(node->hdr.count)));
@@ -619,6 +633,8 @@
 	xfs_da_state_blk_t *drop_blk, *save_blk;
 	int action, error;
 
+	trace_xfs_da_join(state->args);
+
 	action = 0;
 	drop_blk = &state->path.blk[ state->path.active-1 ];
 	save_blk = &state->altpath.blk[ state->path.active-1 ];
@@ -723,6 +739,8 @@
 	xfs_dabuf_t *bp;
 	int error;
 
+	trace_xfs_da_root_join(state->args);
+
 	args = state->args;
 	ASSERT(args != NULL);
 	ASSERT(root_blk->magic == XFS_DA_NODE_MAGIC);
@@ -941,6 +959,8 @@
 	xfs_da_node_entry_t *btree;
 	int tmp;
 
+	trace_xfs_da_node_remove(state->args);
+
 	node = drop_blk->bp->data;
 	ASSERT(drop_blk->index < be16_to_cpu(node->hdr.count));
 	ASSERT(drop_blk->index >= 0);
@@ -984,6 +1004,8 @@
 	int tmp;
 	xfs_trans_t *tp;
 
+	trace_xfs_da_node_unbalance(state->args);
+
 	drop_node = drop_blk->bp->data;
 	save_node = save_blk->bp->data;
 	ASSERT(drop_node->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
@@ -1230,6 +1252,7 @@
 		/*
 		 * Link new block in before existing block.
 		 */
+		trace_xfs_da_link_before(args);
 		new_info->forw = cpu_to_be32(old_blk->blkno);
 		new_info->back = old_info->back;
 		if (old_info->back) {
@@ -1251,6 +1274,7 @@
 		/*
 		 * Link new block in after existing block.
 		 */
+		trace_xfs_da_link_after(args);
 		new_info->forw = old_info->forw;
 		new_info->back = cpu_to_be32(old_blk->blkno);
 		if (old_info->forw) {
@@ -1348,6 +1372,7 @@
 	 * Unlink the leaf block from the doubly linked chain of leaves.
 	 */
 	if (be32_to_cpu(save_info->back) == drop_blk->blkno) {
+		trace_xfs_da_unlink_back(args);
 		save_info->back = drop_info->back;
 		if (drop_info->back) {
 			error = xfs_da_read_buf(args->trans, args->dp,
@@ -1365,6 +1390,7 @@
 			xfs_da_buf_done(bp);
 		}
 	} else {
+		trace_xfs_da_unlink_forward(args);
 		save_info->forw = drop_info->forw;
 		if (drop_info->forw) {
 			error = xfs_da_read_buf(args->trans, args->dp,
@@ -1652,6 +1678,8 @@
 	int			count;
 	int			error;
 
+	trace_xfs_da_grow_inode(args);
+
 	if (args->whichfork == XFS_DATA_FORK) {
 		bno = args->dp->i_mount->m_dirleafblk;
 		count = args->dp->i_mount->m_dirblkfsbs;
@@ -1690,6 +1718,8 @@
 	xfs_dir2_leaf_t *dead_leaf2;
 	xfs_dahash_t dead_hash;
 
+	trace_xfs_da_swap_lastblock(args);
+
 	dead_buf = *dead_bufp;
 	dead_blkno = *dead_blknop;
 	tp = args->trans;
@@ -1878,6 +1908,8 @@
 	xfs_trans_t *tp;
 	xfs_mount_t *mp;
 
+	trace_xfs_da_shrink_inode(args);
+
 	dp = args->dp;
 	w = args->whichfork;
 	tp = args->trans;
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c
index dd974a5..1137bbc 100644
--- a/fs/xfs/xfs_dfrag.c
+++ b/fs/xfs/xfs_dfrag.c
@@ -215,7 +215,7 @@
 	xfs_trans_t	*tp;
 	xfs_bstat_t	*sbp = &sxp->sx_stat;
 	xfs_ifork_t	*tempifp, *ifp, *tifp;
-	int		ilf_fields, tilf_fields;
+	int		src_log_flags, target_log_flags;
 	int		error = 0;
 	int		aforkblks = 0;
 	int		taforkblks = 0;
@@ -385,9 +385,8 @@
 	tip->i_delayed_blks = ip->i_delayed_blks;
 	ip->i_delayed_blks = 0;
 
-	ilf_fields = XFS_ILOG_CORE;
-
-	switch(ip->i_d.di_format) {
+	src_log_flags = XFS_ILOG_CORE;
+	switch (ip->i_d.di_format) {
 	case XFS_DINODE_FMT_EXTENTS:
 		/* If the extents fit in the inode, fix the
 		 * pointer.  Otherwise it's already NULL or
@@ -397,16 +396,15 @@
 			ifp->if_u1.if_extents =
 				ifp->if_u2.if_inline_ext;
 		}
-		ilf_fields |= XFS_ILOG_DEXT;
+		src_log_flags |= XFS_ILOG_DEXT;
 		break;
 	case XFS_DINODE_FMT_BTREE:
-		ilf_fields |= XFS_ILOG_DBROOT;
+		src_log_flags |= XFS_ILOG_DBROOT;
 		break;
 	}
 
-	tilf_fields = XFS_ILOG_CORE;
-
-	switch(tip->i_d.di_format) {
+	target_log_flags = XFS_ILOG_CORE;
+	switch (tip->i_d.di_format) {
 	case XFS_DINODE_FMT_EXTENTS:
 		/* If the extents fit in the inode, fix the
 		 * pointer.  Otherwise it's already NULL or
@@ -416,10 +414,10 @@
 			tifp->if_u1.if_extents =
 				tifp->if_u2.if_inline_ext;
 		}
-		tilf_fields |= XFS_ILOG_DEXT;
+		target_log_flags |= XFS_ILOG_DEXT;
 		break;
 	case XFS_DINODE_FMT_BTREE:
-		tilf_fields |= XFS_ILOG_DBROOT;
+		target_log_flags |= XFS_ILOG_DBROOT;
 		break;
 	}
 
@@ -427,8 +425,8 @@
 	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
 	xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
 
-	xfs_trans_log_inode(tp, ip,  ilf_fields);
-	xfs_trans_log_inode(tp, tip, tilf_fields);
+	xfs_trans_log_inode(tp, ip,  src_log_flags);
+	xfs_trans_log_inode(tp, tip, target_log_flags);
 
 	/*
 	 * If this is a synchronous mount, make sure that the
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
index 9245e02..d3b63ae 100644
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -29,6 +29,7 @@
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
+#include "xfs_dir2.h"
 #include "xfs_dir2_format.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_error.h"
diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c
index 286a051..1ad3a4b 100644
--- a/fs/xfs/xfs_discard.c
+++ b/fs/xfs/xfs_discard.c
@@ -37,9 +37,9 @@
 xfs_trim_extents(
 	struct xfs_mount	*mp,
 	xfs_agnumber_t		agno,
-	xfs_fsblock_t		start,
-	xfs_fsblock_t		end,
-	xfs_fsblock_t		minlen,
+	xfs_daddr_t		start,
+	xfs_daddr_t		end,
+	xfs_daddr_t		minlen,
 	__uint64_t		*blocks_trimmed)
 {
 	struct block_device	*bdev = mp->m_ddev_targp->bt_bdev;
@@ -67,7 +67,7 @@
 	/*
 	 * Look up the longest btree in the AGF and start with it.
 	 */
-	error = xfs_alloc_lookup_le(cur, 0,
+	error = xfs_alloc_lookup_ge(cur, 0,
 			    be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_longest), &i);
 	if (error)
 		goto out_del_cursor;
@@ -77,8 +77,10 @@
 	 * enough to be worth discarding.
 	 */
 	while (i) {
-		xfs_agblock_t fbno;
-		xfs_extlen_t flen;
+		xfs_agblock_t	fbno;
+		xfs_extlen_t	flen;
+		xfs_daddr_t	dbno;
+		xfs_extlen_t	dlen;
 
 		error = xfs_alloc_get_rec(cur, &fbno, &flen, &i);
 		if (error)
@@ -87,9 +89,17 @@
 		ASSERT(flen <= be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_longest));
 
 		/*
+		 * use daddr format for all range/len calculations as that is
+		 * the format the range/len variables are supplied in by
+		 * userspace.
+		 */
+		dbno = XFS_AGB_TO_DADDR(mp, agno, fbno);
+		dlen = XFS_FSB_TO_BB(mp, flen);
+
+		/*
 		 * Too small?  Give up.
 		 */
-		if (flen < minlen) {
+		if (dlen < minlen) {
 			trace_xfs_discard_toosmall(mp, agno, fbno, flen);
 			goto out_del_cursor;
 		}
@@ -99,8 +109,7 @@
 		 * supposed to discard skip it.  Do not bother to trim
 		 * down partially overlapping ranges for now.
 		 */
-		if (XFS_AGB_TO_FSB(mp, agno, fbno) + flen < start ||
-		    XFS_AGB_TO_FSB(mp, agno, fbno) > end) {
+		if (dbno + dlen < start || dbno > end) {
 			trace_xfs_discard_exclude(mp, agno, fbno, flen);
 			goto next_extent;
 		}
@@ -115,10 +124,7 @@
 		}
 
 		trace_xfs_discard_extent(mp, agno, fbno, flen);
-		error = -blkdev_issue_discard(bdev,
-				XFS_AGB_TO_DADDR(mp, agno, fbno),
-				XFS_FSB_TO_BB(mp, flen),
-				GFP_NOFS, 0);
+		error = -blkdev_issue_discard(bdev, dbno, dlen, GFP_NOFS, 0);
 		if (error)
 			goto out_del_cursor;
 		*blocks_trimmed += flen;
@@ -137,6 +143,15 @@
 	return error;
 }
 
+/*
+ * trim a range of the filesystem.
+ *
+ * Note: the parameters passed from userspace are byte ranges into the
+ * filesystem which does not match to the format we use for filesystem block
+ * addressing. FSB addressing is sparse (AGNO|AGBNO), while the incoming format
+ * is a linear address range. Hence we need to use DADDR based conversions and
+ * comparisons for determining the correct offset and regions to trim.
+ */
 int
 xfs_ioc_trim(
 	struct xfs_mount		*mp,
@@ -145,7 +160,7 @@
 	struct request_queue	*q = mp->m_ddev_targp->bt_bdev->bd_disk->queue;
 	unsigned int		granularity = q->limits.discard_granularity;
 	struct fstrim_range	range;
-	xfs_fsblock_t		start, end, minlen;
+	xfs_daddr_t		start, end, minlen;
 	xfs_agnumber_t		start_agno, end_agno, agno;
 	__uint64_t		blocks_trimmed = 0;
 	int			error, last_error = 0;
@@ -159,22 +174,22 @@
 
 	/*
 	 * Truncating down the len isn't actually quite correct, but using
-	 * XFS_B_TO_FSB would mean we trivially get overflows for values
+	 * BBTOB would mean we trivially get overflows for values
 	 * of ULLONG_MAX or slightly lower.  And ULLONG_MAX is the default
 	 * used by the fstrim application.  In the end it really doesn't
 	 * matter as trimming blocks is an advisory interface.
 	 */
-	start = XFS_B_TO_FSBT(mp, range.start);
-	end = start + XFS_B_TO_FSBT(mp, range.len) - 1;
-	minlen = XFS_B_TO_FSB(mp, max_t(u64, granularity, range.minlen));
+	start = BTOBB(range.start);
+	end = start + BTOBBT(range.len) - 1;
+	minlen = BTOBB(max_t(u64, granularity, range.minlen));
 
-	if (start >= mp->m_sb.sb_dblocks)
+	if (XFS_BB_TO_FSB(mp, start) >= mp->m_sb.sb_dblocks)
 		return -XFS_ERROR(EINVAL);
-	if (end > mp->m_sb.sb_dblocks - 1)
-		end = mp->m_sb.sb_dblocks - 1;
+	if (end > XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks) - 1)
+		end = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)- 1;
 
-	start_agno = XFS_FSB_TO_AGNO(mp, start);
-	end_agno = XFS_FSB_TO_AGNO(mp, end);
+	start_agno = xfs_daddr_to_agno(mp, start);
+	end_agno = xfs_daddr_to_agno(mp, end);
 
 	for (agno = start_agno; agno <= end_agno; agno++) {
 		error = -xfs_trim_extents(mp, agno, start, end, minlen,
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 53db20e..1155208 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -43,11 +43,10 @@
  * Lock order:
  *
  * ip->i_lock
- *   qh->qh_lock
- *     qi->qi_dqlist_lock
- *       dquot->q_qlock (xfs_dqlock() and friends)
- *         dquot->q_flush (xfs_dqflock() and friends)
- *         xfs_Gqm->qm_dqfrlist_lock
+ *   qi->qi_tree_lock
+ *     dquot->q_qlock (xfs_dqlock() and friends)
+ *       dquot->q_flush (xfs_dqflock() and friends)
+ *       qi->qi_lru_lock
  *
  * If two dquots need to be locked the order is user before group/project,
  * otherwise by the lowest id first, see xfs_dqlock2.
@@ -60,6 +59,9 @@
 int xfs_dqerror_mod = 33;
 #endif
 
+struct kmem_zone		*xfs_qm_dqtrxzone;
+static struct kmem_zone		*xfs_qm_dqzone;
+
 static struct lock_class_key xfs_dquot_other_class;
 
 /*
@@ -69,12 +71,12 @@
 xfs_qm_dqdestroy(
 	xfs_dquot_t	*dqp)
 {
-	ASSERT(list_empty(&dqp->q_freelist));
+	ASSERT(list_empty(&dqp->q_lru));
 
 	mutex_destroy(&dqp->q_qlock);
-	kmem_zone_free(xfs_Gqm->qm_dqzone, dqp);
+	kmem_zone_free(xfs_qm_dqzone, dqp);
 
-	atomic_dec(&xfs_Gqm->qm_totaldquots);
+	XFS_STATS_DEC(xs_qm_dquot);
 }
 
 /*
@@ -282,7 +284,7 @@
 	 * Return if this type of quotas is turned off while we didn't
 	 * have an inode lock
 	 */
-	if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
+	if (!xfs_this_quota_on(dqp->q_mount, dqp->dq_flags)) {
 		xfs_iunlock(quotip, XFS_ILOCK_EXCL);
 		return (ESRCH);
 	}
@@ -384,7 +386,7 @@
 	dqp->q_fileoffset = (xfs_fileoff_t)id / mp->m_quotainfo->qi_dqperchunk;
 
 	xfs_ilock(quotip, XFS_ILOCK_SHARED);
-	if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
+	if (!xfs_this_quota_on(dqp->q_mount, dqp->dq_flags)) {
 		/*
 		 * Return if this type of quotas is turned off while we
 		 * didn't have the quota inode lock.
@@ -492,12 +494,12 @@
 	int			cancelflags = 0;
 
 
-	dqp = kmem_zone_zalloc(xfs_Gqm->qm_dqzone, KM_SLEEP);
+	dqp = kmem_zone_zalloc(xfs_qm_dqzone, KM_SLEEP);
 
 	dqp->dq_flags = type;
 	dqp->q_core.d_id = cpu_to_be32(id);
 	dqp->q_mount = mp;
-	INIT_LIST_HEAD(&dqp->q_freelist);
+	INIT_LIST_HEAD(&dqp->q_lru);
 	mutex_init(&dqp->q_qlock);
 	init_waitqueue_head(&dqp->q_pinwait);
 
@@ -516,7 +518,7 @@
 	if (!(type & XFS_DQ_USER))
 		lockdep_set_class(&dqp->q_qlock, &xfs_dquot_other_class);
 
-	atomic_inc(&xfs_Gqm->qm_totaldquots);
+	XFS_STATS_INC(xs_qm_dquot);
 
 	trace_xfs_dqread(dqp);
 
@@ -602,60 +604,6 @@
 }
 
 /*
- * Lookup a dquot in the incore dquot hashtable. We keep two separate
- * hashtables for user and group dquots; and, these are global tables
- * inside the XQM, not per-filesystem tables.
- * The hash chain must be locked by caller, and it is left locked
- * on return. Returning dquot is locked.
- */
-STATIC int
-xfs_qm_dqlookup(
-	xfs_mount_t		*mp,
-	xfs_dqid_t		id,
-	xfs_dqhash_t		*qh,
-	xfs_dquot_t		**O_dqpp)
-{
-	xfs_dquot_t		*dqp;
-
-	ASSERT(mutex_is_locked(&qh->qh_lock));
-
-	/*
-	 * Traverse the hashchain looking for a match
-	 */
-	list_for_each_entry(dqp, &qh->qh_list, q_hashlist) {
-		/*
-		 * We already have the hashlock. We don't need the
-		 * dqlock to look at the id field of the dquot, since the
-		 * id can't be modified without the hashlock anyway.
-		 */
-		if (be32_to_cpu(dqp->q_core.d_id) != id || dqp->q_mount != mp)
-			continue;
-
-		trace_xfs_dqlookup_found(dqp);
-
-		xfs_dqlock(dqp);
-		if (dqp->dq_flags & XFS_DQ_FREEING) {
-			*O_dqpp = NULL;
-			xfs_dqunlock(dqp);
-			return -1;
-		}
-
-		dqp->q_nrefs++;
-
-		/*
-		 * move the dquot to the front of the hashchain
-		 */
-		list_move(&dqp->q_hashlist, &qh->qh_list);
-		trace_xfs_dqlookup_done(dqp);
-		*O_dqpp = dqp;
-		return 0;
-	}
-
-	*O_dqpp = NULL;
-	return 1;
-}
-
-/*
  * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a
  * a locked dquot, doing an allocation (if requested) as needed.
  * When both an inode and an id are given, the inode's id takes precedence.
@@ -672,10 +620,10 @@
 	uint		flags,	  /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */
 	xfs_dquot_t	**O_dqpp) /* OUT : locked incore dquot */
 {
-	xfs_dquot_t	*dqp;
-	xfs_dqhash_t	*h;
-	uint		version;
-	int		error;
+	struct xfs_quotainfo	*qi = mp->m_quotainfo;
+	struct radix_tree_root *tree = XFS_DQUOT_TREE(qi, type);
+	struct xfs_dquot	*dqp;
+	int			error;
 
 	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
 	if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) ||
@@ -683,7 +631,6 @@
 	    (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) {
 		return (ESRCH);
 	}
-	h = XFS_DQ_HASH(mp, id, type);
 
 #ifdef DEBUG
 	if (xfs_do_dqerror) {
@@ -699,42 +646,33 @@
 	       type == XFS_DQ_GROUP);
 	if (ip) {
 		ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-		if (type == XFS_DQ_USER)
-			ASSERT(ip->i_udquot == NULL);
-		else
-			ASSERT(ip->i_gdquot == NULL);
+		ASSERT(xfs_inode_dquot(ip, type) == NULL);
 	}
 #endif
 
 restart:
-	mutex_lock(&h->qh_lock);
+	mutex_lock(&qi->qi_tree_lock);
+	dqp = radix_tree_lookup(tree, id);
+	if (dqp) {
+		xfs_dqlock(dqp);
+		if (dqp->dq_flags & XFS_DQ_FREEING) {
+			xfs_dqunlock(dqp);
+			mutex_unlock(&qi->qi_tree_lock);
+			trace_xfs_dqget_freeing(dqp);
+			delay(1);
+			goto restart;
+		}
 
-	/*
-	 * Look in the cache (hashtable).
-	 * The chain is kept locked during lookup.
-	 */
-	switch (xfs_qm_dqlookup(mp, id, h, O_dqpp)) {
-	case -1:
-		XQM_STATS_INC(xqmstats.xs_qm_dquot_dups);
-		mutex_unlock(&h->qh_lock);
-		delay(1);
-		goto restart;
-	case 0:
-		XQM_STATS_INC(xqmstats.xs_qm_dqcachehits);
-		/*
-		 * The dquot was found, moved to the front of the chain,
-		 * taken off the freelist if it was on it, and locked
-		 * at this point. Just unlock the hashchain and return.
-		 */
-		ASSERT(*O_dqpp);
-		ASSERT(XFS_DQ_IS_LOCKED(*O_dqpp));
-		mutex_unlock(&h->qh_lock);
-		trace_xfs_dqget_hit(*O_dqpp);
-		return 0;	/* success */
-	default:
-		XQM_STATS_INC(xqmstats.xs_qm_dqcachemisses);
-		break;
+		dqp->q_nrefs++;
+		mutex_unlock(&qi->qi_tree_lock);
+
+		trace_xfs_dqget_hit(dqp);
+		XFS_STATS_INC(xs_qm_dqcachehits);
+		*O_dqpp = dqp;
+		return 0;
 	}
+	mutex_unlock(&qi->qi_tree_lock);
+	XFS_STATS_INC(xs_qm_dqcachemisses);
 
 	/*
 	 * Dquot cache miss. We don't want to keep the inode lock across
@@ -745,12 +683,6 @@
 	 */
 	if (ip)
 		xfs_iunlock(ip, XFS_ILOCK_EXCL);
-	/*
-	 * Save the hashchain version stamp, and unlock the chain, so that
-	 * we don't keep the lock across a disk read
-	 */
-	version = h->qh_version;
-	mutex_unlock(&h->qh_lock);
 
 	error = xfs_qm_dqread(mp, id, type, flags, &dqp);
 
@@ -760,86 +692,43 @@
 	if (error)
 		return error;
 
-	/*
-	 * Dquot lock comes after hashlock in the lock ordering
-	 */
 	if (ip) {
 		/*
 		 * A dquot could be attached to this inode by now, since
 		 * we had dropped the ilock.
 		 */
-		if (type == XFS_DQ_USER) {
-			if (!XFS_IS_UQUOTA_ON(mp)) {
-				/* inode stays locked on return */
+		if (xfs_this_quota_on(mp, type)) {
+			struct xfs_dquot	*dqp1;
+
+			dqp1 = xfs_inode_dquot(ip, type);
+			if (dqp1) {
 				xfs_qm_dqdestroy(dqp);
-				return XFS_ERROR(ESRCH);
-			}
-			if (ip->i_udquot) {
-				xfs_qm_dqdestroy(dqp);
-				dqp = ip->i_udquot;
+				dqp = dqp1;
 				xfs_dqlock(dqp);
 				goto dqret;
 			}
 		} else {
-			if (!XFS_IS_OQUOTA_ON(mp)) {
-				/* inode stays locked on return */
-				xfs_qm_dqdestroy(dqp);
-				return XFS_ERROR(ESRCH);
-			}
-			if (ip->i_gdquot) {
-				xfs_qm_dqdestroy(dqp);
-				dqp = ip->i_gdquot;
-				xfs_dqlock(dqp);
-				goto dqret;
-			}
-		}
-	}
-
-	/*
-	 * Hashlock comes after ilock in lock order
-	 */
-	mutex_lock(&h->qh_lock);
-	if (version != h->qh_version) {
-		xfs_dquot_t *tmpdqp;
-		/*
-		 * Now, see if somebody else put the dquot in the
-		 * hashtable before us. This can happen because we didn't
-		 * keep the hashchain lock. We don't have to worry about
-		 * lock order between the two dquots here since dqp isn't
-		 * on any findable lists yet.
-		 */
-		switch (xfs_qm_dqlookup(mp, id, h, &tmpdqp)) {
-		case 0:
-		case -1:
-			/*
-			 * Duplicate found, either in cache or on its way out.
-			 * Just throw away the new dquot and start over.
-			 */
-			if (tmpdqp)
-				xfs_qm_dqput(tmpdqp);
-			mutex_unlock(&h->qh_lock);
+			/* inode stays locked on return */
 			xfs_qm_dqdestroy(dqp);
-			XQM_STATS_INC(xqmstats.xs_qm_dquot_dups);
-			goto restart;
-		default:
-			break;
+			return XFS_ERROR(ESRCH);
 		}
 	}
 
-	/*
-	 * Put the dquot at the beginning of the hash-chain and mp's list
-	 * LOCK ORDER: hashlock, freelistlock, mplistlock, udqlock, gdqlock ..
-	 */
-	ASSERT(mutex_is_locked(&h->qh_lock));
-	dqp->q_hash = h;
-	list_add(&dqp->q_hashlist, &h->qh_list);
-	h->qh_version++;
+	mutex_lock(&qi->qi_tree_lock);
+	error = -radix_tree_insert(tree, id, dqp);
+	if (unlikely(error)) {
+		WARN_ON(error != EEXIST);
 
-	/*
-	 * Attach this dquot to this filesystem's list of all dquots,
-	 * kept inside the mount structure in m_quotainfo field
-	 */
-	mutex_lock(&mp->m_quotainfo->qi_dqlist_lock);
+		/*
+		 * Duplicate found. Just throw away the new dquot and start
+		 * over.
+		 */
+		mutex_unlock(&qi->qi_tree_lock);
+		trace_xfs_dqget_dup(dqp);
+		xfs_qm_dqdestroy(dqp);
+		XFS_STATS_INC(xs_qm_dquot_dups);
+		goto restart;
+	}
 
 	/*
 	 * We return a locked dquot to the caller, with a reference taken
@@ -847,10 +736,9 @@
 	xfs_dqlock(dqp);
 	dqp->q_nrefs = 1;
 
-	list_add(&dqp->q_mplist, &mp->m_quotainfo->qi_dqlist);
-	mp->m_quotainfo->qi_dquots++;
-	mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
-	mutex_unlock(&h->qh_lock);
+	qi->qi_dquots++;
+	mutex_unlock(&qi->qi_tree_lock);
+
  dqret:
 	ASSERT((ip == NULL) || xfs_isilocked(ip, XFS_ILOCK_EXCL));
 	trace_xfs_dqget_miss(dqp);
@@ -859,37 +747,22 @@
 }
 
 
-/*
- * Release a reference to the dquot (decrement ref-count)
- * and unlock it. If there is a group quota attached to this
- * dquot, carefully release that too without tripping over
- * deadlocks'n'stuff.
- */
-void
-xfs_qm_dqput(
+STATIC void
+xfs_qm_dqput_final(
 	struct xfs_dquot	*dqp)
 {
+	struct xfs_quotainfo	*qi = dqp->q_mount->m_quotainfo;
 	struct xfs_dquot	*gdqp;
 
-	ASSERT(dqp->q_nrefs > 0);
-	ASSERT(XFS_DQ_IS_LOCKED(dqp));
-
-	trace_xfs_dqput(dqp);
-
-recurse:
-	if (--dqp->q_nrefs > 0) {
-		xfs_dqunlock(dqp);
-		return;
-	}
-
 	trace_xfs_dqput_free(dqp);
 
-	mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
-	if (list_empty(&dqp->q_freelist)) {
-		list_add_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist);
-		xfs_Gqm->qm_dqfrlist_cnt++;
+	mutex_lock(&qi->qi_lru_lock);
+	if (list_empty(&dqp->q_lru)) {
+		list_add_tail(&dqp->q_lru, &qi->qi_lru_list);
+		qi->qi_lru_count++;
+		XFS_STATS_INC(xs_qm_dquot_unused);
 	}
-	mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
+	mutex_unlock(&qi->qi_lru_lock);
 
 	/*
 	 * If we just added a udquot to the freelist, then we want to release
@@ -906,10 +779,29 @@
 	/*
 	 * If we had a group quota hint, release it now.
 	 */
-	if (gdqp) {
-		dqp = gdqp;
-		goto recurse;
-	}
+	if (gdqp)
+		xfs_qm_dqput(gdqp);
+}
+
+/*
+ * Release a reference to the dquot (decrement ref-count) and unlock it.
+ *
+ * If there is a group quota attached to this dquot, carefully release that
+ * too without tripping over deadlocks'n'stuff.
+ */
+void
+xfs_qm_dqput(
+	struct xfs_dquot	*dqp)
+{
+	ASSERT(dqp->q_nrefs > 0);
+	ASSERT(XFS_DQ_IS_LOCKED(dqp));
+
+	trace_xfs_dqput(dqp);
+
+	if (--dqp->q_nrefs > 0)
+		xfs_dqunlock(dqp);
+	else
+		xfs_qm_dqput_final(dqp);
 }
 
 /*
@@ -1091,17 +983,6 @@
 
 }
 
-void
-xfs_dqunlock(
-	xfs_dquot_t *dqp)
-{
-	xfs_dqunlock_nonotify(dqp);
-	if (dqp->q_logitem.qli_dquot == dqp) {
-		xfs_trans_unlocked_item(dqp->q_logitem.qli_item.li_ailp,
-					&dqp->q_logitem.qli_item);
-	}
-}
-
 /*
  * Lock two xfs_dquot structures.
  *
@@ -1131,85 +1012,6 @@
 }
 
 /*
- * Take a dquot out of the mount's dqlist as well as the hashlist.  This is
- * called via unmount as well as quotaoff, and the purge will always succeed.
- */
-void
-xfs_qm_dqpurge(
-	struct xfs_dquot	*dqp)
-{
-	struct xfs_mount	*mp = dqp->q_mount;
-	struct xfs_dqhash	*qh = dqp->q_hash;
-
-	xfs_dqlock(dqp);
-
-	/*
-	 * If we're turning off quotas, we have to make sure that, for
-	 * example, we don't delete quota disk blocks while dquots are
-	 * in the process of getting written to those disk blocks.
-	 * This dquot might well be on AIL, and we can't leave it there
-	 * if we're turning off quotas. Basically, we need this flush
-	 * lock, and are willing to block on it.
-	 */
-	if (!xfs_dqflock_nowait(dqp)) {
-		/*
-		 * Block on the flush lock after nudging dquot buffer,
-		 * if it is incore.
-		 */
-		xfs_dqflock_pushbuf_wait(dqp);
-	}
-
-	/*
-	 * If we are turning this type of quotas off, we don't care
-	 * about the dirty metadata sitting in this dquot. OTOH, if
-	 * we're unmounting, we do care, so we flush it and wait.
-	 */
-	if (XFS_DQ_IS_DIRTY(dqp)) {
-		int	error;
-
-		/*
-		 * We don't care about getting disk errors here. We need
-		 * to purge this dquot anyway, so we go ahead regardless.
-		 */
-		error = xfs_qm_dqflush(dqp, SYNC_WAIT);
-		if (error)
-			xfs_warn(mp, "%s: dquot %p flush failed",
-				__func__, dqp);
-		xfs_dqflock(dqp);
-	}
-
-	ASSERT(atomic_read(&dqp->q_pincount) == 0);
-	ASSERT(XFS_FORCED_SHUTDOWN(mp) ||
-	       !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL));
-
-	xfs_dqfunlock(dqp);
-	xfs_dqunlock(dqp);
-
-	mutex_lock(&qh->qh_lock);
-	list_del_init(&dqp->q_hashlist);
-	qh->qh_version++;
-	mutex_unlock(&qh->qh_lock);
-
-	mutex_lock(&mp->m_quotainfo->qi_dqlist_lock);
-	list_del_init(&dqp->q_mplist);
-	mp->m_quotainfo->qi_dqreclaims++;
-	mp->m_quotainfo->qi_dquots--;
-	mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
-
-	/*
-	 * We move dquots to the freelist as soon as their reference count
-	 * hits zero, so it really should be on the freelist here.
-	 */
-	mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
-	ASSERT(!list_empty(&dqp->q_freelist));
-	list_del_init(&dqp->q_freelist);
-	xfs_Gqm->qm_dqfrlist_cnt--;
-	mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
-
-	xfs_qm_dqdestroy(dqp);
-}
-
-/*
  * Give the buffer a little push if it is incore and
  * wait on the flush lock.
  */
@@ -1241,3 +1043,31 @@
 out_lock:
 	xfs_dqflock(dqp);
 }
+
+int __init
+xfs_qm_init(void)
+{
+	xfs_qm_dqzone =
+		kmem_zone_init(sizeof(struct xfs_dquot), "xfs_dquot");
+	if (!xfs_qm_dqzone)
+		goto out;
+
+	xfs_qm_dqtrxzone =
+		kmem_zone_init(sizeof(struct xfs_dquot_acct), "xfs_dqtrx");
+	if (!xfs_qm_dqtrxzone)
+		goto out_free_dqzone;
+
+	return 0;
+
+out_free_dqzone:
+	kmem_zone_destroy(xfs_qm_dqzone);
+out:
+	return -ENOMEM;
+}
+
+void
+xfs_qm_exit(void)
+{
+	kmem_zone_destroy(xfs_qm_dqtrxzone);
+	kmem_zone_destroy(xfs_qm_dqzone);
+}
diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h
index a1d91d8..ef9190b 100644
--- a/fs/xfs/xfs_dquot.h
+++ b/fs/xfs/xfs_dquot.h
@@ -29,16 +29,6 @@
  * when quotas are off.
  */
 
-/*
- * The hash chain headers (hash buckets)
- */
-typedef struct xfs_dqhash {
-	struct list_head  qh_list;
-	struct mutex	  qh_lock;
-	uint		  qh_version;	/* ever increasing version */
-	uint		  qh_nelems;	/* number of dquots on the list */
-} xfs_dqhash_t;
-
 struct xfs_mount;
 struct xfs_trans;
 
@@ -47,10 +37,7 @@
  */
 typedef struct xfs_dquot {
 	uint		 dq_flags;	/* various flags (XFS_DQ_*) */
-	struct list_head q_freelist;	/* global free list of dquots */
-	struct list_head q_mplist;	/* mount's list of dquots */
-	struct list_head q_hashlist;	/* gloabl hash list of dquots */
-	xfs_dqhash_t	*q_hash;	/* the hashchain header */
+	struct list_head q_lru;		/* global free list of dquots */
 	struct xfs_mount*q_mount;	/* filesystem this relates to */
 	struct xfs_trans*q_transp;	/* trans this belongs to currently */
 	uint		 q_nrefs;	/* # active refs from inodes */
@@ -110,11 +97,37 @@
 	mutex_lock(&dqp->q_qlock);
 }
 
-static inline void xfs_dqunlock_nonotify(struct xfs_dquot *dqp)
+static inline void xfs_dqunlock(struct xfs_dquot *dqp)
 {
 	mutex_unlock(&dqp->q_qlock);
 }
 
+static inline int xfs_this_quota_on(struct xfs_mount *mp, int type)
+{
+	switch (type & XFS_DQ_ALLTYPES) {
+	case XFS_DQ_USER:
+		return XFS_IS_UQUOTA_ON(mp);
+	case XFS_DQ_GROUP:
+	case XFS_DQ_PROJ:
+		return XFS_IS_OQUOTA_ON(mp);
+	default:
+		return 0;
+	}
+}
+
+static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type)
+{
+	switch (type & XFS_DQ_ALLTYPES) {
+	case XFS_DQ_USER:
+		return ip->i_udquot;
+	case XFS_DQ_GROUP:
+	case XFS_DQ_PROJ:
+		return ip->i_gdquot;
+	default:
+		return NULL;
+	}
+}
+
 #define XFS_DQ_IS_LOCKED(dqp)	(mutex_is_locked(&((dqp)->q_qlock)))
 #define XFS_DQ_IS_DIRTY(dqp)	((dqp)->dq_flags & XFS_DQ_DIRTY)
 #define XFS_QM_ISUDQ(dqp)	((dqp)->dq_flags & XFS_DQ_USER)
@@ -125,15 +138,10 @@
 				 XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \
 				 XFS_DQ_TO_QINF(dqp)->qi_gquotaip)
 
-#define XFS_IS_THIS_QUOTA_OFF(d) (! (XFS_QM_ISUDQ(d) ? \
-				     (XFS_IS_UQUOTA_ON((d)->q_mount)) : \
-				     (XFS_IS_OQUOTA_ON((d)->q_mount))))
-
 extern int		xfs_qm_dqread(struct xfs_mount *, xfs_dqid_t, uint,
 					uint, struct xfs_dquot	**);
 extern void		xfs_qm_dqdestroy(xfs_dquot_t *);
 extern int		xfs_qm_dqflush(xfs_dquot_t *, uint);
-extern void		xfs_qm_dqpurge(xfs_dquot_t *);
 extern void		xfs_qm_dqunpin_wait(xfs_dquot_t *);
 extern void		xfs_qm_adjust_dqtimers(xfs_mount_t *,
 					xfs_disk_dquot_t *);
@@ -144,7 +152,6 @@
 extern void		xfs_qm_dqput(xfs_dquot_t *);
 
 extern void		xfs_dqlock2(struct xfs_dquot *, struct xfs_dquot *);
-extern void		xfs_dqunlock(struct xfs_dquot *);
 extern void		xfs_dqflock_pushbuf_wait(struct xfs_dquot *dqp);
 
 static inline struct xfs_dquot *xfs_qm_dqhold(struct xfs_dquot *dqp)
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 7e5bc87..54a67dd 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -163,7 +163,6 @@
 	struct inode		*inode = file->f_mapping->host;
 	struct xfs_inode	*ip = XFS_I(inode);
 	struct xfs_mount	*mp = ip->i_mount;
-	struct xfs_trans	*tp;
 	int			error = 0;
 	int			log_flushed = 0;
 	xfs_lsn_t		lsn = 0;
@@ -194,75 +193,18 @@
 	}
 
 	/*
-	 * We always need to make sure that the required inode state is safe on
-	 * disk.  The inode might be clean but we still might need to force the
-	 * log because of committed transactions that haven't hit the disk yet.
-	 * Likewise, there could be unflushed non-transactional changes to the
-	 * inode core that have to go to disk and this requires us to issue
-	 * a synchronous transaction to capture these changes correctly.
-	 *
-	 * This code relies on the assumption that if the i_update_core field
-	 * of the inode is clear and the inode is unpinned then it is clean
-	 * and no action is required.
+	 * All metadata updates are logged, which means that we just have
+	 * to flush the log up to the latest LSN that touched the inode.
 	 */
 	xfs_ilock(ip, XFS_ILOCK_SHARED);
-
-	/*
-	 * First check if the VFS inode is marked dirty.  All the dirtying
-	 * of non-transactional updates do not go through mark_inode_dirty*,
-	 * which allows us to distinguish between pure timestamp updates
-	 * and i_size updates which need to be caught for fdatasync.
-	 * After that also check for the dirty state in the XFS inode, which
-	 * might gets cleared when the inode gets written out via the AIL
-	 * or xfs_iflush_cluster.
-	 */
-	if (((inode->i_state & I_DIRTY_DATASYNC) ||
-	    ((inode->i_state & I_DIRTY_SYNC) && !datasync)) &&
-	    ip->i_update_core) {
-		/*
-		 * Kick off a transaction to log the inode core to get the
-		 * updates.  The sync transaction will also force the log.
-		 */
-		xfs_iunlock(ip, XFS_ILOCK_SHARED);
-		tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
-		error = xfs_trans_reserve(tp, 0,
-				XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
-		if (error) {
-			xfs_trans_cancel(tp, 0);
-			return -error;
-		}
-		xfs_ilock(ip, XFS_ILOCK_EXCL);
-
-		/*
-		 * Note - it's possible that we might have pushed ourselves out
-		 * of the way during trans_reserve which would flush the inode.
-		 * But there's no guarantee that the inode buffer has actually
-		 * gone out yet (it's delwri).	Plus the buffer could be pinned
-		 * anyway if it's part of an inode in another recent
-		 * transaction.	 So we play it safe and fire off the
-		 * transaction anyway.
-		 */
-		xfs_trans_ijoin(tp, ip, 0);
-		xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-		error = xfs_trans_commit(tp, 0);
-
-		lsn = ip->i_itemp->ili_last_lsn;
-		xfs_iunlock(ip, XFS_ILOCK_EXCL);
-	} else {
-		/*
-		 * Timestamps/size haven't changed since last inode flush or
-		 * inode transaction commit.  That means either nothing got
-		 * written or a transaction committed which caught the updates.
-		 * If the latter happened and the transaction hasn't hit the
-		 * disk yet, the inode will be still be pinned.  If it is,
-		 * force the log.
-		 */
-		if (xfs_ipincount(ip))
+	if (xfs_ipincount(ip)) {
+		if (!datasync ||
+		    (ip->i_itemp->ili_fields & ~XFS_ILOG_TIMESTAMP))
 			lsn = ip->i_itemp->ili_last_lsn;
-		xfs_iunlock(ip, XFS_ILOCK_SHARED);
 	}
+	xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
-	if (!error && lsn)
+	if (lsn)
 		error = _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, &log_flushed);
 
 	/*
@@ -659,9 +601,6 @@
 		return error;
 	}
 
-	if (likely(!(file->f_mode & FMODE_NOCMTIME)))
-		file_update_time(file);
-
 	/*
 	 * If the offset is beyond the size of the file, we need to zero any
 	 * blocks that fall between the existing EOF and the start of this
@@ -685,6 +624,15 @@
 		return error;
 
 	/*
+	 * Updating the timestamps will grab the ilock again from
+	 * xfs_fs_dirty_inode, so we have to call it after dropping the
+	 * lock above.  Eventually we should look into a way to avoid
+	 * the pointless lock roundtrip.
+	 */
+	if (likely(!(file->f_mode & FMODE_NOCMTIME)))
+		file_update_time(file);
+
+	/*
 	 * If we're writing the file then make sure to clear the setuid and
 	 * setgid bits if the process is not being run by root.  This keeps
 	 * people from modifying setuid and setgid binaries.
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index 8c3e463..bcc6c24 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -91,7 +91,6 @@
 	ip->i_afp = NULL;
 	memset(&ip->i_df, 0, sizeof(xfs_ifork_t));
 	ip->i_flags = 0;
-	ip->i_update_core = 0;
 	ip->i_delayed_blks = 0;
 	memset(&ip->i_d, 0, sizeof(xfs_icdinode_t));
 
@@ -290,7 +289,7 @@
 	if (lock_flags != 0)
 		xfs_ilock(ip, lock_flags);
 
-	xfs_iflags_clear(ip, XFS_ISTALE);
+	xfs_iflags_clear(ip, XFS_ISTALE | XFS_IDONTCACHE);
 	XFS_STATS_INC(xs_ig_found);
 
 	return 0;
@@ -315,6 +314,7 @@
 	struct xfs_inode	*ip;
 	int			error;
 	xfs_agino_t		agino = XFS_INO_TO_AGINO(mp, ino);
+	int			iflags;
 
 	ip = xfs_inode_alloc(mp, ino);
 	if (!ip)
@@ -350,9 +350,23 @@
 			BUG();
 	}
 
-	spin_lock(&pag->pag_ici_lock);
+	/*
+	 * These values must be set before inserting the inode into the radix
+	 * tree as the moment it is inserted a concurrent lookup (allowed by the
+	 * RCU locking mechanism) can find it and that lookup must see that this
+	 * is an inode currently under construction (i.e. that XFS_INEW is set).
+	 * The ip->i_flags_lock that protects the XFS_INEW flag forms the
+	 * memory barrier that ensures this detection works correctly at lookup
+	 * time.
+	 */
+	iflags = XFS_INEW;
+	if (flags & XFS_IGET_DONTCACHE)
+		iflags |= XFS_IDONTCACHE;
+	ip->i_udquot = ip->i_gdquot = NULL;
+	xfs_iflags_set(ip, iflags);
 
 	/* insert the new inode */
+	spin_lock(&pag->pag_ici_lock);
 	error = radix_tree_insert(&pag->pag_ici_root, agino, ip);
 	if (unlikely(error)) {
 		WARN_ON(error != -EEXIST);
@@ -360,11 +374,6 @@
 		error = EAGAIN;
 		goto out_preload_end;
 	}
-
-	/* These values _must_ be set before releasing the radix tree lock! */
-	ip->i_udquot = ip->i_gdquot = NULL;
-	xfs_iflags_set(ip, XFS_INEW);
-
 	spin_unlock(&pag->pag_ici_lock);
 	radix_tree_preload_end();
 
@@ -418,6 +427,15 @@
 	xfs_perag_t	*pag;
 	xfs_agino_t	agino;
 
+	/*
+	 * xfs_reclaim_inode() uses the ILOCK to ensure an inode
+	 * doesn't get freed while it's being referenced during a
+	 * radix tree traversal here.  It assumes this function
+	 * aqcuires only the ILOCK (and therefore it has no need to
+	 * involve the IOLOCK in this synchronization).
+	 */
+	ASSERT((lock_flags & (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED)) == 0);
+
 	/* reject inode numbers outside existing AGs */
 	if (!ino || XFS_INO_TO_AGNO(mp, ino) >= mp->m_sb.sb_agcount)
 		return EINVAL;
@@ -642,8 +660,7 @@
 	       (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
 	ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
 	       (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
-	ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_IUNLOCK_NONOTIFY |
-			XFS_LOCK_DEP_MASK)) == 0);
+	ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
 	ASSERT(lock_flags != 0);
 
 	if (lock_flags & XFS_IOLOCK_EXCL)
@@ -656,16 +673,6 @@
 	else if (lock_flags & XFS_ILOCK_SHARED)
 		mrunlock_shared(&ip->i_lock);
 
-	if ((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) &&
-	    !(lock_flags & XFS_IUNLOCK_NONOTIFY) && ip->i_itemp) {
-		/*
-		 * Let the AIL know that this item has been unlocked in case
-		 * it is in the AIL and anyone is waiting on it.  Don't do
-		 * this if the caller has asked us not to.
-		 */
-		xfs_trans_unlocked_item(ip->i_itemp->ili_item.li_ailp,
-					(xfs_log_item_t*)(ip->i_itemp));
-	}
 	trace_xfs_iunlock(ip, lock_flags, _RET_IP_);
 }
 
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index b210224..bc46c0a 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1656,14 +1656,13 @@
 			iip = ip->i_itemp;
 			if (!iip || xfs_inode_clean(ip)) {
 				ASSERT(ip != free_ip);
-				ip->i_update_core = 0;
 				xfs_ifunlock(ip);
 				xfs_iunlock(ip, XFS_ILOCK_EXCL);
 				continue;
 			}
 
-			iip->ili_last_fields = iip->ili_format.ilf_fields;
-			iip->ili_format.ilf_fields = 0;
+			iip->ili_last_fields = iip->ili_fields;
+			iip->ili_fields = 0;
 			iip->ili_logged = 1;
 			xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,
 						&iip->ili_item.li_lsn);
@@ -2177,7 +2176,7 @@
 	mp = ip->i_mount;
 	switch (XFS_IFORK_FORMAT(ip, whichfork)) {
 	case XFS_DINODE_FMT_LOCAL:
-		if ((iip->ili_format.ilf_fields & dataflag[whichfork]) &&
+		if ((iip->ili_fields & dataflag[whichfork]) &&
 		    (ifp->if_bytes > 0)) {
 			ASSERT(ifp->if_u1.if_data != NULL);
 			ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
@@ -2187,8 +2186,8 @@
 
 	case XFS_DINODE_FMT_EXTENTS:
 		ASSERT((ifp->if_flags & XFS_IFEXTENTS) ||
-		       !(iip->ili_format.ilf_fields & extflag[whichfork]));
-		if ((iip->ili_format.ilf_fields & extflag[whichfork]) &&
+		       !(iip->ili_fields & extflag[whichfork]));
+		if ((iip->ili_fields & extflag[whichfork]) &&
 		    (ifp->if_bytes > 0)) {
 			ASSERT(xfs_iext_get_ext(ifp, 0));
 			ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0);
@@ -2198,7 +2197,7 @@
 		break;
 
 	case XFS_DINODE_FMT_BTREE:
-		if ((iip->ili_format.ilf_fields & brootflag[whichfork]) &&
+		if ((iip->ili_fields & brootflag[whichfork]) &&
 		    (ifp->if_broot_bytes > 0)) {
 			ASSERT(ifp->if_broot != NULL);
 			ASSERT(ifp->if_broot_bytes <=
@@ -2211,14 +2210,14 @@
 		break;
 
 	case XFS_DINODE_FMT_DEV:
-		if (iip->ili_format.ilf_fields & XFS_ILOG_DEV) {
+		if (iip->ili_fields & XFS_ILOG_DEV) {
 			ASSERT(whichfork == XFS_DATA_FORK);
 			xfs_dinode_put_rdev(dip, ip->i_df.if_u2.if_rdev);
 		}
 		break;
 
 	case XFS_DINODE_FMT_UUID:
-		if (iip->ili_format.ilf_fields & XFS_ILOG_UUID) {
+		if (iip->ili_fields & XFS_ILOG_UUID) {
 			ASSERT(whichfork == XFS_DATA_FORK);
 			memcpy(XFS_DFORK_DPTR(dip),
 			       &ip->i_df.if_u2.if_uuid,
@@ -2451,9 +2450,8 @@
 	 * to disk, because the log record didn't make it to disk!
 	 */
 	if (XFS_FORCED_SHUTDOWN(mp)) {
-		ip->i_update_core = 0;
 		if (iip)
-			iip->ili_format.ilf_fields = 0;
+			iip->ili_fields = 0;
 		xfs_ifunlock(ip);
 		return XFS_ERROR(EIO);
 	}
@@ -2533,26 +2531,6 @@
 	/* set *dip = inode's place in the buffer */
 	dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);
 
-	/*
-	 * Clear i_update_core before copying out the data.
-	 * This is for coordination with our timestamp updates
-	 * that don't hold the inode lock. They will always
-	 * update the timestamps BEFORE setting i_update_core,
-	 * so if we clear i_update_core after they set it we
-	 * are guaranteed to see their updates to the timestamps.
-	 * I believe that this depends on strongly ordered memory
-	 * semantics, but we have that.  We use the SYNCHRONIZE
-	 * macro to make sure that the compiler does not reorder
-	 * the i_update_core access below the data copy below.
-	 */
-	ip->i_update_core = 0;
-	SYNCHRONIZE();
-
-	/*
-	 * Make sure to get the latest timestamps from the Linux inode.
-	 */
-	xfs_synchronize_times(ip);
-
 	if (XFS_TEST_ERROR(dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC),
 			       mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) {
 		xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
@@ -2663,36 +2641,33 @@
 	xfs_inobp_check(mp, bp);
 
 	/*
-	 * We've recorded everything logged in the inode, so we'd
-	 * like to clear the ilf_fields bits so we don't log and
-	 * flush things unnecessarily.  However, we can't stop
-	 * logging all this information until the data we've copied
-	 * into the disk buffer is written to disk.  If we did we might
-	 * overwrite the copy of the inode in the log with all the
-	 * data after re-logging only part of it, and in the face of
-	 * a crash we wouldn't have all the data we need to recover.
+	 * We've recorded everything logged in the inode, so we'd like to clear
+	 * the ili_fields bits so we don't log and flush things unnecessarily.
+	 * However, we can't stop logging all this information until the data
+	 * we've copied into the disk buffer is written to disk.  If we did we
+	 * might overwrite the copy of the inode in the log with all the data
+	 * after re-logging only part of it, and in the face of a crash we
+	 * wouldn't have all the data we need to recover.
 	 *
-	 * What we do is move the bits to the ili_last_fields field.
-	 * When logging the inode, these bits are moved back to the
-	 * ilf_fields field.  In the xfs_iflush_done() routine we
-	 * clear ili_last_fields, since we know that the information
-	 * those bits represent is permanently on disk.  As long as
-	 * the flush completes before the inode is logged again, then
-	 * both ilf_fields and ili_last_fields will be cleared.
+	 * What we do is move the bits to the ili_last_fields field.  When
+	 * logging the inode, these bits are moved back to the ili_fields field.
+	 * In the xfs_iflush_done() routine we clear ili_last_fields, since we
+	 * know that the information those bits represent is permanently on
+	 * disk.  As long as the flush completes before the inode is logged
+	 * again, then both ili_fields and ili_last_fields will be cleared.
 	 *
-	 * We can play with the ilf_fields bits here, because the inode
-	 * lock must be held exclusively in order to set bits there
-	 * and the flush lock protects the ili_last_fields bits.
-	 * Set ili_logged so the flush done
-	 * routine can tell whether or not to look in the AIL.
-	 * Also, store the current LSN of the inode so that we can tell
-	 * whether the item has moved in the AIL from xfs_iflush_done().
-	 * In order to read the lsn we need the AIL lock, because
-	 * it is a 64 bit value that cannot be read atomically.
+	 * We can play with the ili_fields bits here, because the inode lock
+	 * must be held exclusively in order to set bits there and the flush
+	 * lock protects the ili_last_fields bits.  Set ili_logged so the flush
+	 * done routine can tell whether or not to look in the AIL.  Also, store
+	 * the current LSN of the inode so that we can tell whether the item has
+	 * moved in the AIL from xfs_iflush_done().  In order to read the lsn we
+	 * need the AIL lock, because it is a 64 bit value that cannot be read
+	 * atomically.
 	 */
-	if (iip != NULL && iip->ili_format.ilf_fields != 0) {
-		iip->ili_last_fields = iip->ili_format.ilf_fields;
-		iip->ili_format.ilf_fields = 0;
+	if (iip != NULL && iip->ili_fields != 0) {
+		iip->ili_last_fields = iip->ili_fields;
+		iip->ili_fields = 0;
 		iip->ili_logged = 1;
 
 		xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,
@@ -2711,8 +2686,7 @@
 	} else {
 		/*
 		 * We're flushing an inode which is not in the AIL and has
-		 * not been logged but has i_update_core set.  For this
-		 * case we can use a B_DELWRI flush and immediately drop
+		 * not been logged.  For this case we can immediately drop
 		 * the inode flush lock because we can avoid the whole
 		 * AIL state thing.  It's OK to drop the flush lock now,
 		 * because we've already locked the buffer and to do anything
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 2f27b74..7fee338 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -241,7 +241,6 @@
 	spinlock_t		i_flags_lock;	/* inode i_flags lock */
 	/* Miscellaneous state. */
 	unsigned long		i_flags;	/* see defined flags below */
-	unsigned char		i_update_core;	/* timestamps/size is dirty */
 	unsigned int		i_delayed_blks;	/* count of delay alloc blks */
 
 	xfs_icdinode_t		i_d;		/* most of ondisk inode */
@@ -275,6 +274,20 @@
 }
 
 /*
+ * If this I/O goes past the on-disk inode size update it unless it would
+ * be past the current in-core inode size.
+ */
+static inline xfs_fsize_t
+xfs_new_eof(struct xfs_inode *ip, xfs_fsize_t new_size)
+{
+	xfs_fsize_t i_size = i_size_read(VFS_I(ip));
+
+	if (new_size > i_size)
+		new_size = i_size;
+	return new_size > ip->i_d.di_size ? new_size : 0;
+}
+
+/*
  * i_flags helper functions
  */
 static inline void
@@ -374,10 +387,11 @@
 #define XFS_IFLOCK		(1 << __XFS_IFLOCK_BIT)
 #define __XFS_IPINNED_BIT	8	 /* wakeup key for zero pin count */
 #define XFS_IPINNED		(1 << __XFS_IPINNED_BIT)
+#define XFS_IDONTCACHE		(1 << 9) /* don't cache the inode long term */
 
 /*
  * Per-lifetime flags need to be reset when re-using a reclaimable inode during
- * inode lookup. Thi prevents unintended behaviour on the new inode from
+ * inode lookup. This prevents unintended behaviour on the new inode from
  * ocurring.
  */
 #define XFS_IRECLAIM_RESET_FLAGS	\
@@ -422,7 +436,6 @@
 #define	XFS_IOLOCK_SHARED	(1<<1)
 #define	XFS_ILOCK_EXCL		(1<<2)
 #define	XFS_ILOCK_SHARED	(1<<3)
-#define	XFS_IUNLOCK_NONOTIFY	(1<<4)
 
 #define XFS_LOCK_MASK		(XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED \
 				| XFS_ILOCK_EXCL | XFS_ILOCK_SHARED)
@@ -431,8 +444,7 @@
 	{ XFS_IOLOCK_EXCL,	"IOLOCK_EXCL" }, \
 	{ XFS_IOLOCK_SHARED,	"IOLOCK_SHARED" }, \
 	{ XFS_ILOCK_EXCL,	"ILOCK_EXCL" }, \
-	{ XFS_ILOCK_SHARED,	"ILOCK_SHARED" }, \
-	{ XFS_IUNLOCK_NONOTIFY,	"IUNLOCK_NONOTIFY" }
+	{ XFS_ILOCK_SHARED,	"ILOCK_SHARED" }
 
 
 /*
@@ -522,10 +534,6 @@
 void		xfs_lock_inodes(xfs_inode_t **, int, uint);
 void		xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);
 
-void		xfs_synchronize_times(xfs_inode_t *);
-void		xfs_mark_inode_dirty(xfs_inode_t *);
-void		xfs_mark_inode_dirty_sync(xfs_inode_t *);
-
 #define IHOLD(ip) \
 do { \
 	ASSERT(atomic_read(&VFS_I(ip)->i_count) > 0) ; \
@@ -546,6 +554,7 @@
  */
 #define XFS_IGET_CREATE		0x1
 #define XFS_IGET_UNTRUSTED	0x2
+#define XFS_IGET_DONTCACHE	0x4
 
 int		xfs_inotobp(struct xfs_mount *, struct xfs_trans *,
 			    xfs_ino_t, struct xfs_dinode **,
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 91d71dc..05d924e 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -57,77 +57,28 @@
 	struct xfs_inode	*ip = iip->ili_inode;
 	uint			nvecs = 2;
 
-	/*
-	 * Only log the data/extents/b-tree root if there is something
-	 * left to log.
-	 */
-	iip->ili_format.ilf_fields |= XFS_ILOG_CORE;
-
 	switch (ip->i_d.di_format) {
 	case XFS_DINODE_FMT_EXTENTS:
-		iip->ili_format.ilf_fields &=
-			~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT |
-			  XFS_ILOG_DEV | XFS_ILOG_UUID);
-		if ((iip->ili_format.ilf_fields & XFS_ILOG_DEXT) &&
-		    (ip->i_d.di_nextents > 0) &&
-		    (ip->i_df.if_bytes > 0)) {
-			ASSERT(ip->i_df.if_u1.if_extents != NULL);
+		if ((iip->ili_fields & XFS_ILOG_DEXT) &&
+		    ip->i_d.di_nextents > 0 &&
+		    ip->i_df.if_bytes > 0)
 			nvecs++;
-		} else {
-			iip->ili_format.ilf_fields &= ~XFS_ILOG_DEXT;
-		}
 		break;
 
 	case XFS_DINODE_FMT_BTREE:
-		iip->ili_format.ilf_fields &=
-			~(XFS_ILOG_DDATA | XFS_ILOG_DEXT |
-			  XFS_ILOG_DEV | XFS_ILOG_UUID);
-		if ((iip->ili_format.ilf_fields & XFS_ILOG_DBROOT) &&
-		    (ip->i_df.if_broot_bytes > 0)) {
-			ASSERT(ip->i_df.if_broot != NULL);
+		if ((iip->ili_fields & XFS_ILOG_DBROOT) &&
+		    ip->i_df.if_broot_bytes > 0)
 			nvecs++;
-		} else {
-			ASSERT(!(iip->ili_format.ilf_fields &
-				 XFS_ILOG_DBROOT));
-#ifdef XFS_TRANS_DEBUG
-			if (iip->ili_root_size > 0) {
-				ASSERT(iip->ili_root_size ==
-				       ip->i_df.if_broot_bytes);
-				ASSERT(memcmp(iip->ili_orig_root,
-					    ip->i_df.if_broot,
-					    iip->ili_root_size) == 0);
-			} else {
-				ASSERT(ip->i_df.if_broot_bytes == 0);
-			}
-#endif
-			iip->ili_format.ilf_fields &= ~XFS_ILOG_DBROOT;
-		}
 		break;
 
 	case XFS_DINODE_FMT_LOCAL:
-		iip->ili_format.ilf_fields &=
-			~(XFS_ILOG_DEXT | XFS_ILOG_DBROOT |
-			  XFS_ILOG_DEV | XFS_ILOG_UUID);
-		if ((iip->ili_format.ilf_fields & XFS_ILOG_DDATA) &&
-		    (ip->i_df.if_bytes > 0)) {
-			ASSERT(ip->i_df.if_u1.if_data != NULL);
-			ASSERT(ip->i_d.di_size > 0);
+		if ((iip->ili_fields & XFS_ILOG_DDATA) &&
+		    ip->i_df.if_bytes > 0)
 			nvecs++;
-		} else {
-			iip->ili_format.ilf_fields &= ~XFS_ILOG_DDATA;
-		}
 		break;
 
 	case XFS_DINODE_FMT_DEV:
-		iip->ili_format.ilf_fields &=
-			~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT |
-			  XFS_ILOG_DEXT | XFS_ILOG_UUID);
-		break;
-
 	case XFS_DINODE_FMT_UUID:
-		iip->ili_format.ilf_fields &=
-			~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT |
-			  XFS_ILOG_DEXT | XFS_ILOG_DEV);
 		break;
 
 	default:
@@ -135,56 +86,31 @@
 		break;
 	}
 
-	/*
-	 * If there are no attributes associated with this file,
-	 * then there cannot be anything more to log.
-	 * Clear all attribute-related log flags.
-	 */
-	if (!XFS_IFORK_Q(ip)) {
-		iip->ili_format.ilf_fields &=
-			~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT);
+	if (!XFS_IFORK_Q(ip))
 		return nvecs;
-	}
+
 
 	/*
 	 * Log any necessary attribute data.
 	 */
 	switch (ip->i_d.di_aformat) {
 	case XFS_DINODE_FMT_EXTENTS:
-		iip->ili_format.ilf_fields &=
-			~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT);
-		if ((iip->ili_format.ilf_fields & XFS_ILOG_AEXT) &&
-		    (ip->i_d.di_anextents > 0) &&
-		    (ip->i_afp->if_bytes > 0)) {
-			ASSERT(ip->i_afp->if_u1.if_extents != NULL);
+		if ((iip->ili_fields & XFS_ILOG_AEXT) &&
+		    ip->i_d.di_anextents > 0 &&
+		    ip->i_afp->if_bytes > 0)
 			nvecs++;
-		} else {
-			iip->ili_format.ilf_fields &= ~XFS_ILOG_AEXT;
-		}
 		break;
 
 	case XFS_DINODE_FMT_BTREE:
-		iip->ili_format.ilf_fields &=
-			~(XFS_ILOG_ADATA | XFS_ILOG_AEXT);
-		if ((iip->ili_format.ilf_fields & XFS_ILOG_ABROOT) &&
-		    (ip->i_afp->if_broot_bytes > 0)) {
-			ASSERT(ip->i_afp->if_broot != NULL);
+		if ((iip->ili_fields & XFS_ILOG_ABROOT) &&
+		    ip->i_afp->if_broot_bytes > 0)
 			nvecs++;
-		} else {
-			iip->ili_format.ilf_fields &= ~XFS_ILOG_ABROOT;
-		}
 		break;
 
 	case XFS_DINODE_FMT_LOCAL:
-		iip->ili_format.ilf_fields &=
-			~(XFS_ILOG_AEXT | XFS_ILOG_ABROOT);
-		if ((iip->ili_format.ilf_fields & XFS_ILOG_ADATA) &&
-		    (ip->i_afp->if_bytes > 0)) {
-			ASSERT(ip->i_afp->if_u1.if_data != NULL);
+		if ((iip->ili_fields & XFS_ILOG_ADATA) &&
+		    ip->i_afp->if_bytes > 0)
 			nvecs++;
-		} else {
-			iip->ili_format.ilf_fields &= ~XFS_ILOG_ADATA;
-		}
 		break;
 
 	default:
@@ -254,48 +180,11 @@
 	vecp++;
 	nvecs	     = 1;
 
-	/*
-	 * Clear i_update_core if the timestamps (or any other
-	 * non-transactional modification) need flushing/logging
-	 * and we're about to log them with the rest of the core.
-	 *
-	 * This is the same logic as xfs_iflush() but this code can't
-	 * run at the same time as xfs_iflush because we're in commit
-	 * processing here and so we have the inode lock held in
-	 * exclusive mode.  Although it doesn't really matter
-	 * for the timestamps if both routines were to grab the
-	 * timestamps or not.  That would be ok.
-	 *
-	 * We clear i_update_core before copying out the data.
-	 * This is for coordination with our timestamp updates
-	 * that don't hold the inode lock. They will always
-	 * update the timestamps BEFORE setting i_update_core,
-	 * so if we clear i_update_core after they set it we
-	 * are guaranteed to see their updates to the timestamps
-	 * either here.  Likewise, if they set it after we clear it
-	 * here, we'll see it either on the next commit of this
-	 * inode or the next time the inode gets flushed via
-	 * xfs_iflush().  This depends on strongly ordered memory
-	 * semantics, but we have that.  We use the SYNCHRONIZE
-	 * macro to make sure that the compiler does not reorder
-	 * the i_update_core access below the data copy below.
-	 */
-	if (ip->i_update_core)  {
-		ip->i_update_core = 0;
-		SYNCHRONIZE();
-	}
-
-	/*
-	 * Make sure to get the latest timestamps from the Linux inode.
-	 */
-	xfs_synchronize_times(ip);
-
 	vecp->i_addr = &ip->i_d;
 	vecp->i_len  = sizeof(struct xfs_icdinode);
 	vecp->i_type = XLOG_REG_TYPE_ICORE;
 	vecp++;
 	nvecs++;
-	iip->ili_format.ilf_fields |= XFS_ILOG_CORE;
 
 	/*
 	 * If this is really an old format inode, then we need to
@@ -328,16 +217,17 @@
 
 	switch (ip->i_d.di_format) {
 	case XFS_DINODE_FMT_EXTENTS:
-		ASSERT(!(iip->ili_format.ilf_fields &
-			 (XFS_ILOG_DDATA | XFS_ILOG_DBROOT |
-			  XFS_ILOG_DEV | XFS_ILOG_UUID)));
-		if (iip->ili_format.ilf_fields & XFS_ILOG_DEXT) {
-			ASSERT(ip->i_df.if_bytes > 0);
+		iip->ili_fields &=
+			~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT |
+			  XFS_ILOG_DEV | XFS_ILOG_UUID);
+
+		if ((iip->ili_fields & XFS_ILOG_DEXT) &&
+		    ip->i_d.di_nextents > 0 &&
+		    ip->i_df.if_bytes > 0) {
 			ASSERT(ip->i_df.if_u1.if_extents != NULL);
-			ASSERT(ip->i_d.di_nextents > 0);
+			ASSERT(ip->i_df.if_bytes / sizeof(xfs_bmbt_rec_t) > 0);
 			ASSERT(iip->ili_extents_buf == NULL);
-			ASSERT((ip->i_df.if_bytes /
-				(uint)sizeof(xfs_bmbt_rec_t)) > 0);
+
 #ifdef XFS_NATIVE_HOST
                        if (ip->i_d.di_nextents == ip->i_df.if_bytes /
                                                (uint)sizeof(xfs_bmbt_rec_t)) {
@@ -359,15 +249,18 @@
 			iip->ili_format.ilf_dsize = vecp->i_len;
 			vecp++;
 			nvecs++;
+		} else {
+			iip->ili_fields &= ~XFS_ILOG_DEXT;
 		}
 		break;
 
 	case XFS_DINODE_FMT_BTREE:
-		ASSERT(!(iip->ili_format.ilf_fields &
-			 (XFS_ILOG_DDATA | XFS_ILOG_DEXT |
-			  XFS_ILOG_DEV | XFS_ILOG_UUID)));
-		if (iip->ili_format.ilf_fields & XFS_ILOG_DBROOT) {
-			ASSERT(ip->i_df.if_broot_bytes > 0);
+		iip->ili_fields &=
+			~(XFS_ILOG_DDATA | XFS_ILOG_DEXT |
+			  XFS_ILOG_DEV | XFS_ILOG_UUID);
+
+		if ((iip->ili_fields & XFS_ILOG_DBROOT) &&
+		    ip->i_df.if_broot_bytes > 0) {
 			ASSERT(ip->i_df.if_broot != NULL);
 			vecp->i_addr = ip->i_df.if_broot;
 			vecp->i_len = ip->i_df.if_broot_bytes;
@@ -375,15 +268,30 @@
 			vecp++;
 			nvecs++;
 			iip->ili_format.ilf_dsize = ip->i_df.if_broot_bytes;
+		} else {
+			ASSERT(!(iip->ili_fields &
+				 XFS_ILOG_DBROOT));
+#ifdef XFS_TRANS_DEBUG
+			if (iip->ili_root_size > 0) {
+				ASSERT(iip->ili_root_size ==
+				       ip->i_df.if_broot_bytes);
+				ASSERT(memcmp(iip->ili_orig_root,
+					    ip->i_df.if_broot,
+					    iip->ili_root_size) == 0);
+			} else {
+				ASSERT(ip->i_df.if_broot_bytes == 0);
+			}
+#endif
+			iip->ili_fields &= ~XFS_ILOG_DBROOT;
 		}
 		break;
 
 	case XFS_DINODE_FMT_LOCAL:
-		ASSERT(!(iip->ili_format.ilf_fields &
-			 (XFS_ILOG_DBROOT | XFS_ILOG_DEXT |
-			  XFS_ILOG_DEV | XFS_ILOG_UUID)));
-		if (iip->ili_format.ilf_fields & XFS_ILOG_DDATA) {
-			ASSERT(ip->i_df.if_bytes > 0);
+		iip->ili_fields &=
+			~(XFS_ILOG_DEXT | XFS_ILOG_DBROOT |
+			  XFS_ILOG_DEV | XFS_ILOG_UUID);
+		if ((iip->ili_fields & XFS_ILOG_DDATA) &&
+		    ip->i_df.if_bytes > 0) {
 			ASSERT(ip->i_df.if_u1.if_data != NULL);
 			ASSERT(ip->i_d.di_size > 0);
 
@@ -401,24 +309,26 @@
 			vecp++;
 			nvecs++;
 			iip->ili_format.ilf_dsize = (unsigned)data_bytes;
+		} else {
+			iip->ili_fields &= ~XFS_ILOG_DDATA;
 		}
 		break;
 
 	case XFS_DINODE_FMT_DEV:
-		ASSERT(!(iip->ili_format.ilf_fields &
-			 (XFS_ILOG_DBROOT | XFS_ILOG_DEXT |
-			  XFS_ILOG_DDATA | XFS_ILOG_UUID)));
-		if (iip->ili_format.ilf_fields & XFS_ILOG_DEV) {
+		iip->ili_fields &=
+			~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT |
+			  XFS_ILOG_DEXT | XFS_ILOG_UUID);
+		if (iip->ili_fields & XFS_ILOG_DEV) {
 			iip->ili_format.ilf_u.ilfu_rdev =
 				ip->i_df.if_u2.if_rdev;
 		}
 		break;
 
 	case XFS_DINODE_FMT_UUID:
-		ASSERT(!(iip->ili_format.ilf_fields &
-			 (XFS_ILOG_DBROOT | XFS_ILOG_DEXT |
-			  XFS_ILOG_DDATA | XFS_ILOG_DEV)));
-		if (iip->ili_format.ilf_fields & XFS_ILOG_UUID) {
+		iip->ili_fields &=
+			~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT |
+			  XFS_ILOG_DEXT | XFS_ILOG_DEV);
+		if (iip->ili_fields & XFS_ILOG_UUID) {
 			iip->ili_format.ilf_u.ilfu_uuid =
 				ip->i_df.if_u2.if_uuid;
 		}
@@ -430,31 +340,25 @@
 	}
 
 	/*
-	 * If there are no attributes associated with the file,
-	 * then we're done.
-	 * Assert that no attribute-related log flags are set.
+	 * If there are no attributes associated with the file, then we're done.
 	 */
 	if (!XFS_IFORK_Q(ip)) {
-		iip->ili_format.ilf_size = nvecs;
-		ASSERT(!(iip->ili_format.ilf_fields &
-			 (XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT)));
-		return;
+		iip->ili_fields &=
+			~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT);
+		goto out;
 	}
 
 	switch (ip->i_d.di_aformat) {
 	case XFS_DINODE_FMT_EXTENTS:
-		ASSERT(!(iip->ili_format.ilf_fields &
-			 (XFS_ILOG_ADATA | XFS_ILOG_ABROOT)));
-		if (iip->ili_format.ilf_fields & XFS_ILOG_AEXT) {
-#ifdef DEBUG
-			int nrecs = ip->i_afp->if_bytes /
-				(uint)sizeof(xfs_bmbt_rec_t);
-			ASSERT(nrecs > 0);
-			ASSERT(nrecs == ip->i_d.di_anextents);
-			ASSERT(ip->i_afp->if_bytes > 0);
+		iip->ili_fields &=
+			~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT);
+
+		if ((iip->ili_fields & XFS_ILOG_AEXT) &&
+		    ip->i_d.di_anextents > 0 &&
+		    ip->i_afp->if_bytes > 0) {
+			ASSERT(ip->i_afp->if_bytes / sizeof(xfs_bmbt_rec_t) ==
+				ip->i_d.di_anextents);
 			ASSERT(ip->i_afp->if_u1.if_extents != NULL);
-			ASSERT(ip->i_d.di_anextents > 0);
-#endif
 #ifdef XFS_NATIVE_HOST
 			/*
 			 * There are not delayed allocation extents
@@ -471,29 +375,36 @@
 			iip->ili_format.ilf_asize = vecp->i_len;
 			vecp++;
 			nvecs++;
+		} else {
+			iip->ili_fields &= ~XFS_ILOG_AEXT;
 		}
 		break;
 
 	case XFS_DINODE_FMT_BTREE:
-		ASSERT(!(iip->ili_format.ilf_fields &
-			 (XFS_ILOG_ADATA | XFS_ILOG_AEXT)));
-		if (iip->ili_format.ilf_fields & XFS_ILOG_ABROOT) {
-			ASSERT(ip->i_afp->if_broot_bytes > 0);
+		iip->ili_fields &=
+			~(XFS_ILOG_ADATA | XFS_ILOG_AEXT);
+
+		if ((iip->ili_fields & XFS_ILOG_ABROOT) &&
+		    ip->i_afp->if_broot_bytes > 0) {
 			ASSERT(ip->i_afp->if_broot != NULL);
+
 			vecp->i_addr = ip->i_afp->if_broot;
 			vecp->i_len = ip->i_afp->if_broot_bytes;
 			vecp->i_type = XLOG_REG_TYPE_IATTR_BROOT;
 			vecp++;
 			nvecs++;
 			iip->ili_format.ilf_asize = ip->i_afp->if_broot_bytes;
+		} else {
+			iip->ili_fields &= ~XFS_ILOG_ABROOT;
 		}
 		break;
 
 	case XFS_DINODE_FMT_LOCAL:
-		ASSERT(!(iip->ili_format.ilf_fields &
-			 (XFS_ILOG_ABROOT | XFS_ILOG_AEXT)));
-		if (iip->ili_format.ilf_fields & XFS_ILOG_ADATA) {
-			ASSERT(ip->i_afp->if_bytes > 0);
+		iip->ili_fields &=
+			~(XFS_ILOG_AEXT | XFS_ILOG_ABROOT);
+
+		if ((iip->ili_fields & XFS_ILOG_ADATA) &&
+		    ip->i_afp->if_bytes > 0) {
 			ASSERT(ip->i_afp->if_u1.if_data != NULL);
 
 			vecp->i_addr = ip->i_afp->if_u1.if_data;
@@ -510,6 +421,8 @@
 			vecp++;
 			nvecs++;
 			iip->ili_format.ilf_asize = (unsigned)data_bytes;
+		} else {
+			iip->ili_fields &= ~XFS_ILOG_ADATA;
 		}
 		break;
 
@@ -518,6 +431,15 @@
 		break;
 	}
 
+out:
+	/*
+	 * Now update the log format that goes out to disk from the in-core
+	 * values.  We always write the inode core to make the arithmetic
+	 * games in recovery easier, which isn't a big deal as just about any
+	 * transaction would dirty it anyway.
+	 */
+	iip->ili_format.ilf_fields = XFS_ILOG_CORE |
+		(iip->ili_fields & ~XFS_ILOG_TIMESTAMP);
 	iip->ili_format.ilf_size = nvecs;
 }
 
@@ -596,17 +518,13 @@
 	/* Stale items should force out the iclog */
 	if (ip->i_flags & XFS_ISTALE) {
 		xfs_ifunlock(ip);
-		/*
-		 * we hold the AIL lock - notify the unlock routine of this
-		 * so it doesn't try to get the lock again.
-		 */
-		xfs_iunlock(ip, XFS_ILOCK_SHARED|XFS_IUNLOCK_NONOTIFY);
+		xfs_iunlock(ip, XFS_ILOCK_SHARED);
 		return XFS_ITEM_PINNED;
 	}
 
 #ifdef DEBUG
 	if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
-		ASSERT(iip->ili_format.ilf_fields != 0);
+		ASSERT(iip->ili_fields != 0);
 		ASSERT(iip->ili_logged == 0);
 		ASSERT(lip->li_flags & XFS_LI_IN_AIL);
 	}
@@ -638,7 +556,7 @@
 	if (iip->ili_extents_buf != NULL) {
 		ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS);
 		ASSERT(ip->i_d.di_nextents > 0);
-		ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_DEXT);
+		ASSERT(iip->ili_fields & XFS_ILOG_DEXT);
 		ASSERT(ip->i_df.if_bytes > 0);
 		kmem_free(iip->ili_extents_buf);
 		iip->ili_extents_buf = NULL;
@@ -646,7 +564,7 @@
 	if (iip->ili_aextents_buf != NULL) {
 		ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS);
 		ASSERT(ip->i_d.di_anextents > 0);
-		ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_AEXT);
+		ASSERT(iip->ili_fields & XFS_ILOG_AEXT);
 		ASSERT(ip->i_afp->if_bytes > 0);
 		kmem_free(iip->ili_aextents_buf);
 		iip->ili_aextents_buf = NULL;
@@ -761,8 +679,7 @@
 	 * lock without sleeping, then there must not have been
 	 * anyone in the process of flushing the inode.
 	 */
-	ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) ||
-	       iip->ili_format.ilf_fields != 0);
+	ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || iip->ili_fields != 0);
 
 	/*
 	 * Push the inode to it's backing buffer. This will not remove the
@@ -985,7 +902,7 @@
 		 * Clear the inode logging fields so no more flushes are
 		 * attempted.
 		 */
-		iip->ili_format.ilf_fields = 0;
+		iip->ili_fields = 0;
 	}
 	/*
 	 * Release the inode's flush lock since we're done with it.
diff --git a/fs/xfs/xfs_inode_item.h b/fs/xfs/xfs_inode_item.h
index d3dee61..41d61c3 100644
--- a/fs/xfs/xfs_inode_item.h
+++ b/fs/xfs/xfs_inode_item.h
@@ -86,6 +86,15 @@
 #define	XFS_ILOG_AEXT	0x080	/* log i_af.if_extents */
 #define	XFS_ILOG_ABROOT	0x100	/* log i_af.i_broot */
 
+
+/*
+ * The timestamps are dirty, but not necessarily anything else in the inode
+ * core.  Unlike the other fields above this one must never make it to disk
+ * in the ilf_fields of the inode_log_format, but is purely store in-memory in
+ * ili_fields in the inode_log_item.
+ */
+#define XFS_ILOG_TIMESTAMP	0x4000
+
 #define	XFS_ILOG_NONCORE	(XFS_ILOG_DDATA | XFS_ILOG_DEXT | \
 				 XFS_ILOG_DBROOT | XFS_ILOG_DEV | \
 				 XFS_ILOG_UUID | XFS_ILOG_ADATA | \
@@ -101,7 +110,7 @@
 				 XFS_ILOG_DEXT | XFS_ILOG_DBROOT | \
 				 XFS_ILOG_DEV | XFS_ILOG_UUID | \
 				 XFS_ILOG_ADATA | XFS_ILOG_AEXT | \
-				 XFS_ILOG_ABROOT)
+				 XFS_ILOG_ABROOT | XFS_ILOG_TIMESTAMP)
 
 static inline int xfs_ilog_fbroot(int w)
 {
@@ -134,6 +143,7 @@
 	unsigned short		ili_lock_flags;	   /* lock flags */
 	unsigned short		ili_logged;	   /* flushed logged data */
 	unsigned int		ili_last_fields;   /* fields when flushed */
+	unsigned int		ili_fields;	   /* fields to be logged */
 	struct xfs_bmbt_rec	*ili_extents_buf;  /* array of logged
 						      data exts */
 	struct xfs_bmbt_rec	*ili_aextents_buf; /* array of logged
@@ -148,9 +158,7 @@
 
 static inline int xfs_inode_clean(xfs_inode_t *ip)
 {
-	return (!ip->i_itemp ||
-		!(ip->i_itemp->ili_format.ilf_fields & XFS_ILOG_ALL)) &&
-	       !ip->i_update_core;
+	return !ip->i_itemp || !(ip->i_itemp->ili_fields & XFS_ILOG_ALL);
 }
 
 extern void xfs_inode_item_init(struct xfs_inode *, struct xfs_mount *);
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 76f3ca5..91f8ff5 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -209,6 +209,7 @@
 	struct file		*filp;
 	struct inode		*inode;
 	struct dentry		*dentry;
+	fmode_t			fmode;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -XFS_ERROR(EPERM);
@@ -228,26 +229,21 @@
 	hreq->oflags |= O_LARGEFILE;
 #endif
 
-	/* Put open permission in namei format. */
 	permflag = hreq->oflags;
-	if ((permflag+1) & O_ACCMODE)
-		permflag++;
-	if (permflag & O_TRUNC)
-		permflag |= 2;
-
+	fmode = OPEN_FMODE(permflag);
 	if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) &&
-	    (permflag & FMODE_WRITE) && IS_APPEND(inode)) {
+	    (fmode & FMODE_WRITE) && IS_APPEND(inode)) {
 		error = -XFS_ERROR(EPERM);
 		goto out_dput;
 	}
 
-	if ((permflag & FMODE_WRITE) && IS_IMMUTABLE(inode)) {
+	if ((fmode & FMODE_WRITE) && IS_IMMUTABLE(inode)) {
 		error = -XFS_ERROR(EACCES);
 		goto out_dput;
 	}
 
 	/* Can't write directories. */
-	if (S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) {
+	if (S_ISDIR(inode->i_mode) && (fmode & FMODE_WRITE)) {
 		error = -XFS_ERROR(EISDIR);
 		goto out_dput;
 	}
@@ -450,9 +446,12 @@
 
 	if (*len > XATTR_SIZE_MAX)
 		return EINVAL;
-	kbuf = kmalloc(*len, GFP_KERNEL);
-	if (!kbuf)
-		return ENOMEM;
+	kbuf = kmem_zalloc(*len, KM_SLEEP | KM_MAYFAIL);
+	if (!kbuf) {
+		kbuf = kmem_zalloc_large(*len);
+		if (!kbuf)
+			return ENOMEM;
+	}
 
 	error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags);
 	if (error)
@@ -462,7 +461,10 @@
 		error = EFAULT;
 
  out_kfree:
-	kfree(kbuf);
+	if (is_vmalloc_addr(kbuf))
+		kmem_free_large(kbuf);
+	else
+		kmem_free(kbuf);
 	return error;
 }
 
diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
index f9ccb7b..a849a54 100644
--- a/fs/xfs/xfs_ioctl32.c
+++ b/fs/xfs/xfs_ioctl32.c
@@ -293,7 +293,7 @@
 		int res;
 
 		error = xfs_bulkstat_one_compat(mp, inlast, bulkreq.ubuffer,
-				sizeof(compat_xfs_bstat_t), 0, &res);
+				sizeof(compat_xfs_bstat_t), NULL, &res);
 	} else if (cmd == XFS_IOC_FSBULKSTAT_32) {
 		error = xfs_bulkstat(mp, &inlast, &count,
 			xfs_bulkstat_one_compat, sizeof(compat_xfs_bstat_t),
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 246c7d5..71a4645 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -31,6 +31,7 @@
 #include "xfs_ialloc_btree.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
+#include "xfs_inode_item.h"
 #include "xfs_btree.h"
 #include "xfs_bmap.h"
 #include "xfs_rtalloc.h"
@@ -645,6 +646,7 @@
 	xfs_trans_t	*tp;
 	xfs_bmbt_irec_t imap;
 	xfs_bmap_free_t free_list;
+	xfs_fsize_t	i_size;
 	uint		resblks;
 	int		committed;
 	int		error;
@@ -705,7 +707,22 @@
 		if (error)
 			goto error_on_bmapi_transaction;
 
-		error = xfs_bmap_finish(&(tp), &(free_list), &committed);
+		/*
+		 * Log the updated inode size as we go.  We have to be careful
+		 * to only log it up to the actual write offset if it is
+		 * halfway into a block.
+		 */
+		i_size = XFS_FSB_TO_B(mp, offset_fsb + count_fsb);
+		if (i_size > offset + count)
+			i_size = offset + count;
+
+		i_size = xfs_new_eof(ip, i_size);
+		if (i_size) {
+			ip->i_d.di_size = i_size;
+			xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+		}
+
+		error = xfs_bmap_finish(&tp, &free_list, &committed);
 		if (error)
 			goto error_on_bmapi_transaction;
 
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index ab30253..3011b87 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -50,65 +50,15 @@
 #include <linux/fiemap.h>
 #include <linux/slab.h>
 
-/*
- * Bring the timestamps in the XFS inode uptodate.
- *
- * Used before writing the inode to disk.
- */
-void
-xfs_synchronize_times(
-	xfs_inode_t	*ip)
+static int
+xfs_initxattrs(
+	struct inode		*inode,
+	const struct xattr	*xattr_array,
+	void			*fs_info)
 {
-	struct inode	*inode = VFS_I(ip);
-
-	ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec;
-	ip->i_d.di_atime.t_nsec = (__int32_t)inode->i_atime.tv_nsec;
-	ip->i_d.di_ctime.t_sec = (__int32_t)inode->i_ctime.tv_sec;
-	ip->i_d.di_ctime.t_nsec = (__int32_t)inode->i_ctime.tv_nsec;
-	ip->i_d.di_mtime.t_sec = (__int32_t)inode->i_mtime.tv_sec;
-	ip->i_d.di_mtime.t_nsec = (__int32_t)inode->i_mtime.tv_nsec;
-}
-
-/*
- * If the linux inode is valid, mark it dirty, else mark the dirty state
- * in the XFS inode to make sure we pick it up when reclaiming the inode.
- */
-void
-xfs_mark_inode_dirty_sync(
-	xfs_inode_t	*ip)
-{
-	struct inode	*inode = VFS_I(ip);
-
-	if (!(inode->i_state & (I_WILL_FREE|I_FREEING)))
-		mark_inode_dirty_sync(inode);
-	else {
-		barrier();
-		ip->i_update_core = 1;
-	}
-}
-
-void
-xfs_mark_inode_dirty(
-	xfs_inode_t	*ip)
-{
-	struct inode	*inode = VFS_I(ip);
-
-	if (!(inode->i_state & (I_WILL_FREE|I_FREEING)))
-		mark_inode_dirty(inode);
-	else {
-		barrier();
-		ip->i_update_core = 1;
-	}
-
-}
-
-
-int xfs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
-		   void *fs_info)
-{
-	const struct xattr *xattr;
-	struct xfs_inode *ip = XFS_I(inode);
-	int error = 0;
+	const struct xattr	*xattr;
+	struct xfs_inode	*ip = XFS_I(inode);
+	int			error = 0;
 
 	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
 		error = xfs_attr_set(ip, xattr->name, xattr->value,
@@ -678,19 +628,16 @@
 		inode->i_atime = iattr->ia_atime;
 		ip->i_d.di_atime.t_sec = iattr->ia_atime.tv_sec;
 		ip->i_d.di_atime.t_nsec = iattr->ia_atime.tv_nsec;
-		ip->i_update_core = 1;
 	}
 	if (mask & ATTR_CTIME) {
 		inode->i_ctime = iattr->ia_ctime;
 		ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec;
 		ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec;
-		ip->i_update_core = 1;
 	}
 	if (mask & ATTR_MTIME) {
 		inode->i_mtime = iattr->ia_mtime;
 		ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec;
 		ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec;
-		ip->i_update_core = 1;
 	}
 
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
@@ -918,13 +865,11 @@
 		inode->i_ctime = iattr->ia_ctime;
 		ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec;
 		ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec;
-		ip->i_update_core = 1;
 	}
 	if (mask & ATTR_MTIME) {
 		inode->i_mtime = iattr->ia_mtime;
 		ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec;
 		ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec;
-		ip->i_update_core = 1;
 	}
 
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 751e94f..acc2bf2 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -62,7 +62,6 @@
 {
 	struct xfs_icdinode	*dic;		/* dinode core info pointer */
 	struct xfs_inode	*ip;		/* incore inode pointer */
-	struct inode		*inode;
 	struct xfs_bstat	*buf;		/* return buffer */
 	int			error = 0;	/* error value */
 
@@ -76,7 +75,8 @@
 		return XFS_ERROR(ENOMEM);
 
 	error = xfs_iget(mp, NULL, ino,
-			 XFS_IGET_UNTRUSTED, XFS_ILOCK_SHARED, &ip);
+			 (XFS_IGET_DONTCACHE | XFS_IGET_UNTRUSTED),
+			 XFS_ILOCK_SHARED, &ip);
 	if (error) {
 		*stat = BULKSTAT_RV_NOTHING;
 		goto out_free;
@@ -86,7 +86,6 @@
 	ASSERT(ip->i_imap.im_blkno != 0);
 
 	dic = &ip->i_d;
-	inode = VFS_I(ip);
 
 	/* xfs_iget returns the following without needing
 	 * further change.
@@ -99,19 +98,12 @@
 	buf->bs_uid = dic->di_uid;
 	buf->bs_gid = dic->di_gid;
 	buf->bs_size = dic->di_size;
-
-	/*
-	 * We need to read the timestamps from the Linux inode because
-	 * the VFS keeps writing directly into the inode structure instead
-	 * of telling us about the updates.
-	 */
-	buf->bs_atime.tv_sec = inode->i_atime.tv_sec;
-	buf->bs_atime.tv_nsec = inode->i_atime.tv_nsec;
-	buf->bs_mtime.tv_sec = inode->i_mtime.tv_sec;
-	buf->bs_mtime.tv_nsec = inode->i_mtime.tv_nsec;
-	buf->bs_ctime.tv_sec = inode->i_ctime.tv_sec;
-	buf->bs_ctime.tv_nsec = inode->i_ctime.tv_nsec;
-
+	buf->bs_atime.tv_sec = dic->di_atime.t_sec;
+	buf->bs_atime.tv_nsec = dic->di_atime.t_nsec;
+	buf->bs_mtime.tv_sec = dic->di_mtime.t_sec;
+	buf->bs_mtime.tv_nsec = dic->di_mtime.t_nsec;
+	buf->bs_ctime.tv_sec = dic->di_ctime.t_sec;
+	buf->bs_ctime.tv_nsec = dic->di_ctime.t_nsec;
 	buf->bs_xflags = xfs_ip2xflags(ip);
 	buf->bs_extsize = dic->di_extsize << mp->m_sb.sb_blocklog;
 	buf->bs_extents = dic->di_nextents;
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index e2cc356..6db1fef 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -67,15 +67,10 @@
 				     int		eventual_size);
 STATIC void xlog_state_want_sync(xlog_t	*log, xlog_in_core_t *iclog);
 
-/* local functions to manipulate grant head */
-STATIC int  xlog_grant_log_space(xlog_t		*log,
-				 xlog_ticket_t	*xtic);
 STATIC void xlog_grant_push_ail(struct log	*log,
 				int		need_bytes);
 STATIC void xlog_regrant_reserve_log_space(xlog_t	 *log,
 					   xlog_ticket_t *ticket);
-STATIC int xlog_regrant_write_log_space(xlog_t		*log,
-					 xlog_ticket_t  *ticket);
 STATIC void xlog_ungrant_log_space(xlog_t	 *log,
 				   xlog_ticket_t *ticket);
 
@@ -150,78 +145,93 @@
 	} while (head_val != old);
 }
 
-STATIC bool
-xlog_reserveq_wake(
-	struct log		*log,
-	int			*free_bytes)
+STATIC void
+xlog_grant_head_init(
+	struct xlog_grant_head	*head)
+{
+	xlog_assign_grant_head(&head->grant, 1, 0);
+	INIT_LIST_HEAD(&head->waiters);
+	spin_lock_init(&head->lock);
+}
+
+STATIC void
+xlog_grant_head_wake_all(
+	struct xlog_grant_head	*head)
 {
 	struct xlog_ticket	*tic;
-	int			need_bytes;
 
-	list_for_each_entry(tic, &log->l_reserveq, t_queue) {
+	spin_lock(&head->lock);
+	list_for_each_entry(tic, &head->waiters, t_queue)
+		wake_up_process(tic->t_task);
+	spin_unlock(&head->lock);
+}
+
+static inline int
+xlog_ticket_reservation(
+	struct log		*log,
+	struct xlog_grant_head	*head,
+	struct xlog_ticket	*tic)
+{
+	if (head == &log->l_write_head) {
+		ASSERT(tic->t_flags & XLOG_TIC_PERM_RESERV);
+		return tic->t_unit_res;
+	} else {
 		if (tic->t_flags & XLOG_TIC_PERM_RESERV)
-			need_bytes = tic->t_unit_res * tic->t_cnt;
+			return tic->t_unit_res * tic->t_cnt;
 		else
-			need_bytes = tic->t_unit_res;
-
-		if (*free_bytes < need_bytes)
-			return false;
-		*free_bytes -= need_bytes;
-
-		trace_xfs_log_grant_wake_up(log, tic);
-		wake_up(&tic->t_wait);
+			return tic->t_unit_res;
 	}
-
-	return true;
 }
 
 STATIC bool
-xlog_writeq_wake(
+xlog_grant_head_wake(
 	struct log		*log,
+	struct xlog_grant_head	*head,
 	int			*free_bytes)
 {
 	struct xlog_ticket	*tic;
 	int			need_bytes;
 
-	list_for_each_entry(tic, &log->l_writeq, t_queue) {
-		ASSERT(tic->t_flags & XLOG_TIC_PERM_RESERV);
-
-		need_bytes = tic->t_unit_res;
-
+	list_for_each_entry(tic, &head->waiters, t_queue) {
+		need_bytes = xlog_ticket_reservation(log, head, tic);
 		if (*free_bytes < need_bytes)
 			return false;
-		*free_bytes -= need_bytes;
 
-		trace_xfs_log_regrant_write_wake_up(log, tic);
-		wake_up(&tic->t_wait);
+		*free_bytes -= need_bytes;
+		trace_xfs_log_grant_wake_up(log, tic);
+		wake_up_process(tic->t_task);
 	}
 
 	return true;
 }
 
 STATIC int
-xlog_reserveq_wait(
+xlog_grant_head_wait(
 	struct log		*log,
+	struct xlog_grant_head	*head,
 	struct xlog_ticket	*tic,
 	int			need_bytes)
 {
-	list_add_tail(&tic->t_queue, &log->l_reserveq);
+	list_add_tail(&tic->t_queue, &head->waiters);
 
 	do {
 		if (XLOG_FORCED_SHUTDOWN(log))
 			goto shutdown;
 		xlog_grant_push_ail(log, need_bytes);
 
-		XFS_STATS_INC(xs_sleep_logspace);
-		trace_xfs_log_grant_sleep(log, tic);
+		__set_current_state(TASK_UNINTERRUPTIBLE);
+		spin_unlock(&head->lock);
 
-		xlog_wait(&tic->t_wait, &log->l_grant_reserve_lock);
+		XFS_STATS_INC(xs_sleep_logspace);
+
+		trace_xfs_log_grant_sleep(log, tic);
+		schedule();
 		trace_xfs_log_grant_wake(log, tic);
 
-		spin_lock(&log->l_grant_reserve_lock);
+		spin_lock(&head->lock);
 		if (XLOG_FORCED_SHUTDOWN(log))
 			goto shutdown;
-	} while (xlog_space_left(log, &log->l_grant_reserve_head) < need_bytes);
+	} while (xlog_space_left(log, &head->grant) < need_bytes);
 
 	list_del_init(&tic->t_queue);
 	return 0;
@@ -230,35 +240,58 @@
 	return XFS_ERROR(EIO);
 }
 
+/*
+ * Atomically get the log space required for a log ticket.
+ *
+ * Once a ticket gets put onto head->waiters, it will only return after the
+ * needed reservation is satisfied.
+ *
+ * This function is structured so that it has a lock free fast path. This is
+ * necessary because every new transaction reservation will come through this
+ * path. Hence any lock will be globally hot if we take it unconditionally on
+ * every pass.
+ *
+ * As tickets are only ever moved on and off head->waiters under head->lock, we
+ * only need to take that lock if we are going to add the ticket to the queue
+ * and sleep. We can avoid taking the lock if the ticket was never added to
+ * head->waiters because the t_queue list head will be empty and we hold the
+ * only reference to it so it can safely be checked unlocked.
+ */
 STATIC int
-xlog_writeq_wait(
+xlog_grant_head_check(
 	struct log		*log,
+	struct xlog_grant_head	*head,
 	struct xlog_ticket	*tic,
-	int			need_bytes)
+	int			*need_bytes)
 {
-	list_add_tail(&tic->t_queue, &log->l_writeq);
+	int			free_bytes;
+	int			error = 0;
 
-	do {
-		if (XLOG_FORCED_SHUTDOWN(log))
-			goto shutdown;
-		xlog_grant_push_ail(log, need_bytes);
+	ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY));
 
-		XFS_STATS_INC(xs_sleep_logspace);
-		trace_xfs_log_regrant_write_sleep(log, tic);
+	/*
+	 * If there are other waiters on the queue then give them a chance at
+	 * logspace before us.  Wake up the first waiters, if we do not wake
+	 * up all the waiters then go to sleep waiting for more free space,
+	 * otherwise try to get some space for this transaction.
+	 */
+	*need_bytes = xlog_ticket_reservation(log, head, tic);
+	free_bytes = xlog_space_left(log, &head->grant);
+	if (!list_empty_careful(&head->waiters)) {
+		spin_lock(&head->lock);
+		if (!xlog_grant_head_wake(log, head, &free_bytes) ||
+		    free_bytes < *need_bytes) {
+			error = xlog_grant_head_wait(log, head, tic,
+						     *need_bytes);
+		}
+		spin_unlock(&head->lock);
+	} else if (free_bytes < *need_bytes) {
+		spin_lock(&head->lock);
+		error = xlog_grant_head_wait(log, head, tic, *need_bytes);
+		spin_unlock(&head->lock);
+	}
 
-		xlog_wait(&tic->t_wait, &log->l_grant_write_lock);
-		trace_xfs_log_regrant_write_wake(log, tic);
-
-		spin_lock(&log->l_grant_write_lock);
-		if (XLOG_FORCED_SHUTDOWN(log))
-			goto shutdown;
-	} while (xlog_space_left(log, &log->l_grant_write_head) < need_bytes);
-
-	list_del_init(&tic->t_queue);
-	return 0;
-shutdown:
-	list_del_init(&tic->t_queue);
-	return XFS_ERROR(EIO);
+	return error;
 }
 
 static void
@@ -286,6 +319,128 @@
 }
 
 /*
+ * Replenish the byte reservation required by moving the grant write head.
+ */
+int
+xfs_log_regrant(
+	struct xfs_mount	*mp,
+	struct xlog_ticket	*tic)
+{
+	struct log		*log = mp->m_log;
+	int			need_bytes;
+	int			error = 0;
+
+	if (XLOG_FORCED_SHUTDOWN(log))
+		return XFS_ERROR(EIO);
+
+	XFS_STATS_INC(xs_try_logspace);
+
+	/*
+	 * This is a new transaction on the ticket, so we need to change the
+	 * transaction ID so that the next transaction has a different TID in
+	 * the log. Just add one to the existing tid so that we can see chains
+	 * of rolling transactions in the log easily.
+	 */
+	tic->t_tid++;
+
+	xlog_grant_push_ail(log, tic->t_unit_res);
+
+	tic->t_curr_res = tic->t_unit_res;
+	xlog_tic_reset_res(tic);
+
+	if (tic->t_cnt > 0)
+		return 0;
+
+	trace_xfs_log_regrant(log, tic);
+
+	error = xlog_grant_head_check(log, &log->l_write_head, tic,
+				      &need_bytes);
+	if (error)
+		goto out_error;
+
+	xlog_grant_add_space(log, &log->l_write_head.grant, need_bytes);
+	trace_xfs_log_regrant_exit(log, tic);
+	xlog_verify_grant_tail(log);
+	return 0;
+
+out_error:
+	/*
+	 * If we are failing, make sure the ticket doesn't have any current
+	 * reservations.  We don't want to add this back when the ticket/
+	 * transaction gets cancelled.
+	 */
+	tic->t_curr_res = 0;
+	tic->t_cnt = 0;	/* ungrant will give back unit_res * t_cnt. */
+	return error;
+}
+
+/*
+ * Reserve log space and return a ticket corresponding the reservation.
+ *
+ * Each reservation is going to reserve extra space for a log record header.
+ * When writes happen to the on-disk log, we don't subtract the length of the
+ * log record header from any reservation.  By wasting space in each
+ * reservation, we prevent over allocation problems.
+ */
+int
+xfs_log_reserve(
+	struct xfs_mount	*mp,
+	int		 	unit_bytes,
+	int		 	cnt,
+	struct xlog_ticket	**ticp,
+	__uint8_t	 	client,
+	bool			permanent,
+	uint		 	t_type)
+{
+	struct log		*log = mp->m_log;
+	struct xlog_ticket	*tic;
+	int			need_bytes;
+	int			error = 0;
+
+	ASSERT(client == XFS_TRANSACTION || client == XFS_LOG);
+
+	if (XLOG_FORCED_SHUTDOWN(log))
+		return XFS_ERROR(EIO);
+
+	XFS_STATS_INC(xs_try_logspace);
+
+	ASSERT(*ticp == NULL);
+	tic = xlog_ticket_alloc(log, unit_bytes, cnt, client, permanent,
+				KM_SLEEP | KM_MAYFAIL);
+	if (!tic)
+		return XFS_ERROR(ENOMEM);
+
+	tic->t_trans_type = t_type;
+	*ticp = tic;
+
+	xlog_grant_push_ail(log, tic->t_unit_res * tic->t_cnt);
+
+	trace_xfs_log_reserve(log, tic);
+
+	error = xlog_grant_head_check(log, &log->l_reserve_head, tic,
+				      &need_bytes);
+	if (error)
+		goto out_error;
+
+	xlog_grant_add_space(log, &log->l_reserve_head.grant, need_bytes);
+	xlog_grant_add_space(log, &log->l_write_head.grant, need_bytes);
+	trace_xfs_log_reserve_exit(log, tic);
+	xlog_verify_grant_tail(log);
+	return 0;
+
+out_error:
+	/*
+	 * If we are failing, make sure the ticket doesn't have any current
+	 * reservations.  We don't want to add this back when the ticket/
+	 * transaction gets cancelled.
+	 */
+	tic->t_curr_res = 0;
+	tic->t_cnt = 0;	/* ungrant will give back unit_res * t_cnt. */
+	return error;
+}
+
+
+/*
  * NOTES:
  *
  *	1. currblock field gets updated at startup and after in-core logs
@@ -395,88 +550,6 @@
 }
 
 /*
- *  1. Reserve an amount of on-disk log space and return a ticket corresponding
- *	to the reservation.
- *  2. Potentially, push buffers at tail of log to disk.
- *
- * Each reservation is going to reserve extra space for a log record header.
- * When writes happen to the on-disk log, we don't subtract the length of the
- * log record header from any reservation.  By wasting space in each
- * reservation, we prevent over allocation problems.
- */
-int
-xfs_log_reserve(
-	struct xfs_mount	*mp,
-	int		 	unit_bytes,
-	int		 	cnt,
-	struct xlog_ticket	**ticket,
-	__uint8_t	 	client,
-	uint		 	flags,
-	uint		 	t_type)
-{
-	struct log		*log = mp->m_log;
-	struct xlog_ticket	*internal_ticket;
-	int			retval = 0;
-
-	ASSERT(client == XFS_TRANSACTION || client == XFS_LOG);
-
-	if (XLOG_FORCED_SHUTDOWN(log))
-		return XFS_ERROR(EIO);
-
-	XFS_STATS_INC(xs_try_logspace);
-
-
-	if (*ticket != NULL) {
-		ASSERT(flags & XFS_LOG_PERM_RESERV);
-		internal_ticket = *ticket;
-
-		/*
-		 * this is a new transaction on the ticket, so we need to
-		 * change the transaction ID so that the next transaction has a
-		 * different TID in the log. Just add one to the existing tid
-		 * so that we can see chains of rolling transactions in the log
-		 * easily.
-		 */
-		internal_ticket->t_tid++;
-
-		trace_xfs_log_reserve(log, internal_ticket);
-
-		xlog_grant_push_ail(log, internal_ticket->t_unit_res);
-		retval = xlog_regrant_write_log_space(log, internal_ticket);
-	} else {
-		/* may sleep if need to allocate more tickets */
-		internal_ticket = xlog_ticket_alloc(log, unit_bytes, cnt,
-						  client, flags,
-						  KM_SLEEP|KM_MAYFAIL);
-		if (!internal_ticket)
-			return XFS_ERROR(ENOMEM);
-		internal_ticket->t_trans_type = t_type;
-		*ticket = internal_ticket;
-
-		trace_xfs_log_reserve(log, internal_ticket);
-
-		xlog_grant_push_ail(log,
-				    (internal_ticket->t_unit_res *
-				     internal_ticket->t_cnt));
-		retval = xlog_grant_log_space(log, internal_ticket);
-	}
-
-	if (unlikely(retval)) {
-		/*
-		 * If we are failing, make sure the ticket doesn't have any
-		 * current reservations.  We don't want to add this back
-		 * when the ticket/ transaction gets cancelled.
-		 */
-		internal_ticket->t_curr_res = 0;
-		/* ungrant will give back unit_res * t_cnt. */
-		internal_ticket->t_cnt = 0;
-	}
-
-	return retval;
-}
-
-
-/*
  * Mount a log filesystem
  *
  * mp		- ubiquitous xfs mount point structure
@@ -653,8 +726,9 @@
 				.lv_iovecp = &reg,
 			};
 
-			/* remove inited flag */
+			/* remove inited flag, and account for space used */
 			tic->t_flags = 0;
+			tic->t_curr_res -= sizeof(magic);
 			error = xlog_write(log, &vec, tic, &lsn,
 					   NULL, XLOG_UNMOUNT_TRANS);
 			/*
@@ -760,64 +834,35 @@
 	INIT_LIST_HEAD(&item->li_cil);
 }
 
+/*
+ * Wake up processes waiting for log space after we have moved the log tail.
+ */
 void
-xfs_log_move_tail(xfs_mount_t	*mp,
-		  xfs_lsn_t	tail_lsn)
+xfs_log_space_wake(
+	struct xfs_mount	*mp)
 {
-	xlog_ticket_t	*tic;
-	xlog_t		*log = mp->m_log;
-	int		need_bytes, free_bytes;
+	struct log		*log = mp->m_log;
+	int			free_bytes;
 
 	if (XLOG_FORCED_SHUTDOWN(log))
 		return;
 
-	if (tail_lsn == 0)
-		tail_lsn = atomic64_read(&log->l_last_sync_lsn);
+	if (!list_empty_careful(&log->l_write_head.waiters)) {
+		ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY));
 
-	/* tail_lsn == 1 implies that we weren't passed a valid value.  */
-	if (tail_lsn != 1)
-		atomic64_set(&log->l_tail_lsn, tail_lsn);
-
-	if (!list_empty_careful(&log->l_writeq)) {
-#ifdef DEBUG
-		if (log->l_flags & XLOG_ACTIVE_RECOVERY)
-			panic("Recovery problem");
-#endif
-		spin_lock(&log->l_grant_write_lock);
-		free_bytes = xlog_space_left(log, &log->l_grant_write_head);
-		list_for_each_entry(tic, &log->l_writeq, t_queue) {
-			ASSERT(tic->t_flags & XLOG_TIC_PERM_RESERV);
-
-			if (free_bytes < tic->t_unit_res && tail_lsn != 1)
-				break;
-			tail_lsn = 0;
-			free_bytes -= tic->t_unit_res;
-			trace_xfs_log_regrant_write_wake_up(log, tic);
-			wake_up(&tic->t_wait);
-		}
-		spin_unlock(&log->l_grant_write_lock);
+		spin_lock(&log->l_write_head.lock);
+		free_bytes = xlog_space_left(log, &log->l_write_head.grant);
+		xlog_grant_head_wake(log, &log->l_write_head, &free_bytes);
+		spin_unlock(&log->l_write_head.lock);
 	}
 
-	if (!list_empty_careful(&log->l_reserveq)) {
-#ifdef DEBUG
-		if (log->l_flags & XLOG_ACTIVE_RECOVERY)
-			panic("Recovery problem");
-#endif
-		spin_lock(&log->l_grant_reserve_lock);
-		free_bytes = xlog_space_left(log, &log->l_grant_reserve_head);
-		list_for_each_entry(tic, &log->l_reserveq, t_queue) {
-			if (tic->t_flags & XLOG_TIC_PERM_RESERV)
-				need_bytes = tic->t_unit_res*tic->t_cnt;
-			else
-				need_bytes = tic->t_unit_res;
-			if (free_bytes < need_bytes && tail_lsn != 1)
-				break;
-			tail_lsn = 0;
-			free_bytes -= need_bytes;
-			trace_xfs_log_grant_wake_up(log, tic);
-			wake_up(&tic->t_wait);
-		}
-		spin_unlock(&log->l_grant_reserve_lock);
+	if (!list_empty_careful(&log->l_reserve_head.waiters)) {
+		ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY));
+
+		spin_lock(&log->l_reserve_head.lock);
+		free_bytes = xlog_space_left(log, &log->l_reserve_head.grant);
+		xlog_grant_head_wake(log, &log->l_reserve_head, &free_bytes);
+		spin_unlock(&log->l_reserve_head.lock);
 	}
 }
 
@@ -867,21 +912,7 @@
 	return needed;
 }
 
-/******************************************************************************
- *
- *	local routines
- *
- ******************************************************************************
- */
-
-/* xfs_trans_tail_ail returns 0 when there is nothing in the list.
- * The log manager must keep track of the last LR which was committed
- * to disk.  The lsn of this LR will become the new tail_lsn whenever
- * xfs_trans_tail_ail returns 0.  If we don't do this, we run into
- * the situation where stuff could be written into the log but nothing
- * was ever in the AIL when asked.  Eventually, we panic since the
- * tail hits the head.
- *
+/*
  * We may be holding the log iclog lock upon entering this routine.
  */
 xfs_lsn_t
@@ -891,10 +922,17 @@
 	xfs_lsn_t		tail_lsn;
 	struct log		*log = mp->m_log;
 
+	/*
+	 * To make sure we always have a valid LSN for the log tail we keep
+	 * track of the last LSN which was committed in log->l_last_sync_lsn,
+	 * and use that when the AIL was empty and xfs_ail_min_lsn returns 0.
+	 *
+	 * If the AIL has been emptied we also need to wake any process
+	 * waiting for this condition.
+	 */
 	tail_lsn = xfs_ail_min_lsn(mp->m_ail);
 	if (!tail_lsn)
 		tail_lsn = atomic64_read(&log->l_last_sync_lsn);
-
 	atomic64_set(&log->l_tail_lsn, tail_lsn);
 	return tail_lsn;
 }
@@ -1100,12 +1138,9 @@
 	xlog_assign_atomic_lsn(&log->l_tail_lsn, 1, 0);
 	xlog_assign_atomic_lsn(&log->l_last_sync_lsn, 1, 0);
 	log->l_curr_cycle  = 1;	    /* 0 is bad since this is initial value */
-	xlog_assign_grant_head(&log->l_grant_reserve_head, 1, 0);
-	xlog_assign_grant_head(&log->l_grant_write_head, 1, 0);
-	INIT_LIST_HEAD(&log->l_reserveq);
-	INIT_LIST_HEAD(&log->l_writeq);
-	spin_lock_init(&log->l_grant_reserve_lock);
-	spin_lock_init(&log->l_grant_write_lock);
+
+	xlog_grant_head_init(&log->l_reserve_head);
+	xlog_grant_head_init(&log->l_write_head);
 
 	error = EFSCORRUPTED;
 	if (xfs_sb_version_hassector(&mp->m_sb)) {
@@ -1280,7 +1315,7 @@
 
 	ASSERT(BTOBB(need_bytes) < log->l_logBBsize);
 
-	free_bytes = xlog_space_left(log, &log->l_grant_reserve_head);
+	free_bytes = xlog_space_left(log, &log->l_reserve_head.grant);
 	free_blocks = BTOBBT(free_bytes);
 
 	/*
@@ -1412,8 +1447,8 @@
 		 roundoff < BBTOB(1)));
 
 	/* move grant heads by roundoff in sync */
-	xlog_grant_add_space(log, &log->l_grant_reserve_head, roundoff);
-	xlog_grant_add_space(log, &log->l_grant_write_head, roundoff);
+	xlog_grant_add_space(log, &log->l_reserve_head.grant, roundoff);
+	xlog_grant_add_space(log, &log->l_write_head.grant, roundoff);
 
 	/* put cycle number in every block */
 	xlog_pack_data(log, iclog, roundoff); 
@@ -2566,119 +2601,6 @@
 	return 0;
 }	/* xlog_state_get_iclog_space */
 
-/*
- * Atomically get the log space required for a log ticket.
- *
- * Once a ticket gets put onto the reserveq, it will only return after the
- * needed reservation is satisfied.
- *
- * This function is structured so that it has a lock free fast path. This is
- * necessary because every new transaction reservation will come through this
- * path. Hence any lock will be globally hot if we take it unconditionally on
- * every pass.
- *
- * As tickets are only ever moved on and off the reserveq under the
- * l_grant_reserve_lock, we only need to take that lock if we are going to add
- * the ticket to the queue and sleep. We can avoid taking the lock if the ticket
- * was never added to the reserveq because the t_queue list head will be empty
- * and we hold the only reference to it so it can safely be checked unlocked.
- */
-STATIC int
-xlog_grant_log_space(
-	struct log		*log,
-	struct xlog_ticket	*tic)
-{
-	int			free_bytes, need_bytes;
-	int			error = 0;
-
-	ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY));
-
-	trace_xfs_log_grant_enter(log, tic);
-
-	/*
-	 * If there are other waiters on the queue then give them a chance at
-	 * logspace before us.  Wake up the first waiters, if we do not wake
-	 * up all the waiters then go to sleep waiting for more free space,
-	 * otherwise try to get some space for this transaction.
-	 */
-	need_bytes = tic->t_unit_res;
-	if (tic->t_flags & XFS_LOG_PERM_RESERV)
-		need_bytes *= tic->t_ocnt;
-	free_bytes = xlog_space_left(log, &log->l_grant_reserve_head);
-	if (!list_empty_careful(&log->l_reserveq)) {
-		spin_lock(&log->l_grant_reserve_lock);
-		if (!xlog_reserveq_wake(log, &free_bytes) ||
-		    free_bytes < need_bytes)
-			error = xlog_reserveq_wait(log, tic, need_bytes);
-		spin_unlock(&log->l_grant_reserve_lock);
-	} else if (free_bytes < need_bytes) {
-		spin_lock(&log->l_grant_reserve_lock);
-		error = xlog_reserveq_wait(log, tic, need_bytes);
-		spin_unlock(&log->l_grant_reserve_lock);
-	}
-	if (error)
-		return error;
-
-	xlog_grant_add_space(log, &log->l_grant_reserve_head, need_bytes);
-	xlog_grant_add_space(log, &log->l_grant_write_head, need_bytes);
-	trace_xfs_log_grant_exit(log, tic);
-	xlog_verify_grant_tail(log);
-	return 0;
-}
-
-/*
- * Replenish the byte reservation required by moving the grant write head.
- *
- * Similar to xlog_grant_log_space, the function is structured to have a lock
- * free fast path.
- */
-STATIC int
-xlog_regrant_write_log_space(
-	struct log		*log,
-	struct xlog_ticket	*tic)
-{
-	int			free_bytes, need_bytes;
-	int			error = 0;
-
-	tic->t_curr_res = tic->t_unit_res;
-	xlog_tic_reset_res(tic);
-
-	if (tic->t_cnt > 0)
-		return 0;
-
-	ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY));
-
-	trace_xfs_log_regrant_write_enter(log, tic);
-
-	/*
-	 * If there are other waiters on the queue then give them a chance at
-	 * logspace before us.  Wake up the first waiters, if we do not wake
-	 * up all the waiters then go to sleep waiting for more free space,
-	 * otherwise try to get some space for this transaction.
-	 */
-	need_bytes = tic->t_unit_res;
-	free_bytes = xlog_space_left(log, &log->l_grant_write_head);
-	if (!list_empty_careful(&log->l_writeq)) {
-		spin_lock(&log->l_grant_write_lock);
-		if (!xlog_writeq_wake(log, &free_bytes) ||
-		    free_bytes < need_bytes)
-			error = xlog_writeq_wait(log, tic, need_bytes);
-		spin_unlock(&log->l_grant_write_lock);
-	} else if (free_bytes < need_bytes) {
-		spin_lock(&log->l_grant_write_lock);
-		error = xlog_writeq_wait(log, tic, need_bytes);
-		spin_unlock(&log->l_grant_write_lock);
-	}
-
-	if (error)
-		return error;
-
-	xlog_grant_add_space(log, &log->l_grant_write_head, need_bytes);
-	trace_xfs_log_regrant_write_exit(log, tic);
-	xlog_verify_grant_tail(log);
-	return 0;
-}
-
 /* The first cnt-1 times through here we don't need to
  * move the grant write head because the permanent
  * reservation has reserved cnt times the unit amount.
@@ -2695,9 +2617,9 @@
 	if (ticket->t_cnt > 0)
 		ticket->t_cnt--;
 
-	xlog_grant_sub_space(log, &log->l_grant_reserve_head,
+	xlog_grant_sub_space(log, &log->l_reserve_head.grant,
 					ticket->t_curr_res);
-	xlog_grant_sub_space(log, &log->l_grant_write_head,
+	xlog_grant_sub_space(log, &log->l_write_head.grant,
 					ticket->t_curr_res);
 	ticket->t_curr_res = ticket->t_unit_res;
 	xlog_tic_reset_res(ticket);
@@ -2708,7 +2630,7 @@
 	if (ticket->t_cnt > 0)
 		return;
 
-	xlog_grant_add_space(log, &log->l_grant_reserve_head,
+	xlog_grant_add_space(log, &log->l_reserve_head.grant,
 					ticket->t_unit_res);
 
 	trace_xfs_log_regrant_reserve_exit(log, ticket);
@@ -2754,14 +2676,13 @@
 		bytes += ticket->t_unit_res*ticket->t_cnt;
 	}
 
-	xlog_grant_sub_space(log, &log->l_grant_reserve_head, bytes);
-	xlog_grant_sub_space(log, &log->l_grant_write_head, bytes);
+	xlog_grant_sub_space(log, &log->l_reserve_head.grant, bytes);
+	xlog_grant_sub_space(log, &log->l_write_head.grant, bytes);
 
 	trace_xfs_log_ungrant_exit(log, ticket);
 
-	xfs_log_move_tail(log->l_mp, 1);
-}	/* xlog_ungrant_log_space */
-
+	xfs_log_space_wake(log->l_mp);
+}
 
 /*
  * Flush iclog to disk if this is the last reference to the given iclog and
@@ -3219,7 +3140,7 @@
 	int		unit_bytes,
 	int		cnt,
 	char		client,
-	uint		xflags,
+	bool		permanent,
 	int		alloc_flags)
 {
 	struct xlog_ticket *tic;
@@ -3313,6 +3234,7 @@
         }
 
 	atomic_set(&tic->t_ref, 1);
+	tic->t_task		= current;
 	INIT_LIST_HEAD(&tic->t_queue);
 	tic->t_unit_res		= unit_bytes;
 	tic->t_curr_res		= unit_bytes;
@@ -3322,9 +3244,8 @@
 	tic->t_clientid		= client;
 	tic->t_flags		= XLOG_TIC_INITED;
 	tic->t_trans_type	= 0;
-	if (xflags & XFS_LOG_PERM_RESERV)
+	if (permanent)
 		tic->t_flags |= XLOG_TIC_PERM_RESERV;
-	init_waitqueue_head(&tic->t_wait);
 
 	xlog_tic_reset_res(tic);
 
@@ -3380,7 +3301,7 @@
 	int		tail_cycle, tail_blocks;
 	int		cycle, space;
 
-	xlog_crack_grant_head(&log->l_grant_write_head, &cycle, &space);
+	xlog_crack_grant_head(&log->l_write_head.grant, &cycle, &space);
 	xlog_crack_atomic_lsn(&log->l_tail_lsn, &tail_cycle, &tail_blocks);
 	if (tail_cycle != cycle) {
 		if (cycle - 1 != tail_cycle &&
@@ -3582,7 +3503,6 @@
 	struct xfs_mount	*mp,
 	int			logerror)
 {
-	xlog_ticket_t	*tic;
 	xlog_t		*log;
 	int		retval;
 
@@ -3650,15 +3570,8 @@
 	 * we don't enqueue anything once the SHUTDOWN flag is set, and this
 	 * action is protected by the grant locks.
 	 */
-	spin_lock(&log->l_grant_reserve_lock);
-	list_for_each_entry(tic, &log->l_reserveq, t_queue)
-		wake_up(&tic->t_wait);
-	spin_unlock(&log->l_grant_reserve_lock);
-
-	spin_lock(&log->l_grant_write_lock);
-	list_for_each_entry(tic, &log->l_writeq, t_queue)
-		wake_up(&tic->t_wait);
-	spin_unlock(&log->l_grant_write_lock);
+	xlog_grant_head_wake_all(&log->l_reserve_head);
+	xlog_grant_head_wake_all(&log->l_write_head);
 
 	if (!(log->l_iclog->ic_state & XLOG_STATE_IOERROR)) {
 		ASSERT(!logerror);
diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h
index 2aee3b2..2c622be 100644
--- a/fs/xfs/xfs_log.h
+++ b/fs/xfs/xfs_log.h
@@ -53,15 +53,6 @@
 #define XFS_LOG_REL_PERM_RESERV	0x1
 
 /*
- * Flags to xfs_log_reserve()
- *
- *	XFS_LOG_PERM_RESERV: Permanent reservation.  When writes are
- *		performed against this type of reservation, the reservation
- *		is not decreased.  Long running transactions should use this.
- */
-#define XFS_LOG_PERM_RESERV	0x2
-
-/*
  * Flags to xfs_log_force()
  *
  *	XFS_LOG_SYNC:	Synchronous force in-core log to disk
@@ -160,8 +151,8 @@
 			xfs_daddr_t		start_block,
 			int		 	num_bblocks);
 int	  xfs_log_mount_finish(struct xfs_mount *mp);
-void	  xfs_log_move_tail(struct xfs_mount	*mp,
-			    xfs_lsn_t		tail_lsn);
+xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp);
+void	  xfs_log_space_wake(struct xfs_mount *mp);
 int	  xfs_log_notify(struct xfs_mount	*mp,
 			 struct xlog_in_core	*iclog,
 			 xfs_log_callback_t	*callback_entry);
@@ -172,8 +163,9 @@
 			  int		   count,
 			  struct xlog_ticket **ticket,
 			  __uint8_t	   clientid,
-			  uint		   flags,
+			  bool		   permanent,
 			  uint		   t_type);
+int	  xfs_log_regrant(struct xfs_mount *mp, struct xlog_ticket *tic);
 int	  xfs_log_unmount_write(struct xfs_mount *mp);
 void      xfs_log_unmount(struct xfs_mount *mp);
 int	  xfs_log_force_umount(struct xfs_mount *mp, int logerror);
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h
index 2d3b6a4..2152900 100644
--- a/fs/xfs/xfs_log_priv.h
+++ b/fs/xfs/xfs_log_priv.h
@@ -239,8 +239,8 @@
 } xlog_res_t;
 
 typedef struct xlog_ticket {
-	wait_queue_head_t  t_wait;	 /* ticket wait queue */
 	struct list_head   t_queue;	 /* reserve/write queue */
+	struct task_struct *t_task;	 /* task that owns this ticket */
 	xlog_tid_t	   t_tid;	 /* transaction identifier	 : 4  */
 	atomic_t	   t_ref;	 /* ticket reference count       : 4  */
 	int		   t_curr_res;	 /* current reservation in bytes : 4  */
@@ -470,6 +470,16 @@
 #define XLOG_CIL_HARD_SPACE_LIMIT(log)	(3 * (log->l_logsize >> 4))
 
 /*
+ * ticket grant locks, queues and accounting have their own cachlines
+ * as these are quite hot and can be operated on concurrently.
+ */
+struct xlog_grant_head {
+	spinlock_t		lock ____cacheline_aligned_in_smp;
+	struct list_head	waiters;
+	atomic64_t		grant;
+};
+
+/*
  * The reservation head lsn is not made up of a cycle number and block number.
  * Instead, it uses a cycle number and byte number.  Logs don't expect to
  * overflow 31 bits worth of byte offset, so using a byte number will mean
@@ -520,17 +530,8 @@
 	/* lsn of 1st LR with unflushed * buffers */
 	atomic64_t		l_tail_lsn ____cacheline_aligned_in_smp;
 
-	/*
-	 * ticket grant locks, queues and accounting have their own cachlines
-	 * as these are quite hot and can be operated on concurrently.
-	 */
-	spinlock_t		l_grant_reserve_lock ____cacheline_aligned_in_smp;
-	struct list_head	l_reserveq;
-	atomic64_t		l_grant_reserve_head;
-
-	spinlock_t		l_grant_write_lock ____cacheline_aligned_in_smp;
-	struct list_head	l_writeq;
-	atomic64_t		l_grant_write_head;
+	struct xlog_grant_head	l_reserve_head;
+	struct xlog_grant_head	l_write_head;
 
 	/* The following field are used for debugging; need to hold icloglock */
 #ifdef DEBUG
@@ -545,14 +546,13 @@
 #define XLOG_FORCED_SHUTDOWN(log)	((log)->l_flags & XLOG_IO_ERROR)
 
 /* common routines */
-extern xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp);
 extern int	 xlog_recover(xlog_t *log);
 extern int	 xlog_recover_finish(xlog_t *log);
 extern void	 xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog, int);
 
 extern kmem_zone_t *xfs_log_ticket_zone;
 struct xlog_ticket *xlog_ticket_alloc(struct log *log, int unit_bytes,
-				int count, char client, uint xflags,
+				int count, char client, bool permanent,
 				int alloc_flags);
 
 
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 0ed9ee7..8ecad5b 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -965,9 +965,9 @@
 		log->l_curr_cycle++;
 	atomic64_set(&log->l_tail_lsn, be64_to_cpu(rhead->h_tail_lsn));
 	atomic64_set(&log->l_last_sync_lsn, be64_to_cpu(rhead->h_lsn));
-	xlog_assign_grant_head(&log->l_grant_reserve_head, log->l_curr_cycle,
+	xlog_assign_grant_head(&log->l_reserve_head.grant, log->l_curr_cycle,
 					BBTOB(log->l_curr_block));
-	xlog_assign_grant_head(&log->l_grant_write_head, log->l_curr_cycle,
+	xlog_assign_grant_head(&log->l_write_head.grant, log->l_curr_cycle,
 					BBTOB(log->l_curr_block));
 
 	/*
@@ -3161,37 +3161,26 @@
 			 */
 			continue;
 		}
+		/*
+		 * Unlock the buffer so that it can be acquired in the normal
+		 * course of the transaction to truncate and free each inode.
+		 * Because we are not racing with anyone else here for the AGI
+		 * buffer, we don't even need to hold it locked to read the
+		 * initial unlinked bucket entries out of the buffer. We keep
+		 * buffer reference though, so that it stays pinned in memory
+		 * while we need the buffer.
+		 */
 		agi = XFS_BUF_TO_AGI(agibp);
+		xfs_buf_unlock(agibp);
 
 		for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) {
 			agino = be32_to_cpu(agi->agi_unlinked[bucket]);
 			while (agino != NULLAGINO) {
-				/*
-				 * Release the agi buffer so that it can
-				 * be acquired in the normal course of the
-				 * transaction to truncate and free the inode.
-				 */
-				xfs_buf_relse(agibp);
-
 				agino = xlog_recover_process_one_iunlink(mp,
 							agno, agino, bucket);
-
-				/*
-				 * Reacquire the agibuffer and continue around
-				 * the loop. This should never fail as we know
-				 * the buffer was good earlier on.
-				 */
-				error = xfs_read_agi(mp, NULL, agno, &agibp);
-				ASSERT(error == 0);
-				agi = XFS_BUF_TO_AGI(agibp);
 			}
 		}
-
-		/*
-		 * Release the buffer for the current agi so we can
-		 * go on to the next one.
-		 */
-		xfs_buf_relse(agibp);
+		xfs_buf_rele(agibp);
 	}
 
 	mp->m_dmevmask = mp_dmevmask;
@@ -3695,7 +3684,7 @@
 
 	/* Convert superblock from on-disk format */
 	sbp = &log->l_mp->m_sb;
-	xfs_sb_from_disk(sbp, XFS_BUF_TO_SBP(bp));
+	xfs_sb_from_disk(log->l_mp, XFS_BUF_TO_SBP(bp));
 	ASSERT(sbp->sb_magicnum == XFS_SB_MAGIC);
 	ASSERT(xfs_sb_good_version(sbp));
 	xfs_buf_relse(bp);
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index d06afbc..1ffead4 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -158,7 +158,7 @@
 
  out_duplicate:
 	mutex_unlock(&xfs_uuid_table_mutex);
-	xfs_warn(mp, "Filesystem has duplicate UUID - can't mount");
+	xfs_warn(mp, "Filesystem has duplicate UUID %pU - can't mount", uuid);
 	return XFS_ERROR(EINVAL);
 }
 
@@ -553,9 +553,11 @@
 
 void
 xfs_sb_from_disk(
-	xfs_sb_t	*to,
+	struct xfs_mount	*mp,
 	xfs_dsb_t	*from)
 {
+	struct xfs_sb *to = &mp->m_sb;
+
 	to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
 	to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
 	to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
@@ -693,7 +695,7 @@
 	 * Initialize the mount structure from the superblock.
 	 * But first do some basic consistency checking.
 	 */
-	xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp));
+	xfs_sb_from_disk(mp, XFS_BUF_TO_SBP(bp));
 	error = xfs_mount_validate_sb(mp, &(mp->m_sb), flags);
 	if (error) {
 		if (loud)
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 19f69e2..9eba738 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -211,6 +211,9 @@
 	struct shrinker		m_inode_shrink;	/* inode reclaim shrinker */
 	int64_t			m_low_space[XFS_LOWSP_MAX];
 						/* low free space thresholds */
+
+	struct workqueue_struct	*m_data_workqueue;
+	struct workqueue_struct	*m_unwritten_workqueue;
 } xfs_mount_t;
 
 /*
@@ -395,7 +398,7 @@
 extern void	xfs_mod_sb(struct xfs_trans *, __int64_t);
 extern int	xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t,
 					xfs_agnumber_t *);
-extern void	xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *);
+extern void	xfs_sb_from_disk(struct xfs_mount *, struct xfs_dsb *);
 extern void	xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t);
 
 #endif	/* __XFS_MOUNT_H__ */
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index c436def..55c6afe 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -48,194 +48,189 @@
  * quota functionality, including maintaining the freelist and hash
  * tables of dquots.
  */
-struct mutex	xfs_Gqm_lock;
-struct xfs_qm	*xfs_Gqm;
-
-kmem_zone_t	*qm_dqzone;
-kmem_zone_t	*qm_dqtrxzone;
-
-STATIC void	xfs_qm_list_init(xfs_dqlist_t *, char *, int);
-STATIC void	xfs_qm_list_destroy(xfs_dqlist_t *);
-
 STATIC int	xfs_qm_init_quotainos(xfs_mount_t *);
 STATIC int	xfs_qm_init_quotainfo(xfs_mount_t *);
 STATIC int	xfs_qm_shake(struct shrinker *, struct shrink_control *);
 
-static struct shrinker xfs_qm_shaker = {
-	.shrink = xfs_qm_shake,
-	.seeks = DEFAULT_SEEKS,
-};
-
 /*
- * Initialize the XQM structure.
- * Note that there is not one quota manager per file system.
+ * We use the batch lookup interface to iterate over the dquots as it
+ * currently is the only interface into the radix tree code that allows
+ * fuzzy lookups instead of exact matches.  Holding the lock over multiple
+ * operations is fine as all callers are used either during mount/umount
+ * or quotaoff.
  */
-STATIC struct xfs_qm *
-xfs_Gqm_init(void)
-{
-	xfs_dqhash_t	*udqhash, *gdqhash;
-	xfs_qm_t	*xqm;
-	size_t		hsize;
-	uint		i;
+#define XFS_DQ_LOOKUP_BATCH	32
 
-	/*
-	 * Initialize the dquot hash tables.
-	 */
-	udqhash = kmem_zalloc_greedy(&hsize,
-				     XFS_QM_HASHSIZE_LOW * sizeof(xfs_dqhash_t),
-				     XFS_QM_HASHSIZE_HIGH * sizeof(xfs_dqhash_t));
-	if (!udqhash)
-		goto out;
-
-	gdqhash = kmem_zalloc_large(hsize);
-	if (!gdqhash)
-		goto out_free_udqhash;
-
-	hsize /= sizeof(xfs_dqhash_t);
-
-	xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP);
-	xqm->qm_dqhashmask = hsize - 1;
-	xqm->qm_usr_dqhtable = udqhash;
-	xqm->qm_grp_dqhtable = gdqhash;
-	ASSERT(xqm->qm_usr_dqhtable != NULL);
-	ASSERT(xqm->qm_grp_dqhtable != NULL);
-
-	for (i = 0; i < hsize; i++) {
-		xfs_qm_list_init(&(xqm->qm_usr_dqhtable[i]), "uxdqh", i);
-		xfs_qm_list_init(&(xqm->qm_grp_dqhtable[i]), "gxdqh", i);
-	}
-
-	/*
-	 * Freelist of all dquots of all file systems
-	 */
-	INIT_LIST_HEAD(&xqm->qm_dqfrlist);
-	xqm->qm_dqfrlist_cnt = 0;
-	mutex_init(&xqm->qm_dqfrlist_lock);
-
-	/*
-	 * dquot zone. we register our own low-memory callback.
-	 */
-	if (!qm_dqzone) {
-		xqm->qm_dqzone = kmem_zone_init(sizeof(xfs_dquot_t),
-						"xfs_dquots");
-		qm_dqzone = xqm->qm_dqzone;
-	} else
-		xqm->qm_dqzone = qm_dqzone;
-
-	register_shrinker(&xfs_qm_shaker);
-
-	/*
-	 * The t_dqinfo portion of transactions.
-	 */
-	if (!qm_dqtrxzone) {
-		xqm->qm_dqtrxzone = kmem_zone_init(sizeof(xfs_dquot_acct_t),
-						   "xfs_dqtrx");
-		qm_dqtrxzone = xqm->qm_dqtrxzone;
-	} else
-		xqm->qm_dqtrxzone = qm_dqtrxzone;
-
-	atomic_set(&xqm->qm_totaldquots, 0);
-	xqm->qm_nrefs = 0;
-	return xqm;
-
- out_free_udqhash:
-	kmem_free_large(udqhash);
- out:
-	return NULL;
-}
-
-/*
- * Destroy the global quota manager when its reference count goes to zero.
- */
-STATIC void
-xfs_qm_destroy(
-	struct xfs_qm	*xqm)
-{
-	int		hsize, i;
-
-	ASSERT(xqm != NULL);
-	ASSERT(xqm->qm_nrefs == 0);
-
-	unregister_shrinker(&xfs_qm_shaker);
-
-	mutex_lock(&xqm->qm_dqfrlist_lock);
-	ASSERT(list_empty(&xqm->qm_dqfrlist));
-	mutex_unlock(&xqm->qm_dqfrlist_lock);
-
-	hsize = xqm->qm_dqhashmask + 1;
-	for (i = 0; i < hsize; i++) {
-		xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
-		xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i]));
-	}
-	kmem_free_large(xqm->qm_usr_dqhtable);
-	kmem_free_large(xqm->qm_grp_dqhtable);
-	xqm->qm_usr_dqhtable = NULL;
-	xqm->qm_grp_dqhtable = NULL;
-	xqm->qm_dqhashmask = 0;
-
-	kmem_free(xqm);
-}
-
-/*
- * Called at mount time to let XQM know that another file system is
- * starting quotas. This isn't crucial information as the individual mount
- * structures are pretty independent, but it helps the XQM keep a
- * global view of what's going on.
- */
-/* ARGSUSED */
 STATIC int
-xfs_qm_hold_quotafs_ref(
-	struct xfs_mount *mp)
+xfs_qm_dquot_walk(
+	struct xfs_mount	*mp,
+	int			type,
+	int			(*execute)(struct xfs_dquot *dqp))
 {
-	/*
-	 * Need to lock the xfs_Gqm structure for things like this. For example,
-	 * the structure could disappear between the entry to this routine and
-	 * a HOLD operation if not locked.
-	 */
-	mutex_lock(&xfs_Gqm_lock);
+	struct xfs_quotainfo	*qi = mp->m_quotainfo;
+	struct radix_tree_root	*tree = XFS_DQUOT_TREE(qi, type);
+	uint32_t		next_index;
+	int			last_error = 0;
+	int			skipped;
+	int			nr_found;
 
-	if (!xfs_Gqm) {
-		xfs_Gqm = xfs_Gqm_init();
-		if (!xfs_Gqm) {
-			mutex_unlock(&xfs_Gqm_lock);
-			return ENOMEM;
+restart:
+	skipped = 0;
+	next_index = 0;
+	nr_found = 0;
+
+	while (1) {
+		struct xfs_dquot *batch[XFS_DQ_LOOKUP_BATCH];
+		int		error = 0;
+		int		i;
+
+		mutex_lock(&qi->qi_tree_lock);
+		nr_found = radix_tree_gang_lookup(tree, (void **)batch,
+					next_index, XFS_DQ_LOOKUP_BATCH);
+		if (!nr_found) {
+			mutex_unlock(&qi->qi_tree_lock);
+			break;
+		}
+
+		for (i = 0; i < nr_found; i++) {
+			struct xfs_dquot *dqp = batch[i];
+
+			next_index = be32_to_cpu(dqp->q_core.d_id) + 1;
+
+			error = execute(batch[i]);
+			if (error == EAGAIN) {
+				skipped++;
+				continue;
+			}
+			if (error && last_error != EFSCORRUPTED)
+				last_error = error;
+		}
+
+		mutex_unlock(&qi->qi_tree_lock);
+
+		/* bail out if the filesystem is corrupted.  */
+		if (last_error == EFSCORRUPTED) {
+			skipped = 0;
+			break;
 		}
 	}
 
-	/*
-	 * We can keep a list of all filesystems with quotas mounted for
-	 * debugging and statistical purposes, but ...
-	 * Just take a reference and get out.
-	 */
-	xfs_Gqm->qm_nrefs++;
-	mutex_unlock(&xfs_Gqm_lock);
+	if (skipped) {
+		delay(1);
+		goto restart;
+	}
 
-	return 0;
+	return last_error;
 }
 
 
 /*
- * Release the reference that a filesystem took at mount time,
- * so that we know when we need to destroy the entire quota manager.
+ * Purge a dquot from all tracking data structures and free it.
  */
-/* ARGSUSED */
-STATIC void
-xfs_qm_rele_quotafs_ref(
-	struct xfs_mount *mp)
+STATIC int
+xfs_qm_dqpurge(
+	struct xfs_dquot	*dqp)
 {
-	ASSERT(xfs_Gqm);
-	ASSERT(xfs_Gqm->qm_nrefs > 0);
+	struct xfs_mount	*mp = dqp->q_mount;
+	struct xfs_quotainfo	*qi = mp->m_quotainfo;
+	struct xfs_dquot	*gdqp = NULL;
+
+	xfs_dqlock(dqp);
+	if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0) {
+		xfs_dqunlock(dqp);
+		return EAGAIN;
+	}
 
 	/*
-	 * Destroy the entire XQM. If somebody mounts with quotaon, this'll
-	 * be restarted.
+	 * If this quota has a group hint attached, prepare for releasing it
+	 * now.
 	 */
-	mutex_lock(&xfs_Gqm_lock);
-	if (--xfs_Gqm->qm_nrefs == 0) {
-		xfs_qm_destroy(xfs_Gqm);
-		xfs_Gqm = NULL;
+	gdqp = dqp->q_gdquot;
+	if (gdqp) {
+		xfs_dqlock(gdqp);
+		dqp->q_gdquot = NULL;
 	}
-	mutex_unlock(&xfs_Gqm_lock);
+
+	dqp->dq_flags |= XFS_DQ_FREEING;
+
+	/*
+	 * If we're turning off quotas, we have to make sure that, for
+	 * example, we don't delete quota disk blocks while dquots are
+	 * in the process of getting written to those disk blocks.
+	 * This dquot might well be on AIL, and we can't leave it there
+	 * if we're turning off quotas. Basically, we need this flush
+	 * lock, and are willing to block on it.
+	 */
+	if (!xfs_dqflock_nowait(dqp)) {
+		/*
+		 * Block on the flush lock after nudging dquot buffer,
+		 * if it is incore.
+		 */
+		xfs_dqflock_pushbuf_wait(dqp);
+	}
+
+	/*
+	 * If we are turning this type of quotas off, we don't care
+	 * about the dirty metadata sitting in this dquot. OTOH, if
+	 * we're unmounting, we do care, so we flush it and wait.
+	 */
+	if (XFS_DQ_IS_DIRTY(dqp)) {
+		int	error;
+
+		/*
+		 * We don't care about getting disk errors here. We need
+		 * to purge this dquot anyway, so we go ahead regardless.
+		 */
+		error = xfs_qm_dqflush(dqp, SYNC_WAIT);
+		if (error)
+			xfs_warn(mp, "%s: dquot %p flush failed",
+				__func__, dqp);
+		xfs_dqflock(dqp);
+	}
+
+	ASSERT(atomic_read(&dqp->q_pincount) == 0);
+	ASSERT(XFS_FORCED_SHUTDOWN(mp) ||
+	       !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL));
+
+	xfs_dqfunlock(dqp);
+	xfs_dqunlock(dqp);
+
+	radix_tree_delete(XFS_DQUOT_TREE(qi, dqp->q_core.d_flags),
+			  be32_to_cpu(dqp->q_core.d_id));
+	qi->qi_dquots--;
+
+	/*
+	 * We move dquots to the freelist as soon as their reference count
+	 * hits zero, so it really should be on the freelist here.
+	 */
+	mutex_lock(&qi->qi_lru_lock);
+	ASSERT(!list_empty(&dqp->q_lru));
+	list_del_init(&dqp->q_lru);
+	qi->qi_lru_count--;
+	XFS_STATS_DEC(xs_qm_dquot_unused);
+	mutex_unlock(&qi->qi_lru_lock);
+
+	xfs_qm_dqdestroy(dqp);
+
+	if (gdqp)
+		xfs_qm_dqput(gdqp);
+	return 0;
+}
+
+/*
+ * Purge the dquot cache.
+ */
+void
+xfs_qm_dqpurge_all(
+	struct xfs_mount	*mp,
+	uint			flags)
+{
+	if (flags & XFS_QMOPT_UQUOTA)
+		xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_dqpurge);
+	if (flags & XFS_QMOPT_GQUOTA)
+		xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_dqpurge);
+	if (flags & XFS_QMOPT_PQUOTA)
+		xfs_qm_dquot_walk(mp, XFS_DQ_PROJ, xfs_qm_dqpurge);
 }
 
 /*
@@ -376,175 +371,6 @@
 	}
 }
 
-/*
- * Flush all dquots of the given file system to disk. The dquots are
- * _not_ purged from memory here, just their data written to disk.
- */
-STATIC int
-xfs_qm_dqflush_all(
-	struct xfs_mount	*mp)
-{
-	struct xfs_quotainfo	*q = mp->m_quotainfo;
-	int			recl;
-	struct xfs_dquot	*dqp;
-	int			error;
-
-	if (!q)
-		return 0;
-again:
-	mutex_lock(&q->qi_dqlist_lock);
-	list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) {
-		xfs_dqlock(dqp);
-		if ((dqp->dq_flags & XFS_DQ_FREEING) ||
-		    !XFS_DQ_IS_DIRTY(dqp)) {
-			xfs_dqunlock(dqp);
-			continue;
-		}
-
-		/* XXX a sentinel would be better */
-		recl = q->qi_dqreclaims;
-		if (!xfs_dqflock_nowait(dqp)) {
-			/*
-			 * If we can't grab the flush lock then check
-			 * to see if the dquot has been flushed delayed
-			 * write.  If so, grab its buffer and send it
-			 * out immediately.  We'll be able to acquire
-			 * the flush lock when the I/O completes.
-			 */
-			xfs_dqflock_pushbuf_wait(dqp);
-		}
-		/*
-		 * Let go of the mplist lock. We don't want to hold it
-		 * across a disk write.
-		 */
-		mutex_unlock(&q->qi_dqlist_lock);
-		error = xfs_qm_dqflush(dqp, 0);
-		xfs_dqunlock(dqp);
-		if (error)
-			return error;
-
-		mutex_lock(&q->qi_dqlist_lock);
-		if (recl != q->qi_dqreclaims) {
-			mutex_unlock(&q->qi_dqlist_lock);
-			/* XXX restart limit */
-			goto again;
-		}
-	}
-
-	mutex_unlock(&q->qi_dqlist_lock);
-	/* return ! busy */
-	return 0;
-}
-
-/*
- * Release the group dquot pointers the user dquots may be
- * carrying around as a hint. mplist is locked on entry and exit.
- */
-STATIC void
-xfs_qm_detach_gdquots(
-	struct xfs_mount	*mp)
-{
-	struct xfs_quotainfo	*q = mp->m_quotainfo;
-	struct xfs_dquot	*dqp, *gdqp;
-
- again:
-	ASSERT(mutex_is_locked(&q->qi_dqlist_lock));
-	list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) {
-		xfs_dqlock(dqp);
-		if (dqp->dq_flags & XFS_DQ_FREEING) {
-			xfs_dqunlock(dqp);
-			mutex_unlock(&q->qi_dqlist_lock);
-			delay(1);
-			mutex_lock(&q->qi_dqlist_lock);
-			goto again;
-		}
-
-		gdqp = dqp->q_gdquot;
-		if (gdqp)
-			dqp->q_gdquot = NULL;
-		xfs_dqunlock(dqp);
-
-		if (gdqp)
-			xfs_qm_dqrele(gdqp);
-	}
-}
-
-/*
- * Go through all the incore dquots of this file system and take them
- * off the mplist and hashlist, if the dquot type matches the dqtype
- * parameter. This is used when turning off quota accounting for
- * users and/or groups, as well as when the filesystem is unmounting.
- */
-STATIC int
-xfs_qm_dqpurge_int(
-	struct xfs_mount	*mp,
-	uint			flags)
-{
-	struct xfs_quotainfo	*q = mp->m_quotainfo;
-	struct xfs_dquot	*dqp, *n;
-	uint			dqtype;
-	int			nmisses = 0;
-	LIST_HEAD		(dispose_list);
-
-	if (!q)
-		return 0;
-
-	dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0;
-	dqtype |= (flags & XFS_QMOPT_PQUOTA) ? XFS_DQ_PROJ : 0;
-	dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0;
-
-	mutex_lock(&q->qi_dqlist_lock);
-
-	/*
-	 * In the first pass through all incore dquots of this filesystem,
-	 * we release the group dquot pointers the user dquots may be
-	 * carrying around as a hint. We need to do this irrespective of
-	 * what's being turned off.
-	 */
-	xfs_qm_detach_gdquots(mp);
-
-	/*
-	 * Try to get rid of all of the unwanted dquots.
-	 */
-	list_for_each_entry_safe(dqp, n, &q->qi_dqlist, q_mplist) {
-		xfs_dqlock(dqp);
-		if ((dqp->dq_flags & dqtype) != 0 &&
-		    !(dqp->dq_flags & XFS_DQ_FREEING)) {
-			if (dqp->q_nrefs == 0) {
-				dqp->dq_flags |= XFS_DQ_FREEING;
-				list_move_tail(&dqp->q_mplist, &dispose_list);
-			} else
-				nmisses++;
-		}
-		xfs_dqunlock(dqp);
-	}
-	mutex_unlock(&q->qi_dqlist_lock);
-
-	list_for_each_entry_safe(dqp, n, &dispose_list, q_mplist)
-		xfs_qm_dqpurge(dqp);
-
-	return nmisses;
-}
-
-int
-xfs_qm_dqpurge_all(
-	xfs_mount_t	*mp,
-	uint		flags)
-{
-	int		ndquots;
-
-	/*
-	 * Purge the dquot cache.
-	 * None of the dquots should really be busy at this point.
-	 */
-	if (mp->m_quotainfo) {
-		while ((ndquots = xfs_qm_dqpurge_int(mp, flags))) {
-			delay(ndquots * 10);
-		}
-	}
-	return 0;
-}
-
 STATIC int
 xfs_qm_dqattach_one(
 	xfs_inode_t	*ip,
@@ -783,14 +609,6 @@
 }
 
 /*
- * The hash chains and the mplist use the same xfs_dqhash structure as
- * their list head, but we can take the mplist qh_lock and one of the
- * hash qh_locks at the same time without any problem as they aren't
- * related.
- */
-static struct lock_class_key xfs_quota_mplist_class;
-
-/*
  * This initializes all the quota information that's kept in the
  * mount structure
  */
@@ -804,13 +622,6 @@
 
 	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
 
-	/*
-	 * Tell XQM that we exist as soon as possible.
-	 */
-	if ((error = xfs_qm_hold_quotafs_ref(mp))) {
-		return error;
-	}
-
 	qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), KM_SLEEP);
 
 	/*
@@ -823,11 +634,13 @@
 		return error;
 	}
 
-	INIT_LIST_HEAD(&qinf->qi_dqlist);
-	mutex_init(&qinf->qi_dqlist_lock);
-	lockdep_set_class(&qinf->qi_dqlist_lock, &xfs_quota_mplist_class);
+	INIT_RADIX_TREE(&qinf->qi_uquota_tree, GFP_NOFS);
+	INIT_RADIX_TREE(&qinf->qi_gquota_tree, GFP_NOFS);
+	mutex_init(&qinf->qi_tree_lock);
 
-	qinf->qi_dqreclaims = 0;
+	INIT_LIST_HEAD(&qinf->qi_lru_list);
+	qinf->qi_lru_count = 0;
+	mutex_init(&qinf->qi_lru_lock);
 
 	/* mutex used to serialize quotaoffs */
 	mutex_init(&qinf->qi_quotaofflock);
@@ -894,6 +707,9 @@
 		qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT;
 	}
 
+	qinf->qi_shrinker.shrink = xfs_qm_shake;
+	qinf->qi_shrinker.seeks = DEFAULT_SEEKS;
+	register_shrinker(&qinf->qi_shrinker);
 	return 0;
 }
 
@@ -911,17 +727,8 @@
 
 	qi = mp->m_quotainfo;
 	ASSERT(qi != NULL);
-	ASSERT(xfs_Gqm != NULL);
 
-	/*
-	 * Release the reference that XQM kept, so that we know
-	 * when the XQM structure should be freed. We cannot assume
-	 * that xfs_Gqm is non-null after this point.
-	 */
-	xfs_qm_rele_quotafs_ref(mp);
-
-	ASSERT(list_empty(&qi->qi_dqlist));
-	mutex_destroy(&qi->qi_dqlist_lock);
+	unregister_shrinker(&qi->qi_shrinker);
 
 	if (qi->qi_uquotaip) {
 		IRELE(qi->qi_uquotaip);
@@ -936,30 +743,6 @@
 	mp->m_quotainfo = NULL;
 }
 
-
-
-/* ------------------- PRIVATE STATIC FUNCTIONS ----------------------- */
-
-/* ARGSUSED */
-STATIC void
-xfs_qm_list_init(
-	xfs_dqlist_t	*list,
-	char		*str,
-	int		n)
-{
-	mutex_init(&list->qh_lock);
-	INIT_LIST_HEAD(&list->qh_list);
-	list->qh_version = 0;
-	list->qh_nelems = 0;
-}
-
-STATIC void
-xfs_qm_list_destroy(
-	xfs_dqlist_t	*list)
-{
-	mutex_destroy(&(list->qh_lock));
-}
-
 /*
  * Create an inode and return with a reference already taken, but unlocked
  * This is how we create quota inodes
@@ -1397,6 +1180,28 @@
 	return error;
 }
 
+STATIC int
+xfs_qm_flush_one(
+	struct xfs_dquot	*dqp)
+{
+	int			error = 0;
+
+	xfs_dqlock(dqp);
+	if (dqp->dq_flags & XFS_DQ_FREEING)
+		goto out_unlock;
+	if (!XFS_DQ_IS_DIRTY(dqp))
+		goto out_unlock;
+
+	if (!xfs_dqflock_nowait(dqp))
+		xfs_dqflock_pushbuf_wait(dqp);
+
+	error = xfs_qm_dqflush(dqp, 0);
+
+out_unlock:
+	xfs_dqunlock(dqp);
+	return error;
+}
+
 /*
  * Walk thru all the filesystem inodes and construct a consistent view
  * of the disk quota world. If the quotacheck fails, disable quotas.
@@ -1405,7 +1210,7 @@
 xfs_qm_quotacheck(
 	xfs_mount_t	*mp)
 {
-	int		done, count, error;
+	int		done, count, error, error2;
 	xfs_ino_t	lastino;
 	size_t		structsz;
 	xfs_inode_t	*uip, *gip;
@@ -1419,12 +1224,6 @@
 	ASSERT(mp->m_quotainfo->qi_uquotaip || mp->m_quotainfo->qi_gquotaip);
 	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
 
-	/*
-	 * There should be no cached dquots. The (simplistic) quotacheck
-	 * algorithm doesn't like that.
-	 */
-	ASSERT(list_empty(&mp->m_quotainfo->qi_dqlist));
-
 	xfs_notice(mp, "Quotacheck needed: Please wait.");
 
 	/*
@@ -1463,12 +1262,21 @@
 	} while (!done);
 
 	/*
-	 * We've made all the changes that we need to make incore.
-	 * Flush them down to disk buffers if everything was updated
-	 * successfully.
+	 * We've made all the changes that we need to make incore.  Flush them
+	 * down to disk buffers if everything was updated successfully.
 	 */
-	if (!error)
-		error = xfs_qm_dqflush_all(mp);
+	if (XFS_IS_UQUOTA_ON(mp))
+		error = xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_flush_one);
+	if (XFS_IS_GQUOTA_ON(mp)) {
+		error2 = xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_flush_one);
+		if (!error)
+			error = error2;
+	}
+	if (XFS_IS_PQUOTA_ON(mp)) {
+		error2 = xfs_qm_dquot_walk(mp, XFS_DQ_PROJ, xfs_qm_flush_one);
+		if (!error)
+			error = error2;
+	}
 
 	/*
 	 * We can get this error if we couldn't do a dquot allocation inside
@@ -1496,7 +1304,7 @@
 	 * quotachecked status, since we won't be doing accounting for
 	 * that type anymore.
 	 */
-	mp->m_qflags &= ~(XFS_OQUOTA_CHKD | XFS_UQUOTA_CHKD);
+	mp->m_qflags &= ~XFS_ALL_QUOTA_CHKD;
 	mp->m_qflags |= flags;
 
  error_return:
@@ -1508,7 +1316,6 @@
 		 * We must turn off quotas.
 		 */
 		ASSERT(mp->m_quotainfo != NULL);
-		ASSERT(xfs_Gqm != NULL);
 		xfs_qm_destroy_quotainfo(mp);
 		if (xfs_mount_reset_sbqflags(mp)) {
 			xfs_warn(mp,
@@ -1604,16 +1411,12 @@
 	struct xfs_mount	*mp = dqp->q_mount;
 	struct xfs_quotainfo	*qi = mp->m_quotainfo;
 
-	mutex_lock(&dqp->q_hash->qh_lock);
-	list_del_init(&dqp->q_hashlist);
-	dqp->q_hash->qh_version++;
-	mutex_unlock(&dqp->q_hash->qh_lock);
+	mutex_lock(&qi->qi_tree_lock);
+	radix_tree_delete(XFS_DQUOT_TREE(qi, dqp->q_core.d_flags),
+			  be32_to_cpu(dqp->q_core.d_id));
 
-	mutex_lock(&qi->qi_dqlist_lock);
-	list_del_init(&dqp->q_mplist);
 	qi->qi_dquots--;
-	qi->qi_dqreclaims++;
-	mutex_unlock(&qi->qi_dqlist_lock);
+	mutex_unlock(&qi->qi_tree_lock);
 
 	xfs_qm_dqdestroy(dqp);
 }
@@ -1624,6 +1427,7 @@
 	struct list_head	*dispose_list)
 {
 	struct xfs_mount	*mp = dqp->q_mount;
+	struct xfs_quotainfo	*qi = mp->m_quotainfo;
 	int			error;
 
 	if (!xfs_dqlock_nowait(dqp))
@@ -1637,16 +1441,14 @@
 		xfs_dqunlock(dqp);
 
 		trace_xfs_dqreclaim_want(dqp);
-		XQM_STATS_INC(xqmstats.xs_qm_dqwants);
+		XFS_STATS_INC(xs_qm_dqwants);
 
-		list_del_init(&dqp->q_freelist);
-		xfs_Gqm->qm_dqfrlist_cnt--;
+		list_del_init(&dqp->q_lru);
+		qi->qi_lru_count--;
+		XFS_STATS_DEC(xs_qm_dquot_unused);
 		return;
 	}
 
-	ASSERT(dqp->q_hash);
-	ASSERT(!list_empty(&dqp->q_mplist));
-
 	/*
 	 * Try to grab the flush lock. If this dquot is in the process of
 	 * getting flushed to disk, we don't want to reclaim it.
@@ -1688,11 +1490,12 @@
 	xfs_dqunlock(dqp);
 
 	ASSERT(dqp->q_nrefs == 0);
-	list_move_tail(&dqp->q_freelist, dispose_list);
-	xfs_Gqm->qm_dqfrlist_cnt--;
+	list_move_tail(&dqp->q_lru, dispose_list);
+	qi->qi_lru_count--;
+	XFS_STATS_DEC(xs_qm_dquot_unused);
 
 	trace_xfs_dqreclaim_done(dqp);
-	XQM_STATS_INC(xqmstats.xs_qm_dqreclaims);
+	XFS_STATS_INC(xs_qm_dqreclaims);
 	return;
 
 out_busy:
@@ -1701,10 +1504,10 @@
 	/*
 	 * Move the dquot to the tail of the list so that we don't spin on it.
 	 */
-	list_move_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist);
+	list_move_tail(&dqp->q_lru, &qi->qi_lru_list);
 
 	trace_xfs_dqreclaim_busy(dqp);
-	XQM_STATS_INC(xqmstats.xs_qm_dqreclaim_misses);
+	XFS_STATS_INC(xs_qm_dqreclaim_misses);
 }
 
 STATIC int
@@ -1712,6 +1515,8 @@
 	struct shrinker		*shrink,
 	struct shrink_control	*sc)
 {
+	struct xfs_quotainfo	*qi =
+		container_of(shrink, struct xfs_quotainfo, qi_shrinker);
 	int			nr_to_scan = sc->nr_to_scan;
 	LIST_HEAD		(dispose_list);
 	struct xfs_dquot	*dqp;
@@ -1721,24 +1526,23 @@
 	if (!nr_to_scan)
 		goto out;
 
-	mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
-	while (!list_empty(&xfs_Gqm->qm_dqfrlist)) {
+	mutex_lock(&qi->qi_lru_lock);
+	while (!list_empty(&qi->qi_lru_list)) {
 		if (nr_to_scan-- <= 0)
 			break;
-		dqp = list_first_entry(&xfs_Gqm->qm_dqfrlist, struct xfs_dquot,
-				       q_freelist);
+		dqp = list_first_entry(&qi->qi_lru_list, struct xfs_dquot,
+				       q_lru);
 		xfs_qm_dqreclaim_one(dqp, &dispose_list);
 	}
-	mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
+	mutex_unlock(&qi->qi_lru_lock);
 
 	while (!list_empty(&dispose_list)) {
-		dqp = list_first_entry(&dispose_list, struct xfs_dquot,
-				       q_freelist);
-		list_del_init(&dqp->q_freelist);
+		dqp = list_first_entry(&dispose_list, struct xfs_dquot, q_lru);
+		list_del_init(&dqp->q_lru);
 		xfs_qm_dqfree_one(dqp);
 	}
 out:
-	return (xfs_Gqm->qm_dqfrlist_cnt / 100) * sysctl_vfs_cache_pressure;
+	return (qi->qi_lru_count / 100) * sysctl_vfs_cache_pressure;
 }
 
 /*
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 9a9b997..44b858b 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -21,21 +21,10 @@
 #include "xfs_dquot_item.h"
 #include "xfs_dquot.h"
 #include "xfs_quota_priv.h"
-#include "xfs_qm_stats.h"
 
-struct xfs_qm;
 struct xfs_inode;
 
-extern struct mutex	xfs_Gqm_lock;
-extern struct xfs_qm	*xfs_Gqm;
-extern kmem_zone_t	*qm_dqzone;
-extern kmem_zone_t	*qm_dqtrxzone;
-
-/*
- * Dquot hashtable constants/threshold values.
- */
-#define XFS_QM_HASHSIZE_LOW		(PAGE_SIZE / sizeof(xfs_dqhash_t))
-#define XFS_QM_HASHSIZE_HIGH		((PAGE_SIZE * 4) / sizeof(xfs_dqhash_t))
+extern struct kmem_zone	*xfs_qm_dqtrxzone;
 
 /*
  * This defines the unit of allocation of dquots.
@@ -48,36 +37,20 @@
  */
 #define XFS_DQUOT_CLUSTER_SIZE_FSB	(xfs_filblks_t)1
 
-typedef xfs_dqhash_t	xfs_dqlist_t;
-
-/*
- * Quota Manager (global) structure. Lives only in core.
- */
-typedef struct xfs_qm {
-	xfs_dqlist_t	*qm_usr_dqhtable;/* udquot hash table */
-	xfs_dqlist_t	*qm_grp_dqhtable;/* gdquot hash table */
-	uint		 qm_dqhashmask;	 /* # buckets in dq hashtab - 1 */
-	struct list_head qm_dqfrlist;	 /* freelist of dquots */
-	struct mutex	 qm_dqfrlist_lock;
-	int		 qm_dqfrlist_cnt;
-	atomic_t	 qm_totaldquots; /* total incore dquots */
-	uint		 qm_nrefs;	 /* file systems with quota on */
-	kmem_zone_t	*qm_dqzone;	 /* dquot mem-alloc zone */
-	kmem_zone_t	*qm_dqtrxzone;	 /* t_dqinfo of transactions */
-} xfs_qm_t;
-
 /*
  * Various quota information for individual filesystems.
  * The mount structure keeps a pointer to this.
  */
 typedef struct xfs_quotainfo {
+	struct radix_tree_root qi_uquota_tree;
+	struct radix_tree_root qi_gquota_tree;
+	struct mutex qi_tree_lock;
 	xfs_inode_t	*qi_uquotaip;	 /* user quota inode */
 	xfs_inode_t	*qi_gquotaip;	 /* group quota inode */
-	struct list_head qi_dqlist;	 /* all dquots in filesys */
-	struct mutex	 qi_dqlist_lock;
+	struct list_head qi_lru_list;
+	struct mutex	 qi_lru_lock;
+	int		 qi_lru_count;
 	int		 qi_dquots;
-	int		 qi_dqreclaims;	 /* a change here indicates
-					    a removal in the dqlist */
 	time_t		 qi_btimelimit;	 /* limit for blks timer */
 	time_t		 qi_itimelimit;	 /* limit for inodes timer */
 	time_t		 qi_rtbtimelimit;/* limit for rt blks timer */
@@ -93,8 +66,14 @@
 	xfs_qcnt_t	 qi_isoftlimit;	 /* default inode count soft limit */
 	xfs_qcnt_t	 qi_rtbhardlimit;/* default realtime blk hard limit */
 	xfs_qcnt_t	 qi_rtbsoftlimit;/* default realtime blk soft limit */
+	struct shrinker  qi_shrinker;
 } xfs_quotainfo_t;
 
+#define XFS_DQUOT_TREE(qi, type) \
+	((type & XFS_DQ_USER) ? \
+	 &((qi)->qi_uquota_tree) : \
+	 &((qi)->qi_gquota_tree))
+
 
 extern void	xfs_trans_mod_dquot(xfs_trans_t *, xfs_dquot_t *, uint, long);
 extern int	xfs_trans_reserve_quota_bydquots(xfs_trans_t *, xfs_mount_t *,
@@ -130,7 +109,7 @@
 extern int		xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t);
 
 /* dquot stuff */
-extern int		xfs_qm_dqpurge_all(xfs_mount_t *, uint);
+extern void		xfs_qm_dqpurge_all(xfs_mount_t *, uint);
 extern void		xfs_qm_dqrele_all_inodes(xfs_mount_t *, uint);
 
 /* quota ops */
diff --git a/fs/xfs/xfs_qm_bhv.c b/fs/xfs/xfs_qm_bhv.c
index a0a829a..e6986b5 100644
--- a/fs/xfs/xfs_qm_bhv.c
+++ b/fs/xfs/xfs_qm_bhv.c
@@ -40,28 +40,28 @@
 STATIC void
 xfs_fill_statvfs_from_dquot(
 	struct kstatfs		*statp,
-	xfs_disk_dquot_t	*dp)
+	struct xfs_dquot	*dqp)
 {
 	__uint64_t		limit;
 
-	limit = dp->d_blk_softlimit ?
-		be64_to_cpu(dp->d_blk_softlimit) :
-		be64_to_cpu(dp->d_blk_hardlimit);
+	limit = dqp->q_core.d_blk_softlimit ?
+		be64_to_cpu(dqp->q_core.d_blk_softlimit) :
+		be64_to_cpu(dqp->q_core.d_blk_hardlimit);
 	if (limit && statp->f_blocks > limit) {
 		statp->f_blocks = limit;
 		statp->f_bfree = statp->f_bavail =
-			(statp->f_blocks > be64_to_cpu(dp->d_bcount)) ?
-			 (statp->f_blocks - be64_to_cpu(dp->d_bcount)) : 0;
+			(statp->f_blocks > dqp->q_res_bcount) ?
+			 (statp->f_blocks - dqp->q_res_bcount) : 0;
 	}
 
-	limit = dp->d_ino_softlimit ?
-		be64_to_cpu(dp->d_ino_softlimit) :
-		be64_to_cpu(dp->d_ino_hardlimit);
+	limit = dqp->q_core.d_ino_softlimit ?
+		be64_to_cpu(dqp->q_core.d_ino_softlimit) :
+		be64_to_cpu(dqp->q_core.d_ino_hardlimit);
 	if (limit && statp->f_files > limit) {
 		statp->f_files = limit;
 		statp->f_ffree =
-			(statp->f_files > be64_to_cpu(dp->d_icount)) ?
-			 (statp->f_ffree - be64_to_cpu(dp->d_icount)) : 0;
+			(statp->f_files > dqp->q_res_icount) ?
+			 (statp->f_ffree - dqp->q_res_icount) : 0;
 	}
 }
 
@@ -82,7 +82,7 @@
 	xfs_dquot_t		*dqp;
 
 	if (!xfs_qm_dqget(mp, NULL, xfs_get_projid(ip), XFS_DQ_PROJ, 0, &dqp)) {
-		xfs_fill_statvfs_from_dquot(statp, &dqp->q_core);
+		xfs_fill_statvfs_from_dquot(statp, dqp);
 		xfs_qm_dqput(dqp);
 	}
 }
@@ -156,21 +156,3 @@
 
 	return 0;
 }
-
-void __init
-xfs_qm_init(void)
-{
-	printk(KERN_INFO "SGI XFS Quota Management subsystem\n");
-	mutex_init(&xfs_Gqm_lock);
-	xfs_qm_init_procfs();
-}
-
-void __exit
-xfs_qm_exit(void)
-{
-	xfs_qm_cleanup_procfs();
-	if (qm_dqzone)
-		kmem_zone_destroy(qm_dqzone);
-	if (qm_dqtrxzone)
-		kmem_zone_destroy(qm_dqtrxzone);
-}
diff --git a/fs/xfs/xfs_qm_stats.c b/fs/xfs/xfs_qm_stats.c
deleted file mode 100644
index 5729ba5..0000000
--- a/fs/xfs/xfs_qm_stats.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2000-2003 Silicon Graphics, 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.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT 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 the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#include "xfs.h"
-#include "xfs_fs.h"
-#include "xfs_bit.h"
-#include "xfs_log.h"
-#include "xfs_inum.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_ag.h"
-#include "xfs_alloc.h"
-#include "xfs_quota.h"
-#include "xfs_mount.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_inode.h"
-#include "xfs_itable.h"
-#include "xfs_bmap.h"
-#include "xfs_rtalloc.h"
-#include "xfs_error.h"
-#include "xfs_attr.h"
-#include "xfs_buf_item.h"
-#include "xfs_qm.h"
-
-struct xqmstats xqmstats;
-
-static int xqm_proc_show(struct seq_file *m, void *v)
-{
-	/* maximum; incore; ratio free to inuse; freelist */
-	seq_printf(m, "%d\t%d\t%d\t%u\n",
-			0,
-			xfs_Gqm? atomic_read(&xfs_Gqm->qm_totaldquots) : 0,
-			0,
-			xfs_Gqm? xfs_Gqm->qm_dqfrlist_cnt : 0);
-	return 0;
-}
-
-static int xqm_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, xqm_proc_show, NULL);
-}
-
-static const struct file_operations xqm_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= xqm_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int xqmstat_proc_show(struct seq_file *m, void *v)
-{
-	/* quota performance statistics */
-	seq_printf(m, "qm %u %u %u %u %u %u %u %u\n",
-			xqmstats.xs_qm_dqreclaims,
-			xqmstats.xs_qm_dqreclaim_misses,
-			xqmstats.xs_qm_dquot_dups,
-			xqmstats.xs_qm_dqcachemisses,
-			xqmstats.xs_qm_dqcachehits,
-			xqmstats.xs_qm_dqwants,
-			xqmstats.xs_qm_dqshake_reclaims,
-			xqmstats.xs_qm_dqinact_reclaims);
-	return 0;
-}
-
-static int xqmstat_proc_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, xqmstat_proc_show, NULL);
-}
-
-static const struct file_operations xqmstat_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= xqmstat_proc_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-void
-xfs_qm_init_procfs(void)
-{
-	proc_create("fs/xfs/xqmstat", 0, NULL, &xqmstat_proc_fops);
-	proc_create("fs/xfs/xqm", 0, NULL, &xqm_proc_fops);
-}
-
-void
-xfs_qm_cleanup_procfs(void)
-{
-	remove_proc_entry("fs/xfs/xqm", NULL);
-	remove_proc_entry("fs/xfs/xqmstat", NULL);
-}
diff --git a/fs/xfs/xfs_qm_stats.h b/fs/xfs/xfs_qm_stats.h
deleted file mode 100644
index 5b964fc..0000000
--- a/fs/xfs/xfs_qm_stats.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2002 Silicon Graphics, 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.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT 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 the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#ifndef __XFS_QM_STATS_H__
-#define __XFS_QM_STATS_H__
-
-#if defined(CONFIG_PROC_FS) && !defined(XFS_STATS_OFF)
-
-/*
- * XQM global statistics
- */
-struct xqmstats {
-	__uint32_t		xs_qm_dqreclaims;
-	__uint32_t		xs_qm_dqreclaim_misses;
-	__uint32_t		xs_qm_dquot_dups;
-	__uint32_t		xs_qm_dqcachemisses;
-	__uint32_t		xs_qm_dqcachehits;
-	__uint32_t		xs_qm_dqwants;
-	__uint32_t		xs_qm_dqshake_reclaims;
-	__uint32_t		xs_qm_dqinact_reclaims;
-};
-
-extern struct xqmstats xqmstats;
-
-# define XQM_STATS_INC(count)	( (count)++ )
-
-extern void xfs_qm_init_procfs(void);
-extern void xfs_qm_cleanup_procfs(void);
-
-#else
-
-# define XQM_STATS_INC(count)	do { } while (0)
-
-static inline void xfs_qm_init_procfs(void) { };
-static inline void xfs_qm_cleanup_procfs(void) { };
-
-#endif
-
-#endif	/* __XFS_QM_STATS_H__ */
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 711a86e..c4f396e 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -47,9 +47,6 @@
 					uint);
 STATIC uint	xfs_qm_export_flags(uint);
 STATIC uint	xfs_qm_export_qtype_flags(uint);
-STATIC void	xfs_qm_export_dquot(xfs_mount_t *, xfs_disk_dquot_t *,
-					fs_disk_quota_t *);
-
 
 /*
  * Turn off quota accounting and/or enforcement for all udquots and/or
@@ -69,7 +66,6 @@
 	int			error;
 	uint			inactivate_flags;
 	xfs_qoff_logitem_t	*qoffstart;
-	int			nculprits;
 
 	/*
 	 * No file system can have quotas enabled on disk but not in core.
@@ -175,18 +171,13 @@
 	 * This isn't protected by a particular lock directly, because we
 	 * don't want to take a mrlock every time we depend on quotas being on.
 	 */
-	mp->m_qflags &= ~(flags);
+	mp->m_qflags &= ~flags;
 
 	/*
 	 * Go through all the dquots of this file system and purge them,
-	 * according to what was turned off. We may not be able to get rid
-	 * of all dquots, because dquots can have temporary references that
-	 * are not attached to inodes. eg. xfs_setattr, xfs_create.
-	 * So, if we couldn't purge all the dquots from the filesystem,
-	 * we can't get rid of the incore data structures.
+	 * according to what was turned off.
 	 */
-	while ((nculprits = xfs_qm_dqpurge_all(mp, dqtype)))
-		delay(10 * nculprits);
+	xfs_qm_dqpurge_all(mp, dqtype);
 
 	/*
 	 * Transactions that had started before ACTIVE state bit was cleared
@@ -635,42 +626,6 @@
 	return error;
 }
 
-int
-xfs_qm_scall_getquota(
-	xfs_mount_t	*mp,
-	xfs_dqid_t	id,
-	uint		type,
-	fs_disk_quota_t *out)
-{
-	xfs_dquot_t	*dqp;
-	int		error;
-
-	/*
-	 * Try to get the dquot. We don't want it allocated on disk, so
-	 * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't
-	 * exist, we'll get ENOENT back.
-	 */
-	if ((error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp))) {
-		return (error);
-	}
-
-	/*
-	 * If everything's NULL, this dquot doesn't quite exist as far as
-	 * our utility programs are concerned.
-	 */
-	if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
-		xfs_qm_dqput(dqp);
-		return XFS_ERROR(ENOENT);
-	}
-	/*
-	 * Convert the disk dquot to the exportable format
-	 */
-	xfs_qm_export_dquot(mp, &dqp->q_core, out);
-	xfs_qm_dqput(dqp);
-	return (error ? XFS_ERROR(EFAULT) : 0);
-}
-
-
 STATIC int
 xfs_qm_log_quotaoff_end(
 	xfs_mount_t		*mp,
@@ -759,50 +714,66 @@
 }
 
 
-/*
- * Translate an internal style on-disk-dquot to the exportable format.
- * The main differences are that the counters/limits are all in Basic
- * Blocks (BBs) instead of the internal FSBs, and all on-disk data has
- * to be converted to the native endianness.
- */
-STATIC void
-xfs_qm_export_dquot(
-	xfs_mount_t		*mp,
-	xfs_disk_dquot_t	*src,
+int
+xfs_qm_scall_getquota(
+	struct xfs_mount	*mp,
+	xfs_dqid_t		id,
+	uint			type,
 	struct fs_disk_quota	*dst)
 {
+	struct xfs_dquot	*dqp;
+	int			error;
+
+	/*
+	 * Try to get the dquot. We don't want it allocated on disk, so
+	 * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't
+	 * exist, we'll get ENOENT back.
+	 */
+	error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp);
+	if (error)
+		return error;
+
+	/*
+	 * If everything's NULL, this dquot doesn't quite exist as far as
+	 * our utility programs are concerned.
+	 */
+	if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
+		error = XFS_ERROR(ENOENT);
+		goto out_put;
+	}
+
 	memset(dst, 0, sizeof(*dst));
-	dst->d_version = FS_DQUOT_VERSION;  /* different from src->d_version */
-	dst->d_flags = xfs_qm_export_qtype_flags(src->d_flags);
-	dst->d_id = be32_to_cpu(src->d_id);
+	dst->d_version = FS_DQUOT_VERSION;
+	dst->d_flags = xfs_qm_export_qtype_flags(dqp->q_core.d_flags);
+	dst->d_id = be32_to_cpu(dqp->q_core.d_id);
 	dst->d_blk_hardlimit =
-		XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_blk_hardlimit));
+		XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_blk_hardlimit));
 	dst->d_blk_softlimit =
-		XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_blk_softlimit));
-	dst->d_ino_hardlimit = be64_to_cpu(src->d_ino_hardlimit);
-	dst->d_ino_softlimit = be64_to_cpu(src->d_ino_softlimit);
-	dst->d_bcount = XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_bcount));
-	dst->d_icount = be64_to_cpu(src->d_icount);
-	dst->d_btimer = be32_to_cpu(src->d_btimer);
-	dst->d_itimer = be32_to_cpu(src->d_itimer);
-	dst->d_iwarns = be16_to_cpu(src->d_iwarns);
-	dst->d_bwarns = be16_to_cpu(src->d_bwarns);
+		XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_blk_softlimit));
+	dst->d_ino_hardlimit = be64_to_cpu(dqp->q_core.d_ino_hardlimit);
+	dst->d_ino_softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit);
+	dst->d_bcount = XFS_FSB_TO_BB(mp, dqp->q_res_bcount);
+	dst->d_icount = dqp->q_res_icount;
+	dst->d_btimer = be32_to_cpu(dqp->q_core.d_btimer);
+	dst->d_itimer = be32_to_cpu(dqp->q_core.d_itimer);
+	dst->d_iwarns = be16_to_cpu(dqp->q_core.d_iwarns);
+	dst->d_bwarns = be16_to_cpu(dqp->q_core.d_bwarns);
 	dst->d_rtb_hardlimit =
-		XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_rtb_hardlimit));
+		XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_rtb_hardlimit));
 	dst->d_rtb_softlimit =
-		XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_rtb_softlimit));
-	dst->d_rtbcount = XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_rtbcount));
-	dst->d_rtbtimer = be32_to_cpu(src->d_rtbtimer);
-	dst->d_rtbwarns = be16_to_cpu(src->d_rtbwarns);
+		XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_rtb_softlimit));
+	dst->d_rtbcount = XFS_FSB_TO_BB(mp, dqp->q_res_rtbcount);
+	dst->d_rtbtimer = be32_to_cpu(dqp->q_core.d_rtbtimer);
+	dst->d_rtbwarns = be16_to_cpu(dqp->q_core.d_rtbwarns);
 
 	/*
 	 * Internally, we don't reset all the timers when quota enforcement
 	 * gets turned off. No need to confuse the user level code,
 	 * so return zeroes in that case.
 	 */
-	if ((!XFS_IS_UQUOTA_ENFORCED(mp) && src->d_flags == XFS_DQ_USER) ||
+	if ((!XFS_IS_UQUOTA_ENFORCED(mp) && dqp->q_core.d_flags == XFS_DQ_USER) ||
 	    (!XFS_IS_OQUOTA_ENFORCED(mp) &&
-			(src->d_flags & (XFS_DQ_PROJ | XFS_DQ_GROUP)))) {
+			(dqp->q_core.d_flags & (XFS_DQ_PROJ | XFS_DQ_GROUP)))) {
 		dst->d_btimer = 0;
 		dst->d_itimer = 0;
 		dst->d_rtbtimer = 0;
@@ -823,6 +794,9 @@
 		}
 	}
 #endif
+out_put:
+	xfs_qm_dqput(dqp);
+	return error;
 }
 
 STATIC uint
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
index 8a0807e..b50ec5b 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -174,6 +174,8 @@
 #define XFS_UQUOTA_ACTIVE	0x0100  /* uquotas are being turned off */
 #define XFS_PQUOTA_ACTIVE	0x0200  /* pquotas are being turned off */
 #define XFS_GQUOTA_ACTIVE	0x0400  /* gquotas are being turned off */
+#define XFS_ALL_QUOTA_ACTIVE	\
+	(XFS_UQUOTA_ACTIVE | XFS_PQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE)
 
 /*
  * Checking XFS_IS_*QUOTA_ON() while holding any inode lock guarantees
diff --git a/fs/xfs/xfs_quota_priv.h b/fs/xfs/xfs_quota_priv.h
index 94a3d92..6d86219 100644
--- a/fs/xfs/xfs_quota_priv.h
+++ b/fs/xfs/xfs_quota_priv.h
@@ -24,17 +24,6 @@
  */
 #define XFS_DQITER_MAP_SIZE	10
 
-/*
- * Hash into a bucket in the dquot hash table, based on <mp, id>.
- */
-#define XFS_DQ_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \
-				 (__psunsigned_t)(id)) & \
-				(xfs_Gqm->qm_dqhashmask - 1))
-#define XFS_DQ_HASH(mp, id, type)   (type == XFS_DQ_USER ? \
-				     (xfs_Gqm->qm_usr_dqhtable + \
-				      XFS_DQ_HASHVAL(mp, id)) : \
-				     (xfs_Gqm->qm_grp_dqhtable + \
-				      XFS_DQ_HASHVAL(mp, id)))
 #define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \
 	!dqp->q_core.d_blk_hardlimit && \
 	!dqp->q_core.d_blk_softlimit && \
diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c
index 866de27..e44ef7e 100644
--- a/fs/xfs/xfs_rename.c
+++ b/fs/xfs/xfs_rename.c
@@ -118,17 +118,6 @@
 	new_parent = (src_dp != target_dp);
 	src_is_directory = S_ISDIR(src_ip->i_d.di_mode);
 
-	if (src_is_directory) {
-		/*
-		 * Check for link count overflow on target_dp
-		 */
-		if (target_ip == NULL && new_parent &&
-		    target_dp->i_d.di_nlink >= XFS_MAXLINK) {
-			error = XFS_ERROR(EMLINK);
-			goto std_return;
-		}
-	}
-
 	xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip,
 				inodes, &num_inodes);
 
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index 87323f1..ca4f315 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -183,6 +183,7 @@
 		oblocks = map.br_startoff + map.br_blockcount;
 	}
 	return 0;
+
 error:
 	return error;
 }
@@ -2139,11 +2140,9 @@
 	xfs_buf_t	*sumbp;		/* summary file block buffer */
 
 	mp = tp->t_mountp;
-	/*
-	 * Synchronize by locking the bitmap inode.
-	 */
-	xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
-	xfs_trans_ijoin(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
+
+	ASSERT(mp->m_rbmip->i_itemp != NULL);
+	ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
 
 #if defined(__KERNEL__) && defined(DEBUG)
 	/*
diff --git a/fs/xfs/xfs_sb.h b/fs/xfs/xfs_sb.h
index cb6ae71..f429d9d 100644
--- a/fs/xfs/xfs_sb.h
+++ b/fs/xfs/xfs_sb.h
@@ -529,7 +529,6 @@
 #define	XFS_BB_TO_FSB(mp,bb)	\
 	(((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log)
 #define	XFS_BB_TO_FSBT(mp,bb)	((bb) >> (mp)->m_blkbb_log)
-#define	XFS_BB_FSB_OFFSET(mp,bb) ((bb) & ((mp)->m_bsize - 1))
 
 /*
  * File system block to byte conversions.
diff --git a/fs/xfs/xfs_stats.c b/fs/xfs/xfs_stats.c
index 76fdc58..ce372b7 100644
--- a/fs/xfs/xfs_stats.c
+++ b/fs/xfs/xfs_stats.c
@@ -20,9 +20,18 @@
 
 DEFINE_PER_CPU(struct xfsstats, xfsstats);
 
+static int counter_val(int idx)
+{
+	int val = 0, cpu;
+
+	for_each_possible_cpu(cpu)
+		val += *(((__u32 *)&per_cpu(xfsstats, cpu) + idx));
+	return val;
+}
+
 static int xfs_stat_proc_show(struct seq_file *m, void *v)
 {
-	int		c, i, j, val;
+	int		i, j;
 	__uint64_t	xs_xstrat_bytes = 0;
 	__uint64_t	xs_write_bytes = 0;
 	__uint64_t	xs_read_bytes = 0;
@@ -50,20 +59,16 @@
 		{ "abtc2",		XFSSTAT_END_ABTC_V2		},
 		{ "bmbt2",		XFSSTAT_END_BMBT_V2		},
 		{ "ibt2",		XFSSTAT_END_IBT_V2		},
+		/* we print both series of quota information together */
+		{ "qm",			XFSSTAT_END_QM			},
 	};
 
 	/* Loop over all stats groups */
-	for (i=j = 0; i < ARRAY_SIZE(xstats); i++) {
+	for (i = j = 0; i < ARRAY_SIZE(xstats); i++) {
 		seq_printf(m, "%s", xstats[i].desc);
 		/* inner loop does each group */
-		while (j < xstats[i].endpoint) {
-			val = 0;
-			/* sum over all cpus */
-			for_each_possible_cpu(c)
-				val += *(((__u32*)&per_cpu(xfsstats, c) + j));
-			seq_printf(m, " %u", val);
-			j++;
-		}
+		for (; j < xstats[i].endpoint; j++)
+			seq_printf(m, " %u", counter_val(j));
 		seq_putc(m, '\n');
 	}
 	/* extra precision counters */
@@ -97,6 +102,58 @@
 	.release	= single_release,
 };
 
+/* legacy quota interfaces */
+#ifdef CONFIG_XFS_QUOTA
+static int xqm_proc_show(struct seq_file *m, void *v)
+{
+	/* maximum; incore; ratio free to inuse; freelist */
+	seq_printf(m, "%d\t%d\t%d\t%u\n",
+			0,
+			counter_val(XFSSTAT_END_XQMSTAT),
+			0,
+			counter_val(XFSSTAT_END_XQMSTAT + 1));
+	return 0;
+}
+
+static int xqm_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, xqm_proc_show, NULL);
+}
+
+static const struct file_operations xqm_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= xqm_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+/* legacy quota stats interface no 2 */
+static int xqmstat_proc_show(struct seq_file *m, void *v)
+{
+	int j;
+
+	seq_printf(m, "qm");
+	for (j = XFSSTAT_END_IBT_V2; j < XFSSTAT_END_XQMSTAT; j++)
+		seq_printf(m, " %u", counter_val(j));
+	seq_putc(m, '\n');
+	return 0;
+}
+
+static int xqmstat_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, xqmstat_proc_show, NULL);
+}
+
+static const struct file_operations xqmstat_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= xqmstat_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+#endif /* CONFIG_XFS_QUOTA */
+
 int
 xfs_init_procfs(void)
 {
@@ -105,10 +162,24 @@
 
 	if (!proc_create("fs/xfs/stat", 0, NULL,
 			 &xfs_stat_proc_fops))
-		goto out_remove_entry;
+		goto out_remove_xfs_dir;
+#ifdef CONFIG_XFS_QUOTA
+	if (!proc_create("fs/xfs/xqmstat", 0, NULL,
+			 &xqmstat_proc_fops))
+		goto out_remove_stat_file;
+	if (!proc_create("fs/xfs/xqm", 0, NULL,
+			 &xqm_proc_fops))
+		goto out_remove_xqmstat_file;
+#endif
 	return 0;
 
- out_remove_entry:
+#ifdef CONFIG_XFS_QUOTA
+ out_remove_xqmstat_file:
+	remove_proc_entry("fs/xfs/xqmstat", NULL);
+ out_remove_stat_file:
+	remove_proc_entry("fs/xfs/stat", NULL);
+#endif
+ out_remove_xfs_dir:
 	remove_proc_entry("fs/xfs", NULL);
  out:
 	return -ENOMEM;
@@ -117,6 +188,10 @@
 void
 xfs_cleanup_procfs(void)
 {
+#ifdef CONFIG_XFS_QUOTA
+	remove_proc_entry("fs/xfs/xqm", NULL);
+	remove_proc_entry("fs/xfs/xqmstat", NULL);
+#endif
 	remove_proc_entry("fs/xfs/stat", NULL);
 	remove_proc_entry("fs/xfs", NULL);
 }
diff --git a/fs/xfs/xfs_stats.h b/fs/xfs/xfs_stats.h
index 736854b..c03ad38 100644
--- a/fs/xfs/xfs_stats.h
+++ b/fs/xfs/xfs_stats.h
@@ -183,6 +183,16 @@
 	__uint32_t		xs_ibt_2_alloc;
 	__uint32_t		xs_ibt_2_free;
 	__uint32_t		xs_ibt_2_moves;
+#define XFSSTAT_END_XQMSTAT		(XFSSTAT_END_IBT_V2+6)
+	__uint32_t		xs_qm_dqreclaims;
+	__uint32_t		xs_qm_dqreclaim_misses;
+	__uint32_t		xs_qm_dquot_dups;
+	__uint32_t		xs_qm_dqcachemisses;
+	__uint32_t		xs_qm_dqcachehits;
+	__uint32_t		xs_qm_dqwants;
+#define XFSSTAT_END_QM			(XFSSTAT_END_XQMSTAT+2)
+	__uint32_t		xs_qm_dquot;
+	__uint32_t		xs_qm_dquot_unused;
 /* Extra precision counters */
 	__uint64_t		xs_xstrat_bytes;
 	__uint64_t		xs_write_bytes;
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index ee5b695..dab9a5f 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -324,10 +324,9 @@
 		} else if (!strcmp(this_char, MNTOPT_FILESTREAM)) {
 			mp->m_flags |= XFS_MOUNT_FILESTREAMS;
 		} else if (!strcmp(this_char, MNTOPT_NOQUOTA)) {
-			mp->m_qflags &= ~(XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE |
-					  XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE |
-					  XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE |
-					  XFS_UQUOTA_ENFD | XFS_OQUOTA_ENFD);
+			mp->m_qflags &= ~XFS_ALL_QUOTA_ACCT;
+			mp->m_qflags &= ~XFS_ALL_QUOTA_ENFD;
+			mp->m_qflags &= ~XFS_ALL_QUOTA_ACTIVE;
 		} else if (!strcmp(this_char, MNTOPT_QUOTA) ||
 			   !strcmp(this_char, MNTOPT_UQUOTA) ||
 			   !strcmp(this_char, MNTOPT_USRQUOTA)) {
@@ -760,6 +759,36 @@
 	return 0;
 }
 
+STATIC int
+xfs_init_mount_workqueues(
+	struct xfs_mount	*mp)
+{
+	mp->m_data_workqueue = alloc_workqueue("xfs-data/%s",
+			WQ_MEM_RECLAIM, 0, mp->m_fsname);
+	if (!mp->m_data_workqueue)
+		goto out;
+
+	mp->m_unwritten_workqueue = alloc_workqueue("xfs-conv/%s",
+			WQ_MEM_RECLAIM, 0, mp->m_fsname);
+	if (!mp->m_unwritten_workqueue)
+		goto out_destroy_data_iodone_queue;
+
+	return 0;
+
+out_destroy_data_iodone_queue:
+	destroy_workqueue(mp->m_data_workqueue);
+out:
+	return -ENOMEM;
+}
+
+STATIC void
+xfs_destroy_mount_workqueues(
+	struct xfs_mount	*mp)
+{
+	destroy_workqueue(mp->m_data_workqueue);
+	destroy_workqueue(mp->m_unwritten_workqueue);
+}
+
 /* Catch misguided souls that try to use this interface on XFS */
 STATIC struct inode *
 xfs_fs_alloc_inode(
@@ -834,91 +863,58 @@
 }
 
 /*
- * Dirty the XFS inode when mark_inode_dirty_sync() is called so that
- * we catch unlogged VFS level updates to the inode.
+ * This is called by the VFS when dirtying inode metadata.  This can happen
+ * for a few reasons, but we only care about timestamp updates, given that
+ * we handled the rest ourselves.  In theory no other calls should happen,
+ * but for example generic_write_end() keeps dirtying the inode after
+ * updating i_size.  Thus we check that the flags are exactly I_DIRTY_SYNC,
+ * and skip this call otherwise.
  *
- * We need the barrier() to maintain correct ordering between unlogged
- * updates and the transaction commit code that clears the i_update_core
- * field. This requires all updates to be completed before marking the
- * inode dirty.
+ * We'll hopefull get a different method just for updating timestamps soon,
+ * at which point this hack can go away, and maybe we'll also get real
+ * error handling here.
  */
 STATIC void
 xfs_fs_dirty_inode(
-	struct inode	*inode,
-	int		flags)
-{
-	barrier();
-	XFS_I(inode)->i_update_core = 1;
-}
-
-STATIC int
-xfs_fs_write_inode(
 	struct inode		*inode,
-	struct writeback_control *wbc)
+	int			flags)
 {
 	struct xfs_inode	*ip = XFS_I(inode);
 	struct xfs_mount	*mp = ip->i_mount;
-	int			error = EAGAIN;
+	struct xfs_trans	*tp;
+	int			error;
 
-	trace_xfs_write_inode(ip);
+	if (flags != I_DIRTY_SYNC)
+		return;
 
-	if (XFS_FORCED_SHUTDOWN(mp))
-		return -XFS_ERROR(EIO);
+	trace_xfs_dirty_inode(ip);
 
-	if (wbc->sync_mode == WB_SYNC_ALL || wbc->for_kupdate) {
-		/*
-		 * Make sure the inode has made it it into the log.  Instead
-		 * of forcing it all the way to stable storage using a
-		 * synchronous transaction we let the log force inside the
-		 * ->sync_fs call do that for thus, which reduces the number
-		 * of synchronous log forces dramatically.
-		 */
-		error = xfs_log_dirty_inode(ip, NULL, 0);
-		if (error)
-			goto out;
-		return 0;
-	} else {
-		if (!ip->i_update_core)
-			return 0;
-
-		/*
-		 * We make this non-blocking if the inode is contended, return
-		 * EAGAIN to indicate to the caller that they did not succeed.
-		 * This prevents the flush path from blocking on inodes inside
-		 * another operation right now, they get caught later by
-		 * xfs_sync.
-		 */
-		if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED))
-			goto out;
-
-		if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip))
-			goto out_unlock;
-
-		/*
-		 * Now we have the flush lock and the inode is not pinned, we
-		 * can check if the inode is really clean as we know that
-		 * there are no pending transaction completions, it is not
-		 * waiting on the delayed write queue and there is no IO in
-		 * progress.
-		 */
-		if (xfs_inode_clean(ip)) {
-			xfs_ifunlock(ip);
-			error = 0;
-			goto out_unlock;
-		}
-		error = xfs_iflush(ip, SYNC_TRYLOCK);
+	tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
+	error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
+	if (error) {
+		xfs_trans_cancel(tp, 0);
+		goto trouble;
 	}
-
- out_unlock:
-	xfs_iunlock(ip, XFS_ILOCK_SHARED);
- out:
+	xfs_ilock(ip, XFS_ILOCK_EXCL);
 	/*
-	 * if we failed to write out the inode then mark
-	 * it dirty again so we'll try again later.
+	 * Grab all the latest timestamps from the Linux inode.
 	 */
+	ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec;
+	ip->i_d.di_atime.t_nsec = (__int32_t)inode->i_atime.tv_nsec;
+	ip->i_d.di_ctime.t_sec = (__int32_t)inode->i_ctime.tv_sec;
+	ip->i_d.di_ctime.t_nsec = (__int32_t)inode->i_ctime.tv_nsec;
+	ip->i_d.di_mtime.t_sec = (__int32_t)inode->i_mtime.tv_sec;
+	ip->i_d.di_mtime.t_nsec = (__int32_t)inode->i_mtime.tv_nsec;
+
+	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+	xfs_trans_log_inode(tp, ip, XFS_ILOG_TIMESTAMP);
+	error = xfs_trans_commit(tp, 0);
 	if (error)
-		xfs_mark_inode_dirty_sync(ip);
-	return -error;
+		goto trouble;
+	return;
+
+trouble:
+	xfs_warn(mp, "failed to update timestamps for inode 0x%llx", ip->i_ino);
 }
 
 STATIC void
@@ -954,6 +950,22 @@
 	xfs_inactive(ip);
 }
 
+/*
+ * We do an unlocked check for XFS_IDONTCACHE here because we are already
+ * serialised against cache hits here via the inode->i_lock and igrab() in
+ * xfs_iget_cache_hit(). Hence a lookup that might clear this flag will not be
+ * racing with us, and it avoids needing to grab a spinlock here for every inode
+ * we drop the final reference on.
+ */
+STATIC int
+xfs_fs_drop_inode(
+	struct inode		*inode)
+{
+	struct xfs_inode	*ip = XFS_I(inode);
+
+	return generic_drop_inode(inode) || (ip->i_flags & XFS_IDONTCACHE);
+}
+
 STATIC void
 xfs_free_fsname(
 	struct xfs_mount	*mp)
@@ -983,6 +995,7 @@
 	xfs_unmountfs(mp);
 	xfs_freesb(mp);
 	xfs_icsb_destroy_counters(mp);
+	xfs_destroy_mount_workqueues(mp);
 	xfs_close_devices(mp);
 	xfs_free_fsname(mp);
 	kfree(mp);
@@ -1309,10 +1322,14 @@
 	if (error)
 		goto out_free_fsname;
 
-	error = xfs_icsb_init_counters(mp);
+	error = xfs_init_mount_workqueues(mp);
 	if (error)
 		goto out_close_devices;
 
+	error = xfs_icsb_init_counters(mp);
+	if (error)
+		goto out_destroy_workqueues;
+
 	error = xfs_readsb(mp, flags);
 	if (error)
 		goto out_destroy_counters;
@@ -1341,6 +1358,7 @@
 	sb->s_blocksize = mp->m_sb.sb_blocksize;
 	sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1;
 	sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits);
+	sb->s_max_links = XFS_MAXLINK;
 	sb->s_time_gran = 1;
 	set_posix_acl_flag(sb);
 
@@ -1361,10 +1379,10 @@
 		error = EINVAL;
 		goto out_syncd_stop;
 	}
-	sb->s_root = d_alloc_root(root);
+	sb->s_root = d_make_root(root);
 	if (!sb->s_root) {
 		error = ENOMEM;
-		goto out_iput;
+		goto out_syncd_stop;
 	}
 
 	return 0;
@@ -1375,6 +1393,8 @@
 	xfs_freesb(mp);
  out_destroy_counters:
 	xfs_icsb_destroy_counters(mp);
+out_destroy_workqueues:
+	xfs_destroy_mount_workqueues(mp);
  out_close_devices:
 	xfs_close_devices(mp);
  out_free_fsname:
@@ -1383,8 +1403,6 @@
  out:
 	return -error;
 
- out_iput:
-	iput(root);
  out_syncd_stop:
 	xfs_syncd_stop(mp);
  out_unmount:
@@ -1430,8 +1448,8 @@
 	.alloc_inode		= xfs_fs_alloc_inode,
 	.destroy_inode		= xfs_fs_destroy_inode,
 	.dirty_inode		= xfs_fs_dirty_inode,
-	.write_inode		= xfs_fs_write_inode,
 	.evict_inode		= xfs_fs_evict_inode,
+	.drop_inode		= xfs_fs_drop_inode,
 	.put_super		= xfs_fs_put_super,
 	.sync_fs		= xfs_fs_sync_fs,
 	.freeze_fs		= xfs_fs_freeze,
@@ -1605,12 +1623,28 @@
 	xfs_syncd_wq = alloc_workqueue("xfssyncd", WQ_NON_REENTRANT, 0);
 	if (!xfs_syncd_wq)
 		return -ENOMEM;
+
+	/*
+	 * The allocation workqueue can be used in memory reclaim situations
+	 * (writepage path), and parallelism is only limited by the number of
+	 * AGs in all the filesystems mounted. Hence use the default large
+	 * max_active value for this workqueue.
+	 */
+	xfs_alloc_wq = alloc_workqueue("xfsalloc", WQ_MEM_RECLAIM, 0);
+	if (!xfs_alloc_wq)
+		goto out_destroy_syncd;
+
 	return 0;
+
+out_destroy_syncd:
+	destroy_workqueue(xfs_syncd_wq);
+	return -ENOMEM;
 }
 
 STATIC void
 xfs_destroy_workqueues(void)
 {
+	destroy_workqueue(xfs_alloc_wq);
 	destroy_workqueue(xfs_syncd_wq);
 }
 
@@ -1652,13 +1686,17 @@
 	if (error)
 		goto out_cleanup_procfs;
 
-	vfs_initquota();
+	error = xfs_qm_init();
+	if (error)
+		goto out_sysctl_unregister;
 
 	error = register_filesystem(&xfs_fs_type);
 	if (error)
-		goto out_sysctl_unregister;
+		goto out_qm_exit;
 	return 0;
 
+ out_qm_exit:
+	xfs_qm_exit();
  out_sysctl_unregister:
 	xfs_sysctl_unregister();
  out_cleanup_procfs:
@@ -1680,7 +1718,7 @@
 STATIC void __exit
 exit_xfs_fs(void)
 {
-	vfs_exitquota();
+	xfs_qm_exit();
 	unregister_filesystem(&xfs_fs_type);
 	xfs_sysctl_unregister();
 	xfs_cleanup_procfs();
diff --git a/fs/xfs/xfs_super.h b/fs/xfs/xfs_super.h
index 50a3266..09b0c26 100644
--- a/fs/xfs/xfs_super.h
+++ b/fs/xfs/xfs_super.h
@@ -21,13 +21,11 @@
 #include <linux/exportfs.h>
 
 #ifdef CONFIG_XFS_QUOTA
-extern void xfs_qm_init(void);
+extern int xfs_qm_init(void);
 extern void xfs_qm_exit(void);
-# define vfs_initquota()	xfs_qm_init()
-# define vfs_exitquota()	xfs_qm_exit()
 #else
-# define vfs_initquota()	do { } while (0)
-# define vfs_exitquota()	do { } while (0)
+# define xfs_qm_init()	(0)
+# define xfs_qm_exit()	do { } while (0)
 #endif
 
 #ifdef CONFIG_XFS_POSIX_ACL
diff --git a/fs/xfs/xfs_sync.c b/fs/xfs/xfs_sync.c
index 40b75ee..205ebcb 100644
--- a/fs/xfs/xfs_sync.c
+++ b/fs/xfs/xfs_sync.c
@@ -336,32 +336,6 @@
 	return error;
 }
 
-int
-xfs_log_dirty_inode(
-	struct xfs_inode	*ip,
-	struct xfs_perag	*pag,
-	int			flags)
-{
-	struct xfs_mount	*mp = ip->i_mount;
-	struct xfs_trans	*tp;
-	int			error;
-
-	if (!ip->i_update_core)
-		return 0;
-
-	tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
-	error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
-	if (error) {
-		xfs_trans_cancel(tp, 0);
-		return error;
-	}
-
-	xfs_ilock(ip, XFS_ILOCK_EXCL);
-	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-	return xfs_trans_commit(tp, 0);
-}
-
 /*
  * When remounting a filesystem read-only or freezing the filesystem, we have
  * two phases to execute. This first phase is syncing the data before we
@@ -385,16 +359,6 @@
 {
 	int			error, error2 = 0;
 
-	/*
-	 * Log all pending size and timestamp updates.  The vfs writeback
-	 * code is supposed to do this, but due to its overagressive
-	 * livelock detection it will skip inodes where appending writes
-	 * were written out in the first non-blocking sync phase if their
-	 * completion took long enough that it happened after taking the
-	 * timestamp for the cut-off in the blocking phase.
-	 */
-	xfs_inode_ag_iterator(mp, xfs_log_dirty_inode, 0);
-
 	/* force out the log */
 	xfs_log_force(mp, XFS_LOG_SYNC);
 
@@ -913,17 +877,15 @@
 	 * can reference the inodes in the cache without taking references.
 	 *
 	 * We make that OK here by ensuring that we wait until the inode is
-	 * unlocked after the lookup before we go ahead and free it.  We get
-	 * both the ilock and the iolock because the code may need to drop the
-	 * ilock one but will still hold the iolock.
+	 * unlocked after the lookup before we go ahead and free it.
 	 */
-	xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+	xfs_ilock(ip, XFS_ILOCK_EXCL);
 	xfs_qm_dqdetach(ip);
-	xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
 
 	xfs_inode_free(ip);
-	return error;
 
+	return error;
 }
 
 /*
diff --git a/fs/xfs/xfs_sync.h b/fs/xfs/xfs_sync.h
index fa96547..941202e 100644
--- a/fs/xfs/xfs_sync.h
+++ b/fs/xfs/xfs_sync.h
@@ -34,8 +34,6 @@
 
 void xfs_flush_inodes(struct xfs_inode *ip);
 
-int xfs_log_dirty_inode(struct xfs_inode *ip, struct xfs_perag *pag, int flags);
-
 int xfs_reclaim_inodes(struct xfs_mount *mp, int mode);
 int xfs_reclaim_inodes_count(struct xfs_mount *mp);
 void xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan);
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index bb134a8..06838c4 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -580,7 +580,7 @@
 DEFINE_INODE_EVENT(xfs_dir_fsync);
 DEFINE_INODE_EVENT(xfs_file_fsync);
 DEFINE_INODE_EVENT(xfs_destroy_inode);
-DEFINE_INODE_EVENT(xfs_write_inode);
+DEFINE_INODE_EVENT(xfs_dirty_inode);
 DEFINE_INODE_EVENT(xfs_evict_inode);
 
 DEFINE_INODE_EVENT(xfs_dquot_dqalloc);
@@ -627,16 +627,19 @@
 	TP_STRUCT__entry(
 		__field(dev_t, dev)
 		__field(xfs_ino_t, dp_ino)
+		__field(int, namelen)
 		__dynamic_array(char, name, name->len)
 	),
 	TP_fast_assign(
 		__entry->dev = VFS_I(dp)->i_sb->s_dev;
 		__entry->dp_ino = dp->i_ino;
+		__entry->namelen = name->len;
 		memcpy(__get_str(name), name->name, name->len);
 	),
-	TP_printk("dev %d:%d dp ino 0x%llx name %s",
+	TP_printk("dev %d:%d dp ino 0x%llx name %.*s",
 		  MAJOR(__entry->dev), MINOR(__entry->dev),
 		  __entry->dp_ino,
+		  __entry->namelen,
 		  __get_str(name))
 )
 
@@ -658,6 +661,8 @@
 		__field(dev_t, dev)
 		__field(xfs_ino_t, src_dp_ino)
 		__field(xfs_ino_t, target_dp_ino)
+		__field(int, src_namelen)
+		__field(int, target_namelen)
 		__dynamic_array(char, src_name, src_name->len)
 		__dynamic_array(char, target_name, target_name->len)
 	),
@@ -665,15 +670,20 @@
 		__entry->dev = VFS_I(src_dp)->i_sb->s_dev;
 		__entry->src_dp_ino = src_dp->i_ino;
 		__entry->target_dp_ino = target_dp->i_ino;
+		__entry->src_namelen = src_name->len;
+		__entry->target_namelen = target_name->len;
 		memcpy(__get_str(src_name), src_name->name, src_name->len);
-		memcpy(__get_str(target_name), target_name->name, target_name->len);
+		memcpy(__get_str(target_name), target_name->name,
+			target_name->len);
 	),
 	TP_printk("dev %d:%d src dp ino 0x%llx target dp ino 0x%llx"
-		  " src name %s target name %s",
+		  " src name %.*s target name %.*s",
 		  MAJOR(__entry->dev), MINOR(__entry->dev),
 		  __entry->src_dp_ino,
 		  __entry->target_dp_ino,
+		  __entry->src_namelen,
 		  __get_str(src_name),
+		  __entry->target_namelen,
 		  __get_str(target_name))
 )
 
@@ -741,10 +751,10 @@
 DEFINE_DQUOT_EVENT(xfs_dqtobp_read);
 DEFINE_DQUOT_EVENT(xfs_dqread);
 DEFINE_DQUOT_EVENT(xfs_dqread_fail);
-DEFINE_DQUOT_EVENT(xfs_dqlookup_found);
-DEFINE_DQUOT_EVENT(xfs_dqlookup_done);
 DEFINE_DQUOT_EVENT(xfs_dqget_hit);
 DEFINE_DQUOT_EVENT(xfs_dqget_miss);
+DEFINE_DQUOT_EVENT(xfs_dqget_freeing);
+DEFINE_DQUOT_EVENT(xfs_dqget_dup);
 DEFINE_DQUOT_EVENT(xfs_dqput);
 DEFINE_DQUOT_EVENT(xfs_dqput_wait);
 DEFINE_DQUOT_EVENT(xfs_dqput_free);
@@ -782,12 +792,12 @@
 		__entry->curr_res = tic->t_curr_res;
 		__entry->unit_res = tic->t_unit_res;
 		__entry->flags = tic->t_flags;
-		__entry->reserveq = list_empty(&log->l_reserveq);
-		__entry->writeq = list_empty(&log->l_writeq);
-		xlog_crack_grant_head(&log->l_grant_reserve_head,
+		__entry->reserveq = list_empty(&log->l_reserve_head.waiters);
+		__entry->writeq = list_empty(&log->l_write_head.waiters);
+		xlog_crack_grant_head(&log->l_reserve_head.grant,
 				&__entry->grant_reserve_cycle,
 				&__entry->grant_reserve_bytes);
-		xlog_crack_grant_head(&log->l_grant_write_head,
+		xlog_crack_grant_head(&log->l_write_head.grant,
 				&__entry->grant_write_cycle,
 				&__entry->grant_write_bytes);
 		__entry->curr_cycle = log->l_curr_cycle;
@@ -826,20 +836,14 @@
 	TP_ARGS(log, tic))
 DEFINE_LOGGRANT_EVENT(xfs_log_done_nonperm);
 DEFINE_LOGGRANT_EVENT(xfs_log_done_perm);
-DEFINE_LOGGRANT_EVENT(xfs_log_reserve);
 DEFINE_LOGGRANT_EVENT(xfs_log_umount_write);
-DEFINE_LOGGRANT_EVENT(xfs_log_grant_enter);
-DEFINE_LOGGRANT_EVENT(xfs_log_grant_exit);
-DEFINE_LOGGRANT_EVENT(xfs_log_grant_error);
 DEFINE_LOGGRANT_EVENT(xfs_log_grant_sleep);
 DEFINE_LOGGRANT_EVENT(xfs_log_grant_wake);
 DEFINE_LOGGRANT_EVENT(xfs_log_grant_wake_up);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_write_enter);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_write_exit);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_write_error);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_write_sleep);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_write_wake);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_write_wake_up);
+DEFINE_LOGGRANT_EVENT(xfs_log_reserve);
+DEFINE_LOGGRANT_EVENT(xfs_log_reserve_exit);
+DEFINE_LOGGRANT_EVENT(xfs_log_regrant);
+DEFINE_LOGGRANT_EVENT(xfs_log_regrant_exit);
 DEFINE_LOGGRANT_EVENT(xfs_log_regrant_reserve_enter);
 DEFINE_LOGGRANT_EVENT(xfs_log_regrant_reserve_exit);
 DEFINE_LOGGRANT_EVENT(xfs_log_regrant_reserve_sub);
@@ -1414,7 +1418,7 @@
 DEFINE_ALLOC_EVENT(xfs_alloc_vextent_loopfailed);
 DEFINE_ALLOC_EVENT(xfs_alloc_vextent_allfailed);
 
-DECLARE_EVENT_CLASS(xfs_dir2_class,
+DECLARE_EVENT_CLASS(xfs_da_class,
 	TP_PROTO(struct xfs_da_args *args),
 	TP_ARGS(args),
 	TP_STRUCT__entry(
@@ -1449,7 +1453,7 @@
 )
 
 #define DEFINE_DIR2_EVENT(name) \
-DEFINE_EVENT(xfs_dir2_class, name, \
+DEFINE_EVENT(xfs_da_class, name, \
 	TP_PROTO(struct xfs_da_args *args), \
 	TP_ARGS(args))
 DEFINE_DIR2_EVENT(xfs_dir2_sf_addname);
@@ -1478,6 +1482,64 @@
 DEFINE_DIR2_EVENT(xfs_dir2_node_removename);
 DEFINE_DIR2_EVENT(xfs_dir2_node_to_leaf);
 
+#define DEFINE_ATTR_EVENT(name) \
+DEFINE_EVENT(xfs_da_class, name, \
+	TP_PROTO(struct xfs_da_args *args), \
+	TP_ARGS(args))
+DEFINE_ATTR_EVENT(xfs_attr_sf_add);
+DEFINE_ATTR_EVENT(xfs_attr_sf_addname);
+DEFINE_ATTR_EVENT(xfs_attr_sf_create);
+DEFINE_ATTR_EVENT(xfs_attr_sf_lookup);
+DEFINE_ATTR_EVENT(xfs_attr_sf_remove);
+DEFINE_ATTR_EVENT(xfs_attr_sf_removename);
+DEFINE_ATTR_EVENT(xfs_attr_sf_to_leaf);
+
+DEFINE_ATTR_EVENT(xfs_attr_leaf_add);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_add_old);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_add_new);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_addname);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_create);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_lookup);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_replace);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_removename);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_split);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_split_before);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_split_after);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_clearflag);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_setflag);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_flipflags);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_to_sf);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_to_node);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_rebalance);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_unbalance);
+
+DEFINE_ATTR_EVENT(xfs_attr_node_addname);
+DEFINE_ATTR_EVENT(xfs_attr_node_lookup);
+DEFINE_ATTR_EVENT(xfs_attr_node_replace);
+DEFINE_ATTR_EVENT(xfs_attr_node_removename);
+
+#define DEFINE_DA_EVENT(name) \
+DEFINE_EVENT(xfs_da_class, name, \
+	TP_PROTO(struct xfs_da_args *args), \
+	TP_ARGS(args))
+DEFINE_DA_EVENT(xfs_da_split);
+DEFINE_DA_EVENT(xfs_da_join);
+DEFINE_DA_EVENT(xfs_da_link_before);
+DEFINE_DA_EVENT(xfs_da_link_after);
+DEFINE_DA_EVENT(xfs_da_unlink_back);
+DEFINE_DA_EVENT(xfs_da_unlink_forward);
+DEFINE_DA_EVENT(xfs_da_root_split);
+DEFINE_DA_EVENT(xfs_da_root_join);
+DEFINE_DA_EVENT(xfs_da_node_add);
+DEFINE_DA_EVENT(xfs_da_node_create);
+DEFINE_DA_EVENT(xfs_da_node_split);
+DEFINE_DA_EVENT(xfs_da_node_remove);
+DEFINE_DA_EVENT(xfs_da_node_rebalance);
+DEFINE_DA_EVENT(xfs_da_node_unbalance);
+DEFINE_DA_EVENT(xfs_da_swap_lastblock);
+DEFINE_DA_EVENT(xfs_da_grow_inode);
+DEFINE_DA_EVENT(xfs_da_shrink_inode);
+
 DECLARE_EVENT_CLASS(xfs_dir2_space_class,
 	TP_PROTO(struct xfs_da_args *args, int idx),
 	TP_ARGS(args, idx),
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 7adcdf1..103b00c 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -681,7 +681,6 @@
 	uint		flags,
 	uint		logcount)
 {
-	int		log_flags;
 	int		error = 0;
 	int		rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
 
@@ -707,24 +706,32 @@
 	 * Reserve the log space needed for this transaction.
 	 */
 	if (logspace > 0) {
-		ASSERT((tp->t_log_res == 0) || (tp->t_log_res == logspace));
-		ASSERT((tp->t_log_count == 0) ||
-			(tp->t_log_count == logcount));
+		bool	permanent = false;
+
+		ASSERT(tp->t_log_res == 0 || tp->t_log_res == logspace);
+		ASSERT(tp->t_log_count == 0 || tp->t_log_count == logcount);
+
 		if (flags & XFS_TRANS_PERM_LOG_RES) {
-			log_flags = XFS_LOG_PERM_RESERV;
 			tp->t_flags |= XFS_TRANS_PERM_LOG_RES;
+			permanent = true;
 		} else {
 			ASSERT(tp->t_ticket == NULL);
 			ASSERT(!(tp->t_flags & XFS_TRANS_PERM_LOG_RES));
-			log_flags = 0;
 		}
 
-		error = xfs_log_reserve(tp->t_mountp, logspace, logcount,
-					&tp->t_ticket,
-					XFS_TRANSACTION, log_flags, tp->t_type);
-		if (error) {
-			goto undo_blocks;
+		if (tp->t_ticket != NULL) {
+			ASSERT(flags & XFS_TRANS_PERM_LOG_RES);
+			error = xfs_log_regrant(tp->t_mountp, tp->t_ticket);
+		} else {
+			error = xfs_log_reserve(tp->t_mountp, logspace,
+						logcount, &tp->t_ticket,
+						XFS_TRANSACTION, permanent,
+						tp->t_type);
 		}
+
+		if (error)
+			goto undo_blocks;
+
 		tp->t_log_res = logspace;
 		tp->t_log_count = logcount;
 	}
@@ -752,6 +759,8 @@
 	 */
 undo_log:
 	if (logspace > 0) {
+		int		log_flags;
+
 		if (flags & XFS_TRANS_PERM_LOG_RES) {
 			log_flags = XFS_LOG_REL_PERM_RESERV;
 		} else {
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index ed9252b..1dead07 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -611,50 +611,6 @@
 }
 
 /*
- * This is to be called when an item is unlocked that may have
- * been in the AIL.  It will wake up the first member of the AIL
- * wait list if this item's unlocking might allow it to progress.
- * If the item is in the AIL, then we need to get the AIL lock
- * while doing our checking so we don't race with someone going
- * to sleep waiting for this event in xfs_trans_push_ail().
- */
-void
-xfs_trans_unlocked_item(
-	struct xfs_ail	*ailp,
-	xfs_log_item_t	*lip)
-{
-	xfs_log_item_t	*min_lip;
-
-	/*
-	 * If we're forcibly shutting down, we may have
-	 * unlocked log items arbitrarily. The last thing
-	 * we want to do is to move the tail of the log
-	 * over some potentially valid data.
-	 */
-	if (!(lip->li_flags & XFS_LI_IN_AIL) ||
-	    XFS_FORCED_SHUTDOWN(ailp->xa_mount)) {
-		return;
-	}
-
-	/*
-	 * This is the one case where we can call into xfs_ail_min()
-	 * without holding the AIL lock because we only care about the
-	 * case where we are at the tail of the AIL.  If the object isn't
-	 * at the tail, it doesn't matter what result we get back.  This
-	 * is slightly racy because since we were just unlocked, we could
-	 * go to sleep between the call to xfs_ail_min and the call to
-	 * xfs_log_move_tail, have someone else lock us, commit to us disk,
-	 * move us out of the tail of the AIL, and then we wake up.  However,
-	 * the call to xfs_log_move_tail() doesn't do anything if there's
-	 * not enough free space to wake people up so we're safe calling it.
-	 */
-	min_lip = xfs_ail_min(ailp);
-
-	if (min_lip == lip)
-		xfs_log_move_tail(ailp->xa_mount, 1);
-}	/* xfs_trans_unlocked_item */
-
-/*
  * xfs_trans_ail_update - bulk AIL insertion operation.
  *
  * @xfs_trans_ail_update takes an array of log items that all need to be
@@ -685,7 +641,6 @@
 	xfs_lsn_t		lsn) __releases(ailp->xa_lock)
 {
 	xfs_log_item_t		*mlip;
-	xfs_lsn_t		tail_lsn;
 	int			mlip_changed = 0;
 	int			i;
 	LIST_HEAD(tmp);
@@ -712,22 +667,12 @@
 
 	if (!list_empty(&tmp))
 		xfs_ail_splice(ailp, cur, &tmp, lsn);
-
-	if (!mlip_changed) {
-		spin_unlock(&ailp->xa_lock);
-		return;
-	}
-
-	/*
-	 * It is not safe to access mlip after the AIL lock is dropped, so we
-	 * must get a copy of li_lsn before we do so.  This is especially
-	 * important on 32-bit platforms where accessing and updating 64-bit
-	 * values like li_lsn is not atomic.
-	 */
-	mlip = xfs_ail_min(ailp);
-	tail_lsn = mlip->li_lsn;
 	spin_unlock(&ailp->xa_lock);
-	xfs_log_move_tail(ailp->xa_mount, tail_lsn);
+
+	if (mlip_changed && !XFS_FORCED_SHUTDOWN(ailp->xa_mount)) {
+		xlog_assign_tail_lsn(ailp->xa_mount);
+		xfs_log_space_wake(ailp->xa_mount);
+	}
 }
 
 /*
@@ -758,7 +703,6 @@
 	int			nr_items) __releases(ailp->xa_lock)
 {
 	xfs_log_item_t		*mlip;
-	xfs_lsn_t		tail_lsn;
 	int			mlip_changed = 0;
 	int			i;
 
@@ -785,23 +729,12 @@
 		if (mlip == lip)
 			mlip_changed = 1;
 	}
-
-	if (!mlip_changed) {
-		spin_unlock(&ailp->xa_lock);
-		return;
-	}
-
-	/*
-	 * It is not safe to access mlip after the AIL lock is dropped, so we
-	 * must get a copy of li_lsn before we do so.  This is especially
-	 * important on 32-bit platforms where accessing and updating 64-bit
-	 * values like li_lsn is not atomic. It is possible we've emptied the
-	 * AIL here, so if that is the case, pass an LSN of 0 to the tail move.
-	 */
-	mlip = xfs_ail_min(ailp);
-	tail_lsn = mlip ? mlip->li_lsn : 0;
 	spin_unlock(&ailp->xa_lock);
-	xfs_log_move_tail(ailp->xa_mount, tail_lsn);
+
+	if (mlip_changed && !XFS_FORCED_SHUTDOWN(ailp->xa_mount)) {
+		xlog_assign_tail_lsn(ailp->xa_mount);
+		xfs_log_space_wake(ailp->xa_mount);
+	}
 }
 
 /*
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
index 475a4de..1302d1d 100644
--- a/fs/xfs/xfs_trans_buf.c
+++ b/fs/xfs/xfs_trans_buf.c
@@ -463,19 +463,7 @@
 	 * Default to a normal brelse() call if the tp is NULL.
 	 */
 	if (tp == NULL) {
-		struct xfs_log_item	*lip = bp->b_fspriv;
-
 		ASSERT(bp->b_transp == NULL);
-
-		/*
-		 * If there's a buf log item attached to the buffer,
-		 * then let the AIL know that the buffer is being
-		 * unlocked.
-		 */
-		if (lip != NULL && lip->li_type == XFS_LI_BUF) {
-			bip = bp->b_fspriv;
-			xfs_trans_unlocked_item(bip->bli_item.li_ailp, lip);
-		}
 		xfs_buf_relse(bp);
 		return;
 	}
@@ -550,21 +538,10 @@
 		ASSERT(!(bip->bli_item.li_flags & XFS_LI_IN_AIL));
 		ASSERT(!(bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF));
 		xfs_buf_item_relse(bp);
-		bip = NULL;
 	}
+
 	bp->b_transp = NULL;
-
-	/*
-	 * If we've still got a buf log item on the buffer, then
-	 * tell the AIL that the buffer is being unlocked.
-	 */
-	if (bip != NULL) {
-		xfs_trans_unlocked_item(bip->bli_item.li_ailp,
-					(xfs_log_item_t*)bip);
-	}
-
 	xfs_buf_relse(bp);
-	return;
 }
 
 /*
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index c4ba366..2790997 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -605,7 +605,7 @@
 	time_t		timer;
 	xfs_qwarncnt_t	warns;
 	xfs_qwarncnt_t	warnlimit;
-	xfs_qcnt_t	count;
+	xfs_qcnt_t	total_count;
 	xfs_qcnt_t	*resbcountp;
 	xfs_quotainfo_t	*q = mp->m_quotainfo;
 
@@ -648,13 +648,12 @@
 			 * hardlimit or exceed the timelimit if we allocate
 			 * nblks.
 			 */
-			if (hardlimit > 0ULL &&
-			    hardlimit < nblks + *resbcountp) {
+			total_count = *resbcountp + nblks;
+			if (hardlimit && total_count > hardlimit) {
 				xfs_quota_warn(mp, dqp, QUOTA_NL_BHARDWARN);
 				goto error_return;
 			}
-			if (softlimit > 0ULL &&
-			    softlimit < nblks + *resbcountp) {
+			if (softlimit && total_count > softlimit) {
 				if ((timer != 0 && get_seconds() > timer) ||
 				    (warns != 0 && warns >= warnlimit)) {
 					xfs_quota_warn(mp, dqp,
@@ -666,7 +665,7 @@
 			}
 		}
 		if (ninos > 0) {
-			count = be64_to_cpu(dqp->q_core.d_icount);
+			total_count = be64_to_cpu(dqp->q_core.d_icount) + ninos;
 			timer = be32_to_cpu(dqp->q_core.d_itimer);
 			warns = be16_to_cpu(dqp->q_core.d_iwarns);
 			warnlimit = dqp->q_mount->m_quotainfo->qi_iwarnlimit;
@@ -677,13 +676,11 @@
 			if (!softlimit)
 				softlimit = q->qi_isoftlimit;
 
-			if (hardlimit > 0ULL &&
-			    hardlimit < ninos + count) {
+			if (hardlimit && total_count > hardlimit) {
 				xfs_quota_warn(mp, dqp, QUOTA_NL_IHARDWARN);
 				goto error_return;
 			}
-			if (softlimit > 0ULL &&
-			    softlimit < ninos + count) {
+			if (softlimit && total_count > softlimit) {
 				if  ((timer != 0 && get_seconds() > timer) ||
 				     (warns != 0 && warns >= warnlimit)) {
 					xfs_quota_warn(mp, dqp,
@@ -878,7 +875,7 @@
 xfs_trans_alloc_dqinfo(
 	xfs_trans_t	*tp)
 {
-	tp->t_dqinfo = kmem_zone_zalloc(xfs_Gqm->qm_dqtrxzone, KM_SLEEP);
+	tp->t_dqinfo = kmem_zone_zalloc(xfs_qm_dqtrxzone, KM_SLEEP);
 }
 
 void
@@ -887,6 +884,6 @@
 {
 	if (!tp->t_dqinfo)
 		return;
-	kmem_zone_free(xfs_Gqm->qm_dqtrxzone, tp->t_dqinfo);
+	kmem_zone_free(xfs_qm_dqtrxzone, tp->t_dqinfo);
 	tp->t_dqinfo = NULL;
 }
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c
index 32f0288..7a7442c 100644
--- a/fs/xfs/xfs_trans_inode.c
+++ b/fs/xfs/xfs_trans_inode.c
@@ -95,10 +95,14 @@
 	if ((flags & XFS_ICHGTIME_MOD) &&
 	    !timespec_equal(&inode->i_mtime, &tv)) {
 		inode->i_mtime = tv;
+		ip->i_d.di_mtime.t_sec = tv.tv_sec;
+		ip->i_d.di_mtime.t_nsec = tv.tv_nsec;
 	}
 	if ((flags & XFS_ICHGTIME_CHG) &&
 	    !timespec_equal(&inode->i_ctime, &tv)) {
 		inode->i_ctime = tv;
+		ip->i_d.di_ctime.t_sec = tv.tv_sec;
+		ip->i_d.di_ctime.t_nsec = tv.tv_nsec;
 	}
 }
 
@@ -126,12 +130,12 @@
 	/*
 	 * Always OR in the bits from the ili_last_fields field.
 	 * This is to coordinate with the xfs_iflush() and xfs_iflush_done()
-	 * routines in the eventual clearing of the ilf_fields bits.
+	 * routines in the eventual clearing of the ili_fields bits.
 	 * See the big comment in xfs_iflush() for an explanation of
 	 * this coordination mechanism.
 	 */
 	flags |= ip->i_itemp->ili_last_fields;
-	ip->i_itemp->ili_format.ilf_fields |= flags;
+	ip->i_itemp->ili_fields |= flags;
 }
 
 #ifdef XFS_TRANS_DEBUG
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
index 44820b9..8ab2ced 100644
--- a/fs/xfs/xfs_trans_priv.h
+++ b/fs/xfs/xfs_trans_priv.h
@@ -104,9 +104,6 @@
 void			xfs_ail_push_all(struct xfs_ail *);
 xfs_lsn_t		xfs_ail_min_lsn(struct xfs_ail *ailp);
 
-void			xfs_trans_unlocked_item(struct xfs_ail *,
-					xfs_log_item_t *);
-
 struct xfs_log_item *	xfs_trans_ail_cursor_first(struct xfs_ail *ailp,
 					struct xfs_ail_cursor *cur,
 					xfs_lsn_t lsn);
diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c
index 89dbb4a..79c05ac 100644
--- a/fs/xfs/xfs_utils.c
+++ b/fs/xfs/xfs_utils.c
@@ -296,8 +296,6 @@
 	xfs_trans_t *tp,
 	xfs_inode_t *ip)
 {
-	if (ip->i_d.di_nlink >= XFS_MAXLINK)
-		return XFS_ERROR(EMLINK);
 	xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
 
 	ASSERT(ip->i_d.di_nlink > 0);
diff --git a/fs/xfs/xfs_vnode.h b/fs/xfs/xfs_vnode.h
index 7c220b4..db14d0c 100644
--- a/fs/xfs/xfs_vnode.h
+++ b/fs/xfs/xfs_vnode.h
@@ -22,7 +22,6 @@
 
 struct file;
 struct xfs_inode;
-struct xfs_iomap;
 struct attrlist_cursor_kern;
 
 /*
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index ebdb888..64981d7 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -917,14 +917,6 @@
 	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
 	unlock_dp_on_error = B_TRUE;
 
-	/*
-	 * Check for directory link count overflow.
-	 */
-	if (is_dir && dp->i_d.di_nlink >= XFS_MAXLINK) {
-		error = XFS_ERROR(EMLINK);
-		goto out_trans_cancel;
-	}
-
 	xfs_bmap_init(&free_list, &first_block);
 
 	/*
@@ -1429,14 +1421,6 @@
 	xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);
 
 	/*
-	 * If the source has too many links, we can't make any more to it.
-	 */
-	if (sip->i_d.di_nlink >= XFS_MAXLINK) {
-		error = XFS_ERROR(EMLINK);
-		goto error_return;
-	}
-
-	/*
 	 * If we are using project inheritance, we only allow hard link
 	 * creation in our tree when the project IDs are the same; else
 	 * the tree quota mechanism could be circumvented.
diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h
index 0c877cb..447e146 100644
--- a/fs/xfs/xfs_vnodeops.h
+++ b/fs/xfs/xfs_vnodeops.h
@@ -10,7 +10,6 @@
 struct pipe_inode_info;
 struct uio;
 struct xfs_inode;
-struct xfs_iomap;
 
 
 int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap, int flags);
@@ -49,8 +48,6 @@
 int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		int flags, struct attrlist_cursor_kern *cursor);
-int xfs_bmap(struct xfs_inode *ip, xfs_off_t offset, ssize_t count,
-		int flags, struct xfs_iomap *iomapp, int *niomaps);
 void xfs_tosspages(struct xfs_inode *inode, xfs_off_t first,
 		xfs_off_t last, int fiopt);
 int xfs_flushinval_pages(struct xfs_inode *ip, xfs_off_t first,
diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h
new file mode 100644
index 0000000..03f1485
--- /dev/null
+++ b/include/acpi/acconfig.h
@@ -0,0 +1,248 @@
+/******************************************************************************
+ *
+ * Name: acconfig.h - Global configuration constants
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2012, Intel Corp.
+ * All rights reserved.
+ *
+ * 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 at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#ifndef _ACCONFIG_H
+#define _ACCONFIG_H
+
+/******************************************************************************
+ *
+ * Configuration options
+ *
+ *****************************************************************************/
+
+/*
+ * ACPI_DEBUG_OUTPUT    - This switch enables all the debug facilities of the
+ *                        ACPI subsystem.  This includes the DEBUG_PRINT output
+ *                        statements.  When disabled, all DEBUG_PRINT
+ *                        statements are compiled out.
+ *
+ * ACPI_APPLICATION     - Use this switch if the subsystem is going to be run
+ *                        at the application level.
+ *
+ */
+
+/*
+ * OS name, used for the _OS object.  The _OS object is essentially obsolete,
+ * but there is a large base of ASL/AML code in existing machines that check
+ * for the string below.  The use of this string usually guarantees that
+ * the ASL will execute down the most tested code path.  Also, there is some
+ * code that will not execute the _OSI method unless _OS matches the string
+ * below.  Therefore, change this string at your own risk.
+ */
+#define ACPI_OS_NAME                    "Microsoft Windows NT"
+
+/* Maximum objects in the various object caches */
+
+#define ACPI_MAX_STATE_CACHE_DEPTH      96	/* State objects */
+#define ACPI_MAX_PARSE_CACHE_DEPTH      96	/* Parse tree objects */
+#define ACPI_MAX_EXTPARSE_CACHE_DEPTH   96	/* Parse tree objects */
+#define ACPI_MAX_OBJECT_CACHE_DEPTH     96	/* Interpreter operand objects */
+#define ACPI_MAX_NAMESPACE_CACHE_DEPTH  96	/* Namespace objects */
+
+/*
+ * Should the subsystem abort the loading of an ACPI table if the
+ * table checksum is incorrect?
+ */
+#define ACPI_CHECKSUM_ABORT             FALSE
+
+/*
+ * Generate a version of ACPICA that only supports "reduced hardware"
+ * platforms (as defined in ACPI 5.0). Set to TRUE to generate a specialized
+ * version of ACPICA that ONLY supports the ACPI 5.0 "reduced hardware"
+ * model. In other words, no ACPI hardware is supported.
+ *
+ * If TRUE, this means no support for the following:
+ *      PM Event and Control registers
+ *      SCI interrupt (and handler)
+ *      Fixed Events
+ *      General Purpose Events (GPEs)
+ *      Global Lock
+ *      ACPI PM timer
+ *      FACS table (Waking vectors and Global Lock)
+ */
+#define ACPI_REDUCED_HARDWARE           FALSE
+
+/******************************************************************************
+ *
+ * Subsystem Constants
+ *
+ *****************************************************************************/
+
+/* Version of ACPI supported */
+
+#define ACPI_CA_SUPPORT_LEVEL           5
+
+/* Maximum count for a semaphore object */
+
+#define ACPI_MAX_SEMAPHORE_COUNT        256
+
+/* Maximum object reference count (detects object deletion issues) */
+
+#define ACPI_MAX_REFERENCE_COUNT        0x1000
+
+/* Default page size for use in mapping memory for operation regions */
+
+#define ACPI_DEFAULT_PAGE_SIZE          4096	/* Must be power of 2 */
+
+/* owner_id tracking. 8 entries allows for 255 owner_ids */
+
+#define ACPI_NUM_OWNERID_MASKS          8
+
+/* Size of the root table array is increased by this increment */
+
+#define ACPI_ROOT_TABLE_SIZE_INCREMENT  4
+
+/* Maximum number of While() loop iterations before forced abort */
+
+#define ACPI_MAX_LOOP_ITERATIONS        0xFFFF
+
+/* Maximum sleep allowed via Sleep() operator */
+
+#define ACPI_MAX_SLEEP                  2000	/* Two seconds */
+
+/* Address Range lists are per-space_id (Memory and I/O only) */
+
+#define ACPI_ADDRESS_RANGE_MAX          2
+
+/******************************************************************************
+ *
+ * ACPI Specification constants (Do not change unless the specification changes)
+ *
+ *****************************************************************************/
+
+/* Number of distinct GPE register blocks and register width */
+
+#define ACPI_MAX_GPE_BLOCKS             2
+#define ACPI_GPE_REGISTER_WIDTH         8
+
+/* Method info (in WALK_STATE), containing local variables and argumetns */
+
+#define ACPI_METHOD_NUM_LOCALS          8
+#define ACPI_METHOD_MAX_LOCAL           7
+
+#define ACPI_METHOD_NUM_ARGS            7
+#define ACPI_METHOD_MAX_ARG             6
+
+/* Length of _HID, _UID, _CID, and UUID values */
+
+#define ACPI_DEVICE_ID_LENGTH           0x09
+#define ACPI_MAX_CID_LENGTH             48
+#define ACPI_UUID_LENGTH                16
+
+/*
+ * Operand Stack (in WALK_STATE), Must be large enough to contain METHOD_MAX_ARG
+ */
+#define ACPI_OBJ_NUM_OPERANDS           8
+#define ACPI_OBJ_MAX_OPERAND            7
+
+/* Number of elements in the Result Stack frame, can be an arbitrary value */
+
+#define ACPI_RESULTS_FRAME_OBJ_NUM      8
+
+/*
+ * Maximal number of elements the Result Stack can contain,
+ * it may be an arbitray value not exceeding the types of
+ * result_size and result_count (now u8).
+ */
+#define ACPI_RESULTS_OBJ_NUM_MAX        255
+
+/* Names within the namespace are 4 bytes long */
+
+#define ACPI_NAME_SIZE                  4
+#define ACPI_PATH_SEGMENT_LENGTH        5	/* 4 chars for name + 1 char for separator */
+#define ACPI_PATH_SEPARATOR             '.'
+
+/* Sizes for ACPI table headers */
+
+#define ACPI_OEM_ID_SIZE                6
+#define ACPI_OEM_TABLE_ID_SIZE          8
+
+/* Constants used in searching for the RSDP in low memory */
+
+#define ACPI_EBDA_PTR_LOCATION          0x0000040E	/* Physical Address */
+#define ACPI_EBDA_PTR_LENGTH            2
+#define ACPI_EBDA_WINDOW_SIZE           1024
+#define ACPI_HI_RSDP_WINDOW_BASE        0x000E0000	/* Physical Address */
+#define ACPI_HI_RSDP_WINDOW_SIZE        0x00020000
+#define ACPI_RSDP_SCAN_STEP             16
+
+/* Operation regions */
+
+#define ACPI_USER_REGION_BEGIN          0x80
+
+/* Maximum space_ids for Operation Regions */
+
+#define ACPI_MAX_ADDRESS_SPACE          255
+
+/* Array sizes.  Used for range checking also */
+
+#define ACPI_MAX_MATCH_OPCODE           5
+
+/* RSDP checksums */
+
+#define ACPI_RSDP_CHECKSUM_LENGTH       20
+#define ACPI_RSDP_XCHECKSUM_LENGTH      36
+
+/* SMBus, GSBus and IPMI bidirectional buffer size */
+
+#define ACPI_SMBUS_BUFFER_SIZE          34
+#define ACPI_GSBUS_BUFFER_SIZE          34
+#define ACPI_IPMI_BUFFER_SIZE           66
+
+/* _sx_d and _sx_w control methods */
+
+#define ACPI_NUM_sx_d_METHODS           4
+#define ACPI_NUM_sx_w_METHODS           5
+
+/******************************************************************************
+ *
+ * ACPI AML Debugger
+ *
+ *****************************************************************************/
+
+#define ACPI_DEBUGGER_MAX_ARGS          8	/* Must be max method args + 1 */
+
+#define ACPI_DEBUGGER_COMMAND_PROMPT    '-'
+#define ACPI_DEBUGGER_EXECUTE_PROMPT    '%'
+
+#endif				/* _ACCONFIG_H */
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h
index 5b6c391..92d6e1d 100644
--- a/include/acpi/acexcep.h
+++ b/include/acpi/acexcep.h
@@ -57,6 +57,7 @@
 #define ACPI_SUCCESS(a)                 (!(a))
 #define ACPI_FAILURE(a)                 (a)
 
+#define ACPI_SKIP(a)                    (a == AE_CTRL_SKIP)
 #define AE_OK                           (acpi_status) 0x0000
 
 /*
@@ -89,8 +90,9 @@
 #define AE_SAME_HANDLER                 (acpi_status) (0x0019 | AE_CODE_ENVIRONMENTAL)
 #define AE_NO_HANDLER                   (acpi_status) (0x001A | AE_CODE_ENVIRONMENTAL)
 #define AE_OWNER_ID_LIMIT               (acpi_status) (0x001B | AE_CODE_ENVIRONMENTAL)
+#define AE_NOT_CONFIGURED               (acpi_status) (0x001C | AE_CODE_ENVIRONMENTAL)
 
-#define AE_CODE_ENV_MAX                 0x001B
+#define AE_CODE_ENV_MAX                 0x001C
 
 /*
  * Programmer exceptions
@@ -213,7 +215,8 @@
 	"AE_ABORT_METHOD",
 	"AE_SAME_HANDLER",
 	"AE_NO_HANDLER",
-	"AE_OWNER_ID_LIMIT"
+	"AE_OWNER_ID_LIMIT",
+	"AE_NOT_CONFIGURED"
 };
 
 char const *acpi_gbl_exception_names_pgm[] = {
diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h
index 5b5af0d..38f5088 100644
--- a/include/acpi/acnames.h
+++ b/include/acpi/acnames.h
@@ -46,6 +46,7 @@
 
 /* Method names - these methods can appear anywhere in the namespace */
 
+#define METHOD_NAME__SB_        "_SB_"
 #define METHOD_NAME__HID        "_HID"
 #define METHOD_NAME__CID        "_CID"
 #define METHOD_NAME__UID        "_UID"
@@ -64,11 +65,11 @@
 
 /* Method names - these methods must appear at the namespace root */
 
-#define METHOD_NAME__BFS        "\\_BFS"
-#define METHOD_NAME__GTS        "\\_GTS"
-#define METHOD_NAME__PTS        "\\_PTS"
-#define METHOD_NAME__SST        "\\_SI._SST"
-#define METHOD_NAME__WAK        "\\_WAK"
+#define METHOD_PATHNAME__BFS    "\\_BFS"
+#define METHOD_PATHNAME__GTS    "\\_GTS"
+#define METHOD_PATHNAME__PTS    "\\_PTS"
+#define METHOD_PATHNAME__SST    "\\_SI._SST"
+#define METHOD_PATHNAME__WAK    "\\_WAK"
 
 /* Definitions of the predefined namespace names  */
 
@@ -79,6 +80,5 @@
 #define ACPI_PREFIX_LOWER       (u32) 0x69706361	/* "acpi" */
 
 #define ACPI_NS_ROOT_PATH       "\\"
-#define ACPI_NS_SYSTEM_BUS      "_SB_"
 
 #endif				/* __ACNAMES_H__  */
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 6cd5b64..f1c8ca6 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -323,6 +323,8 @@
 int acpi_bus_update_power(acpi_handle handle, int *state_p);
 bool acpi_bus_power_manageable(acpi_handle handle);
 bool acpi_bus_can_wakeup(acpi_handle handle);
+int acpi_power_resource_register_device(struct device *dev, acpi_handle handle);
+void acpi_power_resource_unregister_device(struct device *dev, acpi_handle handle);
 #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);
@@ -392,8 +394,13 @@
 #endif
 
 #ifdef CONFIG_PM_SLEEP
+int acpi_pm_device_run_wake(struct device *, bool);
 int acpi_pm_device_sleep_wake(struct device *, bool);
 #else
+static inline int acpi_pm_device_run_wake(struct device *dev, bool enable)
+{
+	return -ENODEV;
+}
 static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
 {
 	return -ENODEV;
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 7c9aebe..21a5548 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -95,6 +95,11 @@
 acpi_os_table_override(struct acpi_table_header *existing_table,
 		       struct acpi_table_header **new_table);
 
+acpi_status
+acpi_os_physical_table_override(struct acpi_table_header *existing_table,
+				acpi_physical_address * new_address,
+				u32 *new_table_length);
+
 /*
  * Spinlock primitives
  */
@@ -217,14 +222,10 @@
  * Platform and hardware-independent physical memory interfaces
  */
 acpi_status
-acpi_os_read_memory(acpi_physical_address address, u32 * value, u32 width);
-acpi_status
-acpi_os_read_memory64(acpi_physical_address address, u64 *value, u32 width);
+acpi_os_read_memory(acpi_physical_address address, u64 *value, u32 width);
 
 acpi_status
-acpi_os_write_memory(acpi_physical_address address, u32 value, u32 width);
-acpi_status
-acpi_os_write_memory64(acpi_physical_address address, u64 value, u32 width);
+acpi_os_write_memory(acpi_physical_address address, u64 value, u32 width);
 
 /*
  * Platform and hardware-independent PCI configuration space access
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index a28da35..9821101 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -47,8 +47,9 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20120111
+#define ACPI_CA_VERSION                 0x20120320
 
+#include "acconfig.h"
 #include "actypes.h"
 #include "actbl.h"
 
@@ -71,6 +72,33 @@
 extern u8 acpi_gbl_truncate_io_addresses;
 extern u8 acpi_gbl_disable_auto_repair;
 
+/*
+ * Hardware-reduced prototypes. All interfaces that use these macros will
+ * be configured out of the ACPICA build if the ACPI_REDUCED_HARDWARE flag
+ * is set to TRUE.
+ */
+#if (!ACPI_REDUCED_HARDWARE)
+#define ACPI_HW_DEPENDENT_RETURN_STATUS(prototype) \
+	prototype;
+
+#define ACPI_HW_DEPENDENT_RETURN_OK(prototype) \
+	prototype;
+
+#define ACPI_HW_DEPENDENT_RETURN_VOID(prototype) \
+	prototype;
+
+#else
+#define ACPI_HW_DEPENDENT_RETURN_STATUS(prototype) \
+	static ACPI_INLINE prototype {return(AE_NOT_CONFIGURED);}
+
+#define ACPI_HW_DEPENDENT_RETURN_OK(prototype) \
+	static ACPI_INLINE prototype {return(AE_OK);}
+
+#define ACPI_HW_DEPENDENT_RETURN_VOID(prototype) \
+	static ACPI_INLINE prototype {}
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
+
 extern u32 acpi_current_gpe_count;
 extern struct acpi_table_fadt acpi_gbl_FADT;
 extern u8 acpi_gbl_system_awake_and_running;
@@ -96,9 +124,8 @@
 acpi_status acpi_subsystem_status(void);
 #endif
 
-acpi_status acpi_enable(void);
-
-acpi_status acpi_disable(void);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable(void))
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable(void))
 
 #ifdef ACPI_FUTURE_USAGE
 acpi_status acpi_get_system_info(struct acpi_buffer *ret_buffer);
@@ -235,17 +262,34 @@
 acpi_status
 acpi_install_initialization_handler(acpi_init_handler handler, u32 function);
 
-acpi_status
-acpi_install_global_event_handler(ACPI_GBL_EVENT_HANDLER handler,
-				 void *context);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_install_global_event_handler
+				(ACPI_GBL_EVENT_HANDLER handler, void *context))
 
-acpi_status
-acpi_install_fixed_event_handler(u32 acpi_event,
-				 acpi_event_handler handler, void *context);
-
-acpi_status
-acpi_remove_fixed_event_handler(u32 acpi_event, acpi_event_handler handler);
-
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				 acpi_install_fixed_event_handler(u32
+								  acpi_event,
+								  acpi_event_handler
+								  handler,
+								  void
+								  *context))
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				 acpi_remove_fixed_event_handler(u32 acpi_event,
+								 acpi_event_handler
+								 handler))
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				 acpi_install_gpe_handler(acpi_handle
+							  gpe_device,
+							  u32 gpe_number,
+							  u32 type,
+							  acpi_gpe_handler
+							  address,
+							  void *context))
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				 acpi_remove_gpe_handler(acpi_handle gpe_device,
+							 u32 gpe_number,
+							 acpi_gpe_handler
+							 address))
 acpi_status
 acpi_install_notify_handler(acpi_handle device,
 			    u32 handler_type,
@@ -266,15 +310,6 @@
 				  acpi_adr_space_type space_id,
 				  acpi_adr_space_handler handler);
 
-acpi_status
-acpi_install_gpe_handler(acpi_handle gpe_device,
-			 u32 gpe_number,
-			 u32 type, acpi_gpe_handler address, void *context);
-
-acpi_status
-acpi_remove_gpe_handler(acpi_handle gpe_device,
-			u32 gpe_number, acpi_gpe_handler address);
-
 #ifdef ACPI_FUTURE_USAGE
 acpi_status acpi_install_exception_handler(acpi_exception_handler handler);
 #endif
@@ -284,9 +319,11 @@
 /*
  * Global Lock interfaces
  */
-acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle);
-
-acpi_status acpi_release_global_lock(u32 handle);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_acquire_global_lock(u16 timeout,
+							 u32 *handle))
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_release_global_lock(u32 handle))
 
 /*
  * Interfaces to AML mutex objects
@@ -299,47 +336,75 @@
 /*
  * Fixed Event interfaces
  */
-acpi_status acpi_enable_event(u32 event, u32 flags);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_enable_event(u32 event, u32 flags))
 
-acpi_status acpi_disable_event(u32 event, u32 flags);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_disable_event(u32 event, u32 flags))
 
-acpi_status acpi_clear_event(u32 event);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_clear_event(u32 event))
 
-acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status);
-
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_get_event_status(u32 event,
+						      acpi_event_status
+						      *event_status))
 /*
  * General Purpose Event (GPE) Interfaces
  */
-acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_update_all_gpes(void))
 
-acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_enable_gpe(acpi_handle gpe_device,
+						u32 gpe_number))
 
-acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_disable_gpe(acpi_handle gpe_device,
+						 u32 gpe_number))
 
-acpi_status
-acpi_setup_gpe_for_wake(acpi_handle parent_device,
-			acpi_handle gpe_device, u32 gpe_number);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_clear_gpe(acpi_handle gpe_device,
+					       u32 gpe_number))
 
-acpi_status acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_set_gpe(acpi_handle gpe_device,
+					     u32 gpe_number, u8 action))
 
-acpi_status
-acpi_get_gpe_status(acpi_handle gpe_device,
-		    u32 gpe_number, acpi_event_status *event_status);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_finish_gpe(acpi_handle gpe_device,
+						u32 gpe_number))
 
-acpi_status acpi_disable_all_gpes(void);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_setup_gpe_for_wake(acpi_handle
+							parent_device,
+							acpi_handle gpe_device,
+							u32 gpe_number))
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				 acpi_set_gpe_wake_mask(acpi_handle gpe_device,
+							u32 gpe_number,
+							u8 action))
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				 acpi_get_gpe_status(acpi_handle gpe_device,
+						     u32 gpe_number,
+						     acpi_event_status
+						     *event_status))
 
-acpi_status acpi_enable_all_runtime_gpes(void);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable_all_gpes(void))
 
-acpi_status acpi_get_gpe_device(u32 gpe_index, acpi_handle *gpe_device);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_runtime_gpes(void))
 
-acpi_status
-acpi_install_gpe_block(acpi_handle gpe_device,
-		       struct acpi_generic_address *gpe_block_address,
-		       u32 register_count, u32 interrupt_number);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_get_gpe_device(u32 gpe_index,
+						    acpi_handle * gpe_device))
 
-acpi_status acpi_remove_gpe_block(acpi_handle gpe_device);
-
-acpi_status acpi_update_all_gpes(void);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_install_gpe_block(acpi_handle gpe_device,
+						       struct
+						       acpi_generic_address
+						       *gpe_block_address,
+						       u32 register_count,
+						       u32 interrupt_number))
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				 acpi_remove_gpe_block(acpi_handle gpe_device))
 
 /*
  * Resource interfaces
@@ -391,34 +456,60 @@
  */
 acpi_status acpi_reset(void);
 
-acpi_status acpi_read_bit_register(u32 register_id, u32 *return_value);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_read_bit_register(u32 register_id,
+						       u32 *return_value))
 
-acpi_status acpi_write_bit_register(u32 register_id, u32 value);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_write_bit_register(u32 register_id,
+							u32 value))
 
-acpi_status acpi_set_firmware_waking_vector(u32 physical_address);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_set_firmware_waking_vector(u32
+								physical_address))
 
 #if ACPI_MACHINE_WIDTH == 64
-acpi_status acpi_set_firmware_waking_vector64(u64 physical_address);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_set_firmware_waking_vector64(u64
+								  physical_address))
 #endif
 
 acpi_status acpi_read(u64 *value, struct acpi_generic_address *reg);
 
 acpi_status acpi_write(u64 value, struct acpi_generic_address *reg);
 
+/*
+ * Sleep/Wake interfaces
+ */
 acpi_status
 acpi_get_sleep_type_data(u8 sleep_state, u8 * slp_typ_a, u8 * slp_typ_b);
 
 acpi_status acpi_enter_sleep_state_prep(u8 sleep_state);
 
-acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state);
+acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state, u8 flags);
 
-acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void);
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void))
 
-acpi_status acpi_leave_sleep_state_prep(u8 sleep_state);
+acpi_status acpi_leave_sleep_state_prep(u8 sleep_state, u8 flags);
 
 acpi_status acpi_leave_sleep_state(u8 sleep_state);
 
 /*
+ * ACPI Timer interfaces
+ */
+#ifdef ACPI_FUTURE_USAGE
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_get_timer_resolution(u32 *resolution))
+
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_get_timer(u32 *ticks))
+
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				acpi_get_timer_duration(u32 start_ticks,
+							u32 end_ticks,
+							u32 *time_elapsed))
+#endif				/* ACPI_FUTURE_USAGE */
+
+/*
  * Error/Warning output
  */
 void ACPI_INTERNAL_VAR_XFACE
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index 8e1b92f..8dea546 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -309,6 +309,13 @@
 	PM_TABLET = 8
 };
 
+/* Values for sleep_status and sleep_control registers (V5 FADT) */
+
+#define ACPI_X_WAKE_STATUS          0x80
+#define ACPI_X_SLEEP_TYPE_MASK      0x1C
+#define ACPI_X_SLEEP_TYPE_POSITION  0x02
+#define ACPI_X_SLEEP_ENABLE         0x20
+
 /* Reset to default packing */
 
 #pragma pack()
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index d5dee7c..eba6604 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -518,6 +518,13 @@
 #define ACPI_SLEEP_TYPE_INVALID         0xFF
 
 /*
+ * Sleep/Wake flags
+ */
+#define ACPI_NO_OPTIONAL_METHODS        0x00	/* Do not execute any optional methods */
+#define ACPI_EXECUTE_GTS                0x01	/* For enter sleep interface */
+#define ACPI_EXECUTE_BFS                0x02	/* For leave sleep prep interface */
+
+/*
  * Standard notify values
  */
 #define ACPI_NOTIFY_BUS_CHECK           (u8) 0x00
@@ -532,8 +539,9 @@
 #define ACPI_NOTIFY_DEVICE_PLD_CHECK    (u8) 0x09
 #define ACPI_NOTIFY_RESERVED            (u8) 0x0A
 #define ACPI_NOTIFY_LOCALITY_UPDATE     (u8) 0x0B
+#define ACPI_NOTIFY_SHUTDOWN_REQUEST    (u8) 0x0C
 
-#define ACPI_NOTIFY_MAX                 0x0B
+#define ACPI_NOTIFY_MAX                 0x0C
 
 /*
  * Types associated with ACPI names and objects. The first group of
@@ -698,7 +706,8 @@
 #define ACPI_ALL_NOTIFY                 (ACPI_SYSTEM_NOTIFY | ACPI_DEVICE_NOTIFY)
 #define ACPI_MAX_NOTIFY_HANDLER_TYPE    0x3
 
-#define ACPI_MAX_SYS_NOTIFY             0x7f
+#define ACPI_MAX_SYS_NOTIFY             0x7F
+#define ACPI_MAX_DEVICE_SPECIFIC_NOTIFY 0xBF
 
 /* Address Space (Operation Region) Types */
 
@@ -786,6 +795,15 @@
 #define ACPI_ENABLE_EVENT                       1
 #define ACPI_DISABLE_EVENT                      0
 
+/* Sleep function dispatch */
+
+typedef acpi_status(*ACPI_SLEEP_FUNCTION) (u8 sleep_state, u8 flags);
+
+struct acpi_sleep_functions {
+	ACPI_SLEEP_FUNCTION legacy_function;
+	ACPI_SLEEP_FUNCTION extended_function;
+};
+
 /*
  * External ACPI object definition
  */
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index f4b2eff..6fbc4ca 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -57,7 +57,6 @@
 #include <linux/kernel.h>
 #include <linux/ctype.h>
 #include <linux/sched.h>
-#include <asm/system.h>
 #include <linux/atomic.h>
 #include <asm/div64.h>
 #include <asm/acpi.h>
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h
index e37963c1..1ced641 100644
--- a/include/asm-generic/atomic.h
+++ b/include/asm-generic/atomic.h
@@ -15,6 +15,8 @@
 #ifndef __ASM_GENERIC_ATOMIC_H
 #define __ASM_GENERIC_ATOMIC_H
 
+#include <asm/cmpxchg.h>
+
 #ifdef CONFIG_SMP
 /* Force people to define core atomics */
 # if !defined(atomic_add_return) || !defined(atomic_sub_return) || \
@@ -52,7 +54,6 @@
 #define atomic_set(v, i) (((v)->counter) = (i))
 
 #include <linux/irqflags.h>
-#include <asm/system.h>
 
 /**
  * atomic_add_return - add integer to atomic variable
diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h
new file mode 100644
index 0000000..639d7a4
--- /dev/null
+++ b/include/asm-generic/barrier.h
@@ -0,0 +1,50 @@
+/* Generic barrier definitions, based on MN10300 definitions.
+ *
+ * It should be possible to use these on really simple architectures,
+ * but it serves more as a starting point for new ports.
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef __ASM_GENERIC_BARRIER_H
+#define __ASM_GENERIC_BARRIER_H
+
+#ifndef __ASSEMBLY__
+
+#define nop() asm volatile ("nop")
+
+/*
+ * Force strict CPU ordering.
+ * And yes, this is required on UP too when we're talking
+ * to devices.
+ *
+ * This implementation only contains a compiler barrier.
+ */
+
+#define mb()	asm volatile ("": : :"memory")
+#define rmb()	mb()
+#define wmb()	asm volatile ("": : :"memory")
+
+#ifdef CONFIG_SMP
+#define smp_mb()	mb()
+#define smp_rmb()	rmb()
+#define smp_wmb()	wmb()
+#else
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+#endif
+
+#define set_mb(var, value)  do { var = value;  mb(); } while (0)
+#define set_wmb(var, value) do { var = value; wmb(); } while (0)
+
+#define read_barrier_depends()		do {} while (0)
+#define smp_read_barrier_depends()	do {} while (0)
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_GENERIC_BARRIER_H */
diff --git a/include/asm-generic/bitops/atomic.h b/include/asm-generic/bitops/atomic.h
index ecc44a8..9ae6c34 100644
--- a/include/asm-generic/bitops/atomic.h
+++ b/include/asm-generic/bitops/atomic.h
@@ -2,7 +2,7 @@
 #define _ASM_GENERIC_BITOPS_ATOMIC_H_
 
 #include <asm/types.h>
-#include <asm/system.h>
+#include <linux/irqflags.h>
 
 #ifdef CONFIG_SMP
 #include <asm/spinlock.h>
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index 84458b0..2520a6e 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -134,7 +134,7 @@
 #endif
 
 #define WARN_ON_ONCE(condition)	({				\
-	static bool __warned;					\
+	static bool __section(.data.unlikely) __warned;		\
 	int __ret_warn_once = !!(condition);			\
 								\
 	if (unlikely(__ret_warn_once))				\
@@ -144,7 +144,7 @@
 })
 
 #define WARN_ONCE(condition, format...)	({			\
-	static bool __warned;					\
+	static bool __section(.data.unlikely) __warned;		\
 	int __ret_warn_once = !!(condition);			\
 								\
 	if (unlikely(__ret_warn_once))				\
@@ -154,7 +154,7 @@
 })
 
 #define WARN_TAINT_ONCE(condition, taint, format...)	({	\
-	static bool __warned;					\
+	static bool __section(.data.unlikely) __warned;		\
 	int __ret_warn_once = !!(condition);			\
 								\
 	if (unlikely(__ret_warn_once))				\
diff --git a/include/asm-generic/cmpxchg.h b/include/asm-generic/cmpxchg.h
index 213ac6e..1488302 100644
--- a/include/asm-generic/cmpxchg.h
+++ b/include/asm-generic/cmpxchg.h
@@ -1,22 +1,98 @@
+/*
+ * Generic UP xchg and cmpxchg using interrupt disablement.  Does not
+ * support SMP.
+ */
+
 #ifndef __ASM_GENERIC_CMPXCHG_H
 #define __ASM_GENERIC_CMPXCHG_H
 
-/*
- * Generic cmpxchg
- *
- * Uses the local cmpxchg. Does not support SMP.
- */
 #ifdef CONFIG_SMP
 #error "Cannot use generic cmpxchg on SMP"
 #endif
 
+#include <linux/types.h>
+#include <linux/irqflags.h>
+
+#ifndef xchg
+
+/*
+ * This function doesn't exist, so you'll get a linker error if
+ * something tries to do an invalidly-sized xchg().
+ */
+extern void __xchg_called_with_bad_pointer(void);
+
+static inline
+unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
+{
+	unsigned long ret, flags;
+
+	switch (size) {
+	case 1:
+#ifdef __xchg_u8
+		return __xchg_u8(x, ptr);
+#else
+		local_irq_save(flags);
+		ret = *(volatile u8 *)ptr;
+		*(volatile u8 *)ptr = x;
+		local_irq_restore(flags);
+		return ret;
+#endif /* __xchg_u8 */
+
+	case 2:
+#ifdef __xchg_u16
+		return __xchg_u16(x, ptr);
+#else
+		local_irq_save(flags);
+		ret = *(volatile u16 *)ptr;
+		*(volatile u16 *)ptr = x;
+		local_irq_restore(flags);
+		return ret;
+#endif /* __xchg_u16 */
+
+	case 4:
+#ifdef __xchg_u32
+		return __xchg_u32(x, ptr);
+#else
+		local_irq_save(flags);
+		ret = *(volatile u32 *)ptr;
+		*(volatile u32 *)ptr = x;
+		local_irq_restore(flags);
+		return ret;
+#endif /* __xchg_u32 */
+
+#ifdef CONFIG_64BIT
+	case 8:
+#ifdef __xchg_u64
+		return __xchg_u64(x, ptr);
+#else
+		local_irq_save(flags);
+		ret = *(volatile u64 *)ptr;
+		*(volatile u64 *)ptr = x;
+		local_irq_restore(flags);
+		return ret;
+#endif /* __xchg_u64 */
+#endif /* CONFIG_64BIT */
+
+	default:
+		__xchg_called_with_bad_pointer();
+		return x;
+	}
+}
+
+#define xchg(ptr, x) \
+	((__typeof__(*(ptr))) __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
+
+#endif /* xchg */
+
 /*
  * Atomic compare and exchange.
  *
  * Do not define __HAVE_ARCH_CMPXCHG because we want to use it to check whether
  * a cmpxchg primitive faster than repeated local irq save/restore exists.
  */
+#include <asm-generic/cmpxchg-local.h>
+
 #define cmpxchg(ptr, o, n)	cmpxchg_local((ptr), (o), (n))
 #define cmpxchg64(ptr, o, n)	cmpxchg64_local((ptr), (o), (n))
 
-#endif
+#endif /* __ASM_GENERIC_CMPXCHG_H */
diff --git a/include/asm-generic/dma-mapping-common.h b/include/asm-generic/dma-mapping-common.h
index 9fa3f96..2e248d8 100644
--- a/include/asm-generic/dma-mapping-common.h
+++ b/include/asm-generic/dma-mapping-common.h
@@ -2,6 +2,7 @@
 #define _ASM_GENERIC_DMA_MAPPING_H
 
 #include <linux/kmemcheck.h>
+#include <linux/bug.h>
 #include <linux/scatterlist.h>
 #include <linux/dma-debug.h>
 #include <linux/dma-attrs.h>
diff --git a/include/asm-generic/exec.h b/include/asm-generic/exec.h
new file mode 100644
index 0000000..567766b
--- /dev/null
+++ b/include/asm-generic/exec.h
@@ -0,0 +1,19 @@
+/* Generic process execution definitions, based on MN10300 definitions.
+ *
+ * It should be possible to use these on really simple architectures,
+ * but it serves more as a starting point for new ports.
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef __ASM_GENERIC_EXEC_H
+#define __ASM_GENERIC_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* __ASM_GENERIC_EXEC_H */
diff --git a/include/asm-generic/getorder.h b/include/asm-generic/getorder.h
index 67e7245..65e4468 100644
--- a/include/asm-generic/getorder.h
+++ b/include/asm-generic/getorder.h
@@ -4,21 +4,58 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/compiler.h>
+#include <linux/log2.h>
 
-/* Pure 2^n version of get_order */
-static inline __attribute_const__ int get_order(unsigned long size)
+/*
+ * Runtime evaluation of get_order()
+ */
+static inline __attribute_const__
+int __get_order(unsigned long size)
 {
 	int order;
 
-	size = (size - 1) >> (PAGE_SHIFT - 1);
-	order = -1;
-	do {
-		size >>= 1;
-		order++;
-	} while (size);
+	size--;
+	size >>= PAGE_SHIFT;
+#if BITS_PER_LONG == 32
+	order = fls(size);
+#else
+	order = fls64(size);
+#endif
 	return order;
 }
 
+/**
+ * get_order - Determine the allocation order of a memory size
+ * @size: The size for which to get the order
+ *
+ * Determine the allocation order of a particular sized block of memory.  This
+ * is on a logarithmic scale, where:
+ *
+ *	0 -> 2^0 * PAGE_SIZE and below
+ *	1 -> 2^1 * PAGE_SIZE to 2^0 * PAGE_SIZE + 1
+ *	2 -> 2^2 * PAGE_SIZE to 2^1 * PAGE_SIZE + 1
+ *	3 -> 2^3 * PAGE_SIZE to 2^2 * PAGE_SIZE + 1
+ *	4 -> 2^4 * PAGE_SIZE to 2^3 * PAGE_SIZE + 1
+ *	...
+ *
+ * The order returned is used to find the smallest allocation granule required
+ * to hold an object of the specified size.
+ *
+ * The result is undefined if the size is 0.
+ *
+ * This function may be used to initialise variables with compile time
+ * evaluations of constants.
+ */
+#define get_order(n)						\
+(								\
+	__builtin_constant_p(n) ? (				\
+		((n) == 0UL) ? BITS_PER_LONG - PAGE_SHIFT :	\
+		(((n) < (1UL << PAGE_SHIFT)) ? 0 :		\
+		 ilog2((n) - 1) - PAGE_SHIFT + 1)		\
+	) :							\
+	__get_order(n)						\
+)
+
 #endif	/* __ASSEMBLY__ */
 
 #endif	/* __ASM_GENERIC_GETORDER_H */
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 1ff4e22..5f52690 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -142,9 +142,9 @@
 /* add/remove chips */
 extern int gpiochip_add(struct gpio_chip *chip);
 extern int __must_check gpiochip_remove(struct gpio_chip *chip);
-extern struct gpio_chip *gpiochip_find(void *data,
+extern struct gpio_chip *gpiochip_find(const void *data,
 					int (*match)(struct gpio_chip *chip,
-						     void *data));
+						     const void *data));
 
 
 /* Always use the library code for GPIO management calls,
diff --git a/include/asm-generic/mman-common.h b/include/asm-generic/mman-common.h
index 787abbb..d030d2c 100644
--- a/include/asm-generic/mman-common.h
+++ b/include/asm-generic/mman-common.h
@@ -48,6 +48,10 @@
 #define MADV_HUGEPAGE	14		/* Worth backing with hugepages */
 #define MADV_NOHUGEPAGE	15		/* Not worth backing with hugepages */
 
+#define MADV_DONTDUMP   16		/* Explicity exclude from the core dump,
+					   overrides the coredump filter bits */
+#define MADV_DODUMP	17		/* Clear the MADV_NODUMP flag */
+
 /* compatibility flags */
 #define MAP_FILE	0
 
diff --git a/include/asm-generic/pci-bridge.h b/include/asm-generic/pci-bridge.h
index 4a5aca2..a5b5d5a 100644
--- a/include/asm-generic/pci-bridge.h
+++ b/include/asm-generic/pci-bridge.h
@@ -45,6 +45,11 @@
 	pci_flags |= flags;
 }
 
+static inline void pci_clear_flags(int flags)
+{
+	pci_flags &= ~flags;
+}
+
 static inline int pci_has_flag(int flag)
 {
 	return pci_flags & flag;
@@ -52,6 +57,7 @@
 #else
 static inline void pci_set_flags(int flags) { }
 static inline void pci_add_flags(int flags) { }
+static inline void pci_clear_flags(int flags) { }
 static inline int pci_has_flag(int flag)
 {
 	return 0;
diff --git a/include/asm-generic/pci.h b/include/asm-generic/pci.h
index 26373cf..e80a049 100644
--- a/include/asm-generic/pci.h
+++ b/include/asm-generic/pci.h
@@ -6,30 +6,6 @@
 #ifndef _ASM_GENERIC_PCI_H
 #define _ASM_GENERIC_PCI_H
 
-/**
- * pcibios_resource_to_bus - convert resource to PCI bus address
- * @dev: device which owns this resource
- * @region: converted bus-centric region (start,end)
- * @res: resource to convert
- *
- * Convert a resource to a PCI device bus address or bus window.
- */
-static inline void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-			 struct resource *res)
-{
-	region->start = res->start;
-	region->end = res->end;
-}
-
-static inline void
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-			struct pci_bus_region *region)
-{
-	res->start = region->start;
-	res->end = region->end;
-}
-
 static inline struct resource *
 pcibios_select_root(struct pci_dev *pdev, struct resource *res)
 {
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 76bff2b..125c54e 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -5,6 +5,7 @@
 #ifdef CONFIG_MMU
 
 #include <linux/mm_types.h>
+#include <linux/bug.h>
 
 #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
 extern int ptep_set_access_flags(struct vm_area_struct *vma,
@@ -425,6 +426,8 @@
 				unsigned long size);
 #endif
 
+#ifdef CONFIG_MMU
+
 #ifndef CONFIG_TRANSPARENT_HUGEPAGE
 static inline int pmd_trans_huge(pmd_t pmd)
 {
@@ -441,7 +444,66 @@
 	return 0;
 }
 #endif /* __HAVE_ARCH_PMD_WRITE */
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+
+/*
+ * This function is meant to be used by sites walking pagetables with
+ * the mmap_sem hold in read mode to protect against MADV_DONTNEED and
+ * transhuge page faults. MADV_DONTNEED can convert a transhuge pmd
+ * into a null pmd and the transhuge page fault can convert a null pmd
+ * into an hugepmd or into a regular pmd (if the hugepage allocation
+ * fails). While holding the mmap_sem in read mode the pmd becomes
+ * stable and stops changing under us only if it's not null and not a
+ * transhuge pmd. When those races occurs and this function makes a
+ * difference vs the standard pmd_none_or_clear_bad, the result is
+ * undefined so behaving like if the pmd was none is safe (because it
+ * can return none anyway). The compiler level barrier() is critically
+ * important to compute the two checks atomically on the same pmdval.
+ */
+static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t *pmd)
+{
+	/* depend on compiler for an atomic pmd read */
+	pmd_t pmdval = *pmd;
+	/*
+	 * The barrier will stabilize the pmdval in a register or on
+	 * the stack so that it will stop changing under the code.
+	 */
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+	barrier();
 #endif
+	if (pmd_none(pmdval))
+		return 1;
+	if (unlikely(pmd_bad(pmdval))) {
+		if (!pmd_trans_huge(pmdval))
+			pmd_clear_bad(pmd);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * This is a noop if Transparent Hugepage Support is not built into
+ * the kernel. Otherwise it is equivalent to
+ * pmd_none_or_trans_huge_or_clear_bad(), and shall only be called in
+ * places that already verified the pmd is not none and they want to
+ * walk ptes while holding the mmap sem in read mode (write mode don't
+ * need this). If THP is not enabled, the pmd can't go away under the
+ * code even if MADV_DONTNEED runs, but if THP is enabled we need to
+ * run a pmd_trans_unstable before walking the ptes after
+ * split_huge_page_pmd returns (because it may have run when the pmd
+ * become null, but then a page fault can map in a THP and not a
+ * regular page).
+ */
+static inline int pmd_trans_unstable(pmd_t *pmd)
+{
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+	return pmd_none_or_trans_huge_or_clear_bad(pmd);
+#else
+	return 0;
+#endif
+}
+
+#endif /* CONFIG_MMU */
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/include/asm-generic/posix_types.h b/include/asm-generic/posix_types.h
index 3dab008..91d44bd 100644
--- a/include/asm-generic/posix_types.h
+++ b/include/asm-generic/posix_types.h
@@ -10,8 +10,13 @@
  * architectures, so that you can override them.
  */
 
+#ifndef __kernel_long_t
+typedef long		__kernel_long_t;
+typedef unsigned long	__kernel_ulong_t;
+#endif
+
 #ifndef __kernel_ino_t
-typedef unsigned long	__kernel_ino_t;
+typedef __kernel_ulong_t __kernel_ino_t;
 #endif
 
 #ifndef __kernel_mode_t
@@ -19,7 +24,7 @@
 #endif
 
 #ifndef __kernel_nlink_t
-typedef unsigned long	__kernel_nlink_t;
+typedef __kernel_ulong_t __kernel_nlink_t;
 #endif
 
 #ifndef __kernel_pid_t
@@ -36,7 +41,7 @@
 #endif
 
 #ifndef __kernel_suseconds_t
-typedef long		__kernel_suseconds_t;
+typedef __kernel_long_t		__kernel_suseconds_t;
 #endif
 
 #ifndef __kernel_daddr_t
@@ -44,8 +49,8 @@
 #endif
 
 #ifndef __kernel_uid32_t
-typedef __kernel_uid_t	__kernel_uid32_t;
-typedef __kernel_gid_t	__kernel_gid32_t;
+typedef unsigned int	__kernel_uid32_t;
+typedef unsigned int	__kernel_gid32_t;
 #endif
 
 #ifndef __kernel_old_uid_t
@@ -67,99 +72,29 @@
 typedef int		__kernel_ssize_t;
 typedef int		__kernel_ptrdiff_t;
 #else
-typedef unsigned long	__kernel_size_t;
-typedef long		__kernel_ssize_t;
-typedef long		__kernel_ptrdiff_t;
+typedef __kernel_ulong_t __kernel_size_t;
+typedef __kernel_long_t	__kernel_ssize_t;
+typedef __kernel_long_t	__kernel_ptrdiff_t;
 #endif
 #endif
 
+#ifndef __kernel_fsid_t
+typedef struct {
+	int	val[2];
+} __kernel_fsid_t;
+#endif
+
 /*
  * anything below here should be completely generic
  */
-typedef long		__kernel_off_t;
+typedef __kernel_long_t	__kernel_off_t;
 typedef long long	__kernel_loff_t;
-typedef long		__kernel_time_t;
-typedef long		__kernel_clock_t;
+typedef __kernel_long_t	__kernel_time_t;
+typedef __kernel_long_t	__kernel_clock_t;
 typedef int		__kernel_timer_t;
 typedef int		__kernel_clockid_t;
 typedef char *		__kernel_caddr_t;
 typedef unsigned short	__kernel_uid16_t;
 typedef unsigned short	__kernel_gid16_t;
 
-typedef struct {
-	int	val[2];
-} __kernel_fsid_t;
-
-#ifdef __KERNEL__
-
-#undef __FD_SET
-static inline void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-	unsigned long __tmp = __fd / __NFDBITS;
-	unsigned long __rem = __fd % __NFDBITS;
-	__fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
-}
-
-#undef __FD_CLR
-static inline void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-	unsigned long __tmp = __fd / __NFDBITS;
-	unsigned long __rem = __fd % __NFDBITS;
-	__fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
-}
-
-#undef __FD_ISSET
-static inline int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
-{
-	unsigned long __tmp = __fd / __NFDBITS;
-	unsigned long __rem = __fd % __NFDBITS;
-	return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
-}
-
-/*
- * This will unroll the loop for the normal constant case (8 ints,
- * for a 256-bit fd_set)
- */
-#undef __FD_ZERO
-static inline void __FD_ZERO(__kernel_fd_set *__p)
-{
-	unsigned long *__tmp = __p->fds_bits;
-	int __i;
-
-	if (__builtin_constant_p(__FDSET_LONGS)) {
-		switch (__FDSET_LONGS) {
-		case 16:
-			__tmp[ 0] = 0; __tmp[ 1] = 0;
-			__tmp[ 2] = 0; __tmp[ 3] = 0;
-			__tmp[ 4] = 0; __tmp[ 5] = 0;
-			__tmp[ 6] = 0; __tmp[ 7] = 0;
-			__tmp[ 8] = 0; __tmp[ 9] = 0;
-			__tmp[10] = 0; __tmp[11] = 0;
-			__tmp[12] = 0; __tmp[13] = 0;
-			__tmp[14] = 0; __tmp[15] = 0;
-			return;
-
-		case 8:
-			__tmp[ 0] = 0; __tmp[ 1] = 0;
-			__tmp[ 2] = 0; __tmp[ 3] = 0;
-			__tmp[ 4] = 0; __tmp[ 5] = 0;
-			__tmp[ 6] = 0; __tmp[ 7] = 0;
-			return;
-
-		case 4:
-			__tmp[ 0] = 0; __tmp[ 1] = 0;
-			__tmp[ 2] = 0; __tmp[ 3] = 0;
-			return;
-		}
-	}
-	__i = __FDSET_LONGS;
-	while (__i) {
-		__i--;
-		*__tmp = 0;
-		__tmp++;
-	}
-}
-
-#endif /* __KERNEL__ */
-
 #endif /* __ASM_GENERIC_POSIX_TYPES_H */
diff --git a/include/asm-generic/switch_to.h b/include/asm-generic/switch_to.h
new file mode 100644
index 0000000..052c4ac
--- /dev/null
+++ b/include/asm-generic/switch_to.h
@@ -0,0 +1,30 @@
+/* Generic task switch macro wrapper, based on MN10300 definitions.
+ *
+ * It should be possible to use these on really simple architectures,
+ * but it serves more as a starting point for new ports.
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef __ASM_GENERIC_SWITCH_TO_H
+#define __ASM_GENERIC_SWITCH_TO_H
+
+#include <linux/thread_info.h>
+
+/*
+ * Context switching is now performed out-of-line in switch_to.S
+ */
+extern struct task_struct *__switch_to(struct task_struct *,
+				       struct task_struct *);
+
+#define switch_to(prev, next, last)					\
+	do {								\
+		((last) = __switch_to((prev), (next)));			\
+	} while (0)
+
+#endif /* __ASM_GENERIC_SWITCH_TO_H */
diff --git a/include/asm-generic/system.h b/include/asm-generic/system.h
deleted file mode 100644
index 215efa7..0000000
--- a/include/asm-generic/system.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/* Generic system definitions, based on MN10300 definitions.
- *
- * It should be possible to use these on really simple architectures,
- * but it serves more as a starting point for new ports.
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-#ifndef __ASM_GENERIC_SYSTEM_H
-#define __ASM_GENERIC_SYSTEM_H
-
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-#include <linux/irqflags.h>
-
-#include <asm/cmpxchg-local.h>
-#include <asm/cmpxchg.h>
-
-struct task_struct;
-
-/* context switching is now performed out-of-line in switch_to.S */
-extern struct task_struct *__switch_to(struct task_struct *,
-		struct task_struct *);
-#define switch_to(prev, next, last)					\
-	do {								\
-		((last) = __switch_to((prev), (next)));			\
-	} while (0)
-
-#define arch_align_stack(x) (x)
-
-#define nop() asm volatile ("nop")
-
-#endif /* !__ASSEMBLY__ */
-
-/*
- * Force strict CPU ordering.
- * And yes, this is required on UP too when we're talking
- * to devices.
- *
- * This implementation only contains a compiler barrier.
- */
-
-#define mb()	asm volatile ("": : :"memory")
-#define rmb()	mb()
-#define wmb()	asm volatile ("": : :"memory")
-
-#ifdef CONFIG_SMP
-#define smp_mb()	mb()
-#define smp_rmb()	rmb()
-#define smp_wmb()	wmb()
-#else
-#define smp_mb()	barrier()
-#define smp_rmb()	barrier()
-#define smp_wmb()	barrier()
-#endif
-
-#define set_mb(var, value)  do { var = value;  mb(); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
-
-#define read_barrier_depends()		do {} while (0)
-#define smp_read_barrier_depends()	do {} while (0)
-
-/*
- * we make sure local_irq_enable() doesn't cause priority inversion
- */
-#ifndef __ASSEMBLY__
-
-/* This function doesn't exist, so you'll get a linker error
- *    if something tries to do an invalid xchg().  */
-extern void __xchg_called_with_bad_pointer(void);
-
-static inline
-unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
-{
-	unsigned long ret, flags;
-
-	switch (size) {
-	case 1:
-#ifdef __xchg_u8
-		return __xchg_u8(x, ptr);
-#else
-		local_irq_save(flags);
-		ret = *(volatile u8 *)ptr;
-		*(volatile u8 *)ptr = x;
-		local_irq_restore(flags);
-		return ret;
-#endif /* __xchg_u8 */
-
-	case 2:
-#ifdef __xchg_u16
-		return __xchg_u16(x, ptr);
-#else
-		local_irq_save(flags);
-		ret = *(volatile u16 *)ptr;
-		*(volatile u16 *)ptr = x;
-		local_irq_restore(flags);
-		return ret;
-#endif /* __xchg_u16 */
-
-	case 4:
-#ifdef __xchg_u32
-		return __xchg_u32(x, ptr);
-#else
-		local_irq_save(flags);
-		ret = *(volatile u32 *)ptr;
-		*(volatile u32 *)ptr = x;
-		local_irq_restore(flags);
-		return ret;
-#endif /* __xchg_u32 */
-
-#ifdef CONFIG_64BIT
-	case 8:
-#ifdef __xchg_u64
-		return __xchg_u64(x, ptr);
-#else
-		local_irq_save(flags);
-		ret = *(volatile u64 *)ptr;
-		*(volatile u64 *)ptr = x;
-		local_irq_restore(flags);
-		return ret;
-#endif /* __xchg_u64 */
-#endif /* CONFIG_64BIT */
-
-	default:
-		__xchg_called_with_bad_pointer();
-		return x;
-	}
-}
-
-#define xchg(ptr, x) \
-	((__typeof__(*(ptr))) __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
-
-#endif /* !__ASSEMBLY__ */
-
-#endif /* __ASM_GENERIC_SYSTEM_H */
diff --git a/include/asm-generic/tlbflush.h b/include/asm-generic/tlbflush.h
index c7af037..d6d0a88 100644
--- a/include/asm-generic/tlbflush.h
+++ b/include/asm-generic/tlbflush.h
@@ -9,6 +9,8 @@
 #error need to implement an architecture specific asm/tlbflush.h
 #endif
 
+#include <linux/bug.h>
+
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
 	BUG();
diff --git a/include/asm-generic/unistd.h b/include/asm-generic/unistd.h
index 2292d1a..991ef01 100644
--- a/include/asm-generic/unistd.h
+++ b/include/asm-generic/unistd.h
@@ -218,7 +218,7 @@
 
 /* fs/sendfile.c */
 #define __NR3264_sendfile 71
-__SC_3264(__NR3264_sendfile, sys_sendfile64, sys_sendfile)
+__SYSCALL(__NR3264_sendfile, sys_sendfile64)
 
 /* fs/select.c */
 #define __NR_pselect6 72
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index b5e2e4c..8aeadf6 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -167,6 +167,7 @@
 	CPU_KEEP(exit.data)						\
 	MEM_KEEP(init.data)						\
 	MEM_KEEP(exit.data)						\
+	*(.data.unlikely)						\
 	STRUCT_ALIGN();							\
 	*(__tracepoints)						\
 	/* implement dynamic printk debug */				\
@@ -615,30 +616,23 @@
 		*(.init.setup)						\
 		VMLINUX_SYMBOL(__setup_end) = .;
 
-#define INITCALLS							\
-	*(.initcallearly.init)						\
-	VMLINUX_SYMBOL(__early_initcall_end) = .;			\
-  	*(.initcall0.init)						\
-  	*(.initcall0s.init)						\
-  	*(.initcall1.init)						\
-  	*(.initcall1s.init)						\
-  	*(.initcall2.init)						\
-  	*(.initcall2s.init)						\
-  	*(.initcall3.init)						\
-  	*(.initcall3s.init)						\
-  	*(.initcall4.init)						\
-  	*(.initcall4s.init)						\
-  	*(.initcall5.init)						\
-  	*(.initcall5s.init)						\
-	*(.initcallrootfs.init)						\
-  	*(.initcall6.init)						\
-  	*(.initcall6s.init)						\
-  	*(.initcall7.init)						\
-  	*(.initcall7s.init)
+#define INIT_CALLS_LEVEL(level)						\
+		VMLINUX_SYMBOL(__initcall##level##_start) = .;		\
+		*(.initcall##level##.init)				\
+		*(.initcall##level##s.init)				\
 
 #define INIT_CALLS							\
 		VMLINUX_SYMBOL(__initcall_start) = .;			\
-		INITCALLS						\
+		*(.initcallearly.init)					\
+		INIT_CALLS_LEVEL(0)					\
+		INIT_CALLS_LEVEL(1)					\
+		INIT_CALLS_LEVEL(2)					\
+		INIT_CALLS_LEVEL(3)					\
+		INIT_CALLS_LEVEL(4)					\
+		INIT_CALLS_LEVEL(5)					\
+		INIT_CALLS_LEVEL(rootfs)				\
+		INIT_CALLS_LEVEL(6)					\
+		INIT_CALLS_LEVEL(7)					\
 		VMLINUX_SYMBOL(__initcall_end) = .;
 
 #define CON_INITCALL							\
diff --git a/include/crypto/internal/aead.h b/include/crypto/internal/aead.h
index d838c94..2eba340 100644
--- a/include/crypto/internal/aead.h
+++ b/include/crypto/internal/aead.h
@@ -31,6 +31,8 @@
 	crypto_set_spawn(&spawn->base, inst);
 }
 
+struct crypto_alg *crypto_lookup_aead(const char *name, u32 type, u32 mask);
+
 int crypto_grab_aead(struct crypto_aead_spawn *spawn, const char *name,
 		     u32 type, u32 mask);
 
diff --git a/include/crypto/internal/skcipher.h b/include/crypto/internal/skcipher.h
index 3a748a6..06e8b32 100644
--- a/include/crypto/internal/skcipher.h
+++ b/include/crypto/internal/skcipher.h
@@ -34,6 +34,8 @@
 int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name,
 			 u32 type, u32 mask);
 
+struct crypto_alg *crypto_lookup_skcipher(const char *name, u32 type, u32 mask);
+
 static inline void crypto_drop_skcipher(struct crypto_skcipher_spawn *spawn)
 {
 	crypto_drop_spawn(&spawn->base);
diff --git a/include/drm/drm.h b/include/drm/drm.h
index 49d94ed..64ff02d 100644
--- a/include/drm/drm.h
+++ b/include/drm/drm.h
@@ -617,6 +617,17 @@
 	__u64 value;
 };
 
+#define DRM_CLOEXEC O_CLOEXEC
+struct drm_prime_handle {
+	__u32 handle;
+
+	/** Flags.. only applicable for handle->fd */
+	__u32 flags;
+
+	/** Returned dmabuf file descriptor */
+	__s32 fd;
+};
+
 #include "drm_mode.h"
 
 #define DRM_IOCTL_BASE			'd'
@@ -673,7 +684,8 @@
 #define DRM_IOCTL_UNLOCK		DRM_IOW( 0x2b, struct drm_lock)
 #define DRM_IOCTL_FINISH		DRM_IOW( 0x2c, struct drm_lock)
 
-#define DRM_IOCTL_GEM_PRIME_OPEN        DRM_IOWR(0x2e, struct drm_gem_open)
+#define DRM_IOCTL_PRIME_HANDLE_TO_FD    DRM_IOWR(0x2d, struct drm_prime_handle)
+#define DRM_IOCTL_PRIME_FD_TO_HANDLE    DRM_IOWR(0x2e, struct drm_prime_handle)
 
 #define DRM_IOCTL_AGP_ACQUIRE		DRM_IO(  0x30)
 #define DRM_IOCTL_AGP_RELEASE		DRM_IO(  0x31)
@@ -761,6 +773,8 @@
 
 #define DRM_CAP_DUMB_BUFFER 0x1
 #define DRM_CAP_VBLANK_HIGH_CRTC 0x2
+#define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
+#define DRM_CAP_DUMB_PREFER_SHADOW 0x4
 
 /* typedef area */
 #ifndef __KERNEL__
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 92f0981..dd73104 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -91,6 +91,7 @@
 #define DRM_UT_CORE 		0x01
 #define DRM_UT_DRIVER		0x02
 #define DRM_UT_KMS		0x04
+#define DRM_UT_PRIME		0x08
 /*
  * Three debug levels are defined.
  * drm_core, drm_driver, drm_kms
@@ -150,6 +151,7 @@
 #define DRIVER_IRQ_VBL2    0x800
 #define DRIVER_GEM         0x1000
 #define DRIVER_MODESET     0x2000
+#define DRIVER_PRIME       0x4000
 
 #define DRIVER_BUS_PCI 0x1
 #define DRIVER_BUS_PLATFORM 0x2
@@ -215,6 +217,11 @@
 		drm_ut_debug_printk(DRM_UT_KMS, DRM_NAME, 		\
 					 __func__, fmt, ##args);	\
 	} while (0)
+#define DRM_DEBUG_PRIME(fmt, args...)					\
+	do {								\
+		drm_ut_debug_printk(DRM_UT_PRIME, DRM_NAME,		\
+					__func__, fmt, ##args);		\
+	} while (0)
 #define DRM_LOG(fmt, args...)						\
 	do {								\
 		drm_ut_debug_printk(DRM_UT_CORE, NULL,			\
@@ -238,6 +245,7 @@
 #else
 #define DRM_DEBUG_DRIVER(fmt, args...) do { } while (0)
 #define DRM_DEBUG_KMS(fmt, args...)	do { } while (0)
+#define DRM_DEBUG_PRIME(fmt, args...)	do { } while (0)
 #define DRM_DEBUG(fmt, arg...)		 do { } while (0)
 #define DRM_LOG(fmt, arg...)		do { } while (0)
 #define DRM_LOG_KMS(fmt, args...) do { } while (0)
@@ -410,6 +418,12 @@
 	void (*destroy)(struct drm_pending_event *event);
 };
 
+/* initial implementaton using a linked list - todo hashtab */
+struct drm_prime_file_private {
+	struct list_head head;
+	struct mutex lock;
+};
+
 /** File private data */
 struct drm_file {
 	int authenticated;
@@ -437,6 +451,8 @@
 	wait_queue_head_t event_wait;
 	struct list_head event_list;
 	int event_space;
+
+	struct drm_prime_file_private prime;
 };
 
 /** Wait queue */
@@ -652,6 +668,12 @@
 	uint32_t pending_write_domain;
 
 	void *driver_private;
+
+	/* dma buf exported from this GEM object */
+	struct dma_buf *export_dma_buf;
+
+	/* dma buf attachment backing this object */
+	struct dma_buf_attachment *import_attach;
 };
 
 #include "drm_crtc.h"
@@ -890,6 +912,20 @@
 	int (*gem_open_object) (struct drm_gem_object *, struct drm_file *);
 	void (*gem_close_object) (struct drm_gem_object *, struct drm_file *);
 
+	/* prime: */
+	/* export handle -> fd (see drm_gem_prime_handle_to_fd() helper) */
+	int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv,
+				uint32_t handle, uint32_t flags, int *prime_fd);
+	/* import fd -> handle (see drm_gem_prime_fd_to_handle() helper) */
+	int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv,
+				int prime_fd, uint32_t *handle);
+	/* export GEM -> dmabuf */
+	struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
+				struct drm_gem_object *obj, int flags);
+	/* import dmabuf -> GEM */
+	struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
+				struct dma_buf *dma_buf);
+
 	/* vga arb irq handler */
 	void (*vgaarb_irq)(struct drm_device *dev, bool state);
 
@@ -1170,6 +1206,8 @@
 	struct idr object_name_idr;
 	/*@} */
 	int switch_power_state;
+
+	atomic_t unplugged; /* device has been unplugged or gone away */
 };
 
 #define DRM_SWITCH_POWER_ON 0
@@ -1235,6 +1273,19 @@
 }
 #endif
 
+static inline void drm_device_set_unplugged(struct drm_device *dev)
+{
+	smp_wmb();
+	atomic_set(&dev->unplugged, 1);
+}
+
+static inline int drm_device_is_unplugged(struct drm_device *dev)
+{
+	int ret = atomic_read(&dev->unplugged);
+	smp_rmb();
+	return ret;
+}
+
 /******************************************************************/
 /** \name Internal function definitions */
 /*@{*/
@@ -1264,11 +1315,6 @@
 
 				/* Memory management support (drm_memory.h) */
 #include "drm_memory.h"
-extern void drm_mem_init(void);
-extern int drm_mem_info(char *buf, char **start, off_t offset,
-			int request, int *eof, void *data);
-extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area);
-
 extern void drm_free_agp(DRM_AGP_MEM * handle, int pages);
 extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start);
 extern DRM_AGP_MEM *drm_agp_bind_pages(struct drm_device *dev,
@@ -1383,12 +1429,8 @@
 				/* IRQ support (drm_irq.h) */
 extern int drm_control(struct drm_device *dev, void *data,
 		       struct drm_file *file_priv);
-extern irqreturn_t drm_irq_handler(DRM_IRQ_ARGS);
 extern int drm_irq_install(struct drm_device *dev);
 extern int drm_irq_uninstall(struct drm_device *dev);
-extern void drm_driver_irq_preinstall(struct drm_device *dev);
-extern void drm_driver_irq_postinstall(struct drm_device *dev);
-extern void drm_driver_irq_uninstall(struct drm_device *dev);
 
 extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
 extern int drm_wait_vblank(struct drm_device *dev, void *data,
@@ -1464,6 +1506,7 @@
 
 extern void drm_put_dev(struct drm_device *dev);
 extern int drm_put_minor(struct drm_minor **minor);
+extern void drm_unplug_dev(struct drm_device *dev);
 extern unsigned int drm_debug;
 
 extern unsigned int drm_vblank_offdelay;
@@ -1502,6 +1545,32 @@
 extern int drm_clients_info(struct seq_file *m, void* data);
 extern int drm_gem_name_info(struct seq_file *m, void *data);
 
+
+extern int drm_gem_prime_handle_to_fd(struct drm_device *dev,
+		struct drm_file *file_priv, uint32_t handle, uint32_t flags,
+		int *prime_fd);
+extern int drm_gem_prime_fd_to_handle(struct drm_device *dev,
+		struct drm_file *file_priv, int prime_fd, uint32_t *handle);
+
+extern int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
+					struct drm_file *file_priv);
+extern int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
+					struct drm_file *file_priv);
+
+extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages);
+extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg);
+
+
+void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv);
+void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv);
+int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle);
+int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle);
+void drm_prime_remove_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf);
+
+int drm_prime_add_dma_buf(struct drm_device *dev, struct drm_gem_object *obj);
+int drm_prime_lookup_obj(struct drm_device *dev, struct dma_buf *buf,
+			 struct drm_gem_object **obj);
+
 #if DRM_DEBUG_CODE
 extern int drm_vma_info(struct seq_file *m, void *data);
 #endif
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 4cd4be2..e250eda 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -121,7 +121,7 @@
 	char name[DRM_DISPLAY_MODE_LEN];
 
 	enum drm_mode_status status;
-	int type;
+	unsigned int type;
 
 	/* Proposed mode values */
 	int clock;		/* in kHz */
@@ -257,7 +257,7 @@
 	struct drm_mode_object base;
 	struct list_head head;
 	unsigned int length;
-	void *data;
+	unsigned char data[];
 };
 
 struct drm_property_enum {
@@ -796,6 +796,9 @@
 	struct drm_property *scaling_mode_property;
 	struct drm_property *dithering_mode_property;
 	struct drm_property *dirty_info_property;
+
+	/* dumb ioctl parameters */
+	uint32_t preferred_depth, prefer_shadow;
 };
 
 #define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
@@ -807,23 +810,29 @@
 #define obj_to_blob(x) container_of(x, struct drm_property_blob, base)
 #define obj_to_plane(x) container_of(x, struct drm_plane, base)
 
+struct drm_prop_enum_list {
+	int type;
+	char *name;
+};
 
-extern void drm_crtc_init(struct drm_device *dev,
-			  struct drm_crtc *crtc,
-			  const struct drm_crtc_funcs *funcs);
+extern int drm_crtc_init(struct drm_device *dev,
+			 struct drm_crtc *crtc,
+			 const struct drm_crtc_funcs *funcs);
 extern void drm_crtc_cleanup(struct drm_crtc *crtc);
 
-extern void drm_connector_init(struct drm_device *dev,
-			    struct drm_connector *connector,
-			    const struct drm_connector_funcs *funcs,
-			    int connector_type);
+extern int drm_connector_init(struct drm_device *dev,
+			      struct drm_connector *connector,
+			      const struct drm_connector_funcs *funcs,
+			      int connector_type);
 
 extern void drm_connector_cleanup(struct drm_connector *connector);
+/* helper to unplug all connectors from sysfs for device */
+extern void drm_connector_unplug_all(struct drm_device *dev);
 
-extern void drm_encoder_init(struct drm_device *dev,
-			     struct drm_encoder *encoder,
-			     const struct drm_encoder_funcs *funcs,
-			     int encoder_type);
+extern int drm_encoder_init(struct drm_device *dev,
+			    struct drm_encoder *encoder,
+			    const struct drm_encoder_funcs *funcs,
+			    int encoder_type);
 
 extern int drm_plane_init(struct drm_device *dev,
 			  struct drm_plane *plane,
@@ -848,6 +857,7 @@
 extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
 extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode);
 extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode);
+extern void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src);
 extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
 						   const struct drm_display_mode *mode);
 extern void drm_mode_debug_printmodeline(struct drm_display_mode *mode);
@@ -862,7 +872,7 @@
 /* for us by fb module */
 extern int drm_mode_attachmode_crtc(struct drm_device *dev,
 				    struct drm_crtc *crtc,
-				    struct drm_display_mode *mode);
+				    const struct drm_display_mode *mode);
 extern int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode);
 
 extern struct drm_display_mode *drm_mode_create(struct drm_device *dev);
@@ -904,6 +914,13 @@
 				      struct drm_property *property, uint64_t init_val);
 extern struct drm_property *drm_property_create(struct drm_device *dev, int flags,
 						const char *name, int num_values);
+extern struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
+					 const char *name,
+					 const struct drm_prop_enum_list *props,
+					 int num_values);
+struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
+					 const char *name,
+					 uint64_t min, uint64_t max);
 extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
 extern int drm_property_add_enum(struct drm_property *property, int index,
 				 uint64_t value, const char *name);
@@ -919,7 +936,7 @@
 					     struct drm_encoder *encoder);
 extern void drm_mode_connector_detach_encoder(struct drm_connector *connector,
 					   struct drm_encoder *encoder);
-extern bool drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
+extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
 					 int gamma_size);
 extern struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
 		uint32_t id, uint32_t type);
@@ -995,6 +1012,7 @@
 				int hdisplay, int vdisplay);
 
 extern int drm_edid_header_is_valid(const u8 *raw_edid);
+extern bool drm_edid_block_valid(u8 *raw_edid);
 extern bool drm_edid_is_valid(struct edid *edid);
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
 					   int hsize, int vsize, int fresh);
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 74ce916..bcb9a66 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -238,5 +238,6 @@
 		      struct drm_display_mode *mode);
 struct drm_connector *drm_select_eld(struct drm_encoder *encoder,
 				     struct drm_display_mode *mode);
+int drm_load_edid_firmware(struct drm_connector *connector);
 
 #endif /* __DRM_EDID_H__ */
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 6e3076a..5120b01 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -35,7 +35,6 @@
 #include <linux/kgdb.h>
 
 struct drm_fb_helper_crtc {
-	uint32_t crtc_id;
 	struct drm_mode_set mode_set;
 	struct drm_display_mode *desired_mode;
 };
@@ -74,7 +73,6 @@
 	int connector_count;
 	struct drm_fb_helper_connector **connector_info;
 	struct drm_fb_helper_funcs *funcs;
-	int conn_limit;
 	struct fb_info *fbdev;
 	u32 pseudo_palette[17];
 	struct list_head kernel_fb_list;
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index 2a2acda..4a0aae3 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -27,6 +27,8 @@
 #ifndef _DRM_MODE_H
 #define _DRM_MODE_H
 
+#include <linux/types.h>
+
 #define DRM_DISPLAY_INFO_LEN	32
 #define DRM_CONNECTOR_NAME_LEN	32
 #define DRM_DISPLAY_MODE_LEN	32
diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h
index 14b6cd0..58d0bda 100644
--- a/include/drm/drm_pciids.h
+++ b/include/drm/drm_pciids.h
@@ -202,11 +202,49 @@
 	{0x1002, 0x6778, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6779, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x677B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6784, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6788, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x678A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6790, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6798, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6799, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x679A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x679E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x679F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6802, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6810, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6818, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6819, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6821, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6823, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6824, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6826, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6827, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6829, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x682D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x682F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x683B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x683D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x683F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6841, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6842, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6843, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6849, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x684C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6858, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6859, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
@@ -512,6 +550,22 @@
 	{0x1002, 0x9807, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x9808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x9809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9904, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9905, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9906, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9907, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9908, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9909, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x990A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x990F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9990, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9991, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9993, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x9994, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0, 0, 0}
 
 #define r128_PCI_IDS \
diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
index 1ed3aae..3963116 100644
--- a/include/drm/exynos_drm.h
+++ b/include/drm/exynos_drm.h
@@ -74,16 +74,37 @@
 	uint64_t mapped;
 };
 
+/**
+ * A structure for user connection request of virtual display.
+ *
+ * @connection: indicate whether doing connetion or not by user.
+ * @extensions: if this value is 1 then the vidi driver would need additional
+ *	128bytes edid data.
+ * @edid: the edid data pointer from user side.
+ */
+struct drm_exynos_vidi_connection {
+	unsigned int connection;
+	unsigned int extensions;
+	uint64_t *edid;
+};
+
 struct drm_exynos_plane_set_zpos {
 	__u32 plane_id;
 	__s32 zpos;
 };
 
+/* memory type definitions. */
+enum e_drm_exynos_gem_mem_type {
+	/* Physically Non-Continuous memory. */
+	EXYNOS_BO_NONCONTIG	= 1 << 0
+};
+
 #define DRM_EXYNOS_GEM_CREATE		0x00
 #define DRM_EXYNOS_GEM_MAP_OFFSET	0x01
 #define DRM_EXYNOS_GEM_MMAP		0x02
 /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
 #define DRM_EXYNOS_PLANE_SET_ZPOS	0x06
+#define DRM_EXYNOS_VIDI_CONNECTION	0x07
 
 #define DRM_IOCTL_EXYNOS_GEM_CREATE		DRM_IOWR(DRM_COMMAND_BASE + \
 		DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create)
@@ -97,6 +118,9 @@
 #define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS	DRM_IOWR(DRM_COMMAND_BASE + \
 		DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos)
 
+#define DRM_IOCTL_EXYNOS_VIDI_CONNECTION	DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection)
+
 #ifdef __KERNEL__
 
 /**
@@ -147,11 +171,13 @@
  * @timing: default video mode for initializing
  * @default_win: default window layer number to be used for UI.
  * @bpp: default bit per pixel.
+ * @is_v13: set if hdmi version 13 is.
  */
 struct exynos_drm_hdmi_pdata {
 	struct fb_videomode		timing;
 	unsigned int			default_win;
 	unsigned int			bpp;
+	unsigned int			is_v13:1;
 };
 
 #endif	/* __KERNEL__ */
diff --git a/include/drm/gma_drm.h b/include/drm/gma_drm.h
index 1136867..884613e 100644
--- a/include/drm/gma_drm.h
+++ b/include/drm/gma_drm.h
@@ -83,9 +83,9 @@
 #define DRM_GMA_GAMMA		0x04		/* Set gamma table */
 #define DRM_GMA_ADB		0x05		/* Get backlight */
 #define DRM_GMA_DPST_BL		0x06		/* Set backlight */
-#define DRM_GMA_GET_PIPE_FROM_CRTC_ID 0x1	/* CRTC to physical pipe# */
 #define DRM_GMA_MODE_OPERATION	0x07		/* Mode validation/DC set */
 #define 	PSB_MODE_OPERATION_MODE_VALID	0x01
+#define DRM_GMA_GET_PIPE_FROM_CRTC_ID	0x08	/* CRTC to physical pipe# */
 
 
 #endif
diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h
index 924f6a4..da929bb 100644
--- a/include/drm/i915_drm.h
+++ b/include/drm/i915_drm.h
@@ -296,6 +296,7 @@
 #define I915_PARAM_HAS_EXEC_CONSTANTS	 14
 #define I915_PARAM_HAS_RELAXED_DELTA	 15
 #define I915_PARAM_HAS_GEN7_SOL_RESET	 16
+#define I915_PARAM_HAS_LLC     	 17
 
 typedef struct drm_i915_getparam {
 	int param;
diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h
index b174620..923afb5 100644
--- a/include/drm/intel-gtt.h
+++ b/include/drm/intel-gtt.h
@@ -15,6 +15,10 @@
 	unsigned int needs_dmar : 1;
 	/* Whether we idle the gpu before mapping/unmapping */
 	unsigned int do_idle_maps : 1;
+	/* Share the scratch page dma with ppgtts. */
+	dma_addr_t scratch_page_dma;
+	/* for ppgtt PDE access */
+	u32 __iomem *gtt;
 } *intel_gtt_get(void);
 
 void intel_gtt_chipset_flush(void);
@@ -40,4 +44,8 @@
 /* flag for GFDT type */
 #define AGP_USER_CACHED_MEMORY_GFDT (1 << 3)
 
+#ifdef CONFIG_INTEL_IOMMU
+extern int intel_iommu_gfx_mapped;
+#endif
+
 #endif
diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h
index b55da40..7c491b4 100644
--- a/include/drm/radeon_drm.h
+++ b/include/drm/radeon_drm.h
@@ -804,13 +804,23 @@
 	uint32_t	flags;
 };
 
-#define RADEON_TILING_MACRO       0x1
-#define RADEON_TILING_MICRO       0x2
-#define RADEON_TILING_SWAP_16BIT  0x4
-#define RADEON_TILING_SWAP_32BIT  0x8
-#define RADEON_TILING_SURFACE     0x10 /* this object requires a surface
-					* when mapped - i.e. front buffer */
-#define RADEON_TILING_MICRO_SQUARE 0x20
+#define RADEON_TILING_MACRO				0x1
+#define RADEON_TILING_MICRO				0x2
+#define RADEON_TILING_SWAP_16BIT			0x4
+#define RADEON_TILING_SWAP_32BIT			0x8
+/* this object requires a surface when mapped - i.e. front buffer */
+#define RADEON_TILING_SURFACE				0x10
+#define RADEON_TILING_MICRO_SQUARE			0x20
+#define RADEON_TILING_EG_BANKW_SHIFT			8
+#define RADEON_TILING_EG_BANKW_MASK			0xf
+#define RADEON_TILING_EG_BANKH_SHIFT			12
+#define RADEON_TILING_EG_BANKH_MASK			0xf
+#define RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT	16
+#define RADEON_TILING_EG_MACRO_TILE_ASPECT_MASK		0xf
+#define RADEON_TILING_EG_TILE_SPLIT_SHIFT		24
+#define RADEON_TILING_EG_TILE_SPLIT_MASK		0xf
+#define RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT	28
+#define RADEON_TILING_EG_STENCIL_TILE_SPLIT_MASK	0xf
 
 struct drm_radeon_gem_set_tiling {
 	uint32_t	handle;
@@ -898,6 +908,7 @@
 #define RADEON_CHUNK_ID_RELOCS	0x01
 #define RADEON_CHUNK_ID_IB	0x02
 #define RADEON_CHUNK_ID_FLAGS	0x03
+#define RADEON_CHUNK_ID_CONST_IB	0x04
 
 /* The first dword of RADEON_CHUNK_ID_FLAGS is a uint32 of these flags: */
 #define RADEON_CS_KEEP_TILING_FLAGS 0x01
@@ -952,6 +963,8 @@
 #define RADEON_INFO_VA_START		0x0e
 /* maximum size of ib using the virtual memory cs */
 #define RADEON_INFO_IB_VM_MAX_SIZE	0x0f
+/* max pipes - needed for compute shaders */
+#define RADEON_INFO_MAX_PIPES		0x10
 
 struct drm_radeon_info {
 	uint32_t		request;
diff --git a/include/drm/ttm/ttm_memory.h b/include/drm/ttm/ttm_memory.h
index 26c1f78..d6d1da4 100644
--- a/include/drm/ttm/ttm_memory.h
+++ b/include/drm/ttm/ttm_memory.h
@@ -30,6 +30,7 @@
 
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
+#include <linux/bug.h>
 #include <linux/wait.h>
 #include <linux/errno.h>
 #include <linux/kobject.h>
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index a255553..3c9b616 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -3,6 +3,7 @@
 header-y += caif/
 header-y += dvb/
 header-y += hdlc/
+header-y += hsi/
 header-y += isdn/
 header-y += mmc/
 header-y += nfsd/
@@ -120,7 +121,6 @@
 header-y += errqueue.h
 header-y += ethtool.h
 header-y += eventpoll.h
-header-y += ext2_fs.h
 header-y += fadvise.h
 header-y += falloc.h
 header-y += fanotify.h
@@ -357,6 +357,7 @@
 header-y += swab.h
 header-y += synclink.h
 header-y += sysctl.h
+header-y += sysinfo.h
 header-y += taskstats.h
 header-y += tcp.h
 header-y += telephony.h
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 3f96866..f421dd8 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -151,6 +151,7 @@
 extern int ec_transaction(u8 command,
                           const u8 *wdata, unsigned wdata_len,
                           u8 *rdata, unsigned rdata_len);
+extern acpi_handle ec_get_handle(void);
 
 #if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
 
@@ -371,4 +372,14 @@
 
 #endif	/* !CONFIG_ACPI */
 
+#ifdef CONFIG_ACPI
+void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state,
+			       u32 pm1a_ctrl,  u32 pm1b_ctrl));
+
+acpi_status acpi_os_prepare_sleep(u8 sleep_state,
+				  u32 pm1a_control, u32 pm1b_control);
+#else
+#define acpi_os_set_prepare_sleep(func, pm1a_ctrl, pm1b_ctrl) do { } while (0)
+#endif
+
 #endif	/*_LINUX_ACPI_H*/
diff --git a/include/linux/aio_abi.h b/include/linux/aio_abi.h
index 2c87316..86fa7a7 100644
--- a/include/linux/aio_abi.h
+++ b/include/linux/aio_abi.h
@@ -30,7 +30,7 @@
 #include <linux/types.h>
 #include <asm/byteorder.h>
 
-typedef unsigned long	aio_context_t;
+typedef __kernel_ulong_t aio_context_t;
 
 enum {
 	IOCB_CMD_PREAD = 0,
diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h
index 724c69c..7847e19 100644
--- a/include/linux/amba/bus.h
+++ b/include/linux/amba/bus.h
@@ -60,6 +60,9 @@
 
 int amba_driver_register(struct amba_driver *);
 void amba_driver_unregister(struct amba_driver *);
+struct amba_device *amba_device_alloc(const char *, resource_size_t, size_t);
+void amba_device_put(struct amba_device *);
+int amba_device_add(struct amba_device *, struct resource *);
 int amba_device_register(struct amba_device *, struct resource *);
 void amba_device_unregister(struct amba_device *);
 struct amba_device *amba_find_device(const char *, struct device *, unsigned int, unsigned int);
@@ -89,4 +92,46 @@
 #define amba_manf(d)	AMBA_MANF_BITS((d)->periphid)
 #define amba_part(d)	AMBA_PART_BITS((d)->periphid)
 
+#define __AMBA_DEV(busid, data, mask)				\
+	{							\
+		.coherent_dma_mask = mask,			\
+		.init_name = busid,				\
+		.platform_data = data,				\
+	}
+
+/*
+ * APB devices do not themselves have the ability to address memory,
+ * so DMA masks should be zero (much like USB peripheral devices.)
+ * The DMA controller DMA masks should be used instead (much like
+ * USB host controllers in conventional PCs.)
+ */
+#define AMBA_APB_DEVICE(name, busid, id, base, irqs, data)	\
+struct amba_device name##_device = {				\
+	.dev = __AMBA_DEV(busid, data, 0),			\
+	.res = DEFINE_RES_MEM(base, SZ_4K),			\
+	.irq = irqs,						\
+	.periphid = id,						\
+}
+
+/*
+ * AHB devices are DMA capable, so set their DMA masks
+ */
+#define AMBA_AHB_DEVICE(name, busid, id, base, irqs, data)	\
+struct amba_device name##_device = {				\
+	.dev = __AMBA_DEV(busid, data, ~0ULL),			\
+	.res = DEFINE_RES_MEM(base, SZ_4K),			\
+	.dma_mask = ~0ULL,					\
+	.irq = irqs,						\
+	.periphid = id,						\
+}
+
+/*
+ * module_amba_driver() - Helper macro for drivers that don't do anything
+ * special in module init/exit.  This eliminates a lot of boilerplate.  Each
+ * module may only use this macro once, and calling it replaces module_init()
+ * and module_exit()
+ */
+#define module_amba_driver(__amba_drv) \
+	module_driver(__amba_drv, amba_driver_register, amba_driver_unregister)
+
 #endif
diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h
index 0101e9c..32a89cf 100644
--- a/include/linux/amba/mmci.h
+++ b/include/linux/amba/mmci.h
@@ -6,6 +6,19 @@
 
 #include <linux/mmc/host.h>
 
+
+/*
+ * These defines is places here due to access is needed from machine
+ * configuration files. The ST Micro version does not have ROD and
+ * reuse the voltage registers for direction settings.
+ */
+#define MCI_ST_DATA2DIREN	(1 << 2)
+#define MCI_ST_CMDDIREN		(1 << 3)
+#define MCI_ST_DATA0DIREN	(1 << 4)
+#define MCI_ST_DATA31DIREN	(1 << 5)
+#define MCI_ST_FBCLKEN		(1 << 7)
+#define MCI_ST_DATA74DIREN	(1 << 8)
+
 /* Just some dummy forwarding */
 struct dma_chan;
 
@@ -18,7 +31,8 @@
  * @ocr_mask: available voltages on the 4 pins from the block, this
  * is ignored if a regulator is used, see the MMC_VDD_* masks in
  * mmc/host.h
- * @vdd_handler: a callback function to translate a MMC_VDD_*
+ * @ios_handler: a callback function to act on specfic ios changes,
+ * used for example to control a levelshifter
  * mask into a value to be binary (or set some other custom bits
  * in MMCIPWR) or:ed and written into the MMCIPWR register of the
  * block.  May also control external power based on the power_mode.
@@ -31,6 +45,8 @@
  * @capabilities: the capabilities of the block as implemented in
  * this platform, signify anything MMC_CAP_* from mmc/host.h
  * @capabilities2: more capabilities, MMC_CAP2_* from mmc/host.h
+ * @sigdir: a bit field indicating for what bits in the MMC bus the host
+ * should enable signal direction indication.
  * @dma_filter: function used to select an appropriate RX and TX
  * DMA channel to be used for DMA, if and only if you're deploying the
  * generic DMA engine
@@ -46,14 +62,14 @@
 struct mmci_platform_data {
 	unsigned int f_max;
 	unsigned int ocr_mask;
-	u32 (*vdd_handler)(struct device *, unsigned int vdd,
-			   unsigned char power_mode);
+	int (*ios_handler)(struct device *, struct mmc_ios *);
 	unsigned int (*status)(struct device *);
 	int	gpio_wp;
 	int	gpio_cd;
 	bool	cd_invert;
 	unsigned long capabilities;
 	unsigned long capabilities2;
+	u32 sigdir;
 	bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
 	void *dma_rx_param;
 	void *dma_tx_param;
diff --git a/include/linux/amba/pl022.h b/include/linux/amba/pl022.h
index 3672f40..b8c5112 100644
--- a/include/linux/amba/pl022.h
+++ b/include/linux/amba/pl022.h
@@ -25,8 +25,6 @@
 #ifndef _SSP_PL022_H
 #define _SSP_PL022_H
 
-#include <linux/device.h>
-
 /**
  * whether SSP is in loopback mode or not
  */
diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h
index 033f6aa..e64ce2c 100644
--- a/include/linux/amba/pl08x.h
+++ b/include/linux/amba/pl08x.h
@@ -47,9 +47,6 @@
  * @muxval: a number usually used to poke into some mux regiser to
  * mux in the signal to this channel
  * @cctl_opt: default options for the channel control register
- * @device_fc: Flow Controller Settings for ccfg register. Only valid for slave
- * channels. Fill with 'true' if peripheral should be flow controller. Direction
- * will be selected at Runtime.
  * @addr: source/target address in physical memory for this DMA channel,
  * can be the address of a FIFO register for burst requests for example.
  * This can be left undefined if the PrimeCell API is used for configuring
@@ -68,7 +65,6 @@
 	int max_signal;
 	u32 muxval;
 	u32 cctl;
-	bool device_fc;
 	dma_addr_t addr;
 	bool circular_buffer;
 	bool single;
@@ -176,13 +172,15 @@
  * @runtime_addr: address for RX/TX according to the runtime config
  * @runtime_direction: current direction of this channel according to
  * runtime config
- * @lc: last completed transaction on this channel
  * @pend_list: queued transactions pending on this channel
  * @at: active transaction on this channel
  * @lock: a lock for this channel data
  * @host: a pointer to the host (internal use)
  * @state: whether the channel is idle, paused, running etc
  * @slave: whether this channel is a device (slave) or for memcpy
+ * @device_fc: Flow Controller Settings for ccfg register. Only valid for slave
+ * channels. Fill with 'true' if peripheral should be flow controller. Direction
+ * will be selected at Runtime.
  * @waiting: a TX descriptor on this channel which is waiting for a physical
  * channel to become available
  */
@@ -198,13 +196,13 @@
 	u32 src_cctl;
 	u32 dst_cctl;
 	enum dma_transfer_direction runtime_direction;
-	dma_cookie_t lc;
 	struct list_head pend_list;
 	struct pl08x_txd *at;
 	spinlock_t lock;
 	struct pl08x_driver_data *host;
 	enum pl08x_dma_chan_state state;
 	bool slave;
+	bool device_fc;
 	struct pl08x_txd *waiting;
 };
 
diff --git a/include/linux/amba/pl330.h b/include/linux/amba/pl330.h
index 12e023c..fe93758 100644
--- a/include/linux/amba/pl330.h
+++ b/include/linux/amba/pl330.h
@@ -13,7 +13,6 @@
 #define	__AMBA_PL330_H_
 
 #include <linux/dmaengine.h>
-#include <asm/hardware/pl330.h>
 
 struct dma_pl330_platdata {
 	/*
diff --git a/include/linux/amd-iommu.h b/include/linux/amd-iommu.h
index ef00610..15f6b9e 100644
--- a/include/linux/amd-iommu.h
+++ b/include/linux/amd-iommu.h
@@ -28,7 +28,7 @@
 struct pci_dev;
 
 extern int amd_iommu_detect(void);
-
+extern int amd_iommu_init_hardware(void);
 
 /**
  * amd_iommu_enable_device_erratum() - Enable erratum workaround for device
diff --git a/include/linux/apple_bl.h b/include/linux/apple_bl.h
new file mode 100644
index 0000000..47bedc0
--- /dev/null
+++ b/include/linux/apple_bl.h
@@ -0,0 +1,26 @@
+/*
+ * apple_bl exported symbols
+ */
+
+#ifndef _LINUX_APPLE_BL_H
+#define _LINUX_APPLE_BL_H
+
+#ifdef CONFIG_BACKLIGHT_APPLE
+
+extern int apple_bl_register(void);
+extern void apple_bl_unregister(void);
+
+#else /* !CONFIG_BACKLIGHT_APPLE */
+
+static inline int apple_bl_register(void)
+{
+	return 0;
+}
+
+static inline void apple_bl_unregister(void)
+{
+}
+
+#endif /* !CONFIG_BACKLIGHT_APPLE */
+
+#endif /* _LINUX_APPLE_BL_H */
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
index f4ff882..06fd4bb 100644
--- a/include/linux/atmdev.h
+++ b/include/linux/atmdev.h
@@ -213,10 +213,10 @@
 
 #ifdef __KERNEL__
 
-#include <linux/device.h>
 #include <linux/wait.h> /* wait_queue_head_t */
 #include <linux/time.h> /* struct timeval */
 #include <linux/net.h>
+#include <linux/bug.h>
 #include <linux/skbuff.h> /* struct sk_buff */
 #include <linux/uio.h>
 #include <net/sock.h>
@@ -249,6 +249,7 @@
 	struct k_atm_aal_stats aal5;
 };
 
+struct device;
 
 enum {
 	ATM_VF_ADDR,		/* Address is in use. Set by anybody, cleared
diff --git a/include/linux/atmel_tc.h b/include/linux/atmel_tc.h
index 53ba65e..1d14b1dc 100644
--- a/include/linux/atmel_tc.h
+++ b/include/linux/atmel_tc.h
@@ -34,10 +34,19 @@
 struct clk;
 
 /**
+ * struct atmel_tcb_config - SoC data for a Timer/Counter Block
+ * @counter_width: size in bits of a timer counter register
+ */
+struct atmel_tcb_config {
+	size_t	counter_width;
+};
+
+/**
  * struct atmel_tc - information about a Timer/Counter Block
  * @pdev: physical device
  * @iomem: resource associated with the I/O register
  * @regs: mapping through which the I/O registers can be accessed
+ * @tcb_config: configuration data from SoC
  * @irq: irq for each of the three channels
  * @clk: internal clock source for each of the three channels
  * @node: list node, for tclib internal use
@@ -54,6 +63,7 @@
 	struct platform_device	*pdev;
 	struct resource		*iomem;
 	void __iomem		*regs;
+	struct atmel_tcb_config	*tcb_config;
 	int			irq[3];
 	struct clk		*clk[3];
 	struct list_head	node;
diff --git a/include/linux/atomic.h b/include/linux/atomic.h
index 42b77b5..70cfcb2 100644
--- a/include/linux/atomic.h
+++ b/include/linux/atomic.h
@@ -24,7 +24,9 @@
  * Atomically increments @v by 1, so long as @v is non-zero.
  * Returns non-zero if @v was non-zero, and zero otherwise.
  */
+#ifndef atomic_inc_not_zero
 #define atomic_inc_not_zero(v)		atomic_add_unless((v), 1, 0)
+#endif
 
 /**
  * atomic_inc_not_zero_hint - increment if not null
diff --git a/include/linux/attribute_container.h b/include/linux/attribute_container.h
index c3ab814..896c689 100644
--- a/include/linux/attribute_container.h
+++ b/include/linux/attribute_container.h
@@ -9,10 +9,11 @@
 #ifndef _ATTRIBUTE_CONTAINER_H_
 #define _ATTRIBUTE_CONTAINER_H_
 
-#include <linux/device.h>
 #include <linux/list.h>
 #include <linux/klist.h>
 
+struct device;
+
 struct attribute_container {
 	struct list_head	node;
 	struct klist		containers;
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 9ff7a2c..ed3ef19 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -684,7 +684,7 @@
 						      const char *string);
 extern void		    audit_log_d_path(struct audit_buffer *ab,
 					     const char *prefix,
-					     struct path *path);
+					     const struct path *path);
 extern void		    audit_log_key(struct audit_buffer *ab,
 					  char *key);
 extern void		    audit_log_lost(const char *message);
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 0092102..366422b 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -92,17 +92,17 @@
 	unsigned long min_coredump;	/* minimal dump size */
 };
 
-extern int __register_binfmt(struct linux_binfmt *fmt, int insert);
+extern void __register_binfmt(struct linux_binfmt *fmt, int insert);
 
 /* Registration of default binfmt handlers */
-static inline int register_binfmt(struct linux_binfmt *fmt)
+static inline void register_binfmt(struct linux_binfmt *fmt)
 {
-	return __register_binfmt(fmt, 0);
+	__register_binfmt(fmt, 0);
 }
 /* Same as above, but adds a new binfmt at the top of the list */
-static inline int insert_binfmt(struct linux_binfmt *fmt)
+static inline void insert_binfmt(struct linux_binfmt *fmt)
 {
-	return __register_binfmt(fmt, 1);
+	__register_binfmt(fmt, 1);
 }
 
 extern void unregister_binfmt(struct linux_binfmt *);
diff --git a/include/linux/bio.h b/include/linux/bio.h
index de5422a..4d94eb8 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -23,6 +23,7 @@
 #include <linux/highmem.h>
 #include <linux/mempool.h>
 #include <linux/ioprio.h>
+#include <linux/bug.h>
 
 #ifdef CONFIG_BLOCK
 
diff --git a/include/linux/bit_spinlock.h b/include/linux/bit_spinlock.h
index ac4d9f8..3b5bafc 100644
--- a/include/linux/bit_spinlock.h
+++ b/include/linux/bit_spinlock.h
@@ -4,6 +4,7 @@
 #include <linux/kernel.h>
 #include <linux/preempt.h>
 #include <linux/atomic.h>
+#include <linux/bug.h>
 
 /*
  *  bit-based spin_lock()
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index 94300fe..a3b6b82 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -27,11 +27,22 @@
 	     (bit) = find_next_bit((addr), (size), (bit) + 1))
 
 /* same as for_each_set_bit() but use bit as value to start with */
-#define for_each_set_bit_cont(bit, addr, size) \
+#define for_each_set_bit_from(bit, addr, size) \
 	for ((bit) = find_next_bit((addr), (size), (bit));	\
 	     (bit) < (size);					\
 	     (bit) = find_next_bit((addr), (size), (bit) + 1))
 
+#define for_each_clear_bit(bit, addr, size) \
+	for ((bit) = find_first_zero_bit((addr), (size));	\
+	     (bit) < (size);					\
+	     (bit) = find_next_zero_bit((addr), (size), (bit) + 1))
+
+/* same as for_each_clear_bit() but use bit as value to start with */
+#define for_each_clear_bit_from(bit, addr, size) \
+	for ((bit) = find_next_zero_bit((addr), (size), (bit));	\
+	     (bit) < (size);					\
+	     (bit) = find_next_zero_bit((addr), (size), (bit) + 1))
+
 static __inline__ int get_bitmask_order(unsigned int count)
 {
 	int order;
diff --git a/include/linux/bug.h b/include/linux/bug.h
index d276b55..72961c3 100644
--- a/include/linux/bug.h
+++ b/include/linux/bug.h
@@ -11,6 +11,67 @@
 
 struct pt_regs;
 
+#ifdef __CHECKER__
+#define BUILD_BUG_ON_NOT_POWER_OF_2(n)
+#define BUILD_BUG_ON_ZERO(e) (0)
+#define BUILD_BUG_ON_NULL(e) ((void*)0)
+#define BUILD_BUG_ON(condition)
+#define BUILD_BUG() (0)
+#else /* __CHECKER__ */
+
+/* Force a compilation error if a constant expression is not a power of 2 */
+#define BUILD_BUG_ON_NOT_POWER_OF_2(n)			\
+	BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
+
+/* Force a compilation error if condition is true, but also produce a
+   result (of value 0 and type size_t), so the expression can be used
+   e.g. in a structure initializer (or where-ever else comma expressions
+   aren't permitted). */
+#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
+#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
+
+/**
+ * BUILD_BUG_ON - break compile if a condition is true.
+ * @condition: the condition which the compiler should know is false.
+ *
+ * If you have some code which relies on certain constants being equal, or
+ * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
+ * detect if someone changes it.
+ *
+ * The implementation uses gcc's reluctance to create a negative array, but
+ * gcc (as of 4.4) only emits that error for obvious cases (eg. not arguments
+ * to inline functions).  So as a fallback we use the optimizer; if it can't
+ * prove the condition is false, it will cause a link error on the undefined
+ * "__build_bug_on_failed".  This error message can be harder to track down
+ * though, hence the two different methods.
+ */
+#ifndef __OPTIMIZE__
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+#else
+extern int __build_bug_on_failed;
+#define BUILD_BUG_ON(condition)					\
+	do {							\
+		((void)sizeof(char[1 - 2*!!(condition)]));	\
+		if (condition) __build_bug_on_failed = 1;	\
+	} while(0)
+#endif
+
+/**
+ * BUILD_BUG - break compile if used.
+ *
+ * If you have some code that you expect the compiler to eliminate at
+ * build time, you should use BUILD_BUG to detect if it is
+ * unexpectedly used.
+ */
+#define BUILD_BUG()						\
+	do {							\
+		extern void __build_bug_failed(void)		\
+			__linktime_error("BUILD_BUG failed");	\
+		__build_bug_failed();				\
+	} while (0)
+
+#endif	/* __CHECKER__ */
+
 #ifdef CONFIG_GENERIC_BUG
 #include <asm-generic/bug.h>
 
diff --git a/include/linux/c2port.h b/include/linux/c2port.h
index a2f7d74..4efabcb 100644
--- a/include/linux/c2port.h
+++ b/include/linux/c2port.h
@@ -9,11 +9,12 @@
  * the Free Software Foundation
  */
 
-#include <linux/device.h>
 #include <linux/kmemcheck.h>
 
 #define C2PORT_NAME_LEN			32
 
+struct device;
+
 /*
  * C2 port basic structs
  */
diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h
index 7c48029..dfd7f18 100644
--- a/include/linux/cdrom.h
+++ b/include/linux/cdrom.h
@@ -910,7 +910,6 @@
 
 #ifdef __KERNEL__
 #include <linux/fs.h>		/* not really needed, later.. */
-#include <linux/device.h>
 #include <linux/list.h>
 
 struct packet_command
diff --git a/include/linux/ceph/decode.h b/include/linux/ceph/decode.h
index c5b6939..220ae21 100644
--- a/include/linux/ceph/decode.h
+++ b/include/linux/ceph/decode.h
@@ -1,8 +1,9 @@
 #ifndef __CEPH_DECODE_H
 #define __CEPH_DECODE_H
 
-#include <asm/unaligned.h>
+#include <linux/bug.h>
 #include <linux/time.h>
+#include <asm/unaligned.h>
 
 #include "types.h"
 
diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h
index 95bd850..e71d683 100644
--- a/include/linux/ceph/libceph.h
+++ b/include/linux/ceph/libceph.h
@@ -7,6 +7,7 @@
 #include <linux/backing-dev.h>
 #include <linux/completion.h>
 #include <linux/exportfs.h>
+#include <linux/bug.h>
 #include <linux/fs.h>
 #include <linux/mempool.h>
 #include <linux/pagemap.h>
@@ -207,7 +208,7 @@
 extern struct kmem_cache *ceph_dentry_cachep;
 extern struct kmem_cache *ceph_file_cachep;
 
-extern int ceph_parse_options(struct ceph_options **popt, char *options,
+extern struct ceph_options *ceph_parse_options(char *options,
 			      const char *dev_name, const char *dev_name_end,
 			      int (*parse_extra_token)(char *c, void *private),
 			      void *private);
diff --git a/include/linux/ceph/mdsmap.h b/include/linux/ceph/mdsmap.h
index 4c5cb08..9935fac 100644
--- a/include/linux/ceph/mdsmap.h
+++ b/include/linux/ceph/mdsmap.h
@@ -1,6 +1,7 @@
 #ifndef _FS_CEPH_MDSMAP_H
 #define _FS_CEPH_MDSMAP_H
 
+#include <linux/bug.h>
 #include "types.h"
 
 /*
diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h
index ffbeb2c..3bff047 100644
--- a/include/linux/ceph/messenger.h
+++ b/include/linux/ceph/messenger.h
@@ -14,8 +14,6 @@
 struct ceph_msg;
 struct ceph_connection;
 
-extern struct workqueue_struct *ceph_msgr_wq;       /* receive work queue */
-
 /*
  * Ceph defines these callbacks for handling connection events.
  */
@@ -54,7 +52,6 @@
 struct ceph_messenger {
 	struct ceph_entity_inst inst;    /* my name+address */
 	struct ceph_entity_addr my_enc_addr;
-	struct page *zero_page;          /* used in certain error cases */
 
 	bool nocrc;
 
@@ -101,7 +98,7 @@
 struct ceph_msg_pos {
 	int page, page_pos;  /* which page; offset in page */
 	int data_pos;        /* offset in data payload */
-	int did_page_crc;    /* true if we've calculated crc for current page */
+	bool did_page_crc;   /* true if we've calculated crc for current page */
 };
 
 /* ceph connection fault delay defaults, for exponential backoff */
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 501adb1..5a85b34 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -498,7 +498,7 @@
 	struct list_head sibling;
 	/* used when use_id == true */
 	struct idr idr;
-	rwlock_t id_lock;
+	spinlock_t id_lock;
 
 	/* should be defined only by modular subsystems */
 	struct module *module;
diff --git a/include/linux/cleancache.h b/include/linux/cleancache.h
index 04ffb2e..42e55de 100644
--- a/include/linux/cleancache.h
+++ b/include/linux/cleancache.h
@@ -28,9 +28,9 @@
 			pgoff_t, struct page *);
 	void (*put_page)(int, struct cleancache_filekey,
 			pgoff_t, struct page *);
-	void (*flush_page)(int, struct cleancache_filekey, pgoff_t);
-	void (*flush_inode)(int, struct cleancache_filekey);
-	void (*flush_fs)(int);
+	void (*invalidate_page)(int, struct cleancache_filekey, pgoff_t);
+	void (*invalidate_inode)(int, struct cleancache_filekey);
+	void (*invalidate_fs)(int);
 };
 
 extern struct cleancache_ops
@@ -39,9 +39,9 @@
 extern void __cleancache_init_shared_fs(char *, struct super_block *);
 extern int  __cleancache_get_page(struct page *);
 extern void __cleancache_put_page(struct page *);
-extern void __cleancache_flush_page(struct address_space *, struct page *);
-extern void __cleancache_flush_inode(struct address_space *);
-extern void __cleancache_flush_fs(struct super_block *);
+extern void __cleancache_invalidate_page(struct address_space *, struct page *);
+extern void __cleancache_invalidate_inode(struct address_space *);
+extern void __cleancache_invalidate_fs(struct super_block *);
 extern int cleancache_enabled;
 
 #ifdef CONFIG_CLEANCACHE
@@ -99,24 +99,24 @@
 		__cleancache_put_page(page);
 }
 
-static inline void cleancache_flush_page(struct address_space *mapping,
+static inline void cleancache_invalidate_page(struct address_space *mapping,
 					struct page *page)
 {
 	/* careful... page->mapping is NULL sometimes when this is called */
 	if (cleancache_enabled && cleancache_fs_enabled_mapping(mapping))
-		__cleancache_flush_page(mapping, page);
+		__cleancache_invalidate_page(mapping, page);
 }
 
-static inline void cleancache_flush_inode(struct address_space *mapping)
+static inline void cleancache_invalidate_inode(struct address_space *mapping)
 {
 	if (cleancache_enabled && cleancache_fs_enabled_mapping(mapping))
-		__cleancache_flush_inode(mapping);
+		__cleancache_invalidate_inode(mapping);
 }
 
-static inline void cleancache_flush_fs(struct super_block *sb)
+static inline void cleancache_invalidate_fs(struct super_block *sb)
 {
 	if (cleancache_enabled)
-		__cleancache_flush_fs(sb);
+		__cleancache_invalidate_fs(sb);
 }
 
 #endif /* _LINUX_CLEANCACHE_H */
diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
new file mode 100644
index 0000000..5e4312b
--- /dev/null
+++ b/include/linux/clk-private.h
@@ -0,0 +1,196 @@
+/*
+ *  linux/include/linux/clk-private.h
+ *
+ *  Copyright (c) 2010-2011 Jeremy Kerr <jeremy.kerr@canonical.com>
+ *  Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LINUX_CLK_PRIVATE_H
+#define __LINUX_CLK_PRIVATE_H
+
+#include <linux/clk-provider.h>
+#include <linux/list.h>
+
+/*
+ * WARNING: Do not include clk-private.h from any file that implements struct
+ * clk_ops.  Doing so is a layering violation!
+ *
+ * This header exists only to allow for statically initialized clock data.  Any
+ * static clock data must be defined in a separate file from the logic that
+ * implements the clock operations for that same data.
+ */
+
+#ifdef CONFIG_COMMON_CLK
+
+struct clk {
+	const char		*name;
+	const struct clk_ops	*ops;
+	struct clk_hw		*hw;
+	struct clk		*parent;
+	char			**parent_names;
+	struct clk		**parents;
+	u8			num_parents;
+	unsigned long		rate;
+	unsigned long		new_rate;
+	unsigned long		flags;
+	unsigned int		enable_count;
+	unsigned int		prepare_count;
+	struct hlist_head	children;
+	struct hlist_node	child_node;
+	unsigned int		notifier_count;
+#ifdef CONFIG_COMMON_CLK_DEBUG
+	struct dentry		*dentry;
+#endif
+};
+
+/*
+ * DOC: Basic clock implementations common to many platforms
+ *
+ * Each basic clock hardware type is comprised of a structure describing the
+ * clock hardware, implementations of the relevant callbacks in struct clk_ops,
+ * unique flags for that hardware type, a registration function and an
+ * alternative macro for static initialization
+ */
+
+extern struct clk_ops clk_fixed_rate_ops;
+
+#define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate,		\
+				_fixed_rate_flags)		\
+	static struct clk _name;				\
+	static char *_name##_parent_names[] = {};		\
+	static struct clk_fixed_rate _name##_hw = {		\
+		.hw = {						\
+			.clk = &_name,				\
+		},						\
+		.fixed_rate = _rate,				\
+		.flags = _fixed_rate_flags,			\
+	};							\
+	static struct clk _name = {				\
+		.name = #_name,					\
+		.ops = &clk_fixed_rate_ops,			\
+		.hw = &_name##_hw.hw,				\
+		.parent_names = _name##_parent_names,		\
+		.num_parents =					\
+			ARRAY_SIZE(_name##_parent_names),	\
+		.flags = _flags,				\
+	};
+
+extern struct clk_ops clk_gate_ops;
+
+#define DEFINE_CLK_GATE(_name, _parent_name, _parent_ptr,	\
+				_flags, _reg, _bit_idx,		\
+				_gate_flags, _lock)		\
+	static struct clk _name;				\
+	static char *_name##_parent_names[] = {			\
+		_parent_name,					\
+	};							\
+	static struct clk *_name##_parents[] = {		\
+		_parent_ptr,					\
+	};							\
+	static struct clk_gate _name##_hw = {			\
+		.hw = {						\
+			.clk = &_name,				\
+		},						\
+		.reg = _reg,					\
+		.bit_idx = _bit_idx,				\
+		.flags = _gate_flags,				\
+		.lock = _lock,					\
+	};							\
+	static struct clk _name = {				\
+		.name = #_name,					\
+		.ops = &clk_gate_ops,				\
+		.hw = &_name##_hw.hw,				\
+		.parent_names = _name##_parent_names,		\
+		.num_parents =					\
+			ARRAY_SIZE(_name##_parent_names),	\
+		.parents = _name##_parents,			\
+		.flags = _flags,				\
+	};
+
+extern struct clk_ops clk_divider_ops;
+
+#define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr,	\
+				_flags, _reg, _shift, _width,	\
+				_divider_flags, _lock)		\
+	static struct clk _name;				\
+	static char *_name##_parent_names[] = {			\
+		_parent_name,					\
+	};							\
+	static struct clk *_name##_parents[] = {		\
+		_parent_ptr,					\
+	};							\
+	static struct clk_divider _name##_hw = {		\
+		.hw = {						\
+			.clk = &_name,				\
+		},						\
+		.reg = _reg,					\
+		.shift = _shift,				\
+		.width = _width,				\
+		.flags = _divider_flags,			\
+		.lock = _lock,					\
+	};							\
+	static struct clk _name = {				\
+		.name = #_name,					\
+		.ops = &clk_divider_ops,			\
+		.hw = &_name##_hw.hw,				\
+		.parent_names = _name##_parent_names,		\
+		.num_parents =					\
+			ARRAY_SIZE(_name##_parent_names),	\
+		.parents = _name##_parents,			\
+		.flags = _flags,				\
+	};
+
+extern struct clk_ops clk_mux_ops;
+
+#define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags,	\
+				_reg, _shift, _width,		\
+				_mux_flags, _lock)		\
+	static struct clk _name;				\
+	static struct clk_mux _name##_hw = {			\
+		.hw = {						\
+			.clk = &_name,				\
+		},						\
+		.reg = _reg,					\
+		.shift = _shift,				\
+		.width = _width,				\
+		.flags = _mux_flags,				\
+		.lock = _lock,					\
+	};							\
+	static struct clk _name = {				\
+		.name = #_name,					\
+		.ops = &clk_mux_ops,				\
+		.hw = &_name##_hw.hw,				\
+		.parent_names = _parent_names,			\
+		.num_parents =					\
+			ARRAY_SIZE(_parent_names),		\
+		.parents = _parents,				\
+		.flags = _flags,				\
+	};
+
+/**
+ * __clk_init - initialize the data structures in a struct clk
+ * @dev:	device initializing this clk, placeholder for now
+ * @clk:	clk being initialized
+ *
+ * Initializes the lists in struct clk, queries the hardware for the
+ * parent and rate and sets them both.
+ *
+ * Any struct clk passed into __clk_init must have the following members
+ * populated:
+ * 	.name
+ * 	.ops
+ * 	.hw
+ * 	.parent_names
+ * 	.num_parents
+ * 	.flags
+ *
+ * It is not necessary to call clk_register if __clk_init is used directly with
+ * statically initialized clock data.
+ */
+void __clk_init(struct device *dev, struct clk *clk);
+
+#endif /* CONFIG_COMMON_CLK */
+#endif /* CLK_PRIVATE_H */
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
new file mode 100644
index 0000000..5508897
--- /dev/null
+++ b/include/linux/clk-provider.h
@@ -0,0 +1,300 @@
+/*
+ *  linux/include/linux/clk-provider.h
+ *
+ *  Copyright (c) 2010-2011 Jeremy Kerr <jeremy.kerr@canonical.com>
+ *  Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LINUX_CLK_PROVIDER_H
+#define __LINUX_CLK_PROVIDER_H
+
+#include <linux/clk.h>
+
+#ifdef CONFIG_COMMON_CLK
+
+/**
+ * struct clk_hw - handle for traversing from a struct clk to its corresponding
+ * hardware-specific structure.  struct clk_hw should be declared within struct
+ * clk_foo and then referenced by the struct clk instance that uses struct
+ * clk_foo's clk_ops
+ *
+ * clk: pointer to the struct clk instance that points back to this struct
+ * clk_hw instance
+ */
+struct clk_hw {
+	struct clk *clk;
+};
+
+/*
+ * flags used across common struct clk.  these flags should only affect the
+ * top-level framework.  custom flags for dealing with hardware specifics
+ * belong in struct clk_foo
+ */
+#define CLK_SET_RATE_GATE	BIT(0) /* must be gated across rate change */
+#define CLK_SET_PARENT_GATE	BIT(1) /* must be gated across re-parent */
+#define CLK_SET_RATE_PARENT	BIT(2) /* propagate rate change up one level */
+#define CLK_IGNORE_UNUSED	BIT(3) /* do not gate even if unused */
+#define CLK_IS_ROOT		BIT(4) /* root clk, has no parent */
+
+/**
+ * struct clk_ops -  Callback operations for hardware clocks; these are to
+ * be provided by the clock implementation, and will be called by drivers
+ * through the clk_* api.
+ *
+ * @prepare:	Prepare the clock for enabling. This must not return until
+ * 		the clock is fully prepared, and it's safe to call clk_enable.
+ * 		This callback is intended to allow clock implementations to
+ * 		do any initialisation that may sleep. Called with
+ * 		prepare_lock held.
+ *
+ * @unprepare:	Release the clock from its prepared state. This will typically
+ * 		undo any work done in the @prepare callback. Called with
+ * 		prepare_lock held.
+ *
+ * @enable:	Enable the clock atomically. This must not return until the
+ * 		clock is generating a valid clock signal, usable by consumer
+ * 		devices. Called with enable_lock held. This function must not
+ * 		sleep.
+ *
+ * @disable:	Disable the clock atomically. Called with enable_lock held.
+ * 		This function must not sleep.
+ *
+ * @recalc_rate	Recalculate the rate of this clock, by quering hardware.  The
+ * 		parent rate is an input parameter.  It is up to the caller to
+ * 		insure that the prepare_mutex is held across this call.
+ * 		Returns the calculated rate.  Optional, but recommended - if
+ * 		this op is not set then clock rate will be initialized to 0.
+ *
+ * @round_rate:	Given a target rate as input, returns the closest rate actually
+ * 		supported by the clock.
+ *
+ * @get_parent:	Queries the hardware to determine the parent of a clock.  The
+ * 		return value is a u8 which specifies the index corresponding to
+ * 		the parent clock.  This index can be applied to either the
+ * 		.parent_names or .parents arrays.  In short, this function
+ * 		translates the parent value read from hardware into an array
+ * 		index.  Currently only called when the clock is initialized by
+ * 		__clk_init.  This callback is mandatory for clocks with
+ * 		multiple parents.  It is optional (and unnecessary) for clocks
+ * 		with 0 or 1 parents.
+ *
+ * @set_parent:	Change the input source of this clock; for clocks with multiple
+ * 		possible parents specify a new parent by passing in the index
+ * 		as a u8 corresponding to the parent in either the .parent_names
+ * 		or .parents arrays.  This function in affect translates an
+ * 		array index into the value programmed into the hardware.
+ * 		Returns 0 on success, -EERROR otherwise.
+ *
+ * @set_rate:	Change the rate of this clock. If this callback returns
+ * 		CLK_SET_RATE_PARENT, the rate change will be propagated to the
+ * 		parent clock (which may propagate again if the parent clock
+ * 		also sets this flag). The requested rate of the parent is
+ * 		passed back from the callback in the second 'unsigned long *'
+ * 		argument.  Note that it is up to the hardware clock's set_rate
+ * 		implementation to insure that clocks do not run out of spec
+ * 		when propgating the call to set_rate up to the parent.  One way
+ * 		to do this is to gate the clock (via clk_disable and/or
+ * 		clk_unprepare) before calling clk_set_rate, then ungating it
+ * 		afterward.  If your clock also has the CLK_GATE_SET_RATE flag
+ * 		set then this will insure safety.  Returns 0 on success,
+ * 		-EERROR otherwise.
+ *
+ * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
+ * implementations to split any work between atomic (enable) and sleepable
+ * (prepare) contexts.  If enabling a clock requires code that might sleep,
+ * this must be done in clk_prepare.  Clock enable code that will never be
+ * called in a sleepable context may be implement in clk_enable.
+ *
+ * Typically, drivers will call clk_prepare when a clock may be needed later
+ * (eg. when a device is opened), and clk_enable when the clock is actually
+ * required (eg. from an interrupt). Note that clk_prepare MUST have been
+ * called before clk_enable.
+ */
+struct clk_ops {
+	int		(*prepare)(struct clk_hw *hw);
+	void		(*unprepare)(struct clk_hw *hw);
+	int		(*enable)(struct clk_hw *hw);
+	void		(*disable)(struct clk_hw *hw);
+	int		(*is_enabled)(struct clk_hw *hw);
+	unsigned long	(*recalc_rate)(struct clk_hw *hw,
+					unsigned long parent_rate);
+	long		(*round_rate)(struct clk_hw *hw, unsigned long,
+					unsigned long *);
+	int		(*set_parent)(struct clk_hw *hw, u8 index);
+	u8		(*get_parent)(struct clk_hw *hw);
+	int		(*set_rate)(struct clk_hw *hw, unsigned long);
+	void		(*init)(struct clk_hw *hw);
+};
+
+/*
+ * DOC: Basic clock implementations common to many platforms
+ *
+ * Each basic clock hardware type is comprised of a structure describing the
+ * clock hardware, implementations of the relevant callbacks in struct clk_ops,
+ * unique flags for that hardware type, a registration function and an
+ * alternative macro for static initialization
+ */
+
+/**
+ * struct clk_fixed_rate - fixed-rate clock
+ * @hw:		handle between common and hardware-specific interfaces
+ * @fixed_rate:	constant frequency of clock
+ */
+struct clk_fixed_rate {
+	struct		clk_hw hw;
+	unsigned long	fixed_rate;
+	u8		flags;
+};
+
+struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		unsigned long fixed_rate);
+
+/**
+ * struct clk_gate - gating clock
+ *
+ * @hw:		handle between common and hardware-specific interfaces
+ * @reg:	register controlling gate
+ * @bit_idx:	single bit controlling gate
+ * @flags:	hardware-specific flags
+ * @lock:	register lock
+ *
+ * Clock which can gate its output.  Implements .enable & .disable
+ *
+ * Flags:
+ * CLK_GATE_SET_DISABLE - by default this clock sets the bit at bit_idx to
+ * 	enable the clock.  Setting this flag does the opposite: setting the bit
+ * 	disable the clock and clearing it enables the clock
+ */
+struct clk_gate {
+	struct clk_hw hw;
+	void __iomem	*reg;
+	u8		bit_idx;
+	u8		flags;
+	spinlock_t	*lock;
+	char		*parent[1];
+};
+
+#define CLK_GATE_SET_TO_DISABLE		BIT(0)
+
+struct clk *clk_register_gate(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock);
+
+/**
+ * struct clk_divider - adjustable divider clock
+ *
+ * @hw:		handle between common and hardware-specific interfaces
+ * @reg:	register containing the divider
+ * @shift:	shift to the divider bit field
+ * @width:	width of the divider bit field
+ * @lock:	register lock
+ *
+ * Clock with an adjustable divider affecting its output frequency.  Implements
+ * .recalc_rate, .set_rate and .round_rate
+ *
+ * Flags:
+ * CLK_DIVIDER_ONE_BASED - by default the divisor is the value read from the
+ * 	register plus one.  If CLK_DIVIDER_ONE_BASED is set then the divider is
+ * 	the raw value read from the register, with the value of zero considered
+ * 	invalid
+ * CLK_DIVIDER_POWER_OF_TWO - clock divisor is 2 raised to the value read from
+ * 	the hardware register
+ */
+struct clk_divider {
+	struct clk_hw	hw;
+	void __iomem	*reg;
+	u8		shift;
+	u8		width;
+	u8		flags;
+	spinlock_t	*lock;
+	char		*parent[1];
+};
+
+#define CLK_DIVIDER_ONE_BASED		BIT(0)
+#define CLK_DIVIDER_POWER_OF_TWO	BIT(1)
+
+struct clk *clk_register_divider(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags, spinlock_t *lock);
+
+/**
+ * struct clk_mux - multiplexer clock
+ *
+ * @hw:		handle between common and hardware-specific interfaces
+ * @reg:	register controlling multiplexer
+ * @shift:	shift to multiplexer bit field
+ * @width:	width of mutliplexer bit field
+ * @num_clks:	number of parent clocks
+ * @lock:	register lock
+ *
+ * Clock with multiple selectable parents.  Implements .get_parent, .set_parent
+ * and .recalc_rate
+ *
+ * Flags:
+ * CLK_MUX_INDEX_ONE - register index starts at 1, not 0
+ * CLK_MUX_INDEX_BITWISE - register index is a single bit (power of two)
+ */
+struct clk_mux {
+	struct clk_hw	hw;
+	void __iomem	*reg;
+	u8		shift;
+	u8		width;
+	u8		flags;
+	spinlock_t	*lock;
+};
+
+#define CLK_MUX_INDEX_ONE		BIT(0)
+#define CLK_MUX_INDEX_BIT		BIT(1)
+
+struct clk *clk_register_mux(struct device *dev, const char *name,
+		char **parent_names, u8 num_parents, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_mux_flags, spinlock_t *lock);
+
+/**
+ * clk_register - allocate a new clock, register it and return an opaque cookie
+ * @dev: device that is registering this clock
+ * @name: clock name
+ * @ops: operations this clock supports
+ * @hw: link to hardware-specific clock data
+ * @parent_names: array of string names for all possible parents
+ * @num_parents: number of possible parents
+ * @flags: framework-level hints and quirks
+ *
+ * clk_register is the primary interface for populating the clock tree with new
+ * clock nodes.  It returns a pointer to the newly allocated struct clk which
+ * cannot be dereferenced by driver code but may be used in conjuction with the
+ * rest of the clock API.
+ */
+struct clk *clk_register(struct device *dev, const char *name,
+		const struct clk_ops *ops, struct clk_hw *hw,
+		char **parent_names, u8 num_parents, unsigned long flags);
+
+/* helper functions */
+const char *__clk_get_name(struct clk *clk);
+struct clk_hw *__clk_get_hw(struct clk *clk);
+u8 __clk_get_num_parents(struct clk *clk);
+struct clk *__clk_get_parent(struct clk *clk);
+inline int __clk_get_enable_count(struct clk *clk);
+inline int __clk_get_prepare_count(struct clk *clk);
+unsigned long __clk_get_rate(struct clk *clk);
+unsigned long __clk_get_flags(struct clk *clk);
+int __clk_is_enabled(struct clk *clk);
+struct clk *__clk_lookup(const char *name);
+
+/*
+ * FIXME clock api without lock protection
+ */
+int __clk_prepare(struct clk *clk);
+void __clk_unprepare(struct clk *clk);
+void __clk_reparent(struct clk *clk, struct clk *new_parent);
+unsigned long __clk_round_rate(struct clk *clk, unsigned long rate);
+
+#endif /* CONFIG_COMMON_CLK */
+#endif /* CLK_PROVIDER_H */
diff --git a/include/linux/clk.h b/include/linux/clk.h
index b9d46fa..b025272 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
  *
  * 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
@@ -12,19 +13,76 @@
 #define __LINUX_CLK_H
 
 #include <linux/kernel.h>
+#include <linux/notifier.h>
 
 struct device;
 
-/*
- * The base API.
- */
-
-
-/*
- * struct clk - an machine class defined object / cookie.
- */
 struct clk;
 
+#ifdef CONFIG_COMMON_CLK
+
+/**
+ * DOC: clk notifier callback types
+ *
+ * PRE_RATE_CHANGE - called immediately before the clk rate is changed,
+ *     to indicate that the rate change will proceed.  Drivers must
+ *     immediately terminate any operations that will be affected by the
+ *     rate change.  Callbacks may either return NOTIFY_DONE or
+ *     NOTIFY_STOP.
+ *
+ * ABORT_RATE_CHANGE: called if the rate change failed for some reason
+ *     after PRE_RATE_CHANGE.  In this case, all registered notifiers on
+ *     the clk will be called with ABORT_RATE_CHANGE. Callbacks must
+ *     always return NOTIFY_DONE.
+ *
+ * POST_RATE_CHANGE - called after the clk rate change has successfully
+ *     completed.  Callbacks must always return NOTIFY_DONE.
+ *
+ */
+#define PRE_RATE_CHANGE			BIT(0)
+#define POST_RATE_CHANGE		BIT(1)
+#define ABORT_RATE_CHANGE		BIT(2)
+
+/**
+ * struct clk_notifier - associate a clk with a notifier
+ * @clk: struct clk * to associate the notifier with
+ * @notifier_head: a blocking_notifier_head for this clk
+ * @node: linked list pointers
+ *
+ * A list of struct clk_notifier is maintained by the notifier code.
+ * An entry is created whenever code registers the first notifier on a
+ * particular @clk.  Future notifiers on that @clk are added to the
+ * @notifier_head.
+ */
+struct clk_notifier {
+	struct clk			*clk;
+	struct srcu_notifier_head	notifier_head;
+	struct list_head		node;
+};
+
+/**
+ * struct clk_notifier_data - rate data to pass to the notifier callback
+ * @clk: struct clk * being changed
+ * @old_rate: previous rate of this clk
+ * @new_rate: new rate of this clk
+ *
+ * For a pre-notifier, old_rate is the clk's rate before this rate
+ * change, and new_rate is what the rate will be in the future.  For a
+ * post-notifier, old_rate and new_rate are both set to the clk's
+ * current rate (this was done to optimize the implementation).
+ */
+struct clk_notifier_data {
+	struct clk		*clk;
+	unsigned long		old_rate;
+	unsigned long		new_rate;
+};
+
+int clk_notifier_register(struct clk *clk, struct notifier_block *nb);
+
+int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
+
+#endif /* !CONFIG_COMMON_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
diff --git a/include/linux/cnt32_to_63.h b/include/linux/cnt32_to_63.h
index e3d8bf2..aa629bc 100644
--- a/include/linux/cnt32_to_63.h
+++ b/include/linux/cnt32_to_63.h
@@ -16,7 +16,6 @@
 #include <linux/compiler.h>
 #include <linux/types.h>
 #include <asm/byteorder.h>
-#include <asm/system.h>
 
 /* this is used only to give gcc a clue about good code generation */
 union cnt32_to_63 {
diff --git a/include/linux/compaction.h b/include/linux/compaction.h
index bb2bbdb..51a90b7 100644
--- a/include/linux/compaction.h
+++ b/include/linux/compaction.h
@@ -23,6 +23,7 @@
 extern unsigned long try_to_compact_pages(struct zonelist *zonelist,
 			int order, gfp_t gfp_mask, nodemask_t *mask,
 			bool sync);
+extern int compact_pgdat(pg_data_t *pgdat, int order);
 extern unsigned long compaction_suitable(struct zone *zone, int order);
 
 /* Do not skip compaction more than 64 times */
@@ -33,20 +34,26 @@
  * allocation success. 1 << compact_defer_limit compactions are skipped up
  * to a limit of 1 << COMPACT_MAX_DEFER_SHIFT
  */
-static inline void defer_compaction(struct zone *zone)
+static inline void defer_compaction(struct zone *zone, int order)
 {
 	zone->compact_considered = 0;
 	zone->compact_defer_shift++;
 
+	if (order < zone->compact_order_failed)
+		zone->compact_order_failed = order;
+
 	if (zone->compact_defer_shift > COMPACT_MAX_DEFER_SHIFT)
 		zone->compact_defer_shift = COMPACT_MAX_DEFER_SHIFT;
 }
 
 /* Returns true if compaction should be skipped this time */
-static inline bool compaction_deferred(struct zone *zone)
+static inline bool compaction_deferred(struct zone *zone, int order)
 {
 	unsigned long defer_limit = 1UL << zone->compact_defer_shift;
 
+	if (order < zone->compact_order_failed)
+		return false;
+
 	/* Avoid possible overflow */
 	if (++zone->compact_considered > defer_limit)
 		zone->compact_considered = defer_limit;
@@ -62,16 +69,21 @@
 	return COMPACT_CONTINUE;
 }
 
+static inline int compact_pgdat(pg_data_t *pgdat, int order)
+{
+	return COMPACT_CONTINUE;
+}
+
 static inline unsigned long compaction_suitable(struct zone *zone, int order)
 {
 	return COMPACT_SKIPPED;
 }
 
-static inline void defer_compaction(struct zone *zone)
+static inline void defer_compaction(struct zone *zone, int order)
 {
 }
 
-static inline bool compaction_deferred(struct zone *zone)
+static inline bool compaction_deferred(struct zone *zone, int order)
 {
 	return 1;
 }
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 7e05fce..5d46217 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -19,6 +19,10 @@
 #include <asm/siginfo.h>
 #include <asm/signal.h>
 
+#ifndef COMPAT_USE_64BIT_TIME
+#define COMPAT_USE_64BIT_TIME 0
+#endif
+
 #define compat_jiffies_to_clock_t(x)	\
 		(((unsigned long)(x) * COMPAT_USER_HZ) / HZ)
 
@@ -83,10 +87,26 @@
 	compat_sigset_word	sig[_COMPAT_NSIG_WORDS];
 } compat_sigset_t;
 
+/*
+ * These functions operate strictly on struct compat_time*
+ */
 extern int get_compat_timespec(struct timespec *,
 			       const struct compat_timespec __user *);
 extern int put_compat_timespec(const struct timespec *,
 			       struct compat_timespec __user *);
+extern int get_compat_timeval(struct timeval *,
+			      const struct compat_timeval __user *);
+extern int put_compat_timeval(const struct timeval *,
+			      struct compat_timeval __user *);
+/*
+ * These functions operate on 32- or 64-bit specs depending on
+ * COMPAT_USE_64BIT_TIME, hence the void user pointer arguments and the
+ * naming as compat_get/put_ rather than get/put_compat_.
+ */
+extern int compat_get_timespec(struct timespec *, const void __user *);
+extern int compat_put_timespec(const struct timespec *, void __user *);
+extern int compat_get_timeval(struct timeval *, const void __user *);
+extern int compat_put_timeval(const struct timeval *, void __user *);
 
 struct compat_iovec {
 	compat_uptr_t	iov_base;
@@ -224,6 +244,7 @@
 struct compat_sysctl_args;
 struct compat_kexec_segment;
 struct compat_mq_attr;
+struct compat_msgbuf;
 
 extern void compat_exit_robust_list(struct task_struct *curr);
 
@@ -234,13 +255,22 @@
 compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
 			   compat_size_t __user *len_ptr);
 
+#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
 long compat_sys_semctl(int first, int second, int third, void __user *uptr);
 long compat_sys_msgsnd(int first, int second, int third, void __user *uptr);
 long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
 		int version, void __user *uptr);
-long compat_sys_msgctl(int first, int second, void __user *uptr);
 long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
 		void __user *uptr);
+#else
+long compat_sys_semctl(int semid, int semnum, int cmd, int arg);
+long compat_sys_msgsnd(int msqid, struct compat_msgbuf __user *msgp,
+		size_t msgsz, int msgflg);
+long compat_sys_msgrcv(int msqid, struct compat_msgbuf __user *msgp,
+		size_t msgsz, long msgtyp, int msgflg);
+long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg);
+#endif
+long compat_sys_msgctl(int first, int second, void __user *uptr);
 long compat_sys_shmctl(int first, int second, void __user *uptr);
 long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
 		unsigned nsems, const struct compat_timespec __user *timeout);
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index 3fd17c2..e5834aa 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -87,7 +87,8 @@
  */
 #define __pure				__attribute__((pure))
 #define __aligned(x)			__attribute__((aligned(x)))
-#define __printf(a,b)			__attribute__((format(printf,a,b)))
+#define __printf(a, b)			__attribute__((format(printf, a, b)))
+#define __scanf(a, b)			__attribute__((format(scanf, a, b)))
 #define  noinline			__attribute__((noinline))
 #define __attribute_const__		__attribute__((__const__))
 #define __maybe_unused			__attribute__((unused))
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 6e53b48..ee28844 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -14,11 +14,12 @@
 #ifndef _LINUX_CPU_H_
 #define _LINUX_CPU_H_
 
-#include <linux/device.h>
 #include <linux/node.h>
 #include <linux/compiler.h>
 #include <linux/cpumask.h>
 
+struct device;
+
 struct cpu {
 	int node_id;		/* The node which contains the CPU */
 	int hotpluggable;	/* creates sysfs control file if hotpluggable */
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 6216115..b60f6ba 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -14,7 +14,6 @@
 #include <linux/mutex.h>
 #include <linux/notifier.h>
 #include <linux/threads.h>
-#include <linux/device.h>
 #include <linux/kobject.h>
 #include <linux/sysfs.h>
 #include <linux/completion.h>
@@ -35,6 +34,7 @@
 #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)
@@ -46,6 +46,7 @@
 {
 	return 0;
 }
+static inline void disable_cpufreq(void) { }
 #endif		/* CONFIG_CPU_FREQ */
 
 /* if (cpufreq_driver->target) exists, the ->governor decides what frequency
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 712abcc..6c26a3d 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -15,6 +15,7 @@
 #include <linux/list.h>
 #include <linux/kobject.h>
 #include <linux/completion.h>
+#include <linux/hrtimer.h>
 
 #define CPUIDLE_STATE_MAX	8
 #define CPUIDLE_NAME_LEN	16
@@ -43,12 +44,15 @@
 
 	unsigned int	flags;
 	unsigned int	exit_latency; /* in US */
-	unsigned int	power_usage; /* in mW */
+	int		power_usage; /* in mW */
 	unsigned int	target_residency; /* in US */
+	unsigned int    disable;
 
 	int (*enter)	(struct cpuidle_device *dev,
 			struct cpuidle_driver *drv,
 			int index);
+
+	int (*enter_dead) (struct cpuidle_device *dev, int index);
 };
 
 /* Idle State Flags */
@@ -96,7 +100,6 @@
 	struct list_head 	device_list;
 	struct kobject		kobj;
 	struct completion	kobj_unregister;
-	void			*governor_data;
 };
 
 DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
@@ -118,10 +121,12 @@
  ****************************/
 
 struct cpuidle_driver {
-	char			name[CPUIDLE_NAME_LEN];
+	const char		*name;
 	struct module 		*owner;
 
 	unsigned int		power_specified:1;
+	/* set to 1 to use the core cpuidle time keeping (for all states). */
+	unsigned int		en_core_tk_irqen:1;
 	struct cpuidle_state	states[CPUIDLE_STATE_MAX];
 	int			state_count;
 	int			safe_state_index;
@@ -140,6 +145,11 @@
 extern void cpuidle_resume_and_unlock(void);
 extern int cpuidle_enable_device(struct cpuidle_device *dev);
 extern void cpuidle_disable_device(struct cpuidle_device *dev);
+extern int cpuidle_wrap_enter(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv, int index,
+				int (*enter)(struct cpuidle_device *dev,
+					struct cpuidle_driver *drv, int index));
+extern int cpuidle_play_dead(void);
 
 #else
 static inline void disable_cpuidle(void) { }
@@ -157,6 +167,12 @@
 static inline int cpuidle_enable_device(struct cpuidle_device *dev)
 {return -ENODEV; }
 static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
+static inline int cpuidle_wrap_enter(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv, int index,
+				int (*enter)(struct cpuidle_device *dev,
+					struct cpuidle_driver *drv, int index))
+{ return -ENODEV; }
+static inline int cpuidle_play_dead(void) {return -ENODEV; }
 
 #endif
 
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index 4f7a6323..a2c819d 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/threads.h>
 #include <linux/bitmap.h>
+#include <linux/bug.h>
 
 typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
 
@@ -763,12 +764,6 @@
  *
  */
 #ifndef CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS
-/* These strip const, as traditionally they weren't const. */
-#define cpu_possible_map	(*(cpumask_t *)cpu_possible_mask)
-#define cpu_online_map		(*(cpumask_t *)cpu_online_mask)
-#define cpu_present_map		(*(cpumask_t *)cpu_present_mask)
-#define cpu_active_map		(*(cpumask_t *)cpu_active_mask)
-
 #define cpumask_of_cpu(cpu) (*get_cpu_mask(cpu))
 
 #define CPU_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(NR_CPUS)
@@ -809,11 +804,10 @@
 #else /* NR_CPUS > 1 */
 int __first_cpu(const cpumask_t *srcp);
 int __next_cpu(int n, const cpumask_t *srcp);
-int __any_online_cpu(const cpumask_t *mask);
 
 #define first_cpu(src)		__first_cpu(&(src))
 #define next_cpu(n, src)	__next_cpu((n), &(src))
-#define any_online_cpu(mask) __any_online_cpu(&(mask))
+#define any_online_cpu(mask) cpumask_any_and(&mask, cpu_online_mask)
 #define for_each_cpu_mask(cpu, mask)			\
 	for ((cpu) = -1;				\
 		(cpu) = next_cpu((cpu), (mask)),	\
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index e9eaec5..668f66b 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -22,7 +22,7 @@
 extern void cpuset_init_smp(void);
 extern void cpuset_update_active_cpus(void);
 extern void cpuset_cpus_allowed(struct task_struct *p, struct cpumask *mask);
-extern int cpuset_cpus_allowed_fallback(struct task_struct *p);
+extern void cpuset_cpus_allowed_fallback(struct task_struct *p);
 extern nodemask_t cpuset_mems_allowed(struct task_struct *p);
 #define cpuset_current_mems_allowed (current->mems_allowed)
 void cpuset_init_current_mems_allowed(void);
@@ -89,42 +89,33 @@
 extern void cpuset_print_task_mems_allowed(struct task_struct *p);
 
 /*
- * reading current mems_allowed and mempolicy in the fastpath must protected
- * by get_mems_allowed()
+ * get_mems_allowed is required when making decisions involving mems_allowed
+ * such as during page allocation. mems_allowed can be updated in parallel
+ * and depending on the new value an operation can fail potentially causing
+ * process failure. A retry loop with get_mems_allowed and put_mems_allowed
+ * prevents these artificial failures.
  */
-static inline void get_mems_allowed(void)
+static inline unsigned int get_mems_allowed(void)
 {
-	current->mems_allowed_change_disable++;
-
-	/*
-	 * ensure that reading mems_allowed and mempolicy happens after the
-	 * update of ->mems_allowed_change_disable.
-	 *
-	 * the write-side task finds ->mems_allowed_change_disable is not 0,
-	 * and knows the read-side task is reading mems_allowed or mempolicy,
-	 * so it will clear old bits lazily.
-	 */
-	smp_mb();
+	return read_seqcount_begin(&current->mems_allowed_seq);
 }
 
-static inline void put_mems_allowed(void)
+/*
+ * If this returns false, the operation that took place after get_mems_allowed
+ * may have failed. It is up to the caller to retry the operation if
+ * appropriate.
+ */
+static inline bool put_mems_allowed(unsigned int seq)
 {
-	/*
-	 * ensure that reading mems_allowed and mempolicy before reducing
-	 * mems_allowed_change_disable.
-	 *
-	 * the write-side task will know that the read-side task is still
-	 * reading mems_allowed or mempolicy, don't clears old bits in the
-	 * nodemask.
-	 */
-	smp_mb();
-	--ACCESS_ONCE(current->mems_allowed_change_disable);
+	return !read_seqcount_retry(&current->mems_allowed_seq, seq);
 }
 
 static inline void set_mems_allowed(nodemask_t nodemask)
 {
 	task_lock(current);
+	write_seqcount_begin(&current->mems_allowed_seq);
 	current->mems_allowed = nodemask;
+	write_seqcount_end(&current->mems_allowed_seq);
 	task_unlock(current);
 }
 
@@ -144,10 +135,8 @@
 	cpumask_copy(mask, cpu_possible_mask);
 }
 
-static inline int cpuset_cpus_allowed_fallback(struct task_struct *p)
+static inline void cpuset_cpus_allowed_fallback(struct task_struct *p)
 {
-	do_set_cpus_allowed(p, cpu_possible_mask);
-	return cpumask_any(cpu_active_mask);
 }
 
 static inline nodemask_t cpuset_mems_allowed(struct task_struct *p)
@@ -234,12 +223,14 @@
 {
 }
 
-static inline void get_mems_allowed(void)
+static inline unsigned int get_mems_allowed(void)
 {
+	return 0;
 }
 
-static inline void put_mems_allowed(void)
+static inline bool put_mems_allowed(unsigned int seq)
 {
+	return true;
 }
 
 #endif /* !CONFIG_CPUSETS */
diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
index b936763..37e4f8d 100644
--- a/include/linux/crash_dump.h
+++ b/include/linux/crash_dump.h
@@ -3,7 +3,6 @@
 
 #ifdef CONFIG_CRASH_DUMP
 #include <linux/kexec.h>
-#include <linux/device.h>
 #include <linux/proc_fs.h>
 #include <linux/elf.h>
 
diff --git a/include/linux/crc32.h b/include/linux/crc32.h
index 391a259..68267b6 100644
--- a/include/linux/crc32.h
+++ b/include/linux/crc32.h
@@ -11,6 +11,8 @@
 extern u32  crc32_le(u32 crc, unsigned char const *p, size_t len);
 extern u32  crc32_be(u32 crc, unsigned char const *p, size_t len);
 
+extern u32  __crc32c_le(u32 crc, unsigned char const *p, size_t len);
+
 #define crc32(seed, data, length)  crc32_le(seed, (unsigned char const *)(data), length)
 
 /*
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 48ce547..b92eadf 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -20,6 +20,7 @@
 #include <linux/atomic.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/bug.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/uaccess.h>
diff --git a/include/linux/cryptouser.h b/include/linux/cryptouser.h
index 532fb58..4abf2ea 100644
--- a/include/linux/cryptouser.h
+++ b/include/linux/cryptouser.h
@@ -100,3 +100,6 @@
 	char type[CRYPTO_MAX_NAME];
 	unsigned int seedsize;
 };
+
+#define CRYPTO_REPORT_MAXSIZE (sizeof(struct crypto_user_alg) + \
+			       sizeof(struct crypto_report_blkcipher))
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index ff5f525..7e11f14 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -222,7 +222,6 @@
 extern int d_invalidate(struct dentry *);
 
 /* only used at mount-time */
-extern struct dentry * d_alloc_root(struct inode *);
 extern struct dentry * d_make_root(struct inode *);
 
 /* <clickety>-<click> the ramfs-type tree */
diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h
index 5033fb8..3bd46f7 100644
--- a/include/linux/debug_locks.h
+++ b/include/linux/debug_locks.h
@@ -3,7 +3,7 @@
 
 #include <linux/kernel.h>
 #include <linux/atomic.h>
-#include <asm/system.h>
+#include <linux/bug.h>
 
 struct task_struct;
 
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
index 6169c26..ae36b72 100644
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -86,7 +86,7 @@
 				  struct dentry *parent,
 				  struct debugfs_blob_wrapper *blob);
 
-struct dentry *debugfs_create_regset32(const char *name, mode_t mode,
+struct dentry *debugfs_create_regset32(const char *name, umode_t mode,
 				     struct dentry *parent,
 				     struct debugfs_regset32 *regset);
 
@@ -208,7 +208,7 @@
 }
 
 static inline struct dentry *debugfs_create_regset32(const char *name,
-				   mode_t mode, struct dentry *parent,
+				   umode_t mode, struct dentry *parent,
 				   struct debugfs_regset32 *regset)
 {
 	return ERR_PTR(-ENODEV);
diff --git a/include/linux/device.h b/include/linux/device.h
index 7c46bc3..5ad17cc 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -262,10 +262,6 @@
 extern void driver_remove_file(struct device_driver *driver,
 			       const struct driver_attribute *attr);
 
-extern int __must_check driver_add_kobj(struct device_driver *drv,
-					struct kobject *kobj,
-					const char *fmt, ...);
-
 extern int __must_check driver_for_each_device(struct device_driver *drv,
 					       struct device *start,
 					       void *data,
diff --git a/include/linux/dma-attrs.h b/include/linux/dma-attrs.h
index 71ad34e..547ab56 100644
--- a/include/linux/dma-attrs.h
+++ b/include/linux/dma-attrs.h
@@ -13,6 +13,8 @@
 enum dma_attr {
 	DMA_ATTR_WRITE_BARRIER,
 	DMA_ATTR_WEAK_ORDERING,
+	DMA_ATTR_WRITE_COMBINE,
+	DMA_ATTR_NON_CONSISTENT,
 	DMA_ATTR_MAX,
 };
 
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index f8ac076..3efbfc2 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -26,11 +26,12 @@
 
 #include <linux/file.h>
 #include <linux/err.h>
-#include <linux/device.h>
 #include <linux/scatterlist.h>
 #include <linux/list.h>
 #include <linux/dma-mapping.h>
+#include <linux/fs.h>
 
+struct device;
 struct dma_buf;
 struct dma_buf_attachment;
 
@@ -49,6 +50,17 @@
  * @unmap_dma_buf: decreases usecount of buffer, might deallocate scatter
  *		   pages.
  * @release: release this buffer; to be called after the last dma_buf_put.
+ * @begin_cpu_access: [optional] called before cpu access to invalidate cpu
+ * 		      caches and allocate backing storage (if not yet done)
+ * 		      respectively pin the objet into memory.
+ * @end_cpu_access: [optional] called after cpu access to flush cashes.
+ * @kmap_atomic: maps a page from the buffer into kernel address
+ * 		 space, users may not block until the subsequent unmap call.
+ * 		 This callback must not sleep.
+ * @kunmap_atomic: [optional] unmaps a atomically mapped page from the buffer.
+ * 		   This Callback must not sleep.
+ * @kmap: maps a page from the buffer into kernel address space.
+ * @kunmap: [optional] unmaps a page from the buffer.
  */
 struct dma_buf_ops {
 	int (*attach)(struct dma_buf *, struct device *,
@@ -63,7 +75,8 @@
 	struct sg_table * (*map_dma_buf)(struct dma_buf_attachment *,
 						enum dma_data_direction);
 	void (*unmap_dma_buf)(struct dma_buf_attachment *,
-						struct sg_table *);
+						struct sg_table *,
+						enum dma_data_direction);
 	/* TODO: Add try_map_dma_buf version, to return immed with -EBUSY
 	 * if the call would block.
 	 */
@@ -71,6 +84,14 @@
 	/* after final dma_buf_put() */
 	void (*release)(struct dma_buf *);
 
+	int (*begin_cpu_access)(struct dma_buf *, size_t, size_t,
+				enum dma_data_direction);
+	void (*end_cpu_access)(struct dma_buf *, size_t, size_t,
+			       enum dma_data_direction);
+	void *(*kmap_atomic)(struct dma_buf *, unsigned long);
+	void (*kunmap_atomic)(struct dma_buf *, unsigned long, void *);
+	void *(*kmap)(struct dma_buf *, unsigned long);
+	void (*kunmap)(struct dma_buf *, unsigned long, void *);
 };
 
 /**
@@ -86,7 +107,7 @@
 	struct file *file;
 	struct list_head attachments;
 	const struct dma_buf_ops *ops;
-	/* mutex to serialize list manipulation and other ops */
+	/* mutex to serialize list manipulation and attach/detach */
 	struct mutex lock;
 	void *priv;
 };
@@ -109,20 +130,43 @@
 	void *priv;
 };
 
+/**
+ * get_dma_buf - convenience wrapper for get_file.
+ * @dmabuf:	[in]	pointer to dma_buf
+ *
+ * Increments the reference count on the dma-buf, needed in case of drivers
+ * that either need to create additional references to the dmabuf on the
+ * kernel side.  For example, an exporter that needs to keep a dmabuf ptr
+ * so that subsequent exports don't create a new dmabuf.
+ */
+static inline void get_dma_buf(struct dma_buf *dmabuf)
+{
+	get_file(dmabuf->file);
+}
+
 #ifdef CONFIG_DMA_SHARED_BUFFER
 struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
 							struct device *dev);
 void dma_buf_detach(struct dma_buf *dmabuf,
 				struct dma_buf_attachment *dmabuf_attach);
-struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
-			size_t size, int flags);
-int dma_buf_fd(struct dma_buf *dmabuf);
+struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
+			       size_t size, int flags);
+int dma_buf_fd(struct dma_buf *dmabuf, int flags);
 struct dma_buf *dma_buf_get(int fd);
 void dma_buf_put(struct dma_buf *dmabuf);
 
 struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *,
 					enum dma_data_direction);
-void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *);
+void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *,
+				enum dma_data_direction);
+int dma_buf_begin_cpu_access(struct dma_buf *dma_buf, size_t start, size_t len,
+			     enum dma_data_direction dir);
+void dma_buf_end_cpu_access(struct dma_buf *dma_buf, size_t start, size_t len,
+			    enum dma_data_direction dir);
+void *dma_buf_kmap_atomic(struct dma_buf *, unsigned long);
+void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long, void *);
+void *dma_buf_kmap(struct dma_buf *, unsigned long);
+void dma_buf_kunmap(struct dma_buf *, unsigned long, void *);
 #else
 
 static inline struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
@@ -138,13 +182,13 @@
 }
 
 static inline struct dma_buf *dma_buf_export(void *priv,
-						struct dma_buf_ops *ops,
-						size_t size, int flags)
+					     const struct dma_buf_ops *ops,
+					     size_t size, int flags)
 {
 	return ERR_PTR(-ENODEV);
 }
 
-static inline int dma_buf_fd(struct dma_buf *dmabuf)
+static inline int dma_buf_fd(struct dma_buf *dmabuf, int flags)
 {
 	return -ENODEV;
 }
@@ -166,11 +210,44 @@
 }
 
 static inline void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
-						struct sg_table *sg)
+			struct sg_table *sg, enum dma_data_direction dir)
 {
 	return;
 }
 
+static inline int dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
+					   size_t start, size_t len,
+					   enum dma_data_direction dir)
+{
+	return -ENODEV;
+}
+
+static inline void dma_buf_end_cpu_access(struct dma_buf *dmabuf,
+					  size_t start, size_t len,
+					  enum dma_data_direction dir)
+{
+}
+
+static inline void *dma_buf_kmap_atomic(struct dma_buf *dmabuf,
+					unsigned long pnum)
+{
+	return NULL;
+}
+
+static inline void dma_buf_kunmap_atomic(struct dma_buf *dmabuf,
+					 unsigned long pnum, void *vaddr)
+{
+}
+
+static inline void *dma_buf_kmap(struct dma_buf *dmabuf, unsigned long pnum)
+{
+	return NULL;
+}
+
+static inline void dma_buf_kunmap(struct dma_buf *dmabuf,
+				  unsigned long pnum, void *vaddr)
+{
+}
 #endif /* CONFIG_DMA_SHARED_BUFFER */
 
 #endif /* __DMA_BUF_H__ */
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index e13117c..dfc099e 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -9,10 +9,15 @@
 #include <linux/scatterlist.h>
 
 struct dma_map_ops {
-	void* (*alloc_coherent)(struct device *dev, size_t size,
-				dma_addr_t *dma_handle, gfp_t gfp);
-	void (*free_coherent)(struct device *dev, size_t size,
-			      void *vaddr, dma_addr_t dma_handle);
+	void* (*alloc)(struct device *dev, size_t size,
+				dma_addr_t *dma_handle, gfp_t gfp,
+				struct dma_attrs *attrs);
+	void (*free)(struct device *dev, size_t size,
+			      void *vaddr, dma_addr_t dma_handle,
+			      struct dma_attrs *attrs);
+	int (*mmap)(struct device *, struct vm_area_struct *,
+			  void *, dma_addr_t, size_t, struct dma_attrs *attrs);
+
 	dma_addr_t (*map_page)(struct device *dev, struct page *page,
 			       unsigned long offset, size_t size,
 			       enum dma_data_direction dir,
@@ -77,7 +82,7 @@
 	return DMA_BIT_MASK(32);
 }
 
-#ifdef ARCH_HAS_DMA_SET_COHERENT_MASK
+#ifdef CONFIG_ARCH_HAS_DMA_SET_COHERENT_MASK
 int dma_set_coherent_mask(struct device *dev, u64 mask);
 #else
 static inline int dma_set_coherent_mask(struct device *dev, u64 mask)
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 679b349d..676f967 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -18,13 +18,15 @@
  * The full GNU General Public License is included in this distribution in the
  * file called COPYING.
  */
-#ifndef DMAENGINE_H
-#define DMAENGINE_H
+#ifndef LINUX_DMAENGINE_H
+#define LINUX_DMAENGINE_H
 
 #include <linux/device.h>
 #include <linux/uio.h>
+#include <linux/bug.h>
 #include <linux/scatterlist.h>
 #include <linux/bitmap.h>
+#include <linux/types.h>
 #include <asm/page.h>
 
 /**
@@ -257,6 +259,7 @@
  * struct dma_chan - devices supply DMA channels, clients use them
  * @device: ptr to the dma device who supplies this channel, always !%NULL
  * @cookie: last cookie value returned to client
+ * @completed_cookie: last completed cookie for this channel
  * @chan_id: channel ID for sysfs
  * @dev: class device for sysfs
  * @device_node: used to add this to the device chan list
@@ -268,6 +271,7 @@
 struct dma_chan {
 	struct dma_device *device;
 	dma_cookie_t cookie;
+	dma_cookie_t completed_cookie;
 
 	/* sysfs */
 	int chan_id;
@@ -331,6 +335,9 @@
  * may or may not be applicable on memory sources.
  * @dst_maxburst: same as src_maxburst but for destination target
  * mutatis mutandis.
+ * @device_fc: Flow Controller Settings. Only valid for slave channels. Fill
+ * with 'true' if peripheral should be flow controller. Direction will be
+ * selected at Runtime.
  *
  * This struct is passed in as configuration data to a DMA engine
  * in order to set up a certain channel for DMA transport at runtime.
@@ -357,6 +364,7 @@
 	enum dma_slave_buswidth dst_addr_width;
 	u32 src_maxburst;
 	u32 dst_maxburst;
+	bool device_fc;
 };
 
 static inline const char *dma_chan_name(struct dma_chan *chan)
@@ -575,10 +583,11 @@
 	struct dma_async_tx_descriptor *(*device_prep_slave_sg)(
 		struct dma_chan *chan, struct scatterlist *sgl,
 		unsigned int sg_len, enum dma_transfer_direction direction,
-		unsigned long flags);
+		unsigned long flags, void *context);
 	struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)(
 		struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
-		size_t period_len, enum dma_transfer_direction direction);
+		size_t period_len, enum dma_transfer_direction direction,
+		void *context);
 	struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)(
 		struct dma_chan *chan, struct dma_interleaved_template *xt,
 		unsigned long flags);
@@ -612,7 +621,24 @@
 	struct scatterlist sg;
 	sg_init_one(&sg, buf, len);
 
-	return chan->device->device_prep_slave_sg(chan, &sg, 1, dir, flags);
+	return chan->device->device_prep_slave_sg(chan, &sg, 1,
+						  dir, flags, NULL);
+}
+
+static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
+	struct dma_chan *chan, struct scatterlist *sgl,	unsigned int sg_len,
+	enum dma_transfer_direction dir, unsigned long flags)
+{
+	return chan->device->device_prep_slave_sg(chan, sgl, sg_len,
+						  dir, flags, NULL);
+}
+
+static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(
+		struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+		size_t period_len, enum dma_transfer_direction dir)
+{
+	return chan->device->device_prep_dma_cyclic(chan, buf_addr, buf_len,
+						period_len, dir, NULL);
 }
 
 static inline int dmaengine_terminate_all(struct dma_chan *chan)
diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h
index f2c64f9..2412e02 100644
--- a/include/linux/dw_dmac.h
+++ b/include/linux/dw_dmac.h
@@ -31,18 +31,6 @@
 	unsigned char	chan_priority;
 };
 
-/**
- * enum dw_dma_slave_width - DMA slave register access width.
- * @DMA_SLAVE_WIDTH_8BIT: Do 8-bit slave register accesses
- * @DMA_SLAVE_WIDTH_16BIT: Do 16-bit slave register accesses
- * @DMA_SLAVE_WIDTH_32BIT: Do 32-bit slave register accesses
- */
-enum dw_dma_slave_width {
-	DW_DMA_SLAVE_WIDTH_8BIT,
-	DW_DMA_SLAVE_WIDTH_16BIT,
-	DW_DMA_SLAVE_WIDTH_32BIT,
-};
-
 /* bursts size */
 enum dw_dma_msize {
 	DW_DMA_MSIZE_1,
@@ -55,47 +43,21 @@
 	DW_DMA_MSIZE_256,
 };
 
-/* flow controller */
-enum dw_dma_fc {
-	DW_DMA_FC_D_M2M,
-	DW_DMA_FC_D_M2P,
-	DW_DMA_FC_D_P2M,
-	DW_DMA_FC_D_P2P,
-	DW_DMA_FC_P_P2M,
-	DW_DMA_FC_SP_P2P,
-	DW_DMA_FC_P_M2P,
-	DW_DMA_FC_DP_P2P,
-};
-
 /**
  * struct dw_dma_slave - Controller-specific information about a slave
  *
  * @dma_dev: required DMA master device
- * @tx_reg: physical address of data register used for
- *	memory-to-peripheral transfers
- * @rx_reg: physical address of data register used for
- *	peripheral-to-memory transfers
- * @reg_width: peripheral register width
  * @cfg_hi: Platform-specific initializer for the CFG_HI register
  * @cfg_lo: Platform-specific initializer for the CFG_LO register
  * @src_master: src master for transfers on allocated channel.
  * @dst_master: dest master for transfers on allocated channel.
- * @src_msize: src burst size.
- * @dst_msize: dest burst size.
- * @fc: flow controller for DMA transfer
  */
 struct dw_dma_slave {
 	struct device		*dma_dev;
-	dma_addr_t		tx_reg;
-	dma_addr_t		rx_reg;
-	enum dw_dma_slave_width	reg_width;
 	u32			cfg_hi;
 	u32			cfg_lo;
 	u8			src_master;
 	u8			dst_master;
-	u8			src_msize;
-	u8			dst_msize;
-	u8			fc;
 };
 
 /* Platform-configurable bits in CFG_HI */
diff --git a/include/linux/edac.h b/include/linux/edac.h
index 1cd3947..c621d76 100644
--- a/include/linux/edac.h
+++ b/include/linux/edac.h
@@ -13,7 +13,11 @@
 #define _LINUX_EDAC_H_
 
 #include <linux/atomic.h>
-#include <linux/device.h>
+#include <linux/kobject.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+
+struct device;
 
 #define EDAC_OPSTATE_INVAL	-1
 #define EDAC_OPSTATE_POLL	0
@@ -66,25 +70,64 @@
 #define DEV_FLAG_X32		BIT(DEV_X32)
 #define DEV_FLAG_X64		BIT(DEV_X64)
 
-/* memory types */
+/**
+ * enum mem_type - memory types. For a more detailed reference, please see
+ *			http://en.wikipedia.org/wiki/DRAM
+ *
+ * @MEM_EMPTY		Empty csrow
+ * @MEM_RESERVED:	Reserved csrow type
+ * @MEM_UNKNOWN:	Unknown csrow type
+ * @MEM_FPM:		FPM - Fast Page Mode, used on systems up to 1995.
+ * @MEM_EDO:		EDO - Extended data out, used on systems up to 1998.
+ * @MEM_BEDO:		BEDO - Burst Extended data out, an EDO variant.
+ * @MEM_SDR:		SDR - Single data rate SDRAM
+ *			http://en.wikipedia.org/wiki/Synchronous_dynamic_random-access_memory
+ *			They use 3 pins for chip select: Pins 0 and 2 are
+ *			for rank 0; pins 1 and 3 are for rank 1, if the memory
+ *			is dual-rank.
+ * @MEM_RDR:		Registered SDR SDRAM
+ * @MEM_DDR:		Double data rate SDRAM
+ *			http://en.wikipedia.org/wiki/DDR_SDRAM
+ * @MEM_RDDR:		Registered Double data rate SDRAM
+ *			This is a variant of the DDR memories.
+ *			A registered memory has a buffer inside it, hiding
+ *			part of the memory details to the memory controller.
+ * @MEM_RMBS:		Rambus DRAM, used on a few Pentium III/IV controllers.
+ * @MEM_DDR2:		DDR2 RAM, as described at JEDEC JESD79-2F.
+ *			Those memories are labed as "PC2-" instead of "PC" to
+ *			differenciate from DDR.
+ * @MEM_FB_DDR2:	Fully-Buffered DDR2, as described at JEDEC Std No. 205
+ *			and JESD206.
+ *			Those memories are accessed per DIMM slot, and not by
+ *			a chip select signal.
+ * @MEM_RDDR2:		Registered DDR2 RAM
+ *			This is a variant of the DDR2 memories.
+ * @MEM_XDR:		Rambus XDR
+ *			It is an evolution of the original RAMBUS memories,
+ *			created to compete with DDR2. Weren't used on any
+ *			x86 arch, but cell_edac PPC memory controller uses it.
+ * @MEM_DDR3:		DDR3 RAM
+ * @MEM_RDDR3:		Registered DDR3 RAM
+ *			This is a variant of the DDR3 memories.
+ */
 enum mem_type {
-	MEM_EMPTY = 0,		/* Empty csrow */
-	MEM_RESERVED,		/* Reserved csrow type */
-	MEM_UNKNOWN,		/* Unknown csrow type */
-	MEM_FPM,		/* Fast page mode */
-	MEM_EDO,		/* Extended data out */
-	MEM_BEDO,		/* Burst Extended data out */
-	MEM_SDR,		/* Single data rate SDRAM */
-	MEM_RDR,		/* Registered single data rate SDRAM */
-	MEM_DDR,		/* Double data rate SDRAM */
-	MEM_RDDR,		/* Registered Double data rate SDRAM */
-	MEM_RMBS,		/* Rambus DRAM */
-	MEM_DDR2,		/* DDR2 RAM */
-	MEM_FB_DDR2,		/* fully buffered DDR2 */
-	MEM_RDDR2,		/* Registered DDR2 RAM */
-	MEM_XDR,		/* Rambus XDR */
-	MEM_DDR3,		/* DDR3 RAM */
-	MEM_RDDR3,		/* Registered DDR3 RAM */
+	MEM_EMPTY = 0,
+	MEM_RESERVED,
+	MEM_UNKNOWN,
+	MEM_FPM,
+	MEM_EDO,
+	MEM_BEDO,
+	MEM_SDR,
+	MEM_RDR,
+	MEM_DDR,
+	MEM_RDDR,
+	MEM_RMBS,
+	MEM_DDR2,
+	MEM_FB_DDR2,
+	MEM_RDDR2,
+	MEM_XDR,
+	MEM_DDR3,
+	MEM_RDDR3,
 };
 
 #define MEM_FLAG_EMPTY		BIT(MEM_EMPTY)
@@ -162,8 +205,9 @@
 #define OP_OFFLINE		0x300
 
 /*
- * There are several things to be aware of that aren't at all obvious:
+ * Concepts used at the EDAC subsystem
  *
+ * There are several things to be aware of that aren't at all obvious:
  *
  * SOCKETS, SOCKET SETS, BANKS, ROWS, CHIP-SELECT ROWS, CHANNELS, etc..
  *
@@ -172,36 +216,61 @@
  * creating a common ground for discussion, terms and their definitions
  * will be established.
  *
- * Memory devices:	The individual chip on a memory stick.  These devices
- *			commonly output 4 and 8 bits each.  Grouping several
- *			of these in parallel provides 64 bits which is common
- *			for a memory stick.
+ * Memory devices:	The individual DRAM chips on a memory stick.  These
+ *			devices commonly output 4 and 8 bits each (x4, x8).
+ *			Grouping several of these in parallel provides the
+ *			number of bits that the memory controller expects:
+ *			typically 72 bits, in order to provide 64 bits +
+ *			8 bits of ECC data.
  *
  * Memory Stick:	A printed circuit board that aggregates multiple
- *			memory devices in parallel.  This is the atomic
- *			memory component that is purchaseable by Joe consumer
- *			and loaded into a memory socket.
+ *			memory devices in parallel.  In general, this is the
+ *			Field Replaceable Unit (FRU) which gets replaced, in
+ *			the case of excessive errors. Most often it is also
+ *			called DIMM (Dual Inline Memory Module).
  *
- * Socket:		A physical connector on the motherboard that accepts
- *			a single memory stick.
+ * Memory Socket:	A physical connector on the motherboard that accepts
+ *			a single memory stick. Also called as "slot" on several
+ *			datasheets.
  *
- * Channel:		Set of memory devices on a memory stick that must be
- *			grouped in parallel with one or more additional
- *			channels from other memory sticks.  This parallel
- *			grouping of the output from multiple channels are
- *			necessary for the smallest granularity of memory access.
- *			Some memory controllers are capable of single channel -
- *			which means that memory sticks can be loaded
- *			individually.  Other memory controllers are only
- *			capable of dual channel - which means that memory
- *			sticks must be loaded as pairs (see "socket set").
+ * Channel:		A memory controller channel, responsible to communicate
+ *			with a group of DIMMs. Each channel has its own
+ *			independent control (command) and data bus, and can
+ *			be used independently or grouped with other channels.
  *
- * Chip-select row:	All of the memory devices that are selected together.
- *			for a single, minimum grain of memory access.
- *			This selects all of the parallel memory devices across
- *			all of the parallel channels.  Common chip-select rows
- *			for single channel are 64 bits, for dual channel 128
- *			bits.
+ * Branch:		It is typically the highest hierarchy on a
+ *			Fully-Buffered DIMM memory controller.
+ *			Typically, it contains two channels.
+ *			Two channels at the same branch can be used in single
+ *			mode or in lockstep mode.
+ *			When lockstep is enabled, the cacheline is doubled,
+ *			but it generally brings some performance penalty.
+ *			Also, it is generally not possible to point to just one
+ *			memory stick when an error occurs, as the error
+ *			correction code is calculated using two DIMMs instead
+ *			of one. Due to that, it is capable of correcting more
+ *			errors than on single mode.
+ *
+ * Single-channel:	The data accessed by the memory controller is contained
+ *			into one dimm only. E. g. if the data is 64 bits-wide,
+ *			the data flows to the CPU using one 64 bits parallel
+ *			access.
+ *			Typically used with SDR, DDR, DDR2 and DDR3 memories.
+ *			FB-DIMM and RAMBUS use a different concept for channel,
+ *			so this concept doesn't apply there.
+ *
+ * Double-channel:	The data size accessed by the memory controller is
+ *			interlaced into two dimms, accessed at the same time.
+ *			E. g. if the DIMM is 64 bits-wide (72 bits with ECC),
+ *			the data flows to the CPU using a 128 bits parallel
+ *			access.
+ *
+ * Chip-select row:	This is the name of the DRAM signal used to select the
+ *			DRAM ranks to be accessed. Common chip-select rows for
+ *			single channel are 64 bits, for dual channel 128 bits.
+ *			It may not be visible by the memory controller, as some
+ *			DIMM types have a memory buffer that can hide direct
+ *			access to it from the Memory Controller.
  *
  * Single-Ranked stick:	A Single-ranked stick has 1 chip-select row of memory.
  *			Motherboards commonly drive two chip-select pins to
@@ -214,8 +283,8 @@
  *
  * Double-sided stick:	DEPRECATED TERM, see Double-Ranked stick.
  *			A double-sided stick has two chip-select rows which
- *			access different sets of memory devices.  The two
- *			rows cannot be accessed concurrently.  "Double-sided"
+ *			access different sets of memory devices. The two
+ *			rows cannot be accessed concurrently. "Double-sided"
  *			is irrespective of the memory devices being mounted
  *			on both sides of the memory stick.
  *
@@ -243,10 +312,22 @@
  * PS - I enjoyed writing all that about as much as you enjoyed reading it.
  */
 
-struct channel_info {
-	int chan_idx;		/* channel index */
-	u32 ce_count;		/* Correctable Errors for this CHANNEL */
-	char label[EDAC_MC_LABEL_LEN + 1];	/* DIMM label on motherboard */
+/**
+ * struct rank_info - contains the information for one DIMM rank
+ *
+ * @chan_idx:	channel number where the rank is (typically, 0 or 1)
+ * @ce_count:	number of correctable errors for this rank
+ * @label:	DIMM label. Different ranks for the same DIMM should be
+ *		filled, on userspace, with the same label.
+ *		FIXME: The core currently won't enforce it.
+ * @csrow:	A pointer to the chip select row structure (the parent
+ *		structure). The location of the rank is given by
+ *		the (csrow->csrow_idx, chan_idx) vector.
+ */
+struct rank_info {
+	int chan_idx;
+	u32 ce_count;
+	char label[EDAC_MC_LABEL_LEN + 1];
 	struct csrow_info *csrow;	/* the parent */
 };
 
@@ -270,7 +351,7 @@
 
 	/* channel information for this csrow */
 	u32 nr_channels;
-	struct channel_info *channels;
+	struct rank_info *channels;
 };
 
 struct mcidev_sysfs_group {
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 37c3007..88ec806 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -22,7 +22,6 @@
 #include <linux/pstore.h>
 
 #include <asm/page.h>
-#include <asm/system.h>
 
 #define EFI_SUCCESS		0
 #define EFI_LOAD_ERROR          ( 1 | (1UL << (BITS_PER_LONG-1)))
@@ -315,6 +314,16 @@
 
 typedef struct {
 	efi_guid_t guid;
+	u64 table;
+} efi_config_table_64_t;
+
+typedef struct {
+	efi_guid_t guid;
+	u32 table;
+} efi_config_table_32_t;
+
+typedef struct {
+	efi_guid_t guid;
 	unsigned long table;
 } efi_config_table_t;
 
@@ -329,6 +338,40 @@
 
 typedef struct {
 	efi_table_hdr_t hdr;
+	u64 fw_vendor;	/* physical addr of CHAR16 vendor string */
+	u32 fw_revision;
+	u32 __pad1;
+	u64 con_in_handle;
+	u64 con_in;
+	u64 con_out_handle;
+	u64 con_out;
+	u64 stderr_handle;
+	u64 stderr;
+	u64 runtime;
+	u64 boottime;
+	u32 nr_tables;
+	u32 __pad2;
+	u64 tables;
+} efi_system_table_64_t;
+
+typedef struct {
+	efi_table_hdr_t hdr;
+	u32 fw_vendor;	/* physical addr of CHAR16 vendor string */
+	u32 fw_revision;
+	u32 con_in_handle;
+	u32 con_in;
+	u32 con_out_handle;
+	u32 con_out;
+	u32 stderr_handle;
+	u32 stderr;
+	u32 runtime;
+	u32 boottime;
+	u32 nr_tables;
+	u32 tables;
+} efi_system_table_32_t;
+
+typedef struct {
+	efi_table_hdr_t hdr;
 	unsigned long fw_vendor;	/* physical addr of CHAR16 vendor string */
 	u32 fw_revision;
 	unsigned long con_in_handle;
@@ -497,6 +540,7 @@
 #ifdef CONFIG_EFI
 # ifdef CONFIG_X86
    extern int efi_enabled;
+   extern bool efi_64bit;
 # else
 #  define efi_enabled 1
 # endif
diff --git a/include/linux/elfcore.h b/include/linux/elfcore.h
index 394a3e0..0698c79 100644
--- a/include/linux/elfcore.h
+++ b/include/linux/elfcore.h
@@ -6,6 +6,7 @@
 #include <linux/time.h>
 #ifdef __KERNEL__
 #include <linux/user.h>
+#include <linux/bug.h>
 #endif
 #include <linux/ptrace.h>
 #include <linux/elf.h>
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index e1d9e0e..f5647b5 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -896,8 +896,7 @@
  *
  * All operations are optional (i.e. the function pointer may be set
  * to %NULL) and callers must take this into account.  Callers must
- * hold the RTNL, except that for @get_drvinfo the caller may or may
- * not hold the RTNL.
+ * hold the RTNL lock.
  *
  * See the structures used by these operations for further documentation.
  *
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index ce1b719..2723e71 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -18,574 +18,25 @@
 
 #include <linux/types.h>
 #include <linux/magic.h>
-#include <linux/fs.h>
 
-/*
- * The second extended filesystem constants/structures
- */
-
-/*
- * Define EXT2FS_DEBUG to produce debug messages
- */
-#undef EXT2FS_DEBUG
-
-/*
- * Define EXT2_RESERVATION to reserve data blocks for expanding files
- */
-#define EXT2_DEFAULT_RESERVE_BLOCKS     8
-/*max window size: 1024(direct blocks) + 3([t,d]indirect blocks) */
-#define EXT2_MAX_RESERVE_BLOCKS         1027
-#define EXT2_RESERVE_WINDOW_NOT_ALLOCATED 0
-/*
- * The second extended file system version
- */
-#define EXT2FS_DATE		"95/08/09"
-#define EXT2FS_VERSION		"0.5b"
-
-/*
- * Debug code
- */
-#ifdef EXT2FS_DEBUG
-#	define ext2_debug(f, a...)	{ \
-					printk ("EXT2-fs DEBUG (%s, %d): %s:", \
-						__FILE__, __LINE__, __func__); \
-				  	printk (f, ## a); \
-					}
-#else
-#	define ext2_debug(f, a...)	/**/
-#endif
-
-/*
- * Special inode numbers
- */
-#define	EXT2_BAD_INO		 1	/* Bad blocks inode */
-#define EXT2_ROOT_INO		 2	/* Root inode */
-#define EXT2_BOOT_LOADER_INO	 5	/* Boot loader inode */
-#define EXT2_UNDEL_DIR_INO	 6	/* Undelete directory inode */
-
-/* First non-reserved inode for old ext2 filesystems */
-#define EXT2_GOOD_OLD_FIRST_INO	11
-
-#ifdef __KERNEL__
-#include <linux/ext2_fs_sb.h>
-static inline struct ext2_sb_info *EXT2_SB(struct super_block *sb)
-{
-	return sb->s_fs_info;
-}
-#else
-/* Assume that user mode programs are passing in an ext2fs superblock, not
- * a kernel struct super_block.  This will allow us to call the feature-test
- * macros from user land. */
-#define EXT2_SB(sb)	(sb)
-#endif
+#define EXT2_NAME_LEN 255
 
 /*
  * Maximal count of links to a file
  */
 #define EXT2_LINK_MAX		32000
 
-/*
- * Macro-instructions used to manage several block sizes
- */
-#define EXT2_MIN_BLOCK_SIZE		1024
-#define	EXT2_MAX_BLOCK_SIZE		4096
-#define EXT2_MIN_BLOCK_LOG_SIZE		  10
-#ifdef __KERNEL__
-# define EXT2_BLOCK_SIZE(s)		((s)->s_blocksize)
-#else
-# define EXT2_BLOCK_SIZE(s)		(EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
-#endif
-#define	EXT2_ADDR_PER_BLOCK(s)		(EXT2_BLOCK_SIZE(s) / sizeof (__u32))
-#ifdef __KERNEL__
-# define EXT2_BLOCK_SIZE_BITS(s)	((s)->s_blocksize_bits)
-#else
-# define EXT2_BLOCK_SIZE_BITS(s)	((s)->s_log_block_size + 10)
-#endif
-#ifdef __KERNEL__
-#define	EXT2_ADDR_PER_BLOCK_BITS(s)	(EXT2_SB(s)->s_addr_per_block_bits)
-#define EXT2_INODE_SIZE(s)		(EXT2_SB(s)->s_inode_size)
-#define EXT2_FIRST_INO(s)		(EXT2_SB(s)->s_first_ino)
-#else
-#define EXT2_INODE_SIZE(s)	(((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
-				 EXT2_GOOD_OLD_INODE_SIZE : \
-				 (s)->s_inode_size)
-#define EXT2_FIRST_INO(s)	(((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
-				 EXT2_GOOD_OLD_FIRST_INO : \
-				 (s)->s_first_ino)
-#endif
+#define EXT2_SB_MAGIC_OFFSET	0x38
+#define EXT2_SB_BLOCKS_OFFSET	0x04
+#define EXT2_SB_BSIZE_OFFSET	0x18
 
-/*
- * Macro-instructions used to manage fragments
- */
-#define EXT2_MIN_FRAG_SIZE		1024
-#define	EXT2_MAX_FRAG_SIZE		4096
-#define EXT2_MIN_FRAG_LOG_SIZE		  10
-#ifdef __KERNEL__
-# define EXT2_FRAG_SIZE(s)		(EXT2_SB(s)->s_frag_size)
-# define EXT2_FRAGS_PER_BLOCK(s)	(EXT2_SB(s)->s_frags_per_block)
-#else
-# define EXT2_FRAG_SIZE(s)		(EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
-# define EXT2_FRAGS_PER_BLOCK(s)	(EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
-#endif
-
-/*
- * Structure of a blocks group descriptor
- */
-struct ext2_group_desc
+static inline u64 ext2_image_size(void *ext2_sb)
 {
-	__le32	bg_block_bitmap;		/* Blocks bitmap block */
-	__le32	bg_inode_bitmap;		/* Inodes bitmap block */
-	__le32	bg_inode_table;		/* Inodes table block */
-	__le16	bg_free_blocks_count;	/* Free blocks count */
-	__le16	bg_free_inodes_count;	/* Free inodes count */
-	__le16	bg_used_dirs_count;	/* Directories count */
-	__le16	bg_pad;
-	__le32	bg_reserved[3];
-};
-
-/*
- * Macro-instructions used to manage group descriptors
- */
-#ifdef __KERNEL__
-# define EXT2_BLOCKS_PER_GROUP(s)	(EXT2_SB(s)->s_blocks_per_group)
-# define EXT2_DESC_PER_BLOCK(s)		(EXT2_SB(s)->s_desc_per_block)
-# define EXT2_INODES_PER_GROUP(s)	(EXT2_SB(s)->s_inodes_per_group)
-# define EXT2_DESC_PER_BLOCK_BITS(s)	(EXT2_SB(s)->s_desc_per_block_bits)
-#else
-# define EXT2_BLOCKS_PER_GROUP(s)	((s)->s_blocks_per_group)
-# define EXT2_DESC_PER_BLOCK(s)		(EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
-# define EXT2_INODES_PER_GROUP(s)	((s)->s_inodes_per_group)
-#endif
-
-/*
- * Constants relative to the data blocks
- */
-#define	EXT2_NDIR_BLOCKS		12
-#define	EXT2_IND_BLOCK			EXT2_NDIR_BLOCKS
-#define	EXT2_DIND_BLOCK			(EXT2_IND_BLOCK + 1)
-#define	EXT2_TIND_BLOCK			(EXT2_DIND_BLOCK + 1)
-#define	EXT2_N_BLOCKS			(EXT2_TIND_BLOCK + 1)
-
-/*
- * Inode flags (GETFLAGS/SETFLAGS)
- */
-#define	EXT2_SECRM_FL			FS_SECRM_FL	/* Secure deletion */
-#define	EXT2_UNRM_FL			FS_UNRM_FL	/* Undelete */
-#define	EXT2_COMPR_FL			FS_COMPR_FL	/* Compress file */
-#define EXT2_SYNC_FL			FS_SYNC_FL	/* Synchronous updates */
-#define EXT2_IMMUTABLE_FL		FS_IMMUTABLE_FL	/* Immutable file */
-#define EXT2_APPEND_FL			FS_APPEND_FL	/* writes to file may only append */
-#define EXT2_NODUMP_FL			FS_NODUMP_FL	/* do not dump file */
-#define EXT2_NOATIME_FL			FS_NOATIME_FL	/* do not update atime */
-/* Reserved for compression usage... */
-#define EXT2_DIRTY_FL			FS_DIRTY_FL
-#define EXT2_COMPRBLK_FL		FS_COMPRBLK_FL	/* One or more compressed clusters */
-#define EXT2_NOCOMP_FL			FS_NOCOMP_FL	/* Don't compress */
-#define EXT2_ECOMPR_FL			FS_ECOMPR_FL	/* Compression error */
-/* End compression flags --- maybe not all used */	
-#define EXT2_BTREE_FL			FS_BTREE_FL	/* btree format dir */
-#define EXT2_INDEX_FL			FS_INDEX_FL	/* hash-indexed directory */
-#define EXT2_IMAGIC_FL			FS_IMAGIC_FL	/* AFS directory */
-#define EXT2_JOURNAL_DATA_FL		FS_JOURNAL_DATA_FL /* Reserved for ext3 */
-#define EXT2_NOTAIL_FL			FS_NOTAIL_FL	/* file tail should not be merged */
-#define EXT2_DIRSYNC_FL			FS_DIRSYNC_FL	/* dirsync behaviour (directories only) */
-#define EXT2_TOPDIR_FL			FS_TOPDIR_FL	/* Top of directory hierarchies*/
-#define EXT2_RESERVED_FL		FS_RESERVED_FL	/* reserved for ext2 lib */
-
-#define EXT2_FL_USER_VISIBLE		FS_FL_USER_VISIBLE	/* User visible flags */
-#define EXT2_FL_USER_MODIFIABLE		FS_FL_USER_MODIFIABLE	/* User modifiable flags */
-
-/* Flags that should be inherited by new inodes from their parent. */
-#define EXT2_FL_INHERITED (EXT2_SECRM_FL | EXT2_UNRM_FL | EXT2_COMPR_FL |\
-			   EXT2_SYNC_FL | EXT2_NODUMP_FL |\
-			   EXT2_NOATIME_FL | EXT2_COMPRBLK_FL |\
-			   EXT2_NOCOMP_FL | EXT2_JOURNAL_DATA_FL |\
-			   EXT2_NOTAIL_FL | EXT2_DIRSYNC_FL)
-
-/* Flags that are appropriate for regular files (all but dir-specific ones). */
-#define EXT2_REG_FLMASK (~(EXT2_DIRSYNC_FL | EXT2_TOPDIR_FL))
-
-/* Flags that are appropriate for non-directories/regular files. */
-#define EXT2_OTHER_FLMASK (EXT2_NODUMP_FL | EXT2_NOATIME_FL)
-
-/* Mask out flags that are inappropriate for the given type of inode. */
-static inline __u32 ext2_mask_flags(umode_t mode, __u32 flags)
-{
-	if (S_ISDIR(mode))
-		return flags;
-	else if (S_ISREG(mode))
-		return flags & EXT2_REG_FLMASK;
-	else
-		return flags & EXT2_OTHER_FLMASK;
+	__u8 *p = ext2_sb;
+	if (*(__le16 *)(p + EXT2_SB_MAGIC_OFFSET) != cpu_to_le16(EXT2_SUPER_MAGIC))
+		return 0;
+	return (u64)le32_to_cpup((__le32 *)(p + EXT2_SB_BLOCKS_OFFSET)) <<
+		le32_to_cpup((__le32 *)(p + EXT2_SB_BSIZE_OFFSET));
 }
 
-/*
- * ioctl commands
- */
-#define	EXT2_IOC_GETFLAGS		FS_IOC_GETFLAGS
-#define	EXT2_IOC_SETFLAGS		FS_IOC_SETFLAGS
-#define	EXT2_IOC_GETVERSION		FS_IOC_GETVERSION
-#define	EXT2_IOC_SETVERSION		FS_IOC_SETVERSION
-#define	EXT2_IOC_GETRSVSZ		_IOR('f', 5, long)
-#define	EXT2_IOC_SETRSVSZ		_IOW('f', 6, long)
-
-/*
- * ioctl commands in 32 bit emulation
- */
-#define EXT2_IOC32_GETFLAGS		FS_IOC32_GETFLAGS
-#define EXT2_IOC32_SETFLAGS		FS_IOC32_SETFLAGS
-#define EXT2_IOC32_GETVERSION		FS_IOC32_GETVERSION
-#define EXT2_IOC32_SETVERSION		FS_IOC32_SETVERSION
-
-/*
- * Structure of an inode on the disk
- */
-struct ext2_inode {
-	__le16	i_mode;		/* File mode */
-	__le16	i_uid;		/* Low 16 bits of Owner Uid */
-	__le32	i_size;		/* Size in bytes */
-	__le32	i_atime;	/* Access time */
-	__le32	i_ctime;	/* Creation time */
-	__le32	i_mtime;	/* Modification time */
-	__le32	i_dtime;	/* Deletion Time */
-	__le16	i_gid;		/* Low 16 bits of Group Id */
-	__le16	i_links_count;	/* Links count */
-	__le32	i_blocks;	/* Blocks count */
-	__le32	i_flags;	/* File flags */
-	union {
-		struct {
-			__le32  l_i_reserved1;
-		} linux1;
-		struct {
-			__le32  h_i_translator;
-		} hurd1;
-		struct {
-			__le32  m_i_reserved1;
-		} masix1;
-	} osd1;				/* OS dependent 1 */
-	__le32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
-	__le32	i_generation;	/* File version (for NFS) */
-	__le32	i_file_acl;	/* File ACL */
-	__le32	i_dir_acl;	/* Directory ACL */
-	__le32	i_faddr;	/* Fragment address */
-	union {
-		struct {
-			__u8	l_i_frag;	/* Fragment number */
-			__u8	l_i_fsize;	/* Fragment size */
-			__u16	i_pad1;
-			__le16	l_i_uid_high;	/* these 2 fields    */
-			__le16	l_i_gid_high;	/* were reserved2[0] */
-			__u32	l_i_reserved2;
-		} linux2;
-		struct {
-			__u8	h_i_frag;	/* Fragment number */
-			__u8	h_i_fsize;	/* Fragment size */
-			__le16	h_i_mode_high;
-			__le16	h_i_uid_high;
-			__le16	h_i_gid_high;
-			__le32	h_i_author;
-		} hurd2;
-		struct {
-			__u8	m_i_frag;	/* Fragment number */
-			__u8	m_i_fsize;	/* Fragment size */
-			__u16	m_pad1;
-			__u32	m_i_reserved2[2];
-		} masix2;
-	} osd2;				/* OS dependent 2 */
-};
-
-#define i_size_high	i_dir_acl
-
-#if defined(__KERNEL__) || defined(__linux__)
-#define i_reserved1	osd1.linux1.l_i_reserved1
-#define i_frag		osd2.linux2.l_i_frag
-#define i_fsize		osd2.linux2.l_i_fsize
-#define i_uid_low	i_uid
-#define i_gid_low	i_gid
-#define i_uid_high	osd2.linux2.l_i_uid_high
-#define i_gid_high	osd2.linux2.l_i_gid_high
-#define i_reserved2	osd2.linux2.l_i_reserved2
-#endif
-
-#ifdef	__hurd__
-#define i_translator	osd1.hurd1.h_i_translator
-#define i_frag		osd2.hurd2.h_i_frag
-#define i_fsize		osd2.hurd2.h_i_fsize
-#define i_uid_high	osd2.hurd2.h_i_uid_high
-#define i_gid_high	osd2.hurd2.h_i_gid_high
-#define i_author	osd2.hurd2.h_i_author
-#endif
-
-#ifdef	__masix__
-#define i_reserved1	osd1.masix1.m_i_reserved1
-#define i_frag		osd2.masix2.m_i_frag
-#define i_fsize		osd2.masix2.m_i_fsize
-#define i_reserved2	osd2.masix2.m_i_reserved2
-#endif
-
-/*
- * File system states
- */
-#define	EXT2_VALID_FS			0x0001	/* Unmounted cleanly */
-#define	EXT2_ERROR_FS			0x0002	/* Errors detected */
-
-/*
- * Mount flags
- */
-#define EXT2_MOUNT_CHECK		0x000001  /* Do mount-time checks */
-#define EXT2_MOUNT_OLDALLOC		0x000002  /* Don't use the new Orlov allocator */
-#define EXT2_MOUNT_GRPID		0x000004  /* Create files with directory's group */
-#define EXT2_MOUNT_DEBUG		0x000008  /* Some debugging messages */
-#define EXT2_MOUNT_ERRORS_CONT		0x000010  /* Continue on errors */
-#define EXT2_MOUNT_ERRORS_RO		0x000020  /* Remount fs ro on errors */
-#define EXT2_MOUNT_ERRORS_PANIC		0x000040  /* Panic on errors */
-#define EXT2_MOUNT_MINIX_DF		0x000080  /* Mimics the Minix statfs */
-#define EXT2_MOUNT_NOBH			0x000100  /* No buffer_heads */
-#define EXT2_MOUNT_NO_UID32		0x000200  /* Disable 32-bit UIDs */
-#define EXT2_MOUNT_XATTR_USER		0x004000  /* Extended user attributes */
-#define EXT2_MOUNT_POSIX_ACL		0x008000  /* POSIX Access Control Lists */
-#define EXT2_MOUNT_XIP			0x010000  /* Execute in place */
-#define EXT2_MOUNT_USRQUOTA		0x020000  /* user quota */
-#define EXT2_MOUNT_GRPQUOTA		0x040000  /* group quota */
-#define EXT2_MOUNT_RESERVATION		0x080000  /* Preallocation */
-
-
-#define clear_opt(o, opt)		o &= ~EXT2_MOUNT_##opt
-#define set_opt(o, opt)			o |= EXT2_MOUNT_##opt
-#define test_opt(sb, opt)		(EXT2_SB(sb)->s_mount_opt & \
-					 EXT2_MOUNT_##opt)
-/*
- * Maximal mount counts between two filesystem checks
- */
-#define EXT2_DFL_MAX_MNT_COUNT		20	/* Allow 20 mounts */
-#define EXT2_DFL_CHECKINTERVAL		0	/* Don't use interval check */
-
-/*
- * Behaviour when detecting errors
- */
-#define EXT2_ERRORS_CONTINUE		1	/* Continue execution */
-#define EXT2_ERRORS_RO			2	/* Remount fs read-only */
-#define EXT2_ERRORS_PANIC		3	/* Panic */
-#define EXT2_ERRORS_DEFAULT		EXT2_ERRORS_CONTINUE
-
-/*
- * Structure of the super block
- */
-struct ext2_super_block {
-	__le32	s_inodes_count;		/* Inodes count */
-	__le32	s_blocks_count;		/* Blocks count */
-	__le32	s_r_blocks_count;	/* Reserved blocks count */
-	__le32	s_free_blocks_count;	/* Free blocks count */
-	__le32	s_free_inodes_count;	/* Free inodes count */
-	__le32	s_first_data_block;	/* First Data Block */
-	__le32	s_log_block_size;	/* Block size */
-	__le32	s_log_frag_size;	/* Fragment size */
-	__le32	s_blocks_per_group;	/* # Blocks per group */
-	__le32	s_frags_per_group;	/* # Fragments per group */
-	__le32	s_inodes_per_group;	/* # Inodes per group */
-	__le32	s_mtime;		/* Mount time */
-	__le32	s_wtime;		/* Write time */
-	__le16	s_mnt_count;		/* Mount count */
-	__le16	s_max_mnt_count;	/* Maximal mount count */
-	__le16	s_magic;		/* Magic signature */
-	__le16	s_state;		/* File system state */
-	__le16	s_errors;		/* Behaviour when detecting errors */
-	__le16	s_minor_rev_level; 	/* minor revision level */
-	__le32	s_lastcheck;		/* time of last check */
-	__le32	s_checkinterval;	/* max. time between checks */
-	__le32	s_creator_os;		/* OS */
-	__le32	s_rev_level;		/* Revision level */
-	__le16	s_def_resuid;		/* Default uid for reserved blocks */
-	__le16	s_def_resgid;		/* Default gid for reserved blocks */
-	/*
-	 * These fields are for EXT2_DYNAMIC_REV superblocks only.
-	 *
-	 * Note: the difference between the compatible feature set and
-	 * the incompatible feature set is that if there is a bit set
-	 * in the incompatible feature set that the kernel doesn't
-	 * know about, it should refuse to mount the filesystem.
-	 * 
-	 * e2fsck's requirements are more strict; if it doesn't know
-	 * about a feature in either the compatible or incompatible
-	 * feature set, it must abort and not try to meddle with
-	 * things it doesn't understand...
-	 */
-	__le32	s_first_ino; 		/* First non-reserved inode */
-	__le16   s_inode_size; 		/* size of inode structure */
-	__le16	s_block_group_nr; 	/* block group # of this superblock */
-	__le32	s_feature_compat; 	/* compatible feature set */
-	__le32	s_feature_incompat; 	/* incompatible feature set */
-	__le32	s_feature_ro_compat; 	/* readonly-compatible feature set */
-	__u8	s_uuid[16];		/* 128-bit uuid for volume */
-	char	s_volume_name[16]; 	/* volume name */
-	char	s_last_mounted[64]; 	/* directory where last mounted */
-	__le32	s_algorithm_usage_bitmap; /* For compression */
-	/*
-	 * Performance hints.  Directory preallocation should only
-	 * happen if the EXT2_COMPAT_PREALLOC flag is on.
-	 */
-	__u8	s_prealloc_blocks;	/* Nr of blocks to try to preallocate*/
-	__u8	s_prealloc_dir_blocks;	/* Nr to preallocate for dirs */
-	__u16	s_padding1;
-	/*
-	 * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
-	 */
-	__u8	s_journal_uuid[16];	/* uuid of journal superblock */
-	__u32	s_journal_inum;		/* inode number of journal file */
-	__u32	s_journal_dev;		/* device number of journal file */
-	__u32	s_last_orphan;		/* start of list of inodes to delete */
-	__u32	s_hash_seed[4];		/* HTREE hash seed */
-	__u8	s_def_hash_version;	/* Default hash version to use */
-	__u8	s_reserved_char_pad;
-	__u16	s_reserved_word_pad;
-	__le32	s_default_mount_opts;
- 	__le32	s_first_meta_bg; 	/* First metablock block group */
-	__u32	s_reserved[190];	/* Padding to the end of the block */
-};
-
-/*
- * Codes for operating systems
- */
-#define EXT2_OS_LINUX		0
-#define EXT2_OS_HURD		1
-#define EXT2_OS_MASIX		2
-#define EXT2_OS_FREEBSD		3
-#define EXT2_OS_LITES		4
-
-/*
- * Revision levels
- */
-#define EXT2_GOOD_OLD_REV	0	/* The good old (original) format */
-#define EXT2_DYNAMIC_REV	1 	/* V2 format w/ dynamic inode sizes */
-
-#define EXT2_CURRENT_REV	EXT2_GOOD_OLD_REV
-#define EXT2_MAX_SUPP_REV	EXT2_DYNAMIC_REV
-
-#define EXT2_GOOD_OLD_INODE_SIZE 128
-
-/*
- * Feature set definitions
- */
-
-#define EXT2_HAS_COMPAT_FEATURE(sb,mask)			\
-	( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
-#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask)			\
-	( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
-#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask)			\
-	( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
-#define EXT2_SET_COMPAT_FEATURE(sb,mask)			\
-	EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
-#define EXT2_SET_RO_COMPAT_FEATURE(sb,mask)			\
-	EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
-#define EXT2_SET_INCOMPAT_FEATURE(sb,mask)			\
-	EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
-#define EXT2_CLEAR_COMPAT_FEATURE(sb,mask)			\
-	EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
-#define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask)			\
-	EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
-#define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask)			\
-	EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
-
-#define EXT2_FEATURE_COMPAT_DIR_PREALLOC	0x0001
-#define EXT2_FEATURE_COMPAT_IMAGIC_INODES	0x0002
-#define EXT3_FEATURE_COMPAT_HAS_JOURNAL		0x0004
-#define EXT2_FEATURE_COMPAT_EXT_ATTR		0x0008
-#define EXT2_FEATURE_COMPAT_RESIZE_INO		0x0010
-#define EXT2_FEATURE_COMPAT_DIR_INDEX		0x0020
-#define EXT2_FEATURE_COMPAT_ANY			0xffffffff
-
-#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
-#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
-#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR	0x0004
-#define EXT2_FEATURE_RO_COMPAT_ANY		0xffffffff
-
-#define EXT2_FEATURE_INCOMPAT_COMPRESSION	0x0001
-#define EXT2_FEATURE_INCOMPAT_FILETYPE		0x0002
-#define EXT3_FEATURE_INCOMPAT_RECOVER		0x0004
-#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008
-#define EXT2_FEATURE_INCOMPAT_META_BG		0x0010
-#define EXT2_FEATURE_INCOMPAT_ANY		0xffffffff
-
-#define EXT2_FEATURE_COMPAT_SUPP	EXT2_FEATURE_COMPAT_EXT_ATTR
-#define EXT2_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE| \
-					 EXT2_FEATURE_INCOMPAT_META_BG)
-#define EXT2_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
-					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
-					 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
-#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED	~EXT2_FEATURE_RO_COMPAT_SUPP
-#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED	~EXT2_FEATURE_INCOMPAT_SUPP
-
-/*
- * Default values for user and/or group using reserved blocks
- */
-#define	EXT2_DEF_RESUID		0
-#define	EXT2_DEF_RESGID		0
-
-/*
- * Default mount options
- */
-#define EXT2_DEFM_DEBUG		0x0001
-#define EXT2_DEFM_BSDGROUPS	0x0002
-#define EXT2_DEFM_XATTR_USER	0x0004
-#define EXT2_DEFM_ACL		0x0008
-#define EXT2_DEFM_UID16		0x0010
-    /* Not used by ext2, but reserved for use by ext3 */
-#define EXT3_DEFM_JMODE		0x0060 
-#define EXT3_DEFM_JMODE_DATA	0x0020
-#define EXT3_DEFM_JMODE_ORDERED	0x0040
-#define EXT3_DEFM_JMODE_WBACK	0x0060
-
-/*
- * Structure of a directory entry
- */
-#define EXT2_NAME_LEN 255
-
-struct ext2_dir_entry {
-	__le32	inode;			/* Inode number */
-	__le16	rec_len;		/* Directory entry length */
-	__le16	name_len;		/* Name length */
-	char	name[EXT2_NAME_LEN];	/* File name */
-};
-
-/*
- * The new version of the directory entry.  Since EXT2 structures are
- * stored in intel byte order, and the name_len field could never be
- * bigger than 255 chars, it's safe to reclaim the extra byte for the
- * file_type field.
- */
-struct ext2_dir_entry_2 {
-	__le32	inode;			/* Inode number */
-	__le16	rec_len;		/* Directory entry length */
-	__u8	name_len;		/* Name length */
-	__u8	file_type;
-	char	name[EXT2_NAME_LEN];	/* File name */
-};
-
-/*
- * Ext2 directory file types.  Only the low 3 bits are used.  The
- * other bits are reserved for now.
- */
-enum {
-	EXT2_FT_UNKNOWN		= 0,
-	EXT2_FT_REG_FILE	= 1,
-	EXT2_FT_DIR		= 2,
-	EXT2_FT_CHRDEV		= 3,
-	EXT2_FT_BLKDEV		= 4,
-	EXT2_FT_FIFO		= 5,
-	EXT2_FT_SOCK		= 6,
-	EXT2_FT_SYMLINK		= 7,
-	EXT2_FT_MAX
-};
-
-/*
- * EXT2_DIR_PAD defines the directory entries boundaries
- *
- * NOTE: It must be a multiple of 4
- */
-#define EXT2_DIR_PAD		 	4
-#define EXT2_DIR_ROUND 			(EXT2_DIR_PAD - 1)
-#define EXT2_DIR_REC_LEN(name_len)	(((name_len) + 8 + EXT2_DIR_ROUND) & \
-					 ~EXT2_DIR_ROUND)
-#define EXT2_MAX_REC_LEN		((1<<16)-1)
-
 #endif	/* _LINUX_EXT2_FS_H */
diff --git a/include/linux/ext2_fs_sb.h b/include/linux/ext2_fs_sb.h
deleted file mode 100644
index db4d9f5..0000000
--- a/include/linux/ext2_fs_sb.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- *  linux/include/linux/ext2_fs_sb.h
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- *
- *  from
- *
- *  linux/include/linux/minix_fs_sb.h
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-#ifndef _LINUX_EXT2_FS_SB
-#define _LINUX_EXT2_FS_SB
-
-#include <linux/blockgroup_lock.h>
-#include <linux/percpu_counter.h>
-#include <linux/rbtree.h>
-
-/* XXX Here for now... not interested in restructing headers JUST now */
-
-/* data type for block offset of block group */
-typedef int ext2_grpblk_t;
-
-/* data type for filesystem-wide blocks number */
-typedef unsigned long ext2_fsblk_t;
-
-#define E2FSBLK "%lu"
-
-struct ext2_reserve_window {
-	ext2_fsblk_t		_rsv_start;	/* First byte reserved */
-	ext2_fsblk_t		_rsv_end;	/* Last byte reserved or 0 */
-};
-
-struct ext2_reserve_window_node {
-	struct rb_node	 	rsv_node;
-	__u32			rsv_goal_size;
-	__u32			rsv_alloc_hit;
-	struct ext2_reserve_window	rsv_window;
-};
-
-struct ext2_block_alloc_info {
-	/* information about reservation window */
-	struct ext2_reserve_window_node	rsv_window_node;
-	/*
-	 * was i_next_alloc_block in ext2_inode_info
-	 * is the logical (file-relative) number of the
-	 * most-recently-allocated block in this file.
-	 * We use this for detecting linearly ascending allocation requests.
-	 */
-	__u32			last_alloc_logical_block;
-	/*
-	 * Was i_next_alloc_goal in ext2_inode_info
-	 * is the *physical* companion to i_next_alloc_block.
-	 * it the the physical block number of the block which was most-recentl
-	 * allocated to this file.  This give us the goal (target) for the next
-	 * allocation when we detect linearly ascending requests.
-	 */
-	ext2_fsblk_t		last_alloc_physical_block;
-};
-
-#define rsv_start rsv_window._rsv_start
-#define rsv_end rsv_window._rsv_end
-
-/*
- * second extended-fs super-block data in memory
- */
-struct ext2_sb_info {
-	unsigned long s_frag_size;	/* Size of a fragment in bytes */
-	unsigned long s_frags_per_block;/* Number of fragments per block */
-	unsigned long s_inodes_per_block;/* Number of inodes per block */
-	unsigned long s_frags_per_group;/* Number of fragments in a group */
-	unsigned long s_blocks_per_group;/* Number of blocks in a group */
-	unsigned long s_inodes_per_group;/* Number of inodes in a group */
-	unsigned long s_itb_per_group;	/* Number of inode table blocks per group */
-	unsigned long s_gdb_count;	/* Number of group descriptor blocks */
-	unsigned long s_desc_per_block;	/* Number of group descriptors per block */
-	unsigned long s_groups_count;	/* Number of groups in the fs */
-	unsigned long s_overhead_last;  /* Last calculated overhead */
-	unsigned long s_blocks_last;    /* Last seen block count */
-	struct buffer_head * s_sbh;	/* Buffer containing the super block */
-	struct ext2_super_block * s_es;	/* Pointer to the super block in the buffer */
-	struct buffer_head ** s_group_desc;
-	unsigned long  s_mount_opt;
-	unsigned long s_sb_block;
-	uid_t s_resuid;
-	gid_t s_resgid;
-	unsigned short s_mount_state;
-	unsigned short s_pad;
-	int s_addr_per_block_bits;
-	int s_desc_per_block_bits;
-	int s_inode_size;
-	int s_first_ino;
-	spinlock_t s_next_gen_lock;
-	u32 s_next_generation;
-	unsigned long s_dir_count;
-	u8 *s_debts;
-	struct percpu_counter s_freeblocks_counter;
-	struct percpu_counter s_freeinodes_counter;
-	struct percpu_counter s_dirs_counter;
-	struct blockgroup_lock *s_blockgroup_lock;
-	/* root of the per fs reservation window tree */
-	spinlock_t s_rsv_window_lock;
-	struct rb_root s_rsv_window_root;
-	struct ext2_reserve_window_node s_rsv_window_head;
-	/*
-	 * s_lock protects against concurrent modifications of s_mount_state,
-	 * s_blocks_last, s_overhead_last and the content of superblock's
-	 * buffer pointed to by sbi->s_es.
-	 *
-	 * Note: It is used in ext2_show_options() to provide a consistent view
-	 * of the mount options.
-	 */
-	spinlock_t s_lock;
-};
-
-static inline spinlock_t *
-sb_bgl_lock(struct ext2_sb_info *sbi, unsigned int block_group)
-{
-	return bgl_lock_ptr(sbi->s_blockgroup_lock, block_group);
-}
-
-#endif	/* _LINUX_EXT2_FS_SB */
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
deleted file mode 100644
index f957085..0000000
--- a/include/linux/ext3_fs.h
+++ /dev/null
@@ -1,979 +0,0 @@
-/*
- *  linux/include/linux/ext3_fs.h
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- *
- *  from
- *
- *  linux/include/linux/minix_fs.h
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-#ifndef _LINUX_EXT3_FS_H
-#define _LINUX_EXT3_FS_H
-
-#include <linux/types.h>
-#include <linux/magic.h>
-
-/*
- * The second extended filesystem constants/structures
- */
-
-/*
- * Define EXT3FS_DEBUG to produce debug messages
- */
-#undef EXT3FS_DEBUG
-
-/*
- * Define EXT3_RESERVATION to reserve data blocks for expanding files
- */
-#define EXT3_DEFAULT_RESERVE_BLOCKS     8
-/*max window size: 1024(direct blocks) + 3([t,d]indirect blocks) */
-#define EXT3_MAX_RESERVE_BLOCKS         1027
-#define EXT3_RESERVE_WINDOW_NOT_ALLOCATED 0
-
-/*
- * Debug code
- */
-#ifdef EXT3FS_DEBUG
-#define ext3_debug(f, a...)						\
-	do {								\
-		printk (KERN_DEBUG "EXT3-fs DEBUG (%s, %d): %s:",	\
-			__FILE__, __LINE__, __func__);		\
-		printk (KERN_DEBUG f, ## a);				\
-	} while (0)
-#else
-#define ext3_debug(f, a...)	do {} while (0)
-#endif
-
-/*
- * Special inodes numbers
- */
-#define	EXT3_BAD_INO		 1	/* Bad blocks inode */
-#define EXT3_ROOT_INO		 2	/* Root inode */
-#define EXT3_BOOT_LOADER_INO	 5	/* Boot loader inode */
-#define EXT3_UNDEL_DIR_INO	 6	/* Undelete directory inode */
-#define EXT3_RESIZE_INO		 7	/* Reserved group descriptors inode */
-#define EXT3_JOURNAL_INO	 8	/* Journal inode */
-
-/* First non-reserved inode for old ext3 filesystems */
-#define EXT3_GOOD_OLD_FIRST_INO	11
-
-/*
- * Maximal count of links to a file
- */
-#define EXT3_LINK_MAX		32000
-
-/*
- * Macro-instructions used to manage several block sizes
- */
-#define EXT3_MIN_BLOCK_SIZE		1024
-#define	EXT3_MAX_BLOCK_SIZE		65536
-#define EXT3_MIN_BLOCK_LOG_SIZE		10
-#ifdef __KERNEL__
-# define EXT3_BLOCK_SIZE(s)		((s)->s_blocksize)
-#else
-# define EXT3_BLOCK_SIZE(s)		(EXT3_MIN_BLOCK_SIZE << (s)->s_log_block_size)
-#endif
-#define	EXT3_ADDR_PER_BLOCK(s)		(EXT3_BLOCK_SIZE(s) / sizeof (__u32))
-#ifdef __KERNEL__
-# define EXT3_BLOCK_SIZE_BITS(s)	((s)->s_blocksize_bits)
-#else
-# define EXT3_BLOCK_SIZE_BITS(s)	((s)->s_log_block_size + 10)
-#endif
-#ifdef __KERNEL__
-#define	EXT3_ADDR_PER_BLOCK_BITS(s)	(EXT3_SB(s)->s_addr_per_block_bits)
-#define EXT3_INODE_SIZE(s)		(EXT3_SB(s)->s_inode_size)
-#define EXT3_FIRST_INO(s)		(EXT3_SB(s)->s_first_ino)
-#else
-#define EXT3_INODE_SIZE(s)	(((s)->s_rev_level == EXT3_GOOD_OLD_REV) ? \
-				 EXT3_GOOD_OLD_INODE_SIZE : \
-				 (s)->s_inode_size)
-#define EXT3_FIRST_INO(s)	(((s)->s_rev_level == EXT3_GOOD_OLD_REV) ? \
-				 EXT3_GOOD_OLD_FIRST_INO : \
-				 (s)->s_first_ino)
-#endif
-
-/*
- * Macro-instructions used to manage fragments
- */
-#define EXT3_MIN_FRAG_SIZE		1024
-#define	EXT3_MAX_FRAG_SIZE		4096
-#define EXT3_MIN_FRAG_LOG_SIZE		  10
-#ifdef __KERNEL__
-# define EXT3_FRAG_SIZE(s)		(EXT3_SB(s)->s_frag_size)
-# define EXT3_FRAGS_PER_BLOCK(s)	(EXT3_SB(s)->s_frags_per_block)
-#else
-# define EXT3_FRAG_SIZE(s)		(EXT3_MIN_FRAG_SIZE << (s)->s_log_frag_size)
-# define EXT3_FRAGS_PER_BLOCK(s)	(EXT3_BLOCK_SIZE(s) / EXT3_FRAG_SIZE(s))
-#endif
-
-/*
- * Structure of a blocks group descriptor
- */
-struct ext3_group_desc
-{
-	__le32	bg_block_bitmap;		/* Blocks bitmap block */
-	__le32	bg_inode_bitmap;		/* Inodes bitmap block */
-	__le32	bg_inode_table;		/* Inodes table block */
-	__le16	bg_free_blocks_count;	/* Free blocks count */
-	__le16	bg_free_inodes_count;	/* Free inodes count */
-	__le16	bg_used_dirs_count;	/* Directories count */
-	__u16	bg_pad;
-	__le32	bg_reserved[3];
-};
-
-/*
- * Macro-instructions used to manage group descriptors
- */
-#ifdef __KERNEL__
-# define EXT3_BLOCKS_PER_GROUP(s)	(EXT3_SB(s)->s_blocks_per_group)
-# define EXT3_DESC_PER_BLOCK(s)		(EXT3_SB(s)->s_desc_per_block)
-# define EXT3_INODES_PER_GROUP(s)	(EXT3_SB(s)->s_inodes_per_group)
-# define EXT3_DESC_PER_BLOCK_BITS(s)	(EXT3_SB(s)->s_desc_per_block_bits)
-#else
-# define EXT3_BLOCKS_PER_GROUP(s)	((s)->s_blocks_per_group)
-# define EXT3_DESC_PER_BLOCK(s)		(EXT3_BLOCK_SIZE(s) / sizeof (struct ext3_group_desc))
-# define EXT3_INODES_PER_GROUP(s)	((s)->s_inodes_per_group)
-#endif
-
-/*
- * Constants relative to the data blocks
- */
-#define	EXT3_NDIR_BLOCKS		12
-#define	EXT3_IND_BLOCK			EXT3_NDIR_BLOCKS
-#define	EXT3_DIND_BLOCK			(EXT3_IND_BLOCK + 1)
-#define	EXT3_TIND_BLOCK			(EXT3_DIND_BLOCK + 1)
-#define	EXT3_N_BLOCKS			(EXT3_TIND_BLOCK + 1)
-
-/*
- * Inode flags
- */
-#define	EXT3_SECRM_FL			0x00000001 /* Secure deletion */
-#define	EXT3_UNRM_FL			0x00000002 /* Undelete */
-#define	EXT3_COMPR_FL			0x00000004 /* Compress file */
-#define EXT3_SYNC_FL			0x00000008 /* Synchronous updates */
-#define EXT3_IMMUTABLE_FL		0x00000010 /* Immutable file */
-#define EXT3_APPEND_FL			0x00000020 /* writes to file may only append */
-#define EXT3_NODUMP_FL			0x00000040 /* do not dump file */
-#define EXT3_NOATIME_FL			0x00000080 /* do not update atime */
-/* Reserved for compression usage... */
-#define EXT3_DIRTY_FL			0x00000100
-#define EXT3_COMPRBLK_FL		0x00000200 /* One or more compressed clusters */
-#define EXT3_NOCOMPR_FL			0x00000400 /* Don't compress */
-#define EXT3_ECOMPR_FL			0x00000800 /* Compression error */
-/* End compression flags --- maybe not all used */
-#define EXT3_INDEX_FL			0x00001000 /* hash-indexed directory */
-#define EXT3_IMAGIC_FL			0x00002000 /* AFS directory */
-#define EXT3_JOURNAL_DATA_FL		0x00004000 /* file data should be journaled */
-#define EXT3_NOTAIL_FL			0x00008000 /* file tail should not be merged */
-#define EXT3_DIRSYNC_FL			0x00010000 /* dirsync behaviour (directories only) */
-#define EXT3_TOPDIR_FL			0x00020000 /* Top of directory hierarchies*/
-#define EXT3_RESERVED_FL		0x80000000 /* reserved for ext3 lib */
-
-#define EXT3_FL_USER_VISIBLE		0x0003DFFF /* User visible flags */
-#define EXT3_FL_USER_MODIFIABLE		0x000380FF /* User modifiable flags */
-
-/* Flags that should be inherited by new inodes from their parent. */
-#define EXT3_FL_INHERITED (EXT3_SECRM_FL | EXT3_UNRM_FL | EXT3_COMPR_FL |\
-			   EXT3_SYNC_FL | EXT3_NODUMP_FL |\
-			   EXT3_NOATIME_FL | EXT3_COMPRBLK_FL |\
-			   EXT3_NOCOMPR_FL | EXT3_JOURNAL_DATA_FL |\
-			   EXT3_NOTAIL_FL | EXT3_DIRSYNC_FL)
-
-/* Flags that are appropriate for regular files (all but dir-specific ones). */
-#define EXT3_REG_FLMASK (~(EXT3_DIRSYNC_FL | EXT3_TOPDIR_FL))
-
-/* Flags that are appropriate for non-directories/regular files. */
-#define EXT3_OTHER_FLMASK (EXT3_NODUMP_FL | EXT3_NOATIME_FL)
-
-/* Mask out flags that are inappropriate for the given type of inode. */
-static inline __u32 ext3_mask_flags(umode_t mode, __u32 flags)
-{
-	if (S_ISDIR(mode))
-		return flags;
-	else if (S_ISREG(mode))
-		return flags & EXT3_REG_FLMASK;
-	else
-		return flags & EXT3_OTHER_FLMASK;
-}
-
-/* Used to pass group descriptor data when online resize is done */
-struct ext3_new_group_input {
-	__u32 group;            /* Group number for this data */
-	__u32 block_bitmap;     /* Absolute block number of block bitmap */
-	__u32 inode_bitmap;     /* Absolute block number of inode bitmap */
-	__u32 inode_table;      /* Absolute block number of inode table start */
-	__u32 blocks_count;     /* Total number of blocks in this group */
-	__u16 reserved_blocks;  /* Number of reserved blocks in this group */
-	__u16 unused;
-};
-
-/* The struct ext3_new_group_input in kernel space, with free_blocks_count */
-struct ext3_new_group_data {
-	__u32 group;
-	__u32 block_bitmap;
-	__u32 inode_bitmap;
-	__u32 inode_table;
-	__u32 blocks_count;
-	__u16 reserved_blocks;
-	__u16 unused;
-	__u32 free_blocks_count;
-};
-
-
-/*
- * ioctl commands
- */
-#define	EXT3_IOC_GETFLAGS		FS_IOC_GETFLAGS
-#define	EXT3_IOC_SETFLAGS		FS_IOC_SETFLAGS
-#define	EXT3_IOC_GETVERSION		_IOR('f', 3, long)
-#define	EXT3_IOC_SETVERSION		_IOW('f', 4, long)
-#define EXT3_IOC_GROUP_EXTEND		_IOW('f', 7, unsigned long)
-#define EXT3_IOC_GROUP_ADD		_IOW('f', 8,struct ext3_new_group_input)
-#define	EXT3_IOC_GETVERSION_OLD		FS_IOC_GETVERSION
-#define	EXT3_IOC_SETVERSION_OLD		FS_IOC_SETVERSION
-#ifdef CONFIG_JBD_DEBUG
-#define EXT3_IOC_WAIT_FOR_READONLY	_IOR('f', 99, long)
-#endif
-#define EXT3_IOC_GETRSVSZ		_IOR('f', 5, long)
-#define EXT3_IOC_SETRSVSZ		_IOW('f', 6, long)
-
-/*
- * ioctl commands in 32 bit emulation
- */
-#define EXT3_IOC32_GETFLAGS		FS_IOC32_GETFLAGS
-#define EXT3_IOC32_SETFLAGS		FS_IOC32_SETFLAGS
-#define EXT3_IOC32_GETVERSION		_IOR('f', 3, int)
-#define EXT3_IOC32_SETVERSION		_IOW('f', 4, int)
-#define EXT3_IOC32_GETRSVSZ		_IOR('f', 5, int)
-#define EXT3_IOC32_SETRSVSZ		_IOW('f', 6, int)
-#define EXT3_IOC32_GROUP_EXTEND		_IOW('f', 7, unsigned int)
-#ifdef CONFIG_JBD_DEBUG
-#define EXT3_IOC32_WAIT_FOR_READONLY	_IOR('f', 99, int)
-#endif
-#define EXT3_IOC32_GETVERSION_OLD	FS_IOC32_GETVERSION
-#define EXT3_IOC32_SETVERSION_OLD	FS_IOC32_SETVERSION
-
-
-/*
- *  Mount options
- */
-struct ext3_mount_options {
-	unsigned long s_mount_opt;
-	uid_t s_resuid;
-	gid_t s_resgid;
-	unsigned long s_commit_interval;
-#ifdef CONFIG_QUOTA
-	int s_jquota_fmt;
-	char *s_qf_names[MAXQUOTAS];
-#endif
-};
-
-/*
- * Structure of an inode on the disk
- */
-struct ext3_inode {
-	__le16	i_mode;		/* File mode */
-	__le16	i_uid;		/* Low 16 bits of Owner Uid */
-	__le32	i_size;		/* Size in bytes */
-	__le32	i_atime;	/* Access time */
-	__le32	i_ctime;	/* Creation time */
-	__le32	i_mtime;	/* Modification time */
-	__le32	i_dtime;	/* Deletion Time */
-	__le16	i_gid;		/* Low 16 bits of Group Id */
-	__le16	i_links_count;	/* Links count */
-	__le32	i_blocks;	/* Blocks count */
-	__le32	i_flags;	/* File flags */
-	union {
-		struct {
-			__u32  l_i_reserved1;
-		} linux1;
-		struct {
-			__u32  h_i_translator;
-		} hurd1;
-		struct {
-			__u32  m_i_reserved1;
-		} masix1;
-	} osd1;				/* OS dependent 1 */
-	__le32	i_block[EXT3_N_BLOCKS];/* Pointers to blocks */
-	__le32	i_generation;	/* File version (for NFS) */
-	__le32	i_file_acl;	/* File ACL */
-	__le32	i_dir_acl;	/* Directory ACL */
-	__le32	i_faddr;	/* Fragment address */
-	union {
-		struct {
-			__u8	l_i_frag;	/* Fragment number */
-			__u8	l_i_fsize;	/* Fragment size */
-			__u16	i_pad1;
-			__le16	l_i_uid_high;	/* these 2 fields    */
-			__le16	l_i_gid_high;	/* were reserved2[0] */
-			__u32	l_i_reserved2;
-		} linux2;
-		struct {
-			__u8	h_i_frag;	/* Fragment number */
-			__u8	h_i_fsize;	/* Fragment size */
-			__u16	h_i_mode_high;
-			__u16	h_i_uid_high;
-			__u16	h_i_gid_high;
-			__u32	h_i_author;
-		} hurd2;
-		struct {
-			__u8	m_i_frag;	/* Fragment number */
-			__u8	m_i_fsize;	/* Fragment size */
-			__u16	m_pad1;
-			__u32	m_i_reserved2[2];
-		} masix2;
-	} osd2;				/* OS dependent 2 */
-	__le16	i_extra_isize;
-	__le16	i_pad1;
-};
-
-#define i_size_high	i_dir_acl
-
-#if defined(__KERNEL__) || defined(__linux__)
-#define i_reserved1	osd1.linux1.l_i_reserved1
-#define i_frag		osd2.linux2.l_i_frag
-#define i_fsize		osd2.linux2.l_i_fsize
-#define i_uid_low	i_uid
-#define i_gid_low	i_gid
-#define i_uid_high	osd2.linux2.l_i_uid_high
-#define i_gid_high	osd2.linux2.l_i_gid_high
-#define i_reserved2	osd2.linux2.l_i_reserved2
-
-#elif defined(__GNU__)
-
-#define i_translator	osd1.hurd1.h_i_translator
-#define i_frag		osd2.hurd2.h_i_frag;
-#define i_fsize		osd2.hurd2.h_i_fsize;
-#define i_uid_high	osd2.hurd2.h_i_uid_high
-#define i_gid_high	osd2.hurd2.h_i_gid_high
-#define i_author	osd2.hurd2.h_i_author
-
-#elif defined(__masix__)
-
-#define i_reserved1	osd1.masix1.m_i_reserved1
-#define i_frag		osd2.masix2.m_i_frag
-#define i_fsize		osd2.masix2.m_i_fsize
-#define i_reserved2	osd2.masix2.m_i_reserved2
-
-#endif /* defined(__KERNEL__) || defined(__linux__) */
-
-/*
- * File system states
- */
-#define	EXT3_VALID_FS			0x0001	/* Unmounted cleanly */
-#define	EXT3_ERROR_FS			0x0002	/* Errors detected */
-#define	EXT3_ORPHAN_FS			0x0004	/* Orphans being recovered */
-
-/*
- * Misc. filesystem flags
- */
-#define EXT2_FLAGS_SIGNED_HASH		0x0001  /* Signed dirhash in use */
-#define EXT2_FLAGS_UNSIGNED_HASH	0x0002  /* Unsigned dirhash in use */
-#define EXT2_FLAGS_TEST_FILESYS		0x0004	/* to test development code */
-
-/*
- * Mount flags
- */
-#define EXT3_MOUNT_CHECK		0x00001	/* Do mount-time checks */
-/* EXT3_MOUNT_OLDALLOC was there */
-#define EXT3_MOUNT_GRPID		0x00004	/* Create files with directory's group */
-#define EXT3_MOUNT_DEBUG		0x00008	/* Some debugging messages */
-#define EXT3_MOUNT_ERRORS_CONT		0x00010	/* Continue on errors */
-#define EXT3_MOUNT_ERRORS_RO		0x00020	/* Remount fs ro on errors */
-#define EXT3_MOUNT_ERRORS_PANIC		0x00040	/* Panic on errors */
-#define EXT3_MOUNT_MINIX_DF		0x00080	/* Mimics the Minix statfs */
-#define EXT3_MOUNT_NOLOAD		0x00100	/* Don't use existing journal*/
-#define EXT3_MOUNT_ABORT		0x00200	/* Fatal error detected */
-#define EXT3_MOUNT_DATA_FLAGS		0x00C00	/* Mode for data writes: */
-#define EXT3_MOUNT_JOURNAL_DATA		0x00400	/* Write data to journal */
-#define EXT3_MOUNT_ORDERED_DATA		0x00800	/* Flush data before commit */
-#define EXT3_MOUNT_WRITEBACK_DATA	0x00C00	/* No data ordering */
-#define EXT3_MOUNT_UPDATE_JOURNAL	0x01000	/* Update the journal format */
-#define EXT3_MOUNT_NO_UID32		0x02000  /* Disable 32-bit UIDs */
-#define EXT3_MOUNT_XATTR_USER		0x04000	/* Extended user attributes */
-#define EXT3_MOUNT_POSIX_ACL		0x08000	/* POSIX Access Control Lists */
-#define EXT3_MOUNT_RESERVATION		0x10000	/* Preallocation */
-#define EXT3_MOUNT_BARRIER		0x20000 /* Use block barriers */
-#define EXT3_MOUNT_QUOTA		0x80000 /* Some quota option set */
-#define EXT3_MOUNT_USRQUOTA		0x100000 /* "old" user quota */
-#define EXT3_MOUNT_GRPQUOTA		0x200000 /* "old" group quota */
-#define EXT3_MOUNT_DATA_ERR_ABORT	0x400000 /* Abort on file data write
-						  * error in ordered mode */
-
-/* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
-#ifndef _LINUX_EXT2_FS_H
-#define clear_opt(o, opt)		o &= ~EXT3_MOUNT_##opt
-#define set_opt(o, opt)			o |= EXT3_MOUNT_##opt
-#define test_opt(sb, opt)		(EXT3_SB(sb)->s_mount_opt & \
-					 EXT3_MOUNT_##opt)
-#else
-#define EXT2_MOUNT_NOLOAD		EXT3_MOUNT_NOLOAD
-#define EXT2_MOUNT_ABORT		EXT3_MOUNT_ABORT
-#define EXT2_MOUNT_DATA_FLAGS		EXT3_MOUNT_DATA_FLAGS
-#endif
-
-#define ext3_set_bit			__set_bit_le
-#define ext3_set_bit_atomic		ext2_set_bit_atomic
-#define ext3_clear_bit			__clear_bit_le
-#define ext3_clear_bit_atomic		ext2_clear_bit_atomic
-#define ext3_test_bit			test_bit_le
-#define ext3_find_next_zero_bit		find_next_zero_bit_le
-
-/*
- * Maximal mount counts between two filesystem checks
- */
-#define EXT3_DFL_MAX_MNT_COUNT		20	/* Allow 20 mounts */
-#define EXT3_DFL_CHECKINTERVAL		0	/* Don't use interval check */
-
-/*
- * Behaviour when detecting errors
- */
-#define EXT3_ERRORS_CONTINUE		1	/* Continue execution */
-#define EXT3_ERRORS_RO			2	/* Remount fs read-only */
-#define EXT3_ERRORS_PANIC		3	/* Panic */
-#define EXT3_ERRORS_DEFAULT		EXT3_ERRORS_CONTINUE
-
-/*
- * Structure of the super block
- */
-struct ext3_super_block {
-/*00*/	__le32	s_inodes_count;		/* Inodes count */
-	__le32	s_blocks_count;		/* Blocks count */
-	__le32	s_r_blocks_count;	/* Reserved blocks count */
-	__le32	s_free_blocks_count;	/* Free blocks count */
-/*10*/	__le32	s_free_inodes_count;	/* Free inodes count */
-	__le32	s_first_data_block;	/* First Data Block */
-	__le32	s_log_block_size;	/* Block size */
-	__le32	s_log_frag_size;	/* Fragment size */
-/*20*/	__le32	s_blocks_per_group;	/* # Blocks per group */
-	__le32	s_frags_per_group;	/* # Fragments per group */
-	__le32	s_inodes_per_group;	/* # Inodes per group */
-	__le32	s_mtime;		/* Mount time */
-/*30*/	__le32	s_wtime;		/* Write time */
-	__le16	s_mnt_count;		/* Mount count */
-	__le16	s_max_mnt_count;	/* Maximal mount count */
-	__le16	s_magic;		/* Magic signature */
-	__le16	s_state;		/* File system state */
-	__le16	s_errors;		/* Behaviour when detecting errors */
-	__le16	s_minor_rev_level;	/* minor revision level */
-/*40*/	__le32	s_lastcheck;		/* time of last check */
-	__le32	s_checkinterval;	/* max. time between checks */
-	__le32	s_creator_os;		/* OS */
-	__le32	s_rev_level;		/* Revision level */
-/*50*/	__le16	s_def_resuid;		/* Default uid for reserved blocks */
-	__le16	s_def_resgid;		/* Default gid for reserved blocks */
-	/*
-	 * These fields are for EXT3_DYNAMIC_REV superblocks only.
-	 *
-	 * Note: the difference between the compatible feature set and
-	 * the incompatible feature set is that if there is a bit set
-	 * in the incompatible feature set that the kernel doesn't
-	 * know about, it should refuse to mount the filesystem.
-	 *
-	 * e2fsck's requirements are more strict; if it doesn't know
-	 * about a feature in either the compatible or incompatible
-	 * feature set, it must abort and not try to meddle with
-	 * things it doesn't understand...
-	 */
-	__le32	s_first_ino;		/* First non-reserved inode */
-	__le16   s_inode_size;		/* size of inode structure */
-	__le16	s_block_group_nr;	/* block group # of this superblock */
-	__le32	s_feature_compat;	/* compatible feature set */
-/*60*/	__le32	s_feature_incompat;	/* incompatible feature set */
-	__le32	s_feature_ro_compat;	/* readonly-compatible feature set */
-/*68*/	__u8	s_uuid[16];		/* 128-bit uuid for volume */
-/*78*/	char	s_volume_name[16];	/* volume name */
-/*88*/	char	s_last_mounted[64];	/* directory where last mounted */
-/*C8*/	__le32	s_algorithm_usage_bitmap; /* For compression */
-	/*
-	 * Performance hints.  Directory preallocation should only
-	 * happen if the EXT3_FEATURE_COMPAT_DIR_PREALLOC flag is on.
-	 */
-	__u8	s_prealloc_blocks;	/* Nr of blocks to try to preallocate*/
-	__u8	s_prealloc_dir_blocks;	/* Nr to preallocate for dirs */
-	__le16	s_reserved_gdt_blocks;	/* Per group desc for online growth */
-	/*
-	 * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
-	 */
-/*D0*/	__u8	s_journal_uuid[16];	/* uuid of journal superblock */
-/*E0*/	__le32	s_journal_inum;		/* inode number of journal file */
-	__le32	s_journal_dev;		/* device number of journal file */
-	__le32	s_last_orphan;		/* start of list of inodes to delete */
-	__le32	s_hash_seed[4];		/* HTREE hash seed */
-	__u8	s_def_hash_version;	/* Default hash version to use */
-	__u8	s_reserved_char_pad;
-	__u16	s_reserved_word_pad;
-	__le32	s_default_mount_opts;
-	__le32	s_first_meta_bg;	/* First metablock block group */
-	__le32	s_mkfs_time;		/* When the filesystem was created */
-	__le32	s_jnl_blocks[17];	/* Backup of the journal inode */
-	/* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
-/*150*/	__le32	s_blocks_count_hi;	/* Blocks count */
-	__le32	s_r_blocks_count_hi;	/* Reserved blocks count */
-	__le32	s_free_blocks_count_hi;	/* Free blocks count */
-	__le16	s_min_extra_isize;	/* All inodes have at least # bytes */
-	__le16	s_want_extra_isize; 	/* New inodes should reserve # bytes */
-	__le32	s_flags;		/* Miscellaneous flags */
-	__le16  s_raid_stride;		/* RAID stride */
-	__le16  s_mmp_interval;         /* # seconds to wait in MMP checking */
-	__le64  s_mmp_block;            /* Block for multi-mount protection */
-	__le32  s_raid_stripe_width;    /* blocks on all data disks (N*stride)*/
-	__u8	s_log_groups_per_flex;  /* FLEX_BG group size */
-	__u8	s_reserved_char_pad2;
-	__le16  s_reserved_pad;
-	__u32   s_reserved[162];        /* Padding to the end of the block */
-};
-
-#ifdef __KERNEL__
-#include <linux/ext3_fs_i.h>
-#include <linux/ext3_fs_sb.h>
-static inline struct ext3_sb_info * EXT3_SB(struct super_block *sb)
-{
-	return sb->s_fs_info;
-}
-static inline struct ext3_inode_info *EXT3_I(struct inode *inode)
-{
-	return container_of(inode, struct ext3_inode_info, vfs_inode);
-}
-
-static inline int ext3_valid_inum(struct super_block *sb, unsigned long ino)
-{
-	return ino == EXT3_ROOT_INO ||
-		ino == EXT3_JOURNAL_INO ||
-		ino == EXT3_RESIZE_INO ||
-		(ino >= EXT3_FIRST_INO(sb) &&
-		 ino <= le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count));
-}
-
-/*
- * Inode dynamic state flags
- */
-enum {
-	EXT3_STATE_JDATA,		/* journaled data exists */
-	EXT3_STATE_NEW,			/* inode is newly created */
-	EXT3_STATE_XATTR,		/* has in-inode xattrs */
-	EXT3_STATE_FLUSH_ON_CLOSE,	/* flush dirty pages on close */
-};
-
-static inline int ext3_test_inode_state(struct inode *inode, int bit)
-{
-	return test_bit(bit, &EXT3_I(inode)->i_state_flags);
-}
-
-static inline void ext3_set_inode_state(struct inode *inode, int bit)
-{
-	set_bit(bit, &EXT3_I(inode)->i_state_flags);
-}
-
-static inline void ext3_clear_inode_state(struct inode *inode, int bit)
-{
-	clear_bit(bit, &EXT3_I(inode)->i_state_flags);
-}
-#else
-/* Assume that user mode programs are passing in an ext3fs superblock, not
- * a kernel struct super_block.  This will allow us to call the feature-test
- * macros from user land. */
-#define EXT3_SB(sb)	(sb)
-#endif
-
-#define NEXT_ORPHAN(inode) EXT3_I(inode)->i_dtime
-
-/*
- * Codes for operating systems
- */
-#define EXT3_OS_LINUX		0
-#define EXT3_OS_HURD		1
-#define EXT3_OS_MASIX		2
-#define EXT3_OS_FREEBSD		3
-#define EXT3_OS_LITES		4
-
-/*
- * Revision levels
- */
-#define EXT3_GOOD_OLD_REV	0	/* The good old (original) format */
-#define EXT3_DYNAMIC_REV	1	/* V2 format w/ dynamic inode sizes */
-
-#define EXT3_CURRENT_REV	EXT3_GOOD_OLD_REV
-#define EXT3_MAX_SUPP_REV	EXT3_DYNAMIC_REV
-
-#define EXT3_GOOD_OLD_INODE_SIZE 128
-
-/*
- * Feature set definitions
- */
-
-#define EXT3_HAS_COMPAT_FEATURE(sb,mask)			\
-	( EXT3_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
-#define EXT3_HAS_RO_COMPAT_FEATURE(sb,mask)			\
-	( EXT3_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
-#define EXT3_HAS_INCOMPAT_FEATURE(sb,mask)			\
-	( EXT3_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
-#define EXT3_SET_COMPAT_FEATURE(sb,mask)			\
-	EXT3_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
-#define EXT3_SET_RO_COMPAT_FEATURE(sb,mask)			\
-	EXT3_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
-#define EXT3_SET_INCOMPAT_FEATURE(sb,mask)			\
-	EXT3_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
-#define EXT3_CLEAR_COMPAT_FEATURE(sb,mask)			\
-	EXT3_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
-#define EXT3_CLEAR_RO_COMPAT_FEATURE(sb,mask)			\
-	EXT3_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
-#define EXT3_CLEAR_INCOMPAT_FEATURE(sb,mask)			\
-	EXT3_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
-
-#define EXT3_FEATURE_COMPAT_DIR_PREALLOC	0x0001
-#define EXT3_FEATURE_COMPAT_IMAGIC_INODES	0x0002
-#define EXT3_FEATURE_COMPAT_HAS_JOURNAL		0x0004
-#define EXT3_FEATURE_COMPAT_EXT_ATTR		0x0008
-#define EXT3_FEATURE_COMPAT_RESIZE_INODE	0x0010
-#define EXT3_FEATURE_COMPAT_DIR_INDEX		0x0020
-
-#define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
-#define EXT3_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
-#define EXT3_FEATURE_RO_COMPAT_BTREE_DIR	0x0004
-
-#define EXT3_FEATURE_INCOMPAT_COMPRESSION	0x0001
-#define EXT3_FEATURE_INCOMPAT_FILETYPE		0x0002
-#define EXT3_FEATURE_INCOMPAT_RECOVER		0x0004 /* Needs recovery */
-#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008 /* Journal device */
-#define EXT3_FEATURE_INCOMPAT_META_BG		0x0010
-
-#define EXT3_FEATURE_COMPAT_SUPP	EXT2_FEATURE_COMPAT_EXT_ATTR
-#define EXT3_FEATURE_INCOMPAT_SUPP	(EXT3_FEATURE_INCOMPAT_FILETYPE| \
-					 EXT3_FEATURE_INCOMPAT_RECOVER| \
-					 EXT3_FEATURE_INCOMPAT_META_BG)
-#define EXT3_FEATURE_RO_COMPAT_SUPP	(EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
-					 EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \
-					 EXT3_FEATURE_RO_COMPAT_BTREE_DIR)
-
-/*
- * Default values for user and/or group using reserved blocks
- */
-#define	EXT3_DEF_RESUID		0
-#define	EXT3_DEF_RESGID		0
-
-/*
- * Default mount options
- */
-#define EXT3_DEFM_DEBUG		0x0001
-#define EXT3_DEFM_BSDGROUPS	0x0002
-#define EXT3_DEFM_XATTR_USER	0x0004
-#define EXT3_DEFM_ACL		0x0008
-#define EXT3_DEFM_UID16		0x0010
-#define EXT3_DEFM_JMODE		0x0060
-#define EXT3_DEFM_JMODE_DATA	0x0020
-#define EXT3_DEFM_JMODE_ORDERED	0x0040
-#define EXT3_DEFM_JMODE_WBACK	0x0060
-
-/*
- * Structure of a directory entry
- */
-#define EXT3_NAME_LEN 255
-
-struct ext3_dir_entry {
-	__le32	inode;			/* Inode number */
-	__le16	rec_len;		/* Directory entry length */
-	__le16	name_len;		/* Name length */
-	char	name[EXT3_NAME_LEN];	/* File name */
-};
-
-/*
- * The new version of the directory entry.  Since EXT3 structures are
- * stored in intel byte order, and the name_len field could never be
- * bigger than 255 chars, it's safe to reclaim the extra byte for the
- * file_type field.
- */
-struct ext3_dir_entry_2 {
-	__le32	inode;			/* Inode number */
-	__le16	rec_len;		/* Directory entry length */
-	__u8	name_len;		/* Name length */
-	__u8	file_type;
-	char	name[EXT3_NAME_LEN];	/* File name */
-};
-
-/*
- * Ext3 directory file types.  Only the low 3 bits are used.  The
- * other bits are reserved for now.
- */
-#define EXT3_FT_UNKNOWN		0
-#define EXT3_FT_REG_FILE	1
-#define EXT3_FT_DIR		2
-#define EXT3_FT_CHRDEV		3
-#define EXT3_FT_BLKDEV		4
-#define EXT3_FT_FIFO		5
-#define EXT3_FT_SOCK		6
-#define EXT3_FT_SYMLINK		7
-
-#define EXT3_FT_MAX		8
-
-/*
- * EXT3_DIR_PAD defines the directory entries boundaries
- *
- * NOTE: It must be a multiple of 4
- */
-#define EXT3_DIR_PAD			4
-#define EXT3_DIR_ROUND			(EXT3_DIR_PAD - 1)
-#define EXT3_DIR_REC_LEN(name_len)	(((name_len) + 8 + EXT3_DIR_ROUND) & \
-					 ~EXT3_DIR_ROUND)
-#define EXT3_MAX_REC_LEN		((1<<16)-1)
-
-/*
- * Tests against MAX_REC_LEN etc were put in place for 64k block
- * sizes; if that is not possible on this arch, we can skip
- * those tests and speed things up.
- */
-static inline unsigned ext3_rec_len_from_disk(__le16 dlen)
-{
-	unsigned len = le16_to_cpu(dlen);
-
-#if (PAGE_CACHE_SIZE >= 65536)
-	if (len == EXT3_MAX_REC_LEN)
-		return 1 << 16;
-#endif
-	return len;
-}
-
-static inline __le16 ext3_rec_len_to_disk(unsigned len)
-{
-#if (PAGE_CACHE_SIZE >= 65536)
-	if (len == (1 << 16))
-		return cpu_to_le16(EXT3_MAX_REC_LEN);
-	else if (len > (1 << 16))
-		BUG();
-#endif
-	return cpu_to_le16(len);
-}
-
-/*
- * Hash Tree Directory indexing
- * (c) Daniel Phillips, 2001
- */
-
-#define is_dx(dir) (EXT3_HAS_COMPAT_FEATURE(dir->i_sb, \
-				      EXT3_FEATURE_COMPAT_DIR_INDEX) && \
-		      (EXT3_I(dir)->i_flags & EXT3_INDEX_FL))
-#define EXT3_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT3_LINK_MAX)
-#define EXT3_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1)
-
-/* Legal values for the dx_root hash_version field: */
-
-#define DX_HASH_LEGACY		0
-#define DX_HASH_HALF_MD4	1
-#define DX_HASH_TEA		2
-#define DX_HASH_LEGACY_UNSIGNED	3
-#define DX_HASH_HALF_MD4_UNSIGNED	4
-#define DX_HASH_TEA_UNSIGNED		5
-
-#ifdef __KERNEL__
-
-/* hash info structure used by the directory hash */
-struct dx_hash_info
-{
-	u32		hash;
-	u32		minor_hash;
-	int		hash_version;
-	u32		*seed;
-};
-
-#define EXT3_HTREE_EOF	0x7fffffff
-
-/*
- * Control parameters used by ext3_htree_next_block
- */
-#define HASH_NB_ALWAYS		1
-
-
-/*
- * Describe an inode's exact location on disk and in memory
- */
-struct ext3_iloc
-{
-	struct buffer_head *bh;
-	unsigned long offset;
-	unsigned long block_group;
-};
-
-static inline struct ext3_inode *ext3_raw_inode(struct ext3_iloc *iloc)
-{
-	return (struct ext3_inode *) (iloc->bh->b_data + iloc->offset);
-}
-
-/*
- * This structure is stuffed into the struct file's private_data field
- * for directories.  It is where we put information so that we can do
- * readdir operations in hash tree order.
- */
-struct dir_private_info {
-	struct rb_root	root;
-	struct rb_node	*curr_node;
-	struct fname	*extra_fname;
-	loff_t		last_pos;
-	__u32		curr_hash;
-	__u32		curr_minor_hash;
-	__u32		next_hash;
-};
-
-/* calculate the first block number of the group */
-static inline ext3_fsblk_t
-ext3_group_first_block_no(struct super_block *sb, unsigned long group_no)
-{
-	return group_no * (ext3_fsblk_t)EXT3_BLOCKS_PER_GROUP(sb) +
-		le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block);
-}
-
-/*
- * Special error return code only used by dx_probe() and its callers.
- */
-#define ERR_BAD_DX_DIR	-75000
-
-/*
- * Function prototypes
- */
-
-/*
- * Ok, these declarations are also in <linux/kernel.h> but none of the
- * ext3 source programs needs to include it so they are duplicated here.
- */
-# define NORET_TYPE    /**/
-# define ATTRIB_NORET  __attribute__((noreturn))
-# define NORET_AND     noreturn,
-
-/* balloc.c */
-extern int ext3_bg_has_super(struct super_block *sb, int group);
-extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group);
-extern ext3_fsblk_t ext3_new_block (handle_t *handle, struct inode *inode,
-			ext3_fsblk_t goal, int *errp);
-extern ext3_fsblk_t ext3_new_blocks (handle_t *handle, struct inode *inode,
-			ext3_fsblk_t goal, unsigned long *count, int *errp);
-extern void ext3_free_blocks (handle_t *handle, struct inode *inode,
-			ext3_fsblk_t block, unsigned long count);
-extern void ext3_free_blocks_sb (handle_t *handle, struct super_block *sb,
-				 ext3_fsblk_t block, unsigned long count,
-				unsigned long *pdquot_freed_blocks);
-extern ext3_fsblk_t ext3_count_free_blocks (struct super_block *);
-extern void ext3_check_blocks_bitmap (struct super_block *);
-extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
-						    unsigned int block_group,
-						    struct buffer_head ** bh);
-extern int ext3_should_retry_alloc(struct super_block *sb, int *retries);
-extern void ext3_init_block_alloc_info(struct inode *);
-extern void ext3_rsv_window_add(struct super_block *sb, struct ext3_reserve_window_node *rsv);
-extern int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range);
-
-/* dir.c */
-extern int ext3_check_dir_entry(const char *, struct inode *,
-				struct ext3_dir_entry_2 *,
-				struct buffer_head *, unsigned long);
-extern int ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
-				    __u32 minor_hash,
-				    struct ext3_dir_entry_2 *dirent);
-extern void ext3_htree_free_dir_info(struct dir_private_info *p);
-
-/* fsync.c */
-extern int ext3_sync_file(struct file *, loff_t, loff_t, int);
-
-/* hash.c */
-extern int ext3fs_dirhash(const char *name, int len, struct
-			  dx_hash_info *hinfo);
-
-/* ialloc.c */
-extern struct inode * ext3_new_inode (handle_t *, struct inode *,
-				      const struct qstr *, umode_t);
-extern void ext3_free_inode (handle_t *, struct inode *);
-extern struct inode * ext3_orphan_get (struct super_block *, unsigned long);
-extern unsigned long ext3_count_free_inodes (struct super_block *);
-extern unsigned long ext3_count_dirs (struct super_block *);
-extern void ext3_check_inodes_bitmap (struct super_block *);
-extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
-
-
-/* inode.c */
-int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode,
-		struct buffer_head *bh, ext3_fsblk_t blocknr);
-struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
-struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
-int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
-	sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result,
-	int create);
-
-extern struct inode *ext3_iget(struct super_block *, unsigned long);
-extern int  ext3_write_inode (struct inode *, struct writeback_control *);
-extern int  ext3_setattr (struct dentry *, struct iattr *);
-extern void ext3_evict_inode (struct inode *);
-extern int  ext3_sync_inode (handle_t *, struct inode *);
-extern void ext3_discard_reservation (struct inode *);
-extern void ext3_dirty_inode(struct inode *, int);
-extern int ext3_change_inode_journal_flag(struct inode *, int);
-extern int ext3_get_inode_loc(struct inode *, struct ext3_iloc *);
-extern int ext3_can_truncate(struct inode *inode);
-extern void ext3_truncate(struct inode *inode);
-extern void ext3_set_inode_flags(struct inode *);
-extern void ext3_get_inode_flags(struct ext3_inode_info *);
-extern void ext3_set_aops(struct inode *inode);
-extern int ext3_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
-		       u64 start, u64 len);
-
-/* ioctl.c */
-extern long ext3_ioctl(struct file *, unsigned int, unsigned long);
-extern long ext3_compat_ioctl(struct file *, unsigned int, unsigned long);
-
-/* namei.c */
-extern int ext3_orphan_add(handle_t *, struct inode *);
-extern int ext3_orphan_del(handle_t *, struct inode *);
-extern int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash,
-				__u32 start_minor_hash, __u32 *next_hash);
-
-/* resize.c */
-extern int ext3_group_add(struct super_block *sb,
-				struct ext3_new_group_data *input);
-extern int ext3_group_extend(struct super_block *sb,
-				struct ext3_super_block *es,
-				ext3_fsblk_t n_blocks_count);
-
-/* super.c */
-extern __printf(3, 4)
-void ext3_error(struct super_block *, const char *, const char *, ...);
-extern void __ext3_std_error (struct super_block *, const char *, int);
-extern __printf(3, 4)
-void ext3_abort(struct super_block *, const char *, const char *, ...);
-extern __printf(3, 4)
-void ext3_warning(struct super_block *, const char *, const char *, ...);
-extern __printf(3, 4)
-void ext3_msg(struct super_block *, const char *, const char *, ...);
-extern void ext3_update_dynamic_rev (struct super_block *sb);
-
-#define ext3_std_error(sb, errno)				\
-do {								\
-	if ((errno))						\
-		__ext3_std_error((sb), __func__, (errno));	\
-} while (0)
-
-/*
- * Inodes and files operations
- */
-
-/* dir.c */
-extern const struct file_operations ext3_dir_operations;
-
-/* file.c */
-extern const struct inode_operations ext3_file_inode_operations;
-extern const struct file_operations ext3_file_operations;
-
-/* namei.c */
-extern const struct inode_operations ext3_dir_inode_operations;
-extern const struct inode_operations ext3_special_inode_operations;
-
-/* symlink.c */
-extern const struct inode_operations ext3_symlink_inode_operations;
-extern const struct inode_operations ext3_fast_symlink_inode_operations;
-
-
-#endif	/* __KERNEL__ */
-
-#endif	/* _LINUX_EXT3_FS_H */
diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h
deleted file mode 100644
index f42c098..0000000
--- a/include/linux/ext3_fs_i.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- *  linux/include/linux/ext3_fs_i.h
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- *
- *  from
- *
- *  linux/include/linux/minix_fs_i.h
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-#ifndef _LINUX_EXT3_FS_I
-#define _LINUX_EXT3_FS_I
-
-#include <linux/rwsem.h>
-#include <linux/rbtree.h>
-#include <linux/seqlock.h>
-#include <linux/mutex.h>
-
-/* data type for block offset of block group */
-typedef int ext3_grpblk_t;
-
-/* data type for filesystem-wide blocks number */
-typedef unsigned long ext3_fsblk_t;
-
-#define E3FSBLK "%lu"
-
-struct ext3_reserve_window {
-	ext3_fsblk_t	_rsv_start;	/* First byte reserved */
-	ext3_fsblk_t	_rsv_end;	/* Last byte reserved or 0 */
-};
-
-struct ext3_reserve_window_node {
-	struct rb_node		rsv_node;
-	__u32			rsv_goal_size;
-	__u32			rsv_alloc_hit;
-	struct ext3_reserve_window	rsv_window;
-};
-
-struct ext3_block_alloc_info {
-	/* information about reservation window */
-	struct ext3_reserve_window_node	rsv_window_node;
-	/*
-	 * was i_next_alloc_block in ext3_inode_info
-	 * is the logical (file-relative) number of the
-	 * most-recently-allocated block in this file.
-	 * We use this for detecting linearly ascending allocation requests.
-	 */
-	__u32                   last_alloc_logical_block;
-	/*
-	 * Was i_next_alloc_goal in ext3_inode_info
-	 * is the *physical* companion to i_next_alloc_block.
-	 * it the physical block number of the block which was most-recentl
-	 * allocated to this file.  This give us the goal (target) for the next
-	 * allocation when we detect linearly ascending requests.
-	 */
-	ext3_fsblk_t		last_alloc_physical_block;
-};
-
-#define rsv_start rsv_window._rsv_start
-#define rsv_end rsv_window._rsv_end
-
-/*
- * third extended file system inode data in memory
- */
-struct ext3_inode_info {
-	__le32	i_data[15];	/* unconverted */
-	__u32	i_flags;
-#ifdef EXT3_FRAGMENTS
-	__u32	i_faddr;
-	__u8	i_frag_no;
-	__u8	i_frag_size;
-#endif
-	ext3_fsblk_t	i_file_acl;
-	__u32	i_dir_acl;
-	__u32	i_dtime;
-
-	/*
-	 * i_block_group is the number of the block group which contains
-	 * this file's inode.  Constant across the lifetime of the inode,
-	 * it is ued for making block allocation decisions - we try to
-	 * place a file's data blocks near its inode block, and new inodes
-	 * near to their parent directory's inode.
-	 */
-	__u32	i_block_group;
-	unsigned long	i_state_flags;	/* Dynamic state flags for ext3 */
-
-	/* block reservation info */
-	struct ext3_block_alloc_info *i_block_alloc_info;
-
-	__u32	i_dir_start_lookup;
-#ifdef CONFIG_EXT3_FS_XATTR
-	/*
-	 * Extended attributes can be read independently of the main file
-	 * data. Taking i_mutex even when reading would cause contention
-	 * between readers of EAs and writers of regular file data, so
-	 * instead we synchronize on xattr_sem when reading or changing
-	 * EAs.
-	 */
-	struct rw_semaphore xattr_sem;
-#endif
-
-	struct list_head i_orphan;	/* unlinked but open inodes */
-
-	/*
-	 * i_disksize keeps track of what the inode size is ON DISK, not
-	 * in memory.  During truncate, i_size is set to the new size by
-	 * the VFS prior to calling ext3_truncate(), but the filesystem won't
-	 * set i_disksize to 0 until the truncate is actually under way.
-	 *
-	 * The intent is that i_disksize always represents the blocks which
-	 * are used by this file.  This allows recovery to restart truncate
-	 * on orphans if we crash during truncate.  We actually write i_disksize
-	 * into the on-disk inode when writing inodes out, instead of i_size.
-	 *
-	 * The only time when i_disksize and i_size may be different is when
-	 * a truncate is in progress.  The only things which change i_disksize
-	 * are ext3_get_block (growth) and ext3_truncate (shrinkth).
-	 */
-	loff_t	i_disksize;
-
-	/* on-disk additional length */
-	__u16 i_extra_isize;
-
-	/*
-	 * truncate_mutex is for serialising ext3_truncate() against
-	 * ext3_getblock().  In the 2.4 ext2 design, great chunks of inode's
-	 * data tree are chopped off during truncate. We can't do that in
-	 * ext3 because whenever we perform intermediate commits during
-	 * truncate, the inode and all the metadata blocks *must* be in a
-	 * consistent state which allows truncation of the orphans to restart
-	 * during recovery.  Hence we must fix the get_block-vs-truncate race
-	 * by other means, so we have truncate_mutex.
-	 */
-	struct mutex truncate_mutex;
-
-	/*
-	 * Transactions that contain inode's metadata needed to complete
-	 * fsync and fdatasync, respectively.
-	 */
-	atomic_t i_sync_tid;
-	atomic_t i_datasync_tid;
-
-	struct inode vfs_inode;
-};
-
-#endif	/* _LINUX_EXT3_FS_I */
diff --git a/include/linux/ext3_fs_sb.h b/include/linux/ext3_fs_sb.h
deleted file mode 100644
index 6436525..0000000
--- a/include/linux/ext3_fs_sb.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- *  linux/include/linux/ext3_fs_sb.h
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- *
- *  from
- *
- *  linux/include/linux/minix_fs_sb.h
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-#ifndef _LINUX_EXT3_FS_SB
-#define _LINUX_EXT3_FS_SB
-
-#ifdef __KERNEL__
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/blockgroup_lock.h>
-#include <linux/percpu_counter.h>
-#endif
-#include <linux/rbtree.h>
-
-/*
- * third extended-fs super-block data in memory
- */
-struct ext3_sb_info {
-	unsigned long s_frag_size;	/* Size of a fragment in bytes */
-	unsigned long s_frags_per_block;/* Number of fragments per block */
-	unsigned long s_inodes_per_block;/* Number of inodes per block */
-	unsigned long s_frags_per_group;/* Number of fragments in a group */
-	unsigned long s_blocks_per_group;/* Number of blocks in a group */
-	unsigned long s_inodes_per_group;/* Number of inodes in a group */
-	unsigned long s_itb_per_group;	/* Number of inode table blocks per group */
-	unsigned long s_gdb_count;	/* Number of group descriptor blocks */
-	unsigned long s_desc_per_block;	/* Number of group descriptors per block */
-	unsigned long s_groups_count;	/* Number of groups in the fs */
-	unsigned long s_overhead_last;  /* Last calculated overhead */
-	unsigned long s_blocks_last;    /* Last seen block count */
-	struct buffer_head * s_sbh;	/* Buffer containing the super block */
-	struct ext3_super_block * s_es;	/* Pointer to the super block in the buffer */
-	struct buffer_head ** s_group_desc;
-	unsigned long  s_mount_opt;
-	ext3_fsblk_t s_sb_block;
-	uid_t s_resuid;
-	gid_t s_resgid;
-	unsigned short s_mount_state;
-	unsigned short s_pad;
-	int s_addr_per_block_bits;
-	int s_desc_per_block_bits;
-	int s_inode_size;
-	int s_first_ino;
-	spinlock_t s_next_gen_lock;
-	u32 s_next_generation;
-	u32 s_hash_seed[4];
-	int s_def_hash_version;
-	int s_hash_unsigned;	/* 3 if hash should be signed, 0 if not */
-	struct percpu_counter s_freeblocks_counter;
-	struct percpu_counter s_freeinodes_counter;
-	struct percpu_counter s_dirs_counter;
-	struct blockgroup_lock *s_blockgroup_lock;
-
-	/* root of the per fs reservation window tree */
-	spinlock_t s_rsv_window_lock;
-	struct rb_root s_rsv_window_root;
-	struct ext3_reserve_window_node s_rsv_window_head;
-
-	/* Journaling */
-	struct inode * s_journal_inode;
-	struct journal_s * s_journal;
-	struct list_head s_orphan;
-	struct mutex s_orphan_lock;
-	struct mutex s_resize_lock;
-	unsigned long s_commit_interval;
-	struct block_device *journal_bdev;
-#ifdef CONFIG_QUOTA
-	char *s_qf_names[MAXQUOTAS];		/* Names of quota files with journalled quota */
-	int s_jquota_fmt;			/* Format of quota to use */
-#endif
-};
-
-static inline spinlock_t *
-sb_bgl_lock(struct ext3_sb_info *sbi, unsigned int block_group)
-{
-	return bgl_lock_ptr(sbi->s_blockgroup_lock, block_group);
-}
-
-#endif	/* _LINUX_EXT3_FS_SB */
diff --git a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h
deleted file mode 100644
index d7b5ddc..0000000
--- a/include/linux/ext3_jbd.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * linux/include/linux/ext3_jbd.h
- *
- * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
- *
- * Copyright 1998--1999 Red Hat corp --- All Rights Reserved
- *
- * This file is part of the Linux kernel and is made available under
- * the terms of the GNU General Public License, version 2, or at your
- * option, any later version, incorporated herein by reference.
- *
- * Ext3-specific journaling extensions.
- */
-
-#ifndef _LINUX_EXT3_JBD_H
-#define _LINUX_EXT3_JBD_H
-
-#include <linux/fs.h>
-#include <linux/jbd.h>
-#include <linux/ext3_fs.h>
-
-#define EXT3_JOURNAL(inode)	(EXT3_SB((inode)->i_sb)->s_journal)
-
-/* Define the number of blocks we need to account to a transaction to
- * modify one block of data.
- *
- * We may have to touch one inode, one bitmap buffer, up to three
- * indirection blocks, the group and superblock summaries, and the data
- * block to complete the transaction.  */
-
-#define EXT3_SINGLEDATA_TRANS_BLOCKS	8U
-
-/* Extended attribute operations touch at most two data buffers,
- * two bitmap buffers, and two group summaries, in addition to the inode
- * and the superblock, which are already accounted for. */
-
-#define EXT3_XATTR_TRANS_BLOCKS		6U
-
-/* Define the minimum size for a transaction which modifies data.  This
- * needs to take into account the fact that we may end up modifying two
- * quota files too (one for the group, one for the user quota).  The
- * superblock only gets updated once, of course, so don't bother
- * counting that again for the quota updates. */
-
-#define EXT3_DATA_TRANS_BLOCKS(sb)	(EXT3_SINGLEDATA_TRANS_BLOCKS + \
-					 EXT3_XATTR_TRANS_BLOCKS - 2 + \
-					 EXT3_MAXQUOTAS_TRANS_BLOCKS(sb))
-
-/* Delete operations potentially hit one directory's namespace plus an
- * entire inode, plus arbitrary amounts of bitmap/indirection data.  Be
- * generous.  We can grow the delete transaction later if necessary. */
-
-#define EXT3_DELETE_TRANS_BLOCKS(sb)   (EXT3_MAXQUOTAS_TRANS_BLOCKS(sb) + 64)
-
-/* Define an arbitrary limit for the amount of data we will anticipate
- * writing to any given transaction.  For unbounded transactions such as
- * write(2) and truncate(2) we can write more than this, but we always
- * start off at the maximum transaction size and grow the transaction
- * optimistically as we go. */
-
-#define EXT3_MAX_TRANS_DATA		64U
-
-/* We break up a large truncate or write transaction once the handle's
- * buffer credits gets this low, we need either to extend the
- * transaction or to start a new one.  Reserve enough space here for
- * inode, bitmap, superblock, group and indirection updates for at least
- * one block, plus two quota updates.  Quota allocations are not
- * needed. */
-
-#define EXT3_RESERVE_TRANS_BLOCKS	12U
-
-#define EXT3_INDEX_EXTRA_TRANS_BLOCKS	8
-
-#ifdef CONFIG_QUOTA
-/* Amount of blocks needed for quota update - we know that the structure was
- * allocated so we need to update only inode+data */
-#define EXT3_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 2 : 0)
-/* Amount of blocks needed for quota insert/delete - we do some block writes
- * but inode, sb and group updates are done only once */
-#define EXT3_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\
-		(EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_INIT_REWRITE) : 0)
-#define EXT3_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\
-		(EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_DEL_REWRITE) : 0)
-#else
-#define EXT3_QUOTA_TRANS_BLOCKS(sb) 0
-#define EXT3_QUOTA_INIT_BLOCKS(sb) 0
-#define EXT3_QUOTA_DEL_BLOCKS(sb) 0
-#endif
-#define EXT3_MAXQUOTAS_TRANS_BLOCKS(sb) (MAXQUOTAS*EXT3_QUOTA_TRANS_BLOCKS(sb))
-#define EXT3_MAXQUOTAS_INIT_BLOCKS(sb) (MAXQUOTAS*EXT3_QUOTA_INIT_BLOCKS(sb))
-#define EXT3_MAXQUOTAS_DEL_BLOCKS(sb) (MAXQUOTAS*EXT3_QUOTA_DEL_BLOCKS(sb))
-
-int
-ext3_mark_iloc_dirty(handle_t *handle,
-		     struct inode *inode,
-		     struct ext3_iloc *iloc);
-
-/*
- * On success, We end up with an outstanding reference count against
- * iloc->bh.  This _must_ be cleaned up later.
- */
-
-int ext3_reserve_inode_write(handle_t *handle, struct inode *inode,
-			struct ext3_iloc *iloc);
-
-int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode);
-
-/*
- * Wrapper functions with which ext3 calls into JBD.  The intent here is
- * to allow these to be turned into appropriate stubs so ext3 can control
- * ext2 filesystems, so ext2+ext3 systems only nee one fs.  This work hasn't
- * been done yet.
- */
-
-static inline void ext3_journal_release_buffer(handle_t *handle,
-						struct buffer_head *bh)
-{
-	journal_release_buffer(handle, bh);
-}
-
-void ext3_journal_abort_handle(const char *caller, const char *err_fn,
-		struct buffer_head *bh, handle_t *handle, int err);
-
-int __ext3_journal_get_undo_access(const char *where, handle_t *handle,
-				struct buffer_head *bh);
-
-int __ext3_journal_get_write_access(const char *where, handle_t *handle,
-				struct buffer_head *bh);
-
-int __ext3_journal_forget(const char *where, handle_t *handle,
-				struct buffer_head *bh);
-
-int __ext3_journal_revoke(const char *where, handle_t *handle,
-				unsigned long blocknr, struct buffer_head *bh);
-
-int __ext3_journal_get_create_access(const char *where,
-				handle_t *handle, struct buffer_head *bh);
-
-int __ext3_journal_dirty_metadata(const char *where,
-				handle_t *handle, struct buffer_head *bh);
-
-#define ext3_journal_get_undo_access(handle, bh) \
-	__ext3_journal_get_undo_access(__func__, (handle), (bh))
-#define ext3_journal_get_write_access(handle, bh) \
-	__ext3_journal_get_write_access(__func__, (handle), (bh))
-#define ext3_journal_revoke(handle, blocknr, bh) \
-	__ext3_journal_revoke(__func__, (handle), (blocknr), (bh))
-#define ext3_journal_get_create_access(handle, bh) \
-	__ext3_journal_get_create_access(__func__, (handle), (bh))
-#define ext3_journal_dirty_metadata(handle, bh) \
-	__ext3_journal_dirty_metadata(__func__, (handle), (bh))
-#define ext3_journal_forget(handle, bh) \
-	__ext3_journal_forget(__func__, (handle), (bh))
-
-int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh);
-
-handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks);
-int __ext3_journal_stop(const char *where, handle_t *handle);
-
-static inline handle_t *ext3_journal_start(struct inode *inode, int nblocks)
-{
-	return ext3_journal_start_sb(inode->i_sb, nblocks);
-}
-
-#define ext3_journal_stop(handle) \
-	__ext3_journal_stop(__func__, (handle))
-
-static inline handle_t *ext3_journal_current_handle(void)
-{
-	return journal_current_handle();
-}
-
-static inline int ext3_journal_extend(handle_t *handle, int nblocks)
-{
-	return journal_extend(handle, nblocks);
-}
-
-static inline int ext3_journal_restart(handle_t *handle, int nblocks)
-{
-	return journal_restart(handle, nblocks);
-}
-
-static inline int ext3_journal_blocks_per_page(struct inode *inode)
-{
-	return journal_blocks_per_page(inode);
-}
-
-static inline int ext3_journal_force_commit(journal_t *journal)
-{
-	return journal_force_commit(journal);
-}
-
-/* super.c */
-int ext3_force_commit(struct super_block *sb);
-
-static inline int ext3_should_journal_data(struct inode *inode)
-{
-	if (!S_ISREG(inode->i_mode))
-		return 1;
-	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA)
-		return 1;
-	if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL)
-		return 1;
-	return 0;
-}
-
-static inline int ext3_should_order_data(struct inode *inode)
-{
-	if (!S_ISREG(inode->i_mode))
-		return 0;
-	if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL)
-		return 0;
-	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA)
-		return 1;
-	return 0;
-}
-
-static inline int ext3_should_writeback_data(struct inode *inode)
-{
-	if (!S_ISREG(inode->i_mode))
-		return 0;
-	if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL)
-		return 0;
-	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)
-		return 1;
-	return 0;
-}
-
-#endif	/* _LINUX_EXT3_JBD_H */
diff --git a/include/linux/fb.h b/include/linux/fb.h
index c18122f..d31cb68 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -407,7 +407,6 @@
 
 #include <linux/fs.h>
 #include <linux/init.h>
-#include <linux/device.h>
 #include <linux/workqueue.h>
 #include <linux/notifier.h>
 #include <linux/list.h>
@@ -1003,6 +1002,7 @@
 /* drivers/video/fbmem.c */
 extern int register_framebuffer(struct fb_info *fb_info);
 extern int unregister_framebuffer(struct fb_info *fb_info);
+extern int unlink_framebuffer(struct fb_info *fb_info);
 extern void remove_conflicting_framebuffers(struct apertures_struct *a,
 				const char *name, bool primary);
 extern int fb_prepare_logo(struct fb_info *fb_info, int rotate);
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index 82163c4..158a41e 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -21,23 +21,45 @@
  */
 #define NR_OPEN_DEFAULT BITS_PER_LONG
 
-/*
- * The embedded_fd_set is a small fd_set,
- * suitable for most tasks (which open <= BITS_PER_LONG files)
- */
-struct embedded_fd_set {
-	unsigned long fds_bits[1];
-};
-
 struct fdtable {
 	unsigned int max_fds;
 	struct file __rcu **fd;      /* current fd array */
-	fd_set *close_on_exec;
-	fd_set *open_fds;
+	unsigned long *close_on_exec;
+	unsigned long *open_fds;
 	struct rcu_head rcu;
 	struct fdtable *next;
 };
 
+static inline void __set_close_on_exec(int fd, struct fdtable *fdt)
+{
+	__set_bit(fd, fdt->close_on_exec);
+}
+
+static inline void __clear_close_on_exec(int fd, struct fdtable *fdt)
+{
+	__clear_bit(fd, fdt->close_on_exec);
+}
+
+static inline bool close_on_exec(int fd, const struct fdtable *fdt)
+{
+	return test_bit(fd, fdt->close_on_exec);
+}
+
+static inline void __set_open_fd(int fd, struct fdtable *fdt)
+{
+	__set_bit(fd, fdt->open_fds);
+}
+
+static inline void __clear_open_fd(int fd, struct fdtable *fdt)
+{
+	__clear_bit(fd, fdt->open_fds);
+}
+
+static inline bool fd_is_open(int fd, const struct fdtable *fdt)
+{
+	return test_bit(fd, fdt->open_fds);
+}
+
 /*
  * Open file table structure
  */
@@ -53,8 +75,8 @@
    */
 	spinlock_t file_lock ____cacheline_aligned_in_smp;
 	int next_fd;
-	struct embedded_fd_set close_on_exec_init;
-	struct embedded_fd_set open_fds_init;
+	unsigned long close_on_exec_init[1];
+	unsigned long open_fds_init[1];
 	struct file __rcu * fd_array[NR_OPEN_DEFAULT];
 };
 
diff --git a/include/linux/file.h b/include/linux/file.h
index 21a7995..58bf158 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -12,7 +12,6 @@
 struct file;
 
 extern void fput(struct file *);
-extern void drop_file_write_access(struct file *file);
 
 struct file_operations;
 struct vfsmount;
diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h
index 357dbfc..d500369 100644
--- a/include/linux/firewire-cdev.h
+++ b/include/linux/firewire-cdev.h
@@ -207,12 +207,16 @@
  * @closure:	See &fw_cdev_event_common;
  *		set by %FW_CDEV_CREATE_ISO_CONTEXT ioctl
  * @type:	See &fw_cdev_event_common; always %FW_CDEV_EVENT_ISO_INTERRUPT
- * @cycle:	Cycle counter of the interrupt packet
+ * @cycle:	Cycle counter of the last completed packet
  * @header_length: Total length of following headers, in bytes
  * @header:	Stripped headers, if any
  *
  * This event is sent when the controller has completed an &fw_cdev_iso_packet
- * with the %FW_CDEV_ISO_INTERRUPT bit set.
+ * with the %FW_CDEV_ISO_INTERRUPT bit set, when explicitly requested with
+ * %FW_CDEV_IOC_FLUSH_ISO, or when there have been so many completed packets
+ * without the interrupt bit set that the kernel's internal buffer for @header
+ * is about to overflow.  (In the last case, kernels with ABI version < 5 drop
+ * header data up to the next interrupt packet.)
  *
  * Isochronous transmit events (context type %FW_CDEV_ISO_CONTEXT_TRANSMIT):
  *
@@ -267,9 +271,9 @@
  *
  * This event is sent in multichannel contexts (context type
  * %FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL) for &fw_cdev_iso_packet buffer
- * chunks that have the %FW_CDEV_ISO_INTERRUPT bit set.  Whether this happens
- * when a packet is completed and/or when a buffer chunk is completed depends
- * on the hardware implementation.
+ * chunks that have been completely filled and that have the
+ * %FW_CDEV_ISO_INTERRUPT bit set, or when explicitly requested with
+ * %FW_CDEV_IOC_FLUSH_ISO.
  *
  * The buffer is continuously filled with the following data, per packet:
  *  - the 1394 iso packet header as described at &fw_cdev_event_iso_interrupt,
@@ -419,6 +423,9 @@
 #define FW_CDEV_IOC_RECEIVE_PHY_PACKETS _IOW('#', 0x16, struct fw_cdev_receive_phy_packets)
 #define FW_CDEV_IOC_SET_ISO_CHANNELS    _IOW('#', 0x17, struct fw_cdev_set_iso_channels)
 
+/* available since kernel version 3.4 */
+#define FW_CDEV_IOC_FLUSH_ISO           _IOW('#', 0x18, struct fw_cdev_flush_iso)
+
 /*
  * ABI version history
  *  1  (2.6.22)  - initial version
@@ -441,6 +448,9 @@
  *               - added %FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL,
  *                 %FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL, and
  *                 %FW_CDEV_IOC_SET_ISO_CHANNELS
+ *  5  (3.4)     - send %FW_CDEV_EVENT_ISO_INTERRUPT events when needed to
+ *                 avoid dropping data
+ *               - added %FW_CDEV_IOC_FLUSH_ISO
  */
 
 /**
@@ -851,6 +861,25 @@
 };
 
 /**
+ * struct fw_cdev_flush_iso - flush completed iso packets
+ * @handle:	handle of isochronous context to flush
+ *
+ * For %FW_CDEV_ISO_CONTEXT_TRANSMIT or %FW_CDEV_ISO_CONTEXT_RECEIVE contexts,
+ * report any completed packets.
+ *
+ * For %FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL contexts, report the current
+ * offset in the receive buffer, if it has changed; this is typically in the
+ * middle of some buffer chunk.
+ *
+ * Any %FW_CDEV_EVENT_ISO_INTERRUPT or %FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL
+ * events generated by this ioctl are sent synchronously, i.e., are available
+ * for reading from the file descriptor when this ioctl returns.
+ */
+struct fw_cdev_flush_iso {
+	__u32 handle;
+};
+
+/**
  * struct fw_cdev_get_cycle_timer - read cycle timer register
  * @local_time:   system time, in microseconds since the Epoch
  * @cycle_timer:  Cycle Time register contents
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index 84ccf8e..cdc9b71 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -17,9 +17,6 @@
 #include <linux/atomic.h>
 #include <asm/byteorder.h>
 
-#define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args)
-#define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
-
 #define CSR_REGISTER_BASE		0xfffff0000000ULL
 
 /* register offsets are relative to CSR_REGISTER_BASE */
@@ -203,18 +200,6 @@
 	return atomic_read(&device->state) == FW_DEVICE_SHUTDOWN;
 }
 
-static inline struct fw_device *fw_device_get(struct fw_device *device)
-{
-	get_device(&device->device);
-
-	return device;
-}
-
-static inline void fw_device_put(struct fw_device *device)
-{
-	put_device(&device->device);
-}
-
 int fw_device_enable_phys_dma(struct fw_device *device);
 
 /*
@@ -441,6 +426,7 @@
 			 struct fw_iso_buffer *buffer,
 			 unsigned long payload);
 void fw_iso_context_queue_flush(struct fw_iso_context *ctx);
+int fw_iso_context_flush_completions(struct fw_iso_context *ctx);
 int fw_iso_context_start(struct fw_iso_context *ctx,
 			 int cycle, int sync, int tags);
 int fw_iso_context_stop(struct fw_iso_context *ctx);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 69cd5bb..8de6755 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -92,6 +92,10 @@
 /* File is opened using open(.., 3, ..) and is writeable only for ioctls
    (specialy hack for floppy.c) */
 #define FMODE_WRITE_IOCTL	((__force fmode_t)0x100)
+/* 32bit hashes as llseek() offset (for directories) */
+#define FMODE_32BITHASH         ((__force fmode_t)0x200)
+/* 64bit hashes as llseek() offset (for directories) */
+#define FMODE_64BITHASH         ((__force fmode_t)0x400)
 
 /*
  * Don't update ctime and mtime.
@@ -389,6 +393,7 @@
 #include <linux/prio_tree.h>
 #include <linux/init.h>
 #include <linux/pid.h>
+#include <linux/bug.h>
 #include <linux/mutex.h>
 #include <linux/capability.h>
 #include <linux/semaphore.h>
@@ -1210,6 +1215,7 @@
 extern int lease_modify(struct file_lock **, int);
 extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
 extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
+extern void locks_delete_block(struct file_lock *waiter);
 extern void lock_flocks(void);
 extern void unlock_flocks(void);
 #else /* !CONFIG_FILE_LOCKING */
@@ -1354,6 +1360,10 @@
 	return 1;
 }
 
+static inline void locks_delete_block(struct file_lock *waiter)
+{
+}
+
 static inline void lock_flocks(void)
 {
 }
@@ -1459,6 +1469,7 @@
 	u8 s_uuid[16];				/* UUID */
 
 	void 			*s_fs_info;	/* Filesystem private info */
+	unsigned int		s_max_links;
 	fmode_t			s_mode;
 
 	/* Granularity of c/m/atime in ns.
@@ -1811,11 +1822,11 @@
        spin_unlock(&inode->i_lock);
 }
 
-extern void touch_atime(struct vfsmount *mnt, struct dentry *dentry);
+extern void touch_atime(struct path *);
 static inline void file_accessed(struct file *file)
 {
 	if (!(file->f_flags & O_NOATIME))
-		touch_atime(file->f_path.mnt, file->f_path.dentry);
+		touch_atime(&file->f_path);
 }
 
 int sync_inode(struct inode *inode, struct writeback_control *wbc);
@@ -1870,19 +1881,6 @@
 	const struct dentry_operations *dops,
 	unsigned long);
 
-static inline void sb_mark_dirty(struct super_block *sb)
-{
-	sb->s_dirt = 1;
-}
-static inline void sb_mark_clean(struct super_block *sb)
-{
-	sb->s_dirt = 0;
-}
-static inline int sb_is_dirty(struct super_block *sb)
-{
-	return sb->s_dirt;
-}
-
 /* Alas, no aliases. Too much hassle with bringing module.h everywhere */
 #define fops_get(fops) \
 	(((fops) && try_module_get((fops)->owner) ? (fops) : NULL))
@@ -2304,7 +2302,10 @@
 extern ino_t iunique(struct super_block *, ino_t);
 extern int inode_needs_sync(struct inode *inode);
 extern int generic_delete_inode(struct inode *inode);
-extern int generic_drop_inode(struct inode *inode);
+static inline int generic_drop_inode(struct inode *inode)
+{
+	return !inode->i_nlink || inode_unhashed(inode);
+}
 
 extern struct inode *ilookup5_nowait(struct super_block *sb,
 		unsigned long hashval, int (*test)(struct inode *, void *),
@@ -2510,6 +2511,7 @@
 extern int simple_setattr(struct dentry *, struct iattr *);
 extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern int simple_statfs(struct dentry *, struct kstatfs *);
+extern int simple_open(struct inode *inode, struct file *file);
 extern int simple_link(struct dentry *, struct inode *, struct dentry *);
 extern int simple_unlink(struct inode *, struct dentry *);
 extern int simple_rmdir(struct inode *, struct dentry *);
diff --git a/arch/arm/mach-mxs/include/mach/dma.h b/include/linux/fsl/mxs-dma.h
similarity index 100%
rename from arch/arm/mach-mxs/include/mach/dma.h
rename to include/linux/fsl/mxs-dma.h
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 2a53f10..a6dfe69 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -14,6 +14,7 @@
 #include <linux/fsnotify_backend.h>
 #include <linux/audit.h>
 #include <linux/slab.h>
+#include <linux/bug.h>
 
 /*
  * fsnotify_d_instantiate - instantiate a dentry for inode
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index dd478fc..5f3f3be 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -144,12 +144,14 @@
 enum trace_reg {
 	TRACE_REG_REGISTER,
 	TRACE_REG_UNREGISTER,
+#ifdef CONFIG_PERF_EVENTS
 	TRACE_REG_PERF_REGISTER,
 	TRACE_REG_PERF_UNREGISTER,
 	TRACE_REG_PERF_OPEN,
 	TRACE_REG_PERF_CLOSE,
 	TRACE_REG_PERF_ADD,
 	TRACE_REG_PERF_DEL,
+#endif
 };
 
 struct ftrace_event_call;
diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h
index b148087..fa98bdb 100644
--- a/include/linux/gfs2_ondisk.h
+++ b/include/linux/gfs2_ondisk.h
@@ -168,6 +168,7 @@
 #define GFS2_RGF_METAONLY	0x00000002
 #define GFS2_RGF_DATAONLY	0x00000004
 #define GFS2_RGF_NOALLOC	0x00000008
+#define GFS2_RGF_TRIMMED	0x00000010
 
 struct gfs2_rgrp {
 	struct gfs2_meta_header rg_header;
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index 38ac48b..6155ecf 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -14,6 +14,12 @@
 #define GPIOF_OUT_INIT_LOW	(GPIOF_DIR_OUT | GPIOF_INIT_LOW)
 #define GPIOF_OUT_INIT_HIGH	(GPIOF_DIR_OUT | GPIOF_INIT_HIGH)
 
+/* Gpio pin is open drain */
+#define GPIOF_OPEN_DRAIN	(1 << 2)
+
+/* Gpio pin is open source */
+#define GPIOF_OPEN_SOURCE	(1 << 3)
+
 /**
  * struct gpio - a structure describing a GPIO with configuration
  * @gpio:	the GPIO number
@@ -34,6 +40,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/bug.h>
 
 struct device;
 struct gpio_chip;
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h
index 004ff33..a7e977f 100644
--- a/include/linux/gpio_keys.h
+++ b/include/linux/gpio_keys.h
@@ -6,7 +6,7 @@
 struct gpio_keys_button {
 	/* Configuration parameters */
 	unsigned int code;	/* input event code (KEY_*, SW_*) */
-	int gpio;
+	int gpio;		/* -1 if this key does not support gpio */
 	int active_low;
 	const char *desc;
 	unsigned int type;	/* input event type (EV_KEY, EV_SW, EV_ABS) */
@@ -14,6 +14,7 @@
 	int debounce_interval;	/* debounce ticks interval in msecs */
 	bool can_disable;
 	int value;		/* axis value for EV_ABS */
+	unsigned int irq;	/* Irq number in case of interrupt keys */
 };
 
 struct gpio_keys_platform_data {
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 6549ed7..d3999b4 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -3,6 +3,7 @@
 
 #include <linux/fs.h>
 #include <linux/kernel.h>
+#include <linux/bug.h>
 #include <linux/mm.h>
 #include <linux/uaccess.h>
 #include <linux/hardirq.h>
diff --git a/include/linux/hsi/Kbuild b/include/linux/hsi/Kbuild
new file mode 100644
index 0000000..271a770
--- /dev/null
+++ b/include/linux/hsi/Kbuild
@@ -0,0 +1 @@
+header-y += hsi_char.h
diff --git a/include/linux/hsi/hsi.h b/include/linux/hsi/hsi.h
new file mode 100644
index 0000000..4b17806
--- /dev/null
+++ b/include/linux/hsi/hsi.h
@@ -0,0 +1,410 @@
+/*
+ * HSI core header file.
+ *
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Carlos Chinea <carlos.chinea@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
+ */
+
+#ifndef __LINUX_HSI_H__
+#define __LINUX_HSI_H__
+
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/scatterlist.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/module.h>
+
+/* HSI message ttype */
+#define HSI_MSG_READ	0
+#define HSI_MSG_WRITE	1
+
+/* HSI configuration values */
+enum {
+	HSI_MODE_STREAM	= 1,
+	HSI_MODE_FRAME,
+};
+
+enum {
+	HSI_FLOW_SYNC,	/* Synchronized flow */
+	HSI_FLOW_PIPE,	/* Pipelined flow */
+};
+
+enum {
+	HSI_ARB_RR,	/* Round-robin arbitration */
+	HSI_ARB_PRIO,	/* Channel priority arbitration */
+};
+
+#define HSI_MAX_CHANNELS	16
+
+/* HSI message status codes */
+enum {
+	HSI_STATUS_COMPLETED,	/* Message transfer is completed */
+	HSI_STATUS_PENDING,	/* Message pending to be read/write (POLL) */
+	HSI_STATUS_PROCEEDING,	/* Message transfer is ongoing */
+	HSI_STATUS_QUEUED,	/* Message waiting to be served */
+	HSI_STATUS_ERROR,	/* Error when message transfer was ongoing */
+};
+
+/* HSI port event codes */
+enum {
+	HSI_EVENT_START_RX,
+	HSI_EVENT_STOP_RX,
+};
+
+/**
+ * struct hsi_config - Configuration for RX/TX HSI modules
+ * @mode: Bit transmission mode (STREAM or FRAME)
+ * @channels: Number of channels to use [1..16]
+ * @speed: Max bit transmission speed (Kbit/s)
+ * @flow: RX flow type (SYNCHRONIZED or PIPELINE)
+ * @arb_mode: Arbitration mode for TX frame (Round robin, priority)
+ */
+struct hsi_config {
+	unsigned int	mode;
+	unsigned int	channels;
+	unsigned int	speed;
+	union {
+		unsigned int	flow;		/* RX only */
+		unsigned int	arb_mode;	/* TX only */
+	};
+};
+
+/**
+ * struct hsi_board_info - HSI client board info
+ * @name: Name for the HSI device
+ * @hsi_id: HSI controller id where the client sits
+ * @port: Port number in the controller where the client sits
+ * @tx_cfg: HSI TX configuration
+ * @rx_cfg: HSI RX configuration
+ * @platform_data: Platform related data
+ * @archdata: Architecture-dependent device data
+ */
+struct hsi_board_info {
+	const char		*name;
+	unsigned int		hsi_id;
+	unsigned int		port;
+	struct hsi_config	tx_cfg;
+	struct hsi_config	rx_cfg;
+	void			*platform_data;
+	struct dev_archdata	*archdata;
+};
+
+#ifdef CONFIG_HSI_BOARDINFO
+extern int hsi_register_board_info(struct hsi_board_info const *info,
+							unsigned int len);
+#else
+static inline int hsi_register_board_info(struct hsi_board_info const *info,
+							unsigned int len)
+{
+	return 0;
+}
+#endif /* CONFIG_HSI_BOARDINFO */
+
+/**
+ * struct hsi_client - HSI client attached to an HSI port
+ * @device: Driver model representation of the device
+ * @tx_cfg: HSI TX configuration
+ * @rx_cfg: HSI RX configuration
+ * @hsi_start_rx: Called after incoming wake line goes high
+ * @hsi_stop_rx: Called after incoming wake line goes low
+ */
+struct hsi_client {
+	struct device		device;
+	struct hsi_config	tx_cfg;
+	struct hsi_config	rx_cfg;
+	void			(*hsi_start_rx)(struct hsi_client *cl);
+	void			(*hsi_stop_rx)(struct hsi_client *cl);
+	/* private: */
+	unsigned int		pclaimed:1;
+	struct list_head	link;
+};
+
+#define to_hsi_client(dev) container_of(dev, struct hsi_client, device)
+
+static inline void hsi_client_set_drvdata(struct hsi_client *cl, void *data)
+{
+	dev_set_drvdata(&cl->device, data);
+}
+
+static inline void *hsi_client_drvdata(struct hsi_client *cl)
+{
+	return dev_get_drvdata(&cl->device);
+}
+
+/**
+ * struct hsi_client_driver - Driver associated to an HSI client
+ * @driver: Driver model representation of the driver
+ */
+struct hsi_client_driver {
+	struct device_driver	driver;
+};
+
+#define to_hsi_client_driver(drv) container_of(drv, struct hsi_client_driver,\
+									driver)
+
+int hsi_register_client_driver(struct hsi_client_driver *drv);
+
+static inline void hsi_unregister_client_driver(struct hsi_client_driver *drv)
+{
+	driver_unregister(&drv->driver);
+}
+
+/**
+ * struct hsi_msg - HSI message descriptor
+ * @link: Free to use by the current descriptor owner
+ * @cl: HSI device client that issues the transfer
+ * @sgt: Head of the scatterlist array
+ * @context: Client context data associated to the transfer
+ * @complete: Transfer completion callback
+ * @destructor: Destructor to free resources when flushing
+ * @status: Status of the transfer when completed
+ * @actual_len: Actual length of data transfered on completion
+ * @channel: Channel were to TX/RX the message
+ * @ttype: Transfer type (TX if set, RX otherwise)
+ * @break_frame: if true HSI will send/receive a break frame. Data buffers are
+ *		ignored in the request.
+ */
+struct hsi_msg {
+	struct list_head	link;
+	struct hsi_client	*cl;
+	struct sg_table		sgt;
+	void			*context;
+
+	void			(*complete)(struct hsi_msg *msg);
+	void			(*destructor)(struct hsi_msg *msg);
+
+	int			status;
+	unsigned int		actual_len;
+	unsigned int		channel;
+	unsigned int		ttype:1;
+	unsigned int		break_frame:1;
+};
+
+struct hsi_msg *hsi_alloc_msg(unsigned int n_frag, gfp_t flags);
+void hsi_free_msg(struct hsi_msg *msg);
+
+/**
+ * struct hsi_port - HSI port device
+ * @device: Driver model representation of the device
+ * @tx_cfg: Current TX path configuration
+ * @rx_cfg: Current RX path configuration
+ * @num: Port number
+ * @shared: Set when port can be shared by different clients
+ * @claimed: Reference count of clients which claimed the port
+ * @lock: Serialize port claim
+ * @async: Asynchronous transfer callback
+ * @setup: Callback to set the HSI client configuration
+ * @flush: Callback to clean the HW state and destroy all pending transfers
+ * @start_tx: Callback to inform that a client wants to TX data
+ * @stop_tx: Callback to inform that a client no longer wishes to TX data
+ * @release: Callback to inform that a client no longer uses the port
+ * @clients: List of hsi_clients using the port.
+ * @clock: Lock to serialize access to the clients list.
+ */
+struct hsi_port {
+	struct device			device;
+	struct hsi_config		tx_cfg;
+	struct hsi_config		rx_cfg;
+	unsigned int			num;
+	unsigned int			shared:1;
+	int				claimed;
+	struct mutex			lock;
+	int				(*async)(struct hsi_msg *msg);
+	int				(*setup)(struct hsi_client *cl);
+	int				(*flush)(struct hsi_client *cl);
+	int				(*start_tx)(struct hsi_client *cl);
+	int				(*stop_tx)(struct hsi_client *cl);
+	int				(*release)(struct hsi_client *cl);
+	struct list_head		clients;
+	spinlock_t			clock;
+};
+
+#define to_hsi_port(dev) container_of(dev, struct hsi_port, device)
+#define hsi_get_port(cl) to_hsi_port((cl)->device.parent)
+
+void hsi_event(struct hsi_port *port, unsigned int event);
+int hsi_claim_port(struct hsi_client *cl, unsigned int share);
+void hsi_release_port(struct hsi_client *cl);
+
+static inline int hsi_port_claimed(struct hsi_client *cl)
+{
+	return cl->pclaimed;
+}
+
+static inline void hsi_port_set_drvdata(struct hsi_port *port, void *data)
+{
+	dev_set_drvdata(&port->device, data);
+}
+
+static inline void *hsi_port_drvdata(struct hsi_port *port)
+{
+	return dev_get_drvdata(&port->device);
+}
+
+/**
+ * struct hsi_controller - HSI controller device
+ * @device: Driver model representation of the device
+ * @owner: Pointer to the module owning the controller
+ * @id: HSI controller ID
+ * @num_ports: Number of ports in the HSI controller
+ * @port: Array of HSI ports
+ */
+struct hsi_controller {
+	struct device		device;
+	struct module		*owner;
+	unsigned int		id;
+	unsigned int		num_ports;
+	struct hsi_port		*port;
+};
+
+#define to_hsi_controller(dev) container_of(dev, struct hsi_controller, device)
+
+struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags);
+void hsi_free_controller(struct hsi_controller *hsi);
+int hsi_register_controller(struct hsi_controller *hsi);
+void hsi_unregister_controller(struct hsi_controller *hsi);
+
+static inline void hsi_controller_set_drvdata(struct hsi_controller *hsi,
+								void *data)
+{
+	dev_set_drvdata(&hsi->device, data);
+}
+
+static inline void *hsi_controller_drvdata(struct hsi_controller *hsi)
+{
+	return dev_get_drvdata(&hsi->device);
+}
+
+static inline struct hsi_port *hsi_find_port_num(struct hsi_controller *hsi,
+							unsigned int num)
+{
+	return (num < hsi->num_ports) ? &hsi->port[num] : NULL;
+}
+
+/*
+ * API for HSI clients
+ */
+int hsi_async(struct hsi_client *cl, struct hsi_msg *msg);
+
+/**
+ * hsi_id - Get HSI controller ID associated to a client
+ * @cl: Pointer to a HSI client
+ *
+ * Return the controller id where the client is attached to
+ */
+static inline unsigned int hsi_id(struct hsi_client *cl)
+{
+	return	to_hsi_controller(cl->device.parent->parent)->id;
+}
+
+/**
+ * hsi_port_id - Gets the port number a client is attached to
+ * @cl: Pointer to HSI client
+ *
+ * Return the port number associated to the client
+ */
+static inline unsigned int hsi_port_id(struct hsi_client *cl)
+{
+	return	to_hsi_port(cl->device.parent)->num;
+}
+
+/**
+ * hsi_setup - Configure the client's port
+ * @cl: Pointer to the HSI client
+ *
+ * When sharing ports, clients should either relay on a single
+ * client setup or have the same setup for all of them.
+ *
+ * Return -errno on failure, 0 on success
+ */
+static inline int hsi_setup(struct hsi_client *cl)
+{
+	if (!hsi_port_claimed(cl))
+		return -EACCES;
+	return	hsi_get_port(cl)->setup(cl);
+}
+
+/**
+ * hsi_flush - Flush all pending transactions on the client's port
+ * @cl: Pointer to the HSI client
+ *
+ * This function will destroy all pending hsi_msg in the port and reset
+ * the HW port so it is ready to receive and transmit from a clean state.
+ *
+ * Return -errno on failure, 0 on success
+ */
+static inline int hsi_flush(struct hsi_client *cl)
+{
+	if (!hsi_port_claimed(cl))
+		return -EACCES;
+	return hsi_get_port(cl)->flush(cl);
+}
+
+/**
+ * hsi_async_read - Submit a read transfer
+ * @cl: Pointer to the HSI client
+ * @msg: HSI message descriptor of the transfer
+ *
+ * Return -errno on failure, 0 on success
+ */
+static inline int hsi_async_read(struct hsi_client *cl, struct hsi_msg *msg)
+{
+	msg->ttype = HSI_MSG_READ;
+	return hsi_async(cl, msg);
+}
+
+/**
+ * hsi_async_write - Submit a write transfer
+ * @cl: Pointer to the HSI client
+ * @msg: HSI message descriptor of the transfer
+ *
+ * Return -errno on failure, 0 on success
+ */
+static inline int hsi_async_write(struct hsi_client *cl, struct hsi_msg *msg)
+{
+	msg->ttype = HSI_MSG_WRITE;
+	return hsi_async(cl, msg);
+}
+
+/**
+ * hsi_start_tx - Signal the port that the client wants to start a TX
+ * @cl: Pointer to the HSI client
+ *
+ * Return -errno on failure, 0 on success
+ */
+static inline int hsi_start_tx(struct hsi_client *cl)
+{
+	if (!hsi_port_claimed(cl))
+		return -EACCES;
+	return hsi_get_port(cl)->start_tx(cl);
+}
+
+/**
+ * hsi_stop_tx - Signal the port that the client no longer wants to transmit
+ * @cl: Pointer to the HSI client
+ *
+ * Return -errno on failure, 0 on success
+ */
+static inline int hsi_stop_tx(struct hsi_client *cl)
+{
+	if (!hsi_port_claimed(cl))
+		return -EACCES;
+	return hsi_get_port(cl)->stop_tx(cl);
+}
+#endif /* __LINUX_HSI_H__ */
diff --git a/include/linux/hsi/hsi_char.h b/include/linux/hsi/hsi_char.h
new file mode 100644
index 0000000..76160b4
--- /dev/null
+++ b/include/linux/hsi/hsi_char.h
@@ -0,0 +1,63 @@
+/*
+ * Part of the HSI character device driver.
+ *
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Andras Domokos <andras.domokos at 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
+ */
+
+
+#ifndef __HSI_CHAR_H
+#define __HSI_CHAR_H
+
+#define HSI_CHAR_MAGIC		'k'
+#define HSC_IOW(num, dtype)	_IOW(HSI_CHAR_MAGIC, num, dtype)
+#define HSC_IOR(num, dtype)	_IOR(HSI_CHAR_MAGIC, num, dtype)
+#define HSC_IOWR(num, dtype)	_IOWR(HSI_CHAR_MAGIC, num, dtype)
+#define HSC_IO(num)		_IO(HSI_CHAR_MAGIC, num)
+
+#define HSC_RESET		HSC_IO(16)
+#define HSC_SET_PM		HSC_IO(17)
+#define HSC_SEND_BREAK		HSC_IO(18)
+#define HSC_SET_RX		HSC_IOW(19, struct hsc_rx_config)
+#define HSC_GET_RX		HSC_IOW(20, struct hsc_rx_config)
+#define HSC_SET_TX		HSC_IOW(21, struct hsc_tx_config)
+#define HSC_GET_TX		HSC_IOW(22, struct hsc_tx_config)
+
+#define HSC_PM_DISABLE		0
+#define HSC_PM_ENABLE		1
+
+#define HSC_MODE_STREAM		1
+#define HSC_MODE_FRAME		2
+#define HSC_FLOW_SYNC		0
+#define HSC_ARB_RR		0
+#define HSC_ARB_PRIO		1
+
+struct hsc_rx_config {
+	uint32_t mode;
+	uint32_t flow;
+	uint32_t channels;
+};
+
+struct hsc_tx_config {
+	uint32_t mode;
+	uint32_t channels;
+	uint32_t speed;
+	uint32_t arb_mode;
+};
+
+#endif /* __HSI_CHAR_H */
diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
index 1b92129..c8af7a2 100644
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -51,6 +51,9 @@
 				     unsigned long address,
 				     enum page_check_address_pmd_flag flag);
 
+#define HPAGE_PMD_ORDER (HPAGE_PMD_SHIFT-PAGE_SHIFT)
+#define HPAGE_PMD_NR (1<<HPAGE_PMD_ORDER)
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 #define HPAGE_PMD_SHIFT HPAGE_SHIFT
 #define HPAGE_PMD_MASK HPAGE_MASK
@@ -102,8 +105,6 @@
 		BUG_ON(pmd_trans_splitting(*____pmd) ||			\
 		       pmd_trans_huge(*____pmd));			\
 	} while (0)
-#define HPAGE_PMD_ORDER (HPAGE_PMD_SHIFT-PAGE_SHIFT)
-#define HPAGE_PMD_NR (1<<HPAGE_PMD_ORDER)
 #if HPAGE_PMD_ORDER > MAX_ORDER
 #error "hugepages can't be allocated by the buddy allocator"
 #endif
@@ -113,6 +114,18 @@
 				    unsigned long start,
 				    unsigned long end,
 				    long adjust_next);
+extern int __pmd_trans_huge_lock(pmd_t *pmd,
+				 struct vm_area_struct *vma);
+/* mmap_sem must be held on entry */
+static inline int pmd_trans_huge_lock(pmd_t *pmd,
+				      struct vm_area_struct *vma)
+{
+	VM_BUG_ON(!rwsem_is_locked(&vma->vm_mm->mmap_sem));
+	if (pmd_trans_huge(*pmd))
+		return __pmd_trans_huge_lock(pmd, vma);
+	else
+		return 0;
+}
 static inline void vma_adjust_trans_huge(struct vm_area_struct *vma,
 					 unsigned long start,
 					 unsigned long end,
@@ -146,9 +159,9 @@
 	return page;
 }
 #else /* CONFIG_TRANSPARENT_HUGEPAGE */
-#define HPAGE_PMD_SHIFT ({ BUG(); 0; })
-#define HPAGE_PMD_MASK ({ BUG(); 0; })
-#define HPAGE_PMD_SIZE ({ BUG(); 0; })
+#define HPAGE_PMD_SHIFT ({ BUILD_BUG(); 0; })
+#define HPAGE_PMD_MASK ({ BUILD_BUG(); 0; })
+#define HPAGE_PMD_SIZE ({ BUILD_BUG(); 0; })
 
 #define hpage_nr_pages(x) 1
 
@@ -176,6 +189,11 @@
 					 long adjust_next)
 {
 }
+static inline int pmd_trans_huge_lock(pmd_t *pmd,
+				      struct vm_area_struct *vma)
+{
+	return 0;
+}
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 #endif /* _LINUX_HUGE_MM_H */
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index d9d6c86..000837e 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -14,6 +14,15 @@
 #include <linux/shm.h>
 #include <asm/tlbflush.h>
 
+struct hugepage_subpool {
+	spinlock_t lock;
+	long count;
+	long max_hpages, used_hpages;
+};
+
+struct hugepage_subpool *hugepage_new_subpool(long nr_blocks);
+void hugepage_put_subpool(struct hugepage_subpool *spool);
+
 int PageHuge(struct page *page);
 
 void reset_vma_resv_huge_pages(struct vm_area_struct *vma);
@@ -128,35 +137,14 @@
 };
 
 #ifdef CONFIG_HUGETLBFS
-struct hugetlbfs_config {
-	uid_t   uid;
-	gid_t   gid;
-	umode_t mode;
-	long	nr_blocks;
-	long	nr_inodes;
-	struct hstate *hstate;
-};
-
 struct hugetlbfs_sb_info {
-	long	max_blocks;   /* blocks allowed */
-	long	free_blocks;  /* blocks free */
 	long	max_inodes;   /* inodes allowed */
 	long	free_inodes;  /* inodes free */
 	spinlock_t	stat_lock;
 	struct hstate *hstate;
+	struct hugepage_subpool *spool;
 };
 
-
-struct hugetlbfs_inode_info {
-	struct shared_policy policy;
-	struct inode vfs_inode;
-};
-
-static inline struct hugetlbfs_inode_info *HUGETLBFS_I(struct inode *inode)
-{
-	return container_of(inode, struct hugetlbfs_inode_info, vfs_inode);
-}
-
 static inline struct hugetlbfs_sb_info *HUGETLBFS_SB(struct super_block *sb)
 {
 	return sb->s_fs_info;
@@ -164,10 +152,9 @@
 
 extern const struct file_operations hugetlbfs_file_operations;
 extern const struct vm_operations_struct hugetlb_vm_ops;
-struct file *hugetlb_file_setup(const char *name, size_t size, vm_flags_t acct,
+struct file *hugetlb_file_setup(const char *name, unsigned long addr,
+				size_t size, vm_flags_t acct,
 				struct user_struct **user, int creat_flags);
-int hugetlb_get_quota(struct address_space *mapping, long delta);
-void hugetlb_put_quota(struct address_space *mapping, long delta);
 
 static inline int is_file_hugepages(struct file *file)
 {
@@ -179,15 +166,11 @@
 	return 0;
 }
 
-static inline void set_file_hugepages(struct file *file)
-{
-	file->f_op = &hugetlbfs_file_operations;
-}
 #else /* !CONFIG_HUGETLBFS */
 
 #define is_file_hugepages(file)			0
-#define set_file_hugepages(file)		BUG()
-static inline struct file *hugetlb_file_setup(const char *name, size_t size,
+static inline struct file *
+hugetlb_file_setup(const char *name, unsigned long addr, size_t size,
 		vm_flags_t acctflag, struct user_struct **user, int creat_flags)
 {
 	return ERR_PTR(-ENOSYS);
diff --git a/include/linux/hwmon-sysfs.h b/include/linux/hwmon-sysfs.h
index a90c09d..1c7b89a 100644
--- a/include/linux/hwmon-sysfs.h
+++ b/include/linux/hwmon-sysfs.h
@@ -20,6 +20,8 @@
 #ifndef _LINUX_HWMON_SYSFS_H
 #define _LINUX_HWMON_SYSFS_H
 
+#include <linux/device.h>
+
 struct sensor_device_attribute{
 	struct device_attribute dev_attr;
 	int index;
diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h
index 6b6ee70..82b29ae 100644
--- a/include/linux/hwmon.h
+++ b/include/linux/hwmon.h
@@ -14,7 +14,7 @@
 #ifndef _HWMON_H_
 #define _HWMON_H_
 
-#include <linux/device.h>
+struct device;
 
 struct device *hwmon_device_register(struct device *dev);
 
diff --git a/include/linux/hwspinlock.h b/include/linux/hwspinlock.h
index aad6bd4..3343298 100644
--- a/include/linux/hwspinlock.h
+++ b/include/linux/hwspinlock.h
@@ -20,12 +20,12 @@
 
 #include <linux/err.h>
 #include <linux/sched.h>
-#include <linux/device.h>
 
 /* hwspinlock mode argument */
 #define HWLOCK_IRQSTATE	0x01	/* Disable interrupts, save state */
 #define HWLOCK_IRQ	0x02	/* Disable interrupts, don't save state */
 
+struct device;
 struct hwspinlock;
 struct hwspinlock_device;
 struct hwspinlock_ops;
diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h
index 4f98148..63904ba 100644
--- a/include/linux/i2c-algo-bit.h
+++ b/include/linux/i2c-algo-bit.h
@@ -15,7 +15,8 @@
 
     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.                */
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.							     */
 /* ------------------------------------------------------------------------- */
 
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
@@ -49,5 +50,6 @@
 
 int i2c_bit_add_bus(struct i2c_adapter *);
 int i2c_bit_add_numbered_bus(struct i2c_adapter *);
+extern const struct i2c_algorithm i2c_bit_algo;
 
 #endif /* _LINUX_I2C_ALGO_BIT_H */
diff --git a/include/linux/i2c-algo-pcf.h b/include/linux/i2c-algo-pcf.h
index 0f91a95..538e8f4 100644
--- a/include/linux/i2c-algo-pcf.h
+++ b/include/linux/i2c-algo-pcf.h
@@ -16,7 +16,8 @@
 
     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.                */
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.							     */
 /* ------------------------------------------------------------------------- */
 
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
diff --git a/include/linux/i2c-dev.h b/include/linux/i2c-dev.h
index fd53bfd..8a7406b 100644
--- a/include/linux/i2c-dev.h
+++ b/include/linux/i2c-dev.h
@@ -16,7 +16,8 @@
 
     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.
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.
 */
 
 #ifndef _LINUX_I2C_DEV_H
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index 34536ef..747f0cd 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -18,7 +18,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
  */
 
 #ifndef _LINUX_I2C_MUX_H
diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h
index 63f57a8..017fb40 100644
--- a/include/linux/i2c-smbus.h
+++ b/include/linux/i2c-smbus.h
@@ -15,7 +15,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
  */
 
 #ifndef _LINUX_I2C_SMBUS_H
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 8e25a91..195d8b3 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -17,7 +17,8 @@
 
     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.		     */
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.							     */
 /* ------------------------------------------------------------------------- */
 
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
diff --git a/include/linux/i2c/at24.h b/include/linux/i2c/at24.h
index 8ace930..285025a 100644
--- a/include/linux/i2c/at24.h
+++ b/include/linux/i2c/at24.h
@@ -1,19 +1,42 @@
+/*
+ * at24.h - platform_data for the at24 (generic eeprom) driver
+ * (C) Copyright 2008 by Pengutronix
+ * (C) Copyright 2012 by Wolfram Sang
+ * same license as the driver
+ */
+
 #ifndef _LINUX_AT24_H
 #define _LINUX_AT24_H
 
 #include <linux/types.h>
 #include <linux/memory.h>
 
-/*
- * As seen through Linux I2C, differences between the most common types of I2C
- * memory include:
- * - How much memory is available (usually specified in bit)?
- * - What write page size does it support?
- * - Special flags (16 bit addresses, read_only, world readable...)?
+/**
+ * struct at24_platform_data - data to set up at24 (generic eeprom) driver
+ * @byte_len: size of eeprom in byte
+ * @page_size: number of byte which can be written in one go
+ * @flags: tunable options, check AT24_FLAG_* defines
+ * @setup: an optional callback invoked after eeprom is probed; enables kernel
+	code to access eeprom via memory_accessor, see example
+ * @context: optional parameter passed to setup()
  *
  * If you set up a custom eeprom type, please double-check the parameters.
  * Especially page_size needs extra care, as you risk data loss if your value
  * is bigger than what the chip actually supports!
+ *
+ * An example in pseudo code for a setup() callback:
+ *
+ * void get_mac_addr(struct memory_accessor *mem_acc, void *context)
+ * {
+ * 	u8 *mac_addr = ethernet_pdata->mac_addr;
+ *	off_t offset = context;
+ *
+ *	// Read MAC addr from EEPROM
+ *	if (mem_acc->read(mem_acc, mac_addr, offset, ETH_ALEN) == ETH_ALEN)
+ *		pr_info("Read MAC addr from EEPROM: %pM\n", mac_addr);
+ * }
+ *
+ * This function pointer and context can now be set up in at24_platform_data.
  */
 
 struct at24_platform_data {
diff --git a/include/linux/i2c/tc35876x.h b/include/linux/i2c/tc35876x.h
new file mode 100644
index 0000000..cd6a51c
--- /dev/null
+++ b/include/linux/i2c/tc35876x.h
@@ -0,0 +1,11 @@
+
+#ifndef _TC35876X_H
+#define _TC35876X_H
+
+struct tc35876x_platform_data {
+	int gpio_bridge_reset;
+	int gpio_panel_bl_en;
+	int gpio_panel_vadd;
+};
+
+#endif /* _TC35876X_H */
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index 7fcab23..2463b61 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -761,7 +761,7 @@
 
 /*----------------------------------------------------------------------*/
 
-int twl4030_sih_setup(int module);
+int twl4030_sih_setup(struct device *dev, int module, int irq_base);
 
 /* Offsets to Power Registers */
 #define TWL4030_VDAC_DEV_GRP		0x3B
diff --git a/include/linux/i2o.h b/include/linux/i2o.h
index a6deef4..d23c3c2 100644
--- a/include/linux/i2o.h
+++ b/include/linux/i2o.h
@@ -24,6 +24,7 @@
 #define I2O_MAX_DRIVERS		8
 
 #include <linux/pci.h>
+#include <linux/bug.h>
 #include <linux/dma-mapping.h>
 #include <linux/string.h>
 #include <linux/slab.h>
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 501370b..b179749 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -14,7 +14,6 @@
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/bio.h>
-#include <linux/device.h>
 #include <linux/pci.h>
 #include <linux/completion.h>
 #include <linux/pm.h>
@@ -23,7 +22,6 @@
 #include <acpi/acpi.h>
 #endif
 #include <asm/byteorder.h>
-#include <asm/system.h>
 #include <asm/io.h>
 
 /* for request_sense */
@@ -43,6 +41,8 @@
 #define ERROR_RESET	3	/* Reset controller every 4th retry */
 #define ERROR_RECAL	1	/* Recalibrate every 2nd retry */
 
+struct device;
+
 /* Error codes returned in rq->errors to the higher part of the driver. */
 enum {
 	IDE_DRV_ERROR_GENERAL	= 101,
diff --git a/include/linux/if_eql.h b/include/linux/if_eql.h
index 79c4f26..18a5d02 100644
--- a/include/linux/if_eql.h
+++ b/include/linux/if_eql.h
@@ -22,7 +22,7 @@
 #define EQL_DEFAULT_SLAVE_PRIORITY 28800
 #define EQL_DEFAULT_MAX_SLAVES     4
 #define EQL_DEFAULT_MTU            576
-#define EQL_DEFAULT_RESCHED_IVAL   100
+#define EQL_DEFAULT_RESCHED_IVAL   HZ
 
 #define EQL_ENSLAVE     (SIOCDEVPRIVATE)
 #define EQL_EMANCIPATE  (SIOCDEVPRIVATE + 1)
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 33a6e19..a810987 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -17,6 +17,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
+#include <linux/bug.h>
 
 #define VLAN_HLEN	4		/* The additional bytes required by VLAN
 					 * (in addition to the Ethernet header)
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index f994d51..e4baff5 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -29,6 +29,13 @@
 #define INIT_GROUP_RWSEM(sig)
 #endif
 
+#ifdef CONFIG_CPUSETS
+#define INIT_CPUSET_SEQ							\
+	.mems_allowed_seq = SEQCNT_ZERO,
+#else
+#define INIT_CPUSET_SEQ
+#endif
+
 #define INIT_SIGNALS(sig) {						\
 	.nr_threads	= 1,						\
 	.wait_chldexit	= __WAIT_QUEUE_HEAD_INITIALIZER(sig.wait_chldexit),\
@@ -192,6 +199,7 @@
 	INIT_FTRACE_GRAPH						\
 	INIT_TRACE_RECURSION						\
 	INIT_TASK_RCU_PREEMPT(tsk)					\
+	INIT_CPUSET_SEQ							\
 }
 
 
diff --git a/include/linux/input.h b/include/linux/input.h
index 3862e32..a816714 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -114,6 +114,31 @@
 #define EVIOCGUNIQ(len)		_IOC(_IOC_READ, 'E', 0x08, len)		/* get unique identifier */
 #define EVIOCGPROP(len)		_IOC(_IOC_READ, 'E', 0x09, len)		/* get device properties */
 
+/**
+ * EVIOCGMTSLOTS(len) - get MT slot values
+ *
+ * The ioctl buffer argument should be binary equivalent to
+ *
+ * struct input_mt_request_layout {
+ *	__u32 code;
+ *	__s32 values[num_slots];
+ * };
+ *
+ * where num_slots is the (arbitrary) number of MT slots to extract.
+ *
+ * The ioctl size argument (len) is the size of the buffer, which
+ * should satisfy len = (num_slots + 1) * sizeof(__s32).  If len is
+ * too small to fit all available slots, the first num_slots are
+ * returned.
+ *
+ * Before the call, code is set to the wanted ABS_MT event type. On
+ * return, values[] is filled with the slot values for the specified
+ * ABS_MT code.
+ *
+ * If the request code is not an ABS_MT value, -EINVAL is returned.
+ */
+#define EVIOCGMTSLOTS(len)	_IOC(_IOC_READ, 'E', 0x0a, len)
+
 #define EVIOCGKEY(len)		_IOC(_IOC_READ, 'E', 0x18, len)		/* get global key state */
 #define EVIOCGLED(len)		_IOC(_IOC_READ, 'E', 0x19, len)		/* get all LEDs */
 #define EVIOCGSND(len)		_IOC(_IOC_READ, 'E', 0x1a, len)		/* get all sounds status */
@@ -129,6 +154,8 @@
 
 #define EVIOCGRAB		_IOW('E', 0x90, int)			/* Grab/Release device */
 
+#define EVIOCSCLOCKID		_IOW('E', 0xa0, int)			/* Set clockid to be used for timestamps */
+
 /*
  * Device properties and quirks
  */
diff --git a/include/linux/input/cyttsp.h b/include/linux/input/cyttsp.h
new file mode 100644
index 0000000..5af7c66
--- /dev/null
+++ b/include/linux/input/cyttsp.h
@@ -0,0 +1,58 @@
+/*
+ * Header file for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com)
+ *
+ */
+#ifndef _CYTTSP_H_
+#define _CYTTSP_H_
+
+#define CY_SPI_NAME "cyttsp-spi"
+#define CY_I2C_NAME "cyttsp-i2c"
+/* Active Power state scanning/processing refresh interval */
+#define CY_ACT_INTRVL_DFLT 0x00 /* ms */
+/* touch timeout for the Active power */
+#define CY_TCH_TMOUT_DFLT 0xFF /* ms */
+/* Low Power state scanning/processing refresh interval */
+#define CY_LP_INTRVL_DFLT 0x0A /* ms */
+/* Active distance in pixels for a gesture to be reported */
+#define CY_ACT_DIST_DFLT 0xF8 /* pixels */
+
+struct cyttsp_platform_data {
+	u32 maxx;
+	u32 maxy;
+	bool use_hndshk;
+	u8 act_dist;	/* Active distance */
+	u8 act_intrvl;  /* Active refresh interval; ms */
+	u8 tch_tmout;   /* Active touch timeout; ms */
+	u8 lp_intrvl;   /* Low power refresh interval; ms */
+	int (*init)(void);
+	void (*exit)(void);
+	char *name;
+	s16 irq_gpio;
+	u8 *bl_keys;
+};
+
+#endif /* _CYTTSP_H_ */
diff --git a/include/linux/input/ili210x.h b/include/linux/input/ili210x.h
new file mode 100644
index 0000000..a547124
--- /dev/null
+++ b/include/linux/input/ili210x.h
@@ -0,0 +1,10 @@
+#ifndef _ILI210X_H
+#define _ILI210X_H
+
+struct ili210x_platform_data {
+	unsigned long irq_flags;
+	unsigned int poll_period;
+	bool (*get_pendown_state)(void);
+};
+
+#endif
diff --git a/include/linux/input/kxtj9.h b/include/linux/input/kxtj9.h
index f6bac89..d415579 100644
--- a/include/linux/input/kxtj9.h
+++ b/include/linux/input/kxtj9.h
@@ -24,6 +24,7 @@
 
 struct kxtj9_platform_data {
 	unsigned int min_interval;	/* minimum poll interval (in milli-seconds) */
+	unsigned int init_interval;	/* initial poll interval (in milli-seconds) */
 
 	/*
 	 * By default, x is axis 0, y is axis 1, z is axis 2; these can be
@@ -52,16 +53,6 @@
 	#define KXTJ9_G_8G		(1 << 4)
 	u8 g_range;
 
-	/* DATA_CTRL_REG: controls the output data rate of the part */
-	#define ODR12_5F		0
-	#define ODR25F			1
-	#define ODR50F			2
-	#define ODR100F			3
-	#define ODR200F			4
-	#define ODR400F			5
-	#define ODR800F			6
-	u8 data_odr_init;
-
 	int (*init)(void);
 	void (*exit)(void);
 	int (*power_on)(void);
diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h
index fe7c4b9..6c07ced0 100644
--- a/include/linux/input/matrix_keypad.h
+++ b/include/linux/input/matrix_keypad.h
@@ -3,6 +3,7 @@
 
 #include <linux/types.h>
 #include <linux/input.h>
+#include <linux/of.h>
 
 #define MATRIX_MAX_ROWS		32
 #define MATRIX_MAX_COLS		32
@@ -106,4 +107,22 @@
 	__clear_bit(KEY_RESERVED, keybit);
 }
 
+#ifdef CONFIG_INPUT_OF_MATRIX_KEYMAP
+struct matrix_keymap_data *
+matrix_keyboard_of_fill_keymap(struct device_node *np, const char *propname);
+
+void matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd);
+#else
+static inline struct matrix_keymap_data *
+matrix_keyboard_of_fill_keymap(struct device_node *np, const char *propname)
+{
+	return NULL;
+}
+
+static inline void
+matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd)
+{
+}
+#endif
+
 #endif /* _MATRIX_KEYPAD_H */
diff --git a/include/linux/input/mt.h b/include/linux/input/mt.h
index 318bb82..f867375 100644
--- a/include/linux/input/mt.h
+++ b/include/linux/input/mt.h
@@ -48,10 +48,14 @@
 	input_event(dev, EV_ABS, ABS_MT_SLOT, slot);
 }
 
+static inline bool input_is_mt_value(int axis)
+{
+	return axis >= ABS_MT_FIRST && axis <= ABS_MT_LAST;
+}
+
 static inline bool input_is_mt_axis(int axis)
 {
-	return axis == ABS_MT_SLOT ||
-		(axis >= ABS_MT_FIRST && axis <= ABS_MT_LAST);
+	return axis == ABS_MT_SLOT || input_is_mt_value(axis);
 }
 
 void input_mt_report_slot_state(struct input_dev *dev,
diff --git a/include/linux/input/ti_tscadc.h b/include/linux/input/ti_tscadc.h
new file mode 100644
index 0000000..b10a527
--- /dev/null
+++ b/include/linux/input/ti_tscadc.h
@@ -0,0 +1,17 @@
+#ifndef __LINUX_TI_TSCADC_H
+#define __LINUX_TI_TSCADC_H
+
+/**
+ * struct tsc_data	Touchscreen wire configuration
+ * @wires:		Wires refer to application modes
+ *			i.e. 4/5/8 wire touchscreen support
+ *			on the platform.
+ * @x_plate_resistance:	X plate resistance.
+ */
+
+struct tsc_data {
+	int wires;
+	int x_plate_resistance;
+};
+
+#endif
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 3f830e0..2aea5d2 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -19,7 +19,6 @@
 
 #include <linux/atomic.h>
 #include <asm/ptrace.h>
-#include <asm/system.h>
 
 /*
  * These correspond to the IORESOURCE_IRQ_* defines in
diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h
index e44e84f..657fab4 100644
--- a/include/linux/io-mapping.h
+++ b/include/linux/io-mapping.h
@@ -20,6 +20,7 @@
 
 #include <linux/types.h>
 #include <linux/slab.h>
+#include <linux/bug.h>
 #include <asm/io.h>
 #include <asm/page.h>
 
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 9d57a71..e885ba23 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -23,12 +23,6 @@
 	struct resource *parent, *sibling, *child;
 };
 
-struct resource_list {
-	struct resource_list *next;
-	struct resource *res;
-	struct pci_dev *dev;
-};
-
 /*
  * IO resources have these defined flags.
  */
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
index bbd156b..48dcba9 100644
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -220,10 +220,10 @@
  * The in-kernel interface.
  */
 #include <linux/list.h>
-#include <linux/device.h>
 #include <linux/proc_fs.h>
 
 struct module;
+struct device;
 
 /* Opaque type for a IPMI message user.  One of these is needed to
    send and receive messages. */
diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h
index 3ef0d8b..fcb5d44 100644
--- a/include/linux/ipmi_smi.h
+++ b/include/linux/ipmi_smi.h
@@ -36,10 +36,11 @@
 
 #include <linux/ipmi_msgdefs.h>
 #include <linux/proc_fs.h>
-#include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/ipmi.h>
 
+struct device;
+
 /* This files describes the interface for IPMI system management interface
    drivers to bind into the IPMI message handler. */
 
diff --git a/include/linux/ivtv.h b/include/linux/ivtv.h
index 062d20f..42bf725 100644
--- a/include/linux/ivtv.h
+++ b/include/linux/ivtv.h
@@ -58,7 +58,11 @@
 	__u32 src_height;
 };
 
-#define IVTV_IOC_DMA_FRAME  _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame)
+#define IVTV_IOC_DMA_FRAME		_IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame)
+
+/* Select the passthrough mode (if the argument is non-zero). In the passthrough
+   mode the output of the encoder is passed immediately into the decoder. */
+#define IVTV_IOC_PASSTHROUGH_MODE	_IOW ('V', BASE_VIDIOC_PRIVATE+1, int)
 
 /* Deprecated defines: applications should use the defines from videodev2.h */
 #define IVTV_SLICED_TYPE_TELETEXT_B     V4L2_MPEG_VBI_IVTV_TELETEXT_B
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index 5557bae..912c30a 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -971,6 +971,10 @@
 /* Log buffer allocation */
 extern struct journal_head * jbd2_journal_get_descriptor_buffer(journal_t *);
 int jbd2_journal_next_log_block(journal_t *, unsigned long long *);
+int jbd2_journal_get_log_tail(journal_t *journal, tid_t *tid,
+			      unsigned long *block);
+void __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block);
+void jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block);
 
 /* Commit management */
 extern void jbd2_journal_commit_transaction(journal_t *);
@@ -1020,6 +1024,11 @@
 /* Transaction locking */
 extern void		__wait_on_journal (journal_t *);
 
+/* Transaction cache support */
+extern void jbd2_journal_destroy_transaction_cache(void);
+extern int  jbd2_journal_init_transaction_cache(void);
+extern void jbd2_journal_free_transaction(transaction_t *);
+
 /*
  * Journal locking.
  *
@@ -1082,7 +1091,8 @@
 extern int	   jbd2_journal_recover    (journal_t *journal);
 extern int	   jbd2_journal_wipe       (journal_t *, int);
 extern int	   jbd2_journal_skip_recovery	(journal_t *);
-extern void	   jbd2_journal_update_superblock	(journal_t *, int);
+extern void	   jbd2_journal_update_sb_log_tail	(journal_t *, tid_t,
+				unsigned long, int);
 extern void	   __jbd2_journal_abort_hard	(journal_t *);
 extern void	   jbd2_journal_abort      (journal_t *, int);
 extern int	   jbd2_journal_errno      (journal_t *);
diff --git a/include/linux/journal-head.h b/include/linux/journal-head.h
index 423cb6d..c18b46f 100644
--- a/include/linux/journal-head.h
+++ b/include/linux/journal-head.h
@@ -66,6 +66,8 @@
 	 * transaction (if there is one).  Only applies to buffers on a
 	 * transaction's data or metadata journaling list.
 	 * [j_list_lock] [jbd_lock_bh_state()]
+	 * Either of these locks is enough for reading, both are needed for
+	 * changes.
 	 */
 	transaction_t *b_transaction;
 
diff --git a/include/linux/jz4740-adc.h b/include/linux/jz4740-adc.h
index 9053f95..8184578 100644
--- a/include/linux/jz4740-adc.h
+++ b/include/linux/jz4740-adc.h
@@ -2,7 +2,7 @@
 #ifndef __LINUX_JZ4740_ADC
 #define __LINUX_JZ4740_ADC
 
-#include <linux/device.h>
+struct device;
 
 /*
  * jz4740_adc_set_config - Configure a JZ4740 adc device
diff --git a/include/linux/kernel-page-flags.h b/include/linux/kernel-page-flags.h
index bd92a89..26a6571 100644
--- a/include/linux/kernel-page-flags.h
+++ b/include/linux/kernel-page-flags.h
@@ -30,6 +30,7 @@
 #define KPF_NOPAGE		20
 
 #define KPF_KSM			21
+#define KPF_THP			22
 
 /* kernel hacking assistances
  * WARNING: subject to change, never rely on them!
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index d801acb..645231c 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -1,6 +1,8 @@
 #ifndef _LINUX_KERNEL_H
 #define _LINUX_KERNEL_H
 
+#include <linux/sysinfo.h>
+
 /*
  * 'kernel.h' contains some often-used function prototypes etc
  */
@@ -20,7 +22,6 @@
 #include <linux/printk.h>
 #include <linux/dynamic_debug.h>
 #include <asm/byteorder.h>
-#include <asm/bug.h>
 
 #define USHRT_MAX	((u16)(~0U))
 #define SHRT_MAX	((s16)(USHRT_MAX>>1))
@@ -312,6 +313,8 @@
 #define strict_strtoull	kstrtoull
 #define strict_strtoll	kstrtoll
 
+extern int num_to_str(char *buf, int size, unsigned long long num);
+
 /* lib/printf utilities */
 
 extern __printf(2, 3) int sprintf(char *buf, const char * fmt, ...);
@@ -328,10 +331,10 @@
 char *kasprintf(gfp_t gfp, const char *fmt, ...);
 extern char *kvasprintf(gfp_t gfp, const char *fmt, va_list args);
 
-extern int sscanf(const char *, const char *, ...)
-	__attribute__ ((format (scanf, 2, 3)));
-extern int vsscanf(const char *, const char *, va_list)
-	__attribute__ ((format (scanf, 2, 0)));
+extern __scanf(2, 3)
+int sscanf(const char *, const char *, ...);
+extern __scanf(2, 0)
+int vsscanf(const char *, const char *, va_list);
 
 extern int get_option(char **str, int *pint);
 extern char *get_options(const char *str, int nints, int *ints);
@@ -427,16 +430,10 @@
  * Most likely, you want to use tracing_on/tracing_off.
  */
 #ifdef CONFIG_RING_BUFFER
-void tracing_on(void);
-void tracing_off(void);
 /* trace_off_permanent stops recording with no way to bring it back */
 void tracing_off_permanent(void);
-int tracing_is_on(void);
 #else
-static inline void tracing_on(void) { }
-static inline void tracing_off(void) { }
 static inline void tracing_off_permanent(void) { }
-static inline int tracing_is_on(void) { return 0; }
 #endif
 
 enum ftrace_dump_mode {
@@ -446,6 +443,10 @@
 };
 
 #ifdef CONFIG_TRACING
+void tracing_on(void);
+void tracing_off(void);
+int tracing_is_on(void);
+
 extern void tracing_start(void);
 extern void tracing_stop(void);
 extern void ftrace_off_permanent(void);
@@ -530,6 +531,11 @@
 static inline void tracing_stop(void) { }
 static inline void ftrace_off_permanent(void) { }
 static inline void trace_dump_stack(void) { }
+
+static inline void tracing_on(void) { }
+static inline void tracing_off(void) { }
+static inline int tracing_is_on(void) { return 0; }
+
 static inline int
 trace_printk(const char *fmt, ...)
 {
@@ -675,67 +681,6 @@
 	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
 	(type *)( (char *)__mptr - offsetof(type,member) );})
 
-#ifdef __CHECKER__
-#define BUILD_BUG_ON_NOT_POWER_OF_2(n)
-#define BUILD_BUG_ON_ZERO(e) (0)
-#define BUILD_BUG_ON_NULL(e) ((void*)0)
-#define BUILD_BUG_ON(condition)
-#define BUILD_BUG() (0)
-#else /* __CHECKER__ */
-
-/* Force a compilation error if a constant expression is not a power of 2 */
-#define BUILD_BUG_ON_NOT_POWER_OF_2(n)			\
-	BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
-
-/* Force a compilation error if condition is true, but also produce a
-   result (of value 0 and type size_t), so the expression can be used
-   e.g. in a structure initializer (or where-ever else comma expressions
-   aren't permitted). */
-#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
-#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
-
-/**
- * BUILD_BUG_ON - break compile if a condition is true.
- * @condition: the condition which the compiler should know is false.
- *
- * If you have some code which relies on certain constants being equal, or
- * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
- * detect if someone changes it.
- *
- * The implementation uses gcc's reluctance to create a negative array, but
- * gcc (as of 4.4) only emits that error for obvious cases (eg. not arguments
- * to inline functions).  So as a fallback we use the optimizer; if it can't
- * prove the condition is false, it will cause a link error on the undefined
- * "__build_bug_on_failed".  This error message can be harder to track down
- * though, hence the two different methods.
- */
-#ifndef __OPTIMIZE__
-#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
-#else
-extern int __build_bug_on_failed;
-#define BUILD_BUG_ON(condition)					\
-	do {							\
-		((void)sizeof(char[1 - 2*!!(condition)]));	\
-		if (condition) __build_bug_on_failed = 1;	\
-	} while(0)
-#endif
-
-/**
- * BUILD_BUG - break compile if used.
- *
- * If you have some code that you expect the compiler to eliminate at
- * build time, you should use BUILD_BUG to detect if it is
- * unexpectedly used.
- */
-#define BUILD_BUG()						\
-	do {							\
-		extern void __build_bug_failed(void)		\
-			__linktime_error("BUILD_BUG failed");	\
-		__build_bug_failed();				\
-	} while (0)
-
-#endif	/* __CHECKER__ */
-
 /* Trap pasters of __FUNCTION__ at compile-time */
 #define __FUNCTION__ (__func__)
 
@@ -758,27 +703,8 @@
 # define REBUILD_DUE_TO_FTRACE_MCOUNT_RECORD
 #endif
 
-struct sysinfo;
 extern int do_sysinfo(struct sysinfo *info);
 
 #endif /* __KERNEL__ */
 
-#define SI_LOAD_SHIFT	16
-struct sysinfo {
-	long uptime;			/* Seconds since boot */
-	unsigned long loads[3];		/* 1, 5, and 15 minute load averages */
-	unsigned long totalram;		/* Total usable main memory size */
-	unsigned long freeram;		/* Available memory size */
-	unsigned long sharedram;	/* Amount of shared memory */
-	unsigned long bufferram;	/* Memory used by buffers */
-	unsigned long totalswap;	/* Total swap space size */
-	unsigned long freeswap;		/* swap space still available */
-	unsigned short procs;		/* Number of current processes */
-	unsigned short pad;		/* explicit padding for m68k */
-	unsigned long totalhigh;	/* Total high memory size */
-	unsigned long freehigh;		/* Available high memory size */
-	unsigned int mem_unit;		/* Memory unit size in bytes */
-	char _f[20-2*sizeof(long)-sizeof(int)];	/* Padding: libc5 uses this.. */
-};
-
 #endif
diff --git a/include/linux/key.h b/include/linux/key.h
index 1600ebf..96933b1 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -277,6 +277,8 @@
 	return key ? key->serial : 0;
 }
 
+extern void key_set_timeout(struct key *, unsigned);
+
 /**
  * key_is_instantiated - Determine if a key has been positively instantiated
  * @key: The key to check.
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h
index fa39183..c4d2fc1 100644
--- a/include/linux/kgdb.h
+++ b/include/linux/kgdb.h
@@ -63,7 +63,8 @@
 	BP_HARDWARE_BREAKPOINT,
 	BP_WRITE_WATCHPOINT,
 	BP_READ_WATCHPOINT,
-	BP_ACCESS_WATCHPOINT
+	BP_ACCESS_WATCHPOINT,
+	BP_POKE_BREAKPOINT,
 };
 
 enum kgdb_bpstate {
@@ -207,8 +208,8 @@
 
 /* Optional functions. */
 extern int kgdb_validate_break_address(unsigned long addr);
-extern int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr);
-extern int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle);
+extern int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt);
+extern int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt);
 
 /**
  *	kgdb_arch_late - Perform any architecture specific initalization.
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index 722f477..dd99c329 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -48,11 +48,10 @@
 struct cred;
 struct file;
 
-enum umh_wait {
-	UMH_NO_WAIT = -1,	/* don't wait at all */
-	UMH_WAIT_EXEC = 0,	/* wait for the exec, but not the process */
-	UMH_WAIT_PROC = 1,	/* wait for the process to complete */
-};
+#define UMH_NO_WAIT	0	/* don't wait at all */
+#define UMH_WAIT_EXEC	1	/* wait for the exec, but not the process */
+#define UMH_WAIT_PROC	2	/* wait for the process to complete */
+#define UMH_KILLABLE	4	/* wait for EXEC/PROC killable */
 
 struct subprocess_info {
 	struct work_struct work;
@@ -60,7 +59,7 @@
 	char *path;
 	char **argv;
 	char **envp;
-	enum umh_wait wait;
+	int wait;
 	int retval;
 	int (*init)(struct subprocess_info *info, struct cred *new);
 	void (*cleanup)(struct subprocess_info *info);
@@ -78,15 +77,14 @@
 		    void *data);
 
 /* Actually execute the sub-process */
-int call_usermodehelper_exec(struct subprocess_info *info, enum umh_wait wait);
+int call_usermodehelper_exec(struct subprocess_info *info, int wait);
 
 /* Free the subprocess_info. This is only needed if you're not going
    to call call_usermodehelper_exec */
 void call_usermodehelper_freeinfo(struct subprocess_info *info);
 
 static inline int
-call_usermodehelper_fns(char *path, char **argv, char **envp,
-			enum umh_wait wait,
+call_usermodehelper_fns(char *path, char **argv, char **envp, int wait,
 			int (*init)(struct subprocess_info *info, struct cred *new),
 			void (*cleanup)(struct subprocess_info *), void *data)
 {
@@ -104,7 +102,7 @@
 }
 
 static inline int
-call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait)
+call_usermodehelper(char *path, char **argv, char **envp, int wait)
 {
 	return call_usermodehelper_fns(path, argv, envp, wait,
 				       NULL, NULL, NULL);
@@ -112,12 +110,29 @@
 
 extern struct ctl_table usermodehelper_table[];
 
+enum umh_disable_depth {
+	UMH_ENABLED = 0,
+	UMH_FREEZING,
+	UMH_DISABLED,
+};
+
 extern void usermodehelper_init(void);
 
-extern int usermodehelper_disable(void);
-extern void usermodehelper_enable(void);
-extern bool usermodehelper_is_disabled(void);
-extern void read_lock_usermodehelper(void);
-extern void read_unlock_usermodehelper(void);
+extern int __usermodehelper_disable(enum umh_disable_depth depth);
+extern void __usermodehelper_set_disable_depth(enum umh_disable_depth depth);
+
+static inline int usermodehelper_disable(void)
+{
+	return __usermodehelper_disable(UMH_DISABLED);
+}
+
+static inline void usermodehelper_enable(void)
+{
+	__usermodehelper_set_disable_depth(UMH_ENABLED);
+}
+
+extern int usermodehelper_read_trylock(void);
+extern long usermodehelper_read_lock_wait(long timeout);
+extern void usermodehelper_read_unlock(void);
 
 #endif /* __LINUX_KMOD_H__ */
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index dce6e4d..b6e1f8c 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -33,6 +33,7 @@
 #include <linux/list.h>
 #include <linux/notifier.h>
 #include <linux/smp.h>
+#include <linux/bug.h>
 #include <linux/percpu.h>
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 68e67e5..6c322a9 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -162,6 +162,7 @@
 #define KVM_EXIT_INTERNAL_ERROR   17
 #define KVM_EXIT_OSI              18
 #define KVM_EXIT_PAPR_HCALL	  19
+#define KVM_EXIT_S390_UCONTROL	  20
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 #define KVM_INTERNAL_ERROR_EMULATION 1
@@ -249,6 +250,11 @@
 #define KVM_S390_RESET_CPU_INIT  8
 #define KVM_S390_RESET_IPL       16
 		__u64 s390_reset_flags;
+		/* KVM_EXIT_S390_UCONTROL */
+		struct {
+			__u64 trans_exc_code;
+			__u32 pgm_code;
+		} s390_ucontrol;
 		/* KVM_EXIT_DCR */
 		struct {
 			__u32 dcrn;
@@ -273,6 +279,20 @@
 		/* Fix the size of the union. */
 		char padding[256];
 	};
+
+	/*
+	 * shared registers between kvm and userspace.
+	 * kvm_valid_regs specifies the register classes set by the host
+	 * kvm_dirty_regs specified the register classes dirtied by userspace
+	 * struct kvm_sync_regs is architecture specific, as well as the
+	 * bits for kvm_valid_regs and kvm_dirty_regs
+	 */
+	__u64 kvm_valid_regs;
+	__u64 kvm_dirty_regs;
+	union {
+		struct kvm_sync_regs regs;
+		char padding[1024];
+	} s;
 };
 
 /* for KVM_REGISTER_COALESCED_MMIO / KVM_UNREGISTER_COALESCED_MMIO */
@@ -431,6 +451,11 @@
 
 #define KVMIO 0xAE
 
+/* machine type bits, to be used as argument to KVM_CREATE_VM */
+#define KVM_VM_S390_UCONTROL	1
+
+#define KVM_S390_SIE_PAGE_OFFSET 1
+
 /*
  * ioctls for /dev/kvm fds:
  */
@@ -555,9 +580,15 @@
 #define KVM_CAP_PPC_SMT 64
 #define KVM_CAP_PPC_RMA	65
 #define KVM_CAP_MAX_VCPUS 66       /* returns max vcpus per vm */
+#define KVM_CAP_PPC_HIOR 67
 #define KVM_CAP_PPC_PAPR 68
+#define KVM_CAP_SW_TLB 69
+#define KVM_CAP_ONE_REG 70
 #define KVM_CAP_S390_GMAP 71
 #define KVM_CAP_TSC_DEADLINE_TIMER 72
+#define KVM_CAP_S390_UCONTROL 73
+#define KVM_CAP_SYNC_REGS 74
+#define KVM_CAP_PCI_2_3 75
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -637,6 +668,52 @@
 	__u32 pad[9];
 };
 
+#define KVM_MMU_FSL_BOOKE_NOHV		0
+#define KVM_MMU_FSL_BOOKE_HV		1
+
+struct kvm_config_tlb {
+	__u64 params;
+	__u64 array;
+	__u32 mmu_type;
+	__u32 array_len;
+};
+
+struct kvm_dirty_tlb {
+	__u64 bitmap;
+	__u32 num_dirty;
+};
+
+/* Available with KVM_CAP_ONE_REG */
+
+#define KVM_REG_ARCH_MASK	0xff00000000000000ULL
+#define KVM_REG_GENERIC		0x0000000000000000ULL
+
+/*
+ * Architecture specific registers are to be defined in arch headers and
+ * ORed with the arch identifier.
+ */
+#define KVM_REG_PPC		0x1000000000000000ULL
+#define KVM_REG_X86		0x2000000000000000ULL
+#define KVM_REG_IA64		0x3000000000000000ULL
+#define KVM_REG_ARM		0x4000000000000000ULL
+#define KVM_REG_S390		0x5000000000000000ULL
+
+#define KVM_REG_SIZE_SHIFT	52
+#define KVM_REG_SIZE_MASK	0x00f0000000000000ULL
+#define KVM_REG_SIZE_U8		0x0000000000000000ULL
+#define KVM_REG_SIZE_U16	0x0010000000000000ULL
+#define KVM_REG_SIZE_U32	0x0020000000000000ULL
+#define KVM_REG_SIZE_U64	0x0030000000000000ULL
+#define KVM_REG_SIZE_U128	0x0040000000000000ULL
+#define KVM_REG_SIZE_U256	0x0050000000000000ULL
+#define KVM_REG_SIZE_U512	0x0060000000000000ULL
+#define KVM_REG_SIZE_U1024	0x0070000000000000ULL
+
+struct kvm_one_reg {
+	__u64 id;
+	__u64 addr;
+};
+
 /*
  * ioctls for VM fds
  */
@@ -655,6 +732,17 @@
 					struct kvm_userspace_memory_region)
 #define KVM_SET_TSS_ADDR          _IO(KVMIO,   0x47)
 #define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO,  0x48, __u64)
+
+/* enable ucontrol for s390 */
+struct kvm_s390_ucas_mapping {
+	__u64 user_addr;
+	__u64 vcpu_addr;
+	__u64 length;
+};
+#define KVM_S390_UCAS_MAP        _IOW(KVMIO, 0x50, struct kvm_s390_ucas_mapping)
+#define KVM_S390_UCAS_UNMAP      _IOW(KVMIO, 0x51, struct kvm_s390_ucas_mapping)
+#define KVM_S390_VCPU_FAULT	 _IOW(KVMIO, 0x52, unsigned long)
+
 /* Device model IOC */
 #define KVM_CREATE_IRQCHIP        _IO(KVMIO,   0x60)
 #define KVM_IRQ_LINE              _IOW(KVMIO,  0x61, struct kvm_irq_level)
@@ -697,6 +785,9 @@
 /* Available with KVM_CAP_TSC_CONTROL */
 #define KVM_SET_TSC_KHZ           _IO(KVMIO,  0xa2)
 #define KVM_GET_TSC_KHZ           _IO(KVMIO,  0xa3)
+/* Available with KVM_CAP_PCI_2_3 */
+#define KVM_ASSIGN_SET_INTX_MASK  _IOW(KVMIO,  0xa4, \
+				       struct kvm_assigned_pci_dev)
 
 /*
  * ioctls for vcpu fds
@@ -763,8 +854,15 @@
 #define KVM_CREATE_SPAPR_TCE	  _IOW(KVMIO,  0xa8, struct kvm_create_spapr_tce)
 /* Available with KVM_CAP_RMA */
 #define KVM_ALLOCATE_RMA	  _IOR(KVMIO,  0xa9, struct kvm_allocate_rma)
+/* Available with KVM_CAP_SW_TLB */
+#define KVM_DIRTY_TLB		  _IOW(KVMIO,  0xaa, struct kvm_dirty_tlb)
+/* Available with KVM_CAP_ONE_REG */
+#define KVM_GET_ONE_REG		  _IOW(KVMIO,  0xab, struct kvm_one_reg)
+#define KVM_SET_ONE_REG		  _IOW(KVMIO,  0xac, struct kvm_one_reg)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
+#define KVM_DEV_ASSIGN_PCI_2_3		(1 << 1)
+#define KVM_DEV_ASSIGN_MASK_INTX	(1 << 2)
 
 struct kvm_assigned_pci_dev {
 	__u32 assigned_dev_id;
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 900c763..665a260 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -13,6 +13,7 @@
 #include <linux/spinlock.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
+#include <linux/bug.h>
 #include <linux/mm.h>
 #include <linux/mmu_notifier.h>
 #include <linux/preempt.h>
@@ -171,11 +172,6 @@
  */
 #define KVM_MEM_MAX_NR_PAGES ((1UL << 31) - 1)
 
-struct kvm_lpage_info {
-	unsigned long rmap_pde;
-	int write_count;
-};
-
 struct kvm_memory_slot {
 	gfn_t base_gfn;
 	unsigned long npages;
@@ -184,7 +180,7 @@
 	unsigned long *dirty_bitmap;
 	unsigned long *dirty_bitmap_head;
 	unsigned long nr_dirty_pages;
-	struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1];
+	struct kvm_arch_memory_slot arch;
 	unsigned long userspace_addr;
 	int user_alloc;
 	int id;
@@ -376,6 +372,9 @@
 int __kvm_set_memory_region(struct kvm *kvm,
 			    struct kvm_userspace_memory_region *mem,
 			    int user_alloc);
+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);
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
 				struct kvm_memory_slot *memslot,
 				struct kvm_memory_slot old,
@@ -385,6 +384,7 @@
 				struct kvm_userspace_memory_region *mem,
 				struct kvm_memory_slot old,
 				int user_alloc);
+bool kvm_largepages_enabled(void);
 void kvm_disable_largepages(void);
 void kvm_arch_flush_shadow(struct kvm *kvm);
 
@@ -450,6 +450,7 @@
 			unsigned int ioctl, unsigned long arg);
 long kvm_arch_vcpu_ioctl(struct file *filp,
 			 unsigned int ioctl, unsigned long arg);
+int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf);
 
 int kvm_dev_ioctl_check_extension(long ext);
 
@@ -520,7 +521,7 @@
 }
 #endif
 
-int kvm_arch_init_vm(struct kvm *kvm);
+int kvm_arch_init_vm(struct kvm *kvm, unsigned long type);
 void kvm_arch_destroy_vm(struct kvm *kvm);
 void kvm_free_all_assigned_devices(struct kvm *kvm);
 void kvm_arch_sync_events(struct kvm *kvm);
@@ -546,6 +547,7 @@
 	unsigned int entries_nr;
 	int host_irq;
 	bool host_irq_disabled;
+	bool pci_2_3;
 	struct msix_entry *host_msix_entries;
 	int guest_irq;
 	struct msix_entry *guest_msix_entries;
@@ -555,6 +557,7 @@
 	struct pci_dev *dev;
 	struct kvm *kvm;
 	spinlock_t intx_lock;
+	spinlock_t intx_mask_lock;
 	char irq_name[32];
 	struct pci_saved_state *pci_saved_state;
 };
@@ -650,11 +653,43 @@
 	current->flags &= ~PF_VCPU;
 }
 
+/*
+ * search_memslots() and __gfn_to_memslot() are here because they are
+ * used in non-modular code in arch/powerpc/kvm/book3s_hv_rm_mmu.c.
+ * gfn_to_memslot() itself isn't here as an inline because that would
+ * bloat other code too much.
+ */
+static inline struct kvm_memory_slot *
+search_memslots(struct kvm_memslots *slots, gfn_t gfn)
+{
+	struct kvm_memory_slot *memslot;
+
+	kvm_for_each_memslot(memslot, slots)
+		if (gfn >= memslot->base_gfn &&
+		      gfn < memslot->base_gfn + memslot->npages)
+			return memslot;
+
+	return NULL;
+}
+
+static inline struct kvm_memory_slot *
+__gfn_to_memslot(struct kvm_memslots *slots, gfn_t gfn)
+{
+	return search_memslots(slots, gfn);
+}
+
 static inline int memslot_id(struct kvm *kvm, gfn_t gfn)
 {
 	return gfn_to_memslot(kvm, gfn)->id;
 }
 
+static inline gfn_t gfn_to_index(gfn_t gfn, gfn_t base_gfn, int level)
+{
+	/* KVM_HPAGE_GFN_SHIFT(PT_PAGE_TABLE_LEVEL) must be 0. */
+	return (gfn >> KVM_HPAGE_GFN_SHIFT(level)) -
+		(base_gfn >> KVM_HPAGE_GFN_SHIFT(level));
+}
+
 static inline unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot,
 					       gfn_t gfn)
 {
@@ -701,12 +736,16 @@
 	if (unlikely(vcpu->kvm->mmu_notifier_count))
 		return 1;
 	/*
-	 * Both reads happen under the mmu_lock and both values are
-	 * modified under mmu_lock, so there's no need of smb_rmb()
-	 * here in between, otherwise mmu_notifier_count should be
-	 * read before mmu_notifier_seq, see
-	 * mmu_notifier_invalidate_range_end write side.
+	 * Ensure the read of mmu_notifier_count happens before the read
+	 * of mmu_notifier_seq.  This interacts with the smp_wmb() in
+	 * mmu_notifier_invalidate_range_end to make sure that the caller
+	 * either sees the old (non-zero) value of mmu_notifier_count or
+	 * the new (incremented) value of mmu_notifier_seq.
+	 * PowerPC Book3s HV KVM calls this under a per-page lock
+	 * rather than under kvm->mmu_lock, for scalability, so
+	 * can't rely on kvm->mmu_lock to keep things ordered.
 	 */
+	smp_rmb();
 	if (vcpu->kvm->mmu_notifier_seq != mmu_seq)
 		return 1;
 	return 0;
@@ -769,6 +808,13 @@
 {
 	return vcpu->kvm->bsp_vcpu_id == vcpu->vcpu_id;
 }
+
+bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu);
+
+#else
+
+static inline bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu) { return true; }
+
 #endif
 
 #ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
diff --git a/include/linux/led-lm3530.h b/include/linux/led-lm3530.h
index 8eb12357..eeae6e7 100644
--- a/include/linux/led-lm3530.h
+++ b/include/linux/led-lm3530.h
@@ -72,6 +72,12 @@
 	LM3530_INPUT_CEIL,	/* Max of ALS1 and ALS2 */
 };
 
+/* PWM Platform Specific Data */
+struct lm3530_pwm_data {
+	void (*pwm_set_intensity) (int brightness, int max_brightness);
+	int (*pwm_get_intensity) (int max_brightness);
+};
+
 /**
  * struct lm3530_platform_data
  * @mode: mode of operation i.e. Manual, ALS or PWM
@@ -87,6 +93,7 @@
  * @als_vmin: als input voltage calibrated for max brightness in mV
  * @als_vmax: als input voltage calibrated for min brightness in mV
  * @brt_val: brightness value (0-255)
+ * @pwm_data: PWM control functions (only valid when the mode is PWM)
  */
 struct lm3530_platform_data {
 	enum lm3530_mode mode;
@@ -107,6 +114,8 @@
 	u32 als_vmax;
 
 	u8 brt_val;
+
+	struct lm3530_pwm_data pwm_data;
 };
 
 #endif	/* _LINUX_LED_LM3530_H__ */
diff --git a/include/linux/leds-lp5521.h b/include/linux/leds-lp5521.h
index fd548d2..3f071ec 100644
--- a/include/linux/leds-lp5521.h
+++ b/include/linux/leds-lp5521.h
@@ -26,15 +26,37 @@
 /* See Documentation/leds/leds-lp5521.txt */
 
 struct lp5521_led_config {
+	char		*name;
 	u8		chan_nr;
 	u8		led_current; /* mA x10, 0 if led is not connected */
 	u8		max_current;
 };
 
+struct lp5521_led_pattern {
+	u8 *r;
+	u8 *g;
+	u8 *b;
+	u8 size_r;
+	u8 size_g;
+	u8 size_b;
+};
+
 #define LP5521_CLOCK_AUTO	0
 #define LP5521_CLOCK_INT	1
 #define LP5521_CLOCK_EXT	2
 
+/* Bits in CONFIG register */
+#define LP5521_PWM_HF			0x40	/* PWM: 0 = 256Hz, 1 = 558Hz */
+#define LP5521_PWRSAVE_EN		0x20	/* 1 = Power save mode */
+#define LP5521_CP_MODE_OFF		0	/* Charge pump (CP) off */
+#define LP5521_CP_MODE_BYPASS		8	/* CP forced to bypass mode */
+#define LP5521_CP_MODE_1X5		0x10	/* CP forced to 1.5x mode */
+#define LP5521_CP_MODE_AUTO		0x18	/* Automatic mode selection */
+#define LP5521_R_TO_BATT		4	/* R out: 0 = CP, 1 = Vbat */
+#define LP5521_CLK_SRC_EXT		0	/* Ext-clk source (CLK_32K) */
+#define LP5521_CLK_INT			1	/* Internal clock */
+#define LP5521_CLK_AUTO			2	/* Automatic clock selection */
+
 struct lp5521_platform_data {
 	struct lp5521_led_config *led_config;
 	u8	num_channels;
@@ -43,6 +65,9 @@
 	void	(*release_resources)(void);
 	void	(*enable)(bool state);
 	const char *label;
+	u8	update_config;
+	struct lp5521_led_pattern *patterns;
+	int num_patterns;
 };
 
 #endif /* __LINUX_LP5521_H */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index cafc09a..42378d6 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -996,6 +996,7 @@
 extern void ata_sas_port_destroy(struct ata_port *);
 extern struct ata_port *ata_sas_port_alloc(struct ata_host *,
 					   struct ata_port_info *, struct Scsi_Host *);
+extern int ata_sas_async_port_init(struct ata_port *);
 extern int ata_sas_port_init(struct ata_port *);
 extern int ata_sas_port_start(struct ata_port *ap);
 extern void ata_sas_port_stop(struct ata_port *ap);
@@ -1147,6 +1148,7 @@
  * EH - drivers/ata/libata-eh.c
  */
 extern void ata_port_schedule_eh(struct ata_port *ap);
+extern void ata_port_wait_eh(struct ata_port *ap);
 extern int ata_link_abort(struct ata_link *link);
 extern int ata_port_abort(struct ata_port *ap);
 extern int ata_port_freeze(struct ata_port *ap);
diff --git a/include/linux/llist.h b/include/linux/llist.h
index 801b44b..a5199f6 100644
--- a/include/linux/llist.h
+++ b/include/linux/llist.h
@@ -56,8 +56,7 @@
  */
 
 #include <linux/kernel.h>
-#include <asm/system.h>
-#include <asm/processor.h>
+#include <asm/cmpxchg.h>
 
 struct llist_head {
 	struct llist_node *first;
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index fbc48f8..11a966e 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -42,6 +42,7 @@
 	unsigned short		protocol;
 	u32			nfs_version;
 	int			noresvport;
+	struct net		*net;
 };
 
 /*
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 88a114f..f04ce6a 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -67,6 +67,7 @@
 	struct list_head	h_reclaim;	/* Locks in RECLAIM state */
 	struct nsm_handle	*h_nsmhandle;	/* NSM status handle */
 	char			*h_addrbuf;	/* address eyecatcher */
+	struct net		*net;		/* host net */
 };
 
 /*
@@ -188,7 +189,7 @@
 /*
  * Global variables
  */
-extern struct rpc_program	nlm_program;
+extern const struct rpc_program	nlm_program;
 extern struct svc_procedure	nlmsvc_procedures[];
 #ifdef CONFIG_LOCKD_V4
 extern struct svc_procedure	nlmsvc_procedures4[];
@@ -222,7 +223,8 @@
 					const unsigned short protocol,
 					const u32 version,
 					const char *hostname,
-					int noresvport);
+					int noresvport,
+					struct net *net);
 void		  nlmclnt_release_host(struct nlm_host *);
 struct nlm_host  *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
 					const char *hostname,
@@ -232,6 +234,7 @@
 void		  nlm_rebind_host(struct nlm_host *);
 struct nlm_host * nlm_get_host(struct nlm_host *);
 void		  nlm_shutdown_hosts(void);
+void		  nlm_shutdown_hosts_net(struct net *net);
 void		  nlm_host_rebooted(const struct nlm_reboot *);
 
 /*
diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h
index 7353821..e58c88b 100644
--- a/include/linux/lockd/xdr4.h
+++ b/include/linux/lockd/xdr4.h
@@ -42,6 +42,6 @@
 int	nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *);
 int	nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
  */
-extern struct rpc_version nlm_version4;
+extern const struct rpc_version nlm_version4;
 
 #endif /* LOCKD_XDR4_H */
diff --git a/include/linux/lp855x.h b/include/linux/lp855x.h
new file mode 100644
index 0000000..781a490
--- /dev/null
+++ b/include/linux/lp855x.h
@@ -0,0 +1,131 @@
+/*
+ * LP855x Backlight Driver
+ *
+ *			Copyright (C) 2011 Texas Instruments
+ *
+ * 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 _LP855X_H
+#define _LP855X_H
+
+#define BL_CTL_SHFT	(0)
+#define BRT_MODE_SHFT	(1)
+#define BRT_MODE_MASK	(0x06)
+
+/* Enable backlight. Only valid when BRT_MODE=10(I2C only) */
+#define ENABLE_BL	(1)
+#define DISABLE_BL	(0)
+
+#define I2C_CONFIG(id)	id ## _I2C_CONFIG
+#define PWM_CONFIG(id)	id ## _PWM_CONFIG
+
+/* DEVICE CONTROL register - LP8550 */
+#define LP8550_PWM_CONFIG	(LP8550_PWM_ONLY << BRT_MODE_SHFT)
+#define LP8550_I2C_CONFIG	((ENABLE_BL << BL_CTL_SHFT) | \
+				(LP8550_I2C_ONLY << BRT_MODE_SHFT))
+
+/* DEVICE CONTROL register - LP8551 */
+#define LP8551_PWM_CONFIG	LP8550_PWM_CONFIG
+#define LP8551_I2C_CONFIG	LP8550_I2C_CONFIG
+
+/* DEVICE CONTROL register - LP8552 */
+#define LP8552_PWM_CONFIG	LP8550_PWM_CONFIG
+#define LP8552_I2C_CONFIG	LP8550_I2C_CONFIG
+
+/* DEVICE CONTROL register - LP8553 */
+#define LP8553_PWM_CONFIG	LP8550_PWM_CONFIG
+#define LP8553_I2C_CONFIG	LP8550_I2C_CONFIG
+
+/* DEVICE CONTROL register - LP8556 */
+#define LP8556_PWM_CONFIG	(LP8556_PWM_ONLY << BRT_MODE_SHFT)
+#define LP8556_COMB1_CONFIG	(LP8556_COMBINED1 << BRT_MODE_SHFT)
+#define LP8556_I2C_CONFIG	((ENABLE_BL << BL_CTL_SHFT) | \
+				(LP8556_I2C_ONLY << BRT_MODE_SHFT))
+#define LP8556_COMB2_CONFIG	(LP8556_COMBINED2 << BRT_MODE_SHFT)
+
+/* ROM area boundary */
+#define EEPROM_START	(0xA0)
+#define EEPROM_END	(0xA7)
+#define EPROM_START	(0xA0)
+#define EPROM_END	(0xAF)
+
+enum lp855x_chip_id {
+	LP8550,
+	LP8551,
+	LP8552,
+	LP8553,
+	LP8556,
+};
+
+enum lp855x_brightness_ctrl_mode {
+	PWM_BASED = 1,
+	REGISTER_BASED,
+};
+
+enum lp8550_brighntess_source {
+	LP8550_PWM_ONLY,
+	LP8550_I2C_ONLY = 2,
+};
+
+enum lp8551_brighntess_source {
+	LP8551_PWM_ONLY = LP8550_PWM_ONLY,
+	LP8551_I2C_ONLY = LP8550_I2C_ONLY,
+};
+
+enum lp8552_brighntess_source {
+	LP8552_PWM_ONLY = LP8550_PWM_ONLY,
+	LP8552_I2C_ONLY = LP8550_I2C_ONLY,
+};
+
+enum lp8553_brighntess_source {
+	LP8553_PWM_ONLY = LP8550_PWM_ONLY,
+	LP8553_I2C_ONLY = LP8550_I2C_ONLY,
+};
+
+enum lp8556_brightness_source {
+	LP8556_PWM_ONLY,
+	LP8556_COMBINED1,	/* pwm + i2c before the shaper block */
+	LP8556_I2C_ONLY,
+	LP8556_COMBINED2,	/* pwm + i2c after the shaper block */
+};
+
+struct lp855x_pwm_data {
+	void (*pwm_set_intensity) (int brightness, int max_brightness);
+	int (*pwm_get_intensity) (int max_brightness);
+};
+
+struct lp855x_rom_data {
+	u8 addr;
+	u8 val;
+};
+
+/**
+ * struct lp855x_platform_data
+ * @name : Backlight driver name. If it is not defined, default name is set.
+ * @mode : brightness control by pwm or lp855x register
+ * @device_control : value of DEVICE CONTROL register
+ * @initial_brightness : initial value of backlight brightness
+ * @pwm_data : platform specific pwm generation functions.
+		Only valid when mode is PWM_BASED.
+ * @load_new_rom_data :
+	0 : use default configuration data
+	1 : update values of eeprom or eprom registers on loading driver
+ * @size_program : total size of lp855x_rom_data
+ * @rom_data : list of new eeprom/eprom registers
+ */
+struct lp855x_platform_data {
+	char *name;
+	enum lp855x_brightness_ctrl_mode mode;
+	u8 device_control;
+	int initial_brightness;
+	struct lp855x_pwm_data pwm_data;
+	u8 load_new_rom_data;
+	int size_program;
+	struct lp855x_rom_data *rom_data;
+};
+
+#endif
diff --git a/include/linux/lp8727.h b/include/linux/lp8727.h
index d21fa28..ea98c61 100644
--- a/include/linux/lp8727.h
+++ b/include/linux/lp8727.h
@@ -1,4 +1,7 @@
 /*
+ * LP8727 Micro/Mini USB IC with integrated charger
+ *
+ *			Copyright (C) 2011 Texas Instruments
  *			Copyright (C) 2011 National Semiconductor
  *
  * This program is free software; you can redistribute it and/or modify
@@ -32,13 +35,24 @@
 	ICHG_1000mA,
 };
 
+/**
+ * struct lp8727_chg_param
+ * @eoc_level : end of charge level setting
+ * @ichg : charging current
+ */
 struct lp8727_chg_param {
-	/* end of charge level setting */
 	enum lp8727_eoc_level eoc_level;
-	/* charging current */
 	enum lp8727_ichg ichg;
 };
 
+/**
+ * struct lp8727_platform_data
+ * @get_batt_present : check battery status - exists or not
+ * @get_batt_level : get battery voltage (mV)
+ * @get_batt_capacity : get battery capacity (%)
+ * @get_batt_temp : get battery temperature
+ * @ac, @usb : charging parameters each charger type
+ */
 struct lp8727_platform_data {
 	u8 (*get_batt_present)(void);
 	u16 (*get_batt_level)(void);
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h
index 88e78de..fad48aa 100644
--- a/include/linux/lsm_audit.h
+++ b/include/linux/lsm_audit.h
@@ -21,8 +21,24 @@
 #include <linux/path.h>
 #include <linux/key.h>
 #include <linux/skbuff.h>
-#include <asm/system.h>
 
+struct lsm_network_audit {
+	int netif;
+	struct sock *sk;
+	u16 family;
+	__be16 dport;
+	__be16 sport;
+	union {
+		struct {
+			__be32 daddr;
+			__be32 saddr;
+		} v4;
+		struct {
+			struct in6_addr daddr;
+			struct in6_addr saddr;
+		} v6;
+	} fam;
+};
 
 /* Auxiliary data to use in generating the audit record. */
 struct common_audit_data {
@@ -42,23 +58,7 @@
 		struct path path;
 		struct dentry *dentry;
 		struct inode *inode;
-		struct {
-			int netif;
-			struct sock *sk;
-			u16 family;
-			__be16 dport;
-			__be16 sport;
-			union {
-				struct {
-					__be32 daddr;
-					__be32 saddr;
-				} v4;
-				struct {
-					struct in6_addr daddr;
-					struct in6_addr saddr;
-				} v6;
-			} fam;
-		} net;
+		struct lsm_network_audit *net;
 		int cap;
 		int ipc_id;
 		struct task_struct *tsk;
@@ -73,64 +73,15 @@
 	/* this union contains LSM specific data */
 	union {
 #ifdef CONFIG_SECURITY_SMACK
-		/* SMACK data */
-		struct smack_audit_data {
-			const char *function;
-			char *subject;
-			char *object;
-			char *request;
-			int result;
-		} smack_audit_data;
+		struct smack_audit_data *smack_audit_data;
 #endif
 #ifdef CONFIG_SECURITY_SELINUX
-		/* SELinux data */
-		struct {
-			u32 ssid;
-			u32 tsid;
-			u16 tclass;
-			u32 requested;
-			u32 audited;
-			u32 denied;
-			/*
-			 * auditdeny is a bit tricky and unintuitive.  See the
-			 * comments in avc.c for it's meaning and usage.
-			 */
-			u32 auditdeny;
-			struct av_decision *avd;
-			int result;
-		} selinux_audit_data;
+		struct selinux_audit_data *selinux_audit_data;
 #endif
 #ifdef CONFIG_SECURITY_APPARMOR
-		struct {
-			int error;
-			int op;
-			int type;
-			void *profile;
-			const char *name;
-			const char *info;
-			union {
-				void *target;
-				struct {
-					long pos;
-					void *target;
-				} iface;
-				struct {
-					int rlim;
-					unsigned long max;
-				} rlim;
-				struct {
-					const char *target;
-					u32 request;
-					u32 denied;
-					uid_t ouid;
-				} fs;
-			};
-		} apparmor_audit_data;
+		struct apparmor_audit_data *apparmor_audit_data;
 #endif
-	};
-	/* these callback will be implemented by a specific LSM */
-	void (*lsm_pre_audit)(struct audit_buffer *, void *);
-	void (*lsm_post_audit)(struct audit_buffer *, void *);
+	}; /* per LSM data pointer union */
 };
 
 #define v4info fam.v4
@@ -147,6 +98,8 @@
 	{ memset((_d), 0, sizeof(struct common_audit_data)); \
 	 (_d)->type = LSM_AUDIT_DATA_##_t; }
 
-void common_lsm_audit(struct common_audit_data *a);
+void common_lsm_audit(struct common_audit_data *a,
+	void (*pre_audit)(struct audit_buffer *, void *),
+	void (*post_audit)(struct audit_buffer *, void *));
 
 #endif
diff --git a/include/linux/magic.h b/include/linux/magic.h
index 2d4beab..e15192c 100644
--- a/include/linux/magic.h
+++ b/include/linux/magic.h
@@ -9,7 +9,6 @@
 #define CRAMFS_MAGIC		0x28cd3d45	/* some random number */
 #define CRAMFS_MAGIC_WEND	0x453dcd28	/* magic number with the wrong endianess */
 #define DEBUGFS_MAGIC          0x64626720
-#define SYSFS_MAGIC		0x62656572
 #define SECURITYFS_MAGIC	0x73636673
 #define SELINUX_MAGIC		0xf97cff8c
 #define RAMFS_MAGIC		0x858458f6	/* some random number */
@@ -27,7 +26,6 @@
 #define HPFS_SUPER_MAGIC	0xf995e849
 #define ISOFS_SUPER_MAGIC	0x9660
 #define JFFS2_SUPER_MAGIC	0x72b6
-#define ANON_INODE_FS_MAGIC	0x09041934
 #define PSTOREFS_MAGIC		0x6165676C
 
 #define MINIX_SUPER_MAGIC	0x137F		/* minix v1 fs, 14 char names */
@@ -40,8 +38,8 @@
 #define NCP_SUPER_MAGIC		0x564c		/* Guess, what 0x564c is :-) */
 #define NFS_SUPER_MAGIC		0x6969
 #define OPENPROM_SUPER_MAGIC	0x9fa1
-#define PROC_SUPER_MAGIC	0x9fa0
 #define QNX4_SUPER_MAGIC	0x002f		/* qnx4 fs detection */
+#define QNX6_SUPER_MAGIC	0x68191122	/* qnx6 fs detection */
 
 #define REISERFS_SUPER_MAGIC	0x52654973	/* used by gcc */
 					/* used by file system utilities that
@@ -51,15 +49,24 @@
 #define REISER2FS_JR_SUPER_MAGIC_STRING	"ReIsEr3Fs"
 
 #define SMB_SUPER_MAGIC		0x517B
-#define USBDEVICE_SUPER_MAGIC	0x9fa2
 #define CGROUP_SUPER_MAGIC	0x27e0eb
 
-#define FUTEXFS_SUPER_MAGIC	0xBAD1DEA
 
 #define STACK_END_MAGIC		0x57AC6E9D
 
-#define DEVPTS_SUPER_MAGIC	0x1cd1
-#define SOCKFS_MAGIC		0x534F434B
 #define V9FS_MAGIC		0x01021997
 
+#define BDEVFS_MAGIC            0x62646576
+#define BINFMTFS_MAGIC          0x42494e4d
+#define DEVPTS_SUPER_MAGIC	0x1cd1
+#define FUTEXFS_SUPER_MAGIC	0xBAD1DEA
+#define PIPEFS_MAGIC            0x50495045
+#define PROC_SUPER_MAGIC	0x9fa0
+#define SOCKFS_MAGIC		0x534F434B
+#define SYSFS_MAGIC		0x62656572
+#define USBDEVICE_SUPER_MAGIC	0x9fa2
+#define MTD_INODE_FS_MAGIC      0x11307854
+#define ANON_INODE_FS_MAGIC	0x09041934
+
+
 #endif /* __LINUX_MAGIC_H__ */
diff --git a/include/linux/maple.h b/include/linux/maple.h
index d9a51b9..c37288b 100644
--- a/include/linux/maple.h
+++ b/include/linux/maple.h
@@ -1,9 +1,9 @@
 #ifndef __LINUX_MAPLE_H
 #define __LINUX_MAPLE_H
 
-#include <linux/device.h>
 #include <mach/maple.h>
 
+struct device;
 extern struct bus_type maple_bus_type;
 
 /* Maple Bus command and response codes */
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index b80de52..f94efd2 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -77,7 +77,8 @@
 extern void mem_cgroup_uncharge_page(struct page *page);
 extern void mem_cgroup_uncharge_cache_page(struct page *page);
 
-extern void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask);
+extern void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
+				     int order);
 int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *memcg);
 
 extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page);
@@ -140,6 +141,34 @@
 	return false;
 }
 
+void __mem_cgroup_begin_update_page_stat(struct page *page, bool *locked,
+					 unsigned long *flags);
+
+extern atomic_t memcg_moving;
+
+static inline void mem_cgroup_begin_update_page_stat(struct page *page,
+					bool *locked, unsigned long *flags)
+{
+	if (mem_cgroup_disabled())
+		return;
+	rcu_read_lock();
+	*locked = false;
+	if (atomic_read(&memcg_moving))
+		__mem_cgroup_begin_update_page_stat(page, locked, flags);
+}
+
+void __mem_cgroup_end_update_page_stat(struct page *page,
+				unsigned long *flags);
+static inline void mem_cgroup_end_update_page_stat(struct page *page,
+					bool *locked, unsigned long *flags)
+{
+	if (mem_cgroup_disabled())
+		return;
+	if (*locked)
+		__mem_cgroup_end_update_page_stat(page, flags);
+	rcu_read_unlock();
+}
+
 void mem_cgroup_update_page_stat(struct page *page,
 				 enum mem_cgroup_page_stat_item idx,
 				 int val);
@@ -298,21 +327,6 @@
 {
 }
 
-static inline int mem_cgroup_get_reclaim_priority(struct mem_cgroup *memcg)
-{
-	return 0;
-}
-
-static inline void mem_cgroup_note_reclaim_priority(struct mem_cgroup *memcg,
-						int priority)
-{
-}
-
-static inline void mem_cgroup_record_reclaim_priority(struct mem_cgroup *memcg,
-						int priority)
-{
-}
-
 static inline bool mem_cgroup_disabled(void)
 {
 	return true;
@@ -355,6 +369,16 @@
 {
 }
 
+static inline void mem_cgroup_begin_update_page_stat(struct page *page,
+					bool *locked, unsigned long *flags)
+{
+}
+
+static inline void mem_cgroup_end_update_page_stat(struct page *page,
+					bool *locked, unsigned long *flags)
+{
+}
+
 static inline void mem_cgroup_inc_page_stat(struct page *page,
 					    enum mem_cgroup_page_stat_item idx)
 {
@@ -391,7 +415,7 @@
 				struct page *newpage)
 {
 }
-#endif /* CONFIG_CGROUP_MEM_CONT */
+#endif /* CONFIG_CGROUP_MEM_RES_CTLR */
 
 #if !defined(CONFIG_CGROUP_MEM_RES_CTLR) || !defined(CONFIG_DEBUG_VM)
 static inline bool
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index 0b8e2a7..910550f 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -4,6 +4,7 @@
 #include <linux/mmzone.h>
 #include <linux/spinlock.h>
 #include <linux/notifier.h>
+#include <linux/bug.h>
 
 struct page;
 struct zone;
diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h
index 92be3476..84d071a 100644
--- a/include/linux/mfd/88pm860x.h
+++ b/include/linux/mfd/88pm860x.h
@@ -263,6 +263,22 @@
 #define PM8607_PD_PREBIAS_MASK		(0x1F << 0)
 #define PM8607_PD_PRECHG_MASK		(7 << 5)
 
+#define PM8606_REF_GP_OSC_OFF         0
+#define PM8606_REF_GP_OSC_ON          1
+#define PM8606_REF_GP_OSC_UNKNOWN     2
+
+/* Clients of reference group and 8MHz oscillator in 88PM8606 */
+enum pm8606_ref_gp_and_osc_clients {
+	REF_GP_NO_CLIENTS       = 0,
+	WLED1_DUTY              = (1<<0), /*PF 0x02.7:0*/
+	WLED2_DUTY              = (1<<1), /*PF 0x04.7:0*/
+	WLED3_DUTY              = (1<<2), /*PF 0x06.7:0*/
+	RGB1_ENABLE             = (1<<3), /*PF 0x07.1*/
+	RGB2_ENABLE             = (1<<4), /*PF 0x07.2*/
+	LDO_VBR_EN              = (1<<5), /*PF 0x12.0*/
+	REF_GP_MAX_CLIENT       = 0xFFFF
+};
+
 /* Interrupt Number in 88PM8607 */
 enum {
 	PM8607_IRQ_ONKEY,
@@ -298,6 +314,7 @@
 struct pm860x_chip {
 	struct device		*dev;
 	struct mutex		irq_lock;
+	struct mutex		osc_lock;
 	struct i2c_client	*client;
 	struct i2c_client	*companion;	/* companion chip client */
 	struct regmap           *regmap;
@@ -305,12 +322,15 @@
 
 	int			buck3_double;	/* DVC ramp slope double */
 	unsigned short		companion_addr;
+	unsigned short		osc_vote;
 	int			id;
 	int			irq_mode;
 	int			irq_base;
 	int			core_irq;
 	unsigned char		chip_version;
+	unsigned char		osc_status;
 
+	unsigned int            wakeup_flag;
 };
 
 enum {
@@ -369,6 +389,9 @@
 	int		num_regulators;
 };
 
+extern int pm8606_osc_enable(struct pm860x_chip *, unsigned short);
+extern int pm8606_osc_disable(struct pm860x_chip *, unsigned short);
+
 extern int pm860x_reg_read(struct i2c_client *, int);
 extern int pm860x_reg_write(struct i2c_client *, int, unsigned char);
 extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *);
diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
index 9970337..ee96cd5 100644
--- a/include/linux/mfd/abx500.h
+++ b/include/linux/mfd/abx500.h
@@ -14,9 +14,10 @@
  * Author: Rickard Andersson <rickard.andersson@stericsson.com>
  */
 
-#include <linux/device.h>
 #include <linux/regulator/machine.h>
 
+struct device;
+
 #ifndef MFD_ABX500_H
 #define MFD_ABX500_H
 
@@ -33,13 +34,6 @@
 #define AB5500_1_1	0x21
 #define AB5500_2_0	0x24
 
-/* AB8500 CIDs*/
-#define AB8500_CUT1P0	0x10
-#define AB8500_CUT1P1	0x11
-#define AB8500_CUT2P0	0x20
-#define AB8500_CUT3P0	0x30
-#define AB8500_CUT3P3	0x33
-
 /*
  * AB3100, EVENTA1, A2 and A3 event register flags
  * these are catenated into a single 32-bit flag in the code
@@ -152,6 +146,279 @@
 	u8 setting;
 };
 
+/* Battery driver related data */
+/*
+ * ADC for the battery thermistor.
+ * When using the ABx500_ADC_THERM_BATCTRL the battery ID resistor is combined
+ * with a NTC resistor to both identify the battery and to measure its
+ * temperature. Different phone manufactures uses different techniques to both
+ * identify the battery and to read its temperature.
+ */
+enum abx500_adc_therm {
+	ABx500_ADC_THERM_BATCTRL,
+	ABx500_ADC_THERM_BATTEMP,
+};
+
+/**
+ * struct abx500_res_to_temp - defines one point in a temp to res curve. To
+ * be used in battery packs that combines the identification resistor with a
+ * NTC resistor.
+ * @temp:			battery pack temperature in Celcius
+ * @resist:			NTC resistor net total resistance
+ */
+struct abx500_res_to_temp {
+	int temp;
+	int resist;
+};
+
+/**
+ * struct abx500_v_to_cap - Table for translating voltage to capacity
+ * @voltage:		Voltage in mV
+ * @capacity:		Capacity in percent
+ */
+struct abx500_v_to_cap {
+	int voltage;
+	int capacity;
+};
+
+/* Forward declaration */
+struct abx500_fg;
+
+/**
+ * struct abx500_fg_parameters - Fuel gauge algorithm parameters, in seconds
+ * if not specified
+ * @recovery_sleep_timer:	Time between measurements while recovering
+ * @recovery_total_time:	Total recovery time
+ * @init_timer:			Measurement interval during startup
+ * @init_discard_time:		Time we discard voltage measurement at startup
+ * @init_total_time:		Total init time during startup
+ * @high_curr_time:		Time current has to be high to go to recovery
+ * @accu_charging:		FG accumulation time while charging
+ * @accu_high_curr:		FG accumulation time in high current mode
+ * @high_curr_threshold:	High current threshold, in mA
+ * @lowbat_threshold:		Low battery threshold, in mV
+ * @overbat_threshold:		Over battery threshold, in mV
+ * @battok_falling_th_sel0	Threshold in mV for battOk signal sel0
+ *				Resolution in 50 mV step.
+ * @battok_raising_th_sel1	Threshold in mV for battOk signal sel1
+ *				Resolution in 50 mV step.
+ * @user_cap_limit		Capacity reported from user must be within this
+ *				limit to be considered as sane, in percentage
+ *				points.
+ * @maint_thres			This is the threshold where we stop reporting
+ *				battery full while in maintenance, in per cent
+ */
+struct abx500_fg_parameters {
+	int recovery_sleep_timer;
+	int recovery_total_time;
+	int init_timer;
+	int init_discard_time;
+	int init_total_time;
+	int high_curr_time;
+	int accu_charging;
+	int accu_high_curr;
+	int high_curr_threshold;
+	int lowbat_threshold;
+	int overbat_threshold;
+	int battok_falling_th_sel0;
+	int battok_raising_th_sel1;
+	int user_cap_limit;
+	int maint_thres;
+};
+
+/**
+ * struct abx500_charger_maximization - struct used by the board config.
+ * @use_maxi:		Enable maximization for this battery type
+ * @maxi_chg_curr:	Maximum charger current allowed
+ * @maxi_wait_cycles:	cycles to wait before setting charger current
+ * @charger_curr_step	delta between two charger current settings (mA)
+ */
+struct abx500_maxim_parameters {
+	bool ena_maxi;
+	int chg_curr;
+	int wait_cycles;
+	int charger_curr_step;
+};
+
+/**
+ * struct abx500_battery_type - different batteries supported
+ * @name:			battery technology
+ * @resis_high:			battery upper resistance limit
+ * @resis_low:			battery lower resistance limit
+ * @charge_full_design:		Maximum battery capacity in mAh
+ * @nominal_voltage:		Nominal voltage of the battery in mV
+ * @termination_vol:		max voltage upto which battery can be charged
+ * @termination_curr		battery charging termination current in mA
+ * @recharge_vol		battery voltage limit that will trigger a new
+ *				full charging cycle in the case where maintenan-
+ *				-ce charging has been disabled
+ * @normal_cur_lvl:		charger current in normal state in mA
+ * @normal_vol_lvl:		charger voltage in normal state in mV
+ * @maint_a_cur_lvl:		charger current in maintenance A state in mA
+ * @maint_a_vol_lvl:		charger voltage in maintenance A state in mV
+ * @maint_a_chg_timer_h:	charge time in maintenance A state
+ * @maint_b_cur_lvl:		charger current in maintenance B state in mA
+ * @maint_b_vol_lvl:		charger voltage in maintenance B state in mV
+ * @maint_b_chg_timer_h:	charge time in maintenance B state
+ * @low_high_cur_lvl:		charger current in temp low/high state in mA
+ * @low_high_vol_lvl:		charger voltage in temp low/high state in mV'
+ * @battery_resistance:		battery inner resistance in mOhm.
+ * @n_r_t_tbl_elements:		number of elements in r_to_t_tbl
+ * @r_to_t_tbl:			table containing resistance to temp points
+ * @n_v_cap_tbl_elements:	number of elements in v_to_cap_tbl
+ * @v_to_cap_tbl:		Voltage to capacity (in %) table
+ * @n_batres_tbl_elements	number of elements in the batres_tbl
+ * @batres_tbl			battery internal resistance vs temperature table
+ */
+struct abx500_battery_type {
+	int name;
+	int resis_high;
+	int resis_low;
+	int charge_full_design;
+	int nominal_voltage;
+	int termination_vol;
+	int termination_curr;
+	int recharge_vol;
+	int normal_cur_lvl;
+	int normal_vol_lvl;
+	int maint_a_cur_lvl;
+	int maint_a_vol_lvl;
+	int maint_a_chg_timer_h;
+	int maint_b_cur_lvl;
+	int maint_b_vol_lvl;
+	int maint_b_chg_timer_h;
+	int low_high_cur_lvl;
+	int low_high_vol_lvl;
+	int battery_resistance;
+	int n_temp_tbl_elements;
+	struct abx500_res_to_temp *r_to_t_tbl;
+	int n_v_cap_tbl_elements;
+	struct abx500_v_to_cap *v_to_cap_tbl;
+	int n_batres_tbl_elements;
+	struct batres_vs_temp *batres_tbl;
+};
+
+/**
+ * struct abx500_bm_capacity_levels - abx500 capacity level data
+ * @critical:		critical capacity level in percent
+ * @low:		low capacity level in percent
+ * @normal:		normal capacity level in percent
+ * @high:		high capacity level in percent
+ * @full:		full capacity level in percent
+ */
+struct abx500_bm_capacity_levels {
+	int critical;
+	int low;
+	int normal;
+	int high;
+	int full;
+};
+
+/**
+ * struct abx500_bm_charger_parameters - Charger specific parameters
+ * @usb_volt_max:	maximum allowed USB charger voltage in mV
+ * @usb_curr_max:	maximum allowed USB charger current in mA
+ * @ac_volt_max:	maximum allowed AC charger voltage in mV
+ * @ac_curr_max:	maximum allowed AC charger current in mA
+ */
+struct abx500_bm_charger_parameters {
+	int usb_volt_max;
+	int usb_curr_max;
+	int ac_volt_max;
+	int ac_curr_max;
+};
+
+/**
+ * struct abx500_bm_data - abx500 battery management data
+ * @temp_under		under this temp, charging is stopped
+ * @temp_low		between this temp and temp_under charging is reduced
+ * @temp_high		between this temp and temp_over charging is reduced
+ * @temp_over		over this temp, charging is stopped
+ * @temp_now		present battery temperature
+ * @temp_interval_chg	temperature measurement interval in s when charging
+ * @temp_interval_nochg	temperature measurement interval in s when not charging
+ * @main_safety_tmr_h	safety timer for main charger
+ * @usb_safety_tmr_h	safety timer for usb charger
+ * @bkup_bat_v		voltage which we charge the backup battery with
+ * @bkup_bat_i		current which we charge the backup battery with
+ * @no_maintenance	indicates that maintenance charging is disabled
+ * @abx500_adc_therm	placement of thermistor, batctrl or battemp adc
+ * @chg_unknown_bat	flag to enable charging of unknown batteries
+ * @enable_overshoot	flag to enable VBAT overshoot control
+ * @auto_trig		flag to enable auto adc trigger
+ * @fg_res		resistance of FG resistor in 0.1mOhm
+ * @n_btypes		number of elements in array bat_type
+ * @batt_id		index of the identified battery in array bat_type
+ * @interval_charging	charge alg cycle period time when charging (sec)
+ * @interval_not_charging charge alg cycle period time when not charging (sec)
+ * @temp_hysteresis	temperature hysteresis
+ * @gnd_lift_resistance	Battery ground to phone ground resistance (mOhm)
+ * @maxi:		maximization parameters
+ * @cap_levels		capacity in percent for the different capacity levels
+ * @bat_type		table of supported battery types
+ * @chg_params		charger parameters
+ * @fg_params		fuel gauge parameters
+ */
+struct abx500_bm_data {
+	int temp_under;
+	int temp_low;
+	int temp_high;
+	int temp_over;
+	int temp_now;
+	int temp_interval_chg;
+	int temp_interval_nochg;
+	int main_safety_tmr_h;
+	int usb_safety_tmr_h;
+	int bkup_bat_v;
+	int bkup_bat_i;
+	bool no_maintenance;
+	bool chg_unknown_bat;
+	bool enable_overshoot;
+	bool auto_trig;
+	enum abx500_adc_therm adc_therm;
+	int fg_res;
+	int n_btypes;
+	int batt_id;
+	int interval_charging;
+	int interval_not_charging;
+	int temp_hysteresis;
+	int gnd_lift_resistance;
+	const struct abx500_maxim_parameters *maxi;
+	const struct abx500_bm_capacity_levels *cap_levels;
+	const struct abx500_battery_type *bat_type;
+	const struct abx500_bm_charger_parameters *chg_params;
+	const struct abx500_fg_parameters *fg_params;
+};
+
+struct abx500_chargalg_platform_data {
+	char **supplied_to;
+	size_t num_supplicants;
+};
+
+struct abx500_charger_platform_data {
+	char **supplied_to;
+	size_t num_supplicants;
+	bool autopower_cfg;
+};
+
+struct abx500_btemp_platform_data {
+	char **supplied_to;
+	size_t num_supplicants;
+};
+
+struct abx500_fg_platform_data {
+	char **supplied_to;
+	size_t num_supplicants;
+};
+
+struct abx500_bm_plat_data {
+	struct abx500_bm_data *battery;
+	struct abx500_charger_platform_data *charger;
+	struct abx500_btemp_platform_data *btemp;
+	struct abx500_fg_platform_data *fg;
+	struct abx500_chargalg_platform_data *chargalg;
+};
+
 int abx500_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
 	u8 value);
 int abx500_get_register_interruptible(struct device *dev, u8 bank, u8 reg,
diff --git a/include/linux/mfd/abx500/ab5500.h b/include/linux/mfd/abx500/ab5500.h
index a720051..54f820e 100644
--- a/include/linux/mfd/abx500/ab5500.h
+++ b/include/linux/mfd/abx500/ab5500.h
@@ -6,7 +6,7 @@
 #ifndef MFD_AB5500_H
 #define MFD_AB5500_H
 
-#include <linux/device.h>
+struct device;
 
 enum ab5500_devid {
 	AB5500_DEVID_ADC,
diff --git a/include/linux/mfd/abx500/ab8500-bm.h b/include/linux/mfd/abx500/ab8500-bm.h
new file mode 100644
index 0000000..44310c9
--- /dev/null
+++ b/include/linux/mfd/abx500/ab8500-bm.h
@@ -0,0 +1,474 @@
+/*
+ * Copyright ST-Ericsson 2012.
+ *
+ * Author: Arun Murthy <arun.murthy@stericsson.com>
+ * Licensed under GPLv2.
+ */
+
+#ifndef _AB8500_BM_H
+#define _AB8500_BM_H
+
+#include <linux/kernel.h>
+#include <linux/mfd/abx500.h>
+
+/*
+ * System control 2 register offsets.
+ * bank = 0x02
+ */
+#define AB8500_MAIN_WDOG_CTRL_REG	0x01
+#define AB8500_LOW_BAT_REG		0x03
+#define AB8500_BATT_OK_REG		0x04
+/*
+ * USB/ULPI register offsets
+ * Bank : 0x5
+ */
+#define AB8500_USB_LINE_STAT_REG	0x80
+
+/*
+ * Charger / status register offfsets
+ * Bank : 0x0B
+ */
+#define AB8500_CH_STATUS1_REG		0x00
+#define AB8500_CH_STATUS2_REG		0x01
+#define AB8500_CH_USBCH_STAT1_REG	0x02
+#define AB8500_CH_USBCH_STAT2_REG	0x03
+#define AB8500_CH_FSM_STAT_REG		0x04
+#define AB8500_CH_STAT_REG		0x05
+
+/*
+ * Charger / control register offfsets
+ * Bank : 0x0B
+ */
+#define AB8500_CH_VOLT_LVL_REG		0x40
+#define AB8500_CH_VOLT_LVL_MAX_REG	0x41  /*Only in Cut2.0*/
+#define AB8500_CH_OPT_CRNTLVL_REG	0x42
+#define AB8500_CH_OPT_CRNTLVL_MAX_REG	0x43  /*Only in Cut2.0*/
+#define AB8500_CH_WD_TIMER_REG		0x50
+#define AB8500_CHARG_WD_CTRL		0x51
+#define AB8500_BTEMP_HIGH_TH		0x52
+#define AB8500_LED_INDICATOR_PWM_CTRL	0x53
+#define AB8500_LED_INDICATOR_PWM_DUTY	0x54
+#define AB8500_BATT_OVV			0x55
+#define AB8500_CHARGER_CTRL		0x56
+#define AB8500_BAT_CTRL_CURRENT_SOURCE	0x60  /*Only in Cut2.0*/
+
+/*
+ * Charger / main control register offsets
+ * Bank : 0x0B
+ */
+#define AB8500_MCH_CTRL1		0x80
+#define AB8500_MCH_CTRL2		0x81
+#define AB8500_MCH_IPT_CURLVL_REG	0x82
+#define AB8500_CH_WD_REG		0x83
+
+/*
+ * Charger / USB control register offsets
+ * Bank : 0x0B
+ */
+#define AB8500_USBCH_CTRL1_REG		0xC0
+#define AB8500_USBCH_CTRL2_REG		0xC1
+#define AB8500_USBCH_IPT_CRNTLVL_REG	0xC2
+
+/*
+ * Gas Gauge register offsets
+ * Bank : 0x0C
+ */
+#define AB8500_GASG_CC_CTRL_REG		0x00
+#define AB8500_GASG_CC_ACCU1_REG	0x01
+#define AB8500_GASG_CC_ACCU2_REG	0x02
+#define AB8500_GASG_CC_ACCU3_REG	0x03
+#define AB8500_GASG_CC_ACCU4_REG	0x04
+#define AB8500_GASG_CC_SMPL_CNTRL_REG	0x05
+#define AB8500_GASG_CC_SMPL_CNTRH_REG	0x06
+#define AB8500_GASG_CC_SMPL_CNVL_REG	0x07
+#define AB8500_GASG_CC_SMPL_CNVH_REG	0x08
+#define AB8500_GASG_CC_CNTR_AVGOFF_REG	0x09
+#define AB8500_GASG_CC_OFFSET_REG	0x0A
+#define AB8500_GASG_CC_NCOV_ACCU	0x10
+#define AB8500_GASG_CC_NCOV_ACCU_CTRL	0x11
+#define AB8500_GASG_CC_NCOV_ACCU_LOW	0x12
+#define AB8500_GASG_CC_NCOV_ACCU_MED	0x13
+#define AB8500_GASG_CC_NCOV_ACCU_HIGH	0x14
+
+/*
+ * Interrupt register offsets
+ * Bank : 0x0E
+ */
+#define AB8500_IT_SOURCE2_REG		0x01
+#define AB8500_IT_SOURCE21_REG		0x14
+
+/*
+ * RTC register offsets
+ * Bank: 0x0F
+ */
+#define AB8500_RTC_BACKUP_CHG_REG	0x0C
+#define AB8500_RTC_CC_CONF_REG		0x01
+#define AB8500_RTC_CTRL_REG		0x0B
+
+/*
+ * OTP register offsets
+ * Bank : 0x15
+ */
+#define AB8500_OTP_CONF_15		0x0E
+
+/* GPADC constants from AB8500 spec, UM0836 */
+#define ADC_RESOLUTION			1024
+#define ADC_CH_MAIN_MIN			0
+#define ADC_CH_MAIN_MAX			20030
+#define ADC_CH_VBUS_MIN			0
+#define ADC_CH_VBUS_MAX			20030
+#define ADC_CH_VBAT_MIN			2300
+#define ADC_CH_VBAT_MAX			4800
+#define ADC_CH_BKBAT_MIN		0
+#define ADC_CH_BKBAT_MAX		3200
+
+/* Main charge i/p current */
+#define MAIN_CH_IP_CUR_0P9A		0x80
+#define MAIN_CH_IP_CUR_1P0A		0x90
+#define MAIN_CH_IP_CUR_1P1A		0xA0
+#define MAIN_CH_IP_CUR_1P2A		0xB0
+#define MAIN_CH_IP_CUR_1P3A		0xC0
+#define MAIN_CH_IP_CUR_1P4A		0xD0
+#define MAIN_CH_IP_CUR_1P5A		0xE0
+
+/* ChVoltLevel */
+#define CH_VOL_LVL_3P5			0x00
+#define CH_VOL_LVL_4P0			0x14
+#define CH_VOL_LVL_4P05			0x16
+#define CH_VOL_LVL_4P1			0x1B
+#define CH_VOL_LVL_4P15			0x20
+#define CH_VOL_LVL_4P2			0x25
+#define CH_VOL_LVL_4P6			0x4D
+
+/* ChOutputCurrentLevel */
+#define CH_OP_CUR_LVL_0P1		0x00
+#define CH_OP_CUR_LVL_0P2		0x01
+#define CH_OP_CUR_LVL_0P3		0x02
+#define CH_OP_CUR_LVL_0P4		0x03
+#define CH_OP_CUR_LVL_0P5		0x04
+#define CH_OP_CUR_LVL_0P6		0x05
+#define CH_OP_CUR_LVL_0P7		0x06
+#define CH_OP_CUR_LVL_0P8		0x07
+#define CH_OP_CUR_LVL_0P9		0x08
+#define CH_OP_CUR_LVL_1P4		0x0D
+#define CH_OP_CUR_LVL_1P5		0x0E
+#define CH_OP_CUR_LVL_1P6		0x0F
+
+/* BTEMP High thermal limits */
+#define BTEMP_HIGH_TH_57_0		0x00
+#define BTEMP_HIGH_TH_52		0x01
+#define BTEMP_HIGH_TH_57_1		0x02
+#define BTEMP_HIGH_TH_62		0x03
+
+/* current is mA */
+#define USB_0P1A			100
+#define USB_0P2A			200
+#define USB_0P3A			300
+#define USB_0P4A			400
+#define USB_0P5A			500
+
+#define LOW_BAT_3P1V			0x20
+#define LOW_BAT_2P3V			0x00
+#define LOW_BAT_RESET			0x01
+#define LOW_BAT_ENABLE			0x01
+
+/* Backup battery constants */
+#define BUP_ICH_SEL_50UA		0x00
+#define BUP_ICH_SEL_150UA		0x04
+#define BUP_ICH_SEL_300UA		0x08
+#define BUP_ICH_SEL_700UA		0x0C
+
+#define BUP_VCH_SEL_2P5V		0x00
+#define BUP_VCH_SEL_2P6V		0x01
+#define BUP_VCH_SEL_2P8V		0x02
+#define BUP_VCH_SEL_3P1V		0x03
+
+/* Battery OVV constants */
+#define BATT_OVV_ENA			0x02
+#define BATT_OVV_TH_3P7			0x00
+#define BATT_OVV_TH_4P75		0x01
+
+/* A value to indicate over voltage */
+#define BATT_OVV_VALUE			4750
+
+/* VBUS OVV constants */
+#define VBUS_OVV_SELECT_MASK		0x78
+#define VBUS_OVV_SELECT_5P6V		0x00
+#define VBUS_OVV_SELECT_5P7V		0x08
+#define VBUS_OVV_SELECT_5P8V		0x10
+#define VBUS_OVV_SELECT_5P9V		0x18
+#define VBUS_OVV_SELECT_6P0V		0x20
+#define VBUS_OVV_SELECT_6P1V		0x28
+#define VBUS_OVV_SELECT_6P2V		0x30
+#define VBUS_OVV_SELECT_6P3V		0x38
+
+#define VBUS_AUTO_IN_CURR_LIM_ENA	0x04
+
+/* Fuel Gauge constants */
+#define RESET_ACCU			0x02
+#define READ_REQ			0x01
+#define CC_DEEP_SLEEP_ENA		0x02
+#define CC_PWR_UP_ENA			0x01
+#define CC_SAMPLES_40			0x28
+#define RD_NCONV_ACCU_REQ		0x01
+#define CC_CALIB			0x08
+#define CC_INTAVGOFFSET_ENA		0x10
+#define CC_MUXOFFSET			0x80
+#define CC_INT_CAL_N_AVG_MASK		0x60
+#define CC_INT_CAL_SAMPLES_16		0x40
+#define CC_INT_CAL_SAMPLES_8		0x20
+#define CC_INT_CAL_SAMPLES_4		0x00
+
+/* RTC constants */
+#define RTC_BUP_CH_ENA			0x10
+
+/* BatCtrl Current Source Constants */
+#define BAT_CTRL_7U_ENA			0x01
+#define BAT_CTRL_20U_ENA		0x02
+#define BAT_CTRL_CMP_ENA		0x04
+#define FORCE_BAT_CTRL_CMP_HIGH		0x08
+#define BAT_CTRL_PULL_UP_ENA		0x10
+
+/* Battery type */
+#define BATTERY_UNKNOWN			00
+
+/**
+ * struct res_to_temp - defines one point in a temp to res curve. To
+ * be used in battery packs that combines the identification resistor with a
+ * NTC resistor.
+ * @temp:			battery pack temperature in Celcius
+ * @resist:			NTC resistor net total resistance
+ */
+struct res_to_temp {
+	int temp;
+	int resist;
+};
+
+/**
+ * struct batres_vs_temp - defines one point in a temp vs battery internal
+ * resistance curve.
+ * @temp:			battery pack temperature in Celcius
+ * @resist:			battery internal reistance in mOhm
+ */
+struct batres_vs_temp {
+	int temp;
+	int resist;
+};
+
+/* Forward declaration */
+struct ab8500_fg;
+
+/**
+ * struct ab8500_fg_parameters - Fuel gauge algorithm parameters, in seconds
+ * if not specified
+ * @recovery_sleep_timer:	Time between measurements while recovering
+ * @recovery_total_time:	Total recovery time
+ * @init_timer:			Measurement interval during startup
+ * @init_discard_time:		Time we discard voltage measurement at startup
+ * @init_total_time:		Total init time during startup
+ * @high_curr_time:		Time current has to be high to go to recovery
+ * @accu_charging:		FG accumulation time while charging
+ * @accu_high_curr:		FG accumulation time in high current mode
+ * @high_curr_threshold:	High current threshold, in mA
+ * @lowbat_threshold:		Low battery threshold, in mV
+ * @battok_falling_th_sel0	Threshold in mV for battOk signal sel0
+ *				Resolution in 50 mV step.
+ * @battok_raising_th_sel1	Threshold in mV for battOk signal sel1
+ *				Resolution in 50 mV step.
+ * @user_cap_limit		Capacity reported from user must be within this
+ *				limit to be considered as sane, in percentage
+ *				points.
+ * @maint_thres			This is the threshold where we stop reporting
+ *				battery full while in maintenance, in per cent
+ */
+struct ab8500_fg_parameters {
+	int recovery_sleep_timer;
+	int recovery_total_time;
+	int init_timer;
+	int init_discard_time;
+	int init_total_time;
+	int high_curr_time;
+	int accu_charging;
+	int accu_high_curr;
+	int high_curr_threshold;
+	int lowbat_threshold;
+	int battok_falling_th_sel0;
+	int battok_raising_th_sel1;
+	int user_cap_limit;
+	int maint_thres;
+};
+
+/**
+ * struct ab8500_charger_maximization - struct used by the board config.
+ * @use_maxi:		Enable maximization for this battery type
+ * @maxi_chg_curr:	Maximum charger current allowed
+ * @maxi_wait_cycles:	cycles to wait before setting charger current
+ * @charger_curr_step	delta between two charger current settings (mA)
+ */
+struct ab8500_maxim_parameters {
+	bool ena_maxi;
+	int chg_curr;
+	int wait_cycles;
+	int charger_curr_step;
+};
+
+/**
+ * struct ab8500_bm_capacity_levels - ab8500 capacity level data
+ * @critical:		critical capacity level in percent
+ * @low:		low capacity level in percent
+ * @normal:		normal capacity level in percent
+ * @high:		high capacity level in percent
+ * @full:		full capacity level in percent
+ */
+struct ab8500_bm_capacity_levels {
+	int critical;
+	int low;
+	int normal;
+	int high;
+	int full;
+};
+
+/**
+ * struct ab8500_bm_charger_parameters - Charger specific parameters
+ * @usb_volt_max:	maximum allowed USB charger voltage in mV
+ * @usb_curr_max:	maximum allowed USB charger current in mA
+ * @ac_volt_max:	maximum allowed AC charger voltage in mV
+ * @ac_curr_max:	maximum allowed AC charger current in mA
+ */
+struct ab8500_bm_charger_parameters {
+	int usb_volt_max;
+	int usb_curr_max;
+	int ac_volt_max;
+	int ac_curr_max;
+};
+
+/**
+ * struct ab8500_bm_data - ab8500 battery management data
+ * @temp_under		under this temp, charging is stopped
+ * @temp_low		between this temp and temp_under charging is reduced
+ * @temp_high		between this temp and temp_over charging is reduced
+ * @temp_over		over this temp, charging is stopped
+ * @temp_interval_chg	temperature measurement interval in s when charging
+ * @temp_interval_nochg	temperature measurement interval in s when not charging
+ * @main_safety_tmr_h	safety timer for main charger
+ * @usb_safety_tmr_h	safety timer for usb charger
+ * @bkup_bat_v		voltage which we charge the backup battery with
+ * @bkup_bat_i		current which we charge the backup battery with
+ * @no_maintenance	indicates that maintenance charging is disabled
+ * @adc_therm		placement of thermistor, batctrl or battemp adc
+ * @chg_unknown_bat	flag to enable charging of unknown batteries
+ * @enable_overshoot	flag to enable VBAT overshoot control
+ * @fg_res		resistance of FG resistor in 0.1mOhm
+ * @n_btypes		number of elements in array bat_type
+ * @batt_id		index of the identified battery in array bat_type
+ * @interval_charging	charge alg cycle period time when charging (sec)
+ * @interval_not_charging charge alg cycle period time when not charging (sec)
+ * @temp_hysteresis	temperature hysteresis
+ * @gnd_lift_resistance	Battery ground to phone ground resistance (mOhm)
+ * @maxi:		maximization parameters
+ * @cap_levels		capacity in percent for the different capacity levels
+ * @bat_type		table of supported battery types
+ * @chg_params		charger parameters
+ * @fg_params		fuel gauge parameters
+ */
+struct ab8500_bm_data {
+	int temp_under;
+	int temp_low;
+	int temp_high;
+	int temp_over;
+	int temp_interval_chg;
+	int temp_interval_nochg;
+	int main_safety_tmr_h;
+	int usb_safety_tmr_h;
+	int bkup_bat_v;
+	int bkup_bat_i;
+	bool no_maintenance;
+	bool chg_unknown_bat;
+	bool enable_overshoot;
+	enum abx500_adc_therm adc_therm;
+	int fg_res;
+	int n_btypes;
+	int batt_id;
+	int interval_charging;
+	int interval_not_charging;
+	int temp_hysteresis;
+	int gnd_lift_resistance;
+	const struct ab8500_maxim_parameters *maxi;
+	const struct ab8500_bm_capacity_levels *cap_levels;
+	const struct ab8500_bm_charger_parameters *chg_params;
+	const struct ab8500_fg_parameters *fg_params;
+};
+
+struct ab8500_charger_platform_data {
+	char **supplied_to;
+	size_t num_supplicants;
+	bool autopower_cfg;
+};
+
+struct ab8500_btemp_platform_data {
+	char **supplied_to;
+	size_t num_supplicants;
+};
+
+struct ab8500_fg_platform_data {
+	char **supplied_to;
+	size_t num_supplicants;
+};
+
+struct ab8500_chargalg_platform_data {
+	char **supplied_to;
+	size_t num_supplicants;
+};
+struct ab8500_btemp;
+struct ab8500_gpadc;
+struct ab8500_fg;
+#ifdef CONFIG_AB8500_BM
+void ab8500_fg_reinit(void);
+void ab8500_charger_usb_state_changed(u8 bm_usb_state, u16 mA);
+struct ab8500_btemp *ab8500_btemp_get(void);
+int ab8500_btemp_get_batctrl_temp(struct ab8500_btemp *btemp);
+struct ab8500_fg *ab8500_fg_get(void);
+int ab8500_fg_inst_curr_blocking(struct ab8500_fg *dev);
+int ab8500_fg_inst_curr_start(struct ab8500_fg *di);
+int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res);
+int ab8500_fg_inst_curr_done(struct ab8500_fg *di);
+
+#else
+int ab8500_fg_inst_curr_done(struct ab8500_fg *di)
+{
+}
+static void ab8500_fg_reinit(void)
+{
+}
+static void ab8500_charger_usb_state_changed(u8 bm_usb_state, u16 mA)
+{
+}
+static struct ab8500_btemp *ab8500_btemp_get(void)
+{
+	return NULL;
+}
+static int ab8500_btemp_get_batctrl_temp(struct ab8500_btemp *btemp)
+{
+	return 0;
+}
+struct ab8500_fg *ab8500_fg_get(void)
+{
+	return NULL;
+}
+static int ab8500_fg_inst_curr_blocking(struct ab8500_fg *dev)
+{
+	return -ENODEV;
+}
+
+static inline int ab8500_fg_inst_curr_start(struct ab8500_fg *di)
+{
+	return -ENODEV;
+}
+
+static inline int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res)
+{
+	return -ENODEV;
+}
+
+#endif
+#endif /* _AB8500_BM_H */
diff --git a/include/linux/mfd/abx500/ab8500-gpio.h b/include/linux/mfd/abx500/ab8500-gpio.h
index 488a8c9..2387c20 100644
--- a/include/linux/mfd/abx500/ab8500-gpio.h
+++ b/include/linux/mfd/abx500/ab8500-gpio.h
@@ -10,12 +10,14 @@
 
 /*
  * Platform data to register a block: only the initial gpio/irq number.
+ * Array sizes are large enough to contain all AB8500 and AB9540 GPIO
+ * registers.
  */
 
 struct ab8500_gpio_platform_data {
 	int gpio_base;
 	u32 irq_base;
-	u8  config_reg[7];
+	u8  config_reg[8];
 };
 
 #endif /* _AB8500_GPIO_H */
diff --git a/include/linux/mfd/abx500/ab8500-sysctrl.h b/include/linux/mfd/abx500/ab8500-sysctrl.h
index 10da029..10eb509 100644
--- a/include/linux/mfd/abx500/ab8500-sysctrl.h
+++ b/include/linux/mfd/abx500/ab8500-sysctrl.h
@@ -71,6 +71,13 @@
 #define AB8500_SWATCTRL			0x230
 #define AB8500_HIQCLKCTRL		0x232
 #define AB8500_VSIMSYSCLKCTRL		0x233
+#define AB9540_SYSCLK12BUFCTRL		0x234
+#define AB9540_SYSCLK12CONFCTRL		0x235
+#define AB9540_SYSCLK12BUFCTRL2		0x236
+#define AB9540_SYSCLK12BUF1VALID	0x237
+#define AB9540_SYSCLK12BUF2VALID	0x238
+#define AB9540_SYSCLK12BUF3VALID	0x239
+#define AB9540_SYSCLK12BUF4VALID	0x23A
 
 /* Bits */
 #define AB8500_TURNONSTATUS_PORNVBAT BIT(0)
@@ -251,4 +258,40 @@
 #define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ7VALID BIT(6)
 #define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ8VALID BIT(7)
 
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF1ENA BIT(0)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF2ENA BIT(1)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF3ENA BIT(2)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF4ENA BIT(3)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUFENA_MASK 0x0F
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF1STRE BIT(4)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF2STRE BIT(5)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF3STRE BIT(6)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF4STRE BIT(7)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUFSTRE_MASK 0xF0
+
+#define AB9540_SYSCLK12CONFCTRL_PLL26TO38ENA BIT(0)
+#define AB9540_SYSCLK12CONFCTRL_SYSCLK12USBMUXSEL BIT(1)
+#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL_MASK 0x0C
+#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL_SHIFT 2
+#define AB9540_SYSCLK12CONFCTRL_SYSCLK12BUFMUX BIT(4)
+#define AB9540_SYSCLK12CONFCTRL_SYSCLK12PLLMUX BIT(5)
+#define AB9540_SYSCLK12CONFCTRL_SYSCLK2MUXVALID BIT(6)
+
+#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF1PDENA BIT(0)
+#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF2PDENA BIT(1)
+#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF3PDENA BIT(2)
+#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF4PDENA BIT(3)
+
+#define AB9540_SYSCLK12BUF1VALID_SYSCLK12BUF1VALID_MASK 0xFF
+#define AB9540_SYSCLK12BUF1VALID_SYSCLK12BUF1VALID_SHIFT 0
+
+#define AB9540_SYSCLK12BUF2VALID_SYSCLK12BUF2VALID_MASK 0xFF
+#define AB9540_SYSCLK12BUF2VALID_SYSCLK12BUF2VALID_SHIFT 0
+
+#define AB9540_SYSCLK12BUF3VALID_SYSCLK12BUF3VALID_MASK 0xFF
+#define AB9540_SYSCLK12BUF3VALID_SYSCLK12BUF3VALID_SHIFT 0
+
+#define AB9540_SYSCLK12BUF4VALID_SYSCLK12BUF4VALID_MASK 0xFF
+#define AB9540_SYSCLK12BUF4VALID_SYSCLK12BUF4VALID_SHIFT 0
+
 #endif /* __AB8500_SYSCTRL_H */
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index 838c6b4..fccc300 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -7,7 +7,32 @@
 #ifndef MFD_AB8500_H
 #define MFD_AB8500_H
 
-#include <linux/device.h>
+#include <linux/mutex.h>
+
+struct device;
+
+/*
+ * AB IC versions
+ *
+ * AB8500_VERSION_AB8500 should be 0xFF but will never be read as need a
+ * non-supported multi-byte I2C access via PRCMU. Set to 0x00 to ease the
+ * print of version string.
+ */
+enum ab8500_version {
+	AB8500_VERSION_AB8500 = 0x0,
+	AB8500_VERSION_AB8505 = 0x1,
+	AB8500_VERSION_AB9540 = 0x2,
+	AB8500_VERSION_AB8540 = 0x3,
+	AB8500_VERSION_UNDEFINED,
+};
+
+/* AB8500 CIDs*/
+#define AB8500_CUTEARLY	0x00
+#define AB8500_CUT1P0	0x10
+#define AB8500_CUT1P1	0x11
+#define AB8500_CUT2P0	0x20
+#define AB8500_CUT3P0	0x30
+#define AB8500_CUT3P3	0x33
 
 /*
  * AB8500 bank addresses
@@ -35,30 +60,34 @@
 
 /*
  * Interrupts
+ * Values used to index into array ab8500_irq_regoffset[] defined in
+ * drivers/mdf/ab8500-core.c
  */
-
-#define AB8500_INT_MAIN_EXT_CH_NOT_OK	0
-#define AB8500_INT_UN_PLUG_TV_DET	1
-#define AB8500_INT_PLUG_TV_DET		2
+/* Definitions for AB8500 and AB9540 */
+/* ab8500_irq_regoffset[0] -> IT[Source|Latch|Mask]1 */
+#define AB8500_INT_MAIN_EXT_CH_NOT_OK	0 /* not 8505/9540 */
+#define AB8500_INT_UN_PLUG_TV_DET	1 /* not 8505/9540 */
+#define AB8500_INT_PLUG_TV_DET		2 /* not 8505/9540 */
 #define AB8500_INT_TEMP_WARM		3
 #define AB8500_INT_PON_KEY2DB_F		4
 #define AB8500_INT_PON_KEY2DB_R		5
 #define AB8500_INT_PON_KEY1DB_F		6
 #define AB8500_INT_PON_KEY1DB_R		7
+/* ab8500_irq_regoffset[1] -> IT[Source|Latch|Mask]2 */
 #define AB8500_INT_BATT_OVV		8
-#define AB8500_INT_MAIN_CH_UNPLUG_DET	10
-#define AB8500_INT_MAIN_CH_PLUG_DET	11
-#define AB8500_INT_USB_ID_DET_F		12
-#define AB8500_INT_USB_ID_DET_R		13
+#define AB8500_INT_MAIN_CH_UNPLUG_DET	10 /* not 8505 */
+#define AB8500_INT_MAIN_CH_PLUG_DET	11 /* not 8505 */
 #define AB8500_INT_VBUS_DET_F		14
 #define AB8500_INT_VBUS_DET_R		15
+/* ab8500_irq_regoffset[2] -> IT[Source|Latch|Mask]3 */
 #define AB8500_INT_VBUS_CH_DROP_END	16
 #define AB8500_INT_RTC_60S		17
 #define AB8500_INT_RTC_ALARM		18
 #define AB8500_INT_BAT_CTRL_INDB	20
 #define AB8500_INT_CH_WD_EXP		21
 #define AB8500_INT_VBUS_OVV		22
-#define AB8500_INT_MAIN_CH_DROP_END	23
+#define AB8500_INT_MAIN_CH_DROP_END	23 /* not 8505/9540 */
+/* ab8500_irq_regoffset[3] -> IT[Source|Latch|Mask]4 */
 #define AB8500_INT_CCN_CONV_ACC		24
 #define AB8500_INT_INT_AUD		25
 #define AB8500_INT_CCEOC		26
@@ -67,7 +96,8 @@
 #define AB8500_INT_LOW_BAT_R		29
 #define AB8500_INT_BUP_CHG_NOT_OK	30
 #define AB8500_INT_BUP_CHG_OK		31
-#define AB8500_INT_GP_HW_ADC_CONV_END	32
+/* ab8500_irq_regoffset[4] -> IT[Source|Latch|Mask]5 */
+#define AB8500_INT_GP_HW_ADC_CONV_END	32 /* not 8505 */
 #define AB8500_INT_ACC_DETECT_1DB_F	33
 #define AB8500_INT_ACC_DETECT_1DB_R	34
 #define AB8500_INT_ACC_DETECT_22DB_F	35
@@ -75,38 +105,43 @@
 #define AB8500_INT_ACC_DETECT_21DB_F	37
 #define AB8500_INT_ACC_DETECT_21DB_R	38
 #define AB8500_INT_GP_SW_ADC_CONV_END	39
-#define AB8500_INT_GPIO6R		40
-#define AB8500_INT_GPIO7R		41
-#define AB8500_INT_GPIO8R		42
-#define AB8500_INT_GPIO9R		43
+/* ab8500_irq_regoffset[5] -> IT[Source|Latch|Mask]7 */
+#define AB8500_INT_GPIO6R		40 /* not 8505/9540 */
+#define AB8500_INT_GPIO7R		41 /* not 8505/9540 */
+#define AB8500_INT_GPIO8R		42 /* not 8505/9540 */
+#define AB8500_INT_GPIO9R		43 /* not 8505/9540 */
 #define AB8500_INT_GPIO10R		44
 #define AB8500_INT_GPIO11R		45
-#define AB8500_INT_GPIO12R		46
+#define AB8500_INT_GPIO12R		46 /* not 8505 */
 #define AB8500_INT_GPIO13R		47
-#define AB8500_INT_GPIO24R		48
-#define AB8500_INT_GPIO25R		49
-#define AB8500_INT_GPIO36R		50
-#define AB8500_INT_GPIO37R		51
-#define AB8500_INT_GPIO38R		52
-#define AB8500_INT_GPIO39R		53
+/* ab8500_irq_regoffset[6] -> IT[Source|Latch|Mask]8 */
+#define AB8500_INT_GPIO24R		48 /* not 8505 */
+#define AB8500_INT_GPIO25R		49 /* not 8505 */
+#define AB8500_INT_GPIO36R		50 /* not 8505/9540 */
+#define AB8500_INT_GPIO37R		51 /* not 8505/9540 */
+#define AB8500_INT_GPIO38R		52 /* not 8505/9540 */
+#define AB8500_INT_GPIO39R		53 /* not 8505/9540 */
 #define AB8500_INT_GPIO40R		54
 #define AB8500_INT_GPIO41R		55
-#define AB8500_INT_GPIO6F		56
-#define AB8500_INT_GPIO7F		57
-#define AB8500_INT_GPIO8F		58
-#define AB8500_INT_GPIO9F		59
+/* ab8500_irq_regoffset[7] -> IT[Source|Latch|Mask]9 */
+#define AB8500_INT_GPIO6F		56 /* not 8505/9540 */
+#define AB8500_INT_GPIO7F		57 /* not 8505/9540 */
+#define AB8500_INT_GPIO8F		58 /* not 8505/9540 */
+#define AB8500_INT_GPIO9F		59 /* not 8505/9540 */
 #define AB8500_INT_GPIO10F		60
 #define AB8500_INT_GPIO11F		61
-#define AB8500_INT_GPIO12F		62
+#define AB8500_INT_GPIO12F		62 /* not 8505 */
 #define AB8500_INT_GPIO13F		63
-#define AB8500_INT_GPIO24F		64
-#define AB8500_INT_GPIO25F		65
-#define AB8500_INT_GPIO36F		66
-#define AB8500_INT_GPIO37F		67
-#define AB8500_INT_GPIO38F		68
-#define AB8500_INT_GPIO39F		69
+/* ab8500_irq_regoffset[8] -> IT[Source|Latch|Mask]10 */
+#define AB8500_INT_GPIO24F		64 /* not 8505 */
+#define AB8500_INT_GPIO25F		65 /* not 8505 */
+#define AB8500_INT_GPIO36F		66 /* not 8505/9540 */
+#define AB8500_INT_GPIO37F		67 /* not 8505/9540 */
+#define AB8500_INT_GPIO38F		68 /* not 8505/9540 */
+#define AB8500_INT_GPIO39F		69 /* not 8505/9540 */
 #define AB8500_INT_GPIO40F		70
 #define AB8500_INT_GPIO41F		71
+/* ab8500_irq_regoffset[9] -> IT[Source|Latch|Mask]12 */
 #define AB8500_INT_ADP_SOURCE_ERROR	72
 #define AB8500_INT_ADP_SINK_ERROR	73
 #define AB8500_INT_ADP_PROBE_PLUG	74
@@ -114,30 +149,67 @@
 #define AB8500_INT_ADP_SENSE_OFF	76
 #define AB8500_INT_USB_PHY_POWER_ERR	78
 #define AB8500_INT_USB_LINK_STATUS	79
+/* ab8500_irq_regoffset[10] -> IT[Source|Latch|Mask]19 */
 #define AB8500_INT_BTEMP_LOW		80
 #define AB8500_INT_BTEMP_LOW_MEDIUM	81
 #define AB8500_INT_BTEMP_MEDIUM_HIGH	82
 #define AB8500_INT_BTEMP_HIGH		83
-#define AB8500_INT_USB_CHARGER_NOT_OK	89
+/* ab8500_irq_regoffset[11] -> IT[Source|Latch|Mask]20 */
+#define AB8500_INT_SRP_DETECT		88
+#define AB8500_INT_USB_CHARGER_NOT_OKR	89
 #define AB8500_INT_ID_WAKEUP_R		90
 #define AB8500_INT_ID_DET_R1R		92
 #define AB8500_INT_ID_DET_R2R		93
 #define AB8500_INT_ID_DET_R3R		94
 #define AB8500_INT_ID_DET_R4R		95
+/* ab8500_irq_regoffset[12] -> IT[Source|Latch|Mask]21 */
 #define AB8500_INT_ID_WAKEUP_F		96
 #define AB8500_INT_ID_DET_R1F		98
 #define AB8500_INT_ID_DET_R2F		99
 #define AB8500_INT_ID_DET_R3F		100
 #define AB8500_INT_ID_DET_R4F		101
-#define AB8500_INT_USB_CHG_DET_DONE	102
+#define AB8500_INT_CHAUTORESTARTAFTSEC  102
+#define AB8500_INT_CHSTOPBYSEC		103
+/* ab8500_irq_regoffset[13] -> IT[Source|Latch|Mask]22 */
 #define AB8500_INT_USB_CH_TH_PROT_F	104
 #define AB8500_INT_USB_CH_TH_PROT_R    105
-#define AB8500_INT_MAIN_CH_TH_PROT_F   106
-#define AB8500_INT_MAIN_CH_TH_PROT_R	107
-#define AB8500_INT_USB_CHARGER_NOT_OKF	111
+#define AB8500_INT_MAIN_CH_TH_PROT_F	106 /* not 8505/9540 */
+#define AB8500_INT_MAIN_CH_TH_PROT_R	107 /* not 8505/9540 */
+#define AB8500_INT_CHCURLIMNOHSCHIRP	109
+#define AB8500_INT_CHCURLIMHSCHIRP	110
+#define AB8500_INT_XTAL32K_KO		111
 
+/* Definitions for AB9540 */
+/* ab8500_irq_regoffset[14] -> IT[Source|Latch|Mask]13 */
+#define AB9540_INT_GPIO50R		113
+#define AB9540_INT_GPIO51R		114 /* not 8505 */
+#define AB9540_INT_GPIO52R		115
+#define AB9540_INT_GPIO53R		116
+#define AB9540_INT_GPIO54R		117 /* not 8505 */
+#define AB9540_INT_IEXT_CH_RF_BFN_R	118
+#define AB9540_INT_IEXT_CH_RF_BFN_F	119
+/* ab8500_irq_regoffset[15] -> IT[Source|Latch|Mask]14 */
+#define AB9540_INT_GPIO50F		121
+#define AB9540_INT_GPIO51F		122 /* not 8505 */
+#define AB9540_INT_GPIO52F		123
+#define AB9540_INT_GPIO53F		124
+#define AB9540_INT_GPIO54F		125 /* not 8505 */
+
+/*
+ * AB8500_AB9540_NR_IRQS is used when configuring the IRQ numbers for the
+ * entire platform. This is a "compile time" constant so this must be set to
+ * the largest possible value that may be encountered with different AB SOCs.
+ * Of the currently supported AB devices, AB8500 and AB9540, it is the AB9540
+ * which is larger.
+ */
 #define AB8500_NR_IRQS			112
+#define AB8505_NR_IRQS			128
+#define AB9540_NR_IRQS			128
+/* This is set to the roof of any AB8500 chip variant IRQ counts */
+#define AB8500_MAX_NR_IRQS		AB9540_NR_IRQS
+
 #define AB8500_NUM_IRQ_REGS		14
+#define AB9540_NUM_IRQ_REGS		17
 
 /**
  * struct ab8500 - ab8500 internal structure
@@ -145,13 +217,18 @@
  * @lock: read/write operations lock
  * @irq_lock: genirq bus lock
  * @irq: irq line
+ * @version: chip version id (e.g. ab8500 or ab9540)
  * @chip_id: chip revision id
  * @write: register write
+ * @write_masked: masked register write
  * @read: register read
  * @rx_buf: rx buf for SPI
  * @tx_buf: tx buf for SPI
  * @mask: cache of IRQ regs for bus lock
  * @oldmask: cache of previous IRQ regs for bus lock
+ * @mask_size: Actual number of valid entries in mask[], oldmask[] and
+ * irq_reg_offset
+ * @irq_reg_offset: Array of offsets into IRQ registers
  */
 struct ab8500 {
 	struct device	*dev;
@@ -160,16 +237,20 @@
 
 	int		irq_base;
 	int		irq;
+	enum ab8500_version version;
 	u8		chip_id;
 
-	int (*write) (struct ab8500 *a8500, u16 addr, u8 data);
-	int (*read) (struct ab8500 *a8500, u16 addr);
+	int (*write)(struct ab8500 *ab8500, u16 addr, u8 data);
+	int (*write_masked)(struct ab8500 *ab8500, u16 addr, u8 mask, u8 data);
+	int (*read)(struct ab8500 *ab8500, u16 addr);
 
 	unsigned long	tx_buf[4];
 	unsigned long	rx_buf[4];
 
-	u8 mask[AB8500_NUM_IRQ_REGS];
-	u8 oldmask[AB8500_NUM_IRQ_REGS];
+	u8 *mask;
+	u8 *oldmask;
+	int mask_size;
+	const int *irq_reg_offset;
 };
 
 struct regulator_reg_init;
@@ -195,7 +276,52 @@
 	struct ab8500_gpio_platform_data *gpio;
 };
 
-extern int __devinit ab8500_init(struct ab8500 *ab8500);
+extern int __devinit ab8500_init(struct ab8500 *ab8500,
+				 enum ab8500_version version);
 extern int __devexit ab8500_exit(struct ab8500 *ab8500);
 
+static inline int is_ab8500(struct ab8500 *ab)
+{
+	return ab->version == AB8500_VERSION_AB8500;
+}
+
+static inline int is_ab8505(struct ab8500 *ab)
+{
+	return ab->version == AB8500_VERSION_AB8505;
+}
+
+static inline int is_ab9540(struct ab8500 *ab)
+{
+	return ab->version == AB8500_VERSION_AB9540;
+}
+
+static inline int is_ab8540(struct ab8500 *ab)
+{
+	return ab->version == AB8500_VERSION_AB8540;
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_1p0_or_earlier(struct ab8500 *ab)
+{
+	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P0));
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_1p1_or_earlier(struct ab8500 *ab)
+{
+	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P1));
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_2p0_or_earlier(struct ab8500 *ab)
+{
+	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT2P0));
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_2p0(struct ab8500 *ab)
+{
+	return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
+}
+
 #endif /* MFD_AB8500_H */
diff --git a/include/linux/mfd/abx500/ux500_chargalg.h b/include/linux/mfd/abx500/ux500_chargalg.h
new file mode 100644
index 0000000..9b07725
--- /dev/null
+++ b/include/linux/mfd/abx500/ux500_chargalg.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ * Author: Johan Gardsmark <johan.gardsmark@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef _UX500_CHARGALG_H
+#define _UX500_CHARGALG_H
+
+#include <linux/power_supply.h>
+
+#define psy_to_ux500_charger(x) container_of((x), \
+		struct ux500_charger, psy)
+
+/* Forward declaration */
+struct ux500_charger;
+
+struct ux500_charger_ops {
+	int (*enable) (struct ux500_charger *, int, int, int);
+	int (*kick_wd) (struct ux500_charger *);
+	int (*update_curr) (struct ux500_charger *, int);
+};
+
+/**
+ * struct ux500_charger - power supply ux500 charger sub class
+ * @psy			power supply base class
+ * @ops			ux500 charger operations
+ * @max_out_volt	maximum output charger voltage in mV
+ * @max_out_curr	maximum output charger current in mA
+ */
+struct ux500_charger {
+	struct power_supply psy;
+	struct ux500_charger_ops ops;
+	int max_out_volt;
+	int max_out_curr;
+};
+
+#endif
diff --git a/include/linux/mfd/anatop.h b/include/linux/mfd/anatop.h
new file mode 100644
index 0000000..22c1007
--- /dev/null
+++ b/include/linux/mfd/anatop.h
@@ -0,0 +1,40 @@
+/*
+ * anatop.h - Anatop MFD driver
+ *
+ *  Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *  Copyright (C) 2012 Linaro
+ *
+ * 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
+ */
+
+#ifndef __LINUX_MFD_ANATOP_H
+#define __LINUX_MFD_ANATOP_H
+
+#include <linux/spinlock.h>
+
+/**
+ * anatop - MFD data
+ * @ioreg: ioremap register
+ * @reglock: spinlock for register read/write
+ */
+struct anatop {
+	void *ioreg;
+	spinlock_t reglock;
+};
+
+extern u32 anatop_get_bits(struct anatop *, u32, int, int);
+extern void anatop_set_bits(struct anatop *, u32, int, int, u32);
+
+#endif /*  __LINUX_MFD_ANATOP_H */
diff --git a/include/linux/mfd/da9052/da9052.h b/include/linux/mfd/da9052/da9052.h
index 5702d1b..7ffbd6e 100644
--- a/include/linux/mfd/da9052/da9052.h
+++ b/include/linux/mfd/da9052/da9052.h
@@ -76,8 +76,6 @@
 struct da9052_pdata;
 
 struct da9052 {
-	struct mutex io_lock;
-
 	struct device *dev;
 	struct regmap *regmap;
 
diff --git a/include/linux/mfd/db8500-prcmu.h b/include/linux/mfd/db8500-prcmu.h
index 60d27f7..b3a43b1 100644
--- a/include/linux/mfd/db8500-prcmu.h
+++ b/include/linux/mfd/db8500-prcmu.h
@@ -11,6 +11,24 @@
 #define __MFD_DB8500_PRCMU_H
 
 #include <linux/interrupt.h>
+#include <linux/bitops.h>
+
+/*
+ * Registers
+ */
+#define DB8500_PRCM_GPIOCR 0x138
+#define DB8500_PRCM_GPIOCR_DBG_UARTMOD_CMD0	BIT(0)
+#define DB8500_PRCM_GPIOCR_DBG_STM_APE_CMD	BIT(9)
+#define DB8500_PRCM_GPIOCR_DBG_STM_MOD_CMD1	BIT(11)
+#define DB8500_PRCM_GPIOCR_SPI2_SELECT		BIT(23)
+
+#define DB8500_PRCM_LINE_VALUE 0x170
+#define DB8500_PRCM_LINE_VALUE_HSI_CAWAKE0	BIT(3)
+
+#define DB8500_PRCM_DSI_SW_RESET 0x324
+#define DB8500_PRCM_DSI_SW_RESET_DSI0_SW_RESETN BIT(0)
+#define DB8500_PRCM_DSI_SW_RESET_DSI1_SW_RESETN BIT(1)
+#define DB8500_PRCM_DSI_SW_RESET_DSI2_SW_RESETN BIT(2)
 
 /* This portion previously known as <mach/prcmu-fw-defs_v1.h> */
 
@@ -421,40 +439,22 @@
 /* End of file previously known as prcmu-fw-defs_v1.h */
 
 /**
- * enum hw_acc_dev - enum for hw accelerators
- * @HW_ACC_SVAMMDSP: for SVAMMDSP
- * @HW_ACC_SVAPIPE:  for SVAPIPE
- * @HW_ACC_SIAMMDSP: for SIAMMDSP
- * @HW_ACC_SIAPIPE: for SIAPIPE
- * @HW_ACC_SGA: for SGA
- * @HW_ACC_B2R2: for B2R2
- * @HW_ACC_MCDE: for MCDE
- * @HW_ACC_ESRAM1: for ESRAM1
- * @HW_ACC_ESRAM2: for ESRAM2
- * @HW_ACC_ESRAM3: for ESRAM3
- * @HW_ACC_ESRAM4: for ESRAM4
- * @NUM_HW_ACC: number of hardware accelerators
+ * enum prcmu_power_status - results from set_power_state
+ * @PRCMU_SLEEP_OK: Sleep went ok
+ * @PRCMU_DEEP_SLEEP_OK: DeepSleep went ok
+ * @PRCMU_IDLE_OK: Idle went ok
+ * @PRCMU_DEEPIDLE_OK: DeepIdle went ok
+ * @PRCMU_PRCMU2ARMPENDINGIT_ER: Pending interrupt detected
+ * @PRCMU_ARMPENDINGIT_ER: Pending interrupt detected
  *
- * Different hw accelerators which can be turned ON/
- * OFF or put into retention (MMDSPs and ESRAMs).
- * Used with EPOD API.
- *
- * NOTE! Deprecated, to be removed when all users switched over to use the
- * regulator API.
  */
-enum hw_acc_dev {
-	HW_ACC_SVAMMDSP,
-	HW_ACC_SVAPIPE,
-	HW_ACC_SIAMMDSP,
-	HW_ACC_SIAPIPE,
-	HW_ACC_SGA,
-	HW_ACC_B2R2,
-	HW_ACC_MCDE,
-	HW_ACC_ESRAM1,
-	HW_ACC_ESRAM2,
-	HW_ACC_ESRAM3,
-	HW_ACC_ESRAM4,
-	NUM_HW_ACC
+enum prcmu_power_status {
+	PRCMU_SLEEP_OK			= 0xf3,
+	PRCMU_DEEP_SLEEP_OK		= 0xf6,
+	PRCMU_IDLE_OK			= 0xf0,
+	PRCMU_DEEPIDLE_OK		= 0xe3,
+	PRCMU_PRCMU2ARMPENDINGIT_ER	= 0x91,
+	PRCMU_ARMPENDINGIT_ER		= 0x93,
 };
 
 /*
@@ -493,6 +493,20 @@
 	u8 sva_policy;
 };
 
+#define PRCMU_FW_PROJECT_U8500		2
+#define PRCMU_FW_PROJECT_U9500		4
+#define PRCMU_FW_PROJECT_U8500_C2	7
+#define PRCMU_FW_PROJECT_U9500_C2	11
+#define PRCMU_FW_PROJECT_U8520		13
+#define PRCMU_FW_PROJECT_U8420		14
+
+struct prcmu_fw_version {
+	u8 project;
+	u8 api_version;
+	u8 func_version;
+	u8 errata;
+};
+
 #ifdef CONFIG_MFD_DB8500_PRCMU
 
 void db8500_prcmu_early_init(void);
@@ -500,42 +514,41 @@
 enum romcode_read prcmu_get_rc_p2a(void);
 enum ap_pwrst prcmu_get_xp70_current_state(void);
 bool prcmu_has_arm_maxopp(void);
-bool prcmu_is_u8400(void);
-int prcmu_set_ape_opp(u8 opp);
-int prcmu_get_ape_opp(void);
+struct prcmu_fw_version *prcmu_get_fw_version(void);
 int prcmu_request_ape_opp_100_voltage(bool enable);
 int prcmu_release_usb_wakeup_state(void);
-int prcmu_set_ddr_opp(u8 opp);
-int prcmu_get_ddr_opp(void);
-/* NOTE! Use regulator framework instead */
-int prcmu_set_hwacc(u16 hw_acc_dev, u8 state);
 void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
 	struct prcmu_auto_pm_config *idle);
 bool prcmu_is_auto_pm_enabled(void);
 
 int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
 int prcmu_set_clock_divider(u8 clock, u8 divider);
-int prcmu_config_hotdog(u8 threshold);
-int prcmu_config_hotmon(u8 low, u8 high);
-int prcmu_start_temp_sense(u16 cycles32k);
-int prcmu_stop_temp_sense(void);
+int db8500_prcmu_config_hotdog(u8 threshold);
+int db8500_prcmu_config_hotmon(u8 low, u8 high);
+int db8500_prcmu_start_temp_sense(u16 cycles32k);
+int db8500_prcmu_stop_temp_sense(void);
 int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
 int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
 
 void prcmu_ac_wake_req(void);
 void prcmu_ac_sleep_req(void);
-void prcmu_modem_reset(void);
-void prcmu_enable_spi2(void);
-void prcmu_disable_spi2(void);
+void db8500_prcmu_modem_reset(void);
 
-int prcmu_config_a9wdog(u8 num, bool sleep_auto_off);
-int prcmu_enable_a9wdog(u8 id);
-int prcmu_disable_a9wdog(u8 id);
-int prcmu_kick_a9wdog(u8 id);
-int prcmu_load_a9wdog(u8 id, u32 val);
+int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off);
+int db8500_prcmu_enable_a9wdog(u8 id);
+int db8500_prcmu_disable_a9wdog(u8 id);
+int db8500_prcmu_kick_a9wdog(u8 id);
+int db8500_prcmu_load_a9wdog(u8 id, u32 val);
 
 void db8500_prcmu_system_reset(u16 reset_code);
 int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll);
+u8 db8500_prcmu_get_power_state_result(void);
+int db8500_prcmu_gic_decouple(void);
+int db8500_prcmu_gic_recouple(void);
+int db8500_prcmu_copy_gic_settings(void);
+bool db8500_prcmu_gic_pending_irq(void);
+bool db8500_prcmu_pending_irq(void);
+bool db8500_prcmu_is_cpu_in_wfi(int cpu);
 void db8500_prcmu_enable_wakeups(u32 wakeups);
 int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state);
 int db8500_prcmu_request_clock(u8 clock, bool enable);
@@ -549,6 +562,14 @@
 bool db8500_prcmu_is_ac_wake_requested(void);
 int db8500_prcmu_set_arm_opp(u8 opp);
 int db8500_prcmu_get_arm_opp(void);
+int db8500_prcmu_set_ape_opp(u8 opp);
+int db8500_prcmu_get_ape_opp(void);
+int db8500_prcmu_set_ddr_opp(u8 opp);
+int db8500_prcmu_get_ddr_opp(void);
+
+u32 db8500_prcmu_read(unsigned int reg);
+void db8500_prcmu_write(unsigned int reg, u32 value);
+void db8500_prcmu_write_masked(unsigned int reg, u32 mask, u32 value);
 
 #else /* !CONFIG_MFD_DB8500_PRCMU */
 
@@ -574,17 +595,17 @@
 	return false;
 }
 
-static inline bool prcmu_is_u8400(void)
+static inline struct prcmu_fw_version *prcmu_get_fw_version(void)
 {
-	return false;
+	return NULL;
 }
 
-static inline int prcmu_set_ape_opp(u8 opp)
+static inline int db8500_prcmu_set_ape_opp(u8 opp)
 {
 	return 0;
 }
 
-static inline int prcmu_get_ape_opp(void)
+static inline int db8500_prcmu_get_ape_opp(void)
 {
 	return APE_100_OPP;
 }
@@ -599,21 +620,16 @@
 	return 0;
 }
 
-static inline int prcmu_set_ddr_opp(u8 opp)
+static inline int db8500_prcmu_set_ddr_opp(u8 opp)
 {
 	return 0;
 }
 
-static inline int prcmu_get_ddr_opp(void)
+static inline int db8500_prcmu_get_ddr_opp(void)
 {
 	return DDR_100_OPP;
 }
 
-static inline int prcmu_set_hwacc(u16 hw_acc_dev, u8 state)
-{
-	return 0;
-}
-
 static inline void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
 	struct prcmu_auto_pm_config *idle)
 {
@@ -634,22 +650,22 @@
 	return 0;
 }
 
-static inline int prcmu_config_hotdog(u8 threshold)
+static inline int db8500_prcmu_config_hotdog(u8 threshold)
 {
 	return 0;
 }
 
-static inline int prcmu_config_hotmon(u8 low, u8 high)
+static inline int db8500_prcmu_config_hotmon(u8 low, u8 high)
 {
 	return 0;
 }
 
-static inline int prcmu_start_temp_sense(u16 cycles32k)
+static inline int db8500_prcmu_start_temp_sense(u16 cycles32k)
 {
 	return 0;
 }
 
-static inline int prcmu_stop_temp_sense(void)
+static inline int db8500_prcmu_stop_temp_sense(void)
 {
 	return 0;
 }
@@ -668,17 +684,7 @@
 
 static inline void prcmu_ac_sleep_req(void) {}
 
-static inline void prcmu_modem_reset(void) {}
-
-static inline int prcmu_enable_spi2(void)
-{
-	return 0;
-}
-
-static inline int prcmu_disable_spi2(void)
-{
-	return 0;
-}
+static inline void db8500_prcmu_modem_reset(void) {}
 
 static inline void db8500_prcmu_system_reset(u16 reset_code) {}
 
@@ -688,6 +694,11 @@
 	return 0;
 }
 
+static inline u8 db8500_prcmu_get_power_state_result(void)
+{
+	return 0;
+}
+
 static inline void db8500_prcmu_enable_wakeups(u32 wakeups) {}
 
 static inline int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state)
@@ -729,27 +740,27 @@
 	return 0;
 }
 
-static inline int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
+static inline int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
 {
 	return 0;
 }
 
-static inline int prcmu_enable_a9wdog(u8 id)
+static inline int db8500_prcmu_enable_a9wdog(u8 id)
 {
 	return 0;
 }
 
-static inline int prcmu_disable_a9wdog(u8 id)
+static inline int db8500_prcmu_disable_a9wdog(u8 id)
 {
 	return 0;
 }
 
-static inline int prcmu_kick_a9wdog(u8 id)
+static inline int db8500_prcmu_kick_a9wdog(u8 id)
 {
 	return 0;
 }
 
-static inline int prcmu_load_a9wdog(u8 id, u32 val)
+static inline int db8500_prcmu_load_a9wdog(u8 id, u32 val)
 {
 	return 0;
 }
@@ -769,6 +780,16 @@
 	return 0;
 }
 
+static inline u32 db8500_prcmu_read(unsigned int reg)
+{
+	return 0;
+}
+
+static inline void db8500_prcmu_write(unsigned int reg, u32 value) {}
+
+static inline void db8500_prcmu_write_masked(unsigned int reg, u32 mask,
+	u32 value) {}
+
 #endif /* !CONFIG_MFD_DB8500_PRCMU */
 
 #endif /* __MFD_DB8500_PRCMU_H */
diff --git a/include/linux/mfd/dbx500-prcmu.h b/include/linux/mfd/dbx500-prcmu.h
index bac942f..d7674eb 100644
--- a/include/linux/mfd/dbx500-prcmu.h
+++ b/include/linux/mfd/dbx500-prcmu.h
@@ -10,7 +10,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
-#include <asm/mach-types.h>
+#include <linux/err.h>
 
 /* PRCMU Wakeup defines */
 enum prcmu_wakeup_index {
@@ -80,6 +80,29 @@
 #define EPOD_STATE_ON_CLK_OFF	0x03
 #define EPOD_STATE_ON		0x04
 
+/* DB5500 CLKOUT IDs */
+enum {
+	DB5500_CLKOUT0 = 0,
+	DB5500_CLKOUT1,
+};
+
+/* DB5500 CLKOUTx sources */
+enum {
+	DB5500_CLKOUT_REF_CLK_SEL0,
+	DB5500_CLKOUT_RTC_CLK0_SEL0,
+	DB5500_CLKOUT_ULP_CLK_SEL0,
+	DB5500_CLKOUT_STATIC0,
+	DB5500_CLKOUT_REFCLK,
+	DB5500_CLKOUT_ULPCLK,
+	DB5500_CLKOUT_ARMCLK,
+	DB5500_CLKOUT_SYSACC0CLK,
+	DB5500_CLKOUT_SOC0PLLCLK,
+	DB5500_CLKOUT_SOC1PLLCLK,
+	DB5500_CLKOUT_DDRPLLCLK,
+	DB5500_CLKOUT_TVCLK,
+	DB5500_CLKOUT_IRDACLK,
+};
+
 /*
  * CLKOUT sources
  */
@@ -111,6 +134,7 @@
 	PRCMU_MSP1CLK,
 	PRCMU_I2CCLK,
 	PRCMU_SDMMCCLK,
+	PRCMU_SPARE1CLK,
 	PRCMU_SLIMCLK,
 	PRCMU_PER1CLK,
 	PRCMU_PER2CLK,
@@ -139,12 +163,20 @@
 	PRCMU_IRRCCLK,
 	PRCMU_SIACLK,
 	PRCMU_SVACLK,
+	PRCMU_ACLK,
 	PRCMU_NUM_REG_CLOCKS,
 	PRCMU_SYSCLK = PRCMU_NUM_REG_CLOCKS,
+	PRCMU_CDCLK,
 	PRCMU_TIMCLK,
 	PRCMU_PLLSOC0,
 	PRCMU_PLLSOC1,
 	PRCMU_PLLDDR,
+	PRCMU_PLLDSI,
+	PRCMU_DSI0CLK,
+	PRCMU_DSI1CLK,
+	PRCMU_DSI0ESCCLK,
+	PRCMU_DSI1ESCCLK,
+	PRCMU_DSI2ESCCLK,
 };
 
 /**
@@ -153,12 +185,14 @@
  * @APE_NO_CHANGE: The APE operating point is unchanged
  * @APE_100_OPP: The new APE operating point is ape100opp
  * @APE_50_OPP: 50%
+ * @APE_50_PARTLY_25_OPP: 50%, except some clocks at 25%.
  */
 enum ape_opp {
 	APE_OPP_INIT = 0x00,
 	APE_NO_CHANGE = 0x01,
 	APE_100_OPP = 0x02,
-	APE_50_OPP = 0x03
+	APE_50_OPP = 0x03,
+	APE_50_PARTLY_25_OPP = 0xFF,
 };
 
 /**
@@ -218,9 +252,11 @@
 
 #if defined(CONFIG_UX500_SOC_DB8500) || defined(CONFIG_UX500_SOC_DB5500)
 
+#include <mach/id.h>
+
 static inline void __init prcmu_early_init(void)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_early_init();
 	else
 		return db8500_prcmu_early_init();
@@ -229,7 +265,7 @@
 static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
 		bool keep_ap_pll)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_set_power_state(state, keep_ulp_clk,
 			keep_ap_pll);
 	else
@@ -237,9 +273,65 @@
 			keep_ap_pll);
 }
 
+static inline u8 prcmu_get_power_state_result(void)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_get_power_state_result();
+}
+
+static inline int prcmu_gic_decouple(void)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_gic_decouple();
+}
+
+static inline int prcmu_gic_recouple(void)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_gic_recouple();
+}
+
+static inline bool prcmu_gic_pending_irq(void)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_gic_pending_irq();
+}
+
+static inline bool prcmu_is_cpu_in_wfi(int cpu)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_is_cpu_in_wfi(cpu);
+}
+
+static inline int prcmu_copy_gic_settings(void)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_copy_gic_settings();
+}
+
+static inline bool prcmu_pending_irq(void)
+{
+        if (cpu_is_u5500())
+                return -EINVAL;
+        else
+                return db8500_prcmu_pending_irq();
+}
+
 static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return -EINVAL;
 	else
 		return db8500_prcmu_set_epod(epod_id, epod_state);
@@ -247,7 +339,7 @@
 
 static inline void prcmu_enable_wakeups(u32 wakeups)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		db5500_prcmu_enable_wakeups(wakeups);
 	else
 		db8500_prcmu_enable_wakeups(wakeups);
@@ -260,7 +352,7 @@
 
 static inline void prcmu_config_abb_event_readout(u32 abb_events)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		db5500_prcmu_config_abb_event_readout(abb_events);
 	else
 		db8500_prcmu_config_abb_event_readout(abb_events);
@@ -268,7 +360,7 @@
 
 static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		db5500_prcmu_get_abb_event_buffer(buf);
 	else
 		db8500_prcmu_get_abb_event_buffer(buf);
@@ -276,25 +368,40 @@
 
 int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
 int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
+int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask, u8 size);
 
 int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
 
 static inline int prcmu_request_clock(u8 clock, bool enable)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_request_clock(clock, enable);
 	else
 		return db8500_prcmu_request_clock(clock, enable);
 }
 
-int prcmu_set_ape_opp(u8 opp);
-int prcmu_get_ape_opp(void);
-int prcmu_set_ddr_opp(u8 opp);
-int prcmu_get_ddr_opp(void);
+unsigned long prcmu_clock_rate(u8 clock);
+long prcmu_round_clock_rate(u8 clock, unsigned long rate);
+int prcmu_set_clock_rate(u8 clock, unsigned long rate);
+
+static inline int prcmu_set_ddr_opp(u8 opp)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_set_ddr_opp(opp);
+}
+static inline int prcmu_get_ddr_opp(void)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_get_ddr_opp();
+}
 
 static inline int prcmu_set_arm_opp(u8 opp)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return -EINVAL;
 	else
 		return db8500_prcmu_set_arm_opp(opp);
@@ -302,15 +409,31 @@
 
 static inline int prcmu_get_arm_opp(void)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return -EINVAL;
 	else
 		return db8500_prcmu_get_arm_opp();
 }
 
+static inline int prcmu_set_ape_opp(u8 opp)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_set_ape_opp(opp);
+}
+
+static inline int prcmu_get_ape_opp(void)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_get_ape_opp();
+}
+
 static inline void prcmu_system_reset(u16 reset_code)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_system_reset(reset_code);
 	else
 		return db8500_prcmu_system_reset(reset_code);
@@ -318,7 +441,7 @@
 
 static inline u16 prcmu_get_reset_code(void)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_get_reset_code();
 	else
 		return db8500_prcmu_get_reset_code();
@@ -326,10 +449,17 @@
 
 void prcmu_ac_wake_req(void);
 void prcmu_ac_sleep_req(void);
-void prcmu_modem_reset(void);
+static inline void prcmu_modem_reset(void)
+{
+	if (cpu_is_u5500())
+		return;
+	else
+		return db8500_prcmu_modem_reset();
+}
+
 static inline bool prcmu_is_ac_wake_requested(void)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_is_ac_wake_requested();
 	else
 		return db8500_prcmu_is_ac_wake_requested();
@@ -337,7 +467,7 @@
 
 static inline int prcmu_set_display_clocks(void)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_set_display_clocks();
 	else
 		return db8500_prcmu_set_display_clocks();
@@ -345,7 +475,7 @@
 
 static inline int prcmu_disable_dsipll(void)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_disable_dsipll();
 	else
 		return db8500_prcmu_disable_dsipll();
@@ -353,7 +483,7 @@
 
 static inline int prcmu_enable_dsipll(void)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_enable_dsipll();
 	else
 		return db8500_prcmu_enable_dsipll();
@@ -361,11 +491,107 @@
 
 static inline int prcmu_config_esram0_deep_sleep(u8 state)
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return -EINVAL;
 	else
 		return db8500_prcmu_config_esram0_deep_sleep(state);
 }
+
+static inline int prcmu_config_hotdog(u8 threshold)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_config_hotdog(threshold);
+}
+
+static inline int prcmu_config_hotmon(u8 low, u8 high)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_config_hotmon(low, high);
+}
+
+static inline int prcmu_start_temp_sense(u16 cycles32k)
+{
+	if (cpu_is_u5500())
+		return  -EINVAL;
+	else
+		return  db8500_prcmu_start_temp_sense(cycles32k);
+}
+
+static inline int prcmu_stop_temp_sense(void)
+{
+	if (cpu_is_u5500())
+		return  -EINVAL;
+	else
+		return  db8500_prcmu_stop_temp_sense();
+}
+
+static inline u32 prcmu_read(unsigned int reg)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_read(reg);
+}
+
+static inline void prcmu_write(unsigned int reg, u32 value)
+{
+	if (cpu_is_u5500())
+		return;
+	else
+		db8500_prcmu_write(reg, value);
+}
+
+static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
+{
+	if (cpu_is_u5500())
+		return;
+	else
+		db8500_prcmu_write_masked(reg, mask, value);
+}
+
+static inline int prcmu_enable_a9wdog(u8 id)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_enable_a9wdog(id);
+}
+
+static inline int prcmu_disable_a9wdog(u8 id)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_disable_a9wdog(id);
+}
+
+static inline int prcmu_kick_a9wdog(u8 id)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_kick_a9wdog(id);
+}
+
+static inline int prcmu_load_a9wdog(u8 id, u32 timeout)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_load_a9wdog(id, timeout);
+}
+
+static inline int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_config_a9wdog(num, sleep_auto_off);
+}
 #else
 
 static inline void __init prcmu_early_init(void) {}
@@ -395,6 +621,12 @@
 	return -ENOSYS;
 }
 
+static inline int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask,
+	u8 size)
+{
+	return -ENOSYS;
+}
+
 static inline int prcmu_config_clkout(u8 clkout, u8 source, u8 div)
 {
 	return 0;
@@ -405,6 +637,21 @@
 	return 0;
 }
 
+static inline long prcmu_round_clock_rate(u8 clock, unsigned long rate)
+{
+	return 0;
+}
+
+static inline int prcmu_set_clock_rate(u8 clock, unsigned long rate)
+{
+	return 0;
+}
+
+static inline unsigned long prcmu_clock_rate(u8 clock)
+{
+	return 0;
+}
+
 static inline int prcmu_set_ape_opp(u8 opp)
 {
 	return 0;
@@ -480,14 +727,133 @@
 	*buf = NULL;
 }
 
+static inline int prcmu_config_hotdog(u8 threshold)
+{
+	return 0;
+}
+
+static inline int prcmu_config_hotmon(u8 low, u8 high)
+{
+	return 0;
+}
+
+static inline int prcmu_start_temp_sense(u16 cycles32k)
+{
+	return 0;
+}
+
+static inline int prcmu_stop_temp_sense(void)
+{
+	return 0;
+}
+
+static inline u32 prcmu_read(unsigned int reg)
+{
+	return 0;
+}
+
+static inline void prcmu_write(unsigned int reg, u32 value) {}
+
+static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {}
+
+#endif
+
+static inline void prcmu_set(unsigned int reg, u32 bits)
+{
+	prcmu_write_masked(reg, bits, bits);
+}
+
+static inline void prcmu_clear(unsigned int reg, u32 bits)
+{
+	prcmu_write_masked(reg, bits, 0);
+}
+
+#if defined(CONFIG_UX500_SOC_DB8500) || defined(CONFIG_UX500_SOC_DB5500)
+
+/**
+ * prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1.
+ */
+static inline void prcmu_enable_spi2(void)
+{
+	if (cpu_is_u8500())
+		prcmu_set(DB8500_PRCM_GPIOCR, DB8500_PRCM_GPIOCR_SPI2_SELECT);
+}
+
+/**
+ * prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1.
+ */
+static inline void prcmu_disable_spi2(void)
+{
+	if (cpu_is_u8500())
+		prcmu_clear(DB8500_PRCM_GPIOCR, DB8500_PRCM_GPIOCR_SPI2_SELECT);
+}
+
+/**
+ * prcmu_enable_stm_mod_uart - Enables pin muxing for STMMOD
+ * and UARTMOD on OtherAlternateC3.
+ */
+static inline void prcmu_enable_stm_mod_uart(void)
+{
+	if (cpu_is_u8500()) {
+		prcmu_set(DB8500_PRCM_GPIOCR,
+			(DB8500_PRCM_GPIOCR_DBG_STM_MOD_CMD1 |
+			 DB8500_PRCM_GPIOCR_DBG_UARTMOD_CMD0));
+	}
+}
+
+/**
+ * prcmu_disable_stm_mod_uart - Disables pin muxing for STMMOD
+ * and UARTMOD on OtherAlternateC3.
+ */
+static inline void prcmu_disable_stm_mod_uart(void)
+{
+	if (cpu_is_u8500()) {
+		prcmu_clear(DB8500_PRCM_GPIOCR,
+			(DB8500_PRCM_GPIOCR_DBG_STM_MOD_CMD1 |
+			 DB8500_PRCM_GPIOCR_DBG_UARTMOD_CMD0));
+	}
+}
+
+/**
+ * prcmu_enable_stm_ape - Enables pin muxing for STM APE on OtherAlternateC1.
+ */
+static inline void prcmu_enable_stm_ape(void)
+{
+	if (cpu_is_u8500()) {
+		prcmu_set(DB8500_PRCM_GPIOCR,
+			DB8500_PRCM_GPIOCR_DBG_STM_APE_CMD);
+	}
+}
+
+/**
+ * prcmu_disable_stm_ape - Disables pin muxing for STM APE on OtherAlternateC1.
+ */
+static inline void prcmu_disable_stm_ape(void)
+{
+	if (cpu_is_u8500()) {
+		prcmu_clear(DB8500_PRCM_GPIOCR,
+			DB8500_PRCM_GPIOCR_DBG_STM_APE_CMD);
+	}
+}
+
+#else
+
+static inline void prcmu_enable_spi2(void) {}
+static inline void prcmu_disable_spi2(void) {}
+static inline void prcmu_enable_stm_mod_uart(void) {}
+static inline void prcmu_disable_stm_mod_uart(void) {}
+static inline void prcmu_enable_stm_ape(void) {}
+static inline void prcmu_disable_stm_ape(void) {}
+
 #endif
 
 /* PRCMU QoS APE OPP class */
 #define PRCMU_QOS_APE_OPP 1
 #define PRCMU_QOS_DDR_OPP 2
+#define PRCMU_QOS_ARM_OPP 3
 #define PRCMU_QOS_DEFAULT_VALUE -1
 
-#ifdef CONFIG_UX500_PRCMU_QOS_POWER
+#ifdef CONFIG_DBX500_PRCMU_QOS_POWER
 
 unsigned long prcmu_qos_get_cpufreq_opp_delay(void);
 void prcmu_qos_set_cpufreq_opp_delay(unsigned long);
diff --git a/include/linux/mfd/max8997.h b/include/linux/mfd/max8997.h
index fff5905..28726dd 100644
--- a/include/linux/mfd/max8997.h
+++ b/include/linux/mfd/max8997.h
@@ -131,6 +131,55 @@
 	int num_init_data;
 };
 
+enum max8997_haptic_motor_type {
+	MAX8997_HAPTIC_ERM,
+	MAX8997_HAPTIC_LRA,
+};
+
+enum max8997_haptic_pulse_mode {
+	MAX8997_EXTERNAL_MODE,
+	MAX8997_INTERNAL_MODE,
+};
+
+enum max8997_haptic_pwm_divisor {
+	MAX8997_PWM_DIVISOR_32,
+	MAX8997_PWM_DIVISOR_64,
+	MAX8997_PWM_DIVISOR_128,
+	MAX8997_PWM_DIVISOR_256,
+};
+
+/**
+ * max8997_haptic_platform_data
+ * @pwm_channel_id: channel number of PWM device
+ *		    valid for MAX8997_EXTERNAL_MODE
+ * @pwm_period: period in nano second for PWM device
+ *		valid for MAX8997_EXTERNAL_MODE
+ * @type: motor type
+ * @mode: pulse mode
+ *     MAX8997_EXTERNAL_MODE: external PWM device is used to control motor
+ *     MAX8997_INTERNAL_MODE: internal pulse generator is used to control motor
+ * @pwm_divisor: divisor for external PWM device
+ * @internal_mode_pattern: internal mode pattern for internal mode
+ *     [0 - 3]: valid pattern number
+ * @pattern_cycle: the number of cycles of the waveform
+ *		   for the internal mode pattern
+ *     [0 - 15]: available cycles
+ * @pattern_signal_period: period of the waveform for the internal mode pattern
+ *     [0 - 255]: available period
+ */
+struct max8997_haptic_platform_data {
+	unsigned int pwm_channel_id;
+	unsigned int pwm_period;
+
+	enum max8997_haptic_motor_type type;
+	enum max8997_haptic_pulse_mode mode;
+	enum max8997_haptic_pwm_divisor pwm_divisor;
+
+	unsigned int internal_mode_pattern;
+	unsigned int pattern_cycle;
+	unsigned int pattern_signal_period;
+};
+
 enum max8997_led_mode {
 	MAX8997_NONE,
 	MAX8997_FLASH_MODE,
@@ -192,7 +241,9 @@
 	/* ---- MUIC ---- */
 	struct max8997_muic_platform_data *muic_pdata;
 
-	/* HAPTIC: Not implemented */
+	/* ---- HAPTIC ---- */
+	struct max8997_haptic_platform_data *haptic_pdata;
+
 	/* RTC: Not implemented */
 	/* ---- LED ---- */
 	struct max8997_led_platform_data *led_pdata;
diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h
index b86ee45..10e038b 100644
--- a/include/linux/mfd/mc13xxx.h
+++ b/include/linux/mfd/mc13xxx.h
@@ -38,7 +38,8 @@
 int mc13xxx_get_flags(struct mc13xxx *mc13xxx);
 
 int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx,
-		unsigned int mode, unsigned int channel, unsigned int *sample);
+		unsigned int mode, unsigned int channel,
+		u8 ato, bool atox, unsigned int *sample);
 
 #define MC13XXX_IRQ_ADCDONE	0
 #define MC13XXX_IRQ_ADCBISDONE	1
@@ -157,6 +158,18 @@
 	unsigned short b3on_key;
 };
 
+struct mc13xxx_ts_platform_data {
+	/* Delay between Touchscreen polarization and ADC Conversion.
+	 * Given in clock ticks of a 32 kHz clock which gives a granularity of
+	 * about 30.5ms */
+	u8 ato;
+
+#define MC13783_TS_ATO_FIRST false
+#define MC13783_TS_ATO_EACH  true
+	/* Use the ATO delay only for the first conversion or for each one */
+	bool atox;
+};
+
 struct mc13xxx_platform_data {
 #define MC13XXX_USE_TOUCHSCREEN (1 << 0)
 #define MC13XXX_USE_CODEC	(1 << 1)
@@ -167,6 +180,7 @@
 	struct mc13xxx_regulator_platform_data regulators;
 	struct mc13xxx_leds_platform_data *leds;
 	struct mc13xxx_buttons_platform_data *buttons;
+	struct mc13xxx_ts_platform_data touch;
 };
 
 #define MC13XXX_ADC_MODE_TS		1
diff --git a/include/linux/mfd/mcp.h b/include/linux/mfd/mcp.h
index f88c1cc..a9e8bd1 100644
--- a/include/linux/mfd/mcp.h
+++ b/include/linux/mfd/mcp.h
@@ -10,8 +10,6 @@
 #ifndef MCP_H
 #define MCP_H
 
-#include <mach/dma.h>
-
 struct mcp_ops;
 
 struct mcp {
@@ -21,12 +19,7 @@
 	int		use_count;
 	unsigned int	sclk_rate;
 	unsigned int	rw_timeout;
-	dma_device_t	dma_audio_rd;
-	dma_device_t	dma_audio_wr;
-	dma_device_t	dma_telco_rd;
-	dma_device_t	dma_telco_wr;
 	struct device	attached_device;
-	int		gpio_base;
 };
 
 struct mcp_ops {
@@ -47,15 +40,14 @@
 #define mcp_get_sclk_rate(mcp)	((mcp)->sclk_rate)
 
 struct mcp *mcp_host_alloc(struct device *, size_t);
-int mcp_host_register(struct mcp *);
-void mcp_host_unregister(struct mcp *);
+int mcp_host_add(struct mcp *, void *);
+void mcp_host_del(struct mcp *);
+void mcp_host_free(struct mcp *);
 
 struct mcp_driver {
 	struct device_driver drv;
 	int (*probe)(struct mcp *);
 	void (*remove)(struct mcp *);
-	int (*suspend)(struct mcp *, pm_message_t);
-	int (*resume)(struct mcp *);
 };
 
 int mcp_driver_register(struct mcp_driver *);
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index d5517fd..00fa3de 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.h
@@ -18,7 +18,6 @@
 #ifndef __MFD_PM8921_H
 #define __MFD_PM8921_H
 
-#include <linux/device.h>
 #include <linux/mfd/pm8xxx/irq.h>
 
 #define PM8921_NR_IRQS		256
diff --git a/include/linux/mfd/rc5t583.h b/include/linux/mfd/rc5t583.h
new file mode 100644
index 0000000..a2c6160
--- /dev/null
+++ b/include/linux/mfd/rc5t583.h
@@ -0,0 +1,295 @@
+/*
+ * Core driver interface to access RICOH_RC5T583 power management chip.
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * Based on code
+ *      Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __LINUX_MFD_RC5T583_H
+#define __LINUX_MFD_RC5T583_H
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+#define RC5T583_MAX_REGS		0xF8
+
+/* Maximum number of main interrupts */
+#define MAX_MAIN_INTERRUPT		5
+#define RC5T583_MAX_GPEDGE_REG		2
+#define RC5T583_MAX_INTERRUPT_MASK_REGS	9
+
+/* Interrupt enable register */
+#define RC5T583_INT_EN_SYS1	0x19
+#define RC5T583_INT_EN_SYS2	0x1D
+#define RC5T583_INT_EN_DCDC	0x41
+#define RC5T583_INT_EN_RTC	0xED
+#define RC5T583_INT_EN_ADC1	0x90
+#define RC5T583_INT_EN_ADC2	0x91
+#define RC5T583_INT_EN_ADC3	0x92
+
+/* Interrupt status registers (monitor regs in Ricoh)*/
+#define RC5T583_INTC_INTPOL	0xAD
+#define RC5T583_INTC_INTEN	0xAE
+#define RC5T583_INTC_INTMON	0xAF
+
+#define RC5T583_INT_MON_GRP	0xAF
+#define RC5T583_INT_MON_SYS1	0x1B
+#define RC5T583_INT_MON_SYS2	0x1F
+#define RC5T583_INT_MON_DCDC	0x43
+#define RC5T583_INT_MON_RTC	0xEE
+
+/* Interrupt clearing registers */
+#define RC5T583_INT_IR_SYS1	0x1A
+#define RC5T583_INT_IR_SYS2	0x1E
+#define RC5T583_INT_IR_DCDC	0x42
+#define RC5T583_INT_IR_RTC	0xEE
+#define RC5T583_INT_IR_ADCL	0x94
+#define RC5T583_INT_IR_ADCH	0x95
+#define RC5T583_INT_IR_ADCEND	0x96
+#define RC5T583_INT_IR_GPIOR	0xA9
+#define RC5T583_INT_IR_GPIOF	0xAA
+
+/* Sleep sequence registers */
+#define RC5T583_SLPSEQ1		0x21
+#define RC5T583_SLPSEQ2		0x22
+#define RC5T583_SLPSEQ3		0x23
+#define RC5T583_SLPSEQ4		0x24
+#define RC5T583_SLPSEQ5		0x25
+#define RC5T583_SLPSEQ6		0x26
+#define RC5T583_SLPSEQ7		0x27
+#define RC5T583_SLPSEQ8		0x28
+#define RC5T583_SLPSEQ9		0x29
+#define RC5T583_SLPSEQ10	0x2A
+#define RC5T583_SLPSEQ11	0x2B
+
+/* Regulator registers */
+#define RC5T583_REG_DC0CTL	0x30
+#define RC5T583_REG_DC0DAC	0x31
+#define RC5T583_REG_DC0LATCTL	0x32
+#define RC5T583_REG_SR0CTL	0x33
+
+#define RC5T583_REG_DC1CTL	0x34
+#define RC5T583_REG_DC1DAC	0x35
+#define RC5T583_REG_DC1LATCTL	0x36
+#define RC5T583_REG_SR1CTL	0x37
+
+#define RC5T583_REG_DC2CTL	0x38
+#define RC5T583_REG_DC2DAC	0x39
+#define RC5T583_REG_DC2LATCTL	0x3A
+#define RC5T583_REG_SR2CTL	0x3B
+
+#define RC5T583_REG_DC3CTL	0x3C
+#define RC5T583_REG_DC3DAC	0x3D
+#define RC5T583_REG_DC3LATCTL	0x3E
+#define RC5T583_REG_SR3CTL	0x3F
+
+
+#define RC5T583_REG_LDOEN1	0x50
+#define RC5T583_REG_LDOEN2	0x51
+#define RC5T583_REG_LDODIS1	0x52
+#define RC5T583_REG_LDODIS2	0x53
+
+#define RC5T583_REG_LDO0DAC	0x54
+#define RC5T583_REG_LDO1DAC	0x55
+#define RC5T583_REG_LDO2DAC	0x56
+#define RC5T583_REG_LDO3DAC	0x57
+#define RC5T583_REG_LDO4DAC	0x58
+#define RC5T583_REG_LDO5DAC	0x59
+#define RC5T583_REG_LDO6DAC	0x5A
+#define RC5T583_REG_LDO7DAC	0x5B
+#define RC5T583_REG_LDO8DAC	0x5C
+#define RC5T583_REG_LDO9DAC	0x5D
+
+#define RC5T583_REG_DC0DAC_DS	0x60
+#define RC5T583_REG_DC1DAC_DS	0x61
+#define RC5T583_REG_DC2DAC_DS	0x62
+#define RC5T583_REG_DC3DAC_DS	0x63
+
+#define RC5T583_REG_LDO0DAC_DS	0x64
+#define RC5T583_REG_LDO1DAC_DS	0x65
+#define RC5T583_REG_LDO2DAC_DS	0x66
+#define RC5T583_REG_LDO3DAC_DS	0x67
+#define RC5T583_REG_LDO4DAC_DS	0x68
+#define RC5T583_REG_LDO5DAC_DS	0x69
+#define RC5T583_REG_LDO6DAC_DS	0x6A
+#define RC5T583_REG_LDO7DAC_DS	0x6B
+#define RC5T583_REG_LDO8DAC_DS	0x6C
+#define RC5T583_REG_LDO9DAC_DS	0x6D
+
+/* GPIO register base address */
+#define RC5T583_GPIO_IOSEL	0xA0
+#define RC5T583_GPIO_PDEN	0xA1
+#define RC5T583_GPIO_IOOUT	0xA2
+#define RC5T583_GPIO_PGSEL	0xA3
+#define RC5T583_GPIO_GPINV	0xA4
+#define RC5T583_GPIO_GPDEB	0xA5
+#define RC5T583_GPIO_GPEDGE1	0xA6
+#define RC5T583_GPIO_GPEDGE2	0xA7
+#define RC5T583_GPIO_EN_INT	0xA8
+#define RC5T583_GPIO_MON_IOIN	0xAB
+#define RC5T583_GPIO_GPOFUNC	0xAC
+
+/* RICOH_RC5T583 IRQ definitions */
+enum {
+	RC5T583_IRQ_ONKEY,
+	RC5T583_IRQ_ACOK,
+	RC5T583_IRQ_LIDOPEN,
+	RC5T583_IRQ_PREOT,
+	RC5T583_IRQ_CLKSTP,
+	RC5T583_IRQ_ONKEY_OFF,
+	RC5T583_IRQ_WD,
+	RC5T583_IRQ_EN_PWRREQ1,
+	RC5T583_IRQ_EN_PWRREQ2,
+	RC5T583_IRQ_PRE_VINDET,
+
+	RC5T583_IRQ_DC0LIM,
+	RC5T583_IRQ_DC1LIM,
+	RC5T583_IRQ_DC2LIM,
+	RC5T583_IRQ_DC3LIM,
+
+	RC5T583_IRQ_CTC,
+	RC5T583_IRQ_YALE,
+	RC5T583_IRQ_DALE,
+	RC5T583_IRQ_WALE,
+
+	RC5T583_IRQ_AIN1L,
+	RC5T583_IRQ_AIN2L,
+	RC5T583_IRQ_AIN3L,
+	RC5T583_IRQ_VBATL,
+	RC5T583_IRQ_VIN3L,
+	RC5T583_IRQ_VIN8L,
+	RC5T583_IRQ_AIN1H,
+	RC5T583_IRQ_AIN2H,
+	RC5T583_IRQ_AIN3H,
+	RC5T583_IRQ_VBATH,
+	RC5T583_IRQ_VIN3H,
+	RC5T583_IRQ_VIN8H,
+	RC5T583_IRQ_ADCEND,
+
+	RC5T583_IRQ_GPIO0,
+	RC5T583_IRQ_GPIO1,
+	RC5T583_IRQ_GPIO2,
+	RC5T583_IRQ_GPIO3,
+	RC5T583_IRQ_GPIO4,
+	RC5T583_IRQ_GPIO5,
+	RC5T583_IRQ_GPIO6,
+	RC5T583_IRQ_GPIO7,
+
+	/* Should be last entry */
+	RC5T583_MAX_IRQS,
+};
+
+/* Ricoh583 gpio definitions */
+enum {
+	RC5T583_GPIO0,
+	RC5T583_GPIO1,
+	RC5T583_GPIO2,
+	RC5T583_GPIO3,
+	RC5T583_GPIO4,
+	RC5T583_GPIO5,
+	RC5T583_GPIO6,
+	RC5T583_GPIO7,
+
+	/* Should be last entry */
+	RC5T583_MAX_GPIO,
+};
+
+enum {
+	RC5T583_DS_NONE,
+	RC5T583_DS_DC0,
+	RC5T583_DS_DC1,
+	RC5T583_DS_DC2,
+	RC5T583_DS_DC3,
+	RC5T583_DS_LDO0,
+	RC5T583_DS_LDO1,
+	RC5T583_DS_LDO2,
+	RC5T583_DS_LDO3,
+	RC5T583_DS_LDO4,
+	RC5T583_DS_LDO5,
+	RC5T583_DS_LDO6,
+	RC5T583_DS_LDO7,
+	RC5T583_DS_LDO8,
+	RC5T583_DS_LDO9,
+	RC5T583_DS_PSO0,
+	RC5T583_DS_PSO1,
+	RC5T583_DS_PSO2,
+	RC5T583_DS_PSO3,
+	RC5T583_DS_PSO4,
+	RC5T583_DS_PSO5,
+	RC5T583_DS_PSO6,
+	RC5T583_DS_PSO7,
+
+	/* Should be last entry */
+	RC5T583_DS_MAX,
+};
+
+/*
+ * Ricoh pmic RC5T583 supports sleep through two external controls.
+ * The output of gpios and regulator can be enable/disable through
+ * this external signals.
+ */
+enum {
+	RC5T583_EXT_PWRREQ1_CONTROL = 0x1,
+	RC5T583_EXT_PWRREQ2_CONTROL = 0x2,
+};
+
+struct rc5t583 {
+	struct device	*dev;
+	struct regmap	*regmap;
+	int		chip_irq;
+	int		irq_base;
+	struct mutex	irq_lock;
+	unsigned long	group_irq_en[MAX_MAIN_INTERRUPT];
+
+	/* For main interrupt bits in INTC */
+	uint8_t		intc_inten_reg;
+
+	/* For group interrupt bits and address */
+	uint8_t		irq_en_reg[RC5T583_MAX_INTERRUPT_MASK_REGS];
+
+	/* For gpio edge */
+	uint8_t		gpedge_reg[RC5T583_MAX_GPEDGE_REG];
+};
+
+/*
+ * rc5t583_platform_data: Platform data for ricoh rc5t583 pmu.
+ * The board specific data is provided through this structure.
+ * @irq_base: Irq base number on which this device registers their interrupts.
+ * @enable_shutdown: Enable shutdown through the input pin "shutdown".
+ */
+
+struct rc5t583_platform_data {
+	int		irq_base;
+	bool		enable_shutdown;
+};
+
+int rc5t583_write(struct device *dev, u8 reg, uint8_t val);
+int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val);
+int rc5t583_set_bits(struct device *dev, unsigned int reg,
+		unsigned int bit_mask);
+int rc5t583_clear_bits(struct device *dev, unsigned int reg,
+		unsigned int bit_mask);
+int rc5t583_update(struct device *dev, unsigned int reg,
+		unsigned int val, unsigned int mask);
+int rc5t583_ext_power_req_config(struct device *dev, int deepsleep_id,
+	int ext_pwr_req, int deepsleep_slot_nr);
+int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base);
+int rc5t583_irq_exit(struct rc5t583 *rc5t583);
+
+#endif
diff --git a/include/linux/mfd/stmpe.h b/include/linux/mfd/stmpe.h
index ca1d7a34..8516fd1 100644
--- a/include/linux/mfd/stmpe.h
+++ b/include/linux/mfd/stmpe.h
@@ -8,7 +8,9 @@
 #ifndef __LINUX_MFD_STMPE_H
 #define __LINUX_MFD_STMPE_H
 
-#include <linux/device.h>
+#include <linux/mutex.h>
+
+struct device;
 
 enum stmpe_block {
 	STMPE_BLOCK_GPIO	= 1 << 0,
@@ -26,6 +28,7 @@
 	STMPE1601,
 	STMPE2401,
 	STMPE2403,
+	STMPE_NBR_PARTS
 };
 
 /*
diff --git a/include/linux/mfd/tc3589x.h b/include/linux/mfd/tc3589x.h
index 16c76e1..3acb3a8 100644
--- a/include/linux/mfd/tc3589x.h
+++ b/include/linux/mfd/tc3589x.h
@@ -7,7 +7,7 @@
 #ifndef __LINUX_MFD_TC3589x_H
 #define __LINUX_MFD_TC3589x_H
 
-#include <linux/device.h>
+struct device;
 
 enum tx3589x_block {
 	TC3589x_BLOCK_GPIO        = 1 << 0,
diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h
index 0dc9804..f5171db 100644
--- a/include/linux/mfd/tmio.h
+++ b/include/linux/mfd/tmio.h
@@ -1,8 +1,10 @@
 #ifndef MFD_TMIO_H
 #define MFD_TMIO_H
 
+#include <linux/device.h>
 #include <linux/fb.h>
 #include <linux/io.h>
+#include <linux/jiffies.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 
@@ -64,8 +66,8 @@
 #define TMIO_MMC_SDIO_IRQ		(1 << 2)
 /*
  * Some platforms can detect card insertion events with controller powered
- * down, in which case they have to call tmio_mmc_cd_wakeup() to power up the
- * controller and report the event to the driver.
+ * down, using a GPIO IRQ, in which case they have to fill in cd_irq, cd_gpio,
+ * and cd_flags fields of struct tmio_mmc_data.
  */
 #define TMIO_MMC_HAS_COLD_CD		(1 << 3)
 /*
@@ -73,6 +75,12 @@
  * idle before writing to some registers.
  */
 #define TMIO_MMC_HAS_IDLE_WAIT		(1 << 4)
+/*
+ * A GPIO is used for card hotplug detection. We need an extra flag for this,
+ * because 0 is a valid GPIO number too, and requiring users to specify
+ * cd_gpio < 0 to disable GPIO hotplug would break backwards compatibility.
+ */
+#define TMIO_MMC_USE_GPIO_CD		(1 << 5)
 
 int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base);
 int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base);
@@ -97,19 +105,23 @@
 	u32				ocr_mask;	/* available voltages */
 	struct tmio_mmc_dma		*dma;
 	struct device			*dev;
-	bool				power;
+	unsigned int			cd_gpio;
 	void (*set_pwr)(struct platform_device *host, int state);
 	void (*set_clk_div)(struct platform_device *host, int state);
 	int (*get_cd)(struct platform_device *host);
 	int (*write16_hook)(struct tmio_mmc_host *host, int addr);
 };
 
+/*
+ * This function is deprecated and will be removed soon. Please, convert your
+ * platform to use drivers/mmc/core/cd-gpio.c
+ */
+#include <linux/mmc/host.h>
 static inline void tmio_mmc_cd_wakeup(struct tmio_mmc_data *pdata)
 {
-	if (pdata && !pdata->power) {
-		pdata->power = true;
-		pm_runtime_get(pdata->dev);
-	}
+	if (pdata)
+		mmc_detect_change(dev_get_drvdata(pdata->dev),
+				  msecs_to_jiffies(100));
 }
 
 /*
diff --git a/include/linux/mfd/tps65090.h b/include/linux/mfd/tps65090.h
new file mode 100644
index 0000000..38e31c5
--- /dev/null
+++ b/include/linux/mfd/tps65090.h
@@ -0,0 +1,46 @@
+/*
+ * Core driver interface for TI TPS65090 PMIC family
+ *
+ * Copyright (C) 2012 NVIDIA 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * 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_MFD_TPS65090_H
+#define __LINUX_MFD_TPS65090_H
+
+struct tps65090_subdev_info {
+	int		id;
+	const char	*name;
+	void		*platform_data;
+};
+
+struct tps65090_platform_data {
+	int irq_base;
+	int num_subdevs;
+	struct tps65090_subdev_info *subdevs;
+};
+
+/*
+ * NOTE: the functions below are not intended for use outside
+ * of the TPS65090 sub-device drivers
+ */
+extern int tps65090_write(struct device *dev, int reg, uint8_t val);
+extern int tps65090_read(struct device *dev, int reg, uint8_t *val);
+extern int tps65090_set_bits(struct device *dev, int reg, uint8_t bit_num);
+extern int tps65090_clr_bits(struct device *dev, int reg, uint8_t bit_num);
+
+#endif /*__LINUX_MFD_TPS65090_H */
diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h
new file mode 100644
index 0000000..e030ef9
--- /dev/null
+++ b/include/linux/mfd/tps65217.h
@@ -0,0 +1,283 @@
+/*
+ * linux/mfd/tps65217.h
+ *
+ * Functions to access TPS65217 power management chip.
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.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.
+ */
+
+#ifndef __LINUX_MFD_TPS65217_H
+#define __LINUX_MFD_TPS65217_H
+
+#include <linux/i2c.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+/* I2C ID for TPS65217 part */
+#define TPS65217_I2C_ID			0x24
+
+/* All register addresses */
+#define TPS65217_REG_CHIPID		0X00
+#define TPS65217_REG_PPATH		0X01
+#define TPS65217_REG_INT		0X02
+#define TPS65217_REG_CHGCONFIG0		0X03
+#define TPS65217_REG_CHGCONFIG1		0X04
+#define TPS65217_REG_CHGCONFIG2		0X05
+#define TPS65217_REG_CHGCONFIG3		0X06
+#define TPS65217_REG_WLEDCTRL1		0X07
+#define TPS65217_REG_WLEDCTRL2		0X08
+#define TPS65217_REG_MUXCTRL		0X09
+#define TPS65217_REG_STATUS		0X0A
+#define TPS65217_REG_PASSWORD		0X0B
+#define TPS65217_REG_PGOOD		0X0C
+#define TPS65217_REG_DEFPG		0X0D
+#define TPS65217_REG_DEFDCDC1		0X0E
+#define TPS65217_REG_DEFDCDC2		0X0F
+#define TPS65217_REG_DEFDCDC3		0X10
+#define TPS65217_REG_DEFSLEW		0X11
+#define TPS65217_REG_DEFLDO1		0X12
+#define TPS65217_REG_DEFLDO2		0X13
+#define TPS65217_REG_DEFLS1		0X14
+#define TPS65217_REG_DEFLS2		0X15
+#define TPS65217_REG_ENABLE		0X16
+#define TPS65217_REG_DEFUVLO		0X18
+#define TPS65217_REG_SEQ1		0X19
+#define TPS65217_REG_SEQ2		0X1A
+#define TPS65217_REG_SEQ3		0X1B
+#define TPS65217_REG_SEQ4		0X1C
+#define TPS65217_REG_SEQ5		0X1D
+#define TPS65217_REG_SEQ6		0X1E
+
+/* Register field definitions */
+#define TPS65217_CHIPID_CHIP_MASK	0xF0
+#define TPS65217_CHIPID_REV_MASK	0x0F
+
+#define TPS65217_PPATH_ACSINK_ENABLE	BIT(7)
+#define TPS65217_PPATH_USBSINK_ENABLE	BIT(6)
+#define TPS65217_PPATH_AC_PW_ENABLE	BIT(5)
+#define TPS65217_PPATH_USB_PW_ENABLE	BIT(4)
+#define TPS65217_PPATH_AC_CURRENT_MASK	0x0C
+#define TPS65217_PPATH_USB_CURRENT_MASK	0x03
+
+#define TPS65217_INT_PBM		BIT(6)
+#define TPS65217_INT_ACM		BIT(5)
+#define TPS65217_INT_USBM		BIT(4)
+#define TPS65217_INT_PBI		BIT(2)
+#define TPS65217_INT_ACI		BIT(1)
+#define TPS65217_INT_USBI		BIT(0)
+
+#define TPS65217_CHGCONFIG0_TREG	BIT(7)
+#define TPS65217_CHGCONFIG0_DPPM	BIT(6)
+#define TPS65217_CHGCONFIG0_TSUSP	BIT(5)
+#define TPS65217_CHGCONFIG0_TERMI	BIT(4)
+#define TPS65217_CHGCONFIG0_ACTIVE	BIT(3)
+#define TPS65217_CHGCONFIG0_CHGTOUT	BIT(2)
+#define TPS65217_CHGCONFIG0_PCHGTOUT	BIT(1)
+#define TPS65217_CHGCONFIG0_BATTEMP	BIT(0)
+
+#define TPS65217_CHGCONFIG1_TMR_MASK	0xC0
+#define TPS65217_CHGCONFIG1_TMR_ENABLE	BIT(5)
+#define TPS65217_CHGCONFIG1_NTC_TYPE	BIT(4)
+#define TPS65217_CHGCONFIG1_RESET	BIT(3)
+#define TPS65217_CHGCONFIG1_TERM	BIT(2)
+#define TPS65217_CHGCONFIG1_SUSP	BIT(1)
+#define TPS65217_CHGCONFIG1_CHG_EN	BIT(0)
+
+#define TPS65217_CHGCONFIG2_DYNTMR	BIT(7)
+#define TPS65217_CHGCONFIG2_VPREGHG	BIT(6)
+#define TPS65217_CHGCONFIG2_VOREG_MASK	0x30
+
+#define TPS65217_CHGCONFIG3_ICHRG_MASK	0xC0
+#define TPS65217_CHGCONFIG3_DPPMTH_MASK	0x30
+#define TPS65217_CHGCONFIG2_PCHRGT	BIT(3)
+#define TPS65217_CHGCONFIG2_TERMIF	0x06
+#define TPS65217_CHGCONFIG2_TRANGE	BIT(0)
+
+#define TPS65217_WLEDCTRL1_ISINK_ENABLE	BIT(3)
+#define TPS65217_WLEDCTRL1_ISEL		BIT(2)
+#define TPS65217_WLEDCTRL1_FDIM_MASK	0x03
+
+#define TPS65217_WLEDCTRL2_DUTY_MASK	0x7F
+
+#define TPS65217_MUXCTRL_MUX_MASK	0x07
+
+#define TPS65217_STATUS_OFF		BIT(7)
+#define TPS65217_STATUS_ACPWR		BIT(3)
+#define TPS65217_STATUS_USBPWR		BIT(2)
+#define TPS65217_STATUS_PB		BIT(0)
+
+#define TPS65217_PASSWORD_REGS_UNLOCK	0x7D
+
+#define TPS65217_PGOOD_LDO3_PG		BIT(6)
+#define TPS65217_PGOOD_LDO4_PG		BIT(5)
+#define TPS65217_PGOOD_DC1_PG		BIT(4)
+#define TPS65217_PGOOD_DC2_PG		BIT(3)
+#define TPS65217_PGOOD_DC3_PG		BIT(2)
+#define TPS65217_PGOOD_LDO1_PG		BIT(1)
+#define TPS65217_PGOOD_LDO2_PG		BIT(0)
+
+#define TPS65217_DEFPG_LDO1PGM		BIT(3)
+#define TPS65217_DEFPG_LDO2PGM		BIT(2)
+#define TPS65217_DEFPG_PGDLY_MASK	0x03
+
+#define TPS65217_DEFDCDCX_XADJX		BIT(7)
+#define TPS65217_DEFDCDCX_DCDC_MASK	0x3F
+
+#define TPS65217_DEFSLEW_GO		BIT(7)
+#define TPS65217_DEFSLEW_GODSBL		BIT(6)
+#define TPS65217_DEFSLEW_PFM_EN1	BIT(5)
+#define TPS65217_DEFSLEW_PFM_EN2	BIT(4)
+#define TPS65217_DEFSLEW_PFM_EN3	BIT(3)
+#define TPS65217_DEFSLEW_SLEW_MASK	0x07
+
+#define TPS65217_DEFLDO1_LDO1_MASK	0x0F
+
+#define TPS65217_DEFLDO2_TRACK		BIT(6)
+#define TPS65217_DEFLDO2_LDO2_MASK	0x3F
+
+#define TPS65217_DEFLDO3_LDO3_EN	BIT(5)
+#define TPS65217_DEFLDO3_LDO3_MASK	0x1F
+
+#define TPS65217_DEFLDO4_LDO4_EN	BIT(5)
+#define TPS65217_DEFLDO4_LDO4_MASK	0x1F
+
+#define TPS65217_ENABLE_LS1_EN		BIT(6)
+#define TPS65217_ENABLE_LS2_EN		BIT(5)
+#define TPS65217_ENABLE_DC1_EN		BIT(4)
+#define TPS65217_ENABLE_DC2_EN		BIT(3)
+#define TPS65217_ENABLE_DC3_EN		BIT(2)
+#define TPS65217_ENABLE_LDO1_EN		BIT(1)
+#define TPS65217_ENABLE_LDO2_EN		BIT(0)
+
+#define TPS65217_DEFUVLO_UVLOHYS	BIT(2)
+#define TPS65217_DEFUVLO_UVLO_MASK	0x03
+
+#define TPS65217_SEQ1_DC1_SEQ_MASK	0xF0
+#define TPS65217_SEQ1_DC2_SEQ_MASK	0x0F
+
+#define TPS65217_SEQ2_DC3_SEQ_MASK	0xF0
+#define TPS65217_SEQ2_LDO1_SEQ_MASK	0x0F
+
+#define TPS65217_SEQ3_LDO2_SEQ_MASK	0xF0
+#define TPS65217_SEQ3_LDO3_SEQ_MASK	0x0F
+
+#define TPS65217_SEQ4_LDO4_SEQ_MASK	0xF0
+
+#define TPS65217_SEQ5_DLY1_MASK		0xC0
+#define TPS65217_SEQ5_DLY2_MASK		0x30
+#define TPS65217_SEQ5_DLY3_MASK		0x0C
+#define TPS65217_SEQ5_DLY4_MASK		0x03
+
+#define TPS65217_SEQ6_DLY5_MASK		0xC0
+#define TPS65217_SEQ6_DLY6_MASK		0x30
+#define TPS65217_SEQ6_SEQUP		BIT(2)
+#define TPS65217_SEQ6_SEQDWN		BIT(1)
+#define TPS65217_SEQ6_INSTDWN		BIT(0)
+
+#define TPS65217_MAX_REGISTER		0x1E
+#define TPS65217_PROTECT_NONE		0
+#define TPS65217_PROTECT_L1		1
+#define TPS65217_PROTECT_L2		2
+
+
+enum tps65217_regulator_id {
+	/* DCDC's */
+	TPS65217_DCDC_1,
+	TPS65217_DCDC_2,
+	TPS65217_DCDC_3,
+	/* LDOs */
+	TPS65217_LDO_1,
+	TPS65217_LDO_2,
+	TPS65217_LDO_3,
+	TPS65217_LDO_4,
+};
+
+#define TPS65217_MAX_REG_ID		TPS65217_LDO_4
+
+/* Number of step-down converters available */
+#define TPS65217_NUM_DCDC		3
+/* Number of LDO voltage regulators available */
+#define TPS65217_NUM_LDO		4
+/* Number of total regulators available */
+#define TPS65217_NUM_REGULATOR		(TPS65217_NUM_DCDC + TPS65217_NUM_LDO)
+
+/**
+ * struct tps65217_board - packages regulator init data
+ * @tps65217_regulator_data: regulator initialization values
+ *
+ * Board data may be used to initialize regulator.
+ */
+struct tps65217_board {
+	struct regulator_init_data *tps65217_init_data;
+};
+
+/**
+ * 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
+ * @table:		Table for non-uniform voltage step-size
+ * @table_len:		Length of the voltage table
+ * @enable_mask:	Regulator enable mask bits
+ * @set_vout_reg:	Regulator output voltage set register
+ * @set_vout_mask:	Regulator output voltage set mask
+ *
+ * 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);
+	const int *table;
+	unsigned int table_len;
+	unsigned int enable_mask;
+	unsigned int set_vout_reg;
+	unsigned int set_vout_mask;
+};
+
+/**
+ * struct tps65217 - tps65217 sub-driver chip access routines
+ *
+ * Device data may be used to access the TPS65217 chip
+ */
+
+struct tps65217 {
+	struct device *dev;
+	struct tps65217_board *pdata;
+	struct regulator_desc desc[TPS65217_NUM_REGULATOR];
+	struct regulator_dev *rdev[TPS65217_NUM_REGULATOR];
+	struct tps_info *info[TPS65217_NUM_REGULATOR];
+	struct regmap *regmap;
+
+	/* Client devices */
+	struct platform_device *regulator_pdev[TPS65217_NUM_REGULATOR];
+};
+
+static inline struct tps65217 *dev_to_tps65217(struct device *dev)
+{
+	return dev_get_drvdata(dev);
+}
+
+int tps65217_reg_read(struct tps65217 *tps, unsigned int reg,
+					unsigned int *val);
+int tps65217_reg_write(struct tps65217 *tps, unsigned int reg,
+			unsigned int val, unsigned int level);
+int tps65217_set_bits(struct tps65217 *tps, unsigned int reg,
+		unsigned int mask, unsigned int val, unsigned int level);
+int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
+		unsigned int mask, unsigned int level);
+
+#endif /*  __LINUX_MFD_TPS65217_H */
diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h
index 76700b5..1c6c286 100644
--- a/include/linux/mfd/tps65910.h
+++ b/include/linux/mfd/tps65910.h
@@ -17,6 +17,8 @@
 #ifndef __LINUX_MFD_TPS65910_H
 #define __LINUX_MFD_TPS65910_H
 
+#include <linux/gpio.h>
+
 /* TPS chip id list */
 #define TPS65910			0
 #define TPS65911			1
@@ -657,6 +659,8 @@
 
 
 /*Register GPIO  (0x80) register.RegisterDescription */
+#define GPIO_SLEEP_MASK                         0x80
+#define GPIO_SLEEP_SHIFT                        7
 #define GPIO_DEB_MASK                           0x10
 #define GPIO_DEB_SHIFT                          4
 #define GPIO_PUEN_MASK                          0x08
@@ -740,6 +744,11 @@
 #define TPS65910_GPIO_STS				BIT(1)
 #define TPS65910_GPIO_SET				BIT(0)
 
+/* Max number of TPS65910/11 GPIOs */
+#define TPS65910_NUM_GPIO				6
+#define TPS65911_NUM_GPIO				9
+#define TPS6591X_MAX_NUM_GPIO				9
+
 /* Regulator Index Definitions */
 #define TPS65910_REG_VRTC				0
 #define TPS65910_REG_VIO				1
@@ -785,6 +794,7 @@
 	int irq_base;
 	int vmbch_threshold;
 	int vmbch2_threshold;
+	bool en_gpio_sleep[TPS6591X_MAX_NUM_GPIO];
 	unsigned long regulator_ext_sleep_control[TPS65910_NUM_REGS];
 	struct regulator_init_data *tps65910_pmic_init_data[TPS65910_NUM_REGS];
 };
@@ -796,6 +806,7 @@
 struct tps65910 {
 	struct device *dev;
 	struct i2c_client *i2c_client;
+	struct regmap *regmap;
 	struct mutex io_mutex;
 	unsigned int id;
 	int (*read)(struct tps65910 *tps65910, u8 reg, int size, void *dest);
diff --git a/include/linux/mfd/ucb1x00.h b/include/linux/mfd/ucb1x00.h
index 4321f04..28af417 100644
--- a/include/linux/mfd/ucb1x00.h
+++ b/include/linux/mfd/ucb1x00.h
@@ -12,7 +12,7 @@
 
 #include <linux/mfd/mcp.h>
 #include <linux/gpio.h>
-#include <linux/semaphore.h>
+#include <linux/mutex.h>
 
 #define UCB_IO_DATA	0x00
 #define UCB_IO_DIR	0x01
@@ -104,17 +104,27 @@
 #define UCB_MODE_DYN_VFLAG_ENA	(1 << 12)
 #define UCB_MODE_AUD_OFF_CAN	(1 << 13)
 
+enum ucb1x00_reset {
+	UCB_RST_PROBE,
+	UCB_RST_RESUME,
+	UCB_RST_SUSPEND,
+	UCB_RST_REMOVE,
+	UCB_RST_PROBE_FAIL,
+};
 
-struct ucb1x00_irq {
-	void *devid;
-	void (*fn)(int, void *);
+struct ucb1x00_plat_data {
+	void			(*reset)(enum ucb1x00_reset);
+	unsigned		irq_base;
+	int			gpio_base;
+	unsigned		can_wakeup;
 };
 
 struct ucb1x00 {
-	spinlock_t		lock;
+	raw_spinlock_t		irq_lock;
 	struct mcp		*mcp;
 	unsigned int		irq;
-	struct semaphore	adc_sem;
+	int			irq_base;
+	struct mutex		adc_mutex;
 	spinlock_t		io_lock;
 	u16			id;
 	u16			io_dir;
@@ -122,7 +132,8 @@
 	u16			adc_cr;
 	u16			irq_fal_enbl;
 	u16			irq_ris_enbl;
-	struct ucb1x00_irq	irq_handler[16];
+	u16			irq_mask;
+	u16			irq_wake;
 	struct device		dev;
 	struct list_head	node;
 	struct list_head	devs;
@@ -144,7 +155,7 @@
 	struct list_head	devs;
 	int	(*add)(struct ucb1x00_dev *dev);
 	void	(*remove)(struct ucb1x00_dev *dev);
-	int	(*suspend)(struct ucb1x00_dev *dev, pm_message_t state);
+	int	(*suspend)(struct ucb1x00_dev *dev);
 	int	(*resume)(struct ucb1x00_dev *dev);
 };
 
@@ -245,15 +256,4 @@
 void ucb1x00_adc_enable(struct ucb1x00 *ucb);
 void ucb1x00_adc_disable(struct ucb1x00 *ucb);
 
-/*
- * Which edges of the IRQ do you want to control today?
- */
-#define UCB_RISING	(1 << 0)
-#define UCB_FALLING	(1 << 1)
-
-int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid);
-void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
-void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
-int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid);
-
 #endif
diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h
index 3fb1f407..893267b 100644
--- a/include/linux/mfd/wm8994/pdata.h
+++ b/include/linux/mfd/wm8994/pdata.h
@@ -22,7 +22,6 @@
 	/** GPIOs to enable regulator, 0 or less if not available */
 	int enable;
 
-	const char *supply;
 	const struct regulator_init_data *init_data;
 };
 
@@ -185,6 +184,9 @@
         unsigned int jd_scthr:2;
         unsigned int jd_thr:2;
 
+	/* Configure WM1811 jack detection for use with external capacitor */
+	unsigned int jd_ext_cap:1;
+
 	/* WM8958 microphone bias configuration */
 	int micbias[2];
 
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 05ed282..855c337 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -8,7 +8,6 @@
 typedef struct page *new_page_t(struct page *, unsigned long private, int **);
 
 #ifdef CONFIG_MIGRATION
-#define PAGE_MIGRATION 1
 
 extern void putback_lru_pages(struct list_head *l);
 extern int migrate_page(struct address_space *,
@@ -32,7 +31,6 @@
 extern int migrate_huge_page_move_mapping(struct address_space *mapping,
 				  struct page *newpage, struct page *page);
 #else
-#define PAGE_MIGRATION 0
 
 static inline void putback_lru_pages(struct list_head *l) {}
 static inline int migrate_pages(struct list_head *l, new_page_t x,
diff --git a/include/linux/mlx4/driver.h b/include/linux/mlx4/driver.h
index e1eebf7..5f1298b 100644
--- a/include/linux/mlx4/driver.h
+++ b/include/linux/mlx4/driver.h
@@ -33,7 +33,6 @@
 #ifndef MLX4_DRIVER_H
 #define MLX4_DRIVER_H
 
-#include <linux/device.h>
 #include <linux/mlx4/device.h>
 
 struct mlx4_dev;
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 17b27cd..d8738a4 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -6,6 +6,7 @@
 #ifdef __KERNEL__
 
 #include <linux/gfp.h>
+#include <linux/bug.h>
 #include <linux/list.h>
 #include <linux/mmzone.h>
 #include <linux/rbtree.h>
@@ -111,7 +112,7 @@
 #define VM_HUGEPAGE	0x01000000	/* MADV_HUGEPAGE marked this vma */
 #endif
 #define VM_INSERTPAGE	0x02000000	/* The vma has had "vm_insert_page()" done on it */
-#define VM_ALWAYSDUMP	0x04000000	/* Always include in core dumps */
+#define VM_NODUMP	0x04000000	/* Do not include in the core dump */
 
 #define VM_CAN_NONLINEAR 0x08000000	/* Has ->fault & does nonlinear pages */
 #define VM_MIXEDMAP	0x10000000	/* Can contain "struct page" and pure PFN pages */
@@ -893,9 +894,9 @@
 
 int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
 		unsigned long size);
-unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
+void zap_page_range(struct vm_area_struct *vma, unsigned long address,
 		unsigned long size, struct zap_details *);
-unsigned long unmap_vmas(struct mmu_gather *tlb,
+void unmap_vmas(struct mmu_gather *tlb,
 		struct vm_area_struct *start_vma, unsigned long start_addr,
 		unsigned long end_addr, unsigned long *nr_accounted,
 		struct zap_details *);
@@ -953,7 +954,7 @@
 extern void truncate_setsize(struct inode *inode, loff_t newsize);
 extern int vmtruncate(struct inode *inode, loff_t offset);
 extern int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end);
-
+void truncate_pagecache_range(struct inode *inode, loff_t offset, loff_t end);
 int truncate_inode_page(struct address_space *mapping, struct page *page);
 int generic_error_remove_page(struct address_space *mapping, struct page *page);
 
@@ -1040,6 +1041,9 @@
 		!vma_growsup(vma->vm_next, addr);
 }
 
+extern pid_t
+vm_is_stack(struct task_struct *task, struct vm_area_struct *vma, int in_group);
+
 extern unsigned long move_page_tables(struct vm_area_struct *vma,
 		unsigned long old_addr, struct vm_area_struct *new_vma,
 		unsigned long new_addr, unsigned long len);
@@ -1058,19 +1062,20 @@
 /*
  * per-process(per-mm_struct) statistics.
  */
-static inline void set_mm_counter(struct mm_struct *mm, int member, long value)
-{
-	atomic_long_set(&mm->rss_stat.count[member], value);
-}
-
-#if defined(SPLIT_RSS_COUNTING)
-unsigned long get_mm_counter(struct mm_struct *mm, int member);
-#else
 static inline unsigned long get_mm_counter(struct mm_struct *mm, int member)
 {
-	return atomic_long_read(&mm->rss_stat.count[member]);
-}
+	long val = atomic_long_read(&mm->rss_stat.count[member]);
+
+#ifdef SPLIT_RSS_COUNTING
+	/*
+	 * counter is updated in asynchronous manner and may go to minus.
+	 * But it's never be expected number for users.
+	 */
+	if (val < 0)
+		val = 0;
 #endif
+	return (unsigned long)val;
+}
 
 static inline void add_mm_counter(struct mm_struct *mm, int member, long value)
 {
@@ -1127,9 +1132,9 @@
 }
 
 #if defined(SPLIT_RSS_COUNTING)
-void sync_mm_rss(struct task_struct *task, struct mm_struct *mm);
+void sync_mm_rss(struct mm_struct *mm);
 #else
-static inline void sync_mm_rss(struct task_struct *task, struct mm_struct *mm)
+static inline void sync_mm_rss(struct mm_struct *mm)
 {
 }
 #endif
@@ -1253,6 +1258,8 @@
 extern void free_area_init(unsigned long * zones_size);
 extern void free_area_init_node(int nid, unsigned long * zones_size,
 		unsigned long zone_start_pfn, unsigned long *zholes_size);
+extern void free_initmem(void);
+
 #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
 /*
  * With CONFIG_HAVE_MEMBLOCK_NODE_MAP set, an architecture may initialise its
@@ -1291,8 +1298,6 @@
 extern unsigned long find_min_pfn_with_active_regions(void);
 extern void free_bootmem_with_active_regions(int nid,
 						unsigned long max_low_pfn);
-int add_from_early_node_map(struct range *range, int az,
-				   int nr_range, int nid);
 extern void sparse_memory_present_with_active_regions(int nid);
 
 #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
@@ -1598,9 +1603,9 @@
 
 enum mf_flags {
 	MF_COUNT_INCREASED = 1 << 0,
+	MF_ACTION_REQUIRED = 1 << 1,
 };
-extern void memory_failure(unsigned long pfn, int trapno);
-extern int __memory_failure(unsigned long pfn, int trapno, int flags);
+extern int memory_failure(unsigned long pfn, int trapno, int flags);
 extern void memory_failure_queue(unsigned long pfn, int trapno, int flags);
 extern int unpoison_memory(unsigned long pfn);
 extern int sysctl_memory_failure_early_kill;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 19a41d1..01beae7 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -10,6 +10,7 @@
 #ifndef LINUX_MMC_CARD_H
 #define LINUX_MMC_CARD_H
 
+#include <linux/device.h>
 #include <linux/mmc/core.h>
 #include <linux/mod_devicetable.h>
 
@@ -71,6 +72,8 @@
 	bool			hpi_en;			/* HPI enablebit */
 	bool			hpi;			/* HPI support bit */
 	unsigned int		hpi_cmd;		/* cmd used as HPI */
+	unsigned int            data_sector_size;       /* 512 bytes or 4KB */
+	unsigned int            data_tag_unit_size;     /* DATA TAG UNIT size */
 	unsigned int		boot_ro_lock;		/* ro lock support */
 	bool			boot_ro_lockable;
 	u8			raw_partition_support;	/* 160 */
diff --git a/include/linux/mmc/cd-gpio.h b/include/linux/mmc/cd-gpio.h
index a8e4697..cefaba0 100644
--- a/include/linux/mmc/cd-gpio.h
+++ b/include/linux/mmc/cd-gpio.h
@@ -12,8 +12,7 @@
 #define MMC_CD_GPIO_H
 
 struct mmc_host;
-int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio,
-			unsigned int irq, unsigned long flags);
+int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio);
 void mmc_cd_gpio_free(struct mmc_host *host);
 
 #endif
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 87a976c..1b431c7 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -9,7 +9,7 @@
 #define LINUX_MMC_CORE_H
 
 #include <linux/interrupt.h>
-#include <linux/device.h>
+#include <linux/completion.h>
 
 struct request;
 struct mmc_data;
@@ -175,7 +175,6 @@
 
 extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
 extern void mmc_release_host(struct mmc_host *host);
-extern void mmc_do_release_host(struct mmc_host *host);
 extern int mmc_try_claim_host(struct mmc_host *host);
 
 extern int mmc_flush_cache(struct mmc_card *);
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index aae5d1f..8f66e28 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -76,7 +76,7 @@
  * @num_slots: Number of slots available.
  * @verid: Denote Version ID.
  * @data_offset: Set the offset of DATA register according to VERID.
- * @pdev: Platform device associated with the MMC controller.
+ * @dev: Device associated with the MMC controller.
  * @pdata: Platform data associated with the MMC controller.
  * @slot: Slots sharing this MMC controller.
  * @fifo_depth: depth of FIFO.
@@ -87,6 +87,8 @@
  * @push_data: Pointer to FIFO push function.
  * @pull_data: Pointer to FIFO pull function.
  * @quirks: Set of quirks that apply to specific versions of the IP.
+ * @irq_flags: The flags to be passed to request_irq.
+ * @irq: The irq value to be passed to request_irq.
  *
  * Locking
  * =======
@@ -153,7 +155,7 @@
 	u32			fifoth_val;
 	u16			verid;
 	u16			data_offset;
-	struct platform_device	*pdev;
+	struct device		dev;
 	struct dw_mci_board	*pdata;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
 
@@ -174,6 +176,8 @@
 	u32			quirks;
 
 	struct regulator	*vmmc;	/* Power regulator */
+	unsigned long		irq_flags; /* IRQ flags */
+	unsigned int		irq;
 };
 
 /* DMA ops for Internal/External DMAC interface */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index ee2b036..cbde4b7 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -12,6 +12,7 @@
 
 #include <linux/leds.h>
 #include <linux/sched.h>
+#include <linux/device.h>
 #include <linux/fault-inject.h>
 
 #include <linux/mmc/core.h>
@@ -80,34 +81,11 @@
 
 struct mmc_host_ops {
 	/*
-	 * Hosts that support power saving can use the 'enable' and 'disable'
-	 * methods to exit and enter power saving states. 'enable' is called
-	 * when the host is claimed and 'disable' is called (or scheduled with
-	 * a delay) when the host is released. The 'disable' is scheduled if
-	 * the disable delay set by 'mmc_set_disable_delay()' is non-zero,
-	 * otherwise 'disable' is called immediately. 'disable' may be
-	 * scheduled repeatedly, to permit ever greater power saving at the
-	 * expense of ever greater latency to re-enable. Rescheduling is
-	 * determined by the return value of the 'disable' method. A positive
-	 * value gives the delay in milliseconds.
-	 *
-	 * In the case where a host function (like set_ios) may be called
-	 * with or without the host claimed, enabling and disabling can be
-	 * done directly and will nest correctly. Call 'mmc_host_enable()' and
-	 * 'mmc_host_lazy_disable()' for this purpose, but note that these
-	 * functions must be paired.
-	 *
-	 * Alternatively, 'mmc_host_enable()' may be paired with
-	 * 'mmc_host_disable()' which calls 'disable' immediately.  In this
-	 * case the 'disable' method will be called with 'lazy' set to 0.
-	 * This is mainly useful for error paths.
-	 *
-	 * Because lazy disable may be called from a work queue, the 'disable'
-	 * method must claim the host when 'lazy' != 0, which will work
-	 * correctly because recursion is detected and handled.
+	 * 'enable' is called when the host is claimed and 'disable' is called
+	 * when the host is released. 'enable' and 'disable' are deprecated.
 	 */
 	int (*enable)(struct mmc_host *host);
-	int (*disable)(struct mmc_host *host, int lazy);
+	int (*disable)(struct mmc_host *host);
 	/*
 	 * It is optional for the host to implement pre_req and post_req in
 	 * order to support double buffering of requests (prepare one
@@ -218,7 +196,7 @@
 #define MMC_CAP_SPI		(1 << 4)	/* Talks only SPI protocols */
 #define MMC_CAP_NEEDS_POLL	(1 << 5)	/* Needs polling for card-detection */
 #define MMC_CAP_8_BIT_DATA	(1 << 6)	/* Can the host do 8 bit transfers */
-#define MMC_CAP_DISABLE		(1 << 7)	/* Can the host be disabled */
+
 #define MMC_CAP_NONREMOVABLE	(1 << 8)	/* Nonremovable e.g. eMMC */
 #define MMC_CAP_WAIT_WHILE_BUSY	(1 << 9)	/* Waits while card is busy */
 #define MMC_CAP_ERASE		(1 << 10)	/* Allow erase/trim commands */
@@ -258,6 +236,8 @@
 #define MMC_CAP2_HS200		(MMC_CAP2_HS200_1_8V_SDR | \
 				 MMC_CAP2_HS200_1_2V_SDR)
 #define MMC_CAP2_BROKEN_VOLTAGE	(1 << 7)	/* Use the broken voltage */
+#define MMC_CAP2_DETECT_ON_ERR	(1 << 8)	/* On I/O err check card removal */
+#define MMC_CAP2_HC_ERASE_SZ	(1 << 9)	/* High-capacity erase size */
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 	unsigned int        power_notify_type;
@@ -300,13 +280,7 @@
 	unsigned int		removed:1;	/* host is being removed */
 #endif
 
-	/* Only used with MMC_CAP_DISABLE */
-	int			enabled;	/* host is enabled */
 	int			rescan_disable;	/* disable card detection */
-	int			nesting_cnt;	/* "enable" nesting count */
-	int			en_dis_recurs;	/* detect recursion */
-	unsigned int		disable_delay;	/* disable delay in msecs */
-	struct delayed_work	disable;	/* disabling work */
 
 	struct mmc_card		*card;		/* device attached to this host */
 
@@ -406,17 +380,8 @@
 int mmc_card_sleep(struct mmc_host *host);
 int mmc_card_can_sleep(struct mmc_host *host);
 
-int mmc_host_enable(struct mmc_host *host);
-int mmc_host_disable(struct mmc_host *host);
-int mmc_host_lazy_disable(struct mmc_host *host);
 int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
 
-static inline void mmc_set_disable_delay(struct mmc_host *host,
-					 unsigned int disable_delay)
-{
-	host->disable_delay = disable_delay;
-}
-
 /* Module parameter */
 extern bool mmc_assume_removable;
 
diff --git a/include/linux/mmc/ioctl.h b/include/linux/mmc/ioctl.h
index 8fa5bc5..1f5e689 100644
--- a/include/linux/mmc/ioctl.h
+++ b/include/linux/mmc/ioctl.h
@@ -1,5 +1,8 @@
 #ifndef LINUX_MMC_IOCTL_H
 #define LINUX_MMC_IOCTL_H
+
+#include <linux/types.h>
+
 struct mmc_ioc_cmd {
 	/* Implies direction of data.  true = write, false = read */
 	int write_flag;
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index fb9f6e1..b822a2c 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -274,6 +274,7 @@
 #define EXT_CSD_FLUSH_CACHE		32      /* W */
 #define EXT_CSD_CACHE_CTRL		33      /* R/W */
 #define EXT_CSD_POWER_OFF_NOTIFICATION	34	/* R/W */
+#define EXT_CSD_DATA_SECTOR_SIZE	61	/* R */
 #define EXT_CSD_GP_SIZE_MULT		143	/* R/W */
 #define EXT_CSD_PARTITION_ATTRIBUTE	156	/* R/W */
 #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
@@ -315,6 +316,8 @@
 #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
+#define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
+#define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
 #define EXT_CSD_HPI_FEATURES		503	/* RO */
 
 /*
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index c750f85..e9051e1 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -90,6 +90,8 @@
 
 	unsigned int quirks2;	/* More deviations from spec. */
 
+#define SDHCI_QUIRK2_HOST_OFF_CARD_ON			(1<<0)
+
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
 
diff --git a/include/linux/mmc/sh_mmcif.h b/include/linux/mmc/sh_mmcif.h
index 04ff452..05f0e3d 100644
--- a/include/linux/mmc/sh_mmcif.h
+++ b/include/linux/mmc/sh_mmcif.h
@@ -77,18 +77,15 @@
 
 /* CE_CLK_CTRL */
 #define CLK_ENABLE		(1 << 24) /* 1: output mmc clock */
-#define CLK_CLEAR		((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16))
-#define CLK_SUP_PCLK		((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16))
-#define CLKDIV_4		(1<<16) /* mmc clock frequency.
-					 * n: bus clock/(2^(n+1)) */
-#define CLKDIV_256		(7<<16) /* mmc clock frequency. (see above) */
-#define SRSPTO_256		((1 << 13) | (0 << 12)) /* resp timeout */
-#define SRBSYTO_29		((1 << 11) | (1 << 10) |	\
-				 (1 << 9) | (1 << 8)) /* resp busy timeout */
-#define SRWDTO_29		((1 << 7) | (1 << 6) |		\
-				 (1 << 5) | (1 << 4)) /* read/write timeout */
-#define SCCSTO_29		((1 << 3) | (1 << 2) |		\
-				 (1 << 1) | (1 << 0)) /* ccs timeout */
+#define CLK_CLEAR		(0xf << 16)
+#define CLK_SUP_PCLK		(0xf << 16)
+#define CLKDIV_4		(1 << 16) /* mmc clock frequency.
+					   * n: bus clock/(2^(n+1)) */
+#define CLKDIV_256		(7 << 16) /* mmc clock frequency. (see above) */
+#define SRSPTO_256		(2 << 12) /* resp timeout */
+#define SRBSYTO_29		(0xf << 8) /* resp busy timeout */
+#define SRWDTO_29		(0xf << 4) /* read/write timeout */
+#define SCCSTO_29		(0xf << 0) /* ccs timeout */
 
 /* CE_VERSION */
 #define SOFT_RST_ON		(1 << 31)
diff --git a/include/linux/mmc/sh_mobile_sdhi.h b/include/linux/mmc/sh_mobile_sdhi.h
index 71b8054..e94e620 100644
--- a/include/linux/mmc/sh_mobile_sdhi.h
+++ b/include/linux/mmc/sh_mobile_sdhi.h
@@ -10,15 +10,29 @@
 #define SH_MOBILE_SDHI_IRQ_SDCARD	"sdcard"
 #define SH_MOBILE_SDHI_IRQ_SDIO		"sdio"
 
+/**
+ * struct sh_mobile_sdhi_ops - SDHI driver callbacks
+ * @cd_wakeup:		trigger a card-detection run
+ */
+struct sh_mobile_sdhi_ops {
+	void (*cd_wakeup)(const struct platform_device *pdev);
+};
+
 struct sh_mobile_sdhi_info {
 	int dma_slave_tx;
 	int dma_slave_rx;
 	unsigned long tmio_flags;
 	unsigned long tmio_caps;
 	u32 tmio_ocr_mask;	/* available MMC voltages */
+	unsigned int cd_gpio;
 	struct tmio_mmc_data *pdata;
 	void (*set_pwr)(struct platform_device *pdev, int state);
 	int (*get_cd)(struct platform_device *pdev);
+
+	/* callbacks for board specific setup code */
+	int (*init)(struct platform_device *pdev,
+		    const struct sh_mobile_sdhi_ops *ops);
+	void (*cleanup)(struct platform_device *pdev);
 };
 
 #endif /* LINUX_MMC_SH_MOBILE_SDHI_H */
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 650ba2f..dff7115 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -365,6 +365,7 @@
 	 */
 	unsigned int		compact_considered;
 	unsigned int		compact_defer_shift;
+	int			compact_order_failed;
 #endif
 
 	ZONE_PADDING(_pad1_)
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index fb69ad1..501da4c 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -414,6 +414,15 @@
 			__attribute__((aligned(sizeof(kernel_ulong_t))));
 };
 
+/* rpmsg */
+
+#define RPMSG_NAME_SIZE			32
+#define RPMSG_DEVICE_MODALIAS_FMT	"rpmsg:%s"
+
+struct rpmsg_device_id {
+	char name[RPMSG_NAME_SIZE];
+};
+
 /* i2c */
 
 #define I2C_NAME_SIZE	20
diff --git a/include/linux/module.h b/include/linux/module.h
index 4598bf0..fbcafe2 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -21,8 +21,6 @@
 #include <linux/percpu.h>
 #include <asm/module.h>
 
-#include <trace/events/module.h>
-
 /* Not Yet Implemented */
 #define MODULE_SUPPORTED_DEVICE(name)
 
@@ -452,33 +450,11 @@
 
 /* Sometimes we know we already have a refcount, and it's easier not
    to handle the error case (which only happens with rmmod --wait). */
-static inline void __module_get(struct module *module)
-{
-	if (module) {
-		preempt_disable();
-		__this_cpu_inc(module->refptr->incs);
-		trace_module_get(module, _THIS_IP_);
-		preempt_enable();
-	}
-}
+extern void __module_get(struct module *module);
 
-static inline int try_module_get(struct module *module)
-{
-	int ret = 1;
-
-	if (module) {
-		preempt_disable();
-
-		if (likely(module_is_live(module))) {
-			__this_cpu_inc(module->refptr->incs);
-			trace_module_get(module, _THIS_IP_);
-		} else
-			ret = 0;
-
-		preempt_enable();
-	}
-	return ret;
-}
+/* This is the Right Way to get a module: if it fails, it's being removed,
+ * so pretend it's not there. */
+extern bool try_module_get(struct module *module);
 
 extern void module_put(struct module *module);
 
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index c47f4d6..ea36486 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -47,14 +47,11 @@
 	void (*free)(void *arg);
 };
 
-/* Flag bits for kernel_param.flags */
-#define KPARAM_ISBOOL		2
-
 struct kernel_param {
 	const char *name;
 	const struct kernel_param_ops *ops;
 	u16 perm;
-	u16 flags;
+	s16 level;
 	union {
 		void *arg;
 		const struct kparam_string *str;
@@ -131,8 +128,40 @@
  * The ops can have NULL set or get functions.
  */
 #define module_param_cb(name, ops, arg, perm)				      \
-	__module_param_call(MODULE_PARAM_PREFIX,			      \
-			    name, ops, arg, __same_type((arg), bool *), perm)
+	__module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, 0)
+
+/**
+ * <level>_param_cb - general callback for a module/cmdline parameter
+ *                    to be evaluated before certain initcall level
+ * @name: a valid C identifier which is the parameter name.
+ * @ops: the set & get operations for this parameter.
+ * @perm: visibility in sysfs.
+ *
+ * The ops can have NULL set or get functions.
+ */
+#define __level_param_cb(name, ops, arg, perm, level)			\
+	__module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, level)
+
+#define core_param_cb(name, ops, arg, perm)		\
+	__level_param_cb(name, ops, arg, perm, 1)
+
+#define postcore_param_cb(name, ops, arg, perm)		\
+	__level_param_cb(name, ops, arg, perm, 2)
+
+#define arch_param_cb(name, ops, arg, perm)		\
+	__level_param_cb(name, ops, arg, perm, 3)
+
+#define subsys_param_cb(name, ops, arg, perm)		\
+	__level_param_cb(name, ops, arg, perm, 4)
+
+#define fs_param_cb(name, ops, arg, perm)		\
+	__level_param_cb(name, ops, arg, perm, 5)
+
+#define device_param_cb(name, ops, arg, perm)		\
+	__level_param_cb(name, ops, arg, perm, 6)
+
+#define late_param_cb(name, ops, arg, perm)		\
+	__level_param_cb(name, ops, arg, perm, 7)
 
 /* On alpha, ia64 and ppc64 relocations to global data cannot go into
    read-only sections (which is part of respective UNIX ABI on these
@@ -146,7 +175,7 @@
 
 /* This is the fundamental function for registering boot/module
    parameters. */
-#define __module_param_call(prefix, name, ops, arg, isbool, perm)	\
+#define __module_param_call(prefix, name, ops, arg, perm, level)	\
 	/* Default value instead of permissions? */			\
 	static int __param_perm_check_##name __attribute__((unused)) =	\
 	BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2))	\
@@ -155,8 +184,7 @@
 	static struct kernel_param __moduleparam_const __param_##name	\
 	__used								\
     __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
-	= { __param_str_##name, ops, perm, isbool ? KPARAM_ISBOOL : 0,	\
-	    { arg } }
+	= { __param_str_##name, ops, perm, level, { arg } }
 
 /* Obsolete - use module_param_cb() */
 #define module_param_call(name, set, get, arg, perm)			\
@@ -164,8 +192,7 @@
 		 { (void *)set, (void *)get };				\
 	__module_param_call(MODULE_PARAM_PREFIX,			\
 			    name, &__param_ops_##name, arg,		\
-			    __same_type(arg, bool *),			\
-			    (perm) + sizeof(__check_old_set_param(set))*0)
+			    (perm) + sizeof(__check_old_set_param(set))*0, 0)
 
 /* We don't get oldget: it's often a new-style param_get_uint, etc. */
 static inline int
@@ -245,8 +272,7 @@
  */
 #define core_param(name, var, type, perm)				\
 	param_check_##type(name, &(var));				\
-	__module_param_call("", name, &param_ops_##type,		\
-			    &var, __same_type(var, bool), perm)
+	__module_param_call("", name, &param_ops_##type, &var, perm, 0)
 #endif /* !MODULE */
 
 /**
@@ -264,7 +290,7 @@
 		= { len, string };					\
 	__module_param_call(MODULE_PARAM_PREFIX, name,			\
 			    &param_ops_string,				\
-			    .str = &__param_string_##name, 0, perm);	\
+			    .str = &__param_string_##name, perm, 0);	\
 	__MODULE_PARM_TYPE(name, "string")
 
 /**
@@ -292,6 +318,8 @@
 		      char *args,
 		      const struct kernel_param *params,
 		      unsigned num,
+		      s16 level_min,
+		      s16 level_max,
 		      int (*unknown)(char *param, char *val));
 
 /* Called by module remove. */
@@ -403,7 +431,7 @@
 	__module_param_call(MODULE_PARAM_PREFIX, name,			\
 			    &param_array_ops,				\
 			    .arr = &__param_arr_##name,			\
-			    __same_type(array[0], bool), perm);		\
+			    perm, 0);					\
 	__MODULE_PARM_TYPE(name, "array of " #type)
 
 extern struct kernel_param_ops param_array_ops;
diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h
index c4eec22..650ef35 100644
--- a/include/linux/mtd/bbm.h
+++ b/include/linux/mtd/bbm.h
@@ -112,6 +112,11 @@
 #define NAND_BBT_USE_FLASH	0x00020000
 /* Do not store flash based bad block table in OOB area; store it in-band */
 #define NAND_BBT_NO_OOB		0x00040000
+/*
+ * Do not write new bad block markers to OOB; useful, e.g., when ECC covers
+ * entire spare area. Must be used with NAND_BBT_USE_FLASH.
+ */
+#define NAND_BBT_NO_OOB_BBM	0x00080000
 
 /*
  * Flag set by nand_create_default_bbt_descr(), marking that the nand_bbt_descr
diff --git a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h
index 1bbd9f2..ed270bd 100644
--- a/include/linux/mtd/blktrans.h
+++ b/include/linux/mtd/blktrans.h
@@ -47,6 +47,7 @@
 	struct request_queue *rq;
 	spinlock_t queue_lock;
 	void *priv;
+	fmode_t file_mode;
 };
 
 struct mtd_blktrans_ops {
diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h
index d5d2ec6..37ef6b1 100644
--- a/include/linux/mtd/cfi.h
+++ b/include/linux/mtd/cfi.h
@@ -22,6 +22,7 @@
 
 #include <linux/delay.h>
 #include <linux/types.h>
+#include <linux/bug.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/flashchip.h>
 #include <linux/mtd/map.h>
diff --git a/include/linux/mtd/fsmc.h b/include/linux/mtd/fsmc.h
index 6987995..b200292 100644
--- a/include/linux/mtd/fsmc.h
+++ b/include/linux/mtd/fsmc.h
@@ -26,95 +26,83 @@
 #define FSMC_NAND_BW8		1
 #define FSMC_NAND_BW16		2
 
-/*
- * The placement of the Command Latch Enable (CLE) and
- * Address Latch Enable (ALE) is twisted around in the
- * SPEAR310 implementation.
- */
-#if defined(CONFIG_MACH_SPEAR310)
-#define PLAT_NAND_CLE		(1 << 17)
-#define PLAT_NAND_ALE		(1 << 16)
-#else
-#define PLAT_NAND_CLE		(1 << 16)
-#define PLAT_NAND_ALE		(1 << 17)
-#endif
-
 #define FSMC_MAX_NOR_BANKS	4
 #define FSMC_MAX_NAND_BANKS	4
 
 #define FSMC_FLASH_WIDTH8	1
 #define FSMC_FLASH_WIDTH16	2
 
-struct fsmc_nor_bank_regs {
-	uint32_t ctrl;
-	uint32_t ctrl_tim;
-};
+/* fsmc controller registers for NOR flash */
+#define CTRL			0x0
+	/* ctrl register definitions */
+	#define BANK_ENABLE		(1 << 0)
+	#define MUXED			(1 << 1)
+	#define NOR_DEV			(2 << 2)
+	#define WIDTH_8			(0 << 4)
+	#define WIDTH_16		(1 << 4)
+	#define RSTPWRDWN		(1 << 6)
+	#define WPROT			(1 << 7)
+	#define WRT_ENABLE		(1 << 12)
+	#define WAIT_ENB		(1 << 13)
 
-/* ctrl register definitions */
-#define BANK_ENABLE		(1 << 0)
-#define MUXED			(1 << 1)
-#define NOR_DEV			(2 << 2)
-#define WIDTH_8			(0 << 4)
-#define WIDTH_16		(1 << 4)
-#define RSTPWRDWN		(1 << 6)
-#define WPROT			(1 << 7)
-#define WRT_ENABLE		(1 << 12)
-#define WAIT_ENB		(1 << 13)
+#define CTRL_TIM		0x4
+	/* ctrl_tim register definitions */
 
-/* ctrl_tim register definitions */
-
-struct fsmc_nand_bank_regs {
-	uint32_t pc;
-	uint32_t sts;
-	uint32_t comm;
-	uint32_t attrib;
-	uint32_t ioata;
-	uint32_t ecc1;
-	uint32_t ecc2;
-	uint32_t ecc3;
-};
-
+#define FSMC_NOR_BANK_SZ	0x8
 #define FSMC_NOR_REG_SIZE	0x40
 
-struct fsmc_regs {
-	struct fsmc_nor_bank_regs nor_bank_regs[FSMC_MAX_NOR_BANKS];
-	uint8_t reserved_1[0x40 - 0x20];
-	struct fsmc_nand_bank_regs bank_regs[FSMC_MAX_NAND_BANKS];
-	uint8_t reserved_2[0xfe0 - 0xc0];
-	uint32_t peripid0;			/* 0xfe0 */
-	uint32_t peripid1;			/* 0xfe4 */
-	uint32_t peripid2;			/* 0xfe8 */
-	uint32_t peripid3;			/* 0xfec */
-	uint32_t pcellid0;			/* 0xff0 */
-	uint32_t pcellid1;			/* 0xff4 */
-	uint32_t pcellid2;			/* 0xff8 */
-	uint32_t pcellid3;			/* 0xffc */
-};
+#define FSMC_NOR_REG(base, bank, reg)		(base + \
+						FSMC_NOR_BANK_SZ * (bank) + \
+						reg)
+
+/* fsmc controller registers for NAND flash */
+#define PC			0x00
+	/* pc register definitions */
+	#define FSMC_RESET		(1 << 0)
+	#define FSMC_WAITON		(1 << 1)
+	#define FSMC_ENABLE		(1 << 2)
+	#define FSMC_DEVTYPE_NAND	(1 << 3)
+	#define FSMC_DEVWID_8		(0 << 4)
+	#define FSMC_DEVWID_16		(1 << 4)
+	#define FSMC_ECCEN		(1 << 6)
+	#define FSMC_ECCPLEN_512	(0 << 7)
+	#define FSMC_ECCPLEN_256	(1 << 7)
+	#define FSMC_TCLR_1		(1)
+	#define FSMC_TCLR_SHIFT		(9)
+	#define FSMC_TCLR_MASK		(0xF)
+	#define FSMC_TAR_1		(1)
+	#define FSMC_TAR_SHIFT		(13)
+	#define FSMC_TAR_MASK		(0xF)
+#define STS			0x04
+	/* sts register definitions */
+	#define FSMC_CODE_RDY		(1 << 15)
+#define COMM			0x08
+	/* comm register definitions */
+	#define FSMC_TSET_0		0
+	#define FSMC_TSET_SHIFT		0
+	#define FSMC_TSET_MASK		0xFF
+	#define FSMC_TWAIT_6		6
+	#define FSMC_TWAIT_SHIFT	8
+	#define FSMC_TWAIT_MASK		0xFF
+	#define FSMC_THOLD_4		4
+	#define FSMC_THOLD_SHIFT	16
+	#define FSMC_THOLD_MASK		0xFF
+	#define FSMC_THIZ_1		1
+	#define FSMC_THIZ_SHIFT		24
+	#define FSMC_THIZ_MASK		0xFF
+#define ATTRIB			0x0C
+#define IOATA			0x10
+#define ECC1			0x14
+#define ECC2			0x18
+#define ECC3			0x1C
+#define FSMC_NAND_BANK_SZ	0x20
+
+#define FSMC_NAND_REG(base, bank, reg)		(base + FSMC_NOR_REG_SIZE + \
+						(FSMC_NAND_BANK_SZ * (bank)) + \
+						reg)
 
 #define FSMC_BUSY_WAIT_TIMEOUT	(1 * HZ)
 
-/* pc register definitions */
-#define FSMC_RESET		(1 << 0)
-#define FSMC_WAITON		(1 << 1)
-#define FSMC_ENABLE		(1 << 2)
-#define FSMC_DEVTYPE_NAND	(1 << 3)
-#define FSMC_DEVWID_8		(0 << 4)
-#define FSMC_DEVWID_16		(1 << 4)
-#define FSMC_ECCEN		(1 << 6)
-#define FSMC_ECCPLEN_512	(0 << 7)
-#define FSMC_ECCPLEN_256	(1 << 7)
-#define FSMC_TCLR_1		(1 << 9)
-#define FSMC_TAR_1		(1 << 13)
-
-/* sts register definitions */
-#define FSMC_CODE_RDY		(1 << 15)
-
-/* comm register definitions */
-#define FSMC_TSET_0		(0 << 0)
-#define FSMC_TWAIT_6		(6 << 8)
-#define FSMC_THOLD_4		(4 << 16)
-#define FSMC_THIZ_1		(1 << 24)
-
 /*
  * There are 13 bytes of ecc for every 512 byte block in FSMC version 8
  * and it has to be read consecutively and immediately after the 512
@@ -133,6 +121,20 @@
 	struct fsmc_nand_eccplace eccplace[MAX_ECCPLACE_ENTRIES];
 };
 
+struct fsmc_nand_timings {
+	uint8_t tclr;
+	uint8_t tar;
+	uint8_t thiz;
+	uint8_t thold;
+	uint8_t twait;
+	uint8_t tset;
+};
+
+enum access_mode {
+	USE_DMA_ACCESS = 1,
+	USE_WORD_ACCESS,
+};
+
 /**
  * fsmc_nand_platform_data - platform specific NAND controller config
  * @partitions: partition table for the platform, use a default fallback
@@ -146,12 +148,23 @@
  * this may be set to NULL
  */
 struct fsmc_nand_platform_data {
+	struct fsmc_nand_timings *nand_timings;
 	struct mtd_partition	*partitions;
 	unsigned int		nr_partitions;
 	unsigned int		options;
 	unsigned int		width;
 	unsigned int		bank;
+
+	/* CLE, ALE offsets */
+	unsigned int		cle_off;
+	unsigned int		ale_off;
+	enum access_mode	mode;
+
 	void			(*select_bank)(uint32_t bank, uint32_t busw);
+
+	/* priv structures for dma accesses */
+	void			*read_dma_priv;
+	void			*write_dma_priv;
 };
 
 extern int __init fsmc_nor_init(struct platform_device *pdev,
diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h
index 94e924e..3595a02 100644
--- a/include/linux/mtd/map.h
+++ b/include/linux/mtd/map.h
@@ -29,8 +29,8 @@
 #include <linux/kernel.h>
 
 #include <asm/unaligned.h>
-#include <asm/system.h>
 #include <asm/io.h>
+#include <asm/barrier.h>
 
 #ifdef CONFIG_MTD_MAP_BANK_WIDTH_1
 #define map_bankwidth(map) 1
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index d43dc25..cf5ea8c 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -164,6 +164,9 @@
 	/* ECC layout structure pointer - read only! */
 	struct nand_ecclayout *ecclayout;
 
+	/* max number of correctible bit errors per writesize */
+	unsigned int ecc_strength;
+
 	/* Data for variable erase regions. If numeraseregions is zero,
 	 * it means that the whole device has erasesize as given above.
 	 */
@@ -174,52 +177,52 @@
 	 * Do not call via these pointers, use corresponding mtd_*()
 	 * wrappers instead.
 	 */
-	int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
-	int (*point) (struct mtd_info *mtd, loff_t from, size_t len,
-		      size_t *retlen, void **virt, resource_size_t *phys);
-	void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
-	unsigned long (*get_unmapped_area) (struct mtd_info *mtd,
-					    unsigned long len,
-					    unsigned long offset,
-					    unsigned long flags);
-	int (*read) (struct mtd_info *mtd, loff_t from, size_t len,
-		     size_t *retlen, u_char *buf);
-	int (*write) (struct mtd_info *mtd, loff_t to, size_t len,
-		      size_t *retlen, const u_char *buf);
-	int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len,
-			    size_t *retlen, const u_char *buf);
-	int (*read_oob) (struct mtd_info *mtd, loff_t from,
-			 struct mtd_oob_ops *ops);
-	int (*write_oob) (struct mtd_info *mtd, loff_t to,
+	int (*_erase) (struct mtd_info *mtd, struct erase_info *instr);
+	int (*_point) (struct mtd_info *mtd, loff_t from, size_t len,
+		       size_t *retlen, void **virt, resource_size_t *phys);
+	int (*_unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
+	unsigned long (*_get_unmapped_area) (struct mtd_info *mtd,
+					     unsigned long len,
+					     unsigned long offset,
+					     unsigned long flags);
+	int (*_read) (struct mtd_info *mtd, loff_t from, size_t len,
+		      size_t *retlen, u_char *buf);
+	int (*_write) (struct mtd_info *mtd, loff_t to, size_t len,
+		       size_t *retlen, const u_char *buf);
+	int (*_panic_write) (struct mtd_info *mtd, loff_t to, size_t len,
+			     size_t *retlen, const u_char *buf);
+	int (*_read_oob) (struct mtd_info *mtd, loff_t from,
 			  struct mtd_oob_ops *ops);
-	int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
-				   size_t len);
-	int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from,
-				   size_t len, size_t *retlen, u_char *buf);
-	int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
-				   size_t len);
-	int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from,
-				   size_t len, size_t *retlen, u_char *buf);
-	int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t to, size_t len,
-				    size_t *retlen, u_char *buf);
-	int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from,
-				   size_t len);
-	int (*writev) (struct mtd_info *mtd, const struct kvec *vecs,
+	int (*_write_oob) (struct mtd_info *mtd, loff_t to,
+			   struct mtd_oob_ops *ops);
+	int (*_get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
+				    size_t len);
+	int (*_read_fact_prot_reg) (struct mtd_info *mtd, loff_t from,
+				    size_t len, size_t *retlen, u_char *buf);
+	int (*_get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
+				    size_t len);
+	int (*_read_user_prot_reg) (struct mtd_info *mtd, loff_t from,
+				    size_t len, size_t *retlen, u_char *buf);
+	int (*_write_user_prot_reg) (struct mtd_info *mtd, loff_t to,
+				     size_t len, size_t *retlen, u_char *buf);
+	int (*_lock_user_prot_reg) (struct mtd_info *mtd, loff_t from,
+				    size_t len);
+	int (*_writev) (struct mtd_info *mtd, const struct kvec *vecs,
 			unsigned long count, loff_t to, size_t *retlen);
-	void (*sync) (struct mtd_info *mtd);
-	int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
-	int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
-	int (*is_locked) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
-	int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
-	int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
-	int (*suspend) (struct mtd_info *mtd);
-	void (*resume) (struct mtd_info *mtd);
+	void (*_sync) (struct mtd_info *mtd);
+	int (*_lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
+	int (*_unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
+	int (*_is_locked) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
+	int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
+	int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
+	int (*_suspend) (struct mtd_info *mtd);
+	void (*_resume) (struct mtd_info *mtd);
 	/*
 	 * If the driver is something smart, like UBI, it may need to maintain
 	 * its own reference counting. The below functions are only for driver.
 	 */
-	int (*get_device) (struct mtd_info *mtd);
-	void (*put_device) (struct mtd_info *mtd);
+	int (*_get_device) (struct mtd_info *mtd);
+	void (*_put_device) (struct mtd_info *mtd);
 
 	/* Backing device capabilities for this device
 	 * - provides mmap capabilities
@@ -240,214 +243,75 @@
 	int usecount;
 };
 
-/*
- * Erase is an asynchronous operation.  Device drivers are supposed
- * to call instr->callback() whenever the operation completes, even
- * if it completes with a failure.
- * Callers are supposed to pass a callback function and wait for it
- * to be called before writing to the block.
- */
-static inline int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-	return mtd->erase(mtd, instr);
-}
-
-/*
- * This stuff for eXecute-In-Place. phys is optional and may be set to NULL.
- */
-static inline int mtd_point(struct mtd_info *mtd, loff_t from, size_t len,
-			    size_t *retlen, void **virt, resource_size_t *phys)
-{
-	*retlen = 0;
-	if (!mtd->point)
-		return -EOPNOTSUPP;
-	return mtd->point(mtd, from, len, retlen, virt, phys);
-}
-
-/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
-static inline void mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
-{
-	return mtd->unpoint(mtd, from, len);
-}
-
-/*
- * Allow NOMMU mmap() to directly map the device (if not NULL)
- * - return the address to which the offset maps
- * - return -ENOSYS to indicate refusal to do the mapping
- */
-static inline unsigned long mtd_get_unmapped_area(struct mtd_info *mtd,
-						  unsigned long len,
-						  unsigned long offset,
-						  unsigned long flags)
-{
-	if (!mtd->get_unmapped_area)
-		return -EOPNOTSUPP;
-	return mtd->get_unmapped_area(mtd, len, offset, flags);
-}
-
-static inline int mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
-			   size_t *retlen, u_char *buf)
-{
-	return mtd->read(mtd, from, len, retlen, buf);
-}
-
-static inline int mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
-			    size_t *retlen, const u_char *buf)
-{
-	*retlen = 0;
-	if (!mtd->write)
-		return -EROFS;
-	return mtd->write(mtd, to, len, retlen, buf);
-}
-
-/*
- * In blackbox flight recorder like scenarios we want to make successful writes
- * in interrupt context. panic_write() is only intended to be called when its
- * known the kernel is about to panic and we need the write to succeed. Since
- * the kernel is not going to be running for much longer, this function can
- * break locks and delay to ensure the write succeeds (but not sleep).
- */
-static inline int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
-				  size_t *retlen, const u_char *buf)
-{
-	*retlen = 0;
-	if (!mtd->panic_write)
-		return -EOPNOTSUPP;
-	return mtd->panic_write(mtd, to, len, retlen, buf);
-}
+int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
+int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
+	      void **virt, resource_size_t *phys);
+int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len);
+unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len,
+				    unsigned long offset, unsigned long flags);
+int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
+	     u_char *buf);
+int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
+	      const u_char *buf);
+int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
+		    const u_char *buf);
 
 static inline int mtd_read_oob(struct mtd_info *mtd, loff_t from,
 			       struct mtd_oob_ops *ops)
 {
 	ops->retlen = ops->oobretlen = 0;
-	if (!mtd->read_oob)
+	if (!mtd->_read_oob)
 		return -EOPNOTSUPP;
-	return mtd->read_oob(mtd, from, ops);
+	return mtd->_read_oob(mtd, from, ops);
 }
 
 static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to,
 				struct mtd_oob_ops *ops)
 {
 	ops->retlen = ops->oobretlen = 0;
-	if (!mtd->write_oob)
+	if (!mtd->_write_oob)
 		return -EOPNOTSUPP;
-	return mtd->write_oob(mtd, to, ops);
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	return mtd->_write_oob(mtd, to, ops);
 }
 
-/*
- * Method to access the protection register area, present in some flash
- * devices. The user data is one time programmable but the factory data is read
- * only.
- */
-static inline int mtd_get_fact_prot_info(struct mtd_info *mtd,
-					 struct otp_info *buf, size_t len)
-{
-	if (!mtd->get_fact_prot_info)
-		return -EOPNOTSUPP;
-	return mtd->get_fact_prot_info(mtd, buf, len);
-}
-
-static inline int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
-					 size_t len, size_t *retlen,
-					 u_char *buf)
-{
-	*retlen = 0;
-	if (!mtd->read_fact_prot_reg)
-		return -EOPNOTSUPP;
-	return mtd->read_fact_prot_reg(mtd, from, len, retlen, buf);
-}
-
-static inline int mtd_get_user_prot_info(struct mtd_info *mtd,
-					 struct otp_info *buf,
-					 size_t len)
-{
-	if (!mtd->get_user_prot_info)
-		return -EOPNOTSUPP;
-	return mtd->get_user_prot_info(mtd, buf, len);
-}
-
-static inline int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
-					 size_t len, size_t *retlen,
-					 u_char *buf)
-{
-	*retlen = 0;
-	if (!mtd->read_user_prot_reg)
-		return -EOPNOTSUPP;
-	return mtd->read_user_prot_reg(mtd, from, len, retlen, buf);
-}
-
-static inline int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to,
-					  size_t len, size_t *retlen,
-					  u_char *buf)
-{
-	*retlen = 0;
-	if (!mtd->write_user_prot_reg)
-		return -EOPNOTSUPP;
-	return mtd->write_user_prot_reg(mtd, to, len, retlen, buf);
-}
-
-static inline int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
-					 size_t len)
-{
-	if (!mtd->lock_user_prot_reg)
-		return -EOPNOTSUPP;
-	return mtd->lock_user_prot_reg(mtd, from, len);
-}
+int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
+			   size_t len);
+int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
+			   size_t *retlen, u_char *buf);
+int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf,
+			   size_t len);
+int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
+			   size_t *retlen, u_char *buf);
+int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
+			    size_t *retlen, u_char *buf);
+int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len);
 
 int mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
 	       unsigned long count, loff_t to, size_t *retlen);
 
 static inline void mtd_sync(struct mtd_info *mtd)
 {
-	if (mtd->sync)
-		mtd->sync(mtd);
+	if (mtd->_sync)
+		mtd->_sync(mtd);
 }
 
-/* Chip-supported device locking */
-static inline int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
-{
-	if (!mtd->lock)
-		return -EOPNOTSUPP;
-	return mtd->lock(mtd, ofs, len);
-}
-
-static inline int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
-{
-	if (!mtd->unlock)
-		return -EOPNOTSUPP;
-	return mtd->unlock(mtd, ofs, len);
-}
-
-static inline int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
-{
-	if (!mtd->is_locked)
-		return -EOPNOTSUPP;
-	return mtd->is_locked(mtd, ofs, len);
-}
+int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs);
+int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs);
 
 static inline int mtd_suspend(struct mtd_info *mtd)
 {
-	return mtd->suspend ? mtd->suspend(mtd) : 0;
+	return mtd->_suspend ? mtd->_suspend(mtd) : 0;
 }
 
 static inline void mtd_resume(struct mtd_info *mtd)
 {
-	if (mtd->resume)
-		mtd->resume(mtd);
-}
-
-static inline int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
-{
-	if (!mtd->block_isbad)
-		return 0;
-	return mtd->block_isbad(mtd, ofs);
-}
-
-static inline int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
-{
-	if (!mtd->block_markbad)
-		return -EOPNOTSUPP;
-	return mtd->block_markbad(mtd, ofs);
+	if (mtd->_resume)
+		mtd->_resume(mtd);
 }
 
 static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd)
@@ -482,12 +346,12 @@
 
 static inline int mtd_has_oob(const struct mtd_info *mtd)
 {
-	return mtd->read_oob && mtd->write_oob;
+	return mtd->_read_oob && mtd->_write_oob;
 }
 
 static inline int mtd_can_have_bb(const struct mtd_info *mtd)
 {
-	return !!mtd->block_isbad;
+	return !!mtd->_block_isbad;
 }
 
 	/* Kernel-side ioctl definitions */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 63b5a8b..1482340 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -324,6 +324,7 @@
  * @steps:	number of ECC steps per page
  * @size:	data bytes per ECC step
  * @bytes:	ECC bytes per step
+ * @strength:	max number of correctible bits per ECC step
  * @total:	total number of ECC bytes per page
  * @prepad:	padding information for syndrome based ECC generators
  * @postpad:	padding information for syndrome based ECC generators
@@ -351,6 +352,7 @@
 	int size;
 	int bytes;
 	int total;
+	int strength;
 	int prepad;
 	int postpad;
 	struct nand_ecclayout	*layout;
@@ -448,8 +450,9 @@
  *			will be copied to the appropriate nand_bbt_descr's.
  * @badblockpos:	[INTERN] position of the bad block marker in the oob
  *			area.
- * @badblockbits:	[INTERN] number of bits to left-shift the bad block
- *			number
+ * @badblockbits:	[INTERN] minimum number of set bits in a good block's
+ *			bad block marker position; i.e., BBM == 11110111b is
+ *			not bad when badblockbits == 7
  * @cellinfo:		[INTERN] MLC/multichip data from chip ident
  * @numchips:		[INTERN] number of physical chips
  * @chipsize:		[INTERN] the size of one chip for multichip arrays
diff --git a/include/linux/mtd/pmc551.h b/include/linux/mtd/pmc551.h
deleted file mode 100644
index 27ad40a..0000000
--- a/include/linux/mtd/pmc551.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * PMC551 PCI Mezzanine Ram Device
- *
- * Author:
- *       Mark Ferrell
- *       Copyright 1999,2000 Nortel Networks
- *
- * License:
- *	 As part of this driver was derrived from the slram.c driver it falls
- *	 under the same license, which is GNU General Public License v2
- */
-
-#ifndef __MTD_PMC551_H__
-#define __MTD_PMC551_H__
-
-#include <linux/mtd/mtd.h>
-
-#define PMC551_VERSION \
-       "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n"
-
-/*
- * Our personal and private information
- */
-struct mypriv {
-        struct pci_dev *dev;
-        u_char *start;
-        u32    base_map0;
-        u32    curr_map0;
-        u32    asize;
-	struct mtd_info *nextpmc551;
-};
-
-/*
- * Function Prototypes
- */
-static int pmc551_erase(struct mtd_info *, struct erase_info *);
-static void pmc551_unpoint(struct mtd_info *, loff_t, size_t);
-static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
-		size_t *retlen, void **virt, resource_size_t *phys);
-static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
-
-
-/*
- * Define the PCI ID's if the kernel doesn't define them for us
- */
-#ifndef PCI_VENDOR_ID_V3_SEMI
-#define PCI_VENDOR_ID_V3_SEMI             0x11b0
-#endif
-
-#ifndef PCI_DEVICE_ID_V3_SEMI_V370PDC
-#define PCI_DEVICE_ID_V3_SEMI_V370PDC     0x0200
-#endif
-
-
-#define PMC551_PCI_MEM_MAP0	0x50
-#define PMC551_PCI_MEM_MAP1	0x54
-#define PMC551_PCI_MEM_MAP_MAP_ADDR_MASK	0x3ff00000
-#define PMC551_PCI_MEM_MAP_APERTURE_MASK	0x000000f0
-#define PMC551_PCI_MEM_MAP_REG_EN		0x00000002
-#define PMC551_PCI_MEM_MAP_ENABLE		0x00000001
-
-#define PMC551_SDRAM_MA		0x60
-#define PMC551_SDRAM_CMD	0x62
-#define PMC551_DRAM_CFG		0x64
-#define PMC551_SYS_CTRL_REG	0x78
-
-#define PMC551_DRAM_BLK0	0x68
-#define PMC551_DRAM_BLK1	0x6c
-#define PMC551_DRAM_BLK2	0x70
-#define PMC551_DRAM_BLK3	0x74
-#define PMC551_DRAM_BLK_GET_SIZE(x) (524288<<((x>>4)&0x0f))
-#define PMC551_DRAM_BLK_SET_COL_MUX(x,v) (((x) & ~0x00007000) | (((v) & 0x7) << 12))
-#define PMC551_DRAM_BLK_SET_ROW_MUX(x,v) (((x) & ~0x00000f00) | (((v) & 0xf) << 8))
-
-
-#endif /* __MTD_PMC551_H__ */
-
diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h
index 9cf4c4c..a38e1fa 100644
--- a/include/linux/mtd/sh_flctl.h
+++ b/include/linux/mtd/sh_flctl.h
@@ -23,6 +23,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/pm_qos.h>
 
 /* FLCTL registers */
 #define FLCMNCR(f)		(f->reg + 0x0)
@@ -38,6 +39,7 @@
 #define FLDTFIFO(f)		(f->reg + 0x24)
 #define FLECFIFO(f)		(f->reg + 0x28)
 #define FLTRCR(f)		(f->reg + 0x2C)
+#define FLHOLDCR(f)		(f->reg + 0x38)
 #define	FL4ECCRESULT0(f)	(f->reg + 0x80)
 #define	FL4ECCRESULT1(f)	(f->reg + 0x84)
 #define	FL4ECCRESULT2(f)	(f->reg + 0x88)
@@ -67,6 +69,30 @@
 #define	CE0_ENABLE	(0x1 << 3)	/* Chip Enable 0 */
 #define	TYPESEL_SET	(0x1 << 0)
 
+/*
+ * Clock settings using the PULSEx registers from FLCMNCR
+ *
+ * Some hardware uses bits called PULSEx instead of FCKSEL_E and QTSEL_E
+ * to control the clock divider used between the High-Speed Peripheral Clock
+ * and the FLCTL internal clock. If so, use CLK_8_BIT_xxx for connecting 8 bit
+ * and CLK_16_BIT_xxx for connecting 16 bit bus bandwith NAND chips. For the 16
+ * bit version the divider is seperate for the pulse width of high and low
+ * signals.
+ */
+#define PULSE3	(0x1 << 27)
+#define PULSE2	(0x1 << 17)
+#define PULSE1	(0x1 << 15)
+#define PULSE0	(0x1 << 9)
+#define CLK_8B_0_5			PULSE1
+#define CLK_8B_1			0x0
+#define CLK_8B_1_5			(PULSE1 | PULSE2)
+#define CLK_8B_2			PULSE0
+#define CLK_8B_3			(PULSE0 | PULSE1 | PULSE2)
+#define CLK_8B_4			(PULSE0 | PULSE2)
+#define CLK_16B_6L_2H			PULSE0
+#define CLK_16B_9L_3H			(PULSE0 | PULSE1 | PULSE2)
+#define CLK_16B_12L_4H			(PULSE0 | PULSE2)
+
 /* FLCMDCR control bits */
 #define ADRCNT2_E	(0x1 << 31)	/* 5byte address enable */
 #define ADRMD_E		(0x1 << 26)	/* Sector address access */
@@ -85,6 +111,15 @@
 #define TRSTRT		(0x1 << 0)	/* translation start */
 #define TREND		(0x1 << 1)	/* translation end */
 
+/*
+ * FLHOLDCR control bits
+ *
+ * HOLDEN: Bus Occupancy Enable (inverted)
+ * Enable this bit when the external bus might be used in between transfers.
+ * If not set and the bus gets used by other modules, a deadlock occurs.
+ */
+#define HOLDEN		(0x1 << 0)
+
 /* FL4ECCCR control bits */
 #define	_4ECCFA		(0x1 << 2)	/* 4 symbols correct fault */
 #define	_4ECCEND	(0x1 << 1)	/* 4 symbols end */
@@ -97,6 +132,7 @@
 	struct mtd_info		mtd;
 	struct nand_chip	chip;
 	struct platform_device	*pdev;
+	struct dev_pm_qos_request pm_qos;
 	void __iomem		*reg;
 
 	uint8_t	done_buff[2048 + 64];	/* max size 2048 + 64 */
@@ -108,11 +144,14 @@
 	int	erase1_page_addr;	/* page_addr in ERASE1 cmd */
 	uint32_t erase_ADRCNT;		/* bits of FLCMDCR in ERASE1 cmd */
 	uint32_t rw_ADRCNT;	/* bits of FLCMDCR in READ WRITE cmd */
+	uint32_t flcmncr_base;	/* base value of FLCMNCR */
 
 	int	hwecc_cant_correct[4];
 
 	unsigned page_size:1;	/* NAND page size (0 = 512, 1 = 2048) */
 	unsigned hwecc:1;	/* Hardware ECC (0 = disabled, 1 = enabled) */
+	unsigned holden:1;	/* Hardware has FLHOLDCR and HOLDEN is set */
+	unsigned qos_request:1;	/* QoS request to prevent deep power shutdown */
 };
 
 struct sh_flctl_platform_data {
@@ -121,6 +160,7 @@
 	unsigned long		flcmncr_val;
 
 	unsigned has_hwecc:1;
+	unsigned use_holden:1;
 };
 
 static inline struct sh_flctl *mtd_to_flctl(struct mtd_info *mtdinfo)
diff --git a/include/linux/mtd/spear_smi.h b/include/linux/mtd/spear_smi.h
new file mode 100644
index 0000000..8ae1726
--- /dev/null
+++ b/include/linux/mtd/spear_smi.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2010 ST Microelectronics
+ * Shiraz Hashim <shiraz.hashim@st.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.
+ */
+
+#ifndef __MTD_SPEAR_SMI_H
+#define __MTD_SPEAR_SMI_H
+
+#include <linux/types.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+/* max possible slots for serial-nor flash chip in the SMI controller */
+#define MAX_NUM_FLASH_CHIP	4
+
+/* macro to define partitions for flash devices */
+#define DEFINE_PARTS(n, of, s)		\
+{					\
+	.name = n,			\
+	.offset = of,			\
+	.size = s,			\
+}
+
+/**
+ * struct spear_smi_flash_info - platform structure for passing flash
+ * information
+ *
+ * name: name of the serial nor flash for identification
+ * mem_base: the memory base on which the flash is mapped
+ * size: size of the flash in bytes
+ * partitions: parition details
+ * nr_partitions: number of partitions
+ * fast_mode: whether flash supports fast mode
+ */
+
+struct spear_smi_flash_info {
+	char *name;
+	unsigned long mem_base;
+	unsigned long size;
+	struct mtd_partition *partitions;
+	int nr_partitions;
+	u8 fast_mode;
+};
+
+/**
+ * struct spear_smi_plat_data - platform structure for configuring smi
+ *
+ * clk_rate: clk rate at which SMI must operate
+ * num_flashes: number of flashes present on board
+ * board_flash_info: specific details of each flash present on board
+ */
+struct spear_smi_plat_data {
+	unsigned long clk_rate;
+	int num_flashes;
+	struct spear_smi_flash_info *board_flash_info;
+	struct device_node *np[MAX_NUM_FLASH_CHIP];
+};
+
+#endif /* __MTD_SPEAR_SMI_H */
diff --git a/include/linux/mtio.h b/include/linux/mtio.h
index 8f82575..18543e2 100644
--- a/include/linux/mtio.h
+++ b/include/linux/mtio.h
@@ -194,6 +194,7 @@
 #define MT_ST_SYSV              0x1000
 #define MT_ST_NOWAIT            0x2000
 #define MT_ST_SILI		0x4000
+#define MT_ST_NOWAIT_EOF	0x8000
 
 /* The mode parameters to be controlled. Parameter chosen with bits 20-28 */
 #define MT_ST_CLEAR_DEFAULT	0xfffff
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 8debe29..5cbaa20 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -33,12 +33,12 @@
 #ifdef __KERNEL__
 #include <linux/pm_qos.h>
 #include <linux/timer.h>
+#include <linux/bug.h>
 #include <linux/delay.h>
 #include <linux/atomic.h>
 #include <asm/cache.h>
 #include <asm/byteorder.h>
 
-#include <linux/device.h>
 #include <linux/percpu.h>
 #include <linux/rculist.h>
 #include <linux/dmaengine.h>
@@ -56,6 +56,7 @@
 #include <linux/netdev_features.h>
 
 struct netpoll_info;
+struct device;
 struct phy_device;
 /* 802.11 specific */
 struct wireless_dev;
@@ -2603,8 +2604,6 @@
 extern void *dev_seq_start(struct seq_file *seq, loff_t *pos);
 extern void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos);
 extern void dev_seq_stop(struct seq_file *seq, void *v);
-extern int dev_seq_open_ops(struct inode *inode, struct file *file,
-			    const struct seq_operations *ops);
 #endif
 
 extern int netdev_class_create_file(struct class_attribute *class_attr);
diff --git a/include/linux/netfilter/xt_set.h b/include/linux/netfilter/xt_set.h
index c0405ac..e3a9978 100644
--- a/include/linux/netfilter/xt_set.h
+++ b/include/linux/netfilter/xt_set.h
@@ -58,8 +58,8 @@
 struct xt_set_info_target_v2 {
 	struct xt_set_info add_set;
 	struct xt_set_info del_set;
-	u32 flags;
-	u32 timeout;
+	__u32 flags;
+	__u32 timeout;
 };
 
 #endif /*_XT_SET_H*/
diff --git a/include/linux/nfs.h b/include/linux/nfs.h
index 8c6ee44..6d1fb63 100644
--- a/include/linux/nfs.h
+++ b/include/linux/nfs.h
@@ -29,7 +29,7 @@
 #define NFS_MNT_VERSION		1
 #define NFS_MNT3_VERSION	3
 
-#define NFS_PIPE_DIRNAME "/nfs"
+#define NFS_PIPE_DIRNAME "nfs"
 
 /*
  * NFS stats. The good thing with these values is that NFSv3 errors are
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 32345c2..0987146 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -183,15 +183,12 @@
 
 typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
 
-struct nfs41_stateid {
+struct nfs_stateid4 {
 	__be32 seqid;
 	char other[NFS4_STATEID_OTHER_SIZE];
 } __attribute__ ((packed));
 
-typedef union {
-	char data[NFS4_STATEID_SIZE];
-	struct nfs41_stateid stateid;
-} nfs4_stateid;
+typedef struct nfs_stateid4 nfs4_stateid;
 
 enum nfs_opnum4 {
 	OP_ACCESS = 3,
@@ -441,7 +438,20 @@
 enum open_delegation_type4 {
 	NFS4_OPEN_DELEGATE_NONE = 0,
 	NFS4_OPEN_DELEGATE_READ = 1,
-	NFS4_OPEN_DELEGATE_WRITE = 2
+	NFS4_OPEN_DELEGATE_WRITE = 2,
+	NFS4_OPEN_DELEGATE_NONE_EXT = 3, /* 4.1 */
+};
+
+enum why_no_delegation4 { /* new to v4.1 */
+	WND4_NOT_WANTED = 0,
+	WND4_CONTENTION = 1,
+	WND4_RESOURCE = 2,
+	WND4_NOT_SUPP_FTYPE = 3,
+	WND4_WRITE_DELEG_NOT_SUPP_FTYPE = 4,
+	WND4_NOT_SUPP_UPGRADE = 5,
+	WND4_NOT_SUPP_DOWNGRADE = 6,
+	WND4_CANCELLED = 7,
+	WND4_IS_DIR = 8,
 };
 
 enum lock_type4 {
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 8c29950..52a1bdb 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -38,6 +38,13 @@
 
 #ifdef __KERNEL__
 
+/*
+ * Enable dprintk() debugging support for nfs client.
+ */
+#ifdef CONFIG_NFS_DEBUG
+# define NFS_DEBUG
+#endif
+
 #include <linux/in.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
@@ -171,13 +178,9 @@
 	 */
 	__be32			cookieverf[2];
 
-	/*
-	 * This is the list of dirty unwritten pages.
-	 */
-	struct radix_tree_root	nfs_page_tree;
-
 	unsigned long		npages;
 	unsigned long		ncommit;
+	struct list_head	commit_list;
 
 	/* Open contexts for shared mmap writes */
 	struct list_head	open_files;
@@ -395,6 +398,29 @@
 	kfree(fh);
 }
 
+#ifdef NFS_DEBUG
+extern u32 _nfs_display_fhandle_hash(const struct nfs_fh *fh);
+static inline u32 nfs_display_fhandle_hash(const struct nfs_fh *fh)
+{
+	return _nfs_display_fhandle_hash(fh);
+}
+extern void _nfs_display_fhandle(const struct nfs_fh *fh, const char *caption);
+#define nfs_display_fhandle(fh, caption)			\
+	do {							\
+		if (unlikely(nfs_debug & NFSDBG_FACILITY))	\
+			_nfs_display_fhandle(fh, caption);	\
+	} while (0)
+#else
+static inline u32 nfs_display_fhandle_hash(const struct nfs_fh *fh)
+{
+	return 0;
+}
+static inline void nfs_display_fhandle(const struct nfs_fh *fh,
+				       const char *caption)
+{
+}
+#endif
+
 /*
  * linux/fs/nfs/nfsroot.c
  */
@@ -632,19 +658,13 @@
 
 #ifdef __KERNEL__
 
-/*
- * Enable debugging support for nfs client.
- * Requires RPC_DEBUG.
- */
-#ifdef RPC_DEBUG
-# define NFS_DEBUG
-#endif
-
 # undef ifdebug
 # ifdef NFS_DEBUG
 #  define ifdebug(fac)		if (unlikely(nfs_debug & NFSDBG_##fac))
+#  define NFS_IFDEBUG(x)	x
 # else
 #  define ifdebug(fac)		if (0)
+#  define NFS_IFDEBUG(x)
 # endif
 #endif /* __KERNEL */
 
diff --git a/include/linux/nfs_fs_i.h b/include/linux/nfs_fs_i.h
index 8617302..a5c50d9 100644
--- a/include/linux/nfs_fs_i.h
+++ b/include/linux/nfs_fs_i.h
@@ -1,10 +1,6 @@
 #ifndef _NFS_FS_I
 #define _NFS_FS_I
 
-#include <asm/types.h>
-#include <linux/list.h>
-#include <linux/nfs.h>
-
 struct nlm_lockowner;
 
 /*
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index ba4d765..7073fc7 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -3,6 +3,7 @@
 
 #include <linux/list.h>
 #include <linux/backing-dev.h>
+#include <linux/idr.h>
 #include <linux/wait.h>
 #include <linux/nfs_xdr.h>
 #include <linux/sunrpc/xprt.h>
@@ -17,6 +18,7 @@
 struct nfs_server;
 struct nfs4_minor_version_ops;
 struct server_scope;
+struct nfs41_impl_id;
 
 /*
  * The nfs_client identifies our client state to the server.
@@ -85,6 +87,8 @@
 #endif
 
 	struct server_scope	*server_scope;	/* from exchange_id */
+	struct nfs41_impl_id	*impl_id;	/* from exchange_id */
+	struct net		*net;
 };
 
 /*
@@ -144,15 +148,18 @@
 	u32			acl_bitmask;	/* V4 bitmask representing the ACEs
 						   that are supported on this
 						   filesystem */
+	u32			fh_expire_type;	/* V4 bitmask representing file
+						   handle volatility type for
+						   this filesystem */
 	struct pnfs_layoutdriver_type  *pnfs_curr_ld; /* Active layout driver */
 	struct rpc_wait_queue	roc_rpcwaitq;
 	void			*pnfs_ld_data;	/* per mount point data */
 
 	/* the following fields are protected by nfs_client->cl_lock */
 	struct rb_root		state_owners;
-	struct rb_root		openowner_id;
-	struct rb_root		lockowner_id;
 #endif
+	struct ida		openowner_id;
+	struct ida		lockowner_id;
 	struct list_head	state_owners_lru;
 	struct list_head	layouts;
 	struct list_head	delegations;
@@ -188,21 +195,23 @@
 
 
 /* maximum number of slots to use */
-#define NFS4_MAX_SLOT_TABLE RPC_MAX_SLOT_TABLE
+#define NFS4_DEF_SLOT_TABLE_SIZE (16U)
+#define NFS4_MAX_SLOT_TABLE (256U)
+#define NFS4_NO_SLOT ((u32)-1)
 
 #if defined(CONFIG_NFS_V4)
 
 /* Sessions */
-#define SLOT_TABLE_SZ (NFS4_MAX_SLOT_TABLE/(8*sizeof(long)))
+#define SLOT_TABLE_SZ DIV_ROUND_UP(NFS4_MAX_SLOT_TABLE, 8*sizeof(long))
 struct nfs4_slot_table {
 	struct nfs4_slot *slots;		/* seqid per slot */
 	unsigned long   used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */
 	spinlock_t	slot_tbl_lock;
 	struct rpc_wait_queue	slot_tbl_waitq;	/* allocators may wait here */
-	int		max_slots;		/* # slots in table */
-	int		highest_used_slotid;	/* sent to server on each SEQ.
+	u32		max_slots;		/* # slots in table */
+	u32		highest_used_slotid;	/* sent to server on each SEQ.
 						 * op for dynamic resizing */
-	int		target_max_slots;	/* Set by CB_RECALL_SLOT as
+	u32		target_max_slots;	/* Set by CB_RECALL_SLOT as
 						 * the new max_slots */
 	struct completion complete;
 };
diff --git a/include/linux/nfs_idmap.h b/include/linux/nfs_idmap.h
index 308c188..7eed201 100644
--- a/include/linux/nfs_idmap.h
+++ b/include/linux/nfs_idmap.h
@@ -69,36 +69,22 @@
 struct nfs_fattr;
 struct nfs4_string;
 
-#ifdef CONFIG_NFS_USE_NEW_IDMAPPER
-
+#ifdef CONFIG_NFS_V4
 int nfs_idmap_init(void);
 void nfs_idmap_quit(void);
-
-static inline int nfs_idmap_new(struct nfs_client *clp)
-{
-	return 0;
-}
-
-static inline void nfs_idmap_delete(struct nfs_client *clp)
-{
-}
-
-#else /* CONFIG_NFS_USE_NEW_IDMAPPER not set */
-
+#else
 static inline int nfs_idmap_init(void)
 {
 	return 0;
 }
 
 static inline void nfs_idmap_quit(void)
-{
-}
+{}
+#endif
 
 int nfs_idmap_new(struct nfs_client *);
 void nfs_idmap_delete(struct nfs_client *);
 
-#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
-
 void nfs_fattr_init_names(struct nfs_fattr *fattr,
 		struct nfs4_string *owner_name,
 		struct nfs4_string *group_name);
diff --git a/include/linux/nfs_iostat.h b/include/linux/nfs_iostat.h
index 8866bb3..9dcbbe9 100644
--- a/include/linux/nfs_iostat.h
+++ b/include/linux/nfs_iostat.h
@@ -21,7 +21,7 @@
 #ifndef _LINUX_NFS_IOSTAT
 #define _LINUX_NFS_IOSTAT
 
-#define NFS_IOSTAT_VERS		"1.0"
+#define NFS_IOSTAT_VERS		"1.1"
 
 /*
  * NFS byte counters
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index ab465fe..eac30d6 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -19,12 +19,6 @@
 #include <linux/kref.h>
 
 /*
- * Valid flags for the radix tree
- */
-#define NFS_PAGE_TAG_LOCKED	0
-#define NFS_PAGE_TAG_COMMIT	1
-
-/*
  * Valid flags for a dirty buffer
  */
 enum {
@@ -33,16 +27,13 @@
 	PG_CLEAN,
 	PG_NEED_COMMIT,
 	PG_NEED_RESCHED,
-	PG_PNFS_COMMIT,
 	PG_PARTIAL_READ_FAILED,
+	PG_COMMIT_TO_DS,
 };
 
 struct nfs_inode;
 struct nfs_page {
-	union {
-		struct list_head	wb_list;	/* Defines state of page: */
-		struct pnfs_layout_segment *wb_commit_lseg; /* Used when PG_PNFS_COMMIT set */
-	};
+	struct list_head	wb_list;	/* Defines state of page: */
 	struct page		*wb_page;	/* page to read in/write out */
 	struct nfs_open_context	*wb_context;	/* File state context info */
 	struct nfs_lock_context	*wb_lock_context;	/* lock context info */
@@ -90,8 +81,6 @@
 extern	void nfs_release_request(struct nfs_page *req);
 
 
-extern	int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *dst,
-			  pgoff_t idx_start, unsigned int npages, int tag);
 extern	void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
 			     struct inode *inode,
 			     const struct nfs_pageio_ops *pg_ops,
@@ -106,8 +95,6 @@
 				struct nfs_page *req);
 extern  int nfs_wait_on_request(struct nfs_page *);
 extern	void nfs_unlock_request(struct nfs_page *req);
-extern	int nfs_set_page_tag_locked(struct nfs_page *req);
-extern  void nfs_clear_page_tag_locked(struct nfs_page *req);
 
 /*
  * Lock the page of an asynchronous request without getting a new reference
@@ -118,6 +105,16 @@
 	return !test_and_set_bit(PG_BUSY, &req->wb_flags);
 }
 
+static inline int
+nfs_lock_request(struct nfs_page *req)
+{
+	if (test_and_set_bit(PG_BUSY, &req->wb_flags))
+		return 0;
+	kref_get(&req->wb_kref);
+	return 1;
+}
+
+
 /**
  * nfs_list_add_request - Insert a request into a list
  * @req: request
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index d6ba9a1..bfd0d1b 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -2,7 +2,6 @@
 #define _LINUX_NFS_XDR_H
 
 #include <linux/nfsacl.h>
-#include <linux/nfs3.h>
 #include <linux/sunrpc/gss_api.h>
 
 /*
@@ -89,11 +88,12 @@
 #define NFS_ATTR_FATTR_PRECTIME		(1U << 16)
 #define NFS_ATTR_FATTR_CHANGE		(1U << 17)
 #define NFS_ATTR_FATTR_PRECHANGE	(1U << 18)
-#define NFS_ATTR_FATTR_V4_REFERRAL	(1U << 19)	/* NFSv4 referral */
-#define NFS_ATTR_FATTR_MOUNTPOINT	(1U << 20)	/* Treat as mountpoint */
-#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID		(1U << 21)
-#define NFS_ATTR_FATTR_OWNER_NAME	(1U << 22)
-#define NFS_ATTR_FATTR_GROUP_NAME	(1U << 23)
+#define NFS_ATTR_FATTR_V4_LOCATIONS	(1U << 19)
+#define NFS_ATTR_FATTR_V4_REFERRAL	(1U << 20)
+#define NFS_ATTR_FATTR_MOUNTPOINT	(1U << 21)
+#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 22)
+#define NFS_ATTR_FATTR_OWNER_NAME	(1U << 23)
+#define NFS_ATTR_FATTR_GROUP_NAME	(1U << 24)
 
 #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
 		| NFS_ATTR_FATTR_MODE \
@@ -182,7 +182,7 @@
 
 struct nfs4_sequence_args {
 	struct nfs4_session	*sa_session;
-	u8			sa_slotid;
+	u32			sa_slotid;
 	u8			sa_cache_this;
 };
 
@@ -977,6 +977,7 @@
 	u32				acl_bitmask;
 	u32				has_links;
 	u32				has_symlinks;
+	u32				fh_expire_type;
 	struct nfs4_sequence_res	seq_res;
 };
 
@@ -1055,14 +1056,6 @@
 };
 
 #ifdef CONFIG_NFS_V4_1
-struct nfs_impl_id4 {
-	u32		domain_len;
-	char		*domain;
-	u32		name_len;
-	char		*name;
-	struct nfstime4	date;
-};
-
 #define NFS4_EXCHANGE_ID_LEN	(48)
 struct nfs41_exchange_id_args {
 	struct nfs_client		*client;
@@ -1083,10 +1076,17 @@
 	char 				server_scope[NFS4_OPAQUE_LIMIT];
 };
 
+struct nfs41_impl_id {
+	char				domain[NFS4_OPAQUE_LIMIT + 1];
+	char				name[NFS4_OPAQUE_LIMIT + 1];
+	struct nfstime4			date;
+};
+
 struct nfs41_exchange_id_res {
 	struct nfs_client		*client;
 	u32				flags;
 	struct server_scope		*server_scope;
+	struct nfs41_impl_id		*impl_id;
 };
 
 struct nfs41_create_session_args {
@@ -1192,6 +1192,27 @@
 	struct page		*page_array[NFS_PAGEVEC_SIZE];
 };
 
+struct nfs_unlinkdata {
+	struct hlist_node list;
+	struct nfs_removeargs args;
+	struct nfs_removeres res;
+	struct inode *dir;
+	struct rpc_cred	*cred;
+	struct nfs_fattr dir_attr;
+};
+
+struct nfs_renamedata {
+	struct nfs_renameargs	args;
+	struct nfs_renameres	res;
+	struct rpc_cred		*cred;
+	struct inode		*old_dir;
+	struct dentry		*old_dentry;
+	struct nfs_fattr	old_fattr;
+	struct inode		*new_dir;
+	struct dentry		*new_dentry;
+	struct nfs_fattr	new_fattr;
+};
+
 struct nfs_access_entry;
 struct nfs_client;
 struct rpc_timeout;
@@ -1221,10 +1242,12 @@
 			    struct iattr *, int, struct nfs_open_context *);
 	int	(*remove)  (struct inode *, struct qstr *);
 	void	(*unlink_setup)  (struct rpc_message *, struct inode *dir);
+	void	(*unlink_rpc_prepare) (struct rpc_task *, struct nfs_unlinkdata *);
 	int	(*unlink_done) (struct rpc_task *, struct inode *);
 	int	(*rename)  (struct inode *, struct qstr *,
 			    struct inode *, struct qstr *);
 	void	(*rename_setup)  (struct rpc_message *msg, struct inode *dir);
+	void	(*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *);
 	int	(*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir);
 	int	(*link)    (struct inode *, struct inode *, struct qstr *);
 	int	(*symlink) (struct inode *, struct dentry *, struct page *,
@@ -1244,8 +1267,10 @@
 	int	(*set_capabilities)(struct nfs_server *, struct nfs_fh *);
 	int	(*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int);
 	void	(*read_setup)   (struct nfs_read_data *, struct rpc_message *);
+	void	(*read_rpc_prepare)(struct rpc_task *, struct nfs_read_data *);
 	int	(*read_done)  (struct rpc_task *, struct nfs_read_data *);
 	void	(*write_setup)  (struct nfs_write_data *, struct rpc_message *);
+	void	(*write_rpc_prepare)(struct rpc_task *, struct nfs_write_data *);
 	int	(*write_done)  (struct rpc_task *, struct nfs_write_data *);
 	void	(*commit_setup) (struct nfs_write_data *, struct rpc_message *);
 	int	(*commit_done) (struct rpc_task *, struct nfs_write_data *);
@@ -1275,11 +1300,11 @@
 extern const struct nfs_rpc_ops	nfs_v2_clientops;
 extern const struct nfs_rpc_ops	nfs_v3_clientops;
 extern const struct nfs_rpc_ops	nfs_v4_clientops;
-extern struct rpc_version	nfs_version2;
-extern struct rpc_version	nfs_version3;
-extern struct rpc_version	nfs_version4;
+extern const struct rpc_version nfs_version2;
+extern const struct rpc_version nfs_version3;
+extern const struct rpc_version nfs_version4;
 
-extern struct rpc_version	nfsacl_version3;
-extern struct rpc_program	nfsacl_program;
+extern const struct rpc_version nfsacl_version3;
+extern const struct rpc_program nfsacl_program;
 
 #endif
diff --git a/include/linux/nfsd/cld.h b/include/linux/nfsd/cld.h
new file mode 100644
index 0000000..f14a9ab
--- /dev/null
+++ b/include/linux/nfsd/cld.h
@@ -0,0 +1,56 @@
+/*
+ * Upcall description for nfsdcld communication
+ *
+ * Copyright (c) 2012 Red Hat, Inc.
+ * Author(s): Jeff Layton <jlayton@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _NFSD_CLD_H
+#define _NFSD_CLD_H
+
+/* latest upcall version available */
+#define CLD_UPCALL_VERSION 1
+
+/* defined by RFC3530 */
+#define NFS4_OPAQUE_LIMIT 1024
+
+enum cld_command {
+	Cld_Create,		/* create a record for this cm_id */
+	Cld_Remove,		/* remove record of this cm_id */
+	Cld_Check,		/* is this cm_id allowed? */
+	Cld_GraceDone,		/* grace period is complete */
+};
+
+/* representation of long-form NFSv4 client ID */
+struct cld_name {
+	uint16_t	cn_len;				/* length of cm_id */
+	unsigned char	cn_id[NFS4_OPAQUE_LIMIT];	/* client-provided */
+} __attribute__((packed));
+
+/* message struct for communication with userspace */
+struct cld_msg {
+	uint8_t		cm_vers;		/* upcall version */
+	uint8_t		cm_cmd;			/* upcall command */
+	int16_t		cm_status;		/* return code */
+	uint32_t	cm_xid;			/* transaction id */
+	union {
+		int64_t		cm_gracetime;	/* grace period start time */
+		struct cld_name	cm_name;
+	} __attribute__((packed)) cm_u;
+} __attribute__((packed));
+
+#endif /* !_NFSD_CLD_H */
diff --git a/include/linux/nilfs2_fs.h b/include/linux/nilfs2_fs.h
index 7454ad7..89bd4a4 100644
--- a/include/linux/nilfs2_fs.h
+++ b/include/linux/nilfs2_fs.h
@@ -41,6 +41,7 @@
 #include <linux/types.h>
 #include <linux/ioctl.h>
 #include <linux/magic.h>
+#include <linux/bug.h>
 
 
 #define NILFS_INODE_BMAP_SIZE	7
diff --git a/include/linux/nmi.h b/include/linux/nmi.h
index 2d304ef..db50840 100644
--- a/include/linux/nmi.h
+++ b/include/linux/nmi.h
@@ -14,7 +14,7 @@
  * may be used to reset the timeout - for code which intentionally
  * disables interrupts for a long time. This call is stateless.
  */
-#if defined(ARCH_HAS_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
+#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
 #include <asm/nmi.h>
 extern void touch_nmi_watchdog(void);
 #else
diff --git a/include/linux/of.h b/include/linux/of.h
index f02d8b2..fa7fb1d 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -351,6 +351,22 @@
 #define of_match_node(_matches, _node)	NULL
 #endif /* CONFIG_OF */
 
+/**
+ * of_property_read_bool - Findfrom a property
+ * @np:		device node from which the property value is to be read.
+ * @propname:	name of the property to be searched.
+ *
+ * Search for a property in a device node.
+ * Returns true if the property exist false otherwise.
+ */
+static inline bool of_property_read_bool(const struct device_node *np,
+					 const char *propname)
+{
+	struct property *prop = of_find_property(np, propname, NULL);
+
+	return prop ? true : false;
+}
+
 static inline int of_property_read_u32(const struct device_node *np,
 				       const char *propname,
 				       u32 *out_value)
diff --git a/include/linux/of_device.h b/include/linux/of_device.h
index cbc4214..901b743 100644
--- a/include/linux/of_device.h
+++ b/include/linux/of_device.h
@@ -5,10 +5,11 @@
 #include <linux/of_platform.h> /* temporary until merge */
 
 #ifdef CONFIG_OF_DEVICE
-#include <linux/device.h>
 #include <linux/of.h>
 #include <linux/mod_devicetable.h>
 
+struct device;
+
 extern const struct of_device_id *of_match_device(
 	const struct of_device_id *matches, const struct device *dev);
 extern void of_device_make_bus_id(struct device *dev);
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index b254052..81733d1 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -50,7 +50,8 @@
 extern int of_get_named_gpio_flags(struct device_node *np,
 		const char *list_name, int index, enum of_gpio_flags *flags);
 
-extern unsigned int of_gpio_count(struct device_node *np);
+extern unsigned int of_gpio_named_count(struct device_node *np,
+					const char* propname);
 
 extern int of_mm_gpiochip_add(struct device_node *np,
 			      struct of_mm_gpio_chip *mm_gc);
@@ -71,7 +72,8 @@
 	return -ENOSYS;
 }
 
-static inline unsigned int of_gpio_count(struct device_node *np)
+static inline unsigned int of_gpio_named_count(struct device_node *np,
+					const char* propname)
 {
 	return 0;
 }
@@ -89,6 +91,27 @@
 #endif /* CONFIG_OF_GPIO */
 
 /**
+ * of_gpio_count - Count GPIOs for a device
+ * @np:		device node to count GPIOs for
+ *
+ * The function returns the count of GPIOs specified for a node.
+ *
+ * Note that the empty GPIO specifiers counts too. For example,
+ *
+ * gpios = <0
+ *          &pio1 1 2
+ *          0
+ *          &pio2 3 4>;
+ *
+ * defines four GPIOs (so this function will return 4), two of which
+ * are not specified.
+ */
+static inline unsigned int of_gpio_count(struct device_node *np)
+{
+	return of_gpio_named_count(np, "gpios");
+}
+
+/**
  * of_get_gpio_flags() - Get a GPIO number and flags to use with GPIO API
  * @np:		device node to get GPIO from
  * @index:	index of the GPIO
diff --git a/include/linux/of_mtd.h b/include/linux/of_mtd.h
new file mode 100644
index 0000000..bae1b60
--- /dev/null
+++ b/include/linux/of_mtd.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * OF helpers for mtd.
+ *
+ * This file is released under the GPLv2
+ */
+
+#ifndef __LINUX_OF_MTD_H
+#define __LINUX_OF_NET_H
+
+#ifdef CONFIG_OF_MTD
+#include <linux/of.h>
+extern const int of_get_nand_ecc_mode(struct device_node *np);
+int of_get_nand_bus_width(struct device_node *np);
+bool of_get_nand_on_flash_bbt(struct device_node *np);
+#endif
+
+#endif /* __LINUX_OF_MTD_H */
diff --git a/include/linux/omapfb.h b/include/linux/omapfb.h
index c0b0187..4ff57e8 100644
--- a/include/linux/omapfb.h
+++ b/include/linux/omapfb.h
@@ -222,41 +222,11 @@
 
 #include <plat/board.h>
 
-#ifdef CONFIG_ARCH_OMAP1
-#define OMAPFB_PLANE_NUM		1
-#else
-#define OMAPFB_PLANE_NUM		3
-#endif
-
-struct omapfb_mem_region {
-	u32		paddr;
-	void __iomem	*vaddr;
-	unsigned long	size;
-	u8		type;		/* OMAPFB_PLANE_MEM_* */
-	enum omapfb_color_format format;/* OMAPFB_COLOR_* */
-	unsigned	format_used:1;	/* Must be set when format is set.
-					 * Needed b/c of the badly chosen 0
-					 * base for OMAPFB_COLOR_* values
-					 */
-	unsigned	alloc:1;	/* allocated by the driver */
-	unsigned	map:1;		/* kernel mapped by the driver */
-};
-
-struct omapfb_mem_desc {
-	int				region_cnt;
-	struct omapfb_mem_region	region[OMAPFB_PLANE_NUM];
-};
-
 struct omapfb_platform_data {
 	struct omap_lcd_config		lcd;
-	struct omapfb_mem_desc		mem_desc;
-	void				*ctrl_platform_data;
 };
 
-/* in arch/arm/plat-omap/fb.c */
-extern void omapfb_set_platform_data(struct omapfb_platform_data *data);
-extern void omapfb_set_ctrl_platform_data(void *pdata);
-extern void omapfb_reserve_sdram_memblock(void);
+void __init omapfb_set_lcd_config(const struct omap_lcd_config *config);
 
 #endif
 
diff --git a/include/linux/oom.h b/include/linux/oom.h
index 552fba9..3d76475 100644
--- a/include/linux/oom.h
+++ b/include/linux/oom.h
@@ -49,7 +49,7 @@
 extern void clear_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_flags);
 
 extern void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask,
-		int order, nodemask_t *mask);
+		int order, nodemask_t *mask, bool force_kill);
 extern int register_oom_notifier(struct notifier_block *nb);
 extern int unregister_oom_notifier(struct notifier_block *nb);
 
diff --git a/include/linux/opp.h b/include/linux/opp.h
index ee94b33..2a4e5fa 100644
--- a/include/linux/opp.h
+++ b/include/linux/opp.h
@@ -19,6 +19,7 @@
 #include <linux/notifier.h>
 
 struct opp;
+struct device;
 
 enum opp_event {
 	OPP_EVENT_ADD, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE,
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index e90a673..c88d2a9 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -6,6 +6,7 @@
 #define PAGE_FLAGS_H
 
 #include <linux/types.h>
+#include <linux/bug.h>
 #ifndef __GENERATING_BOUNDS_H
 #include <linux/mm_types.h>
 #include <generated/bounds.h>
@@ -414,11 +415,26 @@
 	return PageHead(page);
 }
 
+/*
+ * PageTransCompound returns true for both transparent huge pages
+ * and hugetlbfs pages, so it should only be called when it's known
+ * that hugetlbfs pages aren't involved.
+ */
 static inline int PageTransCompound(struct page *page)
 {
 	return PageCompound(page);
 }
 
+/*
+ * PageTransTail returns true for both transparent huge pages
+ * and hugetlbfs pages, so it should only be called when it's known
+ * that hugetlbfs pages aren't involved.
+ */
+static inline int PageTransTail(struct page *page)
+{
+	return PageTail(page);
+}
+
 #else
 
 static inline int PageTransHuge(struct page *page)
@@ -430,6 +446,11 @@
 {
 	return 0;
 }
+
+static inline int PageTransTail(struct page *page)
+{
+	return 0;
+}
 #endif
 
 #ifdef CONFIG_MMU
diff --git a/include/linux/page_cgroup.h b/include/linux/page_cgroup.h
index a2d11771..a88cdba 100644
--- a/include/linux/page_cgroup.h
+++ b/include/linux/page_cgroup.h
@@ -4,12 +4,8 @@
 enum {
 	/* flags for mem_cgroup */
 	PCG_LOCK,  /* Lock for pc->mem_cgroup and following bits. */
-	PCG_CACHE, /* charged as cache */
 	PCG_USED, /* this object is in use. */
 	PCG_MIGRATION, /* under page migration */
-	/* flags for mem_cgroup and file and I/O status */
-	PCG_MOVE_LOCK, /* For race between move_account v.s. following bits */
-	PCG_FILE_MAPPED, /* page is accounted as "mapped" */
 	__NR_PCG_FLAGS,
 };
 
@@ -64,19 +60,10 @@
 static inline int TestClearPageCgroup##uname(struct page_cgroup *pc)	\
 	{ return test_and_clear_bit(PCG_##lname, &pc->flags);  }
 
-/* Cache flag is set only once (at allocation) */
-TESTPCGFLAG(Cache, CACHE)
-CLEARPCGFLAG(Cache, CACHE)
-SETPCGFLAG(Cache, CACHE)
-
 TESTPCGFLAG(Used, USED)
 CLEARPCGFLAG(Used, USED)
 SETPCGFLAG(Used, USED)
 
-SETPCGFLAG(FileMapped, FILE_MAPPED)
-CLEARPCGFLAG(FileMapped, FILE_MAPPED)
-TESTPCGFLAG(FileMapped, FILE_MAPPED)
-
 SETPCGFLAG(Migration, MIGRATION)
 CLEARPCGFLAG(Migration, MIGRATION)
 TESTPCGFLAG(Migration, MIGRATION)
@@ -85,7 +72,7 @@
 {
 	/*
 	 * Don't take this lock in IRQ context.
-	 * This lock is for pc->mem_cgroup, USED, CACHE, MIGRATION
+	 * This lock is for pc->mem_cgroup, USED, MIGRATION
 	 */
 	bit_spin_lock(PCG_LOCK, &pc->flags);
 }
@@ -95,24 +82,6 @@
 	bit_spin_unlock(PCG_LOCK, &pc->flags);
 }
 
-static inline void move_lock_page_cgroup(struct page_cgroup *pc,
-	unsigned long *flags)
-{
-	/*
-	 * We know updates to pc->flags of page cache's stats are from both of
-	 * usual context or IRQ context. Disable IRQ to avoid deadlock.
-	 */
-	local_irq_save(*flags);
-	bit_spin_lock(PCG_MOVE_LOCK, &pc->flags);
-}
-
-static inline void move_unlock_page_cgroup(struct page_cgroup *pc,
-	unsigned long *flags)
-{
-	bit_spin_unlock(PCG_MOVE_LOCK, &pc->flags);
-	local_irq_restore(*flags);
-}
-
 #else /* CONFIG_CGROUP_MEM_RES_CTLR */
 struct page_cgroup;
 
diff --git a/include/linux/parport.h b/include/linux/parport.h
index 38a423e..106c2ca 100644
--- a/include/linux/parport.h
+++ b/include/linux/parport.h
@@ -100,7 +100,6 @@
 #include <linux/wait.h>
 #include <linux/irqreturn.h>
 #include <linux/semaphore.h>
-#include <asm/system.h>
 #include <asm/ptrace.h>
 
 /* Define this later. */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index b843fe7..e444f5b 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -299,7 +299,6 @@
 	 */
 	unsigned int	irq;
 	struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
-	resource_size_t	fw_addr[DEVICE_COUNT_RESOURCE]; /* FW-assigned addr */
 
 	/* These fields are used by common fixups */
 	unsigned int	transparent:1;	/* Transparent PCI bridge */
@@ -369,24 +368,17 @@
 	return (pdev->error_state != pci_channel_io_normal);
 }
 
-static inline struct pci_cap_saved_state *pci_find_saved_cap(
-	struct pci_dev *pci_dev, char cap)
-{
-	struct pci_cap_saved_state *tmp;
-	struct hlist_node *pos;
+struct pci_host_bridge_window {
+	struct list_head list;
+	struct resource *res;		/* host bridge aperture (CPU address) */
+	resource_size_t offset;		/* bus address + offset = CPU address */
+};
 
-	hlist_for_each_entry(tmp, pos, &pci_dev->saved_cap_space, next) {
-		if (tmp->cap.cap_nr == cap)
-			return tmp;
-	}
-	return NULL;
-}
-
-static inline void pci_add_saved_cap(struct pci_dev *pci_dev,
-	struct pci_cap_saved_state *new_cap)
-{
-	hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space);
-}
+struct pci_host_bridge {
+	struct list_head list;
+	struct pci_bus *bus;		/* root bus */
+	struct list_head windows;	/* pci_host_bridge_windows */
+};
 
 /*
  * The first PCI_BRIDGE_RESOURCE_NUM PCI bus resources (those that correspond
@@ -656,6 +648,10 @@
 
 /* Generic PCI functions used internally */
 
+void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+			     struct resource *res);
+void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+			     struct pci_bus_region *region);
 void pcibios_scan_specific_bus(int busn);
 extern struct pci_bus *pci_find_bus(int domain, int busnr);
 void pci_bus_add_devices(const struct pci_bus *bus);
@@ -690,7 +686,8 @@
 extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
 extern void pci_dev_put(struct pci_dev *dev);
 extern void pci_remove_bus(struct pci_bus *b);
-extern void pci_remove_bus_device(struct pci_dev *dev);
+extern void __pci_remove_bus_device(struct pci_dev *dev);
+extern void pci_stop_and_remove_bus_device(struct pci_dev *dev);
 extern void pci_stop_bus_device(struct pci_dev *dev);
 void pci_setup_cardbus(struct pci_bus *bus);
 extern void pci_sort_breadthfirst(void);
@@ -817,6 +814,7 @@
 int pcie_get_mps(struct pci_dev *dev);
 int pcie_set_mps(struct pci_dev *dev, int mps);
 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);
 void pci_update_resource(struct pci_dev *dev, int resno);
 int __must_check pci_assign_resource(struct pci_dev *dev, int i);
@@ -882,6 +880,7 @@
 /* Functions for PCI Hotplug drivers to use */
 int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap);
 #ifdef CONFIG_HOTPLUG
+unsigned int pci_rescan_bus_bridge_resize(struct pci_dev *bridge);
 unsigned int pci_rescan_bus(struct pci_bus *bus);
 #endif
 
@@ -891,13 +890,13 @@
 int pci_vpd_truncate(struct pci_dev *dev, size_t size);
 
 /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
+resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);
 void pci_bus_assign_resources(const struct pci_bus *bus);
 void pci_bus_size_bridges(struct pci_bus *bus);
 int pci_claim_resource(struct pci_dev *, int);
 void pci_assign_unassigned_resources(void);
 void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge);
 void pdev_enable_device(struct pci_dev *);
-void pdev_sort_resources(struct pci_dev *, struct resource_list *);
 int pci_enable_resources(struct pci_dev *, int mask);
 void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
 		    int (*)(const struct pci_dev *, u8, u8));
@@ -914,6 +913,8 @@
 
 /* drivers/pci/bus.c */
 void pci_add_resource(struct list_head *resources, struct resource *res);
+void pci_add_resource_offset(struct list_head *resources, struct resource *res,
+			     resource_size_t offset);
 void pci_free_resource_list(struct list_head *resources);
 void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, unsigned int flags);
 struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n);
@@ -959,7 +960,7 @@
 	module_driver(__pci_driver, pci_register_driver, \
 		       pci_unregister_driver)
 
-void pci_remove_behind_bridge(struct pci_dev *dev);
+void pci_stop_and_remove_behind_bridge(struct pci_dev *dev);
 struct pci_driver *pci_dev_driver(const struct pci_dev *dev);
 int pci_add_dynid(struct pci_driver *drv,
 		  unsigned int vendor, unsigned int device,
@@ -1395,7 +1396,10 @@
  */
 
 struct pci_fixup {
-	u16 vendor, device;	/* You can use PCI_ANY_ID here of course */
+	u16 vendor;		/* You can use PCI_ANY_ID here of course */
+	u16 device;		/* You can use PCI_ANY_ID here of course */
+	u32 class;		/* You can use PCI_ANY_ID here too */
+	unsigned int class_shift;	/* should be 0, 8, 16 */
 	void (*hook)(struct pci_dev *dev);
 };
 
@@ -1410,30 +1414,68 @@
 };
 
 /* Anonymous variables would be nice... */
-#define DECLARE_PCI_FIXUP_SECTION(section, name, vendor, device, hook)	\
-	static const struct pci_fixup __pci_fixup_##name __used		\
-	__attribute__((__section__(#section))) = { vendor, device, hook };
+#define DECLARE_PCI_FIXUP_SECTION(section, name, vendor, device, class,	\
+				  class_shift, hook)			\
+	static const struct pci_fixup const __pci_fixup_##name __used	\
+	__attribute__((__section__(#section), aligned((sizeof(void *)))))    \
+		= { vendor, device, class, class_shift, hook };
+
+#define DECLARE_PCI_FIXUP_CLASS_EARLY(vendor, device, class,		\
+					 class_shift, hook)		\
+	DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early,			\
+		vendor##device##hook, vendor, device, class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_HEADER(vendor, device, class,		\
+					 class_shift, hook)		\
+	DECLARE_PCI_FIXUP_SECTION(.pci_fixup_header,			\
+		vendor##device##hook, vendor, device, class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_FINAL(vendor, device, class,		\
+					 class_shift, hook)		\
+	DECLARE_PCI_FIXUP_SECTION(.pci_fixup_final,			\
+		vendor##device##hook, vendor, device, class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_ENABLE(vendor, device, class,		\
+					 class_shift, hook)		\
+	DECLARE_PCI_FIXUP_SECTION(.pci_fixup_enable,			\
+		vendor##device##hook, vendor, device, class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_RESUME(vendor, device, class,		\
+					 class_shift, hook)		\
+	DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume,			\
+		resume##vendor##device##hook, vendor, device, class,	\
+		class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_RESUME_EARLY(vendor, device, class,	\
+					 class_shift, hook)		\
+	DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume_early,		\
+		resume_early##vendor##device##hook, vendor, device,	\
+		class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_SUSPEND(vendor, device, class,		\
+					 class_shift, hook)		\
+	DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend,			\
+		suspend##vendor##device##hook, vendor, device, class,	\
+		class_shift, hook)
+
 #define DECLARE_PCI_FIXUP_EARLY(vendor, device, hook)			\
 	DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early,			\
-			vendor##device##hook, vendor, device, hook)
+		vendor##device##hook, vendor, device, PCI_ANY_ID, 0, hook)
 #define DECLARE_PCI_FIXUP_HEADER(vendor, device, hook)			\
 	DECLARE_PCI_FIXUP_SECTION(.pci_fixup_header,			\
-			vendor##device##hook, vendor, device, hook)
+		vendor##device##hook, vendor, device, PCI_ANY_ID, 0, hook)
 #define DECLARE_PCI_FIXUP_FINAL(vendor, device, hook)			\
 	DECLARE_PCI_FIXUP_SECTION(.pci_fixup_final,			\
-			vendor##device##hook, vendor, device, hook)
+		vendor##device##hook, vendor, device, PCI_ANY_ID, 0, hook)
 #define DECLARE_PCI_FIXUP_ENABLE(vendor, device, hook)			\
 	DECLARE_PCI_FIXUP_SECTION(.pci_fixup_enable,			\
-			vendor##device##hook, vendor, device, hook)
+		vendor##device##hook, vendor, device, PCI_ANY_ID, 0, hook)
 #define DECLARE_PCI_FIXUP_RESUME(vendor, device, hook)			\
 	DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume,			\
-			resume##vendor##device##hook, vendor, device, hook)
+		resume##vendor##device##hook, vendor, device,		\
+		PCI_ANY_ID, 0, hook)
 #define DECLARE_PCI_FIXUP_RESUME_EARLY(vendor, device, hook)		\
 	DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume_early,		\
-			resume_early##vendor##device##hook, vendor, device, hook)
+		resume_early##vendor##device##hook, vendor, device,	\
+		PCI_ANY_ID, 0, hook)
 #define DECLARE_PCI_FIXUP_SUSPEND(vendor, device, hook)			\
 	DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend,			\
-			suspend##vendor##device##hook, vendor, device, hook)
+		suspend##vendor##device##hook, vendor, device,		\
+		PCI_ANY_ID, 0, hook)
 
 #ifdef CONFIG_PCI_QUIRKS
 void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
@@ -1660,6 +1702,13 @@
 static inline void pci_release_bus_of_node(struct pci_bus *bus) { }
 #endif  /* CONFIG_OF */
 
+#ifdef CONFIG_EEH
+static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev)
+{
+	return pdev->dev.archdata.edev;
+}
+#endif
+
 /**
  * pci_find_upstream_pcie_bridge - find upstream PCIe-to-PCI bridge of a device
  * @pdev: the PCI device
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index e41a10f..4b608f5 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -391,6 +391,7 @@
 #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_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 */
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index bd9f55a..ddbb6a9 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -299,18 +299,31 @@
 	/*
 	 * Bits needed to read the hw events in user-space.
 	 *
-	 *   u32 seq;
-	 *   s64 count;
+	 *   u32 seq, time_mult, time_shift, idx, width;
+	 *   u64 count, enabled, running;
+	 *   u64 cyc, time_offset;
+	 *   s64 pmc = 0;
 	 *
 	 *   do {
 	 *     seq = pc->lock;
-	 *
 	 *     barrier()
-	 *     if (pc->index) {
-	 *       count = pmc_read(pc->index - 1);
-	 *       count += pc->offset;
-	 *     } else
-	 *       goto regular_read;
+	 *
+	 *     enabled = pc->time_enabled;
+	 *     running = pc->time_running;
+	 *
+	 *     if (pc->cap_usr_time && enabled != running) {
+	 *       cyc = rdtsc();
+	 *       time_offset = pc->time_offset;
+	 *       time_mult   = pc->time_mult;
+	 *       time_shift  = pc->time_shift;
+	 *     }
+	 *
+	 *     idx = pc->index;
+	 *     count = pc->offset;
+	 *     if (pc->cap_usr_rdpmc && idx) {
+	 *       width = pc->pmc_width;
+	 *       pmc = rdpmc(idx - 1);
+	 *     }
 	 *
 	 *     barrier();
 	 *   } while (pc->lock != seq);
@@ -323,14 +336,57 @@
 	__s64	offset;			/* add to hardware event value */
 	__u64	time_enabled;		/* time event active */
 	__u64	time_running;		/* time event on cpu */
-	__u32	time_mult, time_shift;
+	union {
+		__u64	capabilities;
+		__u64	cap_usr_time  : 1,
+			cap_usr_rdpmc : 1,
+			cap_____res   : 62;
+	};
+
+	/*
+	 * If cap_usr_rdpmc this field provides the bit-width of the value
+	 * read using the rdpmc() or equivalent instruction. This can be used
+	 * to sign extend the result like:
+	 *
+	 *   pmc <<= 64 - width;
+	 *   pmc >>= 64 - width; // signed shift right
+	 *   count += pmc;
+	 */
+	__u16	pmc_width;
+
+	/*
+	 * If cap_usr_time the below fields can be used to compute the time
+	 * delta since time_enabled (in ns) using rdtsc or similar.
+	 *
+	 *   u64 quot, rem;
+	 *   u64 delta;
+	 *
+	 *   quot = (cyc >> time_shift);
+	 *   rem = cyc & ((1 << time_shift) - 1);
+	 *   delta = time_offset + quot * time_mult +
+	 *              ((rem * time_mult) >> time_shift);
+	 *
+	 * Where time_offset,time_mult,time_shift and cyc are read in the
+	 * seqcount loop described above. This delta can then be added to
+	 * enabled and possible running (if idx), improving the scaling:
+	 *
+	 *   enabled += delta;
+	 *   if (idx)
+	 *     running += delta;
+	 *
+	 *   quot = count / running;
+	 *   rem  = count % running;
+	 *   count = quot * enabled + (rem * enabled) / running;
+	 */
+	__u16	time_shift;
+	__u32	time_mult;
 	__u64	time_offset;
 
 		/*
 		 * Hole for extension of the self monitor capabilities
 		 */
 
-	__u64	__reserved[121];	/* align to 1k */
+	__u64	__reserved[120];	/* align to 1k */
 
 	/*
 	 * Control data for the mmap() data buffer.
@@ -550,6 +606,7 @@
 #include <linux/irq_work.h>
 #include <linux/static_key.h>
 #include <linux/atomic.h>
+#include <linux/sysfs.h>
 #include <asm/local.h>
 
 #define PERF_MAX_STACK_DEPTH		255
@@ -1291,5 +1348,18 @@
 	register_cpu_notifier(&fn##_nb);				\
 } while (0)
 
+
+#define PMU_FORMAT_ATTR(_name, _format)					\
+static ssize_t								\
+_name##_show(struct device *dev,					\
+			       struct device_attribute *attr,		\
+			       char *page)				\
+{									\
+	BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE);			\
+	return sprintf(page, _format "\n");				\
+}									\
+									\
+static struct device_attribute format_attr_##_name = __ATTR_RO(_name)
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_PERF_EVENT_H */
diff --git a/include/linux/phy.h b/include/linux/phy.h
index c599f7ec..6fe0a37 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -19,7 +19,6 @@
 #define __PHY_H
 
 #include <linux/spinlock.h>
-#include <linux/device.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/timer.h>
@@ -88,6 +87,9 @@
    IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips. */
 #define MII_ADDR_C45 (1<<30)
 
+struct device;
+struct sk_buff;
+
 /*
  * The Bus class for PHYs.  Devices which provide access to
  * PHYs should register using this structure
@@ -241,7 +243,6 @@
 	PHY_RESUMING
 };
 
-struct sk_buff;
 
 /* phy_device: An instance of a PHY
  *
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index e7cf666..b067bd8 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -2,6 +2,7 @@
 #define _LINUX_PID_NS_H
 
 #include <linux/sched.h>
+#include <linux/bug.h>
 #include <linux/mm.h>
 #include <linux/threads.h>
 #include <linux/nsproxy.h>
@@ -32,6 +33,7 @@
 #endif
 	gid_t pid_gid;
 	int hide_pid;
+	int reboot;	/* group exit code if this pidns was rebooted */
 };
 
 extern struct pid_namespace init_pid_ns;
@@ -47,6 +49,7 @@
 extern struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *ns);
 extern void free_pid_ns(struct kref *kref);
 extern void zap_pid_ns_processes(struct pid_namespace *pid_ns);
+extern int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd);
 
 static inline void put_pid_ns(struct pid_namespace *ns)
 {
@@ -74,11 +77,15 @@
 {
 }
 
-
 static inline void zap_pid_ns_processes(struct pid_namespace *ns)
 {
 	BUG();
 }
+
+static inline int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd)
+{
+	return 0;
+}
 #endif /* CONFIG_PID_NS */
 
 extern struct pid_namespace *task_active_pid_ns(struct task_struct *tsk);
diff --git a/include/linux/pinctrl/consumer.h b/include/linux/pinctrl/consumer.h
new file mode 100644
index 0000000..191e726
--- /dev/null
+++ b/include/linux/pinctrl/consumer.h
@@ -0,0 +1,159 @@
+/*
+ * Consumer interface the pin control subsystem
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ * Based on bits of regulator core, gpio core and clk core
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef __LINUX_PINCTRL_CONSUMER_H
+#define __LINUX_PINCTRL_CONSUMER_H
+
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/seq_file.h>
+#include "pinctrl-state.h"
+
+/* This struct is private to the core and should be regarded as a cookie */
+struct pinctrl;
+struct pinctrl_state;
+
+#ifdef CONFIG_PINCTRL
+
+/* External interface to pin control */
+extern int pinctrl_request_gpio(unsigned gpio);
+extern void pinctrl_free_gpio(unsigned gpio);
+extern int pinctrl_gpio_direction_input(unsigned gpio);
+extern int pinctrl_gpio_direction_output(unsigned gpio);
+
+extern struct pinctrl * __must_check pinctrl_get(struct device *dev);
+extern void pinctrl_put(struct pinctrl *p);
+extern struct pinctrl_state * __must_check pinctrl_lookup_state(
+							struct pinctrl *p,
+							const char *name);
+extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
+
+#else /* !CONFIG_PINCTRL */
+
+static inline int pinctrl_request_gpio(unsigned gpio)
+{
+	return 0;
+}
+
+static inline void pinctrl_free_gpio(unsigned gpio)
+{
+}
+
+static inline int pinctrl_gpio_direction_input(unsigned gpio)
+{
+	return 0;
+}
+
+static inline int pinctrl_gpio_direction_output(unsigned gpio)
+{
+	return 0;
+}
+
+static inline struct pinctrl * __must_check pinctrl_get(struct device *dev)
+{
+	return NULL;
+}
+
+static inline void pinctrl_put(struct pinctrl *p)
+{
+}
+
+static inline struct pinctrl_state * __must_check pinctrl_lookup_state(
+							struct pinctrl *p,
+							const char *name)
+{
+	return NULL;
+}
+
+static inline int pinctrl_select_state(struct pinctrl *p,
+				       struct pinctrl_state *s)
+{
+	return 0;
+}
+
+#endif /* CONFIG_PINCTRL */
+
+static inline struct pinctrl * __must_check pinctrl_get_select(
+					struct device *dev, const char *name)
+{
+	struct pinctrl *p;
+	struct pinctrl_state *s;
+	int ret;
+
+	p = pinctrl_get(dev);
+	if (IS_ERR(p))
+		return p;
+
+	s = pinctrl_lookup_state(p, name);
+	if (IS_ERR(s)) {
+		pinctrl_put(p);
+		return ERR_PTR(PTR_ERR(s));
+	}
+
+	ret = pinctrl_select_state(p, s);
+	if (ret < 0) {
+		pinctrl_put(p);
+		return ERR_PTR(ret);
+	}
+
+	return p;
+}
+
+static inline struct pinctrl * __must_check pinctrl_get_select_default(
+					struct device *dev)
+{
+	return pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT);
+}
+
+#ifdef CONFIG_PINCONF
+
+extern int pin_config_get(const char *dev_name, const char *name,
+			  unsigned long *config);
+extern int pin_config_set(const char *dev_name, const char *name,
+			  unsigned long config);
+extern int pin_config_group_get(const char *dev_name,
+				const char *pin_group,
+				unsigned long *config);
+extern int pin_config_group_set(const char *dev_name,
+				const char *pin_group,
+				unsigned long config);
+
+#else
+
+static inline int pin_config_get(const char *dev_name, const char *name,
+				 unsigned long *config)
+{
+	return 0;
+}
+
+static inline int pin_config_set(const char *dev_name, const char *name,
+				 unsigned long config)
+{
+	return 0;
+}
+
+static inline int pin_config_group_get(const char *dev_name,
+				       const char *pin_group,
+				       unsigned long *config)
+{
+	return 0;
+}
+
+static inline int pin_config_group_set(const char *dev_name,
+				       const char *pin_group,
+				       unsigned long config)
+{
+	return 0;
+}
+
+#endif
+
+#endif /* __LINUX_PINCTRL_CONSUMER_H */
diff --git a/include/linux/pinctrl/machine.h b/include/linux/pinctrl/machine.h
index d0aecb7..fee4349 100644
--- a/include/linux/pinctrl/machine.h
+++ b/include/linux/pinctrl/machine.h
@@ -9,87 +9,153 @@
  *
  * License terms: GNU General Public License (GPL) version 2
  */
-#ifndef __LINUX_PINMUX_MACHINE_H
-#define __LINUX_PINMUX_MACHINE_H
+#ifndef __LINUX_PINCTRL_MACHINE_H
+#define __LINUX_PINCTRL_MACHINE_H
 
-/**
- * struct pinmux_map - boards/machines shall provide this map for devices
- * @name: the name of this specific map entry for the particular machine.
- *	This is the second parameter passed to pinmux_get() when you want
- *	to have several mappings to the same device
- * @ctrl_dev: the pin control device to be used by this mapping, may be NULL
- *	if you provide .ctrl_dev_name instead (this is more common)
- * @ctrl_dev_name: the name of the device controlling this specific mapping,
- *	the name must be the same as in your struct device*, may be NULL if
- *	you provide .ctrl_dev instead
- * @function: a function in the driver to use for this mapping, the driver
- *	will lookup the function referenced by this ID on the specified
- *	pin control device
- * @group: sometimes a function can map to different pin groups, so this
- *	selects a certain specific pin group to activate for the function, if
- *	left as NULL, the first applicable group will be used
- * @dev: the device using this specific mapping, may be NULL if you provide
- *	.dev_name instead (this is more common)
- * @dev_name: the name of the device using this specific mapping, the name
- *	must be the same as in your struct device*, may be NULL if you
- *	provide .dev instead
- * @hog_on_boot: if this is set to true, the pin control subsystem will itself
- *	hog the mappings as the pinmux device drivers are attached, so this is
- *	typically used with system maps (mux mappings without an assigned
- *	device) that you want to get hogged and enabled by default as soon as
- *	a pinmux device supporting it is registered. These maps will not be
- *	disabled and put until the system shuts down.
- */
-struct pinmux_map {
-	const char *name;
-	struct device *ctrl_dev;
-	const char *ctrl_dev_name;
-	const char *function;
-	const char *group;
-	struct device *dev;
-	const char *dev_name;
-	bool hog_on_boot;
+#include "pinctrl-state.h"
+
+enum pinctrl_map_type {
+	PIN_MAP_TYPE_INVALID,
+	PIN_MAP_TYPE_DUMMY_STATE,
+	PIN_MAP_TYPE_MUX_GROUP,
+	PIN_MAP_TYPE_CONFIGS_PIN,
+	PIN_MAP_TYPE_CONFIGS_GROUP,
 };
 
-/*
- * Convenience macro to set a simple map from a certain pin controller and a
- * certain function to a named device
+/**
+ * struct pinctrl_map_mux - mapping table content for MAP_TYPE_MUX_GROUP
+ * @group: the name of the group whose mux function is to be configured. This
+ *	field may be left NULL, and the first applicable group for the function
+ *	will be used.
+ * @function: the mux function to select for the group
  */
-#define PINMUX_MAP(a, b, c, d) \
-	{ .name = a, .ctrl_dev_name = b, .function = c, .dev_name = d }
+struct pinctrl_map_mux {
+	const char *group;
+	const char *function;
+};
 
-/*
- * Convenience macro to map a system function onto a certain pinctrl device.
- * System functions are not assigned to a particular device.
+/**
+ * struct pinctrl_map_configs - mapping table content for MAP_TYPE_CONFIGS_*
+ * @group_or_pin: the name of the pin or group whose configuration parameters
+ *	are to be configured.
+ * @configs: a pointer to an array of config parameters/values to program into
+ *	hardware. Each individual pin controller defines the format and meaning
+ *	of config parameters.
+ * @num_configs: the number of entries in array @configs
  */
-#define PINMUX_MAP_SYS(a, b, c) \
-	{ .name = a, .ctrl_dev_name = b, .function = c }
+struct pinctrl_map_configs {
+	const char *group_or_pin;
+	unsigned long *configs;
+	unsigned num_configs;
+};
 
-/*
- * Convenience macro to map a system function onto a certain pinctrl device,
- * to be hogged by the pinmux core until the system shuts down.
+/**
+ * struct pinctrl_map - boards/machines shall provide this map for devices
+ * @dev_name: the name of the device using this specific mapping, the name
+ *	must be the same as in your struct device*. If this name is set to the
+ *	same name as the pin controllers own dev_name(), the map entry will be
+ *	hogged by the driver itself upon registration
+ * @name: the name of this specific map entry for the particular machine.
+ *	This is the parameter passed to pinmux_lookup_state()
+ * @type: the type of mapping table entry
+ * @ctrl_dev_name: the name of the device controlling this specific mapping,
+ *	the name must be the same as in your struct device*. This field is not
+ *	used for PIN_MAP_TYPE_DUMMY_STATE
+ * @data: Data specific to the mapping type
  */
-#define PINMUX_MAP_SYS_HOG(a, b, c) \
-	{ .name = a, .ctrl_dev_name = b, .function = c, \
-	  .hog_on_boot = true }
+struct pinctrl_map {
+	const char *dev_name;
+	const char *name;
+	enum pinctrl_map_type type;
+	const char *ctrl_dev_name;
+	union {
+		struct pinctrl_map_mux mux;
+		struct pinctrl_map_configs configs;
+	} data;
+};
 
-/*
- * Convenience macro to map a system function onto a certain pinctrl device
- * using a specified group, to be hogged by the pinmux core until the system
- * shuts down.
- */
-#define PINMUX_MAP_SYS_HOG_GROUP(a, b, c, d)		\
-	{ .name = a, .ctrl_dev_name = b, .function = c, .group = d, \
-	  .hog_on_boot = true }
+/* Convenience macros to create mapping table entries */
+
+#define PIN_MAP_DUMMY_STATE(dev, state) \
+	{								\
+		.dev_name = dev,					\
+		.name = state,						\
+		.type = PIN_MAP_TYPE_DUMMY_STATE,			\
+	}
+
+#define PIN_MAP_MUX_GROUP(dev, state, pinctrl, grp, func)		\
+	{								\
+		.dev_name = dev,					\
+		.name = state,						\
+		.type = PIN_MAP_TYPE_MUX_GROUP,				\
+		.ctrl_dev_name = pinctrl,				\
+		.data.mux = {						\
+			.group = grp,					\
+			.function = func,				\
+		},							\
+	}
+
+#define PIN_MAP_MUX_GROUP_DEFAULT(dev, pinctrl, grp, func)		\
+	PIN_MAP_MUX_GROUP(dev, PINCTRL_STATE_DEFAULT, pinctrl, grp, func)
+
+#define PIN_MAP_MUX_GROUP_HOG(dev, state, grp, func)			\
+	PIN_MAP_MUX_GROUP(dev, state, dev, grp, func)
+
+#define PIN_MAP_MUX_GROUP_HOG_DEFAULT(dev, grp, func)			\
+	PIN_MAP_MUX_GROUP(dev, PINCTRL_STATE_DEFAULT, dev, grp, func)
+
+#define PIN_MAP_CONFIGS_PIN(dev, state, pinctrl, pin, cfgs)		\
+	{								\
+		.dev_name = dev,					\
+		.name = state,						\
+		.type = PIN_MAP_TYPE_CONFIGS_PIN,			\
+		.ctrl_dev_name = pinctrl,				\
+		.data.configs = {					\
+			.group_or_pin = pin,				\
+			.configs = cfgs,				\
+			.num_configs = ARRAY_SIZE(cfgs),		\
+		},							\
+	}
+
+#define PIN_MAP_CONFIGS_PIN_DEFAULT(dev, pinctrl, pin, cfgs)		\
+	PIN_MAP_CONFIGS_PIN(dev, PINCTRL_STATE_DEFAULT, pinctrl, pin, cfgs)
+
+#define PIN_MAP_CONFIGS_PIN_HOG(dev, state, pin, cfgs)			\
+	PIN_MAP_CONFIGS_PIN(dev, state, dev, pin, cfgs)
+
+#define PIN_MAP_CONFIGS_PIN_HOG_DEFAULT(dev, pin, cfgs)			\
+	PIN_MAP_CONFIGS_PIN(dev, PINCTRL_STATE_DEFAULT, dev, pin, cfgs)
+
+#define PIN_MAP_CONFIGS_GROUP(dev, state, pinctrl, grp, cfgs)		\
+	{								\
+		.dev_name = dev,					\
+		.name = state,						\
+		.type = PIN_MAP_TYPE_CONFIGS_GROUP,			\
+		.ctrl_dev_name = pinctrl,				\
+		.data.configs = {					\
+			.group_or_pin = grp,				\
+			.configs = cfgs,				\
+			.num_configs = ARRAY_SIZE(cfgs),		\
+		},							\
+	}
+
+#define PIN_MAP_CONFIGS_GROUP_DEFAULT(dev, pinctrl, grp, cfgs)		\
+	PIN_MAP_CONFIGS_GROUP(dev, PINCTRL_STATE_DEFAULT, pinctrl, grp, cfgs)
+
+#define PIN_MAP_CONFIGS_GROUP_HOG(dev, state, grp, cfgs)		\
+	PIN_MAP_CONFIGS_GROUP(dev, state, dev, grp, cfgs)
+
+#define PIN_MAP_CONFIGS_GROUP_HOG_DEFAULT(dev, grp, cfgs)		\
+	PIN_MAP_CONFIGS_GROUP(dev, PINCTRL_STATE_DEFAULT, dev, grp, cfgs)
 
 #ifdef CONFIG_PINMUX
 
-extern int pinmux_register_mappings(struct pinmux_map const *map,
+extern int pinctrl_register_mappings(struct pinctrl_map const *map,
 				unsigned num_maps);
 
 #else
 
-static inline int pinmux_register_mappings(struct pinmux_map const *map,
+static inline int pinctrl_register_mappings(struct pinctrl_map const *map,
 					   unsigned num_maps)
 {
 	return 0;
diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h
new file mode 100644
index 0000000..4f0abb9
--- /dev/null
+++ b/include/linux/pinctrl/pinconf-generic.h
@@ -0,0 +1,114 @@
+/*
+ * Interface the generic pinconfig portions of the pinctrl subsystem
+ *
+ * Copyright (C) 2011 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ * This interface is used in the core to keep track of pins.
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef __LINUX_PINCTRL_PINCONF_GENERIC_H
+#define __LINUX_PINCTRL_PINCONF_GENERIC_H
+
+/*
+ * You shouldn't even be able to compile with these enums etc unless you're
+ * using generic pin config. That is why this is defined out.
+ */
+#ifdef CONFIG_GENERIC_PINCONF
+
+/**
+ * enum pin_config_param - possible pin configuration parameters
+ * @PIN_CONFIG_BIAS_DISABLE: disable any pin bias on the pin, a
+ *	transition from say pull-up to pull-down implies that you disable
+ *	pull-up in the process, this setting disables all biasing.
+ * @PIN_CONFIG_BIAS_HIGH_IMPEDANCE: the pin will be set to a high impedance
+ *	mode, also know as "third-state" (tristate) or "high-Z" or "floating".
+ *	On output pins this effectively disconnects the pin, which is useful
+ *	if for example some other pin is going to drive the signal connected
+ *	to it for a while. Pins used for input are usually always high
+ *	impedance.
+ * @PIN_CONFIG_BIAS_PULL_UP: the pin will be pulled up (usually with high
+ *	impedance to VDD). If the argument is != 0 pull-up is enabled,
+ *	if it is 0, pull-up is disabled.
+ * @PIN_CONFIG_BIAS_PULL_DOWN: the pin will be pulled down (usually with high
+ *	impedance to GROUND). If the argument is != 0 pull-down is enabled,
+ *	if it is 0, pull-down is disabled.
+ * @PIN_CONFIG_DRIVE_PUSH_PULL: the pin will be driven actively high and
+ *	low, this is the most typical case and is typically achieved with two
+ *	active transistors on the output. Sending this config will enabale
+ *	push-pull mode, the argument is ignored.
+ * @PIN_CONFIG_DRIVE_OPEN_DRAIN: the pin will be driven with open drain (open
+ *	collector) which means it is usually wired with other output ports
+ *	which are then pulled up with an external resistor. Sending this
+ *	config will enabale open drain mode, the argument is ignored.
+ * @PIN_CONFIG_DRIVE_OPEN_SOURCE: the pin will be driven with open source
+ *	(open emitter). Sending this config will enabale open drain mode, the
+ *	argument is ignored.
+ * @PIN_CONFIG_INPUT_SCHMITT: this will configure an input pin to run in
+ *	schmitt-trigger mode. If the schmitt-trigger has adjustable hysteresis,
+ *	the threshold value is given on a custom format as argument when
+ *	setting pins to this mode. The argument zero turns the schmitt trigger
+ *	off.
+ * @PIN_CONFIG_INPUT_DEBOUNCE: this will configure the pin to debounce mode,
+ *	which means it will wait for signals to settle when reading inputs. The
+ *	argument gives the debounce time on a custom format. Setting the
+ *	argument to zero turns debouncing off.
+ * @PIN_CONFIG_POWER_SOURCE: if the pin can select between different power
+ *	supplies, the argument to this parameter (on a custom format) tells
+ *	the driver which alternative power source to use.
+ * @PIN_CONFIG_LOW_POWER_MODE: this will configure the pin for low power
+ *	operation, if several modes of operation are supported these can be
+ *	passed in the argument on a custom form, else just use argument 1
+ *	to indicate low power mode, argument 0 turns low power mode off.
+ * @PIN_CONFIG_END: this is the last enumerator for pin configurations, if
+ *	you need to pass in custom configurations to the pin controller, use
+ *	PIN_CONFIG_END+1 as the base offset.
+ */
+enum pin_config_param {
+	PIN_CONFIG_BIAS_DISABLE,
+	PIN_CONFIG_BIAS_HIGH_IMPEDANCE,
+	PIN_CONFIG_BIAS_PULL_UP,
+	PIN_CONFIG_BIAS_PULL_DOWN,
+	PIN_CONFIG_DRIVE_PUSH_PULL,
+	PIN_CONFIG_DRIVE_OPEN_DRAIN,
+	PIN_CONFIG_DRIVE_OPEN_SOURCE,
+	PIN_CONFIG_INPUT_SCHMITT,
+	PIN_CONFIG_INPUT_DEBOUNCE,
+	PIN_CONFIG_POWER_SOURCE,
+	PIN_CONFIG_LOW_POWER_MODE,
+	PIN_CONFIG_END = 0x7FFF,
+};
+
+/*
+ * Helpful configuration macro to be used in tables etc.
+ */
+#define PIN_CONF_PACKED(p, a) ((a << 16) | ((unsigned long) p & 0xffffUL))
+
+/*
+ * The following inlines stuffs a configuration parameter and data value
+ * into and out of an unsigned long argument, as used by the generic pin config
+ * system. We put the parameter in the lower 16 bits and the argument in the
+ * upper 16 bits.
+ */
+
+static inline enum pin_config_param pinconf_to_config_param(unsigned long config)
+{
+	return (enum pin_config_param) (config & 0xffffUL);
+}
+
+static inline u16 pinconf_to_config_argument(unsigned long config)
+{
+	return (enum pin_config_param) ((config >> 16) & 0xffffUL);
+}
+
+static inline unsigned long pinconf_to_config_packed(enum pin_config_param param,
+						     u16 argument)
+{
+	return PIN_CONF_PACKED(param, argument);
+}
+
+#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 477922c..ec431f0 100644
--- a/include/linux/pinctrl/pinconf.h
+++ b/include/linux/pinctrl/pinconf.h
@@ -20,6 +20,8 @@
 /**
  * struct pinconf_ops - pin config operations, to be implemented by
  * pin configuration capable drivers.
+ * @is_generic: for pin controllers that want to use the generic interface,
+ *	this flag tells the framework that it's generic.
  * @pin_config_get: get the config of a certain pin, if the requested config
  *	is not available on this controller this should return -ENOTSUPP
  *	and if it is available but disabled it should return -EINVAL
@@ -33,6 +35,9 @@
  *	per-device info for a certain group in debugfs
  */
 struct pinconf_ops {
+#ifdef CONFIG_GENERIC_PINCONF
+	bool is_generic;
+#endif
 	int (*pin_config_get) (struct pinctrl_dev *pctldev,
 			       unsigned pin,
 			       unsigned long *config);
@@ -53,45 +58,6 @@
 					   unsigned selector);
 };
 
-extern int pin_config_get(const char *dev_name, const char *name,
-			  unsigned long *config);
-extern int pin_config_set(const char *dev_name, const char *name,
-			  unsigned long config);
-extern int pin_config_group_get(const char *dev_name,
-				const char *pin_group,
-				unsigned long *config);
-extern int pin_config_group_set(const char *dev_name,
-				const char *pin_group,
-				unsigned long config);
-
-#else
-
-static inline int pin_config_get(const char *dev_name, const char *name,
-				 unsigned long *config)
-{
-	return 0;
-}
-
-static inline int pin_config_set(const char *dev_name, const char *name,
-				 unsigned long config)
-{
-	return 0;
-}
-
-static inline int pin_config_group_get(const char *dev_name,
-				       const char *pin_group,
-				       unsigned long *config)
-{
-	return 0;
-}
-
-static inline int pin_config_group_set(const char *dev_name,
-				       const char *pin_group,
-				       unsigned long config)
-{
-	return 0;
-}
-
 #endif
 
 #endif /* __LINUX_PINCTRL_PINCONF_H */
diff --git a/include/linux/pinctrl/pinctrl-state.h b/include/linux/pinctrl/pinctrl-state.h
new file mode 100644
index 0000000..3920e28
--- /dev/null
+++ b/include/linux/pinctrl/pinctrl-state.h
@@ -0,0 +1,6 @@
+/*
+ * Standard pin control state definitions
+ */
+
+#define PINCTRL_STATE_DEFAULT "default"
+#define PINCTRL_STATE_IDLE "idle"
diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
index 8bd22ee..4e9f078 100644
--- a/include/linux/pinctrl/pinctrl.h
+++ b/include/linux/pinctrl/pinctrl.h
@@ -15,10 +15,11 @@
 #ifdef CONFIG_PINCTRL
 
 #include <linux/radix-tree.h>
-#include <linux/spinlock.h>
 #include <linux/list.h>
 #include <linux/seq_file.h>
+#include "pinctrl-state.h"
 
+struct device;
 struct pinctrl_dev;
 struct pinmux_ops;
 struct pinconf_ops;
diff --git a/include/linux/pinctrl/pinmux.h b/include/linux/pinctrl/pinmux.h
index 937b3e2..47e9237 100644
--- a/include/linux/pinctrl/pinmux.h
+++ b/include/linux/pinctrl/pinmux.h
@@ -16,9 +16,6 @@
 #include <linux/seq_file.h>
 #include "pinctrl.h"
 
-/* This struct is private to the core and should be regarded as a cookie */
-struct pinmux;
-
 #ifdef CONFIG_PINMUX
 
 struct pinctrl_dev;
@@ -88,55 +85,6 @@
 				   bool input);
 };
 
-/* External interface to pinmux */
-extern int pinmux_request_gpio(unsigned gpio);
-extern void pinmux_free_gpio(unsigned gpio);
-extern int pinmux_gpio_direction_input(unsigned gpio);
-extern int pinmux_gpio_direction_output(unsigned gpio);
-extern struct pinmux * __must_check pinmux_get(struct device *dev, const char *name);
-extern void pinmux_put(struct pinmux *pmx);
-extern int pinmux_enable(struct pinmux *pmx);
-extern void pinmux_disable(struct pinmux *pmx);
-
-#else /* !CONFIG_PINMUX */
-
-static inline int pinmux_request_gpio(unsigned gpio)
-{
-	return 0;
-}
-
-static inline void pinmux_free_gpio(unsigned gpio)
-{
-}
-
-static inline int pinmux_gpio_direction_input(unsigned gpio)
-{
-	return 0;
-}
-
-static inline int pinmux_gpio_direction_output(unsigned gpio)
-{
-	return 0;
-}
-
-static inline struct pinmux * __must_check pinmux_get(struct device *dev, const char *name)
-{
-	return NULL;
-}
-
-static inline void pinmux_put(struct pinmux *pmx)
-{
-}
-
-static inline int pinmux_enable(struct pinmux *pmx)
-{
-	return 0;
-}
-
-static inline void pinmux_disable(struct pinmux *pmx)
-{
-}
-
 #endif /* CONFIG_PINMUX */
 
 #endif /* __LINUX_PINCTRL_PINMUX_H */
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
index 77257c9..6d626ff 100644
--- a/include/linux/pipe_fs_i.h
+++ b/include/linux/pipe_fs_i.h
@@ -1,8 +1,6 @@
 #ifndef _LINUX_PIPE_FS_I_H
 #define _LINUX_PIPE_FS_I_H
 
-#define PIPEFS_MAGIC 0x50495045
-
 #define PIPE_DEF_BUFFERS	16
 
 #define PIPE_BUF_FLAG_LRU	0x01	/* page is on the LRU */
diff --git a/include/linux/platform_data/atmel.h b/include/linux/platform_data/atmel.h
new file mode 100644
index 0000000..b0f2c56
--- /dev/null
+++ b/include/linux/platform_data/atmel.h
@@ -0,0 +1,27 @@
+/*
+ * atmel platform data
+ *
+ * GPL v2 Only
+ */
+
+#ifndef __ATMEL_H__
+#define __ATMEL_H__
+
+#include <linux/mtd/nand.h>
+
+ /* NAND / SmartMedia */
+struct atmel_nand_data {
+	int		enable_pin;		/* chip enable */
+	int		det_pin;		/* card detect */
+	int		rdy_pin;		/* ready/busy */
+	u8		rdy_pin_active_low;	/* rdy_pin value is inverted */
+	u8		ale;			/* address line number connected to ALE */
+	u8		cle;			/* address line number connected to CLE */
+	u8		bus_width_16;		/* buswidth is 16 bit */
+	u8		ecc_mode;		/* ecc mode */
+	u8		on_flash_bbt;		/* bbt on flash */
+	struct mtd_partition *parts;
+	unsigned int	num_parts;
+};
+
+#endif /* __ATMEL_H__ */
diff --git a/include/linux/platform_data/omap-abe-twl6040.h b/include/linux/platform_data/omap-abe-twl6040.h
new file mode 100644
index 0000000..5d298ac
--- /dev/null
+++ b/include/linux/platform_data/omap-abe-twl6040.h
@@ -0,0 +1,49 @@
+/**
+ * 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/omap4-keypad.h b/include/linux/platform_data/omap4-keypad.h
new file mode 100644
index 0000000..4eef5fb
--- /dev/null
+++ b/include/linux/platform_data/omap4-keypad.h
@@ -0,0 +1,13 @@
+#ifndef __LINUX_INPUT_OMAP4_KEYPAD_H
+#define __LINUX_INPUT_OMAP4_KEYPAD_H
+
+#include <linux/input/matrix_keypad.h>
+
+struct omap4_keypad_platform_data {
+	const struct matrix_keymap_data *keymap_data;
+
+	u8 rows;
+	u8 cols;
+};
+
+#endif /* __LINUX_INPUT_OMAP4_KEYPAD_H */
diff --git a/include/linux/platform_data/spear_thermal.h b/include/linux/platform_data/spear_thermal.h
new file mode 100644
index 0000000..724f2e1
--- /dev/null
+++ b/include/linux/platform_data/spear_thermal.h
@@ -0,0 +1,26 @@
+/*
+ * SPEAr thermal driver platform data.
+ *
+ * Copyright (C) 2011-2012 ST Microelectronics
+ * Author: Vincenzo Frascino <vincenzo.frascino@st.com>
+ *
+ * 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 SPEAR_THERMAL_H
+#define SPEAR_THERMAL_H
+
+/* SPEAr Thermal Sensor Platform Data */
+struct spear_thermal_pdata {
+	/* flags used to enable thermal sensor */
+	unsigned int thermal_flags;
+};
+
+#endif /* SPEAR_THERMAL_H */
diff --git a/include/linux/platform_data/tegra_emc.h b/include/linux/platform_data/tegra_emc.h
new file mode 100644
index 0000000..df67505
--- /dev/null
+++ b/include/linux/platform_data/tegra_emc.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Author:
+ *	Colin Cross <ccross@android.com>
+ *	Olof Johansson <olof@lixom.net>
+ *
+ * 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_EMC_H_
+#define __TEGRA_EMC_H_
+
+#define TEGRA_EMC_NUM_REGS 46
+
+struct tegra_emc_table {
+	unsigned long rate;
+	u32 regs[TEGRA_EMC_NUM_REGS];
+};
+
+struct tegra_emc_pdata {
+	int num_tables;
+	struct tegra_emc_table *tables;
+};
+
+#endif
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 1236d26..91f8286 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -10,6 +10,8 @@
 #define _LINUX_PM_DOMAIN_H
 
 #include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/pm.h>
 #include <linux/err.h>
 #include <linux/of.h>
 
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 2e9191a..233149c 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -8,6 +8,7 @@
 #include <linux/notifier.h>
 #include <linux/miscdevice.h>
 #include <linux/device.h>
+#include <linux/workqueue.h>
 
 enum {
 	PM_QOS_RESERVED = 0,
@@ -29,6 +30,7 @@
 struct pm_qos_request {
 	struct plist_node node;
 	int pm_qos_class;
+	struct delayed_work work; /* for pm_qos_update_request_timeout */
 };
 
 struct dev_pm_qos_request {
@@ -73,6 +75,8 @@
 			s32 value);
 void pm_qos_update_request(struct pm_qos_request *req,
 			   s32 new_value);
+void pm_qos_update_request_timeout(struct pm_qos_request *req,
+				   s32 new_value, unsigned long timeout_us);
 void pm_qos_remove_request(struct pm_qos_request *req);
 
 int pm_qos_request(int pm_qos_class);
diff --git a/include/linux/poll.h b/include/linux/poll.h
index cf40010..48fe8bc 100644
--- a/include/linux/poll.h
+++ b/include/linux/poll.h
@@ -32,21 +32,46 @@
  */
 typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *);
 
+/*
+ * Do not touch the structure directly, use the access functions
+ * poll_does_not_wait() and poll_requested_events() instead.
+ */
 typedef struct poll_table_struct {
-	poll_queue_proc qproc;
-	unsigned long key;
+	poll_queue_proc _qproc;
+	unsigned long _key;
 } poll_table;
 
 static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
 {
-	if (p && wait_address)
-		p->qproc(filp, wait_address, p);
+	if (p && p->_qproc && wait_address)
+		p->_qproc(filp, wait_address, p);
+}
+
+/*
+ * Return true if it is guaranteed that poll will not wait. This is the case
+ * if the poll() of another file descriptor in the set got an event, so there
+ * is no need for waiting.
+ */
+static inline bool poll_does_not_wait(const poll_table *p)
+{
+	return p == NULL || p->_qproc == NULL;
+}
+
+/*
+ * Return the set of events that the application wants to poll for.
+ * This is useful for drivers that need to know whether a DMA transfer has
+ * to be started implicitly on poll(). You typically only want to do that
+ * if the application is actually polling for POLLIN and/or POLLOUT.
+ */
+static inline unsigned long poll_requested_events(const poll_table *p)
+{
+	return p ? p->_key : ~0UL;
 }
 
 static inline void init_poll_funcptr(poll_table *pt, poll_queue_proc qproc)
 {
-	pt->qproc = qproc;
-	pt->key   = ~0UL; /* all events enabled */
+	pt->_qproc = qproc;
+	pt->_key   = ~0UL; /* all events enabled */
 }
 
 struct poll_table_entry {
diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h
index b768110..11bad91 100644
--- a/include/linux/posix_acl.h
+++ b/include/linux/posix_acl.h
@@ -8,6 +8,7 @@
 #ifndef __LINUX_POSIX_ACL_H
 #define __LINUX_POSIX_ACL_H
 
+#include <linux/bug.h>
 #include <linux/slab.h>
 #include <linux/rcupdate.h>
 
diff --git a/include/linux/power/max17042_battery.h b/include/linux/power/max17042_battery.h
index fe99211..e01b167 100644
--- a/include/linux/power/max17042_battery.h
+++ b/include/linux/power/max17042_battery.h
@@ -27,6 +27,8 @@
 #define MAX17042_BATTERY_FULL	(100)
 #define MAX17042_DEFAULT_SNS_RESISTOR	(10000)
 
+#define MAX17042_CHARACTERIZATION_DATA_SIZE 48
+
 enum max17042_register {
 	MAX17042_STATUS		= 0x00,
 	MAX17042_VALRT_Th	= 0x01,
@@ -40,11 +42,11 @@
 	MAX17042_VCELL		= 0x09,
 	MAX17042_Current	= 0x0A,
 	MAX17042_AvgCurrent	= 0x0B,
-	MAX17042_Qresidual	= 0x0C,
+
 	MAX17042_SOC		= 0x0D,
 	MAX17042_AvSOC		= 0x0E,
 	MAX17042_RemCap		= 0x0F,
-	MAX17402_FullCAP	= 0x10,
+	MAX17042_FullCAP	= 0x10,
 	MAX17042_TTE		= 0x11,
 	MAX17042_V_empty	= 0x12,
 
@@ -62,14 +64,14 @@
 	MAX17042_AvCap		= 0x1F,
 	MAX17042_ManName	= 0x20,
 	MAX17042_DevName	= 0x21,
-	MAX17042_DevChem	= 0x22,
 
+	MAX17042_FullCAPNom	= 0x23,
 	MAX17042_TempNom	= 0x24,
-	MAX17042_TempCold	= 0x25,
+	MAX17042_TempLim	= 0x25,
 	MAX17042_TempHot	= 0x26,
 	MAX17042_AIN		= 0x27,
 	MAX17042_LearnCFG	= 0x28,
-	MAX17042_SHFTCFG	= 0x29,
+	MAX17042_FilterCFG	= 0x29,
 	MAX17042_RelaxCFG	= 0x2A,
 	MAX17042_MiscCFG	= 0x2B,
 	MAX17042_TGAIN		= 0x2C,
@@ -77,22 +79,41 @@
 	MAX17042_CGAIN		= 0x2E,
 	MAX17042_COFF		= 0x2F,
 
-	MAX17042_Q_empty	= 0x33,
+	MAX17042_MaskSOC	= 0x32,
+	MAX17042_SOC_empty	= 0x33,
 	MAX17042_T_empty	= 0x34,
 
+	MAX17042_FullCAP0       = 0x35,
+	MAX17042_LAvg_empty	= 0x36,
+	MAX17042_FCTC		= 0x37,
 	MAX17042_RCOMP0		= 0x38,
 	MAX17042_TempCo		= 0x39,
-	MAX17042_Rx		= 0x3A,
-	MAX17042_T_empty0	= 0x3B,
+	MAX17042_EmptyTempCo	= 0x3A,
+	MAX17042_K_empty0	= 0x3B,
 	MAX17042_TaskPeriod	= 0x3C,
 	MAX17042_FSTAT		= 0x3D,
 
 	MAX17042_SHDNTIMER	= 0x3F,
 
-	MAX17042_VFRemCap	= 0x4A,
+	MAX17042_dQacc		= 0x45,
+	MAX17042_dPacc		= 0x46,
+
+	MAX17042_VFSOC0		= 0x48,
 
 	MAX17042_QH		= 0x4D,
 	MAX17042_QL		= 0x4E,
+
+	MAX17042_VFSOC0Enable	= 0x60,
+	MAX17042_MLOCKReg1	= 0x62,
+	MAX17042_MLOCKReg2	= 0x63,
+
+	MAX17042_MODELChrTbl	= 0x80,
+
+	MAX17042_OCV		= 0xEE,
+
+	MAX17042_OCVInternal	= 0xFB,
+
+	MAX17042_VFSOC		= 0xFF,
 };
 
 /*
@@ -105,10 +126,64 @@
 	u16 data;
 };
 
+struct max17042_config_data {
+	/* External current sense resistor value in milli-ohms */
+	u32	cur_sense_val;
+
+	/* A/D measurement */
+	u16	tgain;		/* 0x2C */
+	u16	toff;		/* 0x2D */
+	u16	cgain;		/* 0x2E */
+	u16	coff;		/* 0x2F */
+
+	/* Alert / Status */
+	u16	valrt_thresh;	/* 0x01 */
+	u16	talrt_thresh;	/* 0x02 */
+	u16	soc_alrt_thresh;	/* 0x03 */
+	u16	config;		/* 0x01D */
+	u16	shdntimer;	/* 0x03F */
+
+	/* App data */
+	u16	design_cap;	/* 0x18 */
+	u16	ichgt_term;	/* 0x1E */
+
+	/* MG3 config */
+	u16	at_rate;	/* 0x04 */
+	u16	learn_cfg;	/* 0x28 */
+	u16	filter_cfg;	/* 0x29 */
+	u16	relax_cfg;	/* 0x2A */
+	u16	misc_cfg;	/* 0x2B */
+	u16	masksoc;	/* 0x32 */
+
+	/* MG3 save and restore */
+	u16	fullcap;	/* 0x10 */
+	u16	fullcapnom;	/* 0x23 */
+	u16	socempty;	/* 0x33 */
+	u16	lavg_empty;	/* 0x36 */
+	u16	dqacc;		/* 0x45 */
+	u16	dpacc;		/* 0x46 */
+
+	/* Cell technology from power_supply.h */
+	u16	cell_technology;
+
+	/* Cell Data */
+	u16	vempty;		/* 0x12 */
+	u16	temp_nom;	/* 0x24 */
+	u16	temp_lim;	/* 0x25 */
+	u16	fctc;		/* 0x37 */
+	u16	rcomp0;		/* 0x38 */
+	u16	tcompc0;	/* 0x39 */
+	u16	empty_tempco;	/* 0x3A */
+	u16	kempty0;	/* 0x3B */
+	u16	cell_char_tbl[MAX17042_CHARACTERIZATION_DATA_SIZE];
+} __packed;
+
 struct max17042_platform_data {
 	struct max17042_reg_data *init_data;
+	struct max17042_config_data *config_data;
 	int num_init_data; /* Number of enties in init_data array */
 	bool enable_current_sense;
+	bool enable_por_init; /* Use POR init from Maxim appnote */
 
 	/*
 	 * R_sns in micro-ohms.
diff --git a/include/linux/power/smb347-charger.h b/include/linux/power/smb347-charger.h
new file mode 100644
index 0000000..b3cb20d
--- /dev/null
+++ b/include/linux/power/smb347-charger.h
@@ -0,0 +1,117 @@
+/*
+ * Summit Microelectronics SMB347 Battery Charger Driver
+ *
+ * Copyright (C) 2011, Intel Corporation
+ *
+ * Authors: Bruce E. Robertson <bruce.e.robertson@intel.com>
+ *          Mika Westerberg <mika.westerberg@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SMB347_CHARGER_H
+#define SMB347_CHARGER_H
+
+#include <linux/types.h>
+#include <linux/power_supply.h>
+
+enum {
+	/* use the default compensation method */
+	SMB347_SOFT_TEMP_COMPENSATE_DEFAULT = -1,
+
+	SMB347_SOFT_TEMP_COMPENSATE_NONE,
+	SMB347_SOFT_TEMP_COMPENSATE_CURRENT,
+	SMB347_SOFT_TEMP_COMPENSATE_VOLTAGE,
+};
+
+/* Use default factory programmed value for hard/soft temperature limit */
+#define SMB347_TEMP_USE_DEFAULT		-273
+
+/*
+ * Charging enable can be controlled by software (via i2c) by
+ * smb347-charger driver or by EN pin (active low/high).
+ */
+enum smb347_chg_enable {
+	SMB347_CHG_ENABLE_SW,
+	SMB347_CHG_ENABLE_PIN_ACTIVE_LOW,
+	SMB347_CHG_ENABLE_PIN_ACTIVE_HIGH,
+};
+
+/**
+ * struct smb347_charger_platform_data - platform data for SMB347 charger
+ * @battery_info: Information about the battery
+ * @max_charge_current: maximum current (in uA) the battery can be charged
+ * @max_charge_voltage: maximum voltage (in uV) the battery can be charged
+ * @pre_charge_current: current (in uA) to use in pre-charging phase
+ * @termination_current: current (in uA) used to determine when the
+ *			 charging cycle terminates
+ * @pre_to_fast_voltage: voltage (in uV) treshold used for transitioning to
+ *			 pre-charge to fast charge mode
+ * @mains_current_limit: maximum input current drawn from AC/DC input (in uA)
+ * @usb_hc_current_limit: maximum input high current (in uA) drawn from USB
+ *			  input
+ * @chip_temp_threshold: die temperature where device starts limiting charge
+ *			 current [%100 - %130] (in degree C)
+ * @soft_cold_temp_limit: soft cold temperature limit [%0 - %15] (in degree C),
+ *			  granularity is 5 deg C.
+ * @soft_hot_temp_limit: soft hot temperature limit [%40 - %55] (in degree  C),
+ *			 granularity is 5 deg C.
+ * @hard_cold_temp_limit: hard cold temperature limit [%-5 - %10] (in degree C),
+ *			  granularity is 5 deg C.
+ * @hard_hot_temp_limit: hard hot temperature limit [%50 - %65] (in degree C),
+ *			 granularity is 5 deg C.
+ * @suspend_on_hard_temp_limit: suspend charging when hard limit is hit
+ * @soft_temp_limit_compensation: compensation method when soft temperature
+ *				  limit is hit
+ * @charge_current_compensation: current (in uA) for charging compensation
+ *				 current when temperature hits soft limits
+ * @use_mains: AC/DC input can be used
+ * @use_usb: USB input can be used
+ * @use_usb_otg: USB OTG output can be used (not implemented yet)
+ * @irq_gpio: GPIO number used for interrupts (%-1 if not used)
+ * @enable_control: how charging enable/disable is controlled
+ *		    (driver/pin controls)
+ *
+ * @use_main, @use_usb, and @use_usb_otg are means to enable/disable
+ * hardware support for these. This is useful when we want to have for
+ * example OTG charging controlled via OTG transceiver driver and not by
+ * the SMB347 hardware.
+ *
+ * Hard and soft temperature limit values are given as described in the
+ * device data sheet and assuming NTC beta value is %3750. Even if this is
+ * not the case, these values should be used. They can be mapped to the
+ * corresponding NTC beta values with the help of table %2 in the data
+ * sheet. So for example if NTC beta is %3375 and we want to program hard
+ * hot limit to be %53 deg C, @hard_hot_temp_limit should be set to %50.
+ *
+ * If zero value is given in any of the current and voltage values, the
+ * factory programmed default will be used. For soft/hard temperature
+ * values, pass in %SMB347_TEMP_USE_DEFAULT instead.
+ */
+struct smb347_charger_platform_data {
+	struct power_supply_info battery_info;
+	unsigned int	max_charge_current;
+	unsigned int	max_charge_voltage;
+	unsigned int	pre_charge_current;
+	unsigned int	termination_current;
+	unsigned int	pre_to_fast_voltage;
+	unsigned int	mains_current_limit;
+	unsigned int	usb_hc_current_limit;
+	unsigned int	chip_temp_threshold;
+	int		soft_cold_temp_limit;
+	int		soft_hot_temp_limit;
+	int		hard_cold_temp_limit;
+	int		hard_hot_temp_limit;
+	bool		suspend_on_hard_temp_limit;
+	unsigned int	soft_temp_limit_compensation;
+	unsigned int	charge_current_compensation;
+	bool		use_mains;
+	bool		use_usb;
+	bool		use_usb_otg;
+	int		irq_gpio;
+	enum smb347_chg_enable enable_control;
+};
+
+#endif /* SMB347_CHARGER_H */
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index fa9b962..c38c13d 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -13,10 +13,11 @@
 #ifndef __LINUX_POWER_SUPPLY_H__
 #define __LINUX_POWER_SUPPLY_H__
 
-#include <linux/device.h>
 #include <linux/workqueue.h>
 #include <linux/leds.h>
 
+struct device;
+
 /*
  * All voltages, currents, charges, energies, time and temperatures in uV,
  * µA, µAh, µWh, seconds and tenths of degree Celsius unless otherwise
diff --git a/include/linux/prctl.h b/include/linux/prctl.h
index a0413ac..e0cfec2 100644
--- a/include/linux/prctl.h
+++ b/include/linux/prctl.h
@@ -121,4 +121,7 @@
 #define PR_SET_PTRACER 0x59616d61
 # define PR_SET_PTRACER_ANY ((unsigned long)-1)
 
+#define PR_SET_CHILD_SUBREAPER 36
+#define PR_GET_CHILD_SUBREAPER 37
+
 #endif /* _LINUX_PRCTL_H */
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index c2f1f6a..5c71962 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -51,20 +51,6 @@
 #define PTRACE_INTERRUPT	0x4207
 #define PTRACE_LISTEN		0x4208
 
-/* flags in @data for PTRACE_SEIZE */
-#define PTRACE_SEIZE_DEVEL	0x80000000 /* temp flag for development */
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD	0x00000001
-#define PTRACE_O_TRACEFORK	0x00000002
-#define PTRACE_O_TRACEVFORK	0x00000004
-#define PTRACE_O_TRACECLONE	0x00000008
-#define PTRACE_O_TRACEEXEC	0x00000010
-#define PTRACE_O_TRACEVFORKDONE	0x00000020
-#define PTRACE_O_TRACEEXIT	0x00000040
-
-#define PTRACE_O_MASK		0x0000007f
-
 /* Wait extended result codes for the above trace options.  */
 #define PTRACE_EVENT_FORK	1
 #define PTRACE_EVENT_VFORK	2
@@ -72,7 +58,19 @@
 #define PTRACE_EVENT_EXEC	4
 #define PTRACE_EVENT_VFORK_DONE	5
 #define PTRACE_EVENT_EXIT	6
-#define PTRACE_EVENT_STOP	7
+/* Extended result codes which enabled by means other than options.  */
+#define PTRACE_EVENT_STOP	128
+
+/* Options set using PTRACE_SETOPTIONS or using PTRACE_SEIZE @data param */
+#define PTRACE_O_TRACESYSGOOD	1
+#define PTRACE_O_TRACEFORK	(1 << PTRACE_EVENT_FORK)
+#define PTRACE_O_TRACEVFORK	(1 << PTRACE_EVENT_VFORK)
+#define PTRACE_O_TRACECLONE	(1 << PTRACE_EVENT_CLONE)
+#define PTRACE_O_TRACEEXEC	(1 << PTRACE_EVENT_EXEC)
+#define PTRACE_O_TRACEVFORKDONE	(1 << PTRACE_EVENT_VFORK_DONE)
+#define PTRACE_O_TRACEEXIT	(1 << PTRACE_EVENT_EXIT)
+
+#define PTRACE_O_MASK		0x0000007f
 
 #include <asm/ptrace.h>
 
@@ -88,13 +86,12 @@
 #define PT_SEIZED	0x00010000	/* SEIZE used, enable new behavior */
 #define PT_PTRACED	0x00000001
 #define PT_DTRACE	0x00000002	/* delayed trace (used on m68k, i386) */
-#define PT_TRACESYSGOOD	0x00000004
-#define PT_PTRACE_CAP	0x00000008	/* ptracer can follow suid-exec */
+#define PT_PTRACE_CAP	0x00000004	/* ptracer can follow suid-exec */
 
+#define PT_OPT_FLAG_SHIFT	3
 /* PT_TRACE_* event enable flags */
-#define PT_EVENT_FLAG_SHIFT	4
-#define PT_EVENT_FLAG(event)	(1 << (PT_EVENT_FLAG_SHIFT + (event) - 1))
-
+#define PT_EVENT_FLAG(event)	(1 << (PT_OPT_FLAG_SHIFT + (event)))
+#define PT_TRACESYSGOOD		PT_EVENT_FLAG(0)
 #define PT_TRACE_FORK		PT_EVENT_FLAG(PTRACE_EVENT_FORK)
 #define PT_TRACE_VFORK		PT_EVENT_FLAG(PTRACE_EVENT_VFORK)
 #define PT_TRACE_CLONE		PT_EVENT_FLAG(PTRACE_EVENT_CLONE)
@@ -102,8 +99,6 @@
 #define PT_TRACE_VFORK_DONE	PT_EVENT_FLAG(PTRACE_EVENT_VFORK_DONE)
 #define PT_TRACE_EXIT		PT_EVENT_FLAG(PTRACE_EVENT_EXIT)
 
-#define PT_TRACE_MASK	0x000003f4
-
 /* single stepping state bits (used on ARM and PA-RISC) */
 #define PT_SINGLESTEP_BIT	31
 #define PT_SINGLESTEP		(1<<PT_SINGLESTEP_BIT)
@@ -113,6 +108,7 @@
 #include <linux/compiler.h>		/* For unlikely.  */
 #include <linux/sched.h>		/* For struct task_struct.  */
 #include <linux/err.h>			/* for IS_ERR_VALUE */
+#include <linux/bug.h>			/* For BUG_ON.  */
 
 
 extern long arch_ptrace(struct task_struct *child, long request,
@@ -199,9 +195,10 @@
 	if (unlikely(ptrace_event_enabled(current, event))) {
 		current->ptrace_message = message;
 		ptrace_notify((event << 8) | SIGTRAP);
-	} else if (event == PTRACE_EVENT_EXEC && unlikely(current->ptrace)) {
+	} else if (event == PTRACE_EVENT_EXEC) {
 		/* legacy EXEC report via SIGTRAP */
-		send_sig(SIGTRAP, current, 0);
+		if ((current->ptrace & (PT_PTRACED|PT_SEIZED)) == PT_PTRACED)
+			send_sig(SIGTRAP, current, 0);
 	}
 }
 
diff --git a/include/linux/qnx6_fs.h b/include/linux/qnx6_fs.h
new file mode 100644
index 0000000..26049ea
--- /dev/null
+++ b/include/linux/qnx6_fs.h
@@ -0,0 +1,134 @@
+/*
+ *  Name                 : qnx6_fs.h
+ *  Author               : Kai Bankett
+ *  Function             : qnx6 global filesystem definitions
+ *  History              : 17-01-2012 created
+ */
+#ifndef _LINUX_QNX6_FS_H
+#define _LINUX_QNX6_FS_H
+
+#include <linux/types.h>
+#include <linux/magic.h>
+
+#define QNX6_ROOT_INO 1
+
+/* for di_status */
+#define QNX6_FILE_DIRECTORY	0x01
+#define QNX6_FILE_DELETED	0x02
+#define QNX6_FILE_NORMAL	0x03
+
+#define QNX6_SUPERBLOCK_SIZE	0x200	/* superblock always is 512 bytes */
+#define QNX6_SUPERBLOCK_AREA	0x1000	/* area reserved for superblock */
+#define	QNX6_BOOTBLOCK_SIZE	0x2000	/* heading bootblock area */
+#define QNX6_DIR_ENTRY_SIZE	0x20	/* dir entry size of 32 bytes */
+#define QNX6_INODE_SIZE		0x80	/* each inode is 128 bytes */
+#define QNX6_INODE_SIZE_BITS	7	/* inode entry size shift */
+
+#define QNX6_NO_DIRECT_POINTERS	16	/* 16 blockptrs in sbl/inode */
+#define QNX6_PTR_MAX_LEVELS	5	/* maximum indirect levels */
+
+/* for filenames */
+#define QNX6_SHORT_NAME_MAX	27
+#define QNX6_LONG_NAME_MAX	510
+
+/* list of mount options */
+#define QNX6_MOUNT_MMI_FS	0x010000 /* mount as Audi MMI 3G fs */
+
+/*
+ * This is the original qnx6 inode layout on disk.
+ * Each inode is 128 byte long.
+ */
+struct qnx6_inode_entry {
+	__fs64		di_size;
+	__fs32		di_uid;
+	__fs32		di_gid;
+	__fs32		di_ftime;
+	__fs32		di_mtime;
+	__fs32		di_atime;
+	__fs32		di_ctime;
+	__fs16		di_mode;
+	__fs16		di_ext_mode;
+	__fs32		di_block_ptr[QNX6_NO_DIRECT_POINTERS];
+	__u8		di_filelevels;
+	__u8		di_status;
+	__u8		di_unknown2[2];
+	__fs32		di_zero2[6];
+};
+
+/*
+ * Each directory entry is maximum 32 bytes long.
+ * If more characters or special characters required it is stored
+ * in the longfilenames structure.
+ */
+struct qnx6_dir_entry {
+	__fs32		de_inode;
+	__u8		de_size;
+	char		de_fname[QNX6_SHORT_NAME_MAX];
+};
+
+/*
+ * Longfilename direntries have a different structure
+ */
+struct qnx6_long_dir_entry {
+	__fs32		de_inode;
+	__u8		de_size;
+	__u8		de_unknown[3];
+	__fs32		de_long_inode;
+	__fs32		de_checksum;
+};
+
+struct qnx6_long_filename {
+	__fs16		lf_size;
+	__u8		lf_fname[QNX6_LONG_NAME_MAX];
+};
+
+struct qnx6_root_node {
+	__fs64		size;
+	__fs32		ptr[QNX6_NO_DIRECT_POINTERS];
+	__u8		levels;
+	__u8		mode;
+	__u8		spare[6];
+};
+
+struct qnx6_super_block {
+	__fs32		sb_magic;
+	__fs32		sb_checksum;
+	__fs64		sb_serial;
+	__fs32		sb_ctime;	/* time the fs was created */
+	__fs32		sb_atime;	/* last access time */
+	__fs32		sb_flags;
+	__fs16		sb_version1;	/* filesystem version information */
+	__fs16		sb_version2;	/* filesystem version information */
+	__u8		sb_volumeid[16];
+	__fs32		sb_blocksize;
+	__fs32		sb_num_inodes;
+	__fs32		sb_free_inodes;
+	__fs32		sb_num_blocks;
+	__fs32		sb_free_blocks;
+	__fs32		sb_allocgroup;
+	struct qnx6_root_node Inode;
+	struct qnx6_root_node Bitmap;
+	struct qnx6_root_node Longfile;
+	struct qnx6_root_node Unknown;
+};
+
+/* Audi MMI 3G superblock layout is different to plain qnx6 */
+struct qnx6_mmi_super_block {
+	__fs32		sb_magic;
+	__fs32		sb_checksum;
+	__fs64		sb_serial;
+	__u8		sb_spare0[12];
+	__u8		sb_id[12];
+	__fs32		sb_blocksize;
+	__fs32		sb_num_inodes;
+	__fs32		sb_free_inodes;
+	__fs32		sb_num_blocks;
+	__fs32		sb_free_blocks;
+	__u8		sb_spare1[4];
+	struct qnx6_root_node Inode;
+	struct qnx6_root_node Bitmap;
+	struct qnx6_root_node Longfile;
+	struct qnx6_root_node Unknown;
+};
+
+#endif
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index 07e360b..0d04cd6 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -2,6 +2,7 @@
  * Copyright (C) 2001 Momchil Velikov
  * Portions Copyright (C) 2001 Christoph Hellwig
  * Copyright (C) 2006 Nick Piggin
+ * Copyright (C) 2012 Konstantin Khlebnikov
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -22,6 +23,7 @@
 
 #include <linux/preempt.h>
 #include <linux/types.h>
+#include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/rcupdate.h>
 
@@ -256,4 +258,199 @@
 	preempt_enable();
 }
 
+/**
+ * struct radix_tree_iter - radix tree iterator state
+ *
+ * @index:	index of current slot
+ * @next_index:	next-to-last index for this chunk
+ * @tags:	bit-mask for tag-iterating
+ *
+ * This radix tree iterator works in terms of "chunks" of slots.  A chunk is a
+ * subinterval of slots contained within one radix tree leaf node.  It is
+ * described by a pointer to its first slot and a struct radix_tree_iter
+ * which holds the chunk's position in the tree and its size.  For tagged
+ * iteration radix_tree_iter also holds the slots' bit-mask for one chosen
+ * radix tree tag.
+ */
+struct radix_tree_iter {
+	unsigned long	index;
+	unsigned long	next_index;
+	unsigned long	tags;
+};
+
+#define RADIX_TREE_ITER_TAG_MASK	0x00FF	/* tag index in lower byte */
+#define RADIX_TREE_ITER_TAGGED		0x0100	/* lookup tagged slots */
+#define RADIX_TREE_ITER_CONTIG		0x0200	/* stop at first hole */
+
+/**
+ * radix_tree_iter_init - initialize radix tree iterator
+ *
+ * @iter:	pointer to iterator state
+ * @start:	iteration starting index
+ * Returns:	NULL
+ */
+static __always_inline void **
+radix_tree_iter_init(struct radix_tree_iter *iter, unsigned long start)
+{
+	/*
+	 * Leave iter->tags uninitialized. radix_tree_next_chunk() will fill it
+	 * in the case of a successful tagged chunk lookup.  If the lookup was
+	 * unsuccessful or non-tagged then nobody cares about ->tags.
+	 *
+	 * Set index to zero to bypass next_index overflow protection.
+	 * See the comment in radix_tree_next_chunk() for details.
+	 */
+	iter->index = 0;
+	iter->next_index = start;
+	return NULL;
+}
+
+/**
+ * radix_tree_next_chunk - find next chunk of slots for iteration
+ *
+ * @root:	radix tree root
+ * @iter:	iterator state
+ * @flags:	RADIX_TREE_ITER_* flags and tag index
+ * Returns:	pointer to chunk first slot, or NULL if there no more left
+ *
+ * This function looks up the next chunk in the radix tree starting from
+ * @iter->next_index.  It returns a pointer to the chunk's first slot.
+ * Also it fills @iter with data about chunk: position in the tree (index),
+ * its end (next_index), and constructs a bit mask for tagged iterating (tags).
+ */
+void **radix_tree_next_chunk(struct radix_tree_root *root,
+			     struct radix_tree_iter *iter, unsigned flags);
+
+/**
+ * radix_tree_chunk_size - get current chunk size
+ *
+ * @iter:	pointer to radix tree iterator
+ * Returns:	current chunk size
+ */
+static __always_inline unsigned
+radix_tree_chunk_size(struct radix_tree_iter *iter)
+{
+	return iter->next_index - iter->index;
+}
+
+/**
+ * radix_tree_next_slot - find next slot in chunk
+ *
+ * @slot:	pointer to current slot
+ * @iter:	pointer to interator state
+ * @flags:	RADIX_TREE_ITER_*, should be constant
+ * Returns:	pointer to next slot, or NULL if there no more left
+ *
+ * This function updates @iter->index in the case of a successful lookup.
+ * For tagged lookup it also eats @iter->tags.
+ */
+static __always_inline void **
+radix_tree_next_slot(void **slot, struct radix_tree_iter *iter, unsigned flags)
+{
+	if (flags & RADIX_TREE_ITER_TAGGED) {
+		iter->tags >>= 1;
+		if (likely(iter->tags & 1ul)) {
+			iter->index++;
+			return slot + 1;
+		}
+		if (!(flags & RADIX_TREE_ITER_CONTIG) && likely(iter->tags)) {
+			unsigned offset = __ffs(iter->tags);
+
+			iter->tags >>= offset;
+			iter->index += offset + 1;
+			return slot + offset + 1;
+		}
+	} else {
+		unsigned size = radix_tree_chunk_size(iter) - 1;
+
+		while (size--) {
+			slot++;
+			iter->index++;
+			if (likely(*slot))
+				return slot;
+			if (flags & RADIX_TREE_ITER_CONTIG)
+				break;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * radix_tree_for_each_chunk - iterate over chunks
+ *
+ * @slot:	the void** variable for pointer to chunk first slot
+ * @root:	the struct radix_tree_root pointer
+ * @iter:	the struct radix_tree_iter pointer
+ * @start:	iteration starting index
+ * @flags:	RADIX_TREE_ITER_* and tag index
+ *
+ * Locks can be released and reacquired between iterations.
+ */
+#define radix_tree_for_each_chunk(slot, root, iter, start, flags)	\
+	for (slot = radix_tree_iter_init(iter, start) ;			\
+	      (slot = radix_tree_next_chunk(root, iter, flags)) ;)
+
+/**
+ * radix_tree_for_each_chunk_slot - iterate over slots in one chunk
+ *
+ * @slot:	the void** variable, at the beginning points to chunk first slot
+ * @iter:	the struct radix_tree_iter pointer
+ * @flags:	RADIX_TREE_ITER_*, should be constant
+ *
+ * This macro is designed to be nested inside radix_tree_for_each_chunk().
+ * @slot points to the radix tree slot, @iter->index contains its index.
+ */
+#define radix_tree_for_each_chunk_slot(slot, iter, flags)		\
+	for (; slot ; slot = radix_tree_next_slot(slot, iter, flags))
+
+/**
+ * radix_tree_for_each_slot - iterate over non-empty slots
+ *
+ * @slot:	the void** variable for pointer to slot
+ * @root:	the struct radix_tree_root pointer
+ * @iter:	the struct radix_tree_iter pointer
+ * @start:	iteration starting index
+ *
+ * @slot points to radix tree slot, @iter->index contains its index.
+ */
+#define radix_tree_for_each_slot(slot, root, iter, start)		\
+	for (slot = radix_tree_iter_init(iter, start) ;			\
+	     slot || (slot = radix_tree_next_chunk(root, iter, 0)) ;	\
+	     slot = radix_tree_next_slot(slot, iter, 0))
+
+/**
+ * radix_tree_for_each_contig - iterate over contiguous slots
+ *
+ * @slot:	the void** variable for pointer to slot
+ * @root:	the struct radix_tree_root pointer
+ * @iter:	the struct radix_tree_iter pointer
+ * @start:	iteration starting index
+ *
+ * @slot points to radix tree slot, @iter->index contains its index.
+ */
+#define radix_tree_for_each_contig(slot, root, iter, start)		\
+	for (slot = radix_tree_iter_init(iter, start) ;			\
+	     slot || (slot = radix_tree_next_chunk(root, iter,		\
+				RADIX_TREE_ITER_CONTIG)) ;		\
+	     slot = radix_tree_next_slot(slot, iter,			\
+				RADIX_TREE_ITER_CONTIG))
+
+/**
+ * radix_tree_for_each_tagged - iterate over tagged slots
+ *
+ * @slot:	the void** variable for pointer to slot
+ * @root:	the struct radix_tree_root pointer
+ * @iter:	the struct radix_tree_iter pointer
+ * @start:	iteration starting index
+ * @tag:	tag index
+ *
+ * @slot points to radix tree slot, @iter->index contains its index.
+ */
+#define radix_tree_for_each_tagged(slot, root, iter, start, tag)	\
+	for (slot = radix_tree_iter_init(iter, start) ;			\
+	     slot || (slot = radix_tree_next_chunk(root, iter,		\
+			      RADIX_TREE_ITER_TAGGED | tag)) ;		\
+	     slot = radix_tree_next_slot(slot, iter,			\
+				RADIX_TREE_ITER_TAGGED))
+
 #endif /* _LINUX_RADIX_TREE_H */
diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h
index 6f6df86..8c0a3ad 100644
--- a/include/linux/raid/md_p.h
+++ b/include/linux/raid/md_p.h
@@ -281,6 +281,10 @@
 					    * active device with same 'role'.
 					    * 'recovery_offset' is also set.
 					    */
-#define	MD_FEATURE_ALL			(1|2|4|8|16)
+#define	MD_FEATURE_ALL			(MD_FEATURE_BITMAP_OFFSET	\
+					|MD_FEATURE_RECOVERY_OFFSET	\
+					|MD_FEATURE_RESHAPE_ACTIVE	\
+					|MD_FEATURE_BAD_BLOCKS		\
+					|MD_FEATURE_REPLACEMENT)
 
 #endif 
diff --git a/include/linux/rar_register.h b/include/linux/rar_register.h
deleted file mode 100644
index 5c61181..0000000
--- a/include/linux/rar_register.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2010 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General
- * Public License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA  02111-1307, USA.
- * The full GNU General Public License is included in this
- * distribution in the file called COPYING.
- */
-
-
-#ifndef _RAR_REGISTER_H
-#define _RAR_REGISTER_H
-
-#include <linux/types.h>
-
-/* following are used both in drivers as well as user space apps */
-
-#define	RAR_TYPE_VIDEO	0
-#define	RAR_TYPE_AUDIO	1
-#define	RAR_TYPE_IMAGE	2
-#define	RAR_TYPE_DATA	3
-
-#ifdef __KERNEL__
-
-struct rar_device;
-
-#if defined(CONFIG_RAR_REGISTER)
-int register_rar(int num,
-		int (*callback)(unsigned long data), unsigned long data);
-void unregister_rar(int num);
-int rar_get_address(int rar_index, dma_addr_t *start, dma_addr_t *end);
-int rar_lock(int rar_index);
-#else
-extern void unregister_rar(int num)  { }
-extern int rar_lock(int rar_index) { return -EIO; }
-
-extern inline int register_rar(int num,
-		int (*callback)(unsigned long data), unsigned long data)
-{
-	return -ENODEV;
-}
-
-extern int rar_get_address(int rar_index, dma_addr_t *start, dma_addr_t *end)
-{
-	return -ENODEV;
-}
-#endif	/* RAR_REGISTER */
-
-#endif  /* __KERNEL__ */
-#endif  /* _RAR_REGISTER_H */
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 9372174..20fb776 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -42,6 +42,7 @@
 #include <linux/lockdep.h>
 #include <linux/completion.h>
 #include <linux/debugobjects.h>
+#include <linux/bug.h>
 #include <linux/compiler.h>
 
 #ifdef CONFIG_RCU_TORTURE_TEST
@@ -418,7 +419,7 @@
  */
 #define rcu_lockdep_assert(c, s)					\
 	do {								\
-		static bool __warned;					\
+		static bool __section(.data.unlikely) __warned;		\
 		if (debug_lockdep_rcu_enabled() && !__warned && !(c)) {	\
 			__warned = true;				\
 			lockdep_rcu_suspicious(__FILE__, __LINE__, s);	\
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index eb93921..a90abb6 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -13,12 +13,13 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/device.h>
 #include <linux/list.h>
 
 struct module;
+struct device;
 struct i2c_client;
 struct spi_device;
+struct regmap;
 
 /* An enum of all the supported cache types */
 enum regcache_type {
@@ -40,10 +41,13 @@
 	unsigned int def;
 };
 
+#ifdef CONFIG_REGMAP
+
 /**
  * Configuration for the register map of a device.
  *
  * @reg_bits: Number of bits in a register address, mandatory.
+ * @pad_bits: Number of bits of padding between register and value.
  * @val_bits: Number of bits in a register value, mandatory.
  *
  * @writeable_reg: Optional callback returning true if the register
@@ -74,6 +78,7 @@
  */
 struct regmap_config {
 	int reg_bits;
+	int pad_bits;
 	int val_bits;
 
 	bool (*writeable_reg)(struct device *dev, unsigned int reg);
@@ -127,12 +132,22 @@
 struct regmap *regmap_init_spi(struct spi_device *dev,
 			       const struct regmap_config *config);
 
+struct regmap *devm_regmap_init(struct device *dev,
+				const struct regmap_bus *bus,
+				const struct regmap_config *config);
+struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
+				    const struct regmap_config *config);
+struct regmap *devm_regmap_init_spi(struct spi_device *dev,
+				    const struct regmap_config *config);
+
 void regmap_exit(struct regmap *map);
 int regmap_reinit_cache(struct regmap *map,
 			const struct regmap_config *config);
 int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);
 int regmap_raw_write(struct regmap *map, unsigned int reg,
 		     const void *val, size_t val_len);
+int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
+			size_t val_count);
 int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);
 int regmap_raw_read(struct regmap *map, unsigned int reg,
 		    void *val, size_t val_len);
@@ -143,12 +158,18 @@
 int regmap_update_bits_check(struct regmap *map, unsigned int reg,
 			     unsigned int mask, unsigned int val,
 			     bool *change);
+int regmap_get_val_bytes(struct regmap *map);
 
 int regcache_sync(struct regmap *map);
+int regcache_sync_region(struct regmap *map, unsigned int min,
+			 unsigned int max);
 void regcache_cache_only(struct regmap *map, bool enable);
 void regcache_cache_bypass(struct regmap *map, bool enable);
 void regcache_mark_dirty(struct regmap *map);
 
+int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
+			  int num_regs);
+
 /**
  * Description of an IRQ for the generic regmap irq_chip.
  *
@@ -197,4 +218,115 @@
 void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);
 int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data);
 
+#else
+
+/*
+ * These stubs should only ever be called by generic code which has
+ * regmap based facilities, if they ever get called at runtime
+ * something is going wrong and something probably needs to select
+ * REGMAP.
+ */
+
+static inline int regmap_write(struct regmap *map, unsigned int reg,
+			       unsigned int val)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
+static inline int regmap_raw_write(struct regmap *map, unsigned int reg,
+				   const void *val, size_t val_len)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
+static inline int regmap_bulk_write(struct regmap *map, unsigned int reg,
+				    const void *val, size_t val_count)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
+static inline int regmap_read(struct regmap *map, unsigned int reg,
+			      unsigned int *val)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
+static inline int regmap_raw_read(struct regmap *map, unsigned int reg,
+				  void *val, size_t val_len)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
+static inline int regmap_bulk_read(struct regmap *map, unsigned int reg,
+				   void *val, size_t val_count)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
+static inline int regmap_update_bits(struct regmap *map, unsigned int reg,
+				     unsigned int mask, unsigned int val)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
+static inline int regmap_update_bits_check(struct regmap *map,
+					   unsigned int reg,
+					   unsigned int mask, unsigned int val,
+					   bool *change)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
+static inline int regmap_get_val_bytes(struct regmap *map)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
+static inline int regcache_sync(struct regmap *map)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
+static inline int regcache_sync_region(struct regmap *map, unsigned int min,
+				       unsigned int max)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
+static inline void regcache_cache_only(struct regmap *map, bool enable)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+}
+
+static inline void regcache_cache_bypass(struct regmap *map, bool enable)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+}
+
+static inline void regcache_mark_dirty(struct regmap *map)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+}
+
+static inline int regmap_register_patch(struct regmap *map,
+					const struct reg_default *regs,
+					int num_regs)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
+#endif
+
 #endif
diff --git a/include/linux/regset.h b/include/linux/regset.h
index 686f373..8e0c9fe 100644
--- a/include/linux/regset.h
+++ b/include/linux/regset.h
@@ -15,6 +15,7 @@
 
 #include <linux/compiler.h>
 #include <linux/types.h>
+#include <linux/bug.h>
 #include <linux/uaccess.h>
 struct task_struct;
 struct user_regset;
diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h
index 76579f9..7bd73bb 100644
--- a/include/linux/regulator/ab8500.h
+++ b/include/linux/regulator/ab8500.h
@@ -26,7 +26,26 @@
 	AB8500_NUM_REGULATORS,
 };
 
-/* AB8500 register initialization */
+/* AB9450 regulators */
+enum ab9540_regulator_id {
+	AB9540_LDO_AUX1,
+	AB9540_LDO_AUX2,
+	AB9540_LDO_AUX3,
+	AB9540_LDO_AUX4,
+	AB9540_LDO_INTCORE,
+	AB9540_LDO_TVOUT,
+	AB9540_LDO_USB,
+	AB9540_LDO_AUDIO,
+	AB9540_LDO_ANAMIC1,
+	AB9540_LDO_ANAMIC2,
+	AB9540_LDO_DMIC,
+	AB9540_LDO_ANA,
+	AB9540_SYSCLKREQ_2,
+	AB9540_SYSCLKREQ_4,
+	AB9540_NUM_REGULATORS,
+};
+
+/* AB8500 and AB9540 register initialization */
 struct ab8500_regulator_reg_init {
 	int id;
 	u8 value;
@@ -71,4 +90,53 @@
 	AB8500_NUM_REGULATOR_REGISTERS,
 };
 
+
+/* AB9540 registers */
+enum ab9540_regulator_reg {
+	AB9540_REGUREQUESTCTRL1,
+	AB9540_REGUREQUESTCTRL2,
+	AB9540_REGUREQUESTCTRL3,
+	AB9540_REGUREQUESTCTRL4,
+	AB9540_REGUSYSCLKREQ1HPVALID1,
+	AB9540_REGUSYSCLKREQ1HPVALID2,
+	AB9540_REGUHWHPREQ1VALID1,
+	AB9540_REGUHWHPREQ1VALID2,
+	AB9540_REGUHWHPREQ2VALID1,
+	AB9540_REGUHWHPREQ2VALID2,
+	AB9540_REGUSWHPREQVALID1,
+	AB9540_REGUSWHPREQVALID2,
+	AB9540_REGUSYSCLKREQVALID1,
+	AB9540_REGUSYSCLKREQVALID2,
+	AB9540_REGUVAUX4REQVALID,
+	AB9540_REGUMISC1,
+	AB9540_VAUDIOSUPPLY,
+	AB9540_REGUCTRL1VAMIC,
+	AB9540_VSMPS1REGU,
+	AB9540_VSMPS2REGU,
+	AB9540_VSMPS3REGU, /* NOTE! PRCMU register */
+	AB9540_VPLLVANAREGU,
+	AB9540_EXTSUPPLYREGU,
+	AB9540_VAUX12REGU,
+	AB9540_VRF1VAUX3REGU,
+	AB9540_VSMPS1SEL1,
+	AB9540_VSMPS1SEL2,
+	AB9540_VSMPS1SEL3,
+	AB9540_VSMPS2SEL1,
+	AB9540_VSMPS2SEL2,
+	AB9540_VSMPS2SEL3,
+	AB9540_VSMPS3SEL1, /* NOTE! PRCMU register */
+	AB9540_VSMPS3SEL2, /* NOTE! PRCMU register */
+	AB9540_VAUX1SEL,
+	AB9540_VAUX2SEL,
+	AB9540_VRF1VAUX3SEL,
+	AB9540_REGUCTRL2SPARE,
+	AB9540_VAUX4REQCTRL,
+	AB9540_VAUX4REGU,
+	AB9540_VAUX4SEL,
+	AB9540_REGUCTRLDISCH,
+	AB9540_REGUCTRLDISCH2,
+	AB9540_REGUCTRLDISCH3,
+	AB9540_NUM_REGULATOR_REGISTERS,
+};
+
 #endif
diff --git a/include/linux/regulator/bq24022.h b/include/linux/regulator/bq24022.h
deleted file mode 100644
index a6d0140..0000000
--- a/include/linux/regulator/bq24022.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Support for TI bq24022 (bqTINY-II) Dual Input (USB/AC Adpater)
- * 1-Cell Li-Ion Charger connected via GPIOs.
- *
- * Copyright (c) 2008 Philipp Zabel
- *
- * 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 regulator_init_data;
-
-/**
- * bq24022_mach_info - platform data for bq24022
- * @gpio_nce: GPIO line connected to the nCE pin, used to enable / disable charging
- * @gpio_iset2: GPIO line connected to the ISET2 pin, used to limit charging current to 100 mA / 500 mA
- */
-struct bq24022_mach_info {
-	int gpio_nce;
-	int gpio_iset2;
-	struct regulator_init_data *init_data;
-};
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index b6c8d71..4ed1b30 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -35,7 +35,8 @@
 #ifndef __LINUX_REGULATOR_CONSUMER_H_
 #define __LINUX_REGULATOR_CONSUMER_H_
 
-#include <linux/device.h>
+struct device;
+struct notifier_block;
 
 /*
  * Regulator operating modes.
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index 7abb160..b021084 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -71,7 +71,7 @@
  * @uV_offset: Offset applied to voltages from consumer to compensate for
  *             voltage drops.
  *
- * @min_uA: Smallest consumers consumers may set.
+ * @min_uA: Smallest current consumers may set.
  * @max_uA: Largest current consumers may set.
  *
  * @valid_modes_mask: Mask of modes which may be configured by consumers.
@@ -134,10 +134,8 @@
 /**
  * struct regulator_consumer_supply - supply -> device mapping
  *
- * This maps a supply name to a device.  Only one of dev or dev_name
- * can be specified.  Use of dev_name allows support for buses which
- * make struct device available late such as I2C and is the preferred
- * form.
+ * This maps a supply name to a device. Use of dev_name allows support for
+ * buses which make struct device available late such as I2C.
  *
  * @dev_name: Result of dev_name() for the consumer.
  * @supply: Name for the supply.
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
index 2213ddc..ea3700c 100644
--- a/include/linux/reiserfs_fs.h
+++ b/include/linux/reiserfs_fs.h
@@ -1,32 +1,12 @@
 /*
  * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details
  */
-
-				/* this file has an amazingly stupid
-				   name, yura please fix it to be
-				   reiserfs.h, and merge all the rest
-				   of our .h files that are in this
-				   directory into it.  */
-
 #ifndef _LINUX_REISER_FS_H
 #define _LINUX_REISER_FS_H
 
 #include <linux/types.h>
 #include <linux/magic.h>
 
-#ifdef __KERNEL__
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/workqueue.h>
-#include <asm/unaligned.h>
-#include <linux/bitops.h>
-#include <linux/proc_fs.h>
-#include <linux/buffer_head.h>
-#include <linux/reiserfs_fs_i.h>
-#include <linux/reiserfs_fs_sb.h>
-#endif
-
 /*
  *  include/linux/reiser_fs.h
  *
@@ -43,2318 +23,4 @@
 #define REISERFS_IOC_GETVERSION		FS_IOC_GETVERSION
 #define REISERFS_IOC_SETVERSION		FS_IOC_SETVERSION
 
-#ifdef __KERNEL__
-/* the 32 bit compat definitions with int argument */
-#define REISERFS_IOC32_UNPACK		_IOW(0xCD, 1, int)
-#define REISERFS_IOC32_GETFLAGS		FS_IOC32_GETFLAGS
-#define REISERFS_IOC32_SETFLAGS		FS_IOC32_SETFLAGS
-#define REISERFS_IOC32_GETVERSION	FS_IOC32_GETVERSION
-#define REISERFS_IOC32_SETVERSION	FS_IOC32_SETVERSION
-
-/*
- * Locking primitives. The write lock is a per superblock
- * special mutex that has properties close to the Big Kernel Lock
- * which was used in the previous locking scheme.
- */
-void reiserfs_write_lock(struct super_block *s);
-void reiserfs_write_unlock(struct super_block *s);
-int reiserfs_write_lock_once(struct super_block *s);
-void reiserfs_write_unlock_once(struct super_block *s, int lock_depth);
-
-#ifdef CONFIG_REISERFS_CHECK
-void reiserfs_lock_check_recursive(struct super_block *s);
-#else
-static inline void reiserfs_lock_check_recursive(struct super_block *s) { }
-#endif
-
-/*
- * Several mutexes depend on the write lock.
- * However sometimes we want to relax the write lock while we hold
- * these mutexes, according to the release/reacquire on schedule()
- * properties of the Bkl that were used.
- * Reiserfs performances and locking were based on this scheme.
- * Now that the write lock is a mutex and not the bkl anymore, doing so
- * may result in a deadlock:
- *
- * A acquire write_lock
- * A acquire j_commit_mutex
- * A release write_lock and wait for something
- * B acquire write_lock
- * B can't acquire j_commit_mutex and sleep
- * A can't acquire write lock anymore
- * deadlock
- *
- * What we do here is avoiding such deadlock by playing the same game
- * than the Bkl: if we can't acquire a mutex that depends on the write lock,
- * we release the write lock, wait a bit and then retry.
- *
- * The mutexes concerned by this hack are:
- * - The commit mutex of a journal list
- * - The flush mutex
- * - The journal lock
- * - The inode mutex
- */
-static inline void reiserfs_mutex_lock_safe(struct mutex *m,
-			       struct super_block *s)
-{
-	reiserfs_lock_check_recursive(s);
-	reiserfs_write_unlock(s);
-	mutex_lock(m);
-	reiserfs_write_lock(s);
-}
-
-static inline void
-reiserfs_mutex_lock_nested_safe(struct mutex *m, unsigned int subclass,
-			       struct super_block *s)
-{
-	reiserfs_lock_check_recursive(s);
-	reiserfs_write_unlock(s);
-	mutex_lock_nested(m, subclass);
-	reiserfs_write_lock(s);
-}
-
-static inline void
-reiserfs_down_read_safe(struct rw_semaphore *sem, struct super_block *s)
-{
-	reiserfs_lock_check_recursive(s);
-	reiserfs_write_unlock(s);
-	down_read(sem);
-	reiserfs_write_lock(s);
-}
-
-/*
- * When we schedule, we usually want to also release the write lock,
- * according to the previous bkl based locking scheme of reiserfs.
- */
-static inline void reiserfs_cond_resched(struct super_block *s)
-{
-	if (need_resched()) {
-		reiserfs_write_unlock(s);
-		schedule();
-		reiserfs_write_lock(s);
-	}
-}
-
-struct fid;
-
-/* in reading the #defines, it may help to understand that they employ
-   the following abbreviations:
-
-   B = Buffer
-   I = Item header
-   H = Height within the tree (should be changed to LEV)
-   N = Number of the item in the node
-   STAT = stat data
-   DEH = Directory Entry Header
-   EC = Entry Count
-   E = Entry number
-   UL = Unsigned Long
-   BLKH = BLocK Header
-   UNFM = UNForMatted node
-   DC = Disk Child
-   P = Path
-
-   These #defines are named by concatenating these abbreviations,
-   where first comes the arguments, and last comes the return value,
-   of the macro.
-
-*/
-
-#define USE_INODE_GENERATION_COUNTER
-
-#define REISERFS_PREALLOCATE
-#define DISPLACE_NEW_PACKING_LOCALITIES
-#define PREALLOCATION_SIZE 9
-
-/* n must be power of 2 */
-#define _ROUND_UP(x,n) (((x)+(n)-1u) & ~((n)-1u))
-
-// to be ok for alpha and others we have to align structures to 8 byte
-// boundary.
-// FIXME: do not change 4 by anything else: there is code which relies on that
-#define ROUND_UP(x) _ROUND_UP(x,8LL)
-
-/* debug levels.  Right now, CONFIG_REISERFS_CHECK means print all debug
-** messages.
-*/
-#define REISERFS_DEBUG_CODE 5	/* extra messages to help find/debug errors */
-
-void __reiserfs_warning(struct super_block *s, const char *id,
-			 const char *func, const char *fmt, ...);
-#define reiserfs_warning(s, id, fmt, args...) \
-	 __reiserfs_warning(s, id, __func__, fmt, ##args)
-/* assertions handling */
-
-/** always check a condition and panic if it's false. */
-#define __RASSERT(cond, scond, format, args...)			\
-do {									\
-	if (!(cond))							\
-		reiserfs_panic(NULL, "assertion failure", "(" #cond ") at " \
-			       __FILE__ ":%i:%s: " format "\n",		\
-			       in_interrupt() ? -1 : task_pid_nr(current), \
-			       __LINE__, __func__ , ##args);		\
-} while (0)
-
-#define RASSERT(cond, format, args...) __RASSERT(cond, #cond, format, ##args)
-
-#if defined( CONFIG_REISERFS_CHECK )
-#define RFALSE(cond, format, args...) __RASSERT(!(cond), "!(" #cond ")", format, ##args)
-#else
-#define RFALSE( cond, format, args... ) do {;} while( 0 )
-#endif
-
-#define CONSTF __attribute_const__
-/*
- * Disk Data Structures
- */
-
-/***************************************************************************/
-/*                             SUPER BLOCK                                 */
-/***************************************************************************/
-
-/*
- * Structure of super block on disk, a version of which in RAM is often accessed as REISERFS_SB(s)->s_rs
- * the version in RAM is part of a larger structure containing fields never written to disk.
- */
-#define UNSET_HASH 0		// read_super will guess about, what hash names
-		     // in directories were sorted with
-#define TEA_HASH  1
-#define YURA_HASH 2
-#define R5_HASH   3
-#define DEFAULT_HASH R5_HASH
-
-struct journal_params {
-	__le32 jp_journal_1st_block;	/* where does journal start from on its
-					 * device */
-	__le32 jp_journal_dev;	/* journal device st_rdev */
-	__le32 jp_journal_size;	/* size of the journal */
-	__le32 jp_journal_trans_max;	/* max number of blocks in a transaction. */
-	__le32 jp_journal_magic;	/* random value made on fs creation (this
-					 * was sb_journal_block_count) */
-	__le32 jp_journal_max_batch;	/* max number of blocks to batch into a
-					 * trans */
-	__le32 jp_journal_max_commit_age;	/* in seconds, how old can an async
-						 * commit be */
-	__le32 jp_journal_max_trans_age;	/* in seconds, how old can a transaction
-						 * be */
-};
-
-/* this is the super from 3.5.X, where X >= 10 */
-struct reiserfs_super_block_v1 {
-	__le32 s_block_count;	/* blocks count         */
-	__le32 s_free_blocks;	/* free blocks count    */
-	__le32 s_root_block;	/* root block number    */
-	struct journal_params s_journal;
-	__le16 s_blocksize;	/* block size */
-	__le16 s_oid_maxsize;	/* max size of object id array, see
-				 * get_objectid() commentary  */
-	__le16 s_oid_cursize;	/* current size of object id array */
-	__le16 s_umount_state;	/* this is set to 1 when filesystem was
-				 * umounted, to 2 - when not */
-	char s_magic[10];	/* reiserfs magic string indicates that
-				 * file system is reiserfs:
-				 * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
-	__le16 s_fs_state;	/* it is set to used by fsck to mark which
-				 * phase of rebuilding is done */
-	__le32 s_hash_function_code;	/* indicate, what hash function is being use
-					 * to sort names in a directory*/
-	__le16 s_tree_height;	/* height of disk tree */
-	__le16 s_bmap_nr;	/* amount of bitmap blocks needed to address
-				 * each block of file system */
-	__le16 s_version;	/* this field is only reliable on filesystem
-				 * with non-standard journal */
-	__le16 s_reserved_for_journal;	/* size in blocks of journal area on main
-					 * device, we need to keep after
-					 * making fs with non-standard journal */
-} __attribute__ ((__packed__));
-
-#define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1))
-
-/* this is the on disk super block */
-struct reiserfs_super_block {
-	struct reiserfs_super_block_v1 s_v1;
-	__le32 s_inode_generation;
-	__le32 s_flags;		/* Right now used only by inode-attributes, if enabled */
-	unsigned char s_uuid[16];	/* filesystem unique identifier */
-	unsigned char s_label[16];	/* filesystem volume label */
-	__le16 s_mnt_count;		/* Count of mounts since last fsck */
-	__le16 s_max_mnt_count;		/* Maximum mounts before check */
-	__le32 s_lastcheck;		/* Timestamp of last fsck */
-	__le32 s_check_interval;	/* Interval between checks */
-	char s_unused[76];	/* zero filled by mkreiserfs and
-				 * reiserfs_convert_objectid_map_v1()
-				 * so any additions must be updated
-				 * there as well. */
-} __attribute__ ((__packed__));
-
-#define SB_SIZE (sizeof(struct reiserfs_super_block))
-
-#define REISERFS_VERSION_1 0
-#define REISERFS_VERSION_2 2
-
-// on-disk super block fields converted to cpu form
-#define SB_DISK_SUPER_BLOCK(s) (REISERFS_SB(s)->s_rs)
-#define SB_V1_DISK_SUPER_BLOCK(s) (&(SB_DISK_SUPER_BLOCK(s)->s_v1))
-#define SB_BLOCKSIZE(s) \
-        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_blocksize))
-#define SB_BLOCK_COUNT(s) \
-        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_block_count))
-#define SB_FREE_BLOCKS(s) \
-        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks))
-#define SB_REISERFS_MAGIC(s) \
-        (SB_V1_DISK_SUPER_BLOCK(s)->s_magic)
-#define SB_ROOT_BLOCK(s) \
-        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_root_block))
-#define SB_TREE_HEIGHT(s) \
-        le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height))
-#define SB_REISERFS_STATE(s) \
-        le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state))
-#define SB_VERSION(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_version))
-#define SB_BMAP_NR(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr))
-
-#define PUT_SB_BLOCK_COUNT(s, val) \
-   do { SB_V1_DISK_SUPER_BLOCK(s)->s_block_count = cpu_to_le32(val); } while (0)
-#define PUT_SB_FREE_BLOCKS(s, val) \
-   do { SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks = cpu_to_le32(val); } while (0)
-#define PUT_SB_ROOT_BLOCK(s, val) \
-   do { SB_V1_DISK_SUPER_BLOCK(s)->s_root_block = cpu_to_le32(val); } while (0)
-#define PUT_SB_TREE_HEIGHT(s, val) \
-   do { SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height = cpu_to_le16(val); } while (0)
-#define PUT_SB_REISERFS_STATE(s, val) \
-   do { SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state = cpu_to_le16(val); } while (0)
-#define PUT_SB_VERSION(s, val) \
-   do { SB_V1_DISK_SUPER_BLOCK(s)->s_version = cpu_to_le16(val); } while (0)
-#define PUT_SB_BMAP_NR(s, val) \
-   do { SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr = cpu_to_le16 (val); } while (0)
-
-#define SB_ONDISK_JP(s) (&SB_V1_DISK_SUPER_BLOCK(s)->s_journal)
-#define SB_ONDISK_JOURNAL_SIZE(s) \
-         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_size))
-#define SB_ONDISK_JOURNAL_1st_BLOCK(s) \
-         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_1st_block))
-#define SB_ONDISK_JOURNAL_DEVICE(s) \
-         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_dev))
-#define SB_ONDISK_RESERVED_FOR_JOURNAL(s) \
-         le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal))
-
-#define is_block_in_log_or_reserved_area(s, block) \
-         block >= SB_JOURNAL_1st_RESERVED_BLOCK(s) \
-         && block < SB_JOURNAL_1st_RESERVED_BLOCK(s) +  \
-         ((!is_reiserfs_jr(SB_DISK_SUPER_BLOCK(s)) ? \
-         SB_ONDISK_JOURNAL_SIZE(s) + 1 : SB_ONDISK_RESERVED_FOR_JOURNAL(s)))
-
-int is_reiserfs_3_5(struct reiserfs_super_block *rs);
-int is_reiserfs_3_6(struct reiserfs_super_block *rs);
-int is_reiserfs_jr(struct reiserfs_super_block *rs);
-
-/* ReiserFS leaves the first 64k unused, so that partition labels have
-   enough space.  If someone wants to write a fancy bootloader that
-   needs more than 64k, let us know, and this will be increased in size.
-   This number must be larger than than the largest block size on any
-   platform, or code will break.  -Hans */
-#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
-#define REISERFS_FIRST_BLOCK unused_define
-#define REISERFS_JOURNAL_OFFSET_IN_BYTES REISERFS_DISK_OFFSET_IN_BYTES
-
-/* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */
-#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
-
-/* reiserfs internal error code (used by search_by_key and fix_nodes)) */
-#define CARRY_ON      0
-#define REPEAT_SEARCH -1
-#define IO_ERROR      -2
-#define NO_DISK_SPACE -3
-#define NO_BALANCING_NEEDED  (-4)
-#define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5)
-#define QUOTA_EXCEEDED -6
-
-typedef __u32 b_blocknr_t;
-typedef __le32 unp_t;
-
-struct unfm_nodeinfo {
-	unp_t unfm_nodenum;
-	unsigned short unfm_freespace;
-};
-
-/* there are two formats of keys: 3.5 and 3.6
- */
-#define KEY_FORMAT_3_5 0
-#define KEY_FORMAT_3_6 1
-
-/* there are two stat datas */
-#define STAT_DATA_V1 0
-#define STAT_DATA_V2 1
-
-static inline struct reiserfs_inode_info *REISERFS_I(const struct inode *inode)
-{
-	return container_of(inode, struct reiserfs_inode_info, vfs_inode);
-}
-
-static inline struct reiserfs_sb_info *REISERFS_SB(const struct super_block *sb)
-{
-	return sb->s_fs_info;
-}
-
-/* Don't trust REISERFS_SB(sb)->s_bmap_nr, it's a u16
- * which overflows on large file systems. */
-static inline __u32 reiserfs_bmap_count(struct super_block *sb)
-{
-	return (SB_BLOCK_COUNT(sb) - 1) / (sb->s_blocksize * 8) + 1;
-}
-
-static inline int bmap_would_wrap(unsigned bmap_nr)
-{
-	return bmap_nr > ((1LL << 16) - 1);
-}
-
-/** this says about version of key of all items (but stat data) the
-    object consists of */
-#define get_inode_item_key_version( inode )                                    \
-    ((REISERFS_I(inode)->i_flags & i_item_key_version_mask) ? KEY_FORMAT_3_6 : KEY_FORMAT_3_5)
-
-#define set_inode_item_key_version( inode, version )                           \
-         ({ if((version)==KEY_FORMAT_3_6)                                      \
-                REISERFS_I(inode)->i_flags |= i_item_key_version_mask;      \
-            else                                                               \
-                REISERFS_I(inode)->i_flags &= ~i_item_key_version_mask; })
-
-#define get_inode_sd_version(inode)                                            \
-    ((REISERFS_I(inode)->i_flags & i_stat_data_version_mask) ? STAT_DATA_V2 : STAT_DATA_V1)
-
-#define set_inode_sd_version(inode, version)                                   \
-         ({ if((version)==STAT_DATA_V2)                                        \
-                REISERFS_I(inode)->i_flags |= i_stat_data_version_mask;     \
-            else                                                               \
-                REISERFS_I(inode)->i_flags &= ~i_stat_data_version_mask; })
-
-/* This is an aggressive tail suppression policy, I am hoping it
-   improves our benchmarks. The principle behind it is that percentage
-   space saving is what matters, not absolute space saving.  This is
-   non-intuitive, but it helps to understand it if you consider that the
-   cost to access 4 blocks is not much more than the cost to access 1
-   block, if you have to do a seek and rotate.  A tail risks a
-   non-linear disk access that is significant as a percentage of total
-   time cost for a 4 block file and saves an amount of space that is
-   less significant as a percentage of space, or so goes the hypothesis.
-   -Hans */
-#define STORE_TAIL_IN_UNFM_S1(n_file_size,n_tail_size,n_block_size) \
-(\
-  (!(n_tail_size)) || \
-  (((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \
-   ( (n_file_size) >= (n_block_size) * 4 ) || \
-   ( ( (n_file_size) >= (n_block_size) * 3 ) && \
-     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size))/4) ) || \
-   ( ( (n_file_size) >= (n_block_size) * 2 ) && \
-     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size))/2) ) || \
-   ( ( (n_file_size) >= (n_block_size) ) && \
-     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) \
-)
-
-/* Another strategy for tails, this one means only create a tail if all the
-   file would fit into one DIRECT item.
-   Primary intention for this one is to increase performance by decreasing
-   seeking.
-*/
-#define STORE_TAIL_IN_UNFM_S2(n_file_size,n_tail_size,n_block_size) \
-(\
-  (!(n_tail_size)) || \
-  (((n_file_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) ) \
-)
-
-/*
- * values for s_umount_state field
- */
-#define REISERFS_VALID_FS    1
-#define REISERFS_ERROR_FS    2
-
-//
-// there are 5 item types currently
-//
-#define TYPE_STAT_DATA 0
-#define TYPE_INDIRECT 1
-#define TYPE_DIRECT 2
-#define TYPE_DIRENTRY 3
-#define TYPE_MAXTYPE 3
-#define TYPE_ANY 15		// FIXME: comment is required
-
-/***************************************************************************/
-/*                       KEY & ITEM HEAD                                   */
-/***************************************************************************/
-
-//
-// directories use this key as well as old files
-//
-struct offset_v1 {
-	__le32 k_offset;
-	__le32 k_uniqueness;
-} __attribute__ ((__packed__));
-
-struct offset_v2 {
-	__le64 v;
-} __attribute__ ((__packed__));
-
-static inline __u16 offset_v2_k_type(const struct offset_v2 *v2)
-{
-	__u8 type = le64_to_cpu(v2->v) >> 60;
-	return (type <= TYPE_MAXTYPE) ? type : TYPE_ANY;
-}
-
-static inline void set_offset_v2_k_type(struct offset_v2 *v2, int type)
-{
-	v2->v =
-	    (v2->v & cpu_to_le64(~0ULL >> 4)) | cpu_to_le64((__u64) type << 60);
-}
-
-static inline loff_t offset_v2_k_offset(const struct offset_v2 *v2)
-{
-	return le64_to_cpu(v2->v) & (~0ULL >> 4);
-}
-
-static inline void set_offset_v2_k_offset(struct offset_v2 *v2, loff_t offset)
-{
-	offset &= (~0ULL >> 4);
-	v2->v = (v2->v & cpu_to_le64(15ULL << 60)) | cpu_to_le64(offset);
-}
-
-/* Key of an item determines its location in the S+tree, and
-   is composed of 4 components */
-struct reiserfs_key {
-	__le32 k_dir_id;	/* packing locality: by default parent
-				   directory object id */
-	__le32 k_objectid;	/* object identifier */
-	union {
-		struct offset_v1 k_offset_v1;
-		struct offset_v2 k_offset_v2;
-	} __attribute__ ((__packed__)) u;
-} __attribute__ ((__packed__));
-
-struct in_core_key {
-	__u32 k_dir_id;		/* packing locality: by default parent
-				   directory object id */
-	__u32 k_objectid;	/* object identifier */
-	__u64 k_offset;
-	__u8 k_type;
-};
-
-struct cpu_key {
-	struct in_core_key on_disk_key;
-	int version;
-	int key_length;		/* 3 in all cases but direct2indirect and
-				   indirect2direct conversion */
-};
-
-/* Our function for comparing keys can compare keys of different
-   lengths.  It takes as a parameter the length of the keys it is to
-   compare.  These defines are used in determining what is to be passed
-   to it as that parameter. */
-#define REISERFS_FULL_KEY_LEN     4
-#define REISERFS_SHORT_KEY_LEN    2
-
-/* The result of the key compare */
-#define FIRST_GREATER 1
-#define SECOND_GREATER -1
-#define KEYS_IDENTICAL 0
-#define KEY_FOUND 1
-#define KEY_NOT_FOUND 0
-
-#define KEY_SIZE (sizeof(struct reiserfs_key))
-#define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32))
-
-/* return values for search_by_key and clones */
-#define ITEM_FOUND 1
-#define ITEM_NOT_FOUND 0
-#define ENTRY_FOUND 1
-#define ENTRY_NOT_FOUND 0
-#define DIRECTORY_NOT_FOUND -1
-#define REGULAR_FILE_FOUND -2
-#define DIRECTORY_FOUND -3
-#define BYTE_FOUND 1
-#define BYTE_NOT_FOUND 0
-#define FILE_NOT_FOUND -1
-
-#define POSITION_FOUND 1
-#define POSITION_NOT_FOUND 0
-
-// return values for reiserfs_find_entry and search_by_entry_key
-#define NAME_FOUND 1
-#define NAME_NOT_FOUND 0
-#define GOTO_PREVIOUS_ITEM 2
-#define NAME_FOUND_INVISIBLE 3
-
-/*  Everything in the filesystem is stored as a set of items.  The
-    item head contains the key of the item, its free space (for
-    indirect items) and specifies the location of the item itself
-    within the block.  */
-
-struct item_head {
-	/* Everything in the tree is found by searching for it based on
-	 * its key.*/
-	struct reiserfs_key ih_key;
-	union {
-		/* The free space in the last unformatted node of an
-		   indirect item if this is an indirect item.  This
-		   equals 0xFFFF iff this is a direct item or stat data
-		   item. Note that the key, not this field, is used to
-		   determine the item type, and thus which field this
-		   union contains. */
-		__le16 ih_free_space_reserved;
-		/* Iff this is a directory item, this field equals the
-		   number of directory entries in the directory item. */
-		__le16 ih_entry_count;
-	} __attribute__ ((__packed__)) u;
-	__le16 ih_item_len;	/* total size of the item body */
-	__le16 ih_item_location;	/* an offset to the item body
-					 * within the block */
-	__le16 ih_version;	/* 0 for all old items, 2 for new
-				   ones. Highest bit is set by fsck
-				   temporary, cleaned after all
-				   done */
-} __attribute__ ((__packed__));
-/* size of item header     */
-#define IH_SIZE (sizeof(struct item_head))
-
-#define ih_free_space(ih)            le16_to_cpu((ih)->u.ih_free_space_reserved)
-#define ih_version(ih)               le16_to_cpu((ih)->ih_version)
-#define ih_entry_count(ih)           le16_to_cpu((ih)->u.ih_entry_count)
-#define ih_location(ih)              le16_to_cpu((ih)->ih_item_location)
-#define ih_item_len(ih)              le16_to_cpu((ih)->ih_item_len)
-
-#define put_ih_free_space(ih, val)   do { (ih)->u.ih_free_space_reserved = cpu_to_le16(val); } while(0)
-#define put_ih_version(ih, val)      do { (ih)->ih_version = cpu_to_le16(val); } while (0)
-#define put_ih_entry_count(ih, val)  do { (ih)->u.ih_entry_count = cpu_to_le16(val); } while (0)
-#define put_ih_location(ih, val)     do { (ih)->ih_item_location = cpu_to_le16(val); } while (0)
-#define put_ih_item_len(ih, val)     do { (ih)->ih_item_len = cpu_to_le16(val); } while (0)
-
-#define unreachable_item(ih) (ih_version(ih) & (1 << 15))
-
-#define get_ih_free_space(ih) (ih_version (ih) == KEY_FORMAT_3_6 ? 0 : ih_free_space (ih))
-#define set_ih_free_space(ih,val) put_ih_free_space((ih), ((ih_version(ih) == KEY_FORMAT_3_6) ? 0 : (val)))
-
-/* these operate on indirect items, where you've got an array of ints
-** at a possibly unaligned location.  These are a noop on ia32
-** 
-** p is the array of __u32, i is the index into the array, v is the value
-** to store there.
-*/
-#define get_block_num(p, i) get_unaligned_le32((p) + (i))
-#define put_block_num(p, i, v) put_unaligned_le32((v), (p) + (i))
-
-//
-// in old version uniqueness field shows key type
-//
-#define V1_SD_UNIQUENESS 0
-#define V1_INDIRECT_UNIQUENESS 0xfffffffe
-#define V1_DIRECT_UNIQUENESS 0xffffffff
-#define V1_DIRENTRY_UNIQUENESS 500
-#define V1_ANY_UNIQUENESS 555	// FIXME: comment is required
-
-//
-// here are conversion routines
-//
-static inline int uniqueness2type(__u32 uniqueness) CONSTF;
-static inline int uniqueness2type(__u32 uniqueness)
-{
-	switch ((int)uniqueness) {
-	case V1_SD_UNIQUENESS:
-		return TYPE_STAT_DATA;
-	case V1_INDIRECT_UNIQUENESS:
-		return TYPE_INDIRECT;
-	case V1_DIRECT_UNIQUENESS:
-		return TYPE_DIRECT;
-	case V1_DIRENTRY_UNIQUENESS:
-		return TYPE_DIRENTRY;
-	case V1_ANY_UNIQUENESS:
-	default:
-		return TYPE_ANY;
-	}
-}
-
-static inline __u32 type2uniqueness(int type) CONSTF;
-static inline __u32 type2uniqueness(int type)
-{
-	switch (type) {
-	case TYPE_STAT_DATA:
-		return V1_SD_UNIQUENESS;
-	case TYPE_INDIRECT:
-		return V1_INDIRECT_UNIQUENESS;
-	case TYPE_DIRECT:
-		return V1_DIRECT_UNIQUENESS;
-	case TYPE_DIRENTRY:
-		return V1_DIRENTRY_UNIQUENESS;
-	case TYPE_ANY:
-	default:
-		return V1_ANY_UNIQUENESS;
-	}
-}
-
-//
-// key is pointer to on disk key which is stored in le, result is cpu,
-// there is no way to get version of object from key, so, provide
-// version to these defines
-//
-static inline loff_t le_key_k_offset(int version,
-				     const struct reiserfs_key *key)
-{
-	return (version == KEY_FORMAT_3_5) ?
-	    le32_to_cpu(key->u.k_offset_v1.k_offset) :
-	    offset_v2_k_offset(&(key->u.k_offset_v2));
-}
-
-static inline loff_t le_ih_k_offset(const struct item_head *ih)
-{
-	return le_key_k_offset(ih_version(ih), &(ih->ih_key));
-}
-
-static inline loff_t le_key_k_type(int version, const struct reiserfs_key *key)
-{
-	return (version == KEY_FORMAT_3_5) ?
-	    uniqueness2type(le32_to_cpu(key->u.k_offset_v1.k_uniqueness)) :
-	    offset_v2_k_type(&(key->u.k_offset_v2));
-}
-
-static inline loff_t le_ih_k_type(const struct item_head *ih)
-{
-	return le_key_k_type(ih_version(ih), &(ih->ih_key));
-}
-
-static inline void set_le_key_k_offset(int version, struct reiserfs_key *key,
-				       loff_t offset)
-{
-	(version == KEY_FORMAT_3_5) ? (void)(key->u.k_offset_v1.k_offset = cpu_to_le32(offset)) :	/* jdm check */
-	    (void)(set_offset_v2_k_offset(&(key->u.k_offset_v2), offset));
-}
-
-static inline void set_le_ih_k_offset(struct item_head *ih, loff_t offset)
-{
-	set_le_key_k_offset(ih_version(ih), &(ih->ih_key), offset);
-}
-
-static inline void set_le_key_k_type(int version, struct reiserfs_key *key,
-				     int type)
-{
-	(version == KEY_FORMAT_3_5) ?
-	    (void)(key->u.k_offset_v1.k_uniqueness =
-		   cpu_to_le32(type2uniqueness(type)))
-	    : (void)(set_offset_v2_k_type(&(key->u.k_offset_v2), type));
-}
-
-static inline void set_le_ih_k_type(struct item_head *ih, int type)
-{
-	set_le_key_k_type(ih_version(ih), &(ih->ih_key), type);
-}
-
-static inline int is_direntry_le_key(int version, struct reiserfs_key *key)
-{
-	return le_key_k_type(version, key) == TYPE_DIRENTRY;
-}
-
-static inline int is_direct_le_key(int version, struct reiserfs_key *key)
-{
-	return le_key_k_type(version, key) == TYPE_DIRECT;
-}
-
-static inline int is_indirect_le_key(int version, struct reiserfs_key *key)
-{
-	return le_key_k_type(version, key) == TYPE_INDIRECT;
-}
-
-static inline int is_statdata_le_key(int version, struct reiserfs_key *key)
-{
-	return le_key_k_type(version, key) == TYPE_STAT_DATA;
-}
-
-//
-// item header has version.
-//
-static inline int is_direntry_le_ih(struct item_head *ih)
-{
-	return is_direntry_le_key(ih_version(ih), &ih->ih_key);
-}
-
-static inline int is_direct_le_ih(struct item_head *ih)
-{
-	return is_direct_le_key(ih_version(ih), &ih->ih_key);
-}
-
-static inline int is_indirect_le_ih(struct item_head *ih)
-{
-	return is_indirect_le_key(ih_version(ih), &ih->ih_key);
-}
-
-static inline int is_statdata_le_ih(struct item_head *ih)
-{
-	return is_statdata_le_key(ih_version(ih), &ih->ih_key);
-}
-
-//
-// key is pointer to cpu key, result is cpu
-//
-static inline loff_t cpu_key_k_offset(const struct cpu_key *key)
-{
-	return key->on_disk_key.k_offset;
-}
-
-static inline loff_t cpu_key_k_type(const struct cpu_key *key)
-{
-	return key->on_disk_key.k_type;
-}
-
-static inline void set_cpu_key_k_offset(struct cpu_key *key, loff_t offset)
-{
-	key->on_disk_key.k_offset = offset;
-}
-
-static inline void set_cpu_key_k_type(struct cpu_key *key, int type)
-{
-	key->on_disk_key.k_type = type;
-}
-
-static inline void cpu_key_k_offset_dec(struct cpu_key *key)
-{
-	key->on_disk_key.k_offset--;
-}
-
-#define is_direntry_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRENTRY)
-#define is_direct_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRECT)
-#define is_indirect_cpu_key(key) (cpu_key_k_type (key) == TYPE_INDIRECT)
-#define is_statdata_cpu_key(key) (cpu_key_k_type (key) == TYPE_STAT_DATA)
-
-/* are these used ? */
-#define is_direntry_cpu_ih(ih) (is_direntry_cpu_key (&((ih)->ih_key)))
-#define is_direct_cpu_ih(ih) (is_direct_cpu_key (&((ih)->ih_key)))
-#define is_indirect_cpu_ih(ih) (is_indirect_cpu_key (&((ih)->ih_key)))
-#define is_statdata_cpu_ih(ih) (is_statdata_cpu_key (&((ih)->ih_key)))
-
-#define I_K_KEY_IN_ITEM(ih, key, n_blocksize) \
-    (!COMP_SHORT_KEYS(ih, key) && \
-	  I_OFF_BYTE_IN_ITEM(ih, k_offset(key), n_blocksize))
-
-/* maximal length of item */
-#define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE)
-#define MIN_ITEM_LEN 1
-
-/* object identifier for root dir */
-#define REISERFS_ROOT_OBJECTID 2
-#define REISERFS_ROOT_PARENT_OBJECTID 1
-
-extern struct reiserfs_key root_key;
-
-/* 
- * Picture represents a leaf of the S+tree
- *  ______________________________________________________
- * |      |  Array of     |                   |           |
- * |Block |  Object-Item  |      F r e e      |  Objects- |
- * | head |  Headers      |     S p a c e     |   Items   |
- * |______|_______________|___________________|___________|
- */
-
-/* Header of a disk block.  More precisely, header of a formatted leaf
-   or internal node, and not the header of an unformatted node. */
-struct block_head {
-	__le16 blk_level;	/* Level of a block in the tree. */
-	__le16 blk_nr_item;	/* Number of keys/items in a block. */
-	__le16 blk_free_space;	/* Block free space in bytes. */
-	__le16 blk_reserved;
-	/* dump this in v4/planA */
-	struct reiserfs_key blk_right_delim_key;	/* kept only for compatibility */
-};
-
-#define BLKH_SIZE                     (sizeof(struct block_head))
-#define blkh_level(p_blkh)            (le16_to_cpu((p_blkh)->blk_level))
-#define blkh_nr_item(p_blkh)          (le16_to_cpu((p_blkh)->blk_nr_item))
-#define blkh_free_space(p_blkh)       (le16_to_cpu((p_blkh)->blk_free_space))
-#define blkh_reserved(p_blkh)         (le16_to_cpu((p_blkh)->blk_reserved))
-#define set_blkh_level(p_blkh,val)    ((p_blkh)->blk_level = cpu_to_le16(val))
-#define set_blkh_nr_item(p_blkh,val)  ((p_blkh)->blk_nr_item = cpu_to_le16(val))
-#define set_blkh_free_space(p_blkh,val) ((p_blkh)->blk_free_space = cpu_to_le16(val))
-#define set_blkh_reserved(p_blkh,val) ((p_blkh)->blk_reserved = cpu_to_le16(val))
-#define blkh_right_delim_key(p_blkh)  ((p_blkh)->blk_right_delim_key)
-#define set_blkh_right_delim_key(p_blkh,val)  ((p_blkh)->blk_right_delim_key = val)
-
-/*
- * values for blk_level field of the struct block_head
- */
-
-#define FREE_LEVEL 0		/* when node gets removed from the tree its
-				   blk_level is set to FREE_LEVEL. It is then
-				   used to see whether the node is still in the
-				   tree */
-
-#define DISK_LEAF_NODE_LEVEL  1	/* Leaf node level. */
-
-/* Given the buffer head of a formatted node, resolve to the block head of that node. */
-#define B_BLK_HEAD(bh)			((struct block_head *)((bh)->b_data))
-/* Number of items that are in buffer. */
-#define B_NR_ITEMS(bh)			(blkh_nr_item(B_BLK_HEAD(bh)))
-#define B_LEVEL(bh)			(blkh_level(B_BLK_HEAD(bh)))
-#define B_FREE_SPACE(bh)		(blkh_free_space(B_BLK_HEAD(bh)))
-
-#define PUT_B_NR_ITEMS(bh, val)		do { set_blkh_nr_item(B_BLK_HEAD(bh), val); } while (0)
-#define PUT_B_LEVEL(bh, val)		do { set_blkh_level(B_BLK_HEAD(bh), val); } while (0)
-#define PUT_B_FREE_SPACE(bh, val)	do { set_blkh_free_space(B_BLK_HEAD(bh), val); } while (0)
-
-/* Get right delimiting key. -- little endian */
-#define B_PRIGHT_DELIM_KEY(bh)		(&(blk_right_delim_key(B_BLK_HEAD(bh))))
-
-/* Does the buffer contain a disk leaf. */
-#define B_IS_ITEMS_LEVEL(bh)		(B_LEVEL(bh) == DISK_LEAF_NODE_LEVEL)
-
-/* Does the buffer contain a disk internal node */
-#define B_IS_KEYS_LEVEL(bh)      (B_LEVEL(bh) > DISK_LEAF_NODE_LEVEL \
-					    && B_LEVEL(bh) <= MAX_HEIGHT)
-
-/***************************************************************************/
-/*                             STAT DATA                                   */
-/***************************************************************************/
-
-//
-// old stat data is 32 bytes long. We are going to distinguish new one by
-// different size
-//
-struct stat_data_v1 {
-	__le16 sd_mode;		/* file type, permissions */
-	__le16 sd_nlink;	/* number of hard links */
-	__le16 sd_uid;		/* owner */
-	__le16 sd_gid;		/* group */
-	__le32 sd_size;		/* file size */
-	__le32 sd_atime;	/* time of last access */
-	__le32 sd_mtime;	/* time file was last modified  */
-	__le32 sd_ctime;	/* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
-	union {
-		__le32 sd_rdev;
-		__le32 sd_blocks;	/* number of blocks file uses */
-	} __attribute__ ((__packed__)) u;
-	__le32 sd_first_direct_byte;	/* first byte of file which is stored
-					   in a direct item: except that if it
-					   equals 1 it is a symlink and if it
-					   equals ~(__u32)0 there is no
-					   direct item.  The existence of this
-					   field really grates on me. Let's
-					   replace it with a macro based on
-					   sd_size and our tail suppression
-					   policy.  Someday.  -Hans */
-} __attribute__ ((__packed__));
-
-#define SD_V1_SIZE              (sizeof(struct stat_data_v1))
-#define stat_data_v1(ih)        (ih_version (ih) == KEY_FORMAT_3_5)
-#define sd_v1_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
-#define set_sd_v1_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
-#define sd_v1_nlink(sdp)        (le16_to_cpu((sdp)->sd_nlink))
-#define set_sd_v1_nlink(sdp,v)  ((sdp)->sd_nlink = cpu_to_le16(v))
-#define sd_v1_uid(sdp)          (le16_to_cpu((sdp)->sd_uid))
-#define set_sd_v1_uid(sdp,v)    ((sdp)->sd_uid = cpu_to_le16(v))
-#define sd_v1_gid(sdp)          (le16_to_cpu((sdp)->sd_gid))
-#define set_sd_v1_gid(sdp,v)    ((sdp)->sd_gid = cpu_to_le16(v))
-#define sd_v1_size(sdp)         (le32_to_cpu((sdp)->sd_size))
-#define set_sd_v1_size(sdp,v)   ((sdp)->sd_size = cpu_to_le32(v))
-#define sd_v1_atime(sdp)        (le32_to_cpu((sdp)->sd_atime))
-#define set_sd_v1_atime(sdp,v)  ((sdp)->sd_atime = cpu_to_le32(v))
-#define sd_v1_mtime(sdp)        (le32_to_cpu((sdp)->sd_mtime))
-#define set_sd_v1_mtime(sdp,v)  ((sdp)->sd_mtime = cpu_to_le32(v))
-#define sd_v1_ctime(sdp)        (le32_to_cpu((sdp)->sd_ctime))
-#define set_sd_v1_ctime(sdp,v)  ((sdp)->sd_ctime = cpu_to_le32(v))
-#define sd_v1_rdev(sdp)         (le32_to_cpu((sdp)->u.sd_rdev))
-#define set_sd_v1_rdev(sdp,v)   ((sdp)->u.sd_rdev = cpu_to_le32(v))
-#define sd_v1_blocks(sdp)       (le32_to_cpu((sdp)->u.sd_blocks))
-#define set_sd_v1_blocks(sdp,v) ((sdp)->u.sd_blocks = cpu_to_le32(v))
-#define sd_v1_first_direct_byte(sdp) \
-                                (le32_to_cpu((sdp)->sd_first_direct_byte))
-#define set_sd_v1_first_direct_byte(sdp,v) \
-                                ((sdp)->sd_first_direct_byte = cpu_to_le32(v))
-
-/* inode flags stored in sd_attrs (nee sd_reserved) */
-
-/* we want common flags to have the same values as in ext2,
-   so chattr(1) will work without problems */
-#define REISERFS_IMMUTABLE_FL FS_IMMUTABLE_FL
-#define REISERFS_APPEND_FL    FS_APPEND_FL
-#define REISERFS_SYNC_FL      FS_SYNC_FL
-#define REISERFS_NOATIME_FL   FS_NOATIME_FL
-#define REISERFS_NODUMP_FL    FS_NODUMP_FL
-#define REISERFS_SECRM_FL     FS_SECRM_FL
-#define REISERFS_UNRM_FL      FS_UNRM_FL
-#define REISERFS_COMPR_FL     FS_COMPR_FL
-#define REISERFS_NOTAIL_FL    FS_NOTAIL_FL
-
-/* persistent flags that file inherits from the parent directory */
-#define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL |	\
-				REISERFS_SYNC_FL |	\
-				REISERFS_NOATIME_FL |	\
-				REISERFS_NODUMP_FL |	\
-				REISERFS_SECRM_FL |	\
-				REISERFS_COMPR_FL |	\
-				REISERFS_NOTAIL_FL )
-
-/* Stat Data on disk (reiserfs version of UFS disk inode minus the
-   address blocks) */
-struct stat_data {
-	__le16 sd_mode;		/* file type, permissions */
-	__le16 sd_attrs;	/* persistent inode flags */
-	__le32 sd_nlink;	/* number of hard links */
-	__le64 sd_size;		/* file size */
-	__le32 sd_uid;		/* owner */
-	__le32 sd_gid;		/* group */
-	__le32 sd_atime;	/* time of last access */
-	__le32 sd_mtime;	/* time file was last modified  */
-	__le32 sd_ctime;	/* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
-	__le32 sd_blocks;
-	union {
-		__le32 sd_rdev;
-		__le32 sd_generation;
-		//__le32 sd_first_direct_byte;
-		/* first byte of file which is stored in a
-		   direct item: except that if it equals 1
-		   it is a symlink and if it equals
-		   ~(__u32)0 there is no direct item.  The
-		   existence of this field really grates
-		   on me. Let's replace it with a macro
-		   based on sd_size and our tail
-		   suppression policy? */
-	} __attribute__ ((__packed__)) u;
-} __attribute__ ((__packed__));
-//
-// this is 44 bytes long
-//
-#define SD_SIZE (sizeof(struct stat_data))
-#define SD_V2_SIZE              SD_SIZE
-#define stat_data_v2(ih)        (ih_version (ih) == KEY_FORMAT_3_6)
-#define sd_v2_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
-#define set_sd_v2_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
-/* sd_reserved */
-/* set_sd_reserved */
-#define sd_v2_nlink(sdp)        (le32_to_cpu((sdp)->sd_nlink))
-#define set_sd_v2_nlink(sdp,v)  ((sdp)->sd_nlink = cpu_to_le32(v))
-#define sd_v2_size(sdp)         (le64_to_cpu((sdp)->sd_size))
-#define set_sd_v2_size(sdp,v)   ((sdp)->sd_size = cpu_to_le64(v))
-#define sd_v2_uid(sdp)          (le32_to_cpu((sdp)->sd_uid))
-#define set_sd_v2_uid(sdp,v)    ((sdp)->sd_uid = cpu_to_le32(v))
-#define sd_v2_gid(sdp)          (le32_to_cpu((sdp)->sd_gid))
-#define set_sd_v2_gid(sdp,v)    ((sdp)->sd_gid = cpu_to_le32(v))
-#define sd_v2_atime(sdp)        (le32_to_cpu((sdp)->sd_atime))
-#define set_sd_v2_atime(sdp,v)  ((sdp)->sd_atime = cpu_to_le32(v))
-#define sd_v2_mtime(sdp)        (le32_to_cpu((sdp)->sd_mtime))
-#define set_sd_v2_mtime(sdp,v)  ((sdp)->sd_mtime = cpu_to_le32(v))
-#define sd_v2_ctime(sdp)        (le32_to_cpu((sdp)->sd_ctime))
-#define set_sd_v2_ctime(sdp,v)  ((sdp)->sd_ctime = cpu_to_le32(v))
-#define sd_v2_blocks(sdp)       (le32_to_cpu((sdp)->sd_blocks))
-#define set_sd_v2_blocks(sdp,v) ((sdp)->sd_blocks = cpu_to_le32(v))
-#define sd_v2_rdev(sdp)         (le32_to_cpu((sdp)->u.sd_rdev))
-#define set_sd_v2_rdev(sdp,v)   ((sdp)->u.sd_rdev = cpu_to_le32(v))
-#define sd_v2_generation(sdp)   (le32_to_cpu((sdp)->u.sd_generation))
-#define set_sd_v2_generation(sdp,v) ((sdp)->u.sd_generation = cpu_to_le32(v))
-#define sd_v2_attrs(sdp)         (le16_to_cpu((sdp)->sd_attrs))
-#define set_sd_v2_attrs(sdp,v)   ((sdp)->sd_attrs = cpu_to_le16(v))
-
-/***************************************************************************/
-/*                      DIRECTORY STRUCTURE                                */
-/***************************************************************************/
-/* 
-   Picture represents the structure of directory items
-   ________________________________________________
-   |  Array of     |   |     |        |       |   |
-   | directory     |N-1| N-2 | ....   |   1st |0th|
-   | entry headers |   |     |        |       |   |
-   |_______________|___|_____|________|_______|___|
-                    <----   directory entries         ------>
-
- First directory item has k_offset component 1. We store "." and ".."
- in one item, always, we never split "." and ".." into differing
- items.  This makes, among other things, the code for removing
- directories simpler. */
-#define SD_OFFSET  0
-#define SD_UNIQUENESS 0
-#define DOT_OFFSET 1
-#define DOT_DOT_OFFSET 2
-#define DIRENTRY_UNIQUENESS 500
-
-/* */
-#define FIRST_ITEM_OFFSET 1
-
-/*
-   Q: How to get key of object pointed to by entry from entry?  
-
-   A: Each directory entry has its header. This header has deh_dir_id and deh_objectid fields, those are key
-      of object, entry points to */
-
-/* NOT IMPLEMENTED:   
-   Directory will someday contain stat data of object */
-
-struct reiserfs_de_head {
-	__le32 deh_offset;	/* third component of the directory entry key */
-	__le32 deh_dir_id;	/* objectid of the parent directory of the object, that is referenced
-				   by directory entry */
-	__le32 deh_objectid;	/* objectid of the object, that is referenced by directory entry */
-	__le16 deh_location;	/* offset of name in the whole item */
-	__le16 deh_state;	/* whether 1) entry contains stat data (for future), and 2) whether
-				   entry is hidden (unlinked) */
-} __attribute__ ((__packed__));
-#define DEH_SIZE                  sizeof(struct reiserfs_de_head)
-#define deh_offset(p_deh)         (le32_to_cpu((p_deh)->deh_offset))
-#define deh_dir_id(p_deh)         (le32_to_cpu((p_deh)->deh_dir_id))
-#define deh_objectid(p_deh)       (le32_to_cpu((p_deh)->deh_objectid))
-#define deh_location(p_deh)       (le16_to_cpu((p_deh)->deh_location))
-#define deh_state(p_deh)          (le16_to_cpu((p_deh)->deh_state))
-
-#define put_deh_offset(p_deh,v)   ((p_deh)->deh_offset = cpu_to_le32((v)))
-#define put_deh_dir_id(p_deh,v)   ((p_deh)->deh_dir_id = cpu_to_le32((v)))
-#define put_deh_objectid(p_deh,v) ((p_deh)->deh_objectid = cpu_to_le32((v)))
-#define put_deh_location(p_deh,v) ((p_deh)->deh_location = cpu_to_le16((v)))
-#define put_deh_state(p_deh,v)    ((p_deh)->deh_state = cpu_to_le16((v)))
-
-/* empty directory contains two entries "." and ".." and their headers */
-#define EMPTY_DIR_SIZE \
-(DEH_SIZE * 2 + ROUND_UP (strlen (".")) + ROUND_UP (strlen ("..")))
-
-/* old format directories have this size when empty */
-#define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3)
-
-#define DEH_Statdata 0		/* not used now */
-#define DEH_Visible 2
-
-/* 64 bit systems (and the S/390) need to be aligned explicitly -jdm */
-#if BITS_PER_LONG == 64 || defined(__s390__) || defined(__hppa__)
-#   define ADDR_UNALIGNED_BITS  (3)
-#endif
-
-/* These are only used to manipulate deh_state.
- * Because of this, we'll use the ext2_ bit routines,
- * since they are little endian */
-#ifdef ADDR_UNALIGNED_BITS
-
-#   define aligned_address(addr)           ((void *)((long)(addr) & ~((1UL << ADDR_UNALIGNED_BITS) - 1)))
-#   define unaligned_offset(addr)          (((int)((long)(addr) & ((1 << ADDR_UNALIGNED_BITS) - 1))) << 3)
-
-#   define set_bit_unaligned(nr, addr)	\
-	__test_and_set_bit_le((nr) + unaligned_offset(addr), aligned_address(addr))
-#   define clear_bit_unaligned(nr, addr)	\
-	__test_and_clear_bit_le((nr) + unaligned_offset(addr), aligned_address(addr))
-#   define test_bit_unaligned(nr, addr)	\
-	test_bit_le((nr) + unaligned_offset(addr), aligned_address(addr))
-
-#else
-
-#   define set_bit_unaligned(nr, addr)	__test_and_set_bit_le(nr, addr)
-#   define clear_bit_unaligned(nr, addr)	__test_and_clear_bit_le(nr, addr)
-#   define test_bit_unaligned(nr, addr)	test_bit_le(nr, addr)
-
-#endif
-
-#define mark_de_with_sd(deh)        set_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
-#define mark_de_without_sd(deh)     clear_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
-#define mark_de_visible(deh)	    set_bit_unaligned (DEH_Visible, &((deh)->deh_state))
-#define mark_de_hidden(deh)	    clear_bit_unaligned (DEH_Visible, &((deh)->deh_state))
-
-#define de_with_sd(deh)		    test_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
-#define de_visible(deh)	    	    test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
-#define de_hidden(deh)	    	    !test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
-
-extern void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid,
-				   __le32 par_dirid, __le32 par_objid);
-extern void make_empty_dir_item(char *body, __le32 dirid, __le32 objid,
-				__le32 par_dirid, __le32 par_objid);
-
-/* array of the entry headers */
- /* get item body */
-#define B_I_PITEM(bh,ih) ( (bh)->b_data + ih_location(ih) )
-#define B_I_DEH(bh,ih) ((struct reiserfs_de_head *)(B_I_PITEM(bh,ih)))
-
-/* length of the directory entry in directory item. This define
-   calculates length of i-th directory entry using directory entry
-   locations from dir entry head. When it calculates length of 0-th
-   directory entry, it uses length of whole item in place of entry
-   location of the non-existent following entry in the calculation.
-   See picture above.*/
-/*
-#define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \
-((i) ? (deh_location((deh)-1) - deh_location((deh))) : (ih_item_len((ih)) - deh_location((deh))))
-*/
-static inline int entry_length(const struct buffer_head *bh,
-			       const struct item_head *ih, int pos_in_item)
-{
-	struct reiserfs_de_head *deh;
-
-	deh = B_I_DEH(bh, ih) + pos_in_item;
-	if (pos_in_item)
-		return deh_location(deh - 1) - deh_location(deh);
-
-	return ih_item_len(ih) - deh_location(deh);
-}
-
-/* number of entries in the directory item, depends on ENTRY_COUNT being at the start of directory dynamic data. */
-#define I_ENTRY_COUNT(ih) (ih_entry_count((ih)))
-
-/* name by bh, ih and entry_num */
-#define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih_location(ih) + deh_location(B_I_DEH(bh,ih)+(entry_num))))
-
-// two entries per block (at least)
-#define REISERFS_MAX_NAME(block_size) 255
-
-/* this structure is used for operations on directory entries. It is
-   not a disk structure. */
-/* When reiserfs_find_entry or search_by_entry_key find directory
-   entry, they return filled reiserfs_dir_entry structure */
-struct reiserfs_dir_entry {
-	struct buffer_head *de_bh;
-	int de_item_num;
-	struct item_head *de_ih;
-	int de_entry_num;
-	struct reiserfs_de_head *de_deh;
-	int de_entrylen;
-	int de_namelen;
-	char *de_name;
-	unsigned long *de_gen_number_bit_string;
-
-	__u32 de_dir_id;
-	__u32 de_objectid;
-
-	struct cpu_key de_entry_key;
-};
-
-/* these defines are useful when a particular member of a reiserfs_dir_entry is needed */
-
-/* pointer to file name, stored in entry */
-#define B_I_DEH_ENTRY_FILE_NAME(bh,ih,deh) (B_I_PITEM (bh, ih) + deh_location(deh))
-
-/* length of name */
-#define I_DEH_N_ENTRY_FILE_NAME_LENGTH(ih,deh,entry_num) \
-(I_DEH_N_ENTRY_LENGTH (ih, deh, entry_num) - (de_with_sd (deh) ? SD_SIZE : 0))
-
-/* hash value occupies bits from 7 up to 30 */
-#define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80LL)
-/* generation number occupies 7 bits starting from 0 up to 6 */
-#define GET_GENERATION_NUMBER(offset) ((offset) & 0x7fLL)
-#define MAX_GENERATION_NUMBER  127
-
-#define SET_GENERATION_NUMBER(offset,gen_number) (GET_HASH_VALUE(offset)|(gen_number))
-
-/*
- * Picture represents an internal node of the reiserfs tree
- *  ______________________________________________________
- * |      |  Array of     |  Array of         |  Free     |
- * |block |    keys       |  pointers         | space     |
- * | head |      N        |      N+1          |           |
- * |______|_______________|___________________|___________|
- */
-
-/***************************************************************************/
-/*                      DISK CHILD                                         */
-/***************************************************************************/
-/* Disk child pointer: The pointer from an internal node of the tree
-   to a node that is on disk. */
-struct disk_child {
-	__le32 dc_block_number;	/* Disk child's block number. */
-	__le16 dc_size;		/* Disk child's used space.   */
-	__le16 dc_reserved;
-};
-
-#define DC_SIZE (sizeof(struct disk_child))
-#define dc_block_number(dc_p)	(le32_to_cpu((dc_p)->dc_block_number))
-#define dc_size(dc_p)		(le16_to_cpu((dc_p)->dc_size))
-#define put_dc_block_number(dc_p, val)   do { (dc_p)->dc_block_number = cpu_to_le32(val); } while(0)
-#define put_dc_size(dc_p, val)   do { (dc_p)->dc_size = cpu_to_le16(val); } while(0)
-
-/* Get disk child by buffer header and position in the tree node. */
-#define B_N_CHILD(bh, n_pos)  ((struct disk_child *)\
-((bh)->b_data + BLKH_SIZE + B_NR_ITEMS(bh) * KEY_SIZE + DC_SIZE * (n_pos)))
-
-/* Get disk child number by buffer header and position in the tree node. */
-#define B_N_CHILD_NUM(bh, n_pos) (dc_block_number(B_N_CHILD(bh, n_pos)))
-#define PUT_B_N_CHILD_NUM(bh, n_pos, val) \
-				(put_dc_block_number(B_N_CHILD(bh, n_pos), val))
-
- /* maximal value of field child_size in structure disk_child */
- /* child size is the combined size of all items and their headers */
-#define MAX_CHILD_SIZE(bh) ((int)( (bh)->b_size - BLKH_SIZE ))
-
-/* amount of used space in buffer (not including block head) */
-#define B_CHILD_SIZE(cur) (MAX_CHILD_SIZE(cur)-(B_FREE_SPACE(cur)))
-
-/* max and min number of keys in internal node */
-#define MAX_NR_KEY(bh) ( (MAX_CHILD_SIZE(bh)-DC_SIZE)/(KEY_SIZE+DC_SIZE) )
-#define MIN_NR_KEY(bh)    (MAX_NR_KEY(bh)/2)
-
-/***************************************************************************/
-/*                      PATH STRUCTURES AND DEFINES                        */
-/***************************************************************************/
-
-/* Search_by_key fills up the path from the root to the leaf as it descends the tree looking for the
-   key.  It uses reiserfs_bread to try to find buffers in the cache given their block number.  If it
-   does not find them in the cache it reads them from disk.  For each node search_by_key finds using
-   reiserfs_bread it then uses bin_search to look through that node.  bin_search will find the
-   position of the block_number of the next node if it is looking through an internal node.  If it
-   is looking through a leaf node bin_search will find the position of the item which has key either
-   equal to given key, or which is the maximal key less than the given key. */
-
-struct path_element {
-	struct buffer_head *pe_buffer;	/* Pointer to the buffer at the path in the tree. */
-	int pe_position;	/* Position in the tree node which is placed in the */
-	/* buffer above.                                  */
-};
-
-#define MAX_HEIGHT 5		/* maximal height of a tree. don't change this without changing JOURNAL_PER_BALANCE_CNT */
-#define EXTENDED_MAX_HEIGHT         7	/* Must be equals MAX_HEIGHT + FIRST_PATH_ELEMENT_OFFSET */
-#define FIRST_PATH_ELEMENT_OFFSET   2	/* Must be equal to at least 2. */
-
-#define ILLEGAL_PATH_ELEMENT_OFFSET 1	/* Must be equal to FIRST_PATH_ELEMENT_OFFSET - 1 */
-#define MAX_FEB_SIZE 6		/* this MUST be MAX_HEIGHT + 1. See about FEB below */
-
-/* We need to keep track of who the ancestors of nodes are.  When we
-   perform a search we record which nodes were visited while
-   descending the tree looking for the node we searched for. This list
-   of nodes is called the path.  This information is used while
-   performing balancing.  Note that this path information may become
-   invalid, and this means we must check it when using it to see if it
-   is still valid. You'll need to read search_by_key and the comments
-   in it, especially about decrement_counters_in_path(), to understand
-   this structure.  
-
-Paths make the code so much harder to work with and debug.... An
-enormous number of bugs are due to them, and trying to write or modify
-code that uses them just makes my head hurt.  They are based on an
-excessive effort to avoid disturbing the precious VFS code.:-( The
-gods only know how we are going to SMP the code that uses them.
-znodes are the way! */
-
-#define PATH_READA	0x1	/* do read ahead */
-#define PATH_READA_BACK 0x2	/* read backwards */
-
-struct treepath {
-	int path_length;	/* Length of the array above.   */
-	int reada;
-	struct path_element path_elements[EXTENDED_MAX_HEIGHT];	/* Array of the path elements.  */
-	int pos_in_item;
-};
-
-#define pos_in_item(path) ((path)->pos_in_item)
-
-#define INITIALIZE_PATH(var) \
-struct treepath var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
-
-/* Get path element by path and path position. */
-#define PATH_OFFSET_PELEMENT(path, n_offset)  ((path)->path_elements + (n_offset))
-
-/* Get buffer header at the path by path and path position. */
-#define PATH_OFFSET_PBUFFER(path, n_offset)   (PATH_OFFSET_PELEMENT(path, n_offset)->pe_buffer)
-
-/* Get position in the element at the path by path and path position. */
-#define PATH_OFFSET_POSITION(path, n_offset) (PATH_OFFSET_PELEMENT(path, n_offset)->pe_position)
-
-#define PATH_PLAST_BUFFER(path) (PATH_OFFSET_PBUFFER((path), (path)->path_length))
-				/* you know, to the person who didn't
-				   write this the macro name does not
-				   at first suggest what it does.
-				   Maybe POSITION_FROM_PATH_END? Or
-				   maybe we should just focus on
-				   dumping paths... -Hans */
-#define PATH_LAST_POSITION(path) (PATH_OFFSET_POSITION((path), (path)->path_length))
-
-#define PATH_PITEM_HEAD(path)    B_N_PITEM_HEAD(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION(path))
-
-/* in do_balance leaf has h == 0 in contrast with path structure,
-   where root has level == 0. That is why we need these defines */
-#define PATH_H_PBUFFER(path, h) PATH_OFFSET_PBUFFER (path, path->path_length - (h))	/* tb->S[h] */
-#define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1)	/* tb->F[h] or tb->S[0]->b_parent */
-#define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h))
-#define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1)	/* tb->S[h]->b_item_order */
-
-#define PATH_H_PATH_OFFSET(path, n_h) ((path)->path_length - (n_h))
-
-#define get_last_bh(path) PATH_PLAST_BUFFER(path)
-#define get_ih(path) PATH_PITEM_HEAD(path)
-#define get_item_pos(path) PATH_LAST_POSITION(path)
-#define get_item(path) ((void *)B_N_PITEM(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION (path)))
-#define item_moved(ih,path) comp_items(ih, path)
-#define path_changed(ih,path) comp_items (ih, path)
-
-/***************************************************************************/
-/*                       MISC                                              */
-/***************************************************************************/
-
-/* Size of pointer to the unformatted node. */
-#define UNFM_P_SIZE (sizeof(unp_t))
-#define UNFM_P_SHIFT 2
-
-// in in-core inode key is stored on le form
-#define INODE_PKEY(inode) ((struct reiserfs_key *)(REISERFS_I(inode)->i_key))
-
-#define MAX_UL_INT 0xffffffff
-#define MAX_INT    0x7ffffff
-#define MAX_US_INT 0xffff
-
-// reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
-#define U32_MAX (~(__u32)0)
-
-static inline loff_t max_reiserfs_offset(struct inode *inode)
-{
-	if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5)
-		return (loff_t) U32_MAX;
-
-	return (loff_t) ((~(__u64) 0) >> 4);
-}
-
-/*#define MAX_KEY_UNIQUENESS	MAX_UL_INT*/
-#define MAX_KEY_OBJECTID	MAX_UL_INT
-
-#define MAX_B_NUM  MAX_UL_INT
-#define MAX_FC_NUM MAX_US_INT
-
-/* the purpose is to detect overflow of an unsigned short */
-#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
-
-/* The following defines are used in reiserfs_insert_item and reiserfs_append_item  */
-#define REISERFS_KERNEL_MEM		0	/* reiserfs kernel memory mode  */
-#define REISERFS_USER_MEM		1	/* reiserfs user memory mode            */
-
-#define fs_generation(s) (REISERFS_SB(s)->s_generation_counter)
-#define get_generation(s) atomic_read (&fs_generation(s))
-#define FILESYSTEM_CHANGED_TB(tb)  (get_generation((tb)->tb_sb) != (tb)->fs_gen)
-#define __fs_changed(gen,s) (gen != get_generation (s))
-#define fs_changed(gen,s)		\
-({					\
-	reiserfs_cond_resched(s);	\
-	__fs_changed(gen, s);		\
-})
-
-/***************************************************************************/
-/*                  FIXATE NODES                                           */
-/***************************************************************************/
-
-#define VI_TYPE_LEFT_MERGEABLE 1
-#define VI_TYPE_RIGHT_MERGEABLE 2
-
-/* To make any changes in the tree we always first find node, that
-   contains item to be changed/deleted or place to insert a new
-   item. We call this node S. To do balancing we need to decide what
-   we will shift to left/right neighbor, or to a new node, where new
-   item will be etc. To make this analysis simpler we build virtual
-   node. Virtual node is an array of items, that will replace items of
-   node S. (For instance if we are going to delete an item, virtual
-   node does not contain it). Virtual node keeps information about
-   item sizes and types, mergeability of first and last items, sizes
-   of all entries in directory item. We use this array of items when
-   calculating what we can shift to neighbors and how many nodes we
-   have to have if we do not any shiftings, if we shift to left/right
-   neighbor or to both. */
-struct virtual_item {
-	int vi_index;		// index in the array of item operations
-	unsigned short vi_type;	// left/right mergeability
-	unsigned short vi_item_len;	/* length of item that it will have after balancing */
-	struct item_head *vi_ih;
-	const char *vi_item;	// body of item (old or new)
-	const void *vi_new_data;	// 0 always but paste mode
-	void *vi_uarea;		// item specific area
-};
-
-struct virtual_node {
-	char *vn_free_ptr;	/* this is a pointer to the free space in the buffer */
-	unsigned short vn_nr_item;	/* number of items in virtual node */
-	short vn_size;		/* size of node , that node would have if it has unlimited size and no balancing is performed */
-	short vn_mode;		/* mode of balancing (paste, insert, delete, cut) */
-	short vn_affected_item_num;
-	short vn_pos_in_item;
-	struct item_head *vn_ins_ih;	/* item header of inserted item, 0 for other modes */
-	const void *vn_data;
-	struct virtual_item *vn_vi;	/* array of items (including a new one, excluding item to be deleted) */
-};
-
-/* used by directory items when creating virtual nodes */
-struct direntry_uarea {
-	int flags;
-	__u16 entry_count;
-	__u16 entry_sizes[1];
-} __attribute__ ((__packed__));
-
-/***************************************************************************/
-/*                  TREE BALANCE                                           */
-/***************************************************************************/
-
-/* This temporary structure is used in tree balance algorithms, and
-   constructed as we go to the extent that its various parts are
-   needed.  It contains arrays of nodes that can potentially be
-   involved in the balancing of node S, and parameters that define how
-   each of the nodes must be balanced.  Note that in these algorithms
-   for balancing the worst case is to need to balance the current node
-   S and the left and right neighbors and all of their parents plus
-   create a new node.  We implement S1 balancing for the leaf nodes
-   and S0 balancing for the internal nodes (S1 and S0 are defined in
-   our papers.)*/
-
-#define MAX_FREE_BLOCK 7	/* size of the array of buffers to free at end of do_balance */
-
-/* maximum number of FEB blocknrs on a single level */
-#define MAX_AMOUNT_NEEDED 2
-
-/* someday somebody will prefix every field in this struct with tb_ */
-struct tree_balance {
-	int tb_mode;
-	int need_balance_dirty;
-	struct super_block *tb_sb;
-	struct reiserfs_transaction_handle *transaction_handle;
-	struct treepath *tb_path;
-	struct buffer_head *L[MAX_HEIGHT];	/* array of left neighbors of nodes in the path */
-	struct buffer_head *R[MAX_HEIGHT];	/* array of right neighbors of nodes in the path */
-	struct buffer_head *FL[MAX_HEIGHT];	/* array of fathers of the left  neighbors      */
-	struct buffer_head *FR[MAX_HEIGHT];	/* array of fathers of the right neighbors      */
-	struct buffer_head *CFL[MAX_HEIGHT];	/* array of common parents of center node and its left neighbor  */
-	struct buffer_head *CFR[MAX_HEIGHT];	/* array of common parents of center node and its right neighbor */
-
-	struct buffer_head *FEB[MAX_FEB_SIZE];	/* array of empty buffers. Number of buffers in array equals
-						   cur_blknum. */
-	struct buffer_head *used[MAX_FEB_SIZE];
-	struct buffer_head *thrown[MAX_FEB_SIZE];
-	int lnum[MAX_HEIGHT];	/* array of number of items which must be
-				   shifted to the left in order to balance the
-				   current node; for leaves includes item that
-				   will be partially shifted; for internal
-				   nodes, it is the number of child pointers
-				   rather than items. It includes the new item
-				   being created. The code sometimes subtracts
-				   one to get the number of wholly shifted
-				   items for other purposes. */
-	int rnum[MAX_HEIGHT];	/* substitute right for left in comment above */
-	int lkey[MAX_HEIGHT];	/* array indexed by height h mapping the key delimiting L[h] and
-				   S[h] to its item number within the node CFL[h] */
-	int rkey[MAX_HEIGHT];	/* substitute r for l in comment above */
-	int insert_size[MAX_HEIGHT];	/* the number of bytes by we are trying to add or remove from
-					   S[h]. A negative value means removing.  */
-	int blknum[MAX_HEIGHT];	/* number of nodes that will replace node S[h] after
-				   balancing on the level h of the tree.  If 0 then S is
-				   being deleted, if 1 then S is remaining and no new nodes
-				   are being created, if 2 or 3 then 1 or 2 new nodes is
-				   being created */
-
-	/* fields that are used only for balancing leaves of the tree */
-	int cur_blknum;		/* number of empty blocks having been already allocated                 */
-	int s0num;		/* number of items that fall into left most  node when S[0] splits     */
-	int s1num;		/* number of items that fall into first  new node when S[0] splits     */
-	int s2num;		/* number of items that fall into second new node when S[0] splits     */
-	int lbytes;		/* number of bytes which can flow to the left neighbor from the        left    */
-	/* most liquid item that cannot be shifted from S[0] entirely         */
-	/* if -1 then nothing will be partially shifted */
-	int rbytes;		/* number of bytes which will flow to the right neighbor from the right        */
-	/* most liquid item that cannot be shifted from S[0] entirely         */
-	/* if -1 then nothing will be partially shifted                           */
-	int s1bytes;		/* number of bytes which flow to the first  new node when S[0] splits   */
-	/* note: if S[0] splits into 3 nodes, then items do not need to be cut  */
-	int s2bytes;
-	struct buffer_head *buf_to_free[MAX_FREE_BLOCK];	/* buffers which are to be freed after do_balance finishes by unfix_nodes */
-	char *vn_buf;		/* kmalloced memory. Used to create
-				   virtual node and keep map of
-				   dirtied bitmap blocks */
-	int vn_buf_size;	/* size of the vn_buf */
-	struct virtual_node *tb_vn;	/* VN starts after bitmap of bitmap blocks */
-
-	int fs_gen;		/* saved value of `reiserfs_generation' counter
-				   see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */
-#ifdef DISPLACE_NEW_PACKING_LOCALITIES
-	struct in_core_key key;	/* key pointer, to pass to block allocator or
-				   another low-level subsystem */
-#endif
-};
-
-/* These are modes of balancing */
-
-/* When inserting an item. */
-#define M_INSERT	'i'
-/* When inserting into (directories only) or appending onto an already
-   existent item. */
-#define M_PASTE		'p'
-/* When deleting an item. */
-#define M_DELETE	'd'
-/* When truncating an item or removing an entry from a (directory) item. */
-#define M_CUT 		'c'
-
-/* used when balancing on leaf level skipped (in reiserfsck) */
-#define M_INTERNAL	'n'
-
-/* When further balancing is not needed, then do_balance does not need
-   to be called. */
-#define M_SKIP_BALANCING 		's'
-#define M_CONVERT	'v'
-
-/* modes of leaf_move_items */
-#define LEAF_FROM_S_TO_L 0
-#define LEAF_FROM_S_TO_R 1
-#define LEAF_FROM_R_TO_L 2
-#define LEAF_FROM_L_TO_R 3
-#define LEAF_FROM_S_TO_SNEW 4
-
-#define FIRST_TO_LAST 0
-#define LAST_TO_FIRST 1
-
-/* used in do_balance for passing parent of node information that has
-   been gotten from tb struct */
-struct buffer_info {
-	struct tree_balance *tb;
-	struct buffer_head *bi_bh;
-	struct buffer_head *bi_parent;
-	int bi_position;
-};
-
-static inline struct super_block *sb_from_tb(struct tree_balance *tb)
-{
-	return tb ? tb->tb_sb : NULL;
-}
-
-static inline struct super_block *sb_from_bi(struct buffer_info *bi)
-{
-	return bi ? sb_from_tb(bi->tb) : NULL;
-}
-
-/* there are 4 types of items: stat data, directory item, indirect, direct.
-+-------------------+------------+--------------+------------+
-|	            |  k_offset  | k_uniqueness | mergeable? |
-+-------------------+------------+--------------+------------+
-|     stat data     |	0        |      0       |   no       |
-+-------------------+------------+--------------+------------+
-| 1st directory item| DOT_OFFSET |DIRENTRY_UNIQUENESS|   no       | 
-| non 1st directory | hash value |              |   yes      |
-|     item          |            |              |            |
-+-------------------+------------+--------------+------------+
-| indirect item     | offset + 1 |TYPE_INDIRECT |   if this is not the first indirect item of the object
-+-------------------+------------+--------------+------------+
-| direct item       | offset + 1 |TYPE_DIRECT   | if not this is not the first direct item of the object
-+-------------------+------------+--------------+------------+
-*/
-
-struct item_operations {
-	int (*bytes_number) (struct item_head * ih, int block_size);
-	void (*decrement_key) (struct cpu_key *);
-	int (*is_left_mergeable) (struct reiserfs_key * ih,
-				  unsigned long bsize);
-	void (*print_item) (struct item_head *, char *item);
-	void (*check_item) (struct item_head *, char *item);
-
-	int (*create_vi) (struct virtual_node * vn, struct virtual_item * vi,
-			  int is_affected, int insert_size);
-	int (*check_left) (struct virtual_item * vi, int free,
-			   int start_skip, int end_skip);
-	int (*check_right) (struct virtual_item * vi, int free);
-	int (*part_size) (struct virtual_item * vi, int from, int to);
-	int (*unit_num) (struct virtual_item * vi);
-	void (*print_vi) (struct virtual_item * vi);
-};
-
-extern struct item_operations *item_ops[TYPE_ANY + 1];
-
-#define op_bytes_number(ih,bsize)                    item_ops[le_ih_k_type (ih)]->bytes_number (ih, bsize)
-#define op_is_left_mergeable(key,bsize)              item_ops[le_key_k_type (le_key_version (key), key)]->is_left_mergeable (key, bsize)
-#define op_print_item(ih,item)                       item_ops[le_ih_k_type (ih)]->print_item (ih, item)
-#define op_check_item(ih,item)                       item_ops[le_ih_k_type (ih)]->check_item (ih, item)
-#define op_create_vi(vn,vi,is_affected,insert_size)  item_ops[le_ih_k_type ((vi)->vi_ih)]->create_vi (vn,vi,is_affected,insert_size)
-#define op_check_left(vi,free,start_skip,end_skip) item_ops[(vi)->vi_index]->check_left (vi, free, start_skip, end_skip)
-#define op_check_right(vi,free)                      item_ops[(vi)->vi_index]->check_right (vi, free)
-#define op_part_size(vi,from,to)                     item_ops[(vi)->vi_index]->part_size (vi, from, to)
-#define op_unit_num(vi)				     item_ops[(vi)->vi_index]->unit_num (vi)
-#define op_print_vi(vi)                              item_ops[(vi)->vi_index]->print_vi (vi)
-
-#define COMP_SHORT_KEYS comp_short_keys
-
-/* number of blocks pointed to by the indirect item */
-#define I_UNFM_NUM(ih)	(ih_item_len(ih) / UNFM_P_SIZE)
-
-/* the used space within the unformatted node corresponding to pos within the item pointed to by ih */
-#define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - ih_free_space(ih) : (size))
-
-/* number of bytes contained by the direct item or the unformatted nodes the indirect item points to */
-
-/* get the item header */
-#define B_N_PITEM_HEAD(bh,item_num) ( (struct item_head * )((bh)->b_data + BLKH_SIZE) + (item_num) )
-
-/* get key */
-#define B_N_PDELIM_KEY(bh,item_num) ( (struct reiserfs_key * )((bh)->b_data + BLKH_SIZE) + (item_num) )
-
-/* get the key */
-#define B_N_PKEY(bh,item_num) ( &(B_N_PITEM_HEAD(bh,item_num)->ih_key) )
-
-/* get item body */
-#define B_N_PITEM(bh,item_num) ( (bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(item_num))))
-
-/* get the stat data by the buffer header and the item order */
-#define B_N_STAT_DATA(bh,nr) \
-( (struct stat_data *)((bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(nr))) ) )
-
-    /* following defines use reiserfs buffer header and item header */
-
-/* get stat-data */
-#define B_I_STAT_DATA(bh, ih) ( (struct stat_data * )((bh)->b_data + ih_location(ih)) )
-
-// this is 3976 for size==4096
-#define MAX_DIRECT_ITEM_LEN(size) ((size) - BLKH_SIZE - 2*IH_SIZE - SD_SIZE - UNFM_P_SIZE)
-
-/* indirect items consist of entries which contain blocknrs, pos
-   indicates which entry, and B_I_POS_UNFM_POINTER resolves to the
-   blocknr contained by the entry pos points to */
-#define B_I_POS_UNFM_POINTER(bh,ih,pos) le32_to_cpu(*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)))
-#define PUT_B_I_POS_UNFM_POINTER(bh,ih,pos, val) do {*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)) = cpu_to_le32(val); } while (0)
-
-struct reiserfs_iget_args {
-	__u32 objectid;
-	__u32 dirid;
-};
-
-/***************************************************************************/
-/*                    FUNCTION DECLARATIONS                                */
-/***************************************************************************/
-
-#define get_journal_desc_magic(bh) (bh->b_data + bh->b_size - 12)
-
-#define journal_trans_half(blocksize) \
-	((blocksize - sizeof (struct reiserfs_journal_desc) + sizeof (__u32) - 12) / sizeof (__u32))
-
-/* journal.c see journal.c for all the comments here */
-
-/* first block written in a commit.  */
-struct reiserfs_journal_desc {
-	__le32 j_trans_id;	/* id of commit */
-	__le32 j_len;		/* length of commit. len +1 is the commit block */
-	__le32 j_mount_id;	/* mount id of this trans */
-	__le32 j_realblock[1];	/* real locations for each block */
-};
-
-#define get_desc_trans_id(d)   le32_to_cpu((d)->j_trans_id)
-#define get_desc_trans_len(d)  le32_to_cpu((d)->j_len)
-#define get_desc_mount_id(d)   le32_to_cpu((d)->j_mount_id)
-
-#define set_desc_trans_id(d,val)       do { (d)->j_trans_id = cpu_to_le32 (val); } while (0)
-#define set_desc_trans_len(d,val)      do { (d)->j_len = cpu_to_le32 (val); } while (0)
-#define set_desc_mount_id(d,val)       do { (d)->j_mount_id = cpu_to_le32 (val); } while (0)
-
-/* last block written in a commit */
-struct reiserfs_journal_commit {
-	__le32 j_trans_id;	/* must match j_trans_id from the desc block */
-	__le32 j_len;		/* ditto */
-	__le32 j_realblock[1];	/* real locations for each block */
-};
-
-#define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id)
-#define get_commit_trans_len(c)        le32_to_cpu((c)->j_len)
-#define get_commit_mount_id(c) le32_to_cpu((c)->j_mount_id)
-
-#define set_commit_trans_id(c,val)     do { (c)->j_trans_id = cpu_to_le32 (val); } while (0)
-#define set_commit_trans_len(c,val)    do { (c)->j_len = cpu_to_le32 (val); } while (0)
-
-/* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the
-** last fully flushed transaction.  fully flushed means all the log blocks and all the real blocks are on disk,
-** and this transaction does not need to be replayed.
-*/
-struct reiserfs_journal_header {
-	__le32 j_last_flush_trans_id;	/* id of last fully flushed transaction */
-	__le32 j_first_unflushed_offset;	/* offset in the log of where to start replay after a crash */
-	__le32 j_mount_id;
-	/* 12 */ struct journal_params jh_journal;
-};
-
-/* biggest tunable defines are right here */
-#define JOURNAL_BLOCK_COUNT 8192	/* number of blocks in the journal */
-#define JOURNAL_TRANS_MAX_DEFAULT 1024	/* biggest possible single transaction, don't change for now (8/3/99) */
-#define JOURNAL_TRANS_MIN_DEFAULT 256
-#define JOURNAL_MAX_BATCH_DEFAULT   900	/* max blocks to batch into one transaction, don't make this any bigger than 900 */
-#define JOURNAL_MIN_RATIO 2
-#define JOURNAL_MAX_COMMIT_AGE 30
-#define JOURNAL_MAX_TRANS_AGE 30
-#define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9)
-#define JOURNAL_BLOCKS_PER_OBJECT(sb)  (JOURNAL_PER_BALANCE_CNT * 3 + \
-					 2 * (REISERFS_QUOTA_INIT_BLOCKS(sb) + \
-					      REISERFS_QUOTA_TRANS_BLOCKS(sb)))
-
-#ifdef CONFIG_QUOTA
-#define REISERFS_QUOTA_OPTS ((1 << REISERFS_USRQUOTA) | (1 << REISERFS_GRPQUOTA))
-/* We need to update data and inode (atime) */
-#define REISERFS_QUOTA_TRANS_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? 2 : 0)
-/* 1 balancing, 1 bitmap, 1 data per write + stat data update */
-#define REISERFS_QUOTA_INIT_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? \
-(DQUOT_INIT_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_INIT_REWRITE+1) : 0)
-/* same as with INIT */
-#define REISERFS_QUOTA_DEL_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? \
-(DQUOT_DEL_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_DEL_REWRITE+1) : 0)
-#else
-#define REISERFS_QUOTA_TRANS_BLOCKS(s) 0
-#define REISERFS_QUOTA_INIT_BLOCKS(s) 0
-#define REISERFS_QUOTA_DEL_BLOCKS(s) 0
-#endif
-
-/* both of these can be as low as 1, or as high as you want.  The min is the
-** number of 4k bitmap nodes preallocated on mount. New nodes are allocated
-** as needed, and released when transactions are committed.  On release, if 
-** the current number of nodes is > max, the node is freed, otherwise, 
-** it is put on a free list for faster use later.
-*/
-#define REISERFS_MIN_BITMAP_NODES 10
-#define REISERFS_MAX_BITMAP_NODES 100
-
-#define JBH_HASH_SHIFT 13	/* these are based on journal hash size of 8192 */
-#define JBH_HASH_MASK 8191
-
-#define _jhashfn(sb,block)	\
-	(((unsigned long)sb>>L1_CACHE_SHIFT) ^ \
-	 (((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12))))
-#define journal_hash(t,sb,block) ((t)[_jhashfn((sb),(block)) & JBH_HASH_MASK])
-
-// We need these to make journal.c code more readable
-#define journal_find_get_block(s, block) __find_get_block(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
-#define journal_getblk(s, block) __getblk(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
-#define journal_bread(s, block) __bread(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
-
-enum reiserfs_bh_state_bits {
-	BH_JDirty = BH_PrivateStart,	/* buffer is in current transaction */
-	BH_JDirty_wait,
-	BH_JNew,		/* disk block was taken off free list before
-				 * being in a finished transaction, or
-				 * written to disk. Can be reused immed. */
-	BH_JPrepared,
-	BH_JRestore_dirty,
-	BH_JTest,		// debugging only will go away
-};
-
-BUFFER_FNS(JDirty, journaled);
-TAS_BUFFER_FNS(JDirty, journaled);
-BUFFER_FNS(JDirty_wait, journal_dirty);
-TAS_BUFFER_FNS(JDirty_wait, journal_dirty);
-BUFFER_FNS(JNew, journal_new);
-TAS_BUFFER_FNS(JNew, journal_new);
-BUFFER_FNS(JPrepared, journal_prepared);
-TAS_BUFFER_FNS(JPrepared, journal_prepared);
-BUFFER_FNS(JRestore_dirty, journal_restore_dirty);
-TAS_BUFFER_FNS(JRestore_dirty, journal_restore_dirty);
-BUFFER_FNS(JTest, journal_test);
-TAS_BUFFER_FNS(JTest, journal_test);
-
-/*
-** transaction handle which is passed around for all journal calls
-*/
-struct reiserfs_transaction_handle {
-	struct super_block *t_super;	/* super for this FS when journal_begin was
-					   called. saves calls to reiserfs_get_super
-					   also used by nested transactions to make
-					   sure they are nesting on the right FS
-					   _must_ be first in the handle
-					 */
-	int t_refcount;
-	int t_blocks_logged;	/* number of blocks this writer has logged */
-	int t_blocks_allocated;	/* number of blocks this writer allocated */
-	unsigned int t_trans_id;	/* sanity check, equals the current trans id */
-	void *t_handle_save;	/* save existing current->journal_info */
-	unsigned displace_new_blocks:1;	/* if new block allocation occurres, that block
-					   should be displaced from others */
-	struct list_head t_list;
-};
-
-/* used to keep track of ordered and tail writes, attached to the buffer
- * head through b_journal_head.
- */
-struct reiserfs_jh {
-	struct reiserfs_journal_list *jl;
-	struct buffer_head *bh;
-	struct list_head list;
-};
-
-void reiserfs_free_jh(struct buffer_head *bh);
-int reiserfs_add_tail_list(struct inode *inode, struct buffer_head *bh);
-int reiserfs_add_ordered_list(struct inode *inode, struct buffer_head *bh);
-int journal_mark_dirty(struct reiserfs_transaction_handle *,
-		       struct super_block *, struct buffer_head *bh);
-
-static inline int reiserfs_file_data_log(struct inode *inode)
-{
-	if (reiserfs_data_log(inode->i_sb) ||
-	    (REISERFS_I(inode)->i_flags & i_data_log))
-		return 1;
-	return 0;
-}
-
-static inline int reiserfs_transaction_running(struct super_block *s)
-{
-	struct reiserfs_transaction_handle *th = current->journal_info;
-	if (th && th->t_super == s)
-		return 1;
-	if (th && th->t_super == NULL)
-		BUG();
-	return 0;
-}
-
-static inline int reiserfs_transaction_free_space(struct reiserfs_transaction_handle *th)
-{
-	return th->t_blocks_allocated - th->t_blocks_logged;
-}
-
-struct reiserfs_transaction_handle *reiserfs_persistent_transaction(struct
-								    super_block
-								    *,
-								    int count);
-int reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *);
-int reiserfs_commit_page(struct inode *inode, struct page *page,
-			 unsigned from, unsigned to);
-int reiserfs_flush_old_commits(struct super_block *);
-int reiserfs_commit_for_inode(struct inode *);
-int reiserfs_inode_needs_commit(struct inode *);
-void reiserfs_update_inode_transaction(struct inode *);
-void reiserfs_wait_on_write_block(struct super_block *s);
-void reiserfs_block_writes(struct reiserfs_transaction_handle *th);
-void reiserfs_allow_writes(struct super_block *s);
-void reiserfs_check_lock_depth(struct super_block *s, char *caller);
-int reiserfs_prepare_for_journal(struct super_block *, struct buffer_head *bh,
-				 int wait);
-void reiserfs_restore_prepared_buffer(struct super_block *,
-				      struct buffer_head *bh);
-int journal_init(struct super_block *, const char *j_dev_name, int old_format,
-		 unsigned int);
-int journal_release(struct reiserfs_transaction_handle *, struct super_block *);
-int journal_release_error(struct reiserfs_transaction_handle *,
-			  struct super_block *);
-int journal_end(struct reiserfs_transaction_handle *, struct super_block *,
-		unsigned long);
-int journal_end_sync(struct reiserfs_transaction_handle *, struct super_block *,
-		     unsigned long);
-int journal_mark_freed(struct reiserfs_transaction_handle *,
-		       struct super_block *, b_blocknr_t blocknr);
-int journal_transaction_should_end(struct reiserfs_transaction_handle *, int);
-int reiserfs_in_journal(struct super_block *sb, unsigned int bmap_nr,
-			 int bit_nr, int searchall, b_blocknr_t *next);
-int journal_begin(struct reiserfs_transaction_handle *,
-		  struct super_block *sb, unsigned long);
-int journal_join_abort(struct reiserfs_transaction_handle *,
-		       struct super_block *sb, unsigned long);
-void reiserfs_abort_journal(struct super_block *sb, int errno);
-void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...);
-int reiserfs_allocate_list_bitmaps(struct super_block *s,
-				   struct reiserfs_list_bitmap *, unsigned int);
-
-void add_save_link(struct reiserfs_transaction_handle *th,
-		   struct inode *inode, int truncate);
-int remove_save_link(struct inode *inode, int truncate);
-
-/* objectid.c */
-__u32 reiserfs_get_unused_objectid(struct reiserfs_transaction_handle *th);
-void reiserfs_release_objectid(struct reiserfs_transaction_handle *th,
-			       __u32 objectid_to_release);
-int reiserfs_convert_objectid_map_v1(struct super_block *);
-
-/* stree.c */
-int B_IS_IN_TREE(const struct buffer_head *);
-extern void copy_item_head(struct item_head *to,
-			   const struct item_head *from);
-
-// first key is in cpu form, second - le
-extern int comp_short_keys(const struct reiserfs_key *le_key,
-			   const struct cpu_key *cpu_key);
-extern void le_key2cpu_key(struct cpu_key *to, const struct reiserfs_key *from);
-
-// both are in le form
-extern int comp_le_keys(const struct reiserfs_key *,
-			const struct reiserfs_key *);
-extern int comp_short_le_keys(const struct reiserfs_key *,
-			      const struct reiserfs_key *);
-
-//
-// get key version from on disk key - kludge
-//
-static inline int le_key_version(const struct reiserfs_key *key)
-{
-	int type;
-
-	type = offset_v2_k_type(&(key->u.k_offset_v2));
-	if (type != TYPE_DIRECT && type != TYPE_INDIRECT
-	    && type != TYPE_DIRENTRY)
-		return KEY_FORMAT_3_5;
-
-	return KEY_FORMAT_3_6;
-
-}
-
-static inline void copy_key(struct reiserfs_key *to,
-			    const struct reiserfs_key *from)
-{
-	memcpy(to, from, KEY_SIZE);
-}
-
-int comp_items(const struct item_head *stored_ih, const struct treepath *path);
-const struct reiserfs_key *get_rkey(const struct treepath *chk_path,
-				    const struct super_block *sb);
-int search_by_key(struct super_block *, const struct cpu_key *,
-		  struct treepath *, int);
-#define search_item(s,key,path) search_by_key (s, key, path, DISK_LEAF_NODE_LEVEL)
-int search_for_position_by_key(struct super_block *sb,
-			       const struct cpu_key *cpu_key,
-			       struct treepath *search_path);
-extern void decrement_bcount(struct buffer_head *bh);
-void decrement_counters_in_path(struct treepath *search_path);
-void pathrelse(struct treepath *search_path);
-int reiserfs_check_path(struct treepath *p);
-void pathrelse_and_restore(struct super_block *s, struct treepath *search_path);
-
-int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
-			 struct treepath *path,
-			 const struct cpu_key *key,
-			 struct item_head *ih,
-			 struct inode *inode, const char *body);
-
-int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th,
-			     struct treepath *path,
-			     const struct cpu_key *key,
-			     struct inode *inode,
-			     const char *body, int paste_size);
-
-int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th,
-			   struct treepath *path,
-			   struct cpu_key *key,
-			   struct inode *inode,
-			   struct page *page, loff_t new_file_size);
-
-int reiserfs_delete_item(struct reiserfs_transaction_handle *th,
-			 struct treepath *path,
-			 const struct cpu_key *key,
-			 struct inode *inode, struct buffer_head *un_bh);
-
-void reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th,
-				struct inode *inode, struct reiserfs_key *key);
-int reiserfs_delete_object(struct reiserfs_transaction_handle *th,
-			   struct inode *inode);
-int reiserfs_do_truncate(struct reiserfs_transaction_handle *th,
-			 struct inode *inode, struct page *,
-			 int update_timestamps);
-
-#define i_block_size(inode) ((inode)->i_sb->s_blocksize)
-#define file_size(inode) ((inode)->i_size)
-#define tail_size(inode) (file_size (inode) & (i_block_size (inode) - 1))
-
-#define tail_has_to_be_packed(inode) (have_large_tails ((inode)->i_sb)?\
-!STORE_TAIL_IN_UNFM_S1(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):have_small_tails ((inode)->i_sb)?!STORE_TAIL_IN_UNFM_S2(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):0 )
-
-void padd_item(char *item, int total_length, int length);
-
-/* inode.c */
-/* args for the create parameter of reiserfs_get_block */
-#define GET_BLOCK_NO_CREATE 0	/* don't create new blocks or convert tails */
-#define GET_BLOCK_CREATE 1	/* add anything you need to find block */
-#define GET_BLOCK_NO_HOLE 2	/* return -ENOENT for file holes */
-#define GET_BLOCK_READ_DIRECT 4	/* read the tail if indirect item not found */
-#define GET_BLOCK_NO_IMUX     8	/* i_mutex is not held, don't preallocate */
-#define GET_BLOCK_NO_DANGLE   16	/* don't leave any transactions running */
-
-void reiserfs_read_locked_inode(struct inode *inode,
-				struct reiserfs_iget_args *args);
-int reiserfs_find_actor(struct inode *inode, void *p);
-int reiserfs_init_locked_inode(struct inode *inode, void *p);
-void reiserfs_evict_inode(struct inode *inode);
-int reiserfs_write_inode(struct inode *inode, struct writeback_control *wbc);
-int reiserfs_get_block(struct inode *inode, sector_t block,
-		       struct buffer_head *bh_result, int create);
-struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
-				     int fh_len, int fh_type);
-struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid,
-				     int fh_len, int fh_type);
-int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp,
-		       int connectable);
-
-int reiserfs_truncate_file(struct inode *, int update_timestamps);
-void make_cpu_key(struct cpu_key *cpu_key, struct inode *inode, loff_t offset,
-		  int type, int key_length);
-void make_le_item_head(struct item_head *ih, const struct cpu_key *key,
-		       int version,
-		       loff_t offset, int type, int length, int entry_count);
-struct inode *reiserfs_iget(struct super_block *s, const struct cpu_key *key);
-
-struct reiserfs_security_handle;
-int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
-		       struct inode *dir, umode_t mode,
-		       const char *symname, loff_t i_size,
-		       struct dentry *dentry, struct inode *inode,
-		       struct reiserfs_security_handle *security);
-
-void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th,
-			     struct inode *inode, loff_t size);
-
-static inline void reiserfs_update_sd(struct reiserfs_transaction_handle *th,
-				      struct inode *inode)
-{
-	reiserfs_update_sd_size(th, inode, inode->i_size);
-}
-
-void sd_attrs_to_i_attrs(__u16 sd_attrs, struct inode *inode);
-void i_attrs_to_sd_attrs(struct inode *inode, __u16 * sd_attrs);
-int reiserfs_setattr(struct dentry *dentry, struct iattr *attr);
-
-int __reiserfs_write_begin(struct page *page, unsigned from, unsigned len);
-
-/* namei.c */
-void set_de_name_and_namelen(struct reiserfs_dir_entry *de);
-int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
-			struct treepath *path, struct reiserfs_dir_entry *de);
-struct dentry *reiserfs_get_parent(struct dentry *);
-
-#ifdef CONFIG_REISERFS_PROC_INFO
-int reiserfs_proc_info_init(struct super_block *sb);
-int reiserfs_proc_info_done(struct super_block *sb);
-int reiserfs_proc_info_global_init(void);
-int reiserfs_proc_info_global_done(void);
-
-#define PROC_EXP( e )   e
-
-#define __PINFO( sb ) REISERFS_SB(sb) -> s_proc_info_data
-#define PROC_INFO_MAX( sb, field, value )								\
-    __PINFO( sb ).field =												\
-        max( REISERFS_SB( sb ) -> s_proc_info_data.field, value )
-#define PROC_INFO_INC( sb, field ) ( ++ ( __PINFO( sb ).field ) )
-#define PROC_INFO_ADD( sb, field, val ) ( __PINFO( sb ).field += ( val ) )
-#define PROC_INFO_BH_STAT( sb, bh, level )							\
-    PROC_INFO_INC( sb, sbk_read_at[ ( level ) ] );						\
-    PROC_INFO_ADD( sb, free_at[ ( level ) ], B_FREE_SPACE( bh ) );	\
-    PROC_INFO_ADD( sb, items_at[ ( level ) ], B_NR_ITEMS( bh ) )
-#else
-static inline int reiserfs_proc_info_init(struct super_block *sb)
-{
-	return 0;
-}
-
-static inline int reiserfs_proc_info_done(struct super_block *sb)
-{
-	return 0;
-}
-
-static inline int reiserfs_proc_info_global_init(void)
-{
-	return 0;
-}
-
-static inline int reiserfs_proc_info_global_done(void)
-{
-	return 0;
-}
-
-#define PROC_EXP( e )
-#define VOID_V ( ( void ) 0 )
-#define PROC_INFO_MAX( sb, field, value ) VOID_V
-#define PROC_INFO_INC( sb, field ) VOID_V
-#define PROC_INFO_ADD( sb, field, val ) VOID_V
-#define PROC_INFO_BH_STAT(sb, bh, n_node_level) VOID_V
-#endif
-
-/* dir.c */
-extern const struct inode_operations reiserfs_dir_inode_operations;
-extern const struct inode_operations reiserfs_symlink_inode_operations;
-extern const struct inode_operations reiserfs_special_inode_operations;
-extern const struct file_operations reiserfs_dir_operations;
-int reiserfs_readdir_dentry(struct dentry *, void *, filldir_t, loff_t *);
-
-/* tail_conversion.c */
-int direct2indirect(struct reiserfs_transaction_handle *, struct inode *,
-		    struct treepath *, struct buffer_head *, loff_t);
-int indirect2direct(struct reiserfs_transaction_handle *, struct inode *,
-		    struct page *, struct treepath *, const struct cpu_key *,
-		    loff_t, char *);
-void reiserfs_unmap_buffer(struct buffer_head *);
-
-/* file.c */
-extern const struct inode_operations reiserfs_file_inode_operations;
-extern const struct file_operations reiserfs_file_operations;
-extern const struct address_space_operations reiserfs_address_space_operations;
-
-/* fix_nodes.c */
-
-int fix_nodes(int n_op_mode, struct tree_balance *tb,
-	      struct item_head *ins_ih, const void *);
-void unfix_nodes(struct tree_balance *);
-
-/* prints.c */
-void __reiserfs_panic(struct super_block *s, const char *id,
-		      const char *function, const char *fmt, ...)
-    __attribute__ ((noreturn));
-#define reiserfs_panic(s, id, fmt, args...) \
-	__reiserfs_panic(s, id, __func__, fmt, ##args)
-void __reiserfs_error(struct super_block *s, const char *id,
-		      const char *function, const char *fmt, ...);
-#define reiserfs_error(s, id, fmt, args...) \
-	 __reiserfs_error(s, id, __func__, fmt, ##args)
-void reiserfs_info(struct super_block *s, const char *fmt, ...);
-void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...);
-void print_indirect_item(struct buffer_head *bh, int item_num);
-void store_print_tb(struct tree_balance *tb);
-void print_cur_tb(char *mes);
-void print_de(struct reiserfs_dir_entry *de);
-void print_bi(struct buffer_info *bi, char *mes);
-#define PRINT_LEAF_ITEMS 1	/* print all items */
-#define PRINT_DIRECTORY_ITEMS 2	/* print directory items */
-#define PRINT_DIRECT_ITEMS 4	/* print contents of direct items */
-void print_block(struct buffer_head *bh, ...);
-void print_bmap(struct super_block *s, int silent);
-void print_bmap_block(int i, char *data, int size, int silent);
-/*void print_super_block (struct super_block * s, char * mes);*/
-void print_objectid_map(struct super_block *s);
-void print_block_head(struct buffer_head *bh, char *mes);
-void check_leaf(struct buffer_head *bh);
-void check_internal(struct buffer_head *bh);
-void print_statistics(struct super_block *s);
-char *reiserfs_hashname(int code);
-
-/* lbalance.c */
-int leaf_move_items(int shift_mode, struct tree_balance *tb, int mov_num,
-		    int mov_bytes, struct buffer_head *Snew);
-int leaf_shift_left(struct tree_balance *tb, int shift_num, int shift_bytes);
-int leaf_shift_right(struct tree_balance *tb, int shift_num, int shift_bytes);
-void leaf_delete_items(struct buffer_info *cur_bi, int last_first, int first,
-		       int del_num, int del_bytes);
-void leaf_insert_into_buf(struct buffer_info *bi, int before,
-			  struct item_head *inserted_item_ih,
-			  const char *inserted_item_body, int zeros_number);
-void leaf_paste_in_buffer(struct buffer_info *bi, int pasted_item_num,
-			  int pos_in_item, int paste_size, const char *body,
-			  int zeros_number);
-void leaf_cut_from_buffer(struct buffer_info *bi, int cut_item_num,
-			  int pos_in_item, int cut_size);
-void leaf_paste_entries(struct buffer_info *bi, int item_num, int before,
-			int new_entry_count, struct reiserfs_de_head *new_dehs,
-			const char *records, int paste_size);
-/* ibalance.c */
-int balance_internal(struct tree_balance *, int, int, struct item_head *,
-		     struct buffer_head **);
-
-/* do_balance.c */
-void do_balance_mark_leaf_dirty(struct tree_balance *tb,
-				struct buffer_head *bh, int flag);
-#define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty
-#define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty
-
-void do_balance(struct tree_balance *tb, struct item_head *ih,
-		const char *body, int flag);
-void reiserfs_invalidate_buffer(struct tree_balance *tb,
-				struct buffer_head *bh);
-
-int get_left_neighbor_position(struct tree_balance *tb, int h);
-int get_right_neighbor_position(struct tree_balance *tb, int h);
-void replace_key(struct tree_balance *tb, struct buffer_head *, int,
-		 struct buffer_head *, int);
-void make_empty_node(struct buffer_info *);
-struct buffer_head *get_FEB(struct tree_balance *);
-
-/* bitmap.c */
-
-/* structure contains hints for block allocator, and it is a container for
- * arguments, such as node, search path, transaction_handle, etc. */
-struct __reiserfs_blocknr_hint {
-	struct inode *inode;	/* inode passed to allocator, if we allocate unf. nodes */
-	sector_t block;		/* file offset, in blocks */
-	struct in_core_key key;
-	struct treepath *path;	/* search path, used by allocator to deternine search_start by
-				 * various ways */
-	struct reiserfs_transaction_handle *th;	/* transaction handle is needed to log super blocks and
-						 * bitmap blocks changes  */
-	b_blocknr_t beg, end;
-	b_blocknr_t search_start;	/* a field used to transfer search start value (block number)
-					 * between different block allocator procedures
-					 * (determine_search_start() and others) */
-	int prealloc_size;	/* is set in determine_prealloc_size() function, used by underlayed
-				 * function that do actual allocation */
-
-	unsigned formatted_node:1;	/* the allocator uses different polices for getting disk space for
-					 * formatted/unformatted blocks with/without preallocation */
-	unsigned preallocate:1;
-};
-
-typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t;
-
-int reiserfs_parse_alloc_options(struct super_block *, char *);
-void reiserfs_init_alloc_options(struct super_block *s);
-
-/*
- * given a directory, this will tell you what packing locality
- * to use for a new object underneat it.  The locality is returned
- * in disk byte order (le).
- */
-__le32 reiserfs_choose_packing(struct inode *dir);
-
-int reiserfs_init_bitmap_cache(struct super_block *sb);
-void reiserfs_free_bitmap_cache(struct super_block *sb);
-void reiserfs_cache_bitmap_metadata(struct super_block *sb, struct buffer_head *bh, struct reiserfs_bitmap_info *info);
-struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, unsigned int bitmap);
-int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value);
-void reiserfs_free_block(struct reiserfs_transaction_handle *th, struct inode *,
-			 b_blocknr_t, int for_unformatted);
-int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t *, int,
-			       int);
-static inline int reiserfs_new_form_blocknrs(struct tree_balance *tb,
-					     b_blocknr_t * new_blocknrs,
-					     int amount_needed)
-{
-	reiserfs_blocknr_hint_t hint = {
-		.th = tb->transaction_handle,
-		.path = tb->tb_path,
-		.inode = NULL,
-		.key = tb->key,
-		.block = 0,
-		.formatted_node = 1
-	};
-	return reiserfs_allocate_blocknrs(&hint, new_blocknrs, amount_needed,
-					  0);
-}
-
-static inline int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle
-					    *th, struct inode *inode,
-					    b_blocknr_t * new_blocknrs,
-					    struct treepath *path,
-					    sector_t block)
-{
-	reiserfs_blocknr_hint_t hint = {
-		.th = th,
-		.path = path,
-		.inode = inode,
-		.block = block,
-		.formatted_node = 0,
-		.preallocate = 0
-	};
-	return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
-}
-
-#ifdef REISERFS_PREALLOCATE
-static inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle
-					     *th, struct inode *inode,
-					     b_blocknr_t * new_blocknrs,
-					     struct treepath *path,
-					     sector_t block)
-{
-	reiserfs_blocknr_hint_t hint = {
-		.th = th,
-		.path = path,
-		.inode = inode,
-		.block = block,
-		.formatted_node = 0,
-		.preallocate = 1
-	};
-	return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
-}
-
-void reiserfs_discard_prealloc(struct reiserfs_transaction_handle *th,
-			       struct inode *inode);
-void reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle *th);
-#endif
-
-/* hashes.c */
-__u32 keyed_hash(const signed char *msg, int len);
-__u32 yura_hash(const signed char *msg, int len);
-__u32 r5_hash(const signed char *msg, int len);
-
-#define reiserfs_set_le_bit		__set_bit_le
-#define reiserfs_test_and_set_le_bit	__test_and_set_bit_le
-#define reiserfs_clear_le_bit		__clear_bit_le
-#define reiserfs_test_and_clear_le_bit	__test_and_clear_bit_le
-#define reiserfs_test_le_bit		test_bit_le
-#define reiserfs_find_next_zero_le_bit	find_next_zero_bit_le
-
-/* sometimes reiserfs_truncate may require to allocate few new blocks
-   to perform indirect2direct conversion. People probably used to
-   think, that truncate should work without problems on a filesystem
-   without free disk space. They may complain that they can not
-   truncate due to lack of free disk space. This spare space allows us
-   to not worry about it. 500 is probably too much, but it should be
-   absolutely safe */
-#define SPARE_SPACE 500
-
-/* prototypes from ioctl.c */
-long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
-long reiserfs_compat_ioctl(struct file *filp,
-		   unsigned int cmd, unsigned long arg);
-int reiserfs_unpack(struct inode *inode, struct file *filp);
-
-#endif /* __KERNEL__ */
-
 #endif				/* _LINUX_REISER_FS_H */
diff --git a/include/linux/reiserfs_fs_i.h b/include/linux/reiserfs_fs_i.h
deleted file mode 100644
index 97959bd..0000000
--- a/include/linux/reiserfs_fs_i.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef _REISER_FS_I
-#define _REISER_FS_I
-
-#include <linux/list.h>
-
-struct reiserfs_journal_list;
-
-/** bitmasks for i_flags field in reiserfs-specific part of inode */
-typedef enum {
-    /** this says what format of key do all items (but stat data) of
-      an object have.  If this is set, that format is 3.6 otherwise
-      - 3.5 */
-	i_item_key_version_mask = 0x0001,
-    /** If this is unset, object has 3.5 stat data, otherwise, it has
-      3.6 stat data with 64bit size, 32bit nlink etc. */
-	i_stat_data_version_mask = 0x0002,
-    /** file might need tail packing on close */
-	i_pack_on_close_mask = 0x0004,
-    /** don't pack tail of file */
-	i_nopack_mask = 0x0008,
-    /** If those is set, "safe link" was created for this file during
-      truncate or unlink. Safe link is used to avoid leakage of disk
-      space on crash with some files open, but unlinked. */
-	i_link_saved_unlink_mask = 0x0010,
-	i_link_saved_truncate_mask = 0x0020,
-	i_has_xattr_dir = 0x0040,
-	i_data_log = 0x0080,
-} reiserfs_inode_flags;
-
-struct reiserfs_inode_info {
-	__u32 i_key[4];		/* key is still 4 32 bit integers */
-    /** transient inode flags that are never stored on disk. Bitmasks
-      for this field are defined above. */
-	__u32 i_flags;
-
-	__u32 i_first_direct_byte;	// offset of first byte stored in direct item.
-
-	/* copy of persistent inode flags read from sd_attrs. */
-	__u32 i_attrs;
-
-	int i_prealloc_block;	/* first unused block of a sequence of unused blocks */
-	int i_prealloc_count;	/* length of that sequence */
-	struct list_head i_prealloc_list;	/* per-transaction list of inodes which
-						 * have preallocated blocks */
-
-	unsigned new_packing_locality:1;	/* new_packig_locality is created; new blocks
-						 * for the contents of this directory should be
-						 * displaced */
-
-	/* we use these for fsync or O_SYNC to decide which transaction
-	 ** needs to be committed in order for this inode to be properly
-	 ** flushed */
-	unsigned int i_trans_id;
-	struct reiserfs_journal_list *i_jl;
-	atomic_t openers;
-	struct mutex tailpack;
-#ifdef CONFIG_REISERFS_FS_XATTR
-	struct rw_semaphore i_xattr_sem;
-#endif
-	struct inode vfs_inode;
-};
-
-#endif
diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
deleted file mode 100644
index 8c9e85c..0000000
--- a/include/linux/reiserfs_fs_sb.h
+++ /dev/null
@@ -1,554 +0,0 @@
-/* Copyright 1996-2000 Hans Reiser, see reiserfs/README for licensing
- * and copyright details */
-
-#ifndef _LINUX_REISER_FS_SB
-#define _LINUX_REISER_FS_SB
-
-#ifdef __KERNEL__
-#include <linux/workqueue.h>
-#include <linux/rwsem.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#endif
-
-typedef enum {
-	reiserfs_attrs_cleared = 0x00000001,
-} reiserfs_super_block_flags;
-
-/* struct reiserfs_super_block accessors/mutators
- * since this is a disk structure, it will always be in
- * little endian format. */
-#define sb_block_count(sbp)         (le32_to_cpu((sbp)->s_v1.s_block_count))
-#define set_sb_block_count(sbp,v)   ((sbp)->s_v1.s_block_count = cpu_to_le32(v))
-#define sb_free_blocks(sbp)         (le32_to_cpu((sbp)->s_v1.s_free_blocks))
-#define set_sb_free_blocks(sbp,v)   ((sbp)->s_v1.s_free_blocks = cpu_to_le32(v))
-#define sb_root_block(sbp)          (le32_to_cpu((sbp)->s_v1.s_root_block))
-#define set_sb_root_block(sbp,v)    ((sbp)->s_v1.s_root_block = cpu_to_le32(v))
-
-#define sb_jp_journal_1st_block(sbp)  \
-              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_1st_block))
-#define set_sb_jp_journal_1st_block(sbp,v) \
-              ((sbp)->s_v1.s_journal.jp_journal_1st_block = cpu_to_le32(v))
-#define sb_jp_journal_dev(sbp) \
-              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_dev))
-#define set_sb_jp_journal_dev(sbp,v) \
-              ((sbp)->s_v1.s_journal.jp_journal_dev = cpu_to_le32(v))
-#define sb_jp_journal_size(sbp) \
-              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_size))
-#define set_sb_jp_journal_size(sbp,v) \
-              ((sbp)->s_v1.s_journal.jp_journal_size = cpu_to_le32(v))
-#define sb_jp_journal_trans_max(sbp) \
-              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_trans_max))
-#define set_sb_jp_journal_trans_max(sbp,v) \
-              ((sbp)->s_v1.s_journal.jp_journal_trans_max = cpu_to_le32(v))
-#define sb_jp_journal_magic(sbp) \
-              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_magic))
-#define set_sb_jp_journal_magic(sbp,v) \
-              ((sbp)->s_v1.s_journal.jp_journal_magic = cpu_to_le32(v))
-#define sb_jp_journal_max_batch(sbp) \
-              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_max_batch))
-#define set_sb_jp_journal_max_batch(sbp,v) \
-              ((sbp)->s_v1.s_journal.jp_journal_max_batch = cpu_to_le32(v))
-#define sb_jp_jourmal_max_commit_age(sbp) \
-              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_max_commit_age))
-#define set_sb_jp_journal_max_commit_age(sbp,v) \
-              ((sbp)->s_v1.s_journal.jp_journal_max_commit_age = cpu_to_le32(v))
-
-#define sb_blocksize(sbp)          (le16_to_cpu((sbp)->s_v1.s_blocksize))
-#define set_sb_blocksize(sbp,v)    ((sbp)->s_v1.s_blocksize = cpu_to_le16(v))
-#define sb_oid_maxsize(sbp)        (le16_to_cpu((sbp)->s_v1.s_oid_maxsize))
-#define set_sb_oid_maxsize(sbp,v)  ((sbp)->s_v1.s_oid_maxsize = cpu_to_le16(v))
-#define sb_oid_cursize(sbp)        (le16_to_cpu((sbp)->s_v1.s_oid_cursize))
-#define set_sb_oid_cursize(sbp,v)  ((sbp)->s_v1.s_oid_cursize = cpu_to_le16(v))
-#define sb_umount_state(sbp)       (le16_to_cpu((sbp)->s_v1.s_umount_state))
-#define set_sb_umount_state(sbp,v) ((sbp)->s_v1.s_umount_state = cpu_to_le16(v))
-#define sb_fs_state(sbp)           (le16_to_cpu((sbp)->s_v1.s_fs_state))
-#define set_sb_fs_state(sbp,v)     ((sbp)->s_v1.s_fs_state = cpu_to_le16(v))
-#define sb_hash_function_code(sbp) \
-              (le32_to_cpu((sbp)->s_v1.s_hash_function_code))
-#define set_sb_hash_function_code(sbp,v) \
-              ((sbp)->s_v1.s_hash_function_code = cpu_to_le32(v))
-#define sb_tree_height(sbp)        (le16_to_cpu((sbp)->s_v1.s_tree_height))
-#define set_sb_tree_height(sbp,v)  ((sbp)->s_v1.s_tree_height = cpu_to_le16(v))
-#define sb_bmap_nr(sbp)            (le16_to_cpu((sbp)->s_v1.s_bmap_nr))
-#define set_sb_bmap_nr(sbp,v)      ((sbp)->s_v1.s_bmap_nr = cpu_to_le16(v))
-#define sb_version(sbp)            (le16_to_cpu((sbp)->s_v1.s_version))
-#define set_sb_version(sbp,v)      ((sbp)->s_v1.s_version = cpu_to_le16(v))
-
-#define sb_mnt_count(sbp)	   (le16_to_cpu((sbp)->s_mnt_count))
-#define set_sb_mnt_count(sbp, v)   ((sbp)->s_mnt_count = cpu_to_le16(v))
-
-#define sb_reserved_for_journal(sbp) \
-              (le16_to_cpu((sbp)->s_v1.s_reserved_for_journal))
-#define set_sb_reserved_for_journal(sbp,v) \
-              ((sbp)->s_v1.s_reserved_for_journal = cpu_to_le16(v))
-
-/* LOGGING -- */
-
-/* These all interelate for performance.
-**
-** If the journal block count is smaller than n transactions, you lose speed.
-** I don't know what n is yet, I'm guessing 8-16.
-**
-** typical transaction size depends on the application, how often fsync is
-** called, and how many metadata blocks you dirty in a 30 second period.
-** The more small files (<16k) you use, the larger your transactions will
-** be.
-**
-** If your journal fills faster than dirty buffers get flushed to disk, it must flush them before allowing the journal
-** to wrap, which slows things down.  If you need high speed meta data updates, the journal should be big enough
-** to prevent wrapping before dirty meta blocks get to disk.
-**
-** If the batch max is smaller than the transaction max, you'll waste space at the end of the journal
-** because journal_end sets the next transaction to start at 0 if the next transaction has any chance of wrapping.
-**
-** The large the batch max age, the better the speed, and the more meta data changes you'll lose after a crash.
-**
-*/
-
-/* don't mess with these for a while */
-				/* we have a node size define somewhere in reiserfs_fs.h. -Hans */
-#define JOURNAL_BLOCK_SIZE  4096	/* BUG gotta get rid of this */
-#define JOURNAL_MAX_CNODE   1500	/* max cnodes to allocate. */
-#define JOURNAL_HASH_SIZE 8192
-#define JOURNAL_NUM_BITMAPS 5	/* number of copies of the bitmaps to have floating.  Must be >= 2 */
-
-/* One of these for every block in every transaction
-** Each one is in two hash tables.  First, a hash of the current transaction, and after journal_end, a
-** hash of all the in memory transactions.
-** next and prev are used by the current transaction (journal_hash).
-** hnext and hprev are used by journal_list_hash.  If a block is in more than one transaction, the journal_list_hash
-** links it in multiple times.  This allows flush_journal_list to remove just the cnode belonging
-** to a given transaction.
-*/
-struct reiserfs_journal_cnode {
-	struct buffer_head *bh;	/* real buffer head */
-	struct super_block *sb;	/* dev of real buffer head */
-	__u32 blocknr;		/* block number of real buffer head, == 0 when buffer on disk */
-	unsigned long state;
-	struct reiserfs_journal_list *jlist;	/* journal list this cnode lives in */
-	struct reiserfs_journal_cnode *next;	/* next in transaction list */
-	struct reiserfs_journal_cnode *prev;	/* prev in transaction list */
-	struct reiserfs_journal_cnode *hprev;	/* prev in hash list */
-	struct reiserfs_journal_cnode *hnext;	/* next in hash list */
-};
-
-struct reiserfs_bitmap_node {
-	int id;
-	char *data;
-	struct list_head list;
-};
-
-struct reiserfs_list_bitmap {
-	struct reiserfs_journal_list *journal_list;
-	struct reiserfs_bitmap_node **bitmaps;
-};
-
-/*
-** one of these for each transaction.  The most important part here is the j_realblock.
-** this list of cnodes is used to hash all the blocks in all the commits, to mark all the
-** real buffer heads dirty once all the commits hit the disk,
-** and to make sure every real block in a transaction is on disk before allowing the log area
-** to be overwritten */
-struct reiserfs_journal_list {
-	unsigned long j_start;
-	unsigned long j_state;
-	unsigned long j_len;
-	atomic_t j_nonzerolen;
-	atomic_t j_commit_left;
-	atomic_t j_older_commits_done;	/* all commits older than this on disk */
-	struct mutex j_commit_mutex;
-	unsigned int j_trans_id;
-	time_t j_timestamp;
-	struct reiserfs_list_bitmap *j_list_bitmap;
-	struct buffer_head *j_commit_bh;	/* commit buffer head */
-	struct reiserfs_journal_cnode *j_realblock;
-	struct reiserfs_journal_cnode *j_freedlist;	/* list of buffers that were freed during this trans.  free each of these on flush */
-	/* time ordered list of all active transactions */
-	struct list_head j_list;
-
-	/* time ordered list of all transactions we haven't tried to flush yet */
-	struct list_head j_working_list;
-
-	/* list of tail conversion targets in need of flush before commit */
-	struct list_head j_tail_bh_list;
-	/* list of data=ordered buffers in need of flush before commit */
-	struct list_head j_bh_list;
-	int j_refcount;
-};
-
-struct reiserfs_journal {
-	struct buffer_head **j_ap_blocks;	/* journal blocks on disk */
-	struct reiserfs_journal_cnode *j_last;	/* newest journal block */
-	struct reiserfs_journal_cnode *j_first;	/*  oldest journal block.  start here for traverse */
-
-	struct block_device *j_dev_bd;
-	fmode_t j_dev_mode;
-	int j_1st_reserved_block;	/* first block on s_dev of reserved area journal */
-
-	unsigned long j_state;
-	unsigned int j_trans_id;
-	unsigned long j_mount_id;
-	unsigned long j_start;	/* start of current waiting commit (index into j_ap_blocks) */
-	unsigned long j_len;	/* length of current waiting commit */
-	unsigned long j_len_alloc;	/* number of buffers requested by journal_begin() */
-	atomic_t j_wcount;	/* count of writers for current commit */
-	unsigned long j_bcount;	/* batch count. allows turning X transactions into 1 */
-	unsigned long j_first_unflushed_offset;	/* first unflushed transactions offset */
-	unsigned j_last_flush_trans_id;	/* last fully flushed journal timestamp */
-	struct buffer_head *j_header_bh;
-
-	time_t j_trans_start_time;	/* time this transaction started */
-	struct mutex j_mutex;
-	struct mutex j_flush_mutex;
-	wait_queue_head_t j_join_wait;	/* wait for current transaction to finish before starting new one */
-	atomic_t j_jlock;	/* lock for j_join_wait */
-	int j_list_bitmap_index;	/* number of next list bitmap to use */
-	int j_must_wait;	/* no more journal begins allowed. MUST sleep on j_join_wait */
-	int j_next_full_flush;	/* next journal_end will flush all journal list */
-	int j_next_async_flush;	/* next journal_end will flush all async commits */
-
-	int j_cnode_used;	/* number of cnodes on the used list */
-	int j_cnode_free;	/* number of cnodes on the free list */
-
-	unsigned int j_trans_max;	/* max number of blocks in a transaction.  */
-	unsigned int j_max_batch;	/* max number of blocks to batch into a trans */
-	unsigned int j_max_commit_age;	/* in seconds, how old can an async commit be */
-	unsigned int j_max_trans_age;	/* in seconds, how old can a transaction be */
-	unsigned int j_default_max_commit_age;	/* the default for the max commit age */
-
-	struct reiserfs_journal_cnode *j_cnode_free_list;
-	struct reiserfs_journal_cnode *j_cnode_free_orig;	/* orig pointer returned from vmalloc */
-
-	struct reiserfs_journal_list *j_current_jl;
-	int j_free_bitmap_nodes;
-	int j_used_bitmap_nodes;
-
-	int j_num_lists;	/* total number of active transactions */
-	int j_num_work_lists;	/* number that need attention from kreiserfsd */
-
-	/* debugging to make sure things are flushed in order */
-	unsigned int j_last_flush_id;
-
-	/* debugging to make sure things are committed in order */
-	unsigned int j_last_commit_id;
-
-	struct list_head j_bitmap_nodes;
-	struct list_head j_dirty_buffers;
-	spinlock_t j_dirty_buffers_lock;	/* protects j_dirty_buffers */
-
-	/* list of all active transactions */
-	struct list_head j_journal_list;
-	/* lists that haven't been touched by writeback attempts */
-	struct list_head j_working_list;
-
-	struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS];	/* array of bitmaps to record the deleted blocks */
-	struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE];	/* hash table for real buffer heads in current trans */
-	struct reiserfs_journal_cnode *j_list_hash_table[JOURNAL_HASH_SIZE];	/* hash table for all the real buffer heads in all
-										   the transactions */
-	struct list_head j_prealloc_list;	/* list of inodes which have preallocated blocks */
-	int j_persistent_trans;
-	unsigned long j_max_trans_size;
-	unsigned long j_max_batch_size;
-
-	int j_errno;
-
-	/* when flushing ordered buffers, throttle new ordered writers */
-	struct delayed_work j_work;
-	struct super_block *j_work_sb;
-	atomic_t j_async_throttle;
-};
-
-enum journal_state_bits {
-	J_WRITERS_BLOCKED = 1,	/* set when new writers not allowed */
-	J_WRITERS_QUEUED,	/* set when log is full due to too many writers */
-	J_ABORTED,		/* set when log is aborted */
-};
-
-#define JOURNAL_DESC_MAGIC "ReIsErLB"	/* ick.  magic string to find desc blocks in the journal */
-
-typedef __u32(*hashf_t) (const signed char *, int);
-
-struct reiserfs_bitmap_info {
-	__u32 free_count;
-};
-
-struct proc_dir_entry;
-
-#if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO )
-typedef unsigned long int stat_cnt_t;
-typedef struct reiserfs_proc_info_data {
-	spinlock_t lock;
-	int exiting;
-	int max_hash_collisions;
-
-	stat_cnt_t breads;
-	stat_cnt_t bread_miss;
-	stat_cnt_t search_by_key;
-	stat_cnt_t search_by_key_fs_changed;
-	stat_cnt_t search_by_key_restarted;
-
-	stat_cnt_t insert_item_restarted;
-	stat_cnt_t paste_into_item_restarted;
-	stat_cnt_t cut_from_item_restarted;
-	stat_cnt_t delete_solid_item_restarted;
-	stat_cnt_t delete_item_restarted;
-
-	stat_cnt_t leaked_oid;
-	stat_cnt_t leaves_removable;
-
-	/* balances per level. Use explicit 5 as MAX_HEIGHT is not visible yet. */
-	stat_cnt_t balance_at[5];	/* XXX */
-	/* sbk == search_by_key */
-	stat_cnt_t sbk_read_at[5];	/* XXX */
-	stat_cnt_t sbk_fs_changed[5];
-	stat_cnt_t sbk_restarted[5];
-	stat_cnt_t items_at[5];	/* XXX */
-	stat_cnt_t free_at[5];	/* XXX */
-	stat_cnt_t can_node_be_removed[5];	/* XXX */
-	long int lnum[5];	/* XXX */
-	long int rnum[5];	/* XXX */
-	long int lbytes[5];	/* XXX */
-	long int rbytes[5];	/* XXX */
-	stat_cnt_t get_neighbors[5];
-	stat_cnt_t get_neighbors_restart[5];
-	stat_cnt_t need_l_neighbor[5];
-	stat_cnt_t need_r_neighbor[5];
-
-	stat_cnt_t free_block;
-	struct __scan_bitmap_stats {
-		stat_cnt_t call;
-		stat_cnt_t wait;
-		stat_cnt_t bmap;
-		stat_cnt_t retry;
-		stat_cnt_t in_journal_hint;
-		stat_cnt_t in_journal_nohint;
-		stat_cnt_t stolen;
-	} scan_bitmap;
-	struct __journal_stats {
-		stat_cnt_t in_journal;
-		stat_cnt_t in_journal_bitmap;
-		stat_cnt_t in_journal_reusable;
-		stat_cnt_t lock_journal;
-		stat_cnt_t lock_journal_wait;
-		stat_cnt_t journal_being;
-		stat_cnt_t journal_relock_writers;
-		stat_cnt_t journal_relock_wcount;
-		stat_cnt_t mark_dirty;
-		stat_cnt_t mark_dirty_already;
-		stat_cnt_t mark_dirty_notjournal;
-		stat_cnt_t restore_prepared;
-		stat_cnt_t prepare;
-		stat_cnt_t prepare_retry;
-	} journal;
-} reiserfs_proc_info_data_t;
-#else
-typedef struct reiserfs_proc_info_data {
-} reiserfs_proc_info_data_t;
-#endif
-
-/* reiserfs union of in-core super block data */
-struct reiserfs_sb_info {
-	struct buffer_head *s_sbh;	/* Buffer containing the super block */
-	/* both the comment and the choice of
-	   name are unclear for s_rs -Hans */
-	struct reiserfs_super_block *s_rs;	/* Pointer to the super block in the buffer */
-	struct reiserfs_bitmap_info *s_ap_bitmap;
-	struct reiserfs_journal *s_journal;	/* pointer to journal information */
-	unsigned short s_mount_state;	/* reiserfs state (valid, invalid) */
-
-	/* Serialize writers access, replace the old bkl */
-	struct mutex lock;
-	/* Owner of the lock (can be recursive) */
-	struct task_struct *lock_owner;
-	/* Depth of the lock, start from -1 like the bkl */
-	int lock_depth;
-
-	/* Comment? -Hans */
-	void (*end_io_handler) (struct buffer_head *, int);
-	hashf_t s_hash_function;	/* pointer to function which is used
-					   to sort names in directory. Set on
-					   mount */
-	unsigned long s_mount_opt;	/* reiserfs's mount options are set
-					   here (currently - NOTAIL, NOLOG,
-					   REPLAYONLY) */
-
-	struct {		/* This is a structure that describes block allocator options */
-		unsigned long bits;	/* Bitfield for enable/disable kind of options */
-		unsigned long large_file_size;	/* size started from which we consider file to be a large one(in blocks) */
-		int border;	/* percentage of disk, border takes */
-		int preallocmin;	/* Minimal file size (in blocks) starting from which we do preallocations */
-		int preallocsize;	/* Number of blocks we try to prealloc when file
-					   reaches preallocmin size (in blocks) or
-					   prealloc_list is empty. */
-	} s_alloc_options;
-
-	/* Comment? -Hans */
-	wait_queue_head_t s_wait;
-	/* To be obsoleted soon by per buffer seals.. -Hans */
-	atomic_t s_generation_counter;	// increased by one every time the
-	// tree gets re-balanced
-	unsigned long s_properties;	/* File system properties. Currently holds
-					   on-disk FS format */
-
-	/* session statistics */
-	int s_disk_reads;
-	int s_disk_writes;
-	int s_fix_nodes;
-	int s_do_balance;
-	int s_unneeded_left_neighbor;
-	int s_good_search_by_key_reada;
-	int s_bmaps;
-	int s_bmaps_without_search;
-	int s_direct2indirect;
-	int s_indirect2direct;
-	/* set up when it's ok for reiserfs_read_inode2() to read from
-	   disk inode with nlink==0. Currently this is only used during
-	   finish_unfinished() processing at mount time */
-	int s_is_unlinked_ok;
-	reiserfs_proc_info_data_t s_proc_info_data;
-	struct proc_dir_entry *procdir;
-	int reserved_blocks;	/* amount of blocks reserved for further allocations */
-	spinlock_t bitmap_lock;	/* this lock on now only used to protect reserved_blocks variable */
-	struct dentry *priv_root;	/* root of /.reiserfs_priv */
-	struct dentry *xattr_root;	/* root of /.reiserfs_priv/xattrs */
-	int j_errno;
-#ifdef CONFIG_QUOTA
-	char *s_qf_names[MAXQUOTAS];
-	int s_jquota_fmt;
-#endif
-	char *s_jdev;		/* Stored jdev for mount option showing */
-#ifdef CONFIG_REISERFS_CHECK
-
-	struct tree_balance *cur_tb;	/*
-					 * Detects whether more than one
-					 * copy of tb exists per superblock
-					 * as a means of checking whether
-					 * do_balance is executing concurrently
-					 * against another tree reader/writer
-					 * on a same mount point.
-					 */
-#endif
-};
-
-/* Definitions of reiserfs on-disk properties: */
-#define REISERFS_3_5 0
-#define REISERFS_3_6 1
-#define REISERFS_OLD_FORMAT 2
-
-enum reiserfs_mount_options {
-/* Mount options */
-	REISERFS_LARGETAIL,	/* large tails will be created in a session */
-	REISERFS_SMALLTAIL,	/* small (for files less than block size) tails will be created in a session */
-	REPLAYONLY,		/* replay journal and return 0. Use by fsck */
-	REISERFS_CONVERT,	/* -o conv: causes conversion of old
-				   format super block to the new
-				   format. If not specified - old
-				   partition will be dealt with in a
-				   manner of 3.5.x */
-
-/* -o hash={tea, rupasov, r5, detect} is meant for properly mounting
-** reiserfs disks from 3.5.19 or earlier.  99% of the time, this option
-** is not required.  If the normal autodection code can't determine which
-** hash to use (because both hashes had the same value for a file)
-** use this option to force a specific hash.  It won't allow you to override
-** the existing hash on the FS, so if you have a tea hash disk, and mount
-** with -o hash=rupasov, the mount will fail.
-*/
-	FORCE_TEA_HASH,		/* try to force tea hash on mount */
-	FORCE_RUPASOV_HASH,	/* try to force rupasov hash on mount */
-	FORCE_R5_HASH,		/* try to force rupasov hash on mount */
-	FORCE_HASH_DETECT,	/* try to detect hash function on mount */
-
-	REISERFS_DATA_LOG,
-	REISERFS_DATA_ORDERED,
-	REISERFS_DATA_WRITEBACK,
-
-/* used for testing experimental features, makes benchmarking new
-   features with and without more convenient, should never be used by
-   users in any code shipped to users (ideally) */
-
-	REISERFS_NO_BORDER,
-	REISERFS_NO_UNHASHED_RELOCATION,
-	REISERFS_HASHED_RELOCATION,
-	REISERFS_ATTRS,
-	REISERFS_XATTRS_USER,
-	REISERFS_POSIXACL,
-	REISERFS_EXPOSE_PRIVROOT,
-	REISERFS_BARRIER_NONE,
-	REISERFS_BARRIER_FLUSH,
-
-	/* Actions on error */
-	REISERFS_ERROR_PANIC,
-	REISERFS_ERROR_RO,
-	REISERFS_ERROR_CONTINUE,
-
-	REISERFS_USRQUOTA,	/* User quota option specified */
-	REISERFS_GRPQUOTA,	/* Group quota option specified */
-
-	REISERFS_TEST1,
-	REISERFS_TEST2,
-	REISERFS_TEST3,
-	REISERFS_TEST4,
-	REISERFS_UNSUPPORTED_OPT,
-};
-
-#define reiserfs_r5_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_R5_HASH))
-#define reiserfs_rupasov_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_RUPASOV_HASH))
-#define reiserfs_tea_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_TEA_HASH))
-#define reiserfs_hash_detect(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_HASH_DETECT))
-#define reiserfs_no_border(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_NO_BORDER))
-#define reiserfs_no_unhashed_relocation(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_NO_UNHASHED_RELOCATION))
-#define reiserfs_hashed_relocation(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_HASHED_RELOCATION))
-#define reiserfs_test4(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_TEST4))
-
-#define have_large_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_LARGETAIL))
-#define have_small_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_SMALLTAIL))
-#define replay_only(s) (REISERFS_SB(s)->s_mount_opt & (1 << REPLAYONLY))
-#define reiserfs_attrs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ATTRS))
-#define old_format_only(s) (REISERFS_SB(s)->s_properties & (1 << REISERFS_3_5))
-#define convert_reiserfs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_CONVERT))
-#define reiserfs_data_log(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_LOG))
-#define reiserfs_data_ordered(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_ORDERED))
-#define reiserfs_data_writeback(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_WRITEBACK))
-#define reiserfs_xattrs_user(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS_USER))
-#define reiserfs_posixacl(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_POSIXACL))
-#define reiserfs_expose_privroot(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_EXPOSE_PRIVROOT))
-#define reiserfs_xattrs_optional(s) (reiserfs_xattrs_user(s) || reiserfs_posixacl(s))
-#define reiserfs_barrier_none(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_NONE))
-#define reiserfs_barrier_flush(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_FLUSH))
-
-#define reiserfs_error_panic(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_PANIC))
-#define reiserfs_error_ro(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_RO))
-
-void reiserfs_file_buffer(struct buffer_head *bh, int list);
-extern struct file_system_type reiserfs_fs_type;
-int reiserfs_resize(struct super_block *, unsigned long);
-
-#define CARRY_ON                0
-#define SCHEDULE_OCCURRED       1
-
-#define SB_BUFFER_WITH_SB(s) (REISERFS_SB(s)->s_sbh)
-#define SB_JOURNAL(s) (REISERFS_SB(s)->s_journal)
-#define SB_JOURNAL_1st_RESERVED_BLOCK(s) (SB_JOURNAL(s)->j_1st_reserved_block)
-#define SB_JOURNAL_LEN_FREE(s) (SB_JOURNAL(s)->j_journal_len_free)
-#define SB_AP_BITMAP(s) (REISERFS_SB(s)->s_ap_bitmap)
-
-#define SB_DISK_JOURNAL_HEAD(s) (SB_JOURNAL(s)->j_header_bh->)
-
-/* A safe version of the "bdevname", which returns the "s_id" field of
- * a superblock or else "Null superblock" if the super block is NULL.
- */
-static inline char *reiserfs_bdevname(struct super_block *s)
-{
-	return (s == NULL) ? "Null superblock" : s->s_id;
-}
-
-#define reiserfs_is_journal_aborted(journal) (unlikely (__reiserfs_is_journal_aborted (journal)))
-static inline int __reiserfs_is_journal_aborted(struct reiserfs_journal
-						*journal)
-{
-	return test_bit(J_ABORTED, &journal->j_state);
-}
-
-#endif				/* _LINUX_REISER_FS_SB */
diff --git a/include/linux/reiserfs_xattr.h b/include/linux/reiserfs_xattr.h
index c2b7147..d8ce17c 100644
--- a/include/linux/reiserfs_xattr.h
+++ b/include/linux/reiserfs_xattr.h
@@ -21,132 +21,4 @@
 	size_t length;
 };
 
-#ifdef __KERNEL__
-
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/rwsem.h>
-#include <linux/reiserfs_fs_i.h>
-#include <linux/reiserfs_fs.h>
-
-struct inode;
-struct dentry;
-struct iattr;
-struct super_block;
-struct nameidata;
-
-int reiserfs_xattr_register_handlers(void) __init;
-void reiserfs_xattr_unregister_handlers(void);
-int reiserfs_xattr_init(struct super_block *sb, int mount_flags);
-int reiserfs_lookup_privroot(struct super_block *sb);
-int reiserfs_delete_xattrs(struct inode *inode);
-int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs);
-int reiserfs_permission(struct inode *inode, int mask);
-
-#ifdef CONFIG_REISERFS_FS_XATTR
-#define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
-ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name,
-			  void *buffer, size_t size);
-int reiserfs_setxattr(struct dentry *dentry, const char *name,
-		      const void *value, size_t size, int flags);
-ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
-int reiserfs_removexattr(struct dentry *dentry, const char *name);
-
-int reiserfs_xattr_get(struct inode *, const char *, void *, size_t);
-int reiserfs_xattr_set(struct inode *, const char *, const void *, size_t, int);
-int reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *,
-			      struct inode *, const char *, const void *,
-			      size_t, int);
-
-extern const struct xattr_handler reiserfs_xattr_user_handler;
-extern const struct xattr_handler reiserfs_xattr_trusted_handler;
-extern const struct xattr_handler reiserfs_xattr_security_handler;
-#ifdef CONFIG_REISERFS_FS_SECURITY
-int reiserfs_security_init(struct inode *dir, struct inode *inode,
-			   const struct qstr *qstr,
-			   struct reiserfs_security_handle *sec);
-int reiserfs_security_write(struct reiserfs_transaction_handle *th,
-			    struct inode *inode,
-			    struct reiserfs_security_handle *sec);
-void reiserfs_security_free(struct reiserfs_security_handle *sec);
-#endif
-
-static inline int reiserfs_xattrs_initialized(struct super_block *sb)
-{
-	return REISERFS_SB(sb)->priv_root != NULL;
-}
-
-#define xattr_size(size) ((size) + sizeof(struct reiserfs_xattr_header))
-static inline loff_t reiserfs_xattr_nblocks(struct inode *inode, loff_t size)
-{
-	loff_t ret = 0;
-	if (reiserfs_file_data_log(inode)) {
-		ret = _ROUND_UP(xattr_size(size), inode->i_sb->s_blocksize);
-		ret >>= inode->i_sb->s_blocksize_bits;
-	}
-	return ret;
-}
-
-/* We may have to create up to 3 objects: xattr root, xattr dir, xattr file.
- * Let's try to be smart about it.
- * xattr root: We cache it. If it's not cached, we may need to create it.
- * xattr dir: If anything has been loaded for this inode, we can set a flag
- *            saying so.
- * xattr file: Since we don't cache xattrs, we can't tell. We always include
- *             blocks for it.
- *
- * However, since root and dir can be created between calls - YOU MUST SAVE
- * THIS VALUE.
- */
-static inline size_t reiserfs_xattr_jcreate_nblocks(struct inode *inode)
-{
-	size_t nblocks = JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
-
-	if ((REISERFS_I(inode)->i_flags & i_has_xattr_dir) == 0) {
-		nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
-		if (!REISERFS_SB(inode->i_sb)->xattr_root->d_inode)
-			nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
-	}
-
-	return nblocks;
-}
-
-static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
-{
-	init_rwsem(&REISERFS_I(inode)->i_xattr_sem);
-}
-
-#else
-
-#define reiserfs_getxattr NULL
-#define reiserfs_setxattr NULL
-#define reiserfs_listxattr NULL
-#define reiserfs_removexattr NULL
-
-static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
-{
-}
-#endif  /*  CONFIG_REISERFS_FS_XATTR  */
-
-#ifndef CONFIG_REISERFS_FS_SECURITY
-static inline int reiserfs_security_init(struct inode *dir,
-					 struct inode *inode,
-					 const struct qstr *qstr,
-					 struct reiserfs_security_handle *sec)
-{
-	return 0;
-}
-static inline int
-reiserfs_security_write(struct reiserfs_transaction_handle *th,
-			struct inode *inode,
-			struct reiserfs_security_handle *sec)
-{
-	return 0;
-}
-static inline void reiserfs_security_free(struct reiserfs_security_handle *sec)
-{}
-#endif
-
-#endif  /*  __KERNEL__  */
-
 #endif  /*  _LINUX_REISERFS_XATTR_H  */
diff --git a/include/linux/relay.h b/include/linux/relay.h
index a822fd7..91cacc3 100644
--- a/include/linux/relay.h
+++ b/include/linux/relay.h
@@ -15,6 +15,7 @@
 #include <linux/timer.h>
 #include <linux/wait.h>
 #include <linux/list.h>
+#include <linux/bug.h>
 #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/kref.h>
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
new file mode 100644
index 0000000..f1ffabb
--- /dev/null
+++ b/include/linux/remoteproc.h
@@ -0,0 +1,478 @@
+/*
+ * Remote Processor Framework
+ *
+ * Copyright(c) 2011 Texas Instruments, Inc.
+ * Copyright(c) 2011 Google, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name Texas Instruments nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef REMOTEPROC_H
+#define REMOTEPROC_H
+
+#include <linux/types.h>
+#include <linux/kref.h>
+#include <linux/klist.h>
+#include <linux/mutex.h>
+#include <linux/virtio.h>
+#include <linux/completion.h>
+#include <linux/idr.h>
+
+/**
+ * struct resource_table - firmware resource table header
+ * @ver: version number
+ * @num: number of resource entries
+ * @reserved: reserved (must be zero)
+ * @offset: array of offsets pointing at the various resource entries
+ *
+ * A resource table is essentially a list of system resources required
+ * by the remote processor. It may also include configuration entries.
+ * If needed, the remote processor firmware should contain this table
+ * as a dedicated ".resource_table" ELF section.
+ *
+ * Some resources entries are mere announcements, where the host is informed
+ * of specific remoteproc configuration. Other entries require the host to
+ * do something (e.g. allocate a system resource). Sometimes a negotiation
+ * is expected, where the firmware requests a resource, and once allocated,
+ * the host should provide back its details (e.g. address of an allocated
+ * memory region).
+ *
+ * The header of the resource table, as expressed by this structure,
+ * contains a version number (should we need to change this format in the
+ * future), the number of available resource entries, and their offsets
+ * in the table.
+ *
+ * Immediately following this header are the resource entries themselves,
+ * each of which begins with a resource entry header (as described below).
+ */
+struct resource_table {
+	u32 ver;
+	u32 num;
+	u32 reserved[2];
+	u32 offset[0];
+} __packed;
+
+/**
+ * struct fw_rsc_hdr - firmware resource entry header
+ * @type: resource type
+ * @data: resource data
+ *
+ * Every resource entry begins with a 'struct fw_rsc_hdr' header providing
+ * its @type. The content of the entry itself will immediately follow
+ * this header, and it should be parsed according to the resource type.
+ */
+struct fw_rsc_hdr {
+	u32 type;
+	u8 data[0];
+} __packed;
+
+/**
+ * enum fw_resource_type - types of resource entries
+ *
+ * @RSC_CARVEOUT:   request for allocation of a physically contiguous
+ *		    memory region.
+ * @RSC_DEVMEM:     request to iommu_map a memory-based peripheral.
+ * @RSC_TRACE:	    announces the availability of a trace buffer into which
+ *		    the remote processor will be writing logs.
+ * @RSC_VDEV:       declare support for a virtio device, and serve as its
+ *		    virtio header.
+ * @RSC_LAST:       just keep this one at the end
+ *
+ * For more details regarding a specific resource type, please see its
+ * dedicated structure below.
+ *
+ * Please note that these values are used as indices to the rproc_handle_rsc
+ * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to
+ * check the validity of an index before the lookup table is accessed, so
+ * please update it as needed.
+ */
+enum fw_resource_type {
+	RSC_CARVEOUT	= 0,
+	RSC_DEVMEM	= 1,
+	RSC_TRACE	= 2,
+	RSC_VDEV	= 3,
+	RSC_LAST	= 4,
+};
+
+#define FW_RSC_ADDR_ANY (0xFFFFFFFFFFFFFFFF)
+
+/**
+ * struct fw_rsc_carveout - physically contiguous memory request
+ * @da: device address
+ * @pa: physical address
+ * @len: length (in bytes)
+ * @flags: iommu protection flags
+ * @reserved: reserved (must be zero)
+ * @name: human-readable name of the requested memory region
+ *
+ * This resource entry requests the host to allocate a physically contiguous
+ * memory region.
+ *
+ * These request entries should precede other firmware resource entries,
+ * as other entries might request placing other data objects inside
+ * these memory regions (e.g. data/code segments, trace resource entries, ...).
+ *
+ * Allocating memory this way helps utilizing the reserved physical memory
+ * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries
+ * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB
+ * pressure is important; it may have a substantial impact on performance.
+ *
+ * If the firmware is compiled with static addresses, then @da should specify
+ * the expected device address of this memory region. If @da is set to
+ * FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then
+ * overwrite @da with the dynamically allocated address.
+ *
+ * We will always use @da to negotiate the device addresses, even if it
+ * isn't using an iommu. In that case, though, it will obviously contain
+ * physical addresses.
+ *
+ * Some remote processors needs to know the allocated physical address
+ * even if they do use an iommu. This is needed, e.g., if they control
+ * hardware accelerators which access the physical memory directly (this
+ * is the case with OMAP4 for instance). In that case, the host will
+ * overwrite @pa with the dynamically allocated physical address.
+ * Generally we don't want to expose physical addresses if we don't have to
+ * (remote processors are generally _not_ trusted), so we might want to
+ * change this to happen _only_ when explicitly required by the hardware.
+ *
+ * @flags is used to provide IOMMU protection flags, and @name should
+ * (optionally) contain a human readable name of this carveout region
+ * (mainly for debugging purposes).
+ */
+struct fw_rsc_carveout {
+	u32 da;
+	u32 pa;
+	u32 len;
+	u32 flags;
+	u32 reserved;
+	u8 name[32];
+} __packed;
+
+/**
+ * struct fw_rsc_devmem - iommu mapping request
+ * @da: device address
+ * @pa: physical address
+ * @len: length (in bytes)
+ * @flags: iommu protection flags
+ * @reserved: reserved (must be zero)
+ * @name: human-readable name of the requested region to be mapped
+ *
+ * This resource entry requests the host to iommu map a physically contiguous
+ * memory region. This is needed in case the remote processor requires
+ * access to certain memory-based peripherals; _never_ use it to access
+ * regular memory.
+ *
+ * This is obviously only needed if the remote processor is accessing memory
+ * via an iommu.
+ *
+ * @da should specify the required device address, @pa should specify
+ * the physical address we want to map, @len should specify the size of
+ * the mapping and @flags is the IOMMU protection flags. As always, @name may
+ * (optionally) contain a human readable name of this mapping (mainly for
+ * debugging purposes).
+ *
+ * Note: at this point we just "trust" those devmem entries to contain valid
+ * physical addresses, but this isn't safe and will be changed: eventually we
+ * want remoteproc implementations to provide us ranges of physical addresses
+ * the firmware is allowed to request, and not allow firmwares to request
+ * access to physical addresses that are outside those ranges.
+ */
+struct fw_rsc_devmem {
+	u32 da;
+	u32 pa;
+	u32 len;
+	u32 flags;
+	u32 reserved;
+	u8 name[32];
+} __packed;
+
+/**
+ * struct fw_rsc_trace - trace buffer declaration
+ * @da: device address
+ * @len: length (in bytes)
+ * @reserved: reserved (must be zero)
+ * @name: human-readable name of the trace buffer
+ *
+ * This resource entry provides the host information about a trace buffer
+ * into which the remote processor will write log messages.
+ *
+ * @da specifies the device address of the buffer, @len specifies
+ * its size, and @name may contain a human readable name of the trace buffer.
+ *
+ * After booting the remote processor, the trace buffers are exposed to the
+ * user via debugfs entries (called trace0, trace1, etc..).
+ */
+struct fw_rsc_trace {
+	u32 da;
+	u32 len;
+	u32 reserved;
+	u8 name[32];
+} __packed;
+
+/**
+ * struct fw_rsc_vdev_vring - vring descriptor entry
+ * @da: device address
+ * @align: the alignment between the consumer and producer parts of the vring
+ * @num: num of buffers supported by this vring (must be power of two)
+ * @notifyid is a unique rproc-wide notify index for this vring. This notify
+ * index is used when kicking a remote processor, to let it know that this
+ * vring is triggered.
+ * @reserved: reserved (must be zero)
+ *
+ * This descriptor is not a resource entry by itself; it is part of the
+ * vdev resource type (see below).
+ *
+ * Note that @da should either contain the device address where
+ * the remote processor is expecting the vring, or indicate that
+ * dynamically allocation of the vring's device address is supported.
+ */
+struct fw_rsc_vdev_vring {
+	u32 da;
+	u32 align;
+	u32 num;
+	u32 notifyid;
+	u32 reserved;
+} __packed;
+
+/**
+ * struct fw_rsc_vdev - virtio device header
+ * @id: virtio device id (as in virtio_ids.h)
+ * @notifyid is a unique rproc-wide notify index for this vdev. This notify
+ * index is used when kicking a remote processor, to let it know that the
+ * status/features of this vdev have changes.
+ * @dfeatures specifies the virtio device features supported by the firmware
+ * @gfeatures is a place holder used by the host to write back the
+ * negotiated features that are supported by both sides.
+ * @config_len is the size of the virtio config space of this vdev. The config
+ * space lies in the resource table immediate after this vdev header.
+ * @status is a place holder where the host will indicate its virtio progress.
+ * @num_of_vrings indicates how many vrings are described in this vdev header
+ * @reserved: reserved (must be zero)
+ * @vring is an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'.
+ *
+ * This resource is a virtio device header: it provides information about
+ * the vdev, and is then used by the host and its peer remote processors
+ * to negotiate and share certain virtio properties.
+ *
+ * By providing this resource entry, the firmware essentially asks remoteproc
+ * to statically allocate a vdev upon registration of the rproc (dynamic vdev
+ * allocation is not yet supported).
+ *
+ * Note: unlike virtualization systems, the term 'host' here means
+ * the Linux side which is running remoteproc to control the remote
+ * processors. We use the name 'gfeatures' to comply with virtio's terms,
+ * though there isn't really any virtualized guest OS here: it's the host
+ * which is responsible for negotiating the final features.
+ * Yeah, it's a bit confusing.
+ *
+ * Note: immediately following this structure is the virtio config space for
+ * this vdev (which is specific to the vdev; for more info, read the virtio
+ * spec). the size of the config space is specified by @config_len.
+ */
+struct fw_rsc_vdev {
+	u32 id;
+	u32 notifyid;
+	u32 dfeatures;
+	u32 gfeatures;
+	u32 config_len;
+	u8 status;
+	u8 num_of_vrings;
+	u8 reserved[2];
+	struct fw_rsc_vdev_vring vring[0];
+} __packed;
+
+/**
+ * struct rproc_mem_entry - memory entry descriptor
+ * @va:	virtual address
+ * @dma: dma address
+ * @len: length, in bytes
+ * @da: device address
+ * @priv: associated data
+ * @node: list node
+ */
+struct rproc_mem_entry {
+	void *va;
+	dma_addr_t dma;
+	int len;
+	u32 da;
+	void *priv;
+	struct list_head node;
+};
+
+struct rproc;
+
+/**
+ * struct rproc_ops - platform-specific device handlers
+ * @start:	power on the device and boot it
+ * @stop:	power off the device
+ * @kick:	kick a virtqueue (virtqueue id given as a parameter)
+ */
+struct rproc_ops {
+	int (*start)(struct rproc *rproc);
+	int (*stop)(struct rproc *rproc);
+	void (*kick)(struct rproc *rproc, int vqid);
+};
+
+/**
+ * enum rproc_state - remote processor states
+ * @RPROC_OFFLINE:	device is powered off
+ * @RPROC_SUSPENDED:	device is suspended; needs to be woken up to receive
+ *			a message.
+ * @RPROC_RUNNING:	device is up and running
+ * @RPROC_CRASHED:	device has crashed; need to start recovery
+ * @RPROC_LAST:		just keep this one at the end
+ *
+ * Please note that the values of these states are used as indices
+ * to rproc_state_string, a state-to-name lookup table,
+ * so please keep the two synchronized. @RPROC_LAST is used to check
+ * the validity of an index before the lookup table is accessed, so
+ * please update it as needed too.
+ */
+enum rproc_state {
+	RPROC_OFFLINE	= 0,
+	RPROC_SUSPENDED	= 1,
+	RPROC_RUNNING	= 2,
+	RPROC_CRASHED	= 3,
+	RPROC_LAST	= 4,
+};
+
+/**
+ * struct rproc - represents a physical remote processor device
+ * @node: klist node of this rproc object
+ * @domain: iommu domain
+ * @name: human readable name of the rproc
+ * @firmware: name of firmware file to be loaded
+ * @priv: private data which belongs to the platform-specific rproc module
+ * @ops: platform-specific start/stop rproc handlers
+ * @dev: underlying device
+ * @refcount: refcount of users that have a valid pointer to this rproc
+ * @power: refcount of users who need this rproc powered up
+ * @state: state of the device
+ * @lock: lock which protects concurrent manipulations of the rproc
+ * @dbg_dir: debugfs directory of this rproc device
+ * @traces: list of trace buffers
+ * @num_traces: number of trace buffers
+ * @carveouts: list of physically contiguous memory allocations
+ * @mappings: list of iommu mappings we initiated, needed on shutdown
+ * @firmware_loading_complete: marks e/o asynchronous firmware loading
+ * @bootaddr: address of first instruction to boot rproc with (optional)
+ * @rvdevs: list of remote virtio devices
+ * @notifyids: idr for dynamically assigning rproc-wide unique notify ids
+ */
+struct rproc {
+	struct klist_node node;
+	struct iommu_domain *domain;
+	const char *name;
+	const char *firmware;
+	void *priv;
+	const struct rproc_ops *ops;
+	struct device *dev;
+	struct kref refcount;
+	atomic_t power;
+	unsigned int state;
+	struct mutex lock;
+	struct dentry *dbg_dir;
+	struct list_head traces;
+	int num_traces;
+	struct list_head carveouts;
+	struct list_head mappings;
+	struct completion firmware_loading_complete;
+	u32 bootaddr;
+	struct list_head rvdevs;
+	struct idr notifyids;
+};
+
+/* we currently support only two vrings per rvdev */
+#define RVDEV_NUM_VRINGS 2
+
+/**
+ * struct rproc_vring - remoteproc vring state
+ * @va:	virtual address
+ * @dma: dma address
+ * @len: length, in bytes
+ * @da: device address
+ * @align: vring alignment
+ * @notifyid: rproc-specific unique vring index
+ * @rvdev: remote vdev
+ * @vq: the virtqueue of this vring
+ */
+struct rproc_vring {
+	void *va;
+	dma_addr_t dma;
+	int len;
+	u32 da;
+	u32 align;
+	int notifyid;
+	struct rproc_vdev *rvdev;
+	struct virtqueue *vq;
+};
+
+/**
+ * struct rproc_vdev - remoteproc state for a supported virtio device
+ * @node: list node
+ * @rproc: the rproc handle
+ * @vdev: the virio device
+ * @vring: the vrings for this vdev
+ * @dfeatures: virtio device features
+ * @gfeatures: virtio guest features
+ */
+struct rproc_vdev {
+	struct list_head node;
+	struct rproc *rproc;
+	struct virtio_device vdev;
+	struct rproc_vring vring[RVDEV_NUM_VRINGS];
+	unsigned long dfeatures;
+	unsigned long gfeatures;
+};
+
+struct rproc *rproc_get_by_name(const char *name);
+void rproc_put(struct rproc *rproc);
+
+struct rproc *rproc_alloc(struct device *dev, const char *name,
+				const struct rproc_ops *ops,
+				const char *firmware, int len);
+void rproc_free(struct rproc *rproc);
+int rproc_register(struct rproc *rproc);
+int rproc_unregister(struct rproc *rproc);
+
+int rproc_boot(struct rproc *rproc);
+void rproc_shutdown(struct rproc *rproc);
+
+static inline struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev)
+{
+	return container_of(vdev, struct rproc_vdev, vdev);
+}
+
+static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev)
+{
+	struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+
+	return rvdev->rproc;
+}
+
+#endif /* REMOTEPROC_H */
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
index c6c6084..6fdf027 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -117,10 +117,10 @@
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
-#include <linux/device.h>
 #include <linux/leds.h>
 #include <linux/err.h>
 
+struct device;
 /* this is opaque */
 struct rfkill;
 
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index 67be037..7be2e88 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -151,6 +151,9 @@
 
 void ring_buffer_record_disable(struct ring_buffer *buffer);
 void ring_buffer_record_enable(struct ring_buffer *buffer);
+void ring_buffer_record_off(struct ring_buffer *buffer);
+void ring_buffer_record_on(struct ring_buffer *buffer);
+int ring_buffer_record_is_on(struct ring_buffer *buffer);
 void ring_buffer_record_disable_cpu(struct ring_buffer *buffer, int cpu);
 void ring_buffer_record_enable_cpu(struct ring_buffer *buffer, int cpu);
 
diff --git a/include/linux/rio_drv.h b/include/linux/rio_drv.h
index 229b3ca..7f07470 100644
--- a/include/linux/rio_drv.h
+++ b/include/linux/rio_drv.h
@@ -17,7 +17,6 @@
 #include <linux/ioport.h>
 #include <linux/list.h>
 #include <linux/errno.h>
-#include <linux/device.h>
 #include <linux/string.h>
 #include <linux/rio.h>
 
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index 1cdd62a..fd07c45 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -122,7 +122,6 @@
 int anon_vma_clone(struct vm_area_struct *, struct vm_area_struct *);
 void anon_vma_moveto_tail(struct vm_area_struct *);
 int anon_vma_fork(struct vm_area_struct *, struct vm_area_struct *);
-void __anon_vma_link(struct vm_area_struct *);
 
 static inline void anon_vma_merge(struct vm_area_struct *vma,
 				  struct vm_area_struct *next)
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
new file mode 100644
index 0000000..a8e50e4
--- /dev/null
+++ b/include/linux/rpmsg.h
@@ -0,0 +1,326 @@
+/*
+ * Remote processor messaging
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name Texas Instruments nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_RPMSG_H
+#define _LINUX_RPMSG_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+
+/* The feature bitmap for virtio rpmsg */
+#define VIRTIO_RPMSG_F_NS	0 /* RP supports name service notifications */
+
+/**
+ * struct rpmsg_hdr - common header for all rpmsg messages
+ * @src: source address
+ * @dst: destination address
+ * @reserved: reserved for future use
+ * @len: length of payload (in bytes)
+ * @flags: message flags
+ * @data: @len bytes of message payload data
+ *
+ * Every message sent(/received) on the rpmsg bus begins with this header.
+ */
+struct rpmsg_hdr {
+	u32 src;
+	u32 dst;
+	u32 reserved;
+	u16 len;
+	u16 flags;
+	u8 data[0];
+} __packed;
+
+/**
+ * struct rpmsg_ns_msg - dynamic name service announcement message
+ * @name: name of remote service that is published
+ * @addr: address of remote service that is published
+ * @flags: indicates whether service is created or destroyed
+ *
+ * This message is sent across to publish a new service, or announce
+ * about its removal. When we receive these messages, an appropriate
+ * rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe()
+ * or ->remove() handler of the appropriate rpmsg driver will be invoked
+ * (if/as-soon-as one is registered).
+ */
+struct rpmsg_ns_msg {
+	char name[RPMSG_NAME_SIZE];
+	u32 addr;
+	u32 flags;
+} __packed;
+
+/**
+ * enum rpmsg_ns_flags - dynamic name service announcement flags
+ *
+ * @RPMSG_NS_CREATE: a new remote service was just created
+ * @RPMSG_NS_DESTROY: a known remote service was just destroyed
+ */
+enum rpmsg_ns_flags {
+	RPMSG_NS_CREATE		= 0,
+	RPMSG_NS_DESTROY	= 1,
+};
+
+#define RPMSG_ADDR_ANY		0xFFFFFFFF
+
+struct virtproc_info;
+
+/**
+ * rpmsg_channel - devices that belong to the rpmsg bus are called channels
+ * @vrp: the remote processor this channel belongs to
+ * @dev: the device struct
+ * @id: device id (used to match between rpmsg drivers and devices)
+ * @src: local address
+ * @dst: destination address
+ * @ept: the rpmsg endpoint of this channel
+ * @announce: if set, rpmsg will announce the creation/removal of this channel
+ */
+struct rpmsg_channel {
+	struct virtproc_info *vrp;
+	struct device dev;
+	struct rpmsg_device_id id;
+	u32 src;
+	u32 dst;
+	struct rpmsg_endpoint *ept;
+	bool announce;
+};
+
+typedef void (*rpmsg_rx_cb_t)(struct rpmsg_channel *, void *, int, void *, u32);
+
+/**
+ * struct rpmsg_endpoint - binds a local rpmsg address to its user
+ * @rpdev: rpmsg channel device
+ * @cb: rx callback handler
+ * @addr: local rpmsg address
+ * @priv: private data for the driver's use
+ *
+ * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as
+ * it binds an rpmsg address with an rx callback handler.
+ *
+ * Simple rpmsg drivers shouldn't use this struct directly, because
+ * things just work: every rpmsg driver provides an rx callback upon
+ * registering to the bus, and that callback is then bound to its rpmsg
+ * address when the driver is probed. When relevant inbound messages arrive
+ * (i.e. messages which their dst address equals to the src address of
+ * the rpmsg channel), the driver's handler is invoked to process it.
+ *
+ * More complicated drivers though, that do need to allocate additional rpmsg
+ * addresses, and bind them to different rx callbacks, must explicitly
+ * create additional endpoints by themselves (see rpmsg_create_ept()).
+ */
+struct rpmsg_endpoint {
+	struct rpmsg_channel *rpdev;
+	rpmsg_rx_cb_t cb;
+	u32 addr;
+	void *priv;
+};
+
+/**
+ * struct rpmsg_driver - rpmsg driver struct
+ * @drv: underlying device driver
+ * @id_table: rpmsg ids serviced by this driver
+ * @probe: invoked when a matching rpmsg channel (i.e. device) is found
+ * @remove: invoked when the rpmsg channel is removed
+ * @callback: invoked when an inbound message is received on the channel
+ */
+struct rpmsg_driver {
+	struct device_driver drv;
+	const struct rpmsg_device_id *id_table;
+	int (*probe)(struct rpmsg_channel *dev);
+	void (*remove)(struct rpmsg_channel *dev);
+	void (*callback)(struct rpmsg_channel *, void *, int, void *, u32);
+};
+
+int register_rpmsg_device(struct rpmsg_channel *dev);
+void unregister_rpmsg_device(struct rpmsg_channel *dev);
+int register_rpmsg_driver(struct rpmsg_driver *drv);
+void unregister_rpmsg_driver(struct rpmsg_driver *drv);
+void rpmsg_destroy_ept(struct rpmsg_endpoint *);
+struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *,
+				rpmsg_rx_cb_t cb, void *priv, u32 addr);
+int
+rpmsg_send_offchannel_raw(struct rpmsg_channel *, u32, u32, void *, int, bool);
+
+/**
+ * rpmsg_send() - send a message across to the remote processor
+ * @rpdev: the rpmsg channel
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len on the @rpdev channel.
+ * The message will be sent to the remote processor which the @rpdev
+ * channel belongs to, using @rpdev's source and destination addresses.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int len)
+{
+	u32 src = rpdev->src, dst = rpdev->dst;
+
+	return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
+}
+
+/**
+ * rpmsg_sendto() - send a message across to the remote processor, specify dst
+ * @rpdev: the rpmsg channel
+ * @data: payload of message
+ * @len: length of payload
+ * @dst: destination address
+ *
+ * This function sends @data of length @len to the remote @dst address.
+ * The message will be sent to the remote processor which the @rpdev
+ * channel belongs to, using @rpdev's source address.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline
+int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
+{
+	u32 src = rpdev->src;
+
+	return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
+}
+
+/**
+ * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
+ * @rpdev: the rpmsg channel
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len to the remote @dst address,
+ * and uses @src as the source address.
+ * The message will be sent to the remote processor which the @rpdev
+ * channel belongs to.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline
+int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+							void *data, int len)
+{
+	return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
+}
+
+/**
+ * rpmsg_send() - send a message across to the remote processor
+ * @rpdev: the rpmsg channel
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len on the @rpdev channel.
+ * The message will be sent to the remote processor which the @rpdev
+ * channel belongs to, using @rpdev's source and destination addresses.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline
+int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len)
+{
+	u32 src = rpdev->src, dst = rpdev->dst;
+
+	return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
+}
+
+/**
+ * rpmsg_sendto() - send a message across to the remote processor, specify dst
+ * @rpdev: the rpmsg channel
+ * @data: payload of message
+ * @len: length of payload
+ * @dst: destination address
+ *
+ * This function sends @data of length @len to the remote @dst address.
+ * The message will be sent to the remote processor which the @rpdev
+ * channel belongs to, using @rpdev's source address.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline
+int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
+{
+	u32 src = rpdev->src;
+
+	return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
+}
+
+/**
+ * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
+ * @rpdev: the rpmsg channel
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len to the remote @dst address,
+ * and uses @src as the source address.
+ * The message will be sent to the remote processor which the @rpdev
+ * channel belongs to.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline
+int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+							void *data, int len)
+{
+	return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
+}
+
+#endif /* _LINUX_RPMSG_H */
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index 93f4d03..fcabfb4 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -202,7 +202,8 @@
 	struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */
 	int pie_enabled;
 	struct work_struct irqwork;
-
+	/* Some hardware can't support UIE mode */
+	int uie_unsupported;
 
 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
 	struct work_struct uie_task;
diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h
index 63d4065..54bd7cd 100644
--- a/include/linux/rwsem.h
+++ b/include/linux/rwsem.h
@@ -14,7 +14,6 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
-#include <asm/system.h>
 #include <linux/atomic.h>
 
 struct rw_semaphore;
diff --git a/include/linux/sa11x0-dma.h b/include/linux/sa11x0-dma.h
new file mode 100644
index 0000000..65839a5
--- /dev/null
+++ b/include/linux/sa11x0-dma.h
@@ -0,0 +1,24 @@
+/*
+ * SA11x0 DMA Engine support
+ *
+ * Copyright (C) 2012 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LINUX_SA11X0_DMA_H
+#define __LINUX_SA11X0_DMA_H
+
+struct dma_chan;
+
+#if defined(CONFIG_DMA_SA11X0) || defined(CONFIG_DMA_SA11X0_MODULE)
+bool sa11x0_dma_filter_fn(struct dma_chan *, void *);
+#else
+static inline bool sa11x0_dma_filter_fn(struct dma_chan *c, void *d)
+{
+	return false;
+}
+#endif
+
+#endif
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index 9aaf5bf..ac9586d 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -1,10 +1,12 @@
 #ifndef _LINUX_SCATTERLIST_H
 #define _LINUX_SCATTERLIST_H
 
+#include <linux/string.h>
+#include <linux/bug.h>
+#include <linux/mm.h>
+
 #include <asm/types.h>
 #include <asm/scatterlist.h>
-#include <linux/mm.h>
-#include <linux/string.h>
 #include <asm/io.h>
 
 struct sg_table {
diff --git a/include/linux/sched.h b/include/linux/sched.h
index e074e1e..81a173c 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -63,7 +63,6 @@
 #include <linux/nodemask.h>
 #include <linux/mm_types.h>
 
-#include <asm/system.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/cputime.h>
@@ -553,6 +552,18 @@
 	int			group_stop_count;
 	unsigned int		flags; /* see SIGNAL_* flags below */
 
+	/*
+	 * PR_SET_CHILD_SUBREAPER marks a process, like a service
+	 * manager, to re-parent orphan (double-forking) child processes
+	 * to this process instead of 'init'. The service manager is
+	 * able to receive SIGCHLD signals and is able to investigate
+	 * the process until it calls wait(). All children of this
+	 * process will inherit a flag if they should look for a
+	 * child_subreaper process at exit.
+	 */
+	unsigned int		is_child_subreaper:1;
+	unsigned int		has_child_subreaper:1;
+
 	/* POSIX.1b Interval Timers */
 	struct list_head posix_timers;
 
@@ -1514,7 +1525,7 @@
 #endif
 #ifdef CONFIG_CPUSETS
 	nodemask_t mems_allowed;	/* Protected by alloc_lock */
-	int mems_allowed_change_disable;
+	seqcount_t mems_allowed_seq;	/* Seqence no to catch updates */
 	int cpuset_mem_spread_rotor;
 	int cpuset_slab_spread_rotor;
 #endif
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index 44f1514..fc61854 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -3,6 +3,7 @@
 
 #include <linux/types.h>
 #include <linux/string.h>
+#include <linux/bug.h>
 #include <linux/mutex.h>
 #include <linux/cpumask.h>
 #include <linux/nodemask.h>
@@ -121,9 +122,12 @@
 void *__seq_open_private(struct file *, const struct seq_operations *, int);
 int seq_open_private(struct file *, const struct seq_operations *, int);
 int seq_release_private(struct inode *, struct file *);
+int seq_put_decimal_ull(struct seq_file *m, char delimiter,
+			unsigned long long num);
+int seq_put_decimal_ll(struct seq_file *m, char delimiter,
+			long long num);
 
 #define SEQ_START_TOKEN ((void *)1)
-
 /*
  * Helpers for iteration over list_head-s in seq_files
  */
diff --git a/include/linux/serial_pnx8xxx.h b/include/linux/serial_pnx8xxx.h
index de6c19c..79ad87b 100644
--- a/include/linux/serial_pnx8xxx.h
+++ b/include/linux/serial_pnx8xxx.h
@@ -20,7 +20,6 @@
 #define _LINUX_SERIAL_PNX8XXX_H
 
 #include <linux/serial_core.h>
-#include <linux/device.h>
 
 #define PNX8XXX_NR_PORTS	2
 
diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h
index 54341d8..0a9d8f2 100644
--- a/include/linux/sh_clk.h
+++ b/include/linux/sh_clk.h
@@ -18,7 +18,8 @@
 	struct kref		ref;
 };
 
-struct clk_ops {
+
+struct sh_clk_ops {
 #ifdef CONFIG_SH_CLK_CPG_LEGACY
 	void (*init)(struct clk *clk);
 #endif
@@ -37,7 +38,7 @@
 	unsigned short		parent_num;	/* choose between */
 	unsigned char		src_shift;	/* source clock field in the */
 	unsigned char		src_width;	/* configuration register */
-	struct clk_ops		*ops;
+	struct sh_clk_ops	*ops;
 
 	struct list_head	children;
 	struct list_head	sibling;	/* node for children */
diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h
index b160645..6aed080 100644
--- a/include/linux/sh_intc.h
+++ b/include/linux/sh_intc.h
@@ -3,6 +3,23 @@
 
 #include <linux/ioport.h>
 
+#ifdef CONFIG_SUPERH
+#define INTC_NR_IRQS	512
+#else
+#define INTC_NR_IRQS	1024
+#endif
+
+/*
+ * Convert back and forth between INTEVT and IRQ values.
+ */
+#ifdef CONFIG_CPU_HAS_INTEVT
+#define evt2irq(evt)		(((evt) >> 5) - 16)
+#define irq2evt(irq)		(((irq) + 16) << 5)
+#else
+#define evt2irq(evt)		(evt)
+#define irq2evt(irq)		(irq)
+#endif
+
 typedef unsigned char intc_enum;
 
 struct intc_vect {
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index a2b9953..3337027 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -18,6 +18,7 @@
 #include <linux/kmemcheck.h>
 #include <linux/compiler.h>
 #include <linux/time.h>
+#include <linux/bug.h>
 #include <linux/cache.h>
 
 #include <linux/atomic.h>
@@ -500,7 +501,6 @@
  */
 #include <linux/slab.h>
 
-#include <asm/system.h>
 
 /*
  * skb might have a dst pointer attached, refcounted or not.
@@ -1244,7 +1244,7 @@
 }
 
 extern void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page,
-			    int off, int size);
+			    int off, int size, unsigned int truesize);
 
 #define SKB_PAGE_ASSERT(skb) 	BUG_ON(skb_shinfo(skb)->nr_frags)
 #define SKB_FRAG_ASSERT(skb) 	BUG_ON(skb_has_frag_list(skb))
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 573c809..a595dce 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -190,7 +190,7 @@
 #endif
 
 /**
- * kcalloc - allocate memory for an array. The memory is set to zero.
+ * kmalloc_array - allocate memory for an array.
  * @n: number of elements.
  * @size: element size.
  * @flags: the type of memory to allocate.
@@ -240,11 +240,22 @@
  * for general use, and so are not documented here. For a full list of
  * potential flags, always refer to linux/gfp.h.
  */
-static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
+static inline void *kmalloc_array(size_t n, size_t size, gfp_t flags)
 {
 	if (size != 0 && n > ULONG_MAX / size)
 		return NULL;
-	return __kmalloc(n * size, flags | __GFP_ZERO);
+	return __kmalloc(n * size, flags);
+}
+
+/**
+ * kcalloc - allocate memory for an array. The memory is set to zero.
+ * @n: number of elements.
+ * @size: element size.
+ * @flags: the type of memory to allocate (see kmalloc).
+ */
+static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
+{
+	return kmalloc_array(n, size, flags | __GFP_ZERO);
 }
 
 #if !defined(CONFIG_NUMA) && !defined(CONFIG_SLOB)
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
index a32bcfd..c2f8c8b 100644
--- a/include/linux/slub_def.h
+++ b/include/linux/slub_def.h
@@ -8,6 +8,7 @@
  */
 #include <linux/types.h>
 #include <linux/gfp.h>
+#include <linux/bug.h>
 #include <linux/workqueue.h>
 #include <linux/kobject.h>
 
@@ -21,7 +22,7 @@
 	FREE_FROZEN,		/* Freeing to frozen slab */
 	FREE_ADD_PARTIAL,	/* Freeing moves slab to partial list */
 	FREE_REMOVE_PARTIAL,	/* Freeing removes last object */
-	ALLOC_FROM_PARTIAL,	/* Cpu slab acquired from partial list */
+	ALLOC_FROM_PARTIAL,	/* Cpu slab acquired from node partial list */
 	ALLOC_SLAB,		/* Cpu slab acquired from page allocator */
 	ALLOC_REFILL,		/* Refill cpu slab from slab freelist */
 	ALLOC_NODE_MISMATCH,	/* Switching cpu slab */
@@ -37,7 +38,9 @@
 	CMPXCHG_DOUBLE_CPU_FAIL,/* Failure of this_cpu_cmpxchg_double */
 	CMPXCHG_DOUBLE_FAIL,	/* Number of times that cmpxchg double did not match */
 	CPU_PARTIAL_ALLOC,	/* Used cpu partial on alloc */
-	CPU_PARTIAL_FREE,	/* USed cpu partial on free */
+	CPU_PARTIAL_FREE,	/* Refill cpu partial on free */
+	CPU_PARTIAL_NODE,	/* Refill cpu partial from node partial */
+	CPU_PARTIAL_DRAIN,	/* Drain cpu partial to node partial */
 	NR_SLUB_STAT_ITEMS };
 
 struct kmem_cache_cpu {
diff --git a/include/linux/smp.h b/include/linux/smp.h
index 8cc38d3..10530d9 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -102,6 +102,22 @@
 int on_each_cpu(smp_call_func_t func, void *info, int wait);
 
 /*
+ * Call a function on processors specified by mask, which might include
+ * the local one.
+ */
+void on_each_cpu_mask(const struct cpumask *mask, smp_call_func_t func,
+		void *info, bool wait);
+
+/*
+ * Call a function on each processor for which the supplied function
+ * cond_func returns a positive value. This may include the local
+ * processor.
+ */
+void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info),
+		smp_call_func_t func, void *info, bool wait,
+		gfp_t gfp_flags);
+
+/*
  * Mark the boot cpu "online" so that it can call console drivers in
  * printk() and can access its per-cpu storage.
  */
@@ -132,6 +148,36 @@
 		local_irq_enable();		\
 		0;				\
 	})
+/*
+ * Note we still need to test the mask even for UP
+ * because we actually can get an empty mask from
+ * code that on SMP might call us without the local
+ * CPU in the mask.
+ */
+#define on_each_cpu_mask(mask, func, info, wait) \
+	do {						\
+		if (cpumask_test_cpu(0, (mask))) {	\
+			local_irq_disable();		\
+			(func)(info);			\
+			local_irq_enable();		\
+		}					\
+	} while (0)
+/*
+ * Preemption is disabled here to make sure the cond_func is called under the
+ * same condtions in UP and SMP.
+ */
+#define on_each_cpu_cond(cond_func, func, info, wait, gfp_flags)\
+	do {							\
+		void *__info = (info);				\
+		preempt_disable();				\
+		if ((cond_func)(0, __info)) {			\
+			local_irq_disable();			\
+			(func)(__info);				\
+			local_irq_enable();			\
+		}						\
+		preempt_enable();				\
+	} while (0)
+
 static inline void smp_send_reschedule(int cpu) { }
 #define num_booting_cpus()			1
 #define smp_prepare_boot_cpu()			do {} while (0)
diff --git a/include/linux/socket.h b/include/linux/socket.h
index da2d3e2..b84bbd4 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -265,7 +265,7 @@
 #define MSG_NOSIGNAL	0x4000	/* Do not generate SIGPIPE */
 #define MSG_MORE	0x8000	/* Sender will send more */
 #define MSG_WAITFORONE	0x10000	/* recvmmsg(): block until 1+ packets avail */
-
+#define MSG_SENDPAGE_NOTLAST 0x20000 /* sendpage() internal : not the last page */
 #define MSG_EOF         MSG_FIN
 
 #define MSG_CMSG_CLOEXEC 0x40000000	/* Set close_on_exit for file
diff --git a/include/linux/spi/mmc_spi.h b/include/linux/spi/mmc_spi.h
index 0f4eb16..32be8db 100644
--- a/include/linux/spi/mmc_spi.h
+++ b/include/linux/spi/mmc_spi.h
@@ -1,10 +1,10 @@
 #ifndef __LINUX_SPI_MMC_SPI_H
 #define __LINUX_SPI_MMC_SPI_H
 
-#include <linux/device.h>
 #include <linux/spi/spi.h>
 #include <linux/interrupt.h>
 
+struct device;
 struct mmc_host;
 
 /* Put this in platform_data of a device being used to manage an MMC/SD
diff --git a/include/linux/spi/orion_spi.h b/include/linux/spi/orion_spi.h
index decf6d8..b4d9fa6 100644
--- a/include/linux/spi/orion_spi.h
+++ b/include/linux/spi/orion_spi.h
@@ -11,7 +11,6 @@
 
 struct orion_spi_info {
 	u32	tclk;		/* no <linux/clk.h> support yet */
-	u32	enable_clock_fix;
 };
 
 
diff --git a/include/linux/spi/s3c24xx.h b/include/linux/spi/s3c24xx.h
new file mode 100644
index 0000000..c23b923
--- /dev/null
+++ b/include/linux/spi/s3c24xx.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2006 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - SPI Controller platform_device info
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __LINUX_SPI_S3C24XX_H
+#define __LINUX_SPI_S3C24XX_H __FILE__
+
+struct s3c2410_spi_info {
+	int			 pin_cs;	/* simple gpio cs */
+	unsigned int		 num_cs;	/* total chipselects */
+	int			 bus_num;       /* bus number to use. */
+
+	unsigned int		 use_fiq:1;	/* use fiq */
+
+	void (*gpio_setup)(struct s3c2410_spi_info *spi, int enable);
+	void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
+};
+
+#endif /* __LINUX_SPI_S3C24XX_H */
diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index 7df6c17..7d537ce 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -55,8 +55,8 @@
 #include <linux/kernel.h>
 #include <linux/stringify.h>
 #include <linux/bottom_half.h>
+#include <asm/barrier.h>
 
-#include <asm/system.h>
 
 /*
  * Must define these before including other files, inline functions need them
@@ -375,10 +375,7 @@
 	return raw_spin_can_lock(&lock->rlock);
 }
 
-static inline void assert_spin_locked(spinlock_t *lock)
-{
-	assert_raw_spin_locked(&lock->rlock);
-}
+#define assert_spin_locked(lock)	assert_raw_spin_locked(&(lock)->rlock)
 
 /*
  * Pull the atomic_t declaration:
diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_smp.h
index e253ccd..51df117a 100644
--- a/include/linux/spinlock_api_smp.h
+++ b/include/linux/spinlock_api_smp.h
@@ -67,7 +67,7 @@
 #define _raw_spin_trylock_bh(lock) __raw_spin_trylock_bh(lock)
 #endif
 
-#ifdef CONFIG_INLINE_SPIN_UNLOCK
+#ifndef CONFIG_UNINLINE_SPIN_UNLOCK
 #define _raw_spin_unlock(lock) __raw_spin_unlock(lock)
 #endif
 
diff --git a/include/linux/ssb/ssb_driver_gige.h b/include/linux/ssb/ssb_driver_gige.h
index eba52a1..6b05dcd 100644
--- a/include/linux/ssb/ssb_driver_gige.h
+++ b/include/linux/ssb/ssb_driver_gige.h
@@ -2,6 +2,7 @@
 #define LINUX_SSB_DRIVER_GIGE_H_
 
 #include <linux/ssb/ssb.h>
+#include <linux/bug.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
 
diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h
index c170edc..3b5e910 100644
--- a/include/linux/stop_machine.h
+++ b/include/linux/stop_machine.h
@@ -5,7 +5,6 @@
 #include <linux/cpumask.h>
 #include <linux/smp.h>
 #include <linux/list.h>
-#include <asm/system.h>
 
 /*
  * stop_cpu[s]() is simplistic per-cpu maximum priority cpu
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index 7874a8a..492a36d 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -99,6 +99,8 @@
 
 	struct rpc_cred *	(*lookup_cred)(struct rpc_auth *, struct auth_cred *, int);
 	struct rpc_cred *	(*crcreate)(struct rpc_auth*, struct auth_cred *, int);
+	int			(*pipes_create)(struct rpc_auth *);
+	void			(*pipes_destroy)(struct rpc_auth *);
 };
 
 struct rpc_credops {
diff --git a/include/linux/sunrpc/bc_xprt.h b/include/linux/sunrpc/bc_xprt.h
index f7f3ce34..969c0a6 100644
--- a/include/linux/sunrpc/bc_xprt.h
+++ b/include/linux/sunrpc/bc_xprt.h
@@ -35,7 +35,7 @@
 struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt);
 void xprt_free_bc_request(struct rpc_rqst *req);
 int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs);
-void xprt_destroy_backchannel(struct rpc_xprt *, int max_reqs);
+void xprt_destroy_backchannel(struct rpc_xprt *, unsigned int max_reqs);
 int bc_send(struct rpc_rqst *req);
 
 /*
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index 57531f8..f5fd616 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -117,6 +117,7 @@
 		struct cache_detail_procfs procfs;
 		struct cache_detail_pipefs pipefs;
 	} u;
+	struct net		*net;
 };
 
 
@@ -197,11 +198,14 @@
 extern void cache_purge(struct cache_detail *detail);
 #define NEVER (0x7FFFFFFF)
 extern void __init cache_initialize(void);
-extern int cache_register(struct cache_detail *cd);
 extern int cache_register_net(struct cache_detail *cd, struct net *net);
-extern void cache_unregister(struct cache_detail *cd);
 extern void cache_unregister_net(struct cache_detail *cd, struct net *net);
 
+extern struct cache_detail *cache_create_net(struct cache_detail *tmpl, struct net *net);
+extern void cache_destroy_net(struct cache_detail *cd, struct net *net);
+
+extern void sunrpc_init_cache_detail(struct cache_detail *cd);
+extern void sunrpc_destroy_cache_detail(struct cache_detail *cd);
 extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *,
 					umode_t, struct cache_detail *);
 extern void sunrpc_cache_unregister_pipefs(struct cache_detail *);
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 2c5993a..523547e 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -35,14 +35,13 @@
 	struct list_head	cl_clients;	/* Global list of clients */
 	struct list_head	cl_tasks;	/* List of tasks */
 	spinlock_t		cl_lock;	/* spinlock */
-	struct rpc_xprt *	cl_xprt;	/* transport */
+	struct rpc_xprt __rcu *	cl_xprt;	/* transport */
 	struct rpc_procinfo *	cl_procinfo;	/* procedure info */
 	u32			cl_prog,	/* RPC program number */
 				cl_vers,	/* RPC version number */
 				cl_maxproc;	/* max procedure number */
 
-	char *			cl_server;	/* server machine name */
-	char *			cl_protname;	/* protocol name */
+	const char *		cl_protname;	/* protocol name */
 	struct rpc_auth *	cl_auth;	/* authenticator */
 	struct rpc_stat *	cl_stats;	/* per-program statistics */
 	struct rpc_iostats *	cl_metrics;	/* per-client statistics */
@@ -57,12 +56,11 @@
 
 	int			cl_nodelen;	/* nodename length */
 	char 			cl_nodename[UNX_MAXNODENAME];
-	struct path		cl_path;
+	struct dentry *		cl_dentry;
 	struct rpc_clnt *	cl_parent;	/* Points to parent of clones */
 	struct rpc_rtt		cl_rtt_default;
 	struct rpc_timeout	cl_timeout_default;
-	struct rpc_program *	cl_program;
-	char			cl_inline_name[32];
+	const struct rpc_program *cl_program;
 	char			*cl_principal;	/* target to authenticate to */
 };
 
@@ -71,12 +69,12 @@
  */
 #define RPC_MAXVERSION		4
 struct rpc_program {
-	char *			name;		/* protocol name */
+	const char *		name;		/* protocol name */
 	u32			number;		/* program number */
 	unsigned int		nrvers;		/* number of versions */
-	struct rpc_version **	version;	/* version array */
+	const struct rpc_version **	version;	/* version array */
 	struct rpc_stat *	stats;		/* statistics */
-	char *			pipe_dir_name;	/* path to rpc_pipefs dir */
+	const char *		pipe_dir_name;	/* path to rpc_pipefs dir */
 };
 
 struct rpc_version {
@@ -97,7 +95,7 @@
 	unsigned int		p_count;	/* call count */
 	unsigned int		p_timer;	/* Which RTT timer to use */
 	u32			p_statidx;	/* Which procedure to account */
-	char *			p_name;		/* name of procedure */
+	const char *		p_name;		/* name of procedure */
 };
 
 #ifdef __KERNEL__
@@ -109,8 +107,8 @@
 	size_t			addrsize;
 	struct sockaddr		*saddress;
 	const struct rpc_timeout *timeout;
-	char			*servername;
-	struct rpc_program	*program;
+	const char		*servername;
+	const struct rpc_program *program;
 	u32			prognumber;	/* overrides program->number */
 	u32			version;
 	rpc_authflavor_t	authflavor;
@@ -129,17 +127,18 @@
 
 struct rpc_clnt *rpc_create(struct rpc_create_args *args);
 struct rpc_clnt	*rpc_bind_new_program(struct rpc_clnt *,
-				struct rpc_program *, u32);
+				const struct rpc_program *, u32);
 void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt);
 struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
 void		rpc_shutdown_client(struct rpc_clnt *);
 void		rpc_release_client(struct rpc_clnt *);
 void		rpc_task_release_client(struct rpc_task *);
 
-int		rpcb_create_local(void);
-void		rpcb_put_local(void);
-int		rpcb_register(u32, u32, int, unsigned short);
-int		rpcb_v4_register(const u32 program, const u32 version,
+int		rpcb_create_local(struct net *);
+void		rpcb_put_local(struct net *);
+int		rpcb_register(struct net *, u32, u32, int, unsigned short);
+int		rpcb_v4_register(struct net *net, const u32 program,
+				 const u32 version,
 				 const struct sockaddr *address,
 				 const char *netid);
 void		rpcb_getport_async(struct rpc_task *);
@@ -156,16 +155,19 @@
 int		rpc_restart_call_prepare(struct rpc_task *);
 int		rpc_restart_call(struct rpc_task *);
 void		rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
+int		rpc_protocol(struct rpc_clnt *);
+struct net *	rpc_net_ns(struct rpc_clnt *);
 size_t		rpc_max_payload(struct rpc_clnt *);
 void		rpc_force_rebind(struct rpc_clnt *);
 size_t		rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
 const char	*rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
+int		rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t);
 
 size_t		rpc_ntop(const struct sockaddr *, char *, const size_t);
-size_t		rpc_pton(const char *, const size_t,
+size_t		rpc_pton(struct net *, const char *, const size_t,
 			 struct sockaddr *, const size_t);
 char *		rpc_sockaddr2uaddr(const struct sockaddr *, gfp_t);
-size_t		rpc_uaddr2sockaddr(const char *, const size_t,
+size_t		rpc_uaddr2sockaddr(struct net *, const char *, const size_t,
 				   struct sockaddr *, const size_t);
 
 static inline unsigned short rpc_get_port(const struct sockaddr *sap)
diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h
index c2786f2..a76cc20 100644
--- a/include/linux/sunrpc/debug.h
+++ b/include/linux/sunrpc/debug.h
@@ -31,9 +31,12 @@
 /*
  * Enable RPC debugging/profiling.
  */
-#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_SUNRPC_DEBUG
 #define  RPC_DEBUG
 #endif
+#ifdef CONFIG_TRACEPOINTS
+#define RPC_TRACEPOINTS
+#endif
 /* #define  RPC_PROFILE */
 
 /*
@@ -47,15 +50,32 @@
 #endif
 
 #define dprintk(args...)	dfprintk(FACILITY, ## args)
+#define dprintk_rcu(args...)	dfprintk_rcu(FACILITY, ## args)
 
 #undef ifdebug
 #ifdef RPC_DEBUG			
 # define ifdebug(fac)		if (unlikely(rpc_debug & RPCDBG_##fac))
-# define dfprintk(fac, args...)	do { ifdebug(fac) printk(args); } while(0)
+
+# define dfprintk(fac, args...)	\
+	do { \
+		ifdebug(fac) \
+			printk(KERN_DEFAULT args); \
+	} while (0)
+
+# define dfprintk_rcu(fac, args...)	\
+	do { \
+		ifdebug(fac) { \
+			rcu_read_lock(); \
+			printk(KERN_DEFAULT args); \
+			rcu_read_unlock(); \
+		} \
+	} while (0)
+
 # define RPC_IFDEBUG(x)		x
 #else
 # define ifdebug(fac)		if (0)
-# define dfprintk(fac, args...)	do ; while (0)
+# define dfprintk(fac, args...)	do {} while (0)
+# define dfprintk_rcu(fac, args...)	do {} while (0)
 # define RPC_IFDEBUG(x)
 #endif
 
diff --git a/include/linux/sunrpc/metrics.h b/include/linux/sunrpc/metrics.h
index b6edbc0..1565bbe 100644
--- a/include/linux/sunrpc/metrics.h
+++ b/include/linux/sunrpc/metrics.h
@@ -74,14 +74,16 @@
 #ifdef CONFIG_PROC_FS
 
 struct rpc_iostats *	rpc_alloc_iostats(struct rpc_clnt *);
-void			rpc_count_iostats(struct rpc_task *);
+void			rpc_count_iostats(const struct rpc_task *,
+					  struct rpc_iostats *);
 void			rpc_print_iostats(struct seq_file *, struct rpc_clnt *);
 void			rpc_free_iostats(struct rpc_iostats *);
 
 #else  /*  CONFIG_PROC_FS  */
 
 static inline struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt) { return NULL; }
-static inline void rpc_count_iostats(struct rpc_task *task) {}
+static inline void rpc_count_iostats(const struct rpc_task *task,
+				     struct rpc_iostats *stats) {}
 static inline void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) {}
 static inline void rpc_free_iostats(struct rpc_iostats *stats) {}
 
diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h
index 2bb03d7..a7b422b 100644
--- a/include/linux/sunrpc/rpc_pipe_fs.h
+++ b/include/linux/sunrpc/rpc_pipe_fs.h
@@ -21,21 +21,26 @@
 	void (*destroy_msg)(struct rpc_pipe_msg *);
 };
 
-struct rpc_inode {
-	struct inode vfs_inode;
-	void *private;
+struct rpc_pipe {
 	struct list_head pipe;
 	struct list_head in_upcall;
 	struct list_head in_downcall;
 	int pipelen;
 	int nreaders;
 	int nwriters;
-	int nkern_readwriters;
-	wait_queue_head_t waitq;
 #define RPC_PIPE_WAIT_FOR_OPEN	1
 	int flags;
 	struct delayed_work queue_timeout;
 	const struct rpc_pipe_ops *ops;
+	spinlock_t lock;
+	struct dentry *dentry;
+};
+
+struct rpc_inode {
+	struct inode vfs_inode;
+	void *private;
+	struct rpc_pipe *pipe;
+	wait_queue_head_t waitq;
 };
 
 static inline struct rpc_inode *
@@ -44,9 +49,28 @@
 	return container_of(inode, struct rpc_inode, vfs_inode);
 }
 
+enum {
+	SUNRPC_PIPEFS_NFS_PRIO,
+	SUNRPC_PIPEFS_RPC_PRIO,
+};
+
+extern int rpc_pipefs_notifier_register(struct notifier_block *);
+extern void rpc_pipefs_notifier_unregister(struct notifier_block *);
+
+enum {
+	RPC_PIPEFS_MOUNT,
+	RPC_PIPEFS_UMOUNT,
+};
+
+extern struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
+				      const unsigned char *dir_name);
+extern void rpc_pipefs_init_net(struct net *net);
+extern struct super_block *rpc_get_sb_net(const struct net *net);
+extern void rpc_put_sb_net(const struct net *net);
+
 extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *,
 				       char __user *, size_t);
-extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);
+extern int rpc_queue_upcall(struct rpc_pipe *, struct rpc_pipe_msg *);
 
 struct rpc_clnt;
 extern struct dentry *rpc_create_client_dir(struct dentry *, struct qstr *, struct rpc_clnt *);
@@ -59,11 +83,13 @@
 					   struct cache_detail *);
 extern void rpc_remove_cache_dir(struct dentry *);
 
-extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *,
-				 const struct rpc_pipe_ops *, int flags);
+extern int rpc_rmdir(struct dentry *dentry);
+
+struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags);
+void rpc_destroy_pipe_data(struct rpc_pipe *pipe);
+extern struct dentry *rpc_mkpipe_dentry(struct dentry *, const char *, void *,
+					struct rpc_pipe *);
 extern int rpc_unlink(struct dentry *);
-extern struct vfsmount *rpc_get_mount(void);
-extern void rpc_put_mount(void);
 extern int register_rpc_pipefs(void);
 extern void unregister_rpc_pipefs(void);
 
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index e775689..dc0c3cc 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -103,6 +103,7 @@
 struct rpc_call_ops {
 	void (*rpc_call_prepare)(struct rpc_task *, void *);
 	void (*rpc_call_done)(struct rpc_task *, void *);
+	void (*rpc_count_stats)(struct rpc_task *, void *);
 	void (*rpc_release)(void *);
 };
 
@@ -195,7 +196,7 @@
 	unsigned char		nr;			/* # tasks remaining for cookie */
 	unsigned short		qlen;			/* total # tasks waiting in queue */
 	struct rpc_timer	timer_list;
-#ifdef RPC_DEBUG
+#if defined(RPC_DEBUG) || defined(RPC_TRACEPOINTS)
 	const char *		name;
 #endif
 };
@@ -235,6 +236,9 @@
 					struct rpc_task *);
 void		rpc_wake_up(struct rpc_wait_queue *);
 struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
+struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *,
+					bool (*)(struct rpc_task *, void *),
+					void *);
 void		rpc_wake_up_status(struct rpc_wait_queue *, int);
 int		rpc_queue_empty(struct rpc_wait_queue *);
 void		rpc_delay(struct rpc_task *, unsigned long);
@@ -244,7 +248,8 @@
 void		rpciod_down(void);
 int		__rpc_wait_for_completion_task(struct rpc_task *task, int (*)(void *));
 #ifdef RPC_DEBUG
-void		rpc_show_tasks(void);
+struct net;
+void		rpc_show_tasks(struct net *);
 #endif
 int		rpc_init_mempool(void);
 void		rpc_destroy_mempool(void);
@@ -266,11 +271,22 @@
 	return (task->tk_priority + RPC_PRIORITY_LOW == prio);
 }
 
-#ifdef RPC_DEBUG
-static inline const char * rpc_qname(struct rpc_wait_queue *q)
+#if defined(RPC_DEBUG) || defined (RPC_TRACEPOINTS)
+static inline const char * rpc_qname(const struct rpc_wait_queue *q)
 {
 	return ((q && q->name) ? q->name : "unknown");
 }
+
+static inline void rpc_assign_waitqueue_name(struct rpc_wait_queue *q,
+		const char *name)
+{
+	q->name = name;
+}
+#else
+static inline void rpc_assign_waitqueue_name(struct rpc_wait_queue *q,
+		const char *name)
+{
+}
 #endif
 
 #endif /* _LINUX_SUNRPC_SCHED_H_ */
diff --git a/include/linux/sunrpc/stats.h b/include/linux/sunrpc/stats.h
index 680471d..edc6421 100644
--- a/include/linux/sunrpc/stats.h
+++ b/include/linux/sunrpc/stats.h
@@ -12,7 +12,7 @@
 #include <linux/proc_fs.h>
 
 struct rpc_stat {
-	struct rpc_program *	program;
+	const struct rpc_program *program;
 
 	unsigned int		netcnt,
 				netudpcnt,
@@ -58,24 +58,24 @@
 #endif
 
 #ifdef CONFIG_PROC_FS
-struct proc_dir_entry *	rpc_proc_register(struct rpc_stat *);
-void			rpc_proc_unregister(const char *);
-void			rpc_proc_zero(struct rpc_program *);
-struct proc_dir_entry *	svc_proc_register(struct svc_stat *,
+struct proc_dir_entry *	rpc_proc_register(struct net *,struct rpc_stat *);
+void			rpc_proc_unregister(struct net *,const char *);
+void			rpc_proc_zero(const struct rpc_program *);
+struct proc_dir_entry *	svc_proc_register(struct net *, struct svc_stat *,
 					  const struct file_operations *);
-void			svc_proc_unregister(const char *);
+void			svc_proc_unregister(struct net *, const char *);
 
 void			svc_seq_show(struct seq_file *,
 				     const struct svc_stat *);
 #else
 
-static inline struct proc_dir_entry *rpc_proc_register(struct rpc_stat *s) { return NULL; }
-static inline void rpc_proc_unregister(const char *p) {}
-static inline void rpc_proc_zero(struct rpc_program *p) {}
+static inline struct proc_dir_entry *rpc_proc_register(struct net *net, struct rpc_stat *s) { return NULL; }
+static inline void rpc_proc_unregister(struct net *net, const char *p) {}
+static inline void rpc_proc_zero(const struct rpc_program *p) {}
 
-static inline struct proc_dir_entry *svc_proc_register(struct svc_stat *s,
+static inline struct proc_dir_entry *svc_proc_register(struct net *net, struct svc_stat *s,
 						       const struct file_operations *f) { return NULL; }
-static inline void svc_proc_unregister(const char *p) {}
+static inline void svc_proc_unregister(struct net *net, const char *p) {}
 
 static inline void svc_seq_show(struct seq_file *seq,
 				const struct svc_stat *st) {}
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 35b37b1..51b29ac4 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -84,7 +84,8 @@
 	unsigned int		sv_nrpools;	/* number of thread pools */
 	struct svc_pool *	sv_pools;	/* array of thread pools */
 
-	void			(*sv_shutdown)(struct svc_serv *serv);
+	void			(*sv_shutdown)(struct svc_serv *serv,
+					       struct net *net);
 						/* Callback to use when last thread
 						 * exits.
 						 */
@@ -413,22 +414,24 @@
 /*
  * Function prototypes.
  */
-void svc_rpcb_cleanup(struct svc_serv *serv);
+int svc_rpcb_setup(struct svc_serv *serv, struct net *net);
+void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net);
 struct svc_serv *svc_create(struct svc_program *, unsigned int,
-			    void (*shutdown)(struct svc_serv *));
+			    void (*shutdown)(struct svc_serv *, struct net *net));
 struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
 					struct svc_pool *pool, int node);
 void		   svc_exit_thread(struct svc_rqst *);
 struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
-			void (*shutdown)(struct svc_serv *),
+			void (*shutdown)(struct svc_serv *, struct net *net),
 			svc_thread_fn, struct module *);
 int		   svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
 int		   svc_pool_stats_open(struct svc_serv *serv, struct file *file);
 void		   svc_destroy(struct svc_serv *);
+void		   svc_shutdown_net(struct svc_serv *, struct net *);
 int		   svc_process(struct svc_rqst *);
 int		   bc_svc_process(struct svc_serv *, struct rpc_rqst *,
 			struct svc_rqst *);
-int		   svc_register(const struct svc_serv *, const int,
+int		   svc_register(const struct svc_serv *, struct net *, const int,
 				const unsigned short, const unsigned short);
 
 void		   svc_wake_up(struct svc_serv *);
diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h
index c14fe86..0b8e3e6 100644
--- a/include/linux/sunrpc/svc_rdma.h
+++ b/include/linux/sunrpc/svc_rdma.h
@@ -190,7 +190,7 @@
 extern void svc_rdma_xdr_encode_write_list(struct rpcrdma_msg *, int);
 extern void svc_rdma_xdr_encode_reply_array(struct rpcrdma_write_array *, int);
 extern void svc_rdma_xdr_encode_array_chunk(struct rpcrdma_write_array *, int,
-					    u32, u64, u32);
+					    __be32, __be64, u32);
 extern void svc_rdma_xdr_encode_reply_header(struct svcxprt_rdma *,
 					     struct rpcrdma_msg *,
 					     struct rpcrdma_msg *,
@@ -292,7 +292,7 @@
 	if (wr_ary) {
 		rp_ary = (struct rpcrdma_write_array *)
 			&wr_ary->
-			wc_array[wr_ary->wc_nchunks].wc_target.rs_length;
+			wc_array[ntohl(wr_ary->wc_nchunks)].wc_target.rs_length;
 
 		goto found_it;
 	}
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
index dfa90094..b3f64b1 100644
--- a/include/linux/sunrpc/svc_xprt.h
+++ b/include/linux/sunrpc/svc_xprt.h
@@ -121,7 +121,8 @@
 int	svc_port_is_privileged(struct sockaddr *sin);
 int	svc_print_xprts(char *buf, int maxlen);
 struct	svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
-			const sa_family_t af, const unsigned short port);
+			struct net *net, const sa_family_t af,
+			const unsigned short port);
 int	svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen);
 
 static inline void svc_xprt_get(struct svc_xprt *xprt)
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index 25d333c..548790e 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -135,6 +135,9 @@
 extern void svcauth_unix_info_release(struct svc_xprt *xpt);
 extern int svcauth_unix_set_client(struct svc_rqst *rqstp);
 
+extern int unix_gid_cache_create(struct net *net);
+extern void unix_gid_cache_destroy(struct net *net);
+
 static inline unsigned long hash_str(char *name, int bits)
 {
 	unsigned long hash = 0;
diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h
index 83bbee3..7c32daa 100644
--- a/include/linux/sunrpc/svcauth_gss.h
+++ b/include/linux/sunrpc/svcauth_gss.h
@@ -18,6 +18,8 @@
 
 int gss_svc_init(void);
 void gss_svc_shutdown(void);
+int gss_svc_init_net(struct net *net);
+void gss_svc_shutdown_net(struct net *net);
 int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name);
 u32 svcauth_gss_flavor(struct auth_domain *dom);
 char *svc_gss_principal(struct svc_rqst *);
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index c84e974..cb4ac69 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -34,7 +34,7 @@
 /*
  * Function prototypes.
  */
-void		svc_close_all(struct svc_serv *);
+void		svc_close_net(struct svc_serv *, struct net *);
 int		svc_recv(struct svc_rqst *, long);
 int		svc_send(struct svc_rqst *);
 void		svc_drop(struct svc_rqst *);
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index 15518a1..77d278d 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -21,8 +21,8 @@
 
 #define RPC_MIN_SLOT_TABLE	(2U)
 #define RPC_DEF_SLOT_TABLE	(16U)
-#define RPC_MAX_SLOT_TABLE	(128U)
 #define RPC_MAX_SLOT_TABLE_LIMIT	(65536U)
+#define RPC_MAX_SLOT_TABLE	RPC_MAX_SLOT_TABLE_LIMIT
 
 /*
  * This describes a timeout strategy
@@ -219,13 +219,17 @@
 					connect_time,	/* jiffies waiting for connect */
 					sends,		/* how many complete requests */
 					recvs,		/* how many complete requests */
-					bad_xids;	/* lookup_rqst didn't find XID */
+					bad_xids,	/* lookup_rqst didn't find XID */
+					max_slots;	/* max rpc_slots used */
 
 		unsigned long long	req_u,		/* average requests on the wire */
-					bklog_u;	/* backlog queue utilization */
+					bklog_u,	/* backlog queue utilization */
+					sending_u,	/* send q utilization */
+					pending_u;	/* pend q utilization */
 	} stat;
 
 	struct net		*xprt_net;
+	const char		*servername;
 	const char		*address_strings[RPC_DISPLAY_MAX];
 };
 
@@ -255,6 +259,7 @@
 	struct sockaddr *	srcaddr;	/* optional local address */
 	struct sockaddr *	dstaddr;	/* remote peer address */
 	size_t			addrlen;
+	const char		*servername;
 	struct svc_xprt		*bc_xprt;	/* NFSv4.1 backchannel */
 };
 
diff --git a/include/linux/sunrpc/xprtsock.h b/include/linux/sunrpc/xprtsock.h
index 3f14a02..1ad36cc 100644
--- a/include/linux/sunrpc/xprtsock.h
+++ b/include/linux/sunrpc/xprtsock.h
@@ -12,18 +12,6 @@
 int		init_socket_xprt(void);
 void		cleanup_socket_xprt(void);
 
-/*
- * RPC slot table sizes for UDP, TCP transports
- */
-extern unsigned int xprt_udp_slot_table_entries;
-extern unsigned int xprt_tcp_slot_table_entries;
-
-/*
- * Parameters for choosing a free port
- */
-extern unsigned int xprt_min_resvport;
-extern unsigned int xprt_max_resvport;
-
 #define RPC_MIN_RESVPORT	(1U)
 #define RPC_MAX_RESVPORT	(65535U)
 #define RPC_DEF_MIN_RESVPORT	(665U)
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 3e60228..b1fd5c7 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -21,6 +21,9 @@
 #define SWAP_FLAG_PRIO_SHIFT	0
 #define SWAP_FLAG_DISCARD	0x10000 /* discard swap cluster after use */
 
+#define SWAP_FLAGS_VALID	(SWAP_FLAG_PRIO_MASK | SWAP_FLAG_PREFER | \
+				 SWAP_FLAG_DISCARD)
+
 static inline int current_is_kswapd(void)
 {
 	return current->flags & PF_KSWAPD;
@@ -223,6 +226,7 @@
 extern void activate_page(struct page *);
 extern void mark_page_accessed(struct page *);
 extern void lru_add_drain(void);
+extern void lru_add_drain_cpu(int cpu);
 extern int lru_add_drain_all(void);
 extern void rotate_reclaimable_page(struct page *page);
 extern void deactivate_page(struct page *page);
@@ -301,6 +305,13 @@
 	return vm_swappiness;
 }
 #endif
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
+extern void mem_cgroup_uncharge_swap(swp_entry_t ent);
+#else
+static inline void mem_cgroup_uncharge_swap(swp_entry_t ent)
+{
+}
+#endif
 #ifdef CONFIG_SWAP
 /* linux/mm/page_io.c */
 extern int swap_readpage(struct page *);
@@ -329,7 +340,6 @@
 extern void si_swapinfo(struct sysinfo *);
 extern swp_entry_t get_swap_page(void);
 extern swp_entry_t get_swap_page_of_type(int);
-extern int valid_swaphandles(swp_entry_t, unsigned long *);
 extern int add_swap_count_continuation(swp_entry_t, gfp_t);
 extern void swap_shmem_alloc(swp_entry_t);
 extern int swap_duplicate(swp_entry_t);
@@ -372,13 +382,6 @@
 {
 }
 #endif
-#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
-extern void mem_cgroup_uncharge_swap(swp_entry_t ent);
-#else
-static inline void mem_cgroup_uncharge_swap(swp_entry_t ent)
-{
-}
-#endif
 
 #else /* CONFIG_SWAP */
 
diff --git a/include/linux/swapops.h b/include/linux/swapops.h
index 2189d3f..792d16d 100644
--- a/include/linux/swapops.h
+++ b/include/linux/swapops.h
@@ -2,6 +2,7 @@
 #define _LINUX_SWAPOPS_H
 
 #include <linux/radix-tree.h>
+#include <linux/bug.h>
 
 /*
  * swapcache pages are stored in the swapper_space radix tree.  We want to
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 8ec1153..3de3acb 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -68,6 +68,7 @@
 #include <linux/aio_abi.h>
 #include <linux/capability.h>
 #include <linux/list.h>
+#include <linux/bug.h>
 #include <linux/sem.h>
 #include <asm/siginfo.h>
 #include <asm/signal.h>
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index bb9127d..c34b4c8 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -932,34 +932,14 @@
 #include <linux/list.h>
 #include <linux/rcupdate.h>
 #include <linux/wait.h>
+#include <linux/rbtree.h>
 
 /* For the /proc/sys support */
 struct ctl_table;
 struct nsproxy;
 struct ctl_table_root;
-
-struct ctl_table_set {
-	struct list_head list;
-	struct ctl_table_set *parent;
-	int (*is_seen)(struct ctl_table_set *);
-};
-
-extern void setup_sysctl_set(struct ctl_table_set *p,
-	struct ctl_table_set *parent,
-	int (*is_seen)(struct ctl_table_set *));
-
 struct ctl_table_header;
-
-extern void sysctl_head_get(struct ctl_table_header *);
-extern void sysctl_head_put(struct ctl_table_header *);
-extern int sysctl_is_seen(struct ctl_table_header *);
-extern struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *);
-extern struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev);
-extern struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
-						struct ctl_table_header *prev);
-extern void sysctl_head_finish(struct ctl_table_header *prev);
-extern int sysctl_perm(struct ctl_table_root *root,
-		struct ctl_table *table, int op);
+struct ctl_dir;
 
 typedef struct ctl_table ctl_table;
 
@@ -1023,8 +1003,6 @@
 	return (void *)(unsigned long)atomic_read(&poll->event);
 }
 
-void proc_sys_poll_notify(struct ctl_table_poll *poll);
-
 #define __CTL_TABLE_POLL_INITIALIZER(name) {				\
 	.event = ATOMIC_INIT(0),					\
 	.wait = __WAIT_QUEUE_HEAD_INITIALIZER(name.wait) }
@@ -1039,21 +1017,16 @@
 	void *data;
 	int maxlen;
 	umode_t mode;
-	struct ctl_table *child;
-	struct ctl_table *parent;	/* Automatically set */
+	struct ctl_table *child;	/* Deprecated */
 	proc_handler *proc_handler;	/* Callback for text formatting */
 	struct ctl_table_poll *poll;
 	void *extra1;
 	void *extra2;
 };
 
-struct ctl_table_root {
-	struct list_head root_list;
-	struct ctl_table_set default_set;
-	struct ctl_table_set *(*lookup)(struct ctl_table_root *root,
-					   struct nsproxy *namespaces);
-	int (*permissions)(struct ctl_table_root *root,
-			struct nsproxy *namespaces, struct ctl_table *table);
+struct ctl_node {
+	struct rb_node node;
+	struct ctl_table_header *header;
 };
 
 /* struct ctl_table_header is used to maintain dynamic lists of
@@ -1063,9 +1036,9 @@
 	union {
 		struct {
 			struct ctl_table *ctl_table;
-			struct list_head ctl_entry;
 			int used;
 			int count;
+			int nreg;
 		};
 		struct rcu_head rcu;
 	};
@@ -1073,9 +1046,27 @@
 	struct ctl_table *ctl_table_arg;
 	struct ctl_table_root *root;
 	struct ctl_table_set *set;
-	struct ctl_table *attached_by;
-	struct ctl_table *attached_to;
-	struct ctl_table_header *parent;
+	struct ctl_dir *parent;
+	struct ctl_node *node;
+};
+
+struct ctl_dir {
+	/* Header must be at the start of ctl_dir */
+	struct ctl_table_header header;
+	struct rb_root root;
+};
+
+struct ctl_table_set {
+	int (*is_seen)(struct ctl_table_set *);
+	struct ctl_dir dir;
+};
+
+struct ctl_table_root {
+	struct ctl_table_set default_set;
+	struct ctl_table_set *(*lookup)(struct ctl_table_root *root,
+					   struct nsproxy *namespaces);
+	int (*permissions)(struct ctl_table_root *root,
+			struct nsproxy *namespaces, struct ctl_table *table);
 };
 
 /* struct ctl_path describes where in the hierarchy a table is added */
@@ -1083,16 +1074,53 @@
 	const char *procname;
 };
 
+#ifdef CONFIG_SYSCTL
+
+void proc_sys_poll_notify(struct ctl_table_poll *poll);
+
+extern void setup_sysctl_set(struct ctl_table_set *p,
+	struct ctl_table_root *root,
+	int (*is_seen)(struct ctl_table_set *));
+extern void retire_sysctl_set(struct ctl_table_set *set);
+
 void register_sysctl_root(struct ctl_table_root *root);
+struct ctl_table_header *__register_sysctl_table(
+	struct ctl_table_set *set,
+	const char *path, struct ctl_table *table);
 struct ctl_table_header *__register_sysctl_paths(
-	struct ctl_table_root *root, struct nsproxy *namespaces,
+	struct ctl_table_set *set,
 	const struct ctl_path *path, struct ctl_table *table);
+struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table);
 struct ctl_table_header *register_sysctl_table(struct ctl_table * table);
 struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
 						struct ctl_table *table);
 
 void unregister_sysctl_table(struct ctl_table_header * table);
-int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table);
+
+extern int sysctl_init(void);
+#else /* CONFIG_SYSCTL */
+static inline struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
+{
+	return NULL;
+}
+
+static inline struct ctl_table_header *register_sysctl_paths(
+			const struct ctl_path *path, struct ctl_table *table)
+{
+	return NULL;
+}
+
+static inline void unregister_sysctl_table(struct ctl_table_header * table)
+{
+}
+
+static inline void setup_sysctl_set(struct ctl_table_set *p,
+	struct ctl_table_root *root,
+	int (*is_seen)(struct ctl_table_set *))
+{
+}
+
+#endif /* CONFIG_SYSCTL */
 
 #endif /* __KERNEL__ */
 
diff --git a/include/linux/sysinfo.h b/include/linux/sysinfo.h
new file mode 100644
index 0000000..934335a
--- /dev/null
+++ b/include/linux/sysinfo.h
@@ -0,0 +1,24 @@
+#ifndef _LINUX_SYSINFO_H
+#define _LINUX_SYSINFO_H
+
+#include <linux/types.h>
+
+#define SI_LOAD_SHIFT	16
+struct sysinfo {
+	__kernel_long_t uptime;		/* Seconds since boot */
+	__kernel_ulong_t loads[3];	/* 1, 5, and 15 minute load averages */
+	__kernel_ulong_t totalram;	/* Total usable main memory size */
+	__kernel_ulong_t freeram;	/* Available memory size */
+	__kernel_ulong_t sharedram;	/* Amount of shared memory */
+	__kernel_ulong_t bufferram;	/* Memory used by buffers */
+	__kernel_ulong_t totalswap;	/* Total swap space size */
+	__kernel_ulong_t freeswap;	/* swap space still available */
+	__u16 procs;		   	/* Number of current processes */
+	__u16 pad;		   	/* Explicit padding for m68k */
+	__kernel_ulong_t totalhigh;	/* Total high memory size */
+	__kernel_ulong_t freehigh;	/* Available high memory size */
+	__u32 mem_unit;			/* Memory unit size in bytes */
+	char _f[20-2*sizeof(__kernel_ulong_t)-sizeof(__u32)];	/* Padding: libc5 uses this.. */
+};
+
+#endif /* _LINUX_SYSINFO_H */
diff --git a/include/linux/tboot.h b/include/linux/tboot.h
index 1dba6ee..c75128b 100644
--- a/include/linux/tboot.h
+++ b/include/linux/tboot.h
@@ -143,7 +143,6 @@
 
 extern void tboot_probe(void);
 extern void tboot_shutdown(u32 shutdown_type);
-extern void tboot_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control);
 extern struct acpi_table_header *tboot_get_dmar_table(
 				      struct acpi_table_header *dmar_tbl);
 extern int tboot_force_iommu(void);
diff --git a/include/linux/time.h b/include/linux/time.h
index b306178..33a92ea 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -116,7 +116,6 @@
 extern void read_persistent_clock(struct timespec *ts);
 extern void read_boot_clock(struct timespec *ts);
 extern int update_persistent_clock(struct timespec now);
-extern int no_sync_cmos_clock __read_mostly;
 void timekeeping_init(void);
 extern int timekeeping_suspended;
 
@@ -256,6 +255,7 @@
 	a->tv_sec += __iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns);
 	a->tv_nsec = ns;
 }
+
 #endif /* __KERNEL__ */
 
 #define NFDBITS			__NFDBITS
diff --git a/include/linux/timex.h b/include/linux/timex.h
index b75e186..99bc88b 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -252,7 +252,7 @@
 /* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
 extern u64 ntp_tick_length(void);
 
-extern void second_overflow(void);
+extern int second_overflow(unsigned long secs);
 extern int do_adjtimex(struct timex *);
 extern void hardpps(const struct timespec *, const struct timespec *);
 
diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h
index 7dadc3d..a32d86e 100644
--- a/include/linux/trace_seq.h
+++ b/include/linux/trace_seq.h
@@ -44,7 +44,7 @@
 extern int trace_seq_putmem_hex(struct trace_seq *s, const void *mem,
 				size_t len);
 extern void *trace_seq_reserve(struct trace_seq *s, size_t len);
-extern int trace_seq_path(struct trace_seq *s, struct path *path);
+extern int trace_seq_path(struct trace_seq *s, const struct path *path);
 
 #else /* CONFIG_TRACING */
 static inline int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
@@ -88,7 +88,7 @@
 {
 	return NULL;
 }
-static inline int trace_seq_path(struct trace_seq *s, struct path *path)
+static inline int trace_seq_path(struct trace_seq *s, const struct path *path)
 {
 	return 0;
 }
diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
index a71a292..51bd91d 100644
--- a/include/linux/tracehook.h
+++ b/include/linux/tracehook.h
@@ -54,12 +54,12 @@
 /*
  * ptrace report for syscall entry and exit looks identical.
  */
-static inline void ptrace_report_syscall(struct pt_regs *regs)
+static inline int ptrace_report_syscall(struct pt_regs *regs)
 {
 	int ptrace = current->ptrace;
 
 	if (!(ptrace & PT_PTRACED))
-		return;
+		return 0;
 
 	ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
 
@@ -72,6 +72,8 @@
 		send_sig(current->exit_code, current, 1);
 		current->exit_code = 0;
 	}
+
+	return fatal_signal_pending(current);
 }
 
 /**
@@ -96,8 +98,7 @@
 static inline __must_check int tracehook_report_syscall_entry(
 	struct pt_regs *regs)
 {
-	ptrace_report_syscall(regs);
-	return 0;
+	return ptrace_report_syscall(regs);
 }
 
 /**
diff --git a/include/linux/transport_class.h b/include/linux/transport_class.h
index 9ae8da3..11087cd 100644
--- a/include/linux/transport_class.h
+++ b/include/linux/transport_class.h
@@ -10,6 +10,7 @@
 #define _TRANSPORT_CLASS_H_
 
 #include <linux/device.h>
+#include <linux/bug.h>
 #include <linux/attribute_container.h>
 
 struct transport_container;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index a91ff40..9f47ab5 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -44,7 +44,6 @@
 #include <linux/tty_ldisc.h>
 #include <linux/mutex.h>
 
-#include <asm/system.h>
 
 
 /*
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 5e11f8a..c9c9a46 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -235,16 +235,25 @@
 	__u32   denominator;
 };
 
-/*
- *	D R I V E R   C A P A B I L I T I E S
- */
+/**
+  * struct v4l2_capability - Describes V4L2 device caps returned by VIDIOC_QUERYCAP
+  *
+  * @driver:	   name of the driver module (e.g. "bttv")
+  * @card:	   name of the card (e.g. "Hauppauge WinTV")
+  * @bus_info:	   name of the bus (e.g. "PCI:" + pci_name(pci_dev) )
+  * @version:	   KERNEL_VERSION
+  * @capabilities: capabilities of the physical device as a whole
+  * @device_caps:  capabilities accessed via this particular device (node)
+  * @reserved:	   reserved fields for future extensions
+  */
 struct v4l2_capability {
-	__u8	driver[16];	/* i.e. "bttv" */
-	__u8	card[32];	/* i.e. "Hauppauge WinTV" */
-	__u8	bus_info[32];	/* "PCI:" + pci_name(pci_dev) */
-	__u32   version;        /* should use KERNEL_VERSION() */
-	__u32	capabilities;	/* Device capabilities */
-	__u32	reserved[4];
+	__u8	driver[16];
+	__u8	card[32];
+	__u8	bus_info[32];
+	__u32   version;
+	__u32	capabilities;
+	__u32	device_caps;
+	__u32	reserved[3];
 };
 
 /* Values for 'capabilities' field */
@@ -274,6 +283,8 @@
 #define V4L2_CAP_ASYNCIO                0x02000000  /* async I/O */
 #define V4L2_CAP_STREAMING              0x04000000  /* streaming I/O ioctls */
 
+#define V4L2_CAP_DEVICE_CAPS            0x80000000  /* sets device capabilities field */
+
 /*
  *	V I D E O   I M A G E   F O R M A T
  */
@@ -751,20 +762,20 @@
 
 /* Selection targets */
 
-/* current cropping area */
-#define V4L2_SEL_TGT_CROP_ACTIVE	0
-/* default cropping area */
-#define V4L2_SEL_TGT_CROP_DEFAULT	1
-/* cropping bounds */
-#define V4L2_SEL_TGT_CROP_BOUNDS	2
-/* current composing area */
-#define V4L2_SEL_TGT_COMPOSE_ACTIVE	256
-/* default composing area */
-#define V4L2_SEL_TGT_COMPOSE_DEFAULT	257
-/* composing bounds */
-#define V4L2_SEL_TGT_COMPOSE_BOUNDS	258
-/* current composing area plus all padding pixels */
-#define V4L2_SEL_TGT_COMPOSE_PADDED	259
+/* Current cropping area */
+#define V4L2_SEL_TGT_CROP_ACTIVE	0x0000
+/* Default cropping area */
+#define V4L2_SEL_TGT_CROP_DEFAULT	0x0001
+/* Cropping bounds */
+#define V4L2_SEL_TGT_CROP_BOUNDS	0x0002
+/* Current composing area */
+#define V4L2_SEL_TGT_COMPOSE_ACTIVE	0x0100
+/* Default composing area */
+#define V4L2_SEL_TGT_COMPOSE_DEFAULT	0x0101
+/* Composing bounds */
+#define V4L2_SEL_TGT_COMPOSE_BOUNDS	0x0102
+/* Current composing area plus all padding pixels */
+#define V4L2_SEL_TGT_COMPOSE_PADDED	0x0103
 
 /**
  * struct v4l2_selection - selection info
@@ -774,7 +785,7 @@
  * @r:		coordinates of selection window
  * @reserved:	for future use, rounds structure size to 64 bytes, set to zero
  *
- * Hardware may use multiple helper window to process a video stream.
+ * Hardware may use multiple helper windows to process a video stream.
  * The structure is used to exchange this selection areas between
  * an application and a driver.
  */
@@ -1125,6 +1136,7 @@
 #define V4L2_CTRL_CLASS_CAMERA 0x009a0000	/* Camera class controls */
 #define V4L2_CTRL_CLASS_FM_TX 0x009b0000	/* FM Modulator control class */
 #define V4L2_CTRL_CLASS_FLASH 0x009c0000	/* Camera flash controls */
+#define V4L2_CTRL_CLASS_JPEG 0x009d0000		/* JPEG-compression controls */
 
 #define V4L2_CTRL_ID_MASK      	  (0x0fffffff)
 #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
@@ -1396,6 +1408,16 @@
 	V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17,
 	V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18,
 };
+#define V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK	(V4L2_CID_MPEG_BASE+112)
+enum v4l2_mpeg_audio_dec_playback {
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO	    = 0,
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO	    = 1,
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT	    = 2,
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_RIGHT	    = 3,
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_MONO	    = 4,
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO = 5,
+};
+#define V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK (V4L2_CID_MPEG_BASE+113)
 
 /*  MPEG video controls specific to multiplexed streams */
 #define V4L2_CID_MPEG_VIDEO_ENCODING 		(V4L2_CID_MPEG_BASE+200)
@@ -1446,6 +1468,9 @@
 	V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES	= 2,
 };
 #define V4L2_CID_MPEG_VIDEO_VBV_SIZE			(V4L2_CID_MPEG_BASE+222)
+#define V4L2_CID_MPEG_VIDEO_DEC_PTS			(V4L2_CID_MPEG_BASE+223)
+#define V4L2_CID_MPEG_VIDEO_DEC_FRAME			(V4L2_CID_MPEG_BASE+224)
+
 #define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP		(V4L2_CID_MPEG_BASE+300)
 #define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP		(V4L2_CID_MPEG_BASE+301)
 #define V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP		(V4L2_CID_MPEG_BASE+302)
@@ -1734,6 +1759,29 @@
 #define V4L2_CID_FLASH_CHARGE			(V4L2_CID_FLASH_CLASS_BASE + 11)
 #define V4L2_CID_FLASH_READY			(V4L2_CID_FLASH_CLASS_BASE + 12)
 
+/*  JPEG-class control IDs defined by V4L2 */
+#define V4L2_CID_JPEG_CLASS_BASE		(V4L2_CTRL_CLASS_JPEG | 0x900)
+#define V4L2_CID_JPEG_CLASS			(V4L2_CTRL_CLASS_JPEG | 1)
+
+#define	V4L2_CID_JPEG_CHROMA_SUBSAMPLING	(V4L2_CID_JPEG_CLASS_BASE + 1)
+enum v4l2_jpeg_chroma_subsampling {
+	V4L2_JPEG_CHROMA_SUBSAMPLING_444	= 0,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_422	= 1,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_420	= 2,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_411	= 3,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_410	= 4,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY	= 5,
+};
+#define	V4L2_CID_JPEG_RESTART_INTERVAL		(V4L2_CID_JPEG_CLASS_BASE + 2)
+#define	V4L2_CID_JPEG_COMPRESSION_QUALITY	(V4L2_CID_JPEG_CLASS_BASE + 3)
+
+#define	V4L2_CID_JPEG_ACTIVE_MARKER		(V4L2_CID_JPEG_CLASS_BASE + 4)
+#define	V4L2_JPEG_ACTIVE_MARKER_APP0		(1 << 0)
+#define	V4L2_JPEG_ACTIVE_MARKER_APP1		(1 << 1)
+#define	V4L2_JPEG_ACTIVE_MARKER_COM		(1 << 16)
+#define	V4L2_JPEG_ACTIVE_MARKER_DQT		(1 << 17)
+#define	V4L2_JPEG_ACTIVE_MARKER_DHT		(1 << 18)
+
 /*
  *	T U N I N G
  */
@@ -1897,6 +1945,54 @@
 	};
 };
 
+/* Decoder commands */
+#define V4L2_DEC_CMD_START       (0)
+#define V4L2_DEC_CMD_STOP        (1)
+#define V4L2_DEC_CMD_PAUSE       (2)
+#define V4L2_DEC_CMD_RESUME      (3)
+
+/* Flags for V4L2_DEC_CMD_START */
+#define V4L2_DEC_CMD_START_MUTE_AUDIO	(1 << 0)
+
+/* Flags for V4L2_DEC_CMD_PAUSE */
+#define V4L2_DEC_CMD_PAUSE_TO_BLACK	(1 << 0)
+
+/* Flags for V4L2_DEC_CMD_STOP */
+#define V4L2_DEC_CMD_STOP_TO_BLACK	(1 << 0)
+#define V4L2_DEC_CMD_STOP_IMMEDIATELY	(1 << 1)
+
+/* Play format requirements (returned by the driver): */
+
+/* The decoder has no special format requirements */
+#define V4L2_DEC_START_FMT_NONE		(0)
+/* The decoder requires full GOPs */
+#define V4L2_DEC_START_FMT_GOP		(1)
+
+/* The structure must be zeroed before use by the application
+   This ensures it can be extended safely in the future. */
+struct v4l2_decoder_cmd {
+	__u32 cmd;
+	__u32 flags;
+	union {
+		struct {
+			__u64 pts;
+		} stop;
+
+		struct {
+			/* 0 or 1000 specifies normal speed,
+			   1 specifies forward single stepping,
+			   -1 specifies backward single stepping,
+			   >1: playback at speed/1000 of the normal speed,
+			   <-1: reverse playback at (-speed/1000) of the normal speed. */
+			__s32 speed;
+			__u32 format;
+		} start;
+
+		struct {
+			__u32 data[16];
+		} raw;
+	};
+};
 #endif
 
 
@@ -2307,6 +2403,11 @@
 #define VIDIOC_G_SELECTION	_IOWR('V', 94, struct v4l2_selection)
 #define VIDIOC_S_SELECTION	_IOWR('V', 95, struct v4l2_selection)
 
+/* Experimental, these two ioctls may change over the next couple of kernel
+   versions. */
+#define VIDIOC_DECODER_CMD	_IOWR('V', 96, struct v4l2_decoder_cmd)
+#define VIDIOC_TRY_DECODER_CMD	_IOWR('V', 97, struct v4l2_decoder_cmd)
+
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
 
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index d0018d2..8efd28a 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -96,7 +96,6 @@
 	void (*config_changed)(struct virtio_device *dev);
 #ifdef CONFIG_PM
 	int (*freeze)(struct virtio_device *dev);
-	int (*thaw)(struct virtio_device *dev);
 	int (*restore)(struct virtio_device *dev);
 #endif
 };
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index 5206d65..7323a33 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -53,6 +53,7 @@
 
 #ifdef __KERNEL__
 #include <linux/err.h>
+#include <linux/bug.h>
 #include <linux/virtio.h>
 
 /**
diff --git a/include/linux/virtio_ids.h b/include/linux/virtio_ids.h
index 85bb0bb..7529b85 100644
--- a/include/linux/virtio_ids.h
+++ b/include/linux/virtio_ids.h
@@ -34,6 +34,8 @@
 #define VIRTIO_ID_CONSOLE	3 /* virtio console */
 #define VIRTIO_ID_RNG		4 /* virtio ring */
 #define VIRTIO_ID_BALLOON	5 /* virtio balloon */
+#define VIRTIO_ID_RPMSG		7 /* virtio remote processor messaging */
+#define VIRTIO_ID_SCSI		8 /* virtio scsi */
 #define VIRTIO_ID_9P		9 /* 9p virtio console */
 
 #endif /* _LINUX_VIRTIO_IDS_H */
diff --git a/include/linux/virtio_scsi.h b/include/linux/virtio_scsi.h
new file mode 100644
index 0000000..8ddeafd
--- /dev/null
+++ b/include/linux/virtio_scsi.h
@@ -0,0 +1,114 @@
+#ifndef _LINUX_VIRTIO_SCSI_H
+#define _LINUX_VIRTIO_SCSI_H
+/* This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers. */
+
+#define VIRTIO_SCSI_CDB_SIZE   32
+#define VIRTIO_SCSI_SENSE_SIZE 96
+
+/* SCSI command request, followed by data-out */
+struct virtio_scsi_cmd_req {
+	u8 lun[8];		/* Logical Unit Number */
+	u64 tag;		/* Command identifier */
+	u8 task_attr;		/* Task attribute */
+	u8 prio;
+	u8 crn;
+	u8 cdb[VIRTIO_SCSI_CDB_SIZE];
+} __packed;
+
+/* Response, followed by sense data and data-in */
+struct virtio_scsi_cmd_resp {
+	u32 sense_len;		/* Sense data length */
+	u32 resid;		/* Residual bytes in data buffer */
+	u16 status_qualifier;	/* Status qualifier */
+	u8 status;		/* Command completion status */
+	u8 response;		/* Response values */
+	u8 sense[VIRTIO_SCSI_SENSE_SIZE];
+} __packed;
+
+/* Task Management Request */
+struct virtio_scsi_ctrl_tmf_req {
+	u32 type;
+	u32 subtype;
+	u8 lun[8];
+	u64 tag;
+} __packed;
+
+struct virtio_scsi_ctrl_tmf_resp {
+	u8 response;
+} __packed;
+
+/* Asynchronous notification query/subscription */
+struct virtio_scsi_ctrl_an_req {
+	u32 type;
+	u8 lun[8];
+	u32 event_requested;
+} __packed;
+
+struct virtio_scsi_ctrl_an_resp {
+	u32 event_actual;
+	u8 response;
+} __packed;
+
+struct virtio_scsi_event {
+	u32 event;
+	u8 lun[8];
+	u32 reason;
+} __packed;
+
+struct virtio_scsi_config {
+	u32 num_queues;
+	u32 seg_max;
+	u32 max_sectors;
+	u32 cmd_per_lun;
+	u32 event_info_size;
+	u32 sense_size;
+	u32 cdb_size;
+	u16 max_channel;
+	u16 max_target;
+	u32 max_lun;
+} __packed;
+
+/* Response codes */
+#define VIRTIO_SCSI_S_OK                       0
+#define VIRTIO_SCSI_S_OVERRUN                  1
+#define VIRTIO_SCSI_S_ABORTED                  2
+#define VIRTIO_SCSI_S_BAD_TARGET               3
+#define VIRTIO_SCSI_S_RESET                    4
+#define VIRTIO_SCSI_S_BUSY                     5
+#define VIRTIO_SCSI_S_TRANSPORT_FAILURE        6
+#define VIRTIO_SCSI_S_TARGET_FAILURE           7
+#define VIRTIO_SCSI_S_NEXUS_FAILURE            8
+#define VIRTIO_SCSI_S_FAILURE                  9
+#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED       10
+#define VIRTIO_SCSI_S_FUNCTION_REJECTED        11
+#define VIRTIO_SCSI_S_INCORRECT_LUN            12
+
+/* Controlq type codes.  */
+#define VIRTIO_SCSI_T_TMF                      0
+#define VIRTIO_SCSI_T_AN_QUERY                 1
+#define VIRTIO_SCSI_T_AN_SUBSCRIBE             2
+
+/* Valid TMF subtypes.  */
+#define VIRTIO_SCSI_T_TMF_ABORT_TASK           0
+#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET       1
+#define VIRTIO_SCSI_T_TMF_CLEAR_ACA            2
+#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET       3
+#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET      4
+#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET   5
+#define VIRTIO_SCSI_T_TMF_QUERY_TASK           6
+#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET       7
+
+/* Events.  */
+#define VIRTIO_SCSI_T_EVENTS_MISSED            0x80000000
+#define VIRTIO_SCSI_T_NO_EVENT                 0
+#define VIRTIO_SCSI_T_TRANSPORT_RESET          1
+#define VIRTIO_SCSI_T_ASYNC_NOTIFY             2
+
+#define VIRTIO_SCSI_S_SIMPLE                   0
+#define VIRTIO_SCSI_S_ORDERED                  1
+#define VIRTIO_SCSI_S_HEAD                     2
+#define VIRTIO_SCSI_S_ACA                      3
+
+
+#endif /* _LINUX_VIRTIO_SCSI_H */
diff --git a/include/linux/wait.h b/include/linux/wait.h
index 7d9a9e9..1dee81c 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -22,7 +22,6 @@
 #include <linux/list.h>
 #include <linux/stddef.h>
 #include <linux/spinlock.h>
-#include <asm/system.h>
 #include <asm/current.h>
 
 typedef struct __wait_queue wait_queue_t;
diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h
index 43ba5b3c..ac40716 100644
--- a/include/linux/watchdog.h
+++ b/include/linux/watchdog.h
@@ -66,6 +66,7 @@
  * @ping:	The routine that sends a keepalive ping to the watchdog device.
  * @status:	The routine that shows the status of the watchdog device.
  * @set_timeout:The routine for setting the watchdog devices timeout value.
+ * @get_timeleft:The routine that get's the time that's left before a reset.
  * @ioctl:	The routines that handles extra ioctl calls.
  *
  * The watchdog_ops structure contains a list of low-level operations
@@ -82,6 +83,7 @@
 	int (*ping)(struct watchdog_device *);
 	unsigned int (*status)(struct watchdog_device *);
 	int (*set_timeout)(struct watchdog_device *, unsigned int);
+	unsigned int (*get_timeleft)(struct watchdog_device *);
 	long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
 };
 
@@ -127,7 +129,7 @@
 #endif
 
 /* Use the following function to set the nowayout feature */
-static inline void watchdog_set_nowayout(struct watchdog_device *wdd, int nowayout)
+static inline void watchdog_set_nowayout(struct watchdog_device *wdd, bool nowayout)
 {
 	if (nowayout)
 		set_bit(WDOG_NO_WAY_OUT, &wdd->status);
diff --git a/include/linux/wimax/debug.h b/include/linux/wimax/debug.h
index 57031b4..aaf24ba 100644
--- a/include/linux/wimax/debug.h
+++ b/include/linux/wimax/debug.h
@@ -154,9 +154,9 @@
 #define __debug__h__
 
 #include <linux/types.h>
-#include <linux/device.h>
 #include <linux/slab.h>
 
+struct device;
 
 /* Backend stuff */
 
diff --git a/include/media/adv7183.h b/include/media/adv7183.h
new file mode 100644
index 0000000..c5c2d37
--- /dev/null
+++ b/include/media/adv7183.h
@@ -0,0 +1,47 @@
+/*
+ * adv7183.h - definition for adv7183 inputs and outputs
+ *
+ * Copyright (c) 2011 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _ADV7183_H_
+#define _ADV7183_H_
+
+/* ADV7183 HW inputs */
+#define ADV7183_COMPOSITE0  0  /* CVBS in on AIN1 */
+#define ADV7183_COMPOSITE1  1  /* CVBS in on AIN2 */
+#define ADV7183_COMPOSITE2  2  /* CVBS in on AIN3 */
+#define ADV7183_COMPOSITE3  3  /* CVBS in on AIN4 */
+#define ADV7183_COMPOSITE4  4  /* CVBS in on AIN5 */
+#define ADV7183_COMPOSITE5  5  /* CVBS in on AIN6 */
+#define ADV7183_COMPOSITE6  6  /* CVBS in on AIN7 */
+#define ADV7183_COMPOSITE7  7  /* CVBS in on AIN8 */
+#define ADV7183_COMPOSITE8  8  /* CVBS in on AIN9 */
+#define ADV7183_COMPOSITE9  9  /* CVBS in on AIN10 */
+#define ADV7183_COMPOSITE10 10 /* CVBS in on AIN11 */
+
+#define ADV7183_SVIDEO0     11 /* Y on AIN1, C on AIN4 */
+#define ADV7183_SVIDEO1     12 /* Y on AIN2, C on AIN5 */
+#define ADV7183_SVIDEO2     13 /* Y on AIN3, C on AIN6 */
+
+#define ADV7183_COMPONENT0  14 /* Y on AIN1, Pr on AIN4, Pb on AIN5 */
+#define ADV7183_COMPONENT1  15 /* Y on AIN2, Pr on AIN3, Pb on AIN6 */
+
+/* ADV7183 HW outputs */
+#define ADV7183_8BIT_OUT    0
+#define ADV7183_16BIT_OUT   1
+
+#endif
diff --git a/include/media/blackfin/bfin_capture.h b/include/media/blackfin/bfin_capture.h
new file mode 100644
index 0000000..2038a8a
--- /dev/null
+++ b/include/media/blackfin/bfin_capture.h
@@ -0,0 +1,37 @@
+#ifndef _BFIN_CAPTURE_H_
+#define _BFIN_CAPTURE_H_
+
+#include <linux/i2c.h>
+
+struct v4l2_input;
+struct ppi_info;
+
+struct bcap_route {
+	u32 input;
+	u32 output;
+};
+
+struct bfin_capture_config {
+	/* card name */
+	char *card_name;
+	/* inputs available at the sub device */
+	struct v4l2_input *inputs;
+	/* number of inputs supported */
+	int num_inputs;
+	/* routing information for each input */
+	struct bcap_route *routes;
+	/* i2c bus adapter no */
+	int i2c_adapter_id;
+	/* i2c subdevice board info */
+	struct i2c_board_info board_info;
+	/* ppi board info */
+	const struct ppi_info *ppi_info;
+	/* ppi control */
+	unsigned long ppi_control;
+	/* ppi interrupt mask */
+	u32 int_mask;
+	/* horizontal blanking clocks */
+	int blank_clocks;
+};
+
+#endif
diff --git a/include/media/blackfin/ppi.h b/include/media/blackfin/ppi.h
new file mode 100644
index 0000000..8f72f8a
--- /dev/null
+++ b/include/media/blackfin/ppi.h
@@ -0,0 +1,74 @@
+/*
+ * Analog Devices PPI header file
+ *
+ * Copyright (c) 2011 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _PPI_H_
+#define _PPI_H_
+
+#include <linux/interrupt.h>
+
+#ifdef EPPI_EN
+#define PORT_EN EPPI_EN
+#define DMA32 0
+#define PACK_EN PACKEN
+#endif
+
+struct ppi_if;
+
+struct ppi_params {
+	int width;
+	int height;
+	int bpp;
+	unsigned long ppi_control;
+	u32 int_mask;
+	int blank_clocks;
+};
+
+struct ppi_ops {
+	int (*attach_irq)(struct ppi_if *ppi, irq_handler_t handler);
+	void (*detach_irq)(struct ppi_if *ppi);
+	int (*start)(struct ppi_if *ppi);
+	int (*stop)(struct ppi_if *ppi);
+	int (*set_params)(struct ppi_if *ppi, struct ppi_params *params);
+	void (*update_addr)(struct ppi_if *ppi, unsigned long addr);
+};
+
+enum ppi_type {
+	PPI_TYPE_PPI,
+	PPI_TYPE_EPPI,
+};
+
+struct ppi_info {
+	enum ppi_type type;
+	int dma_ch;
+	int irq_err;
+	void __iomem *base;
+	const unsigned short *pin_req;
+};
+
+struct ppi_if {
+	unsigned long ppi_control;
+	const struct ppi_ops *ops;
+	const struct ppi_info *info;
+	bool err_int;
+	void *priv;
+};
+
+struct ppi_if *ppi_create_instance(const struct ppi_info *info);
+void ppi_delete_instance(struct ppi_if *ppi);
+#endif
diff --git a/include/media/davinci/vpif_types.h b/include/media/davinci/vpif_types.h
index 9929b05..bd8217c 100644
--- a/include/media/davinci/vpif_types.h
+++ b/include/media/davinci/vpif_types.h
@@ -17,6 +17,8 @@
 #ifndef _VPIF_TYPES_H
 #define _VPIF_TYPES_H
 
+#include <linux/i2c.h>
+
 #define VPIF_CAPTURE_MAX_CHANNELS	2
 
 enum vpif_if_type {
diff --git a/include/media/gpio-ir-recv.h b/include/media/gpio-ir-recv.h
new file mode 100644
index 0000000..67797bf
--- /dev/null
+++ b/include/media/gpio-ir-recv.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ */
+
+#ifndef __GPIO_IR_RECV_H__
+#define __GPIO_IR_RECV_H__
+
+struct gpio_ir_recv_platform_data {
+	int gpio_nr;
+	bool active_low;
+};
+
+#endif /* __GPIO_IR_RECV_H__ */
+
diff --git a/include/media/media-device.h b/include/media/media-device.h
index 6a27d91..eaade98 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -23,7 +23,6 @@
 #ifndef _MEDIA_DEVICE_H
 #define _MEDIA_DEVICE_H
 
-#include <linux/device.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
@@ -31,6 +30,8 @@
 #include <media/media-devnode.h>
 #include <media/media-entity.h>
 
+struct device;
+
 /**
  * struct media_device - Media device
  * @dev:	Parent device
diff --git a/include/media/mt9m032.h b/include/media/mt9m032.h
new file mode 100644
index 0000000..c3a7811
--- /dev/null
+++ b/include/media/mt9m032.h
@@ -0,0 +1,36 @@
+/*
+ * Driver for MT9M032 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2010-2011 Lund Engineering
+ * Contact: Gil Lund <gwlund@lundeng.com>
+ * Author: Martin Hostettler <martin@neutronstar.dyndns.org>
+ *
+ * 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 MT9M032_H
+#define MT9M032_H
+
+#define MT9M032_NAME		"mt9m032"
+#define MT9M032_I2C_ADDR	(0xb8 >> 1)
+
+struct mt9m032_platform_data {
+	u32 ext_clock;
+	u32 pix_clock;
+	bool invert_pixclock;
+
+};
+#endif /* MT9M032_H */
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index f688bde..8db6741 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -102,8 +102,11 @@
 #define RC_MAP_IMON_MCE                  "rc-imon-mce"
 #define RC_MAP_IMON_PAD                  "rc-imon-pad"
 #define RC_MAP_IODATA_BCTV7E             "rc-iodata-bctv7e"
+#define RC_MAP_IT913X_V1                 "rc-it913x-v1"
+#define RC_MAP_IT913X_V2                 "rc-it913x-v2"
 #define RC_MAP_KAIOMY                    "rc-kaiomy"
 #define RC_MAP_KWORLD_315U               "rc-kworld-315u"
+#define RC_MAP_KWORLD_PC150U             "rc-kworld-pc150u"
 #define RC_MAP_KWORLD_PLUS_TV_ANALOG     "rc-kworld-plus-tv-analog"
 #define RC_MAP_LEADTEK_Y04G0051          "rc-leadtek-y04g0051"
 #define RC_MAP_LIRC                      "rc-lirc"
diff --git a/include/media/s5p_hdmi.h b/include/media/s5p_hdmi.h
new file mode 100644
index 0000000..361a751
--- /dev/null
+++ b/include/media/s5p_hdmi.h
@@ -0,0 +1,35 @@
+/*
+ * Driver header for S5P HDMI chip.
+ *
+ * Copyright (c) 2011 Samsung Electronics, Co. Ltd
+ * Contact: Tomasz Stanislawski <t.stanislaws@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 S5P_HDMI_H
+#define S5P_HDMI_H
+
+struct i2c_board_info;
+
+/**
+ * @hdmiphy_bus: controller id for HDMIPHY bus
+ * @hdmiphy_info: template for HDMIPHY I2C device
+ * @mhl_bus: controller id for MHL control bus
+ * @mhl_info: template for MHL I2C device
+ *
+ * NULL pointer for *_info fields indicates that
+ * the corresponding chip is not present
+ */
+struct s5p_hdmi_platform_data {
+	int hdmiphy_bus;
+	struct i2c_board_info *hdmiphy_info;
+	int mhl_bus;
+	struct i2c_board_info *mhl_info;
+};
+
+#endif /* S5P_HDMI_H */
+
diff --git a/include/media/sh_mobile_ceu.h b/include/media/sh_mobile_ceu.h
index 48413b4..a90a765 100644
--- a/include/media/sh_mobile_ceu.h
+++ b/include/media/sh_mobile_ceu.h
@@ -18,6 +18,8 @@
 
 struct sh_mobile_ceu_info {
 	unsigned long flags;
+	int max_width;
+	int max_height;
 	struct sh_mobile_ceu_companion *csi2;
 };
 
diff --git a/include/media/sii9234.h b/include/media/sii9234.h
new file mode 100644
index 0000000..6a4a809
--- /dev/null
+++ b/include/media/sii9234.h
@@ -0,0 +1,24 @@
+/*
+ * Driver header for SII9234 MHL converter chip.
+ *
+ * Copyright (c) 2011 Samsung Electronics, Co. Ltd
+ * Contact: Tomasz Stanislawski <t.stanislaws@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 SII9234_H
+#define SII9234_H
+
+/**
+ * @gpio_n_reset: GPIO driving nRESET pin
+ */
+
+struct sii9234_platform_data {
+	int gpio_n_reset;
+};
+
+#endif /* SII9234_H */
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 29e1920..926aff9 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -136,6 +136,7 @@
 #define TUNER_TENA_TNF_5337		86
 
 #define TUNER_XC4000			87	/* Xceive Silicon Tuner */
+#define TUNER_XC5000C			88	/* Xceive Silicon Tuner */
 
 /* tv card specific */
 #define TDA9887_PRESENT 		(1<<0)
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
index 810a209..7395c81 100644
--- a/include/media/v4l2-chip-ident.h
+++ b/include/media/v4l2-chip-ident.h
@@ -143,6 +143,9 @@
 	/* module saa6588: just ident 6588 */
 	V4L2_IDENT_SAA6588 = 6588,
 
+	/* module vs6624: just ident 6624 */
+	V4L2_IDENT_VS6624 = 6624,
+
 	/* module saa6752hs: reserved range 6750-6759 */
 	V4L2_IDENT_SAA6752HS = 6752,
 	V4L2_IDENT_SAA6752HS_AC3 = 6753,
@@ -162,6 +165,9 @@
 	/* module adv7180: just ident 7180 */
 	V4L2_IDENT_ADV7180 = 7180,
 
+	/* module adv7183: just ident 7183 */
+	V4L2_IDENT_ADV7183 = 7183,
+
 	/* module saa7185: just ident 7185 */
 	V4L2_IDENT_SAA7185 = 7185,
 
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index eeb3df6..11e6756 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -22,7 +22,6 @@
 #define _V4L2_CTRLS_H
 
 #include <linux/list.h>
-#include <linux/device.h>
 #include <linux/videodev2.h>
 
 /* forward references */
@@ -33,6 +32,7 @@
 struct v4l2_subdev;
 struct v4l2_subscribed_event;
 struct v4l2_fh;
+struct poll_table_struct;
 
 /** struct v4l2_ctrl_ops - The control operations that the driver has to provide.
   * @g_volatile_ctrl: Get a new value for this control. Generally only relevant
@@ -492,6 +492,18 @@
 void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl,
 		struct v4l2_subscribed_event *sev);
 
+/* Can be used as a vidioc_log_status function that just dumps all controls
+   associated with the filehandle. */
+int v4l2_ctrl_log_status(struct file *file, void *fh);
+
+/* Can be used as a vidioc_subscribe_event function that just subscribes
+   control events. */
+int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
+				struct v4l2_event_subscription *sub);
+
+/* Can be used as a poll function that just polls for control events. */
+unsigned int v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait);
+
 /* Helpers for ioctl_ops. If hdl == NULL then they will all return -EINVAL. */
 int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc);
 int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm);
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index c7c40f1..96d2221 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -62,6 +62,9 @@
 	unsigned int (*poll) (struct file *, struct poll_table_struct *);
 	long (*ioctl) (struct file *, unsigned int, unsigned long);
 	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
+#ifdef CONFIG_COMPAT
+	long (*compat_ioctl32) (struct file *, unsigned int, unsigned long);
+#endif
 	unsigned long (*get_unmapped_area) (struct file *, unsigned long,
 				unsigned long, unsigned long, unsigned long);
 	int (*mmap) (struct file *, struct vm_area_struct *);
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 3f5d60f..3cb939c 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -11,7 +11,6 @@
 
 #include <linux/poll.h>
 #include <linux/fs.h>
-#include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/compiler.h> /* need __user */
 #include <linux/videodev2.h>
@@ -211,6 +210,10 @@
 					struct v4l2_encoder_cmd *a);
 	int (*vidioc_try_encoder_cmd)  (struct file *file, void *fh,
 					struct v4l2_encoder_cmd *a);
+	int (*vidioc_decoder_cmd)      (struct file *file, void *fh,
+					struct v4l2_decoder_cmd *a);
+	int (*vidioc_try_decoder_cmd)  (struct file *file, void *fh,
+					struct v4l2_decoder_cmd *a);
 
 	/* Stream type-dependent parameter ioctls */
 	int (*vidioc_g_parm)           (struct file *file, void *fh,
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 5a4e29b..ca68e2c 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -49,8 +49,7 @@
 	/* WARNING: sk has to be the first member */
 	struct sock		sk;
 	struct unix_address     *addr;
-	struct dentry		*dentry;
-	struct vfsmount		*mnt;
+	struct path		path;
 	struct mutex		readlock;
 	struct sock		*peer;
 	struct sock		*other;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 5ccac72..83d800c 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -13,6 +13,7 @@
 #include <linux/netdevice.h>
 #include <linux/debugfs.h>
 #include <linux/list.h>
+#include <linux/bug.h>
 #include <linux/netlink.h>
 #include <linux/skbuff.h>
 #include <linux/nl80211.h>
diff --git a/include/net/dst.h b/include/net/dst.h
index 344c8dd..59c5d18 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -12,6 +12,7 @@
 #include <linux/netdevice.h>
 #include <linux/rtnetlink.h>
 #include <linux/rcupdate.h>
+#include <linux/bug.h>
 #include <linux/jiffies.h>
 #include <net/neighbour.h>
 #include <asm/processor.h>
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index ebe517f..2bdee51 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -16,6 +16,7 @@
 #include <linux/atomic.h>                 /* for struct atomic_t */
 #include <linux/compiler.h>
 #include <linux/timer.h>
+#include <linux/bug.h>
 
 #include <net/checksum.h>
 #include <linux/netfilter.h>		/* for union nf_inet_addr */
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 9a012be6..87d203f 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -13,10 +13,10 @@
 #ifndef MAC80211_H
 #define MAC80211_H
 
+#include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/if_ether.h>
 #include <linux/skbuff.h>
-#include <linux/device.h>
 #include <linux/ieee80211.h>
 #include <net/cfg80211.h>
 #include <asm/unaligned.h>
@@ -87,6 +87,8 @@
  *
  */
 
+struct device;
+
 /**
  * enum ieee80211_max_queues - maximum number of queues
  *
diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h
index 90c67c7..3b572bb 100644
--- a/include/net/netfilter/nf_conntrack_l4proto.h
+++ b/include/net/netfilter/nf_conntrack_l4proto.h
@@ -118,6 +118,10 @@
 extern struct nf_conntrack_l4proto *
 __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto);
 
+extern struct nf_conntrack_l4proto *
+nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto);
+extern void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p);
+
 /* Protocol registration. */
 extern int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *proto);
 extern void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *proto);
diff --git a/include/net/netfilter/nf_conntrack_timeout.h b/include/net/netfilter/nf_conntrack_timeout.h
index 0e04db4..34ec89f 100644
--- a/include/net/netfilter/nf_conntrack_timeout.h
+++ b/include/net/netfilter/nf_conntrack_timeout.h
@@ -15,7 +15,7 @@
 	atomic_t		refcnt;
 	char			name[CTNL_TIMEOUT_NAME_MAX];
 	__u16			l3num;
-	__u8			l4num;
+	struct nf_conntrack_l4proto *l4proto;
 	char			data[0];
 };
 
diff --git a/include/net/netfilter/xt_log.h b/include/net/netfilter/xt_log.h
index 7e1544e..9d9756c 100644
--- a/include/net/netfilter/xt_log.h
+++ b/include/net/netfilter/xt_log.h
@@ -47,7 +47,7 @@
 	if (likely(m != &emergency))
 		kfree(m);
 	else {
-		xchg(&emergency_ptr, m);
+		emergency_ptr = m;
 		local_bh_enable();
 	}
 }
diff --git a/include/net/netns/generic.h b/include/net/netns/generic.h
index d55f434..0931618 100644
--- a/include/net/netns/generic.h
+++ b/include/net/netns/generic.h
@@ -5,6 +5,7 @@
 #ifndef __NET_GENERIC_H__
 #define __NET_GENERIC_H__
 
+#include <linux/bug.h>
 #include <linux/rcupdate.h>
 
 /*
diff --git a/include/net/red.h b/include/net/red.h
index 28068ec..77d4c37 100644
--- a/include/net/red.h
+++ b/include/net/red.h
@@ -2,6 +2,7 @@
 #define __NET_SCHED_RED_H
 
 #include <linux/types.h>
+#include <linux/bug.h>
 #include <net/pkt_sched.h>
 #include <net/inet_ecn.h>
 #include <net/dsfield.h>
diff --git a/include/net/sock.h b/include/net/sock.h
index 04bc0b3..a6ba1f8 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1854,7 +1854,7 @@
 static inline void sock_poll_wait(struct file *filp,
 		wait_queue_head_t *wait_address, poll_table *p)
 {
-	if (p && wait_address) {
+	if (!poll_does_not_wait(p) && wait_address) {
 		poll_wait(filp, wait_address, p);
 		/*
 		 * We need to be sure we are in sync with the
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 8607e6a..f75a04d 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -22,6 +22,7 @@
 
 #include <linux/list.h>
 #include <linux/tcp.h>
+#include <linux/bug.h>
 #include <linux/slab.h>
 #include <linux/cache.h>
 #include <linux/percpu.h>
diff --git a/include/net/timewait_sock.h b/include/net/timewait_sock.h
index 053b3cf..8d6689c 100644
--- a/include/net/timewait_sock.h
+++ b/include/net/timewait_sock.h
@@ -12,6 +12,7 @@
 #define _TIMEWAIT_SOCK_H
 
 #include <linux/slab.h>
+#include <linux/bug.h>
 #include <net/sock.h>
 
 struct timewait_sock_ops {
diff --git a/include/net/udp.h b/include/net/udp.h
index e39592f..5d606d9 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -23,6 +23,7 @@
 #define _UDP_H
 
 #include <linux/list.h>
+#include <linux/bug.h>
 #include <net/inet_sock.h>
 #include <net/sock.h>
 #include <net/snmp.h>
diff --git a/include/net/wpan-phy.h b/include/net/wpan-phy.h
index d86fffd..ff27f1b 100644
--- a/include/net/wpan-phy.h
+++ b/include/net/wpan-phy.h
@@ -23,6 +23,7 @@
 
 #include <linux/netdevice.h>
 #include <linux/mutex.h>
+#include <linux/bug.h>
 
 struct wpan_phy {
 	struct mutex pib_lock;
diff --git a/include/scsi/fc/fc_fcp.h b/include/scsi/fc/fc_fcp.h
index 652dec2..0d7d67e 100644
--- a/include/scsi/fc/fc_fcp.h
+++ b/include/scsi/fc/fc_fcp.h
@@ -20,6 +20,8 @@
 #ifndef _FC_FCP_H_
 #define	_FC_FCP_H_
 
+#include <scsi/scsi.h>
+
 /*
  * Fibre Channel Protocol for SCSI.
  * From T10 FCP-3, T10 project 1560-D Rev 4, Sept. 13, 2005.
@@ -45,7 +47,7 @@
  * FCP_CMND IU Payload.
  */
 struct fcp_cmnd {
-	__u8		fc_lun[8];	/* logical unit number */
+	struct scsi_lun	fc_lun;		/* logical unit number */
 	__u8		fc_cmdref;	/* command reference number */
 	__u8		fc_pri_ta;	/* priority and task attribute */
 	__u8		fc_tm_flags;	/* task management flags */
@@ -57,7 +59,7 @@
 #define	FCP_CMND_LEN	32	/* expected length of structure */
 
 struct fcp_cmnd32 {
-	__u8		fc_lun[8];	/* logical unit number */
+	struct scsi_lun	fc_lun;		/* logical unit number */
 	__u8		fc_cmdref;	/* command reference number */
 	__u8		fc_pri_ta;	/* priority and task attribute */
 	__u8		fc_tm_flags;	/* task management flags */
diff --git a/include/scsi/fc/fc_ms.h b/include/scsi/fc/fc_ms.h
new file mode 100644
index 0000000..f52b921
--- /dev/null
+++ b/include/scsi/fc/fc_ms.h
@@ -0,0 +1,213 @@
+/* * Copyright(c) 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * 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.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#ifndef _FC_MS_H_
+#define	_FC_MS_H_
+
+#include <linux/types.h>
+
+/*
+ * Fibre Channel Services - Management Service (MS)
+ * From T11.org FC-GS-4 Rev 7.91 February 4, 2004
+ */
+
+/*
+ * Fabric Device Management Interface
+ */
+
+/*
+ * Common-transport sub-type for FDMI
+ */
+#define	FC_FDMI_SUBTYPE	    0x10 /* fs_ct_hdr.ct_fs_subtype */
+
+/*
+ * Management server FDMI Requests.
+ */
+enum fc_fdmi_req {
+	FC_FDMI_GRHL = 0x0100,	/* Get Registered HBA List */
+	FC_FDMI_GHAT = 0x0101,	/* Get HBA Attributes */
+	FC_FDMI_GRPL = 0x0102,	/* Get Registered Port List */
+	FC_FDMI_GPAT = 0x0110,	/* Get Port Attributes */
+	FC_FDMI_RHBA = 0x0200,	/* Register HBA */
+	FC_FDMI_RHAT = 0x0201,	/* Register HBA Attributes */
+	FC_FDMI_RPRT = 0x0210,	/* Register Port */
+	FC_FDMI_RPA = 0x0211,	/* Register Port Attributes */
+	FC_FDMI_DHBA = 0x0300,	/* Deregister HBA */
+	FC_FDMI_DHAT = 0x0301,	/* Deregister HBA Attributes */
+	FC_FDMI_DPRT = 0x0310,	/* Deregister Port */
+	FC_FDMI_DPA = 0x0311,	/* Deregister Port Attributes */
+};
+
+/*
+ * HBA Attribute Entry Type
+ */
+enum fc_fdmi_hba_attr_type {
+	FC_FDMI_HBA_ATTR_NODENAME = 0x0001,
+	FC_FDMI_HBA_ATTR_MANUFACTURER = 0x0002,
+	FC_FDMI_HBA_ATTR_SERIALNUMBER = 0x0003,
+	FC_FDMI_HBA_ATTR_MODEL = 0x0004,
+	FC_FDMI_HBA_ATTR_MODELDESCRIPTION = 0x0005,
+	FC_FDMI_HBA_ATTR_HARDWAREVERSION = 0x0006,
+	FC_FDMI_HBA_ATTR_DRIVERVERSION = 0x0007,
+	FC_FDMI_HBA_ATTR_OPTIONROMVERSION = 0x0008,
+	FC_FDMI_HBA_ATTR_FIRMWAREVERSION = 0x0009,
+	FC_FDMI_HBA_ATTR_OSNAMEVERSION = 0x000A,
+	FC_FDMI_HBA_ATTR_MAXCTPAYLOAD = 0x000B,
+};
+
+/*
+ * HBA Attribute Length
+ */
+#define FC_FDMI_HBA_ATTR_NODENAME_LEN		8
+#define FC_FDMI_HBA_ATTR_MANUFACTURER_LEN	64
+#define FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN	64
+#define FC_FDMI_HBA_ATTR_MODEL_LEN		256
+#define FC_FDMI_HBA_ATTR_MODELDESCR_LEN		256
+#define FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN	256
+#define FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN	256
+#define FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN	256
+#define FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN	256
+#define FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN	256
+#define FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN	4
+
+/*
+ * Port Attribute Type
+ */
+enum fc_fdmi_port_attr_type {
+	FC_FDMI_PORT_ATTR_FC4TYPES = 0x0001,
+	FC_FDMI_PORT_ATTR_SUPPORTEDSPEED = 0x0002,
+	FC_FDMI_PORT_ATTR_CURRENTPORTSPEED = 0x0003,
+	FC_FDMI_PORT_ATTR_MAXFRAMESIZE = 0x0004,
+	FC_FDMI_PORT_ATTR_OSDEVICENAME = 0x0005,
+	FC_FDMI_PORT_ATTR_HOSTNAME = 0x0006,
+};
+
+/*
+ * Port Attribute Length
+ */
+#define FC_FDMI_PORT_ATTR_FC4TYPES_LEN		32
+#define FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN	4
+#define FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN	4
+#define FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN	4
+#define FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN	256
+#define FC_FDMI_PORT_ATTR_HOSTNAME_LEN		256
+
+/*
+ * HBA Attribute ID
+ */
+struct fc_fdmi_hba_identifier {
+	__be64		id;
+};
+
+/*
+ * Port Name
+ */
+struct fc_fdmi_port_name {
+	__be64		portname;
+};
+
+/*
+ * Attribute Entry Block for HBA/Port Attributes
+ */
+#define FC_FDMI_ATTR_ENTRY_HEADER_LEN	4
+struct fc_fdmi_attr_entry {
+	__be16		type;
+	__be16		len;
+	__u8		value[1];
+} __attribute__((__packed__));
+
+/*
+ * Common for HBA/Port Attributes
+ */
+struct fs_fdmi_attrs {
+	__be32				numattrs;
+	struct fc_fdmi_attr_entry	attr[1];
+} __attribute__((__packed__));
+
+/*
+ * Registered Port List
+ */
+struct fc_fdmi_rpl {
+	__be32				numport;
+	struct fc_fdmi_port_name	port[1];
+} __attribute__((__packed__));
+
+/*
+ * Register HBA (RHBA)
+ */
+struct fc_fdmi_rhba {
+	struct fc_fdmi_hba_identifier hbaid;
+	struct fc_fdmi_rpl		 port;
+	struct fs_fdmi_attrs		 hba_attrs;
+} __attribute__((__packed__));
+
+/*
+ * Register HBA Attributes (RHAT)
+ */
+struct fc_fdmi_rhat {
+	struct fc_fdmi_hba_identifier hbaid;
+	struct fs_fdmi_attrs		 hba_attrs;
+} __attribute__((__packed__));
+
+/*
+ * Register Port (RPRT)
+ */
+struct fc_fdmi_rprt {
+	struct fc_fdmi_hba_identifier hbaid;
+	struct fc_fdmi_port_name	 port;
+	struct fs_fdmi_attrs		 hba_attrs;
+} __attribute__((__packed__));
+
+/*
+ * Register Port Attributes (RPA)
+ */
+struct fc_fdmi_rpa {
+	struct fc_fdmi_port_name	 port;
+	struct fs_fdmi_attrs		 hba_attrs;
+} __attribute__((__packed__));
+
+/*
+ * Deregister Port (DPRT)
+ */
+struct fc_fdmi_dprt {
+	struct fc_fdmi_port_name	 port;
+} __attribute__((__packed__));
+
+/*
+ * Deregister Port Attributes (DPA)
+ */
+struct fc_fdmi_dpa {
+	struct fc_fdmi_port_name	 port;
+	struct fs_fdmi_attrs		 hba_attrs;
+} __attribute__((__packed__));
+
+/*
+ * Deregister HBA Attributes (DHAT)
+ */
+struct fc_fdmi_dhat {
+	struct fc_fdmi_hba_identifier hbaid;
+} __attribute__((__packed__));
+
+/*
+ * Deregister HBA (DHBA)
+ */
+struct fc_fdmi_dhba {
+	struct fc_fdmi_hba_identifier hbaid;
+} __attribute__((__packed__));
+
+#endif /* _FC_MS_H_ */
diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h
index be418d8..35fd474 100644
--- a/include/scsi/fc_encode.h
+++ b/include/scsi/fc_encode.h
@@ -20,6 +20,7 @@
 #ifndef _FC_ENCODE_H_
 #define _FC_ENCODE_H_
 #include <asm/unaligned.h>
+#include <linux/utsname.h>
 
 /*
  * F_CTL values for simple requests and responses.
@@ -43,6 +44,10 @@
 		struct fc_ns_fid fid;
 		struct fc_ns_rsnn snn;
 		struct fc_ns_rspn spn;
+		struct fc_fdmi_rhba rhba;
+		struct fc_fdmi_rpa  rpa;
+		struct fc_fdmi_dprt dprt;
+		struct fc_fdmi_dhba dhba;
 	} payload;
 };
 
@@ -97,7 +102,9 @@
  * returns pointer to ct request.
  */
 static inline struct fc_ct_req *fc_ct_hdr_fill(const struct fc_frame *fp,
-					       unsigned int op, size_t req_size)
+					       unsigned int op, size_t req_size,
+					       enum fc_ct_fs_type fs_type,
+					       u8 subtype)
 {
 	struct fc_ct_req *ct;
 	size_t ct_plen;
@@ -106,14 +113,14 @@
 	ct = fc_frame_payload_get(fp, ct_plen);
 	memset(ct, 0, ct_plen);
 	ct->hdr.ct_rev = FC_CT_REV;
-	ct->hdr.ct_fs_type = FC_FST_DIR;
-	ct->hdr.ct_fs_subtype = FC_NS_SUBTYPE;
+	ct->hdr.ct_fs_type = fs_type;
+	ct->hdr.ct_fs_subtype = subtype;
 	ct->hdr.ct_cmd = htons((u16) op);
 	return ct;
 }
 
 /**
- * fc_ct_fill() - Fill in a name service request frame
+ * fc_ct_ns_fill() - Fill in a name service request frame
  * @lport: local port.
  * @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries.
  * @fp: frame to contain payload.
@@ -121,7 +128,7 @@
  * @r_ctl: pointer to FC header R_CTL.
  * @fh_type: pointer to FC-4 type.
  */
-static inline int fc_ct_fill(struct fc_lport *lport,
+static inline int fc_ct_ns_fill(struct fc_lport *lport,
 		      u32 fc_id, struct fc_frame *fp,
 		      unsigned int op, enum fc_rctl *r_ctl,
 		      enum fc_fh_type *fh_type)
@@ -131,23 +138,28 @@
 
 	switch (op) {
 	case FC_NS_GPN_FT:
-		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_gid_ft));
+		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_gid_ft),
+				    FC_FST_DIR, FC_NS_SUBTYPE);
 		ct->payload.gid.fn_fc4_type = FC_TYPE_FCP;
 		break;
 
 	case FC_NS_GPN_ID:
-		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_fid));
+		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_fid),
+				    FC_FST_DIR, FC_NS_SUBTYPE);
+		ct->payload.gid.fn_fc4_type = FC_TYPE_FCP;
 		hton24(ct->payload.fid.fp_fid, fc_id);
 		break;
 
 	case FC_NS_RFT_ID:
-		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rft));
+		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rft),
+				    FC_FST_DIR, FC_NS_SUBTYPE);
 		hton24(ct->payload.rft.fid.fp_fid, lport->port_id);
 		ct->payload.rft.fts = lport->fcts;
 		break;
 
 	case FC_NS_RFF_ID:
-		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rff_id));
+		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rff_id),
+				    FC_FST_DIR, FC_NS_SUBTYPE);
 		hton24(ct->payload.rff.fr_fid.fp_fid, lport->port_id);
 		ct->payload.rff.fr_type = FC_TYPE_FCP;
 		if (lport->service_params & FCP_SPPF_INIT_FCN)
@@ -157,14 +169,16 @@
 		break;
 
 	case FC_NS_RNN_ID:
-		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rn_id));
+		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rn_id),
+				    FC_FST_DIR, FC_NS_SUBTYPE);
 		hton24(ct->payload.rn.fr_fid.fp_fid, lport->port_id);
 		put_unaligned_be64(lport->wwnn, &ct->payload.rn.fr_wwn);
 		break;
 
 	case FC_NS_RSPN_ID:
 		len = strnlen(fc_host_symbolic_name(lport->host), 255);
-		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rspn) + len);
+		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rspn) + len,
+				    FC_FST_DIR, FC_NS_SUBTYPE);
 		hton24(ct->payload.spn.fr_fid.fp_fid, lport->port_id);
 		strncpy(ct->payload.spn.fr_name,
 			fc_host_symbolic_name(lport->host), len);
@@ -173,7 +187,8 @@
 
 	case FC_NS_RSNN_NN:
 		len = strnlen(fc_host_symbolic_name(lport->host), 255);
-		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rsnn) + len);
+		ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rsnn) + len,
+				    FC_FST_DIR, FC_NS_SUBTYPE);
 		put_unaligned_be64(lport->wwnn, &ct->payload.snn.fr_wwn);
 		strncpy(ct->payload.snn.fr_name,
 			fc_host_symbolic_name(lport->host), len);
@@ -189,6 +204,330 @@
 }
 
 /**
+ * fc_ct_ms_fill() - Fill in a mgmt service request frame
+ * @lport: local port.
+ * @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries.
+ * @fp: frame to contain payload.
+ * @op: CT opcode.
+ * @r_ctl: pointer to FC header R_CTL.
+ * @fh_type: pointer to FC-4 type.
+ */
+static inline int fc_ct_ms_fill(struct fc_lport *lport,
+		      u32 fc_id, struct fc_frame *fp,
+		      unsigned int op, enum fc_rctl *r_ctl,
+		      enum fc_fh_type *fh_type)
+{
+	struct fc_ct_req *ct;
+	size_t len;
+	struct fc_fdmi_attr_entry *entry;
+	struct fs_fdmi_attrs *hba_attrs;
+	int numattrs = 0;
+
+	switch (op) {
+	case FC_FDMI_RHBA:
+		numattrs = 10;
+		len = sizeof(struct fc_fdmi_rhba);
+		len -= sizeof(struct fc_fdmi_attr_entry);
+		len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
+		len += FC_FDMI_HBA_ATTR_NODENAME_LEN;
+		len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN;
+		len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN;
+		len += FC_FDMI_HBA_ATTR_MODEL_LEN;
+		len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN;
+		len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN;
+		len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN;
+		len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN;
+		len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN;
+		len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN;
+		ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT,
+				    FC_FDMI_SUBTYPE);
+
+		/* HBA Identifier */
+		put_unaligned_be64(lport->wwpn, &ct->payload.rhba.hbaid.id);
+		/* Number of Ports - always 1 */
+		put_unaligned_be32(1, &ct->payload.rhba.port.numport);
+		/* Port Name */
+		put_unaligned_be64(lport->wwpn,
+				   &ct->payload.rhba.port.port[0].portname);
+
+		/* HBA Attributes */
+		put_unaligned_be32(numattrs,
+				   &ct->payload.rhba.hba_attrs.numattrs);
+		hba_attrs = &ct->payload.rhba.hba_attrs;
+		entry = (struct fc_fdmi_attr_entry *)hba_attrs->attr;
+		/* NodeName*/
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_HBA_ATTR_NODENAME_LEN;
+		put_unaligned_be16(FC_FDMI_HBA_ATTR_NODENAME,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+		put_unaligned_be64(lport->wwnn,
+				   (__be64 *)&entry->value[0]);
+
+		/* Manufacturer */
+		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+					FC_FDMI_HBA_ATTR_NODENAME_LEN);
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN;
+		put_unaligned_be16(FC_FDMI_HBA_ATTR_MANUFACTURER,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+		strncpy((char *)&entry->value,
+			fc_host_manufacturer(lport->host),
+			FC_FDMI_HBA_ATTR_MANUFACTURER_LEN);
+
+		/* SerialNumber */
+		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+					FC_FDMI_HBA_ATTR_MANUFACTURER_LEN);
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN;
+		put_unaligned_be16(FC_FDMI_HBA_ATTR_SERIALNUMBER,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+		strncpy((char *)&entry->value,
+			fc_host_serial_number(lport->host),
+			FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN);
+
+		/* Model */
+		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+					FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN);
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_HBA_ATTR_MODEL_LEN;
+		put_unaligned_be16(FC_FDMI_HBA_ATTR_MODEL,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+		strncpy((char *)&entry->value,
+			fc_host_model(lport->host),
+			FC_FDMI_HBA_ATTR_MODEL_LEN);
+
+		/* Model Description */
+		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+					FC_FDMI_HBA_ATTR_MODEL_LEN);
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN;
+		put_unaligned_be16(FC_FDMI_HBA_ATTR_MODELDESCRIPTION,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+		strncpy((char *)&entry->value,
+			fc_host_model_description(lport->host),
+			FC_FDMI_HBA_ATTR_MODELDESCR_LEN);
+
+		/* Hardware Version */
+		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+					FC_FDMI_HBA_ATTR_MODELDESCR_LEN);
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN;
+		put_unaligned_be16(FC_FDMI_HBA_ATTR_HARDWAREVERSION,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+		strncpy((char *)&entry->value,
+			fc_host_hardware_version(lport->host),
+			FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN);
+
+		/* Driver Version */
+		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+					FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN);
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN;
+		put_unaligned_be16(FC_FDMI_HBA_ATTR_DRIVERVERSION,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+		strncpy((char *)&entry->value,
+			fc_host_driver_version(lport->host),
+			FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN);
+
+		/* OptionROM Version */
+		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+					FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN);
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN;
+		put_unaligned_be16(FC_FDMI_HBA_ATTR_OPTIONROMVERSION,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+		strncpy((char *)&entry->value,
+			fc_host_optionrom_version(lport->host),
+			FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN);
+
+		/* Firmware Version */
+		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+					FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN);
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN;
+		put_unaligned_be16(FC_FDMI_HBA_ATTR_FIRMWAREVERSION,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+		strncpy((char *)&entry->value,
+			fc_host_firmware_version(lport->host),
+			FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN);
+
+		/* OS Name and Version */
+		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+					FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN);
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN;
+		put_unaligned_be16(FC_FDMI_HBA_ATTR_OSNAMEVERSION,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+		snprintf((char *)&entry->value,
+			FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN,
+			"%s v%s",
+			init_utsname()->sysname,
+			init_utsname()->release);
+		break;
+	case FC_FDMI_RPA:
+		numattrs = 6;
+		len = sizeof(struct fc_fdmi_rpa);
+		len -= sizeof(struct fc_fdmi_attr_entry);
+		len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
+		len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN;
+		len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN;
+		len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN;
+		len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN;
+		len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN;
+		len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN;
+		ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT,
+				    FC_FDMI_SUBTYPE);
+
+		/* Port Name */
+		put_unaligned_be64(lport->wwpn,
+				   &ct->payload.rpa.port.portname);
+
+		/* Port Attributes */
+		put_unaligned_be32(numattrs,
+				   &ct->payload.rpa.hba_attrs.numattrs);
+
+		hba_attrs = &ct->payload.rpa.hba_attrs;
+		entry = (struct fc_fdmi_attr_entry *)hba_attrs->attr;
+
+		/* FC4 types */
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN;
+		put_unaligned_be16(FC_FDMI_PORT_ATTR_FC4TYPES,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+		memcpy(&entry->value, fc_host_supported_fc4s(lport->host),
+		       FC_FDMI_PORT_ATTR_FC4TYPES_LEN);
+
+		/* Supported Speed */
+		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+					FC_FDMI_PORT_ATTR_FC4TYPES_LEN);
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN;
+		put_unaligned_be16(FC_FDMI_PORT_ATTR_SUPPORTEDSPEED,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+
+		put_unaligned_be32(fc_host_supported_speeds(lport->host),
+				   &entry->value);
+
+		/* Current Port Speed */
+		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+					FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN);
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN;
+		put_unaligned_be16(FC_FDMI_PORT_ATTR_CURRENTPORTSPEED,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+		put_unaligned_be32(lport->link_speed,
+				   &entry->value);
+
+		/* Max Frame Size */
+		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+					FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN);
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN;
+		put_unaligned_be16(FC_FDMI_PORT_ATTR_MAXFRAMESIZE,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+		put_unaligned_be32(fc_host_maxframe_size(lport->host),
+				   &entry->value);
+
+		/* OS Device Name */
+		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+					FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN);
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN;
+		put_unaligned_be16(FC_FDMI_PORT_ATTR_OSDEVICENAME,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+		/* Use the sysfs device name */
+		strncpy((char *)&entry->value,
+			dev_name(&lport->host->shost_gendev),
+			strnlen(dev_name(&lport->host->shost_gendev),
+				FC_FDMI_PORT_ATTR_HOSTNAME_LEN));
+
+		/* Host Name */
+		entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+					FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN);
+		len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+		len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN;
+		put_unaligned_be16(FC_FDMI_PORT_ATTR_HOSTNAME,
+				   &entry->type);
+		put_unaligned_be16(len, &entry->len);
+		if (strlen(fc_host_system_hostname(lport->host)))
+			strncpy((char *)&entry->value,
+				fc_host_system_hostname(lport->host),
+				strnlen(fc_host_system_hostname(lport->host),
+					FC_FDMI_PORT_ATTR_HOSTNAME_LEN));
+		else
+			strncpy((char *)&entry->value,
+				init_utsname()->nodename,
+				FC_FDMI_PORT_ATTR_HOSTNAME_LEN);
+		break;
+	case FC_FDMI_DPRT:
+		len = sizeof(struct fc_fdmi_dprt);
+		ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT,
+				    FC_FDMI_SUBTYPE);
+		/* Port Name */
+		put_unaligned_be64(lport->wwpn,
+				   &ct->payload.dprt.port.portname);
+		break;
+	case FC_FDMI_DHBA:
+		len = sizeof(struct fc_fdmi_dhba);
+		ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT,
+				    FC_FDMI_SUBTYPE);
+		/* HBA Identifier */
+		put_unaligned_be64(lport->wwpn, &ct->payload.dhba.hbaid.id);
+		break;
+	default:
+		return -EINVAL;
+	}
+	*r_ctl = FC_RCTL_DD_UNSOL_CTL;
+	*fh_type = FC_TYPE_CT;
+	return 0;
+}
+
+/**
+ * fc_ct_fill() - Fill in a common transport service request frame
+ * @lport: local port.
+ * @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries.
+ * @fp: frame to contain payload.
+ * @op: CT opcode.
+ * @r_ctl: pointer to FC header R_CTL.
+ * @fh_type: pointer to FC-4 type.
+ */
+static inline int fc_ct_fill(struct fc_lport *lport,
+		      u32 fc_id, struct fc_frame *fp,
+		      unsigned int op, enum fc_rctl *r_ctl,
+		      enum fc_fh_type *fh_type, u32 *did)
+{
+	int rc = -EINVAL;
+
+	switch (fc_id) {
+	case FC_FID_MGMT_SERV:
+		rc = fc_ct_ms_fill(lport, fc_id, fp, op, r_ctl, fh_type);
+		*did = FC_FID_MGMT_SERV;
+		break;
+	case FC_FID_DIR_SERV:
+	default:
+		rc = fc_ct_ns_fill(lport, fc_id, fp, op, r_ctl, fh_type);
+		*did = FC_FID_DIR_SERV;
+		break;
+	}
+
+	return rc;
+}
+/**
  * fc_plogi_fill - Fill in plogi request frame
  */
 static inline void fc_plogi_fill(struct fc_lport *lport, struct fc_frame *fp,
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index 2703e3b..917741b 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -60,6 +60,9 @@
 
 	ISCSI_UEVENT_PATH_UPDATE	= UEVENT_BASE + 20,
 	ISCSI_UEVENT_SET_IFACE_PARAMS	= UEVENT_BASE + 21,
+	ISCSI_UEVENT_PING		= UEVENT_BASE + 22,
+	ISCSI_UEVENT_GET_CHAP		= UEVENT_BASE + 23,
+	ISCSI_UEVENT_DELETE_CHAP	= UEVENT_BASE + 24,
 
 	/* up events */
 	ISCSI_KEVENT_RECV_PDU		= KEVENT_BASE + 1,
@@ -72,6 +75,8 @@
 	ISCSI_KEVENT_PATH_REQ		= KEVENT_BASE + 7,
 	ISCSI_KEVENT_IF_DOWN		= KEVENT_BASE + 8,
 	ISCSI_KEVENT_CONN_LOGIN_STATE   = KEVENT_BASE + 9,
+	ISCSI_KEVENT_HOST_EVENT		= KEVENT_BASE + 10,
+	ISCSI_KEVENT_PING_COMP		= KEVENT_BASE + 11,
 };
 
 enum iscsi_tgt_dscvr {
@@ -80,6 +85,13 @@
 	ISCSI_TGT_DSCVR_SLP		= 3,
 };
 
+enum iscsi_host_event_code {
+	ISCSI_EVENT_LINKUP		= 1,
+	ISCSI_EVENT_LINKDOWN,
+	/* must always be last */
+	ISCSI_EVENT_MAX,
+};
+
 struct iscsi_uevent {
 	uint32_t type; /* k/u events type */
 	uint32_t iferror; /* carries interface or resource errors */
@@ -178,6 +190,26 @@
 			uint32_t	host_no;
 			uint32_t	count;
 		} set_iface_params;
+		struct msg_iscsi_ping {
+			uint32_t        host_no;
+			uint32_t        iface_num;
+			uint32_t        iface_type;
+			uint32_t        payload_size;
+			uint32_t	pid;	/* unique ping id associated
+						   with each ping request */
+		} iscsi_ping;
+		struct msg_get_chap {
+			uint32_t	host_no;
+			uint32_t	num_entries; /* number of CHAP entries
+						      * on request, number of
+						      * valid CHAP entries on
+						      * response */
+			uint16_t	chap_tbl_idx;
+		} get_chap;
+		struct msg_delete_chap {
+		       uint32_t        host_no;
+		       uint16_t        chap_tbl_idx;
+		} delete_chap;
 	} u;
 	union {
 		/* messages k -> u */
@@ -222,6 +254,19 @@
 		struct msg_notify_if_down {
 			uint32_t	host_no;
 		} notify_if_down;
+		struct msg_host_event {
+			uint32_t	host_no;
+			uint32_t	data_size;
+			enum iscsi_host_event_code code;
+		} host_event;
+		struct msg_ping_comp {
+			uint32_t        host_no;
+			uint32_t        status; /* enum
+						 * iscsi_ping_status_code */
+			uint32_t	pid;	/* unique ping id associated
+						   with each ping request */
+			uint32_t        data_size;
+		} ping_comp;
 	} r;
 } __attribute__ ((aligned (sizeof(uint64_t))));
 
@@ -406,6 +451,9 @@
 
 	ISCSI_PARAM_TGT_RESET_TMO,
 	ISCSI_PARAM_TARGET_ALIAS,
+
+	ISCSI_PARAM_CHAP_IN_IDX,
+	ISCSI_PARAM_CHAP_OUT_IDX,
 	/* must always be last */
 	ISCSI_PARAM_MAX,
 };
@@ -416,9 +464,40 @@
 	ISCSI_HOST_PARAM_INITIATOR_NAME,
 	ISCSI_HOST_PARAM_NETDEV_NAME,
 	ISCSI_HOST_PARAM_IPADDRESS,
+	ISCSI_HOST_PARAM_PORT_STATE,
+	ISCSI_HOST_PARAM_PORT_SPEED,
 	ISCSI_HOST_PARAM_MAX,
 };
 
+/* iSCSI port Speed */
+enum iscsi_port_speed {
+	ISCSI_PORT_SPEED_UNKNOWN	= 0x1,
+	ISCSI_PORT_SPEED_10MBPS		= 0x2,
+	ISCSI_PORT_SPEED_100MBPS	= 0x4,
+	ISCSI_PORT_SPEED_1GBPS		= 0x8,
+	ISCSI_PORT_SPEED_10GBPS		= 0x10,
+};
+
+/* iSCSI port state */
+enum iscsi_port_state {
+	ISCSI_PORT_STATE_DOWN		= 0x1,
+	ISCSI_PORT_STATE_UP		= 0x2,
+};
+
+/* iSCSI PING status/error code */
+enum iscsi_ping_status_code {
+	ISCSI_PING_SUCCESS			= 0,
+	ISCSI_PING_FW_DISABLED			= 0x1,
+	ISCSI_PING_IPADDR_INVALID		= 0x2,
+	ISCSI_PING_LINKLOCAL_IPV6_ADDR_INVALID	= 0x3,
+	ISCSI_PING_TIMEOUT			= 0x4,
+	ISCSI_PING_INVALID_DEST_ADDR		= 0x5,
+	ISCSI_PING_OVERSIZE_PACKET		= 0x6,
+	ISCSI_PING_ICMP_ERROR			= 0x7,
+	ISCSI_PING_MAX_REQ_EXCEEDED		= 0x8,
+	ISCSI_PING_NO_ARP_RECEIVED		= 0x9,
+};
+
 #define iscsi_ptr(_handle) ((void*)(unsigned long)_handle)
 #define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr)
 
@@ -501,4 +580,19 @@
 		__attribute__ ((aligned (sizeof(uint64_t))));
 };
 
+enum chap_type_e {
+	CHAP_TYPE_OUT,
+	CHAP_TYPE_IN,
+};
+
+#define ISCSI_CHAP_AUTH_NAME_MAX_LEN	256
+#define ISCSI_CHAP_AUTH_SECRET_MAX_LEN	256
+struct iscsi_chap_rec {
+	uint16_t chap_tbl_idx;
+	enum chap_type_e chap_type;
+	char username[ISCSI_CHAP_AUTH_NAME_MAX_LEN];
+	uint8_t password[ISCSI_CHAP_AUTH_SECRET_MAX_LEN];
+	uint8_t password_length;
+};
+
 #endif
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index 6a3922f..8f9dfba 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -30,6 +30,7 @@
 
 #include <scsi/fc/fc_fcp.h>
 #include <scsi/fc/fc_ns.h>
+#include <scsi/fc/fc_ms.h>
 #include <scsi/fc/fc_els.h>
 #include <scsi/fc/fc_gs.h>
 
@@ -52,6 +53,8 @@
  * @LPORT_ST_RPN_ID:   Register port name by ID (RPN_ID) sent
  * @LPORT_ST_RFT_ID:   Register Fibre Channel types by ID (RFT_ID) sent
  * @LPORT_ST_RFF_ID:   Register FC-4 Features by ID (RFF_ID) sent
+ * @LPORT_ST_FDMI:     Waiting for mgmt server rport to become ready
+ * @LPORT_ST_RHBA:
  * @LPORT_ST_SCR:      State Change Register (SCR) sent
  * @LPORT_ST_READY:    Ready for use
  * @LPORT_ST_LOGO:     Local port logout (LOGO) sent
@@ -66,6 +69,11 @@
 	LPORT_ST_RSPN_ID,
 	LPORT_ST_RFT_ID,
 	LPORT_ST_RFF_ID,
+	LPORT_ST_FDMI,
+	LPORT_ST_RHBA,
+	LPORT_ST_RPA,
+	LPORT_ST_DHBA,
+	LPORT_ST_DPRT,
 	LPORT_ST_SCR,
 	LPORT_ST_READY,
 	LPORT_ST_LOGO,
@@ -797,6 +805,7 @@
  * @host:                  The SCSI host associated with a local port
  * @ema_list:              Exchange manager anchor list
  * @dns_rdata:             The directory server remote port
+ * @ms_rdata:		   The management server remote port
  * @ptp_rdata:             Point to point remote port
  * @scsi_priv:             FCP layer internal data
  * @disc:                  Discovery context
@@ -842,6 +851,7 @@
 	struct Scsi_Host	       *host;
 	struct list_head	       ema_list;
 	struct fc_rport_priv	       *dns_rdata;
+	struct fc_rport_priv	       *ms_rdata;
 	struct fc_rport_priv	       *ptp_rdata;
 	void			       *scsi_priv;
 	struct fc_disc                 disc;
@@ -877,6 +887,7 @@
 	u32			       does_npiv:1;
 	u32			       npiv_enabled:1;
 	u32			       point_to_multipoint:1;
+	u32			       fdmi_enabled:1;
 	u32			       mfs;
 	u8			       max_retry_count;
 	u8			       max_rport_retry_count;
diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h
index 5a35a2a..cfdb55f 100644
--- a/include/scsi/libfcoe.h
+++ b/include/scsi/libfcoe.h
@@ -165,7 +165,8 @@
  * @switch_name: WWN of switch from advertisement
  * @fabric_name: WWN of fabric from advertisement
  * @fc_map:	 FC_MAP value from advertisement
- * @fcf_mac:	 Ethernet address of the FCF
+ * @fcf_mac:	 Ethernet address of the FCF for FIP traffic
+ * @fcoe_mac:	 Ethernet address of the FCF for FCoE traffic
  * @vfid:	 virtual fabric ID
  * @pri:	 selection priority, smaller values are better
  * @flogi_sent:	 current FLOGI sent to this FCF
@@ -188,6 +189,7 @@
 	u32 fc_map;
 	u16 vfid;
 	u8 fcf_mac[ETH_ALEN];
+	u8 fcoe_mac[ETH_ALEN];
 
 	u8 pri;
 	u8 flogi_sent;
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index cedcff3..6e33386 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -268,7 +268,7 @@
 	int			lu_reset_timeout;
 	int			tgt_reset_timeout;
 	int			initial_r2t_en;
-	unsigned		max_r2t;
+	unsigned short		max_r2t;
 	int			imm_data_en;
 	unsigned		first_burst;
 	unsigned		max_burst;
@@ -284,6 +284,7 @@
 	char			*password;
 	char			*password_in;
 	char			*targetname;
+	char			*targetalias;
 	char			*ifacename;
 	char			*initiatorname;
 	/* control data */
diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h
index ac0cc1d..215469a 100644
--- a/include/scsi/libiscsi_tcp.h
+++ b/include/scsi/libiscsi_tcp.h
@@ -128,7 +128,7 @@
 /* misc helpers */
 extern int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session);
 extern void iscsi_tcp_r2tpool_free(struct iscsi_session *session);
-
+extern int iscsi_tcp_set_max_r2t(struct iscsi_conn *conn, char *buf);
 extern void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn,
 				     struct iscsi_stats *stats);
 #endif /* LIBISCSI_TCP_H */
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 6a308d42..5f5ed1b 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -86,7 +86,9 @@
 	DISCE_DISCOVER_DOMAIN   = 0U,
 	DISCE_REVALIDATE_DOMAIN = 1,
 	DISCE_PORT_GONE         = 2,
-	DISC_NUM_EVENTS 	= 3,
+	DISCE_PROBE		= 3,
+	DISCE_DESTRUCT		= 4,
+	DISC_NUM_EVENTS		= 5,
 };
 
 /* ---------- Expander Devices ---------- */
@@ -151,6 +153,8 @@
 
 	struct ex_phy *ex_phy;
 	struct sas_port *parent_port;
+
+	struct mutex cmd_mutex;
 };
 
 /* ---------- SATA device ---------- */
@@ -162,22 +166,21 @@
 struct sata_device {
         enum   ata_command_set command_set;
         struct smp_resp        rps_resp; /* report_phy_sata_resp */
-        __le16 *identify_device;
-        __le16 *identify_packet_device;
-
         u8     port_no;        /* port number, if this is a PM (Port) */
         struct list_head children; /* PM Ports if this is a PM */
 
 	struct ata_port *ap;
 	struct ata_host ata_host;
 	struct ata_taskfile tf;
-	u32 sstatus;
-	u32 serror;
-	u32 scontrol;
 };
 
-/* ---------- Domain device ---------- */
+enum {
+	SAS_DEV_GONE,
+	SAS_DEV_DESTROY,
+};
+
 struct domain_device {
+	spinlock_t done_lock;
         enum sas_dev_type dev_type;
 
         enum sas_linkrate linkrate;
@@ -189,8 +192,10 @@
         struct domain_device *parent;
         struct list_head siblings; /* devices on the same level */
         struct asd_sas_port *port;        /* shortcut to root of the tree */
+	struct sas_phy *phy;
 
         struct list_head dev_list_node;
+	struct list_head disco_list_node; /* awaiting probe or destruct */
 
         enum sas_protocol    iproto;
         enum sas_protocol    tproto;
@@ -208,7 +213,8 @@
         };
 
         void *lldd_dev;
-	int gone;
+	unsigned long state;
+	struct kref kref;
 };
 
 struct sas_discovery_event {
@@ -217,7 +223,6 @@
 };
 
 struct sas_discovery {
-	spinlock_t disc_event_lock;
 	struct sas_discovery_event disc_work[DISC_NUM_EVENTS];
 	unsigned long    pending;
 	u8     fanout_sas_addr[8];
@@ -226,7 +231,6 @@
 	int    max_level;
 };
 
-
 /* The port struct is Class:RW, driver:RO */
 struct asd_sas_port {
 /* private: */
@@ -236,9 +240,10 @@
 	struct domain_device *port_dev;
 	spinlock_t dev_list_lock;
 	struct list_head dev_list;
+	struct list_head disco_list;
+	struct list_head destroy_list;
 	enum   sas_linkrate linkrate;
 
-	struct sas_phy *phy;
 	struct work_struct work;
 
 /* public: */
@@ -274,7 +279,6 @@
  */
 struct asd_sas_phy {
 /* private: */
-	/* protected by ha->event_lock */
 	struct asd_sas_event   port_events[PORT_NUM_EVENTS];
 	struct asd_sas_event   phy_events[PHY_NUM_EVENTS];
 
@@ -320,6 +324,7 @@
 struct scsi_core {
 	struct Scsi_Host *shost;
 
+	struct mutex	  task_queue_flush;
 	spinlock_t        task_queue_lock;
 	struct list_head  task_queue;
 	int               task_queue_size;
@@ -334,18 +339,23 @@
 
 enum sas_ha_state {
 	SAS_HA_REGISTERED,
-	SAS_HA_UNREGISTERED
+	SAS_HA_DRAINING,
+	SAS_HA_ATA_EH_ACTIVE,
+	SAS_HA_FROZEN,
 };
 
 struct sas_ha_struct {
 /* private: */
-	spinlock_t       event_lock;
 	struct sas_ha_event ha_events[HA_NUM_EVENTS];
 	unsigned long	 pending;
 
-	enum sas_ha_state state;
+	struct list_head  defer_q; /* work queued while draining */
+	struct mutex	  drain_mutex;
+	unsigned long	  state;
 	spinlock_t 	  state_lock;
 
+	struct mutex disco_mutex;
+
 	struct scsi_core core;
 
 /* public: */
@@ -374,7 +384,8 @@
 
 	void *lldd_ha;		  /* not touched by sas class code */
 
-	struct list_head eh_done_q;
+	struct list_head eh_done_q;  /* complete via scsi_eh_flush_done_q */
+	struct list_head eh_ata_q; /* scmds to promote from sas to ata eh */
 };
 
 #define SHOST_TO_SAS_HA(_shost) (*(struct sas_ha_struct **)(_shost)->hostdata)
@@ -418,6 +429,11 @@
 	return 3 * device + bit;
 }
 
+static inline void sas_put_local_phy(struct sas_phy *phy)
+{
+	put_device(&phy->dev);
+}
+
 #ifdef CONFIG_SCSI_SAS_HOST_SMP
 int try_test_sas_gpio_gp_bit(unsigned int od, u8 *data, u8 index, u8 count);
 #else
@@ -447,7 +463,10 @@
 };
 
 enum exec_status {
-	/* The SAM_STAT_.. codes fit in the lower 6 bits */
+	/* The SAM_STAT_.. codes fit in the lower 6 bits, alias some of
+	 * them here to silence 'case value not in enumerated type' warnings
+	 */
+	__SAM_STAT_CHECK_CONDITION = SAM_STAT_CHECK_CONDITION,
 
 	SAS_DEV_NO_RESPONSE = 0x80,
 	SAS_DATA_UNDERRUN,
@@ -487,10 +506,6 @@
 struct ata_task_resp {
 	u16  frame_len;
 	u8   ending_fis[24];	  /* dev to host or data-in */
-	u32  sstatus;
-	u32  serror;
-	u32  scontrol;
-	u32  sactive;
 };
 
 #define SAS_STATUS_BUF_SIZE 96
@@ -604,7 +619,8 @@
 	int (*lldd_clear_aca)(struct domain_device *, u8 *lun);
 	int (*lldd_clear_task_set)(struct domain_device *, u8 *lun);
 	int (*lldd_I_T_nexus_reset)(struct domain_device *);
-	int (*lldd_ata_soft_reset)(struct domain_device *);
+	int (*lldd_ata_check_ready)(struct domain_device *);
+	void (*lldd_ata_set_dmamode)(struct domain_device *);
 	int (*lldd_lu_reset)(struct domain_device *, u8 *lun);
 	int (*lldd_query_task)(struct sas_task *);
 
@@ -625,14 +641,11 @@
 
 int sas_set_phy_speed(struct sas_phy *phy,
 		      struct sas_phy_linkrates *rates);
-int sas_phy_enable(struct sas_phy *phy, int enabled);
 int sas_phy_reset(struct sas_phy *phy, int hard_reset);
 int sas_queue_up(struct sas_task *task);
 extern int sas_queuecommand(struct Scsi_Host * ,struct scsi_cmnd *);
 extern int sas_target_alloc(struct scsi_target *);
-extern int sas_slave_alloc(struct scsi_device *);
 extern int sas_slave_configure(struct scsi_device *);
-extern void sas_slave_destroy(struct scsi_device *);
 extern int sas_change_queue_depth(struct scsi_device *, int new_depth,
 				  int reason);
 extern int sas_change_queue_type(struct scsi_device *, int qt);
@@ -649,7 +662,7 @@
 
 int  sas_ex_revalidate_domain(struct domain_device *);
 
-void sas_unregister_domain_devices(struct asd_sas_port *port);
+void sas_unregister_domain_devices(struct asd_sas_port *port, int gone);
 void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *);
 int  sas_discover_event(struct asd_sas_port *, enum discover_event ev);
 
@@ -661,20 +674,20 @@
 void sas_init_dev(struct domain_device *);
 
 void sas_task_abort(struct sas_task *);
-int __sas_task_abort(struct sas_task *);
 int sas_eh_device_reset_handler(struct scsi_cmnd *cmd);
 int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd);
 
 extern void sas_target_destroy(struct scsi_target *);
 extern int sas_slave_alloc(struct scsi_device *);
 extern int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg);
+extern int sas_drain_work(struct sas_ha_struct *ha);
 
 extern int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 			   struct request *req);
 
 extern void sas_ssp_task_response(struct device *dev, struct sas_task *task,
 				  struct ssp_response_iu *iu);
-struct sas_phy *sas_find_local_phy(struct domain_device *dev);
+struct sas_phy *sas_get_local_phy(struct domain_device *dev);
 
 int sas_request_addr(struct Scsi_Host *shost, u8 *addr);
 
diff --git a/include/scsi/osd_ore.h b/include/scsi/osd_ore.h
index f05fa82..a5f9b96 100644
--- a/include/scsi/osd_ore.h
+++ b/include/scsi/osd_ore.h
@@ -26,6 +26,7 @@
 #include <scsi/osd_attributes.h>
 #include <scsi/osd_sec.h>
 #include <linux/pnfs_osd_xdr.h>
+#include <linux/bug.h>
 
 struct ore_comp {
 	struct osd_obj_id	obj;
diff --git a/include/scsi/sas.h b/include/scsi/sas.h
index 3673d68..a577a83 100644
--- a/include/scsi/sas.h
+++ b/include/scsi/sas.h
@@ -89,8 +89,7 @@
 	SAS_OOB_MODE
 };
 
-/* See sas_discover.c if you plan on changing these.
- */
+/* See sas_discover.c if you plan on changing these */
 enum sas_dev_type {
 	NO_DEVICE   = 0,	  /* protocol */
 	SAS_END_DEV = 1,	  /* protocol */
@@ -100,6 +99,7 @@
 	SATA_DEV    = 5,
 	SATA_PM     = 7,
 	SATA_PM_PORT= 8,
+	SATA_PENDING  = 9,
 };
 
 enum sas_protocol {
diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h
index 9c159f7..cdccd2e 100644
--- a/include/scsi/sas_ata.h
+++ b/include/scsi/sas_ata.h
@@ -32,19 +32,19 @@
 
 static inline int dev_is_sata(struct domain_device *dev)
 {
-	return (dev->rphy->identify.target_port_protocols & SAS_PROTOCOL_SATA);
+	return dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM ||
+	       dev->dev_type == SATA_PM_PORT || dev->dev_type == SATA_PENDING;
 }
 
-int sas_ata_init_host_and_port(struct domain_device *found_dev,
-			       struct scsi_target *starget);
-
+int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy);
+int sas_ata_init_host_and_port(struct domain_device *found_dev);
 void sas_ata_task_abort(struct sas_task *task);
 void sas_ata_strategy_handler(struct Scsi_Host *shost);
-int sas_ata_timed_out(struct scsi_cmnd *cmd, struct sas_task *task,
-		      enum blk_eh_timer_return *rtn);
-int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
-	       struct list_head *done_q);
-
+void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
+		struct list_head *done_q);
+void sas_ata_schedule_reset(struct domain_device *dev);
+void sas_ata_wait_eh(struct domain_device *dev);
+void sas_probe_sata(struct asd_sas_port *port);
 #else
 
 
@@ -52,8 +52,7 @@
 {
 	return 0;
 }
-static inline int sas_ata_init_host_and_port(struct domain_device *found_dev,
-			       struct scsi_target *starget)
+static inline int sas_ata_init_host_and_port(struct domain_device *found_dev)
 {
 	return 0;
 }
@@ -65,18 +64,27 @@
 {
 }
 
-static inline int sas_ata_timed_out(struct scsi_cmnd *cmd,
-				    struct sas_task *task,
-				    enum blk_eh_timer_return *rtn)
+static inline void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
+			      struct list_head *done_q)
 {
-	return 0;
-}
-static inline int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
-			     struct list_head *done_q)
-{
-	return 0;
 }
 
+static inline void sas_ata_schedule_reset(struct domain_device *dev)
+{
+}
+
+static inline void sas_ata_wait_eh(struct domain_device *dev)
+{
+}
+
+static inline void sas_probe_sata(struct asd_sas_port *port)
+{
+}
+
+static inline int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy)
+{
+	return 0;
+}
 #endif
 
 #endif /* _SAS_ATA_H_ */
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 8001ae4..f34a5a8 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -143,6 +143,7 @@
 #define READ_ATTRIBUTE        0x8c
 #define WRITE_ATTRIBUTE	      0x8d
 #define VERIFY_16	      0x8f
+#define SYNCHRONIZE_CACHE_16  0x91
 #define WRITE_SAME_16	      0x93
 #define SERVICE_ACTION_IN     0x9e
 /* values for service action in */
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index a5e885a..377df4a 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -10,6 +10,7 @@
 
 struct Scsi_Host;
 struct scsi_device;
+struct scsi_driver;
 
 /*
  * MAX_COMMAND_SIZE is:
@@ -131,6 +132,11 @@
 	unsigned char tag;	/* SCSI-II queued command tag */
 };
 
+static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
+{
+	return *(struct scsi_driver **)cmd->request->rq_disk->private_data;
+}
+
 extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
 extern struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *, gfp_t);
 extern void scsi_put_command(struct scsi_cmnd *);
@@ -289,17 +295,17 @@
 
 static inline void set_msg_byte(struct scsi_cmnd *cmd, char status)
 {
-	cmd->result |= status << 8;
+	cmd->result = (cmd->result & 0xffff00ff) | (status << 8);
 }
 
 static inline void set_host_byte(struct scsi_cmnd *cmd, char status)
 {
-	cmd->result |= status << 16;
+	cmd->result = (cmd->result & 0xff00ffff) | (status << 16);
 }
 
 static inline void set_driver_byte(struct scsi_cmnd *cmd, char status)
 {
-	cmd->result |= status << 24;
+	cmd->result = (cmd->result & 0x00ffffff) | (status << 24);
 }
 
 #endif /* _SCSI_SCSI_CMND_H */
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index b3a1c2d..6efb2e1 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -1,7 +1,6 @@
 #ifndef _SCSI_SCSI_DEVICE_H
 #define _SCSI_SCSI_DEVICE_H
 
-#include <linux/device.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
@@ -9,6 +8,7 @@
 #include <scsi/scsi.h>
 #include <linux/atomic.h>
 
+struct device;
 struct request_queue;
 struct scsi_cmnd;
 struct scsi_lun;
diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h
index 9fd6702..d443aa0 100644
--- a/include/scsi/scsi_driver.h
+++ b/include/scsi/scsi_driver.h
@@ -16,6 +16,7 @@
 
 	void (*rescan)(struct device *);
 	int (*done)(struct scsi_cmnd *);
+	int (*eh_action)(struct scsi_cmnd *, unsigned char *, int, int);
 };
 #define to_scsi_driver(drv) \
 	container_of((drv), struct scsi_driver, gendrv)
diff --git a/include/scsi/scsi_netlink.h b/include/scsi/scsi_netlink.h
index 58ce8fe..5cb20cc 100644
--- a/include/scsi/scsi_netlink.h
+++ b/include/scsi/scsi_netlink.h
@@ -23,7 +23,7 @@
 #define SCSI_NETLINK_H
 
 #include <linux/netlink.h>
-
+#include <linux/types.h>
 
 /*
  * This file intended to be included by both kernel and user space
diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h
index 0de32cd..af244f4 100644
--- a/include/scsi/scsi_transport.h
+++ b/include/scsi/scsi_transport.h
@@ -22,6 +22,7 @@
 
 #include <linux/transport_class.h>
 #include <linux/blkdev.h>
+#include <linux/bug.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index 2a65167..719faf1 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -126,8 +126,8 @@
 					     incapable of reporting */
 #define FC_PORTSPEED_1GBIT		1
 #define FC_PORTSPEED_2GBIT		2
-#define FC_PORTSPEED_4GBIT		4
-#define FC_PORTSPEED_10GBIT		8
+#define FC_PORTSPEED_10GBIT		4
+#define FC_PORTSPEED_4GBIT		8
 #define FC_PORTSPEED_8GBIT		0x10
 #define FC_PORTSPEED_16GBIT		0x20
 #define FC_PORTSPEED_NOT_NEGOTIATED	(1 << 15) /* Speed not established */
@@ -486,6 +486,13 @@
 	u32 maxframe_size;
 	u16 max_npiv_vports;
 	char serial_number[FC_SERIAL_NUMBER_SIZE];
+	char manufacturer[FC_SERIAL_NUMBER_SIZE];
+	char model[FC_SYMBOLIC_NAME_SIZE];
+	char model_description[FC_SYMBOLIC_NAME_SIZE];
+	char hardware_version[FC_VERSION_STRING_SIZE];
+	char driver_version[FC_VERSION_STRING_SIZE];
+	char firmware_version[FC_VERSION_STRING_SIZE];
+	char optionrom_version[FC_VERSION_STRING_SIZE];
 
 	/* Dynamic Attributes */
 	u32 port_id;
@@ -541,6 +548,20 @@
 	(((struct fc_host_attrs *)(x)->shost_data)->max_npiv_vports)
 #define fc_host_serial_number(x)	\
 	(((struct fc_host_attrs *)(x)->shost_data)->serial_number)
+#define fc_host_manufacturer(x)	\
+	(((struct fc_host_attrs *)(x)->shost_data)->manufacturer)
+#define fc_host_model(x)	\
+	(((struct fc_host_attrs *)(x)->shost_data)->model)
+#define fc_host_model_description(x)	\
+	(((struct fc_host_attrs *)(x)->shost_data)->model_description)
+#define fc_host_hardware_version(x)	\
+	(((struct fc_host_attrs *)(x)->shost_data)->hardware_version)
+#define fc_host_driver_version(x)	\
+	(((struct fc_host_attrs *)(x)->shost_data)->driver_version)
+#define fc_host_firmware_version(x)	\
+	(((struct fc_host_attrs *)(x)->shost_data)->firmware_version)
+#define fc_host_optionrom_version(x)	\
+	(((struct fc_host_attrs *)(x)->shost_data)->optionrom_version)
 #define fc_host_port_id(x)	\
 	(((struct fc_host_attrs *)(x)->shost_data)->port_id)
 #define fc_host_port_type(x)	\
@@ -700,6 +721,13 @@
 	unsigned long	show_host_supported_speeds:1;
 	unsigned long	show_host_maxframe_size:1;
 	unsigned long	show_host_serial_number:1;
+	unsigned long	show_host_manufacturer:1;
+	unsigned long	show_host_model:1;
+	unsigned long	show_host_model_description:1;
+	unsigned long	show_host_hardware_version:1;
+	unsigned long	show_host_driver_version:1;
+	unsigned long	show_host_firmware_version:1;
+	unsigned long	show_host_optionrom_version:1;
 	/* host dynamic attributes */
 	unsigned long	show_host_port_id:1;
 	unsigned long	show_host_port_type:1;
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 2c3a46d..53f0b36 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -144,6 +144,12 @@
 				int param, char *buf);
 	umode_t (*attr_is_visible)(int param_type, int param);
 	int (*bsg_request)(struct bsg_job *job);
+	int (*send_ping) (struct Scsi_Host *shost, uint32_t iface_num,
+			  uint32_t iface_type, uint32_t payload_size,
+			  uint32_t pid, struct sockaddr *dst_addr);
+	int (*get_chap) (struct Scsi_Host *shost, uint16_t chap_tbl_idx,
+			 uint32_t *num_entries, char *buf);
+	int (*delete_chap) (struct Scsi_Host *shost, uint16_t chap_tbl_idx);
 };
 
 /*
@@ -166,6 +172,17 @@
 			      struct iscsi_transport *transport, uint32_t type,
 			      char *data, uint16_t data_size);
 
+extern void iscsi_post_host_event(uint32_t host_no,
+				  struct iscsi_transport *transport,
+				  enum iscsi_host_event_code code,
+				  uint32_t data_size,
+				  uint8_t *data);
+
+extern void iscsi_ping_comp_event(uint32_t host_no,
+				  struct iscsi_transport *transport,
+				  uint32_t status, uint32_t pid,
+				  uint32_t data_size, uint8_t *data);
+
 struct iscsi_cls_conn {
 	struct list_head conn_list;	/* item in connlist */
 	void *dd_data;			/* LLD private data */
@@ -238,6 +255,8 @@
 	atomic_t nr_scans;
 	struct mutex mutex;
 	struct request_queue *bsg_q;
+	uint32_t port_speed;
+	uint32_t port_state;
 };
 
 #define iscsi_job_to_shost(_job) \
@@ -307,5 +326,8 @@
 					      uint32_t iface_num, int dd_size);
 extern void iscsi_destroy_iface(struct iscsi_iface *iface);
 extern struct iscsi_iface *iscsi_lookup_iface(int handle);
+extern char *iscsi_get_port_speed_name(struct Scsi_Host *shost);
+extern char *iscsi_get_port_state_name(struct Scsi_Host *shost);
+extern int iscsi_is_session_dev(const struct device *dev);
 
 #endif
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
index ffeebc3..98b3a20 100644
--- a/include/scsi/scsi_transport_sas.h
+++ b/include/scsi/scsi_transport_sas.h
@@ -75,7 +75,8 @@
 	/* for the list of phys belonging to a port */
 	struct list_head	port_siblings;
 
-	struct work_struct      reset_work;
+	/* available to the lldd */
+	void			*hostdata;
 };
 
 #define dev_to_phy(d) \
@@ -169,6 +170,8 @@
 	int (*get_bay_identifier)(struct sas_rphy *);
 	int (*phy_reset)(struct sas_phy *, int);
 	int (*phy_enable)(struct sas_phy *, int);
+	int (*phy_setup)(struct sas_phy *);
+	void (*phy_release)(struct sas_phy *);
 	int (*set_phy_speed)(struct sas_phy *, struct sas_phy_linkrates *);
 	int (*smp_handler)(struct Scsi_Host *, struct sas_rphy *, struct request *);
 };
@@ -194,6 +197,7 @@
 extern int sas_rphy_add(struct sas_rphy *);
 extern void sas_rphy_remove(struct sas_rphy *);
 extern void sas_rphy_delete(struct sas_rphy *);
+extern void sas_rphy_unlink(struct sas_rphy *);
 extern int scsi_is_sas_rphy(const struct device *);
 
 struct sas_port *sas_port_alloc(struct device *, int);
@@ -205,6 +209,12 @@
 void sas_port_delete_phy(struct sas_port *, struct sas_phy *);
 void sas_port_mark_backlink(struct sas_port *);
 int scsi_is_sas_port(const struct device *);
+struct sas_phy *sas_port_get_phy(struct sas_port *port);
+static inline void sas_port_put_phy(struct sas_phy *phy)
+{
+	if (phy)
+		put_device(&phy->dev);
+}
 
 extern struct scsi_transport_template *
 sas_attach_transport(struct sas_function_template *);
diff --git a/include/sound/compress_params.h b/include/sound/compress_params.h
index d97d69f..da4a456 100644
--- a/include/sound/compress_params.h
+++ b/include/sound/compress_params.h
@@ -51,6 +51,8 @@
 #ifndef __SND_COMPRESS_PARAMS_H
 #define __SND_COMPRESS_PARAMS_H
 
+#include <linux/types.h>
+
 /* AUDIO CODECS SUPPORTED */
 #define MAX_NUM_CODECS 32
 #define MAX_NUM_CODEC_DESCRIPTORS 32
diff --git a/include/sound/control.h b/include/sound/control.h
index b2796e8..8332e86 100644
--- a/include/sound/control.h
+++ b/include/sound/control.h
@@ -40,7 +40,7 @@
 	snd_ctl_elem_iface_t iface;	/* interface identifier */
 	unsigned int device;		/* device/client number */
 	unsigned int subdevice;		/* subdevice (substream) number */
-	unsigned char *name;		/* ASCII name of item */
+	const unsigned char *name;	/* ASCII name of item */
 	unsigned int index;		/* index of item */
 	unsigned int access;		/* access rights */
 	unsigned int count;		/* count of same elements */
@@ -227,6 +227,11 @@
 	return _snd_ctl_add_slave(master, slave, SND_CTL_SLAVE_NEED_UPDATE);
 }
 
+int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kctl,
+			     void (*hook)(void *private_data, int),
+			     void *private_data);
+void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kctl);
+
 /*
  * Helper functions for jack-detection controls
  */
diff --git a/include/sound/core.h b/include/sound/core.h
index cea1b54..b6e0f57 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -26,7 +26,6 @@
 #include <linux/mutex.h>		/* struct mutex */
 #include <linux/rwsem.h>		/* struct rw_semaphore */
 #include <linux/pm.h>			/* pm_message_t */
-#include <linux/device.h>
 #include <linux/stringify.h>
 
 /* number of supported soundcards */
@@ -39,10 +38,10 @@
 #define CONFIG_SND_MAJOR	116	/* standard configuration */
 
 /* forward declarations */
-#ifdef CONFIG_PCI
 struct pci_dev;
-#endif
 struct module;
+struct device;
+struct device_attribute;
 
 /* device allocation stuff */
 
diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h
new file mode 100644
index 0000000..a8fcaa6
--- /dev/null
+++ b/include/sound/dmaengine_pcm.h
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (C) 2012, Analog Devices Inc.
+ *	Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under  the terms of the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __SOUND_DMAENGINE_PCM_H__
+#define __SOUND_DMAENGINE_PCM_H__
+
+#include <sound/pcm.h>
+#include <linux/dmaengine.h>
+
+/**
+ * snd_pcm_substream_to_dma_direction - Get dma_transfer_direction for a PCM
+ *   substream
+ * @substream: PCM substream
+ */
+static inline enum dma_transfer_direction
+snd_pcm_substream_to_dma_direction(const struct snd_pcm_substream *substream)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return DMA_MEM_TO_DEV;
+	else
+		return DMA_DEV_TO_MEM;
+}
+
+void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data);
+void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream);
+
+int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
+	const struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config);
+int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
+snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream);
+
+int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
+	dma_filter_fn filter_fn, void *filter_data);
+int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream);
+
+struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream);
+
+#endif
diff --git a/include/sound/jack.h b/include/sound/jack.h
index 63c7907..5891657 100644
--- a/include/sound/jack.h
+++ b/include/sound/jack.h
@@ -53,6 +53,9 @@
 	SND_JACK_BTN_5		= 0x0200,
 };
 
+/* Keep in sync with definitions above */
+#define SND_JACK_SWITCH_TYPES 6
+
 struct snd_jack {
 	struct input_dev *input_dev;
 	int registered;
diff --git a/include/sound/max9768.h b/include/sound/max9768.h
new file mode 100644
index 0000000..0f78b41
--- /dev/null
+++ b/include/sound/max9768.h
@@ -0,0 +1,24 @@
+/*
+ * Platform data for MAX9768
+ * Copyright (C) 2011, 2012 by Wolfram Sang, Pengutronix e.K.
+ * same licence as the driver
+ */
+
+#ifndef __SOUND_MAX9768_PDATA_H__
+#define __SOUND_MAX9768_PDATA_H__
+
+/**
+ * struct max9768_pdata - optional platform specific MAX9768 configuration
+ * @shdn_gpio:	GPIO to SHDN pin. If not valid, pin must be hardwired HIGH
+ * @mute_gpio:	GPIO to MUTE pin. If not valid, control for mute won't be added
+ * @flags: configuration flags, e.g. set classic PWM mode (check datasheet
+ *         regarding "filterless modulation" which is default).
+ */
+struct max9768_pdata {
+	int shdn_gpio;
+	int mute_gpio;
+	unsigned flags;
+#define MAX9768_FLAG_CLASSIC_PWM	(1 << 0)
+};
+
+#endif /* __SOUND_MAX9768_PDATA_H__*/
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 0cf91b2..0d11128 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -264,7 +264,7 @@
 
 struct snd_pcm_hw_constraint_list {
 	unsigned int count;
-	unsigned int *list;
+	const unsigned int *list;
 	unsigned int mask;
 };
 
@@ -454,6 +454,7 @@
 	void *private_data;
 	void (*private_free) (struct snd_pcm *pcm);
 	struct device *dev; /* actual hw device this belongs to */
+	bool internal; /* pcm is for internal use only */
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
 	struct snd_pcm_oss oss;
 #endif
@@ -475,6 +476,9 @@
 int snd_pcm_new(struct snd_card *card, const char *id, int device,
 		int playback_count, int capture_count,
 		struct snd_pcm **rpcm);
+int snd_pcm_new_internal(struct snd_card *card, const char *id, int device,
+		int playback_count, int capture_count,
+		struct snd_pcm **rpcm);
 int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count);
 
 int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree);
@@ -781,7 +785,8 @@
 			  unsigned int k, struct snd_interval *c);
 void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
 			  const struct snd_interval *b, struct snd_interval *c);
-int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask);
+int snd_interval_list(struct snd_interval *i, unsigned int count,
+		      const unsigned int *list, unsigned int mask);
 int snd_interval_ratnum(struct snd_interval *i,
 			unsigned int rats_count, struct snd_ratnum *rats,
 			unsigned int *nump, unsigned int *denp);
diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h
index 9b1aaca..b457e87 100644
--- a/include/sound/sh_fsi.h
+++ b/include/sound/sh_fsi.h
@@ -72,10 +72,16 @@
 #define SH_FSI_BPFMD_32		(5 << 4)
 #define SH_FSI_BPFMD_16		(6 << 4)
 
+struct sh_fsi_port_info {
+	unsigned long flags;
+	int tx_id;
+	int rx_id;
+	int (*set_rate)(struct device *dev, int rate, int enable);
+};
+
 struct sh_fsi_platform_info {
-	unsigned long porta_flags;
-	unsigned long portb_flags;
-	int (*set_rate)(struct device *dev, int is_porta, int rate, int enable);
+	struct sh_fsi_port_info port_a;
+	struct sh_fsi_port_info port_b;
 };
 
 /*
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 2413acc..c429f24 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -17,6 +17,7 @@
 #include <linux/list.h>
 
 struct snd_pcm_substream;
+struct snd_soc_dapm_widget;
 
 /*
  * DAI hardware audio formats.
@@ -238,6 +239,9 @@
 	unsigned char pop_wait:1;
 	unsigned char probed:1;
 
+	struct snd_soc_dapm_widget *playback_widget;
+	struct snd_soc_dapm_widget *capture_widget;
+
 	/* DAI DMA data */
 	void *playback_dma_data;
 	void *capture_dma_data;
@@ -246,10 +250,9 @@
 	unsigned int rate;
 
 	/* parent platform/codec */
-	union {
-		struct snd_soc_platform *platform;
-		struct snd_soc_codec *codec;
-	};
+	struct snd_soc_platform *platform;
+	struct snd_soc_codec *codec;
+
 	struct snd_soc_card *card;
 
 	struct list_head list;
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index d26a9b7..8da3c24 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -13,10 +13,11 @@
 #ifndef __LINUX_SND_SOC_DAPM_H
 #define __LINUX_SND_SOC_DAPM_H
 
-#include <linux/device.h>
 #include <linux/types.h>
 #include <sound/control.h>
 
+struct device;
+
 /* widget has no PM register bit */
 #define SND_SOC_NOPM	-1
 
@@ -243,6 +244,10 @@
 {	.id = snd_soc_dapm_supply, .name = wname, .reg = wreg,	\
 	.shift = wshift, .invert = winvert, .event = wevent, \
 	.event_flags = wflags}
+#define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay) \
+{	.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 }
 
 /* dapm kcontrol types */
 #define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
@@ -322,6 +327,8 @@
 
 int dapm_reg_event(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol, int event);
+int dapm_regulator_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event);
 
 /* dapm controls */
 int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
@@ -346,11 +353,12 @@
 	struct snd_ctl_elem_value *uncontrol);
 int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *uncontrol);
-int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
-	const struct snd_soc_dapm_widget *widget);
 int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
 	const struct snd_soc_dapm_widget *widget,
 	int num);
+int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
+				 struct snd_soc_dai *dai);
+int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
 
 /* dapm path setup */
 int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm);
@@ -361,10 +369,16 @@
 			     const struct snd_soc_dapm_route *route, int num);
 
 /* dapm events */
-int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
-	const char *stream, int event);
+int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+			      struct snd_soc_dai *dai, int event);
 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);
+
 /* dapm sys fs - used by the core */
 int snd_soc_dapm_sys_add(struct device *dev);
 void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
@@ -411,9 +425,11 @@
 	snd_soc_dapm_pre,			/* machine specific pre widget - exec first */
 	snd_soc_dapm_post,			/* machine specific post widget - exec last */
 	snd_soc_dapm_supply,		/* power/clock supply */
+	snd_soc_dapm_regulator_supply,	/* external regulator */
 	snd_soc_dapm_aif_in,		/* audio interface input */
 	snd_soc_dapm_aif_out,		/* audio interface output */
 	snd_soc_dapm_siggen,		/* signal generator */
+	snd_soc_dapm_dai,		/* link to DAI structure */
 };
 
 /*
@@ -434,8 +450,8 @@
 
 /* dapm audio path between two widgets */
 struct snd_soc_dapm_path {
-	char *name;
-	char *long_name;
+	const char *name;
+	const char *long_name;
 
 	/* source (input) and sink (output) widgets */
 	struct snd_soc_dapm_widget *source;
@@ -458,13 +474,15 @@
 /* dapm widget */
 struct snd_soc_dapm_widget {
 	enum snd_soc_dapm_type id;
-	char *name;		/* widget name */
-	char *sname;	/* stream name */
+	const char *name;		/* widget name */
+	const char *sname;	/* stream name */
 	struct snd_soc_codec *codec;
 	struct snd_soc_platform *platform;
 	struct list_head list;
 	struct snd_soc_dapm_context *dapm;
 
+	void *priv;				/* widget specific data */
+
 	/* dapm control */
 	short reg;						/* negative reg = no direct dapm */
 	unsigned char shift;			/* bits to shift */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 0992dff..2ebf787 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -185,6 +185,20 @@
 		 .rreg = xreg_right, .shift = xshift, \
 		 .min = xmin, .max = xmax} }
 
+#define SND_SOC_BYTES(xname, xbase, xregs)		      \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,   \
+	.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
+	.put = snd_soc_bytes_put, .private_value =	      \
+		((unsigned long)&(struct soc_bytes)           \
+		{.base = xbase, .num_regs = xregs }) }
+
+#define SND_SOC_BYTES_MASK(xname, xbase, xregs, xmask)	      \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,   \
+	.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
+	.put = snd_soc_bytes_put, .private_value =	      \
+		((unsigned long)&(struct soc_bytes)           \
+		{.base = xbase, .num_regs = xregs,	      \
+		 .mask = xmask }) }
 
 /*
  * Simplified versions of above macros, declaring a struct and calculating
@@ -366,12 +380,16 @@
  *Controls
  */
 struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
-				  void *data, char *long_name,
+				  void *data, const char *long_name,
 				  const char *prefix);
-int snd_soc_add_controls(struct snd_soc_codec *codec,
+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,
 	const struct snd_kcontrol_new *controls, int num_controls);
+int snd_soc_add_card_controls(struct snd_soc_card *soc_card,
+	const struct snd_kcontrol_new *controls, int num_controls);
+int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
+	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,
@@ -409,6 +427,13 @@
 	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
+		       struct snd_ctl_elem_info *uinfo);
+int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol);
+int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol);
+
 
 /**
  * struct snd_soc_reg_access - Describes whether a given register is
@@ -505,6 +530,7 @@
 	unsigned int rate_max;		/* max rate */
 	unsigned int channels_min;	/* min channels */
 	unsigned int channels_max;	/* max channels */
+	unsigned int sig_bits;		/* number of bits of content */
 };
 
 /* SoC audio ops */
@@ -559,6 +585,7 @@
 	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 */
 	u32 cache_sync; /* Cache needs to be synced to hardware */
 
@@ -637,6 +664,8 @@
 	/* codec stream completion event */
 	int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);
 
+	bool ignore_pmdown_time;  /* Doesn't benefit from pmdown delay */
+
 	/* probe ordering - for components with runtime dependencies */
 	int probe_order;
 	int remove_order;
@@ -689,6 +718,7 @@
 	int id;
 	struct device *dev;
 	struct snd_soc_platform_driver *driver;
+	struct mutex mutex;
 
 	unsigned int suspended:1; /* platform is suspended */
 	unsigned int probed:1;
@@ -698,6 +728,11 @@
 	struct list_head card_list;
 
 	struct snd_soc_dapm_context dapm;
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs_platform_root;
+	struct dentry *debugfs_dapm;
+#endif
 };
 
 struct snd_soc_dai_link {
@@ -875,6 +910,12 @@
 	unsigned int reg, rreg, shift, rshift, invert;
 };
 
+struct soc_bytes {
+	int base;
+	int num_regs;
+	u32 mask;
+};
+
 /* enumerated kcontrol */
 struct soc_enum {
 	unsigned short reg;
diff --git a/include/sound/tea575x-tuner.h b/include/sound/tea575x-tuner.h
index 726e947..ec3f910 100644
--- a/include/sound/tea575x-tuner.h
+++ b/include/sound/tea575x-tuner.h
@@ -25,6 +25,7 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
 
 #define TEA575X_FMIF	10700
 
@@ -42,13 +43,16 @@
 };
 
 struct snd_tea575x {
+	struct v4l2_device *v4l2_dev;
 	struct video_device vd;		/* video device */
+	int radio_nr;			/* radio_nr */
 	bool tea5759;			/* 5759 chip is present */
+	bool cannot_read_data;		/* Device cannot read the data pin */
 	bool mute;			/* Device is muted? */
 	bool stereo;			/* receiving stereo */
 	bool tuned;			/* tuned to a station */
 	unsigned int val;		/* hw value */
-	unsigned long freq;		/* frequency */
+	u32 freq;			/* frequency */
 	struct mutex mutex;
 	struct snd_tea575x_ops *ops;
 	void *private_data;
diff --git a/include/sound/version.h b/include/sound/version.h
index 8fc5321..cc75024 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
 /* include/version.h */
-#define CONFIG_SND_VERSION "1.0.24"
+#define CONFIG_SND_VERSION "1.0.25"
 #define CONFIG_SND_DATE ""
diff --git a/include/sound/wm2200.h b/include/sound/wm2200.h
new file mode 100644
index 0000000..79bf55b
--- /dev/null
+++ b/include/sound/wm2200.h
@@ -0,0 +1,41 @@
+/*
+ * linux/sound/wm2200.h -- Platform data for WM2200
+ *
+ * Copyright 2012 Wolfson Microelectronics. PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_WM2200_H
+#define __LINUX_SND_WM2200_H
+
+#define WM2200_GPIO_SET 0x10000
+
+enum wm2200_in_mode {
+	WM2200_IN_SE = 0,
+	WM2200_IN_DIFF = 1,
+	WM2200_IN_DMIC = 2,
+};
+
+enum wm2200_dmic_sup {
+	WM2200_DMIC_SUP_MICVDD = 0,
+	WM2200_DMIC_SUP_MICBIAS1 = 1,
+	WM2200_DMIC_SUP_MICBIAS2 = 2,
+};
+
+struct wm2200_pdata {
+	int reset;      /** GPIO controlling /RESET, if any */
+	int ldo_ena;    /** GPIO controlling LODENA, if any */
+	int irq_flags;
+
+	int gpio_defaults[4];
+
+	enum wm2200_in_mode in_mode[3];
+	enum wm2200_dmic_sup dmic_sup[3];
+
+	int micbias_cfg[2];  /** Register value to configure MICBIAS */
+};
+
+#endif
diff --git a/include/sound/wm8962.h b/include/sound/wm8962.h
index 1750bed7..79e6d42 100644
--- a/include/sound/wm8962.h
+++ b/include/sound/wm8962.h
@@ -49,6 +49,12 @@
 	bool irq_active_low;
 
 	bool spk_mono;   /* Speaker outputs tied together as mono */
+
+	/**
+	 * This flag should be set if one or both IN4 inputs is wired
+	 * in a DC measurement configuration.
+	 */
+	bool in4_dc_measure;
 };
 
 #endif
diff --git a/include/sound/ymfpci.h b/include/sound/ymfpci.h
index 444cd6b..4119966 100644
--- a/include/sound/ymfpci.h
+++ b/include/sound/ymfpci.h
@@ -366,6 +366,8 @@
 #ifdef CONFIG_PM
 	u32 *saved_regs;
 	u32 saved_ydsxgr_mode;
+	u16 saved_dsxg_legacy;
+	u16 saved_dsxg_elegacy;
 #endif
 };
 
diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h
index e5e6ff9..8c9ff1b 100644
--- a/include/target/target_core_backend.h
+++ b/include/target/target_core_backend.h
@@ -62,4 +62,6 @@
 void	*transport_kmap_data_sg(struct se_cmd *);
 void	transport_kunmap_data_sg(struct se_cmd *);
 
+void	array_free(void *array, int n);
+
 #endif /* TARGET_CORE_BACKEND_H */
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index dc4e345..aaccc5f 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -9,7 +9,7 @@
 #include <net/sock.h>
 #include <net/tcp.h>
 
-#define TARGET_CORE_MOD_VERSION		"v4.1.0-rc1-ml"
+#define TARGET_CORE_MOD_VERSION		"v4.1.0-rc2-ml"
 #define TARGET_CORE_VERSION		TARGET_CORE_MOD_VERSION
 
 /* Maximum Number of LUNs per Target Portal Group */
@@ -86,6 +86,8 @@
 #define DA_UNMAP_GRANULARITY_DEFAULT		0
 /* Default unmap_granularity_alignment */
 #define DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT	0
+/* Default max transfer length */
+#define DA_FABRIC_MAX_SECTORS			8192
 /* Emulation for Direct Page Out */
 #define DA_EMULATE_DPO				0
 /* Emulation for Forced Unit Access WRITEs */
@@ -118,9 +120,9 @@
 /* Queue Algorithm Modifier default for restricted reordering in control mode page */
 #define DA_EMULATE_REST_REORD			0
 
+#define SE_INQUIRY_BUF				512
 #define SE_MODE_PAGE_BUF			512
 
-
 /* struct se_hba->hba_flags */
 enum hba_flags_table {
 	HBA_FLAGS_INTERNAL_USE	= 0x01,
@@ -169,7 +171,8 @@
 	SCF_EMULATED_TASK_SENSE		= 0x00000004,
 	SCF_SCSI_DATA_SG_IO_CDB		= 0x00000008,
 	SCF_SCSI_CONTROL_SG_IO_CDB	= 0x00000010,
-	SCF_SCSI_NON_DATA_CDB		= 0x00000040,
+	SCF_SCSI_NON_DATA_CDB		= 0x00000020,
+	SCF_SCSI_TMR_CDB		= 0x00000040,
 	SCF_SCSI_CDB_EXCEPTION		= 0x00000080,
 	SCF_SCSI_RESERVATION_CONFLICT	= 0x00000100,
 	SCF_FUA				= 0x00000200,
@@ -183,7 +186,8 @@
 	SCF_ALUA_NON_OPTIMIZED		= 0x00040000,
 	SCF_DELAYED_CMD_FROM_SAM_ATTR	= 0x00080000,
 	SCF_UNUSED			= 0x00100000,
-	SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00400000,
+	SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00200000,
+	SCF_ACK_KREF			= 0x00400000,
 };
 
 /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
@@ -474,12 +478,6 @@
 	struct t10_reservation_ops pr_ops;
 };
 
-struct se_queue_req {
-	int			state;
-	struct se_cmd		*cmd;
-	struct list_head	qr_list;
-};
-
 struct se_queue_obj {
 	atomic_t		queue_cnt;
 	spinlock_t		cmd_queue_lock;
@@ -504,6 +502,24 @@
 	struct completion	task_stop_comp;
 };
 
+struct se_tmr_req {
+	/* Task Management function to be performed */
+	u8			function;
+	/* Task Management response to send */
+	u8			response;
+	int			call_transport;
+	/* Reference to ITT that Task Mgmt should be performed */
+	u32			ref_task_tag;
+	/* 64-bit encoded SAM LUN from $FABRIC_MOD TMR header */
+	u64			ref_task_lun;
+	void 			*fabric_tmr_ptr;
+	struct se_cmd		*task_cmd;
+	struct se_cmd		*ref_cmd;
+	struct se_device	*tmr_dev;
+	struct se_lun		*tmr_lun;
+	struct list_head	tmr_list;
+};
+
 struct se_cmd {
 	/* SAM response code being sent to initiator */
 	u8			scsi_status;
@@ -555,23 +571,23 @@
 	unsigned char		*t_task_cdb;
 	unsigned char		__t_task_cdb[TCM_MAX_COMMAND_SIZE];
 	unsigned long long	t_task_lba;
-	int			t_tasks_failed;
 	u32			t_tasks_sg_chained_no;
 	atomic_t		t_fe_count;
 	atomic_t		t_se_count;
 	atomic_t		t_task_cdbs_left;
 	atomic_t		t_task_cdbs_ex_left;
 	atomic_t		t_task_cdbs_sent;
-	atomic_t		t_transport_aborted;
-	atomic_t		t_transport_active;
-	atomic_t		t_transport_complete;
-	atomic_t		t_transport_queue_active;
-	atomic_t		t_transport_sent;
-	atomic_t		t_transport_stop;
-	atomic_t		transport_dev_active;
-	atomic_t		transport_lun_active;
-	atomic_t		transport_lun_fe_stop;
-	atomic_t		transport_lun_stop;
+	unsigned int		transport_state;
+#define CMD_T_ABORTED		(1 << 0)
+#define CMD_T_ACTIVE		(1 << 1)
+#define CMD_T_COMPLETE		(1 << 2)
+#define CMD_T_QUEUED		(1 << 3)
+#define CMD_T_SENT		(1 << 4)
+#define CMD_T_STOP		(1 << 5)
+#define CMD_T_FAILED		(1 << 6)
+#define CMD_T_LUN_STOP		(1 << 7)
+#define CMD_T_LUN_FE_STOP	(1 << 8)
+#define CMD_T_DEV_ACTIVE	(1 << 9)
 	spinlock_t		t_state_lock;
 	struct completion	t_transport_stop_comp;
 	struct completion	transport_lun_fe_stop_comp;
@@ -592,24 +608,6 @@
 
 };
 
-struct se_tmr_req {
-	/* Task Management function to be preformed */
-	u8			function;
-	/* Task Management response to send */
-	u8			response;
-	int			call_transport;
-	/* Reference to ITT that Task Mgmt should be preformed */
-	u32			ref_task_tag;
-	/* 64-bit encoded SAM LUN from $FABRIC_MOD TMR header */
-	u64			ref_task_lun;
-	void 			*fabric_tmr_ptr;
-	struct se_cmd		*task_cmd;
-	struct se_cmd		*ref_cmd;
-	struct se_device	*tmr_dev;
-	struct se_lun		*tmr_lun;
-	struct list_head	tmr_list;
-};
-
 struct se_ua {
 	u8			ua_asc;
 	u8			ua_ascq;
@@ -622,6 +620,7 @@
 	char			initiatorname[TRANSPORT_IQN_LEN];
 	/* Used to signal demo mode created ACL, disabled by default */
 	bool			dynamic_node_acl;
+	bool			acl_stop:1;
 	u32			queue_depth;
 	u32			acl_index;
 	u64			num_cmds;
@@ -630,7 +629,7 @@
 	spinlock_t		stats_lock;
 	/* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */
 	atomic_t		acl_pr_ref_count;
-	struct se_dev_entry	*device_list;
+	struct se_dev_entry	**device_list;
 	struct se_session	*nacl_sess;
 	struct se_portal_group *se_tpg;
 	spinlock_t		device_list_lock;
@@ -643,6 +642,8 @@
 	struct config_group	*acl_default_groups[5];
 	struct list_head	acl_list;
 	struct list_head	acl_sess_list;
+	struct completion	acl_free_comp;
+	struct kref		acl_kref;
 };
 
 struct se_session {
@@ -656,6 +657,7 @@
 	struct list_head	sess_cmd_list;
 	struct list_head	sess_wait_list;
 	spinlock_t		sess_cmd_lock;
+	struct kref		sess_kref;
 };
 
 struct se_device;
@@ -730,6 +732,7 @@
 	u32		block_size;
 	u32		hw_max_sectors;
 	u32		max_sectors;
+	u32		fabric_max_sectors;
 	u32		optimal_sectors;
 	u32		hw_queue_depth;
 	u32		queue_depth;
@@ -931,7 +934,7 @@
 	struct list_head	se_tpg_node;
 	/* linked list for initiator ACL list */
 	struct list_head	acl_node_list;
-	struct se_lun		*tpg_lun_list;
+	struct se_lun		**tpg_lun_list;
 	struct se_lun		tpg_virt_lun0;
 	/* List of TCM sessions associated wth this TPG */
 	struct list_head	tpg_sess_list;
diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h
index d36fad3..10c6908 100644
--- a/include/target/target_core_fabric.h
+++ b/include/target/target_core_fabric.h
@@ -58,9 +58,6 @@
 	 */
 	int (*shutdown_session)(struct se_session *);
 	void (*close_session)(struct se_session *);
-	void (*stop_session)(struct se_session *, int, int);
-	void (*fall_back_to_erl0)(struct se_session *);
-	int (*sess_logged_in)(struct se_session *);
 	u32 (*sess_get_index)(struct se_session *);
 	/*
 	 * Used only for SCSI fabrics that contain multi-value TransportIDs
@@ -78,7 +75,6 @@
 	int (*queue_tm_rsp)(struct se_cmd *);
 	u16 (*set_fabric_sense_len)(struct se_cmd *, u32);
 	u16 (*get_fabric_sense_len)(void);
-	int (*is_state_remove)(struct se_cmd *);
 	/*
 	 * fabric module calls for target_core_fabric_configfs.c
 	 */
@@ -105,7 +101,10 @@
 		struct se_node_acl *, struct se_session *, void *);
 void	transport_register_session(struct se_portal_group *,
 		struct se_node_acl *, struct se_session *, void *);
+void	target_get_session(struct se_session *);
+int	target_put_session(struct se_session *);
 void	transport_free_session(struct se_session *);
+void	target_put_nacl(struct se_node_acl *);
 void	transport_deregister_session_configfs(struct se_session *);
 void	transport_deregister_session(struct se_session *);
 
@@ -116,6 +115,10 @@
 int	transport_generic_allocate_tasks(struct se_cmd *, unsigned char *);
 void	target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *,
 		unsigned char *, u32, u32, int, int, int);
+int	target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
+		unsigned char *sense, u32 unpacked_lun,
+		void *fabric_tmr_ptr, unsigned char tm_type,
+		gfp_t, unsigned int, int);
 int	transport_handle_cdb_direct(struct se_cmd *);
 int	transport_generic_handle_cdb_map(struct se_cmd *);
 int	transport_generic_handle_data(struct se_cmd *);
@@ -139,9 +142,10 @@
 
 int	core_alua_check_nonop_delay(struct se_cmd *);
 
-struct se_tmr_req *core_tmr_alloc_req(struct se_cmd *, void *, u8, gfp_t);
+int	core_tmr_alloc_req(struct se_cmd *, void *, u8, gfp_t);
 void	core_tmr_release_req(struct se_tmr_req *);
 int	transport_generic_handle_tmr(struct se_cmd *);
+void	transport_generic_request_failure(struct se_cmd *);
 int	transport_lookup_tmr_lun(struct se_cmd *, u32);
 
 struct se_node_acl *core_tpg_check_initiator_node_acl(struct se_portal_group *,
diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h
index 84f3001..91b91e8 100644
--- a/include/trace/events/btrfs.h
+++ b/include/trace/events/btrfs.h
@@ -6,6 +6,7 @@
 
 #include <linux/writeback.h>
 #include <linux/tracepoint.h>
+#include <trace/events/gfpflags.h>
 
 struct btrfs_root;
 struct btrfs_fs_info;
@@ -862,6 +863,49 @@
 		  __entry->size, __entry->max_size, __entry->bitmap)
 );
 
+struct extent_state;
+TRACE_EVENT(alloc_extent_state,
+
+	TP_PROTO(struct extent_state *state, gfp_t mask, unsigned long IP),
+
+	TP_ARGS(state, mask, IP),
+
+	TP_STRUCT__entry(
+		__field(struct extent_state *, state)
+		__field(gfp_t, mask)
+		__field(unsigned long, ip)
+	),
+
+	TP_fast_assign(
+		__entry->state	= state,
+		__entry->mask	= mask,
+		__entry->ip	= IP
+	),
+
+	TP_printk("state=%p; mask = %s; caller = %pF", __entry->state,
+		  show_gfp_flags(__entry->mask), (void *)__entry->ip)
+);
+
+TRACE_EVENT(free_extent_state,
+
+	TP_PROTO(struct extent_state *state, unsigned long IP),
+
+	TP_ARGS(state, IP),
+
+	TP_STRUCT__entry(
+		__field(struct extent_state *, state)
+		__field(unsigned long, ip)
+	),
+
+	TP_fast_assign(
+		__entry->state	= state,
+		__entry->ip = IP
+	),
+
+	TP_printk(" state=%p; caller = %pF", __entry->state,
+		  (void *)__entry->ip)
+);
+
 #endif /* _TRACE_BTRFS_H */
 
 /* This part must be outside protection */
diff --git a/include/trace/events/jbd2.h b/include/trace/events/jbd2.h
index 7596441..127993d 100644
--- a/include/trace/events/jbd2.h
+++ b/include/trace/events/jbd2.h
@@ -81,6 +81,13 @@
 	TP_ARGS(journal, commit_transaction)
 );
 
+DEFINE_EVENT(jbd2_commit, jbd2_drop_transaction,
+
+	TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
+
+	TP_ARGS(journal, commit_transaction)
+);
+
 TRACE_EVENT(jbd2_end_commit,
 	TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
 
@@ -200,7 +207,7 @@
 		  __entry->forced_to_close, __entry->written, __entry->dropped)
 );
 
-TRACE_EVENT(jbd2_cleanup_journal_tail,
+TRACE_EVENT(jbd2_update_log_tail,
 
 	TP_PROTO(journal_t *journal, tid_t first_tid,
 		 unsigned long block_nr, unsigned long freed),
@@ -229,6 +236,26 @@
 		  __entry->block_nr, __entry->freed)
 );
 
+TRACE_EVENT(jbd2_write_superblock,
+
+	TP_PROTO(journal_t *journal, int write_op),
+
+	TP_ARGS(journal, write_op),
+
+	TP_STRUCT__entry(
+		__field(	dev_t,  dev			)
+		__field(	  int,  write_op		)
+	),
+
+	TP_fast_assign(
+		__entry->dev		= journal->j_fs_dev->bd_dev;
+		__entry->write_op	= write_op;
+	),
+
+	TP_printk("dev %d,%d write_op %x", MAJOR(__entry->dev),
+		  MINOR(__entry->dev), __entry->write_op)
+);
+
 #endif /* _TRACE_JBD2_H */
 
 /* This part must be outside protection */
diff --git a/include/trace/events/regmap.h b/include/trace/events/regmap.h
index 12fbf43..41a7dbd 100644
--- a/include/trace/events/regmap.h
+++ b/include/trace/events/regmap.h
@@ -4,10 +4,10 @@
 #if !defined(_TRACE_REGMAP_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_REGMAP_H
 
-#include <linux/device.h>
 #include <linux/ktime.h>
 #include <linux/tracepoint.h>
 
+struct device;
 struct regmap;
 
 /*
@@ -139,6 +139,42 @@
 		  __get_str(type), __get_str(status))
 );
 
+DECLARE_EVENT_CLASS(regmap_bool,
+
+	TP_PROTO(struct device *dev, bool flag),
+
+	TP_ARGS(dev, flag),
+
+	TP_STRUCT__entry(
+		__string(	name,		dev_name(dev)	)
+		__field(	int,		flag		)
+	),
+
+	TP_fast_assign(
+		__assign_str(name, dev_name(dev));
+		__entry->flag = flag;
+	),
+
+	TP_printk("%s flag=%d", __get_str(name),
+		  (int)__entry->flag)
+);
+
+DEFINE_EVENT(regmap_bool, regmap_cache_only,
+
+	TP_PROTO(struct device *dev, bool flag),
+
+	TP_ARGS(dev, flag)
+
+);
+
+DEFINE_EVENT(regmap_bool, regmap_cache_bypass,
+
+	TP_PROTO(struct device *dev, bool flag),
+
+	TP_ARGS(dev, flag)
+
+);
+
 #endif /* _TRACE_REGMAP_H */
 
 /* This part must be outside protection */
diff --git a/include/trace/events/rpm.h b/include/trace/events/rpm.h
index d62c558..33f85b6 100644
--- a/include/trace/events/rpm.h
+++ b/include/trace/events/rpm.h
@@ -7,7 +7,8 @@
 
 #include <linux/ktime.h>
 #include <linux/tracepoint.h>
-#include <linux/device.h>
+
+struct device;
 
 /*
  * The rpm_internal events are used for tracing some important
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index fbc7b1a..ea7a203 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -295,7 +295,7 @@
 	TP_fast_assign(
 		__assign_str(filename, bprm->filename);
 		__entry->pid		= p->pid;
-		__entry->old_pid	= p->pid;
+		__entry->old_pid	= old_pid;
 	),
 
 	TP_printk("filename=%s pid=%d old_pid=%d", __get_str(filename),
diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h
new file mode 100644
index 0000000..43be87d
--- /dev/null
+++ b/include/trace/events/sunrpc.h
@@ -0,0 +1,177 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM sunrpc
+
+#if !defined(_TRACE_SUNRPC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_SUNRPC_H
+
+#include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(rpc_task_status,
+
+	TP_PROTO(struct rpc_task *task),
+
+	TP_ARGS(task),
+
+	TP_STRUCT__entry(
+		__field(const struct rpc_task *, task)
+		__field(const struct rpc_clnt *, clnt)
+		__field(int, status)
+	),
+
+	TP_fast_assign(
+		__entry->task = task;
+		__entry->clnt = task->tk_client;
+		__entry->status = task->tk_status;
+	),
+
+	TP_printk("task:%p@%p, status %d",__entry->task, __entry->clnt, __entry->status)
+);
+
+DEFINE_EVENT(rpc_task_status, rpc_call_status,
+	TP_PROTO(struct rpc_task *task),
+
+	TP_ARGS(task)
+);
+
+DEFINE_EVENT(rpc_task_status, rpc_bind_status,
+	TP_PROTO(struct rpc_task *task),
+
+	TP_ARGS(task)
+);
+
+TRACE_EVENT(rpc_connect_status,
+	TP_PROTO(struct rpc_task *task, int status),
+
+	TP_ARGS(task, status),
+
+	TP_STRUCT__entry(
+		__field(const struct rpc_task *, task)
+		__field(const struct rpc_clnt *, clnt)
+		__field(int, status)
+	),
+
+	TP_fast_assign(
+		__entry->task = task;
+		__entry->clnt = task->tk_client;
+		__entry->status = status;
+	),
+
+	TP_printk("task:%p@%p, status %d",__entry->task, __entry->clnt, __entry->status)
+);
+
+DECLARE_EVENT_CLASS(rpc_task_running,
+
+	TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
+
+	TP_ARGS(clnt, task, action),
+
+	TP_STRUCT__entry(
+		__field(const struct rpc_clnt *, clnt)
+		__field(const struct rpc_task *, task)
+		__field(const void *, action)
+		__field(unsigned long, runstate)
+		__field(int, status)
+		__field(unsigned short, flags)
+		),
+
+	TP_fast_assign(
+		__entry->clnt = clnt;
+		__entry->task = task;
+		__entry->action = action;
+		__entry->runstate = task->tk_runstate;
+		__entry->status = task->tk_status;
+		__entry->flags = task->tk_flags;
+		),
+
+	TP_printk("task:%p@%p flags=%4.4x state=%4.4lx status=%d action=%pf",
+		__entry->task,
+		__entry->clnt,
+		__entry->flags,
+		__entry->runstate,
+		__entry->status,
+		__entry->action
+		)
+);
+
+DEFINE_EVENT(rpc_task_running, rpc_task_begin,
+
+	TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
+
+	TP_ARGS(clnt, task, action)
+
+);
+
+DEFINE_EVENT(rpc_task_running, rpc_task_run_action,
+
+	TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
+
+	TP_ARGS(clnt, task, action)
+
+);
+
+DEFINE_EVENT(rpc_task_running, rpc_task_complete,
+
+	TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
+
+	TP_ARGS(clnt, task, action)
+
+);
+
+DECLARE_EVENT_CLASS(rpc_task_queued,
+
+	TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q),
+
+	TP_ARGS(clnt, task, q),
+
+	TP_STRUCT__entry(
+		__field(const struct rpc_clnt *, clnt)
+		__field(const struct rpc_task *, task)
+		__field(unsigned long, timeout)
+		__field(unsigned long, runstate)
+		__field(int, status)
+		__field(unsigned short, flags)
+		__string(q_name, rpc_qname(q))
+		),
+
+	TP_fast_assign(
+		__entry->clnt = clnt;
+		__entry->task = task;
+		__entry->timeout = task->tk_timeout;
+		__entry->runstate = task->tk_runstate;
+		__entry->status = task->tk_status;
+		__entry->flags = task->tk_flags;
+		__assign_str(q_name, rpc_qname(q));
+		),
+
+	TP_printk("task:%p@%p flags=%4.4x state=%4.4lx status=%d timeout=%lu queue=%s",
+		__entry->task,
+		__entry->clnt,
+		__entry->flags,
+		__entry->runstate,
+		__entry->status,
+		__entry->timeout,
+		__get_str(q_name)
+		)
+);
+
+DEFINE_EVENT(rpc_task_queued, rpc_task_sleep,
+
+	TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q),
+
+	TP_ARGS(clnt, task, q)
+
+);
+
+DEFINE_EVENT(rpc_task_queued, rpc_task_wakeup,
+
+	TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q),
+
+	TP_ARGS(clnt, task, q)
+
+);
+
+#endif /* _TRACE_SUNRPC_H */
+
+#include <trace/define_trace.h>
diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h
index 5973410..7b81887 100644
--- a/include/trace/events/writeback.h
+++ b/include/trace/events/writeback.h
@@ -5,7 +5,6 @@
 #define _TRACE_WRITEBACK_H
 
 #include <linux/backing-dev.h>
-#include <linux/device.h>
 #include <linux/writeback.h>
 
 #define show_inode_state(state)					\
diff --git a/include/video/exynos_dp.h b/include/video/exynos_dp.h
new file mode 100644
index 0000000..8847a9d
--- /dev/null
+++ b/include/video/exynos_dp.h
@@ -0,0 +1,131 @@
+/*
+ * Samsung SoC DP device support
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * 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.
+ */
+
+#ifndef _EXYNOS_DP_H
+#define _EXYNOS_DP_H
+
+#define DP_TIMEOUT_LOOP_COUNT 100
+#define MAX_CR_LOOP 5
+#define MAX_EQ_LOOP 4
+
+enum link_rate_type {
+	LINK_RATE_1_62GBPS = 0x06,
+	LINK_RATE_2_70GBPS = 0x0a
+};
+
+enum link_lane_count_type {
+	LANE_COUNT1 = 1,
+	LANE_COUNT2 = 2,
+	LANE_COUNT4 = 4
+};
+
+enum link_training_state {
+	START,
+	CLOCK_RECOVERY,
+	EQUALIZER_TRAINING,
+	FINISHED,
+	FAILED
+};
+
+enum voltage_swing_level {
+	VOLTAGE_LEVEL_0,
+	VOLTAGE_LEVEL_1,
+	VOLTAGE_LEVEL_2,
+	VOLTAGE_LEVEL_3,
+};
+
+enum pre_emphasis_level {
+	PRE_EMPHASIS_LEVEL_0,
+	PRE_EMPHASIS_LEVEL_1,
+	PRE_EMPHASIS_LEVEL_2,
+	PRE_EMPHASIS_LEVEL_3,
+};
+
+enum pattern_set {
+	PRBS7,
+	D10_2,
+	TRAINING_PTN1,
+	TRAINING_PTN2,
+	DP_NONE
+};
+
+enum color_space {
+	COLOR_RGB,
+	COLOR_YCBCR422,
+	COLOR_YCBCR444
+};
+
+enum color_depth {
+	COLOR_6,
+	COLOR_8,
+	COLOR_10,
+	COLOR_12
+};
+
+enum color_coefficient {
+	COLOR_YCBCR601,
+	COLOR_YCBCR709
+};
+
+enum dynamic_range {
+	VESA,
+	CEA
+};
+
+enum pll_status {
+	PLL_UNLOCKED,
+	PLL_LOCKED
+};
+
+enum clock_recovery_m_value_type {
+	CALCULATED_M,
+	REGISTER_M
+};
+
+enum video_timing_recognition_type {
+	VIDEO_TIMING_FROM_CAPTURE,
+	VIDEO_TIMING_FROM_REGISTER
+};
+
+enum analog_power_block {
+	AUX_BLOCK,
+	CH0_BLOCK,
+	CH1_BLOCK,
+	CH2_BLOCK,
+	CH3_BLOCK,
+	ANALOG_TOTAL,
+	POWER_ALL
+};
+
+struct video_info {
+	char *name;
+
+	bool h_sync_polarity;
+	bool v_sync_polarity;
+	bool interlaced;
+
+	enum color_space color_space;
+	enum dynamic_range dynamic_range;
+	enum color_coefficient ycbcr_coeff;
+	enum color_depth color_depth;
+
+	enum link_rate_type link_rate;
+	enum link_lane_count_type lane_count;
+};
+
+struct exynos_dp_platdata {
+	struct video_info *video_info;
+
+	void (*phy_init)(void);
+	void (*phy_exit)(void);
+};
+
+#endif /* _EXYNOS_DP_H */
diff --git a/include/video/exynos_mipi_dsim.h b/include/video/exynos_mipi_dsim.h
new file mode 100644
index 0000000..772c770
--- /dev/null
+++ b/include/video/exynos_mipi_dsim.h
@@ -0,0 +1,359 @@
+/* include/video/exynos_mipi_dsim.h
+ *
+ * Platform data header for Samsung SoC MIPI-DSIM.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@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.
+*/
+
+#ifndef _EXYNOS_MIPI_DSIM_H
+#define _EXYNOS_MIPI_DSIM_H
+
+#include <linux/device.h>
+#include <linux/fb.h>
+
+#define PANEL_NAME_SIZE		(32)
+
+/*
+ * Enumerate display interface type.
+ *
+ * DSIM_COMMAND means cpu interface and rgb interface for DSIM_VIDEO.
+ *
+ * P.S. MIPI DSI Master has two display controller intefaces, RGB Interface
+ *	for main display and CPU Interface(same as I80 Interface) for main
+ *	and sub display.
+ */
+enum mipi_dsim_interface_type {
+	DSIM_COMMAND,
+	DSIM_VIDEO
+};
+
+enum mipi_dsim_virtual_ch_no {
+	DSIM_VIRTUAL_CH_0,
+	DSIM_VIRTUAL_CH_1,
+	DSIM_VIRTUAL_CH_2,
+	DSIM_VIRTUAL_CH_3
+};
+
+enum mipi_dsim_burst_mode_type {
+	DSIM_NON_BURST_SYNC_EVENT,
+	DSIM_BURST_SYNC_EVENT,
+	DSIM_NON_BURST_SYNC_PULSE,
+	DSIM_BURST,
+	DSIM_NON_VIDEO_MODE
+};
+
+enum mipi_dsim_no_of_data_lane {
+	DSIM_DATA_LANE_1,
+	DSIM_DATA_LANE_2,
+	DSIM_DATA_LANE_3,
+	DSIM_DATA_LANE_4
+};
+
+enum mipi_dsim_byte_clk_src {
+	DSIM_PLL_OUT_DIV8,
+	DSIM_EXT_CLK_DIV8,
+	DSIM_EXT_CLK_BYPASS
+};
+
+enum mipi_dsim_pixel_format {
+	DSIM_CMD_3BPP,
+	DSIM_CMD_8BPP,
+	DSIM_CMD_12BPP,
+	DSIM_CMD_16BPP,
+	DSIM_VID_16BPP_565,
+	DSIM_VID_18BPP_666PACKED,
+	DSIM_18BPP_666LOOSELYPACKED,
+	DSIM_24BPP_888
+};
+
+/*
+ * struct mipi_dsim_config - interface for configuring mipi-dsi controller.
+ *
+ * @auto_flush: enable or disable Auto flush of MD FIFO using VSYNC pulse.
+ * @eot_disable: enable or disable EoT packet in HS mode.
+ * @auto_vertical_cnt: specifies auto vertical count mode.
+ *	in Video mode, the vertical line transition uses line counter
+ *	configured by VSA, VBP, and Vertical resolution.
+ *	If this bit is set to '1', the line counter does not use VSA and VBP
+ *	registers.(in command mode, this variable is ignored)
+ * @hse: set horizontal sync event mode.
+ *	In VSYNC pulse and Vporch area, MIPI DSI master transfers only HSYNC
+ *	start packet to MIPI DSI slave at MIPI DSI spec1.1r02.
+ *	this bit transfers HSYNC end packet in VSYNC pulse and Vporch area
+ *	(in mommand mode, this variable is ignored)
+ * @hfp: specifies HFP disable mode.
+ *	if this variable is set, DSI master ignores HFP area in VIDEO mode.
+ *	(in command mode, this variable is ignored)
+ * @hbp: specifies HBP disable mode.
+ *	if this variable is set, DSI master ignores HBP area in VIDEO mode.
+ *	(in command mode, this variable is ignored)
+ * @hsa: specifies HSA disable mode.
+ *	if this variable is set, DSI master ignores HSA area in VIDEO mode.
+ *	(in command mode, this variable is ignored)
+ * @cma_allow: specifies the number of horizontal lines, where command packet
+ *	transmission is allowed after Stable VFP period.
+ * @e_interface: specifies interface to be used.(CPU or RGB interface)
+ * @e_virtual_ch: specifies virtual channel number that main or
+ *	sub diaplsy uses.
+ * @e_pixel_format: specifies pixel stream format for main or sub display.
+ * @e_burst_mode: selects Burst mode in Video mode.
+ *	in Non-burst mode, RGB data area is filled with RGB data and NULL
+ *	packets, according to input bandwidth of RGB interface.
+ *	In Burst mode, RGB data area is filled with RGB data only.
+ * @e_no_data_lane: specifies data lane count to be used by Master.
+ * @e_byte_clk: select byte clock source. (it must be DSIM_PLL_OUT_DIV8)
+ *	DSIM_EXT_CLK_DIV8 and DSIM_EXT_CLK_BYPASSS are not supported.
+ * @pll_stable_time: specifies the PLL Timer for stability of the ganerated
+ *	clock(System clock cycle base)
+ *	if the timer value goes to 0x00000000, the clock stable bit of status
+ *	and interrupt register is set.
+ * @esc_clk: specifies escape clock frequency for getting the escape clock
+ *	prescaler value.
+ * @stop_holding_cnt: specifies the interval value between transmitting
+ *	read packet(or write "set_tear_on" command) and BTA request.
+ *	after transmitting read packet or write "set_tear_on" command,
+ *	BTA requests to D-PHY automatically. this counter value specifies
+ *	the interval between them.
+ * @bta_timeout: specifies the timer for BTA.
+ *	this register specifies time out from BTA request to change
+ *	the direction with respect to Tx escape clock.
+ * @rx_timeout: specifies the timer for LP Rx mode timeout.
+ *	this register specifies time out on how long RxValid deasserts,
+ *	after RxLpdt asserts with respect to Tx escape clock.
+ *	- RxValid specifies Rx data valid indicator.
+ *	- RxLpdt specifies an indicator that D-PHY is under RxLpdt mode.
+ *	- RxValid and RxLpdt specifies signal from D-PHY.
+ */
+struct mipi_dsim_config {
+	unsigned char			auto_flush;
+	unsigned char			eot_disable;
+
+	unsigned char			auto_vertical_cnt;
+	unsigned char			hse;
+	unsigned char			hfp;
+	unsigned char			hbp;
+	unsigned char			hsa;
+	unsigned char			cmd_allow;
+
+	enum mipi_dsim_interface_type	e_interface;
+	enum mipi_dsim_virtual_ch_no	e_virtual_ch;
+	enum mipi_dsim_pixel_format	e_pixel_format;
+	enum mipi_dsim_burst_mode_type	e_burst_mode;
+	enum mipi_dsim_no_of_data_lane	e_no_data_lane;
+	enum mipi_dsim_byte_clk_src	e_byte_clk;
+
+	/*
+	 * ===========================================
+	 * |    P    |    M    |    S    |    MHz    |
+	 * -------------------------------------------
+	 * |    3    |   100   |    3    |    100    |
+	 * |    3    |   100   |    2    |    200    |
+	 * |    3    |    63   |    1    |    252    |
+	 * |    4    |   100   |    1    |    300    |
+	 * |    4    |   110   |    1    |    330    |
+	 * |   12    |   350   |    1    |    350    |
+	 * |    3    |   100   |    1    |    400    |
+	 * |    4    |   150   |    1    |    450    |
+	 * |    6    |   118   |    1    |    472    |
+	 * |	3    |   120   |    1    |    480    |
+	 * |   12    |   250   |    0    |    500    |
+	 * |    4    |   100   |    0    |    600    |
+	 * |    3    |    81   |    0    |    648    |
+	 * |    3    |    88   |    0    |    704    |
+	 * |    3    |    90   |    0    |    720    |
+	 * |    3    |   100   |    0    |    800    |
+	 * |   12    |   425   |    0    |    850    |
+	 * |    4    |   150   |    0    |    900    |
+	 * |   12    |   475   |    0    |    950    |
+	 * |    6    |   250   |    0    |   1000    |
+	 * -------------------------------------------
+	 */
+
+	/*
+	 * pms could be calculated as the following.
+	 * M * 24 / P * 2 ^ S = MHz
+	 */
+	unsigned char			p;
+	unsigned short			m;
+	unsigned char			s;
+
+	unsigned int			pll_stable_time;
+	unsigned long			esc_clk;
+
+	unsigned short			stop_holding_cnt;
+	unsigned char			bta_timeout;
+	unsigned short			rx_timeout;
+};
+
+/*
+ * struct mipi_dsim_device - global interface for mipi-dsi driver.
+ *
+ * @dev: driver model representation of the device.
+ * @id: unique device id.
+ * @clock: pointer to MIPI-DSI clock of clock framework.
+ * @irq: interrupt number to MIPI-DSI controller.
+ * @reg_base: base address to memory mapped SRF of MIPI-DSI controller.
+ *	(virtual address)
+ * @lock: the mutex protecting this data structure.
+ * @dsim_info: infomation for configuring mipi-dsi controller.
+ * @master_ops: callbacks to mipi-dsi operations.
+ * @dsim_lcd_dev: pointer to activated ddi device.
+ *	(it would be registered by mipi-dsi driver.)
+ * @dsim_lcd_drv: pointer to activated_ddi driver.
+ *	(it would be registered by mipi-dsi driver.)
+ * @lcd_info: pointer to mipi_lcd_info structure.
+ * @state: specifies status of MIPI-DSI controller.
+ *	the status could be RESET, INIT, STOP, HSCLKEN and ULPS.
+ * @data_lane: specifiec enabled data lane number.
+ *	this variable would be set by driver according to e_no_data_lane
+ *	automatically.
+ * @e_clk_src: select byte clock source.
+ * @pd: pointer to MIPI-DSI driver platform data.
+ */
+struct mipi_dsim_device {
+	struct device			*dev;
+	int				id;
+	struct resource			*res;
+	struct clk			*clock;
+	unsigned int			irq;
+	void __iomem			*reg_base;
+	struct mutex			lock;
+
+	struct mipi_dsim_config		*dsim_config;
+	struct mipi_dsim_master_ops	*master_ops;
+	struct mipi_dsim_lcd_device	*dsim_lcd_dev;
+	struct mipi_dsim_lcd_driver	*dsim_lcd_drv;
+
+	unsigned int			state;
+	unsigned int			data_lane;
+	unsigned int			e_clk_src;
+	bool				suspended;
+
+	struct mipi_dsim_platform_data	*pd;
+};
+
+/*
+ * struct mipi_dsim_platform_data - interface to platform data
+ *	for mipi-dsi driver.
+ *
+ * @lcd_panel_name: specifies lcd panel name registered to mipi-dsi driver.
+ *	lcd panel driver searched would be actived.
+ * @dsim_config: pointer of structure for configuring mipi-dsi controller.
+ * @enabled: indicate whether mipi controller got enabled or not.
+ * @lcd_panel_info: pointer for lcd panel specific structure.
+ *	this structure specifies width, height, timing and polarity and so on.
+ * @phy_enable: pointer to a callback controlling D-PHY enable/reset
+ */
+struct mipi_dsim_platform_data {
+	char				lcd_panel_name[PANEL_NAME_SIZE];
+
+	struct mipi_dsim_config		*dsim_config;
+	unsigned int			enabled;
+	void				*lcd_panel_info;
+
+	int (*phy_enable)(struct platform_device *pdev, bool on);
+};
+
+/*
+ * struct mipi_dsim_master_ops - callbacks to mipi-dsi operations.
+ *
+ * @cmd_write: transfer command to lcd panel at LP mode.
+ * @cmd_read: read command from rx register.
+ * @get_dsim_frame_done: get the status that all screen data have been
+ *	transferred to mipi-dsi.
+ * @clear_dsim_frame_done: clear frame done status.
+ * @get_fb_frame_done: get frame done status of display controller.
+ * @trigger: trigger display controller.
+ *	- this one would be used only in case of CPU mode.
+ *  @set_early_blank_mode: set framebuffer blank mode.
+ *	- this callback should be called prior to fb_blank() by a client driver
+ *	only if needing.
+ *  @set_blank_mode: set framebuffer blank mode.
+ *	- this callback should be called after fb_blank() by a client driver
+ *	only if needing.
+ */
+
+struct mipi_dsim_master_ops {
+	int (*cmd_write)(struct mipi_dsim_device *dsim, unsigned int data_id,
+		const unsigned char *data0, unsigned int data1);
+	int (*cmd_read)(struct mipi_dsim_device *dsim, unsigned int data_id,
+		unsigned int data0, unsigned int req_size, u8 *rx_buf);
+	int (*get_dsim_frame_done)(struct mipi_dsim_device *dsim);
+	int (*clear_dsim_frame_done)(struct mipi_dsim_device *dsim);
+
+	int (*get_fb_frame_done)(struct fb_info *info);
+	void (*trigger)(struct fb_info *info);
+	int (*set_early_blank_mode)(struct mipi_dsim_device *dsim, int power);
+	int (*set_blank_mode)(struct mipi_dsim_device *dsim, int power);
+};
+
+/*
+ * device structure for mipi-dsi based lcd panel.
+ *
+ * @name: name of the device to use with this device, or an
+ *	alias for that name.
+ * @dev: driver model representation of the device.
+ * @id: id of device to be registered.
+ * @bus_id: bus id for identifing connected bus
+ *	and this bus id should be same as id of mipi_dsim_device.
+ * @irq: irq number for signaling when framebuffer transfer of
+ *	lcd panel module is completed.
+ *	this irq would be used only for MIPI-DSI based CPU mode lcd panel.
+ * @master: pointer to mipi-dsi master device object.
+ * @platform_data: lcd panel specific platform data.
+ */
+struct mipi_dsim_lcd_device {
+	char			*name;
+	struct device		dev;
+	int			id;
+	int			bus_id;
+	int			irq;
+
+	struct mipi_dsim_device *master;
+	void			*platform_data;
+};
+
+/*
+ * driver structure for mipi-dsi based lcd panel.
+ *
+ * this structure should be registered by lcd panel driver.
+ * mipi-dsi driver seeks lcd panel registered through name field
+ * and calls these callback functions in appropriate time.
+ *
+ * @name: name of the driver to use with this device, or an
+ *	alias for that name.
+ * @id: id of driver to be registered.
+ *	this id would be used for finding device object registered.
+ */
+struct mipi_dsim_lcd_driver {
+	char			*name;
+	int			id;
+
+	void	(*power_on)(struct mipi_dsim_lcd_device *dsim_dev, int enable);
+	void	(*set_sequence)(struct mipi_dsim_lcd_device *dsim_dev);
+	int	(*probe)(struct mipi_dsim_lcd_device *dsim_dev);
+	int	(*remove)(struct mipi_dsim_lcd_device *dsim_dev);
+	void	(*shutdown)(struct mipi_dsim_lcd_device *dsim_dev);
+	int	(*suspend)(struct mipi_dsim_lcd_device *dsim_dev);
+	int	(*resume)(struct mipi_dsim_lcd_device *dsim_dev);
+};
+
+/*
+ * register mipi_dsim_lcd_device to mipi-dsi master.
+ */
+int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device
+						*lcd_dev);
+/**
+ * register mipi_dsim_lcd_driver object defined by lcd panel driver
+ * to mipi-dsi driver.
+ */
+int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver
+						*lcd_drv);
+#endif /* _EXYNOS_MIPI_DSIM_H */
diff --git a/include/video/sa1100fb.h b/include/video/sa1100fb.h
new file mode 100644
index 0000000..4ab4096
--- /dev/null
+++ b/include/video/sa1100fb.h
@@ -0,0 +1,63 @@
+/*
+ * StrongARM 1100 LCD Controller Frame Buffer Device
+ *
+ * Copyright (C) 1999 Eric A. Thomas
+ *  Based on acornfb.c Copyright (C) Russell King.
+ *  
+ * 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.
+ */
+#ifndef _VIDEO_SA1100FB_H
+#define _VIDEO_SA1100FB_H
+
+#include <linux/fb.h>
+#include <linux/types.h>
+
+#define RGB_4	0
+#define RGB_8	1
+#define RGB_16	2
+#define NR_RGB	3
+
+/* These are the bitfields for each display depth that we support. */
+struct sa1100fb_rgb {
+	struct fb_bitfield	red;
+	struct fb_bitfield	green;
+	struct fb_bitfield	blue;
+	struct fb_bitfield	transp;
+};
+
+/* This structure describes the machine which we are running on. */
+struct sa1100fb_mach_info {
+	u_long		pixclock;
+
+	u_short		xres;
+	u_short		yres;
+
+	u_char		bpp;
+	u_char		hsync_len;
+	u_char		left_margin;
+	u_char		right_margin;
+
+	u_char		vsync_len;
+	u_char		upper_margin;
+	u_char		lower_margin;
+	u_char		sync;
+
+	u_int		cmap_greyscale:1,
+			cmap_inverse:1,
+			cmap_static:1,
+			unused:29;
+
+	u_int		lccr0;
+	u_int		lccr3;
+
+	/* Overrides for the default RGB maps */
+	const struct sa1100fb_rgb *rgb[NR_RGB];
+
+	void (*backlight_power)(int);
+	void (*lcd_power)(int);
+	void (*set_visual)(u32);
+};
+
+#endif
diff --git a/include/video/sh_mipi_dsi.h b/include/video/sh_mipi_dsi.h
index 434d56b..06c67fb 100644
--- a/include/video/sh_mipi_dsi.h
+++ b/include/video/sh_mipi_dsi.h
@@ -51,6 +51,7 @@
 	int				lane;
 	unsigned long			flags;
 	u32				clksrc;
+	u32				phyctrl; /* for extra setting */
 	unsigned int			vsynw_offset;
 	int	(*set_dot_clock)(struct platform_device *pdev,
 				 void __iomem *base,
diff --git a/include/video/sh_mobile_hdmi.h b/include/video/sh_mobile_hdmi.h
index b569329..728f9de 100644
--- a/include/video/sh_mobile_hdmi.h
+++ b/include/video/sh_mobile_hdmi.h
@@ -31,8 +31,6 @@
 #define HDMI_SND_SRC_HBR	(3 << 0)
 
 struct sh_mobile_hdmi_info {
-	struct sh_mobile_lcdc_chan_cfg	*lcd_chan;
-	struct device			*lcd_dev;
 	unsigned int			 flags;
 	long (*clk_optimize_parent)(unsigned long target, unsigned long *best_freq,
 				    unsigned long *parent_freq);
diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h
index fe30b75..7571b27 100644
--- a/include/video/sh_mobile_lcdc.h
+++ b/include/video/sh_mobile_lcdc.h
@@ -147,29 +147,23 @@
 	unsigned long (*read_data)(void *handle);
 };
 
-struct module;
-struct sh_mobile_lcdc_board_cfg {
-	struct module *owner;
-	void *board_data;
-	int (*setup_sys)(void *board_data, void *sys_ops_handle,
+struct sh_mobile_lcdc_panel_cfg {
+	unsigned long width;		/* Panel width in mm */
+	unsigned long height;		/* Panel height in mm */
+	int (*setup_sys)(void *sys_ops_handle,
 			 struct sh_mobile_lcdc_sys_bus_ops *sys_ops);
-	void (*start_transfer)(void *board_data, void *sys_ops_handle,
+	void (*start_transfer)(void *sys_ops_handle,
 			       struct sh_mobile_lcdc_sys_bus_ops *sys_ops);
-	void (*display_on)(void *board_data, struct fb_info *info);
-	void (*display_off)(void *board_data);
-	int (*set_brightness)(void *board_data, int brightness);
-	int (*get_brightness)(void *board_data);
-};
-
-struct sh_mobile_lcdc_lcd_size_cfg { /* width and height of panel in mm */
-	unsigned long width;
-	unsigned long height;
+	void (*display_on)(void);
+	void (*display_off)(void);
 };
 
 /* backlight info */
 struct sh_mobile_lcdc_bl_info {
 	const char *name;
 	int max_brightness;
+	int (*set_brightness)(int brightness);
+	int (*get_brightness)(void);
 };
 
 struct sh_mobile_lcdc_chan_cfg {
@@ -179,13 +173,14 @@
 	int interface_type; /* selects RGBn or SYSn I/F, see above */
 	int clock_divider;
 	unsigned long flags; /* LCDC_FLAGS_... */
-	const struct fb_videomode *lcd_cfg;
-	int num_cfg;
-	struct sh_mobile_lcdc_lcd_size_cfg lcd_size_cfg;
-	struct sh_mobile_lcdc_board_cfg board_cfg;
+	const struct fb_videomode *lcd_modes;
+	int num_modes;
+	struct sh_mobile_lcdc_panel_cfg panel_cfg;
 	struct sh_mobile_lcdc_bl_info bl_info;
 	struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */
-	struct sh_mobile_meram_cfg *meram_cfg;
+	const struct sh_mobile_meram_cfg *meram_cfg;
+
+	struct platform_device *tx_dev;	/* HDMI/DSI transmitter device */
 };
 
 struct sh_mobile_lcdc_info {
diff --git a/include/video/sh_mobile_meram.h b/include/video/sh_mobile_meram.h
index af602d6..29b2fd3 100644
--- a/include/video/sh_mobile_meram.h
+++ b/include/video/sh_mobile_meram.h
@@ -17,52 +17,47 @@
 struct sh_mobile_meram_priv;
 struct sh_mobile_meram_ops;
 
+/*
+ * struct sh_mobile_meram_info - MERAM platform data
+ * @reserved_icbs: Bitmask of reserved ICBs (for instance used through UIO)
+ */
 struct sh_mobile_meram_info {
 	int				addr_mode;
+	u32				reserved_icbs;
 	struct sh_mobile_meram_ops	*ops;
 	struct sh_mobile_meram_priv	*priv;
 	struct platform_device		*pdev;
 };
 
 /* icb config */
-struct sh_mobile_meram_icb {
-	int marker_icb;		/* ICB # for Marker ICB */
-	int cache_icb;		/* ICB # for Cache ICB */
-	int meram_offset;	/* MERAM Buffer Offset to use */
-	int meram_size;		/* MERAM Buffer Size to use */
-
-	int cache_unit;		/* bytes to cache per ICB */
+struct sh_mobile_meram_icb_cfg {
+	unsigned int meram_size;	/* MERAM Buffer Size to use */
 };
 
 struct sh_mobile_meram_cfg {
-	struct sh_mobile_meram_icb	icb[2];
-	int				pixelformat;
-	int				current_reg;
+	struct sh_mobile_meram_icb_cfg icb[2];
 };
 
 struct module;
 struct sh_mobile_meram_ops {
 	struct module	*module;
 	/* register usage of meram */
-	int (*meram_register)(struct sh_mobile_meram_info *meram_dev,
-			      struct sh_mobile_meram_cfg *cfg,
-			      int xres, int yres, int pixelformat,
-			      unsigned long base_addr_y,
-			      unsigned long base_addr_c,
-			      unsigned long *icb_addr_y,
-			      unsigned long *icb_addr_c, int *pitch);
+	void *(*meram_register)(struct sh_mobile_meram_info *meram_dev,
+				const struct sh_mobile_meram_cfg *cfg,
+				unsigned int xres, unsigned int yres,
+				unsigned int pixelformat,
+				unsigned int *pitch);
 
 	/* unregister usage of meram */
-	int (*meram_unregister)(struct sh_mobile_meram_info *meram_dev,
-				struct sh_mobile_meram_cfg *cfg);
+	void (*meram_unregister)(struct sh_mobile_meram_info *meram_dev,
+				 void *data);
 
 	/* update meram settings */
-	int (*meram_update)(struct sh_mobile_meram_info *meram_dev,
-			    struct sh_mobile_meram_cfg *cfg,
-			    unsigned long base_addr_y,
-			    unsigned long base_addr_c,
-			    unsigned long *icb_addr_y,
-			    unsigned long *icb_addr_c);
+	void (*meram_update)(struct sh_mobile_meram_info *meram_dev, void *data,
+			     unsigned long base_addr_y,
+			     unsigned long base_addr_c,
+			     unsigned long *icb_addr_y,
+			     unsigned long *icb_addr_c);
 };
 
 #endif /* __VIDEO_SH_MOBILE_MERAM_H__  */
diff --git a/include/video/udlfb.h b/include/video/udlfb.h
index c41f308..f9466fa 100644
--- a/include/video/udlfb.h
+++ b/include/video/udlfb.h
@@ -41,6 +41,7 @@
 	char *backing_buffer;
 	int fb_count;
 	bool virtualized; /* true when physical usb device not present */
+	struct delayed_work init_framebuffer_work;
 	struct delayed_work free_framebuffer_work;
 	atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */
 	atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */
diff --git a/include/xen/interface/hvm/params.h b/include/xen/interface/hvm/params.h
index 1888d8c..1b4f923 100644
--- a/include/xen/interface/hvm/params.h
+++ b/include/xen/interface/hvm/params.h
@@ -90,6 +90,10 @@
 /* Boolean: Enable aligning all periodic vpts to reduce interrupts */
 #define HVM_PARAM_VPT_ALIGN    16
 
-#define HVM_NR_PARAMS          17
+/* Console debug shared memory ring and event channel */
+#define HVM_PARAM_CONSOLE_PFN    17
+#define HVM_PARAM_CONSOLE_EVTCHN 18
+
+#define HVM_NR_PARAMS          19
 
 #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h
index c1080d9..9ce788d 100644
--- a/include/xen/interface/physdev.h
+++ b/include/xen/interface/physdev.h
@@ -39,6 +39,27 @@
 };
 
 /*
+ * Register a shared page for the hypervisor to indicate whether the guest
+ * must issue PHYSDEVOP_eoi. The semantics of PHYSDEVOP_eoi change slightly
+ * once the guest used this function in that the associated event channel
+ * will automatically get unmasked. The page registered is used as a bit
+ * array indexed by Xen's PIRQ value.
+ */
+#define PHYSDEVOP_pirq_eoi_gmfn_v1       17
+/*
+ * Register a shared page for the hypervisor to indicate whether the
+ * guest must issue PHYSDEVOP_eoi. This hypercall is very similar to
+ * PHYSDEVOP_pirq_eoi_gmfn_v1 but it doesn't change the semantics of
+ * PHYSDEVOP_eoi. The page registered is used as a bit array indexed by
+ * Xen's PIRQ value.
+ */
+#define PHYSDEVOP_pirq_eoi_gmfn_v2       28
+struct physdev_pirq_eoi_gmfn {
+    /* IN */
+    unsigned long gmfn;
+};
+
+/*
  * Query the status of an IRQ line.
  * @arg == pointer to physdev_irq_status_query structure.
  */
@@ -145,6 +166,13 @@
 	uint8_t devfn;
 };
 
+#define PHYSDEVOP_restore_msi            19
+struct physdev_restore_msi {
+	/* IN */
+	uint8_t bus;
+	uint8_t devfn;
+};
+
 #define PHYSDEVOP_manage_pci_add_ext	20
 struct physdev_manage_pci_ext {
 	/* IN */
diff --git a/include/xen/interface/platform.h b/include/xen/interface/platform.h
index c168468..486653f 100644
--- a/include/xen/interface/platform.h
+++ b/include/xen/interface/platform.h
@@ -200,7 +200,7 @@
 #define XEN_PM_CX   0
 #define XEN_PM_PX   1
 #define XEN_PM_TX   2
-
+#define XEN_PM_PDC  3
 /* Px sub info type */
 #define XEN_PX_PCT   1
 #define XEN_PX_PSS   2
@@ -293,10 +293,27 @@
 	union {
 		struct xen_processor_power          power;/* Cx: _CST/_CSD */
 		struct xen_processor_performance    perf; /* Px: _PPC/_PCT/_PSS/_PSD */
+		GUEST_HANDLE(uint32_t)              pdc;
 	};
 };
 DEFINE_GUEST_HANDLE_STRUCT(xenpf_set_processor_pminfo);
 
+#define XENPF_get_cpuinfo 55
+struct xenpf_pcpuinfo {
+	/* IN */
+	uint32_t xen_cpuid;
+	/* OUT */
+	/* The maxium cpu_id that is present */
+	uint32_t max_present;
+#define XEN_PCPU_FLAGS_ONLINE   1
+	/* Correponding xen_cpuid is not present*/
+#define XEN_PCPU_FLAGS_INVALID  2
+	uint32_t flags;
+	uint32_t apic_id;
+	uint32_t acpi_id;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xenpf_pcpuinfo);
+
 struct xen_platform_op {
 	uint32_t cmd;
 	uint32_t interface_version; /* XENPF_INTERFACE_VERSION */
@@ -312,6 +329,7 @@
 		struct xenpf_change_freq       change_freq;
 		struct xenpf_getidletime       getidletime;
 		struct xenpf_set_processor_pminfo set_pminfo;
+		struct xenpf_pcpuinfo          pcpu_info;
 		uint8_t                        pad[128];
 	} u;
 };
diff --git a/include/xen/swiotlb-xen.h b/include/xen/swiotlb-xen.h
index 2ea2fdc..4f4d449 100644
--- a/include/xen/swiotlb-xen.h
+++ b/include/xen/swiotlb-xen.h
@@ -7,11 +7,13 @@
 
 extern void
 *xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
-			    dma_addr_t *dma_handle, gfp_t flags);
+			    dma_addr_t *dma_handle, gfp_t flags,
+			    struct dma_attrs *attrs);
 
 extern void
 xen_swiotlb_free_coherent(struct device *hwdev, size_t size,
-			  void *vaddr, dma_addr_t dma_handle);
+			  void *vaddr, dma_addr_t dma_handle,
+			  struct dma_attrs *attrs);
 
 extern dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
 				       unsigned long offset, size_t size,
diff --git a/include/xen/tmem.h b/include/xen/tmem.h
index 82e2c83..591550a 100644
--- a/include/xen/tmem.h
+++ b/include/xen/tmem.h
@@ -1,5 +1,9 @@
 #ifndef _XEN_TMEM_H
 #define _XEN_TMEM_H
+
+#include <linux/types.h>
+
 /* defined in drivers/xen/tmem.c */
-extern int tmem_enabled;
+extern bool tmem_enabled;
+
 #endif /* _XEN_TMEM_H */
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
index 03c85d7..6a198e4 100644
--- a/include/xen/xen-ops.h
+++ b/include/xen/xen-ops.h
@@ -23,6 +23,7 @@
 
 void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order);
 
+struct vm_area_struct;
 int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
 			       unsigned long addr,
 			       unsigned long mfn, int nr,
diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h
index e8c599b..0a7515c 100644
--- a/include/xen/xenbus.h
+++ b/include/xen/xenbus.h
@@ -139,9 +139,9 @@
 int xenbus_transaction_end(struct xenbus_transaction t, int abort);
 
 /* Single read and scanf: returns -errno or num scanned if > 0. */
+__scanf(4, 5)
 int xenbus_scanf(struct xenbus_transaction t,
-		 const char *dir, const char *node, const char *fmt, ...)
-	__attribute__((format(scanf, 4, 5)));
+		 const char *dir, const char *node, const char *fmt, ...);
 
 /* Single printf and write: returns -errno or 0. */
 __printf(4, 5)
diff --git a/init/Kconfig b/init/Kconfig
index 72f33fa..6cfd71d 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1414,8 +1414,8 @@
 config INIT_ALL_POSSIBLE
 	bool
 	help
-	  Back when each arch used to define their own cpu_online_map and
-	  cpu_possible_map, some of them chose to initialize cpu_possible_map
+	  Back when each arch used to define their own cpu_online_mask and
+	  cpu_possible_mask, some of them chose to initialize cpu_possible_mask
 	  with all 1s, and others with all 0s.  When they were centralised,
 	  it was better to provide this option than to break all the archs
 	  and have several arch maintainers pursuing me down dark alleys.
diff --git a/init/calibrate.c b/init/calibrate.c
index 5f117ca..fda0a7b 100644
--- a/init/calibrate.c
+++ b/init/calibrate.c
@@ -267,7 +267,8 @@
 
 	if (per_cpu(cpu_loops_per_jiffy, this_cpu)) {
 		lpj = per_cpu(cpu_loops_per_jiffy, this_cpu);
-		pr_info("Calibrating delay loop (skipped) "
+		if (!printed)
+			pr_info("Calibrating delay loop (skipped) "
 				"already calibrated this CPU");
 	} else if (preset_lpj) {
 		lpj = preset_lpj;
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 2974c8b3..0e93f92 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -373,8 +373,8 @@
 #ifdef CONFIG_BLOCK
 		__bdevname(ROOT_DEV, b);
 #endif
-		printk("VFS: Cannot open root device \"%s\" or %s\n",
-				root_device_name, b);
+		printk("VFS: Cannot open root device \"%s\" or %s: error %d\n",
+				root_device_name, b, err);
 		printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");
 
 		printk_all_partitions();
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c
index 3098a38..9047330 100644
--- a/init/do_mounts_initrd.c
+++ b/init/do_mounts_initrd.c
@@ -2,7 +2,6 @@
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/minix_fs.h>
-#include <linux/ext2_fs.h>
 #include <linux/romfs_fs.h>
 #include <linux/initrd.h>
 #include <linux/sched.h>
diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c
index 887629e..6212586 100644
--- a/init/do_mounts_rd.c
+++ b/init/do_mounts_rd.c
@@ -54,20 +54,19 @@
 {
 	const int size = 512;
 	struct minix_super_block *minixsb;
-	struct ext2_super_block *ext2sb;
 	struct romfs_super_block *romfsb;
 	struct cramfs_super *cramfsb;
 	struct squashfs_super_block *squashfsb;
 	int nblocks = -1;
 	unsigned char *buf;
 	const char *compress_name;
+	unsigned long n;
 
 	buf = kmalloc(size, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
 
 	minixsb = (struct minix_super_block *) buf;
-	ext2sb = (struct ext2_super_block *) buf;
 	romfsb = (struct romfs_super_block *) buf;
 	cramfsb = (struct cramfs_super *) buf;
 	squashfsb = (struct squashfs_super_block *) buf;
@@ -150,12 +149,12 @@
 	}
 
 	/* Try ext2 */
-	if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) {
+	n = ext2_image_size(buf);
+	if (n) {
 		printk(KERN_NOTICE
 		       "RAMDISK: ext2 filesystem found at block %d\n",
 		       start_block);
-		nblocks = le32_to_cpu(ext2sb->s_blocks_count) <<
-			le32_to_cpu(ext2sb->s_log_block_size);
+		nblocks = n;
 		goto done;
 	}
 
@@ -178,7 +177,7 @@
 	char *buf = NULL;
 	unsigned short rotate = 0;
 	decompress_fn decompressor = NULL;
-#if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES)
+#if !defined(CONFIG_S390)
 	char rotator[4] = { '|' , '/' , '-' , '\\' };
 #endif
 
@@ -264,7 +263,7 @@
 		}
 		sys_read(in_fd, buf, BLOCK_SIZE);
 		sys_write(out_fd, buf, BLOCK_SIZE);
-#if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES)
+#if !defined(CONFIG_S390)
 		if (!(i % 16)) {
 			printk("%c\b", rotator[rotate & 0x3]);
 			rotate++;
diff --git a/init/main.c b/init/main.c
index c24805c..9d454f0 100644
--- a/init/main.c
+++ b/init/main.c
@@ -87,7 +87,6 @@
 extern void sbus_init(void);
 extern void prio_tree_init(void);
 extern void radix_tree_init(void);
-extern void free_initmem(void);
 #ifndef CONFIG_DEBUG_RODATA
 static inline void mark_rodata_ro(void) { }
 #endif
@@ -400,7 +399,7 @@
 
 void __init parse_early_options(char *cmdline)
 {
-	parse_args("early options", cmdline, NULL, 0, do_early_param);
+	parse_args("early options", cmdline, NULL, 0, 0, 0, do_early_param);
 }
 
 /* Arch code calls this early on, or if not, just before other parsing. */
@@ -503,7 +502,7 @@
 	parse_early_param();
 	parse_args("Booting kernel", static_command_line, __start___param,
 		   __stop___param - __start___param,
-		   &unknown_bootoption);
+		   0, 0, &unknown_bootoption);
 
 	jump_label_init();
 
@@ -699,14 +698,67 @@
 }
 
 
-extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
+extern initcall_t __initcall_start[];
+extern initcall_t __initcall0_start[];
+extern initcall_t __initcall1_start[];
+extern initcall_t __initcall2_start[];
+extern initcall_t __initcall3_start[];
+extern initcall_t __initcall4_start[];
+extern initcall_t __initcall5_start[];
+extern initcall_t __initcall6_start[];
+extern initcall_t __initcall7_start[];
+extern initcall_t __initcall_end[];
+
+static initcall_t *initcall_levels[] __initdata = {
+	__initcall0_start,
+	__initcall1_start,
+	__initcall2_start,
+	__initcall3_start,
+	__initcall4_start,
+	__initcall5_start,
+	__initcall6_start,
+	__initcall7_start,
+	__initcall_end,
+};
+
+static char *initcall_level_names[] __initdata = {
+	"early parameters",
+	"core parameters",
+	"postcore parameters",
+	"arch parameters",
+	"subsys parameters",
+	"fs parameters",
+	"device parameters",
+	"late parameters",
+};
+
+static int __init ignore_unknown_bootoption(char *param, char *val)
+{
+	return 0;
+}
+
+static void __init do_initcall_level(int level)
+{
+	extern const struct kernel_param __start___param[], __stop___param[];
+	initcall_t *fn;
+
+	strcpy(static_command_line, saved_command_line);
+	parse_args(initcall_level_names[level],
+		   static_command_line, __start___param,
+		   __stop___param - __start___param,
+		   level, level,
+		   ignore_unknown_bootoption);
+
+	for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
+		do_one_initcall(*fn);
+}
 
 static void __init do_initcalls(void)
 {
-	initcall_t *fn;
+	int level;
 
-	for (fn = __early_initcall_end; fn < __initcall_end; fn++)
-		do_one_initcall(*fn);
+	for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
+		do_initcall_level(level);
 }
 
 /*
@@ -732,7 +784,7 @@
 {
 	initcall_t *fn;
 
-	for (fn = __initcall_start; fn < __early_initcall_end; fn++)
+	for (fn = __initcall_start; fn < __initcall0_start; fn++)
 		do_one_initcall(*fn);
 }
 
diff --git a/ipc/compat.c b/ipc/compat.c
index 845a287..a6df704 100644
--- a/ipc/compat.c
+++ b/ipc/compat.c
@@ -27,6 +27,7 @@
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/syscalls.h>
+#include <linux/ptrace.h>
 
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
@@ -117,6 +118,7 @@
 
 static inline int compat_ipc_parse_version(int *cmd)
 {
+#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
 	int version = *cmd & IPC_64;
 
 	/* this is tricky: architectures that have support for the old
@@ -128,6 +130,10 @@
 	*cmd &= ~IPC_64;
 #endif
 	return version;
+#else
+	/* With the asm-generic APIs, we always use the 64-bit versions. */
+	return IPC_64;
+#endif
 }
 
 static inline int __get_compat_ipc64_perm(struct ipc64_perm *p64,
@@ -232,10 +238,9 @@
 	return err;
 }
 
-long compat_sys_semctl(int first, int second, int third, void __user *uptr)
+static long do_compat_semctl(int first, int second, int third, u32 pad)
 {
 	union semun fourth;
-	u32 pad;
 	int err, err2;
 	struct semid64_ds s64;
 	struct semid64_ds __user *up64;
@@ -243,10 +248,6 @@
 
 	memset(&s64, 0, sizeof(s64));
 
-	if (!uptr)
-		return -EINVAL;
-	if (get_user(pad, (u32 __user *) uptr))
-		return -EFAULT;
 	if ((third & (~IPC_64)) == SETVAL)
 		fourth.val = (int) pad;
 	else
@@ -305,6 +306,18 @@
 	return err;
 }
 
+#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
+long compat_sys_semctl(int first, int second, int third, void __user *uptr)
+{
+	u32 pad;
+
+	if (!uptr)
+		return -EINVAL;
+	if (get_user(pad, (u32 __user *) uptr))
+		return -EFAULT;
+	return do_compat_semctl(first, second, third, pad);
+}
+
 long compat_sys_msgsnd(int first, int second, int third, void __user *uptr)
 {
 	struct compat_msgbuf __user *up = uptr;
@@ -353,6 +366,37 @@
 out:
 	return err;
 }
+#else
+long compat_sys_semctl(int semid, int semnum, int cmd, int arg)
+{
+	return do_compat_semctl(semid, semnum, cmd, arg);
+}
+
+long compat_sys_msgsnd(int msqid, struct compat_msgbuf __user *msgp,
+		       size_t msgsz, int msgflg)
+{
+	compat_long_t mtype;
+
+	if (get_user(mtype, &msgp->mtype))
+		return -EFAULT;
+	return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg);
+}
+
+long compat_sys_msgrcv(int msqid, struct compat_msgbuf __user *msgp,
+		       size_t msgsz, long msgtyp, int msgflg)
+{
+	long err, mtype;
+
+	err =  do_msgrcv(msqid, &mtype, msgp->mtext, msgsz, msgtyp, msgflg);
+	if (err < 0)
+		goto out;
+
+	if (put_user(mtype, &msgp->mtype))
+		err = -EFAULT;
+ out:
+	return err;
+}
+#endif
 
 static inline int get_compat_msqid64(struct msqid64_ds *m64,
 				     struct compat_msqid64_ds __user *up64)
@@ -470,6 +514,7 @@
 	return err;
 }
 
+#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
 long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
 			void __user *uptr)
 {
@@ -485,6 +530,19 @@
 	uaddr = compat_ptr(third);
 	return put_user(raddr, uaddr);
 }
+#else
+long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg)
+{
+	unsigned long ret;
+	long err;
+
+	err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret);
+	if (err)
+		return err;
+	force_successful_syscall_return();
+	return (long)ret;
+}
+#endif
 
 static inline int get_compat_shmid64_ds(struct shmid64_ds *s64,
 					struct compat_shmid64_ds __user *up64)
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 86ee272..28bd64d 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -188,30 +188,20 @@
 {
 	struct inode *inode;
 	struct ipc_namespace *ns = data;
-	int error;
 
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
 	sb->s_magic = MQUEUE_MAGIC;
 	sb->s_op = &mqueue_super_ops;
 
-	inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO,
-				NULL);
-	if (IS_ERR(inode)) {
-		error = PTR_ERR(inode);
-		goto out;
-	}
+	inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO, NULL);
+	if (IS_ERR(inode))
+		return PTR_ERR(inode);
 
-	sb->s_root = d_alloc_root(inode);
-	if (!sb->s_root) {
-		iput(inode);
-		error = -ENOMEM;
-		goto out;
-	}
-	error = 0;
-
-out:
-	return error;
+	sb->s_root = d_make_root(inode);
+	if (!sb->s_root)
+		return -ENOMEM;
+	return 0;
 }
 
 static struct dentry *mqueue_mount(struct file_system_type *fs_type,
diff --git a/ipc/shm.c b/ipc/shm.c
index b76be5b..406c5b2 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -482,7 +482,7 @@
 		/* hugetlb_file_setup applies strict accounting */
 		if (shmflg & SHM_NORESERVE)
 			acctflag = VM_NORESERVE;
-		file = hugetlb_file_setup(name, size, acctflag,
+		file = hugetlb_file_setup(name, 0, size, acctflag,
 					&shp->mlock_user, HUGETLB_SHMFS_INODE);
 	} else {
 		/*
diff --git a/kernel/Kconfig.locks b/kernel/Kconfig.locks
index 5068e2a..2251882 100644
--- a/kernel/Kconfig.locks
+++ b/kernel/Kconfig.locks
@@ -124,8 +124,8 @@
 	def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \
 		 ARCH_INLINE_SPIN_LOCK_IRQSAVE
 
-config INLINE_SPIN_UNLOCK
-	def_bool !DEBUG_SPINLOCK && (!PREEMPT || ARCH_INLINE_SPIN_UNLOCK)
+config UNINLINE_SPIN_UNLOCK
+	bool
 
 config INLINE_SPIN_UNLOCK_BH
 	def_bool !DEBUG_SPINLOCK && ARCH_INLINE_SPIN_UNLOCK_BH
diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt
index 24e7cb0..3f9c974 100644
--- a/kernel/Kconfig.preempt
+++ b/kernel/Kconfig.preempt
@@ -36,6 +36,7 @@
 config PREEMPT
 	bool "Preemptible Kernel (Low-Latency Desktop)"
 	select PREEMPT_COUNT
+	select UNINLINE_SPIN_UNLOCK if !ARCH_INLINE_SPIN_UNLOCK
 	help
 	  This option reduces the latency of the kernel by making
 	  all kernel code (that is not executing in a critical section)
diff --git a/kernel/Makefile b/kernel/Makefile
index 2d9de86..cb41b95 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -27,7 +27,6 @@
 
 obj-$(CONFIG_FREEZER) += freezer.o
 obj-$(CONFIG_PROFILING) += profile.o
-obj-$(CONFIG_SYSCTL_SYSCALL_CHECK) += sysctl_check.o
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
 obj-y += time/
 obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o
diff --git a/kernel/audit.c b/kernel/audit.c
index bb0eb5b..1c7f2c6 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1418,7 +1418,7 @@
 
 /* This is a helper-function to print the escaped d_path */
 void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
-		      struct path *path)
+		      const struct path *path)
 {
 	char *p, *pathname;
 
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index c6877fe..ed64cca 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1472,7 +1472,6 @@
 
 	struct inode *inode =
 		cgroup_new_inode(S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR, sb);
-	struct dentry *dentry;
 
 	if (!inode)
 		return -ENOMEM;
@@ -1481,12 +1480,9 @@
 	inode->i_op = &cgroup_dir_inode_operations;
 	/* directories start off with i_nlink == 2 (for "." entry) */
 	inc_nlink(inode);
-	dentry = d_alloc_root(inode);
-	if (!dentry) {
-		iput(inode);
+	sb->s_root = d_make_root(inode);
+	if (!sb->s_root)
 		return -ENOMEM;
-	}
-	sb->s_root = dentry;
 	/* for everything else we want ->d_op set */
 	sb->s_d_op = &cgroup_dops;
 	return 0;
@@ -1887,7 +1883,7 @@
  */
 int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
 {
-	int retval;
+	int retval = 0;
 	struct cgroup_subsys *ss, *failed_ss = NULL;
 	struct cgroup *oldcgrp;
 	struct cgroupfs_root *root = cgrp->root;
@@ -4885,9 +4881,9 @@
 
 	rcu_assign_pointer(id->css, NULL);
 	rcu_assign_pointer(css->id, NULL);
-	write_lock(&ss->id_lock);
+	spin_lock(&ss->id_lock);
 	idr_remove(&ss->idr, id->id);
-	write_unlock(&ss->id_lock);
+	spin_unlock(&ss->id_lock);
 	kfree_rcu(id, rcu_head);
 }
 EXPORT_SYMBOL_GPL(free_css_id);
@@ -4913,10 +4909,10 @@
 		error = -ENOMEM;
 		goto err_out;
 	}
-	write_lock(&ss->id_lock);
+	spin_lock(&ss->id_lock);
 	/* Don't use 0. allocates an ID of 1-65535 */
 	error = idr_get_new_above(&ss->idr, newid, 1, &myid);
-	write_unlock(&ss->id_lock);
+	spin_unlock(&ss->id_lock);
 
 	/* Returns error when there are no free spaces for new ID.*/
 	if (error) {
@@ -4931,9 +4927,9 @@
 	return newid;
 remove_idr:
 	error = -ENOSPC;
-	write_lock(&ss->id_lock);
+	spin_lock(&ss->id_lock);
 	idr_remove(&ss->idr, myid);
-	write_unlock(&ss->id_lock);
+	spin_unlock(&ss->id_lock);
 err_out:
 	kfree(newid);
 	return ERR_PTR(error);
@@ -4945,7 +4941,7 @@
 {
 	struct css_id *newid;
 
-	rwlock_init(&ss->id_lock);
+	spin_lock_init(&ss->id_lock);
 	idr_init(&ss->idr);
 
 	newid = get_new_cssid(ss, 0);
@@ -5033,6 +5029,8 @@
 		return NULL;
 
 	BUG_ON(!ss->use_id);
+	WARN_ON_ONCE(!rcu_read_lock_held());
+
 	/* fill start point for scan */
 	tmpid = id;
 	while (1) {
@@ -5040,10 +5038,7 @@
 		 * scan next entry from bitmap(tree), tmpid is updated after
 		 * idr_get_next().
 		 */
-		read_lock(&ss->id_lock);
 		tmp = idr_get_next(&ss->idr, &tmpid);
-		read_unlock(&ss->id_lock);
-
 		if (!tmp)
 			break;
 		if (tmp->depth >= depth && tmp->stack[depth] == rootid) {
diff --git a/kernel/compat.c b/kernel/compat.c
index f346ced..74ff849 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -31,11 +31,10 @@
 #include <asm/uaccess.h>
 
 /*
- * Note that the native side is already converted to a timespec, because
- * that's what we want anyway.
+ * Get/set struct timeval with struct timespec on the native side
  */
-static int compat_get_timeval(struct timespec *o,
-		struct compat_timeval __user *i)
+static int compat_get_timeval_convert(struct timespec *o,
+				      struct compat_timeval __user *i)
 {
 	long usec;
 
@@ -46,8 +45,8 @@
 	return 0;
 }
 
-static int compat_put_timeval(struct compat_timeval __user *o,
-		struct timeval *i)
+static int compat_put_timeval_convert(struct compat_timeval __user *o,
+				      struct timeval *i)
 {
 	return (put_user(i->tv_sec, &o->tv_sec) ||
 		put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0;
@@ -117,7 +116,7 @@
 	if (tv) {
 		struct timeval ktv;
 		do_gettimeofday(&ktv);
-		if (compat_put_timeval(tv, &ktv))
+		if (compat_put_timeval_convert(tv, &ktv))
 			return -EFAULT;
 	}
 	if (tz) {
@@ -135,7 +134,7 @@
 	struct timezone ktz;
 
 	if (tv) {
-		if (compat_get_timeval(&kts, tv))
+		if (compat_get_timeval_convert(&kts, tv))
 			return -EFAULT;
 	}
 	if (tz) {
@@ -146,12 +145,29 @@
 	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
 }
 
+int get_compat_timeval(struct timeval *tv, const struct compat_timeval __user *ctv)
+{
+	return (!access_ok(VERIFY_READ, ctv, sizeof(*ctv)) ||
+			__get_user(tv->tv_sec, &ctv->tv_sec) ||
+			__get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0;
+}
+EXPORT_SYMBOL_GPL(get_compat_timeval);
+
+int put_compat_timeval(const struct timeval *tv, struct compat_timeval __user *ctv)
+{
+	return (!access_ok(VERIFY_WRITE, ctv, sizeof(*ctv)) ||
+			__put_user(tv->tv_sec, &ctv->tv_sec) ||
+			__put_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0;
+}
+EXPORT_SYMBOL_GPL(put_compat_timeval);
+
 int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts)
 {
 	return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) ||
 			__get_user(ts->tv_sec, &cts->tv_sec) ||
 			__get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
 }
+EXPORT_SYMBOL_GPL(get_compat_timespec);
 
 int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user *cts)
 {
@@ -161,6 +177,42 @@
 }
 EXPORT_SYMBOL_GPL(put_compat_timespec);
 
+int compat_get_timeval(struct timeval *tv, const void __user *utv)
+{
+	if (COMPAT_USE_64BIT_TIME)
+		return copy_from_user(tv, utv, sizeof *tv) ? -EFAULT : 0;
+	else
+		return get_compat_timeval(tv, utv);
+}
+EXPORT_SYMBOL_GPL(compat_get_timeval);
+
+int compat_put_timeval(const struct timeval *tv, void __user *utv)
+{
+	if (COMPAT_USE_64BIT_TIME)
+		return copy_to_user(utv, tv, sizeof *tv) ? -EFAULT : 0;
+	else
+		return put_compat_timeval(tv, utv);
+}
+EXPORT_SYMBOL_GPL(compat_put_timeval);
+
+int compat_get_timespec(struct timespec *ts, const void __user *uts)
+{
+	if (COMPAT_USE_64BIT_TIME)
+		return copy_from_user(ts, uts, sizeof *ts) ? -EFAULT : 0;
+	else
+		return get_compat_timespec(ts, uts);
+}
+EXPORT_SYMBOL_GPL(compat_get_timespec);
+
+int compat_put_timespec(const struct timespec *ts, void __user *uts)
+{
+	if (COMPAT_USE_64BIT_TIME)
+		return copy_to_user(uts, ts, sizeof *ts) ? -EFAULT : 0;
+	else
+		return put_compat_timespec(ts, uts);
+}
+EXPORT_SYMBOL_GPL(compat_put_timespec);
+
 static long compat_nanosleep_restart(struct restart_block *restart)
 {
 	struct compat_timespec __user *rmtp;
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 5d57583..14f7070 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -270,11 +270,11 @@
  * are online.  If none are online, walk up the cpuset hierarchy
  * until we find one that does have some online cpus.  If we get
  * all the way to the top and still haven't found any online cpus,
- * return cpu_online_map.  Or if passed a NULL cs from an exit'ing
- * task, return cpu_online_map.
+ * return cpu_online_mask.  Or if passed a NULL cs from an exit'ing
+ * task, return cpu_online_mask.
  *
  * One way or another, we guarantee to return some non-empty subset
- * of cpu_online_map.
+ * of cpu_online_mask.
  *
  * Call with callback_mutex held.
  */
@@ -867,7 +867,7 @@
 	int retval;
 	int is_load_balanced;
 
-	/* top_cpuset.cpus_allowed tracks cpu_online_map; it's read-only */
+	/* top_cpuset.cpus_allowed tracks cpu_online_mask; it's read-only */
 	if (cs == &top_cpuset)
 		return -EACCES;
 
@@ -964,7 +964,6 @@
 {
 	bool need_loop;
 
-repeat:
 	/*
 	 * Allow tasks that have access to memory reserves because they have
 	 * been OOM killed to get memory anywhere.
@@ -983,45 +982,19 @@
 	 */
 	need_loop = task_has_mempolicy(tsk) ||
 			!nodes_intersects(*newmems, tsk->mems_allowed);
+
+	if (need_loop)
+		write_seqcount_begin(&tsk->mems_allowed_seq);
+
 	nodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems);
 	mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP1);
 
-	/*
-	 * ensure checking ->mems_allowed_change_disable after setting all new
-	 * allowed nodes.
-	 *
-	 * the read-side task can see an nodemask with new allowed nodes and
-	 * old allowed nodes. and if it allocates page when cpuset clears newly
-	 * disallowed ones continuous, it can see the new allowed bits.
-	 *
-	 * And if setting all new allowed nodes is after the checking, setting
-	 * all new allowed nodes and clearing newly disallowed ones will be done
-	 * continuous, and the read-side task may find no node to alloc page.
-	 */
-	smp_mb();
-
-	/*
-	 * Allocation of memory is very fast, we needn't sleep when waiting
-	 * for the read-side.
-	 */
-	while (need_loop && ACCESS_ONCE(tsk->mems_allowed_change_disable)) {
-		task_unlock(tsk);
-		if (!task_curr(tsk))
-			yield();
-		goto repeat;
-	}
-
-	/*
-	 * ensure checking ->mems_allowed_change_disable before clearing all new
-	 * disallowed nodes.
-	 *
-	 * if clearing newly disallowed bits before the checking, the read-side
-	 * task may find no node to alloc page.
-	 */
-	smp_mb();
-
 	mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP2);
 	tsk->mems_allowed = *newmems;
+
+	if (need_loop)
+		write_seqcount_end(&tsk->mems_allowed_seq);
+
 	task_unlock(tsk);
 }
 
@@ -2176,7 +2149,7 @@
  *
  * Description: Returns the cpumask_var_t cpus_allowed of the cpuset
  * attached to the specified @tsk.  Guaranteed to return some non-empty
- * subset of cpu_online_map, even if this means going outside the
+ * subset of cpu_online_mask, even if this means going outside the
  * tasks cpuset.
  **/
 
@@ -2189,10 +2162,9 @@
 	mutex_unlock(&callback_mutex);
 }
 
-int cpuset_cpus_allowed_fallback(struct task_struct *tsk)
+void cpuset_cpus_allowed_fallback(struct task_struct *tsk)
 {
 	const struct cpuset *cs;
-	int cpu;
 
 	rcu_read_lock();
 	cs = task_cs(tsk);
@@ -2213,22 +2185,10 @@
 	 * changes in tsk_cs()->cpus_allowed. Otherwise we can temporary
 	 * set any mask even if it is not right from task_cs() pov,
 	 * the pending set_cpus_allowed_ptr() will fix things.
+	 *
+	 * select_fallback_rq() will fix things ups and set cpu_possible_mask
+	 * if required.
 	 */
-
-	cpu = cpumask_any_and(&tsk->cpus_allowed, cpu_active_mask);
-	if (cpu >= nr_cpu_ids) {
-		/*
-		 * Either tsk->cpus_allowed is wrong (see above) or it
-		 * is actually empty. The latter case is only possible
-		 * if we are racing with remove_tasks_in_empty_cpuset().
-		 * Like above we can temporary set any mask and rely on
-		 * set_cpus_allowed_ptr() as synchronization point.
-		 */
-		do_set_cpus_allowed(tsk, cpu_possible_mask);
-		cpu = cpumask_any(cpu_active_mask);
-	}
-
-	return cpu;
 }
 
 void cpuset_init_current_mems_allowed(void)
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c
index 0d7c087..0557f24 100644
--- a/kernel/debug/debug_core.c
+++ b/kernel/debug/debug_core.c
@@ -41,6 +41,7 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/sysrq.h>
+#include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/kgdb.h>
 #include <linux/kdb.h>
@@ -52,7 +53,6 @@
 #include <asm/cacheflush.h>
 #include <asm/byteorder.h>
 #include <linux/atomic.h>
-#include <asm/system.h>
 
 #include "debug_core.h"
 
@@ -75,6 +75,8 @@
 struct kgdb_io		*dbg_io_ops;
 static DEFINE_SPINLOCK(kgdb_registration_lock);
 
+/* Action for the reboot notifiter, a global allow kdb to change it */
+static int kgdbreboot;
 /* kgdb console driver is loaded */
 static int kgdb_con_registered;
 /* determine if kgdb console output should be used */
@@ -96,6 +98,7 @@
 early_param("kgdbcon", opt_kgdb_con);
 
 module_param(kgdb_use_con, int, 0644);
+module_param(kgdbreboot, int, 0644);
 
 /*
  * Holds information about breakpoints in a kernel. These breakpoints are
@@ -157,37 +160,39 @@
  * Weak aliases for breakpoint management,
  * can be overriden by architectures when needed:
  */
-int __weak kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
+int __weak kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
 {
 	int err;
 
-	err = probe_kernel_read(saved_instr, (char *)addr, BREAK_INSTR_SIZE);
+	err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr,
+				BREAK_INSTR_SIZE);
 	if (err)
 		return err;
-
-	return probe_kernel_write((char *)addr, arch_kgdb_ops.gdb_bpt_instr,
-				  BREAK_INSTR_SIZE);
+	err = probe_kernel_write((char *)bpt->bpt_addr,
+				 arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE);
+	return err;
 }
 
-int __weak kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle)
+int __weak kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
 {
-	return probe_kernel_write((char *)addr,
-				  (char *)bundle, BREAK_INSTR_SIZE);
+	return probe_kernel_write((char *)bpt->bpt_addr,
+				  (char *)bpt->saved_instr, BREAK_INSTR_SIZE);
 }
 
 int __weak kgdb_validate_break_address(unsigned long addr)
 {
-	char tmp_variable[BREAK_INSTR_SIZE];
+	struct kgdb_bkpt tmp;
 	int err;
-	/* Validate setting the breakpoint and then removing it.  In the
+	/* Validate setting the breakpoint and then removing it.  If the
 	 * remove fails, the kernel needs to emit a bad message because we
 	 * are deep trouble not being able to put things back the way we
 	 * found them.
 	 */
-	err = kgdb_arch_set_breakpoint(addr, tmp_variable);
+	tmp.bpt_addr = addr;
+	err = kgdb_arch_set_breakpoint(&tmp);
 	if (err)
 		return err;
-	err = kgdb_arch_remove_breakpoint(addr, tmp_variable);
+	err = kgdb_arch_remove_breakpoint(&tmp);
 	if (err)
 		printk(KERN_ERR "KGDB: Critical breakpoint error, kernel "
 		   "memory destroyed at: %lx", addr);
@@ -231,7 +236,6 @@
  */
 int dbg_activate_sw_breakpoints(void)
 {
-	unsigned long addr;
 	int error;
 	int ret = 0;
 	int i;
@@ -240,16 +244,15 @@
 		if (kgdb_break[i].state != BP_SET)
 			continue;
 
-		addr = kgdb_break[i].bpt_addr;
-		error = kgdb_arch_set_breakpoint(addr,
-				kgdb_break[i].saved_instr);
+		error = kgdb_arch_set_breakpoint(&kgdb_break[i]);
 		if (error) {
 			ret = error;
-			printk(KERN_INFO "KGDB: BP install failed: %lx", addr);
+			printk(KERN_INFO "KGDB: BP install failed: %lx",
+			       kgdb_break[i].bpt_addr);
 			continue;
 		}
 
-		kgdb_flush_swbreak_addr(addr);
+		kgdb_flush_swbreak_addr(kgdb_break[i].bpt_addr);
 		kgdb_break[i].state = BP_ACTIVE;
 	}
 	return ret;
@@ -298,7 +301,6 @@
 
 int dbg_deactivate_sw_breakpoints(void)
 {
-	unsigned long addr;
 	int error;
 	int ret = 0;
 	int i;
@@ -306,15 +308,14 @@
 	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
 		if (kgdb_break[i].state != BP_ACTIVE)
 			continue;
-		addr = kgdb_break[i].bpt_addr;
-		error = kgdb_arch_remove_breakpoint(addr,
-					kgdb_break[i].saved_instr);
+		error = kgdb_arch_remove_breakpoint(&kgdb_break[i]);
 		if (error) {
-			printk(KERN_INFO "KGDB: BP remove failed: %lx\n", addr);
+			printk(KERN_INFO "KGDB: BP remove failed: %lx\n",
+			       kgdb_break[i].bpt_addr);
 			ret = error;
 		}
 
-		kgdb_flush_swbreak_addr(addr);
+		kgdb_flush_swbreak_addr(kgdb_break[i].bpt_addr);
 		kgdb_break[i].state = BP_SET;
 	}
 	return ret;
@@ -348,7 +349,6 @@
 
 int dbg_remove_all_break(void)
 {
-	unsigned long addr;
 	int error;
 	int i;
 
@@ -356,12 +356,10 @@
 	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
 		if (kgdb_break[i].state != BP_ACTIVE)
 			goto setundefined;
-		addr = kgdb_break[i].bpt_addr;
-		error = kgdb_arch_remove_breakpoint(addr,
-				kgdb_break[i].saved_instr);
+		error = kgdb_arch_remove_breakpoint(&kgdb_break[i]);
 		if (error)
 			printk(KERN_ERR "KGDB: breakpoint remove failed: %lx\n",
-			   addr);
+			       kgdb_break[i].bpt_addr);
 setundefined:
 		kgdb_break[i].state = BP_UNDEFINED;
 	}
@@ -784,6 +782,33 @@
 	kdb_init(KDB_INIT_FULL);
 }
 
+static int
+dbg_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
+{
+	/*
+	 * Take the following action on reboot notify depending on value:
+	 *    1 == Enter debugger
+	 *    0 == [the default] detatch debug client
+	 *   -1 == Do nothing... and use this until the board resets
+	 */
+	switch (kgdbreboot) {
+	case 1:
+		kgdb_breakpoint();
+	case -1:
+		goto done;
+	}
+	if (!dbg_kdb_mode)
+		gdbstub_exit(code);
+done:
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block dbg_reboot_notifier = {
+	.notifier_call		= dbg_notify_reboot,
+	.next			= NULL,
+	.priority		= INT_MAX,
+};
+
 static void kgdb_register_callbacks(void)
 {
 	if (!kgdb_io_module_registered) {
@@ -791,6 +816,7 @@
 		kgdb_arch_init();
 		if (!dbg_is_early)
 			kgdb_arch_late();
+		register_reboot_notifier(&dbg_reboot_notifier);
 		atomic_notifier_chain_register(&panic_notifier_list,
 					       &kgdb_panic_event_nb);
 #ifdef CONFIG_MAGIC_SYSRQ
@@ -812,6 +838,7 @@
 	 */
 	if (kgdb_io_module_registered) {
 		kgdb_io_module_registered = 0;
+		unregister_reboot_notifier(&dbg_reboot_notifier);
 		atomic_notifier_chain_unregister(&panic_notifier_list,
 					       &kgdb_panic_event_nb);
 		kgdb_arch_exit();
diff --git a/kernel/debug/gdbstub.c b/kernel/debug/gdbstub.c
index c22d8c2..ce615e0 100644
--- a/kernel/debug/gdbstub.c
+++ b/kernel/debug/gdbstub.c
@@ -1111,6 +1111,13 @@
 	unsigned char checksum, ch, buffer[3];
 	int loop;
 
+	if (!kgdb_connected)
+		return;
+	kgdb_connected = 0;
+
+	if (!dbg_io_ops || dbg_kdb_mode)
+		return;
+
 	buffer[0] = 'W';
 	buffer[1] = hex_asc_hi(status);
 	buffer[2] = hex_asc_lo(status);
@@ -1129,5 +1136,6 @@
 	dbg_io_ops->write_char(hex_asc_lo(checksum));
 
 	/* make sure the output is flushed, lest the bootloader clobber it */
-	dbg_io_ops->flush();
+	if (dbg_io_ops->flush)
+		dbg_io_ops->flush();
 }
diff --git a/kernel/debug/kdb/kdb_bp.c b/kernel/debug/kdb/kdb_bp.c
index 20059ef..8418c2f 100644
--- a/kernel/debug/kdb/kdb_bp.c
+++ b/kernel/debug/kdb/kdb_bp.c
@@ -153,6 +153,13 @@
 	} else {
 		kdb_printf("%s: failed to set breakpoint at 0x%lx\n",
 			   __func__, bp->bp_addr);
+#ifdef CONFIG_DEBUG_RODATA
+		if (!bp->bp_type) {
+			kdb_printf("Software breakpoints are unavailable.\n"
+				   "  Change the kernel CONFIG_DEBUG_RODATA=n\n"
+				   "  OR use hw breaks: help bph\n");
+		}
+#endif
 		return 1;
 	}
 	return 0;
diff --git a/kernel/debug/kdb/kdb_bt.c b/kernel/debug/kdb/kdb_bt.c
index 7179eac..07c9bbb 100644
--- a/kernel/debug/kdb/kdb_bt.c
+++ b/kernel/debug/kdb/kdb_bt.c
@@ -15,7 +15,6 @@
 #include <linux/sched.h>
 #include <linux/kdb.h>
 #include <linux/nmi.h>
-#include <asm/system.h>
 #include "kdb_private.h"
 
 
diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c
index 4802eb5..bb9520f 100644
--- a/kernel/debug/kdb/kdb_io.c
+++ b/kernel/debug/kdb/kdb_io.c
@@ -689,7 +689,7 @@
 	if (!dbg_kdb_mode && kgdb_connected) {
 		gdbstub_msg_write(kdb_buffer, retlen);
 	} else {
-		if (!dbg_io_ops->is_console) {
+		if (dbg_io_ops && !dbg_io_ops->is_console) {
 			len = strlen(kdb_buffer);
 			cp = kdb_buffer;
 			while (len--) {
@@ -743,7 +743,7 @@
 		kdb_input_flush();
 		c = console_drivers;
 
-		if (!dbg_io_ops->is_console) {
+		if (dbg_io_ops && !dbg_io_ops->is_console) {
 			len = strlen(moreprompt);
 			cp = moreprompt;
 			while (len--) {
diff --git a/kernel/debug/kdb/kdb_keyboard.c b/kernel/debug/kdb/kdb_keyboard.c
index 4bca634..118527a 100644
--- a/kernel/debug/kdb/kdb_keyboard.c
+++ b/kernel/debug/kdb/kdb_keyboard.c
@@ -25,6 +25,7 @@
 #define KBD_STAT_MOUSE_OBF	0x20	/* Mouse output buffer full */
 
 static int kbd_exists;
+static int kbd_last_ret;
 
 /*
  * Check if the keyboard controller has a keypress for us.
@@ -90,8 +91,11 @@
 		return -1;
 	}
 
-	if ((scancode & 0x80) != 0)
+	if ((scancode & 0x80) != 0) {
+		if (scancode == 0x9c)
+			kbd_last_ret = 0;
 		return -1;
+	}
 
 	scancode &= 0x7f;
 
@@ -178,35 +182,82 @@
 		return -1;	/* ignore unprintables */
 	}
 
-	if ((scancode & 0x7f) == 0x1c) {
-		/*
-		 * enter key.  All done.  Absorb the release scancode.
-		 */
-		while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
-			;
-
-		/*
-		 * Fetch the scancode
-		 */
-		scancode = inb(KBD_DATA_REG);
-		scanstatus = inb(KBD_STATUS_REG);
-
-		while (scanstatus & KBD_STAT_MOUSE_OBF) {
-			scancode = inb(KBD_DATA_REG);
-			scanstatus = inb(KBD_STATUS_REG);
-		}
-
-		if (scancode != 0x9c) {
-			/*
-			 * Wasn't an enter-release,  why not?
-			 */
-			kdb_printf("kdb: expected enter got 0x%x status 0x%x\n",
-			       scancode, scanstatus);
-		}
-
+	if (scancode == 0x1c) {
+		kbd_last_ret = 1;
 		return 13;
 	}
 
 	return keychar & 0xff;
 }
 EXPORT_SYMBOL_GPL(kdb_get_kbd_char);
+
+/*
+ * Best effort cleanup of ENTER break codes on leaving KDB. Called on
+ * exiting KDB, when we know we processed an ENTER or KP ENTER scan
+ * code.
+ */
+void kdb_kbd_cleanup_state(void)
+{
+	int scancode, scanstatus;
+
+	/*
+	 * Nothing to clean up, since either
+	 * ENTER was never pressed, or has already
+	 * gotten cleaned up.
+	 */
+	if (!kbd_last_ret)
+		return;
+
+	kbd_last_ret = 0;
+	/*
+	 * Enter key. Need to absorb the break code here, lest it gets
+	 * leaked out if we exit KDB as the result of processing 'g'.
+	 *
+	 * This has several interesting implications:
+	 * + Need to handle KP ENTER, which has break code 0xe0 0x9c.
+	 * + Need to handle repeat ENTER and repeat KP ENTER. Repeats
+	 *   only get a break code at the end of the repeated
+	 *   sequence. This means we can't propagate the repeated key
+	 *   press, and must swallow it away.
+	 * + Need to handle possible PS/2 mouse input.
+	 * + Need to handle mashed keys.
+	 */
+
+	while (1) {
+		while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
+			cpu_relax();
+
+		/*
+		 * Fetch the scancode.
+		 */
+		scancode = inb(KBD_DATA_REG);
+		scanstatus = inb(KBD_STATUS_REG);
+
+		/*
+		 * Skip mouse input.
+		 */
+		if (scanstatus & KBD_STAT_MOUSE_OBF)
+			continue;
+
+		/*
+		 * If we see 0xe0, this is either a break code for KP
+		 * ENTER, or a repeat make for KP ENTER. Either way,
+		 * since the second byte is equivalent to an ENTER,
+		 * skip the 0xe0 and try again.
+		 *
+		 * If we see 0x1c, this must be a repeat ENTER or KP
+		 * ENTER (and we swallowed 0xe0 before). Try again.
+		 *
+		 * We can also see make and break codes for other keys
+		 * mashed before or after pressing ENTER. Thus, if we
+		 * see anything other than 0x9c, we have to try again.
+		 *
+		 * Note, if you held some key as ENTER was depressed,
+		 * that break code would get leaked out.
+		 */
+		if (scancode != 0x9c)
+			continue;
+
+		return;
+	}
+}
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c
index e2ae734..67b847d 100644
--- a/kernel/debug/kdb/kdb_main.c
+++ b/kernel/debug/kdb/kdb_main.c
@@ -1400,6 +1400,9 @@
 	if (KDB_STATE(DOING_SS))
 		KDB_STATE_CLEAR(SSBPT);
 
+	/* Clean up any keyboard devices before leaving */
+	kdb_kbd_cleanup_state();
+
 	return result;
 }
 
diff --git a/kernel/debug/kdb/kdb_private.h b/kernel/debug/kdb/kdb_private.h
index e381d10..47c4e56 100644
--- a/kernel/debug/kdb/kdb_private.h
+++ b/kernel/debug/kdb/kdb_private.h
@@ -246,6 +246,13 @@
 
 extern void kdb_set_current_task(struct task_struct *);
 extern struct task_struct *kdb_current_task;
+
+#ifdef CONFIG_KDB_KEYBOARD
+extern void kdb_kbd_cleanup_state(void);
+#else /* ! CONFIG_KDB_KEYBOARD */
+#define kdb_kbd_cleanup_state()
+#endif /* ! CONFIG_KDB_KEYBOARD */
+
 #ifdef CONFIG_MODULES
 extern struct list_head *kdb_modules;
 #endif /* CONFIG_MODULES */
diff --git a/kernel/dma.c b/kernel/dma.c
index 68a2306..6c6262f 100644
--- a/kernel/dma.c
+++ b/kernel/dma.c
@@ -18,7 +18,6 @@
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <asm/dma.h>
-#include <asm/system.h>
 
 
 
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 4b50357..a6a9ec4 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -3348,7 +3348,7 @@
 	*running = ctx_time - event->tstamp_running;
 }
 
-void __weak perf_update_user_clock(struct perf_event_mmap_page *userpg, u64 now)
+void __weak arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
 {
 }
 
@@ -3398,7 +3398,7 @@
 	userpg->time_running = running +
 			atomic64_read(&event->child_total_time_running);
 
-	perf_update_user_clock(userpg, now);
+	arch_perf_update_userpage(userpg, now);
 
 	barrier();
 	++userpg->lock;
@@ -7116,6 +7116,13 @@
 
 	/* do not patch jump label more than once per second */
 	jump_label_rate_limit(&perf_sched_events, HZ);
+
+	/*
+	 * Build time assertion that we keep the data_head at the intended
+	 * location.  IOW, validation we got the __reserved[] size right.
+	 */
+	BUILD_BUG_ON((offsetof(struct perf_event_mmap_page, data_head))
+		     != 1024);
 }
 
 static int __init perf_event_sysfs_init(void)
diff --git a/kernel/exit.c b/kernel/exit.c
index 7ad335c..d8bd3b42 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -474,7 +474,7 @@
 		i = j * __NFDBITS;
 		if (i >= fdt->max_fds)
 			break;
-		set = fdt->open_fds->fds_bits[j++];
+		set = fdt->open_fds[j++];
 		while (set) {
 			if (set & 1) {
 				struct file * file = xchg(&fdt->fd[i], NULL);
@@ -687,11 +687,11 @@
 }
 
 /*
- * When we die, we re-parent all our children.
- * Try to give them to another thread in our thread
- * group, and if no such member exists, give it to
- * the child reaper process (ie "init") in our pid
- * space.
+ * When we die, we re-parent all our children, and try to:
+ * 1. give them to another thread in our thread group, if such a member exists
+ * 2. give it to the first ancestor process which prctl'd itself as a
+ *    child_subreaper for its children (like a service manager)
+ * 3. give it to the init process (PID 1) in our pid namespace
  */
 static struct task_struct *find_new_reaper(struct task_struct *father)
 	__releases(&tasklist_lock)
@@ -711,8 +711,11 @@
 
 	if (unlikely(pid_ns->child_reaper == father)) {
 		write_unlock_irq(&tasklist_lock);
-		if (unlikely(pid_ns == &init_pid_ns))
-			panic("Attempted to kill init!");
+		if (unlikely(pid_ns == &init_pid_ns)) {
+			panic("Attempted to kill init! exitcode=0x%08x\n",
+				father->signal->group_exit_code ?:
+					father->exit_code);
+		}
 
 		zap_pid_ns_processes(pid_ns);
 		write_lock_irq(&tasklist_lock);
@@ -722,6 +725,29 @@
 		 * forget_original_parent() must move them somewhere.
 		 */
 		pid_ns->child_reaper = init_pid_ns.child_reaper;
+	} else if (father->signal->has_child_subreaper) {
+		struct task_struct *reaper;
+
+		/*
+		 * Find the first ancestor marked as child_subreaper.
+		 * Note that the code below checks same_thread_group(reaper,
+		 * pid_ns->child_reaper).  This is what we need to DTRT in a
+		 * PID namespace. However we still need the check above, see
+		 * http://marc.info/?l=linux-kernel&m=131385460420380
+		 */
+		for (reaper = father->real_parent;
+		     reaper != &init_task;
+		     reaper = reaper->real_parent) {
+			if (same_thread_group(reaper, pid_ns->child_reaper))
+				break;
+			if (!reaper->signal->is_child_subreaper)
+				continue;
+			thread = reaper;
+			do {
+				if (!(thread->flags & PF_EXITING))
+					return reaper;
+			} while_each_thread(reaper, thread);
+		}
 	}
 
 	return pid_ns->child_reaper;
@@ -935,7 +961,7 @@
 	acct_update_integrals(tsk);
 	/* sync mm's RSS info before statistics gathering */
 	if (tsk->mm)
-		sync_mm_rss(tsk, tsk->mm);
+		sync_mm_rss(tsk->mm);
 	group_dead = atomic_dec_and_test(&tsk->signal->live);
 	if (group_dead) {
 		hrtimer_cancel(&tsk->signal->real_timer);
diff --git a/kernel/fork.c b/kernel/fork.c
index 26a7138..b9372a0 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -512,6 +512,23 @@
 	return NULL;
 }
 
+static void check_mm(struct mm_struct *mm)
+{
+	int i;
+
+	for (i = 0; i < NR_MM_COUNTERS; i++) {
+		long x = atomic_long_read(&mm->rss_stat.count[i]);
+
+		if (unlikely(x))
+			printk(KERN_ALERT "BUG: Bad rss-counter state "
+					  "mm:%p idx:%d val:%ld\n", mm, i, x);
+	}
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+	VM_BUG_ON(mm->pmd_huge_pte);
+#endif
+}
+
 /*
  * Allocate and initialize an mm_struct.
  */
@@ -539,9 +556,7 @@
 	mm_free_pgd(mm);
 	destroy_context(mm);
 	mmu_notifier_mm_destroy(mm);
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-	VM_BUG_ON(mm->pmd_huge_pte);
-#endif
+	check_mm(mm);
 	free_mm(mm);
 }
 EXPORT_SYMBOL_GPL(__mmdrop);
@@ -1036,6 +1051,9 @@
 	sig->oom_score_adj = current->signal->oom_score_adj;
 	sig->oom_score_adj_min = current->signal->oom_score_adj_min;
 
+	sig->has_child_subreaper = current->signal->has_child_subreaper ||
+				   current->signal->is_child_subreaper;
+
 	mutex_init(&sig->cred_guard_mutex);
 
 	return 0;
@@ -1223,6 +1241,7 @@
 #ifdef CONFIG_CPUSETS
 	p->cpuset_mem_spread_rotor = NUMA_NO_NODE;
 	p->cpuset_slab_spread_rotor = NUMA_NO_NODE;
+	seqcount_init(&p->mems_allowed_seq);
 #endif
 #ifdef CONFIG_TRACE_IRQFLAGS
 	p->irq_events = 0;
diff --git a/kernel/futex.c b/kernel/futex.c
index 72efa1e..e2b0fb9 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -59,6 +59,7 @@
 #include <linux/magic.h>
 #include <linux/pid.h>
 #include <linux/nsproxy.h>
+#include <linux/ptrace.h>
 
 #include <asm/futex.h>
 
@@ -2443,40 +2444,31 @@
 {
 	struct robust_list_head __user *head;
 	unsigned long ret;
-	const struct cred *cred = current_cred(), *pcred;
+	struct task_struct *p;
 
 	if (!futex_cmpxchg_enabled)
 		return -ENOSYS;
 
-	if (!pid)
-		head = current->robust_list;
-	else {
-		struct task_struct *p;
+	WARN_ONCE(1, "deprecated: get_robust_list will be deleted in 2013.\n");
 
-		ret = -ESRCH;
-		rcu_read_lock();
+	rcu_read_lock();
+
+	ret = -ESRCH;
+	if (!pid)
+		p = current;
+	else {
 		p = find_task_by_vpid(pid);
 		if (!p)
 			goto err_unlock;
-		ret = -EPERM;
-		pcred = __task_cred(p);
-		/* If victim is in different user_ns, then uids are not
-		   comparable, so we must have CAP_SYS_PTRACE */
-		if (cred->user->user_ns != pcred->user->user_ns) {
-			if (!ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
-				goto err_unlock;
-			goto ok;
-		}
-		/* If victim is in same user_ns, then uids are comparable */
-		if (cred->euid != pcred->euid &&
-		    cred->euid != pcred->uid &&
-		    !ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
-			goto err_unlock;
-ok:
-		head = p->robust_list;
-		rcu_read_unlock();
 	}
 
+	ret = -EPERM;
+	if (!ptrace_may_access(p, PTRACE_MODE_READ))
+		goto err_unlock;
+
+	head = p->robust_list;
+	rcu_read_unlock();
+
 	if (put_user(sizeof(*head), len_ptr))
 		return -EFAULT;
 	return put_user(head, head_ptr);
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
index 5f9e689..83e368b 100644
--- a/kernel/futex_compat.c
+++ b/kernel/futex_compat.c
@@ -10,6 +10,7 @@
 #include <linux/compat.h>
 #include <linux/nsproxy.h>
 #include <linux/futex.h>
+#include <linux/ptrace.h>
 
 #include <asm/uaccess.h>
 
@@ -136,40 +137,31 @@
 {
 	struct compat_robust_list_head __user *head;
 	unsigned long ret;
-	const struct cred *cred = current_cred(), *pcred;
+	struct task_struct *p;
 
 	if (!futex_cmpxchg_enabled)
 		return -ENOSYS;
 
-	if (!pid)
-		head = current->compat_robust_list;
-	else {
-		struct task_struct *p;
+	WARN_ONCE(1, "deprecated: get_robust_list will be deleted in 2013.\n");
 
-		ret = -ESRCH;
-		rcu_read_lock();
+	rcu_read_lock();
+
+	ret = -ESRCH;
+	if (!pid)
+		p = current;
+	else {
 		p = find_task_by_vpid(pid);
 		if (!p)
 			goto err_unlock;
-		ret = -EPERM;
-		pcred = __task_cred(p);
-		/* If victim is in different user_ns, then uids are not
-		   comparable, so we must have CAP_SYS_PTRACE */
-		if (cred->user->user_ns != pcred->user->user_ns) {
-			if (!ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
-				goto err_unlock;
-			goto ok;
-		}
-		/* If victim is in same user_ns, then uids are comparable */
-		if (cred->euid != pcred->euid &&
-		    cred->euid != pcred->uid &&
-		    !ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
-			goto err_unlock;
-ok:
-		head = p->compat_robust_list;
-		rcu_read_unlock();
 	}
 
+	ret = -EPERM;
+	if (!ptrace_may_access(p, PTRACE_MODE_READ))
+		goto err_unlock;
+
+	head = p->compat_robust_list;
+	rcu_read_unlock();
+
 	if (put_user(sizeof(*head), len_ptr))
 		return -EFAULT;
 	return put_user(ptr_to_compat(head), head_ptr);
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
index 5a38bf4..cf1a4a6 100644
--- a/kernel/irq/Kconfig
+++ b/kernel/irq/Kconfig
@@ -13,7 +13,7 @@
 # Options selectable by the architecture code
 
 # Make sparse irq Kconfig switch below available
-config HAVE_SPARSE_IRQ
+config MAY_HAVE_SPARSE_IRQ
        bool
 
 # Enable the generic irq autoprobe mechanism
@@ -56,13 +56,22 @@
 config IRQ_DOMAIN
 	bool
 
+config IRQ_DOMAIN_DEBUG
+	bool "Expose hardware/virtual IRQ mapping via debugfs"
+	depends on IRQ_DOMAIN && DEBUG_FS
+	help
+	  This option will show the mapping relationship between hardware irq
+	  numbers and Linux irq numbers. The mapping is exposed via debugfs
+	  in the file "virq_mapping".
+
+	  If you don't know what this means you don't need it.
+
 # Support forced irq threading
 config IRQ_FORCED_THREADING
        bool
 
 config SPARSE_IRQ
-	bool "Support sparse irq numbering"
-	depends on HAVE_SPARSE_IRQ
+	bool "Support sparse irq numbering" if MAY_HAVE_SPARSE_IRQ
 	---help---
 
 	  Sparse irq numbering is useful for distro kernels that want
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 6ff84e6..bdb1803 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -54,14 +54,18 @@
 static void irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
 {
 	/*
-	 * Wake up the handler thread for this action. In case the
-	 * thread crashed and was killed we just pretend that we
-	 * handled the interrupt. The hardirq handler has disabled the
-	 * device interrupt, so no irq storm is lurking. If the
+	 * In case the thread crashed and was killed we just pretend that
+	 * we handled the interrupt. The hardirq handler has disabled the
+	 * device interrupt, so no irq storm is lurking.
+	 */
+	if (action->thread->flags & PF_EXITING)
+		return;
+
+	/*
+	 * Wake up the handler thread for this action. If the
 	 * RUNTHREAD bit is already set, nothing to do.
 	 */
-	if ((action->thread->flags & PF_EXITING) ||
-	    test_and_set_bit(IRQTF_RUNTHREAD, &action->thread_flags))
+	if (test_and_set_bit(IRQTF_RUNTHREAD, &action->thread_flags))
 		return;
 
 	/*
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index af48e59..3601f3f 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -632,7 +632,7 @@
 	return revmap[hwirq];
 }
 
-#ifdef CONFIG_VIRQ_DEBUG
+#ifdef CONFIG_IRQ_DOMAIN_DEBUG
 static int virq_debug_show(struct seq_file *m, void *private)
 {
 	unsigned long flags;
@@ -668,7 +668,7 @@
 			data = irq_desc_get_chip_data(desc);
 			seq_printf(m, "0x%16p  ", data);
 
-			if (desc->irq_data.domain->of_node)
+			if (desc->irq_data.domain && desc->irq_data.domain->of_node)
 				p = desc->irq_data.domain->of_node->full_name;
 			else
 				p = none;
@@ -695,14 +695,14 @@
 
 static int __init irq_debugfs_init(void)
 {
-	if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root,
+	if (debugfs_create_file("irq_domain_mapping", S_IRUGO, NULL,
 				 NULL, &virq_debug_fops) == NULL)
 		return -ENOMEM;
 
 	return 0;
 }
 __initcall(irq_debugfs_init);
-#endif /* CONFIG_VIRQ_DEBUG */
+#endif /* CONFIG_IRQ_DOMAIN_DEBUG */
 
 int irq_domain_simple_map(struct irq_domain *d, unsigned int irq,
 			  irq_hw_number_t hwirq)
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index b0ccd1a..89a3ea8 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -282,7 +282,7 @@
 {
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	struct cpumask *set = irq_default_affinity;
-	int ret;
+	int ret, node = desc->irq_data.node;
 
 	/* Excludes PER_CPU and NO_BALANCE interrupts */
 	if (!irq_can_set_affinity(irq))
@@ -301,6 +301,13 @@
 	}
 
 	cpumask_and(mask, cpu_online_mask, set);
+	if (node != NUMA_NO_NODE) {
+		const struct cpumask *nodemask = cpumask_of_node(node);
+
+		/* make sure at least one of the cpus in nodemask is online */
+		if (cpumask_intersects(mask, nodemask))
+			cpumask_and(mask, mask, nodemask);
+	}
 	ret = chip->irq_set_affinity(&desc->irq_data, mask, false);
 	switch (ret) {
 	case IRQ_SET_MASK_OK:
@@ -645,7 +652,7 @@
  * is marked MASKED.
  */
 static void irq_finalize_oneshot(struct irq_desc *desc,
-				 struct irqaction *action, bool force)
+				 struct irqaction *action)
 {
 	if (!(desc->istate & IRQS_ONESHOT))
 		return;
@@ -679,7 +686,7 @@
 	 * we would clear the threads_oneshot bit of this thread which
 	 * was just set.
 	 */
-	if (!force && test_bit(IRQTF_RUNTHREAD, &action->thread_flags))
+	if (test_bit(IRQTF_RUNTHREAD, &action->thread_flags))
 		goto out_unlock;
 
 	desc->threads_oneshot &= ~action->thread_mask;
@@ -739,7 +746,7 @@
 
 	local_bh_disable();
 	ret = action->thread_fn(action->irq, action->dev_id);
-	irq_finalize_oneshot(desc, action, false);
+	irq_finalize_oneshot(desc, action);
 	local_bh_enable();
 	return ret;
 }
@@ -755,7 +762,7 @@
 	irqreturn_t ret;
 
 	ret = action->thread_fn(action->irq, action->dev_id);
-	irq_finalize_oneshot(desc, action, false);
+	irq_finalize_oneshot(desc, action);
 	return ret;
 }
 
@@ -844,7 +851,7 @@
 		wake_threads_waitq(desc);
 
 	/* Prevent a stale desc->threads_oneshot */
-	irq_finalize_oneshot(desc, action, true);
+	irq_finalize_oneshot(desc, action);
 }
 
 static void irq_setup_forced_threading(struct irqaction *new)
diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c
index 4742090..c3c8975 100644
--- a/kernel/irq/migration.c
+++ b/kernel/irq/migration.c
@@ -43,12 +43,16 @@
 	 * masking the irqs.
 	 */
 	if (likely(cpumask_any_and(desc->pending_mask, cpu_online_mask)
-		   < nr_cpu_ids))
-		if (!chip->irq_set_affinity(&desc->irq_data,
-					    desc->pending_mask, false)) {
+		   < nr_cpu_ids)) {
+		int ret = chip->irq_set_affinity(&desc->irq_data,
+						 desc->pending_mask, false);
+		switch (ret) {
+		case IRQ_SET_MASK_OK:
 			cpumask_copy(desc->irq_data.affinity, desc->pending_mask);
+		case IRQ_SET_MASK_OK_NOCOPY:
 			irq_set_thread_affinity(desc);
 		}
+	}
 
 	cpumask_clear(desc->pending_mask);
 }
diff --git a/kernel/irq_work.c b/kernel/irq_work.c
index c3c46c7..0c56d44 100644
--- a/kernel/irq_work.c
+++ b/kernel/irq_work.c
@@ -5,6 +5,7 @@
  * context. The enqueueing is NMI-safe.
  */
 
+#include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/export.h>
 #include <linux/irq_work.h>
diff --git a/kernel/kexec.c b/kernel/kexec.c
index a6a675c..4e2e472 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -37,7 +37,6 @@
 #include <asm/page.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/system.h>
 #include <asm/sections.h>
 
 /* Per cpu memory for storing cpu states in case of system crash. */
@@ -1359,6 +1358,10 @@
 
 	if (*cur == '@')
 		*crash_base = memparse(cur+1, &cur);
+	else if (*cur != ' ' && *cur != '\0') {
+		pr_warning("crashkernel: unrecognized char\n");
+		return -EINVAL;
+	}
 
 	return 0;
 }
@@ -1462,7 +1465,9 @@
 
 	VMCOREINFO_SYMBOL(init_uts_ns);
 	VMCOREINFO_SYMBOL(node_online_map);
+#ifdef CONFIG_MMU
 	VMCOREINFO_SYMBOL(swapper_pg_dir);
+#endif
 	VMCOREINFO_SYMBOL(_stext);
 	VMCOREINFO_SYMBOL(vmlist);
 
diff --git a/kernel/kmod.c b/kernel/kmod.c
index a0a8854..05698a7 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -60,6 +60,43 @@
 */
 char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";
 
+static void free_modprobe_argv(struct subprocess_info *info)
+{
+	kfree(info->argv[3]); /* check call_modprobe() */
+	kfree(info->argv);
+}
+
+static int call_modprobe(char *module_name, int wait)
+{
+	static char *envp[] = {
+		"HOME=/",
+		"TERM=linux",
+		"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+		NULL
+	};
+
+	char **argv = kmalloc(sizeof(char *[5]), GFP_KERNEL);
+	if (!argv)
+		goto out;
+
+	module_name = kstrdup(module_name, GFP_KERNEL);
+	if (!module_name)
+		goto free_argv;
+
+	argv[0] = modprobe_path;
+	argv[1] = "-q";
+	argv[2] = "--";
+	argv[3] = module_name;	/* check free_modprobe_argv() */
+	argv[4] = NULL;
+
+	return call_usermodehelper_fns(modprobe_path, argv, envp,
+		wait | UMH_KILLABLE, NULL, free_modprobe_argv, NULL);
+free_argv:
+	kfree(argv);
+out:
+	return -ENOMEM;
+}
+
 /**
  * __request_module - try to load a kernel module
  * @wait: wait (or not) for the operation to complete
@@ -81,11 +118,6 @@
 	char module_name[MODULE_NAME_LEN];
 	unsigned int max_modprobes;
 	int ret;
-	char *argv[] = { modprobe_path, "-q", "--", module_name, NULL };
-	static char *envp[] = { "HOME=/",
-				"TERM=linux",
-				"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
-				NULL };
 	static atomic_t kmod_concurrent = ATOMIC_INIT(0);
 #define MAX_KMOD_CONCURRENT 50	/* Completely arbitrary value - KAO */
 	static int kmod_loop_msg;
@@ -128,9 +160,7 @@
 
 	trace_module_request(module_name, wait, _RET_IP_);
 
-	ret = call_usermodehelper_fns(modprobe_path, argv, envp,
-			wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC,
-			NULL, NULL, NULL);
+	ret = call_modprobe(module_name, wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC);
 
 	atomic_dec(&kmod_concurrent);
 	return ret;
@@ -188,7 +218,7 @@
 	/* Exec failed? */
 fail:
 	sub_info->retval = retval;
-	do_exit(0);
+	return 0;
 }
 
 void call_usermodehelper_freeinfo(struct subprocess_info *info)
@@ -199,6 +229,19 @@
 }
 EXPORT_SYMBOL(call_usermodehelper_freeinfo);
 
+static void umh_complete(struct subprocess_info *sub_info)
+{
+	struct completion *comp = xchg(&sub_info->complete, NULL);
+	/*
+	 * See call_usermodehelper_exec(). If xchg() returns NULL
+	 * we own sub_info, the UMH_KILLABLE caller has gone away.
+	 */
+	if (comp)
+		complete(comp);
+	else
+		call_usermodehelper_freeinfo(sub_info);
+}
+
 /* Keventd can't block, but this (a child) can. */
 static int wait_for_helper(void *data)
 {
@@ -235,7 +278,7 @@
 			sub_info->retval = ret;
 	}
 
-	complete(sub_info->complete);
+	umh_complete(sub_info);
 	return 0;
 }
 
@@ -244,7 +287,7 @@
 {
 	struct subprocess_info *sub_info =
 		container_of(work, struct subprocess_info, work);
-	enum umh_wait wait = sub_info->wait;
+	int wait = sub_info->wait & ~UMH_KILLABLE;
 	pid_t pid;
 
 	/* CLONE_VFORK: wait until the usermode helper has execve'd
@@ -269,7 +312,7 @@
 	case UMH_WAIT_EXEC:
 		if (pid < 0)
 			sub_info->retval = pid;
-		complete(sub_info->complete);
+		umh_complete(sub_info);
 	}
 }
 
@@ -279,7 +322,7 @@
  * land has been frozen during a system-wide hibernation or suspend operation).
  * Should always be manipulated under umhelper_sem acquired for write.
  */
-static int usermodehelper_disabled = 1;
+static enum umh_disable_depth usermodehelper_disabled = UMH_DISABLED;
 
 /* Number of helpers running */
 static atomic_t running_helpers = ATOMIC_INIT(0);
@@ -291,32 +334,110 @@
 static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq);
 
 /*
+ * Used by usermodehelper_read_lock_wait() to wait for usermodehelper_disabled
+ * to become 'false'.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_disabled_waitq);
+
+/*
  * Time to wait for running_helpers to become zero before the setting of
  * usermodehelper_disabled in usermodehelper_disable() fails
  */
 #define RUNNING_HELPERS_TIMEOUT	(5 * HZ)
 
-void read_lock_usermodehelper(void)
+int usermodehelper_read_trylock(void)
 {
-	down_read(&umhelper_sem);
-}
-EXPORT_SYMBOL_GPL(read_lock_usermodehelper);
+	DEFINE_WAIT(wait);
+	int ret = 0;
 
-void read_unlock_usermodehelper(void)
+	down_read(&umhelper_sem);
+	for (;;) {
+		prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
+				TASK_INTERRUPTIBLE);
+		if (!usermodehelper_disabled)
+			break;
+
+		if (usermodehelper_disabled == UMH_DISABLED)
+			ret = -EAGAIN;
+
+		up_read(&umhelper_sem);
+
+		if (ret)
+			break;
+
+		schedule();
+		try_to_freeze();
+
+		down_read(&umhelper_sem);
+	}
+	finish_wait(&usermodehelper_disabled_waitq, &wait);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
+
+long usermodehelper_read_lock_wait(long timeout)
+{
+	DEFINE_WAIT(wait);
+
+	if (timeout < 0)
+		return -EINVAL;
+
+	down_read(&umhelper_sem);
+	for (;;) {
+		prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
+				TASK_UNINTERRUPTIBLE);
+		if (!usermodehelper_disabled)
+			break;
+
+		up_read(&umhelper_sem);
+
+		timeout = schedule_timeout(timeout);
+		if (!timeout)
+			break;
+
+		down_read(&umhelper_sem);
+	}
+	finish_wait(&usermodehelper_disabled_waitq, &wait);
+	return timeout;
+}
+EXPORT_SYMBOL_GPL(usermodehelper_read_lock_wait);
+
+void usermodehelper_read_unlock(void)
 {
 	up_read(&umhelper_sem);
 }
-EXPORT_SYMBOL_GPL(read_unlock_usermodehelper);
+EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
 
 /**
- * usermodehelper_disable - prevent new helpers from being started
+ * __usermodehelper_set_disable_depth - Modify usermodehelper_disabled.
+ * depth: New value to assign to usermodehelper_disabled.
+ *
+ * Change the value of usermodehelper_disabled (under umhelper_sem locked for
+ * writing) and wakeup tasks waiting for it to change.
  */
-int usermodehelper_disable(void)
+void __usermodehelper_set_disable_depth(enum umh_disable_depth depth)
+{
+	down_write(&umhelper_sem);
+	usermodehelper_disabled = depth;
+	wake_up(&usermodehelper_disabled_waitq);
+	up_write(&umhelper_sem);
+}
+
+/**
+ * __usermodehelper_disable - Prevent new helpers from being started.
+ * @depth: New value to assign to usermodehelper_disabled.
+ *
+ * Set usermodehelper_disabled to @depth and wait for running helpers to exit.
+ */
+int __usermodehelper_disable(enum umh_disable_depth depth)
 {
 	long retval;
 
+	if (!depth)
+		return -EINVAL;
+
 	down_write(&umhelper_sem);
-	usermodehelper_disabled = 1;
+	usermodehelper_disabled = depth;
 	up_write(&umhelper_sem);
 
 	/*
@@ -331,31 +452,10 @@
 	if (retval)
 		return 0;
 
-	down_write(&umhelper_sem);
-	usermodehelper_disabled = 0;
-	up_write(&umhelper_sem);
+	__usermodehelper_set_disable_depth(UMH_ENABLED);
 	return -EAGAIN;
 }
 
-/**
- * usermodehelper_enable - allow new helpers to be started again
- */
-void usermodehelper_enable(void)
-{
-	down_write(&umhelper_sem);
-	usermodehelper_disabled = 0;
-	up_write(&umhelper_sem);
-}
-
-/**
- * usermodehelper_is_disabled - check if new helpers are allowed to be started
- */
-bool usermodehelper_is_disabled(void)
-{
-	return usermodehelper_disabled;
-}
-EXPORT_SYMBOL_GPL(usermodehelper_is_disabled);
-
 static void helper_lock(void)
 {
 	atomic_inc(&running_helpers);
@@ -435,8 +535,7 @@
  * asynchronously if wait is not set, and runs as a child of keventd.
  * (ie. it runs with full root capabilities).
  */
-int call_usermodehelper_exec(struct subprocess_info *sub_info,
-			     enum umh_wait wait)
+int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
 {
 	DECLARE_COMPLETION_ONSTACK(done);
 	int retval = 0;
@@ -456,9 +555,21 @@
 	queue_work(khelper_wq, &sub_info->work);
 	if (wait == UMH_NO_WAIT)	/* task has freed sub_info */
 		goto unlock;
-	wait_for_completion(&done);
-	retval = sub_info->retval;
 
+	if (wait & UMH_KILLABLE) {
+		retval = wait_for_completion_killable(&done);
+		if (!retval)
+			goto wait_done;
+
+		/* umh_complete() will see NULL and free sub_info */
+		if (xchg(&sub_info->complete, NULL))
+			goto unlock;
+		/* fallthrough, umh_complete() was already called */
+	}
+
+	wait_for_completion(&done);
+wait_done:
+	retval = sub_info->retval;
 out:
 	call_usermodehelper_freeinfo(sub_info);
 unlock:
diff --git a/kernel/module.c b/kernel/module.c
index 2c93276..78ac6ec 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -105,6 +105,7 @@
 
 /* Block module loading/unloading? */
 int modules_disabled = 0;
+core_param(nomodule, modules_disabled, bint, 0);
 
 /* Waiting for a module to finish initializing? */
 static DECLARE_WAIT_QUEUE_HEAD(module_wq);
@@ -903,6 +904,36 @@
 static struct module_attribute modinfo_refcnt =
 	__ATTR(refcnt, 0444, show_refcnt, NULL);
 
+void __module_get(struct module *module)
+{
+	if (module) {
+		preempt_disable();
+		__this_cpu_inc(module->refptr->incs);
+		trace_module_get(module, _RET_IP_);
+		preempt_enable();
+	}
+}
+EXPORT_SYMBOL(__module_get);
+
+bool try_module_get(struct module *module)
+{
+	bool ret = true;
+
+	if (module) {
+		preempt_disable();
+
+		if (likely(module_is_live(module))) {
+			__this_cpu_inc(module->refptr->incs);
+			trace_module_get(module, _RET_IP_);
+		} else
+			ret = false;
+
+		preempt_enable();
+	}
+	return ret;
+}
+EXPORT_SYMBOL(try_module_get);
+
 void module_put(struct module *module)
 {
 	if (module) {
@@ -2380,8 +2411,7 @@
 		return -ENOEXEC;
 
 	/* Suck in entire file: we'll want most of it. */
-	/* vmalloc barfs on "unusual" numbers.  Check here */
-	if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL)
+	if ((hdr = vmalloc(len)) == NULL)
 		return -ENOMEM;
 
 	if (copy_from_user(hdr, umod, len) != 0) {
@@ -2922,7 +2952,8 @@
 	mutex_unlock(&module_mutex);
 
 	/* Module is ready to execute: parsing args may do that. */
-	err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL);
+	err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
+			 -32768, 32767, NULL);
 	if (err < 0)
 		goto unlink;
 
diff --git a/kernel/padata.c b/kernel/padata.c
index 6f10eb2..89fe3d1 100644
--- a/kernel/padata.c
+++ b/kernel/padata.c
@@ -1,6 +1,8 @@
 /*
  * padata.c - generic interface to process data streams in parallel
  *
+ * See Documentation/padata.txt for an api documentation.
+ *
  * Copyright (C) 2008, 2009 secunet Security Networks AG
  * Copyright (C) 2008, 2009 Steffen Klassert <steffen.klassert@secunet.com>
  *
@@ -354,13 +356,13 @@
 	if (!alloc_cpumask_var(&pd->cpumask.pcpu, GFP_KERNEL))
 		return -ENOMEM;
 
-	cpumask_and(pd->cpumask.pcpu, pcpumask, cpu_active_mask);
+	cpumask_and(pd->cpumask.pcpu, pcpumask, cpu_online_mask);
 	if (!alloc_cpumask_var(&pd->cpumask.cbcpu, GFP_KERNEL)) {
 		free_cpumask_var(pd->cpumask.cbcpu);
 		return -ENOMEM;
 	}
 
-	cpumask_and(pd->cpumask.cbcpu, cbcpumask, cpu_active_mask);
+	cpumask_and(pd->cpumask.cbcpu, cbcpumask, cpu_online_mask);
 	return 0;
 }
 
@@ -564,7 +566,7 @@
 static bool padata_validate_cpumask(struct padata_instance *pinst,
 				    const struct cpumask *cpumask)
 {
-	if (!cpumask_intersects(cpumask, cpu_active_mask)) {
+	if (!cpumask_intersects(cpumask, cpu_online_mask)) {
 		pinst->flags |= PADATA_INVALID;
 		return false;
 	}
@@ -678,7 +680,7 @@
 {
 	struct parallel_data *pd;
 
-	if (cpumask_test_cpu(cpu, cpu_active_mask)) {
+	if (cpumask_test_cpu(cpu, cpu_online_mask)) {
 		pd = padata_alloc_pd(pinst, pinst->cpumask.pcpu,
 				     pinst->cpumask.cbcpu);
 		if (!pd)
@@ -746,6 +748,9 @@
 			return -ENOMEM;
 
 		padata_replace(pinst, pd);
+
+		cpumask_clear_cpu(cpu, pd->cpumask.cbcpu);
+		cpumask_clear_cpu(cpu, pd->cpumask.pcpu);
 	}
 
 	return 0;
diff --git a/kernel/params.c b/kernel/params.c
index 4bc965d..f37d826 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -15,7 +15,6 @@
     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/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/errno.h>
@@ -88,6 +87,8 @@
 		     char *val,
 		     const struct kernel_param *params,
 		     unsigned num_params,
+		     s16 min_level,
+		     s16 max_level,
 		     int (*handle_unknown)(char *param, char *val))
 {
 	unsigned int i;
@@ -96,6 +97,9 @@
 	/* Find parameter */
 	for (i = 0; i < num_params; i++) {
 		if (parameq(param, params[i].name)) {
+			if (params[i].level < min_level
+			    || 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)
@@ -175,6 +179,8 @@
 	       char *args,
 	       const struct kernel_param *params,
 	       unsigned num,
+	       s16 min_level,
+	       s16 max_level,
 	       int (*unknown)(char *param, char *val))
 {
 	char *param, *val;
@@ -190,7 +196,8 @@
 
 		args = next_arg(args, &param, &val);
 		irq_was_disabled = irqs_disabled();
-		ret = parse_one(param, val, params, num, unknown);
+		ret = parse_one(param, val, params, num,
+				min_level, max_level, unknown);
 		if (irq_was_disabled && !irqs_disabled()) {
 			printk(KERN_WARNING "parse_args(): option '%s' enabled "
 					"irq's!\n", param);
@@ -298,35 +305,18 @@
 /* Actually could be a bool or an int, for historical reasons. */
 int param_set_bool(const char *val, const struct kernel_param *kp)
 {
-	bool v;
-	int ret;
-
 	/* No equals means "set"... */
 	if (!val) val = "1";
 
 	/* One of =[yYnN01] */
-	ret = strtobool(val, &v);
-	if (ret)
-		return ret;
-
-	if (kp->flags & KPARAM_ISBOOL)
-		*(bool *)kp->arg = v;
-	else
-		*(int *)kp->arg = v;
-	return 0;
+	return strtobool(val, kp->arg);
 }
 EXPORT_SYMBOL(param_set_bool);
 
 int param_get_bool(char *buffer, const struct kernel_param *kp)
 {
-	bool val;
-	if (kp->flags & KPARAM_ISBOOL)
-		val = *(bool *)kp->arg;
-	else
-		val = *(int *)kp->arg;
-
 	/* Y and N chosen as being relatively non-coder friendly */
-	return sprintf(buffer, "%c", val ? 'Y' : 'N');
+	return sprintf(buffer, "%c", *(bool *)kp->arg ? 'Y' : 'N');
 }
 EXPORT_SYMBOL(param_get_bool);
 
@@ -344,7 +334,6 @@
 	struct kernel_param dummy;
 
 	dummy.arg = &boolval;
-	dummy.flags = KPARAM_ISBOOL;
 	ret = param_set_bool(val, &dummy);
 	if (ret == 0)
 		*(bool *)kp->arg = !boolval;
@@ -373,7 +362,6 @@
 	/* Match bool exactly, by re-using it. */
 	boolkp = *kp;
 	boolkp.arg = &v;
-	boolkp.flags |= KPARAM_ISBOOL;
 
 	ret = param_set_bool(val, &boolkp);
 	if (ret == 0)
@@ -394,7 +382,7 @@
 		       unsigned int min, unsigned int max,
 		       void *elem, int elemsize,
 		       int (*set)(const char *, const struct kernel_param *kp),
-		       u16 flags,
+		       s16 level,
 		       unsigned int *num)
 {
 	int ret;
@@ -404,7 +392,7 @@
 	/* Get the name right for errors. */
 	kp.name = name;
 	kp.arg = elem;
-	kp.flags = flags;
+	kp.level = level;
 
 	*num = 0;
 	/* We expect a comma-separated list of values. */
@@ -445,7 +433,7 @@
 	unsigned int temp_num;
 
 	return param_array(kp->name, val, 1, arr->max, arr->elem,
-			   arr->elemsize, arr->ops->set, kp->flags,
+			   arr->elemsize, arr->ops->set, kp->level,
 			   arr->num ?: &temp_num);
 }
 
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index a896839..57bc1fd 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -15,6 +15,7 @@
 #include <linux/acct.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
+#include <linux/reboot.h>
 
 #define BITS_PER_PAGE		(PAGE_SIZE*8)
 
@@ -168,13 +169,9 @@
 	while (nr > 0) {
 		rcu_read_lock();
 
-		/*
-		 * Any nested-container's init processes won't ignore the
-		 * SEND_SIG_NOINFO signal, see send_signal()->si_fromuser().
-		 */
 		task = pid_task(find_vpid(nr), PIDTYPE_PID);
-		if (task)
-			send_sig_info(SIGKILL, SEND_SIG_NOINFO, task);
+		if (task && !__fatal_signal_pending(task))
+			send_sig_info(SIGKILL, SEND_SIG_FORCED, task);
 
 		rcu_read_unlock();
 
@@ -187,6 +184,9 @@
 		rc = sys_wait4(-1, NULL, __WALL, NULL);
 	} while (rc != -ECHILD);
 
+	if (pid_ns->reboot)
+		current->signal->group_exit_code = pid_ns->reboot;
+
 	acct_exit_ns(pid_ns);
 	return;
 }
@@ -221,6 +221,35 @@
 
 static struct ctl_path kern_path[] = { { .procname = "kernel", }, { } };
 
+int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd)
+{
+	if (pid_ns == &init_pid_ns)
+		return 0;
+
+	switch (cmd) {
+	case LINUX_REBOOT_CMD_RESTART2:
+	case LINUX_REBOOT_CMD_RESTART:
+		pid_ns->reboot = SIGHUP;
+		break;
+
+	case LINUX_REBOOT_CMD_POWER_OFF:
+	case LINUX_REBOOT_CMD_HALT:
+		pid_ns->reboot = SIGINT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	read_lock(&tasklist_lock);
+	force_sig(SIGKILL, pid_ns->child_reaper);
+	read_unlock(&tasklist_lock);
+
+	do_exit(0);
+
+	/* Not reached */
+	return 0;
+}
+
 static __init int pid_namespaces_init(void)
 {
 	pid_ns_cachep = KMEM_CACHE(pid_namespace, SLAB_PANIC);
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 0a186cf..e09dfbf 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -16,7 +16,6 @@
 #include <linux/string.h>
 #include <linux/device.h>
 #include <linux/async.h>
-#include <linux/kmod.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
 #include <linux/mount.h>
@@ -611,14 +610,10 @@
 	if (error)
 		goto Exit;
 
-	error = usermodehelper_disable();
-	if (error)
-		goto Exit;
-
 	/* Allocate memory management structures */
 	error = create_basic_memory_bitmaps();
 	if (error)
-		goto Enable_umh;
+		goto Exit;
 
 	printk(KERN_INFO "PM: Syncing filesystems ... ");
 	sys_sync();
@@ -661,8 +656,6 @@
 
  Free_bitmaps:
 	free_basic_memory_bitmaps();
- Enable_umh:
-	usermodehelper_enable();
  Exit:
 	pm_notifier_call_chain(PM_POST_HIBERNATION);
 	pm_restore_console();
@@ -777,16 +770,10 @@
 	if (error)
 		goto close_finish;
 
-	error = usermodehelper_disable();
+	error = create_basic_memory_bitmaps();
 	if (error)
 		goto close_finish;
 
-	error = create_basic_memory_bitmaps();
-	if (error) {
-		usermodehelper_enable();
-		goto close_finish;
-	}
-
 	pr_debug("PM: Preparing processes for restore.\n");
 	error = freeze_processes();
 	if (error) {
@@ -806,7 +793,6 @@
 	thaw_processes();
  Done:
 	free_basic_memory_bitmaps();
-	usermodehelper_enable();
  Finish:
 	pm_notifier_call_chain(PM_POST_RESTORE);
 	pm_restore_console();
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 0d2aeb2..19db29f 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -16,6 +16,7 @@
 #include <linux/freezer.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
+#include <linux/kmod.h>
 
 /* 
  * Timeout for stopping processes
@@ -122,6 +123,10 @@
 {
 	int error;
 
+	error = __usermodehelper_disable(UMH_FREEZING);
+	if (error)
+		return error;
+
 	if (!pm_freezing)
 		atomic_inc(&system_freezing_cnt);
 
@@ -130,6 +135,7 @@
 	error = try_to_freeze_tasks(true);
 	if (!error) {
 		printk("done.");
+		__usermodehelper_set_disable_depth(UMH_DISABLED);
 		oom_killer_disable();
 	}
 	printk("\n");
@@ -187,6 +193,8 @@
 	} while_each_thread(g, p);
 	read_unlock(&tasklist_lock);
 
+	usermodehelper_enable();
+
 	schedule();
 	printk("done.\n");
 }
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index d6d6dbd..6a031e6 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -230,6 +230,21 @@
 EXPORT_SYMBOL_GPL(pm_qos_request_active);
 
 /**
+ * pm_qos_work_fn - the timeout handler of pm_qos_update_request_timeout
+ * @work: work struct for the delayed work (timeout)
+ *
+ * This cancels the timeout request by falling back to the default at timeout.
+ */
+static void pm_qos_work_fn(struct work_struct *work)
+{
+	struct pm_qos_request *req = container_of(to_delayed_work(work),
+						  struct pm_qos_request,
+						  work);
+
+	pm_qos_update_request(req, PM_QOS_DEFAULT_VALUE);
+}
+
+/**
  * pm_qos_add_request - inserts new qos request into the list
  * @req: pointer to a preallocated handle
  * @pm_qos_class: identifies which list of qos request to use
@@ -253,6 +268,7 @@
 		return;
 	}
 	req->pm_qos_class = pm_qos_class;
+	INIT_DELAYED_WORK(&req->work, pm_qos_work_fn);
 	pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints,
 			     &req->node, PM_QOS_ADD_REQ, value);
 }
@@ -279,6 +295,9 @@
 		return;
 	}
 
+	if (delayed_work_pending(&req->work))
+		cancel_delayed_work_sync(&req->work);
+
 	if (new_value != req->node.prio)
 		pm_qos_update_target(
 			pm_qos_array[req->pm_qos_class]->constraints,
@@ -287,6 +306,34 @@
 EXPORT_SYMBOL_GPL(pm_qos_update_request);
 
 /**
+ * pm_qos_update_request_timeout - modifies an existing qos request temporarily.
+ * @req : handle to list element holding a pm_qos request to use
+ * @new_value: defines the temporal qos request
+ * @timeout_us: the effective duration of this qos request in usecs.
+ *
+ * After timeout_us, this qos request is cancelled automatically.
+ */
+void pm_qos_update_request_timeout(struct pm_qos_request *req, s32 new_value,
+				   unsigned long timeout_us)
+{
+	if (!req)
+		return;
+	if (WARN(!pm_qos_request_active(req),
+		 "%s called for unknown object.", __func__))
+		return;
+
+	if (delayed_work_pending(&req->work))
+		cancel_delayed_work_sync(&req->work);
+
+	if (new_value != req->node.prio)
+		pm_qos_update_target(
+			pm_qos_array[req->pm_qos_class]->constraints,
+			&req->node, PM_QOS_UPDATE_REQ, new_value);
+
+	schedule_delayed_work(&req->work, usecs_to_jiffies(timeout_us));
+}
+
+/**
  * pm_qos_remove_request - modifies an existing qos request
  * @req: handle to request list element
  *
@@ -305,6 +352,9 @@
 		return;
 	}
 
+	if (delayed_work_pending(&req->work))
+		cancel_delayed_work_sync(&req->work);
+
 	pm_qos_update_target(pm_qos_array[req->pm_qos_class]->constraints,
 			     &req->node, PM_QOS_REMOVE_REQ,
 			     PM_QOS_DEFAULT_VALUE);
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 88e5c967..396d262 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -12,7 +12,6 @@
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/kmod.h>
 #include <linux/console.h>
 #include <linux/cpu.h>
 #include <linux/syscalls.h>
@@ -102,17 +101,12 @@
 	if (error)
 		goto Finish;
 
-	error = usermodehelper_disable();
-	if (error)
-		goto Finish;
-
 	error = suspend_freeze_processes();
 	if (!error)
 		return 0;
 
 	suspend_stats.failed_freeze++;
 	dpm_save_failed_step(SUSPEND_FREEZE);
-	usermodehelper_enable();
  Finish:
 	pm_notifier_call_chain(PM_POST_SUSPEND);
 	pm_restore_console();
@@ -259,7 +253,6 @@
 static void suspend_finish(void)
 {
 	suspend_thaw_processes();
-	usermodehelper_enable();
 	pm_notifier_call_chain(PM_POST_SUSPEND);
 	pm_restore_console();
 }
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 33c4329..91b0fd0 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -12,7 +12,6 @@
 #include <linux/suspend.h>
 #include <linux/syscalls.h>
 #include <linux/reboot.h>
-#include <linux/kmod.h>
 #include <linux/string.h>
 #include <linux/device.h>
 #include <linux/miscdevice.h>
@@ -222,14 +221,8 @@
 		sys_sync();
 		printk("done.\n");
 
-		error = usermodehelper_disable();
-		if (error)
-			break;
-
 		error = freeze_processes();
-		if (error)
-			usermodehelper_enable();
-		else
+		if (!error)
 			data->frozen = 1;
 		break;
 
@@ -238,7 +231,6 @@
 			break;
 		pm_restore_gfp_mask();
 		thaw_processes();
-		usermodehelper_enable();
 		data->frozen = 0;
 		break;
 
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 00ab2ca..ee8d49b 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -231,26 +231,22 @@
 }
 
 static int ptrace_attach(struct task_struct *task, long request,
+			 unsigned long addr,
 			 unsigned long flags)
 {
 	bool seize = (request == PTRACE_SEIZE);
 	int retval;
 
-	/*
-	 * SEIZE will enable new ptrace behaviors which will be implemented
-	 * gradually.  SEIZE_DEVEL is used to prevent applications
-	 * expecting full SEIZE behaviors trapping on kernel commits which
-	 * are still in the process of implementing them.
-	 *
-	 * Only test programs for new ptrace behaviors being implemented
-	 * should set SEIZE_DEVEL.  If unset, SEIZE will fail with -EIO.
-	 *
-	 * Once SEIZE behaviors are completely implemented, this flag and
-	 * the following test will be removed.
-	 */
 	retval = -EIO;
-	if (seize && !(flags & PTRACE_SEIZE_DEVEL))
-		goto out;
+	if (seize) {
+		if (addr != 0)
+			goto out;
+		if (flags & ~(unsigned long)PTRACE_O_MASK)
+			goto out;
+		flags = PT_PTRACED | PT_SEIZED | (flags << PT_OPT_FLAG_SHIFT);
+	} else {
+		flags = PT_PTRACED;
+	}
 
 	audit_ptrace(task);
 
@@ -262,7 +258,7 @@
 
 	/*
 	 * Protect exec's credential calculations against our interference;
-	 * interference; SUID, SGID and LSM creds get determined differently
+	 * SUID, SGID and LSM creds get determined differently
 	 * under ptrace.
 	 */
 	retval = -ERESTARTNOINTR;
@@ -282,11 +278,11 @@
 	if (task->ptrace)
 		goto unlock_tasklist;
 
-	task->ptrace = PT_PTRACED;
 	if (seize)
-		task->ptrace |= PT_SEIZED;
+		flags |= PT_SEIZED;
 	if (ns_capable(task_user_ns(task), CAP_SYS_PTRACE))
-		task->ptrace |= PT_PTRACE_CAP;
+		flags |= PT_PTRACE_CAP;
+	task->ptrace = flags;
 
 	__ptrace_link(task, current);
 
@@ -528,30 +524,18 @@
 
 static int ptrace_setoptions(struct task_struct *child, unsigned long data)
 {
-	child->ptrace &= ~PT_TRACE_MASK;
+	unsigned flags;
 
-	if (data & PTRACE_O_TRACESYSGOOD)
-		child->ptrace |= PT_TRACESYSGOOD;
+	if (data & ~(unsigned long)PTRACE_O_MASK)
+		return -EINVAL;
 
-	if (data & PTRACE_O_TRACEFORK)
-		child->ptrace |= PT_TRACE_FORK;
+	/* Avoid intermediate state when all opts are cleared */
+	flags = child->ptrace;
+	flags &= ~(PTRACE_O_MASK << PT_OPT_FLAG_SHIFT);
+	flags |= (data << PT_OPT_FLAG_SHIFT);
+	child->ptrace = flags;
 
-	if (data & PTRACE_O_TRACEVFORK)
-		child->ptrace |= PT_TRACE_VFORK;
-
-	if (data & PTRACE_O_TRACECLONE)
-		child->ptrace |= PT_TRACE_CLONE;
-
-	if (data & PTRACE_O_TRACEEXEC)
-		child->ptrace |= PT_TRACE_EXEC;
-
-	if (data & PTRACE_O_TRACEVFORKDONE)
-		child->ptrace |= PT_TRACE_VFORK_DONE;
-
-	if (data & PTRACE_O_TRACEEXIT)
-		child->ptrace |= PT_TRACE_EXIT;
-
-	return (data & ~PTRACE_O_MASK) ? -EINVAL : 0;
+	return 0;
 }
 
 static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info)
@@ -891,7 +875,7 @@
 	}
 
 	if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) {
-		ret = ptrace_attach(child, request, data);
+		ret = ptrace_attach(child, request, addr, data);
 		/*
 		 * Some architectures need to do book-keeping after
 		 * a ptrace attach.
@@ -1034,7 +1018,7 @@
 	}
 
 	if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) {
-		ret = ptrace_attach(child, request, data);
+		ret = ptrace_attach(child, request, addr, data);
 		/*
 		 * Some architectures need to do book-keeping after
 		 * a ptrace attach.
diff --git a/kernel/rwsem.c b/kernel/rwsem.c
index b152f74..6850f53 100644
--- a/kernel/rwsem.c
+++ b/kernel/rwsem.c
@@ -10,7 +10,6 @@
 #include <linux/export.h>
 #include <linux/rwsem.h>
 
-#include <asm/system.h>
 #include <linux/atomic.h>
 
 /*
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 503d642..4603b9d 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -73,6 +73,7 @@
 #include <linux/init_task.h>
 #include <linux/binfmts.h>
 
+#include <asm/switch_to.h>
 #include <asm/tlb.h>
 #include <asm/irq_regs.h>
 #include <asm/mutex.h>
@@ -1264,29 +1265,59 @@
  */
 static int select_fallback_rq(int cpu, struct task_struct *p)
 {
-	int dest_cpu;
 	const struct cpumask *nodemask = cpumask_of_node(cpu_to_node(cpu));
+	enum { cpuset, possible, fail } state = cpuset;
+	int dest_cpu;
 
 	/* Look for allowed, online CPU in same node. */
-	for_each_cpu_and(dest_cpu, nodemask, cpu_active_mask)
+	for_each_cpu(dest_cpu, nodemask) {
+		if (!cpu_online(dest_cpu))
+			continue;
+		if (!cpu_active(dest_cpu))
+			continue;
 		if (cpumask_test_cpu(dest_cpu, tsk_cpus_allowed(p)))
 			return dest_cpu;
+	}
 
-	/* Any allowed, online CPU? */
-	dest_cpu = cpumask_any_and(tsk_cpus_allowed(p), cpu_active_mask);
-	if (dest_cpu < nr_cpu_ids)
-		return dest_cpu;
+	for (;;) {
+		/* Any allowed, online CPU? */
+		for_each_cpu(dest_cpu, tsk_cpus_allowed(p)) {
+			if (!cpu_online(dest_cpu))
+				continue;
+			if (!cpu_active(dest_cpu))
+				continue;
+			goto out;
+		}
 
-	/* No more Mr. Nice Guy. */
-	dest_cpu = cpuset_cpus_allowed_fallback(p);
-	/*
-	 * Don't tell them about moving exiting tasks or
-	 * kernel threads (both mm NULL), since they never
-	 * leave kernel.
-	 */
-	if (p->mm && printk_ratelimit()) {
-		printk_sched("process %d (%s) no longer affine to cpu%d\n",
-				task_pid_nr(p), p->comm, cpu);
+		switch (state) {
+		case cpuset:
+			/* No more Mr. Nice Guy. */
+			cpuset_cpus_allowed_fallback(p);
+			state = possible;
+			break;
+
+		case possible:
+			do_set_cpus_allowed(p, cpu_possible_mask);
+			state = fail;
+			break;
+
+		case fail:
+			BUG();
+			break;
+		}
+	}
+
+out:
+	if (state != cpuset) {
+		/*
+		 * Don't tell them about moving exiting tasks or
+		 * kernel threads (both mm NULL), since they never
+		 * leave kernel.
+		 */
+		if (p->mm && printk_ratelimit()) {
+			printk_sched("process %d (%s) no longer affine to cpu%d\n",
+					task_pid_nr(p), p->comm, cpu);
+		}
 	}
 
 	return dest_cpu;
@@ -1933,6 +1964,7 @@
 	local_irq_enable();
 #endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */
 	finish_lock_switch(rq, prev);
+	finish_arch_post_lock_switch();
 
 	fire_sched_in_preempt_notifiers(current);
 	if (mm)
@@ -3070,8 +3102,6 @@
  */
 static noinline void __schedule_bug(struct task_struct *prev)
 {
-	struct pt_regs *regs = get_irq_regs();
-
 	if (oops_in_progress)
 		return;
 
@@ -3082,11 +3112,7 @@
 	print_modules();
 	if (irqs_disabled())
 		print_irqtrace_events(prev);
-
-	if (regs)
-		show_regs(regs);
-	else
-		dump_stack();
+	dump_stack();
 }
 
 /*
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 94340c7..0d97ebd 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -416,8 +416,8 @@
 
 #endif	/* CONFIG_FAIR_GROUP_SCHED */
 
-static void account_cfs_rq_runtime(struct cfs_rq *cfs_rq,
-				   unsigned long delta_exec);
+static __always_inline
+void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, unsigned long delta_exec);
 
 /**************************************************************
  * Scheduling class tree data structure manipulation methods:
@@ -1162,7 +1162,7 @@
 		__clear_buddies_skip(se);
 }
 
-static void return_cfs_rq_runtime(struct cfs_rq *cfs_rq);
+static __always_inline void return_cfs_rq_runtime(struct cfs_rq *cfs_rq);
 
 static void
 dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
@@ -1546,8 +1546,8 @@
 		resched_task(rq_of(cfs_rq)->curr);
 }
 
-static __always_inline void account_cfs_rq_runtime(struct cfs_rq *cfs_rq,
-						   unsigned long delta_exec)
+static __always_inline
+void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, unsigned long delta_exec)
 {
 	if (!cfs_bandwidth_used() || !cfs_rq->runtime_enabled)
 		return;
@@ -2073,11 +2073,11 @@
 }
 
 #else /* CONFIG_CFS_BANDWIDTH */
-static void account_cfs_rq_runtime(struct cfs_rq *cfs_rq,
-				     unsigned long delta_exec) {}
+static __always_inline
+void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, unsigned long delta_exec) {}
 static void check_cfs_rq_runtime(struct cfs_rq *cfs_rq) {}
 static void check_enqueue_throttle(struct cfs_rq *cfs_rq) {}
-static void return_cfs_rq_runtime(struct cfs_rq *cfs_rq) {}
+static __always_inline void return_cfs_rq_runtime(struct cfs_rq *cfs_rq) {}
 
 static inline int cfs_rq_throttled(struct cfs_rq *cfs_rq)
 {
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index b60dad7..44af55e 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1428,7 +1428,7 @@
 next_idx:
 		if (idx >= MAX_RT_PRIO)
 			continue;
-		if (next && next->prio < idx)
+		if (next && next->prio <= idx)
 			continue;
 		list_for_each_entry(rt_se, array->queue + idx, run_list) {
 			struct task_struct *p;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 42b1f30..fb3acba 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -681,6 +681,9 @@
 #ifndef finish_arch_switch
 # define finish_arch_switch(prev)	do { } while (0)
 #endif
+#ifndef finish_arch_post_lock_switch
+# define finish_arch_post_lock_switch()	do { } while (0)
+#endif
 
 #ifndef __ARCH_WANT_UNLOCKED_CTXSW
 static inline void prepare_lock_switch(struct rq *rq, struct task_struct *next)
diff --git a/kernel/signal.c b/kernel/signal.c
index e76001c..17afcaf 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -36,6 +36,7 @@
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 #include <asm/siginfo.h>
+#include <asm/cacheflush.h>
 #include "audit.h"	/* audit_signal_info() */
 
 /*
@@ -58,21 +59,20 @@
 		(handler == SIG_DFL && sig_kernel_ignore(sig));
 }
 
-static int sig_task_ignored(struct task_struct *t, int sig,
-		int from_ancestor_ns)
+static int sig_task_ignored(struct task_struct *t, int sig, bool force)
 {
 	void __user *handler;
 
 	handler = sig_handler(t, sig);
 
 	if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) &&
-			handler == SIG_DFL && !from_ancestor_ns)
+			handler == SIG_DFL && !force)
 		return 1;
 
 	return sig_handler_ignored(handler, sig);
 }
 
-static int sig_ignored(struct task_struct *t, int sig, int from_ancestor_ns)
+static int sig_ignored(struct task_struct *t, int sig, bool force)
 {
 	/*
 	 * Blocked signals are never ignored, since the
@@ -82,7 +82,7 @@
 	if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig))
 		return 0;
 
-	if (!sig_task_ignored(t, sig, from_ancestor_ns))
+	if (!sig_task_ignored(t, sig, force))
 		return 0;
 
 	/*
@@ -855,7 +855,7 @@
  * Returns true if the signal should be actually delivered, otherwise
  * it should be dropped.
  */
-static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns)
+static int prepare_signal(int sig, struct task_struct *p, bool force)
 {
 	struct signal_struct *signal = p->signal;
 	struct task_struct *t;
@@ -915,7 +915,7 @@
 		}
 	}
 
-	return !sig_ignored(p, sig, from_ancestor_ns);
+	return !sig_ignored(p, sig, force);
 }
 
 /*
@@ -1059,7 +1059,8 @@
 	assert_spin_locked(&t->sighand->siglock);
 
 	result = TRACE_SIGNAL_IGNORED;
-	if (!prepare_signal(sig, t, from_ancestor_ns))
+	if (!prepare_signal(sig, t,
+			from_ancestor_ns || (info == SEND_SIG_FORCED)))
 		goto ret;
 
 	pending = group ? &t->signal->shared_pending : &t->pending;
@@ -1601,7 +1602,7 @@
 
 	ret = 1; /* the signal is ignored */
 	result = TRACE_SIGNAL_IGNORED;
-	if (!prepare_signal(sig, t, 0))
+	if (!prepare_signal(sig, t, false))
 		goto out;
 
 	ret = 0;
diff --git a/kernel/smp.c b/kernel/smp.c
index db197d6..2f8b10e 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -701,3 +701,93 @@
 	return ret;
 }
 EXPORT_SYMBOL(on_each_cpu);
+
+/**
+ * on_each_cpu_mask(): Run a function on processors specified by
+ * cpumask, which may include the local processor.
+ * @mask: The set of cpus to run on (only runs on online subset).
+ * @func: The function to run. This must be fast and non-blocking.
+ * @info: An arbitrary pointer to pass to the function.
+ * @wait: If true, wait (atomically) until function has completed
+ *        on other CPUs.
+ *
+ * If @wait is true, then returns once @func has returned.
+ *
+ * You must not call this function with disabled interrupts or
+ * from a hardware interrupt handler or from a bottom half handler.
+ */
+void on_each_cpu_mask(const struct cpumask *mask, smp_call_func_t func,
+			void *info, bool wait)
+{
+	int cpu = get_cpu();
+
+	smp_call_function_many(mask, func, info, wait);
+	if (cpumask_test_cpu(cpu, mask)) {
+		local_irq_disable();
+		func(info);
+		local_irq_enable();
+	}
+	put_cpu();
+}
+EXPORT_SYMBOL(on_each_cpu_mask);
+
+/*
+ * on_each_cpu_cond(): Call a function on each processor for which
+ * the supplied function cond_func returns true, optionally waiting
+ * for all the required CPUs to finish. This may include the local
+ * processor.
+ * @cond_func:	A callback function that is passed a cpu id and
+ *		the the info parameter. The function is called
+ *		with preemption disabled. The function should
+ *		return a blooean value indicating whether to IPI
+ *		the specified CPU.
+ * @func:	The function to run on all applicable CPUs.
+ *		This must be fast and non-blocking.
+ * @info:	An arbitrary pointer to pass to both functions.
+ * @wait:	If true, wait (atomically) until function has
+ *		completed on other CPUs.
+ * @gfp_flags:	GFP flags to use when allocating the cpumask
+ *		used internally by the function.
+ *
+ * The function might sleep if the GFP flags indicates a non
+ * atomic allocation is allowed.
+ *
+ * Preemption is disabled to protect against CPUs going offline but not online.
+ * CPUs going online during the call will not be seen or sent an IPI.
+ *
+ * You must not call this function with disabled interrupts or
+ * from a hardware interrupt handler or from a bottom half handler.
+ */
+void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info),
+			smp_call_func_t func, void *info, bool wait,
+			gfp_t gfp_flags)
+{
+	cpumask_var_t cpus;
+	int cpu, ret;
+
+	might_sleep_if(gfp_flags & __GFP_WAIT);
+
+	if (likely(zalloc_cpumask_var(&cpus, (gfp_flags|__GFP_NOWARN)))) {
+		preempt_disable();
+		for_each_online_cpu(cpu)
+			if (cond_func(cpu, info))
+				cpumask_set_cpu(cpu, cpus);
+		on_each_cpu_mask(cpus, func, info, wait);
+		preempt_enable();
+		free_cpumask_var(cpus);
+	} else {
+		/*
+		 * No free cpumask, bother. No matter, we'll
+		 * just have to IPI them one by one.
+		 */
+		preempt_disable();
+		for_each_online_cpu(cpu)
+			if (cond_func(cpu, info)) {
+				ret = smp_call_function_single(cpu, func,
+								info, wait);
+				WARN_ON_ONCE(!ret);
+			}
+		preempt_enable();
+	}
+}
+EXPORT_SYMBOL(on_each_cpu_cond);
diff --git a/kernel/spinlock.c b/kernel/spinlock.c
index 84c7d96..5cdd806 100644
--- a/kernel/spinlock.c
+++ b/kernel/spinlock.c
@@ -163,7 +163,7 @@
 EXPORT_SYMBOL(_raw_spin_lock_bh);
 #endif
 
-#ifndef CONFIG_INLINE_SPIN_UNLOCK
+#ifdef CONFIG_UNINLINE_SPIN_UNLOCK
 void __lockfunc _raw_spin_unlock(raw_spinlock_t *lock)
 {
 	__raw_spin_unlock(lock);
diff --git a/kernel/sys.c b/kernel/sys.c
index 888d227..e7006eb 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -444,6 +444,15 @@
 	                magic2 != LINUX_REBOOT_MAGIC2C))
 		return -EINVAL;
 
+	/*
+	 * If pid namespaces are enabled and the current task is in a child
+	 * pid_namespace, the command is handled by reboot_pid_ns() which will
+	 * call do_exit().
+	 */
+	ret = reboot_pid_ns(task_active_pid_ns(current), cmd);
+	if (ret)
+		return ret;
+
 	/* Instead of trying to make the power_off code look like
 	 * halt when pm_power_off is not set do it the easy way.
 	 */
@@ -1962,6 +1971,14 @@
 		case PR_SET_MM:
 			error = prctl_set_mm(arg2, arg3, arg4, arg5);
 			break;
+		case PR_SET_CHILD_SUBREAPER:
+			me->signal->is_child_subreaper = !!arg2;
+			error = 0;
+			break;
+		case PR_GET_CHILD_SUBREAPER:
+			error = put_user(me->signal->is_child_subreaper,
+					 (int __user *) arg2);
+			break;
 		default:
 			error = -EINVAL;
 			break;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 11d5304..52b3a06 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -23,6 +23,7 @@
 #include <linux/swap.h>
 #include <linux/slab.h>
 #include <linux/sysctl.h>
+#include <linux/bitmap.h>
 #include <linux/signal.h>
 #include <linux/printk.h>
 #include <linux/proc_fs.h>
@@ -68,6 +69,9 @@
 #include <asm/stacktrace.h>
 #include <asm/io.h>
 #endif
+#ifdef CONFIG_SPARC
+#include <asm/setup.h>
+#endif
 #ifdef CONFIG_BSD_PROCESS_ACCT
 #include <linux/acct.h>
 #endif
@@ -142,7 +146,6 @@
 #include <linux/inotify.h>
 #endif
 #ifdef CONFIG_SPARC
-#include <asm/system.h>
 #endif
 
 #ifdef CONFIG_SPARC64
@@ -193,20 +196,6 @@
 
 #endif
 
-static struct ctl_table root_table[];
-static struct ctl_table_root sysctl_table_root;
-static struct ctl_table_header root_table_header = {
-	{{.count = 1,
-	.ctl_table = root_table,
-	.ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),}},
-	.root = &sysctl_table_root,
-	.set = &sysctl_table_root.default_set,
-};
-static struct ctl_table_root sysctl_table_root = {
-	.root_list = LIST_HEAD_INIT(sysctl_table_root.root_list),
-	.default_set.list = LIST_HEAD_INIT(root_table_header.ctl_entry),
-};
-
 static struct ctl_table kern_table[];
 static struct ctl_table vm_table[];
 static struct ctl_table fs_table[];
@@ -223,7 +212,7 @@
 
 /* The default sysctl tables: */
 
-static struct ctl_table root_table[] = {
+static struct ctl_table sysctl_base_table[] = {
 	{
 		.procname	= "kernel",
 		.mode		= 0555,
@@ -1560,490 +1549,12 @@
 	{ }
 };
 
-static DEFINE_SPINLOCK(sysctl_lock);
-
-/* called under sysctl_lock */
-static int use_table(struct ctl_table_header *p)
+int __init sysctl_init(void)
 {
-	if (unlikely(p->unregistering))
-		return 0;
-	p->used++;
-	return 1;
-}
-
-/* called under sysctl_lock */
-static void unuse_table(struct ctl_table_header *p)
-{
-	if (!--p->used)
-		if (unlikely(p->unregistering))
-			complete(p->unregistering);
-}
-
-/* called under sysctl_lock, will reacquire if has to wait */
-static void start_unregistering(struct ctl_table_header *p)
-{
-	/*
-	 * if p->used is 0, nobody will ever touch that entry again;
-	 * we'll eliminate all paths to it before dropping sysctl_lock
-	 */
-	if (unlikely(p->used)) {
-		struct completion wait;
-		init_completion(&wait);
-		p->unregistering = &wait;
-		spin_unlock(&sysctl_lock);
-		wait_for_completion(&wait);
-		spin_lock(&sysctl_lock);
-	} else {
-		/* anything non-NULL; we'll never dereference it */
-		p->unregistering = ERR_PTR(-EINVAL);
-	}
-	/*
-	 * do not remove from the list until nobody holds it; walking the
-	 * list in do_sysctl() relies on that.
-	 */
-	list_del_init(&p->ctl_entry);
-}
-
-void sysctl_head_get(struct ctl_table_header *head)
-{
-	spin_lock(&sysctl_lock);
-	head->count++;
-	spin_unlock(&sysctl_lock);
-}
-
-void sysctl_head_put(struct ctl_table_header *head)
-{
-	spin_lock(&sysctl_lock);
-	if (!--head->count)
-		kfree_rcu(head, rcu);
-	spin_unlock(&sysctl_lock);
-}
-
-struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head)
-{
-	if (!head)
-		BUG();
-	spin_lock(&sysctl_lock);
-	if (!use_table(head))
-		head = ERR_PTR(-ENOENT);
-	spin_unlock(&sysctl_lock);
-	return head;
-}
-
-void sysctl_head_finish(struct ctl_table_header *head)
-{
-	if (!head)
-		return;
-	spin_lock(&sysctl_lock);
-	unuse_table(head);
-	spin_unlock(&sysctl_lock);
-}
-
-static struct ctl_table_set *
-lookup_header_set(struct ctl_table_root *root, struct nsproxy *namespaces)
-{
-	struct ctl_table_set *set = &root->default_set;
-	if (root->lookup)
-		set = root->lookup(root, namespaces);
-	return set;
-}
-
-static struct list_head *
-lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces)
-{
-	struct ctl_table_set *set = lookup_header_set(root, namespaces);
-	return &set->list;
-}
-
-struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
-					    struct ctl_table_header *prev)
-{
-	struct ctl_table_root *root;
-	struct list_head *header_list;
-	struct ctl_table_header *head;
-	struct list_head *tmp;
-
-	spin_lock(&sysctl_lock);
-	if (prev) {
-		head = prev;
-		tmp = &prev->ctl_entry;
-		unuse_table(prev);
-		goto next;
-	}
-	tmp = &root_table_header.ctl_entry;
-	for (;;) {
-		head = list_entry(tmp, struct ctl_table_header, ctl_entry);
-
-		if (!use_table(head))
-			goto next;
-		spin_unlock(&sysctl_lock);
-		return head;
-	next:
-		root = head->root;
-		tmp = tmp->next;
-		header_list = lookup_header_list(root, namespaces);
-		if (tmp != header_list)
-			continue;
-
-		do {
-			root = list_entry(root->root_list.next,
-					struct ctl_table_root, root_list);
-			if (root == &sysctl_table_root)
-				goto out;
-			header_list = lookup_header_list(root, namespaces);
-		} while (list_empty(header_list));
-		tmp = header_list->next;
-	}
-out:
-	spin_unlock(&sysctl_lock);
-	return NULL;
-}
-
-struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev)
-{
-	return __sysctl_head_next(current->nsproxy, prev);
-}
-
-void register_sysctl_root(struct ctl_table_root *root)
-{
-	spin_lock(&sysctl_lock);
-	list_add_tail(&root->root_list, &sysctl_table_root.root_list);
-	spin_unlock(&sysctl_lock);
-}
-
-/*
- * sysctl_perm does NOT grant the superuser all rights automatically, because
- * some sysctl variables are readonly even to root.
- */
-
-static int test_perm(int mode, int op)
-{
-	if (!current_euid())
-		mode >>= 6;
-	else if (in_egroup_p(0))
-		mode >>= 3;
-	if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0)
-		return 0;
-	return -EACCES;
-}
-
-int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
-{
-	int mode;
-
-	if (root->permissions)
-		mode = root->permissions(root, current->nsproxy, table);
-	else
-		mode = table->mode;
-
-	return test_perm(mode, op);
-}
-
-static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table)
-{
-	for (; table->procname; table++) {
-		table->parent = parent;
-		if (table->child)
-			sysctl_set_parent(table, table->child);
-	}
-}
-
-static __init int sysctl_init(void)
-{
-	sysctl_set_parent(NULL, root_table);
-#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
-	sysctl_check_table(current->nsproxy, root_table);
-#endif
+	register_sysctl_table(sysctl_base_table);
 	return 0;
 }
 
-core_initcall(sysctl_init);
-
-static struct ctl_table *is_branch_in(struct ctl_table *branch,
-				      struct ctl_table *table)
-{
-	struct ctl_table *p;
-	const char *s = branch->procname;
-
-	/* branch should have named subdirectory as its first element */
-	if (!s || !branch->child)
-		return NULL;
-
-	/* ... and nothing else */
-	if (branch[1].procname)
-		return NULL;
-
-	/* table should contain subdirectory with the same name */
-	for (p = table; p->procname; p++) {
-		if (!p->child)
-			continue;
-		if (p->procname && strcmp(p->procname, s) == 0)
-			return p;
-	}
-	return NULL;
-}
-
-/* see if attaching q to p would be an improvement */
-static void try_attach(struct ctl_table_header *p, struct ctl_table_header *q)
-{
-	struct ctl_table *to = p->ctl_table, *by = q->ctl_table;
-	struct ctl_table *next;
-	int is_better = 0;
-	int not_in_parent = !p->attached_by;
-
-	while ((next = is_branch_in(by, to)) != NULL) {
-		if (by == q->attached_by)
-			is_better = 1;
-		if (to == p->attached_by)
-			not_in_parent = 1;
-		by = by->child;
-		to = next->child;
-	}
-
-	if (is_better && not_in_parent) {
-		q->attached_by = by;
-		q->attached_to = to;
-		q->parent = p;
-	}
-}
-
-/**
- * __register_sysctl_paths - register a sysctl hierarchy
- * @root: List of sysctl headers to register on
- * @namespaces: Data to compute which lists of sysctl entries are visible
- * @path: The path to the directory the sysctl table is in.
- * @table: the top-level table structure
- *
- * Register a sysctl table hierarchy. @table should be a filled in ctl_table
- * array. A completely 0 filled entry terminates the table.
- *
- * The members of the &struct ctl_table structure are used as follows:
- *
- * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
- *            enter a sysctl file
- *
- * data - a pointer to data for use by proc_handler
- *
- * maxlen - the maximum size in bytes of the data
- *
- * mode - the file permissions for the /proc/sys file, and for sysctl(2)
- *
- * child - a pointer to the child sysctl table if this entry is a directory, or
- *         %NULL.
- *
- * proc_handler - the text handler routine (described below)
- *
- * de - for internal use by the sysctl routines
- *
- * extra1, extra2 - extra pointers usable by the proc handler routines
- *
- * Leaf nodes in the sysctl tree will be represented by a single file
- * under /proc; non-leaf nodes will be represented by directories.
- *
- * sysctl(2) can automatically manage read and write requests through
- * the sysctl table.  The data and maxlen fields of the ctl_table
- * struct enable minimal validation of the values being written to be
- * performed, and the mode field allows minimal authentication.
- *
- * There must be a proc_handler routine for any terminal nodes
- * mirrored under /proc/sys (non-terminals are handled by a built-in
- * directory handler).  Several default handlers are available to
- * cover common cases -
- *
- * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
- * proc_dointvec_userhz_jiffies(), proc_dointvec_minmax(), 
- * proc_doulongvec_ms_jiffies_minmax(), proc_doulongvec_minmax()
- *
- * It is the handler's job to read the input buffer from user memory
- * and process it. The handler should return 0 on success.
- *
- * This routine returns %NULL on a failure to register, and a pointer
- * to the table header on success.
- */
-struct ctl_table_header *__register_sysctl_paths(
-	struct ctl_table_root *root,
-	struct nsproxy *namespaces,
-	const struct ctl_path *path, struct ctl_table *table)
-{
-	struct ctl_table_header *header;
-	struct ctl_table *new, **prevp;
-	unsigned int n, npath;
-	struct ctl_table_set *set;
-
-	/* Count the path components */
-	for (npath = 0; path[npath].procname; ++npath)
-		;
-
-	/*
-	 * For each path component, allocate a 2-element ctl_table array.
-	 * The first array element will be filled with the sysctl entry
-	 * for this, the second will be the sentinel (procname == 0).
-	 *
-	 * We allocate everything in one go so that we don't have to
-	 * worry about freeing additional memory in unregister_sysctl_table.
-	 */
-	header = kzalloc(sizeof(struct ctl_table_header) +
-			 (2 * npath * sizeof(struct ctl_table)), GFP_KERNEL);
-	if (!header)
-		return NULL;
-
-	new = (struct ctl_table *) (header + 1);
-
-	/* Now connect the dots */
-	prevp = &header->ctl_table;
-	for (n = 0; n < npath; ++n, ++path) {
-		/* Copy the procname */
-		new->procname = path->procname;
-		new->mode     = 0555;
-
-		*prevp = new;
-		prevp = &new->child;
-
-		new += 2;
-	}
-	*prevp = table;
-	header->ctl_table_arg = table;
-
-	INIT_LIST_HEAD(&header->ctl_entry);
-	header->used = 0;
-	header->unregistering = NULL;
-	header->root = root;
-	sysctl_set_parent(NULL, header->ctl_table);
-	header->count = 1;
-#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
-	if (sysctl_check_table(namespaces, header->ctl_table)) {
-		kfree(header);
-		return NULL;
-	}
-#endif
-	spin_lock(&sysctl_lock);
-	header->set = lookup_header_set(root, namespaces);
-	header->attached_by = header->ctl_table;
-	header->attached_to = root_table;
-	header->parent = &root_table_header;
-	for (set = header->set; set; set = set->parent) {
-		struct ctl_table_header *p;
-		list_for_each_entry(p, &set->list, ctl_entry) {
-			if (p->unregistering)
-				continue;
-			try_attach(p, header);
-		}
-	}
-	header->parent->count++;
-	list_add_tail(&header->ctl_entry, &header->set->list);
-	spin_unlock(&sysctl_lock);
-
-	return header;
-}
-
-/**
- * register_sysctl_table_path - register a sysctl table hierarchy
- * @path: The path to the directory the sysctl table is in.
- * @table: the top-level table structure
- *
- * Register a sysctl table hierarchy. @table should be a filled in ctl_table
- * array. A completely 0 filled entry terminates the table.
- *
- * See __register_sysctl_paths for more details.
- */
-struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
-						struct ctl_table *table)
-{
-	return __register_sysctl_paths(&sysctl_table_root, current->nsproxy,
-					path, table);
-}
-
-/**
- * register_sysctl_table - register a sysctl table hierarchy
- * @table: the top-level table structure
- *
- * Register a sysctl table hierarchy. @table should be a filled in ctl_table
- * array. A completely 0 filled entry terminates the table.
- *
- * See register_sysctl_paths for more details.
- */
-struct ctl_table_header *register_sysctl_table(struct ctl_table *table)
-{
-	static const struct ctl_path null_path[] = { {} };
-
-	return register_sysctl_paths(null_path, table);
-}
-
-/**
- * unregister_sysctl_table - unregister a sysctl table hierarchy
- * @header: the header returned from register_sysctl_table
- *
- * Unregisters the sysctl table and all children. proc entries may not
- * actually be removed until they are no longer used by anyone.
- */
-void unregister_sysctl_table(struct ctl_table_header * header)
-{
-	might_sleep();
-
-	if (header == NULL)
-		return;
-
-	spin_lock(&sysctl_lock);
-	start_unregistering(header);
-	if (!--header->parent->count) {
-		WARN_ON(1);
-		kfree_rcu(header->parent, rcu);
-	}
-	if (!--header->count)
-		kfree_rcu(header, rcu);
-	spin_unlock(&sysctl_lock);
-}
-
-int sysctl_is_seen(struct ctl_table_header *p)
-{
-	struct ctl_table_set *set = p->set;
-	int res;
-	spin_lock(&sysctl_lock);
-	if (p->unregistering)
-		res = 0;
-	else if (!set->is_seen)
-		res = 1;
-	else
-		res = set->is_seen(set);
-	spin_unlock(&sysctl_lock);
-	return res;
-}
-
-void setup_sysctl_set(struct ctl_table_set *p,
-	struct ctl_table_set *parent,
-	int (*is_seen)(struct ctl_table_set *))
-{
-	INIT_LIST_HEAD(&p->list);
-	p->parent = parent ? parent : &sysctl_table_root.default_set;
-	p->is_seen = is_seen;
-}
-
-#else /* !CONFIG_SYSCTL */
-struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
-{
-	return NULL;
-}
-
-struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
-						    struct ctl_table *table)
-{
-	return NULL;
-}
-
-void unregister_sysctl_table(struct ctl_table_header * table)
-{
-}
-
-void setup_sysctl_set(struct ctl_table_set *p,
-	struct ctl_table_set *parent,
-	int (*is_seen)(struct ctl_table_set *))
-{
-}
-
-void sysctl_head_put(struct ctl_table_header *head)
-{
-}
-
 #endif /* CONFIG_SYSCTL */
 
 /*
@@ -2885,9 +2396,7 @@
 				}
 			}
 
-			while (val_a <= val_b)
-				set_bit(val_a++, tmp_bitmap);
-
+			bitmap_set(tmp_bitmap, val_a, val_b - val_a + 1);
 			first = 0;
 			proc_skip_char(&kbuf, &left, '\n');
 		}
@@ -2930,8 +2439,7 @@
 			if (*ppos)
 				bitmap_or(bitmap, bitmap, tmp_bitmap, bitmap_len);
 			else
-				memcpy(bitmap, tmp_bitmap,
-					BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long));
+				bitmap_copy(bitmap, tmp_bitmap, bitmap_len);
 		}
 		kfree(tmp_bitmap);
 		*lenp -= left;
@@ -3009,6 +2517,3 @@
 EXPORT_SYMBOL(proc_dostring);
 EXPORT_SYMBOL(proc_doulongvec_minmax);
 EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax);
-EXPORT_SYMBOL(register_sysctl_table);
-EXPORT_SYMBOL(register_sysctl_paths);
-EXPORT_SYMBOL(unregister_sysctl_table);
diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c
deleted file mode 100644
index 362da65..0000000
--- a/kernel/sysctl_check.c
+++ /dev/null
@@ -1,160 +0,0 @@
-#include <linux/stat.h>
-#include <linux/sysctl.h>
-#include "../fs/xfs/xfs_sysctl.h"
-#include <linux/sunrpc/debug.h>
-#include <linux/string.h>
-#include <net/ip_vs.h>
-
-
-static int sysctl_depth(struct ctl_table *table)
-{
-	struct ctl_table *tmp;
-	int depth;
-
-	depth = 0;
-	for (tmp = table; tmp->parent; tmp = tmp->parent)
-		depth++;
-
-	return depth;
-}
-
-static struct ctl_table *sysctl_parent(struct ctl_table *table, int n)
-{
-	int i;
-
-	for (i = 0; table && i < n; i++)
-		table = table->parent;
-
-	return table;
-}
-
-
-static void sysctl_print_path(struct ctl_table *table)
-{
-	struct ctl_table *tmp;
-	int depth, i;
-	depth = sysctl_depth(table);
-	if (table->procname) {
-		for (i = depth; i >= 0; i--) {
-			tmp = sysctl_parent(table, i);
-			printk("/%s", tmp->procname?tmp->procname:"");
-		}
-	}
-	printk(" ");
-}
-
-static struct ctl_table *sysctl_check_lookup(struct nsproxy *namespaces,
-						struct ctl_table *table)
-{
-	struct ctl_table_header *head;
-	struct ctl_table *ref, *test;
-	int depth, cur_depth;
-
-	depth = sysctl_depth(table);
-
-	for (head = __sysctl_head_next(namespaces, NULL); head;
-	     head = __sysctl_head_next(namespaces, head)) {
-		cur_depth = depth;
-		ref = head->ctl_table;
-repeat:
-		test = sysctl_parent(table, cur_depth);
-		for (; ref->procname; ref++) {
-			int match = 0;
-			if (cur_depth && !ref->child)
-				continue;
-
-			if (test->procname && ref->procname &&
-			    (strcmp(test->procname, ref->procname) == 0))
-					match++;
-
-			if (match) {
-				if (cur_depth != 0) {
-					cur_depth--;
-					ref = ref->child;
-					goto repeat;
-				}
-				goto out;
-			}
-		}
-	}
-	ref = NULL;
-out:
-	sysctl_head_finish(head);
-	return ref;
-}
-
-static void set_fail(const char **fail, struct ctl_table *table, const char *str)
-{
-	if (*fail) {
-		printk(KERN_ERR "sysctl table check failed: ");
-		sysctl_print_path(table);
-		printk(" %s\n", *fail);
-		dump_stack();
-	}
-	*fail = str;
-}
-
-static void sysctl_check_leaf(struct nsproxy *namespaces,
-				struct ctl_table *table, const char **fail)
-{
-	struct ctl_table *ref;
-
-	ref = sysctl_check_lookup(namespaces, table);
-	if (ref && (ref != table))
-		set_fail(fail, table, "Sysctl already exists");
-}
-
-int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table)
-{
-	int error = 0;
-	for (; table->procname; table++) {
-		const char *fail = NULL;
-
-		if (table->parent) {
-			if (!table->parent->procname)
-				set_fail(&fail, table, "Parent without procname");
-		}
-		if (table->child) {
-			if (table->data)
-				set_fail(&fail, table, "Directory with data?");
-			if (table->maxlen)
-				set_fail(&fail, table, "Directory with maxlen?");
-			if ((table->mode & (S_IRUGO|S_IXUGO)) != table->mode)
-				set_fail(&fail, table, "Writable sysctl directory");
-			if (table->proc_handler)
-				set_fail(&fail, table, "Directory with proc_handler");
-			if (table->extra1)
-				set_fail(&fail, table, "Directory with extra1");
-			if (table->extra2)
-				set_fail(&fail, table, "Directory with extra2");
-		} else {
-			if ((table->proc_handler == proc_dostring) ||
-			    (table->proc_handler == proc_dointvec) ||
-			    (table->proc_handler == proc_dointvec_minmax) ||
-			    (table->proc_handler == proc_dointvec_jiffies) ||
-			    (table->proc_handler == proc_dointvec_userhz_jiffies) ||
-			    (table->proc_handler == proc_dointvec_ms_jiffies) ||
-			    (table->proc_handler == proc_doulongvec_minmax) ||
-			    (table->proc_handler == proc_doulongvec_ms_jiffies_minmax)) {
-				if (!table->data)
-					set_fail(&fail, table, "No data");
-				if (!table->maxlen)
-					set_fail(&fail, table, "No maxlen");
-			}
-#ifdef CONFIG_PROC_SYSCTL
-			if (!table->proc_handler)
-				set_fail(&fail, table, "No proc_handler");
-#endif
-			sysctl_check_leaf(namespaces, table, &fail);
-		}
-		if (table->mode > 0777)
-			set_fail(&fail, table, "bogus .mode");
-		if (fail) {
-			set_fail(&fail, table, NULL);
-			error = -EINVAL;
-		}
-		if (table->child)
-			error |= sysctl_check_table(namespaces, table->child);
-	}
-	return error;
-}
diff --git a/kernel/time.c b/kernel/time.c
index 73e416d..ba744cf 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -163,7 +163,6 @@
 		return error;
 
 	if (tz) {
-		/* SMP safe, global irq locking makes it work. */
 		sys_tz = *tz;
 		update_vsyscall_tz();
 		if (firsttime) {
@@ -173,12 +172,7 @@
 		}
 	}
 	if (tv)
-	{
-		/* SMP safe, again the code in arch/foo/time.c should
-		 * globally block out interrupts when it runs.
-		 */
 		return do_settimeofday(tv);
-	}
 	return 0;
 }
 
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index 8a46f5d..8a538c5 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -96,6 +96,11 @@
 	return 0;
 }
 
+static inline void alarmtimer_rtc_timer_init(void)
+{
+	rtc_timer_init(&rtctimer, NULL, NULL);
+}
+
 static struct class_interface alarmtimer_rtc_interface = {
 	.add_dev = &alarmtimer_rtc_add_device,
 };
@@ -117,6 +122,7 @@
 #define rtcdev (NULL)
 static inline int alarmtimer_rtc_interface_setup(void) { return 0; }
 static inline void alarmtimer_rtc_interface_remove(void) { }
+static inline void alarmtimer_rtc_timer_init(void) { }
 #endif
 
 /**
@@ -783,6 +789,8 @@
 		.nsleep		= alarm_timer_nsleep,
 	};
 
+	alarmtimer_rtc_timer_init();
+
 	posix_timers_register_clock(CLOCK_REALTIME_ALARM, &alarm_clock);
 	posix_timers_register_clock(CLOCK_BOOTTIME_ALARM, &alarm_clock);
 
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index a45ca16..c958338 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -500,7 +500,7 @@
 {
 	u64 ret;
 	/*
-	 * We won't try to correct for more then 11% adjustments (110,000 ppm),
+	 * We won't try to correct for more than 11% adjustments (110,000 ppm),
 	 */
 	ret = (u64)cs->mult * 11;
 	do_div(ret,100);
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 6e039b1..f03fd83 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -34,8 +34,6 @@
 static u64			tick_length;
 static u64			tick_length_base;
 
-static struct hrtimer		leap_timer;
-
 #define MAX_TICKADJ		500LL		/* usecs */
 #define MAX_TICKADJ_SCALED \
 	(((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ)
@@ -381,71 +379,64 @@
 
 
 /*
- * Leap second processing. If in leap-insert state at the end of the
- * day, the system clock is set back one second; if in leap-delete
- * state, the system clock is set ahead one second.
- */
-static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer)
-{
-	enum hrtimer_restart res = HRTIMER_NORESTART;
-	unsigned long flags;
-	int leap = 0;
-
-	spin_lock_irqsave(&ntp_lock, flags);
-	switch (time_state) {
-	case TIME_OK:
-		break;
-	case TIME_INS:
-		leap = -1;
-		time_state = TIME_OOP;
-		printk(KERN_NOTICE
-			"Clock: inserting leap second 23:59:60 UTC\n");
-		hrtimer_add_expires_ns(&leap_timer, NSEC_PER_SEC);
-		res = HRTIMER_RESTART;
-		break;
-	case TIME_DEL:
-		leap = 1;
-		time_tai--;
-		time_state = TIME_WAIT;
-		printk(KERN_NOTICE
-			"Clock: deleting leap second 23:59:59 UTC\n");
-		break;
-	case TIME_OOP:
-		time_tai++;
-		time_state = TIME_WAIT;
-		/* fall through */
-	case TIME_WAIT:
-		if (!(time_status & (STA_INS | STA_DEL)))
-			time_state = TIME_OK;
-		break;
-	}
-	spin_unlock_irqrestore(&ntp_lock, flags);
-
-	/*
-	 * We have to call this outside of the ntp_lock to keep
-	 * the proper locking hierarchy
-	 */
-	if (leap)
-		timekeeping_leap_insert(leap);
-
-	return res;
-}
-
-/*
  * this routine handles the overflow of the microsecond field
  *
  * The tricky bits of code to handle the accurate clock support
  * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
  * They were originally developed for SUN and DEC kernels.
  * All the kudos should go to Dave for this stuff.
+ *
+ * Also handles leap second processing, and returns leap offset
  */
-void second_overflow(void)
+int second_overflow(unsigned long secs)
 {
 	s64 delta;
+	int leap = 0;
 	unsigned long flags;
 
 	spin_lock_irqsave(&ntp_lock, flags);
 
+	/*
+	 * Leap second processing. If in leap-insert state at the end of the
+	 * day, the system clock is set back one second; if in leap-delete
+	 * state, the system clock is set ahead one second.
+	 */
+	switch (time_state) {
+	case TIME_OK:
+		if (time_status & STA_INS)
+			time_state = TIME_INS;
+		else if (time_status & STA_DEL)
+			time_state = TIME_DEL;
+		break;
+	case TIME_INS:
+		if (secs % 86400 == 0) {
+			leap = -1;
+			time_state = TIME_OOP;
+			printk(KERN_NOTICE
+				"Clock: inserting leap second 23:59:60 UTC\n");
+		}
+		break;
+	case TIME_DEL:
+		if ((secs + 1) % 86400 == 0) {
+			leap = 1;
+			time_tai--;
+			time_state = TIME_WAIT;
+			printk(KERN_NOTICE
+				"Clock: deleting leap second 23:59:59 UTC\n");
+		}
+		break;
+	case TIME_OOP:
+		time_tai++;
+		time_state = TIME_WAIT;
+		break;
+
+	case TIME_WAIT:
+		if (!(time_status & (STA_INS | STA_DEL)))
+			time_state = TIME_OK;
+		break;
+	}
+
+
 	/* Bump the maxerror field */
 	time_maxerror += MAXFREQ / NSEC_PER_USEC;
 	if (time_maxerror > NTP_PHASE_LIMIT) {
@@ -481,15 +472,17 @@
 	tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ)
 							 << NTP_SCALE_SHIFT;
 	time_adjust = 0;
+
+
+
 out:
 	spin_unlock_irqrestore(&ntp_lock, flags);
+
+	return leap;
 }
 
 #ifdef CONFIG_GENERIC_CMOS_UPDATE
 
-/* Disable the cmos update - used by virtualization and embedded */
-int no_sync_cmos_clock  __read_mostly;
-
 static void sync_cmos_clock(struct work_struct *work);
 
 static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock);
@@ -536,35 +529,13 @@
 
 static void notify_cmos_timer(void)
 {
-	if (!no_sync_cmos_clock)
-		schedule_delayed_work(&sync_cmos_work, 0);
+	schedule_delayed_work(&sync_cmos_work, 0);
 }
 
 #else
 static inline void notify_cmos_timer(void) { }
 #endif
 
-/*
- * Start the leap seconds timer:
- */
-static inline void ntp_start_leap_timer(struct timespec *ts)
-{
-	long now = ts->tv_sec;
-
-	if (time_status & STA_INS) {
-		time_state = TIME_INS;
-		now += 86400 - now % 86400;
-		hrtimer_start(&leap_timer, ktime_set(now, 0), HRTIMER_MODE_ABS);
-
-		return;
-	}
-
-	if (time_status & STA_DEL) {
-		time_state = TIME_DEL;
-		now += 86400 - (now + 1) % 86400;
-		hrtimer_start(&leap_timer, ktime_set(now, 0), HRTIMER_MODE_ABS);
-	}
-}
 
 /*
  * Propagate a new txc->status value into the NTP state:
@@ -589,22 +560,6 @@
 	time_status &= STA_RONLY;
 	time_status |= txc->status & ~STA_RONLY;
 
-	switch (time_state) {
-	case TIME_OK:
-		ntp_start_leap_timer(ts);
-		break;
-	case TIME_INS:
-	case TIME_DEL:
-		time_state = TIME_OK;
-		ntp_start_leap_timer(ts);
-	case TIME_WAIT:
-		if (!(time_status & (STA_INS | STA_DEL)))
-			time_state = TIME_OK;
-		break;
-	case TIME_OOP:
-		hrtimer_restart(&leap_timer);
-		break;
-	}
 }
 /*
  * Called with the xtime lock held, so we can access and modify
@@ -686,9 +641,6 @@
 		    (txc->tick <  900000/USER_HZ ||
 		     txc->tick > 1100000/USER_HZ))
 			return -EINVAL;
-
-		if (txc->modes & ADJ_STATUS && time_state != TIME_OK)
-			hrtimer_cancel(&leap_timer);
 	}
 
 	if (txc->modes & ADJ_SETOFFSET) {
@@ -1010,6 +962,4 @@
 void __init ntp_init(void)
 {
 	ntp_clear();
-	hrtimer_init(&leap_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
-	leap_timer.function = ntp_leap_second;
 }
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 403c2a0..d66b213 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -184,18 +184,6 @@
 }
 
 
-void timekeeping_leap_insert(int leapsecond)
-{
-	unsigned long flags;
-
-	write_seqlock_irqsave(&timekeeper.lock, flags);
-	timekeeper.xtime.tv_sec += leapsecond;
-	timekeeper.wall_to_monotonic.tv_sec -= leapsecond;
-	timekeeping_update(false);
-	write_sequnlock_irqrestore(&timekeeper.lock, flags);
-
-}
-
 /**
  * timekeeping_forward_now - update clock to the current time
  *
@@ -448,9 +436,12 @@
 static int change_clocksource(void *data)
 {
 	struct clocksource *new, *old;
+	unsigned long flags;
 
 	new = (struct clocksource *) data;
 
+	write_seqlock_irqsave(&timekeeper.lock, flags);
+
 	timekeeping_forward_now();
 	if (!new->enable || new->enable(new) == 0) {
 		old = timekeeper.clock;
@@ -458,6 +449,10 @@
 		if (old->disable)
 			old->disable(old);
 	}
+	timekeeping_update(true);
+
+	write_sequnlock_irqrestore(&timekeeper.lock, flags);
+
 	return 0;
 }
 
@@ -827,7 +822,7 @@
 	int adj;
 
 	/*
-	 * The point of this is to check if the error is greater then half
+	 * The point of this is to check if the error is greater than half
 	 * an interval.
 	 *
 	 * First we shift it down from NTP_SHIFT to clocksource->shifted nsecs.
@@ -835,7 +830,7 @@
 	 * Note we subtract one in the shift, so that error is really error*2.
 	 * This "saves" dividing(shifting) interval twice, but keeps the
 	 * (error > interval) comparison as still measuring if error is
-	 * larger then half an interval.
+	 * larger than half an interval.
 	 *
 	 * Note: It does not "save" on aggravation when reading the code.
 	 */
@@ -843,7 +838,7 @@
 	if (error > interval) {
 		/*
 		 * We now divide error by 4(via shift), which checks if
-		 * the error is greater then twice the interval.
+		 * the error is greater than twice the interval.
 		 * If it is greater, we need a bigadjust, if its smaller,
 		 * we can adjust by 1.
 		 */
@@ -874,13 +869,15 @@
 	} else /* No adjustment needed */
 		return;
 
-	WARN_ONCE(timekeeper.clock->maxadj &&
-			(timekeeper.mult + adj > timekeeper.clock->mult +
-						timekeeper.clock->maxadj),
-			"Adjusting %s more then 11%% (%ld vs %ld)\n",
+	if (unlikely(timekeeper.clock->maxadj &&
+			(timekeeper.mult + adj >
+			timekeeper.clock->mult + timekeeper.clock->maxadj))) {
+		printk_once(KERN_WARNING
+			"Adjusting %s more than 11%% (%ld vs %ld)\n",
 			timekeeper.clock->name, (long)timekeeper.mult + adj,
 			(long)timekeeper.clock->mult +
 				timekeeper.clock->maxadj);
+	}
 	/*
 	 * So the following can be confusing.
 	 *
@@ -952,7 +949,7 @@
 	u64 nsecps = (u64)NSEC_PER_SEC << timekeeper.shift;
 	u64 raw_nsecs;
 
-	/* If the offset is smaller then a shifted interval, do nothing */
+	/* If the offset is smaller than a shifted interval, do nothing */
 	if (offset < timekeeper.cycle_interval<<shift)
 		return offset;
 
@@ -962,9 +959,11 @@
 
 	timekeeper.xtime_nsec += timekeeper.xtime_interval << shift;
 	while (timekeeper.xtime_nsec >= nsecps) {
+		int leap;
 		timekeeper.xtime_nsec -= nsecps;
 		timekeeper.xtime.tv_sec++;
-		second_overflow();
+		leap = second_overflow(timekeeper.xtime.tv_sec);
+		timekeeper.xtime.tv_sec += leap;
 	}
 
 	/* Accumulate raw time */
@@ -1018,13 +1017,13 @@
 	 * With NO_HZ we may have to accumulate many cycle_intervals
 	 * (think "ticks") worth of time at once. To do this efficiently,
 	 * we calculate the largest doubling multiple of cycle_intervals
-	 * that is smaller then the offset. We then accumulate that
+	 * that is smaller than the offset.  We then accumulate that
 	 * chunk in one go, and then try to consume the next smaller
 	 * doubled multiple.
 	 */
 	shift = ilog2(offset) - ilog2(timekeeper.cycle_interval);
 	shift = max(0, shift);
-	/* Bound shift to one less then what overflows tick_length */
+	/* Bound shift to one less than what overflows tick_length */
 	maxshift = (64 - (ilog2(ntp_tick_length())+1)) - 1;
 	shift = min(shift, maxshift);
 	while (offset >= timekeeper.cycle_interval) {
@@ -1072,12 +1071,14 @@
 
 	/*
 	 * Finally, make sure that after the rounding
-	 * xtime.tv_nsec isn't larger then NSEC_PER_SEC
+	 * xtime.tv_nsec isn't larger than NSEC_PER_SEC
 	 */
 	if (unlikely(timekeeper.xtime.tv_nsec >= NSEC_PER_SEC)) {
+		int leap;
 		timekeeper.xtime.tv_nsec -= NSEC_PER_SEC;
 		timekeeper.xtime.tv_sec++;
-		second_overflow();
+		leap = second_overflow(timekeeper.xtime.tv_sec);
+		timekeeper.xtime.tv_sec += leap;
 	}
 
 	timekeeping_update(false);
@@ -1260,6 +1261,8 @@
 
 	return timespec_to_ktime(wtom);
 }
+EXPORT_SYMBOL_GPL(ktime_get_monotonic_offset);
+
 
 /**
  * xtime_update() - advances the timekeeping infrastructure
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index cd31345..a1d2849 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -141,7 +141,7 @@
 config FUNCTION_TRACER
 	bool "Kernel Function Tracer"
 	depends on HAVE_FUNCTION_TRACER
-	select FRAME_POINTER if !ARM_UNWIND && !S390 && !MICROBLAZE
+	select FRAME_POINTER if !ARM_UNWIND && !PPC && !S390 && !MICROBLAZE
 	select KALLSYMS
 	select GENERIC_TRACER
 	select CONTEXT_SWITCH_TRACER
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index cdea7b5..c0bd030 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -311,13 +311,6 @@
 }
 EXPORT_SYMBOL_GPL(blk_trace_remove);
 
-static int blk_dropped_open(struct inode *inode, struct file *filp)
-{
-	filp->private_data = inode->i_private;
-
-	return 0;
-}
-
 static ssize_t blk_dropped_read(struct file *filp, char __user *buffer,
 				size_t count, loff_t *ppos)
 {
@@ -331,18 +324,11 @@
 
 static const struct file_operations blk_dropped_fops = {
 	.owner =	THIS_MODULE,
-	.open =		blk_dropped_open,
+	.open =		simple_open,
 	.read =		blk_dropped_read,
 	.llseek =	default_llseek,
 };
 
-static int blk_msg_open(struct inode *inode, struct file *filp)
-{
-	filp->private_data = inode->i_private;
-
-	return 0;
-}
-
 static ssize_t blk_msg_write(struct file *filp, const char __user *buffer,
 				size_t count, loff_t *ppos)
 {
@@ -371,7 +357,7 @@
 
 static const struct file_operations blk_msg_fops = {
 	.owner =	THIS_MODULE,
-	.open =		blk_msg_open,
+	.open =		simple_open,
 	.write =	blk_msg_write,
 	.llseek =	noop_llseek,
 };
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 867bd1d..0fa92f6 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -249,7 +249,8 @@
 #else
 	__ftrace_trace_function = func;
 #endif
-	ftrace_trace_function = ftrace_test_stop_func;
+	ftrace_trace_function =
+		(func == ftrace_stub) ? func : ftrace_test_stop_func;
 #endif
 }
 
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index f5b7b5c..cf8d11e 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -154,35 +154,12 @@
 
 static unsigned long ring_buffer_flags __read_mostly = RB_BUFFERS_ON;
 
+/* Used for individual buffers (after the counter) */
+#define RB_BUFFER_OFF		(1 << 20)
+
 #define BUF_PAGE_HDR_SIZE offsetof(struct buffer_data_page, data)
 
 /**
- * tracing_on - enable all tracing buffers
- *
- * This function enables all tracing buffers that may have been
- * disabled with tracing_off.
- */
-void tracing_on(void)
-{
-	set_bit(RB_BUFFERS_ON_BIT, &ring_buffer_flags);
-}
-EXPORT_SYMBOL_GPL(tracing_on);
-
-/**
- * tracing_off - turn off all tracing buffers
- *
- * This function stops all tracing buffers from recording data.
- * It does not disable any overhead the tracers themselves may
- * be causing. This function simply causes all recording to
- * the ring buffers to fail.
- */
-void tracing_off(void)
-{
-	clear_bit(RB_BUFFERS_ON_BIT, &ring_buffer_flags);
-}
-EXPORT_SYMBOL_GPL(tracing_off);
-
-/**
  * tracing_off_permanent - permanently disable ring buffers
  *
  * This function, once called, will disable all ring buffers
@@ -193,15 +170,6 @@
 	set_bit(RB_BUFFERS_DISABLED_BIT, &ring_buffer_flags);
 }
 
-/**
- * tracing_is_on - show state of ring buffers enabled
- */
-int tracing_is_on(void)
-{
-	return ring_buffer_flags == RB_BUFFERS_ON;
-}
-EXPORT_SYMBOL_GPL(tracing_is_on);
-
 #define RB_EVNT_HDR_SIZE (offsetof(struct ring_buffer_event, array))
 #define RB_ALIGNMENT		4U
 #define RB_MAX_SMALL_DATA	(RB_ALIGNMENT * RINGBUF_TYPE_DATA_TYPE_LEN_MAX)
@@ -2619,6 +2587,63 @@
 EXPORT_SYMBOL_GPL(ring_buffer_record_enable);
 
 /**
+ * ring_buffer_record_off - stop all writes into the buffer
+ * @buffer: The ring buffer to stop writes to.
+ *
+ * This prevents all writes to the buffer. Any attempt to write
+ * to the buffer after this will fail and return NULL.
+ *
+ * This is different than ring_buffer_record_disable() as
+ * it works like an on/off switch, where as the disable() verison
+ * must be paired with a enable().
+ */
+void ring_buffer_record_off(struct ring_buffer *buffer)
+{
+	unsigned int rd;
+	unsigned int new_rd;
+
+	do {
+		rd = atomic_read(&buffer->record_disabled);
+		new_rd = rd | RB_BUFFER_OFF;
+	} while (atomic_cmpxchg(&buffer->record_disabled, rd, new_rd) != rd);
+}
+EXPORT_SYMBOL_GPL(ring_buffer_record_off);
+
+/**
+ * ring_buffer_record_on - restart writes into the buffer
+ * @buffer: The ring buffer to start writes to.
+ *
+ * This enables all writes to the buffer that was disabled by
+ * ring_buffer_record_off().
+ *
+ * This is different than ring_buffer_record_enable() as
+ * it works like an on/off switch, where as the enable() verison
+ * must be paired with a disable().
+ */
+void ring_buffer_record_on(struct ring_buffer *buffer)
+{
+	unsigned int rd;
+	unsigned int new_rd;
+
+	do {
+		rd = atomic_read(&buffer->record_disabled);
+		new_rd = rd & ~RB_BUFFER_OFF;
+	} while (atomic_cmpxchg(&buffer->record_disabled, rd, new_rd) != rd);
+}
+EXPORT_SYMBOL_GPL(ring_buffer_record_on);
+
+/**
+ * ring_buffer_record_is_on - return true if the ring buffer can write
+ * @buffer: The ring buffer to see if write is enabled
+ *
+ * Returns true if the ring buffer is in a state that it accepts writes.
+ */
+int ring_buffer_record_is_on(struct ring_buffer *buffer)
+{
+	return !atomic_read(&buffer->record_disabled);
+}
+
+/**
  * ring_buffer_record_disable_cpu - stop all writes into the cpu_buffer
  * @buffer: The ring buffer to stop writes to.
  * @cpu: The CPU buffer to stop
@@ -4039,68 +4064,6 @@
 }
 EXPORT_SYMBOL_GPL(ring_buffer_read_page);
 
-#ifdef CONFIG_TRACING
-static ssize_t
-rb_simple_read(struct file *filp, char __user *ubuf,
-	       size_t cnt, loff_t *ppos)
-{
-	unsigned long *p = filp->private_data;
-	char buf[64];
-	int r;
-
-	if (test_bit(RB_BUFFERS_DISABLED_BIT, p))
-		r = sprintf(buf, "permanently disabled\n");
-	else
-		r = sprintf(buf, "%d\n", test_bit(RB_BUFFERS_ON_BIT, p));
-
-	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
-}
-
-static ssize_t
-rb_simple_write(struct file *filp, const char __user *ubuf,
-		size_t cnt, loff_t *ppos)
-{
-	unsigned long *p = filp->private_data;
-	unsigned long val;
-	int ret;
-
-	ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
-	if (ret)
-		return ret;
-
-	if (val)
-		set_bit(RB_BUFFERS_ON_BIT, p);
-	else
-		clear_bit(RB_BUFFERS_ON_BIT, p);
-
-	(*ppos)++;
-
-	return cnt;
-}
-
-static const struct file_operations rb_simple_fops = {
-	.open		= tracing_open_generic,
-	.read		= rb_simple_read,
-	.write		= rb_simple_write,
-	.llseek		= default_llseek,
-};
-
-
-static __init int rb_init_debugfs(void)
-{
-	struct dentry *d_tracer;
-
-	d_tracer = tracing_init_dentry();
-
-	trace_create_file("tracing_on", 0644, d_tracer,
-			    &ring_buffer_flags, &rb_simple_fops);
-
-	return 0;
-}
-
-fs_initcall(rb_init_debugfs);
-#endif
-
 #ifdef CONFIG_HOTPLUG_CPU
 static int rb_cpu_notify(struct notifier_block *self,
 			 unsigned long action, void *hcpu)
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 10d5503..ed7b5d1 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -36,6 +36,7 @@
 #include <linux/ctype.h>
 #include <linux/init.h>
 #include <linux/poll.h>
+#include <linux/nmi.h>
 #include <linux/fs.h>
 
 #include "trace.h"
@@ -352,6 +353,59 @@
 static DECLARE_DELAYED_WORK(wakeup_work, wakeup_work_handler);
 
 /**
+ * tracing_on - enable tracing buffers
+ *
+ * This function enables tracing buffers that may have been
+ * disabled with tracing_off.
+ */
+void tracing_on(void)
+{
+	if (global_trace.buffer)
+		ring_buffer_record_on(global_trace.buffer);
+	/*
+	 * This flag is only looked at when buffers haven't been
+	 * allocated yet. We don't really care about the race
+	 * between setting this flag and actually turning
+	 * on the buffer.
+	 */
+	global_trace.buffer_disabled = 0;
+}
+EXPORT_SYMBOL_GPL(tracing_on);
+
+/**
+ * tracing_off - turn off tracing buffers
+ *
+ * This function stops the tracing buffers from recording data.
+ * It does not disable any overhead the tracers themselves may
+ * be causing. This function simply causes all recording to
+ * the ring buffers to fail.
+ */
+void tracing_off(void)
+{
+	if (global_trace.buffer)
+		ring_buffer_record_on(global_trace.buffer);
+	/*
+	 * This flag is only looked at when buffers haven't been
+	 * allocated yet. We don't really care about the race
+	 * between setting this flag and actually turning
+	 * on the buffer.
+	 */
+	global_trace.buffer_disabled = 1;
+}
+EXPORT_SYMBOL_GPL(tracing_off);
+
+/**
+ * tracing_is_on - show state of ring buffers enabled
+ */
+int tracing_is_on(void)
+{
+	if (global_trace.buffer)
+		return ring_buffer_record_is_on(global_trace.buffer);
+	return !global_trace.buffer_disabled;
+}
+EXPORT_SYMBOL_GPL(tracing_is_on);
+
+/**
  * trace_wake_up - wake up tasks waiting for trace input
  *
  * Schedules a delayed work to wake up any task that is blocked on the
@@ -1644,6 +1698,7 @@
 	int cpu_file = iter->cpu_file;
 	u64 next_ts = 0, ts;
 	int next_cpu = -1;
+	int next_size = 0;
 	int cpu;
 
 	/*
@@ -1675,9 +1730,12 @@
 			next_cpu = cpu;
 			next_ts = ts;
 			next_lost = lost_events;
+			next_size = iter->ent_size;
 		}
 	}
 
+	iter->ent_size = next_size;
+
 	if (ent_cpu)
 		*ent_cpu = next_cpu;
 
@@ -4567,6 +4625,55 @@
 		create_trace_option_core_file(trace_options[i], i);
 }
 
+static ssize_t
+rb_simple_read(struct file *filp, char __user *ubuf,
+	       size_t cnt, loff_t *ppos)
+{
+	struct ring_buffer *buffer = filp->private_data;
+	char buf[64];
+	int r;
+
+	if (buffer)
+		r = ring_buffer_record_is_on(buffer);
+	else
+		r = 0;
+
+	r = sprintf(buf, "%d\n", r);
+
+	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+}
+
+static ssize_t
+rb_simple_write(struct file *filp, const char __user *ubuf,
+		size_t cnt, loff_t *ppos)
+{
+	struct ring_buffer *buffer = filp->private_data;
+	unsigned long val;
+	int ret;
+
+	ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
+	if (ret)
+		return ret;
+
+	if (buffer) {
+		if (val)
+			ring_buffer_record_on(buffer);
+		else
+			ring_buffer_record_off(buffer);
+	}
+
+	(*ppos)++;
+
+	return cnt;
+}
+
+static const struct file_operations rb_simple_fops = {
+	.open		= tracing_open_generic,
+	.read		= rb_simple_read,
+	.write		= rb_simple_write,
+	.llseek		= default_llseek,
+};
+
 static __init int tracer_init_debugfs(void)
 {
 	struct dentry *d_tracer;
@@ -4626,6 +4733,9 @@
 	trace_create_file("trace_clock", 0644, d_tracer, NULL,
 			  &trace_clock_fops);
 
+	trace_create_file("tracing_on", 0644, d_tracer,
+			    global_trace.buffer, &rb_simple_fops);
+
 #ifdef CONFIG_DYNAMIC_FTRACE
 	trace_create_file("dyn_ftrace_total_info", 0444, d_tracer,
 			&ftrace_update_tot_cnt, &tracing_dyn_info_fops);
@@ -4798,6 +4908,7 @@
 			if (ret != TRACE_TYPE_NO_CONSUME)
 				trace_consume(&iter);
 		}
+		touch_nmi_watchdog();
 
 		trace_printk_seq(&iter.seq);
 	}
@@ -4863,6 +4974,8 @@
 		goto out_free_cpumask;
 	}
 	global_trace.entries = ring_buffer_size(global_trace.buffer);
+	if (global_trace.buffer_disabled)
+		tracing_off();
 
 
 #ifdef CONFIG_TRACER_MAX_TRACE
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 54faec7..95059f0 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -154,6 +154,7 @@
 	struct ring_buffer	*buffer;
 	unsigned long		entries;
 	int			cpu;
+	int			buffer_disabled;
 	cycle_t			time_start;
 	struct task_struct	*waiter;
 	struct trace_array_cpu	*data[NR_CPUS];
@@ -835,13 +836,11 @@
 		     filter)
 #include "trace_entries.h"
 
-#ifdef CONFIG_PERF_EVENTS
 #ifdef CONFIG_FUNCTION_TRACER
 int perf_ftrace_event_register(struct ftrace_event_call *call,
 			       enum trace_reg type, void *data);
 #else
 #define perf_ftrace_event_register NULL
 #endif /* CONFIG_FUNCTION_TRACER */
-#endif /* CONFIG_PERF_EVENTS */
 
 #endif /* _LINUX_KERNEL_TRACE_H */
diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h
index d91eb05..4108e12 100644
--- a/kernel/trace/trace_entries.h
+++ b/kernel/trace/trace_entries.h
@@ -166,6 +166,12 @@
 
 #define FTRACE_STACK_ENTRIES	8
 
+#ifndef CONFIG_64BIT
+# define IP_FMT "%08lx"
+#else
+# define IP_FMT "%016lx"
+#endif
+
 FTRACE_ENTRY(kernel_stack, stack_entry,
 
 	TRACE_STACK,
@@ -175,8 +181,9 @@
 		__dynamic_array(unsigned long,	caller	)
 	),
 
-	F_printk("\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n"
-		 "\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n",
+	F_printk("\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n"
+		 "\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n"
+		 "\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n",
 		 __entry->caller[0], __entry->caller[1], __entry->caller[2],
 		 __entry->caller[3], __entry->caller[4], __entry->caller[5],
 		 __entry->caller[6], __entry->caller[7]),
@@ -193,8 +200,9 @@
 		__array(	unsigned long,	caller, FTRACE_STACK_ENTRIES	)
 	),
 
-	F_printk("\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n"
-		 "\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n",
+	F_printk("\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n"
+		 "\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n"
+		 "\t=> (" IP_FMT ")\n\t=> (" IP_FMT ")\n",
 		 __entry->caller[0], __entry->caller[1], __entry->caller[2],
 		 __entry->caller[3], __entry->caller[4], __entry->caller[5],
 		 __entry->caller[6], __entry->caller[7]),
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
index 7b46c9b..3dd15e8 100644
--- a/kernel/trace/trace_export.c
+++ b/kernel/trace/trace_export.c
@@ -162,7 +162,7 @@
 #define __dynamic_array(type, item)
 
 #undef F_printk
-#define F_printk(fmt, args...) #fmt ", "  __stringify(args)
+#define F_printk(fmt, args...) __stringify(fmt) ", "  __stringify(args)
 
 #undef FTRACE_ENTRY_REG
 #define FTRACE_ENTRY_REG(call, struct_name, etype, tstruct, print, filter,\
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index c5a0187..859fae6b 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -264,7 +264,7 @@
 	return ret;
 }
 
-int trace_seq_path(struct trace_seq *s, struct path *path)
+int trace_seq_path(struct trace_seq *s, const struct path *path)
 {
 	unsigned char *p;
 
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 14bc092..df30ee0 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -9,6 +9,8 @@
  * to those contributors as well.
  */
 
+#define pr_fmt(fmt) "NMI watchdog: " fmt
+
 #include <linux/mm.h>
 #include <linux/cpu.h>
 #include <linux/nmi.h>
@@ -319,11 +321,9 @@
  */
 static int watchdog(void *unused)
 {
-	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+	struct sched_param param = { .sched_priority = 0 };
 	struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer);
 
-	sched_setscheduler(current, SCHED_FIFO, &param);
-
 	/* initialize timestamp */
 	__touch_watchdog();
 
@@ -349,8 +349,11 @@
 
 		set_current_state(TASK_INTERRUPTIBLE);
 	}
+	/*
+	 * Drop the policy/priority elevation during thread exit to avoid a
+	 * scheduling latency spike.
+	 */
 	__set_current_state(TASK_RUNNING);
-	param.sched_priority = 0;
 	sched_setscheduler(current, SCHED_NORMAL, &param);
 	return 0;
 }
@@ -376,18 +379,20 @@
 	/* Try to register using hardware perf events */
 	event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL);
 	if (!IS_ERR(event)) {
-		printk(KERN_INFO "NMI watchdog enabled, takes one hw-pmu counter.\n");
+		pr_info("enabled, takes one hw-pmu counter.\n");
 		goto out_save;
 	}
 
 
 	/* vary the KERN level based on the returned errno */
 	if (PTR_ERR(event) == -EOPNOTSUPP)
-		printk(KERN_INFO "NMI watchdog disabled (cpu%i): not supported (no LAPIC?)\n", cpu);
+		pr_info("disabled (cpu%i): not supported (no LAPIC?)\n", cpu);
 	else if (PTR_ERR(event) == -ENOENT)
-		printk(KERN_WARNING "NMI watchdog disabled (cpu%i): hardware events not enabled\n", cpu);
+		pr_warning("disabled (cpu%i): hardware events not enabled\n",
+			 cpu);
 	else
-		printk(KERN_ERR "NMI watchdog disabled (cpu%i): unable to create perf event: %ld\n", cpu, PTR_ERR(event));
+		pr_err("disabled (cpu%i): unable to create perf event: %ld\n",
+			cpu, PTR_ERR(event));
 	return PTR_ERR(event);
 
 	/* success path */
@@ -439,9 +444,10 @@
 
 	/* create the watchdog thread */
 	if (!p) {
+		struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
 		p = kthread_create_on_node(watchdog, NULL, cpu_to_node(cpu), "watchdog/%d", cpu);
 		if (IS_ERR(p)) {
-			printk(KERN_ERR "softlockup watchdog for %i failed\n", cpu);
+			pr_err("softlockup watchdog for %i failed\n", cpu);
 			if (!err) {
 				/* if hardlockup hasn't already set this */
 				err = PTR_ERR(p);
@@ -450,6 +456,7 @@
 			}
 			goto out;
 		}
+		sched_setscheduler(p, SCHED_FIFO, &param);
 		kthread_bind(p, cpu);
 		per_cpu(watchdog_touch_ts, cpu) = 0;
 		per_cpu(softlockup_watchdog, cpu) = p;
@@ -496,7 +503,7 @@
 			watchdog_enabled = 1;
 
 	if (!watchdog_enabled)
-		printk(KERN_ERR "watchdog: failed to be enabled on some cpus\n");
+		pr_err("failed to be enabled on some cpus\n");
 
 }
 
diff --git a/lib/Kconfig b/lib/Kconfig
index 028aba9..4a8aba2 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -29,6 +29,10 @@
 	bool
 	select GENERIC_PCI_IOMAP
 
+config GENERIC_IO
+	boolean
+	default n
+
 config CRC_CCITT
 	tristate "CRC-CCITT functions"
 	help
@@ -61,14 +65,71 @@
 	  functions require M here.
 
 config CRC32
-	tristate "CRC32 functions"
+	tristate "CRC32/CRC32c functions"
 	default y
 	select BITREVERSE
 	help
 	  This option is provided for the case where no in-kernel-tree
-	  modules require CRC32 functions, but a module built outside the
-	  kernel tree does. Such modules that use library CRC32 functions
-	  require M here.
+	  modules require CRC32/CRC32c functions, but a module built outside
+	  the kernel tree does. Such modules that use library CRC32/CRC32c
+	  functions require M here.
+
+config CRC32_SELFTEST
+	bool "CRC32 perform self test on init"
+	default n
+	depends on CRC32
+	help
+	  This option enables the CRC32 library functions to perform a
+	  self test on initialization. The self test computes crc32_le
+	  and crc32_be over byte strings with random alignment and length
+	  and computes the total elapsed time and number of bytes processed.
+
+choice
+	prompt "CRC32 implementation"
+	depends on CRC32
+	default CRC32_SLICEBY8
+	help
+	  This option allows a kernel builder to override the default choice
+	  of CRC32 algorithm.  Choose the default ("slice by 8") unless you
+	  know that you need one of the others.
+
+config CRC32_SLICEBY8
+	bool "Slice by 8 bytes"
+	help
+	  Calculate checksum 8 bytes at a time with a clever slicing algorithm.
+	  This is the fastest algorithm, but comes with a 8KiB lookup table.
+	  Most modern processors have enough cache to hold this table without
+	  thrashing the cache.
+
+	  This is the default implementation choice.  Choose this one unless
+	  you have a good reason not to.
+
+config CRC32_SLICEBY4
+	bool "Slice by 4 bytes"
+	help
+	  Calculate checksum 4 bytes at a time with a clever slicing algorithm.
+	  This is a bit slower than slice by 8, but has a smaller 4KiB lookup
+	  table.
+
+	  Only choose this option if you know what you are doing.
+
+config CRC32_SARWATE
+	bool "Sarwate's Algorithm (one byte at a time)"
+	help
+	  Calculate checksum a byte at a time using Sarwate's algorithm.  This
+	  is not particularly fast, but has a small 256 byte lookup table.
+
+	  Only choose this option if you know what you are doing.
+
+config CRC32_BIT
+	bool "Classic Algorithm (one bit at a time)"
+	help
+	  Calculate checksum one bit at a time.  This is VERY slow, but has
+	  no lookup table.  This is provided as a debugging option.
+
+	  Only choose this option if you are debugging crc32.
+
+endchoice
 
 config CRC7
 	tristate "CRC7 functions"
@@ -224,6 +285,7 @@
 config HAS_IOMEM
 	boolean
 	depends on !NO_IOMEM
+	select GENERIC_IO
 	default y
 
 config HAS_IOPORT
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 05037dc..6777153 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -184,7 +184,7 @@
 
 config HARDLOCKUP_DETECTOR
 	def_bool LOCKUP_DETECTOR && PERF_EVENTS && HAVE_PERF_EVENTS_NMI && \
-		 !ARCH_HAS_NMI_WATCHDOG
+		 !HAVE_NMI_WATCHDOG
 
 config BOOTPARAM_HARDLOCKUP_PANIC
 	bool "Panic (Reboot) On Hard Lockups"
@@ -499,6 +499,7 @@
 config DEBUG_SPINLOCK
 	bool "Spinlock and rw-lock debugging: basic checks"
 	depends on DEBUG_KERNEL
+	select UNINLINE_SPIN_UNLOCK
 	help
 	  Say Y here and build SMP to catch missing spinlock initialization
 	  and certain other kinds of spinlock errors commonly made.  This is
@@ -1141,14 +1142,6 @@
 	  Enable this option if you want to use the LatencyTOP tool
 	  to find out which userspace is blocking on what kernel operations.
 
-config SYSCTL_SYSCALL_CHECK
-	bool "Sysctl checks"
-	depends on SYSCTL
-	---help---
-	  sys_sysctl uses binary paths that have been found challenging
-	  to properly maintain and use. This enables checks that help
-	  you to keep things correct.
-
 source mm/Kconfig.debug
 source kernel/trace/Kconfig
 
diff --git a/lib/argv_split.c b/lib/argv_split.c
index 4b1b083..1e9a6cb 100644
--- a/lib/argv_split.c
+++ b/lib/argv_split.c
@@ -6,7 +6,7 @@
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <linux/slab.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 static const char *skip_arg(const char *cp)
 {
diff --git a/lib/atomic64.c b/lib/atomic64.c
index 3975470..9785378 100644
--- a/lib/atomic64.c
+++ b/lib/atomic64.c
@@ -13,7 +13,7 @@
 #include <linux/cache.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/atomic.h>
 
 /*
diff --git a/lib/atomic64_test.c b/lib/atomic64_test.c
index 0c33cde..cb99b91 100644
--- a/lib/atomic64_test.c
+++ b/lib/atomic64_test.c
@@ -9,6 +9,7 @@
  * (at your option) any later version.
  */
 #include <linux/init.h>
+#include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/atomic.h>
 
diff --git a/lib/average.c b/lib/average.c
index 5576c28..99a67e6 100644
--- a/lib/average.c
+++ b/lib/average.c
@@ -5,8 +5,9 @@
  * Version 2.  See the file COPYING for more details.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/average.h>
+#include <linux/kernel.h>
 #include <linux/bug.h>
 #include <linux/log2.h>
 
diff --git a/lib/bcd.c b/lib/bcd.c
index d74257f..55efaf7 100644
--- a/lib/bcd.c
+++ b/lib/bcd.c
@@ -1,5 +1,5 @@
 #include <linux/bcd.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 unsigned bcd2bin(unsigned char val)
 {
diff --git a/lib/bitmap.c b/lib/bitmap.c
index 0d4a127..b5a8b6a 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -5,11 +5,13 @@
  * This source code is licensed under the GNU General Public License,
  * Version 2.  See the file COPYING for more details.
  */
-#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/thread_info.h>
 #include <linux/ctype.h>
 #include <linux/errno.h>
 #include <linux/bitmap.h>
 #include <linux/bitops.h>
+#include <linux/bug.h>
 #include <asm/uaccess.h>
 
 /*
diff --git a/lib/bsearch.c b/lib/bsearch.c
index 5b54758..e33c179 100644
--- a/lib/bsearch.c
+++ b/lib/bsearch.c
@@ -9,7 +9,7 @@
  * published by the Free Software Foundation; version 2.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/bsearch.h>
 
 /*
diff --git a/lib/check_signature.c b/lib/check_signature.c
index fd6af19..6b49797 100644
--- a/lib/check_signature.c
+++ b/lib/check_signature.c
@@ -1,5 +1,5 @@
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 /**
  *	check_signature		-	find BIOS signatures
diff --git a/lib/checksum.c b/lib/checksum.c
index 8df2f91..12dceb2 100644
--- a/lib/checksum.c
+++ b/lib/checksum.c
@@ -32,7 +32,7 @@
 /* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access
  kills, so most of the assembly has to go. */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <net/checksum.h>
 
 #include <asm/byteorder.h>
diff --git a/lib/cmdline.c b/lib/cmdline.c
index f5f3ad8..eb67911 100644
--- a/lib/cmdline.c
+++ b/lib/cmdline.c
@@ -12,7 +12,7 @@
  *
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 
diff --git a/lib/cpu_rmap.c b/lib/cpu_rmap.c
index 987acfa..145dec5 100644
--- a/lib/cpu_rmap.c
+++ b/lib/cpu_rmap.c
@@ -11,7 +11,7 @@
 #ifdef CONFIG_GENERIC_HARDIRQS
 #include <linux/interrupt.h>
 #endif
-#include <linux/module.h>
+#include <linux/export.h>
 
 /*
  * These functions maintain a mapping from CPUs to some ordered set of
diff --git a/lib/cpumask.c b/lib/cpumask.c
index af3e5817..402a54a 100644
--- a/lib/cpumask.c
+++ b/lib/cpumask.c
@@ -2,7 +2,7 @@
 #include <linux/kernel.h>
 #include <linux/bitops.h>
 #include <linux/cpumask.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/bootmem.h>
 
 int __first_cpu(const cpumask_t *srcp)
@@ -26,18 +26,6 @@
 EXPORT_SYMBOL(__next_cpu_nr);
 #endif
 
-int __any_online_cpu(const cpumask_t *mask)
-{
-	int cpu;
-
-	for_each_cpu(cpu, mask) {
-		if (cpu_online(cpu))
-			break;
-	}
-	return cpu;
-}
-EXPORT_SYMBOL(__any_online_cpu);
-
 /**
  * cpumask_next_and - get the next cpu in *src1p & *src2p
  * @n: the cpu prior to the place to search (ie. return will be > @n)
diff --git a/lib/crc32.c b/lib/crc32.c
index 4b35d2b..b0d278f 100644
--- a/lib/crc32.c
+++ b/lib/crc32.c
@@ -1,4 +1,8 @@
 /*
+ * Aug 8, 2011 Bob Pearson with help from Joakim Tjernlund and George Spelvin
+ * cleaned up code to current version of sparse and added the slicing-by-8
+ * algorithm to the closely similar existing slicing-by-4 algorithm.
+ *
  * Oct 15, 2000 Matt Domsch <Matt_Domsch@dell.com>
  * Nicer crc32 functions/docs submitted by linux@horizon.com.  Thanks!
  * Code was from the public domain, copyright abandoned.  Code was
@@ -20,52 +24,58 @@
  * Version 2.  See the file COPYING for more details.
  */
 
+/* see: Documentation/crc32.txt for a description of algorithms */
+
 #include <linux/crc32.h>
-#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/compiler.h>
 #include <linux/types.h>
-#include <linux/init.h>
-#include <linux/atomic.h>
 #include "crc32defs.h"
-#if CRC_LE_BITS == 8
-# define tole(x) __constant_cpu_to_le32(x)
+
+#if CRC_LE_BITS > 8
+# define tole(x) ((__force u32) __constant_cpu_to_le32(x))
 #else
 # define tole(x) (x)
 #endif
 
-#if CRC_BE_BITS == 8
-# define tobe(x) __constant_cpu_to_be32(x)
+#if CRC_BE_BITS > 8
+# define tobe(x) ((__force u32) __constant_cpu_to_be32(x))
 #else
 # define tobe(x) (x)
 #endif
+
 #include "crc32table.h"
 
 MODULE_AUTHOR("Matt Domsch <Matt_Domsch@dell.com>");
-MODULE_DESCRIPTION("Ethernet CRC32 calculations");
+MODULE_DESCRIPTION("Various CRC32 calculations");
 MODULE_LICENSE("GPL");
 
-#if CRC_LE_BITS == 8 || CRC_BE_BITS == 8
+#if CRC_LE_BITS > 8 || CRC_BE_BITS > 8
 
+/* implements slicing-by-4 or slicing-by-8 algorithm */
 static inline u32
 crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256])
 {
 # ifdef __LITTLE_ENDIAN
 #  define DO_CRC(x) crc = t0[(crc ^ (x)) & 255] ^ (crc >> 8)
-#  define DO_CRC4 crc = t3[(crc) & 255] ^ \
-		t2[(crc >> 8) & 255] ^ \
-		t1[(crc >> 16) & 255] ^ \
-		t0[(crc >> 24) & 255]
+#  define DO_CRC4 (t3[(q) & 255] ^ t2[(q >> 8) & 255] ^ \
+		   t1[(q >> 16) & 255] ^ t0[(q >> 24) & 255])
+#  define DO_CRC8 (t7[(q) & 255] ^ t6[(q >> 8) & 255] ^ \
+		   t5[(q >> 16) & 255] ^ t4[(q >> 24) & 255])
 # else
 #  define DO_CRC(x) crc = t0[((crc >> 24) ^ (x)) & 255] ^ (crc << 8)
-#  define DO_CRC4 crc = t0[(crc) & 255] ^ \
-		t1[(crc >> 8) & 255] ^  \
-		t2[(crc >> 16) & 255] ^	\
-		t3[(crc >> 24) & 255]
+#  define DO_CRC4 (t0[(q) & 255] ^ t1[(q >> 8) & 255] ^ \
+		   t2[(q >> 16) & 255] ^ t3[(q >> 24) & 255])
+#  define DO_CRC8 (t4[(q) & 255] ^ t5[(q >> 8) & 255] ^ \
+		   t6[(q >> 16) & 255] ^ t7[(q >> 24) & 255])
 # endif
 	const u32 *b;
 	size_t    rem_len;
+# ifdef CONFIG_X86
+	size_t i;
+# endif
 	const u32 *t0=tab[0], *t1=tab[1], *t2=tab[2], *t3=tab[3];
+	const u32 *t4 = tab[4], *t5 = tab[5], *t6 = tab[6], *t7 = tab[7];
+	u32 q;
 
 	/* Align it */
 	if (unlikely((long)buf & 3 && len)) {
@@ -73,27 +83,51 @@
 			DO_CRC(*buf++);
 		} while ((--len) && ((long)buf)&3);
 	}
+
+# if CRC_LE_BITS == 32
 	rem_len = len & 3;
-	/* load data 32 bits wide, xor data 32 bits wide. */
 	len = len >> 2;
+# else
+	rem_len = len & 7;
+	len = len >> 3;
+# endif
+
 	b = (const u32 *)buf;
+# ifdef CONFIG_X86
+	--b;
+	for (i = 0; i < len; i++) {
+# else
 	for (--b; len; --len) {
-		crc ^= *++b; /* use pre increment for speed */
-		DO_CRC4;
+# endif
+		q = crc ^ *++b; /* use pre increment for speed */
+# if CRC_LE_BITS == 32
+		crc = DO_CRC4;
+# else
+		crc = DO_CRC8;
+		q = *++b;
+		crc ^= DO_CRC4;
+# endif
 	}
 	len = rem_len;
 	/* And the last few bytes */
 	if (len) {
 		u8 *p = (u8 *)(b + 1) - 1;
+# ifdef CONFIG_X86
+		for (i = 0; i < len; i++)
+			DO_CRC(*++p); /* use pre increment for speed */
+# else
 		do {
 			DO_CRC(*++p); /* use pre increment for speed */
 		} while (--len);
+# endif
 	}
 	return crc;
 #undef DO_CRC
 #undef DO_CRC4
+#undef DO_CRC8
 }
 #endif
+
 /**
  * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
  * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
@@ -101,53 +135,66 @@
  * @p: pointer to buffer over which CRC is run
  * @len: length of buffer @p
  */
-u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len);
-
-#if CRC_LE_BITS == 1
-/*
- * In fact, the table-based code will work in this case, but it can be
- * simplified by inlining the table in ?: form.
- */
-
-u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
+static inline u32 __pure crc32_le_generic(u32 crc, unsigned char const *p,
+					  size_t len, const u32 (*tab)[256],
+					  u32 polynomial)
 {
+#if CRC_LE_BITS == 1
 	int i;
 	while (len--) {
 		crc ^= *p++;
 		for (i = 0; i < 8; i++)
-			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+			crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0);
 	}
-	return crc;
-}
-#else				/* Table-based approach */
-
-u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
-{
-# if CRC_LE_BITS == 8
-	const u32      (*tab)[] = crc32table_le;
-
-	crc = __cpu_to_le32(crc);
-	crc = crc32_body(crc, p, len, tab);
-	return __le32_to_cpu(crc);
-# elif CRC_LE_BITS == 4
-	while (len--) {
-		crc ^= *p++;
-		crc = (crc >> 4) ^ crc32table_le[crc & 15];
-		crc = (crc >> 4) ^ crc32table_le[crc & 15];
-	}
-	return crc;
 # elif CRC_LE_BITS == 2
 	while (len--) {
 		crc ^= *p++;
-		crc = (crc >> 2) ^ crc32table_le[crc & 3];
-		crc = (crc >> 2) ^ crc32table_le[crc & 3];
-		crc = (crc >> 2) ^ crc32table_le[crc & 3];
-		crc = (crc >> 2) ^ crc32table_le[crc & 3];
+		crc = (crc >> 2) ^ tab[0][crc & 3];
+		crc = (crc >> 2) ^ tab[0][crc & 3];
+		crc = (crc >> 2) ^ tab[0][crc & 3];
+		crc = (crc >> 2) ^ tab[0][crc & 3];
 	}
+# elif CRC_LE_BITS == 4
+	while (len--) {
+		crc ^= *p++;
+		crc = (crc >> 4) ^ tab[0][crc & 15];
+		crc = (crc >> 4) ^ tab[0][crc & 15];
+	}
+# elif CRC_LE_BITS == 8
+	/* aka Sarwate algorithm */
+	while (len--) {
+		crc ^= *p++;
+		crc = (crc >> 8) ^ tab[0][crc & 255];
+	}
+# else
+	crc = (__force u32) __cpu_to_le32(crc);
+	crc = crc32_body(crc, p, len, tab);
+	crc = __le32_to_cpu((__force __le32)crc);
+#endif
 	return crc;
-# endif
+}
+
+#if CRC_LE_BITS == 1
+u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
+{
+	return crc32_le_generic(crc, p, len, NULL, CRCPOLY_LE);
+}
+u32 __pure __crc32c_le(u32 crc, unsigned char const *p, size_t len)
+{
+	return crc32_le_generic(crc, p, len, NULL, CRC32C_POLY_LE);
+}
+#else
+u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
+{
+	return crc32_le_generic(crc, p, len, crc32table_le, CRCPOLY_LE);
+}
+u32 __pure __crc32c_le(u32 crc, unsigned char const *p, size_t len)
+{
+	return crc32_le_generic(crc, p, len, crc32ctable_le, CRC32C_POLY_LE);
 }
 #endif
+EXPORT_SYMBOL(crc32_le);
+EXPORT_SYMBOL(__crc32c_le);
 
 /**
  * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
@@ -156,317 +203,913 @@
  * @p: pointer to buffer over which CRC is run
  * @len: length of buffer @p
  */
-u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len);
-
-#if CRC_BE_BITS == 1
-/*
- * In fact, the table-based code will work in this case, but it can be
- * simplified by inlining the table in ?: form.
- */
-
-u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len)
+static inline u32 __pure crc32_be_generic(u32 crc, unsigned char const *p,
+					  size_t len, const u32 (*tab)[256],
+					  u32 polynomial)
 {
+#if CRC_BE_BITS == 1
 	int i;
 	while (len--) {
 		crc ^= *p++ << 24;
 		for (i = 0; i < 8; i++)
 			crc =
-			    (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE :
+			    (crc << 1) ^ ((crc & 0x80000000) ? polynomial :
 					  0);
 	}
-	return crc;
-}
-
-#else				/* Table-based approach */
-u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len)
-{
-# if CRC_BE_BITS == 8
-	const u32      (*tab)[] = crc32table_be;
-
-	crc = __cpu_to_be32(crc);
-	crc = crc32_body(crc, p, len, tab);
-	return __be32_to_cpu(crc);
-# elif CRC_BE_BITS == 4
-	while (len--) {
-		crc ^= *p++ << 24;
-		crc = (crc << 4) ^ crc32table_be[crc >> 28];
-		crc = (crc << 4) ^ crc32table_be[crc >> 28];
-	}
-	return crc;
 # elif CRC_BE_BITS == 2
 	while (len--) {
 		crc ^= *p++ << 24;
-		crc = (crc << 2) ^ crc32table_be[crc >> 30];
-		crc = (crc << 2) ^ crc32table_be[crc >> 30];
-		crc = (crc << 2) ^ crc32table_be[crc >> 30];
-		crc = (crc << 2) ^ crc32table_be[crc >> 30];
+		crc = (crc << 2) ^ tab[0][crc >> 30];
+		crc = (crc << 2) ^ tab[0][crc >> 30];
+		crc = (crc << 2) ^ tab[0][crc >> 30];
+		crc = (crc << 2) ^ tab[0][crc >> 30];
 	}
-	return crc;
+# elif CRC_BE_BITS == 4
+	while (len--) {
+		crc ^= *p++ << 24;
+		crc = (crc << 4) ^ tab[0][crc >> 28];
+		crc = (crc << 4) ^ tab[0][crc >> 28];
+	}
+# elif CRC_BE_BITS == 8
+	while (len--) {
+		crc ^= *p++ << 24;
+		crc = (crc << 8) ^ tab[0][crc >> 24];
+	}
+# else
+	crc = (__force u32) __cpu_to_be32(crc);
+	crc = crc32_body(crc, p, len, tab);
+	crc = __be32_to_cpu((__force __be32)crc);
 # endif
+	return crc;
+}
+
+#if CRC_LE_BITS == 1
+u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len)
+{
+	return crc32_be_generic(crc, p, len, NULL, CRCPOLY_BE);
+}
+#else
+u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len)
+{
+	return crc32_be_generic(crc, p, len, crc32table_be, CRCPOLY_BE);
 }
 #endif
-
-EXPORT_SYMBOL(crc32_le);
 EXPORT_SYMBOL(crc32_be);
 
-/*
- * A brief CRC tutorial.
- *
- * A CRC is a long-division remainder.  You add the CRC to the message,
- * and the whole thing (message+CRC) is a multiple of the given
- * CRC polynomial.  To check the CRC, you can either check that the
- * CRC matches the recomputed value, *or* you can check that the
- * remainder computed on the message+CRC is 0.  This latter approach
- * is used by a lot of hardware implementations, and is why so many
- * protocols put the end-of-frame flag after the CRC.
- *
- * It's actually the same long division you learned in school, except that
- * - We're working in binary, so the digits are only 0 and 1, and
- * - When dividing polynomials, there are no carries.  Rather than add and
- *   subtract, we just xor.  Thus, we tend to get a bit sloppy about
- *   the difference between adding and subtracting.
- *
- * A 32-bit CRC polynomial is actually 33 bits long.  But since it's
- * 33 bits long, bit 32 is always going to be set, so usually the CRC
- * is written in hex with the most significant bit omitted.  (If you're
- * familiar with the IEEE 754 floating-point format, it's the same idea.)
- *
- * Note that a CRC is computed over a string of *bits*, so you have
- * to decide on the endianness of the bits within each byte.  To get
- * the best error-detecting properties, this should correspond to the
- * order they're actually sent.  For example, standard RS-232 serial is
- * little-endian; the most significant bit (sometimes used for parity)
- * is sent last.  And when appending a CRC word to a message, you should
- * do it in the right order, matching the endianness.
- *
- * Just like with ordinary division, the remainder is always smaller than
- * the divisor (the CRC polynomial) you're dividing by.  Each step of the
- * division, you take one more digit (bit) of the dividend and append it
- * to the current remainder.  Then you figure out the appropriate multiple
- * of the divisor to subtract to being the remainder back into range.
- * In binary, it's easy - it has to be either 0 or 1, and to make the
- * XOR cancel, it's just a copy of bit 32 of the remainder.
- *
- * When computing a CRC, we don't care about the quotient, so we can
- * throw the quotient bit away, but subtract the appropriate multiple of
- * the polynomial from the remainder and we're back to where we started,
- * ready to process the next bit.
- *
- * A big-endian CRC written this way would be coded like:
- * for (i = 0; i < input_bits; i++) {
- * 	multiple = remainder & 0x80000000 ? CRCPOLY : 0;
- * 	remainder = (remainder << 1 | next_input_bit()) ^ multiple;
- * }
- * Notice how, to get at bit 32 of the shifted remainder, we look
- * at bit 31 of the remainder *before* shifting it.
- *
- * But also notice how the next_input_bit() bits we're shifting into
- * the remainder don't actually affect any decision-making until
- * 32 bits later.  Thus, the first 32 cycles of this are pretty boring.
- * Also, to add the CRC to a message, we need a 32-bit-long hole for it at
- * the end, so we have to add 32 extra cycles shifting in zeros at the
- * end of every message,
- *
- * So the standard trick is to rearrage merging in the next_input_bit()
- * until the moment it's needed.  Then the first 32 cycles can be precomputed,
- * and merging in the final 32 zero bits to make room for the CRC can be
- * skipped entirely.
- * This changes the code to:
- * for (i = 0; i < input_bits; i++) {
- *      remainder ^= next_input_bit() << 31;
- * 	multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
- * 	remainder = (remainder << 1) ^ multiple;
- * }
- * With this optimization, the little-endian code is simpler:
- * for (i = 0; i < input_bits; i++) {
- *      remainder ^= next_input_bit();
- * 	multiple = (remainder & 1) ? CRCPOLY : 0;
- * 	remainder = (remainder >> 1) ^ multiple;
- * }
- *
- * Note that the other details of endianness have been hidden in CRCPOLY
- * (which must be bit-reversed) and next_input_bit().
- *
- * However, as long as next_input_bit is returning the bits in a sensible
- * order, we can actually do the merging 8 or more bits at a time rather
- * than one bit at a time:
- * for (i = 0; i < input_bytes; i++) {
- * 	remainder ^= next_input_byte() << 24;
- * 	for (j = 0; j < 8; j++) {
- * 		multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
- * 		remainder = (remainder << 1) ^ multiple;
- * 	}
- * }
- * Or in little-endian:
- * for (i = 0; i < input_bytes; i++) {
- * 	remainder ^= next_input_byte();
- * 	for (j = 0; j < 8; j++) {
- * 		multiple = (remainder & 1) ? CRCPOLY : 0;
- * 		remainder = (remainder << 1) ^ multiple;
- * 	}
- * }
- * If the input is a multiple of 32 bits, you can even XOR in a 32-bit
- * word at a time and increase the inner loop count to 32.
- *
- * You can also mix and match the two loop styles, for example doing the
- * bulk of a message byte-at-a-time and adding bit-at-a-time processing
- * for any fractional bytes at the end.
- *
- * The only remaining optimization is to the byte-at-a-time table method.
- * Here, rather than just shifting one bit of the remainder to decide
- * in the correct multiple to subtract, we can shift a byte at a time.
- * This produces a 40-bit (rather than a 33-bit) intermediate remainder,
- * but again the multiple of the polynomial to subtract depends only on
- * the high bits, the high 8 bits in this case.  
- *
- * The multiple we need in that case is the low 32 bits of a 40-bit
- * value whose high 8 bits are given, and which is a multiple of the
- * generator polynomial.  This is simply the CRC-32 of the given
- * one-byte message.
- *
- * Two more details: normally, appending zero bits to a message which
- * is already a multiple of a polynomial produces a larger multiple of that
- * polynomial.  To enable a CRC to detect this condition, it's common to
- * invert the CRC before appending it.  This makes the remainder of the
- * message+crc come out not as zero, but some fixed non-zero value.
- *
- * The same problem applies to zero bits prepended to the message, and
- * a similar solution is used.  Instead of starting with a remainder of
- * 0, an initial remainder of all ones is used.  As long as you start
- * the same way on decoding, it doesn't make a difference.
- */
+#ifdef CONFIG_CRC32_SELFTEST
 
-#ifdef UNITTEST
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#if 0				/*Not used at present */
-static void
-buf_dump(char const *prefix, unsigned char const *buf, size_t len)
+/* 4096 random bytes */
+static u8 __attribute__((__aligned__(8))) test_buf[] =
 {
-	fputs(prefix, stdout);
-	while (len--)
-		printf(" %02x", *buf++);
-	putchar('\n');
+	0x5b, 0x85, 0x21, 0xcb, 0x09, 0x68, 0x7d, 0x30,
+	0xc7, 0x69, 0xd7, 0x30, 0x92, 0xde, 0x59, 0xe4,
+	0xc9, 0x6e, 0x8b, 0xdb, 0x98, 0x6b, 0xaa, 0x60,
+	0xa8, 0xb5, 0xbc, 0x6c, 0xa9, 0xb1, 0x5b, 0x2c,
+	0xea, 0xb4, 0x92, 0x6a, 0x3f, 0x79, 0x91, 0xe4,
+	0xe9, 0x70, 0x51, 0x8c, 0x7f, 0x95, 0x6f, 0x1a,
+	0x56, 0xa1, 0x5c, 0x27, 0x03, 0x67, 0x9f, 0x3a,
+	0xe2, 0x31, 0x11, 0x29, 0x6b, 0x98, 0xfc, 0xc4,
+	0x53, 0x24, 0xc5, 0x8b, 0xce, 0x47, 0xb2, 0xb9,
+	0x32, 0xcb, 0xc1, 0xd0, 0x03, 0x57, 0x4e, 0xd4,
+	0xe9, 0x3c, 0xa1, 0x63, 0xcf, 0x12, 0x0e, 0xca,
+	0xe1, 0x13, 0xd1, 0x93, 0xa6, 0x88, 0x5c, 0x61,
+	0x5b, 0xbb, 0xf0, 0x19, 0x46, 0xb4, 0xcf, 0x9e,
+	0xb6, 0x6b, 0x4c, 0x3a, 0xcf, 0x60, 0xf9, 0x7a,
+	0x8d, 0x07, 0x63, 0xdb, 0x40, 0xe9, 0x0b, 0x6f,
+	0xad, 0x97, 0xf1, 0xed, 0xd0, 0x1e, 0x26, 0xfd,
+	0xbf, 0xb7, 0xc8, 0x04, 0x94, 0xf8, 0x8b, 0x8c,
+	0xf1, 0xab, 0x7a, 0xd4, 0xdd, 0xf3, 0xe8, 0x88,
+	0xc3, 0xed, 0x17, 0x8a, 0x9b, 0x40, 0x0d, 0x53,
+	0x62, 0x12, 0x03, 0x5f, 0x1b, 0x35, 0x32, 0x1f,
+	0xb4, 0x7b, 0x93, 0x78, 0x0d, 0xdb, 0xce, 0xa4,
+	0xc0, 0x47, 0xd5, 0xbf, 0x68, 0xe8, 0x5d, 0x74,
+	0x8f, 0x8e, 0x75, 0x1c, 0xb2, 0x4f, 0x9a, 0x60,
+	0xd1, 0xbe, 0x10, 0xf4, 0x5c, 0xa1, 0x53, 0x09,
+	0xa5, 0xe0, 0x09, 0x54, 0x85, 0x5c, 0xdc, 0x07,
+	0xe7, 0x21, 0x69, 0x7b, 0x8a, 0xfd, 0x90, 0xf1,
+	0x22, 0xd0, 0xb4, 0x36, 0x28, 0xe6, 0xb8, 0x0f,
+	0x39, 0xde, 0xc8, 0xf3, 0x86, 0x60, 0x34, 0xd2,
+	0x5e, 0xdf, 0xfd, 0xcf, 0x0f, 0xa9, 0x65, 0xf0,
+	0xd5, 0x4d, 0x96, 0x40, 0xe3, 0xdf, 0x3f, 0x95,
+	0x5a, 0x39, 0x19, 0x93, 0xf4, 0x75, 0xce, 0x22,
+	0x00, 0x1c, 0x93, 0xe2, 0x03, 0x66, 0xf4, 0x93,
+	0x73, 0x86, 0x81, 0x8e, 0x29, 0x44, 0x48, 0x86,
+	0x61, 0x7c, 0x48, 0xa3, 0x43, 0xd2, 0x9c, 0x8d,
+	0xd4, 0x95, 0xdd, 0xe1, 0x22, 0x89, 0x3a, 0x40,
+	0x4c, 0x1b, 0x8a, 0x04, 0xa8, 0x09, 0x69, 0x8b,
+	0xea, 0xc6, 0x55, 0x8e, 0x57, 0xe6, 0x64, 0x35,
+	0xf0, 0xc7, 0x16, 0x9f, 0x5d, 0x5e, 0x86, 0x40,
+	0x46, 0xbb, 0xe5, 0x45, 0x88, 0xfe, 0xc9, 0x63,
+	0x15, 0xfb, 0xf5, 0xbd, 0x71, 0x61, 0xeb, 0x7b,
+	0x78, 0x70, 0x07, 0x31, 0x03, 0x9f, 0xb2, 0xc8,
+	0xa7, 0xab, 0x47, 0xfd, 0xdf, 0xa0, 0x78, 0x72,
+	0xa4, 0x2a, 0xe4, 0xb6, 0xba, 0xc0, 0x1e, 0x86,
+	0x71, 0xe6, 0x3d, 0x18, 0x37, 0x70, 0xe6, 0xff,
+	0xe0, 0xbc, 0x0b, 0x22, 0xa0, 0x1f, 0xd3, 0xed,
+	0xa2, 0x55, 0x39, 0xab, 0xa8, 0x13, 0x73, 0x7c,
+	0x3f, 0xb2, 0xd6, 0x19, 0xac, 0xff, 0x99, 0xed,
+	0xe8, 0xe6, 0xa6, 0x22, 0xe3, 0x9c, 0xf1, 0x30,
+	0xdc, 0x01, 0x0a, 0x56, 0xfa, 0xe4, 0xc9, 0x99,
+	0xdd, 0xa8, 0xd8, 0xda, 0x35, 0x51, 0x73, 0xb4,
+	0x40, 0x86, 0x85, 0xdb, 0x5c, 0xd5, 0x85, 0x80,
+	0x14, 0x9c, 0xfd, 0x98, 0xa9, 0x82, 0xc5, 0x37,
+	0xff, 0x32, 0x5d, 0xd0, 0x0b, 0xfa, 0xdc, 0x04,
+	0x5e, 0x09, 0xd2, 0xca, 0x17, 0x4b, 0x1a, 0x8e,
+	0x15, 0xe1, 0xcc, 0x4e, 0x52, 0x88, 0x35, 0xbd,
+	0x48, 0xfe, 0x15, 0xa0, 0x91, 0xfd, 0x7e, 0x6c,
+	0x0e, 0x5d, 0x79, 0x1b, 0x81, 0x79, 0xd2, 0x09,
+	0x34, 0x70, 0x3d, 0x81, 0xec, 0xf6, 0x24, 0xbb,
+	0xfb, 0xf1, 0x7b, 0xdf, 0x54, 0xea, 0x80, 0x9b,
+	0xc7, 0x99, 0x9e, 0xbd, 0x16, 0x78, 0x12, 0x53,
+	0x5e, 0x01, 0xa7, 0x4e, 0xbd, 0x67, 0xe1, 0x9b,
+	0x4c, 0x0e, 0x61, 0x45, 0x97, 0xd2, 0xf0, 0x0f,
+	0xfe, 0x15, 0x08, 0xb7, 0x11, 0x4c, 0xe7, 0xff,
+	0x81, 0x53, 0xff, 0x91, 0x25, 0x38, 0x7e, 0x40,
+	0x94, 0xe5, 0xe0, 0xad, 0xe6, 0xd9, 0x79, 0xb6,
+	0x92, 0xc9, 0xfc, 0xde, 0xc3, 0x1a, 0x23, 0xbb,
+	0xdd, 0xc8, 0x51, 0x0c, 0x3a, 0x72, 0xfa, 0x73,
+	0x6f, 0xb7, 0xee, 0x61, 0x39, 0x03, 0x01, 0x3f,
+	0x7f, 0x94, 0x2e, 0x2e, 0xba, 0x3a, 0xbb, 0xb4,
+	0xfa, 0x6a, 0x17, 0xfe, 0xea, 0xef, 0x5e, 0x66,
+	0x97, 0x3f, 0x32, 0x3d, 0xd7, 0x3e, 0xb1, 0xf1,
+	0x6c, 0x14, 0x4c, 0xfd, 0x37, 0xd3, 0x38, 0x80,
+	0xfb, 0xde, 0xa6, 0x24, 0x1e, 0xc8, 0xca, 0x7f,
+	0x3a, 0x93, 0xd8, 0x8b, 0x18, 0x13, 0xb2, 0xe5,
+	0xe4, 0x93, 0x05, 0x53, 0x4f, 0x84, 0x66, 0xa7,
+	0x58, 0x5c, 0x7b, 0x86, 0x52, 0x6d, 0x0d, 0xce,
+	0xa4, 0x30, 0x7d, 0xb6, 0x18, 0x9f, 0xeb, 0xff,
+	0x22, 0xbb, 0x72, 0x29, 0xb9, 0x44, 0x0b, 0x48,
+	0x1e, 0x84, 0x71, 0x81, 0xe3, 0x6d, 0x73, 0x26,
+	0x92, 0xb4, 0x4d, 0x2a, 0x29, 0xb8, 0x1f, 0x72,
+	0xed, 0xd0, 0xe1, 0x64, 0x77, 0xea, 0x8e, 0x88,
+	0x0f, 0xef, 0x3f, 0xb1, 0x3b, 0xad, 0xf9, 0xc9,
+	0x8b, 0xd0, 0xac, 0xc6, 0xcc, 0xa9, 0x40, 0xcc,
+	0x76, 0xf6, 0x3b, 0x53, 0xb5, 0x88, 0xcb, 0xc8,
+	0x37, 0xf1, 0xa2, 0xba, 0x23, 0x15, 0x99, 0x09,
+	0xcc, 0xe7, 0x7a, 0x3b, 0x37, 0xf7, 0x58, 0xc8,
+	0x46, 0x8c, 0x2b, 0x2f, 0x4e, 0x0e, 0xa6, 0x5c,
+	0xea, 0x85, 0x55, 0xba, 0x02, 0x0e, 0x0e, 0x48,
+	0xbc, 0xe1, 0xb1, 0x01, 0x35, 0x79, 0x13, 0x3d,
+	0x1b, 0xc0, 0x53, 0x68, 0x11, 0xe7, 0x95, 0x0f,
+	0x9d, 0x3f, 0x4c, 0x47, 0x7b, 0x4d, 0x1c, 0xae,
+	0x50, 0x9b, 0xcb, 0xdd, 0x05, 0x8d, 0x9a, 0x97,
+	0xfd, 0x8c, 0xef, 0x0c, 0x1d, 0x67, 0x73, 0xa8,
+	0x28, 0x36, 0xd5, 0xb6, 0x92, 0x33, 0x40, 0x75,
+	0x0b, 0x51, 0xc3, 0x64, 0xba, 0x1d, 0xc2, 0xcc,
+	0xee, 0x7d, 0x54, 0x0f, 0x27, 0x69, 0xa7, 0x27,
+	0x63, 0x30, 0x29, 0xd9, 0xc8, 0x84, 0xd8, 0xdf,
+	0x9f, 0x68, 0x8d, 0x04, 0xca, 0xa6, 0xc5, 0xc7,
+	0x7a, 0x5c, 0xc8, 0xd1, 0xcb, 0x4a, 0xec, 0xd0,
+	0xd8, 0x20, 0x69, 0xc5, 0x17, 0xcd, 0x78, 0xc8,
+	0x75, 0x23, 0x30, 0x69, 0xc9, 0xd4, 0xea, 0x5c,
+	0x4f, 0x6b, 0x86, 0x3f, 0x8b, 0xfe, 0xee, 0x44,
+	0xc9, 0x7c, 0xb7, 0xdd, 0x3e, 0xe5, 0xec, 0x54,
+	0x03, 0x3e, 0xaa, 0x82, 0xc6, 0xdf, 0xb2, 0x38,
+	0x0e, 0x5d, 0xb3, 0x88, 0xd9, 0xd3, 0x69, 0x5f,
+	0x8f, 0x70, 0x8a, 0x7e, 0x11, 0xd9, 0x1e, 0x7b,
+	0x38, 0xf1, 0x42, 0x1a, 0xc0, 0x35, 0xf5, 0xc7,
+	0x36, 0x85, 0xf5, 0xf7, 0xb8, 0x7e, 0xc7, 0xef,
+	0x18, 0xf1, 0x63, 0xd6, 0x7a, 0xc6, 0xc9, 0x0e,
+	0x4d, 0x69, 0x4f, 0x84, 0xef, 0x26, 0x41, 0x0c,
+	0xec, 0xc7, 0xe0, 0x7e, 0x3c, 0x67, 0x01, 0x4c,
+	0x62, 0x1a, 0x20, 0x6f, 0xee, 0x47, 0x4d, 0xc0,
+	0x99, 0x13, 0x8d, 0x91, 0x4a, 0x26, 0xd4, 0x37,
+	0x28, 0x90, 0x58, 0x75, 0x66, 0x2b, 0x0a, 0xdf,
+	0xda, 0xee, 0x92, 0x25, 0x90, 0x62, 0x39, 0x9e,
+	0x44, 0x98, 0xad, 0xc1, 0x88, 0xed, 0xe4, 0xb4,
+	0xaf, 0xf5, 0x8c, 0x9b, 0x48, 0x4d, 0x56, 0x60,
+	0x97, 0x0f, 0x61, 0x59, 0x9e, 0xa6, 0x27, 0xfe,
+	0xc1, 0x91, 0x15, 0x38, 0xb8, 0x0f, 0xae, 0x61,
+	0x7d, 0x26, 0x13, 0x5a, 0x73, 0xff, 0x1c, 0xa3,
+	0x61, 0x04, 0x58, 0x48, 0x55, 0x44, 0x11, 0xfe,
+	0x15, 0xca, 0xc3, 0xbd, 0xca, 0xc5, 0xb4, 0x40,
+	0x5d, 0x1b, 0x7f, 0x39, 0xb5, 0x9c, 0x35, 0xec,
+	0x61, 0x15, 0x32, 0x32, 0xb8, 0x4e, 0x40, 0x9f,
+	0x17, 0x1f, 0x0a, 0x4d, 0xa9, 0x91, 0xef, 0xb7,
+	0xb0, 0xeb, 0xc2, 0x83, 0x9a, 0x6c, 0xd2, 0x79,
+	0x43, 0x78, 0x5e, 0x2f, 0xe5, 0xdd, 0x1a, 0x3c,
+	0x45, 0xab, 0x29, 0x40, 0x3a, 0x37, 0x5b, 0x6f,
+	0xd7, 0xfc, 0x48, 0x64, 0x3c, 0x49, 0xfb, 0x21,
+	0xbe, 0xc3, 0xff, 0x07, 0xfb, 0x17, 0xe9, 0xc9,
+	0x0c, 0x4c, 0x5c, 0x15, 0x9e, 0x8e, 0x22, 0x30,
+	0x0a, 0xde, 0x48, 0x7f, 0xdb, 0x0d, 0xd1, 0x2b,
+	0x87, 0x38, 0x9e, 0xcc, 0x5a, 0x01, 0x16, 0xee,
+	0x75, 0x49, 0x0d, 0x30, 0x01, 0x34, 0x6a, 0xb6,
+	0x9a, 0x5a, 0x2a, 0xec, 0xbb, 0x48, 0xac, 0xd3,
+	0x77, 0x83, 0xd8, 0x08, 0x86, 0x4f, 0x48, 0x09,
+	0x29, 0x41, 0x79, 0xa1, 0x03, 0x12, 0xc4, 0xcd,
+	0x90, 0x55, 0x47, 0x66, 0x74, 0x9a, 0xcc, 0x4f,
+	0x35, 0x8c, 0xd6, 0x98, 0xef, 0xeb, 0x45, 0xb9,
+	0x9a, 0x26, 0x2f, 0x39, 0xa5, 0x70, 0x6d, 0xfc,
+	0xb4, 0x51, 0xee, 0xf4, 0x9c, 0xe7, 0x38, 0x59,
+	0xad, 0xf4, 0xbc, 0x46, 0xff, 0x46, 0x8e, 0x60,
+	0x9c, 0xa3, 0x60, 0x1d, 0xf8, 0x26, 0x72, 0xf5,
+	0x72, 0x9d, 0x68, 0x80, 0x04, 0xf6, 0x0b, 0xa1,
+	0x0a, 0xd5, 0xa7, 0x82, 0x3a, 0x3e, 0x47, 0xa8,
+	0x5a, 0xde, 0x59, 0x4f, 0x7b, 0x07, 0xb3, 0xe9,
+	0x24, 0x19, 0x3d, 0x34, 0x05, 0xec, 0xf1, 0xab,
+	0x6e, 0x64, 0x8f, 0xd3, 0xe6, 0x41, 0x86, 0x80,
+	0x70, 0xe3, 0x8d, 0x60, 0x9c, 0x34, 0x25, 0x01,
+	0x07, 0x4d, 0x19, 0x41, 0x4e, 0x3d, 0x5c, 0x7e,
+	0xa8, 0xf5, 0xcc, 0xd5, 0x7b, 0xe2, 0x7d, 0x3d,
+	0x49, 0x86, 0x7d, 0x07, 0xb7, 0x10, 0xe3, 0x35,
+	0xb8, 0x84, 0x6d, 0x76, 0xab, 0x17, 0xc6, 0x38,
+	0xb4, 0xd3, 0x28, 0x57, 0xad, 0xd3, 0x88, 0x5a,
+	0xda, 0xea, 0xc8, 0x94, 0xcc, 0x37, 0x19, 0xac,
+	0x9c, 0x9f, 0x4b, 0x00, 0x15, 0xc0, 0xc8, 0xca,
+	0x1f, 0x15, 0xaa, 0xe0, 0xdb, 0xf9, 0x2f, 0x57,
+	0x1b, 0x24, 0xc7, 0x6f, 0x76, 0x29, 0xfb, 0xed,
+	0x25, 0x0d, 0xc0, 0xfe, 0xbd, 0x5a, 0xbf, 0x20,
+	0x08, 0x51, 0x05, 0xec, 0x71, 0xa3, 0xbf, 0xef,
+	0x5e, 0x99, 0x75, 0xdb, 0x3c, 0x5f, 0x9a, 0x8c,
+	0xbb, 0x19, 0x5c, 0x0e, 0x93, 0x19, 0xf8, 0x6a,
+	0xbc, 0xf2, 0x12, 0x54, 0x2f, 0xcb, 0x28, 0x64,
+	0x88, 0xb3, 0x92, 0x0d, 0x96, 0xd1, 0xa6, 0xe4,
+	0x1f, 0xf1, 0x4d, 0xa4, 0xab, 0x1c, 0xee, 0x54,
+	0xf2, 0xad, 0x29, 0x6d, 0x32, 0x37, 0xb2, 0x16,
+	0x77, 0x5c, 0xdc, 0x2e, 0x54, 0xec, 0x75, 0x26,
+	0xc6, 0x36, 0xd9, 0x17, 0x2c, 0xf1, 0x7a, 0xdc,
+	0x4b, 0xf1, 0xe2, 0xd9, 0x95, 0xba, 0xac, 0x87,
+	0xc1, 0xf3, 0x8e, 0x58, 0x08, 0xd8, 0x87, 0x60,
+	0xc9, 0xee, 0x6a, 0xde, 0xa4, 0xd2, 0xfc, 0x0d,
+	0xe5, 0x36, 0xc4, 0x5c, 0x52, 0xb3, 0x07, 0x54,
+	0x65, 0x24, 0xc1, 0xb1, 0xd1, 0xb1, 0x53, 0x13,
+	0x31, 0x79, 0x7f, 0x05, 0x76, 0xeb, 0x37, 0x59,
+	0x15, 0x2b, 0xd1, 0x3f, 0xac, 0x08, 0x97, 0xeb,
+	0x91, 0x98, 0xdf, 0x6c, 0x09, 0x0d, 0x04, 0x9f,
+	0xdc, 0x3b, 0x0e, 0x60, 0x68, 0x47, 0x23, 0x15,
+	0x16, 0xc6, 0x0b, 0x35, 0xf8, 0x77, 0xa2, 0x78,
+	0x50, 0xd4, 0x64, 0x22, 0x33, 0xff, 0xfb, 0x93,
+	0x71, 0x46, 0x50, 0x39, 0x1b, 0x9c, 0xea, 0x4e,
+	0x8d, 0x0c, 0x37, 0xe5, 0x5c, 0x51, 0x3a, 0x31,
+	0xb2, 0x85, 0x84, 0x3f, 0x41, 0xee, 0xa2, 0xc1,
+	0xc6, 0x13, 0x3b, 0x54, 0x28, 0xd2, 0x18, 0x37,
+	0xcc, 0x46, 0x9f, 0x6a, 0x91, 0x3d, 0x5a, 0x15,
+	0x3c, 0x89, 0xa3, 0x61, 0x06, 0x7d, 0x2e, 0x78,
+	0xbe, 0x7d, 0x40, 0xba, 0x2f, 0x95, 0xb1, 0x2f,
+	0x87, 0x3b, 0x8a, 0xbe, 0x6a, 0xf4, 0xc2, 0x31,
+	0x74, 0xee, 0x91, 0xe0, 0x23, 0xaa, 0x5d, 0x7f,
+	0xdd, 0xf0, 0x44, 0x8c, 0x0b, 0x59, 0x2b, 0xfc,
+	0x48, 0x3a, 0xdf, 0x07, 0x05, 0x38, 0x6c, 0xc9,
+	0xeb, 0x18, 0x24, 0x68, 0x8d, 0x58, 0x98, 0xd3,
+	0x31, 0xa3, 0xe4, 0x70, 0x59, 0xb1, 0x21, 0xbe,
+	0x7e, 0x65, 0x7d, 0xb8, 0x04, 0xab, 0xf6, 0xe4,
+	0xd7, 0xda, 0xec, 0x09, 0x8f, 0xda, 0x6d, 0x24,
+	0x07, 0xcc, 0x29, 0x17, 0x05, 0x78, 0x1a, 0xc1,
+	0xb1, 0xce, 0xfc, 0xaa, 0x2d, 0xe7, 0xcc, 0x85,
+	0x84, 0x84, 0x03, 0x2a, 0x0c, 0x3f, 0xa9, 0xf8,
+	0xfd, 0x84, 0x53, 0x59, 0x5c, 0xf0, 0xd4, 0x09,
+	0xf0, 0xd2, 0x6c, 0x32, 0x03, 0xb0, 0xa0, 0x8c,
+	0x52, 0xeb, 0x23, 0x91, 0x88, 0x43, 0x13, 0x46,
+	0xf6, 0x1e, 0xb4, 0x1b, 0xf5, 0x8e, 0x3a, 0xb5,
+	0x3d, 0x00, 0xf6, 0xe5, 0x08, 0x3d, 0x5f, 0x39,
+	0xd3, 0x21, 0x69, 0xbc, 0x03, 0x22, 0x3a, 0xd2,
+	0x5c, 0x84, 0xf8, 0x15, 0xc4, 0x80, 0x0b, 0xbc,
+	0x29, 0x3c, 0xf3, 0x95, 0x98, 0xcd, 0x8f, 0x35,
+	0xbc, 0xa5, 0x3e, 0xfc, 0xd4, 0x13, 0x9e, 0xde,
+	0x4f, 0xce, 0x71, 0x9d, 0x09, 0xad, 0xf2, 0x80,
+	0x6b, 0x65, 0x7f, 0x03, 0x00, 0x14, 0x7c, 0x15,
+	0x85, 0x40, 0x6d, 0x70, 0xea, 0xdc, 0xb3, 0x63,
+	0x35, 0x4f, 0x4d, 0xe0, 0xd9, 0xd5, 0x3c, 0x58,
+	0x56, 0x23, 0x80, 0xe2, 0x36, 0xdd, 0x75, 0x1d,
+	0x94, 0x11, 0x41, 0x8e, 0xe0, 0x81, 0x8e, 0xcf,
+	0xe0, 0xe5, 0xf6, 0xde, 0xd1, 0xe7, 0x04, 0x12,
+	0x79, 0x92, 0x2b, 0x71, 0x2a, 0x79, 0x8b, 0x7c,
+	0x44, 0x79, 0x16, 0x30, 0x4e, 0xf4, 0xf6, 0x9b,
+	0xb7, 0x40, 0xa3, 0x5a, 0xa7, 0x69, 0x3e, 0xc1,
+	0x3a, 0x04, 0xd0, 0x88, 0xa0, 0x3b, 0xdd, 0xc6,
+	0x9e, 0x7e, 0x1e, 0x1e, 0x8f, 0x44, 0xf7, 0x73,
+	0x67, 0x1e, 0x1a, 0x78, 0xfa, 0x62, 0xf4, 0xa9,
+	0xa8, 0xc6, 0x5b, 0xb8, 0xfa, 0x06, 0x7d, 0x5e,
+	0x38, 0x1c, 0x9a, 0x39, 0xe9, 0x39, 0x98, 0x22,
+	0x0b, 0xa7, 0xac, 0x0b, 0xf3, 0xbc, 0xf1, 0xeb,
+	0x8c, 0x81, 0xe3, 0x48, 0x8a, 0xed, 0x42, 0xc2,
+	0x38, 0xcf, 0x3e, 0xda, 0xd2, 0x89, 0x8d, 0x9c,
+	0x53, 0xb5, 0x2f, 0x41, 0x01, 0x26, 0x84, 0x9c,
+	0xa3, 0x56, 0xf6, 0x49, 0xc7, 0xd4, 0x9f, 0x93,
+	0x1b, 0x96, 0x49, 0x5e, 0xad, 0xb3, 0x84, 0x1f,
+	0x3c, 0xa4, 0xe0, 0x9b, 0xd1, 0x90, 0xbc, 0x38,
+	0x6c, 0xdd, 0x95, 0x4d, 0x9d, 0xb1, 0x71, 0x57,
+	0x2d, 0x34, 0xe8, 0xb8, 0x42, 0xc7, 0x99, 0x03,
+	0xc7, 0x07, 0x30, 0x65, 0x91, 0x55, 0xd5, 0x90,
+	0x70, 0x97, 0x37, 0x68, 0xd4, 0x11, 0xf9, 0xe8,
+	0xce, 0xec, 0xdc, 0x34, 0xd5, 0xd3, 0xb7, 0xc4,
+	0xb8, 0x97, 0x05, 0x92, 0xad, 0xf8, 0xe2, 0x36,
+	0x64, 0x41, 0xc9, 0xc5, 0x41, 0x77, 0x52, 0xd7,
+	0x2c, 0xa5, 0x24, 0x2f, 0xd9, 0x34, 0x0b, 0x47,
+	0x35, 0xa7, 0x28, 0x8b, 0xc5, 0xcd, 0xe9, 0x46,
+	0xac, 0x39, 0x94, 0x3c, 0x10, 0xc6, 0x29, 0x73,
+	0x0e, 0x0e, 0x5d, 0xe0, 0x71, 0x03, 0x8a, 0x72,
+	0x0e, 0x26, 0xb0, 0x7d, 0x84, 0xed, 0x95, 0x23,
+	0x49, 0x5a, 0x45, 0x83, 0x45, 0x60, 0x11, 0x4a,
+	0x46, 0x31, 0xd4, 0xd8, 0x16, 0x54, 0x98, 0x58,
+	0xed, 0x6d, 0xcc, 0x5d, 0xd6, 0x50, 0x61, 0x9f,
+	0x9d, 0xc5, 0x3e, 0x9d, 0x32, 0x47, 0xde, 0x96,
+	0xe1, 0x5d, 0xd8, 0xf8, 0xb4, 0x69, 0x6f, 0xb9,
+	0x15, 0x90, 0x57, 0x7a, 0xf6, 0xad, 0xb0, 0x5b,
+	0xf5, 0xa6, 0x36, 0x94, 0xfd, 0x84, 0xce, 0x1c,
+	0x0f, 0x4b, 0xd0, 0xc2, 0x5b, 0x6b, 0x56, 0xef,
+	0x73, 0x93, 0x0b, 0xc3, 0xee, 0xd9, 0xcf, 0xd3,
+	0xa4, 0x22, 0x58, 0xcd, 0x50, 0x6e, 0x65, 0xf4,
+	0xe9, 0xb7, 0x71, 0xaf, 0x4b, 0xb3, 0xb6, 0x2f,
+	0x0f, 0x0e, 0x3b, 0xc9, 0x85, 0x14, 0xf5, 0x17,
+	0xe8, 0x7a, 0x3a, 0xbf, 0x5f, 0x5e, 0xf8, 0x18,
+	0x48, 0xa6, 0x72, 0xab, 0x06, 0x95, 0xe9, 0xc8,
+	0xa7, 0xf4, 0x32, 0x44, 0x04, 0x0c, 0x84, 0x98,
+	0x73, 0xe3, 0x89, 0x8d, 0x5f, 0x7e, 0x4a, 0x42,
+	0x8f, 0xc5, 0x28, 0xb1, 0x82, 0xef, 0x1c, 0x97,
+	0x31, 0x3b, 0x4d, 0xe0, 0x0e, 0x10, 0x10, 0x97,
+	0x93, 0x49, 0x78, 0x2f, 0x0d, 0x86, 0x8b, 0xa1,
+	0x53, 0xa9, 0x81, 0x20, 0x79, 0xe7, 0x07, 0x77,
+	0xb6, 0xac, 0x5e, 0xd2, 0x05, 0xcd, 0xe9, 0xdb,
+	0x8a, 0x94, 0x82, 0x8a, 0x23, 0xb9, 0x3d, 0x1c,
+	0xa9, 0x7d, 0x72, 0x4a, 0xed, 0x33, 0xa3, 0xdb,
+	0x21, 0xa7, 0x86, 0x33, 0x45, 0xa5, 0xaa, 0x56,
+	0x45, 0xb5, 0x83, 0x29, 0x40, 0x47, 0x79, 0x04,
+	0x6e, 0xb9, 0x95, 0xd0, 0x81, 0x77, 0x2d, 0x48,
+	0x1e, 0xfe, 0xc3, 0xc2, 0x1e, 0xe5, 0xf2, 0xbe,
+	0xfd, 0x3b, 0x94, 0x9f, 0xc4, 0xc4, 0x26, 0x9d,
+	0xe4, 0x66, 0x1e, 0x19, 0xee, 0x6c, 0x79, 0x97,
+	0x11, 0x31, 0x4b, 0x0d, 0x01, 0xcb, 0xde, 0xa8,
+	0xf6, 0x6d, 0x7c, 0x39, 0x46, 0x4e, 0x7e, 0x3f,
+	0x94, 0x17, 0xdf, 0xa1, 0x7d, 0xd9, 0x1c, 0x8e,
+	0xbc, 0x7d, 0x33, 0x7d, 0xe3, 0x12, 0x40, 0xca,
+	0xab, 0x37, 0x11, 0x46, 0xd4, 0xae, 0xef, 0x44,
+	0xa2, 0xb3, 0x6a, 0x66, 0x0e, 0x0c, 0x90, 0x7f,
+	0xdf, 0x5c, 0x66, 0x5f, 0xf2, 0x94, 0x9f, 0xa6,
+	0x73, 0x4f, 0xeb, 0x0d, 0xad, 0xbf, 0xc0, 0x63,
+	0x5c, 0xdc, 0x46, 0x51, 0xe8, 0x8e, 0x90, 0x19,
+	0xa8, 0xa4, 0x3c, 0x91, 0x79, 0xfa, 0x7e, 0x58,
+	0x85, 0x13, 0x55, 0xc5, 0x19, 0x82, 0x37, 0x1b,
+	0x0a, 0x02, 0x1f, 0x99, 0x6b, 0x18, 0xf1, 0x28,
+	0x08, 0xa2, 0x73, 0xb8, 0x0f, 0x2e, 0xcd, 0xbf,
+	0xf3, 0x86, 0x7f, 0xea, 0xef, 0xd0, 0xbb, 0xa6,
+	0x21, 0xdf, 0x49, 0x73, 0x51, 0xcc, 0x36, 0xd3,
+	0x3e, 0xa0, 0xf8, 0x44, 0xdf, 0xd3, 0xa6, 0xbe,
+	0x8a, 0xd4, 0x57, 0xdd, 0x72, 0x94, 0x61, 0x0f,
+	0x82, 0xd1, 0x07, 0xb8, 0x7c, 0x18, 0x83, 0xdf,
+	0x3a, 0xe5, 0x50, 0x6a, 0x82, 0x20, 0xac, 0xa9,
+	0xa8, 0xff, 0xd9, 0xf3, 0x77, 0x33, 0x5a, 0x9e,
+	0x7f, 0x6d, 0xfe, 0x5d, 0x33, 0x41, 0x42, 0xe7,
+	0x6c, 0x19, 0xe0, 0x44, 0x8a, 0x15, 0xf6, 0x70,
+	0x98, 0xb7, 0x68, 0x4d, 0xfa, 0x97, 0x39, 0xb0,
+	0x8e, 0xe8, 0x84, 0x8b, 0x75, 0x30, 0xb7, 0x7d,
+	0x92, 0x69, 0x20, 0x9c, 0x81, 0xfb, 0x4b, 0xf4,
+	0x01, 0x50, 0xeb, 0xce, 0x0c, 0x1c, 0x6c, 0xb5,
+	0x4a, 0xd7, 0x27, 0x0c, 0xce, 0xbb, 0xe5, 0x85,
+	0xf0, 0xb6, 0xee, 0xd5, 0x70, 0xdd, 0x3b, 0xfc,
+	0xd4, 0x99, 0xf1, 0x33, 0xdd, 0x8b, 0xc4, 0x2f,
+	0xae, 0xab, 0x74, 0x96, 0x32, 0xc7, 0x4c, 0x56,
+	0x3c, 0x89, 0x0f, 0x96, 0x0b, 0x42, 0xc0, 0xcb,
+	0xee, 0x0f, 0x0b, 0x8c, 0xfb, 0x7e, 0x47, 0x7b,
+	0x64, 0x48, 0xfd, 0xb2, 0x00, 0x80, 0x89, 0xa5,
+	0x13, 0x55, 0x62, 0xfc, 0x8f, 0xe2, 0x42, 0x03,
+	0xb7, 0x4e, 0x2a, 0x79, 0xb4, 0x82, 0xea, 0x23,
+	0x49, 0xda, 0xaf, 0x52, 0x63, 0x1e, 0x60, 0x03,
+	0x89, 0x06, 0x44, 0x46, 0x08, 0xc3, 0xc4, 0x87,
+	0x70, 0x2e, 0xda, 0x94, 0xad, 0x6b, 0xe0, 0xe4,
+	0xd1, 0x8a, 0x06, 0xc2, 0xa8, 0xc0, 0xa7, 0x43,
+	0x3c, 0x47, 0x52, 0x0e, 0xc3, 0x77, 0x81, 0x11,
+	0x67, 0x0e, 0xa0, 0x70, 0x04, 0x47, 0x29, 0x40,
+	0x86, 0x0d, 0x34, 0x56, 0xa7, 0xc9, 0x35, 0x59,
+	0x68, 0xdc, 0x93, 0x81, 0x70, 0xee, 0x86, 0xd9,
+	0x80, 0x06, 0x40, 0x4f, 0x1a, 0x0d, 0x40, 0x30,
+	0x0b, 0xcb, 0x96, 0x47, 0xc1, 0xb7, 0x52, 0xfd,
+	0x56, 0xe0, 0x72, 0x4b, 0xfb, 0xbd, 0x92, 0x45,
+	0x61, 0x71, 0xc2, 0x33, 0x11, 0xbf, 0x52, 0x83,
+	0x79, 0x26, 0xe0, 0x49, 0x6b, 0xb7, 0x05, 0x8b,
+	0xe8, 0x0e, 0x87, 0x31, 0xd7, 0x9d, 0x8a, 0xf5,
+	0xc0, 0x5f, 0x2e, 0x58, 0x4a, 0xdb, 0x11, 0xb3,
+	0x6c, 0x30, 0x2a, 0x46, 0x19, 0xe3, 0x27, 0x84,
+	0x1f, 0x63, 0x6e, 0xf6, 0x57, 0xc7, 0xc9, 0xd8,
+	0x5e, 0xba, 0xb3, 0x87, 0xd5, 0x83, 0x26, 0x34,
+	0x21, 0x9e, 0x65, 0xde, 0x42, 0xd3, 0xbe, 0x7b,
+	0xbc, 0x91, 0x71, 0x44, 0x4d, 0x99, 0x3b, 0x31,
+	0xe5, 0x3f, 0x11, 0x4e, 0x7f, 0x13, 0x51, 0x3b,
+	0xae, 0x79, 0xc9, 0xd3, 0x81, 0x8e, 0x25, 0x40,
+	0x10, 0xfc, 0x07, 0x1e, 0xf9, 0x7b, 0x9a, 0x4b,
+	0x6c, 0xe3, 0xb3, 0xad, 0x1a, 0x0a, 0xdd, 0x9e,
+	0x59, 0x0c, 0xa2, 0xcd, 0xae, 0x48, 0x4a, 0x38,
+	0x5b, 0x47, 0x41, 0x94, 0x65, 0x6b, 0xbb, 0xeb,
+	0x5b, 0xe3, 0xaf, 0x07, 0x5b, 0xd4, 0x4a, 0xa2,
+	0xc9, 0x5d, 0x2f, 0x64, 0x03, 0xd7, 0x3a, 0x2c,
+	0x6e, 0xce, 0x76, 0x95, 0xb4, 0xb3, 0xc0, 0xf1,
+	0xe2, 0x45, 0x73, 0x7a, 0x5c, 0xab, 0xc1, 0xfc,
+	0x02, 0x8d, 0x81, 0x29, 0xb3, 0xac, 0x07, 0xec,
+	0x40, 0x7d, 0x45, 0xd9, 0x7a, 0x59, 0xee, 0x34,
+	0xf0, 0xe9, 0xd5, 0x7b, 0x96, 0xb1, 0x3d, 0x95,
+	0xcc, 0x86, 0xb5, 0xb6, 0x04, 0x2d, 0xb5, 0x92,
+	0x7e, 0x76, 0xf4, 0x06, 0xa9, 0xa3, 0x12, 0x0f,
+	0xb1, 0xaf, 0x26, 0xba, 0x7c, 0xfc, 0x7e, 0x1c,
+	0xbc, 0x2c, 0x49, 0x97, 0x53, 0x60, 0x13, 0x0b,
+	0xa6, 0x61, 0x83, 0x89, 0x42, 0xd4, 0x17, 0x0c,
+	0x6c, 0x26, 0x52, 0xc3, 0xb3, 0xd4, 0x67, 0xf5,
+	0xe3, 0x04, 0xb7, 0xf4, 0xcb, 0x80, 0xb8, 0xcb,
+	0x77, 0x56, 0x3e, 0xaa, 0x57, 0x54, 0xee, 0xb4,
+	0x2c, 0x67, 0xcf, 0xf2, 0xdc, 0xbe, 0x55, 0xf9,
+	0x43, 0x1f, 0x6e, 0x22, 0x97, 0x67, 0x7f, 0xc4,
+	0xef, 0xb1, 0x26, 0x31, 0x1e, 0x27, 0xdf, 0x41,
+	0x80, 0x47, 0x6c, 0xe2, 0xfa, 0xa9, 0x8c, 0x2a,
+	0xf6, 0xf2, 0xab, 0xf0, 0x15, 0xda, 0x6c, 0xc8,
+	0xfe, 0xb5, 0x23, 0xde, 0xa9, 0x05, 0x3f, 0x06,
+	0x54, 0x4c, 0xcd, 0xe1, 0xab, 0xfc, 0x0e, 0x62,
+	0x33, 0x31, 0x73, 0x2c, 0x76, 0xcb, 0xb4, 0x47,
+	0x1e, 0x20, 0xad, 0xd8, 0xf2, 0x31, 0xdd, 0xc4,
+	0x8b, 0x0c, 0x77, 0xbe, 0xe1, 0x8b, 0x26, 0x00,
+	0x02, 0x58, 0xd6, 0x8d, 0xef, 0xad, 0x74, 0x67,
+	0xab, 0x3f, 0xef, 0xcb, 0x6f, 0xb0, 0xcc, 0x81,
+	0x44, 0x4c, 0xaf, 0xe9, 0x49, 0x4f, 0xdb, 0xa0,
+	0x25, 0xa4, 0xf0, 0x89, 0xf1, 0xbe, 0xd8, 0x10,
+	0xff, 0xb1, 0x3b, 0x4b, 0xfa, 0x98, 0xf5, 0x79,
+	0x6d, 0x1e, 0x69, 0x4d, 0x57, 0xb1, 0xc8, 0x19,
+	0x1b, 0xbd, 0x1e, 0x8c, 0x84, 0xb7, 0x7b, 0xe8,
+	0xd2, 0x2d, 0x09, 0x41, 0x41, 0x37, 0x3d, 0xb1,
+	0x6f, 0x26, 0x5d, 0x71, 0x16, 0x3d, 0xb7, 0x83,
+	0x27, 0x2c, 0xa7, 0xb6, 0x50, 0xbd, 0x91, 0x86,
+	0xab, 0x24, 0xa1, 0x38, 0xfd, 0xea, 0x71, 0x55,
+	0x7e, 0x9a, 0x07, 0x77, 0x4b, 0xfa, 0x61, 0x66,
+	0x20, 0x1e, 0x28, 0x95, 0x18, 0x1b, 0xa4, 0xa0,
+	0xfd, 0xc0, 0x89, 0x72, 0x43, 0xd9, 0x3b, 0x49,
+	0x5a, 0x3f, 0x9d, 0xbf, 0xdb, 0xb4, 0x46, 0xea,
+	0x42, 0x01, 0x77, 0x23, 0x68, 0x95, 0xb6, 0x24,
+	0xb3, 0xa8, 0x6c, 0x28, 0x3b, 0x11, 0x40, 0x7e,
+	0x18, 0x65, 0x6d, 0xd8, 0x24, 0x42, 0x7d, 0x88,
+	0xc0, 0x52, 0xd9, 0x05, 0xe4, 0x95, 0x90, 0x87,
+	0x8c, 0xf4, 0xd0, 0x6b, 0xb9, 0x83, 0x99, 0x34,
+	0x6d, 0xfe, 0x54, 0x40, 0x94, 0x52, 0x21, 0x4f,
+	0x14, 0x25, 0xc5, 0xd6, 0x5e, 0x95, 0xdc, 0x0a,
+	0x2b, 0x89, 0x20, 0x11, 0x84, 0x48, 0xd6, 0x3a,
+	0xcd, 0x5c, 0x24, 0xad, 0x62, 0xe3, 0xb1, 0x93,
+	0x25, 0x8d, 0xcd, 0x7e, 0xfc, 0x27, 0xa3, 0x37,
+	0xfd, 0x84, 0xfc, 0x1b, 0xb2, 0xf1, 0x27, 0x38,
+	0x5a, 0xb7, 0xfc, 0xf2, 0xfa, 0x95, 0x66, 0xd4,
+	0xfb, 0xba, 0xa7, 0xd7, 0xa3, 0x72, 0x69, 0x48,
+	0x48, 0x8c, 0xeb, 0x28, 0x89, 0xfe, 0x33, 0x65,
+	0x5a, 0x36, 0x01, 0x7e, 0x06, 0x79, 0x0a, 0x09,
+	0x3b, 0x74, 0x11, 0x9a, 0x6e, 0xbf, 0xd4, 0x9e,
+	0x58, 0x90, 0x49, 0x4f, 0x4d, 0x08, 0xd4, 0xe5,
+	0x4a, 0x09, 0x21, 0xef, 0x8b, 0xb8, 0x74, 0x3b,
+	0x91, 0xdd, 0x36, 0x85, 0x60, 0x2d, 0xfa, 0xd4,
+	0x45, 0x7b, 0x45, 0x53, 0xf5, 0x47, 0x87, 0x7e,
+	0xa6, 0x37, 0xc8, 0x78, 0x7a, 0x68, 0x9d, 0x8d,
+	0x65, 0x2c, 0x0e, 0x91, 0x5c, 0xa2, 0x60, 0xf0,
+	0x8e, 0x3f, 0xe9, 0x1a, 0xcd, 0xaa, 0xe7, 0xd5,
+	0x77, 0x18, 0xaf, 0xc9, 0xbc, 0x18, 0xea, 0x48,
+	0x1b, 0xfb, 0x22, 0x48, 0x70, 0x16, 0x29, 0x9e,
+	0x5b, 0xc1, 0x2c, 0x66, 0x23, 0xbc, 0xf0, 0x1f,
+	0xef, 0xaf, 0xe4, 0xd6, 0x04, 0x19, 0x82, 0x7a,
+	0x0b, 0xba, 0x4b, 0x46, 0xb1, 0x6a, 0x85, 0x5d,
+	0xb4, 0x73, 0xd6, 0x21, 0xa1, 0x71, 0x60, 0x14,
+	0xee, 0x0a, 0x77, 0xc4, 0x66, 0x2e, 0xf9, 0x69,
+	0x30, 0xaf, 0x41, 0x0b, 0xc8, 0x83, 0x3c, 0x53,
+	0x99, 0x19, 0x27, 0x46, 0xf7, 0x41, 0x6e, 0x56,
+	0xdc, 0x94, 0x28, 0x67, 0x4e, 0xb7, 0x25, 0x48,
+	0x8a, 0xc2, 0xe0, 0x60, 0x96, 0xcc, 0x18, 0xf4,
+	0x84, 0xdd, 0xa7, 0x5e, 0x3e, 0x05, 0x0b, 0x26,
+	0x26, 0xb2, 0x5c, 0x1f, 0x57, 0x1a, 0x04, 0x7e,
+	0x6a, 0xe3, 0x2f, 0xb4, 0x35, 0xb6, 0x38, 0x40,
+	0x40, 0xcd, 0x6f, 0x87, 0x2e, 0xef, 0xa3, 0xd7,
+	0xa9, 0xc2, 0xe8, 0x0d, 0x27, 0xdf, 0x44, 0x62,
+	0x99, 0xa0, 0xfc, 0xcf, 0x81, 0x78, 0xcb, 0xfe,
+	0xe5, 0xa0, 0x03, 0x4e, 0x6c, 0xd7, 0xf4, 0xaf,
+	0x7a, 0xbb, 0x61, 0x82, 0xfe, 0x71, 0x89, 0xb2,
+	0x22, 0x7c, 0x8e, 0x83, 0x04, 0xce, 0xf6, 0x5d,
+	0x84, 0x8f, 0x95, 0x6a, 0x7f, 0xad, 0xfd, 0x32,
+	0x9c, 0x5e, 0xe4, 0x9c, 0x89, 0x60, 0x54, 0xaa,
+	0x96, 0x72, 0xd2, 0xd7, 0x36, 0x85, 0xa9, 0x45,
+	0xd2, 0x2a, 0xa1, 0x81, 0x49, 0x6f, 0x7e, 0x04,
+	0xfa, 0xe2, 0xfe, 0x90, 0x26, 0x77, 0x5a, 0x33,
+	0xb8, 0x04, 0x9a, 0x7a, 0xe6, 0x4c, 0x4f, 0xad,
+	0x72, 0x96, 0x08, 0x28, 0x58, 0x13, 0xf8, 0xc4,
+	0x1c, 0xf0, 0xc3, 0x45, 0x95, 0x49, 0x20, 0x8c,
+	0x9f, 0x39, 0x70, 0xe1, 0x77, 0xfe, 0xd5, 0x4b,
+	0xaf, 0x86, 0xda, 0xef, 0x22, 0x06, 0x83, 0x36,
+	0x29, 0x12, 0x11, 0x40, 0xbc, 0x3b, 0x86, 0xaa,
+	0xaa, 0x65, 0x60, 0xc3, 0x80, 0xca, 0xed, 0xa9,
+	0xf3, 0xb0, 0x79, 0x96, 0xa2, 0x55, 0x27, 0x28,
+	0x55, 0x73, 0x26, 0xa5, 0x50, 0xea, 0x92, 0x4b,
+	0x3c, 0x5c, 0x82, 0x33, 0xf0, 0x01, 0x3f, 0x03,
+	0xc1, 0x08, 0x05, 0xbf, 0x98, 0xf4, 0x9b, 0x6d,
+	0xa5, 0xa8, 0xb4, 0x82, 0x0c, 0x06, 0xfa, 0xff,
+	0x2d, 0x08, 0xf3, 0x05, 0x4f, 0x57, 0x2a, 0x39,
+	0xd4, 0x83, 0x0d, 0x75, 0x51, 0xd8, 0x5b, 0x1b,
+	0xd3, 0x51, 0x5a, 0x32, 0x2a, 0x9b, 0x32, 0xb2,
+	0xf2, 0xa4, 0x96, 0x12, 0xf2, 0xae, 0x40, 0x34,
+	0x67, 0xa8, 0xf5, 0x44, 0xd5, 0x35, 0x53, 0xfe,
+	0xa3, 0x60, 0x96, 0x63, 0x0f, 0x1f, 0x6e, 0xb0,
+	0x5a, 0x42, 0xa6, 0xfc, 0x51, 0x0b, 0x60, 0x27,
+	0xbc, 0x06, 0x71, 0xed, 0x65, 0x5b, 0x23, 0x86,
+	0x4a, 0x07, 0x3b, 0x22, 0x07, 0x46, 0xe6, 0x90,
+	0x3e, 0xf3, 0x25, 0x50, 0x1b, 0x4c, 0x7f, 0x03,
+	0x08, 0xa8, 0x36, 0x6b, 0x87, 0xe5, 0xe3, 0xdb,
+	0x9a, 0x38, 0x83, 0xff, 0x9f, 0x1a, 0x9f, 0x57,
+	0xa4, 0x2a, 0xf6, 0x37, 0xbc, 0x1a, 0xff, 0xc9,
+	0x1e, 0x35, 0x0c, 0xc3, 0x7c, 0xa3, 0xb2, 0xe5,
+	0xd2, 0xc6, 0xb4, 0x57, 0x47, 0xe4, 0x32, 0x16,
+	0x6d, 0xa9, 0xae, 0x64, 0xe6, 0x2d, 0x8d, 0xc5,
+	0x8d, 0x50, 0x8e, 0xe8, 0x1a, 0x22, 0x34, 0x2a,
+	0xd9, 0xeb, 0x51, 0x90, 0x4a, 0xb1, 0x41, 0x7d,
+	0x64, 0xf9, 0xb9, 0x0d, 0xf6, 0x23, 0x33, 0xb0,
+	0x33, 0xf4, 0xf7, 0x3f, 0x27, 0x84, 0xc6, 0x0f,
+	0x54, 0xa5, 0xc0, 0x2e, 0xec, 0x0b, 0x3a, 0x48,
+	0x6e, 0x80, 0x35, 0x81, 0x43, 0x9b, 0x90, 0xb1,
+	0xd0, 0x2b, 0xea, 0x21, 0xdc, 0xda, 0x5b, 0x09,
+	0xf4, 0xcc, 0x10, 0xb4, 0xc7, 0xfe, 0x79, 0x51,
+	0xc3, 0xc5, 0xac, 0x88, 0x74, 0x84, 0x0b, 0x4b,
+	0xca, 0x79, 0x16, 0x29, 0xfb, 0x69, 0x54, 0xdf,
+	0x41, 0x7e, 0xe9, 0xc7, 0x8e, 0xea, 0xa5, 0xfe,
+	0xfc, 0x76, 0x0e, 0x90, 0xc4, 0x92, 0x38, 0xad,
+	0x7b, 0x48, 0xe6, 0x6e, 0xf7, 0x21, 0xfd, 0x4e,
+	0x93, 0x0a, 0x7b, 0x41, 0x83, 0x68, 0xfb, 0x57,
+	0x51, 0x76, 0x34, 0xa9, 0x6c, 0x00, 0xaa, 0x4f,
+	0x66, 0x65, 0x98, 0x4a, 0x4f, 0xa3, 0xa0, 0xef,
+	0x69, 0x3f, 0xe3, 0x1c, 0x92, 0x8c, 0xfd, 0xd8,
+	0xe8, 0xde, 0x7c, 0x7f, 0x3e, 0x84, 0x8e, 0x69,
+	0x3c, 0xf1, 0xf2, 0x05, 0x46, 0xdc, 0x2f, 0x9d,
+	0x5e, 0x6e, 0x4c, 0xfb, 0xb5, 0x99, 0x2a, 0x59,
+	0x63, 0xc1, 0x34, 0xbc, 0x57, 0xc0, 0x0d, 0xb9,
+	0x61, 0x25, 0xf3, 0x33, 0x23, 0x51, 0xb6, 0x0d,
+	0x07, 0xa6, 0xab, 0x94, 0x4a, 0xb7, 0x2a, 0xea,
+	0xee, 0xac, 0xa3, 0xc3, 0x04, 0x8b, 0x0e, 0x56,
+	0xfe, 0x44, 0xa7, 0x39, 0xe2, 0xed, 0xed, 0xb4,
+	0x22, 0x2b, 0xac, 0x12, 0x32, 0x28, 0x91, 0xd8,
+	0xa5, 0xab, 0xff, 0x5f, 0xe0, 0x4b, 0xda, 0x78,
+	0x17, 0xda, 0xf1, 0x01, 0x5b, 0xcd, 0xe2, 0x5f,
+	0x50, 0x45, 0x73, 0x2b, 0xe4, 0x76, 0x77, 0xf4,
+	0x64, 0x1d, 0x43, 0xfb, 0x84, 0x7a, 0xea, 0x91,
+	0xae, 0xf9, 0x9e, 0xb7, 0xb4, 0xb0, 0x91, 0x5f,
+	0x16, 0x35, 0x9a, 0x11, 0xb8, 0xc7, 0xc1, 0x8c,
+	0xc6, 0x10, 0x8d, 0x2f, 0x63, 0x4a, 0xa7, 0x57,
+	0x3a, 0x51, 0xd6, 0x32, 0x2d, 0x64, 0x72, 0xd4,
+	0x66, 0xdc, 0x10, 0xa6, 0x67, 0xd6, 0x04, 0x23,
+	0x9d, 0x0a, 0x11, 0x77, 0xdd, 0x37, 0x94, 0x17,
+	0x3c, 0xbf, 0x8b, 0x65, 0xb0, 0x2e, 0x5e, 0x66,
+	0x47, 0x64, 0xac, 0xdd, 0xf0, 0x84, 0xfd, 0x39,
+	0xfa, 0x15, 0x5d, 0xef, 0xae, 0xca, 0xc1, 0x36,
+	0xa7, 0x5c, 0xbf, 0xc7, 0x08, 0xc2, 0x66, 0x00,
+	0x74, 0x74, 0x4e, 0x27, 0x3f, 0x55, 0x8a, 0xb7,
+	0x38, 0x66, 0x83, 0x6d, 0xcf, 0x99, 0x9e, 0x60,
+	0x8f, 0xdd, 0x2e, 0x62, 0x22, 0x0e, 0xef, 0x0c,
+	0x98, 0xa7, 0x85, 0x74, 0x3b, 0x9d, 0xec, 0x9e,
+	0xa9, 0x19, 0x72, 0xa5, 0x7f, 0x2c, 0x39, 0xb7,
+	0x7d, 0xb7, 0xf1, 0x12, 0x65, 0x27, 0x4b, 0x5a,
+	0xde, 0x17, 0xfe, 0xad, 0x44, 0xf3, 0x20, 0x4d,
+	0xfd, 0xe4, 0x1f, 0xb5, 0x81, 0xb0, 0x36, 0x37,
+	0x08, 0x6f, 0xc3, 0x0c, 0xe9, 0x85, 0x98, 0x82,
+	0xa9, 0x62, 0x0c, 0xc4, 0x97, 0xc0, 0x50, 0xc8,
+	0xa7, 0x3c, 0x50, 0x9f, 0x43, 0xb9, 0xcd, 0x5e,
+	0x4d, 0xfa, 0x1c, 0x4b, 0x0b, 0xa9, 0x98, 0x85,
+	0x38, 0x92, 0xac, 0x8d, 0xe4, 0xad, 0x9b, 0x98,
+	0xab, 0xd9, 0x38, 0xac, 0x62, 0x52, 0xa3, 0x22,
+	0x63, 0x0f, 0xbf, 0x95, 0x48, 0xdf, 0x69, 0xe7,
+	0x8b, 0x33, 0xd5, 0xb2, 0xbd, 0x05, 0x49, 0x49,
+	0x9d, 0x57, 0x73, 0x19, 0x33, 0xae, 0xfa, 0x33,
+	0xf1, 0x19, 0xa8, 0x80, 0xce, 0x04, 0x9f, 0xbc,
+	0x1d, 0x65, 0x82, 0x1b, 0xe5, 0x3a, 0x51, 0xc8,
+	0x1c, 0x21, 0xe3, 0x5d, 0xf3, 0x7d, 0x9b, 0x2f,
+	0x2c, 0x1d, 0x4a, 0x7f, 0x9b, 0x68, 0x35, 0xa3,
+	0xb2, 0x50, 0xf7, 0x62, 0x79, 0xcd, 0xf4, 0x98,
+	0x4f, 0xe5, 0x63, 0x7c, 0x3e, 0x45, 0x31, 0x8c,
+	0x16, 0xa0, 0x12, 0xc8, 0x58, 0xce, 0x39, 0xa6,
+	0xbc, 0x54, 0xdb, 0xc5, 0xe0, 0xd5, 0xba, 0xbc,
+	0xb9, 0x04, 0xf4, 0x8d, 0xe8, 0x2f, 0x15, 0x9d,
+};
 
-}
-#endif
-
-static void bytereverse(unsigned char *buf, size_t len)
+/* 100 test cases */
+static struct crc_test {
+	u32 crc;	/* random starting crc */
+	u32 start;	/* random 6 bit offset in buf */
+	u32 length;	/* random 11 bit length of test */
+	u32 crc_le;	/* expected crc32_le result */
+	u32 crc_be;	/* expected crc32_be result */
+	u32 crc32c_le;	/* expected crc32c_le result */
+} test[] =
 {
-	while (len--) {
-		unsigned char x = bitrev8(*buf);
-		*buf++ = x;
-	}
-}
+	{0x674bf11d, 0x00000038, 0x00000542, 0x0af6d466, 0xd8b6e4c1,
+	 0xf6e93d6c},
+	{0x35c672c6, 0x0000003a, 0x000001aa, 0xc6d3dfba, 0x28aaf3ad,
+	 0x0fe92aca},
+	{0x496da28e, 0x00000039, 0x000005af, 0xd933660f, 0x5d57e81f,
+	 0x52e1ebb8},
+	{0x09a9b90e, 0x00000027, 0x000001f8, 0xb45fe007, 0xf45fca9a,
+	 0x0798af9a},
+	{0xdc97e5a9, 0x00000025, 0x000003b6, 0xf81a3562, 0xe0126ba2,
+	 0x18eb3152},
+	{0x47c58900, 0x0000000a, 0x000000b9, 0x8e58eccf, 0xf3afc793,
+	 0xd00d08c7},
+	{0x292561e8, 0x0000000c, 0x00000403, 0xa2ba8aaf, 0x0b797aed,
+	 0x8ba966bc},
+	{0x415037f6, 0x00000003, 0x00000676, 0xa17d52e8, 0x7f0fdf35,
+	 0x11d694a2},
+	{0x3466e707, 0x00000026, 0x00000042, 0x258319be, 0x75c484a2,
+	 0x6ab3208d},
+	{0xafd1281b, 0x00000023, 0x000002ee, 0x4428eaf8, 0x06c7ad10,
+	 0xba4603c5},
+	{0xd3857b18, 0x00000028, 0x000004a2, 0x5c430821, 0xb062b7cb,
+	 0xe6071c6f},
+	{0x1d825a8f, 0x0000002b, 0x0000050b, 0xd2c45f0c, 0xd68634e0,
+	 0x179ec30a},
+	{0x5033e3bc, 0x0000000b, 0x00000078, 0xa3ea4113, 0xac6d31fb,
+	 0x0903beb8},
+	{0x94f1fb5e, 0x0000000f, 0x000003a2, 0xfbfc50b1, 0x3cfe50ed,
+	 0x6a7cb4fa},
+	{0xc9a0fe14, 0x00000009, 0x00000473, 0x5fb61894, 0x87070591,
+	 0xdb535801},
+	{0x88a034b1, 0x0000001c, 0x000005ad, 0xc1b16053, 0x46f95c67,
+	 0x92bed597},
+	{0xf0f72239, 0x00000020, 0x0000026d, 0xa6fa58f3, 0xf8c2c1dd,
+	 0x192a3f1b},
+	{0xcc20a5e3, 0x0000003b, 0x0000067a, 0x7740185a, 0x308b979a,
+	 0xccbaec1a},
+	{0xce589c95, 0x0000002b, 0x00000641, 0xd055e987, 0x40aae25b,
+	 0x7eabae4d},
+	{0x78edc885, 0x00000035, 0x000005be, 0xa39cb14b, 0x035b0d1f,
+	 0x28c72982},
+	{0x9d40a377, 0x0000003b, 0x00000038, 0x1f47ccd2, 0x197fbc9d,
+	 0xc3cd4d18},
+	{0x703d0e01, 0x0000003c, 0x000006f1, 0x88735e7c, 0xfed57c5a,
+	 0xbca8f0e7},
+	{0x776bf505, 0x0000000f, 0x000005b2, 0x5cc4fc01, 0xf32efb97,
+	 0x713f60b3},
+	{0x4a3e7854, 0x00000027, 0x000004b8, 0x8d923c82, 0x0cbfb4a2,
+	 0xebd08fd5},
+	{0x209172dd, 0x0000003b, 0x00000356, 0xb89e9c2b, 0xd7868138,
+	 0x64406c59},
+	{0x3ba4cc5b, 0x0000002f, 0x00000203, 0xe51601a9, 0x5b2a1032,
+	 0x7421890e},
+	{0xfc62f297, 0x00000000, 0x00000079, 0x71a8e1a2, 0x5d88685f,
+	 0xe9347603},
+	{0x64280b8b, 0x00000016, 0x000007ab, 0x0fa7a30c, 0xda3a455f,
+	 0x1bef9060},
+	{0x97dd724b, 0x00000033, 0x000007ad, 0x5788b2f4, 0xd7326d32,
+	 0x34720072},
+	{0x61394b52, 0x00000035, 0x00000571, 0xc66525f1, 0xcabe7fef,
+	 0x48310f59},
+	{0x29b4faff, 0x00000024, 0x0000006e, 0xca13751e, 0x993648e0,
+	 0x783a4213},
+	{0x29bfb1dc, 0x0000000b, 0x00000244, 0x436c43f7, 0x429f7a59,
+	 0x9e8efd41},
+	{0x86ae934b, 0x00000035, 0x00000104, 0x0760ec93, 0x9cf7d0f4,
+	 0xfc3d34a5},
+	{0xc4c1024e, 0x0000002e, 0x000006b1, 0x6516a3ec, 0x19321f9c,
+	 0x17a52ae2},
+	{0x3287a80a, 0x00000026, 0x00000496, 0x0b257eb1, 0x754ebd51,
+	 0x886d935a},
+	{0xa4db423e, 0x00000023, 0x0000045d, 0x9b3a66dc, 0x873e9f11,
+	 0xeaaeaeb2},
+	{0x7a1078df, 0x00000015, 0x0000014a, 0x8c2484c5, 0x6a628659,
+	 0x8e900a4b},
+	{0x6048bd5b, 0x00000006, 0x0000006a, 0x897e3559, 0xac9961af,
+	 0xd74662b1},
+	{0xd8f9ea20, 0x0000003d, 0x00000277, 0x60eb905b, 0xed2aaf99,
+	 0xd26752ba},
+	{0xea5ec3b4, 0x0000002a, 0x000004fe, 0x869965dc, 0x6c1f833b,
+	 0x8b1fcd62},
+	{0x2dfb005d, 0x00000016, 0x00000345, 0x6a3b117e, 0xf05e8521,
+	 0xf54342fe},
+	{0x5a214ade, 0x00000020, 0x000005b6, 0x467f70be, 0xcb22ccd3,
+	 0x5b95b988},
+	{0xf0ab9cca, 0x00000032, 0x00000515, 0xed223df3, 0x7f3ef01d,
+	 0x2e1176be},
+	{0x91b444f9, 0x0000002e, 0x000007f8, 0x84e9a983, 0x5676756f,
+	 0x66120546},
+	{0x1b5d2ddb, 0x0000002e, 0x0000012c, 0xba638c4c, 0x3f42047b,
+	 0xf256a5cc},
+	{0xd824d1bb, 0x0000003a, 0x000007b5, 0x6288653b, 0x3a3ebea0,
+	 0x4af1dd69},
+	{0x0470180c, 0x00000034, 0x000001f0, 0x9d5b80d6, 0x3de08195,
+	 0x56f0a04a},
+	{0xffaa3a3f, 0x00000036, 0x00000299, 0xf3a82ab8, 0x53e0c13d,
+	 0x74f6b6b2},
+	{0x6406cfeb, 0x00000023, 0x00000600, 0xa920b8e8, 0xe4e2acf4,
+	 0x085951fd},
+	{0xb24aaa38, 0x0000003e, 0x000004a1, 0x657cc328, 0x5077b2c3,
+	 0xc65387eb},
+	{0x58b2ab7c, 0x00000039, 0x000002b4, 0x3a17ee7e, 0x9dcb3643,
+	 0x1ca9257b},
+	{0x3db85970, 0x00000006, 0x000002b6, 0x95268b59, 0xb9812c10,
+	 0xfd196d76},
+	{0x857830c5, 0x00000003, 0x00000590, 0x4ef439d5, 0xf042161d,
+	 0x5ef88339},
+	{0xe1fcd978, 0x0000003e, 0x000007d8, 0xae8d8699, 0xce0a1ef5,
+	 0x2c3714d9},
+	{0xb982a768, 0x00000016, 0x000006e0, 0x62fad3df, 0x5f8a067b,
+	 0x58576548},
+	{0x1d581ce8, 0x0000001e, 0x0000058b, 0xf0f5da53, 0x26e39eee,
+	 0xfd7c57de},
+	{0x2456719b, 0x00000025, 0x00000503, 0x4296ac64, 0xd50e4c14,
+	 0xd5fedd59},
+	{0xfae6d8f2, 0x00000000, 0x0000055d, 0x057fdf2e, 0x2a31391a,
+	 0x1cc3b17b},
+	{0xcba828e3, 0x00000039, 0x000002ce, 0xe3f22351, 0x8f00877b,
+	 0x270eed73},
+	{0x13d25952, 0x0000000a, 0x0000072d, 0x76d4b4cc, 0x5eb67ec3,
+	 0x91ecbb11},
+	{0x0342be3f, 0x00000015, 0x00000599, 0xec75d9f1, 0x9d4d2826,
+	 0x05ed8d0c},
+	{0xeaa344e0, 0x00000014, 0x000004d8, 0x72a4c981, 0x2064ea06,
+	 0x0b09ad5b},
+	{0xbbb52021, 0x0000003b, 0x00000272, 0x04af99fc, 0xaf042d35,
+	 0xf8d511fb},
+	{0xb66384dc, 0x0000001d, 0x000007fc, 0xd7629116, 0x782bd801,
+	 0x5ad832cc},
+	{0x616c01b6, 0x00000022, 0x000002c8, 0x5b1dab30, 0x783ce7d2,
+	 0x1214d196},
+	{0xce2bdaad, 0x00000016, 0x0000062a, 0x932535c8, 0x3f02926d,
+	 0x5747218a},
+	{0x00fe84d7, 0x00000005, 0x00000205, 0x850e50aa, 0x753d649c,
+	 0xde8f14de},
+	{0xbebdcb4c, 0x00000006, 0x0000055d, 0xbeaa37a2, 0x2d8c9eba,
+	 0x3563b7b9},
+	{0xd8b1a02a, 0x00000010, 0x00000387, 0x5017d2fc, 0x503541a5,
+	 0x071475d0},
+	{0x3b96cad2, 0x00000036, 0x00000347, 0x1d2372ae, 0x926cd90b,
+	 0x54c79d60},
+	{0xc94c1ed7, 0x00000005, 0x0000038b, 0x9e9fdb22, 0x144a9178,
+	 0x4c53eee6},
+	{0x1aad454e, 0x00000025, 0x000002b2, 0xc3f6315c, 0x5c7a35b3,
+	 0x10137a3c},
+	{0xa4fec9a6, 0x00000000, 0x000006d6, 0x90be5080, 0xa4107605,
+	 0xaa9d6c73},
+	{0x1bbe71e2, 0x0000001f, 0x000002fd, 0x4e504c3b, 0x284ccaf1,
+	 0xb63d23e7},
+	{0x4201c7e4, 0x00000002, 0x000002b7, 0x7822e3f9, 0x0cc912a9,
+	 0x7f53e9cf},
+	{0x23fddc96, 0x00000003, 0x00000627, 0x8a385125, 0x07767e78,
+	 0x13c1cd83},
+	{0xd82ba25c, 0x00000016, 0x0000063e, 0x98e4148a, 0x283330c9,
+	 0x49ff5867},
+	{0x786f2032, 0x0000002d, 0x0000060f, 0xf201600a, 0xf561bfcd,
+	 0x8467f211},
+	{0xfebe4e1f, 0x0000002a, 0x000004f2, 0x95e51961, 0xfd80dcab,
+	 0x3f9683b2},
+	{0x1a6e0a39, 0x00000008, 0x00000672, 0x8af6c2a5, 0x78dd84cb,
+	 0x76a3f874},
+	{0x56000ab8, 0x0000000e, 0x000000e5, 0x36bacb8f, 0x22ee1f77,
+	 0x863b702f},
+	{0x4717fe0c, 0x00000000, 0x000006ec, 0x8439f342, 0x5c8e03da,
+	 0xdc6c58ff},
+	{0xd5d5d68e, 0x0000003c, 0x000003a3, 0x46fff083, 0x177d1b39,
+	 0x0622cc95},
+	{0xc25dd6c6, 0x00000024, 0x000006c0, 0x5ceb8eb4, 0x892b0d16,
+	 0xe85605cd},
+	{0xe9b11300, 0x00000023, 0x00000683, 0x07a5d59a, 0x6c6a3208,
+	 0x31da5f06},
+	{0x95cd285e, 0x00000001, 0x00000047, 0x7b3a4368, 0x0202c07e,
+	 0xa1f2e784},
+	{0xd9245a25, 0x0000001e, 0x000003a6, 0xd33c1841, 0x1936c0d5,
+	 0xb07cc616},
+	{0x103279db, 0x00000006, 0x0000039b, 0xca09b8a0, 0x77d62892,
+	 0xbf943b6c},
+	{0x1cba3172, 0x00000027, 0x000001c8, 0xcb377194, 0xebe682db,
+	 0x2c01af1c},
+	{0x8f613739, 0x0000000c, 0x000001df, 0xb4b0bc87, 0x7710bd43,
+	 0x0fe5f56d},
+	{0x1c6aa90d, 0x0000001b, 0x0000053c, 0x70559245, 0xda7894ac,
+	 0xf8943b2d},
+	{0xaabe5b93, 0x0000003d, 0x00000715, 0xcdbf42fa, 0x0c3b99e7,
+	 0xe4d89272},
+	{0xf15dd038, 0x00000006, 0x000006db, 0x6e104aea, 0x8d5967f2,
+	 0x7c2f6bbb},
+	{0x584dd49c, 0x00000020, 0x000007bc, 0x36b6cfd6, 0xad4e23b2,
+	 0xabbf388b},
+	{0x5d8c9506, 0x00000020, 0x00000470, 0x4c62378e, 0x31d92640,
+	 0x1dca1f4e},
+	{0xb80d17b0, 0x00000032, 0x00000346, 0x22a5bb88, 0x9a7ec89f,
+	 0x5c170e23},
+	{0xdaf0592e, 0x00000023, 0x000007b0, 0x3cab3f99, 0x9b1fdd99,
+	 0xc0e9d672},
+	{0x4793cc85, 0x0000000d, 0x00000706, 0xe82e04f6, 0xed3db6b7,
+	 0xc18bdc86},
+	{0x82ebf64e, 0x00000009, 0x000007c3, 0x69d590a9, 0x9efa8499,
+	 0xa874fcdd},
+	{0xb18a0319, 0x00000026, 0x000007db, 0x1cf98dcc, 0x8fa9ad6a,
+	 0x9dc0bb48},
+};
 
-static void random_garbage(unsigned char *buf, size_t len)
+#include <linux/time.h>
+
+static int __init crc32c_test(void)
 {
-	while (len--)
-		*buf++ = (unsigned char) random();
-}
+	int i;
+	int errors = 0;
+	int bytes = 0;
+	struct timespec start, stop;
+	u64 nsec;
+	unsigned long flags;
 
-#if 0				/* Not used at present */
-static void store_le(u32 x, unsigned char *buf)
-{
-	buf[0] = (unsigned char) x;
-	buf[1] = (unsigned char) (x >> 8);
-	buf[2] = (unsigned char) (x >> 16);
-	buf[3] = (unsigned char) (x >> 24);
-}
-#endif
+	/* keep static to prevent cache warming code from
+	 * getting eliminated by the compiler */
+	static u32 crc;
 
-static void store_be(u32 x, unsigned char *buf)
-{
-	buf[0] = (unsigned char) (x >> 24);
-	buf[1] = (unsigned char) (x >> 16);
-	buf[2] = (unsigned char) (x >> 8);
-	buf[3] = (unsigned char) x;
-}
+	/* pre-warm the cache */
+	for (i = 0; i < 100; i++) {
+		bytes += 2*test[i].length;
 
-/*
- * This checks that CRC(buf + CRC(buf)) = 0, and that
- * CRC commutes with bit-reversal.  This has the side effect
- * of bytewise bit-reversing the input buffer, and returns
- * the CRC of the reversed buffer.
- */
-static u32 test_step(u32 init, unsigned char *buf, size_t len)
-{
-	u32 crc1, crc2;
-	size_t i;
-
-	crc1 = crc32_be(init, buf, len);
-	store_be(crc1, buf + len);
-	crc2 = crc32_be(init, buf, len + 4);
-	if (crc2)
-		printf("\nCRC cancellation fail: 0x%08x should be 0\n",
-		       crc2);
-
-	for (i = 0; i <= len + 4; i++) {
-		crc2 = crc32_be(init, buf, i);
-		crc2 = crc32_be(crc2, buf + i, len + 4 - i);
-		if (crc2)
-			printf("\nCRC split fail: 0x%08x\n", crc2);
+		crc ^= __crc32c_le(test[i].crc, test_buf +
+		    test[i].start, test[i].length);
 	}
 
-	/* Now swap it around for the other test */
+	/* reduce OS noise */
+	local_irq_save(flags);
+	local_irq_disable();
 
-	bytereverse(buf, len + 4);
-	init = bitrev32(init);
-	crc2 = bitrev32(crc1);
-	if (crc1 != bitrev32(crc2))
-		printf("\nBit reversal fail: 0x%08x -> 0x%08x -> 0x%08x\n",
-		       crc1, crc2, bitrev32(crc2));
-	crc1 = crc32_le(init, buf, len);
-	if (crc1 != crc2)
-		printf("\nCRC endianness fail: 0x%08x != 0x%08x\n", crc1,
-		       crc2);
-	crc2 = crc32_le(init, buf, len + 4);
-	if (crc2)
-		printf("\nCRC cancellation fail: 0x%08x should be 0\n",
-		       crc2);
+	getnstimeofday(&start);
+	for (i = 0; i < 100; i++) {
+		if (test[i].crc32c_le != __crc32c_le(test[i].crc, test_buf +
+		    test[i].start, test[i].length))
+			errors++;
+	}
+	getnstimeofday(&stop);
 
-	for (i = 0; i <= len + 4; i++) {
-		crc2 = crc32_le(init, buf, i);
-		crc2 = crc32_le(crc2, buf + i, len + 4 - i);
-		if (crc2)
-			printf("\nCRC split fail: 0x%08x\n", crc2);
+	local_irq_restore(flags);
+	local_irq_enable();
+
+	nsec = stop.tv_nsec - start.tv_nsec +
+		1000000000 * (stop.tv_sec - start.tv_sec);
+
+	pr_info("crc32c: CRC_LE_BITS = %d\n", CRC_LE_BITS);
+
+	if (errors)
+		pr_warn("crc32c: %d self tests failed\n", errors);
+	else {
+		pr_info("crc32c: self tests passed, processed %d bytes in %lld nsec\n",
+			bytes, nsec);
 	}
 
-	return crc1;
-}
-
-#define SIZE 64
-#define INIT1 0
-#define INIT2 0
-
-int main(void)
-{
-	unsigned char buf1[SIZE + 4];
-	unsigned char buf2[SIZE + 4];
-	unsigned char buf3[SIZE + 4];
-	int i, j;
-	u32 crc1, crc2, crc3;
-
-	for (i = 0; i <= SIZE; i++) {
-		printf("\rTesting length %d...", i);
-		fflush(stdout);
-		random_garbage(buf1, i);
-		random_garbage(buf2, i);
-		for (j = 0; j < i; j++)
-			buf3[j] = buf1[j] ^ buf2[j];
-
-		crc1 = test_step(INIT1, buf1, i);
-		crc2 = test_step(INIT2, buf2, i);
-		/* Now check that CRC(buf1 ^ buf2) = CRC(buf1) ^ CRC(buf2) */
-		crc3 = test_step(INIT1 ^ INIT2, buf3, i);
-		if (crc3 != (crc1 ^ crc2))
-			printf("CRC XOR fail: 0x%08x != 0x%08x ^ 0x%08x\n",
-			       crc3, crc1, crc2);
-	}
-	printf("\nAll test complete.  No failures expected.\n");
 	return 0;
 }
 
-#endif				/* UNITTEST */
+static int __init crc32_test(void)
+{
+	int i;
+	int errors = 0;
+	int bytes = 0;
+	struct timespec start, stop;
+	u64 nsec;
+	unsigned long flags;
+
+	/* keep static to prevent cache warming code from
+	 * getting eliminated by the compiler */
+	static u32 crc;
+
+	/* pre-warm the cache */
+	for (i = 0; i < 100; i++) {
+		bytes += 2*test[i].length;
+
+		crc ^= crc32_le(test[i].crc, test_buf +
+		    test[i].start, test[i].length);
+
+		crc ^= crc32_be(test[i].crc, test_buf +
+		    test[i].start, test[i].length);
+	}
+
+	/* reduce OS noise */
+	local_irq_save(flags);
+	local_irq_disable();
+
+	getnstimeofday(&start);
+	for (i = 0; i < 100; i++) {
+		if (test[i].crc_le != crc32_le(test[i].crc, test_buf +
+		    test[i].start, test[i].length))
+			errors++;
+
+		if (test[i].crc_be != crc32_be(test[i].crc, test_buf +
+		    test[i].start, test[i].length))
+			errors++;
+	}
+	getnstimeofday(&stop);
+
+	local_irq_restore(flags);
+	local_irq_enable();
+
+	nsec = stop.tv_nsec - start.tv_nsec +
+		1000000000 * (stop.tv_sec - start.tv_sec);
+
+	pr_info("crc32: CRC_LE_BITS = %d, CRC_BE BITS = %d\n",
+		 CRC_LE_BITS, CRC_BE_BITS);
+
+	if (errors)
+		pr_warn("crc32: %d self tests failed\n", errors);
+	else {
+		pr_info("crc32: self tests passed, processed %d bytes in %lld nsec\n",
+			bytes, nsec);
+	}
+
+	return 0;
+}
+
+static int __init crc32test_init(void)
+{
+	crc32_test();
+	crc32c_test();
+	return 0;
+}
+
+static void __exit crc32_exit(void)
+{
+}
+
+module_init(crc32test_init);
+module_exit(crc32_exit);
+#endif /* CONFIG_CRC32_SELFTEST */
diff --git a/lib/crc32defs.h b/lib/crc32defs.h
index 9b6773d..64cba2c 100644
--- a/lib/crc32defs.h
+++ b/lib/crc32defs.h
@@ -6,27 +6,67 @@
 #define CRCPOLY_LE 0xedb88320
 #define CRCPOLY_BE 0x04c11db7
 
-/* How many bits at a time to use.  Requires a table of 4<<CRC_xx_BITS bytes. */
-/* For less performance-sensitive, use 4 */
-#ifndef CRC_LE_BITS 
+/*
+ * This is the CRC32c polynomial, as outlined by Castagnoli.
+ * x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+x^11+x^10+x^9+
+ * x^8+x^6+x^0
+ */
+#define CRC32C_POLY_LE 0x82F63B78
+
+/* Try to choose an implementation variant via Kconfig */
+#ifdef CONFIG_CRC32_SLICEBY8
+# define CRC_LE_BITS 64
+# define CRC_BE_BITS 64
+#endif
+#ifdef CONFIG_CRC32_SLICEBY4
+# define CRC_LE_BITS 32
+# define CRC_BE_BITS 32
+#endif
+#ifdef CONFIG_CRC32_SARWATE
 # define CRC_LE_BITS 8
+# define CRC_BE_BITS 8
+#endif
+#ifdef CONFIG_CRC32_BIT
+# define CRC_LE_BITS 1
+# define CRC_BE_BITS 1
+#endif
+
+/*
+ * How many bits at a time to use.  Valid values are 1, 2, 4, 8, 32 and 64.
+ * For less performance-sensitive, use 4 or 8 to save table size.
+ * For larger systems choose same as CPU architecture as default.
+ * This works well on X86_64, SPARC64 systems. This may require some
+ * elaboration after experiments with other architectures.
+ */
+#ifndef CRC_LE_BITS
+#  ifdef CONFIG_64BIT
+#  define CRC_LE_BITS 64
+#  else
+#  define CRC_LE_BITS 32
+#  endif
 #endif
 #ifndef CRC_BE_BITS
-# define CRC_BE_BITS 8
+#  ifdef CONFIG_64BIT
+#  define CRC_BE_BITS 64
+#  else
+#  define CRC_BE_BITS 32
+#  endif
 #endif
 
 /*
  * Little-endian CRC computation.  Used with serial bit streams sent
  * lsbit-first.  Be sure to use cpu_to_le32() to append the computed CRC.
  */
-#if CRC_LE_BITS > 8 || CRC_LE_BITS < 1 || CRC_LE_BITS & CRC_LE_BITS-1
-# error CRC_LE_BITS must be a power of 2 between 1 and 8
+#if CRC_LE_BITS > 64 || CRC_LE_BITS < 1 || CRC_LE_BITS == 16 || \
+	CRC_LE_BITS & CRC_LE_BITS-1
+# error "CRC_LE_BITS must be one of {1, 2, 4, 8, 32, 64}"
 #endif
 
 /*
  * Big-endian CRC computation.  Used with serial bit streams sent
  * msbit-first.  Be sure to use cpu_to_be32() to append the computed CRC.
  */
-#if CRC_BE_BITS > 8 || CRC_BE_BITS < 1 || CRC_BE_BITS & CRC_BE_BITS-1
-# error CRC_BE_BITS must be a power of 2 between 1 and 8
+#if CRC_BE_BITS > 64 || CRC_BE_BITS < 1 || CRC_BE_BITS == 16 || \
+	CRC_BE_BITS & CRC_BE_BITS-1
+# error "CRC_BE_BITS must be one of {1, 2, 4, 8, 32, 64}"
 #endif
diff --git a/lib/ctype.c b/lib/ctype.c
index 26baa62..c646df9 100644
--- a/lib/ctype.c
+++ b/lib/ctype.c
@@ -5,7 +5,8 @@
  */
 
 #include <linux/ctype.h>
-#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/export.h>
 
 const unsigned char _ctype[] = {
 _C,_C,_C,_C,_C,_C,_C,_C,				/* 0-7 */
diff --git a/lib/debug_locks.c b/lib/debug_locks.c
index b1c1773..f2fa60c 100644
--- a/lib/debug_locks.c
+++ b/lib/debug_locks.c
@@ -10,7 +10,7 @@
  */
 #include <linux/rwsem.h>
 #include <linux/mutex.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/debug_locks.h>
 
diff --git a/lib/dec_and_lock.c b/lib/dec_and_lock.c
index b525772..e262785 100644
--- a/lib/dec_and_lock.c
+++ b/lib/dec_and_lock.c
@@ -1,4 +1,4 @@
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/atomic.h>
 
diff --git a/lib/devres.c b/lib/devres.c
index 9676617..80b9c76 100644
--- a/lib/devres.c
+++ b/lib/devres.c
@@ -1,7 +1,7 @@
 #include <linux/pci.h>
 #include <linux/io.h>
 #include <linux/gfp.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 void devm_ioremap_release(struct device *dev, void *res)
 {
diff --git a/lib/div64.c b/lib/div64.c
index 5b49191..3ea2490 100644
--- a/lib/div64.c
+++ b/lib/div64.c
@@ -16,7 +16,8 @@
  * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
 #include <linux/math64.h>
 
 /* Not needed on 64bit architectures */
diff --git a/lib/dump_stack.c b/lib/dump_stack.c
index 53bff4c..42f4f55 100644
--- a/lib/dump_stack.c
+++ b/lib/dump_stack.c
@@ -4,7 +4,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 void dump_stack(void)
 {
diff --git a/lib/fault-inject.c b/lib/fault-inject.c
index b4801f5..6805453 100644
--- a/lib/fault-inject.c
+++ b/lib/fault-inject.c
@@ -5,7 +5,7 @@
 #include <linux/stat.h>
 #include <linux/types.h>
 #include <linux/fs.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/stacktrace.h>
 #include <linux/fault-inject.h>
diff --git a/lib/find_last_bit.c b/lib/find_last_bit.c
index d903959..91ca09f 100644
--- a/lib/find_last_bit.c
+++ b/lib/find_last_bit.c
@@ -11,7 +11,7 @@
  */
 
 #include <linux/bitops.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <asm/types.h>
 #include <asm/byteorder.h>
 
diff --git a/lib/find_next_bit.c b/lib/find_next_bit.c
index 4bd75a7..0cbfc0b 100644
--- a/lib/find_next_bit.c
+++ b/lib/find_next_bit.c
@@ -10,7 +10,7 @@
  */
 
 #include <linux/bitops.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <asm/types.h>
 #include <asm/byteorder.h>
 
diff --git a/lib/flex_array.c b/lib/flex_array.c
index 9b8b894..6948a66 100644
--- a/lib/flex_array.c
+++ b/lib/flex_array.c
@@ -23,7 +23,7 @@
 #include <linux/flex_array.h>
 #include <linux/slab.h>
 #include <linux/stddef.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/reciprocal_div.h>
 
 struct flex_array_part {
diff --git a/lib/gcd.c b/lib/gcd.c
index f879033..cce4f3c 100644
--- a/lib/gcd.c
+++ b/lib/gcd.c
@@ -1,6 +1,6 @@
 #include <linux/kernel.h>
 #include <linux/gcd.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 /* Greatest common divisor */
 unsigned long gcd(unsigned long a, unsigned long b)
diff --git a/lib/gen_crc32table.c b/lib/gen_crc32table.c
index 85d0e41..8f8d543 100644
--- a/lib/gen_crc32table.c
+++ b/lib/gen_crc32table.c
@@ -1,14 +1,29 @@
 #include <stdio.h>
+#include "../include/generated/autoconf.h"
 #include "crc32defs.h"
 #include <inttypes.h>
 
 #define ENTRIES_PER_LINE 4
 
-#define LE_TABLE_SIZE (1 << CRC_LE_BITS)
-#define BE_TABLE_SIZE (1 << CRC_BE_BITS)
+#if CRC_LE_BITS > 8
+# define LE_TABLE_ROWS (CRC_LE_BITS/8)
+# define LE_TABLE_SIZE 256
+#else
+# define LE_TABLE_ROWS 1
+# define LE_TABLE_SIZE (1 << CRC_LE_BITS)
+#endif
 
-static uint32_t crc32table_le[4][LE_TABLE_SIZE];
-static uint32_t crc32table_be[4][BE_TABLE_SIZE];
+#if CRC_BE_BITS > 8
+# define BE_TABLE_ROWS (CRC_BE_BITS/8)
+# define BE_TABLE_SIZE 256
+#else
+# define BE_TABLE_ROWS 1
+# define BE_TABLE_SIZE (1 << CRC_BE_BITS)
+#endif
+
+static uint32_t crc32table_le[LE_TABLE_ROWS][256];
+static uint32_t crc32table_be[BE_TABLE_ROWS][256];
+static uint32_t crc32ctable_le[LE_TABLE_ROWS][256];
 
 /**
  * crc32init_le() - allocate and initialize LE table data
@@ -17,27 +32,38 @@
  * fact that crctable[i^j] = crctable[i] ^ crctable[j].
  *
  */
-static void crc32init_le(void)
+static void crc32init_le_generic(const uint32_t polynomial,
+				 uint32_t (*tab)[256])
 {
 	unsigned i, j;
 	uint32_t crc = 1;
 
-	crc32table_le[0][0] = 0;
+	tab[0][0] = 0;
 
-	for (i = 1 << (CRC_LE_BITS - 1); i; i >>= 1) {
-		crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+	for (i = LE_TABLE_SIZE >> 1; i; i >>= 1) {
+		crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0);
 		for (j = 0; j < LE_TABLE_SIZE; j += 2 * i)
-			crc32table_le[0][i + j] = crc ^ crc32table_le[0][j];
+			tab[0][i + j] = crc ^ tab[0][j];
 	}
 	for (i = 0; i < LE_TABLE_SIZE; i++) {
-		crc = crc32table_le[0][i];
-		for (j = 1; j < 4; j++) {
-			crc = crc32table_le[0][crc & 0xff] ^ (crc >> 8);
-			crc32table_le[j][i] = crc;
+		crc = tab[0][i];
+		for (j = 1; j < LE_TABLE_ROWS; j++) {
+			crc = tab[0][crc & 0xff] ^ (crc >> 8);
+			tab[j][i] = crc;
 		}
 	}
 }
 
+static void crc32init_le(void)
+{
+	crc32init_le_generic(CRCPOLY_LE, crc32table_le);
+}
+
+static void crc32cinit_le(void)
+{
+	crc32init_le_generic(CRC32C_POLY_LE, crc32ctable_le);
+}
+
 /**
  * crc32init_be() - allocate and initialize BE table data
  */
@@ -55,18 +81,18 @@
 	}
 	for (i = 0; i < BE_TABLE_SIZE; i++) {
 		crc = crc32table_be[0][i];
-		for (j = 1; j < 4; j++) {
+		for (j = 1; j < BE_TABLE_ROWS; j++) {
 			crc = crc32table_be[0][(crc >> 24) & 0xff] ^ (crc << 8);
 			crc32table_be[j][i] = crc;
 		}
 	}
 }
 
-static void output_table(uint32_t table[4][256], int len, char *trans)
+static void output_table(uint32_t (*table)[256], int rows, int len, char *trans)
 {
 	int i, j;
 
-	for (j = 0 ; j < 4; j++) {
+	for (j = 0 ; j < rows; j++) {
 		printf("{");
 		for (i = 0; i < len - 1; i++) {
 			if (i % ENTRIES_PER_LINE == 0)
@@ -83,15 +109,30 @@
 
 	if (CRC_LE_BITS > 1) {
 		crc32init_le();
-		printf("static const u32 crc32table_le[4][256] = {");
-		output_table(crc32table_le, LE_TABLE_SIZE, "tole");
+		printf("static const u32 __cacheline_aligned "
+		       "crc32table_le[%d][%d] = {",
+		       LE_TABLE_ROWS, LE_TABLE_SIZE);
+		output_table(crc32table_le, LE_TABLE_ROWS,
+			     LE_TABLE_SIZE, "tole");
 		printf("};\n");
 	}
 
 	if (CRC_BE_BITS > 1) {
 		crc32init_be();
-		printf("static const u32 crc32table_be[4][256] = {");
-		output_table(crc32table_be, BE_TABLE_SIZE, "tobe");
+		printf("static const u32 __cacheline_aligned "
+		       "crc32table_be[%d][%d] = {",
+		       BE_TABLE_ROWS, BE_TABLE_SIZE);
+		output_table(crc32table_be, LE_TABLE_ROWS,
+			     BE_TABLE_SIZE, "tobe");
+		printf("};\n");
+	}
+	if (CRC_LE_BITS > 1) {
+		crc32cinit_le();
+		printf("static const u32 __cacheline_aligned "
+		       "crc32ctable_le[%d][%d] = {",
+		       LE_TABLE_ROWS, LE_TABLE_SIZE);
+		output_table(crc32ctable_le, LE_TABLE_ROWS,
+			     LE_TABLE_SIZE, "tole");
 		printf("};\n");
 	}
 
diff --git a/lib/genalloc.c b/lib/genalloc.c
index f352cc4..6bc04aa 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -29,7 +29,7 @@
  */
 
 #include <linux/slab.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/bitmap.h>
 #include <linux/rculist.h>
 #include <linux/interrupt.h>
diff --git a/lib/halfmd4.c b/lib/halfmd4.c
index e11db26..66d0ee8 100644
--- a/lib/halfmd4.c
+++ b/lib/halfmd4.c
@@ -1,5 +1,5 @@
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/cryptohash.h>
 
 /* F, G and H are basic MD4 functions: selection, majority, parity */
diff --git a/lib/hexdump.c b/lib/hexdump.c
index 51d5ae2..6540d65 100644
--- a/lib/hexdump.c
+++ b/lib/hexdump.c
@@ -10,7 +10,7 @@
 #include <linux/types.h>
 #include <linux/ctype.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 const char hex_asc[] = "0123456789abcdef";
 EXPORT_SYMBOL(hex_asc);
diff --git a/lib/hweight.c b/lib/hweight.c
index 3c79d50..b7d81ba 100644
--- a/lib/hweight.c
+++ b/lib/hweight.c
@@ -1,4 +1,4 @@
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/bitops.h>
 #include <asm/types.h>
 
diff --git a/lib/idr.c b/lib/idr.c
index ed055b2..4046e29 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -29,7 +29,7 @@
 #ifndef TEST                        // to test in user space...
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #endif
 #include <linux/err.h>
 #include <linux/string.h>
@@ -595,8 +595,10 @@
  * Returns pointer to registered object with id, which is next number to
  * given id. After being looked up, *@nextidp will be updated for the next
  * iteration.
+ *
+ * This function can be called under rcu_read_lock(), given that the leaf
+ * pointers lifetimes are correctly managed.
  */
-
 void *idr_get_next(struct idr *idp, int *nextidp)
 {
 	struct idr_layer *p, *pa[MAX_LEVEL];
@@ -605,11 +607,11 @@
 	int n, max;
 
 	/* find first ent */
-	n = idp->layers * IDR_BITS;
-	max = 1 << n;
 	p = rcu_dereference_raw(idp->top);
 	if (!p)
 		return NULL;
+	n = (p->layer + 1) * IDR_BITS;
+	max = 1 << n;
 
 	while (id < max) {
 		while (n > 0 && p) {
diff --git a/lib/int_sqrt.c b/lib/int_sqrt.c
index fd355a9..fc2eeb7 100644
--- a/lib/int_sqrt.c
+++ b/lib/int_sqrt.c
@@ -1,6 +1,6 @@
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 /**
  * int_sqrt - rough approximation to sqrt
diff --git a/lib/iomap.c b/lib/iomap.c
index ada922a..2c08f36 100644
--- a/lib/iomap.c
+++ b/lib/iomap.c
@@ -6,7 +6,7 @@
 #include <linux/pci.h>
 #include <linux/io.h>
 
-#include <linux/module.h>
+#include <linux/export.h>
 
 /*
  * Read/write from/to an (offsettable) iomem cookie. It might be a PIO
diff --git a/lib/iomap_copy.c b/lib/iomap_copy.c
index 864fc5e..4527e75 100644
--- a/lib/iomap_copy.c
+++ b/lib/iomap_copy.c
@@ -15,7 +15,7 @@
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/io.h>
 
 /**
diff --git a/lib/iommu-helper.c b/lib/iommu-helper.c
index da05331..c27e269 100644
--- a/lib/iommu-helper.c
+++ b/lib/iommu-helper.c
@@ -2,8 +2,9 @@
  * IOMMU helper functions for the free area management
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/bitmap.h>
+#include <linux/bug.h>
 
 int iommu_is_span_boundary(unsigned int index, unsigned int nr,
 			   unsigned long shift,
diff --git a/lib/ioremap.c b/lib/ioremap.c
index da4e2ad..0c9216c 100644
--- a/lib/ioremap.c
+++ b/lib/ioremap.c
@@ -9,7 +9,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <asm/cacheflush.h>
 #include <asm/pgtable.h>
 
diff --git a/lib/irq_regs.c b/lib/irq_regs.c
index 753880a..9c0a1d7 100644
--- a/lib/irq_regs.c
+++ b/lib/irq_regs.c
@@ -8,7 +8,8 @@
  * 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/export.h>
+#include <linux/percpu.h>
 #include <asm/irq_regs.h>
 
 #ifndef ARCH_HAS_OWN_IRQ_REGS
diff --git a/lib/kasprintf.c b/lib/kasprintf.c
index 9c4233b..ae0de80 100644
--- a/lib/kasprintf.c
+++ b/lib/kasprintf.c
@@ -5,7 +5,7 @@
  */
 
 #include <stdarg.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/string.h>
diff --git a/lib/klist.c b/lib/klist.c
index 573d606..0874e41 100644
--- a/lib/klist.c
+++ b/lib/klist.c
@@ -35,7 +35,7 @@
  */
 
 #include <linux/klist.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/sched.h>
 
 /*
diff --git a/lib/kobject.c b/lib/kobject.c
index c33d7a1..21dee7c 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -14,7 +14,7 @@
 
 #include <linux/kobject.h>
 #include <linux/string.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/stat.h>
 #include <linux/slab.h>
 
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 75cbdb5..1a91efa 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -17,7 +17,8 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/kobject.h>
-#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/kmod.h>
 #include <linux/slab.h>
 #include <linux/user_namespace.h>
 #include <linux/socket.h>
diff --git a/lib/kstrtox.c b/lib/kstrtox.c
index b1dd3e7..c3615ea 100644
--- a/lib/kstrtox.c
+++ b/lib/kstrtox.c
@@ -15,7 +15,7 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/math64.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/types.h>
 #include <asm/uaccess.h>
 #include "kstrtox.h"
diff --git a/lib/lcm.c b/lib/lcm.c
index 10b5cfc..b9c8de4 100644
--- a/lib/lcm.c
+++ b/lib/lcm.c
@@ -1,6 +1,6 @@
 #include <linux/kernel.h>
 #include <linux/gcd.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/lcm.h>
 
 /* Lowest common multiple */
diff --git a/lib/list_debug.c b/lib/list_debug.c
index b8029a5..982b850 100644
--- a/lib/list_debug.c
+++ b/lib/list_debug.c
@@ -6,8 +6,10 @@
  * DEBUG_LIST.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/list.h>
+#include <linux/bug.h>
+#include <linux/kernel.h>
 
 /*
  * Insert a new entry between two known consecutive entries.
diff --git a/lib/llist.c b/lib/llist.c
index 700cff7..4a15115 100644
--- a/lib/llist.c
+++ b/lib/llist.c
@@ -23,11 +23,10 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/llist.h>
 
-#include <asm/system.h>
 
 /**
  * llist_add_batch - add several linked entries in batch
diff --git a/lib/locking-selftest.c b/lib/locking-selftest.c
index 507a22f..7aae0f2 100644
--- a/lib/locking-selftest.c
+++ b/lib/locking-selftest.c
@@ -14,7 +14,6 @@
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
-#include <linux/module.h>
 #include <linux/lockdep.h>
 #include <linux/spinlock.h>
 #include <linux/kallsyms.h>
diff --git a/lib/md5.c b/lib/md5.c
index c777180..958a3c1 100644
--- a/lib/md5.c
+++ b/lib/md5.c
@@ -1,5 +1,5 @@
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/cryptohash.h>
 
 #define F1(x, y, z)	(z ^ (x & (y ^ z)))
diff --git a/lib/nlattr.c b/lib/nlattr.c
index a8408b6..4226dfe 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -5,7 +5,7 @@
  * 				Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/jiffies.h>
diff --git a/lib/parser.c b/lib/parser.c
index dcbaaef..c434100 100644
--- a/lib/parser.c
+++ b/lib/parser.c
@@ -6,7 +6,8 @@
  */
 
 #include <linux/ctype.h>
-#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/export.h>
 #include <linux/parser.h>
 #include <linux/slab.h>
 #include <linux/string.h>
diff --git a/lib/plist.c b/lib/plist.c
index a0a4da4..6ab0e52 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -23,6 +23,7 @@
  * information.
  */
 
+#include <linux/bug.h>
 #include <linux/plist.h>
 #include <linux/spinlock.h>
 
diff --git a/lib/prio_tree.c b/lib/prio_tree.c
index ccfd850..8d443af 100644
--- a/lib/prio_tree.c
+++ b/lib/prio_tree.c
@@ -85,6 +85,17 @@
 	return index_bits_to_maxindex[bits - 1];
 }
 
+static void prio_set_parent(struct prio_tree_node *parent,
+			    struct prio_tree_node *child, bool left)
+{
+	if (left)
+		parent->left = child;
+	else
+		parent->right = child;
+
+	child->parent = parent;
+}
+
 /*
  * Extend a priority search tree so that it can store a node with heap_index
  * max_heap_index. In the worst case, this algorithm takes O((log n)^2).
@@ -94,44 +105,31 @@
 static struct prio_tree_node *prio_tree_expand(struct prio_tree_root *root,
 		struct prio_tree_node *node, unsigned long max_heap_index)
 {
-	struct prio_tree_node *first = NULL, *prev, *last = NULL;
+	struct prio_tree_node *prev;
 
 	if (max_heap_index > prio_tree_maxindex(root->index_bits))
 		root->index_bits++;
 
+	prev = node;
+	INIT_PRIO_TREE_NODE(node);
+
 	while (max_heap_index > prio_tree_maxindex(root->index_bits)) {
+		struct prio_tree_node *tmp = root->prio_tree_node;
+
 		root->index_bits++;
 
 		if (prio_tree_empty(root))
 			continue;
 
-		if (first == NULL) {
-			first = root->prio_tree_node;
-			prio_tree_remove(root, root->prio_tree_node);
-			INIT_PRIO_TREE_NODE(first);
-			last = first;
-		} else {
-			prev = last;
-			last = root->prio_tree_node;
-			prio_tree_remove(root, root->prio_tree_node);
-			INIT_PRIO_TREE_NODE(last);
-			prev->left = last;
-			last->parent = prev;
-		}
+		prio_tree_remove(root, root->prio_tree_node);
+		INIT_PRIO_TREE_NODE(tmp);
+
+		prio_set_parent(prev, tmp, true);
+		prev = tmp;
 	}
 
-	INIT_PRIO_TREE_NODE(node);
-
-	if (first) {
-		node->left = first;
-		first->parent = node;
-	} else
-		last = node;
-
-	if (!prio_tree_empty(root)) {
-		last->left = root->prio_tree_node;
-		last->left->parent = last;
-	}
+	if (!prio_tree_empty(root))
+		prio_set_parent(prev, root->prio_tree_node, true);
 
 	root->prio_tree_node = node;
 	return node;
@@ -151,25 +149,15 @@
 		 * We can reduce root->index_bits here. However, it is complex
 		 * and does not help much to improve performance (IMO).
 		 */
-		node->parent = node;
 		root->prio_tree_node = node;
-	} else {
-		node->parent = old->parent;
-		if (old->parent->left == old)
-			old->parent->left = node;
-		else
-			old->parent->right = node;
-	}
+	} else
+		prio_set_parent(old->parent, node, old->parent->left == old);
 
-	if (!prio_tree_left_empty(old)) {
-		node->left = old->left;
-		old->left->parent = node;
-	}
+	if (!prio_tree_left_empty(old))
+		prio_set_parent(node, old->left, true);
 
-	if (!prio_tree_right_empty(old)) {
-		node->right = old->right;
-		old->right->parent = node;
-	}
+	if (!prio_tree_right_empty(old))
+		prio_set_parent(node, old->right, false);
 
 	return old;
 }
@@ -229,16 +217,14 @@
 		if (index & mask) {
 			if (prio_tree_right_empty(cur)) {
 				INIT_PRIO_TREE_NODE(node);
-				cur->right = node;
-				node->parent = cur;
+				prio_set_parent(cur, node, false);
 				return res;
 			} else
 				cur = cur->right;
 		} else {
 			if (prio_tree_left_empty(cur)) {
 				INIT_PRIO_TREE_NODE(node);
-				cur->left = node;
-				node->parent = cur;
+				prio_set_parent(cur, node, true);
 				return res;
 			} else
 				cur = cur->left;
@@ -305,6 +291,40 @@
 		cur = prio_tree_replace(root, cur->parent, cur);
 }
 
+static void iter_walk_down(struct prio_tree_iter *iter)
+{
+	iter->mask >>= 1;
+	if (iter->mask) {
+		if (iter->size_level)
+			iter->size_level++;
+		return;
+	}
+
+	if (iter->size_level) {
+		BUG_ON(!prio_tree_left_empty(iter->cur));
+		BUG_ON(!prio_tree_right_empty(iter->cur));
+		iter->size_level++;
+		iter->mask = ULONG_MAX;
+	} else {
+		iter->size_level = 1;
+		iter->mask = 1UL << (BITS_PER_LONG - 1);
+	}
+}
+
+static void iter_walk_up(struct prio_tree_iter *iter)
+{
+	if (iter->mask == ULONG_MAX)
+		iter->mask = 1UL;
+	else if (iter->size_level == 1)
+		iter->mask = 1UL;
+	else
+		iter->mask <<= 1;
+	if (iter->size_level)
+		iter->size_level--;
+	if (!iter->size_level && (iter->value & iter->mask))
+		iter->value ^= iter->mask;
+}
+
 /*
  * Following functions help to enumerate all prio_tree_nodes in the tree that
  * overlap with the input interval X [radix_index, heap_index]. The enumeration
@@ -323,21 +343,7 @@
 
 	if (iter->r_index <= *h_index) {
 		iter->cur = iter->cur->left;
-		iter->mask >>= 1;
-		if (iter->mask) {
-			if (iter->size_level)
-				iter->size_level++;
-		} else {
-			if (iter->size_level) {
-				BUG_ON(!prio_tree_left_empty(iter->cur));
-				BUG_ON(!prio_tree_right_empty(iter->cur));
-				iter->size_level++;
-				iter->mask = ULONG_MAX;
-			} else {
-				iter->size_level = 1;
-				iter->mask = 1UL << (BITS_PER_LONG - 1);
-			}
-		}
+		iter_walk_down(iter);
 		return iter->cur;
 	}
 
@@ -364,22 +370,7 @@
 
 	if (iter->r_index <= *h_index) {
 		iter->cur = iter->cur->right;
-		iter->mask >>= 1;
-		iter->value = value;
-		if (iter->mask) {
-			if (iter->size_level)
-				iter->size_level++;
-		} else {
-			if (iter->size_level) {
-				BUG_ON(!prio_tree_left_empty(iter->cur));
-				BUG_ON(!prio_tree_right_empty(iter->cur));
-				iter->size_level++;
-				iter->mask = ULONG_MAX;
-			} else {
-				iter->size_level = 1;
-				iter->mask = 1UL << (BITS_PER_LONG - 1);
-			}
-		}
+		iter_walk_down(iter);
 		return iter->cur;
 	}
 
@@ -389,16 +380,7 @@
 static struct prio_tree_node *prio_tree_parent(struct prio_tree_iter *iter)
 {
 	iter->cur = iter->cur->parent;
-	if (iter->mask == ULONG_MAX)
-		iter->mask = 1UL;
-	else if (iter->size_level == 1)
-		iter->mask = 1UL;
-	else
-		iter->mask <<= 1;
-	if (iter->size_level)
-		iter->size_level--;
-	if (!iter->size_level && (iter->value & iter->mask))
-		iter->value ^= iter->mask;
+	iter_walk_up(iter);
 	return iter->cur;
 }
 
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index dc63d08..86516f5 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -3,6 +3,7 @@
  * Portions Copyright (C) 2001 Christoph Hellwig
  * Copyright (C) 2005 SGI, Christoph Lameter
  * Copyright (C) 2006 Nick Piggin
+ * Copyright (C) 2012 Konstantin Khlebnikov
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -22,7 +23,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/radix-tree.h>
 #include <linux/percpu.h>
 #include <linux/slab.h>
@@ -146,6 +147,43 @@
 	}
 	return 0;
 }
+
+/**
+ * radix_tree_find_next_bit - find the next set bit in a memory region
+ *
+ * @addr: The address to base the search on
+ * @size: The bitmap size in bits
+ * @offset: The bitnumber to start searching at
+ *
+ * Unrollable variant of find_next_bit() for constant size arrays.
+ * Tail bits starting from size to roundup(size, BITS_PER_LONG) must be zero.
+ * Returns next bit offset, or size if nothing found.
+ */
+static __always_inline unsigned long
+radix_tree_find_next_bit(const unsigned long *addr,
+			 unsigned long size, unsigned long offset)
+{
+	if (!__builtin_constant_p(size))
+		return find_next_bit(addr, size, offset);
+
+	if (offset < size) {
+		unsigned long tmp;
+
+		addr += offset / BITS_PER_LONG;
+		tmp = *addr >> (offset % BITS_PER_LONG);
+		if (tmp)
+			return __ffs(tmp) + offset;
+		offset = (offset + BITS_PER_LONG) & ~(BITS_PER_LONG - 1);
+		while (offset < size) {
+			tmp = *++addr;
+			if (tmp)
+				return __ffs(tmp) + offset;
+			offset += BITS_PER_LONG;
+		}
+	}
+	return size;
+}
+
 /*
  * This assumes that the caller has performed appropriate preallocation, and
  * that the caller has pinned this thread of control to the current CPU.
@@ -613,6 +651,119 @@
 EXPORT_SYMBOL(radix_tree_tag_get);
 
 /**
+ * radix_tree_next_chunk - find next chunk of slots for iteration
+ *
+ * @root:	radix tree root
+ * @iter:	iterator state
+ * @flags:	RADIX_TREE_ITER_* flags and tag index
+ * Returns:	pointer to chunk first slot, or NULL if iteration is over
+ */
+void **radix_tree_next_chunk(struct radix_tree_root *root,
+			     struct radix_tree_iter *iter, unsigned flags)
+{
+	unsigned shift, tag = flags & RADIX_TREE_ITER_TAG_MASK;
+	struct radix_tree_node *rnode, *node;
+	unsigned long index, offset;
+
+	if ((flags & RADIX_TREE_ITER_TAGGED) && !root_tag_get(root, tag))
+		return NULL;
+
+	/*
+	 * Catch next_index overflow after ~0UL. iter->index never overflows
+	 * during iterating; it can be zero only at the beginning.
+	 * And we cannot overflow iter->next_index in a single step,
+	 * because RADIX_TREE_MAP_SHIFT < BITS_PER_LONG.
+	 */
+	index = iter->next_index;
+	if (!index && iter->index)
+		return NULL;
+
+	rnode = rcu_dereference_raw(root->rnode);
+	if (radix_tree_is_indirect_ptr(rnode)) {
+		rnode = indirect_to_ptr(rnode);
+	} else if (rnode && !index) {
+		/* Single-slot tree */
+		iter->index = 0;
+		iter->next_index = 1;
+		iter->tags = 1;
+		return (void **)&root->rnode;
+	} else
+		return NULL;
+
+restart:
+	shift = (rnode->height - 1) * RADIX_TREE_MAP_SHIFT;
+	offset = index >> shift;
+
+	/* Index outside of the tree */
+	if (offset >= RADIX_TREE_MAP_SIZE)
+		return NULL;
+
+	node = rnode;
+	while (1) {
+		if ((flags & RADIX_TREE_ITER_TAGGED) ?
+				!test_bit(offset, node->tags[tag]) :
+				!node->slots[offset]) {
+			/* Hole detected */
+			if (flags & RADIX_TREE_ITER_CONTIG)
+				return NULL;
+
+			if (flags & RADIX_TREE_ITER_TAGGED)
+				offset = radix_tree_find_next_bit(
+						node->tags[tag],
+						RADIX_TREE_MAP_SIZE,
+						offset + 1);
+			else
+				while (++offset	< RADIX_TREE_MAP_SIZE) {
+					if (node->slots[offset])
+						break;
+				}
+			index &= ~((RADIX_TREE_MAP_SIZE << shift) - 1);
+			index += offset << shift;
+			/* Overflow after ~0UL */
+			if (!index)
+				return NULL;
+			if (offset == RADIX_TREE_MAP_SIZE)
+				goto restart;
+		}
+
+		/* This is leaf-node */
+		if (!shift)
+			break;
+
+		node = rcu_dereference_raw(node->slots[offset]);
+		if (node == NULL)
+			goto restart;
+		shift -= RADIX_TREE_MAP_SHIFT;
+		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
+	}
+
+	/* Update the iterator state */
+	iter->index = index;
+	iter->next_index = (index | RADIX_TREE_MAP_MASK) + 1;
+
+	/* Construct iter->tags bit-mask from node->tags[tag] array */
+	if (flags & RADIX_TREE_ITER_TAGGED) {
+		unsigned tag_long, tag_bit;
+
+		tag_long = offset / BITS_PER_LONG;
+		tag_bit  = offset % BITS_PER_LONG;
+		iter->tags = node->tags[tag][tag_long] >> tag_bit;
+		/* This never happens if RADIX_TREE_TAG_LONGS == 1 */
+		if (tag_long < RADIX_TREE_TAG_LONGS - 1) {
+			/* Pick tags from next element */
+			if (tag_bit)
+				iter->tags |= node->tags[tag][tag_long + 1] <<
+						(BITS_PER_LONG - tag_bit);
+			/* Clip chunk size, here only BITS_PER_LONG tags */
+			iter->next_index = index + BITS_PER_LONG;
+		}
+	}
+
+	return node->slots + offset;
+}
+EXPORT_SYMBOL(radix_tree_next_chunk);
+
+/**
  * radix_tree_range_tag_if_tagged - for each item in given range set given
  *				   tag if item has another tag set
  * @root:		radix tree root
@@ -817,57 +968,6 @@
 }
 EXPORT_SYMBOL(radix_tree_prev_hole);
 
-static unsigned int
-__lookup(struct radix_tree_node *slot, void ***results, unsigned long *indices,
-	unsigned long index, unsigned int max_items, unsigned long *next_index)
-{
-	unsigned int nr_found = 0;
-	unsigned int shift, height;
-	unsigned long i;
-
-	height = slot->height;
-	if (height == 0)
-		goto out;
-	shift = (height-1) * RADIX_TREE_MAP_SHIFT;
-
-	for ( ; height > 1; height--) {
-		i = (index >> shift) & RADIX_TREE_MAP_MASK;
-		for (;;) {
-			if (slot->slots[i] != NULL)
-				break;
-			index &= ~((1UL << shift) - 1);
-			index += 1UL << shift;
-			if (index == 0)
-				goto out;	/* 32-bit wraparound */
-			i++;
-			if (i == RADIX_TREE_MAP_SIZE)
-				goto out;
-		}
-
-		shift -= RADIX_TREE_MAP_SHIFT;
-		slot = rcu_dereference_raw(slot->slots[i]);
-		if (slot == NULL)
-			goto out;
-	}
-
-	/* Bottom level: grab some items */
-	for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) {
-		if (slot->slots[i]) {
-			results[nr_found] = &(slot->slots[i]);
-			if (indices)
-				indices[nr_found] = index;
-			if (++nr_found == max_items) {
-				index++;
-				goto out;
-			}
-		}
-		index++;
-	}
-out:
-	*next_index = index;
-	return nr_found;
-}
-
 /**
  *	radix_tree_gang_lookup - perform multiple lookup on a radix tree
  *	@root:		radix tree root
@@ -891,48 +991,19 @@
 radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
 			unsigned long first_index, unsigned int max_items)
 {
-	unsigned long max_index;
-	struct radix_tree_node *node;
-	unsigned long cur_index = first_index;
-	unsigned int ret;
+	struct radix_tree_iter iter;
+	void **slot;
+	unsigned int ret = 0;
 
-	node = rcu_dereference_raw(root->rnode);
-	if (!node)
+	if (unlikely(!max_items))
 		return 0;
 
-	if (!radix_tree_is_indirect_ptr(node)) {
-		if (first_index > 0)
-			return 0;
-		results[0] = node;
-		return 1;
-	}
-	node = indirect_to_ptr(node);
-
-	max_index = radix_tree_maxindex(node->height);
-
-	ret = 0;
-	while (ret < max_items) {
-		unsigned int nr_found, slots_found, i;
-		unsigned long next_index;	/* Index of next search */
-
-		if (cur_index > max_index)
+	radix_tree_for_each_slot(slot, root, &iter, first_index) {
+		results[ret] = indirect_to_ptr(rcu_dereference_raw(*slot));
+		if (!results[ret])
+			continue;
+		if (++ret == max_items)
 			break;
-		slots_found = __lookup(node, (void ***)results + ret, NULL,
-				cur_index, max_items - ret, &next_index);
-		nr_found = 0;
-		for (i = 0; i < slots_found; i++) {
-			struct radix_tree_node *slot;
-			slot = *(((void ***)results)[ret + i]);
-			if (!slot)
-				continue;
-			results[ret + nr_found] =
-				indirect_to_ptr(rcu_dereference_raw(slot));
-			nr_found++;
-		}
-		ret += nr_found;
-		if (next_index == 0)
-			break;
-		cur_index = next_index;
 	}
 
 	return ret;
@@ -962,112 +1033,25 @@
 			void ***results, unsigned long *indices,
 			unsigned long first_index, unsigned int max_items)
 {
-	unsigned long max_index;
-	struct radix_tree_node *node;
-	unsigned long cur_index = first_index;
-	unsigned int ret;
+	struct radix_tree_iter iter;
+	void **slot;
+	unsigned int ret = 0;
 
-	node = rcu_dereference_raw(root->rnode);
-	if (!node)
+	if (unlikely(!max_items))
 		return 0;
 
-	if (!radix_tree_is_indirect_ptr(node)) {
-		if (first_index > 0)
-			return 0;
-		results[0] = (void **)&root->rnode;
+	radix_tree_for_each_slot(slot, root, &iter, first_index) {
+		results[ret] = slot;
 		if (indices)
-			indices[0] = 0;
-		return 1;
-	}
-	node = indirect_to_ptr(node);
-
-	max_index = radix_tree_maxindex(node->height);
-
-	ret = 0;
-	while (ret < max_items) {
-		unsigned int slots_found;
-		unsigned long next_index;	/* Index of next search */
-
-		if (cur_index > max_index)
+			indices[ret] = iter.index;
+		if (++ret == max_items)
 			break;
-		slots_found = __lookup(node, results + ret,
-				indices ? indices + ret : NULL,
-				cur_index, max_items - ret, &next_index);
-		ret += slots_found;
-		if (next_index == 0)
-			break;
-		cur_index = next_index;
 	}
 
 	return ret;
 }
 EXPORT_SYMBOL(radix_tree_gang_lookup_slot);
 
-/*
- * FIXME: the two tag_get()s here should use find_next_bit() instead of
- * open-coding the search.
- */
-static unsigned int
-__lookup_tag(struct radix_tree_node *slot, void ***results, unsigned long index,
-	unsigned int max_items, unsigned long *next_index, unsigned int tag)
-{
-	unsigned int nr_found = 0;
-	unsigned int shift, height;
-
-	height = slot->height;
-	if (height == 0)
-		goto out;
-	shift = (height-1) * RADIX_TREE_MAP_SHIFT;
-
-	while (height > 0) {
-		unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK ;
-
-		for (;;) {
-			if (tag_get(slot, tag, i))
-				break;
-			index &= ~((1UL << shift) - 1);
-			index += 1UL << shift;
-			if (index == 0)
-				goto out;	/* 32-bit wraparound */
-			i++;
-			if (i == RADIX_TREE_MAP_SIZE)
-				goto out;
-		}
-		height--;
-		if (height == 0) {	/* Bottom level: grab some items */
-			unsigned long j = index & RADIX_TREE_MAP_MASK;
-
-			for ( ; j < RADIX_TREE_MAP_SIZE; j++) {
-				index++;
-				if (!tag_get(slot, tag, j))
-					continue;
-				/*
-				 * Even though the tag was found set, we need to
-				 * recheck that we have a non-NULL node, because
-				 * if this lookup is lockless, it may have been
-				 * subsequently deleted.
-				 *
-				 * Similar care must be taken in any place that
-				 * lookup ->slots[x] without a lock (ie. can't
-				 * rely on its value remaining the same).
-				 */
-				if (slot->slots[j]) {
-					results[nr_found++] = &(slot->slots[j]);
-					if (nr_found == max_items)
-						goto out;
-				}
-			}
-		}
-		shift -= RADIX_TREE_MAP_SHIFT;
-		slot = rcu_dereference_raw(slot->slots[i]);
-		if (slot == NULL)
-			break;
-	}
-out:
-	*next_index = index;
-	return nr_found;
-}
-
 /**
  *	radix_tree_gang_lookup_tag - perform multiple lookup on a radix tree
  *	                             based on a tag
@@ -1086,52 +1070,19 @@
 		unsigned long first_index, unsigned int max_items,
 		unsigned int tag)
 {
-	struct radix_tree_node *node;
-	unsigned long max_index;
-	unsigned long cur_index = first_index;
-	unsigned int ret;
+	struct radix_tree_iter iter;
+	void **slot;
+	unsigned int ret = 0;
 
-	/* check the root's tag bit */
-	if (!root_tag_get(root, tag))
+	if (unlikely(!max_items))
 		return 0;
 
-	node = rcu_dereference_raw(root->rnode);
-	if (!node)
-		return 0;
-
-	if (!radix_tree_is_indirect_ptr(node)) {
-		if (first_index > 0)
-			return 0;
-		results[0] = node;
-		return 1;
-	}
-	node = indirect_to_ptr(node);
-
-	max_index = radix_tree_maxindex(node->height);
-
-	ret = 0;
-	while (ret < max_items) {
-		unsigned int nr_found, slots_found, i;
-		unsigned long next_index;	/* Index of next search */
-
-		if (cur_index > max_index)
+	radix_tree_for_each_tagged(slot, root, &iter, first_index, tag) {
+		results[ret] = indirect_to_ptr(rcu_dereference_raw(*slot));
+		if (!results[ret])
+			continue;
+		if (++ret == max_items)
 			break;
-		slots_found = __lookup_tag(node, (void ***)results + ret,
-				cur_index, max_items - ret, &next_index, tag);
-		nr_found = 0;
-		for (i = 0; i < slots_found; i++) {
-			struct radix_tree_node *slot;
-			slot = *(((void ***)results)[ret + i]);
-			if (!slot)
-				continue;
-			results[ret + nr_found] =
-				indirect_to_ptr(rcu_dereference_raw(slot));
-			nr_found++;
-		}
-		ret += nr_found;
-		if (next_index == 0)
-			break;
-		cur_index = next_index;
 	}
 
 	return ret;
@@ -1156,42 +1107,17 @@
 		unsigned long first_index, unsigned int max_items,
 		unsigned int tag)
 {
-	struct radix_tree_node *node;
-	unsigned long max_index;
-	unsigned long cur_index = first_index;
-	unsigned int ret;
+	struct radix_tree_iter iter;
+	void **slot;
+	unsigned int ret = 0;
 
-	/* check the root's tag bit */
-	if (!root_tag_get(root, tag))
+	if (unlikely(!max_items))
 		return 0;
 
-	node = rcu_dereference_raw(root->rnode);
-	if (!node)
-		return 0;
-
-	if (!radix_tree_is_indirect_ptr(node)) {
-		if (first_index > 0)
-			return 0;
-		results[0] = (void **)&root->rnode;
-		return 1;
-	}
-	node = indirect_to_ptr(node);
-
-	max_index = radix_tree_maxindex(node->height);
-
-	ret = 0;
-	while (ret < max_items) {
-		unsigned int slots_found;
-		unsigned long next_index;	/* Index of next search */
-
-		if (cur_index > max_index)
+	radix_tree_for_each_tagged(slot, root, &iter, first_index, tag) {
+		results[ret] = slot;
+		if (++ret == max_items)
 			break;
-		slots_found = __lookup_tag(node, results + ret,
-				cur_index, max_items - ret, &next_index, tag);
-		ret += slots_found;
-		if (next_index == 0)
-			break;
-		cur_index = next_index;
 	}
 
 	return ret;
diff --git a/lib/raid6/altivec.uc b/lib/raid6/altivec.uc
index 2654d5c..b71012b 100644
--- a/lib/raid6/altivec.uc
+++ b/lib/raid6/altivec.uc
@@ -28,8 +28,8 @@
 
 #include <altivec.h>
 #ifdef __KERNEL__
-# include <asm/system.h>
 # include <asm/cputable.h>
+# include <asm/switch_to.h>
 #endif
 
 /*
diff --git a/lib/random32.c b/lib/random32.c
index fc3545a..938bde5 100644
--- a/lib/random32.c
+++ b/lib/random32.c
@@ -35,7 +35,7 @@
 
 #include <linux/types.h>
 #include <linux/percpu.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/jiffies.h>
 #include <linux/random.h>
 
diff --git a/lib/ratelimit.c b/lib/ratelimit.c
index c96d500..40e03ea 100644
--- a/lib/ratelimit.c
+++ b/lib/ratelimit.c
@@ -11,7 +11,7 @@
 
 #include <linux/ratelimit.h>
 #include <linux/jiffies.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 /*
  * __ratelimit - rate limiting
diff --git a/lib/rational.c b/lib/rational.c
index 3ed247b..d326da3 100644
--- a/lib/rational.c
+++ b/lib/rational.c
@@ -7,7 +7,8 @@
  */
 
 #include <linux/rational.h>
-#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/export.h>
 
 /*
  * calculate best rational approximation for a given fraction
diff --git a/lib/rbtree.c b/lib/rbtree.c
index a16be19..d417556 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -21,7 +21,7 @@
 */
 
 #include <linux/rbtree.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
 {
diff --git a/lib/rwsem-spinlock.c b/lib/rwsem-spinlock.c
index f2393c2..7e0d6a5 100644
--- a/lib/rwsem-spinlock.c
+++ b/lib/rwsem-spinlock.c
@@ -7,7 +7,7 @@
  */
 #include <linux/rwsem.h>
 #include <linux/sched.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 struct rwsem_waiter {
 	struct list_head list;
diff --git a/lib/rwsem.c b/lib/rwsem.c
index 410aa11..8337e1b9b 100644
--- a/lib/rwsem.c
+++ b/lib/rwsem.c
@@ -6,7 +6,7 @@
 #include <linux/rwsem.h>
 #include <linux/sched.h>
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 /*
  * Initialize an rwsem:
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index 33b2cbb..6096e89 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -6,7 +6,7 @@
  * This source code is licensed under the GNU General Public License,
  * Version 2. See the file COPYING for more details.
  */
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/scatterlist.h>
 #include <linux/highmem.h>
diff --git a/lib/sha1.c b/lib/sha1.c
index 1de509a..1df191e 100644
--- a/lib/sha1.c
+++ b/lib/sha1.c
@@ -6,7 +6,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/bitops.h>
 #include <linux/cryptohash.h>
 #include <asm/unaligned.h>
diff --git a/lib/smp_processor_id.c b/lib/smp_processor_id.c
index 503f087..4c0d0e5 100644
--- a/lib/smp_processor_id.c
+++ b/lib/smp_processor_id.c
@@ -3,7 +3,7 @@
  *
  * DEBUG_PREEMPT variant of smp_processor_id().
  */
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kallsyms.h>
 #include <linux/sched.h>
 
diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c
index 5f3eacdd..525d160 100644
--- a/lib/spinlock_debug.c
+++ b/lib/spinlock_debug.c
@@ -11,7 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/debug_locks.h>
 #include <linux/delay.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name,
 			  struct lock_class_key *key)
diff --git a/lib/string.c b/lib/string.c
index dc4a863..e5878de 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -22,7 +22,10 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
-#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/bug.h>
+#include <linux/errno.h>
 
 #ifndef __HAVE_ARCH_STRNICMP
 /**
@@ -785,12 +788,24 @@
 	if (bytes <= 16)
 		return check_bytes8(start, value, bytes);
 
-	value64 = value | value << 8 | value << 16 | value << 24;
-	value64 = (value64 & 0xffffffff) | value64 << 32;
-	prefix = 8 - ((unsigned long)start) % 8;
+	value64 = value;
+#if defined(ARCH_HAS_FAST_MULTIPLIER) && BITS_PER_LONG == 64
+	value64 *= 0x0101010101010101;
+#elif defined(ARCH_HAS_FAST_MULTIPLIER)
+	value64 *= 0x01010101;
+	value64 |= value64 << 32;
+#else
+	value64 |= value64 << 8;
+	value64 |= value64 << 16;
+	value64 |= value64 << 32;
+#endif
 
+	prefix = (unsigned long)start % 8;
 	if (prefix) {
-		u8 *r = check_bytes8(start, value, prefix);
+		u8 *r;
+
+		prefix = 8 - prefix;
+		r = check_bytes8(start, value, prefix);
 		if (r)
 			return r;
 		start += prefix;
diff --git a/lib/string_helpers.c b/lib/string_helpers.c
index ab431d4..dd4ece3 100644
--- a/lib/string_helpers.c
+++ b/lib/string_helpers.c
@@ -5,7 +5,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/math64.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/string_helpers.h>
 
 /**
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index d0f6315..414f46e 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -20,7 +20,7 @@
 #include <linux/cache.h>
 #include <linux/dma-mapping.h>
 #include <linux/mm.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/swiotlb.h>
diff --git a/lib/syscall.c b/lib/syscall.c
index a4f7067..58710ee 100644
--- a/lib/syscall.c
+++ b/lib/syscall.c
@@ -1,6 +1,6 @@
 #include <linux/ptrace.h>
 #include <linux/sched.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <asm/syscall.h>
 
 static int collect_syscall(struct task_struct *target, long *callno,
diff --git a/lib/timerqueue.c b/lib/timerqueue.c
index 191176a..a382e4a 100644
--- a/lib/timerqueue.c
+++ b/lib/timerqueue.c
@@ -22,9 +22,10 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <linux/bug.h>
 #include <linux/timerqueue.h>
 #include <linux/rbtree.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 /**
  * timerqueue_add - Adds timer to timerqueue.
diff --git a/lib/uuid.c b/lib/uuid.c
index 8fadd7c..52a6fe6 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -19,7 +19,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/uuid.h>
 #include <linux/random.h>
 
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 38e612e..abbabec 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -17,7 +17,7 @@
  */
 
 #include <stdarg.h>
-#include <linux/module.h>
+#include <linux/module.h>	/* for KSYM_SYMBOL_LEN */
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
@@ -212,6 +212,26 @@
 	}
 }
 
+/*
+ * Convert passed number to decimal string.
+ * Returns the length of string.  On buffer overflow, returns 0.
+ *
+ * If speed is not important, use snprintf(). It's easy to read the code.
+ */
+int num_to_str(char *buf, int size, unsigned long long num)
+{
+	char tmp[21];		/* Enough for 2^64 in decimal */
+	int idx, len;
+
+	len = put_dec(tmp, num) - tmp;
+
+	if (len > size)
+		return 0;
+	for (idx = 0; idx < len; ++idx)
+		buf[idx] = tmp[len - idx - 1];
+	return  len;
+}
+
 #define ZEROPAD	1		/* pad with zero */
 #define SIGN	2		/* unsigned/signed long */
 #define PLUS	4		/* show plus */
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 668e94d..0131170 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -766,14 +766,13 @@
 				    unsigned long section_nr)
 {
 	bootmem_data_t *bdata;
-	unsigned long pfn, goal, limit;
+	unsigned long pfn, goal;
 
 	pfn = section_nr_to_pfn(section_nr);
 	goal = pfn << PAGE_SHIFT;
-	limit = section_nr_to_pfn(section_nr + 1) << PAGE_SHIFT;
 	bdata = &bootmem_node_data[early_pfn_to_nid(pfn)];
 
-	return alloc_bootmem_core(bdata, size, SMP_CACHE_BYTES, goal, limit);
+	return alloc_bootmem_core(bdata, size, SMP_CACHE_BYTES, goal, 0);
 }
 #endif
 
diff --git a/mm/cleancache.c b/mm/cleancache.c
index bcaae4c..5646c74 100644
--- a/mm/cleancache.c
+++ b/mm/cleancache.c
@@ -15,29 +15,34 @@
 #include <linux/fs.h>
 #include <linux/exportfs.h>
 #include <linux/mm.h>
+#include <linux/debugfs.h>
 #include <linux/cleancache.h>
 
 /*
  * This global enablement flag may be read thousands of times per second
- * by cleancache_get/put/flush even on systems where cleancache_ops
+ * by cleancache_get/put/invalidate even on systems where cleancache_ops
  * is not claimed (e.g. cleancache is config'ed on but remains
  * disabled), so is preferred to the slower alternative: a function
  * call that checks a non-global.
  */
-int cleancache_enabled;
+int cleancache_enabled __read_mostly;
 EXPORT_SYMBOL(cleancache_enabled);
 
 /*
  * cleancache_ops is set by cleancache_ops_register to contain the pointers
  * to the cleancache "backend" implementation functions.
  */
-static struct cleancache_ops cleancache_ops;
+static struct cleancache_ops cleancache_ops __read_mostly;
 
-/* useful stats available in /sys/kernel/mm/cleancache */
-static unsigned long cleancache_succ_gets;
-static unsigned long cleancache_failed_gets;
-static unsigned long cleancache_puts;
-static unsigned long cleancache_flushes;
+/*
+ * Counters available via /sys/kernel/debug/frontswap (if debugfs is
+ * properly configured.  These are for information only so are not protected
+ * against increment races.
+ */
+static u64 cleancache_succ_gets;
+static u64 cleancache_failed_gets;
+static u64 cleancache_puts;
+static u64 cleancache_invalidates;
 
 /*
  * register operations for cleancache, returning previous thus allowing
@@ -148,10 +153,11 @@
 EXPORT_SYMBOL(__cleancache_put_page);
 
 /*
- * Flush any data from cleancache associated with the poolid and the
+ * Invalidate any data from cleancache associated with the poolid and the
  * page's inode and page index so that a subsequent "get" will fail.
  */
-void __cleancache_flush_page(struct address_space *mapping, struct page *page)
+void __cleancache_invalidate_page(struct address_space *mapping,
+					struct page *page)
 {
 	/* careful... page->mapping is NULL sometimes when this is called */
 	int pool_id = mapping->host->i_sb->cleancache_poolid;
@@ -160,85 +166,57 @@
 	if (pool_id >= 0) {
 		VM_BUG_ON(!PageLocked(page));
 		if (cleancache_get_key(mapping->host, &key) >= 0) {
-			(*cleancache_ops.flush_page)(pool_id, key, page->index);
-			cleancache_flushes++;
+			(*cleancache_ops.invalidate_page)(pool_id,
+							  key, page->index);
+			cleancache_invalidates++;
 		}
 	}
 }
-EXPORT_SYMBOL(__cleancache_flush_page);
+EXPORT_SYMBOL(__cleancache_invalidate_page);
 
 /*
- * Flush all data from cleancache associated with the poolid and the
+ * Invalidate all data from cleancache associated with the poolid and the
  * mappings's inode so that all subsequent gets to this poolid/inode
  * will fail.
  */
-void __cleancache_flush_inode(struct address_space *mapping)
+void __cleancache_invalidate_inode(struct address_space *mapping)
 {
 	int pool_id = mapping->host->i_sb->cleancache_poolid;
 	struct cleancache_filekey key = { .u.key = { 0 } };
 
 	if (pool_id >= 0 && cleancache_get_key(mapping->host, &key) >= 0)
-		(*cleancache_ops.flush_inode)(pool_id, key);
+		(*cleancache_ops.invalidate_inode)(pool_id, key);
 }
-EXPORT_SYMBOL(__cleancache_flush_inode);
+EXPORT_SYMBOL(__cleancache_invalidate_inode);
 
 /*
  * Called by any cleancache-enabled filesystem at time of unmount;
  * note that pool_id is surrendered and may be reutrned by a subsequent
  * cleancache_init_fs or cleancache_init_shared_fs
  */
-void __cleancache_flush_fs(struct super_block *sb)
+void __cleancache_invalidate_fs(struct super_block *sb)
 {
 	if (sb->cleancache_poolid >= 0) {
 		int old_poolid = sb->cleancache_poolid;
 		sb->cleancache_poolid = -1;
-		(*cleancache_ops.flush_fs)(old_poolid);
+		(*cleancache_ops.invalidate_fs)(old_poolid);
 	}
 }
-EXPORT_SYMBOL(__cleancache_flush_fs);
-
-#ifdef CONFIG_SYSFS
-
-/* see Documentation/ABI/xxx/sysfs-kernel-mm-cleancache */
-
-#define CLEANCACHE_SYSFS_RO(_name) \
-	static ssize_t cleancache_##_name##_show(struct kobject *kobj, \
-				struct kobj_attribute *attr, char *buf) \
-	{ \
-		return sprintf(buf, "%lu\n", cleancache_##_name); \
-	} \
-	static struct kobj_attribute cleancache_##_name##_attr = { \
-		.attr = { .name = __stringify(_name), .mode = 0444 }, \
-		.show = cleancache_##_name##_show, \
-	}
-
-CLEANCACHE_SYSFS_RO(succ_gets);
-CLEANCACHE_SYSFS_RO(failed_gets);
-CLEANCACHE_SYSFS_RO(puts);
-CLEANCACHE_SYSFS_RO(flushes);
-
-static struct attribute *cleancache_attrs[] = {
-	&cleancache_succ_gets_attr.attr,
-	&cleancache_failed_gets_attr.attr,
-	&cleancache_puts_attr.attr,
-	&cleancache_flushes_attr.attr,
-	NULL,
-};
-
-static struct attribute_group cleancache_attr_group = {
-	.attrs = cleancache_attrs,
-	.name = "cleancache",
-};
-
-#endif /* CONFIG_SYSFS */
+EXPORT_SYMBOL(__cleancache_invalidate_fs);
 
 static int __init init_cleancache(void)
 {
-#ifdef CONFIG_SYSFS
-	int err;
-
-	err = sysfs_create_group(mm_kobj, &cleancache_attr_group);
-#endif /* CONFIG_SYSFS */
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *root = debugfs_create_dir("cleancache", NULL);
+	if (root == NULL)
+		return -ENXIO;
+	debugfs_create_u64("succ_gets", S_IRUGO, root, &cleancache_succ_gets);
+	debugfs_create_u64("failed_gets", S_IRUGO,
+				root, &cleancache_failed_gets);
+	debugfs_create_u64("puts", S_IRUGO, root, &cleancache_puts);
+	debugfs_create_u64("invalidates", S_IRUGO,
+				root, &cleancache_invalidates);
+#endif
 	return 0;
 }
 module_init(init_cleancache)
diff --git a/mm/compaction.c b/mm/compaction.c
index d9ebebe..74a8c82 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -35,7 +35,7 @@
 	unsigned long migrate_pfn;	/* isolate_migratepages search base */
 	bool sync;			/* Synchronous migration */
 
-	unsigned int order;		/* order a direct compactor needs */
+	int order;			/* order a direct compactor needs */
 	int migratetype;		/* MOVABLE, RECLAIMABLE etc */
 	struct zone *zone;
 };
@@ -675,49 +675,71 @@
 
 
 /* Compact all zones within a node */
-static int compact_node(int nid)
+static int __compact_pgdat(pg_data_t *pgdat, struct compact_control *cc)
 {
 	int zoneid;
-	pg_data_t *pgdat;
 	struct zone *zone;
 
-	if (nid < 0 || nid >= nr_node_ids || !node_online(nid))
-		return -EINVAL;
-	pgdat = NODE_DATA(nid);
-
-	/* Flush pending updates to the LRU lists */
-	lru_add_drain_all();
-
 	for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) {
-		struct compact_control cc = {
-			.nr_freepages = 0,
-			.nr_migratepages = 0,
-			.order = -1,
-			.sync = true,
-		};
 
 		zone = &pgdat->node_zones[zoneid];
 		if (!populated_zone(zone))
 			continue;
 
-		cc.zone = zone;
-		INIT_LIST_HEAD(&cc.freepages);
-		INIT_LIST_HEAD(&cc.migratepages);
+		cc->nr_freepages = 0;
+		cc->nr_migratepages = 0;
+		cc->zone = zone;
+		INIT_LIST_HEAD(&cc->freepages);
+		INIT_LIST_HEAD(&cc->migratepages);
 
-		compact_zone(zone, &cc);
+		if (cc->order == -1 || !compaction_deferred(zone, cc->order))
+			compact_zone(zone, cc);
 
-		VM_BUG_ON(!list_empty(&cc.freepages));
-		VM_BUG_ON(!list_empty(&cc.migratepages));
+		if (cc->order > 0) {
+			int ok = zone_watermark_ok(zone, cc->order,
+						low_wmark_pages(zone), 0, 0);
+			if (ok && cc->order > zone->compact_order_failed)
+				zone->compact_order_failed = cc->order + 1;
+			/* Currently async compaction is never deferred. */
+			else if (!ok && cc->sync)
+				defer_compaction(zone, cc->order);
+		}
+
+		VM_BUG_ON(!list_empty(&cc->freepages));
+		VM_BUG_ON(!list_empty(&cc->migratepages));
 	}
 
 	return 0;
 }
 
+int compact_pgdat(pg_data_t *pgdat, int order)
+{
+	struct compact_control cc = {
+		.order = order,
+		.sync = false,
+	};
+
+	return __compact_pgdat(pgdat, &cc);
+}
+
+static int compact_node(int nid)
+{
+	struct compact_control cc = {
+		.order = -1,
+		.sync = true,
+	};
+
+	return __compact_pgdat(NODE_DATA(nid), &cc);
+}
+
 /* Compact all nodes in the system */
 static int compact_nodes(void)
 {
 	int nid;
 
+	/* Flush pending updates to the LRU lists */
+	lru_add_drain_all();
+
 	for_each_online_node(nid)
 		compact_node(nid);
 
@@ -750,7 +772,14 @@
 			struct device_attribute *attr,
 			const char *buf, size_t count)
 {
-	compact_node(dev->id);
+	int nid = dev->id;
+
+	if (nid >= 0 && nid < nr_node_ids && node_online(nid)) {
+		/* Flush pending updates to the LRU lists */
+		lru_add_drain_all();
+
+		compact_node(nid);
+	}
 
 	return count;
 }
diff --git a/mm/filemap.c b/mm/filemap.c
index 2f81650..79c4b2b 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -101,9 +101,8 @@
  *    ->inode->i_lock		(zap_pte_range->set_page_dirty)
  *    ->private_lock		(zap_pte_range->__set_page_dirty_buffers)
  *
- *  (code doesn't rely on that order, so you could switch it around)
- *  ->tasklist_lock             (memory_failure, collect_procs_ao)
- *    ->i_mmap_mutex
+ * ->i_mmap_mutex
+ *   ->tasklist_lock            (memory_failure, collect_procs_ao)
  */
 
 /*
@@ -123,7 +122,7 @@
 	if (PageUptodate(page) && PageMappedToDisk(page))
 		cleancache_put_page(page);
 	else
-		cleancache_flush_page(mapping, page);
+		cleancache_invalidate_page(mapping, page);
 
 	radix_tree_delete(&mapping->page_tree, page->index);
 	page->mapping = NULL;
@@ -500,10 +499,13 @@
 	struct page *page;
 
 	if (cpuset_do_page_mem_spread()) {
-		get_mems_allowed();
-		n = cpuset_mem_spread_node();
-		page = alloc_pages_exact_node(n, gfp, 0);
-		put_mems_allowed();
+		unsigned int cpuset_mems_cookie;
+		do {
+			cpuset_mems_cookie = get_mems_allowed();
+			n = cpuset_mem_spread_node();
+			page = alloc_pages_exact_node(n, gfp, 0);
+		} while (!put_mems_allowed(cpuset_mems_cookie) && !page);
+
 		return page;
 	}
 	return alloc_pages(gfp, 0);
@@ -811,20 +813,19 @@
 unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
 			    unsigned int nr_pages, struct page **pages)
 {
-	unsigned int i;
-	unsigned int ret;
-	unsigned int nr_found, nr_skip;
+	struct radix_tree_iter iter;
+	void **slot;
+	unsigned ret = 0;
+
+	if (unlikely(!nr_pages))
+		return 0;
 
 	rcu_read_lock();
 restart:
-	nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree,
-				(void ***)pages, NULL, start, nr_pages);
-	ret = 0;
-	nr_skip = 0;
-	for (i = 0; i < nr_found; i++) {
+	radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
 		struct page *page;
 repeat:
-		page = radix_tree_deref_slot((void **)pages[i]);
+		page = radix_tree_deref_slot(slot);
 		if (unlikely(!page))
 			continue;
 
@@ -835,7 +836,7 @@
 				 * when entry at index 0 moves out of or back
 				 * to root: none yet gotten, safe to restart.
 				 */
-				WARN_ON(start | i);
+				WARN_ON(iter.index);
 				goto restart;
 			}
 			/*
@@ -843,7 +844,6 @@
 			 * here as an exceptional entry: so skip over it -
 			 * we only reach this from invalidate_mapping_pages().
 			 */
-			nr_skip++;
 			continue;
 		}
 
@@ -851,21 +851,16 @@
 			goto repeat;
 
 		/* Has the page moved? */
-		if (unlikely(page != *((void **)pages[i]))) {
+		if (unlikely(page != *slot)) {
 			page_cache_release(page);
 			goto repeat;
 		}
 
 		pages[ret] = page;
-		ret++;
+		if (++ret == nr_pages)
+			break;
 	}
 
-	/*
-	 * If all entries were removed before we could secure them,
-	 * try again, because callers stop trying once 0 is returned.
-	 */
-	if (unlikely(!ret && nr_found > nr_skip))
-		goto restart;
 	rcu_read_unlock();
 	return ret;
 }
@@ -885,21 +880,22 @@
 unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
 			       unsigned int nr_pages, struct page **pages)
 {
-	unsigned int i;
-	unsigned int ret;
-	unsigned int nr_found;
+	struct radix_tree_iter iter;
+	void **slot;
+	unsigned int ret = 0;
+
+	if (unlikely(!nr_pages))
+		return 0;
 
 	rcu_read_lock();
 restart:
-	nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree,
-				(void ***)pages, NULL, index, nr_pages);
-	ret = 0;
-	for (i = 0; i < nr_found; i++) {
+	radix_tree_for_each_contig(slot, &mapping->page_tree, &iter, index) {
 		struct page *page;
 repeat:
-		page = radix_tree_deref_slot((void **)pages[i]);
+		page = radix_tree_deref_slot(slot);
+		/* The hole, there no reason to continue */
 		if (unlikely(!page))
-			continue;
+			break;
 
 		if (radix_tree_exception(page)) {
 			if (radix_tree_deref_retry(page)) {
@@ -922,7 +918,7 @@
 			goto repeat;
 
 		/* Has the page moved? */
-		if (unlikely(page != *((void **)pages[i]))) {
+		if (unlikely(page != *slot)) {
 			page_cache_release(page);
 			goto repeat;
 		}
@@ -932,14 +928,14 @@
 		 * otherwise we can get both false positives and false
 		 * negatives, which is just confusing to the caller.
 		 */
-		if (page->mapping == NULL || page->index != index) {
+		if (page->mapping == NULL || page->index != iter.index) {
 			page_cache_release(page);
 			break;
 		}
 
 		pages[ret] = page;
-		ret++;
-		index++;
+		if (++ret == nr_pages)
+			break;
 	}
 	rcu_read_unlock();
 	return ret;
@@ -960,19 +956,20 @@
 unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
 			int tag, unsigned int nr_pages, struct page **pages)
 {
-	unsigned int i;
-	unsigned int ret;
-	unsigned int nr_found;
+	struct radix_tree_iter iter;
+	void **slot;
+	unsigned ret = 0;
+
+	if (unlikely(!nr_pages))
+		return 0;
 
 	rcu_read_lock();
 restart:
-	nr_found = radix_tree_gang_lookup_tag_slot(&mapping->page_tree,
-				(void ***)pages, *index, nr_pages, tag);
-	ret = 0;
-	for (i = 0; i < nr_found; i++) {
+	radix_tree_for_each_tagged(slot, &mapping->page_tree,
+				   &iter, *index, tag) {
 		struct page *page;
 repeat:
-		page = radix_tree_deref_slot((void **)pages[i]);
+		page = radix_tree_deref_slot(slot);
 		if (unlikely(!page))
 			continue;
 
@@ -996,21 +993,16 @@
 			goto repeat;
 
 		/* Has the page moved? */
-		if (unlikely(page != *((void **)pages[i]))) {
+		if (unlikely(page != *slot)) {
 			page_cache_release(page);
 			goto repeat;
 		}
 
 		pages[ret] = page;
-		ret++;
+		if (++ret == nr_pages)
+			break;
 	}
 
-	/*
-	 * If all entries were removed before we could secure them,
-	 * try again, because callers stop trying once 0 is returned.
-	 */
-	if (unlikely(!ret && nr_found))
-		goto restart;
 	rcu_read_unlock();
 
 	if (ret)
@@ -2341,7 +2333,9 @@
 	struct page *page;
 	gfp_t gfp_notmask = 0;
 
-	gfp_mask = mapping_gfp_mask(mapping) | __GFP_WRITE;
+	gfp_mask = mapping_gfp_mask(mapping);
+	if (mapping_cap_account_dirty(mapping))
+		gfp_mask |= __GFP_WRITE;
 	if (flags & AOP_FLAG_NOFS)
 		gfp_notmask = __GFP_FS;
 repeat:
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 8f7fc39..f0e5306 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1031,32 +1031,23 @@
 {
 	int ret = 0;
 
-	spin_lock(&tlb->mm->page_table_lock);
-	if (likely(pmd_trans_huge(*pmd))) {
-		if (unlikely(pmd_trans_splitting(*pmd))) {
-			spin_unlock(&tlb->mm->page_table_lock);
-			wait_split_huge_page(vma->anon_vma,
-					     pmd);
-		} else {
-			struct page *page;
-			pgtable_t pgtable;
-			pgtable = get_pmd_huge_pte(tlb->mm);
-			page = pmd_page(*pmd);
-			pmd_clear(pmd);
-			tlb_remove_pmd_tlb_entry(tlb, pmd, addr);
-			page_remove_rmap(page);
-			VM_BUG_ON(page_mapcount(page) < 0);
-			add_mm_counter(tlb->mm, MM_ANONPAGES, -HPAGE_PMD_NR);
-			VM_BUG_ON(!PageHead(page));
-			tlb->mm->nr_ptes--;
-			spin_unlock(&tlb->mm->page_table_lock);
-			tlb_remove_page(tlb, page);
-			pte_free(tlb->mm, pgtable);
-			ret = 1;
-		}
-	} else
+	if (__pmd_trans_huge_lock(pmd, vma) == 1) {
+		struct page *page;
+		pgtable_t pgtable;
+		pgtable = get_pmd_huge_pte(tlb->mm);
+		page = pmd_page(*pmd);
+		pmd_clear(pmd);
+		tlb_remove_pmd_tlb_entry(tlb, pmd, addr);
+		page_remove_rmap(page);
+		VM_BUG_ON(page_mapcount(page) < 0);
+		add_mm_counter(tlb->mm, MM_ANONPAGES, -HPAGE_PMD_NR);
+		VM_BUG_ON(!PageHead(page));
+		tlb->mm->nr_ptes--;
 		spin_unlock(&tlb->mm->page_table_lock);
-
+		tlb_remove_page(tlb, page);
+		pte_free(tlb->mm, pgtable);
+		ret = 1;
+	}
 	return ret;
 }
 
@@ -1066,21 +1057,15 @@
 {
 	int ret = 0;
 
-	spin_lock(&vma->vm_mm->page_table_lock);
-	if (likely(pmd_trans_huge(*pmd))) {
-		ret = !pmd_trans_splitting(*pmd);
+	if (__pmd_trans_huge_lock(pmd, vma) == 1) {
+		/*
+		 * All logical pages in the range are present
+		 * if backed by a huge page.
+		 */
 		spin_unlock(&vma->vm_mm->page_table_lock);
-		if (unlikely(!ret))
-			wait_split_huge_page(vma->anon_vma, pmd);
-		else {
-			/*
-			 * All logical pages in the range are present
-			 * if backed by a huge page.
-			 */
-			memset(vec, 1, (end - addr) >> PAGE_SHIFT);
-		}
-	} else
-		spin_unlock(&vma->vm_mm->page_table_lock);
+		memset(vec, 1, (end - addr) >> PAGE_SHIFT);
+		ret = 1;
+	}
 
 	return ret;
 }
@@ -1110,20 +1095,11 @@
 		goto out;
 	}
 
-	spin_lock(&mm->page_table_lock);
-	if (likely(pmd_trans_huge(*old_pmd))) {
-		if (pmd_trans_splitting(*old_pmd)) {
-			spin_unlock(&mm->page_table_lock);
-			wait_split_huge_page(vma->anon_vma, old_pmd);
-			ret = -1;
-		} else {
-			pmd = pmdp_get_and_clear(mm, old_addr, old_pmd);
-			VM_BUG_ON(!pmd_none(*new_pmd));
-			set_pmd_at(mm, new_addr, new_pmd, pmd);
-			spin_unlock(&mm->page_table_lock);
-			ret = 1;
-		}
-	} else {
+	ret = __pmd_trans_huge_lock(old_pmd, vma);
+	if (ret == 1) {
+		pmd = pmdp_get_and_clear(mm, old_addr, old_pmd);
+		VM_BUG_ON(!pmd_none(*new_pmd));
+		set_pmd_at(mm, new_addr, new_pmd, pmd);
 		spin_unlock(&mm->page_table_lock);
 	}
 out:
@@ -1136,26 +1112,43 @@
 	struct mm_struct *mm = vma->vm_mm;
 	int ret = 0;
 
-	spin_lock(&mm->page_table_lock);
-	if (likely(pmd_trans_huge(*pmd))) {
-		if (unlikely(pmd_trans_splitting(*pmd))) {
-			spin_unlock(&mm->page_table_lock);
-			wait_split_huge_page(vma->anon_vma, pmd);
-		} else {
-			pmd_t entry;
-
-			entry = pmdp_get_and_clear(mm, addr, pmd);
-			entry = pmd_modify(entry, newprot);
-			set_pmd_at(mm, addr, pmd, entry);
-			spin_unlock(&vma->vm_mm->page_table_lock);
-			ret = 1;
-		}
-	} else
+	if (__pmd_trans_huge_lock(pmd, vma) == 1) {
+		pmd_t entry;
+		entry = pmdp_get_and_clear(mm, addr, pmd);
+		entry = pmd_modify(entry, newprot);
+		set_pmd_at(mm, addr, pmd, entry);
 		spin_unlock(&vma->vm_mm->page_table_lock);
+		ret = 1;
+	}
 
 	return ret;
 }
 
+/*
+ * Returns 1 if a given pmd maps a stable (not under splitting) thp.
+ * Returns -1 if it maps a thp under splitting. Returns 0 otherwise.
+ *
+ * Note that if it returns 1, this routine returns without unlocking page
+ * table locks. So callers must unlock them.
+ */
+int __pmd_trans_huge_lock(pmd_t *pmd, struct vm_area_struct *vma)
+{
+	spin_lock(&vma->vm_mm->page_table_lock);
+	if (likely(pmd_trans_huge(*pmd))) {
+		if (unlikely(pmd_trans_splitting(*pmd))) {
+			spin_unlock(&vma->vm_mm->page_table_lock);
+			wait_split_huge_page(vma->anon_vma, pmd);
+			return -1;
+		} else {
+			/* Thp mapped by 'pmd' is stable, so we can
+			 * handle it as it is. */
+			return 1;
+		}
+	}
+	spin_unlock(&vma->vm_mm->page_table_lock);
+	return 0;
+}
+
 pmd_t *page_check_address_pmd(struct page *page,
 			      struct mm_struct *mm,
 			      unsigned long address,
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index a876871..b8ce6f4 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -53,6 +53,84 @@
  */
 static DEFINE_SPINLOCK(hugetlb_lock);
 
+static inline void unlock_or_release_subpool(struct hugepage_subpool *spool)
+{
+	bool free = (spool->count == 0) && (spool->used_hpages == 0);
+
+	spin_unlock(&spool->lock);
+
+	/* If no pages are used, and no other handles to the subpool
+	 * remain, free the subpool the subpool remain */
+	if (free)
+		kfree(spool);
+}
+
+struct hugepage_subpool *hugepage_new_subpool(long nr_blocks)
+{
+	struct hugepage_subpool *spool;
+
+	spool = kmalloc(sizeof(*spool), GFP_KERNEL);
+	if (!spool)
+		return NULL;
+
+	spin_lock_init(&spool->lock);
+	spool->count = 1;
+	spool->max_hpages = nr_blocks;
+	spool->used_hpages = 0;
+
+	return spool;
+}
+
+void hugepage_put_subpool(struct hugepage_subpool *spool)
+{
+	spin_lock(&spool->lock);
+	BUG_ON(!spool->count);
+	spool->count--;
+	unlock_or_release_subpool(spool);
+}
+
+static int hugepage_subpool_get_pages(struct hugepage_subpool *spool,
+				      long delta)
+{
+	int ret = 0;
+
+	if (!spool)
+		return 0;
+
+	spin_lock(&spool->lock);
+	if ((spool->used_hpages + delta) <= spool->max_hpages) {
+		spool->used_hpages += delta;
+	} else {
+		ret = -ENOMEM;
+	}
+	spin_unlock(&spool->lock);
+
+	return ret;
+}
+
+static void hugepage_subpool_put_pages(struct hugepage_subpool *spool,
+				       long delta)
+{
+	if (!spool)
+		return;
+
+	spin_lock(&spool->lock);
+	spool->used_hpages -= delta;
+	/* If hugetlbfs_put_super couldn't free spool due to
+	* an outstanding quota reference, free it now. */
+	unlock_or_release_subpool(spool);
+}
+
+static inline struct hugepage_subpool *subpool_inode(struct inode *inode)
+{
+	return HUGETLBFS_SB(inode->i_sb)->spool;
+}
+
+static inline struct hugepage_subpool *subpool_vma(struct vm_area_struct *vma)
+{
+	return subpool_inode(vma->vm_file->f_dentry->d_inode);
+}
+
 /*
  * Region tracking -- allows tracking of reservations and instantiated pages
  *                    across the pages in a mapping.
@@ -454,14 +532,16 @@
 				struct vm_area_struct *vma,
 				unsigned long address, int avoid_reserve)
 {
-	struct page *page = NULL;
+	struct page *page;
 	struct mempolicy *mpol;
 	nodemask_t *nodemask;
 	struct zonelist *zonelist;
 	struct zone *zone;
 	struct zoneref *z;
+	unsigned int cpuset_mems_cookie;
 
-	get_mems_allowed();
+retry_cpuset:
+	cpuset_mems_cookie = get_mems_allowed();
 	zonelist = huge_zonelist(vma, address,
 					htlb_alloc_mask, &mpol, &nodemask);
 	/*
@@ -488,10 +568,15 @@
 			}
 		}
 	}
+
+	mpol_cond_put(mpol);
+	if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+		goto retry_cpuset;
+	return page;
+
 err:
 	mpol_cond_put(mpol);
-	put_mems_allowed();
-	return page;
+	return NULL;
 }
 
 static void update_and_free_page(struct hstate *h, struct page *page)
@@ -533,9 +618,9 @@
 	 */
 	struct hstate *h = page_hstate(page);
 	int nid = page_to_nid(page);
-	struct address_space *mapping;
+	struct hugepage_subpool *spool =
+		(struct hugepage_subpool *)page_private(page);
 
-	mapping = (struct address_space *) page_private(page);
 	set_page_private(page, 0);
 	page->mapping = NULL;
 	BUG_ON(page_count(page));
@@ -551,8 +636,7 @@
 		enqueue_huge_page(h, page);
 	}
 	spin_unlock(&hugetlb_lock);
-	if (mapping)
-		hugetlb_put_quota(mapping, 1);
+	hugepage_subpool_put_pages(spool, 1);
 }
 
 static void prep_new_huge_page(struct hstate *h, struct page *page, int nid)
@@ -852,6 +936,7 @@
 	struct page *page, *tmp;
 	int ret, i;
 	int needed, allocated;
+	bool alloc_ok = true;
 
 	needed = (h->resv_huge_pages + delta) - h->free_huge_pages;
 	if (needed <= 0) {
@@ -867,17 +952,13 @@
 	spin_unlock(&hugetlb_lock);
 	for (i = 0; i < needed; i++) {
 		page = alloc_buddy_huge_page(h, NUMA_NO_NODE);
-		if (!page)
-			/*
-			 * We were not able to allocate enough pages to
-			 * satisfy the entire reservation so we free what
-			 * we've allocated so far.
-			 */
-			goto free;
-
+		if (!page) {
+			alloc_ok = false;
+			break;
+		}
 		list_add(&page->lru, &surplus_list);
 	}
-	allocated += needed;
+	allocated += i;
 
 	/*
 	 * After retaking hugetlb_lock, we need to recalculate 'needed'
@@ -886,9 +967,16 @@
 	spin_lock(&hugetlb_lock);
 	needed = (h->resv_huge_pages + delta) -
 			(h->free_huge_pages + allocated);
-	if (needed > 0)
-		goto retry;
-
+	if (needed > 0) {
+		if (alloc_ok)
+			goto retry;
+		/*
+		 * We were not able to allocate enough pages to
+		 * satisfy the entire reservation so we free what
+		 * we've allocated so far.
+		 */
+		goto free;
+	}
 	/*
 	 * The surplus_list now contains _at_least_ the number of extra pages
 	 * needed to accommodate the reservation.  Add the appropriate number
@@ -914,10 +1002,10 @@
 		VM_BUG_ON(page_count(page));
 		enqueue_huge_page(h, page);
 	}
+free:
 	spin_unlock(&hugetlb_lock);
 
 	/* Free unnecessary surplus pages to the buddy allocator */
-free:
 	if (!list_empty(&surplus_list)) {
 		list_for_each_entry_safe(page, tmp, &surplus_list, lru) {
 			list_del(&page->lru);
@@ -966,11 +1054,12 @@
 /*
  * Determine if the huge page at addr within the vma has an associated
  * reservation.  Where it does not we will need to logically increase
- * reservation and actually increase quota before an allocation can occur.
- * Where any new reservation would be required the reservation change is
- * prepared, but not committed.  Once the page has been quota'd allocated
- * an instantiated the change should be committed via vma_commit_reservation.
- * No action is required on failure.
+ * reservation and actually increase subpool usage before an allocation
+ * can occur.  Where any new reservation would be required the
+ * reservation change is prepared, but not committed.  Once the page
+ * has been allocated from the subpool and instantiated the change should
+ * be committed via vma_commit_reservation.  No action is required on
+ * failure.
  */
 static long vma_needs_reservation(struct hstate *h,
 			struct vm_area_struct *vma, unsigned long addr)
@@ -1019,24 +1108,24 @@
 static struct page *alloc_huge_page(struct vm_area_struct *vma,
 				    unsigned long addr, int avoid_reserve)
 {
+	struct hugepage_subpool *spool = subpool_vma(vma);
 	struct hstate *h = hstate_vma(vma);
 	struct page *page;
-	struct address_space *mapping = vma->vm_file->f_mapping;
-	struct inode *inode = mapping->host;
 	long chg;
 
 	/*
-	 * Processes that did not create the mapping will have no reserves and
-	 * will not have accounted against quota. Check that the quota can be
-	 * made before satisfying the allocation
-	 * MAP_NORESERVE mappings may also need pages and quota allocated
-	 * if no reserve mapping overlaps.
+	 * Processes that did not create the mapping will have no
+	 * reserves and will not have accounted against subpool
+	 * limit. Check that the subpool limit can be made before
+	 * satisfying the allocation MAP_NORESERVE mappings may also
+	 * need pages and subpool limit allocated allocated if no reserve
+	 * mapping overlaps.
 	 */
 	chg = vma_needs_reservation(h, vma, addr);
 	if (chg < 0)
 		return ERR_PTR(-VM_FAULT_OOM);
 	if (chg)
-		if (hugetlb_get_quota(inode->i_mapping, chg))
+		if (hugepage_subpool_get_pages(spool, chg))
 			return ERR_PTR(-VM_FAULT_SIGBUS);
 
 	spin_lock(&hugetlb_lock);
@@ -1046,12 +1135,12 @@
 	if (!page) {
 		page = alloc_buddy_huge_page(h, NUMA_NO_NODE);
 		if (!page) {
-			hugetlb_put_quota(inode->i_mapping, chg);
+			hugepage_subpool_put_pages(spool, chg);
 			return ERR_PTR(-VM_FAULT_SIGBUS);
 		}
 	}
 
-	set_page_private(page, (unsigned long) mapping);
+	set_page_private(page, (unsigned long)spool);
 
 	vma_commit_reservation(h, vma, addr);
 
@@ -2072,6 +2161,7 @@
 {
 	struct hstate *h = hstate_vma(vma);
 	struct resv_map *reservations = vma_resv_map(vma);
+	struct hugepage_subpool *spool = subpool_vma(vma);
 	unsigned long reserve;
 	unsigned long start;
 	unsigned long end;
@@ -2087,7 +2177,7 @@
 
 		if (reserve) {
 			hugetlb_acct_memory(h, -reserve);
-			hugetlb_put_quota(vma->vm_file->f_mapping, reserve);
+			hugepage_subpool_put_pages(spool, reserve);
 		}
 	}
 }
@@ -2241,16 +2331,23 @@
 		if (huge_pmd_unshare(mm, &address, ptep))
 			continue;
 
+		pte = huge_ptep_get(ptep);
+		if (huge_pte_none(pte))
+			continue;
+
+		/*
+		 * HWPoisoned hugepage is already unmapped and dropped reference
+		 */
+		if (unlikely(is_hugetlb_entry_hwpoisoned(pte)))
+			continue;
+
+		page = pte_page(pte);
 		/*
 		 * If a reference page is supplied, it is because a specific
 		 * page is being unmapped, not a range. Ensure the page we
 		 * are about to unmap is the actual page of interest.
 		 */
 		if (ref_page) {
-			pte = huge_ptep_get(ptep);
-			if (huge_pte_none(pte))
-				continue;
-			page = pte_page(pte);
 			if (page != ref_page)
 				continue;
 
@@ -2263,19 +2360,13 @@
 		}
 
 		pte = huge_ptep_get_and_clear(mm, address, ptep);
-		if (huge_pte_none(pte))
-			continue;
-
-		/*
-		 * HWPoisoned hugepage is already unmapped and dropped reference
-		 */
-		if (unlikely(is_hugetlb_entry_hwpoisoned(pte)))
-			continue;
-
-		page = pte_page(pte);
 		if (pte_dirty(pte))
 			set_page_dirty(page);
 		list_add(&page->lru, &page_list);
+
+		/* Bail out after unmapping reference page if supplied */
+		if (ref_page)
+			break;
 	}
 	flush_tlb_range(vma, start, end);
 	spin_unlock(&mm->page_table_lock);
@@ -2316,7 +2407,7 @@
 	 */
 	address = address & huge_page_mask(h);
 	pgoff = vma_hugecache_offset(h, vma, address);
-	mapping = (struct address_space *)page_private(page);
+	mapping = vma->vm_file->f_dentry->d_inode->i_mapping;
 
 	/*
 	 * Take the mapping lock for the duration of the table walk. As
@@ -2869,11 +2960,12 @@
 {
 	long ret, chg;
 	struct hstate *h = hstate_inode(inode);
+	struct hugepage_subpool *spool = subpool_inode(inode);
 
 	/*
 	 * Only apply hugepage reservation if asked. At fault time, an
 	 * attempt will be made for VM_NORESERVE to allocate a page
-	 * and filesystem quota without using reserves
+	 * without using reserves
 	 */
 	if (vm_flags & VM_NORESERVE)
 		return 0;
@@ -2900,17 +2992,17 @@
 	if (chg < 0)
 		return chg;
 
-	/* There must be enough filesystem quota for the mapping */
-	if (hugetlb_get_quota(inode->i_mapping, chg))
+	/* There must be enough pages in the subpool for the mapping */
+	if (hugepage_subpool_get_pages(spool, chg))
 		return -ENOSPC;
 
 	/*
 	 * Check enough hugepages are available for the reservation.
-	 * Hand back the quota if there are not
+	 * Hand the pages back to the subpool if there are not
 	 */
 	ret = hugetlb_acct_memory(h, chg);
 	if (ret < 0) {
-		hugetlb_put_quota(inode->i_mapping, chg);
+		hugepage_subpool_put_pages(spool, chg);
 		return ret;
 	}
 
@@ -2934,12 +3026,13 @@
 {
 	struct hstate *h = hstate_inode(inode);
 	long chg = region_truncate(&inode->i_mapping->private_list, offset);
+	struct hugepage_subpool *spool = subpool_inode(inode);
 
 	spin_lock(&inode->i_lock);
 	inode->i_blocks -= (blocks_per_huge_page(h) * freed);
 	spin_unlock(&inode->i_lock);
 
-	hugetlb_put_quota(inode->i_mapping, (chg - freed));
+	hugepage_subpool_put_pages(spool, (chg - freed));
 	hugetlb_acct_memory(h, -(chg - freed));
 }
 
diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c
index c7fc7fd..cc448bb 100644
--- a/mm/hwpoison-inject.c
+++ b/mm/hwpoison-inject.c
@@ -45,7 +45,7 @@
 	 * do a racy check with elevated page count, to make sure PG_hwpoison
 	 * will only be set for the targeted owner (or on a free page).
 	 * We temporarily take page lock for try_get_mem_cgroup_from_page().
-	 * __memory_failure() will redo the check reliably inside page lock.
+	 * memory_failure() will redo the check reliably inside page lock.
 	 */
 	lock_page(hpage);
 	err = hwpoison_filter(hpage);
@@ -55,7 +55,7 @@
 
 inject:
 	printk(KERN_INFO "Injecting memory failure at pfn %lx\n", pfn);
-	return __memory_failure(pfn, 18, MF_COUNT_INCREASED);
+	return memory_failure(pfn, 18, MF_COUNT_INCREASED);
 }
 
 static int hwpoison_unpoison(void *data, u64 val)
diff --git a/mm/ksm.c b/mm/ksm.c
index a6d3fb7..47c8853 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -374,6 +374,20 @@
 	return (ret & VM_FAULT_OOM) ? -ENOMEM : 0;
 }
 
+static struct vm_area_struct *find_mergeable_vma(struct mm_struct *mm,
+		unsigned long addr)
+{
+	struct vm_area_struct *vma;
+	if (ksm_test_exit(mm))
+		return NULL;
+	vma = find_vma(mm, addr);
+	if (!vma || vma->vm_start > addr)
+		return NULL;
+	if (!(vma->vm_flags & VM_MERGEABLE) || !vma->anon_vma)
+		return NULL;
+	return vma;
+}
+
 static void break_cow(struct rmap_item *rmap_item)
 {
 	struct mm_struct *mm = rmap_item->mm;
@@ -387,15 +401,9 @@
 	put_anon_vma(rmap_item->anon_vma);
 
 	down_read(&mm->mmap_sem);
-	if (ksm_test_exit(mm))
-		goto out;
-	vma = find_vma(mm, addr);
-	if (!vma || vma->vm_start > addr)
-		goto out;
-	if (!(vma->vm_flags & VM_MERGEABLE) || !vma->anon_vma)
-		goto out;
-	break_ksm(vma, addr);
-out:
+	vma = find_mergeable_vma(mm, addr);
+	if (vma)
+		break_ksm(vma, addr);
 	up_read(&mm->mmap_sem);
 }
 
@@ -421,12 +429,8 @@
 	struct page *page;
 
 	down_read(&mm->mmap_sem);
-	if (ksm_test_exit(mm))
-		goto out;
-	vma = find_vma(mm, addr);
-	if (!vma || vma->vm_start > addr)
-		goto out;
-	if (!(vma->vm_flags & VM_MERGEABLE) || !vma->anon_vma)
+	vma = find_mergeable_vma(mm, addr);
+	if (!vma)
 		goto out;
 
 	page = follow_page(vma, addr, FOLL_GET);
diff --git a/mm/madvise.c b/mm/madvise.c
index 74bf193..1ccbba5 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -65,6 +65,12 @@
 		}
 		new_flags &= ~VM_DONTCOPY;
 		break;
+	case MADV_DONTDUMP:
+		new_flags |= VM_NODUMP;
+		break;
+	case MADV_DODUMP:
+		new_flags &= ~VM_NODUMP;
+		break;
 	case MADV_MERGEABLE:
 	case MADV_UNMERGEABLE:
 		error = ksm_madvise(vma, start, end, behavior, &new_flags);
@@ -251,7 +257,7 @@
 		printk(KERN_INFO "Injecting memory failure for page %lx at %lx\n",
 		       page_to_pfn(p), start);
 		/* Ignore return value for now */
-		__memory_failure(page_to_pfn(p), 0, MF_COUNT_INCREASED);
+		memory_failure(page_to_pfn(p), 0, MF_COUNT_INCREASED);
 	}
 	return ret;
 }
@@ -293,6 +299,8 @@
 	case MADV_HUGEPAGE:
 	case MADV_NOHUGEPAGE:
 #endif
+	case MADV_DONTDUMP:
+	case MADV_DODUMP:
 		return 1;
 
 	default:
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 26c6f4e..7d698df 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -89,7 +89,6 @@
 	MEM_CGROUP_STAT_FILE_MAPPED,  /* # of pages charged as file rss */
 	MEM_CGROUP_STAT_SWAPOUT, /* # of pages, swapped out */
 	MEM_CGROUP_STAT_DATA, /* end of data requires synchronization */
-	MEM_CGROUP_ON_MOVE,	/* someone is moving account between groups */
 	MEM_CGROUP_STAT_NSTATS,
 };
 
@@ -135,7 +134,7 @@
  */
 struct mem_cgroup_per_zone {
 	struct lruvec		lruvec;
-	unsigned long		count[NR_LRU_LISTS];
+	unsigned long		lru_size[NR_LRU_LISTS];
 
 	struct mem_cgroup_reclaim_iter reclaim_iter[DEF_PRIORITY + 1];
 
@@ -144,11 +143,9 @@
 	unsigned long long	usage_in_excess;/* Set to the value by which */
 						/* the soft limit is exceeded*/
 	bool			on_tree;
-	struct mem_cgroup	*mem;		/* Back pointer, we cannot */
+	struct mem_cgroup	*memcg;		/* Back pointer, we cannot */
 						/* use container_of	   */
 };
-/* Macro for accessing counter */
-#define MEM_CGROUP_ZSTAT(mz, idx)	((mz)->count[(idx)])
 
 struct mem_cgroup_per_node {
 	struct mem_cgroup_per_zone zoneinfo[MAX_NR_ZONES];
@@ -300,6 +297,12 @@
 	 */
 	unsigned long 	move_charge_at_immigrate;
 	/*
+	 * set > 0 if pages under this cgroup are moving to other cgroup.
+	 */
+	atomic_t	moving_account;
+	/* taken only while moving_account > 0 */
+	spinlock_t	move_lock;
+	/*
 	 * percpu counter.
 	 */
 	struct mem_cgroup_stat_cpu *stat;
@@ -612,9 +615,9 @@
 	 * we will to add it back at the end of reclaim to its correct
 	 * position in the tree.
 	 */
-	__mem_cgroup_remove_exceeded(mz->mem, mz, mctz);
-	if (!res_counter_soft_limit_excess(&mz->mem->res) ||
-		!css_tryget(&mz->mem->css))
+	__mem_cgroup_remove_exceeded(mz->memcg, mz, mctz);
+	if (!res_counter_soft_limit_excess(&mz->memcg->res) ||
+		!css_tryget(&mz->memcg->css))
 		goto retry;
 done:
 	return mz;
@@ -692,15 +695,19 @@
 }
 
 static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg,
-					 bool file, int nr_pages)
+					 bool anon, int nr_pages)
 {
 	preempt_disable();
 
-	if (file)
-		__this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_CACHE],
+	/*
+	 * Here, RSS means 'mapped anon' and anon's SwapCache. Shmem/tmpfs is
+	 * counted as CACHE even if it's on ANON LRU.
+	 */
+	if (anon)
+		__this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_RSS],
 				nr_pages);
 	else
-		__this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_RSS],
+		__this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_CACHE],
 				nr_pages);
 
 	/* pagein of a big page is an event. So, ignore page size */
@@ -721,14 +728,14 @@
 			unsigned int lru_mask)
 {
 	struct mem_cgroup_per_zone *mz;
-	enum lru_list l;
+	enum lru_list lru;
 	unsigned long ret = 0;
 
 	mz = mem_cgroup_zoneinfo(memcg, nid, zid);
 
-	for_each_lru(l) {
-		if (BIT(l) & lru_mask)
-			ret += MEM_CGROUP_ZSTAT(mz, l);
+	for_each_lru(lru) {
+		if (BIT(lru) & lru_mask)
+			ret += mz->lru_size[lru];
 	}
 	return ret;
 }
@@ -1077,7 +1084,7 @@
 
 	mz = page_cgroup_zoneinfo(memcg, page);
 	/* compound_order() is stabilized through lru_lock */
-	MEM_CGROUP_ZSTAT(mz, lru) += 1 << compound_order(page);
+	mz->lru_size[lru] += 1 << compound_order(page);
 	return &mz->lruvec;
 }
 
@@ -1105,8 +1112,8 @@
 	VM_BUG_ON(!memcg);
 	mz = page_cgroup_zoneinfo(memcg, page);
 	/* huge page split is done under lru_lock. so, we have no races. */
-	VM_BUG_ON(MEM_CGROUP_ZSTAT(mz, lru) < (1 << compound_order(page)));
-	MEM_CGROUP_ZSTAT(mz, lru) -= 1 << compound_order(page);
+	VM_BUG_ON(mz->lru_size[lru] < (1 << compound_order(page)));
+	mz->lru_size[lru] -= 1 << compound_order(page);
 }
 
 void mem_cgroup_lru_del(struct page *page)
@@ -1285,40 +1292,48 @@
 	return memcg->swappiness;
 }
 
+/*
+ * memcg->moving_account is used for checking possibility that some thread is
+ * calling move_account(). When a thread on CPU-A starts moving pages under
+ * a memcg, other threads should check memcg->moving_account under
+ * rcu_read_lock(), like this:
+ *
+ *         CPU-A                                    CPU-B
+ *                                              rcu_read_lock()
+ *         memcg->moving_account+1              if (memcg->mocing_account)
+ *                                                   take heavy locks.
+ *         synchronize_rcu()                    update something.
+ *                                              rcu_read_unlock()
+ *         start move here.
+ */
+
+/* for quick checking without looking up memcg */
+atomic_t memcg_moving __read_mostly;
+
 static void mem_cgroup_start_move(struct mem_cgroup *memcg)
 {
-	int cpu;
-
-	get_online_cpus();
-	spin_lock(&memcg->pcp_counter_lock);
-	for_each_online_cpu(cpu)
-		per_cpu(memcg->stat->count[MEM_CGROUP_ON_MOVE], cpu) += 1;
-	memcg->nocpu_base.count[MEM_CGROUP_ON_MOVE] += 1;
-	spin_unlock(&memcg->pcp_counter_lock);
-	put_online_cpus();
-
+	atomic_inc(&memcg_moving);
+	atomic_inc(&memcg->moving_account);
 	synchronize_rcu();
 }
 
 static void mem_cgroup_end_move(struct mem_cgroup *memcg)
 {
-	int cpu;
-
-	if (!memcg)
-		return;
-	get_online_cpus();
-	spin_lock(&memcg->pcp_counter_lock);
-	for_each_online_cpu(cpu)
-		per_cpu(memcg->stat->count[MEM_CGROUP_ON_MOVE], cpu) -= 1;
-	memcg->nocpu_base.count[MEM_CGROUP_ON_MOVE] -= 1;
-	spin_unlock(&memcg->pcp_counter_lock);
-	put_online_cpus();
+	/*
+	 * Now, mem_cgroup_clear_mc() may call this function with NULL.
+	 * We check NULL in callee rather than caller.
+	 */
+	if (memcg) {
+		atomic_dec(&memcg_moving);
+		atomic_dec(&memcg->moving_account);
+	}
 }
+
 /*
  * 2 routines for checking "mem" is under move_account() or not.
  *
- * mem_cgroup_stealed() - checking a cgroup is mc.from or not. This is used
- *			  for avoiding race in accounting. If true,
+ * mem_cgroup_stolen() -  checking whether a cgroup is mc.from or not. This
+ *			  is used for avoiding races in accounting.  If true,
  *			  pc->mem_cgroup may be overwritten.
  *
  * mem_cgroup_under_move() - checking a cgroup is mc.from or mc.to or
@@ -1326,10 +1341,10 @@
  *			  waiting at hith-memory prressure caused by "move".
  */
 
-static bool mem_cgroup_stealed(struct mem_cgroup *memcg)
+static bool mem_cgroup_stolen(struct mem_cgroup *memcg)
 {
 	VM_BUG_ON(!rcu_read_lock_held());
-	return this_cpu_read(memcg->stat->count[MEM_CGROUP_ON_MOVE]) > 0;
+	return atomic_read(&memcg->moving_account) > 0;
 }
 
 static bool mem_cgroup_under_move(struct mem_cgroup *memcg)
@@ -1370,6 +1385,24 @@
 	return false;
 }
 
+/*
+ * Take this lock when
+ * - a code tries to modify page's memcg while it's USED.
+ * - a code tries to modify page state accounting in a memcg.
+ * see mem_cgroup_stolen(), too.
+ */
+static void move_lock_mem_cgroup(struct mem_cgroup *memcg,
+				  unsigned long *flags)
+{
+	spin_lock_irqsave(&memcg->move_lock, *flags);
+}
+
+static void move_unlock_mem_cgroup(struct mem_cgroup *memcg,
+				unsigned long *flags)
+{
+	spin_unlock_irqrestore(&memcg->move_lock, *flags);
+}
+
 /**
  * mem_cgroup_print_oom_info: Called from OOM with tasklist_lock held in read mode.
  * @memcg: The memory cgroup that went over limit
@@ -1393,7 +1426,6 @@
 	if (!memcg || !p)
 		return;
 
-
 	rcu_read_lock();
 
 	mem_cgrp = memcg->css.cgroup;
@@ -1772,22 +1804,22 @@
 static DECLARE_WAIT_QUEUE_HEAD(memcg_oom_waitq);
 
 struct oom_wait_info {
-	struct mem_cgroup *mem;
+	struct mem_cgroup *memcg;
 	wait_queue_t	wait;
 };
 
 static int memcg_oom_wake_function(wait_queue_t *wait,
 	unsigned mode, int sync, void *arg)
 {
-	struct mem_cgroup *wake_memcg = (struct mem_cgroup *)arg,
-			  *oom_wait_memcg;
+	struct mem_cgroup *wake_memcg = (struct mem_cgroup *)arg;
+	struct mem_cgroup *oom_wait_memcg;
 	struct oom_wait_info *oom_wait_info;
 
 	oom_wait_info = container_of(wait, struct oom_wait_info, wait);
-	oom_wait_memcg = oom_wait_info->mem;
+	oom_wait_memcg = oom_wait_info->memcg;
 
 	/*
-	 * Both of oom_wait_info->mem and wake_mem are stable under us.
+	 * Both of oom_wait_info->memcg and wake_memcg are stable under us.
 	 * Then we can use css_is_ancestor without taking care of RCU.
 	 */
 	if (!mem_cgroup_same_or_subtree(oom_wait_memcg, wake_memcg)
@@ -1811,12 +1843,12 @@
 /*
  * try to call OOM killer. returns false if we should exit memory-reclaim loop.
  */
-bool mem_cgroup_handle_oom(struct mem_cgroup *memcg, gfp_t mask)
+bool mem_cgroup_handle_oom(struct mem_cgroup *memcg, gfp_t mask, int order)
 {
 	struct oom_wait_info owait;
 	bool locked, need_to_kill;
 
-	owait.mem = memcg;
+	owait.memcg = memcg;
 	owait.wait.flags = 0;
 	owait.wait.func = memcg_oom_wake_function;
 	owait.wait.private = current;
@@ -1841,7 +1873,7 @@
 
 	if (need_to_kill) {
 		finish_wait(&memcg_oom_waitq, &owait.wait);
-		mem_cgroup_out_of_memory(memcg, mask);
+		mem_cgroup_out_of_memory(memcg, mask, order);
 	} else {
 		schedule();
 		finish_wait(&memcg_oom_waitq, &owait.wait);
@@ -1881,41 +1913,66 @@
  * by flags.
  *
  * Considering "move", this is an only case we see a race. To make the race
- * small, we check MEM_CGROUP_ON_MOVE percpu value and detect there are
- * possibility of race condition. If there is, we take a lock.
+ * small, we check mm->moving_account and detect there are possibility of race
+ * If there is, we take a lock.
  */
 
+void __mem_cgroup_begin_update_page_stat(struct page *page,
+				bool *locked, unsigned long *flags)
+{
+	struct mem_cgroup *memcg;
+	struct page_cgroup *pc;
+
+	pc = lookup_page_cgroup(page);
+again:
+	memcg = pc->mem_cgroup;
+	if (unlikely(!memcg || !PageCgroupUsed(pc)))
+		return;
+	/*
+	 * If this memory cgroup is not under account moving, we don't
+	 * need to take move_lock_page_cgroup(). Because we already hold
+	 * rcu_read_lock(), any calls to move_account will be delayed until
+	 * rcu_read_unlock() if mem_cgroup_stolen() == true.
+	 */
+	if (!mem_cgroup_stolen(memcg))
+		return;
+
+	move_lock_mem_cgroup(memcg, flags);
+	if (memcg != pc->mem_cgroup || !PageCgroupUsed(pc)) {
+		move_unlock_mem_cgroup(memcg, flags);
+		goto again;
+	}
+	*locked = true;
+}
+
+void __mem_cgroup_end_update_page_stat(struct page *page, unsigned long *flags)
+{
+	struct page_cgroup *pc = lookup_page_cgroup(page);
+
+	/*
+	 * It's guaranteed that pc->mem_cgroup never changes while
+	 * lock is held because a routine modifies pc->mem_cgroup
+	 * should take move_lock_page_cgroup().
+	 */
+	move_unlock_mem_cgroup(pc->mem_cgroup, flags);
+}
+
 void mem_cgroup_update_page_stat(struct page *page,
 				 enum mem_cgroup_page_stat_item idx, int val)
 {
 	struct mem_cgroup *memcg;
 	struct page_cgroup *pc = lookup_page_cgroup(page);
-	bool need_unlock = false;
 	unsigned long uninitialized_var(flags);
 
 	if (mem_cgroup_disabled())
 		return;
 
-	rcu_read_lock();
 	memcg = pc->mem_cgroup;
 	if (unlikely(!memcg || !PageCgroupUsed(pc)))
-		goto out;
-	/* pc->mem_cgroup is unstable ? */
-	if (unlikely(mem_cgroup_stealed(memcg)) || PageTransHuge(page)) {
-		/* take a lock against to access pc->mem_cgroup */
-		move_lock_page_cgroup(pc, &flags);
-		need_unlock = true;
-		memcg = pc->mem_cgroup;
-		if (!memcg || !PageCgroupUsed(pc))
-			goto out;
-	}
+		return;
 
 	switch (idx) {
 	case MEMCG_NR_FILE_MAPPED:
-		if (val > 0)
-			SetPageCgroupFileMapped(pc);
-		else if (!page_mapped(page))
-			ClearPageCgroupFileMapped(pc);
 		idx = MEM_CGROUP_STAT_FILE_MAPPED;
 		break;
 	default:
@@ -1923,14 +1980,7 @@
 	}
 
 	this_cpu_add(memcg->stat->count[idx], val);
-
-out:
-	if (unlikely(need_unlock))
-		move_unlock_page_cgroup(pc, &flags);
-	rcu_read_unlock();
-	return;
 }
-EXPORT_SYMBOL(mem_cgroup_update_page_stat);
 
 /*
  * size of first charge trial. "32" comes from vmscan.c's magic value.
@@ -2101,17 +2151,6 @@
 		per_cpu(memcg->stat->events[i], cpu) = 0;
 		memcg->nocpu_base.events[i] += x;
 	}
-	/* need to clear ON_MOVE value, works as a kind of lock. */
-	per_cpu(memcg->stat->count[MEM_CGROUP_ON_MOVE], cpu) = 0;
-	spin_unlock(&memcg->pcp_counter_lock);
-}
-
-static void synchronize_mem_cgroup_on_move(struct mem_cgroup *memcg, int cpu)
-{
-	int idx = MEM_CGROUP_ON_MOVE;
-
-	spin_lock(&memcg->pcp_counter_lock);
-	per_cpu(memcg->stat->count[idx], cpu) = memcg->nocpu_base.count[idx];
 	spin_unlock(&memcg->pcp_counter_lock);
 }
 
@@ -2123,11 +2162,8 @@
 	struct memcg_stock_pcp *stock;
 	struct mem_cgroup *iter;
 
-	if ((action == CPU_ONLINE)) {
-		for_each_mem_cgroup(iter)
-			synchronize_mem_cgroup_on_move(iter, cpu);
+	if (action == CPU_ONLINE)
 		return NOTIFY_OK;
-	}
 
 	if ((action != CPU_DEAD) || action != CPU_DEAD_FROZEN)
 		return NOTIFY_OK;
@@ -2212,7 +2248,7 @@
 	if (!oom_check)
 		return CHARGE_NOMEM;
 	/* check OOM */
-	if (!mem_cgroup_handle_oom(mem_over_limit, gfp_mask))
+	if (!mem_cgroup_handle_oom(mem_over_limit, gfp_mask, get_order(csize)))
 		return CHARGE_OOM_DIE;
 
 	return CHARGE_RETRY;
@@ -2446,6 +2482,7 @@
 {
 	struct zone *uninitialized_var(zone);
 	bool was_on_lru = false;
+	bool anon;
 
 	lock_page_cgroup(pc);
 	if (unlikely(PageCgroupUsed(pc))) {
@@ -2481,19 +2518,7 @@
 	 * See mem_cgroup_add_lru_list(), etc.
  	 */
 	smp_wmb();
-	switch (ctype) {
-	case MEM_CGROUP_CHARGE_TYPE_CACHE:
-	case MEM_CGROUP_CHARGE_TYPE_SHMEM:
-		SetPageCgroupCache(pc);
-		SetPageCgroupUsed(pc);
-		break;
-	case MEM_CGROUP_CHARGE_TYPE_MAPPED:
-		ClearPageCgroupCache(pc);
-		SetPageCgroupUsed(pc);
-		break;
-	default:
-		break;
-	}
+	SetPageCgroupUsed(pc);
 
 	if (lrucare) {
 		if (was_on_lru) {
@@ -2504,7 +2529,12 @@
 		spin_unlock_irq(&zone->lru_lock);
 	}
 
-	mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), nr_pages);
+	if (ctype == MEM_CGROUP_CHARGE_TYPE_MAPPED)
+		anon = true;
+	else
+		anon = false;
+
+	mem_cgroup_charge_statistics(memcg, anon, nr_pages);
 	unlock_page_cgroup(pc);
 
 	/*
@@ -2517,8 +2547,7 @@
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 
-#define PCGF_NOCOPY_AT_SPLIT ((1 << PCG_LOCK) | (1 << PCG_MOVE_LOCK) |\
-			(1 << PCG_MIGRATION))
+#define PCGF_NOCOPY_AT_SPLIT ((1 << PCG_LOCK) | (1 << PCG_MIGRATION))
 /*
  * Because tail pages are not marked as "used", set it. We're under
  * zone->lru_lock, 'splitting on pmd' and compound_lock.
@@ -2569,6 +2598,7 @@
 {
 	unsigned long flags;
 	int ret;
+	bool anon = PageAnon(page);
 
 	VM_BUG_ON(from == to);
 	VM_BUG_ON(PageLRU(page));
@@ -2588,23 +2618,23 @@
 	if (!PageCgroupUsed(pc) || pc->mem_cgroup != from)
 		goto unlock;
 
-	move_lock_page_cgroup(pc, &flags);
+	move_lock_mem_cgroup(from, &flags);
 
-	if (PageCgroupFileMapped(pc)) {
+	if (!anon && page_mapped(page)) {
 		/* Update mapped_file data for mem_cgroup */
 		preempt_disable();
 		__this_cpu_dec(from->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]);
 		__this_cpu_inc(to->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]);
 		preempt_enable();
 	}
-	mem_cgroup_charge_statistics(from, PageCgroupCache(pc), -nr_pages);
+	mem_cgroup_charge_statistics(from, anon, -nr_pages);
 	if (uncharge)
 		/* This is not "cancel", but cancel_charge does all we need. */
 		__mem_cgroup_cancel_charge(from, nr_pages);
 
 	/* caller should have done css_get */
 	pc->mem_cgroup = to;
-	mem_cgroup_charge_statistics(to, PageCgroupCache(pc), nr_pages);
+	mem_cgroup_charge_statistics(to, anon, nr_pages);
 	/*
 	 * We charges against "to" which may not have any tasks. Then, "to"
 	 * can be under rmdir(). But in current implementation, caller of
@@ -2612,7 +2642,7 @@
 	 * guaranteed that "to" is never removed. So, we don't check rmdir
 	 * status here.
 	 */
-	move_unlock_page_cgroup(pc, &flags);
+	move_unlock_mem_cgroup(from, &flags);
 	ret = 0;
 unlock:
 	unlock_page_cgroup(pc);
@@ -2914,7 +2944,6 @@
 		res_counter_uncharge(&memcg->memsw, nr_pages * PAGE_SIZE);
 	if (unlikely(batch->memcg != memcg))
 		memcg_oom_recover(memcg);
-	return;
 }
 
 /*
@@ -2926,6 +2955,7 @@
 	struct mem_cgroup *memcg = NULL;
 	unsigned int nr_pages = 1;
 	struct page_cgroup *pc;
+	bool anon;
 
 	if (mem_cgroup_disabled())
 		return NULL;
@@ -2951,8 +2981,17 @@
 	if (!PageCgroupUsed(pc))
 		goto unlock_out;
 
+	anon = PageAnon(page);
+
 	switch (ctype) {
 	case MEM_CGROUP_CHARGE_TYPE_MAPPED:
+		/*
+		 * Generally PageAnon tells if it's the anon statistics to be
+		 * updated; but sometimes e.g. mem_cgroup_uncharge_page() is
+		 * used before page reached the stage of being marked PageAnon.
+		 */
+		anon = true;
+		/* fallthrough */
 	case MEM_CGROUP_CHARGE_TYPE_DROP:
 		/* See mem_cgroup_prepare_migration() */
 		if (page_mapped(page) || PageCgroupMigration(pc))
@@ -2969,7 +3008,7 @@
 		break;
 	}
 
-	mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), -nr_pages);
+	mem_cgroup_charge_statistics(memcg, anon, -nr_pages);
 
 	ClearPageCgroupUsed(pc);
 	/*
@@ -3276,6 +3315,7 @@
 {
 	struct page *used, *unused;
 	struct page_cgroup *pc;
+	bool anon;
 
 	if (!memcg)
 		return;
@@ -3297,8 +3337,10 @@
 	lock_page_cgroup(pc);
 	ClearPageCgroupMigration(pc);
 	unlock_page_cgroup(pc);
-
-	__mem_cgroup_uncharge_common(unused, MEM_CGROUP_CHARGE_TYPE_FORCE);
+	anon = PageAnon(used);
+	__mem_cgroup_uncharge_common(unused,
+		anon ? MEM_CGROUP_CHARGE_TYPE_MAPPED
+		     : MEM_CGROUP_CHARGE_TYPE_CACHE);
 
 	/*
 	 * If a page is a file cache, radix-tree replacement is very atomic
@@ -3308,7 +3350,7 @@
 	 * and USED bit check in mem_cgroup_uncharge_page() will do enough
 	 * check. (see prepare_charge() also)
 	 */
-	if (PageAnon(used))
+	if (anon)
 		mem_cgroup_uncharge_page(used);
 	/*
 	 * At migration, we may charge account against cgroup which has no
@@ -3338,7 +3380,7 @@
 	/* fix accounting on old pages */
 	lock_page_cgroup(pc);
 	memcg = pc->mem_cgroup;
-	mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), -1);
+	mem_cgroup_charge_statistics(memcg, false, -1);
 	ClearPageCgroupUsed(pc);
 	unlock_page_cgroup(pc);
 
@@ -3549,7 +3591,7 @@
 			break;
 
 		nr_scanned = 0;
-		reclaimed = mem_cgroup_soft_reclaim(mz->mem, zone,
+		reclaimed = mem_cgroup_soft_reclaim(mz->memcg, zone,
 						    gfp_mask, &nr_scanned);
 		nr_reclaimed += reclaimed;
 		*total_scanned += nr_scanned;
@@ -3576,13 +3618,13 @@
 				next_mz =
 				__mem_cgroup_largest_soft_limit_node(mctz);
 				if (next_mz == mz)
-					css_put(&next_mz->mem->css);
+					css_put(&next_mz->memcg->css);
 				else /* next_mz == NULL or other memcg */
 					break;
 			} while (1);
 		}
-		__mem_cgroup_remove_exceeded(mz->mem, mz, mctz);
-		excess = res_counter_soft_limit_excess(&mz->mem->res);
+		__mem_cgroup_remove_exceeded(mz->memcg, mz, mctz);
+		excess = res_counter_soft_limit_excess(&mz->memcg->res);
 		/*
 		 * One school of thought says that we should not add
 		 * back the node to the tree if reclaim returns 0.
@@ -3592,9 +3634,9 @@
 		 * term TODO.
 		 */
 		/* If excess == 0, no tree ops */
-		__mem_cgroup_insert_exceeded(mz->mem, mz, mctz, excess);
+		__mem_cgroup_insert_exceeded(mz->memcg, mz, mctz, excess);
 		spin_unlock(&mctz->lock);
-		css_put(&mz->mem->css);
+		css_put(&mz->memcg->css);
 		loop++;
 		/*
 		 * Could not reclaim anything and there are no more
@@ -3607,7 +3649,7 @@
 			break;
 	} while (!nr_reclaimed);
 	if (next_mz)
-		css_put(&next_mz->mem->css);
+		css_put(&next_mz->memcg->css);
 	return nr_reclaimed;
 }
 
@@ -3629,7 +3671,7 @@
 	mz = mem_cgroup_zoneinfo(memcg, node, zid);
 	list = &mz->lruvec.lists[lru];
 
-	loop = MEM_CGROUP_ZSTAT(mz, lru);
+	loop = mz->lru_size[lru];
 	/* give some margin against EBUSY etc...*/
 	loop += 256;
 	busy = NULL;
@@ -3703,10 +3745,10 @@
 		mem_cgroup_start_move(memcg);
 		for_each_node_state(node, N_HIGH_MEMORY) {
 			for (zid = 0; !ret && zid < MAX_NR_ZONES; zid++) {
-				enum lru_list l;
-				for_each_lru(l) {
+				enum lru_list lru;
+				for_each_lru(lru) {
 					ret = mem_cgroup_force_empty_list(memcg,
-							node, zid, l);
+							node, zid, lru);
 					if (ret)
 						break;
 				}
@@ -3860,7 +3902,6 @@
 		break;
 	default:
 		BUG();
-		break;
 	}
 	return val;
 }
@@ -3939,7 +3980,6 @@
 out:
 	*mem_limit = min_limit;
 	*memsw_limit = min_memsw_limit;
-	return;
 }
 
 static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
@@ -4098,38 +4138,38 @@
 	unsigned long total_nr, file_nr, anon_nr, unevictable_nr;
 	unsigned long node_nr;
 	struct cgroup *cont = m->private;
-	struct mem_cgroup *mem_cont = mem_cgroup_from_cont(cont);
+	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
 
-	total_nr = mem_cgroup_nr_lru_pages(mem_cont, LRU_ALL);
+	total_nr = mem_cgroup_nr_lru_pages(memcg, LRU_ALL);
 	seq_printf(m, "total=%lu", total_nr);
 	for_each_node_state(nid, N_HIGH_MEMORY) {
-		node_nr = mem_cgroup_node_nr_lru_pages(mem_cont, nid, LRU_ALL);
+		node_nr = mem_cgroup_node_nr_lru_pages(memcg, nid, LRU_ALL);
 		seq_printf(m, " N%d=%lu", nid, node_nr);
 	}
 	seq_putc(m, '\n');
 
-	file_nr = mem_cgroup_nr_lru_pages(mem_cont, LRU_ALL_FILE);
+	file_nr = mem_cgroup_nr_lru_pages(memcg, LRU_ALL_FILE);
 	seq_printf(m, "file=%lu", file_nr);
 	for_each_node_state(nid, N_HIGH_MEMORY) {
-		node_nr = mem_cgroup_node_nr_lru_pages(mem_cont, nid,
+		node_nr = mem_cgroup_node_nr_lru_pages(memcg, nid,
 				LRU_ALL_FILE);
 		seq_printf(m, " N%d=%lu", nid, node_nr);
 	}
 	seq_putc(m, '\n');
 
-	anon_nr = mem_cgroup_nr_lru_pages(mem_cont, LRU_ALL_ANON);
+	anon_nr = mem_cgroup_nr_lru_pages(memcg, LRU_ALL_ANON);
 	seq_printf(m, "anon=%lu", anon_nr);
 	for_each_node_state(nid, N_HIGH_MEMORY) {
-		node_nr = mem_cgroup_node_nr_lru_pages(mem_cont, nid,
+		node_nr = mem_cgroup_node_nr_lru_pages(memcg, nid,
 				LRU_ALL_ANON);
 		seq_printf(m, " N%d=%lu", nid, node_nr);
 	}
 	seq_putc(m, '\n');
 
-	unevictable_nr = mem_cgroup_nr_lru_pages(mem_cont, BIT(LRU_UNEVICTABLE));
+	unevictable_nr = mem_cgroup_nr_lru_pages(memcg, BIT(LRU_UNEVICTABLE));
 	seq_printf(m, "unevictable=%lu", unevictable_nr);
 	for_each_node_state(nid, N_HIGH_MEMORY) {
-		node_nr = mem_cgroup_node_nr_lru_pages(mem_cont, nid,
+		node_nr = mem_cgroup_node_nr_lru_pages(memcg, nid,
 				BIT(LRU_UNEVICTABLE));
 		seq_printf(m, " N%d=%lu", nid, node_nr);
 	}
@@ -4141,12 +4181,12 @@
 static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
 				 struct cgroup_map_cb *cb)
 {
-	struct mem_cgroup *mem_cont = mem_cgroup_from_cont(cont);
+	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
 	struct mcs_total_stat mystat;
 	int i;
 
 	memset(&mystat, 0, sizeof(mystat));
-	mem_cgroup_get_local_stat(mem_cont, &mystat);
+	mem_cgroup_get_local_stat(memcg, &mystat);
 
 
 	for (i = 0; i < NR_MCS_STAT; i++) {
@@ -4158,14 +4198,14 @@
 	/* Hierarchical information */
 	{
 		unsigned long long limit, memsw_limit;
-		memcg_get_hierarchical_limit(mem_cont, &limit, &memsw_limit);
+		memcg_get_hierarchical_limit(memcg, &limit, &memsw_limit);
 		cb->fill(cb, "hierarchical_memory_limit", limit);
 		if (do_swap_account)
 			cb->fill(cb, "hierarchical_memsw_limit", memsw_limit);
 	}
 
 	memset(&mystat, 0, sizeof(mystat));
-	mem_cgroup_get_total_stat(mem_cont, &mystat);
+	mem_cgroup_get_total_stat(memcg, &mystat);
 	for (i = 0; i < NR_MCS_STAT; i++) {
 		if (i == MCS_SWAP && !do_swap_account)
 			continue;
@@ -4181,7 +4221,7 @@
 
 		for_each_online_node(nid)
 			for (zid = 0; zid < MAX_NR_ZONES; zid++) {
-				mz = mem_cgroup_zoneinfo(mem_cont, nid, zid);
+				mz = mem_cgroup_zoneinfo(memcg, nid, zid);
 
 				recent_rotated[0] +=
 					mz->reclaim_stat.recent_rotated[0];
@@ -4426,12 +4466,6 @@
 	else
 		BUG();
 
-	/*
-	 * Something went wrong if we trying to unregister a threshold
-	 * if we don't have thresholds
-	 */
-	BUG_ON(!thresholds);
-
 	if (!thresholds->primary)
 		goto unlock;
 
@@ -4736,7 +4770,7 @@
 {
 	struct mem_cgroup_per_node *pn;
 	struct mem_cgroup_per_zone *mz;
-	enum lru_list l;
+	enum lru_list lru;
 	int zone, tmp = node;
 	/*
 	 * This routine is called against possible nodes.
@@ -4754,11 +4788,11 @@
 
 	for (zone = 0; zone < MAX_NR_ZONES; zone++) {
 		mz = &pn->zoneinfo[zone];
-		for_each_lru(l)
-			INIT_LIST_HEAD(&mz->lruvec.lists[l]);
+		for_each_lru(lru)
+			INIT_LIST_HEAD(&mz->lruvec.lists[lru]);
 		mz->usage_in_excess = 0;
 		mz->on_tree = false;
-		mz->mem = memcg;
+		mz->memcg = memcg;
 	}
 	memcg->info.nodeinfo[node] = pn;
 	return 0;
@@ -4771,29 +4805,29 @@
 
 static struct mem_cgroup *mem_cgroup_alloc(void)
 {
-	struct mem_cgroup *mem;
+	struct mem_cgroup *memcg;
 	int size = sizeof(struct mem_cgroup);
 
 	/* Can be very big if MAX_NUMNODES is very big */
 	if (size < PAGE_SIZE)
-		mem = kzalloc(size, GFP_KERNEL);
+		memcg = kzalloc(size, GFP_KERNEL);
 	else
-		mem = vzalloc(size);
+		memcg = vzalloc(size);
 
-	if (!mem)
+	if (!memcg)
 		return NULL;
 
-	mem->stat = alloc_percpu(struct mem_cgroup_stat_cpu);
-	if (!mem->stat)
+	memcg->stat = alloc_percpu(struct mem_cgroup_stat_cpu);
+	if (!memcg->stat)
 		goto out_free;
-	spin_lock_init(&mem->pcp_counter_lock);
-	return mem;
+	spin_lock_init(&memcg->pcp_counter_lock);
+	return memcg;
 
 out_free:
 	if (size < PAGE_SIZE)
-		kfree(mem);
+		kfree(memcg);
 	else
-		vfree(mem);
+		vfree(memcg);
 	return NULL;
 }
 
@@ -4981,6 +5015,7 @@
 	atomic_set(&memcg->refcnt, 1);
 	memcg->move_charge_at_immigrate = 0;
 	mutex_init(&memcg->thresholds_lock);
+	spin_lock_init(&memcg->move_lock);
 	return &memcg->css;
 free_out:
 	__mem_cgroup_free(memcg);
@@ -5075,7 +5110,7 @@
 }
 
 /**
- * is_target_pte_for_mc - check a pte whether it is valid for move charge
+ * get_mctgt_type - get target type of moving charge
  * @vma: the vma the pte to be checked belongs
  * @addr: the address corresponding to the pte to be checked
  * @ptent: the pte to be checked
@@ -5098,7 +5133,7 @@
 };
 
 enum mc_target_type {
-	MC_TARGET_NONE,	/* not used */
+	MC_TARGET_NONE = 0,
 	MC_TARGET_PAGE,
 	MC_TARGET_SWAP,
 };
@@ -5179,12 +5214,12 @@
 	return page;
 }
 
-static int is_target_pte_for_mc(struct vm_area_struct *vma,
+static enum mc_target_type get_mctgt_type(struct vm_area_struct *vma,
 		unsigned long addr, pte_t ptent, union mc_target *target)
 {
 	struct page *page = NULL;
 	struct page_cgroup *pc;
-	int ret = 0;
+	enum mc_target_type ret = MC_TARGET_NONE;
 	swp_entry_t ent = { .val = 0 };
 
 	if (pte_present(ptent))
@@ -5195,7 +5230,7 @@
 		page = mc_handle_file_pte(vma, addr, ptent, &ent);
 
 	if (!page && !ent.val)
-		return 0;
+		return ret;
 	if (page) {
 		pc = lookup_page_cgroup(page);
 		/*
@@ -5221,6 +5256,41 @@
 	return ret;
 }
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+/*
+ * We don't consider swapping or file mapped pages because THP does not
+ * support them for now.
+ * Caller should make sure that pmd_trans_huge(pmd) is true.
+ */
+static enum mc_target_type get_mctgt_type_thp(struct vm_area_struct *vma,
+		unsigned long addr, pmd_t pmd, union mc_target *target)
+{
+	struct page *page = NULL;
+	struct page_cgroup *pc;
+	enum mc_target_type ret = MC_TARGET_NONE;
+
+	page = pmd_page(pmd);
+	VM_BUG_ON(!page || !PageHead(page));
+	if (!move_anon())
+		return ret;
+	pc = lookup_page_cgroup(page);
+	if (PageCgroupUsed(pc) && pc->mem_cgroup == mc.from) {
+		ret = MC_TARGET_PAGE;
+		if (target) {
+			get_page(page);
+			target->page = page;
+		}
+	}
+	return ret;
+}
+#else
+static inline enum mc_target_type get_mctgt_type_thp(struct vm_area_struct *vma,
+		unsigned long addr, pmd_t pmd, union mc_target *target)
+{
+	return MC_TARGET_NONE;
+}
+#endif
+
 static int mem_cgroup_count_precharge_pte_range(pmd_t *pmd,
 					unsigned long addr, unsigned long end,
 					struct mm_walk *walk)
@@ -5229,11 +5299,18 @@
 	pte_t *pte;
 	spinlock_t *ptl;
 
-	split_huge_page_pmd(walk->mm, pmd);
+	if (pmd_trans_huge_lock(pmd, vma) == 1) {
+		if (get_mctgt_type_thp(vma, addr, *pmd, NULL) == MC_TARGET_PAGE)
+			mc.precharge += HPAGE_PMD_NR;
+		spin_unlock(&vma->vm_mm->page_table_lock);
+		return 0;
+	}
 
+	if (pmd_trans_unstable(pmd))
+		return 0;
 	pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
 	for (; addr != end; pte++, addr += PAGE_SIZE)
-		if (is_target_pte_for_mc(vma, addr, *pte, NULL))
+		if (get_mctgt_type(vma, addr, *pte, NULL))
 			mc.precharge++;	/* increment precharge temporarily */
 	pte_unmap_unlock(pte - 1, ptl);
 	cond_resched();
@@ -5388,23 +5465,57 @@
 	struct vm_area_struct *vma = walk->private;
 	pte_t *pte;
 	spinlock_t *ptl;
+	enum mc_target_type target_type;
+	union mc_target target;
+	struct page *page;
+	struct page_cgroup *pc;
 
-	split_huge_page_pmd(walk->mm, pmd);
+	/*
+	 * We don't take compound_lock() here but no race with splitting thp
+	 * happens because:
+	 *  - if pmd_trans_huge_lock() returns 1, the relevant thp is not
+	 *    under splitting, which means there's no concurrent thp split,
+	 *  - if another thread runs into split_huge_page() just after we
+	 *    entered this if-block, the thread must wait for page table lock
+	 *    to be unlocked in __split_huge_page_splitting(), where the main
+	 *    part of thp split is not executed yet.
+	 */
+	if (pmd_trans_huge_lock(pmd, vma) == 1) {
+		if (!mc.precharge) {
+			spin_unlock(&vma->vm_mm->page_table_lock);
+			return 0;
+		}
+		target_type = get_mctgt_type_thp(vma, addr, *pmd, &target);
+		if (target_type == MC_TARGET_PAGE) {
+			page = target.page;
+			if (!isolate_lru_page(page)) {
+				pc = lookup_page_cgroup(page);
+				if (!mem_cgroup_move_account(page, HPAGE_PMD_NR,
+							     pc, mc.from, mc.to,
+							     false)) {
+					mc.precharge -= HPAGE_PMD_NR;
+					mc.moved_charge += HPAGE_PMD_NR;
+				}
+				putback_lru_page(page);
+			}
+			put_page(page);
+		}
+		spin_unlock(&vma->vm_mm->page_table_lock);
+		return 0;
+	}
+
+	if (pmd_trans_unstable(pmd))
+		return 0;
 retry:
 	pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
 	for (; addr != end; addr += PAGE_SIZE) {
 		pte_t ptent = *(pte++);
-		union mc_target target;
-		int type;
-		struct page *page;
-		struct page_cgroup *pc;
 		swp_entry_t ent;
 
 		if (!mc.precharge)
 			break;
 
-		type = is_target_pte_for_mc(vma, addr, ptent, &target);
-		switch (type) {
+		switch (get_mctgt_type(vma, addr, ptent, &target)) {
 		case MC_TARGET_PAGE:
 			page = target.page;
 			if (isolate_lru_page(page))
@@ -5417,7 +5528,7 @@
 				mc.moved_charge++;
 			}
 			putback_lru_page(page);
-put:			/* is_target_pte_for_mc() gets the page */
+put:			/* get_mctgt_type() gets the page */
 			put_page(page);
 			break;
 		case MC_TARGET_SWAP:
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 56080ea..97cc273 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -187,33 +187,40 @@
 EXPORT_SYMBOL_GPL(hwpoison_filter);
 
 /*
- * Send all the processes who have the page mapped an ``action optional''
- * signal.
+ * Send all the processes who have the page mapped a signal.
+ * ``action optional'' if they are not immediately affected by the error
+ * ``action required'' if error happened in current execution context
  */
-static int kill_proc_ao(struct task_struct *t, unsigned long addr, int trapno,
-			unsigned long pfn, struct page *page)
+static int kill_proc(struct task_struct *t, unsigned long addr, int trapno,
+			unsigned long pfn, struct page *page, int flags)
 {
 	struct siginfo si;
 	int ret;
 
 	printk(KERN_ERR
-		"MCE %#lx: Killing %s:%d early due to hardware memory corruption\n",
+		"MCE %#lx: Killing %s:%d due to hardware memory corruption\n",
 		pfn, t->comm, t->pid);
 	si.si_signo = SIGBUS;
 	si.si_errno = 0;
-	si.si_code = BUS_MCEERR_AO;
 	si.si_addr = (void *)addr;
 #ifdef __ARCH_SI_TRAPNO
 	si.si_trapno = trapno;
 #endif
 	si.si_addr_lsb = compound_trans_order(compound_head(page)) + PAGE_SHIFT;
-	/*
-	 * Don't use force here, it's convenient if the signal
-	 * can be temporarily blocked.
-	 * This could cause a loop when the user sets SIGBUS
-	 * to SIG_IGN, but hopefully no one will do that?
-	 */
-	ret = send_sig_info(SIGBUS, &si, t);  /* synchronous? */
+
+	if ((flags & MF_ACTION_REQUIRED) && t == current) {
+		si.si_code = BUS_MCEERR_AR;
+		ret = force_sig_info(SIGBUS, &si, t);
+	} else {
+		/*
+		 * Don't use force here, it's convenient if the signal
+		 * can be temporarily blocked.
+		 * This could cause a loop when the user sets SIGBUS
+		 * to SIG_IGN, but hopefully no one will do that?
+		 */
+		si.si_code = BUS_MCEERR_AO;
+		ret = send_sig_info(SIGBUS, &si, t);  /* synchronous? */
+	}
 	if (ret < 0)
 		printk(KERN_INFO "MCE: Error sending signal to %s:%d: %d\n",
 		       t->comm, t->pid, ret);
@@ -338,8 +345,9 @@
  * Also when FAIL is set do a force kill because something went
  * wrong earlier.
  */
-static void kill_procs_ao(struct list_head *to_kill, int doit, int trapno,
-			  int fail, struct page *page, unsigned long pfn)
+static void kill_procs(struct list_head *to_kill, int doit, int trapno,
+			  int fail, struct page *page, unsigned long pfn,
+			  int flags)
 {
 	struct to_kill *tk, *next;
 
@@ -363,8 +371,8 @@
 			 * check for that, but we need to tell the
 			 * process anyways.
 			 */
-			else if (kill_proc_ao(tk->tsk, tk->addr, trapno,
-					      pfn, page) < 0)
+			else if (kill_proc(tk->tsk, tk->addr, trapno,
+					      pfn, page, flags) < 0)
 				printk(KERN_ERR
 		"MCE %#lx: Cannot send advisory machine check signal to %s:%d\n",
 					pfn, tk->tsk->comm, tk->tsk->pid);
@@ -844,7 +852,7 @@
  * the pages and send SIGBUS to the processes if the data was dirty.
  */
 static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
-				  int trapno)
+				  int trapno, int flags)
 {
 	enum ttu_flags ttu = TTU_UNMAP | TTU_IGNORE_MLOCK | TTU_IGNORE_ACCESS;
 	struct address_space *mapping;
@@ -962,8 +970,8 @@
 	 * use a more force-full uncatchable kill to prevent
 	 * any accesses to the poisoned memory.
 	 */
-	kill_procs_ao(&tokill, !!PageDirty(ppage), trapno,
-		      ret != SWAP_SUCCESS, p, pfn);
+	kill_procs(&tokill, !!PageDirty(ppage), trapno,
+		      ret != SWAP_SUCCESS, p, pfn, flags);
 
 	return ret;
 }
@@ -984,7 +992,25 @@
 		ClearPageHWPoison(hpage + i);
 }
 
-int __memory_failure(unsigned long pfn, int trapno, int flags)
+/**
+ * memory_failure - Handle memory failure of a page.
+ * @pfn: Page Number of the corrupted page
+ * @trapno: Trap number reported in the signal to user space.
+ * @flags: fine tune action taken
+ *
+ * This function is called by the low level machine check code
+ * of an architecture when it detects hardware memory corruption
+ * of a page. It tries its best to recover, which includes
+ * dropping pages, killing processes etc.
+ *
+ * The function is primarily of use for corruptions that
+ * happen outside the current execution context (e.g. when
+ * detected by a background scrubber)
+ *
+ * Must run in process context (e.g. a work queue) with interrupts
+ * enabled and no spinlocks hold.
+ */
+int memory_failure(unsigned long pfn, int trapno, int flags)
 {
 	struct page_state *ps;
 	struct page *p;
@@ -1063,7 +1089,7 @@
 	 * The check (unnecessarily) ignores LRU pages being isolated and
 	 * walked by the page reclaim code, however that's not a big loss.
 	 */
-	if (!PageHuge(p) && !PageTransCompound(p)) {
+	if (!PageHuge(p) && !PageTransTail(p)) {
 		if (!PageLRU(p))
 			shake_page(p, 0);
 		if (!PageLRU(p)) {
@@ -1130,7 +1156,7 @@
 	 * Now take care of user space mappings.
 	 * Abort on fail: __delete_from_page_cache() assumes unmapped page.
 	 */
-	if (hwpoison_user_mappings(p, pfn, trapno) != SWAP_SUCCESS) {
+	if (hwpoison_user_mappings(p, pfn, trapno, flags) != SWAP_SUCCESS) {
 		printk(KERN_ERR "MCE %#lx: cannot unmap page, give up\n", pfn);
 		res = -EBUSY;
 		goto out;
@@ -1156,29 +1182,7 @@
 	unlock_page(hpage);
 	return res;
 }
-EXPORT_SYMBOL_GPL(__memory_failure);
-
-/**
- * memory_failure - Handle memory failure of a page.
- * @pfn: Page Number of the corrupted page
- * @trapno: Trap number reported in the signal to user space.
- *
- * This function is called by the low level machine check code
- * of an architecture when it detects hardware memory corruption
- * of a page. It tries its best to recover, which includes
- * dropping pages, killing processes etc.
- *
- * The function is primarily of use for corruptions that
- * happen outside the current execution context (e.g. when
- * detected by a background scrubber)
- *
- * Must run in process context (e.g. a work queue) with interrupts
- * enabled and no spinlocks hold.
- */
-void memory_failure(unsigned long pfn, int trapno)
-{
-	__memory_failure(pfn, trapno, 0);
-}
+EXPORT_SYMBOL_GPL(memory_failure);
 
 #define MEMORY_FAILURE_FIFO_ORDER	4
 #define MEMORY_FAILURE_FIFO_SIZE	(1 << MEMORY_FAILURE_FIFO_ORDER)
@@ -1251,7 +1255,7 @@
 		spin_unlock_irqrestore(&mf_cpu->lock, proc_flags);
 		if (!gotten)
 			break;
-		__memory_failure(entry.pfn, entry.trapno, entry.flags);
+		memory_failure(entry.pfn, entry.trapno, entry.flags);
 	}
 }
 
diff --git a/mm/memory.c b/mm/memory.c
index 347e5fa..6105f47 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -125,17 +125,17 @@
 
 #if defined(SPLIT_RSS_COUNTING)
 
-static void __sync_task_rss_stat(struct task_struct *task, struct mm_struct *mm)
+void sync_mm_rss(struct mm_struct *mm)
 {
 	int i;
 
 	for (i = 0; i < NR_MM_COUNTERS; i++) {
-		if (task->rss_stat.count[i]) {
-			add_mm_counter(mm, i, task->rss_stat.count[i]);
-			task->rss_stat.count[i] = 0;
+		if (current->rss_stat.count[i]) {
+			add_mm_counter(mm, i, current->rss_stat.count[i]);
+			current->rss_stat.count[i] = 0;
 		}
 	}
-	task->rss_stat.events = 0;
+	current->rss_stat.events = 0;
 }
 
 static void add_mm_counter_fast(struct mm_struct *mm, int member, int val)
@@ -157,30 +157,7 @@
 	if (unlikely(task != current))
 		return;
 	if (unlikely(task->rss_stat.events++ > TASK_RSS_EVENTS_THRESH))
-		__sync_task_rss_stat(task, task->mm);
-}
-
-unsigned long get_mm_counter(struct mm_struct *mm, int member)
-{
-	long val = 0;
-
-	/*
-	 * Don't use task->mm here...for avoiding to use task_get_mm()..
-	 * The caller must guarantee task->mm is not invalid.
-	 */
-	val = atomic_long_read(&mm->rss_stat.count[member]);
-	/*
-	 * counter is updated in asynchronous manner and may go to minus.
-	 * But it's never be expected number for users.
-	 */
-	if (val < 0)
-		return 0;
-	return (unsigned long)val;
-}
-
-void sync_mm_rss(struct task_struct *task, struct mm_struct *mm)
-{
-	__sync_task_rss_stat(task, mm);
+		sync_mm_rss(task->mm);
 }
 #else /* SPLIT_RSS_COUNTING */
 
@@ -661,7 +638,7 @@
 	int i;
 
 	if (current->mm == mm)
-		sync_mm_rss(current, mm);
+		sync_mm_rss(mm);
 	for (i = 0; i < NR_MM_COUNTERS; i++)
 		if (rss[i])
 			add_mm_counter(mm, i, rss[i]);
@@ -1247,16 +1224,24 @@
 	do {
 		next = pmd_addr_end(addr, end);
 		if (pmd_trans_huge(*pmd)) {
-			if (next-addr != HPAGE_PMD_SIZE) {
+			if (next - addr != HPAGE_PMD_SIZE) {
 				VM_BUG_ON(!rwsem_is_locked(&tlb->mm->mmap_sem));
 				split_huge_page_pmd(vma->vm_mm, pmd);
 			} else if (zap_huge_pmd(tlb, vma, pmd, addr))
-				continue;
+				goto next;
 			/* fall through */
 		}
-		if (pmd_none_or_clear_bad(pmd))
-			continue;
+		/*
+		 * Here there can be other concurrent MADV_DONTNEED or
+		 * trans huge page faults running, and if the pmd is
+		 * none or trans huge it can change under us. This is
+		 * because MADV_DONTNEED holds the mmap_sem in read
+		 * mode.
+		 */
+		if (pmd_none_or_trans_huge_or_clear_bad(pmd))
+			goto next;
 		next = zap_pte_range(tlb, vma, pmd, addr, next, details);
+next:
 		cond_resched();
 	} while (pmd++, addr = next, addr != end);
 
@@ -1282,10 +1267,10 @@
 	return addr;
 }
 
-static unsigned long unmap_page_range(struct mmu_gather *tlb,
-				struct vm_area_struct *vma,
-				unsigned long addr, unsigned long end,
-				struct zap_details *details)
+static void unmap_page_range(struct mmu_gather *tlb,
+			     struct vm_area_struct *vma,
+			     unsigned long addr, unsigned long end,
+			     struct zap_details *details)
 {
 	pgd_t *pgd;
 	unsigned long next;
@@ -1305,8 +1290,47 @@
 	} while (pgd++, addr = next, addr != end);
 	tlb_end_vma(tlb, vma);
 	mem_cgroup_uncharge_end();
+}
 
-	return addr;
+
+static void unmap_single_vma(struct mmu_gather *tlb,
+		struct vm_area_struct *vma, unsigned long start_addr,
+		unsigned long end_addr, unsigned long *nr_accounted,
+		struct zap_details *details)
+{
+	unsigned long start = max(vma->vm_start, start_addr);
+	unsigned long end;
+
+	if (start >= vma->vm_end)
+		return;
+	end = min(vma->vm_end, end_addr);
+	if (end <= vma->vm_start)
+		return;
+
+	if (vma->vm_flags & VM_ACCOUNT)
+		*nr_accounted += (end - start) >> PAGE_SHIFT;
+
+	if (unlikely(is_pfn_mapping(vma)))
+		untrack_pfn_vma(vma, 0, 0);
+
+	if (start != end) {
+		if (unlikely(is_vm_hugetlb_page(vma))) {
+			/*
+			 * It is undesirable to test vma->vm_file as it
+			 * should be non-null for valid hugetlb area.
+			 * However, vm_file will be NULL in the error
+			 * cleanup path of do_mmap_pgoff. When
+			 * hugetlbfs ->mmap method fails,
+			 * do_mmap_pgoff() nullifies vma->vm_file
+			 * before calling this function to clean up.
+			 * Since no pte has actually been setup, it is
+			 * safe to do nothing in this case.
+			 */
+			if (vma->vm_file)
+				unmap_hugepage_range(vma, start, end, NULL);
+		} else
+			unmap_page_range(tlb, vma, start, end, details);
+	}
 }
 
 /**
@@ -1318,8 +1342,6 @@
  * @nr_accounted: Place number of unmapped pages in vm-accountable vma's here
  * @details: details of nonlinear truncation or shared cache invalidation
  *
- * Returns the end address of the unmapping (restart addr if interrupted).
- *
  * Unmap all pages in the vma list.
  *
  * Only addresses between `start' and `end' will be unmapped.
@@ -1331,55 +1353,18 @@
  * ensure that any thus-far unmapped pages are flushed before unmap_vmas()
  * drops the lock and schedules.
  */
-unsigned long unmap_vmas(struct mmu_gather *tlb,
+void unmap_vmas(struct mmu_gather *tlb,
 		struct vm_area_struct *vma, unsigned long start_addr,
 		unsigned long end_addr, unsigned long *nr_accounted,
 		struct zap_details *details)
 {
-	unsigned long start = start_addr;
 	struct mm_struct *mm = vma->vm_mm;
 
 	mmu_notifier_invalidate_range_start(mm, start_addr, end_addr);
-	for ( ; vma && vma->vm_start < end_addr; vma = vma->vm_next) {
-		unsigned long end;
-
-		start = max(vma->vm_start, start_addr);
-		if (start >= vma->vm_end)
-			continue;
-		end = min(vma->vm_end, end_addr);
-		if (end <= vma->vm_start)
-			continue;
-
-		if (vma->vm_flags & VM_ACCOUNT)
-			*nr_accounted += (end - start) >> PAGE_SHIFT;
-
-		if (unlikely(is_pfn_mapping(vma)))
-			untrack_pfn_vma(vma, 0, 0);
-
-		while (start != end) {
-			if (unlikely(is_vm_hugetlb_page(vma))) {
-				/*
-				 * It is undesirable to test vma->vm_file as it
-				 * should be non-null for valid hugetlb area.
-				 * However, vm_file will be NULL in the error
-				 * cleanup path of do_mmap_pgoff. When
-				 * hugetlbfs ->mmap method fails,
-				 * do_mmap_pgoff() nullifies vma->vm_file
-				 * before calling this function to clean up.
-				 * Since no pte has actually been setup, it is
-				 * safe to do nothing in this case.
-				 */
-				if (vma->vm_file)
-					unmap_hugepage_range(vma, start, end, NULL);
-
-				start = end;
-			} else
-				start = unmap_page_range(tlb, vma, start, end, details);
-		}
-	}
-
+	for ( ; vma && vma->vm_start < end_addr; vma = vma->vm_next)
+		unmap_single_vma(tlb, vma, start_addr, end_addr, nr_accounted,
+				 details);
 	mmu_notifier_invalidate_range_end(mm, start_addr, end_addr);
-	return start;	/* which is now the end (or restart) address */
 }
 
 /**
@@ -1388,8 +1373,10 @@
  * @address: starting address of pages to zap
  * @size: number of bytes to zap
  * @details: details of nonlinear truncation or shared cache invalidation
+ *
+ * Caller must protect the VMA list
  */
-unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
+void zap_page_range(struct vm_area_struct *vma, unsigned long address,
 		unsigned long size, struct zap_details *details)
 {
 	struct mm_struct *mm = vma->vm_mm;
@@ -1400,9 +1387,34 @@
 	lru_add_drain();
 	tlb_gather_mmu(&tlb, mm, 0);
 	update_hiwater_rss(mm);
-	end = unmap_vmas(&tlb, vma, address, end, &nr_accounted, details);
+	unmap_vmas(&tlb, vma, address, end, &nr_accounted, details);
 	tlb_finish_mmu(&tlb, address, end);
-	return end;
+}
+
+/**
+ * zap_page_range_single - remove user pages in a given range
+ * @vma: vm_area_struct holding the applicable pages
+ * @address: starting address of pages to zap
+ * @size: number of bytes to zap
+ * @details: details of nonlinear truncation or shared cache invalidation
+ *
+ * The range must fit into one VMA.
+ */
+static void zap_page_range_single(struct vm_area_struct *vma, unsigned long address,
+		unsigned long size, struct zap_details *details)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	struct mmu_gather tlb;
+	unsigned long end = address + size;
+	unsigned long nr_accounted = 0;
+
+	lru_add_drain();
+	tlb_gather_mmu(&tlb, mm, 0);
+	update_hiwater_rss(mm);
+	mmu_notifier_invalidate_range_start(mm, address, end);
+	unmap_single_vma(&tlb, vma, address, end, &nr_accounted, details);
+	mmu_notifier_invalidate_range_end(mm, address, end);
+	tlb_finish_mmu(&tlb, address, end);
 }
 
 /**
@@ -1423,7 +1435,7 @@
 	if (address < vma->vm_start || address + size > vma->vm_end ||
 	    		!(vma->vm_flags & VM_PFNMAP))
 		return -1;
-	zap_page_range(vma, address, size, NULL);
+	zap_page_range_single(vma, address, size, NULL);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(zap_vma_ptes);
@@ -2770,7 +2782,7 @@
 		unsigned long start_addr, unsigned long end_addr,
 		struct zap_details *details)
 {
-	zap_page_range(vma, start_addr, end_addr - start_addr, details);
+	zap_page_range_single(vma, start_addr, end_addr - start_addr, details);
 }
 
 static inline void unmap_mapping_range_tree(struct prio_tree_root *root,
@@ -3611,13 +3623,7 @@
 	gate_vma.vm_end = FIXADDR_USER_END;
 	gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
 	gate_vma.vm_page_prot = __P101;
-	/*
-	 * Make sure the vDSO gets into every core dump.
-	 * Dumping its contents makes post-mortem fully interpretable later
-	 * without matching up the same kernel and hardware config to see
-	 * what PC values meant.
-	 */
-	gate_vma.vm_flags |= VM_ALWAYSDUMP;
+
 	return 0;
 }
 __initcall(gate_vma_init);
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 47296fe..cfb6c86 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -512,7 +512,7 @@
 	do {
 		next = pmd_addr_end(addr, end);
 		split_huge_page_pmd(vma->vm_mm, pmd);
-		if (pmd_none_or_clear_bad(pmd))
+		if (pmd_none_or_trans_huge_or_clear_bad(pmd))
 			continue;
 		if (check_pte_range(vma, pmd, addr, next, nodes,
 				    flags, private))
@@ -1323,12 +1323,9 @@
 		err = -ESRCH;
 		goto out;
 	}
-	mm = get_task_mm(task);
-	rcu_read_unlock();
+	get_task_struct(task);
 
 	err = -EINVAL;
-	if (!mm)
-		goto out;
 
 	/*
 	 * Check if this process has the right to modify the specified
@@ -1336,14 +1333,13 @@
 	 * capabilities, superuser privileges or the same
 	 * userid as the target process.
 	 */
-	rcu_read_lock();
 	tcred = __task_cred(task);
 	if (cred->euid != tcred->suid && cred->euid != tcred->uid &&
 	    cred->uid  != tcred->suid && cred->uid  != tcred->uid &&
 	    !capable(CAP_SYS_NICE)) {
 		rcu_read_unlock();
 		err = -EPERM;
-		goto out;
+		goto out_put;
 	}
 	rcu_read_unlock();
 
@@ -1351,26 +1347,36 @@
 	/* Is the user allowed to access the target nodes? */
 	if (!nodes_subset(*new, task_nodes) && !capable(CAP_SYS_NICE)) {
 		err = -EPERM;
-		goto out;
+		goto out_put;
 	}
 
 	if (!nodes_subset(*new, node_states[N_HIGH_MEMORY])) {
 		err = -EINVAL;
-		goto out;
+		goto out_put;
 	}
 
 	err = security_task_movememory(task);
 	if (err)
-		goto out;
+		goto out_put;
 
-	err = do_migrate_pages(mm, old, new,
-		capable(CAP_SYS_NICE) ? MPOL_MF_MOVE_ALL : MPOL_MF_MOVE);
-out:
+	mm = get_task_mm(task);
+	put_task_struct(task);
 	if (mm)
-		mmput(mm);
+		err = do_migrate_pages(mm, old, new,
+			capable(CAP_SYS_NICE) ? MPOL_MF_MOVE_ALL : MPOL_MF_MOVE);
+	else
+		err = -EINVAL;
+
+	mmput(mm);
+out:
 	NODEMASK_SCRATCH_FREE(scratch);
 
 	return err;
+
+out_put:
+	put_task_struct(task);
+	goto out;
+
 }
 
 
@@ -1844,18 +1850,24 @@
 alloc_pages_vma(gfp_t gfp, int order, struct vm_area_struct *vma,
 		unsigned long addr, int node)
 {
-	struct mempolicy *pol = get_vma_policy(current, vma, addr);
+	struct mempolicy *pol;
 	struct zonelist *zl;
 	struct page *page;
+	unsigned int cpuset_mems_cookie;
 
-	get_mems_allowed();
+retry_cpuset:
+	pol = get_vma_policy(current, vma, addr);
+	cpuset_mems_cookie = get_mems_allowed();
+
 	if (unlikely(pol->mode == MPOL_INTERLEAVE)) {
 		unsigned nid;
 
 		nid = interleave_nid(pol, vma, addr, PAGE_SHIFT + order);
 		mpol_cond_put(pol);
 		page = alloc_page_interleave(gfp, order, nid);
-		put_mems_allowed();
+		if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+			goto retry_cpuset;
+
 		return page;
 	}
 	zl = policy_zonelist(gfp, pol, node);
@@ -1866,7 +1878,8 @@
 		struct page *page =  __alloc_pages_nodemask(gfp, order,
 						zl, policy_nodemask(gfp, pol));
 		__mpol_put(pol);
-		put_mems_allowed();
+		if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+			goto retry_cpuset;
 		return page;
 	}
 	/*
@@ -1874,7 +1887,8 @@
 	 */
 	page = __alloc_pages_nodemask(gfp, order, zl,
 				      policy_nodemask(gfp, pol));
-	put_mems_allowed();
+	if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+		goto retry_cpuset;
 	return page;
 }
 
@@ -1901,11 +1915,14 @@
 {
 	struct mempolicy *pol = current->mempolicy;
 	struct page *page;
+	unsigned int cpuset_mems_cookie;
 
 	if (!pol || in_interrupt() || (gfp & __GFP_THISNODE))
 		pol = &default_policy;
 
-	get_mems_allowed();
+retry_cpuset:
+	cpuset_mems_cookie = get_mems_allowed();
+
 	/*
 	 * No reference counting needed for current->mempolicy
 	 * nor system default_policy
@@ -1916,7 +1933,10 @@
 		page = __alloc_pages_nodemask(gfp, order,
 				policy_zonelist(gfp, pol, numa_node_id()),
 				policy_nodemask(gfp, pol));
-	put_mems_allowed();
+
+	if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+		goto retry_cpuset;
+
 	return page;
 }
 EXPORT_SYMBOL(alloc_pages_current);
diff --git a/mm/migrate.c b/mm/migrate.c
index 1503b6b..51c08a0 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -1174,20 +1174,17 @@
  * Migrate an array of page address onto an array of nodes and fill
  * the corresponding array of status.
  */
-static int do_pages_move(struct mm_struct *mm, struct task_struct *task,
+static int do_pages_move(struct mm_struct *mm, nodemask_t task_nodes,
 			 unsigned long nr_pages,
 			 const void __user * __user *pages,
 			 const int __user *nodes,
 			 int __user *status, int flags)
 {
 	struct page_to_node *pm;
-	nodemask_t task_nodes;
 	unsigned long chunk_nr_pages;
 	unsigned long chunk_start;
 	int err;
 
-	task_nodes = cpuset_mems_allowed(task);
-
 	err = -ENOMEM;
 	pm = (struct page_to_node *)__get_free_page(GFP_KERNEL);
 	if (!pm)
@@ -1349,6 +1346,7 @@
 	struct task_struct *task;
 	struct mm_struct *mm;
 	int err;
+	nodemask_t task_nodes;
 
 	/* Check flags */
 	if (flags & ~(MPOL_MF_MOVE|MPOL_MF_MOVE_ALL))
@@ -1364,11 +1362,7 @@
 		rcu_read_unlock();
 		return -ESRCH;
 	}
-	mm = get_task_mm(task);
-	rcu_read_unlock();
-
-	if (!mm)
-		return -EINVAL;
+	get_task_struct(task);
 
 	/*
 	 * Check if this process has the right to modify the specified
@@ -1376,7 +1370,6 @@
 	 * capabilities, superuser privileges or the same
 	 * userid as the target process.
 	 */
-	rcu_read_lock();
 	tcred = __task_cred(task);
 	if (cred->euid != tcred->suid && cred->euid != tcred->uid &&
 	    cred->uid  != tcred->suid && cred->uid  != tcred->uid &&
@@ -1391,15 +1384,24 @@
  	if (err)
 		goto out;
 
-	if (nodes) {
-		err = do_pages_move(mm, task, nr_pages, pages, nodes, status,
-				    flags);
-	} else {
-		err = do_pages_stat(mm, nr_pages, pages, status);
-	}
+	task_nodes = cpuset_mems_allowed(task);
+	mm = get_task_mm(task);
+	put_task_struct(task);
+
+	if (mm) {
+		if (nodes)
+			err = do_pages_move(mm, task_nodes, nr_pages, pages,
+					    nodes, status, flags);
+		else
+			err = do_pages_stat(mm, nr_pages, pages, status);
+	} else
+		err = -EINVAL;
+
+	mmput(mm);
+	return err;
 
 out:
-	mmput(mm);
+	put_task_struct(task);
 	return err;
 }
 
diff --git a/mm/mincore.c b/mm/mincore.c
index 636a868..936b4ce 100644
--- a/mm/mincore.c
+++ b/mm/mincore.c
@@ -164,7 +164,7 @@
 			}
 			/* fall through */
 		}
-		if (pmd_none_or_clear_bad(pmd))
+		if (pmd_none_or_trans_huge_or_clear_bad(pmd))
 			mincore_unmapped_range(vma, addr, next, vec);
 		else
 			mincore_pte_range(vma, pmd, addr, next, vec);
diff --git a/mm/mmap.c b/mm/mmap.c
index 39a68dd..a7bf6a3 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -451,9 +451,8 @@
 }
 
 /*
- * Helper for vma_adjust in the split_vma insert case:
- * insert vm structure into list and rbtree and anon_vma,
- * but it has already been inserted into prio_tree earlier.
+ * Helper for vma_adjust() in the split_vma insert case: insert a vma into the
+ * mm's list and rbtree.  It has already been inserted into the prio_tree.
  */
 static void __insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma)
 {
@@ -1112,9 +1111,9 @@
 		 * A dummy user value is used because we are not locking
 		 * memory so no accounting is necessary
 		 */
-		len = ALIGN(len, huge_page_size(&default_hstate));
-		file = hugetlb_file_setup(HUGETLB_ANON_FILE, len, VM_NORESERVE,
-						&user, HUGETLB_ANONHUGE_INODE);
+		file = hugetlb_file_setup(HUGETLB_ANON_FILE, addr, len,
+						VM_NORESERVE, &user,
+						HUGETLB_ANONHUGE_INODE);
 		if (IS_ERR(file))
 			return PTR_ERR(file);
 	}
@@ -1439,10 +1438,8 @@
 	/*
 	 * Is this a new hole at the lowest possible address?
 	 */
-	if (addr >= TASK_UNMAPPED_BASE && addr < mm->free_area_cache) {
+	if (addr >= TASK_UNMAPPED_BASE && addr < mm->free_area_cache)
 		mm->free_area_cache = addr;
-		mm->cached_hole_size = ~0UL;
-	}
 }
 
 /*
@@ -1457,7 +1454,7 @@
 {
 	struct vm_area_struct *vma;
 	struct mm_struct *mm = current->mm;
-	unsigned long addr = addr0;
+	unsigned long addr = addr0, start_addr;
 
 	/* requested length too big for entire address space */
 	if (len > TASK_SIZE)
@@ -1481,22 +1478,14 @@
  		mm->free_area_cache = mm->mmap_base;
  	}
 
+try_again:
 	/* either no address requested or can't fit in requested address hole */
-	addr = mm->free_area_cache;
+	start_addr = addr = mm->free_area_cache;
 
-	/* make sure it can fit in the remaining address space */
-	if (addr > len) {
-		vma = find_vma(mm, addr-len);
-		if (!vma || addr <= vma->vm_start)
-			/* remember the address as a hint for next time */
-			return (mm->free_area_cache = addr-len);
-	}
+	if (addr < len)
+		goto fail;
 
-	if (mm->mmap_base < len)
-		goto bottomup;
-
-	addr = mm->mmap_base-len;
-
+	addr -= len;
 	do {
 		/*
 		 * Lookup failure means no vma is above this address,
@@ -1516,7 +1505,21 @@
 		addr = vma->vm_start-len;
 	} while (len < vma->vm_start);
 
-bottomup:
+fail:
+	/*
+	 * if hint left us with no space for the requested
+	 * mapping then try again:
+	 *
+	 * Note: this is different with the case of bottomup
+	 * which does the fully line-search, but we use find_vma
+	 * here that causes some holes skipped.
+	 */
+	if (start_addr != mm->mmap_base) {
+		mm->free_area_cache = mm->mmap_base;
+		mm->cached_hole_size = 0;
+		goto try_again;
+	}
+
 	/*
 	 * A failed mmap() very likely causes application failure,
 	 * so fall back to the bottom-up function here. This scenario
@@ -2237,7 +2240,6 @@
 	struct mmu_gather tlb;
 	struct vm_area_struct *vma;
 	unsigned long nr_accounted = 0;
-	unsigned long end;
 
 	/* mm's last user has gone, and its about to be pulled down */
 	mmu_notifier_release(mm);
@@ -2262,11 +2264,11 @@
 	tlb_gather_mmu(&tlb, mm, 1);
 	/* update_hiwater_rss(mm) here? but nobody should be looking */
 	/* Use -1 here to ensure all VMAs in the mm are unmapped */
-	end = unmap_vmas(&tlb, vma, 0, -1, &nr_accounted, NULL);
+	unmap_vmas(&tlb, vma, 0, -1, &nr_accounted, NULL);
 	vm_unacct_memory(nr_accounted);
 
 	free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, 0);
-	tlb_finish_mmu(&tlb, 0, end);
+	tlb_finish_mmu(&tlb, 0, -1);
 
 	/*
 	 * Walk the list again, actually closing and freeing it,
diff --git a/mm/mmu_context.c b/mm/mmu_context.c
index cf332bc..3dcfaf4 100644
--- a/mm/mmu_context.c
+++ b/mm/mmu_context.c
@@ -53,7 +53,7 @@
 	struct task_struct *tsk = current;
 
 	task_lock(tsk);
-	sync_mm_rss(tsk, mm);
+	sync_mm_rss(mm);
 	tsk->mm = NULL;
 	/* active_mm is still 'mm' */
 	enter_lazy_tlb(mm, tsk);
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 142ef4a..a409926 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -60,7 +60,7 @@
 				ptent = pte_mkwrite(ptent);
 
 			ptep_modify_prot_commit(mm, addr, pte, ptent);
-		} else if (PAGE_MIGRATION && !pte_file(oldpte)) {
+		} else if (IS_ENABLED(CONFIG_MIGRATION) && !pte_file(oldpte)) {
 			swp_entry_t entry = pte_to_swp_entry(oldpte);
 
 			if (is_write_migration_entry(entry)) {
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 2958fd8..46bf2ed5 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -34,6 +34,7 @@
 #include <linux/ptrace.h>
 #include <linux/freezer.h>
 #include <linux/ftrace.h>
+#include <linux/ratelimit.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/oom.h>
@@ -309,7 +310,7 @@
  */
 static struct task_struct *select_bad_process(unsigned int *ppoints,
 		unsigned long totalpages, struct mem_cgroup *memcg,
-		const nodemask_t *nodemask)
+		const nodemask_t *nodemask, bool force_kill)
 {
 	struct task_struct *g, *p;
 	struct task_struct *chosen = NULL;
@@ -335,7 +336,8 @@
 		if (test_tsk_thread_flag(p, TIF_MEMDIE)) {
 			if (unlikely(frozen(p)))
 				__thaw_task(p);
-			return ERR_PTR(-1UL);
+			if (!force_kill)
+				return ERR_PTR(-1UL);
 		}
 		if (!p->mm)
 			continue;
@@ -353,7 +355,7 @@
 			if (p == current) {
 				chosen = p;
 				*ppoints = 1000;
-			} else {
+			} else if (!force_kill) {
 				/*
 				 * If this task is not being ptraced on exit,
 				 * then wait for it to finish before killing
@@ -434,66 +436,18 @@
 }
 
 #define K(x) ((x) << (PAGE_SHIFT-10))
-static int oom_kill_task(struct task_struct *p)
-{
-	struct task_struct *q;
-	struct mm_struct *mm;
-
-	p = find_lock_task_mm(p);
-	if (!p)
-		return 1;
-
-	/* mm cannot be safely dereferenced after task_unlock(p) */
-	mm = p->mm;
-
-	pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB\n",
-		task_pid_nr(p), p->comm, K(p->mm->total_vm),
-		K(get_mm_counter(p->mm, MM_ANONPAGES)),
-		K(get_mm_counter(p->mm, MM_FILEPAGES)));
-	task_unlock(p);
-
-	/*
-	 * Kill all user processes sharing p->mm in other thread groups, if any.
-	 * They don't get access to memory reserves or a higher scheduler
-	 * priority, though, to avoid depletion of all memory or task
-	 * starvation.  This prevents mm->mmap_sem livelock when an oom killed
-	 * task cannot exit because it requires the semaphore and its contended
-	 * by another thread trying to allocate memory itself.  That thread will
-	 * now get access to memory reserves since it has a pending fatal
-	 * signal.
-	 */
-	for_each_process(q)
-		if (q->mm == mm && !same_thread_group(q, p) &&
-		    !(q->flags & PF_KTHREAD)) {
-			if (q->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
-				continue;
-
-			task_lock(q);	/* Protect ->comm from prctl() */
-			pr_err("Kill process %d (%s) sharing same memory\n",
-				task_pid_nr(q), q->comm);
-			task_unlock(q);
-			force_sig(SIGKILL, q);
-		}
-
-	set_tsk_thread_flag(p, TIF_MEMDIE);
-	force_sig(SIGKILL, p);
-
-	return 0;
-}
-#undef K
-
-static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
-			    unsigned int points, unsigned long totalpages,
-			    struct mem_cgroup *memcg, nodemask_t *nodemask,
-			    const char *message)
+static void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
+			     unsigned int points, unsigned long totalpages,
+			     struct mem_cgroup *memcg, nodemask_t *nodemask,
+			     const char *message)
 {
 	struct task_struct *victim = p;
 	struct task_struct *child;
 	struct task_struct *t = p;
+	struct mm_struct *mm;
 	unsigned int victim_points = 0;
-
-	if (printk_ratelimit())
-		dump_header(p, gfp_mask, order, memcg, nodemask);
+	static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL,
+					      DEFAULT_RATELIMIT_BURST);
 
 	/*
 	 * If the task is already exiting, don't alarm the sysadmin or kill
@@ -501,9 +455,12 @@
 	 */
 	if (p->flags & PF_EXITING) {
 		set_tsk_thread_flag(p, TIF_MEMDIE);
-		return 0;
+		return;
 	}
 
+	if (__ratelimit(&oom_rs))
+		dump_header(p, gfp_mask, order, memcg, nodemask);
+
 	task_lock(p);
 	pr_err("%s: Kill process %d (%s) score %d or sacrifice child\n",
 		message, task_pid_nr(p), p->comm, points);
@@ -533,8 +490,44 @@
 		}
 	} while_each_thread(p, t);
 
-	return oom_kill_task(victim);
+	victim = find_lock_task_mm(victim);
+	if (!victim)
+		return;
+
+	/* mm cannot safely be dereferenced after task_unlock(victim) */
+	mm = victim->mm;
+	pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB\n",
+		task_pid_nr(victim), victim->comm, K(victim->mm->total_vm),
+		K(get_mm_counter(victim->mm, MM_ANONPAGES)),
+		K(get_mm_counter(victim->mm, MM_FILEPAGES)));
+	task_unlock(victim);
+
+	/*
+	 * Kill all user processes sharing victim->mm in other thread groups, if
+	 * any.  They don't get access to memory reserves, though, to avoid
+	 * depletion of all memory.  This prevents mm->mmap_sem livelock when an
+	 * oom killed thread cannot exit because it requires the semaphore and
+	 * its contended by another thread trying to allocate memory itself.
+	 * That thread will now get access to memory reserves since it has a
+	 * pending fatal signal.
+	 */
+	for_each_process(p)
+		if (p->mm == mm && !same_thread_group(p, victim) &&
+		    !(p->flags & PF_KTHREAD)) {
+			if (p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
+				continue;
+
+			task_lock(p);	/* Protect ->comm from prctl() */
+			pr_err("Kill process %d (%s) sharing same memory\n",
+				task_pid_nr(p), p->comm);
+			task_unlock(p);
+			do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p, true);
+		}
+
+	set_tsk_thread_flag(victim, TIF_MEMDIE);
+	do_send_sig_info(SIGKILL, SEND_SIG_FORCED, victim, true);
 }
+#undef K
 
 /*
  * Determines whether the kernel must panic because of the panic_on_oom sysctl.
@@ -561,7 +554,8 @@
 }
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR
-void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask)
+void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
+			      int order)
 {
 	unsigned long limit;
 	unsigned int points = 0;
@@ -577,18 +571,13 @@
 		return;
 	}
 
-	check_panic_on_oom(CONSTRAINT_MEMCG, gfp_mask, 0, NULL);
+	check_panic_on_oom(CONSTRAINT_MEMCG, gfp_mask, order, NULL);
 	limit = mem_cgroup_get_limit(memcg) >> PAGE_SHIFT;
 	read_lock(&tasklist_lock);
-retry:
-	p = select_bad_process(&points, limit, memcg, NULL);
-	if (!p || PTR_ERR(p) == -1UL)
-		goto out;
-
-	if (oom_kill_process(p, gfp_mask, 0, points, limit, memcg, NULL,
-				"Memory cgroup out of memory"))
-		goto retry;
-out:
+	p = select_bad_process(&points, limit, memcg, NULL, false);
+	if (p && PTR_ERR(p) != -1UL)
+		oom_kill_process(p, gfp_mask, order, points, limit, memcg, NULL,
+				 "Memory cgroup out of memory");
 	read_unlock(&tasklist_lock);
 }
 #endif
@@ -700,6 +689,7 @@
  * @gfp_mask: memory allocation flags
  * @order: amount of memory being requested as a power of 2
  * @nodemask: nodemask passed to page allocator
+ * @force_kill: true if a task must be killed, even if others are exiting
  *
  * If we run out of memory, we have the choice between either
  * killing a random task (bad), letting the system crash (worse)
@@ -707,7 +697,7 @@
  * don't have to be perfect here, we just have to be good.
  */
 void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask,
-		int order, nodemask_t *nodemask)
+		int order, nodemask_t *nodemask, bool force_kill)
 {
 	const nodemask_t *mpol_mask;
 	struct task_struct *p;
@@ -745,33 +735,25 @@
 	if (sysctl_oom_kill_allocating_task &&
 	    !oom_unkillable_task(current, NULL, nodemask) &&
 	    current->mm) {
-		/*
-		 * oom_kill_process() needs tasklist_lock held.  If it returns
-		 * non-zero, current could not be killed so we must fallback to
-		 * the tasklist scan.
-		 */
-		if (!oom_kill_process(current, gfp_mask, order, 0, totalpages,
-				NULL, nodemask,
-				"Out of memory (oom_kill_allocating_task)"))
-			goto out;
+		oom_kill_process(current, gfp_mask, order, 0, totalpages, NULL,
+				 nodemask,
+				 "Out of memory (oom_kill_allocating_task)");
+		goto out;
 	}
 
-retry:
-	p = select_bad_process(&points, totalpages, NULL, mpol_mask);
-	if (PTR_ERR(p) == -1UL)
-		goto out;
-
+	p = select_bad_process(&points, totalpages, NULL, mpol_mask,
+			       force_kill);
 	/* Found nothing?!?! Either we hang forever, or we panic. */
 	if (!p) {
 		dump_header(NULL, gfp_mask, order, NULL, mpol_mask);
 		read_unlock(&tasklist_lock);
 		panic("Out of memory and no killable processes...\n");
 	}
-
-	if (oom_kill_process(p, gfp_mask, order, points, totalpages, NULL,
-				nodemask, "Out of memory"))
-		goto retry;
-	killed = 1;
+	if (PTR_ERR(p) != -1UL) {
+		oom_kill_process(p, gfp_mask, order, points, totalpages, NULL,
+				 nodemask, "Out of memory");
+		killed = 1;
+	}
 out:
 	read_unlock(&tasklist_lock);
 
@@ -792,7 +774,7 @@
 void pagefault_out_of_memory(void)
 {
 	if (try_set_system_oom()) {
-		out_of_memory(NULL, 0, 0, NULL);
+		out_of_memory(NULL, 0, 0, NULL, false);
 		clear_system_oom();
 	}
 	if (!test_thread_flag(TIF_MEMDIE))
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 363ba70..26adea8 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -95,6 +95,8 @@
  */
 unsigned int dirty_writeback_interval = 5 * 100; /* centiseconds */
 
+EXPORT_SYMBOL_GPL(dirty_writeback_interval);
+
 /*
  * The longest time for which data is allowed to remain dirty
  */
@@ -1472,6 +1474,7 @@
 
         for ( ; ; ) {
 		global_dirty_limits(&background_thresh, &dirty_thresh);
+		dirty_thresh = hard_dirty_limit(dirty_thresh);
 
                 /*
                  * Boost the allowable dirty threshold a bit for page
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index a13ded1..a712fb9 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1161,11 +1161,47 @@
 }
 
 /*
- * Spill all the per-cpu pages from all CPUs back into the buddy allocator
+ * Spill all the per-cpu pages from all CPUs back into the buddy allocator.
+ *
+ * Note that this code is protected against sending an IPI to an offline
+ * CPU but does not guarantee sending an IPI to newly hotplugged CPUs:
+ * on_each_cpu_mask() blocks hotplug and won't talk to offlined CPUs but
+ * nothing keeps CPUs from showing up after we populated the cpumask and
+ * before the call to on_each_cpu_mask().
  */
 void drain_all_pages(void)
 {
-	on_each_cpu(drain_local_pages, NULL, 1);
+	int cpu;
+	struct per_cpu_pageset *pcp;
+	struct zone *zone;
+
+	/*
+	 * Allocate in the BSS so we wont require allocation in
+	 * direct reclaim path for CONFIG_CPUMASK_OFFSTACK=y
+	 */
+	static cpumask_t cpus_with_pcps;
+
+	/*
+	 * We don't care about racing with CPU hotplug event
+	 * as offline notification will cause the notified
+	 * cpu to drain that CPU pcps and on_each_cpu_mask
+	 * disables preemption as part of its processing
+	 */
+	for_each_online_cpu(cpu) {
+		bool has_pcps = false;
+		for_each_populated_zone(zone) {
+			pcp = per_cpu_ptr(zone->pageset, cpu);
+			if (pcp->pcp.count) {
+				has_pcps = true;
+				break;
+			}
+		}
+		if (has_pcps)
+			cpumask_set_cpu(cpu, &cpus_with_pcps);
+		else
+			cpumask_clear_cpu(cpu, &cpus_with_pcps);
+	}
+	on_each_cpu_mask(&cpus_with_pcps, drain_local_pages, NULL, 1);
 }
 
 #ifdef CONFIG_HIBERNATION
@@ -1968,7 +2004,7 @@
 			goto out;
 	}
 	/* Exhausted what can be done so it's blamo time */
-	out_of_memory(zonelist, gfp_mask, order, nodemask);
+	out_of_memory(zonelist, gfp_mask, order, nodemask, false);
 
 out:
 	clear_zonelist_oom(zonelist, gfp_mask);
@@ -1990,7 +2026,7 @@
 	if (!order)
 		return NULL;
 
-	if (compaction_deferred(preferred_zone)) {
+	if (compaction_deferred(preferred_zone, order)) {
 		*deferred_compaction = true;
 		return NULL;
 	}
@@ -2012,6 +2048,8 @@
 		if (page) {
 			preferred_zone->compact_considered = 0;
 			preferred_zone->compact_defer_shift = 0;
+			if (order >= preferred_zone->compact_order_failed)
+				preferred_zone->compact_order_failed = order + 1;
 			count_vm_event(COMPACTSUCCESS);
 			return page;
 		}
@@ -2028,7 +2066,7 @@
 		 * defer if the failure was a sync compaction failure.
 		 */
 		if (sync_migration)
-			defer_compaction(preferred_zone);
+			defer_compaction(preferred_zone, order);
 
 		cond_resched();
 	}
@@ -2306,6 +2344,10 @@
 		if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) {
 			if (oom_killer_disabled)
 				goto nopage;
+			/* Coredumps can quickly deplete all memory reserves */
+			if ((current->flags & PF_DUMPCORE) &&
+			    !(gfp_mask & __GFP_NOFAIL))
+				goto nopage;
 			page = __alloc_pages_may_oom(gfp_mask, order,
 					zonelist, high_zoneidx,
 					nodemask, preferred_zone,
@@ -2378,8 +2420,9 @@
 {
 	enum zone_type high_zoneidx = gfp_zone(gfp_mask);
 	struct zone *preferred_zone;
-	struct page *page;
+	struct page *page = NULL;
 	int migratetype = allocflags_to_migratetype(gfp_mask);
+	unsigned int cpuset_mems_cookie;
 
 	gfp_mask &= gfp_allowed_mask;
 
@@ -2398,15 +2441,15 @@
 	if (unlikely(!zonelist->_zonerefs->zone))
 		return NULL;
 
-	get_mems_allowed();
+retry_cpuset:
+	cpuset_mems_cookie = get_mems_allowed();
+
 	/* The preferred zone is used for statistics later */
 	first_zones_zonelist(zonelist, high_zoneidx,
 				nodemask ? : &cpuset_current_mems_allowed,
 				&preferred_zone);
-	if (!preferred_zone) {
-		put_mems_allowed();
-		return NULL;
-	}
+	if (!preferred_zone)
+		goto out;
 
 	/* First allocation attempt */
 	page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order,
@@ -2416,9 +2459,19 @@
 		page = __alloc_pages_slowpath(gfp_mask, order,
 				zonelist, high_zoneidx, nodemask,
 				preferred_zone, migratetype);
-	put_mems_allowed();
 
 	trace_mm_page_alloc(page, order, gfp_mask, migratetype);
+
+out:
+	/*
+	 * When updating a task's mems_allowed, it is possible to race with
+	 * parallel threads in such a way that an allocation can fail while
+	 * the mask is being updated. If a page allocation is about to fail,
+	 * check if the cpuset changed during allocation and if so, retry.
+	 */
+	if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+		goto retry_cpuset;
+
 	return page;
 }
 EXPORT_SYMBOL(__alloc_pages_nodemask);
@@ -2632,13 +2685,15 @@
 bool skip_free_areas_node(unsigned int flags, int nid)
 {
 	bool ret = false;
+	unsigned int cpuset_mems_cookie;
 
 	if (!(flags & SHOW_MEM_FILTER_NODES))
 		goto out;
 
-	get_mems_allowed();
-	ret = !node_isset(nid, cpuset_current_mems_allowed);
-	put_mems_allowed();
+	do {
+		cpuset_mems_cookie = get_mems_allowed();
+		ret = !node_isset(nid, cpuset_current_mems_allowed);
+	} while (!put_mems_allowed(cpuset_mems_cookie));
 out:
 	return ret;
 }
@@ -3925,18 +3980,6 @@
 	}
 }
 
-int __init add_from_early_node_map(struct range *range, int az,
-				   int nr_range, int nid)
-{
-	unsigned long start_pfn, end_pfn;
-	int i;
-
-	/* need to go over early_node_map to find out good range for node */
-	for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL)
-		nr_range = add_range(range, az, nr_range, start_pfn, end_pfn);
-	return nr_range;
-}
-
 /**
  * sparse_memory_present_with_active_regions - Call memory_present for each active range
  * @nid: The node to call memory_present for. If MAX_NUMNODES, all nodes will be used.
@@ -4521,7 +4564,7 @@
  * memory. When they don't, some nodes will have more kernelcore than
  * others
  */
-static void __init find_zone_movable_pfns_for_nodes(unsigned long *movable_pfn)
+static void __init find_zone_movable_pfns_for_nodes(void)
 {
 	int i, nid;
 	unsigned long usable_startpfn;
@@ -4713,7 +4756,7 @@
 
 	/* Find the PFNs that ZONE_MOVABLE begins at in each node */
 	memset(zone_movable_pfn, 0, sizeof(zone_movable_pfn));
-	find_zone_movable_pfns_for_nodes(zone_movable_pfn);
+	find_zone_movable_pfns_for_nodes();
 
 	/* Print out the zone ranges */
 	printk("Zone PFN ranges:\n");
@@ -4823,6 +4866,7 @@
 	int cpu = (unsigned long)hcpu;
 
 	if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
+		lru_add_drain_cpu(cpu);
 		drain_pages(cpu);
 
 		/*
diff --git a/mm/pagewalk.c b/mm/pagewalk.c
index 2f5cf10..aa9701e 100644
--- a/mm/pagewalk.c
+++ b/mm/pagewalk.c
@@ -59,7 +59,7 @@
 			continue;
 
 		split_huge_page_pmd(walk->mm, pmd);
-		if (pmd_none_or_clear_bad(pmd))
+		if (pmd_none_or_trans_huge_or_clear_bad(pmd))
 			goto again;
 		err = walk_pte_range(pmd, addr, next, walk);
 		if (err)
diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c
index eb663fb..5a74fea 100644
--- a/mm/pgtable-generic.c
+++ b/mm/pgtable-generic.c
@@ -70,10 +70,11 @@
 			   unsigned long address, pmd_t *pmdp)
 {
 	int young;
-#ifndef CONFIG_TRANSPARENT_HUGEPAGE
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+	VM_BUG_ON(address & ~HPAGE_PMD_MASK);
+#else
 	BUG();
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
-	VM_BUG_ON(address & ~HPAGE_PMD_MASK);
 	young = pmdp_test_and_clear_young(vma, address, pmdp);
 	if (young)
 		flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
diff --git a/mm/rmap.c b/mm/rmap.c
index c8454e0..5b5ad58 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -120,6 +120,21 @@
 	kmem_cache_free(anon_vma_chain_cachep, anon_vma_chain);
 }
 
+static void anon_vma_chain_link(struct vm_area_struct *vma,
+				struct anon_vma_chain *avc,
+				struct anon_vma *anon_vma)
+{
+	avc->vma = vma;
+	avc->anon_vma = anon_vma;
+	list_add(&avc->same_vma, &vma->anon_vma_chain);
+
+	/*
+	 * It's critical to add new vmas to the tail of the anon_vma,
+	 * see comment in huge_memory.c:__split_huge_page().
+	 */
+	list_add_tail(&avc->same_anon_vma, &anon_vma->head);
+}
+
 /**
  * anon_vma_prepare - attach an anon_vma to a memory region
  * @vma: the memory region in question
@@ -175,10 +190,7 @@
 		spin_lock(&mm->page_table_lock);
 		if (likely(!vma->anon_vma)) {
 			vma->anon_vma = anon_vma;
-			avc->anon_vma = anon_vma;
-			avc->vma = vma;
-			list_add(&avc->same_vma, &vma->anon_vma_chain);
-			list_add_tail(&avc->same_anon_vma, &anon_vma->head);
+			anon_vma_chain_link(vma, avc, anon_vma);
 			allocated = NULL;
 			avc = NULL;
 		}
@@ -224,21 +236,6 @@
 		mutex_unlock(&root->mutex);
 }
 
-static void anon_vma_chain_link(struct vm_area_struct *vma,
-				struct anon_vma_chain *avc,
-				struct anon_vma *anon_vma)
-{
-	avc->vma = vma;
-	avc->anon_vma = anon_vma;
-	list_add(&avc->same_vma, &vma->anon_vma_chain);
-
-	/*
-	 * It's critical to add new vmas to the tail of the anon_vma,
-	 * see comment in huge_memory.c:__split_huge_page().
-	 */
-	list_add_tail(&avc->same_anon_vma, &anon_vma->head);
-}
-
 /*
  * Attach the anon_vmas from src to dst.
  * Returns 0 on success, -ENOMEM on failure.
@@ -1151,10 +1148,15 @@
  */
 void page_add_file_rmap(struct page *page)
 {
+	bool locked;
+	unsigned long flags;
+
+	mem_cgroup_begin_update_page_stat(page, &locked, &flags);
 	if (atomic_inc_and_test(&page->_mapcount)) {
 		__inc_zone_page_state(page, NR_FILE_MAPPED);
 		mem_cgroup_inc_page_stat(page, MEMCG_NR_FILE_MAPPED);
 	}
+	mem_cgroup_end_update_page_stat(page, &locked, &flags);
 }
 
 /**
@@ -1165,9 +1167,21 @@
  */
 void page_remove_rmap(struct page *page)
 {
+	bool anon = PageAnon(page);
+	bool locked;
+	unsigned long flags;
+
+	/*
+	 * The anon case has no mem_cgroup page_stat to update; but may
+	 * uncharge_page() below, where the lock ordering can deadlock if
+	 * we hold the lock against page_stat move: so avoid it on anon.
+	 */
+	if (!anon)
+		mem_cgroup_begin_update_page_stat(page, &locked, &flags);
+
 	/* page still mapped by someone else? */
 	if (!atomic_add_negative(-1, &page->_mapcount))
-		return;
+		goto out;
 
 	/*
 	 * Now that the last pte has gone, s390 must transfer dirty
@@ -1176,7 +1190,7 @@
 	 * not if it's in swapcache - there might be another pte slot
 	 * containing the swap entry, but page not yet written to swap.
 	 */
-	if ((!PageAnon(page) || PageSwapCache(page)) &&
+	if ((!anon || PageSwapCache(page)) &&
 	    page_test_and_clear_dirty(page_to_pfn(page), 1))
 		set_page_dirty(page);
 	/*
@@ -1184,8 +1198,8 @@
 	 * and not charged by memcg for now.
 	 */
 	if (unlikely(PageHuge(page)))
-		return;
-	if (PageAnon(page)) {
+		goto out;
+	if (anon) {
 		mem_cgroup_uncharge_page(page);
 		if (!PageTransHuge(page))
 			__dec_zone_page_state(page, NR_ANON_PAGES);
@@ -1205,6 +1219,9 @@
 	 * Leaving it set also helps swapoff to reinstate ptes
 	 * faster for those pages still in swapcache.
 	 */
+out:
+	if (!anon)
+		mem_cgroup_end_update_page_stat(page, &locked, &flags);
 }
 
 /*
@@ -1282,7 +1299,7 @@
 			}
 			dec_mm_counter(mm, MM_ANONPAGES);
 			inc_mm_counter(mm, MM_SWAPENTS);
-		} else if (PAGE_MIGRATION) {
+		} else if (IS_ENABLED(CONFIG_MIGRATION)) {
 			/*
 			 * Store the pfn of the page in a special migration
 			 * pte. do_swap_page() will wait until the migration
@@ -1293,7 +1310,8 @@
 		}
 		set_pte_at(mm, address, pte, swp_entry_to_pte(entry));
 		BUG_ON(pte_file(*pte));
-	} else if (PAGE_MIGRATION && (TTU_ACTION(flags) == TTU_MIGRATION)) {
+	} else if (IS_ENABLED(CONFIG_MIGRATION) &&
+		   (TTU_ACTION(flags) == TTU_MIGRATION)) {
 		/* Establish migration entry for a file page */
 		swp_entry_t entry;
 		entry = make_migration_entry(page, pte_write(pteval));
@@ -1499,7 +1517,7 @@
 		 * locking requirements of exec(), migration skips
 		 * temporary VMAs until after exec() completes.
 		 */
-		if (PAGE_MIGRATION && (flags & TTU_MIGRATION) &&
+		if (IS_ENABLED(CONFIG_MIGRATION) && (flags & TTU_MIGRATION) &&
 				is_vma_temporary_stack(vma))
 			continue;
 
diff --git a/mm/shmem.c b/mm/shmem.c
index 78307d5..f99ff3e 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1178,6 +1178,12 @@
 static const struct inode_operations shmem_symlink_inode_operations;
 static const struct inode_operations shmem_short_symlink_operations;
 
+#ifdef CONFIG_TMPFS_XATTR
+static int shmem_initxattrs(struct inode *, const struct xattr *, void *);
+#else
+#define shmem_initxattrs NULL
+#endif
+
 static int
 shmem_write_begin(struct file *file, struct address_space *mapping,
 			loff_t pos, unsigned len, unsigned flags,
@@ -1490,7 +1496,7 @@
 	if (inode) {
 		error = security_inode_init_security(inode, dir,
 						     &dentry->d_name,
-						     NULL, NULL);
+						     shmem_initxattrs, NULL);
 		if (error) {
 			if (error != -EOPNOTSUPP) {
 				iput(inode);
@@ -1630,7 +1636,7 @@
 		return -ENOSPC;
 
 	error = security_inode_init_security(inode, dir, &dentry->d_name,
-					     NULL, NULL);
+					     shmem_initxattrs, NULL);
 	if (error) {
 		if (error != -EOPNOTSUPP) {
 			iput(inode);
@@ -1704,6 +1710,66 @@
  * filesystem level, though.
  */
 
+/*
+ * Allocate new xattr and copy in the value; but leave the name to callers.
+ */
+static struct shmem_xattr *shmem_xattr_alloc(const void *value, size_t size)
+{
+	struct shmem_xattr *new_xattr;
+	size_t len;
+
+	/* wrap around? */
+	len = sizeof(*new_xattr) + size;
+	if (len <= sizeof(*new_xattr))
+		return NULL;
+
+	new_xattr = kmalloc(len, GFP_KERNEL);
+	if (!new_xattr)
+		return NULL;
+
+	new_xattr->size = size;
+	memcpy(new_xattr->value, value, size);
+	return new_xattr;
+}
+
+/*
+ * Callback for security_inode_init_security() for acquiring xattrs.
+ */
+static int shmem_initxattrs(struct inode *inode,
+			    const struct xattr *xattr_array,
+			    void *fs_info)
+{
+	struct shmem_inode_info *info = SHMEM_I(inode);
+	const struct xattr *xattr;
+	struct shmem_xattr *new_xattr;
+	size_t len;
+
+	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+		new_xattr = shmem_xattr_alloc(xattr->value, xattr->value_len);
+		if (!new_xattr)
+			return -ENOMEM;
+
+		len = strlen(xattr->name) + 1;
+		new_xattr->name = kmalloc(XATTR_SECURITY_PREFIX_LEN + len,
+					  GFP_KERNEL);
+		if (!new_xattr->name) {
+			kfree(new_xattr);
+			return -ENOMEM;
+		}
+
+		memcpy(new_xattr->name, XATTR_SECURITY_PREFIX,
+		       XATTR_SECURITY_PREFIX_LEN);
+		memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN,
+		       xattr->name, len);
+
+		spin_lock(&info->lock);
+		list_add(&new_xattr->list, &info->xattr_list);
+		spin_unlock(&info->lock);
+	}
+
+	return 0;
+}
+
 static int shmem_xattr_get(struct dentry *dentry, const char *name,
 			   void *buffer, size_t size)
 {
@@ -1731,24 +1797,17 @@
 	return ret;
 }
 
-static int shmem_xattr_set(struct dentry *dentry, const char *name,
+static int shmem_xattr_set(struct inode *inode, const char *name,
 			   const void *value, size_t size, int flags)
 {
-	struct inode *inode = dentry->d_inode;
 	struct shmem_inode_info *info = SHMEM_I(inode);
 	struct shmem_xattr *xattr;
 	struct shmem_xattr *new_xattr = NULL;
-	size_t len;
 	int err = 0;
 
 	/* value == NULL means remove */
 	if (value) {
-		/* wrap around? */
-		len = sizeof(*new_xattr) + size;
-		if (len <= sizeof(*new_xattr))
-			return -ENOMEM;
-
-		new_xattr = kmalloc(len, GFP_KERNEL);
+		new_xattr = shmem_xattr_alloc(value, size);
 		if (!new_xattr)
 			return -ENOMEM;
 
@@ -1757,9 +1816,6 @@
 			kfree(new_xattr);
 			return -ENOMEM;
 		}
-
-		new_xattr->size = size;
-		memcpy(new_xattr->value, value, size);
 	}
 
 	spin_lock(&info->lock);
@@ -1858,7 +1914,7 @@
 	if (size == 0)
 		value = "";  /* empty EA, do not remove */
 
-	return shmem_xattr_set(dentry, name, value, size, flags);
+	return shmem_xattr_set(dentry->d_inode, name, value, size, flags);
 
 }
 
@@ -1878,7 +1934,7 @@
 	if (err)
 		return err;
 
-	return shmem_xattr_set(dentry, name, NULL, 0, XATTR_REPLACE);
+	return shmem_xattr_set(dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
 }
 
 static bool xattr_is_trusted(const char *name)
@@ -2175,7 +2231,6 @@
 int shmem_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *inode;
-	struct dentry *root;
 	struct shmem_sb_info *sbinfo;
 	int err = -ENOMEM;
 
@@ -2232,14 +2287,11 @@
 		goto failed;
 	inode->i_uid = sbinfo->uid;
 	inode->i_gid = sbinfo->gid;
-	root = d_alloc_root(inode);
-	if (!root)
-		goto failed_iput;
-	sb->s_root = root;
+	sb->s_root = d_make_root(inode);
+	if (!sb->s_root)
+		goto failed;
 	return 0;
 
-failed_iput:
-	iput(inode);
 failed:
 	shmem_put_super(sb);
 	return err;
diff --git a/mm/slab.c b/mm/slab.c
index f0bd785..e901a36 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1731,6 +1731,52 @@
 }
 __initcall(cpucache_init);
 
+static noinline void
+slab_out_of_memory(struct kmem_cache *cachep, gfp_t gfpflags, int nodeid)
+{
+	struct kmem_list3 *l3;
+	struct slab *slabp;
+	unsigned long flags;
+	int node;
+
+	printk(KERN_WARNING
+		"SLAB: Unable to allocate memory on node %d (gfp=0x%x)\n",
+		nodeid, gfpflags);
+	printk(KERN_WARNING "  cache: %s, object size: %d, order: %d\n",
+		cachep->name, cachep->buffer_size, cachep->gfporder);
+
+	for_each_online_node(node) {
+		unsigned long active_objs = 0, num_objs = 0, free_objects = 0;
+		unsigned long active_slabs = 0, num_slabs = 0;
+
+		l3 = cachep->nodelists[node];
+		if (!l3)
+			continue;
+
+		spin_lock_irqsave(&l3->list_lock, flags);
+		list_for_each_entry(slabp, &l3->slabs_full, list) {
+			active_objs += cachep->num;
+			active_slabs++;
+		}
+		list_for_each_entry(slabp, &l3->slabs_partial, list) {
+			active_objs += slabp->inuse;
+			active_slabs++;
+		}
+		list_for_each_entry(slabp, &l3->slabs_free, list)
+			num_slabs++;
+
+		free_objects += l3->free_objects;
+		spin_unlock_irqrestore(&l3->list_lock, flags);
+
+		num_slabs += active_slabs;
+		num_objs = num_slabs * cachep->num;
+		printk(KERN_WARNING
+			"  node %d: slabs: %ld/%ld, objs: %ld/%ld, free: %ld\n",
+			node, active_slabs, num_slabs, active_objs, num_objs,
+			free_objects);
+	}
+}
+
 /*
  * Interface to system's page allocator. No need to hold the cache-lock.
  *
@@ -1757,8 +1803,11 @@
 		flags |= __GFP_RECLAIMABLE;
 
 	page = alloc_pages_exact_node(nodeid, flags | __GFP_NOTRACK, cachep->gfporder);
-	if (!page)
+	if (!page) {
+		if (!(flags & __GFP_NOWARN) && printk_ratelimit())
+			slab_out_of_memory(cachep, flags, nodeid);
 		return NULL;
+	}
 
 	nr_pages = (1 << cachep->gfporder);
 	if (cachep->flags & SLAB_RECLAIM_ACCOUNT)
@@ -3284,12 +3333,10 @@
 	if (in_interrupt() || (flags & __GFP_THISNODE))
 		return NULL;
 	nid_alloc = nid_here = numa_mem_id();
-	get_mems_allowed();
 	if (cpuset_do_slab_mem_spread() && (cachep->flags & SLAB_MEM_SPREAD))
 		nid_alloc = cpuset_slab_spread_node();
 	else if (current->mempolicy)
 		nid_alloc = slab_node(current->mempolicy);
-	put_mems_allowed();
 	if (nid_alloc != nid_here)
 		return ____cache_alloc_node(cachep, flags, nid_alloc);
 	return NULL;
@@ -3312,14 +3359,17 @@
 	enum zone_type high_zoneidx = gfp_zone(flags);
 	void *obj = NULL;
 	int nid;
+	unsigned int cpuset_mems_cookie;
 
 	if (flags & __GFP_THISNODE)
 		return NULL;
 
-	get_mems_allowed();
-	zonelist = node_zonelist(slab_node(current->mempolicy), flags);
 	local_flags = flags & (GFP_CONSTRAINT_MASK|GFP_RECLAIM_MASK);
 
+retry_cpuset:
+	cpuset_mems_cookie = get_mems_allowed();
+	zonelist = node_zonelist(slab_node(current->mempolicy), flags);
+
 retry:
 	/*
 	 * Look through allowed nodes for objects available
@@ -3372,7 +3422,9 @@
 			}
 		}
 	}
-	put_mems_allowed();
+
+	if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !obj))
+		goto retry_cpuset;
 	return obj;
 }
 
@@ -3693,13 +3745,12 @@
 
 	if (likely(ac->avail < ac->limit)) {
 		STATS_INC_FREEHIT(cachep);
-		ac->entry[ac->avail++] = objp;
-		return;
 	} else {
 		STATS_INC_FREEMISS(cachep);
 		cache_flusharray(cachep, ac);
-		ac->entry[ac->avail++] = objp;
 	}
+
+	ac->entry[ac->avail++] = objp;
 }
 
 /**
diff --git a/mm/slub.c b/mm/slub.c
index 4907563..ffe13fd 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -29,6 +29,7 @@
 #include <linux/math64.h>
 #include <linux/fault-inject.h>
 #include <linux/stacktrace.h>
+#include <linux/prefetch.h>
 
 #include <trace/events/kmem.h>
 
@@ -269,6 +270,11 @@
 	return *(void **)(object + s->offset);
 }
 
+static void prefetch_freepointer(const struct kmem_cache *s, void *object)
+{
+	prefetch(object + s->offset);
+}
+
 static inline void *get_freepointer_safe(struct kmem_cache *s, void *object)
 {
 	void *p;
@@ -1560,6 +1566,7 @@
 		} else {
 			page->freelist = t;
 			available = put_cpu_partial(s, page, 0);
+			stat(s, CPU_PARTIAL_NODE);
 		}
 		if (kmem_cache_debug(s) || available > s->cpu_partial / 2)
 			break;
@@ -1581,6 +1588,7 @@
 	struct zone *zone;
 	enum zone_type high_zoneidx = gfp_zone(flags);
 	void *object;
+	unsigned int cpuset_mems_cookie;
 
 	/*
 	 * The defrag ratio allows a configuration of the tradeoffs between
@@ -1604,23 +1612,32 @@
 			get_cycles() % 1024 > s->remote_node_defrag_ratio)
 		return NULL;
 
-	get_mems_allowed();
-	zonelist = node_zonelist(slab_node(current->mempolicy), flags);
-	for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
-		struct kmem_cache_node *n;
+	do {
+		cpuset_mems_cookie = get_mems_allowed();
+		zonelist = node_zonelist(slab_node(current->mempolicy), flags);
+		for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
+			struct kmem_cache_node *n;
 
-		n = get_node(s, zone_to_nid(zone));
+			n = get_node(s, zone_to_nid(zone));
 
-		if (n && cpuset_zone_allowed_hardwall(zone, flags) &&
-				n->nr_partial > s->min_partial) {
-			object = get_partial_node(s, n, c);
-			if (object) {
-				put_mems_allowed();
-				return object;
+			if (n && cpuset_zone_allowed_hardwall(zone, flags) &&
+					n->nr_partial > s->min_partial) {
+				object = get_partial_node(s, n, c);
+				if (object) {
+					/*
+					 * Return the object even if
+					 * put_mems_allowed indicated that
+					 * the cpuset mems_allowed was
+					 * updated in parallel. It's a
+					 * harmless race between the alloc
+					 * and the cpuset update.
+					 */
+					put_mems_allowed(cpuset_mems_cookie);
+					return object;
+				}
 			}
 		}
-	}
-	put_mems_allowed();
+	} while (!put_mems_allowed(cpuset_mems_cookie));
 #endif
 	return NULL;
 }
@@ -1973,6 +1990,7 @@
 				local_irq_restore(flags);
 				pobjects = 0;
 				pages = 0;
+				stat(s, CPU_PARTIAL_DRAIN);
 			}
 		}
 
@@ -1984,7 +2002,6 @@
 		page->next = oldpage;
 
 	} while (this_cpu_cmpxchg(s->cpu_slab->partial, oldpage, page) != oldpage);
-	stat(s, CPU_PARTIAL_FREE);
 	return pobjects;
 }
 
@@ -2018,9 +2035,17 @@
 	__flush_cpu_slab(s, smp_processor_id());
 }
 
+static bool has_cpu_slab(int cpu, void *info)
+{
+	struct kmem_cache *s = info;
+	struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
+
+	return !!(c->page);
+}
+
 static void flush_all(struct kmem_cache *s)
 {
-	on_each_cpu(flush_cpu_slab, s, 1);
+	on_each_cpu_cond(has_cpu_slab, flush_cpu_slab, s, 1, GFP_ATOMIC);
 }
 
 /*
@@ -2309,6 +2334,8 @@
 		object = __slab_alloc(s, gfpflags, node, addr, c);
 
 	else {
+		void *next_object = get_freepointer_safe(s, object);
+
 		/*
 		 * The cmpxchg will only match if there was no additional
 		 * operation and if we are on the right processor.
@@ -2324,11 +2351,12 @@
 		if (unlikely(!this_cpu_cmpxchg_double(
 				s->cpu_slab->freelist, s->cpu_slab->tid,
 				object, tid,
-				get_freepointer_safe(s, object), next_tid(tid)))) {
+				next_object, next_tid(tid)))) {
 
 			note_cmpxchg_failure("slab_alloc", s, tid);
 			goto redo;
 		}
+		prefetch_freepointer(s, next_object);
 		stat(s, ALLOC_FASTPATH);
 	}
 
@@ -2465,9 +2493,10 @@
 		 * If we just froze the page then put it onto the
 		 * per cpu partial list.
 		 */
-		if (new.frozen && !was_frozen)
+		if (new.frozen && !was_frozen) {
 			put_cpu_partial(s, page, 1);
-
+			stat(s, CPU_PARTIAL_FREE);
+		}
 		/*
 		 * The list lock was not taken therefore no list
 		 * activity can be necessary.
@@ -3929,13 +3958,14 @@
 		if (kmem_cache_open(s, n,
 				size, align, flags, ctor)) {
 			list_add(&s->list, &slab_caches);
+			up_write(&slub_lock);
 			if (sysfs_slab_add(s)) {
+				down_write(&slub_lock);
 				list_del(&s->list);
 				kfree(n);
 				kfree(s);
 				goto err;
 			}
-			up_write(&slub_lock);
 			return s;
 		}
 		kfree(n);
@@ -5059,6 +5089,8 @@
 STAT_ATTR(CMPXCHG_DOUBLE_FAIL, cmpxchg_double_fail);
 STAT_ATTR(CPU_PARTIAL_ALLOC, cpu_partial_alloc);
 STAT_ATTR(CPU_PARTIAL_FREE, cpu_partial_free);
+STAT_ATTR(CPU_PARTIAL_NODE, cpu_partial_node);
+STAT_ATTR(CPU_PARTIAL_DRAIN, cpu_partial_drain);
 #endif
 
 static struct attribute *slab_attrs[] = {
@@ -5124,6 +5156,8 @@
 	&cmpxchg_double_cpu_fail_attr.attr,
 	&cpu_partial_alloc_attr.attr,
 	&cpu_partial_free_attr.attr,
+	&cpu_partial_node_attr.attr,
+	&cpu_partial_drain_attr.attr,
 #endif
 #ifdef CONFIG_FAILSLAB
 	&failslab_attr.attr,
diff --git a/mm/sparse.c b/mm/sparse.c
index 61d7cde..a8bc7d3 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -353,29 +353,21 @@
 
 	usemap = sparse_early_usemaps_alloc_pgdat_section(NODE_DATA(nodeid),
 								 usemap_count);
-	if (usemap) {
-		for (pnum = pnum_begin; pnum < pnum_end; pnum++) {
-			if (!present_section_nr(pnum))
-				continue;
-			usemap_map[pnum] = usemap;
-			usemap += size;
+	if (!usemap) {
+		usemap = alloc_bootmem_node(NODE_DATA(nodeid), size * usemap_count);
+		if (!usemap) {
+			printk(KERN_WARNING "%s: allocation failed\n", __func__);
+			return;
 		}
-		return;
 	}
 
-	usemap = alloc_bootmem_node(NODE_DATA(nodeid), size * usemap_count);
-	if (usemap) {
-		for (pnum = pnum_begin; pnum < pnum_end; pnum++) {
-			if (!present_section_nr(pnum))
-				continue;
-			usemap_map[pnum] = usemap;
-			usemap += size;
-			check_usemap_section_nr(nodeid, usemap_map[pnum]);
-		}
-		return;
+	for (pnum = pnum_begin; pnum < pnum_end; pnum++) {
+		if (!present_section_nr(pnum))
+			continue;
+		usemap_map[pnum] = usemap;
+		usemap += size;
+		check_usemap_section_nr(nodeid, usemap_map[pnum]);
 	}
-
-	printk(KERN_WARNING "%s: allocation failed\n", __func__);
 }
 
 #ifndef CONFIG_SPARSEMEM_VMEMMAP
diff --git a/mm/swap.c b/mm/swap.c
index 14380e9..5c13f13 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -496,7 +496,7 @@
  * Either "cpu" is the current CPU, and preemption has already been
  * disabled; or "cpu" is being hot-unplugged, and is already dead.
  */
-static void drain_cpu_pagevecs(int cpu)
+void lru_add_drain_cpu(int cpu)
 {
 	struct pagevec *pvecs = per_cpu(lru_add_pvecs, cpu);
 	struct pagevec *pvec;
@@ -553,7 +553,7 @@
 
 void lru_add_drain(void)
 {
-	drain_cpu_pagevecs(get_cpu());
+	lru_add_drain_cpu(get_cpu());
 	put_cpu();
 }
 
diff --git a/mm/swap_state.c b/mm/swap_state.c
index ea6b32d..9d3dd37 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -372,25 +372,23 @@
 struct page *swapin_readahead(swp_entry_t entry, gfp_t gfp_mask,
 			struct vm_area_struct *vma, unsigned long addr)
 {
-	int nr_pages;
 	struct page *page;
-	unsigned long offset;
-	unsigned long end_offset;
+	unsigned long offset = swp_offset(entry);
+	unsigned long start_offset, end_offset;
+	unsigned long mask = (1UL << page_cluster) - 1;
 
-	/*
-	 * Get starting offset for readaround, and number of pages to read.
-	 * Adjust starting address by readbehind (for NUMA interleave case)?
-	 * No, it's very unlikely that swap layout would follow vma layout,
-	 * more likely that neighbouring swap pages came from the same node:
-	 * so use the same "addr" to choose the same node for each swap read.
-	 */
-	nr_pages = valid_swaphandles(entry, &offset);
-	for (end_offset = offset + nr_pages; offset < end_offset; offset++) {
+	/* Read a page_cluster sized and aligned cluster around offset. */
+	start_offset = offset & ~mask;
+	end_offset = offset | mask;
+	if (!start_offset)	/* First page is swap header. */
+		start_offset++;
+
+	for (offset = start_offset; offset <= end_offset ; offset++) {
 		/* Ok, do the async read-ahead now */
 		page = read_swap_cache_async(swp_entry(swp_type(entry), offset),
 						gfp_mask, vma, addr);
 		if (!page)
-			break;
+			continue;
 		page_cache_release(page);
 	}
 	lru_add_drain();	/* Push any new pages onto the LRU now */
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 6bf67ab..fafc26d 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -932,9 +932,7 @@
 	pmd = pmd_offset(pud, addr);
 	do {
 		next = pmd_addr_end(addr, end);
-		if (unlikely(pmd_trans_huge(*pmd)))
-			continue;
-		if (pmd_none_or_clear_bad(pmd))
+		if (pmd_none_or_trans_huge_or_clear_bad(pmd))
 			continue;
 		ret = unuse_pte_range(vma, pmd, addr, next, entry, page);
 		if (ret)
@@ -2024,6 +2022,9 @@
 	struct page *page = NULL;
 	struct inode *inode = NULL;
 
+	if (swap_flags & ~SWAP_FLAGS_VALID)
+		return -EINVAL;
+
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
@@ -2107,7 +2108,7 @@
 			p->flags |= SWP_SOLIDSTATE;
 			p->cluster_next = 1 + (random32() % p->highest_bit);
 		}
-		if (discard_swap(p) == 0 && (swap_flags & SWAP_FLAG_DISCARD))
+		if ((swap_flags & SWAP_FLAG_DISCARD) && discard_swap(p) == 0)
 			p->flags |= SWP_DISCARDABLE;
 	}
 
@@ -2292,58 +2293,6 @@
 }
 
 /*
- * swap_lock prevents swap_map being freed. Don't grab an extra
- * reference on the swaphandle, it doesn't matter if it becomes unused.
- */
-int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
-{
-	struct swap_info_struct *si;
-	int our_page_cluster = page_cluster;
-	pgoff_t target, toff;
-	pgoff_t base, end;
-	int nr_pages = 0;
-
-	if (!our_page_cluster)	/* no readahead */
-		return 0;
-
-	si = swap_info[swp_type(entry)];
-	target = swp_offset(entry);
-	base = (target >> our_page_cluster) << our_page_cluster;
-	end = base + (1 << our_page_cluster);
-	if (!base)		/* first page is swap header */
-		base++;
-
-	spin_lock(&swap_lock);
-	if (end > si->max)	/* don't go beyond end of map */
-		end = si->max;
-
-	/* Count contiguous allocated slots above our target */
-	for (toff = target; ++toff < end; nr_pages++) {
-		/* Don't read in free or bad pages */
-		if (!si->swap_map[toff])
-			break;
-		if (swap_count(si->swap_map[toff]) == SWAP_MAP_BAD)
-			break;
-	}
-	/* Count contiguous allocated slots below our target */
-	for (toff = target; --toff >= base; nr_pages++) {
-		/* Don't read in free or bad pages */
-		if (!si->swap_map[toff])
-			break;
-		if (swap_count(si->swap_map[toff]) == SWAP_MAP_BAD)
-			break;
-	}
-	spin_unlock(&swap_lock);
-
-	/*
-	 * Indicate starting offset, and return number of pages to get:
-	 * if only 1, say 0, since there's then no readahead to be done.
-	 */
-	*offset = ++toff;
-	return nr_pages? ++nr_pages: 0;
-}
-
-/*
  * add_swap_count_continuation - called when a swap count is duplicated
  * beyond SWAP_MAP_MAX, it allocates a new page and links that to the entry's
  * page of the original vmalloc'ed swap_map, to hold the continuation count
diff --git a/mm/truncate.c b/mm/truncate.c
index a188058..61a183b 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -52,7 +52,7 @@
 static inline void truncate_partial_page(struct page *page, unsigned partial)
 {
 	zero_user_segment(page, partial, PAGE_CACHE_SIZE);
-	cleancache_flush_page(page->mapping, page);
+	cleancache_invalidate_page(page->mapping, page);
 	if (page_has_private(page))
 		do_invalidatepage(page, partial);
 }
@@ -213,7 +213,7 @@
 	pgoff_t end;
 	int i;
 
-	cleancache_flush_inode(mapping);
+	cleancache_invalidate_inode(mapping);
 	if (mapping->nrpages == 0)
 		return;
 
@@ -292,7 +292,7 @@
 		mem_cgroup_uncharge_end();
 		index++;
 	}
-	cleancache_flush_inode(mapping);
+	cleancache_invalidate_inode(mapping);
 }
 EXPORT_SYMBOL(truncate_inode_pages_range);
 
@@ -444,7 +444,7 @@
 	int ret2 = 0;
 	int did_range_unmap = 0;
 
-	cleancache_flush_inode(mapping);
+	cleancache_invalidate_inode(mapping);
 	pagevec_init(&pvec, 0);
 	index = start;
 	while (index <= end && pagevec_lookup(&pvec, mapping, index,
@@ -500,7 +500,7 @@
 		cond_resched();
 		index++;
 	}
-	cleancache_flush_inode(mapping);
+	cleancache_invalidate_inode(mapping);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range);
@@ -626,3 +626,43 @@
 
 	return 0;
 }
+
+/**
+ * truncate_pagecache_range - unmap and remove pagecache that is hole-punched
+ * @inode: inode
+ * @lstart: offset of beginning of hole
+ * @lend: offset of last byte of hole
+ *
+ * This function should typically be called before the filesystem
+ * releases resources associated with the freed range (eg. deallocates
+ * blocks). This way, pagecache will always stay logically coherent
+ * with on-disk format, and the filesystem would not have to deal with
+ * situations such as writepage being called for a page that has already
+ * had its underlying blocks deallocated.
+ */
+void truncate_pagecache_range(struct inode *inode, loff_t lstart, loff_t lend)
+{
+	struct address_space *mapping = inode->i_mapping;
+	loff_t unmap_start = round_up(lstart, PAGE_SIZE);
+	loff_t unmap_end = round_down(1 + lend, PAGE_SIZE) - 1;
+	/*
+	 * This rounding is currently just for example: unmap_mapping_range
+	 * expands its hole outwards, whereas we want it to contract the hole
+	 * inwards.  However, existing callers of truncate_pagecache_range are
+	 * doing their own page rounding first; and truncate_inode_pages_range
+	 * currently BUGs if lend is not pagealigned-1 (it handles partial
+	 * page at start of hole, but not partial page at end of hole).  Note
+	 * unmap_mapping_range allows holelen 0 for all, and we allow lend -1.
+	 */
+
+	/*
+	 * Unlike in truncate_pagecache, unmap_mapping_range is called only
+	 * once (before truncating pagecache), and without "even_cows" flag:
+	 * hole-punching should not remove private COWed pages from the hole.
+	 */
+	if ((u64)unmap_end > (u64)unmap_start)
+		unmap_mapping_range(mapping, unmap_start,
+				    1 + unmap_end - unmap_start, 0);
+	truncate_inode_pages_range(mapping, lstart, lend);
+}
+EXPORT_SYMBOL(truncate_pagecache_range);
diff --git a/mm/util.c b/mm/util.c
index 136ac4f..ae962b3 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -239,6 +239,47 @@
 		next->vm_prev = vma;
 }
 
+/* Check if the vma is being used as a stack by this task */
+static int vm_is_stack_for_task(struct task_struct *t,
+				struct vm_area_struct *vma)
+{
+	return (vma->vm_start <= KSTK_ESP(t) && vma->vm_end >= KSTK_ESP(t));
+}
+
+/*
+ * Check if the vma is being used as a stack.
+ * If is_group is non-zero, check in the entire thread group or else
+ * just check in the current task. Returns the pid of the task that
+ * the vma is stack for.
+ */
+pid_t vm_is_stack(struct task_struct *task,
+		  struct vm_area_struct *vma, int in_group)
+{
+	pid_t ret = 0;
+
+	if (vm_is_stack_for_task(task, vma))
+		return task->pid;
+
+	if (in_group) {
+		struct task_struct *t;
+		rcu_read_lock();
+		if (!pid_alive(task))
+			goto done;
+
+		t = task;
+		do {
+			if (vm_is_stack_for_task(t, vma)) {
+				ret = t->pid;
+				goto done;
+			}
+		} while_each_thread(task, t);
+done:
+		rcu_read_unlock();
+	}
+
+	return ret;
+}
+
 #if defined(CONFIG_MMU) && !defined(HAVE_ARCH_PICK_MMAP_LAYOUT)
 void arch_pick_mmap_layout(struct mm_struct *mm)
 {
diff --git a/mm/vmscan.c b/mm/vmscan.c
index c52b235..33c332b 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1138,7 +1138,7 @@
  * @mz:		The mem_cgroup_zone to pull pages from.
  * @dst:	The temp list to put pages on to.
  * @nr_scanned:	The number of pages that were scanned.
- * @order:	The caller's attempted allocation order
+ * @sc:		The scan_control struct for this reclaim session
  * @mode:	One of the LRU isolation modes
  * @active:	True [1] if isolating active pages
  * @file:	True [1] if isolating file [!anon] pages
@@ -1147,8 +1147,8 @@
  */
 static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
 		struct mem_cgroup_zone *mz, struct list_head *dst,
-		unsigned long *nr_scanned, int order, isolate_mode_t mode,
-		int active, int file)
+		unsigned long *nr_scanned, struct scan_control *sc,
+		isolate_mode_t mode, int active, int file)
 {
 	struct lruvec *lruvec;
 	struct list_head *src;
@@ -1194,7 +1194,7 @@
 			BUG();
 		}
 
-		if (!order)
+		if (!sc->order || !(sc->reclaim_mode & RECLAIM_MODE_LUMPYRECLAIM))
 			continue;
 
 		/*
@@ -1208,8 +1208,8 @@
 		 */
 		zone_id = page_zone_id(page);
 		page_pfn = page_to_pfn(page);
-		pfn = page_pfn & ~((1 << order) - 1);
-		end_pfn = pfn + (1 << order);
+		pfn = page_pfn & ~((1 << sc->order) - 1);
+		end_pfn = pfn + (1 << sc->order);
 		for (; pfn < end_pfn; pfn++) {
 			struct page *cursor_page;
 
@@ -1275,7 +1275,7 @@
 
 	*nr_scanned = scan;
 
-	trace_mm_vmscan_lru_isolate(order,
+	trace_mm_vmscan_lru_isolate(sc->order,
 			nr_to_scan, scan,
 			nr_taken,
 			nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed,
@@ -1413,7 +1413,6 @@
 		       unsigned long *nr_anon,
 		       unsigned long *nr_file)
 {
-	struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
 	struct zone *zone = mz->zone;
 	unsigned int count[NR_LRU_LISTS] = { 0, };
 	unsigned long nr_active = 0;
@@ -1434,6 +1433,7 @@
 		count[lru] += numpages;
 	}
 
+	preempt_disable();
 	__count_vm_events(PGDEACTIVATE, nr_active);
 
 	__mod_zone_page_state(zone, NR_ACTIVE_FILE,
@@ -1448,8 +1448,9 @@
 	*nr_anon = count[LRU_ACTIVE_ANON] + count[LRU_INACTIVE_ANON];
 	*nr_file = count[LRU_ACTIVE_FILE] + count[LRU_INACTIVE_FILE];
 
-	reclaim_stat->recent_scanned[0] += *nr_anon;
-	reclaim_stat->recent_scanned[1] += *nr_file;
+	__mod_zone_page_state(zone, NR_ISOLATED_ANON, *nr_anon);
+	__mod_zone_page_state(zone, NR_ISOLATED_FILE, *nr_file);
+	preempt_enable();
 }
 
 /*
@@ -1509,8 +1510,9 @@
 	unsigned long nr_file;
 	unsigned long nr_dirty = 0;
 	unsigned long nr_writeback = 0;
-	isolate_mode_t reclaim_mode = ISOLATE_INACTIVE;
+	isolate_mode_t isolate_mode = ISOLATE_INACTIVE;
 	struct zone *zone = mz->zone;
+	struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
 
 	while (unlikely(too_many_isolated(zone, file, sc))) {
 		congestion_wait(BLK_RW_ASYNC, HZ/10);
@@ -1522,20 +1524,19 @@
 
 	set_reclaim_mode(priority, sc, false);
 	if (sc->reclaim_mode & RECLAIM_MODE_LUMPYRECLAIM)
-		reclaim_mode |= ISOLATE_ACTIVE;
+		isolate_mode |= ISOLATE_ACTIVE;
 
 	lru_add_drain();
 
 	if (!sc->may_unmap)
-		reclaim_mode |= ISOLATE_UNMAPPED;
+		isolate_mode |= ISOLATE_UNMAPPED;
 	if (!sc->may_writepage)
-		reclaim_mode |= ISOLATE_CLEAN;
+		isolate_mode |= ISOLATE_CLEAN;
 
 	spin_lock_irq(&zone->lru_lock);
 
-	nr_taken = isolate_lru_pages(nr_to_scan, mz, &page_list,
-				     &nr_scanned, sc->order,
-				     reclaim_mode, 0, file);
+	nr_taken = isolate_lru_pages(nr_to_scan, mz, &page_list, &nr_scanned,
+				     sc, isolate_mode, 0, file);
 	if (global_reclaim(sc)) {
 		zone->pages_scanned += nr_scanned;
 		if (current_is_kswapd())
@@ -1545,19 +1546,13 @@
 			__count_zone_vm_events(PGSCAN_DIRECT, zone,
 					       nr_scanned);
 	}
+	spin_unlock_irq(&zone->lru_lock);
 
-	if (nr_taken == 0) {
-		spin_unlock_irq(&zone->lru_lock);
+	if (nr_taken == 0)
 		return 0;
-	}
 
 	update_isolated_counts(mz, &page_list, &nr_anon, &nr_file);
 
-	__mod_zone_page_state(zone, NR_ISOLATED_ANON, nr_anon);
-	__mod_zone_page_state(zone, NR_ISOLATED_FILE, nr_file);
-
-	spin_unlock_irq(&zone->lru_lock);
-
 	nr_reclaimed = shrink_page_list(&page_list, mz, sc, priority,
 						&nr_dirty, &nr_writeback);
 
@@ -1570,6 +1565,9 @@
 
 	spin_lock_irq(&zone->lru_lock);
 
+	reclaim_stat->recent_scanned[0] += nr_anon;
+	reclaim_stat->recent_scanned[1] += nr_file;
+
 	if (current_is_kswapd())
 		__count_vm_events(KSWAPD_STEAL, nr_reclaimed);
 	__count_zone_vm_events(PGSTEAL, zone, nr_reclaimed);
@@ -1643,18 +1641,6 @@
 	unsigned long pgmoved = 0;
 	struct page *page;
 
-	if (buffer_heads_over_limit) {
-		spin_unlock_irq(&zone->lru_lock);
-		list_for_each_entry(page, list, lru) {
-			if (page_has_private(page) && trylock_page(page)) {
-				if (page_has_private(page))
-					try_to_release_page(page, 0);
-				unlock_page(page);
-			}
-		}
-		spin_lock_irq(&zone->lru_lock);
-	}
-
 	while (!list_empty(list)) {
 		struct lruvec *lruvec;
 
@@ -1699,21 +1685,22 @@
 	struct page *page;
 	struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
 	unsigned long nr_rotated = 0;
-	isolate_mode_t reclaim_mode = ISOLATE_ACTIVE;
+	isolate_mode_t isolate_mode = ISOLATE_ACTIVE;
 	struct zone *zone = mz->zone;
 
 	lru_add_drain();
 
+	reset_reclaim_mode(sc);
+
 	if (!sc->may_unmap)
-		reclaim_mode |= ISOLATE_UNMAPPED;
+		isolate_mode |= ISOLATE_UNMAPPED;
 	if (!sc->may_writepage)
-		reclaim_mode |= ISOLATE_CLEAN;
+		isolate_mode |= ISOLATE_CLEAN;
 
 	spin_lock_irq(&zone->lru_lock);
 
-	nr_taken = isolate_lru_pages(nr_to_scan, mz, &l_hold,
-				     &nr_scanned, sc->order,
-				     reclaim_mode, 1, file);
+	nr_taken = isolate_lru_pages(nr_to_scan, mz, &l_hold, &nr_scanned, sc,
+				     isolate_mode, 1, file);
 	if (global_reclaim(sc))
 		zone->pages_scanned += nr_scanned;
 
@@ -1737,6 +1724,14 @@
 			continue;
 		}
 
+		if (unlikely(buffer_heads_over_limit)) {
+			if (page_has_private(page) && trylock_page(page)) {
+				if (page_has_private(page))
+					try_to_release_page(page, 0);
+				unlock_page(page);
+			}
+		}
+
 		if (page_referenced(page, 0, mz->mem_cgroup, &vm_flags)) {
 			nr_rotated += hpage_nr_pages(page);
 			/*
@@ -2112,7 +2107,12 @@
 		 * with multiple processes reclaiming pages, the total
 		 * freeing target can get unreasonably large.
 		 */
-		if (nr_reclaimed >= nr_to_reclaim && priority < DEF_PRIORITY)
+		if (nr_reclaimed >= nr_to_reclaim)
+			nr_to_reclaim = 0;
+		else
+			nr_to_reclaim -= nr_reclaimed;
+
+		if (!nr_to_reclaim && priority < DEF_PRIORITY)
 			break;
 	}
 	blk_finish_plug(&plug);
@@ -2195,7 +2195,7 @@
 	 * If compaction is deferred, reclaim up to a point where
 	 * compaction will have a chance of success when re-enabled
 	 */
-	if (compaction_deferred(zone))
+	if (compaction_deferred(zone, sc->order))
 		return watermark_ok;
 
 	/* If compaction is not ready to start, keep reclaiming */
@@ -2235,6 +2235,14 @@
 	unsigned long nr_soft_scanned;
 	bool aborted_reclaim = false;
 
+	/*
+	 * If the number of buffer_heads in the machine exceeds the maximum
+	 * allowed level, force direct reclaim to scan the highmem zone as
+	 * highmem pages could be pinning lowmem pages storing buffer_heads
+	 */
+	if (buffer_heads_over_limit)
+		sc->gfp_mask |= __GFP_HIGHMEM;
+
 	for_each_zone_zonelist_nodemask(zone, z, zonelist,
 					gfp_zone(sc->gfp_mask), sc->nodemask) {
 		if (!populated_zone(zone))
@@ -2255,8 +2263,8 @@
 				 * Even though compaction is invoked for any
 				 * non-zero order, only frequent costly order
 				 * reclamation is disruptive enough to become a
-				 * noticable problem, like transparent huge page
-				 * allocations.
+				 * noticeable problem, like transparent huge
+				 * page allocations.
 				 */
 				if (compaction_ready(zone, sc)) {
 					aborted_reclaim = true;
@@ -2337,7 +2345,6 @@
 	unsigned long writeback_threshold;
 	bool aborted_reclaim;
 
-	get_mems_allowed();
 	delayacct_freepages_start();
 
 	if (global_reclaim(sc))
@@ -2401,7 +2408,6 @@
 
 out:
 	delayacct_freepages_end();
-	put_mems_allowed();
 
 	if (sc->nr_reclaimed)
 		return sc->nr_reclaimed;
@@ -2724,6 +2730,17 @@
 			 */
 			age_active_anon(zone, &sc, priority);
 
+			/*
+			 * If the number of buffer_heads in the machine
+			 * exceeds the maximum allowed level and this node
+			 * has a highmem zone, force kswapd to reclaim from
+			 * it to relieve lowmem pressure.
+			 */
+			if (buffer_heads_over_limit && is_highmem_idx(i)) {
+				end_zone = i;
+				break;
+			}
+
 			if (!zone_watermark_ok_safe(zone, order,
 					high_wmark_pages(zone), 0, 0)) {
 				end_zone = i;
@@ -2753,7 +2770,7 @@
 		 */
 		for (i = 0; i <= end_zone; i++) {
 			struct zone *zone = pgdat->node_zones + i;
-			int nr_slab;
+			int nr_slab, testorder;
 			unsigned long balance_gap;
 
 			if (!populated_zone(zone))
@@ -2786,7 +2803,21 @@
 				(zone->present_pages +
 					KSWAPD_ZONE_BALANCE_GAP_RATIO-1) /
 				KSWAPD_ZONE_BALANCE_GAP_RATIO);
-			if (!zone_watermark_ok_safe(zone, order,
+			/*
+			 * Kswapd reclaims only single pages with compaction
+			 * enabled. Trying too hard to reclaim until contiguous
+			 * free pages have become available can hurt performance
+			 * by evicting too much useful data from memory.
+			 * Do not reclaim more than needed for compaction.
+			 */
+			testorder = order;
+			if (COMPACTION_BUILD && order &&
+					compaction_suitable(zone, order) !=
+						COMPACT_SKIPPED)
+				testorder = 0;
+
+			if ((buffer_heads_over_limit && is_highmem_idx(i)) ||
+				    !zone_watermark_ok_safe(zone, testorder,
 					high_wmark_pages(zone) + balance_gap,
 					end_zone, 0)) {
 				shrink_zone(priority, zone, &sc);
@@ -2815,7 +2846,7 @@
 				continue;
 			}
 
-			if (!zone_watermark_ok_safe(zone, order,
+			if (!zone_watermark_ok_safe(zone, testorder,
 					high_wmark_pages(zone), end_zone, 0)) {
 				all_zones_ok = 0;
 				/*
@@ -2903,6 +2934,8 @@
 	 * and it is potentially going to sleep here.
 	 */
 	if (order) {
+		int zones_need_compaction = 1;
+
 		for (i = 0; i <= end_zone; i++) {
 			struct zone *zone = pgdat->node_zones + i;
 
@@ -2912,6 +2945,11 @@
 			if (zone->all_unreclaimable && priority != DEF_PRIORITY)
 				continue;
 
+			/* Would compaction fail due to lack of free memory? */
+			if (COMPACTION_BUILD &&
+			    compaction_suitable(zone, order) == COMPACT_SKIPPED)
+				goto loop_again;
+
 			/* Confirm the zone is balanced for order-0 */
 			if (!zone_watermark_ok(zone, 0,
 					high_wmark_pages(zone), 0, 0)) {
@@ -2919,11 +2957,17 @@
 				goto loop_again;
 			}
 
+			/* Check if the memory needs to be defragmented. */
+			if (zone_watermark_ok(zone, order,
+				    low_wmark_pages(zone), *classzone_idx, 0))
+				zones_need_compaction = 0;
+
 			/* If balanced, clear the congested flag */
 			zone_clear_flag(zone, ZONE_CONGESTED);
-			if (i <= *classzone_idx)
-				balanced += zone->present_pages;
 		}
+
+		if (zones_need_compaction)
+			compact_pgdat(pgdat, order);
 	}
 
 	/*
diff --git a/net/802/fc.c b/net/802/fc.c
index bd345f3..b324e31 100644
--- a/net/802/fc.c
+++ b/net/802/fc.c
@@ -11,7 +11,6 @@
  */
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
diff --git a/net/802/fddi.c b/net/802/fddi.c
index 94b3ad0..5ab25cd 100644
--- a/net/802/fddi.c
+++ b/net/802/fddi.c
@@ -27,7 +27,6 @@
  */
 
 #include <linux/module.h>
-#include <asm/system.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
diff --git a/net/802/garp.c b/net/802/garp.c
index 8e21b6d..a5c2248 100644
--- a/net/802/garp.c
+++ b/net/802/garp.c
@@ -167,7 +167,8 @@
 	return NULL;
 }
 
-static void garp_attr_insert(struct garp_applicant *app, struct garp_attr *new)
+static struct garp_attr *garp_attr_create(struct garp_applicant *app,
+					  const void *data, u8 len, u8 type)
 {
 	struct rb_node *parent = NULL, **p = &app->gid.rb_node;
 	struct garp_attr *attr;
@@ -176,21 +177,16 @@
 	while (*p) {
 		parent = *p;
 		attr = rb_entry(parent, struct garp_attr, node);
-		d = garp_attr_cmp(attr, new->data, new->dlen, new->type);
+		d = garp_attr_cmp(attr, data, len, type);
 		if (d < 0)
 			p = &parent->rb_left;
 		else if (d > 0)
 			p = &parent->rb_right;
+		else {
+			/* The attribute already exists; re-use it. */
+			return attr;
+		}
 	}
-	rb_link_node(&new->node, parent, p);
-	rb_insert_color(&new->node, &app->gid);
-}
-
-static struct garp_attr *garp_attr_create(struct garp_applicant *app,
-					  const void *data, u8 len, u8 type)
-{
-	struct garp_attr *attr;
-
 	attr = kmalloc(sizeof(*attr) + len, GFP_ATOMIC);
 	if (!attr)
 		return attr;
@@ -198,7 +194,9 @@
 	attr->type  = type;
 	attr->dlen  = len;
 	memcpy(attr->data, data, len);
-	garp_attr_insert(app, attr);
+
+	rb_link_node(&attr->node, parent, p);
+	rb_insert_color(&attr->node, &app->gid);
 	return attr;
 }
 
diff --git a/net/802/hippi.c b/net/802/hippi.c
index 91aca87..056794e 100644
--- a/net/802/hippi.c
+++ b/net/802/hippi.c
@@ -35,7 +35,6 @@
 #include <net/arp.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 /*
  * Create the HIPPI MAC header for an arbitrary protocol layer
diff --git a/net/802/tr.c b/net/802/tr.c
index 5e20cf8..b9a3a14 100644
--- a/net/802/tr.c
+++ b/net/802/tr.c
@@ -16,7 +16,6 @@
  */
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
diff --git a/net/9p/client.c b/net/9p/client.c
index 776618c..b23a17c 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -740,10 +740,18 @@
 			c->status = Disconnected;
 		goto reterr;
 	}
+again:
 	/* Wait for the response */
 	err = wait_event_interruptible(*req->wq,
 				       req->status >= REQ_STATUS_RCVD);
 
+	if ((err == -ERESTARTSYS) && (c->status == Connected)
+				  && (type == P9_TFLUSH)) {
+		sigpending = 1;
+		clear_thread_flag(TIF_SIGPENDING);
+		goto again;
+	}
+
 	if (req->status == REQ_STATUS_ERROR) {
 		p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
 		err = req->t_err;
@@ -1420,6 +1428,7 @@
 	int err;
 	struct p9_client *clnt;
 	struct p9_req_t *req;
+	int retries = 0;
 
 	if (!fid) {
 		pr_warn("%s (%d): Trying to clunk with NULL fid\n",
@@ -1428,7 +1437,9 @@
 		return 0;
 	}
 
-	p9_debug(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid);
+again:
+	p9_debug(P9_DEBUG_9P, ">>> TCLUNK fid %d (try %d)\n", fid->fid,
+								retries);
 	err = 0;
 	clnt = fid->clnt;
 
@@ -1444,8 +1455,14 @@
 error:
 	/*
 	 * Fid is not valid even after a failed clunk
+	 * If interrupted, retry once then give up and
+	 * leak fid until umount.
 	 */
-	p9_fid_destroy(fid);
+	if (err == -ERESTARTSYS) {
+		if (retries++ == 0)
+			goto again;
+	} else
+		p9_fid_destroy(fid);
 	return err;
 }
 EXPORT_SYMBOL(p9_client_clunk);
@@ -1470,7 +1487,10 @@
 
 	p9_free_req(clnt, req);
 error:
-	p9_fid_destroy(fid);
+	if (err == -ERESTARTSYS)
+		p9_client_clunk(fid);
+	else
+		p9_fid_destroy(fid);
 	return err;
 }
 EXPORT_SYMBOL(p9_client_remove);
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 5de42ea..8ae3a78 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -37,7 +37,6 @@
 #include <linux/param.h> /* for HZ */
 #include <linux/uaccess.h>
 #include <asm/byteorder.h> /* for htons etc. */
-#include <asm/system.h> /* save/restore_flags */
 #include <linux/atomic.h>
 
 #include "common.h"
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 3cd0a0d..0906c19 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -33,7 +33,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/termios.h>	/* For TIOCINQ/OUTQ */
 #include <linux/mm.h>
diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c
index 7e7964d..9162409 100644
--- a/net/ax25/ax25_addr.c
+++ b/net/ax25/ax25_addr.c
@@ -22,7 +22,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c
index c1cb982..d0de30e 100644
--- a/net/ax25/ax25_dev.c
+++ b/net/ax25/ax25_dev.c
@@ -24,7 +24,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/ax25/ax25_ds_in.c b/net/ax25/ax25_ds_in.c
index 8273b12..9bd31e8 100644
--- a/net/ax25/ax25_ds_in.c
+++ b/net/ax25/ax25_ds_in.c
@@ -23,7 +23,6 @@
 #include <net/sock.h>
 #include <net/tcp_states.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/ax25/ax25_ds_subr.c b/net/ax25/ax25_ds_subr.c
index 85816e6..5ea7fd3 100644
--- a/net/ax25/ax25_ds_subr.c
+++ b/net/ax25/ax25_ds_subr.c
@@ -24,7 +24,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c
index c7d8143..993c439 100644
--- a/net/ax25/ax25_ds_timer.c
+++ b/net/ax25/ax25_ds_timer.c
@@ -25,7 +25,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/ax25/ax25_iface.c b/net/ax25/ax25_iface.c
index 60b545e..7d5f24b 100644
--- a/net/ax25/ax25_iface.c
+++ b/net/ax25/ax25_iface.c
@@ -24,7 +24,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c
index 9bb7765..96f4cab3 100644
--- a/net/ax25/ax25_in.c
+++ b/net/ax25/ax25_in.c
@@ -27,7 +27,6 @@
 #include <net/sock.h>
 #include <net/tcp_states.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c
index cf0c47a..846ae4e 100644
--- a/net/ax25/ax25_ip.c
+++ b/net/ax25/ax25_ip.c
@@ -24,7 +24,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/termios.h>	/* For TIOCINQ/OUTQ */
 #include <linux/mm.h>
diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c
index 37507d8..be8a25e 100644
--- a/net/ax25/ax25_out.c
+++ b/net/ax25/ax25_out.c
@@ -27,7 +27,6 @@
 #include <linux/netfilter.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index 87fddab..a655880 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -32,7 +32,6 @@
 #include <linux/spinlock.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/ax25/ax25_std_in.c b/net/ax25/ax25_std_in.c
index a8eef88..3fbf8f7 100644
--- a/net/ax25/ax25_std_in.c
+++ b/net/ax25/ax25_std_in.c
@@ -30,7 +30,6 @@
 #include <net/sock.h>
 #include <net/tcp_states.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/ax25/ax25_std_subr.c b/net/ax25/ax25_std_subr.c
index 277f81b..8b66a41 100644
--- a/net/ax25/ax25_std_subr.c
+++ b/net/ax25/ax25_std_subr.c
@@ -21,7 +21,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/ax25/ax25_std_timer.c b/net/ax25/ax25_std_timer.c
index 96e4b92..004467c9 100644
--- a/net/ax25/ax25_std_timer.c
+++ b/net/ax25/ax25_std_timer.c
@@ -25,7 +25,6 @@
 #include <net/sock.h>
 #include <net/tcp_states.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c
index c6715ee..1997538 100644
--- a/net/ax25/ax25_subr.c
+++ b/net/ax25/ax25_subr.c
@@ -26,7 +26,6 @@
 #include <net/sock.h>
 #include <net/tcp_states.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c
index db29ea7..c3cffa7 100644
--- a/net/ax25/ax25_timer.c
+++ b/net/ax25/ax25_timer.c
@@ -29,7 +29,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c
index 4c83137..e3c579b 100644
--- a/net/ax25/ax25_uid.c
+++ b/net/ax25/ax25_uid.c
@@ -26,7 +26,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
index 9f9c8dc..180bfc4 100644
--- a/net/bluetooth/bnep/sock.c
+++ b/net/bluetooth/bnep/sock.c
@@ -42,7 +42,6 @@
 #include <linux/uaccess.h>
 #include <net/sock.h>
 
-#include <asm/system.h>
 
 #include "bnep.h"
 
diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c
index 1230faa..311668d 100644
--- a/net/bluetooth/cmtp/sock.c
+++ b/net/bluetooth/cmtp/sock.c
@@ -39,7 +39,6 @@
 
 #include <linux/isdn/capilli.h>
 
-#include <asm/system.h>
 
 #include "cmtp.h"
 
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 947172bf..5238b6b 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -37,7 +37,6 @@
 #include <linux/interrupt.h>
 #include <net/sock.h>
 
-#include <asm/system.h>
 #include <linux/uaccess.h>
 #include <asm/unaligned.h>
 
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 2054c13..92a857e 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -45,7 +45,6 @@
 #include <linux/crypto.h>
 #include <net/sock.h>
 
-#include <asm/system.h>
 #include <linux/uaccess.h>
 #include <asm/unaligned.h>
 
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index badb785..b375310 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -37,7 +37,6 @@
 #include <linux/interrupt.h>
 #include <net/sock.h>
 
-#include <asm/system.h>
 #include <linux/uaccess.h>
 #include <asm/unaligned.h>
 
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 63afd23..5914623 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -42,7 +42,6 @@
 #include <linux/ioctl.h>
 #include <net/sock.h>
 
-#include <asm/system.h>
 #include <linux/uaccess.h>
 #include <asm/unaligned.h>
 
@@ -734,7 +733,8 @@
 		data = &tv;
 		len = sizeof(tv);
 #ifdef CONFIG_COMPAT
-		if (msg->msg_flags & MSG_CMSG_COMPAT) {
+		if (!COMPAT_USE_64BIT_TIME &&
+		    (msg->msg_flags & MSG_CMSG_COMPAT)) {
 			ctv.tv_sec = tv.tv_sec;
 			ctv.tv_usec = tv.tv_usec;
 			data = &ctv;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 38d934a..94552b3 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -49,7 +49,6 @@
 #include <linux/crc16.h>
 #include <net/sock.h>
 
-#include <asm/system.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 22169c3..a55a43e 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -45,7 +45,6 @@
 #include <linux/security.h>
 #include <net/sock.h>
 
-#include <asm/system.h>
 #include <linux/uaccess.h>
 
 #include <net/bluetooth/bluetooth.h>
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 8bf26d1..f6ab129 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -44,7 +44,6 @@
 #include <linux/security.h>
 #include <net/sock.h>
 
-#include <asm/system.h>
 #include <linux/uaccess.h>
 
 #include <net/bluetooth/bluetooth.h>
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index 761ad9d..cc91319 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -201,7 +201,9 @@
 	Opt_ip,
 	Opt_last_string,
 	/* string args above */
+	Opt_share,
 	Opt_noshare,
+	Opt_crc,
 	Opt_nocrc,
 };
 
@@ -217,7 +219,9 @@
 	{Opt_key, "key=%s"},
 	{Opt_ip, "ip=%s"},
 	/* string args above */
+	{Opt_share, "share"},
 	{Opt_noshare, "noshare"},
+	{Opt_crc, "crc"},
 	{Opt_nocrc, "nocrc"},
 	{-1, NULL}
 };
@@ -277,10 +281,11 @@
 	return err;
 }
 
-int ceph_parse_options(struct ceph_options **popt, char *options,
-		       const char *dev_name, const char *dev_name_end,
-		       int (*parse_extra_token)(char *c, void *private),
-		       void *private)
+struct ceph_options *
+ceph_parse_options(char *options, const char *dev_name,
+			const char *dev_name_end,
+			int (*parse_extra_token)(char *c, void *private),
+			void *private)
 {
 	struct ceph_options *opt;
 	const char *c;
@@ -289,7 +294,7 @@
 
 	opt = kzalloc(sizeof(*opt), GFP_KERNEL);
 	if (!opt)
-		return err;
+		return ERR_PTR(-ENOMEM);
 	opt->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*opt->mon_addr),
 				GFP_KERNEL);
 	if (!opt->mon_addr)
@@ -398,10 +403,16 @@
 			opt->mount_timeout = intval;
 			break;
 
+		case Opt_share:
+			opt->flags &= ~CEPH_OPT_NOSHARE;
+			break;
 		case Opt_noshare:
 			opt->flags |= CEPH_OPT_NOSHARE;
 			break;
 
+		case Opt_crc:
+			opt->flags &= ~CEPH_OPT_NOCRC;
+			break;
 		case Opt_nocrc:
 			opt->flags |= CEPH_OPT_NOCRC;
 			break;
@@ -412,12 +423,11 @@
 	}
 
 	/* success */
-	*popt = opt;
-	return 0;
+	return opt;
 
 out:
 	ceph_destroy_options(opt);
-	return err;
+	return ERR_PTR(err);
 }
 EXPORT_SYMBOL(ceph_parse_options);
 
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
index ad5b708..f0993af 100644
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -38,48 +38,54 @@
 static struct lock_class_key socket_class;
 #endif
 
+/*
+ * When skipping (ignoring) a block of input we read it into a "skip
+ * buffer," which is this many bytes in size.
+ */
+#define SKIP_BUF_SIZE	1024
 
 static void queue_con(struct ceph_connection *con);
 static void con_work(struct work_struct *);
 static void ceph_fault(struct ceph_connection *con);
 
 /*
- * nicely render a sockaddr as a string.
+ * Nicely render a sockaddr as a string.  An array of formatted
+ * strings is used, to approximate reentrancy.
  */
-#define MAX_ADDR_STR 20
-#define MAX_ADDR_STR_LEN 60
-static char addr_str[MAX_ADDR_STR][MAX_ADDR_STR_LEN];
-static DEFINE_SPINLOCK(addr_str_lock);
-static int last_addr_str;
+#define ADDR_STR_COUNT_LOG	5	/* log2(# address strings in array) */
+#define ADDR_STR_COUNT		(1 << ADDR_STR_COUNT_LOG)
+#define ADDR_STR_COUNT_MASK	(ADDR_STR_COUNT - 1)
+#define MAX_ADDR_STR_LEN	64	/* 54 is enough */
+
+static char addr_str[ADDR_STR_COUNT][MAX_ADDR_STR_LEN];
+static atomic_t addr_str_seq = ATOMIC_INIT(0);
+
+static struct page *zero_page;		/* used in certain error cases */
 
 const char *ceph_pr_addr(const struct sockaddr_storage *ss)
 {
 	int i;
 	char *s;
-	struct sockaddr_in *in4 = (void *)ss;
-	struct sockaddr_in6 *in6 = (void *)ss;
+	struct sockaddr_in *in4 = (struct sockaddr_in *) ss;
+	struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) ss;
 
-	spin_lock(&addr_str_lock);
-	i = last_addr_str++;
-	if (last_addr_str == MAX_ADDR_STR)
-		last_addr_str = 0;
-	spin_unlock(&addr_str_lock);
+	i = atomic_inc_return(&addr_str_seq) & ADDR_STR_COUNT_MASK;
 	s = addr_str[i];
 
 	switch (ss->ss_family) {
 	case AF_INET:
-		snprintf(s, MAX_ADDR_STR_LEN, "%pI4:%u", &in4->sin_addr,
-			 (unsigned int)ntohs(in4->sin_port));
+		snprintf(s, MAX_ADDR_STR_LEN, "%pI4:%hu", &in4->sin_addr,
+			 ntohs(in4->sin_port));
 		break;
 
 	case AF_INET6:
-		snprintf(s, MAX_ADDR_STR_LEN, "[%pI6c]:%u", &in6->sin6_addr,
-			 (unsigned int)ntohs(in6->sin6_port));
+		snprintf(s, MAX_ADDR_STR_LEN, "[%pI6c]:%hu", &in6->sin6_addr,
+			 ntohs(in6->sin6_port));
 		break;
 
 	default:
-		snprintf(s, MAX_ADDR_STR_LEN, "(unknown sockaddr family %d)",
-			 (int)ss->ss_family);
+		snprintf(s, MAX_ADDR_STR_LEN, "(unknown sockaddr family %hu)",
+			 ss->ss_family);
 	}
 
 	return s;
@@ -95,22 +101,43 @@
 /*
  * work queue for all reading and writing to/from the socket.
  */
-struct workqueue_struct *ceph_msgr_wq;
+static struct workqueue_struct *ceph_msgr_wq;
+
+void _ceph_msgr_exit(void)
+{
+	if (ceph_msgr_wq) {
+		destroy_workqueue(ceph_msgr_wq);
+		ceph_msgr_wq = NULL;
+	}
+
+	BUG_ON(zero_page == NULL);
+	kunmap(zero_page);
+	page_cache_release(zero_page);
+	zero_page = NULL;
+}
 
 int ceph_msgr_init(void)
 {
+	BUG_ON(zero_page != NULL);
+	zero_page = ZERO_PAGE(0);
+	page_cache_get(zero_page);
+
 	ceph_msgr_wq = alloc_workqueue("ceph-msgr", WQ_NON_REENTRANT, 0);
-	if (!ceph_msgr_wq) {
-		pr_err("msgr_init failed to create workqueue\n");
-		return -ENOMEM;
-	}
-	return 0;
+	if (ceph_msgr_wq)
+		return 0;
+
+	pr_err("msgr_init failed to create workqueue\n");
+	_ceph_msgr_exit();
+
+	return -ENOMEM;
 }
 EXPORT_SYMBOL(ceph_msgr_init);
 
 void ceph_msgr_exit(void)
 {
-	destroy_workqueue(ceph_msgr_wq);
+	BUG_ON(ceph_msgr_wq == NULL);
+
+	_ceph_msgr_exit();
 }
 EXPORT_SYMBOL(ceph_msgr_exit);
 
@@ -128,8 +155,8 @@
 /* data available on socket, or listen socket received a connect */
 static void ceph_data_ready(struct sock *sk, int count_unused)
 {
-	struct ceph_connection *con =
-		(struct ceph_connection *)sk->sk_user_data;
+	struct ceph_connection *con = sk->sk_user_data;
+
 	if (sk->sk_state != TCP_CLOSE_WAIT) {
 		dout("ceph_data_ready on %p state = %lu, queueing work\n",
 		     con, con->state);
@@ -140,26 +167,30 @@
 /* socket has buffer space for writing */
 static void ceph_write_space(struct sock *sk)
 {
-	struct ceph_connection *con =
-		(struct ceph_connection *)sk->sk_user_data;
+	struct ceph_connection *con = sk->sk_user_data;
 
-	/* only queue to workqueue if there is data we want to write. */
+	/* only queue to workqueue if there is data we want to write,
+	 * and there is sufficient space in the socket buffer to accept
+	 * more data.  clear SOCK_NOSPACE so that ceph_write_space()
+	 * doesn't get called again until try_write() fills the socket
+	 * buffer. See net/ipv4/tcp_input.c:tcp_check_space()
+	 * and net/core/stream.c:sk_stream_write_space().
+	 */
 	if (test_bit(WRITE_PENDING, &con->state)) {
-		dout("ceph_write_space %p queueing write work\n", con);
-		queue_con(con);
+		if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) {
+			dout("ceph_write_space %p queueing write work\n", con);
+			clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+			queue_con(con);
+		}
 	} else {
 		dout("ceph_write_space %p nothing to write\n", con);
 	}
-
-	/* since we have our own write_space, clear the SOCK_NOSPACE flag */
-	clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
 }
 
 /* socket's state has changed */
 static void ceph_state_change(struct sock *sk)
 {
-	struct ceph_connection *con =
-		(struct ceph_connection *)sk->sk_user_data;
+	struct ceph_connection *con = sk->sk_user_data;
 
 	dout("ceph_state_change %p state = %lu sk_state = %u\n",
 	     con, con->state, sk->sk_state);
@@ -184,6 +215,8 @@
 		dout("ceph_state_change TCP_ESTABLISHED\n");
 		queue_con(con);
 		break;
+	default:	/* Everything else is uninteresting */
+		break;
 	}
 }
 
@@ -194,7 +227,7 @@
 			       struct ceph_connection *con)
 {
 	struct sock *sk = sock->sk;
-	sk->sk_user_data = (void *)con;
+	sk->sk_user_data = con;
 	sk->sk_data_ready = ceph_data_ready;
 	sk->sk_write_space = ceph_write_space;
 	sk->sk_state_change = ceph_state_change;
@@ -208,7 +241,7 @@
 /*
  * initiate connection to a remote socket.
  */
-static struct socket *ceph_tcp_connect(struct ceph_connection *con)
+static int ceph_tcp_connect(struct ceph_connection *con)
 {
 	struct sockaddr_storage *paddr = &con->peer_addr.in_addr;
 	struct socket *sock;
@@ -218,8 +251,7 @@
 	ret = sock_create_kern(con->peer_addr.in_addr.ss_family, SOCK_STREAM,
 			       IPPROTO_TCP, &sock);
 	if (ret)
-		return ERR_PTR(ret);
-	con->sock = sock;
+		return ret;
 	sock->sk->sk_allocation = GFP_NOFS;
 
 #ifdef CONFIG_LOCKDEP
@@ -236,19 +268,17 @@
 		dout("connect %s EINPROGRESS sk_state = %u\n",
 		     ceph_pr_addr(&con->peer_addr.in_addr),
 		     sock->sk->sk_state);
-		ret = 0;
-	}
-	if (ret < 0) {
+	} else if (ret < 0) {
 		pr_err("connect %s error %d\n",
 		       ceph_pr_addr(&con->peer_addr.in_addr), ret);
 		sock_release(sock);
-		con->sock = NULL;
 		con->error_msg = "connect error";
-	}
 
-	if (ret < 0)
-		return ERR_PTR(ret);
-	return sock;
+		return ret;
+	}
+	con->sock = sock;
+
+	return 0;
 }
 
 static int ceph_tcp_recvmsg(struct socket *sock, void *buf, size_t len)
@@ -284,6 +314,19 @@
 	return r;
 }
 
+static int ceph_tcp_sendpage(struct socket *sock, struct page *page,
+		     int offset, size_t size, int more)
+{
+	int flags = MSG_DONTWAIT | MSG_NOSIGNAL | (more ? MSG_MORE : MSG_EOR);
+	int ret;
+
+	ret = kernel_sendpage(sock, page, offset, size, flags);
+	if (ret == -EAGAIN)
+		ret = 0;
+
+	return ret;
+}
+
 
 /*
  * Shutdown/close the socket for the given connection.
@@ -391,22 +434,23 @@
  */
 struct ceph_connection *ceph_con_get(struct ceph_connection *con)
 {
-	dout("con_get %p nref = %d -> %d\n", con,
-	     atomic_read(&con->nref), atomic_read(&con->nref) + 1);
-	if (atomic_inc_not_zero(&con->nref))
-		return con;
-	return NULL;
+	int nref = __atomic_add_unless(&con->nref, 1, 0);
+
+	dout("con_get %p nref = %d -> %d\n", con, nref, nref + 1);
+
+	return nref ? con : NULL;
 }
 
 void ceph_con_put(struct ceph_connection *con)
 {
-	dout("con_put %p nref = %d -> %d\n", con,
-	     atomic_read(&con->nref), atomic_read(&con->nref) - 1);
-	BUG_ON(atomic_read(&con->nref) == 0);
-	if (atomic_dec_and_test(&con->nref)) {
+	int nref = atomic_dec_return(&con->nref);
+
+	BUG_ON(nref < 0);
+	if (nref == 0) {
 		BUG_ON(con->sock);
 		kfree(con);
 	}
+	dout("con_put %p nref = %d -> %d\n", con, nref + 1, nref);
 }
 
 /*
@@ -442,14 +486,35 @@
 	return ret;
 }
 
+static void ceph_con_out_kvec_reset(struct ceph_connection *con)
+{
+	con->out_kvec_left = 0;
+	con->out_kvec_bytes = 0;
+	con->out_kvec_cur = &con->out_kvec[0];
+}
+
+static void ceph_con_out_kvec_add(struct ceph_connection *con,
+				size_t size, void *data)
+{
+	int index;
+
+	index = con->out_kvec_left;
+	BUG_ON(index >= ARRAY_SIZE(con->out_kvec));
+
+	con->out_kvec[index].iov_len = size;
+	con->out_kvec[index].iov_base = data;
+	con->out_kvec_left++;
+	con->out_kvec_bytes += size;
+}
 
 /*
  * Prepare footer for currently outgoing message, and finish things
  * off.  Assumes out_kvec* are already valid.. we just add on to the end.
  */
-static void prepare_write_message_footer(struct ceph_connection *con, int v)
+static void prepare_write_message_footer(struct ceph_connection *con)
 {
 	struct ceph_msg *m = con->out_msg;
+	int v = con->out_kvec_left;
 
 	dout("prepare_write_message_footer %p\n", con);
 	con->out_kvec_is_msg = true;
@@ -467,9 +532,9 @@
 static void prepare_write_message(struct ceph_connection *con)
 {
 	struct ceph_msg *m;
-	int v = 0;
+	u32 crc;
 
-	con->out_kvec_bytes = 0;
+	ceph_con_out_kvec_reset(con);
 	con->out_kvec_is_msg = true;
 	con->out_msg_done = false;
 
@@ -477,16 +542,13 @@
 	 * TCP packet that's a good thing. */
 	if (con->in_seq > con->in_seq_acked) {
 		con->in_seq_acked = con->in_seq;
-		con->out_kvec[v].iov_base = &tag_ack;
-		con->out_kvec[v++].iov_len = 1;
+		ceph_con_out_kvec_add(con, sizeof (tag_ack), &tag_ack);
 		con->out_temp_ack = cpu_to_le64(con->in_seq_acked);
-		con->out_kvec[v].iov_base = &con->out_temp_ack;
-		con->out_kvec[v++].iov_len = sizeof(con->out_temp_ack);
-		con->out_kvec_bytes = 1 + sizeof(con->out_temp_ack);
+		ceph_con_out_kvec_add(con, sizeof (con->out_temp_ack),
+			&con->out_temp_ack);
 	}
 
-	m = list_first_entry(&con->out_queue,
-		       struct ceph_msg, list_head);
+	m = list_first_entry(&con->out_queue, struct ceph_msg, list_head);
 	con->out_msg = m;
 
 	/* put message on sent list */
@@ -510,30 +572,26 @@
 	BUG_ON(le32_to_cpu(m->hdr.front_len) != m->front.iov_len);
 
 	/* tag + hdr + front + middle */
-	con->out_kvec[v].iov_base = &tag_msg;
-	con->out_kvec[v++].iov_len = 1;
-	con->out_kvec[v].iov_base = &m->hdr;
-	con->out_kvec[v++].iov_len = sizeof(m->hdr);
-	con->out_kvec[v++] = m->front;
+	ceph_con_out_kvec_add(con, sizeof (tag_msg), &tag_msg);
+	ceph_con_out_kvec_add(con, sizeof (m->hdr), &m->hdr);
+	ceph_con_out_kvec_add(con, m->front.iov_len, m->front.iov_base);
+
 	if (m->middle)
-		con->out_kvec[v++] = m->middle->vec;
-	con->out_kvec_left = v;
-	con->out_kvec_bytes += 1 + sizeof(m->hdr) + m->front.iov_len +
-		(m->middle ? m->middle->vec.iov_len : 0);
-	con->out_kvec_cur = con->out_kvec;
+		ceph_con_out_kvec_add(con, m->middle->vec.iov_len,
+			m->middle->vec.iov_base);
 
 	/* fill in crc (except data pages), footer */
-	con->out_msg->hdr.crc =
-		cpu_to_le32(crc32c(0, (void *)&m->hdr,
-				      sizeof(m->hdr) - sizeof(m->hdr.crc)));
+	crc = crc32c(0, &m->hdr, offsetof(struct ceph_msg_header, crc));
+	con->out_msg->hdr.crc = cpu_to_le32(crc);
 	con->out_msg->footer.flags = CEPH_MSG_FOOTER_COMPLETE;
-	con->out_msg->footer.front_crc =
-		cpu_to_le32(crc32c(0, m->front.iov_base, m->front.iov_len));
-	if (m->middle)
-		con->out_msg->footer.middle_crc =
-			cpu_to_le32(crc32c(0, m->middle->vec.iov_base,
-					   m->middle->vec.iov_len));
-	else
+
+	crc = crc32c(0, m->front.iov_base, m->front.iov_len);
+	con->out_msg->footer.front_crc = cpu_to_le32(crc);
+	if (m->middle) {
+		crc = crc32c(0, m->middle->vec.iov_base,
+				m->middle->vec.iov_len);
+		con->out_msg->footer.middle_crc = cpu_to_le32(crc);
+	} else
 		con->out_msg->footer.middle_crc = 0;
 	con->out_msg->footer.data_crc = 0;
 	dout("prepare_write_message front_crc %u data_crc %u\n",
@@ -549,11 +607,11 @@
 		else
 			con->out_msg_pos.page_pos = 0;
 		con->out_msg_pos.data_pos = 0;
-		con->out_msg_pos.did_page_crc = 0;
+		con->out_msg_pos.did_page_crc = false;
 		con->out_more = 1;  /* data + footer will follow */
 	} else {
 		/* no, queue up footer too and be done */
-		prepare_write_message_footer(con, v);
+		prepare_write_message_footer(con);
 	}
 
 	set_bit(WRITE_PENDING, &con->state);
@@ -568,14 +626,14 @@
 	     con->in_seq_acked, con->in_seq);
 	con->in_seq_acked = con->in_seq;
 
-	con->out_kvec[0].iov_base = &tag_ack;
-	con->out_kvec[0].iov_len = 1;
+	ceph_con_out_kvec_reset(con);
+
+	ceph_con_out_kvec_add(con, sizeof (tag_ack), &tag_ack);
+
 	con->out_temp_ack = cpu_to_le64(con->in_seq_acked);
-	con->out_kvec[1].iov_base = &con->out_temp_ack;
-	con->out_kvec[1].iov_len = sizeof(con->out_temp_ack);
-	con->out_kvec_left = 2;
-	con->out_kvec_bytes = 1 + sizeof(con->out_temp_ack);
-	con->out_kvec_cur = con->out_kvec;
+	ceph_con_out_kvec_add(con, sizeof (con->out_temp_ack),
+				&con->out_temp_ack);
+
 	con->out_more = 1;  /* more will follow.. eventually.. */
 	set_bit(WRITE_PENDING, &con->state);
 }
@@ -586,11 +644,8 @@
 static void prepare_write_keepalive(struct ceph_connection *con)
 {
 	dout("prepare_write_keepalive %p\n", con);
-	con->out_kvec[0].iov_base = &tag_keepalive;
-	con->out_kvec[0].iov_len = 1;
-	con->out_kvec_left = 1;
-	con->out_kvec_bytes = 1;
-	con->out_kvec_cur = con->out_kvec;
+	ceph_con_out_kvec_reset(con);
+	ceph_con_out_kvec_add(con, sizeof (tag_keepalive), &tag_keepalive);
 	set_bit(WRITE_PENDING, &con->state);
 }
 
@@ -619,12 +674,9 @@
 	con->out_connect.authorizer_protocol = cpu_to_le32(auth_protocol);
 	con->out_connect.authorizer_len = cpu_to_le32(auth_len);
 
-	if (auth_len) {
-		con->out_kvec[con->out_kvec_left].iov_base = auth_buf;
-		con->out_kvec[con->out_kvec_left].iov_len = auth_len;
-		con->out_kvec_left++;
-		con->out_kvec_bytes += auth_len;
-	}
+	if (auth_len)
+		ceph_con_out_kvec_add(con, auth_len, auth_buf);
+
 	return 0;
 }
 
@@ -634,22 +686,18 @@
 static void prepare_write_banner(struct ceph_messenger *msgr,
 				 struct ceph_connection *con)
 {
-	int len = strlen(CEPH_BANNER);
+	ceph_con_out_kvec_reset(con);
+	ceph_con_out_kvec_add(con, strlen(CEPH_BANNER), CEPH_BANNER);
+	ceph_con_out_kvec_add(con, sizeof (msgr->my_enc_addr),
+					&msgr->my_enc_addr);
 
-	con->out_kvec[0].iov_base = CEPH_BANNER;
-	con->out_kvec[0].iov_len = len;
-	con->out_kvec[1].iov_base = &msgr->my_enc_addr;
-	con->out_kvec[1].iov_len = sizeof(msgr->my_enc_addr);
-	con->out_kvec_left = 2;
-	con->out_kvec_bytes = len + sizeof(msgr->my_enc_addr);
-	con->out_kvec_cur = con->out_kvec;
 	con->out_more = 0;
 	set_bit(WRITE_PENDING, &con->state);
 }
 
 static int prepare_write_connect(struct ceph_messenger *msgr,
 				 struct ceph_connection *con,
-				 int after_banner)
+				 int include_banner)
 {
 	unsigned global_seq = get_global_seq(con->msgr, 0);
 	int proto;
@@ -678,22 +726,18 @@
 	con->out_connect.protocol_version = cpu_to_le32(proto);
 	con->out_connect.flags = 0;
 
-	if (!after_banner) {
-		con->out_kvec_left = 0;
-		con->out_kvec_bytes = 0;
-	}
-	con->out_kvec[con->out_kvec_left].iov_base = &con->out_connect;
-	con->out_kvec[con->out_kvec_left].iov_len = sizeof(con->out_connect);
-	con->out_kvec_left++;
-	con->out_kvec_bytes += sizeof(con->out_connect);
-	con->out_kvec_cur = con->out_kvec;
+	if (include_banner)
+		prepare_write_banner(msgr, con);
+	else
+		ceph_con_out_kvec_reset(con);
+	ceph_con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect);
+
 	con->out_more = 0;
 	set_bit(WRITE_PENDING, &con->state);
 
 	return prepare_connect_authorizer(con);
 }
 
-
 /*
  * write as much of pending kvecs to the socket as we can.
  *  1 -> done
@@ -714,17 +758,18 @@
 		con->out_kvec_bytes -= ret;
 		if (con->out_kvec_bytes == 0)
 			break;            /* done */
-		while (ret > 0) {
-			if (ret >= con->out_kvec_cur->iov_len) {
-				ret -= con->out_kvec_cur->iov_len;
-				con->out_kvec_cur++;
-				con->out_kvec_left--;
-			} else {
-				con->out_kvec_cur->iov_len -= ret;
-				con->out_kvec_cur->iov_base += ret;
-				ret = 0;
-				break;
-			}
+
+		/* account for full iov entries consumed */
+		while (ret >= con->out_kvec_cur->iov_len) {
+			BUG_ON(!con->out_kvec_left);
+			ret -= con->out_kvec_cur->iov_len;
+			con->out_kvec_cur++;
+			con->out_kvec_left--;
+		}
+		/* and for a partially-consumed entry */
+		if (ret) {
+			con->out_kvec_cur->iov_len -= ret;
+			con->out_kvec_cur->iov_base += ret;
 		}
 	}
 	con->out_kvec_left = 0;
@@ -773,7 +818,7 @@
 	struct ceph_msg *msg = con->out_msg;
 	unsigned data_len = le32_to_cpu(msg->hdr.data_len);
 	size_t len;
-	int crc = con->msgr->nocrc;
+	bool do_datacrc = !con->msgr->nocrc;
 	int ret;
 	int total_max_write;
 	int in_trail = 0;
@@ -790,9 +835,8 @@
 
 	while (data_len > con->out_msg_pos.data_pos) {
 		struct page *page = NULL;
-		void *kaddr = NULL;
 		int max_write = PAGE_SIZE;
-		int page_shift = 0;
+		int bio_offset = 0;
 
 		total_max_write = data_len - trail_len -
 			con->out_msg_pos.data_pos;
@@ -811,58 +855,47 @@
 
 			page = list_first_entry(&msg->trail->head,
 						struct page, lru);
-			if (crc)
-				kaddr = kmap(page);
 			max_write = PAGE_SIZE;
 		} else if (msg->pages) {
 			page = msg->pages[con->out_msg_pos.page];
-			if (crc)
-				kaddr = kmap(page);
 		} else if (msg->pagelist) {
 			page = list_first_entry(&msg->pagelist->head,
 						struct page, lru);
-			if (crc)
-				kaddr = kmap(page);
 #ifdef CONFIG_BLOCK
 		} else if (msg->bio) {
 			struct bio_vec *bv;
 
 			bv = bio_iovec_idx(msg->bio_iter, msg->bio_seg);
 			page = bv->bv_page;
-			page_shift = bv->bv_offset;
-			if (crc)
-				kaddr = kmap(page) + page_shift;
+			bio_offset = bv->bv_offset;
 			max_write = bv->bv_len;
 #endif
 		} else {
-			page = con->msgr->zero_page;
-			if (crc)
-				kaddr = page_address(con->msgr->zero_page);
+			page = zero_page;
 		}
 		len = min_t(int, max_write - con->out_msg_pos.page_pos,
 			    total_max_write);
 
-		if (crc && !con->out_msg_pos.did_page_crc) {
-			void *base = kaddr + con->out_msg_pos.page_pos;
+		if (do_datacrc && !con->out_msg_pos.did_page_crc) {
+			void *base;
+			u32 crc;
 			u32 tmpcrc = le32_to_cpu(con->out_msg->footer.data_crc);
+			char *kaddr;
 
+			kaddr = kmap(page);
 			BUG_ON(kaddr == NULL);
-			con->out_msg->footer.data_crc =
-				cpu_to_le32(crc32c(tmpcrc, base, len));
-			con->out_msg_pos.did_page_crc = 1;
+			base = kaddr + con->out_msg_pos.page_pos + bio_offset;
+			crc = crc32c(tmpcrc, base, len);
+			con->out_msg->footer.data_crc = cpu_to_le32(crc);
+			con->out_msg_pos.did_page_crc = true;
 		}
-		ret = kernel_sendpage(con->sock, page,
-				      con->out_msg_pos.page_pos + page_shift,
-				      len,
-				      MSG_DONTWAIT | MSG_NOSIGNAL |
-				      MSG_MORE);
+		ret = ceph_tcp_sendpage(con->sock, page,
+				      con->out_msg_pos.page_pos + bio_offset,
+				      len, 1);
 
-		if (crc &&
-		    (msg->pages || msg->pagelist || msg->bio || in_trail))
+		if (do_datacrc)
 			kunmap(page);
 
-		if (ret == -EAGAIN)
-			ret = 0;
 		if (ret <= 0)
 			goto out;
 
@@ -871,7 +904,7 @@
 		if (ret == len) {
 			con->out_msg_pos.page_pos = 0;
 			con->out_msg_pos.page++;
-			con->out_msg_pos.did_page_crc = 0;
+			con->out_msg_pos.did_page_crc = false;
 			if (in_trail)
 				list_move_tail(&page->lru,
 					       &msg->trail->head);
@@ -888,12 +921,10 @@
 	dout("write_partial_msg_pages %p msg %p done\n", con, msg);
 
 	/* prepare and queue up footer, too */
-	if (!crc)
+	if (!do_datacrc)
 		con->out_msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC;
-	con->out_kvec_bytes = 0;
-	con->out_kvec_left = 0;
-	con->out_kvec_cur = con->out_kvec;
-	prepare_write_message_footer(con, 0);
+	ceph_con_out_kvec_reset(con);
+	prepare_write_message_footer(con);
 	ret = 1;
 out:
 	return ret;
@@ -907,12 +938,9 @@
 	int ret;
 
 	while (con->out_skip > 0) {
-		struct kvec iov = {
-			.iov_base = page_address(con->msgr->zero_page),
-			.iov_len = min(con->out_skip, (int)PAGE_CACHE_SIZE)
-		};
+		size_t size = min(con->out_skip, (int) PAGE_CACHE_SIZE);
 
-		ret = ceph_tcp_sendmsg(con->sock, &iov, 1, iov.iov_len, 1);
+		ret = ceph_tcp_sendpage(con->sock, zero_page, 0, size, 1);
 		if (ret <= 0)
 			goto out;
 		con->out_skip -= ret;
@@ -1085,8 +1113,8 @@
 static int ceph_pton(const char *str, size_t len, struct sockaddr_storage *ss,
 		char delim, const char **ipend)
 {
-	struct sockaddr_in *in4 = (void *)ss;
-	struct sockaddr_in6 *in6 = (void *)ss;
+	struct sockaddr_in *in4 = (struct sockaddr_in *) ss;
+	struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) ss;
 
 	memset(ss, 0, sizeof(*ss));
 
@@ -1512,10 +1540,9 @@
 		if (ret <= 0)
 			return ret;
 		section->iov_len += ret;
-		if (section->iov_len == sec_len)
-			*crc = crc32c(0, section->iov_base,
-				      section->iov_len);
 	}
+	if (section->iov_len == sec_len)
+		*crc = crc32c(0, section->iov_base, section->iov_len);
 
 	return 1;
 }
@@ -1527,7 +1554,7 @@
 
 static int read_partial_message_pages(struct ceph_connection *con,
 				      struct page **pages,
-				      unsigned data_len, int datacrc)
+				      unsigned data_len, bool do_datacrc)
 {
 	void *p;
 	int ret;
@@ -1540,7 +1567,7 @@
 	p = kmap(pages[con->in_msg_pos.page]);
 	ret = ceph_tcp_recvmsg(con->sock, p + con->in_msg_pos.page_pos,
 			       left);
-	if (ret > 0 && datacrc)
+	if (ret > 0 && do_datacrc)
 		con->in_data_crc =
 			crc32c(con->in_data_crc,
 				  p + con->in_msg_pos.page_pos, ret);
@@ -1560,7 +1587,7 @@
 #ifdef CONFIG_BLOCK
 static int read_partial_message_bio(struct ceph_connection *con,
 				    struct bio **bio_iter, int *bio_seg,
-				    unsigned data_len, int datacrc)
+				    unsigned data_len, bool do_datacrc)
 {
 	struct bio_vec *bv = bio_iovec_idx(*bio_iter, *bio_seg);
 	void *p;
@@ -1576,7 +1603,7 @@
 
 	ret = ceph_tcp_recvmsg(con->sock, p + con->in_msg_pos.page_pos,
 			       left);
-	if (ret > 0 && datacrc)
+	if (ret > 0 && do_datacrc)
 		con->in_data_crc =
 			crc32c(con->in_data_crc,
 				  p + con->in_msg_pos.page_pos, ret);
@@ -1603,9 +1630,10 @@
 	int ret;
 	int to, left;
 	unsigned front_len, middle_len, data_len;
-	int datacrc = con->msgr->nocrc;
+	bool do_datacrc = !con->msgr->nocrc;
 	int skip;
 	u64 seq;
+	u32 crc;
 
 	dout("read_partial_message con %p msg %p\n", con, m);
 
@@ -1618,17 +1646,16 @@
 		if (ret <= 0)
 			return ret;
 		con->in_base_pos += ret;
-		if (con->in_base_pos == sizeof(con->in_hdr)) {
-			u32 crc = crc32c(0, (void *)&con->in_hdr,
-				 sizeof(con->in_hdr) - sizeof(con->in_hdr.crc));
-			if (crc != le32_to_cpu(con->in_hdr.crc)) {
-				pr_err("read_partial_message bad hdr "
-				       " crc %u != expected %u\n",
-				       crc, con->in_hdr.crc);
-				return -EBADMSG;
-			}
-		}
 	}
+
+	crc = crc32c(0, &con->in_hdr, offsetof(struct ceph_msg_header, crc));
+	if (cpu_to_le32(crc) != con->in_hdr.crc) {
+		pr_err("read_partial_message bad hdr "
+		       " crc %u != expected %u\n",
+		       crc, con->in_hdr.crc);
+		return -EBADMSG;
+	}
+
 	front_len = le32_to_cpu(con->in_hdr.front_len);
 	if (front_len > CEPH_MSG_MAX_FRONT_LEN)
 		return -EIO;
@@ -1714,7 +1741,7 @@
 	while (con->in_msg_pos.data_pos < data_len) {
 		if (m->pages) {
 			ret = read_partial_message_pages(con, m->pages,
-						 data_len, datacrc);
+						 data_len, do_datacrc);
 			if (ret <= 0)
 				return ret;
 #ifdef CONFIG_BLOCK
@@ -1722,7 +1749,7 @@
 
 			ret = read_partial_message_bio(con,
 						 &m->bio_iter, &m->bio_seg,
-						 data_len, datacrc);
+						 data_len, do_datacrc);
 			if (ret <= 0)
 				return ret;
 #endif
@@ -1757,7 +1784,7 @@
 		       m, con->in_middle_crc, m->footer.middle_crc);
 		return -EBADMSG;
 	}
-	if (datacrc &&
+	if (do_datacrc &&
 	    (m->footer.flags & CEPH_MSG_FOOTER_NOCRC) == 0 &&
 	    con->in_data_crc != le32_to_cpu(m->footer.data_crc)) {
 		pr_err("read_partial_message %p data crc %u != exp. %u\n", m,
@@ -1819,7 +1846,6 @@
 
 	/* open the socket first? */
 	if (con->sock == NULL) {
-		prepare_write_banner(msgr, con);
 		prepare_write_connect(msgr, con, 1);
 		prepare_read_banner(con);
 		set_bit(CONNECTING, &con->state);
@@ -1829,11 +1855,9 @@
 		con->in_tag = CEPH_MSGR_TAG_READY;
 		dout("try_write initiating connect on %p new state %lu\n",
 		     con, con->state);
-		con->sock = ceph_tcp_connect(con);
-		if (IS_ERR(con->sock)) {
-			con->sock = NULL;
+		ret = ceph_tcp_connect(con);
+		if (ret < 0) {
 			con->error_msg = "connect error";
-			ret = -1;
 			goto out;
 		}
 	}
@@ -1953,8 +1977,9 @@
 		 *
 		 * FIXME: there must be a better way to do this!
 		 */
-		static char buf[1024];
-		int skip = min(1024, -con->in_base_pos);
+		static char buf[SKIP_BUF_SIZE];
+		int skip = min((int) sizeof (buf), -con->in_base_pos);
+
 		dout("skipping %d / %d bytes\n", skip, -con->in_base_pos);
 		ret = ceph_tcp_recvmsg(con->sock, buf, skip);
 		if (ret <= 0)
@@ -2216,15 +2241,6 @@
 
 	spin_lock_init(&msgr->global_seq_lock);
 
-	/* the zero page is needed if a request is "canceled" while the message
-	 * is being written over the socket */
-	msgr->zero_page = __page_cache_alloc(GFP_KERNEL | __GFP_ZERO);
-	if (!msgr->zero_page) {
-		kfree(msgr);
-		return ERR_PTR(-ENOMEM);
-	}
-	kmap(msgr->zero_page);
-
 	if (myaddr)
 		msgr->inst.addr = *myaddr;
 
@@ -2241,8 +2257,6 @@
 void ceph_messenger_destroy(struct ceph_messenger *msgr)
 {
 	dout("destroy %p\n", msgr);
-	kunmap(msgr->zero_page);
-	__free_page(msgr->zero_page);
 	kfree(msgr);
 	dout("destroyed messenger %p\n", msgr);
 }
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index fd863fe7..29ad46e 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -283,7 +283,8 @@
 		ceph_decode_32_safe(p, end, yes, bad);
 #if BITS_PER_LONG == 32
 		err = -EINVAL;
-		if (yes > ULONG_MAX / sizeof(struct crush_rule_step))
+		if (yes > (ULONG_MAX - sizeof(*r))
+			  / sizeof(struct crush_rule_step))
 			goto bad;
 #endif
 		r = c->rules[i] = kmalloc(sizeof(*r) +
diff --git a/net/compat.c b/net/compat.c
index 64b4515..e055708 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -219,8 +219,6 @@
 
 int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
 {
-	struct compat_timeval ctv;
-	struct compat_timespec cts[3];
 	struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
 	struct compat_cmsghdr cmhdr;
 	int cmlen;
@@ -230,24 +228,28 @@
 		return 0; /* XXX: return error? check spec. */
 	}
 
-	if (level == SOL_SOCKET && type == SCM_TIMESTAMP) {
-		struct timeval *tv = (struct timeval *)data;
-		ctv.tv_sec = tv->tv_sec;
-		ctv.tv_usec = tv->tv_usec;
-		data = &ctv;
-		len = sizeof(ctv);
-	}
-	if (level == SOL_SOCKET &&
-	    (type == SCM_TIMESTAMPNS || type == SCM_TIMESTAMPING)) {
-		int count = type == SCM_TIMESTAMPNS ? 1 : 3;
-		int i;
-		struct timespec *ts = (struct timespec *)data;
-		for (i = 0; i < count; i++) {
-			cts[i].tv_sec = ts[i].tv_sec;
-			cts[i].tv_nsec = ts[i].tv_nsec;
+	if (!COMPAT_USE_64BIT_TIME) {
+		struct compat_timeval ctv;
+		struct compat_timespec cts[3];
+		if (level == SOL_SOCKET && type == SCM_TIMESTAMP) {
+			struct timeval *tv = (struct timeval *)data;
+			ctv.tv_sec = tv->tv_sec;
+			ctv.tv_usec = tv->tv_usec;
+			data = &ctv;
+			len = sizeof(ctv);
 		}
-		data = &cts;
-		len = sizeof(cts[0]) * count;
+		if (level == SOL_SOCKET &&
+		    (type == SCM_TIMESTAMPNS || type == SCM_TIMESTAMPING)) {
+			int count = type == SCM_TIMESTAMPNS ? 1 : 3;
+			int i;
+			struct timespec *ts = (struct timespec *)data;
+			for (i = 0; i < count; i++) {
+				cts[i].tv_sec = ts[i].tv_sec;
+				cts[i].tv_nsec = ts[i].tv_nsec;
+			}
+			data = &cts;
+			len = sizeof(cts[0]) * count;
+		}
 	}
 
 	cmlen = CMSG_COMPAT_LEN(len);
@@ -454,11 +456,15 @@
 
 int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
 {
-	struct compat_timeval __user *ctv =
-			(struct compat_timeval __user *) userstamp;
-	int err = -ENOENT;
+	struct compat_timeval __user *ctv;
+	int err;
 	struct timeval tv;
 
+	if (COMPAT_USE_64BIT_TIME)
+		return sock_get_timestamp(sk, userstamp);
+
+	ctv = (struct compat_timeval __user *) userstamp;
+	err = -ENOENT;
 	if (!sock_flag(sk, SOCK_TIMESTAMP))
 		sock_enable_timestamp(sk, SOCK_TIMESTAMP);
 	tv = ktime_to_timeval(sk->sk_stamp);
@@ -478,11 +484,15 @@
 
 int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
 {
-	struct compat_timespec __user *ctv =
-			(struct compat_timespec __user *) userstamp;
-	int err = -ENOENT;
+	struct compat_timespec __user *ctv;
+	int err;
 	struct timespec ts;
 
+	if (COMPAT_USE_64BIT_TIME)
+		return sock_get_timestampns (sk, userstamp);
+
+	ctv = (struct compat_timespec __user *) userstamp;
+	err = -ENOENT;
 	if (!sock_flag(sk, SOCK_TIMESTAMP))
 		sock_enable_timestamp(sk, SOCK_TIMESTAMP);
 	ts = ktime_to_timespec(sk->sk_stamp);
@@ -767,6 +777,11 @@
 	int datagrams;
 	struct timespec ktspec;
 
+	if (COMPAT_USE_64BIT_TIME)
+		return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
+				      flags | MSG_CMSG_COMPAT,
+				      (struct timespec *) timeout);
+
 	if (timeout == NULL)
 		return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
 				      flags | MSG_CMSG_COMPAT, NULL);
diff --git a/net/core/datagram.c b/net/core/datagram.c
index d3cf12f..e4fbfd6 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -37,7 +37,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/errno.h>
diff --git a/net/core/dev.c b/net/core/dev.c
index 452db70..c25d453 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -73,7 +73,6 @@
  */
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/bitops.h>
 #include <linux/capability.h>
 #include <linux/cpu.h>
@@ -1597,6 +1596,7 @@
 		kfree_skb(skb);
 		return NET_RX_DROP;
 	}
+	skb->skb_iif = 0;
 	skb_set_dev(skb, dev);
 	skb->tstamp.tv64 = 0;
 	skb->pkt_type = PACKET_HOST;
@@ -4028,54 +4028,41 @@
 
 #ifdef CONFIG_PROC_FS
 
-#define BUCKET_SPACE (32 - NETDEV_HASHBITS)
-
-struct dev_iter_state {
-	struct seq_net_private p;
-	unsigned int pos; /* bucket << BUCKET_SPACE + offset */
-};
+#define BUCKET_SPACE (32 - NETDEV_HASHBITS - 1)
 
 #define get_bucket(x) ((x) >> BUCKET_SPACE)
 #define get_offset(x) ((x) & ((1 << BUCKET_SPACE) - 1))
 #define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o))
 
-static inline struct net_device *dev_from_same_bucket(struct seq_file *seq)
+static inline struct net_device *dev_from_same_bucket(struct seq_file *seq, loff_t *pos)
 {
-	struct dev_iter_state *state = seq->private;
 	struct net *net = seq_file_net(seq);
 	struct net_device *dev;
 	struct hlist_node *p;
 	struct hlist_head *h;
-	unsigned int count, bucket, offset;
+	unsigned int count = 0, offset = get_offset(*pos);
 
-	bucket = get_bucket(state->pos);
-	offset = get_offset(state->pos);
-	h = &net->dev_name_head[bucket];
-	count = 0;
+	h = &net->dev_name_head[get_bucket(*pos)];
 	hlist_for_each_entry_rcu(dev, p, h, name_hlist) {
-		if (count++ == offset) {
-			state->pos = set_bucket_offset(bucket, count);
+		if (++count == offset)
 			return dev;
-		}
 	}
 
 	return NULL;
 }
 
-static inline struct net_device *dev_from_new_bucket(struct seq_file *seq)
+static inline struct net_device *dev_from_bucket(struct seq_file *seq, loff_t *pos)
 {
-	struct dev_iter_state *state = seq->private;
 	struct net_device *dev;
 	unsigned int bucket;
 
-	bucket = get_bucket(state->pos);
 	do {
-		dev = dev_from_same_bucket(seq);
+		dev = dev_from_same_bucket(seq, pos);
 		if (dev)
 			return dev;
 
-		bucket++;
-		state->pos = set_bucket_offset(bucket, 0);
+		bucket = get_bucket(*pos) + 1;
+		*pos = set_bucket_offset(bucket, 1);
 	} while (bucket < NETDEV_HASHENTRIES);
 
 	return NULL;
@@ -4088,33 +4075,20 @@
 void *dev_seq_start(struct seq_file *seq, loff_t *pos)
 	__acquires(RCU)
 {
-	struct dev_iter_state *state = seq->private;
-
 	rcu_read_lock();
 	if (!*pos)
 		return SEQ_START_TOKEN;
 
-	/* check for end of the hash */
-	if (state->pos == 0 && *pos > 1)
+	if (get_bucket(*pos) >= NETDEV_HASHENTRIES)
 		return NULL;
 
-	return dev_from_new_bucket(seq);
+	return dev_from_bucket(seq, pos);
 }
 
 void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-	struct net_device *dev;
-
 	++*pos;
-
-	if (v == SEQ_START_TOKEN)
-		return dev_from_new_bucket(seq);
-
-	dev = dev_from_same_bucket(seq);
-	if (dev)
-		return dev;
-
-	return dev_from_new_bucket(seq);
+	return dev_from_bucket(seq, pos);
 }
 
 void dev_seq_stop(struct seq_file *seq, void *v)
@@ -4213,13 +4187,7 @@
 static int dev_seq_open(struct inode *inode, struct file *file)
 {
 	return seq_open_net(inode, file, &dev_seq_ops,
-			    sizeof(struct dev_iter_state));
-}
-
-int dev_seq_open_ops(struct inode *inode, struct file *file,
-		     const struct seq_operations *ops)
-{
-	return seq_open_net(inode, file, ops, sizeof(struct dev_iter_state));
+			    sizeof(struct seq_net_private));
 }
 
 static const struct file_operations dev_seq_fops = {
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index 29c07fe..626698f 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -696,7 +696,8 @@
 
 static int dev_mc_seq_open(struct inode *inode, struct file *file)
 {
-	return dev_seq_open_ops(inode, file, &dev_mc_seq_ops);
+	return seq_open_net(inode, file, &dev_mc_seq_ops,
+			    sizeof(struct seq_net_private));
 }
 
 static const struct file_operations dev_mc_seq_fops = {
diff --git a/net/core/filter.c b/net/core/filter.c
index 5dea452..6f755cc 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -33,15 +33,17 @@
 #include <net/sock.h>
 #include <linux/errno.h>
 #include <linux/timer.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 #include <linux/filter.h>
 #include <linux/reciprocal_div.h>
 #include <linux/ratelimit.h>
 
-/* No hurry in this branch */
-static void *__load_pointer(const struct sk_buff *skb, int k, unsigned int size)
+/* No hurry in this branch
+ *
+ * Exported for the bpf jit load helper.
+ */
+void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, unsigned int size)
 {
 	u8 *ptr = NULL;
 
@@ -60,7 +62,7 @@
 {
 	if (k >= 0)
 		return skb_header_pointer(skb, k, size, buffer);
-	return __load_pointer(skb, k, size);
+	return bpf_internal_load_pointer_neg_helper(skb, k, size);
 }
 
 /**
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c
index 43b03dd..d9d198a 100644
--- a/net/core/gen_estimator.c
+++ b/net/core/gen_estimator.c
@@ -14,7 +14,6 @@
  */
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/bitops.h>
 #include <linux/module.h>
 #include <linux/types.h>
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 1a63c6e..90430b7 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -38,7 +38,6 @@
 #include <linux/pci.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #include <linux/inet.h>
 #include <linux/netdevice.h>
diff --git a/net/core/scm.c b/net/core/scm.c
index ff52ad0..611c5ef 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -28,7 +28,6 @@
 #include <linux/nsproxy.h>
 #include <linux/slab.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 #include <net/protocol.h>
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 6eb656a..baf8d28 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -66,7 +66,6 @@
 #include <net/xfrm.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <trace/events/skb.h>
 
 #include "kmap_skb.h"
@@ -321,12 +320,12 @@
 EXPORT_SYMBOL(__netdev_alloc_skb);
 
 void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
-		int size)
+		     int size, unsigned int truesize)
 {
 	skb_fill_page_desc(skb, i, page, off, size);
 	skb->len += size;
 	skb->data_len += size;
-	skb->truesize += size;
+	skb->truesize += truesize;
 }
 EXPORT_SYMBOL(skb_add_rx_frag);
 
@@ -3162,6 +3161,8 @@
  */
 int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
 {
+	int len = skb->len;
+
 	if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
 	    (unsigned)sk->sk_rcvbuf)
 		return -ENOMEM;
@@ -3176,7 +3177,7 @@
 
 	skb_queue_tail(&sk->sk_error_queue, skb);
 	if (!sock_flag(sk, SOCK_DEAD))
-		sk->sk_data_ready(sk, skb->len);
+		sk->sk_data_ready(sk, len);
 	return 0;
 }
 EXPORT_SYMBOL(sock_queue_err_skb);
diff --git a/net/core/sock.c b/net/core/sock.c
index 9be6d0d..b2e14c0 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -115,7 +115,6 @@
 #include <linux/memcontrol.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #include <linux/netdevice.h>
 #include <net/protocol.h>
diff --git a/net/core/utils.c b/net/core/utils.c
index 386e263f..dc3c3fa 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -30,7 +30,6 @@
 #include <net/net_ratelimit.h>
 
 #include <asm/byteorder.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 
 int net_msg_warn __read_mostly = 1;
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 19acd00..4136987 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -119,7 +119,6 @@
 #include <net/sock.h>
 #include <net/tcp_states.h>
 #include <net/flow.h>
-#include <asm/system.h>
 #include <asm/ioctls.h>
 #include <linux/capability.h>
 #include <linux/mm.h>
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index 74d321a..c00e307 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -42,7 +42,6 @@
 #include <linux/notifier.h>
 #include <linux/slab.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <net/net_namespace.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
index 73fa268..f6544b2 100644
--- a/net/decnet/dn_nsp_in.c
+++ b/net/decnet/dn_nsp_in.c
@@ -60,7 +60,6 @@
 #include <linux/slab.h>
 #include <net/sock.h>
 #include <net/tcp_states.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/termios.h>
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
index bd78836..e446e85 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -52,7 +52,6 @@
 #include <linux/route.h>
 #include <linux/slab.h>
 #include <net/sock.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/termios.h>
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 7e717cb..71b5edc 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -47,7 +47,6 @@
 #include <linux/mutex.h>
 
 #include <linux/uaccess.h>
-#include <asm/system.h>
 
 static const struct proto_ops econet_ops;
 static struct hlist_head econet_sklist;
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index a93af86..bf10a31 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -59,7 +59,6 @@
 #include <net/ip.h>
 #include <net/dsa.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 __setup("ether=", netdev_boot_setup);
 
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index fdf49fd..10e3751 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -91,7 +91,6 @@
 #include <linux/slab.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 #include <linux/inet.h>
 #include <linux/igmp.h>
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 73f46d6..18d9b81 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -113,7 +113,6 @@
 #include <net/ax25.h>
 #include <net/netrom.h>
 
-#include <asm/system.h>
 #include <linux/uaccess.h>
 
 #include <linux/netfilter_arp.h>
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index d4fad5c..6e447ff 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -27,7 +27,6 @@
 
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/bitops.h>
 #include <linux/capability.h>
 #include <linux/module.h>
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 76e72ba..cbe3a68 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -15,7 +15,6 @@
 
 #include <linux/module.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/bitops.h>
 #include <linux/capability.h>
 #include <linux/types.h>
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index a8c5c1d..5063fa3 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -14,7 +14,6 @@
  */
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index da9b9cb..bce36f1 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -51,7 +51,6 @@
 #define VERSION "0.409"
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 9664d35..2cb2bf8 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -91,7 +91,6 @@
 #include <linux/errno.h>
 #include <linux/timer.h>
 #include <linux/init.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <net/checksum.h>
 #include <net/xfrm.h>
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 450e5d2..5dfecfd 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -73,7 +73,6 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/jiffies.h>
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index f3f1108..26eccc5 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -115,7 +115,6 @@
 
 #define pr_fmt(fmt) "IPv4: " fmt
 
-#include <asm/system.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index ff302bd..4910176 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -43,7 +43,6 @@
  */
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 0518a4f..960fbfc3 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -26,7 +26,6 @@
  *
  */
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/types.h>
 #include <linux/capability.h>
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index ab6b36e..50009c7 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -20,7 +20,6 @@
  *
  */
 
-#include <asm/system.h>
 #include <linux/uaccess.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 12ccf88..167ea10 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -66,7 +66,6 @@
 
 #include <linux/module.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -2042,7 +2041,7 @@
 		if (err < 0)
 			goto e_err;
 	}
-	rth = rt_dst_alloc(init_net.loopback_dev,
+	rth = rt_dst_alloc(dev_net(dev)->loopback_dev,
 			   IN_DEV_CONF_GET(in_dev, NOPOLICY), false);
 	if (!rth)
 		goto e_nobufs;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index cfd7edd..5d54ed3 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -860,7 +860,7 @@
 	}
 
 out:
-	if (copied)
+	if (copied && !(flags & MSG_SENDPAGE_NOTLAST))
 		tcp_push(sk, flags, mss_now, tp->nonagle);
 	return copied;
 
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index d6f5fee..fe14105 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -79,7 +79,6 @@
 
 #define pr_fmt(fmt) "UDP: " fmt
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
 #include <linux/bootmem.h>
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 5605f9d..8ed1b93 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -60,7 +60,6 @@
 #endif
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/mroute6.h>
 
 MODULE_AUTHOR("Cast of dozens");
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index af88934..27ac95a 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -66,7 +66,6 @@
 #include <net/inet_common.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 
 /*
  *	The ICMP socket(s). This is the most convenient way to flow control
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 5aa3981..8110362 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -16,7 +16,6 @@
  *
  */
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/types.h>
 #include <linux/sched.h>
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 16c33e3..b2869ca 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -2044,7 +2044,7 @@
 		if (!delta)
 			pmc->mca_sfcount[sfmode]--;
 		for (j=0; j<i; j++)
-			(void) ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]);
+			ip6_mc_del1_src(pmc, sfmode, &psfsrc[j]);
 	} else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) {
 		struct ip6_sf_list *psf;
 
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 24c456e..3992e26 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -881,6 +881,16 @@
 	return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
 }
 
+static struct dst_entry *ip6_route_input_lookup(struct net *net,
+						struct net_device *dev,
+						struct flowi6 *fl6, int flags)
+{
+	if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
+		flags |= RT6_LOOKUP_F_IFACE;
+
+	return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
+}
+
 void ip6_route_input(struct sk_buff *skb)
 {
 	const struct ipv6hdr *iph = ipv6_hdr(skb);
@@ -895,10 +905,7 @@
 		.flowi6_proto = iph->nexthdr,
 	};
 
-	if (rt6_need_strict(&iph->daddr) && skb->dev->type != ARPHRD_PIMREG)
-		flags |= RT6_LOOKUP_F_IFACE;
-
-	skb_dst_set(skb, fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_input));
+	skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
 }
 
 static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
@@ -2474,8 +2481,12 @@
 
 	rcu_read_lock();
 	n = dst_get_neighbour_noref(&rt->dst);
-	if (n)
-		NLA_PUT(skb, RTA_GATEWAY, 16, &n->primary_key);
+	if (n) {
+		if (nla_put(skb, RTA_GATEWAY, 16, &n->primary_key) < 0) {
+			rcu_read_unlock();
+			goto nla_put_failure;
+		}
+	}
 	rcu_read_unlock();
 
 	if (rt->dst.dev)
@@ -2533,7 +2544,7 @@
 	struct sk_buff *skb;
 	struct rtmsg *rtm;
 	struct flowi6 fl6;
-	int err, iif = 0;
+	int err, iif = 0, oif = 0;
 
 	err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
 	if (err < 0)
@@ -2560,15 +2571,29 @@
 		iif = nla_get_u32(tb[RTA_IIF]);
 
 	if (tb[RTA_OIF])
-		fl6.flowi6_oif = nla_get_u32(tb[RTA_OIF]);
+		oif = nla_get_u32(tb[RTA_OIF]);
 
 	if (iif) {
 		struct net_device *dev;
+		int flags = 0;
+
 		dev = __dev_get_by_index(net, iif);
 		if (!dev) {
 			err = -ENODEV;
 			goto errout;
 		}
+
+		fl6.flowi6_iif = iif;
+
+		if (!ipv6_addr_any(&fl6.saddr))
+			flags |= RT6_LOOKUP_F_HAS_SADDR;
+
+		rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
+							       flags);
+	} else {
+		fl6.flowi6_oif = oif;
+
+		rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
 	}
 
 	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
@@ -2583,7 +2608,6 @@
 	skb_reset_mac_header(skb);
 	skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
 
-	rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl6);
 	skb_dst_set(skb, &rt->dst);
 
 	err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
diff --git a/net/irda/irlan/irlan_client.c b/net/irda/irlan/irlan_client.c
index ba1a3fc..42cf139 100644
--- a/net/irda/irlan/irlan_client.c
+++ b/net/irda/irlan/irlan_client.c
@@ -37,7 +37,6 @@
 #include <linux/bitops.h>
 #include <net/arp.h>
 
-#include <asm/system.h>
 #include <asm/byteorder.h>
 
 #include <net/irda/irda.h>
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
index 579617c..7ac4d1b 100644
--- a/net/irda/irlan/irlan_common.c
+++ b/net/irda/irlan/irlan_common.c
@@ -40,7 +40,6 @@
 #include <linux/moduleparam.h>
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 #include <asm/byteorder.h>
 
 #include <net/irda/irda.h>
diff --git a/net/irda/irlan/irlan_provider.c b/net/irda/irlan/irlan_provider.c
index 8b61cf0..32dcaac 100644
--- a/net/irda/irlan/irlan_provider.c
+++ b/net/irda/irlan/irlan_provider.c
@@ -36,7 +36,6 @@
 #include <linux/bitops.h>
 #include <linux/slab.h>
 
-#include <asm/system.h>
 #include <asm/byteorder.h>
 
 #include <net/irda/irda.h>
diff --git a/net/irda/timer.c b/net/irda/timer.c
index f418cb2..1d552b3 100644
--- a/net/irda/timer.c
+++ b/net/irda/timer.c
@@ -24,7 +24,6 @@
  *
  ********************************************************************/
 
-#include <asm/system.h>
 #include <linux/delay.h>
 
 #include <net/irda/timer.h>
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index 403be43..3ad1f9d 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -1800,7 +1800,7 @@
  * Handles external interrupts coming in from CP.
  * Places the interrupt buffer on a queue and schedules iucv_tasklet_fn().
  */
-static void iucv_external_interrupt(unsigned int ext_int_code,
+static void iucv_external_interrupt(struct ext_code ext_code,
 				    unsigned int param32, unsigned long param64)
 {
 	struct iucv_irq_data *p;
diff --git a/net/lapb/lapb_iface.c b/net/lapb/lapb_iface.c
index 8d0324b..ab3d35f 100644
--- a/net/lapb/lapb_iface.c
+++ b/net/lapb/lapb_iface.c
@@ -32,7 +32,6 @@
 #include <linux/slab.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/lapb/lapb_in.c b/net/lapb/lapb_in.c
index 2ec1af5..f4e3c1a 100644
--- a/net/lapb/lapb_in.c
+++ b/net/lapb/lapb_in.c
@@ -30,7 +30,6 @@
 #include <linux/slab.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/lapb/lapb_out.c b/net/lapb/lapb_out.c
index c75a795..baab276 100644
--- a/net/lapb/lapb_out.c
+++ b/net/lapb/lapb_out.c
@@ -28,7 +28,6 @@
 #include <linux/slab.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/lapb/lapb_subr.c b/net/lapb/lapb_subr.c
index 43a2a7f..066225b 100644
--- a/net/lapb/lapb_subr.c
+++ b/net/lapb/lapb_subr.c
@@ -27,7 +27,6 @@
 #include <linux/slab.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/lapb/lapb_timer.c b/net/lapb/lapb_timer.c
index af6d14b..f8cd641 100644
--- a/net/lapb/lapb_timer.c
+++ b/net/lapb/lapb_timer.c
@@ -28,7 +28,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index cc5b7a6..778e591 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -15,12 +15,6 @@
 #include "rate.h"
 #include "debugfs.h"
 
-int mac80211_open_file_generic(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 #define DEBUGFS_FORMAT_BUFFER_SIZE 100
 
 int mac80211_format_buffer(char __user *userbuf, size_t count,
@@ -50,7 +44,7 @@
 #define DEBUGFS_READONLY_FILE_OPS(name)			\
 static const struct file_operations name## _ops = {			\
 	.read = name## _read,						\
-	.open = mac80211_open_file_generic,				\
+	.open = simple_open,						\
 	.llseek = generic_file_llseek,					\
 };
 
@@ -93,7 +87,7 @@
 
 static const struct file_operations reset_ops = {
 	.write = reset_write,
-	.open = mac80211_open_file_generic,
+	.open = simple_open,
 	.llseek = noop_llseek,
 };
 
@@ -254,7 +248,7 @@
 									\
 static const struct file_operations stats_ ##name## _ops = {		\
 	.read = stats_ ##name## _read,					\
-	.open = mac80211_open_file_generic,				\
+	.open = simple_open,						\
 	.llseek = generic_file_llseek,					\
 };
 
diff --git a/net/mac80211/debugfs.h b/net/mac80211/debugfs.h
index 7c87529..9be4e6d 100644
--- a/net/mac80211/debugfs.h
+++ b/net/mac80211/debugfs.h
@@ -3,7 +3,6 @@
 
 #ifdef CONFIG_MAC80211_DEBUGFS
 extern void debugfs_hw_add(struct ieee80211_local *local);
-extern int mac80211_open_file_generic(struct inode *inode, struct file *file);
 extern int mac80211_format_buffer(char __user *userbuf, size_t count,
 				  loff_t *ppos, char *fmt, ...);
 #else
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 59edcd9..7932767 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -30,7 +30,7 @@
 #define KEY_OPS(name)							\
 static const struct file_operations key_ ##name## _ops = {		\
 	.read = key_##name##_read,					\
-	.open = mac80211_open_file_generic,				\
+	.open = simple_open,						\
 	.llseek = generic_file_llseek,					\
 }
 
@@ -45,7 +45,7 @@
 #define KEY_CONF_OPS(name)						\
 static const struct file_operations key_ ##name## _ops = {		\
 	.read = key_conf_##name##_read,					\
-	.open = mac80211_open_file_generic,				\
+	.open = simple_open,						\
 	.llseek = generic_file_llseek,					\
 }
 
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index a32eeda..30f99c3 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -135,7 +135,7 @@
 static const struct file_operations name##_ops = {			\
 	.read = ieee80211_if_read_##name,				\
 	.write = (_write),						\
-	.open = mac80211_open_file_generic,				\
+	.open = simple_open,						\
 	.llseek = generic_file_llseek,					\
 }
 
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 6d45804..832b2da 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -33,7 +33,7 @@
 #define STA_OPS(name)							\
 static const struct file_operations sta_ ##name## _ops = {		\
 	.read = sta_##name##_read,					\
-	.open = mac80211_open_file_generic,				\
+	.open = simple_open,						\
 	.llseek = generic_file_llseek,					\
 }
 
@@ -41,7 +41,7 @@
 static const struct file_operations sta_ ##name## _ops = {		\
 	.read = sta_##name##_read,					\
 	.write = sta_##name##_write,					\
-	.open = mac80211_open_file_generic,				\
+	.open = simple_open,						\
 	.llseek = generic_file_llseek,					\
 }
 
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index b4f7600..3313c11 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -145,7 +145,7 @@
 
 static const struct file_operations rcname_ops = {
 	.read = rcname_read,
-	.open = mac80211_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 #endif
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 33cd169..c70e176 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -370,7 +370,7 @@
 	 */
 	drv_sw_scan_start(local);
 
-	local->leave_oper_channel_time = 0;
+	local->leave_oper_channel_time = jiffies;
 	local->next_scan_state = SCAN_DECISION;
 	local->scan_channel_idx = 0;
 
diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c
index fe6cb43..5285617 100644
--- a/net/netfilter/ipvs/ip_vs_app.c
+++ b/net/netfilter/ipvs/ip_vs_app.c
@@ -31,7 +31,6 @@
 #include <net/net_namespace.h>
 #include <net/protocol.h>
 #include <net/tcp.h>
-#include <asm/system.h>
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c
index 8531293..f843a88 100644
--- a/net/netfilter/ipvs/ip_vs_proto.c
+++ b/net/netfilter/ipvs/ip_vs_proto.c
@@ -25,7 +25,6 @@
 #include <net/protocol.h>
 #include <net/tcp.h>
 #include <net/udp.h>
-#include <asm/system.h>
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 7b48035..3cc4487 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -735,6 +735,7 @@
 
 #ifdef CONFIG_NF_CONNTRACK_ZONES
 out_free:
+	atomic_dec(&net->ct.count);
 	kmem_cache_free(net->ct.nf_conntrack_cachep, ct);
 	return ERR_PTR(-ENOMEM);
 #endif
@@ -768,8 +769,7 @@
 	       struct nf_conntrack_l3proto *l3proto,
 	       struct nf_conntrack_l4proto *l4proto,
 	       struct sk_buff *skb,
-	       unsigned int dataoff, u32 hash,
-	       unsigned int *timeouts)
+	       unsigned int dataoff, u32 hash)
 {
 	struct nf_conn *ct;
 	struct nf_conn_help *help;
@@ -777,6 +777,8 @@
 	struct nf_conntrack_ecache *ecache;
 	struct nf_conntrack_expect *exp;
 	u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
+	struct nf_conn_timeout *timeout_ext;
+	unsigned int *timeouts;
 
 	if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) {
 		pr_debug("Can't invert tuple.\n");
@@ -788,12 +790,21 @@
 	if (IS_ERR(ct))
 		return (struct nf_conntrack_tuple_hash *)ct;
 
+	timeout_ext = tmpl ? nf_ct_timeout_find(tmpl) : NULL;
+	if (timeout_ext)
+		timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext);
+	else
+		timeouts = l4proto->get_timeouts(net);
+
 	if (!l4proto->new(ct, skb, dataoff, timeouts)) {
 		nf_conntrack_free(ct);
 		pr_debug("init conntrack: can't track with proto module\n");
 		return NULL;
 	}
 
+	if (timeout_ext)
+		nf_ct_timeout_ext_add(ct, timeout_ext->timeout, GFP_ATOMIC);
+
 	nf_ct_acct_ext_add(ct, GFP_ATOMIC);
 	nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
 
@@ -854,8 +865,7 @@
 		  struct nf_conntrack_l3proto *l3proto,
 		  struct nf_conntrack_l4proto *l4proto,
 		  int *set_reply,
-		  enum ip_conntrack_info *ctinfo,
-		  unsigned int *timeouts)
+		  enum ip_conntrack_info *ctinfo)
 {
 	struct nf_conntrack_tuple tuple;
 	struct nf_conntrack_tuple_hash *h;
@@ -875,7 +885,7 @@
 	h = __nf_conntrack_find_get(net, zone, &tuple, hash);
 	if (!h) {
 		h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto,
-				   skb, dataoff, hash, timeouts);
+				   skb, dataoff, hash);
 		if (!h)
 			return NULL;
 		if (IS_ERR(h))
@@ -964,19 +974,8 @@
 			goto out;
 	}
 
-	/* Decide what timeout policy we want to apply to this flow. */
-	if (tmpl) {
-	        timeout_ext = nf_ct_timeout_find(tmpl);
-		if (timeout_ext)
-			timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext);
-		else
-			timeouts = l4proto->get_timeouts(net);
-	} else
-		timeouts = l4proto->get_timeouts(net);
-
 	ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum,
-			       l3proto, l4proto, &set_reply, &ctinfo,
-			       timeouts);
+			       l3proto, l4proto, &set_reply, &ctinfo);
 	if (!ct) {
 		/* Not valid part of a connection */
 		NF_CT_STAT_INC_ATOMIC(net, invalid);
@@ -993,6 +992,13 @@
 
 	NF_CT_ASSERT(skb->nfct);
 
+	/* Decide what timeout policy we want to apply to this flow. */
+	timeout_ext = nf_ct_timeout_find(ct);
+	if (timeout_ext)
+		timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext);
+	else
+		timeouts = l4proto->get_timeouts(net);
+
 	ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum, timeouts);
 	if (ret <= 0) {
 		/* Invalid: inverse of the return code tells
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index 5701c8d..be3da2c 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -127,6 +127,27 @@
 }
 EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put);
 
+struct nf_conntrack_l4proto *
+nf_ct_l4proto_find_get(u_int16_t l3num, u_int8_t l4num)
+{
+	struct nf_conntrack_l4proto *p;
+
+	rcu_read_lock();
+	p = __nf_ct_l4proto_find(l3num, l4num);
+	if (!try_module_get(p->me))
+		p = &nf_conntrack_l4proto_generic;
+	rcu_read_unlock();
+
+	return p;
+}
+EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get);
+
+void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p)
+{
+	module_put(p->me);
+}
+EXPORT_SYMBOL_GPL(nf_ct_l4proto_put);
+
 static int kill_l3proto(struct nf_conn *i, void *data)
 {
 	return nf_ct_l3num(i) == ((struct nf_conntrack_l3proto *)data)->l3proto;
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 4d70785..e6ddde1 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -23,7 +23,6 @@
 #include <linux/net.h>
 #include <linux/skbuff.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <net/sock.h>
 #include <net/netlink.h>
 #include <linux/init.h>
diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c
index 3eb348b..d98c868 100644
--- a/net/netfilter/nfnetlink_acct.c
+++ b/net/netfilter/nfnetlink_acct.c
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
+#include <linux/atomic.h>
 #include <linux/netlink.h>
 #include <linux/rculist.h>
 #include <linux/slab.h>
@@ -17,7 +18,6 @@
 #include <linux/errno.h>
 #include <net/netlink.h>
 #include <net/sock.h>
-#include <asm/atomic.h>
 
 #include <linux/netfilter.h>
 #include <linux/netfilter/nfnetlink.h>
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c
index fec29a4..2b9e79f 100644
--- a/net/netfilter/nfnetlink_cttimeout.c
+++ b/net/netfilter/nfnetlink_cttimeout.c
@@ -98,11 +98,13 @@
 		break;
 	}
 
-	l4proto = __nf_ct_l4proto_find(l3num, l4num);
+	l4proto = nf_ct_l4proto_find_get(l3num, l4num);
 
 	/* This protocol is not supportted, skip. */
-	if (l4proto->l4proto != l4num)
-		return -EOPNOTSUPP;
+	if (l4proto->l4proto != l4num) {
+		ret = -EOPNOTSUPP;
+		goto err_proto_put;
+	}
 
 	if (matching) {
 		if (nlh->nlmsg_flags & NLM_F_REPLACE) {
@@ -110,20 +112,25 @@
 			 * different kind, sorry.
 			 */
 			if (matching->l3num != l3num ||
-			    matching->l4num != l4num)
-				return -EINVAL;
+			    matching->l4proto->l4proto != l4num) {
+				ret = -EINVAL;
+				goto err_proto_put;
+			}
 
 			ret = ctnl_timeout_parse_policy(matching, l4proto,
 							cda[CTA_TIMEOUT_DATA]);
 			return ret;
 		}
-		return -EBUSY;
+		ret = -EBUSY;
+		goto err_proto_put;
 	}
 
 	timeout = kzalloc(sizeof(struct ctnl_timeout) +
 			  l4proto->ctnl_timeout.obj_size, GFP_KERNEL);
-	if (timeout == NULL)
-		return -ENOMEM;
+	if (timeout == NULL) {
+		ret = -ENOMEM;
+		goto err_proto_put;
+	}
 
 	ret = ctnl_timeout_parse_policy(timeout, l4proto,
 					cda[CTA_TIMEOUT_DATA]);
@@ -132,13 +139,15 @@
 
 	strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME]));
 	timeout->l3num = l3num;
-	timeout->l4num = l4num;
+	timeout->l4proto = l4proto;
 	atomic_set(&timeout->refcnt, 1);
 	list_add_tail_rcu(&timeout->head, &cttimeout_list);
 
 	return 0;
 err:
 	kfree(timeout);
+err_proto_put:
+	nf_ct_l4proto_put(l4proto);
 	return ret;
 }
 
@@ -149,7 +158,7 @@
 	struct nlmsghdr *nlh;
 	struct nfgenmsg *nfmsg;
 	unsigned int flags = pid ? NLM_F_MULTI : 0;
-	struct nf_conntrack_l4proto *l4proto;
+	struct nf_conntrack_l4proto *l4proto = timeout->l4proto;
 
 	event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8;
 	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags);
@@ -163,20 +172,10 @@
 
 	NLA_PUT_STRING(skb, CTA_TIMEOUT_NAME, timeout->name);
 	NLA_PUT_BE16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num));
-	NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4num);
+	NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4proto->l4proto);
 	NLA_PUT_BE32(skb, CTA_TIMEOUT_USE,
 			htonl(atomic_read(&timeout->refcnt)));
 
-	l4proto = __nf_ct_l4proto_find(timeout->l3num, timeout->l4num);
-
-	/* If the timeout object does not match the layer 4 protocol tracker,
-	 * then skip dumping the data part since we don't know how to
-	 * interpret it. This may happen for UPDlite, SCTP and DCCP since
-	 * you can unload the module.
-	 */
-	if (timeout->l4num != l4proto->l4proto)
-		goto out;
-
 	if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) {
 		struct nlattr *nest_parms;
 		int ret;
@@ -192,7 +191,7 @@
 
 		nla_nest_end(skb, nest_parms);
 	}
-out:
+
 	nlmsg_end(skb, nlh);
 	return skb->len;
 
@@ -293,6 +292,7 @@
 	if (atomic_dec_and_test(&timeout->refcnt)) {
 		/* We are protected by nfnl mutex. */
 		list_del_rcu(&timeout->head);
+		nf_ct_l4proto_put(timeout->l4proto);
 		kfree_rcu(timeout, rcu_head);
 	} else {
 		/* still in use, restore reference counter. */
@@ -417,6 +417,7 @@
 		/* We are sure that our objects have no clients at this point,
 		 * it's safe to release them all without checking refcnt.
 		 */
+		nf_ct_l4proto_put(cur->l4proto);
 		kfree_rcu(cur, rcu_head);
 	}
 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index b873445..59530e9 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -14,8 +14,10 @@
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_CT.h>
 #include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_l4proto.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_ecache.h>
+#include <net/netfilter/nf_conntrack_l4proto.h>
 #include <net/netfilter/nf_conntrack_timeout.h>
 #include <net/netfilter/nf_conntrack_zones.h>
 
@@ -148,6 +150,17 @@
 	return ret;
 }
 
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+static void __xt_ct_tg_timeout_put(struct ctnl_timeout *timeout)
+{
+	typeof(nf_ct_timeout_put_hook) timeout_put;
+
+	timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
+	if (timeout_put)
+		timeout_put(timeout);
+}
+#endif
+
 static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
 {
 	struct xt_ct_target_info_v1 *info = par->targinfo;
@@ -156,7 +169,9 @@
 	struct nf_conn *ct;
 	int ret = 0;
 	u8 proto;
-
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+	struct ctnl_timeout *timeout;
+#endif
 	if (info->flags & ~XT_CT_NOTRACK)
 		return -EINVAL;
 
@@ -214,53 +229,61 @@
 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
 	if (info->timeout) {
 		typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
-		struct ctnl_timeout *timeout;
 		struct nf_conn_timeout *timeout_ext;
 
+		rcu_read_lock();
 		timeout_find_get =
 			rcu_dereference(nf_ct_timeout_find_get_hook);
 
 		if (timeout_find_get) {
 			const struct ipt_entry *e = par->entryinfo;
+			struct nf_conntrack_l4proto *l4proto;
 
 			if (e->ip.invflags & IPT_INV_PROTO) {
 				ret = -EINVAL;
 				pr_info("You cannot use inversion on "
 					 "L4 protocol\n");
-				goto err3;
+				goto err4;
 			}
 			timeout = timeout_find_get(info->timeout);
 			if (timeout == NULL) {
 				ret = -ENOENT;
 				pr_info("No such timeout policy \"%s\"\n",
 					info->timeout);
-				goto err3;
+				goto err4;
 			}
 			if (timeout->l3num != par->family) {
 				ret = -EINVAL;
 				pr_info("Timeout policy `%s' can only be "
 					"used by L3 protocol number %d\n",
 					info->timeout, timeout->l3num);
-				goto err3;
+				goto err5;
 			}
-			if (timeout->l4num != e->ip.proto) {
+			/* Make sure the timeout policy matches any existing
+			 * protocol tracker, otherwise default to generic.
+			 */
+			l4proto = __nf_ct_l4proto_find(par->family,
+						       e->ip.proto);
+			if (timeout->l4proto->l4proto != l4proto->l4proto) {
 				ret = -EINVAL;
 				pr_info("Timeout policy `%s' can only be "
 					"used by L4 protocol number %d\n",
-					info->timeout, timeout->l4num);
-				goto err3;
+					info->timeout,
+					timeout->l4proto->l4proto);
+				goto err5;
 			}
 			timeout_ext = nf_ct_timeout_ext_add(ct, timeout,
-							    GFP_KERNEL);
+							    GFP_ATOMIC);
 			if (timeout_ext == NULL) {
 				ret = -ENOMEM;
-				goto err3;
+				goto err5;
 			}
 		} else {
 			ret = -ENOENT;
 			pr_info("Timeout policy base is empty\n");
-			goto err3;
+			goto err4;
 		}
+		rcu_read_unlock();
 	}
 #endif
 
@@ -270,6 +293,12 @@
 	info->ct = ct;
 	return 0;
 
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+err5:
+	__xt_ct_tg_timeout_put(timeout);
+err4:
+	rcu_read_unlock();
+#endif
 err3:
 	nf_conntrack_free(ct);
 err2:
@@ -311,6 +340,7 @@
 		nf_ct_l3proto_module_put(par->family);
 
 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+		rcu_read_lock();
 		timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
 
 		if (timeout_put) {
@@ -318,6 +348,7 @@
 			if (timeout_ext)
 				timeout_put(timeout_ext->timeout);
 		}
+		rcu_read_unlock();
 #endif
 	}
 	nf_ct_put(info->ct);
diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c
index f99f8de..ff5f75f 100644
--- a/net/netfilter/xt_LOG.c
+++ b/net/netfilter/xt_LOG.c
@@ -480,7 +480,7 @@
 	sb_close(m);
 }
 
-#if IS_ENABLED(CONFIG_IPV6)
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 /* One level of recursion won't kill us */
 static void dump_ipv6_packet(struct sbuff *m,
 			const struct nf_loginfo *info,
@@ -824,7 +824,7 @@
 	if (par->family == NFPROTO_IPV4)
 		ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in,
 			       par->out, &li, loginfo->prefix);
-#if IS_ENABLED(CONFIG_IPV6)
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 	else if (par->family == NFPROTO_IPV6)
 		ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in,
 				par->out, &li, loginfo->prefix);
@@ -864,7 +864,7 @@
 		.checkentry	= log_tg_check,
 		.me		= THIS_MODULE,
 	},
-#if IS_ENABLED(CONFIG_IPV6)
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 	{
 		.name		= "LOG",
 		.family		= NFPROTO_IPV6,
@@ -882,7 +882,7 @@
 	.me		= THIS_MODULE,
 };
 
-#if IS_ENABLED(CONFIG_IPV6)
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 static struct nf_logger ip6t_log_logger __read_mostly = {
 	.name		= "ip6t_LOG",
 	.logfn		= &ip6t_log_packet,
@@ -899,7 +899,7 @@
 		return ret;
 
 	nf_log_register(NFPROTO_IPV4, &ipt_log_logger);
-#if IS_ENABLED(CONFIG_IPV6)
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 	nf_log_register(NFPROTO_IPV6, &ip6t_log_logger);
 #endif
 	return 0;
@@ -908,7 +908,7 @@
 static void __exit log_tg_exit(void)
 {
 	nf_log_unregister(&ipt_log_logger);
-#if IS_ENABLED(CONFIG_IPV6)
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 	nf_log_unregister(&ip6t_log_logger);
 #endif
 	xt_unregister_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs));
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 32bb753..faa48f7 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -829,12 +829,19 @@
 	return 0;
 }
 
-int netlink_sendskb(struct sock *sk, struct sk_buff *skb)
+static int __netlink_sendskb(struct sock *sk, struct sk_buff *skb)
 {
 	int len = skb->len;
 
 	skb_queue_tail(&sk->sk_receive_queue, skb);
 	sk->sk_data_ready(sk, len);
+	return len;
+}
+
+int netlink_sendskb(struct sock *sk, struct sk_buff *skb)
+{
+	int len = __netlink_sendskb(sk, skb);
+
 	sock_put(sk);
 	return len;
 }
@@ -957,8 +964,7 @@
 	if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf &&
 	    !test_bit(0, &nlk->state)) {
 		skb_set_owner_r(skb, sk);
-		skb_queue_tail(&sk->sk_receive_queue, skb);
-		sk->sk_data_ready(sk, skb->len);
+		__netlink_sendskb(sk, skb);
 		return atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1);
 	}
 	return -1;
@@ -1698,10 +1704,8 @@
 
 		if (sk_filter(sk, skb))
 			kfree_skb(skb);
-		else {
-			skb_queue_tail(&sk->sk_receive_queue, skb);
-			sk->sk_data_ready(sk, skb->len);
-		}
+		else
+			__netlink_sendskb(sk, skb);
 		return 0;
 	}
 
@@ -1715,10 +1719,8 @@
 
 	if (sk_filter(sk, skb))
 		kfree_skb(skb);
-	else {
-		skb_queue_tail(&sk->sk_receive_queue, skb);
-		sk->sk_data_ready(sk, skb->len);
-	}
+	else
+		__netlink_sendskb(sk, skb);
 
 	if (cb->done)
 		cb->done(cb);
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 7dab229..06592d8 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -31,7 +31,6 @@
 #include <net/net_namespace.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/termios.h>	/* For TIOCINQ/OUTQ */
 #include <linux/mm.h>
diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c
index 64e6dde..1c51d7a 100644
--- a/net/netrom/nr_dev.c
+++ b/net/netrom/nr_dev.c
@@ -21,7 +21,6 @@
 #include <linux/if_ether.h>	/* For the statistics structure. */
 #include <linux/slab.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
diff --git a/net/netrom/nr_in.c b/net/netrom/nr_in.c
index 6d4ef6d65..c3073a2 100644
--- a/net/netrom/nr_in.c
+++ b/net/netrom/nr_in.c
@@ -24,7 +24,6 @@
 #include <net/sock.h>
 #include <net/tcp_states.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/netrom/nr_out.c b/net/netrom/nr_out.c
index 607fddb..0b4bcb2 100644
--- a/net/netrom/nr_out.c
+++ b/net/netrom/nr_out.c
@@ -23,7 +23,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index 2cf3301..70ffff7 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -26,7 +26,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/termios.h>	/* For TIOCINQ/OUTQ */
 #include <linux/mm.h>
diff --git a/net/netrom/nr_subr.c b/net/netrom/nr_subr.c
index 6a947ae..ca40e22 100644
--- a/net/netrom/nr_subr.c
+++ b/net/netrom/nr_subr.c
@@ -23,7 +23,6 @@
 #include <net/sock.h>
 #include <net/tcp_states.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c
index 1cb98e8..ff2c1b1 100644
--- a/net/netrom/nr_timer.c
+++ b/net/netrom/nr_timer.c
@@ -24,7 +24,6 @@
 #include <net/sock.h>
 #include <net/tcp_states.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 2c03050..e44e631 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -38,7 +38,6 @@
 #include <linux/udp.h>
 #include <linux/ethtool.h>
 #include <linux/wait.h>
-#include <asm/system.h>
 #include <asm/div64.h>
 #include <linux/highmem.h>
 #include <linux/netfilter_bridge.h>
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index ae2d484..4f2c0df 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -73,7 +73,6 @@
 #include <net/sock.h>
 #include <linux/errno.h>
 #include <linux/timer.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
 #include <asm/page.h>
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index 9f60008..9726fe6 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -1130,6 +1130,9 @@
 	int flags = msg->msg_flags;
 	int err, done;
 
+	if (len > USHRT_MAX)
+		return -EMSGSIZE;
+
 	if ((msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|
 				MSG_CMSG_COMPAT)) ||
 			!(msg->msg_flags & MSG_EOR))
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 354760e..f974961 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -29,6 +29,7 @@
 #include <linux/rfkill.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
+#include <linux/device.h>
 #include <linux/miscdevice.h>
 #include <linux/wait.h>
 #include <linux/poll.h>
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index f9ea925..c4719ce 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -34,7 +34,6 @@
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/fcntl.h>
 #include <linux/termios.h>
diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c
index 178ff4f..906cc05 100644
--- a/net/rose/rose_dev.c
+++ b/net/rose/rose_dev.c
@@ -21,7 +21,6 @@
 #include <linux/if_ether.h>
 #include <linux/slab.h>
 
-#include <asm/system.h>
 #include <asm/io.h>
 
 #include <linux/inet.h>
@@ -96,11 +95,11 @@
 	struct sockaddr *sa = addr;
 	int err;
 
-	if (!memcpy(dev->dev_addr, sa->sa_data, dev->addr_len))
+	if (!memcmp(dev->dev_addr, sa->sa_data, dev->addr_len))
 		return 0;
 
 	if (dev->flags & IFF_UP) {
-		err = rose_add_loopback_node((rose_address *)dev->dev_addr);
+		err = rose_add_loopback_node((rose_address *)sa->sa_data);
 		if (err)
 			return err;
 
diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c
index 7f7fcb4..79c4abc 100644
--- a/net/rose/rose_in.c
+++ b/net/rose/rose_in.c
@@ -26,7 +26,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/tcp_states.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c
index 7a02bd1..bc55142 100644
--- a/net/rose/rose_link.c
+++ b/net/rose/rose_link.c
@@ -22,7 +22,6 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/rose/rose_out.c b/net/rose/rose_out.c
index 4ebf33af..9ad98b5 100644
--- a/net/rose/rose_out.c
+++ b/net/rose/rose_out.c
@@ -21,7 +21,6 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index cd9b7ee..40148932 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -25,7 +25,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/tcp_states.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/fcntl.h>
 #include <linux/termios.h>	/* For TIOCINQ/OUTQ */
diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c
index f6c71ca..47f1fdb 100644
--- a/net/rose/rose_subr.c
+++ b/net/rose/rose_subr.c
@@ -22,7 +22,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/tcp_states.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c
index b6c8f38..bc5469d 100644
--- a/net/rose/rose_timer.c
+++ b/net/rose/rose_timer.c
@@ -23,7 +23,6 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/tcp_states.h>
-#include <asm/system.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 06b42b7..92ba71d 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4133,9 +4133,10 @@
 static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval,
 				  int __user *optlen)
 {
-	if (len < sizeof(struct sctp_event_subscribe))
+	if (len <= 0)
 		return -EINVAL;
-	len = sizeof(struct sctp_event_subscribe);
+	if (len > sizeof(struct sctp_event_subscribe))
+		len = sizeof(struct sctp_event_subscribe);
 	if (put_user(len, optlen))
 		return -EFAULT;
 	if (copy_to_user(optval, &sctp_sk(sk)->subscribe, len))
diff --git a/net/socket.c b/net/socket.c
index 12a48d8..851edcd 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -811,9 +811,9 @@
 
 	sock = file->private_data;
 
-	flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
-	if (more)
-		flags |= MSG_MORE;
+	flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
+	/* more is a combination of MSG_MORE and MSG_SENDPAGE_NOTLAST */
+	flags |= more;
 
 	return kernel_sendpage(sock, page, offset, size, flags);
 }
@@ -2592,7 +2592,7 @@
 
 #ifdef CONFIG_COMPAT
 static int do_siocgstamp(struct net *net, struct socket *sock,
-			 unsigned int cmd, struct compat_timeval __user *up)
+			 unsigned int cmd, void __user *up)
 {
 	mm_segment_t old_fs = get_fs();
 	struct timeval ktv;
@@ -2601,15 +2601,14 @@
 	set_fs(KERNEL_DS);
 	err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv);
 	set_fs(old_fs);
-	if (!err) {
-		err = put_user(ktv.tv_sec, &up->tv_sec);
-		err |= __put_user(ktv.tv_usec, &up->tv_usec);
-	}
+	if (!err)
+		err = compat_put_timeval(up, &ktv);
+
 	return err;
 }
 
 static int do_siocgstampns(struct net *net, struct socket *sock,
-			 unsigned int cmd, struct compat_timespec __user *up)
+			   unsigned int cmd, void __user *up)
 {
 	mm_segment_t old_fs = get_fs();
 	struct timespec kts;
@@ -2618,10 +2617,9 @@
 	set_fs(KERNEL_DS);
 	err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts);
 	set_fs(old_fs);
-	if (!err) {
-		err = put_user(kts.tv_sec, &up->tv_sec);
-		err |= __put_user(kts.tv_nsec, &up->tv_nsec);
-	}
+	if (!err)
+		err = compat_put_timespec(up, &kts);
+
 	return err;
 }
 
diff --git a/net/sunrpc/Kconfig b/net/sunrpc/Kconfig
index ffd243d..9fe8857 100644
--- a/net/sunrpc/Kconfig
+++ b/net/sunrpc/Kconfig
@@ -39,3 +39,16 @@
 	  Kerberos support should be installed.
 
 	  If unsure, say Y.
+
+config SUNRPC_DEBUG
+	bool "RPC: Enable dprintk debugging"
+	depends on SUNRPC && SYSCTL
+	help
+	  This option enables a sysctl-based debugging interface
+	  that is be used by the 'rpcdebug' utility to turn on or off
+	  logging of different aspects of the kernel RPC activity.
+
+	  Disabling this option will make your kernel slightly smaller,
+	  but makes troubleshooting NFS issues significantly harder.
+
+	  If unsure, say Y.
diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c
index ee77742..d11418f 100644
--- a/net/sunrpc/addr.c
+++ b/net/sunrpc/addr.c
@@ -156,8 +156,9 @@
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
-static int rpc_parse_scope_id(const char *buf, const size_t buflen,
-			      const char *delim, struct sockaddr_in6 *sin6)
+static int rpc_parse_scope_id(struct net *net, const char *buf,
+			      const size_t buflen, const char *delim,
+			      struct sockaddr_in6 *sin6)
 {
 	char *p;
 	size_t len;
@@ -177,7 +178,7 @@
 		unsigned long scope_id = 0;
 		struct net_device *dev;
 
-		dev = dev_get_by_name(&init_net, p);
+		dev = dev_get_by_name(net, p);
 		if (dev != NULL) {
 			scope_id = dev->ifindex;
 			dev_put(dev);
@@ -197,7 +198,7 @@
 	return 0;
 }
 
-static size_t rpc_pton6(const char *buf, const size_t buflen,
+static size_t rpc_pton6(struct net *net, const char *buf, const size_t buflen,
 			struct sockaddr *sap, const size_t salen)
 {
 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
@@ -213,14 +214,14 @@
 	if (in6_pton(buf, buflen, addr, IPV6_SCOPE_DELIMITER, &delim) == 0)
 		return 0;
 
-	if (!rpc_parse_scope_id(buf, buflen, delim, sin6))
+	if (!rpc_parse_scope_id(net, buf, buflen, delim, sin6))
 		return 0;
 
 	sin6->sin6_family = AF_INET6;
 	return sizeof(struct sockaddr_in6);
 }
 #else
-static size_t rpc_pton6(const char *buf, const size_t buflen,
+static size_t rpc_pton6(struct net *net, const char *buf, const size_t buflen,
 			struct sockaddr *sap, const size_t salen)
 {
 	return 0;
@@ -229,6 +230,7 @@
 
 /**
  * rpc_pton - Construct a sockaddr in @sap
+ * @net: applicable network namespace
  * @buf: C string containing presentation format IP address
  * @buflen: length of presentation address in bytes
  * @sap: buffer into which to plant socket address
@@ -241,14 +243,14 @@
  * socket address, if successful.  Returns zero if an error
  * occurred.
  */
-size_t rpc_pton(const char *buf, const size_t buflen,
+size_t rpc_pton(struct net *net, const char *buf, const size_t buflen,
 		struct sockaddr *sap, const size_t salen)
 {
 	unsigned int i;
 
 	for (i = 0; i < buflen; i++)
 		if (buf[i] == ':')
-			return rpc_pton6(buf, buflen, sap, salen);
+			return rpc_pton6(net, buf, buflen, sap, salen);
 	return rpc_pton4(buf, buflen, sap, salen);
 }
 EXPORT_SYMBOL_GPL(rpc_pton);
@@ -295,6 +297,7 @@
 
 /**
  * rpc_uaddr2sockaddr - convert a universal address to a socket address.
+ * @net: applicable network namespace
  * @uaddr: C string containing universal address to convert
  * @uaddr_len: length of universal address string
  * @sap: buffer into which to plant socket address
@@ -306,8 +309,9 @@
  * Returns the size of the socket address if successful; otherwise
  * zero is returned.
  */
-size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len,
-			  struct sockaddr *sap, const size_t salen)
+size_t rpc_uaddr2sockaddr(struct net *net, const char *uaddr,
+			  const size_t uaddr_len, struct sockaddr *sap,
+			  const size_t salen)
 {
 	char *c, buf[RPCBIND_MAXUADDRLEN + sizeof('\0')];
 	unsigned long portlo, porthi;
@@ -339,7 +343,7 @@
 	port = (unsigned short)((porthi << 8) | portlo);
 
 	*c = '\0';
-	if (rpc_pton(buf, strlen(buf), sap, salen) == 0)
+	if (rpc_pton(net, buf, strlen(buf), sap, salen) == 0)
 		return 0;
 
 	switch (sap->sa_family) {
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index affa631..d3ad81f 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -81,7 +81,7 @@
 	 * mechanism (for example, "krb5") and exists for
 	 * backwards-compatibility with older gssd's.
 	 */
-	struct dentry *dentry[2];
+	struct rpc_pipe *pipe[2];
 };
 
 /* pipe_version >= 0 if and only if someone has a pipe open. */
@@ -112,7 +112,7 @@
 /* gss_cred_set_ctx:
  * called by gss_upcall_callback and gss_create_upcall in order
  * to set the gss context. The actual exchange of an old context
- * and a new one is protected by the inode->i_lock.
+ * and a new one is protected by the pipe->lock.
  */
 static void
 gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
@@ -251,7 +251,7 @@
 	struct rpc_pipe_msg msg;
 	struct list_head list;
 	struct gss_auth *auth;
-	struct rpc_inode *inode;
+	struct rpc_pipe *pipe;
 	struct rpc_wait_queue rpc_waitqueue;
 	wait_queue_head_t waitqueue;
 	struct gss_cl_ctx *ctx;
@@ -294,10 +294,10 @@
 }
 
 static struct gss_upcall_msg *
-__gss_find_upcall(struct rpc_inode *rpci, uid_t uid)
+__gss_find_upcall(struct rpc_pipe *pipe, uid_t uid)
 {
 	struct gss_upcall_msg *pos;
-	list_for_each_entry(pos, &rpci->in_downcall, list) {
+	list_for_each_entry(pos, &pipe->in_downcall, list) {
 		if (pos->uid != uid)
 			continue;
 		atomic_inc(&pos->count);
@@ -315,18 +315,17 @@
 static inline struct gss_upcall_msg *
 gss_add_msg(struct gss_upcall_msg *gss_msg)
 {
-	struct rpc_inode *rpci = gss_msg->inode;
-	struct inode *inode = &rpci->vfs_inode;
+	struct rpc_pipe *pipe = gss_msg->pipe;
 	struct gss_upcall_msg *old;
 
-	spin_lock(&inode->i_lock);
-	old = __gss_find_upcall(rpci, gss_msg->uid);
+	spin_lock(&pipe->lock);
+	old = __gss_find_upcall(pipe, gss_msg->uid);
 	if (old == NULL) {
 		atomic_inc(&gss_msg->count);
-		list_add(&gss_msg->list, &rpci->in_downcall);
+		list_add(&gss_msg->list, &pipe->in_downcall);
 	} else
 		gss_msg = old;
-	spin_unlock(&inode->i_lock);
+	spin_unlock(&pipe->lock);
 	return gss_msg;
 }
 
@@ -342,14 +341,14 @@
 static void
 gss_unhash_msg(struct gss_upcall_msg *gss_msg)
 {
-	struct inode *inode = &gss_msg->inode->vfs_inode;
+	struct rpc_pipe *pipe = gss_msg->pipe;
 
 	if (list_empty(&gss_msg->list))
 		return;
-	spin_lock(&inode->i_lock);
+	spin_lock(&pipe->lock);
 	if (!list_empty(&gss_msg->list))
 		__gss_unhash_msg(gss_msg);
-	spin_unlock(&inode->i_lock);
+	spin_unlock(&pipe->lock);
 }
 
 static void
@@ -376,11 +375,11 @@
 	struct gss_cred *gss_cred = container_of(task->tk_rqstp->rq_cred,
 			struct gss_cred, gc_base);
 	struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall;
-	struct inode *inode = &gss_msg->inode->vfs_inode;
+	struct rpc_pipe *pipe = gss_msg->pipe;
 
-	spin_lock(&inode->i_lock);
+	spin_lock(&pipe->lock);
 	gss_handle_downcall_result(gss_cred, gss_msg);
-	spin_unlock(&inode->i_lock);
+	spin_unlock(&pipe->lock);
 	task->tk_status = gss_msg->msg.errno;
 	gss_release_msg(gss_msg);
 }
@@ -450,7 +449,7 @@
 		kfree(gss_msg);
 		return ERR_PTR(vers);
 	}
-	gss_msg->inode = RPC_I(gss_auth->dentry[vers]->d_inode);
+	gss_msg->pipe = gss_auth->pipe[vers];
 	INIT_LIST_HEAD(&gss_msg->list);
 	rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
 	init_waitqueue_head(&gss_msg->waitqueue);
@@ -474,8 +473,7 @@
 		return gss_new;
 	gss_msg = gss_add_msg(gss_new);
 	if (gss_msg == gss_new) {
-		struct inode *inode = &gss_new->inode->vfs_inode;
-		int res = rpc_queue_upcall(inode, &gss_new->msg);
+		int res = rpc_queue_upcall(gss_new->pipe, &gss_new->msg);
 		if (res) {
 			gss_unhash_msg(gss_new);
 			gss_msg = ERR_PTR(res);
@@ -506,7 +504,7 @@
 	struct gss_cred *gss_cred = container_of(cred,
 			struct gss_cred, gc_base);
 	struct gss_upcall_msg *gss_msg;
-	struct inode *inode;
+	struct rpc_pipe *pipe;
 	int err = 0;
 
 	dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid,
@@ -524,8 +522,8 @@
 		err = PTR_ERR(gss_msg);
 		goto out;
 	}
-	inode = &gss_msg->inode->vfs_inode;
-	spin_lock(&inode->i_lock);
+	pipe = gss_msg->pipe;
+	spin_lock(&pipe->lock);
 	if (gss_cred->gc_upcall != NULL)
 		rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL);
 	else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
@@ -538,7 +536,7 @@
 		gss_handle_downcall_result(gss_cred, gss_msg);
 		err = gss_msg->msg.errno;
 	}
-	spin_unlock(&inode->i_lock);
+	spin_unlock(&pipe->lock);
 	gss_release_msg(gss_msg);
 out:
 	dprintk("RPC: %5u gss_refresh_upcall for uid %u result %d\n",
@@ -549,7 +547,7 @@
 static inline int
 gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
 {
-	struct inode *inode;
+	struct rpc_pipe *pipe;
 	struct rpc_cred *cred = &gss_cred->gc_base;
 	struct gss_upcall_msg *gss_msg;
 	DEFINE_WAIT(wait);
@@ -573,14 +571,14 @@
 		err = PTR_ERR(gss_msg);
 		goto out;
 	}
-	inode = &gss_msg->inode->vfs_inode;
+	pipe = gss_msg->pipe;
 	for (;;) {
 		prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_KILLABLE);
-		spin_lock(&inode->i_lock);
+		spin_lock(&pipe->lock);
 		if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) {
 			break;
 		}
-		spin_unlock(&inode->i_lock);
+		spin_unlock(&pipe->lock);
 		if (fatal_signal_pending(current)) {
 			err = -ERESTARTSYS;
 			goto out_intr;
@@ -591,7 +589,7 @@
 		gss_cred_set_ctx(cred, gss_msg->ctx);
 	else
 		err = gss_msg->msg.errno;
-	spin_unlock(&inode->i_lock);
+	spin_unlock(&pipe->lock);
 out_intr:
 	finish_wait(&gss_msg->waitqueue, &wait);
 	gss_release_msg(gss_msg);
@@ -609,7 +607,7 @@
 	const void *p, *end;
 	void *buf;
 	struct gss_upcall_msg *gss_msg;
-	struct inode *inode = filp->f_path.dentry->d_inode;
+	struct rpc_pipe *pipe = RPC_I(filp->f_dentry->d_inode)->pipe;
 	struct gss_cl_ctx *ctx;
 	uid_t uid;
 	ssize_t err = -EFBIG;
@@ -639,14 +637,14 @@
 
 	err = -ENOENT;
 	/* Find a matching upcall */
-	spin_lock(&inode->i_lock);
-	gss_msg = __gss_find_upcall(RPC_I(inode), uid);
+	spin_lock(&pipe->lock);
+	gss_msg = __gss_find_upcall(pipe, uid);
 	if (gss_msg == NULL) {
-		spin_unlock(&inode->i_lock);
+		spin_unlock(&pipe->lock);
 		goto err_put_ctx;
 	}
 	list_del_init(&gss_msg->list);
-	spin_unlock(&inode->i_lock);
+	spin_unlock(&pipe->lock);
 
 	p = gss_fill_context(p, end, ctx, gss_msg->auth->mech);
 	if (IS_ERR(p)) {
@@ -674,9 +672,9 @@
 	err = mlen;
 
 err_release_msg:
-	spin_lock(&inode->i_lock);
+	spin_lock(&pipe->lock);
 	__gss_unhash_msg(gss_msg);
-	spin_unlock(&inode->i_lock);
+	spin_unlock(&pipe->lock);
 	gss_release_msg(gss_msg);
 err_put_ctx:
 	gss_put_ctx(ctx);
@@ -722,23 +720,23 @@
 static void
 gss_pipe_release(struct inode *inode)
 {
-	struct rpc_inode *rpci = RPC_I(inode);
+	struct rpc_pipe *pipe = RPC_I(inode)->pipe;
 	struct gss_upcall_msg *gss_msg;
 
 restart:
-	spin_lock(&inode->i_lock);
-	list_for_each_entry(gss_msg, &rpci->in_downcall, list) {
+	spin_lock(&pipe->lock);
+	list_for_each_entry(gss_msg, &pipe->in_downcall, list) {
 
 		if (!list_empty(&gss_msg->msg.list))
 			continue;
 		gss_msg->msg.errno = -EPIPE;
 		atomic_inc(&gss_msg->count);
 		__gss_unhash_msg(gss_msg);
-		spin_unlock(&inode->i_lock);
+		spin_unlock(&pipe->lock);
 		gss_release_msg(gss_msg);
 		goto restart;
 	}
-	spin_unlock(&inode->i_lock);
+	spin_unlock(&pipe->lock);
 
 	put_pipe_version();
 }
@@ -759,6 +757,75 @@
 	}
 }
 
+static void gss_pipes_dentries_destroy(struct rpc_auth *auth)
+{
+	struct gss_auth *gss_auth;
+
+	gss_auth = container_of(auth, struct gss_auth, rpc_auth);
+	if (gss_auth->pipe[0]->dentry)
+		rpc_unlink(gss_auth->pipe[0]->dentry);
+	if (gss_auth->pipe[1]->dentry)
+		rpc_unlink(gss_auth->pipe[1]->dentry);
+}
+
+static int gss_pipes_dentries_create(struct rpc_auth *auth)
+{
+	int err;
+	struct gss_auth *gss_auth;
+	struct rpc_clnt *clnt;
+
+	gss_auth = container_of(auth, struct gss_auth, rpc_auth);
+	clnt = gss_auth->client;
+
+	gss_auth->pipe[1]->dentry = rpc_mkpipe_dentry(clnt->cl_dentry,
+						      "gssd",
+						      clnt, gss_auth->pipe[1]);
+	if (IS_ERR(gss_auth->pipe[1]->dentry))
+		return PTR_ERR(gss_auth->pipe[1]->dentry);
+	gss_auth->pipe[0]->dentry = rpc_mkpipe_dentry(clnt->cl_dentry,
+						      gss_auth->mech->gm_name,
+						      clnt, gss_auth->pipe[0]);
+	if (IS_ERR(gss_auth->pipe[0]->dentry)) {
+		err = PTR_ERR(gss_auth->pipe[0]->dentry);
+		goto err_unlink_pipe_1;
+	}
+	return 0;
+
+err_unlink_pipe_1:
+	rpc_unlink(gss_auth->pipe[1]->dentry);
+	return err;
+}
+
+static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt,
+					   struct rpc_auth *auth)
+{
+	struct net *net = rpc_net_ns(clnt);
+	struct super_block *sb;
+
+	sb = rpc_get_sb_net(net);
+	if (sb) {
+		if (clnt->cl_dentry)
+			gss_pipes_dentries_destroy(auth);
+		rpc_put_sb_net(net);
+	}
+}
+
+static int gss_pipes_dentries_create_net(struct rpc_clnt *clnt,
+					 struct rpc_auth *auth)
+{
+	struct net *net = rpc_net_ns(clnt);
+	struct super_block *sb;
+	int err = 0;
+
+	sb = rpc_get_sb_net(net);
+	if (sb) {
+		if (clnt->cl_dentry)
+			err = gss_pipes_dentries_create(auth);
+		rpc_put_sb_net(net);
+	}
+	return err;
+}
+
 /*
  * NOTE: we have the opportunity to use different
  * parameters based on the input flavor (which must be a pseudoflavor)
@@ -801,32 +868,33 @@
 	 * that we supported only the old pipe.  So we instead create
 	 * the new pipe first.
 	 */
-	gss_auth->dentry[1] = rpc_mkpipe(clnt->cl_path.dentry,
-					 "gssd",
-					 clnt, &gss_upcall_ops_v1,
-					 RPC_PIPE_WAIT_FOR_OPEN);
-	if (IS_ERR(gss_auth->dentry[1])) {
-		err = PTR_ERR(gss_auth->dentry[1]);
+	gss_auth->pipe[1] = rpc_mkpipe_data(&gss_upcall_ops_v1,
+					    RPC_PIPE_WAIT_FOR_OPEN);
+	if (IS_ERR(gss_auth->pipe[1])) {
+		err = PTR_ERR(gss_auth->pipe[1]);
 		goto err_put_mech;
 	}
 
-	gss_auth->dentry[0] = rpc_mkpipe(clnt->cl_path.dentry,
-					 gss_auth->mech->gm_name,
-					 clnt, &gss_upcall_ops_v0,
-					 RPC_PIPE_WAIT_FOR_OPEN);
-	if (IS_ERR(gss_auth->dentry[0])) {
-		err = PTR_ERR(gss_auth->dentry[0]);
-		goto err_unlink_pipe_1;
+	gss_auth->pipe[0] = rpc_mkpipe_data(&gss_upcall_ops_v0,
+					    RPC_PIPE_WAIT_FOR_OPEN);
+	if (IS_ERR(gss_auth->pipe[0])) {
+		err = PTR_ERR(gss_auth->pipe[0]);
+		goto err_destroy_pipe_1;
 	}
+	err = gss_pipes_dentries_create_net(clnt, auth);
+	if (err)
+		goto err_destroy_pipe_0;
 	err = rpcauth_init_credcache(auth);
 	if (err)
-		goto err_unlink_pipe_0;
+		goto err_unlink_pipes;
 
 	return auth;
-err_unlink_pipe_0:
-	rpc_unlink(gss_auth->dentry[0]);
-err_unlink_pipe_1:
-	rpc_unlink(gss_auth->dentry[1]);
+err_unlink_pipes:
+	gss_pipes_dentries_destroy_net(clnt, auth);
+err_destroy_pipe_0:
+	rpc_destroy_pipe_data(gss_auth->pipe[0]);
+err_destroy_pipe_1:
+	rpc_destroy_pipe_data(gss_auth->pipe[1]);
 err_put_mech:
 	gss_mech_put(gss_auth->mech);
 err_free:
@@ -839,8 +907,9 @@
 static void
 gss_free(struct gss_auth *gss_auth)
 {
-	rpc_unlink(gss_auth->dentry[1]);
-	rpc_unlink(gss_auth->dentry[0]);
+	gss_pipes_dentries_destroy_net(gss_auth->client, &gss_auth->rpc_auth);
+	rpc_destroy_pipe_data(gss_auth->pipe[0]);
+	rpc_destroy_pipe_data(gss_auth->pipe[1]);
 	gss_mech_put(gss_auth->mech);
 
 	kfree(gss_auth);
@@ -1547,7 +1616,9 @@
 	.create		= gss_create,
 	.destroy	= gss_destroy,
 	.lookup_cred	= gss_lookup_cred,
-	.crcreate	= gss_create_cred
+	.crcreate	= gss_create_cred,
+	.pipes_create	= gss_pipes_dentries_create,
+	.pipes_destroy	= gss_pipes_dentries_destroy,
 };
 
 static const struct rpc_credops gss_credops = {
@@ -1591,6 +1662,21 @@
 	.release_pipe	= gss_pipe_release,
 };
 
+static __net_init int rpcsec_gss_init_net(struct net *net)
+{
+	return gss_svc_init_net(net);
+}
+
+static __net_exit void rpcsec_gss_exit_net(struct net *net)
+{
+	gss_svc_shutdown_net(net);
+}
+
+static struct pernet_operations rpcsec_gss_net_ops = {
+	.init = rpcsec_gss_init_net,
+	.exit = rpcsec_gss_exit_net,
+};
+
 /*
  * Initialize RPCSEC_GSS module
  */
@@ -1604,8 +1690,13 @@
 	err = gss_svc_init();
 	if (err)
 		goto out_unregister;
+	err = register_pernet_subsys(&rpcsec_gss_net_ops);
+	if (err)
+		goto out_svc_exit;
 	rpc_init_wait_queue(&pipe_version_rpc_waitqueue, "gss pipe version");
 	return 0;
+out_svc_exit:
+	gss_svc_shutdown();
 out_unregister:
 	rpcauth_unregister(&authgss_ops);
 out:
@@ -1614,6 +1705,7 @@
 
 static void __exit exit_rpcsec_gss(void)
 {
+	unregister_pernet_subsys(&rpcsec_gss_net_ops);
 	gss_svc_shutdown();
 	rpcauth_unregister(&authgss_ops);
 	rcu_barrier(); /* Wait for completion of call_rcu()'s */
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 9576f35..0f43e89 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -600,11 +600,14 @@
 	u32 ret;
 	struct scatterlist sg[1];
 	struct blkcipher_desc desc = { .tfm = cipher, .info = iv };
-	u8 data[crypto_blkcipher_blocksize(cipher) * 2];
+	u8 data[GSS_KRB5_MAX_BLOCKSIZE * 2];
 	struct page **save_pages;
 	u32 len = buf->len - offset;
 
-	BUG_ON(len > crypto_blkcipher_blocksize(cipher) * 2);
+	if (len > ARRAY_SIZE(data)) {
+		WARN_ON(0);
+		return -ENOMEM;
+	}
 
 	/*
 	 * For encryption, we want to read from the cleartext
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 8c67890..8eff8c3 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -344,7 +344,7 @@
 	return PTR_ERR(p);
 }
 
-struct crypto_blkcipher *
+static struct crypto_blkcipher *
 context_v2_alloc_cipher(struct krb5_ctx *ctx, const char *cname, u8 *key)
 {
 	struct crypto_blkcipher *cp;
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index d7941ea..62ae327 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -159,7 +159,7 @@
 	return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
 }
 
-u32
+static u32
 gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
 		struct xdr_netobj *token)
 {
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 8d0f7d3..1600cfb 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -48,6 +48,8 @@
 #include <linux/sunrpc/svcauth_gss.h>
 #include <linux/sunrpc/cache.h>
 
+#include "../netns.h"
+
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY	RPCDBG_AUTH
 #endif
@@ -75,10 +77,8 @@
 	int			major_status, minor_status;
 };
 
-static struct cache_head *rsi_table[RSI_HASHMAX];
-static struct cache_detail rsi_cache;
-static struct rsi *rsi_update(struct rsi *new, struct rsi *old);
-static struct rsi *rsi_lookup(struct rsi *item);
+static struct rsi *rsi_update(struct cache_detail *cd, struct rsi *new, struct rsi *old);
+static struct rsi *rsi_lookup(struct cache_detail *cd, struct rsi *item);
 
 static void rsi_free(struct rsi *rsii)
 {
@@ -216,7 +216,7 @@
 	if (dup_to_netobj(&rsii.in_token, buf, len))
 		goto out;
 
-	rsip = rsi_lookup(&rsii);
+	rsip = rsi_lookup(cd, &rsii);
 	if (!rsip)
 		goto out;
 
@@ -258,21 +258,20 @@
 	if (dup_to_netobj(&rsii.out_token, buf, len))
 		goto out;
 	rsii.h.expiry_time = expiry;
-	rsip = rsi_update(&rsii, rsip);
+	rsip = rsi_update(cd, &rsii, rsip);
 	status = 0;
 out:
 	rsi_free(&rsii);
 	if (rsip)
-		cache_put(&rsip->h, &rsi_cache);
+		cache_put(&rsip->h, cd);
 	else
 		status = -ENOMEM;
 	return status;
 }
 
-static struct cache_detail rsi_cache = {
+static struct cache_detail rsi_cache_template = {
 	.owner		= THIS_MODULE,
 	.hash_size	= RSI_HASHMAX,
-	.hash_table     = rsi_table,
 	.name           = "auth.rpcsec.init",
 	.cache_put      = rsi_put,
 	.cache_upcall   = rsi_upcall,
@@ -283,24 +282,24 @@
 	.alloc		= rsi_alloc,
 };
 
-static struct rsi *rsi_lookup(struct rsi *item)
+static struct rsi *rsi_lookup(struct cache_detail *cd, struct rsi *item)
 {
 	struct cache_head *ch;
 	int hash = rsi_hash(item);
 
-	ch = sunrpc_cache_lookup(&rsi_cache, &item->h, hash);
+	ch = sunrpc_cache_lookup(cd, &item->h, hash);
 	if (ch)
 		return container_of(ch, struct rsi, h);
 	else
 		return NULL;
 }
 
-static struct rsi *rsi_update(struct rsi *new, struct rsi *old)
+static struct rsi *rsi_update(struct cache_detail *cd, struct rsi *new, struct rsi *old)
 {
 	struct cache_head *ch;
 	int hash = rsi_hash(new);
 
-	ch = sunrpc_cache_update(&rsi_cache, &new->h,
+	ch = sunrpc_cache_update(cd, &new->h,
 				 &old->h, hash);
 	if (ch)
 		return container_of(ch, struct rsi, h);
@@ -339,10 +338,8 @@
 	char			*client_name;
 };
 
-static struct cache_head *rsc_table[RSC_HASHMAX];
-static struct cache_detail rsc_cache;
-static struct rsc *rsc_update(struct rsc *new, struct rsc *old);
-static struct rsc *rsc_lookup(struct rsc *item);
+static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old);
+static struct rsc *rsc_lookup(struct cache_detail *cd, struct rsc *item);
 
 static void rsc_free(struct rsc *rsci)
 {
@@ -444,7 +441,7 @@
 	if (expiry == 0)
 		goto out;
 
-	rscp = rsc_lookup(&rsci);
+	rscp = rsc_lookup(cd, &rsci);
 	if (!rscp)
 		goto out;
 
@@ -506,22 +503,21 @@
 
 	}
 	rsci.h.expiry_time = expiry;
-	rscp = rsc_update(&rsci, rscp);
+	rscp = rsc_update(cd, &rsci, rscp);
 	status = 0;
 out:
 	gss_mech_put(gm);
 	rsc_free(&rsci);
 	if (rscp)
-		cache_put(&rscp->h, &rsc_cache);
+		cache_put(&rscp->h, cd);
 	else
 		status = -ENOMEM;
 	return status;
 }
 
-static struct cache_detail rsc_cache = {
+static struct cache_detail rsc_cache_template = {
 	.owner		= THIS_MODULE,
 	.hash_size	= RSC_HASHMAX,
-	.hash_table	= rsc_table,
 	.name		= "auth.rpcsec.context",
 	.cache_put	= rsc_put,
 	.cache_parse	= rsc_parse,
@@ -531,24 +527,24 @@
 	.alloc		= rsc_alloc,
 };
 
-static struct rsc *rsc_lookup(struct rsc *item)
+static struct rsc *rsc_lookup(struct cache_detail *cd, struct rsc *item)
 {
 	struct cache_head *ch;
 	int hash = rsc_hash(item);
 
-	ch = sunrpc_cache_lookup(&rsc_cache, &item->h, hash);
+	ch = sunrpc_cache_lookup(cd, &item->h, hash);
 	if (ch)
 		return container_of(ch, struct rsc, h);
 	else
 		return NULL;
 }
 
-static struct rsc *rsc_update(struct rsc *new, struct rsc *old)
+static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old)
 {
 	struct cache_head *ch;
 	int hash = rsc_hash(new);
 
-	ch = sunrpc_cache_update(&rsc_cache, &new->h,
+	ch = sunrpc_cache_update(cd, &new->h,
 				 &old->h, hash);
 	if (ch)
 		return container_of(ch, struct rsc, h);
@@ -558,7 +554,7 @@
 
 
 static struct rsc *
-gss_svc_searchbyctx(struct xdr_netobj *handle)
+gss_svc_searchbyctx(struct cache_detail *cd, struct xdr_netobj *handle)
 {
 	struct rsc rsci;
 	struct rsc *found;
@@ -566,11 +562,11 @@
 	memset(&rsci, 0, sizeof(rsci));
 	if (dup_to_netobj(&rsci.handle, handle->data, handle->len))
 		return NULL;
-	found = rsc_lookup(&rsci);
+	found = rsc_lookup(cd, &rsci);
 	rsc_free(&rsci);
 	if (!found)
 		return NULL;
-	if (cache_check(&rsc_cache, &found->h, NULL))
+	if (cache_check(cd, &found->h, NULL))
 		return NULL;
 	return found;
 }
@@ -968,20 +964,20 @@
 }
 
 static inline int
-gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip)
+gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp, struct rsi *rsip)
 {
 	struct rsc *rsci;
 	int        rc;
 
 	if (rsip->major_status != GSS_S_COMPLETE)
 		return gss_write_null_verf(rqstp);
-	rsci = gss_svc_searchbyctx(&rsip->out_handle);
+	rsci = gss_svc_searchbyctx(cd, &rsip->out_handle);
 	if (rsci == NULL) {
 		rsip->major_status = GSS_S_NO_CONTEXT;
 		return gss_write_null_verf(rqstp);
 	}
 	rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);
-	cache_put(&rsci->h, &rsc_cache);
+	cache_put(&rsci->h, cd);
 	return rc;
 }
 
@@ -1000,6 +996,7 @@
 	struct xdr_netobj tmpobj;
 	struct rsi *rsip, rsikey;
 	int ret;
+	struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id);
 
 	/* Read the verifier; should be NULL: */
 	*authp = rpc_autherr_badverf;
@@ -1028,17 +1025,17 @@
 	}
 
 	/* Perform upcall, or find upcall result: */
-	rsip = rsi_lookup(&rsikey);
+	rsip = rsi_lookup(sn->rsi_cache, &rsikey);
 	rsi_free(&rsikey);
 	if (!rsip)
 		return SVC_CLOSE;
-	if (cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle) < 0)
+	if (cache_check(sn->rsi_cache, &rsip->h, &rqstp->rq_chandle) < 0)
 		/* No upcall result: */
 		return SVC_CLOSE;
 
 	ret = SVC_CLOSE;
 	/* Got an answer to the upcall; use it: */
-	if (gss_write_init_verf(rqstp, rsip))
+	if (gss_write_init_verf(sn->rsc_cache, rqstp, rsip))
 		goto out;
 	if (resv->iov_len + 4 > PAGE_SIZE)
 		goto out;
@@ -1055,7 +1052,7 @@
 
 	ret = SVC_COMPLETE;
 out:
-	cache_put(&rsip->h, &rsi_cache);
+	cache_put(&rsip->h, sn->rsi_cache);
 	return ret;
 }
 
@@ -1079,6 +1076,7 @@
 	__be32		*rpcstart;
 	__be32		*reject_stat = resv->iov_base + resv->iov_len;
 	int		ret;
+	struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id);
 
 	dprintk("RPC:       svcauth_gss: argv->iov_len = %zd\n",
 			argv->iov_len);
@@ -1129,7 +1127,7 @@
 	case RPC_GSS_PROC_DESTROY:
 		/* Look up the context, and check the verifier: */
 		*authp = rpcsec_gsserr_credproblem;
-		rsci = gss_svc_searchbyctx(&gc->gc_ctx);
+		rsci = gss_svc_searchbyctx(sn->rsc_cache, &gc->gc_ctx);
 		if (!rsci)
 			goto auth_err;
 		switch (gss_verify_header(rqstp, rsci, rpcstart, gc, authp)) {
@@ -1209,7 +1207,7 @@
 	ret = SVC_DROP;
 out:
 	if (rsci)
-		cache_put(&rsci->h, &rsc_cache);
+		cache_put(&rsci->h, sn->rsc_cache);
 	return ret;
 }
 
@@ -1362,6 +1360,7 @@
 	struct rpc_gss_wire_cred *gc = &gsd->clcred;
 	struct xdr_buf *resbuf = &rqstp->rq_res;
 	int stat = -EINVAL;
+	struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id);
 
 	if (gc->gc_proc != RPC_GSS_PROC_DATA)
 		goto out;
@@ -1404,7 +1403,7 @@
 		put_group_info(rqstp->rq_cred.cr_group_info);
 	rqstp->rq_cred.cr_group_info = NULL;
 	if (gsd->rsci)
-		cache_put(&gsd->rsci->h, &rsc_cache);
+		cache_put(&gsd->rsci->h, sn->rsc_cache);
 	gsd->rsci = NULL;
 
 	return stat;
@@ -1429,30 +1428,96 @@
 	.set_client	= svcauth_gss_set_client,
 };
 
+static int rsi_cache_create_net(struct net *net)
+{
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+	struct cache_detail *cd;
+	int err;
+
+	cd = cache_create_net(&rsi_cache_template, net);
+	if (IS_ERR(cd))
+		return PTR_ERR(cd);
+	err = cache_register_net(cd, net);
+	if (err) {
+		cache_destroy_net(cd, net);
+		return err;
+	}
+	sn->rsi_cache = cd;
+	return 0;
+}
+
+static void rsi_cache_destroy_net(struct net *net)
+{
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+	struct cache_detail *cd = sn->rsi_cache;
+
+	sn->rsi_cache = NULL;
+	cache_purge(cd);
+	cache_unregister_net(cd, net);
+	cache_destroy_net(cd, net);
+}
+
+static int rsc_cache_create_net(struct net *net)
+{
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+	struct cache_detail *cd;
+	int err;
+
+	cd = cache_create_net(&rsc_cache_template, net);
+	if (IS_ERR(cd))
+		return PTR_ERR(cd);
+	err = cache_register_net(cd, net);
+	if (err) {
+		cache_destroy_net(cd, net);
+		return err;
+	}
+	sn->rsc_cache = cd;
+	return 0;
+}
+
+static void rsc_cache_destroy_net(struct net *net)
+{
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+	struct cache_detail *cd = sn->rsc_cache;
+
+	sn->rsc_cache = NULL;
+	cache_purge(cd);
+	cache_unregister_net(cd, net);
+	cache_destroy_net(cd, net);
+}
+
+int
+gss_svc_init_net(struct net *net)
+{
+	int rv;
+
+	rv = rsc_cache_create_net(net);
+	if (rv)
+		return rv;
+	rv = rsi_cache_create_net(net);
+	if (rv)
+		goto out1;
+	return 0;
+out1:
+	rsc_cache_destroy_net(net);
+	return rv;
+}
+
+void
+gss_svc_shutdown_net(struct net *net)
+{
+	rsi_cache_destroy_net(net);
+	rsc_cache_destroy_net(net);
+}
+
 int
 gss_svc_init(void)
 {
-	int rv = svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss);
-	if (rv)
-		return rv;
-	rv = cache_register(&rsc_cache);
-	if (rv)
-		goto out1;
-	rv = cache_register(&rsi_cache);
-	if (rv)
-		goto out2;
-	return 0;
-out2:
-	cache_unregister(&rsc_cache);
-out1:
-	svc_auth_unregister(RPC_AUTH_GSS);
-	return rv;
+	return svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss);
 }
 
 void
 gss_svc_shutdown(void)
 {
-	cache_unregister(&rsc_cache);
-	cache_unregister(&rsi_cache);
 	svc_auth_unregister(RPC_AUTH_GSS);
 }
diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c
index 3ad435a..31def68 100644
--- a/net/sunrpc/backchannel_rqst.c
+++ b/net/sunrpc/backchannel_rqst.c
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/sunrpc/xprt.h>
 #include <linux/export.h>
+#include <linux/sunrpc/bc_xprt.h>
 
 #ifdef RPC_DEBUG
 #define RPCDBG_FACILITY	RPCDBG_TRANS
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 465df9a..de0b0f3 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -344,7 +344,7 @@
 static void do_cache_clean(struct work_struct *work);
 static struct delayed_work cache_cleaner;
 
-static void sunrpc_init_cache_detail(struct cache_detail *cd)
+void sunrpc_init_cache_detail(struct cache_detail *cd)
 {
 	rwlock_init(&cd->hash_lock);
 	INIT_LIST_HEAD(&cd->queue);
@@ -360,8 +360,9 @@
 	/* start the cleaning process */
 	schedule_delayed_work(&cache_cleaner, 0);
 }
+EXPORT_SYMBOL_GPL(sunrpc_init_cache_detail);
 
-static void sunrpc_destroy_cache_detail(struct cache_detail *cd)
+void sunrpc_destroy_cache_detail(struct cache_detail *cd)
 {
 	cache_purge(cd);
 	spin_lock(&cache_list_lock);
@@ -384,6 +385,7 @@
 out:
 	printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name);
 }
+EXPORT_SYMBOL_GPL(sunrpc_destroy_cache_detail);
 
 /* clean cache tries to find something to clean
  * and cleans it.
@@ -828,6 +830,8 @@
 {
 	ssize_t ret;
 
+	if (count == 0)
+		return -EINVAL;
 	if (copy_from_user(kaddr, buf, count))
 		return -EFAULT;
 	kaddr[count] = '\0';
@@ -1643,12 +1647,6 @@
 }
 EXPORT_SYMBOL_GPL(cache_register_net);
 
-int cache_register(struct cache_detail *cd)
-{
-	return cache_register_net(cd, &init_net);
-}
-EXPORT_SYMBOL_GPL(cache_register);
-
 void cache_unregister_net(struct cache_detail *cd, struct net *net)
 {
 	remove_cache_proc_entries(cd, net);
@@ -1656,11 +1654,31 @@
 }
 EXPORT_SYMBOL_GPL(cache_unregister_net);
 
-void cache_unregister(struct cache_detail *cd)
+struct cache_detail *cache_create_net(struct cache_detail *tmpl, struct net *net)
 {
-	cache_unregister_net(cd, &init_net);
+	struct cache_detail *cd;
+
+	cd = kmemdup(tmpl, sizeof(struct cache_detail), GFP_KERNEL);
+	if (cd == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	cd->hash_table = kzalloc(cd->hash_size * sizeof(struct cache_head *),
+				 GFP_KERNEL);
+	if (cd->hash_table == NULL) {
+		kfree(cd);
+		return ERR_PTR(-ENOMEM);
+	}
+	cd->net = net;
+	return cd;
 }
-EXPORT_SYMBOL_GPL(cache_unregister);
+EXPORT_SYMBOL_GPL(cache_create_net);
+
+void cache_destroy_net(struct cache_detail *cd, struct net *net)
+{
+	kfree(cd->hash_table);
+	kfree(cd);
+}
+EXPORT_SYMBOL_GPL(cache_destroy_net);
 
 static ssize_t cache_read_pipefs(struct file *filp, char __user *buf,
 				 size_t count, loff_t *ppos)
@@ -1787,17 +1805,14 @@
 	struct dentry *dir;
 	int ret = 0;
 
-	sunrpc_init_cache_detail(cd);
 	q.name = name;
 	q.len = strlen(name);
 	q.hash = full_name_hash(q.name, q.len);
 	dir = rpc_create_cache_dir(parent, &q, umode, cd);
 	if (!IS_ERR(dir))
 		cd->u.pipefs.dir = dir;
-	else {
-		sunrpc_destroy_cache_detail(cd);
+	else
 		ret = PTR_ERR(dir);
-	}
 	return ret;
 }
 EXPORT_SYMBOL_GPL(sunrpc_cache_register_pipefs);
@@ -1806,7 +1821,6 @@
 {
 	rpc_remove_cache_dir(cd->u.pipefs.dir);
 	cd->u.pipefs.dir = NULL;
-	sunrpc_destroy_cache_detail(cd);
 }
 EXPORT_SYMBOL_GPL(sunrpc_cache_unregister_pipefs);
 
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index f0268ea..6797246 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -17,7 +17,6 @@
  *  Copyright (C) 1995,1996 Olaf Kirch <okir@monad.swb.de>
  */
 
-#include <asm/system.h>
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -31,13 +30,16 @@
 #include <linux/in.h>
 #include <linux/in6.h>
 #include <linux/un.h>
+#include <linux/rcupdate.h>
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/sunrpc/metrics.h>
 #include <linux/sunrpc/bc_xprt.h>
+#include <trace/events/sunrpc.h>
 
 #include "sunrpc.h"
+#include "netns.h"
 
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY	RPCDBG_CALL
@@ -50,8 +52,6 @@
 /*
  * All RPC clients are linked into this list
  */
-static LIST_HEAD(all_clients);
-static DEFINE_SPINLOCK(rpc_client_lock);
 
 static DECLARE_WAIT_QUEUE_HEAD(destroy_wait);
 
@@ -81,82 +81,191 @@
 
 static void rpc_register_client(struct rpc_clnt *clnt)
 {
-	spin_lock(&rpc_client_lock);
-	list_add(&clnt->cl_clients, &all_clients);
-	spin_unlock(&rpc_client_lock);
+	struct net *net = rpc_net_ns(clnt);
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+	spin_lock(&sn->rpc_client_lock);
+	list_add(&clnt->cl_clients, &sn->all_clients);
+	spin_unlock(&sn->rpc_client_lock);
 }
 
 static void rpc_unregister_client(struct rpc_clnt *clnt)
 {
-	spin_lock(&rpc_client_lock);
+	struct net *net = rpc_net_ns(clnt);
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+	spin_lock(&sn->rpc_client_lock);
 	list_del(&clnt->cl_clients);
-	spin_unlock(&rpc_client_lock);
+	spin_unlock(&sn->rpc_client_lock);
 }
 
-static int
-rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
+static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
+{
+	if (clnt->cl_dentry) {
+		if (clnt->cl_auth && clnt->cl_auth->au_ops->pipes_destroy)
+			clnt->cl_auth->au_ops->pipes_destroy(clnt->cl_auth);
+		rpc_remove_client_dir(clnt->cl_dentry);
+	}
+	clnt->cl_dentry = NULL;
+}
+
+static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
+{
+	struct net *net = rpc_net_ns(clnt);
+	struct super_block *pipefs_sb;
+
+	pipefs_sb = rpc_get_sb_net(net);
+	if (pipefs_sb) {
+		__rpc_clnt_remove_pipedir(clnt);
+		rpc_put_sb_net(net);
+	}
+}
+
+static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
+				    struct rpc_clnt *clnt,
+				    const char *dir_name)
 {
 	static uint32_t clntid;
-	struct path path, dir;
 	char name[15];
 	struct qstr q = {
 		.name = name,
 	};
+	struct dentry *dir, *dentry;
 	int error;
 
-	clnt->cl_path.mnt = ERR_PTR(-ENOENT);
-	clnt->cl_path.dentry = ERR_PTR(-ENOENT);
-	if (dir_name == NULL)
-		return 0;
-
-	path.mnt = rpc_get_mount();
-	if (IS_ERR(path.mnt))
-		return PTR_ERR(path.mnt);
-	error = vfs_path_lookup(path.mnt->mnt_root, path.mnt, dir_name, 0, &dir);
-	if (error)
-		goto err;
-
+	dir = rpc_d_lookup_sb(sb, dir_name);
+	if (dir == NULL)
+		return dir;
 	for (;;) {
 		q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++);
 		name[sizeof(name) - 1] = '\0';
 		q.hash = full_name_hash(q.name, q.len);
-		path.dentry = rpc_create_client_dir(dir.dentry, &q, clnt);
-		if (!IS_ERR(path.dentry))
+		dentry = rpc_create_client_dir(dir, &q, clnt);
+		if (!IS_ERR(dentry))
 			break;
-		error = PTR_ERR(path.dentry);
+		error = PTR_ERR(dentry);
 		if (error != -EEXIST) {
 			printk(KERN_INFO "RPC: Couldn't create pipefs entry"
 					" %s/%s, error %d\n",
 					dir_name, name, error);
-			goto err_path_put;
+			break;
 		}
 	}
-	path_put(&dir);
-	clnt->cl_path = path;
+	dput(dir);
+	return dentry;
+}
+
+static int
+rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name)
+{
+	struct net *net = rpc_net_ns(clnt);
+	struct super_block *pipefs_sb;
+	struct dentry *dentry;
+
+	clnt->cl_dentry = NULL;
+	if (dir_name == NULL)
+		return 0;
+	pipefs_sb = rpc_get_sb_net(net);
+	if (!pipefs_sb)
+		return 0;
+	dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name);
+	rpc_put_sb_net(net);
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
+	clnt->cl_dentry = dentry;
 	return 0;
-err_path_put:
-	path_put(&dir);
-err:
-	rpc_put_mount();
+}
+
+static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event,
+				struct super_block *sb)
+{
+	struct dentry *dentry;
+	int err = 0;
+
+	switch (event) {
+	case RPC_PIPEFS_MOUNT:
+		if (clnt->cl_program->pipe_dir_name == NULL)
+			break;
+		dentry = rpc_setup_pipedir_sb(sb, clnt,
+					      clnt->cl_program->pipe_dir_name);
+		BUG_ON(dentry == NULL);
+		if (IS_ERR(dentry))
+			return PTR_ERR(dentry);
+		clnt->cl_dentry = dentry;
+		if (clnt->cl_auth->au_ops->pipes_create) {
+			err = clnt->cl_auth->au_ops->pipes_create(clnt->cl_auth);
+			if (err)
+				__rpc_clnt_remove_pipedir(clnt);
+		}
+		break;
+	case RPC_PIPEFS_UMOUNT:
+		__rpc_clnt_remove_pipedir(clnt);
+		break;
+	default:
+		printk(KERN_ERR "%s: unknown event: %ld\n", __func__, event);
+		return -ENOTSUPP;
+	}
+	return err;
+}
+
+static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event)
+{
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+	struct rpc_clnt *clnt;
+
+	spin_lock(&sn->rpc_client_lock);
+	list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
+		if (((event == RPC_PIPEFS_MOUNT) && clnt->cl_dentry) ||
+		    ((event == RPC_PIPEFS_UMOUNT) && !clnt->cl_dentry))
+			continue;
+		atomic_inc(&clnt->cl_count);
+		spin_unlock(&sn->rpc_client_lock);
+		return clnt;
+	}
+	spin_unlock(&sn->rpc_client_lock);
+	return NULL;
+}
+
+static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
+			    void *ptr)
+{
+	struct super_block *sb = ptr;
+	struct rpc_clnt *clnt;
+	int error = 0;
+
+	while ((clnt = rpc_get_client_for_event(sb->s_fs_info, event))) {
+		error = __rpc_pipefs_event(clnt, event, sb);
+		rpc_release_client(clnt);
+		if (error)
+			break;
+	}
 	return error;
 }
 
+static struct notifier_block rpc_clients_block = {
+	.notifier_call	= rpc_pipefs_event,
+	.priority	= SUNRPC_PIPEFS_RPC_PRIO,
+};
+
+int rpc_clients_notifier_register(void)
+{
+	return rpc_pipefs_notifier_register(&rpc_clients_block);
+}
+
+void rpc_clients_notifier_unregister(void)
+{
+	return rpc_pipefs_notifier_unregister(&rpc_clients_block);
+}
+
 static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt)
 {
-	struct rpc_program	*program = args->program;
-	struct rpc_version	*version;
+	const struct rpc_program *program = args->program;
+	const struct rpc_version *version;
 	struct rpc_clnt		*clnt = NULL;
 	struct rpc_auth		*auth;
 	int err;
-	size_t len;
 
 	/* sanity check the name before trying to print it */
-	err = -EINVAL;
-	len = strlen(args->servername);
-	if (len > RPC_MAXNETNAMELEN)
-		goto out_no_rpciod;
-	len++;
-
 	dprintk("RPC:       creating %s client for %s (xprt %p)\n",
 			program->name, args->servername, xprt);
 
@@ -179,17 +288,7 @@
 		goto out_err;
 	clnt->cl_parent = clnt;
 
-	clnt->cl_server = clnt->cl_inline_name;
-	if (len > sizeof(clnt->cl_inline_name)) {
-		char *buf = kmalloc(len, GFP_KERNEL);
-		if (buf != NULL)
-			clnt->cl_server = buf;
-		else
-			len = sizeof(clnt->cl_inline_name);
-	}
-	strlcpy(clnt->cl_server, args->servername, len);
-
-	clnt->cl_xprt     = xprt;
+	rcu_assign_pointer(clnt->cl_xprt, xprt);
 	clnt->cl_procinfo = version->procs;
 	clnt->cl_maxproc  = version->nrprocs;
 	clnt->cl_protname = program->name;
@@ -204,7 +303,7 @@
 	INIT_LIST_HEAD(&clnt->cl_tasks);
 	spin_lock_init(&clnt->cl_lock);
 
-	if (!xprt_bound(clnt->cl_xprt))
+	if (!xprt_bound(xprt))
 		clnt->cl_autobind = 1;
 
 	clnt->cl_timeout = xprt->timeout;
@@ -246,17 +345,12 @@
 	return clnt;
 
 out_no_auth:
-	if (!IS_ERR(clnt->cl_path.dentry)) {
-		rpc_remove_client_dir(clnt->cl_path.dentry);
-		rpc_put_mount();
-	}
+	rpc_clnt_remove_pipedir(clnt);
 out_no_path:
 	kfree(clnt->cl_principal);
 out_no_principal:
 	rpc_free_iostats(clnt->cl_metrics);
 out_no_stats:
-	if (clnt->cl_server != clnt->cl_inline_name)
-		kfree(clnt->cl_server);
 	kfree(clnt);
 out_err:
 	xprt_put(xprt);
@@ -286,6 +380,7 @@
 		.srcaddr = args->saddress,
 		.dstaddr = args->address,
 		.addrlen = args->addrsize,
+		.servername = args->servername,
 		.bc_xprt = args->bc_xprt,
 	};
 	char servername[48];
@@ -294,7 +389,7 @@
 	 * If the caller chooses not to specify a hostname, whip
 	 * up a string representation of the passed-in address.
 	 */
-	if (args->servername == NULL) {
+	if (xprtargs.servername == NULL) {
 		struct sockaddr_un *sun =
 				(struct sockaddr_un *)args->address;
 		struct sockaddr_in *sin =
@@ -321,7 +416,7 @@
 			 * address family isn't recognized. */
 			return ERR_PTR(-EINVAL);
 		}
-		args->servername = servername;
+		xprtargs.servername = servername;
 	}
 
 	xprt = xprt_create_transport(&xprtargs);
@@ -374,6 +469,7 @@
 rpc_clone_client(struct rpc_clnt *clnt)
 {
 	struct rpc_clnt *new;
+	struct rpc_xprt *xprt;
 	int err = -ENOMEM;
 
 	new = kmemdup(clnt, sizeof(*new), GFP_KERNEL);
@@ -393,18 +489,25 @@
 		if (new->cl_principal == NULL)
 			goto out_no_principal;
 	}
+	rcu_read_lock();
+	xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
+	rcu_read_unlock();
+	if (xprt == NULL)
+		goto out_no_transport;
+	rcu_assign_pointer(new->cl_xprt, xprt);
 	atomic_set(&new->cl_count, 1);
 	err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name);
 	if (err != 0)
 		goto out_no_path;
 	if (new->cl_auth)
 		atomic_inc(&new->cl_auth->au_count);
-	xprt_get(clnt->cl_xprt);
 	atomic_inc(&clnt->cl_count);
 	rpc_register_client(new);
 	rpciod_up();
 	return new;
 out_no_path:
+	xprt_put(xprt);
+out_no_transport:
 	kfree(new->cl_principal);
 out_no_principal:
 	rpc_free_iostats(new->cl_metrics);
@@ -453,8 +556,9 @@
  */
 void rpc_shutdown_client(struct rpc_clnt *clnt)
 {
-	dprintk("RPC:       shutting down %s client for %s\n",
-			clnt->cl_protname, clnt->cl_server);
+	dprintk_rcu("RPC:       shutting down %s client for %s\n",
+			clnt->cl_protname,
+			rcu_dereference(clnt->cl_xprt)->servername);
 
 	while (!list_empty(&clnt->cl_tasks)) {
 		rpc_killall_tasks(clnt);
@@ -472,24 +576,17 @@
 static void
 rpc_free_client(struct rpc_clnt *clnt)
 {
-	dprintk("RPC:       destroying %s client for %s\n",
-			clnt->cl_protname, clnt->cl_server);
-	if (!IS_ERR(clnt->cl_path.dentry)) {
-		rpc_remove_client_dir(clnt->cl_path.dentry);
-		rpc_put_mount();
-	}
-	if (clnt->cl_parent != clnt) {
+	dprintk_rcu("RPC:       destroying %s client for %s\n",
+			clnt->cl_protname,
+			rcu_dereference(clnt->cl_xprt)->servername);
+	if (clnt->cl_parent != clnt)
 		rpc_release_client(clnt->cl_parent);
-		goto out_free;
-	}
-	if (clnt->cl_server != clnt->cl_inline_name)
-		kfree(clnt->cl_server);
-out_free:
 	rpc_unregister_client(clnt);
+	rpc_clnt_remove_pipedir(clnt);
 	rpc_free_iostats(clnt->cl_metrics);
 	kfree(clnt->cl_principal);
 	clnt->cl_metrics = NULL;
-	xprt_put(clnt->cl_xprt);
+	xprt_put(rcu_dereference_raw(clnt->cl_xprt));
 	rpciod_down();
 	kfree(clnt);
 }
@@ -542,11 +639,11 @@
  * The Sun NFSv2/v3 ACL protocol can do this.
  */
 struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
-				      struct rpc_program *program,
+				      const struct rpc_program *program,
 				      u32 vers)
 {
 	struct rpc_clnt *clnt;
-	struct rpc_version *version;
+	const struct rpc_version *version;
 	int err;
 
 	BUG_ON(vers >= program->nrvers || !program->version[vers]);
@@ -778,13 +875,18 @@
 size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize)
 {
 	size_t bytes;
-	struct rpc_xprt *xprt = clnt->cl_xprt;
+	struct rpc_xprt *xprt;
 
-	bytes = sizeof(xprt->addr);
+	rcu_read_lock();
+	xprt = rcu_dereference(clnt->cl_xprt);
+
+	bytes = xprt->addrlen;
 	if (bytes > bufsize)
 		bytes = bufsize;
-	memcpy(buf, &clnt->cl_xprt->addr, bytes);
-	return xprt->addrlen;
+	memcpy(buf, &xprt->addr, bytes);
+	rcu_read_unlock();
+
+	return bytes;
 }
 EXPORT_SYMBOL_GPL(rpc_peeraddr);
 
@@ -793,11 +895,16 @@
  * @clnt: RPC client structure
  * @format: address format
  *
+ * NB: the lifetime of the memory referenced by the returned pointer is
+ * the same as the rpc_xprt itself.  As long as the caller uses this
+ * pointer, it must hold the RCU read lock.
  */
 const char *rpc_peeraddr2str(struct rpc_clnt *clnt,
 			     enum rpc_display_format_t format)
 {
-	struct rpc_xprt *xprt = clnt->cl_xprt;
+	struct rpc_xprt *xprt;
+
+	xprt = rcu_dereference(clnt->cl_xprt);
 
 	if (xprt->address_strings[format] != NULL)
 		return xprt->address_strings[format];
@@ -806,17 +913,203 @@
 }
 EXPORT_SYMBOL_GPL(rpc_peeraddr2str);
 
+static const struct sockaddr_in rpc_inaddr_loopback = {
+	.sin_family		= AF_INET,
+	.sin_addr.s_addr	= htonl(INADDR_ANY),
+};
+
+static const struct sockaddr_in6 rpc_in6addr_loopback = {
+	.sin6_family		= AF_INET6,
+	.sin6_addr		= IN6ADDR_ANY_INIT,
+};
+
+/*
+ * Try a getsockname() on a connected datagram socket.  Using a
+ * connected datagram socket prevents leaving a socket in TIME_WAIT.
+ * This conserves the ephemeral port number space.
+ *
+ * Returns zero and fills in "buf" if successful; otherwise, a
+ * negative errno is returned.
+ */
+static int rpc_sockname(struct net *net, struct sockaddr *sap, size_t salen,
+			struct sockaddr *buf, int buflen)
+{
+	struct socket *sock;
+	int err;
+
+	err = __sock_create(net, sap->sa_family,
+				SOCK_DGRAM, IPPROTO_UDP, &sock, 1);
+	if (err < 0) {
+		dprintk("RPC:       can't create UDP socket (%d)\n", err);
+		goto out;
+	}
+
+	switch (sap->sa_family) {
+	case AF_INET:
+		err = kernel_bind(sock,
+				(struct sockaddr *)&rpc_inaddr_loopback,
+				sizeof(rpc_inaddr_loopback));
+		break;
+	case AF_INET6:
+		err = kernel_bind(sock,
+				(struct sockaddr *)&rpc_in6addr_loopback,
+				sizeof(rpc_in6addr_loopback));
+		break;
+	default:
+		err = -EAFNOSUPPORT;
+		goto out;
+	}
+	if (err < 0) {
+		dprintk("RPC:       can't bind UDP socket (%d)\n", err);
+		goto out_release;
+	}
+
+	err = kernel_connect(sock, sap, salen, 0);
+	if (err < 0) {
+		dprintk("RPC:       can't connect UDP socket (%d)\n", err);
+		goto out_release;
+	}
+
+	err = kernel_getsockname(sock, buf, &buflen);
+	if (err < 0) {
+		dprintk("RPC:       getsockname failed (%d)\n", err);
+		goto out_release;
+	}
+
+	err = 0;
+	if (buf->sa_family == AF_INET6) {
+		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)buf;
+		sin6->sin6_scope_id = 0;
+	}
+	dprintk("RPC:       %s succeeded\n", __func__);
+
+out_release:
+	sock_release(sock);
+out:
+	return err;
+}
+
+/*
+ * Scraping a connected socket failed, so we don't have a useable
+ * local address.  Fallback: generate an address that will prevent
+ * the server from calling us back.
+ *
+ * Returns zero and fills in "buf" if successful; otherwise, a
+ * negative errno is returned.
+ */
+static int rpc_anyaddr(int family, struct sockaddr *buf, size_t buflen)
+{
+	switch (family) {
+	case AF_INET:
+		if (buflen < sizeof(rpc_inaddr_loopback))
+			return -EINVAL;
+		memcpy(buf, &rpc_inaddr_loopback,
+				sizeof(rpc_inaddr_loopback));
+		break;
+	case AF_INET6:
+		if (buflen < sizeof(rpc_in6addr_loopback))
+			return -EINVAL;
+		memcpy(buf, &rpc_in6addr_loopback,
+				sizeof(rpc_in6addr_loopback));
+	default:
+		dprintk("RPC:       %s: address family not supported\n",
+			__func__);
+		return -EAFNOSUPPORT;
+	}
+	dprintk("RPC:       %s: succeeded\n", __func__);
+	return 0;
+}
+
+/**
+ * rpc_localaddr - discover local endpoint address for an RPC client
+ * @clnt: RPC client structure
+ * @buf: target buffer
+ * @buflen: size of target buffer, in bytes
+ *
+ * Returns zero and fills in "buf" and "buflen" if successful;
+ * otherwise, a negative errno is returned.
+ *
+ * This works even if the underlying transport is not currently connected,
+ * or if the upper layer never previously provided a source address.
+ *
+ * The result of this function call is transient: multiple calls in
+ * succession may give different results, depending on how local
+ * networking configuration changes over time.
+ */
+int rpc_localaddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t buflen)
+{
+	struct sockaddr_storage address;
+	struct sockaddr *sap = (struct sockaddr *)&address;
+	struct rpc_xprt *xprt;
+	struct net *net;
+	size_t salen;
+	int err;
+
+	rcu_read_lock();
+	xprt = rcu_dereference(clnt->cl_xprt);
+	salen = xprt->addrlen;
+	memcpy(sap, &xprt->addr, salen);
+	net = get_net(xprt->xprt_net);
+	rcu_read_unlock();
+
+	rpc_set_port(sap, 0);
+	err = rpc_sockname(net, sap, salen, buf, buflen);
+	put_net(net);
+	if (err != 0)
+		/* Couldn't discover local address, return ANYADDR */
+		return rpc_anyaddr(sap->sa_family, buf, buflen);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rpc_localaddr);
+
 void
 rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize)
 {
-	struct rpc_xprt *xprt = clnt->cl_xprt;
+	struct rpc_xprt *xprt;
+
+	rcu_read_lock();
+	xprt = rcu_dereference(clnt->cl_xprt);
 	if (xprt->ops->set_buffer_size)
 		xprt->ops->set_buffer_size(xprt, sndsize, rcvsize);
+	rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(rpc_setbufsize);
 
-/*
- * Return size of largest payload RPC client can support, in bytes
+/**
+ * rpc_protocol - Get transport protocol number for an RPC client
+ * @clnt: RPC client to query
+ *
+ */
+int rpc_protocol(struct rpc_clnt *clnt)
+{
+	int protocol;
+
+	rcu_read_lock();
+	protocol = rcu_dereference(clnt->cl_xprt)->prot;
+	rcu_read_unlock();
+	return protocol;
+}
+EXPORT_SYMBOL_GPL(rpc_protocol);
+
+/**
+ * rpc_net_ns - Get the network namespace for this RPC client
+ * @clnt: RPC client to query
+ *
+ */
+struct net *rpc_net_ns(struct rpc_clnt *clnt)
+{
+	struct net *ret;
+
+	rcu_read_lock();
+	ret = rcu_dereference(clnt->cl_xprt)->xprt_net;
+	rcu_read_unlock();
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rpc_net_ns);
+
+/**
+ * rpc_max_payload - Get maximum payload size for a transport, in bytes
+ * @clnt: RPC client to query
  *
  * For stream transports, this is one RPC record fragment (see RFC
  * 1831), as we don't support multi-record requests yet.  For datagram
@@ -825,7 +1118,12 @@
  */
 size_t rpc_max_payload(struct rpc_clnt *clnt)
 {
-	return clnt->cl_xprt->max_payload;
+	size_t ret;
+
+	rcu_read_lock();
+	ret = rcu_dereference(clnt->cl_xprt)->max_payload;
+	rcu_read_unlock();
+	return ret;
 }
 EXPORT_SYMBOL_GPL(rpc_max_payload);
 
@@ -836,8 +1134,11 @@
  */
 void rpc_force_rebind(struct rpc_clnt *clnt)
 {
-	if (clnt->cl_autobind)
-		xprt_clear_bound(clnt->cl_xprt);
+	if (clnt->cl_autobind) {
+		rcu_read_lock();
+		xprt_clear_bound(rcu_dereference(clnt->cl_xprt));
+		rcu_read_unlock();
+	}
 }
 EXPORT_SYMBOL_GPL(rpc_force_rebind);
 
@@ -1163,6 +1464,7 @@
 		return;
 	}
 
+	trace_rpc_bind_status(task);
 	switch (task->tk_status) {
 	case -ENOMEM:
 		dprintk("RPC: %5u rpcbind out of memory\n", task->tk_pid);
@@ -1262,6 +1564,7 @@
 		return;
 	}
 
+	trace_rpc_connect_status(task, status);
 	switch (status) {
 		/* if soft mounted, test if we've timed out */
 	case -ETIMEDOUT:
@@ -1450,6 +1753,7 @@
 		return;
 	}
 
+	trace_rpc_call_status(task);
 	task->tk_status = 0;
 	switch(status) {
 	case -EHOSTDOWN:
@@ -1513,8 +1817,11 @@
 	}
 	if (RPC_IS_SOFT(task)) {
 		if (clnt->cl_chatty)
+			rcu_read_lock();
 			printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
-				clnt->cl_protname, clnt->cl_server);
+				clnt->cl_protname,
+				rcu_dereference(clnt->cl_xprt)->servername);
+			rcu_read_unlock();
 		if (task->tk_flags & RPC_TASK_TIMEOUT)
 			rpc_exit(task, -ETIMEDOUT);
 		else
@@ -1524,9 +1831,13 @@
 
 	if (!(task->tk_flags & RPC_CALL_MAJORSEEN)) {
 		task->tk_flags |= RPC_CALL_MAJORSEEN;
-		if (clnt->cl_chatty)
+		if (clnt->cl_chatty) {
+			rcu_read_lock();
 			printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
-			clnt->cl_protname, clnt->cl_server);
+			clnt->cl_protname,
+			rcu_dereference(clnt->cl_xprt)->servername);
+			rcu_read_unlock();
+		}
 	}
 	rpc_force_rebind(clnt);
 	/*
@@ -1555,9 +1866,13 @@
 	dprint_status(task);
 
 	if (task->tk_flags & RPC_CALL_MAJORSEEN) {
-		if (clnt->cl_chatty)
+		if (clnt->cl_chatty) {
+			rcu_read_lock();
 			printk(KERN_NOTICE "%s: server %s OK\n",
-				clnt->cl_protname, clnt->cl_server);
+				clnt->cl_protname,
+				rcu_dereference(clnt->cl_xprt)->servername);
+			rcu_read_unlock();
+		}
 		task->tk_flags &= ~RPC_CALL_MAJORSEEN;
 	}
 
@@ -1635,6 +1950,7 @@
 static __be32 *
 rpc_verify_header(struct rpc_task *task)
 {
+	struct rpc_clnt *clnt = task->tk_client;
 	struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];
 	int len = task->tk_rqstp->rq_rcv_buf.len >> 2;
 	__be32	*p = iov->iov_base;
@@ -1707,8 +2023,11 @@
 			task->tk_action = call_bind;
 			goto out_retry;
 		case RPC_AUTH_TOOWEAK:
+			rcu_read_lock();
 			printk(KERN_NOTICE "RPC: server %s requires stronger "
-			       "authentication.\n", task->tk_client->cl_server);
+			       "authentication.\n",
+			       rcu_dereference(clnt->cl_xprt)->servername);
+			rcu_read_unlock();
 			break;
 		default:
 			dprintk("RPC: %5u %s: unknown auth error: %x\n",
@@ -1731,28 +2050,27 @@
 	case RPC_SUCCESS:
 		return p;
 	case RPC_PROG_UNAVAIL:
-		dprintk("RPC: %5u %s: program %u is unsupported by server %s\n",
-				task->tk_pid, __func__,
-				(unsigned int)task->tk_client->cl_prog,
-				task->tk_client->cl_server);
+		dprintk_rcu("RPC: %5u %s: program %u is unsupported "
+				"by server %s\n", task->tk_pid, __func__,
+				(unsigned int)clnt->cl_prog,
+				rcu_dereference(clnt->cl_xprt)->servername);
 		error = -EPFNOSUPPORT;
 		goto out_err;
 	case RPC_PROG_MISMATCH:
-		dprintk("RPC: %5u %s: program %u, version %u unsupported by "
-				"server %s\n", task->tk_pid, __func__,
-				(unsigned int)task->tk_client->cl_prog,
-				(unsigned int)task->tk_client->cl_vers,
-				task->tk_client->cl_server);
+		dprintk_rcu("RPC: %5u %s: program %u, version %u unsupported "
+				"by server %s\n", task->tk_pid, __func__,
+				(unsigned int)clnt->cl_prog,
+				(unsigned int)clnt->cl_vers,
+				rcu_dereference(clnt->cl_xprt)->servername);
 		error = -EPROTONOSUPPORT;
 		goto out_err;
 	case RPC_PROC_UNAVAIL:
-		dprintk("RPC: %5u %s: proc %s unsupported by program %u, "
+		dprintk_rcu("RPC: %5u %s: proc %s unsupported by program %u, "
 				"version %u on server %s\n",
 				task->tk_pid, __func__,
 				rpc_proc_name(task),
-				task->tk_client->cl_prog,
-				task->tk_client->cl_vers,
-				task->tk_client->cl_server);
+				clnt->cl_prog, clnt->cl_vers,
+				rcu_dereference(clnt->cl_xprt)->servername);
 		error = -EOPNOTSUPP;
 		goto out_err;
 	case RPC_GARBAGE_ARGS:
@@ -1766,7 +2084,7 @@
 	}
 
 out_garbage:
-	task->tk_client->cl_stats->rpcgarbage++;
+	clnt->cl_stats->rpcgarbage++;
 	if (task->tk_garb_retry) {
 		task->tk_garb_retry--;
 		dprintk("RPC: %5u %s: retrying\n",
@@ -1852,14 +2170,15 @@
 		task->tk_action, rpc_waitq);
 }
 
-void rpc_show_tasks(void)
+void rpc_show_tasks(struct net *net)
 {
 	struct rpc_clnt *clnt;
 	struct rpc_task *task;
 	int header = 0;
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
-	spin_lock(&rpc_client_lock);
-	list_for_each_entry(clnt, &all_clients, cl_clients) {
+	spin_lock(&sn->rpc_client_lock);
+	list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
 		spin_lock(&clnt->cl_lock);
 		list_for_each_entry(task, &clnt->cl_tasks, tk_task) {
 			if (!header) {
@@ -1870,6 +2189,6 @@
 		}
 		spin_unlock(&clnt->cl_lock);
 	}
-	spin_unlock(&rpc_client_lock);
+	spin_unlock(&sn->rpc_client_lock);
 }
 #endif
diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h
index d013bf2..ce7bd44 100644
--- a/net/sunrpc/netns.h
+++ b/net/sunrpc/netns.h
@@ -9,6 +9,20 @@
 struct sunrpc_net {
 	struct proc_dir_entry *proc_net_rpc;
 	struct cache_detail *ip_map_cache;
+	struct cache_detail *unix_gid_cache;
+	struct cache_detail *rsc_cache;
+	struct cache_detail *rsi_cache;
+
+	struct super_block *pipefs_sb;
+	struct mutex pipefs_sb_lock;
+
+	struct list_head all_clients;
+	spinlock_t rpc_client_lock;
+
+	struct rpc_clnt *rpcb_local_clnt;
+	struct rpc_clnt *rpcb_local_clnt4;
+	spinlock_t rpcb_clnt_lock;
+	unsigned int rpcb_users;
 };
 
 extern int sunrpc_net_id;
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 63a7a7a..0af37fc 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -16,9 +16,9 @@
 #include <linux/namei.h>
 #include <linux/fsnotify.h>
 #include <linux/kernel.h>
+#include <linux/rcupdate.h>
 
 #include <asm/ioctls.h>
-#include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/wait.h>
 #include <linux/seq_file.h>
@@ -27,9 +27,15 @@
 #include <linux/workqueue.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/sunrpc/cache.h>
+#include <linux/nsproxy.h>
+#include <linux/notifier.h>
 
-static struct vfsmount *rpc_mnt __read_mostly;
-static int rpc_mount_count;
+#include "netns.h"
+#include "sunrpc.h"
+
+#define RPCDBG_FACILITY RPCDBG_DEBUG
+
+#define NET_NAME(net)	((net == &init_net) ? " (init_net)" : "")
 
 static struct file_system_type rpc_pipe_fs_type;
 
@@ -38,7 +44,21 @@
 
 #define RPC_UPCALL_TIMEOUT (30*HZ)
 
-static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head,
+static BLOCKING_NOTIFIER_HEAD(rpc_pipefs_notifier_list);
+
+int rpc_pipefs_notifier_register(struct notifier_block *nb)
+{
+	return blocking_notifier_chain_cond_register(&rpc_pipefs_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_register);
+
+void rpc_pipefs_notifier_unregister(struct notifier_block *nb)
+{
+	blocking_notifier_chain_unregister(&rpc_pipefs_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_unregister);
+
+static void rpc_purge_list(wait_queue_head_t *waitq, struct list_head *head,
 		void (*destroy_msg)(struct rpc_pipe_msg *), int err)
 {
 	struct rpc_pipe_msg *msg;
@@ -51,30 +71,31 @@
 		msg->errno = err;
 		destroy_msg(msg);
 	} while (!list_empty(head));
-	wake_up(&rpci->waitq);
+	wake_up(waitq);
 }
 
 static void
 rpc_timeout_upcall_queue(struct work_struct *work)
 {
 	LIST_HEAD(free_list);
-	struct rpc_inode *rpci =
-		container_of(work, struct rpc_inode, queue_timeout.work);
-	struct inode *inode = &rpci->vfs_inode;
+	struct rpc_pipe *pipe =
+		container_of(work, struct rpc_pipe, queue_timeout.work);
 	void (*destroy_msg)(struct rpc_pipe_msg *);
+	struct dentry *dentry;
 
-	spin_lock(&inode->i_lock);
-	if (rpci->ops == NULL) {
-		spin_unlock(&inode->i_lock);
-		return;
+	spin_lock(&pipe->lock);
+	destroy_msg = pipe->ops->destroy_msg;
+	if (pipe->nreaders == 0) {
+		list_splice_init(&pipe->pipe, &free_list);
+		pipe->pipelen = 0;
 	}
-	destroy_msg = rpci->ops->destroy_msg;
-	if (rpci->nreaders == 0) {
-		list_splice_init(&rpci->pipe, &free_list);
-		rpci->pipelen = 0;
+	dentry = dget(pipe->dentry);
+	spin_unlock(&pipe->lock);
+	if (dentry) {
+		rpc_purge_list(&RPC_I(dentry->d_inode)->waitq,
+			       &free_list, destroy_msg, -ETIMEDOUT);
+		dput(dentry);
 	}
-	spin_unlock(&inode->i_lock);
-	rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT);
 }
 
 ssize_t rpc_pipe_generic_upcall(struct file *filp, struct rpc_pipe_msg *msg,
@@ -108,30 +129,31 @@
  * initialize the fields of @msg (other than @msg->list) appropriately.
  */
 int
-rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
+rpc_queue_upcall(struct rpc_pipe *pipe, struct rpc_pipe_msg *msg)
 {
-	struct rpc_inode *rpci = RPC_I(inode);
 	int res = -EPIPE;
+	struct dentry *dentry;
 
-	spin_lock(&inode->i_lock);
-	if (rpci->ops == NULL)
-		goto out;
-	if (rpci->nreaders) {
-		list_add_tail(&msg->list, &rpci->pipe);
-		rpci->pipelen += msg->len;
+	spin_lock(&pipe->lock);
+	if (pipe->nreaders) {
+		list_add_tail(&msg->list, &pipe->pipe);
+		pipe->pipelen += msg->len;
 		res = 0;
-	} else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) {
-		if (list_empty(&rpci->pipe))
+	} else if (pipe->flags & RPC_PIPE_WAIT_FOR_OPEN) {
+		if (list_empty(&pipe->pipe))
 			queue_delayed_work(rpciod_workqueue,
-					&rpci->queue_timeout,
+					&pipe->queue_timeout,
 					RPC_UPCALL_TIMEOUT);
-		list_add_tail(&msg->list, &rpci->pipe);
-		rpci->pipelen += msg->len;
+		list_add_tail(&msg->list, &pipe->pipe);
+		pipe->pipelen += msg->len;
 		res = 0;
 	}
-out:
-	spin_unlock(&inode->i_lock);
-	wake_up(&rpci->waitq);
+	dentry = dget(pipe->dentry);
+	spin_unlock(&pipe->lock);
+	if (dentry) {
+		wake_up(&RPC_I(dentry->d_inode)->waitq);
+		dput(dentry);
+	}
 	return res;
 }
 EXPORT_SYMBOL_GPL(rpc_queue_upcall);
@@ -145,29 +167,26 @@
 static void
 rpc_close_pipes(struct inode *inode)
 {
-	struct rpc_inode *rpci = RPC_I(inode);
-	const struct rpc_pipe_ops *ops;
+	struct rpc_pipe *pipe = RPC_I(inode)->pipe;
 	int need_release;
+	LIST_HEAD(free_list);
 
 	mutex_lock(&inode->i_mutex);
-	ops = rpci->ops;
-	if (ops != NULL) {
-		LIST_HEAD(free_list);
-		spin_lock(&inode->i_lock);
-		need_release = rpci->nreaders != 0 || rpci->nwriters != 0;
-		rpci->nreaders = 0;
-		list_splice_init(&rpci->in_upcall, &free_list);
-		list_splice_init(&rpci->pipe, &free_list);
-		rpci->pipelen = 0;
-		rpci->ops = NULL;
-		spin_unlock(&inode->i_lock);
-		rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE);
-		rpci->nwriters = 0;
-		if (need_release && ops->release_pipe)
-			ops->release_pipe(inode);
-		cancel_delayed_work_sync(&rpci->queue_timeout);
-	}
+	spin_lock(&pipe->lock);
+	need_release = pipe->nreaders != 0 || pipe->nwriters != 0;
+	pipe->nreaders = 0;
+	list_splice_init(&pipe->in_upcall, &free_list);
+	list_splice_init(&pipe->pipe, &free_list);
+	pipe->pipelen = 0;
+	pipe->dentry = NULL;
+	spin_unlock(&pipe->lock);
+	rpc_purge_list(&RPC_I(inode)->waitq, &free_list, pipe->ops->destroy_msg, -EPIPE);
+	pipe->nwriters = 0;
+	if (need_release && pipe->ops->release_pipe)
+		pipe->ops->release_pipe(inode);
+	cancel_delayed_work_sync(&pipe->queue_timeout);
 	rpc_inode_setowner(inode, NULL);
+	RPC_I(inode)->pipe = NULL;
 	mutex_unlock(&inode->i_mutex);
 }
 
@@ -197,23 +216,24 @@
 static int
 rpc_pipe_open(struct inode *inode, struct file *filp)
 {
-	struct rpc_inode *rpci = RPC_I(inode);
+	struct rpc_pipe *pipe;
 	int first_open;
 	int res = -ENXIO;
 
 	mutex_lock(&inode->i_mutex);
-	if (rpci->ops == NULL)
+	pipe = RPC_I(inode)->pipe;
+	if (pipe == NULL)
 		goto out;
-	first_open = rpci->nreaders == 0 && rpci->nwriters == 0;
-	if (first_open && rpci->ops->open_pipe) {
-		res = rpci->ops->open_pipe(inode);
+	first_open = pipe->nreaders == 0 && pipe->nwriters == 0;
+	if (first_open && pipe->ops->open_pipe) {
+		res = pipe->ops->open_pipe(inode);
 		if (res)
 			goto out;
 	}
 	if (filp->f_mode & FMODE_READ)
-		rpci->nreaders++;
+		pipe->nreaders++;
 	if (filp->f_mode & FMODE_WRITE)
-		rpci->nwriters++;
+		pipe->nwriters++;
 	res = 0;
 out:
 	mutex_unlock(&inode->i_mutex);
@@ -223,38 +243,39 @@
 static int
 rpc_pipe_release(struct inode *inode, struct file *filp)
 {
-	struct rpc_inode *rpci = RPC_I(inode);
+	struct rpc_pipe *pipe;
 	struct rpc_pipe_msg *msg;
 	int last_close;
 
 	mutex_lock(&inode->i_mutex);
-	if (rpci->ops == NULL)
+	pipe = RPC_I(inode)->pipe;
+	if (pipe == NULL)
 		goto out;
 	msg = filp->private_data;
 	if (msg != NULL) {
-		spin_lock(&inode->i_lock);
+		spin_lock(&pipe->lock);
 		msg->errno = -EAGAIN;
 		list_del_init(&msg->list);
-		spin_unlock(&inode->i_lock);
-		rpci->ops->destroy_msg(msg);
+		spin_unlock(&pipe->lock);
+		pipe->ops->destroy_msg(msg);
 	}
 	if (filp->f_mode & FMODE_WRITE)
-		rpci->nwriters --;
+		pipe->nwriters --;
 	if (filp->f_mode & FMODE_READ) {
-		rpci->nreaders --;
-		if (rpci->nreaders == 0) {
+		pipe->nreaders --;
+		if (pipe->nreaders == 0) {
 			LIST_HEAD(free_list);
-			spin_lock(&inode->i_lock);
-			list_splice_init(&rpci->pipe, &free_list);
-			rpci->pipelen = 0;
-			spin_unlock(&inode->i_lock);
-			rpc_purge_list(rpci, &free_list,
-					rpci->ops->destroy_msg, -EAGAIN);
+			spin_lock(&pipe->lock);
+			list_splice_init(&pipe->pipe, &free_list);
+			pipe->pipelen = 0;
+			spin_unlock(&pipe->lock);
+			rpc_purge_list(&RPC_I(inode)->waitq, &free_list,
+					pipe->ops->destroy_msg, -EAGAIN);
 		}
 	}
-	last_close = rpci->nwriters == 0 && rpci->nreaders == 0;
-	if (last_close && rpci->ops->release_pipe)
-		rpci->ops->release_pipe(inode);
+	last_close = pipe->nwriters == 0 && pipe->nreaders == 0;
+	if (last_close && pipe->ops->release_pipe)
+		pipe->ops->release_pipe(inode);
 out:
 	mutex_unlock(&inode->i_mutex);
 	return 0;
@@ -264,39 +285,40 @@
 rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
 {
 	struct inode *inode = filp->f_path.dentry->d_inode;
-	struct rpc_inode *rpci = RPC_I(inode);
+	struct rpc_pipe *pipe;
 	struct rpc_pipe_msg *msg;
 	int res = 0;
 
 	mutex_lock(&inode->i_mutex);
-	if (rpci->ops == NULL) {
+	pipe = RPC_I(inode)->pipe;
+	if (pipe == NULL) {
 		res = -EPIPE;
 		goto out_unlock;
 	}
 	msg = filp->private_data;
 	if (msg == NULL) {
-		spin_lock(&inode->i_lock);
-		if (!list_empty(&rpci->pipe)) {
-			msg = list_entry(rpci->pipe.next,
+		spin_lock(&pipe->lock);
+		if (!list_empty(&pipe->pipe)) {
+			msg = list_entry(pipe->pipe.next,
 					struct rpc_pipe_msg,
 					list);
-			list_move(&msg->list, &rpci->in_upcall);
-			rpci->pipelen -= msg->len;
+			list_move(&msg->list, &pipe->in_upcall);
+			pipe->pipelen -= msg->len;
 			filp->private_data = msg;
 			msg->copied = 0;
 		}
-		spin_unlock(&inode->i_lock);
+		spin_unlock(&pipe->lock);
 		if (msg == NULL)
 			goto out_unlock;
 	}
 	/* NOTE: it is up to the callback to update msg->copied */
-	res = rpci->ops->upcall(filp, msg, buf, len);
+	res = pipe->ops->upcall(filp, msg, buf, len);
 	if (res < 0 || msg->len == msg->copied) {
 		filp->private_data = NULL;
-		spin_lock(&inode->i_lock);
+		spin_lock(&pipe->lock);
 		list_del_init(&msg->list);
-		spin_unlock(&inode->i_lock);
-		rpci->ops->destroy_msg(msg);
+		spin_unlock(&pipe->lock);
+		pipe->ops->destroy_msg(msg);
 	}
 out_unlock:
 	mutex_unlock(&inode->i_mutex);
@@ -307,13 +329,12 @@
 rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset)
 {
 	struct inode *inode = filp->f_path.dentry->d_inode;
-	struct rpc_inode *rpci = RPC_I(inode);
 	int res;
 
 	mutex_lock(&inode->i_mutex);
 	res = -EPIPE;
-	if (rpci->ops != NULL)
-		res = rpci->ops->downcall(filp, buf, len);
+	if (RPC_I(inode)->pipe != NULL)
+		res = RPC_I(inode)->pipe->ops->downcall(filp, buf, len);
 	mutex_unlock(&inode->i_mutex);
 	return res;
 }
@@ -321,17 +342,18 @@
 static unsigned int
 rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait)
 {
-	struct rpc_inode *rpci;
-	unsigned int mask = 0;
+	struct inode *inode = filp->f_path.dentry->d_inode;
+	struct rpc_inode *rpci = RPC_I(inode);
+	unsigned int mask = POLLOUT | POLLWRNORM;
 
-	rpci = RPC_I(filp->f_path.dentry->d_inode);
 	poll_wait(filp, &rpci->waitq, wait);
 
-	mask = POLLOUT | POLLWRNORM;
-	if (rpci->ops == NULL)
+	mutex_lock(&inode->i_mutex);
+	if (rpci->pipe == NULL)
 		mask |= POLLERR | POLLHUP;
-	if (filp->private_data || !list_empty(&rpci->pipe))
+	else if (filp->private_data || !list_empty(&rpci->pipe->pipe))
 		mask |= POLLIN | POLLRDNORM;
+	mutex_unlock(&inode->i_mutex);
 	return mask;
 }
 
@@ -339,23 +361,26 @@
 rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	struct inode *inode = filp->f_path.dentry->d_inode;
-	struct rpc_inode *rpci = RPC_I(inode);
+	struct rpc_pipe *pipe;
 	int len;
 
 	switch (cmd) {
 	case FIONREAD:
-		spin_lock(&inode->i_lock);
-		if (rpci->ops == NULL) {
-			spin_unlock(&inode->i_lock);
+		mutex_lock(&inode->i_mutex);
+		pipe = RPC_I(inode)->pipe;
+		if (pipe == NULL) {
+			mutex_unlock(&inode->i_mutex);
 			return -EPIPE;
 		}
-		len = rpci->pipelen;
+		spin_lock(&pipe->lock);
+		len = pipe->pipelen;
 		if (filp->private_data) {
 			struct rpc_pipe_msg *msg;
 			msg = filp->private_data;
 			len += msg->len - msg->copied;
 		}
-		spin_unlock(&inode->i_lock);
+		spin_unlock(&pipe->lock);
+		mutex_unlock(&inode->i_mutex);
 		return put_user(len, (int __user *)arg);
 	default:
 		return -EINVAL;
@@ -378,12 +403,15 @@
 {
 	struct rpc_clnt *clnt = m->private;
 
-	seq_printf(m, "RPC server: %s\n", clnt->cl_server);
+	rcu_read_lock();
+	seq_printf(m, "RPC server: %s\n",
+			rcu_dereference(clnt->cl_xprt)->servername);
 	seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname,
 			clnt->cl_prog, clnt->cl_vers);
 	seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
 	seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO));
 	seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT));
+	rcu_read_unlock();
 	return 0;
 }
 
@@ -440,23 +468,6 @@
 	umode_t mode;
 };
 
-struct vfsmount *rpc_get_mount(void)
-{
-	int err;
-
-	err = simple_pin_fs(&rpc_pipe_fs_type, &rpc_mnt, &rpc_mount_count);
-	if (err != 0)
-		return ERR_PTR(err);
-	return rpc_mnt;
-}
-EXPORT_SYMBOL_GPL(rpc_get_mount);
-
-void rpc_put_mount(void)
-{
-	simple_release_fs(&rpc_mnt, &rpc_mount_count);
-}
-EXPORT_SYMBOL_GPL(rpc_put_mount);
-
 static int rpc_delete_dentry(const struct dentry *dentry)
 {
 	return 1;
@@ -540,12 +551,47 @@
 	return 0;
 }
 
-static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry,
-			umode_t mode,
-			const struct file_operations *i_fop,
-			void *private,
-			const struct rpc_pipe_ops *ops,
-			int flags)
+static void
+init_pipe(struct rpc_pipe *pipe)
+{
+	pipe->nreaders = 0;
+	pipe->nwriters = 0;
+	INIT_LIST_HEAD(&pipe->in_upcall);
+	INIT_LIST_HEAD(&pipe->in_downcall);
+	INIT_LIST_HEAD(&pipe->pipe);
+	pipe->pipelen = 0;
+	INIT_DELAYED_WORK(&pipe->queue_timeout,
+			    rpc_timeout_upcall_queue);
+	pipe->ops = NULL;
+	spin_lock_init(&pipe->lock);
+	pipe->dentry = NULL;
+}
+
+void rpc_destroy_pipe_data(struct rpc_pipe *pipe)
+{
+	kfree(pipe);
+}
+EXPORT_SYMBOL_GPL(rpc_destroy_pipe_data);
+
+struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags)
+{
+	struct rpc_pipe *pipe;
+
+	pipe = kzalloc(sizeof(struct rpc_pipe), GFP_KERNEL);
+	if (!pipe)
+		return ERR_PTR(-ENOMEM);
+	init_pipe(pipe);
+	pipe->ops = ops;
+	pipe->flags = flags;
+	return pipe;
+}
+EXPORT_SYMBOL_GPL(rpc_mkpipe_data);
+
+static int __rpc_mkpipe_dentry(struct inode *dir, struct dentry *dentry,
+			       umode_t mode,
+			       const struct file_operations *i_fop,
+			       void *private,
+			       struct rpc_pipe *pipe)
 {
 	struct rpc_inode *rpci;
 	int err;
@@ -554,10 +600,8 @@
 	if (err)
 		return err;
 	rpci = RPC_I(dentry->d_inode);
-	rpci->nkern_readwriters = 1;
 	rpci->private = private;
-	rpci->flags = flags;
-	rpci->ops = ops;
+	rpci->pipe = pipe;
 	fsnotify_create(dir, dentry);
 	return 0;
 }
@@ -573,6 +617,22 @@
 	return ret;
 }
 
+int rpc_rmdir(struct dentry *dentry)
+{
+	struct dentry *parent;
+	struct inode *dir;
+	int error;
+
+	parent = dget_parent(dentry);
+	dir = parent->d_inode;
+	mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+	error = __rpc_rmdir(dir, dentry);
+	mutex_unlock(&dir->i_mutex);
+	dput(parent);
+	return error;
+}
+EXPORT_SYMBOL_GPL(rpc_rmdir);
+
 static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
 {
 	int ret;
@@ -587,44 +647,26 @@
 static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
-	struct rpc_inode *rpci = RPC_I(inode);
 
-	rpci->nkern_readwriters--;
-	if (rpci->nkern_readwriters != 0)
-		return 0;
 	rpc_close_pipes(inode);
 	return __rpc_unlink(dir, dentry);
 }
 
-static struct dentry *__rpc_lookup_create(struct dentry *parent,
-					  struct qstr *name)
-{
-	struct dentry *dentry;
-
-	dentry = d_lookup(parent, name);
-	if (!dentry) {
-		dentry = d_alloc(parent, name);
-		if (!dentry) {
-			dentry = ERR_PTR(-ENOMEM);
-			goto out_err;
-		}
-	}
-	if (!dentry->d_inode)
-		d_set_d_op(dentry, &rpc_dentry_operations);
-out_err:
-	return dentry;
-}
-
 static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
 					  struct qstr *name)
 {
 	struct dentry *dentry;
 
-	dentry = __rpc_lookup_create(parent, name);
-	if (IS_ERR(dentry))
+	dentry = d_lookup(parent, name);
+	if (!dentry) {
+		dentry = d_alloc(parent, name);
+		if (!dentry)
+			return ERR_PTR(-ENOMEM);
+	}
+	if (dentry->d_inode == NULL) {
+		d_set_d_op(dentry, &rpc_dentry_operations);
 		return dentry;
-	if (dentry->d_inode == NULL)
-		return dentry;
+	}
 	dput(dentry);
 	return ERR_PTR(-EEXIST);
 }
@@ -779,7 +821,7 @@
  * @private: private data to associate with the pipe, for the caller's use
  * @ops: operations defining the behavior of the pipe: upcall, downcall,
  *	release_pipe, open_pipe, and destroy_msg.
- * @flags: rpc_inode flags
+ * @flags: rpc_pipe flags
  *
  * Data is made available for userspace to read by calls to
  * rpc_queue_upcall().  The actual reads will result in calls to
@@ -792,9 +834,8 @@
  * The @private argument passed here will be available to all these methods
  * from the file pointer, via RPC_I(file->f_dentry->d_inode)->private.
  */
-struct dentry *rpc_mkpipe(struct dentry *parent, const char *name,
-			  void *private, const struct rpc_pipe_ops *ops,
-			  int flags)
+struct dentry *rpc_mkpipe_dentry(struct dentry *parent, const char *name,
+				 void *private, struct rpc_pipe *pipe)
 {
 	struct dentry *dentry;
 	struct inode *dir = parent->d_inode;
@@ -802,9 +843,9 @@
 	struct qstr q;
 	int err;
 
-	if (ops->upcall == NULL)
+	if (pipe->ops->upcall == NULL)
 		umode &= ~S_IRUGO;
-	if (ops->downcall == NULL)
+	if (pipe->ops->downcall == NULL)
 		umode &= ~S_IWUGO;
 
 	q.name = name;
@@ -812,24 +853,11 @@
 	q.hash = full_name_hash(q.name, q.len),
 
 	mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
-	dentry = __rpc_lookup_create(parent, &q);
+	dentry = __rpc_lookup_create_exclusive(parent, &q);
 	if (IS_ERR(dentry))
 		goto out;
-	if (dentry->d_inode) {
-		struct rpc_inode *rpci = RPC_I(dentry->d_inode);
-		if (rpci->private != private ||
-				rpci->ops != ops ||
-				rpci->flags != flags) {
-			dput (dentry);
-			err = -EBUSY;
-			goto out_err;
-		}
-		rpci->nkern_readwriters++;
-		goto out;
-	}
-
-	err = __rpc_mkpipe(dir, dentry, umode, &rpc_pipe_fops,
-			   private, ops, flags);
+	err = __rpc_mkpipe_dentry(dir, dentry, umode, &rpc_pipe_fops,
+				  private, pipe);
 	if (err)
 		goto out_err;
 out:
@@ -842,7 +870,7 @@
 			err);
 	goto out;
 }
-EXPORT_SYMBOL_GPL(rpc_mkpipe);
+EXPORT_SYMBOL_GPL(rpc_mkpipe_dentry);
 
 /**
  * rpc_unlink - remove a pipe
@@ -915,7 +943,7 @@
 
 /**
  * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir()
- * @dentry: directory to remove
+ * @clnt: rpc client
  */
 int rpc_remove_client_dir(struct dentry *dentry)
 {
@@ -986,6 +1014,7 @@
 	RPCAUTH_statd,
 	RPCAUTH_nfsd4_cb,
 	RPCAUTH_cache,
+	RPCAUTH_nfsd,
 	RPCAUTH_RootEOF
 };
 
@@ -1018,13 +1047,70 @@
 		.name = "cache",
 		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
 	},
+	[RPCAUTH_nfsd] = {
+		.name = "nfsd",
+		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
+	},
 };
 
+/*
+ * This call can be used only in RPC pipefs mount notification hooks.
+ */
+struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
+			       const unsigned char *dir_name)
+{
+	struct qstr dir = {
+		.name = dir_name,
+		.len = strlen(dir_name),
+		.hash = full_name_hash(dir_name, strlen(dir_name)),
+	};
+
+	return d_lookup(sb->s_root, &dir);
+}
+EXPORT_SYMBOL_GPL(rpc_d_lookup_sb);
+
+void rpc_pipefs_init_net(struct net *net)
+{
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+	mutex_init(&sn->pipefs_sb_lock);
+}
+
+/*
+ * This call will be used for per network namespace operations calls.
+ * Note: Function will be returned with pipefs_sb_lock taken if superblock was
+ * found. This lock have to be released by rpc_put_sb_net() when all operations
+ * will be completed.
+ */
+struct super_block *rpc_get_sb_net(const struct net *net)
+{
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+	mutex_lock(&sn->pipefs_sb_lock);
+	if (sn->pipefs_sb)
+		return sn->pipefs_sb;
+	mutex_unlock(&sn->pipefs_sb_lock);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(rpc_get_sb_net);
+
+void rpc_put_sb_net(const struct net *net)
+{
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+	BUG_ON(sn->pipefs_sb == NULL);
+	mutex_unlock(&sn->pipefs_sb_lock);
+}
+EXPORT_SYMBOL_GPL(rpc_put_sb_net);
+
 static int
 rpc_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *inode;
 	struct dentry *root;
+	struct net *net = data;
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+	int err;
 
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -1033,30 +1119,59 @@
 	sb->s_time_gran = 1;
 
 	inode = rpc_get_inode(sb, S_IFDIR | 0755);
-	if (!inode)
+	sb->s_root = root = d_make_root(inode);
+	if (!root)
 		return -ENOMEM;
-	sb->s_root = root = d_alloc_root(inode);
-	if (!root) {
-		iput(inode);
-		return -ENOMEM;
-	}
 	if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL))
 		return -ENOMEM;
+	dprintk("RPC:	sending pipefs MOUNT notification for net %p%s\n", net,
+								NET_NAME(net));
+	err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
+					   RPC_PIPEFS_MOUNT,
+					   sb);
+	if (err)
+		goto err_depopulate;
+	sb->s_fs_info = get_net(net);
+	sn->pipefs_sb = sb;
 	return 0;
+
+err_depopulate:
+	blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
+					   RPC_PIPEFS_UMOUNT,
+					   sb);
+	__rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF);
+	return err;
 }
 
 static struct dentry *
 rpc_mount(struct file_system_type *fs_type,
 		int flags, const char *dev_name, void *data)
 {
-	return mount_single(fs_type, flags, data, rpc_fill_super);
+	return mount_ns(fs_type, flags, current->nsproxy->net_ns, rpc_fill_super);
+}
+
+static void rpc_kill_sb(struct super_block *sb)
+{
+	struct net *net = sb->s_fs_info;
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+	mutex_lock(&sn->pipefs_sb_lock);
+	sn->pipefs_sb = NULL;
+	mutex_unlock(&sn->pipefs_sb_lock);
+	put_net(net);
+	dprintk("RPC:	sending pipefs UMOUNT notification for net %p%s\n", net,
+								NET_NAME(net));
+	blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
+					   RPC_PIPEFS_UMOUNT,
+					   sb);
+	kill_litter_super(sb);
 }
 
 static struct file_system_type rpc_pipe_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "rpc_pipefs",
 	.mount		= rpc_mount,
-	.kill_sb	= kill_litter_super,
+	.kill_sb	= rpc_kill_sb,
 };
 
 static void
@@ -1066,16 +1181,8 @@
 
 	inode_init_once(&rpci->vfs_inode);
 	rpci->private = NULL;
-	rpci->nreaders = 0;
-	rpci->nwriters = 0;
-	INIT_LIST_HEAD(&rpci->in_upcall);
-	INIT_LIST_HEAD(&rpci->in_downcall);
-	INIT_LIST_HEAD(&rpci->pipe);
-	rpci->pipelen = 0;
+	rpci->pipe = NULL;
 	init_waitqueue_head(&rpci->waitq);
-	INIT_DELAYED_WORK(&rpci->queue_timeout,
-			    rpc_timeout_upcall_queue);
-	rpci->ops = NULL;
 }
 
 int register_rpc_pipefs(void)
@@ -1089,17 +1196,24 @@
 				init_once);
 	if (!rpc_inode_cachep)
 		return -ENOMEM;
+	err = rpc_clients_notifier_register();
+	if (err)
+		goto err_notifier;
 	err = register_filesystem(&rpc_pipe_fs_type);
-	if (err) {
-		kmem_cache_destroy(rpc_inode_cachep);
-		return err;
-	}
-
+	if (err)
+		goto err_register;
 	return 0;
+
+err_register:
+	rpc_clients_notifier_unregister();
+err_notifier:
+	kmem_cache_destroy(rpc_inode_cachep);
+	return err;
 }
 
 void unregister_rpc_pipefs(void)
 {
+	rpc_clients_notifier_unregister();
 	kmem_cache_destroy(rpc_inode_cachep);
 	unregister_filesystem(&rpc_pipe_fs_type);
 }
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 8761bf8..78ac39f 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -23,12 +23,15 @@
 #include <linux/errno.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/nsproxy.h>
 #include <net/ipv6.h>
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/sched.h>
 #include <linux/sunrpc/xprtsock.h>
 
+#include "netns.h"
+
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY	RPCDBG_BIND
 #endif
@@ -109,13 +112,7 @@
 
 static void			rpcb_getport_done(struct rpc_task *, void *);
 static void			rpcb_map_release(void *data);
-static struct rpc_program	rpcb_program;
-
-static struct rpc_clnt *	rpcb_local_clnt;
-static struct rpc_clnt *	rpcb_local_clnt4;
-
-DEFINE_SPINLOCK(rpcb_clnt_lock);
-unsigned int			rpcb_users;
+static const struct rpc_program	rpcb_program;
 
 struct rpcbind_args {
 	struct rpc_xprt *	r_xprt;
@@ -140,8 +137,8 @@
 	struct rpc_procinfo *	rpc_proc;
 };
 
-static struct rpcb_info rpcb_next_version[];
-static struct rpcb_info rpcb_next_version6[];
+static const struct rpcb_info rpcb_next_version[];
+static const struct rpcb_info rpcb_next_version6[];
 
 static const struct rpc_call_ops rpcb_getport_ops = {
 	.rpc_call_done		= rpcb_getport_done,
@@ -164,32 +161,34 @@
 	kfree(map);
 }
 
-static int rpcb_get_local(void)
+static int rpcb_get_local(struct net *net)
 {
 	int cnt;
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
-	spin_lock(&rpcb_clnt_lock);
-	if (rpcb_users)
-		rpcb_users++;
-	cnt = rpcb_users;
-	spin_unlock(&rpcb_clnt_lock);
+	spin_lock(&sn->rpcb_clnt_lock);
+	if (sn->rpcb_users)
+		sn->rpcb_users++;
+	cnt = sn->rpcb_users;
+	spin_unlock(&sn->rpcb_clnt_lock);
 
 	return cnt;
 }
 
-void rpcb_put_local(void)
+void rpcb_put_local(struct net *net)
 {
-	struct rpc_clnt *clnt = rpcb_local_clnt;
-	struct rpc_clnt *clnt4 = rpcb_local_clnt4;
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+	struct rpc_clnt *clnt = sn->rpcb_local_clnt;
+	struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4;
 	int shutdown;
 
-	spin_lock(&rpcb_clnt_lock);
-	if (--rpcb_users == 0) {
-		rpcb_local_clnt = NULL;
-		rpcb_local_clnt4 = NULL;
+	spin_lock(&sn->rpcb_clnt_lock);
+	if (--sn->rpcb_users == 0) {
+		sn->rpcb_local_clnt = NULL;
+		sn->rpcb_local_clnt4 = NULL;
 	}
-	shutdown = !rpcb_users;
-	spin_unlock(&rpcb_clnt_lock);
+	shutdown = !sn->rpcb_users;
+	spin_unlock(&sn->rpcb_clnt_lock);
 
 	if (shutdown) {
 		/*
@@ -202,30 +201,34 @@
 	}
 }
 
-static void rpcb_set_local(struct rpc_clnt *clnt, struct rpc_clnt *clnt4)
+static void rpcb_set_local(struct net *net, struct rpc_clnt *clnt,
+			struct rpc_clnt *clnt4)
 {
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
 	/* Protected by rpcb_create_local_mutex */
-	rpcb_local_clnt = clnt;
-	rpcb_local_clnt4 = clnt4;
+	sn->rpcb_local_clnt = clnt;
+	sn->rpcb_local_clnt4 = clnt4;
 	smp_wmb(); 
-	rpcb_users = 1;
+	sn->rpcb_users = 1;
 	dprintk("RPC:       created new rpcb local clients (rpcb_local_clnt: "
-			"%p, rpcb_local_clnt4: %p)\n", rpcb_local_clnt,
-			rpcb_local_clnt4);
+			"%p, rpcb_local_clnt4: %p) for net %p%s\n",
+			sn->rpcb_local_clnt, sn->rpcb_local_clnt4,
+			net, (net == &init_net) ? " (init_net)" : "");
 }
 
 /*
  * Returns zero on success, otherwise a negative errno value
  * is returned.
  */
-static int rpcb_create_local_unix(void)
+static int rpcb_create_local_unix(struct net *net)
 {
 	static const struct sockaddr_un rpcb_localaddr_rpcbind = {
 		.sun_family		= AF_LOCAL,
 		.sun_path		= RPCBIND_SOCK_PATHNAME,
 	};
 	struct rpc_create_args args = {
-		.net		= &init_net,
+		.net		= net,
 		.protocol	= XPRT_TRANSPORT_LOCAL,
 		.address	= (struct sockaddr *)&rpcb_localaddr_rpcbind,
 		.addrsize	= sizeof(rpcb_localaddr_rpcbind),
@@ -258,7 +261,7 @@
 		clnt4 = NULL;
 	}
 
-	rpcb_set_local(clnt, clnt4);
+	rpcb_set_local(net, clnt, clnt4);
 
 out:
 	return result;
@@ -268,7 +271,7 @@
  * Returns zero on success, otherwise a negative errno value
  * is returned.
  */
-static int rpcb_create_local_net(void)
+static int rpcb_create_local_net(struct net *net)
 {
 	static const struct sockaddr_in rpcb_inaddr_loopback = {
 		.sin_family		= AF_INET,
@@ -276,7 +279,7 @@
 		.sin_port		= htons(RPCBIND_PORT),
 	};
 	struct rpc_create_args args = {
-		.net		= &init_net,
+		.net		= net,
 		.protocol	= XPRT_TRANSPORT_TCP,
 		.address	= (struct sockaddr *)&rpcb_inaddr_loopback,
 		.addrsize	= sizeof(rpcb_inaddr_loopback),
@@ -310,7 +313,7 @@
 		clnt4 = NULL;
 	}
 
-	rpcb_set_local(clnt, clnt4);
+	rpcb_set_local(net, clnt, clnt4);
 
 out:
 	return result;
@@ -320,31 +323,32 @@
  * Returns zero on success, otherwise a negative errno value
  * is returned.
  */
-int rpcb_create_local(void)
+int rpcb_create_local(struct net *net)
 {
 	static DEFINE_MUTEX(rpcb_create_local_mutex);
 	int result = 0;
 
-	if (rpcb_get_local())
+	if (rpcb_get_local(net))
 		return result;
 
 	mutex_lock(&rpcb_create_local_mutex);
-	if (rpcb_get_local())
+	if (rpcb_get_local(net))
 		goto out;
 
-	if (rpcb_create_local_unix() != 0)
-		result = rpcb_create_local_net();
+	if (rpcb_create_local_unix(net) != 0)
+		result = rpcb_create_local_net(net);
 
 out:
 	mutex_unlock(&rpcb_create_local_mutex);
 	return result;
 }
 
-static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
-				    size_t salen, int proto, u32 version)
+static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname,
+				    struct sockaddr *srvaddr, size_t salen,
+				    int proto, u32 version)
 {
 	struct rpc_create_args args = {
-		.net		= &init_net,
+		.net		= net,
 		.protocol	= proto,
 		.address	= srvaddr,
 		.addrsize	= salen,
@@ -420,7 +424,7 @@
  * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6
  * addresses).
  */
-int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
+int rpcb_register(struct net *net, u32 prog, u32 vers, int prot, unsigned short port)
 {
 	struct rpcbind_args map = {
 		.r_prog		= prog,
@@ -431,6 +435,7 @@
 	struct rpc_message msg = {
 		.rpc_argp	= &map,
 	};
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
 	dprintk("RPC:       %sregistering (%u, %u, %d, %u) with local "
 			"rpcbind\n", (port ? "" : "un"),
@@ -440,13 +445,14 @@
 	if (port)
 		msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
 
-	return rpcb_register_call(rpcb_local_clnt, &msg);
+	return rpcb_register_call(sn->rpcb_local_clnt, &msg);
 }
 
 /*
  * Fill in AF_INET family-specific arguments to register
  */
-static int rpcb_register_inet4(const struct sockaddr *sap,
+static int rpcb_register_inet4(struct sunrpc_net *sn,
+			       const struct sockaddr *sap,
 			       struct rpc_message *msg)
 {
 	const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
@@ -465,7 +471,7 @@
 	if (port)
 		msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
 
-	result = rpcb_register_call(rpcb_local_clnt4, msg);
+	result = rpcb_register_call(sn->rpcb_local_clnt4, msg);
 	kfree(map->r_addr);
 	return result;
 }
@@ -473,7 +479,8 @@
 /*
  * Fill in AF_INET6 family-specific arguments to register
  */
-static int rpcb_register_inet6(const struct sockaddr *sap,
+static int rpcb_register_inet6(struct sunrpc_net *sn,
+			       const struct sockaddr *sap,
 			       struct rpc_message *msg)
 {
 	const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
@@ -492,12 +499,13 @@
 	if (port)
 		msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
 
-	result = rpcb_register_call(rpcb_local_clnt4, msg);
+	result = rpcb_register_call(sn->rpcb_local_clnt4, msg);
 	kfree(map->r_addr);
 	return result;
 }
 
-static int rpcb_unregister_all_protofamilies(struct rpc_message *msg)
+static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn,
+					     struct rpc_message *msg)
 {
 	struct rpcbind_args *map = msg->rpc_argp;
 
@@ -508,7 +516,7 @@
 	map->r_addr = "";
 	msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
 
-	return rpcb_register_call(rpcb_local_clnt4, msg);
+	return rpcb_register_call(sn->rpcb_local_clnt4, msg);
 }
 
 /**
@@ -554,7 +562,7 @@
  * service on any IPv4 address, but not on IPv6.  The latter
  * advertises the service on all IPv4 and IPv6 addresses.
  */
-int rpcb_v4_register(const u32 program, const u32 version,
+int rpcb_v4_register(struct net *net, const u32 program, const u32 version,
 		     const struct sockaddr *address, const char *netid)
 {
 	struct rpcbind_args map = {
@@ -566,18 +574,19 @@
 	struct rpc_message msg = {
 		.rpc_argp	= &map,
 	};
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
-	if (rpcb_local_clnt4 == NULL)
+	if (sn->rpcb_local_clnt4 == NULL)
 		return -EPROTONOSUPPORT;
 
 	if (address == NULL)
-		return rpcb_unregister_all_protofamilies(&msg);
+		return rpcb_unregister_all_protofamilies(sn, &msg);
 
 	switch (address->sa_family) {
 	case AF_INET:
-		return rpcb_register_inet4(address, &msg);
+		return rpcb_register_inet4(sn, address, &msg);
 	case AF_INET6:
-		return rpcb_register_inet6(address, &msg);
+		return rpcb_register_inet6(sn, address, &msg);
 	}
 
 	return -EAFNOSUPPORT;
@@ -611,9 +620,10 @@
 static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt)
 {
 	struct rpc_clnt *parent = clnt->cl_parent;
+	struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt);
 
 	while (parent != clnt) {
-		if (parent->cl_xprt != clnt->cl_xprt)
+		if (rcu_dereference(parent->cl_xprt) != xprt)
 			break;
 		if (clnt->cl_autobind)
 			break;
@@ -644,12 +654,16 @@
 	size_t salen;
 	int status;
 
-	clnt = rpcb_find_transport_owner(task->tk_client);
-	xprt = clnt->cl_xprt;
+	rcu_read_lock();
+	do {
+		clnt = rpcb_find_transport_owner(task->tk_client);
+		xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
+	} while (xprt == NULL);
+	rcu_read_unlock();
 
 	dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
 		task->tk_pid, __func__,
-		clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot);
+		xprt->servername, clnt->cl_prog, clnt->cl_vers, xprt->prot);
 
 	/* Put self on the wait queue to ensure we get notified if
 	 * some other task is already attempting to bind the port */
@@ -658,6 +672,7 @@
 	if (xprt_test_and_set_binding(xprt)) {
 		dprintk("RPC: %5u %s: waiting for another binder\n",
 			task->tk_pid, __func__);
+		xprt_put(xprt);
 		return;
 	}
 
@@ -699,8 +714,8 @@
 	dprintk("RPC: %5u %s: trying rpcbind version %u\n",
 		task->tk_pid, __func__, bind_version);
 
-	rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot,
-				bind_version);
+	rpcb_clnt = rpcb_create(xprt->xprt_net, xprt->servername, sap, salen,
+				xprt->prot, bind_version);
 	if (IS_ERR(rpcb_clnt)) {
 		status = PTR_ERR(rpcb_clnt);
 		dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
@@ -719,13 +734,13 @@
 	map->r_vers = clnt->cl_vers;
 	map->r_prot = xprt->prot;
 	map->r_port = 0;
-	map->r_xprt = xprt_get(xprt);
+	map->r_xprt = xprt;
 	map->r_status = -EIO;
 
 	switch (bind_version) {
 	case RPCBVERS_4:
 	case RPCBVERS_3:
-		map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
+		map->r_netid = xprt->address_strings[RPC_DISPLAY_NETID];
 		map->r_addr = rpc_sockaddr2uaddr(sap, GFP_ATOMIC);
 		map->r_owner = "";
 		break;
@@ -754,6 +769,7 @@
 bailout_nofree:
 	rpcb_wake_rpcbind_waiters(xprt, status);
 	task->tk_status = status;
+	xprt_put(xprt);
 }
 EXPORT_SYMBOL_GPL(rpcb_getport_async);
 
@@ -801,11 +817,11 @@
 static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr,
 			     const struct rpcbind_args *rpcb)
 {
-	struct rpc_task *task = req->rq_task;
 	__be32 *p;
 
 	dprintk("RPC: %5u encoding PMAP_%s call (%u, %u, %d, %u)\n",
-			task->tk_pid, task->tk_msg.rpc_proc->p_name,
+			req->rq_task->tk_pid,
+			req->rq_task->tk_msg.rpc_proc->p_name,
 			rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);
 
 	p = xdr_reserve_space(xdr, RPCB_mappingargs_sz << 2);
@@ -818,7 +834,6 @@
 static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr,
 			    struct rpcbind_args *rpcb)
 {
-	struct rpc_task *task = req->rq_task;
 	unsigned long port;
 	__be32 *p;
 
@@ -829,8 +844,8 @@
 		return -EIO;
 
 	port = be32_to_cpup(p);
-	dprintk("RPC: %5u PMAP_%s result: %lu\n", task->tk_pid,
-			task->tk_msg.rpc_proc->p_name, port);
+	dprintk("RPC: %5u PMAP_%s result: %lu\n", req->rq_task->tk_pid,
+			req->rq_task->tk_msg.rpc_proc->p_name, port);
 	if (unlikely(port > USHRT_MAX))
 		return -EIO;
 
@@ -841,7 +856,6 @@
 static int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr,
 			unsigned int *boolp)
 {
-	struct rpc_task *task = req->rq_task;
 	__be32 *p;
 
 	p = xdr_inline_decode(xdr, 4);
@@ -853,7 +867,8 @@
 		*boolp = 1;
 
 	dprintk("RPC: %5u RPCB_%s call %s\n",
-			task->tk_pid, task->tk_msg.rpc_proc->p_name,
+			req->rq_task->tk_pid,
+			req->rq_task->tk_msg.rpc_proc->p_name,
 			(*boolp ? "succeeded" : "failed"));
 	return 0;
 }
@@ -873,11 +888,11 @@
 static void rpcb_enc_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,
 			     const struct rpcbind_args *rpcb)
 {
-	struct rpc_task *task = req->rq_task;
 	__be32 *p;
 
 	dprintk("RPC: %5u encoding RPCB_%s call (%u, %u, '%s', '%s')\n",
-			task->tk_pid, task->tk_msg.rpc_proc->p_name,
+			req->rq_task->tk_pid,
+			req->rq_task->tk_msg.rpc_proc->p_name,
 			rpcb->r_prog, rpcb->r_vers,
 			rpcb->r_netid, rpcb->r_addr);
 
@@ -895,7 +910,6 @@
 {
 	struct sockaddr_storage address;
 	struct sockaddr *sap = (struct sockaddr *)&address;
-	struct rpc_task *task = req->rq_task;
 	__be32 *p;
 	u32 len;
 
@@ -912,7 +926,7 @@
 	 */
 	if (len == 0) {
 		dprintk("RPC: %5u RPCB reply: program not registered\n",
-				task->tk_pid);
+				req->rq_task->tk_pid);
 		return 0;
 	}
 
@@ -922,10 +936,11 @@
 	p = xdr_inline_decode(xdr, len);
 	if (unlikely(p == NULL))
 		goto out_fail;
-	dprintk("RPC: %5u RPCB_%s reply: %s\n", task->tk_pid,
-			task->tk_msg.rpc_proc->p_name, (char *)p);
+	dprintk("RPC: %5u RPCB_%s reply: %s\n", req->rq_task->tk_pid,
+			req->rq_task->tk_msg.rpc_proc->p_name, (char *)p);
 
-	if (rpc_uaddr2sockaddr((char *)p, len, sap, sizeof(address)) == 0)
+	if (rpc_uaddr2sockaddr(req->rq_xprt->xprt_net, (char *)p, len,
+				sap, sizeof(address)) == 0)
 		goto out_fail;
 	rpcb->r_port = rpc_get_port(sap);
 
@@ -933,7 +948,8 @@
 
 out_fail:
 	dprintk("RPC: %5u malformed RPCB_%s reply\n",
-			task->tk_pid, task->tk_msg.rpc_proc->p_name);
+			req->rq_task->tk_pid,
+			req->rq_task->tk_msg.rpc_proc->p_name);
 	return -EIO;
 }
 
@@ -1041,7 +1057,7 @@
 	},
 };
 
-static struct rpcb_info rpcb_next_version[] = {
+static const struct rpcb_info rpcb_next_version[] = {
 	{
 		.rpc_vers	= RPCBVERS_2,
 		.rpc_proc	= &rpcb_procedures2[RPCBPROC_GETPORT],
@@ -1051,7 +1067,7 @@
 	},
 };
 
-static struct rpcb_info rpcb_next_version6[] = {
+static const struct rpcb_info rpcb_next_version6[] = {
 	{
 		.rpc_vers	= RPCBVERS_4,
 		.rpc_proc	= &rpcb_procedures4[RPCBPROC_GETADDR],
@@ -1065,25 +1081,25 @@
 	},
 };
 
-static struct rpc_version rpcb_version2 = {
+static const struct rpc_version rpcb_version2 = {
 	.number		= RPCBVERS_2,
 	.nrprocs	= ARRAY_SIZE(rpcb_procedures2),
 	.procs		= rpcb_procedures2
 };
 
-static struct rpc_version rpcb_version3 = {
+static const struct rpc_version rpcb_version3 = {
 	.number		= RPCBVERS_3,
 	.nrprocs	= ARRAY_SIZE(rpcb_procedures3),
 	.procs		= rpcb_procedures3
 };
 
-static struct rpc_version rpcb_version4 = {
+static const struct rpc_version rpcb_version4 = {
 	.number		= RPCBVERS_4,
 	.nrprocs	= ARRAY_SIZE(rpcb_procedures4),
 	.procs		= rpcb_procedures4
 };
 
-static struct rpc_version *rpcb_version[] = {
+static const struct rpc_version *rpcb_version[] = {
 	NULL,
 	NULL,
 	&rpcb_version2,
@@ -1093,7 +1109,7 @@
 
 static struct rpc_stat rpcb_stats;
 
-static struct rpc_program rpcb_program = {
+static const struct rpc_program rpcb_program = {
 	.name		= "rpcbind",
 	.number		= RPCBIND_PROGRAM,
 	.nrvers		= ARRAY_SIZE(rpcb_version),
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 3341d89..994cfea 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -28,6 +28,9 @@
 #define RPCDBG_FACILITY		RPCDBG_SCHED
 #endif
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/sunrpc.h>
+
 /*
  * RPC slabs and memory pools
  */
@@ -205,9 +208,7 @@
 	queue->qlen = 0;
 	setup_timer(&queue->timer_list.timer, __rpc_queue_timer_fn, (unsigned long)queue);
 	INIT_LIST_HEAD(&queue->timer_list.list);
-#ifdef RPC_DEBUG
-	queue->name = qname;
-#endif
+	rpc_assign_waitqueue_name(queue, qname);
 }
 
 void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname)
@@ -251,6 +252,8 @@
 
 static void rpc_set_active(struct rpc_task *task)
 {
+	trace_rpc_task_begin(task->tk_client, task, NULL);
+
 	rpc_task_set_debuginfo(task);
 	set_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
 }
@@ -267,6 +270,8 @@
 	unsigned long flags;
 	int ret;
 
+	trace_rpc_task_complete(task->tk_client, task, NULL);
+
 	spin_lock_irqsave(&wq->lock, flags);
 	clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
 	ret = atomic_dec_and_test(&task->tk_count);
@@ -324,6 +329,8 @@
 	dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n",
 			task->tk_pid, rpc_qname(q), jiffies);
 
+	trace_rpc_task_sleep(task->tk_client, task, q);
+
 	__rpc_add_wait_queue(q, task, queue_priority);
 
 	BUG_ON(task->tk_callback != NULL);
@@ -378,6 +385,8 @@
 		return;
 	}
 
+	trace_rpc_task_wakeup(task->tk_client, task, queue);
+
 	__rpc_remove_wait_queue(queue, task);
 
 	rpc_make_runnable(task);
@@ -422,7 +431,7 @@
 /*
  * Wake up the next task on a priority queue.
  */
-static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queue)
+static struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *queue)
 {
 	struct list_head *q;
 	struct rpc_task *task;
@@ -467,30 +476,54 @@
 new_owner:
 	rpc_set_waitqueue_owner(queue, task->tk_owner);
 out:
-	rpc_wake_up_task_queue_locked(queue, task);
 	return task;
 }
 
+static struct rpc_task *__rpc_find_next_queued(struct rpc_wait_queue *queue)
+{
+	if (RPC_IS_PRIORITY(queue))
+		return __rpc_find_next_queued_priority(queue);
+	if (!list_empty(&queue->tasks[0]))
+		return list_first_entry(&queue->tasks[0], struct rpc_task, u.tk_wait.list);
+	return NULL;
+}
+
 /*
- * Wake up the next task on the wait queue.
+ * Wake up the first task on the wait queue.
  */
-struct rpc_task * rpc_wake_up_next(struct rpc_wait_queue *queue)
+struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *queue,
+		bool (*func)(struct rpc_task *, void *), void *data)
 {
 	struct rpc_task	*task = NULL;
 
-	dprintk("RPC:       wake_up_next(%p \"%s\")\n",
+	dprintk("RPC:       wake_up_first(%p \"%s\")\n",
 			queue, rpc_qname(queue));
 	spin_lock_bh(&queue->lock);
-	if (RPC_IS_PRIORITY(queue))
-		task = __rpc_wake_up_next_priority(queue);
-	else {
-		task_for_first(task, &queue->tasks[0])
+	task = __rpc_find_next_queued(queue);
+	if (task != NULL) {
+		if (func(task, data))
 			rpc_wake_up_task_queue_locked(queue, task);
+		else
+			task = NULL;
 	}
 	spin_unlock_bh(&queue->lock);
 
 	return task;
 }
+EXPORT_SYMBOL_GPL(rpc_wake_up_first);
+
+static bool rpc_wake_up_next_func(struct rpc_task *task, void *data)
+{
+	return true;
+}
+
+/*
+ * Wake up the next task on the wait queue.
+*/
+struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *queue)
+{
+	return rpc_wake_up_first(queue, rpc_wake_up_next_func, NULL);
+}
 EXPORT_SYMBOL_GPL(rpc_wake_up_next);
 
 /**
@@ -501,14 +534,18 @@
  */
 void rpc_wake_up(struct rpc_wait_queue *queue)
 {
-	struct rpc_task *task, *next;
 	struct list_head *head;
 
 	spin_lock_bh(&queue->lock);
 	head = &queue->tasks[queue->maxpriority];
 	for (;;) {
-		list_for_each_entry_safe(task, next, head, u.tk_wait.list)
+		while (!list_empty(head)) {
+			struct rpc_task *task;
+			task = list_first_entry(head,
+					struct rpc_task,
+					u.tk_wait.list);
 			rpc_wake_up_task_queue_locked(queue, task);
+		}
 		if (head == &queue->tasks[0])
 			break;
 		head--;
@@ -526,13 +563,16 @@
  */
 void rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
 {
-	struct rpc_task *task, *next;
 	struct list_head *head;
 
 	spin_lock_bh(&queue->lock);
 	head = &queue->tasks[queue->maxpriority];
 	for (;;) {
-		list_for_each_entry_safe(task, next, head, u.tk_wait.list) {
+		while (!list_empty(head)) {
+			struct rpc_task *task;
+			task = list_first_entry(head,
+					struct rpc_task,
+					u.tk_wait.list);
 			task->tk_status = status;
 			rpc_wake_up_task_queue_locked(queue, task);
 		}
@@ -677,6 +717,7 @@
 			if (do_action == NULL)
 				break;
 		}
+		trace_rpc_task_run_action(task->tk_client, task, task->tk_action);
 		do_action(task);
 
 		/*
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c
index 80df89d..bc2068e 100644
--- a/net/sunrpc/stats.c
+++ b/net/sunrpc/stats.c
@@ -22,6 +22,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svcsock.h>
 #include <linux/sunrpc/metrics.h>
+#include <linux/rcupdate.h>
 
 #include "netns.h"
 
@@ -133,20 +134,19 @@
 /**
  * rpc_count_iostats - tally up per-task stats
  * @task: completed rpc_task
+ * @stats: array of stat structures
  *
  * Relies on the caller for serialization.
  */
-void rpc_count_iostats(struct rpc_task *task)
+void rpc_count_iostats(const struct rpc_task *task, struct rpc_iostats *stats)
 {
 	struct rpc_rqst *req = task->tk_rqstp;
-	struct rpc_iostats *stats;
 	struct rpc_iostats *op_metrics;
 	ktime_t delta;
 
-	if (!task->tk_client || !task->tk_client->cl_metrics || !req)
+	if (!stats || !req)
 		return;
 
-	stats = task->tk_client->cl_metrics;
 	op_metrics = &stats[task->tk_msg.rpc_proc->p_statidx];
 
 	op_metrics->om_ops++;
@@ -164,6 +164,7 @@
 	delta = ktime_sub(ktime_get(), task->tk_start);
 	op_metrics->om_execute = ktime_add(op_metrics->om_execute, delta);
 }
+EXPORT_SYMBOL_GPL(rpc_count_iostats);
 
 static void _print_name(struct seq_file *seq, unsigned int op,
 			struct rpc_procinfo *procs)
@@ -179,7 +180,7 @@
 void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt)
 {
 	struct rpc_iostats *stats = clnt->cl_metrics;
-	struct rpc_xprt *xprt = clnt->cl_xprt;
+	struct rpc_xprt *xprt;
 	unsigned int op, maxproc = clnt->cl_maxproc;
 
 	if (!stats)
@@ -189,8 +190,11 @@
 	seq_printf(seq, "p/v: %u/%u (%s)\n",
 			clnt->cl_prog, clnt->cl_vers, clnt->cl_protname);
 
+	rcu_read_lock();
+	xprt = rcu_dereference(clnt->cl_xprt);
 	if (xprt)
 		xprt->ops->print_stats(xprt, seq);
+	rcu_read_unlock();
 
 	seq_printf(seq, "\tper-op statistics\n");
 	for (op = 0; op < maxproc; op++) {
@@ -213,45 +217,46 @@
  * Register/unregister RPC proc files
  */
 static inline struct proc_dir_entry *
-do_register(const char *name, void *data, const struct file_operations *fops)
+do_register(struct net *net, const char *name, void *data,
+	    const struct file_operations *fops)
 {
 	struct sunrpc_net *sn;
 
 	dprintk("RPC:       registering /proc/net/rpc/%s\n", name);
-	sn = net_generic(&init_net, sunrpc_net_id);
+	sn = net_generic(net, sunrpc_net_id);
 	return proc_create_data(name, 0, sn->proc_net_rpc, fops, data);
 }
 
 struct proc_dir_entry *
-rpc_proc_register(struct rpc_stat *statp)
+rpc_proc_register(struct net *net, struct rpc_stat *statp)
 {
-	return do_register(statp->program->name, statp, &rpc_proc_fops);
+	return do_register(net, statp->program->name, statp, &rpc_proc_fops);
 }
 EXPORT_SYMBOL_GPL(rpc_proc_register);
 
 void
-rpc_proc_unregister(const char *name)
+rpc_proc_unregister(struct net *net, const char *name)
 {
 	struct sunrpc_net *sn;
 
-	sn = net_generic(&init_net, sunrpc_net_id);
+	sn = net_generic(net, sunrpc_net_id);
 	remove_proc_entry(name, sn->proc_net_rpc);
 }
 EXPORT_SYMBOL_GPL(rpc_proc_unregister);
 
 struct proc_dir_entry *
-svc_proc_register(struct svc_stat *statp, const struct file_operations *fops)
+svc_proc_register(struct net *net, struct svc_stat *statp, const struct file_operations *fops)
 {
-	return do_register(statp->program->pg_name, statp, fops);
+	return do_register(net, statp->program->pg_name, statp, fops);
 }
 EXPORT_SYMBOL_GPL(svc_proc_register);
 
 void
-svc_proc_unregister(const char *name)
+svc_proc_unregister(struct net *net, const char *name)
 {
 	struct sunrpc_net *sn;
 
-	sn = net_generic(&init_net, sunrpc_net_id);
+	sn = net_generic(net, sunrpc_net_id);
 	remove_proc_entry(name, sn->proc_net_rpc);
 }
 EXPORT_SYMBOL_GPL(svc_proc_unregister);
diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h
index 90c292e..14c9f6d 100644
--- a/net/sunrpc/sunrpc.h
+++ b/net/sunrpc/sunrpc.h
@@ -47,5 +47,7 @@
 		    struct page *headpage, unsigned long headoffset,
 		    struct page *tailpage, unsigned long tailoffset);
 
+int rpc_clients_notifier_register(void);
+void rpc_clients_notifier_unregister(void);
 #endif /* _NET_SUNRPC_SUNRPC_H */
 
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 8ec9778..8adfc88 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -25,10 +25,12 @@
 #include "netns.h"
 
 int sunrpc_net_id;
+EXPORT_SYMBOL_GPL(sunrpc_net_id);
 
 static __net_init int sunrpc_init_net(struct net *net)
 {
 	int err;
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
 	err = rpc_proc_init(net);
 	if (err)
@@ -38,8 +40,18 @@
 	if (err)
 		goto err_ipmap;
 
+	err = unix_gid_cache_create(net);
+	if (err)
+		goto err_unixgid;
+
+	rpc_pipefs_init_net(net);
+	INIT_LIST_HEAD(&sn->all_clients);
+	spin_lock_init(&sn->rpc_client_lock);
+	spin_lock_init(&sn->rpcb_clnt_lock);
 	return 0;
 
+err_unixgid:
+	ip_map_cache_destroy(net);
 err_ipmap:
 	rpc_proc_exit(net);
 err_proc:
@@ -48,6 +60,7 @@
 
 static __net_exit void sunrpc_exit_net(struct net *net)
 {
+	unix_gid_cache_destroy(net);
 	ip_map_cache_destroy(net);
 	rpc_proc_exit(net);
 }
@@ -59,8 +72,6 @@
 	.size = sizeof(struct sunrpc_net),
 };
 
-extern struct cache_detail unix_gid_cache;
-
 static int __init
 init_sunrpc(void)
 {
@@ -82,7 +93,6 @@
 #ifdef RPC_DEBUG
 	rpc_register_sysctl();
 #endif
-	cache_register(&unix_gid_cache);
 	svc_init_xprt_sock();	/* svc sock transport */
 	init_socket_xprt();	/* clnt sock transport */
 	return 0;
@@ -105,7 +115,6 @@
 	svc_cleanup_xprt_sock();
 	unregister_rpc_pipefs();
 	rpc_destroy_mempool();
-	cache_unregister(&unix_gid_cache);
 	unregister_pernet_subsys(&sunrpc_net_ops);
 #ifdef RPC_DEBUG
 	rpc_unregister_sysctl();
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index e4aabc0..4153846 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -20,6 +20,7 @@
 #include <linux/module.h>
 #include <linux/kthread.h>
 #include <linux/slab.h>
+#include <linux/nsproxy.h>
 
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/xdr.h>
@@ -30,7 +31,7 @@
 
 #define RPCDBG_FACILITY	RPCDBG_SVCDSP
 
-static void svc_unregister(const struct svc_serv *serv);
+static void svc_unregister(const struct svc_serv *serv, struct net *net);
 
 #define svc_serv_is_pooled(serv)    ((serv)->sv_function)
 
@@ -368,23 +369,24 @@
 	return &serv->sv_pools[pidx % serv->sv_nrpools];
 }
 
-static int svc_rpcb_setup(struct svc_serv *serv)
+int svc_rpcb_setup(struct svc_serv *serv, struct net *net)
 {
 	int err;
 
-	err = rpcb_create_local();
+	err = rpcb_create_local(net);
 	if (err)
 		return err;
 
 	/* Remove any stale portmap registrations */
-	svc_unregister(serv);
+	svc_unregister(serv, net);
 	return 0;
 }
+EXPORT_SYMBOL_GPL(svc_rpcb_setup);
 
-void svc_rpcb_cleanup(struct svc_serv *serv)
+void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net)
 {
-	svc_unregister(serv);
-	rpcb_put_local();
+	svc_unregister(serv, net);
+	rpcb_put_local(net);
 }
 EXPORT_SYMBOL_GPL(svc_rpcb_cleanup);
 
@@ -410,7 +412,7 @@
  */
 static struct svc_serv *
 __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
-	     void (*shutdown)(struct svc_serv *serv))
+	     void (*shutdown)(struct svc_serv *serv, struct net *net))
 {
 	struct svc_serv	*serv;
 	unsigned int vers;
@@ -470,7 +472,7 @@
 	}
 
 	if (svc_uses_rpcbind(serv)) {
-	       	if (svc_rpcb_setup(serv) < 0) {
+		if (svc_rpcb_setup(serv, current->nsproxy->net_ns) < 0) {
 			kfree(serv->sv_pools);
 			kfree(serv);
 			return NULL;
@@ -484,7 +486,7 @@
 
 struct svc_serv *
 svc_create(struct svc_program *prog, unsigned int bufsize,
-	   void (*shutdown)(struct svc_serv *serv))
+	   void (*shutdown)(struct svc_serv *serv, struct net *net))
 {
 	return __svc_create(prog, bufsize, /*npools*/1, shutdown);
 }
@@ -492,7 +494,7 @@
 
 struct svc_serv *
 svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
-		  void (*shutdown)(struct svc_serv *serv),
+		  void (*shutdown)(struct svc_serv *serv, struct net *net),
 		  svc_thread_fn func, struct module *mod)
 {
 	struct svc_serv *serv;
@@ -509,6 +511,24 @@
 }
 EXPORT_SYMBOL_GPL(svc_create_pooled);
 
+void svc_shutdown_net(struct svc_serv *serv, struct net *net)
+{
+	/*
+	 * The set of xprts (contained in the sv_tempsocks and
+	 * sv_permsocks lists) is now constant, since it is modified
+	 * only by accepting new sockets (done by service threads in
+	 * svc_recv) or aging old ones (done by sv_temptimer), or
+	 * configuration changes (excluded by whatever locking the
+	 * caller is using--nfsd_mutex in the case of nfsd).  So it's
+	 * safe to traverse those lists and shut everything down:
+	 */
+	svc_close_net(serv, net);
+
+	if (serv->sv_shutdown)
+		serv->sv_shutdown(serv, net);
+}
+EXPORT_SYMBOL_GPL(svc_shutdown_net);
+
 /*
  * Destroy an RPC service. Should be called with appropriate locking to
  * protect the sv_nrthreads, sv_permsocks and sv_tempsocks.
@@ -516,6 +536,8 @@
 void
 svc_destroy(struct svc_serv *serv)
 {
+	struct net *net = current->nsproxy->net_ns;
+
 	dprintk("svc: svc_destroy(%s, %d)\n",
 				serv->sv_program->pg_name,
 				serv->sv_nrthreads);
@@ -529,19 +551,15 @@
 		printk("svc_destroy: no threads for serv=%p!\n", serv);
 
 	del_timer_sync(&serv->sv_temptimer);
-	/*
-	 * The set of xprts (contained in the sv_tempsocks and
-	 * sv_permsocks lists) is now constant, since it is modified
-	 * only by accepting new sockets (done by service threads in
-	 * svc_recv) or aging old ones (done by sv_temptimer), or
-	 * configuration changes (excluded by whatever locking the
-	 * caller is using--nfsd_mutex in the case of nfsd).  So it's
-	 * safe to traverse those lists and shut everything down:
-	 */
-	svc_close_all(serv);
 
-	if (serv->sv_shutdown)
-		serv->sv_shutdown(serv);
+	svc_shutdown_net(serv, net);
+
+	/*
+	 * The last user is gone and thus all sockets have to be destroyed to
+	 * the point. Check this.
+	 */
+	BUG_ON(!list_empty(&serv->sv_permsocks));
+	BUG_ON(!list_empty(&serv->sv_tempsocks));
 
 	cache_clean_deferred(serv);
 
@@ -795,7 +813,8 @@
  * Returns zero on success; a negative errno value is returned
  * if any error occurs.
  */
-static int __svc_rpcb_register4(const u32 program, const u32 version,
+static int __svc_rpcb_register4(struct net *net, const u32 program,
+				const u32 version,
 				const unsigned short protocol,
 				const unsigned short port)
 {
@@ -818,7 +837,7 @@
 		return -ENOPROTOOPT;
 	}
 
-	error = rpcb_v4_register(program, version,
+	error = rpcb_v4_register(net, program, version,
 					(const struct sockaddr *)&sin, netid);
 
 	/*
@@ -826,7 +845,7 @@
 	 * registration request with the legacy rpcbind v2 protocol.
 	 */
 	if (error == -EPROTONOSUPPORT)
-		error = rpcb_register(program, version, protocol, port);
+		error = rpcb_register(net, program, version, protocol, port);
 
 	return error;
 }
@@ -842,7 +861,8 @@
  * Returns zero on success; a negative errno value is returned
  * if any error occurs.
  */
-static int __svc_rpcb_register6(const u32 program, const u32 version,
+static int __svc_rpcb_register6(struct net *net, const u32 program,
+				const u32 version,
 				const unsigned short protocol,
 				const unsigned short port)
 {
@@ -865,7 +885,7 @@
 		return -ENOPROTOOPT;
 	}
 
-	error = rpcb_v4_register(program, version,
+	error = rpcb_v4_register(net, program, version,
 					(const struct sockaddr *)&sin6, netid);
 
 	/*
@@ -885,7 +905,7 @@
  * Returns zero on success; a negative errno value is returned
  * if any error occurs.
  */
-static int __svc_register(const char *progname,
+static int __svc_register(struct net *net, const char *progname,
 			  const u32 program, const u32 version,
 			  const int family,
 			  const unsigned short protocol,
@@ -895,12 +915,12 @@
 
 	switch (family) {
 	case PF_INET:
-		error = __svc_rpcb_register4(program, version,
+		error = __svc_rpcb_register4(net, program, version,
 						protocol, port);
 		break;
 #if IS_ENABLED(CONFIG_IPV6)
 	case PF_INET6:
-		error = __svc_rpcb_register6(program, version,
+		error = __svc_rpcb_register6(net, program, version,
 						protocol, port);
 #endif
 	}
@@ -914,14 +934,16 @@
 /**
  * svc_register - register an RPC service with the local portmapper
  * @serv: svc_serv struct for the service to register
+ * @net: net namespace for the service to register
  * @family: protocol family of service's listener socket
  * @proto: transport protocol number to advertise
  * @port: port to advertise
  *
  * Service is registered for any address in the passed-in protocol family
  */
-int svc_register(const struct svc_serv *serv, const int family,
-		 const unsigned short proto, const unsigned short port)
+int svc_register(const struct svc_serv *serv, struct net *net,
+		 const int family, const unsigned short proto,
+		 const unsigned short port)
 {
 	struct svc_program	*progp;
 	unsigned int		i;
@@ -946,7 +968,7 @@
 			if (progp->pg_vers[i]->vs_hidden)
 				continue;
 
-			error = __svc_register(progp->pg_name, progp->pg_prog,
+			error = __svc_register(net, progp->pg_name, progp->pg_prog,
 						i, family, proto, port);
 			if (error < 0)
 				break;
@@ -963,19 +985,19 @@
  * any "inet6" entries anyway.  So a PMAP_UNSET should be sufficient
  * in this case to clear all existing entries for [program, version].
  */
-static void __svc_unregister(const u32 program, const u32 version,
+static void __svc_unregister(struct net *net, const u32 program, const u32 version,
 			     const char *progname)
 {
 	int error;
 
-	error = rpcb_v4_register(program, version, NULL, "");
+	error = rpcb_v4_register(net, program, version, NULL, "");
 
 	/*
 	 * User space didn't support rpcbind v4, so retry this
 	 * request with the legacy rpcbind v2 protocol.
 	 */
 	if (error == -EPROTONOSUPPORT)
-		error = rpcb_register(program, version, 0, 0);
+		error = rpcb_register(net, program, version, 0, 0);
 
 	dprintk("svc: %s(%sv%u), error %d\n",
 			__func__, progname, version, error);
@@ -989,7 +1011,7 @@
  * The result of unregistration is reported via dprintk for those who want
  * verification of the result, but is otherwise not important.
  */
-static void svc_unregister(const struct svc_serv *serv)
+static void svc_unregister(const struct svc_serv *serv, struct net *net)
 {
 	struct svc_program *progp;
 	unsigned long flags;
@@ -1006,7 +1028,7 @@
 
 			dprintk("svc: attempting to unregister %sv%u\n",
 				progp->pg_name, i);
-			__svc_unregister(progp->pg_prog, i, progp->pg_name);
+			__svc_unregister(net, progp->pg_prog, i, progp->pg_name);
 		}
 	}
 
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 74cb0d8..4bda09d 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -922,48 +922,65 @@
 }
 EXPORT_SYMBOL_GPL(svc_close_xprt);
 
-static void svc_close_list(struct list_head *xprt_list)
+static void svc_close_list(struct list_head *xprt_list, struct net *net)
 {
 	struct svc_xprt *xprt;
 
 	list_for_each_entry(xprt, xprt_list, xpt_list) {
+		if (xprt->xpt_net != net)
+			continue;
 		set_bit(XPT_CLOSE, &xprt->xpt_flags);
 		set_bit(XPT_BUSY, &xprt->xpt_flags);
 	}
 }
 
-void svc_close_all(struct svc_serv *serv)
+static void svc_clear_pools(struct svc_serv *serv, struct net *net)
 {
 	struct svc_pool *pool;
 	struct svc_xprt *xprt;
 	struct svc_xprt *tmp;
 	int i;
 
-	svc_close_list(&serv->sv_tempsocks);
-	svc_close_list(&serv->sv_permsocks);
-
 	for (i = 0; i < serv->sv_nrpools; i++) {
 		pool = &serv->sv_pools[i];
 
 		spin_lock_bh(&pool->sp_lock);
-		while (!list_empty(&pool->sp_sockets)) {
-			xprt = list_first_entry(&pool->sp_sockets, struct svc_xprt, xpt_ready);
+		list_for_each_entry_safe(xprt, tmp, &pool->sp_sockets, xpt_ready) {
+			if (xprt->xpt_net != net)
+				continue;
 			list_del_init(&xprt->xpt_ready);
 		}
 		spin_unlock_bh(&pool->sp_lock);
 	}
+}
+
+static void svc_clear_list(struct list_head *xprt_list, struct net *net)
+{
+	struct svc_xprt *xprt;
+	struct svc_xprt *tmp;
+
+	list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) {
+		if (xprt->xpt_net != net)
+			continue;
+		svc_delete_xprt(xprt);
+	}
+	list_for_each_entry(xprt, xprt_list, xpt_list)
+		BUG_ON(xprt->xpt_net == net);
+}
+
+void svc_close_net(struct svc_serv *serv, struct net *net)
+{
+	svc_close_list(&serv->sv_tempsocks, net);
+	svc_close_list(&serv->sv_permsocks, net);
+
+	svc_clear_pools(serv, net);
 	/*
 	 * At this point the sp_sockets lists will stay empty, since
 	 * svc_enqueue will not add new entries without taking the
 	 * sp_lock and checking XPT_BUSY.
 	 */
-	list_for_each_entry_safe(xprt, tmp, &serv->sv_tempsocks, xpt_list)
-		svc_delete_xprt(xprt);
-	list_for_each_entry_safe(xprt, tmp, &serv->sv_permsocks, xpt_list)
-		svc_delete_xprt(xprt);
-
-	BUG_ON(!list_empty(&serv->sv_permsocks));
-	BUG_ON(!list_empty(&serv->sv_tempsocks));
+	svc_clear_list(&serv->sv_tempsocks, net);
+	svc_clear_list(&serv->sv_permsocks, net);
 }
 
 /*
@@ -1089,6 +1106,7 @@
  * svc_find_xprt - find an RPC transport instance
  * @serv: pointer to svc_serv to search
  * @xcl_name: C string containing transport's class name
+ * @net: owner net pointer
  * @af: Address family of transport's local address
  * @port: transport's IP port number
  *
@@ -1101,7 +1119,8 @@
  * service's list that has a matching class name.
  */
 struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
-			       const sa_family_t af, const unsigned short port)
+			       struct net *net, const sa_family_t af,
+			       const unsigned short port)
 {
 	struct svc_xprt *xprt;
 	struct svc_xprt *found = NULL;
@@ -1112,6 +1131,8 @@
 
 	spin_lock_bh(&serv->sv_lock);
 	list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
+		if (xprt->xpt_net != net)
+			continue;
 		if (strcmp(xprt->xpt_class->xcl_name, xcl_name))
 			continue;
 		if (af != AF_UNSPEC && af != xprt->xpt_local.ss_family)
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 01153ea..521d8f7 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -211,7 +211,7 @@
 	len = qword_get(&mesg, buf, mlen);
 	if (len <= 0) return -EINVAL;
 
-	if (rpc_pton(buf, len, &address.sa, sizeof(address)) == 0)
+	if (rpc_pton(cd->net, buf, len, &address.sa, sizeof(address)) == 0)
 		return -EINVAL;
 	switch (address.sa.sa_family) {
 	case AF_INET:
@@ -436,7 +436,6 @@
 	uid_t			uid;
 	struct group_info	*gi;
 };
-static struct cache_head	*gid_table[GID_HASHMAX];
 
 static void unix_gid_put(struct kref *kref)
 {
@@ -494,8 +493,7 @@
 	return sunrpc_cache_pipe_upcall(cd, h, unix_gid_request);
 }
 
-static struct unix_gid *unix_gid_lookup(uid_t uid);
-extern struct cache_detail unix_gid_cache;
+static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid);
 
 static int unix_gid_parse(struct cache_detail *cd,
 			char *mesg, int mlen)
@@ -509,7 +507,7 @@
 	time_t expiry;
 	struct unix_gid ug, *ugp;
 
-	if (mlen <= 0 || mesg[mlen-1] != '\n')
+	if (mesg[mlen - 1] != '\n')
 		return -EINVAL;
 	mesg[mlen-1] = 0;
 
@@ -539,19 +537,19 @@
 		GROUP_AT(ug.gi, i) = gid;
 	}
 
-	ugp = unix_gid_lookup(uid);
+	ugp = unix_gid_lookup(cd, uid);
 	if (ugp) {
 		struct cache_head *ch;
 		ug.h.flags = 0;
 		ug.h.expiry_time = expiry;
-		ch = sunrpc_cache_update(&unix_gid_cache,
+		ch = sunrpc_cache_update(cd,
 					 &ug.h, &ugp->h,
 					 hash_long(uid, GID_HASHBITS));
 		if (!ch)
 			err = -ENOMEM;
 		else {
 			err = 0;
-			cache_put(ch, &unix_gid_cache);
+			cache_put(ch, cd);
 		}
 	} else
 		err = -ENOMEM;
@@ -587,10 +585,9 @@
 	return 0;
 }
 
-struct cache_detail unix_gid_cache = {
+static struct cache_detail unix_gid_cache_template = {
 	.owner		= THIS_MODULE,
 	.hash_size	= GID_HASHMAX,
-	.hash_table	= gid_table,
 	.name		= "auth.unix.gid",
 	.cache_put	= unix_gid_put,
 	.cache_upcall	= unix_gid_upcall,
@@ -602,14 +599,42 @@
 	.alloc		= unix_gid_alloc,
 };
 
-static struct unix_gid *unix_gid_lookup(uid_t uid)
+int unix_gid_cache_create(struct net *net)
+{
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+	struct cache_detail *cd;
+	int err;
+
+	cd = cache_create_net(&unix_gid_cache_template, net);
+	if (IS_ERR(cd))
+		return PTR_ERR(cd);
+	err = cache_register_net(cd, net);
+	if (err) {
+		cache_destroy_net(cd, net);
+		return err;
+	}
+	sn->unix_gid_cache = cd;
+	return 0;
+}
+
+void unix_gid_cache_destroy(struct net *net)
+{
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+	struct cache_detail *cd = sn->unix_gid_cache;
+
+	sn->unix_gid_cache = NULL;
+	cache_purge(cd);
+	cache_unregister_net(cd, net);
+	cache_destroy_net(cd, net);
+}
+
+static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid)
 {
 	struct unix_gid ug;
 	struct cache_head *ch;
 
 	ug.uid = uid;
-	ch = sunrpc_cache_lookup(&unix_gid_cache, &ug.h,
-				 hash_long(uid, GID_HASHBITS));
+	ch = sunrpc_cache_lookup(cd, &ug.h, hash_long(uid, GID_HASHBITS));
 	if (ch)
 		return container_of(ch, struct unix_gid, h);
 	else
@@ -621,11 +646,13 @@
 	struct unix_gid *ug;
 	struct group_info *gi;
 	int ret;
+	struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net,
+					    sunrpc_net_id);
 
-	ug = unix_gid_lookup(uid);
+	ug = unix_gid_lookup(sn->unix_gid_cache, uid);
 	if (!ug)
 		return ERR_PTR(-EAGAIN);
-	ret = cache_check(&unix_gid_cache, &ug->h, &rqstp->rq_chandle);
+	ret = cache_check(sn->unix_gid_cache, &ug->h, &rqstp->rq_chandle);
 	switch (ret) {
 	case -ENOENT:
 		return ERR_PTR(-ENOENT);
@@ -633,7 +660,7 @@
 		return ERR_PTR(-ESHUTDOWN);
 	case 0:
 		gi = get_group_info(ug->gi);
-		cache_put(&ug->h, &unix_gid_cache);
+		cache_put(&ug->h, sn->unix_gid_cache);
 		return gi;
 	default:
 		return ERR_PTR(-EAGAIN);
@@ -849,56 +876,45 @@
 	.set_client	= svcauth_unix_set_client,
 };
 
+static struct cache_detail ip_map_cache_template = {
+	.owner		= THIS_MODULE,
+	.hash_size	= IP_HASHMAX,
+	.name		= "auth.unix.ip",
+	.cache_put	= ip_map_put,
+	.cache_upcall	= ip_map_upcall,
+	.cache_parse	= ip_map_parse,
+	.cache_show	= ip_map_show,
+	.match		= ip_map_match,
+	.init		= ip_map_init,
+	.update		= update,
+	.alloc		= ip_map_alloc,
+};
+
 int ip_map_cache_create(struct net *net)
 {
-	int err = -ENOMEM;
-	struct cache_detail *cd;
-	struct cache_head **tbl;
 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+	struct cache_detail *cd;
+	int err;
 
-	cd = kzalloc(sizeof(struct cache_detail), GFP_KERNEL);
-	if (cd == NULL)
-		goto err_cd;
-
-	tbl = kzalloc(IP_HASHMAX * sizeof(struct cache_head *), GFP_KERNEL);
-	if (tbl == NULL)
-		goto err_tbl;
-
-	cd->owner = THIS_MODULE,
-	cd->hash_size = IP_HASHMAX,
-	cd->hash_table = tbl,
-	cd->name = "auth.unix.ip",
-	cd->cache_put = ip_map_put,
-	cd->cache_upcall = ip_map_upcall,
-	cd->cache_parse = ip_map_parse,
-	cd->cache_show = ip_map_show,
-	cd->match = ip_map_match,
-	cd->init = ip_map_init,
-	cd->update = update,
-	cd->alloc = ip_map_alloc,
-
+	cd = cache_create_net(&ip_map_cache_template, net);
+	if (IS_ERR(cd))
+		return PTR_ERR(cd);
 	err = cache_register_net(cd, net);
-	if (err)
-		goto err_reg;
-
+	if (err) {
+		cache_destroy_net(cd, net);
+		return err;
+	}
 	sn->ip_map_cache = cd;
 	return 0;
-
-err_reg:
-	kfree(tbl);
-err_tbl:
-	kfree(cd);
-err_cd:
-	return err;
 }
 
 void ip_map_cache_destroy(struct net *net)
 {
-	struct sunrpc_net *sn;
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+	struct cache_detail *cd = sn->ip_map_cache;
 
-	sn = net_generic(net, sunrpc_net_id);
-	cache_purge(sn->ip_map_cache);
-	cache_unregister_net(sn->ip_map_cache, net);
-	kfree(sn->ip_map_cache->hash_table);
-	kfree(sn->ip_map_cache);
+	sn->ip_map_cache = NULL;
+	cache_purge(cd);
+	cache_unregister_net(cd, net);
+	cache_destroy_net(cd, net);
 }
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 4645709..824d32f 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -396,7 +396,7 @@
 				int buflen, unsigned int base)
 {
 	size_t save_iovlen;
-	void __user *save_iovbase;
+	void *save_iovbase;
 	unsigned int i;
 	int ret;
 
@@ -1381,8 +1381,6 @@
 	spin_lock_bh(&serv->sv_lock);
 	list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list)
 		set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
-	list_for_each_entry(svsk, &serv->sv_tempsocks, sk_xprt.xpt_list)
-		set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
 	spin_unlock_bh(&serv->sv_lock);
 }
 EXPORT_SYMBOL_GPL(svc_sock_update_bufs);
@@ -1409,7 +1407,8 @@
 
 	/* Register socket with portmapper */
 	if (*errp >= 0 && pmap_register)
-		*errp = svc_register(serv, inet->sk_family, inet->sk_protocol,
+		*errp = svc_register(serv, sock_net(sock->sk), inet->sk_family,
+				     inet->sk_protocol,
 				     ntohs(inet_sk(inet)->inet_sport));
 
 	if (*errp < 0) {
diff --git a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c
index e65dcc6..af7d339 100644
--- a/net/sunrpc/sysctl.c
+++ b/net/sunrpc/sysctl.c
@@ -20,6 +20,8 @@
 #include <linux/sunrpc/stats.h>
 #include <linux/sunrpc/svc_xprt.h>
 
+#include "netns.h"
+
 /*
  * Declare the debug flags here
  */
@@ -110,7 +112,7 @@
 		*(unsigned int *) table->data = value;
 		/* Display the RPC tasks on writing to rpc_debug */
 		if (strcmp(table->procname, "rpc_debug") == 0)
-			rpc_show_tasks();
+			rpc_show_tasks(&init_net);
 	} else {
 		if (!access_ok(VERIFY_WRITE, buffer, left))
 			return -EFAULT;
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index c64c0ef..0cbcd1a 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -66,6 +66,7 @@
 static void	xprt_request_init(struct rpc_task *, struct rpc_xprt *);
 static void	xprt_connect_status(struct rpc_task *task);
 static int      __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
+static void	 xprt_destroy(struct rpc_xprt *xprt);
 
 static DEFINE_SPINLOCK(xprt_list_lock);
 static LIST_HEAD(xprt_list);
@@ -292,54 +293,57 @@
 	return retval;
 }
 
-static void __xprt_lock_write_next(struct rpc_xprt *xprt)
+static bool __xprt_lock_write_func(struct rpc_task *task, void *data)
 {
-	struct rpc_task *task;
+	struct rpc_xprt *xprt = data;
 	struct rpc_rqst *req;
 
-	if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
-		return;
-
-	task = rpc_wake_up_next(&xprt->sending);
-	if (task == NULL)
-		goto out_unlock;
-
 	req = task->tk_rqstp;
 	xprt->snd_task = task;
 	if (req) {
 		req->rq_bytes_sent = 0;
 		req->rq_ntrans++;
 	}
-	return;
+	return true;
+}
 
-out_unlock:
+static void __xprt_lock_write_next(struct rpc_xprt *xprt)
+{
+	if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
+		return;
+
+	if (rpc_wake_up_first(&xprt->sending, __xprt_lock_write_func, xprt))
+		return;
 	xprt_clear_locked(xprt);
 }
 
-static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
+static bool __xprt_lock_write_cong_func(struct rpc_task *task, void *data)
 {
-	struct rpc_task *task;
+	struct rpc_xprt *xprt = data;
 	struct rpc_rqst *req;
 
-	if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
-		return;
-	if (RPCXPRT_CONGESTED(xprt))
-		goto out_unlock;
-	task = rpc_wake_up_next(&xprt->sending);
-	if (task == NULL)
-		goto out_unlock;
-
 	req = task->tk_rqstp;
 	if (req == NULL) {
 		xprt->snd_task = task;
-		return;
+		return true;
 	}
 	if (__xprt_get_cong(xprt, task)) {
 		xprt->snd_task = task;
 		req->rq_bytes_sent = 0;
 		req->rq_ntrans++;
-		return;
+		return true;
 	}
+	return false;
+}
+
+static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
+{
+	if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
+		return;
+	if (RPCXPRT_CONGESTED(xprt))
+		goto out_unlock;
+	if (rpc_wake_up_first(&xprt->sending, __xprt_lock_write_cong_func, xprt))
+		return;
 out_unlock:
 	xprt_clear_locked(xprt);
 }
@@ -712,9 +716,7 @@
 	if (xprt_connected(xprt))
 		xprt_release_write(xprt, task);
 	else {
-		if (task->tk_rqstp)
-			task->tk_rqstp->rq_bytes_sent = 0;
-
+		task->tk_rqstp->rq_bytes_sent = 0;
 		task->tk_timeout = task->tk_rqstp->rq_timeout;
 		rpc_sleep_on(&xprt->pending, task, xprt_connect_status);
 
@@ -750,7 +752,7 @@
 	default:
 		dprintk("RPC: %5u xprt_connect_status: error %d connecting to "
 				"server %s\n", task->tk_pid, -task->tk_status,
-				task->tk_client->cl_server);
+				xprt->servername);
 		xprt_release_write(xprt, task);
 		task->tk_status = -EIO;
 	}
@@ -884,7 +886,7 @@
 {
 	struct rpc_rqst	*req = task->tk_rqstp;
 	struct rpc_xprt	*xprt = req->rq_xprt;
-	int status;
+	int status, numreqs;
 
 	dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen);
 
@@ -921,9 +923,14 @@
 
 	xprt->ops->set_retrans_timeout(task);
 
+	numreqs = atomic_read(&xprt->num_reqs);
+	if (numreqs > xprt->stat.max_slots)
+		xprt->stat.max_slots = numreqs;
 	xprt->stat.sends++;
 	xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs;
 	xprt->stat.bklog_u += xprt->backlog.qlen;
+	xprt->stat.sending_u += xprt->sending.qlen;
+	xprt->stat.pending_u += xprt->pending.qlen;
 
 	/* Don't race with disconnect */
 	if (!xprt_connected(xprt))
@@ -1131,7 +1138,10 @@
 		return;
 
 	xprt = req->rq_xprt;
-	rpc_count_iostats(task);
+	if (task->tk_ops->rpc_count_stats != NULL)
+		task->tk_ops->rpc_count_stats(task, task->tk_calldata);
+	else if (task->tk_client)
+		rpc_count_iostats(task, task->tk_client->cl_metrics);
 	spin_lock_bh(&xprt->transport_lock);
 	xprt->ops->release_xprt(xprt, task);
 	if (xprt->ops->release_request)
@@ -1220,6 +1230,17 @@
 			    (unsigned long)xprt);
 	else
 		init_timer(&xprt->timer);
+
+	if (strlen(args->servername) > RPC_MAXNETNAMELEN) {
+		xprt_destroy(xprt);
+		return ERR_PTR(-EINVAL);
+	}
+	xprt->servername = kstrdup(args->servername, GFP_KERNEL);
+	if (xprt->servername == NULL) {
+		xprt_destroy(xprt);
+		return ERR_PTR(-ENOMEM);
+	}
+
 	dprintk("RPC:       created transport %p with %u slots\n", xprt,
 			xprt->max_reqs);
 out:
@@ -1242,6 +1263,7 @@
 	rpc_destroy_wait_queue(&xprt->sending);
 	rpc_destroy_wait_queue(&xprt->backlog);
 	cancel_work_sync(&xprt->task_cleanup);
+	kfree(xprt->servername);
 	/*
 	 * Tear down transport state and free the rpc_xprt
 	 */
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c
index 1776e57..558fbab 100644
--- a/net/sunrpc/xprtrdma/rpc_rdma.c
+++ b/net/sunrpc/xprtrdma/rpc_rdma.c
@@ -771,13 +771,18 @@
 
 	/* get request object */
 	req = rpcr_to_rdmar(rqst);
+	if (req->rl_reply) {
+		spin_unlock(&xprt->transport_lock);
+		dprintk("RPC:       %s: duplicate reply 0x%p to RPC "
+			"request 0x%p: xid 0x%08x\n", __func__, rep, req,
+			headerp->rm_xid);
+		goto repost;
+	}
 
 	dprintk("RPC:       %s: reply 0x%p completes request 0x%p\n"
 		"                   RPC request 0x%p xid 0x%08x\n",
 			__func__, rep, req, rqst, headerp->rm_xid);
 
-	BUG_ON(!req || req->rl_reply);
-
 	/* from here on, the reply is no longer an orphan */
 	req->rl_reply = rep;
 
diff --git a/net/sunrpc/xprtrdma/svc_rdma.c b/net/sunrpc/xprtrdma/svc_rdma.c
index 09af4fa..8343737 100644
--- a/net/sunrpc/xprtrdma/svc_rdma.c
+++ b/net/sunrpc/xprtrdma/svc_rdma.c
@@ -47,6 +47,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/sched.h>
 #include <linux/sunrpc/svc_rdma.h>
+#include "xprt_rdma.h"
 
 #define RPCDBG_FACILITY	RPCDBG_SVCXPRT
 
diff --git a/net/sunrpc/xprtrdma/svc_rdma_marshal.c b/net/sunrpc/xprtrdma/svc_rdma_marshal.c
index 9530ef2..8d2eddd 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_marshal.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_marshal.c
@@ -60,21 +60,11 @@
 	struct rpcrdma_read_chunk *ch = (struct rpcrdma_read_chunk *)va;
 
 	while (ch->rc_discrim != xdr_zero) {
-		u64 ch_offset;
-
 		if (((unsigned long)ch + sizeof(struct rpcrdma_read_chunk)) >
 		    (unsigned long)vaend) {
 			dprintk("svcrdma: vaend=%p, ch=%p\n", vaend, ch);
 			return NULL;
 		}
-
-		ch->rc_discrim = ntohl(ch->rc_discrim);
-		ch->rc_position = ntohl(ch->rc_position);
-		ch->rc_target.rs_handle = ntohl(ch->rc_target.rs_handle);
-		ch->rc_target.rs_length = ntohl(ch->rc_target.rs_length);
-		va = (u32 *)&ch->rc_target.rs_offset;
-		xdr_decode_hyper(va, &ch_offset);
-		put_unaligned(ch_offset, (u64 *)va);
 		ch++;
 	}
 	return (u32 *)&ch->rc_position;
@@ -91,7 +81,7 @@
 	*byte_count = 0;
 	*ch_count = 0;
 	for (; ch->rc_discrim != 0; ch++) {
-		*byte_count = *byte_count + ch->rc_target.rs_length;
+		*byte_count = *byte_count + ntohl(ch->rc_target.rs_length);
 		*ch_count = *ch_count + 1;
 	}
 }
@@ -108,7 +98,8 @@
  */
 static u32 *decode_write_list(u32 *va, u32 *vaend)
 {
-	int ch_no;
+	int nchunks;
+
 	struct rpcrdma_write_array *ary =
 		(struct rpcrdma_write_array *)va;
 
@@ -121,37 +112,24 @@
 		dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
 		return NULL;
 	}
-	ary->wc_discrim = ntohl(ary->wc_discrim);
-	ary->wc_nchunks = ntohl(ary->wc_nchunks);
+	nchunks = ntohl(ary->wc_nchunks);
 	if (((unsigned long)&ary->wc_array[0] +
-	     (sizeof(struct rpcrdma_write_chunk) * ary->wc_nchunks)) >
+	     (sizeof(struct rpcrdma_write_chunk) * nchunks)) >
 	    (unsigned long)vaend) {
 		dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
-			ary, ary->wc_nchunks, vaend);
+			ary, nchunks, vaend);
 		return NULL;
 	}
-	for (ch_no = 0; ch_no < ary->wc_nchunks; ch_no++) {
-		u64 ch_offset;
-
-		ary->wc_array[ch_no].wc_target.rs_handle =
-			ntohl(ary->wc_array[ch_no].wc_target.rs_handle);
-		ary->wc_array[ch_no].wc_target.rs_length =
-			ntohl(ary->wc_array[ch_no].wc_target.rs_length);
-		va = (u32 *)&ary->wc_array[ch_no].wc_target.rs_offset;
-		xdr_decode_hyper(va, &ch_offset);
-		put_unaligned(ch_offset, (u64 *)va);
-	}
-
 	/*
 	 * rs_length is the 2nd 4B field in wc_target and taking its
 	 * address skips the list terminator
 	 */
-	return (u32 *)&ary->wc_array[ch_no].wc_target.rs_length;
+	return (u32 *)&ary->wc_array[nchunks].wc_target.rs_length;
 }
 
 static u32 *decode_reply_array(u32 *va, u32 *vaend)
 {
-	int ch_no;
+	int nchunks;
 	struct rpcrdma_write_array *ary =
 		(struct rpcrdma_write_array *)va;
 
@@ -164,28 +142,15 @@
 		dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
 		return NULL;
 	}
-	ary->wc_discrim = ntohl(ary->wc_discrim);
-	ary->wc_nchunks = ntohl(ary->wc_nchunks);
+	nchunks = ntohl(ary->wc_nchunks);
 	if (((unsigned long)&ary->wc_array[0] +
-	     (sizeof(struct rpcrdma_write_chunk) * ary->wc_nchunks)) >
+	     (sizeof(struct rpcrdma_write_chunk) * nchunks)) >
 	    (unsigned long)vaend) {
 		dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
-			ary, ary->wc_nchunks, vaend);
+			ary, nchunks, vaend);
 		return NULL;
 	}
-	for (ch_no = 0; ch_no < ary->wc_nchunks; ch_no++) {
-		u64 ch_offset;
-
-		ary->wc_array[ch_no].wc_target.rs_handle =
-			ntohl(ary->wc_array[ch_no].wc_target.rs_handle);
-		ary->wc_array[ch_no].wc_target.rs_length =
-			ntohl(ary->wc_array[ch_no].wc_target.rs_length);
-		va = (u32 *)&ary->wc_array[ch_no].wc_target.rs_offset;
-		xdr_decode_hyper(va, &ch_offset);
-		put_unaligned(ch_offset, (u64 *)va);
-	}
-
-	return (u32 *)&ary->wc_array[ch_no];
+	return (u32 *)&ary->wc_array[nchunks];
 }
 
 int svc_rdma_xdr_decode_req(struct rpcrdma_msg **rdma_req,
@@ -386,13 +351,14 @@
 
 void svc_rdma_xdr_encode_array_chunk(struct rpcrdma_write_array *ary,
 				     int chunk_no,
-				     u32 rs_handle, u64 rs_offset,
+				     __be32 rs_handle,
+				     __be64 rs_offset,
 				     u32 write_len)
 {
 	struct rpcrdma_segment *seg = &ary->wc_array[chunk_no].wc_target;
-	seg->rs_handle = htonl(rs_handle);
+	seg->rs_handle = rs_handle;
+	seg->rs_offset = rs_offset;
 	seg->rs_length = htonl(write_len);
-	xdr_encode_hyper((u32 *) &seg->rs_offset, rs_offset);
 }
 
 void svc_rdma_xdr_encode_reply_header(struct svcxprt_rdma *xprt,
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
index df67211..41cb63b 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
@@ -147,7 +147,7 @@
 	page_off = 0;
 	ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
 	ch_no = 0;
-	ch_bytes = ch->rc_target.rs_length;
+	ch_bytes = ntohl(ch->rc_target.rs_length);
 	head->arg.head[0] = rqstp->rq_arg.head[0];
 	head->arg.tail[0] = rqstp->rq_arg.tail[0];
 	head->arg.pages = &head->pages[head->count];
@@ -183,7 +183,7 @@
 			ch_no++;
 			ch++;
 			chl_map->ch[ch_no].start = sge_no;
-			ch_bytes = ch->rc_target.rs_length;
+			ch_bytes = ntohl(ch->rc_target.rs_length);
 			/* If bytes remaining account for next chunk */
 			if (byte_count) {
 				head->arg.page_len += ch_bytes;
@@ -281,11 +281,12 @@
 	offset = 0;
 	ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
 	for (ch_no = 0; ch_no < ch_count; ch_no++) {
+		int len = ntohl(ch->rc_target.rs_length);
 		rpl_map->sge[ch_no].iov_base = frmr->kva + offset;
-		rpl_map->sge[ch_no].iov_len = ch->rc_target.rs_length;
+		rpl_map->sge[ch_no].iov_len = len;
 		chl_map->ch[ch_no].count = 1;
 		chl_map->ch[ch_no].start = ch_no;
-		offset += ch->rc_target.rs_length;
+		offset += len;
 		ch++;
 	}
 
@@ -316,7 +317,7 @@
 	for (i = 0; i < count; i++) {
 		ctxt->sge[i].length = 0; /* in case map fails */
 		if (!frmr) {
-			BUG_ON(0 == virt_to_page(vec[i].iov_base));
+			BUG_ON(!virt_to_page(vec[i].iov_base));
 			off = (unsigned long)vec[i].iov_base & ~PAGE_MASK;
 			ctxt->sge[i].addr =
 				ib_dma_map_page(xprt->sc_cm_id->device,
@@ -426,6 +427,7 @@
 
 	for (ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
 	     ch->rc_discrim != 0; ch++, ch_no++) {
+		u64 rs_offset;
 next_sge:
 		ctxt = svc_rdma_get_context(xprt);
 		ctxt->direction = DMA_FROM_DEVICE;
@@ -440,10 +442,10 @@
 		read_wr.opcode = IB_WR_RDMA_READ;
 		ctxt->wr_op = read_wr.opcode;
 		read_wr.send_flags = IB_SEND_SIGNALED;
-		read_wr.wr.rdma.rkey = ch->rc_target.rs_handle;
-		read_wr.wr.rdma.remote_addr =
-			get_unaligned(&(ch->rc_target.rs_offset)) +
-			sgl_offset;
+		read_wr.wr.rdma.rkey = ntohl(ch->rc_target.rs_handle);
+		xdr_decode_hyper((__be32 *)&ch->rc_target.rs_offset,
+				 &rs_offset);
+		read_wr.wr.rdma.remote_addr = rs_offset + sgl_offset;
 		read_wr.sg_list = ctxt->sge;
 		read_wr.num_sge =
 			rdma_read_max_sge(xprt, chl_map->ch[ch_no].count);
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
index 249a835..42eb7ba 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
@@ -409,21 +409,21 @@
 		u64 rs_offset;
 
 		arg_ch = &arg_ary->wc_array[chunk_no].wc_target;
-		write_len = min(xfer_len, arg_ch->rs_length);
+		write_len = min(xfer_len, ntohl(arg_ch->rs_length));
 
 		/* Prepare the response chunk given the length actually
 		 * written */
-		rs_offset = get_unaligned(&(arg_ch->rs_offset));
+		xdr_decode_hyper((__be32 *)&arg_ch->rs_offset, &rs_offset);
 		svc_rdma_xdr_encode_array_chunk(res_ary, chunk_no,
-					    arg_ch->rs_handle,
-					    rs_offset,
-					    write_len);
+						arg_ch->rs_handle,
+						arg_ch->rs_offset,
+						write_len);
 		chunk_off = 0;
 		while (write_len) {
 			int this_write;
 			this_write = min(write_len, max_write);
 			ret = send_write(xprt, rqstp,
-					 arg_ch->rs_handle,
+					 ntohl(arg_ch->rs_handle),
 					 rs_offset + chunk_off,
 					 xdr_off,
 					 this_write,
@@ -457,6 +457,7 @@
 	u32 xdr_off;
 	int chunk_no;
 	int chunk_off;
+	int nchunks;
 	struct rpcrdma_segment *ch;
 	struct rpcrdma_write_array *arg_ary;
 	struct rpcrdma_write_array *res_ary;
@@ -476,26 +477,27 @@
 		max_write = xprt->sc_max_sge * PAGE_SIZE;
 
 	/* xdr offset starts at RPC message */
+	nchunks = ntohl(arg_ary->wc_nchunks);
 	for (xdr_off = 0, chunk_no = 0;
-	     xfer_len && chunk_no < arg_ary->wc_nchunks;
+	     xfer_len && chunk_no < nchunks;
 	     chunk_no++) {
 		u64 rs_offset;
 		ch = &arg_ary->wc_array[chunk_no].wc_target;
-		write_len = min(xfer_len, ch->rs_length);
+		write_len = min(xfer_len, htonl(ch->rs_length));
 
 		/* Prepare the reply chunk given the length actually
 		 * written */
-		rs_offset = get_unaligned(&(ch->rs_offset));
+		xdr_decode_hyper((__be32 *)&ch->rs_offset, &rs_offset);
 		svc_rdma_xdr_encode_array_chunk(res_ary, chunk_no,
-					    ch->rs_handle, rs_offset,
-					    write_len);
+						ch->rs_handle, ch->rs_offset,
+						write_len);
 		chunk_off = 0;
 		while (write_len) {
 			int this_write;
 
 			this_write = min(write_len, max_write);
 			ret = send_write(xprt, rqstp,
-					 ch->rs_handle,
+					 ntohl(ch->rs_handle),
 					 rs_offset + chunk_off,
 					 xdr_off,
 					 this_write,
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index 894cb42..73b428b 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -51,6 +51,7 @@
 #include <rdma/rdma_cm.h>
 #include <linux/sunrpc/svc_rdma.h>
 #include <linux/export.h>
+#include "xprt_rdma.h"
 
 #define RPCDBG_FACILITY	RPCDBG_SVCXPRT
 
@@ -90,12 +91,6 @@
 	.xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP,
 };
 
-/* WR context cache. Created in svc_rdma.c  */
-extern struct kmem_cache *svc_rdma_ctxt_cachep;
-
-/* Workqueue created in svc_rdma.c */
-extern struct workqueue_struct *svc_rdma_wq;
-
 struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
 {
 	struct svc_rdma_op_ctxt *ctxt;
@@ -150,9 +145,6 @@
 	atomic_dec(&xprt->sc_ctxt_used);
 }
 
-/* Temporary NFS request map cache. Created in svc_rdma.c  */
-extern struct kmem_cache *svc_rdma_map_cachep;
-
 /*
  * Temporary NFS req mappings are shared across all transport
  * instances. These are short lived and should be bounded by the number
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
index 28236ba..745973b 100644
--- a/net/sunrpc/xprtrdma/verbs.c
+++ b/net/sunrpc/xprtrdma/verbs.c
@@ -1490,6 +1490,9 @@
 	u8 key;
 	int len, pageoff;
 	int i, rc;
+	int seg_len;
+	u64 pa;
+	int page_no;
 
 	pageoff = offset_in_page(seg1->mr_offset);
 	seg1->mr_offset -= pageoff;	/* start of page */
@@ -1497,11 +1500,15 @@
 	len = -pageoff;
 	if (*nsegs > RPCRDMA_MAX_DATA_SEGS)
 		*nsegs = RPCRDMA_MAX_DATA_SEGS;
-	for (i = 0; i < *nsegs;) {
+	for (page_no = i = 0; i < *nsegs;) {
 		rpcrdma_map_one(ia, seg, writing);
-		seg1->mr_chunk.rl_mw->r.frmr.fr_pgl->page_list[i] = seg->mr_dma;
+		pa = seg->mr_dma;
+		for (seg_len = seg->mr_len; seg_len > 0; seg_len -= PAGE_SIZE) {
+			seg1->mr_chunk.rl_mw->r.frmr.fr_pgl->
+				page_list[page_no++] = pa;
+			pa += PAGE_SIZE;
+		}
 		len += seg->mr_len;
-		BUG_ON(seg->mr_len > PAGE_SIZE);
 		++seg;
 		++i;
 		/* Check for holes */
@@ -1540,9 +1547,9 @@
 	frmr_wr.send_flags = IB_SEND_SIGNALED;
 	frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma;
 	frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl;
-	frmr_wr.wr.fast_reg.page_list_len = i;
+	frmr_wr.wr.fast_reg.page_list_len = page_no;
 	frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
-	frmr_wr.wr.fast_reg.length = i << PAGE_SHIFT;
+	frmr_wr.wr.fast_reg.length = page_no << PAGE_SHIFT;
 	BUG_ON(frmr_wr.wr.fast_reg.length < len);
 	frmr_wr.wr.fast_reg.access_flags = (writing ?
 				IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h
index 08c5d5a..9a66c95 100644
--- a/net/sunrpc/xprtrdma/xprt_rdma.h
+++ b/net/sunrpc/xprtrdma/xprt_rdma.h
@@ -343,4 +343,11 @@
  */
 int rpcrdma_marshal_req(struct rpc_rqst *);
 
+/* Temporary NFS request map cache. Created in svc_rdma.c  */
+extern struct kmem_cache *svc_rdma_map_cachep;
+/* WR context cache. Created in svc_rdma.c  */
+extern struct kmem_cache *svc_rdma_ctxt_cachep;
+/* Workqueue created in svc_rdma.c */
+extern struct workqueue_struct *svc_rdma_wq;
+
 #endif				/* _LINUX_SUNRPC_XPRT_RDMA_H */
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 55472c4..890b03f 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -53,12 +53,12 @@
 /*
  * xprtsock tunables
  */
-unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE;
-unsigned int xprt_tcp_slot_table_entries = RPC_MIN_SLOT_TABLE;
-unsigned int xprt_max_tcp_slot_table_entries = RPC_MAX_SLOT_TABLE;
+static unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE;
+static unsigned int xprt_tcp_slot_table_entries = RPC_MIN_SLOT_TABLE;
+static unsigned int xprt_max_tcp_slot_table_entries = RPC_MAX_SLOT_TABLE;
 
-unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT;
-unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT;
+static unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT;
+static unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT;
 
 #define XS_TCP_LINGER_TO	(15U * HZ)
 static unsigned int xs_tcp_fin_timeout __read_mostly = XS_TCP_LINGER_TO;
@@ -2227,7 +2227,7 @@
 		idle_time = (long)(jiffies - xprt->last_used) / HZ;
 
 	seq_printf(seq, "\txprt:\tlocal %lu %lu %lu %ld %lu %lu %lu "
-			"%llu %llu\n",
+			"%llu %llu %lu %llu %llu\n",
 			xprt->stat.bind_count,
 			xprt->stat.connect_count,
 			xprt->stat.connect_time,
@@ -2236,7 +2236,10 @@
 			xprt->stat.recvs,
 			xprt->stat.bad_xids,
 			xprt->stat.req_u,
-			xprt->stat.bklog_u);
+			xprt->stat.bklog_u,
+			xprt->stat.max_slots,
+			xprt->stat.sending_u,
+			xprt->stat.pending_u);
 }
 
 /**
@@ -2249,14 +2252,18 @@
 {
 	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
 
-	seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %Lu %Lu\n",
+	seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %llu %llu "
+			"%lu %llu %llu\n",
 			transport->srcport,
 			xprt->stat.bind_count,
 			xprt->stat.sends,
 			xprt->stat.recvs,
 			xprt->stat.bad_xids,
 			xprt->stat.req_u,
-			xprt->stat.bklog_u);
+			xprt->stat.bklog_u,
+			xprt->stat.max_slots,
+			xprt->stat.sending_u,
+			xprt->stat.pending_u);
 }
 
 /**
@@ -2273,7 +2280,8 @@
 	if (xprt_connected(xprt))
 		idle_time = (long)(jiffies - xprt->last_used) / HZ;
 
-	seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu %Lu %Lu\n",
+	seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu "
+			"%llu %llu %lu %llu %llu\n",
 			transport->srcport,
 			xprt->stat.bind_count,
 			xprt->stat.connect_count,
@@ -2283,7 +2291,10 @@
 			xprt->stat.recvs,
 			xprt->stat.bad_xids,
 			xprt->stat.req_u,
-			xprt->stat.bklog_u);
+			xprt->stat.bklog_u,
+			xprt->stat.max_slots,
+			xprt->stat.sending_u,
+			xprt->stat.pending_u);
 }
 
 /*
@@ -2464,6 +2475,7 @@
 static struct rpc_xprt_ops bc_tcp_ops = {
 	.reserve_xprt		= xprt_reserve_xprt,
 	.release_xprt		= xprt_release_xprt,
+	.rpcbind		= xs_local_rpcbind,
 	.buf_alloc		= bc_malloc,
 	.buf_free		= bc_free,
 	.send_request		= bc_send_request,
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
index e758139..c3e65ae 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -74,15 +74,13 @@
 
 static int __net_init sysctl_net_init(struct net *net)
 {
-	setup_sysctl_set(&net->sysctls,
-			 &net_sysctl_ro_root.default_set,
-			 is_seen);
+	setup_sysctl_set(&net->sysctls, &net_sysctl_root, is_seen);
 	return 0;
 }
 
 static void __net_exit sysctl_net_exit(struct net *net)
 {
-	WARN_ON(!list_empty(&net->sysctls.list));
+	retire_sysctl_set(&net->sysctls);
 }
 
 static struct pernet_operations sysctl_pernet_ops = {
@@ -90,36 +88,32 @@
 	.exit = sysctl_net_exit,
 };
 
-static __init int sysctl_init(void)
+static __init int net_sysctl_init(void)
 {
 	int ret;
 	ret = register_pernet_subsys(&sysctl_pernet_ops);
 	if (ret)
 		goto out;
-	register_sysctl_root(&net_sysctl_root);
-	setup_sysctl_set(&net_sysctl_ro_root.default_set, NULL, NULL);
+	setup_sysctl_set(&net_sysctl_ro_root.default_set, &net_sysctl_ro_root, NULL);
 	register_sysctl_root(&net_sysctl_ro_root);
+	register_sysctl_root(&net_sysctl_root);
 out:
 	return ret;
 }
-subsys_initcall(sysctl_init);
+subsys_initcall(net_sysctl_init);
 
 struct ctl_table_header *register_net_sysctl_table(struct net *net,
 	const struct ctl_path *path, struct ctl_table *table)
 {
-	struct nsproxy namespaces;
-	namespaces = *current->nsproxy;
-	namespaces.net_ns = net;
-	return __register_sysctl_paths(&net_sysctl_root,
-					&namespaces, path, table);
+	return __register_sysctl_paths(&net->sysctls, path, table);
 }
 EXPORT_SYMBOL_GPL(register_net_sysctl_table);
 
 struct ctl_table_header *register_net_sysctl_rotable(const
 		struct ctl_path *path, struct ctl_table *table)
 {
-	return __register_sysctl_paths(&net_sysctl_ro_root,
-			&init_nsproxy, path, table);
+	return __register_sysctl_paths(&net_sysctl_ro_root.default_set,
+					path, table);
 }
 EXPORT_SYMBOL_GPL(register_net_sysctl_rotable);
 
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 8ee85aa..d510353 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -293,7 +293,7 @@
 	spin_lock(&unix_table_lock);
 	sk_for_each(s, node,
 		    &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) {
-		struct dentry *dentry = unix_sk(s)->dentry;
+		struct dentry *dentry = unix_sk(s)->path.dentry;
 
 		if (dentry && dentry->d_inode == i) {
 			sock_hold(s);
@@ -377,8 +377,7 @@
 static int unix_release_sock(struct sock *sk, int embrion)
 {
 	struct unix_sock *u = unix_sk(sk);
-	struct dentry *dentry;
-	struct vfsmount *mnt;
+	struct path path;
 	struct sock *skpair;
 	struct sk_buff *skb;
 	int state;
@@ -389,10 +388,9 @@
 	unix_state_lock(sk);
 	sock_orphan(sk);
 	sk->sk_shutdown = SHUTDOWN_MASK;
-	dentry	     = u->dentry;
-	u->dentry    = NULL;
-	mnt	     = u->mnt;
-	u->mnt	     = NULL;
+	path	     = u->path;
+	u->path.dentry = NULL;
+	u->path.mnt = NULL;
 	state = sk->sk_state;
 	sk->sk_state = TCP_CLOSE;
 	unix_state_unlock(sk);
@@ -425,10 +423,8 @@
 		kfree_skb(skb);
 	}
 
-	if (dentry) {
-		dput(dentry);
-		mntput(mnt);
-	}
+	if (path.dentry)
+		path_put(&path);
 
 	sock_put(sk);
 
@@ -641,8 +637,8 @@
 	sk->sk_max_ack_backlog	= net->unx.sysctl_max_dgram_qlen;
 	sk->sk_destruct		= unix_sock_destructor;
 	u	  = unix_sk(sk);
-	u->dentry = NULL;
-	u->mnt	  = NULL;
+	u->path.dentry = NULL;
+	u->path.mnt = NULL;
 	spin_lock_init(&u->lock);
 	atomic_long_set(&u->inflight, 0);
 	INIT_LIST_HEAD(&u->link);
@@ -788,7 +784,7 @@
 			goto put_fail;
 
 		if (u->sk_type == type)
-			touch_atime(path.mnt, path.dentry);
+			touch_atime(&path);
 
 		path_put(&path);
 
@@ -802,9 +798,9 @@
 		u = unix_find_socket_byname(net, sunname, len, type, hash);
 		if (u) {
 			struct dentry *dentry;
-			dentry = unix_sk(u)->dentry;
+			dentry = unix_sk(u)->path.dentry;
 			if (dentry)
-				touch_atime(unix_sk(u)->mnt, dentry);
+				touch_atime(&unix_sk(u)->path);
 		} else
 			goto fail;
 	}
@@ -910,8 +906,7 @@
 		list = &unix_socket_table[addr->hash];
 	} else {
 		list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)];
-		u->dentry = path.dentry;
-		u->mnt    = path.mnt;
+		u->path = path;
 	}
 
 	err = 0;
@@ -1193,9 +1188,9 @@
 		atomic_inc(&otheru->addr->refcnt);
 		newu->addr = otheru->addr;
 	}
-	if (otheru->dentry) {
-		newu->dentry	= dget(otheru->dentry);
-		newu->mnt	= mntget(otheru->mnt);
+	if (otheru->path.dentry) {
+		path_get(&otheru->path);
+		newu->path = otheru->path;
 	}
 
 	/* Set credentials */
@@ -2211,7 +2206,7 @@
 	}
 
 	/* No write status requested, avoid expensive OUT tests. */
-	if (wait && !(wait->key & (POLLWRBAND | POLLWRNORM | POLLOUT)))
+	if (!(poll_requested_events(wait) & (POLLWRBAND|POLLWRNORM|POLLOUT)))
 		return mask;
 
 	writable = unix_writable(sk);
diff --git a/net/unix/diag.c b/net/unix/diag.c
index 4195555..f0486ae 100644
--- a/net/unix/diag.c
+++ b/net/unix/diag.c
@@ -29,7 +29,7 @@
 
 static int sk_diag_dump_vfs(struct sock *sk, struct sk_buff *nlskb)
 {
-	struct dentry *dentry = unix_sk(sk)->dentry;
+	struct dentry *dentry = unix_sk(sk)->path.dentry;
 	struct unix_diag_vfs *uv;
 
 	if (dentry) {
diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c
index 39765bc..920cabe 100644
--- a/net/wireless/debugfs.c
+++ b/net/wireless/debugfs.c
@@ -13,12 +13,6 @@
 #include "core.h"
 #include "debugfs.h"
 
-static int cfg80211_open_file_generic(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...)		\
 static ssize_t name## _read(struct file *file, char __user *userbuf,	\
 			    size_t count, loff_t *ppos)			\
@@ -33,7 +27,7 @@
 									\
 static const struct file_operations name## _ops = {			\
 	.read = name## _read,						\
-	.open = cfg80211_open_file_generic,				\
+	.open = simple_open,						\
 	.llseek = generic_file_llseek,					\
 };
 
@@ -102,7 +96,7 @@
 
 static const struct file_operations ht40allow_map_ops = {
 	.read = ht40allow_map_read,
-	.open = cfg80211_open_file_generic,
+	.open = simple_open,
 	.llseek = default_llseek,
 };
 
diff --git a/samples/Kconfig b/samples/Kconfig
index 41063e7..7b6792a 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -61,4 +61,12 @@
 	  Build an example of how to dynamically add the hello
 	  command to the kdb shell.
 
+config SAMPLE_RPMSG_CLIENT
+	tristate "Build rpmsg client sample -- loadable modules only"
+	depends on RPMSG && m
+	help
+	  Build an rpmsg client sample driver, which demonstrates how
+	  to communicate with an AMP-configured remote processor over
+	  the rpmsg bus.
+
 endif # SAMPLES
diff --git a/samples/Makefile b/samples/Makefile
index 6280817..2f75851 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -1,4 +1,4 @@
 # Makefile for Linux samples code
 
 obj-$(CONFIG_SAMPLES)	+= kobject/ kprobes/ tracepoints/ trace_events/ \
-			   hw_breakpoint/ kfifo/ kdb/ hidraw/
+			   hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/
diff --git a/samples/rpmsg/Makefile b/samples/rpmsg/Makefile
new file mode 100644
index 0000000..2d4973c
--- /dev/null
+++ b/samples/rpmsg/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SAMPLE_RPMSG_CLIENT) += rpmsg_client_sample.o
diff --git a/samples/rpmsg/rpmsg_client_sample.c b/samples/rpmsg/rpmsg_client_sample.c
new file mode 100644
index 0000000..23ea9f2
--- /dev/null
+++ b/samples/rpmsg/rpmsg_client_sample.c
@@ -0,0 +1,100 @@
+/*
+ * Remote processor messaging - sample client driver
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/rpmsg.h>
+
+#define MSG		"hello world!"
+#define MSG_LIMIT	100
+
+static void rpmsg_sample_cb(struct rpmsg_channel *rpdev, void *data, int len,
+						void *priv, u32 src)
+{
+	int ret;
+	static int rx_count;
+
+	dev_info(&rpdev->dev, "incoming msg %d (src: 0x%x)\n", ++rx_count, src);
+
+	print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
+		       data, len,  true);
+
+	/* samples should not live forever */
+	if (rx_count >= MSG_LIMIT) {
+		dev_info(&rpdev->dev, "goodbye!\n");
+		return;
+	}
+
+	/* send a new message now */
+	ret = rpmsg_send(rpdev, MSG, strlen(MSG));
+	if (ret)
+		dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
+}
+
+static int rpmsg_sample_probe(struct rpmsg_channel *rpdev)
+{
+	int ret;
+
+	dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
+					rpdev->src, rpdev->dst);
+
+	/* send a message to our remote processor */
+	ret = rpmsg_send(rpdev, MSG, strlen(MSG));
+	if (ret) {
+		dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __devexit rpmsg_sample_remove(struct rpmsg_channel *rpdev)
+{
+	dev_info(&rpdev->dev, "rpmsg sample client driver is removed\n");
+}
+
+static struct rpmsg_device_id rpmsg_driver_sample_id_table[] = {
+	{ .name	= "rpmsg-client-sample" },
+	{ },
+};
+MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_sample_id_table);
+
+static struct rpmsg_driver rpmsg_sample_client = {
+	.drv.name	= KBUILD_MODNAME,
+	.drv.owner	= THIS_MODULE,
+	.id_table	= rpmsg_driver_sample_id_table,
+	.probe		= rpmsg_sample_probe,
+	.callback	= rpmsg_sample_cb,
+	.remove		= __devexit_p(rpmsg_sample_remove),
+};
+
+static int __init rpmsg_client_sample_init(void)
+{
+	return register_rpmsg_driver(&rpmsg_sample_client);
+}
+module_init(rpmsg_client_sample_init);
+
+static void __exit rpmsg_client_sample_fini(void)
+{
+	unregister_rpmsg_driver(&rpmsg_sample_client);
+}
+module_exit(rpmsg_client_sample_fini);
+
+MODULE_DESCRIPTION("Remote processor messaging sample client driver");
+MODULE_LICENSE("GPL v2");
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index d897278..6a3ee98 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -104,7 +104,7 @@
 # Usage: cflags-y += $(call as-instr,instr,option1,option2)
 
 as-instr = $(call try-run,\
-	/bin/echo -e "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3))
+	printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3))
 
 # cc-option
 # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index d2b366c1..ff1720d 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -69,6 +69,7 @@
 warning-1 += -Wold-style-definition
 warning-1 += $(call cc-option, -Wmissing-include-dirs)
 warning-1 += $(call cc-option, -Wunused-but-set-variable)
+warning-1 += $(call cc-disable-warning, missing-field-initializers)
 
 warning-2 := -Waggregate-return
 warning-2 += -Wcast-align
@@ -76,6 +77,7 @@
 warning-2 += -Wnested-externs
 warning-2 += -Wshadow
 warning-2 += $(call cc-option, -Wlogical-op)
+warning-2 += $(call cc-option, -Wmissing-field-initializers)
 
 warning-3 := -Wbad-function-cast
 warning-3 += -Wcast-qual
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 00c368c..0be6f11 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -304,6 +304,30 @@
 	lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
 	(rm -f $@ ; false)
 
+# U-Boot mkimage
+# ---------------------------------------------------------------------------
+
+MKIMAGE := $(srctree)/scripts/mkuboot.sh
+
+# SRCARCH just happens to match slightly more than ARCH (on sparc), so reduces
+# the number of overrides in arch makefiles
+UIMAGE_ARCH ?= $(SRCARCH)
+UIMAGE_COMPRESSION ?= $(if $(2),$(2),none)
+UIMAGE_OPTS-y ?=
+UIMAGE_TYPE ?= kernel
+UIMAGE_LOADADDR ?= arch_must_set_this
+UIMAGE_ENTRYADDR ?= $(UIMAGE_LOADADDR)
+UIMAGE_NAME ?= 'Linux-$(KERNELRELEASE)'
+UIMAGE_IN ?= $<
+UIMAGE_OUT ?= $@
+
+quiet_cmd_uimage = UIMAGE  $(UIMAGE_OUT)
+      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(UIMAGE_ARCH) -O linux \
+			-C $(UIMAGE_COMPRESSION) $(UIMAGE_OPTS-y) \
+			-T $(UIMAGE_TYPE) \
+			-a $(UIMAGE_LOADADDR) -e $(UIMAGE_ENTRYADDR) \
+			-n $(UIMAGE_NAME) -d $(UIMAGE_IN) $(UIMAGE_OUT)
+
 # XZ
 # ---------------------------------------------------------------------------
 # Use xzkern to compress the kernel image and xzmisc to compress other things.
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index a3b9782..de639ee 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -323,17 +323,22 @@
 		  }x;
 	$Type	= qr{
 			$NonptrType
-			(?:[\s\*]+\s*const|[\s\*]+|(?:\s*\[\s*\])+)?
+			(?:(?:\s|\*|\[\])+\s*const|(?:\s|\*|\[\])+|(?:\s*\[\s*\])+)?
 			(?:\s+$Inline|\s+$Modifier)*
 		  }x;
 	$Declare	= qr{(?:$Storage\s+)?$Type};
 }
 build_types();
 
-our $match_balanced_parentheses = qr/(\((?:[^\(\)]+|(-1))*\))/;
 
 our $Typecast	= qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*};
-our $LvalOrFunc	= qr{($Lval)\s*($match_balanced_parentheses{0,1})\s*};
+
+# Using $balanced_parens, $LvalOrFunc, or $FuncArg
+# requires at least perl version v5.10.0
+# Any use must be runtime checked with $^V
+
+our $balanced_parens = qr/(\((?:[^\(\)]++|(?-1))*\))/;
+our $LvalOrFunc	= qr{($Lval)\s*($balanced_parens{0,1})\s*};
 our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant)};
 
 sub deparenthesize {
@@ -1330,6 +1335,36 @@
 	}
 }
 
+sub pos_last_openparen {
+	my ($line) = @_;
+
+	my $pos = 0;
+
+	my $opens = $line =~ tr/\(/\(/;
+	my $closes = $line =~ tr/\)/\)/;
+
+	my $last_openparen = 0;
+
+	if (($opens == 0) || ($closes >= $opens)) {
+		return -1;
+	}
+
+	my $len = length($line);
+
+	for ($pos = 0; $pos < $len; $pos++) {
+		my $string = substr($line, $pos);
+		if ($string =~ /^($FuncArg|$balanced_parens)/) {
+			$pos += length($1) - 1;
+		} elsif (substr($line, $pos, 1) eq '(') {
+			$last_openparen = $pos;
+		} elsif (index($string, '(') == -1) {
+			last;
+		}
+	}
+
+	return $last_openparen + 1;
+}
+
 sub process {
 	my $filename = shift;
 
@@ -1737,6 +1772,21 @@
 			     "line over 80 characters\n" . $herecurr);
 		}
 
+# Check for user-visible strings broken across lines, which breaks the ability
+# to grep for the string.  Limited to strings used as parameters (those
+# following an open parenthesis), which almost completely eliminates false
+# positives, as well as warning only once per parameter rather than once per
+# line of the string.  Make an exception when the previous string ends in a
+# newline (multiple lines in one string constant) or \n\t (common in inline
+# assembly to indent the instruction on the following line).
+		if ($line =~ /^\+\s*"/ &&
+		    $prevline =~ /"\s*$/ &&
+		    $prevline =~ /\(/ &&
+		    $prevrawline !~ /\\n(?:\\t)*"\s*$/) {
+			WARN("SPLIT_STRING",
+			     "quoted string split across lines\n" . $hereprev);
+		}
+
 # check for spaces before a quoted newline
 		if ($rawline =~ /^.*\".*\s\\n/) {
 			WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE",
@@ -1783,6 +1833,48 @@
 			     "please, no space before tabs\n" . $herevet);
 		}
 
+# check for && or || at the start of a line
+		if ($rawline =~ /^\+\s*(&&|\|\|)/) {
+			CHK("LOGICAL_CONTINUATIONS",
+			    "Logical continuations should be on the previous line\n" . $hereprev);
+		}
+
+# check multi-line statement indentation matches previous line
+		if ($^V && $^V ge 5.10.0 &&
+		    $prevline =~ /^\+(\t*)(if \(|$Ident\().*(\&\&|\|\||,)\s*$/) {
+			$prevline =~ /^\+(\t*)(.*)$/;
+			my $oldindent = $1;
+			my $rest = $2;
+
+			my $pos = pos_last_openparen($rest);
+			if ($pos >= 0) {
+				$line =~ /^\+([ \t]*)/;
+				my $newindent = $1;
+
+				my $goodtabindent = $oldindent .
+					"\t" x ($pos / 8) .
+					" "  x ($pos % 8);
+				my $goodspaceindent = $oldindent . " "  x $pos;
+
+				if ($newindent ne $goodtabindent &&
+				    $newindent ne $goodspaceindent) {
+					CHK("PARENTHESIS_ALIGNMENT",
+					    "Alignment should match open parenthesis\n" . $hereprev);
+				}
+			}
+		}
+
+		if ($line =~ /^\+.*\*[ \t]*\)[ \t]+/) {
+			CHK("SPACING",
+			    "No space is necessary after a cast\n" . $hereprev);
+		}
+
+		if ($rawline =~ /^\+[ \t]*\/\*[ \t]*$/ &&
+		    $prevrawline =~ /^\+[ \t]*$/) {
+			CHK("BLOCK_COMMENT_STYLE",
+			    "Don't begin block comments with only a /* line, use /* comment...\n" . $hereprev);
+		}
+
 # check for spaces at the beginning of a line.
 # Exceptions:
 #  1) within comments
@@ -2325,7 +2417,7 @@
 			my ($where, $prefix) = ($-[1], $1);
 			if ($prefix !~ /$Type\s+$/ &&
 			    ($where != 0 || $prefix !~ /^.\s+$/) &&
-			    $prefix !~ /{\s+$/) {
+			    $prefix !~ /[{,]\s+$/) {
 				ERROR("BRACKET_SPACE",
 				      "space prohibited before open square bracket '['\n" . $herecurr);
 			}
@@ -2828,6 +2920,12 @@
 			{
 			}
 
+			# Flatten any obvious string concatentation.
+			while ($dstat =~ s/("X*")\s*$Ident/$1/ ||
+			       $dstat =~ s/$Ident\s*("X*")/$1/)
+			{
+			}
+
 			my $exceptions = qr{
 				$Declare|
 				module_param_named|
@@ -2844,7 +2942,8 @@
 			if ($dstat ne '' &&
 			    $dstat !~ /^(?:$Ident|-?$Constant),$/ &&			# 10, // foo(),
 			    $dstat !~ /^(?:$Ident|-?$Constant);$/ &&			# foo();
-			    $dstat !~ /^(?:$Ident|-?$Constant)$/ &&			# 10 // foo()
+			    $dstat !~ /^[!~-]?(?:$Ident|$Constant)$/ &&		# 10 // foo() // !foo // ~foo // -foo
+			    $dstat !~ /^'X'$/ &&					# character constants
 			    $dstat !~ /$exceptions/ &&
 			    $dstat !~ /^\.$Ident\s*=/ &&				# .foo =
 			    $dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ &&	# do {...} while (...); // do {...} while (...)
@@ -2888,7 +2987,8 @@
 			#print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n";
 			#print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n";
 			if ($#chunks > 0 && $level == 0) {
-				my $allowed = 0;
+				my @allowed = ();
+				my $allow = 0;
 				my $seen = 0;
 				my $herectx = $here . "\n";
 				my $ln = $linenr - 1;
@@ -2899,6 +2999,7 @@
 					my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s);
 					my $offset = statement_rawlines($whitespace) - 1;
 
+					$allowed[$allow] = 0;
 					#print "COND<$cond> whitespace<$whitespace> offset<$offset>\n";
 
 					# We have looked at and allowed this specific line.
@@ -2911,23 +3012,34 @@
 
 					$seen++ if ($block =~ /^\s*{/);
 
-					#print "cond<$cond> block<$block> allowed<$allowed>\n";
+					#print "cond<$cond> block<$block> allowed<$allowed[$allow]>\n";
 					if (statement_lines($cond) > 1) {
 						#print "APW: ALLOWED: cond<$cond>\n";
-						$allowed = 1;
+						$allowed[$allow] = 1;
 					}
 					if ($block =~/\b(?:if|for|while)\b/) {
 						#print "APW: ALLOWED: block<$block>\n";
-						$allowed = 1;
+						$allowed[$allow] = 1;
 					}
 					if (statement_block_size($block) > 1) {
 						#print "APW: ALLOWED: lines block<$block>\n";
-						$allowed = 1;
+						$allowed[$allow] = 1;
 					}
+					$allow++;
 				}
-				if ($seen && !$allowed) {
-					WARN("BRACES",
-					     "braces {} are not necessary for any arm of this statement\n" . $herectx);
+				if ($seen) {
+					my $sum_allowed = 0;
+					foreach (@allowed) {
+						$sum_allowed += $_;
+					}
+					if ($sum_allowed == 0) {
+						WARN("BRACES",
+						     "braces {} are not necessary for any arm of this statement\n" . $herectx);
+					} elsif ($sum_allowed != $allow &&
+						 $seen != $allow) {
+						CHK("BRACES",
+						    "braces {} should be used on all arms of this statement\n" . $herectx);
+					}
 				}
 			}
 		}
@@ -3123,6 +3235,12 @@
 			     "__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $herecurr);
 		}
 
+# Check for __attribute__ format(scanf, prefer __scanf
+		if ($line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\b/) {
+			WARN("PREFER_SCANF",
+			     "__scanf(string-index, first-to-check) is preferred over __attribute__((format(scanf, string-index, first-to-check)))\n" . $herecurr);
+		}
+
 # check for sizeof(&)
 		if ($line =~ /\bsizeof\s*\(\s*\&/) {
 			WARN("SIZEOF_ADDRESS",
@@ -3136,12 +3254,13 @@
 		}
 
 # Check for misused memsets
-		if (defined $stat &&
+		if ($^V && $^V ge 5.10.0 &&
+		    defined $stat &&
 		    $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/s) {
 
 			my $ms_addr = $2;
-			my $ms_val = $8;
-			my $ms_size = $14;
+			my $ms_val = $7;
+			my $ms_size = $12;
 
 			if ($ms_size =~ /^(0x|)0$/i) {
 				ERROR("MEMSET",
@@ -3153,17 +3272,18 @@
 		}
 
 # typecasts on min/max could be min_t/max_t
-		if (defined $stat &&
+		if ($^V && $^V ge 5.10.0 &&
+		    defined $stat &&
 		    $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) {
-			if (defined $2 || defined $8) {
+			if (defined $2 || defined $7) {
 				my $call = $1;
 				my $cast1 = deparenthesize($2);
 				my $arg1 = $3;
-				my $cast2 = deparenthesize($8);
-				my $arg2 = $9;
+				my $cast2 = deparenthesize($7);
+				my $arg2 = $8;
 				my $cast;
 
-				if ($cast1 ne "" && $cast2 ne "") {
+				if ($cast1 ne "" && $cast2 ne "" && $cast1 ne $cast2) {
 					$cast = "$cast1 or $cast2";
 				} elsif ($cast1 ne "") {
 					$cast = $cast1;
@@ -3233,22 +3353,30 @@
 			     "__func__ should be used instead of gcc specific __FUNCTION__\n"  . $herecurr);
 		}
 
+# check for use of yield()
+		if ($line =~ /\byield\s*\(\s*\)/) {
+			WARN("YIELD",
+			     "Using yield() is generally wrong. See yield() kernel-doc (sched/core.c)\n"  . $herecurr);
+		}
+
 # check for semaphores initialized locked
 		if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) {
 			WARN("CONSIDER_COMPLETION",
 			     "consider using a completion\n" . $herecurr);
-
 		}
+
 # recommend kstrto* over simple_strto* and strict_strto*
 		if ($line =~ /\b((simple|strict)_(strto(l|ll|ul|ull)))\s*\(/) {
 			WARN("CONSIDER_KSTRTO",
 			     "$1 is obsolete, use k$3 instead\n" . $herecurr);
 		}
+
 # check for __initcall(), use device_initcall() explicitly please
 		if ($line =~ /^.\s*__initcall\s*\(/) {
 			WARN("USE_DEVICE_INITCALL",
 			     "please use device_initcall() instead of __initcall()\n" . $herecurr);
 		}
+
 # check for various ops structs, ensure they are const.
 		my $struct_ops = qr{acpi_dock_ops|
 				address_space_operations|
@@ -3385,6 +3513,12 @@
 	}
 
 	if ($quiet == 0) {
+
+		if ($^V lt 5.10.0) {
+			print("NOTE: perl $^V is not modern enough to detect all possible issues.\n");
+			print("An upgrade to at least perl v5.10.0 is suggested.\n\n");
+		}
+
 		# If there were whitespace errors which cleanpatch can fix
 		# then suggest that.
 		if ($rpt_cleaners) {
@@ -3394,13 +3528,12 @@
 		}
 	}
 
-	if (keys %ignore_type) {
+	if ($quiet == 0 && keys %ignore_type) {
 	    print "NOTE: Ignored message types:";
 	    foreach my $ignore (sort keys %ignore_type) {
 		print " $ignore";
 	    }
-	    print "\n";
-	    print "\n" if ($quiet == 0);
+	    print "\n\n";
 	}
 
 	if ($clean == 1 && $quiet == 0) {
diff --git a/scripts/coccinelle/api/ptr_ret.cocci b/scripts/coccinelle/api/ptr_ret.cocci
new file mode 100644
index 0000000..cbfd08c
--- /dev/null
+++ b/scripts/coccinelle/api/ptr_ret.cocci
@@ -0,0 +1,70 @@
+///
+/// Use PTR_RET rather than if(IS_ERR(...)) + PTR_ERR
+///
+// Confidence: High
+// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Options: -no_includes -include_headers
+//
+// Keywords: ERR_PTR, PTR_ERR, PTR_RET
+// Version min: 2.6.39
+//
+
+virtual context
+virtual patch
+virtual org
+virtual report
+
+@depends on patch@
+expression ptr;
+@@
+
+- if (IS_ERR(ptr)) return PTR_ERR(ptr); else return 0;
++ return PTR_RET(ptr);
+
+@depends on patch@
+expression ptr;
+@@
+
+- if (IS_ERR(ptr)) return PTR_ERR(ptr); return 0;
++ return PTR_RET(ptr);
+
+@r1 depends on !patch@
+expression ptr;
+position p1;
+@@
+
+* if@p1 (IS_ERR(ptr)) return PTR_ERR(ptr); else return 0;
+
+@r2 depends on !patch@
+expression ptr;
+position p2;
+@@
+
+* if@p2 (IS_ERR(ptr)) return PTR_ERR(ptr); return 0;
+
+@script:python depends on org@
+p << r1.p1;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING: PTR_RET can be used")
+
+
+@script:python depends on org@
+p << r2.p2;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING: PTR_RET can be used")
+
+@script:python depends on report@
+p << r1.p1;
+@@
+
+coccilib.report.print_report(p[0], "WARNING: PTR_RET can be used")
+
+@script:python depends on report@
+p << r2.p2;
+@@
+
+coccilib.report.print_report(p[0], "WARNING: PTR_RET can be used")
diff --git a/scripts/coccinelle/api/simple_open.cocci b/scripts/coccinelle/api/simple_open.cocci
new file mode 100644
index 0000000..05962f7
--- /dev/null
+++ b/scripts/coccinelle/api/simple_open.cocci
@@ -0,0 +1,70 @@
+/// This removes an open coded simple_open() function
+/// and replaces file operations references to the function
+/// with simple_open() instead.
+///
+// Confidence: High
+// Comments:
+// Options: -no_includes -include_headers
+
+virtual patch
+virtual report
+
+@ open depends on patch @
+identifier open_f != simple_open;
+identifier i, f;
+@@
+-int open_f(struct inode *i, struct file *f)
+-{
+(
+-if (i->i_private)
+-f->private_data = i->i_private;
+|
+-f->private_data = i->i_private;
+)
+-return 0;
+-}
+
+@ has_open depends on open @
+identifier fops;
+identifier open.open_f;
+@@
+struct file_operations fops = {
+...,
+-.open = open_f,
++.open = simple_open,
+...
+};
+
+@ openr depends on report @
+identifier open_f != simple_open;
+identifier i, f;
+position p;
+@@
+int open_f@p(struct inode *i, struct file *f)
+{
+(
+if (i->i_private)
+f->private_data = i->i_private;
+|
+f->private_data = i->i_private;
+)
+return 0;
+}
+
+@ has_openr depends on openr @
+identifier fops;
+identifier openr.open_f;
+position p;
+@@
+struct file_operations fops = {
+...,
+.open = open_f@p,
+...
+};
+
+@script:python@
+pf << openr.p;
+ps << has_openr.p;
+@@
+
+coccilib.report.print_report(pf[0],"WARNING opportunity for simple_open, see also structure on line %s"%(ps[0].line))
diff --git a/scripts/coccinelle/free/clk_put.cocci b/scripts/coccinelle/free/clk_put.cocci
new file mode 100644
index 0000000..46747ad
--- /dev/null
+++ b/scripts/coccinelle/free/clk_put.cocci
@@ -0,0 +1,67 @@
+/// Find missing clk_puts.
+///
+//# This only signals a missing clk_put when there is a clk_put later
+//# in the same function.
+//# False positives can be due to loops.
+//
+// Confidence: Moderate
+// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options:
+
+virtual context
+virtual org
+virtual report
+
+@clk@
+expression e;
+statement S,S1;
+int ret;
+position p1,p2,p3;
+@@
+
+e = clk_get@p1(...)
+... when != clk_put(e)
+if (<+...e...+>) S
+... when any
+    when != clk_put(e)
+    when != if (...) { ... clk_put(e); ... }
+(
+ if (ret == 0) S1
+|
+if (...)
+   { ...
+     return 0; }
+|
+if (...)
+   { ...
+     return <+...e...+>; }
+|
+*if@p2 (...)
+   { ... when != clk_put(e)
+         when forall
+     return@p3 ...; }
+)
+... when any
+clk_put(e);
+
+@script:python depends on org@
+p1 << clk.p1;
+p2 << clk.p2;
+p3 << clk.p3;
+@@
+
+cocci.print_main("clk_get",p1)
+cocci.print_secs("if",p2)
+cocci.print_secs("needed clk_put",p3)
+
+@script:python depends on report@
+p1 << clk.p1;
+p2 << clk.p2;
+p3 << clk.p3;
+@@
+
+msg = "ERROR: missing clk_put; clk_get on line %s and execution via conditional on line %s" % (p1[0].line,p2[0].line)
+coccilib.report.print_report(p3[0],msg)
diff --git a/scripts/coccinelle/free/iounmap.cocci b/scripts/coccinelle/free/iounmap.cocci
new file mode 100644
index 0000000..5384f4ba
--- /dev/null
+++ b/scripts/coccinelle/free/iounmap.cocci
@@ -0,0 +1,67 @@
+/// Find missing iounmaps.
+///
+//# This only signals a missing iounmap when there is an iounmap later
+//# in the same function.
+//# False positives can be due to loops.
+//
+// Confidence: Moderate
+// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options:
+
+virtual context
+virtual org
+virtual report
+
+@iom@
+expression e;
+statement S,S1;
+int ret;
+position p1,p2,p3;
+@@
+
+e = \(ioremap@p1\|ioremap_nocache@p1\)(...)
+... when != iounmap(e)
+if (<+...e...+>) S
+... when any
+    when != iounmap(e)
+    when != if (...) { ... iounmap(e); ... }
+(
+ if (ret == 0) S1
+|
+if (...)
+   { ...
+     return 0; }
+|
+if (...)
+   { ...
+     return <+...e...+>; }
+|
+*if@p2 (...)
+   { ... when != iounmap(e)
+         when forall
+     return@p3 ...; }
+)
+... when any
+iounmap(e);
+
+@script:python depends on org@
+p1 << iom.p1;
+p2 << iom.p2;
+p3 << iom.p3;
+@@
+
+cocci.print_main("ioremap",p1)
+cocci.print_secs("if",p2)
+cocci.print_secs("needed iounmap",p3)
+
+@script:python depends on report@
+p1 << iom.p1;
+p2 << iom.p2;
+p3 << iom.p3;
+@@
+
+msg = "ERROR: missing iounmap; ioremap on line %s and execution via conditional on line %s" % (p1[0].line,p2[0].line)
+coccilib.report.print_report(p3[0],msg)
diff --git a/scripts/coccinelle/misc/boolinit.cocci b/scripts/coccinelle/misc/boolinit.cocci
new file mode 100644
index 0000000..97ce41c
--- /dev/null
+++ b/scripts/coccinelle/misc/boolinit.cocci
@@ -0,0 +1,178 @@
+/// Bool initializations should use true and false.  Bool tests don't need
+/// comparisons.  Based on contributions from Joe Perches, Rusty Russell
+/// and Bruce W Allan.
+///
+// Confidence: High
+// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Options: -include_headers
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@depends on patch@
+bool t;
+symbol true;
+symbol false;
+@@
+
+(
+- t == true
++ t
+|
+- true == t
++ t
+|
+- t != true
++ !t
+|
+- true != t
++ !t
+|
+- t == false
++ !t
+|
+- false == t
++ !t
+|
+- t != false
++ t
+|
+- false != t
++ t
+)
+
+@depends on patch disable is_zero, isnt_zero@
+bool t;
+@@
+
+(
+- t == 1
++ t
+|
+- t != 1
++ !t
+|
+- t == 0
++ !t
+|
+- t != 0
++ t
+)
+
+@depends on patch@
+bool b;
+@@
+(
+ b =
+- 0
++ false
+|
+ b =
+- 1
++ true
+)
+
+// ---------------------------------------------------------------------
+
+@r1 depends on !patch@
+bool t;
+position p;
+@@
+
+(
+* t@p == true
+|
+* true == t@p
+|
+* t@p != true
+|
+* true != t@p
+|
+* t@p == false
+|
+* false == t@p
+|
+* t@p != false
+|
+* false != t@p
+)
+
+@r2 depends on !patch disable is_zero, isnt_zero@
+bool t;
+position p;
+@@
+
+(
+* t@p == 1
+|
+* t@p != 1
+|
+* t@p == 0
+|
+* t@p != 0
+)
+
+@r3 depends on !patch@
+bool b;
+position p1,p2;
+constant c;
+@@
+(
+*b@p1 = 0
+|
+*b@p1 = 1
+|
+*b@p2 = c
+)
+
+@script:python depends on org@
+p << r1.p;
+@@
+
+cocci.print_main("WARNING: Comparison to bool",p)
+
+@script:python depends on org@
+p << r2.p;
+@@
+
+cocci.print_main("WARNING: Comparison of bool to 0/1",p)
+
+@script:python depends on org@
+p1 << r3.p1;
+@@
+
+cocci.print_main("WARNING: Assignment of bool to 0/1",p1)
+
+@script:python depends on org@
+p2 << r3.p2;
+@@
+
+cocci.print_main("ERROR: Assignment of bool to non-0/1 constant",p2)
+
+@script:python depends on report@
+p << r1.p;
+@@
+
+coccilib.report.print_report(p[0],"WARNING: Comparison to bool")
+
+@script:python depends on report@
+p << r2.p;
+@@
+
+coccilib.report.print_report(p[0],"WARNING: Comparison of bool to 0/1")
+
+@script:python depends on report@
+p1 << r3.p1;
+@@
+
+coccilib.report.print_report(p1[0],"WARNING: Assignment of bool to 0/1")
+
+@script:python depends on report@
+p2 << r3.p2;
+@@
+
+coccilib.report.print_report(p2[0],"ERROR: Assignment of bool to non-0/1 constant")
diff --git a/scripts/coccinelle/misc/cstptr.cocci b/scripts/coccinelle/misc/cstptr.cocci
new file mode 100644
index 0000000..d425644
--- /dev/null
+++ b/scripts/coccinelle/misc/cstptr.cocci
@@ -0,0 +1,41 @@
+/// PTR_ERR should be applied before its argument is reassigned, typically
+/// to NULL
+///
+// Confidence: High
+// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: -no_includes -include_headers
+
+virtual org
+virtual report
+virtual context
+
+@r exists@
+expression e,e1;
+constant c;
+position p1,p2;
+@@
+
+*e@p1 = c
+... when != e = e1
+    when != &e
+    when != true IS_ERR(e)
+*PTR_ERR@p2(e)
+
+@script:python depends on org@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+cocci.print_main("PTR_ERR",p2)
+cocci.print_secs("assignment",p1)
+
+@script:python depends on report@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+msg = "ERROR: PTR_ERR applied after initialization to constant on line %s" % (p1[0].line)
+coccilib.report.print_report(p2[0],msg)
diff --git a/scripts/coccinelle/null/badzero.cocci b/scripts/coccinelle/null/badzero.cocci
new file mode 100644
index 0000000..d79baf7
--- /dev/null
+++ b/scripts/coccinelle/null/badzero.cocci
@@ -0,0 +1,237 @@
+/// Compare pointer-typed values to NULL rather than 0
+///
+//# This makes an effort to choose between !x and x == NULL.  !x is used
+//# if it has previously been used with the function used to initialize x.
+//# This relies on type information.  More type information can be obtained
+//# using the option -all_includes and the option -I to specify an
+//# include path.
+//
+// Confidence: High
+// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options:
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@initialize:ocaml@
+let negtable = Hashtbl.create 101
+
+@depends on patch@
+expression *E;
+identifier f;
+@@
+
+(
+  (E = f(...)) ==
+- 0
++ NULL
+|
+  (E = f(...)) !=
+- 0
++ NULL
+|
+- 0
++ NULL
+  == (E = f(...))
+|
+- 0
++ NULL
+  != (E = f(...))
+)
+
+
+@t1 depends on !patch@
+expression *E;
+identifier f;
+position p;
+@@
+
+(
+  (E = f(...)) ==
+* 0@p
+|
+  (E = f(...)) !=
+* 0@p
+|
+* 0@p
+  == (E = f(...))
+|
+* 0@p
+  != (E = f(...))
+)
+
+@script:python depends on org@
+p << t1.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0")
+
+@script:python depends on report@
+p << t1.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING comparing pointer to 0")
+
+// Tests of returned values
+
+@s@
+identifier f;
+expression E,E1;
+@@
+
+ E = f(...)
+ ... when != E = E1
+ !E
+
+@script:ocaml depends on s@
+f << s.f;
+@@
+
+try let _ = Hashtbl.find negtable f in ()
+with Not_found -> Hashtbl.add negtable f ()
+
+@ r disable is_zero,isnt_zero exists @
+expression *E;
+identifier f;
+@@
+
+E = f(...)
+...
+(E == 0
+|E != 0
+|0 == E
+|0 != E
+)
+
+@script:ocaml@
+f << r.f;
+@@
+
+try let _ = Hashtbl.find negtable f in ()
+with Not_found -> include_match false
+
+// This rule may lead to inconsistent path problems, if E is defined in two
+// places
+@ depends on patch disable is_zero,isnt_zero @
+expression *E;
+expression E1;
+identifier r.f;
+@@
+
+E = f(...)
+<...
+(
+- E == 0
++ !E
+|
+- E != 0
++ E
+|
+- 0 == E
++ !E
+|
+- 0 != E
++ E
+)
+...>
+?E = E1
+
+@t2 depends on !patch disable is_zero,isnt_zero @
+expression *E;
+expression E1;
+identifier r.f;
+position p1;
+position p2;
+@@
+
+E = f(...)
+<...
+(
+* E == 0@p1
+|
+* E != 0@p2
+|
+* 0@p1 == E
+|
+* 0@p1 != E
+)
+...>
+?E = E1
+
+@script:python depends on org@
+p << t2.p1;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0, suggest !E")
+
+@script:python depends on org@
+p << t2.p2;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0")
+
+@script:python depends on report@
+p << t2.p1;
+@@
+
+coccilib.report.print_report(p[0], "WARNING comparing pointer to 0, suggest !E")
+
+@script:python depends on report@
+p << t2.p2;
+@@
+
+coccilib.report.print_report(p[0], "WARNING comparing pointer to 0")
+
+@ depends on patch disable is_zero,isnt_zero @
+expression *E;
+@@
+
+(
+  E ==
+- 0
++ NULL
+|
+  E !=
+- 0
++ NULL
+|
+- 0
++ NULL
+  == E
+|
+- 0
++ NULL
+  != E
+)
+
+@ t3 depends on !patch disable is_zero,isnt_zero @
+expression *E;
+position p;
+@@
+
+(
+* E == 0@p
+|
+* E != 0@p
+|
+* 0@p == E
+|
+* 0@p != E
+)
+
+@script:python depends on org@
+p << t3.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0")
+
+@script:python depends on report@
+p << t3.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING comparing pointer to 0")
diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c
index 451c92d..2ef5e2e 100644
--- a/scripts/dtc/dtc.c
+++ b/scripts/dtc/dtc.c
@@ -101,7 +101,7 @@
 	const char *outform = "dts";
 	const char *outname = "-";
 	const char *depname = NULL;
-	int force = 0, check = 0, sort = 0;
+	int force = 0, sort = 0;
 	const char *arg;
 	int opt;
 	FILE *outf = NULL;
@@ -143,9 +143,6 @@
 		case 'f':
 			force = 1;
 			break;
-		case 'c':
-			check = 1;
-			break;
 		case 'q':
 			quiet++;
 			break;
diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c
index ead0332..28d0b23 100644
--- a/scripts/dtc/flattree.c
+++ b/scripts/dtc/flattree.c
@@ -697,7 +697,6 @@
 {
 	struct reserve_info *reservelist = NULL;
 	struct reserve_info *new;
-	const char *p;
 	struct fdt_reserve_entry re;
 
 	/*
@@ -706,7 +705,6 @@
 	 *
 	 * First pass, count entries.
 	 */
-	p = inb->ptr;
 	while (1) {
 		flat_read_chunk(inb, &re, sizeof(re));
 		re.address  = fdt64_to_cpu(re.address);
diff --git a/scripts/gcc-goto.sh b/scripts/gcc-goto.sh
index 98cffcb9..a2af2e8 100644
--- a/scripts/gcc-goto.sh
+++ b/scripts/gcc-goto.sh
@@ -2,4 +2,20 @@
 # Test for gcc 'asm goto' support
 # Copyright (C) 2010, Jason Baron <jbaron@redhat.com>
 
-echo "int main(void) { entry: asm goto (\"\"::::entry); return 0; }" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
+cat << "END" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
+int main(void)
+{
+#ifdef __arm__
+	/*
+	 * Not related to asm goto, but used by jump label
+	 * and broken on some ARM GCC versions (see GCC Bug 48637).
+	 */
+	static struct { int dummy; int state; } tp;
+	asm (".long %c0" :: "i" (&tp.state));
+#endif
+
+entry:
+	asm goto ("" :::: entry);
+	return 0;
+}
+END
diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
index f32a04c..0948c6b 100755
--- a/scripts/get_maintainer.pl
+++ b/scripts/get_maintainer.pl
@@ -931,7 +931,7 @@
     my $start = find_starting_index($index);
     my $end = find_ending_index($index);
 
-    my $role;
+    my $role = "unknown";
     my $subsystem = $typevalue[$start];
     if (length($subsystem) > 20) {
 	$subsystem = substr($subsystem, 0, 17);
@@ -1027,8 +1027,13 @@
 		    if ($email_list) {
 			if (!$hash_list_to{lc($list_address)}) {
 			    $hash_list_to{lc($list_address)} = 1;
-			    push(@list_to, [$list_address,
-					    "open list${list_role}"]);
+			    if ($list_additional =~ m/moderated/) {
+				push(@list_to, [$list_address,
+						"moderated list${list_role}"]);
+			    } else {
+				push(@list_to, [$list_address,
+						"open list${list_role}"]);
+			    }
 			}
 		    }
 		}
diff --git a/scripts/headers_check.pl b/scripts/headers_check.pl
index 7957e7a..64ac238 100644
--- a/scripts/headers_check.pl
+++ b/scripts/headers_check.pl
@@ -19,6 +19,7 @@
 # 3) Check for leaked CONFIG_ symbols
 
 use strict;
+use File::Basename;
 
 my ($dir, $arch, @files) = @ARGV;
 
@@ -99,6 +100,39 @@
 }
 
 my $linux_types;
+my %import_stack = ();
+sub check_include_typesh
+{
+	my $path = $_[0];
+	my $import_path;
+
+	my $fh;
+	my @file_paths = ($path, $dir . "/" .  $path, dirname($filename) . "/" . $path);
+	for my $possible ( @file_paths ) {
+	    if (not $import_stack{$possible} and open($fh, '<', $possible)) {
+		$import_path = $possible;
+		$import_stack{$import_path} = 1;
+		last;
+	    }
+	}
+	if (eof $fh) {
+	    return;
+	}
+
+	my $line;
+	while ($line = <$fh>) {
+		if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) {
+			$linux_types = 1;
+			last;
+		}
+		if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) {
+			check_include_typesh($included);
+		}
+	}
+	close $fh;
+	delete $import_stack{$import_path};
+}
+
 sub check_sizetypes
 {
 	if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
@@ -113,6 +147,9 @@
 		$linux_types = 1;
 		return;
 	}
+	if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) {
+		check_include_typesh($included);
+	}
 	if ($line =~ m/__[us](8|16|32|64)\b/) {
 		printf STDERR "$filename:$lineno: " .
 		              "found __[us]{8,16,32,64} type " .
@@ -122,4 +159,3 @@
 		#$ret = 1;
 	}
 }
-
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 7c7a5a6..0586085 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -344,10 +344,8 @@
 
 int conf_read(const char *name)
 {
-	struct symbol *sym, *choice_sym;
-	struct property *prop;
-	struct expr *e;
-	int i, flags;
+	struct symbol *sym;
+	int i;
 
 	sym_set_change_count(0);
 
@@ -357,7 +355,7 @@
 	for_all_symbols(i, sym) {
 		sym_calc_value(sym);
 		if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
-			goto sym_ok;
+			continue;
 		if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
 			/* check that calculated value agrees with saved value */
 			switch (sym->type) {
@@ -366,30 +364,18 @@
 				if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
 					break;
 				if (!sym_is_choice(sym))
-					goto sym_ok;
+					continue;
 				/* fall through */
 			default:
 				if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
-					goto sym_ok;
+					continue;
 				break;
 			}
 		} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
 			/* no previous value and not saved */
-			goto sym_ok;
+			continue;
 		conf_unsaved++;
 		/* maybe print value in verbose mode... */
-	sym_ok:
-		if (!sym_is_choice(sym))
-			continue;
-		/* The choice symbol only has a set value (and thus is not new)
-		 * if all its visible childs have values.
-		 */
-		prop = sym_get_choice_prop(sym);
-		flags = sym->flags;
-		expr_list_for_each_sym(prop->expr, e, choice_sym)
-			if (choice_sym->visible != no)
-				flags &= choice_sym->flags;
-		sym->flags &= flags | ~SYMBOL_DEF_USER;
 	}
 
 	for_all_symbols(i, sym) {
diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
old mode 100644
new mode 100755
index ceadf0e..974d5cb
--- a/scripts/kconfig/merge_config.sh
+++ b/scripts/kconfig/merge_config.sh
@@ -31,10 +31,12 @@
 	echo "  -h    display this help text"
 	echo "  -m    only merge the fragments, do not execute the make command"
 	echo "  -n    use allnoconfig instead of alldefconfig"
+	echo "  -r    list redundant entries when merging fragments"
 }
 
 MAKE=true
 ALLTARGET=alldefconfig
+WARNREDUN=false
 
 while true; do
 	case $1 in
@@ -52,18 +54,27 @@
 		usage
 		exit
 		;;
+	"-r")
+		WARNREDUN=true
+		shift
+		continue
+		;;
 	*)
 		break
 		;;
 	esac
 done
 
-
+INITFILE=$1
+shift;
 
 MERGE_LIST=$*
 SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p"
 TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
 
+echo "Using $INITFILE as base"
+cat $INITFILE > $TMP_FILE
+
 # Merge files, printing warnings on overrided values
 for MERGE_FILE in $MERGE_LIST ; do
 	echo "Merging $MERGE_FILE"
@@ -79,6 +90,8 @@
 			echo Previous  value: $PREV_VAL
 			echo New value:       $NEW_VAL
 			echo
+			elif [ "$WARNREDUN" = "true" ]; then
+			echo Value of $CFG is redundant by fragment $MERGE_FILE:
 			fi
 			sed -i "/$CFG[ =]/d" $TMP_FILE
 		fi
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 071f00c..22a3c40 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -262,11 +262,18 @@
 	struct symbol *def_sym;
 	struct property *prop;
 	struct expr *e;
+	int flags;
 
 	/* first calculate all choice values' visibilities */
+	flags = sym->flags;
 	prop = sym_get_choice_prop(sym);
-	expr_list_for_each_sym(prop->expr, e, def_sym)
+	expr_list_for_each_sym(prop->expr, e, def_sym) {
 		sym_calc_visibility(def_sym);
+		if (def_sym->visible != no)
+			flags &= def_sym->flags;
+	}
+
+	sym->flags &= flags | ~SYMBOL_DEF_USER;
 
 	/* is the user choice visible? */
 	def_sym = sym->def[S_DEF_USER].val;
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 9adb667..3f01fd9 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -849,7 +849,7 @@
 
 #define ALL_INIT_DATA_SECTIONS \
 	".init.setup$", ".init.rodata$", \
-	".devinit.rodata$", ".cpuinit.rodata$", ".meminit.rodata$" \
+	".devinit.rodata$", ".cpuinit.rodata$", ".meminit.rodata$", \
 	".init.data$", ".devinit.data$", ".cpuinit.data$", ".meminit.data$"
 #define ALL_EXIT_DATA_SECTIONS \
 	".exit.data$", ".devexit.data$", ".cpuexit.data$", ".memexit.data$"
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 3c6c0b1..eee5f8e 100644
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -97,6 +97,7 @@
 mkdir -p "$libc_headers_dir/usr/share/doc/$libc_headers_packagename"
 mkdir -m 755 -p "$kernel_headers_dir/DEBIAN"
 mkdir -p "$kernel_headers_dir/usr/share/doc/$kernel_headers_packagename"
+mkdir -p "$kernel_headers_dir/lib/modules/$version/"
 if [ "$ARCH" = "um" ] ; then
 	mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/bin"
 fi
@@ -120,15 +121,19 @@
 fi
 
 if grep -q '^CONFIG_MODULES=y' .config ; then
-	INSTALL_MOD_PATH="$tmpdir" make KBUILD_SRC= modules_install
+	INSTALL_MOD_PATH="$tmpdir" $MAKE KBUILD_SRC= modules_install
+	rm -f "$tmpdir/lib/modules/$version/build"
+	rm -f "$tmpdir/lib/modules/$version/source"
 	if [ "$ARCH" = "um" ] ; then
 		mv "$tmpdir/lib/modules/$version"/* "$tmpdir/usr/lib/uml/modules/$version/"
 		rmdir "$tmpdir/lib/modules/$version"
 	fi
 fi
 
-make headers_check
-make headers_install INSTALL_HDR_PATH="$libc_headers_dir/usr"
+if [ "$ARCH" != "um" ]; then
+	$MAKE headers_check KBUILD_SRC=
+	$MAKE headers_install KBUILD_SRC= INSTALL_HDR_PATH="$libc_headers_dir/usr"
+fi
 
 # Install the maintainer scripts
 # Note: hook scripts under /etc/kernel are also executed by official Debian
@@ -245,6 +250,7 @@
 mkdir -p "$destdir"
 (cd $srctree; tar -c -f - -T "$objtree/debian/hdrsrcfiles") | (cd $destdir; tar -xf -)
 (cd $objtree; tar -c -f - -T "$objtree/debian/hdrobjfiles") | (cd $destdir; tar -xf -)
+ln -sf "/usr/src/linux-headers-$version" "$kernel_headers_dir/lib/modules/$version/build"
 rm -f "$objtree/debian/hdrsrcfiles" "$objtree/debian/hdrobjfiles"
 arch=$(dpkg --print-architecture)
 
@@ -259,8 +265,6 @@
  This is useful for people who need to build external modules
 EOF
 
-create_package "$kernel_headers_packagename" "$kernel_headers_dir"
-
 # Do we have firmware? Move it out of the way and build it into a package.
 if [ -e "$tmpdir/lib/firmware" ]; then
 	mv "$tmpdir/lib/firmware" "$fwdir/lib/"
@@ -287,7 +291,11 @@
  are used by the installed headers for GNU glibc and other system libraries.
 EOF
 
-create_package "$libc_headers_packagename" "$libc_headers_dir"
+if [ "$ARCH" != "um" ]; then
+	create_package "$kernel_headers_packagename" "$kernel_headers_dir"
+	create_package "$libc_headers_packagename" "$libc_headers_dir"
+fi
+
 create_package "$packagename" "$tmpdir"
 
 exit 0
diff --git a/scripts/patch-kernel b/scripts/patch-kernel
index 20fb25c..d000ea3 100755
--- a/scripts/patch-kernel
+++ b/scripts/patch-kernel
@@ -116,6 +116,10 @@
 		ext=".bz2"
 		name="bzip2"
 		uncomp="bunzip2 -dc"
+  elif [ -r ${filebase}.xz ]; then
+                ext=".xz"
+                name="xz"
+                uncomp="xz -dc"
   elif [ -r ${filebase}.zip ]; then
 		ext=".zip"
 		name="zip"
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 4d40384..bd6dca8 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -75,8 +75,7 @@
 		[ -w . ] && git update-index --refresh --unmerged > /dev/null
 
 		# Check for uncommitted changes
-		if git diff-index --name-only HEAD | grep -v "^scripts/package" \
-		    | read dummy; then
+		if git diff-index --name-only HEAD | grep -qv "^scripts/package"; then
 			printf '%s' -dirty
 		fi
 
diff --git a/scripts/tags.sh b/scripts/tags.sh
index 833813a..cf7b12f 100755
--- a/scripts/tags.sh
+++ b/scripts/tags.sh
@@ -116,7 +116,7 @@
 
 dogtags()
 {
-	all_sources | gtags -f -
+	all_sources | gtags -i -f -
 }
 
 exuberant()
@@ -166,9 +166,6 @@
 	all_defconfigs | xargs -r $1 -a                         \
 	--langdef=dotconfig --language-force=dotconfig          \
 	--regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/'
-
-	# Remove structure forward declarations.
-	LANG=C sed -i -e '/^\([a-zA-Z_][a-zA-Z0-9_]*\)\t.*\t\/\^struct \1;.*\$\/;"\tx$/d' tags
 }
 
 emacs()
@@ -233,6 +230,7 @@
 	fi
 fi
 
+remove_structs=
 case "$1" in
 	"cscope")
 		docscope
@@ -245,10 +243,17 @@
 	"tags")
 		rm -f tags
 		xtags ctags
+		remove_structs=y
 		;;
 
 	"TAGS")
 		rm -f TAGS
 		xtags etags
+		remove_structs=y
 		;;
 esac
+
+# Remove structure forward declarations.
+if [ -n "$remove_structs" ]; then
+    LANG=C sed -i -e '/^\([a-zA-Z_][a-zA-Z0-9_]*\)\t.*\t\/\^struct \1;.*\$\/;"\tx$/d' $1
+fi
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index 5ff6777..cc3520d 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -115,23 +115,23 @@
 
 	if (aa_g_audit_header) {
 		audit_log_format(ab, "apparmor=");
-		audit_log_string(ab, aa_audit_type[sa->aad.type]);
+		audit_log_string(ab, aa_audit_type[sa->aad->type]);
 	}
 
-	if (sa->aad.op) {
+	if (sa->aad->op) {
 		audit_log_format(ab, " operation=");
-		audit_log_string(ab, op_table[sa->aad.op]);
+		audit_log_string(ab, op_table[sa->aad->op]);
 	}
 
-	if (sa->aad.info) {
+	if (sa->aad->info) {
 		audit_log_format(ab, " info=");
-		audit_log_string(ab, sa->aad.info);
-		if (sa->aad.error)
-			audit_log_format(ab, " error=%d", sa->aad.error);
+		audit_log_string(ab, sa->aad->info);
+		if (sa->aad->error)
+			audit_log_format(ab, " error=%d", sa->aad->error);
 	}
 
-	if (sa->aad.profile) {
-		struct aa_profile *profile = sa->aad.profile;
+	if (sa->aad->profile) {
+		struct aa_profile *profile = sa->aad->profile;
 		pid_t pid;
 		rcu_read_lock();
 		pid = rcu_dereference(tsk->real_parent)->pid;
@@ -145,9 +145,9 @@
 		audit_log_untrustedstring(ab, profile->base.hname);
 	}
 
-	if (sa->aad.name) {
+	if (sa->aad->name) {
 		audit_log_format(ab, " name=");
-		audit_log_untrustedstring(ab, sa->aad.name);
+		audit_log_untrustedstring(ab, sa->aad->name);
 	}
 }
 
@@ -159,10 +159,8 @@
 void aa_audit_msg(int type, struct common_audit_data *sa,
 		  void (*cb) (struct audit_buffer *, void *))
 {
-	sa->aad.type = type;
-	sa->lsm_pre_audit = audit_pre;
-	sa->lsm_post_audit = cb;
-	common_lsm_audit(sa);
+	sa->aad->type = type;
+	common_lsm_audit(sa, audit_pre, cb);
 }
 
 /**
@@ -184,7 +182,7 @@
 	BUG_ON(!profile);
 
 	if (type == AUDIT_APPARMOR_AUTO) {
-		if (likely(!sa->aad.error)) {
+		if (likely(!sa->aad->error)) {
 			if (AUDIT_MODE(profile) != AUDIT_ALL)
 				return 0;
 			type = AUDIT_APPARMOR_AUDIT;
@@ -196,21 +194,21 @@
 	if (AUDIT_MODE(profile) == AUDIT_QUIET ||
 	    (type == AUDIT_APPARMOR_DENIED &&
 	     AUDIT_MODE(profile) == AUDIT_QUIET))
-		return sa->aad.error;
+		return sa->aad->error;
 
 	if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
 		type = AUDIT_APPARMOR_KILL;
 
 	if (!unconfined(profile))
-		sa->aad.profile = profile;
+		sa->aad->profile = profile;
 
 	aa_audit_msg(type, sa, cb);
 
-	if (sa->aad.type == AUDIT_APPARMOR_KILL)
+	if (sa->aad->type == AUDIT_APPARMOR_KILL)
 		(void)send_sig_info(SIGKILL, NULL, sa->tsk ? sa->tsk : current);
 
-	if (sa->aad.type == AUDIT_APPARMOR_ALLOWED)
-		return complain_error(sa->aad.error);
+	if (sa->aad->type == AUDIT_APPARMOR_ALLOWED)
+		return complain_error(sa->aad->error);
 
-	return sa->aad.error;
+	return sa->aad->error;
 }
diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c
index 9982c48..088dba3 100644
--- a/security/apparmor/capability.c
+++ b/security/apparmor/capability.c
@@ -64,11 +64,13 @@
 	struct audit_cache *ent;
 	int type = AUDIT_APPARMOR_AUTO;
 	struct common_audit_data sa;
+	struct apparmor_audit_data aad = {0,};
 	COMMON_AUDIT_DATA_INIT(&sa, CAP);
+	sa.aad = &aad;
 	sa.tsk = task;
 	sa.u.cap = cap;
-	sa.aad.op = OP_CAPABLE;
-	sa.aad.error = error;
+	sa.aad->op = OP_CAPABLE;
+	sa.aad->error = error;
 
 	if (likely(!error)) {
 		/* test if auditing is being forced */
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 7c69599..6327685 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -410,7 +410,8 @@
 		 * exec\0change_profile
 		 */
 		state = aa_dfa_null_transition(profile->file.dfa, state);
-		cp = change_profile_perms(profile, cxt->onexec->ns, name,
+		cp = change_profile_perms(profile, cxt->onexec->ns,
+					  cxt->onexec->base.name,
 					  AA_MAY_ONEXEC, state);
 
 		if (!(cp.allow & AA_MAY_ONEXEC))
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index 3022c0f..2f8fcba 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -67,22 +67,22 @@
 	struct common_audit_data *sa = va;
 	uid_t fsuid = current_fsuid();
 
-	if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
+	if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) {
 		audit_log_format(ab, " requested_mask=");
-		audit_file_mask(ab, sa->aad.fs.request);
+		audit_file_mask(ab, sa->aad->fs.request);
 	}
-	if (sa->aad.fs.denied & AA_AUDIT_FILE_MASK) {
+	if (sa->aad->fs.denied & AA_AUDIT_FILE_MASK) {
 		audit_log_format(ab, " denied_mask=");
-		audit_file_mask(ab, sa->aad.fs.denied);
+		audit_file_mask(ab, sa->aad->fs.denied);
 	}
-	if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
+	if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) {
 		audit_log_format(ab, " fsuid=%d", fsuid);
-		audit_log_format(ab, " ouid=%d", sa->aad.fs.ouid);
+		audit_log_format(ab, " ouid=%d", sa->aad->fs.ouid);
 	}
 
-	if (sa->aad.fs.target) {
+	if (sa->aad->fs.target) {
 		audit_log_format(ab, " target=");
-		audit_log_untrustedstring(ab, sa->aad.fs.target);
+		audit_log_untrustedstring(ab, sa->aad->fs.target);
 	}
 }
 
@@ -107,45 +107,47 @@
 {
 	int type = AUDIT_APPARMOR_AUTO;
 	struct common_audit_data sa;
+	struct apparmor_audit_data aad = {0,};
 	COMMON_AUDIT_DATA_INIT(&sa, NONE);
-	sa.aad.op = op,
-	sa.aad.fs.request = request;
-	sa.aad.name = name;
-	sa.aad.fs.target = target;
-	sa.aad.fs.ouid = ouid;
-	sa.aad.info = info;
-	sa.aad.error = error;
+	sa.aad = &aad;
+	aad.op = op,
+	aad.fs.request = request;
+	aad.name = name;
+	aad.fs.target = target;
+	aad.fs.ouid = ouid;
+	aad.info = info;
+	aad.error = error;
 
-	if (likely(!sa.aad.error)) {
+	if (likely(!sa.aad->error)) {
 		u32 mask = perms->audit;
 
 		if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
 			mask = 0xffff;
 
 		/* mask off perms that are not being force audited */
-		sa.aad.fs.request &= mask;
+		sa.aad->fs.request &= mask;
 
-		if (likely(!sa.aad.fs.request))
+		if (likely(!sa.aad->fs.request))
 			return 0;
 		type = AUDIT_APPARMOR_AUDIT;
 	} else {
 		/* only report permissions that were denied */
-		sa.aad.fs.request = sa.aad.fs.request & ~perms->allow;
+		sa.aad->fs.request = sa.aad->fs.request & ~perms->allow;
 
-		if (sa.aad.fs.request & perms->kill)
+		if (sa.aad->fs.request & perms->kill)
 			type = AUDIT_APPARMOR_KILL;
 
 		/* quiet known rejects, assumes quiet and kill do not overlap */
-		if ((sa.aad.fs.request & perms->quiet) &&
+		if ((sa.aad->fs.request & perms->quiet) &&
 		    AUDIT_MODE(profile) != AUDIT_NOQUIET &&
 		    AUDIT_MODE(profile) != AUDIT_ALL)
-			sa.aad.fs.request &= ~perms->quiet;
+			sa.aad->fs.request &= ~perms->quiet;
 
-		if (!sa.aad.fs.request)
-			return COMPLAIN_MODE(profile) ? 0 : sa.aad.error;
+		if (!sa.aad->fs.request)
+			return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
 	}
 
-	sa.aad.fs.denied = sa.aad.fs.request & ~perms->allow;
+	sa.aad->fs.denied = sa.aad->fs.request & ~perms->allow;
 	return aa_audit(type, profile, gfp, &sa, file_audit_cb);
 }
 
@@ -215,6 +217,8 @@
 	/* change_profile wasn't determined by ownership in old mapping */
 	if (ACCEPT_TABLE(dfa)[state] & 0x80000000)
 		perms.allow |= AA_MAY_CHANGE_PROFILE;
+	if (ACCEPT_TABLE(dfa)[state] & 0x40000000)
+		perms.allow |= AA_MAY_ONEXEC;
 
 	return perms;
 }
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index 4ba78c2..3868b1e 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -103,7 +103,33 @@
 };
 
 
-/* define a short hand for apparmor_audit_data portion of common_audit_data */
+struct apparmor_audit_data {
+	int error;
+	int op;
+	int type;
+	void *profile;
+	const char *name;
+	const char *info;
+	union {
+		void *target;
+		struct {
+			long pos;
+			void *target;
+		} iface;
+		struct {
+			int rlim;
+			unsigned long max;
+		} rlim;
+		struct {
+			const char *target;
+			u32 request;
+			u32 denied;
+			uid_t ouid;
+		} fs;
+	};
+};
+
+/* define a short hand for apparmor_audit_data structure */
 #define aad apparmor_audit_data
 
 void aa_audit_msg(int type, struct common_audit_data *sa,
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
index 7ee05c6..c3da93a 100644
--- a/security/apparmor/ipc.c
+++ b/security/apparmor/ipc.c
@@ -26,7 +26,7 @@
 {
 	struct common_audit_data *sa = va;
 	audit_log_format(ab, " target=");
-	audit_log_untrustedstring(ab, sa->aad.target);
+	audit_log_untrustedstring(ab, sa->aad->target);
 }
 
 /**
@@ -41,10 +41,12 @@
 			   struct aa_profile *target, int error)
 {
 	struct common_audit_data sa;
+	struct apparmor_audit_data aad = {0,};
 	COMMON_AUDIT_DATA_INIT(&sa, NONE);
-	sa.aad.op = OP_PTRACE;
-	sa.aad.target = target;
-	sa.aad.error = error;
+	sa.aad = &aad;
+	aad.op = OP_PTRACE;
+	aad.target = target;
+	aad.error = error;
 
 	return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa,
 			audit_cb);
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
index 9516948..e75829b 100644
--- a/security/apparmor/lib.c
+++ b/security/apparmor/lib.c
@@ -65,8 +65,10 @@
 {
 	if (audit_enabled) {
 		struct common_audit_data sa;
+		struct apparmor_audit_data aad = {0,};
 		COMMON_AUDIT_DATA_INIT(&sa, NONE);
-		sa.aad.info = str;
+		sa.aad = &aad;
+		aad.info = str;
 		aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
 	}
 	printk(KERN_INFO "AppArmor: %s\n", str);
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 97ce8fa..ad05d39 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -588,10 +588,12 @@
 			error = aa_setprocattr_permipc(args);
 		} else {
 			struct common_audit_data sa;
+			struct apparmor_audit_data aad = {0,};
 			COMMON_AUDIT_DATA_INIT(&sa, NONE);
-			sa.aad.op = OP_SETPROCATTR;
-			sa.aad.info = name;
-			sa.aad.error = -EINVAL;
+			sa.aad = &aad;
+			aad.op = OP_SETPROCATTR;
+			aad.info = name;
+			aad.error = -EINVAL;
 			return aa_audit(AUDIT_APPARMOR_DENIED,
 					__aa_current_profile(), GFP_KERNEL,
 					&sa, NULL);
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 9064143..f1f7506 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -964,11 +964,13 @@
 			int error)
 {
 	struct common_audit_data sa;
+	struct apparmor_audit_data aad = {0,};
 	COMMON_AUDIT_DATA_INIT(&sa, NONE);
-	sa.aad.op = op;
-	sa.aad.name = name;
-	sa.aad.info = info;
-	sa.aad.error = error;
+	sa.aad = &aad;
+	aad.op = op;
+	aad.name = name;
+	aad.info = info;
+	aad.error = error;
 
 	return aa_audit(AUDIT_APPARMOR_STATUS, __aa_current_profile(), gfp,
 			&sa, NULL);
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 25fd51e..deab7c7 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -70,13 +70,13 @@
 static void audit_cb(struct audit_buffer *ab, void *va)
 {
 	struct common_audit_data *sa = va;
-	if (sa->aad.iface.target) {
-		struct aa_profile *name = sa->aad.iface.target;
+	if (sa->aad->iface.target) {
+		struct aa_profile *name = sa->aad->iface.target;
 		audit_log_format(ab, " name=");
 		audit_log_untrustedstring(ab, name->base.hname);
 	}
-	if (sa->aad.iface.pos)
-		audit_log_format(ab, " offset=%ld", sa->aad.iface.pos);
+	if (sa->aad->iface.pos)
+		audit_log_format(ab, " offset=%ld", sa->aad->iface.pos);
 }
 
 /**
@@ -94,13 +94,15 @@
 {
 	struct aa_profile *profile = __aa_current_profile();
 	struct common_audit_data sa;
+	struct apparmor_audit_data aad = {0,};
 	COMMON_AUDIT_DATA_INIT(&sa, NONE);
+	sa.aad = &aad;
 	if (e)
-		sa.aad.iface.pos = e->pos - e->start;
-	sa.aad.iface.target = new;
-	sa.aad.name = name;
-	sa.aad.info = info;
-	sa.aad.error = error;
+		aad.iface.pos = e->pos - e->start;
+	aad.iface.target = new;
+	aad.name = name;
+	aad.info = info;
+	aad.error = error;
 
 	return aa_audit(AUDIT_APPARMOR_STATUS, profile, GFP_KERNEL, &sa,
 			audit_cb);
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
index 72c25a4f..2fe8613 100644
--- a/security/apparmor/resource.c
+++ b/security/apparmor/resource.c
@@ -34,7 +34,7 @@
 	struct common_audit_data *sa = va;
 
 	audit_log_format(ab, " rlimit=%s value=%lu",
-			 rlim_names[sa->aad.rlim.rlim], sa->aad.rlim.max);
+			 rlim_names[sa->aad->rlim.rlim], sa->aad->rlim.max);
 }
 
 /**
@@ -50,12 +50,14 @@
 			  unsigned long value, int error)
 {
 	struct common_audit_data sa;
+	struct apparmor_audit_data aad = {0,};
 
 	COMMON_AUDIT_DATA_INIT(&sa, NONE);
-	sa.aad.op = OP_SETRLIMIT,
-	sa.aad.rlim.rlim = resource;
-	sa.aad.rlim.max = value;
-	sa.aad.error = error;
+	sa.aad = &aad;
+	aad.op = OP_SETRLIMIT,
+	aad.rlim.rlim = resource;
+	aad.rlim.max = value;
+	aad.error = error;
 	return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_KERNEL, &sa,
 			audit_cb);
 }
diff --git a/security/keys/key.c b/security/keys/key.c
index 7ada801..06783cf 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -671,6 +671,26 @@
 	return ktype;
 }
 
+void key_set_timeout(struct key *key, unsigned timeout)
+{
+	struct timespec now;
+	time_t expiry = 0;
+
+	/* make the changes with the locks held to prevent races */
+	down_write(&key->sem);
+
+	if (timeout > 0) {
+		now = current_kernel_time();
+		expiry = now.tv_sec + timeout;
+	}
+
+	key->expiry = expiry;
+	key_schedule_gc(key->expiry + key_gc_delay);
+
+	up_write(&key->sem);
+}
+EXPORT_SYMBOL_GPL(key_set_timeout);
+
 /*
  * Unlock a key type locked by key_type_lookup().
  */
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 6523599..fb767c6 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/syscalls.h>
+#include <linux/key.h>
 #include <linux/keyctl.h>
 #include <linux/fs.h>
 #include <linux/capability.h>
@@ -1257,10 +1258,8 @@
  */
 long keyctl_set_timeout(key_serial_t id, unsigned timeout)
 {
-	struct timespec now;
 	struct key *key, *instkey;
 	key_ref_t key_ref;
-	time_t expiry;
 	long ret;
 
 	key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
@@ -1286,20 +1285,7 @@
 
 okay:
 	key = key_ref_to_ptr(key_ref);
-
-	/* make the changes with the locks held to prevent races */
-	down_write(&key->sem);
-
-	expiry = 0;
-	if (timeout > 0) {
-		now = current_kernel_time();
-		expiry = now.tv_sec + timeout;
-	}
-
-	key->expiry = expiry;
-	key_schedule_gc(key->expiry + key_gc_delay);
-
-	up_write(&key->sem);
+	key_set_timeout(key, timeout);
 	key_put(key);
 
 	ret = 0;
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 8246532..cc37903 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -91,7 +91,7 @@
  * Call a usermode helper with a specific session keyring.
  */
 static int call_usermodehelper_keys(char *path, char **argv, char **envp,
-			 struct key *session_keyring, enum umh_wait wait)
+					struct key *session_keyring, int wait)
 {
 	gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
 	struct subprocess_info *info =
diff --git a/security/lsm_audit.c b/security/lsm_audit.c
index 293b8c4..90c129b 100644
--- a/security/lsm_audit.c
+++ b/security/lsm_audit.c
@@ -49,8 +49,8 @@
 	if (ih == NULL)
 		return -EINVAL;
 
-	ad->u.net.v4info.saddr = ih->saddr;
-	ad->u.net.v4info.daddr = ih->daddr;
+	ad->u.net->v4info.saddr = ih->saddr;
+	ad->u.net->v4info.daddr = ih->daddr;
 
 	if (proto)
 		*proto = ih->protocol;
@@ -64,8 +64,8 @@
 		if (th == NULL)
 			break;
 
-		ad->u.net.sport = th->source;
-		ad->u.net.dport = th->dest;
+		ad->u.net->sport = th->source;
+		ad->u.net->dport = th->dest;
 		break;
 	}
 	case IPPROTO_UDP: {
@@ -73,8 +73,8 @@
 		if (uh == NULL)
 			break;
 
-		ad->u.net.sport = uh->source;
-		ad->u.net.dport = uh->dest;
+		ad->u.net->sport = uh->source;
+		ad->u.net->dport = uh->dest;
 		break;
 	}
 	case IPPROTO_DCCP: {
@@ -82,16 +82,16 @@
 		if (dh == NULL)
 			break;
 
-		ad->u.net.sport = dh->dccph_sport;
-		ad->u.net.dport = dh->dccph_dport;
+		ad->u.net->sport = dh->dccph_sport;
+		ad->u.net->dport = dh->dccph_dport;
 		break;
 	}
 	case IPPROTO_SCTP: {
 		struct sctphdr *sh = sctp_hdr(skb);
 		if (sh == NULL)
 			break;
-		ad->u.net.sport = sh->source;
-		ad->u.net.dport = sh->dest;
+		ad->u.net->sport = sh->source;
+		ad->u.net->dport = sh->dest;
 		break;
 	}
 	default:
@@ -119,8 +119,8 @@
 	ip6 = ipv6_hdr(skb);
 	if (ip6 == NULL)
 		return -EINVAL;
-	ad->u.net.v6info.saddr = ip6->saddr;
-	ad->u.net.v6info.daddr = ip6->daddr;
+	ad->u.net->v6info.saddr = ip6->saddr;
+	ad->u.net->v6info.daddr = ip6->daddr;
 	ret = 0;
 	/* IPv6 can have several extension header before the Transport header
 	 * skip them */
@@ -140,8 +140,8 @@
 		if (th == NULL)
 			break;
 
-		ad->u.net.sport = th->source;
-		ad->u.net.dport = th->dest;
+		ad->u.net->sport = th->source;
+		ad->u.net->dport = th->dest;
 		break;
 	}
 	case IPPROTO_UDP: {
@@ -151,8 +151,8 @@
 		if (uh == NULL)
 			break;
 
-		ad->u.net.sport = uh->source;
-		ad->u.net.dport = uh->dest;
+		ad->u.net->sport = uh->source;
+		ad->u.net->dport = uh->dest;
 		break;
 	}
 	case IPPROTO_DCCP: {
@@ -162,8 +162,8 @@
 		if (dh == NULL)
 			break;
 
-		ad->u.net.sport = dh->dccph_sport;
-		ad->u.net.dport = dh->dccph_dport;
+		ad->u.net->sport = dh->dccph_sport;
+		ad->u.net->dport = dh->dccph_dport;
 		break;
 	}
 	case IPPROTO_SCTP: {
@@ -172,8 +172,8 @@
 		sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
 		if (sh == NULL)
 			break;
-		ad->u.net.sport = sh->source;
-		ad->u.net.dport = sh->dest;
+		ad->u.net->sport = sh->source;
+		ad->u.net->dport = sh->dest;
 		break;
 	}
 	default:
@@ -281,8 +281,8 @@
 		}
 		break;
 	case LSM_AUDIT_DATA_NET:
-		if (a->u.net.sk) {
-			struct sock *sk = a->u.net.sk;
+		if (a->u.net->sk) {
+			struct sock *sk = a->u.net->sk;
 			struct unix_sock *u;
 			int len = 0;
 			char *p = NULL;
@@ -313,12 +313,8 @@
 			}
 			case AF_UNIX:
 				u = unix_sk(sk);
-				if (u->dentry) {
-					struct path path = {
-						.dentry = u->dentry,
-						.mnt = u->mnt
-					};
-					audit_log_d_path(ab, " path=", &path);
+				if (u->path.dentry) {
+					audit_log_d_path(ab, " path=", &u->path);
 					break;
 				}
 				if (!u->addr)
@@ -334,29 +330,29 @@
 			}
 		}
 
-		switch (a->u.net.family) {
+		switch (a->u.net->family) {
 		case AF_INET:
-			print_ipv4_addr(ab, a->u.net.v4info.saddr,
-					a->u.net.sport,
+			print_ipv4_addr(ab, a->u.net->v4info.saddr,
+					a->u.net->sport,
 					"saddr", "src");
-			print_ipv4_addr(ab, a->u.net.v4info.daddr,
-					a->u.net.dport,
+			print_ipv4_addr(ab, a->u.net->v4info.daddr,
+					a->u.net->dport,
 					"daddr", "dest");
 			break;
 		case AF_INET6:
-			print_ipv6_addr(ab, &a->u.net.v6info.saddr,
-					a->u.net.sport,
+			print_ipv6_addr(ab, &a->u.net->v6info.saddr,
+					a->u.net->sport,
 					"saddr", "src");
-			print_ipv6_addr(ab, &a->u.net.v6info.daddr,
-					a->u.net.dport,
+			print_ipv6_addr(ab, &a->u.net->v6info.daddr,
+					a->u.net->dport,
 					"daddr", "dest");
 			break;
 		}
-		if (a->u.net.netif > 0) {
+		if (a->u.net->netif > 0) {
 			struct net_device *dev;
 
 			/* NOTE: we always use init's namespace */
-			dev = dev_get_by_index(&init_net, a->u.net.netif);
+			dev = dev_get_by_index(&init_net, a->u.net->netif);
 			if (dev) {
 				audit_log_format(ab, " netif=%s", dev->name);
 				dev_put(dev);
@@ -382,11 +378,15 @@
 /**
  * common_lsm_audit - generic LSM auditing function
  * @a:  auxiliary audit data
+ * @pre_audit: lsm-specific pre-audit callback
+ * @post_audit: lsm-specific post-audit callback
  *
  * setup the audit buffer for common security information
  * uses callback to print LSM specific information
  */
-void common_lsm_audit(struct common_audit_data *a)
+void common_lsm_audit(struct common_audit_data *a,
+	void (*pre_audit)(struct audit_buffer *, void *),
+	void (*post_audit)(struct audit_buffer *, void *))
 {
 	struct audit_buffer *ab;
 
@@ -398,13 +398,13 @@
 	if (ab == NULL)
 		return;
 
-	if (a->lsm_pre_audit)
-		a->lsm_pre_audit(ab, a);
+	if (pre_audit)
+		pre_audit(ab, a);
 
 	dump_common_audit_data(ab, a);
 
-	if (a->lsm_post_audit)
-		a->lsm_post_audit(ab, a);
+	if (post_audit)
+		post_audit(ab, a);
 
 	audit_log_end(ab);
 }
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index dca1c22..8ee42b2 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -436,9 +436,9 @@
 {
 	struct common_audit_data *ad = a;
 	audit_log_format(ab, "avc:  %s ",
-			 ad->selinux_audit_data.denied ? "denied" : "granted");
-	avc_dump_av(ab, ad->selinux_audit_data.tclass,
-			ad->selinux_audit_data.audited);
+			 ad->selinux_audit_data->slad->denied ? "denied" : "granted");
+	avc_dump_av(ab, ad->selinux_audit_data->slad->tclass,
+			ad->selinux_audit_data->slad->audited);
 	audit_log_format(ab, " for ");
 }
 
@@ -452,9 +452,48 @@
 {
 	struct common_audit_data *ad = a;
 	audit_log_format(ab, " ");
-	avc_dump_query(ab, ad->selinux_audit_data.ssid,
-			   ad->selinux_audit_data.tsid,
-			   ad->selinux_audit_data.tclass);
+	avc_dump_query(ab, ad->selinux_audit_data->slad->ssid,
+			   ad->selinux_audit_data->slad->tsid,
+			   ad->selinux_audit_data->slad->tclass);
+}
+
+/* This is the slow part of avc audit with big stack footprint */
+static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
+		u32 requested, u32 audited, u32 denied,
+		struct common_audit_data *a,
+		unsigned flags)
+{
+	struct common_audit_data stack_data;
+	struct selinux_audit_data sad = {0,};
+	struct selinux_late_audit_data slad;
+
+	if (!a) {
+		a = &stack_data;
+		COMMON_AUDIT_DATA_INIT(a, NONE);
+		a->selinux_audit_data = &sad;
+	}
+
+	/*
+	 * When in a RCU walk do the audit on the RCU retry.  This is because
+	 * the collection of the dname in an inode audit message is not RCU
+	 * safe.  Note this may drop some audits when the situation changes
+	 * during retry. However this is logically just as if the operation
+	 * happened a little later.
+	 */
+	if ((a->type == LSM_AUDIT_DATA_INODE) &&
+	    (flags & MAY_NOT_BLOCK))
+		return -ECHILD;
+
+	slad.tclass = tclass;
+	slad.requested = requested;
+	slad.ssid = ssid;
+	slad.tsid = tsid;
+	slad.audited = audited;
+	slad.denied = denied;
+
+	a->selinux_audit_data->slad = &slad;
+	common_lsm_audit(a, avc_audit_pre_callback, avc_audit_post_callback);
+	return 0;
 }
 
 /**
@@ -477,18 +516,17 @@
  * be performed under a lock, to allow the lock to be released
  * before calling the auditing code.
  */
-int avc_audit(u32 ssid, u32 tsid,
+inline int avc_audit(u32 ssid, u32 tsid,
 	       u16 tclass, u32 requested,
 	       struct av_decision *avd, int result, struct common_audit_data *a,
 	       unsigned flags)
 {
-	struct common_audit_data stack_data;
 	u32 denied, audited;
 	denied = requested & ~avd->allowed;
-	if (denied) {
+	if (unlikely(denied)) {
 		audited = denied & avd->auditdeny;
 		/*
-		 * a->selinux_audit_data.auditdeny is TRICKY!  Setting a bit in
+		 * a->selinux_audit_data->auditdeny is TRICKY!  Setting a bit in
 		 * this field means that ANY denials should NOT be audited if
 		 * the policy contains an explicit dontaudit rule for that
 		 * permission.  Take notice that this is unrelated to the
@@ -497,49 +535,26 @@
 		 *
 		 * denied == READ
 		 * avd.auditdeny & ACCESS == 0 (not set means explicit rule)
-		 * selinux_audit_data.auditdeny & ACCESS == 1
+		 * selinux_audit_data->auditdeny & ACCESS == 1
 		 *
 		 * We will NOT audit the denial even though the denied
 		 * permission was READ and the auditdeny checks were for
 		 * ACCESS
 		 */
 		if (a &&
-		    a->selinux_audit_data.auditdeny &&
-		    !(a->selinux_audit_data.auditdeny & avd->auditdeny))
+		    a->selinux_audit_data->auditdeny &&
+		    !(a->selinux_audit_data->auditdeny & avd->auditdeny))
 			audited = 0;
 	} else if (result)
 		audited = denied = requested;
 	else
 		audited = requested & avd->auditallow;
-	if (!audited)
+	if (likely(!audited))
 		return 0;
 
-	if (!a) {
-		a = &stack_data;
-		COMMON_AUDIT_DATA_INIT(a, NONE);
-	}
-
-	/*
-	 * When in a RCU walk do the audit on the RCU retry.  This is because
-	 * the collection of the dname in an inode audit message is not RCU
-	 * safe.  Note this may drop some audits when the situation changes
-	 * during retry. However this is logically just as if the operation
-	 * happened a little later.
-	 */
-	if ((a->type == LSM_AUDIT_DATA_INODE) &&
-	    (flags & MAY_NOT_BLOCK))
-		return -ECHILD;
-
-	a->selinux_audit_data.tclass = tclass;
-	a->selinux_audit_data.requested = requested;
-	a->selinux_audit_data.ssid = ssid;
-	a->selinux_audit_data.tsid = tsid;
-	a->selinux_audit_data.audited = audited;
-	a->selinux_audit_data.denied = denied;
-	a->lsm_pre_audit = avc_audit_pre_callback;
-	a->lsm_post_audit = avc_audit_post_callback;
-	common_lsm_audit(a);
-	return 0;
+	return slow_avc_audit(ssid, tsid, tclass,
+		requested, audited, denied,
+		a, flags);
 }
 
 /**
@@ -729,6 +744,41 @@
 	return rc;
 }
 
+/*
+ * Slow-path helper function for avc_has_perm_noaudit,
+ * when the avc_node lookup fails. We get called with
+ * the RCU read lock held, and need to return with it
+ * still held, but drop if for the security compute.
+ *
+ * Don't inline this, since it's the slow-path and just
+ * results in a bigger stack frame.
+ */
+static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid,
+			 u16 tclass, struct av_decision *avd)
+{
+	rcu_read_unlock();
+	security_compute_av(ssid, tsid, tclass, avd);
+	rcu_read_lock();
+	return avc_insert(ssid, tsid, tclass, avd);
+}
+
+static noinline int avc_denied(u32 ssid, u32 tsid,
+			 u16 tclass, u32 requested,
+			 unsigned flags,
+			 struct av_decision *avd)
+{
+	if (flags & AVC_STRICT)
+		return -EACCES;
+
+	if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE))
+		return -EACCES;
+
+	avc_update_node(AVC_CALLBACK_GRANT, requested, ssid,
+				tsid, tclass, avd->seqno);
+	return 0;
+}
+
+
 /**
  * avc_has_perm_noaudit - Check permissions but perform no auditing.
  * @ssid: source security identifier
@@ -749,7 +799,7 @@
  * auditing, e.g. in cases where a lock must be held for the check but
  * should be released for the auditing.
  */
-int avc_has_perm_noaudit(u32 ssid, u32 tsid,
+inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
 			 u16 tclass, u32 requested,
 			 unsigned flags,
 			 struct av_decision *avd)
@@ -764,26 +814,15 @@
 
 	node = avc_lookup(ssid, tsid, tclass);
 	if (unlikely(!node)) {
-		rcu_read_unlock();
-		security_compute_av(ssid, tsid, tclass, avd);
-		rcu_read_lock();
-		node = avc_insert(ssid, tsid, tclass, avd);
+		node = avc_compute_av(ssid, tsid, tclass, avd);
 	} else {
 		memcpy(avd, &node->ae.avd, sizeof(*avd));
 		avd = &node->ae.avd;
 	}
 
 	denied = requested & ~(avd->allowed);
-
-	if (denied) {
-		if (flags & AVC_STRICT)
-			rc = -EACCES;
-		else if (!selinux_enforcing || (avd->flags & AVD_FLAGS_PERMISSIVE))
-			avc_update_node(AVC_CALLBACK_GRANT, requested, ssid,
-					tsid, tclass, avd->seqno);
-		else
-			rc = -EACCES;
-	}
+	if (unlikely(denied))
+		rc = avc_denied(ssid, tsid, tclass, requested, flags, avd);
 
 	rcu_read_unlock();
 	return rc;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 3049299..d85b793 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -28,7 +28,6 @@
 #include <linux/kernel.h>
 #include <linux/tracehook.h>
 #include <linux/errno.h>
-#include <linux/ext2_fs.h>
 #include <linux/sched.h>
 #include <linux/security.h>
 #include <linux/xattr.h>
@@ -1421,6 +1420,7 @@
 			       int cap, int audit)
 {
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	struct av_decision avd;
 	u16 sclass;
 	u32 sid = cred_sid(cred);
@@ -1428,6 +1428,7 @@
 	int rc;
 
 	COMMON_AUDIT_DATA_INIT(&ad, CAP);
+	ad.selinux_audit_data = &sad;
 	ad.tsk = current;
 	ad.u.cap = cap;
 
@@ -1493,9 +1494,11 @@
 				unsigned flags)
 {
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 
 	COMMON_AUDIT_DATA_INIT(&ad, INODE);
 	ad.u.inode = inode;
+	ad.selinux_audit_data = &sad;
 	return inode_has_perm(cred, inode, perms, &ad, flags);
 }
 
@@ -1508,9 +1511,11 @@
 {
 	struct inode *inode = dentry->d_inode;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 
 	COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
 	ad.u.dentry = dentry;
+	ad.selinux_audit_data = &sad;
 	return inode_has_perm(cred, inode, av, &ad, 0);
 }
 
@@ -1523,9 +1528,11 @@
 {
 	struct inode *inode = path->dentry->d_inode;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 
 	COMMON_AUDIT_DATA_INIT(&ad, PATH);
 	ad.u.path = *path;
+	ad.selinux_audit_data = &sad;
 	return inode_has_perm(cred, inode, av, &ad, 0);
 }
 
@@ -1544,11 +1551,13 @@
 	struct file_security_struct *fsec = file->f_security;
 	struct inode *inode = file->f_path.dentry->d_inode;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = cred_sid(cred);
 	int rc;
 
 	COMMON_AUDIT_DATA_INIT(&ad, PATH);
 	ad.u.path = file->f_path;
+	ad.selinux_audit_data = &sad;
 
 	if (sid != fsec->sid) {
 		rc = avc_has_perm(sid, fsec->sid,
@@ -1578,6 +1587,7 @@
 	struct superblock_security_struct *sbsec;
 	u32 sid, newsid;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	int rc;
 
 	dsec = dir->i_security;
@@ -1588,6 +1598,7 @@
 
 	COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
 	ad.u.dentry = dentry;
+	ad.selinux_audit_data = &sad;
 
 	rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
 			  DIR__ADD_NAME | DIR__SEARCH,
@@ -1632,6 +1643,7 @@
 {
 	struct inode_security_struct *dsec, *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 	u32 av;
 	int rc;
@@ -1641,6 +1653,7 @@
 
 	COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
 	ad.u.dentry = dentry;
+	ad.selinux_audit_data = &sad;
 
 	av = DIR__SEARCH;
 	av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
@@ -1675,6 +1688,7 @@
 {
 	struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 	u32 av;
 	int old_is_dir, new_is_dir;
@@ -1686,6 +1700,7 @@
 	new_dsec = new_dir->i_security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+	ad.selinux_audit_data = &sad;
 
 	ad.u.dentry = old_dentry;
 	rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
@@ -1971,6 +1986,7 @@
 	struct task_security_struct *new_tsec;
 	struct inode_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	struct inode *inode = bprm->file->f_path.dentry->d_inode;
 	int rc;
 
@@ -2010,6 +2026,7 @@
 	}
 
 	COMMON_AUDIT_DATA_INIT(&ad, PATH);
+	ad.selinux_audit_data = &sad;
 	ad.u.path = bprm->file->f_path;
 
 	if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
@@ -2099,6 +2116,7 @@
 					    struct files_struct *files)
 {
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	struct file *file, *devnull = NULL;
 	struct tty_struct *tty;
 	struct fdtable *fdt;
@@ -2136,6 +2154,7 @@
 	/* Revalidate access to inherited open files. */
 
 	COMMON_AUDIT_DATA_INIT(&ad, INODE);
+	ad.selinux_audit_data = &sad;
 
 	spin_lock(&files->file_lock);
 	for (;;) {
@@ -2147,7 +2166,7 @@
 		fdt = files_fdtable(files);
 		if (i >= fdt->max_fds)
 			break;
-		set = fdt->open_fds->fds_bits[j];
+		set = fdt->open_fds[j];
 		if (!set)
 			continue;
 		spin_unlock(&files->file_lock);
@@ -2473,6 +2492,7 @@
 {
 	const struct cred *cred = current_cred();
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	int rc;
 
 	rc = superblock_doinit(sb, data);
@@ -2484,6 +2504,7 @@
 		return 0;
 
 	COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+	ad.selinux_audit_data = &sad;
 	ad.u.dentry = sb->s_root;
 	return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
 }
@@ -2492,8 +2513,10 @@
 {
 	const struct cred *cred = current_cred();
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 
 	COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+	ad.selinux_audit_data = &sad;
 	ad.u.dentry = dentry->d_sb->s_root;
 	return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
 }
@@ -2657,6 +2680,7 @@
 {
 	const struct cred *cred = current_cred();
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 perms;
 	bool from_access;
 	unsigned flags = mask & MAY_NOT_BLOCK;
@@ -2669,10 +2693,11 @@
 		return 0;
 
 	COMMON_AUDIT_DATA_INIT(&ad, INODE);
+	ad.selinux_audit_data = &sad;
 	ad.u.inode = inode;
 
 	if (from_access)
-		ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
+		ad.selinux_audit_data->auditdeny |= FILE__AUDIT_ACCESS;
 
 	perms = file_mask_to_av(inode->i_mode, mask);
 
@@ -2738,6 +2763,7 @@
 	struct inode_security_struct *isec = inode->i_security;
 	struct superblock_security_struct *sbsec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 newsid, sid = current_sid();
 	int rc = 0;
 
@@ -2752,6 +2778,7 @@
 		return -EPERM;
 
 	COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+	ad.selinux_audit_data = &sad;
 	ad.u.dentry = dentry;
 
 	rc = avc_has_perm(sid, isec->sid, isec->sclass,
@@ -2971,15 +2998,15 @@
 	/* fall through */
 	case FIGETBSZ:
 	/* fall through */
-	case EXT2_IOC_GETFLAGS:
+	case FS_IOC_GETFLAGS:
 	/* fall through */
-	case EXT2_IOC_GETVERSION:
+	case FS_IOC_GETVERSION:
 		error = file_has_perm(cred, file, FILE__GETATTR);
 		break;
 
-	case EXT2_IOC_SETFLAGS:
+	case FS_IOC_SETFLAGS:
 	/* fall through */
-	case EXT2_IOC_SETVERSION:
+	case FS_IOC_SETVERSION:
 		error = file_has_perm(cred, file, FILE__SETATTR);
 		break;
 
@@ -3346,10 +3373,12 @@
 {
 	u32 sid;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 
 	sid = task_sid(current);
 
 	COMMON_AUDIT_DATA_INIT(&ad, KMOD);
+	ad.selinux_audit_data = &sad;
 	ad.u.kmod_name = kmod_name;
 
 	return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM,
@@ -3488,8 +3517,8 @@
 	if (ihlen < sizeof(_iph))
 		goto out;
 
-	ad->u.net.v4info.saddr = ih->saddr;
-	ad->u.net.v4info.daddr = ih->daddr;
+	ad->u.net->v4info.saddr = ih->saddr;
+	ad->u.net->v4info.daddr = ih->daddr;
 	ret = 0;
 
 	if (proto)
@@ -3507,8 +3536,8 @@
 		if (th == NULL)
 			break;
 
-		ad->u.net.sport = th->source;
-		ad->u.net.dport = th->dest;
+		ad->u.net->sport = th->source;
+		ad->u.net->dport = th->dest;
 		break;
 	}
 
@@ -3523,8 +3552,8 @@
 		if (uh == NULL)
 			break;
 
-		ad->u.net.sport = uh->source;
-		ad->u.net.dport = uh->dest;
+		ad->u.net->sport = uh->source;
+		ad->u.net->dport = uh->dest;
 		break;
 	}
 
@@ -3539,8 +3568,8 @@
 		if (dh == NULL)
 			break;
 
-		ad->u.net.sport = dh->dccph_sport;
-		ad->u.net.dport = dh->dccph_dport;
+		ad->u.net->sport = dh->dccph_sport;
+		ad->u.net->dport = dh->dccph_dport;
 		break;
 	}
 
@@ -3567,8 +3596,8 @@
 	if (ip6 == NULL)
 		goto out;
 
-	ad->u.net.v6info.saddr = ip6->saddr;
-	ad->u.net.v6info.daddr = ip6->daddr;
+	ad->u.net->v6info.saddr = ip6->saddr;
+	ad->u.net->v6info.daddr = ip6->daddr;
 	ret = 0;
 
 	nexthdr = ip6->nexthdr;
@@ -3588,8 +3617,8 @@
 		if (th == NULL)
 			break;
 
-		ad->u.net.sport = th->source;
-		ad->u.net.dport = th->dest;
+		ad->u.net->sport = th->source;
+		ad->u.net->dport = th->dest;
 		break;
 	}
 
@@ -3600,8 +3629,8 @@
 		if (uh == NULL)
 			break;
 
-		ad->u.net.sport = uh->source;
-		ad->u.net.dport = uh->dest;
+		ad->u.net->sport = uh->source;
+		ad->u.net->dport = uh->dest;
 		break;
 	}
 
@@ -3612,8 +3641,8 @@
 		if (dh == NULL)
 			break;
 
-		ad->u.net.sport = dh->dccph_sport;
-		ad->u.net.dport = dh->dccph_dport;
+		ad->u.net->sport = dh->dccph_sport;
+		ad->u.net->dport = dh->dccph_dport;
 		break;
 	}
 
@@ -3633,13 +3662,13 @@
 	char *addrp;
 	int ret;
 
-	switch (ad->u.net.family) {
+	switch (ad->u.net->family) {
 	case PF_INET:
 		ret = selinux_parse_skb_ipv4(skb, ad, proto);
 		if (ret)
 			goto parse_error;
-		addrp = (char *)(src ? &ad->u.net.v4info.saddr :
-				       &ad->u.net.v4info.daddr);
+		addrp = (char *)(src ? &ad->u.net->v4info.saddr :
+				       &ad->u.net->v4info.daddr);
 		goto okay;
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -3647,8 +3676,8 @@
 		ret = selinux_parse_skb_ipv6(skb, ad, proto);
 		if (ret)
 			goto parse_error;
-		addrp = (char *)(src ? &ad->u.net.v6info.saddr :
-				       &ad->u.net.v6info.daddr);
+		addrp = (char *)(src ? &ad->u.net->v6info.saddr :
+				       &ad->u.net->v6info.daddr);
 		goto okay;
 #endif	/* IPV6 */
 	default:
@@ -3722,13 +3751,17 @@
 {
 	struct sk_security_struct *sksec = sk->sk_security;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 	u32 tsid = task_sid(task);
 
 	if (sksec->sid == SECINITSID_KERNEL)
 		return 0;
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.sk = sk;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->sk = sk;
 
 	return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
 }
@@ -3806,6 +3839,8 @@
 		char *addrp;
 		struct sk_security_struct *sksec = sk->sk_security;
 		struct common_audit_data ad;
+		struct selinux_audit_data sad = {0,};
+		struct lsm_network_audit net = {0,};
 		struct sockaddr_in *addr4 = NULL;
 		struct sockaddr_in6 *addr6 = NULL;
 		unsigned short snum;
@@ -3832,8 +3867,10 @@
 				if (err)
 					goto out;
 				COMMON_AUDIT_DATA_INIT(&ad, NET);
-				ad.u.net.sport = htons(snum);
-				ad.u.net.family = family;
+				ad.selinux_audit_data = &sad;
+				ad.u.net = &net;
+				ad.u.net->sport = htons(snum);
+				ad.u.net->family = family;
 				err = avc_has_perm(sksec->sid, sid,
 						   sksec->sclass,
 						   SOCKET__NAME_BIND, &ad);
@@ -3865,13 +3902,15 @@
 			goto out;
 
 		COMMON_AUDIT_DATA_INIT(&ad, NET);
-		ad.u.net.sport = htons(snum);
-		ad.u.net.family = family;
+		ad.selinux_audit_data = &sad;
+		ad.u.net = &net;
+		ad.u.net->sport = htons(snum);
+		ad.u.net->family = family;
 
 		if (family == PF_INET)
-			ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
+			ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
 		else
-			ad.u.net.v6info.saddr = addr6->sin6_addr;
+			ad.u.net->v6info.saddr = addr6->sin6_addr;
 
 		err = avc_has_perm(sksec->sid, sid,
 				   sksec->sclass, node_perm, &ad);
@@ -3898,6 +3937,8 @@
 	if (sksec->sclass == SECCLASS_TCP_SOCKET ||
 	    sksec->sclass == SECCLASS_DCCP_SOCKET) {
 		struct common_audit_data ad;
+		struct selinux_audit_data sad = {0,};
+		struct lsm_network_audit net = {0,};
 		struct sockaddr_in *addr4 = NULL;
 		struct sockaddr_in6 *addr6 = NULL;
 		unsigned short snum;
@@ -3923,8 +3964,10 @@
 		       TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
 
 		COMMON_AUDIT_DATA_INIT(&ad, NET);
-		ad.u.net.dport = htons(snum);
-		ad.u.net.family = sk->sk_family;
+		ad.selinux_audit_data = &sad;
+		ad.u.net = &net;
+		ad.u.net->dport = htons(snum);
+		ad.u.net->family = sk->sk_family;
 		err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
 		if (err)
 			goto out;
@@ -4013,10 +4056,14 @@
 	struct sk_security_struct *sksec_other = other->sk_security;
 	struct sk_security_struct *sksec_new = newsk->sk_security;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 	int err;
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.sk = other;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->sk = other;
 
 	err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
 			   sksec_other->sclass,
@@ -4043,9 +4090,13 @@
 	struct sk_security_struct *ssec = sock->sk->sk_security;
 	struct sk_security_struct *osec = other->sk->sk_security;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.sk = other->sk;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->sk = other->sk;
 
 	return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
 			    &ad);
@@ -4081,11 +4132,15 @@
 	struct sk_security_struct *sksec = sk->sk_security;
 	u32 sk_sid = sksec->sid;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 	char *addrp;
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.netif = skb->skb_iif;
-	ad.u.net.family = family;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->netif = skb->skb_iif;
+	ad.u.net->family = family;
 	err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
 	if (err)
 		return err;
@@ -4112,6 +4167,8 @@
 	u16 family = sk->sk_family;
 	u32 sk_sid = sksec->sid;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 	char *addrp;
 	u8 secmark_active;
 	u8 peerlbl_active;
@@ -4136,8 +4193,10 @@
 		return 0;
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.netif = skb->skb_iif;
-	ad.u.net.family = family;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->netif = skb->skb_iif;
+	ad.u.net->family = family;
 	err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
 	if (err)
 		return err;
@@ -4472,6 +4531,8 @@
 	char *addrp;
 	u32 peer_sid;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 	u8 secmark_active;
 	u8 netlbl_active;
 	u8 peerlbl_active;
@@ -4489,8 +4550,10 @@
 		return NF_DROP;
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.netif = ifindex;
-	ad.u.net.family = family;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->netif = ifindex;
+	ad.u.net->family = family;
 	if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
 		return NF_DROP;
 
@@ -4577,6 +4640,8 @@
 	struct sock *sk = skb->sk;
 	struct sk_security_struct *sksec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 	char *addrp;
 	u8 proto;
 
@@ -4585,8 +4650,10 @@
 	sksec = sk->sk_security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.netif = ifindex;
-	ad.u.net.family = family;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->netif = ifindex;
+	ad.u.net->family = family;
 	if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
 		return NF_DROP;
 
@@ -4608,6 +4675,8 @@
 	u32 peer_sid;
 	struct sock *sk;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	struct lsm_network_audit net = {0,};
 	char *addrp;
 	u8 secmark_active;
 	u8 peerlbl_active;
@@ -4654,8 +4723,10 @@
 	}
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.netif = ifindex;
-	ad.u.net.family = family;
+	ad.selinux_audit_data = &sad;
+	ad.u.net = &net;
+	ad.u.net->netif = ifindex;
+	ad.u.net->family = family;
 	if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
 		return NF_DROP;
 
@@ -4770,11 +4841,13 @@
 {
 	struct ipc_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 
 	isec = ipc_perms->security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = ipc_perms->key;
 
 	return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
@@ -4795,6 +4868,7 @@
 {
 	struct ipc_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 	int rc;
 
@@ -4805,6 +4879,7 @@
 	isec = msq->q_perm.security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = msq->q_perm.key;
 
 	rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
@@ -4825,11 +4900,13 @@
 {
 	struct ipc_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 
 	isec = msq->q_perm.security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = msq->q_perm.key;
 
 	return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
@@ -4869,6 +4946,7 @@
 	struct ipc_security_struct *isec;
 	struct msg_security_struct *msec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 	int rc;
 
@@ -4890,6 +4968,7 @@
 	}
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = msq->q_perm.key;
 
 	/* Can this process write to the queue? */
@@ -4914,6 +4993,7 @@
 	struct ipc_security_struct *isec;
 	struct msg_security_struct *msec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = task_sid(target);
 	int rc;
 
@@ -4921,6 +5001,7 @@
 	msec = msg->security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = msq->q_perm.key;
 
 	rc = avc_has_perm(sid, isec->sid,
@@ -4936,6 +5017,7 @@
 {
 	struct ipc_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 	int rc;
 
@@ -4946,6 +5028,7 @@
 	isec = shp->shm_perm.security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = shp->shm_perm.key;
 
 	rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
@@ -4966,11 +5049,13 @@
 {
 	struct ipc_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 
 	isec = shp->shm_perm.security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = shp->shm_perm.key;
 
 	return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
@@ -5028,6 +5113,7 @@
 {
 	struct ipc_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 	int rc;
 
@@ -5038,6 +5124,7 @@
 	isec = sma->sem_perm.security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = sma->sem_perm.key;
 
 	rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
@@ -5058,11 +5145,13 @@
 {
 	struct ipc_security_struct *isec;
 	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
 	u32 sid = current_sid();
 
 	isec = sma->sem_perm.security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, IPC);
+	ad.selinux_audit_data = &sad;
 	ad.u.ipc_id = sma->sem_perm.key;
 
 	return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 47fda96..1931370 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -15,7 +15,6 @@
 #include <linux/audit.h>
 #include <linux/lsm_audit.h>
 #include <linux/in6.h>
-#include <asm/system.h>
 #include "flask.h"
 #include "av_permissions.h"
 #include "security.h"
@@ -48,6 +47,31 @@
 };
 
 /*
+ * We only need this data after we have decided to send an audit message.
+ */
+struct selinux_late_audit_data {
+	u32 ssid;
+	u32 tsid;
+	u16 tclass;
+	u32 requested;
+	u32 audited;
+	u32 denied;
+	int result;
+};
+
+/*
+ * We collect this at the beginning or during an selinux security operation
+ */
+struct selinux_audit_data {
+	/*
+	 * auditdeny is a bit tricky and unintuitive.  See the
+	 * comments in avc.c for it's meaning and usage.
+	 */
+	u32 auditdeny;
+	struct selinux_late_audit_data *slad;
+};
+
+/*
  * AVC operations
  */
 
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
index b43813c..c220f31 100644
--- a/security/selinux/include/xfrm.h
+++ b/security/selinux/include/xfrm.h
@@ -7,6 +7,8 @@
 #ifndef _SELINUX_XFRM_H_
 #define _SELINUX_XFRM_H_
 
+#include <net/flow.h>
+
 int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
 			      struct xfrm_user_sec_ctx *sec_ctx);
 int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 48a7d00..d7018bf 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -344,7 +344,7 @@
 static int sel_make_policycap(void);
 
 /* declaration for sel_make_class_dirs */
-static int sel_make_dir(struct inode *dir, struct dentry *dentry,
+static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
 			unsigned long *ino);
 
 static ssize_t sel_read_mls(struct file *filp, char __user *buf,
@@ -1678,13 +1678,9 @@
 	inode->i_ino = sel_class_to_ino(index);
 	d_add(dentry, inode);
 
-	dentry = d_alloc_name(dir, "perms");
-	if (!dentry)
-		return -ENOMEM;
-
-	rc = sel_make_dir(dir->d_inode, dentry, &last_class_ino);
-	if (rc)
-		return rc;
+	dentry = sel_make_dir(dir, "perms", &last_class_ino);
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
 
 	rc = sel_make_perm_files(classname, index, dentry);
 
@@ -1733,15 +1729,12 @@
 	for (i = 0; i < nclasses; i++) {
 		struct dentry *class_name_dir;
 
-		rc = -ENOMEM;
-		class_name_dir = d_alloc_name(class_dir, classes[i]);
-		if (!class_name_dir)
-			goto out;
-
-		rc = sel_make_dir(class_dir->d_inode, class_name_dir,
+		class_name_dir = sel_make_dir(class_dir, classes[i],
 				&last_class_ino);
-		if (rc)
+		if (IS_ERR(class_name_dir)) {
+			rc = PTR_ERR(class_name_dir);
 			goto out;
+		}
 
 		/* i+1 since class values are 1-indexed */
 		rc = sel_make_class_dir_entries(classes[i], i + 1,
@@ -1787,14 +1780,20 @@
 	return 0;
 }
 
-static int sel_make_dir(struct inode *dir, struct dentry *dentry,
+static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
 			unsigned long *ino)
 {
+	struct dentry *dentry = d_alloc_name(dir, name);
 	struct inode *inode;
 
-	inode = sel_make_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO);
-	if (!inode)
-		return -ENOMEM;
+	if (!dentry)
+		return ERR_PTR(-ENOMEM);
+
+	inode = sel_make_inode(dir->d_sb, S_IFDIR | S_IRUGO | S_IXUGO);
+	if (!inode) {
+		dput(dentry);
+		return ERR_PTR(-ENOMEM);
+	}
 
 	inode->i_op = &simple_dir_inode_operations;
 	inode->i_fop = &simple_dir_operations;
@@ -1803,16 +1802,16 @@
 	inc_nlink(inode);
 	d_add(dentry, inode);
 	/* bump link count on parent directory, too */
-	inc_nlink(dir);
+	inc_nlink(dir->d_inode);
 
-	return 0;
+	return dentry;
 }
 
 static int sel_fill_super(struct super_block *sb, void *data, int silent)
 {
 	int ret;
 	struct dentry *dentry;
-	struct inode *inode, *root_inode;
+	struct inode *inode;
 	struct inode_security_struct *isec;
 
 	static struct tree_descr selinux_files[] = {
@@ -1839,18 +1838,12 @@
 	if (ret)
 		goto err;
 
-	root_inode = sb->s_root->d_inode;
-
-	ret = -ENOMEM;
-	dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME);
-	if (!dentry)
+	bool_dir = sel_make_dir(sb->s_root, BOOL_DIR_NAME, &sel_last_ino);
+	if (IS_ERR(bool_dir)) {
+		ret = PTR_ERR(bool_dir);
+		bool_dir = NULL;
 		goto err;
-
-	ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
-	if (ret)
-		goto err;
-
-	bool_dir = dentry;
+	}
 
 	ret = -ENOMEM;
 	dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME);
@@ -1872,54 +1865,39 @@
 	d_add(dentry, inode);
 	selinux_null = dentry;
 
-	ret = -ENOMEM;
-	dentry = d_alloc_name(sb->s_root, "avc");
-	if (!dentry)
+	dentry = sel_make_dir(sb->s_root, "avc", &sel_last_ino);
+	if (IS_ERR(dentry)) {
+		ret = PTR_ERR(dentry);
 		goto err;
-
-	ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
-	if (ret)
-		goto err;
+	}
 
 	ret = sel_make_avc_files(dentry);
 	if (ret)
 		goto err;
 
-	ret = -ENOMEM;
-	dentry = d_alloc_name(sb->s_root, "initial_contexts");
-	if (!dentry)
+	dentry = sel_make_dir(sb->s_root, "initial_contexts", &sel_last_ino);
+	if (IS_ERR(dentry)) {
+		ret = PTR_ERR(dentry);
 		goto err;
-
-	ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
-	if (ret)
-		goto err;
+	}
 
 	ret = sel_make_initcon_files(dentry);
 	if (ret)
 		goto err;
 
-	ret = -ENOMEM;
-	dentry = d_alloc_name(sb->s_root, "class");
-	if (!dentry)
+	class_dir = sel_make_dir(sb->s_root, "class", &sel_last_ino);
+	if (IS_ERR(class_dir)) {
+		ret = PTR_ERR(class_dir);
+		class_dir = NULL;
 		goto err;
+	}
 
-	ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
-	if (ret)
+	policycap_dir = sel_make_dir(sb->s_root, "policy_capabilities", &sel_last_ino);
+	if (IS_ERR(policycap_dir)) {
+		ret = PTR_ERR(policycap_dir);
+		policycap_dir = NULL;
 		goto err;
-
-	class_dir = dentry;
-
-	ret = -ENOMEM;
-	dentry = d_alloc_name(sb->s_root, "policy_capabilities");
-	if (!dentry)
-		goto err;
-
-	ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
-	if (ret)
-		goto err;
-
-	policycap_dir = dentry;
-
+	}
 	return 0;
 err:
 	printk(KERN_ERR "SELinux: %s:  failed while creating inodes\n",
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 2ad0065..4ede719 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -185,6 +185,15 @@
  */
 #define SMK_NUM_ACCESS_TYPE 5
 
+/* SMACK data */
+struct smack_audit_data {
+	const char *function;
+	char *subject;
+	char *object;
+	char *request;
+	int result;
+};
+
 /*
  * Smack audit data; is empty if CONFIG_AUDIT not set
  * to save some stack
@@ -192,6 +201,7 @@
 struct smk_audit_info {
 #ifdef CONFIG_AUDIT
 	struct common_audit_data a;
+	struct smack_audit_data sad;
 #endif
 };
 /*
@@ -311,7 +321,16 @@
 {
 	memset(a, 0, sizeof(*a));
 	a->a.type = type;
-	a->a.smack_audit_data.function = func;
+	a->a.smack_audit_data = &a->sad;
+	a->a.smack_audit_data->function = func;
+}
+
+static inline void smk_ad_init_net(struct smk_audit_info *a, const char *func,
+				   char type, struct lsm_network_audit *net)
+{
+	smk_ad_init(a, func, type);
+	memset(net, 0, sizeof(*net));
+	a->a.u.net = net;
 }
 
 static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a,
@@ -337,7 +356,7 @@
 static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a,
 					    struct sock *sk)
 {
-	a->a.u.net.sk = sk;
+	a->a.u.net->sk = sk;
 }
 
 #else /* no AUDIT */
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index cc7cb6e..c8115f7 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -275,9 +275,9 @@
 static void smack_log_callback(struct audit_buffer *ab, void *a)
 {
 	struct common_audit_data *ad = a;
-	struct smack_audit_data *sad = &ad->smack_audit_data;
+	struct smack_audit_data *sad = ad->smack_audit_data;
 	audit_log_format(ab, "lsm=SMACK fn=%s action=%s",
-			 ad->smack_audit_data.function,
+			 ad->smack_audit_data->function,
 			 sad->result ? "denied" : "granted");
 	audit_log_format(ab, " subject=");
 	audit_log_untrustedstring(ab, sad->subject);
@@ -310,19 +310,19 @@
 	if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
 		return;
 
-	if (a->smack_audit_data.function == NULL)
-		a->smack_audit_data.function = "unknown";
+	sad = a->smack_audit_data;
+
+	if (sad->function == NULL)
+		sad->function = "unknown";
 
 	/* end preparing the audit data */
-	sad = &a->smack_audit_data;
 	smack_str_from_perm(request_buffer, request);
 	sad->subject = subject_label;
 	sad->object  = object_label;
 	sad->request = request_buffer;
 	sad->result  = result;
-	a->lsm_pre_audit = smack_log_callback;
 
-	common_lsm_audit(a);
+	common_lsm_audit(a, smack_log_callback, NULL);
 }
 #else /* #ifdef CONFIG_AUDIT */
 void smack_log(char *subject_label, char *object_label, int request,
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index cd667b4..81c03a5 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1939,16 +1939,17 @@
 	char *hostsp;
 	struct socket_smack *ssp = sk->sk_security;
 	struct smk_audit_info ad;
+	struct lsm_network_audit net;
 
 	rcu_read_lock();
 	hostsp = smack_host_label(sap);
 	if (hostsp != NULL) {
 		sk_lbl = SMACK_UNLABELED_SOCKET;
 #ifdef CONFIG_AUDIT
-		smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
-		ad.a.u.net.family = sap->sin_family;
-		ad.a.u.net.dport = sap->sin_port;
-		ad.a.u.net.v4info.daddr = sap->sin_addr.s_addr;
+		smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
+		ad.a.u.net->family = sap->sin_family;
+		ad.a.u.net->dport = sap->sin_port;
+		ad.a.u.net->v4info.daddr = sap->sin_addr.s_addr;
 #endif
 		rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE, &ad);
 	} else {
@@ -2808,9 +2809,10 @@
 	struct socket_smack *osp = other->sk_security;
 	struct socket_smack *nsp = newsk->sk_security;
 	struct smk_audit_info ad;
+	struct lsm_network_audit net;
 	int rc = 0;
 
-	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
+	smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
 	smk_ad_setfield_u_net_sk(&ad, other);
 
 	if (!capable(CAP_MAC_OVERRIDE))
@@ -2840,9 +2842,10 @@
 	struct socket_smack *ssp = sock->sk->sk_security;
 	struct socket_smack *osp = other->sk->sk_security;
 	struct smk_audit_info ad;
+	struct lsm_network_audit net;
 	int rc = 0;
 
-	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
+	smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
 	smk_ad_setfield_u_net_sk(&ad, other->sk);
 
 	if (!capable(CAP_MAC_OVERRIDE))
@@ -2990,6 +2993,7 @@
 	char *csp;
 	int rc;
 	struct smk_audit_info ad;
+	struct lsm_network_audit net;
 	if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
 		return 0;
 
@@ -3007,9 +3011,9 @@
 	netlbl_secattr_destroy(&secattr);
 
 #ifdef CONFIG_AUDIT
-	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
-	ad.a.u.net.family = sk->sk_family;
-	ad.a.u.net.netif = skb->skb_iif;
+	smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
+	ad.a.u.net->family = sk->sk_family;
+	ad.a.u.net->netif = skb->skb_iif;
 	ipv4_skb_to_auditdata(skb, &ad.a, NULL);
 #endif
 	/*
@@ -3152,6 +3156,7 @@
 	char *sp;
 	int rc;
 	struct smk_audit_info ad;
+	struct lsm_network_audit net;
 
 	/* handle mapped IPv4 packets arriving via IPv6 sockets */
 	if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
@@ -3166,9 +3171,9 @@
 	netlbl_secattr_destroy(&secattr);
 
 #ifdef CONFIG_AUDIT
-	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET);
-	ad.a.u.net.family = family;
-	ad.a.u.net.netif = skb->skb_iif;
+	smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
+	ad.a.u.net->family = family;
+	ad.a.u.net->netif = skb->skb_iif;
 	ipv4_skb_to_auditdata(skb, &ad.a, NULL);
 #endif
 	/*
diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c
index 6797540..078fac0 100644
--- a/security/tomoyo/load_policy.c
+++ b/security/tomoyo/load_policy.c
@@ -102,7 +102,7 @@
 	envp[0] = "HOME=/";
 	envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
 	envp[2] = NULL;
-	call_usermodehelper(argv[0], argv, envp, 1);
+	call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
 	tomoyo_check_profile();
 }
 
diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c
index 762af68..270790d 100644
--- a/sound/aoa/codecs/onyx.c
+++ b/sound/aoa/codecs/onyx.c
@@ -1132,15 +1132,4 @@
 	.id_table = onyx_i2c_id,
 };
 
-static int __init onyx_init(void)
-{
-	return i2c_add_driver(&onyx_driver);
-}
-
-static void __exit onyx_exit(void)
-{
-	i2c_del_driver(&onyx_driver);
-}
-
-module_init(onyx_init);
-module_exit(onyx_exit);
+module_i2c_driver(onyx_driver);
diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c
index fd2188c..8e63d1f 100644
--- a/sound/aoa/codecs/tas.c
+++ b/sound/aoa/codecs/tas.c
@@ -1026,15 +1026,4 @@
 	.id_table = tas_i2c_id,
 };
 
-static int __init tas_init(void)
-{
-	return i2c_add_driver(&tas_driver);
-}
-
-static void __exit tas_exit(void)
-{
-	i2c_del_driver(&tas_driver);
-}
-
-module_init(tas_init);
-module_exit(tas_exit);
+module_i2c_driver(tas_driver);
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index b37b702a..5119fda 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -1110,18 +1110,7 @@
 	.id_table	= aaci_ids,
 };
 
-static int __init aaci_init(void)
-{
-	return amba_driver_register(&aaci_driver);
-}
-
-static void __exit aaci_exit(void)
-{
-	amba_driver_unregister(&aaci_driver);
-}
-
-module_init(aaci_init);
-module_exit(aaci_exit);
+module_amba_driver(aaci_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("ARM PrimeCell PL041 Advanced Audio CODEC Interface driver");
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c
index d1aa421..48d7c0a 100644
--- a/sound/arm/pxa2xx-ac97-lib.c
+++ b/sound/arm/pxa2xx-ac97-lib.c
@@ -17,11 +17,12 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/io.h>
 
 #include <sound/ac97_codec.h>
 #include <sound/pxa2xx-lib.h>
 
-#include <asm/irq.h>
+#include <mach/irqs.h>
 #include <mach/regs-ac97.h>
 #include <mach/audio.h>
 
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index 3a39626..afef72c 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c
index 4fa1dbd..f7c2bb0 100644
--- a/sound/atmel/abdac.c
+++ b/sound/atmel/abdac.c
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/types.h>
 #include <linux/io.h>
 
 #include <sound/core.h>
@@ -467,15 +468,24 @@
 	snd_card_set_dev(card, &pdev->dev);
 
 	if (pdata->dws.dma_dev) {
-		struct dw_dma_slave *dws = &pdata->dws;
 		dma_cap_mask_t mask;
 
-		dws->tx_reg = regs->start + DAC_DATA;
-
 		dma_cap_zero(mask);
 		dma_cap_set(DMA_SLAVE, mask);
 
-		dac->dma.chan = dma_request_channel(mask, filter, dws);
+		dac->dma.chan = dma_request_channel(mask, filter, &pdata->dws);
+		if (dac->dma.chan) {
+			struct dma_slave_config dma_conf = {
+				.dst_addr = regs->start + DAC_DATA,
+				.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+				.src_maxburst = 1,
+				.dst_maxburst = 1,
+				.direction = DMA_MEM_TO_DEV,
+				.device_fc = false,
+			};
+
+			dmaengine_slave_config(dac->dma.chan, &dma_conf);
+		}
 	}
 	if (!pdata->dws.dma_dev || !dac->dma.chan) {
 		dev_dbg(&pdev->dev, "DMA not available\n");
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index 61dade6..115313e 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -20,6 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
 #include <linux/gpio.h>
+#include <linux/types.h>
 #include <linux/io.h>
 
 #include <sound/core.h>
@@ -1014,16 +1015,28 @@
 
 	if (cpu_is_at32ap7000()) {
 		if (pdata->rx_dws.dma_dev) {
-			struct dw_dma_slave *dws = &pdata->rx_dws;
 			dma_cap_mask_t mask;
 
-			dws->rx_reg = regs->start + AC97C_CARHR + 2;
-
 			dma_cap_zero(mask);
 			dma_cap_set(DMA_SLAVE, mask);
 
 			chip->dma.rx_chan = dma_request_channel(mask, filter,
-								dws);
+								&pdata->rx_dws);
+			if (chip->dma.rx_chan) {
+				struct dma_slave_config dma_conf = {
+					.src_addr = regs->start + AC97C_CARHR +
+						2,
+					.src_addr_width =
+						DMA_SLAVE_BUSWIDTH_2_BYTES,
+					.src_maxburst = 1,
+					.dst_maxburst = 1,
+					.direction = DMA_DEV_TO_MEM,
+					.device_fc = false,
+				};
+
+				dmaengine_slave_config(chip->dma.rx_chan,
+						&dma_conf);
+			}
 
 			dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
 				dev_name(&chip->dma.rx_chan->dev->device));
@@ -1031,16 +1044,28 @@
 		}
 
 		if (pdata->tx_dws.dma_dev) {
-			struct dw_dma_slave *dws = &pdata->tx_dws;
 			dma_cap_mask_t mask;
 
-			dws->tx_reg = regs->start + AC97C_CATHR + 2;
-
 			dma_cap_zero(mask);
 			dma_cap_set(DMA_SLAVE, mask);
 
 			chip->dma.tx_chan = dma_request_channel(mask, filter,
-								dws);
+								&pdata->tx_dws);
+			if (chip->dma.tx_chan) {
+				struct dma_slave_config dma_conf = {
+					.dst_addr = regs->start + AC97C_CATHR +
+						2,
+					.dst_addr_width =
+						DMA_SLAVE_BUSWIDTH_2_BYTES,
+					.src_maxburst = 1,
+					.dst_maxburst = 1,
+					.direction = DMA_MEM_TO_DEV,
+					.device_fc = false,
+				};
+
+				dmaengine_slave_config(chip->dma.tx_chan,
+						&dma_conf);
+			}
 
 			dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
 				dev_name(&chip->dma.tx_chan->dev->device));
diff --git a/sound/core/control.c b/sound/core/control.c
index 819a5c5..2487a6b 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1313,7 +1313,7 @@
 			err = -EPERM;
 			goto __kctl_end;
 		}
-		err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); 
+		err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
 		if (err > 0) {
 			up_read(&card->controls_rwsem);
 			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id);
diff --git a/sound/core/init.c b/sound/core/init.c
index 3ac49b1..d8ec849 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/module.h>
+#include <linux/device.h>
 #include <linux/file.h>
 #include <linux/slab.h>
 #include <linux/time.h>
@@ -480,74 +481,104 @@
 
 EXPORT_SYMBOL(snd_card_free);
 
-static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid)
+/* retrieve the last word of shortname or longname */
+static const char *retrieve_id_from_card_name(const char *name)
 {
-	int i, len, idx_flag = 0, loops = SNDRV_CARDS;
-	const char *spos, *src;
+	const char *spos = name;
+
+	while (*name) {
+		if (isspace(*name) && isalnum(name[1]))
+			spos = name + 1;
+		name++;
+	}
+	return spos;
+}
+
+/* return true if the given id string doesn't conflict any other card ids */
+static bool card_id_ok(struct snd_card *card, const char *id)
+{
+	int i;
+	if (!snd_info_check_reserved_words(id))
+		return false;
+	for (i = 0; i < snd_ecards_limit; i++) {
+		if (snd_cards[i] && snd_cards[i] != card &&
+		    !strcmp(snd_cards[i]->id, id))
+			return false;
+	}
+	return true;
+}
+
+/* copy to card->id only with valid letters from nid */
+static void copy_valid_id_string(struct snd_card *card, const char *src,
+				 const char *nid)
+{
+	char *id = card->id;
+
+	while (*nid && !isalnum(*nid))
+		nid++;
+	if (isdigit(*nid))
+		*id++ = isalpha(*src) ? *src : 'D';
+	while (*nid && (size_t)(id - card->id) < sizeof(card->id) - 1) {
+		if (isalnum(*nid))
+			*id++ = *nid;
+		nid++;
+	}
+	*id = 0;
+}
+
+/* Set card->id from the given string
+ * If the string conflicts with other ids, add a suffix to make it unique.
+ */
+static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
+				    const char *nid)
+{
+	int len, loops;
+	bool with_suffix;
+	bool is_default = false;
 	char *id;
 	
-	if (nid == NULL) {
-		id = card->shortname;
-		spos = src = id;
-		while (*id != '\0') {
-			if (*id == ' ')
-				spos = id + 1;
-			id++;
-		}
-	} else {
-		spos = src = nid;
-	}
+	copy_valid_id_string(card, src, nid);
 	id = card->id;
-	while (*spos != '\0' && !isalnum(*spos))
-		spos++;
-	if (isdigit(*spos))
-		*id++ = isalpha(src[0]) ? src[0] : 'D';
-	while (*spos != '\0' && (size_t)(id - card->id) < sizeof(card->id) - 1) {
-		if (isalnum(*spos))
-			*id++ = *spos;
-		spos++;
-	}
-	*id = '\0';
 
-	id = card->id;
-	
-	if (*id == '\0')
+ again:
+	/* use "Default" for obviously invalid strings
+	 * ("card" conflicts with proc directories)
+	 */
+	if (!*id || !strncmp(id, "card", 4)) {
 		strcpy(id, "Default");
+		is_default = true;
+	}
 
-	while (1) {
-	      	if (loops-- == 0) {
-			snd_printk(KERN_ERR "unable to set card id (%s)\n", id);
-      			strcpy(card->id, card->proc_root->name);
-      			return;
-      		}
-	      	if (!snd_info_check_reserved_words(id))
-      			goto __change;
-		for (i = 0; i < snd_ecards_limit; i++) {
-			if (snd_cards[i] && !strcmp(snd_cards[i]->id, id))
-				goto __change;
-		}
-		break;
+	with_suffix = false;
+	for (loops = 0; loops < SNDRV_CARDS; loops++) {
+		if (card_id_ok(card, id))
+			return; /* OK */
 
-	      __change:
 		len = strlen(id);
-		if (idx_flag) {
-			if (id[len-1] != '9')
-				id[len-1]++;
-			else
-				id[len-1] = 'A';
-		} else if ((size_t)len <= sizeof(card->id) - 3) {
-			strcat(id, "_1");
-			idx_flag++;
+		if (!with_suffix) {
+			/* add the "_X" suffix */
+			char *spos = id + len;
+			if (len >  sizeof(card->id) - 3)
+				spos = id + sizeof(card->id) - 3;
+			strcpy(spos, "_1");
+			with_suffix = true;
 		} else {
-			spos = id + len - 2;
-			if ((size_t)len <= sizeof(card->id) - 2)
-				spos++;
-			*(char *)spos++ = '_';
-			*(char *)spos++ = '1';
-			*(char *)spos++ = '\0';
-			idx_flag++;
+			/* modify the existing suffix */
+			if (id[len - 1] != '9')
+				id[len - 1]++;
+			else
+				id[len - 1] = 'A';
 		}
 	}
+	/* fallback to the default id */
+	if (!is_default) {
+		*id = 0;
+		goto again;
+	}
+	/* last resort... */
+	snd_printk(KERN_ERR "unable to set card id (%s)\n", id);
+	if (card->proc_root->name)
+		strcpy(card->id, card->proc_root->name);
 }
 
 /**
@@ -564,7 +595,7 @@
 	if (card->id[0] != '\0')
 		return;
 	mutex_lock(&snd_card_mutex);
-	snd_card_set_id_no_lock(card, nid);
+	snd_card_set_id_no_lock(card, nid, nid);
 	mutex_unlock(&snd_card_mutex);
 }
 EXPORT_SYMBOL(snd_card_set_id);
@@ -596,22 +627,12 @@
 	memcpy(buf1, buf, copy);
 	buf1[copy] = '\0';
 	mutex_lock(&snd_card_mutex);
-	if (!snd_info_check_reserved_words(buf1)) {
-	     __exist:
+	if (!card_id_ok(NULL, buf1)) {
 		mutex_unlock(&snd_card_mutex);
 		return -EEXIST;
 	}
-	for (idx = 0; idx < snd_ecards_limit; idx++) {
-		if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) {
-			if (card == snd_cards[idx])
-				goto __ok;
-			else
-				goto __exist;
-		}
-	}
 	strcpy(card->id, buf1);
 	snd_info_card_id_change(card);
-__ok:
 	mutex_unlock(&snd_card_mutex);
 
 	return count;
@@ -665,7 +686,18 @@
 		mutex_unlock(&snd_card_mutex);
 		return 0;
 	}
-	snd_card_set_id_no_lock(card, card->id[0] == '\0' ? NULL : card->id);
+	if (*card->id) {
+		/* make a unique id name from the given string */
+		char tmpid[sizeof(card->id)];
+		memcpy(tmpid, card->id, sizeof(card->id));
+		snd_card_set_id_no_lock(card, tmpid, tmpid);
+	} else {
+		/* create an id from either shortname or longname */
+		const char *src;
+		src = *card->shortname ? card->shortname : card->longname;
+		snd_card_set_id_no_lock(card, src,
+					retrieve_id_from_card_name(src));
+	}
 	snd_cards[card->number] = card;
 	mutex_unlock(&snd_card_mutex);
 	init_info_for_card(card);
diff --git a/sound/core/jack.c b/sound/core/jack.c
index 26edf63..471e1e3 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -25,7 +25,7 @@
 #include <sound/jack.h>
 #include <sound/core.h>
 
-static int jack_switch_types[] = {
+static int jack_switch_types[SND_JACK_SWITCH_TYPES] = {
 	SW_HEADPHONE_INSERT,
 	SW_MICROPHONE_INSERT,
 	SW_LINEOUT_INSERT,
@@ -128,7 +128,7 @@
 
 	jack->type = type;
 
-	for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++)
+	for (i = 0; i < SND_JACK_SWITCH_TYPES; i++)
 		if (type & (1 << i))
 			input_set_capability(jack->input_dev, EV_SW,
 					     jack_switch_types[i]);
diff --git a/sound/core/misc.c b/sound/core/misc.c
index 465f0ce..7681679 100644
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -72,7 +72,7 @@
 	char verbose_fmt[] = KERN_DEFAULT "ALSA %s:%d %pV";
 #endif
 
-#ifdef CONFIG_SND_DEBUG	
+#ifdef CONFIG_SND_DEBUG
 	if (debug < level)
 		return;
 #endif
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 8928ca87..1a3070b 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/time.h>
 #include <linux/mutex.h>
+#include <linux/device.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/pcm.h>
@@ -650,7 +651,7 @@
 	pstr->stream = stream;
 	pstr->pcm = pcm;
 	pstr->substream_count = substream_count;
-	if (substream_count > 0) {
+	if (substream_count > 0 && !pcm->internal) {
 		err = snd_pcm_stream_proc_init(pstr);
 		if (err < 0) {
 			snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n");
@@ -674,15 +675,18 @@
 			pstr->substream = substream;
 		else
 			prev->next = substream;
-		err = snd_pcm_substream_proc_init(substream);
-		if (err < 0) {
-			snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n");
-			if (prev == NULL)
-				pstr->substream = NULL;
-			else
-				prev->next = NULL;
-			kfree(substream);
-			return err;
+
+		if (!pcm->internal) {
+			err = snd_pcm_substream_proc_init(substream);
+			if (err < 0) {
+				snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n");
+				if (prev == NULL)
+					pstr->substream = NULL;
+				else
+					prev->next = NULL;
+				kfree(substream);
+				return err;
+			}
 		}
 		substream->group = &substream->self_group;
 		spin_lock_init(&substream->self_group.lock);
@@ -696,25 +700,9 @@
 
 EXPORT_SYMBOL(snd_pcm_new_stream);
 
-/**
- * snd_pcm_new - create a new PCM instance
- * @card: the card instance
- * @id: the id string
- * @device: the device index (zero based)
- * @playback_count: the number of substreams for playback
- * @capture_count: the number of substreams for capture
- * @rpcm: the pointer to store the new pcm instance
- *
- * Creates a new PCM instance.
- *
- * The pcm operators have to be set afterwards to the new instance
- * via snd_pcm_set_ops().
- *
- * Returns zero if successful, or a negative error code on failure.
- */
-int snd_pcm_new(struct snd_card *card, const char *id, int device,
-		int playback_count, int capture_count,
-	        struct snd_pcm ** rpcm)
+static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
+		int playback_count, int capture_count, bool internal,
+		struct snd_pcm **rpcm)
 {
 	struct snd_pcm *pcm;
 	int err;
@@ -735,6 +723,7 @@
 	}
 	pcm->card = card;
 	pcm->device = device;
+	pcm->internal = internal;
 	if (id)
 		strlcpy(pcm->id, id, sizeof(pcm->id));
 	if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) {
@@ -756,8 +745,59 @@
 	return 0;
 }
 
+/**
+ * snd_pcm_new - create a new PCM instance
+ * @card: the card instance
+ * @id: the id string
+ * @device: the device index (zero based)
+ * @playback_count: the number of substreams for playback
+ * @capture_count: the number of substreams for capture
+ * @rpcm: the pointer to store the new pcm instance
+ *
+ * Creates a new PCM instance.
+ *
+ * The pcm operators have to be set afterwards to the new instance
+ * via snd_pcm_set_ops().
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ */
+int snd_pcm_new(struct snd_card *card, const char *id, int device,
+		int playback_count, int capture_count, struct snd_pcm **rpcm)
+{
+	return _snd_pcm_new(card, id, device, playback_count, capture_count,
+			false, rpcm);
+}
 EXPORT_SYMBOL(snd_pcm_new);
 
+/**
+ * snd_pcm_new_internal - create a new internal PCM instance
+ * @card: the card instance
+ * @id: the id string
+ * @device: the device index (zero based - shared with normal PCMs)
+ * @playback_count: the number of substreams for playback
+ * @capture_count: the number of substreams for capture
+ * @rpcm: the pointer to store the new pcm instance
+ *
+ * Creates a new internal PCM instance with no userspace device or procfs
+ * entries. This is used by ASoC Back End PCMs in order to create a PCM that
+ * will only be used internally by kernel drivers. i.e. it cannot be opened
+ * by userspace. It provides existing ASoC components drivers with a substream
+ * and access to any private data.
+ *
+ * The pcm operators have to be set afterwards to the new instance
+ * via snd_pcm_set_ops().
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ */
+int snd_pcm_new_internal(struct snd_card *card, const char *id, int device,
+	int playback_count, int capture_count,
+	struct snd_pcm **rpcm)
+{
+	return _snd_pcm_new(card, id, device, playback_count, capture_count,
+			true, rpcm);
+}
+EXPORT_SYMBOL(snd_pcm_new_internal);
+
 static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
 {
 	struct snd_pcm_substream *substream, *substream_next;
@@ -994,7 +1034,7 @@
 	}
 	for (cidx = 0; cidx < 2; cidx++) {
 		int devtype = -1;
-		if (pcm->streams[cidx].substream == NULL)
+		if (pcm->streams[cidx].substream == NULL || pcm->internal)
 			continue;
 		switch (cidx) {
 		case SNDRV_PCM_STREAM_PLAYBACK:
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 3420bd3..4d18941 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1029,7 +1029,8 @@
  *
  * Returns non-zero if the value is changed, zero if not changed.
  */
-int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask)
+int snd_interval_list(struct snd_interval *i, unsigned int count,
+		      const unsigned int *list, unsigned int mask)
 {
         unsigned int k;
 	struct snd_interval list_range;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 25ed9fe..3fe99e6 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1586,12 +1586,18 @@
 	struct file *file;
 	struct snd_pcm_file *pcm_file;
 	struct snd_pcm_substream *substream1;
+	struct snd_pcm_group *group;
 
 	file = snd_pcm_file_fd(fd);
 	if (!file)
 		return -EBADFD;
 	pcm_file = file->private_data;
 	substream1 = pcm_file->substream;
+	group = kmalloc(sizeof(*group), GFP_KERNEL);
+	if (!group) {
+		res = -ENOMEM;
+		goto _nolock;
+	}
 	down_write(&snd_pcm_link_rwsem);
 	write_lock_irq(&snd_pcm_link_rwlock);
 	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN ||
@@ -1604,11 +1610,7 @@
 		goto _end;
 	}
 	if (!snd_pcm_stream_linked(substream)) {
-		substream->group = kmalloc(sizeof(struct snd_pcm_group), GFP_ATOMIC);
-		if (substream->group == NULL) {
-			res = -ENOMEM;
-			goto _end;
-		}
+		substream->group = group;
 		spin_lock_init(&substream->group->lock);
 		INIT_LIST_HEAD(&substream->group->substreams);
 		list_add_tail(&substream->link_list, &substream->group->substreams);
@@ -1620,7 +1622,10 @@
  _end:
 	write_unlock_irq(&snd_pcm_link_rwlock);
 	up_write(&snd_pcm_link_rwsem);
+ _nolock:
 	fput(file);
+	if (res < 0)
+		kfree(group);
 	return res;
 }
 
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c
index 9d8379a..7121105 100644
--- a/sound/core/seq/seq.c
+++ b/sound/core/seq/seq.c
@@ -21,6 +21,7 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/device.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 
diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c
index bbe32d2..dbc5507 100644
--- a/sound/core/seq/seq_dummy.c
+++ b/sound/core/seq/seq_dummy.c
@@ -46,7 +46,7 @@
 
   The number of ports to be created can be specified via the module
   parameter "ports".  For example, to create four ports, add the
-  following option in /etc/modprobe.conf:
+  following option in a configuration file under /etc/modprobe.d/:
 
 	option snd-seq-dummy ports=4
 
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 8e7561d..6ddcf06 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/mutex.h>
+#include <linux/device.h>
 #include <linux/module.h>
 #include <linux/string.h>
 #include <sound/core.h>
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index 130cfe6..14a286a 100644
--- a/sound/core/vmaster.c
+++ b/sound/core/vmaster.c
@@ -37,6 +37,8 @@
 	struct link_ctl_info info;
 	int val;		/* the master value */
 	unsigned int tlv[4];
+	void (*hook)(void *private_data, int);
+	void *hook_private_data;
 };
 
 /*
@@ -126,7 +128,9 @@
 		master->info.count = 1; /* always mono */
 		/* set full volume as default (= no attenuation) */
 		master->val = master->info.max_val;
-		return 0;
+		if (master->hook)
+			master->hook(master->hook_private_data, master->val);
+		return 1;
 	}
 	return -ENOENT;
 }
@@ -329,6 +333,8 @@
 		slave_put_val(slave, uval);
 	}
 	kfree(uval);
+	if (master->hook && !err)
+		master->hook(master->hook_private_data, master->val);
 	return 1;
 }
 
@@ -408,3 +414,41 @@
 	return kctl;
 }
 EXPORT_SYMBOL(snd_ctl_make_virtual_master);
+
+/**
+ * snd_ctl_add_vmaster_hook - Add a hook to a vmaster control
+ * @kcontrol: vmaster kctl element
+ * @hook: the hook function
+ *
+ * Adds the given hook to the vmaster control element so that it's called
+ * at each time when the value is changed.
+ */
+int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol,
+			     void (*hook)(void *private_data, int),
+			     void *private_data)
+{
+	struct link_master *master = snd_kcontrol_chip(kcontrol);
+	master->hook = hook;
+	master->hook_private_data = private_data;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_ctl_add_vmaster_hook);
+
+/**
+ * snd_ctl_sync_vmaster_hook - Sync the vmaster hook
+ * @kcontrol: vmaster kctl element
+ *
+ * Call the hook function to synchronize with the current value of the given
+ * vmaster element.  NOP when NULL is passed to @kcontrol or the hook doesn't
+ * exist.
+ */
+void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kcontrol)
+{
+	struct link_master *master;
+	if (!kcontrol)
+		return;
+	master = snd_kcontrol_chip(kcontrol);
+	if (master->hook)
+		master->hook(master->hook_private_data, master->val);
+}
+EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster_hook);
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
index c896116..fe5ae09 100644
--- a/sound/drivers/Kconfig
+++ b/sound/drivers/Kconfig
@@ -50,7 +50,8 @@
 	  before the other sound driver of yours, making the
 	  pc-speaker a default sound device. Which is likely not
 	  what you want. To make this driver play nicely with other
-	  sound driver, you can add this into your /etc/modprobe.conf:
+	  sound driver, you can add this in a configuration file under
+	  /etc/modprobe.d/ directory:
 	  options snd-pcsp index=2
 
 	  You don't need this driver if you only want your pc-speaker to beep.
diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c
index cd094ec..d428ffe 100644
--- a/sound/firewire/isight.c
+++ b/sound/firewire/isight.c
@@ -611,7 +611,6 @@
 
 	fw_iso_resources_destroy(&isight->resources);
 	fw_unit_put(isight->unit);
-	fw_device_put(isight->device);
 	mutex_destroy(&isight->mutex);
 }
 
@@ -644,7 +643,7 @@
 	isight->card = card;
 	mutex_init(&isight->mutex);
 	isight->unit = fw_unit_get(unit);
-	isight->device = fw_device_get(fw_dev);
+	isight->device = fw_dev;
 	isight->audio_base = get_unit_base(unit);
 	if (!isight->audio_base) {
 		dev_err(&unit->device, "audio unit base not found\n");
@@ -681,7 +680,6 @@
 
 err_unit:
 	fw_unit_put(isight->unit);
-	fw_device_put(isight->device);
 	mutex_destroy(&isight->mutex);
 error:
 	snd_card_free(card);
diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c
index cbe6bb9..297244e 100644
--- a/sound/firewire/speakers.c
+++ b/sound/firewire/speakers.c
@@ -656,12 +656,10 @@
 static void fwspk_card_free(struct snd_card *card)
 {
 	struct fwspk *fwspk = card->private_data;
-	struct fw_device *dev = fw_parent_device(fwspk->unit);
 
 	amdtp_out_stream_destroy(&fwspk->stream);
 	cmp_connection_destroy(&fwspk->connection);
 	fw_unit_put(fwspk->unit);
-	fw_device_put(dev);
 	mutex_destroy(&fwspk->mutex);
 }
 
@@ -718,7 +716,6 @@
 	fwspk = card->private_data;
 	fwspk->card = card;
 	mutex_init(&fwspk->mutex);
-	fw_device_get(fw_dev);
 	fwspk->unit = fw_unit_get(unit);
 	fwspk->device_info = fwspk_detect(fw_dev);
 	if (!fwspk->device_info) {
@@ -767,7 +764,6 @@
 	cmp_connection_destroy(&fwspk->connection);
 err_unit:
 	fw_unit_put(fwspk->unit);
-	fw_device_put(fw_dev);
 	mutex_destroy(&fwspk->mutex);
 error:
 	snd_card_free(card);
diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c
index 6b68c82..a63faec 100644
--- a/sound/i2c/other/tea575x-tuner.c
+++ b/sound/i2c/other/tea575x-tuner.c
@@ -25,21 +25,20 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/version.h>
+#include <linux/sched.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
 #include <sound/tea575x-tuner.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips");
 MODULE_LICENSE("GPL");
 
-static int radio_nr = -1;
-module_param(radio_nr, int, 0);
-
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-#define FREQ_LO		 (50UL * 16000)
-#define FREQ_HI		(150UL * 16000)
+#define FREQ_LO		 (76U * 16000)
+#define FREQ_HI		(108U * 16000)
 
 /*
  * definitions
@@ -90,7 +89,7 @@
 		tea->ops->set_pins(tea, 0);
 }
 
-static unsigned int snd_tea575x_read(struct snd_tea575x *tea)
+static u32 snd_tea575x_read(struct snd_tea575x *tea)
 {
 	u16 l, rdata;
 	u32 data = 0;
@@ -121,11 +120,13 @@
 	return data;
 }
 
-static void snd_tea575x_get_freq(struct snd_tea575x *tea)
+static u32 snd_tea575x_get_freq(struct snd_tea575x *tea)
 {
-	unsigned long freq;
+	u32 freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK;
 
-	freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK;
+	if (freq == 0)
+		return freq;
+
 	/* freq *= 12.5 */
 	freq *= 125;
 	freq /= 10;
@@ -135,14 +136,13 @@
 	else
 		freq -= TEA575X_FMIF;
 
-	tea->freq = freq * 16;		/* from kHz */
+	return clamp(freq * 16, FREQ_LO, FREQ_HI); /* from kHz */
 }
 
 static void snd_tea575x_set_freq(struct snd_tea575x *tea)
 {
-	unsigned long freq;
+	u32 freq = tea->freq;
 
-	freq = clamp(tea->freq, FREQ_LO, FREQ_HI);
 	freq /= 16;		/* to kHz */
 	/* crystal fixup */
 	if (tea->tea5759)
@@ -167,12 +167,14 @@
 {
 	struct snd_tea575x *tea = video_drvdata(file);
 
-	strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver));
+	strlcpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver));
 	strlcpy(v->card, tea->card, sizeof(v->card));
 	strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card));
 	strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
-	v->version = RADIO_VERSION;
-	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	if (!tea->cannot_read_data)
+		v->device_caps |= V4L2_CAP_HW_FREQ_SEEK;
+	v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
@@ -191,18 +193,24 @@
 	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
 	v->rangelow = FREQ_LO;
 	v->rangehigh = FREQ_HI;
-	v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-	v->audmode = tea->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
+	v->rxsubchans = tea->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+	v->audmode = (tea->val & TEA575X_BIT_MONO) ?
+		V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO;
 	v->signal = tea->tuned ? 0xffff : 0;
-
 	return 0;
 }
 
 static int vidioc_s_tuner(struct file *file, void *priv,
 					struct v4l2_tuner *v)
 {
-	if (v->index > 0)
+	struct snd_tea575x *tea = video_drvdata(file);
+
+	if (v->index)
 		return -EINVAL;
+	tea->val &= ~TEA575X_BIT_MONO;
+	if (v->audmode == V4L2_TUNER_MODE_MONO)
+		tea->val |= TEA575X_BIT_MONO;
+	snd_tea575x_write(tea, tea->val);
 	return 0;
 }
 
@@ -214,7 +222,6 @@
 	if (f->tuner != 0)
 		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
-	snd_tea575x_get_freq(tea);
 	f->frequency = tea->freq;
 	return 0;
 }
@@ -227,33 +234,72 @@
 	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
 		return -EINVAL;
 
-	if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
-		return -EINVAL;
-
-	tea->freq = f->frequency;
-
+	tea->val &= ~TEA575X_BIT_SEARCH;
+	tea->freq = clamp(f->frequency, FREQ_LO, FREQ_HI);
 	snd_tea575x_set_freq(tea);
-
 	return 0;
 }
 
-static int vidioc_g_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
+static int vidioc_s_hw_freq_seek(struct file *file, void *fh,
+					struct v4l2_hw_freq_seek *a)
 {
-	if (a->index > 1)
+	struct snd_tea575x *tea = video_drvdata(file);
+	unsigned long timeout;
+	int i;
+
+	if (tea->cannot_read_data)
+		return -ENOTTY;
+	if (a->tuner || a->wrap_around)
 		return -EINVAL;
 
-	strcpy(a->name, "Radio");
-	a->capability = V4L2_AUDCAP_STEREO;
-	return 0;
-}
+	/* clear the frequency, HW will fill it in */
+	tea->val &= ~TEA575X_BIT_FREQ_MASK;
+	tea->val |= TEA575X_BIT_SEARCH;
+	if (a->seek_upward)
+		tea->val |= TEA575X_BIT_UPDOWN;
+	else
+		tea->val &= ~TEA575X_BIT_UPDOWN;
+	snd_tea575x_write(tea, tea->val);
+	timeout = jiffies + msecs_to_jiffies(10000);
+	for (;;) {
+		if (time_after(jiffies, timeout))
+			break;
+		if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
+			/* some signal arrived, stop search */
+			tea->val &= ~TEA575X_BIT_SEARCH;
+			snd_tea575x_set_freq(tea);
+			return -ERESTARTSYS;
+		}
+		if (!(snd_tea575x_read(tea) & TEA575X_BIT_SEARCH)) {
+			u32 freq;
 
-static int vidioc_s_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
-{
-	if (a->index != 0)
-		return -EINVAL;
-	return 0;
+			/* Found a frequency, wait until it can be read */
+			for (i = 0; i < 100; i++) {
+				msleep(10);
+				freq = snd_tea575x_get_freq(tea);
+				if (freq) /* available */
+					break;
+			}
+			if (freq == 0) /* shouldn't happen */
+				break;
+			/*
+			 * if we moved by less than 50 kHz, or in the wrong
+			 * direction, continue seeking
+			 */
+			if (abs(tea->freq - freq) < 16 * 50 ||
+					(a->seek_upward && freq < tea->freq) ||
+					(!a->seek_upward && freq > tea->freq)) {
+				snd_tea575x_write(tea, tea->val);
+				continue;
+			}
+			tea->freq = freq;
+			tea->val &= ~TEA575X_BIT_SEARCH;
+			return 0;
+		}
+	}
+	tea->val &= ~TEA575X_BIT_SEARCH;
+	snd_tea575x_set_freq(tea);
+	return -EAGAIN;
 }
 
 static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -273,23 +319,27 @@
 static const struct v4l2_file_operations tea575x_fops = {
 	.owner		= THIS_MODULE,
 	.unlocked_ioctl	= video_ioctl2,
+	.open           = v4l2_fh_open,
+	.release        = v4l2_fh_release,
+	.poll           = v4l2_ctrl_poll,
 };
 
 static const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
 	.vidioc_querycap    = vidioc_querycap,
 	.vidioc_g_tuner     = vidioc_g_tuner,
 	.vidioc_s_tuner     = vidioc_s_tuner,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
 	.vidioc_g_frequency = vidioc_g_frequency,
 	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek,
+	.vidioc_log_status  = v4l2_ctrl_log_status,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
-static struct video_device tea575x_radio = {
-	.name           = "tea575x-tuner",
+static const struct video_device tea575x_radio = {
 	.fops           = &tea575x_fops,
 	.ioctl_ops 	= &tea575x_ioctl_ops,
-	.release	= video_device_release_empty,
+	.release        = video_device_release_empty,
 };
 
 static const struct v4l2_ctrl_ops tea575x_ctrl_ops = {
@@ -303,27 +353,34 @@
 {
 	int retval;
 
-	tea->mute = 1;
+	tea->mute = true;
 
-	snd_tea575x_write(tea, 0x55AA);
-	if (snd_tea575x_read(tea) != 0x55AA)
-		return -ENODEV;
+	/* Not all devices can or know how to read the data back.
+	   Such devices can set cannot_read_data to true. */
+	if (!tea->cannot_read_data) {
+		snd_tea575x_write(tea, 0x55AA);
+		if (snd_tea575x_read(tea) != 0x55AA)
+			return -ENODEV;
+	}
 
-	tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40;
+	tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_5_28;
 	tea->freq = 90500 * 16;		/* 90.5Mhz default */
 	snd_tea575x_set_freq(tea);
 
 	tea->vd = tea575x_radio;
 	video_set_drvdata(&tea->vd, tea);
 	mutex_init(&tea->mutex);
+	strlcpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name));
 	tea->vd.lock = &tea->mutex;
+	tea->vd.v4l2_dev = tea->v4l2_dev;
+	tea->vd.ctrl_handler = &tea->ctrl_handler;
+	set_bit(V4L2_FL_USE_FH_PRIO, &tea->vd.flags);
 
 	v4l2_ctrl_handler_init(&tea->ctrl_handler, 1);
-	tea->vd.ctrl_handler = &tea->ctrl_handler;
 	v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
 	retval = tea->ctrl_handler.error;
 	if (retval) {
-		printk(KERN_ERR "tea575x-tuner: can't initialize controls\n");
+		v4l2_err(tea->v4l2_dev, "can't initialize controls\n");
 		v4l2_ctrl_handler_free(&tea->ctrl_handler);
 		return retval;
 	}
@@ -338,9 +395,9 @@
 
 	v4l2_ctrl_handler_setup(&tea->ctrl_handler);
 
-	retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, radio_nr);
+	retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->radio_nr);
 	if (retval) {
-		printk(KERN_ERR "tea575x-tuner: can't register video device!\n");
+		v4l2_err(tea->v4l2_dev, "can't register video device!\n");
 		v4l2_ctrl_handler_free(&tea->ctrl_handler);
 		return retval;
 	}
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index babaedd..d7ccf28 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -65,7 +65,7 @@
 static char *id = SNDRV_DEFAULT_STR1;		/* ID for this card */
 //static bool enable = SNDRV_DEFAULT_ENABLE1;	/* Enable this card */
 #ifdef CONFIG_PNP
-static int isapnp = 1;			/* Enable ISA PnP detection */
+static bool isapnp = true;			/* Enable ISA PnP detection */
 #endif
 static long port = SNDRV_DEFAULT_PORT1; 	/* 0x530,0xe80,0xf40,0x604 */
 static long mpu_port = SNDRV_DEFAULT_PORT1;	/* 0x300,0x310,0x320,0x330 */
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c
index eba7345..2c79d60 100644
--- a/sound/oss/msnd_pinnacle.c
+++ b/sound/oss/msnd_pinnacle.c
@@ -1631,7 +1631,7 @@
 static int joystick_io __initdata = 0;
 
 /* If we have the digital daugherboard... */
-static int digital __initdata = 0;
+static bool digital __initdata = false;
 #endif
 
 static int fifosize __initdata =	DEFFIFOSIZE;
diff --git a/sound/oss/os.h b/sound/oss/os.h
index a1a962d..75ad0cd 100644
--- a/sound/oss/os.h
+++ b/sound/oss/os.h
@@ -16,7 +16,6 @@
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <asm/page.h>
-#include <asm/system.h>
 #include <linux/vmalloc.h>
 #include <asm/uaccess.h>
 #include <linux/poll.h>
diff --git a/sound/oss/vidc.c b/sound/oss/vidc.c
index 12ba28e..92ca5be 100644
--- a/sound/oss/vidc.c
+++ b/sound/oss/vidc.c
@@ -28,7 +28,6 @@
 #include <asm/io.h>
 #include <asm/hardware/iomd.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 
 #include "sound_config.h"
 #include "vidc.h"
diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c
index 5246874..24c430f 100644
--- a/sound/oss/waveartist.c
+++ b/sound/oss/waveartist.c
@@ -42,7 +42,6 @@
 #include <linux/spinlock.h>
 #include <linux/bitops.h>
 
-#include <asm/system.h>
 
 #include "sound_config.h"
 #include "waveartist.h"
diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h
index 4cc315d..8c63200 100644
--- a/sound/pci/asihpi/hpi_internal.h
+++ b/sound/pci/asihpi/hpi_internal.h
@@ -42,7 +42,7 @@
 If this function succeeds, then HpiOs_LockedMem_GetVirtAddr() and
 HpiOs_LockedMem_GetPyhsAddr() will always succed on the returned handle.
 */
-u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_locked_mem_handle,
+int hpios_locked_mem_alloc(struct consistent_dma_area *p_locked_mem_handle,
 							   /**< memory handle */
 	u32 size, /**< Size in bytes to allocate */
 	struct pci_dev *p_os_reference
diff --git a/sound/pci/asihpi/hpios.c b/sound/pci/asihpi/hpios.c
index 2d7d1c2..87f4385 100644
--- a/sound/pci/asihpi/hpios.c
+++ b/sound/pci/asihpi/hpios.c
@@ -43,7 +43,7 @@
 
 On error, return -ENOMEM, and *pMemArea.size = 0
 */
-u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_mem_area, u32 size,
+int hpios_locked_mem_alloc(struct consistent_dma_area *p_mem_area, u32 size,
 	struct pci_dev *pdev)
 {
 	/*?? any benefit in using managed dmam_alloc_coherent? */
diff --git a/sound/pci/asihpi/hpios.h b/sound/pci/asihpi/hpios.h
index c5cef11..d3fbd0d 100644
--- a/sound/pci/asihpi/hpios.h
+++ b/sound/pci/asihpi/hpios.h
@@ -30,7 +30,6 @@
 #define HPI_BUILD_KERNEL_MODE
 
 #include <linux/io.h>
-#include <asm/system.h>
 #include <linux/ioctl.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
index bb93815..466a5c8 100644
--- a/sound/pci/au88x0/au88x0.h
+++ b/sound/pci/au88x0/au88x0.h
@@ -26,7 +26,7 @@
 #include <sound/mpu401.h>
 #include <sound/hwdep.h>
 #include <sound/ac97_codec.h>
-
+#include <sound/tlv.h>
 #endif
 
 #ifndef CHIP_AU8820
@@ -107,6 +107,14 @@
 #define NR_WTPB 0x20		/* WT channels per each bank. */
 #define NR_PCM	0x10
 
+struct pcm_vol {
+	struct snd_kcontrol *kctl;
+	int active;
+	int dma;
+	int mixin[4];
+	int vol[4];
+};
+
 /* Structs */
 typedef struct {
 	//int this_08;          /* Still unknown */
@@ -168,6 +176,7 @@
 	/* Xtalk canceler */
 	int xt_mode;		/* 1: speakers, 0:headphones. */
 #endif
+	struct pcm_vol pcm_vol[NR_PCM];
 
 	int isquad;		/* cache of extended ID codec flag. */
 
@@ -239,7 +248,7 @@
 /* Connection  stuff. */
 static void vortex_connect_default(vortex_t * vortex, int en);
 static int vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch,
-				 int dir, int type);
+				 int dir, int type, int subdev);
 static char vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out,
 				  int restype);
 #ifndef CHIP_AU8810
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index 6933a27..525f881 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -2050,8 +2050,6 @@
 }
 
 /* Default Connections  */
-static int
-vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type);
 
 static void vortex_connect_default(vortex_t * vortex, int en)
 {
@@ -2111,15 +2109,13 @@
   Return: Return allocated DMA or same DMA passed as "dma" when dma >= 0.
 */
 static int
-vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type)
+vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir,
+			int type, int subdev)
 {
 	stream_t *stream;
 	int i, en;
+	struct pcm_vol *p;
 	
-	if ((nr_ch == 3)
-	    || ((dir == SNDRV_PCM_STREAM_CAPTURE) && (nr_ch > 2)))
-		return -EBUSY;
-
 	if (dma >= 0) {
 		en = 0;
 		vortex_adb_checkinout(vortex,
@@ -2250,6 +2246,14 @@
 							      MIX_DEFIGAIN);
 #endif
 			}
+			if (stream->type == VORTEX_PCM_ADB && en) {
+				p = &vortex->pcm_vol[subdev];
+				p->dma = dma;
+				for (i = 0; i < nr_ch; i++)
+					p->mixin[i] = mix[i];
+				for (i = 0; i < ch_top; i++)
+					p->vol[i] = 0;
+			}
 		}
 #ifndef CHIP_AU8820
 		else {
@@ -2473,7 +2477,7 @@
 		hwread(vortex->mmio, VORTEX_IRQ_STAT);
 		handled = 1;
 	}
-	if (source & IRQ_MIDI) {
+	if ((source & IRQ_MIDI) && vortex->rmidi) {
 		snd_mpu401_uart_interrupt(vortex->irq,
 					  vortex->rmidi->private_data);
 		handled = 1;
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
index 0ef2f97..e59f120 100644
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -122,6 +122,18 @@
 	.mask = 0,
 };
 #endif
+
+static void vortex_notify_pcm_vol_change(struct snd_card *card,
+			struct snd_kcontrol *kctl, int activate)
+{
+	if (activate)
+		kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+	else
+		kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+	snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE |
+				SNDRV_CTL_EVENT_MASK_INFO, &(kctl->id));
+}
+
 /* open callback */
 static int snd_vortex_pcm_open(struct snd_pcm_substream *substream)
 {
@@ -230,12 +242,14 @@
 		if (stream != NULL)
 			vortex_adb_allocroute(chip, stream->dma,
 					      stream->nr_ch, stream->dir,
-					      stream->type);
+					      stream->type,
+					      substream->number);
 		/* Alloc routes. */
 		dma =
 		    vortex_adb_allocroute(chip, -1,
 					  params_channels(hw_params),
-					  substream->stream, type);
+					  substream->stream, type,
+					  substream->number);
 		if (dma < 0) {
 			spin_unlock_irq(&chip->lock);
 			return dma;
@@ -246,6 +260,11 @@
 		vortex_adbdma_setbuffers(chip, dma,
 					 params_period_bytes(hw_params),
 					 params_periods(hw_params));
+		if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
+			chip->pcm_vol[substream->number].active = 1;
+			vortex_notify_pcm_vol_change(chip->card,
+				chip->pcm_vol[substream->number].kctl, 1);
+		}
 	}
 #ifndef CHIP_AU8810
 	else {
@@ -275,10 +294,18 @@
 	spin_lock_irq(&chip->lock);
 	// Delete audio routes.
 	if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
-		if (stream != NULL)
+		if (stream != NULL) {
+			if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
+				chip->pcm_vol[substream->number].active = 0;
+				vortex_notify_pcm_vol_change(chip->card,
+					chip->pcm_vol[substream->number].kctl,
+					0);
+			}
 			vortex_adb_allocroute(chip, stream->dma,
 					      stream->nr_ch, stream->dir,
-					      stream->type);
+					      stream->type,
+					      substream->number);
+		}
 	}
 #ifndef CHIP_AU8810
 	else {
@@ -506,6 +533,83 @@
 	},
 };
 
+/* subdevice PCM Volume control */
+
+static int snd_vortex_pcm_vol_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
+	uinfo->value.integer.min = -128;
+	uinfo->value.integer.max = 32;
+	return 0;
+}
+
+static int snd_vortex_pcm_vol_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int i;
+	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
+	int subdev = kcontrol->id.subdevice;
+	struct pcm_vol *p = &vortex->pcm_vol[subdev];
+	int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
+	for (i = 0; i < max_chn; i++)
+		ucontrol->value.integer.value[i] = p->vol[i];
+	return 0;
+}
+
+static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int i;
+	int changed = 0;
+	int mixin;
+	unsigned char vol;
+	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
+	int subdev = kcontrol->id.subdevice;
+	struct pcm_vol *p = &vortex->pcm_vol[subdev];
+	int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
+	for (i = 0; i < max_chn; i++) {
+		if (p->vol[i] != ucontrol->value.integer.value[i]) {
+			p->vol[i] = ucontrol->value.integer.value[i];
+			if (p->active) {
+				switch (vortex->dma_adb[p->dma].nr_ch) {
+				case 1:
+					mixin = p->mixin[0];
+					break;
+				case 2:
+				default:
+					mixin = p->mixin[(i < 2) ? i : (i - 2)];
+					break;
+				case 4:
+					mixin = p->mixin[i];
+					break;
+				};
+				vol = p->vol[i];
+				vortex_mix_setinputvolumebyte(vortex,
+					vortex->mixplayb[i], mixin, vol);
+			}
+			changed = 1;
+		}
+	}
+	return changed;
+}
+
+static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400);
+
+static struct snd_kcontrol_new snd_vortex_pcm_vol __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+	.name = "PCM Playback Volume",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+		SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+		SNDRV_CTL_ELEM_ACCESS_INACTIVE,
+	.info = snd_vortex_pcm_vol_info,
+	.get = snd_vortex_pcm_vol_get,
+	.put = snd_vortex_pcm_vol_put,
+	.tlv = { .p = vortex_pcm_vol_db_scale },
+};
+
 /* create a pcm device */
 static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
 {
@@ -555,5 +659,20 @@
 				return err;
 		}
 	}
+	if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_ADB) {
+		for (i = 0; i < NR_PCM; i++) {
+			chip->pcm_vol[i].active = 0;
+			chip->pcm_vol[i].dma = -1;
+			kctl = snd_ctl_new1(&snd_vortex_pcm_vol, chip);
+			if (!kctl)
+				return -ENOMEM;
+			chip->pcm_vol[i].kctl = kctl;
+			kctl->id.device = 0;
+			kctl->id.subdevice = i;
+			err = snd_ctl_add(chip->card, kctl);
+			if (err < 0)
+				return err;
+		}
+	}
 	return 0;
 }
diff --git a/sound/pci/aw2/aw2-saa7146.c b/sound/pci/aw2/aw2-saa7146.c
index 8afd8b5..4439636 100644
--- a/sound/pci/aw2/aw2-saa7146.c
+++ b/sound/pci/aw2/aw2-saa7146.c
@@ -27,7 +27,6 @@
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <asm/system.h>
 #include <asm/io.h>
 #include <sound/core.h>
 #include <sound/initval.h>
diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c
index b78f3fc..6109490 100644
--- a/sound/pci/ctxfi/ctvmem.c
+++ b/sound/pci/ctxfi/ctvmem.c
@@ -36,7 +36,7 @@
 
 	size = CT_PAGE_ALIGN(size);
 	if (size > vm->size) {
-		printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural "
+		printk(KERN_ERR "ctxfi: Fail! No sufficient device virtual "
 				  "memory space available!\n");
 		return NULL;
 	}
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index cb557c6..a8faae1 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -142,6 +142,7 @@
 #ifdef SUPPORT_JOYSTICK
 static bool joystick[SNDRV_CARDS];
 #endif
+static int radio_nr[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
@@ -165,6 +166,9 @@
 module_param_array(joystick, bool, NULL, 0444);
 MODULE_PARM_DESC(joystick, "Enable joystick.");
 #endif
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
+
 
 
 #define NR_APUS			64
@@ -558,6 +562,7 @@
 	struct work_struct hwvol_work;
 
 #ifdef CONFIG_SND_ES1968_RADIO
+	struct v4l2_device v4l2_dev;
 	struct snd_tea575x tea;
 #endif
 };
@@ -2613,6 +2618,7 @@
 
 #ifdef CONFIG_SND_ES1968_RADIO
 	snd_tea575x_exit(&chip->tea);
+	v4l2_device_unregister(&chip->v4l2_dev);
 #endif
 
 	if (chip->irq >= 0)
@@ -2655,6 +2661,7 @@
 				       int capt_streams,
 				       int chip_type,
 				       int do_pm,
+				       int radio_nr,
 				       struct es1968 **chip_ret)
 {
 	static struct snd_device_ops ops = {
@@ -2751,7 +2758,14 @@
 	snd_card_set_dev(card, &pci->dev);
 
 #ifdef CONFIG_SND_ES1968_RADIO
+	err = v4l2_device_register(&pci->dev, &chip->v4l2_dev);
+	if (err < 0) {
+		snd_es1968_free(chip);
+		return err;
+	}
+	chip->tea.v4l2_dev = &chip->v4l2_dev;
 	chip->tea.private_data = chip;
+	chip->tea.radio_nr = radio_nr;
 	chip->tea.ops = &snd_es1968_tea_ops;
 	strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card));
 	sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
@@ -2797,6 +2811,7 @@
 				     pcm_substreams_c[dev],
 				     pci_id->driver_data,
 				     use_pm[dev],
+				     radio_nr[dev],
 				     &chip)) < 0) {
 		snd_card_free(card);
 		return err;
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 9597ef1..a416ea8 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -58,6 +58,7 @@
  *  High 16-bits are video (radio) device number + 1
  */
 static int tea575x_tuner[SNDRV_CARDS];
+static int radio_nr[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the FM801 soundcard.");
@@ -67,6 +68,9 @@
 MODULE_PARM_DESC(enable, "Enable FM801 soundcard.");
 module_param_array(tea575x_tuner, int, NULL, 0444);
 MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (0 = auto, 1 = SF256-PCS, 2=SF256-PCP, 3=SF64-PCR, 8=disable, +16=tuner-only).");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
+
 
 #define TUNER_DISABLED		(1<<3)
 #define TUNER_ONLY		(1<<4)
@@ -197,6 +201,7 @@
 	struct snd_info_entry *proc_entry;
 
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
+	struct v4l2_device v4l2_dev;
 	struct snd_tea575x tea;
 #endif
 
@@ -1154,8 +1159,10 @@
 
       __end_hw:
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
-	if (!(chip->tea575x_tuner & TUNER_DISABLED))
+	if (!(chip->tea575x_tuner & TUNER_DISABLED)) {
 		snd_tea575x_exit(&chip->tea);
+		v4l2_device_unregister(&chip->v4l2_dev);
+	}
 #endif
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
@@ -1175,6 +1182,7 @@
 static int __devinit snd_fm801_create(struct snd_card *card,
 				      struct pci_dev * pci,
 				      int tea575x_tuner,
+				      int radio_nr,
 				      struct fm801 ** rchip)
 {
 	struct fm801 *chip;
@@ -1234,6 +1242,13 @@
 	snd_card_set_dev(card, &pci->dev);
 
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
+	err = v4l2_device_register(&pci->dev, &chip->v4l2_dev);
+	if (err < 0) {
+		snd_fm801_free(chip);
+		return err;
+	}
+	chip->tea.v4l2_dev = &chip->v4l2_dev;
+	chip->tea.radio_nr = radio_nr;
 	chip->tea.private_data = chip;
 	chip->tea.ops = &snd_fm801_tea_ops;
 	sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
@@ -1241,6 +1256,7 @@
 	    (tea575x_tuner & TUNER_TYPE_MASK) < 4) {
 		if (snd_tea575x_init(&chip->tea)) {
 			snd_printk(KERN_ERR "TEA575x radio not found\n");
+			snd_fm801_free(chip);
 			return -ENODEV;
 		}
 	} else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) {
@@ -1287,7 +1303,7 @@
 	err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
 	if (err < 0)
 		return err;
-	if ((err = snd_fm801_create(card, pci, tea575x_tuner[dev], &chip)) < 0) {
+	if ((err = snd_fm801_create(card, pci, tea575x_tuner[dev], radio_nr[dev], &chip)) < 0) {
 		snd_card_free(card);
 		return err;
 	}
diff --git a/sound/pci/hda/alc260_quirks.c b/sound/pci/hda/alc260_quirks.c
deleted file mode 100644
index 3b5170b..0000000
--- a/sound/pci/hda/alc260_quirks.c
+++ /dev/null
@@ -1,968 +0,0 @@
-/*
- * ALC260 quirk models
- * included by patch_realtek.c
- */
-
-/* ALC260 models */
-enum {
-	ALC260_AUTO,
-	ALC260_BASIC,
-	ALC260_FUJITSU_S702X,
-	ALC260_ACER,
-	ALC260_WILL,
-	ALC260_REPLACER_672V,
-	ALC260_FAVORIT100,
-#ifdef CONFIG_SND_DEBUG
-	ALC260_TEST,
-#endif
-	ALC260_MODEL_LAST /* last tag */
-};
-
-static const hda_nid_t alc260_dac_nids[1] = {
-	/* front */
-	0x02,
-};
-
-static const hda_nid_t alc260_adc_nids[1] = {
-	/* ADC0 */
-	0x04,
-};
-
-static const hda_nid_t alc260_adc_nids_alt[1] = {
-	/* ADC1 */
-	0x05,
-};
-
-/* NIDs used when simultaneous access to both ADCs makes sense.  Note that
- * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
- */
-static const hda_nid_t alc260_dual_adc_nids[2] = {
-	/* ADC0, ADC1 */
-	0x04, 0x05
-};
-
-#define ALC260_DIGOUT_NID	0x03
-#define ALC260_DIGIN_NID	0x06
-
-static const struct hda_input_mux alc260_capture_source = {
-	.num_items = 4,
-	.items = {
-		{ "Mic", 0x0 },
-		{ "Front Mic", 0x1 },
-		{ "Line", 0x2 },
-		{ "CD", 0x4 },
-	},
-};
-
-/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
- * headphone jack and the internal CD lines since these are the only pins at
- * which audio can appear.  For flexibility, also allow the option of
- * recording the mixer output on the second ADC (ADC0 doesn't have a
- * connection to the mixer output).
- */
-static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
-	{
-		.num_items = 3,
-		.items = {
-			{ "Mic/Line", 0x0 },
-			{ "CD", 0x4 },
-			{ "Headphone", 0x2 },
-		},
-	},
-	{
-		.num_items = 4,
-		.items = {
-			{ "Mic/Line", 0x0 },
-			{ "CD", 0x4 },
-			{ "Headphone", 0x2 },
-			{ "Mixer", 0x5 },
-		},
-	},
-
-};
-
-/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
- * the Fujitsu S702x, but jacks are marked differently.
- */
-static const struct hda_input_mux alc260_acer_capture_sources[2] = {
-	{
-		.num_items = 4,
-		.items = {
-			{ "Mic", 0x0 },
-			{ "Line", 0x2 },
-			{ "CD", 0x4 },
-			{ "Headphone", 0x5 },
-		},
-	},
-	{
-		.num_items = 5,
-		.items = {
-			{ "Mic", 0x0 },
-			{ "Line", 0x2 },
-			{ "CD", 0x4 },
-			{ "Headphone", 0x6 },
-			{ "Mixer", 0x5 },
-		},
-	},
-};
-
-/* Maxdata Favorit 100XS */
-static const struct hda_input_mux alc260_favorit100_capture_sources[2] = {
-	{
-		.num_items = 2,
-		.items = {
-			{ "Line/Mic", 0x0 },
-			{ "CD", 0x4 },
-		},
-	},
-	{
-		.num_items = 3,
-		.items = {
-			{ "Line/Mic", 0x0 },
-			{ "CD", 0x4 },
-			{ "Mixer", 0x5 },
-		},
-	},
-};
-
-/*
- * This is just place-holder, so there's something for alc_build_pcms to look
- * at when it calculates the maximum number of channels. ALC260 has no mixer
- * element which allows changing the channel mode, so the verb list is
- * never used.
- */
-static const struct hda_channel_mode alc260_modes[1] = {
-	{ 2, NULL },
-};
-
-
-/* Mixer combinations
- *
- * basic: base_output + input + pc_beep + capture
- * fujitsu: fujitsu + capture
- * acer: acer + capture
- */
-
-static const struct snd_kcontrol_new alc260_base_output_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new alc260_input_mixer[] = {
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
-	{ } /* end */
-};
-
-/* Fujitsu S702x series laptops.  ALC260 pin usage: Mic/Line jack = 0x12,
- * HP jack = 0x14, CD audio =  0x16, internal speaker = 0x10.
- */
-static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
-	ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
-	ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
-	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
-	{ } /* end */
-};
-
-/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks.  Note that current
- * versions of the ALC260 don't act on requests to enable mic bias from NID
- * 0x0f (used to drive the headphone jack in these laptops).  The ALC260
- * datasheet doesn't mention this restriction.  At this stage it's not clear
- * whether this behaviour is intentional or is a hardware bug in chip
- * revisions available in early 2006.  Therefore for now allow the
- * "Headphone Jack Mode" control to span all choices, but if it turns out
- * that the lack of mic bias for this NID is intentional we could change the
- * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
- *
- * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
- * don't appear to make the mic bias available from the "line" jack, even
- * though the NID used for this jack (0x14) can supply it.  The theory is
- * that perhaps Acer have included blocking capacitors between the ALC260
- * and the output jack.  If this turns out to be the case for all such
- * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
- * to ALC_PIN_DIR_INOUT_NOMICBIAS.
- *
- * The C20x Tablet series have a mono internal speaker which is controlled
- * via the chip's Mono sum widget and pin complex, so include the necessary
- * controls for such models.  On models without a "mono speaker" the control
- * won't do anything.
- */
-static const struct snd_kcontrol_new alc260_acer_mixer[] = {
-	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
-	ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
-	HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
-			      HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
-			   HDA_INPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
-	ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
-	ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
-	{ } /* end */
-};
-
-/* Maxdata Favorit 100XS: one output and one input (0x12) jack
- */
-static const struct snd_kcontrol_new alc260_favorit100_mixer[] = {
-	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
-	ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
-	HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
-	ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
-	{ } /* end */
-};
-
-/* Packard bell V7900  ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
- * Line In jack = 0x14, CD audio =  0x16, pc beep = 0x17.
- */
-static const struct snd_kcontrol_new alc260_will_mixer[] = {
-	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
-	ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
-	ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
-	{ } /* end */
-};
-
-/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
- * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
- */
-static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
-	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
-	ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
-	HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
-	HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
-	ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
-	{ } /* end */
-};
-
-/*
- * initialization verbs
- */
-static const struct hda_verb alc260_init_verbs[] = {
-	/* Line In pin widget for input */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	/* CD pin widget for input */
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	/* Mic1 (rear panel) pin widget for input and vref at 80% */
-	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	/* Mic2 (front panel) pin widget for input and vref at 80% */
-	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	/* LINE-2 is used for line-out in rear */
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	/* select line-out */
-	{0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
-	/* LINE-OUT pin */
-	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	/* enable HP */
-	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	/* enable Mono */
-	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	/* mute capture amp left and right */
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	/* set connection select to line in (default select for this ADC) */
-	{0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
-	/* mute capture amp left and right */
-	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	/* set connection select to line in (default select for this ADC) */
-	{0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
-	/* set vol=0 Line-Out mixer amp left and right */
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	/* unmute pin widget amp left and right (no gain on this amp) */
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* set vol=0 HP mixer amp left and right */
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	/* unmute pin widget amp left and right (no gain on this amp) */
-	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* set vol=0 Mono mixer amp left and right */
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	/* unmute pin widget amp left and right (no gain on this amp) */
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* unmute LINE-2 out pin */
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
-	 * Line In 2 = 0x03
-	 */
-	/* mute analog inputs */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	/* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
-	/* mute Front out path */
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* mute Headphone out path */
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* mute Mono out path */
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{ }
-};
-
-/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
- * laptops.  ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
- * audio = 0x16, internal speaker = 0x10.
- */
-static const struct hda_verb alc260_fujitsu_init_verbs[] = {
-	/* Disable all GPIOs */
-	{0x01, AC_VERB_SET_GPIO_MASK, 0},
-	/* Internal speaker is connected to headphone pin */
-	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	/* Headphone/Line-out jack connects to Line1 pin; make it an output */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	/* Mic/Line-in jack is connected to mic1 pin, so make it an input */
-	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	/* Ensure all other unused pins are disabled and muted. */
-	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-
-	/* Disable digital (SPDIF) pins */
-	{0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
-	{0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
-
-	/* Ensure Line1 pin widget takes its input from the OUT1 sum bus
-	 * when acting as an output.
-	 */
-	{0x0d, AC_VERB_SET_CONNECT_SEL, 0},
-
-	/* Start with output sum widgets muted and their output gains at min */
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-	/* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
-	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Unmute Line1 pin widget output buffer since it starts as an output.
-	 * If the pin mode is changed by the user the pin mode control will
-	 * take care of enabling the pin's input/output buffers as needed.
-	 * Therefore there's no need to enable the input buffer at this
-	 * stage.
-	 */
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Unmute input buffer of pin widget used for Line-in (no equiv
-	 * mixer ctrl)
-	 */
-	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-	/* Mute capture amp left and right */
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	/* Set ADC connection select to match default mixer setting - line
-	 * in (on mic1 pin)
-	 */
-	{0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-	/* Do the same for the second ADC: mute capture input amp and
-	 * set ADC connection to line in (on mic1 pin)
-	 */
-	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-	/* Mute all inputs to mixer widget (even unconnected ones) */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
-
-	{ }
-};
-
-/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
- * similar laptops (adapted from Fujitsu init verbs).
- */
-static const struct hda_verb alc260_acer_init_verbs[] = {
-	/* On TravelMate laptops, GPIO 0 enables the internal speaker and
-	 * the headphone jack.  Turn this on and rely on the standard mute
-	 * methods whenever the user wants to turn these outputs off.
-	 */
-	{0x01, AC_VERB_SET_GPIO_MASK, 0x01},
-	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
-	{0x01, AC_VERB_SET_GPIO_DATA, 0x01},
-	/* Internal speaker/Headphone jack is connected to Line-out pin */
-	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	/* Internal microphone/Mic jack is connected to Mic1 pin */
-	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
-	/* Line In jack is connected to Line1 pin */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	/* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
-	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	/* Ensure all other unused pins are disabled and muted. */
-	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	/* Disable digital (SPDIF) pins */
-	{0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
-	{0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
-
-	/* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
-	 * bus when acting as outputs.
-	 */
-	{0x0b, AC_VERB_SET_CONNECT_SEL, 0},
-	{0x0d, AC_VERB_SET_CONNECT_SEL, 0},
-
-	/* Start with output sum widgets muted and their output gains at min */
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-	/* Unmute Line-out pin widget amp left and right
-	 * (no equiv mixer ctrl)
-	 */
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Unmute mono pin widget amp output (no equiv mixer ctrl) */
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Unmute Mic1 and Line1 pin widget input buffers since they start as
-	 * inputs. If the pin mode is changed by the user the pin mode control
-	 * will take care of enabling the pin's input/output buffers as needed.
-	 * Therefore there's no need to enable the input buffer at this
-	 * stage.
-	 */
-	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-	/* Mute capture amp left and right */
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	/* Set ADC connection select to match default mixer setting - mic
-	 * (on mic1 pin)
-	 */
-	{0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-	/* Do similar with the second ADC: mute capture input amp and
-	 * set ADC connection to mic to match ALSA's default state.
-	 */
-	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-	/* Mute all inputs to mixer widget (even unconnected ones) */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
-
-	{ }
-};
-
-/* Initialisation sequence for Maxdata Favorit 100XS
- * (adapted from Acer init verbs).
- */
-static const struct hda_verb alc260_favorit100_init_verbs[] = {
-	/* GPIO 0 enables the output jack.
-	 * Turn this on and rely on the standard mute
-	 * methods whenever the user wants to turn these outputs off.
-	 */
-	{0x01, AC_VERB_SET_GPIO_MASK, 0x01},
-	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
-	{0x01, AC_VERB_SET_GPIO_DATA, 0x01},
-	/* Line/Mic input jack is connected to Mic1 pin */
-	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
-	/* Ensure all other unused pins are disabled and muted. */
-	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	/* Disable digital (SPDIF) pins */
-	{0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
-	{0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
-
-	/* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
-	 * bus when acting as outputs.
-	 */
-	{0x0b, AC_VERB_SET_CONNECT_SEL, 0},
-	{0x0d, AC_VERB_SET_CONNECT_SEL, 0},
-
-	/* Start with output sum widgets muted and their output gains at min */
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-	/* Unmute Line-out pin widget amp left and right
-	 * (no equiv mixer ctrl)
-	 */
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Unmute Mic1 and Line1 pin widget input buffers since they start as
-	 * inputs. If the pin mode is changed by the user the pin mode control
-	 * will take care of enabling the pin's input/output buffers as needed.
-	 * Therefore there's no need to enable the input buffer at this
-	 * stage.
-	 */
-	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-	/* Mute capture amp left and right */
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	/* Set ADC connection select to match default mixer setting - mic
-	 * (on mic1 pin)
-	 */
-	{0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-	/* Do similar with the second ADC: mute capture input amp and
-	 * set ADC connection to mic to match ALSA's default state.
-	 */
-	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-	/* Mute all inputs to mixer widget (even unconnected ones) */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
-
-	{ }
-};
-
-static const struct hda_verb alc260_will_verbs[] = {
-	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
-	{0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
-	{0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
-	{}
-};
-
-static const struct hda_verb alc260_replacer_672v_verbs[] = {
-	{0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
-	{0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
-	{0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
-
-	{0x01, AC_VERB_SET_GPIO_MASK, 0x01},
-	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
-	{0x01, AC_VERB_SET_GPIO_DATA, 0x00},
-
-	{0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-	{}
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc260_replacer_672v_automute(struct hda_codec *codec)
-{
-        unsigned int present;
-
-	/* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
-	present = snd_hda_jack_detect(codec, 0x0f);
-	if (present) {
-		snd_hda_codec_write_cache(codec, 0x01, 0,
-					  AC_VERB_SET_GPIO_DATA, 1);
-		snd_hda_codec_write_cache(codec, 0x0f, 0,
-					  AC_VERB_SET_PIN_WIDGET_CONTROL,
-					  PIN_HP);
-	} else {
-		snd_hda_codec_write_cache(codec, 0x01, 0,
-					  AC_VERB_SET_GPIO_DATA, 0);
-		snd_hda_codec_write_cache(codec, 0x0f, 0,
-					  AC_VERB_SET_PIN_WIDGET_CONTROL,
-					  PIN_OUT);
-	}
-}
-
-static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
-                                       unsigned int res)
-{
-        if ((res >> 26) == ALC_HP_EVENT)
-                alc260_replacer_672v_automute(codec);
-}
-
-static const struct hda_verb alc260_hp_dc7600_verbs[] = {
-	{0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-	{}
-};
-
-/* Test configuration for debugging, modelled after the ALC880 test
- * configuration.
- */
-#ifdef CONFIG_SND_DEBUG
-static const hda_nid_t alc260_test_dac_nids[1] = {
-	0x02,
-};
-static const hda_nid_t alc260_test_adc_nids[2] = {
-	0x04, 0x05,
-};
-/* For testing the ALC260, each input MUX needs its own definition since
- * the signal assignments are different.  This assumes that the first ADC
- * is NID 0x04.
- */
-static const struct hda_input_mux alc260_test_capture_sources[2] = {
-	{
-		.num_items = 7,
-		.items = {
-			{ "MIC1 pin", 0x0 },
-			{ "MIC2 pin", 0x1 },
-			{ "LINE1 pin", 0x2 },
-			{ "LINE2 pin", 0x3 },
-			{ "CD pin", 0x4 },
-			{ "LINE-OUT pin", 0x5 },
-			{ "HP-OUT pin", 0x6 },
-		},
-        },
-	{
-		.num_items = 8,
-		.items = {
-			{ "MIC1 pin", 0x0 },
-			{ "MIC2 pin", 0x1 },
-			{ "LINE1 pin", 0x2 },
-			{ "LINE2 pin", 0x3 },
-			{ "CD pin", 0x4 },
-			{ "Mixer", 0x5 },
-			{ "LINE-OUT pin", 0x6 },
-			{ "HP-OUT pin", 0x7 },
-		},
-        },
-};
-static const struct snd_kcontrol_new alc260_test_mixer[] = {
-	/* Output driver widgets */
-	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
-
-	/* Modes for retasking pin widgets
-	 * Note: the ALC260 doesn't seem to act on requests to enable mic
-         * bias from NIDs 0x0f and 0x10.  The ALC260 datasheet doesn't
-         * mention this restriction.  At this stage it's not clear whether
-         * this behaviour is intentional or is a hardware bug in chip
-         * revisions available at least up until early 2006.  Therefore for
-         * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
-         * choices, but if it turns out that the lack of mic bias for these
-         * NIDs is intentional we could change their modes from
-         * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
-	 */
-	ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
-	ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
-	ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
-	ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
-	ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
-	ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
-
-	/* Loopback mixer controls */
-	HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
-	HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
-	HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
-	HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
-	HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
-	HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
-	HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
-	HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
-
-	/* Controls for GPIO pins, assuming they are configured as outputs */
-	ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
-	ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
-	ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
-	ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
-
-	/* Switches to allow the digital IO pins to be enabled.  The datasheet
-	 * is ambigious as to which NID is which; testing on laptops which
-	 * make this output available should provide clarification.
-	 */
-	ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
-	ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
-
-	/* A switch allowing EAPD to be enabled.  Some laptops seem to use
-	 * this output to turn on an external amplifier.
-	 */
-	ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
-	ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
-
-	{ } /* end */
-};
-static const struct hda_verb alc260_test_init_verbs[] = {
-	/* Enable all GPIOs as outputs with an initial value of 0 */
-	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
-	{0x01, AC_VERB_SET_GPIO_DATA, 0x00},
-	{0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
-
-	/* Enable retasking pins as output, initially without power amp */
-	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-	/* Disable digital (SPDIF) pins initially, but users can enable
-	 * them via a mixer switch.  In the case of SPDIF-out, this initverb
-	 * payload also sets the generation to 0, output to be in "consumer"
-	 * PCM format, copyright asserted, no pre-emphasis and no validity
-	 * control.
-	 */
-	{0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
-	{0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
-
-	/* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
-	 * OUT1 sum bus when acting as an output.
-	 */
-	{0x0b, AC_VERB_SET_CONNECT_SEL, 0},
-	{0x0c, AC_VERB_SET_CONNECT_SEL, 0},
-	{0x0d, AC_VERB_SET_CONNECT_SEL, 0},
-	{0x0e, AC_VERB_SET_CONNECT_SEL, 0},
-
-	/* Start with output sum widgets muted and their output gains at min */
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
-	/* Unmute retasking pin widget output buffers since the default
-	 * state appears to be output.  As the pin mode is changed by the
-	 * user the pin mode control will take care of enabling the pin's
-	 * input/output buffers as needed.
-	 */
-	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Also unmute the mono-out pin widget */
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-	/* Mute capture amp left and right */
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	/* Set ADC connection select to match default mixer setting (mic1
-	 * pin)
-	 */
-	{0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-	/* Do the same for the second ADC: mute capture input amp and
-	 * set ADC connection to mic1 pin
-	 */
-	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-	/* Mute all inputs to mixer widget (even unconnected ones) */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
-
-	{ }
-};
-#endif
-
-/*
- * ALC260 configurations
- */
-static const char * const alc260_models[ALC260_MODEL_LAST] = {
-	[ALC260_BASIC]		= "basic",
-	[ALC260_FUJITSU_S702X]	= "fujitsu",
-	[ALC260_ACER]		= "acer",
-	[ALC260_WILL]		= "will",
-	[ALC260_REPLACER_672V]	= "replacer",
-	[ALC260_FAVORIT100]	= "favorit100",
-#ifdef CONFIG_SND_DEBUG
-	[ALC260_TEST]		= "test",
-#endif
-	[ALC260_AUTO]		= "auto",
-};
-
-static const struct snd_pci_quirk alc260_cfg_tbl[] = {
-	SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
-	SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
-	SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
-	SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
-	SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
-	SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
-	SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
-	SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
-	SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
-	SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
-	SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
-	{}
-};
-
-static const struct alc_config_preset alc260_presets[] = {
-	[ALC260_BASIC] = {
-		.mixers = { alc260_base_output_mixer,
-			    alc260_input_mixer },
-		.init_verbs = { alc260_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
-		.dac_nids = alc260_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
-		.adc_nids = alc260_dual_adc_nids,
-		.num_channel_mode = ARRAY_SIZE(alc260_modes),
-		.channel_mode = alc260_modes,
-		.input_mux = &alc260_capture_source,
-	},
-	[ALC260_FUJITSU_S702X] = {
-		.mixers = { alc260_fujitsu_mixer },
-		.init_verbs = { alc260_fujitsu_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
-		.dac_nids = alc260_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
-		.adc_nids = alc260_dual_adc_nids,
-		.num_channel_mode = ARRAY_SIZE(alc260_modes),
-		.channel_mode = alc260_modes,
-		.num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
-		.input_mux = alc260_fujitsu_capture_sources,
-	},
-	[ALC260_ACER] = {
-		.mixers = { alc260_acer_mixer },
-		.init_verbs = { alc260_acer_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
-		.dac_nids = alc260_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
-		.adc_nids = alc260_dual_adc_nids,
-		.num_channel_mode = ARRAY_SIZE(alc260_modes),
-		.channel_mode = alc260_modes,
-		.num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
-		.input_mux = alc260_acer_capture_sources,
-	},
-	[ALC260_FAVORIT100] = {
-		.mixers = { alc260_favorit100_mixer },
-		.init_verbs = { alc260_favorit100_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
-		.dac_nids = alc260_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
-		.adc_nids = alc260_dual_adc_nids,
-		.num_channel_mode = ARRAY_SIZE(alc260_modes),
-		.channel_mode = alc260_modes,
-		.num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
-		.input_mux = alc260_favorit100_capture_sources,
-	},
-	[ALC260_WILL] = {
-		.mixers = { alc260_will_mixer },
-		.init_verbs = { alc260_init_verbs, alc260_will_verbs },
-		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
-		.dac_nids = alc260_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
-		.adc_nids = alc260_adc_nids,
-		.dig_out_nid = ALC260_DIGOUT_NID,
-		.num_channel_mode = ARRAY_SIZE(alc260_modes),
-		.channel_mode = alc260_modes,
-		.input_mux = &alc260_capture_source,
-	},
-	[ALC260_REPLACER_672V] = {
-		.mixers = { alc260_replacer_672v_mixer },
-		.init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
-		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
-		.dac_nids = alc260_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
-		.adc_nids = alc260_adc_nids,
-		.dig_out_nid = ALC260_DIGOUT_NID,
-		.num_channel_mode = ARRAY_SIZE(alc260_modes),
-		.channel_mode = alc260_modes,
-		.input_mux = &alc260_capture_source,
-		.unsol_event = alc260_replacer_672v_unsol_event,
-		.init_hook = alc260_replacer_672v_automute,
-	},
-#ifdef CONFIG_SND_DEBUG
-	[ALC260_TEST] = {
-		.mixers = { alc260_test_mixer },
-		.init_verbs = { alc260_test_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
-		.dac_nids = alc260_test_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
-		.adc_nids = alc260_test_adc_nids,
-		.num_channel_mode = ARRAY_SIZE(alc260_modes),
-		.channel_mode = alc260_modes,
-		.num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
-		.input_mux = alc260_test_capture_sources,
-	},
-#endif
-};
-
diff --git a/sound/pci/hda/alc880_quirks.c b/sound/pci/hda/alc880_quirks.c
deleted file mode 100644
index 501501e..0000000
--- a/sound/pci/hda/alc880_quirks.c
+++ /dev/null
@@ -1,1707 +0,0 @@
-/*
- * ALC880 quirk models
- * included by patch_realtek.c
- */
-
-/* ALC880 board config type */
-enum {
-	ALC880_AUTO,
-	ALC880_3ST,
-	ALC880_3ST_DIG,
-	ALC880_5ST,
-	ALC880_5ST_DIG,
-	ALC880_W810,
-	ALC880_Z71V,
-	ALC880_6ST,
-	ALC880_6ST_DIG,
-	ALC880_F1734,
-	ALC880_ASUS,
-	ALC880_ASUS_DIG,
-	ALC880_ASUS_W1V,
-	ALC880_ASUS_DIG2,
-	ALC880_FUJITSU,
-	ALC880_UNIWILL_DIG,
-	ALC880_UNIWILL,
-	ALC880_UNIWILL_P53,
-	ALC880_CLEVO,
-	ALC880_TCL_S700,
-	ALC880_LG,
-#ifdef CONFIG_SND_DEBUG
-	ALC880_TEST,
-#endif
-	ALC880_MODEL_LAST /* last tag */
-};
-
-/*
- * ALC880 3-stack model
- *
- * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
- * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
- *                 F-Mic = 0x1b, HP = 0x19
- */
-
-static const hda_nid_t alc880_dac_nids[4] = {
-	/* front, rear, clfe, rear_surr */
-	0x02, 0x05, 0x04, 0x03
-};
-
-static const hda_nid_t alc880_adc_nids[3] = {
-	/* ADC0-2 */
-	0x07, 0x08, 0x09,
-};
-
-/* The datasheet says the node 0x07 is connected from inputs,
- * but it shows zero connection in the real implementation on some devices.
- * Note: this is a 915GAV bug, fixed on 915GLV
- */
-static const hda_nid_t alc880_adc_nids_alt[2] = {
-	/* ADC1-2 */
-	0x08, 0x09,
-};
-
-#define ALC880_DIGOUT_NID	0x06
-#define ALC880_DIGIN_NID	0x0a
-#define ALC880_PIN_CD_NID	0x1c
-
-static const struct hda_input_mux alc880_capture_source = {
-	.num_items = 4,
-	.items = {
-		{ "Mic", 0x0 },
-		{ "Front Mic", 0x3 },
-		{ "Line", 0x2 },
-		{ "CD", 0x4 },
-	},
-};
-
-/* channel source setting (2/6 channel selection for 3-stack) */
-/* 2ch mode */
-static const struct hda_verb alc880_threestack_ch2_init[] = {
-	/* set line-in to input, mute it */
-	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-	/* set mic-in to input vref 80%, mute it */
-	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-	{ } /* end */
-};
-
-/* 6ch mode */
-static const struct hda_verb alc880_threestack_ch6_init[] = {
-	/* set line-in to output, unmute it */
-	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-	/* set mic-in to output, unmute it */
-	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-	{ } /* end */
-};
-
-static const struct hda_channel_mode alc880_threestack_modes[2] = {
-	{ 2, alc880_threestack_ch2_init },
-	{ 6, alc880_threestack_ch6_init },
-};
-
-static const struct snd_kcontrol_new alc880_three_stack_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Channel Mode",
-		.info = alc_ch_mode_info,
-		.get = alc_ch_mode_get,
-		.put = alc_ch_mode_put,
-	},
-	{ } /* end */
-};
-
-/*
- * ALC880 5-stack model
- *
- * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
- *      Side = 0x02 (0xd)
- * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
- *                 Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
- */
-
-/* additional mixers to alc880_three_stack_mixer */
-static const struct snd_kcontrol_new alc880_five_stack_mixer[] = {
-	HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
-	{ } /* end */
-};
-
-/* channel source setting (6/8 channel selection for 5-stack) */
-/* 6ch mode */
-static const struct hda_verb alc880_fivestack_ch6_init[] = {
-	/* set line-in to input, mute it */
-	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-	{ } /* end */
-};
-
-/* 8ch mode */
-static const struct hda_verb alc880_fivestack_ch8_init[] = {
-	/* set line-in to output, unmute it */
-	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-	{ } /* end */
-};
-
-static const struct hda_channel_mode alc880_fivestack_modes[2] = {
-	{ 6, alc880_fivestack_ch6_init },
-	{ 8, alc880_fivestack_ch8_init },
-};
-
-
-/*
- * ALC880 6-stack model
- *
- * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
- *      Side = 0x05 (0x0f)
- * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
- *   Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
- */
-
-static const hda_nid_t alc880_6st_dac_nids[4] = {
-	/* front, rear, clfe, rear_surr */
-	0x02, 0x03, 0x04, 0x05
-};
-
-static const struct hda_input_mux alc880_6stack_capture_source = {
-	.num_items = 4,
-	.items = {
-		{ "Mic", 0x0 },
-		{ "Front Mic", 0x1 },
-		{ "Line", 0x2 },
-		{ "CD", 0x4 },
-	},
-};
-
-/* fixed 8-channels */
-static const struct hda_channel_mode alc880_sixstack_modes[1] = {
-	{ 8, NULL },
-};
-
-static const struct snd_kcontrol_new alc880_six_stack_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Channel Mode",
-		.info = alc_ch_mode_info,
-		.get = alc_ch_mode_get,
-		.put = alc_ch_mode_put,
-	},
-	{ } /* end */
-};
-
-
-/*
- * ALC880 W810 model
- *
- * W810 has rear IO for:
- * Front (DAC 02)
- * Surround (DAC 03)
- * Center/LFE (DAC 04)
- * Digital out (06)
- *
- * The system also has a pair of internal speakers, and a headphone jack.
- * These are both connected to Line2 on the codec, hence to DAC 02.
- *
- * There is a variable resistor to control the speaker or headphone
- * volume. This is a hardware-only device without a software API.
- *
- * Plugging headphones in will disable the internal speakers. This is
- * implemented in hardware, not via the driver using jack sense. In
- * a similar fashion, plugging into the rear socket marked "front" will
- * disable both the speakers and headphones.
- *
- * For input, there's a microphone jack, and an "audio in" jack.
- * These may not do anything useful with this driver yet, because I
- * haven't setup any initialization verbs for these yet...
- */
-
-static const hda_nid_t alc880_w810_dac_nids[3] = {
-	/* front, rear/surround, clfe */
-	0x02, 0x03, 0x04
-};
-
-/* fixed 6 channels */
-static const struct hda_channel_mode alc880_w810_modes[1] = {
-	{ 6, NULL }
-};
-
-/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
-static const struct snd_kcontrol_new alc880_w810_base_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-	{ } /* end */
-};
-
-
-/*
- * Z710V model
- *
- * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
- * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
- *                 Line = 0x1a
- */
-
-static const hda_nid_t alc880_z71v_dac_nids[1] = {
-	0x02
-};
-#define ALC880_Z71V_HP_DAC	0x03
-
-/* fixed 2 channels */
-static const struct hda_channel_mode alc880_2_jack_modes[1] = {
-	{ 2, NULL }
-};
-
-static const struct snd_kcontrol_new alc880_z71v_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	{ } /* end */
-};
-
-
-/*
- * ALC880 F1734 model
- *
- * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
- * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
- */
-
-static const hda_nid_t alc880_f1734_dac_nids[1] = {
-	0x03
-};
-#define ALC880_F1734_HP_DAC	0x02
-
-static const struct snd_kcontrol_new alc880_f1734_mixer[] = {
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	{ } /* end */
-};
-
-static const struct hda_input_mux alc880_f1734_capture_source = {
-	.num_items = 2,
-	.items = {
-		{ "Mic", 0x1 },
-		{ "CD", 0x4 },
-	},
-};
-
-
-/*
- * ALC880 ASUS model
- *
- * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
- * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
- *  Mic = 0x18, Line = 0x1a
- */
-
-#define alc880_asus_dac_nids	alc880_w810_dac_nids	/* identical with w810 */
-#define alc880_asus_modes	alc880_threestack_modes	/* 2/6 channel mode */
-
-static const struct snd_kcontrol_new alc880_asus_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Channel Mode",
-		.info = alc_ch_mode_info,
-		.get = alc_ch_mode_get,
-		.put = alc_ch_mode_put,
-	},
-	{ } /* end */
-};
-
-/*
- * ALC880 ASUS W1V model
- *
- * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
- * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
- *  Mic = 0x18, Line = 0x1a, Line2 = 0x1b
- */
-
-/* additional mixers to alc880_asus_mixer */
-static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
-	HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
-	HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
-	{ } /* end */
-};
-
-/* TCL S700 */
-static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	{ } /* end */
-};
-
-/* Uniwill */
-static const struct snd_kcontrol_new alc880_uniwill_mixer[] = {
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Channel Mode",
-		.info = alc_ch_mode_info,
-		.get = alc_ch_mode_get,
-		.put = alc_ch_mode_put,
-	},
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	{ } /* end */
-};
-
-/*
- * initialize the codec volumes, etc
- */
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc880_volume_init_verbs[] = {
-	/*
-	 * Unmute ADC0-2 and set the default input to mic-in
-	 */
-	{0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
-	 * mixer widget
-	 * Note: PASD motherboards uses the Line In 2 as the input for front
-	 * panel mic (mic 2)
-	 */
-	/* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-
-	/*
-	 * Set up output mixers (0x0c - 0x0f)
-	 */
-	/* set vol=0 to output mixers */
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	/* set up input amps for analog loopback */
-	/* Amp Indices: DAC = 0, mixer = 1 */
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
-	{ }
-};
-
-/*
- * 3-stack pin configuration:
- * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
- */
-static const struct hda_verb alc880_pin_3stack_init_verbs[] = {
-	/*
-	 * preset connection lists of input pins
-	 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
-	 */
-	{0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
-	{0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-	{0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
-
-	/*
-	 * Set pin mode and muting
-	 */
-	/* set front pin widgets 0x14 for output */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Mic1 (rear panel) pin widget for input and vref at 80% */
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Mic2 (as headphone out) for HP output */
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Line In pin widget for input */
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Line2 (as front mic) pin widget for input and vref at 80% */
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* CD pin widget for input */
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-	{ }
-};
-
-/*
- * 5-stack pin configuration:
- * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
- * line-in/side = 0x1a, f-mic = 0x1b
- */
-static const struct hda_verb alc880_pin_5stack_init_verbs[] = {
-	/*
-	 * preset connection lists of input pins
-	 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
-	 */
-	{0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-	{0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
-
-	/*
-	 * Set pin mode and muting
-	 */
-	/* set pin widgets 0x14-0x17 for output */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	/* unmute pins for output (no gain on this amp) */
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-	/* Mic1 (rear panel) pin widget for input and vref at 80% */
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Mic2 (as headphone out) for HP output */
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Line In pin widget for input */
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Line2 (as front mic) pin widget for input and vref at 80% */
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* CD pin widget for input */
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-	{ }
-};
-
-/*
- * W810 pin configuration:
- * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
- */
-static const struct hda_verb alc880_pin_w810_init_verbs[] = {
-	/* hphone/speaker input selector: front DAC */
-	{0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
-
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-	{ }
-};
-
-/*
- * Z71V pin configuration:
- * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
- */
-static const struct hda_verb alc880_pin_z71v_init_verbs[] = {
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-	{ }
-};
-
-/*
- * 6-stack pin configuration:
- * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
- * f-mic = 0x19, line = 0x1a, HP = 0x1b
- */
-static const struct hda_verb alc880_pin_6stack_init_verbs[] = {
-	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-	{ }
-};
-
-/*
- * Uniwill pin configuration:
- * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
- * line = 0x1a
- */
-static const struct hda_verb alc880_uniwill_init_verbs[] = {
-	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
-	/* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
-
-	{ }
-};
-
-/*
-* Uniwill P53
-* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
- */
-static const struct hda_verb alc880_uniwill_p53_init_verbs[] = {
-	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-	{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_DCVOL_EVENT},
-
-	{ }
-};
-
-static const struct hda_verb alc880_beep_init_verbs[] = {
-	{ 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
-	{ }
-};
-
-static void alc880_uniwill_setup(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	spec->autocfg.hp_pins[0] = 0x14;
-	spec->autocfg.speaker_pins[0] = 0x15;
-	spec->autocfg.speaker_pins[0] = 0x16;
-	alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static void alc880_uniwill_init_hook(struct hda_codec *codec)
-{
-	alc_hp_automute(codec);
-	alc88x_simple_mic_automute(codec);
-}
-
-static void alc880_uniwill_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	/* Looks like the unsol event is incompatible with the standard
-	 * definition.  4bit tag is placed at 28 bit!
-	 */
-	res >>= 28;
-	switch (res) {
-	case ALC_MIC_EVENT:
-		alc88x_simple_mic_automute(codec);
-		break;
-	default:
-		alc_exec_unsol_event(codec, res);
-		break;
-	}
-}
-
-static void alc880_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	alc_exec_unsol_event(codec, res >> 28);
-}
-
-static void alc880_uniwill_p53_setup(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	spec->autocfg.hp_pins[0] = 0x14;
-	spec->autocfg.speaker_pins[0] = 0x15;
-	alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-
-	present = snd_hda_codec_read(codec, 0x21, 0,
-				     AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
-	present &= HDA_AMP_VOLMASK;
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
-				 HDA_AMP_VOLMASK, present);
-	snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
-				 HDA_AMP_VOLMASK, present);
-}
-
-static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	/* Looks like the unsol event is incompatible with the standard
-	 * definition.  4bit tag is placed at 28 bit!
-	 */
-	res >>= 28;
-	if (res == ALC_DCVOL_EVENT)
-		alc880_uniwill_p53_dcvol_automute(codec);
-	else
-		alc_exec_unsol_event(codec, res);
-}
-
-/*
- * F1734 pin configuration:
- * HP = 0x14, speaker-out = 0x15, mic = 0x18
- */
-static const struct hda_verb alc880_pin_f1734_init_verbs[] = {
-	{0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
-	{0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
-	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT},
-	{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_DCVOL_EVENT},
-
-	{ }
-};
-
-/*
- * ASUS pin configuration:
- * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
- */
-static const struct hda_verb alc880_pin_asus_init_verbs[] = {
-	{0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
-	{0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-	{ }
-};
-
-/* Enable GPIO mask and set output */
-#define alc880_gpio1_init_verbs	alc_gpio1_init_verbs
-#define alc880_gpio2_init_verbs	alc_gpio2_init_verbs
-#define alc880_gpio3_init_verbs	alc_gpio3_init_verbs
-
-/* Clevo m520g init */
-static const struct hda_verb alc880_pin_clevo_init_verbs[] = {
-	/* headphone output */
-	{0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
-	/* line-out */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Line-in */
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* CD */
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Mic1 (rear panel) */
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Mic2 (front panel) */
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* headphone */
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-        /* change to EAPD mode */
-	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-	{0x20, AC_VERB_SET_PROC_COEF,  0x3060},
-
-	{ }
-};
-
-static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
-	/* change to EAPD mode */
-	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-	{0x20, AC_VERB_SET_PROC_COEF,  0x3060},
-
-	/* Headphone output */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	/* Front output*/
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-	/* Line In pin widget for input */
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	/* CD pin widget for input */
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	/* Mic1 (rear panel) pin widget for input and vref at 80% */
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-
-	/* change to EAPD mode */
-	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-	{0x20, AC_VERB_SET_PROC_COEF,  0x3070},
-
-	{ }
-};
-
-/*
- * LG m1 express dual
- *
- * Pin assignment:
- *   Rear Line-In/Out (blue): 0x14
- *   Build-in Mic-In: 0x15
- *   Speaker-out: 0x17
- *   HP-Out (green): 0x1b
- *   Mic-In/Out (red): 0x19
- *   SPDIF-Out: 0x1e
- */
-
-/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
-static const hda_nid_t alc880_lg_dac_nids[3] = {
-	0x05, 0x02, 0x03
-};
-
-/* seems analog CD is not working */
-static const struct hda_input_mux alc880_lg_capture_source = {
-	.num_items = 3,
-	.items = {
-		{ "Mic", 0x1 },
-		{ "Line", 0x5 },
-		{ "Internal Mic", 0x6 },
-	},
-};
-
-/* 2,4,6 channel modes */
-static const struct hda_verb alc880_lg_ch2_init[] = {
-	/* set line-in and mic-in to input */
-	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-	{ }
-};
-
-static const struct hda_verb alc880_lg_ch4_init[] = {
-	/* set line-in to out and mic-in to input */
-	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
-	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-	{ }
-};
-
-static const struct hda_verb alc880_lg_ch6_init[] = {
-	/* set line-in and mic-in to output */
-	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
-	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
-	{ }
-};
-
-static const struct hda_channel_mode alc880_lg_ch_modes[3] = {
-	{ 2, alc880_lg_ch2_init },
-	{ 4, alc880_lg_ch4_init },
-	{ 6, alc880_lg_ch6_init },
-};
-
-static const struct snd_kcontrol_new alc880_lg_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
-	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
-	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Channel Mode",
-		.info = alc_ch_mode_info,
-		.get = alc_ch_mode_get,
-		.put = alc_ch_mode_put,
-	},
-	{ } /* end */
-};
-
-static const struct hda_verb alc880_lg_init_verbs[] = {
-	/* set capture source to mic-in */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* mute all amp mixer inputs */
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-	/* line-in to input */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* built-in mic */
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* speaker-out */
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* mic-in to input */
-	{0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* HP-out */
-	{0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* jack sense */
-	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-	{ }
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc880_lg_setup(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	spec->autocfg.hp_pins[0] = 0x1b;
-	spec->autocfg.speaker_pins[0] = 0x17;
-	alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list alc880_lg_loopbacks[] = {
-	{ 0x0b, HDA_INPUT, 1 },
-	{ 0x0b, HDA_INPUT, 6 },
-	{ 0x0b, HDA_INPUT, 7 },
-	{ } /* end */
-};
-#endif
-
-/*
- * Test configuration for debugging
- *
- * Almost all inputs/outputs are enabled.  I/O pins can be configured via
- * enum controls.
- */
-#ifdef CONFIG_SND_DEBUG
-static const hda_nid_t alc880_test_dac_nids[4] = {
-	0x02, 0x03, 0x04, 0x05
-};
-
-static const struct hda_input_mux alc880_test_capture_source = {
-	.num_items = 7,
-	.items = {
-		{ "In-1", 0x0 },
-		{ "In-2", 0x1 },
-		{ "In-3", 0x2 },
-		{ "In-4", 0x3 },
-		{ "CD", 0x4 },
-		{ "Front", 0x5 },
-		{ "Surround", 0x6 },
-	},
-};
-
-static const struct hda_channel_mode alc880_test_modes[4] = {
-	{ 2, NULL },
-	{ 4, NULL },
-	{ 6, NULL },
-	{ 8, NULL },
-};
-
-static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
-				 struct snd_ctl_elem_info *uinfo)
-{
-	static const char * const texts[] = {
-		"N/A", "Line Out", "HP Out",
-		"In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
-	};
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 8;
-	if (uinfo->value.enumerated.item >= 8)
-		uinfo->value.enumerated.item = 7;
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-	return 0;
-}
-
-static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
-	unsigned int pin_ctl, item = 0;
-
-	pin_ctl = snd_hda_codec_read(codec, nid, 0,
-				     AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-	if (pin_ctl & AC_PINCTL_OUT_EN) {
-		if (pin_ctl & AC_PINCTL_HP_EN)
-			item = 2;
-		else
-			item = 1;
-	} else if (pin_ctl & AC_PINCTL_IN_EN) {
-		switch (pin_ctl & AC_PINCTL_VREFEN) {
-		case AC_PINCTL_VREF_HIZ: item = 3; break;
-		case AC_PINCTL_VREF_50:  item = 4; break;
-		case AC_PINCTL_VREF_GRD: item = 5; break;
-		case AC_PINCTL_VREF_80:  item = 6; break;
-		case AC_PINCTL_VREF_100: item = 7; break;
-		}
-	}
-	ucontrol->value.enumerated.item[0] = item;
-	return 0;
-}
-
-static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
-	static const unsigned int ctls[] = {
-		0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
-		AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
-		AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
-		AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
-		AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
-		AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
-	};
-	unsigned int old_ctl, new_ctl;
-
-	old_ctl = snd_hda_codec_read(codec, nid, 0,
-				     AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-	new_ctl = ctls[ucontrol->value.enumerated.item[0]];
-	if (old_ctl != new_ctl) {
-		int val;
-		snd_hda_codec_write_cache(codec, nid, 0,
-					  AC_VERB_SET_PIN_WIDGET_CONTROL,
-					  new_ctl);
-		val = ucontrol->value.enumerated.item[0] >= 3 ?
-			HDA_AMP_MUTE : 0;
-		snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, val);
-		return 1;
-	}
-	return 0;
-}
-
-static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
-				 struct snd_ctl_elem_info *uinfo)
-{
-	static const char * const texts[] = {
-		"Front", "Surround", "CLFE", "Side"
-	};
-	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 alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
-	unsigned int sel;
-
-	sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
-	ucontrol->value.enumerated.item[0] = sel & 3;
-	return 0;
-}
-
-static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
-	unsigned int sel;
-
-	sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
-	if (ucontrol->value.enumerated.item[0] != sel) {
-		sel = ucontrol->value.enumerated.item[0] & 3;
-		snd_hda_codec_write_cache(codec, nid, 0,
-					  AC_VERB_SET_CONNECT_SEL, sel);
-		return 1;
-	}
-	return 0;
-}
-
-#define PIN_CTL_TEST(xname,nid) {			\
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	\
-			.name = xname,		       \
-			.subdevice = HDA_SUBDEV_NID_FLAG | nid, \
-			.info = alc_test_pin_ctl_info, \
-			.get = alc_test_pin_ctl_get,   \
-			.put = alc_test_pin_ctl_put,   \
-			.private_value = nid	       \
-			}
-
-#define PIN_SRC_TEST(xname,nid) {			\
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	\
-			.name = xname,		       \
-			.subdevice = HDA_SUBDEV_NID_FLAG | nid, \
-			.info = alc_test_pin_src_info, \
-			.get = alc_test_pin_src_get,   \
-			.put = alc_test_pin_src_put,   \
-			.private_value = nid	       \
-			}
-
-static const struct snd_kcontrol_new alc880_test_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-	HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
-	HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-	PIN_CTL_TEST("Front Pin Mode", 0x14),
-	PIN_CTL_TEST("Surround Pin Mode", 0x15),
-	PIN_CTL_TEST("CLFE Pin Mode", 0x16),
-	PIN_CTL_TEST("Side Pin Mode", 0x17),
-	PIN_CTL_TEST("In-1 Pin Mode", 0x18),
-	PIN_CTL_TEST("In-2 Pin Mode", 0x19),
-	PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
-	PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
-	PIN_SRC_TEST("In-1 Pin Source", 0x18),
-	PIN_SRC_TEST("In-2 Pin Source", 0x19),
-	PIN_SRC_TEST("In-3 Pin Source", 0x1a),
-	PIN_SRC_TEST("In-4 Pin Source", 0x1b),
-	HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
-	HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
-	HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
-	HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Channel Mode",
-		.info = alc_ch_mode_info,
-		.get = alc_ch_mode_get,
-		.put = alc_ch_mode_put,
-	},
-	{ } /* end */
-};
-
-static const struct hda_verb alc880_test_init_verbs[] = {
-	/* Unmute inputs of 0x0c - 0x0f */
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* Vol output for 0x0c-0x0f */
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	/* Set output pins 0x14-0x17 */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	/* Unmute output pins 0x14-0x17 */
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Set input pins 0x18-0x1c */
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	/* Mute input pins 0x18-0x1b */
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* ADC set up */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-	/* Analog input/passthru */
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	{ }
-};
-#endif
-
-/*
- */
-
-static const char * const alc880_models[ALC880_MODEL_LAST] = {
-	[ALC880_3ST]		= "3stack",
-	[ALC880_TCL_S700]	= "tcl",
-	[ALC880_3ST_DIG]	= "3stack-digout",
-	[ALC880_CLEVO]		= "clevo",
-	[ALC880_5ST]		= "5stack",
-	[ALC880_5ST_DIG]	= "5stack-digout",
-	[ALC880_W810]		= "w810",
-	[ALC880_Z71V]		= "z71v",
-	[ALC880_6ST]		= "6stack",
-	[ALC880_6ST_DIG]	= "6stack-digout",
-	[ALC880_ASUS]		= "asus",
-	[ALC880_ASUS_W1V]	= "asus-w1v",
-	[ALC880_ASUS_DIG]	= "asus-dig",
-	[ALC880_ASUS_DIG2]	= "asus-dig2",
-	[ALC880_UNIWILL_DIG]	= "uniwill",
-	[ALC880_UNIWILL_P53]	= "uniwill-p53",
-	[ALC880_FUJITSU]	= "fujitsu",
-	[ALC880_F1734]		= "F1734",
-	[ALC880_LG]		= "lg",
-#ifdef CONFIG_SND_DEBUG
-	[ALC880_TEST]		= "test",
-#endif
-	[ALC880_AUTO]		= "auto",
-};
-
-static const struct snd_pci_quirk alc880_cfg_tbl[] = {
-	SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
-	SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
-	SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
-	SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
-	SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
-	SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
-	SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
-	SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
-	SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
-	SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
-	SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
-	SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
-	SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
-	SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
-	SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
-	SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
-	/* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
-	SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
-	SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
-	SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
-	SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
-	SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
-	SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
-	SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
-	SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
-	SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
-	SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
-	SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
-	SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
-	SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
-	SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
-	SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
-	SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
-	SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
-	SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
-	SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
-	SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
-	SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734),
-	SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
-	SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
-	SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
-	SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
-	SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
-	SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
-	SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
-	SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
-	SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
-	SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
-	SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
-	SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
-	SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
-	/* default Intel */
-	SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
-	SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
-	{}
-};
-
-/*
- * ALC880 codec presets
- */
-static const struct alc_config_preset alc880_presets[] = {
-	[ALC880_3ST] = {
-		.mixers = { alc880_three_stack_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_3stack_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_dac_nids),
-		.dac_nids = alc880_dac_nids,
-		.num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
-		.channel_mode = alc880_threestack_modes,
-		.need_dac_fix = 1,
-		.input_mux = &alc880_capture_source,
-	},
-	[ALC880_3ST_DIG] = {
-		.mixers = { alc880_three_stack_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_3stack_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_dac_nids),
-		.dac_nids = alc880_dac_nids,
-		.dig_out_nid = ALC880_DIGOUT_NID,
-		.num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
-		.channel_mode = alc880_threestack_modes,
-		.need_dac_fix = 1,
-		.input_mux = &alc880_capture_source,
-	},
-	[ALC880_TCL_S700] = {
-		.mixers = { alc880_tcl_s700_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_tcl_S700_init_verbs,
-				alc880_gpio2_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_dac_nids),
-		.dac_nids = alc880_dac_nids,
-		.adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
-		.num_adc_nids = 1, /* single ADC */
-		.hp_nid = 0x03,
-		.num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
-		.channel_mode = alc880_2_jack_modes,
-		.input_mux = &alc880_capture_source,
-	},
-	[ALC880_5ST] = {
-		.mixers = { alc880_three_stack_mixer,
-			    alc880_five_stack_mixer},
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_5stack_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_dac_nids),
-		.dac_nids = alc880_dac_nids,
-		.num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
-		.channel_mode = alc880_fivestack_modes,
-		.input_mux = &alc880_capture_source,
-	},
-	[ALC880_5ST_DIG] = {
-		.mixers = { alc880_three_stack_mixer,
-			    alc880_five_stack_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_5stack_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_dac_nids),
-		.dac_nids = alc880_dac_nids,
-		.dig_out_nid = ALC880_DIGOUT_NID,
-		.num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
-		.channel_mode = alc880_fivestack_modes,
-		.input_mux = &alc880_capture_source,
-	},
-	[ALC880_6ST] = {
-		.mixers = { alc880_six_stack_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_6stack_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
-		.dac_nids = alc880_6st_dac_nids,
-		.num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
-		.channel_mode = alc880_sixstack_modes,
-		.input_mux = &alc880_6stack_capture_source,
-	},
-	[ALC880_6ST_DIG] = {
-		.mixers = { alc880_six_stack_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_6stack_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
-		.dac_nids = alc880_6st_dac_nids,
-		.dig_out_nid = ALC880_DIGOUT_NID,
-		.num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
-		.channel_mode = alc880_sixstack_modes,
-		.input_mux = &alc880_6stack_capture_source,
-	},
-	[ALC880_W810] = {
-		.mixers = { alc880_w810_base_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_w810_init_verbs,
-				alc880_gpio2_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
-		.dac_nids = alc880_w810_dac_nids,
-		.dig_out_nid = ALC880_DIGOUT_NID,
-		.num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
-		.channel_mode = alc880_w810_modes,
-		.input_mux = &alc880_capture_source,
-	},
-	[ALC880_Z71V] = {
-		.mixers = { alc880_z71v_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_z71v_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
-		.dac_nids = alc880_z71v_dac_nids,
-		.dig_out_nid = ALC880_DIGOUT_NID,
-		.hp_nid = 0x03,
-		.num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
-		.channel_mode = alc880_2_jack_modes,
-		.input_mux = &alc880_capture_source,
-	},
-	[ALC880_F1734] = {
-		.mixers = { alc880_f1734_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_f1734_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
-		.dac_nids = alc880_f1734_dac_nids,
-		.hp_nid = 0x02,
-		.num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
-		.channel_mode = alc880_2_jack_modes,
-		.input_mux = &alc880_f1734_capture_source,
-		.unsol_event = alc880_uniwill_p53_unsol_event,
-		.setup = alc880_uniwill_p53_setup,
-		.init_hook = alc_hp_automute,
-	},
-	[ALC880_ASUS] = {
-		.mixers = { alc880_asus_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_asus_init_verbs,
-				alc880_gpio1_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
-		.dac_nids = alc880_asus_dac_nids,
-		.num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
-		.channel_mode = alc880_asus_modes,
-		.need_dac_fix = 1,
-		.input_mux = &alc880_capture_source,
-	},
-	[ALC880_ASUS_DIG] = {
-		.mixers = { alc880_asus_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_asus_init_verbs,
-				alc880_gpio1_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
-		.dac_nids = alc880_asus_dac_nids,
-		.dig_out_nid = ALC880_DIGOUT_NID,
-		.num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
-		.channel_mode = alc880_asus_modes,
-		.need_dac_fix = 1,
-		.input_mux = &alc880_capture_source,
-	},
-	[ALC880_ASUS_DIG2] = {
-		.mixers = { alc880_asus_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_asus_init_verbs,
-				alc880_gpio2_init_verbs }, /* use GPIO2 */
-		.num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
-		.dac_nids = alc880_asus_dac_nids,
-		.dig_out_nid = ALC880_DIGOUT_NID,
-		.num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
-		.channel_mode = alc880_asus_modes,
-		.need_dac_fix = 1,
-		.input_mux = &alc880_capture_source,
-	},
-	[ALC880_ASUS_W1V] = {
-		.mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_asus_init_verbs,
-				alc880_gpio1_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
-		.dac_nids = alc880_asus_dac_nids,
-		.dig_out_nid = ALC880_DIGOUT_NID,
-		.num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
-		.channel_mode = alc880_asus_modes,
-		.need_dac_fix = 1,
-		.input_mux = &alc880_capture_source,
-	},
-	[ALC880_UNIWILL_DIG] = {
-		.mixers = { alc880_asus_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_asus_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
-		.dac_nids = alc880_asus_dac_nids,
-		.dig_out_nid = ALC880_DIGOUT_NID,
-		.num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
-		.channel_mode = alc880_asus_modes,
-		.need_dac_fix = 1,
-		.input_mux = &alc880_capture_source,
-	},
-	[ALC880_UNIWILL] = {
-		.mixers = { alc880_uniwill_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_uniwill_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
-		.dac_nids = alc880_asus_dac_nids,
-		.dig_out_nid = ALC880_DIGOUT_NID,
-		.num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
-		.channel_mode = alc880_threestack_modes,
-		.need_dac_fix = 1,
-		.input_mux = &alc880_capture_source,
-		.unsol_event = alc880_uniwill_unsol_event,
-		.setup = alc880_uniwill_setup,
-		.init_hook = alc880_uniwill_init_hook,
-	},
-	[ALC880_UNIWILL_P53] = {
-		.mixers = { alc880_uniwill_p53_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_uniwill_p53_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
-		.dac_nids = alc880_asus_dac_nids,
-		.num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
-		.channel_mode = alc880_threestack_modes,
-		.input_mux = &alc880_capture_source,
-		.unsol_event = alc880_uniwill_p53_unsol_event,
-		.setup = alc880_uniwill_p53_setup,
-		.init_hook = alc_hp_automute,
-	},
-	[ALC880_FUJITSU] = {
-		.mixers = { alc880_fujitsu_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_uniwill_p53_init_verbs,
-	       			alc880_beep_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_dac_nids),
-		.dac_nids = alc880_dac_nids,
-		.dig_out_nid = ALC880_DIGOUT_NID,
-		.num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
-		.channel_mode = alc880_2_jack_modes,
-		.input_mux = &alc880_capture_source,
-		.unsol_event = alc880_uniwill_p53_unsol_event,
-		.setup = alc880_uniwill_p53_setup,
-		.init_hook = alc_hp_automute,
-	},
-	[ALC880_CLEVO] = {
-		.mixers = { alc880_three_stack_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_pin_clevo_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_dac_nids),
-		.dac_nids = alc880_dac_nids,
-		.hp_nid = 0x03,
-		.num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
-		.channel_mode = alc880_threestack_modes,
-		.need_dac_fix = 1,
-		.input_mux = &alc880_capture_source,
-	},
-	[ALC880_LG] = {
-		.mixers = { alc880_lg_mixer },
-		.init_verbs = { alc880_volume_init_verbs,
-				alc880_lg_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
-		.dac_nids = alc880_lg_dac_nids,
-		.dig_out_nid = ALC880_DIGOUT_NID,
-		.num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
-		.channel_mode = alc880_lg_ch_modes,
-		.need_dac_fix = 1,
-		.input_mux = &alc880_lg_capture_source,
-		.unsol_event = alc880_unsol_event,
-		.setup = alc880_lg_setup,
-		.init_hook = alc_hp_automute,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-		.loopbacks = alc880_lg_loopbacks,
-#endif
-	},
-#ifdef CONFIG_SND_DEBUG
-	[ALC880_TEST] = {
-		.mixers = { alc880_test_mixer },
-		.init_verbs = { alc880_test_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
-		.dac_nids = alc880_test_dac_nids,
-		.dig_out_nid = ALC880_DIGOUT_NID,
-		.num_channel_mode = ARRAY_SIZE(alc880_test_modes),
-		.channel_mode = alc880_test_modes,
-		.input_mux = &alc880_test_capture_source,
-	},
-#endif
-};
-
diff --git a/sound/pci/hda/alc882_quirks.c b/sound/pci/hda/alc882_quirks.c
deleted file mode 100644
index bb364a5..0000000
--- a/sound/pci/hda/alc882_quirks.c
+++ /dev/null
@@ -1,866 +0,0 @@
-/*
- * ALC882/ALC883/ALC888/ALC889 quirk models
- * included by patch_realtek.c
- */
-
-/* ALC882 models */
-enum {
-	ALC882_AUTO,
-	ALC885_MBA21,
-	ALC885_MBP3,
-	ALC885_MB5,
-	ALC885_MACMINI3,
-	ALC885_IMAC91,
-	ALC889A_MB31,
-	ALC882_MODEL_LAST,
-};
-
-#define ALC882_DIGOUT_NID	0x06
-#define ALC882_DIGIN_NID	0x0a
-#define ALC883_DIGOUT_NID	ALC882_DIGOUT_NID
-#define ALC883_DIGIN_NID	ALC882_DIGIN_NID
-#define ALC1200_DIGOUT_NID	0x10
-
-
-static const struct hda_channel_mode alc882_ch_modes[1] = {
-	{ 8, NULL }
-};
-
-/* DACs */
-static const hda_nid_t alc882_dac_nids[4] = {
-	/* front, rear, clfe, rear_surr */
-	0x02, 0x03, 0x04, 0x05
-};
-#define alc883_dac_nids		alc882_dac_nids
-
-/* ADCs */
-#define alc882_adc_nids		alc880_adc_nids
-#define alc882_adc_nids_alt	alc880_adc_nids_alt
-#define alc883_adc_nids		alc882_adc_nids_alt
-
-static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
-#define alc883_capsrc_nids	alc882_capsrc_nids_alt
-
-/* input MUX */
-/* FIXME: should be a matrix-type input source selection */
-
-static const struct hda_input_mux alc882_capture_source = {
-	.num_items = 4,
-	.items = {
-		{ "Mic", 0x0 },
-		{ "Front Mic", 0x1 },
-		{ "Line", 0x2 },
-		{ "CD", 0x4 },
-	},
-};
-
-#define alc883_capture_source	alc882_capture_source
-
-static const struct hda_input_mux mb5_capture_source = {
-	.num_items = 3,
-	.items = {
-		{ "Mic", 0x1 },
-		{ "Line", 0x7 },
-		{ "CD", 0x4 },
-	},
-};
-
-static const struct hda_input_mux macmini3_capture_source = {
-	.num_items = 2,
-	.items = {
-		{ "Line", 0x2 },
-		{ "CD", 0x4 },
-	},
-};
-
-static const struct hda_input_mux alc883_3stack_6ch_intel = {
-	.num_items = 4,
-	.items = {
-		{ "Mic", 0x1 },
-		{ "Front Mic", 0x0 },
-		{ "Line", 0x2 },
-		{ "CD", 0x4 },
-	},
-};
-
-static const struct hda_input_mux alc889A_mb31_capture_source = {
-	.num_items = 2,
-	.items = {
-		{ "Mic", 0x0 },
-		/* Front Mic (0x01) unused */
-		{ "Line", 0x2 },
-		/* Line 2 (0x03) unused */
-		/* CD (0x04) unused? */
-	},
-};
-
-static const struct hda_input_mux alc889A_imac91_capture_source = {
-	.num_items = 2,
-	.items = {
-		{ "Mic", 0x01 },
-		{ "Line", 0x2 }, /* Not sure! */
-	},
-};
-
-/* Macbook Air 2,1 */
-
-static const struct hda_channel_mode alc885_mba21_ch_modes[1] = {
-      { 2, NULL },
-};
-
-/*
- * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
- */
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc885_mbp_ch2_init[] = {
-	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{ } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc885_mbp_ch4_init[] = {
-	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{ 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	{ } /* end */
-};
-
-static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
-	{ 2, alc885_mbp_ch2_init },
-	{ 4, alc885_mbp_ch4_init },
-};
-
-/*
- * 2ch
- * Speakers/Woofer/HP = Front
- * LineIn = Input
- */
-static const struct hda_verb alc885_mb5_ch2_init[] = {
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{ } /* end */
-};
-
-/*
- * 6ch mode
- * Speakers/HP = Front
- * Woofer = LFE
- * LineIn = Surround
- */
-static const struct hda_verb alc885_mb5_ch6_init[] = {
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{ } /* end */
-};
-
-static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
-	{ 2, alc885_mb5_ch2_init },
-	{ 6, alc885_mb5_ch6_init },
-};
-
-#define alc885_macmini3_6ch_modes	alc885_mb5_6ch_modes
-
-/* Macbook Air 2,1 same control for HP and internal Speaker */
-
-static const struct snd_kcontrol_new alc885_mba21_mixer[] = {
-      HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-      HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
-     { }
-};
-
-
-static const struct snd_kcontrol_new alc885_mbp3_mixer[] = {
-	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-	HDA_BIND_MUTE   ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
-	HDA_BIND_MUTE   ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
-	HDA_CODEC_MUTE  ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new alc885_mb5_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-	HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
-	HDA_BIND_MUTE   ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
-	HDA_BIND_MUTE   ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
-	HDA_BIND_MUTE   ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
-	HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-	HDA_CODEC_MUTE  ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new alc885_macmini3_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-	HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
-	HDA_BIND_MUTE   ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
-	HDA_BIND_MUTE   ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
-	HDA_BIND_MUTE   ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
-	HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new alc885_imac91_mixer[] = {
-	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-	HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
-	{ } /* end */
-};
-
-
-static const struct snd_kcontrol_new alc882_chmode_mixer[] = {
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Channel Mode",
-		.info = alc_ch_mode_info,
-		.get = alc_ch_mode_get,
-		.put = alc_ch_mode_put,
-	},
-	{ } /* end */
-};
-
-static const struct hda_verb alc882_base_init_verbs[] = {
-	/* Front mixer: unmute input/output amp left and right (volume = 0) */
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* Rear mixer */
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* CLFE mixer */
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* Side mixer */
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
-	/* Front Pin: output 0 (0x0c) */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-	/* Rear Pin: output 1 (0x0d) */
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-	/* CLFE Pin: output 2 (0x0e) */
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
-	/* Side Pin: output 3 (0x0f) */
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-	/* Mic (rear) pin: input vref at 80% */
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Front Mic pin: input vref at 80% */
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Line In pin: input */
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Line-2 In: Headphone output (output 0 - 0x0c) */
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-	/* CD pin widget for input */
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
-	/* FIXME: use matrix-type input source selection */
-	/* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-	/* Input mixer2 */
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	/* Input mixer3 */
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	/* ADC2: mute amp left and right */
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-	/* ADC3: mute amp left and right */
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-	{ }
-};
-
-#define alc883_init_verbs	alc882_base_init_verbs
-
-/* Macbook 5,1 */
-static const struct hda_verb alc885_mb5_init_verbs[] = {
-	/* DACs */
-	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Front mixer */
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* Surround mixer */
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* LFE mixer */
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* HP mixer */
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* Front Pin (0x0c) */
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
-	/* LFE Pin (0x0e) */
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
-	/* HP Pin (0x0f) */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
-	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-	/* Front Mic pin: input vref at 80% */
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Line In pin */
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
-	{ }
-};
-
-/* Macmini 3,1 */
-static const struct hda_verb alc885_macmini3_init_verbs[] = {
-	/* DACs */
-	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Front mixer */
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* Surround mixer */
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* LFE mixer */
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* HP mixer */
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* Front Pin (0x0c) */
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
-	/* LFE Pin (0x0e) */
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
-	/* HP Pin (0x0f) */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
-	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-	/* Line In pin */
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	{ }
-};
-
-
-static const struct hda_verb alc885_mba21_init_verbs[] = {
-	/*Internal and HP Speaker Mixer*/
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/*Internal Speaker Pin (0x0c)*/
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
-	/* HP Pin: output 0 (0x0e) */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC_HP_EVENT | AC_USRSP_EN)},
-	/* Line in (is hp when jack connected)*/
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
-	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-	{ }
- };
-
-
-/* Macbook Pro rev3 */
-static const struct hda_verb alc885_mbp3_init_verbs[] = {
-	/* Front mixer: unmute input/output amp left and right (volume = 0) */
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* Rear mixer */
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* HP mixer */
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* Front Pin: output 0 (0x0c) */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-	/* HP Pin: output 0 (0x0e) */
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
-	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-	/* Mic (rear) pin: input vref at 80% */
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Front Mic pin: input vref at 80% */
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Line In pin: use output 1 when in LineOut mode */
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
-
-	/* FIXME: use matrix-type input source selection */
-	/* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-	/* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	/* Input mixer2 */
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	/* Input mixer3 */
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	/* ADC1: mute amp left and right */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-	/* ADC2: mute amp left and right */
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-	/* ADC3: mute amp left and right */
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-	{ }
-};
-
-/* iMac 9,1 */
-static const struct hda_verb alc885_imac91_init_verbs[] = {
-	/* Internal Speaker Pin (0x0c) */
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
-	/* HP Pin: Rear */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC_HP_EVENT | AC_USRSP_EN)},
-	/* Line in Rear */
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Front Mic pin: input vref at 80% */
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Rear mixer */
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	/* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	/* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	/* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-	/* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-	/* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{ }
-};
-
-/* Toggle speaker-output according to the hp-jack state */
-static void alc885_imac24_setup(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	spec->autocfg.hp_pins[0] = 0x14;
-	spec->autocfg.speaker_pins[0] = 0x18;
-	spec->autocfg.speaker_pins[1] = 0x1a;
-	alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-#define alc885_mb5_setup	alc885_imac24_setup
-#define alc885_macmini3_setup	alc885_imac24_setup
-
-/* Macbook Air 2,1 */
-static void alc885_mba21_setup(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	spec->autocfg.hp_pins[0] = 0x14;
-	spec->autocfg.speaker_pins[0] = 0x18;
-	alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-
-
-static void alc885_mbp3_setup(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	spec->autocfg.hp_pins[0] = 0x15;
-	spec->autocfg.speaker_pins[0] = 0x14;
-	alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static void alc885_imac91_setup(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	spec->autocfg.hp_pins[0] = 0x14;
-	spec->autocfg.speaker_pins[0] = 0x18;
-	spec->autocfg.speaker_pins[1] = 0x1a;
-	alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
-static const struct hda_verb alc889A_mb31_ch2_init[] = {
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},             /* HP as front */
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},    /* Line as input */
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},   /* Line off */
-	{ } /* end */
-};
-
-/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
-static const struct hda_verb alc889A_mb31_ch4_init[] = {
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},             /* HP as front */
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},   /* Line as output */
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
-	{ } /* end */
-};
-
-/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
-static const struct hda_verb alc889A_mb31_ch5_init[] = {
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},             /* HP as rear */
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},    /* Line as input */
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},   /* Line off */
-	{ } /* end */
-};
-
-/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
-static const struct hda_verb alc889A_mb31_ch6_init[] = {
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},             /* HP as front */
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},   /* Subwoofer off */
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},   /* Line as output */
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
-	{ } /* end */
-};
-
-static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
-	{ 2, alc889A_mb31_ch2_init },
-	{ 4, alc889A_mb31_ch4_init },
-	{ 5, alc889A_mb31_ch5_init },
-	{ 6, alc889A_mb31_ch6_init },
-};
-
-static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new alc889A_mb31_mixer[] = {
-	/* Output mixers */
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
-		HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
-	/* Output switches */
-	HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
-	/* Boost mixers */
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
-	/* Input mixers */
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_chmode_mixer[] = {
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Channel Mode",
-		.info = alc_ch_mode_info,
-		.get = alc_ch_mode_get,
-		.put = alc_ch_mode_put,
-	},
-	{ } /* end */
-};
-
-static const struct hda_verb alc889A_mb31_verbs[] = {
-	/* Init rear pin (used as headphone output) */
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},    /* Apple Headphones */
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},           /* Connect to front */
-	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-	/* Init line pin (used as output in 4ch and 6ch mode) */
-	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},           /* Connect to CLFE */
-	/* Init line 2 pin (used as headphone out by default) */
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},  /* Use as input */
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
-	{ } /* end */
-};
-
-/* Mute speakers according to the headphone jack state */
-static void alc889A_mb31_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-
-	/* Mute only in 2ch or 4ch mode */
-	if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
-	    == 0x00) {
-		present = snd_hda_jack_detect(codec, 0x15);
-		snd_hda_codec_amp_stereo(codec, 0x14,  HDA_OUTPUT, 0,
-			HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-		snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-			HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-	}
-}
-
-static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	if ((res >> 26) == ALC_HP_EVENT)
-		alc889A_mb31_automute(codec);
-}
-
-static void alc882_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	alc_exec_unsol_event(codec, res >> 26);
-}
-
-/*
- * configuration and preset
- */
-static const char * const alc882_models[ALC882_MODEL_LAST] = {
-	[ALC885_MB5]		= "mb5",
-	[ALC885_MACMINI3]	= "macmini3",
-	[ALC885_MBA21]		= "mba21",
-	[ALC885_MBP3]		= "mbp3",
-	[ALC885_IMAC91]		= "imac91",
-	[ALC889A_MB31]		= "mb31",
-	[ALC882_AUTO]		= "auto",
-};
-
-/* codec SSID table for Intel Mac */
-static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
-	SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
-	SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
-	SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
-	SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
-	SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
-	SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
-	SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
-	SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
-	SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
-	SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
-	SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
-	SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
-	/* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
-	 * so apparently no perfect solution yet
-	 */
-	SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
-	SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
-	SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
-	{} /* terminator */
-};
-
-static const struct alc_config_preset alc882_presets[] = {
-	   [ALC885_MBA21] = {
-			.mixers = { alc885_mba21_mixer },
-			.init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
-			.num_dacs = 2,
-			.dac_nids = alc882_dac_nids,
-			.channel_mode = alc885_mba21_ch_modes,
-			.num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
-			.input_mux = &alc882_capture_source,
-			.unsol_event = alc882_unsol_event,
-			.setup = alc885_mba21_setup,
-			.init_hook = alc_hp_automute,
-       },
-	[ALC885_MBP3] = {
-		.mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
-		.init_verbs = { alc885_mbp3_init_verbs,
-				alc880_gpio1_init_verbs },
-		.num_dacs = 2,
-		.dac_nids = alc882_dac_nids,
-		.hp_nid = 0x04,
-		.channel_mode = alc885_mbp_4ch_modes,
-		.num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
-		.input_mux = &alc882_capture_source,
-		.dig_out_nid = ALC882_DIGOUT_NID,
-		.dig_in_nid = ALC882_DIGIN_NID,
-		.unsol_event = alc882_unsol_event,
-		.setup = alc885_mbp3_setup,
-		.init_hook = alc_hp_automute,
-	},
-	[ALC885_MB5] = {
-		.mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
-		.init_verbs = { alc885_mb5_init_verbs,
-				alc880_gpio1_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc882_dac_nids),
-		.dac_nids = alc882_dac_nids,
-		.channel_mode = alc885_mb5_6ch_modes,
-		.num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
-		.input_mux = &mb5_capture_source,
-		.dig_out_nid = ALC882_DIGOUT_NID,
-		.dig_in_nid = ALC882_DIGIN_NID,
-		.unsol_event = alc882_unsol_event,
-		.setup = alc885_mb5_setup,
-		.init_hook = alc_hp_automute,
-	},
-	[ALC885_MACMINI3] = {
-		.mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
-		.init_verbs = { alc885_macmini3_init_verbs,
-				alc880_gpio1_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc882_dac_nids),
-		.dac_nids = alc882_dac_nids,
-		.channel_mode = alc885_macmini3_6ch_modes,
-		.num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
-		.input_mux = &macmini3_capture_source,
-		.dig_out_nid = ALC882_DIGOUT_NID,
-		.dig_in_nid = ALC882_DIGIN_NID,
-		.unsol_event = alc882_unsol_event,
-		.setup = alc885_macmini3_setup,
-		.init_hook = alc_hp_automute,
-	},
-	[ALC885_IMAC91] = {
-		.mixers = {alc885_imac91_mixer},
-		.init_verbs = { alc885_imac91_init_verbs,
-				alc880_gpio1_init_verbs },
-		.num_dacs = ARRAY_SIZE(alc882_dac_nids),
-		.dac_nids = alc882_dac_nids,
-		.channel_mode = alc885_mba21_ch_modes,
-		.num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
-		.input_mux = &alc889A_imac91_capture_source,
-		.dig_out_nid = ALC882_DIGOUT_NID,
-		.dig_in_nid = ALC882_DIGIN_NID,
-		.unsol_event = alc882_unsol_event,
-		.setup = alc885_imac91_setup,
-		.init_hook = alc_hp_automute,
-	},
-	[ALC889A_MB31] = {
-		.mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
-		.init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
-			alc880_gpio1_init_verbs },
-		.adc_nids = alc883_adc_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.capsrc_nids = alc883_capsrc_nids,
-		.dac_nids = alc883_dac_nids,
-		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
-		.channel_mode = alc889A_mb31_6ch_modes,
-		.num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
-		.input_mux = &alc889A_mb31_capture_source,
-		.dig_out_nid = ALC883_DIGOUT_NID,
-		.unsol_event = alc889A_mb31_unsol_event,
-		.init_hook = alc889A_mb31_automute,
-	},
-};
-
-
diff --git a/sound/pci/hda/alc_quirks.c b/sound/pci/hda/alc_quirks.c
deleted file mode 100644
index a18952e..0000000
--- a/sound/pci/hda/alc_quirks.c
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * Common codes for Realtek codec quirks
- * included by patch_realtek.c
- */
-
-/*
- * configuration template - to be copied to the spec instance
- */
-struct alc_config_preset {
-	const struct snd_kcontrol_new *mixers[5]; /* should be identical size
-					     * with spec
-					     */
-	const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
-	const struct hda_verb *init_verbs[5];
-	unsigned int num_dacs;
-	const hda_nid_t *dac_nids;
-	hda_nid_t dig_out_nid;		/* optional */
-	hda_nid_t hp_nid;		/* optional */
-	const hda_nid_t *slave_dig_outs;
-	unsigned int num_adc_nids;
-	const hda_nid_t *adc_nids;
-	const hda_nid_t *capsrc_nids;
-	hda_nid_t dig_in_nid;
-	unsigned int num_channel_mode;
-	const struct hda_channel_mode *channel_mode;
-	int need_dac_fix;
-	int const_channel_count;
-	unsigned int num_mux_defs;
-	const struct hda_input_mux *input_mux;
-	void (*unsol_event)(struct hda_codec *, unsigned int);
-	void (*setup)(struct hda_codec *);
-	void (*init_hook)(struct hda_codec *);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-	const struct hda_amp_list *loopbacks;
-	void (*power_hook)(struct hda_codec *codec);
-#endif
-};
-
-/*
- * channel mode setting
- */
-static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
-			    struct snd_ctl_elem_info *uinfo)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
-				    spec->num_channel_mode);
-}
-
-static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
-			   struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
-				   spec->num_channel_mode,
-				   spec->ext_channel_count);
-}
-
-static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
-			   struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
-				      spec->num_channel_mode,
-				      &spec->ext_channel_count);
-	if (err >= 0 && !spec->const_channel_count) {
-		spec->multiout.max_channels = spec->ext_channel_count;
-		if (spec->need_dac_fix)
-			spec->multiout.num_dacs = spec->multiout.max_channels / 2;
-	}
-	return err;
-}
-
-/*
- * Control the mode of pin widget settings via the mixer.  "pc" is used
- * instead of "%" to avoid consequences of accidentally treating the % as
- * being part of a format specifier.  Maximum allowed length of a value is
- * 63 characters plus NULL terminator.
- *
- * Note: some retasking pin complexes seem to ignore requests for input
- * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
- * are requested.  Therefore order this list so that this behaviour will not
- * cause problems when mixer clients move through the enum sequentially.
- * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
- * March 2006.
- */
-static const char * const alc_pin_mode_names[] = {
-	"Mic 50pc bias", "Mic 80pc bias",
-	"Line in", "Line out", "Headphone out",
-};
-static const unsigned char alc_pin_mode_values[] = {
-	PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
-};
-/* The control can present all 5 options, or it can limit the options based
- * in the pin being assumed to be exclusively an input or an output pin.  In
- * addition, "input" pins may or may not process the mic bias option
- * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
- * accept requests for bias as of chip versions up to March 2006) and/or
- * wiring in the computer.
- */
-#define ALC_PIN_DIR_IN              0x00
-#define ALC_PIN_DIR_OUT             0x01
-#define ALC_PIN_DIR_INOUT           0x02
-#define ALC_PIN_DIR_IN_NOMICBIAS    0x03
-#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
-
-/* Info about the pin modes supported by the different pin direction modes.
- * For each direction the minimum and maximum values are given.
- */
-static const signed char alc_pin_mode_dir_info[5][2] = {
-	{ 0, 2 },    /* ALC_PIN_DIR_IN */
-	{ 3, 4 },    /* ALC_PIN_DIR_OUT */
-	{ 0, 4 },    /* ALC_PIN_DIR_INOUT */
-	{ 2, 2 },    /* ALC_PIN_DIR_IN_NOMICBIAS */
-	{ 2, 4 },    /* ALC_PIN_DIR_INOUT_NOMICBIAS */
-};
-#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
-#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
-#define alc_pin_mode_n_items(_dir) \
-	(alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
-
-static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
-			     struct snd_ctl_elem_info *uinfo)
-{
-	unsigned int item_num = uinfo->value.enumerated.item;
-	unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
-
-	if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
-		item_num = alc_pin_mode_min(dir);
-	strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
-	return 0;
-}
-
-static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
-			    struct snd_ctl_elem_value *ucontrol)
-{
-	unsigned int i;
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	hda_nid_t nid = kcontrol->private_value & 0xffff;
-	unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
-	long *valp = ucontrol->value.integer.value;
-	unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
-						 AC_VERB_GET_PIN_WIDGET_CONTROL,
-						 0x00);
-
-	/* Find enumerated value for current pinctl setting */
-	i = alc_pin_mode_min(dir);
-	while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
-		i++;
-	*valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
-	return 0;
-}
-
-static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
-			    struct snd_ctl_elem_value *ucontrol)
-{
-	signed int change;
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	hda_nid_t nid = kcontrol->private_value & 0xffff;
-	unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
-	long val = *ucontrol->value.integer.value;
-	unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
-						 AC_VERB_GET_PIN_WIDGET_CONTROL,
-						 0x00);
-
-	if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
-		val = alc_pin_mode_min(dir);
-
-	change = pinctl != alc_pin_mode_values[val];
-	if (change) {
-		/* Set pin mode to that requested */
-		snd_hda_codec_write_cache(codec, nid, 0,
-					  AC_VERB_SET_PIN_WIDGET_CONTROL,
-					  alc_pin_mode_values[val]);
-
-		/* Also enable the retasking pin's input/output as required
-		 * for the requested pin mode.  Enum values of 2 or less are
-		 * input modes.
-		 *
-		 * Dynamically switching the input/output buffers probably
-		 * reduces noise slightly (particularly on input) so we'll
-		 * do it.  However, having both input and output buffers
-		 * enabled simultaneously doesn't seem to be problematic if
-		 * this turns out to be necessary in the future.
-		 */
-		if (val <= 2) {
-			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
-						 HDA_AMP_MUTE, HDA_AMP_MUTE);
-			snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
-						 HDA_AMP_MUTE, 0);
-		} else {
-			snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
-						 HDA_AMP_MUTE, HDA_AMP_MUTE);
-			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
-						 HDA_AMP_MUTE, 0);
-		}
-	}
-	return change;
-}
-
-#define ALC_PIN_MODE(xname, nid, dir) \
-	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
-	  .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
-	  .info = alc_pin_mode_info, \
-	  .get = alc_pin_mode_get, \
-	  .put = alc_pin_mode_put, \
-	  .private_value = nid | (dir<<16) }
-
-/* A switch control for ALC260 GPIO pins.  Multiple GPIOs can be ganged
- * together using a mask with more than one bit set.  This control is
- * currently used only by the ALC260 test model.  At this stage they are not
- * needed for any "production" models.
- */
-#ifdef CONFIG_SND_DEBUG
-#define alc_gpio_data_info	snd_ctl_boolean_mono_info
-
-static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
-			     struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	hda_nid_t nid = kcontrol->private_value & 0xffff;
-	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
-	long *valp = ucontrol->value.integer.value;
-	unsigned int val = snd_hda_codec_read(codec, nid, 0,
-					      AC_VERB_GET_GPIO_DATA, 0x00);
-
-	*valp = (val & mask) != 0;
-	return 0;
-}
-static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
-			     struct snd_ctl_elem_value *ucontrol)
-{
-	signed int change;
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	hda_nid_t nid = kcontrol->private_value & 0xffff;
-	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
-	long val = *ucontrol->value.integer.value;
-	unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
-						    AC_VERB_GET_GPIO_DATA,
-						    0x00);
-
-	/* Set/unset the masked GPIO bit(s) as needed */
-	change = (val == 0 ? 0 : mask) != (gpio_data & mask);
-	if (val == 0)
-		gpio_data &= ~mask;
-	else
-		gpio_data |= mask;
-	snd_hda_codec_write_cache(codec, nid, 0,
-				  AC_VERB_SET_GPIO_DATA, gpio_data);
-
-	return change;
-}
-#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
-	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
-	  .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
-	  .info = alc_gpio_data_info, \
-	  .get = alc_gpio_data_get, \
-	  .put = alc_gpio_data_put, \
-	  .private_value = nid | (mask<<16) }
-#endif   /* CONFIG_SND_DEBUG */
-
-/* A switch control to allow the enabling of the digital IO pins on the
- * ALC260.  This is incredibly simplistic; the intention of this control is
- * to provide something in the test model allowing digital outputs to be
- * identified if present.  If models are found which can utilise these
- * outputs a more complete mixer control can be devised for those models if
- * necessary.
- */
-#ifdef CONFIG_SND_DEBUG
-#define alc_spdif_ctrl_info	snd_ctl_boolean_mono_info
-
-static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	hda_nid_t nid = kcontrol->private_value & 0xffff;
-	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
-	long *valp = ucontrol->value.integer.value;
-	unsigned int val = snd_hda_codec_read(codec, nid, 0,
-					      AC_VERB_GET_DIGI_CONVERT_1, 0x00);
-
-	*valp = (val & mask) != 0;
-	return 0;
-}
-static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol)
-{
-	signed int change;
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	hda_nid_t nid = kcontrol->private_value & 0xffff;
-	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
-	long val = *ucontrol->value.integer.value;
-	unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
-						    AC_VERB_GET_DIGI_CONVERT_1,
-						    0x00);
-
-	/* Set/unset the masked control bit(s) as needed */
-	change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
-	if (val==0)
-		ctrl_data &= ~mask;
-	else
-		ctrl_data |= mask;
-	snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
-				  ctrl_data);
-
-	return change;
-}
-#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
-	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
-	  .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
-	  .info = alc_spdif_ctrl_info, \
-	  .get = alc_spdif_ctrl_get, \
-	  .put = alc_spdif_ctrl_put, \
-	  .private_value = nid | (mask<<16) }
-#endif   /* CONFIG_SND_DEBUG */
-
-/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
- * Again, this is only used in the ALC26x test models to help identify when
- * the EAPD line must be asserted for features to work.
- */
-#ifdef CONFIG_SND_DEBUG
-#define alc_eapd_ctrl_info	snd_ctl_boolean_mono_info
-
-static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	hda_nid_t nid = kcontrol->private_value & 0xffff;
-	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
-	long *valp = ucontrol->value.integer.value;
-	unsigned int val = snd_hda_codec_read(codec, nid, 0,
-					      AC_VERB_GET_EAPD_BTLENABLE, 0x00);
-
-	*valp = (val & mask) != 0;
-	return 0;
-}
-
-static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol)
-{
-	int change;
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	hda_nid_t nid = kcontrol->private_value & 0xffff;
-	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
-	long val = *ucontrol->value.integer.value;
-	unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
-						    AC_VERB_GET_EAPD_BTLENABLE,
-						    0x00);
-
-	/* Set/unset the masked control bit(s) as needed */
-	change = (!val ? 0 : mask) != (ctrl_data & mask);
-	if (!val)
-		ctrl_data &= ~mask;
-	else
-		ctrl_data |= mask;
-	snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
-				  ctrl_data);
-
-	return change;
-}
-
-#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
-	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
-	  .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
-	  .info = alc_eapd_ctrl_info, \
-	  .get = alc_eapd_ctrl_get, \
-	  .put = alc_eapd_ctrl_put, \
-	  .private_value = nid | (mask<<16) }
-#endif   /* CONFIG_SND_DEBUG */
-
-static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->autocfg;
-
-	if (!cfg->line_outs) {
-		while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
-		       cfg->line_out_pins[cfg->line_outs])
-			cfg->line_outs++;
-	}
-	if (!cfg->speaker_outs) {
-		while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
-		       cfg->speaker_pins[cfg->speaker_outs])
-			cfg->speaker_outs++;
-	}
-	if (!cfg->hp_outs) {
-		while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
-		       cfg->hp_pins[cfg->hp_outs])
-			cfg->hp_outs++;
-	}
-}
-
-/*
- * set up from the preset table
- */
-static void setup_preset(struct hda_codec *codec,
-			 const struct alc_config_preset *preset)
-{
-	struct alc_spec *spec = codec->spec;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
-		add_mixer(spec, preset->mixers[i]);
-	spec->cap_mixer = preset->cap_mixer;
-	for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
-	     i++)
-		add_verb(spec, preset->init_verbs[i]);
-
-	spec->channel_mode = preset->channel_mode;
-	spec->num_channel_mode = preset->num_channel_mode;
-	spec->need_dac_fix = preset->need_dac_fix;
-	spec->const_channel_count = preset->const_channel_count;
-
-	if (preset->const_channel_count)
-		spec->multiout.max_channels = preset->const_channel_count;
-	else
-		spec->multiout.max_channels = spec->channel_mode[0].channels;
-	spec->ext_channel_count = spec->channel_mode[0].channels;
-
-	spec->multiout.num_dacs = preset->num_dacs;
-	spec->multiout.dac_nids = preset->dac_nids;
-	spec->multiout.dig_out_nid = preset->dig_out_nid;
-	spec->multiout.slave_dig_outs = preset->slave_dig_outs;
-	spec->multiout.hp_nid = preset->hp_nid;
-
-	spec->num_mux_defs = preset->num_mux_defs;
-	if (!spec->num_mux_defs)
-		spec->num_mux_defs = 1;
-	spec->input_mux = preset->input_mux;
-
-	spec->num_adc_nids = preset->num_adc_nids;
-	spec->adc_nids = preset->adc_nids;
-	spec->capsrc_nids = preset->capsrc_nids;
-	spec->dig_in_nid = preset->dig_in_nid;
-
-	spec->unsol_event = preset->unsol_event;
-	spec->init_hook = preset->init_hook;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-	spec->power_hook = preset->power_hook;
-	spec->loopback.amplist = preset->loopbacks;
-#endif
-
-	if (preset->setup)
-		preset->setup(codec);
-
-	alc_fixup_autocfg_pin_nums(codec);
-}
-
-static void alc_simple_setup_automute(struct alc_spec *spec, int mode)
-{
-	int lo_pin = spec->autocfg.line_out_pins[0];
-
-	if (lo_pin == spec->autocfg.speaker_pins[0] ||
-		lo_pin == spec->autocfg.hp_pins[0])
-		lo_pin = 0;
-	spec->automute_mode = mode;
-	spec->detect_hp = !!spec->autocfg.hp_pins[0];
-	spec->detect_lo = !!lo_pin;
-	spec->automute_lo = spec->automute_lo_possible = !!lo_pin;
-	spec->automute_speaker = spec->automute_speaker_possible = !!spec->autocfg.speaker_pins[0];
-}
-
-/* auto-toggle front mic */
-static void alc88x_simple_mic_automute(struct hda_codec *codec)
-{
- 	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x18);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
-}
-
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 6843073..7a8fcc4 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -19,6 +19,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -2304,7 +2305,7 @@
 
 /* apply the function to all matching slave ctls in the mixer list */
 static int map_slaves(struct hda_codec *codec, const char * const *slaves,
-		      map_slave_func_t func, void *data) 
+		      const char *suffix, map_slave_func_t func, void *data) 
 {
 	struct hda_nid_item *items;
 	const char * const *s;
@@ -2317,7 +2318,14 @@
 		    sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER)
 			continue;
 		for (s = slaves; *s; s++) {
-			if (!strcmp(sctl->id.name, *s)) {
+			char tmpname[sizeof(sctl->id.name)];
+			const char *name = *s;
+			if (suffix) {
+				snprintf(tmpname, sizeof(tmpname), "%s %s",
+					 name, suffix);
+				name = tmpname;
+			}
+			if (!strcmp(sctl->id.name, name)) {
 				err = func(data, sctl);
 				if (err)
 					return err;
@@ -2333,12 +2341,65 @@
 	return 1;
 }
 
+/* guess the value corresponding to 0dB */
+static int get_kctl_0dB_offset(struct snd_kcontrol *kctl)
+{
+	int _tlv[4];
+	const int *tlv = NULL;
+	int val = -1;
+
+	if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+		/* FIXME: set_fs() hack for obtaining user-space TLV data */
+		mm_segment_t fs = get_fs();
+		set_fs(get_ds());
+		if (!kctl->tlv.c(kctl, 0, sizeof(_tlv), _tlv))
+			tlv = _tlv;
+		set_fs(fs);
+	} else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ)
+		tlv = kctl->tlv.p;
+	if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE)
+		val = -tlv[2] / tlv[3];
+	return val;
+}
+
+/* call kctl->put with the given value(s) */
+static int put_kctl_with_value(struct snd_kcontrol *kctl, int val)
+{
+	struct snd_ctl_elem_value *ucontrol;
+	ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL);
+	if (!ucontrol)
+		return -ENOMEM;
+	ucontrol->value.integer.value[0] = val;
+	ucontrol->value.integer.value[1] = val;
+	kctl->put(kctl, ucontrol);
+	kfree(ucontrol);
+	return 0;
+}
+
+/* initialize the slave volume with 0dB */
+static int init_slave_0dB(void *data, struct snd_kcontrol *slave)
+{
+	int offset = get_kctl_0dB_offset(slave);
+	if (offset > 0)
+		put_kctl_with_value(slave, offset);
+	return 0;
+}
+
+/* unmute the slave */
+static int init_slave_unmute(void *data, struct snd_kcontrol *slave)
+{
+	return put_kctl_with_value(slave, 1);
+}
+
 /**
  * snd_hda_add_vmaster - create a virtual master control and add slaves
  * @codec: HD-audio codec
  * @name: vmaster control name
  * @tlv: TLV data (optional)
  * @slaves: slave control names (optional)
+ * @suffix: suffix string to each slave name (optional)
+ * @init_slave_vol: initialize slaves to unmute/0dB
+ * @ctl_ret: store the vmaster kcontrol in return
  *
  * Create a virtual master control with the given name.  The TLV data
  * must be either NULL or a valid data.
@@ -2349,13 +2410,18 @@
  *
  * This function returns zero if successful or a negative error code.
  */
-int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
-			unsigned int *tlv, const char * const *slaves)
+int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
+			unsigned int *tlv, const char * const *slaves,
+			  const char *suffix, bool init_slave_vol,
+			  struct snd_kcontrol **ctl_ret)
 {
 	struct snd_kcontrol *kctl;
 	int err;
 
-	err = map_slaves(codec, slaves, check_slave_present, NULL);
+	if (ctl_ret)
+		*ctl_ret = NULL;
+
+	err = map_slaves(codec, slaves, suffix, check_slave_present, NULL);
 	if (err != 1) {
 		snd_printdd("No slave found for %s\n", name);
 		return 0;
@@ -2367,13 +2433,119 @@
 	if (err < 0)
 		return err;
 
-	err = map_slaves(codec, slaves, (map_slave_func_t)snd_ctl_add_slave,
-			 kctl);
+	err = map_slaves(codec, slaves, suffix,
+			 (map_slave_func_t)snd_ctl_add_slave, kctl);
 	if (err < 0)
 		return err;
+
+	/* init with master mute & zero volume */
+	put_kctl_with_value(kctl, 0);
+	if (init_slave_vol)
+		map_slaves(codec, slaves, suffix,
+			   tlv ? init_slave_0dB : init_slave_unmute, kctl);
+
+	if (ctl_ret)
+		*ctl_ret = kctl;
 	return 0;
 }
-EXPORT_SYMBOL_HDA(snd_hda_add_vmaster);
+EXPORT_SYMBOL_HDA(__snd_hda_add_vmaster);
+
+/*
+ * mute-LED control using vmaster
+ */
+static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	static const char * const texts[] = {
+		"Off", "On", "Follow Master"
+	};
+	unsigned int index;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 3;
+	index = uinfo->value.enumerated.item;
+	if (index >= 3)
+		index = 2;
+	strcpy(uinfo->value.enumerated.name, texts[index]);
+	return 0;
+}
+
+static int vmaster_mute_mode_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.enumerated.item[0] = hook->mute_mode;
+	return 0;
+}
+
+static int vmaster_mute_mode_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol);
+	unsigned int old_mode = hook->mute_mode;
+
+	hook->mute_mode = ucontrol->value.enumerated.item[0];
+	if (hook->mute_mode > HDA_VMUTE_FOLLOW_MASTER)
+		hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER;
+	if (old_mode == hook->mute_mode)
+		return 0;
+	snd_hda_sync_vmaster_hook(hook);
+	return 1;
+}
+
+static struct snd_kcontrol_new vmaster_mute_mode = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Mute-LED Mode",
+	.info = vmaster_mute_mode_info,
+	.get = vmaster_mute_mode_get,
+	.put = vmaster_mute_mode_put,
+};
+
+/*
+ * Add a mute-LED hook with the given vmaster switch kctl
+ * "Mute-LED Mode" control is automatically created and associated with
+ * the given hook.
+ */
+int snd_hda_add_vmaster_hook(struct hda_codec *codec,
+			     struct hda_vmaster_mute_hook *hook,
+			     bool expose_enum_ctl)
+{
+	struct snd_kcontrol *kctl;
+
+	if (!hook->hook || !hook->sw_kctl)
+		return 0;
+	snd_ctl_add_vmaster_hook(hook->sw_kctl, hook->hook, codec);
+	hook->codec = codec;
+	hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER;
+	if (!expose_enum_ctl)
+		return 0;
+	kctl = snd_ctl_new1(&vmaster_mute_mode, hook);
+	if (!kctl)
+		return -ENOMEM;
+	return snd_hda_ctl_add(codec, 0, kctl);
+}
+EXPORT_SYMBOL_HDA(snd_hda_add_vmaster_hook);
+
+/*
+ * Call the hook with the current value for synchronization
+ * Should be called in init callback
+ */
+void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook)
+{
+	if (!hook->hook || !hook->codec)
+		return;
+	switch (hook->mute_mode) {
+	case HDA_VMUTE_FOLLOW_MASTER:
+		snd_ctl_sync_vmaster_hook(hook->sw_kctl);
+		break;
+	default:
+		hook->hook(hook->codec, hook->mute_mode);
+		break;
+	}
+}
+EXPORT_SYMBOL_HDA(snd_hda_sync_vmaster_hook);
+
 
 /**
  * snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch
@@ -5272,6 +5444,10 @@
 	list_for_each_entry(codec, &bus->codec_list, list) {
 		if (hda_codec_is_power_on(codec))
 			hda_call_codec_suspend(codec);
+		else /* forcibly change the power to D3 even if not used */
+			hda_set_power_state(codec,
+					    codec->afg ? codec->afg : codec->mfg,
+					    AC_PWRST_D3);
 		if (codec->patch_ops.post_suspend)
 			codec->patch_ops.post_suspend(codec);
 	}
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index f0f1943..9a9f372 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -855,6 +855,7 @@
 	unsigned int pins_shutup:1;	/* pins are shut up */
 	unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
 	unsigned int ignore_misc_bit:1; /* ignore MISC_NO_PRESENCE bit */
+	unsigned int no_jack_detect:1;	/* Machine has no jack-detection */
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	unsigned int power_on :1;	/* current (global) power-state */
 	unsigned int power_transition :1; /* power-state in transition */
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index c1da422..b58b4b1 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -385,8 +385,8 @@
 static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen)
 {
 	static unsigned int alsa_rates[] = {
-		5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
-		96000, 176400, 192000, 384000
+		5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
+		88200, 96000, 176400, 192000, 384000
 	};
 	int i, j;
 
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 95dfb68..c19e71a 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -84,7 +84,7 @@
 MODULE_PARM_DESC(model, "Use the given board model.");
 module_param_array(position_fix, int, NULL, 0444);
 MODULE_PARM_DESC(position_fix, "DMA pointer read method."
-		 "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO).");
+		 "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO).");
 module_param_array(bdl_pos_adj, int, NULL, 0644);
 MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
 module_param_array(probe_mask, int, NULL, 0444);
@@ -94,7 +94,7 @@
 module_param(single_cmd, bool, 0444);
 MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
 		 "(for debugging only).");
-module_param(enable_msi, int, 0444);
+module_param(enable_msi, bint, 0444);
 MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
 module_param_array(patch, charp, NULL, 0444);
@@ -121,8 +121,8 @@
 MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
 #endif
 
-static bool align_buffer_size = 1;
-module_param(align_buffer_size, bool, 0644);
+static int align_buffer_size = -1;
+module_param(align_buffer_size, bint, 0644);
 MODULE_PARM_DESC(align_buffer_size,
 		"Force buffer and period sizes to be multiple of 128 bytes.");
 
@@ -148,6 +148,7 @@
 			 "{Intel, PCH},"
 			 "{Intel, CPT},"
 			 "{Intel, PPT},"
+			 "{Intel, LPT},"
 			 "{Intel, PBG},"
 			 "{Intel, SCH},"
 			 "{ATI, SB450},"
@@ -329,6 +330,7 @@
 	POS_FIX_LPIB,
 	POS_FIX_POSBUF,
 	POS_FIX_VIACOMBO,
+	POS_FIX_COMBO,
 };
 
 /* Defines for ATI HD Audio support in SB450 south bridge */
@@ -515,6 +517,7 @@
 #define AZX_DCAPS_SYNC_WRITE	(1 << 19)	/* sync each cmd write */
 #define AZX_DCAPS_OLD_SSYNC	(1 << 20)	/* Old SSYNC reg for ICH */
 #define AZX_DCAPS_BUFSIZE	(1 << 21)	/* no buffer size alignment */
+#define AZX_DCAPS_ALIGN_BUFSIZE	(1 << 22)	/* buffer size alignment */
 
 /* quirks for ATI SB / AMD Hudson */
 #define AZX_DCAPS_PRESET_ATI_SB \
@@ -527,7 +530,8 @@
 
 /* quirks for Nvidia */
 #define AZX_DCAPS_PRESET_NVIDIA \
-	(AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI)
+	(AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\
+	 AZX_DCAPS_ALIGN_BUFSIZE)
 
 static char *driver_short_names[] __devinitdata = {
 	[AZX_DRIVER_ICH] = "HDA Intel",
@@ -2347,17 +2351,6 @@
  * power management
  */
 
-static int snd_hda_codecs_inuse(struct hda_bus *bus)
-{
-	struct hda_codec *codec;
-
-	list_for_each_entry(codec, &bus->codec_list, list) {
-		if (snd_hda_codec_needs_resume(codec))
-			return 1;
-	}
-	return 0;
-}
-
 static int azx_suspend(struct pci_dev *pci, pm_message_t state)
 {
 	struct snd_card *card = pci_get_drvdata(pci);
@@ -2404,8 +2397,7 @@
 		return -EIO;
 	azx_init_pci(chip);
 
-	if (snd_hda_codecs_inuse(chip->bus))
-		azx_init_chip(chip, 1);
+	azx_init_chip(chip, 1);
 
 	snd_hda_resume(chip->bus);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
@@ -2517,6 +2509,7 @@
 	case POS_FIX_LPIB:
 	case POS_FIX_POSBUF:
 	case POS_FIX_VIACOMBO:
+	case POS_FIX_COMBO:
 		return fix;
 	}
 
@@ -2696,6 +2689,12 @@
 
 	chip->position_fix[0] = chip->position_fix[1] =
 		check_position_fix(chip, position_fix[dev]);
+	/* combo mode uses LPIB for playback */
+	if (chip->position_fix[0] == POS_FIX_COMBO) {
+		chip->position_fix[0] = POS_FIX_LPIB;
+		chip->position_fix[1] = POS_FIX_AUTO;
+	}
+
 	check_probe_mask(chip, dev);
 
 	chip->single_cmd = single_cmd;
@@ -2774,9 +2773,16 @@
 	}
 
 	/* disable buffer size rounding to 128-byte multiples if supported */
-	chip->align_buffer_size = align_buffer_size;
-	if (chip->driver_caps & AZX_DCAPS_BUFSIZE)
-		chip->align_buffer_size = 0;
+	if (align_buffer_size >= 0)
+		chip->align_buffer_size = !!align_buffer_size;
+	else {
+		if (chip->driver_caps & AZX_DCAPS_BUFSIZE)
+			chip->align_buffer_size = 0;
+		else if (chip->driver_caps & AZX_DCAPS_ALIGN_BUFSIZE)
+			chip->align_buffer_size = 1;
+		else
+			chip->align_buffer_size = 1;
+	}
 
 	/* allow 64bit DMA address if supported by H/W */
 	if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
@@ -2992,6 +2998,10 @@
 	{ PCI_DEVICE(0x8086, 0x1e20),
 	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
 	  AZX_DCAPS_BUFSIZE},
+	/* Lynx Point */
+	{ PCI_DEVICE(0x8086, 0x8c20),
+	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
+	  AZX_DCAPS_BUFSIZE},
 	/* SCH */
 	{ PCI_DEVICE(0x8086, 0x811b),
 	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index 9d819c4..d689484 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -19,6 +19,22 @@
 #include "hda_local.h"
 #include "hda_jack.h"
 
+bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
+{
+	if (codec->no_jack_detect)
+		return false;
+	if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT))
+		return false;
+	if (!codec->ignore_misc_bit &&
+	    (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
+	     AC_DEFCFG_MISC_NO_PRESENCE))
+		return false;
+	if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
+		return false;
+	return true;
+}
+EXPORT_SYMBOL_HDA(is_jack_detectable);
+
 /* execute pin sense measurement */
 static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid)
 {
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
index f8f97c7..c66655c 100644
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/pci/hda/hda_jack.h
@@ -62,18 +62,7 @@
 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);
 
-static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
-{
-	if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT))
-		return false;
-	if (!codec->ignore_misc_bit &&
-	    (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
-	     AC_DEFCFG_MISC_NO_PRESENCE))
-		return false;
-	if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
-		return false;
-	return true;
-}
+bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid);
 
 int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
 			  const char *name, int idx);
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index aca8d31..0ec9248 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -139,10 +139,36 @@
 			     unsigned int *tlv);
 struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
 					    const char *name);
-int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
-			unsigned int *tlv, const char * const *slaves);
+int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
+			  unsigned int *tlv, const char * const *slaves,
+			  const char *suffix, bool init_slave_vol,
+			  struct snd_kcontrol **ctl_ret);
+#define snd_hda_add_vmaster(codec, name, tlv, slaves, suffix) \
+	__snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true, NULL)
 int snd_hda_codec_reset(struct hda_codec *codec);
 
+enum {
+	HDA_VMUTE_OFF,
+	HDA_VMUTE_ON,
+	HDA_VMUTE_FOLLOW_MASTER,
+};
+
+struct hda_vmaster_mute_hook {
+	/* below two fields must be filled by the caller of
+	 * snd_hda_add_vmaster_hook() beforehand
+	 */
+	struct snd_kcontrol *sw_kctl;
+	void (*hook)(void *, int);
+	/* below are initialized automatically */
+	unsigned int mute_mode; /* HDA_VMUTE_XXX */
+	struct hda_codec *codec;
+};
+
+int snd_hda_add_vmaster_hook(struct hda_codec *codec,
+			     struct hda_vmaster_mute_hook *hook,
+			     bool expose_enum_ctl);
+void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook);
+
 /* amp value bits */
 #define HDA_AMP_MUTE	0x80
 #define HDA_AMP_UNMUTE	0x00
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 9cb14b4..7143393 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -82,6 +82,7 @@
 	unsigned int inv_jack_detect: 1;/* inverted jack-detection */
 	unsigned int inv_eapd: 1;	/* inverted EAPD implementation */
 	unsigned int analog_beep: 1;	/* analog beep input present */
+	unsigned int avoid_init_slave_vol:1;
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	struct hda_loopback_check loopback;
@@ -137,51 +138,17 @@
 	return 0;
 }
 
-static const char * const ad_slave_vols[] = {
-	"Front Playback Volume",
-	"Surround Playback Volume",
-	"Center Playback Volume",
-	"LFE Playback Volume",
-	"Side Playback Volume",
-	"Headphone Playback Volume",
-	"Mono Playback Volume",
-	"Speaker Playback Volume",
-	"IEC958 Playback Volume",
+static const char * const ad_slave_pfxs[] = {
+	"Front", "Surround", "Center", "LFE", "Side",
+	"Headphone", "Mono", "Speaker", "IEC958",
 	NULL
 };
 
-static const char * const ad_slave_sws[] = {
-	"Front Playback Switch",
-	"Surround Playback Switch",
-	"Center Playback Switch",
-	"LFE Playback Switch",
-	"Side Playback Switch",
-	"Headphone Playback Switch",
-	"Mono Playback Switch",
-	"Speaker Playback Switch",
-	"IEC958 Playback Switch",
+static const char * const ad1988_6stack_fp_slave_pfxs[] = {
+	"Front", "Surround", "Center", "LFE", "Side", "IEC958",
 	NULL
 };
 
-static const char * const ad1988_6stack_fp_slave_vols[] = {
-	"Front Playback Volume",
-	"Surround Playback Volume",
-	"Center Playback Volume",
-	"LFE Playback Volume",
-	"Side Playback Volume",
-	"IEC958 Playback Volume",
-	NULL
-};
-
-static const char * const ad1988_6stack_fp_slave_sws[] = {
-	"Front Playback Switch",
-	"Surround Playback Switch",
-	"Center Playback Switch",
-	"LFE Playback Switch",
-	"Side Playback Switch",
-	"IEC958 Playback Switch",
-	NULL
-};
 static void ad198x_free_kctls(struct hda_codec *codec);
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
@@ -257,10 +224,12 @@
 		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",
+		err = __snd_hda_add_vmaster(codec, "Master Playback Volume",
 					  vmaster_tlv,
 					  (spec->slave_vols ?
-					   spec->slave_vols : ad_slave_vols));
+					   spec->slave_vols : ad_slave_pfxs),
+					  "Playback Volume",
+					  !spec->avoid_init_slave_vol, NULL);
 		if (err < 0)
 			return err;
 	}
@@ -268,7 +237,8 @@
 		err = snd_hda_add_vmaster(codec, "Master Playback Switch",
 					  NULL,
 					  (spec->slave_sws ?
-					   spec->slave_sws : ad_slave_sws));
+					   spec->slave_sws : ad_slave_pfxs),
+					  "Playback Switch");
 		if (err < 0)
 			return err;
 	}
@@ -3385,8 +3355,8 @@
 
 	if (spec->autocfg.hp_pins[0]) {
 		spec->mixers[spec->num_mixers++] = ad1988_hp_mixers;
-		spec->slave_vols = ad1988_6stack_fp_slave_vols;
-		spec->slave_sws = ad1988_6stack_fp_slave_sws;
+		spec->slave_vols = ad1988_6stack_fp_slave_pfxs;
+		spec->slave_sws = ad1988_6stack_fp_slave_pfxs;
 		spec->alt_dac_nid = ad1988_alt_dac_nid;
 		spec->stream_analog_alt_playback =
 			&ad198x_pcm_analog_alt_playback;
@@ -3594,16 +3564,8 @@
 #endif
 
 static const char * const ad1884_slave_vols[] = {
-	"PCM Playback Volume",
-	"Mic Playback Volume",
-	"Mono Playback Volume",
-	"Front Mic Playback Volume",
-	"Mic Playback Volume",
-	"CD Playback Volume",
-	"Internal Mic Playback Volume",
-	"Docking Mic Playback Volume",
-	/* "Beep Playback Volume", */
-	"IEC958 Playback Volume",
+	"PCM", "Mic", "Mono", "Front Mic", "Mic", "CD",
+	"Internal Mic", "Docking Mic", /* "Beep", */ "IEC958",
 	NULL
 };
 
@@ -3644,6 +3606,8 @@
 	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;
 
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index f584f6d..8c6523b 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -70,6 +70,8 @@
 	const struct snd_kcontrol_new *mixers[5];
 	int num_mixers;
 	hda_nid_t vmaster_nid;
+	struct hda_vmaster_mute_hook vmaster_mute;
+	bool vmaster_mute_led;
 
 	const struct hda_verb *init_verbs[5];	/* initialization verbs
 						 * don't forget NULL
@@ -465,21 +467,8 @@
 };
 #endif
 
-static const char * const slave_vols[] = {
-	"Headphone Playback Volume",
-	"Speaker Playback Volume",
-	"Front Playback Volume",
-	"Surround Playback Volume",
-	"CLFE Playback Volume",
-	NULL
-};
-
-static const char * const slave_sws[] = {
-	"Headphone Playback Switch",
-	"Speaker Playback Switch",
-	"Front Playback Switch",
-	"Surround Playback Switch",
-	"CLFE Playback Switch",
+static const char * const slave_pfxs[] = {
+	"Headphone", "Speaker", "Front", "Surround", "CLFE",
 	NULL
 };
 
@@ -519,14 +508,17 @@
 		snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
 					HDA_OUTPUT, vmaster_tlv);
 		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
-					  vmaster_tlv, slave_vols);
+					  vmaster_tlv, slave_pfxs,
+					  "Playback Volume");
 		if (err < 0)
 			return err;
 	}
 	if (spec->vmaster_nid &&
 	    !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
-		err = snd_hda_add_vmaster(codec, "Master Playback Switch",
-					  NULL, slave_sws);
+		err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
+					    NULL, slave_pfxs,
+					    "Playback Switch", true,
+					    &spec->vmaster_mute.sw_kctl);
 		if (err < 0)
 			return err;
 	}
@@ -3034,7 +3026,6 @@
 	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS),
 	SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS),
 	SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G565", CXT5066_AUTO),
-	SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */
 	SND_PCI_QUIRK(0x1b0a, 0x2092, "CyberpowerPC Gamer Xplorer N57001", CXT5066_AUTO),
 	{}
 };
@@ -3943,6 +3934,63 @@
 		snd_hda_jack_detect_enable(codec, pins[i], action);
 }
 
+static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+	int i;
+	for (i = 0; i < nums; i++)
+		if (list[i] == nid)
+			return true;
+	return false;
+}
+
+/* is the given NID found in any of autocfg items? */
+static bool found_in_autocfg(struct auto_pin_cfg *cfg, hda_nid_t nid)
+{
+	int i;
+
+	if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) ||
+	    found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) ||
+	    found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs) ||
+	    found_in_nid_list(nid, cfg->dig_out_pins, cfg->dig_outs))
+		return true;
+	for (i = 0; i < cfg->num_inputs; i++)
+		if (cfg->inputs[i].pin == nid)
+			return true;
+	if (cfg->dig_in_pin == nid)
+		return true;
+	return false;
+}
+
+/* clear unsol-event tags on unused pins; Conexant codecs seem to leave
+ * invalid unsol tags by some reason
+ */
+static void clear_unsol_on_unused_pins(struct hda_codec *codec)
+{
+	struct conexant_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int i;
+
+	for (i = 0; i < codec->init_pins.used; i++) {
+		struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
+		if (!found_in_autocfg(cfg, pin->nid))
+			snd_hda_codec_write(codec, pin->nid, 0,
+					    AC_VERB_SET_UNSOLICITED_ENABLE, 0);
+	}
+}
+
+/* turn on/off EAPD according to Master switch */
+static void cx_auto_vmaster_hook(void *private_data, int enabled)
+{
+	struct hda_codec *codec = private_data;
+	struct conexant_spec *spec = codec->spec;
+
+	if (enabled && spec->pin_eapd_ctrls) {
+		cx_auto_update_speakers(codec);
+		return;
+	}
+	cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled);
+}
+
 static void cx_auto_init_output(struct hda_codec *codec)
 {
 	struct conexant_spec *spec = codec->spec;
@@ -3983,6 +4031,7 @@
 	/* turn on all EAPDs if no individual EAPD control is available */
 	if (!spec->pin_eapd_ctrls)
 		cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
+	clear_unsol_on_unused_pins(codec);
 }
 
 static void cx_auto_init_input(struct hda_codec *codec)
@@ -4046,11 +4095,13 @@
 
 static int cx_auto_init(struct hda_codec *codec)
 {
+	struct conexant_spec *spec = codec->spec;
 	/*snd_hda_sequence_write(codec, cx_auto_init_verbs);*/
 	cx_auto_init_output(codec);
 	cx_auto_init_input(codec);
 	cx_auto_init_digital(codec);
 	snd_hda_jack_report_sync(codec);
+	snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
 	return 0;
 }
 
@@ -4296,6 +4347,13 @@
 	err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
 	if (err < 0)
 		return err;
+	if (spec->vmaster_mute.sw_kctl) {
+		spec->vmaster_mute.hook = cx_auto_vmaster_hook;
+		err = snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute,
+					       spec->vmaster_mute_led);
+		if (err < 0)
+			return err;
+	}
 	return 0;
 }
 
@@ -4320,7 +4378,6 @@
 	return 0;
 }
 
-
 static const struct hda_codec_ops cx_auto_patch_ops = {
 	.build_controls = cx_auto_build_controls,
 	.build_pcms = conexant_build_pcms,
@@ -4368,6 +4425,7 @@
 	{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
 	{ 0x17, 0x21a11000 }, /* dock-mic */
 	{ 0x19, 0x2121103f }, /* dock-HP */
+	{ 0x1c, 0x21440100 }, /* dock SPDIF out */
 	{}
 };
 
@@ -4421,6 +4479,18 @@
 
 	apply_pin_fixup(codec, cxt_fixups, cxt_pincfg_tbl);
 
+	/* Show mute-led control only on HP laptops
+	 * This is a sort of white-list: on HP laptops, EAPD corresponds
+	 * only to the mute-LED without actualy amp function.  Meanwhile,
+	 * others may use EAPD really as an amp switch, so it might be
+	 * not good to expose it blindly.
+	 */
+	switch (codec->subsystem_id >> 16) {
+	case 0x103c:
+		spec->vmaster_mute_led = 1;
+		break;
+	}
+
 	err = cx_auto_search_adcs(codec);
 	if (err < 0)
 		return err;
@@ -4434,6 +4504,18 @@
 	codec->patch_ops = cx_auto_patch_ops;
 	if (spec->beep_amp)
 		snd_hda_attach_beep_device(codec, spec->beep_amp);
+
+	/* Some laptops with Conexant chips show stalls in S3 resume,
+	 * which falls into the single-cmd mode.
+	 * Better to make reset, then.
+	 */
+	if (!codec->bus->sync_write) {
+		snd_printd("hda_codec: "
+			   "Enable sync_write for stable communication\n");
+		codec->bus->sync_write = 1;
+		codec->bus->allow_bus_reset = 1;
+	}
+
 	return 0;
 }
 
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 1168ebd..540cd13 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1912,6 +1912,7 @@
 { .id = 0x80862804, .name = "IbexPeak HDMI",	.patch = patch_generic_hdmi },
 { .id = 0x80862805, .name = "CougarPoint HDMI",	.patch = patch_generic_hdmi },
 { .id = 0x80862806, .name = "PantherPoint HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x80862880, .name = "CedarTrail HDMI",	.patch = patch_generic_hdmi },
 { .id = 0x808629fb, .name = "Crestline HDMI",	.patch = patch_generic_hdmi },
 {} /* terminator */
 };
@@ -1958,6 +1959,7 @@
 MODULE_ALIAS("snd-hda-codec-id:80862804");
 MODULE_ALIAS("snd-hda-codec-id:80862805");
 MODULE_ALIAS("snd-hda-codec-id:80862806");
+MODULE_ALIAS("snd-hda-codec-id:80862880");
 MODULE_ALIAS("snd-hda-codec-id:808629fb");
 
 MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 22c73b7..9917e55 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -198,8 +198,11 @@
 
 	/* for virtual master */
 	hda_nid_t vmaster_nid;
+	struct hda_vmaster_mute_hook vmaster_mute;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	struct hda_loopback_check loopback;
+	int num_loopbacks;
+	struct hda_amp_list loopback_list[8];
 #endif
 
 	/* for PLL fix */
@@ -220,8 +223,6 @@
 	struct snd_array bind_ctls;
 };
 
-#define ALC_MODEL_AUTO		0	/* common for all chips */
-
 static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
 			   int dir, unsigned int bits)
 {
@@ -300,6 +301,9 @@
 	int i, type, num_conns;
 	hda_nid_t nid;
 
+	if (!spec->input_mux)
+		return 0;
+
 	mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
 	imux = &spec->input_mux[mux_idx];
 	if (!imux->num_items && mux_idx > 0)
@@ -651,15 +655,51 @@
 	snd_hda_jack_report_sync(codec);
 }
 
+/* update the master volume per volume-knob's unsol event */
+static void alc_update_knob_master(struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int val;
+	struct snd_kcontrol *kctl;
+	struct snd_ctl_elem_value *uctl;
+
+	kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume");
+	if (!kctl)
+		return;
+	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
+	if (!uctl)
+		return;
+	val = snd_hda_codec_read(codec, nid, 0,
+				 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
+	val &= HDA_AMP_VOLMASK;
+	uctl->value.integer.value[0] = val;
+	uctl->value.integer.value[1] = val;
+	kctl->put(kctl, uctl);
+	kfree(uctl);
+}
+
 /* unsolicited event for HP jack sensing */
 static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
 {
+	int action;
+
 	if (codec->vendor_id == 0x10ec0880)
 		res >>= 28;
 	else
 		res >>= 26;
-	res = snd_hda_jack_get_action(codec, res);
-	alc_exec_unsol_event(codec, res);
+	action = snd_hda_jack_get_action(codec, res);
+	if (action == ALC_DCVOL_EVENT) {
+		/* Execute the dc-vol event here as it requires the NID
+		 * but we don't pass NID to alc_exec_unsol_event().
+		 * Once when we convert all static quirks to the auto-parser,
+		 * this can be integerated into there.
+		 */
+		struct hda_jack_tbl *jack;
+		jack = snd_hda_jack_tbl_get_from_tag(codec, res);
+		if (jack)
+			alc_update_knob_master(codec, jack->nid);
+		return;
+	}
+	alc_exec_unsol_event(codec, action);
 }
 
 /* call init functions of standard auto-mute helpers */
@@ -1033,45 +1073,6 @@
 	return true;
 }
 
-/* rebuild imux for matching with the given auto-mic pins (if not yet) */
-static bool alc_rebuild_imux_for_auto_mic(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	struct hda_input_mux *imux;
-	static char * const texts[3] = {
-		"Mic", "Internal Mic", "Dock Mic"
-	};
-	int i;
-
-	if (!spec->auto_mic)
-		return false;
-	imux = &spec->private_imux[0];
-	if (spec->input_mux == imux)
-		return true;
-	spec->imux_pins[0] = spec->ext_mic_pin;
-	spec->imux_pins[1] = spec->int_mic_pin;
-	spec->imux_pins[2] = spec->dock_mic_pin;
-	for (i = 0; i < 3; i++) {
-		strcpy(imux->items[i].label, texts[i]);
-		if (spec->imux_pins[i]) {
-			hda_nid_t pin = spec->imux_pins[i];
-			int c;
-			for (c = 0; c < spec->num_adc_nids; c++) {
-				hda_nid_t cap = get_capsrc(spec, c);
-				int idx = get_connection_index(codec, cap, pin);
-				if (idx >= 0) {
-					imux->items[i].index = idx;
-					break;
-				}
-			}
-			imux->num_items = i + 1;
-		}
-	}
-	spec->num_mux_defs = 1;
-	spec->input_mux = imux;
-	return true;
-}
-
 /* check whether all auto-mic pins are valid; setup indices if OK */
 static bool alc_auto_mic_check_imux(struct hda_codec *codec)
 {
@@ -1441,6 +1442,7 @@
 	ALC_FIXUP_ACT_PRE_PROBE,
 	ALC_FIXUP_ACT_PROBE,
 	ALC_FIXUP_ACT_INIT,
+	ALC_FIXUP_ACT_BUILD,
 };
 
 static void alc_apply_fixup(struct hda_codec *codec, int action)
@@ -1520,6 +1522,13 @@
 	int id = -1;
 	const char *name = NULL;
 
+	/* when model=nofixup is given, don't pick up any fixups */
+	if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
+		spec->fixup_list = NULL;
+		spec->fixup_id = -1;
+		return;
+	}
+
 	if (codec->modelname && models) {
 		while (models->name) {
 			if (!strcmp(codec->modelname, models->name)) {
@@ -1847,36 +1856,10 @@
 /*
  * slave controls for virtual master
  */
-static const char * const alc_slave_vols[] = {
-	"Front Playback Volume",
-	"Surround Playback Volume",
-	"Center Playback Volume",
-	"LFE Playback Volume",
-	"Side Playback Volume",
-	"Headphone Playback Volume",
-	"Speaker Playback Volume",
-	"Mono Playback Volume",
-	"Line Out Playback Volume",
-	"CLFE Playback Volume",
-	"Bass Speaker Playback Volume",
-	"PCM Playback Volume",
-	NULL,
-};
-
-static const char * const alc_slave_sws[] = {
-	"Front Playback Switch",
-	"Surround Playback Switch",
-	"Center Playback Switch",
-	"LFE Playback Switch",
-	"Side Playback Switch",
-	"Headphone Playback Switch",
-	"Speaker Playback Switch",
-	"Mono Playback Switch",
-	"IEC958 Playback Switch",
-	"Line Out Playback Switch",
-	"CLFE Playback Switch",
-	"Bass Speaker Playback Switch",
-	"PCM Playback Switch",
+static const char * const alc_slave_pfxs[] = {
+	"Front", "Surround", "Center", "LFE", "Side",
+	"Headphone", "Speaker", "Mono", "Line Out",
+	"CLFE", "Bass Speaker", "PCM",
 	NULL,
 };
 
@@ -1967,14 +1950,17 @@
 		snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
 					HDA_OUTPUT, vmaster_tlv);
 		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
-					  vmaster_tlv, alc_slave_vols);
+					  vmaster_tlv, alc_slave_pfxs,
+					  "Playback Volume");
 		if (err < 0)
 			return err;
 	}
 	if (!spec->no_analog &&
 	    !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
-		err = snd_hda_add_vmaster(codec, "Master Playback Switch",
-					  NULL, alc_slave_sws);
+		err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
+					    NULL, alc_slave_pfxs,
+					    "Playback Switch",
+					    true, &spec->vmaster_mute.sw_kctl);
 		if (err < 0)
 			return err;
 	}
@@ -2059,7 +2045,11 @@
 	int err = __alc_build_controls(codec);
 	if (err < 0)
 		return err;
-	return snd_hda_jack_add_kctls(codec, &spec->autocfg);
+	err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	alc_apply_fixup(codec, ALC_FIXUP_ACT_BUILD);
+	return 0;
 }
 
 
@@ -2068,15 +2058,15 @@
  */
 
 static void alc_init_special_input_src(struct hda_codec *codec);
-static int alc269_fill_coef(struct hda_codec *codec);
+static void alc_auto_init_std(struct hda_codec *codec);
 
 static int alc_init(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	unsigned int i;
 
-	if (codec->vendor_id == 0x10ec0269)
-		alc269_fill_coef(codec);
+	if (spec->init_hook)
+		spec->init_hook(codec);
 
 	alc_fix_pll(codec);
 	alc_auto_init_amp(codec, spec->init_amp);
@@ -2084,9 +2074,7 @@
 	for (i = 0; i < spec->num_init_verbs; i++)
 		snd_hda_sequence_write(codec, spec->init_verbs[i]);
 	alc_init_special_input_src(codec);
-
-	if (spec->init_hook)
-		spec->init_hook(codec);
+	alc_auto_init_std(codec);
 
 	alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
 
@@ -2675,6 +2663,25 @@
 	return channel_name[ch];
 }
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+/* add the powersave loopback-list entry */
+static void add_loopback_list(struct alc_spec *spec, hda_nid_t mix, int idx)
+{
+	struct hda_amp_list *list;
+
+	if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1)
+		return;
+	list = spec->loopback_list + spec->num_loopbacks;
+	list->nid = mix;
+	list->dir = HDA_INPUT;
+	list->idx = idx;
+	spec->num_loopbacks++;
+	spec->loopback.amplist = spec->loopback_list;
+}
+#else
+#define add_loopback_list(spec, mix, idx) /* NOP */
+#endif
+
 /* create input playback/capture controls for the given pin */
 static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
 			    const char *ctlname, int ctlidx,
@@ -2690,6 +2697,7 @@
 			  HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
 	if (err < 0)
 		return err;
+	add_loopback_list(spec, mix_nid, idx);
 	return 0;
 }
 
@@ -2709,9 +2717,6 @@
 	int max_nums = ARRAY_SIZE(spec->private_adc_nids);
 	int i, nums = 0;
 
-	if (spec->shared_mic_hp)
-		max_nums = 1; /* no multi streams with the shared HP/mic */
-
 	nid = codec->start_nid;
 	for (i = 0; i < codec->num_nodes; i++, nid++) {
 		hda_nid_t src;
@@ -2954,10 +2959,27 @@
 	return 0;
 }
 
+static bool alc_is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
+{
+	struct alc_spec *spec = codec->spec;
+	int i;
+	if (found_in_nid_list(nid, spec->multiout.dac_nids,
+			      ARRAY_SIZE(spec->private_dac_nids)) ||
+	    found_in_nid_list(nid, spec->multiout.hp_out_nid,
+			      ARRAY_SIZE(spec->multiout.hp_out_nid)) ||
+	    found_in_nid_list(nid, spec->multiout.extra_out_nid,
+			      ARRAY_SIZE(spec->multiout.extra_out_nid)))
+		return true;
+	for (i = 0; i < spec->multi_ios; i++) {
+		if (spec->multi_io[i].dac == nid)
+			return true;
+	}
+	return false;
+}
+
 /* look for an empty DAC slot */
 static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
 {
-	struct alc_spec *spec = codec->spec;
 	hda_nid_t srcs[5];
 	int i, num;
 
@@ -2967,16 +2989,8 @@
 		hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
 		if (!nid)
 			continue;
-		if (found_in_nid_list(nid, spec->multiout.dac_nids,
-				      ARRAY_SIZE(spec->private_dac_nids)))
-			continue;
-		if (found_in_nid_list(nid, spec->multiout.hp_out_nid,
-				      ARRAY_SIZE(spec->multiout.hp_out_nid)))
-		    continue;
-		if (found_in_nid_list(nid, spec->multiout.extra_out_nid,
-				      ARRAY_SIZE(spec->multiout.extra_out_nid)))
-		    continue;
-		return nid;
+		if (!alc_is_dac_already_used(codec, nid))
+			return nid;
 	}
 	return 0;
 }
@@ -2988,6 +3002,8 @@
 	hda_nid_t srcs[5];
 	int i, num;
 
+	if (!pin || !dac)
+		return false;
 	pin = alc_go_down_to_selector(codec, pin);
 	num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
 	for (i = 0; i < num; i++) {
@@ -3000,158 +3016,30 @@
 
 static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
 {
-	hda_nid_t sel = alc_go_down_to_selector(codec, pin);
-	if (snd_hda_get_conn_list(codec, sel, NULL) == 1)
-		return alc_auto_look_for_dac(codec, pin);
-	return 0;
-}
-
-/* return 0 if no possible DAC is found, 1 if one or more found */
-static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
-				    const hda_nid_t *pins, hda_nid_t *dacs)
-{
-	int i;
-
-	if (num_outs && !dacs[0]) {
-		dacs[0] = alc_auto_look_for_dac(codec, pins[0]);
-		if (!dacs[0])
-			return 0;
-	}
-
-	for (i = 1; i < num_outs; i++)
-		dacs[i] = get_dac_if_single(codec, pins[i]);
-	for (i = 1; i < num_outs; i++) {
-		if (!dacs[i])
-			dacs[i] = alc_auto_look_for_dac(codec, pins[i]);
-	}
-	return 1;
-}
-
-static int alc_auto_fill_multi_ios(struct hda_codec *codec,
-				   unsigned int location, int offset);
-static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
-					  hda_nid_t pin, hda_nid_t dac);
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int alc_auto_fill_dac_nids(struct hda_codec *codec)
-{
 	struct alc_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->autocfg;
-	unsigned int location, defcfg;
-	int num_pins;
-	bool redone = false;
-	int i;
-
- again:
-	/* set num_dacs once to full for alc_auto_look_for_dac() */
-	spec->multiout.num_dacs = cfg->line_outs;
-	spec->multiout.hp_out_nid[0] = 0;
-	spec->multiout.extra_out_nid[0] = 0;
-	memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
-	spec->multiout.dac_nids = spec->private_dac_nids;
-	spec->multi_ios = 0;
-
-	/* fill hard-wired DACs first */
-	if (!redone) {
-		for (i = 0; i < cfg->line_outs; i++)
-			spec->private_dac_nids[i] =
-				get_dac_if_single(codec, cfg->line_out_pins[i]);
-		if (cfg->hp_outs)
-			spec->multiout.hp_out_nid[0] =
-				get_dac_if_single(codec, cfg->hp_pins[0]);
-		if (cfg->speaker_outs)
-			spec->multiout.extra_out_nid[0] =
-				get_dac_if_single(codec, cfg->speaker_pins[0]);
-	}
-
-	for (i = 0; i < cfg->line_outs; i++) {
-		hda_nid_t pin = cfg->line_out_pins[i];
-		if (spec->private_dac_nids[i])
+	hda_nid_t sel = alc_go_down_to_selector(codec, pin);
+	hda_nid_t nid, nid_found, srcs[5];
+	int i, num = snd_hda_get_connections(codec, sel, srcs,
+					  ARRAY_SIZE(srcs));
+	if (num == 1)
+		return alc_auto_look_for_dac(codec, pin);
+	nid_found = 0;
+	for (i = 0; i < num; i++) {
+		if (srcs[i] == spec->mixer_nid)
 			continue;
-		spec->private_dac_nids[i] = alc_auto_look_for_dac(codec, pin);
-		if (!spec->private_dac_nids[i] && !redone) {
-			/* if we can't find primary DACs, re-probe without
-			 * checking the hard-wired DACs
-			 */
-			redone = true;
-			goto again;
+		nid = alc_auto_mix_to_dac(codec, srcs[i]);
+		if (nid && !alc_is_dac_already_used(codec, nid)) {
+			if (nid_found)
+				return 0;
+			nid_found = nid;
 		}
 	}
-
-	/* re-count num_dacs and squash invalid entries */
-	spec->multiout.num_dacs = 0;
-	for (i = 0; i < cfg->line_outs; i++) {
-		if (spec->private_dac_nids[i])
-			spec->multiout.num_dacs++;
-		else {
-			memmove(spec->private_dac_nids + i,
-				spec->private_dac_nids + i + 1,
-				sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
-			spec->private_dac_nids[cfg->line_outs - 1] = 0;
-		}
-	}
-
-	if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
-		/* try to fill multi-io first */
-		defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
-		location = get_defcfg_location(defcfg);
-
-		num_pins = alc_auto_fill_multi_ios(codec, location, 0);
-		if (num_pins > 0) {
-			spec->multi_ios = num_pins;
-			spec->ext_channel_count = 2;
-			spec->multiout.num_dacs = num_pins + 1;
-		}
-	}
-
-	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
-		alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins,
-				 spec->multiout.hp_out_nid);
-	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
-		int err = alc_auto_fill_extra_dacs(codec, cfg->speaker_outs,
-					cfg->speaker_pins,
-					spec->multiout.extra_out_nid);
-		/* if no speaker volume is assigned, try again as the primary
-		 * output
-		 */
-		if (!err && cfg->speaker_outs > 0 &&
-		    cfg->line_out_type == AUTO_PIN_HP_OUT) {
-			cfg->hp_outs = cfg->line_outs;
-			memcpy(cfg->hp_pins, cfg->line_out_pins,
-			       sizeof(cfg->hp_pins));
-			cfg->line_outs = cfg->speaker_outs;
-			memcpy(cfg->line_out_pins, cfg->speaker_pins,
-			       sizeof(cfg->speaker_pins));
-			cfg->speaker_outs = 0;
-			memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
-			cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
-			redone = false;
-			goto again;
-		}
-	}
-
-	if (!spec->multi_ios &&
-	    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
-	    cfg->hp_outs) {
-		/* try multi-ios with HP + inputs */
-		defcfg = snd_hda_codec_get_pincfg(codec, cfg->hp_pins[0]);
-		location = get_defcfg_location(defcfg);
-
-		num_pins = alc_auto_fill_multi_ios(codec, location, 1);
-		if (num_pins > 0) {
-			spec->multi_ios = num_pins;
-			spec->ext_channel_count = 2;
-			spec->multiout.num_dacs = num_pins + 1;
-		}
-	}
-
-	if (cfg->line_out_pins[0])
-		spec->vmaster_nid =
-			alc_look_for_out_vol_nid(codec, cfg->line_out_pins[0],
-						 spec->multiout.dac_nids[0]);
-	return 0;
+	return nid_found;
 }
 
+/* mark up volume and mute control NIDs: used during badness parsing and
+ * at creating actual controls
+ */
 static inline unsigned int get_ctl_pos(unsigned int data)
 {
 	hda_nid_t nid = get_amp_nid_(data);
@@ -3167,6 +3055,422 @@
 #define mark_ctl_usage(bits, data) \
 	set_bit(get_ctl_pos(data), bits)
 
+static void clear_vol_marks(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	memset(spec->vol_ctls, 0, sizeof(spec->vol_ctls));
+	memset(spec->sw_ctls, 0, sizeof(spec->sw_ctls));
+}
+
+/* badness definition */
+enum {
+	/* No primary DAC is found for the main output */
+	BAD_NO_PRIMARY_DAC = 0x10000,
+	/* No DAC is found for the extra output */
+	BAD_NO_DAC = 0x4000,
+	/* No possible multi-ios */
+	BAD_MULTI_IO = 0x103,
+	/* No individual DAC for extra output */
+	BAD_NO_EXTRA_DAC = 0x102,
+	/* No individual DAC for extra surrounds */
+	BAD_NO_EXTRA_SURR_DAC = 0x101,
+	/* Primary DAC shared with main surrounds */
+	BAD_SHARED_SURROUND = 0x100,
+	/* Primary DAC shared with main CLFE */
+	BAD_SHARED_CLFE = 0x10,
+	/* Primary DAC shared with extra surrounds */
+	BAD_SHARED_EXTRA_SURROUND = 0x10,
+	/* Volume widget is shared */
+	BAD_SHARED_VOL = 0x10,
+};
+
+static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec,
+					   hda_nid_t pin, hda_nid_t dac);
+static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
+					  hda_nid_t pin, hda_nid_t dac);
+
+static int eval_shared_vol_badness(struct hda_codec *codec, hda_nid_t pin,
+				   hda_nid_t dac)
+{
+	struct alc_spec *spec = codec->spec;
+	hda_nid_t nid;
+	unsigned int val;
+	int badness = 0;
+
+	nid = alc_look_for_out_vol_nid(codec, pin, dac);
+	if (nid) {
+		val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+		if (is_ctl_used(spec->vol_ctls, nid))
+			badness += BAD_SHARED_VOL;
+		else
+			mark_ctl_usage(spec->vol_ctls, val);
+	} else
+		badness += BAD_SHARED_VOL;
+	nid = alc_look_for_out_mute_nid(codec, pin, dac);
+	if (nid) {
+		unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid));
+		if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT)
+			val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+		else
+			val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
+		if (is_ctl_used(spec->sw_ctls, val))
+			badness += BAD_SHARED_VOL;
+		else
+			mark_ctl_usage(spec->sw_ctls, val);
+	} else
+		badness += BAD_SHARED_VOL;
+	return badness;
+}
+
+struct badness_table {
+	int no_primary_dac;	/* no primary DAC */
+	int no_dac;		/* no secondary DACs */
+	int shared_primary;	/* primary DAC is shared with main output */
+	int shared_surr;	/* secondary DAC shared with main or primary */
+	int shared_clfe;	/* third DAC shared with main or primary */
+	int shared_surr_main;	/* secondary DAC sahred with main/DAC0 */
+};
+
+static struct badness_table main_out_badness = {
+	.no_primary_dac = BAD_NO_PRIMARY_DAC,
+	.no_dac = BAD_NO_DAC,
+	.shared_primary = BAD_NO_PRIMARY_DAC,
+	.shared_surr = BAD_SHARED_SURROUND,
+	.shared_clfe = BAD_SHARED_CLFE,
+	.shared_surr_main = BAD_SHARED_SURROUND,
+};
+
+static struct badness_table extra_out_badness = {
+	.no_primary_dac = BAD_NO_DAC,
+	.no_dac = BAD_NO_DAC,
+	.shared_primary = BAD_NO_EXTRA_DAC,
+	.shared_surr = BAD_SHARED_EXTRA_SURROUND,
+	.shared_clfe = BAD_SHARED_EXTRA_SURROUND,
+	.shared_surr_main = BAD_NO_EXTRA_SURR_DAC,
+};
+
+/* try to assign DACs to pins and return the resultant badness */
+static int alc_auto_fill_dacs(struct hda_codec *codec, int num_outs,
+			      const hda_nid_t *pins, hda_nid_t *dacs,
+			      const struct badness_table *bad)
+{
+	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int i, j;
+	int badness = 0;
+	hda_nid_t dac;
+
+	if (!num_outs)
+		return 0;
+
+	for (i = 0; i < num_outs; i++) {
+		hda_nid_t pin = pins[i];
+		if (!dacs[i])
+			dacs[i] = alc_auto_look_for_dac(codec, pin);
+		if (!dacs[i] && !i) {
+			for (j = 1; j < num_outs; j++) {
+				if (alc_auto_is_dac_reachable(codec, pin, dacs[j])) {
+					dacs[0] = dacs[j];
+					dacs[j] = 0;
+					break;
+				}
+			}
+		}
+		dac = dacs[i];
+		if (!dac) {
+			if (alc_auto_is_dac_reachable(codec, pin, dacs[0]))
+				dac = dacs[0];
+			else if (cfg->line_outs > i &&
+				 alc_auto_is_dac_reachable(codec, pin,
+					spec->private_dac_nids[i]))
+				dac = spec->private_dac_nids[i];
+			if (dac) {
+				if (!i)
+					badness += bad->shared_primary;
+				else if (i == 1)
+					badness += bad->shared_surr;
+				else
+					badness += bad->shared_clfe;
+			} else if (alc_auto_is_dac_reachable(codec, pin,
+					spec->private_dac_nids[0])) {
+				dac = spec->private_dac_nids[0];
+				badness += bad->shared_surr_main;
+			} else if (!i)
+				badness += bad->no_primary_dac;
+			else
+				badness += bad->no_dac;
+		}
+		if (dac)
+			badness += eval_shared_vol_badness(codec, pin, dac);
+	}
+
+	return badness;
+}
+
+static int alc_auto_fill_multi_ios(struct hda_codec *codec,
+				   hda_nid_t reference_pin,
+				   bool hardwired, int offset);
+
+static bool alc_map_singles(struct hda_codec *codec, int outs,
+			    const hda_nid_t *pins, hda_nid_t *dacs)
+{
+	int i;
+	bool found = false;
+	for (i = 0; i < outs; i++) {
+		if (dacs[i])
+			continue;
+		dacs[i] = get_dac_if_single(codec, pins[i]);
+		if (dacs[i])
+			found = true;
+	}
+	return found;
+}
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int fill_and_eval_dacs(struct hda_codec *codec,
+			      bool fill_hardwired,
+			      bool fill_mio_first)
+{
+	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int i, err, badness;
+
+	/* set num_dacs once to full for alc_auto_look_for_dac() */
+	spec->multiout.num_dacs = cfg->line_outs;
+	spec->multiout.dac_nids = spec->private_dac_nids;
+	memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
+	memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid));
+	memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid));
+	spec->multi_ios = 0;
+	clear_vol_marks(codec);
+	badness = 0;
+
+	/* fill hard-wired DACs first */
+	if (fill_hardwired) {
+		bool mapped;
+		do {
+			mapped = alc_map_singles(codec, cfg->line_outs,
+						 cfg->line_out_pins,
+						 spec->private_dac_nids);
+			mapped |= alc_map_singles(codec, cfg->hp_outs,
+						  cfg->hp_pins,
+						  spec->multiout.hp_out_nid);
+			mapped |= alc_map_singles(codec, cfg->speaker_outs,
+						  cfg->speaker_pins,
+						  spec->multiout.extra_out_nid);
+			if (fill_mio_first && cfg->line_outs == 1 &&
+			    cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+				err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], true, 0);
+				if (!err)
+					mapped = true;
+			}
+		} while (mapped);
+	}
+
+	badness += alc_auto_fill_dacs(codec, cfg->line_outs, cfg->line_out_pins,
+				      spec->private_dac_nids,
+				      &main_out_badness);
+
+	/* re-count num_dacs and squash invalid entries */
+	spec->multiout.num_dacs = 0;
+	for (i = 0; i < cfg->line_outs; i++) {
+		if (spec->private_dac_nids[i])
+			spec->multiout.num_dacs++;
+		else {
+			memmove(spec->private_dac_nids + i,
+				spec->private_dac_nids + i + 1,
+				sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
+			spec->private_dac_nids[cfg->line_outs - 1] = 0;
+		}
+	}
+
+	if (fill_mio_first &&
+	    cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+		/* try to fill multi-io first */
+		err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0);
+		if (err < 0)
+			return err;
+		/* we don't count badness at this stage yet */
+	}
+
+	if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+		err = alc_auto_fill_dacs(codec, cfg->hp_outs, cfg->hp_pins,
+					 spec->multiout.hp_out_nid,
+					 &extra_out_badness);
+		if (err < 0)
+			return err;
+		badness += err;
+	}
+	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+		err = alc_auto_fill_dacs(codec, cfg->speaker_outs,
+					 cfg->speaker_pins,
+					 spec->multiout.extra_out_nid,
+					 &extra_out_badness);
+		if (err < 0)
+			return err;
+		badness += err;
+	}
+	if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+		err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0);
+		if (err < 0)
+			return err;
+		badness += err;
+	}
+	if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
+		/* try multi-ios with HP + inputs */
+		int offset = 0;
+		if (cfg->line_outs >= 3)
+			offset = 1;
+		err = alc_auto_fill_multi_ios(codec, cfg->hp_pins[0], false,
+					      offset);
+		if (err < 0)
+			return err;
+		badness += err;
+	}
+
+	if (spec->multi_ios == 2) {
+		for (i = 0; i < 2; i++)
+			spec->private_dac_nids[spec->multiout.num_dacs++] =
+				spec->multi_io[i].dac;
+		spec->ext_channel_count = 2;
+	} else if (spec->multi_ios) {
+		spec->multi_ios = 0;
+		badness += BAD_MULTI_IO;
+	}
+
+	return badness;
+}
+
+#define DEBUG_BADNESS
+
+#ifdef DEBUG_BADNESS
+#define debug_badness	snd_printdd
+#else
+#define debug_badness(...)
+#endif
+
+static void debug_show_configs(struct alc_spec *spec, struct auto_pin_cfg *cfg)
+{
+	debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
+		      cfg->line_out_pins[0], cfg->line_out_pins[1],
+		      cfg->line_out_pins[2], cfg->line_out_pins[2],
+		      spec->multiout.dac_nids[0],
+		      spec->multiout.dac_nids[1],
+		      spec->multiout.dac_nids[2],
+		      spec->multiout.dac_nids[3]);
+	if (spec->multi_ios > 0)
+		debug_badness("multi_ios(%d) = %x/%x : %x/%x\n",
+			      spec->multi_ios,
+			      spec->multi_io[0].pin, spec->multi_io[1].pin,
+			      spec->multi_io[0].dac, spec->multi_io[1].dac);
+	debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
+		      cfg->hp_pins[0], cfg->hp_pins[1],
+		      cfg->hp_pins[2], cfg->hp_pins[2],
+		      spec->multiout.hp_out_nid[0],
+		      spec->multiout.hp_out_nid[1],
+		      spec->multiout.hp_out_nid[2],
+		      spec->multiout.hp_out_nid[3]);
+	debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
+		      cfg->speaker_pins[0], cfg->speaker_pins[1],
+		      cfg->speaker_pins[2], cfg->speaker_pins[3],
+		      spec->multiout.extra_out_nid[0],
+		      spec->multiout.extra_out_nid[1],
+		      spec->multiout.extra_out_nid[2],
+		      spec->multiout.extra_out_nid[3]);
+}
+
+static int alc_auto_fill_dac_nids(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	struct auto_pin_cfg *best_cfg;
+	int best_badness = INT_MAX;
+	int badness;
+	bool fill_hardwired = true, fill_mio_first = true;
+	bool best_wired = true, best_mio = true;
+	bool hp_spk_swapped = false;
+
+	best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL);
+	if (!best_cfg)
+		return -ENOMEM;
+	*best_cfg = *cfg;
+
+	for (;;) {
+		badness = fill_and_eval_dacs(codec, fill_hardwired,
+					     fill_mio_first);
+		if (badness < 0)
+			return badness;
+		debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n",
+			      cfg->line_out_type, fill_hardwired, fill_mio_first,
+			      badness);
+		debug_show_configs(spec, cfg);
+		if (badness < best_badness) {
+			best_badness = badness;
+			*best_cfg = *cfg;
+			best_wired = fill_hardwired;
+			best_mio = fill_mio_first;
+		}
+		if (!badness)
+			break;
+		fill_mio_first = !fill_mio_first;
+		if (!fill_mio_first)
+			continue;
+		fill_hardwired = !fill_hardwired;
+		if (!fill_hardwired)
+			continue;
+		if (hp_spk_swapped)
+			break;
+		hp_spk_swapped = true;
+		if (cfg->speaker_outs > 0 &&
+		    cfg->line_out_type == AUTO_PIN_HP_OUT) {
+			cfg->hp_outs = cfg->line_outs;
+			memcpy(cfg->hp_pins, cfg->line_out_pins,
+			       sizeof(cfg->hp_pins));
+			cfg->line_outs = cfg->speaker_outs;
+			memcpy(cfg->line_out_pins, cfg->speaker_pins,
+			       sizeof(cfg->speaker_pins));
+			cfg->speaker_outs = 0;
+			memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
+			cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
+			fill_hardwired = true;
+			continue;
+		} 
+		if (cfg->hp_outs > 0 &&
+		    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
+			cfg->speaker_outs = cfg->line_outs;
+			memcpy(cfg->speaker_pins, cfg->line_out_pins,
+			       sizeof(cfg->speaker_pins));
+			cfg->line_outs = cfg->hp_outs;
+			memcpy(cfg->line_out_pins, cfg->hp_pins,
+			       sizeof(cfg->hp_pins));
+			cfg->hp_outs = 0;
+			memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
+			cfg->line_out_type = AUTO_PIN_HP_OUT;
+			fill_hardwired = true;
+			continue;
+		} 
+		break;
+	}
+
+	if (badness) {
+		*cfg = *best_cfg;
+		fill_and_eval_dacs(codec, best_wired, best_mio);
+	}
+	debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n",
+		      cfg->line_out_type, best_wired, best_mio);
+	debug_show_configs(spec, cfg);
+
+	if (cfg->line_out_pins[0])
+		spec->vmaster_nid =
+			alc_look_for_out_vol_nid(codec, cfg->line_out_pins[0],
+						 spec->multiout.dac_nids[0]);
+
+	/* clear the bitmap flags for creating controls */
+	clear_vol_marks(codec);
+	kfree(best_cfg);
+	return 0;
+}
+
 static int alc_auto_add_vol_ctl(struct hda_codec *codec,
 			      const char *pfx, int cidx,
 			      hda_nid_t nid, unsigned int chs)
@@ -3278,14 +3582,17 @@
 		dac = spec->multiout.dac_nids[i];
 		if (!dac)
 			continue;
-		if (i >= cfg->line_outs)
+		if (i >= cfg->line_outs) {
 			pin = spec->multi_io[i - 1].pin;
-		else
+			index = 0;
+			name = channel_name[i];
+		} else {
 			pin = cfg->line_out_pins[i];
+			name = alc_get_line_out_pfx(spec, i, true, &index);
+		}
 
 		sw = alc_look_for_out_mute_nid(codec, pin, dac);
 		vol = alc_look_for_out_vol_nid(codec, pin, dac);
-		name = alc_get_line_out_pfx(spec, i, true, &index);
 		if (!name || !strcmp(name, "CLFE")) {
 			/* Center/LFE */
 			err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1);
@@ -3382,41 +3689,31 @@
 		return alc_auto_create_extra_out(codec, *pins, dac, pfx, 0);
 	}
 
-	if (dacs[num_pins - 1]) {
-		/* OK, we have a multi-output system with individual volumes */
-		for (i = 0; i < num_pins; i++) {
-			if (num_pins >= 3) {
-				snprintf(name, sizeof(name), "%s %s",
-					 pfx, channel_name[i]);
-				err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
-								name, 0);
-			} else {
-				err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
-								pfx, i);
-			}
-			if (err < 0)
-				return err;
-		}
-		return 0;
-	}
-
-	/* Let's create a bind-controls */
-	ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_sw);
-	if (!ctl)
-		return -ENOMEM;
-	n = 0;
 	for (i = 0; i < num_pins; i++) {
-		if (get_wcaps(codec, pins[i]) & AC_WCAP_OUT_AMP)
-			ctl->values[n++] =
-				HDA_COMPOSE_AMP_VAL(pins[i], 3, 0, HDA_OUTPUT);
-	}
-	if (n) {
-		snprintf(name, sizeof(name), "%s Playback Switch", pfx);
-		err = add_control(spec, ALC_CTL_BIND_SW, name, 0, (long)ctl);
+		hda_nid_t dac;
+		if (dacs[num_pins - 1])
+			dac = dacs[i]; /* with individual volumes */
+		else
+			dac = 0;
+		if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) {
+			err = alc_auto_create_extra_out(codec, pins[i], dac,
+							"Bass Speaker", 0);
+		} else if (num_pins >= 3) {
+			snprintf(name, sizeof(name), "%s %s",
+				 pfx, channel_name[i]);
+			err = alc_auto_create_extra_out(codec, pins[i], dac,
+							name, 0);
+		} else {
+			err = alc_auto_create_extra_out(codec, pins[i], dac,
+							pfx, i);
+		}
 		if (err < 0)
 			return err;
 	}
+	if (dacs[num_pins - 1])
+		return 0;
 
+	/* Let's create a bind-controls for volumes */
 	ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol);
 	if (!ctl)
 		return -ENOMEM;
@@ -3552,58 +3849,111 @@
 	}
 }
 
+/* check whether the given pin can be a multi-io pin */
+static bool can_be_multiio_pin(struct hda_codec *codec,
+			       unsigned int location, hda_nid_t nid)
+{
+	unsigned int defcfg, caps;
+
+	defcfg = snd_hda_codec_get_pincfg(codec, nid);
+	if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
+		return false;
+	if (location && get_defcfg_location(defcfg) != location)
+		return false;
+	caps = snd_hda_query_pin_caps(codec, nid);
+	if (!(caps & AC_PINCAP_OUT))
+		return false;
+	return true;
+}
+
 /*
  * multi-io helper
+ *
+ * When hardwired is set, try to fill ony hardwired pins, and returns
+ * zero if any pins are filled, non-zero if nothing found.
+ * When hardwired is off, try to fill possible input pins, and returns
+ * the badness value.
  */
 static int alc_auto_fill_multi_ios(struct hda_codec *codec,
-				   unsigned int location,
-				   int offset)
+				   hda_nid_t reference_pin,
+				   bool hardwired, int offset)
 {
 	struct alc_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
-	hda_nid_t prime_dac = spec->private_dac_nids[0];
-	int type, i, dacs, num_pins = 0;
+	int type, i, j, dacs, num_pins, old_pins;
+	unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
+	unsigned int location = get_defcfg_location(defcfg);
+	int badness = 0;
+
+	old_pins = spec->multi_ios;
+	if (old_pins >= 2)
+		goto end_fill;
+
+	num_pins = 0;
+	for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
+		for (i = 0; i < cfg->num_inputs; i++) {
+			if (cfg->inputs[i].type != type)
+				continue;
+			if (can_be_multiio_pin(codec, location,
+					       cfg->inputs[i].pin))
+				num_pins++;
+		}
+	}
+	if (num_pins < 2)
+		goto end_fill;
 
 	dacs = spec->multiout.num_dacs;
 	for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
 		for (i = 0; i < cfg->num_inputs; i++) {
 			hda_nid_t nid = cfg->inputs[i].pin;
 			hda_nid_t dac = 0;
-			unsigned int defcfg, caps;
+
 			if (cfg->inputs[i].type != type)
 				continue;
-			defcfg = snd_hda_codec_get_pincfg(codec, nid);
-			if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
+			if (!can_be_multiio_pin(codec, location, nid))
 				continue;
-			if (location && get_defcfg_location(defcfg) != location)
+			for (j = 0; j < spec->multi_ios; j++) {
+				if (nid == spec->multi_io[j].pin)
+					break;
+			}
+			if (j < spec->multi_ios)
 				continue;
-			caps = snd_hda_query_pin_caps(codec, nid);
-			if (!(caps & AC_PINCAP_OUT))
-				continue;
-			if (offset && offset + num_pins < dacs) {
-				dac = spec->private_dac_nids[offset + num_pins];
+
+			if (offset && offset + spec->multi_ios < dacs) {
+				dac = spec->private_dac_nids[offset + spec->multi_ios];
 				if (!alc_auto_is_dac_reachable(codec, nid, dac))
 					dac = 0;
 			}
-			if (!dac)
+			if (hardwired)
+				dac = get_dac_if_single(codec, nid);
+			else if (!dac)
 				dac = alc_auto_look_for_dac(codec, nid);
-			if (!dac)
+			if (!dac) {
+				badness++;
 				continue;
-			spec->multi_io[num_pins].pin = nid;
-			spec->multi_io[num_pins].dac = dac;
-			num_pins++;
-			spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
+			}
+			spec->multi_io[spec->multi_ios].pin = nid;
+			spec->multi_io[spec->multi_ios].dac = dac;
+			spec->multi_ios++;
+			if (spec->multi_ios >= 2)
+				break;
 		}
 	}
-	spec->multiout.num_dacs = dacs;
-	if (num_pins < 2) {
-		/* clear up again */
-		memset(spec->private_dac_nids + dacs, 0,
-		       sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - dacs));
-		spec->private_dac_nids[0] = prime_dac;
-		return 0;
+ end_fill:
+	if (badness)
+		badness = BAD_MULTI_IO;
+	if (old_pins == spec->multi_ios) {
+		if (hardwired)
+			return 1; /* nothing found */
+		else
+			return badness; /* no badness if nothing found */
 	}
-	return num_pins;
+	if (!hardwired && spec->multi_ios < 2) {
+		spec->multi_ios = old_pins;
+		return badness;
+	}
+
+	return 0;
 }
 
 static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
@@ -3723,6 +4073,7 @@
 	if (spec->dyn_adc_switch)
 		return;
 
+ again:
 	nums = 0;
 	for (n = 0; n < spec->num_adc_nids; n++) {
 		hda_nid_t cap = spec->private_capsrc_nids[n];
@@ -3743,6 +4094,11 @@
 	if (!nums) {
 		/* check whether ADC-switch is possible */
 		if (!alc_check_dyn_adc_switch(codec)) {
+			if (spec->shared_mic_hp) {
+				spec->shared_mic_hp = 0;
+				spec->private_imux[0].num_items = 1;
+				goto again;
+			}
 			printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
 			       " using fallback 0x%x\n",
 			       codec->chip_name, spec->private_adc_nids[0]);
@@ -3760,7 +4116,7 @@
 
 	if (spec->auto_mic)
 		alc_auto_mic_check_imux(codec); /* check auto-mic setups */
-	else if (spec->input_mux->num_items == 1)
+	else if (spec->input_mux->num_items == 1 || spec->shared_mic_hp)
 		spec->num_adc_nids = 1; /* reduce to a single ADC */
 }
 
@@ -3958,6 +4314,7 @@
 	SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
 	SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
 	SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
+	SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1),
 	SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
 	{}
 };
@@ -4057,6 +4414,9 @@
 	if (spec->kctls.list)
 		add_mixer(spec, spec->kctls.list);
 
+	if (!spec->no_analog && !spec->cap_mixer)
+		set_capture_mixer(codec);
+
 	return 1;
 }
 
@@ -4067,26 +4427,47 @@
 	return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list alc880_loopbacks[] = {
-	{ 0x0b, HDA_INPUT, 0 },
-	{ 0x0b, HDA_INPUT, 1 },
-	{ 0x0b, HDA_INPUT, 2 },
-	{ 0x0b, HDA_INPUT, 3 },
-	{ 0x0b, HDA_INPUT, 4 },
-	{ } /* end */
-};
-#endif
-
 /*
  * ALC880 fix-ups
  */
 enum {
+	ALC880_FIXUP_GPIO1,
 	ALC880_FIXUP_GPIO2,
 	ALC880_FIXUP_MEDION_RIM,
+	ALC880_FIXUP_LG,
+	ALC880_FIXUP_W810,
+	ALC880_FIXUP_EAPD_COEF,
+	ALC880_FIXUP_TCL_S700,
+	ALC880_FIXUP_VOL_KNOB,
+	ALC880_FIXUP_FUJITSU,
+	ALC880_FIXUP_F1734,
+	ALC880_FIXUP_UNIWILL,
+	ALC880_FIXUP_UNIWILL_DIG,
+	ALC880_FIXUP_Z71V,
+	ALC880_FIXUP_3ST_BASE,
+	ALC880_FIXUP_3ST,
+	ALC880_FIXUP_3ST_DIG,
+	ALC880_FIXUP_5ST_BASE,
+	ALC880_FIXUP_5ST,
+	ALC880_FIXUP_5ST_DIG,
+	ALC880_FIXUP_6ST_BASE,
+	ALC880_FIXUP_6ST,
+	ALC880_FIXUP_6ST_DIG,
 };
 
+/* enable the volume-knob widget support on NID 0x21 */
+static void alc880_fixup_vol_knob(struct hda_codec *codec,
+				  const struct alc_fixup *fix, int action)
+{
+	if (action == ALC_FIXUP_ACT_PROBE)
+		snd_hda_jack_detect_enable(codec, 0x21, ALC_DCVOL_EVENT);
+}
+
 static const struct alc_fixup alc880_fixups[] = {
+	[ALC880_FIXUP_GPIO1] = {
+		.type = ALC_FIXUP_VERBS,
+		.v.verbs = alc_gpio1_init_verbs,
+	},
 	[ALC880_FIXUP_GPIO2] = {
 		.type = ALC_FIXUP_VERBS,
 		.v.verbs = alc_gpio2_init_verbs,
@@ -4101,40 +4482,323 @@
 		.chained = true,
 		.chain_id = ALC880_FIXUP_GPIO2,
 	},
+	[ALC880_FIXUP_LG] = {
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			/* disable bogus unused pins */
+			{ 0x16, 0x411111f0 },
+			{ 0x18, 0x411111f0 },
+			{ 0x1a, 0x411111f0 },
+			{ }
+		}
+	},
+	[ALC880_FIXUP_W810] = {
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			/* disable bogus unused pins */
+			{ 0x17, 0x411111f0 },
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_GPIO2,
+	},
+	[ALC880_FIXUP_EAPD_COEF] = {
+		.type = ALC_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			/* change to EAPD mode */
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
+			{}
+		},
+	},
+	[ALC880_FIXUP_TCL_S700] = {
+		.type = ALC_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			/* change to EAPD mode */
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3070 },
+			{}
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_GPIO2,
+	},
+	[ALC880_FIXUP_VOL_KNOB] = {
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc880_fixup_vol_knob,
+	},
+	[ALC880_FIXUP_FUJITSU] = {
+		/* override all pins as BIOS on old Amilo is broken */
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			{ 0x14, 0x0121411f }, /* HP */
+			{ 0x15, 0x99030120 }, /* speaker */
+			{ 0x16, 0x99030130 }, /* bass speaker */
+			{ 0x17, 0x411111f0 }, /* N/A */
+			{ 0x18, 0x411111f0 }, /* N/A */
+			{ 0x19, 0x01a19950 }, /* mic-in */
+			{ 0x1a, 0x411111f0 }, /* N/A */
+			{ 0x1b, 0x411111f0 }, /* N/A */
+			{ 0x1c, 0x411111f0 }, /* N/A */
+			{ 0x1d, 0x411111f0 }, /* N/A */
+			{ 0x1e, 0x01454140 }, /* SPDIF out */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_VOL_KNOB,
+	},
+	[ALC880_FIXUP_F1734] = {
+		/* almost compatible with FUJITSU, but no bass and SPDIF */
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			{ 0x14, 0x0121411f }, /* HP */
+			{ 0x15, 0x99030120 }, /* speaker */
+			{ 0x16, 0x411111f0 }, /* N/A */
+			{ 0x17, 0x411111f0 }, /* N/A */
+			{ 0x18, 0x411111f0 }, /* N/A */
+			{ 0x19, 0x01a19950 }, /* mic-in */
+			{ 0x1a, 0x411111f0 }, /* N/A */
+			{ 0x1b, 0x411111f0 }, /* N/A */
+			{ 0x1c, 0x411111f0 }, /* N/A */
+			{ 0x1d, 0x411111f0 }, /* N/A */
+			{ 0x1e, 0x411111f0 }, /* N/A */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_VOL_KNOB,
+	},
+	[ALC880_FIXUP_UNIWILL] = {
+		/* need to fix HP and speaker pins to be parsed correctly */
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			{ 0x14, 0x0121411f }, /* HP */
+			{ 0x15, 0x99030120 }, /* speaker */
+			{ 0x16, 0x99030130 }, /* bass speaker */
+			{ }
+		},
+	},
+	[ALC880_FIXUP_UNIWILL_DIG] = {
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			/* disable bogus unused pins */
+			{ 0x17, 0x411111f0 },
+			{ 0x19, 0x411111f0 },
+			{ 0x1b, 0x411111f0 },
+			{ 0x1f, 0x411111f0 },
+			{ }
+		}
+	},
+	[ALC880_FIXUP_Z71V] = {
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			/* set up the whole pins as BIOS is utterly broken */
+			{ 0x14, 0x99030120 }, /* speaker */
+			{ 0x15, 0x0121411f }, /* HP */
+			{ 0x16, 0x411111f0 }, /* N/A */
+			{ 0x17, 0x411111f0 }, /* N/A */
+			{ 0x18, 0x01a19950 }, /* mic-in */
+			{ 0x19, 0x411111f0 }, /* N/A */
+			{ 0x1a, 0x01813031 }, /* line-in */
+			{ 0x1b, 0x411111f0 }, /* N/A */
+			{ 0x1c, 0x411111f0 }, /* N/A */
+			{ 0x1d, 0x411111f0 }, /* N/A */
+			{ 0x1e, 0x0144111e }, /* SPDIF */
+			{ }
+		}
+	},
+	[ALC880_FIXUP_3ST_BASE] = {
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			{ 0x14, 0x01014010 }, /* line-out */
+			{ 0x15, 0x411111f0 }, /* N/A */
+			{ 0x16, 0x411111f0 }, /* N/A */
+			{ 0x17, 0x411111f0 }, /* N/A */
+			{ 0x18, 0x01a19c30 }, /* mic-in */
+			{ 0x19, 0x0121411f }, /* HP */
+			{ 0x1a, 0x01813031 }, /* line-in */
+			{ 0x1b, 0x02a19c40 }, /* front-mic */
+			{ 0x1c, 0x411111f0 }, /* N/A */
+			{ 0x1d, 0x411111f0 }, /* N/A */
+			/* 0x1e is filled in below */
+			{ 0x1f, 0x411111f0 }, /* N/A */
+			{ }
+		}
+	},
+	[ALC880_FIXUP_3ST] = {
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			{ 0x1e, 0x411111f0 }, /* N/A */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_3ST_BASE,
+	},
+	[ALC880_FIXUP_3ST_DIG] = {
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			{ 0x1e, 0x0144111e }, /* SPDIF */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_3ST_BASE,
+	},
+	[ALC880_FIXUP_5ST_BASE] = {
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			{ 0x14, 0x01014010 }, /* front */
+			{ 0x15, 0x411111f0 }, /* N/A */
+			{ 0x16, 0x01011411 }, /* CLFE */
+			{ 0x17, 0x01016412 }, /* surr */
+			{ 0x18, 0x01a19c30 }, /* mic-in */
+			{ 0x19, 0x0121411f }, /* HP */
+			{ 0x1a, 0x01813031 }, /* line-in */
+			{ 0x1b, 0x02a19c40 }, /* front-mic */
+			{ 0x1c, 0x411111f0 }, /* N/A */
+			{ 0x1d, 0x411111f0 }, /* N/A */
+			/* 0x1e is filled in below */
+			{ 0x1f, 0x411111f0 }, /* N/A */
+			{ }
+		}
+	},
+	[ALC880_FIXUP_5ST] = {
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			{ 0x1e, 0x411111f0 }, /* N/A */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_5ST_BASE,
+	},
+	[ALC880_FIXUP_5ST_DIG] = {
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			{ 0x1e, 0x0144111e }, /* SPDIF */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_5ST_BASE,
+	},
+	[ALC880_FIXUP_6ST_BASE] = {
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			{ 0x14, 0x01014010 }, /* front */
+			{ 0x15, 0x01016412 }, /* surr */
+			{ 0x16, 0x01011411 }, /* CLFE */
+			{ 0x17, 0x01012414 }, /* side */
+			{ 0x18, 0x01a19c30 }, /* mic-in */
+			{ 0x19, 0x02a19c40 }, /* front-mic */
+			{ 0x1a, 0x01813031 }, /* line-in */
+			{ 0x1b, 0x0121411f }, /* HP */
+			{ 0x1c, 0x411111f0 }, /* N/A */
+			{ 0x1d, 0x411111f0 }, /* N/A */
+			/* 0x1e is filled in below */
+			{ 0x1f, 0x411111f0 }, /* N/A */
+			{ }
+		}
+	},
+	[ALC880_FIXUP_6ST] = {
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			{ 0x1e, 0x411111f0 }, /* N/A */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_6ST_BASE,
+	},
+	[ALC880_FIXUP_6ST_DIG] = {
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			{ 0x1e, 0x0144111e }, /* SPDIF */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_6ST_BASE,
+	},
 };
 
 static const struct snd_pci_quirk alc880_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810),
+	SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V),
+	SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1),
+	SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2),
+	SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF),
+	SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG),
+	SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734),
+	SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL),
+	SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB),
+	SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810),
 	SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
+	SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_FIXUP_F1734),
+	SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU),
+	SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734),
+	SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU),
+	SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG),
+	SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG),
+	SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG),
+	SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700),
+
+	/* Below is the copied entries from alc880_quirks.c.
+	 * It's not quite sure whether BIOS sets the correct pin-config table
+	 * on these machines, thus they are kept to be compatible with
+	 * the old static quirks.  Once when it's confirmed to work without
+	 * these overrides, it'd be better to remove.
+	 */
+	SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST),
+	SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG),
+	SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG),
+	SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST),
+	SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST),
+	SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST),
+	SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST),
+	SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST),
+	SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST),
+	SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */
+	SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+	/* default Intel */
+	SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST),
+	SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG),
+	{}
+};
+
+static const struct alc_model_fixup alc880_fixup_models[] = {
+	{.id = ALC880_FIXUP_3ST, .name = "3stack"},
+	{.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"},
+	{.id = ALC880_FIXUP_5ST, .name = "5stack"},
+	{.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"},
+	{.id = ALC880_FIXUP_6ST, .name = "6stack"},
+	{.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"},
 	{}
 };
 
 
 /*
- * board setups
- */
-#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
-#define alc_board_config \
-	snd_hda_check_board_config
-#define alc_board_codec_sid_config \
-	snd_hda_check_board_codec_sid_config
-#include "alc_quirks.c"
-#else
-#define alc_board_config(codec, nums, models, tbl)	-1
-#define alc_board_codec_sid_config(codec, nums, models, tbl)	-1
-#define setup_preset(codec, x)	/* NOP */
-#endif
-
-/*
  * OK, here we have finally the patch for ALC880
  */
-#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
-#include "alc880_quirks.c"
-#endif
-
 static int patch_alc880(struct hda_codec *codec)
 {
 	struct alc_spec *spec;
-	int board_config;
 	int err;
 
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
@@ -4146,47 +4810,14 @@
 	spec->mixer_nid = 0x0b;
 	spec->need_dac_fix = 1;
 
-	board_config = alc_board_config(codec, ALC880_MODEL_LAST,
-					alc880_models, alc880_cfg_tbl);
-	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-		       codec->chip_name);
-		board_config = ALC_MODEL_AUTO;
-	}
+	alc_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
+		       alc880_fixups);
+	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
 
-	if (board_config == ALC_MODEL_AUTO) {
-		alc_pick_fixup(codec, NULL, alc880_fixup_tbl, alc880_fixups);
-		alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
-	}
-
-	if (board_config == ALC_MODEL_AUTO) {
-		/* automatic parse from the BIOS config */
-		err = alc880_parse_auto_config(codec);
-		if (err < 0)
-			goto error;
-#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
-		else if (!err) {
-			printk(KERN_INFO
-			       "hda_codec: Cannot set up configuration "
-			       "from BIOS.  Using 3-stack mode...\n");
-			board_config = ALC880_3ST;
-		}
-#endif
-	}
-
-	if (board_config != ALC_MODEL_AUTO) {
-		spec->vmaster_nid = 0x0c;
-		setup_preset(codec, &alc880_presets[board_config]);
-	}
-
-	if (!spec->no_analog && !spec->adc_nids) {
-		alc_auto_fill_adc_caps(codec);
-		alc_rebuild_imux_for_auto_mic(codec);
-		alc_remove_invalid_adc_nids(codec);
-	}
-
-	if (!spec->no_analog && !spec->cap_mixer)
-		set_capture_mixer(codec);
+	/* automatic parse from the BIOS config */
+	err = alc880_parse_auto_config(codec);
+	if (err < 0)
+		goto error;
 
 	if (!spec->no_analog) {
 		err = snd_hda_attach_beep_device(codec, 0x1);
@@ -4195,17 +4826,9 @@
 		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 	}
 
-	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
 	codec->patch_ops = alc_patch_ops;
-	if (board_config == ALC_MODEL_AUTO)
-		spec->init_hook = alc_auto_init_std;
-	else
-		codec->patch_ops.build_controls = __alc_build_controls;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-	if (!spec->loopback.amplist)
-		spec->loopback.amplist = alc880_loopbacks;
-#endif
+
+	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
 	return 0;
 
@@ -4225,49 +4848,115 @@
 	return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list alc260_loopbacks[] = {
-	{ 0x07, HDA_INPUT, 0 },
-	{ 0x07, HDA_INPUT, 1 },
-	{ 0x07, HDA_INPUT, 2 },
-	{ 0x07, HDA_INPUT, 3 },
-	{ 0x07, HDA_INPUT, 4 },
-	{ } /* end */
-};
-#endif
-
 /*
  * Pin config fixes
  */
 enum {
-	PINFIX_HP_DC5750,
+	ALC260_FIXUP_HP_DC5750,
+	ALC260_FIXUP_HP_PIN_0F,
+	ALC260_FIXUP_COEF,
+	ALC260_FIXUP_GPIO1,
+	ALC260_FIXUP_GPIO1_TOGGLE,
+	ALC260_FIXUP_REPLACER,
+	ALC260_FIXUP_HP_B1900,
 };
 
+static void alc260_gpio1_automute(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+			    spec->hp_jack_present);
+}
+
+static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
+				      const struct alc_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	if (action == ALC_FIXUP_ACT_PROBE) {
+		/* although the machine has only one output pin, we need to
+		 * toggle GPIO1 according to the jack state
+		 */
+		spec->automute_hook = alc260_gpio1_automute;
+		spec->detect_hp = 1;
+		spec->automute_speaker = 1;
+		spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
+		snd_hda_jack_detect_enable(codec, 0x0f, ALC_HP_EVENT);
+		spec->unsol_event = alc_sku_unsol_event;
+		add_verb(codec->spec, alc_gpio1_init_verbs);
+	}
+}
+
 static const struct alc_fixup alc260_fixups[] = {
-	[PINFIX_HP_DC5750] = {
+	[ALC260_FIXUP_HP_DC5750] = {
 		.type = ALC_FIXUP_PINS,
 		.v.pins = (const struct alc_pincfg[]) {
 			{ 0x11, 0x90130110 }, /* speaker */
 			{ }
 		}
 	},
+	[ALC260_FIXUP_HP_PIN_0F] = {
+		.type = ALC_FIXUP_PINS,
+		.v.pins = (const struct alc_pincfg[]) {
+			{ 0x0f, 0x01214000 }, /* HP */
+			{ }
+		}
+	},
+	[ALC260_FIXUP_COEF] = {
+		.type = ALC_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3040 },
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC260_FIXUP_HP_PIN_0F,
+	},
+	[ALC260_FIXUP_GPIO1] = {
+		.type = ALC_FIXUP_VERBS,
+		.v.verbs = alc_gpio1_init_verbs,
+	},
+	[ALC260_FIXUP_GPIO1_TOGGLE] = {
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc260_fixup_gpio1_toggle,
+		.chained = true,
+		.chain_id = ALC260_FIXUP_HP_PIN_0F,
+	},
+	[ALC260_FIXUP_REPLACER] = {
+		.type = ALC_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3050 },
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC260_FIXUP_GPIO1_TOGGLE,
+	},
+	[ALC260_FIXUP_HP_B1900] = {
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc260_fixup_gpio1_toggle,
+		.chained = true,
+		.chain_id = ALC260_FIXUP_COEF,
+	}
 };
 
 static const struct snd_pci_quirk alc260_fixup_tbl[] = {
-	SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
+	SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1),
+	SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF),
+	SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1),
+	SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750),
+	SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900),
+	SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1),
+	SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER),
+	SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF),
 	{}
 };
 
 /*
  */
-#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
-#include "alc260_quirks.c"
-#endif
-
 static int patch_alc260(struct hda_codec *codec)
 {
 	struct alc_spec *spec;
-	int err, board_config;
+	int err;
 
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
@@ -4277,47 +4966,13 @@
 
 	spec->mixer_nid = 0x07;
 
-	board_config = alc_board_config(codec, ALC260_MODEL_LAST,
-					alc260_models, alc260_cfg_tbl);
-	if (board_config < 0) {
-		snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-			   codec->chip_name);
-		board_config = ALC_MODEL_AUTO;
-	}
+	alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
+	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
 
-	if (board_config == ALC_MODEL_AUTO) {
-		alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
-		alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
-	}
-
-	if (board_config == ALC_MODEL_AUTO) {
-		/* automatic parse from the BIOS config */
-		err = alc260_parse_auto_config(codec);
-		if (err < 0)
-			goto error;
-#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
-		else if (!err) {
-			printk(KERN_INFO
-			       "hda_codec: Cannot set up configuration "
-			       "from BIOS.  Using base mode...\n");
-			board_config = ALC260_BASIC;
-		}
-#endif
-	}
-
-	if (board_config != ALC_MODEL_AUTO) {
-		setup_preset(codec, &alc260_presets[board_config]);
-		spec->vmaster_nid = 0x08;
-	}
-
-	if (!spec->no_analog && !spec->adc_nids) {
-		alc_auto_fill_adc_caps(codec);
-		alc_rebuild_imux_for_auto_mic(codec);
-		alc_remove_invalid_adc_nids(codec);
-	}
-
-	if (!spec->no_analog && !spec->cap_mixer)
-		set_capture_mixer(codec);
+	/* automatic parse from the BIOS config */
+	err = alc260_parse_auto_config(codec);
+	if (err < 0)
+		goto error;
 
 	if (!spec->no_analog) {
 		err = snd_hda_attach_beep_device(codec, 0x1);
@@ -4326,18 +4981,10 @@
 		set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
 	}
 
-	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
 	codec->patch_ops = alc_patch_ops;
-	if (board_config == ALC_MODEL_AUTO)
-		spec->init_hook = alc_auto_init_std;
-	else
-		codec->patch_ops.build_controls = __alc_build_controls;
 	spec->shutup = alc_eapd_shutup;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-	if (!spec->loopback.amplist)
-		spec->loopback.amplist = alc260_loopbacks;
-#endif
+
+	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
 	return 0;
 
@@ -4358,9 +5005,6 @@
  * In addition, an independent DAC for the multi-playback (not used in this
  * driver yet).
  */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc882_loopbacks	alc880_loopbacks
-#endif
 
 /*
  * Pin config fixes
@@ -4377,6 +5021,8 @@
 	ALC882_FIXUP_EAPD,
 	ALC883_FIXUP_EAPD,
 	ALC883_FIXUP_ACER_EAPD,
+	ALC882_FIXUP_GPIO1,
+	ALC882_FIXUP_GPIO2,
 	ALC882_FIXUP_GPIO3,
 	ALC889_FIXUP_COEF,
 	ALC882_FIXUP_ASUS_W2JC,
@@ -4385,6 +5031,8 @@
 	ALC882_FIXUP_ASPIRE_8930G_VERBS,
 	ALC885_FIXUP_MACPRO_GPIO,
 	ALC889_FIXUP_DAC_ROUTE,
+	ALC889_FIXUP_MBP_VREF,
+	ALC889_FIXUP_IMAC91_VREF,
 };
 
 static void alc889_fixup_coef(struct hda_codec *codec,
@@ -4463,6 +5111,51 @@
 	}
 }
 
+/* Set VREF on HP pin */
+static void alc889_fixup_mbp_vref(struct hda_codec *codec,
+				  const struct alc_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	static hda_nid_t nids[2] = { 0x14, 0x15 };
+	int i;
+
+	if (action != ALC_FIXUP_ACT_INIT)
+		return;
+	for (i = 0; i < ARRAY_SIZE(nids); i++) {
+		unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]);
+		if (get_defcfg_device(val) != AC_JACK_HP_OUT)
+			continue;
+		val = snd_hda_codec_read(codec, nids[i], 0,
+					 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+		val |= AC_PINCTL_VREF_80;
+		snd_hda_codec_write(codec, nids[i], 0,
+				    AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+		spec->keep_vref_in_automute = 1;
+		break;
+	}
+}
+
+/* Set VREF on speaker pins on imac91 */
+static void alc889_fixup_imac91_vref(struct hda_codec *codec,
+				     const struct alc_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	static hda_nid_t nids[2] = { 0x18, 0x1a };
+	int i;
+
+	if (action != ALC_FIXUP_ACT_INIT)
+		return;
+	for (i = 0; i < ARRAY_SIZE(nids); i++) {
+		unsigned int val;
+		val = snd_hda_codec_read(codec, nids[i], 0,
+					 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+		val |= AC_PINCTL_VREF_50;
+		snd_hda_codec_write(codec, nids[i], 0,
+				    AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+	}
+	spec->keep_vref_in_automute = 1;
+}
+
 static const struct alc_fixup alc882_fixups[] = {
 	[ALC882_FIXUP_ABIT_AW9D_MAX] = {
 		.type = ALC_FIXUP_PINS,
@@ -4548,6 +5241,14 @@
 			{ }
 		}
 	},
+	[ALC882_FIXUP_GPIO1] = {
+		.type = ALC_FIXUP_VERBS,
+		.v.verbs = alc_gpio1_init_verbs,
+	},
+	[ALC882_FIXUP_GPIO2] = {
+		.type = ALC_FIXUP_VERBS,
+		.v.verbs = alc_gpio2_init_verbs,
+	},
 	[ALC882_FIXUP_GPIO3] = {
 		.type = ALC_FIXUP_VERBS,
 		.v.verbs = alc_gpio3_init_verbs,
@@ -4621,6 +5322,18 @@
 		.type = ALC_FIXUP_FUNC,
 		.v.func = alc889_fixup_dac_route,
 	},
+	[ALC889_FIXUP_MBP_VREF] = {
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc889_fixup_mbp_vref,
+		.chained = true,
+		.chain_id = ALC882_FIXUP_GPIO1,
+	},
+	[ALC889_FIXUP_IMAC91_VREF] = {
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc889_fixup_imac91_vref,
+		.chained = true,
+		.chain_id = ALC882_FIXUP_GPIO1,
+	},
 };
 
 static const struct snd_pci_quirk alc882_fixup_tbl[] = {
@@ -4654,11 +5367,26 @@
 	SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
 
 	/* All Apple entries are in codec SSIDs */
+	SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF),
+	SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF),
+	SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
 	SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_FIXUP_MACPRO_GPIO),
 	SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO),
 	SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO),
+	SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF),
+	SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF),
 	SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
+	SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBP_VREF),
+	SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBP_VREF),
+	SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF),
+	SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
 	SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO),
+	SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF),
+	SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF),
+	SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF),
+	SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF),
+	SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF),
+	SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_IMAC91_VREF),
 
 	SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
 	SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
@@ -4684,14 +5412,10 @@
 
 /*
  */
-#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
-#include "alc882_quirks.c"
-#endif
-
 static int patch_alc882(struct hda_codec *codec)
 {
 	struct alc_spec *spec;
-	int err, board_config;
+	int err;
 
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
@@ -4715,45 +5439,15 @@
 	if (err < 0)
 		goto error;
 
-	board_config = alc_board_config(codec, ALC882_MODEL_LAST,
-					alc882_models, NULL);
-	if (board_config < 0)
-		board_config = alc_board_codec_sid_config(codec,
-			ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
-
-	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-		       codec->chip_name);
-		board_config = ALC_MODEL_AUTO;
-	}
-
-	if (board_config == ALC_MODEL_AUTO) {
-		alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
-		alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
-	}
+	alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
+	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
 
 	alc_auto_parse_customize_define(codec);
 
-	if (board_config == ALC_MODEL_AUTO) {
-		/* automatic parse from the BIOS config */
-		err = alc882_parse_auto_config(codec);
-		if (err < 0)
-			goto error;
-	}
-
-	if (board_config != ALC_MODEL_AUTO) {
-		setup_preset(codec, &alc882_presets[board_config]);
-		spec->vmaster_nid = 0x0c;
-	}
-
-	if (!spec->no_analog && !spec->adc_nids) {
-		alc_auto_fill_adc_caps(codec);
-		alc_rebuild_imux_for_auto_mic(codec);
-		alc_remove_invalid_adc_nids(codec);
-	}
-
-	if (!spec->no_analog && !spec->cap_mixer)
-		set_capture_mixer(codec);
+	/* automatic parse from the BIOS config */
+	err = alc882_parse_auto_config(codec);
+	if (err < 0)
+		goto error;
 
 	if (!spec->no_analog && has_cdefine_beep(codec)) {
 		err = snd_hda_attach_beep_device(codec, 0x1);
@@ -4762,18 +5456,9 @@
 		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 	}
 
-	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
 	codec->patch_ops = alc_patch_ops;
-	if (board_config == ALC_MODEL_AUTO)
-		spec->init_hook = alc_auto_init_std;
-	else
-		codec->patch_ops.build_controls = __alc_build_controls;
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-	if (!spec->loopback.amplist)
-		spec->loopback.amplist = alc882_loopbacks;
-#endif
+	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
 	return 0;
 
@@ -4869,10 +5554,6 @@
 };
 
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc262_loopbacks	alc880_loopbacks
-#endif
-
 /*
  */
 static int patch_alc262(struct hda_codec *codec)
@@ -4912,15 +5593,6 @@
 	if (err < 0)
 		goto error;
 
-	if (!spec->no_analog && !spec->adc_nids) {
-		alc_auto_fill_adc_caps(codec);
-		alc_rebuild_imux_for_auto_mic(codec);
-		alc_remove_invalid_adc_nids(codec);
-	}
-
-	if (!spec->no_analog && !spec->cap_mixer)
-		set_capture_mixer(codec);
-
 	if (!spec->no_analog && has_cdefine_beep(codec)) {
 		err = snd_hda_attach_beep_device(codec, 0x1);
 		if (err < 0)
@@ -4928,16 +5600,10 @@
 		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 	}
 
-	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
 	codec->patch_ops = alc_patch_ops;
-	spec->init_hook = alc_auto_init_std;
 	spec->shutup = alc_eapd_shutup;
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-	if (!spec->loopback.amplist)
-		spec->loopback.amplist = alc262_loopbacks;
-#endif
+	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
 	return 0;
 
@@ -5031,17 +5697,7 @@
 					  (0 << AC_AMPCAP_MUTE_SHIFT));
 	}
 
-	if (!spec->no_analog && !spec->adc_nids) {
-		alc_auto_fill_adc_caps(codec);
-		alc_rebuild_imux_for_auto_mic(codec);
-		alc_remove_invalid_adc_nids(codec);
-	}
-
-	if (!spec->no_analog && !spec->cap_mixer)
-		set_capture_mixer(codec);
-
 	codec->patch_ops = alc_patch_ops;
-	spec->init_hook = alc_auto_init_std;
 	spec->shutup = alc_eapd_shutup;
 
 	return 0;
@@ -5054,10 +5710,6 @@
 /*
  * ALC269
  */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc269_loopbacks	alc880_loopbacks
-#endif
-
 static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
 	.substreams = 1,
 	.channels_min = 2,
@@ -5079,35 +5731,6 @@
 	/* NID is set in alc_build_pcms */
 };
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static int alc269_mic2_for_mute_led(struct hda_codec *codec)
-{
-	switch (codec->subsystem_id) {
-	case 0x103c1586:
-		return 1;
-	}
-	return 0;
-}
-
-static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
-{
-	/* update mute-LED according to the speaker mute state */
-	if (nid == 0x01 || nid == 0x14) {
-		int pinval;
-		if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
-		    HDA_AMP_MUTE)
-			pinval = 0x24;
-		else
-			pinval = 0x20;
-		/* mic2 vref pin is used for mute LED control */
-		snd_hda_codec_update_cache(codec, 0x19, 0,
-					   AC_VERB_SET_PIN_WIDGET_CONTROL,
-					   pinval);
-	}
-	return alc_check_power_status(codec, nid);
-}
-#endif /* CONFIG_SND_HDA_POWER_SAVE */
-
 /* different alc269-variants */
 enum {
 	ALC269_TYPE_ALC269VA,
@@ -5258,6 +5881,31 @@
 	spec->automute_hook = alc269_quanta_automute;
 }
 
+/* update mute-LED according to the speaker mute state via mic2 VREF pin */
+static void alc269_fixup_mic2_mute_hook(void *private_data, int enabled)
+{
+	struct hda_codec *codec = private_data;
+	unsigned int pinval = enabled ? 0x20 : 0x24;
+	snd_hda_codec_update_cache(codec, 0x19, 0,
+				   AC_VERB_SET_PIN_WIDGET_CONTROL,
+				   pinval);
+}
+
+static void alc269_fixup_mic2_mute(struct hda_codec *codec,
+				   const struct alc_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	switch (action) {
+	case ALC_FIXUP_ACT_BUILD:
+		spec->vmaster_mute.hook = alc269_fixup_mic2_mute_hook;
+		snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, true);
+		/* fallthru */
+	case ALC_FIXUP_ACT_INIT:
+		snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
+		break;
+	}
+}
+
 enum {
 	ALC269_FIXUP_SONY_VAIO,
 	ALC275_FIXUP_SONY_VAIO_GPIO2,
@@ -5275,6 +5923,7 @@
 	ALC269_FIXUP_DMIC,
 	ALC269VB_FIXUP_AMIC,
 	ALC269VB_FIXUP_DMIC,
+	ALC269_FIXUP_MIC2_MUTE_LED,
 };
 
 static const struct alc_fixup alc269_fixups[] = {
@@ -5395,9 +6044,14 @@
 			{ }
 		},
 	},
+	[ALC269_FIXUP_MIC2_MUTE_LED] = {
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc269_fixup_mic2_mute,
+	},
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED),
 	SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
 	SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
@@ -5420,7 +6074,7 @@
 	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K),
 	SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
 
-#if 1
+#if 0
 	/* Below is a quirk table taken from the old code.
 	 * Basically the device should work as is without the fixup table.
 	 * If BIOS doesn't give a proper info, enable the corresponding
@@ -5478,13 +6132,13 @@
 };
 
 
-static int alc269_fill_coef(struct hda_codec *codec)
+static void alc269_fill_coef(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	int val;
 
 	if (spec->codec_variant != ALC269_TYPE_ALC269VB)
-		return 0;
+		return;
 
 	if ((alc_get_coef0(codec) & 0x00ff) < 0x015) {
 		alc_write_coef_idx(codec, 0xf, 0x960b);
@@ -5520,8 +6174,6 @@
 
 	val = alc_read_coef_idx(codec, 0x4); /* HP */
 	alc_write_coef_idx(codec, 0x4, val | (1<<11));
-
-	return 0;
 }
 
 /*
@@ -5565,6 +6217,7 @@
 		}
 		if (err < 0)
 			goto error;
+		spec->init_hook = alc269_fill_coef;
 		alc269_fill_coef(codec);
 	}
 
@@ -5577,15 +6230,6 @@
 	if (err < 0)
 		goto error;
 
-	if (!spec->no_analog && !spec->adc_nids) {
-		alc_auto_fill_adc_caps(codec);
-		alc_rebuild_imux_for_auto_mic(codec);
-		alc_remove_invalid_adc_nids(codec);
-	}
-
-	if (!spec->no_analog && !spec->cap_mixer)
-		set_capture_mixer(codec);
-
 	if (!spec->no_analog && has_cdefine_beep(codec)) {
 		err = snd_hda_attach_beep_device(codec, 0x1);
 		if (err < 0)
@@ -5593,21 +6237,13 @@
 		set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
 	}
 
-	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
 	codec->patch_ops = alc_patch_ops;
 #ifdef CONFIG_PM
 	codec->patch_ops.resume = alc269_resume;
 #endif
-	spec->init_hook = alc_auto_init_std;
 	spec->shutup = alc269_shutup;
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-	if (!spec->loopback.amplist)
-		spec->loopback.amplist = alc269_loopbacks;
-	if (alc269_mic2_for_mute_led(codec))
-		codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
-#endif
+	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
 	return 0;
 
@@ -5627,21 +6263,12 @@
 	return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list alc861_loopbacks[] = {
-	{ 0x15, HDA_INPUT, 0 },
-	{ 0x15, HDA_INPUT, 1 },
-	{ 0x15, HDA_INPUT, 2 },
-	{ 0x15, HDA_INPUT, 3 },
-	{ } /* end */
-};
-#endif
-
-
 /* Pin config fixes */
 enum {
-	PINFIX_FSC_AMILO_PI1505,
-	PINFIX_ASUS_A6RP,
+	ALC861_FIXUP_FSC_AMILO_PI1505,
+	ALC861_FIXUP_AMP_VREF_0F,
+	ALC861_FIXUP_NO_JACK_DETECT,
+	ALC861_FIXUP_ASUS_A6RP,
 };
 
 /* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */
@@ -5663,8 +6290,16 @@
 	spec->keep_vref_in_automute = 1;
 }
 
+/* suppress the jack-detection */
+static void alc_fixup_no_jack_detect(struct hda_codec *codec,
+				     const struct alc_fixup *fix, int action)
+{
+	if (action == ALC_FIXUP_ACT_PRE_PROBE)
+		codec->no_jack_detect = 1;
+}	
+
 static const struct alc_fixup alc861_fixups[] = {
-	[PINFIX_FSC_AMILO_PI1505] = {
+	[ALC861_FIXUP_FSC_AMILO_PI1505] = {
 		.type = ALC_FIXUP_PINS,
 		.v.pins = (const struct alc_pincfg[]) {
 			{ 0x0b, 0x0221101f }, /* HP */
@@ -5672,17 +6307,29 @@
 			{ }
 		}
 	},
-	[PINFIX_ASUS_A6RP] = {
+	[ALC861_FIXUP_AMP_VREF_0F] = {
 		.type = ALC_FIXUP_FUNC,
 		.v.func = alc861_fixup_asus_amp_vref_0f,
 	},
+	[ALC861_FIXUP_NO_JACK_DETECT] = {
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc_fixup_no_jack_detect,
+	},
+	[ALC861_FIXUP_ASUS_A6RP] = {
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc861_fixup_asus_amp_vref_0f,
+		.chained = true,
+		.chain_id = ALC861_FIXUP_NO_JACK_DETECT,
+	}
 };
 
 static const struct snd_pci_quirk alc861_fixup_tbl[] = {
-	SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", PINFIX_ASUS_A6RP),
-	SND_PCI_QUIRK(0x1584, 0x0000, "Uniwill ECS M31EI", PINFIX_ASUS_A6RP),	
-	SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", PINFIX_ASUS_A6RP),
-	SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
+	SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP),
+	SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F),
+	SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT),
+	SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", ALC861_FIXUP_AMP_VREF_0F),
+	SND_PCI_QUIRK(0x1584, 0x0000, "Uniwill ECS M31EI", ALC861_FIXUP_AMP_VREF_0F),
+	SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505),
 	{}
 };
 
@@ -5709,15 +6356,6 @@
 	if (err < 0)
 		goto error;
 
-	if (!spec->no_analog && !spec->adc_nids) {
-		alc_auto_fill_adc_caps(codec);
-		alc_rebuild_imux_for_auto_mic(codec);
-		alc_remove_invalid_adc_nids(codec);
-	}
-
-	if (!spec->no_analog && !spec->cap_mixer)
-		set_capture_mixer(codec);
-
 	if (!spec->no_analog) {
 		err = snd_hda_attach_beep_device(codec, 0x23);
 		if (err < 0)
@@ -5725,16 +6363,13 @@
 		set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
 	}
 
-	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
 	codec->patch_ops = alc_patch_ops;
-	spec->init_hook = alc_auto_init_std;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	spec->power_hook = alc_power_eapd;
-	if (!spec->loopback.amplist)
-		spec->loopback.amplist = alc861_loopbacks;
 #endif
 
+	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
+
 	return 0;
 
  error:
@@ -5749,10 +6384,6 @@
  *
  * In addition, an independent DAC
  */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc861vd_loopbacks	alc880_loopbacks
-#endif
-
 static int alc861vd_parse_auto_config(struct hda_codec *codec)
 {
 	static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
@@ -5833,15 +6464,6 @@
 		add_verb(spec, alc660vd_eapd_verbs);
 	}
 
-	if (!spec->no_analog && !spec->adc_nids) {
-		alc_auto_fill_adc_caps(codec);
-		alc_rebuild_imux_for_auto_mic(codec);
-		alc_remove_invalid_adc_nids(codec);
-	}
-
-	if (!spec->no_analog && !spec->cap_mixer)
-		set_capture_mixer(codec);
-
 	if (!spec->no_analog) {
 		err = snd_hda_attach_beep_device(codec, 0x23);
 		if (err < 0)
@@ -5849,16 +6471,11 @@
 		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 	}
 
-	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
 	codec->patch_ops = alc_patch_ops;
 
-	spec->init_hook = alc_auto_init_std;
 	spec->shutup = alc_eapd_shutup;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-	if (!spec->loopback.amplist)
-		spec->loopback.amplist = alc861vd_loopbacks;
-#endif
+
+	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
 	return 0;
 
@@ -5878,9 +6495,6 @@
  * In addition, an independent DAC for the multi-playback (not used in this
  * driver yet).
  */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc662_loopbacks	alc880_loopbacks
-#endif
 
 /*
  * BIOS auto configuration
@@ -5930,6 +6544,7 @@
 	ALC662_FIXUP_ASUS_MODE6,
 	ALC662_FIXUP_ASUS_MODE7,
 	ALC662_FIXUP_ASUS_MODE8,
+	ALC662_FIXUP_NO_JACK_DETECT,
 };
 
 static const struct alc_fixup alc662_fixups[] = {
@@ -6075,6 +6690,10 @@
 		.chained = true,
 		.chain_id = ALC662_FIXUP_SKU_IGNORE
 	},
+	[ALC662_FIXUP_NO_JACK_DETECT] = {
+		.type = ALC_FIXUP_FUNC,
+		.v.func = alc_fixup_no_jack_detect,
+	},
 };
 
 static const struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -6083,6 +6702,7 @@
 	SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
 	SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
 	SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
+	SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
 	SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
 	SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
 	SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
@@ -6204,15 +6824,6 @@
 	if (err < 0)
 		goto error;
 
-	if (!spec->no_analog && !spec->adc_nids) {
-		alc_auto_fill_adc_caps(codec);
-		alc_rebuild_imux_for_auto_mic(codec);
-		alc_remove_invalid_adc_nids(codec);
-	}
-
-	if (!spec->no_analog && !spec->cap_mixer)
-		set_capture_mixer(codec);
-
 	if (!spec->no_analog && has_cdefine_beep(codec)) {
 		err = snd_hda_attach_beep_device(codec, 0x1);
 		if (err < 0)
@@ -6232,16 +6843,10 @@
 		}
 	}
 
-	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
 	codec->patch_ops = alc_patch_ops;
-	spec->init_hook = alc_auto_init_std;
 	spec->shutup = alc_eapd_shutup;
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-	if (!spec->loopback.amplist)
-		spec->loopback.amplist = alc662_loopbacks;
-#endif
+	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
 	return 0;
 
@@ -6281,11 +6886,7 @@
 		return err;
 	}
 
-	if (!spec->no_analog && !spec->cap_mixer)
-		set_capture_mixer(codec);
-
 	codec->patch_ops = alc_patch_ops;
-	spec->init_hook = alc_auto_init_std;
 
 	return 0;
 }
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 9dbb573..33a9946 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -99,6 +99,7 @@
 	STAC_DELL_VOSTRO_3500,
 	STAC_92HD83XXX_HP_cNB11_INTQUAD,
 	STAC_HP_DV7_4000,
+	STAC_HP_ZEPHYR,
 	STAC_92HD83XXX_MODELS
 };
 
@@ -309,6 +310,8 @@
 	unsigned long auto_capvols[MAX_ADCS_NUM];
 	unsigned auto_dmic_cnt;
 	hda_nid_t auto_dmic_nids[MAX_DMICS_NUM];
+
+	struct hda_vmaster_mute_hook vmaster_mute;
 };
 
 static const hda_nid_t stac9200_adc_nids[1] = {
@@ -662,7 +665,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
 static int stac_vrefout_set(struct hda_codec *codec,
 					hda_nid_t nid, unsigned int new_vref)
 {
@@ -686,7 +688,6 @@
 
 	return 1;
 }
-#endif
 
 static unsigned int stac92xx_vref_set(struct hda_codec *codec,
 					hda_nid_t nid, unsigned int new_vref)
@@ -894,6 +895,13 @@
 	{}
 };
 
+static const struct hda_verb stac92hd83xxx_hp_zephyr_init[] = {
+	{ 0x22, 0x785, 0x43 },
+	{ 0x22, 0x782, 0xe0 },
+	{ 0x22, 0x795, 0x00 },
+	{}
+};
+
 static const struct hda_verb stac92hd71bxx_core_init[] = {
 	/* set master volume and direct control */
 	{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
@@ -999,8 +1007,8 @@
 	}
 
 static const struct snd_kcontrol_new stac9200_mixer[] = {
-	HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xb, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0xb, 0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
 	{ } /* end */
@@ -1027,8 +1035,8 @@
 };
 
 static const struct snd_kcontrol_new stac925x_mixer[] = {
-	HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xe, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x0e, 0, HDA_OUTPUT),
 	{ } /* end */
 };
 
@@ -1060,34 +1068,25 @@
 	.put = stac92xx_smux_enum_put,
 };
 
-static const char * const slave_vols[] = {
-	"Front Playback Volume",
-	"Surround Playback Volume",
-	"Center Playback Volume",
-	"LFE Playback Volume",
-	"Side Playback Volume",
-	"Headphone Playback Volume",
-	"Speaker Playback Volume",
+static const char * const slave_pfxs[] = {
+	"Front", "Surround", "Center", "LFE", "Side",
+	"Headphone", "Speaker", "IEC958",
 	NULL
 };
 
-static const char * const slave_sws[] = {
-	"Front Playback Switch",
-	"Surround Playback Switch",
-	"Center Playback Switch",
-	"LFE Playback Switch",
-	"Side Playback Switch",
-	"Headphone Playback Switch",
-	"Speaker Playback Switch",
-	"IEC958 Playback Switch",
-	NULL
-};
+static void stac92xx_update_led_status(struct hda_codec *codec, int enabled);
+
+static void stac92xx_vmaster_hook(void *private_data, int val)
+{
+	stac92xx_update_led_status(private_data, val);
+}
 
 static void stac92xx_free_kctls(struct hda_codec *codec);
 
 static int stac92xx_build_controls(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
+	unsigned int vmaster_tlv[4];
 	int err;
 	int i;
 
@@ -1144,22 +1143,28 @@
 	}
 
 	/* 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->multiout.dac_nids[0],
-					HDA_OUTPUT, vmaster_tlv);
-		/* correct volume offset */
-		vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
-		/* minimum value is actually mute */
-		vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
-		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
-					  vmaster_tlv, slave_vols);
-		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, slave_sws);
+	snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
+				HDA_OUTPUT, vmaster_tlv);
+	/* correct volume offset */
+	vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
+	/* minimum value is actually mute */
+	vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
+	err = snd_hda_add_vmaster(codec, "Master Playback Volume",
+				  vmaster_tlv, slave_pfxs,
+				  "Playback Volume");
+	if (err < 0)
+		return err;
+
+	err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
+				    NULL, slave_pfxs,
+				    "Playback Switch", true,
+				    &spec->vmaster_mute.sw_kctl);
+	if (err < 0)
+		return err;
+
+	if (spec->gpio_led) {
+		spec->vmaster_mute.hook = stac92xx_vmaster_hook;
+		err = snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, true);
 		if (err < 0)
 			return err;
 	}
@@ -1636,6 +1641,12 @@
 	0x40f000f0, 0x40f000f0,
 };
 
+static const unsigned int hp_zephyr_pin_configs[10] = {
+	0x01813050, 0x0421201f, 0x04a1205e, 0x96130310,
+	0x96130310, 0x0101401f, 0x1111611f, 0xd5a30130,
+	0, 0,
+};
+
 static const unsigned int hp_cNB11_intquad_pin_configs[10] = {
 	0x40f000f0, 0x0221101f, 0x02a11020, 0x92170110,
 	0x40f000f0, 0x92170110, 0x40f000f0, 0xd5a30130,
@@ -1649,6 +1660,7 @@
 	[STAC_DELL_VOSTRO_3500] = dell_vostro_3500_pin_configs,
 	[STAC_92HD83XXX_HP_cNB11_INTQUAD] = hp_cNB11_intquad_pin_configs,
 	[STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs,
+	[STAC_HP_ZEPHYR] = hp_zephyr_pin_configs,
 };
 
 static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
@@ -1659,6 +1671,7 @@
 	[STAC_DELL_VOSTRO_3500] = "dell-vostro-3500",
 	[STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad",
 	[STAC_HP_DV7_4000] = "hp-dv7-4000",
+	[STAC_HP_ZEPHYR] = "hp-zephyr",
 };
 
 static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
@@ -1711,6 +1724,14 @@
 			  "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3593,
 			  "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3561,
+			  "HP", STAC_HP_ZEPHYR),
+	{} /* terminator */
+};
+
+static const struct snd_pci_quirk stac92hd83xxx_codec_id_cfg_tbl[] = {
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3561,
+			  "HP", STAC_HP_ZEPHYR),
 	{} /* terminator */
 };
 
@@ -4410,8 +4431,7 @@
 	snd_hda_jack_report_sync(codec);
 
 	/* sync mute LED */
-	if (spec->gpio_led)
-		hda_call_check_power_status(codec, 0x01);
+	snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
 	if (spec->dac_list)
 		stac92xx_power_down(codec);
 	return 0;
@@ -4989,7 +5009,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
 static int stac92xx_pre_resume(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
@@ -5024,83 +5043,41 @@
 			afg_power_state);
 	snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
 }
+#else
+#define stac92xx_suspend	NULL
+#define stac92xx_resume		NULL
+#define stac92xx_pre_resume	NULL
+#define stac92xx_set_power_state NULL
+#endif /* CONFIG_PM */
 
-/*
- * For this feature CONFIG_SND_HDA_POWER_SAVE is needed
- * as mute LED state is updated in check_power_status hook
- */
-static int stac92xx_update_led_status(struct hda_codec *codec)
+/* update mute-LED accoring to the master switch */
+static void stac92xx_update_led_status(struct hda_codec *codec, int enabled)
 {
 	struct sigmatel_spec *spec = codec->spec;
-	int i, num_ext_dacs, muted = 1;
-	unsigned int muted_lvl, notmtd_lvl;
-	hda_nid_t nid;
+	int muted = !enabled;
 
 	if (!spec->gpio_led)
-		return 0;
+		return;
 
-	for (i = 0; i < spec->multiout.num_dacs; i++) {
-		nid = spec->multiout.dac_nids[i];
-		if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
-		      HDA_AMP_MUTE)) {
-			muted = 0; /* something heard */
-			break;
-		}
-	}
-	if (muted && spec->multiout.hp_nid)
-		if (!(snd_hda_codec_amp_read(codec,
-				spec->multiout.hp_nid, 0, HDA_OUTPUT, 0) &
-					HDA_AMP_MUTE)) {
-			muted = 0; /* HP is not muted */
-		}
-	num_ext_dacs = ARRAY_SIZE(spec->multiout.extra_out_nid);
-	for (i = 0; muted && i < num_ext_dacs; i++) {
-		nid = spec->multiout.extra_out_nid[i];
-		if (nid == 0)
-			break;
-		if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
-		      HDA_AMP_MUTE)) {
-			muted = 0; /* extra output is not muted */
-		}
-	}
+	/* LED state is inverted on these systems */
+	if (spec->gpio_led_polarity)
+		muted = !muted;
+
 	/*polarity defines *not* muted state level*/
 	if (!spec->vref_mute_led_nid) {
 		if (muted)
 			spec->gpio_data &= ~spec->gpio_led; /* orange */
 		else
 			spec->gpio_data |= spec->gpio_led; /* white */
-
-		if (!spec->gpio_led_polarity) {
-			/* LED state is inverted on these systems */
-			spec->gpio_data ^= spec->gpio_led;
-		}
 		stac_gpio_set(codec, spec->gpio_mask,
 				spec->gpio_dir, spec->gpio_data);
 	} else {
-		notmtd_lvl = spec->gpio_led_polarity ?
-				AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD;
-		muted_lvl = spec->gpio_led_polarity ?
-				AC_PINCTL_VREF_GRD : AC_PINCTL_VREF_50;
-		spec->vref_led = muted ? muted_lvl : notmtd_lvl;
+		spec->vref_led = muted ? AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD;
 		stac_vrefout_set(codec,	spec->vref_mute_led_nid,
 				 spec->vref_led);
 	}
-	return 0;
 }
 
-/*
- * use power check for controlling mute led of HP notebooks
- */
-static int stac92xx_check_power_status(struct hda_codec *codec,
-					      hda_nid_t nid)
-{
-	stac92xx_update_led_status(codec);
-
-	return 0;
-}
-#endif /* CONFIG_SND_HDA_POWER_SAVE */
-#endif /* CONFIG_PM */
-
 static const struct hda_codec_ops stac92xx_patch_ops = {
 	.build_controls = stac92xx_build_controls,
 	.build_pcms = stac92xx_build_pcms,
@@ -5580,6 +5557,12 @@
 							STAC_92HD83XXX_MODELS,
 							stac92hd83xxx_models,
 							stac92hd83xxx_cfg_tbl);
+	/* check codec subsystem id if not found */
+	if (spec->board_config < 0)
+		spec->board_config =
+			snd_hda_check_board_codec_sid_config(codec,
+				STAC_92HD83XXX_MODELS, stac92hd83xxx_models,
+				stac92hd83xxx_codec_id_cfg_tbl);
 again:
 	if (spec->board_config < 0)
 		snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
@@ -5590,12 +5573,17 @@
 
 	codec->patch_ops = stac92xx_patch_ops;
 
+	switch (spec->board_config) {
+	case STAC_HP_ZEPHYR:
+		spec->init = stac92hd83xxx_hp_zephyr_init;
+		break;
+	}
+
 	if (find_mute_led_cfg(codec, -1/*no default cfg*/))
 		snd_printd("mute LED gpio %d polarity %d\n",
 				spec->gpio_led,
 				spec->gpio_led_polarity);
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
 	if (spec->gpio_led) {
 		if (!spec->vref_mute_led_nid) {
 			spec->gpio_mask |= spec->gpio_led;
@@ -5605,11 +5593,10 @@
 			codec->patch_ops.set_power_state =
 					stac92xx_set_power_state;
 		}
+#ifdef CONFIG_PM
 		codec->patch_ops.pre_resume = stac92xx_pre_resume;
-		codec->patch_ops.check_power_status =
-			stac92xx_check_power_status;
+#endif
 	}
-#endif	
 
 	err = stac92xx_parse_auto_config(codec);
 	if (!err) {
@@ -5906,7 +5893,6 @@
 				spec->gpio_led,
 				spec->gpio_led_polarity);
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
 	if (spec->gpio_led) {
 		if (!spec->vref_mute_led_nid) {
 			spec->gpio_mask |= spec->gpio_led;
@@ -5916,11 +5902,10 @@
 			codec->patch_ops.set_power_state =
 					stac92xx_set_power_state;
 		}
+#ifdef CONFIG_PM
 		codec->patch_ops.pre_resume = stac92xx_pre_resume;
-		codec->patch_ops.check_power_status =
-			stac92xx_check_power_status;
+#endif
 	}
-#endif	
 
 	spec->multiout.dac_nids = spec->dac_nids;
 
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index dff9a00..06214fd 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -550,7 +550,10 @@
 	pin = path->path[path->depth - 1];
 
 	init_output_pin(codec, pin, pin_type);
-	caps = query_amp_caps(codec, pin, HDA_OUTPUT);
+	if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
+		caps = query_amp_caps(codec, pin, HDA_OUTPUT);
+	else
+		caps = 0;
 	if (caps & AC_AMPCAP_MUTE) {
 		unsigned int val;
 		val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
@@ -645,6 +648,10 @@
 
 	/* init ADCs */
 	for (i = 0; i < spec->num_adc_nids; i++) {
+		hda_nid_t nid = spec->adc_nids[i];
+		if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP) ||
+		    !(query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE))
+			continue;
 		snd_hda_codec_write(codec, spec->adc_nids[i], 0,
 				    AC_VERB_SET_AMP_GAIN_MUTE,
 				    AMP_IN_UNMUTE(0));
@@ -1445,25 +1452,9 @@
 /*
  * slave controls for virtual master
  */
-static const char * const via_slave_vols[] = {
-	"Front Playback Volume",
-	"Surround Playback Volume",
-	"Center Playback Volume",
-	"LFE Playback Volume",
-	"Side Playback Volume",
-	"Headphone Playback Volume",
-	"Speaker Playback Volume",
-	NULL,
-};
-
-static const char * const via_slave_sws[] = {
-	"Front Playback Switch",
-	"Surround Playback Switch",
-	"Center Playback Switch",
-	"LFE Playback Switch",
-	"Side Playback Switch",
-	"Headphone Playback Switch",
-	"Speaker Playback Switch",
+static const char * const via_slave_pfxs[] = {
+	"Front", "Surround", "Center", "LFE", "Side",
+	"Headphone", "Speaker",
 	NULL,
 };
 
@@ -1508,13 +1499,15 @@
 		snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
 					HDA_OUTPUT, vmaster_tlv);
 		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
-					  vmaster_tlv, via_slave_vols);
+					  vmaster_tlv, via_slave_pfxs,
+					  "Playback Volume");
 		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, via_slave_sws);
+					  NULL, via_slave_pfxs,
+					  "Playback Switch");
 		if (err < 0)
 			return err;
 	}
@@ -1522,6 +1515,8 @@
 	/* assign Capture Source enums to NID */
 	kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
 	for (i = 0; kctl && i < kctl->count; i++) {
+		if (!spec->mux_nids[i])
+			continue;
 		err = snd_hda_add_nid(codec, kctl, i, spec->mux_nids[i]);
 		if (err < 0)
 			return err;
@@ -2488,6 +2483,8 @@
 {
 	struct via_spec *spec = codec->spec;
 	const struct auto_pin_cfg *cfg = &spec->autocfg;
+	const char *prev_label = NULL;
+	int type_idx = 0;
 	int i, err;
 
 	for (i = 0; i < cfg->num_inputs; i++) {
@@ -2502,8 +2499,13 @@
 		if (caps == -1 || !(caps & AC_AMPCAP_NUM_STEPS))
 			continue;
 		label = hda_get_autocfg_input_label(codec, cfg, i);
+		if (prev_label && !strcmp(label, prev_label))
+			type_idx++;
+		else
+			type_idx = 0;
+		prev_label = label;
 		snprintf(name, sizeof(name), "%s Boost Volume", label);
-		err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+		err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, name, type_idx,
 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT));
 		if (err < 0)
 			return err;
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 9236297..812d10e 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -1013,6 +1013,25 @@
 					  ice->hw_rates);
 }
 
+/* if the card has the internal rate locked (is_pro_locked), limit runtime
+   hw rates to the current internal rate only.
+*/
+static void constrain_rate_if_locked(struct snd_pcm_substream *substream)
+{
+	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned int rate;
+	if (is_pro_rate_locked(ice)) {
+		rate = ice->get_rate(ice);
+		if (rate >= runtime->hw.rate_min
+		    && rate <= runtime->hw.rate_max) {
+			runtime->hw.rate_min = rate;
+			runtime->hw.rate_max = rate;
+		}
+	}
+}
+
+
 /* multi-channel playback needs alignment 8x32bit regardless of the channels
  * actually used
  */
@@ -1046,6 +1065,7 @@
 				   VT1724_BUFFER_ALIGN);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
 				   VT1724_BUFFER_ALIGN);
+	constrain_rate_if_locked(substream);
 	if (ice->pro_open)
 		ice->pro_open(ice, substream);
 	return 0;
@@ -1066,6 +1086,7 @@
 				   VT1724_BUFFER_ALIGN);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
 				   VT1724_BUFFER_ALIGN);
+	constrain_rate_if_locked(substream);
 	if (ice->pro_open)
 		ice->pro_open(ice, substream);
 	return 0;
@@ -1215,6 +1236,7 @@
 				   VT1724_BUFFER_ALIGN);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
 				   VT1724_BUFFER_ALIGN);
+	constrain_rate_if_locked(substream);
 	if (ice->spdif.ops.open)
 		ice->spdif.ops.open(ice, substream);
 	return 0;
@@ -1251,6 +1273,7 @@
 				   VT1724_BUFFER_ALIGN);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
 				   VT1724_BUFFER_ALIGN);
+	constrain_rate_if_locked(substream);
 	if (ice->spdif.ops.open)
 		ice->spdif.ops.open(ice, substream);
 	return 0;
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 12a9a2b..a8159b81 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -2317,6 +2317,10 @@
 	for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++)
 		chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]);
 	chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE);
+	pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY,
+			     &chip->saved_dsxg_legacy);
+	pci_read_config_word(chip->pci, PCIR_DSXG_ELEGACY,
+			     &chip->saved_dsxg_elegacy);
 	snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
 	snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0);
 	snd_ymfpci_disable_dsp(chip);
@@ -2351,6 +2355,11 @@
 
 	snd_ac97_resume(chip->ac97);
 
+	pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY,
+			      chip->saved_dsxg_legacy);
+	pci_write_config_word(chip->pci, PCIR_DSXG_ELEGACY,
+			      chip->saved_dsxg_elegacy);
+
 	/* start hw again */
 	if (chip->start_count > 0) {
 		spin_lock_irq(&chip->reg_lock);
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 35e662d..91c9855 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -25,6 +25,9 @@
 config SND_SOC_AC97_BUS
 	bool
 
+config SND_SOC_DMAENGINE_PCM
+	bool
+
 # All the supported SoCs
 source "sound/soc/atmel/Kconfig"
 source "sound/soc/au1x/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 9ea8ac8..2feaf37 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,6 +1,9 @@
 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-io.o
 
+snd-soc-dmaengine-pcm-objs := soc-dmaengine-pcm.o
+obj-$(CONFIG_SND_SOC_DMAENGINE_PCM) += snd-soc-dmaengine-pcm.o
+
 obj-$(CONFIG_SND_SOC)	+= snd-soc-core.o
 obj-$(CONFIG_SND_SOC)	+= codecs/
 obj-$(CONFIG_SND_SOC)	+= atmel/
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
index a21ff45..9b84f98 100644
--- a/sound/soc/atmel/atmel-pcm.c
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -362,7 +362,7 @@
 /*--------------------------------------------------------------------------*\
  * ASoC platform driver
 \*--------------------------------------------------------------------------*/
-static u64 atmel_pcm_dmamask = 0xffffffff;
+static u64 atmel_pcm_dmamask = DMA_BIT_MASK(32);
 
 static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
@@ -373,7 +373,7 @@
 	if (!card->dev->dma_mask)
 		card->dev->dma_mask = &atmel_pcm_dmamask;
 	if (!card->dev->coherent_dma_mask)
-		card->dev->coherent_dma_mask = 0xffffffff;
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
 	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
 		ret = atmel_pcm_preallocate_dma_buffer(pcm,
diff --git a/sound/soc/atmel/snd-soc-afeb9260.c b/sound/soc/atmel/snd-soc-afeb9260.c
index 4ca667d..f65f08b 100644
--- a/sound/soc/atmel/snd-soc-afeb9260.c
+++ b/sound/soc/atmel/snd-soc-afeb9260.c
@@ -46,29 +46,8 @@
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	int err;
 
-	/* Set codec DAI configuration */
-	err = snd_soc_dai_set_fmt(codec_dai,
-				  SND_SOC_DAIFMT_I2S|
-				  SND_SOC_DAIFMT_NB_IF |
-				  SND_SOC_DAIFMT_CBM_CFM);
-	if (err < 0) {
-		printk(KERN_ERR "can't set codec DAI configuration\n");
-		return err;
-	}
-
-	/* Set cpu DAI configuration */
-	err = snd_soc_dai_set_fmt(cpu_dai,
-				  SND_SOC_DAIFMT_I2S |
-				  SND_SOC_DAIFMT_NB_IF |
-				  SND_SOC_DAIFMT_CBM_CFM);
-	if (err < 0) {
-		printk(KERN_ERR "can't set cpu DAI configuration\n");
-		return err;
-	}
-
 	/* Set the codec system clock for DAC and ADC */
 	err =
 	    snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
@@ -91,7 +70,7 @@
 	SND_SOC_DAPM_MIC("Mic Jack", NULL),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route afeb9260_audio_map[] = {
 	{"Headphone Jack", NULL, "LHPOUT"},
 	{"Headphone Jack", NULL, "RHPOUT"},
 
@@ -106,13 +85,6 @@
 	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-	/* Add afeb9260 specific widgets */
-	snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
-				  ARRAY_SIZE(tlv320aic23_dapm_widgets));
-
-	/* Set up afeb9260 specific audio path audio_map */
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
 	snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
 	snd_soc_dapm_enable_pin(dapm, "Line In");
 	snd_soc_dapm_enable_pin(dapm, "Mic Jack");
@@ -129,6 +101,8 @@
 	.platform_name = "atmel_pcm-audio",
 	.codec_name = "tlv320aic23-codec.0-001a",
 	.init = afeb9260_tlv320aic23_init,
+	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
+		   SND_SOC_DAIFMT_CBM_CFM,
 	.ops = &afeb9260_ops,
 };
 
@@ -138,6 +112,11 @@
 	.owner = THIS_MODULE,
 	.dai_link = &afeb9260_dai,
 	.num_links = 1,
+
+	.dapm_widgets = tlv320aic23_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
+	.dapm_routes = afeb9260_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(afeb9260_audio_map),
 };
 
 static struct platform_device *afeb9260_snd_device;
diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c
index 60962ce..d542d40 100644
--- a/sound/soc/blackfin/bf5xx-ad1836.c
+++ b/sound/soc/blackfin/bf5xx-ad1836.c
@@ -40,20 +40,8 @@
 {
 	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 channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
 	int ret = 0;
-	/* set cpu DAI configuration */
-	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
-		SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
-	/* set codec DAI configuration */
-	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A |
-		SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
 
 	/* set cpu DAI channel mapping */
 	ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map),
@@ -68,6 +56,9 @@
 	.hw_params = bf5xx_ad1836_hw_params,
 };
 
+#define BF5XX_AD1836_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
+				SND_SOC_DAIFMT_CBM_CFM)
+
 static struct snd_soc_dai_link bf5xx_ad1836_dai[] = {
 	{
 		.name = "ad1836",
@@ -77,6 +68,7 @@
 		.platform_name = "bfin-tdm-pcm-audio",
 		.codec_name = "spi0.4",
 		.ops = &bf5xx_ad1836_ops,
+		.dai_fmt = BF5XX_AD1836_DAIFMT,
 	},
 	{
 		.name = "ad1836",
@@ -86,6 +78,7 @@
 		.platform_name = "bfin-tdm-pcm-audio",
 		.codec_name = "spi0.4",
 		.ops = &bf5xx_ad1836_ops,
+		.dai_fmt = BF5XX_AD1836_DAIFMT,
 	},
 };
 
diff --git a/sound/soc/blackfin/bf5xx-ad193x.c b/sound/soc/blackfin/bf5xx-ad193x.c
index 2d8d82d..0e55e9f 100644
--- a/sound/soc/blackfin/bf5xx-ad193x.c
+++ b/sound/soc/blackfin/bf5xx-ad193x.c
@@ -60,18 +60,6 @@
 		break;
 	}
 
-	/* set cpu DAI configuration */
-	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
-		SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
-	/* set codec DAI configuration */
-	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A |
-		SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
 	/* set the codec system clock for DAC and ADC */
 	ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
 		SND_SOC_CLOCK_IN);
@@ -92,6 +80,9 @@
 	return 0;
 }
 
+#define BF5XX_AD193X_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
+				SND_SOC_DAIFMT_CBM_CFM)
+
 static struct snd_soc_ops bf5xx_ad193x_ops = {
 	.hw_params = bf5xx_ad193x_hw_params,
 };
@@ -105,6 +96,7 @@
 		.platform_name = "bfin-tdm-pcm-audio",
 		.codec_name = "spi0.5",
 		.ops = &bf5xx_ad193x_ops,
+		.dai_fmt = BF5XX_AD193X_DAIFMT,
 	},
 	{
 		.name = "ad193x",
@@ -114,6 +106,7 @@
 		.platform_name = "bfin-tdm-pcm-audio",
 		.codec_name = "spi0.5",
 		.ops = &bf5xx_ad193x_ops,
+		.dai_fmt = BF5XX_AD193X_DAIFMT,
 	},
 };
 
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c
index 8e49508..61cc91d 100644
--- a/sound/soc/blackfin/bf5xx-ad73311.c
+++ b/sound/soc/blackfin/bf5xx-ad73311.c
@@ -145,29 +145,8 @@
 	return 0;
 }
 
-static int bf5xx_ad73311_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;
-	int ret = 0;
-
-	pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
-		params_format(params));
-
-	/* set cpu DAI configuration */
-	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
-		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-
-static struct snd_soc_ops bf5xx_ad73311_ops = {
-	.hw_params = bf5xx_ad73311_hw_params,
-};
+#define BF5XX_AD7311_DAI_FMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | \
+				SND_SOC_DAIFMT_CBM_CFM)
 
 static struct snd_soc_dai_link bf5xx_ad73311_dai[] = {
 	{
@@ -177,7 +156,7 @@
 		.codec_dai_name = "ad73311-hifi",
 		.platform_name = "bfin-i2s-pcm-audio",
 		.codec_name = "ad73311",
-		.ops = &bf5xx_ad73311_ops,
+		.dai_fmt = BF5XX_AD7311_DAI_FMT,
 	},
 	{
 		.name = "ad73311",
@@ -186,7 +165,7 @@
 		.codec_dai_name = "ad73311-hifi",
 		.platform_name = "bfin-i2s-pcm-audio",
 		.codec_name = "ad73311",
-		.ops = &bf5xx_ad73311_ops,
+		.dai_fmt = BF5XX_AD7311_DAI_FMT,
 	},
 };
 
diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c
index 0303032..df3ac73 100644
--- a/sound/soc/blackfin/bf5xx-ssm2602.c
+++ b/sound/soc/blackfin/bf5xx-ssm2602.c
@@ -49,7 +49,6 @@
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	unsigned int clk = 0;
 	int ret = 0;
 
@@ -75,21 +74,6 @@
 		break;
 	}
 
-	/*
-	 * CODEC is master for BCLK and LRC in this configuration.
-	 */
-
-	/* set codec DAI configuration */
-	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;
-	/* set cpu DAI configuration */
-	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_sysclk(codec_dai, SSM2602_SYSCLK, clk,
 		SND_SOC_CLOCK_IN);
 	if (ret < 0)
@@ -102,6 +86,10 @@
 	.hw_params = bf5xx_ssm2602_hw_params,
 };
 
+/* CODEC is master for BCLK and LRC in this configuration. */
+#define BF5XX_SSM2602_DAIFMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
+				SND_SOC_DAIFMT_CBM_CFM)
+
 static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = {
 	{
 		.name = "ssm2602",
diff --git a/sound/soc/blackfin/bfin-eval-adau1373.c b/sound/soc/blackfin/bfin-eval-adau1373.c
index 26b271c..f3adbdb 100644
--- a/sound/soc/blackfin/bfin-eval-adau1373.c
+++ b/sound/soc/blackfin/bfin-eval-adau1373.c
@@ -67,21 +67,10 @@
 	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;
 	int ret;
 	int pll_rate;
 
-	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret)
-		return ret;
-
-	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret)
-		return ret;
-
 	switch (params_rate(params)) {
 	case 48000:
 	case 8000:
@@ -143,6 +132,8 @@
 	.codec_name = "adau1373.0-001a",
 	.ops = &bfin_eval_adau1373_ops,
 	.init = bfin_eval_adau1373_codec_init,
+	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBM_CFM,
 };
 
 static struct snd_soc_card bfin_eval_adau1373 = {
diff --git a/sound/soc/blackfin/bfin-eval-adau1701.c b/sound/soc/blackfin/bfin-eval-adau1701.c
index c0064fa..b0531fc 100644
--- a/sound/soc/blackfin/bfin-eval-adau1701.c
+++ b/sound/soc/blackfin/bfin-eval-adau1701.c
@@ -37,20 +37,9 @@
 	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;
 	int 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)
-		return ret;
-
-	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret)
-		return ret;
-
 	ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1701_CLK_SRC_OSC, 12288000,
 			SND_SOC_CLOCK_IN);
 
@@ -61,6 +50,9 @@
 	.hw_params = bfin_eval_adau1701_hw_params,
 };
 
+#define BFIN_EVAL_ADAU1701_DAI_FMT (SND_SOC_DAIFMT_I2S | \
+				SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM)
+
 static struct snd_soc_dai_link bfin_eval_adau1701_dai[] = {
 	{
 		.name = "adau1701",
@@ -70,6 +62,7 @@
 		.platform_name = "bfin-i2s-pcm-audio",
 		.codec_name = "adau1701.0-0034",
 		.ops = &bfin_eval_adau1701_ops,
+		.dai_fmt = BFIN_EVAL_ADAU1701_DAI_FMT,
 	},
 	{
 		.name = "adau1701",
@@ -79,6 +72,7 @@
 		.platform_name = "bfin-i2s-pcm-audio",
 		.codec_name = "adau1701.0-0034",
 		.ops = &bfin_eval_adau1701_ops,
+		.dai_fmt = BFIN_EVAL_ADAU1701_DAI_FMT,
 	},
 };
 
diff --git a/sound/soc/blackfin/bfin-eval-adav80x.c b/sound/soc/blackfin/bfin-eval-adav80x.c
index 4ef079f..84b09987 100644
--- a/sound/soc/blackfin/bfin-eval-adav80x.c
+++ b/sound/soc/blackfin/bfin-eval-adav80x.c
@@ -34,20 +34,9 @@
 	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;
 	int 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)
-		return ret;
-
-	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret)
-		return ret;
-
 	ret = snd_soc_dai_set_pll(codec_dai, ADAV80X_PLL1, ADAV80X_PLL_SRC_XTAL,
 			27000000, params_rate(params) * 256);
 	if (ret)
@@ -88,6 +77,8 @@
 		.platform_name = "bfin-i2s-pcm-audio",
 		.init = bfin_eval_adav80x_codec_init,
 		.ops = &bfin_eval_adav80x_ops,
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+				SND_SOC_DAIFMT_CBM_CFM,
 	},
 };
 
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 7c205e7..6508e8b 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -40,6 +40,7 @@
 	select SND_SOC_MAX98088 if I2C
 	select SND_SOC_MAX98095 if I2C
 	select SND_SOC_MAX9850 if I2C
+	select SND_SOC_MAX9768 if I2C
 	select SND_SOC_MAX9877 if I2C
 	select SND_SOC_PCM3008
 	select SND_SOC_RT5631 if I2C
@@ -62,6 +63,7 @@
 	select SND_SOC_WL1273 if MFD_WL1273_CORE
 	select SND_SOC_WM1250_EV1 if I2C
 	select SND_SOC_WM2000 if I2C
+	select SND_SOC_WM2200 if I2C
 	select SND_SOC_WM5100 if I2C
 	select SND_SOC_WM8350 if MFD_WM8350
 	select SND_SOC_WM8400 if MFD_WM8400
@@ -292,6 +294,9 @@
 config SND_SOC_WM2000
 	tristate
 
+config SND_SOC_WM2200
+	tristate
+
 config SND_SOC_WM5100
 	tristate
 
@@ -425,6 +430,9 @@
 config SND_SOC_LM4857
 	tristate
 
+config SND_SOC_MAX9768
+	tristate
+
 config SND_SOC_MAX9877
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index de80781..6662eb0 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -25,6 +25,7 @@
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-l3-objs := l3.o
 snd-soc-lm4857-objs := lm4857.o
+snd-soc-max9768-objs := max9768.o
 snd-soc-max98088-objs := max98088.o
 snd-soc-max98095-objs := max98095.o
 snd-soc-max9850-objs := max9850.o
@@ -51,6 +52,7 @@
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm1250-ev1-objs := wm1250-ev1.o
 snd-soc-wm2000-objs := wm2000.o
+snd-soc-wm2200-objs := wm2200.o
 snd-soc-wm5100-objs := wm5100.o wm5100-tables.o
 snd-soc-wm8350-objs := wm8350.o
 snd-soc-wm8400-objs := wm8400.o
@@ -129,6 +131,7 @@
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_LM4857)	+= snd-soc-lm4857.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
+obj-$(CONFIG_SND_SOC_MAX9768)	+= snd-soc-max9768.o
 obj-$(CONFIG_SND_SOC_MAX98088)	+= snd-soc-max98088.o
 obj-$(CONFIG_SND_SOC_MAX98095)	+= snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
@@ -153,6 +156,7 @@
 obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
 obj-$(CONFIG_SND_SOC_WM2000)	+= snd-soc-wm2000.o
+obj-$(CONFIG_SND_SOC_WM2200)	+= snd-soc-wm2200.o
 obj-$(CONFIG_SND_SOC_WM5100)	+= snd-soc-wm5100.o
 obj-$(CONFIG_SND_SOC_WM8350)	+= snd-soc-wm8350.o
 obj-$(CONFIG_SND_SOC_WM8400)	+= snd-soc-wm8400.o
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index 982d201..12e3b41 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -277,7 +277,7 @@
 	if (ad1836->type == AD1836) {
 		/* left/right diff:PGA/MUX */
 		snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A);
-		ret = snd_soc_add_controls(codec, ad1836_controls,
+		ret = snd_soc_add_codec_controls(codec, ad1836_controls,
 				ARRAY_SIZE(ad1836_controls));
 		if (ret)
 			return ret;
@@ -285,11 +285,11 @@
 		snd_soc_write(codec, AD1836_ADC_CTRL3, 0x00);
 	}
 
-	ret = snd_soc_add_controls(codec, ad183x_dac_controls, num_dacs * 2);
+	ret = snd_soc_add_codec_controls(codec, ad183x_dac_controls, num_dacs * 2);
 	if (ret)
 		return ret;
 
-	ret = snd_soc_add_controls(codec, ad183x_adc_controls, num_adcs);
+	ret = snd_soc_add_codec_controls(codec, ad183x_adc_controls, num_adcs);
 	if (ret)
 		return ret;
 
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 9bba7f8..8c39ddd 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -228,7 +228,7 @@
 	ext_status = ac97_read(codec, AC97_EXTENDED_STATUS);
 	ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
 
-	snd_soc_add_controls(codec, ad1980_snd_ac97_controls,
+	snd_soc_add_codec_controls(codec, ad1980_snd_ac97_controls,
 				ARRAY_SIZE(ad1980_snd_ac97_controls));
 
 	return 0;
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 971ba45..44f5906 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -1244,8 +1244,6 @@
 		return ret;
 	}
 
-	codec->dapm.idle_bias_off = true;
-
 	if (pdata) {
 		if (pdata->num_drc > ARRAY_SIZE(pdata->drc_setting))
 			return -EINVAL;
@@ -1259,7 +1257,7 @@
 				pdata->drc_setting[i]);
 		}
 
-		snd_soc_add_controls(codec, adau1373_drc_controls,
+		snd_soc_add_codec_controls(codec, adau1373_drc_controls,
 			pdata->num_drc);
 
 		val = 0;
@@ -1284,7 +1282,7 @@
 	}
 
 	if (!lineout_differential) {
-		snd_soc_add_controls(codec, adau1373_lineout2_controls,
+		snd_soc_add_codec_controls(codec, adau1373_lineout2_controls,
 			ARRAY_SIZE(adau1373_lineout2_controls));
 	}
 
@@ -1340,6 +1338,7 @@
 	.suspend =	adau1373_suspend,
 	.resume =	adau1373_resume,
 	.set_bias_level = adau1373_set_bias_level,
+	.idle_bias_off = true,
 	.reg_cache_size = ARRAY_SIZE(adau1373_default_regs),
 	.reg_cache_default = adau1373_default_regs,
 	.reg_word_size = sizeof(uint8_t),
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 6b325ea..78e9ce4 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -457,7 +457,6 @@
 {
 	int ret;
 
-	codec->dapm.idle_bias_off = 1;
 	codec->control_data = to_i2c_client(codec->dev);
 
 	ret = adau1701_load_firmware(codec);
@@ -473,6 +472,7 @@
 static struct snd_soc_codec_driver adau1701_codec_drv = {
 	.probe			= adau1701_probe,
 	.set_bias_level		= adau1701_set_bias_level,
+	.idle_bias_off		= true,
 
 	.reg_cache_size		= ADAU1701_NUM_REGS,
 	.reg_word_size		= sizeof(u16),
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index d27b5e4..ceb96ec 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -46,75 +46,15 @@
 #define DRV_NAME "ak4104-codec"
 
 struct ak4104_private {
-	enum snd_soc_control_type control_type;
-	void *control_data;
+	struct regmap *regmap;
 };
 
-static int ak4104_fill_cache(struct snd_soc_codec *codec)
-{
-	int i;
-	u8 *reg_cache = codec->reg_cache;
-	struct spi_device *spi = codec->control_data;
-
-	for (i = 0; i < codec->driver->reg_cache_size; i++) {
-		int ret = spi_w8r8(spi, i | AK4104_READ);
-		if (ret < 0) {
-			dev_err(&spi->dev, "SPI write failure\n");
-			return ret;
-		}
-
-		reg_cache[i] = ret;
-	}
-
-	return 0;
-}
-
-static unsigned int ak4104_read_reg_cache(struct snd_soc_codec *codec,
-					  unsigned int reg)
-{
-	u8 *reg_cache = codec->reg_cache;
-
-	if (reg >= codec->driver->reg_cache_size)
-		return -EINVAL;
-
-	return reg_cache[reg];
-}
-
-static int ak4104_spi_write(struct snd_soc_codec *codec, unsigned int reg,
-			    unsigned int value)
-{
-	u8 *cache = codec->reg_cache;
-	struct spi_device *spi = codec->control_data;
-
-	if (reg >= codec->driver->reg_cache_size)
-		return -EINVAL;
-
-	/* only write to the hardware if value has changed */
-	if (cache[reg] != value) {
-		u8 tmp[2] = { (reg & AK4104_REG_MASK) | AK4104_WRITE, value };
-
-		if (spi_write(spi, tmp, sizeof(tmp))) {
-			dev_err(&spi->dev, "SPI write failed\n");
-			return -EIO;
-		}
-
-		cache[reg] = value;
-	}
-
-	return 0;
-}
-
 static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int format)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
 	int val = 0;
-
-	val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
-	if (val < 0)
-		return val;
-
-	val &= ~(AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1);
+	int ret;
 
 	/* set DAI format */
 	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -135,7 +75,13 @@
 	if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
 		return -EINVAL;
 
-	return ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
+	ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1,
+				  AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1,
+				  val);
+	if (ret < 0)
+		return ret;
+
+	return 0;
 }
 
 static int ak4104_hw_params(struct snd_pcm_substream *substream,
@@ -148,7 +94,7 @@
 
 	/* set the IEC958 bits: consumer mode, no copyright bit */
 	val |= IEC958_AES0_CON_NOT_COPYRIGHT;
-	ak4104_spi_write(codec, AK4104_REG_CHN_STATUS(0), val);
+	snd_soc_write(codec, AK4104_REG_CHN_STATUS(0), val);
 
 	val = 0;
 
@@ -167,7 +113,7 @@
 		return -EINVAL;
 	}
 
-	return ak4104_spi_write(codec, AK4104_REG_CHN_STATUS(3), val);
+	return snd_soc_write(codec, AK4104_REG_CHN_STATUS(3), val);
 }
 
 static const struct snd_soc_dai_ops ak4101_dai_ops = {
@@ -192,67 +138,57 @@
 static int ak4104_probe(struct snd_soc_codec *codec)
 {
 	struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
-	int ret, val;
+	int ret;
 
-	codec->control_data = ak4104->control_data;
-
-	/* read all regs and fill the cache */
-	ret = ak4104_fill_cache(codec);
-	if (ret < 0) {
-		dev_err(codec->dev, "failed to fill register cache\n");
+	codec->control_data = ak4104->regmap;
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+	if (ret != 0)
 		return ret;
-	}
-
-	/* read the 'reserved' register - according to the datasheet, it
-	 * should contain 0x5b. Not a good way to verify the presence of
-	 * the device, but there is no hardware ID register. */
-	if (ak4104_read_reg_cache(codec, AK4104_REG_RESERVED) !=
-					 AK4104_RESERVED_VAL)
-		return -ENODEV;
 
 	/* set power-up and non-reset bits */
-	val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
-	val |= AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN;
-	ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
+	ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1,
+				  AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
+				  AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
 	if (ret < 0)
 		return ret;
 
 	/* enable transmitter */
-	val = ak4104_read_reg_cache(codec, AK4104_REG_TX);
-	val |= AK4104_TX_TXE;
-	ret = ak4104_spi_write(codec, AK4104_REG_TX, val);
+	ret = snd_soc_update_bits(codec, AK4104_REG_TX,
+				  AK4104_TX_TXE, AK4104_TX_TXE);
 	if (ret < 0)
 		return ret;
 
-	dev_info(codec->dev, "SPI device initialized\n");
 	return 0;
 }
 
 static int ak4104_remove(struct snd_soc_codec *codec)
 {
-	int val, ret;
+	snd_soc_update_bits(codec, AK4104_REG_CONTROL1,
+			    AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
 
-	val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
-	if (val < 0)
-		return val;
-
-	/* clear power-up and non-reset bits */
-	val &= ~(AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
-	ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
-
-	return ret;
+	return 0;
 }
 
 static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
 	.probe =	ak4104_probe,
 	.remove =	ak4104_remove,
-	.reg_cache_size = AK4104_NUM_REGS,
-	.reg_word_size = sizeof(u8),
+};
+
+static const struct regmap_config ak4104_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = AK4104_NUM_REGS - 1,
+	.read_flag_mask = AK4104_READ,
+	.write_flag_mask = AK4104_WRITE,
+
+	.cache_type = REGCACHE_RBTREE,
 };
 
 static int ak4104_spi_probe(struct spi_device *spi)
 {
 	struct ak4104_private *ak4104;
+	unsigned int val;
 	int ret;
 
 	spi->bits_per_word = 8;
@@ -266,17 +202,41 @@
 	if (ak4104 == NULL)
 		return -ENOMEM;
 
-	ak4104->control_data = spi;
-	ak4104->control_type = SND_SOC_SPI;
+	ak4104->regmap = regmap_init_spi(spi, &ak4104_regmap);
+	if (IS_ERR(ak4104->regmap)) {
+		ret = PTR_ERR(ak4104->regmap);
+		return ret;
+	}
+
+	/* read the 'reserved' register - according to the datasheet, it
+	 * should contain 0x5b. Not a good way to verify the presence of
+	 * the device, but there is no hardware ID register. */
+	ret = regmap_read(ak4104->regmap, AK4104_REG_RESERVED, &val);
+	if (ret != 0)
+		goto err;
+	if (val != AK4104_RESERVED_VAL) {
+		ret = -ENODEV;
+		goto err;
+	}
+
 	spi_set_drvdata(spi, ak4104);
 
 	ret = snd_soc_register_codec(&spi->dev,
 			&soc_codec_device_ak4104, &ak4104_dai, 1);
+	if (ret != 0)
+		goto err;
+
+	return 0;
+
+err:
+	regmap_exit(ak4104->regmap);
 	return ret;
 }
 
 static int __devexit ak4104_spi_remove(struct spi_device *spi)
 {
+	struct ak4104_private *ak4101 = spi_get_drvdata(spi);
+	regmap_exit(ak4101->regmap);
 	snd_soc_unregister_codec(&spi->dev);
 	return 0;
 }
@@ -290,17 +250,7 @@
 	.remove = __devexit_p(ak4104_spi_remove),
 };
 
-static int __init ak4104_init(void)
-{
-	return spi_register_driver(&ak4104_spi_driver);
-}
-module_init(ak4104_init);
-
-static void __exit ak4104_exit(void)
-{
-	spi_unregister_driver(&ak4104_spi_driver);
-}
-module_exit(ak4104_exit);
+module_spi_driver(ak4104_spi_driver);
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
 MODULE_DESCRIPTION("Asahi Kasei AK4104 ALSA SoC driver");
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 9e809e0..838ae8b 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -27,24 +28,43 @@
 
 #include "ak4535.h"
 
-#define AK4535_VERSION "0.3"
-
 /* codec private data */
 struct ak4535_priv {
+	struct regmap *regmap;
 	unsigned int sysclk;
-	enum snd_soc_control_type control_type;
 };
 
 /*
  * ak4535 register cache
  */
-static const u8 ak4535_reg[AK4535_CACHEREGNUM] = {
-	0x00, 0x80, 0x00, 0x03,
-	0x02, 0x00, 0x11, 0x01,
-	0x00, 0x40, 0x36, 0x10,
-	0x00, 0x00, 0x57, 0x00,
+static const struct reg_default ak4535_reg_defaults[] = {
+	{ 0, 0x00 },
+	{ 1, 0x80 },
+	{ 2, 0x00 },
+	{ 3, 0x03 },
+	{ 4, 0x02 },
+	{ 5, 0x00 },
+	{ 6, 0x11 },
+	{ 7, 0x01 },
+	{ 8, 0x00 },
+	{ 9, 0x40 },
+	{ 10, 0x36 },
+	{ 11, 0x10 },
+	{ 12, 0x00 },
+	{ 13, 0x00 },
+	{ 14, 0x57 },
 };
 
+static bool ak4535_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AK4535_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
 static const char *ak4535_mono_gain[] = {"+6dB", "-17dB"};
 static const char *ak4535_mono_out[] = {"(L + R)/2", "Hi-Z"};
 static const char *ak4535_hp_out[] = {"Stereo", "Mono"};
@@ -372,9 +392,8 @@
 	struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 
-	printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
-
-	ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4535->control_type);
+	codec->control_data = ak4535->regmap;
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
@@ -382,7 +401,7 @@
 	/* power on device */
 	ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-	snd_soc_add_controls(codec, ak4535_snd_controls,
+	snd_soc_add_codec_controls(codec, ak4535_snd_controls,
 				ARRAY_SIZE(ak4535_snd_controls));
 	return 0;
 }
@@ -394,22 +413,30 @@
 	return 0;
 }
 
+static const struct regmap_config ak4535_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = AK4535_STATUS,
+	.volatile_reg = ak4535_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = ak4535_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ak4535_reg_defaults),
+};
+
 static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
 	.probe =	ak4535_probe,
 	.remove =	ak4535_remove,
 	.suspend =	ak4535_suspend,
 	.resume =	ak4535_resume,
 	.set_bias_level = ak4535_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(ak4535_reg),
-	.reg_word_size = sizeof(u8),
-	.reg_cache_default = ak4535_reg,
 	.dapm_widgets = ak4535_dapm_widgets,
 	.num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets),
 	.dapm_routes = ak4535_audio_map,
 	.num_dapm_routes = ARRAY_SIZE(ak4535_audio_map),
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int ak4535_i2c_probe(struct i2c_client *i2c,
 				      const struct i2c_device_id *id)
 {
@@ -421,17 +448,29 @@
 	if (ak4535 == NULL)
 		return -ENOMEM;
 
+	ak4535->regmap = regmap_init_i2c(i2c, &ak4535_regmap);
+	if (IS_ERR(ak4535->regmap)) {
+		ret = PTR_ERR(ak4535->regmap);
+		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
+
 	i2c_set_clientdata(i2c, ak4535);
-	ak4535->control_type = SND_SOC_I2C;
 
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_ak4535, &ak4535_dai, 1);
+	if (ret != 0)
+		regmap_exit(ak4535->regmap);
+
 	return ret;
 }
 
 static __devexit int ak4535_i2c_remove(struct i2c_client *client)
 {
+	struct ak4535_priv *ak4535 = i2c_get_clientdata(client);
+
 	snd_soc_unregister_codec(&client->dev);
+	regmap_exit(ak4535->regmap);
 	return 0;
 }
 
@@ -443,36 +482,15 @@
 
 static struct i2c_driver ak4535_i2c_driver = {
 	.driver = {
-		.name = "ak4535-codec",
+		.name = "ak4535",
 		.owner = THIS_MODULE,
 	},
 	.probe =    ak4535_i2c_probe,
 	.remove =   __devexit_p(ak4535_i2c_remove),
 	.id_table = ak4535_i2c_id,
 };
-#endif
 
-static int __init ak4535_modinit(void)
-{
-	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	ret = i2c_add_driver(&ak4535_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register AK4535 I2C driver: %d\n",
-		       ret);
-	}
-#endif
-	return ret;
-}
-module_init(ak4535_modinit);
-
-static void __exit ak4535_exit(void)
-{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	i2c_del_driver(&ak4535_i2c_driver);
-#endif
-}
-module_exit(ak4535_exit);
+module_i2c_driver(ak4535_i2c_driver);
 
 MODULE_DESCRIPTION("Soc AK4535 driver");
 MODULE_AUTHOR("Richard Purdie");
diff --git a/sound/soc/codecs/ak4535.h b/sound/soc/codecs/ak4535.h
index 0431e5f..402de1d 100644
--- a/sound/soc/codecs/ak4535.h
+++ b/sound/soc/codecs/ak4535.h
@@ -34,6 +34,4 @@
 #define AK4535_VOL		0xe
 #define AK4535_STATUS		0xf
 
-#define AK4535_CACHEREGNUM 	0x10
-
 #endif
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 278c0a0..f8e10ce 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -477,7 +477,7 @@
 		return ret;
 	}
 
-	snd_soc_add_controls(codec, ak4642_snd_controls,
+	snd_soc_add_codec_controls(codec, ak4642_snd_controls,
 			     ARRAY_SIZE(ak4642_snd_controls));
 
 	ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index a53b152..5fb7c2a 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -628,7 +628,7 @@
 		return ret;
 	}
 
-	snd_soc_add_controls(codec, ak4671_snd_controls,
+	snd_soc_add_codec_controls(codec, ak4671_snd_controls,
 			     ARRAY_SIZE(ak4671_snd_controls));
 
 	ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index 3feee56..d47b62d 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -925,22 +925,22 @@
 
 	switch (alc5623->id) {
 	case 0x21:
-		snd_soc_add_controls(codec, alc5621_vol_snd_controls,
+		snd_soc_add_codec_controls(codec, alc5621_vol_snd_controls,
 			ARRAY_SIZE(alc5621_vol_snd_controls));
 		break;
 	case 0x22:
-		snd_soc_add_controls(codec, alc5622_vol_snd_controls,
+		snd_soc_add_codec_controls(codec, alc5622_vol_snd_controls,
 			ARRAY_SIZE(alc5622_vol_snd_controls));
 		break;
 	case 0x23:
-		snd_soc_add_controls(codec, alc5623_vol_snd_controls,
+		snd_soc_add_codec_controls(codec, alc5623_vol_snd_controls,
 			ARRAY_SIZE(alc5623_vol_snd_controls));
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	snd_soc_add_controls(codec, alc5623_snd_controls,
+	snd_soc_add_codec_controls(codec, alc5623_snd_controls,
 			ARRAY_SIZE(alc5623_snd_controls));
 
 	snd_soc_dapm_new_controls(dapm, alc5623_dapm_widgets,
@@ -992,7 +992,7 @@
  *    low  = 0x1a
  *    high = 0x1b
  */
-static int alc5623_i2c_probe(struct i2c_client *client,
+static __devinit int alc5623_i2c_probe(struct i2c_client *client,
 				const struct i2c_device_id *id)
 {
 	struct alc5623_platform_data *pdata;
@@ -1059,7 +1059,7 @@
 	return ret;
 }
 
-static int alc5623_i2c_remove(struct i2c_client *client)
+static __devexit int alc5623_i2c_remove(struct i2c_client *client)
 {
 	snd_soc_unregister_codec(&client->dev);
 	return 0;
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index 390e437..e2111e0 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -145,15 +145,14 @@
 /* -16.5db min scale, 1.5db steps, no mute */
 static const DECLARE_TLV_DB_SCALE(adc_rec_tlv, -1650, 150, 0);
 static const unsigned int boost_tlv[] = {
-	TLV_DB_RANGE_HEAD(3),
-	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
-	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
-	2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
+	TLV_DB_RANGE_HEAD(2),
+	0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
+	1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0),
 };
 /* 0db min scale, 6 db steps, no mute */
 static const DECLARE_TLV_DB_SCALE(dig_tlv, 0, 600, 0);
 /* 0db min scalem 0.75db steps, no mute */
-static const DECLARE_TLV_DB_SCALE(vdac_tlv, -3525, 075, 0);
+static const DECLARE_TLV_DB_SCALE(vdac_tlv, -3525, 75, 0);
 
 static const struct snd_kcontrol_new alc5632_vol_snd_controls[] = {
 	/* left starts at bit 8, right at bit 0 */
@@ -176,26 +175,32 @@
 			ALC5632_AUX_OUT_VOL, 15, 7, 1, 1),
 	SOC_SINGLE_TLV("Voice DAC Playback Volume",
 			ALC5632_VOICE_DAC_VOL, 0, 63, 0, vdac_tlv),
-	SOC_SINGLE_TLV("Phone Capture Volume",
+	SOC_SINGLE("Voice DAC Playback Switch",
+			ALC5632_VOICE_DAC_VOL, 12, 1, 1),
+	SOC_SINGLE_TLV("Phone Playback Volume",
 			ALC5632_PHONE_IN_VOL, 8, 31, 1, vol_tlv),
-	SOC_DOUBLE_TLV("LineIn Capture Volume",
+	SOC_DOUBLE_TLV("LineIn Playback Volume",
 			ALC5632_LINE_IN_VOL, 8, 0, 31, 1, vol_tlv),
 	SOC_DOUBLE_TLV("Master Playback Volume",
 			ALC5632_STEREO_DAC_IN_VOL, 8, 0, 63, 1, vdac_tlv),
 	SOC_DOUBLE("Master Playback Switch",
 			ALC5632_STEREO_DAC_IN_VOL, 15, 7, 1, 1),
-	SOC_SINGLE_TLV("Mic1 Capture Volume",
+	SOC_SINGLE_TLV("Mic1 Playback Volume",
 			ALC5632_MIC_VOL, 8, 31, 1, vol_tlv),
-	SOC_SINGLE_TLV("Mic2 Capture Volume",
+	SOC_SINGLE_TLV("Mic2 Playback Volume",
 			ALC5632_MIC_VOL, 0, 31, 1, vol_tlv),
 	SOC_DOUBLE_TLV("Rec Capture Volume",
 			ALC5632_ADC_REC_GAIN, 8, 0, 31, 0, adc_rec_tlv),
 	SOC_SINGLE_TLV("Mic 1 Boost Volume",
-			ALC5632_MIC_CTRL, 10, 2, 0, boost_tlv),
+			ALC5632_MIC_CTRL, 10, 3, 0, boost_tlv),
 	SOC_SINGLE_TLV("Mic 2 Boost Volume",
-			ALC5632_MIC_CTRL, 8, 2, 0, boost_tlv),
-	SOC_SINGLE_TLV("Digital Boost Volume",
+			ALC5632_MIC_CTRL, 8, 3, 0, boost_tlv),
+	SOC_SINGLE_TLV("DMIC Boost Capture Volume",
 			ALC5632_DIGI_BOOST_CTRL, 0, 7, 0, dig_tlv),
+	SOC_SINGLE("DMIC En Capture Switch",
+			ALC5632_DIGI_BOOST_CTRL, 15, 1, 0),
+	SOC_SINGLE("DMIC PreFilter Capture Switch",
+			ALC5632_DIGI_BOOST_CTRL, 12, 1, 0),
 };
 
 /*
@@ -244,36 +249,48 @@
 
 /* Left Record Mixer */
 static const struct snd_kcontrol_new alc5632_captureL_mixer_controls[] = {
-SOC_DAPM_SINGLE("Mic1 Capture Switch", ALC5632_ADC_REC_MIXER, 14, 1, 1),
-SOC_DAPM_SINGLE("Mic2 Capture Switch", ALC5632_ADC_REC_MIXER, 13, 1, 1),
-SOC_DAPM_SINGLE("LineInL Capture Switch", ALC5632_ADC_REC_MIXER, 12, 1, 1),
-SOC_DAPM_SINGLE("Left Phone Capture Switch", ALC5632_ADC_REC_MIXER, 11, 1, 1),
-SOC_DAPM_SINGLE("HPMixerL Capture Switch", ALC5632_ADC_REC_MIXER, 10, 1, 1),
-SOC_DAPM_SINGLE("SPKMixer Capture Switch", ALC5632_ADC_REC_MIXER, 9, 1, 1),
-SOC_DAPM_SINGLE("MonoMixer Capture Switch", ALC5632_ADC_REC_MIXER, 8, 1, 1),
+SOC_DAPM_SINGLE("MIC12REC_L Capture Switch", ALC5632_ADC_REC_MIXER, 14, 1, 1),
+SOC_DAPM_SINGLE("MIC22REC_L Capture Switch", ALC5632_ADC_REC_MIXER, 13, 1, 1),
+SOC_DAPM_SINGLE("LIL2REC Capture Switch", ALC5632_ADC_REC_MIXER, 12, 1, 1),
+SOC_DAPM_SINGLE("PH2REC_L Capture Switch", ALC5632_ADC_REC_MIXER, 11, 1, 1),
+SOC_DAPM_SINGLE("HPL2REC Capture Switch", ALC5632_ADC_REC_MIXER, 10, 1, 1),
+SOC_DAPM_SINGLE("SPK2REC_L Capture Switch", ALC5632_ADC_REC_MIXER, 9, 1, 1),
+SOC_DAPM_SINGLE("MONO2REC_L Capture Switch", ALC5632_ADC_REC_MIXER, 8, 1, 1),
 };
 
 /* Right Record Mixer */
 static const struct snd_kcontrol_new alc5632_captureR_mixer_controls[] = {
-SOC_DAPM_SINGLE("Mic1 Capture Switch", ALC5632_ADC_REC_MIXER, 6, 1, 1),
-SOC_DAPM_SINGLE("Mic2 Capture Switch", ALC5632_ADC_REC_MIXER, 5, 1, 1),
-SOC_DAPM_SINGLE("LineInR Capture Switch", ALC5632_ADC_REC_MIXER, 4, 1, 1),
-SOC_DAPM_SINGLE("Right Phone Capture Switch", ALC5632_ADC_REC_MIXER, 3, 1, 1),
-SOC_DAPM_SINGLE("HPMixerR Capture Switch", ALC5632_ADC_REC_MIXER, 2, 1, 1),
-SOC_DAPM_SINGLE("SPKMixer Capture Switch", ALC5632_ADC_REC_MIXER, 1, 1, 1),
-SOC_DAPM_SINGLE("MonoMixer Capture Switch", ALC5632_ADC_REC_MIXER, 0, 1, 1),
+SOC_DAPM_SINGLE("MIC12REC_R Capture Switch", ALC5632_ADC_REC_MIXER, 6, 1, 1),
+SOC_DAPM_SINGLE("MIC22REC_R Capture Switch", ALC5632_ADC_REC_MIXER, 5, 1, 1),
+SOC_DAPM_SINGLE("LIR2REC Capture Switch", ALC5632_ADC_REC_MIXER, 4, 1, 1),
+SOC_DAPM_SINGLE("PH2REC_R Capture Switch", ALC5632_ADC_REC_MIXER, 3, 1, 1),
+SOC_DAPM_SINGLE("HPR2REC Capture Switch", ALC5632_ADC_REC_MIXER, 2, 1, 1),
+SOC_DAPM_SINGLE("SPK2REC_R Capture Switch", ALC5632_ADC_REC_MIXER, 1, 1, 1),
+SOC_DAPM_SINGLE("MONO2REC_R Capture Switch", ALC5632_ADC_REC_MIXER, 0, 1, 1),
 };
 
-static const char *alc5632_spk_n_sour_sel[] = {
+/* Dmic Mixer */
+static const struct snd_kcontrol_new alc5632_dmicl_mixer_controls[] = {
+SOC_DAPM_SINGLE("DMICL2ADC Capture Switch", ALC5632_DIGI_BOOST_CTRL, 7, 1, 1),
+};
+static const struct snd_kcontrol_new alc5632_dmicr_mixer_controls[] = {
+SOC_DAPM_SINGLE("DMICR2ADC Capture Switch", ALC5632_DIGI_BOOST_CTRL, 6, 1, 1),
+};
+
+static const char * const alc5632_spk_n_sour_sel[] = {
 		"RN/-R", "RP/+R", "LN/-R", "Mute"};
-static const char *alc5632_hpl_out_input_sel[] = {
+static const char * const alc5632_hpl_out_input_sel[] = {
 		"Vmid", "HP Left Mix"};
-static const char *alc5632_hpr_out_input_sel[] = {
+static const char * const alc5632_hpr_out_input_sel[] = {
 		"Vmid", "HP Right Mix"};
-static const char *alc5632_spkout_input_sel[] = {
+static const char * const alc5632_spkout_input_sel[] = {
 		"Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"};
-static const char *alc5632_aux_out_input_sel[] = {
+static const char * const alc5632_aux_out_input_sel[] = {
 		"Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"};
+static const char * const alc5632_adcr_func_sel[] = {
+		"Stereo ADC", "Voice ADC"};
+static const char * const alc5632_i2s_out_sel[] = {
+		"ADC LR", "Voice Stereo Digital"};
 
 /* auxout output mux */
 static const struct soc_enum alc5632_aux_out_input_enum =
@@ -312,6 +329,17 @@
 static const struct snd_kcontrol_new alc5632_amp_mux_controls =
 	SOC_DAPM_ENUM("AB-D Amp Mux", alc5632_amp_enum);
 
+/* ADC output select */
+static const struct soc_enum alc5632_adcr_func_enum =
+	SOC_ENUM_SINGLE(ALC5632_DAC_FUNC_SELECT, 5, 2, alc5632_adcr_func_sel);
+static const struct snd_kcontrol_new alc5632_adcr_func_controls =
+	SOC_DAPM_ENUM("ADCR Mux", alc5632_adcr_func_enum);
+
+/* I2S out select */
+static const struct soc_enum alc5632_i2s_out_enum =
+	SOC_ENUM_SINGLE(ALC5632_I2S_OUT_CTL, 5, 2, alc5632_i2s_out_sel);
+static const struct snd_kcontrol_new alc5632_i2s_out_controls =
+	SOC_DAPM_ENUM("I2SOut Mux", alc5632_i2s_out_enum);
 
 static const struct snd_soc_dapm_widget alc5632_dapm_widgets[] = {
 /* Muxes */
@@ -325,6 +353,10 @@
 	&alc5632_hpr_out_mux_controls),
 SND_SOC_DAPM_MUX("SpeakerOut N Mux", SND_SOC_NOPM, 0, 0,
 	&alc5632_spkoutn_mux_controls),
+SND_SOC_DAPM_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0,
+	&alc5632_adcr_func_controls),
+SND_SOC_DAPM_MUX("I2SOut Mux", ALC5632_PWR_MANAG_ADD1, 11, 0,
+	&alc5632_i2s_out_controls),
 
 /* output mixers */
 SND_SOC_DAPM_MIXER("HP Mix", SND_SOC_NOPM, 0, 0,
@@ -343,6 +375,12 @@
 SND_SOC_DAPM_MIXER("Speaker Mix", ALC5632_PWR_MANAG_ADD2, 3, 0,
 	&alc5632_speaker_mixer_controls[0],
 	ARRAY_SIZE(alc5632_speaker_mixer_controls)),
+SND_SOC_DAPM_MIXER("DMICL Mix", SND_SOC_NOPM, 0, 0,
+	&alc5632_dmicl_mixer_controls[0],
+	ARRAY_SIZE(alc5632_dmicl_mixer_controls)),
+SND_SOC_DAPM_MIXER("DMICR Mix", SND_SOC_NOPM, 0, 0,
+	&alc5632_dmicr_mixer_controls[0],
+	ARRAY_SIZE(alc5632_dmicr_mixer_controls)),
 
 /* input mixers */
 SND_SOC_DAPM_MIXER("Left Capture Mix", ALC5632_PWR_MANAG_ADD2, 1, 0,
@@ -352,20 +390,28 @@
 	&alc5632_captureR_mixer_controls[0],
 	ARRAY_SIZE(alc5632_captureR_mixer_controls)),
 
-SND_SOC_DAPM_DAC("Left DAC", "HiFi Playback",
-	ALC5632_PWR_MANAG_ADD2, 9, 0),
-SND_SOC_DAPM_DAC("Right DAC", "HiFi Playback",
-	ALC5632_PWR_MANAG_ADD2, 8, 0),
+SND_SOC_DAPM_AIF_IN("AIFRXL", "Left HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIFRXR", "Right HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIFTXL", "Left HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIFTXR", "Right HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("VAIFRX", "Voice Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("VAIFTX", "Voice Capture", 0, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_DAC("Voice DAC", NULL, ALC5632_PWR_MANAG_ADD2, 10, 0),
+SND_SOC_DAPM_DAC("Left DAC", NULL, ALC5632_PWR_MANAG_ADD2, 9, 0),
+SND_SOC_DAPM_DAC("Right DAC", NULL, ALC5632_PWR_MANAG_ADD2, 8, 0),
+SND_SOC_DAPM_ADC("Left ADC", NULL, ALC5632_PWR_MANAG_ADD2, 7, 0),
+SND_SOC_DAPM_ADC("Right ADC", NULL, ALC5632_PWR_MANAG_ADD2, 6, 0),
+
 SND_SOC_DAPM_MIXER("DAC Left Channel", ALC5632_PWR_MANAG_ADD1, 15, 0, NULL, 0),
 SND_SOC_DAPM_MIXER("DAC Right Channel",
 	ALC5632_PWR_MANAG_ADD1, 14, 0, NULL, 0),
 SND_SOC_DAPM_MIXER("I2S Mix", ALC5632_PWR_MANAG_ADD1, 11, 0, NULL, 0),
 SND_SOC_DAPM_MIXER("Phone Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
 SND_SOC_DAPM_MIXER("Line Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
-SND_SOC_DAPM_ADC("Left ADC", "HiFi Capture",
-	ALC5632_PWR_MANAG_ADD2, 7, 0),
-SND_SOC_DAPM_ADC("Right ADC", "HiFi Capture",
-	ALC5632_PWR_MANAG_ADD2, 6, 0),
+SND_SOC_DAPM_MIXER("Voice Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("ADCLR", SND_SOC_NOPM, 0, 0, NULL, 0),
+
 SND_SOC_DAPM_PGA("Left Headphone", ALC5632_PWR_MANAG_ADD3, 11, 0, NULL, 0),
 SND_SOC_DAPM_PGA("Right Headphone", ALC5632_PWR_MANAG_ADD3, 10, 0, NULL, 0),
 SND_SOC_DAPM_PGA("Left Speaker", ALC5632_PWR_MANAG_ADD3, 13, 0, NULL, 0),
@@ -393,10 +439,12 @@
 SND_SOC_DAPM_OUTPUT("HPR"),
 SND_SOC_DAPM_OUTPUT("SPKOUT"),
 SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+
 SND_SOC_DAPM_INPUT("LINEINL"),
 SND_SOC_DAPM_INPUT("LINEINR"),
 SND_SOC_DAPM_INPUT("PHONEP"),
 SND_SOC_DAPM_INPUT("PHONEN"),
+SND_SOC_DAPM_INPUT("DMICDAT"),
 SND_SOC_DAPM_INPUT("MIC1"),
 SND_SOC_DAPM_INPUT("MIC2"),
 SND_SOC_DAPM_VMID("Vmid"),
@@ -404,6 +452,10 @@
 
 
 static const struct snd_soc_dapm_route alc5632_dapm_routes[] = {
+	/* Playback streams */
+	{"Left DAC", NULL, "AIFRXL"},
+	{"Right DAC", NULL, "AIFRXR"},
+
 	/* virtual mixer - mixes left & right channels */
 	{"I2S Mix",	NULL,	"Left DAC"},
 	{"I2S Mix",	NULL,	"Right DAC"},
@@ -426,9 +478,12 @@
 	{"HP Mix",	"PHONE2HP Playback Switch",	"Phone Mix"},
 	{"HP Mix",	"MIC12HP Playback Switch",	"MIC1 PGA"},
 	{"HP Mix",	"MIC22HP Playback Switch",	"MIC2 PGA"},
-
+	{"HP Mix", "VOICE2HP Playback Switch",	"Voice Mix"},
 	{"HPR Mix", "DACR2HP Playback Switch",	"DAC Right Channel"},
 	{"HPL Mix", "DACL2HP Playback Switch",	"DAC Left Channel"},
+	{"HPOut Mix", NULL, "HP Mix"},
+	{"HPOut Mix", NULL, "HPR Mix"},
+	{"HPOut Mix", NULL, "HPL Mix"},
 
 	/* speaker mixer */
 	{"Speaker Mix", "LI2SPK Playback Switch",	"Line Mix"},
@@ -436,35 +491,34 @@
 	{"Speaker Mix", "MIC12SPK Playback Switch",	"MIC1 PGA"},
 	{"Speaker Mix", "MIC22SPK Playback Switch",	"MIC2 PGA"},
 	{"Speaker Mix", "DAC2SPK Playback Switch",	"DAC Left Channel"},
-
-
+	{"Speaker Mix", "VOICE2SPK Playback Switch",	"Voice Mix"},
 
 	/* mono mixer */
 	{"Mono Mix", "ADC2MONO_L Playback Switch",	"Left Capture Mix"},
 	{"Mono Mix", "ADC2MONO_R Playback Switch",	"Right Capture Mix"},
 	{"Mono Mix", "LI2MONO Playback Switch",		"Line Mix"},
-	{"Mono Mix", "VOICE2MONO Playback Switch",	"Phone Mix"},
 	{"Mono Mix", "MIC12MONO Playback Switch",	"MIC1 PGA"},
 	{"Mono Mix", "MIC22MONO Playback Switch",	"MIC2 PGA"},
 	{"Mono Mix", "DAC2MONO Playback Switch",	"DAC Left Channel"},
+	{"Mono Mix", "VOICE2MONO Playback Switch",	"Voice Mix"},
 
 	/* Left record mixer */
-	{"Left Capture Mix", "LineInL Capture Switch",	"LINEINL"},
-	{"Left Capture Mix", "Left Phone Capture Switch", "PHONEN"},
-	{"Left Capture Mix", "Mic1 Capture Switch",	"MIC1 Pre Amp"},
-	{"Left Capture Mix", "Mic2 Capture Switch",	"MIC2 Pre Amp"},
-	{"Left Capture Mix", "HPMixerL Capture Switch", "HPL Mix"},
-	{"Left Capture Mix", "SPKMixer Capture Switch", "Speaker Mix"},
-	{"Left Capture Mix", "MonoMixer Capture Switch", "Mono Mix"},
+	{"Left Capture Mix", "LIL2REC Capture Switch", "LINEINL"},
+	{"Left Capture Mix", "PH2REC_L Capture Switch", "PHONEN"},
+	{"Left Capture Mix", "MIC12REC_L Capture Switch", "MIC1 Pre Amp"},
+	{"Left Capture Mix", "MIC22REC_L Capture Switch", "MIC2 Pre Amp"},
+	{"Left Capture Mix", "HPL2REC Capture Switch", "HPL Mix"},
+	{"Left Capture Mix", "SPK2REC_L Capture Switch", "Speaker Mix"},
+	{"Left Capture Mix", "MONO2REC_L Capture Switch", "Mono Mix"},
 
 	/*Right record mixer */
-	{"Right Capture Mix", "LineInR Capture Switch",	"LINEINR"},
-	{"Right Capture Mix", "Right Phone Capture Switch",	"PHONEP"},
-	{"Right Capture Mix", "Mic1 Capture Switch",	"MIC1 Pre Amp"},
-	{"Right Capture Mix", "Mic2 Capture Switch",	"MIC2 Pre Amp"},
-	{"Right Capture Mix", "HPMixerR Capture Switch", "HPR Mix"},
-	{"Right Capture Mix", "SPKMixer Capture Switch", "Speaker Mix"},
-	{"Right Capture Mix", "MonoMixer Capture Switch", "Mono Mix"},
+	{"Right Capture Mix", "LIR2REC Capture Switch", "LINEINR"},
+	{"Right Capture Mix", "PH2REC_R Capture Switch", "PHONEP"},
+	{"Right Capture Mix", "MIC12REC_R Capture Switch", "MIC1 Pre Amp"},
+	{"Right Capture Mix", "MIC22REC_R Capture Switch", "MIC2 Pre Amp"},
+	{"Right Capture Mix", "HPR2REC Capture Switch", "HPR Mix"},
+	{"Right Capture Mix", "SPK2REC_R Capture Switch", "Speaker Mix"},
+	{"Right Capture Mix", "MONO2REC_R Capture Switch", "Mono Mix"},
 
 	/* headphone left mux */
 	{"Left Headphone Mux", "HP Left Mix",		"HPL Mix"},
@@ -504,10 +558,30 @@
 
 	/* left ADC */
 	{"Left ADC", NULL,				"Left Capture Mix"},
+	{"DMICL Mix", "DMICL2ADC Capture Switch", "DMICDAT"},
+	{"Left ADC", NULL,				"DMICL Mix"},
+	{"ADCLR", NULL,					"Left ADC"},
 
 	/* right ADC */
-	{"Right ADC", NULL,				"Right Capture Mix"},
+	{"Right ADC", NULL, "Right Capture Mix"},
+	{"DMICR Mix", "DMICR2ADC Capture Switch", "DMICDAT"},
+	{"Right ADC", NULL, "DMICR Mix"},
+	{"ADCR Mux", "Stereo ADC", "Right ADC"},
+	{"ADCR Mux", "Voice ADC", "Right ADC"},
+	{"ADCLR", NULL, "ADCR Mux"},
+	{"VAIFTX", NULL, "ADCR Mux"},
 
+	/* Digital I2S out */
+	{"I2SOut Mux", "ADC LR", "ADCLR"},
+	{"I2SOut Mux", "Voice Stereo Digital", "VAIFRX"},
+	{"AIFTXL", NULL, "I2SOut Mux"},
+	{"AIFTXR", NULL, "I2SOut Mux"},
+
+	/* Voice Mix */
+	{"Voice DAC", NULL, "VAIFRX"},
+	{"Voice Mix", NULL, "Voice DAC"},
+
+	/* Speaker Output */
 	{"SpeakerOut N Mux", "RN/-R",			"Left Speaker"},
 	{"SpeakerOut N Mux", "RP/+R",			"Left Speaker"},
 	{"SpeakerOut N Mux", "LN/-R",			"Left Speaker"},
@@ -714,6 +788,7 @@
 	struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
 
 	switch (freq) {
+	case  4096000:
 	case  8192000:
 	case 11289600:
 	case 12288000:
@@ -994,7 +1069,7 @@
 
 	switch (alc5632->id) {
 	case 0x5c:
-		snd_soc_add_controls(codec, alc5632_vol_snd_controls,
+		snd_soc_add_codec_controls(codec, alc5632_vol_snd_controls,
 			ARRAY_SIZE(alc5632_vol_snd_controls));
 		break;
 	default:
@@ -1109,7 +1184,7 @@
 	return ret;
 }
 
-static int alc5632_i2c_remove(struct i2c_client *client)
+static __devexit int alc5632_i2c_remove(struct i2c_client *client)
 {
 	struct alc5632_priv *alc5632 = i2c_get_clientdata(client);
 	snd_soc_unregister_codec(&client->dev);
diff --git a/sound/soc/codecs/alc5632.h b/sound/soc/codecs/alc5632.h
index 357651e..1b5bda5 100644
--- a/sound/soc/codecs/alc5632.h
+++ b/sound/soc/codecs/alc5632.h
@@ -51,6 +51,7 @@
 #define ALC5632_ADC_REC_MONOMIX			(1 << 0)
 
 #define ALC5632_VOICE_DAC_VOL			0x18 /* voice dac vol */
+#define ALC5632_I2S_OUT_CTL				0x1A /* undocumented reg. found in path scheme */
 /* ALC5632_OUTPUT_MIXER_CTRL :			*/
 /* same remark as for reg 2 line vs speaker	*/
 #define ALC5632_OUTPUT_MIXER_CTRL		0x1C /* out mix ctrl */
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c
index 4854b47..064cd6a 100644
--- a/sound/soc/codecs/cq93vc.c
+++ b/sound/soc/codecs/cq93vc.c
@@ -38,8 +38,6 @@
 #include <sound/soc.h>
 #include <sound/initval.h>
 
-#include <mach/dm365.h>
-
 static inline unsigned int cq93vc_read(struct snd_soc_codec *codec,
 						unsigned int reg)
 {
@@ -159,7 +157,7 @@
 	codec->control_data = davinci_vc;
 
 	/* Set controls */
-	snd_soc_add_controls(codec, cq93vc_snd_controls,
+	snd_soc_add_codec_controls(codec, cq93vc_snd_controls,
 			     ARRAY_SIZE(cq93vc_snd_controls));
 
 	/* Off, with power on */
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 0555366..1d672f5 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -521,7 +521,7 @@
 	}
 
 	/* Add the non-DAPM controls */
-	ret = snd_soc_add_controls(codec, cs4270_snd_controls,
+	ret = snd_soc_add_codec_controls(codec, cs4270_snd_controls,
 				ARRAY_SIZE(cs4270_snd_controls));
 	if (ret < 0) {
 		dev_err(codec->dev, "failed to add controls\n");
@@ -715,7 +715,7 @@
  */
 static struct i2c_driver cs4270_i2c_driver = {
 	.driver = {
-		.name = "cs4270-codec",
+		.name = "cs4270",
 		.owner = THIS_MODULE,
 	},
 	.id_table = cs4270_id,
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index f6fe846..bf71412 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -513,7 +513,7 @@
 	/* Power-up sequence requires 85 uS */
 	udelay(85);
 
-	return snd_soc_add_controls(codec, cs4271_snd_controls,
+	return snd_soc_add_codec_controls(codec, cs4271_snd_controls,
 		ARRAY_SIZE(cs4271_snd_controls));
 }
 
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index ab38e93..7843711 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -17,6 +17,7 @@
 
 #include <linux/delay.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <sound/pcm.h>
@@ -626,41 +627,82 @@
 
 /* Codec private data */
 struct da7210_priv {
-	enum snd_soc_control_type control_type;
+	struct regmap *regmap;
 };
 
-/*
- * Register cache
- */
-static const u8 da7210_reg[] = {
-	0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R0  - R7  */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,	/* R8  - RF  */
-	0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x54,	/* R10 - R17 */
-	0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R18 - R1F */
-	0x00, 0x00, 0x00, 0x02, 0x00, 0x76, 0x00, 0x00,	/* R20 - R27 */
-	0x04, 0x00, 0x00, 0x30, 0x2A, 0x00, 0x40, 0x00,	/* R28 - R2F */
-	0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00,	/* R30 - R37 */
-	0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00,	/* R38 - R3F */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R40 - R4F */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R48 - R4F */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R50 - R57 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R58 - R5F */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R60 - R67 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R68 - R6F */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R70 - R77 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x00,	/* R78 - R7F */
-	0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R80 - R87 */
-	0x00,						/* R88       */
+static struct reg_default da7210_reg_defaults[] = {
+	{ 0x01, 0x11 },
+	{ 0x03, 0x00 },
+	{ 0x04, 0x00 },
+	{ 0x05, 0x00 },
+	{ 0x06, 0x00 },
+	{ 0x07, 0x00 },
+	{ 0x08, 0x00 },
+	{ 0x09, 0x00 },
+	{ 0x0a, 0x00 },
+	{ 0x0b, 0x00 },
+	{ 0x0c, 0x00 },
+	{ 0x0d, 0x00 },
+	{ 0x0e, 0x00 },
+	{ 0x0f, 0x08 },
+	{ 0x10, 0x00 },
+	{ 0x11, 0x00 },
+	{ 0x12, 0x00 },
+	{ 0x13, 0x00 },
+	{ 0x14, 0x08 },
+	{ 0x15, 0x10 },
+	{ 0x16, 0x10 },
+	{ 0x17, 0x54 },
+	{ 0x18, 0x40 },
+	{ 0x19, 0x00 },
+	{ 0x1a, 0x00 },
+	{ 0x1b, 0x00 },
+	{ 0x1c, 0x00 },
+	{ 0x1d, 0x00 },
+	{ 0x1e, 0x00 },
+	{ 0x1f, 0x00 },
+	{ 0x20, 0x00 },
+	{ 0x21, 0x00 },
+	{ 0x22, 0x00 },
+	{ 0x23, 0x02 },
+	{ 0x24, 0x00 },
+	{ 0x25, 0x76 },
+	{ 0x26, 0x00 },
+	{ 0x27, 0x00 },
+	{ 0x28, 0x04 },
+	{ 0x29, 0x00 },
+	{ 0x2a, 0x00 },
+	{ 0x2b, 0x30 },
+	{ 0x2c, 0x2A },
+	{ 0x83, 0x00 },
+	{ 0x84, 0x00 },
+	{ 0x85, 0x00 },
+	{ 0x86, 0x00 },
+	{ 0x87, 0x00 },
+	{ 0x88, 0x00 },
 };
 
-static int da7210_volatile_register(struct snd_soc_codec *codec,
+static bool da7210_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case DA7210_A_HID_UNLOCK:
+	case DA7210_A_TEST_UNLOCK:
+	case DA7210_A_PLL1:
+	case DA7210_A_CP_MODE:
+		return false;
+	default:
+		return true;
+	}
+}
+
+static bool da7210_volatile_register(struct device *dev,
 				    unsigned int reg)
 {
 	switch (reg) {
 	case DA7210_STATUS:
-		return 1;
+		return true;
 	default:
-		return 0;
+		return false;
 	}
 }
 
@@ -866,7 +908,8 @@
 
 	dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
 
-	ret = snd_soc_codec_set_cache_io(codec, 8, 8, da7210->control_type);
+	codec->control_data = da7210->regmap;
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
@@ -983,12 +1026,14 @@
 	snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
 
 	/* As suggested by Dialog */
-	snd_soc_write(codec, DA7210_A_HID_UNLOCK,	0x8B); /* unlock */
-	snd_soc_write(codec, DA7210_A_TEST_UNLOCK,	0xB4);
-	snd_soc_write(codec, DA7210_A_PLL1,		0x01);
-	snd_soc_write(codec, DA7210_A_CP_MODE,		0x7C);
-	snd_soc_write(codec, DA7210_A_HID_UNLOCK,	0x00); /* re-lock */
-	snd_soc_write(codec, DA7210_A_TEST_UNLOCK,	0x00);
+	/* unlock */
+	regmap_write(da7210->regmap, DA7210_A_HID_UNLOCK,	0x8B);
+	regmap_write(da7210->regmap, DA7210_A_TEST_UNLOCK,	0xB4);
+	regmap_write(da7210->regmap, DA7210_A_PLL1,		0x01);
+	regmap_write(da7210->regmap, DA7210_A_CP_MODE,		0x7C);
+	/* re-lock */
+	regmap_write(da7210->regmap, DA7210_A_HID_UNLOCK,	0x00);
+	regmap_write(da7210->regmap, DA7210_A_TEST_UNLOCK,	0x00);
 
 	/* Activate all enabled subsystem */
 	snd_soc_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
@@ -1000,10 +1045,6 @@
 
 static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
 	.probe			= da7210_probe,
-	.reg_cache_size		= ARRAY_SIZE(da7210_reg),
-	.reg_word_size		= sizeof(u8),
-	.reg_cache_default	= da7210_reg,
-	.volatile_register	= da7210_volatile_register,
 
 	.controls		= da7210_snd_controls,
 	.num_controls		= ARRAY_SIZE(da7210_snd_controls),
@@ -1014,6 +1055,17 @@
 	.num_dapm_routes	= ARRAY_SIZE(da7210_audio_map),
 };
 
+static struct regmap_config da7210_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.reg_defaults = da7210_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(da7210_reg_defaults),
+	.volatile_reg = da7210_volatile_register,
+	.readable_reg = da7210_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
 			   	      const struct i2c_device_id *id)
@@ -1027,16 +1079,34 @@
 		return -ENOMEM;
 
 	i2c_set_clientdata(i2c, da7210);
-	da7210->control_type = SND_SOC_I2C;
+
+	da7210->regmap = regmap_init_i2c(i2c, &da7210_regmap);
+	if (IS_ERR(da7210->regmap)) {
+		ret = PTR_ERR(da7210->regmap);
+		dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
 
 	ret =  snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_da7210, &da7210_dai, 1);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		goto err_regmap;
+	}
+	return ret;
+
+err_regmap:
+	regmap_exit(da7210->regmap);
+
 	return ret;
 }
 
 static int __devexit da7210_i2c_remove(struct i2c_client *client)
 {
+	struct da7210_priv *da7210 = i2c_get_clientdata(client);
+
 	snd_soc_unregister_codec(&client->dev);
+	regmap_exit(da7210->regmap);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c
index 3190392..ba4fafb 100644
--- a/sound/soc/codecs/lm4857.c
+++ b/sound/soc/codecs/lm4857.c
@@ -179,7 +179,7 @@
 
 	codec->control_data = lm4857->i2c;
 
-	ret = snd_soc_add_controls(codec, lm4857_controls,
+	ret = snd_soc_add_codec_controls(codec, lm4857_controls,
 			ARRAY_SIZE(lm4857_controls));
 	if (ret)
 		return ret;
diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c
new file mode 100644
index 0000000..17b3ec2
--- /dev/null
+++ b/sound/soc/codecs/max9768.c
@@ -0,0 +1,247 @@
+/*
+ * MAX9768 AMP driver
+ *
+ * Copyright (C) 2011, 2012 by Wolfram Sang, Pengutronix e.K.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/max9768.h>
+
+/* "Registers" */
+#define MAX9768_VOL 0
+#define MAX9768_CTRL 3
+
+/* Commands */
+#define MAX9768_CTRL_PWM 0x15
+#define MAX9768_CTRL_FILTERLESS 0x16
+
+struct max9768 {
+	struct regmap *regmap;
+	int mute_gpio;
+	int shdn_gpio;
+	u32 flags;
+};
+
+static struct reg_default max9768_default_regs[] = {
+	{ 0, 0 },
+	{ 3,  MAX9768_CTRL_FILTERLESS},
+};
+
+static int max9768_get_gpio(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
+	int val = gpio_get_value_cansleep(max9768->mute_gpio);
+
+	ucontrol->value.integer.value[0] = !val;
+
+	return 0;
+}
+
+static int max9768_set_gpio(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
+
+	gpio_set_value_cansleep(max9768->mute_gpio, !ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static const unsigned int volume_tlv[] = {
+	TLV_DB_RANGE_HEAD(43),
+	0, 0, TLV_DB_SCALE_ITEM(-16150, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(-9280, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(-9030, 0, 0),
+	3, 3, TLV_DB_SCALE_ITEM(-8680, 0, 0),
+	4, 4, TLV_DB_SCALE_ITEM(-8430, 0, 0),
+	5, 5, TLV_DB_SCALE_ITEM(-8080, 0, 0),
+	6, 6, TLV_DB_SCALE_ITEM(-7830, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(-7470, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(-7220, 0, 0),
+	9, 9, TLV_DB_SCALE_ITEM(-6870, 0, 0),
+	10, 10, TLV_DB_SCALE_ITEM(-6620, 0, 0),
+	11, 11, TLV_DB_SCALE_ITEM(-6270, 0, 0),
+	12, 12, TLV_DB_SCALE_ITEM(-6020, 0, 0),
+	13, 13, TLV_DB_SCALE_ITEM(-5670, 0, 0),
+	14, 14, TLV_DB_SCALE_ITEM(-5420, 0, 0),
+	15, 17, TLV_DB_SCALE_ITEM(-5060, 250, 0),
+	18, 18, TLV_DB_SCALE_ITEM(-4370, 0, 0),
+	19, 19, TLV_DB_SCALE_ITEM(-4210, 0, 0),
+	20, 20, TLV_DB_SCALE_ITEM(-3960, 0, 0),
+	21, 21, TLV_DB_SCALE_ITEM(-3760, 0, 0),
+	22, 22, TLV_DB_SCALE_ITEM(-3600, 0, 0),
+	23, 23, TLV_DB_SCALE_ITEM(-3340, 0, 0),
+	24, 24, TLV_DB_SCALE_ITEM(-3150, 0, 0),
+	25, 25, TLV_DB_SCALE_ITEM(-2980, 0, 0),
+	26, 26, TLV_DB_SCALE_ITEM(-2720, 0, 0),
+	27, 27, TLV_DB_SCALE_ITEM(-2520, 0, 0),
+	28, 30, TLV_DB_SCALE_ITEM(-2350, 190, 0),
+	31, 31, TLV_DB_SCALE_ITEM(-1750, 0, 0),
+	32, 34, TLV_DB_SCALE_ITEM(-1640, 100, 0),
+	35, 37, TLV_DB_SCALE_ITEM(-1310, 110, 0),
+	38, 39, TLV_DB_SCALE_ITEM(-990, 100, 0),
+	40, 40, TLV_DB_SCALE_ITEM(-710, 0, 0),
+	41, 41, TLV_DB_SCALE_ITEM(-600, 0, 0),
+	42, 42, TLV_DB_SCALE_ITEM(-500, 0, 0),
+	43, 43, TLV_DB_SCALE_ITEM(-340, 0, 0),
+	44, 44, TLV_DB_SCALE_ITEM(-190, 0, 0),
+	45, 45, TLV_DB_SCALE_ITEM(-50, 0, 0),
+	46, 46, TLV_DB_SCALE_ITEM(50, 0, 0),
+	47, 50, TLV_DB_SCALE_ITEM(120, 40, 0),
+	51, 57, TLV_DB_SCALE_ITEM(290, 50, 0),
+	58, 58, TLV_DB_SCALE_ITEM(650, 0, 0),
+	59, 62, TLV_DB_SCALE_ITEM(700, 60, 0),
+	63, 63, TLV_DB_SCALE_ITEM(950, 0, 0),
+};
+
+static const struct snd_kcontrol_new max9768_volume[] = {
+	SOC_SINGLE_TLV("Playback Volume", MAX9768_VOL, 0, 63, 0, volume_tlv),
+};
+
+static const struct snd_kcontrol_new max9768_mute[] = {
+	SOC_SINGLE_BOOL_EXT("Playback Switch", 0, max9768_get_gpio, max9768_set_gpio),
+};
+
+static int max9768_probe(struct snd_soc_codec *codec)
+{
+	struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	codec->control_data = max9768->regmap;
+	ret = snd_soc_codec_set_cache_io(codec, 2, 6, SND_SOC_REGMAP);
+	if (ret)
+		return ret;
+
+	if (max9768->flags & MAX9768_FLAG_CLASSIC_PWM) {
+		ret = snd_soc_write(codec, MAX9768_CTRL, MAX9768_CTRL_PWM);
+		if (ret)
+			return ret;
+	}
+
+	if (gpio_is_valid(max9768->mute_gpio)) {
+		ret = snd_soc_add_codec_controls(codec, max9768_mute,
+				ARRAY_SIZE(max9768_mute));
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver max9768_codec_driver = {
+	.probe = max9768_probe,
+	.controls = max9768_volume,
+	.num_controls = ARRAY_SIZE(max9768_volume),
+};
+
+static const struct regmap_config max9768_i2c_regmap_config = {
+	.reg_bits = 2,
+	.val_bits = 6,
+	.max_register = 3,
+	.reg_defaults = max9768_default_regs,
+	.num_reg_defaults = ARRAY_SIZE(max9768_default_regs),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit max9768_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct max9768 *max9768;
+	struct max9768_pdata *pdata = client->dev.platform_data;
+	int err;
+
+	max9768 = devm_kzalloc(&client->dev, sizeof(*max9768), GFP_KERNEL);
+	if (!max9768)
+		return -ENOMEM;
+
+	if (pdata) {
+		/* Mute on powerup to avoid clicks */
+		err = gpio_request_one(pdata->mute_gpio, GPIOF_INIT_HIGH, "MAX9768 Mute");
+		max9768->mute_gpio = err ?: pdata->mute_gpio;
+
+		/* Activate chip by releasing shutdown, enables I2C */
+		err = gpio_request_one(pdata->shdn_gpio, GPIOF_INIT_HIGH, "MAX9768 Shutdown");
+		max9768->shdn_gpio = err ?: pdata->shdn_gpio;
+
+		max9768->flags = pdata->flags;
+	} else {
+		max9768->shdn_gpio = -EINVAL;
+		max9768->mute_gpio = -EINVAL;
+	}
+
+	i2c_set_clientdata(client, max9768);
+
+	max9768->regmap = regmap_init_i2c(client, &max9768_i2c_regmap_config);
+	if (IS_ERR(max9768->regmap)) {
+		err = PTR_ERR(max9768->regmap);
+		goto err_gpio_free;
+	}
+
+	err = snd_soc_register_codec(&client->dev, &max9768_codec_driver, NULL, 0);
+	if (err)
+		goto err_regmap_free;
+
+	return 0;
+
+ err_regmap_free:
+	regmap_exit(max9768->regmap);
+ err_gpio_free:
+	if (gpio_is_valid(max9768->shdn_gpio))
+		gpio_free(max9768->shdn_gpio);
+	if (gpio_is_valid(max9768->mute_gpio))
+		gpio_free(max9768->mute_gpio);
+
+	return err;
+}
+
+static int __devexit max9768_i2c_remove(struct i2c_client *client)
+{
+	struct max9768 *max9768 = i2c_get_clientdata(client);
+
+	snd_soc_unregister_codec(&client->dev);
+	regmap_exit(max9768->regmap);
+
+	if (gpio_is_valid(max9768->shdn_gpio))
+		gpio_free(max9768->shdn_gpio);
+	if (gpio_is_valid(max9768->mute_gpio))
+		gpio_free(max9768->mute_gpio);
+
+	return 0;
+}
+
+static const struct i2c_device_id max9768_i2c_id[] = {
+	{ "max9768", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max9768_i2c_id);
+
+static struct i2c_driver max9768_i2c_driver = {
+	.driver = {
+		.name = "max9768",
+		.owner = THIS_MODULE,
+	},
+	.probe = max9768_i2c_probe,
+	.remove = __devexit_p(max9768_i2c_remove),
+	.id_table = max9768_i2c_id,
+};
+module_i2c_driver(max9768_i2c_driver);
+
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("ASoC MAX9768 amplifier driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 006efcf..af7324b 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -1908,7 +1908,7 @@
        max98088->eq_enum.texts = max98088->eq_texts;
        max98088->eq_enum.max = max98088->eq_textcnt;
 
-       ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+       ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
        if (ret != 0)
                dev_err(codec->dev, "Failed to add EQ control: %d\n", ret);
 }
@@ -2030,7 +2030,7 @@
 
        max98088_handle_pdata(codec);
 
-       snd_soc_add_controls(codec, max98088_snd_controls,
+       snd_soc_add_codec_controls(codec, max98088_snd_controls,
                             ARRAY_SIZE(max98088_snd_controls));
 
 err_access:
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index fcfa749..0bb511a 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -1284,7 +1284,7 @@
 
 static int max98095_add_widgets(struct snd_soc_codec *codec)
 {
-	snd_soc_add_controls(codec, max98095_snd_controls,
+	snd_soc_add_codec_controls(codec, max98095_snd_controls,
 			     ARRAY_SIZE(max98095_snd_controls));
 
 	return 0;
@@ -1984,7 +1984,7 @@
 	max98095->eq_enum.texts = max98095->eq_texts;
 	max98095->eq_enum.max = max98095->eq_textcnt;
 
-	ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+	ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
 	if (ret != 0)
 		dev_err(codec->dev, "Failed to add EQ control: %d\n", ret);
 }
@@ -2139,7 +2139,7 @@
 	max98095->bq_enum.texts = max98095->bq_texts;
 	max98095->bq_enum.max = max98095->bq_textcnt;
 
-	ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+	ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
 	if (ret != 0)
 		dev_err(codec->dev, "Failed to add Biquad control: %d\n", ret);
 }
diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c
index dcf6f2a..3a2ba3d 100644
--- a/sound/soc/codecs/max9877.c
+++ b/sound/soc/codecs/max9877.c
@@ -253,7 +253,7 @@
 /* This function is called from ASoC machine driver */
 int max9877_add_controls(struct snd_soc_codec *codec)
 {
-	return snd_soc_add_controls(codec, max9877_controls,
+	return snd_soc_add_codec_controls(codec, max9877_controls,
 			ARRAY_SIZE(max9877_controls));
 }
 EXPORT_SYMBOL_GPL(max9877_add_controls);
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 7f4ba81..d192626 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -227,7 +227,7 @@
 };
 
 /* routes for sgtl5000 */
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route sgtl5000_dapm_routes[] = {
 	{"Capture Mux", "LINE_IN", "LINE_IN"},	/* line_in --> adc_mux */
 	{"Capture Mux", "MIC_IN", "MIC_IN"},	/* mic_in --> adc_mux */
 
@@ -1248,7 +1248,7 @@
 	}
 
 	rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
-	dev_info(codec->dev, "sgtl5000 revision %d\n", rev);
+	dev_info(codec->dev, "sgtl5000 revision 0x%x\n", rev);
 
 	/*
 	 * workaround for revision 0x11 and later,
@@ -1353,15 +1353,6 @@
 	if (ret)
 		goto err;
 
-	snd_soc_add_controls(codec, sgtl5000_snd_controls,
-			     ARRAY_SIZE(sgtl5000_snd_controls));
-
-	snd_soc_dapm_new_controls(&codec->dapm, sgtl5000_dapm_widgets,
-				  ARRAY_SIZE(sgtl5000_dapm_widgets));
-
-	snd_soc_dapm_add_routes(&codec->dapm, audio_map,
-				ARRAY_SIZE(audio_map));
-
 	snd_soc_dapm_new_widgets(&codec->dapm);
 
 	return 0;
@@ -1402,6 +1393,12 @@
 	.reg_cache_step = 2,
 	.reg_cache_default = sgtl5000_regs,
 	.volatile_register = sgtl5000_volatile_register,
+	.controls = sgtl5000_snd_controls,
+	.num_controls = ARRAY_SIZE(sgtl5000_snd_controls),
+	.dapm_widgets = sgtl5000_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(sgtl5000_dapm_widgets),
+	.dapm_routes = sgtl5000_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(sgtl5000_dapm_routes),
 };
 
 static __devinit int sgtl5000_i2c_probe(struct i2c_client *client,
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c
index f99baa0..50dbdb9 100644
--- a/sound/soc/codecs/sn95031.c
+++ b/sound/soc/codecs/sn95031.c
@@ -827,8 +827,6 @@
 {
 	pr_debug("codec_probe called\n");
 
-	codec->dapm.idle_bias_off = 1;
-
 	/* PCM interface config
 	 * This sets the pcm rx slot conguration to max 6 slots
 	 * for max 4 dais (2 stereo and 2 mono)
@@ -871,7 +869,7 @@
 	snd_soc_write(codec, SN95031_SSR2, 0x10);
 	snd_soc_write(codec, SN95031_SSR3, 0x40);
 
-	snd_soc_add_controls(codec, sn95031_snd_controls,
+	snd_soc_add_codec_controls(codec, sn95031_snd_controls,
 			     ARRAY_SIZE(sn95031_snd_controls));
 
 	return 0;
@@ -891,6 +889,7 @@
 	.read		= sn95031_read,
 	.write		= sn95031_write,
 	.set_bias_level	= sn95031_set_vaud_bias,
+	.idle_bias_off	= true,
 	.dapm_widgets	= sn95031_dapm_widgets,
 	.num_dapm_widgets	= ARRAY_SIZE(sn95031_dapm_widgets),
 	.dapm_routes	= sn95031_audio_map,
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 333dd98..de2b205 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -548,7 +548,7 @@
 	snd_soc_update_bits(codec, SSM2602_ROUT1V,
 			    ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH);
 
-	ret = snd_soc_add_controls(codec, ssm2602_snd_controls,
+	ret = snd_soc_add_codec_controls(codec, ssm2602_snd_controls,
 			ARRAY_SIZE(ssm2602_snd_controls));
 	if (ret)
 		return ret;
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index cc0566c..982e437 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -355,7 +355,7 @@
 
 	stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-	snd_soc_add_controls(codec, stac9766_snd_ac97_controls,
+	snd_soc_add_codec_controls(codec, stac9766_snd_ac97_controls,
 			     ARRAY_SIZE(stac9766_snd_ac97_controls));
 
 	return 0;
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index dfa41a9..16d55f9 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -593,7 +593,7 @@
 
 	snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x1);
 
-	snd_soc_add_controls(codec, tlv320aic23_snd_controls,
+	snd_soc_add_codec_controls(codec, tlv320aic23_snd_controls,
 				ARRAY_SIZE(tlv320aic23_snd_controls));
 
 	return 0;
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index a038dae..802064b 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -389,7 +389,7 @@
 
 	/* register controls */
 	dev_dbg(codec->dev, "Registering controls\n");
-	err = snd_soc_add_controls(codec, aic26_snd_controls,
+	err = snd_soc_add_codec_controls(codec, aic26_snd_controls,
 			ARRAY_SIZE(aic26_snd_controls));
 	WARN_ON(err < 0);
 
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 372b0b8..b0a73d3 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -671,7 +671,7 @@
 	}
 
 	aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-	snd_soc_add_controls(codec, aic32x4_snd_controls,
+	snd_soc_add_codec_controls(codec, aic32x4_snd_controls,
 			     ARRAY_SIZE(aic32x4_snd_controls));
 	aic32x4_add_widgets(codec);
 
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 492f22f..8d20f6e 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -121,30 +121,6 @@
 	0x00, 0x00, 0x02,	/* 100 */
 };
 
-/*
- * read from the aic3x register space. Only use for this function is if
- * wanting to read volatile bits from those registers that has both read-only
- * and read/write bits. All other cases should use snd_soc_read.
- */
-static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
-		      u8 *value)
-{
-	u8 *cache = codec->reg_cache;
-
-	if (codec->cache_only)
-		return -EINVAL;
-	if (reg >= AIC3X_CACHEREGNUM)
-		return -1;
-
-	codec->cache_bypass = 1;
-	*value = snd_soc_read(codec, reg);
-	codec->cache_bypass = 0;
-
-	cache[reg] = *value;
-
-	return 0;
-}
-
 #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.info = snd_soc_info_volsw, \
@@ -1185,25 +1161,6 @@
 	return 0;
 }
 
-void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state)
-{
-	u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG;
-	u8 bit = gpio ? 3: 0;
-	u8 val = snd_soc_read(codec, reg) & ~(1 << bit);
-	snd_soc_write(codec, reg, val | (!!state << bit));
-}
-EXPORT_SYMBOL_GPL(aic3x_set_gpio);
-
-int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio)
-{
-	u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG;
-	u8 val = 0, bit = gpio ? 2 : 1;
-
-	aic3x_read(codec, reg, &val);
-	return (val >> bit) & 1;
-}
-EXPORT_SYMBOL_GPL(aic3x_get_gpio);
-
 void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect,
 				 int headset_debounce, int button_debounce)
 {
@@ -1221,23 +1178,6 @@
 
 	snd_soc_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val);
 }
-EXPORT_SYMBOL_GPL(aic3x_set_headset_detection);
-
-int aic3x_headset_detected(struct snd_soc_codec *codec)
-{
-	u8 val = 0;
-	aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val);
-	return (val >> 4) & 1;
-}
-EXPORT_SYMBOL_GPL(aic3x_headset_detected);
-
-int aic3x_button_pressed(struct snd_soc_codec *codec)
-{
-	u8 val = 0;
-	aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val);
-	return (val >> 5) & 1;
-}
-EXPORT_SYMBOL_GPL(aic3x_button_pressed);
 
 #define AIC3X_RATES	SNDRV_PCM_RATE_8000_96000
 #define AIC3X_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
@@ -1377,7 +1317,6 @@
 
 	INIT_LIST_HEAD(&aic3x->list);
 	aic3x->codec = codec;
-	codec->dapm.idle_bias_off = 1;
 
 	ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type);
 	if (ret != 0) {
@@ -1426,10 +1365,10 @@
 			      (aic3x->setup->gpio_func[1] & 0xf) << 4);
 	}
 
-	snd_soc_add_controls(codec, aic3x_snd_controls,
+	snd_soc_add_codec_controls(codec, aic3x_snd_controls,
 			     ARRAY_SIZE(aic3x_snd_controls));
 	if (aic3x->model == AIC3X_MODEL_3007)
-		snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
+		snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
 
 	aic3x_add_widgets(codec);
 	list_add(&aic3x->list, &reset_list);
@@ -1471,6 +1410,7 @@
 
 static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
 	.set_bias_level = aic3x_set_bias_level,
+	.idle_bias_off = true,
 	.reg_cache_size = ARRAY_SIZE(aic3x_reg),
 	.reg_word_size = sizeof(u8),
 	.reg_cache_default = aic3x_reg,
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
index 06a1978..6f097fb 100644
--- a/sound/soc/codecs/tlv320aic3x.h
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -212,9 +212,6 @@
 /* Default input volume */
 #define DEFAULT_GAIN    0x20
 
-void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state);
-int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio);
-
 /* headset detection / button API */
 
 /* The AIC3x supports detection of stereo headsets (GND + left + right signal)
@@ -252,10 +249,4 @@
 #define AIC3X_BUTTON_DEBOUNCE_SHIFT 	0
 #define AIC3X_BUTTON_DEBOUNCE_MASK	3
 
-/* see the enums above for valid parameters to this function */
-void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect,
-				 int headset_debounce, int button_debounce);
-int aic3x_headset_detected(struct snd_soc_codec *codec);
-int aic3x_button_pressed(struct snd_soc_codec *codec);
-
 #endif /* _AIC3X_H */
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index f0aad26..4587ddd 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -806,8 +806,6 @@
 	/* Stream started, save the substream pointer */
 	dac33->substream = substream;
 
-	snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24);
-
 	return 0;
 }
 
@@ -1397,7 +1395,6 @@
 
 	codec->control_data = dac33->control_data;
 	codec->hw_write = (hw_write_t) i2c_master_send;
-	codec->dapm.idle_bias_off = 1;
 	dac33->codec = codec;
 
 	/* Read the tlv320dac33 ID registers */
@@ -1440,7 +1437,7 @@
 
 	/* Only add the FIFO controls, if we have valid IRQ number */
 	if (dac33->irq >= 0)
-		snd_soc_add_controls(codec, dac33_mode_snd_controls,
+		snd_soc_add_codec_controls(codec, dac33_mode_snd_controls,
 				     ARRAY_SIZE(dac33_mode_snd_controls));
 
 err_power:
@@ -1478,6 +1475,7 @@
 	.read = dac33_read_reg_cache,
 	.write = dac33_write_locked,
 	.set_bias_level = dac33_set_bias_level,
+	.idle_bias_off = true,
 	.reg_cache_size = ARRAY_SIZE(dac33_reg),
 	.reg_word_size = sizeof(u8),
 	.reg_cache_default = dac33_reg,
@@ -1515,7 +1513,9 @@
 		.channels_min = 2,
 		.channels_max = 2,
 		.rates = DAC33_RATES,
-		.formats = DAC33_FORMATS,},
+		.formats = DAC33_FORMATS,
+		.sig_bits = 24,
+	},
 	.ops = &dac33_dai_ops,
 };
 
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index 363b99d..6fe4aa3 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -351,10 +351,10 @@
 	data = i2c_get_clientdata(tpa6130a2_client);
 
 	if (data->id == TPA6140A2)
-		return snd_soc_add_controls(codec, tpa6140a2_controls,
+		return snd_soc_add_codec_controls(codec, tpa6140a2_controls,
 						ARRAY_SIZE(tpa6140a2_controls));
 	else
-		return snd_soc_add_controls(codec, tpa6130a2_controls,
+		return snd_soc_add_codec_controls(codec, tpa6130a2_controls,
 						ARRAY_SIZE(tpa6130a2_controls));
 }
 EXPORT_SYMBOL_GPL(tpa6130a2_add_controls);
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 18e7101..170cf9a 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -1002,8 +1002,8 @@
 	unsigned short mask, bitmask;
 
 	if (twl4030->configured) {
-		printk(KERN_ERR "twl4030 operation mode cannot be "
-			"changed on-the-fly\n");
+		dev_err(codec->dev,
+			"operation mode cannot be changed on-the-fly\n");
 		return -EBUSY;
 	}
 
@@ -1689,7 +1689,6 @@
 	struct snd_soc_codec *codec = rtd->codec;
 	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
-	snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24);
 	if (twl4030->master_substream) {
 		twl4030->slave_substream = substream;
 		/* The DAI has one configuration for playback and capture, so
@@ -1801,7 +1800,7 @@
 		mode |= TWL4030_APLL_RATE_96000;
 		break;
 	default:
-		printk(KERN_ERR "TWL4030 hw params: unknown rate %d\n",
+		dev_err(codec->dev, "%s: unknown rate %d\n", __func__,
 			params_rate(params));
 		return -EINVAL;
 	}
@@ -1818,7 +1817,7 @@
 		format |= TWL4030_DATA_WIDTH_32S_24W;
 		break;
 	default:
-		printk(KERN_ERR "TWL4030 hw params: unknown format %d\n",
+		dev_err(codec->dev, "%s: unknown format %d\n", __func__,
 			params_format(params));
 		return -EINVAL;
 	}
@@ -1868,13 +1867,13 @@
 	case 38400000:
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported APLL mclk: %u\n", freq);
+		dev_err(codec->dev, "Unsupported HFCLKIN: %u\n", freq);
 		return -EINVAL;
 	}
 
 	if ((freq / 1000) != twl4030->sysclk) {
 		dev_err(codec->dev,
-			"Mismatch in APLL mclk: %u (configured: %u)\n",
+			"Mismatch in HFCLKIN: %u (configured: %u)\n",
 			freq, twl4030->sysclk * 1000);
 		return -EINVAL;
 	}
@@ -1984,9 +1983,9 @@
 	 * not available.
 	 */
 	if (twl4030->sysclk != 26000) {
-		dev_err(codec->dev, "The board is configured for %u Hz, while"
-			"the Voice interface needs 26MHz APLL mclk\n",
-			twl4030->sysclk * 1000);
+		dev_err(codec->dev,
+			"%s: HFCLKIN is %u KHz, voice interface needs 26MHz\n",
+			__func__, twl4030->sysclk);
 		return -EINVAL;
 	}
 
@@ -1997,8 +1996,8 @@
 		& TWL4030_OPT_MODE;
 
 	if (mode != TWL4030_OPTION_2) {
-		printk(KERN_ERR "TWL4030 voice startup: "
-			"the codec mode is not option2\n");
+		dev_err(codec->dev, "%s: the codec mode is not option2\n",
+			__func__);
 		return -EINVAL;
 	}
 
@@ -2039,7 +2038,7 @@
 		mode |= TWL4030_SEL_16K;
 		break;
 	default:
-		printk(KERN_ERR "TWL4030 voice hw params: unknown rate %d\n",
+		dev_err(codec->dev, "%s: unknown rate %d\n", __func__,
 			params_rate(params));
 		return -EINVAL;
 	}
@@ -2068,13 +2067,14 @@
 	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
 	if (freq != 26000000) {
-		dev_err(codec->dev, "Unsupported APLL mclk: %u, the Voice"
-			"interface needs 26MHz APLL mclk\n", freq);
+		dev_err(codec->dev,
+			"%s: HFCLKIN is %u KHz, voice interface needs 26MHz\n",
+			__func__, freq / 1000);
 		return -EINVAL;
 	}
 	if ((freq / 1000) != twl4030->sysclk) {
 		dev_err(codec->dev,
-			"Mismatch in APLL mclk: %u (configured: %u)\n",
+			"Mismatch in HFCLKIN: %u (configured: %u)\n",
 			freq, twl4030->sysclk * 1000);
 		return -EINVAL;
 	}
@@ -2175,13 +2175,15 @@
 		.channels_min = 2,
 		.channels_max = 4,
 		.rates = TWL4030_RATES | SNDRV_PCM_RATE_96000,
-		.formats = TWL4030_FORMATS,},
+		.formats = TWL4030_FORMATS,
+		.sig_bits = 24,},
 	.capture = {
 		.stream_name = "Capture",
 		.channels_min = 2,
 		.channels_max = 4,
 		.rates = TWL4030_RATES,
-		.formats = TWL4030_FORMATS,},
+		.formats = TWL4030_FORMATS,
+		.sig_bits = 24,},
 	.ops = &twl4030_dai_hifi_ops,
 },
 {
@@ -2220,13 +2222,12 @@
 
 	twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
 	if (twl4030 == NULL) {
-		printk("Can not allocate memroy\n");
+		dev_err(codec->dev, "Can not allocate memory\n");
 		return -ENOMEM;
 	}
 	snd_soc_codec_set_drvdata(codec, twl4030);
 	/* Set the defaults, and power up the codec */
 	twl4030->sysclk = twl4030_audio_get_mclk() / 1000;
-	codec->dapm.idle_bias_off = 1;
 
 	twl4030_init_chip(codec);
 
@@ -2252,6 +2253,7 @@
 	.read = twl4030_read_reg_cache,
 	.write = twl4030_write,
 	.set_bias_level = twl4030_set_bias_level,
+	.idle_bias_off = true,
 	.reg_cache_size = sizeof(twl4030_reg),
 	.reg_word_size = sizeof(u8),
 	.reg_cache_default = twl4030_reg,
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 5b9c79b..2d8c6b8 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -1052,6 +1052,19 @@
 }
 EXPORT_SYMBOL_GPL(twl6040_get_trim_value);
 
+int twl6040_get_hs_step_size(struct snd_soc_codec *codec)
+{
+	struct twl6040 *twl6040 = codec->control_data;
+
+	if (twl6040_get_revid(twl6040) < TWL6040_REV_ES1_2)
+		/* For ES under ES_1.3 HS step is 2 mV */
+		return 2;
+	else
+		/* For ES_1.3 HS step is 1 mV */
+		return 1;
+}
+EXPORT_SYMBOL_GPL(twl6040_get_hs_step_size);
+
 static const struct snd_kcontrol_new twl6040_snd_controls[] = {
 	/* Capture gains */
 	SOC_DOUBLE_TLV("Capture Preamplifier Volume",
@@ -1125,14 +1138,14 @@
 			TWL6040_REG_MICRCTL, 2, 0),
 
 	/* Microphone bias */
-	SND_SOC_DAPM_MICBIAS("Headset Mic Bias",
-			TWL6040_REG_AMICBCTL, 0, 0),
-	SND_SOC_DAPM_MICBIAS("Main Mic Bias",
-			TWL6040_REG_AMICBCTL, 4, 0),
-	SND_SOC_DAPM_MICBIAS("Digital Mic1 Bias",
-			TWL6040_REG_DMICBCTL, 0, 0),
-	SND_SOC_DAPM_MICBIAS("Digital Mic2 Bias",
-			TWL6040_REG_DMICBCTL, 4, 0),
+	SND_SOC_DAPM_SUPPLY("Headset Mic Bias",
+			    TWL6040_REG_AMICBCTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Main Mic Bias",
+			    TWL6040_REG_AMICBCTL, 4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Digital Mic1 Bias",
+			    TWL6040_REG_DMICBCTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Digital Mic2 Bias",
+			    TWL6040_REG_DMICBCTL, 4, 0, NULL, 0),
 
 	/* DACs */
 	SND_SOC_DAPM_DAC("HSDAC Left", "Headset Playback", SND_SOC_NOPM, 0, 0),
@@ -1527,7 +1540,6 @@
 
 	priv->codec = codec;
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
-	codec->ignore_pmdown_time = 1;
 
 	if (pdata && pdata->hs_left_step && pdata->hs_right_step) {
 		priv->hs_left_step = pdata->hs_left_step;
@@ -1613,6 +1625,7 @@
 	.reg_cache_size = ARRAY_SIZE(twl6040_reg),
 	.reg_word_size = sizeof(u8),
 	.reg_cache_default = twl6040_reg,
+	.ignore_pmdown_time = true,
 
 	.controls = twl6040_snd_controls,
 	.num_controls = ARRAY_SIZE(twl6040_snd_controls),
diff --git a/sound/soc/codecs/twl6040.h b/sound/soc/codecs/twl6040.h
index ef273f1..0611406 100644
--- a/sound/soc/codecs/twl6040.h
+++ b/sound/soc/codecs/twl6040.h
@@ -39,5 +39,6 @@
 			    struct snd_soc_jack *jack, int report);
 int twl6040_get_clk_id(struct snd_soc_codec *codec);
 int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim);
+int twl6040_get_hs_step_size(struct snd_soc_codec *codec);
 
 #endif /* End of __TWL6040_H__ */
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index 8f4f469..797b0dd 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -531,15 +531,15 @@
 	switch (pd->model) {
 	case UDA134X_UDA1340:
 	case UDA134X_UDA1344:
-		ret = snd_soc_add_controls(codec, uda1340_snd_controls,
+		ret = snd_soc_add_codec_controls(codec, uda1340_snd_controls,
 					ARRAY_SIZE(uda1340_snd_controls));
 	break;
 	case UDA134X_UDA1341:
-		ret = snd_soc_add_controls(codec, uda1341_snd_controls,
+		ret = snd_soc_add_codec_controls(codec, uda1341_snd_controls,
 					ARRAY_SIZE(uda1341_snd_controls));
 	break;
 	case UDA134X_UDA1345:
-		ret = snd_soc_add_controls(codec, uda1345_snd_controls,
+		ret = snd_soc_add_codec_controls(codec, uda1345_snd_controls,
 					ARRAY_SIZE(uda1345_snd_controls));
 	break;
 	default:
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index 44aacf9..3d868dc 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -464,7 +464,7 @@
 
 	snd_soc_codec_set_drvdata(codec, wl1273);
 
-	r = snd_soc_add_controls(codec, wl1273_controls,
+	r = snd_soc_add_codec_controls(codec, wl1273_controls,
 				 ARRAY_SIZE(wl1273_controls));
 	if (r)
 		kfree(wl1273);
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
new file mode 100644
index 0000000..acbdc5f
--- /dev/null
+++ b/sound/soc/codecs/wm2200.c
@@ -0,0 +1,2286 @@
+/*
+ * wm2200.c  --  WM2200 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.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gcd.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/fixed.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 <sound/wm2200.h>
+
+#include "wm2200.h"
+
+/* The code assumes DCVDD is generated internally */
+#define WM2200_NUM_CORE_SUPPLIES 2
+static const char *wm2200_core_supply_names[WM2200_NUM_CORE_SUPPLIES] = {
+	"DBVDD",
+	"LDOVDD",
+};
+
+struct wm2200_fll {
+	int fref;
+	int fout;
+	int src;
+	struct completion lock;
+};
+
+/* codec private data */
+struct wm2200_priv {
+	struct regmap *regmap;
+	struct device *dev;
+	struct snd_soc_codec *codec;
+	struct wm2200_pdata pdata;
+	struct regulator_bulk_data core_supplies[WM2200_NUM_CORE_SUPPLIES];
+
+	struct completion fll_lock;
+	int fll_fout;
+	int fll_fref;
+	int fll_src;
+
+	int rev;
+	int sysclk;
+};
+
+static struct reg_default wm2200_reg_defaults[] = {
+	{ 0x000B, 0x0000 },   /* R11    - Tone Generator 1 */
+	{ 0x0102, 0x0000 },   /* R258   - Clocking 3 */
+	{ 0x0103, 0x0011 },   /* R259   - Clocking 4 */
+	{ 0x0111, 0x0000 },   /* R273   - FLL Control 1 */
+	{ 0x0112, 0x0000 },   /* R274   - FLL Control 2 */
+	{ 0x0113, 0x0000 },   /* R275   - FLL Control 3 */
+	{ 0x0114, 0x0000 },   /* R276   - FLL Control 4 */
+	{ 0x0116, 0x0177 },   /* R278   - FLL Control 6 */
+	{ 0x0117, 0x0004 },   /* R279   - FLL Control 7 */
+	{ 0x0119, 0x0000 },   /* R281   - FLL EFS 1 */
+	{ 0x011A, 0x0002 },   /* R282   - FLL EFS 2 */
+	{ 0x0200, 0x0000 },   /* R512   - Mic Charge Pump 1 */
+	{ 0x0201, 0x03FF },   /* R513   - Mic Charge Pump 2 */
+	{ 0x0202, 0x9BDE },   /* R514   - DM Charge Pump 1 */
+	{ 0x020C, 0x0000 },   /* R524   - Mic Bias Ctrl 1 */
+	{ 0x020D, 0x0000 },   /* R525   - Mic Bias Ctrl 2 */
+	{ 0x020F, 0x0000 },   /* R527   - Ear Piece Ctrl 1 */
+	{ 0x0210, 0x0000 },   /* R528   - Ear Piece Ctrl 2 */
+	{ 0x0301, 0x0000 },   /* R769   - Input Enables */
+	{ 0x0302, 0x2240 },   /* R770   - IN1L Control */
+	{ 0x0303, 0x0040 },   /* R771   - IN1R Control */
+	{ 0x0304, 0x2240 },   /* R772   - IN2L Control */
+	{ 0x0305, 0x0040 },   /* R773   - IN2R Control */
+	{ 0x0306, 0x2240 },   /* R774   - IN3L Control */
+	{ 0x0307, 0x0040 },   /* R775   - IN3R Control */
+	{ 0x030A, 0x0000 },   /* R778   - RXANC_SRC */
+	{ 0x030B, 0x0022 },   /* R779   - Input Volume Ramp */
+	{ 0x030C, 0x0180 },   /* R780   - ADC Digital Volume 1L */
+	{ 0x030D, 0x0180 },   /* R781   - ADC Digital Volume 1R */
+	{ 0x030E, 0x0180 },   /* R782   - ADC Digital Volume 2L */
+	{ 0x030F, 0x0180 },   /* R783   - ADC Digital Volume 2R */
+	{ 0x0310, 0x0180 },   /* R784   - ADC Digital Volume 3L */
+	{ 0x0311, 0x0180 },   /* R785   - ADC Digital Volume 3R */
+	{ 0x0400, 0x0000 },   /* R1024  - Output Enables */
+	{ 0x0401, 0x0000 },   /* R1025  - DAC Volume Limit 1L */
+	{ 0x0402, 0x0000 },   /* R1026  - DAC Volume Limit 1R */
+	{ 0x0403, 0x0000 },   /* R1027  - DAC Volume Limit 2L */
+	{ 0x0404, 0x0000 },   /* R1028  - DAC Volume Limit 2R */
+	{ 0x0409, 0x0000 },   /* R1033  - DAC AEC Control 1 */
+	{ 0x040A, 0x0022 },   /* R1034  - Output Volume Ramp */
+	{ 0x040B, 0x0180 },   /* R1035  - DAC Digital Volume 1L */
+	{ 0x040C, 0x0180 },   /* R1036  - DAC Digital Volume 1R */
+	{ 0x040D, 0x0180 },   /* R1037  - DAC Digital Volume 2L */
+	{ 0x040E, 0x0180 },   /* R1038  - DAC Digital Volume 2R */
+	{ 0x0417, 0x0069 },   /* R1047  - PDM 1 */
+	{ 0x0418, 0x0000 },   /* R1048  - PDM 2 */
+	{ 0x0500, 0x0000 },   /* R1280  - Audio IF 1_1 */
+	{ 0x0501, 0x0008 },   /* R1281  - Audio IF 1_2 */
+	{ 0x0502, 0x0000 },   /* R1282  - Audio IF 1_3 */
+	{ 0x0503, 0x0000 },   /* R1283  - Audio IF 1_4 */
+	{ 0x0504, 0x0000 },   /* R1284  - Audio IF 1_5 */
+	{ 0x0505, 0x0001 },   /* R1285  - Audio IF 1_6 */
+	{ 0x0506, 0x0001 },   /* R1286  - Audio IF 1_7 */
+	{ 0x0507, 0x0000 },   /* R1287  - Audio IF 1_8 */
+	{ 0x0508, 0x0000 },   /* R1288  - Audio IF 1_9 */
+	{ 0x0509, 0x0000 },   /* R1289  - Audio IF 1_10 */
+	{ 0x050A, 0x0000 },   /* R1290  - Audio IF 1_11 */
+	{ 0x050B, 0x0000 },   /* R1291  - Audio IF 1_12 */
+	{ 0x050C, 0x0000 },   /* R1292  - Audio IF 1_13 */
+	{ 0x050D, 0x0000 },   /* R1293  - Audio IF 1_14 */
+	{ 0x050E, 0x0000 },   /* R1294  - Audio IF 1_15 */
+	{ 0x050F, 0x0000 },   /* R1295  - Audio IF 1_16 */
+	{ 0x0510, 0x0000 },   /* R1296  - Audio IF 1_17 */
+	{ 0x0511, 0x0000 },   /* R1297  - Audio IF 1_18 */
+	{ 0x0512, 0x0000 },   /* R1298  - Audio IF 1_19 */
+	{ 0x0513, 0x0000 },   /* R1299  - Audio IF 1_20 */
+	{ 0x0514, 0x0000 },   /* R1300  - Audio IF 1_21 */
+	{ 0x0515, 0x0001 },   /* R1301  - Audio IF 1_22 */
+	{ 0x0600, 0x0000 },   /* R1536  - OUT1LMIX Input 1 Source */
+	{ 0x0601, 0x0080 },   /* R1537  - OUT1LMIX Input 1 Volume */
+	{ 0x0602, 0x0000 },   /* R1538  - OUT1LMIX Input 2 Source */
+	{ 0x0603, 0x0080 },   /* R1539  - OUT1LMIX Input 2 Volume */
+	{ 0x0604, 0x0000 },   /* R1540  - OUT1LMIX Input 3 Source */
+	{ 0x0605, 0x0080 },   /* R1541  - OUT1LMIX Input 3 Volume */
+	{ 0x0606, 0x0000 },   /* R1542  - OUT1LMIX Input 4 Source */
+	{ 0x0607, 0x0080 },   /* R1543  - OUT1LMIX Input 4 Volume */
+	{ 0x0608, 0x0000 },   /* R1544  - OUT1RMIX Input 1 Source */
+	{ 0x0609, 0x0080 },   /* R1545  - OUT1RMIX Input 1 Volume */
+	{ 0x060A, 0x0000 },   /* R1546  - OUT1RMIX Input 2 Source */
+	{ 0x060B, 0x0080 },   /* R1547  - OUT1RMIX Input 2 Volume */
+	{ 0x060C, 0x0000 },   /* R1548  - OUT1RMIX Input 3 Source */
+	{ 0x060D, 0x0080 },   /* R1549  - OUT1RMIX Input 3 Volume */
+	{ 0x060E, 0x0000 },   /* R1550  - OUT1RMIX Input 4 Source */
+	{ 0x060F, 0x0080 },   /* R1551  - OUT1RMIX Input 4 Volume */
+	{ 0x0610, 0x0000 },   /* R1552  - OUT2LMIX Input 1 Source */
+	{ 0x0611, 0x0080 },   /* R1553  - OUT2LMIX Input 1 Volume */
+	{ 0x0612, 0x0000 },   /* R1554  - OUT2LMIX Input 2 Source */
+	{ 0x0613, 0x0080 },   /* R1555  - OUT2LMIX Input 2 Volume */
+	{ 0x0614, 0x0000 },   /* R1556  - OUT2LMIX Input 3 Source */
+	{ 0x0615, 0x0080 },   /* R1557  - OUT2LMIX Input 3 Volume */
+	{ 0x0616, 0x0000 },   /* R1558  - OUT2LMIX Input 4 Source */
+	{ 0x0617, 0x0080 },   /* R1559  - OUT2LMIX Input 4 Volume */
+	{ 0x0618, 0x0000 },   /* R1560  - OUT2RMIX Input 1 Source */
+	{ 0x0619, 0x0080 },   /* R1561  - OUT2RMIX Input 1 Volume */
+	{ 0x061A, 0x0000 },   /* R1562  - OUT2RMIX Input 2 Source */
+	{ 0x061B, 0x0080 },   /* R1563  - OUT2RMIX Input 2 Volume */
+	{ 0x061C, 0x0000 },   /* R1564  - OUT2RMIX Input 3 Source */
+	{ 0x061D, 0x0080 },   /* R1565  - OUT2RMIX Input 3 Volume */
+	{ 0x061E, 0x0000 },   /* R1566  - OUT2RMIX Input 4 Source */
+	{ 0x061F, 0x0080 },   /* R1567  - OUT2RMIX Input 4 Volume */
+	{ 0x0620, 0x0000 },   /* R1568  - AIF1TX1MIX Input 1 Source */
+	{ 0x0621, 0x0080 },   /* R1569  - AIF1TX1MIX Input 1 Volume */
+	{ 0x0622, 0x0000 },   /* R1570  - AIF1TX1MIX Input 2 Source */
+	{ 0x0623, 0x0080 },   /* R1571  - AIF1TX1MIX Input 2 Volume */
+	{ 0x0624, 0x0000 },   /* R1572  - AIF1TX1MIX Input 3 Source */
+	{ 0x0625, 0x0080 },   /* R1573  - AIF1TX1MIX Input 3 Volume */
+	{ 0x0626, 0x0000 },   /* R1574  - AIF1TX1MIX Input 4 Source */
+	{ 0x0627, 0x0080 },   /* R1575  - AIF1TX1MIX Input 4 Volume */
+	{ 0x0628, 0x0000 },   /* R1576  - AIF1TX2MIX Input 1 Source */
+	{ 0x0629, 0x0080 },   /* R1577  - AIF1TX2MIX Input 1 Volume */
+	{ 0x062A, 0x0000 },   /* R1578  - AIF1TX2MIX Input 2 Source */
+	{ 0x062B, 0x0080 },   /* R1579  - AIF1TX2MIX Input 2 Volume */
+	{ 0x062C, 0x0000 },   /* R1580  - AIF1TX2MIX Input 3 Source */
+	{ 0x062D, 0x0080 },   /* R1581  - AIF1TX2MIX Input 3 Volume */
+	{ 0x062E, 0x0000 },   /* R1582  - AIF1TX2MIX Input 4 Source */
+	{ 0x062F, 0x0080 },   /* R1583  - AIF1TX2MIX Input 4 Volume */
+	{ 0x0630, 0x0000 },   /* R1584  - AIF1TX3MIX Input 1 Source */
+	{ 0x0631, 0x0080 },   /* R1585  - AIF1TX3MIX Input 1 Volume */
+	{ 0x0632, 0x0000 },   /* R1586  - AIF1TX3MIX Input 2 Source */
+	{ 0x0633, 0x0080 },   /* R1587  - AIF1TX3MIX Input 2 Volume */
+	{ 0x0634, 0x0000 },   /* R1588  - AIF1TX3MIX Input 3 Source */
+	{ 0x0635, 0x0080 },   /* R1589  - AIF1TX3MIX Input 3 Volume */
+	{ 0x0636, 0x0000 },   /* R1590  - AIF1TX3MIX Input 4 Source */
+	{ 0x0637, 0x0080 },   /* R1591  - AIF1TX3MIX Input 4 Volume */
+	{ 0x0638, 0x0000 },   /* R1592  - AIF1TX4MIX Input 1 Source */
+	{ 0x0639, 0x0080 },   /* R1593  - AIF1TX4MIX Input 1 Volume */
+	{ 0x063A, 0x0000 },   /* R1594  - AIF1TX4MIX Input 2 Source */
+	{ 0x063B, 0x0080 },   /* R1595  - AIF1TX4MIX Input 2 Volume */
+	{ 0x063C, 0x0000 },   /* R1596  - AIF1TX4MIX Input 3 Source */
+	{ 0x063D, 0x0080 },   /* R1597  - AIF1TX4MIX Input 3 Volume */
+	{ 0x063E, 0x0000 },   /* R1598  - AIF1TX4MIX Input 4 Source */
+	{ 0x063F, 0x0080 },   /* R1599  - AIF1TX4MIX Input 4 Volume */
+	{ 0x0640, 0x0000 },   /* R1600  - AIF1TX5MIX Input 1 Source */
+	{ 0x0641, 0x0080 },   /* R1601  - AIF1TX5MIX Input 1 Volume */
+	{ 0x0642, 0x0000 },   /* R1602  - AIF1TX5MIX Input 2 Source */
+	{ 0x0643, 0x0080 },   /* R1603  - AIF1TX5MIX Input 2 Volume */
+	{ 0x0644, 0x0000 },   /* R1604  - AIF1TX5MIX Input 3 Source */
+	{ 0x0645, 0x0080 },   /* R1605  - AIF1TX5MIX Input 3 Volume */
+	{ 0x0646, 0x0000 },   /* R1606  - AIF1TX5MIX Input 4 Source */
+	{ 0x0647, 0x0080 },   /* R1607  - AIF1TX5MIX Input 4 Volume */
+	{ 0x0648, 0x0000 },   /* R1608  - AIF1TX6MIX Input 1 Source */
+	{ 0x0649, 0x0080 },   /* R1609  - AIF1TX6MIX Input 1 Volume */
+	{ 0x064A, 0x0000 },   /* R1610  - AIF1TX6MIX Input 2 Source */
+	{ 0x064B, 0x0080 },   /* R1611  - AIF1TX6MIX Input 2 Volume */
+	{ 0x064C, 0x0000 },   /* R1612  - AIF1TX6MIX Input 3 Source */
+	{ 0x064D, 0x0080 },   /* R1613  - AIF1TX6MIX Input 3 Volume */
+	{ 0x064E, 0x0000 },   /* R1614  - AIF1TX6MIX Input 4 Source */
+	{ 0x064F, 0x0080 },   /* R1615  - AIF1TX6MIX Input 4 Volume */
+	{ 0x0650, 0x0000 },   /* R1616  - EQLMIX Input 1 Source */
+	{ 0x0651, 0x0080 },   /* R1617  - EQLMIX Input 1 Volume */
+	{ 0x0652, 0x0000 },   /* R1618  - EQLMIX Input 2 Source */
+	{ 0x0653, 0x0080 },   /* R1619  - EQLMIX Input 2 Volume */
+	{ 0x0654, 0x0000 },   /* R1620  - EQLMIX Input 3 Source */
+	{ 0x0655, 0x0080 },   /* R1621  - EQLMIX Input 3 Volume */
+	{ 0x0656, 0x0000 },   /* R1622  - EQLMIX Input 4 Source */
+	{ 0x0657, 0x0080 },   /* R1623  - EQLMIX Input 4 Volume */
+	{ 0x0658, 0x0000 },   /* R1624  - EQRMIX Input 1 Source */
+	{ 0x0659, 0x0080 },   /* R1625  - EQRMIX Input 1 Volume */
+	{ 0x065A, 0x0000 },   /* R1626  - EQRMIX Input 2 Source */
+	{ 0x065B, 0x0080 },   /* R1627  - EQRMIX Input 2 Volume */
+	{ 0x065C, 0x0000 },   /* R1628  - EQRMIX Input 3 Source */
+	{ 0x065D, 0x0080 },   /* R1629  - EQRMIX Input 3 Volume */
+	{ 0x065E, 0x0000 },   /* R1630  - EQRMIX Input 4 Source */
+	{ 0x065F, 0x0080 },   /* R1631  - EQRMIX Input 4 Volume */
+	{ 0x0660, 0x0000 },   /* R1632  - LHPF1MIX Input 1 Source */
+	{ 0x0661, 0x0080 },   /* R1633  - LHPF1MIX Input 1 Volume */
+	{ 0x0662, 0x0000 },   /* R1634  - LHPF1MIX Input 2 Source */
+	{ 0x0663, 0x0080 },   /* R1635  - LHPF1MIX Input 2 Volume */
+	{ 0x0664, 0x0000 },   /* R1636  - LHPF1MIX Input 3 Source */
+	{ 0x0665, 0x0080 },   /* R1637  - LHPF1MIX Input 3 Volume */
+	{ 0x0666, 0x0000 },   /* R1638  - LHPF1MIX Input 4 Source */
+	{ 0x0667, 0x0080 },   /* R1639  - LHPF1MIX Input 4 Volume */
+	{ 0x0668, 0x0000 },   /* R1640  - LHPF2MIX Input 1 Source */
+	{ 0x0669, 0x0080 },   /* R1641  - LHPF2MIX Input 1 Volume */
+	{ 0x066A, 0x0000 },   /* R1642  - LHPF2MIX Input 2 Source */
+	{ 0x066B, 0x0080 },   /* R1643  - LHPF2MIX Input 2 Volume */
+	{ 0x066C, 0x0000 },   /* R1644  - LHPF2MIX Input 3 Source */
+	{ 0x066D, 0x0080 },   /* R1645  - LHPF2MIX Input 3 Volume */
+	{ 0x066E, 0x0000 },   /* R1646  - LHPF2MIX Input 4 Source */
+	{ 0x066F, 0x0080 },   /* R1647  - LHPF2MIX Input 4 Volume */
+	{ 0x0670, 0x0000 },   /* R1648  - DSP1LMIX Input 1 Source */
+	{ 0x0671, 0x0080 },   /* R1649  - DSP1LMIX Input 1 Volume */
+	{ 0x0672, 0x0000 },   /* R1650  - DSP1LMIX Input 2 Source */
+	{ 0x0673, 0x0080 },   /* R1651  - DSP1LMIX Input 2 Volume */
+	{ 0x0674, 0x0000 },   /* R1652  - DSP1LMIX Input 3 Source */
+	{ 0x0675, 0x0080 },   /* R1653  - DSP1LMIX Input 3 Volume */
+	{ 0x0676, 0x0000 },   /* R1654  - DSP1LMIX Input 4 Source */
+	{ 0x0677, 0x0080 },   /* R1655  - DSP1LMIX Input 4 Volume */
+	{ 0x0678, 0x0000 },   /* R1656  - DSP1RMIX Input 1 Source */
+	{ 0x0679, 0x0080 },   /* R1657  - DSP1RMIX Input 1 Volume */
+	{ 0x067A, 0x0000 },   /* R1658  - DSP1RMIX Input 2 Source */
+	{ 0x067B, 0x0080 },   /* R1659  - DSP1RMIX Input 2 Volume */
+	{ 0x067C, 0x0000 },   /* R1660  - DSP1RMIX Input 3 Source */
+	{ 0x067D, 0x0080 },   /* R1661  - DSP1RMIX Input 3 Volume */
+	{ 0x067E, 0x0000 },   /* R1662  - DSP1RMIX Input 4 Source */
+	{ 0x067F, 0x0080 },   /* R1663  - DSP1RMIX Input 4 Volume */
+	{ 0x0680, 0x0000 },   /* R1664  - DSP1AUX1MIX Input 1 Source */
+	{ 0x0681, 0x0000 },   /* R1665  - DSP1AUX2MIX Input 1 Source */
+	{ 0x0682, 0x0000 },   /* R1666  - DSP1AUX3MIX Input 1 Source */
+	{ 0x0683, 0x0000 },   /* R1667  - DSP1AUX4MIX Input 1 Source */
+	{ 0x0684, 0x0000 },   /* R1668  - DSP1AUX5MIX Input 1 Source */
+	{ 0x0685, 0x0000 },   /* R1669  - DSP1AUX6MIX Input 1 Source */
+	{ 0x0686, 0x0000 },   /* R1670  - DSP2LMIX Input 1 Source */
+	{ 0x0687, 0x0080 },   /* R1671  - DSP2LMIX Input 1 Volume */
+	{ 0x0688, 0x0000 },   /* R1672  - DSP2LMIX Input 2 Source */
+	{ 0x0689, 0x0080 },   /* R1673  - DSP2LMIX Input 2 Volume */
+	{ 0x068A, 0x0000 },   /* R1674  - DSP2LMIX Input 3 Source */
+	{ 0x068B, 0x0080 },   /* R1675  - DSP2LMIX Input 3 Volume */
+	{ 0x068C, 0x0000 },   /* R1676  - DSP2LMIX Input 4 Source */
+	{ 0x068D, 0x0080 },   /* R1677  - DSP2LMIX Input 4 Volume */
+	{ 0x068E, 0x0000 },   /* R1678  - DSP2RMIX Input 1 Source */
+	{ 0x068F, 0x0080 },   /* R1679  - DSP2RMIX Input 1 Volume */
+	{ 0x0690, 0x0000 },   /* R1680  - DSP2RMIX Input 2 Source */
+	{ 0x0691, 0x0080 },   /* R1681  - DSP2RMIX Input 2 Volume */
+	{ 0x0692, 0x0000 },   /* R1682  - DSP2RMIX Input 3 Source */
+	{ 0x0693, 0x0080 },   /* R1683  - DSP2RMIX Input 3 Volume */
+	{ 0x0694, 0x0000 },   /* R1684  - DSP2RMIX Input 4 Source */
+	{ 0x0695, 0x0080 },   /* R1685  - DSP2RMIX Input 4 Volume */
+	{ 0x0696, 0x0000 },   /* R1686  - DSP2AUX1MIX Input 1 Source */
+	{ 0x0697, 0x0000 },   /* R1687  - DSP2AUX2MIX Input 1 Source */
+	{ 0x0698, 0x0000 },   /* R1688  - DSP2AUX3MIX Input 1 Source */
+	{ 0x0699, 0x0000 },   /* R1689  - DSP2AUX4MIX Input 1 Source */
+	{ 0x069A, 0x0000 },   /* R1690  - DSP2AUX5MIX Input 1 Source */
+	{ 0x069B, 0x0000 },   /* R1691  - DSP2AUX6MIX Input 1 Source */
+	{ 0x0700, 0xA101 },   /* R1792  - GPIO CTRL 1 */
+	{ 0x0701, 0xA101 },   /* R1793  - GPIO CTRL 2 */
+	{ 0x0702, 0xA101 },   /* R1794  - GPIO CTRL 3 */
+	{ 0x0703, 0xA101 },   /* R1795  - GPIO CTRL 4 */
+	{ 0x0709, 0x0000 },   /* R1801  - Misc Pad Ctrl 1 */
+	{ 0x0801, 0x00FF },   /* R2049  - Interrupt Status 1 Mask */
+	{ 0x0804, 0xFFFF },   /* R2052  - Interrupt Status 2 Mask */
+	{ 0x0808, 0x0000 },   /* R2056  - Interrupt Control */
+	{ 0x0900, 0x0000 },   /* R2304  - EQL_1 */
+	{ 0x0901, 0x0000 },   /* R2305  - EQL_2 */
+	{ 0x0902, 0x0000 },   /* R2306  - EQL_3 */
+	{ 0x0903, 0x0000 },   /* R2307  - EQL_4 */
+	{ 0x0904, 0x0000 },   /* R2308  - EQL_5 */
+	{ 0x0905, 0x0000 },   /* R2309  - EQL_6 */
+	{ 0x0906, 0x0000 },   /* R2310  - EQL_7 */
+	{ 0x0907, 0x0000 },   /* R2311  - EQL_8 */
+	{ 0x0908, 0x0000 },   /* R2312  - EQL_9 */
+	{ 0x0909, 0x0000 },   /* R2313  - EQL_10 */
+	{ 0x090A, 0x0000 },   /* R2314  - EQL_11 */
+	{ 0x090B, 0x0000 },   /* R2315  - EQL_12 */
+	{ 0x090C, 0x0000 },   /* R2316  - EQL_13 */
+	{ 0x090D, 0x0000 },   /* R2317  - EQL_14 */
+	{ 0x090E, 0x0000 },   /* R2318  - EQL_15 */
+	{ 0x090F, 0x0000 },   /* R2319  - EQL_16 */
+	{ 0x0910, 0x0000 },   /* R2320  - EQL_17 */
+	{ 0x0911, 0x0000 },   /* R2321  - EQL_18 */
+	{ 0x0912, 0x0000 },   /* R2322  - EQL_19 */
+	{ 0x0913, 0x0000 },   /* R2323  - EQL_20 */
+	{ 0x0916, 0x0000 },   /* R2326  - EQR_1 */
+	{ 0x0917, 0x0000 },   /* R2327  - EQR_2 */
+	{ 0x0918, 0x0000 },   /* R2328  - EQR_3 */
+	{ 0x0919, 0x0000 },   /* R2329  - EQR_4 */
+	{ 0x091A, 0x0000 },   /* R2330  - EQR_5 */
+	{ 0x091B, 0x0000 },   /* R2331  - EQR_6 */
+	{ 0x091C, 0x0000 },   /* R2332  - EQR_7 */
+	{ 0x091D, 0x0000 },   /* R2333  - EQR_8 */
+	{ 0x091E, 0x0000 },   /* R2334  - EQR_9 */
+	{ 0x091F, 0x0000 },   /* R2335  - EQR_10 */
+	{ 0x0920, 0x0000 },   /* R2336  - EQR_11 */
+	{ 0x0921, 0x0000 },   /* R2337  - EQR_12 */
+	{ 0x0922, 0x0000 },   /* R2338  - EQR_13 */
+	{ 0x0923, 0x0000 },   /* R2339  - EQR_14 */
+	{ 0x0924, 0x0000 },   /* R2340  - EQR_15 */
+	{ 0x0925, 0x0000 },   /* R2341  - EQR_16 */
+	{ 0x0926, 0x0000 },   /* R2342  - EQR_17 */
+	{ 0x0927, 0x0000 },   /* R2343  - EQR_18 */
+	{ 0x0928, 0x0000 },   /* R2344  - EQR_19 */
+	{ 0x0929, 0x0000 },   /* R2345  - EQR_20 */
+	{ 0x093E, 0x0000 },   /* R2366  - HPLPF1_1 */
+	{ 0x093F, 0x0000 },   /* R2367  - HPLPF1_2 */
+	{ 0x0942, 0x0000 },   /* R2370  - HPLPF2_1 */
+	{ 0x0943, 0x0000 },   /* R2371  - HPLPF2_2 */
+	{ 0x0A00, 0x0000 },   /* R2560  - DSP1 Control 1 */
+	{ 0x0A02, 0x0000 },   /* R2562  - DSP1 Control 2 */
+	{ 0x0A03, 0x0000 },   /* R2563  - DSP1 Control 3 */
+	{ 0x0A04, 0x0000 },   /* R2564  - DSP1 Control 4 */
+	{ 0x0A06, 0x0000 },   /* R2566  - DSP1 Control 5 */
+	{ 0x0A07, 0x0000 },   /* R2567  - DSP1 Control 6 */
+	{ 0x0A08, 0x0000 },   /* R2568  - DSP1 Control 7 */
+	{ 0x0A09, 0x0000 },   /* R2569  - DSP1 Control 8 */
+	{ 0x0A0A, 0x0000 },   /* R2570  - DSP1 Control 9 */
+	{ 0x0A0B, 0x0000 },   /* R2571  - DSP1 Control 10 */
+	{ 0x0A0C, 0x0000 },   /* R2572  - DSP1 Control 11 */
+	{ 0x0A0D, 0x0000 },   /* R2573  - DSP1 Control 12 */
+	{ 0x0A0F, 0x0000 },   /* R2575  - DSP1 Control 13 */
+	{ 0x0A10, 0x0000 },   /* R2576  - DSP1 Control 14 */
+	{ 0x0A11, 0x0000 },   /* R2577  - DSP1 Control 15 */
+	{ 0x0A12, 0x0000 },   /* R2578  - DSP1 Control 16 */
+	{ 0x0A13, 0x0000 },   /* R2579  - DSP1 Control 17 */
+	{ 0x0A14, 0x0000 },   /* R2580  - DSP1 Control 18 */
+	{ 0x0A16, 0x0000 },   /* R2582  - DSP1 Control 19 */
+	{ 0x0A17, 0x0000 },   /* R2583  - DSP1 Control 20 */
+	{ 0x0A18, 0x0000 },   /* R2584  - DSP1 Control 21 */
+	{ 0x0A1A, 0x1800 },   /* R2586  - DSP1 Control 22 */
+	{ 0x0A1B, 0x1000 },   /* R2587  - DSP1 Control 23 */
+	{ 0x0A1C, 0x0400 },   /* R2588  - DSP1 Control 24 */
+	{ 0x0A1E, 0x0000 },   /* R2590  - DSP1 Control 25 */
+	{ 0x0A20, 0x0000 },   /* R2592  - DSP1 Control 26 */
+	{ 0x0A21, 0x0000 },   /* R2593  - DSP1 Control 27 */
+	{ 0x0A22, 0x0000 },   /* R2594  - DSP1 Control 28 */
+	{ 0x0A23, 0x0000 },   /* R2595  - DSP1 Control 29 */
+	{ 0x0A24, 0x0000 },   /* R2596  - DSP1 Control 30 */
+	{ 0x0A26, 0x0000 },   /* R2598  - DSP1 Control 31 */
+	{ 0x0B00, 0x0000 },   /* R2816  - DSP2 Control 1 */
+	{ 0x0B02, 0x0000 },   /* R2818  - DSP2 Control 2 */
+	{ 0x0B03, 0x0000 },   /* R2819  - DSP2 Control 3 */
+	{ 0x0B04, 0x0000 },   /* R2820  - DSP2 Control 4 */
+	{ 0x0B06, 0x0000 },   /* R2822  - DSP2 Control 5 */
+	{ 0x0B07, 0x0000 },   /* R2823  - DSP2 Control 6 */
+	{ 0x0B08, 0x0000 },   /* R2824  - DSP2 Control 7 */
+	{ 0x0B09, 0x0000 },   /* R2825  - DSP2 Control 8 */
+	{ 0x0B0A, 0x0000 },   /* R2826  - DSP2 Control 9 */
+	{ 0x0B0B, 0x0000 },   /* R2827  - DSP2 Control 10 */
+	{ 0x0B0C, 0x0000 },   /* R2828  - DSP2 Control 11 */
+	{ 0x0B0D, 0x0000 },   /* R2829  - DSP2 Control 12 */
+	{ 0x0B0F, 0x0000 },   /* R2831  - DSP2 Control 13 */
+	{ 0x0B10, 0x0000 },   /* R2832  - DSP2 Control 14 */
+	{ 0x0B11, 0x0000 },   /* R2833  - DSP2 Control 15 */
+	{ 0x0B12, 0x0000 },   /* R2834  - DSP2 Control 16 */
+	{ 0x0B13, 0x0000 },   /* R2835  - DSP2 Control 17 */
+	{ 0x0B14, 0x0000 },   /* R2836  - DSP2 Control 18 */
+	{ 0x0B16, 0x0000 },   /* R2838  - DSP2 Control 19 */
+	{ 0x0B17, 0x0000 },   /* R2839  - DSP2 Control 20 */
+	{ 0x0B18, 0x0000 },   /* R2840  - DSP2 Control 21 */
+	{ 0x0B1A, 0x0800 },   /* R2842  - DSP2 Control 22 */
+	{ 0x0B1B, 0x1000 },   /* R2843  - DSP2 Control 23 */
+	{ 0x0B1C, 0x0400 },   /* R2844  - DSP2 Control 24 */
+	{ 0x0B1E, 0x0000 },   /* R2846  - DSP2 Control 25 */
+	{ 0x0B20, 0x0000 },   /* R2848  - DSP2 Control 26 */
+	{ 0x0B21, 0x0000 },   /* R2849  - DSP2 Control 27 */
+	{ 0x0B22, 0x0000 },   /* R2850  - DSP2 Control 28 */
+	{ 0x0B23, 0x0000 },   /* R2851  - DSP2 Control 29 */
+	{ 0x0B24, 0x0000 },   /* R2852  - DSP2 Control 30 */
+	{ 0x0B26, 0x0000 },   /* R2854  - DSP2 Control 31 */
+};
+
+static bool wm2200_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM2200_SOFTWARE_RESET:
+	case WM2200_DEVICE_REVISION:
+	case WM2200_ADPS1_IRQ0:
+	case WM2200_ADPS1_IRQ1:
+	case WM2200_INTERRUPT_STATUS_1:
+	case WM2200_INTERRUPT_STATUS_2:
+	case WM2200_INTERRUPT_RAW_STATUS_2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool wm2200_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM2200_SOFTWARE_RESET:
+	case WM2200_DEVICE_REVISION:
+	case WM2200_TONE_GENERATOR_1:
+	case WM2200_CLOCKING_3:
+	case WM2200_CLOCKING_4:
+	case WM2200_FLL_CONTROL_1:
+	case WM2200_FLL_CONTROL_2:
+	case WM2200_FLL_CONTROL_3:
+	case WM2200_FLL_CONTROL_4:
+	case WM2200_FLL_CONTROL_6:
+	case WM2200_FLL_CONTROL_7:
+	case WM2200_FLL_EFS_1:
+	case WM2200_FLL_EFS_2:
+	case WM2200_MIC_CHARGE_PUMP_1:
+	case WM2200_MIC_CHARGE_PUMP_2:
+	case WM2200_DM_CHARGE_PUMP_1:
+	case WM2200_MIC_BIAS_CTRL_1:
+	case WM2200_MIC_BIAS_CTRL_2:
+	case WM2200_EAR_PIECE_CTRL_1:
+	case WM2200_EAR_PIECE_CTRL_2:
+	case WM2200_INPUT_ENABLES:
+	case WM2200_IN1L_CONTROL:
+	case WM2200_IN1R_CONTROL:
+	case WM2200_IN2L_CONTROL:
+	case WM2200_IN2R_CONTROL:
+	case WM2200_IN3L_CONTROL:
+	case WM2200_IN3R_CONTROL:
+	case WM2200_RXANC_SRC:
+	case WM2200_INPUT_VOLUME_RAMP:
+	case WM2200_ADC_DIGITAL_VOLUME_1L:
+	case WM2200_ADC_DIGITAL_VOLUME_1R:
+	case WM2200_ADC_DIGITAL_VOLUME_2L:
+	case WM2200_ADC_DIGITAL_VOLUME_2R:
+	case WM2200_ADC_DIGITAL_VOLUME_3L:
+	case WM2200_ADC_DIGITAL_VOLUME_3R:
+	case WM2200_OUTPUT_ENABLES:
+	case WM2200_DAC_VOLUME_LIMIT_1L:
+	case WM2200_DAC_VOLUME_LIMIT_1R:
+	case WM2200_DAC_VOLUME_LIMIT_2L:
+	case WM2200_DAC_VOLUME_LIMIT_2R:
+	case WM2200_DAC_AEC_CONTROL_1:
+	case WM2200_OUTPUT_VOLUME_RAMP:
+	case WM2200_DAC_DIGITAL_VOLUME_1L:
+	case WM2200_DAC_DIGITAL_VOLUME_1R:
+	case WM2200_DAC_DIGITAL_VOLUME_2L:
+	case WM2200_DAC_DIGITAL_VOLUME_2R:
+	case WM2200_PDM_1:
+	case WM2200_PDM_2:
+	case WM2200_AUDIO_IF_1_1:
+	case WM2200_AUDIO_IF_1_2:
+	case WM2200_AUDIO_IF_1_3:
+	case WM2200_AUDIO_IF_1_4:
+	case WM2200_AUDIO_IF_1_5:
+	case WM2200_AUDIO_IF_1_6:
+	case WM2200_AUDIO_IF_1_7:
+	case WM2200_AUDIO_IF_1_8:
+	case WM2200_AUDIO_IF_1_9:
+	case WM2200_AUDIO_IF_1_10:
+	case WM2200_AUDIO_IF_1_11:
+	case WM2200_AUDIO_IF_1_12:
+	case WM2200_AUDIO_IF_1_13:
+	case WM2200_AUDIO_IF_1_14:
+	case WM2200_AUDIO_IF_1_15:
+	case WM2200_AUDIO_IF_1_16:
+	case WM2200_AUDIO_IF_1_17:
+	case WM2200_AUDIO_IF_1_18:
+	case WM2200_AUDIO_IF_1_19:
+	case WM2200_AUDIO_IF_1_20:
+	case WM2200_AUDIO_IF_1_21:
+	case WM2200_AUDIO_IF_1_22:
+	case WM2200_OUT1LMIX_INPUT_1_SOURCE:
+	case WM2200_OUT1LMIX_INPUT_1_VOLUME:
+	case WM2200_OUT1LMIX_INPUT_2_SOURCE:
+	case WM2200_OUT1LMIX_INPUT_2_VOLUME:
+	case WM2200_OUT1LMIX_INPUT_3_SOURCE:
+	case WM2200_OUT1LMIX_INPUT_3_VOLUME:
+	case WM2200_OUT1LMIX_INPUT_4_SOURCE:
+	case WM2200_OUT1LMIX_INPUT_4_VOLUME:
+	case WM2200_OUT1RMIX_INPUT_1_SOURCE:
+	case WM2200_OUT1RMIX_INPUT_1_VOLUME:
+	case WM2200_OUT1RMIX_INPUT_2_SOURCE:
+	case WM2200_OUT1RMIX_INPUT_2_VOLUME:
+	case WM2200_OUT1RMIX_INPUT_3_SOURCE:
+	case WM2200_OUT1RMIX_INPUT_3_VOLUME:
+	case WM2200_OUT1RMIX_INPUT_4_SOURCE:
+	case WM2200_OUT1RMIX_INPUT_4_VOLUME:
+	case WM2200_OUT2LMIX_INPUT_1_SOURCE:
+	case WM2200_OUT2LMIX_INPUT_1_VOLUME:
+	case WM2200_OUT2LMIX_INPUT_2_SOURCE:
+	case WM2200_OUT2LMIX_INPUT_2_VOLUME:
+	case WM2200_OUT2LMIX_INPUT_3_SOURCE:
+	case WM2200_OUT2LMIX_INPUT_3_VOLUME:
+	case WM2200_OUT2LMIX_INPUT_4_SOURCE:
+	case WM2200_OUT2LMIX_INPUT_4_VOLUME:
+	case WM2200_OUT2RMIX_INPUT_1_SOURCE:
+	case WM2200_OUT2RMIX_INPUT_1_VOLUME:
+	case WM2200_OUT2RMIX_INPUT_2_SOURCE:
+	case WM2200_OUT2RMIX_INPUT_2_VOLUME:
+	case WM2200_OUT2RMIX_INPUT_3_SOURCE:
+	case WM2200_OUT2RMIX_INPUT_3_VOLUME:
+	case WM2200_OUT2RMIX_INPUT_4_SOURCE:
+	case WM2200_OUT2RMIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX1MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX1MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX1MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX1MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX1MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX1MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX1MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX1MIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX2MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX2MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX2MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX2MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX2MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX2MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX2MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX2MIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX3MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX3MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX3MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX3MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX3MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX3MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX3MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX3MIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX4MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX4MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX4MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX4MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX4MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX4MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX4MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX4MIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX5MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX5MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX5MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX5MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX5MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX5MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX5MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX5MIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX6MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX6MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX6MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX6MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX6MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX6MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX6MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX6MIX_INPUT_4_VOLUME:
+	case WM2200_EQLMIX_INPUT_1_SOURCE:
+	case WM2200_EQLMIX_INPUT_1_VOLUME:
+	case WM2200_EQLMIX_INPUT_2_SOURCE:
+	case WM2200_EQLMIX_INPUT_2_VOLUME:
+	case WM2200_EQLMIX_INPUT_3_SOURCE:
+	case WM2200_EQLMIX_INPUT_3_VOLUME:
+	case WM2200_EQLMIX_INPUT_4_SOURCE:
+	case WM2200_EQLMIX_INPUT_4_VOLUME:
+	case WM2200_EQRMIX_INPUT_1_SOURCE:
+	case WM2200_EQRMIX_INPUT_1_VOLUME:
+	case WM2200_EQRMIX_INPUT_2_SOURCE:
+	case WM2200_EQRMIX_INPUT_2_VOLUME:
+	case WM2200_EQRMIX_INPUT_3_SOURCE:
+	case WM2200_EQRMIX_INPUT_3_VOLUME:
+	case WM2200_EQRMIX_INPUT_4_SOURCE:
+	case WM2200_EQRMIX_INPUT_4_VOLUME:
+	case WM2200_LHPF1MIX_INPUT_1_SOURCE:
+	case WM2200_LHPF1MIX_INPUT_1_VOLUME:
+	case WM2200_LHPF1MIX_INPUT_2_SOURCE:
+	case WM2200_LHPF1MIX_INPUT_2_VOLUME:
+	case WM2200_LHPF1MIX_INPUT_3_SOURCE:
+	case WM2200_LHPF1MIX_INPUT_3_VOLUME:
+	case WM2200_LHPF1MIX_INPUT_4_SOURCE:
+	case WM2200_LHPF1MIX_INPUT_4_VOLUME:
+	case WM2200_LHPF2MIX_INPUT_1_SOURCE:
+	case WM2200_LHPF2MIX_INPUT_1_VOLUME:
+	case WM2200_LHPF2MIX_INPUT_2_SOURCE:
+	case WM2200_LHPF2MIX_INPUT_2_VOLUME:
+	case WM2200_LHPF2MIX_INPUT_3_SOURCE:
+	case WM2200_LHPF2MIX_INPUT_3_VOLUME:
+	case WM2200_LHPF2MIX_INPUT_4_SOURCE:
+	case WM2200_LHPF2MIX_INPUT_4_VOLUME:
+	case WM2200_DSP1LMIX_INPUT_1_SOURCE:
+	case WM2200_DSP1LMIX_INPUT_1_VOLUME:
+	case WM2200_DSP1LMIX_INPUT_2_SOURCE:
+	case WM2200_DSP1LMIX_INPUT_2_VOLUME:
+	case WM2200_DSP1LMIX_INPUT_3_SOURCE:
+	case WM2200_DSP1LMIX_INPUT_3_VOLUME:
+	case WM2200_DSP1LMIX_INPUT_4_SOURCE:
+	case WM2200_DSP1LMIX_INPUT_4_VOLUME:
+	case WM2200_DSP1RMIX_INPUT_1_SOURCE:
+	case WM2200_DSP1RMIX_INPUT_1_VOLUME:
+	case WM2200_DSP1RMIX_INPUT_2_SOURCE:
+	case WM2200_DSP1RMIX_INPUT_2_VOLUME:
+	case WM2200_DSP1RMIX_INPUT_3_SOURCE:
+	case WM2200_DSP1RMIX_INPUT_3_VOLUME:
+	case WM2200_DSP1RMIX_INPUT_4_SOURCE:
+	case WM2200_DSP1RMIX_INPUT_4_VOLUME:
+	case WM2200_DSP1AUX1MIX_INPUT_1_SOURCE:
+	case WM2200_DSP1AUX2MIX_INPUT_1_SOURCE:
+	case WM2200_DSP1AUX3MIX_INPUT_1_SOURCE:
+	case WM2200_DSP1AUX4MIX_INPUT_1_SOURCE:
+	case WM2200_DSP1AUX5MIX_INPUT_1_SOURCE:
+	case WM2200_DSP1AUX6MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2LMIX_INPUT_1_SOURCE:
+	case WM2200_DSP2LMIX_INPUT_1_VOLUME:
+	case WM2200_DSP2LMIX_INPUT_2_SOURCE:
+	case WM2200_DSP2LMIX_INPUT_2_VOLUME:
+	case WM2200_DSP2LMIX_INPUT_3_SOURCE:
+	case WM2200_DSP2LMIX_INPUT_3_VOLUME:
+	case WM2200_DSP2LMIX_INPUT_4_SOURCE:
+	case WM2200_DSP2LMIX_INPUT_4_VOLUME:
+	case WM2200_DSP2RMIX_INPUT_1_SOURCE:
+	case WM2200_DSP2RMIX_INPUT_1_VOLUME:
+	case WM2200_DSP2RMIX_INPUT_2_SOURCE:
+	case WM2200_DSP2RMIX_INPUT_2_VOLUME:
+	case WM2200_DSP2RMIX_INPUT_3_SOURCE:
+	case WM2200_DSP2RMIX_INPUT_3_VOLUME:
+	case WM2200_DSP2RMIX_INPUT_4_SOURCE:
+	case WM2200_DSP2RMIX_INPUT_4_VOLUME:
+	case WM2200_DSP2AUX1MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2AUX2MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2AUX3MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2AUX4MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2AUX5MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2AUX6MIX_INPUT_1_SOURCE:
+	case WM2200_GPIO_CTRL_1:
+	case WM2200_GPIO_CTRL_2:
+	case WM2200_GPIO_CTRL_3:
+	case WM2200_GPIO_CTRL_4:
+	case WM2200_ADPS1_IRQ0:
+	case WM2200_ADPS1_IRQ1:
+	case WM2200_MISC_PAD_CTRL_1:
+	case WM2200_INTERRUPT_STATUS_1:
+	case WM2200_INTERRUPT_STATUS_1_MASK:
+	case WM2200_INTERRUPT_STATUS_2:
+	case WM2200_INTERRUPT_RAW_STATUS_2:
+	case WM2200_INTERRUPT_STATUS_2_MASK:
+	case WM2200_INTERRUPT_CONTROL:
+	case WM2200_EQL_1:
+	case WM2200_EQL_2:
+	case WM2200_EQL_3:
+	case WM2200_EQL_4:
+	case WM2200_EQL_5:
+	case WM2200_EQL_6:
+	case WM2200_EQL_7:
+	case WM2200_EQL_8:
+	case WM2200_EQL_9:
+	case WM2200_EQL_10:
+	case WM2200_EQL_11:
+	case WM2200_EQL_12:
+	case WM2200_EQL_13:
+	case WM2200_EQL_14:
+	case WM2200_EQL_15:
+	case WM2200_EQL_16:
+	case WM2200_EQL_17:
+	case WM2200_EQL_18:
+	case WM2200_EQL_19:
+	case WM2200_EQL_20:
+	case WM2200_EQR_1:
+	case WM2200_EQR_2:
+	case WM2200_EQR_3:
+	case WM2200_EQR_4:
+	case WM2200_EQR_5:
+	case WM2200_EQR_6:
+	case WM2200_EQR_7:
+	case WM2200_EQR_8:
+	case WM2200_EQR_9:
+	case WM2200_EQR_10:
+	case WM2200_EQR_11:
+	case WM2200_EQR_12:
+	case WM2200_EQR_13:
+	case WM2200_EQR_14:
+	case WM2200_EQR_15:
+	case WM2200_EQR_16:
+	case WM2200_EQR_17:
+	case WM2200_EQR_18:
+	case WM2200_EQR_19:
+	case WM2200_EQR_20:
+	case WM2200_HPLPF1_1:
+	case WM2200_HPLPF1_2:
+	case WM2200_HPLPF2_1:
+	case WM2200_HPLPF2_2:
+	case WM2200_DSP1_CONTROL_1:
+	case WM2200_DSP1_CONTROL_2:
+	case WM2200_DSP1_CONTROL_3:
+	case WM2200_DSP1_CONTROL_4:
+	case WM2200_DSP1_CONTROL_5:
+	case WM2200_DSP1_CONTROL_6:
+	case WM2200_DSP1_CONTROL_7:
+	case WM2200_DSP1_CONTROL_8:
+	case WM2200_DSP1_CONTROL_9:
+	case WM2200_DSP1_CONTROL_10:
+	case WM2200_DSP1_CONTROL_11:
+	case WM2200_DSP1_CONTROL_12:
+	case WM2200_DSP1_CONTROL_13:
+	case WM2200_DSP1_CONTROL_14:
+	case WM2200_DSP1_CONTROL_15:
+	case WM2200_DSP1_CONTROL_16:
+	case WM2200_DSP1_CONTROL_17:
+	case WM2200_DSP1_CONTROL_18:
+	case WM2200_DSP1_CONTROL_19:
+	case WM2200_DSP1_CONTROL_20:
+	case WM2200_DSP1_CONTROL_21:
+	case WM2200_DSP1_CONTROL_22:
+	case WM2200_DSP1_CONTROL_23:
+	case WM2200_DSP1_CONTROL_24:
+	case WM2200_DSP1_CONTROL_25:
+	case WM2200_DSP1_CONTROL_26:
+	case WM2200_DSP1_CONTROL_27:
+	case WM2200_DSP1_CONTROL_28:
+	case WM2200_DSP1_CONTROL_29:
+	case WM2200_DSP1_CONTROL_30:
+	case WM2200_DSP1_CONTROL_31:
+	case WM2200_DSP2_CONTROL_1:
+	case WM2200_DSP2_CONTROL_2:
+	case WM2200_DSP2_CONTROL_3:
+	case WM2200_DSP2_CONTROL_4:
+	case WM2200_DSP2_CONTROL_5:
+	case WM2200_DSP2_CONTROL_6:
+	case WM2200_DSP2_CONTROL_7:
+	case WM2200_DSP2_CONTROL_8:
+	case WM2200_DSP2_CONTROL_9:
+	case WM2200_DSP2_CONTROL_10:
+	case WM2200_DSP2_CONTROL_11:
+	case WM2200_DSP2_CONTROL_12:
+	case WM2200_DSP2_CONTROL_13:
+	case WM2200_DSP2_CONTROL_14:
+	case WM2200_DSP2_CONTROL_15:
+	case WM2200_DSP2_CONTROL_16:
+	case WM2200_DSP2_CONTROL_17:
+	case WM2200_DSP2_CONTROL_18:
+	case WM2200_DSP2_CONTROL_19:
+	case WM2200_DSP2_CONTROL_20:
+	case WM2200_DSP2_CONTROL_21:
+	case WM2200_DSP2_CONTROL_22:
+	case WM2200_DSP2_CONTROL_23:
+	case WM2200_DSP2_CONTROL_24:
+	case WM2200_DSP2_CONTROL_25:
+	case WM2200_DSP2_CONTROL_26:
+	case WM2200_DSP2_CONTROL_27:
+	case WM2200_DSP2_CONTROL_28:
+	case WM2200_DSP2_CONTROL_29:
+	case WM2200_DSP2_CONTROL_30:
+	case WM2200_DSP2_CONTROL_31:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct reg_default wm2200_reva_patch[] = {
+	{ 0x07, 0x0003 },
+	{ 0x102, 0x0200 },
+	{ 0x203, 0x0084 },
+	{ 0x201, 0x83FF },
+	{ 0x20C, 0x0062 },
+	{ 0x20D, 0x0062 },
+	{ 0x207, 0x2002 },
+	{ 0x208, 0x20C0 },
+	{ 0x21D, 0x01C0 },
+	{ 0x50A, 0x0001 },
+	{ 0x50B, 0x0002 },
+	{ 0x50C, 0x0003 },
+	{ 0x50D, 0x0004 },
+	{ 0x50E, 0x0005 },
+	{ 0x510, 0x0001 },
+	{ 0x511, 0x0002 },
+	{ 0x512, 0x0003 },
+	{ 0x513, 0x0004 },
+	{ 0x514, 0x0005 },
+	{ 0x515, 0x0000 },
+	{ 0x201, 0x8084 },
+	{ 0x202, 0xBBDE },
+	{ 0x203, 0x00EC },
+	{ 0x500, 0x8000 },
+	{ 0x507, 0x1820 },
+	{ 0x508, 0x1820 },
+	{ 0x505, 0x0300 },
+	{ 0x506, 0x0300 },
+	{ 0x302, 0x2280 },
+	{ 0x303, 0x0080 },
+	{ 0x304, 0x2280 },
+	{ 0x305, 0x0080 },
+	{ 0x306, 0x2280 },
+	{ 0x307, 0x0080 },
+	{ 0x401, 0x0080 },
+	{ 0x402, 0x0080 },
+	{ 0x417, 0x3069 },
+	{ 0x900, 0x6318 },
+	{ 0x901, 0x6300 },
+	{ 0x902, 0x0FC8 },
+	{ 0x903, 0x03FE },
+	{ 0x904, 0x00E0 },
+	{ 0x905, 0x1EC4 },
+	{ 0x906, 0xF136 },
+	{ 0x907, 0x0409 },
+	{ 0x908, 0x04CC },
+	{ 0x909, 0x1C9B },
+	{ 0x90A, 0xF337 },
+	{ 0x90B, 0x040B },
+	{ 0x90C, 0x0CBB },
+	{ 0x90D, 0x16F8 },
+	{ 0x90E, 0xF7D9 },
+	{ 0x90F, 0x040A },
+	{ 0x910, 0x1F14 },
+	{ 0x911, 0x058C },
+	{ 0x912, 0x0563 },
+	{ 0x913, 0x4000 },
+	{ 0x916, 0x6318 },
+	{ 0x917, 0x6300 },
+	{ 0x918, 0x0FC8 },
+	{ 0x919, 0x03FE },
+	{ 0x91A, 0x00E0 },
+	{ 0x91B, 0x1EC4 },
+	{ 0x91C, 0xF136 },
+	{ 0x91D, 0x0409 },
+	{ 0x91E, 0x04CC },
+	{ 0x91F, 0x1C9B },
+	{ 0x920, 0xF337 },
+	{ 0x921, 0x040B },
+	{ 0x922, 0x0CBB },
+	{ 0x923, 0x16F8 },
+	{ 0x924, 0xF7D9 },
+	{ 0x925, 0x040A },
+	{ 0x926, 0x1F14 },
+	{ 0x927, 0x058C },
+	{ 0x928, 0x0563 },
+	{ 0x929, 0x4000 },
+	{ 0x709, 0x2000 },
+	{ 0x207, 0x200E },
+	{ 0x208, 0x20D4 },
+	{ 0x20A, 0x0080 },
+	{ 0x07, 0x0000 },
+};
+
+static int wm2200_reset(struct wm2200_priv *wm2200)
+{
+	if (wm2200->pdata.reset) {
+		gpio_set_value_cansleep(wm2200->pdata.reset, 0);
+		gpio_set_value_cansleep(wm2200->pdata.reset, 1);
+
+		return 0;
+	} else {
+		return regmap_write(wm2200->regmap, WM2200_SOFTWARE_RESET,
+				    0x2200);
+	}
+}
+
+static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0);
+
+static const char *wm2200_mixer_texts[] = {
+	"None",
+	"Tone Generator",
+	"AEC loopback",
+	"IN1L",
+	"IN1R",
+	"IN2L",
+	"IN2R",
+	"IN3L",
+	"IN3R",
+	"AIF1RX1",
+	"AIF1RX2",
+	"AIF1RX3",
+	"AIF1RX4",
+	"AIF1RX5",
+	"AIF1RX6",
+	"EQL",
+	"EQR",
+	"LHPF1",
+	"LHPF2",
+	"LHPF3",
+	"LHPF4",
+	"DSP1.1",
+	"DSP1.2",
+	"DSP1.3",
+	"DSP1.4",
+	"DSP1.5",
+	"DSP1.6",
+	"DSP2.1",
+	"DSP2.2",
+	"DSP2.3",
+	"DSP2.4",
+	"DSP2.5",
+	"DSP2.6",
+};
+
+static int wm2200_mixer_values[] = {
+	0x00,
+	0x04,   /* Tone */
+	0x08,   /* AEC */
+	0x10,   /* Input */
+	0x11,
+	0x12,
+	0x13,
+	0x14,
+	0x15,
+	0x20,   /* AIF */
+	0x21,
+	0x22,
+	0x23,
+	0x24,
+	0x25,
+	0x50,   /* EQ */
+	0x51,
+	0x52,
+	0x60,   /* LHPF1 */
+	0x61,   /* LHPF2 */
+	0x68,   /* DSP1 */
+	0x69,
+	0x6a,
+	0x6b,
+	0x6c,
+	0x6d,
+	0x70,   /* DSP2 */
+	0x71,
+	0x72,
+	0x73,
+	0x74,
+	0x75,
+};
+
+#define WM2200_MIXER_CONTROLS(name, base) \
+	SOC_SINGLE_TLV(name " Input 1 Volume", base + 1 , \
+		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
+	SOC_SINGLE_TLV(name " Input 2 Volume", base + 3 , \
+		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
+	SOC_SINGLE_TLV(name " Input 3 Volume", base + 5 , \
+		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
+	SOC_SINGLE_TLV(name " Input 4 Volume", base + 7 , \
+		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv)
+
+#define WM2200_MUX_ENUM_DECL(name, reg) \
+	SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff, 			\
+				   wm2200_mixer_texts, wm2200_mixer_values)
+
+#define WM2200_MUX_CTL_DECL(name) \
+	const struct snd_kcontrol_new name##_mux =	\
+		SOC_DAPM_VALUE_ENUM("Route", name##_enum)
+
+#define WM2200_MIXER_ENUMS(name, base_reg) \
+	static WM2200_MUX_ENUM_DECL(name##_in1_enum, base_reg);	     \
+	static WM2200_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2);  \
+	static WM2200_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4);  \
+	static WM2200_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6);  \
+	static WM2200_MUX_CTL_DECL(name##_in1); \
+	static WM2200_MUX_CTL_DECL(name##_in2); \
+	static WM2200_MUX_CTL_DECL(name##_in3); \
+	static WM2200_MUX_CTL_DECL(name##_in4)
+
+static const struct snd_kcontrol_new wm2200_snd_controls[] = {
+SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL,
+	   WM2200_IN1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN2 High Performance Switch", WM2200_IN2L_CONTROL,
+	   WM2200_IN2_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN3 High Performance Switch", WM2200_IN3L_CONTROL,
+	   WM2200_IN3_OSR_SHIFT, 1, 0),
+
+SOC_DOUBLE_R_TLV("IN1 Volume", WM2200_IN1L_CONTROL, WM2200_IN1R_CONTROL,
+		 WM2200_IN1L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv),
+SOC_DOUBLE_R_TLV("IN2 Volume", WM2200_IN2L_CONTROL, WM2200_IN2R_CONTROL,
+		 WM2200_IN2L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv),
+SOC_DOUBLE_R_TLV("IN3 Volume", WM2200_IN3L_CONTROL, WM2200_IN3R_CONTROL,
+		 WM2200_IN3L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv),
+
+SOC_DOUBLE_R("IN1 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
+	     WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
+	     WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
+	     WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("IN1 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_1L,
+		 WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_DIG_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("IN2 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_2L,
+		 WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_DIG_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("IN3 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_3L,
+		 WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_DIG_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+
+SOC_SINGLE("OUT1 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_1L,
+	   WM2200_OUT1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("OUT2 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_2L,
+	   WM2200_OUT2_OSR_SHIFT, 1, 0),
+
+SOC_DOUBLE_R("OUT1 Digital Switch", WM2200_DAC_DIGITAL_VOLUME_1L,
+	     WM2200_DAC_DIGITAL_VOLUME_1R, WM2200_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R_TLV("OUT1 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_1L,
+		 WM2200_DAC_DIGITAL_VOLUME_1R, WM2200_OUT1L_VOL_SHIFT, 0x9f, 0,
+		 digital_tlv),
+SOC_DOUBLE_R_TLV("OUT1 Volume", WM2200_DAC_VOLUME_LIMIT_1L,
+		 WM2200_DAC_VOLUME_LIMIT_1R, WM2200_OUT1L_PGA_VOL_SHIFT,
+		 0x46, 0, out_tlv),
+
+SOC_DOUBLE_R("OUT2 Digital Switch", WM2200_DAC_DIGITAL_VOLUME_2L,
+	     WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L,
+		 WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_VOL_SHIFT, 0x9f, 0,
+		 digital_tlv),
+SOC_DOUBLE("OUT2 Switch", WM2200_PDM_1, WM2200_SPK1L_MUTE_SHIFT,
+	   WM2200_SPK1R_MUTE_SHIFT, 1, 0),
+};
+
+WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(OUT1R, WM2200_OUT1RMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(OUT2L, WM2200_OUT2LMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(OUT2R, WM2200_OUT2RMIX_INPUT_1_SOURCE);
+
+WM2200_MIXER_ENUMS(AIF1TX1, WM2200_AIF1TX1MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(AIF1TX2, WM2200_AIF1TX2MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(AIF1TX3, WM2200_AIF1TX3MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(AIF1TX4, WM2200_AIF1TX4MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(AIF1TX5, WM2200_AIF1TX5MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(AIF1TX6, WM2200_AIF1TX6MIX_INPUT_1_SOURCE);
+
+WM2200_MIXER_ENUMS(EQL, WM2200_EQLMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(EQR, WM2200_EQRMIX_INPUT_1_SOURCE);
+
+WM2200_MIXER_ENUMS(DSP1L, WM2200_DSP1LMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(DSP1R, WM2200_DSP1RMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(DSP2L, WM2200_DSP2LMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(DSP2R, WM2200_DSP2RMIX_INPUT_1_SOURCE);
+
+WM2200_MIXER_ENUMS(LHPF1, WM2200_LHPF1MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE);
+
+#define WM2200_MUX(name, ctrl) \
+	SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+
+#define WM2200_MIXER_WIDGETS(name, name_str)	\
+	WM2200_MUX(name_str " Input 1", &name##_in1_mux), \
+	WM2200_MUX(name_str " Input 2", &name##_in2_mux), \
+	WM2200_MUX(name_str " Input 3", &name##_in3_mux), \
+	WM2200_MUX(name_str " Input 4", &name##_in4_mux), \
+	SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
+
+#define WM2200_MIXER_INPUT_ROUTES(name)	\
+	{ name, "Tone Generator", "Tone Generator" }, \
+        { name, "IN1L", "IN1L PGA" }, \
+        { name, "IN1R", "IN1R PGA" }, \
+        { name, "IN2L", "IN2L PGA" }, \
+        { name, "IN2R", "IN2R PGA" }, \
+        { name, "IN3L", "IN3L PGA" }, \
+        { name, "IN3R", "IN3R PGA" }, \
+        { name, "DSP1.1", "DSP1" }, \
+        { name, "DSP1.2", "DSP1" }, \
+        { name, "DSP1.3", "DSP1" }, \
+        { name, "DSP1.4", "DSP1" }, \
+        { name, "DSP1.5", "DSP1" }, \
+        { name, "DSP1.6", "DSP1" }, \
+        { name, "DSP2.1", "DSP2" }, \
+        { name, "DSP2.2", "DSP2" }, \
+        { name, "DSP2.3", "DSP2" }, \
+        { name, "DSP2.4", "DSP2" }, \
+        { name, "DSP2.5", "DSP2" }, \
+        { name, "DSP2.6", "DSP2" }, \
+        { name, "AIF1RX1", "AIF1RX1" }, \
+        { name, "AIF1RX2", "AIF1RX2" }, \
+        { name, "AIF1RX3", "AIF1RX3" }, \
+        { name, "AIF1RX4", "AIF1RX4" }, \
+        { name, "AIF1RX5", "AIF1RX5" }, \
+        { name, "AIF1RX6", "AIF1RX6" }, \
+        { name, "EQL", "EQL" }, \
+        { name, "EQR", "EQR" }, \
+        { name, "LHPF1", "LHPF1" }, \
+        { name, "LHPF2", "LHPF2" }
+
+#define WM2200_MIXER_ROUTES(widget, name) \
+	{ widget, NULL, name " Mixer" },         \
+	{ name " Mixer", NULL, name " Input 1" }, \
+	{ name " Mixer", NULL, name " Input 2" }, \
+	{ name " Mixer", NULL, name " Input 3" }, \
+	{ name " Mixer", NULL, name " Input 4" }, \
+	WM2200_MIXER_INPUT_ROUTES(name " Input 1"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Input 2"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Input 3"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Input 4")
+
+static const struct snd_soc_dapm_widget wm2200_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM2200_CLOCKING_3, WM2200_SYSCLK_ENA_SHIFT, 0,
+		    NULL, 0),
+SND_SOC_DAPM_SUPPLY("CP1", WM2200_DM_CHARGE_PUMP_1, WM2200_CPDM_ENA_SHIFT, 0,
+		    NULL, 0),
+SND_SOC_DAPM_SUPPLY("CP2", WM2200_MIC_CHARGE_PUMP_1, WM2200_CPMIC_ENA_SHIFT, 0,
+		    NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS1", WM2200_MIC_BIAS_CTRL_1, WM2200_MICB1_ENA_SHIFT,
+		    0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", WM2200_MIC_BIAS_CTRL_2, WM2200_MICB2_ENA_SHIFT,
+		    0, NULL, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20),
+SND_SOC_DAPM_REGULATOR_SUPPLY("AVDD", 20),
+
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_PGA("Tone Generator", WM2200_TONE_GENERATOR_1,
+		 WM2200_TONE_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("IN1L PGA", WM2200_INPUT_ENABLES, WM2200_IN1L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("IN1R PGA", WM2200_INPUT_ENABLES, WM2200_IN1R_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("IN2L PGA", WM2200_INPUT_ENABLES, WM2200_IN2L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("IN2R PGA", WM2200_INPUT_ENABLES, WM2200_IN2R_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("IN3L PGA", WM2200_INPUT_ENABLES, WM2200_IN3L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("IN3R PGA", WM2200_INPUT_ENABLES, WM2200_IN3R_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", "Playback", 0,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", "Playback", 1,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", "Playback", 2,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", "Playback", 3,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", "Playback", 4,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", "Playback", 5,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_PGA("EQL", WM2200_EQL_1, WM2200_EQL_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQR", WM2200_EQR_1, WM2200_EQR_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", WM2200_HPLPF1_1, WM2200_LHPF1_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", WM2200_HPLPF2_1, WM2200_LHPF2_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA_E("DSP1", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0),
+SND_SOC_DAPM_PGA_E("DSP2", SND_SOC_NOPM, 1, 0, NULL, 0, NULL, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", "Capture", 1,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", "Capture", 2,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", "Capture", 3,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 4,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 5,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_PGA_S("OUT1L", 0, WM2200_OUTPUT_ENABLES,
+		   WM2200_OUT1L_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("OUT1R", 0, WM2200_OUTPUT_ENABLES,
+		   WM2200_OUT1R_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("EPD_LP", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_LP_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_OUTP_LP", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_OUTP_LP_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_LP", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_RMV_SHRT_LP_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("EPD_LN", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_LN_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_OUTP_LN", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_OUTP_LN_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_LN", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_RMV_SHRT_LN_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("EPD_RP", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_RP_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_OUTP_RP", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_OUTP_RP_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_RP", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_RMV_SHRT_RP_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("EPD_RN", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_RN_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_OUTP_RN", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_OUTP_RN_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_RN", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_RMV_SHRT_RN_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("OUT2L", WM2200_OUTPUT_ENABLES, WM2200_OUT2L_ENA_SHIFT,
+		 0, NULL, 0),
+SND_SOC_DAPM_PGA("OUT2R", WM2200_OUTPUT_ENABLES, WM2200_OUT2R_ENA_SHIFT,
+		 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("EPOUTLN"),
+SND_SOC_DAPM_OUTPUT("EPOUTLP"),
+SND_SOC_DAPM_OUTPUT("EPOUTRN"),
+SND_SOC_DAPM_OUTPUT("EPOUTRP"),
+SND_SOC_DAPM_OUTPUT("SPK"),
+
+WM2200_MIXER_WIDGETS(EQL, "EQL"),
+WM2200_MIXER_WIDGETS(EQR, "EQR"),
+
+WM2200_MIXER_WIDGETS(LHPF1, "LHPF1"),
+WM2200_MIXER_WIDGETS(LHPF2, "LHPF2"),
+
+WM2200_MIXER_WIDGETS(DSP1L, "DSP1L"),
+WM2200_MIXER_WIDGETS(DSP1R, "DSP1R"),
+WM2200_MIXER_WIDGETS(DSP2L, "DSP2L"),
+WM2200_MIXER_WIDGETS(DSP2R, "DSP2R"),
+
+WM2200_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+WM2200_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+WM2200_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+WM2200_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+WM2200_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+WM2200_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+
+WM2200_MIXER_WIDGETS(OUT1L, "OUT1L"),
+WM2200_MIXER_WIDGETS(OUT1R, "OUT1R"),
+WM2200_MIXER_WIDGETS(OUT2L, "OUT2L"),
+WM2200_MIXER_WIDGETS(OUT2R, "OUT2R"),
+};
+
+static const struct snd_soc_dapm_route wm2200_dapm_routes[] = {
+	/* Everything needs SYSCLK but only hook up things on the edge
+	 * of the chip */
+	{ "IN1L", NULL, "SYSCLK" },
+	{ "IN1R", NULL, "SYSCLK" },
+	{ "IN2L", NULL, "SYSCLK" },
+	{ "IN2R", NULL, "SYSCLK" },
+	{ "IN3L", NULL, "SYSCLK" },
+	{ "IN3R", NULL, "SYSCLK" },
+	{ "OUT1L", NULL, "SYSCLK" },
+	{ "OUT1R", NULL, "SYSCLK" },
+	{ "OUT2L", NULL, "SYSCLK" },
+	{ "OUT2R", NULL, "SYSCLK" },
+	{ "AIF1RX1", NULL, "SYSCLK" },
+	{ "AIF1RX2", NULL, "SYSCLK" },
+	{ "AIF1RX3", NULL, "SYSCLK" },
+	{ "AIF1RX4", NULL, "SYSCLK" },
+	{ "AIF1RX5", NULL, "SYSCLK" },
+	{ "AIF1RX6", NULL, "SYSCLK" },
+	{ "AIF1TX1", NULL, "SYSCLK" },
+	{ "AIF1TX2", NULL, "SYSCLK" },
+	{ "AIF1TX3", NULL, "SYSCLK" },
+	{ "AIF1TX4", NULL, "SYSCLK" },
+	{ "AIF1TX5", NULL, "SYSCLK" },
+	{ "AIF1TX6", NULL, "SYSCLK" },
+
+	{ "IN1L", NULL, "AVDD" },
+	{ "IN1R", NULL, "AVDD" },
+	{ "IN2L", NULL, "AVDD" },
+	{ "IN2R", NULL, "AVDD" },
+	{ "IN3L", NULL, "AVDD" },
+	{ "IN3R", NULL, "AVDD" },
+	{ "OUT1L", NULL, "AVDD" },
+	{ "OUT1R", NULL, "AVDD" },
+
+	{ "IN1L PGA", NULL, "IN1L" },
+	{ "IN1R PGA", NULL, "IN1R" },
+	{ "IN2L PGA", NULL, "IN2L" },
+	{ "IN2R PGA", NULL, "IN2R" },
+	{ "IN3L PGA", NULL, "IN3L" },
+	{ "IN3R PGA", NULL, "IN3R" },
+
+	{ "Tone Generator", NULL, "TONE" },
+
+	{ "CP2", NULL, "CPVDD" },
+	{ "MICBIAS1", NULL, "CP2" },
+	{ "MICBIAS2", NULL, "CP2" },
+
+	{ "CP1", NULL, "CPVDD" },
+	{ "EPD_LN", NULL, "CP1" },
+	{ "EPD_LP", NULL, "CP1" },
+	{ "EPD_RN", NULL, "CP1" },
+	{ "EPD_RP", NULL, "CP1" },
+
+	{ "EPD_LP", NULL, "OUT1L" },
+	{ "EPD_OUTP_LP", NULL, "EPD_LP" },
+	{ "EPD_RMV_SHRT_LP", NULL, "EPD_OUTP_LP" },
+	{ "EPOUTLP", NULL, "EPD_RMV_SHRT_LP" },
+
+	{ "EPD_LN", NULL, "OUT1L" },
+	{ "EPD_OUTP_LN", NULL, "EPD_LN" },
+	{ "EPD_RMV_SHRT_LN", NULL, "EPD_OUTP_LN" },
+	{ "EPOUTLN", NULL, "EPD_RMV_SHRT_LN" },
+
+	{ "EPD_RP", NULL, "OUT1R" },
+	{ "EPD_OUTP_RP", NULL, "EPD_RP" },
+	{ "EPD_RMV_SHRT_RP", NULL, "EPD_OUTP_RP" },
+	{ "EPOUTRP", NULL, "EPD_RMV_SHRT_RP" },
+
+	{ "EPD_RN", NULL, "OUT1R" },
+	{ "EPD_OUTP_RN", NULL, "EPD_RN" },
+	{ "EPD_RMV_SHRT_RN", NULL, "EPD_OUTP_RN" },
+	{ "EPOUTRN", NULL, "EPD_RMV_SHRT_RN" },
+
+	{ "SPK", NULL, "OUT2L" },
+	{ "SPK", NULL, "OUT2R" },
+
+	WM2200_MIXER_ROUTES("DSP1", "DSP1L"),
+	WM2200_MIXER_ROUTES("DSP1", "DSP1R"),
+	WM2200_MIXER_ROUTES("DSP2", "DSP2L"),
+	WM2200_MIXER_ROUTES("DSP2", "DSP2R"),
+
+	WM2200_MIXER_ROUTES("OUT1L", "OUT1L"),
+	WM2200_MIXER_ROUTES("OUT1R", "OUT1R"),
+	WM2200_MIXER_ROUTES("OUT2L", "OUT2L"),
+	WM2200_MIXER_ROUTES("OUT2R", "OUT2R"),
+
+	WM2200_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+	WM2200_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+	WM2200_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+	WM2200_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+	WM2200_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+	WM2200_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+
+	WM2200_MIXER_ROUTES("EQL", "EQL"),
+	WM2200_MIXER_ROUTES("EQR", "EQR"),
+
+	WM2200_MIXER_ROUTES("LHPF1", "LHPF1"),
+	WM2200_MIXER_ROUTES("LHPF2", "LHPF2"),
+};
+
+static int wm2200_probe(struct snd_soc_codec *codec)
+{
+	struct wm2200_priv *wm2200 = dev_get_drvdata(codec->dev);
+	int ret;
+
+	wm2200->codec = codec;
+	codec->control_data = wm2200->regmap;
+	codec->dapm.bias_level = SND_SOC_BIAS_OFF;
+
+	ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	int lrclk, bclk, fmt_val;
+
+	lrclk = 0;
+	bclk = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		fmt_val = 0;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		fmt_val = 1;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		fmt_val = 2;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		fmt_val = 3;
+		break;
+	default:
+		dev_err(codec->dev, "Unsupported DAI format %d\n",
+			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		lrclk |= WM2200_AIF1TX_LRCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		bclk |= WM2200_AIF1_BCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		lrclk |= WM2200_AIF1TX_LRCLK_MSTR;
+		bclk |= WM2200_AIF1_BCLK_MSTR;
+		break;
+	default:
+		dev_err(codec->dev, "Unsupported master mode %d\n",
+			fmt & SND_SOC_DAIFMT_MASTER_MASK);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		bclk |= WM2200_AIF1_BCLK_INV;
+		lrclk |= WM2200_AIF1TX_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		bclk |= WM2200_AIF1_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		lrclk |= WM2200_AIF1TX_LRCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_1, WM2200_AIF1_BCLK_MSTR |
+			    WM2200_AIF1_BCLK_INV, bclk);
+	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_2,
+			    WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV,
+			    lrclk);
+	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_3,
+			    WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV,
+			    lrclk);
+	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_5,
+			    WM2200_AIF1_FMT_MASK << 1, fmt_val << 1);
+
+	return 0;
+}
+
+static int wm2200_sr_code[] = {
+	0,
+	12000,
+	24000,
+	48000,
+	96000,
+	192000,
+	384000,
+	768000,
+	0,
+	11025,
+	22050,
+	44100,
+	88200,
+	176400,
+	352800,
+	705600,
+	4000,
+	8000,
+	16000,
+	32000,
+	64000,
+	128000,
+	256000,
+	512000,
+};
+
+#define WM2200_NUM_BCLK_RATES 12
+
+static int wm2200_bclk_rates_dat[WM2200_NUM_BCLK_RATES] = {
+	6144000,
+	3072000,
+	2048000,
+	1536000,
+	768000,
+	512000,
+	384000,
+	256000,
+	192000,
+	128000,
+	96000,
+	64000,
+};	
+
+static int wm2200_bclk_rates_cd[WM2200_NUM_BCLK_RATES] = {
+	5644800,
+	2882400,
+	1881600,
+	1411200,
+	705600,
+	470400,
+	352800,
+	176400,
+	117600,
+	88200,
+	58800,
+};
+
+static int wm2200_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 wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
+	int i, bclk, lrclk, wl, fl, sr_code;
+	int *bclk_rates;
+
+	/* Data sizes if not using TDM */
+	wl = snd_pcm_format_width(params_format(params));
+	if (wl < 0)
+		return wl;
+	fl = snd_soc_params_to_frame_size(params);
+	if (fl < 0)
+		return fl;
+
+	dev_dbg(codec->dev, "Word length %d bits, frame length %d bits\n",
+		wl, fl);
+
+	/* Target BCLK rate */
+	bclk = snd_soc_params_to_bclk(params);
+	if (bclk < 0)
+		return bclk;
+
+	if (!wm2200->sysclk) {
+		dev_err(codec->dev, "SYSCLK has no rate set\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm2200_sr_code); i++)
+		if (wm2200_sr_code[i] == params_rate(params))
+			break;
+	if (i == ARRAY_SIZE(wm2200_sr_code)) {
+		dev_err(codec->dev, "Unsupported sample rate: %dHz\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+	sr_code = i;
+
+	dev_dbg(codec->dev, "Target BCLK is %dHz, using %dHz SYSCLK\n",
+		bclk, wm2200->sysclk);
+
+	if (wm2200->sysclk % 4000)
+		bclk_rates = wm2200_bclk_rates_cd;
+	else
+		bclk_rates = wm2200_bclk_rates_dat;
+
+	for (i = 0; i < WM2200_NUM_BCLK_RATES; i++)
+		if (bclk_rates[i] >= bclk && (bclk_rates[i] % bclk == 0))
+			break;
+	if (i == WM2200_NUM_BCLK_RATES) {
+		dev_err(codec->dev,
+			"No valid BCLK for %dHz found from %dHz SYSCLK\n",
+			bclk, wm2200->sysclk);
+		return -EINVAL;
+	}
+
+	bclk = i;
+	dev_dbg(codec->dev, "Setting %dHz BCLK\n", bclk_rates[bclk]);
+	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_1,
+			    WM2200_AIF1_BCLK_DIV_MASK, bclk);
+
+	lrclk = bclk_rates[bclk] / params_rate(params);
+	dev_dbg(codec->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+	    dai->symmetric_rates)
+		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_7,
+				    WM2200_AIF1RX_BCPF_MASK, lrclk);
+	else
+		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_6,
+				    WM2200_AIF1TX_BCPF_MASK, lrclk);
+
+	i = (wl << WM2200_AIF1TX_WL_SHIFT) | wl;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_9,
+				    WM2200_AIF1RX_WL_MASK |
+				    WM2200_AIF1RX_SLOT_LEN_MASK, i);
+	else
+		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_8,
+				    WM2200_AIF1TX_WL_MASK |
+				    WM2200_AIF1TX_SLOT_LEN_MASK, i);
+
+	snd_soc_update_bits(codec, WM2200_CLOCKING_4,
+			    WM2200_SAMPLE_RATE_1_MASK, sr_code);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops wm2200_dai_ops = {
+	.set_fmt = wm2200_set_fmt,
+	.hw_params = wm2200_hw_params,
+};
+
+static int wm2200_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+			     int source, unsigned int freq, int dir)
+{
+	struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
+	int fval;
+
+	switch (clk_id) {
+	case WM2200_CLK_SYSCLK:
+		break;
+
+	default:
+		dev_err(codec->dev, "Unknown clock %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	switch (source) {
+	case WM2200_CLKSRC_MCLK1:
+	case WM2200_CLKSRC_MCLK2:
+	case WM2200_CLKSRC_FLL:
+	case WM2200_CLKSRC_BCLK1:
+		break;
+	default:
+		dev_err(codec->dev, "Invalid source %d\n", source);
+		return -EINVAL;
+	}
+
+	switch (freq) {
+	case 22579200:
+	case 24576000:
+		fval = 2;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid clock rate: %d\n", freq);
+		return -EINVAL;
+	}
+
+	/* TODO: Check if MCLKs are in use and enable/disable pulls to
+	 * match.
+	 */
+
+	snd_soc_update_bits(codec, WM2200_CLOCKING_3, WM2200_SYSCLK_FREQ_MASK |
+			    WM2200_SYSCLK_SRC_MASK,
+			    fval << WM2200_SYSCLK_FREQ_SHIFT | source);
+
+	wm2200->sysclk = freq;
+
+	return 0;
+}
+
+struct _fll_div {
+	u16 fll_fratio;
+	u16 fll_outdiv;
+	u16 fll_refclk_div;
+	u16 n;
+	u16 theta;
+	u16 lambda;
+};
+
+static struct {
+	unsigned int min;
+	unsigned int max;
+	u16 fll_fratio;
+	int ratio;
+} fll_fratios[] = {
+	{       0,    64000, 4, 16 },
+	{   64000,   128000, 3,  8 },
+	{  128000,   256000, 2,  4 },
+	{  256000,  1000000, 1,  2 },
+	{ 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+		       unsigned int Fout)
+{
+	unsigned int target;
+	unsigned int div;
+	unsigned int fratio, gcd_fll;
+	int i;
+
+	/* Fref must be <=13.5MHz */
+	div = 1;
+	fll_div->fll_refclk_div = 0;
+	while ((Fref / div) > 13500000) {
+		div *= 2;
+		fll_div->fll_refclk_div++;
+
+		if (div > 8) {
+			pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+			       Fref);
+			return -EINVAL;
+		}
+	}
+
+	pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+	/* Apply the division for our remaining calculations */
+	Fref /= div;
+
+	/* Fvco should be 90-100MHz; don't check the upper bound */
+	div = 2;
+	while (Fout * div < 90000000) {
+		div++;
+		if (div > 64) {
+			pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+			       Fout);
+			return -EINVAL;
+		}
+	}
+	target = Fout * div;
+	fll_div->fll_outdiv = div - 1;
+
+	pr_debug("FLL Fvco=%dHz\n", target);
+
+	/* Find an appropraite FLL_FRATIO and factor it out of the target */
+	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+			fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+			fratio = fll_fratios[i].ratio;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(fll_fratios)) {
+		pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+		return -EINVAL;
+	}
+
+	fll_div->n = target / (fratio * Fref);
+
+	if (target % Fref == 0) {
+		fll_div->theta = 0;
+		fll_div->lambda = 0;
+	} else {
+		gcd_fll = gcd(target, fratio * Fref);
+
+		fll_div->theta = (target - (fll_div->n * fratio * Fref))
+			/ gcd_fll;
+		fll_div->lambda = (fratio * Fref) / gcd_fll;
+	}
+
+	pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+		 fll_div->n, fll_div->theta, fll_div->lambda);
+	pr_debug("FLL_FRATIO=%x(%d) FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+		 fll_div->fll_fratio, fratio, fll_div->fll_outdiv,
+		 fll_div->fll_refclk_div);
+
+	return 0;
+}
+
+static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+			  unsigned int Fref, unsigned int Fout)
+{
+	struct i2c_client *i2c = to_i2c_client(codec->dev);
+	struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
+	struct _fll_div factors;
+	int ret, i, timeout;
+
+	if (!Fout) {
+		dev_dbg(codec->dev, "FLL disabled");
+
+		if (wm2200->fll_fout)
+			pm_runtime_put(codec->dev);
+
+		wm2200->fll_fout = 0;
+		snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1,
+				    WM2200_FLL_ENA, 0);
+		return 0;
+	}
+
+	switch (source) {
+	case WM2200_FLL_SRC_MCLK1:
+	case WM2200_FLL_SRC_MCLK2:
+	case WM2200_FLL_SRC_BCLK:
+		break;
+	default:
+		dev_err(codec->dev, "Invalid FLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = fll_factors(&factors, Fref, Fout);
+	if (ret < 0)
+		return ret;
+
+	/* Disable the FLL while we reconfigure */
+	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1, WM2200_FLL_ENA, 0);
+
+	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_2,
+			    WM2200_FLL_OUTDIV_MASK | WM2200_FLL_FRATIO_MASK,
+			    (factors.fll_outdiv << WM2200_FLL_OUTDIV_SHIFT) |
+			    factors.fll_fratio);
+	if (factors.theta) {
+		snd_soc_update_bits(codec, WM2200_FLL_CONTROL_3,
+				    WM2200_FLL_FRACN_ENA,
+				    WM2200_FLL_FRACN_ENA);
+		snd_soc_update_bits(codec, WM2200_FLL_EFS_2,
+				    WM2200_FLL_EFS_ENA,
+				    WM2200_FLL_EFS_ENA);
+	} else {
+		snd_soc_update_bits(codec, WM2200_FLL_CONTROL_3,
+				    WM2200_FLL_FRACN_ENA, 0);
+		snd_soc_update_bits(codec, WM2200_FLL_EFS_2,
+				    WM2200_FLL_EFS_ENA, 0);
+	}
+
+	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_4, WM2200_FLL_THETA_MASK,
+			    factors.theta);
+	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_6, WM2200_FLL_N_MASK,
+			    factors.n);
+	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_7,
+			    WM2200_FLL_CLK_REF_DIV_MASK |
+			    WM2200_FLL_CLK_REF_SRC_MASK,
+			    (factors.fll_refclk_div
+			     << WM2200_FLL_CLK_REF_DIV_SHIFT) | source);
+	snd_soc_update_bits(codec, WM2200_FLL_EFS_1,
+			    WM2200_FLL_LAMBDA_MASK, factors.lambda);
+
+	/* Clear any pending completions */
+	try_wait_for_completion(&wm2200->fll_lock);
+
+	pm_runtime_get_sync(codec->dev);
+
+	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1,
+			    WM2200_FLL_ENA, WM2200_FLL_ENA);
+
+	if (i2c->irq)
+		timeout = 2;
+	else
+		timeout = 50;
+
+	snd_soc_update_bits(codec, WM2200_CLOCKING_3, WM2200_SYSCLK_ENA,
+			    WM2200_SYSCLK_ENA);
+
+	/* Poll for the lock; will use the interrupt to exit quickly */
+	for (i = 0; i < timeout; i++) {
+		if (i2c->irq) {
+			ret = wait_for_completion_timeout(&wm2200->fll_lock,
+							  msecs_to_jiffies(25));
+			if (ret > 0)
+				break;
+		} else {
+			msleep(1);
+		}
+
+		ret = snd_soc_read(codec,
+				   WM2200_INTERRUPT_RAW_STATUS_2);
+		if (ret < 0) {
+			dev_err(codec->dev,
+				"Failed to read FLL status: %d\n",
+				ret);
+			continue;
+		}
+		if (ret & WM2200_FLL_LOCK_STS)
+			break;
+	}
+	if (i == timeout) {
+		dev_err(codec->dev, "FLL lock timed out\n");
+		pm_runtime_put(codec->dev);
+		return -ETIMEDOUT;
+	}
+
+	wm2200->fll_src = source;
+	wm2200->fll_fref = Fref;
+	wm2200->fll_fout = Fout;
+
+	dev_dbg(codec->dev, "FLL running %dHz->%dHz\n", Fref, Fout);
+
+	return 0;
+}
+
+static int wm2200_dai_probe(struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned int val = 0;
+	int ret;
+
+	ret = snd_soc_read(codec, WM2200_GPIO_CTRL_1);
+	if (ret >= 0) {
+		if ((ret & WM2200_GP1_FN_MASK) != 0) {
+			dai->symmetric_rates = true;
+			val = WM2200_AIF1TX_LRCLK_SRC;
+		}
+	} else {
+		dev_err(codec->dev, "Failed to read GPIO 1 config: %d\n", ret);
+	}
+
+	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_2,
+			    WM2200_AIF1TX_LRCLK_SRC, val);
+
+	return 0;
+}
+
+#define WM2200_RATES SNDRV_PCM_RATE_8000_48000
+
+#define WM2200_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 wm2200_dai = {
+	.name = "wm2200",
+	.probe = wm2200_dai_probe,
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM2200_RATES,
+		.formats = WM2200_FORMATS,
+	},
+	.capture = {
+		 .stream_name = "Capture",
+		 .channels_min = 2,
+		 .channels_max = 2,
+		 .rates = WM2200_RATES,
+		 .formats = WM2200_FORMATS,
+	 },
+	.ops = &wm2200_dai_ops,
+};
+
+static struct snd_soc_codec_driver soc_codec_wm2200 = {
+	.probe = wm2200_probe,
+
+	.idle_bias_off = true,
+	.ignore_pmdown_time = true,
+	.set_sysclk = wm2200_set_sysclk,
+	.set_pll = wm2200_set_fll,
+
+	.controls = wm2200_snd_controls,
+	.num_controls = ARRAY_SIZE(wm2200_snd_controls),
+	.dapm_widgets = wm2200_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm2200_dapm_widgets),
+	.dapm_routes = wm2200_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm2200_dapm_routes),
+};
+
+static irqreturn_t wm2200_irq(int irq, void *data)
+{
+	struct wm2200_priv *wm2200 = data;
+	unsigned int val, mask;
+	int ret;
+
+	ret = regmap_read(wm2200->regmap, WM2200_INTERRUPT_STATUS_2, &val);
+	if (ret != 0) {
+		dev_err(wm2200->dev, "Failed to read IRQ status: %d\n", ret);
+		return IRQ_NONE;
+	}
+
+	ret = regmap_read(wm2200->regmap, WM2200_INTERRUPT_STATUS_2_MASK,
+			   &mask);
+	if (ret != 0) {
+		dev_warn(wm2200->dev, "Failed to read IRQ mask: %d\n", ret);
+		mask = 0;
+	}
+
+	val &= ~mask;
+
+	if (val & WM2200_FLL_LOCK_EINT) {
+		dev_dbg(wm2200->dev, "FLL locked\n");
+		complete(&wm2200->fll_lock);
+	}
+
+	if (val) {
+		regmap_write(wm2200->regmap, WM2200_INTERRUPT_STATUS_2, val);
+		
+		return IRQ_HANDLED;
+	} else {
+		return IRQ_NONE;
+	}
+}
+
+static const struct regmap_config wm2200_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+
+	.max_register = WM2200_MAX_REGISTER,
+	.reg_defaults = wm2200_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm2200_reg_defaults),
+	.volatile_reg = wm2200_volatile_register,
+	.readable_reg = wm2200_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const unsigned int wm2200_dig_vu[] = {
+	WM2200_DAC_DIGITAL_VOLUME_1L,
+	WM2200_DAC_DIGITAL_VOLUME_1R,
+	WM2200_DAC_DIGITAL_VOLUME_2L,
+	WM2200_DAC_DIGITAL_VOLUME_2R,
+	WM2200_ADC_DIGITAL_VOLUME_1L,
+	WM2200_ADC_DIGITAL_VOLUME_1R,
+	WM2200_ADC_DIGITAL_VOLUME_2L,
+	WM2200_ADC_DIGITAL_VOLUME_2R,
+	WM2200_ADC_DIGITAL_VOLUME_3L,
+	WM2200_ADC_DIGITAL_VOLUME_3R,
+};
+
+static const unsigned int wm2200_mic_ctrl_reg[] = {
+	WM2200_IN1L_CONTROL,
+	WM2200_IN2L_CONTROL,
+	WM2200_IN3L_CONTROL,
+};
+
+static __devinit int wm2200_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct wm2200_pdata *pdata = dev_get_platdata(&i2c->dev);
+	struct wm2200_priv *wm2200;
+	unsigned int reg;
+	int ret, i;
+
+	wm2200 = devm_kzalloc(&i2c->dev, sizeof(struct wm2200_priv),
+			      GFP_KERNEL);
+	if (wm2200 == NULL)
+		return -ENOMEM;
+
+	wm2200->dev = &i2c->dev;
+	init_completion(&wm2200->fll_lock);
+
+	wm2200->regmap = regmap_init_i2c(i2c, &wm2200_regmap);
+	if (IS_ERR(wm2200->regmap)) {
+		ret = PTR_ERR(wm2200->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		goto err;
+	}
+
+	if (pdata)
+		wm2200->pdata = *pdata;
+
+	i2c_set_clientdata(i2c, wm2200);
+
+	for (i = 0; i < ARRAY_SIZE(wm2200->core_supplies); i++)
+		wm2200->core_supplies[i].supply = wm2200_core_supply_names[i];
+
+	ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm2200->core_supplies),
+				 wm2200->core_supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request core supplies: %d\n",
+			ret);
+		goto err_regmap;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies),
+				    wm2200->core_supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable core supplies: %d\n",
+			ret);
+		goto err_core;
+	}
+
+	if (wm2200->pdata.ldo_ena) {
+		ret = gpio_request_one(wm2200->pdata.ldo_ena,
+				       GPIOF_OUT_INIT_HIGH, "WM2200 LDOENA");
+		if (ret < 0) {
+			dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n",
+				wm2200->pdata.ldo_ena, ret);
+			goto err_enable;
+		}
+		msleep(2);
+	}
+
+	if (wm2200->pdata.reset) {
+		ret = gpio_request_one(wm2200->pdata.reset,
+				       GPIOF_OUT_INIT_HIGH, "WM2200 /RESET");
+		if (ret < 0) {
+			dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n",
+				wm2200->pdata.reset, ret);
+			goto err_ldo;
+		}
+	}
+
+	ret = regmap_read(wm2200->regmap, WM2200_SOFTWARE_RESET, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
+		goto err_reset;
+	}
+	switch (reg) {
+	case 0x2200:
+		break;
+
+	default:
+		dev_err(&i2c->dev, "Device is not a WM2200, ID is %x\n", reg);
+		ret = -EINVAL;
+		goto err_reset;
+	}
+
+	ret = regmap_read(wm2200->regmap, WM2200_DEVICE_REVISION, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read revision register\n");
+		goto err_reset;
+	}
+
+	wm2200->rev = reg & WM2200_DEVICE_REVISION_MASK;
+
+	dev_info(&i2c->dev, "revision %c\n", wm2200->rev + 'A');
+
+	switch (wm2200->rev) {
+	case 0:
+		ret = regmap_register_patch(wm2200->regmap, wm2200_reva_patch,
+					    ARRAY_SIZE(wm2200_reva_patch));
+		if (ret != 0) {
+			dev_err(&i2c->dev, "Failed to register patch: %d\n",
+				ret);
+		}
+		break;
+	default:
+		break;
+	}
+
+	ret = wm2200_reset(wm2200);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to issue reset\n");
+		goto err_reset;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm2200->pdata.gpio_defaults); i++) {
+		if (!wm2200->pdata.gpio_defaults[i])
+			continue;
+
+		regmap_write(wm2200->regmap, WM2200_GPIO_CTRL_1 + i,
+			     wm2200->pdata.gpio_defaults[i]);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm2200_dig_vu); i++)
+		regmap_update_bits(wm2200->regmap, wm2200_dig_vu[i],
+				   WM2200_OUT_VU, WM2200_OUT_VU);
+
+	/* Assign slots 1-6 to channels 1-6 for both TX and RX */
+	for (i = 0; i < 6; i++) {
+		regmap_write(wm2200->regmap, WM2200_AUDIO_IF_1_10 + i, i);
+		regmap_write(wm2200->regmap, WM2200_AUDIO_IF_1_16 + i, i);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm2200->pdata.in_mode); i++) {
+		regmap_update_bits(wm2200->regmap, wm2200_mic_ctrl_reg[i],
+				   WM2200_IN1_MODE_MASK |
+				   WM2200_IN1_DMIC_SUP_MASK,
+				   (wm2200->pdata.in_mode[i] <<
+				    WM2200_IN1_MODE_SHIFT) |
+				   (wm2200->pdata.dmic_sup[i] <<
+				    WM2200_IN1_DMIC_SUP_SHIFT));
+	}
+
+	if (i2c->irq) {
+		ret = request_threaded_irq(i2c->irq, NULL, wm2200_irq,
+					   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+					   "wm2200", wm2200);
+		if (ret == 0)
+			regmap_update_bits(wm2200->regmap,
+					   WM2200_INTERRUPT_STATUS_2_MASK,
+					   WM2200_FLL_LOCK_EINT, 0);
+		else
+			dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
+				i2c->irq, ret);
+	}
+
+	pm_runtime_set_active(&i2c->dev);
+	pm_runtime_enable(&i2c->dev);
+	pm_request_idle(&i2c->dev);
+
+	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_wm2200,
+				     &wm2200_dai, 1);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+		goto err_pm_runtime;
+	}
+
+	return 0;
+
+err_pm_runtime:
+	pm_runtime_disable(&i2c->dev);
+err_reset:
+	if (wm2200->pdata.reset) {
+		gpio_set_value_cansleep(wm2200->pdata.reset, 0);
+		gpio_free(wm2200->pdata.reset);
+	}
+err_ldo:
+	if (wm2200->pdata.ldo_ena) {
+		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
+		gpio_free(wm2200->pdata.ldo_ena);
+	}
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
+			       wm2200->core_supplies);
+err_core:
+	regulator_bulk_free(ARRAY_SIZE(wm2200->core_supplies),
+			    wm2200->core_supplies);
+err_regmap:
+	regmap_exit(wm2200->regmap);
+err:
+	return ret;
+}
+
+static __devexit int wm2200_i2c_remove(struct i2c_client *i2c)
+{
+	struct wm2200_priv *wm2200 = i2c_get_clientdata(i2c);
+
+	snd_soc_unregister_codec(&i2c->dev);
+	if (i2c->irq)
+		free_irq(i2c->irq, wm2200);
+	if (wm2200->pdata.reset) {
+		gpio_set_value_cansleep(wm2200->pdata.reset, 0);
+		gpio_free(wm2200->pdata.reset);
+	}
+	if (wm2200->pdata.ldo_ena) {
+		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
+		gpio_free(wm2200->pdata.ldo_ena);
+	}
+	regulator_bulk_free(ARRAY_SIZE(wm2200->core_supplies),
+			    wm2200->core_supplies);
+	regmap_exit(wm2200->regmap);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int wm2200_runtime_suspend(struct device *dev)
+{
+	struct wm2200_priv *wm2200 = dev_get_drvdata(dev);
+
+	regcache_cache_only(wm2200->regmap, true);
+	regcache_mark_dirty(wm2200->regmap);
+	if (wm2200->pdata.ldo_ena)
+		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
+	regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
+			       wm2200->core_supplies);
+
+	return 0;
+}
+
+static int wm2200_runtime_resume(struct device *dev)
+{
+	struct wm2200_priv *wm2200 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies),
+				    wm2200->core_supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	if (wm2200->pdata.ldo_ena) {
+		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 1);
+		msleep(2);
+	}
+
+	regcache_cache_only(wm2200->regmap, false);
+	regcache_sync(wm2200->regmap);
+
+	return 0;
+}
+#endif
+
+static struct dev_pm_ops wm2200_pm = {
+	SET_RUNTIME_PM_OPS(wm2200_runtime_suspend, wm2200_runtime_resume,
+			   NULL)
+};
+
+static const struct i2c_device_id wm2200_i2c_id[] = {
+	{ "wm2200", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm2200_i2c_id);
+
+static struct i2c_driver wm2200_i2c_driver = {
+	.driver = {
+		.name = "wm2200",
+		.owner = THIS_MODULE,
+		.pm = &wm2200_pm,
+	},
+	.probe =    wm2200_i2c_probe,
+	.remove =   __devexit_p(wm2200_i2c_remove),
+	.id_table = wm2200_i2c_id,
+};
+
+static int __init wm2200_modinit(void)
+{
+	return i2c_add_driver(&wm2200_i2c_driver);
+}
+module_init(wm2200_modinit);
+
+static void __exit wm2200_exit(void)
+{
+	i2c_del_driver(&wm2200_i2c_driver);
+}
+module_exit(wm2200_exit);
+
+MODULE_DESCRIPTION("ASoC WM2200 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm2200.h b/sound/soc/codecs/wm2200.h
new file mode 100644
index 0000000..5d719d6
--- /dev/null
+++ b/sound/soc/codecs/wm2200.h
@@ -0,0 +1,3674 @@
+/*
+ * wm2200.h - WM2200 audio codec interface
+ *
+ * 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 as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _WM2200_H
+#define _WM2200_H
+
+#define WM2200_CLK_SYSCLK 1
+
+#define WM2200_CLKSRC_MCLK1  0
+#define WM2200_CLKSRC_MCLK2  1
+#define WM2200_CLKSRC_FLL    4
+#define WM2200_CLKSRC_BCLK1  8
+
+#define WM2200_FLL_SRC_MCLK1 0
+#define WM2200_FLL_SRC_MCLK2 1
+#define WM2200_FLL_SRC_BCLK  2
+
+/*
+ * Register values.
+ */
+#define WM2200_SOFTWARE_RESET                   0x00
+#define WM2200_DEVICE_REVISION                  0x01
+#define WM2200_TONE_GENERATOR_1                 0x0B
+#define WM2200_CLOCKING_3                       0x102
+#define WM2200_CLOCKING_4                       0x103
+#define WM2200_FLL_CONTROL_1                    0x111
+#define WM2200_FLL_CONTROL_2                    0x112
+#define WM2200_FLL_CONTROL_3                    0x113
+#define WM2200_FLL_CONTROL_4                    0x114
+#define WM2200_FLL_CONTROL_6                    0x116
+#define WM2200_FLL_CONTROL_7                    0x117
+#define WM2200_FLL_EFS_1                        0x119
+#define WM2200_FLL_EFS_2                        0x11A
+#define WM2200_MIC_CHARGE_PUMP_1                0x200
+#define WM2200_MIC_CHARGE_PUMP_2                0x201
+#define WM2200_DM_CHARGE_PUMP_1                 0x202
+#define WM2200_MIC_BIAS_CTRL_1                  0x20C
+#define WM2200_MIC_BIAS_CTRL_2                  0x20D
+#define WM2200_EAR_PIECE_CTRL_1                 0x20F
+#define WM2200_EAR_PIECE_CTRL_2                 0x210
+#define WM2200_INPUT_ENABLES                    0x301
+#define WM2200_IN1L_CONTROL                     0x302
+#define WM2200_IN1R_CONTROL                     0x303
+#define WM2200_IN2L_CONTROL                     0x304
+#define WM2200_IN2R_CONTROL                     0x305
+#define WM2200_IN3L_CONTROL                     0x306
+#define WM2200_IN3R_CONTROL                     0x307
+#define WM2200_RXANC_SRC                        0x30A
+#define WM2200_INPUT_VOLUME_RAMP                0x30B
+#define WM2200_ADC_DIGITAL_VOLUME_1L            0x30C
+#define WM2200_ADC_DIGITAL_VOLUME_1R            0x30D
+#define WM2200_ADC_DIGITAL_VOLUME_2L            0x30E
+#define WM2200_ADC_DIGITAL_VOLUME_2R            0x30F
+#define WM2200_ADC_DIGITAL_VOLUME_3L            0x310
+#define WM2200_ADC_DIGITAL_VOLUME_3R            0x311
+#define WM2200_OUTPUT_ENABLES                   0x400
+#define WM2200_DAC_VOLUME_LIMIT_1L              0x401
+#define WM2200_DAC_VOLUME_LIMIT_1R              0x402
+#define WM2200_DAC_VOLUME_LIMIT_2L              0x403
+#define WM2200_DAC_VOLUME_LIMIT_2R              0x404
+#define WM2200_DAC_AEC_CONTROL_1                0x409
+#define WM2200_OUTPUT_VOLUME_RAMP               0x40A
+#define WM2200_DAC_DIGITAL_VOLUME_1L            0x40B
+#define WM2200_DAC_DIGITAL_VOLUME_1R            0x40C
+#define WM2200_DAC_DIGITAL_VOLUME_2L            0x40D
+#define WM2200_DAC_DIGITAL_VOLUME_2R            0x40E
+#define WM2200_PDM_1                            0x417
+#define WM2200_PDM_2                            0x418
+#define WM2200_AUDIO_IF_1_1                     0x500
+#define WM2200_AUDIO_IF_1_2                     0x501
+#define WM2200_AUDIO_IF_1_3                     0x502
+#define WM2200_AUDIO_IF_1_4                     0x503
+#define WM2200_AUDIO_IF_1_5                     0x504
+#define WM2200_AUDIO_IF_1_6                     0x505
+#define WM2200_AUDIO_IF_1_7                     0x506
+#define WM2200_AUDIO_IF_1_8                     0x507
+#define WM2200_AUDIO_IF_1_9                     0x508
+#define WM2200_AUDIO_IF_1_10                    0x509
+#define WM2200_AUDIO_IF_1_11                    0x50A
+#define WM2200_AUDIO_IF_1_12                    0x50B
+#define WM2200_AUDIO_IF_1_13                    0x50C
+#define WM2200_AUDIO_IF_1_14                    0x50D
+#define WM2200_AUDIO_IF_1_15                    0x50E
+#define WM2200_AUDIO_IF_1_16                    0x50F
+#define WM2200_AUDIO_IF_1_17                    0x510
+#define WM2200_AUDIO_IF_1_18                    0x511
+#define WM2200_AUDIO_IF_1_19                    0x512
+#define WM2200_AUDIO_IF_1_20                    0x513
+#define WM2200_AUDIO_IF_1_21                    0x514
+#define WM2200_AUDIO_IF_1_22                    0x515
+#define WM2200_OUT1LMIX_INPUT_1_SOURCE          0x600
+#define WM2200_OUT1LMIX_INPUT_1_VOLUME          0x601
+#define WM2200_OUT1LMIX_INPUT_2_SOURCE          0x602
+#define WM2200_OUT1LMIX_INPUT_2_VOLUME          0x603
+#define WM2200_OUT1LMIX_INPUT_3_SOURCE          0x604
+#define WM2200_OUT1LMIX_INPUT_3_VOLUME          0x605
+#define WM2200_OUT1LMIX_INPUT_4_SOURCE          0x606
+#define WM2200_OUT1LMIX_INPUT_4_VOLUME          0x607
+#define WM2200_OUT1RMIX_INPUT_1_SOURCE          0x608
+#define WM2200_OUT1RMIX_INPUT_1_VOLUME          0x609
+#define WM2200_OUT1RMIX_INPUT_2_SOURCE          0x60A
+#define WM2200_OUT1RMIX_INPUT_2_VOLUME          0x60B
+#define WM2200_OUT1RMIX_INPUT_3_SOURCE          0x60C
+#define WM2200_OUT1RMIX_INPUT_3_VOLUME          0x60D
+#define WM2200_OUT1RMIX_INPUT_4_SOURCE          0x60E
+#define WM2200_OUT1RMIX_INPUT_4_VOLUME          0x60F
+#define WM2200_OUT2LMIX_INPUT_1_SOURCE          0x610
+#define WM2200_OUT2LMIX_INPUT_1_VOLUME          0x611
+#define WM2200_OUT2LMIX_INPUT_2_SOURCE          0x612
+#define WM2200_OUT2LMIX_INPUT_2_VOLUME          0x613
+#define WM2200_OUT2LMIX_INPUT_3_SOURCE          0x614
+#define WM2200_OUT2LMIX_INPUT_3_VOLUME          0x615
+#define WM2200_OUT2LMIX_INPUT_4_SOURCE          0x616
+#define WM2200_OUT2LMIX_INPUT_4_VOLUME          0x617
+#define WM2200_OUT2RMIX_INPUT_1_SOURCE          0x618
+#define WM2200_OUT2RMIX_INPUT_1_VOLUME          0x619
+#define WM2200_OUT2RMIX_INPUT_2_SOURCE          0x61A
+#define WM2200_OUT2RMIX_INPUT_2_VOLUME          0x61B
+#define WM2200_OUT2RMIX_INPUT_3_SOURCE          0x61C
+#define WM2200_OUT2RMIX_INPUT_3_VOLUME          0x61D
+#define WM2200_OUT2RMIX_INPUT_4_SOURCE          0x61E
+#define WM2200_OUT2RMIX_INPUT_4_VOLUME          0x61F
+#define WM2200_AIF1TX1MIX_INPUT_1_SOURCE        0x620
+#define WM2200_AIF1TX1MIX_INPUT_1_VOLUME        0x621
+#define WM2200_AIF1TX1MIX_INPUT_2_SOURCE        0x622
+#define WM2200_AIF1TX1MIX_INPUT_2_VOLUME        0x623
+#define WM2200_AIF1TX1MIX_INPUT_3_SOURCE        0x624
+#define WM2200_AIF1TX1MIX_INPUT_3_VOLUME        0x625
+#define WM2200_AIF1TX1MIX_INPUT_4_SOURCE        0x626
+#define WM2200_AIF1TX1MIX_INPUT_4_VOLUME        0x627
+#define WM2200_AIF1TX2MIX_INPUT_1_SOURCE        0x628
+#define WM2200_AIF1TX2MIX_INPUT_1_VOLUME        0x629
+#define WM2200_AIF1TX2MIX_INPUT_2_SOURCE        0x62A
+#define WM2200_AIF1TX2MIX_INPUT_2_VOLUME        0x62B
+#define WM2200_AIF1TX2MIX_INPUT_3_SOURCE        0x62C
+#define WM2200_AIF1TX2MIX_INPUT_3_VOLUME        0x62D
+#define WM2200_AIF1TX2MIX_INPUT_4_SOURCE        0x62E
+#define WM2200_AIF1TX2MIX_INPUT_4_VOLUME        0x62F
+#define WM2200_AIF1TX3MIX_INPUT_1_SOURCE        0x630
+#define WM2200_AIF1TX3MIX_INPUT_1_VOLUME        0x631
+#define WM2200_AIF1TX3MIX_INPUT_2_SOURCE        0x632
+#define WM2200_AIF1TX3MIX_INPUT_2_VOLUME        0x633
+#define WM2200_AIF1TX3MIX_INPUT_3_SOURCE        0x634
+#define WM2200_AIF1TX3MIX_INPUT_3_VOLUME        0x635
+#define WM2200_AIF1TX3MIX_INPUT_4_SOURCE        0x636
+#define WM2200_AIF1TX3MIX_INPUT_4_VOLUME        0x637
+#define WM2200_AIF1TX4MIX_INPUT_1_SOURCE        0x638
+#define WM2200_AIF1TX4MIX_INPUT_1_VOLUME        0x639
+#define WM2200_AIF1TX4MIX_INPUT_2_SOURCE        0x63A
+#define WM2200_AIF1TX4MIX_INPUT_2_VOLUME        0x63B
+#define WM2200_AIF1TX4MIX_INPUT_3_SOURCE        0x63C
+#define WM2200_AIF1TX4MIX_INPUT_3_VOLUME        0x63D
+#define WM2200_AIF1TX4MIX_INPUT_4_SOURCE        0x63E
+#define WM2200_AIF1TX4MIX_INPUT_4_VOLUME        0x63F
+#define WM2200_AIF1TX5MIX_INPUT_1_SOURCE        0x640
+#define WM2200_AIF1TX5MIX_INPUT_1_VOLUME        0x641
+#define WM2200_AIF1TX5MIX_INPUT_2_SOURCE        0x642
+#define WM2200_AIF1TX5MIX_INPUT_2_VOLUME        0x643
+#define WM2200_AIF1TX5MIX_INPUT_3_SOURCE        0x644
+#define WM2200_AIF1TX5MIX_INPUT_3_VOLUME        0x645
+#define WM2200_AIF1TX5MIX_INPUT_4_SOURCE        0x646
+#define WM2200_AIF1TX5MIX_INPUT_4_VOLUME        0x647
+#define WM2200_AIF1TX6MIX_INPUT_1_SOURCE        0x648
+#define WM2200_AIF1TX6MIX_INPUT_1_VOLUME        0x649
+#define WM2200_AIF1TX6MIX_INPUT_2_SOURCE        0x64A
+#define WM2200_AIF1TX6MIX_INPUT_2_VOLUME        0x64B
+#define WM2200_AIF1TX6MIX_INPUT_3_SOURCE        0x64C
+#define WM2200_AIF1TX6MIX_INPUT_3_VOLUME        0x64D
+#define WM2200_AIF1TX6MIX_INPUT_4_SOURCE        0x64E
+#define WM2200_AIF1TX6MIX_INPUT_4_VOLUME        0x64F
+#define WM2200_EQLMIX_INPUT_1_SOURCE            0x650
+#define WM2200_EQLMIX_INPUT_1_VOLUME            0x651
+#define WM2200_EQLMIX_INPUT_2_SOURCE            0x652
+#define WM2200_EQLMIX_INPUT_2_VOLUME            0x653
+#define WM2200_EQLMIX_INPUT_3_SOURCE            0x654
+#define WM2200_EQLMIX_INPUT_3_VOLUME            0x655
+#define WM2200_EQLMIX_INPUT_4_SOURCE            0x656
+#define WM2200_EQLMIX_INPUT_4_VOLUME            0x657
+#define WM2200_EQRMIX_INPUT_1_SOURCE            0x658
+#define WM2200_EQRMIX_INPUT_1_VOLUME            0x659
+#define WM2200_EQRMIX_INPUT_2_SOURCE            0x65A
+#define WM2200_EQRMIX_INPUT_2_VOLUME            0x65B
+#define WM2200_EQRMIX_INPUT_3_SOURCE            0x65C
+#define WM2200_EQRMIX_INPUT_3_VOLUME            0x65D
+#define WM2200_EQRMIX_INPUT_4_SOURCE            0x65E
+#define WM2200_EQRMIX_INPUT_4_VOLUME            0x65F
+#define WM2200_LHPF1MIX_INPUT_1_SOURCE          0x660
+#define WM2200_LHPF1MIX_INPUT_1_VOLUME          0x661
+#define WM2200_LHPF1MIX_INPUT_2_SOURCE          0x662
+#define WM2200_LHPF1MIX_INPUT_2_VOLUME          0x663
+#define WM2200_LHPF1MIX_INPUT_3_SOURCE          0x664
+#define WM2200_LHPF1MIX_INPUT_3_VOLUME          0x665
+#define WM2200_LHPF1MIX_INPUT_4_SOURCE          0x666
+#define WM2200_LHPF1MIX_INPUT_4_VOLUME          0x667
+#define WM2200_LHPF2MIX_INPUT_1_SOURCE          0x668
+#define WM2200_LHPF2MIX_INPUT_1_VOLUME          0x669
+#define WM2200_LHPF2MIX_INPUT_2_SOURCE          0x66A
+#define WM2200_LHPF2MIX_INPUT_2_VOLUME          0x66B
+#define WM2200_LHPF2MIX_INPUT_3_SOURCE          0x66C
+#define WM2200_LHPF2MIX_INPUT_3_VOLUME          0x66D
+#define WM2200_LHPF2MIX_INPUT_4_SOURCE          0x66E
+#define WM2200_LHPF2MIX_INPUT_4_VOLUME          0x66F
+#define WM2200_DSP1LMIX_INPUT_1_SOURCE          0x670
+#define WM2200_DSP1LMIX_INPUT_1_VOLUME          0x671
+#define WM2200_DSP1LMIX_INPUT_2_SOURCE          0x672
+#define WM2200_DSP1LMIX_INPUT_2_VOLUME          0x673
+#define WM2200_DSP1LMIX_INPUT_3_SOURCE          0x674
+#define WM2200_DSP1LMIX_INPUT_3_VOLUME          0x675
+#define WM2200_DSP1LMIX_INPUT_4_SOURCE          0x676
+#define WM2200_DSP1LMIX_INPUT_4_VOLUME          0x677
+#define WM2200_DSP1RMIX_INPUT_1_SOURCE          0x678
+#define WM2200_DSP1RMIX_INPUT_1_VOLUME          0x679
+#define WM2200_DSP1RMIX_INPUT_2_SOURCE          0x67A
+#define WM2200_DSP1RMIX_INPUT_2_VOLUME          0x67B
+#define WM2200_DSP1RMIX_INPUT_3_SOURCE          0x67C
+#define WM2200_DSP1RMIX_INPUT_3_VOLUME          0x67D
+#define WM2200_DSP1RMIX_INPUT_4_SOURCE          0x67E
+#define WM2200_DSP1RMIX_INPUT_4_VOLUME          0x67F
+#define WM2200_DSP1AUX1MIX_INPUT_1_SOURCE       0x680
+#define WM2200_DSP1AUX2MIX_INPUT_1_SOURCE       0x681
+#define WM2200_DSP1AUX3MIX_INPUT_1_SOURCE       0x682
+#define WM2200_DSP1AUX4MIX_INPUT_1_SOURCE       0x683
+#define WM2200_DSP1AUX5MIX_INPUT_1_SOURCE       0x684
+#define WM2200_DSP1AUX6MIX_INPUT_1_SOURCE       0x685
+#define WM2200_DSP2LMIX_INPUT_1_SOURCE          0x686
+#define WM2200_DSP2LMIX_INPUT_1_VOLUME          0x687
+#define WM2200_DSP2LMIX_INPUT_2_SOURCE          0x688
+#define WM2200_DSP2LMIX_INPUT_2_VOLUME          0x689
+#define WM2200_DSP2LMIX_INPUT_3_SOURCE          0x68A
+#define WM2200_DSP2LMIX_INPUT_3_VOLUME          0x68B
+#define WM2200_DSP2LMIX_INPUT_4_SOURCE          0x68C
+#define WM2200_DSP2LMIX_INPUT_4_VOLUME          0x68D
+#define WM2200_DSP2RMIX_INPUT_1_SOURCE          0x68E
+#define WM2200_DSP2RMIX_INPUT_1_VOLUME          0x68F
+#define WM2200_DSP2RMIX_INPUT_2_SOURCE          0x690
+#define WM2200_DSP2RMIX_INPUT_2_VOLUME          0x691
+#define WM2200_DSP2RMIX_INPUT_3_SOURCE          0x692
+#define WM2200_DSP2RMIX_INPUT_3_VOLUME          0x693
+#define WM2200_DSP2RMIX_INPUT_4_SOURCE          0x694
+#define WM2200_DSP2RMIX_INPUT_4_VOLUME          0x695
+#define WM2200_DSP2AUX1MIX_INPUT_1_SOURCE       0x696
+#define WM2200_DSP2AUX2MIX_INPUT_1_SOURCE       0x697
+#define WM2200_DSP2AUX3MIX_INPUT_1_SOURCE       0x698
+#define WM2200_DSP2AUX4MIX_INPUT_1_SOURCE       0x699
+#define WM2200_DSP2AUX5MIX_INPUT_1_SOURCE       0x69A
+#define WM2200_DSP2AUX6MIX_INPUT_1_SOURCE       0x69B
+#define WM2200_GPIO_CTRL_1                      0x700
+#define WM2200_GPIO_CTRL_2                      0x701
+#define WM2200_GPIO_CTRL_3                      0x702
+#define WM2200_GPIO_CTRL_4                      0x703
+#define WM2200_ADPS1_IRQ0                       0x707
+#define WM2200_ADPS1_IRQ1                       0x708
+#define WM2200_MISC_PAD_CTRL_1                  0x709
+#define WM2200_INTERRUPT_STATUS_1               0x800
+#define WM2200_INTERRUPT_STATUS_1_MASK          0x801
+#define WM2200_INTERRUPT_STATUS_2               0x802
+#define WM2200_INTERRUPT_RAW_STATUS_2           0x803
+#define WM2200_INTERRUPT_STATUS_2_MASK          0x804
+#define WM2200_INTERRUPT_CONTROL                0x808
+#define WM2200_EQL_1                            0x900
+#define WM2200_EQL_2                            0x901
+#define WM2200_EQL_3                            0x902
+#define WM2200_EQL_4                            0x903
+#define WM2200_EQL_5                            0x904
+#define WM2200_EQL_6                            0x905
+#define WM2200_EQL_7                            0x906
+#define WM2200_EQL_8                            0x907
+#define WM2200_EQL_9                            0x908
+#define WM2200_EQL_10                           0x909
+#define WM2200_EQL_11                           0x90A
+#define WM2200_EQL_12                           0x90B
+#define WM2200_EQL_13                           0x90C
+#define WM2200_EQL_14                           0x90D
+#define WM2200_EQL_15                           0x90E
+#define WM2200_EQL_16                           0x90F
+#define WM2200_EQL_17                           0x910
+#define WM2200_EQL_18                           0x911
+#define WM2200_EQL_19                           0x912
+#define WM2200_EQL_20                           0x913
+#define WM2200_EQR_1                            0x916
+#define WM2200_EQR_2                            0x917
+#define WM2200_EQR_3                            0x918
+#define WM2200_EQR_4                            0x919
+#define WM2200_EQR_5                            0x91A
+#define WM2200_EQR_6                            0x91B
+#define WM2200_EQR_7                            0x91C
+#define WM2200_EQR_8                            0x91D
+#define WM2200_EQR_9                            0x91E
+#define WM2200_EQR_10                           0x91F
+#define WM2200_EQR_11                           0x920
+#define WM2200_EQR_12                           0x921
+#define WM2200_EQR_13                           0x922
+#define WM2200_EQR_14                           0x923
+#define WM2200_EQR_15                           0x924
+#define WM2200_EQR_16                           0x925
+#define WM2200_EQR_17                           0x926
+#define WM2200_EQR_18                           0x927
+#define WM2200_EQR_19                           0x928
+#define WM2200_EQR_20                           0x929
+#define WM2200_HPLPF1_1                         0x93E
+#define WM2200_HPLPF1_2                         0x93F
+#define WM2200_HPLPF2_1                         0x942
+#define WM2200_HPLPF2_2                         0x943
+#define WM2200_DSP1_CONTROL_1                   0xA00
+#define WM2200_DSP1_CONTROL_2                   0xA02
+#define WM2200_DSP1_CONTROL_3                   0xA03
+#define WM2200_DSP1_CONTROL_4                   0xA04
+#define WM2200_DSP1_CONTROL_5                   0xA06
+#define WM2200_DSP1_CONTROL_6                   0xA07
+#define WM2200_DSP1_CONTROL_7                   0xA08
+#define WM2200_DSP1_CONTROL_8                   0xA09
+#define WM2200_DSP1_CONTROL_9                   0xA0A
+#define WM2200_DSP1_CONTROL_10                  0xA0B
+#define WM2200_DSP1_CONTROL_11                  0xA0C
+#define WM2200_DSP1_CONTROL_12                  0xA0D
+#define WM2200_DSP1_CONTROL_13                  0xA0F
+#define WM2200_DSP1_CONTROL_14                  0xA10
+#define WM2200_DSP1_CONTROL_15                  0xA11
+#define WM2200_DSP1_CONTROL_16                  0xA12
+#define WM2200_DSP1_CONTROL_17                  0xA13
+#define WM2200_DSP1_CONTROL_18                  0xA14
+#define WM2200_DSP1_CONTROL_19                  0xA16
+#define WM2200_DSP1_CONTROL_20                  0xA17
+#define WM2200_DSP1_CONTROL_21                  0xA18
+#define WM2200_DSP1_CONTROL_22                  0xA1A
+#define WM2200_DSP1_CONTROL_23                  0xA1B
+#define WM2200_DSP1_CONTROL_24                  0xA1C
+#define WM2200_DSP1_CONTROL_25                  0xA1E
+#define WM2200_DSP1_CONTROL_26                  0xA20
+#define WM2200_DSP1_CONTROL_27                  0xA21
+#define WM2200_DSP1_CONTROL_28                  0xA22
+#define WM2200_DSP1_CONTROL_29                  0xA23
+#define WM2200_DSP1_CONTROL_30                  0xA24
+#define WM2200_DSP1_CONTROL_31                  0xA26
+#define WM2200_DSP2_CONTROL_1                   0xB00
+#define WM2200_DSP2_CONTROL_2                   0xB02
+#define WM2200_DSP2_CONTROL_3                   0xB03
+#define WM2200_DSP2_CONTROL_4                   0xB04
+#define WM2200_DSP2_CONTROL_5                   0xB06
+#define WM2200_DSP2_CONTROL_6                   0xB07
+#define WM2200_DSP2_CONTROL_7                   0xB08
+#define WM2200_DSP2_CONTROL_8                   0xB09
+#define WM2200_DSP2_CONTROL_9                   0xB0A
+#define WM2200_DSP2_CONTROL_10                  0xB0B
+#define WM2200_DSP2_CONTROL_11                  0xB0C
+#define WM2200_DSP2_CONTROL_12                  0xB0D
+#define WM2200_DSP2_CONTROL_13                  0xB0F
+#define WM2200_DSP2_CONTROL_14                  0xB10
+#define WM2200_DSP2_CONTROL_15                  0xB11
+#define WM2200_DSP2_CONTROL_16                  0xB12
+#define WM2200_DSP2_CONTROL_17                  0xB13
+#define WM2200_DSP2_CONTROL_18                  0xB14
+#define WM2200_DSP2_CONTROL_19                  0xB16
+#define WM2200_DSP2_CONTROL_20                  0xB17
+#define WM2200_DSP2_CONTROL_21                  0xB18
+#define WM2200_DSP2_CONTROL_22                  0xB1A
+#define WM2200_DSP2_CONTROL_23                  0xB1B
+#define WM2200_DSP2_CONTROL_24                  0xB1C
+#define WM2200_DSP2_CONTROL_25                  0xB1E
+#define WM2200_DSP2_CONTROL_26                  0xB20
+#define WM2200_DSP2_CONTROL_27                  0xB21
+#define WM2200_DSP2_CONTROL_28                  0xB22
+#define WM2200_DSP2_CONTROL_29                  0xB23
+#define WM2200_DSP2_CONTROL_30                  0xB24
+#define WM2200_DSP2_CONTROL_31                  0xB26
+#define WM2200_ANC_CTRL1                        0xD00
+#define WM2200_ANC_CTRL2                        0xD01
+#define WM2200_ANC_CTRL3                        0xD02
+#define WM2200_ANC_CTRL7                        0xD08
+#define WM2200_ANC_CTRL8                        0xD09
+#define WM2200_ANC_CTRL9                        0xD0A
+#define WM2200_ANC_CTRL10                       0xD0B
+#define WM2200_ANC_CTRL11                       0xD0C
+#define WM2200_ANC_CTRL12                       0xD0D
+#define WM2200_ANC_CTRL13                       0xD0E
+#define WM2200_ANC_CTRL14                       0xD0F
+#define WM2200_ANC_CTRL15                       0xD10
+#define WM2200_ANC_CTRL16                       0xD11
+#define WM2200_ANC_CTRL17                       0xD12
+#define WM2200_ANC_CTRL18                       0xD15
+#define WM2200_ANC_CTRL19                       0xD16
+#define WM2200_ANC_CTRL20                       0xD17
+#define WM2200_ANC_CTRL21                       0xD18
+#define WM2200_ANC_CTRL22                       0xD19
+#define WM2200_ANC_CTRL23                       0xD1A
+#define WM2200_ANC_CTRL24                       0xD1B
+#define WM2200_ANC_CTRL25                       0xD1C
+#define WM2200_ANC_CTRL26                       0xD1D
+#define WM2200_ANC_CTRL27                       0xD1E
+#define WM2200_ANC_CTRL28                       0xD1F
+#define WM2200_ANC_CTRL29                       0xD20
+#define WM2200_ANC_CTRL30                       0xD21
+#define WM2200_ANC_CTRL31                       0xD23
+#define WM2200_ANC_CTRL32                       0xD24
+#define WM2200_ANC_CTRL33                       0xD25
+#define WM2200_ANC_CTRL34                       0xD27
+#define WM2200_ANC_CTRL35                       0xD28
+#define WM2200_ANC_CTRL36                       0xD29
+#define WM2200_ANC_CTRL37                       0xD2A
+#define WM2200_ANC_CTRL38                       0xD2B
+#define WM2200_ANC_CTRL39                       0xD2C
+#define WM2200_ANC_CTRL40                       0xD2D
+#define WM2200_ANC_CTRL41                       0xD2E
+#define WM2200_ANC_CTRL42                       0xD2F
+#define WM2200_ANC_CTRL43                       0xD30
+#define WM2200_ANC_CTRL44                       0xD31
+#define WM2200_ANC_CTRL45                       0xD32
+#define WM2200_ANC_CTRL46                       0xD33
+#define WM2200_ANC_CTRL47                       0xD34
+#define WM2200_ANC_CTRL48                       0xD35
+#define WM2200_ANC_CTRL49                       0xD36
+#define WM2200_ANC_CTRL50                       0xD37
+#define WM2200_ANC_CTRL51                       0xD38
+#define WM2200_ANC_CTRL52                       0xD39
+#define WM2200_ANC_CTRL53                       0xD3A
+#define WM2200_ANC_CTRL54                       0xD3B
+#define WM2200_ANC_CTRL55                       0xD3C
+#define WM2200_ANC_CTRL56                       0xD3D
+#define WM2200_ANC_CTRL57                       0xD3E
+#define WM2200_ANC_CTRL58                       0xD3F
+#define WM2200_ANC_CTRL59                       0xD40
+#define WM2200_ANC_CTRL60                       0xD41
+#define WM2200_ANC_CTRL61                       0xD42
+#define WM2200_ANC_CTRL62                       0xD43
+#define WM2200_ANC_CTRL63                       0xD44
+#define WM2200_ANC_CTRL64                       0xD45
+#define WM2200_ANC_CTRL65                       0xD46
+#define WM2200_ANC_CTRL66                       0xD47
+#define WM2200_ANC_CTRL67                       0xD48
+#define WM2200_ANC_CTRL68                       0xD49
+#define WM2200_ANC_CTRL69                       0xD4A
+#define WM2200_ANC_CTRL70                       0xD4B
+#define WM2200_ANC_CTRL71                       0xD4C
+#define WM2200_ANC_CTRL72                       0xD4D
+#define WM2200_ANC_CTRL73                       0xD4E
+#define WM2200_ANC_CTRL74                       0xD4F
+#define WM2200_ANC_CTRL75                       0xD50
+#define WM2200_ANC_CTRL76                       0xD51
+#define WM2200_ANC_CTRL77                       0xD52
+#define WM2200_ANC_CTRL78                       0xD53
+#define WM2200_ANC_CTRL79                       0xD54
+#define WM2200_ANC_CTRL80                       0xD55
+#define WM2200_ANC_CTRL81                       0xD56
+#define WM2200_ANC_CTRL82                       0xD57
+#define WM2200_ANC_CTRL83                       0xD58
+#define WM2200_ANC_CTRL84                       0xD5B
+#define WM2200_ANC_CTRL85                       0xD5C
+#define WM2200_ANC_CTRL86                       0xD5F
+#define WM2200_ANC_CTRL87                       0xD60
+#define WM2200_ANC_CTRL88                       0xD61
+#define WM2200_ANC_CTRL89                       0xD62
+#define WM2200_ANC_CTRL90                       0xD63
+#define WM2200_ANC_CTRL91                       0xD64
+#define WM2200_ANC_CTRL92                       0xD65
+#define WM2200_ANC_CTRL93                       0xD66
+#define WM2200_ANC_CTRL94                       0xD67
+#define WM2200_ANC_CTRL95                       0xD68
+#define WM2200_ANC_CTRL96                       0xD69
+#define WM2200_DSP1_DM_0                        0x3000
+#define WM2200_DSP1_DM_1                        0x3001
+#define WM2200_DSP1_DM_2                        0x3002
+#define WM2200_DSP1_DM_3                        0x3003
+#define WM2200_DSP1_DM_2044                     0x37FC
+#define WM2200_DSP1_DM_2045                     0x37FD
+#define WM2200_DSP1_DM_2046                     0x37FE
+#define WM2200_DSP1_DM_2047                     0x37FF
+#define WM2200_DSP1_PM_0                        0x3800
+#define WM2200_DSP1_PM_1                        0x3801
+#define WM2200_DSP1_PM_2                        0x3802
+#define WM2200_DSP1_PM_3                        0x3803
+#define WM2200_DSP1_PM_4                        0x3804
+#define WM2200_DSP1_PM_5                        0x3805
+#define WM2200_DSP1_PM_762                      0x3AFA
+#define WM2200_DSP1_PM_763                      0x3AFB
+#define WM2200_DSP1_PM_764                      0x3AFC
+#define WM2200_DSP1_PM_765                      0x3AFD
+#define WM2200_DSP1_PM_766                      0x3AFE
+#define WM2200_DSP1_PM_767                      0x3AFF
+#define WM2200_DSP1_ZM_0                        0x3C00
+#define WM2200_DSP1_ZM_1                        0x3C01
+#define WM2200_DSP1_ZM_2                        0x3C02
+#define WM2200_DSP1_ZM_3                        0x3C03
+#define WM2200_DSP1_ZM_1020                     0x3FFC
+#define WM2200_DSP1_ZM_1021                     0x3FFD
+#define WM2200_DSP1_ZM_1022                     0x3FFE
+#define WM2200_DSP1_ZM_1023                     0x3FFF
+#define WM2200_DSP2_DM_0                        0x4000
+#define WM2200_DSP2_DM_1                        0x4001
+#define WM2200_DSP2_DM_2                        0x4002
+#define WM2200_DSP2_DM_3                        0x4003
+#define WM2200_DSP2_DM_2044                     0x47FC
+#define WM2200_DSP2_DM_2045                     0x47FD
+#define WM2200_DSP2_DM_2046                     0x47FE
+#define WM2200_DSP2_DM_2047                     0x47FF
+#define WM2200_DSP2_PM_0                        0x4800
+#define WM2200_DSP2_PM_1                        0x4801
+#define WM2200_DSP2_PM_2                        0x4802
+#define WM2200_DSP2_PM_3                        0x4803
+#define WM2200_DSP2_PM_4                        0x4804
+#define WM2200_DSP2_PM_5                        0x4805
+#define WM2200_DSP2_PM_762                      0x4AFA
+#define WM2200_DSP2_PM_763                      0x4AFB
+#define WM2200_DSP2_PM_764                      0x4AFC
+#define WM2200_DSP2_PM_765                      0x4AFD
+#define WM2200_DSP2_PM_766                      0x4AFE
+#define WM2200_DSP2_PM_767                      0x4AFF
+#define WM2200_DSP2_ZM_0                        0x4C00
+#define WM2200_DSP2_ZM_1                        0x4C01
+#define WM2200_DSP2_ZM_2                        0x4C02
+#define WM2200_DSP2_ZM_3                        0x4C03
+#define WM2200_DSP2_ZM_1020                     0x4FFC
+#define WM2200_DSP2_ZM_1021                     0x4FFD
+#define WM2200_DSP2_ZM_1022                     0x4FFE
+#define WM2200_DSP2_ZM_1023                     0x4FFF
+
+#define WM2200_REGISTER_COUNT                   494
+#define WM2200_MAX_REGISTER                     0x4FFF
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - software reset
+ */
+#define WM2200_SW_RESET_CHIP_ID1_MASK           0xFFFF  /* SW_RESET_CHIP_ID1 - [15:0] */
+#define WM2200_SW_RESET_CHIP_ID1_SHIFT               0  /* SW_RESET_CHIP_ID1 - [15:0] */
+#define WM2200_SW_RESET_CHIP_ID1_WIDTH              16  /* SW_RESET_CHIP_ID1 - [15:0] */
+
+/*
+ * R1 (0x01) - Device Revision
+ */
+#define WM2200_DEVICE_REVISION_MASK             0x000F  /* DEVICE_REVISION - [3:0] */
+#define WM2200_DEVICE_REVISION_SHIFT                 0  /* DEVICE_REVISION - [3:0] */
+#define WM2200_DEVICE_REVISION_WIDTH                 4  /* DEVICE_REVISION - [3:0] */
+
+/*
+ * R11 (0x0B) - Tone Generator 1
+ */
+#define WM2200_TONE_ENA                         0x0001  /* TONE_ENA */
+#define WM2200_TONE_ENA_MASK                    0x0001  /* TONE_ENA */
+#define WM2200_TONE_ENA_SHIFT                        0  /* TONE_ENA */
+#define WM2200_TONE_ENA_WIDTH                        1  /* TONE_ENA */
+
+/*
+ * R258 (0x102) - Clocking 3
+ */
+#define WM2200_SYSCLK_FREQ_MASK                 0x0700  /* SYSCLK_FREQ - [10:8] */
+#define WM2200_SYSCLK_FREQ_SHIFT                     8  /* SYSCLK_FREQ - [10:8] */
+#define WM2200_SYSCLK_FREQ_WIDTH                     3  /* SYSCLK_FREQ - [10:8] */
+#define WM2200_SYSCLK_ENA                       0x0040  /* SYSCLK_ENA */
+#define WM2200_SYSCLK_ENA_MASK                  0x0040  /* SYSCLK_ENA */
+#define WM2200_SYSCLK_ENA_SHIFT                      6  /* SYSCLK_ENA */
+#define WM2200_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+#define WM2200_SYSCLK_SRC_MASK                  0x000F  /* SYSCLK_SRC - [3:0] */
+#define WM2200_SYSCLK_SRC_SHIFT                      0  /* SYSCLK_SRC - [3:0] */
+#define WM2200_SYSCLK_SRC_WIDTH                      4  /* SYSCLK_SRC - [3:0] */
+
+/*
+ * R259 (0x103) - Clocking 4
+ */
+#define WM2200_SAMPLE_RATE_1_MASK               0x001F  /* SAMPLE_RATE_1 - [4:0] */
+#define WM2200_SAMPLE_RATE_1_SHIFT                   0  /* SAMPLE_RATE_1 - [4:0] */
+#define WM2200_SAMPLE_RATE_1_WIDTH                   5  /* SAMPLE_RATE_1 - [4:0] */
+
+/*
+ * R273 (0x111) - FLL Control 1
+ */
+#define WM2200_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM2200_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM2200_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM2200_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R274 (0x112) - FLL Control 2
+ */
+#define WM2200_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
+#define WM2200_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
+#define WM2200_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
+#define WM2200_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM2200_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM2200_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R275 (0x113) - FLL Control 3
+ */
+#define WM2200_FLL_FRACN_ENA                    0x0001  /* FLL_FRACN_ENA */
+#define WM2200_FLL_FRACN_ENA_MASK               0x0001  /* FLL_FRACN_ENA */
+#define WM2200_FLL_FRACN_ENA_SHIFT                   0  /* FLL_FRACN_ENA */
+#define WM2200_FLL_FRACN_ENA_WIDTH                   1  /* FLL_FRACN_ENA */
+
+/*
+ * R276 (0x114) - FLL Control 4
+ */
+#define WM2200_FLL_THETA_MASK                   0xFFFF  /* FLL_THETA - [15:0] */
+#define WM2200_FLL_THETA_SHIFT                       0  /* FLL_THETA - [15:0] */
+#define WM2200_FLL_THETA_WIDTH                      16  /* FLL_THETA - [15:0] */
+
+/*
+ * R278 (0x116) - FLL Control 6
+ */
+#define WM2200_FLL_N_MASK                       0x03FF  /* FLL_N - [9:0] */
+#define WM2200_FLL_N_SHIFT                           0  /* FLL_N - [9:0] */
+#define WM2200_FLL_N_WIDTH                          10  /* FLL_N - [9:0] */
+
+/*
+ * R279 (0x117) - FLL Control 7
+ */
+#define WM2200_FLL_CLK_REF_DIV_MASK             0x0030  /* FLL_CLK_REF_DIV - [5:4] */
+#define WM2200_FLL_CLK_REF_DIV_SHIFT                 4  /* FLL_CLK_REF_DIV - [5:4] */
+#define WM2200_FLL_CLK_REF_DIV_WIDTH                 2  /* FLL_CLK_REF_DIV - [5:4] */
+#define WM2200_FLL_CLK_REF_SRC_MASK             0x0003  /* FLL_CLK_REF_SRC - [1:0] */
+#define WM2200_FLL_CLK_REF_SRC_SHIFT                 0  /* FLL_CLK_REF_SRC - [1:0] */
+#define WM2200_FLL_CLK_REF_SRC_WIDTH                 2  /* FLL_CLK_REF_SRC - [1:0] */
+
+/*
+ * R281 (0x119) - FLL EFS 1
+ */
+#define WM2200_FLL_LAMBDA_MASK                  0xFFFF  /* FLL_LAMBDA - [15:0] */
+#define WM2200_FLL_LAMBDA_SHIFT                      0  /* FLL_LAMBDA - [15:0] */
+#define WM2200_FLL_LAMBDA_WIDTH                     16  /* FLL_LAMBDA - [15:0] */
+
+/*
+ * R282 (0x11A) - FLL EFS 2
+ */
+#define WM2200_FLL_EFS_ENA                      0x0001  /* FLL_EFS_ENA */
+#define WM2200_FLL_EFS_ENA_MASK                 0x0001  /* FLL_EFS_ENA */
+#define WM2200_FLL_EFS_ENA_SHIFT                     0  /* FLL_EFS_ENA */
+#define WM2200_FLL_EFS_ENA_WIDTH                     1  /* FLL_EFS_ENA */
+
+/*
+ * R512 (0x200) - Mic Charge Pump 1
+ */
+#define WM2200_CPMIC_BYPASS_MODE                0x0020  /* CPMIC_BYPASS_MODE */
+#define WM2200_CPMIC_BYPASS_MODE_MASK           0x0020  /* CPMIC_BYPASS_MODE */
+#define WM2200_CPMIC_BYPASS_MODE_SHIFT               5  /* CPMIC_BYPASS_MODE */
+#define WM2200_CPMIC_BYPASS_MODE_WIDTH               1  /* CPMIC_BYPASS_MODE */
+#define WM2200_CPMIC_ENA                        0x0001  /* CPMIC_ENA */
+#define WM2200_CPMIC_ENA_MASK                   0x0001  /* CPMIC_ENA */
+#define WM2200_CPMIC_ENA_SHIFT                       0  /* CPMIC_ENA */
+#define WM2200_CPMIC_ENA_WIDTH                       1  /* CPMIC_ENA */
+
+/*
+ * R513 (0x201) - Mic Charge Pump 2
+ */
+#define WM2200_CPMIC_LDO_VSEL_OVERRIDE_MASK     0xF800  /* CPMIC_LDO_VSEL_OVERRIDE - [15:11] */
+#define WM2200_CPMIC_LDO_VSEL_OVERRIDE_SHIFT        11  /* CPMIC_LDO_VSEL_OVERRIDE - [15:11] */
+#define WM2200_CPMIC_LDO_VSEL_OVERRIDE_WIDTH         5  /* CPMIC_LDO_VSEL_OVERRIDE - [15:11] */
+
+/*
+ * R514 (0x202) - DM Charge Pump 1
+ */
+#define WM2200_CPDM_ENA                         0x0001  /* CPDM_ENA */
+#define WM2200_CPDM_ENA_MASK                    0x0001  /* CPDM_ENA */
+#define WM2200_CPDM_ENA_SHIFT                        0  /* CPDM_ENA */
+#define WM2200_CPDM_ENA_WIDTH                        1  /* CPDM_ENA */
+
+/*
+ * R524 (0x20C) - Mic Bias Ctrl 1
+ */
+#define WM2200_MICB1_DISCH                      0x0040  /* MICB1_DISCH */
+#define WM2200_MICB1_DISCH_MASK                 0x0040  /* MICB1_DISCH */
+#define WM2200_MICB1_DISCH_SHIFT                     6  /* MICB1_DISCH */
+#define WM2200_MICB1_DISCH_WIDTH                     1  /* MICB1_DISCH */
+#define WM2200_MICB1_RATE                       0x0020  /* MICB1_RATE */
+#define WM2200_MICB1_RATE_MASK                  0x0020  /* MICB1_RATE */
+#define WM2200_MICB1_RATE_SHIFT                      5  /* MICB1_RATE */
+#define WM2200_MICB1_RATE_WIDTH                      1  /* MICB1_RATE */
+#define WM2200_MICB1_LVL_MASK                   0x001C  /* MICB1_LVL - [4:2] */
+#define WM2200_MICB1_LVL_SHIFT                       2  /* MICB1_LVL - [4:2] */
+#define WM2200_MICB1_LVL_WIDTH                       3  /* MICB1_LVL - [4:2] */
+#define WM2200_MICB1_MODE                       0x0002  /* MICB1_MODE */
+#define WM2200_MICB1_MODE_MASK                  0x0002  /* MICB1_MODE */
+#define WM2200_MICB1_MODE_SHIFT                      1  /* MICB1_MODE */
+#define WM2200_MICB1_MODE_WIDTH                      1  /* MICB1_MODE */
+#define WM2200_MICB1_ENA                        0x0001  /* MICB1_ENA */
+#define WM2200_MICB1_ENA_MASK                   0x0001  /* MICB1_ENA */
+#define WM2200_MICB1_ENA_SHIFT                       0  /* MICB1_ENA */
+#define WM2200_MICB1_ENA_WIDTH                       1  /* MICB1_ENA */
+
+/*
+ * R525 (0x20D) - Mic Bias Ctrl 2
+ */
+#define WM2200_MICB2_DISCH                      0x0040  /* MICB2_DISCH */
+#define WM2200_MICB2_DISCH_MASK                 0x0040  /* MICB2_DISCH */
+#define WM2200_MICB2_DISCH_SHIFT                     6  /* MICB2_DISCH */
+#define WM2200_MICB2_DISCH_WIDTH                     1  /* MICB2_DISCH */
+#define WM2200_MICB2_RATE                       0x0020  /* MICB2_RATE */
+#define WM2200_MICB2_RATE_MASK                  0x0020  /* MICB2_RATE */
+#define WM2200_MICB2_RATE_SHIFT                      5  /* MICB2_RATE */
+#define WM2200_MICB2_RATE_WIDTH                      1  /* MICB2_RATE */
+#define WM2200_MICB2_LVL_MASK                   0x001C  /* MICB2_LVL - [4:2] */
+#define WM2200_MICB2_LVL_SHIFT                       2  /* MICB2_LVL - [4:2] */
+#define WM2200_MICB2_LVL_WIDTH                       3  /* MICB2_LVL - [4:2] */
+#define WM2200_MICB2_MODE                       0x0002  /* MICB2_MODE */
+#define WM2200_MICB2_MODE_MASK                  0x0002  /* MICB2_MODE */
+#define WM2200_MICB2_MODE_SHIFT                      1  /* MICB2_MODE */
+#define WM2200_MICB2_MODE_WIDTH                      1  /* MICB2_MODE */
+#define WM2200_MICB2_ENA                        0x0001  /* MICB2_ENA */
+#define WM2200_MICB2_ENA_MASK                   0x0001  /* MICB2_ENA */
+#define WM2200_MICB2_ENA_SHIFT                       0  /* MICB2_ENA */
+#define WM2200_MICB2_ENA_WIDTH                       1  /* MICB2_ENA */
+
+/*
+ * R527 (0x20F) - Ear Piece Ctrl 1
+ */
+#define WM2200_EPD_LP_ENA                       0x4000  /* EPD_LP_ENA */
+#define WM2200_EPD_LP_ENA_MASK                  0x4000  /* EPD_LP_ENA */
+#define WM2200_EPD_LP_ENA_SHIFT                     14  /* EPD_LP_ENA */
+#define WM2200_EPD_LP_ENA_WIDTH                      1  /* EPD_LP_ENA */
+#define WM2200_EPD_OUTP_LP_ENA                  0x2000  /* EPD_OUTP_LP_ENA */
+#define WM2200_EPD_OUTP_LP_ENA_MASK             0x2000  /* EPD_OUTP_LP_ENA */
+#define WM2200_EPD_OUTP_LP_ENA_SHIFT                13  /* EPD_OUTP_LP_ENA */
+#define WM2200_EPD_OUTP_LP_ENA_WIDTH                 1  /* EPD_OUTP_LP_ENA */
+#define WM2200_EPD_RMV_SHRT_LP                  0x1000  /* EPD_RMV_SHRT_LP */
+#define WM2200_EPD_RMV_SHRT_LP_MASK             0x1000  /* EPD_RMV_SHRT_LP */
+#define WM2200_EPD_RMV_SHRT_LP_SHIFT                12  /* EPD_RMV_SHRT_LP */
+#define WM2200_EPD_RMV_SHRT_LP_WIDTH                 1  /* EPD_RMV_SHRT_LP */
+#define WM2200_EPD_LN_ENA                       0x0800  /* EPD_LN_ENA */
+#define WM2200_EPD_LN_ENA_MASK                  0x0800  /* EPD_LN_ENA */
+#define WM2200_EPD_LN_ENA_SHIFT                     11  /* EPD_LN_ENA */
+#define WM2200_EPD_LN_ENA_WIDTH                      1  /* EPD_LN_ENA */
+#define WM2200_EPD_OUTP_LN_ENA                  0x0400  /* EPD_OUTP_LN_ENA */
+#define WM2200_EPD_OUTP_LN_ENA_MASK             0x0400  /* EPD_OUTP_LN_ENA */
+#define WM2200_EPD_OUTP_LN_ENA_SHIFT                10  /* EPD_OUTP_LN_ENA */
+#define WM2200_EPD_OUTP_LN_ENA_WIDTH                 1  /* EPD_OUTP_LN_ENA */
+#define WM2200_EPD_RMV_SHRT_LN                  0x0200  /* EPD_RMV_SHRT_LN */
+#define WM2200_EPD_RMV_SHRT_LN_MASK             0x0200  /* EPD_RMV_SHRT_LN */
+#define WM2200_EPD_RMV_SHRT_LN_SHIFT                 9  /* EPD_RMV_SHRT_LN */
+#define WM2200_EPD_RMV_SHRT_LN_WIDTH                 1  /* EPD_RMV_SHRT_LN */
+
+/*
+ * R528 (0x210) - Ear Piece Ctrl 2
+ */
+#define WM2200_EPD_RP_ENA                       0x4000  /* EPD_RP_ENA */
+#define WM2200_EPD_RP_ENA_MASK                  0x4000  /* EPD_RP_ENA */
+#define WM2200_EPD_RP_ENA_SHIFT                     14  /* EPD_RP_ENA */
+#define WM2200_EPD_RP_ENA_WIDTH                      1  /* EPD_RP_ENA */
+#define WM2200_EPD_OUTP_RP_ENA                  0x2000  /* EPD_OUTP_RP_ENA */
+#define WM2200_EPD_OUTP_RP_ENA_MASK             0x2000  /* EPD_OUTP_RP_ENA */
+#define WM2200_EPD_OUTP_RP_ENA_SHIFT                13  /* EPD_OUTP_RP_ENA */
+#define WM2200_EPD_OUTP_RP_ENA_WIDTH                 1  /* EPD_OUTP_RP_ENA */
+#define WM2200_EPD_RMV_SHRT_RP                  0x1000  /* EPD_RMV_SHRT_RP */
+#define WM2200_EPD_RMV_SHRT_RP_MASK             0x1000  /* EPD_RMV_SHRT_RP */
+#define WM2200_EPD_RMV_SHRT_RP_SHIFT                12  /* EPD_RMV_SHRT_RP */
+#define WM2200_EPD_RMV_SHRT_RP_WIDTH                 1  /* EPD_RMV_SHRT_RP */
+#define WM2200_EPD_RN_ENA                       0x0800  /* EPD_RN_ENA */
+#define WM2200_EPD_RN_ENA_MASK                  0x0800  /* EPD_RN_ENA */
+#define WM2200_EPD_RN_ENA_SHIFT                     11  /* EPD_RN_ENA */
+#define WM2200_EPD_RN_ENA_WIDTH                      1  /* EPD_RN_ENA */
+#define WM2200_EPD_OUTP_RN_ENA                  0x0400  /* EPD_OUTP_RN_ENA */
+#define WM2200_EPD_OUTP_RN_ENA_MASK             0x0400  /* EPD_OUTP_RN_ENA */
+#define WM2200_EPD_OUTP_RN_ENA_SHIFT                10  /* EPD_OUTP_RN_ENA */
+#define WM2200_EPD_OUTP_RN_ENA_WIDTH                 1  /* EPD_OUTP_RN_ENA */
+#define WM2200_EPD_RMV_SHRT_RN                  0x0200  /* EPD_RMV_SHRT_RN */
+#define WM2200_EPD_RMV_SHRT_RN_MASK             0x0200  /* EPD_RMV_SHRT_RN */
+#define WM2200_EPD_RMV_SHRT_RN_SHIFT                 9  /* EPD_RMV_SHRT_RN */
+#define WM2200_EPD_RMV_SHRT_RN_WIDTH                 1  /* EPD_RMV_SHRT_RN */
+
+/*
+ * R769 (0x301) - Input Enables
+ */
+#define WM2200_IN3L_ENA                         0x0020  /* IN3L_ENA */
+#define WM2200_IN3L_ENA_MASK                    0x0020  /* IN3L_ENA */
+#define WM2200_IN3L_ENA_SHIFT                        5  /* IN3L_ENA */
+#define WM2200_IN3L_ENA_WIDTH                        1  /* IN3L_ENA */
+#define WM2200_IN3R_ENA                         0x0010  /* IN3R_ENA */
+#define WM2200_IN3R_ENA_MASK                    0x0010  /* IN3R_ENA */
+#define WM2200_IN3R_ENA_SHIFT                        4  /* IN3R_ENA */
+#define WM2200_IN3R_ENA_WIDTH                        1  /* IN3R_ENA */
+#define WM2200_IN2L_ENA                         0x0008  /* IN2L_ENA */
+#define WM2200_IN2L_ENA_MASK                    0x0008  /* IN2L_ENA */
+#define WM2200_IN2L_ENA_SHIFT                        3  /* IN2L_ENA */
+#define WM2200_IN2L_ENA_WIDTH                        1  /* IN2L_ENA */
+#define WM2200_IN2R_ENA                         0x0004  /* IN2R_ENA */
+#define WM2200_IN2R_ENA_MASK                    0x0004  /* IN2R_ENA */
+#define WM2200_IN2R_ENA_SHIFT                        2  /* IN2R_ENA */
+#define WM2200_IN2R_ENA_WIDTH                        1  /* IN2R_ENA */
+#define WM2200_IN1L_ENA                         0x0002  /* IN1L_ENA */
+#define WM2200_IN1L_ENA_MASK                    0x0002  /* IN1L_ENA */
+#define WM2200_IN1L_ENA_SHIFT                        1  /* IN1L_ENA */
+#define WM2200_IN1L_ENA_WIDTH                        1  /* IN1L_ENA */
+#define WM2200_IN1R_ENA                         0x0001  /* IN1R_ENA */
+#define WM2200_IN1R_ENA_MASK                    0x0001  /* IN1R_ENA */
+#define WM2200_IN1R_ENA_SHIFT                        0  /* IN1R_ENA */
+#define WM2200_IN1R_ENA_WIDTH                        1  /* IN1R_ENA */
+
+/*
+ * R770 (0x302) - IN1L Control
+ */
+#define WM2200_IN1_OSR                          0x2000  /* IN1_OSR */
+#define WM2200_IN1_OSR_MASK                     0x2000  /* IN1_OSR */
+#define WM2200_IN1_OSR_SHIFT                        13  /* IN1_OSR */
+#define WM2200_IN1_OSR_WIDTH                         1  /* IN1_OSR */
+#define WM2200_IN1_DMIC_SUP_MASK                0x1800  /* IN1_DMIC_SUP - [12:11] */
+#define WM2200_IN1_DMIC_SUP_SHIFT                   11  /* IN1_DMIC_SUP - [12:11] */
+#define WM2200_IN1_DMIC_SUP_WIDTH                    2  /* IN1_DMIC_SUP - [12:11] */
+#define WM2200_IN1_MODE_MASK                    0x0600  /* IN1_MODE - [10:9] */
+#define WM2200_IN1_MODE_SHIFT                        9  /* IN1_MODE - [10:9] */
+#define WM2200_IN1_MODE_WIDTH                        2  /* IN1_MODE - [10:9] */
+#define WM2200_IN1L_PGA_VOL_MASK                0x00FE  /* IN1L_PGA_VOL - [7:1] */
+#define WM2200_IN1L_PGA_VOL_SHIFT                    1  /* IN1L_PGA_VOL - [7:1] */
+#define WM2200_IN1L_PGA_VOL_WIDTH                    7  /* IN1L_PGA_VOL - [7:1] */
+
+/*
+ * R771 (0x303) - IN1R Control
+ */
+#define WM2200_IN1R_PGA_VOL_MASK                0x00FE  /* IN1R_PGA_VOL - [7:1] */
+#define WM2200_IN1R_PGA_VOL_SHIFT                    1  /* IN1R_PGA_VOL - [7:1] */
+#define WM2200_IN1R_PGA_VOL_WIDTH                    7  /* IN1R_PGA_VOL - [7:1] */
+
+/*
+ * R772 (0x304) - IN2L Control
+ */
+#define WM2200_IN2_OSR                          0x2000  /* IN2_OSR */
+#define WM2200_IN2_OSR_MASK                     0x2000  /* IN2_OSR */
+#define WM2200_IN2_OSR_SHIFT                        13  /* IN2_OSR */
+#define WM2200_IN2_OSR_WIDTH                         1  /* IN2_OSR */
+#define WM2200_IN2_DMIC_SUP_MASK                0x1800  /* IN2_DMIC_SUP - [12:11] */
+#define WM2200_IN2_DMIC_SUP_SHIFT                   11  /* IN2_DMIC_SUP - [12:11] */
+#define WM2200_IN2_DMIC_SUP_WIDTH                    2  /* IN2_DMIC_SUP - [12:11] */
+#define WM2200_IN2_MODE_MASK                    0x0600  /* IN2_MODE - [10:9] */
+#define WM2200_IN2_MODE_SHIFT                        9  /* IN2_MODE - [10:9] */
+#define WM2200_IN2_MODE_WIDTH                        2  /* IN2_MODE - [10:9] */
+#define WM2200_IN2L_PGA_VOL_MASK                0x00FE  /* IN2L_PGA_VOL - [7:1] */
+#define WM2200_IN2L_PGA_VOL_SHIFT                    1  /* IN2L_PGA_VOL - [7:1] */
+#define WM2200_IN2L_PGA_VOL_WIDTH                    7  /* IN2L_PGA_VOL - [7:1] */
+
+/*
+ * R773 (0x305) - IN2R Control
+ */
+#define WM2200_IN2R_PGA_VOL_MASK                0x00FE  /* IN2R_PGA_VOL - [7:1] */
+#define WM2200_IN2R_PGA_VOL_SHIFT                    1  /* IN2R_PGA_VOL - [7:1] */
+#define WM2200_IN2R_PGA_VOL_WIDTH                    7  /* IN2R_PGA_VOL - [7:1] */
+
+/*
+ * R774 (0x306) - IN3L Control
+ */
+#define WM2200_IN3_OSR                          0x2000  /* IN3_OSR */
+#define WM2200_IN3_OSR_MASK                     0x2000  /* IN3_OSR */
+#define WM2200_IN3_OSR_SHIFT                        13  /* IN3_OSR */
+#define WM2200_IN3_OSR_WIDTH                         1  /* IN3_OSR */
+#define WM2200_IN3_DMIC_SUP_MASK                0x1800  /* IN3_DMIC_SUP - [12:11] */
+#define WM2200_IN3_DMIC_SUP_SHIFT                   11  /* IN3_DMIC_SUP - [12:11] */
+#define WM2200_IN3_DMIC_SUP_WIDTH                    2  /* IN3_DMIC_SUP - [12:11] */
+#define WM2200_IN3_MODE_MASK                    0x0600  /* IN3_MODE - [10:9] */
+#define WM2200_IN3_MODE_SHIFT                        9  /* IN3_MODE - [10:9] */
+#define WM2200_IN3_MODE_WIDTH                        2  /* IN3_MODE - [10:9] */
+#define WM2200_IN3L_PGA_VOL_MASK                0x00FE  /* IN3L_PGA_VOL - [7:1] */
+#define WM2200_IN3L_PGA_VOL_SHIFT                    1  /* IN3L_PGA_VOL - [7:1] */
+#define WM2200_IN3L_PGA_VOL_WIDTH                    7  /* IN3L_PGA_VOL - [7:1] */
+
+/*
+ * R775 (0x307) - IN3R Control
+ */
+#define WM2200_IN3R_PGA_VOL_MASK                0x00FE  /* IN3R_PGA_VOL - [7:1] */
+#define WM2200_IN3R_PGA_VOL_SHIFT                    1  /* IN3R_PGA_VOL - [7:1] */
+#define WM2200_IN3R_PGA_VOL_WIDTH                    7  /* IN3R_PGA_VOL - [7:1] */
+
+/*
+ * R778 (0x30A) - RXANC_SRC
+ */
+#define WM2200_IN_RXANC_SEL_MASK                0x0007  /* IN_RXANC_SEL - [2:0] */
+#define WM2200_IN_RXANC_SEL_SHIFT                    0  /* IN_RXANC_SEL - [2:0] */
+#define WM2200_IN_RXANC_SEL_WIDTH                    3  /* IN_RXANC_SEL - [2:0] */
+
+/*
+ * R779 (0x30B) - Input Volume Ramp
+ */
+#define WM2200_IN_VD_RAMP_MASK                  0x0070  /* IN_VD_RAMP - [6:4] */
+#define WM2200_IN_VD_RAMP_SHIFT                      4  /* IN_VD_RAMP - [6:4] */
+#define WM2200_IN_VD_RAMP_WIDTH                      3  /* IN_VD_RAMP - [6:4] */
+#define WM2200_IN_VI_RAMP_MASK                  0x0007  /* IN_VI_RAMP - [2:0] */
+#define WM2200_IN_VI_RAMP_SHIFT                      0  /* IN_VI_RAMP - [2:0] */
+#define WM2200_IN_VI_RAMP_WIDTH                      3  /* IN_VI_RAMP - [2:0] */
+
+/*
+ * R780 (0x30C) - ADC Digital Volume 1L
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN1L_MUTE                        0x0100  /* IN1L_MUTE */
+#define WM2200_IN1L_MUTE_MASK                   0x0100  /* IN1L_MUTE */
+#define WM2200_IN1L_MUTE_SHIFT                       8  /* IN1L_MUTE */
+#define WM2200_IN1L_MUTE_WIDTH                       1  /* IN1L_MUTE */
+#define WM2200_IN1L_DIG_VOL_MASK                0x00FF  /* IN1L_DIG_VOL - [7:0] */
+#define WM2200_IN1L_DIG_VOL_SHIFT                    0  /* IN1L_DIG_VOL - [7:0] */
+#define WM2200_IN1L_DIG_VOL_WIDTH                    8  /* IN1L_DIG_VOL - [7:0] */
+
+/*
+ * R781 (0x30D) - ADC Digital Volume 1R
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN1R_MUTE                        0x0100  /* IN1R_MUTE */
+#define WM2200_IN1R_MUTE_MASK                   0x0100  /* IN1R_MUTE */
+#define WM2200_IN1R_MUTE_SHIFT                       8  /* IN1R_MUTE */
+#define WM2200_IN1R_MUTE_WIDTH                       1  /* IN1R_MUTE */
+#define WM2200_IN1R_DIG_VOL_MASK                0x00FF  /* IN1R_DIG_VOL - [7:0] */
+#define WM2200_IN1R_DIG_VOL_SHIFT                    0  /* IN1R_DIG_VOL - [7:0] */
+#define WM2200_IN1R_DIG_VOL_WIDTH                    8  /* IN1R_DIG_VOL - [7:0] */
+
+/*
+ * R782 (0x30E) - ADC Digital Volume 2L
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN2L_MUTE                        0x0100  /* IN2L_MUTE */
+#define WM2200_IN2L_MUTE_MASK                   0x0100  /* IN2L_MUTE */
+#define WM2200_IN2L_MUTE_SHIFT                       8  /* IN2L_MUTE */
+#define WM2200_IN2L_MUTE_WIDTH                       1  /* IN2L_MUTE */
+#define WM2200_IN2L_DIG_VOL_MASK                0x00FF  /* IN2L_DIG_VOL - [7:0] */
+#define WM2200_IN2L_DIG_VOL_SHIFT                    0  /* IN2L_DIG_VOL - [7:0] */
+#define WM2200_IN2L_DIG_VOL_WIDTH                    8  /* IN2L_DIG_VOL - [7:0] */
+
+/*
+ * R783 (0x30F) - ADC Digital Volume 2R
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN2R_MUTE                        0x0100  /* IN2R_MUTE */
+#define WM2200_IN2R_MUTE_MASK                   0x0100  /* IN2R_MUTE */
+#define WM2200_IN2R_MUTE_SHIFT                       8  /* IN2R_MUTE */
+#define WM2200_IN2R_MUTE_WIDTH                       1  /* IN2R_MUTE */
+#define WM2200_IN2R_DIG_VOL_MASK                0x00FF  /* IN2R_DIG_VOL - [7:0] */
+#define WM2200_IN2R_DIG_VOL_SHIFT                    0  /* IN2R_DIG_VOL - [7:0] */
+#define WM2200_IN2R_DIG_VOL_WIDTH                    8  /* IN2R_DIG_VOL - [7:0] */
+
+/*
+ * R784 (0x310) - ADC Digital Volume 3L
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN3L_MUTE                        0x0100  /* IN3L_MUTE */
+#define WM2200_IN3L_MUTE_MASK                   0x0100  /* IN3L_MUTE */
+#define WM2200_IN3L_MUTE_SHIFT                       8  /* IN3L_MUTE */
+#define WM2200_IN3L_MUTE_WIDTH                       1  /* IN3L_MUTE */
+#define WM2200_IN3L_DIG_VOL_MASK                0x00FF  /* IN3L_DIG_VOL - [7:0] */
+#define WM2200_IN3L_DIG_VOL_SHIFT                    0  /* IN3L_DIG_VOL - [7:0] */
+#define WM2200_IN3L_DIG_VOL_WIDTH                    8  /* IN3L_DIG_VOL - [7:0] */
+
+/*
+ * R785 (0x311) - ADC Digital Volume 3R
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN3R_MUTE                        0x0100  /* IN3R_MUTE */
+#define WM2200_IN3R_MUTE_MASK                   0x0100  /* IN3R_MUTE */
+#define WM2200_IN3R_MUTE_SHIFT                       8  /* IN3R_MUTE */
+#define WM2200_IN3R_MUTE_WIDTH                       1  /* IN3R_MUTE */
+#define WM2200_IN3R_DIG_VOL_MASK                0x00FF  /* IN3R_DIG_VOL - [7:0] */
+#define WM2200_IN3R_DIG_VOL_SHIFT                    0  /* IN3R_DIG_VOL - [7:0] */
+#define WM2200_IN3R_DIG_VOL_WIDTH                    8  /* IN3R_DIG_VOL - [7:0] */
+
+/*
+ * R1024 (0x400) - Output Enables
+ */
+#define WM2200_OUT2L_ENA                        0x0008  /* OUT2L_ENA */
+#define WM2200_OUT2L_ENA_MASK                   0x0008  /* OUT2L_ENA */
+#define WM2200_OUT2L_ENA_SHIFT                       3  /* OUT2L_ENA */
+#define WM2200_OUT2L_ENA_WIDTH                       1  /* OUT2L_ENA */
+#define WM2200_OUT2R_ENA                        0x0004  /* OUT2R_ENA */
+#define WM2200_OUT2R_ENA_MASK                   0x0004  /* OUT2R_ENA */
+#define WM2200_OUT2R_ENA_SHIFT                       2  /* OUT2R_ENA */
+#define WM2200_OUT2R_ENA_WIDTH                       1  /* OUT2R_ENA */
+#define WM2200_OUT1L_ENA                        0x0002  /* OUT1L_ENA */
+#define WM2200_OUT1L_ENA_MASK                   0x0002  /* OUT1L_ENA */
+#define WM2200_OUT1L_ENA_SHIFT                       1  /* OUT1L_ENA */
+#define WM2200_OUT1L_ENA_WIDTH                       1  /* OUT1L_ENA */
+#define WM2200_OUT1R_ENA                        0x0001  /* OUT1R_ENA */
+#define WM2200_OUT1R_ENA_MASK                   0x0001  /* OUT1R_ENA */
+#define WM2200_OUT1R_ENA_SHIFT                       0  /* OUT1R_ENA */
+#define WM2200_OUT1R_ENA_WIDTH                       1  /* OUT1R_ENA */
+
+/*
+ * R1025 (0x401) - DAC Volume Limit 1L
+ */
+#define WM2200_OUT1_OSR                         0x2000  /* OUT1_OSR */
+#define WM2200_OUT1_OSR_MASK                    0x2000  /* OUT1_OSR */
+#define WM2200_OUT1_OSR_SHIFT                       13  /* OUT1_OSR */
+#define WM2200_OUT1_OSR_WIDTH                        1  /* OUT1_OSR */
+#define WM2200_OUT1L_ANC_SRC                    0x0800  /* OUT1L_ANC_SRC */
+#define WM2200_OUT1L_ANC_SRC_MASK               0x0800  /* OUT1L_ANC_SRC */
+#define WM2200_OUT1L_ANC_SRC_SHIFT                  11  /* OUT1L_ANC_SRC */
+#define WM2200_OUT1L_ANC_SRC_WIDTH                   1  /* OUT1L_ANC_SRC */
+#define WM2200_OUT1L_PGA_VOL_MASK               0x00FE  /* OUT1L_PGA_VOL - [7:1] */
+#define WM2200_OUT1L_PGA_VOL_SHIFT                   1  /* OUT1L_PGA_VOL - [7:1] */
+#define WM2200_OUT1L_PGA_VOL_WIDTH                   7  /* OUT1L_PGA_VOL - [7:1] */
+
+/*
+ * R1026 (0x402) - DAC Volume Limit 1R
+ */
+#define WM2200_OUT1R_ANC_SRC                    0x0800  /* OUT1R_ANC_SRC */
+#define WM2200_OUT1R_ANC_SRC_MASK               0x0800  /* OUT1R_ANC_SRC */
+#define WM2200_OUT1R_ANC_SRC_SHIFT                  11  /* OUT1R_ANC_SRC */
+#define WM2200_OUT1R_ANC_SRC_WIDTH                   1  /* OUT1R_ANC_SRC */
+#define WM2200_OUT1R_PGA_VOL_MASK               0x00FE  /* OUT1R_PGA_VOL - [7:1] */
+#define WM2200_OUT1R_PGA_VOL_SHIFT                   1  /* OUT1R_PGA_VOL - [7:1] */
+#define WM2200_OUT1R_PGA_VOL_WIDTH                   7  /* OUT1R_PGA_VOL - [7:1] */
+
+/*
+ * R1027 (0x403) - DAC Volume Limit 2L
+ */
+#define WM2200_OUT2_OSR                         0x2000  /* OUT2_OSR */
+#define WM2200_OUT2_OSR_MASK                    0x2000  /* OUT2_OSR */
+#define WM2200_OUT2_OSR_SHIFT                       13  /* OUT2_OSR */
+#define WM2200_OUT2_OSR_WIDTH                        1  /* OUT2_OSR */
+#define WM2200_OUT2L_ANC_SRC                    0x0800  /* OUT2L_ANC_SRC */
+#define WM2200_OUT2L_ANC_SRC_MASK               0x0800  /* OUT2L_ANC_SRC */
+#define WM2200_OUT2L_ANC_SRC_SHIFT                  11  /* OUT2L_ANC_SRC */
+#define WM2200_OUT2L_ANC_SRC_WIDTH                   1  /* OUT2L_ANC_SRC */
+
+/*
+ * R1028 (0x404) - DAC Volume Limit 2R
+ */
+#define WM2200_OUT2R_ANC_SRC                    0x0800  /* OUT2R_ANC_SRC */
+#define WM2200_OUT2R_ANC_SRC_MASK               0x0800  /* OUT2R_ANC_SRC */
+#define WM2200_OUT2R_ANC_SRC_SHIFT                  11  /* OUT2R_ANC_SRC */
+#define WM2200_OUT2R_ANC_SRC_WIDTH                   1  /* OUT2R_ANC_SRC */
+
+/*
+ * R1033 (0x409) - DAC AEC Control 1
+ */
+#define WM2200_AEC_LOOPBACK_ENA                 0x0004  /* AEC_LOOPBACK_ENA */
+#define WM2200_AEC_LOOPBACK_ENA_MASK            0x0004  /* AEC_LOOPBACK_ENA */
+#define WM2200_AEC_LOOPBACK_ENA_SHIFT                2  /* AEC_LOOPBACK_ENA */
+#define WM2200_AEC_LOOPBACK_ENA_WIDTH                1  /* AEC_LOOPBACK_ENA */
+#define WM2200_AEC_LOOPBACK_SRC_MASK            0x0003  /* AEC_LOOPBACK_SRC - [1:0] */
+#define WM2200_AEC_LOOPBACK_SRC_SHIFT                0  /* AEC_LOOPBACK_SRC - [1:0] */
+#define WM2200_AEC_LOOPBACK_SRC_WIDTH                2  /* AEC_LOOPBACK_SRC - [1:0] */
+
+/*
+ * R1034 (0x40A) - Output Volume Ramp
+ */
+#define WM2200_OUT_VD_RAMP_MASK                 0x0070  /* OUT_VD_RAMP - [6:4] */
+#define WM2200_OUT_VD_RAMP_SHIFT                     4  /* OUT_VD_RAMP - [6:4] */
+#define WM2200_OUT_VD_RAMP_WIDTH                     3  /* OUT_VD_RAMP - [6:4] */
+#define WM2200_OUT_VI_RAMP_MASK                 0x0007  /* OUT_VI_RAMP - [2:0] */
+#define WM2200_OUT_VI_RAMP_SHIFT                     0  /* OUT_VI_RAMP - [2:0] */
+#define WM2200_OUT_VI_RAMP_WIDTH                     3  /* OUT_VI_RAMP - [2:0] */
+
+/*
+ * R1035 (0x40B) - DAC Digital Volume 1L
+ */
+#define WM2200_OUT_VU                           0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM2200_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM2200_OUT1L_MUTE                       0x0100  /* OUT1L_MUTE */
+#define WM2200_OUT1L_MUTE_MASK                  0x0100  /* OUT1L_MUTE */
+#define WM2200_OUT1L_MUTE_SHIFT                      8  /* OUT1L_MUTE */
+#define WM2200_OUT1L_MUTE_WIDTH                      1  /* OUT1L_MUTE */
+#define WM2200_OUT1L_VOL_MASK                   0x00FF  /* OUT1L_VOL - [7:0] */
+#define WM2200_OUT1L_VOL_SHIFT                       0  /* OUT1L_VOL - [7:0] */
+#define WM2200_OUT1L_VOL_WIDTH                       8  /* OUT1L_VOL - [7:0] */
+
+/*
+ * R1036 (0x40C) - DAC Digital Volume 1R
+ */
+#define WM2200_OUT_VU                           0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM2200_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM2200_OUT1R_MUTE                       0x0100  /* OUT1R_MUTE */
+#define WM2200_OUT1R_MUTE_MASK                  0x0100  /* OUT1R_MUTE */
+#define WM2200_OUT1R_MUTE_SHIFT                      8  /* OUT1R_MUTE */
+#define WM2200_OUT1R_MUTE_WIDTH                      1  /* OUT1R_MUTE */
+#define WM2200_OUT1R_VOL_MASK                   0x00FF  /* OUT1R_VOL - [7:0] */
+#define WM2200_OUT1R_VOL_SHIFT                       0  /* OUT1R_VOL - [7:0] */
+#define WM2200_OUT1R_VOL_WIDTH                       8  /* OUT1R_VOL - [7:0] */
+
+/*
+ * R1037 (0x40D) - DAC Digital Volume 2L
+ */
+#define WM2200_OUT_VU                           0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM2200_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM2200_OUT2L_MUTE                       0x0100  /* OUT2L_MUTE */
+#define WM2200_OUT2L_MUTE_MASK                  0x0100  /* OUT2L_MUTE */
+#define WM2200_OUT2L_MUTE_SHIFT                      8  /* OUT2L_MUTE */
+#define WM2200_OUT2L_MUTE_WIDTH                      1  /* OUT2L_MUTE */
+#define WM2200_OUT2L_VOL_MASK                   0x00FF  /* OUT2L_VOL - [7:0] */
+#define WM2200_OUT2L_VOL_SHIFT                       0  /* OUT2L_VOL - [7:0] */
+#define WM2200_OUT2L_VOL_WIDTH                       8  /* OUT2L_VOL - [7:0] */
+
+/*
+ * R1038 (0x40E) - DAC Digital Volume 2R
+ */
+#define WM2200_OUT_VU                           0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM2200_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM2200_OUT2R_MUTE                       0x0100  /* OUT2R_MUTE */
+#define WM2200_OUT2R_MUTE_MASK                  0x0100  /* OUT2R_MUTE */
+#define WM2200_OUT2R_MUTE_SHIFT                      8  /* OUT2R_MUTE */
+#define WM2200_OUT2R_MUTE_WIDTH                      1  /* OUT2R_MUTE */
+#define WM2200_OUT2R_VOL_MASK                   0x00FF  /* OUT2R_VOL - [7:0] */
+#define WM2200_OUT2R_VOL_SHIFT                       0  /* OUT2R_VOL - [7:0] */
+#define WM2200_OUT2R_VOL_WIDTH                       8  /* OUT2R_VOL - [7:0] */
+
+/*
+ * R1047 (0x417) - PDM 1
+ */
+#define WM2200_SPK1R_MUTE                       0x2000  /* SPK1R_MUTE */
+#define WM2200_SPK1R_MUTE_MASK                  0x2000  /* SPK1R_MUTE */
+#define WM2200_SPK1R_MUTE_SHIFT                     13  /* SPK1R_MUTE */
+#define WM2200_SPK1R_MUTE_WIDTH                      1  /* SPK1R_MUTE */
+#define WM2200_SPK1L_MUTE                       0x1000  /* SPK1L_MUTE */
+#define WM2200_SPK1L_MUTE_MASK                  0x1000  /* SPK1L_MUTE */
+#define WM2200_SPK1L_MUTE_SHIFT                     12  /* SPK1L_MUTE */
+#define WM2200_SPK1L_MUTE_WIDTH                      1  /* SPK1L_MUTE */
+#define WM2200_SPK1_MUTE_ENDIAN                 0x0100  /* SPK1_MUTE_ENDIAN */
+#define WM2200_SPK1_MUTE_ENDIAN_MASK            0x0100  /* SPK1_MUTE_ENDIAN */
+#define WM2200_SPK1_MUTE_ENDIAN_SHIFT                8  /* SPK1_MUTE_ENDIAN */
+#define WM2200_SPK1_MUTE_ENDIAN_WIDTH                1  /* SPK1_MUTE_ENDIAN */
+#define WM2200_SPK1_MUTE_SEQL_MASK              0x00FF  /* SPK1_MUTE_SEQL - [7:0] */
+#define WM2200_SPK1_MUTE_SEQL_SHIFT                  0  /* SPK1_MUTE_SEQL - [7:0] */
+#define WM2200_SPK1_MUTE_SEQL_WIDTH                  8  /* SPK1_MUTE_SEQL - [7:0] */
+
+/*
+ * R1048 (0x418) - PDM 2
+ */
+#define WM2200_SPK1_FMT                         0x0001  /* SPK1_FMT */
+#define WM2200_SPK1_FMT_MASK                    0x0001  /* SPK1_FMT */
+#define WM2200_SPK1_FMT_SHIFT                        0  /* SPK1_FMT */
+#define WM2200_SPK1_FMT_WIDTH                        1  /* SPK1_FMT */
+
+/*
+ * R1280 (0x500) - Audio IF 1_1
+ */
+#define WM2200_AIF1_BCLK_INV                    0x0040  /* AIF1_BCLK_INV */
+#define WM2200_AIF1_BCLK_INV_MASK               0x0040  /* AIF1_BCLK_INV */
+#define WM2200_AIF1_BCLK_INV_SHIFT                   6  /* AIF1_BCLK_INV */
+#define WM2200_AIF1_BCLK_INV_WIDTH                   1  /* AIF1_BCLK_INV */
+#define WM2200_AIF1_BCLK_FRC                    0x0020  /* AIF1_BCLK_FRC */
+#define WM2200_AIF1_BCLK_FRC_MASK               0x0020  /* AIF1_BCLK_FRC */
+#define WM2200_AIF1_BCLK_FRC_SHIFT                   5  /* AIF1_BCLK_FRC */
+#define WM2200_AIF1_BCLK_FRC_WIDTH                   1  /* AIF1_BCLK_FRC */
+#define WM2200_AIF1_BCLK_MSTR                   0x0010  /* AIF1_BCLK_MSTR */
+#define WM2200_AIF1_BCLK_MSTR_MASK              0x0010  /* AIF1_BCLK_MSTR */
+#define WM2200_AIF1_BCLK_MSTR_SHIFT                  4  /* AIF1_BCLK_MSTR */
+#define WM2200_AIF1_BCLK_MSTR_WIDTH                  1  /* AIF1_BCLK_MSTR */
+#define WM2200_AIF1_BCLK_DIV_MASK               0x000F  /* AIF1_BCLK_DIV - [3:0] */
+#define WM2200_AIF1_BCLK_DIV_SHIFT                   0  /* AIF1_BCLK_DIV - [3:0] */
+#define WM2200_AIF1_BCLK_DIV_WIDTH                   4  /* AIF1_BCLK_DIV - [3:0] */
+
+/*
+ * R1281 (0x501) - Audio IF 1_2
+ */
+#define WM2200_AIF1TX_DAT_TRI                   0x0020  /* AIF1TX_DAT_TRI */
+#define WM2200_AIF1TX_DAT_TRI_MASK              0x0020  /* AIF1TX_DAT_TRI */
+#define WM2200_AIF1TX_DAT_TRI_SHIFT                  5  /* AIF1TX_DAT_TRI */
+#define WM2200_AIF1TX_DAT_TRI_WIDTH                  1  /* AIF1TX_DAT_TRI */
+#define WM2200_AIF1TX_LRCLK_SRC                 0x0008  /* AIF1TX_LRCLK_SRC */
+#define WM2200_AIF1TX_LRCLK_SRC_MASK            0x0008  /* AIF1TX_LRCLK_SRC */
+#define WM2200_AIF1TX_LRCLK_SRC_SHIFT                3  /* AIF1TX_LRCLK_SRC */
+#define WM2200_AIF1TX_LRCLK_SRC_WIDTH                1  /* AIF1TX_LRCLK_SRC */
+#define WM2200_AIF1TX_LRCLK_INV                 0x0004  /* AIF1TX_LRCLK_INV */
+#define WM2200_AIF1TX_LRCLK_INV_MASK            0x0004  /* AIF1TX_LRCLK_INV */
+#define WM2200_AIF1TX_LRCLK_INV_SHIFT                2  /* AIF1TX_LRCLK_INV */
+#define WM2200_AIF1TX_LRCLK_INV_WIDTH                1  /* AIF1TX_LRCLK_INV */
+#define WM2200_AIF1TX_LRCLK_FRC                 0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM2200_AIF1TX_LRCLK_FRC_MASK            0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM2200_AIF1TX_LRCLK_FRC_SHIFT                1  /* AIF1TX_LRCLK_FRC */
+#define WM2200_AIF1TX_LRCLK_FRC_WIDTH                1  /* AIF1TX_LRCLK_FRC */
+#define WM2200_AIF1TX_LRCLK_MSTR                0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM2200_AIF1TX_LRCLK_MSTR_MASK           0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM2200_AIF1TX_LRCLK_MSTR_SHIFT               0  /* AIF1TX_LRCLK_MSTR */
+#define WM2200_AIF1TX_LRCLK_MSTR_WIDTH               1  /* AIF1TX_LRCLK_MSTR */
+
+/*
+ * R1282 (0x502) - Audio IF 1_3
+ */
+#define WM2200_AIF1RX_LRCLK_INV                 0x0004  /* AIF1RX_LRCLK_INV */
+#define WM2200_AIF1RX_LRCLK_INV_MASK            0x0004  /* AIF1RX_LRCLK_INV */
+#define WM2200_AIF1RX_LRCLK_INV_SHIFT                2  /* AIF1RX_LRCLK_INV */
+#define WM2200_AIF1RX_LRCLK_INV_WIDTH                1  /* AIF1RX_LRCLK_INV */
+#define WM2200_AIF1RX_LRCLK_FRC                 0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM2200_AIF1RX_LRCLK_FRC_MASK            0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM2200_AIF1RX_LRCLK_FRC_SHIFT                1  /* AIF1RX_LRCLK_FRC */
+#define WM2200_AIF1RX_LRCLK_FRC_WIDTH                1  /* AIF1RX_LRCLK_FRC */
+#define WM2200_AIF1RX_LRCLK_MSTR                0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM2200_AIF1RX_LRCLK_MSTR_MASK           0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM2200_AIF1RX_LRCLK_MSTR_SHIFT               0  /* AIF1RX_LRCLK_MSTR */
+#define WM2200_AIF1RX_LRCLK_MSTR_WIDTH               1  /* AIF1RX_LRCLK_MSTR */
+
+/*
+ * R1283 (0x503) - Audio IF 1_4
+ */
+#define WM2200_AIF1_TRI                         0x0040  /* AIF1_TRI */
+#define WM2200_AIF1_TRI_MASK                    0x0040  /* AIF1_TRI */
+#define WM2200_AIF1_TRI_SHIFT                        6  /* AIF1_TRI */
+#define WM2200_AIF1_TRI_WIDTH                        1  /* AIF1_TRI */
+
+/*
+ * R1284 (0x504) - Audio IF 1_5
+ */
+#define WM2200_AIF1_FMT_MASK                    0x0007  /* AIF1_FMT - [2:0] */
+#define WM2200_AIF1_FMT_SHIFT                        0  /* AIF1_FMT - [2:0] */
+#define WM2200_AIF1_FMT_WIDTH                        3  /* AIF1_FMT - [2:0] */
+
+/*
+ * R1285 (0x505) - Audio IF 1_6
+ */
+#define WM2200_AIF1TX_BCPF_MASK                 0x07FF  /* AIF1TX_BCPF - [10:0] */
+#define WM2200_AIF1TX_BCPF_SHIFT                     0  /* AIF1TX_BCPF - [10:0] */
+#define WM2200_AIF1TX_BCPF_WIDTH                    11  /* AIF1TX_BCPF - [10:0] */
+
+/*
+ * R1286 (0x506) - Audio IF 1_7
+ */
+#define WM2200_AIF1RX_BCPF_MASK                 0x07FF  /* AIF1RX_BCPF - [10:0] */
+#define WM2200_AIF1RX_BCPF_SHIFT                     0  /* AIF1RX_BCPF - [10:0] */
+#define WM2200_AIF1RX_BCPF_WIDTH                    11  /* AIF1RX_BCPF - [10:0] */
+
+/*
+ * R1287 (0x507) - Audio IF 1_8
+ */
+#define WM2200_AIF1TX_WL_MASK                   0x3F00  /* AIF1TX_WL - [13:8] */
+#define WM2200_AIF1TX_WL_SHIFT                       8  /* AIF1TX_WL - [13:8] */
+#define WM2200_AIF1TX_WL_WIDTH                       6  /* AIF1TX_WL - [13:8] */
+#define WM2200_AIF1TX_SLOT_LEN_MASK             0x00FF  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM2200_AIF1TX_SLOT_LEN_SHIFT                 0  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM2200_AIF1TX_SLOT_LEN_WIDTH                 8  /* AIF1TX_SLOT_LEN - [7:0] */
+
+/*
+ * R1288 (0x508) - Audio IF 1_9
+ */
+#define WM2200_AIF1RX_WL_MASK                   0x3F00  /* AIF1RX_WL - [13:8] */
+#define WM2200_AIF1RX_WL_SHIFT                       8  /* AIF1RX_WL - [13:8] */
+#define WM2200_AIF1RX_WL_WIDTH                       6  /* AIF1RX_WL - [13:8] */
+#define WM2200_AIF1RX_SLOT_LEN_MASK             0x00FF  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM2200_AIF1RX_SLOT_LEN_SHIFT                 0  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM2200_AIF1RX_SLOT_LEN_WIDTH                 8  /* AIF1RX_SLOT_LEN - [7:0] */
+
+/*
+ * R1289 (0x509) - Audio IF 1_10
+ */
+#define WM2200_AIF1TX1_SLOT_MASK                0x003F  /* AIF1TX1_SLOT - [5:0] */
+#define WM2200_AIF1TX1_SLOT_SHIFT                    0  /* AIF1TX1_SLOT - [5:0] */
+#define WM2200_AIF1TX1_SLOT_WIDTH                    6  /* AIF1TX1_SLOT - [5:0] */
+
+/*
+ * R1290 (0x50A) - Audio IF 1_11
+ */
+#define WM2200_AIF1TX2_SLOT_MASK                0x003F  /* AIF1TX2_SLOT - [5:0] */
+#define WM2200_AIF1TX2_SLOT_SHIFT                    0  /* AIF1TX2_SLOT - [5:0] */
+#define WM2200_AIF1TX2_SLOT_WIDTH                    6  /* AIF1TX2_SLOT - [5:0] */
+
+/*
+ * R1291 (0x50B) - Audio IF 1_12
+ */
+#define WM2200_AIF1TX3_SLOT_MASK                0x003F  /* AIF1TX3_SLOT - [5:0] */
+#define WM2200_AIF1TX3_SLOT_SHIFT                    0  /* AIF1TX3_SLOT - [5:0] */
+#define WM2200_AIF1TX3_SLOT_WIDTH                    6  /* AIF1TX3_SLOT - [5:0] */
+
+/*
+ * R1292 (0x50C) - Audio IF 1_13
+ */
+#define WM2200_AIF1TX4_SLOT_MASK                0x003F  /* AIF1TX4_SLOT - [5:0] */
+#define WM2200_AIF1TX4_SLOT_SHIFT                    0  /* AIF1TX4_SLOT - [5:0] */
+#define WM2200_AIF1TX4_SLOT_WIDTH                    6  /* AIF1TX4_SLOT - [5:0] */
+
+/*
+ * R1293 (0x50D) - Audio IF 1_14
+ */
+#define WM2200_AIF1TX5_SLOT_MASK                0x003F  /* AIF1TX5_SLOT - [5:0] */
+#define WM2200_AIF1TX5_SLOT_SHIFT                    0  /* AIF1TX5_SLOT - [5:0] */
+#define WM2200_AIF1TX5_SLOT_WIDTH                    6  /* AIF1TX5_SLOT - [5:0] */
+
+/*
+ * R1294 (0x50E) - Audio IF 1_15
+ */
+#define WM2200_AIF1TX6_SLOT_MASK                0x003F  /* AIF1TX6_SLOT - [5:0] */
+#define WM2200_AIF1TX6_SLOT_SHIFT                    0  /* AIF1TX6_SLOT - [5:0] */
+#define WM2200_AIF1TX6_SLOT_WIDTH                    6  /* AIF1TX6_SLOT - [5:0] */
+
+/*
+ * R1295 (0x50F) - Audio IF 1_16
+ */
+#define WM2200_AIF1RX1_SLOT_MASK                0x003F  /* AIF1RX1_SLOT - [5:0] */
+#define WM2200_AIF1RX1_SLOT_SHIFT                    0  /* AIF1RX1_SLOT - [5:0] */
+#define WM2200_AIF1RX1_SLOT_WIDTH                    6  /* AIF1RX1_SLOT - [5:0] */
+
+/*
+ * R1296 (0x510) - Audio IF 1_17
+ */
+#define WM2200_AIF1RX2_SLOT_MASK                0x003F  /* AIF1RX2_SLOT - [5:0] */
+#define WM2200_AIF1RX2_SLOT_SHIFT                    0  /* AIF1RX2_SLOT - [5:0] */
+#define WM2200_AIF1RX2_SLOT_WIDTH                    6  /* AIF1RX2_SLOT - [5:0] */
+
+/*
+ * R1297 (0x511) - Audio IF 1_18
+ */
+#define WM2200_AIF1RX3_SLOT_MASK                0x003F  /* AIF1RX3_SLOT - [5:0] */
+#define WM2200_AIF1RX3_SLOT_SHIFT                    0  /* AIF1RX3_SLOT - [5:0] */
+#define WM2200_AIF1RX3_SLOT_WIDTH                    6  /* AIF1RX3_SLOT - [5:0] */
+
+/*
+ * R1298 (0x512) - Audio IF 1_19
+ */
+#define WM2200_AIF1RX4_SLOT_MASK                0x003F  /* AIF1RX4_SLOT - [5:0] */
+#define WM2200_AIF1RX4_SLOT_SHIFT                    0  /* AIF1RX4_SLOT - [5:0] */
+#define WM2200_AIF1RX4_SLOT_WIDTH                    6  /* AIF1RX4_SLOT - [5:0] */
+
+/*
+ * R1299 (0x513) - Audio IF 1_20
+ */
+#define WM2200_AIF1RX5_SLOT_MASK                0x003F  /* AIF1RX5_SLOT - [5:0] */
+#define WM2200_AIF1RX5_SLOT_SHIFT                    0  /* AIF1RX5_SLOT - [5:0] */
+#define WM2200_AIF1RX5_SLOT_WIDTH                    6  /* AIF1RX5_SLOT - [5:0] */
+
+/*
+ * R1300 (0x514) - Audio IF 1_21
+ */
+#define WM2200_AIF1RX6_SLOT_MASK                0x003F  /* AIF1RX6_SLOT - [5:0] */
+#define WM2200_AIF1RX6_SLOT_SHIFT                    0  /* AIF1RX6_SLOT - [5:0] */
+#define WM2200_AIF1RX6_SLOT_WIDTH                    6  /* AIF1RX6_SLOT - [5:0] */
+
+/*
+ * R1301 (0x515) - Audio IF 1_22
+ */
+#define WM2200_AIF1RX6_ENA                      0x0800  /* AIF1RX6_ENA */
+#define WM2200_AIF1RX6_ENA_MASK                 0x0800  /* AIF1RX6_ENA */
+#define WM2200_AIF1RX6_ENA_SHIFT                    11  /* AIF1RX6_ENA */
+#define WM2200_AIF1RX6_ENA_WIDTH                     1  /* AIF1RX6_ENA */
+#define WM2200_AIF1RX5_ENA                      0x0400  /* AIF1RX5_ENA */
+#define WM2200_AIF1RX5_ENA_MASK                 0x0400  /* AIF1RX5_ENA */
+#define WM2200_AIF1RX5_ENA_SHIFT                    10  /* AIF1RX5_ENA */
+#define WM2200_AIF1RX5_ENA_WIDTH                     1  /* AIF1RX5_ENA */
+#define WM2200_AIF1RX4_ENA                      0x0200  /* AIF1RX4_ENA */
+#define WM2200_AIF1RX4_ENA_MASK                 0x0200  /* AIF1RX4_ENA */
+#define WM2200_AIF1RX4_ENA_SHIFT                     9  /* AIF1RX4_ENA */
+#define WM2200_AIF1RX4_ENA_WIDTH                     1  /* AIF1RX4_ENA */
+#define WM2200_AIF1RX3_ENA                      0x0100  /* AIF1RX3_ENA */
+#define WM2200_AIF1RX3_ENA_MASK                 0x0100  /* AIF1RX3_ENA */
+#define WM2200_AIF1RX3_ENA_SHIFT                     8  /* AIF1RX3_ENA */
+#define WM2200_AIF1RX3_ENA_WIDTH                     1  /* AIF1RX3_ENA */
+#define WM2200_AIF1RX2_ENA                      0x0080  /* AIF1RX2_ENA */
+#define WM2200_AIF1RX2_ENA_MASK                 0x0080  /* AIF1RX2_ENA */
+#define WM2200_AIF1RX2_ENA_SHIFT                     7  /* AIF1RX2_ENA */
+#define WM2200_AIF1RX2_ENA_WIDTH                     1  /* AIF1RX2_ENA */
+#define WM2200_AIF1RX1_ENA                      0x0040  /* AIF1RX1_ENA */
+#define WM2200_AIF1RX1_ENA_MASK                 0x0040  /* AIF1RX1_ENA */
+#define WM2200_AIF1RX1_ENA_SHIFT                     6  /* AIF1RX1_ENA */
+#define WM2200_AIF1RX1_ENA_WIDTH                     1  /* AIF1RX1_ENA */
+#define WM2200_AIF1TX6_ENA                      0x0020  /* AIF1TX6_ENA */
+#define WM2200_AIF1TX6_ENA_MASK                 0x0020  /* AIF1TX6_ENA */
+#define WM2200_AIF1TX6_ENA_SHIFT                     5  /* AIF1TX6_ENA */
+#define WM2200_AIF1TX6_ENA_WIDTH                     1  /* AIF1TX6_ENA */
+#define WM2200_AIF1TX5_ENA                      0x0010  /* AIF1TX5_ENA */
+#define WM2200_AIF1TX5_ENA_MASK                 0x0010  /* AIF1TX5_ENA */
+#define WM2200_AIF1TX5_ENA_SHIFT                     4  /* AIF1TX5_ENA */
+#define WM2200_AIF1TX5_ENA_WIDTH                     1  /* AIF1TX5_ENA */
+#define WM2200_AIF1TX4_ENA                      0x0008  /* AIF1TX4_ENA */
+#define WM2200_AIF1TX4_ENA_MASK                 0x0008  /* AIF1TX4_ENA */
+#define WM2200_AIF1TX4_ENA_SHIFT                     3  /* AIF1TX4_ENA */
+#define WM2200_AIF1TX4_ENA_WIDTH                     1  /* AIF1TX4_ENA */
+#define WM2200_AIF1TX3_ENA                      0x0004  /* AIF1TX3_ENA */
+#define WM2200_AIF1TX3_ENA_MASK                 0x0004  /* AIF1TX3_ENA */
+#define WM2200_AIF1TX3_ENA_SHIFT                     2  /* AIF1TX3_ENA */
+#define WM2200_AIF1TX3_ENA_WIDTH                     1  /* AIF1TX3_ENA */
+#define WM2200_AIF1TX2_ENA                      0x0002  /* AIF1TX2_ENA */
+#define WM2200_AIF1TX2_ENA_MASK                 0x0002  /* AIF1TX2_ENA */
+#define WM2200_AIF1TX2_ENA_SHIFT                     1  /* AIF1TX2_ENA */
+#define WM2200_AIF1TX2_ENA_WIDTH                     1  /* AIF1TX2_ENA */
+#define WM2200_AIF1TX1_ENA                      0x0001  /* AIF1TX1_ENA */
+#define WM2200_AIF1TX1_ENA_MASK                 0x0001  /* AIF1TX1_ENA */
+#define WM2200_AIF1TX1_ENA_SHIFT                     0  /* AIF1TX1_ENA */
+#define WM2200_AIF1TX1_ENA_WIDTH                     1  /* AIF1TX1_ENA */
+
+/*
+ * R1536 (0x600) - OUT1LMIX Input 1 Source
+ */
+#define WM2200_OUT1LMIX_SRC1_MASK               0x007F  /* OUT1LMIX_SRC1 - [6:0] */
+#define WM2200_OUT1LMIX_SRC1_SHIFT                   0  /* OUT1LMIX_SRC1 - [6:0] */
+#define WM2200_OUT1LMIX_SRC1_WIDTH                   7  /* OUT1LMIX_SRC1 - [6:0] */
+
+/*
+ * R1537 (0x601) - OUT1LMIX Input 1 Volume
+ */
+#define WM2200_OUT1LMIX_VOL1_MASK               0x00FE  /* OUT1LMIX_VOL1 - [7:1] */
+#define WM2200_OUT1LMIX_VOL1_SHIFT                   1  /* OUT1LMIX_VOL1 - [7:1] */
+#define WM2200_OUT1LMIX_VOL1_WIDTH                   7  /* OUT1LMIX_VOL1 - [7:1] */
+
+/*
+ * R1538 (0x602) - OUT1LMIX Input 2 Source
+ */
+#define WM2200_OUT1LMIX_SRC2_MASK               0x007F  /* OUT1LMIX_SRC2 - [6:0] */
+#define WM2200_OUT1LMIX_SRC2_SHIFT                   0  /* OUT1LMIX_SRC2 - [6:0] */
+#define WM2200_OUT1LMIX_SRC2_WIDTH                   7  /* OUT1LMIX_SRC2 - [6:0] */
+
+/*
+ * R1539 (0x603) - OUT1LMIX Input 2 Volume
+ */
+#define WM2200_OUT1LMIX_VOL2_MASK               0x00FE  /* OUT1LMIX_VOL2 - [7:1] */
+#define WM2200_OUT1LMIX_VOL2_SHIFT                   1  /* OUT1LMIX_VOL2 - [7:1] */
+#define WM2200_OUT1LMIX_VOL2_WIDTH                   7  /* OUT1LMIX_VOL2 - [7:1] */
+
+/*
+ * R1540 (0x604) - OUT1LMIX Input 3 Source
+ */
+#define WM2200_OUT1LMIX_SRC3_MASK               0x007F  /* OUT1LMIX_SRC3 - [6:0] */
+#define WM2200_OUT1LMIX_SRC3_SHIFT                   0  /* OUT1LMIX_SRC3 - [6:0] */
+#define WM2200_OUT1LMIX_SRC3_WIDTH                   7  /* OUT1LMIX_SRC3 - [6:0] */
+
+/*
+ * R1541 (0x605) - OUT1LMIX Input 3 Volume
+ */
+#define WM2200_OUT1LMIX_VOL3_MASK               0x00FE  /* OUT1LMIX_VOL3 - [7:1] */
+#define WM2200_OUT1LMIX_VOL3_SHIFT                   1  /* OUT1LMIX_VOL3 - [7:1] */
+#define WM2200_OUT1LMIX_VOL3_WIDTH                   7  /* OUT1LMIX_VOL3 - [7:1] */
+
+/*
+ * R1542 (0x606) - OUT1LMIX Input 4 Source
+ */
+#define WM2200_OUT1LMIX_SRC4_MASK               0x007F  /* OUT1LMIX_SRC4 - [6:0] */
+#define WM2200_OUT1LMIX_SRC4_SHIFT                   0  /* OUT1LMIX_SRC4 - [6:0] */
+#define WM2200_OUT1LMIX_SRC4_WIDTH                   7  /* OUT1LMIX_SRC4 - [6:0] */
+
+/*
+ * R1543 (0x607) - OUT1LMIX Input 4 Volume
+ */
+#define WM2200_OUT1LMIX_VOL4_MASK               0x00FE  /* OUT1LMIX_VOL4 - [7:1] */
+#define WM2200_OUT1LMIX_VOL4_SHIFT                   1  /* OUT1LMIX_VOL4 - [7:1] */
+#define WM2200_OUT1LMIX_VOL4_WIDTH                   7  /* OUT1LMIX_VOL4 - [7:1] */
+
+/*
+ * R1544 (0x608) - OUT1RMIX Input 1 Source
+ */
+#define WM2200_OUT1RMIX_SRC1_MASK               0x007F  /* OUT1RMIX_SRC1 - [6:0] */
+#define WM2200_OUT1RMIX_SRC1_SHIFT                   0  /* OUT1RMIX_SRC1 - [6:0] */
+#define WM2200_OUT1RMIX_SRC1_WIDTH                   7  /* OUT1RMIX_SRC1 - [6:0] */
+
+/*
+ * R1545 (0x609) - OUT1RMIX Input 1 Volume
+ */
+#define WM2200_OUT1RMIX_VOL1_MASK               0x00FE  /* OUT1RMIX_VOL1 - [7:1] */
+#define WM2200_OUT1RMIX_VOL1_SHIFT                   1  /* OUT1RMIX_VOL1 - [7:1] */
+#define WM2200_OUT1RMIX_VOL1_WIDTH                   7  /* OUT1RMIX_VOL1 - [7:1] */
+
+/*
+ * R1546 (0x60A) - OUT1RMIX Input 2 Source
+ */
+#define WM2200_OUT1RMIX_SRC2_MASK               0x007F  /* OUT1RMIX_SRC2 - [6:0] */
+#define WM2200_OUT1RMIX_SRC2_SHIFT                   0  /* OUT1RMIX_SRC2 - [6:0] */
+#define WM2200_OUT1RMIX_SRC2_WIDTH                   7  /* OUT1RMIX_SRC2 - [6:0] */
+
+/*
+ * R1547 (0x60B) - OUT1RMIX Input 2 Volume
+ */
+#define WM2200_OUT1RMIX_VOL2_MASK               0x00FE  /* OUT1RMIX_VOL2 - [7:1] */
+#define WM2200_OUT1RMIX_VOL2_SHIFT                   1  /* OUT1RMIX_VOL2 - [7:1] */
+#define WM2200_OUT1RMIX_VOL2_WIDTH                   7  /* OUT1RMIX_VOL2 - [7:1] */
+
+/*
+ * R1548 (0x60C) - OUT1RMIX Input 3 Source
+ */
+#define WM2200_OUT1RMIX_SRC3_MASK               0x007F  /* OUT1RMIX_SRC3 - [6:0] */
+#define WM2200_OUT1RMIX_SRC3_SHIFT                   0  /* OUT1RMIX_SRC3 - [6:0] */
+#define WM2200_OUT1RMIX_SRC3_WIDTH                   7  /* OUT1RMIX_SRC3 - [6:0] */
+
+/*
+ * R1549 (0x60D) - OUT1RMIX Input 3 Volume
+ */
+#define WM2200_OUT1RMIX_VOL3_MASK               0x00FE  /* OUT1RMIX_VOL3 - [7:1] */
+#define WM2200_OUT1RMIX_VOL3_SHIFT                   1  /* OUT1RMIX_VOL3 - [7:1] */
+#define WM2200_OUT1RMIX_VOL3_WIDTH                   7  /* OUT1RMIX_VOL3 - [7:1] */
+
+/*
+ * R1550 (0x60E) - OUT1RMIX Input 4 Source
+ */
+#define WM2200_OUT1RMIX_SRC4_MASK               0x007F  /* OUT1RMIX_SRC4 - [6:0] */
+#define WM2200_OUT1RMIX_SRC4_SHIFT                   0  /* OUT1RMIX_SRC4 - [6:0] */
+#define WM2200_OUT1RMIX_SRC4_WIDTH                   7  /* OUT1RMIX_SRC4 - [6:0] */
+
+/*
+ * R1551 (0x60F) - OUT1RMIX Input 4 Volume
+ */
+#define WM2200_OUT1RMIX_VOL4_MASK               0x00FE  /* OUT1RMIX_VOL4 - [7:1] */
+#define WM2200_OUT1RMIX_VOL4_SHIFT                   1  /* OUT1RMIX_VOL4 - [7:1] */
+#define WM2200_OUT1RMIX_VOL4_WIDTH                   7  /* OUT1RMIX_VOL4 - [7:1] */
+
+/*
+ * R1552 (0x610) - OUT2LMIX Input 1 Source
+ */
+#define WM2200_OUT2LMIX_SRC1_MASK               0x007F  /* OUT2LMIX_SRC1 - [6:0] */
+#define WM2200_OUT2LMIX_SRC1_SHIFT                   0  /* OUT2LMIX_SRC1 - [6:0] */
+#define WM2200_OUT2LMIX_SRC1_WIDTH                   7  /* OUT2LMIX_SRC1 - [6:0] */
+
+/*
+ * R1553 (0x611) - OUT2LMIX Input 1 Volume
+ */
+#define WM2200_OUT2LMIX_VOL1_MASK               0x00FE  /* OUT2LMIX_VOL1 - [7:1] */
+#define WM2200_OUT2LMIX_VOL1_SHIFT                   1  /* OUT2LMIX_VOL1 - [7:1] */
+#define WM2200_OUT2LMIX_VOL1_WIDTH                   7  /* OUT2LMIX_VOL1 - [7:1] */
+
+/*
+ * R1554 (0x612) - OUT2LMIX Input 2 Source
+ */
+#define WM2200_OUT2LMIX_SRC2_MASK               0x007F  /* OUT2LMIX_SRC2 - [6:0] */
+#define WM2200_OUT2LMIX_SRC2_SHIFT                   0  /* OUT2LMIX_SRC2 - [6:0] */
+#define WM2200_OUT2LMIX_SRC2_WIDTH                   7  /* OUT2LMIX_SRC2 - [6:0] */
+
+/*
+ * R1555 (0x613) - OUT2LMIX Input 2 Volume
+ */
+#define WM2200_OUT2LMIX_VOL2_MASK               0x00FE  /* OUT2LMIX_VOL2 - [7:1] */
+#define WM2200_OUT2LMIX_VOL2_SHIFT                   1  /* OUT2LMIX_VOL2 - [7:1] */
+#define WM2200_OUT2LMIX_VOL2_WIDTH                   7  /* OUT2LMIX_VOL2 - [7:1] */
+
+/*
+ * R1556 (0x614) - OUT2LMIX Input 3 Source
+ */
+#define WM2200_OUT2LMIX_SRC3_MASK               0x007F  /* OUT2LMIX_SRC3 - [6:0] */
+#define WM2200_OUT2LMIX_SRC3_SHIFT                   0  /* OUT2LMIX_SRC3 - [6:0] */
+#define WM2200_OUT2LMIX_SRC3_WIDTH                   7  /* OUT2LMIX_SRC3 - [6:0] */
+
+/*
+ * R1557 (0x615) - OUT2LMIX Input 3 Volume
+ */
+#define WM2200_OUT2LMIX_VOL3_MASK               0x00FE  /* OUT2LMIX_VOL3 - [7:1] */
+#define WM2200_OUT2LMIX_VOL3_SHIFT                   1  /* OUT2LMIX_VOL3 - [7:1] */
+#define WM2200_OUT2LMIX_VOL3_WIDTH                   7  /* OUT2LMIX_VOL3 - [7:1] */
+
+/*
+ * R1558 (0x616) - OUT2LMIX Input 4 Source
+ */
+#define WM2200_OUT2LMIX_SRC4_MASK               0x007F  /* OUT2LMIX_SRC4 - [6:0] */
+#define WM2200_OUT2LMIX_SRC4_SHIFT                   0  /* OUT2LMIX_SRC4 - [6:0] */
+#define WM2200_OUT2LMIX_SRC4_WIDTH                   7  /* OUT2LMIX_SRC4 - [6:0] */
+
+/*
+ * R1559 (0x617) - OUT2LMIX Input 4 Volume
+ */
+#define WM2200_OUT2LMIX_VOL4_MASK               0x00FE  /* OUT2LMIX_VOL4 - [7:1] */
+#define WM2200_OUT2LMIX_VOL4_SHIFT                   1  /* OUT2LMIX_VOL4 - [7:1] */
+#define WM2200_OUT2LMIX_VOL4_WIDTH                   7  /* OUT2LMIX_VOL4 - [7:1] */
+
+/*
+ * R1560 (0x618) - OUT2RMIX Input 1 Source
+ */
+#define WM2200_OUT2RMIX_SRC1_MASK               0x007F  /* OUT2RMIX_SRC1 - [6:0] */
+#define WM2200_OUT2RMIX_SRC1_SHIFT                   0  /* OUT2RMIX_SRC1 - [6:0] */
+#define WM2200_OUT2RMIX_SRC1_WIDTH                   7  /* OUT2RMIX_SRC1 - [6:0] */
+
+/*
+ * R1561 (0x619) - OUT2RMIX Input 1 Volume
+ */
+#define WM2200_OUT2RMIX_VOL1_MASK               0x00FE  /* OUT2RMIX_VOL1 - [7:1] */
+#define WM2200_OUT2RMIX_VOL1_SHIFT                   1  /* OUT2RMIX_VOL1 - [7:1] */
+#define WM2200_OUT2RMIX_VOL1_WIDTH                   7  /* OUT2RMIX_VOL1 - [7:1] */
+
+/*
+ * R1562 (0x61A) - OUT2RMIX Input 2 Source
+ */
+#define WM2200_OUT2RMIX_SRC2_MASK               0x007F  /* OUT2RMIX_SRC2 - [6:0] */
+#define WM2200_OUT2RMIX_SRC2_SHIFT                   0  /* OUT2RMIX_SRC2 - [6:0] */
+#define WM2200_OUT2RMIX_SRC2_WIDTH                   7  /* OUT2RMIX_SRC2 - [6:0] */
+
+/*
+ * R1563 (0x61B) - OUT2RMIX Input 2 Volume
+ */
+#define WM2200_OUT2RMIX_VOL2_MASK               0x00FE  /* OUT2RMIX_VOL2 - [7:1] */
+#define WM2200_OUT2RMIX_VOL2_SHIFT                   1  /* OUT2RMIX_VOL2 - [7:1] */
+#define WM2200_OUT2RMIX_VOL2_WIDTH                   7  /* OUT2RMIX_VOL2 - [7:1] */
+
+/*
+ * R1564 (0x61C) - OUT2RMIX Input 3 Source
+ */
+#define WM2200_OUT2RMIX_SRC3_MASK               0x007F  /* OUT2RMIX_SRC3 - [6:0] */
+#define WM2200_OUT2RMIX_SRC3_SHIFT                   0  /* OUT2RMIX_SRC3 - [6:0] */
+#define WM2200_OUT2RMIX_SRC3_WIDTH                   7  /* OUT2RMIX_SRC3 - [6:0] */
+
+/*
+ * R1565 (0x61D) - OUT2RMIX Input 3 Volume
+ */
+#define WM2200_OUT2RMIX_VOL3_MASK               0x00FE  /* OUT2RMIX_VOL3 - [7:1] */
+#define WM2200_OUT2RMIX_VOL3_SHIFT                   1  /* OUT2RMIX_VOL3 - [7:1] */
+#define WM2200_OUT2RMIX_VOL3_WIDTH                   7  /* OUT2RMIX_VOL3 - [7:1] */
+
+/*
+ * R1566 (0x61E) - OUT2RMIX Input 4 Source
+ */
+#define WM2200_OUT2RMIX_SRC4_MASK               0x007F  /* OUT2RMIX_SRC4 - [6:0] */
+#define WM2200_OUT2RMIX_SRC4_SHIFT                   0  /* OUT2RMIX_SRC4 - [6:0] */
+#define WM2200_OUT2RMIX_SRC4_WIDTH                   7  /* OUT2RMIX_SRC4 - [6:0] */
+
+/*
+ * R1567 (0x61F) - OUT2RMIX Input 4 Volume
+ */
+#define WM2200_OUT2RMIX_VOL4_MASK               0x00FE  /* OUT2RMIX_VOL4 - [7:1] */
+#define WM2200_OUT2RMIX_VOL4_SHIFT                   1  /* OUT2RMIX_VOL4 - [7:1] */
+#define WM2200_OUT2RMIX_VOL4_WIDTH                   7  /* OUT2RMIX_VOL4 - [7:1] */
+
+/*
+ * R1568 (0x620) - AIF1TX1MIX Input 1 Source
+ */
+#define WM2200_AIF1TX1MIX_SRC1_MASK             0x007F  /* AIF1TX1MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC1_SHIFT                 0  /* AIF1TX1MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC1_WIDTH                 7  /* AIF1TX1MIX_SRC1 - [6:0] */
+
+/*
+ * R1569 (0x621) - AIF1TX1MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX1MIX_VOL1_MASK             0x00FE  /* AIF1TX1MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL1_SHIFT                 1  /* AIF1TX1MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL1_WIDTH                 7  /* AIF1TX1MIX_VOL1 - [7:1] */
+
+/*
+ * R1570 (0x622) - AIF1TX1MIX Input 2 Source
+ */
+#define WM2200_AIF1TX1MIX_SRC2_MASK             0x007F  /* AIF1TX1MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC2_SHIFT                 0  /* AIF1TX1MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC2_WIDTH                 7  /* AIF1TX1MIX_SRC2 - [6:0] */
+
+/*
+ * R1571 (0x623) - AIF1TX1MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX1MIX_VOL2_MASK             0x00FE  /* AIF1TX1MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL2_SHIFT                 1  /* AIF1TX1MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL2_WIDTH                 7  /* AIF1TX1MIX_VOL2 - [7:1] */
+
+/*
+ * R1572 (0x624) - AIF1TX1MIX Input 3 Source
+ */
+#define WM2200_AIF1TX1MIX_SRC3_MASK             0x007F  /* AIF1TX1MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC3_SHIFT                 0  /* AIF1TX1MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC3_WIDTH                 7  /* AIF1TX1MIX_SRC3 - [6:0] */
+
+/*
+ * R1573 (0x625) - AIF1TX1MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX1MIX_VOL3_MASK             0x00FE  /* AIF1TX1MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL3_SHIFT                 1  /* AIF1TX1MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL3_WIDTH                 7  /* AIF1TX1MIX_VOL3 - [7:1] */
+
+/*
+ * R1574 (0x626) - AIF1TX1MIX Input 4 Source
+ */
+#define WM2200_AIF1TX1MIX_SRC4_MASK             0x007F  /* AIF1TX1MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC4_SHIFT                 0  /* AIF1TX1MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC4_WIDTH                 7  /* AIF1TX1MIX_SRC4 - [6:0] */
+
+/*
+ * R1575 (0x627) - AIF1TX1MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX1MIX_VOL4_MASK             0x00FE  /* AIF1TX1MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL4_SHIFT                 1  /* AIF1TX1MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL4_WIDTH                 7  /* AIF1TX1MIX_VOL4 - [7:1] */
+
+/*
+ * R1576 (0x628) - AIF1TX2MIX Input 1 Source
+ */
+#define WM2200_AIF1TX2MIX_SRC1_MASK             0x007F  /* AIF1TX2MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC1_SHIFT                 0  /* AIF1TX2MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC1_WIDTH                 7  /* AIF1TX2MIX_SRC1 - [6:0] */
+
+/*
+ * R1577 (0x629) - AIF1TX2MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX2MIX_VOL1_MASK             0x00FE  /* AIF1TX2MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL1_SHIFT                 1  /* AIF1TX2MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL1_WIDTH                 7  /* AIF1TX2MIX_VOL1 - [7:1] */
+
+/*
+ * R1578 (0x62A) - AIF1TX2MIX Input 2 Source
+ */
+#define WM2200_AIF1TX2MIX_SRC2_MASK             0x007F  /* AIF1TX2MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC2_SHIFT                 0  /* AIF1TX2MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC2_WIDTH                 7  /* AIF1TX2MIX_SRC2 - [6:0] */
+
+/*
+ * R1579 (0x62B) - AIF1TX2MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX2MIX_VOL2_MASK             0x00FE  /* AIF1TX2MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL2_SHIFT                 1  /* AIF1TX2MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL2_WIDTH                 7  /* AIF1TX2MIX_VOL2 - [7:1] */
+
+/*
+ * R1580 (0x62C) - AIF1TX2MIX Input 3 Source
+ */
+#define WM2200_AIF1TX2MIX_SRC3_MASK             0x007F  /* AIF1TX2MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC3_SHIFT                 0  /* AIF1TX2MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC3_WIDTH                 7  /* AIF1TX2MIX_SRC3 - [6:0] */
+
+/*
+ * R1581 (0x62D) - AIF1TX2MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX2MIX_VOL3_MASK             0x00FE  /* AIF1TX2MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL3_SHIFT                 1  /* AIF1TX2MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL3_WIDTH                 7  /* AIF1TX2MIX_VOL3 - [7:1] */
+
+/*
+ * R1582 (0x62E) - AIF1TX2MIX Input 4 Source
+ */
+#define WM2200_AIF1TX2MIX_SRC4_MASK             0x007F  /* AIF1TX2MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC4_SHIFT                 0  /* AIF1TX2MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC4_WIDTH                 7  /* AIF1TX2MIX_SRC4 - [6:0] */
+
+/*
+ * R1583 (0x62F) - AIF1TX2MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX2MIX_VOL4_MASK             0x00FE  /* AIF1TX2MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL4_SHIFT                 1  /* AIF1TX2MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL4_WIDTH                 7  /* AIF1TX2MIX_VOL4 - [7:1] */
+
+/*
+ * R1584 (0x630) - AIF1TX3MIX Input 1 Source
+ */
+#define WM2200_AIF1TX3MIX_SRC1_MASK             0x007F  /* AIF1TX3MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC1_SHIFT                 0  /* AIF1TX3MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC1_WIDTH                 7  /* AIF1TX3MIX_SRC1 - [6:0] */
+
+/*
+ * R1585 (0x631) - AIF1TX3MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX3MIX_VOL1_MASK             0x00FE  /* AIF1TX3MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL1_SHIFT                 1  /* AIF1TX3MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL1_WIDTH                 7  /* AIF1TX3MIX_VOL1 - [7:1] */
+
+/*
+ * R1586 (0x632) - AIF1TX3MIX Input 2 Source
+ */
+#define WM2200_AIF1TX3MIX_SRC2_MASK             0x007F  /* AIF1TX3MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC2_SHIFT                 0  /* AIF1TX3MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC2_WIDTH                 7  /* AIF1TX3MIX_SRC2 - [6:0] */
+
+/*
+ * R1587 (0x633) - AIF1TX3MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX3MIX_VOL2_MASK             0x00FE  /* AIF1TX3MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL2_SHIFT                 1  /* AIF1TX3MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL2_WIDTH                 7  /* AIF1TX3MIX_VOL2 - [7:1] */
+
+/*
+ * R1588 (0x634) - AIF1TX3MIX Input 3 Source
+ */
+#define WM2200_AIF1TX3MIX_SRC3_MASK             0x007F  /* AIF1TX3MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC3_SHIFT                 0  /* AIF1TX3MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC3_WIDTH                 7  /* AIF1TX3MIX_SRC3 - [6:0] */
+
+/*
+ * R1589 (0x635) - AIF1TX3MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX3MIX_VOL3_MASK             0x00FE  /* AIF1TX3MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL3_SHIFT                 1  /* AIF1TX3MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL3_WIDTH                 7  /* AIF1TX3MIX_VOL3 - [7:1] */
+
+/*
+ * R1590 (0x636) - AIF1TX3MIX Input 4 Source
+ */
+#define WM2200_AIF1TX3MIX_SRC4_MASK             0x007F  /* AIF1TX3MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC4_SHIFT                 0  /* AIF1TX3MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC4_WIDTH                 7  /* AIF1TX3MIX_SRC4 - [6:0] */
+
+/*
+ * R1591 (0x637) - AIF1TX3MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX3MIX_VOL4_MASK             0x00FE  /* AIF1TX3MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL4_SHIFT                 1  /* AIF1TX3MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL4_WIDTH                 7  /* AIF1TX3MIX_VOL4 - [7:1] */
+
+/*
+ * R1592 (0x638) - AIF1TX4MIX Input 1 Source
+ */
+#define WM2200_AIF1TX4MIX_SRC1_MASK             0x007F  /* AIF1TX4MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC1_SHIFT                 0  /* AIF1TX4MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC1_WIDTH                 7  /* AIF1TX4MIX_SRC1 - [6:0] */
+
+/*
+ * R1593 (0x639) - AIF1TX4MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX4MIX_VOL1_MASK             0x00FE  /* AIF1TX4MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL1_SHIFT                 1  /* AIF1TX4MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL1_WIDTH                 7  /* AIF1TX4MIX_VOL1 - [7:1] */
+
+/*
+ * R1594 (0x63A) - AIF1TX4MIX Input 2 Source
+ */
+#define WM2200_AIF1TX4MIX_SRC2_MASK             0x007F  /* AIF1TX4MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC2_SHIFT                 0  /* AIF1TX4MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC2_WIDTH                 7  /* AIF1TX4MIX_SRC2 - [6:0] */
+
+/*
+ * R1595 (0x63B) - AIF1TX4MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX4MIX_VOL2_MASK             0x00FE  /* AIF1TX4MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL2_SHIFT                 1  /* AIF1TX4MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL2_WIDTH                 7  /* AIF1TX4MIX_VOL2 - [7:1] */
+
+/*
+ * R1596 (0x63C) - AIF1TX4MIX Input 3 Source
+ */
+#define WM2200_AIF1TX4MIX_SRC3_MASK             0x007F  /* AIF1TX4MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC3_SHIFT                 0  /* AIF1TX4MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC3_WIDTH                 7  /* AIF1TX4MIX_SRC3 - [6:0] */
+
+/*
+ * R1597 (0x63D) - AIF1TX4MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX4MIX_VOL3_MASK             0x00FE  /* AIF1TX4MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL3_SHIFT                 1  /* AIF1TX4MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL3_WIDTH                 7  /* AIF1TX4MIX_VOL3 - [7:1] */
+
+/*
+ * R1598 (0x63E) - AIF1TX4MIX Input 4 Source
+ */
+#define WM2200_AIF1TX4MIX_SRC4_MASK             0x007F  /* AIF1TX4MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC4_SHIFT                 0  /* AIF1TX4MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC4_WIDTH                 7  /* AIF1TX4MIX_SRC4 - [6:0] */
+
+/*
+ * R1599 (0x63F) - AIF1TX4MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX4MIX_VOL4_MASK             0x00FE  /* AIF1TX4MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL4_SHIFT                 1  /* AIF1TX4MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL4_WIDTH                 7  /* AIF1TX4MIX_VOL4 - [7:1] */
+
+/*
+ * R1600 (0x640) - AIF1TX5MIX Input 1 Source
+ */
+#define WM2200_AIF1TX5MIX_SRC1_MASK             0x007F  /* AIF1TX5MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC1_SHIFT                 0  /* AIF1TX5MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC1_WIDTH                 7  /* AIF1TX5MIX_SRC1 - [6:0] */
+
+/*
+ * R1601 (0x641) - AIF1TX5MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX5MIX_VOL1_MASK             0x00FE  /* AIF1TX5MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL1_SHIFT                 1  /* AIF1TX5MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL1_WIDTH                 7  /* AIF1TX5MIX_VOL1 - [7:1] */
+
+/*
+ * R1602 (0x642) - AIF1TX5MIX Input 2 Source
+ */
+#define WM2200_AIF1TX5MIX_SRC2_MASK             0x007F  /* AIF1TX5MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC2_SHIFT                 0  /* AIF1TX5MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC2_WIDTH                 7  /* AIF1TX5MIX_SRC2 - [6:0] */
+
+/*
+ * R1603 (0x643) - AIF1TX5MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX5MIX_VOL2_MASK             0x00FE  /* AIF1TX5MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL2_SHIFT                 1  /* AIF1TX5MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL2_WIDTH                 7  /* AIF1TX5MIX_VOL2 - [7:1] */
+
+/*
+ * R1604 (0x644) - AIF1TX5MIX Input 3 Source
+ */
+#define WM2200_AIF1TX5MIX_SRC3_MASK             0x007F  /* AIF1TX5MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC3_SHIFT                 0  /* AIF1TX5MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC3_WIDTH                 7  /* AIF1TX5MIX_SRC3 - [6:0] */
+
+/*
+ * R1605 (0x645) - AIF1TX5MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX5MIX_VOL3_MASK             0x00FE  /* AIF1TX5MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL3_SHIFT                 1  /* AIF1TX5MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL3_WIDTH                 7  /* AIF1TX5MIX_VOL3 - [7:1] */
+
+/*
+ * R1606 (0x646) - AIF1TX5MIX Input 4 Source
+ */
+#define WM2200_AIF1TX5MIX_SRC4_MASK             0x007F  /* AIF1TX5MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC4_SHIFT                 0  /* AIF1TX5MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC4_WIDTH                 7  /* AIF1TX5MIX_SRC4 - [6:0] */
+
+/*
+ * R1607 (0x647) - AIF1TX5MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX5MIX_VOL4_MASK             0x00FE  /* AIF1TX5MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL4_SHIFT                 1  /* AIF1TX5MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL4_WIDTH                 7  /* AIF1TX5MIX_VOL4 - [7:1] */
+
+/*
+ * R1608 (0x648) - AIF1TX6MIX Input 1 Source
+ */
+#define WM2200_AIF1TX6MIX_SRC1_MASK             0x007F  /* AIF1TX6MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC1_SHIFT                 0  /* AIF1TX6MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC1_WIDTH                 7  /* AIF1TX6MIX_SRC1 - [6:0] */
+
+/*
+ * R1609 (0x649) - AIF1TX6MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX6MIX_VOL1_MASK             0x00FE  /* AIF1TX6MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL1_SHIFT                 1  /* AIF1TX6MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL1_WIDTH                 7  /* AIF1TX6MIX_VOL1 - [7:1] */
+
+/*
+ * R1610 (0x64A) - AIF1TX6MIX Input 2 Source
+ */
+#define WM2200_AIF1TX6MIX_SRC2_MASK             0x007F  /* AIF1TX6MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC2_SHIFT                 0  /* AIF1TX6MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC2_WIDTH                 7  /* AIF1TX6MIX_SRC2 - [6:0] */
+
+/*
+ * R1611 (0x64B) - AIF1TX6MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX6MIX_VOL2_MASK             0x00FE  /* AIF1TX6MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL2_SHIFT                 1  /* AIF1TX6MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL2_WIDTH                 7  /* AIF1TX6MIX_VOL2 - [7:1] */
+
+/*
+ * R1612 (0x64C) - AIF1TX6MIX Input 3 Source
+ */
+#define WM2200_AIF1TX6MIX_SRC3_MASK             0x007F  /* AIF1TX6MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC3_SHIFT                 0  /* AIF1TX6MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC3_WIDTH                 7  /* AIF1TX6MIX_SRC3 - [6:0] */
+
+/*
+ * R1613 (0x64D) - AIF1TX6MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX6MIX_VOL3_MASK             0x00FE  /* AIF1TX6MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL3_SHIFT                 1  /* AIF1TX6MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL3_WIDTH                 7  /* AIF1TX6MIX_VOL3 - [7:1] */
+
+/*
+ * R1614 (0x64E) - AIF1TX6MIX Input 4 Source
+ */
+#define WM2200_AIF1TX6MIX_SRC4_MASK             0x007F  /* AIF1TX6MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC4_SHIFT                 0  /* AIF1TX6MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC4_WIDTH                 7  /* AIF1TX6MIX_SRC4 - [6:0] */
+
+/*
+ * R1615 (0x64F) - AIF1TX6MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX6MIX_VOL4_MASK             0x00FE  /* AIF1TX6MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL4_SHIFT                 1  /* AIF1TX6MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL4_WIDTH                 7  /* AIF1TX6MIX_VOL4 - [7:1] */
+
+/*
+ * R1616 (0x650) - EQLMIX Input 1 Source
+ */
+#define WM2200_EQLMIX_SRC1_MASK                 0x007F  /* EQLMIX_SRC1 - [6:0] */
+#define WM2200_EQLMIX_SRC1_SHIFT                     0  /* EQLMIX_SRC1 - [6:0] */
+#define WM2200_EQLMIX_SRC1_WIDTH                     7  /* EQLMIX_SRC1 - [6:0] */
+
+/*
+ * R1617 (0x651) - EQLMIX Input 1 Volume
+ */
+#define WM2200_EQLMIX_VOL1_MASK                 0x00FE  /* EQLMIX_VOL1 - [7:1] */
+#define WM2200_EQLMIX_VOL1_SHIFT                     1  /* EQLMIX_VOL1 - [7:1] */
+#define WM2200_EQLMIX_VOL1_WIDTH                     7  /* EQLMIX_VOL1 - [7:1] */
+
+/*
+ * R1618 (0x652) - EQLMIX Input 2 Source
+ */
+#define WM2200_EQLMIX_SRC2_MASK                 0x007F  /* EQLMIX_SRC2 - [6:0] */
+#define WM2200_EQLMIX_SRC2_SHIFT                     0  /* EQLMIX_SRC2 - [6:0] */
+#define WM2200_EQLMIX_SRC2_WIDTH                     7  /* EQLMIX_SRC2 - [6:0] */
+
+/*
+ * R1619 (0x653) - EQLMIX Input 2 Volume
+ */
+#define WM2200_EQLMIX_VOL2_MASK                 0x00FE  /* EQLMIX_VOL2 - [7:1] */
+#define WM2200_EQLMIX_VOL2_SHIFT                     1  /* EQLMIX_VOL2 - [7:1] */
+#define WM2200_EQLMIX_VOL2_WIDTH                     7  /* EQLMIX_VOL2 - [7:1] */
+
+/*
+ * R1620 (0x654) - EQLMIX Input 3 Source
+ */
+#define WM2200_EQLMIX_SRC3_MASK                 0x007F  /* EQLMIX_SRC3 - [6:0] */
+#define WM2200_EQLMIX_SRC3_SHIFT                     0  /* EQLMIX_SRC3 - [6:0] */
+#define WM2200_EQLMIX_SRC3_WIDTH                     7  /* EQLMIX_SRC3 - [6:0] */
+
+/*
+ * R1621 (0x655) - EQLMIX Input 3 Volume
+ */
+#define WM2200_EQLMIX_VOL3_MASK                 0x00FE  /* EQLMIX_VOL3 - [7:1] */
+#define WM2200_EQLMIX_VOL3_SHIFT                     1  /* EQLMIX_VOL3 - [7:1] */
+#define WM2200_EQLMIX_VOL3_WIDTH                     7  /* EQLMIX_VOL3 - [7:1] */
+
+/*
+ * R1622 (0x656) - EQLMIX Input 4 Source
+ */
+#define WM2200_EQLMIX_SRC4_MASK                 0x007F  /* EQLMIX_SRC4 - [6:0] */
+#define WM2200_EQLMIX_SRC4_SHIFT                     0  /* EQLMIX_SRC4 - [6:0] */
+#define WM2200_EQLMIX_SRC4_WIDTH                     7  /* EQLMIX_SRC4 - [6:0] */
+
+/*
+ * R1623 (0x657) - EQLMIX Input 4 Volume
+ */
+#define WM2200_EQLMIX_VOL4_MASK                 0x00FE  /* EQLMIX_VOL4 - [7:1] */
+#define WM2200_EQLMIX_VOL4_SHIFT                     1  /* EQLMIX_VOL4 - [7:1] */
+#define WM2200_EQLMIX_VOL4_WIDTH                     7  /* EQLMIX_VOL4 - [7:1] */
+
+/*
+ * R1624 (0x658) - EQRMIX Input 1 Source
+ */
+#define WM2200_EQRMIX_SRC1_MASK                 0x007F  /* EQRMIX_SRC1 - [6:0] */
+#define WM2200_EQRMIX_SRC1_SHIFT                     0  /* EQRMIX_SRC1 - [6:0] */
+#define WM2200_EQRMIX_SRC1_WIDTH                     7  /* EQRMIX_SRC1 - [6:0] */
+
+/*
+ * R1625 (0x659) - EQRMIX Input 1 Volume
+ */
+#define WM2200_EQRMIX_VOL1_MASK                 0x00FE  /* EQRMIX_VOL1 - [7:1] */
+#define WM2200_EQRMIX_VOL1_SHIFT                     1  /* EQRMIX_VOL1 - [7:1] */
+#define WM2200_EQRMIX_VOL1_WIDTH                     7  /* EQRMIX_VOL1 - [7:1] */
+
+/*
+ * R1626 (0x65A) - EQRMIX Input 2 Source
+ */
+#define WM2200_EQRMIX_SRC2_MASK                 0x007F  /* EQRMIX_SRC2 - [6:0] */
+#define WM2200_EQRMIX_SRC2_SHIFT                     0  /* EQRMIX_SRC2 - [6:0] */
+#define WM2200_EQRMIX_SRC2_WIDTH                     7  /* EQRMIX_SRC2 - [6:0] */
+
+/*
+ * R1627 (0x65B) - EQRMIX Input 2 Volume
+ */
+#define WM2200_EQRMIX_VOL2_MASK                 0x00FE  /* EQRMIX_VOL2 - [7:1] */
+#define WM2200_EQRMIX_VOL2_SHIFT                     1  /* EQRMIX_VOL2 - [7:1] */
+#define WM2200_EQRMIX_VOL2_WIDTH                     7  /* EQRMIX_VOL2 - [7:1] */
+
+/*
+ * R1628 (0x65C) - EQRMIX Input 3 Source
+ */
+#define WM2200_EQRMIX_SRC3_MASK                 0x007F  /* EQRMIX_SRC3 - [6:0] */
+#define WM2200_EQRMIX_SRC3_SHIFT                     0  /* EQRMIX_SRC3 - [6:0] */
+#define WM2200_EQRMIX_SRC3_WIDTH                     7  /* EQRMIX_SRC3 - [6:0] */
+
+/*
+ * R1629 (0x65D) - EQRMIX Input 3 Volume
+ */
+#define WM2200_EQRMIX_VOL3_MASK                 0x00FE  /* EQRMIX_VOL3 - [7:1] */
+#define WM2200_EQRMIX_VOL3_SHIFT                     1  /* EQRMIX_VOL3 - [7:1] */
+#define WM2200_EQRMIX_VOL3_WIDTH                     7  /* EQRMIX_VOL3 - [7:1] */
+
+/*
+ * R1630 (0x65E) - EQRMIX Input 4 Source
+ */
+#define WM2200_EQRMIX_SRC4_MASK                 0x007F  /* EQRMIX_SRC4 - [6:0] */
+#define WM2200_EQRMIX_SRC4_SHIFT                     0  /* EQRMIX_SRC4 - [6:0] */
+#define WM2200_EQRMIX_SRC4_WIDTH                     7  /* EQRMIX_SRC4 - [6:0] */
+
+/*
+ * R1631 (0x65F) - EQRMIX Input 4 Volume
+ */
+#define WM2200_EQRMIX_VOL4_MASK                 0x00FE  /* EQRMIX_VOL4 - [7:1] */
+#define WM2200_EQRMIX_VOL4_SHIFT                     1  /* EQRMIX_VOL4 - [7:1] */
+#define WM2200_EQRMIX_VOL4_WIDTH                     7  /* EQRMIX_VOL4 - [7:1] */
+
+/*
+ * R1632 (0x660) - LHPF1MIX Input 1 Source
+ */
+#define WM2200_LHPF1MIX_SRC1_MASK               0x007F  /* LHPF1MIX_SRC1 - [6:0] */
+#define WM2200_LHPF1MIX_SRC1_SHIFT                   0  /* LHPF1MIX_SRC1 - [6:0] */
+#define WM2200_LHPF1MIX_SRC1_WIDTH                   7  /* LHPF1MIX_SRC1 - [6:0] */
+
+/*
+ * R1633 (0x661) - LHPF1MIX Input 1 Volume
+ */
+#define WM2200_LHPF1MIX_VOL1_MASK               0x00FE  /* LHPF1MIX_VOL1 - [7:1] */
+#define WM2200_LHPF1MIX_VOL1_SHIFT                   1  /* LHPF1MIX_VOL1 - [7:1] */
+#define WM2200_LHPF1MIX_VOL1_WIDTH                   7  /* LHPF1MIX_VOL1 - [7:1] */
+
+/*
+ * R1634 (0x662) - LHPF1MIX Input 2 Source
+ */
+#define WM2200_LHPF1MIX_SRC2_MASK               0x007F  /* LHPF1MIX_SRC2 - [6:0] */
+#define WM2200_LHPF1MIX_SRC2_SHIFT                   0  /* LHPF1MIX_SRC2 - [6:0] */
+#define WM2200_LHPF1MIX_SRC2_WIDTH                   7  /* LHPF1MIX_SRC2 - [6:0] */
+
+/*
+ * R1635 (0x663) - LHPF1MIX Input 2 Volume
+ */
+#define WM2200_LHPF1MIX_VOL2_MASK               0x00FE  /* LHPF1MIX_VOL2 - [7:1] */
+#define WM2200_LHPF1MIX_VOL2_SHIFT                   1  /* LHPF1MIX_VOL2 - [7:1] */
+#define WM2200_LHPF1MIX_VOL2_WIDTH                   7  /* LHPF1MIX_VOL2 - [7:1] */
+
+/*
+ * R1636 (0x664) - LHPF1MIX Input 3 Source
+ */
+#define WM2200_LHPF1MIX_SRC3_MASK               0x007F  /* LHPF1MIX_SRC3 - [6:0] */
+#define WM2200_LHPF1MIX_SRC3_SHIFT                   0  /* LHPF1MIX_SRC3 - [6:0] */
+#define WM2200_LHPF1MIX_SRC3_WIDTH                   7  /* LHPF1MIX_SRC3 - [6:0] */
+
+/*
+ * R1637 (0x665) - LHPF1MIX Input 3 Volume
+ */
+#define WM2200_LHPF1MIX_VOL3_MASK               0x00FE  /* LHPF1MIX_VOL3 - [7:1] */
+#define WM2200_LHPF1MIX_VOL3_SHIFT                   1  /* LHPF1MIX_VOL3 - [7:1] */
+#define WM2200_LHPF1MIX_VOL3_WIDTH                   7  /* LHPF1MIX_VOL3 - [7:1] */
+
+/*
+ * R1638 (0x666) - LHPF1MIX Input 4 Source
+ */
+#define WM2200_LHPF1MIX_SRC4_MASK               0x007F  /* LHPF1MIX_SRC4 - [6:0] */
+#define WM2200_LHPF1MIX_SRC4_SHIFT                   0  /* LHPF1MIX_SRC4 - [6:0] */
+#define WM2200_LHPF1MIX_SRC4_WIDTH                   7  /* LHPF1MIX_SRC4 - [6:0] */
+
+/*
+ * R1639 (0x667) - LHPF1MIX Input 4 Volume
+ */
+#define WM2200_LHPF1MIX_VOL4_MASK               0x00FE  /* LHPF1MIX_VOL4 - [7:1] */
+#define WM2200_LHPF1MIX_VOL4_SHIFT                   1  /* LHPF1MIX_VOL4 - [7:1] */
+#define WM2200_LHPF1MIX_VOL4_WIDTH                   7  /* LHPF1MIX_VOL4 - [7:1] */
+
+/*
+ * R1640 (0x668) - LHPF2MIX Input 1 Source
+ */
+#define WM2200_LHPF2MIX_SRC1_MASK               0x007F  /* LHPF2MIX_SRC1 - [6:0] */
+#define WM2200_LHPF2MIX_SRC1_SHIFT                   0  /* LHPF2MIX_SRC1 - [6:0] */
+#define WM2200_LHPF2MIX_SRC1_WIDTH                   7  /* LHPF2MIX_SRC1 - [6:0] */
+
+/*
+ * R1641 (0x669) - LHPF2MIX Input 1 Volume
+ */
+#define WM2200_LHPF2MIX_VOL1_MASK               0x00FE  /* LHPF2MIX_VOL1 - [7:1] */
+#define WM2200_LHPF2MIX_VOL1_SHIFT                   1  /* LHPF2MIX_VOL1 - [7:1] */
+#define WM2200_LHPF2MIX_VOL1_WIDTH                   7  /* LHPF2MIX_VOL1 - [7:1] */
+
+/*
+ * R1642 (0x66A) - LHPF2MIX Input 2 Source
+ */
+#define WM2200_LHPF2MIX_SRC2_MASK               0x007F  /* LHPF2MIX_SRC2 - [6:0] */
+#define WM2200_LHPF2MIX_SRC2_SHIFT                   0  /* LHPF2MIX_SRC2 - [6:0] */
+#define WM2200_LHPF2MIX_SRC2_WIDTH                   7  /* LHPF2MIX_SRC2 - [6:0] */
+
+/*
+ * R1643 (0x66B) - LHPF2MIX Input 2 Volume
+ */
+#define WM2200_LHPF2MIX_VOL2_MASK               0x00FE  /* LHPF2MIX_VOL2 - [7:1] */
+#define WM2200_LHPF2MIX_VOL2_SHIFT                   1  /* LHPF2MIX_VOL2 - [7:1] */
+#define WM2200_LHPF2MIX_VOL2_WIDTH                   7  /* LHPF2MIX_VOL2 - [7:1] */
+
+/*
+ * R1644 (0x66C) - LHPF2MIX Input 3 Source
+ */
+#define WM2200_LHPF2MIX_SRC3_MASK               0x007F  /* LHPF2MIX_SRC3 - [6:0] */
+#define WM2200_LHPF2MIX_SRC3_SHIFT                   0  /* LHPF2MIX_SRC3 - [6:0] */
+#define WM2200_LHPF2MIX_SRC3_WIDTH                   7  /* LHPF2MIX_SRC3 - [6:0] */
+
+/*
+ * R1645 (0x66D) - LHPF2MIX Input 3 Volume
+ */
+#define WM2200_LHPF2MIX_VOL3_MASK               0x00FE  /* LHPF2MIX_VOL3 - [7:1] */
+#define WM2200_LHPF2MIX_VOL3_SHIFT                   1  /* LHPF2MIX_VOL3 - [7:1] */
+#define WM2200_LHPF2MIX_VOL3_WIDTH                   7  /* LHPF2MIX_VOL3 - [7:1] */
+
+/*
+ * R1646 (0x66E) - LHPF2MIX Input 4 Source
+ */
+#define WM2200_LHPF2MIX_SRC4_MASK               0x007F  /* LHPF2MIX_SRC4 - [6:0] */
+#define WM2200_LHPF2MIX_SRC4_SHIFT                   0  /* LHPF2MIX_SRC4 - [6:0] */
+#define WM2200_LHPF2MIX_SRC4_WIDTH                   7  /* LHPF2MIX_SRC4 - [6:0] */
+
+/*
+ * R1647 (0x66F) - LHPF2MIX Input 4 Volume
+ */
+#define WM2200_LHPF2MIX_VOL4_MASK               0x00FE  /* LHPF2MIX_VOL4 - [7:1] */
+#define WM2200_LHPF2MIX_VOL4_SHIFT                   1  /* LHPF2MIX_VOL4 - [7:1] */
+#define WM2200_LHPF2MIX_VOL4_WIDTH                   7  /* LHPF2MIX_VOL4 - [7:1] */
+
+/*
+ * R1648 (0x670) - DSP1LMIX Input 1 Source
+ */
+#define WM2200_DSP1LMIX_SRC1_MASK               0x007F  /* DSP1LMIX_SRC1 - [6:0] */
+#define WM2200_DSP1LMIX_SRC1_SHIFT                   0  /* DSP1LMIX_SRC1 - [6:0] */
+#define WM2200_DSP1LMIX_SRC1_WIDTH                   7  /* DSP1LMIX_SRC1 - [6:0] */
+
+/*
+ * R1649 (0x671) - DSP1LMIX Input 1 Volume
+ */
+#define WM2200_DSP1LMIX_VOL1_MASK               0x00FE  /* DSP1LMIX_VOL1 - [7:1] */
+#define WM2200_DSP1LMIX_VOL1_SHIFT                   1  /* DSP1LMIX_VOL1 - [7:1] */
+#define WM2200_DSP1LMIX_VOL1_WIDTH                   7  /* DSP1LMIX_VOL1 - [7:1] */
+
+/*
+ * R1650 (0x672) - DSP1LMIX Input 2 Source
+ */
+#define WM2200_DSP1LMIX_SRC2_MASK               0x007F  /* DSP1LMIX_SRC2 - [6:0] */
+#define WM2200_DSP1LMIX_SRC2_SHIFT                   0  /* DSP1LMIX_SRC2 - [6:0] */
+#define WM2200_DSP1LMIX_SRC2_WIDTH                   7  /* DSP1LMIX_SRC2 - [6:0] */
+
+/*
+ * R1651 (0x673) - DSP1LMIX Input 2 Volume
+ */
+#define WM2200_DSP1LMIX_VOL2_MASK               0x00FE  /* DSP1LMIX_VOL2 - [7:1] */
+#define WM2200_DSP1LMIX_VOL2_SHIFT                   1  /* DSP1LMIX_VOL2 - [7:1] */
+#define WM2200_DSP1LMIX_VOL2_WIDTH                   7  /* DSP1LMIX_VOL2 - [7:1] */
+
+/*
+ * R1652 (0x674) - DSP1LMIX Input 3 Source
+ */
+#define WM2200_DSP1LMIX_SRC3_MASK               0x007F  /* DSP1LMIX_SRC3 - [6:0] */
+#define WM2200_DSP1LMIX_SRC3_SHIFT                   0  /* DSP1LMIX_SRC3 - [6:0] */
+#define WM2200_DSP1LMIX_SRC3_WIDTH                   7  /* DSP1LMIX_SRC3 - [6:0] */
+
+/*
+ * R1653 (0x675) - DSP1LMIX Input 3 Volume
+ */
+#define WM2200_DSP1LMIX_VOL3_MASK               0x00FE  /* DSP1LMIX_VOL3 - [7:1] */
+#define WM2200_DSP1LMIX_VOL3_SHIFT                   1  /* DSP1LMIX_VOL3 - [7:1] */
+#define WM2200_DSP1LMIX_VOL3_WIDTH                   7  /* DSP1LMIX_VOL3 - [7:1] */
+
+/*
+ * R1654 (0x676) - DSP1LMIX Input 4 Source
+ */
+#define WM2200_DSP1LMIX_SRC4_MASK               0x007F  /* DSP1LMIX_SRC4 - [6:0] */
+#define WM2200_DSP1LMIX_SRC4_SHIFT                   0  /* DSP1LMIX_SRC4 - [6:0] */
+#define WM2200_DSP1LMIX_SRC4_WIDTH                   7  /* DSP1LMIX_SRC4 - [6:0] */
+
+/*
+ * R1655 (0x677) - DSP1LMIX Input 4 Volume
+ */
+#define WM2200_DSP1LMIX_VOL4_MASK               0x00FE  /* DSP1LMIX_VOL4 - [7:1] */
+#define WM2200_DSP1LMIX_VOL4_SHIFT                   1  /* DSP1LMIX_VOL4 - [7:1] */
+#define WM2200_DSP1LMIX_VOL4_WIDTH                   7  /* DSP1LMIX_VOL4 - [7:1] */
+
+/*
+ * R1656 (0x678) - DSP1RMIX Input 1 Source
+ */
+#define WM2200_DSP1RMIX_SRC1_MASK               0x007F  /* DSP1RMIX_SRC1 - [6:0] */
+#define WM2200_DSP1RMIX_SRC1_SHIFT                   0  /* DSP1RMIX_SRC1 - [6:0] */
+#define WM2200_DSP1RMIX_SRC1_WIDTH                   7  /* DSP1RMIX_SRC1 - [6:0] */
+
+/*
+ * R1657 (0x679) - DSP1RMIX Input 1 Volume
+ */
+#define WM2200_DSP1RMIX_VOL1_MASK               0x00FE  /* DSP1RMIX_VOL1 - [7:1] */
+#define WM2200_DSP1RMIX_VOL1_SHIFT                   1  /* DSP1RMIX_VOL1 - [7:1] */
+#define WM2200_DSP1RMIX_VOL1_WIDTH                   7  /* DSP1RMIX_VOL1 - [7:1] */
+
+/*
+ * R1658 (0x67A) - DSP1RMIX Input 2 Source
+ */
+#define WM2200_DSP1RMIX_SRC2_MASK               0x007F  /* DSP1RMIX_SRC2 - [6:0] */
+#define WM2200_DSP1RMIX_SRC2_SHIFT                   0  /* DSP1RMIX_SRC2 - [6:0] */
+#define WM2200_DSP1RMIX_SRC2_WIDTH                   7  /* DSP1RMIX_SRC2 - [6:0] */
+
+/*
+ * R1659 (0x67B) - DSP1RMIX Input 2 Volume
+ */
+#define WM2200_DSP1RMIX_VOL2_MASK               0x00FE  /* DSP1RMIX_VOL2 - [7:1] */
+#define WM2200_DSP1RMIX_VOL2_SHIFT                   1  /* DSP1RMIX_VOL2 - [7:1] */
+#define WM2200_DSP1RMIX_VOL2_WIDTH                   7  /* DSP1RMIX_VOL2 - [7:1] */
+
+/*
+ * R1660 (0x67C) - DSP1RMIX Input 3 Source
+ */
+#define WM2200_DSP1RMIX_SRC3_MASK               0x007F  /* DSP1RMIX_SRC3 - [6:0] */
+#define WM2200_DSP1RMIX_SRC3_SHIFT                   0  /* DSP1RMIX_SRC3 - [6:0] */
+#define WM2200_DSP1RMIX_SRC3_WIDTH                   7  /* DSP1RMIX_SRC3 - [6:0] */
+
+/*
+ * R1661 (0x67D) - DSP1RMIX Input 3 Volume
+ */
+#define WM2200_DSP1RMIX_VOL3_MASK               0x00FE  /* DSP1RMIX_VOL3 - [7:1] */
+#define WM2200_DSP1RMIX_VOL3_SHIFT                   1  /* DSP1RMIX_VOL3 - [7:1] */
+#define WM2200_DSP1RMIX_VOL3_WIDTH                   7  /* DSP1RMIX_VOL3 - [7:1] */
+
+/*
+ * R1662 (0x67E) - DSP1RMIX Input 4 Source
+ */
+#define WM2200_DSP1RMIX_SRC4_MASK               0x007F  /* DSP1RMIX_SRC4 - [6:0] */
+#define WM2200_DSP1RMIX_SRC4_SHIFT                   0  /* DSP1RMIX_SRC4 - [6:0] */
+#define WM2200_DSP1RMIX_SRC4_WIDTH                   7  /* DSP1RMIX_SRC4 - [6:0] */
+
+/*
+ * R1663 (0x67F) - DSP1RMIX Input 4 Volume
+ */
+#define WM2200_DSP1RMIX_VOL4_MASK               0x00FE  /* DSP1RMIX_VOL4 - [7:1] */
+#define WM2200_DSP1RMIX_VOL4_SHIFT                   1  /* DSP1RMIX_VOL4 - [7:1] */
+#define WM2200_DSP1RMIX_VOL4_WIDTH                   7  /* DSP1RMIX_VOL4 - [7:1] */
+
+/*
+ * R1664 (0x680) - DSP1AUX1MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX1MIX_SRC1_MASK            0x007F  /* DSP1AUX1MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX1MIX_SRC1_SHIFT                0  /* DSP1AUX1MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX1MIX_SRC1_WIDTH                7  /* DSP1AUX1MIX_SRC1 - [6:0] */
+
+/*
+ * R1665 (0x681) - DSP1AUX2MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX2MIX_SRC1_MASK            0x007F  /* DSP1AUX2MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX2MIX_SRC1_SHIFT                0  /* DSP1AUX2MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX2MIX_SRC1_WIDTH                7  /* DSP1AUX2MIX_SRC1 - [6:0] */
+
+/*
+ * R1666 (0x682) - DSP1AUX3MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX3MIX_SRC1_MASK            0x007F  /* DSP1AUX3MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX3MIX_SRC1_SHIFT                0  /* DSP1AUX3MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX3MIX_SRC1_WIDTH                7  /* DSP1AUX3MIX_SRC1 - [6:0] */
+
+/*
+ * R1667 (0x683) - DSP1AUX4MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX4MIX_SRC1_MASK            0x007F  /* DSP1AUX4MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX4MIX_SRC1_SHIFT                0  /* DSP1AUX4MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX4MIX_SRC1_WIDTH                7  /* DSP1AUX4MIX_SRC1 - [6:0] */
+
+/*
+ * R1668 (0x684) - DSP1AUX5MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX5MIX_SRC1_MASK            0x007F  /* DSP1AUX5MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX5MIX_SRC1_SHIFT                0  /* DSP1AUX5MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX5MIX_SRC1_WIDTH                7  /* DSP1AUX5MIX_SRC1 - [6:0] */
+
+/*
+ * R1669 (0x685) - DSP1AUX6MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX6MIX_SRC1_MASK            0x007F  /* DSP1AUX6MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX6MIX_SRC1_SHIFT                0  /* DSP1AUX6MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX6MIX_SRC1_WIDTH                7  /* DSP1AUX6MIX_SRC1 - [6:0] */
+
+/*
+ * R1670 (0x686) - DSP2LMIX Input 1 Source
+ */
+#define WM2200_DSP2LMIX_SRC1_MASK               0x007F  /* DSP2LMIX_SRC1 - [6:0] */
+#define WM2200_DSP2LMIX_SRC1_SHIFT                   0  /* DSP2LMIX_SRC1 - [6:0] */
+#define WM2200_DSP2LMIX_SRC1_WIDTH                   7  /* DSP2LMIX_SRC1 - [6:0] */
+
+/*
+ * R1671 (0x687) - DSP2LMIX Input 1 Volume
+ */
+#define WM2200_DSP2LMIX_VOL1_MASK               0x00FE  /* DSP2LMIX_VOL1 - [7:1] */
+#define WM2200_DSP2LMIX_VOL1_SHIFT                   1  /* DSP2LMIX_VOL1 - [7:1] */
+#define WM2200_DSP2LMIX_VOL1_WIDTH                   7  /* DSP2LMIX_VOL1 - [7:1] */
+
+/*
+ * R1672 (0x688) - DSP2LMIX Input 2 Source
+ */
+#define WM2200_DSP2LMIX_SRC2_MASK               0x007F  /* DSP2LMIX_SRC2 - [6:0] */
+#define WM2200_DSP2LMIX_SRC2_SHIFT                   0  /* DSP2LMIX_SRC2 - [6:0] */
+#define WM2200_DSP2LMIX_SRC2_WIDTH                   7  /* DSP2LMIX_SRC2 - [6:0] */
+
+/*
+ * R1673 (0x689) - DSP2LMIX Input 2 Volume
+ */
+#define WM2200_DSP2LMIX_VOL2_MASK               0x00FE  /* DSP2LMIX_VOL2 - [7:1] */
+#define WM2200_DSP2LMIX_VOL2_SHIFT                   1  /* DSP2LMIX_VOL2 - [7:1] */
+#define WM2200_DSP2LMIX_VOL2_WIDTH                   7  /* DSP2LMIX_VOL2 - [7:1] */
+
+/*
+ * R1674 (0x68A) - DSP2LMIX Input 3 Source
+ */
+#define WM2200_DSP2LMIX_SRC3_MASK               0x007F  /* DSP2LMIX_SRC3 - [6:0] */
+#define WM2200_DSP2LMIX_SRC3_SHIFT                   0  /* DSP2LMIX_SRC3 - [6:0] */
+#define WM2200_DSP2LMIX_SRC3_WIDTH                   7  /* DSP2LMIX_SRC3 - [6:0] */
+
+/*
+ * R1675 (0x68B) - DSP2LMIX Input 3 Volume
+ */
+#define WM2200_DSP2LMIX_VOL3_MASK               0x00FE  /* DSP2LMIX_VOL3 - [7:1] */
+#define WM2200_DSP2LMIX_VOL3_SHIFT                   1  /* DSP2LMIX_VOL3 - [7:1] */
+#define WM2200_DSP2LMIX_VOL3_WIDTH                   7  /* DSP2LMIX_VOL3 - [7:1] */
+
+/*
+ * R1676 (0x68C) - DSP2LMIX Input 4 Source
+ */
+#define WM2200_DSP2LMIX_SRC4_MASK               0x007F  /* DSP2LMIX_SRC4 - [6:0] */
+#define WM2200_DSP2LMIX_SRC4_SHIFT                   0  /* DSP2LMIX_SRC4 - [6:0] */
+#define WM2200_DSP2LMIX_SRC4_WIDTH                   7  /* DSP2LMIX_SRC4 - [6:0] */
+
+/*
+ * R1677 (0x68D) - DSP2LMIX Input 4 Volume
+ */
+#define WM2200_DSP2LMIX_VOL4_MASK               0x00FE  /* DSP2LMIX_VOL4 - [7:1] */
+#define WM2200_DSP2LMIX_VOL4_SHIFT                   1  /* DSP2LMIX_VOL4 - [7:1] */
+#define WM2200_DSP2LMIX_VOL4_WIDTH                   7  /* DSP2LMIX_VOL4 - [7:1] */
+
+/*
+ * R1678 (0x68E) - DSP2RMIX Input 1 Source
+ */
+#define WM2200_DSP2RMIX_SRC1_MASK               0x007F  /* DSP2RMIX_SRC1 - [6:0] */
+#define WM2200_DSP2RMIX_SRC1_SHIFT                   0  /* DSP2RMIX_SRC1 - [6:0] */
+#define WM2200_DSP2RMIX_SRC1_WIDTH                   7  /* DSP2RMIX_SRC1 - [6:0] */
+
+/*
+ * R1679 (0x68F) - DSP2RMIX Input 1 Volume
+ */
+#define WM2200_DSP2RMIX_VOL1_MASK               0x00FE  /* DSP2RMIX_VOL1 - [7:1] */
+#define WM2200_DSP2RMIX_VOL1_SHIFT                   1  /* DSP2RMIX_VOL1 - [7:1] */
+#define WM2200_DSP2RMIX_VOL1_WIDTH                   7  /* DSP2RMIX_VOL1 - [7:1] */
+
+/*
+ * R1680 (0x690) - DSP2RMIX Input 2 Source
+ */
+#define WM2200_DSP2RMIX_SRC2_MASK               0x007F  /* DSP2RMIX_SRC2 - [6:0] */
+#define WM2200_DSP2RMIX_SRC2_SHIFT                   0  /* DSP2RMIX_SRC2 - [6:0] */
+#define WM2200_DSP2RMIX_SRC2_WIDTH                   7  /* DSP2RMIX_SRC2 - [6:0] */
+
+/*
+ * R1681 (0x691) - DSP2RMIX Input 2 Volume
+ */
+#define WM2200_DSP2RMIX_VOL2_MASK               0x00FE  /* DSP2RMIX_VOL2 - [7:1] */
+#define WM2200_DSP2RMIX_VOL2_SHIFT                   1  /* DSP2RMIX_VOL2 - [7:1] */
+#define WM2200_DSP2RMIX_VOL2_WIDTH                   7  /* DSP2RMIX_VOL2 - [7:1] */
+
+/*
+ * R1682 (0x692) - DSP2RMIX Input 3 Source
+ */
+#define WM2200_DSP2RMIX_SRC3_MASK               0x007F  /* DSP2RMIX_SRC3 - [6:0] */
+#define WM2200_DSP2RMIX_SRC3_SHIFT                   0  /* DSP2RMIX_SRC3 - [6:0] */
+#define WM2200_DSP2RMIX_SRC3_WIDTH                   7  /* DSP2RMIX_SRC3 - [6:0] */
+
+/*
+ * R1683 (0x693) - DSP2RMIX Input 3 Volume
+ */
+#define WM2200_DSP2RMIX_VOL3_MASK               0x00FE  /* DSP2RMIX_VOL3 - [7:1] */
+#define WM2200_DSP2RMIX_VOL3_SHIFT                   1  /* DSP2RMIX_VOL3 - [7:1] */
+#define WM2200_DSP2RMIX_VOL3_WIDTH                   7  /* DSP2RMIX_VOL3 - [7:1] */
+
+/*
+ * R1684 (0x694) - DSP2RMIX Input 4 Source
+ */
+#define WM2200_DSP2RMIX_SRC4_MASK               0x007F  /* DSP2RMIX_SRC4 - [6:0] */
+#define WM2200_DSP2RMIX_SRC4_SHIFT                   0  /* DSP2RMIX_SRC4 - [6:0] */
+#define WM2200_DSP2RMIX_SRC4_WIDTH                   7  /* DSP2RMIX_SRC4 - [6:0] */
+
+/*
+ * R1685 (0x695) - DSP2RMIX Input 4 Volume
+ */
+#define WM2200_DSP2RMIX_VOL4_MASK               0x00FE  /* DSP2RMIX_VOL4 - [7:1] */
+#define WM2200_DSP2RMIX_VOL4_SHIFT                   1  /* DSP2RMIX_VOL4 - [7:1] */
+#define WM2200_DSP2RMIX_VOL4_WIDTH                   7  /* DSP2RMIX_VOL4 - [7:1] */
+
+/*
+ * R1686 (0x696) - DSP2AUX1MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX1MIX_SRC1_MASK            0x007F  /* DSP2AUX1MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX1MIX_SRC1_SHIFT                0  /* DSP2AUX1MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX1MIX_SRC1_WIDTH                7  /* DSP2AUX1MIX_SRC1 - [6:0] */
+
+/*
+ * R1687 (0x697) - DSP2AUX2MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX2MIX_SRC1_MASK            0x007F  /* DSP2AUX2MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX2MIX_SRC1_SHIFT                0  /* DSP2AUX2MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX2MIX_SRC1_WIDTH                7  /* DSP2AUX2MIX_SRC1 - [6:0] */
+
+/*
+ * R1688 (0x698) - DSP2AUX3MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX3MIX_SRC1_MASK            0x007F  /* DSP2AUX3MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX3MIX_SRC1_SHIFT                0  /* DSP2AUX3MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX3MIX_SRC1_WIDTH                7  /* DSP2AUX3MIX_SRC1 - [6:0] */
+
+/*
+ * R1689 (0x699) - DSP2AUX4MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX4MIX_SRC1_MASK            0x007F  /* DSP2AUX4MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX4MIX_SRC1_SHIFT                0  /* DSP2AUX4MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX4MIX_SRC1_WIDTH                7  /* DSP2AUX4MIX_SRC1 - [6:0] */
+
+/*
+ * R1690 (0x69A) - DSP2AUX5MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX5MIX_SRC1_MASK            0x007F  /* DSP2AUX5MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX5MIX_SRC1_SHIFT                0  /* DSP2AUX5MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX5MIX_SRC1_WIDTH                7  /* DSP2AUX5MIX_SRC1 - [6:0] */
+
+/*
+ * R1691 (0x69B) - DSP2AUX6MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX6MIX_SRC1_MASK            0x007F  /* DSP2AUX6MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX6MIX_SRC1_SHIFT                0  /* DSP2AUX6MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX6MIX_SRC1_WIDTH                7  /* DSP2AUX6MIX_SRC1 - [6:0] */
+
+/*
+ * R1792 (0x700) - GPIO CTRL 1
+ */
+#define WM2200_GP1_DIR                          0x8000  /* GP1_DIR */
+#define WM2200_GP1_DIR_MASK                     0x8000  /* GP1_DIR */
+#define WM2200_GP1_DIR_SHIFT                        15  /* GP1_DIR */
+#define WM2200_GP1_DIR_WIDTH                         1  /* GP1_DIR */
+#define WM2200_GP1_PU                           0x4000  /* GP1_PU */
+#define WM2200_GP1_PU_MASK                      0x4000  /* GP1_PU */
+#define WM2200_GP1_PU_SHIFT                         14  /* GP1_PU */
+#define WM2200_GP1_PU_WIDTH                          1  /* GP1_PU */
+#define WM2200_GP1_PD                           0x2000  /* GP1_PD */
+#define WM2200_GP1_PD_MASK                      0x2000  /* GP1_PD */
+#define WM2200_GP1_PD_SHIFT                         13  /* GP1_PD */
+#define WM2200_GP1_PD_WIDTH                          1  /* GP1_PD */
+#define WM2200_GP1_POL                          0x0400  /* GP1_POL */
+#define WM2200_GP1_POL_MASK                     0x0400  /* GP1_POL */
+#define WM2200_GP1_POL_SHIFT                        10  /* GP1_POL */
+#define WM2200_GP1_POL_WIDTH                         1  /* GP1_POL */
+#define WM2200_GP1_OP_CFG                       0x0200  /* GP1_OP_CFG */
+#define WM2200_GP1_OP_CFG_MASK                  0x0200  /* GP1_OP_CFG */
+#define WM2200_GP1_OP_CFG_SHIFT                      9  /* GP1_OP_CFG */
+#define WM2200_GP1_OP_CFG_WIDTH                      1  /* GP1_OP_CFG */
+#define WM2200_GP1_DB                           0x0100  /* GP1_DB */
+#define WM2200_GP1_DB_MASK                      0x0100  /* GP1_DB */
+#define WM2200_GP1_DB_SHIFT                          8  /* GP1_DB */
+#define WM2200_GP1_DB_WIDTH                          1  /* GP1_DB */
+#define WM2200_GP1_LVL                          0x0040  /* GP1_LVL */
+#define WM2200_GP1_LVL_MASK                     0x0040  /* GP1_LVL */
+#define WM2200_GP1_LVL_SHIFT                         6  /* GP1_LVL */
+#define WM2200_GP1_LVL_WIDTH                         1  /* GP1_LVL */
+#define WM2200_GP1_FN_MASK                      0x003F  /* GP1_FN - [5:0] */
+#define WM2200_GP1_FN_SHIFT                          0  /* GP1_FN - [5:0] */
+#define WM2200_GP1_FN_WIDTH                          6  /* GP1_FN - [5:0] */
+
+/*
+ * R1793 (0x701) - GPIO CTRL 2
+ */
+#define WM2200_GP2_DIR                          0x8000  /* GP2_DIR */
+#define WM2200_GP2_DIR_MASK                     0x8000  /* GP2_DIR */
+#define WM2200_GP2_DIR_SHIFT                        15  /* GP2_DIR */
+#define WM2200_GP2_DIR_WIDTH                         1  /* GP2_DIR */
+#define WM2200_GP2_PU                           0x4000  /* GP2_PU */
+#define WM2200_GP2_PU_MASK                      0x4000  /* GP2_PU */
+#define WM2200_GP2_PU_SHIFT                         14  /* GP2_PU */
+#define WM2200_GP2_PU_WIDTH                          1  /* GP2_PU */
+#define WM2200_GP2_PD                           0x2000  /* GP2_PD */
+#define WM2200_GP2_PD_MASK                      0x2000  /* GP2_PD */
+#define WM2200_GP2_PD_SHIFT                         13  /* GP2_PD */
+#define WM2200_GP2_PD_WIDTH                          1  /* GP2_PD */
+#define WM2200_GP2_POL                          0x0400  /* GP2_POL */
+#define WM2200_GP2_POL_MASK                     0x0400  /* GP2_POL */
+#define WM2200_GP2_POL_SHIFT                        10  /* GP2_POL */
+#define WM2200_GP2_POL_WIDTH                         1  /* GP2_POL */
+#define WM2200_GP2_OP_CFG                       0x0200  /* GP2_OP_CFG */
+#define WM2200_GP2_OP_CFG_MASK                  0x0200  /* GP2_OP_CFG */
+#define WM2200_GP2_OP_CFG_SHIFT                      9  /* GP2_OP_CFG */
+#define WM2200_GP2_OP_CFG_WIDTH                      1  /* GP2_OP_CFG */
+#define WM2200_GP2_DB                           0x0100  /* GP2_DB */
+#define WM2200_GP2_DB_MASK                      0x0100  /* GP2_DB */
+#define WM2200_GP2_DB_SHIFT                          8  /* GP2_DB */
+#define WM2200_GP2_DB_WIDTH                          1  /* GP2_DB */
+#define WM2200_GP2_LVL                          0x0040  /* GP2_LVL */
+#define WM2200_GP2_LVL_MASK                     0x0040  /* GP2_LVL */
+#define WM2200_GP2_LVL_SHIFT                         6  /* GP2_LVL */
+#define WM2200_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM2200_GP2_FN_MASK                      0x003F  /* GP2_FN - [5:0] */
+#define WM2200_GP2_FN_SHIFT                          0  /* GP2_FN - [5:0] */
+#define WM2200_GP2_FN_WIDTH                          6  /* GP2_FN - [5:0] */
+
+/*
+ * R1794 (0x702) - GPIO CTRL 3
+ */
+#define WM2200_GP3_DIR                          0x8000  /* GP3_DIR */
+#define WM2200_GP3_DIR_MASK                     0x8000  /* GP3_DIR */
+#define WM2200_GP3_DIR_SHIFT                        15  /* GP3_DIR */
+#define WM2200_GP3_DIR_WIDTH                         1  /* GP3_DIR */
+#define WM2200_GP3_PU                           0x4000  /* GP3_PU */
+#define WM2200_GP3_PU_MASK                      0x4000  /* GP3_PU */
+#define WM2200_GP3_PU_SHIFT                         14  /* GP3_PU */
+#define WM2200_GP3_PU_WIDTH                          1  /* GP3_PU */
+#define WM2200_GP3_PD                           0x2000  /* GP3_PD */
+#define WM2200_GP3_PD_MASK                      0x2000  /* GP3_PD */
+#define WM2200_GP3_PD_SHIFT                         13  /* GP3_PD */
+#define WM2200_GP3_PD_WIDTH                          1  /* GP3_PD */
+#define WM2200_GP3_POL                          0x0400  /* GP3_POL */
+#define WM2200_GP3_POL_MASK                     0x0400  /* GP3_POL */
+#define WM2200_GP3_POL_SHIFT                        10  /* GP3_POL */
+#define WM2200_GP3_POL_WIDTH                         1  /* GP3_POL */
+#define WM2200_GP3_OP_CFG                       0x0200  /* GP3_OP_CFG */
+#define WM2200_GP3_OP_CFG_MASK                  0x0200  /* GP3_OP_CFG */
+#define WM2200_GP3_OP_CFG_SHIFT                      9  /* GP3_OP_CFG */
+#define WM2200_GP3_OP_CFG_WIDTH                      1  /* GP3_OP_CFG */
+#define WM2200_GP3_DB                           0x0100  /* GP3_DB */
+#define WM2200_GP3_DB_MASK                      0x0100  /* GP3_DB */
+#define WM2200_GP3_DB_SHIFT                          8  /* GP3_DB */
+#define WM2200_GP3_DB_WIDTH                          1  /* GP3_DB */
+#define WM2200_GP3_LVL                          0x0040  /* GP3_LVL */
+#define WM2200_GP3_LVL_MASK                     0x0040  /* GP3_LVL */
+#define WM2200_GP3_LVL_SHIFT                         6  /* GP3_LVL */
+#define WM2200_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM2200_GP3_FN_MASK                      0x003F  /* GP3_FN - [5:0] */
+#define WM2200_GP3_FN_SHIFT                          0  /* GP3_FN - [5:0] */
+#define WM2200_GP3_FN_WIDTH                          6  /* GP3_FN - [5:0] */
+
+/*
+ * R1795 (0x703) - GPIO CTRL 4
+ */
+#define WM2200_GP4_DIR                          0x8000  /* GP4_DIR */
+#define WM2200_GP4_DIR_MASK                     0x8000  /* GP4_DIR */
+#define WM2200_GP4_DIR_SHIFT                        15  /* GP4_DIR */
+#define WM2200_GP4_DIR_WIDTH                         1  /* GP4_DIR */
+#define WM2200_GP4_PU                           0x4000  /* GP4_PU */
+#define WM2200_GP4_PU_MASK                      0x4000  /* GP4_PU */
+#define WM2200_GP4_PU_SHIFT                         14  /* GP4_PU */
+#define WM2200_GP4_PU_WIDTH                          1  /* GP4_PU */
+#define WM2200_GP4_PD                           0x2000  /* GP4_PD */
+#define WM2200_GP4_PD_MASK                      0x2000  /* GP4_PD */
+#define WM2200_GP4_PD_SHIFT                         13  /* GP4_PD */
+#define WM2200_GP4_PD_WIDTH                          1  /* GP4_PD */
+#define WM2200_GP4_POL                          0x0400  /* GP4_POL */
+#define WM2200_GP4_POL_MASK                     0x0400  /* GP4_POL */
+#define WM2200_GP4_POL_SHIFT                        10  /* GP4_POL */
+#define WM2200_GP4_POL_WIDTH                         1  /* GP4_POL */
+#define WM2200_GP4_OP_CFG                       0x0200  /* GP4_OP_CFG */
+#define WM2200_GP4_OP_CFG_MASK                  0x0200  /* GP4_OP_CFG */
+#define WM2200_GP4_OP_CFG_SHIFT                      9  /* GP4_OP_CFG */
+#define WM2200_GP4_OP_CFG_WIDTH                      1  /* GP4_OP_CFG */
+#define WM2200_GP4_DB                           0x0100  /* GP4_DB */
+#define WM2200_GP4_DB_MASK                      0x0100  /* GP4_DB */
+#define WM2200_GP4_DB_SHIFT                          8  /* GP4_DB */
+#define WM2200_GP4_DB_WIDTH                          1  /* GP4_DB */
+#define WM2200_GP4_LVL                          0x0040  /* GP4_LVL */
+#define WM2200_GP4_LVL_MASK                     0x0040  /* GP4_LVL */
+#define WM2200_GP4_LVL_SHIFT                         6  /* GP4_LVL */
+#define WM2200_GP4_LVL_WIDTH                         1  /* GP4_LVL */
+#define WM2200_GP4_FN_MASK                      0x003F  /* GP4_FN - [5:0] */
+#define WM2200_GP4_FN_SHIFT                          0  /* GP4_FN - [5:0] */
+#define WM2200_GP4_FN_WIDTH                          6  /* GP4_FN - [5:0] */
+
+/*
+ * R1799 (0x707) - ADPS1 IRQ0
+ */
+#define WM2200_DSP_IRQ1                         0x0002  /* DSP_IRQ1 */
+#define WM2200_DSP_IRQ1_MASK                    0x0002  /* DSP_IRQ1 */
+#define WM2200_DSP_IRQ1_SHIFT                        1  /* DSP_IRQ1 */
+#define WM2200_DSP_IRQ1_WIDTH                        1  /* DSP_IRQ1 */
+#define WM2200_DSP_IRQ0                         0x0001  /* DSP_IRQ0 */
+#define WM2200_DSP_IRQ0_MASK                    0x0001  /* DSP_IRQ0 */
+#define WM2200_DSP_IRQ0_SHIFT                        0  /* DSP_IRQ0 */
+#define WM2200_DSP_IRQ0_WIDTH                        1  /* DSP_IRQ0 */
+
+/*
+ * R1800 (0x708) - ADPS1 IRQ1
+ */
+#define WM2200_DSP_IRQ3                         0x0002  /* DSP_IRQ3 */
+#define WM2200_DSP_IRQ3_MASK                    0x0002  /* DSP_IRQ3 */
+#define WM2200_DSP_IRQ3_SHIFT                        1  /* DSP_IRQ3 */
+#define WM2200_DSP_IRQ3_WIDTH                        1  /* DSP_IRQ3 */
+#define WM2200_DSP_IRQ2                         0x0001  /* DSP_IRQ2 */
+#define WM2200_DSP_IRQ2_MASK                    0x0001  /* DSP_IRQ2 */
+#define WM2200_DSP_IRQ2_SHIFT                        0  /* DSP_IRQ2 */
+#define WM2200_DSP_IRQ2_WIDTH                        1  /* DSP_IRQ2 */
+
+/*
+ * R1801 (0x709) - Misc Pad Ctrl 1
+ */
+#define WM2200_LDO1ENA_PD                       0x8000  /* LDO1ENA_PD */
+#define WM2200_LDO1ENA_PD_MASK                  0x8000  /* LDO1ENA_PD */
+#define WM2200_LDO1ENA_PD_SHIFT                     15  /* LDO1ENA_PD */
+#define WM2200_LDO1ENA_PD_WIDTH                      1  /* LDO1ENA_PD */
+#define WM2200_MCLK2_PD                         0x2000  /* MCLK2_PD */
+#define WM2200_MCLK2_PD_MASK                    0x2000  /* MCLK2_PD */
+#define WM2200_MCLK2_PD_SHIFT                       13  /* MCLK2_PD */
+#define WM2200_MCLK2_PD_WIDTH                        1  /* MCLK2_PD */
+#define WM2200_MCLK1_PD                         0x1000  /* MCLK1_PD */
+#define WM2200_MCLK1_PD_MASK                    0x1000  /* MCLK1_PD */
+#define WM2200_MCLK1_PD_SHIFT                       12  /* MCLK1_PD */
+#define WM2200_MCLK1_PD_WIDTH                        1  /* MCLK1_PD */
+#define WM2200_DACLRCLK1_PU                     0x0400  /* DACLRCLK1_PU */
+#define WM2200_DACLRCLK1_PU_MASK                0x0400  /* DACLRCLK1_PU */
+#define WM2200_DACLRCLK1_PU_SHIFT                   10  /* DACLRCLK1_PU */
+#define WM2200_DACLRCLK1_PU_WIDTH                    1  /* DACLRCLK1_PU */
+#define WM2200_DACLRCLK1_PD                     0x0200  /* DACLRCLK1_PD */
+#define WM2200_DACLRCLK1_PD_MASK                0x0200  /* DACLRCLK1_PD */
+#define WM2200_DACLRCLK1_PD_SHIFT                    9  /* DACLRCLK1_PD */
+#define WM2200_DACLRCLK1_PD_WIDTH                    1  /* DACLRCLK1_PD */
+#define WM2200_BCLK1_PU                         0x0100  /* BCLK1_PU */
+#define WM2200_BCLK1_PU_MASK                    0x0100  /* BCLK1_PU */
+#define WM2200_BCLK1_PU_SHIFT                        8  /* BCLK1_PU */
+#define WM2200_BCLK1_PU_WIDTH                        1  /* BCLK1_PU */
+#define WM2200_BCLK1_PD                         0x0080  /* BCLK1_PD */
+#define WM2200_BCLK1_PD_MASK                    0x0080  /* BCLK1_PD */
+#define WM2200_BCLK1_PD_SHIFT                        7  /* BCLK1_PD */
+#define WM2200_BCLK1_PD_WIDTH                        1  /* BCLK1_PD */
+#define WM2200_DACDAT1_PU                       0x0040  /* DACDAT1_PU */
+#define WM2200_DACDAT1_PU_MASK                  0x0040  /* DACDAT1_PU */
+#define WM2200_DACDAT1_PU_SHIFT                      6  /* DACDAT1_PU */
+#define WM2200_DACDAT1_PU_WIDTH                      1  /* DACDAT1_PU */
+#define WM2200_DACDAT1_PD                       0x0020  /* DACDAT1_PD */
+#define WM2200_DACDAT1_PD_MASK                  0x0020  /* DACDAT1_PD */
+#define WM2200_DACDAT1_PD_SHIFT                      5  /* DACDAT1_PD */
+#define WM2200_DACDAT1_PD_WIDTH                      1  /* DACDAT1_PD */
+#define WM2200_DMICDAT3_PD                      0x0010  /* DMICDAT3_PD */
+#define WM2200_DMICDAT3_PD_MASK                 0x0010  /* DMICDAT3_PD */
+#define WM2200_DMICDAT3_PD_SHIFT                     4  /* DMICDAT3_PD */
+#define WM2200_DMICDAT3_PD_WIDTH                     1  /* DMICDAT3_PD */
+#define WM2200_DMICDAT2_PD                      0x0008  /* DMICDAT2_PD */
+#define WM2200_DMICDAT2_PD_MASK                 0x0008  /* DMICDAT2_PD */
+#define WM2200_DMICDAT2_PD_SHIFT                     3  /* DMICDAT2_PD */
+#define WM2200_DMICDAT2_PD_WIDTH                     1  /* DMICDAT2_PD */
+#define WM2200_DMICDAT1_PD                      0x0004  /* DMICDAT1_PD */
+#define WM2200_DMICDAT1_PD_MASK                 0x0004  /* DMICDAT1_PD */
+#define WM2200_DMICDAT1_PD_SHIFT                     2  /* DMICDAT1_PD */
+#define WM2200_DMICDAT1_PD_WIDTH                     1  /* DMICDAT1_PD */
+#define WM2200_RSTB_PU                          0x0002  /* RSTB_PU */
+#define WM2200_RSTB_PU_MASK                     0x0002  /* RSTB_PU */
+#define WM2200_RSTB_PU_SHIFT                         1  /* RSTB_PU */
+#define WM2200_RSTB_PU_WIDTH                         1  /* RSTB_PU */
+#define WM2200_ADDR_PD                          0x0001  /* ADDR_PD */
+#define WM2200_ADDR_PD_MASK                     0x0001  /* ADDR_PD */
+#define WM2200_ADDR_PD_SHIFT                         0  /* ADDR_PD */
+#define WM2200_ADDR_PD_WIDTH                         1  /* ADDR_PD */
+
+/*
+ * R2048 (0x800) - Interrupt Status 1
+ */
+#define WM2200_DSP_IRQ0_EINT                    0x0080  /* DSP_IRQ0_EINT */
+#define WM2200_DSP_IRQ0_EINT_MASK               0x0080  /* DSP_IRQ0_EINT */
+#define WM2200_DSP_IRQ0_EINT_SHIFT                   7  /* DSP_IRQ0_EINT */
+#define WM2200_DSP_IRQ0_EINT_WIDTH                   1  /* DSP_IRQ0_EINT */
+#define WM2200_DSP_IRQ1_EINT                    0x0040  /* DSP_IRQ1_EINT */
+#define WM2200_DSP_IRQ1_EINT_MASK               0x0040  /* DSP_IRQ1_EINT */
+#define WM2200_DSP_IRQ1_EINT_SHIFT                   6  /* DSP_IRQ1_EINT */
+#define WM2200_DSP_IRQ1_EINT_WIDTH                   1  /* DSP_IRQ1_EINT */
+#define WM2200_DSP_IRQ2_EINT                    0x0020  /* DSP_IRQ2_EINT */
+#define WM2200_DSP_IRQ2_EINT_MASK               0x0020  /* DSP_IRQ2_EINT */
+#define WM2200_DSP_IRQ2_EINT_SHIFT                   5  /* DSP_IRQ2_EINT */
+#define WM2200_DSP_IRQ2_EINT_WIDTH                   1  /* DSP_IRQ2_EINT */
+#define WM2200_DSP_IRQ3_EINT                    0x0010  /* DSP_IRQ3_EINT */
+#define WM2200_DSP_IRQ3_EINT_MASK               0x0010  /* DSP_IRQ3_EINT */
+#define WM2200_DSP_IRQ3_EINT_SHIFT                   4  /* DSP_IRQ3_EINT */
+#define WM2200_DSP_IRQ3_EINT_WIDTH                   1  /* DSP_IRQ3_EINT */
+#define WM2200_GP4_EINT                         0x0008  /* GP4_EINT */
+#define WM2200_GP4_EINT_MASK                    0x0008  /* GP4_EINT */
+#define WM2200_GP4_EINT_SHIFT                        3  /* GP4_EINT */
+#define WM2200_GP4_EINT_WIDTH                        1  /* GP4_EINT */
+#define WM2200_GP3_EINT                         0x0004  /* GP3_EINT */
+#define WM2200_GP3_EINT_MASK                    0x0004  /* GP3_EINT */
+#define WM2200_GP3_EINT_SHIFT                        2  /* GP3_EINT */
+#define WM2200_GP3_EINT_WIDTH                        1  /* GP3_EINT */
+#define WM2200_GP2_EINT                         0x0002  /* GP2_EINT */
+#define WM2200_GP2_EINT_MASK                    0x0002  /* GP2_EINT */
+#define WM2200_GP2_EINT_SHIFT                        1  /* GP2_EINT */
+#define WM2200_GP2_EINT_WIDTH                        1  /* GP2_EINT */
+#define WM2200_GP1_EINT                         0x0001  /* GP1_EINT */
+#define WM2200_GP1_EINT_MASK                    0x0001  /* GP1_EINT */
+#define WM2200_GP1_EINT_SHIFT                        0  /* GP1_EINT */
+#define WM2200_GP1_EINT_WIDTH                        1  /* GP1_EINT */
+
+/*
+ * R2049 (0x801) - Interrupt Status 1 Mask
+ */
+#define WM2200_IM_DSP_IRQ0_EINT                 0x0080  /* IM_DSP_IRQ0_EINT */
+#define WM2200_IM_DSP_IRQ0_EINT_MASK            0x0080  /* IM_DSP_IRQ0_EINT */
+#define WM2200_IM_DSP_IRQ0_EINT_SHIFT                7  /* IM_DSP_IRQ0_EINT */
+#define WM2200_IM_DSP_IRQ0_EINT_WIDTH                1  /* IM_DSP_IRQ0_EINT */
+#define WM2200_IM_DSP_IRQ1_EINT                 0x0040  /* IM_DSP_IRQ1_EINT */
+#define WM2200_IM_DSP_IRQ1_EINT_MASK            0x0040  /* IM_DSP_IRQ1_EINT */
+#define WM2200_IM_DSP_IRQ1_EINT_SHIFT                6  /* IM_DSP_IRQ1_EINT */
+#define WM2200_IM_DSP_IRQ1_EINT_WIDTH                1  /* IM_DSP_IRQ1_EINT */
+#define WM2200_IM_DSP_IRQ2_EINT                 0x0020  /* IM_DSP_IRQ2_EINT */
+#define WM2200_IM_DSP_IRQ2_EINT_MASK            0x0020  /* IM_DSP_IRQ2_EINT */
+#define WM2200_IM_DSP_IRQ2_EINT_SHIFT                5  /* IM_DSP_IRQ2_EINT */
+#define WM2200_IM_DSP_IRQ2_EINT_WIDTH                1  /* IM_DSP_IRQ2_EINT */
+#define WM2200_IM_DSP_IRQ3_EINT                 0x0010  /* IM_DSP_IRQ3_EINT */
+#define WM2200_IM_DSP_IRQ3_EINT_MASK            0x0010  /* IM_DSP_IRQ3_EINT */
+#define WM2200_IM_DSP_IRQ3_EINT_SHIFT                4  /* IM_DSP_IRQ3_EINT */
+#define WM2200_IM_DSP_IRQ3_EINT_WIDTH                1  /* IM_DSP_IRQ3_EINT */
+#define WM2200_IM_GP4_EINT                      0x0008  /* IM_GP4_EINT */
+#define WM2200_IM_GP4_EINT_MASK                 0x0008  /* IM_GP4_EINT */
+#define WM2200_IM_GP4_EINT_SHIFT                     3  /* IM_GP4_EINT */
+#define WM2200_IM_GP4_EINT_WIDTH                     1  /* IM_GP4_EINT */
+#define WM2200_IM_GP3_EINT                      0x0004  /* IM_GP3_EINT */
+#define WM2200_IM_GP3_EINT_MASK                 0x0004  /* IM_GP3_EINT */
+#define WM2200_IM_GP3_EINT_SHIFT                     2  /* IM_GP3_EINT */
+#define WM2200_IM_GP3_EINT_WIDTH                     1  /* IM_GP3_EINT */
+#define WM2200_IM_GP2_EINT                      0x0002  /* IM_GP2_EINT */
+#define WM2200_IM_GP2_EINT_MASK                 0x0002  /* IM_GP2_EINT */
+#define WM2200_IM_GP2_EINT_SHIFT                     1  /* IM_GP2_EINT */
+#define WM2200_IM_GP2_EINT_WIDTH                     1  /* IM_GP2_EINT */
+#define WM2200_IM_GP1_EINT                      0x0001  /* IM_GP1_EINT */
+#define WM2200_IM_GP1_EINT_MASK                 0x0001  /* IM_GP1_EINT */
+#define WM2200_IM_GP1_EINT_SHIFT                     0  /* IM_GP1_EINT */
+#define WM2200_IM_GP1_EINT_WIDTH                     1  /* IM_GP1_EINT */
+
+/*
+ * R2050 (0x802) - Interrupt Status 2
+ */
+#define WM2200_WSEQ_BUSY_EINT                   0x0100  /* WSEQ_BUSY_EINT */
+#define WM2200_WSEQ_BUSY_EINT_MASK              0x0100  /* WSEQ_BUSY_EINT */
+#define WM2200_WSEQ_BUSY_EINT_SHIFT                  8  /* WSEQ_BUSY_EINT */
+#define WM2200_WSEQ_BUSY_EINT_WIDTH                  1  /* WSEQ_BUSY_EINT */
+#define WM2200_FLL_LOCK_EINT                    0x0002  /* FLL_LOCK_EINT */
+#define WM2200_FLL_LOCK_EINT_MASK               0x0002  /* FLL_LOCK_EINT */
+#define WM2200_FLL_LOCK_EINT_SHIFT                   1  /* FLL_LOCK_EINT */
+#define WM2200_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM2200_CLKGEN_EINT                      0x0001  /* CLKGEN_EINT */
+#define WM2200_CLKGEN_EINT_MASK                 0x0001  /* CLKGEN_EINT */
+#define WM2200_CLKGEN_EINT_SHIFT                     0  /* CLKGEN_EINT */
+#define WM2200_CLKGEN_EINT_WIDTH                     1  /* CLKGEN_EINT */
+
+/*
+ * R2051 (0x803) - Interrupt Raw Status 2
+ */
+#define WM2200_WSEQ_BUSY_STS                    0x0100  /* WSEQ_BUSY_STS */
+#define WM2200_WSEQ_BUSY_STS_MASK               0x0100  /* WSEQ_BUSY_STS */
+#define WM2200_WSEQ_BUSY_STS_SHIFT                   8  /* WSEQ_BUSY_STS */
+#define WM2200_WSEQ_BUSY_STS_WIDTH                   1  /* WSEQ_BUSY_STS */
+#define WM2200_FLL_LOCK_STS                     0x0002  /* FLL_LOCK_STS */
+#define WM2200_FLL_LOCK_STS_MASK                0x0002  /* FLL_LOCK_STS */
+#define WM2200_FLL_LOCK_STS_SHIFT                    1  /* FLL_LOCK_STS */
+#define WM2200_FLL_LOCK_STS_WIDTH                    1  /* FLL_LOCK_STS */
+#define WM2200_CLKGEN_STS                       0x0001  /* CLKGEN_STS */
+#define WM2200_CLKGEN_STS_MASK                  0x0001  /* CLKGEN_STS */
+#define WM2200_CLKGEN_STS_SHIFT                      0  /* CLKGEN_STS */
+#define WM2200_CLKGEN_STS_WIDTH                      1  /* CLKGEN_STS */
+
+/*
+ * R2052 (0x804) - Interrupt Status 2 Mask
+ */
+#define WM2200_IM_WSEQ_BUSY_EINT                0x0100  /* IM_WSEQ_BUSY_EINT */
+#define WM2200_IM_WSEQ_BUSY_EINT_MASK           0x0100  /* IM_WSEQ_BUSY_EINT */
+#define WM2200_IM_WSEQ_BUSY_EINT_SHIFT               8  /* IM_WSEQ_BUSY_EINT */
+#define WM2200_IM_WSEQ_BUSY_EINT_WIDTH               1  /* IM_WSEQ_BUSY_EINT */
+#define WM2200_IM_FLL_LOCK_EINT                 0x0002  /* IM_FLL_LOCK_EINT */
+#define WM2200_IM_FLL_LOCK_EINT_MASK            0x0002  /* IM_FLL_LOCK_EINT */
+#define WM2200_IM_FLL_LOCK_EINT_SHIFT                1  /* IM_FLL_LOCK_EINT */
+#define WM2200_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM2200_IM_CLKGEN_EINT                   0x0001  /* IM_CLKGEN_EINT */
+#define WM2200_IM_CLKGEN_EINT_MASK              0x0001  /* IM_CLKGEN_EINT */
+#define WM2200_IM_CLKGEN_EINT_SHIFT                  0  /* IM_CLKGEN_EINT */
+#define WM2200_IM_CLKGEN_EINT_WIDTH                  1  /* IM_CLKGEN_EINT */
+
+/*
+ * R2056 (0x808) - Interrupt Control
+ */
+#define WM2200_IM_IRQ                           0x0001  /* IM_IRQ */
+#define WM2200_IM_IRQ_MASK                      0x0001  /* IM_IRQ */
+#define WM2200_IM_IRQ_SHIFT                          0  /* IM_IRQ */
+#define WM2200_IM_IRQ_WIDTH                          1  /* IM_IRQ */
+
+/*
+ * R2304 (0x900) - EQL_1
+ */
+#define WM2200_EQL_B1_GAIN_MASK                 0xF800  /* EQL_B1_GAIN - [15:11] */
+#define WM2200_EQL_B1_GAIN_SHIFT                    11  /* EQL_B1_GAIN - [15:11] */
+#define WM2200_EQL_B1_GAIN_WIDTH                     5  /* EQL_B1_GAIN - [15:11] */
+#define WM2200_EQL_B2_GAIN_MASK                 0x07C0  /* EQL_B2_GAIN - [10:6] */
+#define WM2200_EQL_B2_GAIN_SHIFT                     6  /* EQL_B2_GAIN - [10:6] */
+#define WM2200_EQL_B2_GAIN_WIDTH                     5  /* EQL_B2_GAIN - [10:6] */
+#define WM2200_EQL_B3_GAIN_MASK                 0x003E  /* EQL_B3_GAIN - [5:1] */
+#define WM2200_EQL_B3_GAIN_SHIFT                     1  /* EQL_B3_GAIN - [5:1] */
+#define WM2200_EQL_B3_GAIN_WIDTH                     5  /* EQL_B3_GAIN - [5:1] */
+#define WM2200_EQL_ENA                          0x0001  /* EQL_ENA */
+#define WM2200_EQL_ENA_MASK                     0x0001  /* EQL_ENA */
+#define WM2200_EQL_ENA_SHIFT                         0  /* EQL_ENA */
+#define WM2200_EQL_ENA_WIDTH                         1  /* EQL_ENA */
+
+/*
+ * R2305 (0x901) - EQL_2
+ */
+#define WM2200_EQL_B4_GAIN_MASK                 0xF800  /* EQL_B4_GAIN - [15:11] */
+#define WM2200_EQL_B4_GAIN_SHIFT                    11  /* EQL_B4_GAIN - [15:11] */
+#define WM2200_EQL_B4_GAIN_WIDTH                     5  /* EQL_B4_GAIN - [15:11] */
+#define WM2200_EQL_B5_GAIN_MASK                 0x07C0  /* EQL_B5_GAIN - [10:6] */
+#define WM2200_EQL_B5_GAIN_SHIFT                     6  /* EQL_B5_GAIN - [10:6] */
+#define WM2200_EQL_B5_GAIN_WIDTH                     5  /* EQL_B5_GAIN - [10:6] */
+
+/*
+ * R2306 (0x902) - EQL_3
+ */
+#define WM2200_EQL_B1_A_MASK                    0xFFFF  /* EQL_B1_A - [15:0] */
+#define WM2200_EQL_B1_A_SHIFT                        0  /* EQL_B1_A - [15:0] */
+#define WM2200_EQL_B1_A_WIDTH                       16  /* EQL_B1_A - [15:0] */
+
+/*
+ * R2307 (0x903) - EQL_4
+ */
+#define WM2200_EQL_B1_B_MASK                    0xFFFF  /* EQL_B1_B - [15:0] */
+#define WM2200_EQL_B1_B_SHIFT                        0  /* EQL_B1_B - [15:0] */
+#define WM2200_EQL_B1_B_WIDTH                       16  /* EQL_B1_B - [15:0] */
+
+/*
+ * R2308 (0x904) - EQL_5
+ */
+#define WM2200_EQL_B1_PG_MASK                   0xFFFF  /* EQL_B1_PG - [15:0] */
+#define WM2200_EQL_B1_PG_SHIFT                       0  /* EQL_B1_PG - [15:0] */
+#define WM2200_EQL_B1_PG_WIDTH                      16  /* EQL_B1_PG - [15:0] */
+
+/*
+ * R2309 (0x905) - EQL_6
+ */
+#define WM2200_EQL_B2_A_MASK                    0xFFFF  /* EQL_B2_A - [15:0] */
+#define WM2200_EQL_B2_A_SHIFT                        0  /* EQL_B2_A - [15:0] */
+#define WM2200_EQL_B2_A_WIDTH                       16  /* EQL_B2_A - [15:0] */
+
+/*
+ * R2310 (0x906) - EQL_7
+ */
+#define WM2200_EQL_B2_B_MASK                    0xFFFF  /* EQL_B2_B - [15:0] */
+#define WM2200_EQL_B2_B_SHIFT                        0  /* EQL_B2_B - [15:0] */
+#define WM2200_EQL_B2_B_WIDTH                       16  /* EQL_B2_B - [15:0] */
+
+/*
+ * R2311 (0x907) - EQL_8
+ */
+#define WM2200_EQL_B2_C_MASK                    0xFFFF  /* EQL_B2_C - [15:0] */
+#define WM2200_EQL_B2_C_SHIFT                        0  /* EQL_B2_C - [15:0] */
+#define WM2200_EQL_B2_C_WIDTH                       16  /* EQL_B2_C - [15:0] */
+
+/*
+ * R2312 (0x908) - EQL_9
+ */
+#define WM2200_EQL_B2_PG_MASK                   0xFFFF  /* EQL_B2_PG - [15:0] */
+#define WM2200_EQL_B2_PG_SHIFT                       0  /* EQL_B2_PG - [15:0] */
+#define WM2200_EQL_B2_PG_WIDTH                      16  /* EQL_B2_PG - [15:0] */
+
+/*
+ * R2313 (0x909) - EQL_10
+ */
+#define WM2200_EQL_B3_A_MASK                    0xFFFF  /* EQL_B3_A - [15:0] */
+#define WM2200_EQL_B3_A_SHIFT                        0  /* EQL_B3_A - [15:0] */
+#define WM2200_EQL_B3_A_WIDTH                       16  /* EQL_B3_A - [15:0] */
+
+/*
+ * R2314 (0x90A) - EQL_11
+ */
+#define WM2200_EQL_B3_B_MASK                    0xFFFF  /* EQL_B3_B - [15:0] */
+#define WM2200_EQL_B3_B_SHIFT                        0  /* EQL_B3_B - [15:0] */
+#define WM2200_EQL_B3_B_WIDTH                       16  /* EQL_B3_B - [15:0] */
+
+/*
+ * R2315 (0x90B) - EQL_12
+ */
+#define WM2200_EQL_B3_C_MASK                    0xFFFF  /* EQL_B3_C - [15:0] */
+#define WM2200_EQL_B3_C_SHIFT                        0  /* EQL_B3_C - [15:0] */
+#define WM2200_EQL_B3_C_WIDTH                       16  /* EQL_B3_C - [15:0] */
+
+/*
+ * R2316 (0x90C) - EQL_13
+ */
+#define WM2200_EQL_B3_PG_MASK                   0xFFFF  /* EQL_B3_PG - [15:0] */
+#define WM2200_EQL_B3_PG_SHIFT                       0  /* EQL_B3_PG - [15:0] */
+#define WM2200_EQL_B3_PG_WIDTH                      16  /* EQL_B3_PG - [15:0] */
+
+/*
+ * R2317 (0x90D) - EQL_14
+ */
+#define WM2200_EQL_B4_A_MASK                    0xFFFF  /* EQL_B4_A - [15:0] */
+#define WM2200_EQL_B4_A_SHIFT                        0  /* EQL_B4_A - [15:0] */
+#define WM2200_EQL_B4_A_WIDTH                       16  /* EQL_B4_A - [15:0] */
+
+/*
+ * R2318 (0x90E) - EQL_15
+ */
+#define WM2200_EQL_B4_B_MASK                    0xFFFF  /* EQL_B4_B - [15:0] */
+#define WM2200_EQL_B4_B_SHIFT                        0  /* EQL_B4_B - [15:0] */
+#define WM2200_EQL_B4_B_WIDTH                       16  /* EQL_B4_B - [15:0] */
+
+/*
+ * R2319 (0x90F) - EQL_16
+ */
+#define WM2200_EQL_B4_C_MASK                    0xFFFF  /* EQL_B4_C - [15:0] */
+#define WM2200_EQL_B4_C_SHIFT                        0  /* EQL_B4_C - [15:0] */
+#define WM2200_EQL_B4_C_WIDTH                       16  /* EQL_B4_C - [15:0] */
+
+/*
+ * R2320 (0x910) - EQL_17
+ */
+#define WM2200_EQL_B4_PG_MASK                   0xFFFF  /* EQL_B4_PG - [15:0] */
+#define WM2200_EQL_B4_PG_SHIFT                       0  /* EQL_B4_PG - [15:0] */
+#define WM2200_EQL_B4_PG_WIDTH                      16  /* EQL_B4_PG - [15:0] */
+
+/*
+ * R2321 (0x911) - EQL_18
+ */
+#define WM2200_EQL_B5_A_MASK                    0xFFFF  /* EQL_B5_A - [15:0] */
+#define WM2200_EQL_B5_A_SHIFT                        0  /* EQL_B5_A - [15:0] */
+#define WM2200_EQL_B5_A_WIDTH                       16  /* EQL_B5_A - [15:0] */
+
+/*
+ * R2322 (0x912) - EQL_19
+ */
+#define WM2200_EQL_B5_B_MASK                    0xFFFF  /* EQL_B5_B - [15:0] */
+#define WM2200_EQL_B5_B_SHIFT                        0  /* EQL_B5_B - [15:0] */
+#define WM2200_EQL_B5_B_WIDTH                       16  /* EQL_B5_B - [15:0] */
+
+/*
+ * R2323 (0x913) - EQL_20
+ */
+#define WM2200_EQL_B5_PG_MASK                   0xFFFF  /* EQL_B5_PG - [15:0] */
+#define WM2200_EQL_B5_PG_SHIFT                       0  /* EQL_B5_PG - [15:0] */
+#define WM2200_EQL_B5_PG_WIDTH                      16  /* EQL_B5_PG - [15:0] */
+
+/*
+ * R2326 (0x916) - EQR_1
+ */
+#define WM2200_EQR_B1_GAIN_MASK                 0xF800  /* EQR_B1_GAIN - [15:11] */
+#define WM2200_EQR_B1_GAIN_SHIFT                    11  /* EQR_B1_GAIN - [15:11] */
+#define WM2200_EQR_B1_GAIN_WIDTH                     5  /* EQR_B1_GAIN - [15:11] */
+#define WM2200_EQR_B2_GAIN_MASK                 0x07C0  /* EQR_B2_GAIN - [10:6] */
+#define WM2200_EQR_B2_GAIN_SHIFT                     6  /* EQR_B2_GAIN - [10:6] */
+#define WM2200_EQR_B2_GAIN_WIDTH                     5  /* EQR_B2_GAIN - [10:6] */
+#define WM2200_EQR_B3_GAIN_MASK                 0x003E  /* EQR_B3_GAIN - [5:1] */
+#define WM2200_EQR_B3_GAIN_SHIFT                     1  /* EQR_B3_GAIN - [5:1] */
+#define WM2200_EQR_B3_GAIN_WIDTH                     5  /* EQR_B3_GAIN - [5:1] */
+#define WM2200_EQR_ENA                          0x0001  /* EQR_ENA */
+#define WM2200_EQR_ENA_MASK                     0x0001  /* EQR_ENA */
+#define WM2200_EQR_ENA_SHIFT                         0  /* EQR_ENA */
+#define WM2200_EQR_ENA_WIDTH                         1  /* EQR_ENA */
+
+/*
+ * R2327 (0x917) - EQR_2
+ */
+#define WM2200_EQR_B4_GAIN_MASK                 0xF800  /* EQR_B4_GAIN - [15:11] */
+#define WM2200_EQR_B4_GAIN_SHIFT                    11  /* EQR_B4_GAIN - [15:11] */
+#define WM2200_EQR_B4_GAIN_WIDTH                     5  /* EQR_B4_GAIN - [15:11] */
+#define WM2200_EQR_B5_GAIN_MASK                 0x07C0  /* EQR_B5_GAIN - [10:6] */
+#define WM2200_EQR_B5_GAIN_SHIFT                     6  /* EQR_B5_GAIN - [10:6] */
+#define WM2200_EQR_B5_GAIN_WIDTH                     5  /* EQR_B5_GAIN - [10:6] */
+
+/*
+ * R2328 (0x918) - EQR_3
+ */
+#define WM2200_EQR_B1_A_MASK                    0xFFFF  /* EQR_B1_A - [15:0] */
+#define WM2200_EQR_B1_A_SHIFT                        0  /* EQR_B1_A - [15:0] */
+#define WM2200_EQR_B1_A_WIDTH                       16  /* EQR_B1_A - [15:0] */
+
+/*
+ * R2329 (0x919) - EQR_4
+ */
+#define WM2200_EQR_B1_B_MASK                    0xFFFF  /* EQR_B1_B - [15:0] */
+#define WM2200_EQR_B1_B_SHIFT                        0  /* EQR_B1_B - [15:0] */
+#define WM2200_EQR_B1_B_WIDTH                       16  /* EQR_B1_B - [15:0] */
+
+/*
+ * R2330 (0x91A) - EQR_5
+ */
+#define WM2200_EQR_B1_PG_MASK                   0xFFFF  /* EQR_B1_PG - [15:0] */
+#define WM2200_EQR_B1_PG_SHIFT                       0  /* EQR_B1_PG - [15:0] */
+#define WM2200_EQR_B1_PG_WIDTH                      16  /* EQR_B1_PG - [15:0] */
+
+/*
+ * R2331 (0x91B) - EQR_6
+ */
+#define WM2200_EQR_B2_A_MASK                    0xFFFF  /* EQR_B2_A - [15:0] */
+#define WM2200_EQR_B2_A_SHIFT                        0  /* EQR_B2_A - [15:0] */
+#define WM2200_EQR_B2_A_WIDTH                       16  /* EQR_B2_A - [15:0] */
+
+/*
+ * R2332 (0x91C) - EQR_7
+ */
+#define WM2200_EQR_B2_B_MASK                    0xFFFF  /* EQR_B2_B - [15:0] */
+#define WM2200_EQR_B2_B_SHIFT                        0  /* EQR_B2_B - [15:0] */
+#define WM2200_EQR_B2_B_WIDTH                       16  /* EQR_B2_B - [15:0] */
+
+/*
+ * R2333 (0x91D) - EQR_8
+ */
+#define WM2200_EQR_B2_C_MASK                    0xFFFF  /* EQR_B2_C - [15:0] */
+#define WM2200_EQR_B2_C_SHIFT                        0  /* EQR_B2_C - [15:0] */
+#define WM2200_EQR_B2_C_WIDTH                       16  /* EQR_B2_C - [15:0] */
+
+/*
+ * R2334 (0x91E) - EQR_9
+ */
+#define WM2200_EQR_B2_PG_MASK                   0xFFFF  /* EQR_B2_PG - [15:0] */
+#define WM2200_EQR_B2_PG_SHIFT                       0  /* EQR_B2_PG - [15:0] */
+#define WM2200_EQR_B2_PG_WIDTH                      16  /* EQR_B2_PG - [15:0] */
+
+/*
+ * R2335 (0x91F) - EQR_10
+ */
+#define WM2200_EQR_B3_A_MASK                    0xFFFF  /* EQR_B3_A - [15:0] */
+#define WM2200_EQR_B3_A_SHIFT                        0  /* EQR_B3_A - [15:0] */
+#define WM2200_EQR_B3_A_WIDTH                       16  /* EQR_B3_A - [15:0] */
+
+/*
+ * R2336 (0x920) - EQR_11
+ */
+#define WM2200_EQR_B3_B_MASK                    0xFFFF  /* EQR_B3_B - [15:0] */
+#define WM2200_EQR_B3_B_SHIFT                        0  /* EQR_B3_B - [15:0] */
+#define WM2200_EQR_B3_B_WIDTH                       16  /* EQR_B3_B - [15:0] */
+
+/*
+ * R2337 (0x921) - EQR_12
+ */
+#define WM2200_EQR_B3_C_MASK                    0xFFFF  /* EQR_B3_C - [15:0] */
+#define WM2200_EQR_B3_C_SHIFT                        0  /* EQR_B3_C - [15:0] */
+#define WM2200_EQR_B3_C_WIDTH                       16  /* EQR_B3_C - [15:0] */
+
+/*
+ * R2338 (0x922) - EQR_13
+ */
+#define WM2200_EQR_B3_PG_MASK                   0xFFFF  /* EQR_B3_PG - [15:0] */
+#define WM2200_EQR_B3_PG_SHIFT                       0  /* EQR_B3_PG - [15:0] */
+#define WM2200_EQR_B3_PG_WIDTH                      16  /* EQR_B3_PG - [15:0] */
+
+/*
+ * R2339 (0x923) - EQR_14
+ */
+#define WM2200_EQR_B4_A_MASK                    0xFFFF  /* EQR_B4_A - [15:0] */
+#define WM2200_EQR_B4_A_SHIFT                        0  /* EQR_B4_A - [15:0] */
+#define WM2200_EQR_B4_A_WIDTH                       16  /* EQR_B4_A - [15:0] */
+
+/*
+ * R2340 (0x924) - EQR_15
+ */
+#define WM2200_EQR_B4_B_MASK                    0xFFFF  /* EQR_B4_B - [15:0] */
+#define WM2200_EQR_B4_B_SHIFT                        0  /* EQR_B4_B - [15:0] */
+#define WM2200_EQR_B4_B_WIDTH                       16  /* EQR_B4_B - [15:0] */
+
+/*
+ * R2341 (0x925) - EQR_16
+ */
+#define WM2200_EQR_B4_C_MASK                    0xFFFF  /* EQR_B4_C - [15:0] */
+#define WM2200_EQR_B4_C_SHIFT                        0  /* EQR_B4_C - [15:0] */
+#define WM2200_EQR_B4_C_WIDTH                       16  /* EQR_B4_C - [15:0] */
+
+/*
+ * R2342 (0x926) - EQR_17
+ */
+#define WM2200_EQR_B4_PG_MASK                   0xFFFF  /* EQR_B4_PG - [15:0] */
+#define WM2200_EQR_B4_PG_SHIFT                       0  /* EQR_B4_PG - [15:0] */
+#define WM2200_EQR_B4_PG_WIDTH                      16  /* EQR_B4_PG - [15:0] */
+
+/*
+ * R2343 (0x927) - EQR_18
+ */
+#define WM2200_EQR_B5_A_MASK                    0xFFFF  /* EQR_B5_A - [15:0] */
+#define WM2200_EQR_B5_A_SHIFT                        0  /* EQR_B5_A - [15:0] */
+#define WM2200_EQR_B5_A_WIDTH                       16  /* EQR_B5_A - [15:0] */
+
+/*
+ * R2344 (0x928) - EQR_19
+ */
+#define WM2200_EQR_B5_B_MASK                    0xFFFF  /* EQR_B5_B - [15:0] */
+#define WM2200_EQR_B5_B_SHIFT                        0  /* EQR_B5_B - [15:0] */
+#define WM2200_EQR_B5_B_WIDTH                       16  /* EQR_B5_B - [15:0] */
+
+/*
+ * R2345 (0x929) - EQR_20
+ */
+#define WM2200_EQR_B5_PG_MASK                   0xFFFF  /* EQR_B5_PG - [15:0] */
+#define WM2200_EQR_B5_PG_SHIFT                       0  /* EQR_B5_PG - [15:0] */
+#define WM2200_EQR_B5_PG_WIDTH                      16  /* EQR_B5_PG - [15:0] */
+
+/*
+ * R2366 (0x93E) - HPLPF1_1
+ */
+#define WM2200_LHPF1_MODE                       0x0002  /* LHPF1_MODE */
+#define WM2200_LHPF1_MODE_MASK                  0x0002  /* LHPF1_MODE */
+#define WM2200_LHPF1_MODE_SHIFT                      1  /* LHPF1_MODE */
+#define WM2200_LHPF1_MODE_WIDTH                      1  /* LHPF1_MODE */
+#define WM2200_LHPF1_ENA                        0x0001  /* LHPF1_ENA */
+#define WM2200_LHPF1_ENA_MASK                   0x0001  /* LHPF1_ENA */
+#define WM2200_LHPF1_ENA_SHIFT                       0  /* LHPF1_ENA */
+#define WM2200_LHPF1_ENA_WIDTH                       1  /* LHPF1_ENA */
+
+/*
+ * R2367 (0x93F) - HPLPF1_2
+ */
+#define WM2200_LHPF1_COEFF_MASK                 0xFFFF  /* LHPF1_COEFF - [15:0] */
+#define WM2200_LHPF1_COEFF_SHIFT                     0  /* LHPF1_COEFF - [15:0] */
+#define WM2200_LHPF1_COEFF_WIDTH                    16  /* LHPF1_COEFF - [15:0] */
+
+/*
+ * R2370 (0x942) - HPLPF2_1
+ */
+#define WM2200_LHPF2_MODE                       0x0002  /* LHPF2_MODE */
+#define WM2200_LHPF2_MODE_MASK                  0x0002  /* LHPF2_MODE */
+#define WM2200_LHPF2_MODE_SHIFT                      1  /* LHPF2_MODE */
+#define WM2200_LHPF2_MODE_WIDTH                      1  /* LHPF2_MODE */
+#define WM2200_LHPF2_ENA                        0x0001  /* LHPF2_ENA */
+#define WM2200_LHPF2_ENA_MASK                   0x0001  /* LHPF2_ENA */
+#define WM2200_LHPF2_ENA_SHIFT                       0  /* LHPF2_ENA */
+#define WM2200_LHPF2_ENA_WIDTH                       1  /* LHPF2_ENA */
+
+/*
+ * R2371 (0x943) - HPLPF2_2
+ */
+#define WM2200_LHPF2_COEFF_MASK                 0xFFFF  /* LHPF2_COEFF - [15:0] */
+#define WM2200_LHPF2_COEFF_SHIFT                     0  /* LHPF2_COEFF - [15:0] */
+#define WM2200_LHPF2_COEFF_WIDTH                    16  /* LHPF2_COEFF - [15:0] */
+
+/*
+ * R2560 (0xA00) - DSP1 Control 1
+ */
+#define WM2200_DSP1_RW_SEQUENCE_ENA             0x0001  /* DSP1_RW_SEQUENCE_ENA */
+#define WM2200_DSP1_RW_SEQUENCE_ENA_MASK        0x0001  /* DSP1_RW_SEQUENCE_ENA */
+#define WM2200_DSP1_RW_SEQUENCE_ENA_SHIFT            0  /* DSP1_RW_SEQUENCE_ENA */
+#define WM2200_DSP1_RW_SEQUENCE_ENA_WIDTH            1  /* DSP1_RW_SEQUENCE_ENA */
+
+/*
+ * R2562 (0xA02) - DSP1 Control 2
+ */
+#define WM2200_DSP1_PAGE_BASE_PM_0_MASK         0xFF00  /* DSP1_PAGE_BASE_PM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_PM_0_SHIFT             8  /* DSP1_PAGE_BASE_PM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_PM_0_WIDTH             8  /* DSP1_PAGE_BASE_PM - [15:8] */
+
+/*
+ * R2563 (0xA03) - DSP1 Control 3
+ */
+#define WM2200_DSP1_PAGE_BASE_DM_0_MASK         0xFF00  /* DSP1_PAGE_BASE_DM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_DM_0_SHIFT             8  /* DSP1_PAGE_BASE_DM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_DM_0_WIDTH             8  /* DSP1_PAGE_BASE_DM - [15:8] */
+
+/*
+ * R2564 (0xA04) - DSP1 Control 4
+ */
+#define WM2200_DSP1_PAGE_BASE_ZM_0_MASK         0xFF00  /* DSP1_PAGE_BASE_ZM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_ZM_0_SHIFT             8  /* DSP1_PAGE_BASE_ZM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_ZM_0_WIDTH             8  /* DSP1_PAGE_BASE_ZM - [15:8] */
+
+/*
+ * R2566 (0xA06) - DSP1 Control 5
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_0_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_0_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_0_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+
+/*
+ * R2567 (0xA07) - DSP1 Control 6
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_1_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_1_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_1_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+
+/*
+ * R2568 (0xA08) - DSP1 Control 7
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_2_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_2_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_2_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+
+/*
+ * R2569 (0xA09) - DSP1 Control 8
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_3_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_3_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_3_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+
+/*
+ * R2570 (0xA0A) - DSP1 Control 9
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_4_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_4_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_4_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+
+/*
+ * R2571 (0xA0B) - DSP1 Control 10
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_5_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_5_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_5_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+
+/*
+ * R2572 (0xA0C) - DSP1 Control 11
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_6_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_6_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_6_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+
+/*
+ * R2573 (0xA0D) - DSP1 Control 12
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_7_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_7_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_7_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+
+/*
+ * R2575 (0xA0F) - DSP1 Control 13
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_0_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_0_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_0_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+
+/*
+ * R2576 (0xA10) - DSP1 Control 14
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_1_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_1_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_1_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+
+/*
+ * R2577 (0xA11) - DSP1 Control 15
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_2_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_2_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_2_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+
+/*
+ * R2578 (0xA12) - DSP1 Control 16
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_3_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_3_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_3_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+
+/*
+ * R2579 (0xA13) - DSP1 Control 17
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_4_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_4_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_4_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+
+/*
+ * R2580 (0xA14) - DSP1 Control 18
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_5_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_5_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_5_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+
+/*
+ * R2582 (0xA16) - DSP1 Control 19
+ */
+#define WM2200_DSP1_WDMA_BUFFER_LENGTH_MASK     0x00FF  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
+#define WM2200_DSP1_WDMA_BUFFER_LENGTH_SHIFT         0  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
+#define WM2200_DSP1_WDMA_BUFFER_LENGTH_WIDTH         8  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
+
+/*
+ * R2583 (0xA17) - DSP1 Control 20
+ */
+#define WM2200_DSP1_WDMA_CHANNEL_ENABLE_MASK    0x00FF  /* DSP1_WDMA_CHANNEL_ENABLE - [7:0] */
+#define WM2200_DSP1_WDMA_CHANNEL_ENABLE_SHIFT        0  /* DSP1_WDMA_CHANNEL_ENABLE - [7:0] */
+#define WM2200_DSP1_WDMA_CHANNEL_ENABLE_WIDTH        8  /* DSP1_WDMA_CHANNEL_ENABLE - [7:0] */
+
+/*
+ * R2584 (0xA18) - DSP1 Control 21
+ */
+#define WM2200_DSP1_RDMA_CHANNEL_ENABLE_MASK    0x003F  /* DSP1_RDMA_CHANNEL_ENABLE - [5:0] */
+#define WM2200_DSP1_RDMA_CHANNEL_ENABLE_SHIFT        0  /* DSP1_RDMA_CHANNEL_ENABLE - [5:0] */
+#define WM2200_DSP1_RDMA_CHANNEL_ENABLE_WIDTH        6  /* DSP1_RDMA_CHANNEL_ENABLE - [5:0] */
+
+/*
+ * R2586 (0xA1A) - DSP1 Control 22
+ */
+#define WM2200_DSP1_DM_SIZE_MASK                0xFFFF  /* DSP1_DM_SIZE - [15:0] */
+#define WM2200_DSP1_DM_SIZE_SHIFT                    0  /* DSP1_DM_SIZE - [15:0] */
+#define WM2200_DSP1_DM_SIZE_WIDTH                   16  /* DSP1_DM_SIZE - [15:0] */
+
+/*
+ * R2587 (0xA1B) - DSP1 Control 23
+ */
+#define WM2200_DSP1_PM_SIZE_MASK                0xFFFF  /* DSP1_PM_SIZE - [15:0] */
+#define WM2200_DSP1_PM_SIZE_SHIFT                    0  /* DSP1_PM_SIZE - [15:0] */
+#define WM2200_DSP1_PM_SIZE_WIDTH                   16  /* DSP1_PM_SIZE - [15:0] */
+
+/*
+ * R2588 (0xA1C) - DSP1 Control 24
+ */
+#define WM2200_DSP1_ZM_SIZE_MASK                0xFFFF  /* DSP1_ZM_SIZE - [15:0] */
+#define WM2200_DSP1_ZM_SIZE_SHIFT                    0  /* DSP1_ZM_SIZE - [15:0] */
+#define WM2200_DSP1_ZM_SIZE_WIDTH                   16  /* DSP1_ZM_SIZE - [15:0] */
+
+/*
+ * R2590 (0xA1E) - DSP1 Control 25
+ */
+#define WM2200_DSP1_PING_FULL                   0x8000  /* DSP1_PING_FULL */
+#define WM2200_DSP1_PING_FULL_MASK              0x8000  /* DSP1_PING_FULL */
+#define WM2200_DSP1_PING_FULL_SHIFT                 15  /* DSP1_PING_FULL */
+#define WM2200_DSP1_PING_FULL_WIDTH                  1  /* DSP1_PING_FULL */
+#define WM2200_DSP1_PONG_FULL                   0x4000  /* DSP1_PONG_FULL */
+#define WM2200_DSP1_PONG_FULL_MASK              0x4000  /* DSP1_PONG_FULL */
+#define WM2200_DSP1_PONG_FULL_SHIFT                 14  /* DSP1_PONG_FULL */
+#define WM2200_DSP1_PONG_FULL_WIDTH                  1  /* DSP1_PONG_FULL */
+#define WM2200_DSP1_WDMA_ACTIVE_CHANNELS_MASK   0x00FF  /* DSP1_WDMA_ACTIVE_CHANNELS - [7:0] */
+#define WM2200_DSP1_WDMA_ACTIVE_CHANNELS_SHIFT       0  /* DSP1_WDMA_ACTIVE_CHANNELS - [7:0] */
+#define WM2200_DSP1_WDMA_ACTIVE_CHANNELS_WIDTH       8  /* DSP1_WDMA_ACTIVE_CHANNELS - [7:0] */
+
+/*
+ * R2592 (0xA20) - DSP1 Control 26
+ */
+#define WM2200_DSP1_SCRATCH_0_MASK              0xFFFF  /* DSP1_SCRATCH_0 - [15:0] */
+#define WM2200_DSP1_SCRATCH_0_SHIFT                  0  /* DSP1_SCRATCH_0 - [15:0] */
+#define WM2200_DSP1_SCRATCH_0_WIDTH                 16  /* DSP1_SCRATCH_0 - [15:0] */
+
+/*
+ * R2593 (0xA21) - DSP1 Control 27
+ */
+#define WM2200_DSP1_SCRATCH_1_MASK              0xFFFF  /* DSP1_SCRATCH_1 - [15:0] */
+#define WM2200_DSP1_SCRATCH_1_SHIFT                  0  /* DSP1_SCRATCH_1 - [15:0] */
+#define WM2200_DSP1_SCRATCH_1_WIDTH                 16  /* DSP1_SCRATCH_1 - [15:0] */
+
+/*
+ * R2594 (0xA22) - DSP1 Control 28
+ */
+#define WM2200_DSP1_SCRATCH_2_MASK              0xFFFF  /* DSP1_SCRATCH_2 - [15:0] */
+#define WM2200_DSP1_SCRATCH_2_SHIFT                  0  /* DSP1_SCRATCH_2 - [15:0] */
+#define WM2200_DSP1_SCRATCH_2_WIDTH                 16  /* DSP1_SCRATCH_2 - [15:0] */
+
+/*
+ * R2595 (0xA23) - DSP1 Control 29
+ */
+#define WM2200_DSP1_SCRATCH_3_MASK              0xFFFF  /* DSP1_SCRATCH_3 - [15:0] */
+#define WM2200_DSP1_SCRATCH_3_SHIFT                  0  /* DSP1_SCRATCH_3 - [15:0] */
+#define WM2200_DSP1_SCRATCH_3_WIDTH                 16  /* DSP1_SCRATCH_3 - [15:0] */
+
+/*
+ * R2596 (0xA24) - DSP1 Control 30
+ */
+#define WM2200_DSP1_DBG_CLK_ENA                 0x0008  /* DSP1_DBG_CLK_ENA */
+#define WM2200_DSP1_DBG_CLK_ENA_MASK            0x0008  /* DSP1_DBG_CLK_ENA */
+#define WM2200_DSP1_DBG_CLK_ENA_SHIFT                3  /* DSP1_DBG_CLK_ENA */
+#define WM2200_DSP1_DBG_CLK_ENA_WIDTH                1  /* DSP1_DBG_CLK_ENA */
+#define WM2200_DSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
+#define WM2200_DSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
+#define WM2200_DSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
+#define WM2200_DSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
+#define WM2200_DSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
+#define WM2200_DSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
+#define WM2200_DSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
+#define WM2200_DSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
+#define WM2200_DSP1_START                       0x0001  /* DSP1_START */
+#define WM2200_DSP1_START_MASK                  0x0001  /* DSP1_START */
+#define WM2200_DSP1_START_SHIFT                      0  /* DSP1_START */
+#define WM2200_DSP1_START_WIDTH                      1  /* DSP1_START */
+
+/*
+ * R2598 (0xA26) - DSP1 Control 31
+ */
+#define WM2200_DSP1_CLK_RATE_MASK               0x0018  /* DSP1_CLK_RATE - [4:3] */
+#define WM2200_DSP1_CLK_RATE_SHIFT                   3  /* DSP1_CLK_RATE - [4:3] */
+#define WM2200_DSP1_CLK_RATE_WIDTH                   2  /* DSP1_CLK_RATE - [4:3] */
+#define WM2200_DSP1_CLK_AVAIL                   0x0004  /* DSP1_CLK_AVAIL */
+#define WM2200_DSP1_CLK_AVAIL_MASK              0x0004  /* DSP1_CLK_AVAIL */
+#define WM2200_DSP1_CLK_AVAIL_SHIFT                  2  /* DSP1_CLK_AVAIL */
+#define WM2200_DSP1_CLK_AVAIL_WIDTH                  1  /* DSP1_CLK_AVAIL */
+#define WM2200_DSP1_CLK_REQ_MASK                0x0003  /* DSP1_CLK_REQ - [1:0] */
+#define WM2200_DSP1_CLK_REQ_SHIFT                    0  /* DSP1_CLK_REQ - [1:0] */
+#define WM2200_DSP1_CLK_REQ_WIDTH                    2  /* DSP1_CLK_REQ - [1:0] */
+
+/*
+ * R2816 (0xB00) - DSP2 Control 1
+ */
+#define WM2200_DSP2_RW_SEQUENCE_ENA             0x0001  /* DSP2_RW_SEQUENCE_ENA */
+#define WM2200_DSP2_RW_SEQUENCE_ENA_MASK        0x0001  /* DSP2_RW_SEQUENCE_ENA */
+#define WM2200_DSP2_RW_SEQUENCE_ENA_SHIFT            0  /* DSP2_RW_SEQUENCE_ENA */
+#define WM2200_DSP2_RW_SEQUENCE_ENA_WIDTH            1  /* DSP2_RW_SEQUENCE_ENA */
+
+/*
+ * R2818 (0xB02) - DSP2 Control 2
+ */
+#define WM2200_DSP2_PAGE_BASE_PM_0_MASK         0xFF00  /* DSP2_PAGE_BASE_PM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_PM_0_SHIFT             8  /* DSP2_PAGE_BASE_PM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_PM_0_WIDTH             8  /* DSP2_PAGE_BASE_PM - [15:8] */
+
+/*
+ * R2819 (0xB03) - DSP2 Control 3
+ */
+#define WM2200_DSP2_PAGE_BASE_DM_0_MASK         0xFF00  /* DSP2_PAGE_BASE_DM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_DM_0_SHIFT             8  /* DSP2_PAGE_BASE_DM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_DM_0_WIDTH             8  /* DSP2_PAGE_BASE_DM - [15:8] */
+
+/*
+ * R2820 (0xB04) - DSP2 Control 4
+ */
+#define WM2200_DSP2_PAGE_BASE_ZM_0_MASK         0xFF00  /* DSP2_PAGE_BASE_ZM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_ZM_0_SHIFT             8  /* DSP2_PAGE_BASE_ZM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_ZM_0_WIDTH             8  /* DSP2_PAGE_BASE_ZM - [15:8] */
+
+/*
+ * R2822 (0xB06) - DSP2 Control 5
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_0_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_0_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_0_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+
+/*
+ * R2823 (0xB07) - DSP2 Control 6
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_1_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_1_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_1_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+
+/*
+ * R2824 (0xB08) - DSP2 Control 7
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_2_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_2_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_2_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+
+/*
+ * R2825 (0xB09) - DSP2 Control 8
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_3_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_3_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_3_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+
+/*
+ * R2826 (0xB0A) - DSP2 Control 9
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_4_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_4_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_4_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+
+/*
+ * R2827 (0xB0B) - DSP2 Control 10
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_5_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_5_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_5_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+
+/*
+ * R2828 (0xB0C) - DSP2 Control 11
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_6_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_6_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_6_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+
+/*
+ * R2829 (0xB0D) - DSP2 Control 12
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_7_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_7_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_7_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+
+/*
+ * R2831 (0xB0F) - DSP2 Control 13
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_0_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_0_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_0_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+
+/*
+ * R2832 (0xB10) - DSP2 Control 14
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_1_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_1_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_1_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+
+/*
+ * R2833 (0xB11) - DSP2 Control 15
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_2_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_2_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_2_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+
+/*
+ * R2834 (0xB12) - DSP2 Control 16
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_3_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_3_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_3_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+
+/*
+ * R2835 (0xB13) - DSP2 Control 17
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_4_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_4_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_4_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+
+/*
+ * R2836 (0xB14) - DSP2 Control 18
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_5_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_5_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_5_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+
+/*
+ * R2838 (0xB16) - DSP2 Control 19
+ */
+#define WM2200_DSP2_WDMA_BUFFER_LENGTH_MASK     0x00FF  /* DSP2_WDMA_BUFFER_LENGTH - [7:0] */
+#define WM2200_DSP2_WDMA_BUFFER_LENGTH_SHIFT         0  /* DSP2_WDMA_BUFFER_LENGTH - [7:0] */
+#define WM2200_DSP2_WDMA_BUFFER_LENGTH_WIDTH         8  /* DSP2_WDMA_BUFFER_LENGTH - [7:0] */
+
+/*
+ * R2839 (0xB17) - DSP2 Control 20
+ */
+#define WM2200_DSP2_WDMA_CHANNEL_ENABLE_MASK    0x00FF  /* DSP2_WDMA_CHANNEL_ENABLE - [7:0] */
+#define WM2200_DSP2_WDMA_CHANNEL_ENABLE_SHIFT        0  /* DSP2_WDMA_CHANNEL_ENABLE - [7:0] */
+#define WM2200_DSP2_WDMA_CHANNEL_ENABLE_WIDTH        8  /* DSP2_WDMA_CHANNEL_ENABLE - [7:0] */
+
+/*
+ * R2840 (0xB18) - DSP2 Control 21
+ */
+#define WM2200_DSP2_RDMA_CHANNEL_ENABLE_MASK    0x003F  /* DSP2_RDMA_CHANNEL_ENABLE - [5:0] */
+#define WM2200_DSP2_RDMA_CHANNEL_ENABLE_SHIFT        0  /* DSP2_RDMA_CHANNEL_ENABLE - [5:0] */
+#define WM2200_DSP2_RDMA_CHANNEL_ENABLE_WIDTH        6  /* DSP2_RDMA_CHANNEL_ENABLE - [5:0] */
+
+/*
+ * R2842 (0xB1A) - DSP2 Control 22
+ */
+#define WM2200_DSP2_DM_SIZE_MASK                0xFFFF  /* DSP2_DM_SIZE - [15:0] */
+#define WM2200_DSP2_DM_SIZE_SHIFT                    0  /* DSP2_DM_SIZE - [15:0] */
+#define WM2200_DSP2_DM_SIZE_WIDTH                   16  /* DSP2_DM_SIZE - [15:0] */
+
+/*
+ * R2843 (0xB1B) - DSP2 Control 23
+ */
+#define WM2200_DSP2_PM_SIZE_MASK                0xFFFF  /* DSP2_PM_SIZE - [15:0] */
+#define WM2200_DSP2_PM_SIZE_SHIFT                    0  /* DSP2_PM_SIZE - [15:0] */
+#define WM2200_DSP2_PM_SIZE_WIDTH                   16  /* DSP2_PM_SIZE - [15:0] */
+
+/*
+ * R2844 (0xB1C) - DSP2 Control 24
+ */
+#define WM2200_DSP2_ZM_SIZE_MASK                0xFFFF  /* DSP2_ZM_SIZE - [15:0] */
+#define WM2200_DSP2_ZM_SIZE_SHIFT                    0  /* DSP2_ZM_SIZE - [15:0] */
+#define WM2200_DSP2_ZM_SIZE_WIDTH                   16  /* DSP2_ZM_SIZE - [15:0] */
+
+/*
+ * R2846 (0xB1E) - DSP2 Control 25
+ */
+#define WM2200_DSP2_PING_FULL                   0x8000  /* DSP2_PING_FULL */
+#define WM2200_DSP2_PING_FULL_MASK              0x8000  /* DSP2_PING_FULL */
+#define WM2200_DSP2_PING_FULL_SHIFT                 15  /* DSP2_PING_FULL */
+#define WM2200_DSP2_PING_FULL_WIDTH                  1  /* DSP2_PING_FULL */
+#define WM2200_DSP2_PONG_FULL                   0x4000  /* DSP2_PONG_FULL */
+#define WM2200_DSP2_PONG_FULL_MASK              0x4000  /* DSP2_PONG_FULL */
+#define WM2200_DSP2_PONG_FULL_SHIFT                 14  /* DSP2_PONG_FULL */
+#define WM2200_DSP2_PONG_FULL_WIDTH                  1  /* DSP2_PONG_FULL */
+#define WM2200_DSP2_WDMA_ACTIVE_CHANNELS_MASK   0x00FF  /* DSP2_WDMA_ACTIVE_CHANNELS - [7:0] */
+#define WM2200_DSP2_WDMA_ACTIVE_CHANNELS_SHIFT       0  /* DSP2_WDMA_ACTIVE_CHANNELS - [7:0] */
+#define WM2200_DSP2_WDMA_ACTIVE_CHANNELS_WIDTH       8  /* DSP2_WDMA_ACTIVE_CHANNELS - [7:0] */
+
+/*
+ * R2848 (0xB20) - DSP2 Control 26
+ */
+#define WM2200_DSP2_SCRATCH_0_MASK              0xFFFF  /* DSP2_SCRATCH_0 - [15:0] */
+#define WM2200_DSP2_SCRATCH_0_SHIFT                  0  /* DSP2_SCRATCH_0 - [15:0] */
+#define WM2200_DSP2_SCRATCH_0_WIDTH                 16  /* DSP2_SCRATCH_0 - [15:0] */
+
+/*
+ * R2849 (0xB21) - DSP2 Control 27
+ */
+#define WM2200_DSP2_SCRATCH_1_MASK              0xFFFF  /* DSP2_SCRATCH_1 - [15:0] */
+#define WM2200_DSP2_SCRATCH_1_SHIFT                  0  /* DSP2_SCRATCH_1 - [15:0] */
+#define WM2200_DSP2_SCRATCH_1_WIDTH                 16  /* DSP2_SCRATCH_1 - [15:0] */
+
+/*
+ * R2850 (0xB22) - DSP2 Control 28
+ */
+#define WM2200_DSP2_SCRATCH_2_MASK              0xFFFF  /* DSP2_SCRATCH_2 - [15:0] */
+#define WM2200_DSP2_SCRATCH_2_SHIFT                  0  /* DSP2_SCRATCH_2 - [15:0] */
+#define WM2200_DSP2_SCRATCH_2_WIDTH                 16  /* DSP2_SCRATCH_2 - [15:0] */
+
+/*
+ * R2851 (0xB23) - DSP2 Control 29
+ */
+#define WM2200_DSP2_SCRATCH_3_MASK              0xFFFF  /* DSP2_SCRATCH_3 - [15:0] */
+#define WM2200_DSP2_SCRATCH_3_SHIFT                  0  /* DSP2_SCRATCH_3 - [15:0] */
+#define WM2200_DSP2_SCRATCH_3_WIDTH                 16  /* DSP2_SCRATCH_3 - [15:0] */
+
+/*
+ * R2852 (0xB24) - DSP2 Control 30
+ */
+#define WM2200_DSP2_DBG_CLK_ENA                 0x0008  /* DSP2_DBG_CLK_ENA */
+#define WM2200_DSP2_DBG_CLK_ENA_MASK            0x0008  /* DSP2_DBG_CLK_ENA */
+#define WM2200_DSP2_DBG_CLK_ENA_SHIFT                3  /* DSP2_DBG_CLK_ENA */
+#define WM2200_DSP2_DBG_CLK_ENA_WIDTH                1  /* DSP2_DBG_CLK_ENA */
+#define WM2200_DSP2_SYS_ENA                     0x0004  /* DSP2_SYS_ENA */
+#define WM2200_DSP2_SYS_ENA_MASK                0x0004  /* DSP2_SYS_ENA */
+#define WM2200_DSP2_SYS_ENA_SHIFT                    2  /* DSP2_SYS_ENA */
+#define WM2200_DSP2_SYS_ENA_WIDTH                    1  /* DSP2_SYS_ENA */
+#define WM2200_DSP2_CORE_ENA                    0x0002  /* DSP2_CORE_ENA */
+#define WM2200_DSP2_CORE_ENA_MASK               0x0002  /* DSP2_CORE_ENA */
+#define WM2200_DSP2_CORE_ENA_SHIFT                   1  /* DSP2_CORE_ENA */
+#define WM2200_DSP2_CORE_ENA_WIDTH                   1  /* DSP2_CORE_ENA */
+#define WM2200_DSP2_START                       0x0001  /* DSP2_START */
+#define WM2200_DSP2_START_MASK                  0x0001  /* DSP2_START */
+#define WM2200_DSP2_START_SHIFT                      0  /* DSP2_START */
+#define WM2200_DSP2_START_WIDTH                      1  /* DSP2_START */
+
+/*
+ * R2854 (0xB26) - DSP2 Control 31
+ */
+#define WM2200_DSP2_CLK_RATE_MASK               0x0018  /* DSP2_CLK_RATE - [4:3] */
+#define WM2200_DSP2_CLK_RATE_SHIFT                   3  /* DSP2_CLK_RATE - [4:3] */
+#define WM2200_DSP2_CLK_RATE_WIDTH                   2  /* DSP2_CLK_RATE - [4:3] */
+#define WM2200_DSP2_CLK_AVAIL                   0x0004  /* DSP2_CLK_AVAIL */
+#define WM2200_DSP2_CLK_AVAIL_MASK              0x0004  /* DSP2_CLK_AVAIL */
+#define WM2200_DSP2_CLK_AVAIL_SHIFT                  2  /* DSP2_CLK_AVAIL */
+#define WM2200_DSP2_CLK_AVAIL_WIDTH                  1  /* DSP2_CLK_AVAIL */
+#define WM2200_DSP2_CLK_REQ_MASK                0x0003  /* DSP2_CLK_REQ - [1:0] */
+#define WM2200_DSP2_CLK_REQ_SHIFT                    0  /* DSP2_CLK_REQ - [1:0] */
+#define WM2200_DSP2_CLK_REQ_WIDTH                    2  /* DSP2_CLK_REQ - [1:0] */
+
+#endif
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 89f2af7..b9c185c 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -18,6 +18,7 @@
 #include <linux/gcd.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
+#include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/fixed.h>
 #include <linux/slab.h>
@@ -50,13 +51,11 @@
 
 /* codec private data */
 struct wm5100_priv {
+	struct device *dev;
 	struct regmap *regmap;
 	struct snd_soc_codec *codec;
 
 	struct regulator_bulk_data core_supplies[WM5100_NUM_CORE_SUPPLIES];
-	struct regulator *cpvdd;
-	struct regulator *dbvdd2;
-	struct regulator *dbvdd3;
 
 	int rev;
 
@@ -73,6 +72,7 @@
 	bool jack_detecting;
 	bool jack_mic;
 	int jack_mode;
+	int jack_flips;
 
 	struct wm5100_fll fll[2];
 
@@ -709,6 +709,8 @@
 
 WM5100_MIXER_CONTROLS("DRC1L", WM5100_DRC1LMIX_INPUT_1_SOURCE),
 WM5100_MIXER_CONTROLS("DRC1R", WM5100_DRC1RMIX_INPUT_1_SOURCE),
+SND_SOC_BYTES_MASK("DRC", WM5100_DRC1_CTRL1, 5,
+		   WM5100_DRCL_ENA | WM5100_DRCR_ENA),
 
 WM5100_MIXER_CONTROLS("LHPF1", WM5100_HPLP1MIX_INPUT_1_SOURCE),
 WM5100_MIXER_CONTROLS("LHPF2", WM5100_HPLP2MIX_INPUT_1_SOURCE),
@@ -776,127 +778,48 @@
 	return 0;
 }
 
-static int wm5100_cp_ev(struct snd_soc_dapm_widget *w,
-			struct snd_kcontrol *kcontrol,
-			int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
-	int ret;
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		ret = regulator_enable(wm5100->cpvdd);
-		if (ret != 0) {
-			dev_err(codec->dev, "Failed to enable CPVDD: %d\n",
-				ret);
-			return ret;
-		}
-		return ret;
-
-	case SND_SOC_DAPM_POST_PMD:
-		ret = regulator_disable_deferred(wm5100->cpvdd, 20);
-		if (ret != 0) {
-			dev_err(codec->dev, "Failed to disable CPVDD: %d\n",
-				ret);
-			return ret;
-		}
-		return ret;
-
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static int wm5100_dbvdd_ev(struct snd_soc_dapm_widget *w,
-			   struct snd_kcontrol *kcontrol,
-			   int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
-	struct regulator *regulator;
-	int ret;
-
-	switch (w->shift) {
-	case 2:
-		regulator = wm5100->dbvdd2;
-		break;
-	case 3:
-		regulator = wm5100->dbvdd3;
-		break;
-	default:
-		BUG();
-		return 0;
-	}
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		ret = regulator_enable(regulator);
-		if (ret != 0) {
-			dev_err(codec->dev, "Failed to enable DBVDD%d: %d\n",
-				w->shift, ret);
-			return ret;
-		}
-		return ret;
-
-	case SND_SOC_DAPM_POST_PMD:
-		ret = regulator_disable(regulator);
-		if (ret != 0) {
-			dev_err(codec->dev, "Failed to enable DBVDD%d: %d\n",
-				w->shift, ret);
-			return ret;
-		}
-		return ret;
-
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static void wm5100_log_status3(struct snd_soc_codec *codec, int val)
+static void wm5100_log_status3(struct wm5100_priv *wm5100, int val)
 {
 	if (val & WM5100_SPK_SHUTDOWN_WARN_EINT)
-		dev_crit(codec->dev, "Speaker shutdown warning\n");
+		dev_crit(wm5100->dev, "Speaker shutdown warning\n");
 	if (val & WM5100_SPK_SHUTDOWN_EINT)
-		dev_crit(codec->dev, "Speaker shutdown\n");
+		dev_crit(wm5100->dev, "Speaker shutdown\n");
 	if (val & WM5100_CLKGEN_ERR_EINT)
-		dev_crit(codec->dev, "SYSCLK underclocked\n");
+		dev_crit(wm5100->dev, "SYSCLK underclocked\n");
 	if (val & WM5100_CLKGEN_ERR_ASYNC_EINT)
-		dev_crit(codec->dev, "ASYNCCLK underclocked\n");
+		dev_crit(wm5100->dev, "ASYNCCLK underclocked\n");
 }
 
-static void wm5100_log_status4(struct snd_soc_codec *codec, int val)
+static void wm5100_log_status4(struct wm5100_priv *wm5100, int val)
 {
 	if (val & WM5100_AIF3_ERR_EINT)
-		dev_err(codec->dev, "AIF3 configuration error\n");
+		dev_err(wm5100->dev, "AIF3 configuration error\n");
 	if (val & WM5100_AIF2_ERR_EINT)
-		dev_err(codec->dev, "AIF2 configuration error\n");
+		dev_err(wm5100->dev, "AIF2 configuration error\n");
 	if (val & WM5100_AIF1_ERR_EINT)
-		dev_err(codec->dev, "AIF1 configuration error\n");
+		dev_err(wm5100->dev, "AIF1 configuration error\n");
 	if (val & WM5100_CTRLIF_ERR_EINT)
-		dev_err(codec->dev, "Control interface error\n");
+		dev_err(wm5100->dev, "Control interface error\n");
 	if (val & WM5100_ISRC2_UNDERCLOCKED_EINT)
-		dev_err(codec->dev, "ISRC2 underclocked\n");
+		dev_err(wm5100->dev, "ISRC2 underclocked\n");
 	if (val & WM5100_ISRC1_UNDERCLOCKED_EINT)
-		dev_err(codec->dev, "ISRC1 underclocked\n");
+		dev_err(wm5100->dev, "ISRC1 underclocked\n");
 	if (val & WM5100_FX_UNDERCLOCKED_EINT)
-		dev_err(codec->dev, "FX underclocked\n");
+		dev_err(wm5100->dev, "FX underclocked\n");
 	if (val & WM5100_AIF3_UNDERCLOCKED_EINT)
-		dev_err(codec->dev, "AIF3 underclocked\n");
+		dev_err(wm5100->dev, "AIF3 underclocked\n");
 	if (val & WM5100_AIF2_UNDERCLOCKED_EINT)
-		dev_err(codec->dev, "AIF2 underclocked\n");
+		dev_err(wm5100->dev, "AIF2 underclocked\n");
 	if (val & WM5100_AIF1_UNDERCLOCKED_EINT)
-		dev_err(codec->dev, "AIF1 underclocked\n");
+		dev_err(wm5100->dev, "AIF1 underclocked\n");
 	if (val & WM5100_ASRC_UNDERCLOCKED_EINT)
-		dev_err(codec->dev, "ASRC underclocked\n");
+		dev_err(wm5100->dev, "ASRC underclocked\n");
 	if (val & WM5100_DAC_UNDERCLOCKED_EINT)
-		dev_err(codec->dev, "DAC underclocked\n");
+		dev_err(wm5100->dev, "DAC underclocked\n");
 	if (val & WM5100_ADC_UNDERCLOCKED_EINT)
-		dev_err(codec->dev, "ADC underclocked\n");
+		dev_err(wm5100->dev, "ADC underclocked\n");
 	if (val & WM5100_MIXER_UNDERCLOCKED_EINT)
-		dev_err(codec->dev, "Mixer underclocked\n");
+		dev_err(wm5100->dev, "Mixer underclocked\n");
 }
 
 static int wm5100_post_ev(struct snd_soc_dapm_widget *w,
@@ -904,16 +827,17 @@
 			  int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 
 	ret = snd_soc_read(codec, WM5100_INTERRUPT_RAW_STATUS_3);
 	ret &= WM5100_SPK_SHUTDOWN_WARN_STS |
 		WM5100_SPK_SHUTDOWN_STS | WM5100_CLKGEN_ERR_STS |
 		WM5100_CLKGEN_ERR_ASYNC_STS;
-	wm5100_log_status3(codec, ret);
+	wm5100_log_status3(wm5100, ret);
 
 	ret = snd_soc_read(codec, WM5100_INTERRUPT_RAW_STATUS_4);
-	wm5100_log_status4(codec, ret);
+	wm5100_log_status4(wm5100, ret);
 
 	return 0;
 }
@@ -924,18 +848,16 @@
 SND_SOC_DAPM_SUPPLY("ASYNCCLK", WM5100_CLOCKING_6, WM5100_ASYNC_CLK_ENA_SHIFT,
 		    0, NULL, 0),
 
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20),
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0),
+
 SND_SOC_DAPM_SUPPLY("CP1", WM5100_HP_CHARGE_PUMP_1, WM5100_CP1_ENA_SHIFT, 0,
-		    wm5100_cp_ev,
-		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+		    NULL, 0),
 SND_SOC_DAPM_SUPPLY("CP2", WM5100_MIC_CHARGE_PUMP_1, WM5100_CP2_ENA_SHIFT, 0,
 		    NULL, 0),
 SND_SOC_DAPM_SUPPLY("CP2 Active", WM5100_MIC_CHARGE_PUMP_1,
-		    WM5100_CP2_BYPASS_SHIFT, 1, wm5100_cp_ev,
-		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-SND_SOC_DAPM_SUPPLY("DBVDD2", SND_SOC_NOPM, 2, 0, wm5100_dbvdd_ev,
-		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-SND_SOC_DAPM_SUPPLY("DBVDD3", SND_SOC_NOPM, 3, 0, wm5100_dbvdd_ev,
-		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+		    WM5100_CP2_BYPASS_SHIFT, 1, NULL, 0),
 
 SND_SOC_DAPM_SUPPLY("MICBIAS1", WM5100_MIC_BIAS_CTRL_1, WM5100_MICB1_ENA_SHIFT,
 		    0, NULL, 0),
@@ -1146,6 +1068,9 @@
 };
 
 static const struct snd_soc_dapm_route wm5100_dapm_routes[] = {
+	{ "CP1", NULL, "CPVDD" },
+	{ "CP2 Active", NULL, "CPVDD" },
+
 	{ "IN1L", NULL, "SYSCLK" },
 	{ "IN1R", NULL, "SYSCLK" },
 	{ "IN2L", NULL, "SYSCLK" },
@@ -1308,10 +1233,7 @@
 	{ "PWM2", NULL, "PWM2 Driver" },
 };
 
-static struct {
-	int reg;
-	int val;
-} wm5100_reva_patches[] = {
+static const __devinitdata struct reg_default wm5100_reva_patches[] = {
 	{ WM5100_AUDIO_IF_1_10, 0 },
 	{ WM5100_AUDIO_IF_1_11, 1 },
 	{ WM5100_AUDIO_IF_1_12, 2 },
@@ -1343,80 +1265,6 @@
 	{ WM5100_AUDIO_IF_3_19, 1 },
 };
 
-static int wm5100_set_bias_level(struct snd_soc_codec *codec,
-				 enum snd_soc_bias_level level)
-{
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
-	int ret, i;
-
-	switch (level) {
-	case SND_SOC_BIAS_ON:
-		break;
-
-	case SND_SOC_BIAS_PREPARE:
-		break;
-
-	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-			ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
-						    wm5100->core_supplies);
-			if (ret != 0) {
-				dev_err(codec->dev,
-					"Failed to enable supplies: %d\n",
-					ret);
-				return ret;
-			}
-
-			if (wm5100->pdata.ldo_ena) {
-				gpio_set_value_cansleep(wm5100->pdata.ldo_ena,
-							1);
-				msleep(2);
-			}
-
-			regcache_cache_only(wm5100->regmap, false);
-
-			switch (wm5100->rev) {
-			case 0:
-				regcache_cache_bypass(wm5100->regmap, true);
-				snd_soc_write(codec, 0x11, 0x3);
-				snd_soc_write(codec, 0x203, 0xc);
-				snd_soc_write(codec, 0x206, 0);
-				snd_soc_write(codec, 0x207, 0xf0);
-				snd_soc_write(codec, 0x208, 0x3c);
-				snd_soc_write(codec, 0x209, 0);
-				snd_soc_write(codec, 0x211, 0x20d8);
-				snd_soc_write(codec, 0x11, 0);
-
-				for (i = 0;
-				     i < ARRAY_SIZE(wm5100_reva_patches);
-				     i++)
-					snd_soc_write(codec,
-						      wm5100_reva_patches[i].reg,
-						      wm5100_reva_patches[i].val);
-				regcache_cache_bypass(wm5100->regmap, false);
-				break;
-			default:
-				break;
-			}
-
-			regcache_sync(wm5100->regmap);
-		}
-		break;
-
-	case SND_SOC_BIAS_OFF:
-		regcache_cache_only(wm5100->regmap, true);
-		regcache_mark_dirty(wm5100->regmap);
-		if (wm5100->pdata.ldo_ena)
-			gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
-		regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
-				       wm5100->core_supplies);
-		break;
-	}
-	codec->dapm.bias_level = level;
-
-	return 0;
-}
-
 static int wm5100_dai_to_base(struct snd_soc_dai *dai)
 {
 	switch (dai->id) {
@@ -1944,6 +1792,8 @@
 
 	if (!Fout) {
 		dev_dbg(codec->dev, "FLL%d disabled", fll_id);
+		if (fll->fout)
+			pm_runtime_put(codec->dev);
 		fll->fout = 0;
 		snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, 0);
 		return 0;
@@ -1988,6 +1838,8 @@
 	/* Clear any pending completions */
 	try_wait_for_completion(&fll->lock);
 
+	pm_runtime_get_sync(codec->dev);
+
 	snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, WM5100_FLL1_ENA);
 
 	if (i2c->irq)
@@ -2022,6 +1874,7 @@
 	}
 	if (i == timeout) {
 		dev_err(codec->dev, "FLL%d lock timed out\n", fll_id);
+		pm_runtime_put(codec->dev);
 		return -ETIMEDOUT;
 	}
 
@@ -2124,55 +1977,73 @@
 	WM5100_DAC_DIGITAL_VOLUME_6R,
 };
 
-static void wm5100_set_detect_mode(struct snd_soc_codec *codec, int the_mode)
+static void wm5100_set_detect_mode(struct wm5100_priv *wm5100, int the_mode)
 {
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
 	struct wm5100_jack_mode *mode = &wm5100->pdata.jack_modes[the_mode];
 
 	BUG_ON(the_mode >= ARRAY_SIZE(wm5100->pdata.jack_modes));
 
 	gpio_set_value_cansleep(wm5100->pdata.hp_pol, mode->hp_pol);
-	snd_soc_update_bits(codec, WM5100_ACCESSORY_DETECT_MODE_1,
-			    WM5100_ACCDET_BIAS_SRC_MASK |
-			    WM5100_ACCDET_SRC,
-			    (mode->bias << WM5100_ACCDET_BIAS_SRC_SHIFT) |
-			    mode->micd_src << WM5100_ACCDET_SRC_SHIFT);
-	snd_soc_update_bits(codec, WM5100_MISC_CONTROL,
-			    WM5100_HPCOM_SRC,
-			    mode->micd_src << WM5100_HPCOM_SRC_SHIFT);
+	regmap_update_bits(wm5100->regmap, WM5100_ACCESSORY_DETECT_MODE_1,
+			   WM5100_ACCDET_BIAS_SRC_MASK |
+			   WM5100_ACCDET_SRC,
+			   (mode->bias << WM5100_ACCDET_BIAS_SRC_SHIFT) |
+			   mode->micd_src << WM5100_ACCDET_SRC_SHIFT);
+	regmap_update_bits(wm5100->regmap, WM5100_MISC_CONTROL,
+			   WM5100_HPCOM_SRC,
+			   mode->micd_src << WM5100_HPCOM_SRC_SHIFT);
 
 	wm5100->jack_mode = the_mode;
 
-	dev_dbg(codec->dev, "Set microphone polarity to %d\n",
+	dev_dbg(wm5100->dev, "Set microphone polarity to %d\n",
 		wm5100->jack_mode);
 }
 
-static void wm5100_micd_irq(struct snd_soc_codec *codec)
+static void wm5100_report_headphone(struct wm5100_priv *wm5100)
 {
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
-	int val;
+	dev_dbg(wm5100->dev, "Headphone detected\n");
+	wm5100->jack_detecting = false;
+	snd_soc_jack_report(wm5100->jack, SND_JACK_HEADPHONE,
+			    SND_JACK_HEADPHONE);
 
-	val = snd_soc_read(codec, WM5100_MIC_DETECT_3);
+	/* Increase the detection rate a bit for responsiveness. */
+	regmap_update_bits(wm5100->regmap, WM5100_MIC_DETECT_1,
+			   WM5100_ACCDET_RATE_MASK,
+			   7 << WM5100_ACCDET_RATE_SHIFT);
+}
 
-	dev_dbg(codec->dev, "Microphone event: %x\n", val);
+static void wm5100_micd_irq(struct wm5100_priv *wm5100)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(wm5100->regmap, WM5100_MIC_DETECT_3, &val);
+	if (ret != 0) {
+		dev_err(wm5100->dev, "Failed to read micropone status: %d\n",
+			ret);
+		return;
+	}
+
+	dev_dbg(wm5100->dev, "Microphone event: %x\n", val);
 
 	if (!(val & WM5100_ACCDET_VALID)) {
-		dev_warn(codec->dev, "Microphone detection state invalid\n");
+		dev_warn(wm5100->dev, "Microphone detection state invalid\n");
 		return;
 	}
 
 	/* No accessory, reset everything and report removal */
 	if (!(val & WM5100_ACCDET_STS)) {
-		dev_dbg(codec->dev, "Jack removal detected\n");
+		dev_dbg(wm5100->dev, "Jack removal detected\n");
 		wm5100->jack_mic = false;
 		wm5100->jack_detecting = true;
+		wm5100->jack_flips = 0;
 		snd_soc_jack_report(wm5100->jack, 0,
 				    SND_JACK_LINEOUT | SND_JACK_HEADSET |
 				    SND_JACK_BTN_0);
 
-		snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
-				    WM5100_ACCDET_RATE_MASK,
-				    WM5100_ACCDET_RATE_MASK);
+		regmap_update_bits(wm5100->regmap, WM5100_MIC_DETECT_1,
+				   WM5100_ACCDET_RATE_MASK,
+				   WM5100_ACCDET_RATE_MASK);
 		return;
 	}
 
@@ -2182,7 +2053,7 @@
 	 */
 	if (val & 0x400) {
 		if (wm5100->jack_detecting) {
-			dev_dbg(codec->dev, "Microphone detected\n");
+			dev_dbg(wm5100->dev, "Microphone detected\n");
 			wm5100->jack_mic = true;
 			wm5100->jack_detecting = false;
 			snd_soc_jack_report(wm5100->jack,
@@ -2191,11 +2062,11 @@
 
 			/* Increase poll rate to give better responsiveness
 			 * for buttons */
-			snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
-					    WM5100_ACCDET_RATE_MASK,
-					    5 << WM5100_ACCDET_RATE_SHIFT);
+			regmap_update_bits(wm5100->regmap, WM5100_MIC_DETECT_1,
+					   WM5100_ACCDET_RATE_MASK,
+					   5 << WM5100_ACCDET_RATE_SHIFT);
 		} else {
-			dev_dbg(codec->dev, "Mic button up\n");
+			dev_dbg(wm5100->dev, "Mic button up\n");
 			snd_soc_jack_report(wm5100->jack, 0, SND_JACK_BTN_0);
 		}
 
@@ -2205,10 +2076,16 @@
 	/* If we detected a lower impedence during initial startup
 	 * then we probably have the wrong polarity, flip it.  Don't
 	 * do this for the lowest impedences to speed up detection of
-	 * plain headphones.
+	 * plain headphones and give up if neither polarity looks
+	 * sensible.
 	 */
 	if (wm5100->jack_detecting && (val & 0x3f8)) {
-		wm5100_set_detect_mode(codec, !wm5100->jack_mode);
+		wm5100->jack_flips++;
+
+		if (wm5100->jack_flips > 1)
+			wm5100_report_headphone(wm5100);
+		else
+			wm5100_set_detect_mode(wm5100, !wm5100->jack_mode);
 
 		return;
 	}
@@ -2218,21 +2095,11 @@
 	 */
 	if (val & 0x3fc) {
 		if (wm5100->jack_mic) {
-			dev_dbg(codec->dev, "Mic button detected\n");
+			dev_dbg(wm5100->dev, "Mic button detected\n");
 			snd_soc_jack_report(wm5100->jack, SND_JACK_BTN_0,
 					    SND_JACK_BTN_0);
 		} else if (wm5100->jack_detecting) {
-			dev_dbg(codec->dev, "Headphone detected\n");
-			wm5100->jack_detecting = false;
-			snd_soc_jack_report(wm5100->jack, SND_JACK_HEADPHONE,
-					    SND_JACK_HEADPHONE);
-
-			/* Increase the detection rate a bit for
-			 * responsiveness.
-			 */
-			snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
-					    WM5100_ACCDET_RATE_MASK,
-					    7 << WM5100_ACCDET_RATE_SHIFT);
+			wm5100_report_headphone(wm5100);
 		}
 	}
 }
@@ -2244,8 +2111,9 @@
 	if (jack) {
 		wm5100->jack = jack;
 		wm5100->jack_detecting = true;
+		wm5100->jack_flips = 0;
 
-		wm5100_set_detect_mode(codec, 0);
+		wm5100_set_detect_mode(wm5100, 0);
 
 		/* Slowest detection rate, gives debounce for initial
 		 * detection */
@@ -2284,52 +2152,70 @@
 
 static irqreturn_t wm5100_irq(int irq, void *data)
 {
-	struct snd_soc_codec *codec = data;
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+	struct wm5100_priv *wm5100 = data;
 	irqreturn_t status = IRQ_NONE;
-	int irq_val;
+	unsigned int irq_val, mask_val;
+	int ret;
 
-	irq_val = snd_soc_read(codec, WM5100_INTERRUPT_STATUS_3);
-	if (irq_val < 0) {
-		dev_err(codec->dev, "Failed to read IRQ status 3: %d\n",
-			irq_val);
+	ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_3, &irq_val);
+	if (ret < 0) {
+		dev_err(wm5100->dev, "Failed to read IRQ status 3: %d\n",
+			ret);
 		irq_val = 0;
 	}
-	irq_val &= ~snd_soc_read(codec, WM5100_INTERRUPT_STATUS_3_MASK);
 
-	snd_soc_write(codec, WM5100_INTERRUPT_STATUS_3, irq_val);
+	ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_3_MASK,
+			  &mask_val);
+	if (ret < 0) {
+		dev_err(wm5100->dev, "Failed to read IRQ mask 3: %d\n",
+			ret);
+		mask_val = 0xffff;
+	}
+
+	irq_val &= ~mask_val;
+
+	regmap_write(wm5100->regmap, WM5100_INTERRUPT_STATUS_3, irq_val);
 
 	if (irq_val)
 		status = IRQ_HANDLED;
 
-	wm5100_log_status3(codec, irq_val);
+	wm5100_log_status3(wm5100, irq_val);
 
 	if (irq_val & WM5100_FLL1_LOCK_EINT) {
-		dev_dbg(codec->dev, "FLL1 locked\n");
+		dev_dbg(wm5100->dev, "FLL1 locked\n");
 		complete(&wm5100->fll[0].lock);
 	}
 	if (irq_val & WM5100_FLL2_LOCK_EINT) {
-		dev_dbg(codec->dev, "FLL2 locked\n");
+		dev_dbg(wm5100->dev, "FLL2 locked\n");
 		complete(&wm5100->fll[1].lock);
 	}
 
 	if (irq_val & WM5100_ACCDET_EINT)
-		wm5100_micd_irq(codec);
+		wm5100_micd_irq(wm5100);
 
-	irq_val = snd_soc_read(codec, WM5100_INTERRUPT_STATUS_4);
-	if (irq_val < 0) {
-		dev_err(codec->dev, "Failed to read IRQ status 4: %d\n",
-			irq_val);
+	ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_4, &irq_val);
+	if (ret < 0) {
+		dev_err(wm5100->dev, "Failed to read IRQ status 4: %d\n",
+			ret);
 		irq_val = 0;
 	}
-	irq_val &= ~snd_soc_read(codec, WM5100_INTERRUPT_STATUS_4_MASK);
+
+	ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_4_MASK,
+			  &mask_val);
+	if (ret < 0) {
+		dev_err(wm5100->dev, "Failed to read IRQ mask 4: %d\n",
+			ret);
+		mask_val = 0xffff;
+	}
+
+	irq_val &= ~mask_val;
 
 	if (irq_val)
 		status = IRQ_HANDLED;
 
-	snd_soc_write(codec, WM5100_INTERRUPT_STATUS_4, irq_val);
+	regmap_write(wm5100->regmap, WM5100_INTERRUPT_STATUS_4, irq_val);
 
-	wm5100_log_status4(codec, irq_val);
+	wm5100_log_status4(wm5100, irq_val);
 
 	return status;
 }
@@ -2454,7 +2340,7 @@
 {
 	struct i2c_client *i2c = to_i2c_client(codec->dev);
 	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
-	int ret, i, irq_flags;
+	int ret, i;
 
 	wm5100->codec = codec;
 	codec->control_data = wm5100->regmap;
@@ -2465,9 +2351,6 @@
 		return ret;
 	}
 
-	regcache_cache_only(wm5100->regmap, true);
-
-
 	for (i = 0; i < ARRAY_SIZE(wm5100_dig_vu); i++)
 		snd_soc_update_bits(codec, wm5100_dig_vu[i], WM5100_OUT_VU,
 				    WM5100_OUT_VU);
@@ -2478,60 +2361,10 @@
 
 	/* TODO: check if we're symmetric */
 
-	if (i2c->irq) {
-		if (wm5100->pdata.irq_flags)
-			irq_flags = wm5100->pdata.irq_flags;
-		else
-			irq_flags = IRQF_TRIGGER_LOW;
-
-		irq_flags |= IRQF_ONESHOT;
-
-		if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
-			ret = request_threaded_irq(i2c->irq, NULL,
-						   wm5100_edge_irq,
-						   irq_flags, "wm5100", codec);
-		else
-			ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq,
-						   irq_flags, "wm5100", codec);
-
-		if (ret != 0) {
-			dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
-				i2c->irq, ret);
-		} else {
-			/* Enable default interrupts */
-			snd_soc_update_bits(codec,
-					    WM5100_INTERRUPT_STATUS_3_MASK,
-					    WM5100_IM_SPK_SHUTDOWN_WARN_EINT |
-					    WM5100_IM_SPK_SHUTDOWN_EINT |
-					    WM5100_IM_ASRC2_LOCK_EINT |
-					    WM5100_IM_ASRC1_LOCK_EINT |
-					    WM5100_IM_FLL2_LOCK_EINT |
-					    WM5100_IM_FLL1_LOCK_EINT |
-					    WM5100_CLKGEN_ERR_EINT |
-					    WM5100_CLKGEN_ERR_ASYNC_EINT, 0);
-
-			snd_soc_update_bits(codec,
-					    WM5100_INTERRUPT_STATUS_4_MASK,
-					    WM5100_AIF3_ERR_EINT |
-					    WM5100_AIF2_ERR_EINT |
-					    WM5100_AIF1_ERR_EINT |
-					    WM5100_CTRLIF_ERR_EINT |
-					    WM5100_ISRC2_UNDERCLOCKED_EINT |
-					    WM5100_ISRC1_UNDERCLOCKED_EINT |
-					    WM5100_FX_UNDERCLOCKED_EINT |
-					    WM5100_AIF3_UNDERCLOCKED_EINT |
-					    WM5100_AIF2_UNDERCLOCKED_EINT |
-					    WM5100_AIF1_UNDERCLOCKED_EINT |
-					    WM5100_ASRC_UNDERCLOCKED_EINT |
-					    WM5100_DAC_UNDERCLOCKED_EINT |
-					    WM5100_ADC_UNDERCLOCKED_EINT |
-					    WM5100_MIXER_UNDERCLOCKED_EINT, 0);
-		}
-	} else {
+	if (i2c->irq)
 		snd_soc_dapm_new_controls(&codec->dapm,
 					  wm5100_dapm_widgets_noirq,
 					  ARRAY_SIZE(wm5100_dapm_widgets_noirq));
-	}
 
 	if (wm5100->pdata.hp_pol) {
 		ret = gpio_request_one(wm5100->pdata.hp_pol,
@@ -2543,19 +2376,9 @@
 		}
 	}
 
-	/* We'll get woken up again when the system has something useful
-	 * for us to do.
-	 */
-	if (wm5100->pdata.ldo_ena)
-		gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
-	regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
-			       wm5100->core_supplies);
-
 	return 0;
 
 err_gpio:
-	if (i2c->irq)
-		free_irq(i2c->irq, codec);
 
 	return ret;
 }
@@ -2563,14 +2386,11 @@
 static int wm5100_remove(struct snd_soc_codec *codec)
 {
 	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
-	struct i2c_client *i2c = to_i2c_client(codec->dev);
 
-	wm5100_set_bias_level(codec, SND_SOC_BIAS_OFF);
 	if (wm5100->pdata.hp_pol) {
 		gpio_free(wm5100->pdata.hp_pol);
 	}
-	if (i2c->irq)
-		free_irq(i2c->irq, codec);
+
 	return 0;
 }
 
@@ -2587,7 +2407,6 @@
 
 	.set_sysclk = wm5100_set_sysclk,
 	.set_pll = wm5100_set_fll,
-	.set_bias_level = wm5100_set_bias_level,
 	.idle_bias_off = 1,
 	.reg_cache_size = WM5100_MAX_REGISTER,
 	.volatile_register = wm5100_soc_volatile,
@@ -2626,13 +2445,15 @@
 	struct wm5100_pdata *pdata = dev_get_platdata(&i2c->dev);
 	struct wm5100_priv *wm5100;
 	unsigned int reg;
-	int ret, i;
+	int ret, i, irq_flags;
 
 	wm5100 = devm_kzalloc(&i2c->dev, sizeof(struct wm5100_priv),
 			      GFP_KERNEL);
 	if (wm5100 == NULL)
 		return -ENOMEM;
 
+	wm5100->dev = &i2c->dev;
+
 	wm5100->regmap = regmap_init_i2c(i2c, &wm5100_regmap);
 	if (IS_ERR(wm5100->regmap)) {
 		ret = PTR_ERR(wm5100->regmap);
@@ -2652,41 +2473,21 @@
 	for (i = 0; i < ARRAY_SIZE(wm5100->core_supplies); i++)
 		wm5100->core_supplies[i].supply = wm5100_core_supply_names[i];
 
-	ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm5100->core_supplies),
-				 wm5100->core_supplies);
+	ret = devm_regulator_bulk_get(&i2c->dev,
+				      ARRAY_SIZE(wm5100->core_supplies),
+				      wm5100->core_supplies);
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to request core supplies: %d\n",
 			ret);
 		goto err_regmap;
 	}
 
-	wm5100->cpvdd = regulator_get(&i2c->dev, "CPVDD");
-	if (IS_ERR(wm5100->cpvdd)) {
-		ret = PTR_ERR(wm5100->cpvdd);
-		dev_err(&i2c->dev, "Failed to get CPVDD: %d\n", ret);
-		goto err_core;
-	}
-
-	wm5100->dbvdd2 = regulator_get(&i2c->dev, "DBVDD2");
-	if (IS_ERR(wm5100->dbvdd2)) {
-		ret = PTR_ERR(wm5100->dbvdd2);
-		dev_err(&i2c->dev, "Failed to get DBVDD2: %d\n", ret);
-		goto err_cpvdd;
-	}
-
-	wm5100->dbvdd3 = regulator_get(&i2c->dev, "DBVDD3");
-	if (IS_ERR(wm5100->dbvdd3)) {
-		ret = PTR_ERR(wm5100->dbvdd3);
-		dev_err(&i2c->dev, "Failed to get DBVDD2: %d\n", ret);
-		goto err_dbvdd2;
-	}
-
 	ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
 				    wm5100->core_supplies);
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to enable core supplies: %d\n",
 			ret);
-		goto err_dbvdd3;
+		goto err_regmap;
 	}
 
 	if (wm5100->pdata.ldo_ena) {
@@ -2712,7 +2513,7 @@
 
 	ret = regmap_read(wm5100->regmap, WM5100_SOFTWARE_RESET, &reg);
 	if (ret < 0) {
-		dev_err(&i2c->dev, "Failed to read ID register\n");
+		dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
 		goto err_reset;
 	}
 	switch (reg) {
@@ -2741,6 +2542,22 @@
 		goto err_reset;
 	}
 
+	switch (wm5100->rev) {
+	case 0:
+		ret = regmap_register_patch(wm5100->regmap,
+					    wm5100_reva_patches,
+					    ARRAY_SIZE(wm5100_reva_patches));
+		if (ret != 0) {
+			dev_err(&i2c->dev, "Failed to register patches: %d\n",
+				ret);
+			goto err_reset;
+		}
+		break;
+	default:
+		break;
+	}
+
+
 	wm5100_init_gpio(i2c);
 
 	for (i = 0; i < ARRAY_SIZE(wm5100->pdata.gpio_defaults); i++) {
@@ -2761,6 +2578,62 @@
 				    WM5100_IN1_DMIC_SUP_SHIFT));
 	}
 
+	if (i2c->irq) {
+		if (wm5100->pdata.irq_flags)
+			irq_flags = wm5100->pdata.irq_flags;
+		else
+			irq_flags = IRQF_TRIGGER_LOW;
+
+		irq_flags |= IRQF_ONESHOT;
+
+		if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+			ret = request_threaded_irq(i2c->irq, NULL,
+						   wm5100_edge_irq, irq_flags,
+						   "wm5100", wm5100);
+		else
+			ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq,
+						   irq_flags, "wm5100",
+						   wm5100);
+
+		if (ret != 0) {
+			dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
+				i2c->irq, ret);
+		} else {
+			/* Enable default interrupts */
+			regmap_update_bits(wm5100->regmap,
+					   WM5100_INTERRUPT_STATUS_3_MASK,
+					   WM5100_IM_SPK_SHUTDOWN_WARN_EINT |
+					   WM5100_IM_SPK_SHUTDOWN_EINT |
+					   WM5100_IM_ASRC2_LOCK_EINT |
+					   WM5100_IM_ASRC1_LOCK_EINT |
+					   WM5100_IM_FLL2_LOCK_EINT |
+					   WM5100_IM_FLL1_LOCK_EINT |
+					   WM5100_CLKGEN_ERR_EINT |
+					   WM5100_CLKGEN_ERR_ASYNC_EINT, 0);
+
+			regmap_update_bits(wm5100->regmap,
+					   WM5100_INTERRUPT_STATUS_4_MASK,
+					   WM5100_AIF3_ERR_EINT |
+					   WM5100_AIF2_ERR_EINT |
+					   WM5100_AIF1_ERR_EINT |
+					   WM5100_CTRLIF_ERR_EINT |
+					   WM5100_ISRC2_UNDERCLOCKED_EINT |
+					   WM5100_ISRC1_UNDERCLOCKED_EINT |
+					   WM5100_FX_UNDERCLOCKED_EINT |
+					   WM5100_AIF3_UNDERCLOCKED_EINT |
+					   WM5100_AIF2_UNDERCLOCKED_EINT |
+					   WM5100_AIF1_UNDERCLOCKED_EINT |
+					   WM5100_ASRC_UNDERCLOCKED_EINT |
+					   WM5100_DAC_UNDERCLOCKED_EINT |
+					   WM5100_ADC_UNDERCLOCKED_EINT |
+					   WM5100_MIXER_UNDERCLOCKED_EINT, 0);
+		}
+	}
+
+	pm_runtime_set_active(&i2c->dev);
+	pm_runtime_enable(&i2c->dev);
+	pm_request_idle(&i2c->dev);
+
 	ret = snd_soc_register_codec(&i2c->dev,
 				     &soc_codec_dev_wm5100, wm5100_dai,
 				     ARRAY_SIZE(wm5100_dai));
@@ -2772,9 +2645,11 @@
 	return ret;
 
 err_reset:
+	if (i2c->irq)
+		free_irq(i2c->irq, wm5100);
 	wm5100_free_gpio(i2c);
 	if (wm5100->pdata.reset) {
-		gpio_set_value_cansleep(wm5100->pdata.reset, 1);
+		gpio_set_value_cansleep(wm5100->pdata.reset, 0);
 		gpio_free(wm5100->pdata.reset);
 	}
 err_ldo:
@@ -2785,45 +2660,78 @@
 err_enable:
 	regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
 			       wm5100->core_supplies);
-err_dbvdd3:
-	regulator_put(wm5100->dbvdd3);
-err_dbvdd2:
-	regulator_put(wm5100->dbvdd2);
-err_cpvdd:
-	regulator_put(wm5100->cpvdd);
-err_core:
-	regulator_bulk_free(ARRAY_SIZE(wm5100->core_supplies),
-			    wm5100->core_supplies);
 err_regmap:
 	regmap_exit(wm5100->regmap);
 err:
 	return ret;
 }
 
-static __devexit int wm5100_i2c_remove(struct i2c_client *client)
+static __devexit int wm5100_i2c_remove(struct i2c_client *i2c)
 {
-	struct wm5100_priv *wm5100 = i2c_get_clientdata(client);
+	struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
 
-	snd_soc_unregister_codec(&client->dev);
-	wm5100_free_gpio(client);
+	snd_soc_unregister_codec(&i2c->dev);
+	if (i2c->irq)
+		free_irq(i2c->irq, wm5100);
+	wm5100_free_gpio(i2c);
 	if (wm5100->pdata.reset) {
-		gpio_set_value_cansleep(wm5100->pdata.reset, 1);
+		gpio_set_value_cansleep(wm5100->pdata.reset, 0);
 		gpio_free(wm5100->pdata.reset);
 	}
 	if (wm5100->pdata.ldo_ena) {
 		gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
 		gpio_free(wm5100->pdata.ldo_ena);
 	}
-	regulator_put(wm5100->dbvdd3);
-	regulator_put(wm5100->dbvdd2);
-	regulator_put(wm5100->cpvdd);
-	regulator_bulk_free(ARRAY_SIZE(wm5100->core_supplies),
-			    wm5100->core_supplies);
 	regmap_exit(wm5100->regmap);
 
 	return 0;
 }
 
+#ifdef CONFIG_PM_RUNTIME
+static int wm5100_runtime_suspend(struct device *dev)
+{
+	struct wm5100_priv *wm5100 = dev_get_drvdata(dev);
+
+	regcache_cache_only(wm5100->regmap, true);
+	regcache_mark_dirty(wm5100->regmap);
+	if (wm5100->pdata.ldo_ena)
+		gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
+	regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
+			       wm5100->core_supplies);
+
+	return 0;
+}
+
+static int wm5100_runtime_resume(struct device *dev)
+{
+	struct wm5100_priv *wm5100 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
+				    wm5100->core_supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	if (wm5100->pdata.ldo_ena) {
+		gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 1);
+		msleep(2);
+	}
+
+	regcache_cache_only(wm5100->regmap, false);
+	regcache_sync(wm5100->regmap);
+
+	return 0;
+}
+#endif
+
+static struct dev_pm_ops wm5100_pm = {
+	SET_RUNTIME_PM_OPS(wm5100_runtime_suspend, wm5100_runtime_resume,
+			   NULL)
+};
+
 static const struct i2c_device_id wm5100_i2c_id[] = {
 	{ "wm5100", 0 },
 	{ }
@@ -2834,6 +2742,7 @@
 	.driver = {
 		.name = "wm5100",
 		.owner = THIS_MODULE,
+		.pm = &wm5100_pm,
 	},
 	.probe =    wm5100_i2c_probe,
 	.remove =   __devexit_p(wm5100_i2c_remove),
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 8821af7..a32caa7 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -19,6 +19,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 #include <linux/of_device.h>
@@ -41,7 +42,7 @@
 
 /* codec private data */
 struct wm8731_priv {
-	enum snd_soc_control_type control_type;
+	struct regmap *regmap;
 	struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
 	unsigned int sysclk;
 	int sysclk_type;
@@ -52,16 +53,30 @@
 
 /*
  * wm8731 register cache
- * We can't read the WM8731 register space when we are
- * using 2 wire for device control, so we cache them instead.
- * There is no point in caching the reset register
  */
-static const u16 wm8731_reg[WM8731_CACHEREGNUM] = {
-	0x0097, 0x0097, 0x0079, 0x0079,
-	0x000a, 0x0008, 0x009f, 0x000a,
-	0x0000, 0x0000
+static const struct reg_default wm8731_reg_defaults[] = {
+	{ 0, 0x0097 },
+	{ 1, 0x0097 },
+	{ 2, 0x0079 },
+	{ 3, 0x0079 },
+	{ 4, 0x000a },
+	{ 5, 0x0008 },
+	{ 6, 0x009f },
+	{ 7, 0x000a },
+	{ 8, 0x0000 },
+	{ 9, 0x0000 },
 };
 
+static bool wm8731_volatile(struct device *dev, unsigned int reg)
+{
+	return reg == WM8731_RESET;
+}
+
+static bool wm8731_writeable(struct device *dev, unsigned int reg)
+{
+	return reg <= WM8731_RESET;
+}
+
 #define wm8731_reset(c)	snd_soc_write(c, WM8731_RESET, 0)
 
 static const char *wm8731_input_select[] = {"Line In", "Mic"};
@@ -441,7 +456,7 @@
 			if (ret != 0)
 				return ret;
 
-			snd_soc_cache_sync(codec);
+			regcache_sync(wm8731->regmap);
 		}
 
 		/* Clear PWROFF, gate CLKOUT, everything else as-is */
@@ -452,7 +467,7 @@
 		snd_soc_write(codec, WM8731_PWR, 0xffff);
 		regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
 				       wm8731->supplies);
-		codec->cache_sync = 1;
+		regcache_mark_dirty(wm8731->regmap);
 		break;
 	}
 	codec->dapm.bias_level = level;
@@ -513,7 +528,8 @@
 	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
 	int ret = 0, i;
 
-	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8731->control_type);
+	codec->control_data = wm8731->regmap;
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
@@ -585,9 +601,6 @@
 	.suspend =	wm8731_suspend,
 	.resume =	wm8731_resume,
 	.set_bias_level = wm8731_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(wm8731_reg),
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = wm8731_reg,
 	.dapm_widgets = wm8731_dapm_widgets,
 	.num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
 	.dapm_routes = wm8731_intercon,
@@ -603,6 +616,19 @@
 
 MODULE_DEVICE_TABLE(of, wm8731_of_match);
 
+static const struct regmap_config wm8731_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = WM8731_RESET,
+	.volatile_reg = wm8731_volatile,
+	.writeable_reg = wm8731_writeable,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8731_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8731_reg_defaults),
+};
+
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit wm8731_spi_probe(struct spi_device *spi)
 {
@@ -613,20 +639,39 @@
 	if (wm8731 == NULL)
 		return -ENOMEM;
 
-	wm8731->control_type = SND_SOC_SPI;
+	wm8731->regmap = regmap_init_spi(spi, &wm8731_regmap);
+	if (IS_ERR(wm8731->regmap)) {
+		ret = PTR_ERR(wm8731->regmap);
+		dev_err(&spi->dev, "Failed to allocate register map: %d\n",
+			ret);
+		goto err;
+	}
+
 	spi_set_drvdata(spi, wm8731);
 
 	ret = snd_soc_register_codec(&spi->dev,
 			&soc_codec_dev_wm8731, &wm8731_dai, 1);
-	if (ret < 0)
-		kfree(wm8731);
+	if (ret != 0) {
+		dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret);
+		goto err_regmap;
+	}
+
+	return 0;
+
+err_regmap:
+	regmap_exit(wm8731->regmap);
+err:
+	kfree(wm8731);
 	return ret;
 }
 
 static int __devexit wm8731_spi_remove(struct spi_device *spi)
 {
+	struct wm8731_priv *wm8731 = spi_get_drvdata(spi);
+
 	snd_soc_unregister_codec(&spi->dev);
-	kfree(spi_get_drvdata(spi));
+	regmap_exit(wm8731->regmap);
+	kfree(wm8731);
 	return 0;
 }
 
@@ -652,20 +697,38 @@
 	if (wm8731 == NULL)
 		return -ENOMEM;
 
-	i2c_set_clientdata(i2c, wm8731);
-	wm8731->control_type = SND_SOC_I2C;
+	wm8731->regmap = regmap_init_i2c(i2c, &wm8731_regmap);
+	if (IS_ERR(wm8731->regmap)) {
+		ret = PTR_ERR(wm8731->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		goto err;
+	}
 
-	ret =  snd_soc_register_codec(&i2c->dev,
+	i2c_set_clientdata(i2c, wm8731);
+
+	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_wm8731, &wm8731_dai, 1);
-	if (ret < 0)
-		kfree(wm8731);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+		goto err_regmap;
+	}
+
+	return 0;
+
+err_regmap:
+	regmap_exit(wm8731->regmap);
+err:
+	kfree(wm8731);
 	return ret;
 }
 
 static __devexit int wm8731_i2c_remove(struct i2c_client *client)
 {
+	struct wm8731_priv *wm8731 = i2c_get_clientdata(client);
 	snd_soc_unregister_codec(&client->dev);
-	kfree(i2c_get_clientdata(client));
+	regmap_exit(wm8731->regmap);
+	kfree(wm8731);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
index ff95e62c..4fe9d19 100644
--- a/sound/soc/codecs/wm8737.c
+++ b/sound/soc/codecs/wm8737.c
@@ -599,7 +599,7 @@
 	/* Bias level configuration will have done an extra enable */
 	regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
 
-	snd_soc_add_controls(codec, wm8737_snd_controls,
+	snd_soc_add_codec_controls(codec, wm8737_snd_controls,
 			     ARRAY_SIZE(wm8737_snd_controls));
 	wm8737_add_widgets(codec);
 
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index b114c19..e27e7b6 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -39,6 +39,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/of_device.h>
+#include <linux/regmap.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -65,28 +66,86 @@
  * We can't read the WM8753 register space when we
  * are using 2 wire for device control, so we cache them instead.
  */
-static const u16 wm8753_reg[] = {
-	0x0000, 0x0008, 0x0000, 0x000a,
-	0x000a, 0x0033, 0x0000, 0x0007,
-	0x00ff, 0x00ff, 0x000f, 0x000f,
-	0x007b, 0x0000, 0x0032, 0x0000,
-	0x00c3, 0x00c3, 0x00c0, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0055, 0x0005, 0x0050, 0x0055,
-	0x0050, 0x0055, 0x0050, 0x0055,
-	0x0079, 0x0079, 0x0079, 0x0079,
-	0x0079, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0097, 0x0097, 0x0000,
-	0x0004, 0x0000, 0x0083, 0x0024,
-	0x01ba, 0x0000, 0x0083, 0x0024,
-	0x01ba, 0x0000, 0x0000, 0x0000
+static const struct reg_default wm8753_reg_defaults[] = {
+	{ 0x00, 0x0000 },
+	{ 0x01, 0x0008 },
+	{ 0x02, 0x0000 },
+	{ 0x03, 0x000a },
+	{ 0x04, 0x000a },
+	{ 0x05, 0x0033 },
+	{ 0x06, 0x0000 },
+	{ 0x07, 0x0007 },
+	{ 0x08, 0x00ff },
+	{ 0x09, 0x00ff },
+	{ 0x0a, 0x000f },
+	{ 0x0b, 0x000f },
+	{ 0x0c, 0x007b },
+	{ 0x0d, 0x0000 },
+	{ 0x0e, 0x0032 },
+	{ 0x0f, 0x0000 },
+	{ 0x10, 0x00c3 },
+	{ 0x11, 0x00c3 },
+	{ 0x12, 0x00c0 },
+	{ 0x13, 0x0000 },
+	{ 0x14, 0x0000 },
+	{ 0x15, 0x0000 },
+	{ 0x16, 0x0000 },
+	{ 0x17, 0x0000 },
+	{ 0x18, 0x0000 },
+	{ 0x19, 0x0000 },
+	{ 0x1a, 0x0000 },
+	{ 0x1b, 0x0000 },
+	{ 0x1c, 0x0000 },
+	{ 0x1d, 0x0000 },
+	{ 0x1e, 0x0000 },
+	{ 0x1f, 0x0000 },
+	{ 0x20, 0x0055 },
+	{ 0x21, 0x0005 },
+	{ 0x22, 0x0050 },
+	{ 0x23, 0x0055 },
+	{ 0x24, 0x0050 },
+	{ 0x25, 0x0055 },
+	{ 0x26, 0x0050 },
+	{ 0x27, 0x0055 },
+	{ 0x28, 0x0079 },
+	{ 0x29, 0x0079 },
+	{ 0x2a, 0x0079 },
+	{ 0x2b, 0x0079 },
+	{ 0x2c, 0x0079 },
+	{ 0x2d, 0x0000 },
+	{ 0x2e, 0x0000 },
+	{ 0x2f, 0x0000 },
+	{ 0x30, 0x0000 },
+	{ 0x31, 0x0097 },
+	{ 0x32, 0x0097 },
+	{ 0x33, 0x0000 },
+	{ 0x34, 0x0004 },
+	{ 0x35, 0x0000 },
+	{ 0x36, 0x0083 },
+	{ 0x37, 0x0024 },
+	{ 0x38, 0x01ba },
+	{ 0x39, 0x0000 },
+	{ 0x3a, 0x0083 },
+	{ 0x3b, 0x0024 },
+	{ 0x3c, 0x01ba },
+	{ 0x3d, 0x0000 },
+	{ 0x3e, 0x0000 },
+	{ 0x3f, 0x0000 },
 };
 
+static bool wm8753_volatile(struct device *dev, unsigned int reg)
+{
+	return reg == WM8753_RESET;
+}
+
+static bool wm8753_writeable(struct device *dev, unsigned int reg)
+{
+	return reg <= WM8753_ADCTL2;
+}
+
 /* codec private data */
 struct wm8753_priv {
-	enum snd_soc_control_type control_type;
+	struct regmap *regmap;
 	unsigned int sysclk;
 	unsigned int pcmclk;
 
@@ -1383,25 +1442,15 @@
 static int wm8753_suspend(struct snd_soc_codec *codec)
 {
 	wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	codec->cache_sync = 1;
 	return 0;
 }
 
 static int wm8753_resume(struct snd_soc_codec *codec)
 {
-	u16 *reg_cache = codec->reg_cache;
-	int i;
+	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
 
-	/* Sync reg_cache with the hardware */
-	for (i = 1; i < ARRAY_SIZE(wm8753_reg); i++) {
-		if (i == WM8753_RESET)
-			continue;
-
-		/* No point in writing hardware default values back */
-		if (reg_cache[i] == wm8753_reg[i])
-			continue;
-
-		snd_soc_write(codec, i, reg_cache[i]);
-	}
+	regcache_sync(wm8753->regmap);
 
 	wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -1423,7 +1472,8 @@
 
 	INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8753_work);
 
-	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8753->control_type);
+	codec->control_data = wm8753->regmap;
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
@@ -1473,9 +1523,6 @@
 	.suspend =	wm8753_suspend,
 	.resume =	wm8753_resume,
 	.set_bias_level = wm8753_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(wm8753_reg),
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = wm8753_reg,
 
 	.controls = wm8753_snd_controls,
 	.num_controls = ARRAY_SIZE(wm8753_snd_controls),
@@ -1491,30 +1538,62 @@
 };
 MODULE_DEVICE_TABLE(of, wm8753_of_match);
 
+static const struct regmap_config wm8753_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = WM8753_ADCTL2,
+	.writeable_reg = wm8753_writeable,
+	.volatile_reg = wm8753_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8753_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8753_reg_defaults),
+};
+
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit wm8753_spi_probe(struct spi_device *spi)
 {
 	struct wm8753_priv *wm8753;
 	int ret;
 
-	wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
+	wm8753 = devm_kzalloc(&spi->dev, sizeof(struct wm8753_priv),
+			      GFP_KERNEL);
 	if (wm8753 == NULL)
 		return -ENOMEM;
 
-	wm8753->control_type = SND_SOC_SPI;
 	spi_set_drvdata(spi, wm8753);
 
-	ret = snd_soc_register_codec(&spi->dev,
-			&soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai));
-	if (ret < 0)
-		kfree(wm8753);
+	wm8753->regmap = regmap_init_spi(spi, &wm8753_regmap);
+	if (IS_ERR(wm8753->regmap)) {
+		ret = PTR_ERR(wm8753->regmap);
+		dev_err(&spi->dev, "Failed to allocate register map: %d\n",
+			ret);
+		goto err;
+	}
+
+	ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8753,
+				     wm8753_dai, ARRAY_SIZE(wm8753_dai));
+	if (ret != 0) {
+		dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret);
+		goto err_regmap;
+	}
+
+	return 0;
+
+err_regmap:
+	regmap_exit(wm8753->regmap);
+err:
 	return ret;
 }
 
 static int __devexit wm8753_spi_remove(struct spi_device *spi)
 {
+	struct wm8753_priv *wm8753 = spi_get_drvdata(spi);
+
 	snd_soc_unregister_codec(&spi->dev);
-	kfree(spi_get_drvdata(spi));
+	regmap_exit(wm8753->regmap);
+	kfree(wm8753);
 	return 0;
 }
 
@@ -1536,24 +1615,42 @@
 	struct wm8753_priv *wm8753;
 	int ret;
 
-	wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
+	wm8753 = devm_kzalloc(&i2c->dev, sizeof(struct wm8753_priv),
+			      GFP_KERNEL);
 	if (wm8753 == NULL)
 		return -ENOMEM;
 
 	i2c_set_clientdata(i2c, wm8753);
-	wm8753->control_type = SND_SOC_I2C;
 
-	ret =  snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai));
-	if (ret < 0)
-		kfree(wm8753);
+	wm8753->regmap = regmap_init_i2c(i2c, &wm8753_regmap);
+	if (IS_ERR(wm8753->regmap)) {
+		ret = PTR_ERR(wm8753->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		goto err;
+	}
+
+	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8753,
+				     wm8753_dai, ARRAY_SIZE(wm8753_dai));
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+		goto err_regmap;
+	}
+
+	return 0;
+
+err_regmap:
+	regmap_exit(wm8753->regmap);
+err:
 	return ret;
 }
 
 static __devexit int wm8753_i2c_remove(struct i2c_client *client)
 {
+	struct wm8753_priv *wm8753 = i2c_get_clientdata(client);
+
 	snd_soc_unregister_codec(&client->dev);
-	kfree(i2c_get_clientdata(client));
+	regmap_exit(wm8753->regmap);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c
index 19374a9..a5127b4 100644
--- a/sound/soc/codecs/wm8770.c
+++ b/sound/soc/codecs/wm8770.c
@@ -580,8 +580,6 @@
 	wm8770 = snd_soc_codec_get_drvdata(codec);
 	wm8770->codec = codec;
 
-	codec->dapm.idle_bias_off = 1;
-
 	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8770->control_type);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
@@ -643,7 +641,7 @@
 	/* mute all DACs */
 	snd_soc_update_bits(codec, WM8770_DACMUTE, 0x10, 0x10);
 
-	snd_soc_add_controls(codec, wm8770_snd_controls,
+	snd_soc_add_codec_controls(codec, wm8770_snd_controls,
 			     ARRAY_SIZE(wm8770_snd_controls));
 	snd_soc_dapm_new_controls(&codec->dapm, wm8770_dapm_widgets,
 				  ARRAY_SIZE(wm8770_dapm_widgets));
@@ -679,6 +677,7 @@
 	.suspend = wm8770_suspend,
 	.resume = wm8770_resume,
 	.set_bias_level = wm8770_set_bias_level,
+	.idle_bias_off = true,
 	.reg_cache_size = ARRAY_SIZE(wm8770_reg_defs),
 	.reg_word_size = sizeof (u16),
 	.reg_cache_default = wm8770_reg_defs
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index 33e97d1..a19db5a 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -30,6 +30,11 @@
 
 #include "wm8776.h"
 
+enum wm8776_chip_type {
+	WM8775 = 1,
+	WM8776,
+};
+
 /* codec private data */
 struct wm8776_priv {
 	enum snd_soc_control_type control_type;
@@ -512,7 +517,8 @@
 }
 
 static const struct i2c_device_id wm8776_i2c_id[] = {
-	{ "wm8776", 0 },
+	{ "wm8775", WM8775 },
+	{ "wm8776", WM8776 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id);
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index d54a3ca..6bd1b76 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -18,6 +18,7 @@
 #include <linux/i2c.h>
 #include <linux/of_device.h>
 #include <linux/spi/spi.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -35,45 +36,33 @@
 	"DVDD"
 };
 
-static const u8 wm8804_reg_defs[] = {
-	0x05,     /* R0  - RST/DEVID1 */
-	0x88,     /* R1  - DEVID2 */
-	0x04,     /* R2  - DEVREV */
-	0x21,     /* R3  - PLL1 */
-	0xFD,     /* R4  - PLL2 */
-	0x36,     /* R5  - PLL3 */
-	0x07,     /* R6  - PLL4 */
-	0x16,     /* R7  - PLL5 */
-	0x18,     /* R8  - PLL6 */
-	0xFF,     /* R9  - SPDMODE */
-	0x00,     /* R10 - INTMASK */
-	0x00,     /* R11 - INTSTAT */
-	0x00,     /* R12 - SPDSTAT */
-	0x00,     /* R13 - RXCHAN1 */
-	0x00,     /* R14 - RXCHAN2 */
-	0x00,     /* R15 - RXCHAN3 */
-	0x00,     /* R16 - RXCHAN4 */
-	0x00,     /* R17 - RXCHAN5 */
-	0x00,     /* R18 - SPDTX1 */
-	0x00,     /* R19 - SPDTX2 */
-	0x00,     /* R20 - SPDTX3 */
-	0x71,     /* R21 - SPDTX4 */
-	0x0B,     /* R22 - SPDTX5 */
-	0x70,     /* R23 - GPO0 */
-	0x57,     /* R24 - GPO1 */
-	0x00,     /* R25 */
-	0x42,     /* R26 - GPO2 */
-	0x06,     /* R27 - AIFTX */
-	0x06,     /* R28 - AIFRX */
-	0x80,     /* R29 - SPDRX1 */
-	0x07,     /* R30 - PWRDN */
+static const struct reg_default wm8804_reg_defaults[] = {
+	{ 3,  0x21 },     /* R3  - PLL1 */
+	{ 4,  0xFD },     /* R4  - PLL2 */
+	{ 5,  0x36 },     /* R5  - PLL3 */
+	{ 6,  0x07 },     /* R6  - PLL4 */
+	{ 7,  0x16 },     /* R7  - PLL5 */
+	{ 8,  0x18 },     /* R8  - PLL6 */
+	{ 9,  0xFF },     /* R9  - SPDMODE */
+	{ 10, 0x00 },     /* R10 - INTMASK */
+	{ 18, 0x00 },     /* R18 - SPDTX1 */
+	{ 19, 0x00 },     /* R19 - SPDTX2 */
+	{ 20, 0x00 },     /* R20 - SPDTX3 */
+	{ 21, 0x71 },     /* R21 - SPDTX4 */
+	{ 22, 0x0B },     /* R22 - SPDTX5 */
+	{ 23, 0x70 },     /* R23 - GPO0 */
+	{ 24, 0x57 },     /* R24 - GPO1 */
+	{ 26, 0x42 },     /* R26 - GPO2 */
+	{ 27, 0x06 },     /* R27 - AIFTX */
+	{ 28, 0x06 },     /* R28 - AIFRX */
+	{ 29, 0x80 },     /* R29 - SPDRX1 */
+	{ 30, 0x07 },     /* R30 - PWRDN */
 };
 
 struct wm8804_priv {
-	enum snd_soc_control_type control_type;
+	struct regmap *regmap;
 	struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES];
 	struct notifier_block disable_nb[WM8804_NUM_SUPPLIES];
-	struct snd_soc_codec *codec;
 };
 
 static int txsrc_get(struct snd_kcontrol *kcontrol,
@@ -94,7 +83,7 @@
 	struct wm8804_priv *wm8804 = container_of(nb, struct wm8804_priv, \
 						  disable_nb[n]); \
 	if (event & REGULATOR_EVENT_DISABLE) { \
-		wm8804->codec->cache_sync = 1; \
+		regcache_mark_dirty(wm8804->regmap);	\
 	} \
 	return 0; \
 }
@@ -176,7 +165,7 @@
 	return 0;
 }
 
-static int wm8804_volatile(struct snd_soc_codec *codec, unsigned int reg)
+static bool wm8804_volatile(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
 	case WM8804_RST_DEVID1:
@@ -189,12 +178,10 @@
 	case WM8804_RXCHAN3:
 	case WM8804_RXCHAN4:
 	case WM8804_RXCHAN5:
-		return 1;
+		return true;
 	default:
-		break;
+		return false;
 	}
-
-	return 0;
 }
 
 static int wm8804_reset(struct snd_soc_codec *codec)
@@ -482,24 +469,6 @@
 	return 0;
 }
 
-static void wm8804_sync_cache(struct snd_soc_codec *codec)
-{
-	short i;
-	u8 *cache;
-
-	if (!codec->cache_sync)
-		return;
-
-	codec->cache_only = 0;
-	cache = codec->reg_cache;
-	for (i = 0; i < codec->driver->reg_cache_size; i++) {
-		if (i == WM8804_RST_DEVID1 || cache[i] == wm8804_reg_defs[i])
-			continue;
-		snd_soc_write(codec, i, cache[i]);
-	}
-	codec->cache_sync = 0;
-}
-
 static int wm8804_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
@@ -524,7 +493,7 @@
 					ret);
 				return ret;
 			}
-			wm8804_sync_cache(codec);
+			regcache_sync(wm8804->regmap);
 		}
 		/* power down the OSC and the PLL */
 		snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9);
@@ -579,11 +548,10 @@
 	int i, id1, id2, ret;
 
 	wm8804 = snd_soc_codec_get_drvdata(codec);
-	wm8804->codec = codec;
 
-	codec->dapm.idle_bias_off = 1;
+	codec->control_data = wm8804->regmap;
 
-	ret = snd_soc_codec_set_cache_io(codec, 8, 8, wm8804->control_type);
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
 		return ret;
@@ -636,8 +604,7 @@
 
 	id2 = (id2 << 8) | id1;
 
-	if (id2 != ((wm8804_reg_defs[WM8804_DEVID2] << 8)
-			| wm8804_reg_defs[WM8804_RST_DEVID1])) {
+	if (id2 != 0x8805) {
 		dev_err(codec->dev, "Invalid device ID: %#x\n", id2);
 		ret = -EINVAL;
 		goto err_reg_enable;
@@ -710,10 +677,7 @@
 	.suspend = wm8804_suspend,
 	.resume = wm8804_resume,
 	.set_bias_level = wm8804_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(wm8804_reg_defs),
-	.reg_word_size = sizeof(u8),
-	.reg_cache_default = wm8804_reg_defs,
-	.volatile_register = wm8804_volatile,
+	.idle_bias_off = true,
 
 	.controls = wm8804_snd_controls,
 	.num_controls = ARRAY_SIZE(wm8804_snd_controls),
@@ -725,30 +689,47 @@
 };
 MODULE_DEVICE_TABLE(of, wm8804_of_match);
 
+static struct regmap_config wm8804_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = WM8804_MAX_REGISTER,
+	.volatile_reg = wm8804_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8804_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults),
+};
+
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit wm8804_spi_probe(struct spi_device *spi)
 {
 	struct wm8804_priv *wm8804;
 	int ret;
 
-	wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL);
+	wm8804 = devm_kzalloc(&spi->dev, sizeof *wm8804, GFP_KERNEL);
 	if (!wm8804)
 		return -ENOMEM;
 
-	wm8804->control_type = SND_SOC_SPI;
+	wm8804->regmap = regmap_init_spi(spi, &wm8804_regmap_config);
+	if (IS_ERR(wm8804->regmap)) {
+		ret = PTR_ERR(wm8804->regmap);
+		return ret;
+	}
+
 	spi_set_drvdata(spi, wm8804);
 
 	ret = snd_soc_register_codec(&spi->dev,
 				     &soc_codec_dev_wm8804, &wm8804_dai, 1);
-	if (ret < 0)
-		kfree(wm8804);
+
 	return ret;
 }
 
 static int __devexit wm8804_spi_remove(struct spi_device *spi)
 {
+	struct wm8804_priv *wm8804 = spi_get_drvdata(spi);
 	snd_soc_unregister_codec(&spi->dev);
-	kfree(spi_get_drvdata(spi));
+	regmap_exit(wm8804->regmap);
 	return 0;
 }
 
@@ -770,24 +751,37 @@
 	struct wm8804_priv *wm8804;
 	int ret;
 
-	wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL);
+	wm8804 = devm_kzalloc(&i2c->dev, sizeof *wm8804, GFP_KERNEL);
 	if (!wm8804)
 		return -ENOMEM;
 
-	wm8804->control_type = SND_SOC_I2C;
+	wm8804->regmap = regmap_init_i2c(i2c, &wm8804_regmap_config);
+	if (IS_ERR(wm8804->regmap)) {
+		ret = PTR_ERR(wm8804->regmap);
+		return ret;
+	}
+
 	i2c_set_clientdata(i2c, wm8804);
 
 	ret = snd_soc_register_codec(&i2c->dev,
 				     &soc_codec_dev_wm8804, &wm8804_dai, 1);
-	if (ret < 0)
-		kfree(wm8804);
+	if (ret != 0)
+		goto err;
+
+	return 0;
+
+err:
+	regmap_exit(wm8804->regmap);
 	return ret;
 }
 
-static __devexit int wm8804_i2c_remove(struct i2c_client *client)
+static __devexit int wm8804_i2c_remove(struct i2c_client *i2c)
 {
-	snd_soc_unregister_codec(&client->dev);
-	kfree(i2c_get_clientdata(client));
+	struct wm8804_priv *wm8804 = i2c_get_clientdata(i2c);
+
+	snd_soc_unregister_codec(&i2c->dev);
+	regmap_exit(wm8804->regmap);
+
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index f31c754..65d525d 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -47,6 +48,7 @@
 
 /* codec private data */
 struct wm8904_priv {
+	struct regmap *regmap;
 
 	enum wm8904_type devtype;
 
@@ -86,517 +88,230 @@
 	int dcs_state[WM8904_NUM_DCS_CHANNELS];
 };
 
-static const u16 wm8904_reg[WM8904_MAX_REGISTER + 1] = {
-	0x8904,     /* R0   - SW Reset and ID */
-	0x0000,     /* R1   - Revision */
-	0x0000,     /* R2 */
-	0x0000,     /* R3 */
-	0x0018,     /* R4   - Bias Control 0 */
-	0x0000,     /* R5   - VMID Control 0 */
-	0x0000,     /* R6   - Mic Bias Control 0 */
-	0x0000,     /* R7   - Mic Bias Control 1 */
-	0x0001,     /* R8   - Analogue DAC 0 */
-	0x9696,     /* R9   - mic Filter Control */
-	0x0001,     /* R10  - Analogue ADC 0 */
-	0x0000,     /* R11 */
-	0x0000,     /* R12  - Power Management 0 */
-	0x0000,     /* R13 */
-	0x0000,     /* R14  - Power Management 2 */
-	0x0000,     /* R15  - Power Management 3 */
-	0x0000,     /* R16 */
-	0x0000,     /* R17 */
-	0x0000,     /* R18  - Power Management 6 */
-	0x0000,     /* R19 */
-	0x945E,     /* R20  - Clock Rates 0 */
-	0x0C05,     /* R21  - Clock Rates 1 */
-	0x0006,     /* R22  - Clock Rates 2 */
-	0x0000,     /* R23 */
-	0x0050,     /* R24  - Audio Interface 0 */
-	0x000A,     /* R25  - Audio Interface 1 */
-	0x00E4,     /* R26  - Audio Interface 2 */
-	0x0040,     /* R27  - Audio Interface 3 */
-	0x0000,     /* R28 */
-	0x0000,     /* R29 */
-	0x00C0,     /* R30  - DAC Digital Volume Left */
-	0x00C0,     /* R31  - DAC Digital Volume Right */
-	0x0000,     /* R32  - DAC Digital 0 */
-	0x0008,     /* R33  - DAC Digital 1 */
-	0x0000,     /* R34 */
-	0x0000,     /* R35 */
-	0x00C0,     /* R36  - ADC Digital Volume Left */
-	0x00C0,     /* R37  - ADC Digital Volume Right */
-	0x0010,     /* R38  - ADC Digital 0 */
-	0x0000,     /* R39  - Digital Microphone 0 */
-	0x01AF,     /* R40  - DRC 0 */
-	0x3248,     /* R41  - DRC 1 */
-	0x0000,     /* R42  - DRC 2 */
-	0x0000,     /* R43  - DRC 3 */
-	0x0085,     /* R44  - Analogue Left Input 0 */
-	0x0085,     /* R45  - Analogue Right Input 0 */
-	0x0044,     /* R46  - Analogue Left Input 1 */
-	0x0044,     /* R47  - Analogue Right Input 1 */
-	0x0000,     /* R48 */
-	0x0000,     /* R49 */
-	0x0000,     /* R50 */
-	0x0000,     /* R51 */
-	0x0000,     /* R52 */
-	0x0000,     /* R53 */
-	0x0000,     /* R54 */
-	0x0000,     /* R55 */
-	0x0000,     /* R56 */
-	0x002D,     /* R57  - Analogue OUT1 Left */
-	0x002D,     /* R58  - Analogue OUT1 Right */
-	0x0039,     /* R59  - Analogue OUT2 Left */
-	0x0039,     /* R60  - Analogue OUT2 Right */
-	0x0000,     /* R61  - Analogue OUT12 ZC */
-	0x0000,     /* R62 */
-	0x0000,     /* R63 */
-	0x0000,     /* R64 */
-	0x0000,     /* R65 */
-	0x0000,     /* R66 */
-	0x0000,     /* R67  - DC Servo 0 */
-	0x0000,     /* R68  - DC Servo 1 */
-	0xAAAA,     /* R69  - DC Servo 2 */
-	0x0000,     /* R70 */
-	0xAAAA,     /* R71  - DC Servo 4 */
-	0xAAAA,     /* R72  - DC Servo 5 */
-	0x0000,     /* R73  - DC Servo 6 */
-	0x0000,     /* R74  - DC Servo 7 */
-	0x0000,     /* R75  - DC Servo 8 */
-	0x0000,     /* R76  - DC Servo 9 */
-	0x0000,     /* R77  - DC Servo Readback 0 */
-	0x0000,     /* R78 */
-	0x0000,     /* R79 */
-	0x0000,     /* R80 */
-	0x0000,     /* R81 */
-	0x0000,     /* R82 */
-	0x0000,     /* R83 */
-	0x0000,     /* R84 */
-	0x0000,     /* R85 */
-	0x0000,     /* R86 */
-	0x0000,     /* R87 */
-	0x0000,     /* R88 */
-	0x0000,     /* R89 */
-	0x0000,     /* R90  - Analogue HP 0 */
-	0x0000,     /* R91 */
-	0x0000,     /* R92 */
-	0x0000,     /* R93 */
-	0x0000,     /* R94  - Analogue Lineout 0 */
-	0x0000,     /* R95 */
-	0x0000,     /* R96 */
-	0x0000,     /* R97 */
-	0x0000,     /* R98  - Charge Pump 0 */
-	0x0000,     /* R99 */
-	0x0000,     /* R100 */
-	0x0000,     /* R101 */
-	0x0000,     /* R102 */
-	0x0000,     /* R103 */
-	0x0004,     /* R104 - Class W 0 */
-	0x0000,     /* R105 */
-	0x0000,     /* R106 */
-	0x0000,     /* R107 */
-	0x0000,     /* R108 - Write Sequencer 0 */
-	0x0000,     /* R109 - Write Sequencer 1 */
-	0x0000,     /* R110 - Write Sequencer 2 */
-	0x0000,     /* R111 - Write Sequencer 3 */
-	0x0000,     /* R112 - Write Sequencer 4 */
-	0x0000,     /* R113 */
-	0x0000,     /* R114 */
-	0x0000,     /* R115 */
-	0x0000,     /* R116 - FLL Control 1 */
-	0x0007,     /* R117 - FLL Control 2 */
-	0x0000,     /* R118 - FLL Control 3 */
-	0x2EE0,     /* R119 - FLL Control 4 */
-	0x0004,     /* R120 - FLL Control 5 */
-	0x0014,     /* R121 - GPIO Control 1 */
-	0x0010,     /* R122 - GPIO Control 2 */
-	0x0010,     /* R123 - GPIO Control 3 */
-	0x0000,     /* R124 - GPIO Control 4 */
-	0x0000,     /* R125 */
-	0x0000,     /* R126 - Digital Pulls */
-	0x0000,     /* R127 - Interrupt Status */
-	0xFFFF,     /* R128 - Interrupt Status Mask */
-	0x0000,     /* R129 - Interrupt Polarity */
-	0x0000,     /* R130 - Interrupt Debounce */
-	0x0000,     /* R131 */
-	0x0000,     /* R132 */
-	0x0000,     /* R133 */
-	0x0000,     /* R134 - EQ1 */
-	0x000C,     /* R135 - EQ2 */
-	0x000C,     /* R136 - EQ3 */
-	0x000C,     /* R137 - EQ4 */
-	0x000C,     /* R138 - EQ5 */
-	0x000C,     /* R139 - EQ6 */
-	0x0FCA,     /* R140 - EQ7 */
-	0x0400,     /* R141 - EQ8 */
-	0x00D8,     /* R142 - EQ9 */
-	0x1EB5,     /* R143 - EQ10 */
-	0xF145,     /* R144 - EQ11 */
-	0x0B75,     /* R145 - EQ12 */
-	0x01C5,     /* R146 - EQ13 */
-	0x1C58,     /* R147 - EQ14 */
-	0xF373,     /* R148 - EQ15 */
-	0x0A54,     /* R149 - EQ16 */
-	0x0558,     /* R150 - EQ17 */
-	0x168E,     /* R151 - EQ18 */
-	0xF829,     /* R152 - EQ19 */
-	0x07AD,     /* R153 - EQ20 */
-	0x1103,     /* R154 - EQ21 */
-	0x0564,     /* R155 - EQ22 */
-	0x0559,     /* R156 - EQ23 */
-	0x4000,     /* R157 - EQ24 */
-	0x0000,     /* R158 */
-	0x0000,     /* R159 */
-	0x0000,     /* R160 */
-	0x0000,     /* R161 - Control Interface Test 1 */
-	0x0000,     /* R162 */
-	0x0000,     /* R163 */
-	0x0000,     /* R164 */
-	0x0000,     /* R165 */
-	0x0000,     /* R166 */
-	0x0000,     /* R167 */
-	0x0000,     /* R168 */
-	0x0000,     /* R169 */
-	0x0000,     /* R170 */
-	0x0000,     /* R171 */
-	0x0000,     /* R172 */
-	0x0000,     /* R173 */
-	0x0000,     /* R174 */
-	0x0000,     /* R175 */
-	0x0000,     /* R176 */
-	0x0000,     /* R177 */
-	0x0000,     /* R178 */
-	0x0000,     /* R179 */
-	0x0000,     /* R180 */
-	0x0000,     /* R181 */
-	0x0000,     /* R182 */
-	0x0000,     /* R183 */
-	0x0000,     /* R184 */
-	0x0000,     /* R185 */
-	0x0000,     /* R186 */
-	0x0000,     /* R187 */
-	0x0000,     /* R188 */
-	0x0000,     /* R189 */
-	0x0000,     /* R190 */
-	0x0000,     /* R191 */
-	0x0000,     /* R192 */
-	0x0000,     /* R193 */
-	0x0000,     /* R194 */
-	0x0000,     /* R195 */
-	0x0000,     /* R196 */
-	0x0000,     /* R197 */
-	0x0000,     /* R198 */
-	0x0000,     /* R199 */
-	0x0000,     /* R200 */
-	0x0000,     /* R201 */
-	0x0000,     /* R202 */
-	0x0000,     /* R203 */
-	0x0000,     /* R204 - Analogue Output Bias 0 */
-	0x0000,     /* R205 */
-	0x0000,     /* R206 */
-	0x0000,     /* R207 */
-	0x0000,     /* R208 */
-	0x0000,     /* R209 */
-	0x0000,     /* R210 */
-	0x0000,     /* R211 */
-	0x0000,     /* R212 */
-	0x0000,     /* R213 */
-	0x0000,     /* R214 */
-	0x0000,     /* R215 */
-	0x0000,     /* R216 */
-	0x0000,     /* R217 */
-	0x0000,     /* R218 */
-	0x0000,     /* R219 */
-	0x0000,     /* R220 */
-	0x0000,     /* R221 */
-	0x0000,     /* R222 */
-	0x0000,     /* R223 */
-	0x0000,     /* R224 */
-	0x0000,     /* R225 */
-	0x0000,     /* R226 */
-	0x0000,     /* R227 */
-	0x0000,     /* R228 */
-	0x0000,     /* R229 */
-	0x0000,     /* R230 */
-	0x0000,     /* R231 */
-	0x0000,     /* R232 */
-	0x0000,     /* R233 */
-	0x0000,     /* R234 */
-	0x0000,     /* R235 */
-	0x0000,     /* R236 */
-	0x0000,     /* R237 */
-	0x0000,     /* R238 */
-	0x0000,     /* R239 */
-	0x0000,     /* R240 */
-	0x0000,     /* R241 */
-	0x0000,     /* R242 */
-	0x0000,     /* R243 */
-	0x0000,     /* R244 */
-	0x0000,     /* R245 */
-	0x0000,     /* R246 */
-	0x0000,     /* R247 - FLL NCO Test 0 */
-	0x0019,     /* R248 - FLL NCO Test 1 */
+static const struct reg_default wm8904_reg_defaults[] = {
+	{ 4,   0x0018 },     /* R4   - Bias Control 0 */
+	{ 5,   0x0000 },     /* R5   - VMID Control 0 */
+	{ 6,   0x0000 },     /* R6   - Mic Bias Control 0 */
+	{ 7,   0x0000 },     /* R7   - Mic Bias Control 1 */
+	{ 8,   0x0001 },     /* R8   - Analogue DAC 0 */
+	{ 9,   0x9696 },     /* R9   - mic Filter Control */
+	{ 10,  0x0001 },     /* R10  - Analogue ADC 0 */
+	{ 12,  0x0000 },     /* R12  - Power Management 0 */
+	{ 14,  0x0000 },     /* R14  - Power Management 2 */
+	{ 15,  0x0000 },     /* R15  - Power Management 3 */
+	{ 18,  0x0000 },     /* R18  - Power Management 6 */
+	{ 19,  0x945E },     /* R20  - Clock Rates 0 */
+	{ 21,  0x0C05 },     /* R21  - Clock Rates 1 */
+	{ 22,  0x0006 },     /* R22  - Clock Rates 2 */
+	{ 24,  0x0050 },     /* R24  - Audio Interface 0 */
+	{ 25,  0x000A },     /* R25  - Audio Interface 1 */
+	{ 26,  0x00E4 },     /* R26  - Audio Interface 2 */
+	{ 27,  0x0040 },     /* R27  - Audio Interface 3 */
+	{ 30,  0x00C0 },     /* R30  - DAC Digital Volume Left */
+	{ 31,  0x00C0 },     /* R31  - DAC Digital Volume Right */
+	{ 32,  0x0000 },     /* R32  - DAC Digital 0 */
+	{ 33,  0x0008 },     /* R33  - DAC Digital 1 */
+	{ 36,  0x00C0 },     /* R36  - ADC Digital Volume Left */
+	{ 37,  0x00C0 },     /* R37  - ADC Digital Volume Right */
+	{ 38,  0x0010 },     /* R38  - ADC Digital 0 */
+	{ 39,  0x0000 },     /* R39  - Digital Microphone 0 */
+	{ 40,  0x01AF },     /* R40  - DRC 0 */
+	{ 41,  0x3248 },     /* R41  - DRC 1 */
+	{ 42,  0x0000 },     /* R42  - DRC 2 */
+	{ 43,  0x0000 },     /* R43  - DRC 3 */
+	{ 44,  0x0085 },     /* R44  - Analogue Left Input 0 */
+	{ 45,  0x0085 },     /* R45  - Analogue Right Input 0 */
+	{ 46,  0x0044 },     /* R46  - Analogue Left Input 1 */
+	{ 47,  0x0044 },     /* R47  - Analogue Right Input 1 */
+	{ 57,  0x002D },     /* R57  - Analogue OUT1 Left */
+	{ 58,  0x002D },     /* R58  - Analogue OUT1 Right */
+	{ 59,  0x0039 },     /* R59  - Analogue OUT2 Left */
+	{ 60,  0x0039 },     /* R60  - Analogue OUT2 Right */
+	{ 61,  0x0000 },     /* R61  - Analogue OUT12 ZC */
+	{ 67,  0x0000 },     /* R67  - DC Servo 0 */
+	{ 69,  0xAAAA },     /* R69  - DC Servo 2 */
+	{ 71,  0xAAAA },     /* R71  - DC Servo 4 */
+	{ 72,  0xAAAA },     /* R72  - DC Servo 5 */
+	{ 90,  0x0000 },     /* R90  - Analogue HP 0 */
+	{ 94,  0x0000 },     /* R94  - Analogue Lineout 0 */
+	{ 98,  0x0000 },     /* R98  - Charge Pump 0 */
+	{ 104, 0x0004 },     /* R104 - Class W 0 */
+	{ 108, 0x0000 },     /* R108 - Write Sequencer 0 */
+	{ 109, 0x0000 },     /* R109 - Write Sequencer 1 */
+	{ 110, 0x0000 },     /* R110 - Write Sequencer 2 */
+	{ 111, 0x0000 },     /* R111 - Write Sequencer 3 */
+	{ 112, 0x0000 },     /* R112 - Write Sequencer 4 */
+	{ 116, 0x0000 },     /* R116 - FLL Control 1 */
+	{ 117, 0x0007 },     /* R117 - FLL Control 2 */
+	{ 118, 0x0000 },     /* R118 - FLL Control 3 */
+	{ 119, 0x2EE0 },     /* R119 - FLL Control 4 */
+	{ 120, 0x0004 },     /* R120 - FLL Control 5 */
+	{ 121, 0x0014 },     /* R121 - GPIO Control 1 */
+	{ 122, 0x0010 },     /* R122 - GPIO Control 2 */
+	{ 123, 0x0010 },     /* R123 - GPIO Control 3 */
+	{ 124, 0x0000 },     /* R124 - GPIO Control 4 */
+	{ 126, 0x0000 },     /* R126 - Digital Pulls */
+	{ 128, 0xFFFF },     /* R128 - Interrupt Status Mask */
+	{ 129, 0x0000 },     /* R129 - Interrupt Polarity */
+	{ 130, 0x0000 },     /* R130 - Interrupt Debounce */
+	{ 134, 0x0000 },     /* R134 - EQ1 */
+	{ 135, 0x000C },     /* R135 - EQ2 */
+	{ 136, 0x000C },     /* R136 - EQ3 */
+	{ 137, 0x000C },     /* R137 - EQ4 */
+	{ 138, 0x000C },     /* R138 - EQ5 */
+	{ 139, 0x000C },     /* R139 - EQ6 */
+	{ 140, 0x0FCA },     /* R140 - EQ7 */
+	{ 141, 0x0400 },     /* R141 - EQ8 */
+	{ 142, 0x00D8 },     /* R142 - EQ9 */
+	{ 143, 0x1EB5 },     /* R143 - EQ10 */
+	{ 144, 0xF145 },     /* R144 - EQ11 */
+	{ 145, 0x0B75 },     /* R145 - EQ12 */
+	{ 146, 0x01C5 },     /* R146 - EQ13 */
+	{ 147, 0x1C58 },     /* R147 - EQ14 */
+	{ 148, 0xF373 },     /* R148 - EQ15 */
+	{ 149, 0x0A54 },     /* R149 - EQ16 */
+	{ 150, 0x0558 },     /* R150 - EQ17 */
+	{ 151, 0x168E },     /* R151 - EQ18 */
+	{ 152, 0xF829 },     /* R152 - EQ19 */
+	{ 153, 0x07AD },     /* R153 - EQ20 */
+	{ 154, 0x1103 },     /* R154 - EQ21 */
+	{ 155, 0x0564 },     /* R155 - EQ22 */
+	{ 156, 0x0559 },     /* R156 - EQ23 */
+	{ 157, 0x4000 },     /* R157 - EQ24 */
+	{ 161, 0x0000 },     /* R161 - Control Interface Test 1 */
+	{ 204, 0x0000 },     /* R204 - Analogue Output Bias 0 */
+	{ 247, 0x0000 },     /* R247 - FLL NCO Test 0 */
+	{ 248, 0x0019 },     /* R248 - FLL NCO Test 1 */
 };
 
-static struct {
-	int readable;
-	int writable;
-	int vol;
-} wm8904_access[] = {
-	{ 0xFFFF, 0xFFFF, 1 }, /* R0   - SW Reset and ID */
-	{ 0x0000, 0x0000, 0 }, /* R1   - Revision */
-	{ 0x0000, 0x0000, 0 }, /* R2 */
-	{ 0x0000, 0x0000, 0 }, /* R3 */
-	{ 0x001F, 0x001F, 0 }, /* R4   - Bias Control 0 */
-	{ 0x0047, 0x0047, 0 }, /* R5   - VMID Control 0 */
-	{ 0x007F, 0x007F, 0 }, /* R6   - Mic Bias Control 0 */
-	{ 0xC007, 0xC007, 0 }, /* R7   - Mic Bias Control 1 */
-	{ 0x001E, 0x001E, 0 }, /* R8   - Analogue DAC 0 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R9   - mic Filter Control */
-	{ 0x0001, 0x0001, 0 }, /* R10  - Analogue ADC 0 */
-	{ 0x0000, 0x0000, 0 }, /* R11 */
-	{ 0x0003, 0x0003, 0 }, /* R12  - Power Management 0 */
-	{ 0x0000, 0x0000, 0 }, /* R13 */
-	{ 0x0003, 0x0003, 0 }, /* R14  - Power Management 2 */
-	{ 0x0003, 0x0003, 0 }, /* R15  - Power Management 3 */
-	{ 0x0000, 0x0000, 0 }, /* R16 */
-	{ 0x0000, 0x0000, 0 }, /* R17 */
-	{ 0x000F, 0x000F, 0 }, /* R18  - Power Management 6 */
-	{ 0x0000, 0x0000, 0 }, /* R19 */
-	{ 0x7001, 0x7001, 0 }, /* R20  - Clock Rates 0 */
-	{ 0x3C07, 0x3C07, 0 }, /* R21  - Clock Rates 1 */
-	{ 0xD00F, 0xD00F, 0 }, /* R22  - Clock Rates 2 */
-	{ 0x0000, 0x0000, 0 }, /* R23 */
-	{ 0x1FFF, 0x1FFF, 0 }, /* R24  - Audio Interface 0 */
-	{ 0x3DDF, 0x3DDF, 0 }, /* R25  - Audio Interface 1 */
-	{ 0x0F1F, 0x0F1F, 0 }, /* R26  - Audio Interface 2 */
-	{ 0x0FFF, 0x0FFF, 0 }, /* R27  - Audio Interface 3 */
-	{ 0x0000, 0x0000, 0 }, /* R28 */
-	{ 0x0000, 0x0000, 0 }, /* R29 */
-	{ 0x00FF, 0x01FF, 0 }, /* R30  - DAC Digital Volume Left */
-	{ 0x00FF, 0x01FF, 0 }, /* R31  - DAC Digital Volume Right */
-	{ 0x0FFF, 0x0FFF, 0 }, /* R32  - DAC Digital 0 */
-	{ 0x1E4E, 0x1E4E, 0 }, /* R33  - DAC Digital 1 */
-	{ 0x0000, 0x0000, 0 }, /* R34 */
-	{ 0x0000, 0x0000, 0 }, /* R35 */
-	{ 0x00FF, 0x01FF, 0 }, /* R36  - ADC Digital Volume Left */
-	{ 0x00FF, 0x01FF, 0 }, /* R37  - ADC Digital Volume Right */
-	{ 0x0073, 0x0073, 0 }, /* R38  - ADC Digital 0 */
-	{ 0x1800, 0x1800, 0 }, /* R39  - Digital Microphone 0 */
-	{ 0xDFEF, 0xDFEF, 0 }, /* R40  - DRC 0 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R41  - DRC 1 */
-	{ 0x003F, 0x003F, 0 }, /* R42  - DRC 2 */
-	{ 0x07FF, 0x07FF, 0 }, /* R43  - DRC 3 */
-	{ 0x009F, 0x009F, 0 }, /* R44  - Analogue Left Input 0 */
-	{ 0x009F, 0x009F, 0 }, /* R45  - Analogue Right Input 0 */
-	{ 0x007F, 0x007F, 0 }, /* R46  - Analogue Left Input 1 */
-	{ 0x007F, 0x007F, 0 }, /* R47  - Analogue Right Input 1 */
-	{ 0x0000, 0x0000, 0 }, /* R48 */
-	{ 0x0000, 0x0000, 0 }, /* R49 */
-	{ 0x0000, 0x0000, 0 }, /* R50 */
-	{ 0x0000, 0x0000, 0 }, /* R51 */
-	{ 0x0000, 0x0000, 0 }, /* R52 */
-	{ 0x0000, 0x0000, 0 }, /* R53 */
-	{ 0x0000, 0x0000, 0 }, /* R54 */
-	{ 0x0000, 0x0000, 0 }, /* R55 */
-	{ 0x0000, 0x0000, 0 }, /* R56 */
-	{ 0x017F, 0x01FF, 0 }, /* R57  - Analogue OUT1 Left */
-	{ 0x017F, 0x01FF, 0 }, /* R58  - Analogue OUT1 Right */
-	{ 0x017F, 0x01FF, 0 }, /* R59  - Analogue OUT2 Left */
-	{ 0x017F, 0x01FF, 0 }, /* R60  - Analogue OUT2 Right */
-	{ 0x000F, 0x000F, 0 }, /* R61  - Analogue OUT12 ZC */
-	{ 0x0000, 0x0000, 0 }, /* R62 */
-	{ 0x0000, 0x0000, 0 }, /* R63 */
-	{ 0x0000, 0x0000, 0 }, /* R64 */
-	{ 0x0000, 0x0000, 0 }, /* R65 */
-	{ 0x0000, 0x0000, 0 }, /* R66 */
-	{ 0x000F, 0x000F, 0 }, /* R67  - DC Servo 0 */
-	{ 0xFFFF, 0xFFFF, 1 }, /* R68  - DC Servo 1 */
-	{ 0x0F0F, 0x0F0F, 0 }, /* R69  - DC Servo 2 */
-	{ 0x0000, 0x0000, 0 }, /* R70 */
-	{ 0x007F, 0x007F, 0 }, /* R71  - DC Servo 4 */
-	{ 0x007F, 0x007F, 0 }, /* R72  - DC Servo 5 */
-	{ 0x00FF, 0x00FF, 1 }, /* R73  - DC Servo 6 */
-	{ 0x00FF, 0x00FF, 1 }, /* R74  - DC Servo 7 */
-	{ 0x00FF, 0x00FF, 1 }, /* R75  - DC Servo 8 */
-	{ 0x00FF, 0x00FF, 1 }, /* R76  - DC Servo 9 */
-	{ 0x0FFF, 0x0000, 1 }, /* R77  - DC Servo Readback 0 */
-	{ 0x0000, 0x0000, 0 }, /* R78 */
-	{ 0x0000, 0x0000, 0 }, /* R79 */
-	{ 0x0000, 0x0000, 0 }, /* R80 */
-	{ 0x0000, 0x0000, 0 }, /* R81 */
-	{ 0x0000, 0x0000, 0 }, /* R82 */
-	{ 0x0000, 0x0000, 0 }, /* R83 */
-	{ 0x0000, 0x0000, 0 }, /* R84 */
-	{ 0x0000, 0x0000, 0 }, /* R85 */
-	{ 0x0000, 0x0000, 0 }, /* R86 */
-	{ 0x0000, 0x0000, 0 }, /* R87 */
-	{ 0x0000, 0x0000, 0 }, /* R88 */
-	{ 0x0000, 0x0000, 0 }, /* R89 */
-	{ 0x00FF, 0x00FF, 0 }, /* R90  - Analogue HP 0 */
-	{ 0x0000, 0x0000, 0 }, /* R91 */
-	{ 0x0000, 0x0000, 0 }, /* R92 */
-	{ 0x0000, 0x0000, 0 }, /* R93 */
-	{ 0x00FF, 0x00FF, 0 }, /* R94  - Analogue Lineout 0 */
-	{ 0x0000, 0x0000, 0 }, /* R95 */
-	{ 0x0000, 0x0000, 0 }, /* R96 */
-	{ 0x0000, 0x0000, 0 }, /* R97 */
-	{ 0x0001, 0x0001, 0 }, /* R98  - Charge Pump 0 */
-	{ 0x0000, 0x0000, 0 }, /* R99 */
-	{ 0x0000, 0x0000, 0 }, /* R100 */
-	{ 0x0000, 0x0000, 0 }, /* R101 */
-	{ 0x0000, 0x0000, 0 }, /* R102 */
-	{ 0x0000, 0x0000, 0 }, /* R103 */
-	{ 0x0001, 0x0001, 0 }, /* R104 - Class W 0 */
-	{ 0x0000, 0x0000, 0 }, /* R105 */
-	{ 0x0000, 0x0000, 0 }, /* R106 */
-	{ 0x0000, 0x0000, 0 }, /* R107 */
-	{ 0x011F, 0x011F, 0 }, /* R108 - Write Sequencer 0 */
-	{ 0x7FFF, 0x7FFF, 0 }, /* R109 - Write Sequencer 1 */
-	{ 0x4FFF, 0x4FFF, 0 }, /* R110 - Write Sequencer 2 */
-	{ 0x003F, 0x033F, 0 }, /* R111 - Write Sequencer 3 */
-	{ 0x03F1, 0x0000, 0 }, /* R112 - Write Sequencer 4 */
-	{ 0x0000, 0x0000, 0 }, /* R113 */
-	{ 0x0000, 0x0000, 0 }, /* R114 */
-	{ 0x0000, 0x0000, 0 }, /* R115 */
-	{ 0x0007, 0x0007, 0 }, /* R116 - FLL Control 1 */
-	{ 0x3F77, 0x3F77, 0 }, /* R117 - FLL Control 2 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R118 - FLL Control 3 */
-	{ 0x7FEF, 0x7FEF, 0 }, /* R119 - FLL Control 4 */
-	{ 0x001B, 0x001B, 0 }, /* R120 - FLL Control 5 */
-	{ 0x003F, 0x003F, 0 }, /* R121 - GPIO Control 1 */
-	{ 0x003F, 0x003F, 0 }, /* R122 - GPIO Control 2 */
-	{ 0x003F, 0x003F, 0 }, /* R123 - GPIO Control 3 */
-	{ 0x038F, 0x038F, 0 }, /* R124 - GPIO Control 4 */
-	{ 0x0000, 0x0000, 0 }, /* R125 */
-	{ 0x00FF, 0x00FF, 0 }, /* R126 - Digital Pulls */
-	{ 0x07FF, 0x03FF, 1 }, /* R127 - Interrupt Status */
-	{ 0x03FF, 0x03FF, 0 }, /* R128 - Interrupt Status Mask */
-	{ 0x03FF, 0x03FF, 0 }, /* R129 - Interrupt Polarity */
-	{ 0x03FF, 0x03FF, 0 }, /* R130 - Interrupt Debounce */
-	{ 0x0000, 0x0000, 0 }, /* R131 */
-	{ 0x0000, 0x0000, 0 }, /* R132 */
-	{ 0x0000, 0x0000, 0 }, /* R133 */
-	{ 0x0001, 0x0001, 0 }, /* R134 - EQ1 */
-	{ 0x001F, 0x001F, 0 }, /* R135 - EQ2 */
-	{ 0x001F, 0x001F, 0 }, /* R136 - EQ3 */
-	{ 0x001F, 0x001F, 0 }, /* R137 - EQ4 */
-	{ 0x001F, 0x001F, 0 }, /* R138 - EQ5 */
-	{ 0x001F, 0x001F, 0 }, /* R139 - EQ6 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R140 - EQ7 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R141 - EQ8 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R142 - EQ9 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R143 - EQ10 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R144 - EQ11 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R145 - EQ12 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R146 - EQ13 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R147 - EQ14 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R148 - EQ15 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R149 - EQ16 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R150 - EQ17 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R151wm8523_dai - EQ18 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R152 - EQ19 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R153 - EQ20 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R154 - EQ21 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R155 - EQ22 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R156 - EQ23 */
-	{ 0xFFFF, 0xFFFF, 0 }, /* R157 - EQ24 */
-	{ 0x0000, 0x0000, 0 }, /* R158 */
-	{ 0x0000, 0x0000, 0 }, /* R159 */
-	{ 0x0000, 0x0000, 0 }, /* R160 */
-	{ 0x0002, 0x0002, 0 }, /* R161 - Control Interface Test 1 */
-	{ 0x0000, 0x0000, 0 }, /* R162 */
-	{ 0x0000, 0x0000, 0 }, /* R163 */
-	{ 0x0000, 0x0000, 0 }, /* R164 */
-	{ 0x0000, 0x0000, 0 }, /* R165 */
-	{ 0x0000, 0x0000, 0 }, /* R166 */
-	{ 0x0000, 0x0000, 0 }, /* R167 */
-	{ 0x0000, 0x0000, 0 }, /* R168 */
-	{ 0x0000, 0x0000, 0 }, /* R169 */
-	{ 0x0000, 0x0000, 0 }, /* R170 */
-	{ 0x0000, 0x0000, 0 }, /* R171 */
-	{ 0x0000, 0x0000, 0 }, /* R172 */
-	{ 0x0000, 0x0000, 0 }, /* R173 */
-	{ 0x0000, 0x0000, 0 }, /* R174 */
-	{ 0x0000, 0x0000, 0 }, /* R175 */
-	{ 0x0000, 0x0000, 0 }, /* R176 */
-	{ 0x0000, 0x0000, 0 }, /* R177 */
-	{ 0x0000, 0x0000, 0 }, /* R178 */
-	{ 0x0000, 0x0000, 0 }, /* R179 */
-	{ 0x0000, 0x0000, 0 }, /* R180 */
-	{ 0x0000, 0x0000, 0 }, /* R181 */
-	{ 0x0000, 0x0000, 0 }, /* R182 */
-	{ 0x0000, 0x0000, 0 }, /* R183 */
-	{ 0x0000, 0x0000, 0 }, /* R184 */
-	{ 0x0000, 0x0000, 0 }, /* R185 */
-	{ 0x0000, 0x0000, 0 }, /* R186 */
-	{ 0x0000, 0x0000, 0 }, /* R187 */
-	{ 0x0000, 0x0000, 0 }, /* R188 */
-	{ 0x0000, 0x0000, 0 }, /* R189 */
-	{ 0x0000, 0x0000, 0 }, /* R190 */
-	{ 0x0000, 0x0000, 0 }, /* R191 */
-	{ 0x0000, 0x0000, 0 }, /* R192 */
-	{ 0x0000, 0x0000, 0 }, /* R193 */
-	{ 0x0000, 0x0000, 0 }, /* R194 */
-	{ 0x0000, 0x0000, 0 }, /* R195 */
-	{ 0x0000, 0x0000, 0 }, /* R196 */
-	{ 0x0000, 0x0000, 0 }, /* R197 */
-	{ 0x0000, 0x0000, 0 }, /* R198 */
-	{ 0x0000, 0x0000, 0 }, /* R199 */
-	{ 0x0000, 0x0000, 0 }, /* R200 */
-	{ 0x0000, 0x0000, 0 }, /* R201 */
-	{ 0x0000, 0x0000, 0 }, /* R202 */
-	{ 0x0000, 0x0000, 0 }, /* R203 */
-	{ 0x0070, 0x0070, 0 }, /* R204 - Analogue Output Bias 0 */
-	{ 0x0000, 0x0000, 0 }, /* R205 */
-	{ 0x0000, 0x0000, 0 }, /* R206 */
-	{ 0x0000, 0x0000, 0 }, /* R207 */
-	{ 0x0000, 0x0000, 0 }, /* R208 */
-	{ 0x0000, 0x0000, 0 }, /* R209 */
-	{ 0x0000, 0x0000, 0 }, /* R210 */
-	{ 0x0000, 0x0000, 0 }, /* R211 */
-	{ 0x0000, 0x0000, 0 }, /* R212 */
-	{ 0x0000, 0x0000, 0 }, /* R213 */
-	{ 0x0000, 0x0000, 0 }, /* R214 */
-	{ 0x0000, 0x0000, 0 }, /* R215 */
-	{ 0x0000, 0x0000, 0 }, /* R216 */
-	{ 0x0000, 0x0000, 0 }, /* R217 */
-	{ 0x0000, 0x0000, 0 }, /* R218 */
-	{ 0x0000, 0x0000, 0 }, /* R219 */
-	{ 0x0000, 0x0000, 0 }, /* R220 */
-	{ 0x0000, 0x0000, 0 }, /* R221 */
-	{ 0x0000, 0x0000, 0 }, /* R222 */
-	{ 0x0000, 0x0000, 0 }, /* R223 */
-	{ 0x0000, 0x0000, 0 }, /* R224 */
-	{ 0x0000, 0x0000, 0 }, /* R225 */
-	{ 0x0000, 0x0000, 0 }, /* R226 */
-	{ 0x0000, 0x0000, 0 }, /* R227 */
-	{ 0x0000, 0x0000, 0 }, /* R228 */
-	{ 0x0000, 0x0000, 0 }, /* R229 */
-	{ 0x0000, 0x0000, 0 }, /* R230 */
-	{ 0x0000, 0x0000, 0 }, /* R231 */
-	{ 0x0000, 0x0000, 0 }, /* R232 */
-	{ 0x0000, 0x0000, 0 }, /* R233 */
-	{ 0x0000, 0x0000, 0 }, /* R234 */
-	{ 0x0000, 0x0000, 0 }, /* R235 */
-	{ 0x0000, 0x0000, 0 }, /* R236 */
-	{ 0x0000, 0x0000, 0 }, /* R237 */
-	{ 0x0000, 0x0000, 0 }, /* R238 */
-	{ 0x0000, 0x0000, 0 }, /* R239 */
-	{ 0x0000, 0x0000, 0 }, /* R240 */
-	{ 0x0000, 0x0000, 0 }, /* R241 */
-	{ 0x0000, 0x0000, 0 }, /* R242 */
-	{ 0x0000, 0x0000, 0 }, /* R243 */
-	{ 0x0000, 0x0000, 0 }, /* R244 */
-	{ 0x0000, 0x0000, 0 }, /* R245 */
-	{ 0x0000, 0x0000, 0 }, /* R246 */
-	{ 0x0001, 0x0001, 0 }, /* R247 - FLL NCO Test 0 */
-	{ 0x003F, 0x003F, 0 }, /* R248 - FLL NCO Test 1 */
-};
-
-static int wm8904_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
+static bool wm8904_volatile_register(struct device *dev, unsigned int reg)
 {
-	return wm8904_access[reg].vol;
+	switch (reg) {
+	case WM8904_SW_RESET_AND_ID:
+	case WM8904_REVISION:
+	case WM8904_DC_SERVO_1:
+	case WM8904_DC_SERVO_6:
+	case WM8904_DC_SERVO_7:
+	case WM8904_DC_SERVO_8:
+	case WM8904_DC_SERVO_9:
+	case WM8904_DC_SERVO_READBACK_0:
+	case WM8904_INTERRUPT_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool wm8904_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8904_SW_RESET_AND_ID:
+	case WM8904_REVISION:
+	case WM8904_BIAS_CONTROL_0:
+	case WM8904_VMID_CONTROL_0:
+	case WM8904_MIC_BIAS_CONTROL_0:
+	case WM8904_MIC_BIAS_CONTROL_1:
+	case WM8904_ANALOGUE_DAC_0:
+	case WM8904_MIC_FILTER_CONTROL:
+	case WM8904_ANALOGUE_ADC_0:
+	case WM8904_POWER_MANAGEMENT_0:
+	case WM8904_POWER_MANAGEMENT_2:
+	case WM8904_POWER_MANAGEMENT_3:
+	case WM8904_POWER_MANAGEMENT_6:
+	case WM8904_CLOCK_RATES_0:
+	case WM8904_CLOCK_RATES_1:
+	case WM8904_CLOCK_RATES_2:
+	case WM8904_AUDIO_INTERFACE_0:
+	case WM8904_AUDIO_INTERFACE_1:
+	case WM8904_AUDIO_INTERFACE_2:
+	case WM8904_AUDIO_INTERFACE_3:
+	case WM8904_DAC_DIGITAL_VOLUME_LEFT:
+	case WM8904_DAC_DIGITAL_VOLUME_RIGHT:
+	case WM8904_DAC_DIGITAL_0:
+	case WM8904_DAC_DIGITAL_1:
+	case WM8904_ADC_DIGITAL_VOLUME_LEFT:
+	case WM8904_ADC_DIGITAL_VOLUME_RIGHT:
+	case WM8904_ADC_DIGITAL_0:
+	case WM8904_DIGITAL_MICROPHONE_0:
+	case WM8904_DRC_0:
+	case WM8904_DRC_1:
+	case WM8904_DRC_2:
+	case WM8904_DRC_3:
+	case WM8904_ANALOGUE_LEFT_INPUT_0:
+	case WM8904_ANALOGUE_RIGHT_INPUT_0:
+	case WM8904_ANALOGUE_LEFT_INPUT_1:
+	case WM8904_ANALOGUE_RIGHT_INPUT_1:
+	case WM8904_ANALOGUE_OUT1_LEFT:
+	case WM8904_ANALOGUE_OUT1_RIGHT:
+	case WM8904_ANALOGUE_OUT2_LEFT:
+	case WM8904_ANALOGUE_OUT2_RIGHT:
+	case WM8904_ANALOGUE_OUT12_ZC:
+	case WM8904_DC_SERVO_0:
+	case WM8904_DC_SERVO_1:
+	case WM8904_DC_SERVO_2:
+	case WM8904_DC_SERVO_4:
+	case WM8904_DC_SERVO_5:
+	case WM8904_DC_SERVO_6:
+	case WM8904_DC_SERVO_7:
+	case WM8904_DC_SERVO_8:
+	case WM8904_DC_SERVO_9:
+	case WM8904_DC_SERVO_READBACK_0:
+	case WM8904_ANALOGUE_HP_0:
+	case WM8904_ANALOGUE_LINEOUT_0:
+	case WM8904_CHARGE_PUMP_0:
+	case WM8904_CLASS_W_0:
+	case WM8904_WRITE_SEQUENCER_0:
+	case WM8904_WRITE_SEQUENCER_1:
+	case WM8904_WRITE_SEQUENCER_2:
+	case WM8904_WRITE_SEQUENCER_3:
+	case WM8904_WRITE_SEQUENCER_4:
+	case WM8904_FLL_CONTROL_1:
+	case WM8904_FLL_CONTROL_2:
+	case WM8904_FLL_CONTROL_3:
+	case WM8904_FLL_CONTROL_4:
+	case WM8904_FLL_CONTROL_5:
+	case WM8904_GPIO_CONTROL_1:
+	case WM8904_GPIO_CONTROL_2:
+	case WM8904_GPIO_CONTROL_3:
+	case WM8904_GPIO_CONTROL_4:
+	case WM8904_DIGITAL_PULLS:
+	case WM8904_INTERRUPT_STATUS:
+	case WM8904_INTERRUPT_STATUS_MASK:
+	case WM8904_INTERRUPT_POLARITY:
+	case WM8904_INTERRUPT_DEBOUNCE:
+	case WM8904_EQ1:
+	case WM8904_EQ2:
+	case WM8904_EQ3:
+	case WM8904_EQ4:
+	case WM8904_EQ5:
+	case WM8904_EQ6:
+	case WM8904_EQ7:
+	case WM8904_EQ8:
+	case WM8904_EQ9:
+	case WM8904_EQ10:
+	case WM8904_EQ11:
+	case WM8904_EQ12:
+	case WM8904_EQ13:
+	case WM8904_EQ14:
+	case WM8904_EQ15:
+	case WM8904_EQ16:
+	case WM8904_EQ17:
+	case WM8904_EQ18:
+	case WM8904_EQ19:
+	case WM8904_EQ20:
+	case WM8904_EQ21:
+	case WM8904_EQ22:
+	case WM8904_EQ23:
+	case WM8904_EQ24:
+	case WM8904_CONTROL_INTERFACE_TEST_1:
+	case WM8904_ADC_TEST_0:
+	case WM8904_ANALOGUE_OUTPUT_BIAS_0:
+	case WM8904_FLL_NCO_TEST_0:
+	case WM8904_FLL_NCO_TEST_1:
+		return true;
+	default:
+		return true;
+	}
 }
 
 static int wm8904_reset(struct snd_soc_codec *codec)
@@ -855,6 +570,29 @@
 static const struct soc_enum hpf_mode =
 	SOC_ENUM_SINGLE(WM8904_ADC_DIGITAL_0, 5, 4, hpf_mode_text);
 
+static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int val;
+	int ret;
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+	if (ret < 0)
+		return ret;
+
+	if (ucontrol->value.integer.value[0])
+		val = 0;
+	else
+		val = WM8904_ADC_128_OSR_TST_MODE | WM8904_ADC_BIASX1P5;
+
+	snd_soc_update_bits(codec, WM8904_ADC_TEST_0,
+			    WM8904_ADC_128_OSR_TST_MODE | WM8904_ADC_BIASX1P5,
+			    val);
+
+	return ret;
+}
+
 static const struct snd_kcontrol_new wm8904_adc_snd_controls[] = {
 SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8904_ADC_DIGITAL_VOLUME_LEFT,
 		 WM8904_ADC_DIGITAL_VOLUME_RIGHT, 1, 119, 0, digital_tlv),
@@ -871,7 +609,12 @@
 SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0),
 SOC_ENUM("High Pass Filter Mode", hpf_mode),
 
-SOC_SINGLE("ADC 128x OSR Switch", WM8904_ANALOGUE_ADC_0, 0, 1, 0),
+{       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "ADC 128x OSR Switch",
+	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,
+	.put = wm8904_adc_osr_put,
+	.private_value = SOC_SINGLE_VALUE(WM8904_ANALOGUE_ADC_0, 0, 1, 0),
+},
 };
 
 static const char *drc_path_text[] = {
@@ -1433,11 +1176,11 @@
 
 	switch (wm8904->devtype) {
 	case WM8904:
-		snd_soc_add_controls(codec, wm8904_adc_snd_controls,
+		snd_soc_add_codec_controls(codec, wm8904_adc_snd_controls,
 				     ARRAY_SIZE(wm8904_adc_snd_controls));
-		snd_soc_add_controls(codec, wm8904_dac_snd_controls,
+		snd_soc_add_codec_controls(codec, wm8904_dac_snd_controls,
 				     ARRAY_SIZE(wm8904_dac_snd_controls));
-		snd_soc_add_controls(codec, wm8904_snd_controls,
+		snd_soc_add_codec_controls(codec, wm8904_snd_controls,
 				     ARRAY_SIZE(wm8904_snd_controls));
 
 		snd_soc_dapm_new_controls(dapm, wm8904_adc_dapm_widgets,
@@ -1458,7 +1201,7 @@
 		break;
 
 	case WM8912:
-		snd_soc_add_controls(codec, wm8904_dac_snd_controls,
+		snd_soc_add_codec_controls(codec, wm8904_dac_snd_controls,
 				     ARRAY_SIZE(wm8904_dac_snd_controls));
 
 		snd_soc_dapm_new_controls(dapm, wm8904_dac_dapm_widgets,
@@ -2088,32 +1831,6 @@
 	return 0;
 }
 
-static void wm8904_sync_cache(struct snd_soc_codec *codec)
-{
-	u16 *reg_cache = codec->reg_cache;
-	int i;
-
-	if (!codec->cache_sync)
-		return;
-
-	codec->cache_only = 0;
-
-	/* Sync back cached values if they're different from the
-	 * hardware default.
-	 */
-	for (i = 1; i < codec->driver->reg_cache_size; i++) {
-		if (!wm8904_access[i].writable)
-			continue;
-
-		if (reg_cache[i] == wm8904_reg[i])
-			continue;
-
-		snd_soc_write(codec, i, reg_cache[i]);
-	}
-
-	codec->cache_sync = 0;
-}
-
 static int wm8904_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
@@ -2146,7 +1863,7 @@
 				return ret;
 			}
 
-			wm8904_sync_cache(codec);
+			regcache_sync(wm8904->regmap);
 
 			/* Enable bias */
 			snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
@@ -2303,7 +2020,7 @@
 	wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts;
 	wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts;
 
-	ret = snd_soc_add_controls(codec, &control, 1);
+	ret = snd_soc_add_codec_controls(codec, &control, 1);
 	if (ret != 0)
 		dev_err(codec->dev,
 			"Failed to add ReTune Mobile control: %d\n", ret);
@@ -2316,7 +2033,7 @@
 	int ret, i;
 
 	if (!pdata) {
-		snd_soc_add_controls(codec, wm8904_eq_controls,
+		snd_soc_add_codec_controls(codec, wm8904_eq_controls,
 				     ARRAY_SIZE(wm8904_eq_controls));
 		return;
 	}
@@ -2344,7 +2061,7 @@
 		wm8904->drc_enum.max = pdata->num_drc_cfgs;
 		wm8904->drc_enum.texts = wm8904->drc_texts;
 
-		ret = snd_soc_add_controls(codec, &control, 1);
+		ret = snd_soc_add_codec_controls(codec, &control, 1);
 		if (ret != 0)
 			dev_err(codec->dev,
 				"Failed to add DRC mode control: %d\n", ret);
@@ -2358,7 +2075,7 @@
 	if (pdata->num_retune_mobile_cfgs)
 		wm8904_handle_retune_mobile_pdata(codec);
 	else
-		snd_soc_add_controls(codec, wm8904_eq_controls,
+		snd_soc_add_codec_controls(codec, wm8904_eq_controls,
 				     ARRAY_SIZE(wm8904_eq_controls));
 }
 
@@ -2371,7 +2088,7 @@
 	int ret, i;
 
 	codec->cache_sync = 1;
-	codec->dapm.idle_bias_off = 1;
+	codec->control_data = wm8904->regmap;
 
 	switch (wm8904->devtype) {
 	case WM8904:
@@ -2385,7 +2102,7 @@
 		return -EINVAL;
 	}
 
-	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
 	if (ret != 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
@@ -2413,7 +2130,7 @@
 		dev_err(codec->dev, "Failed to read ID register\n");
 		goto err_enable;
 	}
-	if (ret != wm8904_reg[WM8904_SW_RESET_AND_ID]) {
+	if (ret != 0x8904) {
 		dev_err(codec->dev, "Device is not a WM8904, ID is %x\n", ret);
 		ret = -EINVAL;
 		goto err_enable;
@@ -2519,38 +2236,62 @@
 	.suspend =	wm8904_suspend,
 	.resume =	wm8904_resume,
 	.set_bias_level = wm8904_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(wm8904_reg),
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = wm8904_reg,
-	.volatile_register = wm8904_volatile_register,
+	.idle_bias_off = true,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static const struct regmap_config wm8904_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = WM8904_MAX_REGISTER,
+	.volatile_reg = wm8904_volatile_register,
+	.readable_reg = wm8904_readable_register,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8904_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8904_reg_defaults),
+};
+
 static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
 				      const struct i2c_device_id *id)
 {
 	struct wm8904_priv *wm8904;
 	int ret;
 
-	wm8904 = kzalloc(sizeof(struct wm8904_priv), GFP_KERNEL);
+	wm8904 = devm_kzalloc(&i2c->dev, sizeof(struct wm8904_priv),
+			      GFP_KERNEL);
 	if (wm8904 == NULL)
 		return -ENOMEM;
 
+	wm8904->regmap = regmap_init_i2c(i2c, &wm8904_regmap);
+	if (IS_ERR(wm8904->regmap)) {
+		ret = PTR_ERR(wm8904->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
 	wm8904->devtype = id->driver_data;
 	i2c_set_clientdata(i2c, wm8904);
 	wm8904->pdata = i2c->dev.platform_data;
 
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_wm8904, &wm8904_dai, 1);
-	if (ret < 0)
-		kfree(wm8904);
+	if (ret != 0)
+		goto err;
+
+	return 0;
+
+err:
+	regmap_exit(wm8904->regmap);
 	return ret;
 }
 
 static __devexit int wm8904_i2c_remove(struct i2c_client *client)
 {
+	struct wm8904_priv *wm8904 = i2c_get_clientdata(client);
 	snd_soc_unregister_codec(&client->dev);
-	kfree(i2c_get_clientdata(client));
+	regmap_exit(wm8904->regmap);
 	return 0;
 }
 
@@ -2571,27 +2312,22 @@
 	.remove =   __devexit_p(wm8904_i2c_remove),
 	.id_table = wm8904_i2c_id,
 };
-#endif
 
 static int __init wm8904_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	ret = i2c_add_driver(&wm8904_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register wm8904 I2C driver: %d\n",
 		       ret);
 	}
-#endif
 	return ret;
 }
 module_init(wm8904_modinit);
 
 static void __exit wm8904_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	i2c_del_driver(&wm8904_i2c_driver);
-#endif
 }
 module_exit(wm8904_exit);
 
diff --git a/sound/soc/codecs/wm8904.h b/sound/soc/codecs/wm8904.h
index 9e8c841..c29a0e8 100644
--- a/sound/soc/codecs/wm8904.h
+++ b/sound/soc/codecs/wm8904.h
@@ -123,6 +123,7 @@
 #define WM8904_EQ23                             0x9C
 #define WM8904_EQ24                             0x9D
 #define WM8904_CONTROL_INTERFACE_TEST_1         0xA1
+#define WM8904_ADC_TEST_0			0xC6
 #define WM8904_ANALOGUE_OUTPUT_BIAS_0           0xCC
 #define WM8904_FLL_NCO_TEST_0                   0xF7
 #define WM8904_FLL_NCO_TEST_1                   0xF8
@@ -1557,6 +1558,16 @@
 #define WM8904_USER_KEY_WIDTH                        1  /* USER_KEY */
 
 /*
+ * R198 (0xC6) - ADC Test 0
+ */
+#define WM8904_ADC_128_OSR_TST_MODE             0x0004  /* ADC_128_OSR_TST_MODE */
+#define WM8904_ADC_128_OSR_TST_MODE_SHIFT            2  /* ADC_128_OSR_TST_MODE */
+#define WM8904_ADC_128_OSR_TST_MODE_WIDTH            1  /* ADC_128_OSR_TST_MODE */
+#define WM8904_ADC_BIASX1P5                     0x0001  /* ADC_BIASX1P5 */
+#define WM8904_ADC_BIASX1P5_SHIFT                    0  /* ADC_BIASX1P5 */
+#define WM8904_ADC_BIASX1P5_WIDTH                    1  /* ADC_BIASX1P5 */
+
+/*
  * R204 (0xCC) - Analogue Output Bias 0
  */
 #define WM8904_PGA_BIAS_MASK                    0x0070  /* PGA_BIAS - [6:4] */
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index 14039ea..d2883af 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -717,7 +717,7 @@
 			return ret;
 	}
 
-	ret = snd_soc_add_controls(codec, wm8940_snd_controls,
+	ret = snd_soc_add_codec_controls(codec, wm8940_snd_controls,
 			     ARRAY_SIZE(wm8940_snd_controls));
 	if (ret)
 		return ret;
@@ -743,14 +743,14 @@
 	.volatile_register = wm8940_volatile_register,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8940_i2c_probe(struct i2c_client *i2c,
 				      const struct i2c_device_id *id)
 {
 	struct wm8940_priv *wm8940;
 	int ret;
 
-	wm8940 = kzalloc(sizeof(struct wm8940_priv), GFP_KERNEL);
+	wm8940 = devm_kzalloc(&i2c->dev, sizeof(struct wm8940_priv),
+			      GFP_KERNEL);
 	if (wm8940 == NULL)
 		return -ENOMEM;
 
@@ -759,15 +759,14 @@
 
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_wm8940, &wm8940_dai, 1);
-	if (ret < 0)
-		kfree(wm8940);
+
 	return ret;
 }
 
 static __devexit int wm8940_i2c_remove(struct i2c_client *client)
 {
 	snd_soc_unregister_codec(&client->dev);
-	kfree(i2c_get_clientdata(client));
+
 	return 0;
 }
 
@@ -786,27 +785,22 @@
 	.remove =   __devexit_p(wm8940_i2c_remove),
 	.id_table = wm8940_i2c_id,
 };
-#endif
 
 static int __init wm8940_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	ret = i2c_add_driver(&wm8940_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register wm8940 I2C driver: %d\n",
 		       ret);
 	}
-#endif
 	return ret;
 }
 module_init(wm8940_modinit);
 
 static void __exit wm8940_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	i2c_del_driver(&wm8940_i2c_driver);
-#endif
 }
 module_exit(wm8940_exit);
 
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index 9245481..61fe974 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -38,7 +39,7 @@
 
 /* codec private data */
 struct wm8955_priv {
-	enum snd_soc_control_type control_type;
+	struct regmap *regmap;
 
 	unsigned int mclk_rate;
 
@@ -48,69 +49,85 @@
 	struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES];
 };
 
-static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = {
-	0x0000,     /* R0 */
-	0x0000,     /* R1 */
-	0x0079,     /* R2  - LOUT1 volume */
-	0x0079,     /* R3  - ROUT1 volume */
-	0x0000,     /* R4 */
-	0x0008,     /* R5  - DAC Control */
-	0x0000,     /* R6 */
-	0x000A,     /* R7  - Audio Interface */
-	0x0000,     /* R8  - Sample Rate */
-	0x0000,     /* R9 */
-	0x00FF,     /* R10 - Left DAC volume */
-	0x00FF,     /* R11 - Right DAC volume */
-	0x000F,     /* R12 - Bass control */
-	0x000F,     /* R13 - Treble control */
-	0x0000,     /* R14 */
-	0x0000,     /* R15 - Reset */
-	0x0000,     /* R16 */
-	0x0000,     /* R17 */
-	0x0000,     /* R18 */
-	0x0000,     /* R19 */
-	0x0000,     /* R20 */
-	0x0000,     /* R21 */
-	0x0000,     /* R22 */
-	0x00C1,     /* R23 - Additional control (1) */
-	0x0000,     /* R24 - Additional control (2) */
-	0x0000,     /* R25 - Power Management (1) */
-	0x0000,     /* R26 - Power Management (2) */
-	0x0000,     /* R27 - Additional Control (3) */
-	0x0000,     /* R28 */
-	0x0000,     /* R29 */
-	0x0000,     /* R30 */
-	0x0000,     /* R31 */
-	0x0000,     /* R32 */
-	0x0000,     /* R33 */
-	0x0050,     /* R34 - Left out Mix (1) */
-	0x0050,     /* R35 - Left out Mix (2) */
-	0x0050,     /* R36 - Right out Mix (1) */
-	0x0050,     /* R37 - Right Out Mix (2) */
-	0x0050,     /* R38 - Mono out Mix (1) */
-	0x0050,     /* R39 - Mono out Mix (2) */
-	0x0079,     /* R40 - LOUT2 volume */
-	0x0079,     /* R41 - ROUT2 volume */
-	0x0079,     /* R42 - MONOOUT volume */
-	0x0000,     /* R43 - Clocking / PLL */
-	0x0103,     /* R44 - PLL Control 1 */
-	0x0024,     /* R45 - PLL Control 2 */
-	0x01BA,     /* R46 - PLL Control 3 */
-	0x0000,     /* R47 */
-	0x0000,     /* R48 */
-	0x0000,     /* R49 */
-	0x0000,     /* R50 */
-	0x0000,     /* R51 */
-	0x0000,     /* R52 */
-	0x0000,     /* R53 */
-	0x0000,     /* R54 */
-	0x0000,     /* R55 */
-	0x0000,     /* R56 */
-	0x0000,     /* R57 */
-	0x0000,     /* R58 */
-	0x0000,     /* R59 - PLL Control 4 */
+static const struct reg_default wm8955_reg_defaults[] = {
+	{ 2,  0x0079 },     /* R2  - LOUT1 volume */
+	{ 3,  0x0079 },     /* R3  - ROUT1 volume */
+	{ 5,  0x0008 },     /* R5  - DAC Control */
+	{ 7,  0x000A },     /* R7  - Audio Interface */
+	{ 8,  0x0000 },     /* R8  - Sample Rate */
+	{ 10, 0x00FF },     /* R10 - Left DAC volume */
+	{ 11, 0x00FF },     /* R11 - Right DAC volume */
+	{ 12, 0x000F },     /* R12 - Bass control */
+	{ 13, 0x000F },     /* R13 - Treble control */
+	{ 23, 0x00C1 },     /* R23 - Additional control (1) */
+	{ 24, 0x0000 },     /* R24 - Additional control (2) */
+	{ 25, 0x0000 },     /* R25 - Power Management (1) */
+	{ 26, 0x0000 },     /* R26 - Power Management (2) */
+	{ 27, 0x0000 },     /* R27 - Additional Control (3) */
+	{ 34, 0x0050 },     /* R34 - Left out Mix (1) */
+	{ 35, 0x0050 },     /* R35 - Left out Mix (2) */
+	{ 36, 0x0050 },     /* R36 - Right out Mix (1) */
+	{ 37, 0x0050 },     /* R37 - Right Out Mix (2) */
+	{ 38, 0x0050 },     /* R38 - Mono out Mix (1) */
+	{ 39, 0x0050 },     /* R39 - Mono out Mix (2) */
+	{ 40, 0x0079 },     /* R40 - LOUT2 volume */
+	{ 41, 0x0079 },     /* R41 - ROUT2 volume */
+	{ 42, 0x0079 },     /* R42 - MONOOUT volume */
+	{ 43, 0x0000 },     /* R43 - Clocking / PLL */
+	{ 44, 0x0103 },     /* R44 - PLL Control 1 */
+	{ 45, 0x0024 },     /* R45 - PLL Control 2 */
+	{ 46, 0x01BA },     /* R46 - PLL Control 3 */
+	{ 59, 0x0000 },     /* R59 - PLL Control 4 */
 };
 
+static bool wm8955_writeable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8955_LOUT1_VOLUME:
+	case WM8955_ROUT1_VOLUME:
+	case WM8955_DAC_CONTROL:
+	case WM8955_AUDIO_INTERFACE:
+	case WM8955_SAMPLE_RATE:
+	case WM8955_LEFT_DAC_VOLUME:
+	case WM8955_RIGHT_DAC_VOLUME:
+	case WM8955_BASS_CONTROL:
+	case WM8955_TREBLE_CONTROL:
+	case WM8955_RESET:
+	case WM8955_ADDITIONAL_CONTROL_1:
+	case WM8955_ADDITIONAL_CONTROL_2:
+	case WM8955_POWER_MANAGEMENT_1:
+	case WM8955_POWER_MANAGEMENT_2:
+	case WM8955_ADDITIONAL_CONTROL_3:
+	case WM8955_LEFT_OUT_MIX_1:
+	case WM8955_LEFT_OUT_MIX_2:
+	case WM8955_RIGHT_OUT_MIX_1:
+	case WM8955_RIGHT_OUT_MIX_2:
+	case WM8955_MONO_OUT_MIX_1:
+	case WM8955_MONO_OUT_MIX_2:
+	case WM8955_LOUT2_VOLUME:
+	case WM8955_ROUT2_VOLUME:
+	case WM8955_MONOOUT_VOLUME:
+	case WM8955_CLOCKING_PLL:
+	case WM8955_PLL_CONTROL_1:
+	case WM8955_PLL_CONTROL_2:
+	case WM8955_PLL_CONTROL_3:
+	case WM8955_PLL_CONTROL_4:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool wm8955_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8955_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
 static int wm8955_reset(struct snd_soc_codec *codec)
 {
 	return snd_soc_write(codec, WM8955_RESET, 0);
@@ -527,7 +544,7 @@
 SND_SOC_DAPM_OUTPUT("OUT3"),
 };
 
-static const struct snd_soc_dapm_route wm8955_intercon[] = {
+static const struct snd_soc_dapm_route wm8955_dapm_routes[] = {
 	{ "DACL", NULL, "SYSCLK" },
 	{ "DACR", NULL, "SYSCLK" },
 
@@ -572,21 +589,6 @@
 	{ "OUT3", NULL, "OUT3 PGA" },
 };
 
-static int wm8955_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_add_controls(codec, wm8955_snd_controls,
-			     ARRAY_SIZE(wm8955_snd_controls));
-
-	snd_soc_dapm_new_controls(dapm, wm8955_dapm_widgets,
-				  ARRAY_SIZE(wm8955_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, wm8955_intercon,
-				ARRAY_SIZE(wm8955_intercon));
-
-	return 0;
-}
-
 static int wm8955_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
@@ -765,8 +767,7 @@
 				 enum snd_soc_bias_level level)
 {
 	struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
-	u16 *reg_cache = codec->reg_cache;
-	int ret, i;
+	int ret;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -795,18 +796,7 @@
 				return ret;
 			}
 
-			/* Sync back cached values if they're
-			 * different from the hardware default.
-			 */
-			for (i = 0; i < codec->driver->reg_cache_size; i++) {
-				if (i == WM8955_RESET)
-					continue;
-
-				if (reg_cache[i] == wm8955_reg[i])
-					continue;
-
-				snd_soc_write(codec, i, reg_cache[i]);
-			}
+			regcache_sync(wm8955->regmap);
 
 			/* Enable VREF and VMID */
 			snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
@@ -880,8 +870,12 @@
 #ifdef CONFIG_PM
 static int wm8955_suspend(struct snd_soc_codec *codec)
 {
+	struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+
 	wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
+	regcache_mark_dirty(wm8955->regmap);
+
 	return 0;
 }
 
@@ -900,10 +894,11 @@
 {
 	struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
 	struct wm8955_pdata *pdata = dev_get_platdata(codec->dev);
-	u16 *reg_cache = codec->reg_cache;
 	int ret, i;
 
-	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8955->control_type);
+	codec->control_data = wm8955->regmap;
+
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
 	if (ret != 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
@@ -958,12 +953,12 @@
 	/* Set platform data values */
 	if (pdata) {
 		if (pdata->out2_speaker)
-			reg_cache[WM8955_ADDITIONAL_CONTROL_2]
-				|= WM8955_ROUT2INV;
+			snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_2,
+					    WM8955_ROUT2INV, WM8955_ROUT2INV);
 
 		if (pdata->monoin_diff)
-			reg_cache[WM8955_MONO_OUT_MIX_1]
-				|= WM8955_DMEN;
+			snd_soc_update_bits(codec, WM8955_MONO_OUT_MIX_1,
+					    WM8955_DMEN, WM8955_DMEN);
 	}
 
 	wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -971,7 +966,6 @@
 	/* Bias level configuration will have done an extra enable */
 	regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
 
-	wm8955_add_widgets(codec);
 	return 0;
 
 err_enable:
@@ -996,36 +990,68 @@
 	.suspend =	wm8955_suspend,
 	.resume =	wm8955_resume,
 	.set_bias_level = wm8955_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(wm8955_reg),
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = wm8955_reg,
+
+	.controls =	wm8955_snd_controls,
+	.num_controls = ARRAY_SIZE(wm8955_snd_controls),
+	.dapm_widgets = wm8955_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8955_dapm_widgets),
+	.dapm_routes =	wm8955_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm8955_dapm_routes),
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static const struct regmap_config wm8955_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = WM8955_MAX_REGISTER,
+	.volatile_reg = wm8955_volatile,
+	.writeable_reg = wm8955_writeable,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8955_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8955_reg_defaults),
+};
+
 static __devinit int wm8955_i2c_probe(struct i2c_client *i2c,
 				      const struct i2c_device_id *id)
 {
 	struct wm8955_priv *wm8955;
 	int ret;
 
-	wm8955 = kzalloc(sizeof(struct wm8955_priv), GFP_KERNEL);
+	wm8955 = devm_kzalloc(&i2c->dev, sizeof(struct wm8955_priv),
+			      GFP_KERNEL);
 	if (wm8955 == NULL)
 		return -ENOMEM;
 
+	wm8955->regmap = regmap_init_i2c(i2c, &wm8955_regmap);
+	if (IS_ERR(wm8955->regmap)) {
+		ret = PTR_ERR(wm8955->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
 	i2c_set_clientdata(i2c, wm8955);
-	wm8955->control_type = SND_SOC_I2C;
 
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_wm8955, &wm8955_dai, 1);
-	if (ret < 0)
-		kfree(wm8955);
+	if (ret != 0)
+		goto err;
+
+	return ret;
+
+err:
+	regmap_exit(wm8955->regmap);
 	return ret;
 }
 
 static __devexit int wm8955_i2c_remove(struct i2c_client *client)
 {
+	struct wm8955_priv *wm8955 = i2c_get_clientdata(client);
+
 	snd_soc_unregister_codec(&client->dev);
-	kfree(i2c_get_clientdata(client));
+	regmap_exit(wm8955->regmap);
+
 	return 0;
 }
 
@@ -1044,27 +1070,22 @@
 	.remove =   __devexit_p(wm8955_i2c_remove),
 	.id_table = wm8955_i2c_id,
 };
-#endif
 
 static int __init wm8955_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	ret = i2c_add_driver(&wm8955_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register WM8955 I2C driver: %d\n",
 		       ret);
 	}
-#endif
 	return ret;
 }
 module_init(wm8955_modinit);
 
 static void __exit wm8955_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	i2c_del_driver(&wm8955_i2c_driver);
-#endif
 }
 module_exit(wm8955_exit);
 
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
index 40ac888..1332692 100644
--- a/sound/soc/codecs/wm8958-dsp2.c
+++ b/sound/soc/codecs/wm8958-dsp2.c
@@ -920,11 +920,11 @@
 
 	wm8994->dsp_active = -1;
 
-	snd_soc_add_controls(codec, wm8958_mbc_snd_controls,
+	snd_soc_add_codec_controls(codec, wm8958_mbc_snd_controls,
 			     ARRAY_SIZE(wm8958_mbc_snd_controls));
-	snd_soc_add_controls(codec, wm8958_vss_snd_controls,
+	snd_soc_add_codec_controls(codec, wm8958_vss_snd_controls,
 			     ARRAY_SIZE(wm8958_vss_snd_controls));
-	snd_soc_add_controls(codec, wm8958_enh_eq_snd_controls,
+	snd_soc_add_codec_controls(codec, wm8958_enh_eq_snd_controls,
 			     ARRAY_SIZE(wm8958_enh_eq_snd_controls));
 
 
@@ -958,7 +958,7 @@
 		wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
 		wm8994->mbc_enum.texts = wm8994->mbc_texts;
 
-		ret = snd_soc_add_controls(wm8994->codec, control, 1);
+		ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
 		if (ret != 0)
 			dev_err(wm8994->codec->dev,
 				"Failed to add MBC mode controls: %d\n", ret);
@@ -986,7 +986,7 @@
 		wm8994->vss_enum.max = pdata->num_vss_cfgs;
 		wm8994->vss_enum.texts = wm8994->vss_texts;
 
-		ret = snd_soc_add_controls(wm8994->codec, control, 1);
+		ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
 		if (ret != 0)
 			dev_err(wm8994->codec->dev,
 				"Failed to add VSS mode controls: %d\n", ret);
@@ -1015,7 +1015,7 @@
 		wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs;
 		wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
 
-		ret = snd_soc_add_controls(wm8994->codec, control, 1);
+		ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
 		if (ret != 0)
 			dev_err(wm8994->codec->dev,
 				"Failed to add VSS HPFmode controls: %d\n",
@@ -1045,7 +1045,7 @@
 		wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs;
 		wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
 
-		ret = snd_soc_add_controls(wm8994->codec, control, 1);
+		ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
 		if (ret != 0)
 			dev_err(wm8994->codec->dev,
 				"Failed to add enhanced EQ controls: %d\n",
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index e5caae3..840d720 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -940,7 +940,7 @@
 	snd_soc_update_bits(codec, WM8960_LOUT2, 0x100, 0x100);
 	snd_soc_update_bits(codec, WM8960_ROUT2, 0x100, 0x100);
 
-	snd_soc_add_controls(codec, wm8960_snd_controls,
+	snd_soc_add_codec_controls(codec, wm8960_snd_controls,
 				     ARRAY_SIZE(wm8960_snd_controls));
 	wm8960_add_widgets(codec);
 
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 4f20c72..05ea7c2 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -1022,7 +1022,7 @@
 
 	wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-	snd_soc_add_controls(codec, wm8961_snd_controls,
+	snd_soc_add_codec_controls(codec, wm8961_snd_controls,
 				ARRAY_SIZE(wm8961_snd_controls));
 	snd_soc_dapm_new_controls(dapm, wm8961_dapm_widgets,
 				  ARRAY_SIZE(wm8961_dapm_widgets));
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 0ac228b..15d467f 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -20,6 +20,7 @@
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
@@ -115,11 +116,11 @@
 	{ 1, 0x049F },   /* R1     - Right Input volume */
 	{ 2, 0x0000 },   /* R2     - HPOUTL volume */
 	{ 3, 0x0000 },   /* R3     - HPOUTR volume */
-	{ 4, 0x0020 },   /* R4     - Clocking1 */
+
 	{ 5, 0x0018 },   /* R5     - ADC & DAC Control 1 */
 	{ 6, 0x2008 },   /* R6     - ADC & DAC Control 2 */
 	{ 7, 0x000A },   /* R7     - Audio Interface 0 */
-	{ 8, 0x01E4 },   /* R8     - Clocking2 */
+
 	{ 9, 0x0300 },   /* R9     - Audio Interface 1 */
 	{ 10, 0x00C0 },  /* R10    - Left DAC volume */
 	{ 11, 0x00C0 },  /* R11    - Right DAC volume */
@@ -128,7 +129,7 @@
 	{ 15, 0x6243 },   /* R15    - Software Reset */
 
 	{ 17, 0x007B },   /* R17    - ALC1 */
-	{ 18, 0x0000 },   /* R18    - ALC2 */
+
 	{ 19, 0x1C32 },   /* R19    - ALC3 */
 	{ 20, 0x3200 },   /* R20    - Noise Gate */
 	{ 21, 0x00C0 },   /* R21    - Left ADC volume */
@@ -152,10 +153,6 @@
 	{ 40, 0x0000 },   /* R40    - SPKOUTL volume */
 	{ 41, 0x0000 },   /* R41    - SPKOUTR volume */
 
-	{ 47, 0x0000 },   /* R47    - Thermal Shutdown Status */
-	{ 48, 0x8027 },   /* R48    - Additional Control (4) */
-	{ 49, 0x0010 },   /* R49    - Class D Control 1 */
-
 	{ 51, 0x0003 },   /* R51    - Class D Control 2 */
 
 	{ 56, 0x0506 },   /* R56    - Clocking 4 */
@@ -167,8 +164,6 @@
 
 	{ 64, 0x0810 },   /* R64    - DC Servo 4 */
 
-	{ 66, 0x0000 },   /* R66    - DC Servo 6 */
-
 	{ 68, 0x001B },   /* R68    - Analogue PGA Bias */
 	{ 69, 0x0000 },   /* R69    - Analogue HP 0 */
 
@@ -207,8 +202,6 @@
 	{ 126, 0x000D },   /* R126   - Analogue Clocking3 */
 	{ 127, 0x0000 },   /* R127   - PLL Software Reset */
 
-	{ 129, 0x0000 },   /* R129   - PLL2 */
-
 	{ 131, 0x0000 },   /* R131   - PLL 4 */
 
 	{ 136, 0x0067 },   /* R136   - PLL 9 */
@@ -303,9 +296,6 @@
 	{ 516, 0x8100 },   /* R516   - GPIO 5 */
 	{ 517, 0x8100 },   /* R517   - GPIO 6 */
 
-	{ 560, 0x0000 },   /* R560   - Interrupt Status 1 */
-	{ 561, 0x0000 },   /* R561   - Interrupt Status 2 */
-
 	{ 568, 0x0030 },   /* R568   - Interrupt Status 1 Mask */
 	{ 569, 0xFFED },   /* R569   - Interrupt Status 2 Mask */
 
@@ -317,8 +307,6 @@
 
 	{ 768, 0x1C00 },   /* R768   - DSP2 Power Management */
 
-	{ 1037, 0x0000 },   /* R1037  - DSP2_ExecControl */
-
 	{ 8192, 0x0000 },   /* R8192  - DSP2 Instruction RAM 0 */
 
 	{ 9216, 0x0030 },   /* R9216  - DSP2 Address RAM 2 */
@@ -797,1167 +785,660 @@
 	{ 21139, 0x8580 },   /* R21139 - VSS_XTS32_0 */
 };
 
-static const struct wm8962_reg_access {
-	u16 read;
-	u16 write;
-	u16 vol;
-} wm8962_reg_access[WM8962_MAX_REGISTER + 1] = {
-	[0] = { 0x00FF, 0x01FF, 0x0000 }, /* R0     - Left Input volume */
-	[1] = { 0xFEFF, 0x01FF, 0x0000 }, /* R1     - Right Input volume */
-	[2] = { 0x00FF, 0x01FF, 0x0000 }, /* R2     - HPOUTL volume */
-	[3] = { 0x00FF, 0x01FF, 0x0000 }, /* R3     - HPOUTR volume */
-	[4] = { 0x07FE, 0x07FE, 0xFFFF }, /* R4     - Clocking1 */
-	[5] = { 0x007F, 0x007F, 0x0000 }, /* R5     - ADC & DAC Control 1 */
-	[6] = { 0x37ED, 0x37ED, 0x0000 }, /* R6     - ADC & DAC Control 2 */
-	[7] = { 0x1FFF, 0x1FFF, 0x0000 }, /* R7     - Audio Interface 0 */
-	[8] = { 0x0FEF, 0x0FEF, 0xFFFF }, /* R8     - Clocking2 */
-	[9] = { 0x0B9F, 0x039F, 0x0000 }, /* R9     - Audio Interface 1 */
-	[10] = { 0x00FF, 0x01FF, 0x0000 }, /* R10    - Left DAC volume */
-	[11] = { 0x00FF, 0x01FF, 0x0000 }, /* R11    - Right DAC volume */
-	[14] = { 0x07FF, 0x07FF, 0x0000 }, /* R14    - Audio Interface 2 */
-	[15] = { 0xFFFF, 0xFFFF, 0xFFFF }, /* R15    - Software Reset */
-	[17] = { 0x07FF, 0x07FF, 0x0000 }, /* R17    - ALC1 */
-	[18] = { 0xF8FF, 0x00FF, 0xFFFF }, /* R18    - ALC2 */
-	[19] = { 0x1DFF, 0x1DFF, 0x0000 }, /* R19    - ALC3 */
-	[20] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20    - Noise Gate */
-	[21] = { 0x00FF, 0x01FF, 0x0000 }, /* R21    - Left ADC volume */
-	[22] = { 0x00FF, 0x01FF, 0x0000 }, /* R22    - Right ADC volume */
-	[23] = { 0x0161, 0x0161, 0x0000 }, /* R23    - Additional control(1) */
-	[24] = { 0x0008, 0x0008, 0x0000 }, /* R24    - Additional control(2) */
-	[25] = { 0x07FE, 0x07FE, 0x0000 }, /* R25    - Pwr Mgmt (1) */
-	[26] = { 0x01FB, 0x01FB, 0x0000 }, /* R26    - Pwr Mgmt (2) */
-	[27] = { 0x0017, 0x0017, 0x0000 }, /* R27    - Additional Control (3) */
-	[28] = { 0x001C, 0x001C, 0x0000 }, /* R28    - Anti-pop */
-
-	[30] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R30    - Clocking 3 */
-	[31] = { 0x000F, 0x000F, 0x0000 }, /* R31    - Input mixer control (1) */
-	[32] = { 0x01FF, 0x01FF, 0x0000 }, /* R32    - Left input mixer volume */
-	[33] = { 0x01FF, 0x01FF, 0x0000 }, /* R33    - Right input mixer volume */
-	[34] = { 0x003F, 0x003F, 0x0000 }, /* R34    - Input mixer control (2) */
-	[35] = { 0x003F, 0x003F, 0x0000 }, /* R35    - Input bias control */
-	[37] = { 0x001F, 0x001F, 0x0000 }, /* R37    - Left input PGA control */
-	[38] = { 0x001F, 0x001F, 0x0000 }, /* R38    - Right input PGA control */
-	[40] = { 0x00FF, 0x01FF, 0x0000 }, /* R40    - SPKOUTL volume */
-	[41] = { 0x00FF, 0x01FF, 0x0000 }, /* R41    - SPKOUTR volume */
-
-	[47] = { 0x000F, 0x0000, 0xFFFF }, /* R47    - Thermal Shutdown Status */
-	[48] = { 0x7EC7, 0x7E07, 0xFFFF }, /* R48    - Additional Control (4) */
-	[49] = { 0x00D3, 0x00D7, 0xFFFF }, /* R49    - Class D Control 1 */
-	[51] = { 0x0047, 0x0047, 0x0000 }, /* R51    - Class D Control 2 */
-	[56] = { 0x001E, 0x001E, 0x0000 }, /* R56    - Clocking 4 */
-	[57] = { 0x02FC, 0x02FC, 0x0000 }, /* R57    - DAC DSP Mixing (1) */
-	[58] = { 0x00FC, 0x00FC, 0x0000 }, /* R58    - DAC DSP Mixing (2) */
-	[60] = { 0x00CC, 0x00CC, 0x0000 }, /* R60    - DC Servo 0 */
-	[61] = { 0x00DD, 0x00DD, 0x0000 }, /* R61    - DC Servo 1 */
-	[64] = { 0x3F80, 0x3F80, 0x0000 }, /* R64    - DC Servo 4 */
-	[66] = { 0x0780, 0x0000, 0xFFFF }, /* R66    - DC Servo 6 */
-	[68] = { 0x0007, 0x0007, 0x0000 }, /* R68    - Analogue PGA Bias */
-	[69] = { 0x00FF, 0x00FF, 0x0000 }, /* R69    - Analogue HP 0 */
-	[71] = { 0x01FF, 0x01FF, 0x0000 }, /* R71    - Analogue HP 2 */
-	[72] = { 0x0001, 0x0001, 0x0000 }, /* R72    - Charge Pump 1 */
-	[82] = { 0x0001, 0x0001, 0x0000 }, /* R82    - Charge Pump B */
-	[87] = { 0x00A0, 0x00A0, 0x0000 }, /* R87    - Write Sequencer Control 1 */
-	[90] = { 0x007F, 0x01FF, 0x0000 }, /* R90    - Write Sequencer Control 2 */
-	[93] = { 0x03F9, 0x0000, 0x0000 }, /* R93    - Write Sequencer Control 3 */
-	[94] = { 0x0070, 0x0070, 0x0000 }, /* R94    - Control Interface */
-	[99] = { 0x000F, 0x000F, 0x0000 }, /* R99    - Mixer Enables */
-	[100] = { 0x00BF, 0x00BF, 0x0000 }, /* R100   - Headphone Mixer (1) */
-	[101] = { 0x00BF, 0x00BF, 0x0000 }, /* R101   - Headphone Mixer (2) */
-	[102] = { 0x01FF, 0x01FF, 0x0000 }, /* R102   - Headphone Mixer (3) */
-	[103] = { 0x01FF, 0x01FF, 0x0000 }, /* R103   - Headphone Mixer (4) */
-	[105] = { 0x00BF, 0x00BF, 0x0000 }, /* R105   - Speaker Mixer (1) */
-	[106] = { 0x00BF, 0x00BF, 0x0000 }, /* R106   - Speaker Mixer (2) */
-	[107] = { 0x01FF, 0x01FF, 0x0000 }, /* R107   - Speaker Mixer (3) */
-	[108] = { 0x01FF, 0x01FF, 0x0000 }, /* R108   - Speaker Mixer (4) */
-	[109] = { 0x00F0, 0x00F0, 0x0000 }, /* R109   - Speaker Mixer (5) */
-	[110] = { 0x00F7, 0x00F7, 0x0000 }, /* R110   - Beep Generator (1) */
-	[115] = { 0x001F, 0x001F, 0x0000 }, /* R115   - Oscillator Trim (3) */
-	[116] = { 0x001F, 0x001F, 0x0000 }, /* R116   - Oscillator Trim (4) */
-	[119] = { 0x00FF, 0x00FF, 0x0000 }, /* R119   - Oscillator Trim (7) */
-	[124] = { 0x0079, 0x0079, 0x0000 }, /* R124   - Analogue Clocking1 */
-	[125] = { 0x00DF, 0x00DF, 0x0000 }, /* R125   - Analogue Clocking2 */
-	[126] = { 0x000D, 0x000D, 0x0000 }, /* R126   - Analogue Clocking3 */
-	[127] = { 0x0000, 0xFFFF, 0x0000 }, /* R127   - PLL Software Reset */
-	[129] = { 0x00B0, 0x00B0, 0x0000 }, /* R129   - PLL2 */
-	[131] = { 0x0003, 0x0003, 0x0000 }, /* R131   - PLL 4 */
-	[136] = { 0x005F, 0x005F, 0x0000 }, /* R136   - PLL 9 */
-	[137] = { 0x00FF, 0x00FF, 0x0000 }, /* R137   - PLL 10 */
-	[138] = { 0x00FF, 0x00FF, 0x0000 }, /* R138   - PLL 11 */
-	[139] = { 0x00FF, 0x00FF, 0x0000 }, /* R139   - PLL 12 */
-	[140] = { 0x005F, 0x005F, 0x0000 }, /* R140   - PLL 13 */
-	[141] = { 0x00FF, 0x00FF, 0x0000 }, /* R141   - PLL 14 */
-	[142] = { 0x00FF, 0x00FF, 0x0000 }, /* R142   - PLL 15 */
-	[143] = { 0x00FF, 0x00FF, 0x0000 }, /* R143   - PLL 16 */
-	[155] = { 0x0067, 0x0067, 0x0000 }, /* R155   - FLL Control (1) */
-	[156] = { 0x01FB, 0x01FB, 0x0000 }, /* R156   - FLL Control (2) */
-	[157] = { 0x0007, 0x0007, 0x0000 }, /* R157   - FLL Control (3) */
-	[159] = { 0x007F, 0x007F, 0x0000 }, /* R159   - FLL Control (5) */
-	[160] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R160   - FLL Control (6) */
-	[161] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R161   - FLL Control (7) */
-	[162] = { 0x03FF, 0x03FF, 0x0000 }, /* R162   - FLL Control (8) */
-	[252] = { 0x0005, 0x0005, 0x0000 }, /* R252   - General test 1 */
-	[256] = { 0x000F, 0x000F, 0x0000 }, /* R256   - DF1 */
-	[257] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R257   - DF2 */
-	[258] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R258   - DF3 */
-	[259] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R259   - DF4 */
-	[260] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R260   - DF5 */
-	[261] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R261   - DF6 */
-	[262] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R262   - DF7 */
-	[264] = { 0x0003, 0x0003, 0x0000 }, /* R264   - LHPF1 */
-	[265] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R265   - LHPF2 */
-	[268] = { 0x0077, 0x0077, 0x0000 }, /* R268   - THREED1 */
-	[269] = { 0xFFFC, 0xFFFC, 0x0000 }, /* R269   - THREED2 */
-	[270] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R270   - THREED3 */
-	[271] = { 0xFFFC, 0xFFFC, 0x0000 }, /* R271   - THREED4 */
-	[276] = { 0x7FFF, 0x7FFF, 0x0000 }, /* R276   - DRC 1 */
-	[277] = { 0x1FFF, 0x1FFF, 0x0000 }, /* R277   - DRC 2 */
-	[278] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R278   - DRC 3 */
-	[279] = { 0x07FF, 0x07FF, 0x0000 }, /* R279   - DRC 4 */
-	[280] = { 0x03FF, 0x03FF, 0x0000 }, /* R280   - DRC 5 */
-	[285] = { 0x0003, 0x0003, 0x0000 }, /* R285   - Tloopback */
-	[335] = { 0x0007, 0x0007, 0x0000 }, /* R335   - EQ1 */
-	[336] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R336   - EQ2 */
-	[337] = { 0xFFC0, 0xFFC0, 0x0000 }, /* R337   - EQ3 */
-	[338] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R338   - EQ4 */
-	[339] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R339   - EQ5 */
-	[340] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R340   - EQ6 */
-	[341] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R341   - EQ7 */
-	[342] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R342   - EQ8 */
-	[343] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R343   - EQ9 */
-	[344] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R344   - EQ10 */
-	[345] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R345   - EQ11 */
-	[346] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R346   - EQ12 */
-	[347] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R347   - EQ13 */
-	[348] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R348   - EQ14 */
-	[349] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R349   - EQ15 */
-	[350] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R350   - EQ16 */
-	[351] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R351   - EQ17 */
-	[352] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R352   - EQ18 */
-	[353] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R353   - EQ19 */
-	[354] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R354   - EQ20 */
-	[355] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R355   - EQ21 */
-	[356] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R356   - EQ22 */
-	[357] = { 0xFFC0, 0xFFC0, 0x0000 }, /* R357   - EQ23 */
-	[358] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R358   - EQ24 */
-	[359] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R359   - EQ25 */
-	[360] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R360   - EQ26 */
-	[361] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R361   - EQ27 */
-	[362] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R362   - EQ28 */
-	[363] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R363   - EQ29 */
-	[364] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R364   - EQ30 */
-	[365] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R365   - EQ31 */
-	[366] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R366   - EQ32 */
-	[367] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R367   - EQ33 */
-	[368] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R368   - EQ34 */
-	[369] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R369   - EQ35 */
-	[370] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R370   - EQ36 */
-	[371] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R371   - EQ37 */
-	[372] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R372   - EQ38 */
-	[373] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R373   - EQ39 */
-	[374] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R374   - EQ40 */
-	[375] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R375   - EQ41 */
-	[513] = { 0x045F, 0x045F, 0x0000 }, /* R513   - GPIO 2 */
-	[514] = { 0x045F, 0x045F, 0x0000 }, /* R514   - GPIO 3 */
-	[516] = { 0xE75F, 0xE75F, 0x0000 }, /* R516   - GPIO 5 */
-	[517] = { 0xE75F, 0xE75F, 0x0000 }, /* R517   - GPIO 6 */
-	[560] = { 0x0030, 0x0030, 0xFFFF }, /* R560   - Interrupt Status 1 */
-	[561] = { 0xFFED, 0xFFED, 0xFFFF }, /* R561   - Interrupt Status 2 */
-	[568] = { 0x0030, 0x0030, 0x0000 }, /* R568   - Interrupt Status 1 Mask */
-	[569] = { 0xFFED, 0xFFED, 0x0000 }, /* R569   - Interrupt Status 2 Mask */
-	[576] = { 0x0001, 0x0001, 0x0000 }, /* R576   - Interrupt Control */
-	[584] = { 0x002D, 0x002D, 0x0000 }, /* R584   - IRQ Debounce */
-	[586] = { 0xC000, 0xC000, 0x0000 }, /* R586   -  MICINT Source Pol */
-	[768] = { 0x0001, 0x0001, 0x0000 }, /* R768   - DSP2 Power Management */
-	[1037] = { 0x0000, 0x003F, 0xFFFF }, /* R1037  - DSP2_ExecControl */
-	[4096] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4096  - Write Sequencer 0 */
-	[4097] = { 0x00FF, 0x00FF, 0x0000 }, /* R4097  - Write Sequencer 1 */
-	[4098] = { 0x070F, 0x070F, 0x0000 }, /* R4098  - Write Sequencer 2 */
-	[4099] = { 0x010F, 0x010F, 0x0000 }, /* R4099  - Write Sequencer 3 */
-	[4100] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4100  - Write Sequencer 4 */
-	[4101] = { 0x00FF, 0x00FF, 0x0000 }, /* R4101  - Write Sequencer 5 */
-	[4102] = { 0x070F, 0x070F, 0x0000 }, /* R4102  - Write Sequencer 6 */
-	[4103] = { 0x010F, 0x010F, 0x0000 }, /* R4103  - Write Sequencer 7 */
-	[4104] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4104  - Write Sequencer 8 */
-	[4105] = { 0x00FF, 0x00FF, 0x0000 }, /* R4105  - Write Sequencer 9 */
-	[4106] = { 0x070F, 0x070F, 0x0000 }, /* R4106  - Write Sequencer 10 */
-	[4107] = { 0x010F, 0x010F, 0x0000 }, /* R4107  - Write Sequencer 11 */
-	[4108] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4108  - Write Sequencer 12 */
-	[4109] = { 0x00FF, 0x00FF, 0x0000 }, /* R4109  - Write Sequencer 13 */
-	[4110] = { 0x070F, 0x070F, 0x0000 }, /* R4110  - Write Sequencer 14 */
-	[4111] = { 0x010F, 0x010F, 0x0000 }, /* R4111  - Write Sequencer 15 */
-	[4112] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4112  - Write Sequencer 16 */
-	[4113] = { 0x00FF, 0x00FF, 0x0000 }, /* R4113  - Write Sequencer 17 */
-	[4114] = { 0x070F, 0x070F, 0x0000 }, /* R4114  - Write Sequencer 18 */
-	[4115] = { 0x010F, 0x010F, 0x0000 }, /* R4115  - Write Sequencer 19 */
-	[4116] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4116  - Write Sequencer 20 */
-	[4117] = { 0x00FF, 0x00FF, 0x0000 }, /* R4117  - Write Sequencer 21 */
-	[4118] = { 0x070F, 0x070F, 0x0000 }, /* R4118  - Write Sequencer 22 */
-	[4119] = { 0x010F, 0x010F, 0x0000 }, /* R4119  - Write Sequencer 23 */
-	[4120] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4120  - Write Sequencer 24 */
-	[4121] = { 0x00FF, 0x00FF, 0x0000 }, /* R4121  - Write Sequencer 25 */
-	[4122] = { 0x070F, 0x070F, 0x0000 }, /* R4122  - Write Sequencer 26 */
-	[4123] = { 0x010F, 0x010F, 0x0000 }, /* R4123  - Write Sequencer 27 */
-	[4124] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4124  - Write Sequencer 28 */
-	[4125] = { 0x00FF, 0x00FF, 0x0000 }, /* R4125  - Write Sequencer 29 */
-	[4126] = { 0x070F, 0x070F, 0x0000 }, /* R4126  - Write Sequencer 30 */
-	[4127] = { 0x010F, 0x010F, 0x0000 }, /* R4127  - Write Sequencer 31 */
-	[4128] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4128  - Write Sequencer 32 */
-	[4129] = { 0x00FF, 0x00FF, 0x0000 }, /* R4129  - Write Sequencer 33 */
-	[4130] = { 0x070F, 0x070F, 0x0000 }, /* R4130  - Write Sequencer 34 */
-	[4131] = { 0x010F, 0x010F, 0x0000 }, /* R4131  - Write Sequencer 35 */
-	[4132] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4132  - Write Sequencer 36 */
-	[4133] = { 0x00FF, 0x00FF, 0x0000 }, /* R4133  - Write Sequencer 37 */
-	[4134] = { 0x070F, 0x070F, 0x0000 }, /* R4134  - Write Sequencer 38 */
-	[4135] = { 0x010F, 0x010F, 0x0000 }, /* R4135  - Write Sequencer 39 */
-	[4136] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4136  - Write Sequencer 40 */
-	[4137] = { 0x00FF, 0x00FF, 0x0000 }, /* R4137  - Write Sequencer 41 */
-	[4138] = { 0x070F, 0x070F, 0x0000 }, /* R4138  - Write Sequencer 42 */
-	[4139] = { 0x010F, 0x010F, 0x0000 }, /* R4139  - Write Sequencer 43 */
-	[4140] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4140  - Write Sequencer 44 */
-	[4141] = { 0x00FF, 0x00FF, 0x0000 }, /* R4141  - Write Sequencer 45 */
-	[4142] = { 0x070F, 0x070F, 0x0000 }, /* R4142  - Write Sequencer 46 */
-	[4143] = { 0x010F, 0x010F, 0x0000 }, /* R4143  - Write Sequencer 47 */
-	[4144] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4144  - Write Sequencer 48 */
-	[4145] = { 0x00FF, 0x00FF, 0x0000 }, /* R4145  - Write Sequencer 49 */
-	[4146] = { 0x070F, 0x070F, 0x0000 }, /* R4146  - Write Sequencer 50 */
-	[4147] = { 0x010F, 0x010F, 0x0000 }, /* R4147  - Write Sequencer 51 */
-	[4148] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4148  - Write Sequencer 52 */
-	[4149] = { 0x00FF, 0x00FF, 0x0000 }, /* R4149  - Write Sequencer 53 */
-	[4150] = { 0x070F, 0x070F, 0x0000 }, /* R4150  - Write Sequencer 54 */
-	[4151] = { 0x010F, 0x010F, 0x0000 }, /* R4151  - Write Sequencer 55 */
-	[4152] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4152  - Write Sequencer 56 */
-	[4153] = { 0x00FF, 0x00FF, 0x0000 }, /* R4153  - Write Sequencer 57 */
-	[4154] = { 0x070F, 0x070F, 0x0000 }, /* R4154  - Write Sequencer 58 */
-	[4155] = { 0x010F, 0x010F, 0x0000 }, /* R4155  - Write Sequencer 59 */
-	[4156] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4156  - Write Sequencer 60 */
-	[4157] = { 0x00FF, 0x00FF, 0x0000 }, /* R4157  - Write Sequencer 61 */
-	[4158] = { 0x070F, 0x070F, 0x0000 }, /* R4158  - Write Sequencer 62 */
-	[4159] = { 0x010F, 0x010F, 0x0000 }, /* R4159  - Write Sequencer 63 */
-	[4160] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4160  - Write Sequencer 64 */
-	[4161] = { 0x00FF, 0x00FF, 0x0000 }, /* R4161  - Write Sequencer 65 */
-	[4162] = { 0x070F, 0x070F, 0x0000 }, /* R4162  - Write Sequencer 66 */
-	[4163] = { 0x010F, 0x010F, 0x0000 }, /* R4163  - Write Sequencer 67 */
-	[4164] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4164  - Write Sequencer 68 */
-	[4165] = { 0x00FF, 0x00FF, 0x0000 }, /* R4165  - Write Sequencer 69 */
-	[4166] = { 0x070F, 0x070F, 0x0000 }, /* R4166  - Write Sequencer 70 */
-	[4167] = { 0x010F, 0x010F, 0x0000 }, /* R4167  - Write Sequencer 71 */
-	[4168] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4168  - Write Sequencer 72 */
-	[4169] = { 0x00FF, 0x00FF, 0x0000 }, /* R4169  - Write Sequencer 73 */
-	[4170] = { 0x070F, 0x070F, 0x0000 }, /* R4170  - Write Sequencer 74 */
-	[4171] = { 0x010F, 0x010F, 0x0000 }, /* R4171  - Write Sequencer 75 */
-	[4172] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4172  - Write Sequencer 76 */
-	[4173] = { 0x00FF, 0x00FF, 0x0000 }, /* R4173  - Write Sequencer 77 */
-	[4174] = { 0x070F, 0x070F, 0x0000 }, /* R4174  - Write Sequencer 78 */
-	[4175] = { 0x010F, 0x010F, 0x0000 }, /* R4175  - Write Sequencer 79 */
-	[4176] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4176  - Write Sequencer 80 */
-	[4177] = { 0x00FF, 0x00FF, 0x0000 }, /* R4177  - Write Sequencer 81 */
-	[4178] = { 0x070F, 0x070F, 0x0000 }, /* R4178  - Write Sequencer 82 */
-	[4179] = { 0x010F, 0x010F, 0x0000 }, /* R4179  - Write Sequencer 83 */
-	[4180] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4180  - Write Sequencer 84 */
-	[4181] = { 0x00FF, 0x00FF, 0x0000 }, /* R4181  - Write Sequencer 85 */
-	[4182] = { 0x070F, 0x070F, 0x0000 }, /* R4182  - Write Sequencer 86 */
-	[4183] = { 0x010F, 0x010F, 0x0000 }, /* R4183  - Write Sequencer 87 */
-	[4184] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4184  - Write Sequencer 88 */
-	[4185] = { 0x00FF, 0x00FF, 0x0000 }, /* R4185  - Write Sequencer 89 */
-	[4186] = { 0x070F, 0x070F, 0x0000 }, /* R4186  - Write Sequencer 90 */
-	[4187] = { 0x010F, 0x010F, 0x0000 }, /* R4187  - Write Sequencer 91 */
-	[4188] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4188  - Write Sequencer 92 */
-	[4189] = { 0x00FF, 0x00FF, 0x0000 }, /* R4189  - Write Sequencer 93 */
-	[4190] = { 0x070F, 0x070F, 0x0000 }, /* R4190  - Write Sequencer 94 */
-	[4191] = { 0x010F, 0x010F, 0x0000 }, /* R4191  - Write Sequencer 95 */
-	[4192] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4192  - Write Sequencer 96 */
-	[4193] = { 0x00FF, 0x00FF, 0x0000 }, /* R4193  - Write Sequencer 97 */
-	[4194] = { 0x070F, 0x070F, 0x0000 }, /* R4194  - Write Sequencer 98 */
-	[4195] = { 0x010F, 0x010F, 0x0000 }, /* R4195  - Write Sequencer 99 */
-	[4196] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4196  - Write Sequencer 100 */
-	[4197] = { 0x00FF, 0x00FF, 0x0000 }, /* R4197  - Write Sequencer 101 */
-	[4198] = { 0x070F, 0x070F, 0x0000 }, /* R4198  - Write Sequencer 102 */
-	[4199] = { 0x010F, 0x010F, 0x0000 }, /* R4199  - Write Sequencer 103 */
-	[4200] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4200  - Write Sequencer 104 */
-	[4201] = { 0x00FF, 0x00FF, 0x0000 }, /* R4201  - Write Sequencer 105 */
-	[4202] = { 0x070F, 0x070F, 0x0000 }, /* R4202  - Write Sequencer 106 */
-	[4203] = { 0x010F, 0x010F, 0x0000 }, /* R4203  - Write Sequencer 107 */
-	[4204] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4204  - Write Sequencer 108 */
-	[4205] = { 0x00FF, 0x00FF, 0x0000 }, /* R4205  - Write Sequencer 109 */
-	[4206] = { 0x070F, 0x070F, 0x0000 }, /* R4206  - Write Sequencer 110 */
-	[4207] = { 0x010F, 0x010F, 0x0000 }, /* R4207  - Write Sequencer 111 */
-	[4208] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4208  - Write Sequencer 112 */
-	[4209] = { 0x00FF, 0x00FF, 0x0000 }, /* R4209  - Write Sequencer 113 */
-	[4210] = { 0x070F, 0x070F, 0x0000 }, /* R4210  - Write Sequencer 114 */
-	[4211] = { 0x010F, 0x010F, 0x0000 }, /* R4211  - Write Sequencer 115 */
-	[4212] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4212  - Write Sequencer 116 */
-	[4213] = { 0x00FF, 0x00FF, 0x0000 }, /* R4213  - Write Sequencer 117 */
-	[4214] = { 0x070F, 0x070F, 0x0000 }, /* R4214  - Write Sequencer 118 */
-	[4215] = { 0x010F, 0x010F, 0x0000 }, /* R4215  - Write Sequencer 119 */
-	[4216] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4216  - Write Sequencer 120 */
-	[4217] = { 0x00FF, 0x00FF, 0x0000 }, /* R4217  - Write Sequencer 121 */
-	[4218] = { 0x070F, 0x070F, 0x0000 }, /* R4218  - Write Sequencer 122 */
-	[4219] = { 0x010F, 0x010F, 0x0000 }, /* R4219  - Write Sequencer 123 */
-	[4220] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4220  - Write Sequencer 124 */
-	[4221] = { 0x00FF, 0x00FF, 0x0000 }, /* R4221  - Write Sequencer 125 */
-	[4222] = { 0x070F, 0x070F, 0x0000 }, /* R4222  - Write Sequencer 126 */
-	[4223] = { 0x010F, 0x010F, 0x0000 }, /* R4223  - Write Sequencer 127 */
-	[4224] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4224  - Write Sequencer 128 */
-	[4225] = { 0x00FF, 0x00FF, 0x0000 }, /* R4225  - Write Sequencer 129 */
-	[4226] = { 0x070F, 0x070F, 0x0000 }, /* R4226  - Write Sequencer 130 */
-	[4227] = { 0x010F, 0x010F, 0x0000 }, /* R4227  - Write Sequencer 131 */
-	[4228] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4228  - Write Sequencer 132 */
-	[4229] = { 0x00FF, 0x00FF, 0x0000 }, /* R4229  - Write Sequencer 133 */
-	[4230] = { 0x070F, 0x070F, 0x0000 }, /* R4230  - Write Sequencer 134 */
-	[4231] = { 0x010F, 0x010F, 0x0000 }, /* R4231  - Write Sequencer 135 */
-	[4232] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4232  - Write Sequencer 136 */
-	[4233] = { 0x00FF, 0x00FF, 0x0000 }, /* R4233  - Write Sequencer 137 */
-	[4234] = { 0x070F, 0x070F, 0x0000 }, /* R4234  - Write Sequencer 138 */
-	[4235] = { 0x010F, 0x010F, 0x0000 }, /* R4235  - Write Sequencer 139 */
-	[4236] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4236  - Write Sequencer 140 */
-	[4237] = { 0x00FF, 0x00FF, 0x0000 }, /* R4237  - Write Sequencer 141 */
-	[4238] = { 0x070F, 0x070F, 0x0000 }, /* R4238  - Write Sequencer 142 */
-	[4239] = { 0x010F, 0x010F, 0x0000 }, /* R4239  - Write Sequencer 143 */
-	[4240] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4240  - Write Sequencer 144 */
-	[4241] = { 0x00FF, 0x00FF, 0x0000 }, /* R4241  - Write Sequencer 145 */
-	[4242] = { 0x070F, 0x070F, 0x0000 }, /* R4242  - Write Sequencer 146 */
-	[4243] = { 0x010F, 0x010F, 0x0000 }, /* R4243  - Write Sequencer 147 */
-	[4244] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4244  - Write Sequencer 148 */
-	[4245] = { 0x00FF, 0x00FF, 0x0000 }, /* R4245  - Write Sequencer 149 */
-	[4246] = { 0x070F, 0x070F, 0x0000 }, /* R4246  - Write Sequencer 150 */
-	[4247] = { 0x010F, 0x010F, 0x0000 }, /* R4247  - Write Sequencer 151 */
-	[4248] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4248  - Write Sequencer 152 */
-	[4249] = { 0x00FF, 0x00FF, 0x0000 }, /* R4249  - Write Sequencer 153 */
-	[4250] = { 0x070F, 0x070F, 0x0000 }, /* R4250  - Write Sequencer 154 */
-	[4251] = { 0x010F, 0x010F, 0x0000 }, /* R4251  - Write Sequencer 155 */
-	[4252] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4252  - Write Sequencer 156 */
-	[4253] = { 0x00FF, 0x00FF, 0x0000 }, /* R4253  - Write Sequencer 157 */
-	[4254] = { 0x070F, 0x070F, 0x0000 }, /* R4254  - Write Sequencer 158 */
-	[4255] = { 0x010F, 0x010F, 0x0000 }, /* R4255  - Write Sequencer 159 */
-	[4256] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4256  - Write Sequencer 160 */
-	[4257] = { 0x00FF, 0x00FF, 0x0000 }, /* R4257  - Write Sequencer 161 */
-	[4258] = { 0x070F, 0x070F, 0x0000 }, /* R4258  - Write Sequencer 162 */
-	[4259] = { 0x010F, 0x010F, 0x0000 }, /* R4259  - Write Sequencer 163 */
-	[4260] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4260  - Write Sequencer 164 */
-	[4261] = { 0x00FF, 0x00FF, 0x0000 }, /* R4261  - Write Sequencer 165 */
-	[4262] = { 0x070F, 0x070F, 0x0000 }, /* R4262  - Write Sequencer 166 */
-	[4263] = { 0x010F, 0x010F, 0x0000 }, /* R4263  - Write Sequencer 167 */
-	[4264] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4264  - Write Sequencer 168 */
-	[4265] = { 0x00FF, 0x00FF, 0x0000 }, /* R4265  - Write Sequencer 169 */
-	[4266] = { 0x070F, 0x070F, 0x0000 }, /* R4266  - Write Sequencer 170 */
-	[4267] = { 0x010F, 0x010F, 0x0000 }, /* R4267  - Write Sequencer 171 */
-	[4268] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4268  - Write Sequencer 172 */
-	[4269] = { 0x00FF, 0x00FF, 0x0000 }, /* R4269  - Write Sequencer 173 */
-	[4270] = { 0x070F, 0x070F, 0x0000 }, /* R4270  - Write Sequencer 174 */
-	[4271] = { 0x010F, 0x010F, 0x0000 }, /* R4271  - Write Sequencer 175 */
-	[4272] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4272  - Write Sequencer 176 */
-	[4273] = { 0x00FF, 0x00FF, 0x0000 }, /* R4273  - Write Sequencer 177 */
-	[4274] = { 0x070F, 0x070F, 0x0000 }, /* R4274  - Write Sequencer 178 */
-	[4275] = { 0x010F, 0x010F, 0x0000 }, /* R4275  - Write Sequencer 179 */
-	[4276] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4276  - Write Sequencer 180 */
-	[4277] = { 0x00FF, 0x00FF, 0x0000 }, /* R4277  - Write Sequencer 181 */
-	[4278] = { 0x070F, 0x070F, 0x0000 }, /* R4278  - Write Sequencer 182 */
-	[4279] = { 0x010F, 0x010F, 0x0000 }, /* R4279  - Write Sequencer 183 */
-	[4280] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4280  - Write Sequencer 184 */
-	[4281] = { 0x00FF, 0x00FF, 0x0000 }, /* R4281  - Write Sequencer 185 */
-	[4282] = { 0x070F, 0x070F, 0x0000 }, /* R4282  - Write Sequencer 186 */
-	[4283] = { 0x010F, 0x010F, 0x0000 }, /* R4283  - Write Sequencer 187 */
-	[4284] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4284  - Write Sequencer 188 */
-	[4285] = { 0x00FF, 0x00FF, 0x0000 }, /* R4285  - Write Sequencer 189 */
-	[4286] = { 0x070F, 0x070F, 0x0000 }, /* R4286  - Write Sequencer 190 */
-	[4287] = { 0x010F, 0x010F, 0x0000 }, /* R4287  - Write Sequencer 191 */
-	[4288] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4288  - Write Sequencer 192 */
-	[4289] = { 0x00FF, 0x00FF, 0x0000 }, /* R4289  - Write Sequencer 193 */
-	[4290] = { 0x070F, 0x070F, 0x0000 }, /* R4290  - Write Sequencer 194 */
-	[4291] = { 0x010F, 0x010F, 0x0000 }, /* R4291  - Write Sequencer 195 */
-	[4292] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4292  - Write Sequencer 196 */
-	[4293] = { 0x00FF, 0x00FF, 0x0000 }, /* R4293  - Write Sequencer 197 */
-	[4294] = { 0x070F, 0x070F, 0x0000 }, /* R4294  - Write Sequencer 198 */
-	[4295] = { 0x010F, 0x010F, 0x0000 }, /* R4295  - Write Sequencer 199 */
-	[4296] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4296  - Write Sequencer 200 */
-	[4297] = { 0x00FF, 0x00FF, 0x0000 }, /* R4297  - Write Sequencer 201 */
-	[4298] = { 0x070F, 0x070F, 0x0000 }, /* R4298  - Write Sequencer 202 */
-	[4299] = { 0x010F, 0x010F, 0x0000 }, /* R4299  - Write Sequencer 203 */
-	[4300] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4300  - Write Sequencer 204 */
-	[4301] = { 0x00FF, 0x00FF, 0x0000 }, /* R4301  - Write Sequencer 205 */
-	[4302] = { 0x070F, 0x070F, 0x0000 }, /* R4302  - Write Sequencer 206 */
-	[4303] = { 0x010F, 0x010F, 0x0000 }, /* R4303  - Write Sequencer 207 */
-	[4304] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4304  - Write Sequencer 208 */
-	[4305] = { 0x00FF, 0x00FF, 0x0000 }, /* R4305  - Write Sequencer 209 */
-	[4306] = { 0x070F, 0x070F, 0x0000 }, /* R4306  - Write Sequencer 210 */
-	[4307] = { 0x010F, 0x010F, 0x0000 }, /* R4307  - Write Sequencer 211 */
-	[4308] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4308  - Write Sequencer 212 */
-	[4309] = { 0x00FF, 0x00FF, 0x0000 }, /* R4309  - Write Sequencer 213 */
-	[4310] = { 0x070F, 0x070F, 0x0000 }, /* R4310  - Write Sequencer 214 */
-	[4311] = { 0x010F, 0x010F, 0x0000 }, /* R4311  - Write Sequencer 215 */
-	[4312] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4312  - Write Sequencer 216 */
-	[4313] = { 0x00FF, 0x00FF, 0x0000 }, /* R4313  - Write Sequencer 217 */
-	[4314] = { 0x070F, 0x070F, 0x0000 }, /* R4314  - Write Sequencer 218 */
-	[4315] = { 0x010F, 0x010F, 0x0000 }, /* R4315  - Write Sequencer 219 */
-	[4316] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4316  - Write Sequencer 220 */
-	[4317] = { 0x00FF, 0x00FF, 0x0000 }, /* R4317  - Write Sequencer 221 */
-	[4318] = { 0x070F, 0x070F, 0x0000 }, /* R4318  - Write Sequencer 222 */
-	[4319] = { 0x010F, 0x010F, 0x0000 }, /* R4319  - Write Sequencer 223 */
-	[4320] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4320  - Write Sequencer 224 */
-	[4321] = { 0x00FF, 0x00FF, 0x0000 }, /* R4321  - Write Sequencer 225 */
-	[4322] = { 0x070F, 0x070F, 0x0000 }, /* R4322  - Write Sequencer 226 */
-	[4323] = { 0x010F, 0x010F, 0x0000 }, /* R4323  - Write Sequencer 227 */
-	[4324] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4324  - Write Sequencer 228 */
-	[4325] = { 0x00FF, 0x00FF, 0x0000 }, /* R4325  - Write Sequencer 229 */
-	[4326] = { 0x070F, 0x070F, 0x0000 }, /* R4326  - Write Sequencer 230 */
-	[4327] = { 0x010F, 0x010F, 0x0000 }, /* R4327  - Write Sequencer 231 */
-	[4328] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4328  - Write Sequencer 232 */
-	[4329] = { 0x00FF, 0x00FF, 0x0000 }, /* R4329  - Write Sequencer 233 */
-	[4330] = { 0x070F, 0x070F, 0x0000 }, /* R4330  - Write Sequencer 234 */
-	[4331] = { 0x010F, 0x010F, 0x0000 }, /* R4331  - Write Sequencer 235 */
-	[4332] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4332  - Write Sequencer 236 */
-	[4333] = { 0x00FF, 0x00FF, 0x0000 }, /* R4333  - Write Sequencer 237 */
-	[4334] = { 0x070F, 0x070F, 0x0000 }, /* R4334  - Write Sequencer 238 */
-	[4335] = { 0x010F, 0x010F, 0x0000 }, /* R4335  - Write Sequencer 239 */
-	[4336] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4336  - Write Sequencer 240 */
-	[4337] = { 0x00FF, 0x00FF, 0x0000 }, /* R4337  - Write Sequencer 241 */
-	[4338] = { 0x070F, 0x070F, 0x0000 }, /* R4338  - Write Sequencer 242 */
-	[4339] = { 0x010F, 0x010F, 0x0000 }, /* R4339  - Write Sequencer 243 */
-	[4340] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4340  - Write Sequencer 244 */
-	[4341] = { 0x00FF, 0x00FF, 0x0000 }, /* R4341  - Write Sequencer 245 */
-	[4342] = { 0x070F, 0x070F, 0x0000 }, /* R4342  - Write Sequencer 246 */
-	[4343] = { 0x010F, 0x010F, 0x0000 }, /* R4343  - Write Sequencer 247 */
-	[4344] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4344  - Write Sequencer 248 */
-	[4345] = { 0x00FF, 0x00FF, 0x0000 }, /* R4345  - Write Sequencer 249 */
-	[4346] = { 0x070F, 0x070F, 0x0000 }, /* R4346  - Write Sequencer 250 */
-	[4347] = { 0x010F, 0x010F, 0x0000 }, /* R4347  - Write Sequencer 251 */
-	[4348] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4348  - Write Sequencer 252 */
-	[4349] = { 0x00FF, 0x00FF, 0x0000 }, /* R4349  - Write Sequencer 253 */
-	[4350] = { 0x070F, 0x070F, 0x0000 }, /* R4350  - Write Sequencer 254 */
-	[4351] = { 0x010F, 0x010F, 0x0000 }, /* R4351  - Write Sequencer 255 */
-	[4352] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4352  - Write Sequencer 256 */
-	[4353] = { 0x00FF, 0x00FF, 0x0000 }, /* R4353  - Write Sequencer 257 */
-	[4354] = { 0x070F, 0x070F, 0x0000 }, /* R4354  - Write Sequencer 258 */
-	[4355] = { 0x010F, 0x010F, 0x0000 }, /* R4355  - Write Sequencer 259 */
-	[4356] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4356  - Write Sequencer 260 */
-	[4357] = { 0x00FF, 0x00FF, 0x0000 }, /* R4357  - Write Sequencer 261 */
-	[4358] = { 0x070F, 0x070F, 0x0000 }, /* R4358  - Write Sequencer 262 */
-	[4359] = { 0x010F, 0x010F, 0x0000 }, /* R4359  - Write Sequencer 263 */
-	[4360] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4360  - Write Sequencer 264 */
-	[4361] = { 0x00FF, 0x00FF, 0x0000 }, /* R4361  - Write Sequencer 265 */
-	[4362] = { 0x070F, 0x070F, 0x0000 }, /* R4362  - Write Sequencer 266 */
-	[4363] = { 0x010F, 0x010F, 0x0000 }, /* R4363  - Write Sequencer 267 */
-	[4364] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4364  - Write Sequencer 268 */
-	[4365] = { 0x00FF, 0x00FF, 0x0000 }, /* R4365  - Write Sequencer 269 */
-	[4366] = { 0x070F, 0x070F, 0x0000 }, /* R4366  - Write Sequencer 270 */
-	[4367] = { 0x010F, 0x010F, 0x0000 }, /* R4367  - Write Sequencer 271 */
-	[4368] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4368  - Write Sequencer 272 */
-	[4369] = { 0x00FF, 0x00FF, 0x0000 }, /* R4369  - Write Sequencer 273 */
-	[4370] = { 0x070F, 0x070F, 0x0000 }, /* R4370  - Write Sequencer 274 */
-	[4371] = { 0x010F, 0x010F, 0x0000 }, /* R4371  - Write Sequencer 275 */
-	[4372] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4372  - Write Sequencer 276 */
-	[4373] = { 0x00FF, 0x00FF, 0x0000 }, /* R4373  - Write Sequencer 277 */
-	[4374] = { 0x070F, 0x070F, 0x0000 }, /* R4374  - Write Sequencer 278 */
-	[4375] = { 0x010F, 0x010F, 0x0000 }, /* R4375  - Write Sequencer 279 */
-	[4376] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4376  - Write Sequencer 280 */
-	[4377] = { 0x00FF, 0x00FF, 0x0000 }, /* R4377  - Write Sequencer 281 */
-	[4378] = { 0x070F, 0x070F, 0x0000 }, /* R4378  - Write Sequencer 282 */
-	[4379] = { 0x010F, 0x010F, 0x0000 }, /* R4379  - Write Sequencer 283 */
-	[4380] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4380  - Write Sequencer 284 */
-	[4381] = { 0x00FF, 0x00FF, 0x0000 }, /* R4381  - Write Sequencer 285 */
-	[4382] = { 0x070F, 0x070F, 0x0000 }, /* R4382  - Write Sequencer 286 */
-	[4383] = { 0x010F, 0x010F, 0x0000 }, /* R4383  - Write Sequencer 287 */
-	[4384] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4384  - Write Sequencer 288 */
-	[4385] = { 0x00FF, 0x00FF, 0x0000 }, /* R4385  - Write Sequencer 289 */
-	[4386] = { 0x070F, 0x070F, 0x0000 }, /* R4386  - Write Sequencer 290 */
-	[4387] = { 0x010F, 0x010F, 0x0000 }, /* R4387  - Write Sequencer 291 */
-	[4388] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4388  - Write Sequencer 292 */
-	[4389] = { 0x00FF, 0x00FF, 0x0000 }, /* R4389  - Write Sequencer 293 */
-	[4390] = { 0x070F, 0x070F, 0x0000 }, /* R4390  - Write Sequencer 294 */
-	[4391] = { 0x010F, 0x010F, 0x0000 }, /* R4391  - Write Sequencer 295 */
-	[4392] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4392  - Write Sequencer 296 */
-	[4393] = { 0x00FF, 0x00FF, 0x0000 }, /* R4393  - Write Sequencer 297 */
-	[4394] = { 0x070F, 0x070F, 0x0000 }, /* R4394  - Write Sequencer 298 */
-	[4395] = { 0x010F, 0x010F, 0x0000 }, /* R4395  - Write Sequencer 299 */
-	[4396] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4396  - Write Sequencer 300 */
-	[4397] = { 0x00FF, 0x00FF, 0x0000 }, /* R4397  - Write Sequencer 301 */
-	[4398] = { 0x070F, 0x070F, 0x0000 }, /* R4398  - Write Sequencer 302 */
-	[4399] = { 0x010F, 0x010F, 0x0000 }, /* R4399  - Write Sequencer 303 */
-	[4400] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4400  - Write Sequencer 304 */
-	[4401] = { 0x00FF, 0x00FF, 0x0000 }, /* R4401  - Write Sequencer 305 */
-	[4402] = { 0x070F, 0x070F, 0x0000 }, /* R4402  - Write Sequencer 306 */
-	[4403] = { 0x010F, 0x010F, 0x0000 }, /* R4403  - Write Sequencer 307 */
-	[4404] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4404  - Write Sequencer 308 */
-	[4405] = { 0x00FF, 0x00FF, 0x0000 }, /* R4405  - Write Sequencer 309 */
-	[4406] = { 0x070F, 0x070F, 0x0000 }, /* R4406  - Write Sequencer 310 */
-	[4407] = { 0x010F, 0x010F, 0x0000 }, /* R4407  - Write Sequencer 311 */
-	[4408] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4408  - Write Sequencer 312 */
-	[4409] = { 0x00FF, 0x00FF, 0x0000 }, /* R4409  - Write Sequencer 313 */
-	[4410] = { 0x070F, 0x070F, 0x0000 }, /* R4410  - Write Sequencer 314 */
-	[4411] = { 0x010F, 0x010F, 0x0000 }, /* R4411  - Write Sequencer 315 */
-	[4412] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4412  - Write Sequencer 316 */
-	[4413] = { 0x00FF, 0x00FF, 0x0000 }, /* R4413  - Write Sequencer 317 */
-	[4414] = { 0x070F, 0x070F, 0x0000 }, /* R4414  - Write Sequencer 318 */
-	[4415] = { 0x010F, 0x010F, 0x0000 }, /* R4415  - Write Sequencer 319 */
-	[4416] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4416  - Write Sequencer 320 */
-	[4417] = { 0x00FF, 0x00FF, 0x0000 }, /* R4417  - Write Sequencer 321 */
-	[4418] = { 0x070F, 0x070F, 0x0000 }, /* R4418  - Write Sequencer 322 */
-	[4419] = { 0x010F, 0x010F, 0x0000 }, /* R4419  - Write Sequencer 323 */
-	[4420] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4420  - Write Sequencer 324 */
-	[4421] = { 0x00FF, 0x00FF, 0x0000 }, /* R4421  - Write Sequencer 325 */
-	[4422] = { 0x070F, 0x070F, 0x0000 }, /* R4422  - Write Sequencer 326 */
-	[4423] = { 0x010F, 0x010F, 0x0000 }, /* R4423  - Write Sequencer 327 */
-	[4424] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4424  - Write Sequencer 328 */
-	[4425] = { 0x00FF, 0x00FF, 0x0000 }, /* R4425  - Write Sequencer 329 */
-	[4426] = { 0x070F, 0x070F, 0x0000 }, /* R4426  - Write Sequencer 330 */
-	[4427] = { 0x010F, 0x010F, 0x0000 }, /* R4427  - Write Sequencer 331 */
-	[4428] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4428  - Write Sequencer 332 */
-	[4429] = { 0x00FF, 0x00FF, 0x0000 }, /* R4429  - Write Sequencer 333 */
-	[4430] = { 0x070F, 0x070F, 0x0000 }, /* R4430  - Write Sequencer 334 */
-	[4431] = { 0x010F, 0x010F, 0x0000 }, /* R4431  - Write Sequencer 335 */
-	[4432] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4432  - Write Sequencer 336 */
-	[4433] = { 0x00FF, 0x00FF, 0x0000 }, /* R4433  - Write Sequencer 337 */
-	[4434] = { 0x070F, 0x070F, 0x0000 }, /* R4434  - Write Sequencer 338 */
-	[4435] = { 0x010F, 0x010F, 0x0000 }, /* R4435  - Write Sequencer 339 */
-	[4436] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4436  - Write Sequencer 340 */
-	[4437] = { 0x00FF, 0x00FF, 0x0000 }, /* R4437  - Write Sequencer 341 */
-	[4438] = { 0x070F, 0x070F, 0x0000 }, /* R4438  - Write Sequencer 342 */
-	[4439] = { 0x010F, 0x010F, 0x0000 }, /* R4439  - Write Sequencer 343 */
-	[4440] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4440  - Write Sequencer 344 */
-	[4441] = { 0x00FF, 0x00FF, 0x0000 }, /* R4441  - Write Sequencer 345 */
-	[4442] = { 0x070F, 0x070F, 0x0000 }, /* R4442  - Write Sequencer 346 */
-	[4443] = { 0x010F, 0x010F, 0x0000 }, /* R4443  - Write Sequencer 347 */
-	[4444] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4444  - Write Sequencer 348 */
-	[4445] = { 0x00FF, 0x00FF, 0x0000 }, /* R4445  - Write Sequencer 349 */
-	[4446] = { 0x070F, 0x070F, 0x0000 }, /* R4446  - Write Sequencer 350 */
-	[4447] = { 0x010F, 0x010F, 0x0000 }, /* R4447  - Write Sequencer 351 */
-	[4448] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4448  - Write Sequencer 352 */
-	[4449] = { 0x00FF, 0x00FF, 0x0000 }, /* R4449  - Write Sequencer 353 */
-	[4450] = { 0x070F, 0x070F, 0x0000 }, /* R4450  - Write Sequencer 354 */
-	[4451] = { 0x010F, 0x010F, 0x0000 }, /* R4451  - Write Sequencer 355 */
-	[4452] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4452  - Write Sequencer 356 */
-	[4453] = { 0x00FF, 0x00FF, 0x0000 }, /* R4453  - Write Sequencer 357 */
-	[4454] = { 0x070F, 0x070F, 0x0000 }, /* R4454  - Write Sequencer 358 */
-	[4455] = { 0x010F, 0x010F, 0x0000 }, /* R4455  - Write Sequencer 359 */
-	[4456] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4456  - Write Sequencer 360 */
-	[4457] = { 0x00FF, 0x00FF, 0x0000 }, /* R4457  - Write Sequencer 361 */
-	[4458] = { 0x070F, 0x070F, 0x0000 }, /* R4458  - Write Sequencer 362 */
-	[4459] = { 0x010F, 0x010F, 0x0000 }, /* R4459  - Write Sequencer 363 */
-	[4460] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4460  - Write Sequencer 364 */
-	[4461] = { 0x00FF, 0x00FF, 0x0000 }, /* R4461  - Write Sequencer 365 */
-	[4462] = { 0x070F, 0x070F, 0x0000 }, /* R4462  - Write Sequencer 366 */
-	[4463] = { 0x010F, 0x010F, 0x0000 }, /* R4463  - Write Sequencer 367 */
-	[4464] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4464  - Write Sequencer 368 */
-	[4465] = { 0x00FF, 0x00FF, 0x0000 }, /* R4465  - Write Sequencer 369 */
-	[4466] = { 0x070F, 0x070F, 0x0000 }, /* R4466  - Write Sequencer 370 */
-	[4467] = { 0x010F, 0x010F, 0x0000 }, /* R4467  - Write Sequencer 371 */
-	[4468] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4468  - Write Sequencer 372 */
-	[4469] = { 0x00FF, 0x00FF, 0x0000 }, /* R4469  - Write Sequencer 373 */
-	[4470] = { 0x070F, 0x070F, 0x0000 }, /* R4470  - Write Sequencer 374 */
-	[4471] = { 0x010F, 0x010F, 0x0000 }, /* R4471  - Write Sequencer 375 */
-	[4472] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4472  - Write Sequencer 376 */
-	[4473] = { 0x00FF, 0x00FF, 0x0000 }, /* R4473  - Write Sequencer 377 */
-	[4474] = { 0x070F, 0x070F, 0x0000 }, /* R4474  - Write Sequencer 378 */
-	[4475] = { 0x010F, 0x010F, 0x0000 }, /* R4475  - Write Sequencer 379 */
-	[4476] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4476  - Write Sequencer 380 */
-	[4477] = { 0x00FF, 0x00FF, 0x0000 }, /* R4477  - Write Sequencer 381 */
-	[4478] = { 0x070F, 0x070F, 0x0000 }, /* R4478  - Write Sequencer 382 */
-	[4479] = { 0x010F, 0x010F, 0x0000 }, /* R4479  - Write Sequencer 383 */
-	[4480] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4480  - Write Sequencer 384 */
-	[4481] = { 0x00FF, 0x00FF, 0x0000 }, /* R4481  - Write Sequencer 385 */
-	[4482] = { 0x070F, 0x070F, 0x0000 }, /* R4482  - Write Sequencer 386 */
-	[4483] = { 0x010F, 0x010F, 0x0000 }, /* R4483  - Write Sequencer 387 */
-	[4484] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4484  - Write Sequencer 388 */
-	[4485] = { 0x00FF, 0x00FF, 0x0000 }, /* R4485  - Write Sequencer 389 */
-	[4486] = { 0x070F, 0x070F, 0x0000 }, /* R4486  - Write Sequencer 390 */
-	[4487] = { 0x010F, 0x010F, 0x0000 }, /* R4487  - Write Sequencer 391 */
-	[4488] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4488  - Write Sequencer 392 */
-	[4489] = { 0x00FF, 0x00FF, 0x0000 }, /* R4489  - Write Sequencer 393 */
-	[4490] = { 0x070F, 0x070F, 0x0000 }, /* R4490  - Write Sequencer 394 */
-	[4491] = { 0x010F, 0x010F, 0x0000 }, /* R4491  - Write Sequencer 395 */
-	[4492] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4492  - Write Sequencer 396 */
-	[4493] = { 0x00FF, 0x00FF, 0x0000 }, /* R4493  - Write Sequencer 397 */
-	[4494] = { 0x070F, 0x070F, 0x0000 }, /* R4494  - Write Sequencer 398 */
-	[4495] = { 0x010F, 0x010F, 0x0000 }, /* R4495  - Write Sequencer 399 */
-	[4496] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4496  - Write Sequencer 400 */
-	[4497] = { 0x00FF, 0x00FF, 0x0000 }, /* R4497  - Write Sequencer 401 */
-	[4498] = { 0x070F, 0x070F, 0x0000 }, /* R4498  - Write Sequencer 402 */
-	[4499] = { 0x010F, 0x010F, 0x0000 }, /* R4499  - Write Sequencer 403 */
-	[4500] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4500  - Write Sequencer 404 */
-	[4501] = { 0x00FF, 0x00FF, 0x0000 }, /* R4501  - Write Sequencer 405 */
-	[4502] = { 0x070F, 0x070F, 0x0000 }, /* R4502  - Write Sequencer 406 */
-	[4503] = { 0x010F, 0x010F, 0x0000 }, /* R4503  - Write Sequencer 407 */
-	[4504] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4504  - Write Sequencer 408 */
-	[4505] = { 0x00FF, 0x00FF, 0x0000 }, /* R4505  - Write Sequencer 409 */
-	[4506] = { 0x070F, 0x070F, 0x0000 }, /* R4506  - Write Sequencer 410 */
-	[4507] = { 0x010F, 0x010F, 0x0000 }, /* R4507  - Write Sequencer 411 */
-	[4508] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4508  - Write Sequencer 412 */
-	[4509] = { 0x00FF, 0x00FF, 0x0000 }, /* R4509  - Write Sequencer 413 */
-	[4510] = { 0x070F, 0x070F, 0x0000 }, /* R4510  - Write Sequencer 414 */
-	[4511] = { 0x010F, 0x010F, 0x0000 }, /* R4511  - Write Sequencer 415 */
-	[4512] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4512  - Write Sequencer 416 */
-	[4513] = { 0x00FF, 0x00FF, 0x0000 }, /* R4513  - Write Sequencer 417 */
-	[4514] = { 0x070F, 0x070F, 0x0000 }, /* R4514  - Write Sequencer 418 */
-	[4515] = { 0x010F, 0x010F, 0x0000 }, /* R4515  - Write Sequencer 419 */
-	[4516] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4516  - Write Sequencer 420 */
-	[4517] = { 0x00FF, 0x00FF, 0x0000 }, /* R4517  - Write Sequencer 421 */
-	[4518] = { 0x070F, 0x070F, 0x0000 }, /* R4518  - Write Sequencer 422 */
-	[4519] = { 0x010F, 0x010F, 0x0000 }, /* R4519  - Write Sequencer 423 */
-	[4520] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4520  - Write Sequencer 424 */
-	[4521] = { 0x00FF, 0x00FF, 0x0000 }, /* R4521  - Write Sequencer 425 */
-	[4522] = { 0x070F, 0x070F, 0x0000 }, /* R4522  - Write Sequencer 426 */
-	[4523] = { 0x010F, 0x010F, 0x0000 }, /* R4523  - Write Sequencer 427 */
-	[4524] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4524  - Write Sequencer 428 */
-	[4525] = { 0x00FF, 0x00FF, 0x0000 }, /* R4525  - Write Sequencer 429 */
-	[4526] = { 0x070F, 0x070F, 0x0000 }, /* R4526  - Write Sequencer 430 */
-	[4527] = { 0x010F, 0x010F, 0x0000 }, /* R4527  - Write Sequencer 431 */
-	[4528] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4528  - Write Sequencer 432 */
-	[4529] = { 0x00FF, 0x00FF, 0x0000 }, /* R4529  - Write Sequencer 433 */
-	[4530] = { 0x070F, 0x070F, 0x0000 }, /* R4530  - Write Sequencer 434 */
-	[4531] = { 0x010F, 0x010F, 0x0000 }, /* R4531  - Write Sequencer 435 */
-	[4532] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4532  - Write Sequencer 436 */
-	[4533] = { 0x00FF, 0x00FF, 0x0000 }, /* R4533  - Write Sequencer 437 */
-	[4534] = { 0x070F, 0x070F, 0x0000 }, /* R4534  - Write Sequencer 438 */
-	[4535] = { 0x010F, 0x010F, 0x0000 }, /* R4535  - Write Sequencer 439 */
-	[4536] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4536  - Write Sequencer 440 */
-	[4537] = { 0x00FF, 0x00FF, 0x0000 }, /* R4537  - Write Sequencer 441 */
-	[4538] = { 0x070F, 0x070F, 0x0000 }, /* R4538  - Write Sequencer 442 */
-	[4539] = { 0x010F, 0x010F, 0x0000 }, /* R4539  - Write Sequencer 443 */
-	[4540] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4540  - Write Sequencer 444 */
-	[4541] = { 0x00FF, 0x00FF, 0x0000 }, /* R4541  - Write Sequencer 445 */
-	[4542] = { 0x070F, 0x070F, 0x0000 }, /* R4542  - Write Sequencer 446 */
-	[4543] = { 0x010F, 0x010F, 0x0000 }, /* R4543  - Write Sequencer 447 */
-	[4544] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4544  - Write Sequencer 448 */
-	[4545] = { 0x00FF, 0x00FF, 0x0000 }, /* R4545  - Write Sequencer 449 */
-	[4546] = { 0x070F, 0x070F, 0x0000 }, /* R4546  - Write Sequencer 450 */
-	[4547] = { 0x010F, 0x010F, 0x0000 }, /* R4547  - Write Sequencer 451 */
-	[4548] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4548  - Write Sequencer 452 */
-	[4549] = { 0x00FF, 0x00FF, 0x0000 }, /* R4549  - Write Sequencer 453 */
-	[4550] = { 0x070F, 0x070F, 0x0000 }, /* R4550  - Write Sequencer 454 */
-	[4551] = { 0x010F, 0x010F, 0x0000 }, /* R4551  - Write Sequencer 455 */
-	[4552] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4552  - Write Sequencer 456 */
-	[4553] = { 0x00FF, 0x00FF, 0x0000 }, /* R4553  - Write Sequencer 457 */
-	[4554] = { 0x070F, 0x070F, 0x0000 }, /* R4554  - Write Sequencer 458 */
-	[4555] = { 0x010F, 0x010F, 0x0000 }, /* R4555  - Write Sequencer 459 */
-	[4556] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4556  - Write Sequencer 460 */
-	[4557] = { 0x00FF, 0x00FF, 0x0000 }, /* R4557  - Write Sequencer 461 */
-	[4558] = { 0x070F, 0x070F, 0x0000 }, /* R4558  - Write Sequencer 462 */
-	[4559] = { 0x010F, 0x010F, 0x0000 }, /* R4559  - Write Sequencer 463 */
-	[4560] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4560  - Write Sequencer 464 */
-	[4561] = { 0x00FF, 0x00FF, 0x0000 }, /* R4561  - Write Sequencer 465 */
-	[4562] = { 0x070F, 0x070F, 0x0000 }, /* R4562  - Write Sequencer 466 */
-	[4563] = { 0x010F, 0x010F, 0x0000 }, /* R4563  - Write Sequencer 467 */
-	[4564] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4564  - Write Sequencer 468 */
-	[4565] = { 0x00FF, 0x00FF, 0x0000 }, /* R4565  - Write Sequencer 469 */
-	[4566] = { 0x070F, 0x070F, 0x0000 }, /* R4566  - Write Sequencer 470 */
-	[4567] = { 0x010F, 0x010F, 0x0000 }, /* R4567  - Write Sequencer 471 */
-	[4568] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4568  - Write Sequencer 472 */
-	[4569] = { 0x00FF, 0x00FF, 0x0000 }, /* R4569  - Write Sequencer 473 */
-	[4570] = { 0x070F, 0x070F, 0x0000 }, /* R4570  - Write Sequencer 474 */
-	[4571] = { 0x010F, 0x010F, 0x0000 }, /* R4571  - Write Sequencer 475 */
-	[4572] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4572  - Write Sequencer 476 */
-	[4573] = { 0x00FF, 0x00FF, 0x0000 }, /* R4573  - Write Sequencer 477 */
-	[4574] = { 0x070F, 0x070F, 0x0000 }, /* R4574  - Write Sequencer 478 */
-	[4575] = { 0x010F, 0x010F, 0x0000 }, /* R4575  - Write Sequencer 479 */
-	[4576] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4576  - Write Sequencer 480 */
-	[4577] = { 0x00FF, 0x00FF, 0x0000 }, /* R4577  - Write Sequencer 481 */
-	[4578] = { 0x070F, 0x070F, 0x0000 }, /* R4578  - Write Sequencer 482 */
-	[4579] = { 0x010F, 0x010F, 0x0000 }, /* R4579  - Write Sequencer 483 */
-	[4580] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4580  - Write Sequencer 484 */
-	[4581] = { 0x00FF, 0x00FF, 0x0000 }, /* R4581  - Write Sequencer 485 */
-	[4582] = { 0x070F, 0x070F, 0x0000 }, /* R4582  - Write Sequencer 486 */
-	[4583] = { 0x010F, 0x010F, 0x0000 }, /* R4583  - Write Sequencer 487 */
-	[4584] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4584  - Write Sequencer 488 */
-	[4585] = { 0x00FF, 0x00FF, 0x0000 }, /* R4585  - Write Sequencer 489 */
-	[4586] = { 0x070F, 0x070F, 0x0000 }, /* R4586  - Write Sequencer 490 */
-	[4587] = { 0x010F, 0x010F, 0x0000 }, /* R4587  - Write Sequencer 491 */
-	[4588] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4588  - Write Sequencer 492 */
-	[4589] = { 0x00FF, 0x00FF, 0x0000 }, /* R4589  - Write Sequencer 493 */
-	[4590] = { 0x070F, 0x070F, 0x0000 }, /* R4590  - Write Sequencer 494 */
-	[4591] = { 0x010F, 0x010F, 0x0000 }, /* R4591  - Write Sequencer 495 */
-	[4592] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4592  - Write Sequencer 496 */
-	[4593] = { 0x00FF, 0x00FF, 0x0000 }, /* R4593  - Write Sequencer 497 */
-	[4594] = { 0x070F, 0x070F, 0x0000 }, /* R4594  - Write Sequencer 498 */
-	[4595] = { 0x010F, 0x010F, 0x0000 }, /* R4595  - Write Sequencer 499 */
-	[4596] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4596  - Write Sequencer 500 */
-	[4597] = { 0x00FF, 0x00FF, 0x0000 }, /* R4597  - Write Sequencer 501 */
-	[4598] = { 0x070F, 0x070F, 0x0000 }, /* R4598  - Write Sequencer 502 */
-	[4599] = { 0x010F, 0x010F, 0x0000 }, /* R4599  - Write Sequencer 503 */
-	[4600] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4600  - Write Sequencer 504 */
-	[4601] = { 0x00FF, 0x00FF, 0x0000 }, /* R4601  - Write Sequencer 505 */
-	[4602] = { 0x070F, 0x070F, 0x0000 }, /* R4602  - Write Sequencer 506 */
-	[4603] = { 0x010F, 0x010F, 0x0000 }, /* R4603  - Write Sequencer 507 */
-	[4604] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4604  - Write Sequencer 508 */
-	[4605] = { 0x00FF, 0x00FF, 0x0000 }, /* R4605  - Write Sequencer 509 */
-	[4606] = { 0x070F, 0x070F, 0x0000 }, /* R4606  - Write Sequencer 510 */
-	[4607] = { 0x010F, 0x010F, 0x0000 }, /* R4607  - Write Sequencer 511 */
-	[8192] = { 0x03FF, 0x03FF, 0x0000 }, /* R8192  - DSP2 Instruction RAM 0 */
-	[9216] = { 0x003F, 0x003F, 0x0000 }, /* R9216  - DSP2 Address RAM 2 */
-	[9217] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R9217  - DSP2 Address RAM 1 */
-	[9218] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R9218  - DSP2 Address RAM 0 */
-	[12288] = { 0x00FF, 0x00FF, 0x0000 }, /* R12288 - DSP2 Data1 RAM 1 */
-	[12289] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R12289 - DSP2 Data1 RAM 0 */
-	[13312] = { 0x00FF, 0x00FF, 0x0000 }, /* R13312 - DSP2 Data2 RAM 1 */
-	[13313] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R13313 - DSP2 Data2 RAM 0 */
-	[14336] = { 0x00FF, 0x00FF, 0x0000 }, /* R14336 - DSP2 Data3 RAM 1 */
-	[14337] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R14337 - DSP2 Data3 RAM 0 */
-	[15360] = { 0x07FF, 0x07FF, 0x0000 }, /* R15360 - DSP2 Coeff RAM 0 */
-	[16384] = { 0x00FF, 0x00FF, 0x0000 }, /* R16384 - RETUNEADC_SHARED_COEFF_1 */
-	[16385] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16385 - RETUNEADC_SHARED_COEFF_0 */
-	[16386] = { 0x00FF, 0x00FF, 0x0000 }, /* R16386 - RETUNEDAC_SHARED_COEFF_1 */
-	[16387] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16387 - RETUNEDAC_SHARED_COEFF_0 */
-	[16388] = { 0x00FF, 0x00FF, 0x0000 }, /* R16388 - SOUNDSTAGE_ENABLES_1 */
-	[16389] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16389 - SOUNDSTAGE_ENABLES_0 */
-	[16896] = { 0x00FF, 0x00FF, 0x0000 }, /* R16896 - HDBASS_AI_1 */
-	[16897] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16897 - HDBASS_AI_0 */
-	[16898] = { 0x00FF, 0x00FF, 0x0000 }, /* R16898 - HDBASS_AR_1 */
-	[16899] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16899 - HDBASS_AR_0 */
-	[16900] = { 0x00FF, 0x00FF, 0x0000 }, /* R16900 - HDBASS_B_1 */
-	[16901] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16901 - HDBASS_B_0 */
-	[16902] = { 0x00FF, 0x00FF, 0x0000 }, /* R16902 - HDBASS_K_1 */
-	[16903] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16903 - HDBASS_K_0 */
-	[16904] = { 0x00FF, 0x00FF, 0x0000 }, /* R16904 - HDBASS_N1_1 */
-	[16905] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16905 - HDBASS_N1_0 */
-	[16906] = { 0x00FF, 0x00FF, 0x0000 }, /* R16906 - HDBASS_N2_1 */
-	[16907] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16907 - HDBASS_N2_0 */
-	[16908] = { 0x00FF, 0x00FF, 0x0000 }, /* R16908 - HDBASS_N3_1 */
-	[16909] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16909 - HDBASS_N3_0 */
-	[16910] = { 0x00FF, 0x00FF, 0x0000 }, /* R16910 - HDBASS_N4_1 */
-	[16911] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16911 - HDBASS_N4_0 */
-	[16912] = { 0x00FF, 0x00FF, 0x0000 }, /* R16912 - HDBASS_N5_1 */
-	[16913] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16913 - HDBASS_N5_0 */
-	[16914] = { 0x00FF, 0x00FF, 0x0000 }, /* R16914 - HDBASS_X1_1 */
-	[16915] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16915 - HDBASS_X1_0 */
-	[16916] = { 0x00FF, 0x00FF, 0x0000 }, /* R16916 - HDBASS_X2_1 */
-	[16917] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16917 - HDBASS_X2_0 */
-	[16918] = { 0x00FF, 0x00FF, 0x0000 }, /* R16918 - HDBASS_X3_1 */
-	[16919] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16919 - HDBASS_X3_0 */
-	[16920] = { 0x00FF, 0x00FF, 0x0000 }, /* R16920 - HDBASS_ATK_1 */
-	[16921] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16921 - HDBASS_ATK_0 */
-	[16922] = { 0x00FF, 0x00FF, 0x0000 }, /* R16922 - HDBASS_DCY_1 */
-	[16923] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16923 - HDBASS_DCY_0 */
-	[16924] = { 0x00FF, 0x00FF, 0x0000 }, /* R16924 - HDBASS_PG_1 */
-	[16925] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16925 - HDBASS_PG_0 */
-	[17408] = { 0x00FF, 0x00FF, 0x0000 }, /* R17408 - HPF_C_1 */
-	[17409] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17409 - HPF_C_0 */
-	[17920] = { 0x00FF, 0x00FF, 0x0000 }, /* R17920 - ADCL_RETUNE_C1_1 */
-	[17921] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17921 - ADCL_RETUNE_C1_0 */
-	[17922] = { 0x00FF, 0x00FF, 0x0000 }, /* R17922 - ADCL_RETUNE_C2_1 */
-	[17923] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17923 - ADCL_RETUNE_C2_0 */
-	[17924] = { 0x00FF, 0x00FF, 0x0000 }, /* R17924 - ADCL_RETUNE_C3_1 */
-	[17925] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17925 - ADCL_RETUNE_C3_0 */
-	[17926] = { 0x00FF, 0x00FF, 0x0000 }, /* R17926 - ADCL_RETUNE_C4_1 */
-	[17927] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17927 - ADCL_RETUNE_C4_0 */
-	[17928] = { 0x00FF, 0x00FF, 0x0000 }, /* R17928 - ADCL_RETUNE_C5_1 */
-	[17929] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17929 - ADCL_RETUNE_C5_0 */
-	[17930] = { 0x00FF, 0x00FF, 0x0000 }, /* R17930 - ADCL_RETUNE_C6_1 */
-	[17931] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17931 - ADCL_RETUNE_C6_0 */
-	[17932] = { 0x00FF, 0x00FF, 0x0000 }, /* R17932 - ADCL_RETUNE_C7_1 */
-	[17933] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17933 - ADCL_RETUNE_C7_0 */
-	[17934] = { 0x00FF, 0x00FF, 0x0000 }, /* R17934 - ADCL_RETUNE_C8_1 */
-	[17935] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17935 - ADCL_RETUNE_C8_0 */
-	[17936] = { 0x00FF, 0x00FF, 0x0000 }, /* R17936 - ADCL_RETUNE_C9_1 */
-	[17937] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17937 - ADCL_RETUNE_C9_0 */
-	[17938] = { 0x00FF, 0x00FF, 0x0000 }, /* R17938 - ADCL_RETUNE_C10_1 */
-	[17939] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17939 - ADCL_RETUNE_C10_0 */
-	[17940] = { 0x00FF, 0x00FF, 0x0000 }, /* R17940 - ADCL_RETUNE_C11_1 */
-	[17941] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17941 - ADCL_RETUNE_C11_0 */
-	[17942] = { 0x00FF, 0x00FF, 0x0000 }, /* R17942 - ADCL_RETUNE_C12_1 */
-	[17943] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17943 - ADCL_RETUNE_C12_0 */
-	[17944] = { 0x00FF, 0x00FF, 0x0000 }, /* R17944 - ADCL_RETUNE_C13_1 */
-	[17945] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17945 - ADCL_RETUNE_C13_0 */
-	[17946] = { 0x00FF, 0x00FF, 0x0000 }, /* R17946 - ADCL_RETUNE_C14_1 */
-	[17947] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17947 - ADCL_RETUNE_C14_0 */
-	[17948] = { 0x00FF, 0x00FF, 0x0000 }, /* R17948 - ADCL_RETUNE_C15_1 */
-	[17949] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17949 - ADCL_RETUNE_C15_0 */
-	[17950] = { 0x00FF, 0x00FF, 0x0000 }, /* R17950 - ADCL_RETUNE_C16_1 */
-	[17951] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17951 - ADCL_RETUNE_C16_0 */
-	[17952] = { 0x00FF, 0x00FF, 0x0000 }, /* R17952 - ADCL_RETUNE_C17_1 */
-	[17953] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17953 - ADCL_RETUNE_C17_0 */
-	[17954] = { 0x00FF, 0x00FF, 0x0000 }, /* R17954 - ADCL_RETUNE_C18_1 */
-	[17955] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17955 - ADCL_RETUNE_C18_0 */
-	[17956] = { 0x00FF, 0x00FF, 0x0000 }, /* R17956 - ADCL_RETUNE_C19_1 */
-	[17957] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17957 - ADCL_RETUNE_C19_0 */
-	[17958] = { 0x00FF, 0x00FF, 0x0000 }, /* R17958 - ADCL_RETUNE_C20_1 */
-	[17959] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17959 - ADCL_RETUNE_C20_0 */
-	[17960] = { 0x00FF, 0x00FF, 0x0000 }, /* R17960 - ADCL_RETUNE_C21_1 */
-	[17961] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17961 - ADCL_RETUNE_C21_0 */
-	[17962] = { 0x00FF, 0x00FF, 0x0000 }, /* R17962 - ADCL_RETUNE_C22_1 */
-	[17963] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17963 - ADCL_RETUNE_C22_0 */
-	[17964] = { 0x00FF, 0x00FF, 0x0000 }, /* R17964 - ADCL_RETUNE_C23_1 */
-	[17965] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17965 - ADCL_RETUNE_C23_0 */
-	[17966] = { 0x00FF, 0x00FF, 0x0000 }, /* R17966 - ADCL_RETUNE_C24_1 */
-	[17967] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17967 - ADCL_RETUNE_C24_0 */
-	[17968] = { 0x00FF, 0x00FF, 0x0000 }, /* R17968 - ADCL_RETUNE_C25_1 */
-	[17969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17969 - ADCL_RETUNE_C25_0 */
-	[17970] = { 0x00FF, 0x00FF, 0x0000 }, /* R17970 - ADCL_RETUNE_C26_1 */
-	[17971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17971 - ADCL_RETUNE_C26_0 */
-	[17972] = { 0x00FF, 0x00FF, 0x0000 }, /* R17972 - ADCL_RETUNE_C27_1 */
-	[17973] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17973 - ADCL_RETUNE_C27_0 */
-	[17974] = { 0x00FF, 0x00FF, 0x0000 }, /* R17974 - ADCL_RETUNE_C28_1 */
-	[17975] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17975 - ADCL_RETUNE_C28_0 */
-	[17976] = { 0x00FF, 0x00FF, 0x0000 }, /* R17976 - ADCL_RETUNE_C29_1 */
-	[17977] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17977 - ADCL_RETUNE_C29_0 */
-	[17978] = { 0x00FF, 0x00FF, 0x0000 }, /* R17978 - ADCL_RETUNE_C30_1 */
-	[17979] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17979 - ADCL_RETUNE_C30_0 */
-	[17980] = { 0x00FF, 0x00FF, 0x0000 }, /* R17980 - ADCL_RETUNE_C31_1 */
-	[17981] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17981 - ADCL_RETUNE_C31_0 */
-	[17982] = { 0x00FF, 0x00FF, 0x0000 }, /* R17982 - ADCL_RETUNE_C32_1 */
-	[17983] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17983 - ADCL_RETUNE_C32_0 */
-	[18432] = { 0x00FF, 0x00FF, 0x0000 }, /* R18432 - RETUNEADC_PG2_1 */
-	[18433] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18433 - RETUNEADC_PG2_0 */
-	[18434] = { 0x00FF, 0x00FF, 0x0000 }, /* R18434 - RETUNEADC_PG_1 */
-	[18435] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18435 - RETUNEADC_PG_0 */
-	[18944] = { 0x00FF, 0x00FF, 0x0000 }, /* R18944 - ADCR_RETUNE_C1_1 */
-	[18945] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18945 - ADCR_RETUNE_C1_0 */
-	[18946] = { 0x00FF, 0x00FF, 0x0000 }, /* R18946 - ADCR_RETUNE_C2_1 */
-	[18947] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18947 - ADCR_RETUNE_C2_0 */
-	[18948] = { 0x00FF, 0x00FF, 0x0000 }, /* R18948 - ADCR_RETUNE_C3_1 */
-	[18949] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18949 - ADCR_RETUNE_C3_0 */
-	[18950] = { 0x00FF, 0x00FF, 0x0000 }, /* R18950 - ADCR_RETUNE_C4_1 */
-	[18951] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18951 - ADCR_RETUNE_C4_0 */
-	[18952] = { 0x00FF, 0x00FF, 0x0000 }, /* R18952 - ADCR_RETUNE_C5_1 */
-	[18953] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18953 - ADCR_RETUNE_C5_0 */
-	[18954] = { 0x00FF, 0x00FF, 0x0000 }, /* R18954 - ADCR_RETUNE_C6_1 */
-	[18955] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18955 - ADCR_RETUNE_C6_0 */
-	[18956] = { 0x00FF, 0x00FF, 0x0000 }, /* R18956 - ADCR_RETUNE_C7_1 */
-	[18957] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18957 - ADCR_RETUNE_C7_0 */
-	[18958] = { 0x00FF, 0x00FF, 0x0000 }, /* R18958 - ADCR_RETUNE_C8_1 */
-	[18959] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18959 - ADCR_RETUNE_C8_0 */
-	[18960] = { 0x00FF, 0x00FF, 0x0000 }, /* R18960 - ADCR_RETUNE_C9_1 */
-	[18961] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18961 - ADCR_RETUNE_C9_0 */
-	[18962] = { 0x00FF, 0x00FF, 0x0000 }, /* R18962 - ADCR_RETUNE_C10_1 */
-	[18963] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18963 - ADCR_RETUNE_C10_0 */
-	[18964] = { 0x00FF, 0x00FF, 0x0000 }, /* R18964 - ADCR_RETUNE_C11_1 */
-	[18965] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18965 - ADCR_RETUNE_C11_0 */
-	[18966] = { 0x00FF, 0x00FF, 0x0000 }, /* R18966 - ADCR_RETUNE_C12_1 */
-	[18967] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18967 - ADCR_RETUNE_C12_0 */
-	[18968] = { 0x00FF, 0x00FF, 0x0000 }, /* R18968 - ADCR_RETUNE_C13_1 */
-	[18969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18969 - ADCR_RETUNE_C13_0 */
-	[18970] = { 0x00FF, 0x00FF, 0x0000 }, /* R18970 - ADCR_RETUNE_C14_1 */
-	[18971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18971 - ADCR_RETUNE_C14_0 */
-	[18972] = { 0x00FF, 0x00FF, 0x0000 }, /* R18972 - ADCR_RETUNE_C15_1 */
-	[18973] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18973 - ADCR_RETUNE_C15_0 */
-	[18974] = { 0x00FF, 0x00FF, 0x0000 }, /* R18974 - ADCR_RETUNE_C16_1 */
-	[18975] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18975 - ADCR_RETUNE_C16_0 */
-	[18976] = { 0x00FF, 0x00FF, 0x0000 }, /* R18976 - ADCR_RETUNE_C17_1 */
-	[18977] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18977 - ADCR_RETUNE_C17_0 */
-	[18978] = { 0x00FF, 0x00FF, 0x0000 }, /* R18978 - ADCR_RETUNE_C18_1 */
-	[18979] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18979 - ADCR_RETUNE_C18_0 */
-	[18980] = { 0x00FF, 0x00FF, 0x0000 }, /* R18980 - ADCR_RETUNE_C19_1 */
-	[18981] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18981 - ADCR_RETUNE_C19_0 */
-	[18982] = { 0x00FF, 0x00FF, 0x0000 }, /* R18982 - ADCR_RETUNE_C20_1 */
-	[18983] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18983 - ADCR_RETUNE_C20_0 */
-	[18984] = { 0x00FF, 0x00FF, 0x0000 }, /* R18984 - ADCR_RETUNE_C21_1 */
-	[18985] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18985 - ADCR_RETUNE_C21_0 */
-	[18986] = { 0x00FF, 0x00FF, 0x0000 }, /* R18986 - ADCR_RETUNE_C22_1 */
-	[18987] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18987 - ADCR_RETUNE_C22_0 */
-	[18988] = { 0x00FF, 0x00FF, 0x0000 }, /* R18988 - ADCR_RETUNE_C23_1 */
-	[18989] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18989 - ADCR_RETUNE_C23_0 */
-	[18990] = { 0x00FF, 0x00FF, 0x0000 }, /* R18990 - ADCR_RETUNE_C24_1 */
-	[18991] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18991 - ADCR_RETUNE_C24_0 */
-	[18992] = { 0x00FF, 0x00FF, 0x0000 }, /* R18992 - ADCR_RETUNE_C25_1 */
-	[18993] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18993 - ADCR_RETUNE_C25_0 */
-	[18994] = { 0x00FF, 0x00FF, 0x0000 }, /* R18994 - ADCR_RETUNE_C26_1 */
-	[18995] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18995 - ADCR_RETUNE_C26_0 */
-	[18996] = { 0x00FF, 0x00FF, 0x0000 }, /* R18996 - ADCR_RETUNE_C27_1 */
-	[18997] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18997 - ADCR_RETUNE_C27_0 */
-	[18998] = { 0x00FF, 0x00FF, 0x0000 }, /* R18998 - ADCR_RETUNE_C28_1 */
-	[18999] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18999 - ADCR_RETUNE_C28_0 */
-	[19000] = { 0x00FF, 0x00FF, 0x0000 }, /* R19000 - ADCR_RETUNE_C29_1 */
-	[19001] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19001 - ADCR_RETUNE_C29_0 */
-	[19002] = { 0x00FF, 0x00FF, 0x0000 }, /* R19002 - ADCR_RETUNE_C30_1 */
-	[19003] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19003 - ADCR_RETUNE_C30_0 */
-	[19004] = { 0x00FF, 0x00FF, 0x0000 }, /* R19004 - ADCR_RETUNE_C31_1 */
-	[19005] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19005 - ADCR_RETUNE_C31_0 */
-	[19006] = { 0x00FF, 0x00FF, 0x0000 }, /* R19006 - ADCR_RETUNE_C32_1 */
-	[19007] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19007 - ADCR_RETUNE_C32_0 */
-	[19456] = { 0x00FF, 0x00FF, 0x0000 }, /* R19456 - DACL_RETUNE_C1_1 */
-	[19457] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19457 - DACL_RETUNE_C1_0 */
-	[19458] = { 0x00FF, 0x00FF, 0x0000 }, /* R19458 - DACL_RETUNE_C2_1 */
-	[19459] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19459 - DACL_RETUNE_C2_0 */
-	[19460] = { 0x00FF, 0x00FF, 0x0000 }, /* R19460 - DACL_RETUNE_C3_1 */
-	[19461] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19461 - DACL_RETUNE_C3_0 */
-	[19462] = { 0x00FF, 0x00FF, 0x0000 }, /* R19462 - DACL_RETUNE_C4_1 */
-	[19463] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19463 - DACL_RETUNE_C4_0 */
-	[19464] = { 0x00FF, 0x00FF, 0x0000 }, /* R19464 - DACL_RETUNE_C5_1 */
-	[19465] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19465 - DACL_RETUNE_C5_0 */
-	[19466] = { 0x00FF, 0x00FF, 0x0000 }, /* R19466 - DACL_RETUNE_C6_1 */
-	[19467] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19467 - DACL_RETUNE_C6_0 */
-	[19468] = { 0x00FF, 0x00FF, 0x0000 }, /* R19468 - DACL_RETUNE_C7_1 */
-	[19469] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19469 - DACL_RETUNE_C7_0 */
-	[19470] = { 0x00FF, 0x00FF, 0x0000 }, /* R19470 - DACL_RETUNE_C8_1 */
-	[19471] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19471 - DACL_RETUNE_C8_0 */
-	[19472] = { 0x00FF, 0x00FF, 0x0000 }, /* R19472 - DACL_RETUNE_C9_1 */
-	[19473] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19473 - DACL_RETUNE_C9_0 */
-	[19474] = { 0x00FF, 0x00FF, 0x0000 }, /* R19474 - DACL_RETUNE_C10_1 */
-	[19475] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19475 - DACL_RETUNE_C10_0 */
-	[19476] = { 0x00FF, 0x00FF, 0x0000 }, /* R19476 - DACL_RETUNE_C11_1 */
-	[19477] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19477 - DACL_RETUNE_C11_0 */
-	[19478] = { 0x00FF, 0x00FF, 0x0000 }, /* R19478 - DACL_RETUNE_C12_1 */
-	[19479] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19479 - DACL_RETUNE_C12_0 */
-	[19480] = { 0x00FF, 0x00FF, 0x0000 }, /* R19480 - DACL_RETUNE_C13_1 */
-	[19481] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19481 - DACL_RETUNE_C13_0 */
-	[19482] = { 0x00FF, 0x00FF, 0x0000 }, /* R19482 - DACL_RETUNE_C14_1 */
-	[19483] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19483 - DACL_RETUNE_C14_0 */
-	[19484] = { 0x00FF, 0x00FF, 0x0000 }, /* R19484 - DACL_RETUNE_C15_1 */
-	[19485] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19485 - DACL_RETUNE_C15_0 */
-	[19486] = { 0x00FF, 0x00FF, 0x0000 }, /* R19486 - DACL_RETUNE_C16_1 */
-	[19487] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19487 - DACL_RETUNE_C16_0 */
-	[19488] = { 0x00FF, 0x00FF, 0x0000 }, /* R19488 - DACL_RETUNE_C17_1 */
-	[19489] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19489 - DACL_RETUNE_C17_0 */
-	[19490] = { 0x00FF, 0x00FF, 0x0000 }, /* R19490 - DACL_RETUNE_C18_1 */
-	[19491] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19491 - DACL_RETUNE_C18_0 */
-	[19492] = { 0x00FF, 0x00FF, 0x0000 }, /* R19492 - DACL_RETUNE_C19_1 */
-	[19493] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19493 - DACL_RETUNE_C19_0 */
-	[19494] = { 0x00FF, 0x00FF, 0x0000 }, /* R19494 - DACL_RETUNE_C20_1 */
-	[19495] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19495 - DACL_RETUNE_C20_0 */
-	[19496] = { 0x00FF, 0x00FF, 0x0000 }, /* R19496 - DACL_RETUNE_C21_1 */
-	[19497] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19497 - DACL_RETUNE_C21_0 */
-	[19498] = { 0x00FF, 0x00FF, 0x0000 }, /* R19498 - DACL_RETUNE_C22_1 */
-	[19499] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19499 - DACL_RETUNE_C22_0 */
-	[19500] = { 0x00FF, 0x00FF, 0x0000 }, /* R19500 - DACL_RETUNE_C23_1 */
-	[19501] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19501 - DACL_RETUNE_C23_0 */
-	[19502] = { 0x00FF, 0x00FF, 0x0000 }, /* R19502 - DACL_RETUNE_C24_1 */
-	[19503] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19503 - DACL_RETUNE_C24_0 */
-	[19504] = { 0x00FF, 0x00FF, 0x0000 }, /* R19504 - DACL_RETUNE_C25_1 */
-	[19505] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19505 - DACL_RETUNE_C25_0 */
-	[19506] = { 0x00FF, 0x00FF, 0x0000 }, /* R19506 - DACL_RETUNE_C26_1 */
-	[19507] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19507 - DACL_RETUNE_C26_0 */
-	[19508] = { 0x00FF, 0x00FF, 0x0000 }, /* R19508 - DACL_RETUNE_C27_1 */
-	[19509] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19509 - DACL_RETUNE_C27_0 */
-	[19510] = { 0x00FF, 0x00FF, 0x0000 }, /* R19510 - DACL_RETUNE_C28_1 */
-	[19511] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19511 - DACL_RETUNE_C28_0 */
-	[19512] = { 0x00FF, 0x00FF, 0x0000 }, /* R19512 - DACL_RETUNE_C29_1 */
-	[19513] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19513 - DACL_RETUNE_C29_0 */
-	[19514] = { 0x00FF, 0x00FF, 0x0000 }, /* R19514 - DACL_RETUNE_C30_1 */
-	[19515] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19515 - DACL_RETUNE_C30_0 */
-	[19516] = { 0x00FF, 0x00FF, 0x0000 }, /* R19516 - DACL_RETUNE_C31_1 */
-	[19517] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19517 - DACL_RETUNE_C31_0 */
-	[19518] = { 0x00FF, 0x00FF, 0x0000 }, /* R19518 - DACL_RETUNE_C32_1 */
-	[19519] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19519 - DACL_RETUNE_C32_0 */
-	[19968] = { 0x00FF, 0x00FF, 0x0000 }, /* R19968 - RETUNEDAC_PG2_1 */
-	[19969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19969 - RETUNEDAC_PG2_0 */
-	[19970] = { 0x00FF, 0x00FF, 0x0000 }, /* R19970 - RETUNEDAC_PG_1 */
-	[19971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19971 - RETUNEDAC_PG_0 */
-	[20480] = { 0x00FF, 0x00FF, 0x0000 }, /* R20480 - DACR_RETUNE_C1_1 */
-	[20481] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20481 - DACR_RETUNE_C1_0 */
-	[20482] = { 0x00FF, 0x00FF, 0x0000 }, /* R20482 - DACR_RETUNE_C2_1 */
-	[20483] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20483 - DACR_RETUNE_C2_0 */
-	[20484] = { 0x00FF, 0x00FF, 0x0000 }, /* R20484 - DACR_RETUNE_C3_1 */
-	[20485] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20485 - DACR_RETUNE_C3_0 */
-	[20486] = { 0x00FF, 0x00FF, 0x0000 }, /* R20486 - DACR_RETUNE_C4_1 */
-	[20487] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20487 - DACR_RETUNE_C4_0 */
-	[20488] = { 0x00FF, 0x00FF, 0x0000 }, /* R20488 - DACR_RETUNE_C5_1 */
-	[20489] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20489 - DACR_RETUNE_C5_0 */
-	[20490] = { 0x00FF, 0x00FF, 0x0000 }, /* R20490 - DACR_RETUNE_C6_1 */
-	[20491] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20491 - DACR_RETUNE_C6_0 */
-	[20492] = { 0x00FF, 0x00FF, 0x0000 }, /* R20492 - DACR_RETUNE_C7_1 */
-	[20493] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20493 - DACR_RETUNE_C7_0 */
-	[20494] = { 0x00FF, 0x00FF, 0x0000 }, /* R20494 - DACR_RETUNE_C8_1 */
-	[20495] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20495 - DACR_RETUNE_C8_0 */
-	[20496] = { 0x00FF, 0x00FF, 0x0000 }, /* R20496 - DACR_RETUNE_C9_1 */
-	[20497] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20497 - DACR_RETUNE_C9_0 */
-	[20498] = { 0x00FF, 0x00FF, 0x0000 }, /* R20498 - DACR_RETUNE_C10_1 */
-	[20499] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20499 - DACR_RETUNE_C10_0 */
-	[20500] = { 0x00FF, 0x00FF, 0x0000 }, /* R20500 - DACR_RETUNE_C11_1 */
-	[20501] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20501 - DACR_RETUNE_C11_0 */
-	[20502] = { 0x00FF, 0x00FF, 0x0000 }, /* R20502 - DACR_RETUNE_C12_1 */
-	[20503] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20503 - DACR_RETUNE_C12_0 */
-	[20504] = { 0x00FF, 0x00FF, 0x0000 }, /* R20504 - DACR_RETUNE_C13_1 */
-	[20505] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20505 - DACR_RETUNE_C13_0 */
-	[20506] = { 0x00FF, 0x00FF, 0x0000 }, /* R20506 - DACR_RETUNE_C14_1 */
-	[20507] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20507 - DACR_RETUNE_C14_0 */
-	[20508] = { 0x00FF, 0x00FF, 0x0000 }, /* R20508 - DACR_RETUNE_C15_1 */
-	[20509] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20509 - DACR_RETUNE_C15_0 */
-	[20510] = { 0x00FF, 0x00FF, 0x0000 }, /* R20510 - DACR_RETUNE_C16_1 */
-	[20511] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20511 - DACR_RETUNE_C16_0 */
-	[20512] = { 0x00FF, 0x00FF, 0x0000 }, /* R20512 - DACR_RETUNE_C17_1 */
-	[20513] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20513 - DACR_RETUNE_C17_0 */
-	[20514] = { 0x00FF, 0x00FF, 0x0000 }, /* R20514 - DACR_RETUNE_C18_1 */
-	[20515] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20515 - DACR_RETUNE_C18_0 */
-	[20516] = { 0x00FF, 0x00FF, 0x0000 }, /* R20516 - DACR_RETUNE_C19_1 */
-	[20517] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20517 - DACR_RETUNE_C19_0 */
-	[20518] = { 0x00FF, 0x00FF, 0x0000 }, /* R20518 - DACR_RETUNE_C20_1 */
-	[20519] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20519 - DACR_RETUNE_C20_0 */
-	[20520] = { 0x00FF, 0x00FF, 0x0000 }, /* R20520 - DACR_RETUNE_C21_1 */
-	[20521] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20521 - DACR_RETUNE_C21_0 */
-	[20522] = { 0x00FF, 0x00FF, 0x0000 }, /* R20522 - DACR_RETUNE_C22_1 */
-	[20523] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20523 - DACR_RETUNE_C22_0 */
-	[20524] = { 0x00FF, 0x00FF, 0x0000 }, /* R20524 - DACR_RETUNE_C23_1 */
-	[20525] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20525 - DACR_RETUNE_C23_0 */
-	[20526] = { 0x00FF, 0x00FF, 0x0000 }, /* R20526 - DACR_RETUNE_C24_1 */
-	[20527] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20527 - DACR_RETUNE_C24_0 */
-	[20528] = { 0x00FF, 0x00FF, 0x0000 }, /* R20528 - DACR_RETUNE_C25_1 */
-	[20529] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20529 - DACR_RETUNE_C25_0 */
-	[20530] = { 0x00FF, 0x00FF, 0x0000 }, /* R20530 - DACR_RETUNE_C26_1 */
-	[20531] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20531 - DACR_RETUNE_C26_0 */
-	[20532] = { 0x00FF, 0x00FF, 0x0000 }, /* R20532 - DACR_RETUNE_C27_1 */
-	[20533] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20533 - DACR_RETUNE_C27_0 */
-	[20534] = { 0x00FF, 0x00FF, 0x0000 }, /* R20534 - DACR_RETUNE_C28_1 */
-	[20535] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20535 - DACR_RETUNE_C28_0 */
-	[20536] = { 0x00FF, 0x00FF, 0x0000 }, /* R20536 - DACR_RETUNE_C29_1 */
-	[20537] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20537 - DACR_RETUNE_C29_0 */
-	[20538] = { 0x00FF, 0x00FF, 0x0000 }, /* R20538 - DACR_RETUNE_C30_1 */
-	[20539] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20539 - DACR_RETUNE_C30_0 */
-	[20540] = { 0x00FF, 0x00FF, 0x0000 }, /* R20540 - DACR_RETUNE_C31_1 */
-	[20541] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20541 - DACR_RETUNE_C31_0 */
-	[20542] = { 0x00FF, 0x00FF, 0x0000 }, /* R20542 - DACR_RETUNE_C32_1 */
-	[20543] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20543 - DACR_RETUNE_C32_0 */
-	[20992] = { 0x00FF, 0x00FF, 0x0000 }, /* R20992 - VSS_XHD2_1 */
-	[20993] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20993 - VSS_XHD2_0 */
-	[20994] = { 0x00FF, 0x00FF, 0x0000 }, /* R20994 - VSS_XHD3_1 */
-	[20995] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20995 - VSS_XHD3_0 */
-	[20996] = { 0x00FF, 0x00FF, 0x0000 }, /* R20996 - VSS_XHN1_1 */
-	[20997] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20997 - VSS_XHN1_0 */
-	[20998] = { 0x00FF, 0x00FF, 0x0000 }, /* R20998 - VSS_XHN2_1 */
-	[20999] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20999 - VSS_XHN2_0 */
-	[21000] = { 0x00FF, 0x00FF, 0x0000 }, /* R21000 - VSS_XHN3_1 */
-	[21001] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21001 - VSS_XHN3_0 */
-	[21002] = { 0x00FF, 0x00FF, 0x0000 }, /* R21002 - VSS_XLA_1 */
-	[21003] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21003 - VSS_XLA_0 */
-	[21004] = { 0x00FF, 0x00FF, 0x0000 }, /* R21004 - VSS_XLB_1 */
-	[21005] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21005 - VSS_XLB_0 */
-	[21006] = { 0x00FF, 0x00FF, 0x0000 }, /* R21006 - VSS_XLG_1 */
-	[21007] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21007 - VSS_XLG_0 */
-	[21008] = { 0x00FF, 0x00FF, 0x0000 }, /* R21008 - VSS_PG2_1 */
-	[21009] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21009 - VSS_PG2_0 */
-	[21010] = { 0x00FF, 0x00FF, 0x0000 }, /* R21010 - VSS_PG_1 */
-	[21011] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21011 - VSS_PG_0 */
-	[21012] = { 0x00FF, 0x00FF, 0x0000 }, /* R21012 - VSS_XTD1_1 */
-	[21013] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21013 - VSS_XTD1_0 */
-	[21014] = { 0x00FF, 0x00FF, 0x0000 }, /* R21014 - VSS_XTD2_1 */
-	[21015] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21015 - VSS_XTD2_0 */
-	[21016] = { 0x00FF, 0x00FF, 0x0000 }, /* R21016 - VSS_XTD3_1 */
-	[21017] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21017 - VSS_XTD3_0 */
-	[21018] = { 0x00FF, 0x00FF, 0x0000 }, /* R21018 - VSS_XTD4_1 */
-	[21019] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21019 - VSS_XTD4_0 */
-	[21020] = { 0x00FF, 0x00FF, 0x0000 }, /* R21020 - VSS_XTD5_1 */
-	[21021] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21021 - VSS_XTD5_0 */
-	[21022] = { 0x00FF, 0x00FF, 0x0000 }, /* R21022 - VSS_XTD6_1 */
-	[21023] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21023 - VSS_XTD6_0 */
-	[21024] = { 0x00FF, 0x00FF, 0x0000 }, /* R21024 - VSS_XTD7_1 */
-	[21025] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21025 - VSS_XTD7_0 */
-	[21026] = { 0x00FF, 0x00FF, 0x0000 }, /* R21026 - VSS_XTD8_1 */
-	[21027] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21027 - VSS_XTD8_0 */
-	[21028] = { 0x00FF, 0x00FF, 0x0000 }, /* R21028 - VSS_XTD9_1 */
-	[21029] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21029 - VSS_XTD9_0 */
-	[21030] = { 0x00FF, 0x00FF, 0x0000 }, /* R21030 - VSS_XTD10_1 */
-	[21031] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21031 - VSS_XTD10_0 */
-	[21032] = { 0x00FF, 0x00FF, 0x0000 }, /* R21032 - VSS_XTD11_1 */
-	[21033] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21033 - VSS_XTD11_0 */
-	[21034] = { 0x00FF, 0x00FF, 0x0000 }, /* R21034 - VSS_XTD12_1 */
-	[21035] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21035 - VSS_XTD12_0 */
-	[21036] = { 0x00FF, 0x00FF, 0x0000 }, /* R21036 - VSS_XTD13_1 */
-	[21037] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21037 - VSS_XTD13_0 */
-	[21038] = { 0x00FF, 0x00FF, 0x0000 }, /* R21038 - VSS_XTD14_1 */
-	[21039] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21039 - VSS_XTD14_0 */
-	[21040] = { 0x00FF, 0x00FF, 0x0000 }, /* R21040 - VSS_XTD15_1 */
-	[21041] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21041 - VSS_XTD15_0 */
-	[21042] = { 0x00FF, 0x00FF, 0x0000 }, /* R21042 - VSS_XTD16_1 */
-	[21043] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21043 - VSS_XTD16_0 */
-	[21044] = { 0x00FF, 0x00FF, 0x0000 }, /* R21044 - VSS_XTD17_1 */
-	[21045] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21045 - VSS_XTD17_0 */
-	[21046] = { 0x00FF, 0x00FF, 0x0000 }, /* R21046 - VSS_XTD18_1 */
-	[21047] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21047 - VSS_XTD18_0 */
-	[21048] = { 0x00FF, 0x00FF, 0x0000 }, /* R21048 - VSS_XTD19_1 */
-	[21049] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21049 - VSS_XTD19_0 */
-	[21050] = { 0x00FF, 0x00FF, 0x0000 }, /* R21050 - VSS_XTD20_1 */
-	[21051] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21051 - VSS_XTD20_0 */
-	[21052] = { 0x00FF, 0x00FF, 0x0000 }, /* R21052 - VSS_XTD21_1 */
-	[21053] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21053 - VSS_XTD21_0 */
-	[21054] = { 0x00FF, 0x00FF, 0x0000 }, /* R21054 - VSS_XTD22_1 */
-	[21055] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21055 - VSS_XTD22_0 */
-	[21056] = { 0x00FF, 0x00FF, 0x0000 }, /* R21056 - VSS_XTD23_1 */
-	[21057] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21057 - VSS_XTD23_0 */
-	[21058] = { 0x00FF, 0x00FF, 0x0000 }, /* R21058 - VSS_XTD24_1 */
-	[21059] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21059 - VSS_XTD24_0 */
-	[21060] = { 0x00FF, 0x00FF, 0x0000 }, /* R21060 - VSS_XTD25_1 */
-	[21061] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21061 - VSS_XTD25_0 */
-	[21062] = { 0x00FF, 0x00FF, 0x0000 }, /* R21062 - VSS_XTD26_1 */
-	[21063] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21063 - VSS_XTD26_0 */
-	[21064] = { 0x00FF, 0x00FF, 0x0000 }, /* R21064 - VSS_XTD27_1 */
-	[21065] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21065 - VSS_XTD27_0 */
-	[21066] = { 0x00FF, 0x00FF, 0x0000 }, /* R21066 - VSS_XTD28_1 */
-	[21067] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21067 - VSS_XTD28_0 */
-	[21068] = { 0x00FF, 0x00FF, 0x0000 }, /* R21068 - VSS_XTD29_1 */
-	[21069] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21069 - VSS_XTD29_0 */
-	[21070] = { 0x00FF, 0x00FF, 0x0000 }, /* R21070 - VSS_XTD30_1 */
-	[21071] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21071 - VSS_XTD30_0 */
-	[21072] = { 0x00FF, 0x00FF, 0x0000 }, /* R21072 - VSS_XTD31_1 */
-	[21073] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21073 - VSS_XTD31_0 */
-	[21074] = { 0x00FF, 0x00FF, 0x0000 }, /* R21074 - VSS_XTD32_1 */
-	[21075] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21075 - VSS_XTD32_0 */
-	[21076] = { 0x00FF, 0x00FF, 0x0000 }, /* R21076 - VSS_XTS1_1 */
-	[21077] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21077 - VSS_XTS1_0 */
-	[21078] = { 0x00FF, 0x00FF, 0x0000 }, /* R21078 - VSS_XTS2_1 */
-	[21079] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21079 - VSS_XTS2_0 */
-	[21080] = { 0x00FF, 0x00FF, 0x0000 }, /* R21080 - VSS_XTS3_1 */
-	[21081] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21081 - VSS_XTS3_0 */
-	[21082] = { 0x00FF, 0x00FF, 0x0000 }, /* R21082 - VSS_XTS4_1 */
-	[21083] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21083 - VSS_XTS4_0 */
-	[21084] = { 0x00FF, 0x00FF, 0x0000 }, /* R21084 - VSS_XTS5_1 */
-	[21085] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21085 - VSS_XTS5_0 */
-	[21086] = { 0x00FF, 0x00FF, 0x0000 }, /* R21086 - VSS_XTS6_1 */
-	[21087] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21087 - VSS_XTS6_0 */
-	[21088] = { 0x00FF, 0x00FF, 0x0000 }, /* R21088 - VSS_XTS7_1 */
-	[21089] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21089 - VSS_XTS7_0 */
-	[21090] = { 0x00FF, 0x00FF, 0x0000 }, /* R21090 - VSS_XTS8_1 */
-	[21091] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21091 - VSS_XTS8_0 */
-	[21092] = { 0x00FF, 0x00FF, 0x0000 }, /* R21092 - VSS_XTS9_1 */
-	[21093] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21093 - VSS_XTS9_0 */
-	[21094] = { 0x00FF, 0x00FF, 0x0000 }, /* R21094 - VSS_XTS10_1 */
-	[21095] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21095 - VSS_XTS10_0 */
-	[21096] = { 0x00FF, 0x00FF, 0x0000 }, /* R21096 - VSS_XTS11_1 */
-	[21097] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21097 - VSS_XTS11_0 */
-	[21098] = { 0x00FF, 0x00FF, 0x0000 }, /* R21098 - VSS_XTS12_1 */
-	[21099] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21099 - VSS_XTS12_0 */
-	[21100] = { 0x00FF, 0x00FF, 0x0000 }, /* R21100 - VSS_XTS13_1 */
-	[21101] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21101 - VSS_XTS13_0 */
-	[21102] = { 0x00FF, 0x00FF, 0x0000 }, /* R21102 - VSS_XTS14_1 */
-	[21103] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21103 - VSS_XTS14_0 */
-	[21104] = { 0x00FF, 0x00FF, 0x0000 }, /* R21104 - VSS_XTS15_1 */
-	[21105] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21105 - VSS_XTS15_0 */
-	[21106] = { 0x00FF, 0x00FF, 0x0000 }, /* R21106 - VSS_XTS16_1 */
-	[21107] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21107 - VSS_XTS16_0 */
-	[21108] = { 0x00FF, 0x00FF, 0x0000 }, /* R21108 - VSS_XTS17_1 */
-	[21109] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21109 - VSS_XTS17_0 */
-	[21110] = { 0x00FF, 0x00FF, 0x0000 }, /* R21110 - VSS_XTS18_1 */
-	[21111] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21111 - VSS_XTS18_0 */
-	[21112] = { 0x00FF, 0x00FF, 0x0000 }, /* R21112 - VSS_XTS19_1 */
-	[21113] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21113 - VSS_XTS19_0 */
-	[21114] = { 0x00FF, 0x00FF, 0x0000 }, /* R21114 - VSS_XTS20_1 */
-	[21115] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21115 - VSS_XTS20_0 */
-	[21116] = { 0x00FF, 0x00FF, 0x0000 }, /* R21116 - VSS_XTS21_1 */
-	[21117] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21117 - VSS_XTS21_0 */
-	[21118] = { 0x00FF, 0x00FF, 0x0000 }, /* R21118 - VSS_XTS22_1 */
-	[21119] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21119 - VSS_XTS22_0 */
-	[21120] = { 0x00FF, 0x00FF, 0x0000 }, /* R21120 - VSS_XTS23_1 */
-	[21121] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21121 - VSS_XTS23_0 */
-	[21122] = { 0x00FF, 0x00FF, 0x0000 }, /* R21122 - VSS_XTS24_1 */
-	[21123] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21123 - VSS_XTS24_0 */
-	[21124] = { 0x00FF, 0x00FF, 0x0000 }, /* R21124 - VSS_XTS25_1 */
-	[21125] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21125 - VSS_XTS25_0 */
-	[21126] = { 0x00FF, 0x00FF, 0x0000 }, /* R21126 - VSS_XTS26_1 */
-	[21127] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21127 - VSS_XTS26_0 */
-	[21128] = { 0x00FF, 0x00FF, 0x0000 }, /* R21128 - VSS_XTS27_1 */
-	[21129] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21129 - VSS_XTS27_0 */
-	[21130] = { 0x00FF, 0x00FF, 0x0000 }, /* R21130 - VSS_XTS28_1 */
-	[21131] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21131 - VSS_XTS28_0 */
-	[21132] = { 0x00FF, 0x00FF, 0x0000 }, /* R21132 - VSS_XTS29_1 */
-	[21133] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21133 - VSS_XTS29_0 */
-	[21134] = { 0x00FF, 0x00FF, 0x0000 }, /* R21134 - VSS_XTS30_1 */
-	[21135] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21135 - VSS_XTS30_0 */
-	[21136] = { 0x00FF, 0x00FF, 0x0000 }, /* R21136 - VSS_XTS31_1 */
-	[21137] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21137 - VSS_XTS31_0 */
-	[21138] = { 0x00FF, 0x00FF, 0x0000 }, /* R21138 - VSS_XTS32_1 */
-	[21139] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21139 - VSS_XTS32_0 */
-};
-
 static bool wm8962_volatile_register(struct device *dev, unsigned int reg)
 {
-	if (wm8962_reg_access[reg].vol)
-		return 1;
-	else
-		return 0;
+	switch (reg) {
+	case WM8962_CLOCKING1:
+	case WM8962_CLOCKING2:
+	case WM8962_SOFTWARE_RESET:
+	case WM8962_ALC2:
+	case WM8962_THERMAL_SHUTDOWN_STATUS:
+	case WM8962_ADDITIONAL_CONTROL_4:
+	case WM8962_CLASS_D_CONTROL_1:
+	case WM8962_DC_SERVO_6:
+	case WM8962_INTERRUPT_STATUS_1:
+	case WM8962_INTERRUPT_STATUS_2:
+	case WM8962_DSP2_EXECCONTROL:
+		return true;
+	default:
+		return false;
+	}
 }
 
 static bool wm8962_readable_register(struct device *dev, unsigned int reg)
 {
-	if (wm8962_reg_access[reg].read)
-		return 1;
-	else
-		return 0;
+	switch (reg) {
+	case WM8962_LEFT_INPUT_VOLUME:
+	case WM8962_RIGHT_INPUT_VOLUME:
+	case WM8962_HPOUTL_VOLUME:
+	case WM8962_HPOUTR_VOLUME:
+	case WM8962_CLOCKING1:
+	case WM8962_ADC_DAC_CONTROL_1:
+	case WM8962_ADC_DAC_CONTROL_2:
+	case WM8962_AUDIO_INTERFACE_0:
+	case WM8962_CLOCKING2:
+	case WM8962_AUDIO_INTERFACE_1:
+	case WM8962_LEFT_DAC_VOLUME:
+	case WM8962_RIGHT_DAC_VOLUME:
+	case WM8962_AUDIO_INTERFACE_2:
+	case WM8962_SOFTWARE_RESET:
+	case WM8962_ALC1:
+	case WM8962_ALC2:
+	case WM8962_ALC3:
+	case WM8962_NOISE_GATE:
+	case WM8962_LEFT_ADC_VOLUME:
+	case WM8962_RIGHT_ADC_VOLUME:
+	case WM8962_ADDITIONAL_CONTROL_1:
+	case WM8962_ADDITIONAL_CONTROL_2:
+	case WM8962_PWR_MGMT_1:
+	case WM8962_PWR_MGMT_2:
+	case WM8962_ADDITIONAL_CONTROL_3:
+	case WM8962_ANTI_POP:
+	case WM8962_CLOCKING_3:
+	case WM8962_INPUT_MIXER_CONTROL_1:
+	case WM8962_LEFT_INPUT_MIXER_VOLUME:
+	case WM8962_RIGHT_INPUT_MIXER_VOLUME:
+	case WM8962_INPUT_MIXER_CONTROL_2:
+	case WM8962_INPUT_BIAS_CONTROL:
+	case WM8962_LEFT_INPUT_PGA_CONTROL:
+	case WM8962_RIGHT_INPUT_PGA_CONTROL:
+	case WM8962_SPKOUTL_VOLUME:
+	case WM8962_SPKOUTR_VOLUME:
+	case WM8962_THERMAL_SHUTDOWN_STATUS:
+	case WM8962_ADDITIONAL_CONTROL_4:
+	case WM8962_CLASS_D_CONTROL_1:
+	case WM8962_CLASS_D_CONTROL_2:
+	case WM8962_CLOCKING_4:
+	case WM8962_DAC_DSP_MIXING_1:
+	case WM8962_DAC_DSP_MIXING_2:
+	case WM8962_DC_SERVO_0:
+	case WM8962_DC_SERVO_1:
+	case WM8962_DC_SERVO_4:
+	case WM8962_DC_SERVO_6:
+	case WM8962_ANALOGUE_PGA_BIAS:
+	case WM8962_ANALOGUE_HP_0:
+	case WM8962_ANALOGUE_HP_2:
+	case WM8962_CHARGE_PUMP_1:
+	case WM8962_CHARGE_PUMP_B:
+	case WM8962_WRITE_SEQUENCER_CONTROL_1:
+	case WM8962_WRITE_SEQUENCER_CONTROL_2:
+	case WM8962_WRITE_SEQUENCER_CONTROL_3:
+	case WM8962_CONTROL_INTERFACE:
+	case WM8962_MIXER_ENABLES:
+	case WM8962_HEADPHONE_MIXER_1:
+	case WM8962_HEADPHONE_MIXER_2:
+	case WM8962_HEADPHONE_MIXER_3:
+	case WM8962_HEADPHONE_MIXER_4:
+	case WM8962_SPEAKER_MIXER_1:
+	case WM8962_SPEAKER_MIXER_2:
+	case WM8962_SPEAKER_MIXER_3:
+	case WM8962_SPEAKER_MIXER_4:
+	case WM8962_SPEAKER_MIXER_5:
+	case WM8962_BEEP_GENERATOR_1:
+	case WM8962_OSCILLATOR_TRIM_3:
+	case WM8962_OSCILLATOR_TRIM_4:
+	case WM8962_OSCILLATOR_TRIM_7:
+	case WM8962_ANALOGUE_CLOCKING1:
+	case WM8962_ANALOGUE_CLOCKING2:
+	case WM8962_ANALOGUE_CLOCKING3:
+	case WM8962_PLL_SOFTWARE_RESET:
+	case WM8962_PLL2:
+	case WM8962_PLL_4:
+	case WM8962_PLL_9:
+	case WM8962_PLL_10:
+	case WM8962_PLL_11:
+	case WM8962_PLL_12:
+	case WM8962_PLL_13:
+	case WM8962_PLL_14:
+	case WM8962_PLL_15:
+	case WM8962_PLL_16:
+	case WM8962_FLL_CONTROL_1:
+	case WM8962_FLL_CONTROL_2:
+	case WM8962_FLL_CONTROL_3:
+	case WM8962_FLL_CONTROL_5:
+	case WM8962_FLL_CONTROL_6:
+	case WM8962_FLL_CONTROL_7:
+	case WM8962_FLL_CONTROL_8:
+	case WM8962_GENERAL_TEST_1:
+	case WM8962_DF1:
+	case WM8962_DF2:
+	case WM8962_DF3:
+	case WM8962_DF4:
+	case WM8962_DF5:
+	case WM8962_DF6:
+	case WM8962_DF7:
+	case WM8962_LHPF1:
+	case WM8962_LHPF2:
+	case WM8962_THREED1:
+	case WM8962_THREED2:
+	case WM8962_THREED3:
+	case WM8962_THREED4:
+	case WM8962_DRC_1:
+	case WM8962_DRC_2:
+	case WM8962_DRC_3:
+	case WM8962_DRC_4:
+	case WM8962_DRC_5:
+	case WM8962_TLOOPBACK:
+	case WM8962_EQ1:
+	case WM8962_EQ2:
+	case WM8962_EQ3:
+	case WM8962_EQ4:
+	case WM8962_EQ5:
+	case WM8962_EQ6:
+	case WM8962_EQ7:
+	case WM8962_EQ8:
+	case WM8962_EQ9:
+	case WM8962_EQ10:
+	case WM8962_EQ11:
+	case WM8962_EQ12:
+	case WM8962_EQ13:
+	case WM8962_EQ14:
+	case WM8962_EQ15:
+	case WM8962_EQ16:
+	case WM8962_EQ17:
+	case WM8962_EQ18:
+	case WM8962_EQ19:
+	case WM8962_EQ20:
+	case WM8962_EQ21:
+	case WM8962_EQ22:
+	case WM8962_EQ23:
+	case WM8962_EQ24:
+	case WM8962_EQ25:
+	case WM8962_EQ26:
+	case WM8962_EQ27:
+	case WM8962_EQ28:
+	case WM8962_EQ29:
+	case WM8962_EQ30:
+	case WM8962_EQ31:
+	case WM8962_EQ32:
+	case WM8962_EQ33:
+	case WM8962_EQ34:
+	case WM8962_EQ35:
+	case WM8962_EQ36:
+	case WM8962_EQ37:
+	case WM8962_EQ38:
+	case WM8962_EQ39:
+	case WM8962_EQ40:
+	case WM8962_EQ41:
+	case WM8962_GPIO_BASE:
+	case WM8962_GPIO_2:
+	case WM8962_GPIO_3:
+	case WM8962_GPIO_5:
+	case WM8962_GPIO_6:
+	case WM8962_INTERRUPT_STATUS_1:
+	case WM8962_INTERRUPT_STATUS_2:
+	case WM8962_INTERRUPT_STATUS_1_MASK:
+	case WM8962_INTERRUPT_STATUS_2_MASK:
+	case WM8962_INTERRUPT_CONTROL:
+	case WM8962_IRQ_DEBOUNCE:
+	case WM8962_MICINT_SOURCE_POL:
+	case WM8962_DSP2_POWER_MANAGEMENT:
+	case WM8962_DSP2_EXECCONTROL:
+	case WM8962_DSP2_INSTRUCTION_RAM_0:
+	case WM8962_DSP2_ADDRESS_RAM_2:
+	case WM8962_DSP2_ADDRESS_RAM_1:
+	case WM8962_DSP2_ADDRESS_RAM_0:
+	case WM8962_DSP2_DATA1_RAM_1:
+	case WM8962_DSP2_DATA1_RAM_0:
+	case WM8962_DSP2_DATA2_RAM_1:
+	case WM8962_DSP2_DATA2_RAM_0:
+	case WM8962_DSP2_DATA3_RAM_1:
+	case WM8962_DSP2_DATA3_RAM_0:
+	case WM8962_DSP2_COEFF_RAM_0:
+	case WM8962_RETUNEADC_SHARED_COEFF_1:
+	case WM8962_RETUNEADC_SHARED_COEFF_0:
+	case WM8962_RETUNEDAC_SHARED_COEFF_1:
+	case WM8962_RETUNEDAC_SHARED_COEFF_0:
+	case WM8962_SOUNDSTAGE_ENABLES_1:
+	case WM8962_SOUNDSTAGE_ENABLES_0:
+	case WM8962_HDBASS_AI_1:
+	case WM8962_HDBASS_AI_0:
+	case WM8962_HDBASS_AR_1:
+	case WM8962_HDBASS_AR_0:
+	case WM8962_HDBASS_B_1:
+	case WM8962_HDBASS_B_0:
+	case WM8962_HDBASS_K_1:
+	case WM8962_HDBASS_K_0:
+	case WM8962_HDBASS_N1_1:
+	case WM8962_HDBASS_N1_0:
+	case WM8962_HDBASS_N2_1:
+	case WM8962_HDBASS_N2_0:
+	case WM8962_HDBASS_N3_1:
+	case WM8962_HDBASS_N3_0:
+	case WM8962_HDBASS_N4_1:
+	case WM8962_HDBASS_N4_0:
+	case WM8962_HDBASS_N5_1:
+	case WM8962_HDBASS_N5_0:
+	case WM8962_HDBASS_X1_1:
+	case WM8962_HDBASS_X1_0:
+	case WM8962_HDBASS_X2_1:
+	case WM8962_HDBASS_X2_0:
+	case WM8962_HDBASS_X3_1:
+	case WM8962_HDBASS_X3_0:
+	case WM8962_HDBASS_ATK_1:
+	case WM8962_HDBASS_ATK_0:
+	case WM8962_HDBASS_DCY_1:
+	case WM8962_HDBASS_DCY_0:
+	case WM8962_HDBASS_PG_1:
+	case WM8962_HDBASS_PG_0:
+	case WM8962_HPF_C_1:
+	case WM8962_HPF_C_0:
+	case WM8962_ADCL_RETUNE_C1_1:
+	case WM8962_ADCL_RETUNE_C1_0:
+	case WM8962_ADCL_RETUNE_C2_1:
+	case WM8962_ADCL_RETUNE_C2_0:
+	case WM8962_ADCL_RETUNE_C3_1:
+	case WM8962_ADCL_RETUNE_C3_0:
+	case WM8962_ADCL_RETUNE_C4_1:
+	case WM8962_ADCL_RETUNE_C4_0:
+	case WM8962_ADCL_RETUNE_C5_1:
+	case WM8962_ADCL_RETUNE_C5_0:
+	case WM8962_ADCL_RETUNE_C6_1:
+	case WM8962_ADCL_RETUNE_C6_0:
+	case WM8962_ADCL_RETUNE_C7_1:
+	case WM8962_ADCL_RETUNE_C7_0:
+	case WM8962_ADCL_RETUNE_C8_1:
+	case WM8962_ADCL_RETUNE_C8_0:
+	case WM8962_ADCL_RETUNE_C9_1:
+	case WM8962_ADCL_RETUNE_C9_0:
+	case WM8962_ADCL_RETUNE_C10_1:
+	case WM8962_ADCL_RETUNE_C10_0:
+	case WM8962_ADCL_RETUNE_C11_1:
+	case WM8962_ADCL_RETUNE_C11_0:
+	case WM8962_ADCL_RETUNE_C12_1:
+	case WM8962_ADCL_RETUNE_C12_0:
+	case WM8962_ADCL_RETUNE_C13_1:
+	case WM8962_ADCL_RETUNE_C13_0:
+	case WM8962_ADCL_RETUNE_C14_1:
+	case WM8962_ADCL_RETUNE_C14_0:
+	case WM8962_ADCL_RETUNE_C15_1:
+	case WM8962_ADCL_RETUNE_C15_0:
+	case WM8962_ADCL_RETUNE_C16_1:
+	case WM8962_ADCL_RETUNE_C16_0:
+	case WM8962_ADCL_RETUNE_C17_1:
+	case WM8962_ADCL_RETUNE_C17_0:
+	case WM8962_ADCL_RETUNE_C18_1:
+	case WM8962_ADCL_RETUNE_C18_0:
+	case WM8962_ADCL_RETUNE_C19_1:
+	case WM8962_ADCL_RETUNE_C19_0:
+	case WM8962_ADCL_RETUNE_C20_1:
+	case WM8962_ADCL_RETUNE_C20_0:
+	case WM8962_ADCL_RETUNE_C21_1:
+	case WM8962_ADCL_RETUNE_C21_0:
+	case WM8962_ADCL_RETUNE_C22_1:
+	case WM8962_ADCL_RETUNE_C22_0:
+	case WM8962_ADCL_RETUNE_C23_1:
+	case WM8962_ADCL_RETUNE_C23_0:
+	case WM8962_ADCL_RETUNE_C24_1:
+	case WM8962_ADCL_RETUNE_C24_0:
+	case WM8962_ADCL_RETUNE_C25_1:
+	case WM8962_ADCL_RETUNE_C25_0:
+	case WM8962_ADCL_RETUNE_C26_1:
+	case WM8962_ADCL_RETUNE_C26_0:
+	case WM8962_ADCL_RETUNE_C27_1:
+	case WM8962_ADCL_RETUNE_C27_0:
+	case WM8962_ADCL_RETUNE_C28_1:
+	case WM8962_ADCL_RETUNE_C28_0:
+	case WM8962_ADCL_RETUNE_C29_1:
+	case WM8962_ADCL_RETUNE_C29_0:
+	case WM8962_ADCL_RETUNE_C30_1:
+	case WM8962_ADCL_RETUNE_C30_0:
+	case WM8962_ADCL_RETUNE_C31_1:
+	case WM8962_ADCL_RETUNE_C31_0:
+	case WM8962_ADCL_RETUNE_C32_1:
+	case WM8962_ADCL_RETUNE_C32_0:
+	case WM8962_RETUNEADC_PG2_1:
+	case WM8962_RETUNEADC_PG2_0:
+	case WM8962_RETUNEADC_PG_1:
+	case WM8962_RETUNEADC_PG_0:
+	case WM8962_ADCR_RETUNE_C1_1:
+	case WM8962_ADCR_RETUNE_C1_0:
+	case WM8962_ADCR_RETUNE_C2_1:
+	case WM8962_ADCR_RETUNE_C2_0:
+	case WM8962_ADCR_RETUNE_C3_1:
+	case WM8962_ADCR_RETUNE_C3_0:
+	case WM8962_ADCR_RETUNE_C4_1:
+	case WM8962_ADCR_RETUNE_C4_0:
+	case WM8962_ADCR_RETUNE_C5_1:
+	case WM8962_ADCR_RETUNE_C5_0:
+	case WM8962_ADCR_RETUNE_C6_1:
+	case WM8962_ADCR_RETUNE_C6_0:
+	case WM8962_ADCR_RETUNE_C7_1:
+	case WM8962_ADCR_RETUNE_C7_0:
+	case WM8962_ADCR_RETUNE_C8_1:
+	case WM8962_ADCR_RETUNE_C8_0:
+	case WM8962_ADCR_RETUNE_C9_1:
+	case WM8962_ADCR_RETUNE_C9_0:
+	case WM8962_ADCR_RETUNE_C10_1:
+	case WM8962_ADCR_RETUNE_C10_0:
+	case WM8962_ADCR_RETUNE_C11_1:
+	case WM8962_ADCR_RETUNE_C11_0:
+	case WM8962_ADCR_RETUNE_C12_1:
+	case WM8962_ADCR_RETUNE_C12_0:
+	case WM8962_ADCR_RETUNE_C13_1:
+	case WM8962_ADCR_RETUNE_C13_0:
+	case WM8962_ADCR_RETUNE_C14_1:
+	case WM8962_ADCR_RETUNE_C14_0:
+	case WM8962_ADCR_RETUNE_C15_1:
+	case WM8962_ADCR_RETUNE_C15_0:
+	case WM8962_ADCR_RETUNE_C16_1:
+	case WM8962_ADCR_RETUNE_C16_0:
+	case WM8962_ADCR_RETUNE_C17_1:
+	case WM8962_ADCR_RETUNE_C17_0:
+	case WM8962_ADCR_RETUNE_C18_1:
+	case WM8962_ADCR_RETUNE_C18_0:
+	case WM8962_ADCR_RETUNE_C19_1:
+	case WM8962_ADCR_RETUNE_C19_0:
+	case WM8962_ADCR_RETUNE_C20_1:
+	case WM8962_ADCR_RETUNE_C20_0:
+	case WM8962_ADCR_RETUNE_C21_1:
+	case WM8962_ADCR_RETUNE_C21_0:
+	case WM8962_ADCR_RETUNE_C22_1:
+	case WM8962_ADCR_RETUNE_C22_0:
+	case WM8962_ADCR_RETUNE_C23_1:
+	case WM8962_ADCR_RETUNE_C23_0:
+	case WM8962_ADCR_RETUNE_C24_1:
+	case WM8962_ADCR_RETUNE_C24_0:
+	case WM8962_ADCR_RETUNE_C25_1:
+	case WM8962_ADCR_RETUNE_C25_0:
+	case WM8962_ADCR_RETUNE_C26_1:
+	case WM8962_ADCR_RETUNE_C26_0:
+	case WM8962_ADCR_RETUNE_C27_1:
+	case WM8962_ADCR_RETUNE_C27_0:
+	case WM8962_ADCR_RETUNE_C28_1:
+	case WM8962_ADCR_RETUNE_C28_0:
+	case WM8962_ADCR_RETUNE_C29_1:
+	case WM8962_ADCR_RETUNE_C29_0:
+	case WM8962_ADCR_RETUNE_C30_1:
+	case WM8962_ADCR_RETUNE_C30_0:
+	case WM8962_ADCR_RETUNE_C31_1:
+	case WM8962_ADCR_RETUNE_C31_0:
+	case WM8962_ADCR_RETUNE_C32_1:
+	case WM8962_ADCR_RETUNE_C32_0:
+	case WM8962_DACL_RETUNE_C1_1:
+	case WM8962_DACL_RETUNE_C1_0:
+	case WM8962_DACL_RETUNE_C2_1:
+	case WM8962_DACL_RETUNE_C2_0:
+	case WM8962_DACL_RETUNE_C3_1:
+	case WM8962_DACL_RETUNE_C3_0:
+	case WM8962_DACL_RETUNE_C4_1:
+	case WM8962_DACL_RETUNE_C4_0:
+	case WM8962_DACL_RETUNE_C5_1:
+	case WM8962_DACL_RETUNE_C5_0:
+	case WM8962_DACL_RETUNE_C6_1:
+	case WM8962_DACL_RETUNE_C6_0:
+	case WM8962_DACL_RETUNE_C7_1:
+	case WM8962_DACL_RETUNE_C7_0:
+	case WM8962_DACL_RETUNE_C8_1:
+	case WM8962_DACL_RETUNE_C8_0:
+	case WM8962_DACL_RETUNE_C9_1:
+	case WM8962_DACL_RETUNE_C9_0:
+	case WM8962_DACL_RETUNE_C10_1:
+	case WM8962_DACL_RETUNE_C10_0:
+	case WM8962_DACL_RETUNE_C11_1:
+	case WM8962_DACL_RETUNE_C11_0:
+	case WM8962_DACL_RETUNE_C12_1:
+	case WM8962_DACL_RETUNE_C12_0:
+	case WM8962_DACL_RETUNE_C13_1:
+	case WM8962_DACL_RETUNE_C13_0:
+	case WM8962_DACL_RETUNE_C14_1:
+	case WM8962_DACL_RETUNE_C14_0:
+	case WM8962_DACL_RETUNE_C15_1:
+	case WM8962_DACL_RETUNE_C15_0:
+	case WM8962_DACL_RETUNE_C16_1:
+	case WM8962_DACL_RETUNE_C16_0:
+	case WM8962_DACL_RETUNE_C17_1:
+	case WM8962_DACL_RETUNE_C17_0:
+	case WM8962_DACL_RETUNE_C18_1:
+	case WM8962_DACL_RETUNE_C18_0:
+	case WM8962_DACL_RETUNE_C19_1:
+	case WM8962_DACL_RETUNE_C19_0:
+	case WM8962_DACL_RETUNE_C20_1:
+	case WM8962_DACL_RETUNE_C20_0:
+	case WM8962_DACL_RETUNE_C21_1:
+	case WM8962_DACL_RETUNE_C21_0:
+	case WM8962_DACL_RETUNE_C22_1:
+	case WM8962_DACL_RETUNE_C22_0:
+	case WM8962_DACL_RETUNE_C23_1:
+	case WM8962_DACL_RETUNE_C23_0:
+	case WM8962_DACL_RETUNE_C24_1:
+	case WM8962_DACL_RETUNE_C24_0:
+	case WM8962_DACL_RETUNE_C25_1:
+	case WM8962_DACL_RETUNE_C25_0:
+	case WM8962_DACL_RETUNE_C26_1:
+	case WM8962_DACL_RETUNE_C26_0:
+	case WM8962_DACL_RETUNE_C27_1:
+	case WM8962_DACL_RETUNE_C27_0:
+	case WM8962_DACL_RETUNE_C28_1:
+	case WM8962_DACL_RETUNE_C28_0:
+	case WM8962_DACL_RETUNE_C29_1:
+	case WM8962_DACL_RETUNE_C29_0:
+	case WM8962_DACL_RETUNE_C30_1:
+	case WM8962_DACL_RETUNE_C30_0:
+	case WM8962_DACL_RETUNE_C31_1:
+	case WM8962_DACL_RETUNE_C31_0:
+	case WM8962_DACL_RETUNE_C32_1:
+	case WM8962_DACL_RETUNE_C32_0:
+	case WM8962_RETUNEDAC_PG2_1:
+	case WM8962_RETUNEDAC_PG2_0:
+	case WM8962_RETUNEDAC_PG_1:
+	case WM8962_RETUNEDAC_PG_0:
+	case WM8962_DACR_RETUNE_C1_1:
+	case WM8962_DACR_RETUNE_C1_0:
+	case WM8962_DACR_RETUNE_C2_1:
+	case WM8962_DACR_RETUNE_C2_0:
+	case WM8962_DACR_RETUNE_C3_1:
+	case WM8962_DACR_RETUNE_C3_0:
+	case WM8962_DACR_RETUNE_C4_1:
+	case WM8962_DACR_RETUNE_C4_0:
+	case WM8962_DACR_RETUNE_C5_1:
+	case WM8962_DACR_RETUNE_C5_0:
+	case WM8962_DACR_RETUNE_C6_1:
+	case WM8962_DACR_RETUNE_C6_0:
+	case WM8962_DACR_RETUNE_C7_1:
+	case WM8962_DACR_RETUNE_C7_0:
+	case WM8962_DACR_RETUNE_C8_1:
+	case WM8962_DACR_RETUNE_C8_0:
+	case WM8962_DACR_RETUNE_C9_1:
+	case WM8962_DACR_RETUNE_C9_0:
+	case WM8962_DACR_RETUNE_C10_1:
+	case WM8962_DACR_RETUNE_C10_0:
+	case WM8962_DACR_RETUNE_C11_1:
+	case WM8962_DACR_RETUNE_C11_0:
+	case WM8962_DACR_RETUNE_C12_1:
+	case WM8962_DACR_RETUNE_C12_0:
+	case WM8962_DACR_RETUNE_C13_1:
+	case WM8962_DACR_RETUNE_C13_0:
+	case WM8962_DACR_RETUNE_C14_1:
+	case WM8962_DACR_RETUNE_C14_0:
+	case WM8962_DACR_RETUNE_C15_1:
+	case WM8962_DACR_RETUNE_C15_0:
+	case WM8962_DACR_RETUNE_C16_1:
+	case WM8962_DACR_RETUNE_C16_0:
+	case WM8962_DACR_RETUNE_C17_1:
+	case WM8962_DACR_RETUNE_C17_0:
+	case WM8962_DACR_RETUNE_C18_1:
+	case WM8962_DACR_RETUNE_C18_0:
+	case WM8962_DACR_RETUNE_C19_1:
+	case WM8962_DACR_RETUNE_C19_0:
+	case WM8962_DACR_RETUNE_C20_1:
+	case WM8962_DACR_RETUNE_C20_0:
+	case WM8962_DACR_RETUNE_C21_1:
+	case WM8962_DACR_RETUNE_C21_0:
+	case WM8962_DACR_RETUNE_C22_1:
+	case WM8962_DACR_RETUNE_C22_0:
+	case WM8962_DACR_RETUNE_C23_1:
+	case WM8962_DACR_RETUNE_C23_0:
+	case WM8962_DACR_RETUNE_C24_1:
+	case WM8962_DACR_RETUNE_C24_0:
+	case WM8962_DACR_RETUNE_C25_1:
+	case WM8962_DACR_RETUNE_C25_0:
+	case WM8962_DACR_RETUNE_C26_1:
+	case WM8962_DACR_RETUNE_C26_0:
+	case WM8962_DACR_RETUNE_C27_1:
+	case WM8962_DACR_RETUNE_C27_0:
+	case WM8962_DACR_RETUNE_C28_1:
+	case WM8962_DACR_RETUNE_C28_0:
+	case WM8962_DACR_RETUNE_C29_1:
+	case WM8962_DACR_RETUNE_C29_0:
+	case WM8962_DACR_RETUNE_C30_1:
+	case WM8962_DACR_RETUNE_C30_0:
+	case WM8962_DACR_RETUNE_C31_1:
+	case WM8962_DACR_RETUNE_C31_0:
+	case WM8962_DACR_RETUNE_C32_1:
+	case WM8962_DACR_RETUNE_C32_0:
+	case WM8962_VSS_XHD2_1:
+	case WM8962_VSS_XHD2_0:
+	case WM8962_VSS_XHD3_1:
+	case WM8962_VSS_XHD3_0:
+	case WM8962_VSS_XHN1_1:
+	case WM8962_VSS_XHN1_0:
+	case WM8962_VSS_XHN2_1:
+	case WM8962_VSS_XHN2_0:
+	case WM8962_VSS_XHN3_1:
+	case WM8962_VSS_XHN3_0:
+	case WM8962_VSS_XLA_1:
+	case WM8962_VSS_XLA_0:
+	case WM8962_VSS_XLB_1:
+	case WM8962_VSS_XLB_0:
+	case WM8962_VSS_XLG_1:
+	case WM8962_VSS_XLG_0:
+	case WM8962_VSS_PG2_1:
+	case WM8962_VSS_PG2_0:
+	case WM8962_VSS_PG_1:
+	case WM8962_VSS_PG_0:
+	case WM8962_VSS_XTD1_1:
+	case WM8962_VSS_XTD1_0:
+	case WM8962_VSS_XTD2_1:
+	case WM8962_VSS_XTD2_0:
+	case WM8962_VSS_XTD3_1:
+	case WM8962_VSS_XTD3_0:
+	case WM8962_VSS_XTD4_1:
+	case WM8962_VSS_XTD4_0:
+	case WM8962_VSS_XTD5_1:
+	case WM8962_VSS_XTD5_0:
+	case WM8962_VSS_XTD6_1:
+	case WM8962_VSS_XTD6_0:
+	case WM8962_VSS_XTD7_1:
+	case WM8962_VSS_XTD7_0:
+	case WM8962_VSS_XTD8_1:
+	case WM8962_VSS_XTD8_0:
+	case WM8962_VSS_XTD9_1:
+	case WM8962_VSS_XTD9_0:
+	case WM8962_VSS_XTD10_1:
+	case WM8962_VSS_XTD10_0:
+	case WM8962_VSS_XTD11_1:
+	case WM8962_VSS_XTD11_0:
+	case WM8962_VSS_XTD12_1:
+	case WM8962_VSS_XTD12_0:
+	case WM8962_VSS_XTD13_1:
+	case WM8962_VSS_XTD13_0:
+	case WM8962_VSS_XTD14_1:
+	case WM8962_VSS_XTD14_0:
+	case WM8962_VSS_XTD15_1:
+	case WM8962_VSS_XTD15_0:
+	case WM8962_VSS_XTD16_1:
+	case WM8962_VSS_XTD16_0:
+	case WM8962_VSS_XTD17_1:
+	case WM8962_VSS_XTD17_0:
+	case WM8962_VSS_XTD18_1:
+	case WM8962_VSS_XTD18_0:
+	case WM8962_VSS_XTD19_1:
+	case WM8962_VSS_XTD19_0:
+	case WM8962_VSS_XTD20_1:
+	case WM8962_VSS_XTD20_0:
+	case WM8962_VSS_XTD21_1:
+	case WM8962_VSS_XTD21_0:
+	case WM8962_VSS_XTD22_1:
+	case WM8962_VSS_XTD22_0:
+	case WM8962_VSS_XTD23_1:
+	case WM8962_VSS_XTD23_0:
+	case WM8962_VSS_XTD24_1:
+	case WM8962_VSS_XTD24_0:
+	case WM8962_VSS_XTD25_1:
+	case WM8962_VSS_XTD25_0:
+	case WM8962_VSS_XTD26_1:
+	case WM8962_VSS_XTD26_0:
+	case WM8962_VSS_XTD27_1:
+	case WM8962_VSS_XTD27_0:
+	case WM8962_VSS_XTD28_1:
+	case WM8962_VSS_XTD28_0:
+	case WM8962_VSS_XTD29_1:
+	case WM8962_VSS_XTD29_0:
+	case WM8962_VSS_XTD30_1:
+	case WM8962_VSS_XTD30_0:
+	case WM8962_VSS_XTD31_1:
+	case WM8962_VSS_XTD31_0:
+	case WM8962_VSS_XTD32_1:
+	case WM8962_VSS_XTD32_0:
+	case WM8962_VSS_XTS1_1:
+	case WM8962_VSS_XTS1_0:
+	case WM8962_VSS_XTS2_1:
+	case WM8962_VSS_XTS2_0:
+	case WM8962_VSS_XTS3_1:
+	case WM8962_VSS_XTS3_0:
+	case WM8962_VSS_XTS4_1:
+	case WM8962_VSS_XTS4_0:
+	case WM8962_VSS_XTS5_1:
+	case WM8962_VSS_XTS5_0:
+	case WM8962_VSS_XTS6_1:
+	case WM8962_VSS_XTS6_0:
+	case WM8962_VSS_XTS7_1:
+	case WM8962_VSS_XTS7_0:
+	case WM8962_VSS_XTS8_1:
+	case WM8962_VSS_XTS8_0:
+	case WM8962_VSS_XTS9_1:
+	case WM8962_VSS_XTS9_0:
+	case WM8962_VSS_XTS10_1:
+	case WM8962_VSS_XTS10_0:
+	case WM8962_VSS_XTS11_1:
+	case WM8962_VSS_XTS11_0:
+	case WM8962_VSS_XTS12_1:
+	case WM8962_VSS_XTS12_0:
+	case WM8962_VSS_XTS13_1:
+	case WM8962_VSS_XTS13_0:
+	case WM8962_VSS_XTS14_1:
+	case WM8962_VSS_XTS14_0:
+	case WM8962_VSS_XTS15_1:
+	case WM8962_VSS_XTS15_0:
+	case WM8962_VSS_XTS16_1:
+	case WM8962_VSS_XTS16_0:
+	case WM8962_VSS_XTS17_1:
+	case WM8962_VSS_XTS17_0:
+	case WM8962_VSS_XTS18_1:
+	case WM8962_VSS_XTS18_0:
+	case WM8962_VSS_XTS19_1:
+	case WM8962_VSS_XTS19_0:
+	case WM8962_VSS_XTS20_1:
+	case WM8962_VSS_XTS20_0:
+	case WM8962_VSS_XTS21_1:
+	case WM8962_VSS_XTS21_0:
+	case WM8962_VSS_XTS22_1:
+	case WM8962_VSS_XTS22_0:
+	case WM8962_VSS_XTS23_1:
+	case WM8962_VSS_XTS23_0:
+	case WM8962_VSS_XTS24_1:
+	case WM8962_VSS_XTS24_0:
+	case WM8962_VSS_XTS25_1:
+	case WM8962_VSS_XTS25_0:
+	case WM8962_VSS_XTS26_1:
+	case WM8962_VSS_XTS26_0:
+	case WM8962_VSS_XTS27_1:
+	case WM8962_VSS_XTS27_0:
+	case WM8962_VSS_XTS28_1:
+	case WM8962_VSS_XTS28_0:
+	case WM8962_VSS_XTS29_1:
+	case WM8962_VSS_XTS29_0:
+	case WM8962_VSS_XTS30_1:
+	case WM8962_VSS_XTS30_0:
+	case WM8962_VSS_XTS31_1:
+	case WM8962_VSS_XTS31_0:
+	case WM8962_VSS_XTS32_1:
+	case WM8962_VSS_XTS32_0:
+		return true;
+	default:
+		return false;
+	}
 }
 
 static int wm8962_reset(struct wm8962_priv *wm8962)
@@ -2221,6 +1702,8 @@
 SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8962_LEFT_DAC_VOLUME,
 		 WM8962_RIGHT_DAC_VOLUME, 1, 127, 0, digital_tlv),
 SOC_SINGLE("DAC High Performance Switch", WM8962_ADC_DAC_CONTROL_2, 0, 1, 0),
+SOC_SINGLE("DAC L/R Swap Switch", WM8962_AUDIO_INTERFACE_0, 5, 1, 0),
+SOC_SINGLE("ADC L/R Swap Switch", WM8962_AUDIO_INTERFACE_0, 8, 1, 0),
 
 SOC_SINGLE("ADC High Performance Switch", WM8962_ADDITIONAL_CONTROL_1,
 	   5, 1, 0),
@@ -2337,65 +1820,6 @@
 	       4, 1, 0, inmix_tlv),
 };
 
-static int sysclk_event(struct snd_soc_dapm_widget *w,
-			struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
-	unsigned long timeout;
-	int src;
-	int fll;
-
-	/* Ignore attempts to run the event during startup */
-	if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
-		return 0;
-
-	src = snd_soc_read(codec, WM8962_CLOCKING2) & WM8962_SYSCLK_SRC_MASK;
-
-	switch (src) {
-	case 0:      /* MCLK */
-		fll = 0;
-		break;
-	case 0x200:  /* FLL */
-		fll = 1;
-		break;
-	default:
-		dev_err(codec->dev, "Unknown SYSCLK source %x\n", src);
-		return -EINVAL;
-	}
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		if (fll) {
-			try_wait_for_completion(&wm8962->fll_lock);
-
-			snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
-					    WM8962_FLL_ENA, WM8962_FLL_ENA);
-
-			timeout = msecs_to_jiffies(5);
-			timeout = wait_for_completion_timeout(&wm8962->fll_lock,
-							      timeout);
-
-			if (wm8962->irq && timeout == 0)
-				dev_err(codec->dev,
-					"Timed out starting FLL\n");
-		}
-		break;
-
-	case SND_SOC_DAPM_POST_PMD:
-		if (fll)
-			snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
-					    WM8962_FLL_ENA, 0);
-		break;
-
-	default:
-		BUG();
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 static int cp_event(struct snd_soc_dapm_widget *w,
 		    struct snd_kcontrol *kcontrol, int event)
 {
@@ -2681,8 +2105,7 @@
 SND_SOC_DAPM_SUPPLY("MICBIAS", WM8962_PWR_MGMT_1, 1, 0, NULL, 0),
 
 SND_SOC_DAPM_SUPPLY("Class G", WM8962_CHARGE_PUMP_B, 0, 1, NULL, 0),
-SND_SOC_DAPM_SUPPLY("SYSCLK", WM8962_CLOCKING2, 5, 0, sysclk_event,
-		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM8962_CLOCKING2, 5, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("Charge Pump", WM8962_CHARGE_PUMP_1, 0, 0, cp_event,
 		    SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0),
@@ -2796,9 +2219,11 @@
 
 	{ "STL", "Left", "ADCL" },
 	{ "STL", "Right", "ADCR" },
+	{ "STL", NULL, "Class G" },
 
 	{ "STR", "Left", "ADCL" },
 	{ "STR", "Right", "ADCR" },
+	{ "STR", NULL, "Class G" },
 
 	{ "DACL", NULL, "SYSCLK" },
 	{ "DACL", NULL, "TOCLK" },
@@ -2910,13 +2335,13 @@
 	struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-	snd_soc_add_controls(codec, wm8962_snd_controls,
+	snd_soc_add_codec_controls(codec, wm8962_snd_controls,
 			     ARRAY_SIZE(wm8962_snd_controls));
 	if (pdata && pdata->spk_mono)
-		snd_soc_add_controls(codec, wm8962_spk_mono_controls,
+		snd_soc_add_codec_controls(codec, wm8962_spk_mono_controls,
 				     ARRAY_SIZE(wm8962_spk_mono_controls));
 	else
-		snd_soc_add_controls(codec, wm8962_spk_stereo_controls,
+		snd_soc_add_codec_controls(codec, wm8962_spk_stereo_controls,
 				     ARRAY_SIZE(wm8962_spk_stereo_controls));
 
 
@@ -2950,7 +2375,7 @@
 };
 
 static const int sysclk_rates[] = {
-	64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536,
+	64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536, 3072, 6144
 };
 
 static void wm8962_configure_bclk(struct snd_soc_codec *codec)
@@ -2984,6 +2409,8 @@
 		return;
 	}
 
+	dev_dbg(codec->dev, "Selected sysclk ratio %d\n", sysclk_rates[i]);
+
 	snd_soc_update_bits(codec, WM8962_CLOCKING_4,
 			    WM8962_SYSCLK_RATE_MASK, clocking4);
 
@@ -3042,9 +2469,6 @@
 static int wm8962_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
-	int ret;
-
 	if (level == codec->dapm.bias_level)
 		return 0;
 
@@ -3061,51 +2485,15 @@
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-			ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
-						    wm8962->supplies);
-			if (ret != 0) {
-				dev_err(codec->dev,
-					"Failed to enable supplies: %d\n",
-					ret);
-				return ret;
-			}
-
-			regcache_cache_only(wm8962->regmap, false);
-			regcache_sync(wm8962->regmap);
-
-			snd_soc_update_bits(codec, WM8962_ANTI_POP,
-					    WM8962_STARTUP_BIAS_ENA |
-					    WM8962_VMID_BUF_ENA,
-					    WM8962_STARTUP_BIAS_ENA |
-					    WM8962_VMID_BUF_ENA);
-
-			/* Bias enable at 2*50k for ramp */
-			snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
-					    WM8962_VMID_SEL_MASK |
-					    WM8962_BIAS_ENA,
-					    WM8962_BIAS_ENA | 0x180);
-
-			msleep(5);
-		}
-
 		/* VMID 2*250k */
 		snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
 				    WM8962_VMID_SEL_MASK, 0x100);
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
-				    WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA, 0);
-
-		snd_soc_update_bits(codec, WM8962_ANTI_POP,
-				    WM8962_STARTUP_BIAS_ENA |
-				    WM8962_VMID_BUF_ENA, 0);
-
-		regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies),
-				       wm8962->supplies);
 		break;
 	}
+
 	codec->dapm.bias_level = level;
 	return 0;
 }
@@ -3139,6 +2527,9 @@
 	int adctl3 = 0;
 
 	wm8962->bclk = snd_soc_params_to_bclk(params);
+	if (params_channels(params) == 1)
+		wm8962->bclk *= 2;
+
 	wm8962->lrclk = params_rate(params);
 
 	for (i = 0; i < ARRAY_SIZE(sr_vals); i++) {
@@ -3177,7 +2568,8 @@
 			    WM8962_SAMPLE_RATE_INT_MODE |
 			    WM8962_SAMPLE_RATE_MASK, adctl3);
 
-	wm8962_configure_bclk(codec);
+	if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
+		wm8962_configure_bclk(codec);
 
 	return 0;
 }
@@ -3207,6 +2599,8 @@
 
 	wm8962->sysclk_rate = freq;
 
+	wm8962_configure_bclk(codec);
+
 	return 0;
 }
 
@@ -3385,8 +2779,7 @@
 	struct _fll_div fll_div;
 	unsigned long timeout;
 	int ret;
-	int fll1 = snd_soc_read(codec, WM8962_FLL_CONTROL_1) & WM8962_FLL_ENA;
-	int sysclk = snd_soc_read(codec, WM8962_CLOCKING2) & WM8962_SYSCLK_ENA;
+	int fll1 = 0;
 
 	/* Any change? */
 	if (source == wm8962->fll_src && Fref == wm8962->fll_fref &&
@@ -3402,6 +2795,8 @@
 		snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
 				    WM8962_FLL_ENA, 0);
 
+		pm_runtime_put(codec->dev);
+
 		return 0;
 	}
 
@@ -3409,6 +2804,9 @@
 	if (ret != 0)
 		return ret;
 
+	/* Parameters good, disable so we can reprogram */
+	snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0);
+
 	switch (fll_id) {
 	case WM8962_FLL_MCLK:
 	case WM8962_FLL_BCLK:
@@ -3447,12 +2845,11 @@
 
 	try_wait_for_completion(&wm8962->fll_lock);
 
-	if (sysclk)
-		fll1 |= WM8962_FLL_ENA;
+	pm_runtime_get_sync(codec->dev);
 
 	snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
 			    WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK |
-			    WM8962_FLL_ENA, fll1);
+			    WM8962_FLL_ENA, fll1 | WM8962_FLL_ENA);
 
 	dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
 
@@ -3513,14 +2910,14 @@
 	.name = "wm8962",
 	.playback = {
 		.stream_name = "Playback",
-		.channels_min = 2,
+		.channels_min = 1,
 		.channels_max = 2,
 		.rates = WM8962_RATES,
 		.formats = WM8962_FORMATS,
 	},
 	.capture = {
 		.stream_name = "Capture",
-		.channels_min = 2,
+		.channels_min = 1,
 		.channels_max = 2,
 		.rates = WM8962_RATES,
 		.formats = WM8962_FORMATS,
@@ -3561,54 +2958,73 @@
 
 static irqreturn_t wm8962_irq(int irq, void *data)
 {
-	struct snd_soc_codec *codec = data;
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
-	int mask;
-	int active;
-	int reg;
+	struct device *dev = data;
+	struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
+	unsigned int mask;
+	unsigned int active;
+	int reg, ret;
 
-	mask = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2_MASK);
+	ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2_MASK,
+			  &mask);
+	if (ret != 0) {
+		dev_err(dev, "Failed to read interrupt mask: %d\n",
+			ret);
+		return IRQ_NONE;
+	}
 
-	active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
+	ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, &active);
+	if (ret != 0) {
+		dev_err(dev, "Failed to read interrupt: %d\n", ret);
+		return IRQ_NONE;
+	}
+
 	active &= ~mask;
 
 	if (!active)
 		return IRQ_NONE;
 
 	/* Acknowledge the interrupts */
-	snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active);
+	ret = regmap_write(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, active);
+	if (ret != 0)
+		dev_warn(dev, "Failed to ack interrupt: %d\n", ret);
 
 	if (active & WM8962_FLL_LOCK_EINT) {
-		dev_dbg(codec->dev, "FLL locked\n");
+		dev_dbg(dev, "FLL locked\n");
 		complete(&wm8962->fll_lock);
 	}
 
 	if (active & WM8962_FIFOS_ERR_EINT)
-		dev_err(codec->dev, "FIFO error\n");
+		dev_err(dev, "FIFO error\n");
 
 	if (active & WM8962_TEMP_SHUT_EINT) {
-		dev_crit(codec->dev, "Thermal shutdown\n");
+		dev_crit(dev, "Thermal shutdown\n");
 
-		reg = snd_soc_read(codec, WM8962_THERMAL_SHUTDOWN_STATUS);
+		ret = regmap_read(wm8962->regmap,
+				  WM8962_THERMAL_SHUTDOWN_STATUS,  &reg);
+		if (ret != 0) {
+			dev_warn(dev, "Failed to read thermal status: %d\n",
+				 ret);
+			reg = 0;
+		}
 
 		if (reg & WM8962_TEMP_ERR_HP)
-			dev_crit(codec->dev, "Headphone thermal error\n");
+			dev_crit(dev, "Headphone thermal error\n");
 		if (reg & WM8962_TEMP_WARN_HP)
-			dev_crit(codec->dev, "Headphone thermal warning\n");
+			dev_crit(dev, "Headphone thermal warning\n");
 		if (reg & WM8962_TEMP_ERR_SPK)
-			dev_crit(codec->dev, "Speaker thermal error\n");
+			dev_crit(dev, "Speaker thermal error\n");
 		if (reg & WM8962_TEMP_WARN_SPK)
-			dev_crit(codec->dev, "Speaker thermal warning\n");
+			dev_crit(dev, "Speaker thermal warning\n");
 	}
 
 	if (active & (WM8962_MICSCD_EINT | WM8962_MICD_EINT)) {
-		dev_dbg(codec->dev, "Microphone event detected\n");
+		dev_dbg(dev, "Microphone event detected\n");
 
 #ifndef CONFIG_SND_SOC_WM8962_MODULE
-		trace_snd_soc_jack_irq(dev_name(codec->dev));
+		trace_snd_soc_jack_irq(dev_name(dev));
 #endif
 
-		pm_wakeup_event(codec->dev, 300);
+		pm_wakeup_event(dev, 300);
 
 		schedule_delayed_work(&wm8962->mic_work,
 				      msecs_to_jiffies(250));
@@ -4089,7 +3505,7 @@
 
 		ret = request_threaded_irq(wm8962->irq, NULL, wm8962_irq,
 					   trigger | IRQF_ONESHOT,
-					   "wm8962", codec);
+					   "wm8962", codec->dev);
 		if (ret != 0) {
 			dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
 				wm8962->irq, ret);
@@ -4127,20 +3543,19 @@
 	return 0;
 }
 
-static int wm8962_soc_volatile(struct snd_soc_codec *codec,
-			       unsigned int reg)
-{
-	return true;
-}
-
-
 static struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
 	.probe =	wm8962_probe,
 	.remove =	wm8962_remove,
 	.set_bias_level = wm8962_set_bias_level,
 	.set_pll = wm8962_set_fll,
-	.reg_cache_size	= WM8962_MAX_REGISTER,
-	.volatile_register = wm8962_soc_volatile,
+	.idle_bias_off = true,
+};
+
+/* Improve power consumption for IN4 DC measurement mode */
+static const struct reg_default wm8962_dc_measure[] = {
+	{ 0xfd, 0x1 },
+	{ 0xcc, 0x40 },
+	{ 0xfd, 0 },
 };
 
 static const struct regmap_config wm8962_regmap = {
@@ -4155,10 +3570,10 @@
 	.cache_type = REGCACHE_RBTREE,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8962_i2c_probe(struct i2c_client *i2c,
 				      const struct i2c_device_id *id)
 {
+	struct wm8962_pdata *pdata = dev_get_platdata(&i2c->dev);
 	struct wm8962_priv *wm8962;
 	unsigned int reg;
 	int ret, i;
@@ -4212,7 +3627,7 @@
 	}
 	if (reg != 0x6243) {
 		dev_err(&i2c->dev,
-			"Device is not a WM8962, ID %x != 0x6243\n", ret);
+			"Device is not a WM8962, ID %x != 0x6243\n", reg);
 		ret = -EINVAL;
 		goto err_regmap;
 	}
@@ -4237,7 +3652,18 @@
 		goto err_regmap;
 	}
 
-	regcache_cache_only(wm8962->regmap, true);
+	if (pdata && pdata->in4_dc_measure) {
+		ret = regmap_register_patch(wm8962->regmap,
+					    wm8962_dc_measure,
+					    ARRAY_SIZE(wm8962_dc_measure));
+		if (ret != 0)
+			dev_err(&i2c->dev,
+				"Failed to configure for DC mesurement: %d\n",
+				ret);
+	}
+
+	pm_runtime_enable(&i2c->dev);
+	pm_request_idle(&i2c->dev);
 
 	ret = snd_soc_register_codec(&i2c->dev,
 				     &soc_codec_dev_wm8962, &wm8962_dai, 1);
@@ -4269,6 +3695,65 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_RUNTIME
+static int wm8962_runtime_resume(struct device *dev)
+{
+	struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
+				    wm8962->supplies);
+	if (ret != 0) {
+		dev_err(dev,
+			"Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	regcache_cache_only(wm8962->regmap, false);
+	regcache_sync(wm8962->regmap);
+
+	regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,
+			   WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA,
+			   WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA);
+
+	/* Bias enable at 2*50k for ramp */
+	regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
+			   WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA,
+			   WM8962_BIAS_ENA | 0x180);
+
+	msleep(5);
+
+	/* VMID back to 2x250k for standby */
+	regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
+			   WM8962_VMID_SEL_MASK, 0x100);
+
+	return 0;
+}
+
+static int wm8962_runtime_suspend(struct device *dev)
+{
+	struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
+
+	regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
+			   WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA, 0);
+
+	regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,
+			   WM8962_STARTUP_BIAS_ENA |
+			   WM8962_VMID_BUF_ENA, 0);
+
+	regcache_cache_only(wm8962->regmap, true);
+
+	regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies),
+			       wm8962->supplies);
+
+	return 0;
+}
+#endif
+
+static struct dev_pm_ops wm8962_pm = {
+	SET_RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL)
+};
+
 static const struct i2c_device_id wm8962_i2c_id[] = {
 	{ "wm8962", 0 },
 	{ }
@@ -4279,34 +3764,14 @@
 	.driver = {
 		.name = "wm8962",
 		.owner = THIS_MODULE,
+		.pm = &wm8962_pm,
 	},
 	.probe =    wm8962_i2c_probe,
 	.remove =   __devexit_p(wm8962_i2c_remove),
 	.id_table = wm8962_i2c_id,
 };
-#endif
 
-static int __init wm8962_modinit(void)
-{
-	int ret;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	ret = i2c_add_driver(&wm8962_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register WM8962 I2C driver: %d\n",
-		       ret);
-	}
-#endif
-	return 0;
-}
-module_init(wm8962_modinit);
-
-static void __exit wm8962_exit(void)
-{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	i2c_del_driver(&wm8962_i2c_driver);
-#endif
-}
-module_exit(wm8962_exit);
+module_i2c_driver(wm8962_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8962 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 4af8936..28fe59e 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -252,7 +252,7 @@
 	SND_SOC_DAPM_INPUT("MIC"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8971_dapm_routes[] = {
 	/* left mixer */
 	{"Left Mixer", "Playback Switch", "Left DAC"},
 	{"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
@@ -329,17 +329,6 @@
 	{"Right ADC", NULL, "Right ADC Mux"},
 };
 
-static int wm8971_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm8971_dapm_widgets,
-				  ARRAY_SIZE(wm8971_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-	return 0;
-}
-
 struct _coeff_div {
 	u32 mclk;
 	u32 rate;
@@ -659,10 +648,6 @@
 	snd_soc_update_bits(codec, WM8971_LINVOL, 0x0100, 0x0100);
 	snd_soc_update_bits(codec, WM8971_RINVOL, 0x0100, 0x0100);
 
-	snd_soc_add_controls(codec, wm8971_snd_controls,
-				ARRAY_SIZE(wm8971_snd_controls));
-	wm8971_add_widgets(codec);
-
 	return ret;
 }
 
@@ -686,16 +671,23 @@
 	.reg_cache_size = ARRAY_SIZE(wm8971_reg),
 	.reg_word_size = sizeof(u16),
 	.reg_cache_default = wm8971_reg,
+
+	.controls = wm8971_snd_controls,
+	.num_controls = ARRAY_SIZE(wm8971_snd_controls),
+	.dapm_widgets = wm8971_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8971_dapm_widgets),
+	.dapm_routes = wm8971_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm8971_dapm_routes),
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8971_i2c_probe(struct i2c_client *i2c,
 				      const struct i2c_device_id *id)
 {
 	struct wm8971_priv *wm8971;
 	int ret;
 
-	wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL);
+	wm8971 = devm_kzalloc(&i2c->dev, sizeof(struct wm8971_priv),
+			      GFP_KERNEL);
 	if (wm8971 == NULL)
 		return -ENOMEM;
 
@@ -704,15 +696,13 @@
 
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_wm8971, &wm8971_dai, 1);
-	if (ret < 0)
-		kfree(wm8971);
+
 	return ret;
 }
 
 static __devexit int wm8971_i2c_remove(struct i2c_client *client)
 {
 	snd_soc_unregister_codec(&client->dev);
-	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
@@ -731,27 +721,22 @@
 	.remove =   __devexit_p(wm8971_i2c_remove),
 	.id_table = wm8971_i2c_id,
 };
-#endif
 
 static int __init wm8971_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	ret = i2c_add_driver(&wm8971_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register WM8971 I2C driver: %d\n",
 		       ret);
 	}
-#endif
 	return ret;
 }
 module_init(wm8971_modinit);
 
 static void __exit wm8971_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	i2c_del_driver(&wm8971_i2c_driver);
-#endif
 }
 module_exit(wm8971_exit);
 
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 4a6a7b5..d93c03f 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -48,10 +48,6 @@
 #define WM8974_POWER1_BIASEN  0x08
 #define WM8974_POWER1_BUFIOEN 0x04
 
-struct wm8974_priv {
-	enum snd_soc_control_type control_type;
-};
-
 #define wm8974_reset(c)	snd_soc_write(c, WM8974_RESET, 0)
 
 static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" };
@@ -235,7 +231,7 @@
 SND_SOC_DAPM_OUTPUT("SPKOUTN"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8974_dapm_routes[] = {
 	/* Mono output mixer */
 	{"Mono Mixer", "PCM Playback Switch", "DAC"},
 	{"Mono Mixer", "Aux Playback Switch", "Aux Input"},
@@ -269,17 +265,6 @@
 	{"Aux Input", NULL, "AUX"},
 };
 
-static int wm8974_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm8974_dapm_widgets,
-				  ARRAY_SIZE(wm8974_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-	return 0;
-}
-
 struct pll_ {
 	unsigned int pre_div:1;
 	unsigned int n:4;
@@ -611,9 +596,6 @@
 	}
 
 	wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-	snd_soc_add_controls(codec, wm8974_snd_controls,
-			     ARRAY_SIZE(wm8974_snd_controls));
-	wm8974_add_widgets(codec);
 
 	return ret;
 }
@@ -634,32 +616,30 @@
 	.reg_cache_size = ARRAY_SIZE(wm8974_reg),
 	.reg_word_size = sizeof(u16),
 	.reg_cache_default = wm8974_reg,
+
+	.controls = wm8974_snd_controls,
+	.num_controls = ARRAY_SIZE(wm8974_snd_controls),
+	.dapm_widgets = wm8974_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8974_dapm_widgets),
+	.dapm_routes = wm8974_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm8974_dapm_routes),
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8974_i2c_probe(struct i2c_client *i2c,
 				      const struct i2c_device_id *id)
 {
-	struct wm8974_priv *wm8974;
 	int ret;
 
-	wm8974 = kzalloc(sizeof(struct wm8974_priv), GFP_KERNEL);
-	if (wm8974 == NULL)
-		return -ENOMEM;
-
-	i2c_set_clientdata(i2c, wm8974);
-
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_wm8974, &wm8974_dai, 1);
-	if (ret < 0)
-		kfree(wm8974);
+
 	return ret;
 }
 
 static __devexit int wm8974_i2c_remove(struct i2c_client *client)
 {
 	snd_soc_unregister_codec(&client->dev);
-	kfree(i2c_get_clientdata(client));
+
 	return 0;
 }
 
@@ -678,27 +658,22 @@
 	.remove =   __devexit_p(wm8974_i2c_remove),
 	.id_table = wm8974_i2c_id,
 };
-#endif
 
 static int __init wm8974_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	ret = i2c_add_driver(&wm8974_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register wm8974 I2C driver: %d\n",
 		       ret);
 	}
-#endif
 	return ret;
 }
 module_init(wm8974_modinit);
 
 static void __exit wm8974_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	i2c_del_driver(&wm8974_i2c_driver);
-#endif
 }
 module_exit(wm8974_exit);
 
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 85d514d..72d5fdc 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -29,28 +30,74 @@
 
 #include "wm8978.h"
 
-/* wm8978 register cache. Note that register 0 is not included in the cache. */
-static const u16 wm8978_reg[WM8978_CACHEREGNUM] = {
-	0x0000, 0x0000, 0x0000, 0x0000,	/* 0x00...0x03 */
-	0x0050, 0x0000, 0x0140, 0x0000,	/* 0x04...0x07 */
-	0x0000, 0x0000, 0x0000, 0x00ff,	/* 0x08...0x0b */
-	0x00ff, 0x0000, 0x0100, 0x00ff,	/* 0x0c...0x0f */
-	0x00ff, 0x0000, 0x012c, 0x002c,	/* 0x10...0x13 */
-	0x002c, 0x002c, 0x002c, 0x0000,	/* 0x14...0x17 */
-	0x0032, 0x0000, 0x0000, 0x0000,	/* 0x18...0x1b */
-	0x0000, 0x0000, 0x0000, 0x0000,	/* 0x1c...0x1f */
-	0x0038, 0x000b, 0x0032, 0x0000,	/* 0x20...0x23 */
-	0x0008, 0x000c, 0x0093, 0x00e9,	/* 0x24...0x27 */
-	0x0000, 0x0000, 0x0000, 0x0000,	/* 0x28...0x2b */
-	0x0033, 0x0010, 0x0010, 0x0100,	/* 0x2c...0x2f */
-	0x0100, 0x0002, 0x0001, 0x0001,	/* 0x30...0x33 */
-	0x0039, 0x0039, 0x0039, 0x0039,	/* 0x34...0x37 */
-	0x0001,	0x0001,			/* 0x38...0x3b */
+static const struct reg_default wm8978_reg_defaults[] = {
+	{ 1, 0x0000 },
+	{ 2, 0x0000 },
+	{ 3, 0x0000 },
+	{ 4, 0x0050 },
+	{ 5, 0x0000 },
+	{ 6, 0x0140 },
+	{ 7, 0x0000 },
+	{ 8, 0x0000 },
+	{ 9, 0x0000 },
+	{ 10, 0x0000 },
+	{ 11, 0x00ff },
+	{ 12, 0x00ff },
+	{ 13, 0x0000 },
+	{ 14, 0x0100 },
+	{ 15, 0x00ff },
+	{ 16, 0x00ff },
+	{ 17, 0x0000 },
+	{ 18, 0x012c },
+	{ 19, 0x002c },
+	{ 20, 0x002c },
+	{ 21, 0x002c },
+	{ 22, 0x002c },
+	{ 23, 0x0000 },
+	{ 24, 0x0032 },
+	{ 25, 0x0000 },
+	{ 26, 0x0000 },
+	{ 27, 0x0000 },
+	{ 28, 0x0000 },
+	{ 29, 0x0000 },
+	{ 30, 0x0000 },
+	{ 31, 0x0000 },
+	{ 32, 0x0038 },
+	{ 33, 0x000b },
+	{ 34, 0x0032 },
+	{ 35, 0x0000 },
+	{ 36, 0x0008 },
+	{ 37, 0x000c },
+	{ 38, 0x0093 },
+	{ 39, 0x00e9 },
+	{ 40, 0x0000 },
+	{ 41, 0x0000 },
+	{ 42, 0x0000 },
+	{ 43, 0x0000 },
+	{ 44, 0x0033 },
+	{ 45, 0x0010 },
+	{ 46, 0x0010 },
+	{ 47, 0x0100 },
+	{ 48, 0x0100 },
+	{ 49, 0x0002 },
+	{ 50, 0x0001 },
+	{ 51, 0x0001 },
+	{ 52, 0x0039 },
+	{ 53, 0x0039 },
+	{ 54, 0x0039 },
+	{ 55, 0x0039 },
+	{ 56, 0x0001 },
+	{ 57, 0x0001 },
 };
 
+static bool wm8978_volatile(struct device *dev, unsigned int reg)
+{
+	return reg == WM8978_RESET;
+}
+
 /* codec private data */
 struct wm8978_priv {
-	enum snd_soc_control_type control_type;
+	struct regmap *regmap;
 	unsigned int f_pllout;
 	unsigned int f_mclk;
 	unsigned int f_256fs;
@@ -303,7 +350,7 @@
 	SND_SOC_DAPM_OUTPUT("RSPK"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8978_dapm_routes[] = {
 	/* Output mixer */
 	{"Right Output Mixer", "PCM Playback Switch", "Right DAC"},
 	{"Right Output Mixer", "Aux Playback Switch", "RAUX"},
@@ -352,18 +399,6 @@
 	{"Left Input Mixer", "MicP Switch", "LMICP"},
 };
 
-static int wm8978_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm8978_dapm_widgets,
-				  ARRAY_SIZE(wm8978_dapm_widgets));
-	/* set up the WM8978 audio map */
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-	return 0;
-}
-
 /* PLL divisors */
 struct wm8978_pll_div {
 	u32 k;
@@ -894,26 +929,23 @@
 
 static int wm8978_suspend(struct snd_soc_codec *codec)
 {
+	struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
+
 	wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
 	/* Also switch PLL off */
 	snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0);
 
+	regcache_mark_dirty(wm8978->regmap);
+
 	return 0;
 }
 
 static int wm8978_resume(struct snd_soc_codec *codec)
 {
 	struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
-	int i;
-	u16 *cache = codec->reg_cache;
 
 	/* Sync reg_cache with the hardware */
-	for (i = 0; i < ARRAY_SIZE(wm8978_reg); i++) {
-		if (i == WM8978_RESET)
-			continue;
-		if (cache[i] != wm8978_reg[i])
-			snd_soc_write(codec, i, cache[i]);
-	}
+	regcache_sync(wm8978->regmap);
 
 	wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -953,7 +985,8 @@
 	 * default hardware setting
 	 */
 	wm8978->sysclk = WM8978_PLL;
-	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
+	codec->control_data = wm8978->regmap;
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
@@ -967,19 +1000,8 @@
 	for (i = 0; i < ARRAY_SIZE(update_reg); i++)
 		snd_soc_update_bits(codec, update_reg[i], 0x100, 0x100);
 
-	/* Reset the codec */
-	ret = snd_soc_write(codec, WM8978_RESET, 0);
-	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset\n");
-		return ret;
-	}
-
 	wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-	snd_soc_add_controls(codec, wm8978_snd_controls,
-			     ARRAY_SIZE(wm8978_snd_controls));
-	wm8978_add_widgets(codec);
-
 	return 0;
 }
 
@@ -996,35 +1018,75 @@
 	.suspend =	wm8978_suspend,
 	.resume =	wm8978_resume,
 	.set_bias_level = wm8978_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(wm8978_reg),
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = wm8978_reg,
+
+	.controls = wm8978_snd_controls,
+	.num_controls = ARRAY_SIZE(wm8978_snd_controls),
+	.dapm_widgets = wm8978_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8978_dapm_widgets),
+	.dapm_routes = wm8978_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm8978_dapm_routes),
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static const struct regmap_config wm8978_regmap_config = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = WM8978_MAX_REGISTER,
+	.volatile_reg = wm8978_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8978_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8978_reg_defaults),
+};
+
 static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,
 				      const struct i2c_device_id *id)
 {
 	struct wm8978_priv *wm8978;
 	int ret;
 
-	wm8978 = kzalloc(sizeof(struct wm8978_priv), GFP_KERNEL);
+	wm8978 = devm_kzalloc(&i2c->dev, sizeof(struct wm8978_priv),
+			      GFP_KERNEL);
 	if (wm8978 == NULL)
 		return -ENOMEM;
 
+	wm8978->regmap = regmap_init_i2c(i2c, &wm8978_regmap_config);
+	if (IS_ERR(wm8978->regmap)) {
+		ret = PTR_ERR(wm8978->regmap);
+		dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
 	i2c_set_clientdata(i2c, wm8978);
 
+	/* Reset the codec */
+	ret = regmap_write(wm8978->regmap, WM8978_RESET, 0);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
+		goto err;
+	}
+
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_wm8978, &wm8978_dai, 1);
-	if (ret < 0)
-		kfree(wm8978);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	regmap_exit(wm8978->regmap);
 	return ret;
 }
 
 static __devexit int wm8978_i2c_remove(struct i2c_client *client)
 {
+	struct wm8978_priv *wm8978 = i2c_get_clientdata(client);
+
 	snd_soc_unregister_codec(&client->dev);
-	kfree(i2c_get_clientdata(client));
+	regmap_exit(wm8978->regmap);
+
 	return 0;
 }
 
@@ -1043,27 +1105,22 @@
 	.remove =   __devexit_p(wm8978_i2c_remove),
 	.id_table = wm8978_i2c_id,
 };
-#endif
 
 static int __init wm8978_modinit(void)
 {
 	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	ret = i2c_add_driver(&wm8978_i2c_driver);
 	if (ret != 0) {
 		printk(KERN_ERR "Failed to register WM8978 I2C driver: %d\n",
 		       ret);
 	}
-#endif
 	return ret;
 }
 module_init(wm8978_modinit);
 
 static void __exit wm8978_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	i2c_del_driver(&wm8978_i2c_driver);
-#endif
 }
 module_exit(wm8978_exit);
 
diff --git a/sound/soc/codecs/wm8978.h b/sound/soc/codecs/wm8978.h
index c75525b..6ae4349 100644
--- a/sound/soc/codecs/wm8978.h
+++ b/sound/soc/codecs/wm8978.h
@@ -67,6 +67,8 @@
 #define WM8978_OUT3_MIXER_CONTROL		0x38
 #define WM8978_OUT4_MIXER_CONTROL		0x39
 
+#define WM8978_MAX_REGISTER			0x39
+
 #define WM8978_CACHEREGNUM			58
 
 /* Clock divider Id's */
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index cebde56..367388f 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -249,9 +249,6 @@
 static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5,
 				  eq5_cutoff_text);
 
-static const char *speaker_mode_text[] = { "Class A/B", "Class D" };
-static const SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text);
-
 static const char *depth_3d_text[] = {
 	"Off",
 	"6.67%",
@@ -369,8 +366,6 @@
 	SOC_SINGLE_TLV("EQ5 Volume", WM8983_EQ5_HIGH_SHELF, 0, 24, 1, eq_tlv),
 
 	SOC_ENUM("3D Depth", depth_3d),
-
-	SOC_ENUM("Speaker Mode", speaker_mode)
 };
 
 static const struct snd_kcontrol_new left_out_mixer[] = {
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index c0c86b3..14f6663 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -19,6 +19,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
@@ -39,73 +40,127 @@
 	"AVDD2"
 };
 
-static const u16 wm8985_reg_defs[] = {
-	0x0000,     /* R0  - Software Reset */
-	0x0000,     /* R1  - Power management 1 */
-	0x0000,     /* R2  - Power management 2 */
-	0x0000,     /* R3  - Power management 3 */
-	0x0050,     /* R4  - Audio Interface */
-	0x0000,     /* R5  - Companding control */
-	0x0140,     /* R6  - Clock Gen control */
-	0x0000,     /* R7  - Additional control */
-	0x0000,     /* R8  - GPIO Control */
-	0x0000,     /* R9  - Jack Detect Control 1 */
-	0x0000,     /* R10 - DAC Control */
-	0x00FF,     /* R11 - Left DAC digital Vol */
-	0x00FF,     /* R12 - Right DAC digital vol */
-	0x0000,     /* R13 - Jack Detect Control 2 */
-	0x0100,     /* R14 - ADC Control */
-	0x00FF,     /* R15 - Left ADC Digital Vol */
-	0x00FF,     /* R16 - Right ADC Digital Vol */
-	0x0000,     /* R17 */
-	0x012C,     /* R18 - EQ1 - low shelf */
-	0x002C,     /* R19 - EQ2 - peak 1 */
-	0x002C,     /* R20 - EQ3 - peak 2 */
-	0x002C,     /* R21 - EQ4 - peak 3 */
-	0x002C,     /* R22 - EQ5 - high shelf */
-	0x0000,     /* R23 */
-	0x0032,     /* R24 - DAC Limiter 1 */
-	0x0000,     /* R25 - DAC Limiter 2 */
-	0x0000,     /* R26 */
-	0x0000,     /* R27 - Notch Filter 1 */
-	0x0000,     /* R28 - Notch Filter 2 */
-	0x0000,     /* R29 - Notch Filter 3 */
-	0x0000,     /* R30 - Notch Filter 4 */
-	0x0000,     /* R31 */
-	0x0038,     /* R32 - ALC control 1 */
-	0x000B,     /* R33 - ALC control 2 */
-	0x0032,     /* R34 - ALC control 3 */
-	0x0000,     /* R35 - Noise Gate */
-	0x0008,     /* R36 - PLL N */
-	0x000C,     /* R37 - PLL K 1 */
-	0x0093,     /* R38 - PLL K 2 */
-	0x00E9,     /* R39 - PLL K 3 */
-	0x0000,     /* R40 */
-	0x0000,     /* R41 - 3D control */
-	0x0000,     /* R42 - OUT4 to ADC */
-	0x0000,     /* R43 - Beep control */
-	0x0033,     /* R44 - Input ctrl */
-	0x0010,     /* R45 - Left INP PGA gain ctrl */
-	0x0010,     /* R46 - Right INP PGA gain ctrl */
-	0x0100,     /* R47 - Left ADC BOOST ctrl */
-	0x0100,     /* R48 - Right ADC BOOST ctrl */
-	0x0002,     /* R49 - Output ctrl */
-	0x0001,     /* R50 - Left mixer ctrl */
-	0x0001,     /* R51 - Right mixer ctrl */
-	0x0039,     /* R52 - LOUT1 (HP) volume ctrl */
-	0x0039,     /* R53 - ROUT1 (HP) volume ctrl */
-	0x0039,     /* R54 - LOUT2 (SPK) volume ctrl */
-	0x0039,     /* R55 - ROUT2 (SPK) volume ctrl */
-	0x0001,     /* R56 - OUT3 mixer ctrl */
-	0x0001,     /* R57 - OUT4 (MONO) mix ctrl */
-	0x0001,     /* R58 */
-	0x0000,     /* R59 */
-	0x0004,     /* R60 - OUTPUT ctrl */
-	0x0000,     /* R61 - BIAS CTRL */
-	0x0180,     /* R62 */
-	0x0000      /* R63 */
+static const struct reg_default wm8985_reg_defaults[] = {
+	{ 1,  0x0000 },     /* R1  - Power management 1 */
+	{ 2,  0x0000 },     /* R2  - Power management 2 */
+	{ 3,  0x0000 },     /* R3  - Power management 3 */
+	{ 4,  0x0050 },     /* R4  - Audio Interface */
+	{ 5,  0x0000 },     /* R5  - Companding control */
+	{ 6,  0x0140 },     /* R6  - Clock Gen control */
+	{ 7,  0x0000 },     /* R7  - Additional control */
+	{ 8,  0x0000 },     /* R8  - GPIO Control */
+	{ 9,  0x0000 },     /* R9  - Jack Detect Control 1 */
+	{ 10, 0x0000 },     /* R10 - DAC Control */
+	{ 11, 0x00FF },     /* R11 - Left DAC digital Vol */
+	{ 12, 0x00FF },     /* R12 - Right DAC digital vol */
+	{ 13, 0x0000 },     /* R13 - Jack Detect Control 2 */
+	{ 14, 0x0100 },     /* R14 - ADC Control */
+	{ 15, 0x00FF },     /* R15 - Left ADC Digital Vol */
+	{ 16, 0x00FF },     /* R16 - Right ADC Digital Vol */
+	{ 18, 0x012C },     /* R18 - EQ1 - low shelf */
+	{ 19, 0x002C },     /* R19 - EQ2 - peak 1 */
+	{ 20, 0x002C },     /* R20 - EQ3 - peak 2 */
+	{ 21, 0x002C },     /* R21 - EQ4 - peak 3 */
+	{ 22, 0x002C },     /* R22 - EQ5 - high shelf */
+	{ 24, 0x0032 },     /* R24 - DAC Limiter 1 */
+	{ 25, 0x0000 },     /* R25 - DAC Limiter 2 */
+	{ 27, 0x0000 },     /* R27 - Notch Filter 1 */
+	{ 28, 0x0000 },     /* R28 - Notch Filter 2 */
+	{ 29, 0x0000 },     /* R29 - Notch Filter 3 */
+	{ 30, 0x0000 },     /* R30 - Notch Filter 4 */
+	{ 32, 0x0038 },     /* R32 - ALC control 1 */
+	{ 33, 0x000B },     /* R33 - ALC control 2 */
+	{ 34, 0x0032 },     /* R34 - ALC control 3 */
+	{ 35, 0x0000 },     /* R35 - Noise Gate */
+	{ 36, 0x0008 },     /* R36 - PLL N */
+	{ 37, 0x000C },     /* R37 - PLL K 1 */
+	{ 38, 0x0093 },     /* R38 - PLL K 2 */
+	{ 39, 0x00E9 },     /* R39 - PLL K 3 */
+	{ 41, 0x0000 },     /* R41 - 3D control */
+	{ 42, 0x0000 },     /* R42 - OUT4 to ADC */
+	{ 43, 0x0000 },     /* R43 - Beep control */
+	{ 44, 0x0033 },     /* R44 - Input ctrl */
+	{ 45, 0x0010 },     /* R45 - Left INP PGA gain ctrl */
+	{ 46, 0x0010 },     /* R46 - Right INP PGA gain ctrl */
+	{ 47, 0x0100 },     /* R47 - Left ADC BOOST ctrl */
+	{ 48, 0x0100 },     /* R48 - Right ADC BOOST ctrl */
+	{ 49, 0x0002 },     /* R49 - Output ctrl */
+	{ 50, 0x0001 },     /* R50 - Left mixer ctrl */
+	{ 51, 0x0001 },     /* R51 - Right mixer ctrl */
+	{ 52, 0x0039 },     /* R52 - LOUT1 (HP) volume ctrl */
+	{ 53, 0x0039 },     /* R53 - ROUT1 (HP) volume ctrl */
+	{ 54, 0x0039 },     /* R54 - LOUT2 (SPK) volume ctrl */
+	{ 55, 0x0039 },     /* R55 - ROUT2 (SPK) volume ctrl */
+	{ 56, 0x0001 },     /* R56 - OUT3 mixer ctrl */
+	{ 57, 0x0001 },     /* R57 - OUT4 (MONO) mix ctrl */
+	{ 60, 0x0004 },     /* R60 - OUTPUT ctrl */
+	{ 61, 0x0000 },     /* R61 - BIAS CTRL */
 };
 
+static bool wm8985_writeable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8985_SOFTWARE_RESET:
+	case WM8985_POWER_MANAGEMENT_1:
+	case WM8985_POWER_MANAGEMENT_2:
+	case WM8985_POWER_MANAGEMENT_3:
+	case WM8985_AUDIO_INTERFACE:
+	case WM8985_COMPANDING_CONTROL:
+	case WM8985_CLOCK_GEN_CONTROL:
+	case WM8985_ADDITIONAL_CONTROL:
+	case WM8985_GPIO_CONTROL:
+	case WM8985_JACK_DETECT_CONTROL_1:
+	case WM8985_DAC_CONTROL:
+	case WM8985_LEFT_DAC_DIGITAL_VOL:
+	case WM8985_RIGHT_DAC_DIGITAL_VOL:
+	case WM8985_JACK_DETECT_CONTROL_2:
+	case WM8985_ADC_CONTROL:
+	case WM8985_LEFT_ADC_DIGITAL_VOL:
+	case WM8985_RIGHT_ADC_DIGITAL_VOL:
+	case WM8985_EQ1_LOW_SHELF:
+	case WM8985_EQ2_PEAK_1:
+	case WM8985_EQ3_PEAK_2:
+	case WM8985_EQ4_PEAK_3:
+	case WM8985_EQ5_HIGH_SHELF:
+	case WM8985_DAC_LIMITER_1:
+	case WM8985_DAC_LIMITER_2:
+	case WM8985_NOTCH_FILTER_1:
+	case WM8985_NOTCH_FILTER_2:
+	case WM8985_NOTCH_FILTER_3:
+	case WM8985_NOTCH_FILTER_4:
+	case WM8985_ALC_CONTROL_1:
+	case WM8985_ALC_CONTROL_2:
+	case WM8985_ALC_CONTROL_3:
+	case WM8985_NOISE_GATE:
+	case WM8985_PLL_N:
+	case WM8985_PLL_K_1:
+	case WM8985_PLL_K_2:
+	case WM8985_PLL_K_3:
+	case WM8985_3D_CONTROL:
+	case WM8985_OUT4_TO_ADC:
+	case WM8985_BEEP_CONTROL:
+	case WM8985_INPUT_CTRL:
+	case WM8985_LEFT_INP_PGA_GAIN_CTRL:
+	case WM8985_RIGHT_INP_PGA_GAIN_CTRL:
+	case WM8985_LEFT_ADC_BOOST_CTRL:
+	case WM8985_RIGHT_ADC_BOOST_CTRL:
+	case WM8985_OUTPUT_CTRL0:
+	case WM8985_LEFT_MIXER_CTRL:
+	case WM8985_RIGHT_MIXER_CTRL:
+	case WM8985_LOUT1_HP_VOLUME_CTRL:
+	case WM8985_ROUT1_HP_VOLUME_CTRL:
+	case WM8985_LOUT2_SPK_VOLUME_CTRL:
+	case WM8985_ROUT2_SPK_VOLUME_CTRL:
+	case WM8985_OUT3_MIXER_CTRL:
+	case WM8985_OUT4_MONO_MIX_CTRL:
+	case WM8985_OUTPUT_CTRL1:
+	case WM8985_BIAS_CTRL:
+		return true;
+	default:
+		return false;
+	}
+}
+
 /*
  * latch bit 8 of these registers to ensure instant
  * volume updates
@@ -124,7 +179,7 @@
 };
 
 struct wm8985_priv {
-	enum snd_soc_control_type control_type;
+	struct regmap *regmap;
 	struct regulator_bulk_data supplies[WM8985_NUM_SUPPLIES];
 	unsigned int sysclk;
 	unsigned int bclk;
@@ -428,7 +483,7 @@
 	SND_SOC_DAPM_OUTPUT("SPKR")
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8985_dapm_routes[] = {
 	{ "Right Output Mixer", "PCM Switch", "Right DAC" },
 	{ "Right Output Mixer", "Aux Switch", "AUXR" },
 	{ "Right Output Mixer", "Line Switch", "Right Boost Mixer" },
@@ -531,17 +586,6 @@
 	return 0;
 }
 
-static int wm8985_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm8985_dapm_widgets,
-				  ARRAY_SIZE(wm8985_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, audio_map,
-				ARRAY_SIZE(audio_map));
-	return 0;
-}
-
 static int wm8985_reset(struct snd_soc_codec *codec)
 {
 	return snd_soc_write(codec, WM8985_SOFTWARE_RESET, 0x0);
@@ -845,25 +889,6 @@
 	return 0;
 }
 
-static void wm8985_sync_cache(struct snd_soc_codec *codec)
-{
-	short i;
-	u16 *cache;
-
-	if (!codec->cache_sync)
-		return;
-	codec->cache_only = 0;
-	/* restore cache */
-	cache = codec->reg_cache;
-	for (i = 0; i < codec->driver->reg_cache_size; i++) {
-		if (i == WM8985_SOFTWARE_RESET
-				|| cache[i] == wm8985_reg_defs[i])
-			continue;
-		snd_soc_write(codec, i, cache[i]);
-	}
-	codec->cache_sync = 0;
-}
-
 static int wm8985_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
@@ -890,7 +915,7 @@
 				return ret;
 			}
 
-			wm8985_sync_cache(codec);
+			regcache_sync(wm8985->regmap);
 
 			/* enable anti-pop features */
 			snd_soc_update_bits(codec, WM8985_OUT4_TO_ADC,
@@ -933,7 +958,7 @@
 		snd_soc_write(codec, WM8985_POWER_MANAGEMENT_2, 0);
 		snd_soc_write(codec, WM8985_POWER_MANAGEMENT_3, 0);
 
-		codec->cache_sync = 1;
+		regcache_mark_dirty(wm8985->regmap);
 
 		regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies),
 				       wm8985->supplies);
@@ -976,11 +1001,11 @@
 	size_t i;
 	struct wm8985_priv *wm8985;
 	int ret;
-	u16 *cache;
 
 	wm8985 = snd_soc_codec_get_drvdata(codec);
+	codec->control_data = wm8985->regmap;
 
-	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8985->control_type);
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
 		return ret;
@@ -1009,17 +1034,13 @@
 		goto err_reg_enable;
 	}
 
-	cache = codec->reg_cache;
 	/* latch volume update bits */
 	for (i = 0; i < ARRAY_SIZE(volume_update_regs); ++i)
-		cache[volume_update_regs[i]] |= 0x100;
+		snd_soc_update_bits(codec, volume_update_regs[i],
+				    0x100, 0x100);
 	/* enable BIASCUT */
-	cache[WM8985_BIAS_CTRL] |= WM8985_BIASCUT;
-	codec->cache_sync = 1;
-
-	snd_soc_add_controls(codec, wm8985_snd_controls,
-			     ARRAY_SIZE(wm8985_snd_controls));
-	wm8985_add_widgets(codec);
+	snd_soc_update_bits(codec, WM8985_BIAS_CTRL, WM8985_BIASCUT,
+			    WM8985_BIASCUT);
 
 	wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	return 0;
@@ -1068,9 +1089,25 @@
 	.suspend = wm8985_suspend,
 	.resume = wm8985_resume,
 	.set_bias_level = wm8985_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(wm8985_reg_defs),
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = wm8985_reg_defs
+
+	.controls = wm8985_snd_controls,
+	.num_controls = ARRAY_SIZE(wm8985_snd_controls),
+	.dapm_widgets = wm8985_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8985_dapm_widgets),
+	.dapm_routes = wm8985_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm8985_dapm_routes),
+};
+
+static const struct regmap_config wm8985_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = WM8985_MAX_REGISTER,
+	.writeable_reg = wm8985_writeable,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8985_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8985_reg_defaults),
 };
 
 #if defined(CONFIG_SPI_MASTER)
@@ -1079,24 +1116,39 @@
 	struct wm8985_priv *wm8985;
 	int ret;
 
-	wm8985 = kzalloc(sizeof *wm8985, GFP_KERNEL);
+	wm8985 = devm_kzalloc(&spi->dev, sizeof *wm8985, GFP_KERNEL);
 	if (!wm8985)
 		return -ENOMEM;
 
-	wm8985->control_type = SND_SOC_SPI;
 	spi_set_drvdata(spi, wm8985);
 
+	wm8985->regmap = regmap_init_spi(spi, &wm8985_regmap);
+	if (IS_ERR(wm8985->regmap)) {
+		ret = PTR_ERR(wm8985->regmap);
+		dev_err(&spi->dev, "Failed to allocate register map: %d\n",
+			ret);
+		goto err;
+	}
+
 	ret = snd_soc_register_codec(&spi->dev,
 				     &soc_codec_dev_wm8985, &wm8985_dai, 1);
-	if (ret < 0)
-		kfree(wm8985);
+	if (ret != 0)
+		goto err;
+
+	return 0;
+
+err:
+	regmap_exit(wm8985->regmap);
 	return ret;
 }
 
 static int __devexit wm8985_spi_remove(struct spi_device *spi)
 {
+	struct wm8985_priv *wm8985 = spi_get_drvdata(spi);
+
 	snd_soc_unregister_codec(&spi->dev);
-	kfree(spi_get_drvdata(spi));
+	regmap_exit(wm8985->regmap);
+
 	return 0;
 }
 
@@ -1117,24 +1169,39 @@
 	struct wm8985_priv *wm8985;
 	int ret;
 
-	wm8985 = kzalloc(sizeof *wm8985, GFP_KERNEL);
+	wm8985 = devm_kzalloc(&i2c->dev, sizeof *wm8985, GFP_KERNEL);
 	if (!wm8985)
 		return -ENOMEM;
 
-	wm8985->control_type = SND_SOC_I2C;
 	i2c_set_clientdata(i2c, wm8985);
 
+	wm8985->regmap = regmap_init_i2c(i2c, &wm8985_regmap);
+	if (IS_ERR(wm8985->regmap)) {
+		ret = PTR_ERR(wm8985->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		goto err;
+	}
+
 	ret = snd_soc_register_codec(&i2c->dev,
 				     &soc_codec_dev_wm8985, &wm8985_dai, 1);
-	if (ret < 0)
-		kfree(wm8985);
+	if (ret != 0)
+		goto err;
+
+	return 0;
+
+err:
+	regmap_exit(wm8985->regmap);
 	return ret;
 }
 
-static __devexit int wm8985_i2c_remove(struct i2c_client *client)
+static __devexit int wm8985_i2c_remove(struct i2c_client *i2c)
 {
-	snd_soc_unregister_codec(&client->dev);
-	kfree(i2c_get_clientdata(client));
+	struct wm8985_priv *wm8985 = i2c_get_clientdata(i2c);
+
+	snd_soc_unregister_codec(&i2c->dev);
+	regmap_exit(wm8985->regmap);
+
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index ab52963..6cdf6a2 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -33,24 +33,89 @@
  * We can't read the WM8988 register space when we
  * are using 2 wire for device control, so we cache them instead.
  */
-static const u16 wm8988_reg[] = {
-	0x0097, 0x0097, 0x0079, 0x0079,  /*  0 */
-	0x0000, 0x0008, 0x0000, 0x000a,  /*  4 */
-	0x0000, 0x0000, 0x00ff, 0x00ff,  /*  8 */
-	0x000f, 0x000f, 0x0000, 0x0000,  /* 12 */
-	0x0000, 0x007b, 0x0000, 0x0032,  /* 16 */
-	0x0000, 0x00c3, 0x00c3, 0x00c0,  /* 20 */
-	0x0000, 0x0000, 0x0000, 0x0000,  /* 24 */
-	0x0000, 0x0000, 0x0000, 0x0000,  /* 28 */
-	0x0000, 0x0000, 0x0050, 0x0050,  /* 32 */
-	0x0050, 0x0050, 0x0050, 0x0050,  /* 36 */
-	0x0079, 0x0079, 0x0079,          /* 40 */
+static const struct reg_default wm8988_reg_defaults[] = {
+	{ 0, 0x0097 },
+	{ 1, 0x0097 },
+	{ 2, 0x0079 },
+	{ 3, 0x0079 },
+	{ 5, 0x0008 },
+	{ 7, 0x000a },
+	{ 8, 0x0000 },
+	{ 10, 0x00ff },
+	{ 11, 0x00ff },
+	{ 12, 0x000f },
+	{ 13, 0x000f },
+	{ 16, 0x0000 },
+	{ 17, 0x007b },
+	{ 18, 0x0000 },
+	{ 19, 0x0032 },
+	{ 20, 0x0000 },
+	{ 21, 0x00c3 },
+	{ 22, 0x00c3 },
+	{ 23, 0x00c0 },
+	{ 24, 0x0000 },
+	{ 25, 0x0000 },
+	{ 26, 0x0000 },
+	{ 27, 0x0000 },
+	{ 31, 0x0000 },
+	{ 32, 0x0000 },
+	{ 33, 0x0000 },
+	{ 34, 0x0050 },
+	{ 35, 0x0050 },
+	{ 36, 0x0050 },
+	{ 37, 0x0050 },
+	{ 40, 0x0079 },
+	{ 41, 0x0079 },
+	{ 42, 0x0079 },
 };
 
+static bool wm8988_writeable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8988_LINVOL:
+	case WM8988_RINVOL:
+	case WM8988_LOUT1V:
+	case WM8988_ROUT1V:
+	case WM8988_ADCDAC:
+	case WM8988_IFACE:
+	case WM8988_SRATE:
+	case WM8988_LDAC:
+	case WM8988_RDAC:
+	case WM8988_BASS:
+	case WM8988_TREBLE:
+	case WM8988_RESET:
+	case WM8988_3D:
+	case WM8988_ALC1:
+	case WM8988_ALC2:
+	case WM8988_ALC3:
+	case WM8988_NGATE:
+	case WM8988_LADC:
+	case WM8988_RADC:
+	case WM8988_ADCTL1:
+	case WM8988_ADCTL2:
+	case WM8988_PWR1:
+	case WM8988_PWR2:
+	case WM8988_ADCTL3:
+	case WM8988_ADCIN:
+	case WM8988_LADCIN:
+	case WM8988_RADCIN:
+	case WM8988_LOUTM1:
+	case WM8988_LOUTM2:
+	case WM8988_ROUTM1:
+	case WM8988_ROUTM2:
+	case WM8988_LOUT2V:
+	case WM8988_ROUT2V:
+	case WM8988_LPPB:
+		return true;
+	default:
+		return false;
+	}
+}
+
 /* codec private data */
 struct wm8988_priv {
+	struct regmap *regmap;
 	unsigned int sysclk;
-	enum snd_soc_control_type control_type;
 	struct snd_pcm_hw_constraint_list *sysclk_constraints;
 };
 
@@ -317,7 +382,7 @@
 	SND_SOC_DAPM_INPUT("RINPUT2"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8988_dapm_routes[] = {
 
 	{ "Left Line Mux", "Line 1", "LINPUT1" },
 	{ "Left Line Mux", "Line 2", "LINPUT2" },
@@ -661,6 +726,7 @@
 static int wm8988_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
+	struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
 	u16 pwr_reg = snd_soc_read(codec, WM8988_PWR1) & ~0x1c1;
 
 	switch (level) {
@@ -674,7 +740,7 @@
 
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-			snd_soc_cache_sync(codec);
+			regcache_sync(wm8988->regmap);
 
 			/* VREF, VMID=2x5k */
 			snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x1c1);
@@ -730,7 +796,10 @@
 
 static int wm8988_suspend(struct snd_soc_codec *codec)
 {
+	struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
+
 	wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	regcache_mark_dirty(wm8988->regmap);
 	return 0;
 }
 
@@ -743,10 +812,10 @@
 static int wm8988_probe(struct snd_soc_codec *codec)
 {
 	struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int ret = 0;
 
-	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8988->control_type);
+	codec->control_data = wm8988->regmap;
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
 	if (ret < 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
@@ -767,12 +836,6 @@
 
 	wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-	snd_soc_add_controls(codec, wm8988_snd_controls,
-				ARRAY_SIZE(wm8988_snd_controls));
-	snd_soc_dapm_new_controls(dapm, wm8988_dapm_widgets,
-				  ARRAY_SIZE(wm8988_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
 	return 0;
 }
 
@@ -788,9 +851,25 @@
 	.suspend =	wm8988_suspend,
 	.resume =	wm8988_resume,
 	.set_bias_level = wm8988_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(wm8988_reg),
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = wm8988_reg,
+
+	.controls = wm8988_snd_controls,
+	.num_controls = ARRAY_SIZE(wm8988_snd_controls),
+	.dapm_widgets = wm8988_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8988_dapm_widgets),
+	.dapm_routes = wm8988_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm8988_dapm_routes),
+};
+
+static struct regmap_config wm8988_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = WM8988_LPPB,
+	.writeable_reg = wm8988_writeable,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8988_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8988_reg_defaults),
 };
 
 #if defined(CONFIG_SPI_MASTER)
@@ -799,24 +878,33 @@
 	struct wm8988_priv *wm8988;
 	int ret;
 
-	wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL);
+	wm8988 = devm_kzalloc(&spi->dev, sizeof(struct wm8988_priv),
+			      GFP_KERNEL);
 	if (wm8988 == NULL)
 		return -ENOMEM;
 
-	wm8988->control_type = SND_SOC_SPI;
+	wm8988->regmap = regmap_init_spi(spi, &wm8988_regmap);
+	if (IS_ERR(wm8988->regmap)) {
+		ret = PTR_ERR(wm8988->regmap);
+		dev_err(&spi->dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
+
 	spi_set_drvdata(spi, wm8988);
 
 	ret = snd_soc_register_codec(&spi->dev,
 			&soc_codec_dev_wm8988, &wm8988_dai, 1);
-	if (ret < 0)
-		kfree(wm8988);
+	if (ret != 0)
+		regmap_exit(wm8988->regmap);
+
 	return ret;
 }
 
 static int __devexit wm8988_spi_remove(struct spi_device *spi)
 {
+	struct wm8988_priv *wm8988 = spi_get_drvdata(spi);
 	snd_soc_unregister_codec(&spi->dev);
-	kfree(spi_get_drvdata(spi));
+	regmap_exit(wm8988->regmap);
 	return 0;
 }
 
@@ -837,24 +925,33 @@
 	struct wm8988_priv *wm8988;
 	int ret;
 
-	wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL);
+	wm8988 = devm_kzalloc(&i2c->dev, sizeof(struct wm8988_priv),
+			      GFP_KERNEL);
 	if (wm8988 == NULL)
 		return -ENOMEM;
 
 	i2c_set_clientdata(i2c, wm8988);
-	wm8988->control_type = SND_SOC_I2C;
+
+	wm8988->regmap = regmap_init_i2c(i2c, &wm8988_regmap);
+	if (IS_ERR(wm8988->regmap)) {
+		ret = PTR_ERR(wm8988->regmap);
+		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
 
 	ret =  snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_wm8988, &wm8988_dai, 1);
-	if (ret < 0)
-		kfree(wm8988);
+	if (ret != 0)
+		regmap_exit(wm8988->regmap);
+
 	return ret;
 }
 
 static __devexit int wm8988_i2c_remove(struct i2c_client *client)
 {
+	struct wm8988_priv *wm8988 = i2c_get_clientdata(client);
 	snd_soc_unregister_codec(&client->dev);
-	kfree(i2c_get_clientdata(client));
+	regmap_exit(wm8988->regmap);
 	return 0;
 }
 
@@ -866,7 +963,7 @@
 
 static struct i2c_driver wm8988_i2c_driver = {
 	.driver = {
-		.name = "wm8988-codec",
+		.name = "wm8988",
 		.owner = THIS_MODULE,
 	},
 	.probe =    wm8988_i2c_probe,
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index e538eda..9d24235 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -1356,7 +1356,7 @@
 	snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
 	snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
 
-	snd_soc_add_controls(codec, wm8990_snd_controls,
+	snd_soc_add_codec_controls(codec, wm8990_snd_controls,
 				ARRAY_SIZE(wm8990_snd_controls));
 	wm8990_add_widgets(codec);
 
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index 7ee40da..9ac31ba 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -1297,7 +1297,7 @@
 	snd_soc_write(codec, WM8991_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
 	snd_soc_write(codec, WM8991_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
 
-	snd_soc_add_controls(codec, wm8991_snd_controls,
+	snd_soc_add_codec_controls(codec, wm8991_snd_controls,
 			     ARRAY_SIZE(wm8991_snd_controls));
 
 	snd_soc_dapm_new_controls(&codec->dapm, wm8991_dapm_widgets,
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 7c7fd92..d256a93 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
@@ -40,134 +41,113 @@
 	"SPKVDD",
 };
 
-static u16 wm8993_reg_defaults[WM8993_REGISTER_COUNT] = {
-	0x8993,     /* R0   - Software Reset */
-	0x0000,     /* R1   - Power Management (1) */
-	0x6000,     /* R2   - Power Management (2) */
-	0x0000,     /* R3   - Power Management (3) */
-	0x4050,     /* R4   - Audio Interface (1) */
-	0x4000,     /* R5   - Audio Interface (2) */
-	0x01C8,     /* R6   - Clocking 1 */
-	0x0000,     /* R7   - Clocking 2 */
-	0x0000,     /* R8   - Audio Interface (3) */
-	0x0040,     /* R9   - Audio Interface (4) */
-	0x0004,     /* R10  - DAC CTRL */
-	0x00C0,     /* R11  - Left DAC Digital Volume */
-	0x00C0,     /* R12  - Right DAC Digital Volume */
-	0x0000,     /* R13  - Digital Side Tone */
-	0x0300,     /* R14  - ADC CTRL */
-	0x00C0,     /* R15  - Left ADC Digital Volume */
-	0x00C0,     /* R16  - Right ADC Digital Volume */
-	0x0000,     /* R17 */
-	0x0000,     /* R18  - GPIO CTRL 1 */
-	0x0010,     /* R19  - GPIO1 */
-	0x0000,     /* R20  - IRQ_DEBOUNCE */
-	0x0000,     /* R21 */
-	0x8000,     /* R22  - GPIOCTRL 2 */
-	0x0800,     /* R23  - GPIO_POL */
-	0x008B,     /* R24  - Left Line Input 1&2 Volume */
-	0x008B,     /* R25  - Left Line Input 3&4 Volume */
-	0x008B,     /* R26  - Right Line Input 1&2 Volume */
-	0x008B,     /* R27  - Right Line Input 3&4 Volume */
-	0x006D,     /* R28  - Left Output Volume */
-	0x006D,     /* R29  - Right Output Volume */
-	0x0066,     /* R30  - Line Outputs Volume */
-	0x0020,     /* R31  - HPOUT2 Volume */
-	0x0079,     /* R32  - Left OPGA Volume */
-	0x0079,     /* R33  - Right OPGA Volume */
-	0x0003,     /* R34  - SPKMIXL Attenuation */
-	0x0003,     /* R35  - SPKMIXR Attenuation */
-	0x0011,     /* R36  - SPKOUT Mixers */
-	0x0100,     /* R37  - SPKOUT Boost */
-	0x0079,     /* R38  - Speaker Volume Left */
-	0x0079,     /* R39  - Speaker Volume Right */
-	0x0000,     /* R40  - Input Mixer2 */
-	0x0000,     /* R41  - Input Mixer3 */
-	0x0000,     /* R42  - Input Mixer4 */
-	0x0000,     /* R43  - Input Mixer5 */
-	0x0000,     /* R44  - Input Mixer6 */
-	0x0000,     /* R45  - Output Mixer1 */
-	0x0000,     /* R46  - Output Mixer2 */
-	0x0000,     /* R47  - Output Mixer3 */
-	0x0000,     /* R48  - Output Mixer4 */
-	0x0000,     /* R49  - Output Mixer5 */
-	0x0000,     /* R50  - Output Mixer6 */
-	0x0000,     /* R51  - HPOUT2 Mixer */
-	0x0000,     /* R52  - Line Mixer1 */
-	0x0000,     /* R53  - Line Mixer2 */
-	0x0000,     /* R54  - Speaker Mixer */
-	0x0000,     /* R55  - Additional Control */
-	0x0000,     /* R56  - AntiPOP1 */
-	0x0000,     /* R57  - AntiPOP2 */
-	0x0000,     /* R58  - MICBIAS */
-	0x0000,     /* R59 */
-	0x0000,     /* R60  - FLL Control 1 */
-	0x0000,     /* R61  - FLL Control 2 */
-	0x0000,     /* R62  - FLL Control 3 */
-	0x2EE0,     /* R63  - FLL Control 4 */
-	0x0002,     /* R64  - FLL Control 5 */
-	0x2287,     /* R65  - Clocking 3 */
-	0x025F,     /* R66  - Clocking 4 */
-	0x0000,     /* R67  - MW Slave Control */
-	0x0000,     /* R68 */
-	0x0002,     /* R69  - Bus Control 1 */
-	0x0000,     /* R70  - Write Sequencer 0 */
-	0x0000,     /* R71  - Write Sequencer 1 */
-	0x0000,     /* R72  - Write Sequencer 2 */
-	0x0000,     /* R73  - Write Sequencer 3 */
-	0x0000,     /* R74  - Write Sequencer 4 */
-	0x0000,     /* R75  - Write Sequencer 5 */
-	0x1F25,     /* R76  - Charge Pump 1 */
-	0x0000,     /* R77 */
-	0x0000,     /* R78 */
-	0x0000,     /* R79 */
-	0x0000,     /* R80 */
-	0x0000,     /* R81  - Class W 0 */
-	0x0000,     /* R82 */
-	0x0000,     /* R83 */
-	0x0000,     /* R84  - DC Servo 0 */
-	0x054A,     /* R85  - DC Servo 1 */
-	0x0000,     /* R86 */
-	0x0000,     /* R87  - DC Servo 3 */
-	0x0000,     /* R88  - DC Servo Readback 0 */
-	0x0000,     /* R89  - DC Servo Readback 1 */
-	0x0000,     /* R90  - DC Servo Readback 2 */
-	0x0000,     /* R91 */
-	0x0000,     /* R92 */
-	0x0000,     /* R93 */
-	0x0000,     /* R94 */
-	0x0000,     /* R95 */
-	0x0100,     /* R96  - Analogue HP 0 */
-	0x0000,     /* R97 */
-	0x0000,     /* R98  - EQ1 */
-	0x000C,     /* R99  - EQ2 */
-	0x000C,     /* R100 - EQ3 */
-	0x000C,     /* R101 - EQ4 */
-	0x000C,     /* R102 - EQ5 */
-	0x000C,     /* R103 - EQ6 */
-	0x0FCA,     /* R104 - EQ7 */
-	0x0400,     /* R105 - EQ8 */
-	0x00D8,     /* R106 - EQ9 */
-	0x1EB5,     /* R107 - EQ10 */
-	0xF145,     /* R108 - EQ11 */
-	0x0B75,     /* R109 - EQ12 */
-	0x01C5,     /* R110 - EQ13 */
-	0x1C58,     /* R111 - EQ14 */
-	0xF373,     /* R112 - EQ15 */
-	0x0A54,     /* R113 - EQ16 */
-	0x0558,     /* R114 - EQ17 */
-	0x168E,     /* R115 - EQ18 */
-	0xF829,     /* R116 - EQ19 */
-	0x07AD,     /* R117 - EQ20 */
-	0x1103,     /* R118 - EQ21 */
-	0x0564,     /* R119 - EQ22 */
-	0x0559,     /* R120 - EQ23 */
-	0x4000,     /* R121 - EQ24 */
-	0x0000,     /* R122 - Digital Pulls */
-	0x0F08,     /* R123 - DRC Control 1 */
-	0x0000,     /* R124 - DRC Control 2 */
-	0x0080,     /* R125 - DRC Control 3 */
-	0x0000,     /* R126 - DRC Control 4 */
+static struct reg_default wm8993_reg_defaults[] = {
+	{ 1,   0x0000 },     /* R1   - Power Management (1) */
+	{ 2,   0x6000 },     /* R2   - Power Management (2) */
+	{ 3,   0x0000 },     /* R3   - Power Management (3) */
+	{ 4,   0x4050 },     /* R4   - Audio Interface (1) */
+	{ 5,   0x4000 },     /* R5   - Audio Interface (2) */
+	{ 6,   0x01C8 },     /* R6   - Clocking 1 */
+	{ 7,   0x0000 },     /* R7   - Clocking 2 */
+	{ 8,   0x0000 },     /* R8   - Audio Interface (3) */
+	{ 9,   0x0040 },     /* R9   - Audio Interface (4) */
+	{ 10,  0x0004 },     /* R10  - DAC CTRL */
+	{ 11,  0x00C0 },     /* R11  - Left DAC Digital Volume */
+	{ 12,  0x00C0 },     /* R12  - Right DAC Digital Volume */
+	{ 13,  0x0000 },     /* R13  - Digital Side Tone */
+	{ 14,  0x0300 },     /* R14  - ADC CTRL */
+	{ 15,  0x00C0 },     /* R15  - Left ADC Digital Volume */
+	{ 16,  0x00C0 },     /* R16  - Right ADC Digital Volume */
+	{ 18,  0x0000 },     /* R18  - GPIO CTRL 1 */
+	{ 19,  0x0010 },     /* R19  - GPIO1 */
+	{ 20,  0x0000 },     /* R20  - IRQ_DEBOUNCE */
+	{ 21,  0x0000 },     /* R21  - Inputs Clamp */
+	{ 22,  0x8000 },     /* R22  - GPIOCTRL 2 */
+	{ 23,  0x0800 },     /* R23  - GPIO_POL */
+	{ 24,  0x008B },     /* R24  - Left Line Input 1&2 Volume */
+	{ 25,  0x008B },     /* R25  - Left Line Input 3&4 Volume */
+	{ 26,  0x008B },     /* R26  - Right Line Input 1&2 Volume */
+	{ 27,  0x008B },     /* R27  - Right Line Input 3&4 Volume */
+	{ 28,  0x006D },     /* R28  - Left Output Volume */
+	{ 29,  0x006D },     /* R29  - Right Output Volume */
+	{ 30,  0x0066 },     /* R30  - Line Outputs Volume */
+	{ 31,  0x0020 },     /* R31  - HPOUT2 Volume */
+	{ 32,  0x0079 },     /* R32  - Left OPGA Volume */
+	{ 33,  0x0079 },     /* R33  - Right OPGA Volume */
+	{ 34,  0x0003 },     /* R34  - SPKMIXL Attenuation */
+	{ 35,  0x0003 },     /* R35  - SPKMIXR Attenuation */
+	{ 36,  0x0011 },     /* R36  - SPKOUT Mixers */
+	{ 37,  0x0100 },     /* R37  - SPKOUT Boost */
+	{ 38,  0x0079 },     /* R38  - Speaker Volume Left */
+	{ 39,  0x0079 },     /* R39  - Speaker Volume Right */
+	{ 40,  0x0000 },     /* R40  - Input Mixer2 */
+	{ 41,  0x0000 },     /* R41  - Input Mixer3 */
+	{ 42,  0x0000 },     /* R42  - Input Mixer4 */
+	{ 43,  0x0000 },     /* R43  - Input Mixer5 */
+	{ 44,  0x0000 },     /* R44  - Input Mixer6 */
+	{ 45,  0x0000 },     /* R45  - Output Mixer1 */
+	{ 46,  0x0000 },     /* R46  - Output Mixer2 */
+	{ 47,  0x0000 },     /* R47  - Output Mixer3 */
+	{ 48,  0x0000 },     /* R48  - Output Mixer4 */
+	{ 49,  0x0000 },     /* R49  - Output Mixer5 */
+	{ 50,  0x0000 },     /* R50  - Output Mixer6 */
+	{ 51,  0x0000 },     /* R51  - HPOUT2 Mixer */
+	{ 52,  0x0000 },     /* R52  - Line Mixer1 */
+	{ 53,  0x0000 },     /* R53  - Line Mixer2 */
+	{ 54,  0x0000 },     /* R54  - Speaker Mixer */
+	{ 55,  0x0000 },     /* R55  - Additional Control */
+	{ 56,  0x0000 },     /* R56  - AntiPOP1 */
+	{ 57,  0x0000 },     /* R57  - AntiPOP2 */
+	{ 58,  0x0000 },     /* R58  - MICBIAS */
+	{ 60,  0x0000 },     /* R60  - FLL Control 1 */
+	{ 61,  0x0000 },     /* R61  - FLL Control 2 */
+	{ 62,  0x0000 },     /* R62  - FLL Control 3 */
+	{ 63,  0x2EE0 },     /* R63  - FLL Control 4 */
+	{ 64,  0x0002 },     /* R64  - FLL Control 5 */
+	{ 65,  0x2287 },     /* R65  - Clocking 3 */
+	{ 66,  0x025F },     /* R66  - Clocking 4 */
+	{ 67,  0x0000 },     /* R67  - MW Slave Control */
+	{ 69,  0x0002 },     /* R69  - Bus Control 1 */
+	{ 70,  0x0000 },     /* R70  - Write Sequencer 0 */
+	{ 71,  0x0000 },     /* R71  - Write Sequencer 1 */
+	{ 72,  0x0000 },     /* R72  - Write Sequencer 2 */
+	{ 73,  0x0000 },     /* R73  - Write Sequencer 3 */
+	{ 74,  0x0000 },     /* R74  - Write Sequencer 4 */
+	{ 75,  0x0000 },     /* R75  - Write Sequencer 5 */
+	{ 76,  0x1F25 },     /* R76  - Charge Pump 1 */
+	{ 81,  0x0000 },     /* R81  - Class W 0 */
+	{ 85,  0x054A },     /* R85  - DC Servo 1 */
+	{ 87,  0x0000 },     /* R87  - DC Servo 3 */
+	{ 96,  0x0100 },     /* R96  - Analogue HP 0 */
+	{ 98,  0x0000 },     /* R98  - EQ1 */
+	{ 99,  0x000C },     /* R99  - EQ2 */
+	{ 100, 0x000C },     /* R100 - EQ3 */
+	{ 101, 0x000C },     /* R101 - EQ4 */
+	{ 102, 0x000C },     /* R102 - EQ5 */
+	{ 103, 0x000C },     /* R103 - EQ6 */
+	{ 104, 0x0FCA },     /* R104 - EQ7 */
+	{ 105, 0x0400 },     /* R105 - EQ8 */
+	{ 106, 0x00D8 },     /* R106 - EQ9 */
+	{ 107, 0x1EB5 },     /* R107 - EQ10 */
+	{ 108, 0xF145 },     /* R108 - EQ11 */
+	{ 109, 0x0B75 },     /* R109 - EQ12 */
+	{ 110, 0x01C5 },     /* R110 - EQ13 */
+	{ 111, 0x1C58 },     /* R111 - EQ14 */
+	{ 112, 0xF373 },     /* R112 - EQ15 */
+	{ 113, 0x0A54 },     /* R113 - EQ16 */
+	{ 114, 0x0558 },     /* R114 - EQ17 */
+	{ 115, 0x168E },     /* R115 - EQ18 */
+	{ 116, 0xF829 },     /* R116 - EQ19 */
+	{ 117, 0x07AD },     /* R117 - EQ20 */
+	{ 118, 0x1103 },     /* R118 - EQ21 */
+	{ 119, 0x0564 },     /* R119 - EQ22 */
+	{ 120, 0x0559 },     /* R120 - EQ23 */
+	{ 121, 0x4000 },     /* R121 - EQ24 */
+	{ 122, 0x0000 },     /* R122 - Digital Pulls */
+	{ 123, 0x0F08 },     /* R123 - DRC Control 1 */
+	{ 124, 0x0000 },     /* R124 - DRC Control 2 */
+	{ 125, 0x0080 },     /* R125 - DRC Control 3 */
+	{ 126, 0x0000 },     /* R126 - DRC Control 4 */
 };
 
 static struct {
@@ -225,9 +205,11 @@
 
 struct wm8993_priv {
 	struct wm_hubs_data hubs_data;
+	struct device *dev;
+	struct regmap *regmap;
 	struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES];
 	struct wm8993_platform_data pdata;
-	enum snd_soc_control_type control_type;
+	struct completion fll_lock;
 	int master;
 	int sysclk_source;
 	int tdm_slots;
@@ -242,17 +224,137 @@
 	int fll_src;
 };
 
-static int wm8993_volatile(struct snd_soc_codec *codec, unsigned int reg)
+static bool wm8993_volatile(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
 	case WM8993_SOFTWARE_RESET:
+	case WM8993_GPIO_CTRL_1:
 	case WM8993_DC_SERVO_0:
 	case WM8993_DC_SERVO_READBACK_0:
 	case WM8993_DC_SERVO_READBACK_1:
 	case WM8993_DC_SERVO_READBACK_2:
-		return 1;
+		return true;
 	default:
-		return 0;
+		return false;
+	}
+}
+
+static bool wm8993_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8993_SOFTWARE_RESET:
+	case WM8993_POWER_MANAGEMENT_1:
+	case WM8993_POWER_MANAGEMENT_2:
+	case WM8993_POWER_MANAGEMENT_3:
+	case WM8993_AUDIO_INTERFACE_1:
+	case WM8993_AUDIO_INTERFACE_2:
+	case WM8993_CLOCKING_1:
+	case WM8993_CLOCKING_2:
+	case WM8993_AUDIO_INTERFACE_3:
+	case WM8993_AUDIO_INTERFACE_4:
+	case WM8993_DAC_CTRL:
+	case WM8993_LEFT_DAC_DIGITAL_VOLUME:
+	case WM8993_RIGHT_DAC_DIGITAL_VOLUME:
+	case WM8993_DIGITAL_SIDE_TONE:
+	case WM8993_ADC_CTRL:
+	case WM8993_LEFT_ADC_DIGITAL_VOLUME:
+	case WM8993_RIGHT_ADC_DIGITAL_VOLUME:
+	case WM8993_GPIO_CTRL_1:
+	case WM8993_GPIO1:
+	case WM8993_IRQ_DEBOUNCE:
+	case WM8993_GPIOCTRL_2:
+	case WM8993_GPIO_POL:
+	case WM8993_LEFT_LINE_INPUT_1_2_VOLUME:
+	case WM8993_LEFT_LINE_INPUT_3_4_VOLUME:
+	case WM8993_RIGHT_LINE_INPUT_1_2_VOLUME:
+	case WM8993_RIGHT_LINE_INPUT_3_4_VOLUME:
+	case WM8993_LEFT_OUTPUT_VOLUME:
+	case WM8993_RIGHT_OUTPUT_VOLUME:
+	case WM8993_LINE_OUTPUTS_VOLUME:
+	case WM8993_HPOUT2_VOLUME:
+	case WM8993_LEFT_OPGA_VOLUME:
+	case WM8993_RIGHT_OPGA_VOLUME:
+	case WM8993_SPKMIXL_ATTENUATION:
+	case WM8993_SPKMIXR_ATTENUATION:
+	case WM8993_SPKOUT_MIXERS:
+	case WM8993_SPKOUT_BOOST:
+	case WM8993_SPEAKER_VOLUME_LEFT:
+	case WM8993_SPEAKER_VOLUME_RIGHT:
+	case WM8993_INPUT_MIXER2:
+	case WM8993_INPUT_MIXER3:
+	case WM8993_INPUT_MIXER4:
+	case WM8993_INPUT_MIXER5:
+	case WM8993_INPUT_MIXER6:
+	case WM8993_OUTPUT_MIXER1:
+	case WM8993_OUTPUT_MIXER2:
+	case WM8993_OUTPUT_MIXER3:
+	case WM8993_OUTPUT_MIXER4:
+	case WM8993_OUTPUT_MIXER5:
+	case WM8993_OUTPUT_MIXER6:
+	case WM8993_HPOUT2_MIXER:
+	case WM8993_LINE_MIXER1:
+	case WM8993_LINE_MIXER2:
+	case WM8993_SPEAKER_MIXER:
+	case WM8993_ADDITIONAL_CONTROL:
+	case WM8993_ANTIPOP1:
+	case WM8993_ANTIPOP2:
+	case WM8993_MICBIAS:
+	case WM8993_FLL_CONTROL_1:
+	case WM8993_FLL_CONTROL_2:
+	case WM8993_FLL_CONTROL_3:
+	case WM8993_FLL_CONTROL_4:
+	case WM8993_FLL_CONTROL_5:
+	case WM8993_CLOCKING_3:
+	case WM8993_CLOCKING_4:
+	case WM8993_MW_SLAVE_CONTROL:
+	case WM8993_BUS_CONTROL_1:
+	case WM8993_WRITE_SEQUENCER_0:
+	case WM8993_WRITE_SEQUENCER_1:
+	case WM8993_WRITE_SEQUENCER_2:
+	case WM8993_WRITE_SEQUENCER_3:
+	case WM8993_WRITE_SEQUENCER_4:
+	case WM8993_WRITE_SEQUENCER_5:
+	case WM8993_CHARGE_PUMP_1:
+	case WM8993_CLASS_W_0:
+	case WM8993_DC_SERVO_0:
+	case WM8993_DC_SERVO_1:
+	case WM8993_DC_SERVO_3:
+	case WM8993_DC_SERVO_READBACK_0:
+	case WM8993_DC_SERVO_READBACK_1:
+	case WM8993_DC_SERVO_READBACK_2:
+	case WM8993_ANALOGUE_HP_0:
+	case WM8993_EQ1:
+	case WM8993_EQ2:
+	case WM8993_EQ3:
+	case WM8993_EQ4:
+	case WM8993_EQ5:
+	case WM8993_EQ6:
+	case WM8993_EQ7:
+	case WM8993_EQ8:
+	case WM8993_EQ9:
+	case WM8993_EQ10:
+	case WM8993_EQ11:
+	case WM8993_EQ12:
+	case WM8993_EQ13:
+	case WM8993_EQ14:
+	case WM8993_EQ15:
+	case WM8993_EQ16:
+	case WM8993_EQ17:
+	case WM8993_EQ18:
+	case WM8993_EQ19:
+	case WM8993_EQ20:
+	case WM8993_EQ21:
+	case WM8993_EQ22:
+	case WM8993_EQ23:
+	case WM8993_EQ24:
+	case WM8993_DIGITAL_PULLS:
+	case WM8993_DRC_CONTROL_1:
+	case WM8993_DRC_CONTROL_2:
+	case WM8993_DRC_CONTROL_3:
+	case WM8993_DRC_CONTROL_4:
+		return true;
+	default:
+		return false;
 	}
 }
 
@@ -369,8 +471,10 @@
 			  unsigned int Fref, unsigned int Fout)
 {
 	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *i2c = to_i2c_client(codec->dev);
 	u16 reg1, reg4, reg5;
 	struct _fll_div fll_div;
+	unsigned int timeout;
 	int ret;
 
 	/* Any change? */
@@ -441,14 +545,22 @@
 	reg5 |= fll_div.fll_clk_ref_div << WM8993_FLL_CLK_REF_DIV_SHIFT;
 	snd_soc_write(codec, WM8993_FLL_CONTROL_5, reg5);
 
+	/* If we've got an interrupt wired up make sure we get it */
+	if (i2c->irq)
+		timeout = msecs_to_jiffies(20);
+	else if (Fref < 1000000)
+		timeout = msecs_to_jiffies(3);
+	else
+		timeout = msecs_to_jiffies(1);
+
+	try_wait_for_completion(&wm8993->fll_lock);
+
 	/* Enable the FLL */
 	snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA);
 
-	/* Both overestimates */
-	if (Fref < 1000000)
-		msleep(3);
-	else
-		msleep(1);
+	timeout = wait_for_completion_timeout(&wm8993->fll_lock, timeout);
+	if (i2c->irq && !timeout)
+		dev_warn(codec->dev, "Timed out waiting for FLL\n");
 
 	dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
 
@@ -946,6 +1058,8 @@
 	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 
+	wm_hubs_set_bias_level(codec, level);
+
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
@@ -963,12 +1077,10 @@
 			if (ret != 0)
 				return ret;
 
-			snd_soc_cache_sync(codec);
+			regcache_cache_only(wm8993->regmap, false);
+			regcache_sync(wm8993->regmap);
 
-			/* Tune DC servo configuration */
-			snd_soc_write(codec, 0x44, 3);
-			snd_soc_write(codec, 0x56, 3);
-			snd_soc_write(codec, 0x44, 0);
+			wm_hubs_vmid_ena(codec);
 
 			/* Bring up VMID with fast soft start */
 			snd_soc_update_bits(codec, WM8993_ANTIPOP2,
@@ -1024,14 +1136,8 @@
 				    WM8993_VMID_RAMP_MASK |
 				    WM8993_BIAS_SRC, 0);
 
-#ifdef CONFIG_REGULATOR
-               /* Post 2.6.34 we will be able to get a callback when
-                * the regulators are disabled which we can use but
-		* for now just assume that the power will be cut if
-		* the regulator API is in use.
-		*/
-		codec->cache_sync = 1;
-#endif
+		regcache_cache_only(wm8993->regmap, true);
+		regcache_mark_dirty(wm8993->regmap);
 
 		regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies),
 				       wm8993->supplies);
@@ -1378,6 +1484,45 @@
 	return 0;
 }
 
+static irqreturn_t wm8993_irq(int irq, void *data)
+{
+	struct wm8993_priv *wm8993 = data;
+	int mask, val, ret;
+
+	ret = regmap_read(wm8993->regmap, WM8993_GPIO_CTRL_1, &val);
+	if (ret != 0) {
+		dev_err(wm8993->dev, "Failed to read interrupt status: %d\n",
+			ret);
+		return IRQ_NONE;
+	}
+
+	ret = regmap_read(wm8993->regmap, WM8993_GPIOCTRL_2, &mask);
+	if (ret != 0) {
+		dev_err(wm8993->dev, "Failed to read interrupt mask: %d\n",
+			ret);
+		return IRQ_NONE;
+	}
+
+	/* The IRQ pin status is visible in the register too */
+	val &= ~(mask | WM8993_IRQ);
+	if (!val)
+		return IRQ_NONE;
+
+	if (val & WM8993_TEMPOK_EINT)
+		dev_crit(wm8993->dev, "Thermal warning\n");
+
+	if (val & WM8993_FLL_LOCK_EINT) {
+		dev_dbg(wm8993->dev, "FLL locked\n");
+		complete(&wm8993->fll_lock);
+	}
+
+	ret = regmap_write(wm8993->regmap, WM8993_GPIO_CTRL_1, val);
+	if (ret != 0)
+		dev_err(wm8993->dev, "Failed to ack interrupt: %d\n", ret);
+
+	return IRQ_HANDLED;
+}
+
 static const struct snd_soc_dai_ops wm8993_ops = {
 	.set_sysclk = wm8993_set_sysclk,
 	.set_fmt = wm8993_set_dai_fmt,
@@ -1402,6 +1547,7 @@
 		.channels_max = 2,
 		.rates = WM8993_RATES,
 		.formats = WM8993_FORMATS,
+		.sig_bits = 24,
 	},
 	.capture = {
 		 .stream_name = "Capture",
@@ -1409,6 +1555,7 @@
 		 .channels_max = 2,
 		 .rates = WM8993_RATES,
 		 .formats = WM8993_FORMATS,
+		 .sig_bits = 24,
 	 },
 	.ops = &wm8993_ops,
 	.symmetric_rates = 1,
@@ -1418,49 +1565,20 @@
 {
 	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
-	int ret, i, val;
+	int ret;
 
 	wm8993->hubs_data.hp_startup_mode = 1;
 	wm8993->hubs_data.dcs_codes_l = -2;
 	wm8993->hubs_data.dcs_codes_r = -2;
 	wm8993->hubs_data.series_startup = 1;
 
-	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+	codec->control_data = wm8993->regmap;
+	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
 	if (ret != 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++)
-		wm8993->supplies[i].supply = wm8993_supply_names[i];
-
-	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8993->supplies),
-				 wm8993->supplies);
-	if (ret != 0) {
-		dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-		return ret;
-	}
-
-	ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
-				    wm8993->supplies);
-	if (ret != 0) {
-		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-		goto err_get;
-	}
-
-	val = snd_soc_read(codec, WM8993_SOFTWARE_RESET);
-	if (val != wm8993_reg_defaults[WM8993_SOFTWARE_RESET]) {
-		dev_err(codec->dev, "Invalid ID register value %x\n", val);
-		ret = -EINVAL;
-		goto err_enable;
-	}
-
-	ret = snd_soc_write(codec, WM8993_SOFTWARE_RESET, 0xffff);
-	if (ret != 0)
-		goto err_enable;
-
-	codec->cache_only = 1;
-
 	/* By default we're using the output mixers */
 	wm8993->class_w_users = 2;
 
@@ -1489,15 +1607,15 @@
 
 	ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	if (ret != 0)
-		goto err_enable;
+		return ret;
 
-	snd_soc_add_controls(codec, wm8993_snd_controls,
+	snd_soc_add_codec_controls(codec, wm8993_snd_controls,
 			     ARRAY_SIZE(wm8993_snd_controls));
 	if (wm8993->pdata.num_retune_configs != 0) {
 		dev_dbg(codec->dev, "Using ReTune Mobile\n");
 	} else {
 		dev_dbg(codec->dev, "No ReTune Mobile, using normal EQ\n");
-		snd_soc_add_controls(codec, wm8993_eq_controls,
+		snd_soc_add_codec_controls(codec, wm8993_eq_controls,
 				     ARRAY_SIZE(wm8993_eq_controls));
 	}
 
@@ -1509,13 +1627,14 @@
 	wm_hubs_add_analogue_routes(codec, wm8993->pdata.lineout1_diff,
 				    wm8993->pdata.lineout2_diff);
 
+	/* If the line outputs are differential then we aren't presenting
+	 * VMID as an output and can disable it.
+	 */
+	if (wm8993->pdata.lineout1_diff && wm8993->pdata.lineout2_diff)
+		codec->dapm.idle_bias_off = 1;
+
 	return 0;
 
-err_enable:
-	regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
-err_get:
-	regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
-	return ret;
 }
 
 static int wm8993_remove(struct snd_soc_codec *codec)
@@ -1578,41 +1697,149 @@
 #define wm8993_resume NULL
 #endif
 
+/* Tune DC servo configuration */
+static struct reg_default wm8993_regmap_patch[] = {
+	{ 0x44, 3 },
+	{ 0x56, 3 },
+	{ 0x44, 0 },
+};
+
+static const struct regmap_config wm8993_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = WM8993_MAX_REGISTER,
+	.volatile_reg = wm8993_volatile,
+	.readable_reg = wm8993_readable,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8993_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8993_reg_defaults),
+};
+
 static struct snd_soc_codec_driver soc_codec_dev_wm8993 = {
 	.probe = 	wm8993_probe,
 	.remove = 	wm8993_remove,
 	.suspend =	wm8993_suspend,
 	.resume =	wm8993_resume,
 	.set_bias_level = wm8993_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(wm8993_reg_defaults),
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = wm8993_reg_defaults,
-	.volatile_register = wm8993_volatile,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8993_i2c_probe(struct i2c_client *i2c,
 				      const struct i2c_device_id *id)
 {
 	struct wm8993_priv *wm8993;
-	int ret;
+	unsigned int reg;
+	int ret, i;
 
 	wm8993 = devm_kzalloc(&i2c->dev, sizeof(struct wm8993_priv),
 			      GFP_KERNEL);
 	if (wm8993 == NULL)
 		return -ENOMEM;
 
+	wm8993->dev = &i2c->dev;
+	init_completion(&wm8993->fll_lock);
+
+	wm8993->regmap = regmap_init_i2c(i2c, &wm8993_regmap);
+	if (IS_ERR(wm8993->regmap)) {
+		ret = PTR_ERR(wm8993->regmap);
+		dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
 	i2c_set_clientdata(i2c, wm8993);
 
+	for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++)
+		wm8993->supplies[i].supply = wm8993_supply_names[i];
+
+	ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8993->supplies),
+				 wm8993->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		goto err;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
+				    wm8993->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		goto err_get;
+	}
+
+	ret = regmap_read(wm8993->regmap, WM8993_SOFTWARE_RESET, &reg);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret);
+		goto err_enable;
+	}
+
+	if (reg != 0x8993) {
+		dev_err(&i2c->dev, "Invalid ID register value %x\n", reg);
+		ret = -EINVAL;
+		goto err_enable;
+	}
+
+	ret = regmap_write(wm8993->regmap, WM8993_SOFTWARE_RESET, 0xffff);
+	if (ret != 0)
+		goto err_enable;
+
+	ret = regmap_register_patch(wm8993->regmap, wm8993_regmap_patch,
+				    ARRAY_SIZE(wm8993_regmap_patch));
+	if (ret != 0)
+		dev_warn(wm8993->dev, "Failed to apply regmap patch: %d\n",
+			 ret);
+
+	if (i2c->irq) {
+		/* Put GPIO1 into interrupt mode (only GPIO1 can output IRQ) */
+		ret = regmap_update_bits(wm8993->regmap, WM8993_GPIO1,
+					 WM8993_GPIO1_PD |
+					 WM8993_GPIO1_SEL_MASK, 7);
+		if (ret != 0)
+			goto err_enable;
+
+		ret = request_threaded_irq(i2c->irq, NULL, wm8993_irq,
+					   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+					   "wm8993", wm8993);
+		if (ret != 0)
+			goto err_enable;
+
+	}
+
+	regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
+
+	regcache_cache_only(wm8993->regmap, true);
+
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_wm8993, &wm8993_dai, 1);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+		goto err_irq;
+	}
+
+	return 0;
+
+err_irq:
+	if (i2c->irq)
+		free_irq(i2c->irq, wm8993);
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
+err_get:
+	regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
+err:
+	regmap_exit(wm8993->regmap);
 	return ret;
 }
 
-static __devexit int wm8993_i2c_remove(struct i2c_client *client)
+static __devexit int wm8993_i2c_remove(struct i2c_client *i2c)
 {
-	snd_soc_unregister_codec(&client->dev);
-	kfree(i2c_get_clientdata(client));
+	struct wm8993_priv *wm8993 = i2c_get_clientdata(i2c);
+
+	snd_soc_unregister_codec(&i2c->dev);
+	if (i2c->irq)
+		free_irq(i2c->irq, wm8993);
+	regmap_exit(wm8993->regmap);
+	regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
+	regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
+
 	return 0;
 }
 
@@ -1631,30 +1858,8 @@
 	.remove =   __devexit_p(wm8993_i2c_remove),
 	.id_table = wm8993_i2c_id,
 };
-#endif
 
-static int __init wm8993_modinit(void)
-{
-	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	ret = i2c_add_driver(&wm8993_i2c_driver);
-	if (ret != 0) {
-		pr_err("WM8993: Unable to register I2C driver: %d\n",
-		       ret);
-	}
-#endif
-	return ret;
-}
-module_init(wm8993_modinit);
-
-static void __exit wm8993_exit(void)
-{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	i2c_del_driver(&wm8993_i2c_driver);
-#endif
-}
-module_exit(wm8993_exit);
-
+module_i2c_driver(wm8993_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8993 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/sound/soc/codecs/wm8993.h b/sound/soc/codecs/wm8993.h
index 2184617..4478b40 100644
--- a/sound/soc/codecs/wm8993.h
+++ b/sound/soc/codecs/wm8993.h
@@ -31,6 +31,7 @@
 #define WM8993_GPIO_CTRL_1                      0x12
 #define WM8993_GPIO1                            0x13
 #define WM8993_IRQ_DEBOUNCE                     0x14
+#define WM8993_INPUTS_CLAMP_REG			0x15
 #define WM8993_GPIOCTRL_2                       0x16
 #define WM8993_GPIO_POL                         0x17
 #define WM8993_LEFT_LINE_INPUT_1_2_VOLUME       0x18
@@ -656,6 +657,14 @@
 #define WM8993_GPIO1_DB_WIDTH                        1  /* GPIO1_DB */
 
 /*
+ * R21 (0x15) - Inputs Clamp
+ */
+#define WM8993_INPUTS_CLAMP                     0x0040  /* INPUTS_CLAMP */
+#define WM8993_INPUTS_CLAMP_MASK                0x0040  /* INPUTS_CLAMP */
+#define WM8993_INPUTS_CLAMP_SHIFT                    7  /* INPUTS_CLAMP */
+#define WM8993_INPUTS_CLAMP_WIDTH                    1  /* INPUTS_CLAMP */
+
+/*
  * R22 (0x16) - GPIOCTRL 2
  */
 #define WM8993_IM_JD2_EINT                      0x2000  /* IM_JD2_EINT */
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index ec69a6c..7c49642 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -686,14 +686,23 @@
 {
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
+	if (!wm8994->jackdet || !wm8994->jack_cb)
+		return;
+
 	if (wm8994->active_refcount)
 		mode = WM1811_JACKDET_MODE_AUDIO;
 
+	if (mode == wm8994->jackdet_mode)
+		return;
+
+	wm8994->jackdet_mode = mode;
+
+	/* Always use audio mode to detect while the system is active */
+	if (mode != WM1811_JACKDET_MODE_NONE)
+		mode = WM1811_JACKDET_MODE_AUDIO;
+
 	snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
 			    WM1811_JACKDET_MODE_MASK, mode);
-
-	if (mode == WM1811_JACKDET_MODE_MIC)
-		msleep(2);
 }
 
 static void active_reference(struct snd_soc_codec *codec)
@@ -707,15 +716,8 @@
 	dev_dbg(codec->dev, "Active refcount incremented, now %d\n",
 		wm8994->active_refcount);
 
-	if (wm8994->active_refcount == 1) {
-		/* If we're using jack detection go into audio mode */
-		if (wm8994->jackdet && wm8994->jack_cb) {
-			snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
-					    WM1811_JACKDET_MODE_MASK,
-					    WM1811_JACKDET_MODE_AUDIO);
-			msleep(2);
-		}
-	}
+	/* If we're using jack detection go into audio mode */
+	wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_AUDIO);
 
 	mutex_unlock(&wm8994->accdet_lock);
 }
@@ -734,16 +736,12 @@
 
 	if (wm8994->active_refcount == 0) {
 		/* Go into appropriate detection only mode */
-		if (wm8994->jackdet && wm8994->jack_cb) {
-			if (wm8994->jack_mic || wm8994->mic_detecting)
-				mode = WM1811_JACKDET_MODE_MIC;
-			else
-				mode = WM1811_JACKDET_MODE_JACK;
+		if (wm8994->jack_mic || wm8994->mic_detecting)
+			mode = WM1811_JACKDET_MODE_MIC;
+		else
+			mode = WM1811_JACKDET_MODE_JACK;
 
-			snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
-					    WM1811_JACKDET_MODE_MASK,
-					    mode);
-		}
+		wm1811_jackdet_set_mode(codec, mode);
 	}
 
 	mutex_unlock(&wm8994->accdet_lock);
@@ -778,27 +776,69 @@
 		wm8994->vmid_refcount);
 
 	if (wm8994->vmid_refcount == 1) {
-		/* Startup bias, VMID ramp & buffer */
-		snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
-				    WM8994_STARTUP_BIAS_ENA |
-				    WM8994_VMID_BUF_ENA |
-				    WM8994_VMID_RAMP_MASK,
-				    WM8994_STARTUP_BIAS_ENA |
-				    WM8994_VMID_BUF_ENA |
-				    (0x3 << WM8994_VMID_RAMP_SHIFT));
-
-		/* Remove discharge for line out */
 		snd_soc_update_bits(codec, WM8994_ANTIPOP_1,
 				    WM8994_LINEOUT1_DISCH |
 				    WM8994_LINEOUT2_DISCH, 0);
 
-		/* Main bias enable, VMID=2x40k */
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
-				    WM8994_BIAS_ENA |
-				    WM8994_VMID_SEL_MASK,
-				    WM8994_BIAS_ENA | 0x2);
+		wm_hubs_vmid_ena(codec);
 
-		msleep(20);
+		switch (wm8994->vmid_mode) {
+		default:
+			WARN_ON(0 == "Invalid VMID mode");
+		case WM8994_VMID_NORMAL:
+			/* Startup bias, VMID ramp & buffer */
+			snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+					    WM8994_BIAS_SRC |
+					    WM8994_VMID_DISCH |
+					    WM8994_STARTUP_BIAS_ENA |
+					    WM8994_VMID_BUF_ENA |
+					    WM8994_VMID_RAMP_MASK,
+					    WM8994_BIAS_SRC |
+					    WM8994_STARTUP_BIAS_ENA |
+					    WM8994_VMID_BUF_ENA |
+					    (0x3 << WM8994_VMID_RAMP_SHIFT));
+
+			/* Main bias enable, VMID=2x40k */
+			snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
+					    WM8994_BIAS_ENA |
+					    WM8994_VMID_SEL_MASK,
+					    WM8994_BIAS_ENA | 0x2);
+
+			msleep(50);
+
+			snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+					    WM8994_VMID_RAMP_MASK |
+					    WM8994_BIAS_SRC,
+					    0);
+			break;
+
+		case WM8994_VMID_FORCE:
+			/* Startup bias, slow VMID ramp & buffer */
+			snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+					    WM8994_BIAS_SRC |
+					    WM8994_VMID_DISCH |
+					    WM8994_STARTUP_BIAS_ENA |
+					    WM8994_VMID_BUF_ENA |
+					    WM8994_VMID_RAMP_MASK,
+					    WM8994_BIAS_SRC |
+					    WM8994_STARTUP_BIAS_ENA |
+					    WM8994_VMID_BUF_ENA |
+					    (0x2 << WM8994_VMID_RAMP_SHIFT));
+
+			/* Main bias enable, VMID=2x40k */
+			snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
+					    WM8994_BIAS_ENA |
+					    WM8994_VMID_SEL_MASK,
+					    WM8994_BIAS_ENA | 0x2);
+
+			msleep(400);
+
+			snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+					    WM8994_VMID_RAMP_MASK |
+					    WM8994_BIAS_SRC,
+					    0);
+			break;
+		}
 	}
 }
 
@@ -812,30 +852,55 @@
 		wm8994->vmid_refcount);
 
 	if (wm8994->vmid_refcount == 0) {
-		/* Switch over to startup biases */
+		if (wm8994->hubs.lineout1_se)
+			snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3,
+					    WM8994_LINEOUT1N_ENA |
+					    WM8994_LINEOUT1P_ENA,
+					    WM8994_LINEOUT1N_ENA |
+					    WM8994_LINEOUT1P_ENA);
+
+		if (wm8994->hubs.lineout2_se)
+			snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3,
+					    WM8994_LINEOUT2N_ENA |
+					    WM8994_LINEOUT2P_ENA,
+					    WM8994_LINEOUT2N_ENA |
+					    WM8994_LINEOUT2P_ENA);
+
+		/* Start discharging VMID */
 		snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
 				    WM8994_BIAS_SRC |
-				    WM8994_STARTUP_BIAS_ENA |
-				    WM8994_VMID_BUF_ENA |
-				    WM8994_VMID_RAMP_MASK,
+				    WM8994_VMID_DISCH,
 				    WM8994_BIAS_SRC |
-				    WM8994_STARTUP_BIAS_ENA |
-				    WM8994_VMID_BUF_ENA |
-				    (1 << WM8994_VMID_RAMP_SHIFT));
+				    WM8994_VMID_DISCH);
 
-		/* Disable main biases */
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
-				    WM8994_BIAS_ENA |
-				    WM8994_VMID_SEL_MASK, 0);
+		switch (wm8994->vmid_mode) {
+		case WM8994_VMID_FORCE:
+			msleep(350);
+			break;
+		default:
+			break;
+		}
 
-		/* Discharge line */
+		snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL,
+				    WM8994_VROI, WM8994_VROI);
+
+		/* Active discharge */
 		snd_soc_update_bits(codec, WM8994_ANTIPOP_1,
 				    WM8994_LINEOUT1_DISCH |
 				    WM8994_LINEOUT2_DISCH,
 				    WM8994_LINEOUT1_DISCH |
 				    WM8994_LINEOUT2_DISCH);
 
-		msleep(5);
+		msleep(150);
+
+		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3,
+				    WM8994_LINEOUT1N_ENA |
+				    WM8994_LINEOUT1P_ENA |
+				    WM8994_LINEOUT2N_ENA |
+				    WM8994_LINEOUT2P_ENA, 0);
+
+		snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL,
+				    WM8994_VROI, 0);
 
 		/* Switch off startup biases */
 		snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
@@ -843,6 +908,12 @@
 				    WM8994_STARTUP_BIAS_ENA |
 				    WM8994_VMID_BUF_ENA |
 				    WM8994_VMID_RAMP_MASK, 0);
+
+		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
+				    WM8994_BIAS_ENA | WM8994_VMID_SEL_MASK, 0);
+
+		snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+				    WM8994_VMID_RAMP_MASK, 0);
 	}
 
 	pm_runtime_put(codec->dev);
@@ -1459,17 +1530,17 @@
 		      WM8994_POWER_MANAGEMENT_5, 12, 0, wm8958_aif_ev,
 		      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 
-SND_SOC_DAPM_AIF_IN("AIF1DACDAT", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
-SND_SOC_DAPM_AIF_IN("AIF2DACDAT", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1ADCDAT", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
-SND_SOC_DAPM_AIF_OUT("AIF2ADCDAT", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIF1DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIF2DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1ADCDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2ADCDAT",  NULL, 0, SND_SOC_NOPM, 0, 0),
 
 SND_SOC_DAPM_MUX("AIF1DAC Mux", SND_SOC_NOPM, 0, 0, &aif1dac_mux),
 SND_SOC_DAPM_MUX("AIF2DAC Mux", SND_SOC_NOPM, 0, 0, &aif2dac_mux),
 SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux),
 
-SND_SOC_DAPM_AIF_IN("AIF3DACDAT", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0),
-SND_SOC_DAPM_AIF_OUT("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIF3DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIF3ADCDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
 
 SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0),
 
@@ -1584,6 +1655,14 @@
 
 	{ "TOCLK", NULL, "CLK_SYS" },
 
+	{ "AIF1DACDAT", NULL, "AIF1 Playback" },
+	{ "AIF2DACDAT", NULL, "AIF2 Playback" },
+	{ "AIF3DACDAT", NULL, "AIF3 Playback" },
+
+	{ "AIF1 Capture", NULL, "AIF1ADCDAT" },
+	{ "AIF2 Capture", NULL, "AIF2ADCDAT" },
+	{ "AIF3 Capture", NULL, "AIF3ADCDAT" },
+
 	/* AIF1 outputs */
 	{ "AIF1ADC1L", NULL, "AIF1ADC1L Mixer" },
 	{ "AIF1ADC1L Mixer", "ADC/DMIC Switch", "ADCL Mux" },
@@ -1896,7 +1975,8 @@
 			    WM8994_FLL1_OUTDIV_MASK |
 			    WM8994_FLL1_FRATIO_MASK, reg);
 
-	snd_soc_write(codec, WM8994_FLL1_CONTROL_3 + reg_offset, fll.k);
+	snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_3 + reg_offset,
+			    WM8994_FLL1_K_MASK, fll.k);
 
 	snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_4 + reg_offset,
 			    WM8994_FLL1_N_MASK,
@@ -2074,6 +2154,8 @@
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 	struct wm8994 *control = wm8994->wm8994;
 
+	wm_hubs_set_bias_level(codec, level);
+
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		break;
@@ -2099,26 +2181,9 @@
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
 			switch (control->type) {
-			case WM8994:
-				if (wm8994->revision < 4) {
-					/* Tweak DC servo and DSP
-					 * configuration for improved
-					 * performance. */
-					snd_soc_write(codec, 0x102, 0x3);
-					snd_soc_write(codec, 0x56, 0x3);
-					snd_soc_write(codec, 0x817, 0);
-					snd_soc_write(codec, 0x102, 0);
-				}
-				break;
-
 			case WM8958:
 				if (wm8994->revision == 0) {
 					/* Optimise performance for rev A */
-					snd_soc_write(codec, 0x102, 0x3);
-					snd_soc_write(codec, 0xcb, 0x81);
-					snd_soc_write(codec, 0x817, 0);
-					snd_soc_write(codec, 0x102, 0);
-
 					snd_soc_update_bits(codec,
 							    WM8958_CHARGE_PUMP_2,
 							    WM8958_CP_DISCH,
@@ -2126,13 +2191,7 @@
 				}
 				break;
 
-			case WM1811:
-				if (wm8994->revision < 2) {
-					snd_soc_write(codec, 0x102, 0x3);
-					snd_soc_write(codec, 0x5d, 0x7e);
-					snd_soc_write(codec, 0x5e, 0x0);
-					snd_soc_write(codec, 0x102, 0x0);
-				}
+			default:
 				break;
 			}
 
@@ -2168,11 +2227,61 @@
 			wm8994->cur_fw = NULL;
 		break;
 	}
+
 	codec->dapm.bias_level = level;
 
 	return 0;
 }
 
+int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	switch (mode) {
+	case WM8994_VMID_NORMAL:
+		if (wm8994->hubs.lineout1_se) {
+			snd_soc_dapm_disable_pin(&codec->dapm,
+						 "LINEOUT1N Driver");
+			snd_soc_dapm_disable_pin(&codec->dapm,
+						 "LINEOUT1P Driver");
+		}
+		if (wm8994->hubs.lineout2_se) {
+			snd_soc_dapm_disable_pin(&codec->dapm,
+						 "LINEOUT2N Driver");
+			snd_soc_dapm_disable_pin(&codec->dapm,
+						 "LINEOUT2P Driver");
+		}
+
+		/* Do the sync with the old mode to allow it to clean up */
+		snd_soc_dapm_sync(&codec->dapm);
+		wm8994->vmid_mode = mode;
+		break;
+
+	case WM8994_VMID_FORCE:
+		if (wm8994->hubs.lineout1_se) {
+			snd_soc_dapm_force_enable_pin(&codec->dapm,
+						      "LINEOUT1N Driver");
+			snd_soc_dapm_force_enable_pin(&codec->dapm,
+						      "LINEOUT1P Driver");
+		}
+		if (wm8994->hubs.lineout2_se) {
+			snd_soc_dapm_force_enable_pin(&codec->dapm,
+						      "LINEOUT2N Driver");
+			snd_soc_dapm_force_enable_pin(&codec->dapm,
+						      "LINEOUT2P Driver");
+		}
+
+		wm8994->vmid_mode = mode;
+		snd_soc_dapm_sync(&codec->dapm);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct snd_soc_codec *codec = dai->codec;
@@ -2654,6 +2763,7 @@
 			.channels_max = 2,
 			.rates = WM8994_RATES,
 			.formats = WM8994_FORMATS,
+			.sig_bits = 24,
 		},
 		.capture = {
 			.stream_name = "AIF1 Capture",
@@ -2661,6 +2771,7 @@
 			.channels_max = 2,
 			.rates = WM8994_RATES,
 			.formats = WM8994_FORMATS,
+			.sig_bits = 24,
 		 },
 		.ops = &wm8994_aif1_dai_ops,
 	},
@@ -2673,6 +2784,7 @@
 			.channels_max = 2,
 			.rates = WM8994_RATES,
 			.formats = WM8994_FORMATS,
+			.sig_bits = 24,
 		},
 		.capture = {
 			.stream_name = "AIF2 Capture",
@@ -2680,6 +2792,7 @@
 			.channels_max = 2,
 			.rates = WM8994_RATES,
 			.formats = WM8994_FORMATS,
+			.sig_bits = 24,
 		},
 		.probe = wm8994_aif2_probe,
 		.ops = &wm8994_aif2_dai_ops,
@@ -2693,6 +2806,7 @@
 			.channels_max = 2,
 			.rates = WM8994_RATES,
 			.formats = WM8994_FORMATS,
+			.sig_bits = 24,
 		},
 		.capture = {
 			.stream_name = "AIF3 Capture",
@@ -2700,13 +2814,14 @@
 			.channels_max = 2,
 			.rates = WM8994_RATES,
 			.formats = WM8994_FORMATS,
-		},
+			.sig_bits = 24,
+		 },
 		.ops = &wm8994_aif3_dai_ops,
 	}
 };
 
 #ifdef CONFIG_PM
-static int wm8994_suspend(struct snd_soc_codec *codec)
+static int wm8994_codec_suspend(struct snd_soc_codec *codec)
 {
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 	struct wm8994 *control = wm8994->wm8994;
@@ -2740,7 +2855,7 @@
 	return 0;
 }
 
-static int wm8994_resume(struct snd_soc_codec *codec)
+static int wm8994_codec_resume(struct snd_soc_codec *codec)
 {
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 	struct wm8994 *control = wm8994->wm8994;
@@ -2762,8 +2877,6 @@
 		codec->cache_only = 0;
 	}
 
-	wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
 		if (!wm8994->fll_suspend[i].out)
 			continue;
@@ -2791,6 +2904,7 @@
 					    WM1811_JACKDET_MODE_JACK);
 			break;
 		}
+		break;
 	case WM8958:
 		if (wm8994->jack_cb)
 			snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
@@ -2801,8 +2915,8 @@
 	return 0;
 }
 #else
-#define wm8994_suspend NULL
-#define wm8994_resume NULL
+#define wm8994_codec_suspend NULL
+#define wm8994_codec_resume NULL
 #endif
 
 static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
@@ -2865,7 +2979,7 @@
 	wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts;
 	wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts;
 
-	ret = snd_soc_add_controls(wm8994->codec, controls,
+	ret = snd_soc_add_codec_controls(wm8994->codec, controls,
 				   ARRAY_SIZE(controls));
 	if (ret != 0)
 		dev_err(wm8994->codec->dev,
@@ -2918,7 +3032,7 @@
 		wm8994->drc_enum.max = pdata->num_drc_cfgs;
 		wm8994->drc_enum.texts = wm8994->drc_texts;
 
-		ret = snd_soc_add_controls(wm8994->codec, controls,
+		ret = snd_soc_add_codec_controls(wm8994->codec, controls,
 					   ARRAY_SIZE(controls));
 		if (ret != 0)
 			dev_err(wm8994->codec->dev,
@@ -2934,7 +3048,7 @@
 	if (pdata->num_retune_mobile_cfgs)
 		wm8994_handle_retune_mobile_pdata(wm8994);
 	else
-		snd_soc_add_controls(wm8994->codec, wm8994_eq_controls,
+		snd_soc_add_codec_controls(wm8994->codec, wm8994_eq_controls,
 				     ARRAY_SIZE(wm8994_eq_controls));
 
 	for (i = 0; i < ARRAY_SIZE(pdata->micbias); i++) {
@@ -2951,8 +3065,6 @@
  * @codec:   WM8994 codec
  * @jack:    jack to report detection events on
  * @micbias: microphone bias to detect on
- * @det:     value to report for presence detection
- * @shrt:    value to report for short detection
  *
  * Enable microphone detection via IRQ on the WM8994.  If GPIOs are
  * being used to bring out signals to the processor then only platform
@@ -2963,43 +3075,63 @@
  * and micbias2_lvl platform data members.
  */
 int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
-		      int micbias, int det, int shrt)
+		      int micbias)
 {
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 	struct wm8994_micdet *micdet;
 	struct wm8994 *control = wm8994->wm8994;
-	int reg;
+	int reg, ret;
 
-	if (control->type != WM8994)
+	if (control->type != WM8994) {
+		dev_warn(codec->dev, "Not a WM8994\n");
 		return -EINVAL;
+	}
 
 	switch (micbias) {
 	case 1:
 		micdet = &wm8994->micdet[0];
+		if (jack)
+			ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
+							    "MICBIAS1");
+		else
+			ret = snd_soc_dapm_disable_pin(&codec->dapm,
+						       "MICBIAS1");
 		break;
 	case 2:
 		micdet = &wm8994->micdet[1];
+		if (jack)
+			ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
+							    "MICBIAS1");
+		else
+			ret = snd_soc_dapm_disable_pin(&codec->dapm,
+						       "MICBIAS1");
 		break;
 	default:
+		dev_warn(codec->dev, "Invalid MICBIAS %d\n", micbias);
 		return -EINVAL;
-	}	
+	}
 
-	dev_dbg(codec->dev, "Configuring microphone detection on %d: %x %x\n",
-		micbias, det, shrt);
+	if (ret != 0)
+		dev_warn(codec->dev, "Failed to configure MICBIAS%d: %d\n",
+			 micbias, ret);
+
+	dev_dbg(codec->dev, "Configuring microphone detection on %d %p\n",
+		micbias, jack);
 
 	/* Store the configuration */
 	micdet->jack = jack;
-	micdet->det = det;
-	micdet->shrt = shrt;
+	micdet->detecting = true;
 
 	/* If either of the jacks is set up then enable detection */
 	if (wm8994->micdet[0].jack || wm8994->micdet[1].jack)
 		reg = WM8994_MICD_ENA;
-	else 
+	else
 		reg = 0;
 
 	snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, reg);
 
+	snd_soc_dapm_sync(&codec->dapm);
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(wm8994_mic_detect);
@@ -3025,20 +3157,42 @@
 	dev_dbg(codec->dev, "Microphone status: %x\n", reg);
 
 	report = 0;
-	if (reg & WM8994_MIC1_DET_STS)
-		report |= priv->micdet[0].det;
-	if (reg & WM8994_MIC1_SHRT_STS)
-		report |= priv->micdet[0].shrt;
+	if (reg & WM8994_MIC1_DET_STS) {
+		if (priv->micdet[0].detecting)
+			report = SND_JACK_HEADSET;
+	}
+	if (reg & WM8994_MIC1_SHRT_STS) {
+		if (priv->micdet[0].detecting)
+			report = SND_JACK_HEADPHONE;
+		else
+			report |= SND_JACK_BTN_0;
+	}
+	if (report)
+		priv->micdet[0].detecting = false;
+	else
+		priv->micdet[0].detecting = true;
+
 	snd_soc_jack_report(priv->micdet[0].jack, report,
-			    priv->micdet[0].det | priv->micdet[0].shrt);
+			    SND_JACK_HEADSET | SND_JACK_BTN_0);
 
 	report = 0;
-	if (reg & WM8994_MIC2_DET_STS)
-		report |= priv->micdet[1].det;
-	if (reg & WM8994_MIC2_SHRT_STS)
-		report |= priv->micdet[1].shrt;
+	if (reg & WM8994_MIC2_DET_STS) {
+		if (priv->micdet[1].detecting)
+			report = SND_JACK_HEADSET;
+	}
+	if (reg & WM8994_MIC2_SHRT_STS) {
+		if (priv->micdet[1].detecting)
+			report = SND_JACK_HEADPHONE;
+		else
+			report |= SND_JACK_BTN_0;
+	}
+	if (report)
+		priv->micdet[1].detecting = false;
+	else
+		priv->micdet[1].detecting = true;
+
 	snd_soc_jack_report(priv->micdet[1].jack, report,
-			    priv->micdet[1].det | priv->micdet[1].shrt);
+			    SND_JACK_HEADSET | SND_JACK_BTN_0);
 
 	return IRQ_HANDLED;
 }
@@ -3087,7 +3241,7 @@
 	}
 
 
-	if (wm8994->mic_detecting && status & 0x4) {
+	if (wm8994->mic_detecting && status & 0xfc) {
 		dev_dbg(codec->dev, "Detected headphone\n");
 		wm8994->mic_detecting = false;
 
@@ -3098,11 +3252,23 @@
 
 		/* If we have jackdet that will detect removal */
 		if (wm8994->jackdet) {
+			mutex_lock(&wm8994->accdet_lock);
+
 			snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
 					    WM8958_MICD_ENA, 0);
 
 			wm1811_jackdet_set_mode(codec,
 						WM1811_JACKDET_MODE_JACK);
+
+			mutex_unlock(&wm8994->accdet_lock);
+
+			if (wm8994->pdata->jd_ext_cap) {
+				mutex_lock(&codec->mutex);
+				snd_soc_dapm_disable_pin(&codec->dapm,
+							 "MICBIAS2");
+				snd_soc_dapm_sync(&codec->dapm);
+				mutex_unlock(&codec->mutex);
+			}
 		}
 	}
 
@@ -3137,6 +3303,7 @@
 	struct wm8994_priv *wm8994 = data;
 	struct snd_soc_codec *codec = wm8994->codec;
 	int reg;
+	bool present;
 
 	mutex_lock(&wm8994->accdet_lock);
 
@@ -3149,11 +3316,17 @@
 
 	dev_dbg(codec->dev, "JACKDET %x\n", reg);
 
-	if (reg & WM1811_JACKDET_LVL) {
+	present = reg & WM1811_JACKDET_LVL;
+
+	if (present) {
 		dev_dbg(codec->dev, "Jack detected\n");
 
-		snd_soc_jack_report(wm8994->micdet[0].jack,
-				    SND_JACK_MECHANICAL, SND_JACK_MECHANICAL);
+		snd_soc_update_bits(codec, WM8958_MICBIAS2,
+				    WM8958_MICB2_DISCH, 0);
+
+		/* Disable debounce while inserted */
+		snd_soc_update_bits(codec, WM1811_JACKDET_CTRL,
+				    WM1811_JACKDET_DB, 0);
 
 		/*
 		 * Start off measument of microphone impedence to find
@@ -3161,14 +3334,18 @@
 		 */
 		wm8994->mic_detecting = true;
 		wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_MIC);
+
 		snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
 				    WM8958_MICD_ENA, WM8958_MICD_ENA);
 	} else {
 		dev_dbg(codec->dev, "Jack not detected\n");
 
-		snd_soc_jack_report(wm8994->micdet[0].jack, 0,
-				    SND_JACK_MECHANICAL | SND_JACK_HEADSET |
-				    wm8994->btn_mask);
+		snd_soc_update_bits(codec, WM8958_MICBIAS2,
+				    WM8958_MICB2_DISCH, WM8958_MICB2_DISCH);
+
+		/* Enable debounce while removed */
+		snd_soc_update_bits(codec, WM1811_JACKDET_CTRL,
+				    WM1811_JACKDET_DB, WM1811_JACKDET_DB);
 
 		wm8994->mic_detecting = false;
 		wm8994->jack_mic = false;
@@ -3179,6 +3356,28 @@
 
 	mutex_unlock(&wm8994->accdet_lock);
 
+	/* If required for an external cap force MICBIAS on */
+	if (wm8994->pdata->jd_ext_cap) {
+		mutex_lock(&codec->mutex);
+
+		if (present)
+			snd_soc_dapm_force_enable_pin(&codec->dapm,
+						      "MICBIAS2");
+		else
+			snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2");
+
+		snd_soc_dapm_sync(&codec->dapm);
+		mutex_unlock(&codec->mutex);
+	}
+
+	if (present)
+		snd_soc_jack_report(wm8994->micdet[0].jack,
+				    SND_JACK_MECHANICAL, SND_JACK_MECHANICAL);
+	else
+		snd_soc_jack_report(wm8994->micdet[0].jack, 0,
+				    SND_JACK_MECHANICAL | SND_JACK_HEADSET |
+				    wm8994->btn_mask);
+
 	return IRQ_HANDLED;
 }
 
@@ -3221,6 +3420,7 @@
 		}
 
 		snd_soc_dapm_force_enable_pin(&codec->dapm, "CLK_SYS");
+		snd_soc_dapm_sync(&codec->dapm);
 
 		wm8994->micdet[0].jack = jack;
 		wm8994->jack_cb = cb;
@@ -3251,6 +3451,9 @@
 		 * otherwise jump straight to microphone detection.
 		 */
 		if (wm8994->jackdet) {
+			snd_soc_update_bits(codec, WM8958_MICBIAS2,
+					    WM8958_MICB2_DISCH,
+					    WM8958_MICB2_DISCH);
 			snd_soc_update_bits(codec, WM8994_LDO_1,
 					    WM8994_LDO1_DISCH, 0);
 			wm1811_jackdet_set_mode(codec,
@@ -3263,7 +3466,9 @@
 	} else {
 		snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
 				    WM8958_MICD_ENA, 0);
+		wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_NONE);
 		snd_soc_dapm_disable_pin(&codec->dapm, "CLK_SYS");
+		snd_soc_dapm_sync(&codec->dapm);
 	}
 
 	return 0;
@@ -3276,17 +3481,13 @@
 	struct snd_soc_codec *codec = wm8994->codec;
 	int reg, count;
 
-	mutex_lock(&wm8994->accdet_lock);
-
 	/*
 	 * Jack detection may have detected a removal simulataneously
 	 * with an update of the MICDET status; if so it will have
 	 * stopped detection and we can ignore this interrupt.
 	 */
-	if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA)) {
-		mutex_unlock(&wm8994->accdet_lock);
+	if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA))
 		return IRQ_HANDLED;
-	}
 
 	/* We may occasionally read a detection without an impedence
 	 * range being provided - if that happens loop again.
@@ -3295,7 +3496,6 @@
 	do {
 		reg = snd_soc_read(codec, WM8958_MIC_DETECT_3);
 		if (reg < 0) {
-			mutex_unlock(&wm8994->accdet_lock);
 			dev_err(codec->dev,
 				"Failed to read mic detect status: %d\n",
 				reg);
@@ -3326,8 +3526,6 @@
 		dev_warn(codec->dev, "Accessory detection with no callback\n");
 
 out:
-	mutex_unlock(&wm8994->accdet_lock);
-
 	return IRQ_HANDLED;
 }
 
@@ -3361,23 +3559,16 @@
 static int wm8994_codec_probe(struct snd_soc_codec *codec)
 {
 	struct wm8994 *control = dev_get_drvdata(codec->dev->parent);
-	struct wm8994_priv *wm8994;
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	unsigned int reg;
 	int ret, i;
 
+	wm8994->codec = codec;
 	codec->control_data = control->regmap;
 
-	wm8994 = devm_kzalloc(codec->dev, sizeof(struct wm8994_priv),
-			      GFP_KERNEL);
-	if (wm8994 == NULL)
-		return -ENOMEM;
-	snd_soc_codec_set_drvdata(codec, wm8994);
-
 	snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
 
-	wm8994->wm8994 = dev_get_drvdata(codec->dev->parent);
-	wm8994->pdata = dev_get_platdata(codec->dev->parent);
 	wm8994->codec = codec;
 
 	mutex_init(&wm8994->accdet_lock);
@@ -3392,12 +3583,20 @@
 				     WM8994_IRQ_MIC1_DET;
 
 	pm_runtime_enable(codec->dev);
-	pm_runtime_resume(codec->dev);
+	pm_runtime_idle(codec->dev);
+
+	/* By default use idle_bias_off, will override for WM8994 */
+	codec->dapm.idle_bias_off = 1;
 
 	/* Set revision-specific configuration */
 	wm8994->revision = snd_soc_read(codec, WM8994_CHIP_REVISION);
 	switch (control->type) {
 	case WM8994:
+		/* Single ended line outputs should have VMID on. */
+		if (!wm8994->pdata->lineout1_diff ||
+		    !wm8994->pdata->lineout2_diff)
+			codec->dapm.idle_bias_off = 0;
+
 		switch (wm8994->revision) {
 		case 2:
 		case 3:
@@ -3415,11 +3614,14 @@
 
 	case WM8958:
 		wm8994->hubs.dcs_readback_mode = 1;
+		wm8994->hubs.hp_startup_mode = 1;
 		break;
 
 	case WM1811:
 		wm8994->hubs.dcs_readback_mode = 2;
 		wm8994->hubs.no_series_update = 1;
+		wm8994->hubs.hp_startup_mode = 1;
+		wm8994->hubs.no_cache_class_w = true;
 
 		switch (wm8994->revision) {
 		case 0:
@@ -3427,7 +3629,7 @@
 		case 2:
 		case 3:
 			wm8994->hubs.dcs_codes_l = -9;
-			wm8994->hubs.dcs_codes_r = -5;
+			wm8994->hubs.dcs_codes_r = -7;
 			break;
 		default:
 			break;
@@ -3536,6 +3738,9 @@
 			wm8994->fll_locked_irq = false;
 	}
 
+	/* Make sure we can read from the GPIOs if they're inputs */
+	pm_runtime_get_sync(codec->dev);
+
 	/* Remember if AIFnLRCLK is configured as a GPIO.  This should be
 	 * configured on init - if a system wants to do this dynamically
 	 * at runtime we can deal with that then.
@@ -3564,7 +3769,7 @@
 		wm8994->lrclk_shared[1] = 0;
 	}
 
-	wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	pm_runtime_put(codec->dev);
 
 	/* Latch volume updates (right only; we always do left then right). */
 	snd_soc_update_bits(codec, WM8994_AIF1_DAC1_LEFT_VOLUME,
@@ -3642,7 +3847,7 @@
 	wm8994_handle_pdata(wm8994);
 
 	wm_hubs_add_analogue_controls(codec);
-	snd_soc_add_controls(codec, wm8994_snd_controls,
+	snd_soc_add_codec_controls(codec, wm8994_snd_controls,
 			     ARRAY_SIZE(wm8994_snd_controls));
 	snd_soc_dapm_new_controls(dapm, wm8994_dapm_widgets,
 				  ARRAY_SIZE(wm8994_dapm_widgets));
@@ -3668,7 +3873,7 @@
 		}
 		break;
 	case WM8958:
-		snd_soc_add_controls(codec, wm8958_snd_controls,
+		snd_soc_add_codec_controls(codec, wm8958_snd_controls,
 				     ARRAY_SIZE(wm8958_snd_controls));
 		snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
 					  ARRAY_SIZE(wm8958_dapm_widgets));
@@ -3690,7 +3895,7 @@
 		break;
 
 	case WM1811:
-		snd_soc_add_controls(codec, wm8958_snd_controls,
+		snd_soc_add_codec_controls(codec, wm8958_snd_controls,
 				     ARRAY_SIZE(wm8958_snd_controls));
 		snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
 					  ARRAY_SIZE(wm8958_dapm_widgets));
@@ -3819,24 +4024,27 @@
 	return 0;
 }
 
-static int wm8994_soc_volatile(struct snd_soc_codec *codec,
-			       unsigned int reg)
-{
-	return true;
-}
-
 static struct snd_soc_codec_driver soc_codec_dev_wm8994 = {
 	.probe =	wm8994_codec_probe,
 	.remove =	wm8994_codec_remove,
-	.suspend =	wm8994_suspend,
-	.resume =	wm8994_resume,
+	.suspend =	wm8994_codec_suspend,
+	.resume =	wm8994_codec_resume,
 	.set_bias_level = wm8994_set_bias_level,
-	.reg_cache_size	= WM8994_MAX_REGISTER,
-	.volatile_register = wm8994_soc_volatile,
 };
 
 static int __devinit wm8994_probe(struct platform_device *pdev)
 {
+	struct wm8994_priv *wm8994;
+
+	wm8994 = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_priv),
+			      GFP_KERNEL);
+	if (wm8994 == NULL)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, wm8994);
+
+	wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent);
+	wm8994->pdata = dev_get_platdata(pdev->dev.parent);
+
 	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994,
 			wm8994_dai, ARRAY_SIZE(wm8994_dai));
 }
@@ -3847,11 +4055,43 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int wm8994_suspend(struct device *dev)
+{
+	struct wm8994_priv *wm8994 = dev_get_drvdata(dev);
+
+	/* Drop down to power saving mode when system is suspended */
+	if (wm8994->jackdet && !wm8994->active_refcount)
+		regmap_update_bits(wm8994->wm8994->regmap, WM8994_ANTIPOP_2,
+				   WM1811_JACKDET_MODE_MASK,
+				   wm8994->jackdet_mode);
+
+	return 0;
+}
+
+static int wm8994_resume(struct device *dev)
+{
+	struct wm8994_priv *wm8994 = dev_get_drvdata(dev);
+
+	if (wm8994->jackdet && wm8994->jack_cb)
+		regmap_update_bits(wm8994->wm8994->regmap, WM8994_ANTIPOP_2,
+				   WM1811_JACKDET_MODE_MASK,
+				   WM1811_JACKDET_MODE_AUDIO);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops wm8994_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(wm8994_suspend, wm8994_resume)
+};
+
 static struct platform_driver wm8994_codec_driver = {
 	.driver = {
-		   .name = "wm8994-codec",
-		   .owner = THIS_MODULE,
-		   },
+		.name = "wm8994-codec",
+		.owner = THIS_MODULE,
+		.pm = &wm8994_pm_ops,
+	},
 	.probe = wm8994_probe,
 	.remove = __devexit_p(wm8994_remove),
 };
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index c3a4247..c724112 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -32,13 +32,20 @@
 #define WM8994_FLL_SRC_LRCLK  3
 #define WM8994_FLL_SRC_BCLK   4
 
+enum wm8994_vmid_mode {
+	WM8994_VMID_NORMAL,
+	WM8994_VMID_FORCE,
+};
+
 typedef void (*wm8958_micdet_cb)(u16 status, void *data);
 
 int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
-		      int micbias, int det, int shrt);
+		      int micbias);
 int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 		      wm8958_micdet_cb cb, void *cb_data);
 
+int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode);
+
 int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
 		  struct snd_kcontrol *kcontrol, int event);
 
@@ -46,8 +53,7 @@
 
 struct wm8994_micdet {
 	struct snd_soc_jack *jack;
-	int det;
-	int shrt;
+	bool detecting;
 };
 
 /* codec private data */
@@ -76,6 +82,7 @@
 
 	int vmid_refcount;
 	int active_refcount;
+	enum wm8994_vmid_mode vmid_mode;
 
 	int dac_rates[2];
 	int lrclk_shared[2];
@@ -123,6 +130,7 @@
 	bool jack_mic;
 	int btn_mask;
 	bool jackdet;
+	int jackdet_mode;
 
 	wm8958_micdet_cb jack_cb;
 	void *jack_cb_data;
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index c8aada5..28c89b0 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -2047,7 +2047,6 @@
 	int i;
 	int ret;
 
-	codec->dapm.idle_bias_off = 1;
 	wm8995 = snd_soc_codec_get_drvdata(codec);
 	wm8995->codec = codec;
 
@@ -2137,7 +2136,7 @@
 
 	wm8995_update_class_w(codec);
 
-	snd_soc_add_controls(codec, wm8995_snd_controls,
+	snd_soc_add_codec_controls(codec, wm8995_snd_controls,
 			     ARRAY_SIZE(wm8995_snd_controls));
 	snd_soc_dapm_new_controls(&codec->dapm, wm8995_dapm_widgets,
 				  ARRAY_SIZE(wm8995_dapm_widgets));
@@ -2241,6 +2240,7 @@
 	.suspend = wm8995_suspend,
 	.resume = wm8995_resume,
 	.set_bias_level = wm8995_set_bias_level,
+	.idle_bias_off = true,
 };
 
 static struct regmap_config wm8995_regmap = {
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index 61f7daa..1fd6354 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -73,7 +73,6 @@
 
 	struct regulator_bulk_data supplies[WM8996_NUM_SUPPLIES];
 	struct notifier_block disable_nb[WM8996_NUM_SUPPLIES];
-	struct regulator *cpvdd;
 	int bg_ena;
 
 	struct wm8996_pdata pdata;
@@ -90,6 +89,7 @@
 	struct snd_soc_jack *jack;
 	bool detecting;
 	bool jack_mic;
+	int jack_flips;
 	wm8996_polarity_fn polarity_cb;
 
 #ifdef CONFIG_GPIOLIB
@@ -118,7 +118,6 @@
 WM8996_REGULATOR_EVENT(2)
 
 static struct reg_default wm8996_reg[] = {
-	{ WM8996_SOFTWARE_RESET, 0x8996 },
 	{ WM8996_POWER_MANAGEMENT_1, 0x0 },
 	{ WM8996_POWER_MANAGEMENT_2, 0x0 },
 	{ WM8996_POWER_MANAGEMENT_3, 0x0 },
@@ -153,7 +152,6 @@
 	{ WM8996_CHARGE_PUMP_1, 0x1f25 },
 	{ WM8996_CHARGE_PUMP_2, 0xab19 },
 	{ WM8996_DC_SERVO_1, 0x0 },
-	{ WM8996_DC_SERVO_2, 0x0 },
 	{ WM8996_DC_SERVO_3, 0x0 },
 	{ WM8996_DC_SERVO_5, 0x2a2a },
 	{ WM8996_DC_SERVO_6, 0x0 },
@@ -716,10 +714,16 @@
 SOC_SINGLE("DSP1 DRC TXL Switch", WM8996_DSP1_DRC_1, 0, 1, 0),
 SOC_SINGLE("DSP1 DRC TXR Switch", WM8996_DSP1_DRC_1, 1, 1, 0),
 SOC_SINGLE("DSP1 DRC RX Switch", WM8996_DSP1_DRC_1, 2, 1, 0),
+SND_SOC_BYTES_MASK("DSP1 DRC", WM8996_DSP1_DRC_1, 5,
+		   WM8996_DSP1RX_DRC_ENA | WM8996_DSP1TXL_DRC_ENA |
+		   WM8996_DSP1TXR_DRC_ENA),
 
 SOC_SINGLE("DSP2 DRC TXL Switch", WM8996_DSP2_DRC_1, 0, 1, 0),
 SOC_SINGLE("DSP2 DRC TXR Switch", WM8996_DSP2_DRC_1, 1, 1, 0),
 SOC_SINGLE("DSP2 DRC RX Switch", WM8996_DSP2_DRC_1, 2, 1, 0),
+SND_SOC_BYTES_MASK("DSP2 DRC", WM8996_DSP2_DRC_1, 5,
+		   WM8996_DSP2RX_DRC_ENA | WM8996_DSP2TXL_DRC_ENA |
+		   WM8996_DSP2TXR_DRC_ENA),
 };
 
 static const struct snd_kcontrol_new wm8996_eq_controls[] = {
@@ -792,29 +796,18 @@
 static int cp_event(struct snd_soc_dapm_widget *w,
 		    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = w->codec;
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
 	int ret = 0;
 
 	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		ret = regulator_enable(wm8996->cpvdd);
-		if (ret != 0)
-			dev_err(codec->dev, "Failed to enable CPVDD: %d\n",
-				ret);
-		break;
 	case SND_SOC_DAPM_POST_PMU:
 		msleep(5);
 		break;
-	case SND_SOC_DAPM_POST_PMD:
-		regulator_disable_deferred(wm8996->cpvdd, 20);
-		break;
 	default:
 		BUG();
 		ret = -EINVAL;
 	}
 
-	return ret;
+	return 0;
 }
 
 static int rmv_short_event(struct snd_soc_dapm_widget *w,
@@ -897,8 +890,8 @@
 		val = 0;
 		mask = 0;
 		if (wm8996->hpout_pending & HPOUT1L) {
-			val |= WM8996_HPOUT1L_RMV_SHORT;
-			mask |= WM8996_HPOUT1L_RMV_SHORT;
+			val |= WM8996_HPOUT1L_RMV_SHORT | WM8996_HPOUT1L_OUTP;
+			mask |= WM8996_HPOUT1L_RMV_SHORT | WM8996_HPOUT1L_OUTP;
 		} else {
 			mask |= WM8996_HPOUT1L_RMV_SHORT |
 				WM8996_HPOUT1L_OUTP |
@@ -906,8 +899,8 @@
 		}
 
 		if (wm8996->hpout_pending & HPOUT1R) {
-			val |= WM8996_HPOUT1R_RMV_SHORT;
-			mask |= WM8996_HPOUT1R_RMV_SHORT;
+			val |= WM8996_HPOUT1R_RMV_SHORT | WM8996_HPOUT1R_OUTP;
+			mask |= WM8996_HPOUT1R_RMV_SHORT | WM8996_HPOUT1R_OUTP;
 		} else {
 			mask |= WM8996_HPOUT1R_RMV_SHORT |
 				WM8996_HPOUT1R_OUTP |
@@ -919,8 +912,8 @@
 		val = 0;
 		mask = 0;
 		if (wm8996->hpout_pending & HPOUT2L) {
-			val |= WM8996_HPOUT2L_RMV_SHORT;
-			mask |= WM8996_HPOUT2L_RMV_SHORT;
+			val |= WM8996_HPOUT2L_RMV_SHORT | WM8996_HPOUT2L_OUTP;
+			mask |= WM8996_HPOUT2L_RMV_SHORT | WM8996_HPOUT2L_OUTP;
 		} else {
 			mask |= WM8996_HPOUT2L_RMV_SHORT |
 				WM8996_HPOUT2L_OUTP |
@@ -928,8 +921,8 @@
 		}
 
 		if (wm8996->hpout_pending & HPOUT2R) {
-			val |= WM8996_HPOUT2R_RMV_SHORT;
-			mask |= WM8996_HPOUT2R_RMV_SHORT;
+			val |= WM8996_HPOUT2R_RMV_SHORT | WM8996_HPOUT2R_OUTP;
+			mask |= WM8996_HPOUT2R_RMV_SHORT | WM8996_HPOUT2R_OUTP;
 		} else {
 			mask |= WM8996_HPOUT2R_RMV_SHORT |
 				WM8996_HPOUT2R_OUTP |
@@ -1116,12 +1109,12 @@
 SND_SOC_DAPM_INPUT("DMIC1DAT"),
 SND_SOC_DAPM_INPUT("DMIC2DAT"),
 
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20),
 SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8996_AIF_CLOCKING_1, 0, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8996_CLOCKING_1, 1, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8996_CLOCKING_1, 2, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY_S("Charge Pump", 2, WM8996_CHARGE_PUMP_1, 15, 0, cp_event,
-		      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		      SND_SOC_DAPM_POST_PMD),
+		      SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_SUPPLY("Bandgap", SND_SOC_NOPM, 0, 0, bg_event,
 		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 SND_SOC_DAPM_SUPPLY("LDO2", WM8996_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
@@ -1180,41 +1173,25 @@
 SND_SOC_DAPM_DAC("DAC1L", NULL, WM8996_POWER_MANAGEMENT_5, 1, 0),
 SND_SOC_DAPM_DAC("DAC1R", NULL, WM8996_POWER_MANAGEMENT_5, 0, 0),
 
-SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 0,
-		    WM8996_POWER_MANAGEMENT_4, 9, 0),
-SND_SOC_DAPM_AIF_IN("AIF2RX0", "AIF2 Playback", 1,
-		    WM8996_POWER_MANAGEMENT_4, 8, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, WM8996_POWER_MANAGEMENT_4, 9, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX0", NULL, 1, WM8996_POWER_MANAGEMENT_4, 8, 0),
 
-SND_SOC_DAPM_AIF_OUT("AIF2TX1", "AIF2 Capture", 0,
-		    WM8996_POWER_MANAGEMENT_6, 9, 0),
-SND_SOC_DAPM_AIF_OUT("AIF2TX0", "AIF2 Capture", 1,
-		    WM8996_POWER_MANAGEMENT_6, 8, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, WM8996_POWER_MANAGEMENT_6, 9, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX0", NULL, 1, WM8996_POWER_MANAGEMENT_6, 8, 0),
 
-SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 5,
-		    WM8996_POWER_MANAGEMENT_4, 5, 0),
-SND_SOC_DAPM_AIF_IN("AIF1RX4", "AIF1 Playback", 4,
-		    WM8996_POWER_MANAGEMENT_4, 4, 0),
-SND_SOC_DAPM_AIF_IN("AIF1RX3", "AIF1 Playback", 3,
-		    WM8996_POWER_MANAGEMENT_4, 3, 0),
-SND_SOC_DAPM_AIF_IN("AIF1RX2", "AIF1 Playback", 2,
-		    WM8996_POWER_MANAGEMENT_4, 2, 0),
-SND_SOC_DAPM_AIF_IN("AIF1RX1", "AIF1 Playback", 1,
-		    WM8996_POWER_MANAGEMENT_4, 1, 0),
-SND_SOC_DAPM_AIF_IN("AIF1RX0", "AIF1 Playback", 0,
-		    WM8996_POWER_MANAGEMENT_4, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 5, WM8996_POWER_MANAGEMENT_4, 5, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 4, WM8996_POWER_MANAGEMENT_4, 4, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 3, WM8996_POWER_MANAGEMENT_4, 3, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 2, WM8996_POWER_MANAGEMENT_4, 2, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 1, WM8996_POWER_MANAGEMENT_4, 1, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX0", NULL, 0, WM8996_POWER_MANAGEMENT_4, 0, 0),
 
-SND_SOC_DAPM_AIF_OUT("AIF1TX5", "AIF1 Capture", 5,
-		     WM8996_POWER_MANAGEMENT_6, 5, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1TX4", "AIF1 Capture", 4,
-		     WM8996_POWER_MANAGEMENT_6, 4, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1TX3", "AIF1 Capture", 3,
-		     WM8996_POWER_MANAGEMENT_6, 3, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1TX2", "AIF1 Capture", 2,
-		     WM8996_POWER_MANAGEMENT_6, 2, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1TX1", "AIF1 Capture", 1,
-		     WM8996_POWER_MANAGEMENT_6, 1, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1TX0", "AIF1 Capture", 0,
-		     WM8996_POWER_MANAGEMENT_6, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 5, WM8996_POWER_MANAGEMENT_6, 5, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 4, WM8996_POWER_MANAGEMENT_6, 4, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 3, WM8996_POWER_MANAGEMENT_6, 3, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 2, WM8996_POWER_MANAGEMENT_6, 2, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 1, WM8996_POWER_MANAGEMENT_6, 1, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX0", NULL, 0, WM8996_POWER_MANAGEMENT_6, 0, 0),
 
 /* We route as stereo pairs so define some dummy widgets to squash
  * things down for now.  RXA = 0,1, RXB = 2,3 and so on */
@@ -1237,7 +1214,6 @@
 SND_SOC_DAPM_PGA_S("HPOUT2L_DLY", 1, WM8996_ANALOGUE_HP_2, 5, 0, NULL, 0),
 SND_SOC_DAPM_PGA_S("HPOUT2L_DCS", 2, WM8996_DC_SERVO_1, 2, 0, dcs_start,
 		   SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_S("HPOUT2L_OUTP", 3, WM8996_ANALOGUE_HP_2, 6, 0, NULL, 0),
 SND_SOC_DAPM_PGA_S("HPOUT2L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2L, 0,
 		   rmv_short_event,
 		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -1246,7 +1222,6 @@
 SND_SOC_DAPM_PGA_S("HPOUT2R_DLY", 1, WM8996_ANALOGUE_HP_2, 1, 0, NULL, 0),
 SND_SOC_DAPM_PGA_S("HPOUT2R_DCS", 2, WM8996_DC_SERVO_1, 3, 0, dcs_start,
 		   SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_S("HPOUT2R_OUTP", 3, WM8996_ANALOGUE_HP_2, 2, 0, NULL, 0),
 SND_SOC_DAPM_PGA_S("HPOUT2R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2R, 0,
 		   rmv_short_event,
 		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -1255,7 +1230,6 @@
 SND_SOC_DAPM_PGA_S("HPOUT1L_DLY", 1, WM8996_ANALOGUE_HP_1, 5, 0, NULL, 0),
 SND_SOC_DAPM_PGA_S("HPOUT1L_DCS", 2, WM8996_DC_SERVO_1, 0, 0, dcs_start,
 		   SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_S("HPOUT1L_OUTP", 3, WM8996_ANALOGUE_HP_1, 6, 0, NULL, 0),
 SND_SOC_DAPM_PGA_S("HPOUT1L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1L, 0,
 		   rmv_short_event,
 		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -1264,7 +1238,6 @@
 SND_SOC_DAPM_PGA_S("HPOUT1R_DLY", 1, WM8996_ANALOGUE_HP_1, 1, 0, NULL, 0),
 SND_SOC_DAPM_PGA_S("HPOUT1R_DCS", 2, WM8996_DC_SERVO_1, 1, 0, dcs_start,
 		   SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_S("HPOUT1R_OUTP", 3, WM8996_ANALOGUE_HP_1, 2, 0, NULL, 0),
 SND_SOC_DAPM_PGA_S("HPOUT1R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1R, 0,
 		   rmv_short_event,
 		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -1280,6 +1253,7 @@
 	{ "AIFCLK", NULL, "SYSCLK" },
 	{ "SYSDSPCLK", NULL, "SYSCLK" },
 	{ "Charge Pump", NULL, "SYSCLK" },
+	{ "Charge Pump", NULL, "CPVDD" },
 
 	{ "MICB1", NULL, "LDO2" },
 	{ "MICB1", NULL, "MICB1 Audio" },
@@ -1288,6 +1262,26 @@
 	{ "MICB2", NULL, "MICB2 Audio" },
 	{ "MICB2", NULL, "Bandgap" },
 
+	{ "AIF1RX0", NULL, "AIF1 Playback" },
+	{ "AIF1RX1", NULL, "AIF1 Playback" },
+	{ "AIF1RX2", NULL, "AIF1 Playback" },
+	{ "AIF1RX3", NULL, "AIF1 Playback" },
+	{ "AIF1RX4", NULL, "AIF1 Playback" },
+	{ "AIF1RX5", NULL, "AIF1 Playback" },
+
+	{ "AIF2RX0", NULL, "AIF2 Playback" },
+	{ "AIF2RX1", NULL, "AIF2 Playback" },
+
+	{ "AIF1 Capture", NULL, "AIF1TX0" },
+	{ "AIF1 Capture", NULL, "AIF1TX1" },
+	{ "AIF1 Capture", NULL, "AIF1TX2" },
+	{ "AIF1 Capture", NULL, "AIF1TX3" },
+	{ "AIF1 Capture", NULL, "AIF1TX4" },
+	{ "AIF1 Capture", NULL, "AIF1TX5" },
+
+	{ "AIF2 Capture", NULL, "AIF2TX0" },
+	{ "AIF2 Capture", NULL, "AIF2TX1" },
+
 	{ "IN1L PGA", NULL, "IN2LN" },
 	{ "IN1L PGA", NULL, "IN2LP" },
 	{ "IN1L PGA", NULL, "IN1LN" },
@@ -1436,32 +1430,28 @@
 	{ "HPOUT2L PGA", NULL, "DAC2L" },
 	{ "HPOUT2L_DLY", NULL, "HPOUT2L PGA" },
 	{ "HPOUT2L_DCS", NULL, "HPOUT2L_DLY" },
-	{ "HPOUT2L_OUTP", NULL, "HPOUT2L_DCS" },
-	{ "HPOUT2L_RMV_SHORT", NULL, "HPOUT2L_OUTP" },
+	{ "HPOUT2L_RMV_SHORT", NULL, "HPOUT2L_DCS" },
 
 	{ "HPOUT2R PGA", NULL, "Charge Pump" },
 	{ "HPOUT2R PGA", NULL, "Bandgap" },
 	{ "HPOUT2R PGA", NULL, "DAC2R" },
 	{ "HPOUT2R_DLY", NULL, "HPOUT2R PGA" },
 	{ "HPOUT2R_DCS", NULL, "HPOUT2R_DLY" },
-	{ "HPOUT2R_OUTP", NULL, "HPOUT2R_DCS" },
-	{ "HPOUT2R_RMV_SHORT", NULL, "HPOUT2R_OUTP" },
+	{ "HPOUT2R_RMV_SHORT", NULL, "HPOUT2R_DCS" },
 
 	{ "HPOUT1L PGA", NULL, "Charge Pump" },
 	{ "HPOUT1L PGA", NULL, "Bandgap" },
 	{ "HPOUT1L PGA", NULL, "DAC1L" },
 	{ "HPOUT1L_DLY", NULL, "HPOUT1L PGA" },
 	{ "HPOUT1L_DCS", NULL, "HPOUT1L_DLY" },
-	{ "HPOUT1L_OUTP", NULL, "HPOUT1L_DCS" },
-	{ "HPOUT1L_RMV_SHORT", NULL, "HPOUT1L_OUTP" },
+	{ "HPOUT1L_RMV_SHORT", NULL, "HPOUT1L_DCS" },
 
 	{ "HPOUT1R PGA", NULL, "Charge Pump" },
 	{ "HPOUT1R PGA", NULL, "Bandgap" },
 	{ "HPOUT1R PGA", NULL, "DAC1R" },
 	{ "HPOUT1R_DLY", NULL, "HPOUT1R PGA" },
 	{ "HPOUT1R_DCS", NULL, "HPOUT1R_DLY" },
-	{ "HPOUT1R_OUTP", NULL, "HPOUT1R_DCS" },
-	{ "HPOUT1R_RMV_SHORT", NULL, "HPOUT1R_OUTP" },
+	{ "HPOUT1R_RMV_SHORT", NULL, "HPOUT1R_DCS" },
 
 	{ "HPOUT2L", NULL, "HPOUT2L_RMV_SHORT" },
 	{ "HPOUT2R", NULL, "HPOUT2R_RMV_SHORT" },
@@ -1720,6 +1710,7 @@
 {
 	if (wm8996->pdata.ldo_ena > 0) {
 		gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+		gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 1);
 		return 0;
 	} else {
 		return regmap_write(wm8996->regmap, WM8996_SOFTWARE_RESET,
@@ -1923,7 +1914,7 @@
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
-	int bits, i, bclk_rate;
+	int bits, i, bclk_rate, best;
 	int aifdata = 0;
 	int lrclk = 0;
 	int dsp = 0;
@@ -1972,14 +1963,11 @@
 		return bits;
 	aifdata |= (bits << WM8996_AIF1TX_WL_SHIFT) | bits;
 
+	best = 0;
 	for (i = 0; i < ARRAY_SIZE(dsp_divs); i++) {
-		if (dsp_divs[i] == params_rate(params))
-			break;
-	}
-	if (i == ARRAY_SIZE(dsp_divs)) {
-		dev_err(codec->dev, "Unsupported sample rate %dHz\n",
-			params_rate(params));
-		return -EINVAL;
+		if (abs(dsp_divs[i] - params_rate(params)) <
+		    abs(dsp_divs[best] - params_rate(params)))
+			best = i;
 	}
 	dsp |= i << dsp_shift;
 
@@ -2039,13 +2027,16 @@
 	}
 
 	switch (wm8996->sysclk) {
+	case 5644800:
 	case 6144000:
 		snd_soc_update_bits(codec, WM8996_AIF_RATE,
 				    WM8996_SYSCLK_RATE, 0);
 		break;
+	case 22579200:
 	case 24576000:
 		ratediv = WM8996_SYSCLK_DIV;
 		wm8996->sysclk /= 2;
+	case 11289600:
 	case 12288000:
 		snd_soc_update_bits(codec, WM8996_AIF_RATE,
 				    WM8996_SYSCLK_RATE, WM8996_SYSCLK_RATE);
@@ -2438,6 +2429,7 @@
 	wm8996->jack = jack;
 	wm8996->detecting = true;
 	wm8996->polarity_cb = polarity_cb;
+	wm8996->jack_flips = 0;
 
 	if (wm8996->polarity_cb)
 		wm8996->polarity_cb(codec, 0);
@@ -2553,6 +2545,19 @@
 			    WM8996_HP_POLL, WM8996_HP_POLL);
 }
 
+static void wm8996_report_headphone(struct snd_soc_codec *codec)
+{
+	dev_dbg(codec->dev, "Headphone detected\n");
+	wm8996_hpdet_start(codec);
+
+	/* Increase the detection rate a bit for responsiveness. */
+	snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+			    WM8996_MICD_RATE_MASK |
+			    WM8996_MICD_BIAS_STARTTIME_MASK,
+			    7 << WM8996_MICD_RATE_SHIFT |
+			    7 << WM8996_MICD_BIAS_STARTTIME_SHIFT);
+}
+
 static void wm8996_micd(struct snd_soc_codec *codec)
 {
 	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
@@ -2572,6 +2577,7 @@
 		dev_dbg(codec->dev, "Jack removal detected\n");
 		wm8996->jack_mic = false;
 		wm8996->detecting = true;
+		wm8996->jack_flips = 0;
 		snd_soc_jack_report(wm8996->jack, 0,
 				    SND_JACK_LINEOUT | SND_JACK_HEADSET |
 				    SND_JACK_BTN_0);
@@ -2612,9 +2618,17 @@
 	/* If we detected a lower impedence during initial startup
 	 * then we probably have the wrong polarity, flip it.  Don't
 	 * do this for the lowest impedences to speed up detection of
-	 * plain headphones.
+	 * plain headphones.  If both polarities report a low
+	 * impedence then give up and report headphones.
 	 */
 	if (wm8996->detecting && (val & 0x3f0)) {
+		wm8996->jack_flips++;
+
+		if (wm8996->jack_flips > 1) {
+			wm8996_report_headphone(codec);
+			return;
+		}
+
 		reg = snd_soc_read(codec, WM8996_ACCESSORY_DETECT_MODE_2);
 		reg ^= WM8996_HPOUT1FB_SRC | WM8996_MICD_SRC |
 			WM8996_MICD_BIAS_SRC;
@@ -2641,17 +2655,7 @@
 			snd_soc_jack_report(wm8996->jack, SND_JACK_BTN_0,
 					    SND_JACK_BTN_0);
 		} else if (wm8996->detecting) {
-			dev_dbg(codec->dev, "Headphone detected\n");
-			wm8996_hpdet_start(codec);
-
-			/* Increase the detection rate a bit for
-			 * responsiveness.
-			 */
-			snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
-					    WM8996_MICD_RATE_MASK |
-					    WM8996_MICD_BIAS_STARTTIME_MASK,
-					    7 << WM8996_MICD_RATE_SHIFT |
-					    7 << WM8996_MICD_BIAS_STARTTIME_SHIFT);
+			wm8996_report_headphone(codec);
 		}
 	}
 }
@@ -2768,7 +2772,7 @@
 	wm8996->retune_mobile_enum.max = wm8996->num_retune_mobile_texts;
 	wm8996->retune_mobile_enum.texts = wm8996->retune_mobile_texts;
 
-	ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+	ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
 	if (ret != 0)
 		dev_err(codec->dev,
 			"Failed to add ReTune Mobile controls: %d\n", ret);
@@ -2791,7 +2795,6 @@
 	int ret;
 	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
 	struct i2c_client *i2c = to_i2c_client(codec->dev);
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int i, irq_flags;
 
 	wm8996->codec = codec;
@@ -2799,8 +2802,6 @@
 	init_completion(&wm8996->dcs_done);
 	init_completion(&wm8996->fll_lock);
 
-	dapm->idle_bias_off = true;
-
 	codec->control_data = wm8996->regmap;
 
 	ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
@@ -2966,7 +2967,7 @@
 	if (wm8996->pdata.num_retune_mobile_cfgs)
 		wm8996_retune_mobile_pdata(codec);
 	else
-		snd_soc_add_controls(codec, wm8996_eq_controls,
+		snd_soc_add_codec_controls(codec, wm8996_eq_controls,
 				     ARRAY_SIZE(wm8996_eq_controls));
 
 	/* If the TX LRCLK pins are not in LRCLK mode configure the
@@ -3038,22 +3039,16 @@
 	for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
 		regulator_unregister_notifier(wm8996->supplies[i].consumer,
 					      &wm8996->disable_nb[i]);
-	regulator_put(wm8996->cpvdd);
 	regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
 
 	return 0;
 }
 
-static int wm8996_soc_volatile_register(struct snd_soc_codec *codec,
-					unsigned int reg)
-{
-	return true;
-}
-
 static struct snd_soc_codec_driver soc_codec_dev_wm8996 = {
 	.probe =	wm8996_probe,
 	.remove =	wm8996_remove,
 	.set_bias_level = wm8996_set_bias_level,
+	.idle_bias_off	= true,
 	.seq_notifier = wm8996_seq_notifier,
 	.controls = wm8996_snd_controls,
 	.num_controls = ARRAY_SIZE(wm8996_snd_controls),
@@ -3062,12 +3057,11 @@
 	.dapm_routes = wm8996_dapm_routes,
 	.num_dapm_routes = ARRAY_SIZE(wm8996_dapm_routes),
 	.set_pll = wm8996_set_fll,
-	.reg_cache_size = WM8996_MAX_REGISTER,
-	.volatile_register = wm8996_soc_volatile_register,
 };
 
 #define WM8996_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
-		      SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+		      SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+		      SNDRV_PCM_RATE_48000)
 #define WM8996_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
 			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |\
 			SNDRV_PCM_FMTBIT_S32_LE)
@@ -3087,6 +3081,7 @@
 			.channels_max = 6,
 			.rates = WM8996_RATES,
 			.formats = WM8996_FORMATS,
+			.sig_bits = 24,
 		},
 		.capture = {
 			 .stream_name = "AIF1 Capture",
@@ -3094,6 +3089,7 @@
 			 .channels_max = 6,
 			 .rates = WM8996_RATES,
 			 .formats = WM8996_FORMATS,
+			 .sig_bits = 24,
 		 },
 		.ops = &wm8996_dai_ops,
 	},
@@ -3105,6 +3101,7 @@
 			.channels_max = 2,
 			.rates = WM8996_RATES,
 			.formats = WM8996_FORMATS,
+			.sig_bits = 24,
 		},
 		.capture = {
 			 .stream_name = "AIF2 Capture",
@@ -3112,6 +3109,7 @@
 			 .channels_max = 2,
 			 .rates = WM8996_RATES,
 			 .formats = WM8996_FORMATS,
+			.sig_bits = 24,
 		 },
 		.ops = &wm8996_dai_ops,
 	},
@@ -3149,25 +3147,18 @@
 	for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
 		wm8996->supplies[i].supply = wm8996_supply_names[i];
 
-	ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8996->supplies),
-				 wm8996->supplies);
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8996->supplies),
+				      wm8996->supplies);
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
 		goto err_gpio;
 	}
 
-	wm8996->cpvdd = regulator_get(&i2c->dev, "CPVDD");
-	if (IS_ERR(wm8996->cpvdd)) {
-		ret = PTR_ERR(wm8996->cpvdd);
-		dev_err(&i2c->dev, "Failed to get CPVDD: %d\n", ret);
-		goto err_get;
-	}
-
 	ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies),
 				    wm8996->supplies);
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
-		goto err_cpvdd;
+		goto err_gpio;
 	}
 
 	if (wm8996->pdata.ldo_ena > 0) {
@@ -3188,7 +3179,7 @@
 		goto err_regmap;
 	}
 	if (reg != 0x8915) {
-		dev_err(&i2c->dev, "Device is not a WM8996, ID %x\n", ret);
+		dev_err(&i2c->dev, "Device is not a WM8996, ID %x\n", reg);
 		ret = -EINVAL;
 		goto err_regmap;
 	}
@@ -3229,10 +3220,6 @@
 	if (wm8996->pdata.ldo_ena > 0)
 		gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
 	regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
-err_cpvdd:
-	regulator_put(wm8996->cpvdd);
-err_get:
-	regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
 err_gpio:
 	if (wm8996->pdata.ldo_ena > 0)
 		gpio_free(wm8996->pdata.ldo_ena);
@@ -3247,8 +3234,6 @@
 
 	snd_soc_unregister_codec(&client->dev);
 	wm8996_free_gpio(wm8996);
-	regulator_put(wm8996->cpvdd);
-	regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
 	regmap_exit(wm8996->regmap);
 	if (wm8996->pdata.ldo_ena > 0) {
 		gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
@@ -3273,25 +3258,7 @@
 	.id_table = wm8996_i2c_id,
 };
 
-static int __init wm8996_modinit(void)
-{
-	int ret;
-
-	ret = i2c_add_driver(&wm8996_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register WM8996 I2C driver: %d\n",
-		       ret);
-	}
-
-	return ret;
-}
-module_init(wm8996_modinit);
-
-static void __exit wm8996_exit(void)
-{
-	i2c_del_driver(&wm8996_i2c_driver);
-}
-module_exit(wm8996_exit);
+module_i2c_driver(wm8996_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8996 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index a6bab39..076c126 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -824,6 +824,8 @@
 static int wm9081_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
+	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
+
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		break;
@@ -841,6 +843,9 @@
 	case SND_SOC_BIAS_STANDBY:
 		/* Initial cold start */
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			regcache_cache_only(wm9081->regmap, false);
+			regcache_sync(wm9081->regmap);
+
 			/* Disable LINEOUT discharge */
 			snd_soc_update_bits(codec, WM9081_ANTI_POP_CONTROL,
 					    WM9081_LINEOUT_DISCH, 0);
@@ -892,6 +897,8 @@
 		snd_soc_update_bits(codec, WM9081_ANTI_POP_CONTROL,
 				    WM9081_LINEOUT_DISCH,
 				    WM9081_LINEOUT_DISCH);
+
+		regcache_cache_only(wm9081->regmap, true);
 		break;
 	}
 
@@ -1258,7 +1265,6 @@
 {
 	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
 	int ret;
-	u16 reg;
 
 	codec->control_data = wm9081->regmap;
 
@@ -1268,16 +1274,6 @@
 		return ret;
 	}
 
-	reg = 0;
-	if (wm9081->pdata.irq_high)
-		reg |= WM9081_IRQ_POL;
-	if (!wm9081->pdata.irq_cmos)
-		reg |= WM9081_IRQ_OP_CTRL;
-	snd_soc_update_bits(codec, WM9081_INTERRUPT_CONTROL,
-			    WM9081_IRQ_POL | WM9081_IRQ_OP_CTRL, reg);
-
-	wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	/* Enable zero cross by default */
 	snd_soc_update_bits(codec, WM9081_ANALOGUE_LINEOUT,
 			    WM9081_LINEOUTZC, WM9081_LINEOUTZC);
@@ -1287,7 +1283,7 @@
 	if (!wm9081->pdata.num_retune_configs) {
 		dev_dbg(codec->dev,
 			"No ReTune Mobile data, using normal EQ\n");
-		snd_soc_add_controls(codec, wm9081_eq_controls,
+		snd_soc_add_codec_controls(codec, wm9081_eq_controls,
 				     ARRAY_SIZE(wm9081_eq_controls));
 	}
 
@@ -1300,38 +1296,15 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm9081_suspend(struct snd_soc_codec *codec)
-{
-	wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	return 0;
-}
-
-static int wm9081_resume(struct snd_soc_codec *codec)
-{
-	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
-
-	regcache_sync(wm9081->regmap);
-
-	wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-	return 0;
-}
-#else
-#define wm9081_suspend NULL
-#define wm9081_resume NULL
-#endif
-
 static struct snd_soc_codec_driver soc_codec_dev_wm9081 = {
 	.probe = 	wm9081_probe,
 	.remove = 	wm9081_remove,
-	.suspend =	wm9081_suspend,
-	.resume =	wm9081_resume,
 
 	.set_sysclk = wm9081_set_sysclk,
 	.set_bias_level = wm9081_set_bias_level,
 
+	.idle_bias_off = true,
+
 	.controls         = wm9081_snd_controls,
 	.num_controls     = ARRAY_SIZE(wm9081_snd_controls),
 	.dapm_widgets	  = wm9081_dapm_widgets,
@@ -1395,6 +1368,16 @@
 		memcpy(&wm9081->pdata, dev_get_platdata(&i2c->dev),
 		       sizeof(wm9081->pdata));
 
+	reg = 0;
+	if (wm9081->pdata.irq_high)
+		reg |= WM9081_IRQ_POL;
+	if (!wm9081->pdata.irq_cmos)
+		reg |= WM9081_IRQ_OP_CTRL;
+	regmap_update_bits(wm9081->regmap, WM9081_INTERRUPT_CONTROL,
+			   WM9081_IRQ_POL | WM9081_IRQ_OP_CTRL, reg);
+
+	regcache_cache_only(wm9081->regmap, true);
+
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_wm9081, &wm9081_dai, 1);
 	if (ret < 0)
@@ -1435,28 +1418,7 @@
 };
 #endif
 
-static int __init wm9081_modinit(void)
-{
-	int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	ret = i2c_add_driver(&wm9081_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register WM9081 I2C driver: %d\n",
-		       ret);
-	}
-#endif
-	return ret;
-}
-module_init(wm9081_modinit);
-
-static void __exit wm9081_exit(void)
-{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	i2c_del_driver(&wm9081_i2c_driver);
-#endif
-}
-module_exit(wm9081_exit);
-
+module_i2c_driver(wm9081_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM9081 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
index 41ebe0dc..4b263b6 100644
--- a/sound/soc/codecs/wm9090.c
+++ b/sound/soc/codecs/wm9090.c
@@ -25,6 +25,7 @@
 #include <linux/device.h>
 #include <linux/i2c.h>
 #include <linux/delay.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
@@ -33,116 +34,51 @@
 
 #include "wm9090.h"
 
-static const u16 wm9090_reg_defaults[] = {
-	0x9093,     /* R0   - Software Reset */
-	0x0006,     /* R1   - Power Management (1) */
-	0x6000,     /* R2   - Power Management (2) */
-	0x0000,     /* R3   - Power Management (3) */
-	0x0000,     /* R4 */
-	0x0000,     /* R5 */
-	0x01C0,     /* R6   - Clocking 1 */
-	0x0000,     /* R7 */
-	0x0000,     /* R8 */
-	0x0000,     /* R9 */
-	0x0000,     /* R10 */
-	0x0000,     /* R11 */
-	0x0000,     /* R12 */
-	0x0000,     /* R13 */
-	0x0000,     /* R14 */
-	0x0000,     /* R15 */
-	0x0000,     /* R16 */
-	0x0000,     /* R17 */
-	0x0000,     /* R18 */
-	0x0000,     /* R19 */
-	0x0000,     /* R20 */
-	0x0000,     /* R21 */
-	0x0003,     /* R22  - IN1 Line Control */
-	0x0003,     /* R23  - IN2 Line Control */
-	0x0083,     /* R24  - IN1 Line Input A Volume */
-	0x0083,     /* R25  - IN1  Line Input B Volume */
-	0x0083,     /* R26  - IN2 Line Input A Volume */
-	0x0083,     /* R27  - IN2 Line Input B Volume */
-	0x002D,     /* R28  - Left Output Volume */
-	0x002D,     /* R29  - Right Output Volume */
-	0x0000,     /* R30 */
-	0x0000,     /* R31 */
-	0x0000,     /* R32 */
-	0x0000,     /* R33 */
-	0x0100,     /* R34  - SPKMIXL Attenuation */
-	0x0000,     /* R35 */
-	0x0010,     /* R36  - SPKOUT Mixers */
-	0x0140,     /* R37  - ClassD3 */
-	0x0039,     /* R38  - Speaker Volume Left */
-	0x0000,     /* R39 */
-	0x0000,     /* R40 */
-	0x0000,     /* R41 */
-	0x0000,     /* R42 */
-	0x0000,     /* R43 */
-	0x0000,     /* R44 */
-	0x0000,     /* R45  - Output Mixer1 */
-	0x0000,     /* R46  - Output Mixer2 */
-	0x0100,     /* R47  - Output Mixer3 */
-	0x0100,     /* R48  - Output Mixer4 */
-	0x0000,     /* R49 */
-	0x0000,     /* R50 */
-	0x0000,     /* R51 */
-	0x0000,     /* R52 */
-	0x0000,     /* R53 */
-	0x0000,     /* R54  - Speaker Mixer */
-	0x0000,     /* R55 */
-	0x0000,     /* R56 */
-	0x000D,     /* R57  - AntiPOP2 */
-	0x0000,     /* R58 */
-	0x0000,     /* R59 */
-	0x0000,     /* R60 */
-	0x0000,     /* R61 */
-	0x0000,     /* R62 */
-	0x0000,     /* R63 */
-	0x0000,     /* R64 */
-	0x0000,     /* R65 */
-	0x0000,     /* R66 */
-	0x0000,     /* R67 */
-	0x0000,     /* R68 */
-	0x0000,     /* R69 */
-	0x0000,     /* R70  - Write Sequencer 0 */
-	0x0000,     /* R71  - Write Sequencer 1 */
-	0x0000,     /* R72  - Write Sequencer 2 */
-	0x0000,     /* R73  - Write Sequencer 3 */
-	0x0000,     /* R74  - Write Sequencer 4 */
-	0x0000,     /* R75  - Write Sequencer 5 */
-	0x1F25,     /* R76  - Charge Pump 1 */
-	0x0000,     /* R77 */
-	0x0000,     /* R78 */
-	0x0000,     /* R79 */
-	0x0000,     /* R80 */
-	0x0000,     /* R81 */
-	0x0000,     /* R82 */
-	0x0000,     /* R83 */
-	0x0000,     /* R84  - DC Servo 0 */
-	0x054A,     /* R85  - DC Servo 1 */
-	0x0000,     /* R86 */
-	0x0000,     /* R87  - DC Servo 3 */
-	0x0000,     /* R88  - DC Servo Readback 0 */
-	0x0000,     /* R89  - DC Servo Readback 1 */
-	0x0000,     /* R90  - DC Servo Readback 2 */
-	0x0000,     /* R91 */
-	0x0000,     /* R92 */
-	0x0000,     /* R93 */
-	0x0000,     /* R94 */
-	0x0000,     /* R95 */
-	0x0100,     /* R96  - Analogue HP 0 */
-	0x0000,     /* R97 */
-	0x8640,     /* R98  - AGC Control 0 */
-	0xC000,     /* R99  - AGC Control 1 */
-	0x0200,     /* R100 - AGC Control 2 */
+static const struct reg_default wm9090_reg_defaults[] = {
+	{ 1,  0x0006 },     /* R1   - Power Management (1) */
+	{ 2,  0x6000 },     /* R2   - Power Management (2) */
+	{ 3,  0x0000 },     /* R3   - Power Management (3) */
+	{ 6,  0x01C0 },     /* R6   - Clocking 1 */
+	{ 22, 0x0003 },     /* R22  - IN1 Line Control */
+	{ 23, 0x0003 },     /* R23  - IN2 Line Control */
+	{ 24, 0x0083 },     /* R24  - IN1 Line Input A Volume */
+	{ 25, 0x0083 },     /* R25  - IN1  Line Input B Volume */
+	{ 26, 0x0083 },     /* R26  - IN2 Line Input A Volume */
+	{ 27, 0x0083 },     /* R27  - IN2 Line Input B Volume */
+	{ 28, 0x002D },     /* R28  - Left Output Volume */
+	{ 29, 0x002D },     /* R29  - Right Output Volume */
+	{ 34, 0x0100 },     /* R34  - SPKMIXL Attenuation */
+	{ 35, 0x0010 },     /* R36  - SPKOUT Mixers */
+	{ 37, 0x0140 },     /* R37  - ClassD3 */
+	{ 38, 0x0039 },     /* R38  - Speaker Volume Left */
+	{ 45, 0x0000 },     /* R45  - Output Mixer1 */
+	{ 46, 0x0000 },     /* R46  - Output Mixer2 */
+	{ 47, 0x0100 },     /* R47  - Output Mixer3 */
+	{ 48, 0x0100 },     /* R48  - Output Mixer4 */
+	{ 54, 0x0000 },     /* R54  - Speaker Mixer */
+	{ 57, 0x000D },     /* R57  - AntiPOP2 */
+	{ 70, 0x0000 },     /* R70  - Write Sequencer 0 */
+	{ 71, 0x0000 },     /* R71  - Write Sequencer 1 */
+	{ 72, 0x0000 },     /* R72  - Write Sequencer 2 */
+	{ 73, 0x0000 },     /* R73  - Write Sequencer 3 */
+	{ 74, 0x0000 },     /* R74  - Write Sequencer 4 */
+	{ 75, 0x0000 },     /* R75  - Write Sequencer 5 */
+	{ 76, 0x1F25 },     /* R76  - Charge Pump 1 */
+	{ 85, 0x054A },     /* R85  - DC Servo 1 */
+	{ 87, 0x0000 },     /* R87  - DC Servo 3 */
+	{ 96, 0x0100 },     /* R96  - Analogue HP 0 */
+	{ 98, 0x8640 },     /* R98  - AGC Control 0 */
+	{ 99, 0xC000 },     /* R99  - AGC Control 1 */
+	{ 100, 0x0200 },     /* R100 - AGC Control 2 */
 };
 
 /* This struct is used to save the context */
 struct wm9090_priv {
 	struct wm9090_platform_data pdata;
+	struct regmap *regmap;
 };
 
-static int wm9090_volatile(struct snd_soc_codec *codec, unsigned int reg)
+static bool wm9090_volatile(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
 	case WM9090_SOFTWARE_RESET:
@@ -150,10 +86,60 @@
 	case WM9090_DC_SERVO_READBACK_0:
 	case WM9090_DC_SERVO_READBACK_1:
 	case WM9090_DC_SERVO_READBACK_2:
-		return 1;
+		return true;
 
 	default:
-		return 0;
+		return false;
+	}
+}
+
+static bool wm9090_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM9090_SOFTWARE_RESET:
+	case WM9090_POWER_MANAGEMENT_1:
+	case WM9090_POWER_MANAGEMENT_2:
+	case WM9090_POWER_MANAGEMENT_3:
+	case WM9090_CLOCKING_1:
+	case WM9090_IN1_LINE_CONTROL:
+	case WM9090_IN2_LINE_CONTROL:
+	case WM9090_IN1_LINE_INPUT_A_VOLUME:
+	case WM9090_IN1_LINE_INPUT_B_VOLUME:
+	case WM9090_IN2_LINE_INPUT_A_VOLUME:
+	case WM9090_IN2_LINE_INPUT_B_VOLUME:
+	case WM9090_LEFT_OUTPUT_VOLUME:
+	case WM9090_RIGHT_OUTPUT_VOLUME:
+	case WM9090_SPKMIXL_ATTENUATION:
+	case WM9090_SPKOUT_MIXERS:
+	case WM9090_CLASSD3:
+	case WM9090_SPEAKER_VOLUME_LEFT:
+	case WM9090_OUTPUT_MIXER1:
+	case WM9090_OUTPUT_MIXER2:
+	case WM9090_OUTPUT_MIXER3:
+	case WM9090_OUTPUT_MIXER4:
+	case WM9090_SPEAKER_MIXER:
+	case WM9090_ANTIPOP2:
+	case WM9090_WRITE_SEQUENCER_0:
+	case WM9090_WRITE_SEQUENCER_1:
+	case WM9090_WRITE_SEQUENCER_2:
+	case WM9090_WRITE_SEQUENCER_3:
+	case WM9090_WRITE_SEQUENCER_4:
+	case WM9090_WRITE_SEQUENCER_5:
+	case WM9090_CHARGE_PUMP_1:
+	case WM9090_DC_SERVO_0:
+	case WM9090_DC_SERVO_1:
+	case WM9090_DC_SERVO_3:
+	case WM9090_DC_SERVO_READBACK_0:
+	case WM9090_DC_SERVO_READBACK_1:
+	case WM9090_DC_SERVO_READBACK_2:
+	case WM9090_ANALOGUE_HP_0:
+	case WM9090_AGC_CONTROL_0:
+	case WM9090_AGC_CONTROL_1:
+	case WM9090_AGC_CONTROL_2:
+		return true;
+
+	default:
+		return false;
 	}
 }
 
@@ -447,7 +433,7 @@
 
 	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
-	snd_soc_add_controls(codec, wm9090_controls,
+	snd_soc_add_codec_controls(codec, wm9090_controls,
 			     ARRAY_SIZE(wm9090_controls));
 
 	if (wm9090->pdata.lin1_diff) {
@@ -456,7 +442,7 @@
 	} else {
 		snd_soc_dapm_add_routes(dapm, audio_map_in1_se,
 					ARRAY_SIZE(audio_map_in1_se));
-		snd_soc_add_controls(codec, wm9090_in1_se_controls,
+		snd_soc_add_codec_controls(codec, wm9090_in1_se_controls,
 				     ARRAY_SIZE(wm9090_in1_se_controls));
 	}
 
@@ -466,7 +452,7 @@
 	} else {
 		snd_soc_dapm_add_routes(dapm, audio_map_in2_se,
 					ARRAY_SIZE(audio_map_in2_se));
-		snd_soc_add_controls(codec, wm9090_in2_se_controls,
+		snd_soc_add_codec_controls(codec, wm9090_in2_se_controls,
 				     ARRAY_SIZE(wm9090_in2_se_controls));
 	}
 
@@ -492,8 +478,7 @@
 static int wm9090_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
-	u16 *reg_cache = codec->reg_cache;
-	int i, ret;
+	struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -513,7 +498,7 @@
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
 			/* Restore the register cache */
-			snd_soc_cache_sync(codec);
+			regcache_sync(wm9090->regmap);
 		}
 
 		/* We keep VMID off during standby since the combination of
@@ -537,26 +522,16 @@
 
 static int wm9090_probe(struct snd_soc_codec *codec)
 {
+	struct wm9090_priv *wm9090 = dev_get_drvdata(codec->dev);
 	int ret;
 
-	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+	codec->control_data = wm9090->regmap;
+	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
 	if (ret != 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
 	}
 
-	ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET);
-	if (ret < 0)
-		return ret;
-	if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) {
-		dev_err(codec->dev, "Device is not a WM9090, ID=%x\n", ret);
-		return -EINVAL;
-	}
-
-	ret = snd_soc_write(codec, WM9090_SOFTWARE_RESET, 0);
-	if (ret < 0)
-		return ret;
-
 	/* Configure some defaults; they will be written out when we
 	 * bring the bias up.
 	 */
@@ -624,16 +599,27 @@
 	.suspend = 	wm9090_suspend,
 	.resume =	wm9090_resume,
 	.set_bias_level = wm9090_set_bias_level,
-	.reg_cache_size = (WM9090_MAX_REGISTER + 1),
-	.reg_word_size = sizeof(u16),
-	.reg_cache_default = wm9090_reg_defaults,
-	.volatile_register = wm9090_volatile,
 };
 
+static const struct regmap_config wm9090_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = WM9090_MAX_REGISTER,
+	.volatile_reg = wm9090_volatile,
+	.readable_reg = wm9090_readable,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm9090_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm9090_reg_defaults),
+};
+
+
 static int wm9090_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
 	struct wm9090_priv *wm9090;
+	unsigned int reg;
 	int ret;
 
 	wm9090 = devm_kzalloc(&i2c->dev, sizeof(*wm9090), GFP_KERNEL);
@@ -642,6 +628,26 @@
 		return -ENOMEM;
 	}
 
+	wm9090->regmap = regmap_init_i2c(i2c, &wm9090_regmap);
+	if (IS_ERR(wm9090->regmap)) {
+		ret = PTR_ERR(wm9090->regmap);
+		dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(wm9090->regmap, WM9090_SOFTWARE_RESET, &reg);
+	if (ret < 0)
+		goto err;
+	if (reg != 0x9093) {
+		dev_err(&i2c->dev, "Device is not a WM9090, ID=%x\n", reg);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	ret = regmap_write(wm9090->regmap, WM9090_SOFTWARE_RESET, 0);
+	if (ret < 0)
+		goto err;
+
 	if (i2c->dev.platform_data)
 		memcpy(&wm9090->pdata, i2c->dev.platform_data,
 		       sizeof(wm9090->pdata));
@@ -650,6 +656,15 @@
 
 	ret =  snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_wm9090,  NULL, 0);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	regmap_exit(wm9090->regmap);
 	return ret;
 }
 
@@ -658,6 +673,7 @@
 	struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c);
 
 	snd_soc_unregister_codec(&i2c->dev);
+	regmap_exit(wm9090->regmap);
 
 	return 0;
 }
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index 40c92ea..cacc6a8 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -351,7 +351,7 @@
 	if (ret)
 		goto reset_err;
 
-	snd_soc_add_controls(codec, wm9705_snd_ac97_controls,
+	snd_soc_add_codec_controls(codec, wm9705_snd_ac97_controls,
 				ARRAY_SIZE(wm9705_snd_ac97_controls));
 
 	return 0;
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index b7b31f8..b342ae5 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -20,10 +20,9 @@
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/tlv.h>
 #include "wm9712.h"
 
-#define WM9712_VERSION "0.4"
-
 static unsigned int ac97_read(struct snd_soc_codec *codec,
 	unsigned int reg);
 static int ac97_write(struct snd_soc_codec *codec,
@@ -71,6 +70,9 @@
 static const char *wm9712_ng_type[] = {"Constant Gain", "Mute"};
 static const char *wm9712_diff_sel[] = {"Mic", "Line"};
 
+static const DECLARE_TLV_DB_SCALE(main_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 2000, 0);
+
 static const struct soc_enum wm9712_enum[] = {
 SOC_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9712_alc_select),
 SOC_ENUM_SINGLE(AC97_VIDEO, 12, 4, wm9712_alc_mux),
@@ -149,9 +151,9 @@
 SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 1),
 SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
 
-SOC_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1),
-SOC_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1),
-SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0),
+SOC_SINGLE_TLV("Mic 1 Volume", AC97_MIC, 8, 31, 1, main_tlv),
+SOC_SINGLE_TLV("Mic 2 Volume", AC97_MIC, 0, 31, 1, main_tlv),
+SOC_SINGLE_TLV("Mic Boost Volume", AC97_MIC, 7, 1, 0, boost_tlv),
 };
 
 /* We have to create a fake left and right HP mixers because
@@ -619,8 +621,6 @@
 {
 	int ret = 0;
 
-	printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION);
-
 	ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
 	if (ret < 0) {
 		printk(KERN_ERR "wm9712: failed to register AC97 codec\n");
@@ -637,7 +637,7 @@
 	ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000);
 
 	wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-	snd_soc_add_controls(codec, wm9712_snd_ac97_controls,
+	snd_soc_add_codec_controls(codec, wm9712_snd_ac97_controls,
 				ARRAY_SIZE(wm9712_snd_ac97_controls));
 
 	return 0;
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 2b8479b..2d22cc7 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -1216,7 +1216,7 @@
 	reg = ac97_read(codec, AC97_CD) & 0x7fff;
 	ac97_write(codec, AC97_CD, reg);
 
-	snd_soc_add_controls(codec, wm9713_snd_ac97_controls,
+	snd_soc_add_codec_controls(codec, wm9713_snd_ac97_controls,
 				ARRAY_SIZE(wm9713_snd_ac97_controls));
 
 	return 0;
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 8a68cea..f13f288 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -172,7 +172,7 @@
 		break;
 	default:
 		WARN(1, "Unknown DCS readback method\n");
-		break;
+		return;
 	}
 
 	dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
@@ -207,7 +207,7 @@
 
 	/* Save the callibrated offset if we're in class W mode and
 	 * therefore don't have any analogue signal mixed in. */
-	if (hubs->class_w)
+	if (hubs->class_w && !hubs->no_cache_class_w)
 		hubs->class_w_dcs = dcs_cfg;
 }
 
@@ -500,6 +500,36 @@
 	return 0;
 }
 
+static int lineout_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *control, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	bool *flag;
+
+	switch (w->shift) {
+	case WM8993_LINEOUT1N_ENA_SHIFT:
+		flag = &hubs->lineout1n_ena;
+		break;
+	case WM8993_LINEOUT1P_ENA_SHIFT:
+		flag = &hubs->lineout1p_ena;
+		break;
+	case WM8993_LINEOUT2N_ENA_SHIFT:
+		flag = &hubs->lineout2n_ena;
+		break;
+	case WM8993_LINEOUT2P_ENA_SHIFT:
+		flag = &hubs->lineout2p_ena;
+		break;
+	default:
+		WARN(1, "Unknown line output");
+		return -EINVAL;
+	}
+
+	*flag = SND_SOC_DAPM_EVENT_ON(event);
+
+	return 0;
+}
+
 static const struct snd_kcontrol_new in1l_pga[] = {
 SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0),
 SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0),
@@ -613,8 +643,6 @@
 SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0, NULL, 0),
 
-SND_SOC_DAPM_SUPPLY("LINEOUT_VMID_BUF", WM8993_ANTIPOP1, 7, 0, NULL, 0),
-
 SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,
 		   in1l_pga, ARRAY_SIZE(in1l_pga)),
 SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0,
@@ -640,9 +668,8 @@
 
 SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event, 
 		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
-SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0,
-		   NULL, 0,
-		   hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_OUT_DRV_E("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
+		       hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 
 SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
 		   earpiece_mixer, ARRAY_SIZE(earpiece_mixer)),
@@ -656,10 +683,10 @@
 		   right_speaker_boost, ARRAY_SIZE(right_speaker_boost)),
 
 SND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0),
-SND_SOC_DAPM_PGA("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0,
-		 NULL, 0),
-SND_SOC_DAPM_PGA("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0,
-		 NULL, 0),
+SND_SOC_DAPM_OUT_DRV("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0,
+		     NULL, 0),
+SND_SOC_DAPM_OUT_DRV("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0,
+		     NULL, 0),
 
 SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0,
 		   line1_mix, ARRAY_SIZE(line1_mix)),
@@ -675,14 +702,18 @@
 SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0,
 		   line2p_mix, ARRAY_SIZE(line2p_mix)),
 
-SND_SOC_DAPM_PGA("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0,
-		 NULL, 0),
-SND_SOC_DAPM_PGA("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0,
-		 NULL, 0),
-SND_SOC_DAPM_PGA("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0,
-		 NULL, 0),
-SND_SOC_DAPM_PGA("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0,
-		 NULL, 0),
+SND_SOC_DAPM_OUT_DRV_E("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0,
+		       NULL, 0, lineout_event,
+		     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_OUT_DRV_E("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0,
+		       NULL, 0, lineout_event,
+		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_OUT_DRV_E("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0,
+		       NULL, 0, lineout_event,
+		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_OUT_DRV_E("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0,
+		       NULL, 0, lineout_event,
+		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 
 SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
 SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
@@ -836,11 +867,9 @@
 };
 
 static const struct snd_soc_dapm_route lineout1_se_routes[] = {
-	{ "LINEOUT1N Mixer", NULL, "LINEOUT_VMID_BUF" },
 	{ "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" },
 	{ "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" },
 
-	{ "LINEOUT1P Mixer", NULL, "LINEOUT_VMID_BUF" },
 	{ "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" },
 
 	{ "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
@@ -857,11 +886,9 @@
 };
 
 static const struct snd_soc_dapm_route lineout2_se_routes[] = {
-	{ "LINEOUT2N Mixer", NULL, "LINEOUT_VMID_BUF" },
 	{ "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" },
 	{ "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" },
 
-	{ "LINEOUT2P Mixer", NULL, "LINEOUT_VMID_BUF" },
 	{ "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" },
 
 	{ "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
@@ -901,7 +928,7 @@
 			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU,
 			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU);
 
-	snd_soc_add_controls(codec, analogue_snd_controls,
+	snd_soc_add_codec_controls(codec, analogue_snd_controls,
 			     ARRAY_SIZE(analogue_snd_controls));
 
 	snd_soc_dapm_new_controls(dapm, analogue_dapm_widgets,
@@ -949,6 +976,11 @@
 				  int jd_scthr, int jd_thr, int micbias1_lvl,
 				  int micbias2_lvl)
 {
+	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+
+	hubs->lineout1_se = !lineout1_diff;
+	hubs->lineout2_se = !lineout2_diff;
+
 	if (!lineout1_diff)
 		snd_soc_update_bits(codec, WM8993_LINE_MIXER1,
 				    WM8993_LINEOUT1_MODE,
@@ -958,11 +990,10 @@
 				    WM8993_LINEOUT2_MODE,
 				    WM8993_LINEOUT2_MODE);
 
-	/* If the line outputs are differential then we aren't presenting
-	 * VMID as an output and can disable it.
-	 */
-	if (lineout1_diff && lineout2_diff)
-		codec->dapm.idle_bias_off = 1;
+	if (!lineout1_diff && !lineout2_diff)
+		snd_soc_update_bits(codec, WM8993_ANTIPOP1,
+				    WM8993_LINEOUT_VMID_BUF_ENA,
+				    WM8993_LINEOUT_VMID_BUF_ENA);
 
 	if (lineout1fb)
 		snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
@@ -984,6 +1015,69 @@
 }
 EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata);
 
+void wm_hubs_vmid_ena(struct snd_soc_codec *codec)
+{
+	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	int val = 0;
+
+	if (hubs->lineout1_se)
+		val |= WM8993_LINEOUT1N_ENA | WM8993_LINEOUT1P_ENA;
+
+	if (hubs->lineout2_se)
+		val |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA;
+
+	/* Enable the line outputs while we power up */
+	snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3, val, val);
+}
+EXPORT_SYMBOL_GPL(wm_hubs_vmid_ena);
+
+void wm_hubs_set_bias_level(struct snd_soc_codec *codec,
+			    enum snd_soc_bias_level level)
+{
+	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	int val;
+
+	switch (level) {
+	case SND_SOC_BIAS_STANDBY:
+		/* Clamp the inputs to VMID while we ramp to charge caps */
+		snd_soc_update_bits(codec, WM8993_INPUTS_CLAMP_REG,
+				    WM8993_INPUTS_CLAMP, WM8993_INPUTS_CLAMP);
+		break;
+
+	case SND_SOC_BIAS_ON:
+		/* Turn off any unneded single ended outputs */
+		val = 0;
+
+		if (hubs->lineout1_se && hubs->lineout1n_ena)
+			val |= WM8993_LINEOUT1N_ENA;
+
+		if (hubs->lineout1_se && hubs->lineout1p_ena)
+			val |= WM8993_LINEOUT1P_ENA;
+
+		if (hubs->lineout2_se && hubs->lineout2n_ena)
+			val |= WM8993_LINEOUT2N_ENA;
+
+		if (hubs->lineout2_se && hubs->lineout2p_ena)
+			val |= WM8993_LINEOUT2P_ENA;
+
+		snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3,
+				    WM8993_LINEOUT1N_ENA |
+				    WM8993_LINEOUT1P_ENA |
+				    WM8993_LINEOUT2N_ENA |
+				    WM8993_LINEOUT2P_ENA,
+				    val);
+
+		/* Remove the input clamps */
+		snd_soc_update_bits(codec, WM8993_INPUTS_CLAMP_REG,
+				    WM8993_INPUTS_CLAMP, 0);
+		break;
+
+	default:
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(wm_hubs_set_bias_level);
+
 MODULE_DESCRIPTION("Shared support for Wolfson hubs products");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h
index c674c7a..5705276 100644
--- a/sound/soc/codecs/wm_hubs.h
+++ b/sound/soc/codecs/wm_hubs.h
@@ -30,9 +30,18 @@
 	int series_startup;
 	int no_series_update;
 
+	bool no_cache_class_w;
 	bool class_w;
 	u16 class_w_dcs;
 
+	bool lineout1_se;
+	bool lineout1n_ena;
+	bool lineout1p_ena;
+
+	bool lineout2_se;
+	bool lineout2n_ena;
+	bool lineout2p_ena;
+
 	bool dcs_done_irq;
 	struct completion dcs_done;
 };
@@ -46,5 +55,8 @@
 					 int micbias1_lvl, int micbias2_lvl);
 
 extern irqreturn_t wm_hubs_dcs_done(int irq, void *data);
+extern void wm_hubs_vmid_ena(struct snd_soc_codec *codec);
+extern void wm_hubs_set_bias_level(struct snd_soc_codec *codec,
+				   enum snd_soc_bias_level level);
 
 #endif
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index b26401f..97d77b2 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -826,7 +826,7 @@
 	}
 }
 
-static u64 davinci_pcm_dmamask = 0xffffffff;
+static u64 davinci_pcm_dmamask = DMA_BIT_MASK(32);
 
 static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
@@ -837,7 +837,7 @@
 	if (!card->dev->dma_mask)
 		card->dev->dma_mask = &davinci_pcm_dmamask;
 	if (!card->dev->coherent_dma_mask)
-		card->dev->coherent_dma_mask = 0xffffffff;
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
 	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
 		ret = davinci_pcm_preallocate_dma_buffer(pcm,
diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/ep93xx/Kconfig
index 91a28de..88143db 100644
--- a/sound/soc/ep93xx/Kconfig
+++ b/sound/soc/ep93xx/Kconfig
@@ -1,6 +1,7 @@
 config SND_EP93XX_SOC
 	tristate "SoC Audio support for the Cirrus Logic EP93xx series"
 	depends on ARCH_EP93XX && SND_SOC
+	select SND_SOC_DMAENGINE_PCM
 	help
 	  Say Y or M if you want to add support for codecs attached to
 	  the EP93xx I2S or AC97 interfaces.
diff --git a/sound/soc/ep93xx/edb93xx.c b/sound/soc/ep93xx/edb93xx.c
index bae5cbb..e01cb02 100644
--- a/sound/soc/ep93xx/edb93xx.c
+++ b/sound/soc/ep93xx/edb93xx.c
@@ -85,9 +85,7 @@
 	struct snd_soc_card *card = &snd_soc_edb93xx;
 	int ret;
 
-	ret = ep93xx_i2s_acquire(EP93XX_SYSCON_DEVCFG_I2SONAC97,
-				 EP93XX_SYSCON_I2SCLKDIV_ORIDE |
-				 EP93XX_SYSCON_I2SCLKDIV_SPOL);
+	ret = ep93xx_i2s_acquire();
 	if (ret)
 		return ret;
 
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c
index de83904..162dbb7 100644
--- a/sound/soc/ep93xx/ep93xx-pcm.c
+++ b/sound/soc/ep93xx/ep93xx-pcm.c
@@ -23,6 +23,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include <mach/dma.h>
 #include <mach/hardware.h>
@@ -52,26 +53,6 @@
 	.fifo_size		= 32,
 };
 
-struct ep93xx_runtime_data
-{
-	int				pointer_bytes;
-	int				periods;
-	int				period_bytes;
-	struct dma_chan			*dma_chan;
-	struct ep93xx_dma_data		dma_data;
-};
-
-static void ep93xx_pcm_dma_callback(void *data)
-{
-	struct snd_pcm_substream *substream = data;
-	struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
-
-	rtd->pointer_bytes += rtd->period_bytes;
-	rtd->pointer_bytes %= rtd->period_bytes * rtd->periods;
-
-	snd_pcm_period_elapsed(substream);
-}
-
 static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
 {
 	struct ep93xx_dma_data *data = filter_param;
@@ -86,98 +67,48 @@
 
 static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
 {
-	struct snd_soc_pcm_runtime *soc_rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = soc_rtd->cpu_dai;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct ep93xx_pcm_dma_params *dma_params;
-	struct ep93xx_runtime_data *rtd;    
-	dma_cap_mask_t mask;
+	struct ep93xx_dma_data *dma_data;
 	int ret;
 
-	ret = snd_pcm_hw_constraint_integer(substream->runtime,
-					    SNDRV_PCM_HW_PARAM_PERIODS);
-	if (ret < 0)
-		return ret;
-
 	snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
 
-	rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
-	if (!rtd) 
+	dma_data = kmalloc(sizeof(*dma_data), GFP_KERNEL);
+	if (!dma_data)
 		return -ENOMEM;
 
-	dma_cap_zero(mask);
-	dma_cap_set(DMA_SLAVE, mask);
-	dma_cap_set(DMA_CYCLIC, mask);
-
 	dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
-	rtd->dma_data.port = dma_params->dma_port;
-	rtd->dma_data.name = dma_params->name;
+	dma_data->port = dma_params->dma_port;
+	dma_data->name = dma_params->name;
+	dma_data->direction = snd_pcm_substream_to_dma_direction(substream);
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		rtd->dma_data.direction = DMA_MEM_TO_DEV;
-	else
-		rtd->dma_data.direction = DMA_DEV_TO_MEM;
-
-	rtd->dma_chan = dma_request_channel(mask, ep93xx_pcm_dma_filter,
-					    &rtd->dma_data);
-	if (!rtd->dma_chan) {
-		kfree(rtd);
-		return -EINVAL;
+	ret = snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter, dma_data);
+	if (ret) {
+		kfree(dma_data);
+		return ret;
 	}
-	
-	substream->runtime->private_data = rtd;
+
+	snd_dmaengine_pcm_set_data(substream, dma_data);
+
 	return 0;
 }
 
 static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
 {
-	struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+	struct dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
 
-	dma_release_channel(rtd->dma_chan);
-	kfree(rtd);
+	snd_dmaengine_pcm_close(substream);
+	kfree(dma_data);
 	return 0;
 }
 
-static int ep93xx_pcm_dma_submit(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct ep93xx_runtime_data *rtd = runtime->private_data;
-	struct dma_chan *chan = rtd->dma_chan;
-	struct dma_device *dma_dev = chan->device;
-	struct dma_async_tx_descriptor *desc;
-
-	rtd->pointer_bytes = 0;
-	desc = dma_dev->device_prep_dma_cyclic(chan, runtime->dma_addr,
-					       rtd->period_bytes * rtd->periods,
-					       rtd->period_bytes,
-					       rtd->dma_data.direction);
-	if (!desc)
-		return -EINVAL;
-
-	desc->callback = ep93xx_pcm_dma_callback;
-	desc->callback_param = substream;
-
-	dmaengine_submit(desc);
-	return 0;
-}
-
-static void ep93xx_pcm_dma_flush(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct ep93xx_runtime_data *rtd = runtime->private_data;
-
-	dmaengine_terminate_all(rtd->dma_chan);
-}
-
 static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct ep93xx_runtime_data *rtd = runtime->private_data;
-
 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 
-	rtd->periods = params_periods(params);
-	rtd->period_bytes = params_period_bytes(params);
 	return 0;
 }
 
@@ -187,41 +118,6 @@
 	return 0;
 }
 
-static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-	int ret;
-
-	ret = 0;
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		ret = ep93xx_pcm_dma_submit(substream);
-		break;
-
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		ep93xx_pcm_dma_flush(substream);
-		break;
-
-	default:
-		ret = -EINVAL;
-		break;
-	}
-
-	return ret;
-}
-
-static snd_pcm_uframes_t ep93xx_pcm_pointer(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
-
-	/* FIXME: implement this with sub-period granularity */
-	return bytes_to_frames(runtime, rtd->pointer_bytes);
-}
-
 static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
 			   struct vm_area_struct *vma)
 {
@@ -239,8 +135,8 @@
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= ep93xx_pcm_hw_params,
 	.hw_free	= ep93xx_pcm_hw_free,
-	.trigger	= ep93xx_pcm_trigger,
-	.pointer	= ep93xx_pcm_pointer,
+	.trigger	= snd_dmaengine_pcm_trigger,
+	.pointer	= snd_dmaengine_pcm_pointer,
 	.mmap		= ep93xx_pcm_mmap,
 };
 
@@ -281,7 +177,7 @@
 	}
 }
 
-static u64 ep93xx_pcm_dmamask = 0xffffffff;
+static u64 ep93xx_pcm_dmamask = DMA_BIT_MASK(32);
 
 static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
@@ -292,7 +188,7 @@
 	if (!card->dev->dma_mask)
 		card->dev->dma_mask = &ep93xx_pcm_dmamask;
 	if (!card->dev->coherent_dma_mask)
-		card->dev->coherent_dma_mask = 0xffffffff;
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
 	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
 		ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
diff --git a/sound/soc/ep93xx/snappercl15.c b/sound/soc/ep93xx/snappercl15.c
index ccae34a..a193cea 100644
--- a/sound/soc/ep93xx/snappercl15.c
+++ b/sound/soc/ep93xx/snappercl15.c
@@ -103,9 +103,7 @@
 	struct snd_soc_card *card = &snd_soc_snappercl15;
 	int ret;
 
-	ret = ep93xx_i2s_acquire(EP93XX_SYSCON_DEVCFG_I2SONAC97,
-				 EP93XX_SYSCON_I2SCLKDIV_ORIDE |
-				 EP93XX_SYSCON_I2SCLKDIV_SPOL);
+	ret = ep93xx_i2s_acquire();
 	if (ret)
 		return ret;
 
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 4f59bba..96bb92d 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -311,23 +311,23 @@
 	 * should allocate a DMA buffer only for the streams that are valid.
 	 */
 
-	if (pcm->streams[0].substream) {
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
 		ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
 			fsl_dma_hardware.buffer_bytes_max,
-			&pcm->streams[0].substream->dma_buffer);
+			&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer);
 		if (ret) {
 			dev_err(card->dev, "can't alloc playback dma buffer\n");
 			return ret;
 		}
 	}
 
-	if (pcm->streams[1].substream) {
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
 		ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
 			fsl_dma_hardware.buffer_bytes_max,
-			&pcm->streams[1].substream->dma_buffer);
+			&pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->dma_buffer);
 		if (ret) {
 			dev_err(card->dev, "can't alloc capture dma buffer\n");
-			snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
+			snd_dma_free_pages(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer);
 			return ret;
 		}
 	}
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 3e06696..2eb407f 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -716,12 +716,12 @@
 	}
 
 	/* Trigger the machine driver's probe function.  The platform driver
-	 * name of the machine driver is taken from the /model property of the
+	 * name of the machine driver is taken from /compatible property of the
 	 * device tree.  We also pass the address of the CPU DAI driver
 	 * structure.
 	 */
-	sprop = of_get_property(of_find_node_by_path("/"), "model", NULL);
-	/* Sometimes the model name has a "fsl," prefix, so we strip that. */
+	sprop = of_get_property(of_find_node_by_path("/"), "compatible", NULL);
+	/* Sometimes the compatible name has a "fsl," prefix, so we strip it. */
 	p = strrchr(sprop, ',');
 	if (p)
 		sprop = p + 1;
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index e7803d3..9a3f7c5 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -8,6 +8,7 @@
 
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/of_platform.h>
 
@@ -298,7 +299,7 @@
 	.hw_params	= psc_dma_hw_params,
 };
 
-static u64 psc_dma_dmamask = 0xffffffff;
+static u64 psc_dma_dmamask = DMA_BIT_MASK(32);
 static int psc_dma_new(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_card *card = rtd->card->snd_card;
@@ -314,18 +315,18 @@
 	if (!card->dev->dma_mask)
 		card->dev->dma_mask = &psc_dma_dmamask;
 	if (!card->dev->coherent_dma_mask)
-		card->dev->coherent_dma_mask = 0xffffffff;
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-	if (pcm->streams[0].substream) {
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
 		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,
-				size, &pcm->streams[0].substream->dma_buffer);
+				size, &pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer);
 		if (rc)
 			goto playback_alloc_err;
 	}
 
-	if (pcm->streams[1].substream) {
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
 		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,
-				size, &pcm->streams[1].substream->dma_buffer);
+				size, &pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->dma_buffer);
 		if (rc)
 			goto capture_alloc_err;
 	}
@@ -336,8 +337,8 @@
 	return 0;
 
  capture_alloc_err:
-	if (pcm->streams[0].substream)
-		snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
+		snd_dma_free_pages(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer);
 
  playback_alloc_err:
 	dev_err(card->dev, "Cannot allocate buffer(s)\n");
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 0ea4a5a..3fea5a1 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -58,9 +58,9 @@
 {
 	struct mpc8610_hpcd_data *machine_data =
 		container_of(card, struct mpc8610_hpcd_data, card);
-	struct ccsr_guts_86xx __iomem *guts;
+	struct ccsr_guts __iomem *guts;
 
-	guts = ioremap(guts_phys, sizeof(struct ccsr_guts_86xx));
+	guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
 	if (!guts) {
 		dev_err(card->dev, "could not map global utilities\n");
 		return -ENOMEM;
@@ -142,9 +142,9 @@
 {
 	struct mpc8610_hpcd_data *machine_data =
 		container_of(card, struct mpc8610_hpcd_data, card);
-	struct ccsr_guts_86xx __iomem *guts;
+	struct ccsr_guts __iomem *guts;
 
-	guts = ioremap(guts_phys, sizeof(struct ccsr_guts_86xx));
+	guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
 	if (!guts) {
 		dev_err(card->dev, "could not map global utilities\n");
 		return -ENOMEM;
@@ -245,7 +245,7 @@
  * 'struct device'  It's ugly and hackish, but it works.
  *
  * The dev_name for such devices include the bus number and I2C address. For
- * example, "cs4270-codec.0-004f".
+ * example, "cs4270.0-004f".
  */
 static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
 {
@@ -267,13 +267,13 @@
 	if (!i2c)
 		return -ENODEV;
 
-	snprintf(buf, len, "%s-codec.%u-%04x", temp, i2c->adapter->nr, addr);
+	snprintf(buf, len, "%s.%u-%04x", temp, i2c->adapter->nr, addr);
 
 	return 0;
 }
 
 static int get_dma_channel(struct device_node *ssi_np,
-			   const char *compatible,
+			   const char *name,
 			   struct snd_soc_dai_link *dai,
 			   unsigned int *dma_channel_id,
 			   unsigned int *dma_id)
@@ -283,7 +283,7 @@
 	const u32 *iprop;
 	int ret;
 
-	dma_channel_np = get_node_by_phandle_name(ssi_np, compatible,
+	dma_channel_np = get_node_by_phandle_name(ssi_np, name,
 						  "fsl,ssi-dma-channel");
 	if (!dma_channel_np)
 		return -EINVAL;
@@ -336,12 +336,8 @@
 	const char *sprop;
 	const u32 *iprop;
 
-	/* We are only interested in SSIs with a codec phandle in them,
-	 * so let's make sure this SSI has one. The MPC8610 HPCD only
-	 * knows about the CS4270 codec, so reject anything else.
-	 */
-	codec_np = get_node_by_phandle_name(np, "codec-handle",
-					    "cirrus,cs4270");
+	/* Find the codec node for this SSI. */
+	codec_np = of_parse_phandle(np, "codec-handle", 0);
 	if (!codec_np) {
 		dev_err(dev, "invalid codec node\n");
 		return -EINVAL;
@@ -550,7 +546,7 @@
 	.probe = mpc8610_hpcd_probe,
 	.remove = __devexit_p(mpc8610_hpcd_remove),
 	.driver = {
-		/* The name must match the 'model' property in the device tree,
+		/* The name must match 'compatible' property in the device tree,
 		 * in lowercase letters.
 		 */
 		.name = "snd-soc-mpc8610hpcd",
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index a5d4e80..982a1c9 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -46,7 +46,7 @@
  * ch: The channel on the DMA controller (0, 1, 2, or 3)
  * device: The device to set as the target (CCSR_GUTS_DMUXCR_xxx)
  */
-static inline void guts_set_dmuxcr(struct ccsr_guts_85xx __iomem *guts,
+static inline void guts_set_dmuxcr(struct ccsr_guts __iomem *guts,
 	unsigned int co, unsigned int ch, unsigned int device)
 {
 	unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
@@ -90,9 +90,9 @@
 {
 	struct machine_data *mdata =
 		container_of(card, struct machine_data, card);
-	struct ccsr_guts_85xx __iomem *guts;
+	struct ccsr_guts __iomem *guts;
 
-	guts = ioremap(guts_phys, sizeof(struct ccsr_guts_85xx));
+	guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
 	if (!guts) {
 		dev_err(card->dev, "could not map global utilities\n");
 		return -ENOMEM;
@@ -164,9 +164,9 @@
 {
 	struct machine_data *mdata =
 		container_of(card, struct machine_data, card);
-	struct ccsr_guts_85xx __iomem *guts;
+	struct ccsr_guts __iomem *guts;
 
-	guts = ioremap(guts_phys, sizeof(struct ccsr_guts_85xx));
+	guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
 	if (!guts) {
 		dev_err(card->dev, "could not map global utilities\n");
 		return -ENOMEM;
@@ -276,7 +276,7 @@
 }
 
 static int get_dma_channel(struct device_node *ssi_np,
-			   const char *compatible,
+			   const char *name,
 			   struct snd_soc_dai_link *dai,
 			   unsigned int *dma_channel_id,
 			   unsigned int *dma_id)
@@ -286,7 +286,7 @@
 	const u32 *iprop;
 	int ret;
 
-	dma_channel_np = get_node_by_phandle_name(ssi_np, compatible,
+	dma_channel_np = get_node_by_phandle_name(ssi_np, name,
 						  "fsl,ssi-dma-channel");
 	if (!dma_channel_np)
 		return -EINVAL;
@@ -395,7 +395,8 @@
 	}
 
 	if (strcasecmp(sprop, "i2s-slave") == 0) {
-		mdata->dai_format = SND_SOC_DAIFMT_I2S;
+		mdata->dai_format = SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM;
 		mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
 		mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
 
@@ -412,31 +413,38 @@
 		}
 		mdata->clk_frequency = be32_to_cpup(iprop);
 	} else if (strcasecmp(sprop, "i2s-master") == 0) {
-		mdata->dai_format = SND_SOC_DAIFMT_I2S;
+		mdata->dai_format = SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS;
 		mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
 		mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
 	} else if (strcasecmp(sprop, "lj-slave") == 0) {
-		mdata->dai_format = SND_SOC_DAIFMT_LEFT_J;
+		mdata->dai_format = SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM;
 		mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
 		mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
 	} else if (strcasecmp(sprop, "lj-master") == 0) {
-		mdata->dai_format = SND_SOC_DAIFMT_LEFT_J;
+		mdata->dai_format = SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBS_CFS;
 		mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
 		mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
 	} else if (strcasecmp(sprop, "rj-slave") == 0) {
-		mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J;
+		mdata->dai_format = SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBM_CFM;
 		mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
 		mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
 	} else if (strcasecmp(sprop, "rj-master") == 0) {
-		mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J;
+		mdata->dai_format = SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBS_CFS;
 		mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
 		mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
 	} else if (strcasecmp(sprop, "ac97-slave") == 0) {
-		mdata->dai_format = SND_SOC_DAIFMT_AC97;
+		mdata->dai_format = SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBM_CFM;
 		mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
 		mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
 	} else if (strcasecmp(sprop, "ac97-master") == 0) {
-		mdata->dai_format = SND_SOC_DAIFMT_AC97;
+		mdata->dai_format = SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBS_CFS;
 		mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
 		mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
 	} else {
@@ -543,6 +551,11 @@
 	.probe = p1022_ds_probe,
 	.remove = __devexit_p(p1022_ds_remove),
 	.driver = {
+		/*
+		 * The name must match 'compatible' property in the device tree,
+		 * in lowercase letters.
+		 */
+		.name = "snd-soc-p1022ds",
 		.owner = THIS_MODULE,
 	},
 };
@@ -556,33 +569,6 @@
 {
 	struct device_node *guts_np;
 	struct resource res;
-	const char *sprop;
-
-	/*
-	 * Check if we're actually running on a P1022DS.  Older device trees
-	 * have a model of "fsl,P1022" and newer ones use "fsl,P1022DS", so we
-	 * need to support both.  The SSI driver uses that property to link to
-	 * the machine driver, so have to match it.
-	 */
-	sprop = of_get_property(of_find_node_by_path("/"), "model", NULL);
-	if (!sprop) {
-		pr_err("snd-soc-p1022ds: missing /model node");
-		return -ENODEV;
-	}
-
-	pr_debug("snd-soc-p1022ds: board model name is %s\n", sprop);
-
-	/*
-	 * The name of this board, taken from the device tree.  Normally, this is a*
-	 * fixed string, but some P1022DS device trees have a /model property of
-	 * "fsl,P1022", and others have "fsl,P1022DS".
-	 */
-	if (strcasecmp(sprop, "fsl,p1022ds") == 0)
-		p1022_ds_driver.driver.name = "snd-soc-p1022ds";
-	else if (strcasecmp(sprop, "fsl,p1022") == 0)
-		p1022_ds_driver.driver.name = "snd-soc-p1022";
-	else
-		return -ENODEV;
 
 	/* Get the physical address of the global utilities registers */
 	guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index 7383917..810acaa 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -1,9 +1,6 @@
 menuconfig SND_IMX_SOC
 	tristate "SoC Audio for Freescale i.MX CPUs"
 	depends on ARCH_MXC
-	select SND_PCM
-	select FIQ
-	select SND_SOC_AC97_BUS
 	help
 	  Say Y or M if you want to add support for codecs attached to
 	  the i.MX SSI interface.
@@ -11,10 +8,23 @@
 
 if SND_IMX_SOC
 
-config SND_MXC_SOC_FIQ
+config SND_SOC_IMX_SSI
 	tristate
 
+config SND_SOC_IMX_PCM
+	tristate
+
+config SND_MXC_SOC_FIQ
+	tristate
+	select FIQ
+	select SND_SOC_IMX_PCM
+
 config SND_MXC_SOC_MX2
+	select SND_SOC_DMAENGINE_PCM
+	tristate
+	select SND_SOC_IMX_PCM
+
+config SND_SOC_IMX_AUDMUX
 	tristate
 
 config SND_MXC_SOC_WM1133_EV1
@@ -22,6 +32,8 @@
 	depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
 	select SND_SOC_WM8350
 	select SND_MXC_SOC_FIQ
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_IMX_SSI
 	help
 	  Enable support for audio on the i.MX31ADS with the WM1133-EV1
 	  PMIC board with WM8835x fitted.
@@ -31,6 +43,8 @@
 	depends on MACH_IMX27_VISSTRIM_M10 && I2C
 	select SND_SOC_TLV320AIC32X4
 	select SND_MXC_SOC_MX2
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_IMX_SSI
 	help
 	  Say Y if you want to add support for SoC audio on Visstrim SM10
 	  board with TLV320AIC32X4 codec.
@@ -38,8 +52,11 @@
 config SND_SOC_PHYCORE_AC97
 	tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
 	depends on MACH_PCM043 || MACH_PCA100
+	select SND_SOC_AC97_BUS
 	select SND_SOC_WM9712
 	select SND_MXC_SOC_FIQ
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_IMX_SSI
 	help
 	  Say Y if you want to add support for SoC audio on Phytec phyCORE
 	  and phyCARD boards in AC97 mode
@@ -53,6 +70,8 @@
 	depends on I2C
 	select SND_SOC_TLV320AIC23
 	select SND_MXC_SOC_FIQ
+	select SND_SOC_IMX_AUDMUX
+	select SND_SOC_IMX_SSI
 	help
 	  Enable I2S based access to the TLV320AIC23B codec attached
 	  to the SSI interface
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
index d6d609b..f5db3e9 100644
--- a/sound/soc/imx/Makefile
+++ b/sound/soc/imx/Makefile
@@ -1,11 +1,14 @@
 # i.MX Platform Support
-snd-soc-imx-objs := imx-ssi.o
-snd-soc-imx-fiq-objs := imx-pcm-fiq.o
-snd-soc-imx-mx2-objs := imx-pcm-dma-mx2.o
+snd-soc-imx-ssi-objs := imx-ssi.o
+snd-soc-imx-audmux-objs := imx-audmux.o
 
-obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o
-obj-$(CONFIG_SND_MXC_SOC_FIQ) += snd-soc-imx-fiq.o
-obj-$(CONFIG_SND_MXC_SOC_MX2) += snd-soc-imx-mx2.o
+obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o
+obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
+
+obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o
+snd-soc-imx-pcm-y := imx-pcm.o
+snd-soc-imx-pcm-$(CONFIG_SND_MXC_SOC_FIQ) += imx-pcm-fiq.o
+snd-soc-imx-pcm-$(CONFIG_SND_MXC_SOC_MX2) += imx-pcm-dma-mx2.o
 
 # i.MX Machine Support
 snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/imx/eukrea-tlv320.c
index 1c1fdd1..7d4475c 100644
--- a/sound/soc/imx/eukrea-tlv320.c
+++ b/sound/soc/imx/eukrea-tlv320.c
@@ -26,6 +26,7 @@
 
 #include "../codecs/tlv320aic23.h"
 #include "imx-ssi.h"
+#include "imx-audmux.h"
 
 #define CODEC_CLOCK 12000000
 
@@ -97,12 +98,43 @@
 static int __init eukrea_tlv320_init(void)
 {
 	int ret;
+	int int_port = 0, ext_port;
 
-	if (!machine_is_eukrea_cpuimx27() && !machine_is_eukrea_cpuimx25sd()
-		&& !machine_is_eukrea_cpuimx35sd()
-		&& !machine_is_eukrea_cpuimx51sd())
+	if (machine_is_eukrea_cpuimx27()) {
+		imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
+			IMX_AUDMUX_V1_PCR_SYN |
+			IMX_AUDMUX_V1_PCR_TFSDIR |
+			IMX_AUDMUX_V1_PCR_TCLKDIR |
+			IMX_AUDMUX_V1_PCR_RFSDIR |
+			IMX_AUDMUX_V1_PCR_RCLKDIR |
+			IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
+			IMX_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
+			IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4)
+		);
+		imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4,
+			IMX_AUDMUX_V1_PCR_SYN |
+			IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
+		);
+	} else if (machine_is_eukrea_cpuimx25sd() ||
+		   machine_is_eukrea_cpuimx35sd() ||
+		   machine_is_eukrea_cpuimx51sd()) {
+		ext_port = machine_is_eukrea_cpuimx25sd() ? 4 : 3;
+		imx_audmux_v2_configure_port(int_port,
+			IMX_AUDMUX_V2_PTCR_SYN |
+			IMX_AUDMUX_V2_PTCR_TFSDIR |
+			IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
+			IMX_AUDMUX_V2_PTCR_TCLKDIR |
+			IMX_AUDMUX_V2_PTCR_TCSEL(ext_port),
+			IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)
+		);
+		imx_audmux_v2_configure_port(ext_port,
+			IMX_AUDMUX_V2_PTCR_SYN,
+			IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)
+		);
+	} else {
 		/* return happy. We might run on a totally different machine */
 		return 0;
+	}
 
 	eukrea_tlv320_snd_device = platform_device_alloc("soc-audio", -1);
 	if (!eukrea_tlv320_snd_device)
diff --git a/sound/soc/imx/imx-audmux.c b/sound/soc/imx/imx-audmux.c
new file mode 100644
index 0000000..1765a19
--- /dev/null
+++ b/sound/soc/imx/imx-audmux.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012 Linaro Ltd.
+ * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * Initial development of this code was funded by
+ * Phytec Messtechnik GmbH, http://www.phytec.de
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "imx-audmux.h"
+
+#define DRIVER_NAME "imx-audmux"
+
+static struct clk *audmux_clk;
+static void __iomem *audmux_base;
+
+#define IMX_AUDMUX_V2_PTCR(x)		((x) * 8)
+#define IMX_AUDMUX_V2_PDCR(x)		((x) * 8 + 4)
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *audmux_debugfs_root;
+
+/* There is an annoying discontinuity in the SSI numbering with regard
+ * to the Linux number of the devices */
+static const char *audmux_port_string(int port)
+{
+	switch (port) {
+	case MX31_AUDMUX_PORT1_SSI0:
+		return "imx-ssi.0";
+	case MX31_AUDMUX_PORT2_SSI1:
+		return "imx-ssi.1";
+	case MX31_AUDMUX_PORT3_SSI_PINS_3:
+		return "SSI3";
+	case MX31_AUDMUX_PORT4_SSI_PINS_4:
+		return "SSI4";
+	case MX31_AUDMUX_PORT5_SSI_PINS_5:
+		return "SSI5";
+	case MX31_AUDMUX_PORT6_SSI_PINS_6:
+		return "SSI6";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
+				size_t count, loff_t *ppos)
+{
+	ssize_t ret;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	int port = (int)file->private_data;
+	u32 pdcr, ptcr;
+
+	if (!buf)
+		return -ENOMEM;
+
+	if (audmux_clk)
+		clk_prepare_enable(audmux_clk);
+
+	ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port));
+	pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port));
+
+	if (audmux_clk)
+		clk_disable_unprepare(audmux_clk);
+
+	ret = snprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n",
+		       pdcr, ptcr);
+
+	if (ptcr & IMX_AUDMUX_V2_PTCR_TFSDIR)
+		ret += snprintf(buf + ret, PAGE_SIZE - ret,
+				"TxFS output from %s, ",
+				audmux_port_string((ptcr >> 27) & 0x7));
+	else
+		ret += snprintf(buf + ret, PAGE_SIZE - ret,
+				"TxFS input, ");
+
+	if (ptcr & IMX_AUDMUX_V2_PTCR_TCLKDIR)
+		ret += snprintf(buf + ret, PAGE_SIZE - ret,
+				"TxClk output from %s",
+				audmux_port_string((ptcr >> 22) & 0x7));
+	else
+		ret += snprintf(buf + ret, PAGE_SIZE - ret,
+				"TxClk input");
+
+	ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
+
+	if (ptcr & IMX_AUDMUX_V2_PTCR_SYN) {
+		ret += snprintf(buf + ret, PAGE_SIZE - ret,
+				"Port is symmetric");
+	} else {
+		if (ptcr & IMX_AUDMUX_V2_PTCR_RFSDIR)
+			ret += snprintf(buf + ret, PAGE_SIZE - ret,
+					"RxFS output from %s, ",
+					audmux_port_string((ptcr >> 17) & 0x7));
+		else
+			ret += snprintf(buf + ret, PAGE_SIZE - ret,
+					"RxFS input, ");
+
+		if (ptcr & IMX_AUDMUX_V2_PTCR_RCLKDIR)
+			ret += snprintf(buf + ret, PAGE_SIZE - ret,
+					"RxClk output from %s",
+					audmux_port_string((ptcr >> 12) & 0x7));
+		else
+			ret += snprintf(buf + ret, PAGE_SIZE - ret,
+					"RxClk input");
+	}
+
+	ret += snprintf(buf + ret, PAGE_SIZE - ret,
+			"\nData received from %s\n",
+			audmux_port_string((pdcr >> 13) & 0x7));
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+
+	return ret;
+}
+
+static const struct file_operations audmux_debugfs_fops = {
+	.open = simple_open,
+	.read = audmux_read_file,
+	.llseek = default_llseek,
+};
+
+static void __init audmux_debugfs_init(void)
+{
+	int i;
+	char buf[20];
+
+	audmux_debugfs_root = debugfs_create_dir("audmux", NULL);
+	if (!audmux_debugfs_root) {
+		pr_warning("Failed to create AUDMUX debugfs root\n");
+		return;
+	}
+
+	for (i = 1; i < 8; i++) {
+		snprintf(buf, sizeof(buf), "ssi%d", i);
+		if (!debugfs_create_file(buf, 0444, audmux_debugfs_root,
+					 (void *)i, &audmux_debugfs_fops))
+			pr_warning("Failed to create AUDMUX port %d debugfs file\n",
+				   i);
+	}
+}
+
+static void __devexit audmux_debugfs_remove(void)
+{
+	debugfs_remove_recursive(audmux_debugfs_root);
+}
+#else
+static inline void audmux_debugfs_init(void)
+{
+}
+
+static inline void audmux_debugfs_remove(void)
+{
+}
+#endif
+
+enum imx_audmux_type {
+	IMX21_AUDMUX,
+	IMX31_AUDMUX,
+} audmux_type;
+
+static struct platform_device_id imx_audmux_ids[] = {
+	{
+		.name = "imx21-audmux",
+		.driver_data = IMX21_AUDMUX,
+	}, {
+		.name = "imx31-audmux",
+		.driver_data = IMX31_AUDMUX,
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(platform, imx_audmux_ids);
+
+static const struct of_device_id imx_audmux_dt_ids[] = {
+	{ .compatible = "fsl,imx21-audmux", .data = &imx_audmux_ids[0], },
+	{ .compatible = "fsl,imx31-audmux", .data = &imx_audmux_ids[1], },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_audmux_dt_ids);
+
+static const uint8_t port_mapping[] = {
+	0x0, 0x4, 0x8, 0x10, 0x14, 0x1c,
+};
+
+int imx_audmux_v1_configure_port(unsigned int port, unsigned int pcr)
+{
+	if (audmux_type != IMX21_AUDMUX)
+		return -EINVAL;
+
+	if (!audmux_base)
+		return -ENOSYS;
+
+	if (port >= ARRAY_SIZE(port_mapping))
+		return -EINVAL;
+
+	writel(pcr, audmux_base + port_mapping[port]);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(imx_audmux_v1_configure_port);
+
+int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
+		unsigned int pdcr)
+{
+	if (audmux_type != IMX31_AUDMUX)
+		return -EINVAL;
+
+	if (!audmux_base)
+		return -ENOSYS;
+
+	if (audmux_clk)
+		clk_prepare_enable(audmux_clk);
+
+	writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port));
+	writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port));
+
+	if (audmux_clk)
+		clk_disable_unprepare(audmux_clk);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(imx_audmux_v2_configure_port);
+
+static int __devinit imx_audmux_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	const struct of_device_id *of_id =
+			of_match_device(imx_audmux_dt_ids, &pdev->dev);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	audmux_base = devm_request_and_ioremap(&pdev->dev, res);
+	if (!audmux_base)
+		return -EADDRNOTAVAIL;
+
+	audmux_clk = clk_get(&pdev->dev, "audmux");
+	if (IS_ERR(audmux_clk)) {
+		dev_dbg(&pdev->dev, "cannot get clock: %ld\n",
+				PTR_ERR(audmux_clk));
+		audmux_clk = NULL;
+	}
+
+	if (of_id)
+		pdev->id_entry = of_id->data;
+	audmux_type = pdev->id_entry->driver_data;
+	if (audmux_type == IMX31_AUDMUX)
+		audmux_debugfs_init();
+
+	return 0;
+}
+
+static int __devexit imx_audmux_remove(struct platform_device *pdev)
+{
+	if (audmux_type == IMX31_AUDMUX)
+		audmux_debugfs_remove();
+	clk_put(audmux_clk);
+
+	return 0;
+}
+
+static struct platform_driver imx_audmux_driver = {
+	.probe		= imx_audmux_probe,
+	.remove		= __devexit_p(imx_audmux_remove),
+	.id_table	= imx_audmux_ids,
+	.driver	= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = imx_audmux_dt_ids,
+	}
+};
+
+static int __init imx_audmux_init(void)
+{
+	return platform_driver_register(&imx_audmux_driver);
+}
+subsys_initcall(imx_audmux_init);
+
+static void __exit imx_audmux_exit(void)
+{
+	platform_driver_unregister(&imx_audmux_driver);
+}
+module_exit(imx_audmux_exit);
+
+MODULE_DESCRIPTION("Freescale i.MX AUDMUX driver");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/sound/soc/imx/imx-audmux.h b/sound/soc/imx/imx-audmux.h
new file mode 100644
index 0000000..04ebbab
--- /dev/null
+++ b/sound/soc/imx/imx-audmux.h
@@ -0,0 +1,60 @@
+#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 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)
+
+int imx_audmux_v1_configure_port(unsigned int port, unsigned int pcr);
+
+int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
+		unsigned int pdcr);
+
+#endif /* __IMX_AUDMUX_H */
diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c
index 5780c9b..6b818de 100644
--- a/sound/soc/imx/imx-pcm-dma-mx2.c
+++ b/sound/soc/imx/imx-pcm-dma-mx2.c
@@ -21,218 +21,63 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/dmaengine.h>
+#include <linux/types.h>
 
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include <mach/dma.h>
 
-#include "imx-ssi.h"
-
-struct imx_pcm_runtime_data {
-	int period_bytes;
-	int periods;
-	int dma;
-	unsigned long offset;
-	unsigned long size;
-	void *buf;
-	int period_time;
-	struct dma_async_tx_descriptor *desc;
-	struct dma_chan *dma_chan;
-	struct imx_dma_data dma_data;
-};
-
-static void audio_dma_irq(void *data)
-{
-	struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
-
-	iprtd->offset += iprtd->period_bytes;
-	iprtd->offset %= iprtd->period_bytes * iprtd->periods;
-
-	snd_pcm_period_elapsed(substream);
-}
+#include "imx-pcm.h"
 
 static bool filter(struct dma_chan *chan, void *param)
 {
-	struct imx_pcm_runtime_data *iprtd = param;
-
 	if (!imx_dma_is_general_purpose(chan))
 		return false;
 
-        chan->private = &iprtd->dma_data;
+	chan->private = param;
 
-        return true;
-}
-
-static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct imx_pcm_dma_params *dma_params;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
-	struct dma_slave_config slave_config;
-	dma_cap_mask_t mask;
-	enum dma_slave_buswidth buswidth;
-	int ret;
-
-	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-	iprtd->dma_data.peripheral_type = IMX_DMATYPE_SSI;
-	iprtd->dma_data.priority = DMA_PRIO_HIGH;
-	iprtd->dma_data.dma_request = dma_params->dma;
-
-	/* Try to grab a DMA channel */
-	if (!iprtd->dma_chan) {
-		dma_cap_zero(mask);
-		dma_cap_set(DMA_SLAVE, mask);
-		iprtd->dma_chan = dma_request_channel(mask, filter, iprtd);
-		if (!iprtd->dma_chan)
-			return -EINVAL;
-	}
-
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S16_LE:
-		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
-		break;
-	case SNDRV_PCM_FORMAT_S20_3LE:
-	case SNDRV_PCM_FORMAT_S24_LE:
-		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
-		break;
-	default:
-		return 0;
-	}
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		slave_config.direction = DMA_MEM_TO_DEV;
-		slave_config.dst_addr = dma_params->dma_addr;
-		slave_config.dst_addr_width = buswidth;
-		slave_config.dst_maxburst = dma_params->burstsize;
-	} else {
-		slave_config.direction = DMA_DEV_TO_MEM;
-		slave_config.src_addr = dma_params->dma_addr;
-		slave_config.src_addr_width = buswidth;
-		slave_config.src_maxburst = dma_params->burstsize;
-	}
-
-	ret = dmaengine_slave_config(iprtd->dma_chan, &slave_config);
-	if (ret)
-		return ret;
-
-	return 0;
+	return true;
 }
 
 static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
-	unsigned long dma_addr;
-	struct dma_chan *chan;
+	struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
 	struct imx_pcm_dma_params *dma_params;
+	struct dma_slave_config slave_config;
 	int ret;
 
 	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-	ret = imx_ssi_dma_alloc(substream, params);
+
+	ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config);
 	if (ret)
 		return ret;
-	chan = iprtd->dma_chan;
 
-	iprtd->size = params_buffer_bytes(params);
-	iprtd->periods = params_periods(params);
-	iprtd->period_bytes = params_period_bytes(params);
-	iprtd->offset = 0;
-	iprtd->period_time = HZ / (params_rate(params) /
-			params_period_size(params));
+	slave_config.device_fc = false;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		slave_config.dst_addr = dma_params->dma_addr;
+		slave_config.dst_maxburst = dma_params->burstsize;
+	} else {
+		slave_config.src_addr = dma_params->dma_addr;
+		slave_config.src_maxburst = dma_params->burstsize;
+	}
+
+	ret = dmaengine_slave_config(chan, &slave_config);
+	if (ret)
+		return ret;
 
 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 
-	dma_addr = runtime->dma_addr;
-
-	iprtd->buf = (unsigned int *)substream->dma_buffer.area;
-
-	iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr,
-			iprtd->period_bytes * iprtd->periods,
-			iprtd->period_bytes,
-			substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-			DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
-	if (!iprtd->desc) {
-		dev_err(&chan->dev->device, "cannot prepare slave dma\n");
-		return -EINVAL;
-	}
-
-	iprtd->desc->callback = audio_dma_irq;
-	iprtd->desc->callback_param = substream;
-
 	return 0;
 }
 
-static int snd_imx_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
-
-	if (iprtd->dma_chan) {
-		dma_release_channel(iprtd->dma_chan);
-		iprtd->dma_chan = NULL;
-	}
-
-	return 0;
-}
-
-static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct imx_pcm_dma_params *dma_params;
-
-	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-	return 0;
-}
-
-static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		dmaengine_submit(iprtd->desc);
-
-		break;
-
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		dmaengine_terminate_all(iprtd->dma_chan);
-
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
-
-	pr_debug("%s: %ld %ld\n", __func__, iprtd->offset,
-			bytes_to_frames(substream->runtime, iprtd->offset));
-
-	return bytes_to_frames(substream->runtime, iprtd->offset);
-}
-
 static struct snd_pcm_hardware snd_imx_hardware = {
 	.info = SNDRV_PCM_INFO_INTERLEAVED |
 		SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -254,33 +99,37 @@
 
 static int snd_imx_open(struct snd_pcm_substream *substream)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct imx_pcm_runtime_data *iprtd;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct imx_pcm_dma_params *dma_params;
+	struct imx_dma_data *dma_data;
 	int ret;
 
-	iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
-	if (iprtd == NULL)
-		return -ENOMEM;
-	runtime->private_data = iprtd;
+	snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
 
-	ret = snd_pcm_hw_constraint_integer(substream->runtime,
-			SNDRV_PCM_HW_PARAM_PERIODS);
-	if (ret < 0) {
-		kfree(iprtd);
-		return ret;
+	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+	dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL);
+	dma_data->peripheral_type = IMX_DMATYPE_SSI;
+	dma_data->priority = DMA_PRIO_HIGH;
+	dma_data->dma_request = dma_params->dma;
+
+	ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
+	if (ret) {
+		kfree(dma_data);
+		return 0;
 	}
 
-	snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
+	snd_dmaengine_pcm_set_data(substream, dma_data);
 
 	return 0;
 }
 
 static int snd_imx_close(struct snd_pcm_substream *substream)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+	struct imx_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
 
-	kfree(iprtd);
+	snd_dmaengine_pcm_close(substream);
+	kfree(dma_data);
 
 	return 0;
 }
@@ -290,10 +139,8 @@
 	.close		= snd_imx_close,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= snd_imx_pcm_hw_params,
-	.hw_free	= snd_imx_pcm_hw_free,
-	.prepare	= snd_imx_pcm_prepare,
-	.trigger	= snd_imx_pcm_trigger,
-	.pointer	= snd_imx_pcm_pointer,
+	.trigger	= snd_dmaengine_pcm_trigger,
+	.pointer	= snd_dmaengine_pcm_pointer,
 	.mmap		= snd_imx_pcm_mmap,
 };
 
@@ -305,11 +152,6 @@
 
 static int __devinit imx_soc_platform_probe(struct platform_device *pdev)
 {
-	struct imx_ssi *ssi = platform_get_drvdata(pdev);
-
-	ssi->dma_params_tx.burstsize = 6;
-	ssi->dma_params_rx.burstsize = 4;
-
 	return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2);
 }
 
diff --git a/sound/soc/imx/imx-pcm.c b/sound/soc/imx/imx-pcm.c
new file mode 100644
index 0000000..93dc360b
--- /dev/null
+++ b/sound/soc/imx/imx-pcm.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This code is based on code copyrighted by Freescale,
+ * Liam Girdwood, Javier Martin and probably others.
+ *
+ * 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/dma-mapping.h>
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include "imx-pcm.h"
+
+int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
+		struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int ret;
+
+	ret = dma_mmap_writecombine(substream->pcm->card->dev, vma,
+		runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
+
+	pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
+			runtime->dma_area,
+			runtime->dma_addr,
+			runtime->dma_bytes);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap);
+
+static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = IMX_SSI_DMABUF_SIZE;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+	buf->bytes = size;
+
+	return 0;
+}
+
+static u64 imx_pcm_dmamask = DMA_BIT_MASK(32);
+
+int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	struct snd_pcm *pcm = rtd->pcm;
+	int ret = 0;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &imx_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+		ret = imx_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			goto out;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+		ret = imx_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			goto out;
+	}
+
+out:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(imx_pcm_new);
+
+void imx_pcm_free(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_writecombine(pcm->card->dev, buf->bytes,
+				      buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(imx_pcm_free);
diff --git a/sound/soc/imx/imx-pcm.h b/sound/soc/imx/imx-pcm.h
new file mode 100644
index 0000000..b5f5c3a
--- /dev/null
+++ b/sound/soc/imx/imx-pcm.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This code is based on code copyrighted by Freescale,
+ * Liam Girdwood, Javier Martin and probably others.
+ *
+ * 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 _IMX_PCM_H
+#define _IMX_PCM_H
+
+/*
+ * Do not change this as the FIQ handler depends on this size
+ */
+#define IMX_SSI_DMABUF_SIZE	(64 * 1024)
+
+struct imx_pcm_dma_params {
+	int dma;
+	unsigned long dma_addr;
+	int burstsize;
+};
+
+int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
+		     struct vm_area_struct *vma);
+int imx_pcm_new(struct snd_soc_pcm_runtime *rtd);
+void imx_pcm_free(struct snd_pcm *pcm);
+
+#endif /* _IMX_PCM_H */
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index b6adbed..4f81ed4 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -233,6 +233,23 @@
 	return 0;
 }
 
+static int imx_ssi_startup(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *cpu_dai)
+{
+	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
+	struct imx_pcm_dma_params *dma_data;
+
+	/* Tx/Rx config */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_data = &ssi->dma_params_tx;
+	else
+		dma_data = &ssi->dma_params_rx;
+
+	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+
+	return 0;
+}
+
 /*
  * Should only be called when port is inactive (i.e. SSIEN = 0),
  * although can be called multiple times by upper layers.
@@ -242,23 +259,17 @@
 			     struct snd_soc_dai *cpu_dai)
 {
 	struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-	struct imx_pcm_dma_params *dma_data;
 	u32 reg, sccr;
 
 	/* Tx/Rx config */
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		reg = SSI_STCCR;
-		dma_data = &ssi->dma_params_tx;
-	} else {
+	else
 		reg = SSI_SRCCR;
-		dma_data = &ssi->dma_params_rx;
-	}
 
 	if (ssi->flags & IMX_SSI_SYN)
 		reg = SSI_STCCR;
 
-	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
-
 	sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK;
 
 	/* DAI data (word) size */
@@ -343,6 +354,7 @@
 }
 
 static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
+	.startup	= imx_ssi_startup,
 	.hw_params	= imx_ssi_hw_params,
 	.set_fmt	= imx_ssi_set_dai_fmt,
 	.set_clkdiv	= imx_ssi_set_dai_clkdiv,
@@ -351,94 +363,6 @@
 	.trigger	= imx_ssi_trigger,
 };
 
-int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
-		struct vm_area_struct *vma)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	int ret;
-
-	ret = dma_mmap_writecombine(substream->pcm->card->dev, vma,
-		runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
-
-	pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
-			runtime->dma_area,
-			runtime->dma_addr,
-			runtime->dma_bytes);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap);
-
-static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-	struct snd_dma_buffer *buf = &substream->dma_buffer;
-	size_t size = IMX_SSI_DMABUF_SIZE;
-
-	buf->dev.type = SNDRV_DMA_TYPE_DEV;
-	buf->dev.dev = pcm->card->dev;
-	buf->private_data = NULL;
-	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-					   &buf->addr, GFP_KERNEL);
-	if (!buf->area)
-		return -ENOMEM;
-	buf->bytes = size;
-
-	return 0;
-}
-
-static u64 imx_pcm_dmamask = DMA_BIT_MASK(32);
-
-int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_card *card = rtd->card->snd_card;
-	struct snd_pcm *pcm = rtd->pcm;
-	int ret = 0;
-
-	if (!card->dev->dma_mask)
-		card->dev->dma_mask = &imx_pcm_dmamask;
-	if (!card->dev->coherent_dma_mask)
-		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-		ret = imx_pcm_preallocate_dma_buffer(pcm,
-			SNDRV_PCM_STREAM_PLAYBACK);
-		if (ret)
-			goto out;
-	}
-
-	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-		ret = imx_pcm_preallocate_dma_buffer(pcm,
-			SNDRV_PCM_STREAM_CAPTURE);
-		if (ret)
-			goto out;
-	}
-
-out:
-	return ret;
-}
-EXPORT_SYMBOL_GPL(imx_pcm_new);
-
-void imx_pcm_free(struct snd_pcm *pcm)
-{
-	struct snd_pcm_substream *substream;
-	struct snd_dma_buffer *buf;
-	int stream;
-
-	for (stream = 0; stream < 2; stream++) {
-		substream = pcm->streams[stream].substream;
-		if (!substream)
-			continue;
-
-		buf = &substream->dma_buffer;
-		if (!buf->area)
-			continue;
-
-		dma_free_writecombine(pcm->card->dev, buf->bytes,
-				      buf->area, buf->addr);
-		buf->area = NULL;
-	}
-}
-EXPORT_SYMBOL_GPL(imx_pcm_free);
-
 static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
 {
 	struct imx_ssi *ssi = dev_get_drvdata(dai->dev);
@@ -656,7 +580,7 @@
 	ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0;
 	ssi->dma_params_tx.dma_addr = res->start + SSI_STX0;
 
-	ssi->dma_params_tx.burstsize = 4;
+	ssi->dma_params_tx.burstsize = 6;
 	ssi->dma_params_rx.burstsize = 4;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h
index 1072dfb..5744e86 100644
--- a/sound/soc/imx/imx-ssi.h
+++ b/sound/soc/imx/imx-ssi.h
@@ -187,12 +187,7 @@
 
 #include <linux/dmaengine.h>
 #include <mach/dma.h>
-
-struct imx_pcm_dma_params {
-	int dma;
-	unsigned long dma_addr;
-	int burstsize;
-};
+#include "imx-pcm.h"
 
 struct imx_ssi {
 	struct platform_device *ac97_dev;
@@ -218,13 +213,4 @@
 	struct platform_device *soc_platform_pdev_fiq;
 };
 
-int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma);
-int imx_pcm_new(struct snd_soc_pcm_runtime *rtd);
-void imx_pcm_free(struct snd_pcm *pcm);
-
-/*
- * Do not change this as the FIQ handler depends on this size
- */
-#define IMX_SSI_DMABUF_SIZE	(64 * 1024)
-
 #endif /* _IMX_SSI_H */
diff --git a/sound/soc/imx/mx27vis-aic32x4.c b/sound/soc/imx/mx27vis-aic32x4.c
index 3c2eed9..f6d04ad 100644
--- a/sound/soc/imx/mx27vis-aic32x4.c
+++ b/sound/soc/imx/mx27vis-aic32x4.c
@@ -25,15 +25,36 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/i2c.h>
+#include <linux/gpio.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include <sound/tlv.h>
 #include <asm/mach-types.h>
-#include <mach/audmux.h>
+#include <mach/iomux-mx27.h>
 
 #include "../codecs/tlv320aic32x4.h"
 #include "imx-ssi.h"
+#include "imx-audmux.h"
+
+#define MX27VIS_AMP_GAIN	0
+#define MX27VIS_AMP_MUTE	1
+
+#define MX27VIS_PIN_G0		(GPIO_PORTF + 9)
+#define MX27VIS_PIN_G1		(GPIO_PORTF + 8)
+#define MX27VIS_PIN_SDL		(GPIO_PORTE + 5)
+#define MX27VIS_PIN_SDR		(GPIO_PORTF + 7)
+
+static int mx27vis_amp_gain;
+static int mx27vis_amp_mute;
+
+static const int mx27vis_amp_pins[] = {
+	MX27VIS_PIN_G0 | GPIO_GPIO | GPIO_OUT,
+	MX27VIS_PIN_G1 | GPIO_GPIO | GPIO_OUT,
+	MX27VIS_PIN_SDL | GPIO_GPIO | GPIO_OUT,
+	MX27VIS_PIN_SDR | GPIO_GPIO | GPIO_OUT,
+};
 
 static int mx27vis_aic32x4_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params)
@@ -74,6 +95,76 @@
 	.hw_params	= mx27vis_aic32x4_hw_params,
 };
 
+static int mx27vis_amp_set(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	int value = ucontrol->value.integer.value[0];
+	unsigned int reg = mc->reg;
+	int max = mc->max;
+
+	if (value > max)
+		return -EINVAL;
+
+	switch (reg) {
+	case MX27VIS_AMP_GAIN:
+		gpio_set_value(MX27VIS_PIN_G0, value & 1);
+		gpio_set_value(MX27VIS_PIN_G1, value >> 1);
+		mx27vis_amp_gain = value;
+		break;
+	case MX27VIS_AMP_MUTE:
+		gpio_set_value(MX27VIS_PIN_SDL, value & 1);
+		gpio_set_value(MX27VIS_PIN_SDR, value >> 1);
+		mx27vis_amp_mute = value;
+		break;
+	}
+	return 0;
+}
+
+static int mx27vis_amp_get(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;
+
+	switch (reg) {
+	case MX27VIS_AMP_GAIN:
+		ucontrol->value.integer.value[0] = mx27vis_amp_gain;
+		break;
+	case MX27VIS_AMP_MUTE:
+		ucontrol->value.integer.value[0] = mx27vis_amp_mute;
+		break;
+	}
+	return 0;
+}
+
+/* From 6dB to 24dB in steps of 6dB */
+static const DECLARE_TLV_DB_SCALE(mx27vis_amp_tlv, 600, 600, 0);
+
+static const struct snd_kcontrol_new mx27vis_aic32x4_controls[] = {
+	SOC_DAPM_PIN_SWITCH("External Mic"),
+	SOC_SINGLE_EXT_TLV("LO Ext Boost", MX27VIS_AMP_GAIN, 0, 3, 0,
+		       mx27vis_amp_get, mx27vis_amp_set, mx27vis_amp_tlv),
+	SOC_DOUBLE_EXT("LO Ext Mute Switch", MX27VIS_AMP_MUTE, 0, 1, 1, 0,
+		       mx27vis_amp_get, mx27vis_amp_set),
+};
+
+static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = {
+	SND_SOC_DAPM_MIC("External Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
+	{"Mic Bias", NULL, "External Mic"},
+	{"IN1_R", NULL, "Mic Bias"},
+	{"IN2_R", NULL, "Mic Bias"},
+	{"IN3_R", NULL, "Mic Bias"},
+	{"IN1_L", NULL, "Mic Bias"},
+	{"IN2_L", NULL, "Mic Bias"},
+	{"IN3_L", NULL, "Mic Bias"},
+};
+
 static struct snd_soc_dai_link mx27vis_aic32x4_dai = {
 	.name		= "tlv320aic32x4",
 	.stream_name	= "TLV320AIC32X4",
@@ -89,50 +180,66 @@
 	.owner		= THIS_MODULE,
 	.dai_link	= &mx27vis_aic32x4_dai,
 	.num_links	= 1,
+	.controls	= mx27vis_aic32x4_controls,
+	.num_controls	= ARRAY_SIZE(mx27vis_aic32x4_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 struct platform_device *mx27vis_aic32x4_snd_device;
-
-static int __init mx27vis_aic32x4_init(void)
+static int __devinit mx27vis_aic32x4_probe(struct platform_device *pdev)
 {
 	int ret;
 
-	mx27vis_aic32x4_snd_device = platform_device_alloc("soc-audio", -1);
-	if (!mx27vis_aic32x4_snd_device)
-		return -ENOMEM;
-
-	platform_set_drvdata(mx27vis_aic32x4_snd_device, &mx27vis_aic32x4);
-	ret = platform_device_add(mx27vis_aic32x4_snd_device);
-
+	mx27vis_aic32x4.dev = &pdev->dev;
+	ret = snd_soc_register_card(&mx27vis_aic32x4);
 	if (ret) {
-		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
-		platform_device_put(mx27vis_aic32x4_snd_device);
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+			ret);
+		return ret;
 	}
 
 	/* Connect SSI0 as clock slave to SSI1 external pins */
-	mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
-			MXC_AUDMUX_V1_PCR_SYN |
-			MXC_AUDMUX_V1_PCR_TFSDIR |
-			MXC_AUDMUX_V1_PCR_TCLKDIR |
-			MXC_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) |
-			MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1)
+	imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
+			IMX_AUDMUX_V1_PCR_SYN |
+			IMX_AUDMUX_V1_PCR_TFSDIR |
+			IMX_AUDMUX_V1_PCR_TCLKDIR |
+			IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) |
+			IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1)
 	);
-	mxc_audmux_v1_configure_port(MX27_AUDMUX_PPCR1_SSI_PINS_1,
-			MXC_AUDMUX_V1_PCR_SYN |
-			MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
+	imx_audmux_v1_configure_port(MX27_AUDMUX_PPCR1_SSI_PINS_1,
+			IMX_AUDMUX_V1_PCR_SYN |
+			IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
 	);
 
+	ret = mxc_gpio_setup_multiple_pins(mx27vis_amp_pins,
+			ARRAY_SIZE(mx27vis_amp_pins), "MX27VIS_AMP");
+	if (ret)
+		printk(KERN_ERR "ASoC: unable to setup gpios\n");
+
 	return ret;
 }
 
-static void __exit mx27vis_aic32x4_exit(void)
+static int __devexit mx27vis_aic32x4_remove(struct platform_device *pdev)
 {
-	platform_device_unregister(mx27vis_aic32x4_snd_device);
+	snd_soc_unregister_card(&mx27vis_aic32x4);
+
+	return 0;
 }
 
-module_init(mx27vis_aic32x4_init);
-module_exit(mx27vis_aic32x4_exit);
+static struct platform_driver mx27vis_aic32x4_audio_driver = {
+	.driver = {
+		.name = "mx27vis",
+		.owner = THIS_MODULE,
+	},
+	.probe = mx27vis_aic32x4_probe,
+	.remove = __devexit_p(mx27vis_aic32x4_remove),
+};
+
+module_platform_driver(mx27vis_aic32x4_audio_driver);
 
 MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
 MODULE_DESCRIPTION("ALSA SoC AIC32X4 mx27 visstrim");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mx27vis");
diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/imx/phycore-ac97.c
index 6ac1211..f8da6dd 100644
--- a/sound/soc/imx/phycore-ac97.c
+++ b/sound/soc/imx/phycore-ac97.c
@@ -19,6 +19,8 @@
 #include <sound/soc.h>
 #include <asm/mach-types.h>
 
+#include "imx-audmux.h"
+
 static struct snd_soc_card imx_phycore;
 
 static struct snd_soc_ops imx_phycore_hifi_ops = {
@@ -50,9 +52,32 @@
 {
 	int ret;
 
-	if (!machine_is_pcm043() && !machine_is_pca100())
+	if (machine_is_pca100()) {
+		imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
+			IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */
+			IMX_AUDMUX_V1_PCR_TFCSEL(3) |
+			IMX_AUDMUX_V1_PCR_TCLKDIR | /* clock is output */
+			IMX_AUDMUX_V1_PCR_RXDSEL(3));
+		imx_audmux_v1_configure_port(3,
+			IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */
+			IMX_AUDMUX_V1_PCR_TFCSEL(0) |
+			IMX_AUDMUX_V1_PCR_TFSDIR |
+			IMX_AUDMUX_V1_PCR_RXDSEL(0));
+	} else if (machine_is_pcm043()) {
+		imx_audmux_v2_configure_port(3,
+			IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
+			IMX_AUDMUX_V2_PTCR_TFSEL(0) |
+			IMX_AUDMUX_V2_PTCR_TFSDIR,
+			IMX_AUDMUX_V2_PDCR_RXDSEL(0));
+		imx_audmux_v2_configure_port(0,
+			IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
+			IMX_AUDMUX_V2_PTCR_TCSEL(3) |
+			IMX_AUDMUX_V2_PTCR_TCLKDIR, /* clock is output */
+			IMX_AUDMUX_V2_PDCR_RXDSEL(3));
+	} else {
 		/* return happy. We might run on a totally different machine */
 		return 0;
+	}
 
 	imx_phycore_snd_ac97_device = platform_device_alloc("soc-audio", -1);
 	if (!imx_phycore_snd_ac97_device)
diff --git a/sound/soc/imx/wm1133-ev1.c b/sound/soc/imx/wm1133-ev1.c
index 37480c9..fe54a69 100644
--- a/sound/soc/imx/wm1133-ev1.c
+++ b/sound/soc/imx/wm1133-ev1.c
@@ -21,10 +21,9 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 
-#include <mach/audmux.h>
-
 #include "imx-ssi.h"
 #include "../codecs/wm8350.h"
+#include "imx-audmux.h"
 
 /* There is a silicon mic on the board optionally connected via a solder pad
  * SP1.  Define this to enable it.
@@ -268,17 +267,17 @@
 	unsigned int ptcr, pdcr;
 
 	/* SSI0 mastered by port 5 */
-	ptcr = MXC_AUDMUX_V2_PTCR_SYN |
-		MXC_AUDMUX_V2_PTCR_TFSDIR |
-		MXC_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT5_SSI_PINS_5) |
-		MXC_AUDMUX_V2_PTCR_TCLKDIR |
-		MXC_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT5_SSI_PINS_5);
-	pdcr = MXC_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT5_SSI_PINS_5);
-	mxc_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0, ptcr, pdcr);
+	ptcr = IMX_AUDMUX_V2_PTCR_SYN |
+		IMX_AUDMUX_V2_PTCR_TFSDIR |
+		IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT5_SSI_PINS_5) |
+		IMX_AUDMUX_V2_PTCR_TCLKDIR |
+		IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT5_SSI_PINS_5);
+	pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT5_SSI_PINS_5);
+	imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0, ptcr, pdcr);
 
-	ptcr = MXC_AUDMUX_V2_PTCR_SYN;
-	pdcr = MXC_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0);
-	mxc_audmux_v2_configure_port(MX31_AUDMUX_PORT5_SSI_PINS_5, ptcr, pdcr);
+	ptcr = IMX_AUDMUX_V2_PTCR_SYN;
+	pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0);
+	imx_audmux_v2_configure_port(MX31_AUDMUX_PORT5_SSI_PINS_5, ptcr, pdcr);
 
 	wm1133_ev1_snd_device = platform_device_alloc("soc-audio", -1);
 	if (!wm1133_ev1_snd_device)
diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c
index 0097c3b..e8aaff1 100644
--- a/sound/soc/jz4740/qi_lb60.c
+++ b/sound/soc/jz4740/qi_lb60.c
@@ -91,56 +91,52 @@
 	.num_dapm_routes = ARRAY_SIZE(qi_lb60_routes),
 };
 
-static struct platform_device *qi_lb60_snd_device;
-
 static const struct gpio qi_lb60_gpios[] = {
 	{ QI_LB60_SND_GPIO, GPIOF_OUT_INIT_LOW, "SND" },
 	{ QI_LB60_AMP_GPIO, GPIOF_OUT_INIT_LOW, "AMP" },
 };
 
-static int __init qi_lb60_init(void)
+static int __devinit qi_lb60_probe(struct platform_device *pdev)
 {
+	struct snd_soc_card *card = &qi_lb60;
 	int ret;
 
-	qi_lb60_snd_device = platform_device_alloc("soc-audio", -1);
-
-	if (!qi_lb60_snd_device)
-		return -ENOMEM;
-
 	ret = gpio_request_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
+	if (ret)
+		return ret;
+
+	card->dev = &pdev->dev;
+
+	ret = snd_soc_register_card(card);
 	if (ret) {
-		pr_err("qi_lb60 snd: Failed to request gpios: %d\n", ret);
-		goto err_device_put;
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+		gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
 	}
-
-	platform_set_drvdata(qi_lb60_snd_device, &qi_lb60);
-
-	ret = platform_device_add(qi_lb60_snd_device);
-	if (ret) {
-		pr_err("qi_lb60 snd: Failed to add snd soc device: %d\n", ret);
-		goto err_unset_pdata;
-	}
-
-	 return 0;
-
-err_unset_pdata:
-	platform_set_drvdata(qi_lb60_snd_device, NULL);
-/*err_gpio_free_array:*/
-	gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
-err_device_put:
-	platform_device_put(qi_lb60_snd_device);
-
 	return ret;
 }
-module_init(qi_lb60_init);
 
-static void __exit qi_lb60_exit(void)
+static int __devexit qi_lb60_remove(struct platform_device *pdev)
 {
-	platform_device_unregister(qi_lb60_snd_device);
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(card);
 	gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
+	return 0;
 }
-module_exit(qi_lb60_exit);
+
+static struct platform_driver qi_lb60_driver = {
+	.driver		= {
+		.name	= "qi-lb60-audio",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= qi_lb60_probe,
+	.remove		= __devexit_p(qi_lb60_remove),
+};
+
+module_platform_driver(qi_lb60_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("ALSA SoC QI LB60 Audio support");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:qi-lb60-audio");
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index d038540..b9f1659 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -55,7 +55,7 @@
 	.fifo_size		= 0,
 };
 
-static u64 kirkwood_dma_dmamask = 0xFFFFFFFFUL;
+static u64 kirkwood_dma_dmamask = DMA_BIT_MASK(32);
 
 static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id)
 {
@@ -324,7 +324,7 @@
 	if (!card->dev->dma_mask)
 		card->dev->dma_mask = &kirkwood_dma_dmamask;
 	if (!card->dev->coherent_dma_mask)
-		card->dev->coherent_dma_mask = 0xffffffff;
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
 	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
 		ret = kirkwood_dma_preallocate_dma_buffer(pcm,
diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c
index 55d2ed3..80bd59c 100644
--- a/sound/soc/kirkwood/kirkwood-openrd.c
+++ b/sound/soc/kirkwood/kirkwood-openrd.c
@@ -71,41 +71,41 @@
 	.num_links = ARRAY_SIZE(openrd_client_dai),
 };
 
-static struct platform_device *openrd_client_snd_device;
-
-static int __init openrd_client_init(void)
+static int __devinit openrd_probe(struct platform_device *pdev)
 {
+	struct snd_soc_card *card = &openrd_client;
 	int ret;
 
-	if (!machine_is_openrd_client() && !machine_is_openrd_ultimate())
-		return 0;
+	card->dev = &pdev->dev;
 
-	openrd_client_snd_device = platform_device_alloc("soc-audio", -1);
-	if (!openrd_client_snd_device)
-		return -ENOMEM;
-
-	platform_set_drvdata(openrd_client_snd_device,
-			&openrd_client);
-
-	ret = platform_device_add(openrd_client_snd_device);
-	if (ret) {
-		printk(KERN_ERR "%s: platform_device_add failed\n", __func__);
-		platform_device_put(openrd_client_snd_device);
-	}
-
+	ret = snd_soc_register_card(card);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
 	return ret;
 }
 
-static void __exit openrd_client_exit(void)
+static int __devexit openrd_remove(struct platform_device *pdev)
 {
-	platform_device_unregister(openrd_client_snd_device);
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(card);
+	return 0;
 }
 
-module_init(openrd_client_init);
-module_exit(openrd_client_exit);
+static struct platform_driver openrd_driver = {
+	.driver		= {
+		.name	= "openrd-client-audio",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= openrd_probe,
+	.remove		= __devexit_p(openrd_remove),
+};
+
+module_platform_driver(openrd_driver);
 
 /* Module information */
 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("ALSA SoC OpenRD Client");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:soc-audio");
+MODULE_ALIAS("platform:openrd-client-audio");
diff --git a/sound/soc/kirkwood/kirkwood-t5325.c b/sound/soc/kirkwood/kirkwood-t5325.c
index b47cc4e..f898363 100644
--- a/sound/soc/kirkwood/kirkwood-t5325.c
+++ b/sound/soc/kirkwood/kirkwood-t5325.c
@@ -80,7 +80,6 @@
 },
 };
 
-
 static struct snd_soc_card t5325 = {
 	.name = "t5325",
 	.owner = THIS_MODULE,
@@ -93,38 +92,40 @@
 	.num_dapm_routes = ARRAY_SIZE(t5325_route),
 };
 
-static struct platform_device *t5325_snd_device;
-
-static int __init t5325_init(void)
+static int __devinit t5325_probe(struct platform_device *pdev)
 {
+	struct snd_soc_card *card = &t5325;
 	int ret;
 
-	if (!machine_is_t5325())
-		return 0;
+	card->dev = &pdev->dev;
 
-	t5325_snd_device = platform_device_alloc("soc-audio", -1);
-	if (!t5325_snd_device)
-		return -ENOMEM;
-
-	platform_set_drvdata(t5325_snd_device,
-			&t5325);
-
-	ret = platform_device_add(t5325_snd_device);
-	if (ret) {
-		printk(KERN_ERR "%s: platform_device_add failed\n", __func__);
-		platform_device_put(t5325_snd_device);
-	}
-
+	ret = snd_soc_register_card(card);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
 	return ret;
 }
-module_init(t5325_init);
 
-static void __exit t5325_exit(void)
+static int __devexit t5325_remove(struct platform_device *pdev)
 {
-	platform_device_unregister(t5325_snd_device);
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(card);
+	return 0;
 }
-module_exit(t5325_exit);
+
+static struct platform_driver t5325_driver = {
+	.driver		= {
+		.name	= "t5325-audio",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= t5325_probe,
+	.remove		= __devexit_p(t5325_remove),
+};
+
+module_platform_driver(t5325_driver);
 
 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("ALSA SoC t5325 audio client");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:t5325-audio");
diff --git a/sound/soc/mid-x86/mfld_machine.c b/sound/soc/mid-x86/mfld_machine.c
index 6f77eef..2937e54 100644
--- a/sound/soc/mid-x86/mfld_machine.c
+++ b/sound/soc/mid-x86/mfld_machine.c
@@ -235,7 +235,7 @@
 	snd_soc_dapm_enable_pin(dapm, "Headphones");
 	snd_soc_dapm_enable_pin(dapm, "Mic");
 
-	ret_val = snd_soc_add_controls(codec, mfld_snd_controls,
+	ret_val = snd_soc_add_codec_controls(codec, mfld_snd_controls,
 				ARRAY_SIZE(mfld_snd_controls));
 	if (ret_val) {
 		pr_err("soc_add_controls failed %d", ret_val);
diff --git a/sound/soc/mxs/Kconfig b/sound/soc/mxs/Kconfig
index e4ba8d5..99a997f 100644
--- a/sound/soc/mxs/Kconfig
+++ b/sound/soc/mxs/Kconfig
@@ -1,7 +1,7 @@
 menuconfig SND_MXS_SOC
 	tristate "SoC Audio for Freescale MXS CPUs"
 	depends on ARCH_MXS
-	select SND_PCM
+	select SND_SOC_DMAENGINE_PCM
 	help
 	  Say Y or M if you want to add support for codecs attached to
 	  the MXS SAIF interface.
diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
index 105f42a..e373fbb 100644
--- a/sound/soc/mxs/mxs-pcm.c
+++ b/sound/soc/mxs/mxs-pcm.c
@@ -28,16 +28,22 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/dmaengine.h>
+#include <linux/fsl/mxs-dma.h>
 
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
-#include <mach/dma.h>
 #include "mxs-pcm.h"
 
+struct mxs_pcm_dma_data {
+	struct mxs_dma_data dma_data;
+	struct mxs_pcm_dma_params *dma_params;
+};
+
 static struct snd_pcm_hardware snd_mxs_hardware = {
 	.info			= SNDRV_PCM_INFO_MMAP |
 				  SNDRV_PCM_INFO_MMAP_VALID |
@@ -58,21 +64,10 @@
 
 };
 
-static void audio_dma_irq(void *data)
-{
-	struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
-
-	iprtd->offset += iprtd->period_bytes;
-	iprtd->offset %= iprtd->period_bytes * iprtd->periods;
-	snd_pcm_period_elapsed(substream);
-}
-
 static bool filter(struct dma_chan *chan, void *param)
 {
-	struct mxs_pcm_runtime_data *iprtd = param;
-	struct mxs_pcm_dma_params *dma_params = iprtd->dma_params;
+	struct mxs_pcm_dma_data *pcm_dma_data = param;
+	struct mxs_pcm_dma_params *dma_params = pcm_dma_data->dma_params;
 
 	if (!mxs_dma_is_apbx(chan))
 		return false;
@@ -80,150 +75,51 @@
 	if (chan->chan_id != dma_params->chan_num)
 		return false;
 
-	chan->private = &iprtd->dma_data;
+	chan->private = &pcm_dma_data->dma_data;
 
 	return true;
 }
 
-static int mxs_dma_alloc(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
-	dma_cap_mask_t mask;
-
-	iprtd->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-	dma_cap_zero(mask);
-	dma_cap_set(DMA_SLAVE, mask);
-	iprtd->dma_data.chan_irq = iprtd->dma_params->chan_irq;
-	iprtd->dma_chan = dma_request_channel(mask, filter, iprtd);
-	if (!iprtd->dma_chan)
-		return -EINVAL;
-
-	return 0;
-}
-
 static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
-	unsigned long dma_addr;
-	struct dma_chan *chan;
-	int ret;
-
-	ret = mxs_dma_alloc(substream, params);
-	if (ret)
-		return ret;
-	chan = iprtd->dma_chan;
-
-	iprtd->size = params_buffer_bytes(params);
-	iprtd->periods = params_periods(params);
-	iprtd->period_bytes = params_period_bytes(params);
-	iprtd->offset = 0;
-	iprtd->period_time = HZ / (params_rate(params) /
-			params_period_size(params));
-
 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 
-	dma_addr = runtime->dma_addr;
-
-	iprtd->buf = substream->dma_buffer.area;
-
-	iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr,
-			iprtd->period_bytes * iprtd->periods,
-			iprtd->period_bytes,
-			substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-			DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
-	if (!iprtd->desc) {
-		dev_err(&chan->dev->device, "cannot prepare slave dma\n");
-		return -EINVAL;
-	}
-
-	iprtd->desc->callback = audio_dma_irq;
-	iprtd->desc->callback_param = substream;
-
 	return 0;
 }
 
-static int snd_mxs_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
-
-	if (iprtd->dma_chan) {
-		dma_release_channel(iprtd->dma_chan);
-		iprtd->dma_chan = NULL;
-	}
-
-	return 0;
-}
-
-static int snd_mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		dmaengine_submit(iprtd->desc);
-
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		dmaengine_terminate_all(iprtd->dma_chan);
-
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static snd_pcm_uframes_t snd_mxs_pcm_pointer(
-		struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
-
-	return bytes_to_frames(substream->runtime, iprtd->offset);
-}
-
 static int snd_mxs_open(struct snd_pcm_substream *substream)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct mxs_pcm_runtime_data *iprtd;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mxs_pcm_dma_data *pcm_dma_data;
 	int ret;
 
-	iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
-	if (iprtd == NULL)
+	pcm_dma_data = kzalloc(sizeof(*pcm_dma_data), GFP_KERNEL);
+	if (pcm_dma_data == NULL)
 		return -ENOMEM;
-	runtime->private_data = iprtd;
 
-	ret = snd_pcm_hw_constraint_integer(substream->runtime,
-			SNDRV_PCM_HW_PARAM_PERIODS);
-	if (ret < 0) {
-		kfree(iprtd);
+	pcm_dma_data->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+	pcm_dma_data->dma_data.chan_irq = pcm_dma_data->dma_params->chan_irq;
+
+	ret = snd_dmaengine_pcm_open(substream, filter, pcm_dma_data);
+	if (ret) {
+		kfree(pcm_dma_data);
 		return ret;
 	}
 
 	snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware);
 
+	snd_dmaengine_pcm_set_data(substream, pcm_dma_data);
+
 	return 0;
 }
 
 static int snd_mxs_close(struct snd_pcm_substream *substream)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+	struct mxs_pcm_dma_data *pcm_dma_data = snd_dmaengine_pcm_get_data(substream);
 
-	kfree(iprtd);
+	snd_dmaengine_pcm_close(substream);
+	kfree(pcm_dma_data);
 
 	return 0;
 }
@@ -244,9 +140,8 @@
 	.close		= snd_mxs_close,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= snd_mxs_pcm_hw_params,
-	.hw_free	= snd_mxs_pcm_hw_free,
-	.trigger	= snd_mxs_pcm_trigger,
-	.pointer	= snd_mxs_pcm_pointer,
+	.trigger	= snd_dmaengine_pcm_trigger,
+	.pointer	= snd_dmaengine_pcm_pointer,
 	.mmap		= snd_mxs_pcm_mmap,
 };
 
diff --git a/sound/soc/mxs/mxs-pcm.h b/sound/soc/mxs/mxs-pcm.h
index f55ac4f..5f01a91 100644
--- a/sound/soc/mxs/mxs-pcm.h
+++ b/sound/soc/mxs/mxs-pcm.h
@@ -19,25 +19,9 @@
 #ifndef _MXS_PCM_H
 #define _MXS_PCM_H
 
-#include <mach/dma.h>
-
 struct mxs_pcm_dma_params {
 	int chan_irq;
 	int chan_num;
 };
 
-struct mxs_pcm_runtime_data {
-	int period_bytes;
-	int periods;
-	int dma;
-	unsigned long offset;
-	unsigned long size;
-	void *buf;
-	int period_time;
-	struct dma_async_tx_descriptor *desc;
-	struct dma_chan *dma_chan;
-	struct mxs_dma_data dma_data;
-	struct mxs_pcm_dma_params *dma_params;
-};
-
 #endif
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index f204dba..53f4fd8 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -24,12 +24,12 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/time.h>
+#include <linux/fsl/mxs-dma.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/saif.h>
-#include <mach/dma.h>
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/mxs.h>
@@ -630,7 +630,7 @@
 	if (pdev->id >= ARRAY_SIZE(mxs_saif))
 		return -EINVAL;
 
-	saif = kzalloc(sizeof(*saif), GFP_KERNEL);
+	saif = devm_kzalloc(&pdev->dev, sizeof(*saif), GFP_KERNEL);
 	if (!saif)
 		return -ENOMEM;
 
@@ -655,29 +655,16 @@
 		ret = PTR_ERR(saif->clk);
 		dev_err(&pdev->dev, "Cannot get the clock: %d\n",
 			ret);
-		goto failed_clk;
+		return ret;
 	}
 
 	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!iores) {
-		ret = -ENODEV;
-		dev_err(&pdev->dev, "failed to get io resource: %d\n",
-			ret);
-		goto failed_get_resource;
-	}
 
-	if (!request_mem_region(iores->start, resource_size(iores),
-				"mxs-saif")) {
-		dev_err(&pdev->dev, "request_mem_region failed\n");
-		ret = -EBUSY;
-		goto failed_get_resource;
-	}
-
-	saif->base = ioremap(iores->start, resource_size(iores));
+	saif->base = devm_request_and_ioremap(&pdev->dev, iores);
 	if (!saif->base) {
 		dev_err(&pdev->dev, "ioremap failed\n");
 		ret = -ENODEV;
-		goto failed_ioremap;
+		goto failed_get_resource;
 	}
 
 	dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -685,7 +672,7 @@
 		ret = -ENODEV;
 		dev_err(&pdev->dev, "failed to get dma resource: %d\n",
 			ret);
-		goto failed_ioremap;
+		goto failed_get_resource;
 	}
 	saif->dma_param.chan_num = dmares->start;
 
@@ -694,14 +681,15 @@
 		ret = saif->irq;
 		dev_err(&pdev->dev, "failed to get irq resource: %d\n",
 			ret);
-		goto failed_get_irq1;
+		goto failed_get_resource;
 	}
 
 	saif->dev = &pdev->dev;
-	ret = request_irq(saif->irq, mxs_saif_irq, 0, "mxs-saif", saif);
+	ret = devm_request_irq(&pdev->dev, saif->irq, mxs_saif_irq, 0,
+			       "mxs-saif", saif);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to request irq\n");
-		goto failed_get_irq1;
+		goto failed_get_resource;
 	}
 
 	saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
@@ -709,7 +697,7 @@
 		ret = saif->dma_param.chan_irq;
 		dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
 			ret);
-		goto failed_get_irq2;
+		goto failed_get_resource;
 	}
 
 	platform_set_drvdata(pdev, saif);
@@ -717,7 +705,7 @@
 	ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
 	if (ret) {
 		dev_err(&pdev->dev, "register DAI failed\n");
-		goto failed_register;
+		goto failed_get_resource;
 	}
 
 	saif->soc_platform_pdev = platform_device_alloc(
@@ -740,36 +728,19 @@
 	platform_device_put(saif->soc_platform_pdev);
 failed_pdev_alloc:
 	snd_soc_unregister_dai(&pdev->dev);
-failed_register:
-failed_get_irq2:
-	free_irq(saif->irq, saif);
-failed_get_irq1:
-	iounmap(saif->base);
-failed_ioremap:
-	release_mem_region(iores->start, resource_size(iores));
 failed_get_resource:
 	clk_put(saif->clk);
-failed_clk:
-	kfree(saif);
 
 	return ret;
 }
 
 static int __devexit mxs_saif_remove(struct platform_device *pdev)
 {
-	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	struct mxs_saif *saif = platform_get_drvdata(pdev);
 
 	platform_device_unregister(saif->soc_platform_pdev);
-
 	snd_soc_unregister_dai(&pdev->dev);
-
-	iounmap(saif->base);
-	release_mem_region(res->start, resource_size(res));
-	free_irq(saif->irq, saif);
-
 	clk_put(saif->clk);
-	kfree(saif);
 
 	return 0;
 }
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index fb1bf258..e00dd0b 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -7,7 +7,6 @@
 
 config SND_OMAP_SOC_MCBSP
 	tristate
-	select OMAP_MCBSP
 
 config SND_OMAP_SOC_MCPDM
 	tristate
@@ -27,7 +26,6 @@
 config SND_OMAP_SOC_RX51
 	tristate "SoC Audio support for Nokia RX-51"
 	depends on SND_OMAP_SOC && MACH_NOKIA_RX51
-	select OMAP_MCBSP
 	select SND_OMAP_SOC_MCBSP
 	select SND_SOC_TLV320AIC3X
 	select SND_SOC_TPA6130A2
@@ -97,16 +95,19 @@
 	  Say Y if you want to add support for SoC audio on Texas Instruments
 	  SDP3430.
 
-config SND_OMAP_SOC_SDP4430
-	tristate "SoC Audio support for Texas Instruments SDP4430"
-	depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_4430SDP
+config SND_OMAP_SOC_OMAP_ABE_TWL6040
+	tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
+	depends on TWL4030_CORE && SND_OMAP_SOC && ARCH_OMAP4
 	select SND_OMAP_SOC_DMIC
 	select SND_OMAP_SOC_MCPDM
 	select SND_SOC_TWL6040
 	select SND_SOC_DMIC
 	help
-	  Say Y if you want to add support for SoC audio on Texas Instruments
-	  SDP4430.
+	  Say Y if you want to add support for SoC audio on OMAP boards using
+	  ABE and twl6040 codec. This driver currently supports:
+	  - SDP4430/Blaze boards
+	  - PandaBoard (4430)
+	  - PandaBoardES (4460)
 
 config SND_OMAP_SOC_OMAP4_HDMI
 	tristate "SoC Audio support for Texas Instruments OMAP4 HDMI"
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index 1fd723f..1d656bc 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -1,7 +1,7 @@
 # OMAP Platform Support
 snd-soc-omap-objs := omap-pcm.o
 snd-soc-omap-dmic-objs := omap-dmic.o
-snd-soc-omap-mcbsp-objs := omap-mcbsp.o
+snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o
 snd-soc-omap-mcpdm-objs := omap-mcpdm.o
 snd-soc-omap-hdmi-objs := omap-hdmi.o
 
@@ -20,7 +20,7 @@
 snd-soc-omap3evm-objs := omap3evm.o
 snd-soc-am3517evm-objs := am3517evm.o
 snd-soc-sdp3430-objs := sdp3430.o
-snd-soc-sdp4430-objs := sdp4430.o
+snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
 snd-soc-omap3pandora-objs := omap3pandora.o
 snd-soc-omap3beagle-objs := omap3beagle.o
 snd-soc-zoom2-objs := zoom2.o
@@ -36,7 +36,7 @@
 obj-$(CONFIG_SND_OMAP_SOC_OMAP3EVM) += snd-soc-omap3evm.o
 obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o
 obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o
-obj-$(CONFIG_SND_OMAP_SOC_SDP4430) += snd-soc-sdp4430.o
+obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
 obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
index add4866..009533a 100644
--- a/sound/soc/omap/am3517evm.c
+++ b/sound/soc/omap/am3517evm.c
@@ -95,7 +95,7 @@
 static struct snd_soc_dai_link am3517evm_dai = {
 	.name = "TLV320AIC23",
 	.stream_name = "AIC23",
-	.cpu_dai_name ="omap-mcbsp-dai.0",
+	.cpu_dai_name = "omap-mcbsp.1",
 	.codec_dai_name = "tlv320aic23-hifi",
 	.platform_name = "omap-pcm-audio",
 	.codec_name = "tlv320aic23-codec.2-001a",
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index a67f437..7d4fa8e 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -426,29 +426,6 @@
 };
 
 
-/* Board specific codec bias level control */
-static int ams_delta_set_bias_level(struct snd_soc_card *card,
-				    struct snd_soc_dapm_context *dapm,
-				    enum snd_soc_bias_level level)
-{
-	switch (level) {
-	case SND_SOC_BIAS_ON:
-	case SND_SOC_BIAS_PREPARE:
-	case SND_SOC_BIAS_STANDBY:
-		if (card->dapm.bias_level == SND_SOC_BIAS_OFF)
-			ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET,
-						AMS_DELTA_LATCH2_MODEM_NRESET);
-		break;
-	case SND_SOC_BIAS_OFF:
-		if (card->dapm.bias_level != SND_SOC_BIAS_OFF)
-			ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET,
-						0);
-	}
-	card->dapm.bias_level = level;
-
-	return 0;
-}
-
 /* Digital mute implemented using modem/CPU multiplexer.
  * Shares hardware with codec config pulse generation */
 static bool ams_delta_muted = 1;
@@ -512,9 +489,6 @@
 		ams_delta_ops.shutdown = ams_delta_shutdown;
 	}
 
-	/* Set codec bias level */
-	ams_delta_set_bias_level(card, dapm, SND_SOC_BIAS_STANDBY);
-
 	/* Add hook switch - can be used to control the codec from userspace
 	 * even if line discipline fails */
 	ret = snd_soc_jack_new(rtd->codec, "hook_switch",
@@ -570,7 +544,7 @@
 	snd_soc_dapm_disable_pin(dapm, "AGCOUT");
 
 	/* Add virtual switch */
-	ret = snd_soc_add_controls(codec, ams_delta_audio_controls,
+	ret = snd_soc_add_codec_controls(codec, ams_delta_audio_controls,
 					ARRAY_SIZE(ams_delta_audio_controls));
 	if (ret)
 		dev_warn(card->dev,
@@ -584,7 +558,7 @@
 static struct snd_soc_dai_link ams_delta_dai_link = {
 	.name = "CX20442",
 	.stream_name = "CX20442",
-	.cpu_dai_name ="omap-mcbsp-dai.0",
+	.cpu_dai_name = "omap-mcbsp.1",
 	.codec_dai_name = "cx20442-voice",
 	.init = ams_delta_cx20442_init,
 	.platform_name = "omap-pcm-audio",
@@ -598,7 +572,6 @@
 	.owner = THIS_MODULE,
 	.dai_link = &ams_delta_dai_link,
 	.num_links = 1,
-	.set_bias_level = ams_delta_set_bias_level,
 };
 
 /* Module init/exit */
@@ -635,7 +608,7 @@
 	platform_device_put(ams_delta_audio_platform_device);
 	return ret;
 }
-module_init(ams_delta_module_init);
+late_initcall(ams_delta_module_init);
 
 static void __exit ams_delta_module_exit(void)
 {
@@ -647,11 +620,6 @@
 			ARRAY_SIZE(ams_delta_hook_switch_gpios),
 			ams_delta_hook_switch_gpios);
 
-	/* Keep modem power on */
-	ams_delta_set_bias_level(&ams_delta_audio_card,
-				 &ams_delta_audio_card.rtd[0].codec->dapm,
-				 SND_SOC_BIAS_STANDBY);
-
 	platform_device_unregister(cx20442_platform_device);
 	platform_device_unregister(ams_delta_audio_platform_device);
 }
diff --git a/sound/soc/omap/igep0020.c b/sound/soc/omap/igep0020.c
index ccae58a..e835781 100644
--- a/sound/soc/omap/igep0020.c
+++ b/sound/soc/omap/igep0020.c
@@ -60,7 +60,7 @@
 static struct snd_soc_dai_link igep2_dai = {
 	.name = "TWL4030",
 	.stream_name = "TWL4030",
-	.cpu_dai_name = "omap-mcbsp-dai.1",
+	.cpu_dai_name = "omap-mcbsp.2",
 	.codec_dai_name = "twl4030-hifi",
 	.platform_name = "omap-pcm-audio",
 	.codec_name = "twl4030-codec",
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
new file mode 100644
index 0000000..e5f4444
--- /dev/null
+++ b/sound/soc/omap/mcbsp.c
@@ -0,0 +1,1040 @@
+/*
+ * sound/soc/omap/mcbsp.c
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Samuel Ortiz <samuel.ortiz@nokia.com>
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
+ *          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.
+ *
+ * Multichannel mode not supported.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <plat/mcbsp.h>
+
+#include "mcbsp.h"
+
+static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+{
+	void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
+
+	if (mcbsp->pdata->reg_size == 2) {
+		((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
+		__raw_writew((u16)val, addr);
+	} else {
+		((u32 *)mcbsp->reg_cache)[reg] = val;
+		__raw_writel(val, addr);
+	}
+}
+
+static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
+{
+	void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
+
+	if (mcbsp->pdata->reg_size == 2) {
+		return !from_cache ? __raw_readw(addr) :
+				     ((u16 *)mcbsp->reg_cache)[reg];
+	} else {
+		return !from_cache ? __raw_readl(addr) :
+				     ((u32 *)mcbsp->reg_cache)[reg];
+	}
+}
+
+static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+{
+	__raw_writel(val, mcbsp->st_data->io_base_st + reg);
+}
+
+static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
+{
+	return __raw_readl(mcbsp->st_data->io_base_st + reg);
+}
+
+#define MCBSP_READ(mcbsp, reg) \
+		omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0)
+#define MCBSP_WRITE(mcbsp, reg, val) \
+		omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val)
+#define MCBSP_READ_CACHE(mcbsp, reg) \
+		omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
+
+#define MCBSP_ST_READ(mcbsp, reg) \
+			omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
+#define MCBSP_ST_WRITE(mcbsp, reg, val) \
+			omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
+
+static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp)
+{
+	dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id);
+	dev_dbg(mcbsp->dev, "DRR2:  0x%04x\n",
+			MCBSP_READ(mcbsp, DRR2));
+	dev_dbg(mcbsp->dev, "DRR1:  0x%04x\n",
+			MCBSP_READ(mcbsp, DRR1));
+	dev_dbg(mcbsp->dev, "DXR2:  0x%04x\n",
+			MCBSP_READ(mcbsp, DXR2));
+	dev_dbg(mcbsp->dev, "DXR1:  0x%04x\n",
+			MCBSP_READ(mcbsp, DXR1));
+	dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n",
+			MCBSP_READ(mcbsp, SPCR2));
+	dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n",
+			MCBSP_READ(mcbsp, SPCR1));
+	dev_dbg(mcbsp->dev, "RCR2:  0x%04x\n",
+			MCBSP_READ(mcbsp, RCR2));
+	dev_dbg(mcbsp->dev, "RCR1:  0x%04x\n",
+			MCBSP_READ(mcbsp, RCR1));
+	dev_dbg(mcbsp->dev, "XCR2:  0x%04x\n",
+			MCBSP_READ(mcbsp, XCR2));
+	dev_dbg(mcbsp->dev, "XCR1:  0x%04x\n",
+			MCBSP_READ(mcbsp, XCR1));
+	dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n",
+			MCBSP_READ(mcbsp, SRGR2));
+	dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n",
+			MCBSP_READ(mcbsp, SRGR1));
+	dev_dbg(mcbsp->dev, "PCR0:  0x%04x\n",
+			MCBSP_READ(mcbsp, PCR0));
+	dev_dbg(mcbsp->dev, "***********************\n");
+}
+
+static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
+{
+	struct omap_mcbsp *mcbsp_tx = dev_id;
+	u16 irqst_spcr2;
+
+	irqst_spcr2 = MCBSP_READ(mcbsp_tx, SPCR2);
+	dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
+
+	if (irqst_spcr2 & XSYNC_ERR) {
+		dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n",
+			irqst_spcr2);
+		/* Writing zero to XSYNC_ERR clears the IRQ */
+		MCBSP_WRITE(mcbsp_tx, SPCR2, MCBSP_READ_CACHE(mcbsp_tx, SPCR2));
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
+{
+	struct omap_mcbsp *mcbsp_rx = dev_id;
+	u16 irqst_spcr1;
+
+	irqst_spcr1 = MCBSP_READ(mcbsp_rx, SPCR1);
+	dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
+
+	if (irqst_spcr1 & RSYNC_ERR) {
+		dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n",
+			irqst_spcr1);
+		/* Writing zero to RSYNC_ERR clears the IRQ */
+		MCBSP_WRITE(mcbsp_rx, SPCR1, MCBSP_READ_CACHE(mcbsp_rx, SPCR1));
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * omap_mcbsp_config simply write a config to the
+ * appropriate McBSP.
+ * You either call this function or set the McBSP registers
+ * by yourself before calling omap_mcbsp_start().
+ */
+void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
+		       const struct omap_mcbsp_reg_cfg *config)
+{
+	dev_dbg(mcbsp->dev, "Configuring McBSP%d  phys_base: 0x%08lx\n",
+			mcbsp->id, mcbsp->phys_base);
+
+	/* We write the given config */
+	MCBSP_WRITE(mcbsp, SPCR2, config->spcr2);
+	MCBSP_WRITE(mcbsp, SPCR1, config->spcr1);
+	MCBSP_WRITE(mcbsp, RCR2, config->rcr2);
+	MCBSP_WRITE(mcbsp, RCR1, config->rcr1);
+	MCBSP_WRITE(mcbsp, XCR2, config->xcr2);
+	MCBSP_WRITE(mcbsp, XCR1, config->xcr1);
+	MCBSP_WRITE(mcbsp, SRGR2, config->srgr2);
+	MCBSP_WRITE(mcbsp, SRGR1, config->srgr1);
+	MCBSP_WRITE(mcbsp, MCR2, config->mcr2);
+	MCBSP_WRITE(mcbsp, MCR1, config->mcr1);
+	MCBSP_WRITE(mcbsp, PCR0, config->pcr0);
+	if (mcbsp->pdata->has_ccr) {
+		MCBSP_WRITE(mcbsp, XCCR, config->xccr);
+		MCBSP_WRITE(mcbsp, RCCR, config->rccr);
+	}
+	/* Enable wakeup behavior */
+	if (mcbsp->pdata->has_wakeup)
+		MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
+}
+
+/**
+ * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
+ * @id - mcbsp id
+ * @stream - indicates the direction of data flow (rx or tx)
+ *
+ * Returns the address of mcbsp data transmit register or data receive register
+ * to be used by DMA for transferring/receiving data based on the value of
+ * @stream for the requested mcbsp given by @id
+ */
+static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp,
+				     unsigned int stream)
+{
+	int data_reg;
+
+	if (mcbsp->pdata->reg_size == 2) {
+		if (stream)
+			data_reg = OMAP_MCBSP_REG_DRR1;
+		else
+			data_reg = OMAP_MCBSP_REG_DXR1;
+	} else {
+		if (stream)
+			data_reg = OMAP_MCBSP_REG_DRR;
+		else
+			data_reg = OMAP_MCBSP_REG_DXR;
+	}
+
+	return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step;
+}
+
+static void omap_st_on(struct omap_mcbsp *mcbsp)
+{
+	unsigned int w;
+
+	if (mcbsp->pdata->enable_st_clock)
+		mcbsp->pdata->enable_st_clock(mcbsp->id, 1);
+
+	/* Enable McBSP Sidetone */
+	w = MCBSP_READ(mcbsp, SSELCR);
+	MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
+
+	/* Enable Sidetone from Sidetone Core */
+	w = MCBSP_ST_READ(mcbsp, SSELCR);
+	MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
+}
+
+static void omap_st_off(struct omap_mcbsp *mcbsp)
+{
+	unsigned int w;
+
+	w = MCBSP_ST_READ(mcbsp, SSELCR);
+	MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
+
+	w = MCBSP_READ(mcbsp, SSELCR);
+	MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
+
+	if (mcbsp->pdata->enable_st_clock)
+		mcbsp->pdata->enable_st_clock(mcbsp->id, 0);
+}
+
+static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
+{
+	u16 val, i;
+
+	val = MCBSP_ST_READ(mcbsp, SSELCR);
+
+	if (val & ST_COEFFWREN)
+		MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
+
+	MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
+
+	for (i = 0; i < 128; i++)
+		MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
+
+	i = 0;
+
+	val = MCBSP_ST_READ(mcbsp, SSELCR);
+	while (!(val & ST_COEFFWRDONE) && (++i < 1000))
+		val = MCBSP_ST_READ(mcbsp, SSELCR);
+
+	MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
+
+	if (i == 1000)
+		dev_err(mcbsp->dev, "McBSP FIR load error!\n");
+}
+
+static void omap_st_chgain(struct omap_mcbsp *mcbsp)
+{
+	u16 w;
+	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+	w = MCBSP_ST_READ(mcbsp, SSELCR);
+
+	MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | \
+		      ST_CH1GAIN(st_data->ch1gain));
+}
+
+int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain)
+{
+	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+	int ret = 0;
+
+	if (!st_data)
+		return -ENOENT;
+
+	spin_lock_irq(&mcbsp->lock);
+	if (channel == 0)
+		st_data->ch0gain = chgain;
+	else if (channel == 1)
+		st_data->ch1gain = chgain;
+	else
+		ret = -EINVAL;
+
+	if (st_data->enabled)
+		omap_st_chgain(mcbsp);
+	spin_unlock_irq(&mcbsp->lock);
+
+	return ret;
+}
+
+int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain)
+{
+	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+	int ret = 0;
+
+	if (!st_data)
+		return -ENOENT;
+
+	spin_lock_irq(&mcbsp->lock);
+	if (channel == 0)
+		*chgain = st_data->ch0gain;
+	else if (channel == 1)
+		*chgain = st_data->ch1gain;
+	else
+		ret = -EINVAL;
+	spin_unlock_irq(&mcbsp->lock);
+
+	return ret;
+}
+
+static int omap_st_start(struct omap_mcbsp *mcbsp)
+{
+	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+	if (st_data->enabled && !st_data->running) {
+		omap_st_fir_write(mcbsp, st_data->taps);
+		omap_st_chgain(mcbsp);
+
+		if (!mcbsp->free) {
+			omap_st_on(mcbsp);
+			st_data->running = 1;
+		}
+	}
+
+	return 0;
+}
+
+int omap_st_enable(struct omap_mcbsp *mcbsp)
+{
+	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+	if (!st_data)
+		return -ENODEV;
+
+	spin_lock_irq(&mcbsp->lock);
+	st_data->enabled = 1;
+	omap_st_start(mcbsp);
+	spin_unlock_irq(&mcbsp->lock);
+
+	return 0;
+}
+
+static int omap_st_stop(struct omap_mcbsp *mcbsp)
+{
+	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+	if (st_data->running) {
+		if (!mcbsp->free) {
+			omap_st_off(mcbsp);
+			st_data->running = 0;
+		}
+	}
+
+	return 0;
+}
+
+int omap_st_disable(struct omap_mcbsp *mcbsp)
+{
+	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+	int ret = 0;
+
+	if (!st_data)
+		return -ENODEV;
+
+	spin_lock_irq(&mcbsp->lock);
+	omap_st_stop(mcbsp);
+	st_data->enabled = 0;
+	spin_unlock_irq(&mcbsp->lock);
+
+	return ret;
+}
+
+int omap_st_is_enabled(struct omap_mcbsp *mcbsp)
+{
+	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+	if (!st_data)
+		return -ENODEV;
+
+	return st_data->enabled;
+}
+
+/*
+ * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH2 register.
+ */
+void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
+{
+	if (mcbsp->pdata->buffer_size == 0)
+		return;
+
+	if (threshold && threshold <= mcbsp->max_tx_thres)
+		MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
+}
+
+/*
+ * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH1 register.
+ */
+void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
+{
+	if (mcbsp->pdata->buffer_size == 0)
+		return;
+
+	if (threshold && threshold <= mcbsp->max_rx_thres)
+		MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
+}
+
+/*
+ * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
+ */
+u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp)
+{
+	u16 buffstat;
+
+	if (mcbsp->pdata->buffer_size == 0)
+		return 0;
+
+	/* Returns the number of free locations in the buffer */
+	buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
+
+	/* Number of slots are different in McBSP ports */
+	return mcbsp->pdata->buffer_size - buffstat;
+}
+
+/*
+ * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO
+ * to reach the threshold value (when the DMA will be triggered to read it)
+ */
+u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp)
+{
+	u16 buffstat, threshold;
+
+	if (mcbsp->pdata->buffer_size == 0)
+		return 0;
+
+	/* Returns the number of used locations in the buffer */
+	buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
+	/* RX threshold */
+	threshold = MCBSP_READ(mcbsp, THRSH1);
+
+	/* Return the number of location till we reach the threshold limit */
+	if (threshold <= buffstat)
+		return 0;
+	else
+		return threshold - buffstat;
+}
+
+int omap_mcbsp_request(struct omap_mcbsp *mcbsp)
+{
+	void *reg_cache;
+	int err;
+
+	reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL);
+	if (!reg_cache) {
+		return -ENOMEM;
+	}
+
+	spin_lock(&mcbsp->lock);
+	if (!mcbsp->free) {
+		dev_err(mcbsp->dev, "McBSP%d is currently in use\n",
+			mcbsp->id);
+		err = -EBUSY;
+		goto err_kfree;
+	}
+
+	mcbsp->free = false;
+	mcbsp->reg_cache = reg_cache;
+	spin_unlock(&mcbsp->lock);
+
+	if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request)
+		mcbsp->pdata->ops->request(mcbsp->id - 1);
+
+	/*
+	 * Make sure that transmitter, receiver and sample-rate generator are
+	 * not running before activating IRQs.
+	 */
+	MCBSP_WRITE(mcbsp, SPCR1, 0);
+	MCBSP_WRITE(mcbsp, SPCR2, 0);
+
+	err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler,
+				0, "McBSP", (void *)mcbsp);
+	if (err != 0) {
+		dev_err(mcbsp->dev, "Unable to request TX IRQ %d "
+				"for McBSP%d\n", mcbsp->tx_irq,
+				mcbsp->id);
+		goto err_clk_disable;
+	}
+
+	if (mcbsp->rx_irq) {
+		err = request_irq(mcbsp->rx_irq,
+				omap_mcbsp_rx_irq_handler,
+				0, "McBSP", (void *)mcbsp);
+		if (err != 0) {
+			dev_err(mcbsp->dev, "Unable to request RX IRQ %d "
+					"for McBSP%d\n", mcbsp->rx_irq,
+					mcbsp->id);
+			goto err_free_irq;
+		}
+	}
+
+	return 0;
+err_free_irq:
+	free_irq(mcbsp->tx_irq, (void *)mcbsp);
+err_clk_disable:
+	if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+		mcbsp->pdata->ops->free(mcbsp->id - 1);
+
+	/* Disable wakeup behavior */
+	if (mcbsp->pdata->has_wakeup)
+		MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
+
+	spin_lock(&mcbsp->lock);
+	mcbsp->free = true;
+	mcbsp->reg_cache = NULL;
+err_kfree:
+	spin_unlock(&mcbsp->lock);
+	kfree(reg_cache);
+
+	return err;
+}
+
+void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
+{
+	void *reg_cache;
+
+	if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+		mcbsp->pdata->ops->free(mcbsp->id - 1);
+
+	/* Disable wakeup behavior */
+	if (mcbsp->pdata->has_wakeup)
+		MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
+
+	if (mcbsp->rx_irq)
+		free_irq(mcbsp->rx_irq, (void *)mcbsp);
+	free_irq(mcbsp->tx_irq, (void *)mcbsp);
+
+	reg_cache = mcbsp->reg_cache;
+
+	/*
+	 * Select CLKS source from internal source unconditionally before
+	 * marking the McBSP port as free.
+	 * If the external clock source via MCBSP_CLKS pin has been selected the
+	 * system will refuse to enter idle if the CLKS pin source is not reset
+	 * back to internal source.
+	 */
+	if (!cpu_class_is_omap1())
+		omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC);
+
+	spin_lock(&mcbsp->lock);
+	if (mcbsp->free)
+		dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id);
+	else
+		mcbsp->free = true;
+	mcbsp->reg_cache = NULL;
+	spin_unlock(&mcbsp->lock);
+
+	if (reg_cache)
+		kfree(reg_cache);
+}
+
+/*
+ * Here we start the McBSP, by enabling transmitter, receiver or both.
+ * If no transmitter or receiver is active prior calling, then sample-rate
+ * generator and frame sync are started.
+ */
+void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx)
+{
+	int enable_srg = 0;
+	u16 w;
+
+	if (mcbsp->st_data)
+		omap_st_start(mcbsp);
+
+	/* Only enable SRG, if McBSP is master */
+	w = MCBSP_READ_CACHE(mcbsp, PCR0);
+	if (w & (FSXM | FSRM | CLKXM | CLKRM))
+		enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
+				MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
+
+	if (enable_srg) {
+		/* Start the sample generator */
+		w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+		MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
+	}
+
+	/* Enable transmitter and receiver */
+	tx &= 1;
+	w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+	MCBSP_WRITE(mcbsp, SPCR2, w | tx);
+
+	rx &= 1;
+	w = MCBSP_READ_CACHE(mcbsp, SPCR1);
+	MCBSP_WRITE(mcbsp, SPCR1, w | rx);
+
+	/*
+	 * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec
+	 * REVISIT: 100us may give enough time for two CLKSRG, however
+	 * due to some unknown PM related, clock gating etc. reason it
+	 * is now at 500us.
+	 */
+	udelay(500);
+
+	if (enable_srg) {
+		/* Start frame sync */
+		w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+		MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
+	}
+
+	if (mcbsp->pdata->has_ccr) {
+		/* Release the transmitter and receiver */
+		w = MCBSP_READ_CACHE(mcbsp, XCCR);
+		w &= ~(tx ? XDISABLE : 0);
+		MCBSP_WRITE(mcbsp, XCCR, w);
+		w = MCBSP_READ_CACHE(mcbsp, RCCR);
+		w &= ~(rx ? RDISABLE : 0);
+		MCBSP_WRITE(mcbsp, RCCR, w);
+	}
+
+	/* Dump McBSP Regs */
+	omap_mcbsp_dump_reg(mcbsp);
+}
+
+void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx)
+{
+	int idle;
+	u16 w;
+
+	/* Reset transmitter */
+	tx &= 1;
+	if (mcbsp->pdata->has_ccr) {
+		w = MCBSP_READ_CACHE(mcbsp, XCCR);
+		w |= (tx ? XDISABLE : 0);
+		MCBSP_WRITE(mcbsp, XCCR, w);
+	}
+	w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+	MCBSP_WRITE(mcbsp, SPCR2, w & ~tx);
+
+	/* Reset receiver */
+	rx &= 1;
+	if (mcbsp->pdata->has_ccr) {
+		w = MCBSP_READ_CACHE(mcbsp, RCCR);
+		w |= (rx ? RDISABLE : 0);
+		MCBSP_WRITE(mcbsp, RCCR, w);
+	}
+	w = MCBSP_READ_CACHE(mcbsp, SPCR1);
+	MCBSP_WRITE(mcbsp, SPCR1, w & ~rx);
+
+	idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
+			MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
+
+	if (idle) {
+		/* Reset the sample rate generator */
+		w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+		MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6));
+	}
+
+	if (mcbsp->st_data)
+		omap_st_stop(mcbsp);
+}
+
+int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id)
+{
+	const char *src;
+
+	if (fck_src_id == MCBSP_CLKS_PAD_SRC)
+		src = "clks_ext";
+	else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
+		src = "clks_fclk";
+	else
+		return -EINVAL;
+
+	if (mcbsp->pdata->set_clk_src)
+		return mcbsp->pdata->set_clk_src(mcbsp->dev, mcbsp->fclk, src);
+	else
+		return -EINVAL;
+}
+
+int omap_mcbsp_6pin_src_mux(struct omap_mcbsp *mcbsp, u8 mux)
+{
+	const char *signal, *src;
+
+	if (mcbsp->pdata->mux_signal)
+		return -EINVAL;
+
+	switch (mux) {
+	case CLKR_SRC_CLKR:
+		signal = "clkr";
+		src = "clkr";
+		break;
+	case CLKR_SRC_CLKX:
+		signal = "clkr";
+		src = "clkx";
+		break;
+	case FSR_SRC_FSR:
+		signal = "fsr";
+		src = "fsr";
+		break;
+	case FSR_SRC_FSX:
+		signal = "fsr";
+		src = "fsx";
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return mcbsp->pdata->mux_signal(mcbsp->dev, signal, src);
+}
+
+#define max_thres(m)			(mcbsp->pdata->buffer_size)
+#define valid_threshold(m, val)		((val) <= max_thres(m))
+#define THRESHOLD_PROP_BUILDER(prop)					\
+static ssize_t prop##_show(struct device *dev,				\
+			struct device_attribute *attr, char *buf)	\
+{									\
+	struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);		\
+									\
+	return sprintf(buf, "%u\n", mcbsp->prop);			\
+}									\
+									\
+static ssize_t prop##_store(struct device *dev,				\
+				struct device_attribute *attr,		\
+				const char *buf, size_t size)		\
+{									\
+	struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);		\
+	unsigned long val;						\
+	int status;							\
+									\
+	status = strict_strtoul(buf, 0, &val);				\
+	if (status)							\
+		return status;						\
+									\
+	if (!valid_threshold(mcbsp, val))				\
+		return -EDOM;						\
+									\
+	mcbsp->prop = val;						\
+	return size;							\
+}									\
+									\
+static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store);
+
+THRESHOLD_PROP_BUILDER(max_tx_thres);
+THRESHOLD_PROP_BUILDER(max_rx_thres);
+
+static const char *dma_op_modes[] = {
+	"element", "threshold", "frame",
+};
+
+static ssize_t dma_op_mode_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+	int dma_op_mode, i = 0;
+	ssize_t len = 0;
+	const char * const *s;
+
+	dma_op_mode = mcbsp->dma_op_mode;
+
+	for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) {
+		if (dma_op_mode == i)
+			len += sprintf(buf + len, "[%s] ", *s);
+		else
+			len += sprintf(buf + len, "%s ", *s);
+	}
+	len += sprintf(buf + len, "\n");
+
+	return len;
+}
+
+static ssize_t dma_op_mode_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+	const char * const *s;
+	int i = 0;
+
+	for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++)
+		if (sysfs_streq(buf, *s))
+			break;
+
+	if (i == ARRAY_SIZE(dma_op_modes))
+		return -EINVAL;
+
+	spin_lock_irq(&mcbsp->lock);
+	if (!mcbsp->free) {
+		size = -EBUSY;
+		goto unlock;
+	}
+	mcbsp->dma_op_mode = i;
+
+unlock:
+	spin_unlock_irq(&mcbsp->lock);
+
+	return size;
+}
+
+static DEVICE_ATTR(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store);
+
+static const struct attribute *additional_attrs[] = {
+	&dev_attr_max_tx_thres.attr,
+	&dev_attr_max_rx_thres.attr,
+	&dev_attr_dma_op_mode.attr,
+	NULL,
+};
+
+static const struct attribute_group additional_attr_group = {
+	.attrs = (struct attribute **)additional_attrs,
+};
+
+static ssize_t st_taps_show(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+	ssize_t status = 0;
+	int i;
+
+	spin_lock_irq(&mcbsp->lock);
+	for (i = 0; i < st_data->nr_taps; i++)
+		status += sprintf(&buf[status], (i ? ", %d" : "%d"),
+				  st_data->taps[i]);
+	if (i)
+		status += sprintf(&buf[status], "\n");
+	spin_unlock_irq(&mcbsp->lock);
+
+	return status;
+}
+
+static ssize_t st_taps_store(struct device *dev,
+			     struct device_attribute *attr,
+			     const char *buf, size_t size)
+{
+	struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+	struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+	int val, tmp, status, i = 0;
+
+	spin_lock_irq(&mcbsp->lock);
+	memset(st_data->taps, 0, sizeof(st_data->taps));
+	st_data->nr_taps = 0;
+
+	do {
+		status = sscanf(buf, "%d%n", &val, &tmp);
+		if (status < 0 || status == 0) {
+			size = -EINVAL;
+			goto out;
+		}
+		if (val < -32768 || val > 32767) {
+			size = -EINVAL;
+			goto out;
+		}
+		st_data->taps[i++] = val;
+		buf += tmp;
+		if (*buf != ',')
+			break;
+		buf++;
+	} while (1);
+
+	st_data->nr_taps = i;
+
+out:
+	spin_unlock_irq(&mcbsp->lock);
+
+	return size;
+}
+
+static DEVICE_ATTR(st_taps, 0644, st_taps_show, st_taps_store);
+
+static const struct attribute *sidetone_attrs[] = {
+	&dev_attr_st_taps.attr,
+	NULL,
+};
+
+static const struct attribute_group sidetone_attr_group = {
+	.attrs = (struct attribute **)sidetone_attrs,
+};
+
+static int __devinit omap_st_add(struct omap_mcbsp *mcbsp,
+				 struct resource *res)
+{
+	struct omap_mcbsp_st_data *st_data;
+	int err;
+
+	st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL);
+	if (!st_data)
+		return -ENOMEM;
+
+	st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start,
+					   resource_size(res));
+	if (!st_data->io_base_st)
+		return -ENOMEM;
+
+	err = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
+	if (err)
+		return err;
+
+	mcbsp->st_data = st_data;
+	return 0;
+}
+
+/*
+ * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
+ * 730 has only 2 McBSP, and both of them are MPU peripherals.
+ */
+int __devinit omap_mcbsp_init(struct platform_device *pdev)
+{
+	struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+	struct resource *res;
+	int ret = 0;
+
+	spin_lock_init(&mcbsp->lock);
+	mcbsp->free = true;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
+	if (!res) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (!res) {
+			dev_err(mcbsp->dev, "invalid memory resource\n");
+			return -ENOMEM;
+		}
+	}
+	if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
+				     dev_name(&pdev->dev))) {
+		dev_err(mcbsp->dev, "memory region already claimed\n");
+		return -ENODEV;
+	}
+
+	mcbsp->phys_base = res->start;
+	mcbsp->reg_cache_size = resource_size(res);
+	mcbsp->io_base = devm_ioremap(&pdev->dev, res->start,
+				      resource_size(res));
+	if (!mcbsp->io_base)
+		return -ENOMEM;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
+	if (!res)
+		mcbsp->phys_dma_base = mcbsp->phys_base;
+	else
+		mcbsp->phys_dma_base = res->start;
+
+	mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
+	mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
+
+	/* From OMAP4 there will be a single irq line */
+	if (mcbsp->tx_irq == -ENXIO) {
+		mcbsp->tx_irq = platform_get_irq(pdev, 0);
+		mcbsp->rx_irq = 0;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+	if (!res) {
+		dev_err(&pdev->dev, "invalid rx DMA channel\n");
+		return -ENODEV;
+	}
+	/* RX DMA request number, and port address configuration */
+	mcbsp->dma_data[1].name = "Audio Capture";
+	mcbsp->dma_data[1].dma_req = res->start;
+	mcbsp->dma_data[1].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+	if (!res) {
+		dev_err(&pdev->dev, "invalid tx DMA channel\n");
+		return -ENODEV;
+	}
+	/* TX DMA request number, and port address configuration */
+	mcbsp->dma_data[0].name = "Audio Playback";
+	mcbsp->dma_data[0].dma_req = res->start;
+	mcbsp->dma_data[0].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 0);
+
+	mcbsp->fclk = clk_get(&pdev->dev, "fck");
+	if (IS_ERR(mcbsp->fclk)) {
+		ret = PTR_ERR(mcbsp->fclk);
+		dev_err(mcbsp->dev, "unable to get fck: %d\n", ret);
+		return ret;
+	}
+
+	mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
+	if (mcbsp->pdata->buffer_size) {
+		/*
+		 * Initially configure the maximum thresholds to a safe value.
+		 * The McBSP FIFO usage with these values should not go under
+		 * 16 locations.
+		 * If the whole FIFO without safety buffer is used, than there
+		 * is a possibility that the DMA will be not able to push the
+		 * new data on time, causing channel shifts in runtime.
+		 */
+		mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
+		mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
+
+		ret = sysfs_create_group(&mcbsp->dev->kobj,
+					 &additional_attr_group);
+		if (ret) {
+			dev_err(mcbsp->dev,
+				"Unable to create additional controls\n");
+			goto err_thres;
+		}
+	} else {
+		mcbsp->max_tx_thres = -EINVAL;
+		mcbsp->max_rx_thres = -EINVAL;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
+	if (res) {
+		ret = omap_st_add(mcbsp, res);
+		if (ret) {
+			dev_err(mcbsp->dev,
+				"Unable to create sidetone controls\n");
+			goto err_st;
+		}
+	}
+
+	return 0;
+
+err_st:
+	if (mcbsp->pdata->buffer_size)
+		sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
+err_thres:
+	clk_put(mcbsp->fclk);
+	return ret;
+}
+
+void __devexit omap_mcbsp_sysfs_remove(struct omap_mcbsp *mcbsp)
+{
+	if (mcbsp->pdata->buffer_size)
+		sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
+
+	if (mcbsp->st_data)
+		sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
+}
diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/mcbsp.h
new file mode 100644
index 0000000..a944fcc
--- /dev/null
+++ b/sound/soc/omap/mcbsp.h
@@ -0,0 +1,346 @@
+/*
+ * sound/soc/omap/mcbsp.h
+ *
+ * OMAP Multi-Channel Buffered Serial Port
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
+ *          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 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
+ *
+ */
+#ifndef __ASOC_MCBSP_H
+#define __ASOC_MCBSP_H
+
+#include "omap-pcm.h"
+
+/* McBSP register numbers. Register address offset = num * reg_step */
+enum {
+	/* Common registers */
+	OMAP_MCBSP_REG_SPCR2 = 4,
+	OMAP_MCBSP_REG_SPCR1,
+	OMAP_MCBSP_REG_RCR2,
+	OMAP_MCBSP_REG_RCR1,
+	OMAP_MCBSP_REG_XCR2,
+	OMAP_MCBSP_REG_XCR1,
+	OMAP_MCBSP_REG_SRGR2,
+	OMAP_MCBSP_REG_SRGR1,
+	OMAP_MCBSP_REG_MCR2,
+	OMAP_MCBSP_REG_MCR1,
+	OMAP_MCBSP_REG_RCERA,
+	OMAP_MCBSP_REG_RCERB,
+	OMAP_MCBSP_REG_XCERA,
+	OMAP_MCBSP_REG_XCERB,
+	OMAP_MCBSP_REG_PCR0,
+	OMAP_MCBSP_REG_RCERC,
+	OMAP_MCBSP_REG_RCERD,
+	OMAP_MCBSP_REG_XCERC,
+	OMAP_MCBSP_REG_XCERD,
+	OMAP_MCBSP_REG_RCERE,
+	OMAP_MCBSP_REG_RCERF,
+	OMAP_MCBSP_REG_XCERE,
+	OMAP_MCBSP_REG_XCERF,
+	OMAP_MCBSP_REG_RCERG,
+	OMAP_MCBSP_REG_RCERH,
+	OMAP_MCBSP_REG_XCERG,
+	OMAP_MCBSP_REG_XCERH,
+
+	/* OMAP1-OMAP2420 registers */
+	OMAP_MCBSP_REG_DRR2 = 0,
+	OMAP_MCBSP_REG_DRR1,
+	OMAP_MCBSP_REG_DXR2,
+	OMAP_MCBSP_REG_DXR1,
+
+	/* OMAP2430 and onwards */
+	OMAP_MCBSP_REG_DRR = 0,
+	OMAP_MCBSP_REG_DXR = 2,
+	OMAP_MCBSP_REG_SYSCON =	35,
+	OMAP_MCBSP_REG_THRSH2,
+	OMAP_MCBSP_REG_THRSH1,
+	OMAP_MCBSP_REG_IRQST = 40,
+	OMAP_MCBSP_REG_IRQEN,
+	OMAP_MCBSP_REG_WAKEUPEN,
+	OMAP_MCBSP_REG_XCCR,
+	OMAP_MCBSP_REG_RCCR,
+	OMAP_MCBSP_REG_XBUFFSTAT,
+	OMAP_MCBSP_REG_RBUFFSTAT,
+	OMAP_MCBSP_REG_SSELCR,
+};
+
+/* OMAP3 sidetone control registers */
+#define OMAP_ST_REG_REV		0x00
+#define OMAP_ST_REG_SYSCONFIG	0x10
+#define OMAP_ST_REG_IRQSTATUS	0x18
+#define OMAP_ST_REG_IRQENABLE	0x1C
+#define OMAP_ST_REG_SGAINCR	0x24
+#define OMAP_ST_REG_SFIRCR	0x28
+#define OMAP_ST_REG_SSELCR	0x2C
+
+/************************** McBSP SPCR1 bit definitions ***********************/
+#define RRST			BIT(0)
+#define RRDY			BIT(1)
+#define RFULL			BIT(2)
+#define RSYNC_ERR		BIT(3)
+#define RINTM(value)		(((value) & 0x3) << 4)	/* bits 4:5 */
+#define ABIS			BIT(6)
+#define DXENA			BIT(7)
+#define CLKSTP(value)		(((value) & 0x3) << 11)	/* bits 11:12 */
+#define RJUST(value)		(((value) & 0x3) << 13)	/* bits 13:14 */
+#define ALB			BIT(15)
+#define DLB			BIT(15)
+
+/************************** McBSP SPCR2 bit definitions ***********************/
+#define XRST			BIT(0)
+#define XRDY			BIT(1)
+#define XEMPTY			BIT(2)
+#define XSYNC_ERR		BIT(3)
+#define XINTM(value)		(((value) & 0x3) << 4)	/* bits 4:5 */
+#define GRST			BIT(6)
+#define FRST			BIT(7)
+#define SOFT			BIT(8)
+#define FREE			BIT(9)
+
+/************************** McBSP PCR bit definitions *************************/
+#define CLKRP			BIT(0)
+#define CLKXP			BIT(1)
+#define FSRP			BIT(2)
+#define FSXP			BIT(3)
+#define DR_STAT			BIT(4)
+#define DX_STAT			BIT(5)
+#define CLKS_STAT		BIT(6)
+#define SCLKME			BIT(7)
+#define CLKRM			BIT(8)
+#define CLKXM			BIT(9)
+#define FSRM			BIT(10)
+#define FSXM			BIT(11)
+#define RIOEN			BIT(12)
+#define XIOEN			BIT(13)
+#define IDLE_EN			BIT(14)
+
+/************************** McBSP RCR1 bit definitions ************************/
+#define RWDLEN1(value)		(((value) & 0x7) << 5)	/* Bits 5:7 */
+#define RFRLEN1(value)		(((value) & 0x7f) << 8)	/* Bits 8:14 */
+
+/************************** McBSP XCR1 bit definitions ************************/
+#define XWDLEN1(value)		(((value) & 0x7) << 5)	/* Bits 5:7 */
+#define XFRLEN1(value)		(((value) & 0x7f) << 8)	/* Bits 8:14 */
+
+/*************************** McBSP RCR2 bit definitions ***********************/
+#define RDATDLY(value)		((value) & 0x3)		/* Bits 0:1 */
+#define RFIG			BIT(2)
+#define RCOMPAND(value)		(((value) & 0x3) << 3)	/* Bits 3:4 */
+#define RWDLEN2(value)		(((value) & 0x7) << 5)	/* Bits 5:7 */
+#define RFRLEN2(value)		(((value) & 0x7f) << 8)	/* Bits 8:14 */
+#define RPHASE			BIT(15)
+
+/*************************** McBSP XCR2 bit definitions ***********************/
+#define XDATDLY(value)		((value) & 0x3)		/* Bits 0:1 */
+#define XFIG			BIT(2)
+#define XCOMPAND(value)		(((value) & 0x3) << 3)	/* Bits 3:4 */
+#define XWDLEN2(value)		(((value) & 0x7) << 5)	/* Bits 5:7 */
+#define XFRLEN2(value)		(((value) & 0x7f) << 8)	/* Bits 8:14 */
+#define XPHASE			BIT(15)
+
+/************************* McBSP SRGR1 bit definitions ************************/
+#define CLKGDV(value)		((value) & 0x7f)		/* Bits 0:7 */
+#define FWID(value)		(((value) & 0xff) << 8)	/* Bits 8:15 */
+
+/************************* McBSP SRGR2 bit definitions ************************/
+#define FPER(value)		((value) & 0x0fff)	/* Bits 0:11 */
+#define FSGM			BIT(12)
+#define CLKSM			BIT(13)
+#define CLKSP			BIT(14)
+#define GSYNC			BIT(15)
+
+/************************* McBSP MCR1 bit definitions *************************/
+#define RMCM			BIT(0)
+#define RCBLK(value)		(((value) & 0x7) << 2)	/* Bits 2:4 */
+#define RPABLK(value)		(((value) & 0x3) << 5)	/* Bits 5:6 */
+#define RPBBLK(value)		(((value) & 0x3) << 7)	/* Bits 7:8 */
+
+/************************* McBSP MCR2 bit definitions *************************/
+#define XMCM(value)		((value) & 0x3)		/* Bits 0:1 */
+#define XCBLK(value)		(((value) & 0x7) << 2)	/* Bits 2:4 */
+#define XPABLK(value)		(((value) & 0x3) << 5)	/* Bits 5:6 */
+#define XPBBLK(value)		(((value) & 0x3) << 7)	/* Bits 7:8 */
+
+/*********************** McBSP XCCR bit definitions *************************/
+#define XDISABLE		BIT(0)
+#define XDMAEN			BIT(3)
+#define DILB			BIT(5)
+#define XFULL_CYCLE		BIT(11)
+#define DXENDLY(value)		(((value) & 0x3) << 12)	/* Bits 12:13 */
+#define PPCONNECT		BIT(14)
+#define EXTCLKGATE		BIT(15)
+
+/********************** McBSP RCCR bit definitions *************************/
+#define RDISABLE		BIT(0)
+#define RDMAEN			BIT(3)
+#define RFULL_CYCLE		BIT(11)
+
+/********************** McBSP SYSCONFIG bit definitions ********************/
+#define SOFTRST			BIT(1)
+#define ENAWAKEUP		BIT(2)
+#define SIDLEMODE(value)	(((value) & 0x3) << 3)
+#define CLOCKACTIVITY(value)	(((value) & 0x3) << 8)
+
+/********************** McBSP SSELCR bit definitions ***********************/
+#define SIDETONEEN		BIT(10)
+
+/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/
+#define ST_AUTOIDLE		BIT(0)
+
+/********************** McBSP Sidetone SGAINCR bit definitions *************/
+#define ST_CH0GAIN(value)	((value) & 0xffff)	/* Bits 0:15 */
+#define ST_CH1GAIN(value)	(((value) & 0xffff) << 16) /* Bits 16:31 */
+
+/********************** McBSP Sidetone SFIRCR bit definitions **************/
+#define ST_FIRCOEFF(value)	((value) & 0xffff)	/* Bits 0:15 */
+
+/********************** McBSP Sidetone SSELCR bit definitions **************/
+#define ST_SIDETONEEN		BIT(0)
+#define ST_COEFFWREN		BIT(1)
+#define ST_COEFFWRDONE		BIT(2)
+
+/********************** McBSP DMA operating modes **************************/
+#define MCBSP_DMA_MODE_ELEMENT		0
+#define MCBSP_DMA_MODE_THRESHOLD	1
+#define MCBSP_DMA_MODE_FRAME		2
+
+/********************** McBSP WAKEUPEN bit definitions *********************/
+#define RSYNCERREN		BIT(0)
+#define RFSREN			BIT(1)
+#define REOFEN			BIT(2)
+#define RRDYEN			BIT(3)
+#define XSYNCERREN		BIT(7)
+#define XFSXEN			BIT(8)
+#define XEOFEN			BIT(9)
+#define XRDYEN			BIT(10)
+#define XEMPTYEOFEN		BIT(14)
+
+/* Clock signal muxing options */
+#define CLKR_SRC_CLKR		0 /* CLKR signal is from the CLKR pin */
+#define CLKR_SRC_CLKX		1 /* CLKR signal is from the CLKX pin */
+#define FSR_SRC_FSR		2 /* FSR signal is from the FSR pin */
+#define FSR_SRC_FSX		3 /* FSR signal is from the FSX pin */
+
+/* McBSP functional clock sources */
+#define MCBSP_CLKS_PRCM_SRC	0
+#define MCBSP_CLKS_PAD_SRC	1
+
+/* we don't do multichannel for now */
+struct omap_mcbsp_reg_cfg {
+	u16 spcr2;
+	u16 spcr1;
+	u16 rcr2;
+	u16 rcr1;
+	u16 xcr2;
+	u16 xcr1;
+	u16 srgr2;
+	u16 srgr1;
+	u16 mcr2;
+	u16 mcr1;
+	u16 pcr0;
+	u16 rcerc;
+	u16 rcerd;
+	u16 xcerc;
+	u16 xcerd;
+	u16 rcere;
+	u16 rcerf;
+	u16 xcere;
+	u16 xcerf;
+	u16 rcerg;
+	u16 rcerh;
+	u16 xcerg;
+	u16 xcerh;
+	u16 xccr;
+	u16 rccr;
+};
+
+struct omap_mcbsp_st_data {
+	void __iomem *io_base_st;
+	bool running;
+	bool enabled;
+	s16 taps[128];	/* Sidetone filter coefficients */
+	int nr_taps;	/* Number of filter coefficients in use */
+	s16 ch0gain;
+	s16 ch1gain;
+};
+
+struct omap_mcbsp {
+	struct device *dev;
+	struct clk *fclk;
+	spinlock_t lock;
+	unsigned long phys_base;
+	unsigned long phys_dma_base;
+	void __iomem *io_base;
+	u8 id;
+	/*
+	 * Flags indicating is the bus already activated and configured by
+	 * another substream
+	 */
+	int active;
+	int configured;
+	u8 free;
+
+	int rx_irq;
+	int tx_irq;
+
+	/* Protect the field .free, while checking if the mcbsp is in use */
+	struct omap_mcbsp_platform_data *pdata;
+	struct omap_mcbsp_st_data *st_data;
+	struct omap_mcbsp_reg_cfg cfg_regs;
+	struct omap_pcm_dma_data dma_data[2];
+	int dma_op_mode;
+	u16 max_tx_thres;
+	u16 max_rx_thres;
+	void *reg_cache;
+	int reg_cache_size;
+
+	unsigned int fmt;
+	unsigned int in_freq;
+	int clk_div;
+	int wlen;
+};
+
+void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
+		       const struct omap_mcbsp_reg_cfg *config);
+void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold);
+void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold);
+u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp);
+u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp);
+int omap_mcbsp_get_dma_op_mode(struct omap_mcbsp *mcbsp);
+int omap_mcbsp_request(struct omap_mcbsp *mcbsp);
+void omap_mcbsp_free(struct omap_mcbsp *mcbsp);
+void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx);
+void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx);
+
+/* McBSP functional clock source changing function */
+int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id);
+
+/* McBSP signal muxing API */
+int omap_mcbsp_6pin_src_mux(struct omap_mcbsp *mcbsp, u8 mux);
+
+/* Sidetone specific API */
+int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain);
+int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain);
+int omap_st_enable(struct omap_mcbsp *mcbsp);
+int omap_st_disable(struct omap_mcbsp *mcbsp);
+int omap_st_is_enabled(struct omap_mcbsp *mcbsp);
+
+int __devinit omap_mcbsp_init(struct platform_device *pdev);
+void __devexit omap_mcbsp_sysfs_remove(struct omap_mcbsp *mcbsp);
+
+#endif /* __ASOC_MCBSP_H */
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 597be41..abac4b6 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -55,9 +55,8 @@
 static int n810_jack_func;
 static int n810_dmic_func;
 
-static void n810_ext_control(struct snd_soc_codec *codec)
+static void n810_ext_control(struct snd_soc_dapm_context *dapm)
 {
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int hp = 0, line1l = 0;
 
 	switch (n810_jack_func) {
@@ -102,7 +101,7 @@
 	snd_pcm_hw_constraint_minmax(runtime,
 				     SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
 
-	n810_ext_control(codec);
+	n810_ext_control(&codec->dapm);
 	return clk_enable(sys_clkout2);
 }
 
@@ -142,13 +141,13 @@
 static int n810_set_spk(struct snd_kcontrol *kcontrol,
 			struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
 
 	if (n810_spk_func == ucontrol->value.integer.value[0])
 		return 0;
 
 	n810_spk_func = ucontrol->value.integer.value[0];
-	n810_ext_control(codec);
+	n810_ext_control(&card->dapm);
 
 	return 1;
 }
@@ -164,13 +163,13 @@
 static int n810_set_jack(struct snd_kcontrol *kcontrol,
 			 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
 
 	if (n810_jack_func == ucontrol->value.integer.value[0])
 		return 0;
 
 	n810_jack_func = ucontrol->value.integer.value[0];
-	n810_ext_control(codec);
+	n810_ext_control(&card->dapm);
 
 	return 1;
 }
@@ -186,13 +185,13 @@
 static int n810_set_input(struct snd_kcontrol *kcontrol,
 			  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
 
 	if (n810_dmic_func == ucontrol->value.integer.value[0])
 		return 0;
 
 	n810_dmic_func = ucontrol->value.integer.value[0];
-	n810_ext_control(codec);
+	n810_ext_control(&card->dapm);
 
 	return 1;
 }
@@ -276,7 +275,7 @@
 static struct snd_soc_dai_link n810_dai = {
 	.name = "TLV320AIC33",
 	.stream_name = "AIC33",
-	.cpu_dai_name = "omap-mcbsp-dai.1",
+	.cpu_dai_name = "omap-mcbsp.2",
 	.platform_name = "omap-pcm-audio",
 	.codec_name = "tlv320aic3x-codec.2-0018",
 	.codec_dai_name = "tlv320aic3x-hifi",
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
new file mode 100644
index 0000000..93bb8ee
--- /dev/null
+++ b/sound/soc/omap/omap-abe-twl6040.c
@@ -0,0 +1,349 @@
+/*
+ * omap-abe-twl6040.c  --  SoC audio for TI OMAP based boards with ABE and
+ *			   twl6040 codec
+ *
+ * Author: Misael Lopez Cruz <misael.lopez@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
+ *
+ */
+
+#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 <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+#include <plat/hardware.h>
+#include <plat/mux.h>
+
+#include "omap-dmic.h"
+#include "omap-mcpdm.h"
+#include "omap-pcm.h"
+#include "../codecs/twl6040.h"
+
+static int omap_abe_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;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_card *card = codec->card;
+	struct omap_abe_twl6040_data *pdata = dev_get_platdata(card->dev);
+	int clk_id, freq;
+	int ret;
+
+	clk_id = twl6040_get_clk_id(rtd->codec);
+	if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
+		freq = pdata->mclk_freq;
+	else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL)
+		freq = 32768;
+	else
+		return -EINVAL;
+
+	/* set the codec mclk */
+	ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq,
+				SND_SOC_CLOCK_IN);
+	if (ret) {
+		printk(KERN_ERR "can't set codec system clock\n");
+		return ret;
+	}
+	return ret;
+}
+
+static struct snd_soc_ops omap_abe_ops = {
+	.hw_params = omap_abe_hw_params,
+};
+
+static int omap_abe_dmic_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;
+	int ret = 0;
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_SYSCLK_PAD_CLKS,
+				     19200000, SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		printk(KERN_ERR "can't set DMIC cpu system clock\n");
+		return ret;
+	}
+	ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_ABE_DMIC_CLK, 2400000,
+				     SND_SOC_CLOCK_OUT);
+	if (ret < 0) {
+		printk(KERN_ERR "can't set DMIC output clock\n");
+		return ret;
+	}
+	return 0;
+}
+
+static struct snd_soc_ops omap_abe_dmic_ops = {
+	.hw_params = omap_abe_dmic_hw_params,
+};
+
+/* Headset jack */
+static struct snd_soc_jack hs_jack;
+
+/*Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+	{
+		.pin = "Headset Mic",
+		.mask = SND_JACK_MICROPHONE,
+	},
+	{
+		.pin = "Headset Stereophone",
+		.mask = SND_JACK_HEADPHONE,
+	},
+};
+
+/* SDP4430 machine DAPM */
+static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
+	/* Outputs */
+	SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+	SND_SOC_DAPM_SPK("Earphone Spk", NULL),
+	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+	SND_SOC_DAPM_LINE("Line Out", NULL),
+	SND_SOC_DAPM_SPK("Vibrator", NULL),
+
+	/* Inputs */
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Main Handset Mic", NULL),
+	SND_SOC_DAPM_MIC("Sub Handset Mic", NULL),
+	SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* Routings for outputs */
+	{"Headset Stereophone", NULL, "HSOL"},
+	{"Headset Stereophone", NULL, "HSOR"},
+
+	{"Earphone Spk", NULL, "EP"},
+
+	{"Ext Spk", NULL, "HFL"},
+	{"Ext Spk", NULL, "HFR"},
+
+	{"Line Out", NULL, "AUXL"},
+	{"Line Out", NULL, "AUXR"},
+
+	{"Vibrator", NULL, "VIBRAL"},
+	{"Vibrator", NULL, "VIBRAR"},
+
+	/* Routings for inputs */
+	{"HSMIC", NULL, "Headset Mic"},
+	{"Headset Mic", NULL, "Headset Mic Bias"},
+
+	{"MAINMIC", NULL, "Main Handset Mic"},
+	{"Main Handset Mic", NULL, "Main Mic Bias"},
+
+	{"SUBMIC", NULL, "Sub Handset Mic"},
+	{"Sub Handset Mic", NULL, "Main Mic Bias"},
+
+	{"AFML", NULL, "Line In"},
+	{"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);
+	int hs_trim;
+	int ret = 0;
+
+	/* 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, "Vinrator");
+	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");
+
+	/*
+	 * Configure McPDM offset cancellation based on the HSOTRIM value from
+	 * twl6040.
+	 */
+	hs_trim = twl6040_get_trim_value(codec, TWL6040_TRIM_HSOTRIM);
+	omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim),
+					TWL6040_HSF_TRIM_RIGHT(hs_trim));
+
+	/* Headset jack detection only if it is supported */
+	if (pdata->jack_detection) {
+		ret = snd_soc_jack_new(codec, "Headset Jack",
+					SND_JACK_HEADSET, &hs_jack);
+		if (ret)
+			return ret;
+
+		ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+					hs_jack_pins);
+		twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
+	}
+
+	return ret;
+}
+
+static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = {
+	SND_SOC_DAPM_MIC("Digital Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route dmic_audio_map[] = {
+	{"DMic", NULL, "Digital Mic"},
+	{"Digital Mic", NULL, "Digital Mic1 Bias"},
+};
+
+static int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int ret;
+
+	ret = snd_soc_dapm_new_controls(dapm, dmic_dapm_widgets,
+				ARRAY_SIZE(dmic_dapm_widgets));
+	if (ret)
+		return ret;
+
+	return snd_soc_dapm_add_routes(dapm, dmic_audio_map,
+				ARRAY_SIZE(dmic_audio_map));
+}
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link twl6040_dmic_dai[] = {
+	{
+		.name = "TWL6040",
+		.stream_name = "TWL6040",
+		.cpu_dai_name = "omap-mcpdm",
+		.codec_dai_name = "twl6040-legacy",
+		.platform_name = "omap-pcm-audio",
+		.codec_name = "twl6040-codec",
+		.init = omap_abe_twl6040_init,
+		.ops = &omap_abe_ops,
+	},
+	{
+		.name = "DMIC",
+		.stream_name = "DMIC Capture",
+		.cpu_dai_name = "omap-dmic",
+		.codec_dai_name = "dmic-hifi",
+		.platform_name = "omap-pcm-audio",
+		.codec_name = "dmic-codec",
+		.init = omap_abe_dmic_init,
+		.ops = &omap_abe_dmic_ops,
+	},
+};
+
+static struct snd_soc_dai_link twl6040_only_dai[] = {
+	{
+		.name = "TWL6040",
+		.stream_name = "TWL6040",
+		.cpu_dai_name = "omap-mcpdm",
+		.codec_dai_name = "twl6040-legacy",
+		.platform_name = "omap-pcm-audio",
+		.codec_name = "twl6040-codec",
+		.init = omap_abe_twl6040_init,
+		.ops = &omap_abe_ops,
+	},
+};
+
+/* Audio machine driver */
+static struct snd_soc_card omap_abe_card = {
+	.owner = THIS_MODULE,
+
+	.dapm_widgets = twl6040_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets),
+	.dapm_routes = audio_map,
+	.num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static __devinit int omap_abe_probe(struct platform_device *pdev)
+{
+	struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev);
+	struct snd_soc_card *card = &omap_abe_card;
+	int ret;
+
+	card->dev = &pdev->dev;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "Missing pdata\n");
+		return -ENODEV;
+	}
+
+	if (pdata->card_name) {
+		card->name = pdata->card_name;
+	} else {
+		dev_err(&pdev->dev, "Card name is not provided\n");
+		return -ENODEV;
+	}
+
+	if (!pdata->mclk_freq) {
+		dev_err(&pdev->dev, "MCLK frequency missing\n");
+		return -ENODEV;
+	}
+
+	if (pdata->has_dmic) {
+		card->dai_link = twl6040_dmic_dai;
+		card->num_links = ARRAY_SIZE(twl6040_dmic_dai);
+	} else {
+		card->dai_link = twl6040_only_dai;
+		card->num_links = ARRAY_SIZE(twl6040_only_dai);
+	}
+
+	ret = snd_soc_register_card(card);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+
+	return ret;
+}
+
+static int __devexit omap_abe_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(card);
+
+	return 0;
+}
+
+static struct platform_driver omap_abe_driver = {
+	.driver = {
+		.name = "omap-abe-twl6040",
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe = omap_abe_probe,
+	.remove = __devexit_p(omap_abe_remove),
+};
+
+module_platform_driver(omap_abe_driver);
+
+MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
+MODULE_DESCRIPTION("ALSA SoC for OMAP boards with ABE and twl6040 codec");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap-abe-twl6040");
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
index 0855c1c..4dcb5a7 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/omap/omap-dmic.c
@@ -113,12 +113,10 @@
 
 	mutex_lock(&dmic->mutex);
 
-	if (!dai->active) {
-		snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24);
+	if (!dai->active)
 		dmic->active = 1;
-	} else {
+	else
 		ret = -EBUSY;
-	}
 
 	mutex_unlock(&dmic->mutex);
 
@@ -445,6 +443,7 @@
 		.channels_max = 6,
 		.rates = SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000,
 		.formats = SNDRV_PCM_FMTBIT_S32_LE,
+		.sig_bits = 24,
 	},
 	.ops = &omap_dmic_dai_ops,
 };
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 0173719..6912ac7 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -25,6 +25,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/pm_runtime.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -33,6 +34,7 @@
 
 #include <plat/dma.h>
 #include <plat/mcbsp.h>
+#include "mcbsp.h"
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
 
@@ -46,42 +48,31 @@
 	.private_value = (unsigned long) &(struct soc_mixer_control) \
 	{.min = xmin, .max = xmax} }
 
-struct omap_mcbsp_data {
-	unsigned int			bus_id;
-	struct omap_mcbsp_reg_cfg	regs;
-	unsigned int			fmt;
-	/*
-	 * Flags indicating is the bus already activated and configured by
-	 * another substream
-	 */
-	int				active;
-	int				configured;
-	unsigned int			in_freq;
-	int				clk_div;
-	int				wlen;
+enum {
+	OMAP_MCBSP_WORD_8 = 0,
+	OMAP_MCBSP_WORD_12,
+	OMAP_MCBSP_WORD_16,
+	OMAP_MCBSP_WORD_20,
+	OMAP_MCBSP_WORD_24,
+	OMAP_MCBSP_WORD_32,
 };
 
-static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
-
 /*
  * Stream DMA parameters. DMA request line and port address are set runtime
  * since they are different between OMAP1 and later OMAPs
  */
-static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2];
-
 static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
 	struct omap_pcm_dma_data *dma_data;
-	int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
 	int words;
 
 	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
 	/* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
-	if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
+	if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
 		/*
 		 * Configure McBSP threshold based on either:
 		 * packet_size, when the sDMA is in packet mode, or
@@ -91,15 +82,15 @@
 			words = dma_data->packet_size;
 		else
 			words = snd_pcm_lib_period_bytes(substream) /
-							(mcbsp_data->wlen / 8);
+							(mcbsp->wlen / 8);
 	else
 		words = 1;
 
 	/* Configure McBSP internal buffer usage */
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, words);
+		omap_mcbsp_set_tx_threshold(mcbsp, words);
 	else
-		omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words);
+		omap_mcbsp_set_rx_threshold(mcbsp, words);
 }
 
 static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
@@ -109,12 +100,12 @@
 					SNDRV_PCM_HW_PARAM_BUFFER_SIZE);
 	struct snd_interval *channels = hw_param_interval(params,
 					SNDRV_PCM_HW_PARAM_CHANNELS);
-	struct omap_mcbsp_data *mcbsp_data = rule->private;
+	struct omap_mcbsp *mcbsp = rule->private;
 	struct snd_interval frames;
 	int size;
 
 	snd_interval_any(&frames);
-	size = omap_mcbsp_get_fifo_size(mcbsp_data->bus_id);
+	size = mcbsp->pdata->buffer_size;
 
 	frames.min = size / channels->min;
 	frames.integer = 1;
@@ -124,12 +115,11 @@
 static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
 				  struct snd_soc_dai *cpu_dai)
 {
-	struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
-	int bus_id = mcbsp_data->bus_id;
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
 	int err = 0;
 
 	if (!cpu_dai->active)
-		err = omap_mcbsp_request(bus_id);
+		err = omap_mcbsp_request(mcbsp);
 
 	/*
 	 * OMAP3 McBSP FIFO is word structured.
@@ -146,16 +136,16 @@
 	 * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
 	 * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
 	 */
-	if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
+	if (mcbsp->pdata->buffer_size) {
 		/*
 		* Rule for the buffer size. We should not allow
 		* smaller buffer than the FIFO size to avoid underruns
 		*/
 		snd_pcm_hw_rule_add(substream->runtime, 0,
-				    SNDRV_PCM_HW_PARAM_CHANNELS,
+				    SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
 				    omap_mcbsp_hwrule_min_buffersize,
-				    mcbsp_data,
-				    SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
+				    mcbsp,
+				    SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 
 		/* Make sure, that the period size is always even */
 		snd_pcm_hw_constraint_step(substream->runtime, 0,
@@ -168,33 +158,33 @@
 static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
 				    struct snd_soc_dai *cpu_dai)
 {
-	struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
 
 	if (!cpu_dai->active) {
-		omap_mcbsp_free(mcbsp_data->bus_id);
-		mcbsp_data->configured = 0;
+		omap_mcbsp_free(mcbsp);
+		mcbsp->configured = 0;
 	}
 }
 
 static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 				  struct snd_soc_dai *cpu_dai)
 {
-	struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
 	int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		mcbsp_data->active++;
-		omap_mcbsp_start(mcbsp_data->bus_id, play, !play);
+		mcbsp->active++;
+		omap_mcbsp_start(mcbsp, play, !play);
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		omap_mcbsp_stop(mcbsp_data->bus_id, play, !play);
-		mcbsp_data->active--;
+		omap_mcbsp_stop(mcbsp, play, !play);
+		mcbsp->active--;
 		break;
 	default:
 		err = -EINVAL;
@@ -209,14 +199,14 @@
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
 	u16 fifo_use;
 	snd_pcm_sframes_t delay;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		fifo_use = omap_mcbsp_get_tx_delay(mcbsp_data->bus_id);
+		fifo_use = omap_mcbsp_get_tx_delay(mcbsp);
 	else
-		fifo_use = omap_mcbsp_get_rx_delay(mcbsp_data->bus_id);
+		fifo_use = omap_mcbsp_get_rx_delay(mcbsp);
 
 	/*
 	 * Divide the used locations with the channel count to get the
@@ -232,19 +222,14 @@
 				    struct snd_pcm_hw_params *params,
 				    struct snd_soc_dai *cpu_dai)
 {
-	struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
-	struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+	struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
 	struct omap_pcm_dma_data *dma_data;
-	int dma, bus_id = mcbsp_data->bus_id;
 	int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
 	int pkt_size = 0;
-	unsigned long port;
 	unsigned int format, div, framesize, master;
 
-	dma_data = &omap_mcbsp_dai_dma_params[cpu_dai->id][substream->stream];
-
-	dma = omap_mcbsp_dma_ch_params(bus_id, substream->stream);
-	port = omap_mcbsp_dma_reg_params(bus_id, substream->stream);
+	dma_data = &mcbsp->dma_data[substream->stream];
 
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
@@ -258,20 +243,17 @@
 	default:
 		return -EINVAL;
 	}
-	if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
+	if (mcbsp->pdata->buffer_size) {
 		dma_data->set_threshold = omap_mcbsp_set_threshold;
 		/* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
-		if (omap_mcbsp_get_dma_op_mode(bus_id) ==
-						MCBSP_DMA_MODE_THRESHOLD) {
+		if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
 			int period_words, max_thrsh;
 
 			period_words = params_period_bytes(params) / (wlen / 8);
 			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-				max_thrsh = omap_mcbsp_get_max_tx_threshold(
-							    mcbsp_data->bus_id);
+				max_thrsh = mcbsp->max_tx_thres;
 			else
-				max_thrsh = omap_mcbsp_get_max_rx_threshold(
-							    mcbsp_data->bus_id);
+				max_thrsh = mcbsp->max_rx_thres;
 			/*
 			 * If the period contains less or equal number of words,
 			 * we are using the original threshold mode setup:
@@ -304,15 +286,12 @@
 		}
 	}
 
-	dma_data->name = substream->stream ? "Audio Capture" : "Audio Playback";
-	dma_data->dma_req = dma;
-	dma_data->port_addr = port;
 	dma_data->sync_mode = sync_mode;
 	dma_data->packet_size = pkt_size;
 
 	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
 
-	if (mcbsp_data->configured) {
+	if (mcbsp->configured) {
 		/* McBSP already configured by another stream */
 		return 0;
 	}
@@ -321,7 +300,7 @@
 	regs->xcr2	&= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7));
 	regs->rcr1	&= ~(RFRLEN1(0x7f) | RWDLEN1(7));
 	regs->xcr1	&= ~(XFRLEN1(0x7f) | XWDLEN1(7));
-	format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+	format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
 	wpf = channels = params_channels(params);
 	if (channels == 2 && (format == SND_SOC_DAIFMT_I2S ||
 			      format == SND_SOC_DAIFMT_LEFT_J)) {
@@ -359,10 +338,10 @@
 
 	/* In McBSP master modes, FRAME (i.e. sample rate) is generated
 	 * by _counting_ BCLKs. Calculate frame size in BCLKs */
-	master = mcbsp_data->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+	master = mcbsp->fmt & SND_SOC_DAIFMT_MASTER_MASK;
 	if (master ==	SND_SOC_DAIFMT_CBS_CFS) {
-		div = mcbsp_data->clk_div ? mcbsp_data->clk_div : 1;
-		framesize = (mcbsp_data->in_freq / div) / params_rate(params);
+		div = mcbsp->clk_div ? mcbsp->clk_div : 1;
+		framesize = (mcbsp->in_freq / div) / params_rate(params);
 
 		if (framesize < wlen * channels) {
 			printk(KERN_ERR "%s: not enough bandwidth for desired rate and "
@@ -388,9 +367,9 @@
 		break;
 	}
 
-	omap_mcbsp_config(bus_id, &mcbsp_data->regs);
-	mcbsp_data->wlen = wlen;
-	mcbsp_data->configured = 1;
+	omap_mcbsp_config(mcbsp, &mcbsp->cfg_regs);
+	mcbsp->wlen = wlen;
+	mcbsp->configured = 1;
 
 	return 0;
 }
@@ -402,14 +381,14 @@
 static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 				      unsigned int fmt)
 {
-	struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
-	struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+	struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
 	bool inv_fs = false;
 
-	if (mcbsp_data->configured)
+	if (mcbsp->configured)
 		return 0;
 
-	mcbsp_data->fmt = fmt;
+	mcbsp->fmt = fmt;
 	memset(regs, 0, sizeof(*regs));
 	/* Generic McBSP register settings */
 	regs->spcr2	|= XINTM(3) | FREE;
@@ -504,13 +483,13 @@
 static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
 				     int div_id, int div)
 {
-	struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
-	struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+	struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
 
 	if (div_id != OMAP_MCBSP_CLKGDV)
 		return -ENODEV;
 
-	mcbsp_data->clk_div = div;
+	mcbsp->clk_div = div;
 	regs->srgr1	&= ~CLKGDV(0xff);
 	regs->srgr1	|= CLKGDV(div - 1);
 
@@ -521,28 +500,32 @@
 					 int clk_id, unsigned int freq,
 					 int dir)
 {
-	struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
-	struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+	struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
 	int err = 0;
 
-	if (mcbsp_data->active) {
-		if (freq == mcbsp_data->in_freq)
+	if (mcbsp->active) {
+		if (freq == mcbsp->in_freq)
 			return 0;
 		else
 			return -EBUSY;
 	}
 
-	/* The McBSP signal muxing functions are only available on McBSP1 */
-	if (clk_id == OMAP_MCBSP_CLKR_SRC_CLKR ||
-	    clk_id == OMAP_MCBSP_CLKR_SRC_CLKX ||
-	    clk_id == OMAP_MCBSP_FSR_SRC_FSR ||
-	    clk_id == OMAP_MCBSP_FSR_SRC_FSX)
-		if (cpu_class_is_omap1() || mcbsp_data->bus_id != 0)
-			return -EINVAL;
-
-	mcbsp_data->in_freq = freq;
-	regs->srgr2	&= ~CLKSM;
-	regs->pcr0	&= ~SCLKME;
+	if (clk_id == OMAP_MCBSP_SYSCLK_CLK ||
+	    clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK ||
+	    clk_id == OMAP_MCBSP_SYSCLK_CLKS_EXT ||
+	    clk_id == OMAP_MCBSP_SYSCLK_CLKX_EXT ||
+	    clk_id == OMAP_MCBSP_SYSCLK_CLKR_EXT) {
+		mcbsp->in_freq = freq;
+		regs->srgr2	&= ~CLKSM;
+		regs->pcr0	&= ~SCLKME;
+	} else if (cpu_class_is_omap1()) {
+		/*
+		 * McBSP CLKR/FSR signal muxing functions are only available on
+		 * OMAP2 or newer versions
+		 */
+		return -EINVAL;
+	}
 
 	switch (clk_id) {
 	case OMAP_MCBSP_SYSCLK_CLK:
@@ -553,7 +536,7 @@
 			err = -EINVAL;
 			break;
 		}
-		err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id,
+		err = omap2_mcbsp_set_clks_src(mcbsp,
 					       MCBSP_CLKS_PRCM_SRC);
 		break;
 	case OMAP_MCBSP_SYSCLK_CLKS_EXT:
@@ -561,7 +544,7 @@
 			err = 0;
 			break;
 		}
-		err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id,
+		err = omap2_mcbsp_set_clks_src(mcbsp,
 					       MCBSP_CLKS_PAD_SRC);
 		break;
 
@@ -573,24 +556,16 @@
 
 
 	case OMAP_MCBSP_CLKR_SRC_CLKR:
-		if (cpu_class_is_omap1())
-			break;
-		omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKR);
+		err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKR);
 		break;
 	case OMAP_MCBSP_CLKR_SRC_CLKX:
-		if (cpu_class_is_omap1())
-			break;
-		omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKX);
+		err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKX);
 		break;
 	case OMAP_MCBSP_FSR_SRC_FSR:
-		if (cpu_class_is_omap1())
-			break;
-		omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSR);
+		err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSR);
 		break;
 	case OMAP_MCBSP_FSR_SRC_FSX:
-		if (cpu_class_is_omap1())
-			break;
-		omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSX);
+		err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSX);
 		break;
 	default:
 		err = -ENODEV;
@@ -610,15 +585,27 @@
 	.set_sysclk	= omap_mcbsp_dai_set_dai_sysclk,
 };
 
-static int mcbsp_dai_probe(struct snd_soc_dai *dai)
+static int omap_mcbsp_probe(struct snd_soc_dai *dai)
 {
-	mcbsp_data[dai->id].bus_id = dai->id;
-	snd_soc_dai_set_drvdata(dai, &mcbsp_data[dai->id].bus_id);
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai);
+
+	pm_runtime_enable(mcbsp->dev);
+
+	return 0;
+}
+
+static int omap_mcbsp_remove(struct snd_soc_dai *dai)
+{
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai);
+
+	pm_runtime_disable(mcbsp->dev);
+
 	return 0;
 }
 
 static struct snd_soc_dai_driver omap_mcbsp_dai = {
-	.probe = mcbsp_dai_probe,
+	.probe = omap_mcbsp_probe,
+	.remove = omap_mcbsp_remove,
 	.playback = {
 		.channels_min = 1,
 		.channels_max = 16,
@@ -649,11 +636,13 @@
 	return 0;
 }
 
-#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(id, channel)			\
+#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(channel)			\
 static int								\
-omap_mcbsp##id##_set_st_ch##channel##_volume(struct snd_kcontrol *kc,	\
+omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc,	\
 					struct snd_ctl_elem_value *uc)	\
 {									\
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);		\
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);	\
 	struct soc_mixer_control *mc =					\
 		(struct soc_mixer_control *)kc->private_value;		\
 	int max = mc->max;						\
@@ -664,46 +653,44 @@
 		return -EINVAL;						\
 									\
 	/* OMAP McBSP implementation uses index values 0..4 */		\
-	return omap_st_set_chgain((id)-1, channel, val);		\
+	return omap_st_set_chgain(mcbsp, channel, val);			\
 }
 
-#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(id, channel)			\
+#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(channel)			\
 static int								\
-omap_mcbsp##id##_get_st_ch##channel##_volume(struct snd_kcontrol *kc,	\
+omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc,	\
 					struct snd_ctl_elem_value *uc)	\
 {									\
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);		\
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);	\
 	s16 chgain;							\
 									\
-	if (omap_st_get_chgain((id)-1, channel, &chgain))		\
+	if (omap_st_get_chgain(mcbsp, channel, &chgain))		\
 		return -EAGAIN;						\
 									\
 	uc->value.integer.value[0] = chgain;				\
 	return 0;							\
 }
 
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 0)
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 1)
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 0)
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 1)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 0)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 1)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 0)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 1)
+OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(0)
+OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(1)
+OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(0)
+OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(1)
 
 static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
 	u8 value = ucontrol->value.integer.value[0];
 
-	if (value == omap_st_is_enabled(mc->reg))
+	if (value == omap_st_is_enabled(mcbsp))
 		return 0;
 
 	if (value)
-		omap_st_enable(mc->reg);
+		omap_st_enable(mcbsp);
 	else
-		omap_st_disable(mc->reg);
+		omap_st_disable(mcbsp);
 
 	return 1;
 }
@@ -711,10 +698,10 @@
 static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
 
-	ucontrol->value.integer.value[0] = omap_st_is_enabled(mc->reg);
+	ucontrol->value.integer.value[0] = omap_st_is_enabled(mcbsp);
 	return 0;
 }
 
@@ -723,12 +710,12 @@
 			omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
 	OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 0 Volume",
 				      -32768, 32767,
-				      omap_mcbsp2_get_st_ch0_volume,
-				      omap_mcbsp2_set_st_ch0_volume),
+				      omap_mcbsp_get_st_ch0_volume,
+				      omap_mcbsp_set_st_ch0_volume),
 	OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 1 Volume",
 				      -32768, 32767,
-				      omap_mcbsp2_get_st_ch1_volume,
-				      omap_mcbsp2_set_st_ch1_volume),
+				      omap_mcbsp_get_st_ch1_volume,
+				      omap_mcbsp_set_st_ch1_volume),
 };
 
 static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = {
@@ -736,25 +723,30 @@
 			omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
 	OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 0 Volume",
 				      -32768, 32767,
-				      omap_mcbsp3_get_st_ch0_volume,
-				      omap_mcbsp3_set_st_ch0_volume),
+				      omap_mcbsp_get_st_ch0_volume,
+				      omap_mcbsp_set_st_ch0_volume),
 	OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 1 Volume",
 				      -32768, 32767,
-				      omap_mcbsp3_get_st_ch1_volume,
-				      omap_mcbsp3_set_st_ch1_volume),
+				      omap_mcbsp_get_st_ch1_volume,
+				      omap_mcbsp_set_st_ch1_volume),
 };
 
-int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id)
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)
 {
-	if (!cpu_is_omap34xx())
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+
+	if (!mcbsp->st_data)
 		return -ENODEV;
 
-	switch (mcbsp_id) {
-	case 1: /* McBSP 2 */
-		return snd_soc_add_controls(codec, omap_mcbsp2_st_controls,
+	switch (cpu_dai->id) {
+	case 2: /* McBSP 2 */
+		return snd_soc_add_dai_controls(cpu_dai,
+					omap_mcbsp2_st_controls,
 					ARRAY_SIZE(omap_mcbsp2_st_controls));
-	case 2: /* McBSP 3 */
-		return snd_soc_add_controls(codec, omap_mcbsp3_st_controls,
+	case 3: /* McBSP 3 */
+		return snd_soc_add_dai_controls(cpu_dai,
+					omap_mcbsp3_st_controls,
 					ARRAY_SIZE(omap_mcbsp3_st_controls));
 	default:
 		break;
@@ -766,18 +758,51 @@
 
 static __devinit int asoc_mcbsp_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai);
+	struct omap_mcbsp_platform_data *pdata = dev_get_platdata(&pdev->dev);
+	struct omap_mcbsp *mcbsp;
+	int ret;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "missing platform data.\n");
+		return -EINVAL;
+	}
+	mcbsp = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcbsp), GFP_KERNEL);
+	if (!mcbsp)
+		return -ENOMEM;
+
+	mcbsp->id = pdev->id;
+	mcbsp->pdata = pdata;
+	mcbsp->dev = &pdev->dev;
+	platform_set_drvdata(pdev, mcbsp);
+
+	ret = omap_mcbsp_init(pdev);
+	if (!ret)
+		return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai);
+
+	return ret;
 }
 
 static int __devexit asoc_mcbsp_remove(struct platform_device *pdev)
 {
+	struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+
 	snd_soc_unregister_dai(&pdev->dev);
+
+	if (mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+		mcbsp->pdata->ops->free(mcbsp->id);
+
+	omap_mcbsp_sysfs_remove(mcbsp);
+
+	clk_put(mcbsp->fclk);
+
+	platform_set_drvdata(pdev, NULL);
+
 	return 0;
 }
 
 static struct platform_driver asoc_mcbsp_driver = {
 	.driver = {
-			.name = "omap-mcbsp-dai",
+			.name = "omap-mcbsp",
 			.owner = THIS_MODULE,
 	},
 
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index 65cde9d..f877b16 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -59,6 +59,6 @@
 #define NUM_LINKS	5
 #endif
 
-int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id);
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd);
 
 #endif
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index 0e25df4..3970556 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -419,12 +419,14 @@
 		.channels_max = 5,
 		.rates = OMAP_MCPDM_RATES,
 		.formats = OMAP_MCPDM_FORMATS,
+		.sig_bits = 24,
 	},
 	.capture = {
 		.channels_min = 1,
 		.channels_max = 3,
 		.rates = OMAP_MCPDM_RATES,
 		.formats = OMAP_MCPDM_FORMATS,
+		.sig_bits = 24,
 	},
 	.ops = &omap_mcpdm_dai_ops,
 };
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
index f95fe30..b92248c 100644
--- a/sound/soc/omap/omap-pcm.h
+++ b/sound/soc/omap/omap-pcm.h
@@ -25,6 +25,8 @@
 #ifndef __OMAP_PCM_H__
 #define __OMAP_PCM_H__
 
+struct snd_pcm_substream;
+
 struct omap_pcm_dma_data {
 	char		*name;		/* stream identifier */
 	int		dma_req;	/* DMA request line */
diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c
index 3357dcc..2830dfd 100644
--- a/sound/soc/omap/omap3beagle.c
+++ b/sound/soc/omap/omap3beagle.c
@@ -91,7 +91,7 @@
 static struct snd_soc_dai_link omap3beagle_dai = {
 	.name = "TWL4030",
 	.stream_name = "TWL4030",
-	.cpu_dai_name = "omap-mcbsp-dai.1",
+	.cpu_dai_name = "omap-mcbsp.2",
 	.platform_name = "omap-pcm-audio",
 	.codec_dai_name = "twl4030-hifi",
 	.codec_name = "twl4030-codec",
diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
index 071fcb0..3d468c9 100644
--- a/sound/soc/omap/omap3evm.c
+++ b/sound/soc/omap/omap3evm.c
@@ -58,7 +58,7 @@
 static struct snd_soc_dai_link omap3evm_dai = {
 	.name 		= "TWL4030",
 	.stream_name 	= "TWL4030",
-	.cpu_dai_name = "omap-mcbsp-dai.1",
+	.cpu_dai_name = "omap-mcbsp.2",
 	.codec_dai_name = "twl4030-hifi",
 	.platform_name = "omap-pcm-audio",
 	.codec_name = "twl4030-codec",
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index 07794bd..4c3a097 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -208,7 +208,7 @@
 	{
 		.name = "PCM1773",
 		.stream_name = "HiFi Out",
-		.cpu_dai_name = "omap-mcbsp-dai.1",
+		.cpu_dai_name = "omap-mcbsp.2",
 		.codec_dai_name = "twl4030-hifi",
 		.platform_name = "omap-pcm-audio",
 		.codec_name = "twl4030-codec",
@@ -219,7 +219,7 @@
 	}, {
 		.name = "TWL4030",
 		.stream_name = "Line/Mic In",
-		.cpu_dai_name = "omap-mcbsp-dai.3",
+		.cpu_dai_name = "omap-mcbsp.4",
 		.codec_dai_name = "twl4030-hifi",
 		.platform_name = "omap-pcm-audio",
 		.codec_name = "twl4030-codec",
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index d859b59..b1a9d64 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -96,7 +96,7 @@
 static struct snd_soc_dai_link osk_dai = {
 	.name = "TLV320AIC23",
 	.stream_name = "AIC23",
-	.cpu_dai_name = "omap-mcbsp-dai.0",
+	.cpu_dai_name = "omap-mcbsp.1",
 	.codec_dai_name = "tlv320aic23-hifi",
 	.platform_name = "omap-pcm-audio",
 	.codec_name = "tlv320aic23-codec",
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
index 2ee889c..6ac3e0c 100644
--- a/sound/soc/omap/overo.c
+++ b/sound/soc/omap/overo.c
@@ -60,7 +60,7 @@
 static struct snd_soc_dai_link overo_dai = {
 	.name = "TWL4030",
 	.stream_name = "TWL4030",
-	.cpu_dai_name = "omap-mcbsp-dai.1",
+	.cpu_dai_name = "omap-mcbsp.2",
 	.codec_dai_name = "twl4030-hifi",
 	.platform_name = "omap-pcm-audio",
 	.codec_name = "twl4030-codec",
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index fada6ef..2712dd2 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -59,9 +59,8 @@
 static int rx51_dmic_func;
 static int rx51_jack_func;
 
-static void rx51_ext_control(struct snd_soc_codec *codec)
+static void rx51_ext_control(struct snd_soc_dapm_context *dapm)
 {
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int hp = 0, hs = 0, tvout = 0;
 
 	switch (rx51_jack_func) {
@@ -102,11 +101,11 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_card *card = rtd->card;
 
 	snd_pcm_hw_constraint_minmax(runtime,
 				     SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
-	rx51_ext_control(codec);
+	rx51_ext_control(&card->dapm);
 
 	return 0;
 }
@@ -138,13 +137,13 @@
 static int rx51_set_spk(struct snd_kcontrol *kcontrol,
 			struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 
 	if (rx51_spk_func == ucontrol->value.integer.value[0])
 		return 0;
 
 	rx51_spk_func = ucontrol->value.integer.value[0];
-	rx51_ext_control(codec);
+	rx51_ext_control(&card->dapm);
 
 	return 1;
 }
@@ -184,13 +183,13 @@
 static int rx51_set_input(struct snd_kcontrol *kcontrol,
 			  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 
 	if (rx51_dmic_func == ucontrol->value.integer.value[0])
 		return 0;
 
 	rx51_dmic_func = ucontrol->value.integer.value[0];
-	rx51_ext_control(codec);
+	rx51_ext_control(&card->dapm);
 
 	return 1;
 }
@@ -206,13 +205,13 @@
 static int rx51_set_jack(struct snd_kcontrol *kcontrol,
 			 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 
 	if (rx51_jack_func == ucontrol->value.integer.value[0])
 		return 0;
 
 	rx51_jack_func = ucontrol->value.integer.value[0];
-	rx51_ext_control(codec);
+	rx51_ext_control(&card->dapm);
 
 	return 1;
 }
@@ -297,7 +296,7 @@
 	snd_soc_dapm_nc_pin(dapm, "LINE1R");
 
 	/* Add RX-51 specific controls */
-	err = snd_soc_add_controls(codec, aic34_rx51_controls,
+	err = snd_soc_add_card_controls(rtd->card, aic34_rx51_controls,
 				   ARRAY_SIZE(aic34_rx51_controls));
 	if (err < 0)
 		return err;
@@ -314,7 +313,7 @@
 		return err;
 	snd_soc_limit_volume(codec, "TPA6130A2 Headphone Playback Volume", 42);
 
-	err = omap_mcbsp_st_add_controls(codec, 1);
+	err = omap_mcbsp_st_add_controls(rtd);
 	if (err < 0)
 		return err;
 
@@ -335,7 +334,7 @@
 {
 	int err;
 
-	err = snd_soc_add_controls(dapm->codec, aic34_rx51_controlsb,
+	err = snd_soc_add_card_controls(dapm->card, aic34_rx51_controlsb,
 				   ARRAY_SIZE(aic34_rx51_controlsb));
 	if (err < 0)
 		return err;
@@ -354,7 +353,7 @@
 	{
 		.name = "TLV320AIC34",
 		.stream_name = "AIC34",
-		.cpu_dai_name = "omap-mcbsp-dai.1",
+		.cpu_dai_name = "omap-mcbsp.2",
 		.codec_dai_name = "tlv320aic3x-hifi",
 		.platform_name = "omap-pcm-audio",
 		.codec_name = "tlv320aic3x-codec.2-0018",
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 2c85066..0e28322 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -187,7 +187,7 @@
 	{
 		.name = "TWL4030 I2S",
 		.stream_name = "TWL4030 Audio",
-		.cpu_dai_name = "omap-mcbsp-dai.1",
+		.cpu_dai_name = "omap-mcbsp.2",
 		.codec_dai_name = "twl4030-hifi",
 		.platform_name = "omap-pcm-audio",
 		.codec_name = "twl4030-codec",
@@ -199,7 +199,7 @@
 	{
 		.name = "TWL4030 PCM",
 		.stream_name = "TWL4030 Voice",
-		.cpu_dai_name = "omap-mcbsp-dai.2",
+		.cpu_dai_name = "omap-mcbsp.3",
 		.codec_dai_name = "twl4030-voice",
 		.platform_name = "omap-pcm-audio",
 		.codec_name = "twl4030-codec",
diff --git a/sound/soc/omap/sdp4430.c b/sound/soc/omap/sdp4430.c
deleted file mode 100644
index 175ba9a..0000000
--- a/sound/soc/omap/sdp4430.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * sdp4430.c  --  SoC audio for TI OMAP4430 SDP
- *
- * Author: Misael Lopez Cruz <x0052729@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
- *
- */
-
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/twl6040.h>
-#include <linux/module.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-
-#include <asm/mach-types.h>
-#include <plat/hardware.h>
-#include <plat/mux.h>
-
-#include "omap-dmic.h"
-#include "omap-mcpdm.h"
-#include "omap-pcm.h"
-#include "../codecs/twl6040.h"
-
-static int sdp4430_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 clk_id, freq;
-	int ret;
-
-	clk_id = twl6040_get_clk_id(rtd->codec);
-	if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
-		freq = 38400000;
-	else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL)
-		freq = 32768;
-	else
-		return -EINVAL;
-
-	/* set the codec mclk */
-	ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq,
-				SND_SOC_CLOCK_IN);
-	if (ret) {
-		printk(KERN_ERR "can't set codec system clock\n");
-		return ret;
-	}
-	return ret;
-}
-
-static struct snd_soc_ops sdp4430_ops = {
-	.hw_params = sdp4430_hw_params,
-};
-
-static int sdp4430_dmic_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;
-	int ret = 0;
-
-	ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_SYSCLK_PAD_CLKS,
-				     19200000, SND_SOC_CLOCK_IN);
-	if (ret < 0) {
-		printk(KERN_ERR "can't set DMIC cpu system clock\n");
-		return ret;
-	}
-	ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_ABE_DMIC_CLK, 2400000,
-				     SND_SOC_CLOCK_OUT);
-	if (ret < 0) {
-		printk(KERN_ERR "can't set DMIC output clock\n");
-		return ret;
-	}
-	return 0;
-}
-
-static struct snd_soc_ops sdp4430_dmic_ops = {
-	.hw_params = sdp4430_dmic_hw_params,
-};
-
-/* Headset jack */
-static struct snd_soc_jack hs_jack;
-
-/*Headset jack detection DAPM pins */
-static struct snd_soc_jack_pin hs_jack_pins[] = {
-	{
-		.pin = "Headset Mic",
-		.mask = SND_JACK_MICROPHONE,
-	},
-	{
-		.pin = "Headset Stereophone",
-		.mask = SND_JACK_HEADPHONE,
-	},
-};
-
-/* SDP4430 machine DAPM */
-static const struct snd_soc_dapm_widget sdp4430_twl6040_dapm_widgets[] = {
-	SND_SOC_DAPM_MIC("Ext Mic", NULL),
-	SND_SOC_DAPM_SPK("Ext Spk", NULL),
-	SND_SOC_DAPM_MIC("Headset Mic", NULL),
-	SND_SOC_DAPM_HP("Headset Stereophone", NULL),
-	SND_SOC_DAPM_SPK("Earphone Spk", NULL),
-	SND_SOC_DAPM_INPUT("FM Stereo In"),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
-	/* External Mics: MAINMIC, SUBMIC with bias*/
-	{"MAINMIC", NULL, "Main Mic Bias"},
-	{"SUBMIC", NULL, "Main Mic Bias"},
-	{"Main Mic Bias", NULL, "Ext Mic"},
-
-	/* External Speakers: HFL, HFR */
-	{"Ext Spk", NULL, "HFL"},
-	{"Ext Spk", NULL, "HFR"},
-
-	/* Headset Mic: HSMIC with bias */
-	{"HSMIC", NULL, "Headset Mic Bias"},
-	{"Headset Mic Bias", NULL, "Headset Mic"},
-
-	/* Headset Stereophone (Headphone): HSOL, HSOR */
-	{"Headset Stereophone", NULL, "HSOL"},
-	{"Headset Stereophone", NULL, "HSOR"},
-
-	/* Earphone speaker */
-	{"Earphone Spk", NULL, "EP"},
-
-	/* Aux/FM Stereo In: AFML, AFMR */
-	{"AFML", NULL, "FM Stereo In"},
-	{"AFMR", NULL, "FM Stereo In"},
-};
-
-static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_codec *codec = rtd->codec;
-	int ret, hs_trim;
-
-	/*
-	 * Configure McPDM offset cancellation based on the HSOTRIM value from
-	 * twl6040.
-	 */
-	hs_trim = twl6040_get_trim_value(codec, TWL6040_TRIM_HSOTRIM);
-	omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim),
-					TWL6040_HSF_TRIM_RIGHT(hs_trim));
-
-	/* Headset jack detection */
-	ret = snd_soc_jack_new(codec, "Headset Jack",
-				SND_JACK_HEADSET, &hs_jack);
-	if (ret)
-		return ret;
-
-	ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
-				hs_jack_pins);
-
-	if (machine_is_omap_4430sdp())
-		twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
-	else
-		snd_soc_jack_report(&hs_jack, SND_JACK_HEADSET, SND_JACK_HEADSET);
-
-	return ret;
-}
-
-static const struct snd_soc_dapm_widget sdp4430_dmic_dapm_widgets[] = {
-	SND_SOC_DAPM_MIC("Digital Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route dmic_audio_map[] = {
-	{"DMic", NULL, "Digital Mic1 Bias"},
-	{"Digital Mic1 Bias", NULL, "Digital Mic"},
-};
-
-static int sdp4430_dmic_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_codec *codec = rtd->codec;
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-	int ret;
-
-	ret = snd_soc_dapm_new_controls(dapm, sdp4430_dmic_dapm_widgets,
-				ARRAY_SIZE(sdp4430_dmic_dapm_widgets));
-	if (ret)
-		return ret;
-
-	return snd_soc_dapm_add_routes(dapm, dmic_audio_map,
-				ARRAY_SIZE(dmic_audio_map));
-}
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link sdp4430_dai[] = {
-	{
-		.name = "TWL6040",
-		.stream_name = "TWL6040",
-		.cpu_dai_name = "omap-mcpdm",
-		.codec_dai_name = "twl6040-legacy",
-		.platform_name = "omap-pcm-audio",
-		.codec_name = "twl6040-codec",
-		.init = sdp4430_twl6040_init,
-		.ops = &sdp4430_ops,
-	},
-	{
-		.name = "DMIC",
-		.stream_name = "DMIC Capture",
-		.cpu_dai_name = "omap-dmic",
-		.codec_dai_name = "dmic-hifi",
-		.platform_name = "omap-pcm-audio",
-		.codec_name = "dmic-codec",
-		.init = sdp4430_dmic_init,
-		.ops = &sdp4430_dmic_ops,
-	},
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_sdp4430 = {
-	.name = "SDP4430",
-	.owner = THIS_MODULE,
-	.dai_link = sdp4430_dai,
-	.num_links = ARRAY_SIZE(sdp4430_dai),
-
-	.dapm_widgets = sdp4430_twl6040_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(sdp4430_twl6040_dapm_widgets),
-	.dapm_routes = audio_map,
-	.num_dapm_routes = ARRAY_SIZE(audio_map),
-};
-
-static struct platform_device *sdp4430_snd_device;
-
-static int __init sdp4430_soc_init(void)
-{
-	int ret;
-
-	if (!machine_is_omap_4430sdp())
-		return -ENODEV;
-	printk(KERN_INFO "SDP4430 SoC init\n");
-
-	sdp4430_snd_device = platform_device_alloc("soc-audio", -1);
-	if (!sdp4430_snd_device) {
-		printk(KERN_ERR "Platform device allocation failed\n");
-		return -ENOMEM;
-	}
-
-	platform_set_drvdata(sdp4430_snd_device, &snd_soc_sdp4430);
-
-	ret = platform_device_add(sdp4430_snd_device);
-	if (ret)
-		goto err;
-
-	return 0;
-
-err:
-	printk(KERN_ERR "Unable to add platform device\n");
-	platform_device_put(sdp4430_snd_device);
-	return ret;
-}
-module_init(sdp4430_soc_init);
-
-static void __exit sdp4430_soc_exit(void)
-{
-	platform_device_unregister(sdp4430_snd_device);
-}
-module_exit(sdp4430_soc_exit);
-
-MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
-MODULE_DESCRIPTION("ALSA SoC SDP4430");
-MODULE_LICENSE("GPL");
-
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index 981616d..920e0d9 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -131,7 +131,7 @@
 	{
 		.name = "TWL4030 I2S",
 		.stream_name = "TWL4030 Audio",
-		.cpu_dai_name = "omap-mcbsp-dai.1",
+		.cpu_dai_name = "omap-mcbsp.2",
 		.codec_dai_name = "twl4030-hifi",
 		.platform_name = "omap-pcm-audio",
 		.codec_name = "twl4030-codec",
@@ -143,7 +143,7 @@
 	{
 		.name = "TWL4030 PCM",
 		.stream_name = "TWL4030 Voice",
-		.cpu_dai_name = "omap-mcbsp-dai.2",
+		.cpu_dai_name = "omap-mcbsp.3",
 		.codec_dai_name = "twl4030-voice",
 		.platform_name = "omap-pcm-audio",
 		.codec_name = "twl4030-codec",
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index bc21944..863367a 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -45,10 +45,8 @@
 static int corgi_jack_func;
 static int corgi_spk_func;
 
-static void corgi_ext_control(struct snd_soc_codec *codec)
+static void corgi_ext_control(struct snd_soc_dapm_context *dapm)
 {
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
 	/* set up jack connection */
 	switch (corgi_jack_func) {
 	case CORGI_HP:
@@ -104,7 +102,7 @@
 	mutex_lock(&codec->mutex);
 
 	/* check the jack status at stream startup */
-	corgi_ext_control(codec);
+	corgi_ext_control(&codec->dapm);
 
 	mutex_unlock(&codec->mutex);
 
@@ -173,13 +171,13 @@
 static int corgi_set_jack(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 
 	if (corgi_jack_func == ucontrol->value.integer.value[0])
 		return 0;
 
 	corgi_jack_func = ucontrol->value.integer.value[0];
-	corgi_ext_control(codec);
+	corgi_ext_control(&card->dapm);
 	return 1;
 }
 
@@ -193,13 +191,13 @@
 static int corgi_set_spk(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
 
 	if (corgi_spk_func == ucontrol->value.integer.value[0])
 		return 0;
 
 	corgi_spk_func = ucontrol->value.integer.value[0];
-	corgi_ext_control(codec);
+	corgi_ext_control(&card->dapm);
 	return 1;
 }
 
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index 3f7a8ec..aace19e 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -411,7 +411,7 @@
 	snd_soc_dapm_nc_pin(dapm, "VINR");
 
 	/* Add magician specific controls */
-	err = snd_soc_add_controls(codec, uda1380_magician_controls,
+	err = snd_soc_add_codec_controls(codec, uda1380_magician_controls,
 				ARRAY_SIZE(uda1380_magician_controls));
 	if (err < 0)
 		return err;
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index fd0ed10..d2cc8173 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -43,10 +43,8 @@
 static int poodle_jack_func;
 static int poodle_spk_func;
 
-static void poodle_ext_control(struct snd_soc_codec *codec)
+static void poodle_ext_control(struct snd_soc_dapm_context *dapm)
 {
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
 	/* set up jack connection */
 	if (poodle_jack_func == POODLE_HP) {
 		/* set = unmute headphone */
@@ -81,7 +79,7 @@
 	mutex_lock(&codec->mutex);
 
 	/* check the jack status at stream startup */
-	poodle_ext_control(codec);
+	poodle_ext_control(&codec->dapm);
 
 	mutex_unlock(&codec->mutex);
 
@@ -152,13 +150,13 @@
 static int poodle_set_jack(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
 
 	if (poodle_jack_func == ucontrol->value.integer.value[0])
 		return 0;
 
 	poodle_jack_func = ucontrol->value.integer.value[0];
-	poodle_ext_control(codec);
+	poodle_ext_control(&card->dapm);
 	return 1;
 }
 
@@ -172,13 +170,13 @@
 static int poodle_set_spk(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
 
 	if (poodle_spk_func == ucontrol->value.integer.value[0])
 		return 0;
 
 	poodle_spk_func = ucontrol->value.integer.value[0];
-	poodle_ext_control(codec);
+	poodle_ext_control(&card->dapm);
 	return 1;
 }
 
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index a57cfbc..fd04ce1 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -668,6 +668,38 @@
 	return 0;
 }
 
+static void pxa_ssp_set_running_bit(struct snd_pcm_substream *substream,
+				    struct ssp_device *ssp, int value)
+{
+	uint32_t sscr0 = pxa_ssp_read_reg(ssp, SSCR0);
+	uint32_t sscr1 = pxa_ssp_read_reg(ssp, SSCR1);
+	uint32_t sspsp = pxa_ssp_read_reg(ssp, SSPSP);
+	uint32_t sssr = pxa_ssp_read_reg(ssp, SSSR);
+
+	if (value && (sscr0 & SSCR0_SSE))
+		pxa_ssp_write_reg(ssp, SSCR0, sscr0 & ~SSCR0_SSE);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (value)
+			sscr1 |= SSCR1_TSRE;
+		else
+			sscr1 &= ~SSCR1_TSRE;
+	} else {
+		if (value)
+			sscr1 |= SSCR1_RSRE;
+		else
+			sscr1 &= ~SSCR1_RSRE;
+	}
+
+	pxa_ssp_write_reg(ssp, SSCR1, sscr1);
+
+	if (value) {
+		pxa_ssp_write_reg(ssp, SSSR, sssr);
+		pxa_ssp_write_reg(ssp, SSPSP, sspsp);
+		pxa_ssp_write_reg(ssp, SSCR0, sscr0 | SSCR0_SSE);
+	}
+}
+
 static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
 			   struct snd_soc_dai *cpu_dai)
 {
@@ -681,42 +713,21 @@
 		pxa_ssp_enable(ssp);
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		val = pxa_ssp_read_reg(ssp, SSCR1);
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			val |= SSCR1_TSRE;
-		else
-			val |= SSCR1_RSRE;
-		pxa_ssp_write_reg(ssp, SSCR1, val);
+		pxa_ssp_set_running_bit(substream, ssp, 1);
 		val = pxa_ssp_read_reg(ssp, SSSR);
 		pxa_ssp_write_reg(ssp, SSSR, val);
 		break;
 	case SNDRV_PCM_TRIGGER_START:
-		val = pxa_ssp_read_reg(ssp, SSCR1);
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			val |= SSCR1_TSRE;
-		else
-			val |= SSCR1_RSRE;
-		pxa_ssp_write_reg(ssp, SSCR1, val);
-		pxa_ssp_enable(ssp);
+		pxa_ssp_set_running_bit(substream, ssp, 1);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
-		val = pxa_ssp_read_reg(ssp, SSCR1);
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			val &= ~SSCR1_TSRE;
-		else
-			val &= ~SSCR1_RSRE;
-		pxa_ssp_write_reg(ssp, SSCR1, val);
+		pxa_ssp_set_running_bit(substream, ssp, 0);
 		break;
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 		pxa_ssp_disable(ssp);
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		val = pxa_ssp_read_reg(ssp, SSCR1);
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			val &= ~SSCR1_TSRE;
-		else
-			val &= ~SSCR1_RSRE;
-		pxa_ssp_write_reg(ssp, SSCR1, val);
+		pxa_ssp_set_running_bit(substream, ssp, 0);
 		break;
 
 	default:
@@ -764,7 +775,8 @@
 
 #define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
 			  SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |	\
-			  SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |	\
+			  SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |	\
+			  SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 |	\
 			  SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
 #define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index 837ff34..06ea274 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
@@ -103,7 +104,7 @@
 #define pxa2xx_ac97_resume	NULL
 #endif
 
-static int pxa2xx_ac97_probe(struct snd_soc_dai *dai)
+static int __devinit pxa2xx_ac97_probe(struct snd_soc_dai *dai)
 {
 	return pxa2xx_ac97_hw_probe(to_platform_device(dai->dev));
 }
@@ -179,7 +180,7 @@
  * There is only 1 physical AC97 interface for pxa2xx, but it
  * has extra fifo's that can be used for aux DACs and ADCs.
  */
-static struct snd_soc_dai_driver pxa_ac97_dai[] = {
+static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
 {
 	.name = "pxa2xx-ac97",
 	.ac97_control = 1,
@@ -244,13 +245,13 @@
 	 * driver to do interesting things with the clocking to get us up
 	 * and running.
 	 */
-	return snd_soc_register_dais(&pdev->dev, pxa_ac97_dai,
-			ARRAY_SIZE(pxa_ac97_dai));
+	return snd_soc_register_dais(&pdev->dev, pxa_ac97_dai_driver,
+			ARRAY_SIZE(pxa_ac97_dai_driver));
 }
 
 static int __devexit pxa2xx_ac97_dev_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(pxa_ac97_dai));
+	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(pxa_ac97_dai_driver));
 	return 0;
 }
 
diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c
index ba15451..0837065 100644
--- a/sound/soc/pxa/raumfeld.c
+++ b/sound/soc/pxa/raumfeld.c
@@ -232,7 +232,7 @@
 	.cpu_dai_name	= "pxa-ssp-dai.0",		\
 	.platform_name	= "pxa-pcm-audio",		\
 	.codec_dai_name	= "cs4270-hifi",		\
-	.codec_name	= "cs4270-codec.0-0048",	\
+	.codec_name	= "cs4270.0-0048",	\
 	.ops		= &raumfeld_cs4270_ops,		\
 }
 
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index 90c5245..fc052d8 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -44,10 +44,8 @@
 static int spitz_spk_func;
 static int spitz_mic_gpio;
 
-static void spitz_ext_control(struct snd_soc_codec *codec)
+static void spitz_ext_control(struct snd_soc_dapm_context *dapm)
 {
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
 	if (spitz_spk_func == SPITZ_SPK_ON)
 		snd_soc_dapm_enable_pin(dapm, "Ext Spk");
 	else
@@ -113,7 +111,7 @@
 	mutex_lock(&codec->mutex);
 
 	/* check the jack status at stream startup */
-	spitz_ext_control(codec);
+	spitz_ext_control(&codec->dapm);
 
 	mutex_unlock(&codec->mutex);
 
@@ -173,13 +171,13 @@
 static int spitz_set_jack(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 
 	if (spitz_jack_func == ucontrol->value.integer.value[0])
 		return 0;
 
 	spitz_jack_func = ucontrol->value.integer.value[0];
-	spitz_ext_control(codec);
+	spitz_ext_control(&card->dapm);
 	return 1;
 }
 
@@ -193,13 +191,13 @@
 static int spitz_set_spk(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 
 	if (spitz_spk_func == ucontrol->value.integer.value[0])
 		return 0;
 
 	spitz_spk_func = ucontrol->value.integer.value[0];
-	spitz_ext_control(codec);
+	spitz_ext_control(&card->dapm);
 	return 1;
 }
 
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index 564ef08..2aec63f 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -197,7 +197,7 @@
 	snd_soc_dapm_nc_pin(dapm, "MONOOUT");
 
 	/* add tosa specific controls */
-	err = snd_soc_add_controls(codec, tosa_controls,
+	err = snd_soc_add_codec_controls(codec, tosa_controls,
 				ARRAY_SIZE(tosa_controls));
 	if (err < 0)
 		return err;
diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c
index 43c014f..716da86 100644
--- a/sound/soc/s6000/s6000-pcm.c
+++ b/sound/soc/s6000/s6000-pcm.c
@@ -435,7 +435,8 @@
 {
 	struct snd_soc_pcm_runtime *runtime = pcm->private_data;
 	struct s6000_pcm_dma_params *params =
-		snd_soc_dai_get_dma_data(runtime->cpu_dai, pcm->streams[0].substream);
+		snd_soc_dai_get_dma_data(runtime->cpu_dai,
+			pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream);
 
 	free_irq(params->irq, pcm);
 	snd_pcm_lib_preallocate_free_for_all(pcm);
@@ -451,7 +452,7 @@
 	int res;
 
 	params = snd_soc_dai_get_dma_data(runtime->cpu_dai,
-			pcm->streams[0].substream);
+			pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream);
 
 	if (!card->dev->dma_mask)
 		card->dev->dma_mask = &s6000_pcm_dmamask;
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index f3417f2..fe3995c 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -1,8 +1,8 @@
 config SND_SOC_SAMSUNG
 	tristate "ASoC support for Samsung"
-	depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_EXYNOS4
+	depends on ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_EXYNOS4
 	select S3C64XX_DMA if ARCH_S3C64XX
-	select S3C2410_DMA if ARCH_S3C2410
+	select S3C2410_DMA if ARCH_S3C24XX
 	help
 	  Say Y or M if you want to add support for codecs attached to
 	  the Samsung SoCs' Audio interfaces. You will also need to
@@ -84,7 +84,7 @@
 
 config SND_SOC_SAMSUNG_LN2440SBC_ALC650
 	tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
-	depends on SND_SOC_SAMSUNG && ARCH_S3C2410
+	depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
 	select S3C2410_DMA
 	select AC97_BUS
 	select SND_SOC_AC97_CODEC
@@ -95,7 +95,7 @@
 
 config SND_SOC_SAMSUNG_S3C24XX_UDA134X
 	tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
-	depends on SND_SOC_SAMSUNG && ARCH_S3C2410
+	depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
 	select SND_S3C24XX_I2S
 	select SND_SOC_L3
 	select SND_SOC_UDA134X
@@ -107,14 +107,14 @@
 
 config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23
 	tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
-	depends on SND_SOC_SAMSUNG && ARCH_S3C2410
+	depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
 	select SND_S3C24XX_I2S
 	select SND_SOC_TLV320AIC23
 	select SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_SIMTEC_HERMES
 	tristate "SoC I2S Audio support for Simtec Hermes board"
-	depends on SND_SOC_SAMSUNG && ARCH_S3C2410
+	depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
 	select SND_S3C24XX_I2S
 	select SND_SOC_TLV320AIC3X
 	select SND_SOC_SAMSUNG_SIMTEC
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
index 7b9bf93..3d04c1f 100644
--- a/sound/soc/samsung/ac97.c
+++ b/sound/soc/samsung/ac97.c
@@ -4,7 +4,7 @@
  * 	Evolved from s3c2443-ac97.c
  *
  * Copyright (c) 2010 Samsung Electronics Co. Ltd
- * 	Author: Jaswinder Singh <jassi.brar@samsung.com>
+ *	Author: Jaswinder Singh <jassisinghbrar@gmail.com>
  * 	Credits: Graeme Gregory, Sean Choi
  *
  * This program is free software; you can redistribute it and/or modify
@@ -511,7 +511,7 @@
 
 module_platform_driver(s3c_ac97_driver);
 
-MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
+MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>");
 MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:samsung-ac97");
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c
index e4ba17c..ddc6cde 100644
--- a/sound/soc/samsung/dma.c
+++ b/sound/soc/samsung/dma.c
@@ -411,7 +411,7 @@
 	if (!card->dev->dma_mask)
 		card->dev->dma_mask = &dma_mask;
 	if (!card->dev->coherent_dma_mask)
-		card->dev->coherent_dma_mask = 0xffffffff;
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
 	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
 		ret = preallocate_dma_buffer(pcm,
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 87a874d..6ac7b82 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -3,7 +3,7 @@
  * ALSA SoC Audio Layer - Samsung I2S Controller driver
  *
  * Copyright (c) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.com>
+ *	Jaswinder Singh <jassisinghbrar@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
@@ -559,6 +559,17 @@
 		mod |= MOD_DC1_EN;
 		break;
 	case 2:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			i2s->dma_playback.dma_size = 4;
+		else
+			i2s->dma_capture.dma_size = 4;
+		break;
+	case 1:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			i2s->dma_playback.dma_size = 2;
+		else
+			i2s->dma_capture.dma_size = 2;
+
 		break;
 	default:
 		dev_err(&i2s->pdev->dev, "%d channels not supported\n",
@@ -761,15 +772,13 @@
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		local_irq_save(flags);
 
-		if (capture)
+		if (capture) {
 			i2s_rxctrl(i2s, 0);
-		else
-			i2s_txctrl(i2s, 0);
-
-		if (capture)
 			i2s_fifo(i2s, FIC_RXFLUSH);
-		else
+		} else {
+			i2s_txctrl(i2s, 0);
 			i2s_fifo(i2s, FIC_TXFLUSH);
+		}
 
 		local_irq_restore(flags);
 		break;
@@ -965,7 +974,7 @@
 	i2s->i2s_dai_drv.playback.formats = SAMSUNG_I2S_FMTS;
 
 	if (!sec) {
-		i2s->i2s_dai_drv.capture.channels_min = 2;
+		i2s->i2s_dai_drv.capture.channels_min = 1;
 		i2s->i2s_dai_drv.capture.channels_max = 2;
 		i2s->i2s_dai_drv.capture.rates = SAMSUNG_I2S_RATES;
 		i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS;
@@ -1143,7 +1152,7 @@
 module_platform_driver(samsung_i2s_driver);
 
 /* Module information */
-MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
+MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>");
 MODULE_DESCRIPTION("Samsung I2S Interface");
 MODULE_ALIAS("platform:samsung-i2s");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/i2s.h b/sound/soc/samsung/i2s.h
index 8e15f6a..d420a7c 100644
--- a/sound/soc/samsung/i2s.h
+++ b/sound/soc/samsung/i2s.h
@@ -3,7 +3,7 @@
  * ALSA SoC Audio Layer - Samsung I2S Controller driver
  *
  * Copyright (c) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.com>
+ *	Jaswinder Singh <jassisinghbrar@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/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c
index 9dd818b..e741685 100644
--- a/sound/soc/samsung/littlemill.c
+++ b/sound/soc/samsung/littlemill.c
@@ -189,6 +189,9 @@
 	/* This will check device compatibility itself */
 	wm8958_mic_detect(codec, &littlemill_headset, NULL, NULL);
 
+	/* As will this */
+	wm8994_mic_detect(codec, &littlemill_headset, 1);
+
 	return 0;
 }
 
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
index d23b19a..321d511 100644
--- a/sound/soc/samsung/neo1973_wm8753.c
+++ b/sound/soc/samsung/neo1973_wm8753.c
@@ -296,7 +296,7 @@
 	if (ret)
 		return ret;
 
-	ret = snd_soc_add_controls(codec, neo1973_gta02_wm8753_controls,
+	ret = snd_soc_add_card_controls(codec->card, neo1973_gta02_wm8753_controls,
 			ARRAY_SIZE(neo1973_gta02_wm8753_controls));
 	if (ret)
 		return ret;
@@ -328,7 +328,7 @@
 		return ret;
 
 	/* add neo1973 specific controls */
-	ret = snd_soc_add_controls(codec, neo1973_wm8753_controls,
+	ret = snd_soc_add_card_controls(rtd->card, neo1973_wm8753_controls,
 			ARRAY_SIZE(neo1973_wm8753_controls));
 	if (ret)
 		return ret;
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index 56780206c..b7b2a1f 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -3,7 +3,7 @@
  * ALSA SoC Audio Layer - S3C PCM-Controller driver
  *
  * Copyright (c) 2009 Samsung Electronics Co. Ltd
- * Author: Jaswinder Singh <jassi.brar@samsung.com>
+ * Author: Jaswinder Singh <jassisinghbrar@gmail.com>
  * based upon I2S drivers by Ben Dooks.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -639,7 +639,7 @@
 module_platform_driver(s3c_pcm_driver);
 
 /* Module information */
-MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
+MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>");
 MODULE_DESCRIPTION("S3C PCM Controller Driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:samsung-pcm");
diff --git a/sound/soc/samsung/s3c24xx_simtec.c b/sound/soc/samsung/s3c24xx_simtec.c
index a253bcc..656d5af 100644
--- a/sound/soc/samsung/s3c24xx_simtec.c
+++ b/sound/soc/samsung/s3c24xx_simtec.c
@@ -134,18 +134,18 @@
 
 void simtec_audio_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_card *card = rtd->card;
 
 	if (pdata->amp_gpio > 0) {
 		pr_debug("%s: adding amp routes\n", __func__);
 
-		snd_soc_add_controls(codec, amp_unmute_controls,
+		snd_soc_add_card_controls(card, amp_unmute_controls,
 				     ARRAY_SIZE(amp_unmute_controls));
 	}
 
 	if (pdata->amp_gain[0] > 0) {
 		pr_debug("%s: adding amp controls\n", __func__);
-		snd_soc_add_controls(codec, amp_gain_controls,
+		snd_soc_add_card_controls(card, amp_gain_controls,
 				     ARRAY_SIZE(amp_gain_controls));
 	}
 }
diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c
index bff8758..ade2809 100644
--- a/sound/soc/samsung/smdk_wm8580.c
+++ b/sound/soc/samsung/smdk_wm8580.c
@@ -2,7 +2,7 @@
  *  smdk_wm8580.c
  *
  *  Copyright (c) 2009 Samsung Electronics Co. Ltd
- *  Author: Jaswinder Singh <jassi.brar@samsung.com>
+ *  Author: Jaswinder Singh <jassisinghbrar@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
@@ -253,6 +253,6 @@
 }
 module_exit(smdk_audio_exit);
 
-MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com");
+MODULE_AUTHOR("Jaswinder Singh, jassisinghbrar@gmail.com");
 MODULE_DESCRIPTION("ALSA SoC SMDK WM8580");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/smdk_wm9713.c b/sound/soc/samsung/smdk_wm9713.c
index 8e26a73..55b2ca7 100644
--- a/sound/soc/samsung/smdk_wm9713.c
+++ b/sound/soc/samsung/smdk_wm9713.c
@@ -2,7 +2,7 @@
  * smdk_wm9713.c  --  SoC audio for SMDK
  *
  * Copyright 2010 Samsung Electronics Co. Ltd.
- * Author: Jaswinder Singh Brar <jassi.brar@samsung.com>
+ * Author: Jaswinder Singh Brar <jassisinghbrar@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
@@ -103,6 +103,6 @@
 module_exit(smdk_exit);
 
 /* Module information */
-MODULE_AUTHOR("Jaswinder Singh Brar, jassi.brar@samsung.com");
+MODULE_AUTHOR("Jaswinder Singh Brar, jassisinghbrar@gmail.com");
 MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index ea4a82d0..378cc5b 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -13,8 +13,11 @@
  */
 
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/pm_runtime.h>
 #include <linux/io.h>
+#include <linux/scatterlist.h>
+#include <linux/sh_dma.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <sound/soc.h>
@@ -53,6 +56,7 @@
 
 /* DO_FMT */
 /* DI_FMT */
+#define CR_BWS_MASK	(0x3 << 20) /* FSI2 */
 #define CR_BWS_24	(0x0 << 20) /* FSI2 */
 #define CR_BWS_16	(0x1 << 20) /* FSI2 */
 #define CR_BWS_20	(0x2 << 20) /* FSI2 */
@@ -68,6 +72,15 @@
 #define CR_TDM		(0x4 << 4)
 #define CR_TDM_D	(0x5 << 4)
 
+/* OUT_DMAC */
+/* IN_DMAC */
+#define VDMD_MASK	(0x3 << 4)
+#define VDMD_FRONT	(0x0 << 4) /* Package in front */
+#define VDMD_BACK	(0x1 << 4) /* Package in back */
+#define VDMD_STREAM	(0x2 << 4) /* Stream mode(16bit * 2) */
+
+#define DMA_ON		(0x1 << 0)
+
 /* DOFF_CTL */
 /* DIFF_CTL */
 #define IRQ_HALF	0x00100000
@@ -116,7 +129,7 @@
 
 #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
 
-typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int enable);
+typedef int (*set_rate_func)(struct device *dev, int rate, int enable);
 
 /*
  * FSI driver use below type name for variable
@@ -159,22 +172,41 @@
  *		struct
  */
 
+struct fsi_stream_handler;
 struct fsi_stream {
-	struct snd_pcm_substream *substream;
 
+	/*
+	 * these are initialized by fsi_stream_init()
+	 */
+	struct snd_pcm_substream *substream;
 	int fifo_sample_capa;	/* sample capacity of FSI FIFO */
 	int buff_sample_capa;	/* sample capacity of ALSA buffer */
 	int buff_sample_pos;	/* sample position of ALSA buffer */
 	int period_samples;	/* sample number / 1 period */
 	int period_pos;		/* current period position */
-
+	int sample_width;	/* sample width */
 	int uerr_num;
 	int oerr_num;
+
+	/*
+	 * thse are initialized by fsi_handler_init()
+	 */
+	struct fsi_stream_handler *handler;
+	struct fsi_priv		*priv;
+
+	/*
+	 * these are for DMAEngine
+	 */
+	struct dma_chan		*chan;
+	struct sh_dmae_slave	slave; /* see fsi_handler_init() */
+	struct tasklet_struct	tasklet;
+	dma_addr_t		dma;
 };
 
 struct fsi_priv {
 	void __iomem *base;
 	struct fsi_master *master;
+	struct sh_fsi_port_info *info;
 
 	struct fsi_stream playback;
 	struct fsi_stream capture;
@@ -189,6 +221,20 @@
 	long rate;
 };
 
+struct fsi_stream_handler {
+	int (*init)(struct fsi_priv *fsi, struct fsi_stream *io);
+	int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io);
+	int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io);
+	int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io);
+	int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io);
+	void (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io,
+			   int enable);
+};
+#define fsi_stream_handler_call(io, func, args...)	\
+	(!(io) ? -ENODEV :				\
+	 !((io)->handler->func) ? 0 :			\
+	 (io)->handler->func(args))
+
 struct fsi_core {
 	int ver;
 
@@ -205,10 +251,11 @@
 	struct fsi_priv fsia;
 	struct fsi_priv fsib;
 	struct fsi_core *core;
-	struct sh_fsi_platform_info *info;
 	spinlock_t lock;
 };
 
+static int fsi_stream_is_play(struct fsi_priv *fsi, struct fsi_stream *io);
+
 /*
  *		basic read write function
  */
@@ -295,6 +342,11 @@
 	return fsi->spdif;
 }
 
+static int fsi_is_play(struct snd_pcm_substream *substream)
+{
+	return substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+}
+
 static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -317,44 +369,25 @@
 	return fsi_get_priv_frm_dai(fsi_get_dai(substream));
 }
 
-static set_rate_func fsi_get_info_set_rate(struct fsi_master *master)
+static set_rate_func fsi_get_info_set_rate(struct fsi_priv *fsi)
 {
-	if (!master->info)
+	if (!fsi->info)
 		return NULL;
 
-	return master->info->set_rate;
+	return fsi->info->set_rate;
 }
 
 static u32 fsi_get_info_flags(struct fsi_priv *fsi)
 {
-	int is_porta = fsi_is_port_a(fsi);
-	struct fsi_master *master = fsi_get_master(fsi);
-
-	if (!master->info)
+	if (!fsi->info)
 		return 0;
 
-	return is_porta ? master->info->porta_flags :
-		master->info->portb_flags;
+	return fsi->info->flags;
 }
 
-static inline int fsi_stream_is_play(int stream)
+static u32 fsi_get_port_shift(struct fsi_priv *fsi, struct fsi_stream *io)
 {
-	return stream == SNDRV_PCM_STREAM_PLAYBACK;
-}
-
-static inline int fsi_is_play(struct snd_pcm_substream *substream)
-{
-	return fsi_stream_is_play(substream->stream);
-}
-
-static inline struct fsi_stream *fsi_get_stream(struct fsi_priv *fsi,
-						int is_play)
-{
-	return is_play ? &fsi->playback : &fsi->capture;
-}
-
-static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play)
-{
+	int is_play = fsi_stream_is_play(fsi, io);
 	int is_porta = fsi_is_port_a(fsi);
 	u32 shift;
 
@@ -376,68 +409,10 @@
 	return samples / fsi->chan_num;
 }
 
-static int fsi_stream_is_working(struct fsi_priv *fsi,
-				  int is_play)
+static int fsi_get_current_fifo_samples(struct fsi_priv *fsi,
+					struct fsi_stream *io)
 {
-	struct fsi_stream *io = fsi_get_stream(fsi, is_play);
-	struct fsi_master *master = fsi_get_master(fsi);
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&master->lock, flags);
-	ret = !!io->substream;
-	spin_unlock_irqrestore(&master->lock, flags);
-
-	return ret;
-}
-
-static void fsi_stream_push(struct fsi_priv *fsi,
-			    int is_play,
-			    struct snd_pcm_substream *substream)
-{
-	struct fsi_stream *io = fsi_get_stream(fsi, is_play);
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct fsi_master *master = fsi_get_master(fsi);
-	unsigned long flags;
-
-	spin_lock_irqsave(&master->lock, flags);
-	io->substream	= substream;
-	io->buff_sample_capa	= fsi_frame2sample(fsi, runtime->buffer_size);
-	io->buff_sample_pos	= 0;
-	io->period_samples	= fsi_frame2sample(fsi, runtime->period_size);
-	io->period_pos		= 0;
-	io->oerr_num	= -1; /* ignore 1st err */
-	io->uerr_num	= -1; /* ignore 1st err */
-	spin_unlock_irqrestore(&master->lock, flags);
-}
-
-static void fsi_stream_pop(struct fsi_priv *fsi, int is_play)
-{
-	struct fsi_stream *io = fsi_get_stream(fsi, is_play);
-	struct snd_soc_dai *dai = fsi_get_dai(io->substream);
-	struct fsi_master *master = fsi_get_master(fsi);
-	unsigned long flags;
-
-	spin_lock_irqsave(&master->lock, flags);
-
-	if (io->oerr_num > 0)
-		dev_err(dai->dev, "over_run = %d\n", io->oerr_num);
-
-	if (io->uerr_num > 0)
-		dev_err(dai->dev, "under_run = %d\n", io->uerr_num);
-
-	io->substream	= NULL;
-	io->buff_sample_capa	= 0;
-	io->buff_sample_pos	= 0;
-	io->period_samples	= 0;
-	io->period_pos		= 0;
-	io->oerr_num	= 0;
-	io->uerr_num	= 0;
-	spin_unlock_irqrestore(&master->lock, flags);
-}
-
-static int fsi_get_current_fifo_samples(struct fsi_priv *fsi, int is_play)
-{
+	int is_play = fsi_stream_is_play(fsi, io);
 	u32 status;
 	int frames;
 
@@ -472,81 +447,155 @@
 }
 
 /*
- *		dma function
+ *		fsi_stream_xx() function
  */
-
-static u8 *fsi_dma_get_area(struct fsi_priv *fsi, int stream)
+static inline int fsi_stream_is_play(struct fsi_priv *fsi,
+				     struct fsi_stream *io)
 {
-	int is_play = fsi_stream_is_play(stream);
-	struct fsi_stream *io = fsi_get_stream(fsi, is_play);
-	struct snd_pcm_runtime *runtime = io->substream->runtime;
-
-	return runtime->dma_area +
-		samples_to_bytes(runtime, io->buff_sample_pos);
+	return &fsi->playback == io;
 }
 
-static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num)
+static inline struct fsi_stream *fsi_stream_get(struct fsi_priv *fsi,
+					struct snd_pcm_substream *substream)
 {
-	u16 *start;
-	int i;
-
-	start  = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK);
-
-	for (i = 0; i < num; i++)
-		fsi_reg_write(fsi, DODT, ((u32)*(start + i) << 8));
+	return fsi_is_play(substream) ? &fsi->playback : &fsi->capture;
 }
 
-static void fsi_dma_soft_pop16(struct fsi_priv *fsi, int num)
+static int fsi_stream_is_working(struct fsi_priv *fsi,
+				 struct fsi_stream *io)
 {
-	u16 *start;
-	int i;
+	struct fsi_master *master = fsi_get_master(fsi);
+	unsigned long flags;
+	int ret;
 
-	start  = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE);
+	spin_lock_irqsave(&master->lock, flags);
+	ret = !!(io->substream && io->substream->runtime);
+	spin_unlock_irqrestore(&master->lock, flags);
 
-
-	for (i = 0; i < num; i++)
-		*(start + i) = (u16)(fsi_reg_read(fsi, DIDT) >> 8);
+	return ret;
 }
 
-static void fsi_dma_soft_push32(struct fsi_priv *fsi, int num)
+static struct fsi_priv *fsi_stream_to_priv(struct fsi_stream *io)
 {
-	u32 *start;
-	int i;
-
-	start  = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK);
-
-
-	for (i = 0; i < num; i++)
-		fsi_reg_write(fsi, DODT, *(start + i));
+	return io->priv;
 }
 
-static void fsi_dma_soft_pop32(struct fsi_priv *fsi, int num)
+static void fsi_stream_init(struct fsi_priv *fsi,
+			    struct fsi_stream *io,
+			    struct snd_pcm_substream *substream)
 {
-	u32 *start;
-	int i;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct fsi_master *master = fsi_get_master(fsi);
+	unsigned long flags;
 
-	start  = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE);
+	spin_lock_irqsave(&master->lock, flags);
+	io->substream	= substream;
+	io->buff_sample_capa	= fsi_frame2sample(fsi, runtime->buffer_size);
+	io->buff_sample_pos	= 0;
+	io->period_samples	= fsi_frame2sample(fsi, runtime->period_size);
+	io->period_pos		= 0;
+	io->sample_width	= samples_to_bytes(runtime, 1);
+	io->oerr_num	= -1; /* ignore 1st err */
+	io->uerr_num	= -1; /* ignore 1st err */
+	fsi_stream_handler_call(io, init, fsi, io);
+	spin_unlock_irqrestore(&master->lock, flags);
+}
 
-	for (i = 0; i < num; i++)
-		*(start + i) = fsi_reg_read(fsi, DIDT);
+static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+	struct snd_soc_dai *dai = fsi_get_dai(io->substream);
+	struct fsi_master *master = fsi_get_master(fsi);
+	unsigned long flags;
+
+	spin_lock_irqsave(&master->lock, flags);
+
+	if (io->oerr_num > 0)
+		dev_err(dai->dev, "over_run = %d\n", io->oerr_num);
+
+	if (io->uerr_num > 0)
+		dev_err(dai->dev, "under_run = %d\n", io->uerr_num);
+
+	fsi_stream_handler_call(io, quit, fsi, io);
+	io->substream	= NULL;
+	io->buff_sample_capa	= 0;
+	io->buff_sample_pos	= 0;
+	io->period_samples	= 0;
+	io->period_pos		= 0;
+	io->sample_width	= 0;
+	io->oerr_num	= 0;
+	io->uerr_num	= 0;
+	spin_unlock_irqrestore(&master->lock, flags);
+}
+
+static int fsi_stream_transfer(struct fsi_stream *io)
+{
+	struct fsi_priv *fsi = fsi_stream_to_priv(io);
+	if (!fsi)
+		return -EIO;
+
+	return fsi_stream_handler_call(io, transfer, fsi, io);
+}
+
+#define fsi_stream_start(fsi, io)\
+	fsi_stream_handler_call(io, start_stop, fsi, io, 1)
+
+#define fsi_stream_stop(fsi, io)\
+	fsi_stream_handler_call(io, start_stop, fsi, io, 0)
+
+static int fsi_stream_probe(struct fsi_priv *fsi)
+{
+	struct fsi_stream *io;
+	int ret1, ret2;
+
+	io = &fsi->playback;
+	ret1 = fsi_stream_handler_call(io, probe, fsi, io);
+
+	io = &fsi->capture;
+	ret2 = fsi_stream_handler_call(io, probe, fsi, io);
+
+	if (ret1 < 0)
+		return ret1;
+	if (ret2 < 0)
+		return ret2;
+
+	return 0;
+}
+
+static int fsi_stream_remove(struct fsi_priv *fsi)
+{
+	struct fsi_stream *io;
+	int ret1, ret2;
+
+	io = &fsi->playback;
+	ret1 = fsi_stream_handler_call(io, remove, fsi, io);
+
+	io = &fsi->capture;
+	ret2 = fsi_stream_handler_call(io, remove, fsi, io);
+
+	if (ret1 < 0)
+		return ret1;
+	if (ret2 < 0)
+		return ret2;
+
+	return 0;
 }
 
 /*
  *		irq function
  */
 
-static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
+static void fsi_irq_enable(struct fsi_priv *fsi, struct fsi_stream *io)
 {
-	u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play));
+	u32 data = AB_IO(1, fsi_get_port_shift(fsi, io));
 	struct fsi_master *master = fsi_get_master(fsi);
 
 	fsi_core_mask_set(master, imsk,  data, data);
 	fsi_core_mask_set(master, iemsk, data, data);
 }
 
-static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
+static void fsi_irq_disable(struct fsi_priv *fsi, struct fsi_stream *io)
 {
-	u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play));
+	u32 data = AB_IO(1, fsi_get_port_shift(fsi, io));
 	struct fsi_master *master = fsi_get_master(fsi);
 
 	fsi_core_mask_set(master, imsk,  data, 0);
@@ -563,8 +612,8 @@
 	u32 data = 0;
 	struct fsi_master *master = fsi_get_master(fsi);
 
-	data |= AB_IO(1, fsi_get_port_shift(fsi, 0));
-	data |= AB_IO(1, fsi_get_port_shift(fsi, 1));
+	data |= AB_IO(1, fsi_get_port_shift(fsi, &fsi->playback));
+	data |= AB_IO(1, fsi_get_port_shift(fsi, &fsi->capture));
 
 	/* clear interrupt factor */
 	fsi_core_mask_set(master, int_st, data, 0);
@@ -600,11 +649,14 @@
 			      long rate, int enable)
 {
 	struct fsi_master *master = fsi_get_master(fsi);
-	set_rate_func set_rate = fsi_get_info_set_rate(master);
+	set_rate_func set_rate = fsi_get_info_set_rate(fsi);
 	int fsi_ver = master->core->ver;
 	int ret;
 
-	ret = set_rate(dev, fsi_is_port_a(fsi), rate, enable);
+	if (!set_rate)
+		return 0;
+
+	ret = set_rate(dev, rate, enable);
 	if (ret < 0) /* error */
 		return ret;
 
@@ -671,37 +723,413 @@
 	return ret;
 }
 
-#define fsi_port_start(f, i)	__fsi_port_clk_ctrl(f, i, 1)
-#define fsi_port_stop(f, i)	__fsi_port_clk_ctrl(f, i, 0)
-static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int is_play, int enable)
+/*
+ *		pio data transfer handler
+ */
+static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples)
+{
+	u16 *buf = (u16 *)_buf;
+	int i;
+
+	for (i = 0; i < samples; i++)
+		fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8));
+}
+
+static void fsi_pio_pop16(struct fsi_priv *fsi, u8 *_buf, int samples)
+{
+	u16 *buf = (u16 *)_buf;
+	int i;
+
+	for (i = 0; i < samples; i++)
+		*(buf + i) = (u16)(fsi_reg_read(fsi, DIDT) >> 8);
+}
+
+static void fsi_pio_push32(struct fsi_priv *fsi, u8 *_buf, int samples)
+{
+	u32 *buf = (u32 *)_buf;
+	int i;
+
+	for (i = 0; i < samples; i++)
+		fsi_reg_write(fsi, DODT, *(buf + i));
+}
+
+static void fsi_pio_pop32(struct fsi_priv *fsi, u8 *_buf, int samples)
+{
+	u32 *buf = (u32 *)_buf;
+	int i;
+
+	for (i = 0; i < samples; i++)
+		*(buf + i) = fsi_reg_read(fsi, DIDT);
+}
+
+static u8 *fsi_pio_get_area(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+	struct snd_pcm_runtime *runtime = io->substream->runtime;
+
+	return runtime->dma_area +
+		samples_to_bytes(runtime, io->buff_sample_pos);
+}
+
+static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io,
+		void (*run16)(struct fsi_priv *fsi, u8 *buf, int samples),
+		void (*run32)(struct fsi_priv *fsi, u8 *buf, int samples),
+		int samples)
+{
+	struct snd_pcm_runtime *runtime;
+	struct snd_pcm_substream *substream;
+	u8 *buf;
+	int over_period;
+
+	if (!fsi_stream_is_working(fsi, io))
+		return -EINVAL;
+
+	over_period	= 0;
+	substream	= io->substream;
+	runtime		= substream->runtime;
+
+	/* FSI FIFO has limit.
+	 * So, this driver can not send periods data at a time
+	 */
+	if (io->buff_sample_pos >=
+	    io->period_samples * (io->period_pos + 1)) {
+
+		over_period = 1;
+		io->period_pos = (io->period_pos + 1) % runtime->periods;
+
+		if (0 == io->period_pos)
+			io->buff_sample_pos = 0;
+	}
+
+	buf = fsi_pio_get_area(fsi, io);
+
+	switch (io->sample_width) {
+	case 2:
+		run16(fsi, buf, samples);
+		break;
+	case 4:
+		run32(fsi, buf, samples);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* update buff_sample_pos */
+	io->buff_sample_pos += samples;
+
+	if (over_period)
+		snd_pcm_period_elapsed(substream);
+
+	return 0;
+}
+
+static int fsi_pio_pop(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+	int sample_residues;	/* samples in FSI fifo */
+	int sample_space;	/* ALSA free samples space */
+	int samples;
+
+	sample_residues	= fsi_get_current_fifo_samples(fsi, io);
+	sample_space	= io->buff_sample_capa - io->buff_sample_pos;
+
+	samples = min(sample_residues, sample_space);
+
+	return fsi_pio_transfer(fsi, io,
+				  fsi_pio_pop16,
+				  fsi_pio_pop32,
+				  samples);
+}
+
+static int fsi_pio_push(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+	int sample_residues;	/* ALSA residue samples */
+	int sample_space;	/* FSI fifo free samples space */
+	int samples;
+
+	sample_residues	= io->buff_sample_capa - io->buff_sample_pos;
+	sample_space	= io->fifo_sample_capa -
+		fsi_get_current_fifo_samples(fsi, io);
+
+	samples = min(sample_residues, sample_space);
+
+	return fsi_pio_transfer(fsi, io,
+				  fsi_pio_push16,
+				  fsi_pio_push32,
+				  samples);
+}
+
+static void fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
+			       int enable)
 {
 	struct fsi_master *master = fsi_get_master(fsi);
 	u32 clk  = fsi_is_port_a(fsi) ? CRA  : CRB;
 
 	if (enable)
-		fsi_irq_enable(fsi, is_play);
+		fsi_irq_enable(fsi, io);
 	else
-		fsi_irq_disable(fsi, is_play);
+		fsi_irq_disable(fsi, io);
 
 	if (fsi_is_clk_master(fsi))
 		fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
 }
 
+static struct fsi_stream_handler fsi_pio_push_handler = {
+	.transfer	= fsi_pio_push,
+	.start_stop	= fsi_pio_start_stop,
+};
+
+static struct fsi_stream_handler fsi_pio_pop_handler = {
+	.transfer	= fsi_pio_pop,
+	.start_stop	= fsi_pio_start_stop,
+};
+
+static irqreturn_t fsi_interrupt(int irq, void *data)
+{
+	struct fsi_master *master = data;
+	u32 int_st = fsi_irq_get_status(master);
+
+	/* clear irq status */
+	fsi_master_mask_set(master, SOFT_RST, IR, 0);
+	fsi_master_mask_set(master, SOFT_RST, IR, IR);
+
+	if (int_st & AB_IO(1, AO_SHIFT))
+		fsi_stream_transfer(&master->fsia.playback);
+	if (int_st & AB_IO(1, BO_SHIFT))
+		fsi_stream_transfer(&master->fsib.playback);
+	if (int_st & AB_IO(1, AI_SHIFT))
+		fsi_stream_transfer(&master->fsia.capture);
+	if (int_st & AB_IO(1, BI_SHIFT))
+		fsi_stream_transfer(&master->fsib.capture);
+
+	fsi_count_fifo_err(&master->fsia);
+	fsi_count_fifo_err(&master->fsib);
+
+	fsi_irq_clear_status(&master->fsia);
+	fsi_irq_clear_status(&master->fsib);
+
+	return IRQ_HANDLED;
+}
+
 /*
- *		ctrl function
+ *		dma data transfer handler
+ */
+static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+	struct snd_pcm_runtime *runtime = io->substream->runtime;
+	struct snd_soc_dai *dai = fsi_get_dai(io->substream);
+	enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
+				DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+	io->dma = dma_map_single(dai->dev, runtime->dma_area,
+				 snd_pcm_lib_buffer_bytes(io->substream), dir);
+	return 0;
+}
+
+static int fsi_dma_quit(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+	struct snd_soc_dai *dai = fsi_get_dai(io->substream);
+	enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
+		DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+	dma_unmap_single(dai->dev, io->dma,
+			 snd_pcm_lib_buffer_bytes(io->substream), dir);
+	return 0;
+}
+
+static void fsi_dma_complete(void *data)
+{
+	struct fsi_stream *io = (struct fsi_stream *)data;
+	struct fsi_priv *fsi = fsi_stream_to_priv(io);
+	struct snd_pcm_runtime *runtime = io->substream->runtime;
+	struct snd_soc_dai *dai = fsi_get_dai(io->substream);
+	enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
+		DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+	dma_sync_single_for_cpu(dai->dev, io->dma,
+			samples_to_bytes(runtime, io->period_samples), dir);
+
+	io->buff_sample_pos += io->period_samples;
+	io->period_pos++;
+
+	if (io->period_pos >= runtime->periods) {
+		io->period_pos = 0;
+		io->buff_sample_pos = 0;
+	}
+
+	fsi_count_fifo_err(fsi);
+	fsi_stream_transfer(io);
+
+	snd_pcm_period_elapsed(io->substream);
+}
+
+static dma_addr_t fsi_dma_get_area(struct fsi_stream *io)
+{
+	struct snd_pcm_runtime *runtime = io->substream->runtime;
+
+	return io->dma + samples_to_bytes(runtime, io->buff_sample_pos);
+}
+
+static void fsi_dma_do_tasklet(unsigned long data)
+{
+	struct fsi_stream *io = (struct fsi_stream *)data;
+	struct fsi_priv *fsi = fsi_stream_to_priv(io);
+	struct dma_chan *chan;
+	struct snd_soc_dai *dai;
+	struct dma_async_tx_descriptor *desc;
+	struct scatterlist sg;
+	struct snd_pcm_runtime *runtime;
+	enum dma_data_direction dir;
+	dma_cookie_t cookie;
+	int is_play = fsi_stream_is_play(fsi, io);
+	int len;
+	dma_addr_t buf;
+
+	if (!fsi_stream_is_working(fsi, io))
+		return;
+
+	dai	= fsi_get_dai(io->substream);
+	chan	= io->chan;
+	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, io->dma, len, dir);
+
+	sg_init_table(&sg, 1);
+	sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)),
+		    len , offset_in_page(buf));
+	sg_dma_address(&sg) = buf;
+	sg_dma_len(&sg) = len;
+
+	desc = chan->device->device_prep_slave_sg(chan, &sg, 1, dir,
+						  DMA_PREP_INTERRUPT |
+						  DMA_CTRL_ACK);
+	if (!desc) {
+		dev_err(dai->dev, "device_prep_slave_sg() fail\n");
+		return;
+	}
+
+	desc->callback		= fsi_dma_complete;
+	desc->callback_param	= io;
+
+	cookie = desc->tx_submit(desc);
+	if (cookie < 0) {
+		dev_err(dai->dev, "tx_submit() fail\n");
+		return;
+	}
+
+	dma_async_issue_pending(chan);
+
+	/*
+	 * FIXME
+	 *
+	 * In DMAEngine case, codec and FSI cannot be started simultaneously
+	 * since FSI is using tasklet.
+	 * Therefore, in capture case, probably FSI FIFO will have got
+	 * overflow error in this point.
+	 * in that case, DMA cannot start transfer until error was cleared.
+	 */
+	if (!is_play) {
+		if (ERR_OVER & fsi_reg_read(fsi, DIFF_ST)) {
+			fsi_reg_mask_set(fsi, DIFF_CTL, FIFO_CLR, FIFO_CLR);
+			fsi_reg_write(fsi, DIFF_ST, 0);
+		}
+	}
+}
+
+static bool fsi_dma_filter(struct dma_chan *chan, void *param)
+{
+	struct sh_dmae_slave *slave = param;
+
+	chan->private = slave;
+
+	return true;
+}
+
+static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+	tasklet_schedule(&io->tasklet);
+
+	return 0;
+}
+
+static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
+				 int start)
+{
+	u32 bws;
+	u32 dma;
+
+	switch (io->sample_width * start) {
+	case 2:
+		bws = CR_BWS_16;
+		dma = VDMD_STREAM | DMA_ON;
+		break;
+	case 4:
+		bws = CR_BWS_24;
+		dma = VDMD_BACK | DMA_ON;
+		break;
+	default:
+		bws = 0;
+		dma = 0;
+	}
+
+	fsi_reg_mask_set(fsi, DO_FMT, CR_BWS_MASK, bws);
+	fsi_reg_write(fsi, OUT_DMAC, dma);
+}
+
+static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+	dma_cap_mask_t mask;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+
+	io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave);
+	if (!io->chan)
+		return -EIO;
+
+	tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io);
+
+	return 0;
+}
+
+static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+	tasklet_kill(&io->tasklet);
+
+	fsi_stream_stop(fsi, io);
+
+	if (io->chan)
+		dma_release_channel(io->chan);
+
+	io->chan = NULL;
+	return 0;
+}
+
+static struct fsi_stream_handler fsi_dma_push_handler = {
+	.init		= fsi_dma_init,
+	.quit		= fsi_dma_quit,
+	.probe		= fsi_dma_probe,
+	.transfer	= fsi_dma_transfer,
+	.remove		= fsi_dma_remove,
+	.start_stop	= fsi_dma_push_start_stop,
+};
+
+/*
+ *		dai ops
  */
 static void fsi_fifo_init(struct fsi_priv *fsi,
-			  int is_play,
+			  struct fsi_stream *io,
 			  struct device *dev)
 {
 	struct fsi_master *master = fsi_get_master(fsi);
-	struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+	int is_play = fsi_stream_is_play(fsi, io);
 	u32 shift, i;
 	int frame_capa;
 
 	/* get on-chip RAM capacity */
 	shift = fsi_master_read(master, FIFO_SZ);
-	shift >>= fsi_get_port_shift(fsi, is_play);
+	shift >>= fsi_get_port_shift(fsi, io);
 	shift &= FIFO_SZ_MASK;
 	frame_capa = 256 << shift;
 	dev_dbg(dev, "fifo = %d words\n", frame_capa);
@@ -745,147 +1173,8 @@
 	}
 }
 
-static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
-{
-	struct snd_pcm_runtime *runtime;
-	struct snd_pcm_substream *substream = NULL;
-	int is_play = fsi_stream_is_play(stream);
-	struct fsi_stream *io = fsi_get_stream(fsi, is_play);
-	int sample_residues;
-	int sample_width;
-	int samples;
-	int samples_max;
-	int over_period;
-	void (*fn)(struct fsi_priv *fsi, int size);
-
-	if (!fsi			||
-	    !io->substream		||
-	    !io->substream->runtime)
-		return -EINVAL;
-
-	over_period	= 0;
-	substream	= io->substream;
-	runtime		= substream->runtime;
-
-	/* FSI FIFO has limit.
-	 * So, this driver can not send periods data at a time
-	 */
-	if (io->buff_sample_pos >=
-	    io->period_samples * (io->period_pos + 1)) {
-
-		over_period = 1;
-		io->period_pos = (io->period_pos + 1) % runtime->periods;
-
-		if (0 == io->period_pos)
-			io->buff_sample_pos = 0;
-	}
-
-	/* get 1 sample data width */
-	sample_width = samples_to_bytes(runtime, 1);
-
-	/* get number of residue samples */
-	sample_residues = io->buff_sample_capa - io->buff_sample_pos;
-
-	if (is_play) {
-		/*
-		 * for play-back
-		 *
-		 * samples_max	: number of FSI fifo free samples space
-		 * samples	: number of ALSA residue samples
-		 */
-		samples_max  = io->fifo_sample_capa;
-		samples_max -= fsi_get_current_fifo_samples(fsi, is_play);
-
-		samples = sample_residues;
-
-		switch (sample_width) {
-		case 2:
-			fn = fsi_dma_soft_push16;
-			break;
-		case 4:
-			fn = fsi_dma_soft_push32;
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else {
-		/*
-		 * for capture
-		 *
-		 * samples_max	: number of ALSA free samples space
-		 * samples	: number of samples in FSI fifo
-		 */
-		samples_max = sample_residues;
-		samples     = fsi_get_current_fifo_samples(fsi, is_play);
-
-		switch (sample_width) {
-		case 2:
-			fn = fsi_dma_soft_pop16;
-			break;
-		case 4:
-			fn = fsi_dma_soft_pop32;
-			break;
-		default:
-			return -EINVAL;
-		}
-	}
-
-	samples = min(samples, samples_max);
-
-	fn(fsi, samples);
-
-	/* update buff_sample_pos */
-	io->buff_sample_pos += samples;
-
-	if (over_period)
-		snd_pcm_period_elapsed(substream);
-
-	return 0;
-}
-
-static int fsi_data_pop(struct fsi_priv *fsi)
-{
-	return fsi_fifo_data_ctrl(fsi, SNDRV_PCM_STREAM_CAPTURE);
-}
-
-static int fsi_data_push(struct fsi_priv *fsi)
-{
-	return fsi_fifo_data_ctrl(fsi, SNDRV_PCM_STREAM_PLAYBACK);
-}
-
-static irqreturn_t fsi_interrupt(int irq, void *data)
-{
-	struct fsi_master *master = data;
-	u32 int_st = fsi_irq_get_status(master);
-
-	/* clear irq status */
-	fsi_master_mask_set(master, SOFT_RST, IR, 0);
-	fsi_master_mask_set(master, SOFT_RST, IR, IR);
-
-	if (int_st & AB_IO(1, AO_SHIFT))
-		fsi_data_push(&master->fsia);
-	if (int_st & AB_IO(1, BO_SHIFT))
-		fsi_data_push(&master->fsib);
-	if (int_st & AB_IO(1, AI_SHIFT))
-		fsi_data_pop(&master->fsia);
-	if (int_st & AB_IO(1, BI_SHIFT))
-		fsi_data_pop(&master->fsib);
-
-	fsi_count_fifo_err(&master->fsia);
-	fsi_count_fifo_err(&master->fsib);
-
-	fsi_irq_clear_status(&master->fsia);
-	fsi_irq_clear_status(&master->fsib);
-
-	return IRQ_HANDLED;
-}
-
-/*
- *		dai ops
- */
-
 static int fsi_hw_startup(struct fsi_priv *fsi,
-			  int is_play,
+			  struct fsi_stream *io,
 			  struct device *dev)
 {
 	struct fsi_master *master = fsi_get_master(fsi);
@@ -934,17 +1223,16 @@
 	}
 
 	/* irq clear */
-	fsi_irq_disable(fsi, is_play);
+	fsi_irq_disable(fsi, io);
 	fsi_irq_clear_status(fsi);
 
 	/* fifo init */
-	fsi_fifo_init(fsi, is_play, dev);
+	fsi_fifo_init(fsi, io, dev);
 
 	return 0;
 }
 
 static void fsi_hw_shutdown(struct fsi_priv *fsi,
-			    int is_play,
 			    struct device *dev)
 {
 	if (fsi_is_clk_master(fsi))
@@ -955,18 +1243,16 @@
 			   struct snd_soc_dai *dai)
 {
 	struct fsi_priv *fsi = fsi_get_priv(substream);
-	int is_play = fsi_is_play(substream);
 
-	return fsi_hw_startup(fsi, is_play, dai->dev);
+	return fsi_hw_startup(fsi, fsi_stream_get(fsi, substream), dai->dev);
 }
 
 static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
 			     struct snd_soc_dai *dai)
 {
 	struct fsi_priv *fsi = fsi_get_priv(substream);
-	int is_play = fsi_is_play(substream);
 
-	fsi_hw_shutdown(fsi, is_play, dai->dev);
+	fsi_hw_shutdown(fsi, dai->dev);
 	fsi->rate = 0;
 }
 
@@ -974,18 +1260,19 @@
 			   struct snd_soc_dai *dai)
 {
 	struct fsi_priv *fsi = fsi_get_priv(substream);
-	int is_play = fsi_is_play(substream);
+	struct fsi_stream *io = fsi_stream_get(fsi, substream);
 	int ret = 0;
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
-		fsi_stream_push(fsi, is_play, substream);
-		ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
-		fsi_port_start(fsi, is_play);
+		fsi_stream_init(fsi, io, substream);
+		ret = fsi_stream_transfer(io);
+		if (0 == ret)
+			fsi_stream_start(fsi, io);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
-		fsi_port_stop(fsi, is_play);
-		fsi_stream_pop(fsi, is_play);
+		fsi_stream_stop(fsi, io);
+		fsi_stream_quit(fsi, io);
 		break;
 	}
 
@@ -1036,8 +1323,7 @@
 static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai);
-	struct fsi_master *master = fsi_get_master(fsi);
-	set_rate_func set_rate = fsi_get_info_set_rate(master);
+	set_rate_func set_rate = fsi_get_info_set_rate(fsi);
 	u32 flags = fsi_get_info_flags(fsi);
 	int ret;
 
@@ -1151,7 +1437,7 @@
 static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
 {
 	struct fsi_priv *fsi = fsi_get_priv(substream);
-	struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream));
+	struct fsi_stream *io = fsi_stream_get(fsi, substream);
 
 	return fsi_sample2frame(fsi, io->buff_sample_pos);
 }
@@ -1239,11 +1525,24 @@
 /*
  *		platform function
  */
+static void fsi_handler_init(struct fsi_priv *fsi)
+{
+	fsi->playback.handler	= &fsi_pio_push_handler; /* default PIO */
+	fsi->playback.priv	= fsi;
+	fsi->capture.handler	= &fsi_pio_pop_handler;  /* default PIO */
+	fsi->capture.priv	= fsi;
+
+	if (fsi->info->tx_id) {
+		fsi->playback.slave.slave_id	= fsi->info->tx_id;
+		fsi->playback.handler		= &fsi_dma_push_handler;
+	}
+}
 
 static int fsi_probe(struct platform_device *pdev)
 {
 	struct fsi_master *master;
 	const struct platform_device_id	*id_entry;
+	struct sh_fsi_platform_info *info = pdev->dev.platform_data;
 	struct resource *res;
 	unsigned int irq;
 	int ret;
@@ -1278,17 +1577,30 @@
 
 	/* master setting */
 	master->irq		= irq;
-	master->info		= pdev->dev.platform_data;
 	master->core		= (struct fsi_core *)id_entry->driver_data;
 	spin_lock_init(&master->lock);
 
 	/* FSI A setting */
 	master->fsia.base	= master->base;
 	master->fsia.master	= master;
+	master->fsia.info	= &info->port_a;
+	fsi_handler_init(&master->fsia);
+	ret = fsi_stream_probe(&master->fsia);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "FSIA stream probe failed\n");
+		goto exit_iounmap;
+	}
 
 	/* FSI B setting */
 	master->fsib.base	= master->base + 0x40;
 	master->fsib.master	= master;
+	master->fsib.info	= &info->port_b;
+	fsi_handler_init(&master->fsib);
+	ret = fsi_stream_probe(&master->fsib);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "FSIB stream probe failed\n");
+		goto exit_fsia;
+	}
 
 	pm_runtime_enable(&pdev->dev);
 	dev_set_drvdata(&pdev->dev, master);
@@ -1297,7 +1609,7 @@
 			  id_entry->name, master);
 	if (ret) {
 		dev_err(&pdev->dev, "irq request err\n");
-		goto exit_iounmap;
+		goto exit_fsib;
 	}
 
 	ret = snd_soc_register_platform(&pdev->dev, &fsi_soc_platform);
@@ -1319,6 +1631,10 @@
 	snd_soc_unregister_platform(&pdev->dev);
 exit_free_irq:
 	free_irq(irq, master);
+exit_fsib:
+	fsi_stream_remove(&master->fsib);
+exit_fsia:
+	fsi_stream_remove(&master->fsia);
 exit_iounmap:
 	iounmap(master->base);
 	pm_runtime_disable(&pdev->dev);
@@ -1341,6 +1657,9 @@
 	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai));
 	snd_soc_unregister_platform(&pdev->dev);
 
+	fsi_stream_remove(&master->fsia);
+	fsi_stream_remove(&master->fsib);
+
 	iounmap(master->base);
 	kfree(master);
 
@@ -1348,30 +1667,29 @@
 }
 
 static void __fsi_suspend(struct fsi_priv *fsi,
-			  int is_play,
+			  struct fsi_stream *io,
 			  struct device *dev)
 {
-	if (!fsi_stream_is_working(fsi, is_play))
+	if (!fsi_stream_is_working(fsi, io))
 		return;
 
-	fsi_port_stop(fsi, is_play);
-	fsi_hw_shutdown(fsi, is_play, dev);
+	fsi_stream_stop(fsi, io);
+	fsi_hw_shutdown(fsi, dev);
 }
 
 static void __fsi_resume(struct fsi_priv *fsi,
-			 int is_play,
+			 struct fsi_stream *io,
 			 struct device *dev)
 {
-	if (!fsi_stream_is_working(fsi, is_play))
+	if (!fsi_stream_is_working(fsi, io))
 		return;
 
-	fsi_hw_startup(fsi, is_play, dev);
+	fsi_hw_startup(fsi, io, dev);
 
 	if (fsi_is_clk_master(fsi) && fsi->rate)
 		fsi_set_master_clk(dev, fsi, fsi->rate, 1);
 
-	fsi_port_start(fsi, is_play);
-
+	fsi_stream_start(fsi, io);
 }
 
 static int fsi_suspend(struct device *dev)
@@ -1380,11 +1698,11 @@
 	struct fsi_priv *fsia = &master->fsia;
 	struct fsi_priv *fsib = &master->fsib;
 
-	__fsi_suspend(fsia, 1, dev);
-	__fsi_suspend(fsia, 0, dev);
+	__fsi_suspend(fsia, &fsia->playback, dev);
+	__fsi_suspend(fsia, &fsia->capture, dev);
 
-	__fsi_suspend(fsib, 1, dev);
-	__fsi_suspend(fsib, 0, dev);
+	__fsi_suspend(fsib, &fsib->playback, dev);
+	__fsi_suspend(fsib, &fsib->capture, dev);
 
 	return 0;
 }
@@ -1395,32 +1713,18 @@
 	struct fsi_priv *fsia = &master->fsia;
 	struct fsi_priv *fsib = &master->fsib;
 
-	__fsi_resume(fsia, 1, dev);
-	__fsi_resume(fsia, 0, dev);
+	__fsi_resume(fsia, &fsia->playback, dev);
+	__fsi_resume(fsia, &fsia->capture, dev);
 
-	__fsi_resume(fsib, 1, dev);
-	__fsi_resume(fsib, 0, dev);
+	__fsi_resume(fsib, &fsib->playback, dev);
+	__fsi_resume(fsib, &fsib->capture, dev);
 
 	return 0;
 }
 
-static int fsi_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;
-}
-
 static struct dev_pm_ops fsi_pm_ops = {
 	.suspend		= fsi_suspend,
 	.resume			= fsi_resume,
-	.runtime_suspend	= fsi_runtime_nop,
-	.runtime_resume		= fsi_runtime_nop,
 };
 
 static struct fsi_core fsi1_core = {
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
index 0193e59..5cfcc65 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/sh/siu_pcm.c
@@ -130,7 +130,7 @@
 	sg_dma_len(&sg) = size;
 	sg_dma_address(&sg) = buff;
 
-	desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
+	desc = dmaengine_prep_slave_sg(siu_stream->chan,
 		&sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc) {
 		dev_err(dev, "Failed to allocate a dma descriptor\n");
@@ -180,7 +180,7 @@
 	sg_dma_len(&sg) = size;
 	sg_dma_address(&sg) = buff;
 
-	desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
+	desc = dmaengine_prep_slave_sg(siu_stream->chan,
 		&sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!desc) {
 		dev_err(dev, "Failed to allocate dma descriptor\n");
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 92cee24..e19c24a 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -201,12 +201,6 @@
 static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set);
 
 #ifdef CONFIG_DEBUG_FS
-static int codec_reg_open_file(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
 				   size_t count, loff_t *ppos)
 {
@@ -264,7 +258,7 @@
 }
 
 static const struct file_operations codec_reg_fops = {
-	.open = codec_reg_open_file,
+	.open = simple_open,
 	.read = codec_reg_read_file,
 	.write = codec_reg_write_file,
 	.llseek = default_llseek,
@@ -277,8 +271,7 @@
 	codec->debugfs_codec_root = debugfs_create_dir(codec->name,
 						       debugfs_card_root);
 	if (!codec->debugfs_codec_root) {
-		printk(KERN_WARNING
-		       "ASoC: Failed to create codec debugfs directory\n");
+		dev_warn(codec->dev, "Failed to create codec debugfs directory\n");
 		return;
 	}
 
@@ -291,8 +284,7 @@
 						 codec->debugfs_codec_root,
 						 codec, &codec_reg_fops);
 	if (!codec->debugfs_reg)
-		printk(KERN_WARNING
-		       "ASoC: Failed to create codec register debugfs file\n");
+		dev_warn(codec->dev, "Failed to create codec register debugfs file\n");
 
 	snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root);
 }
@@ -302,6 +294,27 @@
 	debugfs_remove_recursive(codec->debugfs_codec_root);
 }
 
+static void soc_init_platform_debugfs(struct snd_soc_platform *platform)
+{
+	struct dentry *debugfs_card_root = platform->card->debugfs_card_root;
+
+	platform->debugfs_platform_root = debugfs_create_dir(platform->name,
+						       debugfs_card_root);
+	if (!platform->debugfs_platform_root) {
+		dev_warn(platform->dev,
+			"Failed to create platform debugfs directory\n");
+		return;
+	}
+
+	snd_soc_dapm_debugfs_init(&platform->dapm,
+		platform->debugfs_platform_root);
+}
+
+static void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform)
+{
+	debugfs_remove_recursive(platform->debugfs_platform_root);
+}
+
 static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
 				    size_t count, loff_t *ppos)
 {
@@ -435,6 +448,14 @@
 {
 }
 
+static inline void soc_init_platform_debugfs(struct snd_soc_platform *platform)
+{
+}
+
+static inline void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform)
+{
+}
+
 static inline void soc_init_card_debugfs(struct snd_soc_card *card)
 {
 }
@@ -546,18 +567,20 @@
 	}
 
 	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
+		struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
 
 		if (card->rtd[i].dai_link->ignore_suspend)
 			continue;
 
-		if (driver->playback.stream_name != NULL)
-			snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
-				SND_SOC_DAPM_STREAM_SUSPEND);
+		snd_soc_dapm_stream_event(&card->rtd[i],
+					  SNDRV_PCM_STREAM_PLAYBACK,
+					  codec_dai,
+					  SND_SOC_DAPM_STREAM_SUSPEND);
 
-		if (driver->capture.stream_name != NULL)
-			snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
-				SND_SOC_DAPM_STREAM_SUSPEND);
+		snd_soc_dapm_stream_event(&card->rtd[i],
+					  SNDRV_PCM_STREAM_CAPTURE,
+					  codec_dai,
+					  SND_SOC_DAPM_STREAM_SUSPEND);
 	}
 
 	/* suspend all CODECs */
@@ -660,18 +683,18 @@
 	}
 
 	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
+		struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
 
 		if (card->rtd[i].dai_link->ignore_suspend)
 			continue;
 
-		if (driver->playback.stream_name != NULL)
-			snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
-				SND_SOC_DAPM_STREAM_RESUME);
+		snd_soc_dapm_stream_event(&card->rtd[i],
+					  SNDRV_PCM_STREAM_PLAYBACK, codec_dai,
+					  SND_SOC_DAPM_STREAM_RESUME);
 
-		if (driver->capture.stream_name != NULL)
-			snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
-				SND_SOC_DAPM_STREAM_RESUME);
+		snd_soc_dapm_stream_event(&card->rtd[i],
+					  SNDRV_PCM_STREAM_CAPTURE, codec_dai,
+					  SND_SOC_DAPM_STREAM_RESUME);
 	}
 
 	/* unmute any active DACs */
@@ -904,7 +927,8 @@
 		if (codec_dai->driver->remove) {
 			err = codec_dai->driver->remove(codec_dai);
 			if (err < 0)
-				printk(KERN_ERR "asoc: failed to remove %s\n", codec_dai->name);
+				pr_err("asoc: failed to remove %s: %d\n",
+							codec_dai->name, err);
 		}
 		codec_dai->probed = 0;
 		list_del(&codec_dai->card_list);
@@ -916,12 +940,14 @@
 		if (platform->driver->remove) {
 			err = platform->driver->remove(platform);
 			if (err < 0)
-				printk(KERN_ERR "asoc: failed to remove %s\n", platform->name);
+				pr_err("asoc: failed to remove %s: %d\n",
+							platform->name, err);
 		}
 
 		/* Make sure all DAPM widgets are freed */
 		snd_soc_dapm_free(&platform->dapm);
 
+		soc_cleanup_platform_debugfs(platform);
 		platform->probed = 0;
 		list_del(&platform->card_list);
 		module_put(platform->dev->driver->owner);
@@ -938,7 +964,8 @@
 		if (cpu_dai->driver->remove) {
 			err = cpu_dai->driver->remove(cpu_dai);
 			if (err < 0)
-				printk(KERN_ERR "asoc: failed to remove %s\n", cpu_dai->name);
+				pr_err("asoc: failed to remove %s: %d\n",
+							cpu_dai->name, err);
 		}
 		cpu_dai->probed = 0;
 		list_del(&cpu_dai->card_list);
@@ -980,6 +1007,7 @@
 {
 	int ret = 0;
 	const struct snd_soc_codec_driver *driver = codec->driver;
+	struct snd_soc_dai *dai;
 
 	codec->card = card;
 	codec->dapm.card = card;
@@ -994,6 +1022,14 @@
 		snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
 					  driver->num_dapm_widgets);
 
+	/* Create DAPM widgets for each DAI stream */
+	list_for_each_entry(dai, &dai_list, list) {
+		if (dai->dev != codec->dev)
+			continue;
+
+		snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
+	}
+
 	codec->dapm.idle_bias_off = driver->idle_bias_off;
 
 	if (driver->probe) {
@@ -1007,7 +1043,7 @@
 	}
 
 	if (driver->controls)
-		snd_soc_add_controls(codec, driver->controls,
+		snd_soc_add_codec_controls(codec, driver->controls,
 				     driver->num_controls);
 	if (driver->dapm_routes)
 		snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes,
@@ -1039,6 +1075,8 @@
 	if (!try_module_get(platform->dev->driver->owner))
 		return -ENODEV;
 
+	soc_init_platform_debugfs(platform);
+
 	if (driver->dapm_widgets)
 		snd_soc_dapm_new_controls(&platform->dapm,
 			driver->dapm_widgets, driver->num_dapm_widgets);
@@ -1068,6 +1106,7 @@
 	return 0;
 
 err_probe:
+	soc_cleanup_platform_debugfs(platform);
 	module_put(platform->dev->driver->owner);
 
 	return ret;
@@ -1183,8 +1222,8 @@
 		if (cpu_dai->driver->probe) {
 			ret = cpu_dai->driver->probe(cpu_dai);
 			if (ret < 0) {
-				printk(KERN_ERR "asoc: failed to probe CPU DAI %s\n",
-						cpu_dai->name);
+				pr_err("asoc: failed to probe CPU DAI %s: %d\n",
+							cpu_dai->name, ret);
 				module_put(cpu_dai->dev->driver->owner);
 				return ret;
 			}
@@ -1215,8 +1254,8 @@
 		if (codec_dai->driver->probe) {
 			ret = codec_dai->driver->probe(codec_dai);
 			if (ret < 0) {
-				printk(KERN_ERR "asoc: failed to probe CODEC DAI %s\n",
-						codec_dai->name);
+				pr_err("asoc: failed to probe CODEC DAI %s: %d\n",
+							codec_dai->name, ret);
 				return ret;
 			}
 		}
@@ -1236,12 +1275,13 @@
 
 	ret = device_create_file(rtd->dev, &dev_attr_pmdown_time);
 	if (ret < 0)
-		printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n");
+		pr_warn("asoc: failed to add pmdown_time sysfs:%d\n", ret);
 
 	/* create the pcm */
 	ret = soc_new_pcm(rtd, num);
 	if (ret < 0) {
-		printk(KERN_ERR "asoc: can't create pcm %s\n", dai_link->stream_name);
+		pr_err("asoc: can't create pcm %s :%d\n",
+				dai_link->stream_name, ret);
 		return ret;
 	}
 
@@ -1274,7 +1314,7 @@
 
 		ret = soc_ac97_dev_register(rtd->codec);
 		if (ret < 0) {
-			printk(KERN_ERR "asoc: AC97 device register failed\n");
+			pr_err("asoc: AC97 device register failed:%d\n", ret);
 			return ret;
 		}
 
@@ -1414,8 +1454,8 @@
 	ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
 			card->owner, 0, &card->snd_card);
 	if (ret < 0) {
-		printk(KERN_ERR "asoc: can't create sound card for card %s\n",
-			card->name);
+		pr_err("asoc: can't create sound card for card %s: %d\n",
+			card->name, ret);
 		mutex_unlock(&card->mutex);
 		return;
 	}
@@ -1468,13 +1508,10 @@
 		}
 	}
 
-	/* We should have a non-codec control add function but we don't */
+	snd_soc_dapm_link_dai_widgets(card);
+
 	if (card->controls)
-		snd_soc_add_controls(list_first_entry(&card->codec_dev_list,
-						      struct snd_soc_codec,
-						      card_list),
-				     card->controls,
-				     card->num_controls);
+		snd_soc_add_card_controls(card, card->controls, card->num_controls);
 
 	if (card->dapm_routes)
 		snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
@@ -1488,14 +1525,14 @@
 		if (dai_link->dai_fmt) {
 			ret = snd_soc_dai_set_fmt(card->rtd[i].codec_dai,
 						  dai_link->dai_fmt);
-			if (ret != 0)
+			if (ret != 0 && ret != -ENOTSUPP)
 				dev_warn(card->rtd[i].codec_dai->dev,
 					 "Failed to set DAI format: %d\n",
 					 ret);
 
 			ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
 						  dai_link->dai_fmt);
-			if (ret != 0)
+			if (ret != 0 && ret != -ENOTSUPP)
 				dev_warn(card->rtd[i].cpu_dai->dev,
 					 "Failed to set DAI format: %d\n",
 					 ret);
@@ -1538,7 +1575,8 @@
 
 	ret = snd_card_register(card->snd_card);
 	if (ret < 0) {
-		printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name);
+		pr_err("asoc: failed to register soundcard for %s: %d\n",
+							card->name, ret);
 		goto probe_aux_dev_err;
 	}
 
@@ -1547,7 +1585,8 @@
 	for (i = 0; i < card->num_rtd; i++) {
 		ret = soc_register_ac97_dai_link(&card->rtd[i]);
 		if (ret < 0) {
-			printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name);
+			pr_err("asoc: failed to register AC97 %s: %d\n",
+							card->name, ret);
 			while (--i >= 0)
 				soc_unregister_ac97_dai_link(card->rtd[i].codec);
 			goto probe_aux_dev_err;
@@ -1600,6 +1639,10 @@
 	if (!card)
 		return -EINVAL;
 
+	dev_warn(&pdev->dev,
+		 "ASoC machine %s should use snd_soc_register_card()\n",
+		 card->name);
+
 	/* Bodge while we unpick instantiation */
 	card->dev = &pdev->dev;
 
@@ -1637,7 +1680,6 @@
 
 	snd_soc_dapm_free(&card->dapm);
 
-	kfree(card->rtd);
 	snd_card_free(card->snd_card);
 	return 0;
 
@@ -1676,7 +1718,10 @@
 const struct dev_pm_ops snd_soc_pm_ops = {
 	.suspend = snd_soc_suspend,
 	.resume = snd_soc_resume,
+	.freeze = snd_soc_suspend,
+	.thaw = snd_soc_resume,
 	.poweroff = snd_soc_poweroff,
+	.restore = snd_soc_resume,
 };
 EXPORT_SYMBOL_GPL(snd_soc_pm_ops);
 
@@ -1880,23 +1925,28 @@
 int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
 				unsigned int mask, unsigned int value)
 {
-	int change;
+	bool change;
 	unsigned int old, new;
 	int ret;
 
-	ret = snd_soc_read(codec, reg);
-	if (ret < 0)
-		return ret;
-
-	old = ret;
-	new = (old & ~mask) | (value & mask);
-	change = old != new;
-	if (change) {
-		ret = snd_soc_write(codec, reg, new);
+	if (codec->using_regmap) {
+		ret = regmap_update_bits_check(codec->control_data, reg,
+					       mask, value, &change);
+	} else {
+		ret = snd_soc_read(codec, reg);
 		if (ret < 0)
 			return ret;
+
+		old = ret;
+		new = (old & ~mask) | (value & mask);
+		change = old != new;
+		if (change)
+			ret = snd_soc_write(codec, reg, new);
 	}
 
+	if (ret < 0)
+		return ret;
+
 	return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_update_bits);
@@ -1987,7 +2037,7 @@
  * Returns 0 for success, else error.
  */
 struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
-				  void *data, char *long_name,
+				  void *data, const char *long_name,
 				  const char *prefix)
 {
 	struct snd_kcontrol_new template;
@@ -2022,9 +2072,28 @@
 }
 EXPORT_SYMBOL_GPL(snd_soc_cnew);
 
+static int snd_soc_add_controls(struct snd_card *card, struct device *dev,
+	const struct snd_kcontrol_new *controls, int num_controls,
+	const char *prefix, void *data)
+{
+	int err, i;
+
+	for (i = 0; i < num_controls; i++) {
+		const struct snd_kcontrol_new *control = &controls[i];
+		err = snd_ctl_add(card, snd_soc_cnew(control, data,
+						     control->name, prefix));
+		if (err < 0) {
+			dev_err(dev, "Failed to add %s: %d\n", control->name, err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
 /**
- * snd_soc_add_controls - add an array of controls to a codec.
- * Convienience function to add a list of controls. Many codecs were
+ * snd_soc_add_codec_controls - add an array of controls to a codec.
+ * Convenience function to add a list of controls. Many codecs were
  * duplicating this code.
  *
  * @codec: codec to add controls to
@@ -2033,31 +2102,19 @@
  *
  * Return 0 for success, else error.
  */
-int snd_soc_add_controls(struct snd_soc_codec *codec,
+int snd_soc_add_codec_controls(struct snd_soc_codec *codec,
 	const struct snd_kcontrol_new *controls, int num_controls)
 {
 	struct snd_card *card = codec->card->snd_card;
-	int err, i;
 
-	for (i = 0; i < num_controls; i++) {
-		const struct snd_kcontrol_new *control = &controls[i];
-		err = snd_ctl_add(card, snd_soc_cnew(control, codec,
-						     control->name,
-						     codec->name_prefix));
-		if (err < 0) {
-			dev_err(codec->dev, "%s: Failed to add %s: %d\n",
-				codec->name, control->name, err);
-			return err;
-		}
-	}
-
-	return 0;
+	return snd_soc_add_controls(card, codec->dev, controls, num_controls,
+			codec->name_prefix, codec);
 }
-EXPORT_SYMBOL_GPL(snd_soc_add_controls);
+EXPORT_SYMBOL_GPL(snd_soc_add_codec_controls);
 
 /**
  * snd_soc_add_platform_controls - add an array of controls to a platform.
- * Convienience function to add a list of controls.
+ * Convenience function to add a list of controls.
  *
  * @platform: platform to add controls to
  * @controls: array of controls to add
@@ -2069,23 +2126,53 @@
 	const struct snd_kcontrol_new *controls, int num_controls)
 {
 	struct snd_card *card = platform->card->snd_card;
-	int err, i;
 
-	for (i = 0; i < num_controls; i++) {
-		const struct snd_kcontrol_new *control = &controls[i];
-		err = snd_ctl_add(card, snd_soc_cnew(control, platform,
-				control->name, NULL));
-		if (err < 0) {
-			dev_err(platform->dev, "Failed to add %s %d\n",control->name, err);
-			return err;
-		}
-	}
-
-	return 0;
+	return snd_soc_add_controls(card, platform->dev, controls, num_controls,
+			NULL, platform);
 }
 EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls);
 
 /**
+ * snd_soc_add_card_controls - add an array of controls to a SoC card.
+ * Convenience function to add a list of controls.
+ *
+ * @soc_card: SoC card to add controls to
+ * @controls: array of controls to add
+ * @num_controls: number of elements in the array
+ *
+ * Return 0 for success, else error.
+ */
+int snd_soc_add_card_controls(struct snd_soc_card *soc_card,
+	const struct snd_kcontrol_new *controls, int num_controls)
+{
+	struct snd_card *card = soc_card->snd_card;
+
+	return snd_soc_add_controls(card, soc_card->dev, controls, num_controls,
+			NULL, soc_card);
+}
+EXPORT_SYMBOL_GPL(snd_soc_add_card_controls);
+
+/**
+ * snd_soc_add_dai_controls - add an array of controls to a DAI.
+ * Convienience function to add a list of controls.
+ *
+ * @dai: DAI to add controls to
+ * @controls: array of controls to add
+ * @num_controls: number of elements in the array
+ *
+ * Return 0 for success, else error.
+ */
+int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
+	const struct snd_kcontrol_new *controls, int num_controls)
+{
+	struct snd_card *card = dai->card->snd_card;
+
+	return snd_soc_add_controls(card, dai->dev, controls, num_controls,
+			NULL, dai);
+}
+EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls);
+
+/**
  * snd_soc_info_enum_double - enumerated double mixer info callback
  * @kcontrol: mixer control
  * @uinfo: control element information
@@ -2651,6 +2738,115 @@
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
 
+int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
+		       struct snd_ctl_elem_info *uinfo)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct soc_bytes *params = (void *)kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = params->num_regs * codec->val_bytes;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_bytes_info);
+
+int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int ret;
+
+	if (codec->using_regmap)
+		ret = regmap_raw_read(codec->control_data, params->base,
+				      ucontrol->value.bytes.data,
+				      params->num_regs * codec->val_bytes);
+	else
+		ret = -EINVAL;
+
+	/* Hide any masked bytes to ensure consistent data reporting */
+	if (ret == 0 && params->mask) {
+		switch (codec->val_bytes) {
+		case 1:
+			ucontrol->value.bytes.data[0] &= ~params->mask;
+			break;
+		case 2:
+			((u16 *)(&ucontrol->value.bytes.data))[0]
+				&= ~params->mask;
+			break;
+		case 4:
+			((u32 *)(&ucontrol->value.bytes.data))[0]
+				&= ~params->mask;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_bytes_get);
+
+int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int ret, len;
+	unsigned int val;
+	void *data;
+
+	if (!codec->using_regmap)
+		return -EINVAL;
+
+	data = ucontrol->value.bytes.data;
+	len = params->num_regs * codec->val_bytes;
+
+	/*
+	 * If we've got a mask then we need to preserve the register
+	 * bits.  We shouldn't modify the incoming data so take a
+	 * copy.
+	 */
+	if (params->mask) {
+		ret = regmap_read(codec->control_data, params->base, &val);
+		if (ret != 0)
+			return ret;
+
+		val &= params->mask;
+
+		data = kmemdup(data, len, GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+
+		switch (codec->val_bytes) {
+		case 1:
+			((u8 *)data)[0] &= ~params->mask;
+			((u8 *)data)[0] |= val;
+			break;
+		case 2:
+			((u16 *)data)[0] &= cpu_to_be16(~params->mask);
+			((u16 *)data)[0] |= cpu_to_be16(val);
+			break;
+		case 4:
+			((u32 *)data)[0] &= cpu_to_be32(~params->mask);
+			((u32 *)data)[0] |= cpu_to_be32(val);
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	ret = regmap_raw_write(codec->control_data, params->base,
+			       data, len);
+
+	if (params->mask)
+		kfree(data);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_bytes_put);
+
 /**
  * snd_soc_dai_set_sysclk - configure DAI system or master clock.
  * @dai: DAI
@@ -2768,10 +2964,11 @@
  */
 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	if (dai->driver && dai->driver->ops->set_fmt)
-		return dai->driver->ops->set_fmt(dai, fmt);
-	else
+	if (dai->driver == NULL)
 		return -EINVAL;
+	if (dai->driver->ops->set_fmt == NULL)
+		return -ENOTSUPP;
+	return dai->driver->ops->set_fmt(dai, fmt);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
 
@@ -2875,7 +3072,8 @@
 		 */
 		if (!!link->codec_name == !!link->codec_of_node) {
 			dev_err(card->dev,
-				"Neither/both codec name/of_node are set\n");
+				"Neither/both codec name/of_node are set for %s\n",
+				link->name);
 			return -EINVAL;
 		}
 
@@ -2885,7 +3083,7 @@
 		 */
 		if (link->platform_name && link->platform_of_node) {
 			dev_err(card->dev,
-				"Both platform name/of_node are set\n");
+				"Both platform name/of_node are set for %s\n", link->name);
 			return -EINVAL;
 		}
 
@@ -2895,7 +3093,8 @@
 		 */
 		if (!!link->cpu_dai_name == !!link->cpu_dai_of_node) {
 			dev_err(card->dev,
-				"Neither/both cpu_dai name/of_node are set\n");
+				"Neither/both cpu_dai name/of_node are set for %s\n",
+				link->name);
 			return -EINVAL;
 		}
 	}
@@ -2906,9 +3105,10 @@
 
 	soc_init_card_debugfs(card);
 
-	card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) *
-			    (card->num_links + card->num_aux_devs),
-			    GFP_KERNEL);
+	card->rtd = devm_kzalloc(card->dev,
+				 sizeof(struct snd_soc_pcm_runtime) *
+				 (card->num_links + card->num_aux_devs),
+				 GFP_KERNEL);
 	if (card->rtd == NULL)
 		return -ENOMEM;
 	card->rtd_aux = &card->rtd[card->num_links];
@@ -3002,7 +3202,7 @@
 		struct snd_soc_dai_driver *dai_drv)
 {
 	if (dai_drv->name == NULL) {
-		printk(KERN_ERR "asoc: error - multiple DAI %s registered with no name\n",
+		pr_err("asoc: error - multiple DAI %s registered with no name\n",
 				dev_name(dev));
 		return NULL;
 	}
@@ -3177,6 +3377,7 @@
 	platform->dapm.dev = dev;
 	platform->dapm.platform = platform;
 	platform->dapm.stream_event = platform_drv->stream_event;
+	mutex_init(&platform->mutex);
 
 	mutex_lock(&client_mutex);
 	list_add(&platform->list, &platform_list);
@@ -3285,6 +3486,7 @@
 	codec->volatile_register = codec_drv->volatile_register;
 	codec->readable_register = codec_drv->readable_register;
 	codec->writable_register = codec_drv->writable_register;
+	codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time;
 	codec->dapm.bias_level = SND_SOC_BIAS_OFF;
 	codec->dapm.dev = dev;
 	codec->dapm.codec = codec;
@@ -3473,8 +3675,7 @@
 #ifdef CONFIG_DEBUG_FS
 	snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
 	if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) {
-		printk(KERN_WARNING
-		       "ASoC: Failed to create debugfs directory\n");
+		pr_warn("ASoC: Failed to create debugfs directory\n");
 		snd_soc_debugfs_root = NULL;
 	}
 
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 1315663..5cbd2d76 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -14,19 +14,13 @@
  *      dynamic configuration of codec internal audio paths and active
  *      DACs/ADCs.
  *    o Platform power domain - can support external components i.e. amps and
- *      mic/meadphone insertion events.
+ *      mic/headphone insertion events.
  *    o Automatic Mic Bias support
  *    o Jack insertion power event initiation - e.g. hp insertion will enable
  *      sinks, dacs, etc
- *    o Delayed powerdown of audio susbsystem to reduce pops between a quick
+ *    o Delayed power down of audio subsystem to reduce pops between a quick
  *      device reopen.
  *
- *  Todo:
- *    o DAPM power change sequencing - allow for configurable per
- *      codec sequences.
- *    o Support for analogue bias optimisation.
- *    o Support for reduced codec oversampling rates.
- *    o Support for reduced codec bias currents.
  */
 
 #include <linux/module.h>
@@ -40,6 +34,7 @@
 #include <linux/jiffies.h>
 #include <linux/debugfs.h>
 #include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -55,7 +50,9 @@
 static int dapm_up_seq[] = {
 	[snd_soc_dapm_pre] = 0,
 	[snd_soc_dapm_supply] = 1,
+	[snd_soc_dapm_regulator_supply] = 1,
 	[snd_soc_dapm_micbias] = 2,
+	[snd_soc_dapm_dai] = 3,
 	[snd_soc_dapm_aif_in] = 3,
 	[snd_soc_dapm_aif_out] = 3,
 	[snd_soc_dapm_mic] = 4,
@@ -90,6 +87,8 @@
 	[snd_soc_dapm_value_mux] = 9,
 	[snd_soc_dapm_aif_in] = 10,
 	[snd_soc_dapm_aif_out] = 10,
+	[snd_soc_dapm_dai] = 10,
+	[snd_soc_dapm_regulator_supply] = 11,
 	[snd_soc_dapm_supply] = 11,
 	[snd_soc_dapm_post] = 12,
 };
@@ -172,6 +171,19 @@
 	return NULL;
 }
 
+static void dapm_reset(struct snd_soc_card *card)
+{
+	struct snd_soc_dapm_widget *w;
+
+	memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
+
+	list_for_each_entry(w, &card->widgets, list) {
+		w->power_checked = false;
+		w->inputs = -1;
+		w->outputs = -1;
+	}
+}
+
 static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg)
 {
 	if (w->codec)
@@ -197,21 +209,28 @@
 static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
 	unsigned short reg, unsigned int mask, unsigned int value)
 {
-	int change;
+	bool change;
 	unsigned int old, new;
 	int ret;
 
-	ret = soc_widget_read(w, reg);
-	if (ret < 0)
-		return ret;
-
-	old = ret;
-	new = (old & ~mask) | (value & mask);
-	change = old != new;
-	if (change) {
-		ret = soc_widget_write(w, reg, new);
+	if (w->codec && w->codec->using_regmap) {
+		ret = regmap_update_bits_check(w->codec->control_data,
+					       reg, mask, value, &change);
+		if (ret != 0)
+			return ret;
+	} else {
+		ret = soc_widget_read(w, reg);
 		if (ret < 0)
 			return ret;
+
+		old = ret;
+		new = (old & ~mask) | (value & mask);
+		change = old != new;
+		if (change) {
+			ret = soc_widget_write(w, reg, new);
+			if (ret < 0)
+				return ret;
+		}
 	}
 
 	return change;
@@ -345,8 +364,10 @@
 	case snd_soc_dapm_micbias:
 	case snd_soc_dapm_vmid:
 	case snd_soc_dapm_supply:
+	case snd_soc_dapm_regulator_supply:
 	case snd_soc_dapm_aif_in:
 	case snd_soc_dapm_aif_out:
+	case snd_soc_dapm_dai:
 	case snd_soc_dapm_hp:
 	case snd_soc_dapm_mic:
 	case snd_soc_dapm_spk:
@@ -504,17 +525,17 @@
 				 * for widgets so cut the prefix off
 				 * the front of the widget name.
 				 */
-				snprintf(path->long_name, name_len, "%s %s",
-					 w->name + prefix_len,
+				snprintf((char *)path->long_name, name_len,
+					 "%s %s", w->name + prefix_len,
 					 w->kcontrol_news[i].name);
 				break;
 			case snd_soc_dapm_mixer_named_ctl:
-				snprintf(path->long_name, name_len, "%s",
-					 w->kcontrol_news[i].name);
+				snprintf((char *)path->long_name, name_len,
+					 "%s", w->kcontrol_news[i].name);
 				break;
 			}
 
-			path->long_name[name_len - 1] = '\0';
+			((char *)path->long_name)[name_len - 1] = '\0';
 
 			path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
 						      wlist, path->long_name,
@@ -548,7 +569,7 @@
 	struct snd_soc_dapm_widget_list *wlist;
 	int shared, wlistentries;
 	size_t wlistsize;
-	char *name;
+	const char *name;
 
 	if (w->num_kcontrols != 1) {
 		dev_err(dapm->dev,
@@ -673,12 +694,18 @@
 
 	DAPM_UPDATE_STAT(widget, path_checks);
 
-	if (widget->id == snd_soc_dapm_supply)
+	switch (widget->id) {
+	case snd_soc_dapm_supply:
+	case snd_soc_dapm_regulator_supply:
 		return 0;
+	default:
+		break;
+	}
 
 	switch (widget->id) {
 	case snd_soc_dapm_adc:
 	case snd_soc_dapm_aif_out:
+	case snd_soc_dapm_dai:
 		if (widget->active) {
 			widget->outputs = snd_soc_dapm_suspend_check(widget);
 			return widget->outputs;
@@ -738,13 +765,19 @@
 
 	DAPM_UPDATE_STAT(widget, path_checks);
 
-	if (widget->id == snd_soc_dapm_supply)
+	switch (widget->id) {
+	case snd_soc_dapm_supply:
+	case snd_soc_dapm_regulator_supply:
 		return 0;
+	default:
+		break;
+	}
 
 	/* active stream ? */
 	switch (widget->id) {
 	case snd_soc_dapm_dac:
 	case snd_soc_dapm_aif_in:
+	case snd_soc_dapm_dai:
 		if (widget->active) {
 			widget->inputs = snd_soc_dapm_suspend_check(widget);
 			return widget->inputs;
@@ -821,6 +854,19 @@
 }
 EXPORT_SYMBOL_GPL(dapm_reg_event);
 
+/*
+ * Handler for regulator supply widget.
+ */
+int dapm_regulator_event(struct snd_soc_dapm_widget *w,
+		   struct snd_kcontrol *kcontrol, int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		return regulator_enable(w->priv);
+	else
+		return regulator_disable_deferred(w->priv, w->shift);
+}
+EXPORT_SYMBOL_GPL(dapm_regulator_event);
+
 static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
 {
 	if (w->power_checked)
@@ -851,6 +897,13 @@
 	return out != 0 && in != 0;
 }
 
+static int dapm_dai_check_power(struct snd_soc_dapm_widget *w)
+{
+	DAPM_UPDATE_STAT(w, power_checks);
+
+	return w->active;
+}
+
 /* Check to see if an ADC has power */
 static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
 {
@@ -1251,7 +1304,7 @@
 			dev_err(d->dev, "Failed to turn off bias: %d\n", ret);
 
 		if (d->dev)
-			pm_runtime_put_sync(d->dev);
+			pm_runtime_put(d->dev);
 	}
 
 	/* If we just powered up then move to active bias */
@@ -1301,6 +1354,7 @@
 	}
 	switch (w->id) {
 	case snd_soc_dapm_supply:
+	case snd_soc_dapm_regulator_supply:
 		/* Supplies can't affect their outputs, only their inputs */
 		break;
 	default:
@@ -1373,13 +1427,7 @@
 		}
 	}
 
-	memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
-
-	list_for_each_entry(w, &card->widgets, list) {
-		w->power_checked = false;
-		w->inputs = -1;
-		w->outputs = -1;
-	}
+	dapm_reset(card);
 
 	/* Check which widgets we need to power and store them in
 	 * lists indicating if they should be powered up or down.  We
@@ -1400,10 +1448,15 @@
 			/* Supplies and micbiases only bring the
 			 * context up to STANDBY as unless something
 			 * else is active and passing audio they
-			 * generally don't require full power.
+			 * generally don't require full power.  Signal
+			 * generators are virtual pins and have no
+			 * power impact themselves.
 			 */
 			switch (w->id) {
+			case snd_soc_dapm_siggen:
+				break;
 			case snd_soc_dapm_supply:
+			case snd_soc_dapm_regulator_supply:
 			case snd_soc_dapm_micbias:
 				if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
 					d->target_bias_level = SND_SOC_BIAS_STANDBY;
@@ -1475,6 +1528,12 @@
 					&async_domain);
 	async_synchronize_full_domain(&async_domain);
 
+	/* do we need to notify any clients that DAPM event is complete */
+	list_for_each_entry(d, &card->dapm_list, list) {
+		if (d->stream_event)
+			d->stream_event(d, event);
+	}
+
 	pop_dbg(dapm->dev, card->pop_time,
 		"DAPM sequencing finished, waiting %dms\n", card->pop_time);
 	pop_wait(card->pop_time);
@@ -1485,12 +1544,6 @@
 }
 
 #ifdef CONFIG_DEBUG_FS
-static int dapm_widget_power_open_file(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t dapm_widget_power_read_file(struct file *file,
 					   char __user *user_buf,
 					   size_t count, loff_t *ppos)
@@ -1510,8 +1563,9 @@
 	out = is_connected_output_ep(w);
 	dapm_clear_walk(w->dapm);
 
-	ret = snprintf(buf, PAGE_SIZE, "%s: %s  in %d out %d",
-		       w->name, w->power ? "On" : "Off", in, out);
+	ret = snprintf(buf, PAGE_SIZE, "%s: %s%s  in %d out %d",
+		       w->name, w->power ? "On" : "Off",
+		       w->force ? " (forced)" : "", in, out);
 
 	if (w->reg >= 0)
 		ret += snprintf(buf + ret, PAGE_SIZE - ret,
@@ -1553,17 +1607,11 @@
 }
 
 static const struct file_operations dapm_widget_power_fops = {
-	.open = dapm_widget_power_open_file,
+	.open = simple_open,
 	.read = dapm_widget_power_read_file,
 	.llseek = default_llseek,
 };
 
-static int dapm_bias_open_file(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
 static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
 				   size_t count, loff_t *ppos)
 {
@@ -1594,7 +1642,7 @@
 }
 
 static const struct file_operations dapm_bias_fops = {
-	.open = dapm_bias_open_file,
+	.open = simple_open,
 	.read = dapm_bias_read_file,
 	.llseek = default_llseek,
 };
@@ -1607,7 +1655,7 @@
 	dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
 
 	if (!dapm->debugfs_dapm) {
-		printk(KERN_WARNING
+		dev_warn(dapm->dev,
 		       "Failed to create DAPM debugfs directory\n");
 		return;
 	}
@@ -1659,9 +1707,8 @@
 #endif
 
 /* test and update the power status of a mux widget */
-static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
-				 struct snd_kcontrol *kcontrol, int change,
-				 int mux, struct soc_enum *e)
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+				 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
 {
 	struct snd_soc_dapm_path *path;
 	int found = 0;
@@ -1671,9 +1718,6 @@
 	    widget->id != snd_soc_dapm_value_mux)
 		return -ENODEV;
 
-	if (!change)
-		return 0;
-
 	/* find dapm widget path assoc with kcontrol */
 	list_for_each_entry(path, &widget->dapm->card->paths, list) {
 		if (path->kcontrol != kcontrol)
@@ -1702,9 +1746,10 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
 
 /* test and update the power status of a mixer or switch widget */
-static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
 				   struct snd_kcontrol *kcontrol, int connect)
 {
 	struct snd_soc_dapm_path *path;
@@ -1733,6 +1778,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
 
 /* show dapm widget status in sys fs */
 static ssize_t dapm_widget_show(struct device *dev,
@@ -1762,6 +1808,7 @@
 		case snd_soc_dapm_mixer:
 		case snd_soc_dapm_mixer_named_ctl:
 		case snd_soc_dapm_supply:
+		case snd_soc_dapm_regulator_supply:
 			if (w->name)
 				count += sprintf(buf + count, "%s: %s\n",
 					w->name, w->power ? "On":"Off");
@@ -1869,10 +1916,12 @@
 		return -EINVAL;
 	}
 
+	if (w->connected != status)
+		dapm_mark_dirty(w, "pin configuration");
+
 	w->connected = status;
 	if (status == 0)
 		w->force = 0;
-	dapm_mark_dirty(w, "pin configuration");
 
 	return 0;
 }
@@ -2000,8 +2049,10 @@
 	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_aif_in:
 	case snd_soc_dapm_aif_out:
+	case snd_soc_dapm_dai:
 		list_add(&path->list, &dapm->card->paths);
 		list_add(&path->list_sink, &wsink->sources);
 		list_add(&path->list_source, &wsource->sinks);
@@ -2315,7 +2366,7 @@
 			update.val = val;
 			widget->dapm->update = &update;
 
-			dapm_mixer_update_power(widget, kcontrol, connect);
+			snd_soc_dapm_mixer_update_power(widget, kcontrol, connect);
 
 			widget->dapm->update = NULL;
 		}
@@ -2406,7 +2457,7 @@
 			update.val = val;
 			widget->dapm->update = &update;
 
-			dapm_mux_update_power(widget, kcontrol, change, mux, e);
+			snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e);
 
 			widget->dapm->update = NULL;
 		}
@@ -2467,8 +2518,7 @@
 
 			widget->value = ucontrol->value.enumerated.item[0];
 
-			dapm_mux_update_power(widget, kcontrol, change,
-					      widget->value, e);
+			snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
 		}
 	}
 
@@ -2571,7 +2621,7 @@
 			update.val = val;
 			widget->dapm->update = &update;
 
-			dapm_mux_update_power(widget, kcontrol, change, mux, e);
+			snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e);
 
 			widget->dapm->update = NULL;
 		}
@@ -2611,15 +2661,15 @@
 int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 	const char *pin = (const char *)kcontrol->private_value;
 
-	mutex_lock(&codec->mutex);
+	mutex_lock(&card->mutex);
 
 	ucontrol->value.integer.value[0] =
-		snd_soc_dapm_get_pin_status(&codec->dapm, pin);
+		snd_soc_dapm_get_pin_status(&card->dapm, pin);
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->mutex);
 
 	return 0;
 }
@@ -2634,41 +2684,48 @@
 int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 	const char *pin = (const char *)kcontrol->private_value;
 
-	mutex_lock(&codec->mutex);
+	mutex_lock(&card->mutex);
 
 	if (ucontrol->value.integer.value[0])
-		snd_soc_dapm_enable_pin(&codec->dapm, pin);
+		snd_soc_dapm_enable_pin(&card->dapm, pin);
 	else
-		snd_soc_dapm_disable_pin(&codec->dapm, pin);
+		snd_soc_dapm_disable_pin(&card->dapm, pin);
 
-	snd_soc_dapm_sync(&codec->dapm);
+	snd_soc_dapm_sync(&card->dapm);
 
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->mutex);
 
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
 
-/**
- * snd_soc_dapm_new_control - create new dapm control
- * @dapm: DAPM context
- * @widget: widget template
- *
- * Creates a new dapm control based upon the template.
- *
- * Returns 0 for success else error.
- */
-int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
-	const struct snd_soc_dapm_widget *widget)
+static struct snd_soc_dapm_widget *
+snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
+			 const struct snd_soc_dapm_widget *widget)
 {
 	struct snd_soc_dapm_widget *w;
 	size_t name_len;
+	int ret;
 
 	if ((w = dapm_cnew_widget(widget)) == NULL)
-		return -ENOMEM;
+		return NULL;
+
+	switch (w->id) {
+	case snd_soc_dapm_regulator_supply:
+		w->priv = devm_regulator_get(dapm->dev, w->name);
+		if (IS_ERR(w->priv)) {
+			ret = PTR_ERR(w->priv);
+			dev_err(dapm->dev, "Failed to request %s: %d\n",
+				w->name, ret);
+			return NULL;
+		}
+		break;
+	default:
+		break;
+	}
 
 	name_len = strlen(widget->name) + 1;
 	if (dapm->codec && dapm->codec->name_prefix)
@@ -2676,13 +2733,13 @@
 	w->name = kmalloc(name_len, GFP_KERNEL);
 	if (w->name == NULL) {
 		kfree(w);
-		return -ENOMEM;
+		return NULL;
 	}
 	if (dapm->codec && dapm->codec->name_prefix)
-		snprintf(w->name, name_len, "%s %s",
+		snprintf((char *)w->name, name_len, "%s %s",
 			dapm->codec->name_prefix, widget->name);
 	else
-		snprintf(w->name, name_len, "%s", widget->name);
+		snprintf((char *)w->name, name_len, "%s", widget->name);
 
 	switch (w->id) {
 	case snd_soc_dapm_switch:
@@ -2715,8 +2772,12 @@
 		w->power_check = dapm_generic_check_power;
 		break;
 	case snd_soc_dapm_supply:
+	case snd_soc_dapm_regulator_supply:
 		w->power_check = dapm_supply_check_power;
 		break;
+	case snd_soc_dapm_dai:
+		w->power_check = dapm_dai_check_power;
+		break;
 	default:
 		w->power_check = dapm_always_on_check_power;
 		break;
@@ -2734,9 +2795,8 @@
 
 	/* machine layer set ups unconnected pins and insertions */
 	w->connected = 1;
-	return 0;
+	return w;
 }
-EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
 
 /**
  * snd_soc_dapm_new_controls - create new dapm controls
@@ -2752,15 +2812,16 @@
 	const struct snd_soc_dapm_widget *widget,
 	int num)
 {
-	int i, ret;
+	struct snd_soc_dapm_widget *w;
+	int i;
 
 	for (i = 0; i < num; i++) {
-		ret = snd_soc_dapm_new_control(dapm, widget);
-		if (ret < 0) {
+		w = snd_soc_dapm_new_control(dapm, widget);
+		if (!w) {
 			dev_err(dapm->dev,
-				"ASoC: Failed to create DAPM control %s: %d\n",
-				widget->name, ret);
-			return ret;
+				"ASoC: Failed to create DAPM control %s\n",
+				widget->name);
+			return -ENOMEM;
 		}
 		widget++;
 	}
@@ -2768,40 +2829,140 @@
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
 
-static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
-	const char *stream, int event)
+int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
+				 struct snd_soc_dai *dai)
 {
+	struct snd_soc_dapm_widget template;
 	struct snd_soc_dapm_widget *w;
 
-	list_for_each_entry(w, &dapm->card->widgets, list)
-	{
-		if (!w->sname || w->dapm != dapm)
+	WARN_ON(dapm->dev != dai->dev);
+
+	memset(&template, 0, sizeof(template));
+	template.reg = SND_SOC_NOPM;
+
+	if (dai->driver->playback.stream_name) {
+		template.id = snd_soc_dapm_dai;
+		template.name = dai->driver->playback.stream_name;
+		template.sname = dai->driver->playback.stream_name;
+
+		dev_dbg(dai->dev, "adding %s widget\n",
+			template.name);
+
+		w = snd_soc_dapm_new_control(dapm, &template);
+		if (!w) {
+			dev_err(dapm->dev, "Failed to create %s widget\n",
+				dai->driver->playback.stream_name);
+		}
+
+		w->priv = dai;
+		dai->playback_widget = w;
+	}
+
+	if (dai->driver->capture.stream_name) {
+		template.id = snd_soc_dapm_dai;
+		template.name = dai->driver->capture.stream_name;
+		template.sname = dai->driver->capture.stream_name;
+
+		dev_dbg(dai->dev, "adding %s widget\n",
+			template.name);
+
+		w = snd_soc_dapm_new_control(dapm, &template);
+		if (!w) {
+			dev_err(dapm->dev, "Failed to create %s widget\n",
+				dai->driver->capture.stream_name);
+		}
+
+		w->priv = dai;
+		dai->capture_widget = w;
+	}
+
+	return 0;
+}
+
+int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
+{
+	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) {
+		if (dai_w->id != snd_soc_dapm_dai)
 			continue;
-		dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n",
-			w->name, w->sname, stream, event);
-		if (strstr(w->sname, stream)) {
-			dapm_mark_dirty(w, "stream event");
-			switch(event) {
-			case SND_SOC_DAPM_STREAM_START:
-				w->active = 1;
-				break;
-			case SND_SOC_DAPM_STREAM_STOP:
-				w->active = 0;
-				break;
-			case SND_SOC_DAPM_STREAM_SUSPEND:
-			case SND_SOC_DAPM_STREAM_RESUME:
-			case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
-			case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
-				break;
+
+		dai = dai_w->priv;
+
+		/* ...find all widgets with the same stream and link them */
+		list_for_each_entry(w, &card->widgets, list) {
+			if (w->dapm != dai_w->dapm)
+				continue;
+
+			if (w->id == snd_soc_dapm_dai)
+				continue;
+
+			if (!w->sname)
+				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);
+
+				snd_soc_dapm_add_route(w->dapm, &r);
+			}
+
+			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);
+
+				snd_soc_dapm_add_route(w->dapm, &r);
 			}
 		}
 	}
 
-	dapm_power_widgets(dapm, event);
+	return 0;
+}
 
-	/* do we need to notify any clients that DAPM stream is complete */
-	if (dapm->stream_event)
-		dapm->stream_event(dapm, event);
+static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
+				  int stream, struct snd_soc_dai *dai,
+				  int event)
+{
+	struct snd_soc_dapm_widget *w;
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		w = dai->playback_widget;
+	else
+		w = dai->capture_widget;
+
+	if (!w)
+		return;
+
+	dapm_mark_dirty(w, "stream event");
+
+	switch (event) {
+	case SND_SOC_DAPM_STREAM_START:
+		w->active = 1;
+		break;
+	case SND_SOC_DAPM_STREAM_STOP:
+		w->active = 0;
+		break;
+	case SND_SOC_DAPM_STREAM_SUSPEND:
+	case SND_SOC_DAPM_STREAM_RESUME:
+	case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
+	case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
+		break;
+	}
+
+	dapm_power_widgets(dapm, event);
 }
 
 /**
@@ -2815,16 +2976,13 @@
  *
  * Returns 0 for success else error.
  */
-int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
-	const char *stream, int event)
+int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+			      struct snd_soc_dai *dai, int event)
 {
 	struct snd_soc_codec *codec = rtd->codec;
 
-	if (stream == NULL)
-		return 0;
-
 	mutex_lock(&codec->mutex);
-	soc_dapm_stream_event(&codec->dapm, stream, event);
+	soc_dapm_stream_event(&codec->dapm, stream, dai, event);
 	mutex_unlock(&codec->mutex);
 	return 0;
 }
diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c
new file mode 100644
index 0000000..4756952
--- /dev/null
+++ b/sound/soc/soc-dmaengine-pcm.c
@@ -0,0 +1,288 @@
+/*
+ *  Copyright (C) 2012, Analog Devices Inc.
+ *	Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ *  Based on:
+ *	imx-pcm-dma-mx2.c, Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
+ *	mxs-pcm.c, Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *	ep93xx-pcm.c, Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *		      Copyright (C) 2006 Applied Data Systems
+ *
+ *  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.
+ *
+ *  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/init.h>
+#include <linux/dmaengine.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <sound/dmaengine_pcm.h>
+
+struct dmaengine_pcm_runtime_data {
+	struct dma_chan *dma_chan;
+
+	unsigned int pos;
+
+	void *data;
+};
+
+static inline struct dmaengine_pcm_runtime_data *substream_to_prtd(
+	const struct snd_pcm_substream *substream)
+{
+	return substream->runtime->private_data;
+}
+
+/**
+ * snd_dmaengine_pcm_set_data - Set dmaengine substream private data
+ * @substream: PCM substream
+ * @data: Data to set
+ */
+void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+
+	prtd->data = data;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_data);
+
+/**
+ * snd_dmaengine_pcm_get_data - Get dmaeinge substream private data
+ * @substream: PCM substream
+ *
+ * Returns the data previously set with snd_dmaengine_pcm_set_data
+ */
+void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+
+	return prtd->data;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_data);
+
+struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+
+	return prtd->dma_chan;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_chan);
+
+/**
+ * snd_hwparams_to_dma_slave_config - Convert hw_params to dma_slave_config
+ * @substream: PCM substream
+ * @params: hw_params
+ * @slave_config: DMA slave config
+ *
+ * This function can be used to initialize a dma_slave_config from a substream
+ * and hw_params in a dmaengine based PCM driver implementation.
+ */
+int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
+	const struct snd_pcm_hw_params *params,
+	struct dma_slave_config *slave_config)
+{
+	enum dma_slave_buswidth buswidth;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+		break;
+	case SNDRV_PCM_FORMAT_S18_3LE:
+	case SNDRV_PCM_FORMAT_S20_3LE:
+	case SNDRV_PCM_FORMAT_S24_LE:
+	case SNDRV_PCM_FORMAT_S32_LE:
+		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		slave_config->direction = DMA_MEM_TO_DEV;
+		slave_config->dst_addr_width = buswidth;
+	} else {
+		slave_config->direction = DMA_DEV_TO_MEM;
+		slave_config->src_addr_width = buswidth;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config);
+
+static void dmaengine_pcm_dma_complete(void *arg)
+{
+	struct snd_pcm_substream *substream = arg;
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+
+	prtd->pos += snd_pcm_lib_period_bytes(substream);
+	if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream))
+		prtd->pos = 0;
+
+	snd_pcm_period_elapsed(substream);
+}
+
+static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+	struct dma_chan *chan = prtd->dma_chan;
+	struct dma_async_tx_descriptor *desc;
+	enum dma_transfer_direction direction;
+
+	direction = snd_pcm_substream_to_dma_direction(substream);
+
+	prtd->pos = 0;
+	desc = dmaengine_prep_dma_cyclic(chan,
+		substream->runtime->dma_addr,
+		snd_pcm_lib_buffer_bytes(substream),
+		snd_pcm_lib_period_bytes(substream), direction);
+
+	if (!desc)
+		return -ENOMEM;
+
+	desc->callback = dmaengine_pcm_dma_complete;
+	desc->callback_param = substream;
+	dmaengine_submit(desc);
+
+	return 0;
+}
+
+/**
+ * snd_dmaengine_pcm_trigger - dmaengine based PCM trigger implementation
+ * @substream: PCM substream
+ * @cmd: Trigger command
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ *
+ * This function can be used as the PCM trigger callback for dmaengine based PCM
+ * driver implementations.
+ */
+int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+	int ret;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		ret = dmaengine_pcm_prepare_and_submit(substream);
+		if (ret)
+			return ret;
+		dma_async_issue_pending(prtd->dma_chan);
+		break;
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		dmaengine_resume(prtd->dma_chan);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		dmaengine_pause(prtd->dma_chan);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		dmaengine_terminate_all(prtd->dma_chan);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_trigger);
+
+/**
+ * snd_dmaengine_pcm_pointer - dmaengine based PCM pointer implementation
+ * @substream: PCM substream
+ *
+ * This function can be used as the PCM pointer callback for dmaengine based PCM
+ * driver implementations.
+ */
+snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+	return bytes_to_frames(substream->runtime, prtd->pos);
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer);
+
+static int dmaengine_pcm_request_channel(struct dmaengine_pcm_runtime_data *prtd,
+	dma_filter_fn filter_fn, void *filter_data)
+{
+	dma_cap_mask_t mask;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	dma_cap_set(DMA_CYCLIC, mask);
+	prtd->dma_chan = dma_request_channel(mask, filter_fn, filter_data);
+
+	if (!prtd->dma_chan)
+		return -ENXIO;
+
+	return 0;
+}
+
+/**
+ * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream
+ * @substream: PCM substream
+ * @filter_fn: Filter function used to request the DMA channel
+ * @filter_data: Data passed to the DMA filter function
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ *
+ * This function will request a DMA channel using the passed filter function and
+ * data. The function should usually be called from the pcm open callback.
+ *
+ * Note that this function will use private_data field of the substream's
+ * runtime. So it is not availabe to your pcm driver implementation. If you need
+ * to keep additional data attached to a substream use
+ * snd_dmaeinge_pcm_{set,get}_data.
+ */
+int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
+	dma_filter_fn filter_fn, void *filter_data)
+{
+	struct dmaengine_pcm_runtime_data *prtd;
+	int ret;
+
+	ret = snd_pcm_hw_constraint_integer(substream->runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		return ret;
+
+	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
+	if (!prtd)
+		return -ENOMEM;
+
+	ret = dmaengine_pcm_request_channel(prtd, filter_fn, filter_data);
+	if (ret < 0) {
+		kfree(prtd);
+		return ret;
+	}
+
+	substream->runtime->private_data = prtd;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open);
+
+/**
+ * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
+ * @substream: PCM substream
+ */
+int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+
+	dma_release_channel(prtd->dma_chan);
+	kfree(prtd);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close);
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index c8610cb..4d8dc6a 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -114,6 +114,7 @@
 			       enum snd_soc_control_type control)
 {
 	struct regmap_config config;
+	int ret;
 
 	memset(&config, 0, sizeof(config));
 	codec->write = hw_write;
@@ -140,6 +141,12 @@
 
 	case SND_SOC_REGMAP:
 		/* Device has made its own regmap arrangements */
+		codec->using_regmap = true;
+
+		ret = regmap_get_val_bytes(codec->control_data);
+		/* Errors are legitimate for non-integer byte multiples */
+		if (ret > 0)
+			codec->val_bytes = ret;
 		break;
 
 	default:
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index cdc860a..0ad8dca 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -63,6 +63,41 @@
 }
 
 /*
+ * List of sample sizes that might go over the bus for parameter
+ * application.  There ought to be a wildcard sample size for things
+ * like the DAC/ADC resolution to use but there isn't right now.
+ */
+static int sample_sizes[] = {
+	24, 32,
+};
+
+static void soc_pcm_apply_msb(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	int ret, i, bits;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		bits = dai->driver->playback.sig_bits;
+	else
+		bits = dai->driver->capture.sig_bits;
+
+	if (!bits)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(sample_sizes); i++) {
+		if (bits >= sample_sizes[i])
+			continue;
+
+		ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0,
+						   sample_sizes[i], bits);
+		if (ret != 0)
+			dev_warn(dai->dev,
+				 "Failed to set MSB %d/%d: %d\n",
+				 bits, sample_sizes[i], ret);
+	}
+}
+
+/*
  * Called by ALSA when a PCM substream is opened, the runtime->hw record is
  * then initialized and any private data can be allocated. This also calls
  * startup for the cpu DAI, platform, machine and codec DAI.
@@ -88,8 +123,8 @@
 	if (cpu_dai->driver->ops->startup) {
 		ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
 		if (ret < 0) {
-			printk(KERN_ERR "asoc: can't open interface %s\n",
-				cpu_dai->name);
+			dev_err(cpu_dai->dev, "can't open interface %s: %d\n",
+				cpu_dai->name, ret);
 			goto out;
 		}
 	}
@@ -97,7 +132,8 @@
 	if (platform->driver->ops && platform->driver->ops->open) {
 		ret = platform->driver->ops->open(substream);
 		if (ret < 0) {
-			printk(KERN_ERR "asoc: can't open platform %s\n", platform->name);
+			dev_err(platform->dev, "can't open platform %s: %d\n",
+				platform->name, ret);
 			goto platform_err;
 		}
 	}
@@ -105,8 +141,8 @@
 	if (codec_dai->driver->ops->startup) {
 		ret = codec_dai->driver->ops->startup(substream, codec_dai);
 		if (ret < 0) {
-			printk(KERN_ERR "asoc: can't open codec %s\n",
-				codec_dai->name);
+			dev_err(codec_dai->dev, "can't open codec %s: %d\n",
+				codec_dai->name, ret);
 			goto codec_dai_err;
 		}
 	}
@@ -114,7 +150,8 @@
 	if (rtd->dai_link->ops && rtd->dai_link->ops->startup) {
 		ret = rtd->dai_link->ops->startup(substream);
 		if (ret < 0) {
-			printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name);
+			pr_err("asoc: %s startup failed: %d\n",
+			       rtd->dai_link->name, ret);
 			goto machine_err;
 		}
 	}
@@ -187,6 +224,9 @@
 		goto config_err;
 	}
 
+	soc_pcm_apply_msb(substream, codec_dai);
+	soc_pcm_apply_msb(substream, cpu_dai);
+
 	/* Symmetry only applies if we've already got an active stream. */
 	if (cpu_dai->active) {
 		ret = soc_pcm_apply_symmetry(substream, cpu_dai);
@@ -267,9 +307,8 @@
 	/* are we waiting on this codec DAI stream */
 	if (codec_dai->pop_wait == 1) {
 		codec_dai->pop_wait = 0;
-		snd_soc_dapm_stream_event(rtd,
-			codec_dai->driver->playback.stream_name,
-			SND_SOC_DAPM_STREAM_STOP);
+		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
+					  codec_dai, SND_SOC_DAPM_STREAM_STOP);
 	}
 
 	mutex_unlock(&rtd->pcm_mutex);
@@ -329,12 +368,13 @@
 	cpu_dai->runtime = NULL;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		if (codec->ignore_pmdown_time ||
+		if (!rtd->pmdown_time || codec->ignore_pmdown_time ||
 		    rtd->dai_link->ignore_pmdown_time) {
 			/* powered down playback stream now */
 			snd_soc_dapm_stream_event(rtd,
-				codec_dai->driver->playback.stream_name,
-				SND_SOC_DAPM_STREAM_STOP);
+						  SNDRV_PCM_STREAM_PLAYBACK,
+						  codec_dai,
+						  SND_SOC_DAPM_STREAM_STOP);
 		} else {
 			/* start delayed pop wq here for playback streams */
 			codec_dai->pop_wait = 1;
@@ -343,9 +383,8 @@
 		}
 	} else {
 		/* capture streams can be powered down now */
-		snd_soc_dapm_stream_event(rtd,
-			codec_dai->driver->capture.stream_name,
-			SND_SOC_DAPM_STREAM_STOP);
+		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
+					  codec_dai, SND_SOC_DAPM_STREAM_STOP);
 	}
 
 	mutex_unlock(&rtd->pcm_mutex);
@@ -375,7 +414,7 @@
 	if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) {
 		ret = rtd->dai_link->ops->prepare(substream);
 		if (ret < 0) {
-			printk(KERN_ERR "asoc: machine prepare error\n");
+			pr_err("asoc: machine prepare error: %d\n", ret);
 			goto out;
 		}
 	}
@@ -383,7 +422,8 @@
 	if (platform->driver->ops && platform->driver->ops->prepare) {
 		ret = platform->driver->ops->prepare(substream);
 		if (ret < 0) {
-			printk(KERN_ERR "asoc: platform prepare error\n");
+			dev_err(platform->dev, "platform prepare error: %d\n",
+				ret);
 			goto out;
 		}
 	}
@@ -391,7 +431,8 @@
 	if (codec_dai->driver->ops->prepare) {
 		ret = codec_dai->driver->ops->prepare(substream, codec_dai);
 		if (ret < 0) {
-			printk(KERN_ERR "asoc: codec DAI prepare error\n");
+			dev_err(codec_dai->dev, "DAI prepare error: %d\n",
+				ret);
 			goto out;
 		}
 	}
@@ -399,7 +440,8 @@
 	if (cpu_dai->driver->ops->prepare) {
 		ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
 		if (ret < 0) {
-			printk(KERN_ERR "asoc: cpu DAI prepare error\n");
+			dev_err(cpu_dai->dev, "DAI prepare error: %d\n",
+				ret);
 			goto out;
 		}
 	}
@@ -411,14 +453,8 @@
 		cancel_delayed_work(&rtd->delayed_work);
 	}
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		snd_soc_dapm_stream_event(rtd,
-					  codec_dai->driver->playback.stream_name,
-					  SND_SOC_DAPM_STREAM_START);
-	else
-		snd_soc_dapm_stream_event(rtd,
-					  codec_dai->driver->capture.stream_name,
-					  SND_SOC_DAPM_STREAM_START);
+	snd_soc_dapm_stream_event(rtd, substream->stream, codec_dai,
+				  SND_SOC_DAPM_STREAM_START);
 
 	snd_soc_dai_digital_mute(codec_dai, 0);
 
@@ -446,7 +482,7 @@
 	if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
 		ret = rtd->dai_link->ops->hw_params(substream, params);
 		if (ret < 0) {
-			printk(KERN_ERR "asoc: machine hw_params failed\n");
+			pr_err("asoc: machine hw_params failed: %d\n", ret);
 			goto out;
 		}
 	}
@@ -454,8 +490,8 @@
 	if (codec_dai->driver->ops->hw_params) {
 		ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai);
 		if (ret < 0) {
-			printk(KERN_ERR "asoc: can't set codec %s hw params\n",
-				codec_dai->name);
+			dev_err(codec_dai->dev, "can't set %s hw params: %d\n",
+				codec_dai->name, ret);
 			goto codec_err;
 		}
 	}
@@ -463,8 +499,8 @@
 	if (cpu_dai->driver->ops->hw_params) {
 		ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai);
 		if (ret < 0) {
-			printk(KERN_ERR "asoc: interface %s hw params failed\n",
-				cpu_dai->name);
+			dev_err(cpu_dai->dev, "%s hw params failed: %d\n",
+				cpu_dai->name, ret);
 			goto interface_err;
 		}
 	}
@@ -472,8 +508,8 @@
 	if (platform->driver->ops && platform->driver->ops->hw_params) {
 		ret = platform->driver->ops->hw_params(substream, params);
 		if (ret < 0) {
-			printk(KERN_ERR "asoc: platform %s hw params failed\n",
-				platform->name);
+			dev_err(platform->dev, "%s hw params failed: %d\n",
+			       platform->name, ret);
 			goto platform_err;
 		}
 	}
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index 4220bb0..6005370 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -89,14 +89,32 @@
 	.ops = &dummy_dma_ops,
 };
 
+static struct snd_soc_codec_driver dummy_codec;
+static struct snd_soc_dai_driver dummy_dai = {
+	.name = "snd-soc-dummy-dai",
+};
+
 static __devinit int snd_soc_dummy_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_platform(&pdev->dev, &dummy_platform);
+	int ret;
+
+	ret = snd_soc_register_codec(&pdev->dev, &dummy_codec, &dummy_dai, 1);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_register_platform(&pdev->dev, &dummy_platform);
+	if (ret < 0) {
+		snd_soc_unregister_codec(&pdev->dev);
+		return ret;
+	}
+
+	return ret;
 }
 
 static __devexit int snd_soc_dummy_remove(struct platform_device *pdev)
 {
 	snd_soc_unregister_platform(&pdev->dev);
+	snd_soc_unregister_codec(&pdev->dev);
 
 	return 0;
 }
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
index 4a0e805..e45ccd8 100644
--- a/sound/soc/tegra/tegra_alc5632.c
+++ b/sound/soc/tegra/tegra_alc5632.c
@@ -18,6 +18,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/gpio.h>
+#include <linux/of_gpio.h>
 
 #include <sound/core.h>
 #include <sound/jack.h>
@@ -34,8 +35,13 @@
 
 #define DRV_NAME "tegra-alc5632"
 
+#define GPIO_HP_DET     BIT(0)
+
 struct tegra_alc5632 {
 	struct tegra_asoc_utils_data util_data;
+	struct platform_device *pcm_dev;
+	int gpio_requested;
+	int gpio_hp_det;
 };
 
 static int tegra_alc5632_asoc_hw_params(struct snd_pcm_substream *substream,
@@ -85,24 +91,18 @@
 	},
 };
 
+static struct snd_soc_jack_gpio tegra_alc5632_hp_jack_gpio = {
+	.name = "Headset detection",
+	.report = SND_JACK_HEADSET,
+	.debounce_time = 150,
+	.invert = 1,
+};
+
 static const struct snd_soc_dapm_widget tegra_alc5632_dapm_widgets[] = {
 	SND_SOC_DAPM_SPK("Int Spk", NULL),
 	SND_SOC_DAPM_HP("Headset Stereophone", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route tegra_alc5632_audio_map[] = {
-	/* Internal Speaker */
-	{"Int Spk", NULL, "SPKOUT"},
-	{"Int Spk", NULL, "SPKOUTN"},
-
-	/* Headset Mic */
-	{"MIC1", NULL, "MICBIAS1"},
-	{"MICBIAS1", NULL, "Headset Mic"},
-
-	/* Headset Stereophone */
-	{"Headset Stereophone", NULL, "HPR"},
-	{"Headset Stereophone", NULL, "HPL"},
+	SND_SOC_DAPM_MIC("Digital Mic", NULL),
 };
 
 static const struct snd_kcontrol_new tegra_alc5632_controls[] = {
@@ -113,6 +113,8 @@
 {
 	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct device_node *np = codec->card->dev->of_node;
+	struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(codec->card);
 
 	snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
 			 &tegra_alc5632_hs_jack);
@@ -120,6 +122,16 @@
 			ARRAY_SIZE(tegra_alc5632_hs_jack_pins),
 			tegra_alc5632_hs_jack_pins);
 
+	machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
+
+	if (gpio_is_valid(machine->gpio_hp_det)) {
+		tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det;
+		snd_soc_jack_add_gpios(&tegra_alc5632_hs_jack,
+						1,
+						&tegra_alc5632_hp_jack_gpio);
+		machine->gpio_requested |= GPIO_HP_DET;
+	}
+
 	snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
 
 	return 0;
@@ -128,9 +140,7 @@
 static struct snd_soc_dai_link tegra_alc5632_dai = {
 	.name = "ALC5632",
 	.stream_name = "ALC5632 PCM",
-	.codec_name = "alc5632.0-001e",
 	.platform_name = "tegra-pcm-audio",
-	.cpu_dai_name = "tegra-i2s.0",
 	.codec_dai_name = "alc5632-hifi",
 	.init = tegra_alc5632_asoc_init,
 	.ops = &tegra_alc5632_asoc_ops,
@@ -148,8 +158,6 @@
 	.num_controls = ARRAY_SIZE(tegra_alc5632_controls),
 	.dapm_widgets = tegra_alc5632_dapm_widgets,
 	.num_dapm_widgets = ARRAY_SIZE(tegra_alc5632_dapm_widgets),
-	.dapm_routes = tegra_alc5632_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(tegra_alc5632_audio_map),
 	.fully_routed = true,
 };
 
@@ -163,45 +171,111 @@
 			sizeof(struct tegra_alc5632), GFP_KERNEL);
 	if (!alc5632) {
 		dev_err(&pdev->dev, "Can't allocate tegra_alc5632\n");
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto err;
 	}
 
-	ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev);
-	if (ret)
-		return ret;
-
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
 	snd_soc_card_set_drvdata(card, alc5632);
 
+	alc5632->pcm_dev = ERR_PTR(-EINVAL);
+
+	if (!(pdev->dev.of_node)) {
+		dev_err(&pdev->dev, "Must be instantiated using device tree\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+	if (ret)
+		goto err;
+
+	ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+	if (ret)
+		goto err;
+
+	tegra_alc5632_dai.codec_of_node = of_parse_phandle(
+			pdev->dev.of_node, "nvidia,audio-codec", 0);
+
+	if (!tegra_alc5632_dai.codec_of_node) {
+		dev_err(&pdev->dev,
+			"Property 'nvidia,audio-codec' missing or invalid\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	tegra_alc5632_dai.cpu_dai_of_node = of_parse_phandle(
+			pdev->dev.of_node, "nvidia,i2s-controller", 0);
+	if (!tegra_alc5632_dai.cpu_dai_of_node) {
+		dev_err(&pdev->dev,
+		"Property 'nvidia,i2s-controller' missing or invalid\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	alc5632->pcm_dev = platform_device_register_simple(
+		"tegra-pcm-audio", -1, NULL, 0);
+	if (IS_ERR(alc5632->pcm_dev)) {
+		dev_err(&pdev->dev,
+			"Can't instantiate tegra-pcm-audio\n");
+		ret = PTR_ERR(alc5632->pcm_dev);
+		goto err;
+	}
+
+	ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev);
+	if (ret)
+		goto err_unregister;
+
 	ret = snd_soc_register_card(card);
 	if (ret) {
 		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
 			ret);
-		tegra_asoc_utils_fini(&alc5632->util_data);
-		return ret;
+		goto err_fini_utils;
 	}
 
 	return 0;
+
+err_fini_utils:
+	tegra_asoc_utils_fini(&alc5632->util_data);
+err_unregister:
+	if (!IS_ERR(alc5632->pcm_dev))
+		platform_device_unregister(alc5632->pcm_dev);
+err:
+	return ret;
 }
 
 static int __devexit tegra_alc5632_remove(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
-	struct tegra_alc5632 *alc5632 = snd_soc_card_get_drvdata(card);
+	struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card);
+
+	if (machine->gpio_requested & GPIO_HP_DET)
+		snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack,
+					1,
+					&tegra_alc5632_hp_jack_gpio);
+	machine->gpio_requested = 0;
 
 	snd_soc_unregister_card(card);
 
-	tegra_asoc_utils_fini(&alc5632->util_data);
+	tegra_asoc_utils_fini(&machine->util_data);
+	if (!IS_ERR(machine->pcm_dev))
+		platform_device_unregister(machine->pcm_dev);
 
 	return 0;
 }
 
+static const struct of_device_id tegra_alc5632_of_match[] __devinitconst = {
+	{ .compatible = "nvidia,tegra-audio-alc5632", },
+	{},
+};
+
 static struct platform_driver tegra_alc5632_driver = {
 	.driver = {
 		.name = DRV_NAME,
 		.owner = THIS_MODULE,
 		.pm = &snd_soc_pm_ops,
+		.of_match_table = tegra_alc5632_of_match,
 	},
 	.probe = tegra_alc5632_probe,
 	.remove = __devexit_p(tegra_alc5632_remove),
@@ -212,3 +286,4 @@
 MODULE_DESCRIPTION("Tegra+ALC5632 machine ASoC driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_alc5632_of_match);
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index c224315..8b44571 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -336,7 +336,7 @@
 	if (!card->dev->dma_mask)
 		card->dev->dma_mask = &tegra_dma_mask;
 	if (!card->dev->coherent_dma_mask)
-		card->dev->coherent_dma_mask = 0xffffffff;
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
 	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
 		ret = tegra_pcm_preallocate_dma_buffer(pcm,
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
index 2155461..b609d2c 100644
--- a/sound/soc/txx9/txx9aclc.c
+++ b/sound/soc/txx9/txx9aclc.c
@@ -132,7 +132,7 @@
 	sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf_dma_addr)),
 		    dmadata->frag_bytes, buf_dma_addr & (PAGE_SIZE - 1));
 	sg_dma_address(&sg) = buf_dma_addr;
-	desc = chan->device->device_prep_slave_sg(chan, &sg, 1,
+	desc = dmaengine_prep_slave_sg(chan, &sg, 1,
 		dmadata->substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
 		DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
 		DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c
index 4dd051b..c6500d0 100644
--- a/sound/spi/at73c213.c
+++ b/sound/spi/at73c213.c
@@ -1112,17 +1112,7 @@
 	.remove		= __devexit_p(snd_at73c213_remove),
 };
 
-static int __init at73c213_init(void)
-{
-	return spi_register_driver(&at73c213_driver);
-}
-module_init(at73c213_init);
-
-static void __exit at73c213_exit(void)
-{
-	spi_unregister_driver(&at73c213_driver);
-}
-module_exit(at73c213_exit);
+module_spi_driver(at73c213_driver);
 
 MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
 MODULE_DESCRIPTION("Sound driver for AT73C213 with Atmel SSC");
diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c
index 8af92e3..fc8cc82 100644
--- a/sound/usb/6fire/chip.c
+++ b/sound/usb/6fire/chip.c
@@ -5,7 +5,6 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
@@ -29,7 +28,7 @@
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Torsten Schenk <torsten.schenk@zoho.com>");
-MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver, version 0.3.0");
+MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver");
 MODULE_LICENSE("GPL v2");
 MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}");
 
diff --git a/sound/usb/6fire/chip.h b/sound/usb/6fire/chip.h
index d11e5cb..bde02d1 100644
--- a/sound/usb/6fire/chip.h
+++ b/sound/usb/6fire/chip.h
@@ -3,7 +3,6 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c
index c994daa..6c3d531 100644
--- a/sound/usb/6fire/comm.c
+++ b/sound/usb/6fire/comm.c
@@ -5,7 +5,6 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/sound/usb/6fire/comm.h b/sound/usb/6fire/comm.h
index edc5dc8..d2af0a5 100644
--- a/sound/usb/6fire/comm.h
+++ b/sound/usb/6fire/comm.h
@@ -3,7 +3,6 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/sound/usb/6fire/common.h b/sound/usb/6fire/common.h
index 7dbeb4a..b6eb03e 100644
--- a/sound/usb/6fire/common.h
+++ b/sound/usb/6fire/common.h
@@ -3,7 +3,6 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c
index ac828ef..07ed914 100644
--- a/sound/usb/6fire/control.c
+++ b/sound/usb/6fire/control.c
@@ -5,9 +5,12 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
  * Copyright:	(C) Torsten Schenk
  *
+ * Thanks to:
+ * - Holger Ruckdeschel: he found out how to control individual channel
+ *   volumes and introduced mute switch
+ *
  * 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
@@ -16,6 +19,7 @@
 
 #include <linux/interrupt.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 
 #include "control.h"
 #include "comm.h"
@@ -25,26 +29,6 @@
 static char *line_phono_texts[2] = { "Line", "Phono" };
 
 /*
- * calculated with $value\[i\] = 128 \cdot sqrt[3]{\frac{i}{128}}$
- * this is done because the linear values cause rapid degredation
- * of volume in the uppermost region.
- */
-static const u8 log_volume_table[128] = {
-	0x00, 0x19, 0x20, 0x24, 0x28, 0x2b, 0x2e, 0x30, 0x32, 0x34,
-	0x36, 0x38, 0x3a, 0x3b, 0x3d, 0x3e, 0x40, 0x41, 0x42, 0x43,
-	0x44, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
-	0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x53, 0x54, 0x55, 0x56,
-	0x56, 0x57, 0x58, 0x58, 0x59, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c,
-	0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62,
-	0x63, 0x63, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x68,
-	0x68, 0x69, 0x69, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c,
-	0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71,
-	0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75,
-	0x75, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79,
-	0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c,
-	0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f };
-
-/*
  * data that needs to be sent to device. sets up card internal stuff.
  * values dumped from windows driver and filtered by trial'n'error.
  */
@@ -59,7 +43,7 @@
 	{ 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 },
 	{ 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 },
 	{ 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 },
-	{ 0x12, 0x0d, 0x78 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 },
+	{ 0x12, 0x0d, 0x38 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 },
 	{ 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 },
 	{ 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 },
 	{ 0 } /* TERMINATING ENTRY */
@@ -70,20 +54,47 @@
 static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
 static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
 
+static DECLARE_TLV_DB_MINMAX(tlv_output, -9000, 0);
+static DECLARE_TLV_DB_MINMAX(tlv_input, -1500, 1500);
+
 enum {
 	DIGITAL_THRU_ONLY_SAMPLERATE = 3
 };
 
-static void usb6fire_control_master_vol_update(struct control_runtime *rt)
+static void usb6fire_control_output_vol_update(struct control_runtime *rt)
 {
 	struct comm_runtime *comm_rt = rt->chip->comm;
-	if (comm_rt) {
-		/* set volume */
-		comm_rt->write8(comm_rt, 0x12, 0x0f, 0x7f -
-				log_volume_table[rt->master_vol]);
-		 /* unmute */
-		comm_rt->write8(comm_rt, 0x12, 0x0e, 0x00);
-	}
+	int i;
+
+	if (comm_rt)
+		for (i = 0; i < 6; i++)
+			if (!(rt->ovol_updated & (1 << i))) {
+				comm_rt->write8(comm_rt, 0x12, 0x0f + i,
+					180 - rt->output_vol[i]);
+				rt->ovol_updated |= 1 << i;
+			}
+}
+
+static void usb6fire_control_output_mute_update(struct control_runtime *rt)
+{
+	struct comm_runtime *comm_rt = rt->chip->comm;
+
+	if (comm_rt)
+		comm_rt->write8(comm_rt, 0x12, 0x0e, ~rt->output_mute);
+}
+
+static void usb6fire_control_input_vol_update(struct control_runtime *rt)
+{
+	struct comm_runtime *comm_rt = rt->chip->comm;
+	int i;
+
+	if (comm_rt)
+		for (i = 0; i < 2; i++)
+			if (!(rt->ivol_updated & (1 << i))) {
+				comm_rt->write8(comm_rt, 0x12, 0x1c + i,
+					rt->input_vol[i] & 0x3f);
+				rt->ivol_updated |= 1 << i;
+			}
 }
 
 static void usb6fire_control_line_phono_update(struct control_runtime *rt)
@@ -165,34 +176,147 @@
 	return -EINVAL;
 }
 
-static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol,
+static int usb6fire_control_output_vol_info(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_info *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 1;
+	uinfo->count = 2;
 	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = 127;
+	uinfo->value.integer.max = 180;
 	return 0;
 }
 
-static int usb6fire_control_master_vol_put(struct snd_kcontrol *kcontrol,
+static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+	unsigned int ch = kcontrol->private_value;
+	int changed = 0;
+
+	if (ch > 4) {
+		snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
+		return -EINVAL;
+	}
+
+	if (rt->output_vol[ch] != ucontrol->value.integer.value[0]) {
+		rt->output_vol[ch] = ucontrol->value.integer.value[0];
+		rt->ovol_updated &= ~(1 << ch);
+		changed = 1;
+	}
+	if (rt->output_vol[ch + 1] != ucontrol->value.integer.value[1]) {
+		rt->output_vol[ch + 1] = ucontrol->value.integer.value[1];
+		rt->ovol_updated &= ~(2 << ch);
+		changed = 1;
+	}
+
+	if (changed)
+		usb6fire_control_output_vol_update(rt);
+
+	return changed;
+}
+
+static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+	unsigned int ch = kcontrol->private_value;
+
+	if (ch > 4) {
+		snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
+		return -EINVAL;
+	}
+
+	ucontrol->value.integer.value[0] = rt->output_vol[ch];
+	ucontrol->value.integer.value[1] = rt->output_vol[ch + 1];
+	return 0;
+}
+
+static int usb6fire_control_output_mute_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+	unsigned int ch = kcontrol->private_value;
+	u8 old = rt->output_mute;
+	u8 value = 0;
+
+	if (ch > 4) {
+		snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
+		return -EINVAL;
+	}
+
+	rt->output_mute &= ~(3 << ch);
+	if (ucontrol->value.integer.value[0])
+		value |= 1;
+	if (ucontrol->value.integer.value[1])
+		value |= 2;
+	rt->output_mute |= value << ch;
+
+	if (rt->output_mute != old)
+		usb6fire_control_output_mute_update(rt);
+
+	return rt->output_mute != old;
+}
+
+static int usb6fire_control_output_mute_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+	unsigned int ch = kcontrol->private_value;
+	u8 value = rt->output_mute >> ch;
+
+	if (ch > 4) {
+		snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
+		return -EINVAL;
+	}
+
+	ucontrol->value.integer.value[0] = 1 & value;
+	value >>= 1;
+	ucontrol->value.integer.value[1] = 1 & value;
+
+	return 0;
+}
+
+static int usb6fire_control_input_vol_info(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 30;
+	return 0;
+}
+
+static int usb6fire_control_input_vol_put(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_value *ucontrol)
 {
 	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 	int changed = 0;
-	if (rt->master_vol != ucontrol->value.integer.value[0]) {
-		rt->master_vol = ucontrol->value.integer.value[0];
-		usb6fire_control_master_vol_update(rt);
+
+	if (rt->input_vol[0] != ucontrol->value.integer.value[0]) {
+		rt->input_vol[0] = ucontrol->value.integer.value[0] - 15;
+		rt->ivol_updated &= ~(1 << 0);
 		changed = 1;
 	}
+	if (rt->input_vol[1] != ucontrol->value.integer.value[1]) {
+		rt->input_vol[1] = ucontrol->value.integer.value[1] - 15;
+		rt->ivol_updated &= ~(1 << 1);
+		changed = 1;
+	}
+
+	if (changed)
+		usb6fire_control_input_vol_update(rt);
+
 	return changed;
 }
 
-static int usb6fire_control_master_vol_get(struct snd_kcontrol *kcontrol,
+static int usb6fire_control_input_vol_get(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_value *ucontrol)
 {
 	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
-	ucontrol->value.integer.value[0] = rt->master_vol;
+
+	ucontrol->value.integer.value[0] = rt->input_vol[0] + 15;
+	ucontrol->value.integer.value[1] = rt->input_vol[1] + 15;
+
 	return 0;
 }
 
@@ -287,18 +411,83 @@
 	return 0;
 }
 
-static struct __devinitdata snd_kcontrol_new elements[] = {
+static struct __devinitdata snd_kcontrol_new vol_elements[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Volume",
+		.name = "Analog Playback Volume",
 		.index = 0,
-		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-		.info = usb6fire_control_master_vol_info,
-		.get = usb6fire_control_master_vol_get,
-		.put = usb6fire_control_master_vol_put
+		.private_value = 0,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+		.info = usb6fire_control_output_vol_info,
+		.get = usb6fire_control_output_vol_get,
+		.put = usb6fire_control_output_vol_put,
+		.tlv = { .p = tlv_output }
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Analog Playback Volume",
+		.index = 1,
+		.private_value = 2,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+		.info = usb6fire_control_output_vol_info,
+		.get = usb6fire_control_output_vol_get,
+		.put = usb6fire_control_output_vol_put,
+		.tlv = { .p = tlv_output }
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Analog Playback Volume",
+		.index = 2,
+		.private_value = 4,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+		.info = usb6fire_control_output_vol_info,
+		.get = usb6fire_control_output_vol_get,
+		.put = usb6fire_control_output_vol_put,
+		.tlv = { .p = tlv_output }
+	},
+	{}
+};
+
+static struct __devinitdata snd_kcontrol_new mute_elements[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Analog Playback Switch",
+		.index = 0,
+		.private_value = 0,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = snd_ctl_boolean_stereo_info,
+		.get = usb6fire_control_output_mute_get,
+		.put = usb6fire_control_output_mute_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Analog Playback Switch",
+		.index = 1,
+		.private_value = 2,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = snd_ctl_boolean_stereo_info,
+		.get = usb6fire_control_output_mute_get,
+		.put = usb6fire_control_output_mute_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Analog Playback Switch",
+		.index = 2,
+		.private_value = 4,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = snd_ctl_boolean_stereo_info,
+		.get = usb6fire_control_output_mute_get,
+		.put = usb6fire_control_output_mute_put,
+	},
+	{}
+};
+
+static struct __devinitdata snd_kcontrol_new elements[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Line/Phono Capture Route",
 		.index = 0,
 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
@@ -324,9 +513,54 @@
 		.get = usb6fire_control_digital_thru_get,
 		.put = usb6fire_control_digital_thru_put
 	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Analog Capture Volume",
+		.index = 0,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+		.info = usb6fire_control_input_vol_info,
+		.get = usb6fire_control_input_vol_get,
+		.put = usb6fire_control_input_vol_put,
+		.tlv = { .p = tlv_input }
+	},
 	{}
 };
 
+static int usb6fire_control_add_virtual(
+	struct control_runtime *rt,
+	struct snd_card *card,
+	char *name,
+	struct snd_kcontrol_new *elems)
+{
+	int ret;
+	int i;
+	struct snd_kcontrol *vmaster =
+		snd_ctl_make_virtual_master(name, tlv_output);
+	struct snd_kcontrol *control;
+
+	if (!vmaster)
+		return -ENOMEM;
+	ret = snd_ctl_add(card, vmaster);
+	if (ret < 0)
+		return ret;
+
+	i = 0;
+	while (elems[i].name) {
+		control = snd_ctl_new1(&elems[i], rt);
+		if (!control)
+			return -ENOMEM;
+		ret = snd_ctl_add(card, control);
+		if (ret < 0)
+			return ret;
+		ret = snd_ctl_add_slave(vmaster, control);
+		if (ret < 0)
+			return ret;
+		i++;
+	}
+	return 0;
+}
+
 int __devinit usb6fire_control_init(struct sfire_chip *chip)
 {
 	int i;
@@ -352,9 +586,26 @@
 
 	usb6fire_control_opt_coax_update(rt);
 	usb6fire_control_line_phono_update(rt);
-	usb6fire_control_master_vol_update(rt);
+	usb6fire_control_output_vol_update(rt);
+	usb6fire_control_output_mute_update(rt);
+	usb6fire_control_input_vol_update(rt);
 	usb6fire_control_streaming_update(rt);
 
+	ret = usb6fire_control_add_virtual(rt, chip->card,
+		"Master Playback Volume", vol_elements);
+	if (ret) {
+		snd_printk(KERN_ERR PREFIX "cannot add control.\n");
+		kfree(rt);
+		return ret;
+	}
+	ret = usb6fire_control_add_virtual(rt, chip->card,
+		"Master Playback Switch", mute_elements);
+	if (ret) {
+		snd_printk(KERN_ERR PREFIX "cannot add control.\n");
+		kfree(rt);
+		return ret;
+	}
+
 	i = 0;
 	while (elements[i].name) {
 		ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt));
diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h
index 8f5aeea..9a596d9 100644
--- a/sound/usb/6fire/control.h
+++ b/sound/usb/6fire/control.h
@@ -3,7 +3,6 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
@@ -44,7 +43,11 @@
 	bool line_phono_switch;
 	bool digital_thru_switch;
 	bool usb_streaming;
-	u8 master_vol;
+	u8 output_vol[6];
+	u8 ovol_updated;
+	u8 output_mute;
+	s8 input_vol[2];
+	u8 ivol_updated;
 };
 
 int __devinit usb6fire_control_init(struct sfire_chip *chip);
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
index 3b5f517..6f9715a 100644
--- a/sound/usb/6fire/firmware.c
+++ b/sound/usb/6fire/firmware.c
@@ -5,7 +5,6 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c
index 13f4509..f0e5179 100644
--- a/sound/usb/6fire/midi.c
+++ b/sound/usb/6fire/midi.c
@@ -5,7 +5,6 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/sound/usb/6fire/midi.h b/sound/usb/6fire/midi.h
index 97a7bf66..5114ecc 100644
--- a/sound/usb/6fire/midi.h
+++ b/sound/usb/6fire/midi.h
@@ -3,7 +3,6 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
index d144cdb..c97d05f 100644
--- a/sound/usb/6fire/pcm.c
+++ b/sound/usb/6fire/pcm.c
@@ -5,7 +5,6 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/sound/usb/6fire/pcm.h b/sound/usb/6fire/pcm.h
index 2bee813..3104301 100644
--- a/sound/usb/6fire/pcm.h
+++ b/sound/usb/6fire/pcm.h
@@ -3,7 +3,6 @@
  *
  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
  * Created:	Jan 01, 2011
- * Version:	0.3.0
  * Copyright:	(C) Torsten Schenk
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index 3efc21c..ff77b28 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -106,6 +106,7 @@
         select BITREVERSE
         select SND_RAWMIDI
         select SND_PCM
+        select SND_VMASTER
         help
           Say Y here to include support for TerraTec 6fire DMX USB interface.
 
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 0220b0f..0eed611 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -695,6 +695,7 @@
 				  struct snd_usb_substream *subs)
 {
 	struct audioformat *fp;
+	int *rate_list;
 	int count = 0, needs_knot = 0;
 	int err;
 
@@ -708,7 +709,8 @@
 	if (!needs_knot)
 		return 0;
 
-	subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL);
+	subs->rate_list.list = rate_list =
+		kmalloc(sizeof(int) * count, GFP_KERNEL);
 	if (!subs->rate_list.list)
 		return -ENOMEM;
 	subs->rate_list.count = count;
@@ -717,7 +719,7 @@
 	list_for_each_entry(fp, &subs->fmt_list, list) {
 		int i;
 		for (i = 0; i < fp->nr_rates; i++)
-			subs->rate_list.list[count++] = fp->rate_table[i];
+			rate_list[count++] = fp->rate_table[i];
 	}
 	err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 					 &subs->rate_list);
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index 6ffb371..520ef96 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -80,7 +80,7 @@
 		cp = (unsigned char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
 		if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
 			snd_printk(KERN_ERR "active frame status %i. "
-				   "Most propably some hardware problem.\n",
+				   "Most probably some hardware problem.\n",
 				   urb->iso_frame_desc[i].status);
 			return urb->iso_frame_desc[i].status;
 		}
@@ -300,7 +300,7 @@
 {
 	snd_printk(KERN_ERR
 "Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n"
-"Most propably some urb of usb-frame %i is still missing.\n"
+"Most probably some urb of usb-frame %i is still missing.\n"
 "Cause could be too long delays in usb-hcd interrupt handling.\n",
 		   usb_get_current_frame_number(usX2Y->dev),
 		   subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index a51340f..8e40b6e 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -74,7 +74,7 @@
 	}
 	for (i = 0; i < nr_of_packs(); i++) {
 		if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
-			snd_printk(KERN_ERR "activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status);
+			snd_printk(KERN_ERR "active frame status %i. Most probably some hardware problem.\n", urb->iso_frame_desc[i].status);
 			return urb->iso_frame_desc[i].status;
 		}
 		lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride;
diff --git a/tools/include/tools/be_byteshift.h b/tools/include/tools/be_byteshift.h
new file mode 100644
index 0000000..f4912e2
--- /dev/null
+++ b/tools/include/tools/be_byteshift.h
@@ -0,0 +1,70 @@
+#ifndef _TOOLS_BE_BYTESHIFT_H
+#define _TOOLS_BE_BYTESHIFT_H
+
+#include <linux/types.h>
+
+static inline __u16 __get_unaligned_be16(const __u8 *p)
+{
+	return p[0] << 8 | p[1];
+}
+
+static inline __u32 __get_unaligned_be32(const __u8 *p)
+{
+	return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
+}
+
+static inline __u64 __get_unaligned_be64(const __u8 *p)
+{
+	return (__u64)__get_unaligned_be32(p) << 32 |
+	       __get_unaligned_be32(p + 4);
+}
+
+static inline void __put_unaligned_be16(__u16 val, __u8 *p)
+{
+	*p++ = val >> 8;
+	*p++ = val;
+}
+
+static inline void __put_unaligned_be32(__u32 val, __u8 *p)
+{
+	__put_unaligned_be16(val >> 16, p);
+	__put_unaligned_be16(val, p + 2);
+}
+
+static inline void __put_unaligned_be64(__u64 val, __u8 *p)
+{
+	__put_unaligned_be32(val >> 32, p);
+	__put_unaligned_be32(val, p + 4);
+}
+
+static inline __u16 get_unaligned_be16(const void *p)
+{
+	return __get_unaligned_be16((const __u8 *)p);
+}
+
+static inline __u32 get_unaligned_be32(const void *p)
+{
+	return __get_unaligned_be32((const __u8 *)p);
+}
+
+static inline __u64 get_unaligned_be64(const void *p)
+{
+	return __get_unaligned_be64((const __u8 *)p);
+}
+
+static inline void put_unaligned_be16(__u16 val, void *p)
+{
+	__put_unaligned_be16(val, p);
+}
+
+static inline void put_unaligned_be32(__u32 val, void *p)
+{
+	__put_unaligned_be32(val, p);
+}
+
+static inline void put_unaligned_be64(__u64 val, void *p)
+{
+	__put_unaligned_be64(val, p);
+}
+
+#endif /* _TOOLS_BE_BYTESHIFT_H */
diff --git a/tools/include/tools/le_byteshift.h b/tools/include/tools/le_byteshift.h
new file mode 100644
index 0000000..c99d45a
--- /dev/null
+++ b/tools/include/tools/le_byteshift.h
@@ -0,0 +1,70 @@
+#ifndef _TOOLS_LE_BYTESHIFT_H
+#define _TOOLS_LE_BYTESHIFT_H
+
+#include <linux/types.h>
+
+static inline __u16 __get_unaligned_le16(const __u8 *p)
+{
+	return p[0] | p[1] << 8;
+}
+
+static inline __u32 __get_unaligned_le32(const __u8 *p)
+{
+	return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
+}
+
+static inline __u64 __get_unaligned_le64(const __u8 *p)
+{
+	return (__u64)__get_unaligned_le32(p + 4) << 32 |
+	       __get_unaligned_le32(p);
+}
+
+static inline void __put_unaligned_le16(__u16 val, __u8 *p)
+{
+	*p++ = val;
+	*p++ = val >> 8;
+}
+
+static inline void __put_unaligned_le32(__u32 val, __u8 *p)
+{
+	__put_unaligned_le16(val >> 16, p + 2);
+	__put_unaligned_le16(val, p);
+}
+
+static inline void __put_unaligned_le64(__u64 val, __u8 *p)
+{
+	__put_unaligned_le32(val >> 32, p + 4);
+	__put_unaligned_le32(val, p);
+}
+
+static inline __u16 get_unaligned_le16(const void *p)
+{
+	return __get_unaligned_le16((const __u8 *)p);
+}
+
+static inline __u32 get_unaligned_le32(const void *p)
+{
+	return __get_unaligned_le32((const __u8 *)p);
+}
+
+static inline __u64 get_unaligned_le64(const void *p)
+{
+	return __get_unaligned_le64((const __u8 *)p);
+}
+
+static inline void put_unaligned_le16(__u16 val, void *p)
+{
+	__put_unaligned_le16(val, p);
+}
+
+static inline void put_unaligned_le32(__u32 val, void *p)
+{
+	__put_unaligned_le32(val, p);
+}
+
+static inline void put_unaligned_le64(__u64 val, void *p)
+{
+	__put_unaligned_le64(val, p);
+}
+
+#endif /* _TOOLS_LE_BYTESHIFT_H */
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 87feeee..2d89f02 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -48,6 +48,9 @@
 	Only consider these symbols. CSV that understands
 	file://filename entries.
 
+--symbol-filter=::
+	Only show symbols that match (partially) with this filter.
+
 -U::
 --hide-unresolved::
         Only display entries resolved to a symbol.
@@ -110,6 +113,8 @@
 	requires a tty, if one is not present, as when piping to other
 	commands, the stdio interface is used.
 
+--gtk:: Use the GTK2 interface.
+
 -k::
 --vmlinux=<file>::
         vmlinux pathname
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 74fd7f8..820371f 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -182,7 +182,7 @@
 
 ### --- END CONFIGURATION SECTION ---
 
-BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 BASIC_LDFLAGS =
 
 # Guard against environment variables
@@ -234,6 +234,25 @@
 
 export PERL_PATH
 
+FLEX = $(CROSS_COMPILE)flex
+BISON= $(CROSS_COMPILE)bison
+
+event-parser:
+	$(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c
+	$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
+
+$(OUTPUT)util/parse-events-flex.c: event-parser
+$(OUTPUT)util/parse-events-bison.c: event-parser
+
+pmu-parser:
+	$(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c
+	$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
+
+$(OUTPUT)util/pmu-flex.c: pmu-parser
+$(OUTPUT)util/pmu-bison.c: pmu-parser
+
+$(OUTPUT)util/parse-events.o: event-parser pmu-parser
+
 LIB_FILE=$(OUTPUT)libperf.a
 
 LIB_H += ../../include/linux/perf_event.h
@@ -249,7 +268,7 @@
 LIB_H += util/include/linux/ctype.h
 LIB_H += util/include/linux/kernel.h
 LIB_H += util/include/linux/list.h
-LIB_H += util/include/linux/module.h
+LIB_H += util/include/linux/export.h
 LIB_H += util/include/linux/poison.h
 LIB_H += util/include/linux/prefetch.h
 LIB_H += util/include/linux/rbtree.h
@@ -276,6 +295,7 @@
 LIB_H += util/debug.h
 LIB_H += util/debugfs.h
 LIB_H += util/sysfs.h
+LIB_H += util/pmu.h
 LIB_H += util/event.h
 LIB_H += util/evsel.h
 LIB_H += util/evlist.h
@@ -323,6 +343,7 @@
 LIB_OBJS += $(OUTPUT)util/ctype.o
 LIB_OBJS += $(OUTPUT)util/debugfs.o
 LIB_OBJS += $(OUTPUT)util/sysfs.o
+LIB_OBJS += $(OUTPUT)util/pmu.o
 LIB_OBJS += $(OUTPUT)util/environment.o
 LIB_OBJS += $(OUTPUT)util/event.o
 LIB_OBJS += $(OUTPUT)util/evlist.o
@@ -359,6 +380,10 @@
 LIB_OBJS += $(OUTPUT)util/thread.o
 LIB_OBJS += $(OUTPUT)util/thread_map.o
 LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
+LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
+LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
+LIB_OBJS += $(OUTPUT)util/pmu-flex.o
+LIB_OBJS += $(OUTPUT)util/pmu-bison.o
 LIB_OBJS += $(OUTPUT)util/trace-event-read.o
 LIB_OBJS += $(OUTPUT)util/trace-event-info.o
 LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
@@ -501,6 +526,20 @@
 	endif
 endif
 
+ifdef NO_GTK2
+	BASIC_CFLAGS += -DNO_GTK2
+else
+	FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0)
+	ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2)),y)
+		msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
+		BASIC_CFLAGS += -DNO_GTK2_SUPPORT
+	else
+		BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
+		EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
+		LIB_OBJS += $(OUTPUT)util/gtk/browser.o
+	endif
+endif
+
 ifdef NO_LIBPERL
 	BASIC_CFLAGS += -DNO_LIBPERL
 else
@@ -647,6 +686,8 @@
 	QUIET_LINK     = @echo '   ' LINK $@;
 	QUIET_MKDIR    = @echo '   ' MKDIR $@;
 	QUIET_GEN      = @echo '   ' GEN $@;
+	QUIET_FLEX     = @echo '   ' FLEX $@;
+	QUIET_BISON    = @echo '   ' BISON $@;
 endif
 endif
 
@@ -727,12 +768,28 @@
 	$(SCRIPTS) \
 	: $(OUTPUT)PERF-VERSION-FILE
 
+.SUFFIXES:
+.SUFFIXES: .o .c .S .s
+
+# These two need to be here so that when O= is not used they take precedence
+# over the general rule for .o
+
+$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
+	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Iutil/ -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
+
+$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
+	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -Iutil/ -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
+
 $(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
+$(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS
+	$(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $<
 $(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
-	$(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
+	$(QUIET_CC)$(CC) -o $@ -S $(ALL_CFLAGS) $<
 $(OUTPUT)%.o: %.S
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
+$(OUTPUT)%.s: %.S
+	$(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $<
 
 $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
@@ -795,6 +852,8 @@
 	@echo '  html		- make html documentation'
 	@echo '  info		- make GNU info documentation (access with info <foo>)'
 	@echo '  pdf		- make pdf documentation'
+	@echo '  event-parser	- make event parser code'
+	@echo '  pmu-parser	- make pmu format parser code'
 	@echo '  TAGS		- use etags to make tag information for source browsing'
 	@echo '  tags		- use ctags to make tag information for source browsing'
 	@echo '  cscope	- use cscope to make interactive browsing database'
@@ -931,6 +990,7 @@
 	$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
 	$(MAKE) -C Documentation/ clean
 	$(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
+	$(RM) $(OUTPUT)util/*-{bison,flex}*
 	$(python-clean)
 
 .PHONY: all install clean strip
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 4f19513..d29d350 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -24,6 +24,11 @@
 static bool  force;
 static bool show_displacement;
 
+struct perf_diff {
+	struct perf_tool tool;
+	struct perf_session *session;
+};
+
 static int hists__add_entry(struct hists *self,
 			    struct addr_location *al, u64 period)
 {
@@ -32,12 +37,14 @@
 	return -ENOMEM;
 }
 
-static int diff__process_sample_event(struct perf_tool *tool __used,
+static int diff__process_sample_event(struct perf_tool *tool,
 				      union perf_event *event,
 				      struct perf_sample *sample,
 				      struct perf_evsel *evsel __used,
 				      struct machine *machine)
 {
+	struct perf_diff *_diff = container_of(tool, struct perf_diff, tool);
+	struct perf_session *session = _diff->session;
 	struct addr_location al;
 
 	if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) {
@@ -49,24 +56,26 @@
 	if (al.filtered || al.sym == NULL)
 		return 0;
 
-	if (hists__add_entry(&evsel->hists, &al, sample->period)) {
+	if (hists__add_entry(&session->hists, &al, sample->period)) {
 		pr_warning("problem incrementing symbol period, skipping event\n");
 		return -1;
 	}
 
-	evsel->hists.stats.total_period += sample->period;
+	session->hists.stats.total_period += sample->period;
 	return 0;
 }
 
-static struct perf_tool perf_diff = {
-	.sample	= diff__process_sample_event,
-	.mmap	= perf_event__process_mmap,
-	.comm	= perf_event__process_comm,
-	.exit	= perf_event__process_task,
-	.fork	= perf_event__process_task,
-	.lost	= perf_event__process_lost,
-	.ordered_samples = true,
-	.ordering_requires_timestamps = true,
+static struct perf_diff diff = {
+	.tool = {
+		.sample	= diff__process_sample_event,
+		.mmap	= perf_event__process_mmap,
+		.comm	= perf_event__process_comm,
+		.exit	= perf_event__process_task,
+		.fork	= perf_event__process_task,
+		.lost	= perf_event__process_lost,
+		.ordered_samples = true,
+		.ordering_requires_timestamps = true,
+	},
 };
 
 static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
@@ -107,12 +116,6 @@
 	self->entries = tmp;
 }
 
-static void hists__set_positions(struct hists *self)
-{
-	hists__output_resort(self);
-	hists__resort_entries(self);
-}
-
 static struct hist_entry *hists__find_entry(struct hists *self,
 					    struct hist_entry *he)
 {
@@ -146,30 +149,37 @@
 static int __cmd_diff(void)
 {
 	int ret, i;
+#define older (session[0])
+#define newer (session[1])
 	struct perf_session *session[2];
 
-	session[0] = perf_session__new(input_old, O_RDONLY, force, false, &perf_diff);
-	session[1] = perf_session__new(input_new, O_RDONLY, force, false, &perf_diff);
+	older = perf_session__new(input_old, O_RDONLY, force, false,
+				  &diff.tool);
+	newer = perf_session__new(input_new, O_RDONLY, force, false,
+				  &diff.tool);
 	if (session[0] == NULL || session[1] == NULL)
 		return -ENOMEM;
 
 	for (i = 0; i < 2; ++i) {
-		ret = perf_session__process_events(session[i], &perf_diff);
+		diff.session = session[i];
+		ret = perf_session__process_events(session[i], &diff.tool);
 		if (ret)
 			goto out_delete;
+		hists__output_resort(&session[i]->hists);
 	}
 
-	hists__output_resort(&session[1]->hists);
 	if (show_displacement)
-		hists__set_positions(&session[0]->hists);
+		hists__resort_entries(&older->hists);
 
-	hists__match(&session[0]->hists, &session[1]->hists);
-	hists__fprintf(&session[1]->hists, &session[0]->hists,
+	hists__match(&older->hists, &newer->hists);
+	hists__fprintf(&newer->hists, &older->hists,
 		       show_displacement, true, 0, 0, stdout);
 out_delete:
 	for (i = 0; i < 2; ++i)
 		perf_session__delete(session[i]);
 	return ret;
+#undef older
+#undef newer
 }
 
 static const char * const diff_usage[] = {
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 8e91c6e..2e31743 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -40,7 +40,7 @@
 	struct perf_tool	tool;
 	struct perf_session	*session;
 	char const		*input_name;
-	bool			force, use_tui, use_stdio;
+	bool			force, use_tui, use_gtk, use_stdio;
 	bool			hide_unresolved;
 	bool			dont_use_callchains;
 	bool			show_full_info;
@@ -50,6 +50,7 @@
 	const char		*pretty_printing_style;
 	symbol_filter_t		annotate_init;
 	const char		*cpu_list;
+	const char		*symbol_filter_str;
 	DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
 };
 
@@ -400,6 +401,9 @@
 	list_for_each_entry(pos, &session->evlist->entries, node) {
 		struct hists *hists = &pos->hists;
 
+		if (pos->idx == 0)
+			hists->symbol_filter_str = rep->symbol_filter_str;
+
 		hists__collapse_resort(hists);
 		hists__output_resort(hists);
 		nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
@@ -411,8 +415,13 @@
 	}
 
 	if (use_browser > 0) {
-		perf_evlist__tui_browse_hists(session->evlist, help,
-					      NULL, NULL, 0);
+		if (use_browser == 1) {
+			perf_evlist__tui_browse_hists(session->evlist, help,
+						      NULL, NULL, 0);
+		} else if (use_browser == 2) {
+			perf_evlist__gtk_browse_hists(session->evlist, help,
+						      NULL, NULL, 0);
+		}
 	} else
 		perf_evlist__tty_browse_hists(session->evlist, rep, help);
 
@@ -569,6 +578,7 @@
 	OPT_STRING(0, "pretty", &report.pretty_printing_style, "key",
 		   "pretty printing style key: normal raw"),
 	OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"),
+	OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"),
 	OPT_BOOLEAN(0, "stdio", &report.use_stdio,
 		    "Use the stdio interface"),
 	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
@@ -591,6 +601,8 @@
 		   "only consider symbols in these comms"),
 	OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
 		   "only consider these symbols"),
+	OPT_STRING(0, "symbol-filter", &report.symbol_filter_str, "filter",
+		   "only show symbols that (partially) match with this filter"),
 	OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
 		   "width[,width...]",
 		   "don't try to adjust column width, use these fixed values"),
@@ -624,6 +636,8 @@
 		use_browser = 0;
 	else if (report.use_tui)
 		use_browser = 1;
+	else if (report.use_gtk)
+		use_browser = 2;
 
 	if (report.inverted_callchain)
 		callchain_param.order = ORDER_CALLER;
@@ -660,7 +674,10 @@
 	}
 
 	if (strcmp(report.input_name, "-") != 0) {
-		setup_browser(true);
+		if (report.use_gtk)
+			perf_gtk_setup_browser(argc, argv, true);
+		else
+			setup_browser(true);
 	} else {
 		use_browser = 0;
 	}
@@ -709,11 +726,16 @@
 	} else
 		symbol_conf.exclude_other = false;
 
-	/*
-	 * Any (unrecognized) arguments left?
-	 */
-	if (argc)
-		usage_with_options(report_usage, options);
+	if (argc) {
+		/*
+		 * Special case: if there's an argument left then assume that
+		 * it's a symbol filter:
+		 */
+		if (argc > 1)
+			usage_with_options(report_usage, options);
+
+		report.symbol_filter_str = argv[0];
+	}
 
 	sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
 
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index ea40e4e..c941bb6 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -296,7 +296,7 @@
 	if (system_wide)
 		return perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
 						group, group_fd);
-	if (!target_pid && !target_tid) {
+	if (!target_pid && !target_tid && (!group || evsel == first)) {
 		attr->disabled = 1;
 		attr->enable_on_exec = 1;
 	}
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 3e087ce..1c5b980 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -13,6 +13,7 @@
 #include "util/parse-events.h"
 #include "util/symbol.h"
 #include "util/thread_map.h"
+#include "util/pmu.h"
 #include "../../include/linux/hw_breakpoint.h"
 
 #include <sys/mman.h>
@@ -650,7 +651,7 @@
 
 	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
-	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
 	return 0;
 }
 
@@ -677,6 +678,24 @@
 	return 0;
 }
 
+static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	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 period",
+			100000 == evsel->attr.sample_period);
+	TEST_ASSERT_VAL("wrong config1",
+			0 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config2",
+			1 == evsel->attr.config2);
+	return 0;
+}
+
 static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
 {
 	struct perf_evsel *evsel = list_entry(evlist->entries.next,
@@ -858,6 +877,115 @@
 	return test__checkevent_genhw(evlist);
 }
 
+static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	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);
+
+	return test__checkevent_breakpoint(evlist);
+}
+
+static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	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);
+
+	return test__checkevent_breakpoint_x(evlist);
+}
+
+static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	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);
+
+	return test__checkevent_breakpoint_r(evlist);
+}
+
+static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	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);
+
+	return test__checkevent_breakpoint_w(evlist);
+}
+
+static int test__checkevent_pmu(struct perf_evlist *evlist)
+{
+
+	struct perf_evsel *evsel = list_entry(evlist->entries.next,
+					      struct perf_evsel, node);
+
+	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",    10 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong config1",    1 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config2",    3 == evsel->attr.config2);
+	TEST_ASSERT_VAL("wrong period",  1000 == evsel->attr.sample_period);
+
+	return 0;
+}
+
+static int test__checkevent_list(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+
+	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
+
+	/* r1 */
+	evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
+	TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
+	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);
+
+	/* syscalls:sys_enter_open:k */
+	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong sample_type",
+		(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
+		evsel->attr.sample_type);
+	TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
+	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);
+
+	/* 1:1:hp */
+	evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+	TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config", 1 == 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 precise_ip", evsel->attr.precise_ip);
+
+	return 0;
+}
+
 static struct test__event_st {
 	const char *name;
 	__u32 type;
@@ -872,7 +1000,7 @@
 		.check = test__checkevent_tracepoint_multi,
 	},
 	{
-		.name  = "r1",
+		.name  = "r1a",
 		.check = test__checkevent_raw,
 	},
 	{
@@ -884,6 +1012,10 @@
 		.check = test__checkevent_symbolic_name,
 	},
 	{
+		.name  = "cycles/period=100000,config2/",
+		.check = test__checkevent_symbolic_name_config,
+	},
+	{
 		.name  = "faults",
 		.check = test__checkevent_symbolic_alias,
 	},
@@ -916,7 +1048,7 @@
 		.check = test__checkevent_tracepoint_multi_modifier,
 	},
 	{
-		.name  = "r1:kp",
+		.name  = "r1a:kp",
 		.check = test__checkevent_raw_modifier,
 	},
 	{
@@ -935,6 +1067,30 @@
 		.name  = "L1-dcache-load-miss:kp",
 		.check = test__checkevent_genhw_modifier,
 	},
+	{
+		.name  = "mem:0:u",
+		.check = test__checkevent_breakpoint_modifier,
+	},
+	{
+		.name  = "mem:0:x:k",
+		.check = test__checkevent_breakpoint_x_modifier,
+	},
+	{
+		.name  = "mem:0:r:hp",
+		.check = test__checkevent_breakpoint_r_modifier,
+	},
+	{
+		.name  = "mem:0:w:up",
+		.check = test__checkevent_breakpoint_w_modifier,
+	},
+	{
+		.name  = "cpu/config=10,config1,config2=3,period=1000/u",
+		.check = test__checkevent_pmu,
+	},
+	{
+		.name  = "r1,syscalls:sys_enter_open:k,1:1:hp",
+		.check = test__checkevent_list,
+	},
 };
 
 #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
@@ -960,10 +1116,9 @@
 		}
 
 		ret = e->check(evlist);
+		perf_evlist__delete(evlist);
 		if (ret)
 			break;
-
-		perf_evlist__delete(evlist);
 	}
 
 	return ret;
@@ -1462,6 +1617,11 @@
 
 #endif
 
+static int test__perf_pmu(void)
+{
+	return perf_pmu__test();
+}
+
 static struct test {
 	const char *desc;
 	int (*func)(void);
@@ -1497,6 +1657,10 @@
 		.func = test__PERF_RECORD,
 	},
 	{
+		.desc = "Test perf pmu format parsing",
+		.func = test__perf_pmu,
+	},
+	{
 		.func = NULL,
 	},
 };
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index 6170fd2..d9084e0 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -65,6 +65,21 @@
 endef
 endif
 
+ifndef NO_GTK2
+define SOURCE_GTK2
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#include <gtk/gtk.h>
+#pragma GCC diagnostic error \"-Wstrict-prototypes\"
+
+int main(int argc, char *argv[])
+{
+        gtk_init(&argc, &argv);
+
+        return 0;
+}
+endef
+endif
+
 ifndef NO_LIBPERL
 define SOURCE_PERL_EMBED
 #include <EXTERN.h>
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index e5a462f..199f69e 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -28,8 +28,8 @@
 int symbol__alloc_hist(struct symbol *sym)
 {
 	struct annotation *notes = symbol__annotation(sym);
-	size_t sizeof_sym_hist = (sizeof(struct sym_hist) +
-				  (sym->end - sym->start) * sizeof(u64));
+	const size_t size = sym->end - sym->start + 1;
+	size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
 
 	notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
 	if (notes->src == NULL)
@@ -64,7 +64,7 @@
 
 	pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
 
-	if (addr >= sym->end)
+	if (addr > sym->end)
 		return 0;
 
 	offset = addr - sym->start;
@@ -408,7 +408,7 @@
 	if (!notes->src->lines)
 		return -1;
 
-	start = map->unmap_ip(map, sym->start);
+	start = map__rip_2objdump(map, sym->start);
 
 	for (i = 0; i < len; i++) {
 		char *path = NULL;
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index fc5e5a0..8dd224d 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -45,6 +45,18 @@
 void exit_browser(bool wait_for_ok);
 #endif
 
+#ifdef NO_GTK2_SUPPORT
+static inline void perf_gtk_setup_browser(int argc __used, const char *argv[] __used, bool fallback_to_pager)
+{
+	if (fallback_to_pager)
+		setup_pager();
+}
+static inline void perf_gtk_exit_browser(bool wait_for_ok __used) {}
+#else
+void perf_gtk_setup_browser(int argc, const char *argv[], bool fallback_to_pager);
+void perf_gtk_exit_browser(bool wait_for_ok);
+#endif
+
 char *alias_lookup(const char *alias);
 int split_cmdline(char *cmdline, const char ***argv);
 
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 159263d..1986d80 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -51,13 +51,15 @@
 void perf_evlist__config_attrs(struct perf_evlist *evlist,
 			       struct perf_record_opts *opts)
 {
-	struct perf_evsel *evsel;
+	struct perf_evsel *evsel, *first;
 
 	if (evlist->cpus->map[0] < 0)
 		opts->no_inherit = true;
 
+	first = list_entry(evlist->entries.next, struct perf_evsel, node);
+
 	list_for_each_entry(evsel, &evlist->entries, node) {
-		perf_evsel__config(evsel, opts);
+		perf_evsel__config(evsel, opts, first);
 
 		if (evlist->nr_entries > 1)
 			evsel->attr.sample_type |= PERF_SAMPLE_ID;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index f421f7c..8c13dbc 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -34,7 +34,7 @@
 	return size;
 }
 
-static void hists__init(struct hists *hists)
+void hists__init(struct hists *hists)
 {
 	memset(hists, 0, sizeof(*hists));
 	hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
@@ -63,7 +63,8 @@
 	return evsel;
 }
 
-void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts)
+void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
+			struct perf_evsel *first)
 {
 	struct perf_event_attr *attr = &evsel->attr;
 	int track = !evsel->idx; /* only the first counter needs these */
@@ -134,7 +135,8 @@
 	attr->mmap = track;
 	attr->comm = track;
 
-	if (!opts->target_pid && !opts->target_tid && !opts->system_wide) {
+	if (!opts->target_pid && !opts->target_tid && !opts->system_wide &&
+	    (!opts->group || evsel == first)) {
 		attr->disabled = 1;
 		attr->enable_on_exec = 1;
 	}
@@ -578,6 +580,8 @@
 			return -EFAULT;
 
 		data->raw_data = (void *) pdata;
+
+		array = (void *)array + data->raw_size + sizeof(u32);
 	}
 
 	if (type & PERF_SAMPLE_BRANCH_STACK) {
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 326b8e4..3d6b3e4 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -80,7 +80,8 @@
 void perf_evsel__delete(struct perf_evsel *evsel);
 
 void perf_evsel__config(struct perf_evsel *evsel,
-			struct perf_record_opts *opts);
+			struct perf_record_opts *opts,
+			struct perf_evsel *first);
 
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
@@ -169,4 +170,6 @@
 	return __perf_evsel__sample_size(evsel->attr.sample_type);
 }
 
+void hists__init(struct hists *hists);
+
 #endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/gtk/browser.c b/tools/perf/util/gtk/browser.c
new file mode 100644
index 0000000..258352a
--- /dev/null
+++ b/tools/perf/util/gtk/browser.c
@@ -0,0 +1,189 @@
+#include "../evlist.h"
+#include "../cache.h"
+#include "../evsel.h"
+#include "../sort.h"
+#include "../hist.h"
+#include "gtk.h"
+
+#include <signal.h>
+
+#define MAX_COLUMNS			32
+
+void perf_gtk_setup_browser(int argc, const char *argv[],
+			    bool fallback_to_pager __used)
+{
+	gtk_init(&argc, (char ***)&argv);
+}
+
+void perf_gtk_exit_browser(bool wait_for_ok __used)
+{
+	gtk_main_quit();
+}
+
+static void perf_gtk_signal(int sig)
+{
+	psignal(sig, "perf");
+	gtk_main_quit();
+}
+
+static void perf_gtk_resize_window(GtkWidget *window)
+{
+	GdkRectangle rect;
+	GdkScreen *screen;
+	int monitor;
+	int height;
+	int width;
+
+	screen = gtk_widget_get_screen(window);
+
+	monitor = gdk_screen_get_monitor_at_window(screen, window->window);
+
+	gdk_screen_get_monitor_geometry(screen, monitor, &rect);
+
+	width	= rect.width * 3 / 4;
+	height	= rect.height * 3 / 4;
+
+	gtk_window_resize(GTK_WINDOW(window), width, height);
+}
+
+static void perf_gtk_show_hists(GtkWidget *window, struct hists *hists)
+{
+	GType col_types[MAX_COLUMNS];
+	GtkCellRenderer *renderer;
+	struct sort_entry *se;
+	GtkListStore *store;
+	struct rb_node *nd;
+	u64 total_period;
+	GtkWidget *view;
+	int col_idx;
+	int nr_cols;
+
+	nr_cols = 0;
+
+	/* The percentage column */
+	col_types[nr_cols++] = G_TYPE_STRING;
+
+	list_for_each_entry(se, &hist_entry__sort_list, list) {
+		if (se->elide)
+			continue;
+
+		col_types[nr_cols++] = G_TYPE_STRING;
+	}
+
+	store = gtk_list_store_newv(nr_cols, col_types);
+
+	view = gtk_tree_view_new();
+
+	renderer = gtk_cell_renderer_text_new();
+
+	col_idx = 0;
+
+	/* The percentage column */
+	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+						    -1, "Overhead (%)",
+						    renderer, "text",
+						    col_idx++, NULL);
+
+	list_for_each_entry(se, &hist_entry__sort_list, list) {
+		if (se->elide)
+			continue;
+
+		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+							    -1, se->se_header,
+							    renderer, "text",
+							    col_idx++, NULL);
+	}
+
+	gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
+
+	g_object_unref(GTK_TREE_MODEL(store));
+
+	total_period = hists->stats.total_period;
+
+	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
+		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+		GtkTreeIter iter;
+		double percent;
+		char s[512];
+
+		if (h->filtered)
+			continue;
+
+		gtk_list_store_append(store, &iter);
+
+		col_idx = 0;
+
+		percent = (h->period * 100.0) / total_period;
+
+		snprintf(s, ARRAY_SIZE(s), "%.2f", percent);
+
+		gtk_list_store_set(store, &iter, col_idx++, s, -1);
+
+		list_for_each_entry(se, &hist_entry__sort_list, list) {
+			if (se->elide)
+				continue;
+
+			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_container_add(GTK_CONTAINER(window), view);
+}
+
+int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
+				  const char *help __used,
+				  void (*timer) (void *arg)__used,
+				  void *arg __used, int delay_secs __used)
+{
+	struct perf_evsel *pos;
+	GtkWidget *notebook;
+	GtkWidget *window;
+
+	signal(SIGSEGV, perf_gtk_signal);
+	signal(SIGFPE,  perf_gtk_signal);
+	signal(SIGINT,  perf_gtk_signal);
+	signal(SIGQUIT, perf_gtk_signal);
+	signal(SIGTERM, perf_gtk_signal);
+
+	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+	gtk_window_set_title(GTK_WINDOW(window), "perf report");
+
+	g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
+
+	notebook = gtk_notebook_new();
+
+	list_for_each_entry(pos, &evlist->entries, node) {
+		struct hists *hists = &pos->hists;
+		const char *evname = event_name(pos);
+		GtkWidget *scrolled_window;
+		GtkWidget *tab_label;
+
+		scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+
+		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
+							GTK_POLICY_AUTOMATIC,
+							GTK_POLICY_AUTOMATIC);
+
+		perf_gtk_show_hists(scrolled_window, hists);
+
+		tab_label = gtk_label_new(evname);
+
+		gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
+	}
+
+	gtk_container_add(GTK_CONTAINER(window), notebook);
+
+	gtk_widget_show_all(window);
+
+	perf_gtk_resize_window(window);
+
+	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+
+	gtk_main();
+
+	return 0;
+}
diff --git a/tools/perf/util/gtk/gtk.h b/tools/perf/util/gtk/gtk.h
new file mode 100644
index 0000000..75177ee
--- /dev/null
+++ b/tools/perf/util/gtk/gtk.h
@@ -0,0 +1,8 @@
+#ifndef _PERF_GTK_H_
+#define _PERF_GTK_H_ 1
+
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#include <gtk/gtk.h>
+#pragma GCC diagnostic error "-Wstrict-prototypes"
+
+#endif /* _PERF_GTK_H_ */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index fcd9cf3..4c7c2d7 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1177,7 +1177,7 @@
 		goto error;
 
 	msz = sizeof(attr);
-	if (sz < (ssize_t)msz)
+	if (sz < msz)
 		msz = sz;
 
 	for (i = 0 ; i < nre; i++) {
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 3dc99a9..2ec4b60 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -10,11 +10,14 @@
 				       struct hist_entry *he);
 static bool hists__filter_entry_by_thread(struct hists *hists,
 					  struct hist_entry *he);
+static bool hists__filter_entry_by_symbol(struct hists *hists,
+					  struct hist_entry *he);
 
 enum hist_filter {
 	HIST_FILTER__DSO,
 	HIST_FILTER__THREAD,
 	HIST_FILTER__PARENT,
+	HIST_FILTER__SYMBOL,
 };
 
 struct callchain_param	callchain_param = {
@@ -420,6 +423,7 @@
 {
 	hists__filter_entry_by_dso(hists, he);
 	hists__filter_entry_by_thread(hists, he);
+	hists__filter_entry_by_symbol(hists, he);
 }
 
 static void __hists__collapse_resort(struct hists *hists, bool threaded)
@@ -603,7 +607,7 @@
 	rem_hits.ms.sym = rem_sq_bracket;
 }
 
-static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
+static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
 					 u64 total_samples, int depth,
 					 int depth_mask, int left_margin)
 {
@@ -611,21 +615,16 @@
 	struct callchain_node *child;
 	struct callchain_list *chain;
 	int new_depth_mask = depth_mask;
-	u64 new_total;
 	u64 remaining;
 	size_t ret = 0;
 	int i;
 	uint entries_printed = 0;
 
-	if (callchain_param.mode == CHAIN_GRAPH_REL)
-		new_total = self->children_hit;
-	else
-		new_total = total_samples;
+	remaining = total_samples;
 
-	remaining = new_total;
-
-	node = rb_first(&self->rb_root);
+	node = rb_first(root);
 	while (node) {
+		u64 new_total;
 		u64 cumul;
 
 		child = rb_entry(node, struct callchain_node, rb_node);
@@ -653,11 +652,17 @@
 		list_for_each_entry(chain, &child->val, list) {
 			ret += ipchain__fprintf_graph(fp, chain, depth,
 						      new_depth_mask, i++,
-						      new_total,
+						      total_samples,
 						      cumul,
 						      left_margin);
 		}
-		ret += __callchain__fprintf_graph(fp, child, new_total,
+
+		if (callchain_param.mode == CHAIN_GRAPH_REL)
+			new_total = child->children_hit;
+		else
+			new_total = total_samples;
+
+		ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total,
 						  depth + 1,
 						  new_depth_mask | (1 << depth),
 						  left_margin);
@@ -667,61 +672,75 @@
 	}
 
 	if (callchain_param.mode == CHAIN_GRAPH_REL &&
-		remaining && remaining != new_total) {
+		remaining && remaining != total_samples) {
 
 		if (!rem_sq_bracket)
 			return ret;
 
 		new_depth_mask &= ~(1 << (depth - 1));
-
 		ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
-					      new_depth_mask, 0, new_total,
+					      new_depth_mask, 0, total_samples,
 					      remaining, left_margin);
 	}
 
 	return ret;
 }
 
-static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
+static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
 				       u64 total_samples, int left_margin)
 {
+	struct callchain_node *cnode;
 	struct callchain_list *chain;
-	bool printed = false;
-	int i = 0;
-	int ret = 0;
 	u32 entries_printed = 0;
+	bool printed = false;
+	struct rb_node *node;
+	int i = 0;
+	int ret;
 
-	list_for_each_entry(chain, &self->val, list) {
-		if (!i++ && sort__first_dimension == SORT_SYM)
-			continue;
+	/*
+	 * If have one single callchain root, don't bother printing
+	 * its percentage (100 % in fractal mode and the same percentage
+	 * than the hist in graph mode). This also avoid one level of column.
+	 */
+	node = rb_first(root);
+	if (node && !rb_next(node)) {
+		cnode = rb_entry(node, struct callchain_node, rb_node);
+		list_for_each_entry(chain, &cnode->val, list) {
+			/*
+			 * If we sort by symbol, the first entry is the same than
+			 * the symbol. No need to print it otherwise it appears as
+			 * displayed twice.
+			 */
+			if (!i++ && sort__first_dimension == SORT_SYM)
+				continue;
+			if (!printed) {
+				ret += callchain__fprintf_left_margin(fp, left_margin);
+				ret += fprintf(fp, "|\n");
+				ret += callchain__fprintf_left_margin(fp, left_margin);
+				ret += fprintf(fp, "---");
+				left_margin += 3;
+				printed = true;
+			} else
+				ret += callchain__fprintf_left_margin(fp, left_margin);
 
-		if (!printed) {
-			ret += callchain__fprintf_left_margin(fp, left_margin);
-			ret += fprintf(fp, "|\n");
-			ret += callchain__fprintf_left_margin(fp, left_margin);
-			ret += fprintf(fp, "---");
+			if (chain->ms.sym)
+				ret += fprintf(fp, " %s\n", chain->ms.sym->name);
+			else
+				ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
 
-			left_margin += 3;
-			printed = true;
-		} else
-			ret += callchain__fprintf_left_margin(fp, left_margin);
-
-		if (chain->ms.sym)
-			ret += fprintf(fp, " %s\n", chain->ms.sym->name);
-		else
-			ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
-
-		if (++entries_printed == callchain_param.print_limit)
-			break;
+			if (++entries_printed == callchain_param.print_limit)
+				break;
+		}
+		root = &cnode->rb_root;
 	}
 
-	ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
-
-	return ret;
+	return __callchain__fprintf_graph(fp, root, total_samples,
+					  1, 1, left_margin);
 }
 
-static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
-				      u64 total_samples)
+static size_t __callchain__fprintf_flat(FILE *fp,
+					struct callchain_node *self,
+					u64 total_samples)
 {
 	struct callchain_list *chain;
 	size_t ret = 0;
@@ -729,7 +748,7 @@
 	if (!self)
 		return 0;
 
-	ret += callchain__fprintf_flat(fp, self->parent, total_samples);
+	ret += __callchain__fprintf_flat(fp, self->parent, total_samples);
 
 
 	list_for_each_entry(chain, &self->val, list) {
@@ -745,44 +764,58 @@
 	return ret;
 }
 
-static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
-					    u64 total_samples, int left_margin,
-					    FILE *fp)
+static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *self,
+				      u64 total_samples)
 {
-	struct rb_node *rb_node;
-	struct callchain_node *chain;
 	size_t ret = 0;
 	u32 entries_printed = 0;
+	struct rb_node *rb_node;
+	struct callchain_node *chain;
 
-	rb_node = rb_first(&he->sorted_chain);
+	rb_node = rb_first(self);
 	while (rb_node) {
 		double percent;
 
 		chain = rb_entry(rb_node, struct callchain_node, rb_node);
 		percent = chain->hit * 100.0 / total_samples;
-		switch (callchain_param.mode) {
-		case CHAIN_FLAT:
-			ret += percent_color_fprintf(fp, "           %6.2f%%\n",
-						     percent);
-			ret += callchain__fprintf_flat(fp, chain, total_samples);
-			break;
-		case CHAIN_GRAPH_ABS: /* Falldown */
-		case CHAIN_GRAPH_REL:
-			ret += callchain__fprintf_graph(fp, chain, total_samples,
-							left_margin);
-		case CHAIN_NONE:
-		default:
-			break;
-		}
+
+		ret = percent_color_fprintf(fp, "           %6.2f%%\n", percent);
+		ret += __callchain__fprintf_flat(fp, chain, total_samples);
 		ret += fprintf(fp, "\n");
 		if (++entries_printed == callchain_param.print_limit)
 			break;
+
 		rb_node = rb_next(rb_node);
 	}
 
 	return ret;
 }
 
+static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
+					    u64 total_samples, int left_margin,
+					    FILE *fp)
+{
+	switch (callchain_param.mode) {
+	case CHAIN_GRAPH_REL:
+		return callchain__fprintf_graph(fp, &he->sorted_chain, he->period,
+						left_margin);
+		break;
+	case CHAIN_GRAPH_ABS:
+		return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
+						left_margin);
+		break;
+	case CHAIN_FLAT:
+		return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
+		break;
+	case CHAIN_NONE:
+		break;
+	default:
+		pr_err("Bad callchain mode\n");
+	}
+
+	return 0;
+}
+
 void hists__output_recalc_col_len(struct hists *hists, int max_rows)
 {
 	struct rb_node *next = rb_first(&hists->entries);
@@ -887,9 +920,9 @@
 		diff = new_percent - old_percent;
 
 		if (fabs(diff) >= 0.01)
-			ret += scnprintf(bf, sizeof(bf), "%+4.2F%%", diff);
+			scnprintf(bf, sizeof(bf), "%+4.2F%%", diff);
 		else
-			ret += scnprintf(bf, sizeof(bf), " ");
+			scnprintf(bf, sizeof(bf), " ");
 
 		if (sep)
 			ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
@@ -898,9 +931,9 @@
 
 		if (show_displacement) {
 			if (displacement)
-				ret += scnprintf(bf, sizeof(bf), "%+4ld", displacement);
+				scnprintf(bf, sizeof(bf), "%+4ld", displacement);
 			else
-				ret += scnprintf(bf, sizeof(bf), " ");
+				scnprintf(bf, sizeof(bf), " ");
 
 			if (sep)
 				ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
@@ -1247,6 +1280,37 @@
 	}
 }
 
+static bool hists__filter_entry_by_symbol(struct hists *hists,
+					  struct hist_entry *he)
+{
+	if (hists->symbol_filter_str != NULL &&
+	    (!he->ms.sym || strstr(he->ms.sym->name,
+				   hists->symbol_filter_str) == NULL)) {
+		he->filtered |= (1 << HIST_FILTER__SYMBOL);
+		return true;
+	}
+
+	return false;
+}
+
+void hists__filter_by_symbol(struct hists *hists)
+{
+	struct rb_node *nd;
+
+	hists->nr_entries = hists->stats.total_period = 0;
+	hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
+	hists__reset_col_len(hists);
+
+	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
+		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+
+		if (hists__filter_entry_by_symbol(hists, h))
+			continue;
+
+		hists__remove_entry_filter(hists, h, HIST_FILTER__SYMBOL);
+	}
+}
+
 int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
 {
 	return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 9413f3e..2cae9df 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -62,6 +62,7 @@
 	const struct thread	*thread_filter;
 	const struct dso	*dso_filter;
 	const char		*uid_filter_str;
+	const char		*symbol_filter_str;
 	pthread_mutex_t		lock;
 	struct events_stats	stats;
 	u64			event_stream;
@@ -107,6 +108,7 @@
 
 void hists__filter_by_dso(struct hists *hists);
 void hists__filter_by_thread(struct hists *hists);
+void hists__filter_by_symbol(struct hists *hists);
 
 u16 hists__col_len(struct hists *self, enum hist_column col);
 void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
@@ -145,6 +147,23 @@
 				  int refresh);
 #endif
 
+#ifdef NO_GTK2_SUPPORT
+static inline
+int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __used,
+				  const char *help __used,
+				  void(*timer)(void *arg) __used,
+				  void *arg __used,
+				  int refresh __used)
+{
+	return 0;
+}
+
+#else
+int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
+				  void(*timer)(void *arg), void *arg,
+				  int refresh);
+#endif
+
 unsigned int hists__sort_list_width(struct hists *self);
 
 #endif	/* __PERF_HIST_H */
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index 62cdee7..f1584833 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -15,7 +15,7 @@
 	     (bit) = find_next_bit((addr), (size), (bit) + 1))
 
 /* same as for_each_set_bit() but use bit as value to start with */
-#define for_each_set_bit_cont(bit, addr, size) \
+#define for_each_set_bit_from(bit, addr, size) \
 	for ((bit) = find_next_bit((addr), (size), (bit));	\
 	     (bit) < (size);					\
 	     (bit) = find_next_bit((addr), (size), (bit) + 1))
diff --git a/tools/perf/util/include/linux/module.h b/tools/perf/util/include/linux/export.h
similarity index 100%
rename from tools/perf/util/include/linux/module.h
rename to tools/perf/util/include/linux/export.h
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index c7a6f6f..5b3a0ef 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -11,6 +11,10 @@
 #include "cache.h"
 #include "header.h"
 #include "debugfs.h"
+#include "parse-events-flex.h"
+#include "pmu.h"
+
+#define MAX_NAME_LEN 100
 
 struct event_symbol {
 	u8		type;
@@ -19,11 +23,8 @@
 	const char	*alias;
 };
 
-enum event_result {
-	EVT_FAILED,
-	EVT_HANDLED,
-	EVT_HANDLED_ALL
-};
+int parse_events_parse(struct list_head *list, struct list_head *list_tmp,
+		       int *idx);
 
 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -354,7 +355,24 @@
 	return "unknown";
 }
 
-static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size)
+static int add_event(struct list_head *list, int *idx,
+		     struct perf_event_attr *attr, char *name)
+{
+	struct perf_evsel *evsel;
+
+	event_attr_init(attr);
+
+	evsel = perf_evsel__new(attr, (*idx)++);
+	if (!evsel)
+		return -ENOMEM;
+
+	list_add_tail(&evsel->node, list);
+
+	evsel->name = strdup(name);
+	return 0;
+}
+
+static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
 {
 	int i, j;
 	int n, longest = -1;
@@ -362,58 +380,57 @@
 	for (i = 0; i < size; i++) {
 		for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
 			n = strlen(names[i][j]);
-			if (n > longest && !strncasecmp(*str, names[i][j], n))
+			if (n > longest && !strncasecmp(str, names[i][j], n))
 				longest = n;
 		}
-		if (longest > 0) {
-			*str += longest;
+		if (longest > 0)
 			return i;
-		}
 	}
 
 	return -1;
 }
 
-static enum event_result
-parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
+int parse_events_add_cache(struct list_head *list, int *idx,
+			   char *type, char *op_result1, char *op_result2)
 {
-	const char *s = *str;
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 	int cache_type = -1, cache_op = -1, cache_result = -1;
+	char *op_result[2] = { op_result1, op_result2 };
+	int i, n;
 
-	cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
 	/*
 	 * No fallback - if we cannot get a clear cache type
 	 * then bail out:
 	 */
+	cache_type = parse_aliases(type, hw_cache,
+				   PERF_COUNT_HW_CACHE_MAX);
 	if (cache_type == -1)
-		return EVT_FAILED;
+		return -EINVAL;
 
-	while ((cache_op == -1 || cache_result == -1) && *s == '-') {
-		++s;
+	n = snprintf(name, MAX_NAME_LEN, "%s", type);
+
+	for (i = 0; (i < 2) && (op_result[i]); i++) {
+		char *str = op_result[i];
+
+		snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
 
 		if (cache_op == -1) {
-			cache_op = parse_aliases(&s, hw_cache_op,
-						PERF_COUNT_HW_CACHE_OP_MAX);
+			cache_op = parse_aliases(str, hw_cache_op,
+						 PERF_COUNT_HW_CACHE_OP_MAX);
 			if (cache_op >= 0) {
 				if (!is_cache_op_valid(cache_type, cache_op))
-					return EVT_FAILED;
+					return -EINVAL;
 				continue;
 			}
 		}
 
 		if (cache_result == -1) {
-			cache_result = parse_aliases(&s, hw_cache_result,
+			cache_result = parse_aliases(str, hw_cache_result,
 						PERF_COUNT_HW_CACHE_RESULT_MAX);
 			if (cache_result >= 0)
 				continue;
 		}
-
-		/*
-		 * Can't parse this as a cache op or result, so back up
-		 * to the '-'.
-		 */
-		--s;
-		break;
 	}
 
 	/*
@@ -428,20 +445,17 @@
 	if (cache_result == -1)
 		cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
 
-	attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
-	attr->type = PERF_TYPE_HW_CACHE;
-
-	*str = s;
-	return EVT_HANDLED;
+	memset(&attr, 0, sizeof(attr));
+	attr.config = cache_type | (cache_op << 8) | (cache_result << 16);
+	attr.type = PERF_TYPE_HW_CACHE;
+	return add_event(list, idx, &attr, name);
 }
 
-static enum event_result
-parse_single_tracepoint_event(char *sys_name,
-			      const char *evt_name,
-			      unsigned int evt_length,
-			      struct perf_event_attr *attr,
-			      const char **strp)
+static int add_tracepoint(struct list_head *list, int *idx,
+			  char *sys_name, char *evt_name)
 {
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 	char evt_path[MAXPATHLEN];
 	char id_buf[4];
 	u64 id;
@@ -452,130 +466,80 @@
 
 	fd = open(evt_path, O_RDONLY);
 	if (fd < 0)
-		return EVT_FAILED;
+		return -1;
 
 	if (read(fd, id_buf, sizeof(id_buf)) < 0) {
 		close(fd);
-		return EVT_FAILED;
+		return -1;
 	}
 
 	close(fd);
 	id = atoll(id_buf);
-	attr->config = id;
-	attr->type = PERF_TYPE_TRACEPOINT;
-	*strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */
 
-	attr->sample_type |= PERF_SAMPLE_RAW;
-	attr->sample_type |= PERF_SAMPLE_TIME;
-	attr->sample_type |= PERF_SAMPLE_CPU;
+	memset(&attr, 0, sizeof(attr));
+	attr.config = id;
+	attr.type = PERF_TYPE_TRACEPOINT;
+	attr.sample_type |= PERF_SAMPLE_RAW;
+	attr.sample_type |= PERF_SAMPLE_TIME;
+	attr.sample_type |= PERF_SAMPLE_CPU;
+	attr.sample_period = 1;
 
-	attr->sample_period = 1;
-
-
-	return EVT_HANDLED;
+	snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name);
+	return add_event(list, idx, &attr, name);
 }
 
-/* sys + ':' + event + ':' + flags*/
-#define MAX_EVOPT_LEN	(MAX_EVENT_LENGTH * 2 + 2 + 128)
-static enum event_result
-parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name,
-				const char *evt_exp, char *flags)
+static int add_tracepoint_multi(struct list_head *list, int *idx,
+				char *sys_name, char *evt_name)
 {
 	char evt_path[MAXPATHLEN];
 	struct dirent *evt_ent;
 	DIR *evt_dir;
+	int ret = 0;
 
 	snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name);
 	evt_dir = opendir(evt_path);
-
 	if (!evt_dir) {
 		perror("Can't open event dir");
-		return EVT_FAILED;
+		return -1;
 	}
 
-	while ((evt_ent = readdir(evt_dir))) {
-		char event_opt[MAX_EVOPT_LEN + 1];
-		int len;
-
+	while (!ret && (evt_ent = readdir(evt_dir))) {
 		if (!strcmp(evt_ent->d_name, ".")
 		    || !strcmp(evt_ent->d_name, "..")
 		    || !strcmp(evt_ent->d_name, "enable")
 		    || !strcmp(evt_ent->d_name, "filter"))
 			continue;
 
-		if (!strglobmatch(evt_ent->d_name, evt_exp))
+		if (!strglobmatch(evt_ent->d_name, evt_name))
 			continue;
 
-		len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
-			       evt_ent->d_name, flags ? ":" : "",
-			       flags ?: "");
-		if (len < 0)
-			return EVT_FAILED;
-
-		if (parse_events(evlist, event_opt, 0))
-			return EVT_FAILED;
+		ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name);
 	}
 
-	return EVT_HANDLED_ALL;
+	return ret;
 }
 
-static enum event_result
-parse_tracepoint_event(struct perf_evlist *evlist, const char **strp,
-		       struct perf_event_attr *attr)
+int parse_events_add_tracepoint(struct list_head *list, int *idx,
+				char *sys, char *event)
 {
-	const char *evt_name;
-	char *flags = NULL, *comma_loc;
-	char sys_name[MAX_EVENT_LENGTH];
-	unsigned int sys_length, evt_length;
+	int ret;
 
-	if (debugfs_valid_mountpoint(tracing_events_path))
-		return 0;
+	ret = debugfs_valid_mountpoint(tracing_events_path);
+	if (ret)
+		return ret;
 
-	evt_name = strchr(*strp, ':');
-	if (!evt_name)
-		return EVT_FAILED;
-
-	sys_length = evt_name - *strp;
-	if (sys_length >= MAX_EVENT_LENGTH)
-		return 0;
-
-	strncpy(sys_name, *strp, sys_length);
-	sys_name[sys_length] = '\0';
-	evt_name = evt_name + 1;
-
-	comma_loc = strchr(evt_name, ',');
-	if (comma_loc) {
-		/* take the event name up to the comma */
-		evt_name = strndup(evt_name, comma_loc - evt_name);
-	}
-	flags = strchr(evt_name, ':');
-	if (flags) {
-		/* split it out: */
-		evt_name = strndup(evt_name, flags - evt_name);
-		flags++;
-	}
-
-	evt_length = strlen(evt_name);
-	if (evt_length >= MAX_EVENT_LENGTH)
-		return EVT_FAILED;
-	if (strpbrk(evt_name, "*?")) {
-		*strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
-		return parse_multiple_tracepoint_event(evlist, sys_name,
-						       evt_name, flags);
-	} else {
-		return parse_single_tracepoint_event(sys_name, evt_name,
-						     evt_length, attr, strp);
-	}
+	return strpbrk(event, "*?") ?
+	       add_tracepoint_multi(list, idx, sys, event) :
+	       add_tracepoint(list, idx, sys, event);
 }
 
-static enum event_result
-parse_breakpoint_type(const char *type, const char **strp,
-		      struct perf_event_attr *attr)
+static int
+parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
 {
 	int i;
 
 	for (i = 0; i < 3; i++) {
-		if (!type[i])
+		if (!type || !type[i])
 			break;
 
 		switch (type[i]) {
@@ -589,164 +553,146 @@
 			attr->bp_type |= HW_BREAKPOINT_X;
 			break;
 		default:
-			return EVT_FAILED;
+			return -EINVAL;
 		}
 	}
+
 	if (!attr->bp_type) /* Default */
 		attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
 
-	*strp = type + i;
-
-	return EVT_HANDLED;
+	return 0;
 }
 
-static enum event_result
-parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
+int parse_events_add_breakpoint(struct list_head *list, int *idx,
+				void *ptr, char *type)
 {
-	const char *target;
-	const char *type;
-	char *endaddr;
-	u64 addr;
-	enum event_result err;
+	struct perf_event_attr attr;
+	char name[MAX_NAME_LEN];
 
-	target = strchr(*strp, ':');
-	if (!target)
-		return EVT_FAILED;
+	memset(&attr, 0, sizeof(attr));
+	attr.bp_addr = (unsigned long) ptr;
 
-	if (strncmp(*strp, "mem", target - *strp) != 0)
-		return EVT_FAILED;
-
-	target++;
-
-	addr = strtoull(target, &endaddr, 0);
-	if (target == endaddr)
-		return EVT_FAILED;
-
-	attr->bp_addr = addr;
-	*strp = endaddr;
-
-	type = strchr(target, ':');
-
-	/* If no type is defined, just rw as default */
-	if (!type) {
-		attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
-	} else {
-		err = parse_breakpoint_type(++type, strp, attr);
-		if (err == EVT_FAILED)
-			return EVT_FAILED;
-	}
+	if (parse_breakpoint_type(type, &attr))
+		return -EINVAL;
 
 	/*
 	 * We should find a nice way to override the access length
 	 * Provide some defaults for now
 	 */
-	if (attr->bp_type == HW_BREAKPOINT_X)
-		attr->bp_len = sizeof(long);
+	if (attr.bp_type == HW_BREAKPOINT_X)
+		attr.bp_len = sizeof(long);
 	else
-		attr->bp_len = HW_BREAKPOINT_LEN_4;
+		attr.bp_len = HW_BREAKPOINT_LEN_4;
 
-	attr->type = PERF_TYPE_BREAKPOINT;
+	attr.type = PERF_TYPE_BREAKPOINT;
 
-	return EVT_HANDLED;
+	snprintf(name, MAX_NAME_LEN, "mem:%p:%s", ptr, type ? type : "rw");
+	return add_event(list, idx, &attr, name);
 }
 
-static int check_events(const char *str, unsigned int i)
+static int config_term(struct perf_event_attr *attr,
+		       struct parse_events__term *term)
 {
-	int n;
-
-	n = strlen(event_symbols[i].symbol);
-	if (!strncasecmp(str, event_symbols[i].symbol, n))
-		return n;
-
-	n = strlen(event_symbols[i].alias);
-	if (n) {
-		if (!strncasecmp(str, event_symbols[i].alias, n))
-			return n;
+	switch (term->type) {
+	case PARSE_EVENTS__TERM_TYPE_CONFIG:
+		attr->config = term->val.num;
+		break;
+	case PARSE_EVENTS__TERM_TYPE_CONFIG1:
+		attr->config1 = term->val.num;
+		break;
+	case PARSE_EVENTS__TERM_TYPE_CONFIG2:
+		attr->config2 = term->val.num;
+		break;
+	case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
+		attr->sample_period = term->val.num;
+		break;
+	case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
+		/*
+		 * TODO uncomment when the field is available
+		 * attr->branch_sample_type = term->val.num;
+		 */
+		break;
+	default:
+		return -EINVAL;
 	}
+	return 0;
+}
+
+static int config_attr(struct perf_event_attr *attr,
+		       struct list_head *head, int fail)
+{
+	struct parse_events__term *term;
+
+	list_for_each_entry(term, head, list)
+		if (config_term(attr, term) && fail)
+			return -EINVAL;
 
 	return 0;
 }
 
-static enum event_result
-parse_symbolic_event(const char **strp, struct perf_event_attr *attr)
+int parse_events_add_numeric(struct list_head *list, int *idx,
+			     unsigned long type, unsigned long config,
+			     struct list_head *head_config)
 {
-	const char *str = *strp;
-	unsigned int i;
-	int n;
+	struct perf_event_attr attr;
 
-	for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
-		n = check_events(str, i);
-		if (n > 0) {
-			attr->type = event_symbols[i].type;
-			attr->config = event_symbols[i].config;
-			*strp = str + n;
-			return EVT_HANDLED;
-		}
-	}
-	return EVT_FAILED;
+	memset(&attr, 0, sizeof(attr));
+	attr.type = type;
+	attr.config = config;
+
+	if (head_config &&
+	    config_attr(&attr, head_config, 1))
+		return -EINVAL;
+
+	return add_event(list, idx, &attr,
+			 (char *) __event_name(type, config));
 }
 
-static enum event_result
-parse_raw_event(const char **strp, struct perf_event_attr *attr)
+int parse_events_add_pmu(struct list_head *list, int *idx,
+			 char *name, struct list_head *head_config)
 {
-	const char *str = *strp;
-	u64 config;
-	int n;
+	struct perf_event_attr attr;
+	struct perf_pmu *pmu;
 
-	if (*str != 'r')
-		return EVT_FAILED;
-	n = hex2u64(str + 1, &config);
-	if (n > 0) {
-		const char *end = str + n + 1;
-		if (*end != '\0' && *end != ',' && *end != ':')
-			return EVT_FAILED;
+	pmu = perf_pmu__find(name);
+	if (!pmu)
+		return -EINVAL;
 
-		*strp = end;
-		attr->type = PERF_TYPE_RAW;
-		attr->config = config;
-		return EVT_HANDLED;
-	}
-	return EVT_FAILED;
+	memset(&attr, 0, sizeof(attr));
+
+	/*
+	 * Configure hardcoded terms first, no need to check
+	 * return value when called with fail == 0 ;)
+	 */
+	config_attr(&attr, head_config, 0);
+
+	if (perf_pmu__config(pmu, &attr, head_config))
+		return -EINVAL;
+
+	return add_event(list, idx, &attr, (char *) "pmu");
 }
 
-static enum event_result
-parse_numeric_event(const char **strp, struct perf_event_attr *attr)
+void parse_events_update_lists(struct list_head *list_event,
+			       struct list_head *list_all)
 {
-	const char *str = *strp;
-	char *endp;
-	unsigned long type;
-	u64 config;
-
-	type = strtoul(str, &endp, 0);
-	if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
-		str = endp + 1;
-		config = strtoul(str, &endp, 0);
-		if (endp > str) {
-			attr->type = type;
-			attr->config = config;
-			*strp = endp;
-			return EVT_HANDLED;
-		}
-	}
-	return EVT_FAILED;
+	/*
+	 * Called for single event definition. Update the
+	 * 'all event' list, and reinit the 'signle event'
+	 * list, for next event definition.
+	 */
+	list_splice_tail(list_event, list_all);
+	INIT_LIST_HEAD(list_event);
 }
 
-static int
-parse_event_modifier(const char **strp, struct perf_event_attr *attr)
+int parse_events_modifier(struct list_head *list, char *str)
 {
-	const char *str = *strp;
+	struct perf_evsel *evsel;
 	int exclude = 0, exclude_GH = 0;
 	int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0;
 
-	if (!*str)
+	if (str == NULL)
 		return 0;
 
-	if (*str == ',')
-		return 0;
-
-	if (*str++ != ':')
-		return -1;
-
 	while (*str) {
 		if (*str == 'u') {
 			if (!exclude)
@@ -775,111 +721,62 @@
 
 		++str;
 	}
-	if (str < *strp + 2)
-		return -1;
 
-	*strp = str;
+	/*
+	 * precise ip:
+	 *
+	 *  0 - SAMPLE_IP can have arbitrary skid
+	 *  1 - SAMPLE_IP must have constant skid
+	 *  2 - SAMPLE_IP requested to have 0 skid
+	 *  3 - SAMPLE_IP must have 0 skid
+	 *
+	 *  See also PERF_RECORD_MISC_EXACT_IP
+	 */
+	if (precise > 3)
+		return -EINVAL;
 
-	attr->exclude_user   = eu;
-	attr->exclude_kernel = ek;
-	attr->exclude_hv     = eh;
-	attr->precise_ip     = precise;
-	attr->exclude_host   = eH;
-	attr->exclude_guest  = eG;
+	list_for_each_entry(evsel, list, node) {
+		evsel->attr.exclude_user   = eu;
+		evsel->attr.exclude_kernel = ek;
+		evsel->attr.exclude_hv     = eh;
+		evsel->attr.precise_ip     = precise;
+		evsel->attr.exclude_host   = eH;
+		evsel->attr.exclude_guest  = eG;
+	}
 
 	return 0;
 }
 
-/*
- * Each event can have multiple symbolic names.
- * Symbolic names are (almost) exactly matched.
- */
-static enum event_result
-parse_event_symbols(struct perf_evlist *evlist, const char **str,
-		    struct perf_event_attr *attr)
+int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
 {
-	enum event_result ret;
+	LIST_HEAD(list);
+	LIST_HEAD(list_tmp);
+	YY_BUFFER_STATE buffer;
+	int ret, idx = evlist->nr_entries;
 
-	ret = parse_tracepoint_event(evlist, str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	buffer = parse_events__scan_string(str);
 
-	ret = parse_raw_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	ret = parse_events_parse(&list, &list_tmp, &idx);
 
-	ret = parse_numeric_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	parse_events__flush_buffer(buffer);
+	parse_events__delete_buffer(buffer);
 
-	ret = parse_symbolic_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
+	if (!ret) {
+		int entries = idx - evlist->nr_entries;
+		perf_evlist__splice_list_tail(evlist, &list, entries);
+		return 0;
+	}
 
-	ret = parse_generic_hw_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
-
-	ret = parse_breakpoint_event(str, attr);
-	if (ret != EVT_FAILED)
-		goto modifier;
-
-	fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
+	/*
+	 * There are 2 users - builtin-record and builtin-test objects.
+	 * Both call perf_evlist__delete in case of error, so we dont
+	 * need to bother.
+	 */
+	fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
 	fprintf(stderr, "Run 'perf list' for a list of valid events\n");
-	return EVT_FAILED;
-
-modifier:
-	if (parse_event_modifier(str, attr) < 0) {
-		fprintf(stderr, "invalid event modifier: '%s'\n", *str);
-		fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n");
-
-		return EVT_FAILED;
-	}
-
 	return ret;
 }
 
-int parse_events(struct perf_evlist *evlist , const char *str, int unset __used)
-{
-	struct perf_event_attr attr;
-	enum event_result ret;
-	const char *ostr;
-
-	for (;;) {
-		ostr = str;
-		memset(&attr, 0, sizeof(attr));
-		event_attr_init(&attr);
-		ret = parse_event_symbols(evlist, &str, &attr);
-		if (ret == EVT_FAILED)
-			return -1;
-
-		if (!(*str == 0 || *str == ',' || isspace(*str)))
-			return -1;
-
-		if (ret != EVT_HANDLED_ALL) {
-			struct perf_evsel *evsel;
-			evsel = perf_evsel__new(&attr, evlist->nr_entries);
-			if (evsel == NULL)
-				return -1;
-			perf_evlist__add(evlist, evsel);
-
-			evsel->name = calloc(str - ostr + 1, 1);
-			if (!evsel->name)
-				return -1;
-			strncpy(evsel->name, ostr, str - ostr);
-		}
-
-		if (*str == 0)
-			break;
-		if (*str == ',')
-			++str;
-		while (isspace(*str))
-			++str;
-	}
-
-	return 0;
-}
-
 int parse_events_option(const struct option *opt, const char *str,
 			int unset __used)
 {
@@ -1052,8 +949,6 @@
 	return printed;
 }
 
-#define MAX_NAME_LEN 100
-
 /*
  * Print the help text for the event symbols:
  */
@@ -1102,8 +997,12 @@
 
 	printf("\n");
 	printf("  %-50s [%s]\n",
-		"rNNN (see 'perf list --help' on how to encode it)",
+	       "rNNN",
 	       event_type_descriptors[PERF_TYPE_RAW]);
+	printf("  %-50s [%s]\n",
+	       "cpu/t1=v1[,t2=v2,t3 ...]/modifier",
+	       event_type_descriptors[PERF_TYPE_RAW]);
+	printf("   (see 'perf list --help' on how to encode it)\n");
 	printf("\n");
 
 	printf("  %-50s [%s]\n",
@@ -1113,3 +1012,51 @@
 
 	print_tracepoint_events(NULL, NULL);
 }
+
+int parse_events__is_hardcoded_term(struct parse_events__term *term)
+{
+	return term->type <= PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX;
+}
+
+int parse_events__new_term(struct parse_events__term **_term, int type,
+			   char *config, char *str, long num)
+{
+	struct parse_events__term *term;
+
+	term = zalloc(sizeof(*term));
+	if (!term)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&term->list);
+	term->type = type;
+	term->config = config;
+
+	switch (type) {
+	case PARSE_EVENTS__TERM_TYPE_CONFIG:
+	case PARSE_EVENTS__TERM_TYPE_CONFIG1:
+	case PARSE_EVENTS__TERM_TYPE_CONFIG2:
+	case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
+	case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
+	case PARSE_EVENTS__TERM_TYPE_NUM:
+		term->val.num = num;
+		break;
+	case PARSE_EVENTS__TERM_TYPE_STR:
+		term->val.str = str;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*_term = term;
+	return 0;
+}
+
+void parse_events__free_terms(struct list_head *terms)
+{
+	struct parse_events__term *term, *h;
+
+	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 7e0cbe7..ca069f8 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -33,6 +33,55 @@
 
 #define EVENTS_HELP_MAX (128*1024)
 
+enum {
+	PARSE_EVENTS__TERM_TYPE_CONFIG,
+	PARSE_EVENTS__TERM_TYPE_CONFIG1,
+	PARSE_EVENTS__TERM_TYPE_CONFIG2,
+	PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
+	PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
+	PARSE_EVENTS__TERM_TYPE_NUM,
+	PARSE_EVENTS__TERM_TYPE_STR,
+
+	PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX =
+		PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
+};
+
+struct parse_events__term {
+	char *config;
+	union {
+		char *str;
+		long  num;
+	} val;
+	int type;
+
+	struct list_head list;
+};
+
+int parse_events__is_hardcoded_term(struct parse_events__term *term);
+int parse_events__new_term(struct parse_events__term **term, int type,
+			   char *config, char *str, long num);
+void parse_events__free_terms(struct list_head *terms);
+int parse_events_modifier(struct list_head *list __used, char *str __used);
+int parse_events_add_tracepoint(struct list_head *list, int *idx,
+				char *sys, char *event);
+int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config,
+			 unsigned long config1, unsigned long config2,
+			 char *mod);
+int parse_events_add_numeric(struct list_head *list, int *idx,
+			     unsigned long type, unsigned long config,
+			     struct list_head *head_config);
+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,
+				void *ptr, char *type);
+int parse_events_add_pmu(struct list_head *list, int *idx,
+			 char *pmu , struct list_head *head_config);
+void parse_events_update_lists(struct list_head *list_event,
+			       struct list_head *list_all);
+void parse_events_error(struct list_head *list_all,
+			struct list_head *list_event,
+			int *idx, char const *msg);
+
 void print_events(const char *event_glob);
 void print_events_type(u8 type);
 void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
new file mode 100644
index 0000000..05d766e
--- /dev/null
+++ b/tools/perf/util/parse-events.l
@@ -0,0 +1,127 @@
+
+%option prefix="parse_events_"
+
+%{
+#include <errno.h>
+#include "../perf.h"
+#include "parse-events-bison.h"
+#include "parse-events.h"
+
+static int __value(char *str, int base, int token)
+{
+	long num;
+
+	errno = 0;
+	num = strtoul(str, NULL, base);
+	if (errno)
+		return PE_ERROR;
+
+	parse_events_lval.num = num;
+	return token;
+}
+
+static int value(int base)
+{
+	return __value(parse_events_text, base, PE_VALUE);
+}
+
+static int raw(void)
+{
+	return __value(parse_events_text + 1, 16, PE_RAW);
+}
+
+static int str(int token)
+{
+	parse_events_lval.str = strdup(parse_events_text);
+	return token;
+}
+
+static int sym(int type, int config)
+{
+	parse_events_lval.num = (type << 16) + config;
+	return PE_VALUE_SYM;
+}
+
+static int term(int type)
+{
+	parse_events_lval.num = type;
+	return PE_TERM;
+}
+
+%}
+
+num_dec		[0-9]+
+num_hex		0x[a-fA-F0-9]+
+num_raw_hex	[a-fA-F0-9]+
+name		[a-zA-Z_*?][a-zA-Z0-9_*?]*
+modifier_event	[ukhp]{1,5}
+modifier_bp	[rwx]
+
+%%
+cpu-cycles|cycles				{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
+stalled-cycles-frontend|idle-cycles-frontend	{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
+stalled-cycles-backend|idle-cycles-backend	{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
+instructions					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
+cache-references				{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
+cache-misses					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
+branch-instructions|branches			{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
+branch-misses					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
+bus-cycles					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
+ref-cycles					{ return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
+cpu-clock					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
+task-clock					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
+page-faults|faults				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
+minor-faults					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
+major-faults					{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
+context-switches|cs				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
+cpu-migrations|migrations			{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
+alignment-faults				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
+emulation-faults				{ return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
+
+L1-dcache|l1-d|l1d|L1-data		|
+L1-icache|l1-i|l1i|L1-instruction	|
+LLC|L2					|
+dTLB|d-tlb|Data-TLB			|
+iTLB|i-tlb|Instruction-TLB		|
+branch|branches|bpu|btb|bpc		|
+node					{ return str(PE_NAME_CACHE_TYPE); }
+
+load|loads|read				|
+store|stores|write			|
+prefetch|prefetches			|
+speculative-read|speculative-load	|
+refs|Reference|ops|access		|
+misses|miss				{ return str(PE_NAME_CACHE_OP_RESULT); }
+
+	/*
+	 * These are event config hardcoded term names to be specified
+	 * within xxx/.../ syntax. So far we dont clash with other names,
+	 * so we can put them here directly. In case the we have a conflict
+	 * in future, this needs to go into '//' condition block.
+	 */
+config			{ return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
+config1			{ return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
+config2			{ return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
+period			{ return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
+branch_type		{ return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
+
+mem:			{ return PE_PREFIX_MEM; }
+r{num_raw_hex}		{ return raw(); }
+{num_dec}		{ return value(10); }
+{num_hex}		{ return value(16); }
+
+{modifier_event}	{ return str(PE_MODIFIER_EVENT); }
+{modifier_bp}		{ return str(PE_MODIFIER_BP); }
+{name}			{ return str(PE_NAME); }
+"/"			{ return '/'; }
+-			{ return '-'; }
+,			{ return ','; }
+:			{ return ':'; }
+=			{ return '='; }
+
+%%
+
+int parse_events_wrap(void)
+{
+	return 1;
+}
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
new file mode 100644
index 0000000..d9637da
--- /dev/null
+++ b/tools/perf/util/parse-events.y
@@ -0,0 +1,229 @@
+
+%name-prefix "parse_events_"
+%parse-param {struct list_head *list_all}
+%parse-param {struct list_head *list_event}
+%parse-param {int *idx}
+
+%{
+
+#define YYDEBUG 1
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include "types.h"
+#include "util.h"
+#include "parse-events.h"
+
+extern int parse_events_lex (void);
+
+#define ABORT_ON(val) \
+do { \
+	if (val) \
+		YYABORT; \
+} while (0)
+
+%}
+
+%token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM
+%token PE_NAME
+%token PE_MODIFIER_EVENT PE_MODIFIER_BP
+%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
+%token PE_PREFIX_MEM PE_PREFIX_RAW
+%token PE_ERROR
+%type <num> PE_VALUE
+%type <num> PE_VALUE_SYM
+%type <num> PE_RAW
+%type <num> PE_TERM
+%type <str> PE_NAME
+%type <str> PE_NAME_CACHE_TYPE
+%type <str> PE_NAME_CACHE_OP_RESULT
+%type <str> PE_MODIFIER_EVENT
+%type <str> PE_MODIFIER_BP
+%type <head> event_config
+%type <term> event_term
+
+%union
+{
+	char *str;
+	unsigned long num;
+	struct list_head *head;
+	struct parse_events__term *term;
+}
+%%
+
+events:
+events ',' event | event
+
+event:
+event_def PE_MODIFIER_EVENT
+{
+	/*
+	 * Apply modifier on all events added by single event definition
+	 * (there could be more events added for multiple tracepoint
+	 * definitions via '*?'.
+	 */
+	ABORT_ON(parse_events_modifier(list_event, $2));
+	parse_events_update_lists(list_event, list_all);
+}
+|
+event_def
+{
+	parse_events_update_lists(list_event, list_all);
+}
+
+event_def: event_pmu |
+	   event_legacy_symbol |
+	   event_legacy_cache sep_dc |
+	   event_legacy_mem |
+	   event_legacy_tracepoint sep_dc |
+	   event_legacy_numeric sep_dc |
+	   event_legacy_raw sep_dc
+
+event_pmu:
+PE_NAME '/' event_config '/'
+{
+	ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3));
+	parse_events__free_terms($3);
+}
+
+event_legacy_symbol:
+PE_VALUE_SYM '/' event_config '/'
+{
+	int type = $1 >> 16;
+	int config = $1 & 255;
+
+	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3));
+	parse_events__free_terms($3);
+}
+|
+PE_VALUE_SYM sep_slash_dc
+{
+	int type = $1 >> 16;
+	int config = $1 & 255;
+
+	ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL));
+}
+
+event_legacy_cache:
+PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
+{
+	ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5));
+}
+|
+PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
+{
+	ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL));
+}
+|
+PE_NAME_CACHE_TYPE
+{
+	ABORT_ON(parse_events_add_cache(list_event, idx, $1, NULL, NULL));
+}
+
+event_legacy_mem:
+PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
+{
+	ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4));
+}
+|
+PE_PREFIX_MEM PE_VALUE sep_dc
+{
+	ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL));
+}
+
+event_legacy_tracepoint:
+PE_NAME ':' PE_NAME
+{
+	ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3));
+}
+
+event_legacy_numeric:
+PE_VALUE ':' PE_VALUE
+{
+	ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL));
+}
+
+event_legacy_raw:
+PE_RAW
+{
+	ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL));
+}
+
+event_config:
+event_config ',' event_term
+{
+	struct list_head *head = $1;
+	struct parse_events__term *term = $3;
+
+	ABORT_ON(!head);
+	list_add_tail(&term->list, head);
+	$$ = $1;
+}
+|
+event_term
+{
+	struct list_head *head = malloc(sizeof(*head));
+	struct parse_events__term *term = $1;
+
+	ABORT_ON(!head);
+	INIT_LIST_HEAD(head);
+	list_add_tail(&term->list, head);
+	$$ = head;
+}
+
+event_term:
+PE_NAME '=' PE_NAME
+{
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR,
+		 $1, $3, 0));
+	$$ = term;
+}
+|
+PE_NAME '=' PE_VALUE
+{
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
+		 $1, NULL, $3));
+	$$ = term;
+}
+|
+PE_NAME
+{
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
+		 $1, NULL, 1));
+	$$ = term;
+}
+|
+PE_TERM '=' PE_VALUE
+{
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, $3));
+	$$ = term;
+}
+|
+PE_TERM
+{
+	struct parse_events__term *term;
+
+	ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, 1));
+	$$ = term;
+}
+
+sep_dc: ':' |
+
+sep_slash_dc: '/' | ':' |
+
+%%
+
+void parse_events_error(struct list_head *list_all __used,
+			struct list_head *list_event __used,
+			int *idx __used,
+			char const *msg __used)
+{
+}
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
new file mode 100644
index 0000000..cb08a11
--- /dev/null
+++ b/tools/perf/util/pmu.c
@@ -0,0 +1,469 @@
+
+#include <linux/list.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <dirent.h>
+#include "sysfs.h"
+#include "util.h"
+#include "pmu.h"
+#include "parse-events.h"
+
+int perf_pmu_parse(struct list_head *list, char *name);
+extern FILE *perf_pmu_in;
+
+static LIST_HEAD(pmus);
+
+/*
+ * Parse & process all the sysfs attributes located under
+ * the directory specified in 'dir' parameter.
+ */
+static int pmu_format_parse(char *dir, struct list_head *head)
+{
+	struct dirent *evt_ent;
+	DIR *format_dir;
+	int ret = 0;
+
+	format_dir = opendir(dir);
+	if (!format_dir)
+		return -EINVAL;
+
+	while (!ret && (evt_ent = readdir(format_dir))) {
+		char path[PATH_MAX];
+		char *name = evt_ent->d_name;
+		FILE *file;
+
+		if (!strcmp(name, ".") || !strcmp(name, ".."))
+			continue;
+
+		snprintf(path, PATH_MAX, "%s/%s", dir, name);
+
+		ret = -EINVAL;
+		file = fopen(path, "r");
+		if (!file)
+			break;
+
+		perf_pmu_in = file;
+		ret = perf_pmu_parse(head, name);
+		fclose(file);
+	}
+
+	closedir(format_dir);
+	return ret;
+}
+
+/*
+ * Reading/parsing the default pmu format definition, which should be
+ * located at:
+ * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
+ */
+static int pmu_format(char *name, struct list_head *format)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+
+	sysfs = sysfs_find_mountpoint();
+	if (!sysfs)
+		return -1;
+
+	snprintf(path, PATH_MAX,
+		 "%s/bus/event_source/devices/%s/format", sysfs, name);
+
+	if (stat(path, &st) < 0)
+		return -1;
+
+	if (pmu_format_parse(path, format))
+		return -1;
+
+	return 0;
+}
+
+/*
+ * Reading/parsing the default pmu type value, which should be
+ * located at:
+ * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
+ */
+static int pmu_type(char *name, __u32 *type)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+	FILE *file;
+	int ret = 0;
+
+	sysfs = sysfs_find_mountpoint();
+	if (!sysfs)
+		return -1;
+
+	snprintf(path, PATH_MAX,
+		 "%s/bus/event_source/devices/%s/type", sysfs, name);
+
+	if (stat(path, &st) < 0)
+		return -1;
+
+	file = fopen(path, "r");
+	if (!file)
+		return -EINVAL;
+
+	if (1 != fscanf(file, "%u", type))
+		ret = -1;
+
+	fclose(file);
+	return ret;
+}
+
+static struct perf_pmu *pmu_lookup(char *name)
+{
+	struct perf_pmu *pmu;
+	LIST_HEAD(format);
+	__u32 type;
+
+	/*
+	 * The pmu data we store & need consists of the pmu
+	 * type value and format definitions. Load both right
+	 * now.
+	 */
+	if (pmu_format(name, &format))
+		return NULL;
+
+	if (pmu_type(name, &type))
+		return NULL;
+
+	pmu = zalloc(sizeof(*pmu));
+	if (!pmu)
+		return NULL;
+
+	INIT_LIST_HEAD(&pmu->format);
+	list_splice(&format, &pmu->format);
+	pmu->name = strdup(name);
+	pmu->type = type;
+	return pmu;
+}
+
+static struct perf_pmu *pmu_find(char *name)
+{
+	struct perf_pmu *pmu;
+
+	list_for_each_entry(pmu, &pmus, list)
+		if (!strcmp(pmu->name, name))
+			return pmu;
+
+	return NULL;
+}
+
+struct perf_pmu *perf_pmu__find(char *name)
+{
+	struct perf_pmu *pmu;
+
+	/*
+	 * Once PMU is loaded it stays in the list,
+	 * so we keep us from multiple reading/parsing
+	 * the pmu format definitions.
+	 */
+	pmu = pmu_find(name);
+	if (pmu)
+		return pmu;
+
+	return pmu_lookup(name);
+}
+
+static struct perf_pmu__format*
+pmu_find_format(struct list_head *formats, char *name)
+{
+	struct perf_pmu__format *format;
+
+	list_for_each_entry(format, formats, list)
+		if (!strcmp(format->name, name))
+			return format;
+
+	return NULL;
+}
+
+/*
+ * Returns value based on the format definition (format parameter)
+ * and unformated value (value parameter).
+ *
+ * TODO maybe optimize a little ;)
+ */
+static __u64 pmu_format_value(unsigned long *format, __u64 value)
+{
+	unsigned long fbit, vbit;
+	__u64 v = 0;
+
+	for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
+
+		if (!test_bit(fbit, format))
+			continue;
+
+		if (!(value & (1llu << vbit++)))
+			continue;
+
+		v |= (1llu << fbit);
+	}
+
+	return v;
+}
+
+/*
+ * Setup one of config[12] attr members based on the
+ * user input data - temr parameter.
+ */
+static int pmu_config_term(struct list_head *formats,
+			   struct perf_event_attr *attr,
+			   struct parse_events__term *term)
+{
+	struct perf_pmu__format *format;
+	__u64 *vp;
+
+	/*
+	 * Support only for hardcoded and numnerial terms.
+	 * Hardcoded terms should be already in, so nothing
+	 * to be done for them.
+	 */
+	if (parse_events__is_hardcoded_term(term))
+		return 0;
+
+	if (term->type != PARSE_EVENTS__TERM_TYPE_NUM)
+		return -EINVAL;
+
+	format = pmu_find_format(formats, term->config);
+	if (!format)
+		return -EINVAL;
+
+	switch (format->value) {
+	case PERF_PMU_FORMAT_VALUE_CONFIG:
+		vp = &attr->config;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG1:
+		vp = &attr->config1;
+		break;
+	case PERF_PMU_FORMAT_VALUE_CONFIG2:
+		vp = &attr->config2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*vp |= pmu_format_value(format->bits, term->val.num);
+	return 0;
+}
+
+static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
+		      struct list_head *head_terms)
+{
+	struct parse_events__term *term, *h;
+
+	list_for_each_entry_safe(term, h, head_terms, list)
+		if (pmu_config_term(formats, attr, term))
+			return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * Configures event's 'attr' parameter based on the:
+ * 1) users input - specified in terms parameter
+ * 2) pmu format definitions - specified by pmu parameter
+ */
+int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
+		     struct list_head *head_terms)
+{
+	attr->type = pmu->type;
+	return pmu_config(&pmu->format, attr, head_terms);
+}
+
+int perf_pmu__new_format(struct list_head *list, char *name,
+			 int config, unsigned long *bits)
+{
+	struct perf_pmu__format *format;
+
+	format = zalloc(sizeof(*format));
+	if (!format)
+		return -ENOMEM;
+
+	format->name = strdup(name);
+	format->value = config;
+	memcpy(format->bits, bits, sizeof(format->bits));
+
+	list_add_tail(&format->list, list);
+	return 0;
+}
+
+void perf_pmu__set_format(unsigned long *bits, long from, long to)
+{
+	long b;
+
+	if (!to)
+		to = from;
+
+	memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS));
+	for (b = from; b <= to; b++)
+		set_bit(b, bits);
+}
+
+/* Simulated format definitions. */
+static struct test_format {
+	const char *name;
+	const char *value;
+} test_formats[] = {
+	{ "krava01", "config:0-1,62-63\n", },
+	{ "krava02", "config:10-17\n", },
+	{ "krava03", "config:5\n", },
+	{ "krava11", "config1:0,2,4,6,8,20-28\n", },
+	{ "krava12", "config1:63\n", },
+	{ "krava13", "config1:45-47\n", },
+	{ "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
+	{ "krava22", "config2:8,18,48,58\n", },
+	{ "krava23", "config2:28-29,38\n", },
+};
+
+#define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
+
+/* Simulated users input. */
+static struct parse_events__term test_terms[] = {
+	{
+		.config  = (char *) "krava01",
+		.val.num = 15,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char *) "krava02",
+		.val.num = 170,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char *) "krava03",
+		.val.num = 1,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char *) "krava11",
+		.val.num = 27,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char *) "krava12",
+		.val.num = 1,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char *) "krava13",
+		.val.num = 2,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char *) "krava21",
+		.val.num = 119,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char *) "krava22",
+		.val.num = 11,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+	{
+		.config  = (char *) "krava23",
+		.val.num = 2,
+		.type    = PARSE_EVENTS__TERM_TYPE_NUM,
+	},
+};
+#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
+
+/*
+ * Prepare format directory data, exported by kernel
+ * at /sys/bus/event_source/devices/<dev>/format.
+ */
+static char *test_format_dir_get(void)
+{
+	static char dir[PATH_MAX];
+	unsigned int i;
+
+	snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
+	if (!mkdtemp(dir))
+		return NULL;
+
+	for (i = 0; i < TEST_FORMATS_CNT; i++) {
+		static char name[PATH_MAX];
+		struct test_format *format = &test_formats[i];
+		FILE *file;
+
+		snprintf(name, PATH_MAX, "%s/%s", dir, format->name);
+
+		file = fopen(name, "w");
+		if (!file)
+			return NULL;
+
+		if (1 != fwrite(format->value, strlen(format->value), 1, file))
+			break;
+
+		fclose(file);
+	}
+
+	return dir;
+}
+
+/* Cleanup format directory. */
+static int test_format_dir_put(char *dir)
+{
+	char buf[PATH_MAX];
+	snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir);
+	if (system(buf))
+		return -1;
+
+	snprintf(buf, PATH_MAX, "rmdir %s\n", dir);
+	return system(buf);
+}
+
+static struct list_head *test_terms_list(void)
+{
+	static LIST_HEAD(terms);
+	unsigned int i;
+
+	for (i = 0; i < TERMS_CNT; i++)
+		list_add_tail(&test_terms[i].list, &terms);
+
+	return &terms;
+}
+
+#undef TERMS_CNT
+
+int perf_pmu__test(void)
+{
+	char *format = test_format_dir_get();
+	LIST_HEAD(formats);
+	struct list_head *terms = test_terms_list();
+	int ret;
+
+	if (!format)
+		return -EINVAL;
+
+	do {
+		struct perf_event_attr attr;
+
+		memset(&attr, 0, sizeof(attr));
+
+		ret = pmu_format_parse(format, &formats);
+		if (ret)
+			break;
+
+		ret = pmu_config(&formats, &attr, terms);
+		if (ret)
+			break;
+
+		ret = -EINVAL;
+
+		if (attr.config  != 0xc00000000002a823)
+			break;
+		if (attr.config1 != 0x8000400000000145)
+			break;
+		if (attr.config2 != 0x0400000020041d07)
+			break;
+
+		ret = 0;
+	} while (0);
+
+	test_format_dir_put(format);
+	return ret;
+}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
new file mode 100644
index 0000000..68c0db9
--- /dev/null
+++ b/tools/perf/util/pmu.h
@@ -0,0 +1,41 @@
+#ifndef __PMU_H
+#define __PMU_H
+
+#include <linux/bitops.h>
+#include "../../../include/linux/perf_event.h"
+
+enum {
+	PERF_PMU_FORMAT_VALUE_CONFIG,
+	PERF_PMU_FORMAT_VALUE_CONFIG1,
+	PERF_PMU_FORMAT_VALUE_CONFIG2,
+};
+
+#define PERF_PMU_FORMAT_BITS 64
+
+struct perf_pmu__format {
+	char *name;
+	int value;
+	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
+	struct list_head list;
+};
+
+struct perf_pmu {
+	char *name;
+	__u32 type;
+	struct list_head format;
+	struct list_head list;
+};
+
+struct perf_pmu *perf_pmu__find(char *name);
+int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
+		     struct list_head *head_terms);
+
+int perf_pmu_wrap(void);
+void perf_pmu_error(struct list_head *list, char *name, char const *msg);
+
+int perf_pmu__new_format(struct list_head *list, char *name,
+			 int config, unsigned long *bits);
+void perf_pmu__set_format(unsigned long *bits, long from, long to);
+
+int perf_pmu__test(void);
+#endif /* __PMU_H */
diff --git a/tools/perf/util/pmu.l b/tools/perf/util/pmu.l
new file mode 100644
index 0000000..a15d9fb
--- /dev/null
+++ b/tools/perf/util/pmu.l
@@ -0,0 +1,43 @@
+%option prefix="perf_pmu_"
+
+%{
+#include <stdlib.h>
+#include <linux/bitops.h>
+#include "pmu.h"
+#include "pmu-bison.h"
+
+static int value(int base)
+{
+	long num;
+
+	errno = 0;
+	num = strtoul(perf_pmu_text, NULL, base);
+	if (errno)
+		return PP_ERROR;
+
+	perf_pmu_lval.num = num;
+	return PP_VALUE;
+}
+
+%}
+
+num_dec         [0-9]+
+
+%%
+
+{num_dec}	{ return value(10); }
+config		{ return PP_CONFIG; }
+config1		{ return PP_CONFIG1; }
+config2		{ return PP_CONFIG2; }
+-		{ return '-'; }
+:		{ return ':'; }
+,		{ return ','; }
+.		{ ; }
+\n		{ ; }
+
+%%
+
+int perf_pmu_wrap(void)
+{
+	return 1;
+}
diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y
new file mode 100644
index 0000000..20ea77e
--- /dev/null
+++ b/tools/perf/util/pmu.y
@@ -0,0 +1,93 @@
+
+%name-prefix "perf_pmu_"
+%parse-param {struct list_head *format}
+%parse-param {char *name}
+
+%{
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include <linux/bitmap.h>
+#include <string.h>
+#include "pmu.h"
+
+extern int perf_pmu_lex (void);
+
+#define ABORT_ON(val) \
+do { \
+        if (val) \
+                YYABORT; \
+} while (0)
+
+%}
+
+%token PP_CONFIG PP_CONFIG1 PP_CONFIG2
+%token PP_VALUE PP_ERROR
+%type <num> PP_VALUE
+%type <bits> bit_term
+%type <bits> bits
+
+%union
+{
+	unsigned long num;
+	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
+}
+
+%%
+
+format:
+format format_term
+|
+format_term
+
+format_term:
+PP_CONFIG ':' bits
+{
+	ABORT_ON(perf_pmu__new_format(format, name,
+				      PERF_PMU_FORMAT_VALUE_CONFIG,
+				      $3));
+}
+|
+PP_CONFIG1 ':' bits
+{
+	ABORT_ON(perf_pmu__new_format(format, name,
+				      PERF_PMU_FORMAT_VALUE_CONFIG1,
+				      $3));
+}
+|
+PP_CONFIG2 ':' bits
+{
+	ABORT_ON(perf_pmu__new_format(format, name,
+				      PERF_PMU_FORMAT_VALUE_CONFIG2,
+				      $3));
+}
+
+bits:
+bits ',' bit_term
+{
+	bitmap_or($$, $1, $3, 64);
+}
+|
+bit_term
+{
+	memcpy($$, $1, sizeof($1));
+}
+
+bit_term:
+PP_VALUE '-' PP_VALUE
+{
+	perf_pmu__set_format($$, $1, $3);
+}
+|
+PP_VALUE
+{
+	perf_pmu__set_format($$, $1, 0);
+}
+
+%%
+
+void perf_pmu_error(struct list_head *list __used,
+		    char *name __used,
+		    char const *msg __used)
+{
+}
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 2cc162d..d448984 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -972,10 +972,12 @@
 	struct dwarf_callback_param *param = data;
 	struct probe_finder *pf = param->data;
 	struct perf_probe_point *pp = &pf->pev->point;
+	Dwarf_Attribute attr;
 
 	/* Check tag and diename */
 	if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
-	    !die_compare_name(sp_die, pp->function))
+	    !die_compare_name(sp_die, pp->function) ||
+	    dwarf_attr(sp_die, DW_AT_declaration, &attr))
 		return DWARF_CB_OK;
 
 	/* Check declared file */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 002ebbf..9412e3b 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -140,6 +140,7 @@
 	INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
 	INIT_LIST_HEAD(&self->ordered_samples.to_free);
 	machine__init(&self->host_machine, "", HOST_KERNEL_ID);
+	hists__init(&self->hists);
 
 	if (mode == O_RDONLY) {
 		if (perf_session__open(self, force) < 0)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 5dd83c3..c0a028c 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,6 +1,5 @@
 #include <dirent.h>
 #include <errno.h>
-#include <libgen.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -51,6 +50,8 @@
 
 int dso__name_len(const struct dso *dso)
 {
+	if (!dso)
+		return strlen("[unknown]");
 	if (verbose)
 		return dso->long_name_len;
 
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index a4088ce..dfd1bd8 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -722,7 +722,7 @@
 static int event_read_id(void)
 {
 	char *token;
-	int id;
+	int id = -1;
 
 	if (read_expected_item(EVENT_ITEM, "ID") < 0)
 		return -1;
@@ -731,15 +731,13 @@
 		return -1;
 
 	if (read_expect_type(EVENT_ITEM, &token) < 0)
-		goto fail;
+		goto free;
 
 	id = strtoul(token, NULL, 0);
+
+ free:
 	free_token(token);
 	return id;
-
- fail:
-	free_token(token);
-	return -1;
 }
 
 static int field_is_string(struct format_field *field)
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
index 84d761b..6ee82f6 100644
--- a/tools/perf/util/ui/browser.h
+++ b/tools/perf/util/ui/browser.h
@@ -49,6 +49,8 @@
 			const char *format, ...);
 int ui_browser__help_window(struct ui_browser *browser, const char *text);
 bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
+int ui_browser__input_window(const char *title, const char *text, char *input,
+			     const char *exit_msg, int delay_sec);
 
 void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
 unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index fa530fc..d7a1c4a 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -879,6 +879,7 @@
 	char *options[16];
 	int nr_options = 0;
 	int key = -1;
+	char buf[64];
 
 	if (browser == NULL)
 		return -1;
@@ -933,6 +934,16 @@
 			goto zoom_dso;
 		case 't':
 			goto zoom_thread;
+		case 's':
+			if (ui_browser__input_window("Symbol to show",
+					"Please enter the name of symbol you want to see",
+					buf, "ENTER: OK, ESC: Cancel",
+					delay_secs * 2) == K_ENTER) {
+				self->symbol_filter_str = *buf ? buf : NULL;
+				hists__filter_by_symbol(self);
+				hist_browser__reset(browser);
+			}
+			continue;
 		case K_F1:
 		case 'h':
 		case '?':
@@ -950,7 +961,8 @@
 					"C             Collapse all callchains\n"
 					"E             Expand all callchains\n"
 					"d             Zoom into current DSO\n"
-					"t             Zoom into current Thread");
+					"t             Zoom into current Thread\n"
+					"s             Filter symbol by name");
 			continue;
 		case K_ENTER:
 		case K_RIGHT:
diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/util/ui/keysyms.h
index 3458b19..809eca5 100644
--- a/tools/perf/util/ui/keysyms.h
+++ b/tools/perf/util/ui/keysyms.h
@@ -16,6 +16,8 @@
 #define K_TAB	'\t'
 #define K_UNTAB	SL_KEY_UNTAB
 #define K_UP	SL_KEY_UP
+#define K_BKSPC 0x7f
+#define K_DEL	SL_KEY_DELETE
 
 /* Not really keys */
 #define K_TIMER	 -1
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c
index 45daa7c..ad4374a 100644
--- a/tools/perf/util/ui/util.c
+++ b/tools/perf/util/ui/util.c
@@ -69,6 +69,88 @@
 	return popup_menu__run(&menu);
 }
 
+int ui_browser__input_window(const char *title, const char *text, char *input,
+			     const char *exit_msg, int delay_secs)
+{
+	int x, y, len, key;
+	int max_len = 60, nr_lines = 0;
+	static char buf[50];
+	const char *t;
+
+	t = text;
+	while (1) {
+		const char *sep = strchr(t, '\n');
+
+		if (sep == NULL)
+			sep = strchr(t, '\0');
+		len = sep - t;
+		if (max_len < len)
+			max_len = len;
+		++nr_lines;
+		if (*sep == '\0')
+			break;
+		t = sep + 1;
+	}
+
+	max_len += 2;
+	nr_lines += 8;
+	y = SLtt_Screen_Rows / 2 - nr_lines / 2;
+	x = SLtt_Screen_Cols / 2 - max_len / 2;
+
+	SLsmg_set_color(0);
+	SLsmg_draw_box(y, x++, nr_lines, max_len);
+	if (title) {
+		SLsmg_gotorc(y, x + 1);
+		SLsmg_write_string((char *)title);
+	}
+	SLsmg_gotorc(++y, x);
+	nr_lines -= 7;
+	max_len -= 2;
+	SLsmg_write_wrapped_string((unsigned char *)text, y, x,
+				   nr_lines, max_len, 1);
+	y += nr_lines;
+	len = 5;
+	while (len--) {
+		SLsmg_gotorc(y + len - 1, x);
+		SLsmg_write_nstring((char *)" ", max_len);
+	}
+	SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
+
+	SLsmg_gotorc(y + 3, x);
+	SLsmg_write_nstring((char *)exit_msg, max_len);
+	SLsmg_refresh();
+
+	x += 2;
+	len = 0;
+	key = ui__getch(delay_secs);
+	while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
+		if (key == K_BKSPC) {
+			if (len == 0)
+				goto next_key;
+			SLsmg_gotorc(y, x + --len);
+			SLsmg_write_char(' ');
+		} else {
+			buf[len] = key;
+			SLsmg_gotorc(y, x + len++);
+			SLsmg_write_char(key);
+		}
+		SLsmg_refresh();
+
+		/* XXX more graceful overflow handling needed */
+		if (len == sizeof(buf) - 1) {
+			ui_helpline__push("maximum size of symbol name reached!");
+			key = K_ENTER;
+			break;
+		}
+next_key:
+		key = ui__getch(delay_secs);
+	}
+
+	buf[len] = '\0';
+	strncpy(input, buf, len+1);
+	return key;
+}
+
 int ui__question_window(const char *title, const char *text,
 			const char *exit_msg, int delay_secs)
 {
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
index e8a03ac..a93e06c 100644
--- a/tools/power/cpupower/Makefile
+++ b/tools/power/cpupower/Makefile
@@ -19,6 +19,16 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 #
+OUTPUT=./
+ifeq ("$(origin O)", "command line")
+	OUTPUT := $(O)/
+endif
+
+ifneq ($(OUTPUT),)
+# check that the output directory actually exists
+OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
+$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
+endif
 
 # --- CONFIGURATION BEGIN ---
 
@@ -87,6 +97,7 @@
 STRIP = $(CROSS)strip
 RANLIB = $(CROSS)ranlib
 HOSTCC = gcc
+MKDIR = mkdir
 
 
 # Now we set up the build system
@@ -95,7 +106,7 @@
 # set up PWD so that older versions of make will work with our build.
 PWD = $(shell pwd)
 
-GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo po/$$HLANG.gmo; done;}
+GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo $(OUTPUT)po/$$HLANG.gmo; done;}
 
 export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS
 
@@ -122,15 +133,18 @@
 	utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \
 	utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o
 
+UTIL_SRC := $(UTIL_OBJS:.o=.c)
+
+UTIL_OBJS := $(addprefix $(OUTPUT),$(UTIL_OBJS))
+
 UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \
 	utils/helpers/bitmask.h \
 	utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def
 
-UTIL_SRC := $(UTIL_OBJS:.o=.c)
-
 LIB_HEADERS = 	lib/cpufreq.h lib/sysfs.h
 LIB_SRC = 	lib/cpufreq.c lib/sysfs.c
 LIB_OBJS = 	lib/cpufreq.o lib/sysfs.o
+LIB_OBJS :=	$(addprefix $(OUTPUT),$(LIB_OBJS))
 
 CFLAGS +=	-pipe
 
@@ -168,83 +182,90 @@
 
 # the actual make rules
 
-all: libcpupower cpupower $(COMPILE_NLS) $(COMPILE_BENCH)
+all: libcpupower $(OUTPUT)cpupower $(COMPILE_NLS) $(COMPILE_BENCH)
 
-lib/%.o: $(LIB_SRC) $(LIB_HEADERS)
+$(OUTPUT)lib/%.o: $(LIB_SRC) $(LIB_HEADERS)
 	$(ECHO) "  CC      " $@
 	$(QUIET) $(CC) $(CFLAGS) -fPIC -o $@ -c lib/$*.c
 
-libcpupower.so.$(LIB_MAJ): $(LIB_OBJS)
+$(OUTPUT)libcpupower.so.$(LIB_MAJ): $(LIB_OBJS)
 	$(ECHO) "  LD      " $@
 	$(QUIET) $(CC) -shared $(CFLAGS) $(LDFLAGS) -o $@ \
 		-Wl,-soname,libcpupower.so.$(LIB_MIN) $(LIB_OBJS)
-	@ln -sf $@ libcpupower.so
-	@ln -sf $@ libcpupower.so.$(LIB_MIN)
+	@ln -sf $(@F) $(OUTPUT)libcpupower.so
+	@ln -sf $(@F) $(OUTPUT)libcpupower.so.$(LIB_MIN)
 
-libcpupower: libcpupower.so.$(LIB_MAJ)
+libcpupower: $(OUTPUT)libcpupower.so.$(LIB_MAJ)
 
 # Let all .o files depend on its .c file and all headers
 # Might be worth to put this into utils/Makefile at some point of time
 $(UTIL_OBJS): $(UTIL_HEADERS)
 
-.c.o:
+$(OUTPUT)%.o: %.c
 	$(ECHO) "  CC      " $@
 	$(QUIET) $(CC) $(CFLAGS) -I./lib -I ./utils -o $@ -c $*.c
 
-cpupower: $(UTIL_OBJS) libcpupower.so.$(LIB_MAJ)
+$(OUTPUT)cpupower: $(UTIL_OBJS) $(OUTPUT)libcpupower.so.$(LIB_MAJ)
 	$(ECHO) "  CC      " $@
-	$(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) -lcpupower -lrt -lpci -L. -o $@ $(UTIL_OBJS)
+	$(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -lrt -lpci -L$(OUTPUT) -o $@
 	$(QUIET) $(STRIPCMD) $@
 
-po/$(PACKAGE).pot: $(UTIL_SRC)
+$(OUTPUT)po/$(PACKAGE).pot: $(UTIL_SRC)
 	$(ECHO) "  GETTEXT " $@
 	$(QUIET) xgettext --default-domain=$(PACKAGE) --add-comments \
-		--keyword=_ --keyword=N_ $(UTIL_SRC) && \
-	test -f $(PACKAGE).po && \
-	mv -f $(PACKAGE).po po/$(PACKAGE).pot
+		--keyword=_ --keyword=N_ $(UTIL_SRC) -p $(@D) -o $(@F)
 
-po/%.gmo: po/%.po
+$(OUTPUT)po/%.gmo: po/%.po
 	$(ECHO) "  MSGFMT  " $@
 	$(QUIET) msgfmt -o $@ po/$*.po
 
 create-gmo: ${GMO_FILES}
 
-update-po: po/$(PACKAGE).pot
+update-po: $(OUTPUT)po/$(PACKAGE).pot
 	$(ECHO) "  MSGMRG  " $@
 	$(QUIET) @for HLANG in $(LANGUAGES); do \
 		echo -n "Updating $$HLANG "; \
-		if msgmerge po/$$HLANG.po po/$(PACKAGE).pot -o \
-		   po/$$HLANG.new.po; then \
-			mv -f po/$$HLANG.new.po po/$$HLANG.po; \
+		if msgmerge po/$$HLANG.po $< -o \
+		   $(OUTPUT)po/$$HLANG.new.po; then \
+			mv -f $(OUTPUT)po/$$HLANG.new.po $(OUTPUT)po/$$HLANG.po; \
 		else \
 			echo "msgmerge for $$HLANG failed!"; \
-			rm -f po/$$HLANG.new.po; \
+			rm -f $(OUTPUT)po/$$HLANG.new.po; \
 		fi; \
 	done;
 
-compile-bench: libcpupower.so.$(LIB_MAJ)
-	@V=$(V) confdir=$(confdir) $(MAKE) -C bench
+compile-bench: $(OUTPUT)libcpupower.so.$(LIB_MAJ)
+	@V=$(V) confdir=$(confdir) $(MAKE) -C bench O=$(OUTPUT)
+
+# we compile into subdirectories. if the target directory is not the
+# source directory, they might not exists. So we depend the various
+# files onto their directories.
+DIRECTORY_DEPS = $(LIB_OBJS) $(UTIL_OBJS) $(GMO_FILES)
+$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS)))
+
+# In the second step, we make a rule to actually create these directories
+$(sort $(dir $(DIRECTORY_DEPS))):
+	$(ECHO) "  MKDIR      " $@
+	$(QUIET) $(MKDIR) -p $@ 2>/dev/null
 
 clean:
-	-find . \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \
+	-find $(OUTPUT) \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \
 	 | xargs rm -f
-	-rm -f $(UTIL_BINS)
-	-rm -f $(IDLE_OBJS)
-	-rm -f cpupower
-	-rm -f libcpupower.so*
-	-rm -rf po/*.gmo po/*.pot
-	$(MAKE) -C bench clean
+	-rm -f $(OUTPUT)cpupower
+	-rm -f $(OUTPUT)libcpupower.so*
+	-rm -rf $(OUTPUT)po/*.{gmo,pot}
+	$(MAKE) -C bench O=$(OUTPUT) clean
 
 
 install-lib:
 	$(INSTALL) -d $(DESTDIR)${libdir}
-	$(CP) libcpupower.so* $(DESTDIR)${libdir}/
+	$(CP) $(OUTPUT)libcpupower.so* $(DESTDIR)${libdir}/
 	$(INSTALL) -d $(DESTDIR)${includedir}
 	$(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h
 
 install-tools:
 	$(INSTALL) -d $(DESTDIR)${bindir}
-	$(INSTALL_PROGRAM) cpupower $(DESTDIR)${bindir}
+	$(INSTALL_PROGRAM) $(OUTPUT)cpupower $(DESTDIR)${bindir}
 
 install-man:
 	$(INSTALL_DATA) -D man/cpupower.1 $(DESTDIR)${mandir}/man1/cpupower.1
@@ -257,13 +278,13 @@
 install-gmo:
 	$(INSTALL) -d $(DESTDIR)${localedir}
 	for HLANG in $(LANGUAGES); do \
-		echo '$(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo'; \
-		$(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \
+		echo '$(INSTALL_DATA) -D $(OUTPUT)po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo'; \
+		$(INSTALL_DATA) -D $(OUTPUT)po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \
 	done;
 
 install-bench:
 	@#DESTDIR must be set from outside to survive
-	@sbindir=$(sbindir) bindir=$(bindir) docdir=$(docdir) confdir=$(confdir) $(MAKE) -C bench install
+	@sbindir=$(sbindir) bindir=$(bindir) docdir=$(docdir) confdir=$(confdir) $(MAKE) -C bench O=$(OUTPUT) install
 
 install: all install-lib install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH)
 
diff --git a/tools/power/cpupower/bench/Makefile b/tools/power/cpupower/bench/Makefile
index 2b67606..7ec7021 100644
--- a/tools/power/cpupower/bench/Makefile
+++ b/tools/power/cpupower/bench/Makefile
@@ -1,29 +1,36 @@
-LIBS = -L../ -lm -lcpupower
+OUTPUT := ./
+ifeq ("$(origin O)", "command line")
+ifneq ($(O),)
+	OUTPUT := $(O)/
+endif
+endif
 
-OBJS = main.o parse.o system.o benchmark.o
+LIBS = -L../ -L$(OUTPUT) -lm -lcpupower
+
+OBJS = $(OUTPUT)main.o $(OUTPUT)parse.o $(OUTPUT)system.o $(OUTPUT)benchmark.o
 CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\"
 
-%.o : %.c
+$(OUTPUT)%.o : %.c
 	$(ECHO) "  CC      " $@
 	$(QUIET) $(CC) -c $(CFLAGS) $< -o $@
 
-cpufreq-bench: $(OBJS)
+$(OUTPUT)cpufreq-bench: $(OBJS)
 	$(ECHO) "  CC      " $@
 	$(QUIET) $(CC) -o $@ $(CFLAGS) $(OBJS) $(LIBS)
 
-all: cpufreq-bench
+all: $(OUTPUT)cpufreq-bench
 
 install:
 	mkdir -p $(DESTDIR)/$(sbindir)
 	mkdir -p $(DESTDIR)/$(bindir)
 	mkdir -p $(DESTDIR)/$(docdir)
 	mkdir -p $(DESTDIR)/$(confdir)
-	install -m 755 cpufreq-bench $(DESTDIR)/$(sbindir)/cpufreq-bench
+	install -m 755 $(OUTPUT)cpufreq-bench $(DESTDIR)/$(sbindir)/cpufreq-bench
 	install -m 755 cpufreq-bench_plot.sh $(DESTDIR)/$(bindir)/cpufreq-bench_plot.sh
 	install -m 644 README-BENCH $(DESTDIR)/$(docdir)/README-BENCH
 	install -m 755 cpufreq-bench_script.sh $(DESTDIR)/$(docdir)/cpufreq-bench_script.sh
 	install -m 644 example.cfg $(DESTDIR)/$(confdir)/cpufreq-bench.conf
 
 clean:
-	rm -f *.o
-	rm -f cpufreq-bench
+	rm -f $(OUTPUT)*.o
+	rm -f $(OUTPUT)cpufreq-bench
diff --git a/tools/power/cpupower/debug/i386/Makefile b/tools/power/cpupower/debug/i386/Makefile
index d08cc1e..3ba158f 100644
--- a/tools/power/cpupower/debug/i386/Makefile
+++ b/tools/power/cpupower/debug/i386/Makefile
@@ -1,20 +1,38 @@
+OUTPUT=./
+ifeq ("$(origin O)", "command line")
+	OUTPUT := $(O)/
+endif
+
+DESTDIR =
+bindir  = /usr/bin
+
+INSTALL = /usr/bin/install
+
+
 default: all
 
-centrino-decode: centrino-decode.c
-	$(CC) $(CFLAGS) -o centrino-decode centrino-decode.c
+$(OUTPUT)centrino-decode: centrino-decode.c
+	$(CC) $(CFLAGS) -o $@ centrino-decode.c
 
-dump_psb: dump_psb.c
-	$(CC) $(CFLAGS) -o dump_psb dump_psb.c
+$(OUTPUT)dump_psb: dump_psb.c
+	$(CC) $(CFLAGS) -o $@ dump_psb.c
 
-intel_gsic: intel_gsic.c
-	$(CC) $(CFLAGS) -o intel_gsic -llrmi intel_gsic.c
+$(OUTPUT)intel_gsic: intel_gsic.c
+	$(CC) $(CFLAGS) -o $@ -llrmi intel_gsic.c
 
-powernow-k8-decode: powernow-k8-decode.c
-	$(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c
+$(OUTPUT)powernow-k8-decode: powernow-k8-decode.c
+	$(CC) $(CFLAGS) -o $@ powernow-k8-decode.c
 
-all: centrino-decode dump_psb intel_gsic powernow-k8-decode
+all: $(OUTPUT)centrino-decode $(OUTPUT)dump_psb $(OUTPUT)intel_gsic $(OUTPUT)powernow-k8-decode
 
 clean:
-	rm -rf centrino-decode dump_psb intel_gsic powernow-k8-decode
+	rm -rf $(OUTPUT){centrino-decode,dump_psb,intel_gsic,powernow-k8-decode}
 
-.PHONY: all default clean
+install:
+	$(INSTALL) -d $(DESTDIR)${bindir}
+	$(INSTALL) $(OUTPUT)centrino-decode $(DESTDIR)${bindir}
+	$(INSTALL) $(OUTPUT)powernow-k8-decode $(DESTDIR)${bindir}
+	$(INSTALL) $(OUTPUT)dump_psb $(DESTDIR)${bindir}
+	$(INSTALL) $(OUTPUT)intel_gsic $(DESTDIR)${bindir}
+
+.PHONY: all default clean install
diff --git a/tools/power/cpupower/debug/x86_64/Makefile b/tools/power/cpupower/debug/x86_64/Makefile
index 3326217..1c52145 100644
--- a/tools/power/cpupower/debug/x86_64/Makefile
+++ b/tools/power/cpupower/debug/x86_64/Makefile
@@ -1,14 +1,30 @@
+OUTPUT=./
+ifeq ("$(origin O)", "command line")
+	OUTPUT := $(O)/
+endif
+
+DESTDIR =
+bindir  = /usr/bin
+
+INSTALL = /usr/bin/install
+
+
 default: all
 
-centrino-decode: ../i386/centrino-decode.c
+$(OUTPUT)centrino-decode: ../i386/centrino-decode.c
 	$(CC) $(CFLAGS) -o $@ $<
 
-powernow-k8-decode: ../i386/powernow-k8-decode.c
+$(OUTPUT)powernow-k8-decode: ../i386/powernow-k8-decode.c
 	$(CC) $(CFLAGS) -o $@ $<
 
-all: centrino-decode powernow-k8-decode
+all: $(OUTPUT)centrino-decode $(OUTPUT)powernow-k8-decode
 
 clean:
-	rm -rf centrino-decode powernow-k8-decode
+	rm -rf $(OUTPUT)centrino-decode $(OUTPUT)powernow-k8-decode
 
-.PHONY: all default clean
+install:
+	$(INSTALL) -d $(DESTDIR)${bindir}
+	$(INSTALL) $(OUTPUT)centrino-decode $(DESTDIR)${bindir}
+	$(INSTALL) $(OUTPUT)powernow-k8-decode $(DESTDIR)${bindir}
+
+.PHONY: all default clean install
diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1
index bb60a8d..4a1918e 100644
--- a/tools/power/cpupower/man/cpupower-frequency-info.1
+++ b/tools/power/cpupower/man/cpupower-frequency-info.1
@@ -1,4 +1,4 @@
-.TH "cpupower-frequency-info" "1" "0.1" "Mattia Dongili" ""
+.TH "CPUPOWER\-FREQUENCY\-INFO" "1" "0.1" "" "cpupower Manual"
 .SH "NAME"
 .LP 
 cpupower frequency\-info \- Utility to retrieve cpufreq kernel information
@@ -50,8 +50,6 @@
 \fB\-m\fR \fB\-\-human\fR
 human\-readable output for the \-f, \-w, \-s and \-y parameters.
 .TP  
-\fB\-h\fR \fB\-\-help\fR
-Prints out the help screen.
 .SH "REMARKS"
 .LP 
 By default only values of core zero are displayed. How to display settings of
diff --git a/tools/power/cpupower/man/cpupower-frequency-set.1 b/tools/power/cpupower/man/cpupower-frequency-set.1
index 685f469..3eacc8d 100644
--- a/tools/power/cpupower/man/cpupower-frequency-set.1
+++ b/tools/power/cpupower/man/cpupower-frequency-set.1
@@ -1,4 +1,4 @@
-.TH "cpupower-freqency-set" "1" "0.1" "Mattia Dongili" ""
+.TH "CPUPOWER\-FREQUENCY\-SET" "1" "0.1" "" "cpupower Manual"
 .SH "NAME"
 .LP 
 cpupower frequency\-set \- A small tool which allows to modify cpufreq settings.
@@ -26,8 +26,6 @@
 \fB\-r\fR \fB\-\-related\fR
 modify all hardware-related CPUs at the same time
 .TP 
-\fB\-h\fR \fB\-\-help\fR
-Prints out the help screen.
 .SH "REMARKS"
 .LP 
 By default values are applied on all cores. How to modify single core
diff --git a/tools/power/cpupower/man/cpupower-idle-info.1 b/tools/power/cpupower/man/cpupower-idle-info.1
new file mode 100644
index 0000000..4178eff
--- /dev/null
+++ b/tools/power/cpupower/man/cpupower-idle-info.1
@@ -0,0 +1,90 @@
+.TH "CPUPOWER-IDLE-INFO" "1" "0.1" "" "cpupower Manual"
+.SH "NAME"
+.LP
+cpupower idle\-info \- Utility to retrieve cpu idle kernel information
+.SH "SYNTAX"
+.LP
+cpupower [ \-c cpulist ] idle\-info [\fIoptions\fP]
+.SH "DESCRIPTION"
+.LP
+A tool which prints out per cpu idle information helpful to developers and interested users.
+.SH "OPTIONS"
+.LP
+.TP
+\fB\-f\fR \fB\-\-silent\fR
+Only print a summary of all available C-states in the system.
+.TP
+\fB\-e\fR \fB\-\-proc\fR
+deprecated.
+Prints out idle information in old /proc/acpi/processor/*/power format. This
+interface has been removed from the kernel for quite some time, do not let
+further code depend on this option, best do not use it.
+
+.SH IDLE\-INFO DESCRIPTIONS
+CPU sleep state statistics and descriptions are retrieved from sysfs files,
+exported by the cpuidle kernel subsystem. The kernel only updates these
+statistics when it enters or leaves an idle state, therefore on a very idle or
+a very busy system, these statistics may not be accurate. They still provide a
+good overview about the usage and availability of processor sleep states on
+the platform.
+
+Be aware that the sleep states as exported by the hardware or BIOS and used by
+the Linux kernel may not exactly reflect the capabilities of the
+processor. This often is the case on the X86 architecture when the acpi_idle
+driver is used. It is also possible that the hardware overrules the kernel
+requests, due to internal activity monitors or other reasons.
+On recent X86 platforms it is often possible to read out hardware registers
+which monitor the duration of sleep states the processor resided in. The
+cpupower monitor tool (cpupower\-monitor(1)) can be used to show real sleep
+state residencies. Please refer to the architecture specific description
+section below.
+
+.SH IDLE\-INFO ARCHITECTURE SPECIFIC DESCRIPTIONS
+.SS "X86"
+POLL idle state
+
+If cpuidle is active, X86 platforms have one special idle state.
+The POLL idle state is not a real idle state, it does not save any
+power. Instead, a busy\-loop is executed doing nothing for a short period of
+time. This state is used if the kernel knows that work has to be processed
+very soon and entering any real hardware idle state may result in a slight
+performance penalty.
+
+There exist two different cpuidle drivers on the X86 architecture platform:
+
+"acpi_idle" cpuidle driver
+
+The acpi_idle cpuidle driver retrieves available sleep states (C\-states) from
+the ACPI BIOS tables (from the _CST ACPI function on recent platforms or from
+the FADT BIOS table on older ones).
+The C1 state is not retrieved from ACPI tables. If the C1 state is entered,
+the kernel will call the hlt instruction (or mwait on Intel).
+
+"intel_idle" cpuidle driver
+
+In kernel 2.6.36 the intel_idle driver was introduced.
+It only serves recent Intel CPUs (Nehalem, Westmere, Sandybridge, Atoms or
+newer). On older Intel CPUs the acpi_idle driver is still used (if the BIOS
+provides C\-state ACPI tables).
+The intel_idle driver knows the sleep state capabilities of the processor and
+ignores ACPI BIOS exported processor sleep states tables.
+
+.SH "REMARKS"
+.LP
+By default only values of core zero are displayed. How to display settings of
+other cores is described in the cpupower(1) manpage in the \-\-cpu option
+section.
+.SH REFERENCES
+http://www.acpi.info/spec.htm
+.SH "FILES"
+.nf
+\fI/sys/devices/system/cpu/cpu*/cpuidle/state*\fP
+\fI/sys/devices/system/cpu/cpuidle/*\fP
+.fi
+.SH "AUTHORS"
+.nf
+Thomas Renninger <trenn@suse.de>
+.fi
+.SH "SEE ALSO"
+.LP
+cpupower(1), cpupower\-monitor(1), cpupower\-info(1), cpupower\-set(1)
diff --git a/tools/power/cpupower/man/cpupower-monitor.1 b/tools/power/cpupower/man/cpupower-monitor.1
index d5cfa26..1141c20 100644
--- a/tools/power/cpupower/man/cpupower-monitor.1
+++ b/tools/power/cpupower/man/cpupower-monitor.1
@@ -107,7 +107,7 @@
 sleep states and can only be entered if all cores are idle. Look up Intel
 manuals (some are provided in the References section) for further details.
 
-.SS "Ontario" "Liano"
+.SS "Fam_12h" "Fam_14h"
 AMD laptop and desktop processor (family 12h and 14h) sleep state counters.
 The registers are accessed via PCI and therefore can still be read out while
 cores have been offlined.
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
index b028267..8145af5 100644
--- a/tools/power/cpupower/utils/cpuidle-info.c
+++ b/tools/power/cpupower/utils/cpuidle-info.c
@@ -35,17 +35,9 @@
 		printf(_("CPU %u: Can't read idle state info\n"), cpu);
 		return;
 	}
-	tmp = sysfs_get_idlestate_name(cpu, idlestates - 1);
-	if (!tmp) {
-		printf(_("Could not determine max idle state %u\n"),
-		       idlestates - 1);
-		return;
-	}
-
 	printf(_("Number of idle states: %d\n"), idlestates);
-
 	printf(_("Available idle states:"));
-	for (idlestate = 1; idlestate < idlestates; idlestate++) {
+	for (idlestate = 0; idlestate < idlestates; idlestate++) {
 		tmp = sysfs_get_idlestate_name(cpu, idlestate);
 		if (!tmp)
 			continue;
@@ -57,7 +49,7 @@
 	if (!verbose)
 		return;
 
-	for (idlestate = 1; idlestate < idlestates; idlestate++) {
+	for (idlestate = 0; idlestate < idlestates; idlestate++) {
 		tmp = sysfs_get_idlestate_name(cpu, idlestate);
 		if (!tmp)
 			continue;
diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c
index 87d5605..6437ef3 100644
--- a/tools/power/cpupower/utils/helpers/amd.c
+++ b/tools/power/cpupower/utils/helpers/amd.c
@@ -112,14 +112,12 @@
 int amd_pci_get_num_boost_states(int *active, int *states)
 {
 	struct pci_access *pci_acc;
-	int vendor_id = 0x1022;
-	int boost_dev_ids[4] = {0x1204, 0x1604, 0x1704, 0};
 	struct pci_dev *device;
 	uint8_t val = 0;
 
 	*active = *states = 0;
 
-	device = pci_acc_init(&pci_acc, vendor_id, boost_dev_ids);
+	device = pci_slot_func_init(&pci_acc, 0x18, 4);
 
 	if (device == NULL)
 		return -ENODEV;
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
index 2747e73..2eb584c 100644
--- a/tools/power/cpupower/utils/helpers/helpers.h
+++ b/tools/power/cpupower/utils/helpers/helpers.h
@@ -66,8 +66,8 @@
 #define CPUPOWER_CAP_AMD_CBP		0x00000004
 #define CPUPOWER_CAP_PERF_BIAS		0x00000008
 #define CPUPOWER_CAP_HAS_TURBO_RATIO	0x00000010
-#define CPUPOWER_CAP_IS_SNB		0x00000011
-#define CPUPOWER_CAP_INTEL_IDA		0x00000012
+#define CPUPOWER_CAP_IS_SNB		0x00000020
+#define CPUPOWER_CAP_INTEL_IDA		0x00000040
 
 #define MAX_HW_PSTATES 10
 
@@ -132,8 +132,11 @@
 
 /* PCI stuff ****************************/
 extern int amd_pci_get_num_boost_states(int *active, int *states);
-extern struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id,
-				    int *dev_ids);
+extern struct pci_dev *pci_acc_init(struct pci_access **pacc, int domain,
+				    int bus, int slot, int func, int vendor,
+				    int dev);
+extern struct pci_dev *pci_slot_func_init(struct pci_access **pacc,
+					      int slot, int func);
 
 /* PCI stuff ****************************/
 
diff --git a/tools/power/cpupower/utils/helpers/pci.c b/tools/power/cpupower/utils/helpers/pci.c
index cd2eb6f..9690798 100644
--- a/tools/power/cpupower/utils/helpers/pci.c
+++ b/tools/power/cpupower/utils/helpers/pci.c
@@ -10,19 +10,24 @@
  * **pacc : if a valid pci_dev is returned
  *         *pacc must be passed to pci_acc_cleanup to free it
  *
- * vendor_id : the pci vendor id matching the pci device to access
- * dev_ids :   device ids matching the pci device to access
+ * domain: domain
+ * bus:    bus
+ * slot:   slot
+ * func:   func
+ * vendor: vendor
+ * device: device
+ * Pass -1 for one of the six above to match any
  *
  * Returns :
  * struct pci_dev which can be used with pci_{read,write}_* functions
  *                to access the PCI config space of matching pci devices
  */
-struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id,
-				    int *dev_ids)
+struct pci_dev *pci_acc_init(struct pci_access **pacc, int domain, int bus,
+			     int slot, int func, int vendor, int dev)
 {
-	struct pci_filter filter_nb_link = { -1, -1, -1, -1, vendor_id, 0};
+	struct pci_filter filter_nb_link = { domain, bus, slot, func,
+					     vendor, dev };
 	struct pci_dev *device;
-	unsigned int i;
 
 	*pacc = pci_alloc();
 	if (*pacc == NULL)
@@ -31,14 +36,20 @@
 	pci_init(*pacc);
 	pci_scan_bus(*pacc);
 
-	for (i = 0; dev_ids[i] != 0; i++) {
-		filter_nb_link.device = dev_ids[i];
-		for (device = (*pacc)->devices; device; device = device->next) {
-			if (pci_filter_match(&filter_nb_link, device))
-				return device;
-		}
+	for (device = (*pacc)->devices; device; device = device->next) {
+		if (pci_filter_match(&filter_nb_link, device))
+			return device;
 	}
 	pci_cleanup(*pacc);
 	return NULL;
 }
+
+/* Typically one wants to get a specific slot(device)/func of the root domain
+   and bus */
+struct pci_dev *pci_slot_func_init(struct pci_access **pacc, int slot,
+				       int func)
+{
+	return pci_acc_init(pacc, 0, 0, slot, func, -1, -1);
+}
+
 #endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c
index 202e555..2116df9 100644
--- a/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c
+++ b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c
@@ -20,8 +20,6 @@
 #include "idle_monitor/cpupower-monitor.h"
 #include "helpers/helpers.h"
 
-/******** PCI parts could go into own file and get shared ***************/
-
 #define PCI_NON_PC0_OFFSET	0xb0
 #define PCI_PC1_OFFSET		0xb4
 #define PCI_PC6_OFFSET		0xb8
@@ -82,10 +80,7 @@
 };
 
 static struct pci_access *pci_acc;
-static int pci_vendor_id = 0x1022;
-static int pci_dev_ids[2] = {0x1716, 0};
 static struct pci_dev *amd_fam14h_pci_dev;
-
 static int nbp1_entered;
 
 struct timespec start_time;
@@ -286,13 +281,13 @@
 	if (cpupower_cpu_info.vendor != X86_VENDOR_AMD)
 		return NULL;
 
-	if (cpupower_cpu_info.family == 0x14) {
-		if (cpu_count <= 0 || cpu_count > 2) {
-			fprintf(stderr, "AMD fam14h: Invalid cpu count: %d\n",
-				cpu_count);
-			return NULL;
-		}
-	} else
+	if (cpupower_cpu_info.family == 0x14)
+		strncpy(amd_fam14h_monitor.name, "Fam_14h",
+			MONITOR_NAME_LEN - 1);
+	else if (cpupower_cpu_info.family == 0x12)
+		strncpy(amd_fam14h_monitor.name, "Fam_12h",
+			MONITOR_NAME_LEN - 1);
+	else
 		return NULL;
 
 	/* We do not alloc for nbp1 machine wide counter */
@@ -303,7 +298,9 @@
 					      sizeof(unsigned long long));
 	}
 
-	amd_fam14h_pci_dev = pci_acc_init(&pci_acc, pci_vendor_id, pci_dev_ids);
+	/* We need PCI device: Slot 18, Func 6, compare with BKDG
+	   for fam 12h/14h */
+	amd_fam14h_pci_dev = pci_slot_func_init(&pci_acc, 0x18, 6);
 	if (amd_fam14h_pci_dev == NULL || pci_acc == NULL)
 		return NULL;
 
@@ -325,7 +322,7 @@
 }
 
 struct cpuidle_monitor amd_fam14h_monitor = {
-	.name			= "Ontario",
+	.name			= "",
 	.hw_states		= amd_fam14h_cstates,
 	.hw_states_num		= AMD_FAM14H_STATE_NUM,
 	.start			= amd_fam14h_start,
diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
index 555c69a..adf175f 100644
--- a/tools/power/x86/turbostat/turbostat.8
+++ b/tools/power/x86/turbostat/turbostat.8
@@ -4,11 +4,13 @@
 .SH SYNOPSIS
 .ft B
 .B turbostat
+.RB [ "\-s" ]
 .RB [ "\-v" ]
 .RB [ "\-M MSR#" ]
 .RB command
 .br
 .B turbostat
+.RB [ "\-s" ]
 .RB [ "\-v" ]
 .RB [ "\-M MSR#" ]
 .RB [ "\-i interval_sec" ]
@@ -25,6 +27,8 @@
 on processors that additionally support C-state residency counters.
 
 .SS Options
+The \fB-s\fP option prints only a 1-line summary for each sample interval.
+.PP
 The \fB-v\fP option increases verbosity.
 .PP
 The \fB-M MSR#\fP option dumps the specified MSR,
@@ -39,13 +43,14 @@
 .SH FIELD DESCRIPTIONS
 .nf
 \fBpk\fP processor package number.
-\fBcr\fP processor core number.
+\fBcor\fP processor core number.
 \fBCPU\fP Linux CPU (logical processor) number.
+Note that multiple CPUs per core indicate support for Intel(R) Hyper-Threading Technology.
 \fB%c0\fP percent of the interval that the CPU retired instructions.
 \fBGHz\fP average clock rate while the CPU was in c0 state.
 \fBTSC\fP average GHz that the TSC ran during the entire interval.
-\fB%c1, %c3, %c6\fP show the percentage residency in hardware core idle states.
-\fB%pc3, %pc6\fP percentage residency in hardware package idle states.
+\fB%c1, %c3, %c6, %c7\fP show the percentage residency in hardware core idle states.
+\fB%pc2, %pc3, %pc6, %pc7\fP percentage residency in hardware package idle states.
 .fi
 .PP
 .SH EXAMPLE
@@ -53,25 +58,37 @@
 (override interval with "-i sec" option, or specify a command
 for turbostat to fork).
 
-The first row of statistics reflect the average for the entire system.
+The first row of statistics is a summary for the entire system.
+Note that the summary is a weighted average.
 Subsequent rows show per-CPU statistics.
 
 .nf
 [root@x980]# ./turbostat
-cr   CPU   %c0   GHz  TSC   %c1    %c3    %c6   %pc3   %pc6
-          0.04 1.62 3.38   0.11   0.00  99.85   0.00  95.07
-  0   0   0.04 1.62 3.38   0.06   0.00  99.90   0.00  95.07
-  0   6   0.02 1.62 3.38   0.08   0.00  99.90   0.00  95.07
-  1   2   0.10 1.62 3.38   0.29   0.00  99.61   0.00  95.07
-  1   8   0.11 1.62 3.38   0.28   0.00  99.61   0.00  95.07
-  2   4   0.01 1.62 3.38   0.01   0.00  99.98   0.00  95.07
-  2  10   0.01 1.61 3.38   0.02   0.00  99.98   0.00  95.07
-  8   1   0.07 1.62 3.38   0.15   0.00  99.78   0.00  95.07
-  8   7   0.03 1.62 3.38   0.19   0.00  99.78   0.00  95.07
-  9   3   0.01 1.62 3.38   0.02   0.00  99.98   0.00  95.07
-  9   9   0.01 1.62 3.38   0.02   0.00  99.98   0.00  95.07
- 10   5   0.01 1.62 3.38   0.13   0.00  99.86   0.00  95.07
- 10  11   0.08 1.62 3.38   0.05   0.00  99.86   0.00  95.07
+cor CPU    %c0  GHz  TSC    %c1    %c3    %c6   %pc3   %pc6
+          0.60 1.63 3.38   2.91   0.00  96.49   0.00  76.64
+  0   0   0.59 1.62 3.38   4.51   0.00  94.90   0.00  76.64
+  0   6   1.13 1.64 3.38   3.97   0.00  94.90   0.00  76.64
+  1   2   0.08 1.62 3.38   0.07   0.00  99.85   0.00  76.64
+  1   8   0.03 1.62 3.38   0.12   0.00  99.85   0.00  76.64
+  2   4   0.01 1.62 3.38   0.06   0.00  99.93   0.00  76.64
+  2  10   0.04 1.62 3.38   0.02   0.00  99.93   0.00  76.64
+  8   1   2.85 1.62 3.38  11.71   0.00  85.44   0.00  76.64
+  8   7   1.98 1.62 3.38  12.58   0.00  85.44   0.00  76.64
+  9   3   0.36 1.62 3.38   0.71   0.00  98.93   0.00  76.64
+  9   9   0.09 1.62 3.38   0.98   0.00  98.93   0.00  76.64
+ 10   5   0.03 1.62 3.38   0.09   0.00  99.87   0.00  76.64
+ 10  11   0.07 1.62 3.38   0.06   0.00  99.87   0.00  76.64
+.fi
+.SH SUMMARY EXAMPLE
+The "-s" option prints the column headers just once,
+and then the one line system summary for each sample interval.
+
+.nf
+[root@x980]# ./turbostat -s
+   %c0  GHz  TSC    %c1    %c3    %c6   %pc3   %pc6
+  0.61 1.89 3.38   5.95   0.00  93.44   0.00  66.33
+  0.52 1.62 3.38   6.83   0.00  92.65   0.00  61.11
+  0.62 1.92 3.38   5.47   0.00  93.91   0.00  67.31
 .fi
 .SH VERBOSE EXAMPLE
 The "-v" option adds verbosity to the output:
@@ -101,33 +118,33 @@
 
 .nf
 [root@x980 lenb]# ./turbostat cat /dev/zero > /dev/null
-
-^Ccr   CPU   %c0   GHz  TSC   %c1    %c3    %c6   %pc3   %pc6
-           8.49 3.63 3.38  16.23   0.66  74.63   0.00   0.00
-   0   0   1.22 3.62 3.38  32.18   0.00  66.60   0.00   0.00
-   0   6   0.40 3.61 3.38  33.00   0.00  66.60   0.00   0.00
-   1   2   0.11 3.14 3.38   0.19   3.95  95.75   0.00   0.00
-   1   8   0.05 2.88 3.38   0.25   3.95  95.75   0.00   0.00
-   2   4   0.00 3.13 3.38   0.02   0.00  99.98   0.00   0.00
-   2  10   0.00 3.09 3.38   0.02   0.00  99.98   0.00   0.00
-   8   1   0.04 3.50 3.38  14.43   0.00  85.54   0.00   0.00
-   8   7   0.03 2.98 3.38  14.43   0.00  85.54   0.00   0.00
-   9   3   0.00 3.16 3.38 100.00   0.00   0.00   0.00   0.00
-   9   9  99.93 3.63 3.38   0.06   0.00   0.00   0.00   0.00
-  10   5   0.01 2.82 3.38   0.08   0.00  99.91   0.00   0.00
-  10  11   0.02 3.36 3.38   0.06   0.00  99.91   0.00   0.00
-6.950866 sec
+^C
+cor CPU    %c0  GHz  TSC    %c1    %c3    %c6   %pc3   %pc6
+          8.63 3.64 3.38  14.46   0.49  76.42   0.00   0.00
+  0   0   0.34 3.36 3.38  99.66   0.00   0.00   0.00   0.00
+  0   6  99.96 3.64 3.38   0.04   0.00   0.00   0.00   0.00
+  1   2   0.14 3.50 3.38   1.75   2.04  96.07   0.00   0.00
+  1   8   0.38 3.57 3.38   1.51   2.04  96.07   0.00   0.00
+  2   4   0.01 2.65 3.38   0.06   0.00  99.93   0.00   0.00
+  2  10   0.03 2.12 3.38   0.04   0.00  99.93   0.00   0.00
+  8   1   0.91 3.59 3.38  35.27   0.92  62.90   0.00   0.00
+  8   7   1.61 3.63 3.38  34.57   0.92  62.90   0.00   0.00
+  9   3   0.04 3.38 3.38   0.20   0.00  99.76   0.00   0.00
+  9   9   0.04 3.29 3.38   0.20   0.00  99.76   0.00   0.00
+ 10   5   0.03 3.08 3.38   0.12   0.00  99.85   0.00   0.00
+ 10  11   0.05 3.07 3.38   0.10   0.00  99.85   0.00   0.00
+4.907015 sec
 
 .fi
-Above the cycle soaker drives cpu9 up 3.6 Ghz turbo limit
+Above the cycle soaker drives cpu6 up 3.6 Ghz turbo limit
 while the other processors are generally in various states of idle.
 
-Note that cpu3 is an HT sibling sharing core9
-with cpu9, and thus it is unable to get to an idle state
-deeper than c1 while cpu9 is busy.
+Note that cpu0 is an HT sibling sharing core0
+with cpu6, and thus it is unable to get to an idle state
+deeper than c1 while cpu6 is busy.
 
-Note that turbostat reports average GHz of 3.61, while
-the arithmetic average of the GHz column above is 3.24.
+Note that turbostat reports average GHz of 3.64, while
+the arithmetic average of the GHz column above is lower.
 This is a weighted average, where the weight is %c0.  ie. it is the total number of
 un-halted cycles elapsed per time divided by the number of CPUs.
 .SH NOTES
@@ -167,6 +184,6 @@
 .SH "SEE ALSO"
 msr(4), vmstat(8)
 .PP
-.SH AUTHORS
+.SH AUTHOR
 .nf
 Written by Len Brown <len.brown@intel.com>
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 310d3dd..ab2f682 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -2,7 +2,7 @@
  * turbostat -- show CPU frequency and C-state residency
  * on modern Intel turbo-capable processors.
  *
- * Copyright (c) 2010, Intel Corporation.
+ * Copyright (c) 2012 Intel Corporation.
  * Len Brown <len.brown@intel.com>
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -19,6 +19,7 @@
  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <unistd.h>
 #include <sys/types.h>
@@ -32,6 +33,7 @@
 #include <dirent.h>
 #include <string.h>
 #include <ctype.h>
+#include <sched.h>
 
 #define MSR_TSC	0x10
 #define MSR_NEHALEM_PLATFORM_INFO	0xCE
@@ -49,6 +51,7 @@
 char *proc_stat = "/proc/stat";
 unsigned int interval_sec = 5;	/* set with -i interval_sec */
 unsigned int verbose;		/* set with -v */
+unsigned int summary_only;	/* set with -s */
 unsigned int skip_c0;
 unsigned int skip_c1;
 unsigned int do_nhm_cstates;
@@ -68,9 +71,10 @@
 int aperf_mperf_unstable;
 int backwards_count;
 char *progname;
-int need_reinitialize;
 
 int num_cpus;
+cpu_set_t *cpu_mask;
+size_t cpu_mask_size;
 
 struct counters {
 	unsigned long long tsc;		/* per thread */
@@ -99,44 +103,76 @@
 struct timeval tv_odd;
 struct timeval tv_delta;
 
-unsigned long long get_msr(int cpu, off_t offset)
+/*
+ * cpu_mask_init(ncpus)
+ *
+ * allocate and clear cpu_mask
+ * set cpu_mask_size
+ */
+void cpu_mask_init(int ncpus)
+{
+	cpu_mask = CPU_ALLOC(ncpus);
+	if (cpu_mask == NULL) {
+		perror("CPU_ALLOC");
+		exit(3);
+	}
+	cpu_mask_size = CPU_ALLOC_SIZE(ncpus);
+	CPU_ZERO_S(cpu_mask_size, cpu_mask);
+}
+
+void cpu_mask_uninit()
+{
+	CPU_FREE(cpu_mask);
+	cpu_mask = NULL;
+	cpu_mask_size = 0;
+}
+
+int cpu_migrate(int cpu)
+{
+	CPU_ZERO_S(cpu_mask_size, cpu_mask);
+	CPU_SET_S(cpu, cpu_mask_size, cpu_mask);
+	if (sched_setaffinity(0, cpu_mask_size, cpu_mask) == -1)
+		return -1;
+	else
+		return 0;
+}
+
+int get_msr(int cpu, off_t offset, unsigned long long *msr)
 {
 	ssize_t retval;
-	unsigned long long msr;
 	char pathname[32];
 	int fd;
 
 	sprintf(pathname, "/dev/cpu/%d/msr", cpu);
 	fd = open(pathname, O_RDONLY);
-	if (fd < 0) {
-		perror(pathname);
-		need_reinitialize = 1;
-		return 0;
-	}
+	if (fd < 0)
+		return -1;
 
-	retval = pread(fd, &msr, sizeof msr, offset);
-	if (retval != sizeof msr) {
-		fprintf(stderr, "cpu%d pread(..., 0x%zx) = %jd\n",
-			cpu, offset, retval);
-		exit(-2);
-	}
-
+	retval = pread(fd, msr, sizeof *msr, offset);
 	close(fd);
-	return msr;
+
+	if (retval != sizeof *msr)
+		return -1;
+
+	return 0;
 }
 
 void print_header(void)
 {
 	if (show_pkg)
 		fprintf(stderr, "pk");
+	if (show_pkg)
+		fprintf(stderr, " ");
 	if (show_core)
-		fprintf(stderr, " cr");
+		fprintf(stderr, "cor");
 	if (show_cpu)
 		fprintf(stderr, " CPU");
+	if (show_pkg || show_core || show_cpu)
+		fprintf(stderr, " ");
 	if (do_nhm_cstates)
-		fprintf(stderr, "    %%c0 ");
+		fprintf(stderr, "   %%c0");
 	if (has_aperf)
-		fprintf(stderr, " GHz");
+		fprintf(stderr, "  GHz");
 	fprintf(stderr, "  TSC");
 	if (do_nhm_cstates)
 		fprintf(stderr, "    %%c1");
@@ -147,13 +183,13 @@
 	if (do_snb_cstates)
 		fprintf(stderr, "    %%c7");
 	if (do_snb_cstates)
-		fprintf(stderr, "  %%pc2");
+		fprintf(stderr, "   %%pc2");
 	if (do_nhm_cstates)
-		fprintf(stderr, "  %%pc3");
+		fprintf(stderr, "   %%pc3");
 	if (do_nhm_cstates)
-		fprintf(stderr, "  %%pc6");
+		fprintf(stderr, "   %%pc6");
 	if (do_snb_cstates)
-		fprintf(stderr, "  %%pc7");
+		fprintf(stderr, "   %%pc7");
 	if (extra_msr_offset)
 		fprintf(stderr, "        MSR 0x%x ", extra_msr_offset);
 
@@ -187,6 +223,15 @@
 		dump_cnt(cnt);
 }
 
+/*
+ * column formatting convention & formats
+ * package: "pk" 2 columns %2d
+ * core: "cor" 3 columns %3d
+ * CPU: "CPU" 3 columns %3d
+ * GHz: "GHz" 3 columns %3.2
+ * TSC: "TSC" 3 columns %3.2
+ * percentage " %pc3" %6.2
+ */
 void print_cnt(struct counters *p)
 {
 	double interval_float;
@@ -196,39 +241,45 @@
 	/* topology columns, print blanks on 1st (average) line */
 	if (p == cnt_average) {
 		if (show_pkg)
+			fprintf(stderr, "  ");
+		if (show_pkg && show_core)
 			fprintf(stderr, " ");
 		if (show_core)
-			fprintf(stderr, "    ");
+			fprintf(stderr, "   ");
 		if (show_cpu)
-			fprintf(stderr, "    ");
+			fprintf(stderr, " " "   ");
 	} else {
 		if (show_pkg)
-			fprintf(stderr, "%d", p->pkg);
+			fprintf(stderr, "%2d", p->pkg);
+		if (show_pkg && show_core)
+			fprintf(stderr, " ");
 		if (show_core)
-			fprintf(stderr, "%4d", p->core);
+			fprintf(stderr, "%3d", p->core);
 		if (show_cpu)
-			fprintf(stderr, "%4d", p->cpu);
+			fprintf(stderr, " %3d", p->cpu);
 	}
 
 	/* %c0 */
 	if (do_nhm_cstates) {
+		if (show_pkg || show_core || show_cpu)
+			fprintf(stderr, " ");
 		if (!skip_c0)
-			fprintf(stderr, "%7.2f", 100.0 * p->mperf/p->tsc);
+			fprintf(stderr, "%6.2f", 100.0 * p->mperf/p->tsc);
 		else
-			fprintf(stderr, "   ****");
+			fprintf(stderr, "  ****");
 	}
 
 	/* GHz */
 	if (has_aperf) {
 		if (!aperf_mperf_unstable) {
-			fprintf(stderr, "%5.2f",
+			fprintf(stderr, " %3.2f",
 				1.0 * p->tsc / units * p->aperf /
 				p->mperf / interval_float);
 		} else {
 			if (p->aperf > p->tsc || p->mperf > p->tsc) {
-				fprintf(stderr, " ****");
+				fprintf(stderr, " ***");
 			} else {
-				fprintf(stderr, "%4.1f*",
+				fprintf(stderr, "%3.1f*",
 					1.0 * p->tsc /
 					units * p->aperf /
 					p->mperf / interval_float);
@@ -241,7 +292,7 @@
 
 	if (do_nhm_cstates) {
 		if (!skip_c1)
-			fprintf(stderr, "%7.2f", 100.0 * p->c1/p->tsc);
+			fprintf(stderr, " %6.2f", 100.0 * p->c1/p->tsc);
 		else
 			fprintf(stderr, "  ****");
 	}
@@ -252,13 +303,13 @@
 	if (do_snb_cstates)
 		fprintf(stderr, " %6.2f", 100.0 * p->c7/p->tsc);
 	if (do_snb_cstates)
-		fprintf(stderr, " %5.2f", 100.0 * p->pc2/p->tsc);
+		fprintf(stderr, " %6.2f", 100.0 * p->pc2/p->tsc);
 	if (do_nhm_cstates)
-		fprintf(stderr, " %5.2f", 100.0 * p->pc3/p->tsc);
+		fprintf(stderr, " %6.2f", 100.0 * p->pc3/p->tsc);
 	if (do_nhm_cstates)
-		fprintf(stderr, " %5.2f", 100.0 * p->pc6/p->tsc);
+		fprintf(stderr, " %6.2f", 100.0 * p->pc6/p->tsc);
 	if (do_snb_cstates)
-		fprintf(stderr, " %5.2f", 100.0 * p->pc7/p->tsc);
+		fprintf(stderr, " %6.2f", 100.0 * p->pc7/p->tsc);
 	if (extra_msr_offset)
 		fprintf(stderr, "  0x%016llx", p->extra_msr);
 	putc('\n', stderr);
@@ -267,12 +318,20 @@
 void print_counters(struct counters *counters)
 {
 	struct counters *cnt;
+	static int printed;
 
-	print_header();
+
+	if (!printed || !summary_only)
+		print_header();
 
 	if (num_cpus > 1)
 		print_cnt(cnt_average);
 
+	printed = 1;
+
+	if (summary_only)
+		return;
+
 	for (cnt = counters; cnt != NULL; cnt = cnt->next)
 		print_cnt(cnt);
 
@@ -440,31 +499,51 @@
 	free(sum);
 }
 
-void get_counters(struct counters *cnt)
+int get_counters(struct counters *cnt)
 {
 	for ( ; cnt; cnt = cnt->next) {
-		cnt->tsc = get_msr(cnt->cpu, MSR_TSC);
-		if (do_nhm_cstates)
-			cnt->c3 = get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY);
-		if (do_nhm_cstates)
-			cnt->c6 = get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY);
+
+		if (cpu_migrate(cnt->cpu))
+			return -1;
+
+		if (get_msr(cnt->cpu, MSR_TSC, &cnt->tsc))
+			return -1;
+
+		if (has_aperf) {
+			if (get_msr(cnt->cpu, MSR_APERF, &cnt->aperf))
+				return -1;
+			if (get_msr(cnt->cpu, MSR_MPERF, &cnt->mperf))
+				return -1;
+		}
+
+		if (do_nhm_cstates) {
+			if (get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY, &cnt->c3))
+				return -1;
+			if (get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY, &cnt->c6))
+				return -1;
+		}
+
 		if (do_snb_cstates)
-			cnt->c7 = get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY);
-		if (has_aperf)
-			cnt->aperf = get_msr(cnt->cpu, MSR_APERF);
-		if (has_aperf)
-			cnt->mperf = get_msr(cnt->cpu, MSR_MPERF);
-		if (do_snb_cstates)
-			cnt->pc2 = get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY);
-		if (do_nhm_cstates)
-			cnt->pc3 = get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY);
-		if (do_nhm_cstates)
-			cnt->pc6 = get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY);
-		if (do_snb_cstates)
-			cnt->pc7 = get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY);
+			if (get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY, &cnt->c7))
+				return -1;
+
+		if (do_nhm_cstates) {
+			if (get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY, &cnt->pc3))
+				return -1;
+			if (get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY, &cnt->pc6))
+				return -1;
+		}
+		if (do_snb_cstates) {
+			if (get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY, &cnt->pc2))
+				return -1;
+			if (get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY, &cnt->pc7))
+				return -1;
+		}
 		if (extra_msr_offset)
-			cnt->extra_msr = get_msr(cnt->cpu, extra_msr_offset);
+			if (get_msr(cnt->cpu, extra_msr_offset, &cnt->extra_msr))
+				return -1;
 	}
+	return 0;
 }
 
 void print_nehalem_info(void)
@@ -475,7 +554,7 @@
 	if (!do_nehalem_platform_info)
 		return;
 
-	msr = get_msr(0, MSR_NEHALEM_PLATFORM_INFO);
+	get_msr(0, MSR_NEHALEM_PLATFORM_INFO, &msr);
 
 	ratio = (msr >> 40) & 0xFF;
 	fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n",
@@ -491,7 +570,7 @@
 	if (!do_nehalem_turbo_ratio_limit)
 		return;
 
-	msr = get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT);
+	get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT, &msr);
 
 	ratio = (msr >> 24) & 0xFF;
 	if (ratio)
@@ -557,7 +636,8 @@
 		return;
 	}
 
-	show_cpu = 1;	/* there is more than one CPU */
+	if (!summary_only)
+		show_cpu = 1;	/* there is more than one CPU */
 
 	/*
 	 * insert on front of list.
@@ -575,13 +655,15 @@
 
 	while (prev->next && (prev->next->pkg < new->pkg)) {
 		prev = prev->next;
-		show_pkg = 1;	/* there is more than 1 package */
+		if (!summary_only)
+			show_pkg = 1;	/* there is more than 1 package */
 	}
 
 	while (prev->next && (prev->next->pkg == new->pkg)
 		&& (prev->next->core < new->core)) {
 		prev = prev->next;
-		show_core = 1;	/* there is more than 1 core */
+		if (!summary_only)
+			show_core = 1;	/* there is more than 1 core */
 	}
 
 	while (prev->next && (prev->next->pkg == new->pkg)
@@ -681,7 +763,7 @@
 }
 
 /*
- * run func(index, cpu) on every cpu in /proc/stat
+ * run func(pkg, core, cpu) on every cpu in /proc/stat
  */
 
 int for_all_cpus(void (func)(int, int, int))
@@ -717,18 +799,18 @@
 
 void re_initialize(void)
 {
-	printf("turbostat: topology changed, re-initializing.\n");
 	free_all_counters();
 	num_cpus = for_all_cpus(alloc_new_counters);
-	need_reinitialize = 0;
-	printf("num_cpus is now %d\n", num_cpus);
+	cpu_mask_uninit();
+	cpu_mask_init(num_cpus);
+	printf("turbostat: re-initialized with num_cpus %d\n", num_cpus);
 }
 
 void dummy(int pkg, int core, int cpu) { return; }
 /*
  * check to see if a cpu came on-line
  */
-void verify_num_cpus(void)
+int verify_num_cpus(void)
 {
 	int new_num_cpus;
 
@@ -738,8 +820,9 @@
 		if (verbose)
 			printf("num_cpus was %d, is now  %d\n",
 				num_cpus, new_num_cpus);
-		need_reinitialize = 1;
+		return -1;
 	}
+	return 0;
 }
 
 void turbostat_loop()
@@ -749,25 +832,25 @@
 	gettimeofday(&tv_even, (struct timezone *)NULL);
 
 	while (1) {
-		verify_num_cpus();
-		if (need_reinitialize) {
+		if (verify_num_cpus()) {
 			re_initialize();
 			goto restart;
 		}
 		sleep(interval_sec);
-		get_counters(cnt_odd);
+		if (get_counters(cnt_odd)) {
+			re_initialize();
+			goto restart;
+		}
 		gettimeofday(&tv_odd, (struct timezone *)NULL);
-
 		compute_delta(cnt_odd, cnt_even, cnt_delta);
 		timersub(&tv_odd, &tv_even, &tv_delta);
 		compute_average(cnt_delta, cnt_average);
 		print_counters(cnt_delta);
-		if (need_reinitialize) {
+		sleep(interval_sec);
+		if (get_counters(cnt_even)) {
 			re_initialize();
 			goto restart;
 		}
-		sleep(interval_sec);
-		get_counters(cnt_even);
 		gettimeofday(&tv_even, (struct timezone *)NULL);
 		compute_delta(cnt_even, cnt_odd, cnt_delta);
 		timersub(&tv_even, &tv_odd, &tv_delta);
@@ -953,6 +1036,7 @@
 	check_super_user();
 
 	num_cpus = for_all_cpus(alloc_new_counters);
+	cpu_mask_init(num_cpus);
 
 	if (verbose)
 		print_nehalem_info();
@@ -1005,8 +1089,11 @@
 
 	progname = argv[0];
 
-	while ((opt = getopt(argc, argv, "+vi:M:")) != -1) {
+	while ((opt = getopt(argc, argv, "+svi:M:")) != -1) {
 		switch (opt) {
+		case 's':
+			summary_only++;
+			break;
 		case 'v':
 			verbose++;
 			break;
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 758ec2a..95d6a6f 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -46,6 +46,7 @@
     "DIE_ON_FAILURE"		=> 1,
     "SSH_EXEC"			=> "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND",
     "SCP_TO_TARGET"		=> "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE",
+    "SCP_TO_TARGET_INSTALL"	=> "\${SCP_TO_TARGET}",
     "REBOOT"			=> "ssh \$SSH_USER\@\$MACHINE reboot",
     "STOP_AFTER_SUCCESS"	=> 10,
     "STOP_AFTER_FAILURE"	=> 60,
@@ -86,11 +87,13 @@
 my $switch_to_good;
 my $switch_to_test;
 my $poweroff_on_error;
+my $reboot_on_success;
 my $die_on_failure;
 my $powercycle_after_reboot;
 my $poweroff_after_halt;
 my $ssh_exec;
 my $scp_to_target;
+my $scp_to_target_install;
 my $power_off;
 my $grub_menu;
 my $grub_number;
@@ -211,6 +214,7 @@
     "SWITCH_TO_GOOD"		=> \$switch_to_good,
     "SWITCH_TO_TEST"		=> \$switch_to_test,
     "POWEROFF_ON_ERROR"		=> \$poweroff_on_error,
+    "REBOOT_ON_SUCCESS"		=> \$reboot_on_success,
     "DIE_ON_FAILURE"		=> \$die_on_failure,
     "POWER_OFF"			=> \$power_off,
     "POWERCYCLE_AFTER_REBOOT"	=> \$powercycle_after_reboot,
@@ -243,6 +247,7 @@
     "BUILD_TARGET"		=> \$build_target,
     "SSH_EXEC"			=> \$ssh_exec,
     "SCP_TO_TARGET"		=> \$scp_to_target,
+    "SCP_TO_TARGET_INSTALL"	=> \$scp_to_target_install,
     "CHECKOUT"			=> \$checkout,
     "TARGET_IMAGE"		=> \$target_image,
     "LOCALVERSION"		=> \$localversion,
@@ -1113,7 +1118,6 @@
 
     if (defined($switch_to_good)) {
 	run_command $switch_to_good;
-	return;
     }
 
     reboot $time;
@@ -1349,8 +1353,7 @@
 }
 
 sub run_scp {
-    my ($src, $dst) = @_;
-    my $cp_scp = $scp_to_target;
+    my ($src, $dst, $cp_scp) = @_;
 
     $cp_scp =~ s/\$SRC_FILE/$src/g;
     $cp_scp =~ s/\$DST_FILE/$dst/g;
@@ -1358,6 +1361,22 @@
     return run_command "$cp_scp";
 }
 
+sub run_scp_install {
+    my ($src, $dst) = @_;
+
+    my $cp_scp = $scp_to_target_install;
+
+    return run_scp($src, $dst, $cp_scp);
+}
+
+sub run_scp_mod {
+    my ($src, $dst) = @_;
+
+    my $cp_scp = $scp_to_target;
+
+    return run_scp($src, $dst, $cp_scp);
+}
+
 sub get_grub_index {
 
     if ($reboot_type ne "grub") {
@@ -1460,6 +1479,7 @@
 sub monitor {
     my $booted = 0;
     my $bug = 0;
+    my $bug_ignored = 0;
     my $skip_call_trace = 0;
     my $loops;
 
@@ -1531,9 +1551,13 @@
 	}
 
 	if ($full_line =~ /call trace:/i) {
-	    if (!$ignore_errors && !$bug && !$skip_call_trace) {
-		$bug = 1;
-		$failure_start = time;
+	    if (!$bug && !$skip_call_trace) {
+		if ($ignore_errors) {
+		    $bug_ignored = 1;
+		} else {
+		    $bug = 1;
+		    $failure_start = time;
+		}
 	    }
 	}
 
@@ -1595,6 +1619,10 @@
 	fail "failed - never got a boot prompt." and return 0;
     }
 
+    if ($bug_ignored) {
+	doprint "WARNING: Call Trace detected but ignored due to IGNORE_ERRORS=1\n";
+    }
+
     return 1;
 }
 
@@ -1621,7 +1649,7 @@
 
     my $cp_target = eval_kernel_version $target_image;
 
-    run_scp "$outputdir/$build_target", "$cp_target" or
+    run_scp_install "$outputdir/$build_target", "$cp_target" or
 	dodie "failed to copy image";
 
     my $install_mods = 0;
@@ -1643,7 +1671,7 @@
 	return;
     }
 
-    run_command "$make INSTALL_MOD_PATH=$tmpdir modules_install" or
+    run_command "$make INSTALL_MOD_STRIP=1 INSTALL_MOD_PATH=$tmpdir modules_install" or
 	dodie "Failed to install modules";
 
     my $modlib = "/lib/modules/$version";
@@ -1656,7 +1684,7 @@
     run_command "cd $tmpdir && tar -cjf $modtar lib/modules/$version" or
 	dodie "making tarball";
 
-    run_scp "$tmpdir/$modtar", "/tmp" or
+    run_scp_mod "$tmpdir/$modtar", "/tmp" or
 	dodie "failed to copy modules";
 
     unlink "$tmpdir/$modtar";
@@ -3526,8 +3554,10 @@
 	    die "failed to checkout $checkout";
     }
 
-    $no_reboot = 0;
-
+    # A test may opt to not reboot the box
+    if ($reboot_on_success) {
+	$no_reboot = 0;
+    }
 
     if ($test_type eq "bisect") {
 	bisect $i;
@@ -3572,8 +3602,12 @@
     halt;
 } elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot) {
     reboot_to_good;
+} elsif (defined($switch_to_good)) {
+    # still need to get to the good kernel
+    run_command $switch_to_good;
 }
 
+
 doprint "\n    $successes of $opt{NUM_TESTS} tests were successful\n\n";
 
 exit 0;
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
index 5ea04c6..b682456 100644
--- a/tools/testing/ktest/sample.conf
+++ b/tools/testing/ktest/sample.conf
@@ -710,10 +710,18 @@
 # The variables SSH_USER, MACHINE and SSH_COMMAND are defined
 #SSH_EXEC = ssh $SSH_USER@$MACHINE $SSH_COMMAND";
 
-# The way to copy a file to the target
+# The way to copy a file to the target (install and modules)
 # (default scp $SRC_FILE $SSH_USER@$MACHINE:$DST_FILE)
-# The variables SSH_USER, MACHINE, SRC_FILE and DST_FILE are defined.
-#SCP_TO_TARGET = scp $SRC_FILE $SSH_USER@$MACHINE:$DST_FILE
+# The variables SSH_USER, MACHINE are defined by the config
+# SRC_FILE and DST_FILE are ktest internal variables and
+# should only have '$' and not the '${}' notation.
+# (default scp $SRC_FILE ${SSH_USER}@${MACHINE}:$DST_FILE)
+#SCP_TO_TARGET = echo skip scp for $SRC_FILE $DST_FILE
+
+# If install needs to be different than modules, then this
+# option will override the SCP_TO_TARGET for installation.
+# (default ${SCP_TO_TARGET} )
+#SCP_TO_TARGET_INSTALL = scp $SRC_FILE tftp@tftpserver:$DST_FILE
 
 # The nice way to reboot the target
 # (default ssh $SSH_USER@$MACHINE reboot)
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 4ec8401..28bc57e 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -1,10 +1,15 @@
-TARGETS = breakpoints
+TARGETS = breakpoints vm
 
 all:
 	for TARGET in $(TARGETS); do \
 		make -C $$TARGET; \
 	done;
 
+run_tests: all
+	for TARGET in $(TARGETS); do \
+		make -C $$TARGET run_tests; \
+	done;
+
 clean:
 	for TARGET in $(TARGETS); do \
 		make -C $$TARGET clean; \
diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/selftests/breakpoints/Makefile
index f362722..9312780 100644
--- a/tools/testing/selftests/breakpoints/Makefile
+++ b/tools/testing/selftests/breakpoints/Makefile
@@ -11,10 +11,13 @@
 
 all:
 ifeq ($(ARCH),x86)
-	gcc breakpoint_test.c -o run_test
+	gcc breakpoint_test.c -o breakpoint_test
 else
 	echo "Not an x86 target, can't build breakpoints selftests"
 endif
 
+run_tests:
+	./breakpoint_test
+
 clean:
-	rm -fr run_test
+	rm -fr breakpoint_test
diff --git a/tools/testing/selftests/run_tests b/tools/testing/selftests/run_tests
deleted file mode 100644
index 320718a..0000000
--- a/tools/testing/selftests/run_tests
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-TARGETS=breakpoints
-
-for TARGET in $TARGETS
-do
-	$TARGET/run_test
-done
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile
new file mode 100644
index 0000000..b336b24
--- /dev/null
+++ b/tools/testing/selftests/vm/Makefile
@@ -0,0 +1,14 @@
+# Makefile for vm selftests
+
+CC = $(CROSS_COMPILE)gcc
+CFLAGS = -Wall -Wextra
+
+all: hugepage-mmap hugepage-shm  map_hugetlb
+%: %.c
+	$(CC) $(CFLAGS) -o $@ $^
+
+run_tests: all
+	/bin/sh ./run_vmtests
+
+clean:
+	$(RM) hugepage-mmap hugepage-shm  map_hugetlb
diff --git a/tools/testing/selftests/vm/hugepage-mmap.c b/tools/testing/selftests/vm/hugepage-mmap.c
new file mode 100644
index 0000000..a10f310
--- /dev/null
+++ b/tools/testing/selftests/vm/hugepage-mmap.c
@@ -0,0 +1,92 @@
+/*
+ * hugepage-mmap:
+ *
+ * Example of using huge page memory in a user application using the mmap
+ * system call.  Before running this application, make sure that the
+ * administrator has mounted the hugetlbfs filesystem (on some directory
+ * like /mnt) using the command mount -t hugetlbfs nodev /mnt. In this
+ * example, the app is requesting memory of size 256MB that is backed by
+ * huge pages.
+ *
+ * For the ia64 architecture, the Linux kernel reserves Region number 4 for
+ * huge pages.  That means that if one requires a fixed address, a huge page
+ * aligned address starting with 0x800000... will be required.  If a fixed
+ * address is not required, the kernel will select an address in the proper
+ * range.
+ * Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#define FILE_NAME "huge/hugepagefile"
+#define LENGTH (256UL*1024*1024)
+#define PROTECTION (PROT_READ | PROT_WRITE)
+
+/* Only ia64 requires this */
+#ifdef __ia64__
+#define ADDR (void *)(0x8000000000000000UL)
+#define FLAGS (MAP_SHARED | MAP_FIXED)
+#else
+#define ADDR (void *)(0x0UL)
+#define FLAGS (MAP_SHARED)
+#endif
+
+static void check_bytes(char *addr)
+{
+	printf("First hex is %x\n", *((unsigned int *)addr));
+}
+
+static void write_bytes(char *addr)
+{
+	unsigned long i;
+
+	for (i = 0; i < LENGTH; i++)
+		*(addr + i) = (char)i;
+}
+
+static int read_bytes(char *addr)
+{
+	unsigned long i;
+
+	check_bytes(addr);
+	for (i = 0; i < LENGTH; i++)
+		if (*(addr + i) != (char)i) {
+			printf("Mismatch at %lu\n", i);
+			return 1;
+		}
+	return 0;
+}
+
+int main(void)
+{
+	void *addr;
+	int fd, ret;
+
+	fd = open(FILE_NAME, O_CREAT | O_RDWR, 0755);
+	if (fd < 0) {
+		perror("Open failed");
+		exit(1);
+	}
+
+	addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, fd, 0);
+	if (addr == MAP_FAILED) {
+		perror("mmap");
+		unlink(FILE_NAME);
+		exit(1);
+	}
+
+	printf("Returned address is %p\n", addr);
+	check_bytes(addr);
+	write_bytes(addr);
+	ret = read_bytes(addr);
+
+	munmap(addr, LENGTH);
+	close(fd);
+	unlink(FILE_NAME);
+
+	return ret;
+}
diff --git a/tools/testing/selftests/vm/hugepage-shm.c b/tools/testing/selftests/vm/hugepage-shm.c
new file mode 100644
index 0000000..0d0ef4f
--- /dev/null
+++ b/tools/testing/selftests/vm/hugepage-shm.c
@@ -0,0 +1,100 @@
+/*
+ * hugepage-shm:
+ *
+ * Example of using huge page memory in a user application using Sys V shared
+ * memory system calls.  In this example the app is requesting 256MB of
+ * memory that is backed by huge pages.  The application uses the flag
+ * SHM_HUGETLB in the shmget system call to inform the kernel that it is
+ * requesting huge pages.
+ *
+ * For the ia64 architecture, the Linux kernel reserves Region number 4 for
+ * huge pages.  That means that if one requires a fixed address, a huge page
+ * aligned address starting with 0x800000... will be required.  If a fixed
+ * address is not required, the kernel will select an address in the proper
+ * range.
+ * Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
+ *
+ * Note: The default shared memory limit is quite low on many kernels,
+ * you may need to increase it via:
+ *
+ * echo 268435456 > /proc/sys/kernel/shmmax
+ *
+ * This will increase the maximum size per shared memory segment to 256MB.
+ * The other limit that you will hit eventually is shmall which is the
+ * total amount of shared memory in pages. To set it to 16GB on a system
+ * with a 4kB pagesize do:
+ *
+ * echo 4194304 > /proc/sys/kernel/shmall
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/mman.h>
+
+#ifndef SHM_HUGETLB
+#define SHM_HUGETLB 04000
+#endif
+
+#define LENGTH (256UL*1024*1024)
+
+#define dprintf(x)  printf(x)
+
+/* Only ia64 requires this */
+#ifdef __ia64__
+#define ADDR (void *)(0x8000000000000000UL)
+#define SHMAT_FLAGS (SHM_RND)
+#else
+#define ADDR (void *)(0x0UL)
+#define SHMAT_FLAGS (0)
+#endif
+
+int main(void)
+{
+	int shmid;
+	unsigned long i;
+	char *shmaddr;
+
+	shmid = shmget(2, LENGTH, SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W);
+	if (shmid < 0) {
+		perror("shmget");
+		exit(1);
+	}
+	printf("shmid: 0x%x\n", shmid);
+
+	shmaddr = shmat(shmid, ADDR, SHMAT_FLAGS);
+	if (shmaddr == (char *)-1) {
+		perror("Shared memory attach failure");
+		shmctl(shmid, IPC_RMID, NULL);
+		exit(2);
+	}
+	printf("shmaddr: %p\n", shmaddr);
+
+	dprintf("Starting the writes:\n");
+	for (i = 0; i < LENGTH; i++) {
+		shmaddr[i] = (char)(i);
+		if (!(i % (1024 * 1024)))
+			dprintf(".");
+	}
+	dprintf("\n");
+
+	dprintf("Starting the Check...");
+	for (i = 0; i < LENGTH; i++)
+		if (shmaddr[i] != (char)i) {
+			printf("\nIndex %lu mismatched\n", i);
+			exit(3);
+		}
+	dprintf("Done.\n");
+
+	if (shmdt((const void *)shmaddr) != 0) {
+		perror("Detach failure");
+		shmctl(shmid, IPC_RMID, NULL);
+		exit(4);
+	}
+
+	shmctl(shmid, IPC_RMID, NULL);
+
+	return 0;
+}
diff --git a/tools/testing/selftests/vm/map_hugetlb.c b/tools/testing/selftests/vm/map_hugetlb.c
new file mode 100644
index 0000000..ac56639
--- /dev/null
+++ b/tools/testing/selftests/vm/map_hugetlb.c
@@ -0,0 +1,79 @@
+/*
+ * Example of using hugepage memory in a user application using the mmap
+ * system call with MAP_HUGETLB flag.  Before running this program make
+ * sure the administrator has allocated enough default sized huge pages
+ * to cover the 256 MB allocation.
+ *
+ * For ia64 architecture, Linux kernel reserves Region number 4 for hugepages.
+ * That means the addresses starting with 0x800000... will need to be
+ * specified.  Specifying a fixed address is not required on ppc64, i386
+ * or x86_64.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#define LENGTH (256UL*1024*1024)
+#define PROTECTION (PROT_READ | PROT_WRITE)
+
+#ifndef MAP_HUGETLB
+#define MAP_HUGETLB 0x40000 /* arch specific */
+#endif
+
+/* Only ia64 requires this */
+#ifdef __ia64__
+#define ADDR (void *)(0x8000000000000000UL)
+#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_FIXED)
+#else
+#define ADDR (void *)(0x0UL)
+#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
+#endif
+
+static void check_bytes(char *addr)
+{
+	printf("First hex is %x\n", *((unsigned int *)addr));
+}
+
+static void write_bytes(char *addr)
+{
+	unsigned long i;
+
+	for (i = 0; i < LENGTH; i++)
+		*(addr + i) = (char)i;
+}
+
+static int read_bytes(char *addr)
+{
+	unsigned long i;
+
+	check_bytes(addr);
+	for (i = 0; i < LENGTH; i++)
+		if (*(addr + i) != (char)i) {
+			printf("Mismatch at %lu\n", i);
+			return 1;
+		}
+	return 0;
+}
+
+int main(void)
+{
+	void *addr;
+	int ret;
+
+	addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, 0, 0);
+	if (addr == MAP_FAILED) {
+		perror("mmap");
+		exit(1);
+	}
+
+	printf("Returned address is %p\n", addr);
+	check_bytes(addr);
+	write_bytes(addr);
+	ret = read_bytes(addr);
+
+	munmap(addr, LENGTH);
+
+	return ret;
+}
diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests
new file mode 100644
index 0000000..8b40bd5
--- /dev/null
+++ b/tools/testing/selftests/vm/run_vmtests
@@ -0,0 +1,77 @@
+#!/bin/bash
+#please run as root
+
+#we need 256M, below is the size in kB
+needmem=262144
+mnt=./huge
+
+#get pagesize and freepages from /proc/meminfo
+while read name size unit; do
+	if [ "$name" = "HugePages_Free:" ]; then
+		freepgs=$size
+	fi
+	if [ "$name" = "Hugepagesize:" ]; then
+		pgsize=$size
+	fi
+done < /proc/meminfo
+
+#set proper nr_hugepages
+if [ -n "$freepgs" ] && [ -n "$pgsize" ]; then
+	nr_hugepgs=`cat /proc/sys/vm/nr_hugepages`
+	needpgs=`expr $needmem / $pgsize`
+	if [ $freepgs -lt $needpgs ]; then
+		lackpgs=$(( $needpgs - $freepgs ))
+		echo $(( $lackpgs + $nr_hugepgs )) > /proc/sys/vm/nr_hugepages
+		if [ $? -ne 0 ]; then
+			echo "Please run this test as root"
+			exit 1
+		fi
+	fi
+else
+	echo "no hugetlbfs support in kernel?"
+	exit 1
+fi
+
+mkdir $mnt
+mount -t hugetlbfs none $mnt
+
+echo "--------------------"
+echo "runing hugepage-mmap"
+echo "--------------------"
+./hugepage-mmap
+if [ $? -ne 0 ]; then
+	echo "[FAIL]"
+else
+	echo "[PASS]"
+fi
+
+shmmax=`cat /proc/sys/kernel/shmmax`
+shmall=`cat /proc/sys/kernel/shmall`
+echo 268435456 > /proc/sys/kernel/shmmax
+echo 4194304 > /proc/sys/kernel/shmall
+echo "--------------------"
+echo "runing hugepage-shm"
+echo "--------------------"
+./hugepage-shm
+if [ $? -ne 0 ]; then
+	echo "[FAIL]"
+else
+	echo "[PASS]"
+fi
+echo $shmmax > /proc/sys/kernel/shmmax
+echo $shmall > /proc/sys/kernel/shmall
+
+echo "--------------------"
+echo "runing map_hugetlb"
+echo "--------------------"
+./map_hugetlb
+if [ $? -ne 0 ]; then
+	echo "[FAIL]"
+else
+	echo "[PASS]"
+fi
+
+#cleanup
+umount $mnt
+rm -rf $mnt
+echo $nr_hugepgs > /proc/sys/vm/nr_hugepages
diff --git a/tools/usb/Makefile b/tools/usb/Makefile
index 8b704af..396d6c4 100644
--- a/tools/usb/Makefile
+++ b/tools/usb/Makefile
@@ -3,7 +3,7 @@
 CC = $(CROSS_COMPILE)gcc
 PTHREAD_LIBS = -lpthread
 WARNINGS = -Wall -Wextra
-CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS)
+CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS) -I../include
 
 all: testusb ffs-test
 %: %.c
diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c
index 53452c3..4b107b5 100644
--- a/tools/usb/ffs-test.c
+++ b/tools/usb/ffs-test.c
@@ -36,6 +36,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <tools/le_byteshift.h>
 
 #include "../../include/linux/usb/functionfs.h"
 
@@ -47,34 +48,6 @@
 #define le32_to_cpu(x)  le32toh(x)
 #define le16_to_cpu(x)  le16toh(x)
 
-static inline __u16 get_unaligned_le16(const void *_ptr)
-{
-	const __u8 *ptr = _ptr;
-	return ptr[0] | (ptr[1] << 8);
-}
-
-static inline __u32 get_unaligned_le32(const void *_ptr)
-{
-	const __u8 *ptr = _ptr;
-	return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
-}
-
-static inline void put_unaligned_le16(__u16 val, void *_ptr)
-{
-	__u8 *ptr = _ptr;
-	*ptr++ = val;
-	*ptr++ = val >> 8;
-}
-
-static inline void put_unaligned_le32(__u32 val, void *_ptr)
-{
-	__u8 *ptr = _ptr;
-	*ptr++ = val;
-	*ptr++ = val >>  8;
-	*ptr++ = val >> 16;
-	*ptr++ = val >> 24;
-}
-
 
 /******************** Messages and Errors ***********************************/
 
diff --git a/tools/virtio/linux/hrtimer.h b/tools/virtio/linux/hrtimer.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/virtio/linux/hrtimer.h
diff --git a/tools/virtio/linux/module.h b/tools/virtio/linux/module.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/virtio/linux/module.h
diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h
index b4fbc91..7579f19 100644
--- a/tools/virtio/linux/virtio.h
+++ b/tools/virtio/linux/virtio.h
@@ -181,6 +181,9 @@
 #define smp_mb()	mb()
 # define smp_rmb()	barrier()
 # define smp_wmb()	barrier()
+/* Weak barriers should be used. If not - it's a bug */
+# define rmb()	abort()
+# define wmb()	abort()
 #else
 #error Please fill in barrier macros
 #endif
diff --git a/tools/vm/Makefile b/tools/vm/Makefile
new file mode 100644
index 0000000..8e30e5c
--- /dev/null
+++ b/tools/vm/Makefile
@@ -0,0 +1,11 @@
+# Makefile for vm tools
+
+CC = $(CROSS_COMPILE)gcc
+CFLAGS = -Wall -Wextra
+
+all: page-types slabinfo
+%: %.c
+	$(CC) $(CFLAGS) -o $@ $^
+
+clean:
+	$(RM) page-types slabinfo
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
new file mode 100644
index 0000000..7dab7b25
--- /dev/null
+++ b/tools/vm/page-types.c
@@ -0,0 +1,1102 @@
+/*
+ * page-types: Tool for querying page flags
+ *
+ * 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 in the hope that it will be useful, but WITHOUT
+ * 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 find a copy of v2 of the GNU General Public License somewhere on
+ * your Linux system; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Copyright (C) 2009 Intel corporation
+ *
+ * Authors: Wu Fengguang <fengguang.wu@intel.com>
+ */
+
+#define _LARGEFILE64_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <getopt.h>
+#include <limits.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+#include <sys/mount.h>
+#include <sys/statfs.h>
+#include "../../include/linux/magic.h"
+
+
+#ifndef MAX_PATH
+# define MAX_PATH 256
+#endif
+
+#ifndef STR
+# define _STR(x) #x
+# define STR(x) _STR(x)
+#endif
+
+/*
+ * pagemap kernel ABI bits
+ */
+
+#define PM_ENTRY_BYTES      sizeof(uint64_t)
+#define PM_STATUS_BITS      3
+#define PM_STATUS_OFFSET    (64 - PM_STATUS_BITS)
+#define PM_STATUS_MASK      (((1LL << PM_STATUS_BITS) - 1) << PM_STATUS_OFFSET)
+#define PM_STATUS(nr)       (((nr) << PM_STATUS_OFFSET) & PM_STATUS_MASK)
+#define PM_PSHIFT_BITS      6
+#define PM_PSHIFT_OFFSET    (PM_STATUS_OFFSET - PM_PSHIFT_BITS)
+#define PM_PSHIFT_MASK      (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET)
+#define PM_PSHIFT(x)        (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK)
+#define PM_PFRAME_MASK      ((1LL << PM_PSHIFT_OFFSET) - 1)
+#define PM_PFRAME(x)        ((x) & PM_PFRAME_MASK)
+
+#define PM_PRESENT          PM_STATUS(4LL)
+#define PM_SWAP             PM_STATUS(2LL)
+
+
+/*
+ * kernel page flags
+ */
+
+#define KPF_BYTES		8
+#define PROC_KPAGEFLAGS		"/proc/kpageflags"
+
+/* copied from kpageflags_read() */
+#define KPF_LOCKED		0
+#define KPF_ERROR		1
+#define KPF_REFERENCED		2
+#define KPF_UPTODATE		3
+#define KPF_DIRTY		4
+#define KPF_LRU			5
+#define KPF_ACTIVE		6
+#define KPF_SLAB		7
+#define KPF_WRITEBACK		8
+#define KPF_RECLAIM		9
+#define KPF_BUDDY		10
+
+/* [11-20] new additions in 2.6.31 */
+#define KPF_MMAP		11
+#define KPF_ANON		12
+#define KPF_SWAPCACHE		13
+#define KPF_SWAPBACKED		14
+#define KPF_COMPOUND_HEAD	15
+#define KPF_COMPOUND_TAIL	16
+#define KPF_HUGE		17
+#define KPF_UNEVICTABLE		18
+#define KPF_HWPOISON		19
+#define KPF_NOPAGE		20
+#define KPF_KSM			21
+#define KPF_THP			22
+
+/* [32-] kernel hacking assistances */
+#define KPF_RESERVED		32
+#define KPF_MLOCKED		33
+#define KPF_MAPPEDTODISK	34
+#define KPF_PRIVATE		35
+#define KPF_PRIVATE_2		36
+#define KPF_OWNER_PRIVATE	37
+#define KPF_ARCH		38
+#define KPF_UNCACHED		39
+
+/* [48-] take some arbitrary free slots for expanding overloaded flags
+ * not part of kernel API
+ */
+#define KPF_READAHEAD		48
+#define KPF_SLOB_FREE		49
+#define KPF_SLUB_FROZEN		50
+#define KPF_SLUB_DEBUG		51
+
+#define KPF_ALL_BITS		((uint64_t)~0ULL)
+#define KPF_HACKERS_BITS	(0xffffULL << 32)
+#define KPF_OVERLOADED_BITS	(0xffffULL << 48)
+#define BIT(name)		(1ULL << KPF_##name)
+#define BITS_COMPOUND		(BIT(COMPOUND_HEAD) | BIT(COMPOUND_TAIL))
+
+static const char * const page_flag_names[] = {
+	[KPF_LOCKED]		= "L:locked",
+	[KPF_ERROR]		= "E:error",
+	[KPF_REFERENCED]	= "R:referenced",
+	[KPF_UPTODATE]		= "U:uptodate",
+	[KPF_DIRTY]		= "D:dirty",
+	[KPF_LRU]		= "l:lru",
+	[KPF_ACTIVE]		= "A:active",
+	[KPF_SLAB]		= "S:slab",
+	[KPF_WRITEBACK]		= "W:writeback",
+	[KPF_RECLAIM]		= "I:reclaim",
+	[KPF_BUDDY]		= "B:buddy",
+
+	[KPF_MMAP]		= "M:mmap",
+	[KPF_ANON]		= "a:anonymous",
+	[KPF_SWAPCACHE]		= "s:swapcache",
+	[KPF_SWAPBACKED]	= "b:swapbacked",
+	[KPF_COMPOUND_HEAD]	= "H:compound_head",
+	[KPF_COMPOUND_TAIL]	= "T:compound_tail",
+	[KPF_HUGE]		= "G:huge",
+	[KPF_UNEVICTABLE]	= "u:unevictable",
+	[KPF_HWPOISON]		= "X:hwpoison",
+	[KPF_NOPAGE]		= "n:nopage",
+	[KPF_KSM]		= "x:ksm",
+	[KPF_THP]		= "t:thp",
+
+	[KPF_RESERVED]		= "r:reserved",
+	[KPF_MLOCKED]		= "m:mlocked",
+	[KPF_MAPPEDTODISK]	= "d:mappedtodisk",
+	[KPF_PRIVATE]		= "P:private",
+	[KPF_PRIVATE_2]		= "p:private_2",
+	[KPF_OWNER_PRIVATE]	= "O:owner_private",
+	[KPF_ARCH]		= "h:arch",
+	[KPF_UNCACHED]		= "c:uncached",
+
+	[KPF_READAHEAD]		= "I:readahead",
+	[KPF_SLOB_FREE]		= "P:slob_free",
+	[KPF_SLUB_FROZEN]	= "A:slub_frozen",
+	[KPF_SLUB_DEBUG]	= "E:slub_debug",
+};
+
+
+static const char * const debugfs_known_mountpoints[] = {
+	"/sys/kernel/debug",
+	"/debug",
+	0,
+};
+
+/*
+ * data structures
+ */
+
+static int		opt_raw;	/* for kernel developers */
+static int		opt_list;	/* list pages (in ranges) */
+static int		opt_no_summary;	/* don't show summary */
+static pid_t		opt_pid;	/* process to walk */
+
+#define MAX_ADDR_RANGES	1024
+static int		nr_addr_ranges;
+static unsigned long	opt_offset[MAX_ADDR_RANGES];
+static unsigned long	opt_size[MAX_ADDR_RANGES];
+
+#define MAX_VMAS	10240
+static int		nr_vmas;
+static unsigned long	pg_start[MAX_VMAS];
+static unsigned long	pg_end[MAX_VMAS];
+
+#define MAX_BIT_FILTERS	64
+static int		nr_bit_filters;
+static uint64_t		opt_mask[MAX_BIT_FILTERS];
+static uint64_t		opt_bits[MAX_BIT_FILTERS];
+
+static int		page_size;
+
+static int		pagemap_fd;
+static int		kpageflags_fd;
+
+static int		opt_hwpoison;
+static int		opt_unpoison;
+
+static char		hwpoison_debug_fs[MAX_PATH+1];
+static int		hwpoison_inject_fd;
+static int		hwpoison_forget_fd;
+
+#define HASH_SHIFT	13
+#define HASH_SIZE	(1 << HASH_SHIFT)
+#define HASH_MASK	(HASH_SIZE - 1)
+#define HASH_KEY(flags)	(flags & HASH_MASK)
+
+static unsigned long	total_pages;
+static unsigned long	nr_pages[HASH_SIZE];
+static uint64_t		page_flags[HASH_SIZE];
+
+
+/*
+ * helper functions
+ */
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#define min_t(type, x, y) ({			\
+	type __min1 = (x);			\
+	type __min2 = (y);			\
+	__min1 < __min2 ? __min1 : __min2; })
+
+#define max_t(type, x, y) ({			\
+	type __max1 = (x);			\
+	type __max2 = (y);			\
+	__max1 > __max2 ? __max1 : __max2; })
+
+static unsigned long pages2mb(unsigned long pages)
+{
+	return (pages * page_size) >> 20;
+}
+
+static void fatal(const char *x, ...)
+{
+	va_list ap;
+
+	va_start(ap, x);
+	vfprintf(stderr, x, ap);
+	va_end(ap);
+	exit(EXIT_FAILURE);
+}
+
+static int checked_open(const char *pathname, int flags)
+{
+	int fd = open(pathname, flags);
+
+	if (fd < 0) {
+		perror(pathname);
+		exit(EXIT_FAILURE);
+	}
+
+	return fd;
+}
+
+/*
+ * pagemap/kpageflags routines
+ */
+
+static unsigned long do_u64_read(int fd, char *name,
+				 uint64_t *buf,
+				 unsigned long index,
+				 unsigned long count)
+{
+	long bytes;
+
+	if (index > ULONG_MAX / 8)
+		fatal("index overflow: %lu\n", index);
+
+	if (lseek(fd, index * 8, SEEK_SET) < 0) {
+		perror(name);
+		exit(EXIT_FAILURE);
+	}
+
+	bytes = read(fd, buf, count * 8);
+	if (bytes < 0) {
+		perror(name);
+		exit(EXIT_FAILURE);
+	}
+	if (bytes % 8)
+		fatal("partial read: %lu bytes\n", bytes);
+
+	return bytes / 8;
+}
+
+static unsigned long kpageflags_read(uint64_t *buf,
+				     unsigned long index,
+				     unsigned long pages)
+{
+	return do_u64_read(kpageflags_fd, PROC_KPAGEFLAGS, buf, index, pages);
+}
+
+static unsigned long pagemap_read(uint64_t *buf,
+				  unsigned long index,
+				  unsigned long pages)
+{
+	return do_u64_read(pagemap_fd, "/proc/pid/pagemap", buf, index, pages);
+}
+
+static unsigned long pagemap_pfn(uint64_t val)
+{
+	unsigned long pfn;
+
+	if (val & PM_PRESENT)
+		pfn = PM_PFRAME(val);
+	else
+		pfn = 0;
+
+	return pfn;
+}
+
+
+/*
+ * page flag names
+ */
+
+static char *page_flag_name(uint64_t flags)
+{
+	static char buf[65];
+	int present;
+	int i, j;
+
+	for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
+		present = (flags >> i) & 1;
+		if (!page_flag_names[i]) {
+			if (present)
+				fatal("unknown flag bit %d\n", i);
+			continue;
+		}
+		buf[j++] = present ? page_flag_names[i][0] : '_';
+	}
+
+	return buf;
+}
+
+static char *page_flag_longname(uint64_t flags)
+{
+	static char buf[1024];
+	int i, n;
+
+	for (i = 0, n = 0; i < ARRAY_SIZE(page_flag_names); i++) {
+		if (!page_flag_names[i])
+			continue;
+		if ((flags >> i) & 1)
+			n += snprintf(buf + n, sizeof(buf) - n, "%s,",
+					page_flag_names[i] + 2);
+	}
+	if (n)
+		n--;
+	buf[n] = '\0';
+
+	return buf;
+}
+
+
+/*
+ * page list and summary
+ */
+
+static void show_page_range(unsigned long voffset,
+			    unsigned long offset, uint64_t flags)
+{
+	static uint64_t      flags0;
+	static unsigned long voff;
+	static unsigned long index;
+	static unsigned long count;
+
+	if (flags == flags0 && offset == index + count &&
+	    (!opt_pid || voffset == voff + count)) {
+		count++;
+		return;
+	}
+
+	if (count) {
+		if (opt_pid)
+			printf("%lx\t", voff);
+		printf("%lx\t%lx\t%s\n",
+				index, count, page_flag_name(flags0));
+	}
+
+	flags0 = flags;
+	index  = offset;
+	voff   = voffset;
+	count  = 1;
+}
+
+static void show_page(unsigned long voffset,
+		      unsigned long offset, uint64_t flags)
+{
+	if (opt_pid)
+		printf("%lx\t", voffset);
+	printf("%lx\t%s\n", offset, page_flag_name(flags));
+}
+
+static void show_summary(void)
+{
+	int i;
+
+	printf("             flags\tpage-count       MB"
+		"  symbolic-flags\t\t\tlong-symbolic-flags\n");
+
+	for (i = 0; i < ARRAY_SIZE(nr_pages); i++) {
+		if (nr_pages[i])
+			printf("0x%016llx\t%10lu %8lu  %s\t%s\n",
+				(unsigned long long)page_flags[i],
+				nr_pages[i],
+				pages2mb(nr_pages[i]),
+				page_flag_name(page_flags[i]),
+				page_flag_longname(page_flags[i]));
+	}
+
+	printf("             total\t%10lu %8lu\n",
+			total_pages, pages2mb(total_pages));
+}
+
+
+/*
+ * page flag filters
+ */
+
+static int bit_mask_ok(uint64_t flags)
+{
+	int i;
+
+	for (i = 0; i < nr_bit_filters; i++) {
+		if (opt_bits[i] == KPF_ALL_BITS) {
+			if ((flags & opt_mask[i]) == 0)
+				return 0;
+		} else {
+			if ((flags & opt_mask[i]) != opt_bits[i])
+				return 0;
+		}
+	}
+
+	return 1;
+}
+
+static uint64_t expand_overloaded_flags(uint64_t flags)
+{
+	/* SLOB/SLUB overload several page flags */
+	if (flags & BIT(SLAB)) {
+		if (flags & BIT(PRIVATE))
+			flags ^= BIT(PRIVATE) | BIT(SLOB_FREE);
+		if (flags & BIT(ACTIVE))
+			flags ^= BIT(ACTIVE) | BIT(SLUB_FROZEN);
+		if (flags & BIT(ERROR))
+			flags ^= BIT(ERROR) | BIT(SLUB_DEBUG);
+	}
+
+	/* PG_reclaim is overloaded as PG_readahead in the read path */
+	if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM))
+		flags ^= BIT(RECLAIM) | BIT(READAHEAD);
+
+	return flags;
+}
+
+static uint64_t well_known_flags(uint64_t flags)
+{
+	/* hide flags intended only for kernel hacker */
+	flags &= ~KPF_HACKERS_BITS;
+
+	/* hide non-hugeTLB compound pages */
+	if ((flags & BITS_COMPOUND) && !(flags & BIT(HUGE)))
+		flags &= ~BITS_COMPOUND;
+
+	return flags;
+}
+
+static uint64_t kpageflags_flags(uint64_t flags)
+{
+	flags = expand_overloaded_flags(flags);
+
+	if (!opt_raw)
+		flags = well_known_flags(flags);
+
+	return flags;
+}
+
+/* verify that a mountpoint is actually a debugfs instance */
+static int debugfs_valid_mountpoint(const char *debugfs)
+{
+	struct statfs st_fs;
+
+	if (statfs(debugfs, &st_fs) < 0)
+		return -ENOENT;
+	else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
+		return -ENOENT;
+
+	return 0;
+}
+
+/* find the path to the mounted debugfs */
+static const char *debugfs_find_mountpoint(void)
+{
+	const char **ptr;
+	char type[100];
+	FILE *fp;
+
+	ptr = debugfs_known_mountpoints;
+	while (*ptr) {
+		if (debugfs_valid_mountpoint(*ptr) == 0) {
+			strcpy(hwpoison_debug_fs, *ptr);
+			return hwpoison_debug_fs;
+		}
+		ptr++;
+	}
+
+	/* give up and parse /proc/mounts */
+	fp = fopen("/proc/mounts", "r");
+	if (fp == NULL)
+		perror("Can't open /proc/mounts for read");
+
+	while (fscanf(fp, "%*s %"
+		      STR(MAX_PATH)
+		      "s %99s %*s %*d %*d\n",
+		      hwpoison_debug_fs, type) == 2) {
+		if (strcmp(type, "debugfs") == 0)
+			break;
+	}
+	fclose(fp);
+
+	if (strcmp(type, "debugfs") != 0)
+		return NULL;
+
+	return hwpoison_debug_fs;
+}
+
+/* mount the debugfs somewhere if it's not mounted */
+
+static void debugfs_mount(void)
+{
+	const char **ptr;
+
+	/* see if it's already mounted */
+	if (debugfs_find_mountpoint())
+		return;
+
+	ptr = debugfs_known_mountpoints;
+	while (*ptr) {
+		if (mount(NULL, *ptr, "debugfs", 0, NULL) == 0) {
+			/* save the mountpoint */
+			strcpy(hwpoison_debug_fs, *ptr);
+			break;
+		}
+		ptr++;
+	}
+
+	if (*ptr == NULL) {
+		perror("mount debugfs");
+		exit(EXIT_FAILURE);
+	}
+}
+
+/*
+ * page actions
+ */
+
+static void prepare_hwpoison_fd(void)
+{
+	char buf[MAX_PATH + 1];
+
+	debugfs_mount();
+
+	if (opt_hwpoison && !hwpoison_inject_fd) {
+		snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn",
+			hwpoison_debug_fs);
+		hwpoison_inject_fd = checked_open(buf, O_WRONLY);
+	}
+
+	if (opt_unpoison && !hwpoison_forget_fd) {
+		snprintf(buf, MAX_PATH, "%s/hwpoison/unpoison-pfn",
+			hwpoison_debug_fs);
+		hwpoison_forget_fd = checked_open(buf, O_WRONLY);
+	}
+}
+
+static int hwpoison_page(unsigned long offset)
+{
+	char buf[100];
+	int len;
+
+	len = sprintf(buf, "0x%lx\n", offset);
+	len = write(hwpoison_inject_fd, buf, len);
+	if (len < 0) {
+		perror("hwpoison inject");
+		return len;
+	}
+	return 0;
+}
+
+static int unpoison_page(unsigned long offset)
+{
+	char buf[100];
+	int len;
+
+	len = sprintf(buf, "0x%lx\n", offset);
+	len = write(hwpoison_forget_fd, buf, len);
+	if (len < 0) {
+		perror("hwpoison forget");
+		return len;
+	}
+	return 0;
+}
+
+/*
+ * page frame walker
+ */
+
+static int hash_slot(uint64_t flags)
+{
+	int k = HASH_KEY(flags);
+	int i;
+
+	/* Explicitly reserve slot 0 for flags 0: the following logic
+	 * cannot distinguish an unoccupied slot from slot (flags==0).
+	 */
+	if (flags == 0)
+		return 0;
+
+	/* search through the remaining (HASH_SIZE-1) slots */
+	for (i = 1; i < ARRAY_SIZE(page_flags); i++, k++) {
+		if (!k || k >= ARRAY_SIZE(page_flags))
+			k = 1;
+		if (page_flags[k] == 0) {
+			page_flags[k] = flags;
+			return k;
+		}
+		if (page_flags[k] == flags)
+			return k;
+	}
+
+	fatal("hash table full: bump up HASH_SHIFT?\n");
+	exit(EXIT_FAILURE);
+}
+
+static void add_page(unsigned long voffset,
+		     unsigned long offset, uint64_t flags)
+{
+	flags = kpageflags_flags(flags);
+
+	if (!bit_mask_ok(flags))
+		return;
+
+	if (opt_hwpoison)
+		hwpoison_page(offset);
+	if (opt_unpoison)
+		unpoison_page(offset);
+
+	if (opt_list == 1)
+		show_page_range(voffset, offset, flags);
+	else if (opt_list == 2)
+		show_page(voffset, offset, flags);
+
+	nr_pages[hash_slot(flags)]++;
+	total_pages++;
+}
+
+#define KPAGEFLAGS_BATCH	(64 << 10)	/* 64k pages */
+static void walk_pfn(unsigned long voffset,
+		     unsigned long index,
+		     unsigned long count)
+{
+	uint64_t buf[KPAGEFLAGS_BATCH];
+	unsigned long batch;
+	long pages;
+	unsigned long i;
+
+	while (count) {
+		batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH);
+		pages = kpageflags_read(buf, index, batch);
+		if (pages == 0)
+			break;
+
+		for (i = 0; i < pages; i++)
+			add_page(voffset + i, index + i, buf[i]);
+
+		index += pages;
+		count -= pages;
+	}
+}
+
+#define PAGEMAP_BATCH	(64 << 10)
+static void walk_vma(unsigned long index, unsigned long count)
+{
+	uint64_t buf[PAGEMAP_BATCH];
+	unsigned long batch;
+	unsigned long pages;
+	unsigned long pfn;
+	unsigned long i;
+
+	while (count) {
+		batch = min_t(unsigned long, count, PAGEMAP_BATCH);
+		pages = pagemap_read(buf, index, batch);
+		if (pages == 0)
+			break;
+
+		for (i = 0; i < pages; i++) {
+			pfn = pagemap_pfn(buf[i]);
+			if (pfn)
+				walk_pfn(index + i, pfn, 1);
+		}
+
+		index += pages;
+		count -= pages;
+	}
+}
+
+static void walk_task(unsigned long index, unsigned long count)
+{
+	const unsigned long end = index + count;
+	unsigned long start;
+	int i = 0;
+
+	while (index < end) {
+
+		while (pg_end[i] <= index)
+			if (++i >= nr_vmas)
+				return;
+		if (pg_start[i] >= end)
+			return;
+
+		start = max_t(unsigned long, pg_start[i], index);
+		index = min_t(unsigned long, pg_end[i], end);
+
+		assert(start < index);
+		walk_vma(start, index - start);
+	}
+}
+
+static void add_addr_range(unsigned long offset, unsigned long size)
+{
+	if (nr_addr_ranges >= MAX_ADDR_RANGES)
+		fatal("too many addr ranges\n");
+
+	opt_offset[nr_addr_ranges] = offset;
+	opt_size[nr_addr_ranges] = min_t(unsigned long, size, ULONG_MAX-offset);
+	nr_addr_ranges++;
+}
+
+static void walk_addr_ranges(void)
+{
+	int i;
+
+	kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY);
+
+	if (!nr_addr_ranges)
+		add_addr_range(0, ULONG_MAX);
+
+	for (i = 0; i < nr_addr_ranges; i++)
+		if (!opt_pid)
+			walk_pfn(0, opt_offset[i], opt_size[i]);
+		else
+			walk_task(opt_offset[i], opt_size[i]);
+
+	close(kpageflags_fd);
+}
+
+
+/*
+ * user interface
+ */
+
+static const char *page_flag_type(uint64_t flag)
+{
+	if (flag & KPF_HACKERS_BITS)
+		return "(r)";
+	if (flag & KPF_OVERLOADED_BITS)
+		return "(o)";
+	return "   ";
+}
+
+static void usage(void)
+{
+	int i, j;
+
+	printf(
+"page-types [options]\n"
+"            -r|--raw                   Raw mode, for kernel developers\n"
+"            -d|--describe flags        Describe flags\n"
+"            -a|--addr    addr-spec     Walk a range of pages\n"
+"            -b|--bits    bits-spec     Walk pages with specified bits\n"
+"            -p|--pid     pid           Walk process address space\n"
+#if 0 /* planned features */
+"            -f|--file    filename      Walk file address space\n"
+#endif
+"            -l|--list                  Show page details in ranges\n"
+"            -L|--list-each             Show page details one by one\n"
+"            -N|--no-summary            Don't show summary info\n"
+"            -X|--hwpoison              hwpoison pages\n"
+"            -x|--unpoison              unpoison pages\n"
+"            -h|--help                  Show this usage message\n"
+"flags:\n"
+"            0x10                       bitfield format, e.g.\n"
+"            anon                       bit-name, e.g.\n"
+"            0x10,anon                  comma-separated list, e.g.\n"
+"addr-spec:\n"
+"            N                          one page at offset N (unit: pages)\n"
+"            N+M                        pages range from N to N+M-1\n"
+"            N,M                        pages range from N to M-1\n"
+"            N,                         pages range from N to end\n"
+"            ,M                         pages range from 0 to M-1\n"
+"bits-spec:\n"
+"            bit1,bit2                  (flags & (bit1|bit2)) != 0\n"
+"            bit1,bit2=bit1             (flags & (bit1|bit2)) == bit1\n"
+"            bit1,~bit2                 (flags & (bit1|bit2)) == bit1\n"
+"            =bit1,bit2                 flags == (bit1|bit2)\n"
+"bit-names:\n"
+	);
+
+	for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
+		if (!page_flag_names[i])
+			continue;
+		printf("%16s%s", page_flag_names[i] + 2,
+				 page_flag_type(1ULL << i));
+		if (++j > 3) {
+			j = 0;
+			putchar('\n');
+		}
+	}
+	printf("\n                                   "
+		"(r) raw mode bits  (o) overloaded bits\n");
+}
+
+static unsigned long long parse_number(const char *str)
+{
+	unsigned long long n;
+
+	n = strtoll(str, NULL, 0);
+
+	if (n == 0 && str[0] != '0')
+		fatal("invalid name or number: %s\n", str);
+
+	return n;
+}
+
+static void parse_pid(const char *str)
+{
+	FILE *file;
+	char buf[5000];
+
+	opt_pid = parse_number(str);
+
+	sprintf(buf, "/proc/%d/pagemap", opt_pid);
+	pagemap_fd = checked_open(buf, O_RDONLY);
+
+	sprintf(buf, "/proc/%d/maps", opt_pid);
+	file = fopen(buf, "r");
+	if (!file) {
+		perror(buf);
+		exit(EXIT_FAILURE);
+	}
+
+	while (fgets(buf, sizeof(buf), file) != NULL) {
+		unsigned long vm_start;
+		unsigned long vm_end;
+		unsigned long long pgoff;
+		int major, minor;
+		char r, w, x, s;
+		unsigned long ino;
+		int n;
+
+		n = sscanf(buf, "%lx-%lx %c%c%c%c %llx %x:%x %lu",
+			   &vm_start,
+			   &vm_end,
+			   &r, &w, &x, &s,
+			   &pgoff,
+			   &major, &minor,
+			   &ino);
+		if (n < 10) {
+			fprintf(stderr, "unexpected line: %s\n", buf);
+			continue;
+		}
+		pg_start[nr_vmas] = vm_start / page_size;
+		pg_end[nr_vmas] = vm_end / page_size;
+		if (++nr_vmas >= MAX_VMAS) {
+			fprintf(stderr, "too many VMAs\n");
+			break;
+		}
+	}
+	fclose(file);
+}
+
+static void parse_file(const char *name)
+{
+}
+
+static void parse_addr_range(const char *optarg)
+{
+	unsigned long offset;
+	unsigned long size;
+	char *p;
+
+	p = strchr(optarg, ',');
+	if (!p)
+		p = strchr(optarg, '+');
+
+	if (p == optarg) {
+		offset = 0;
+		size   = parse_number(p + 1);
+	} else if (p) {
+		offset = parse_number(optarg);
+		if (p[1] == '\0')
+			size = ULONG_MAX;
+		else {
+			size = parse_number(p + 1);
+			if (*p == ',') {
+				if (size < offset)
+					fatal("invalid range: %lu,%lu\n",
+							offset, size);
+				size -= offset;
+			}
+		}
+	} else {
+		offset = parse_number(optarg);
+		size   = 1;
+	}
+
+	add_addr_range(offset, size);
+}
+
+static void add_bits_filter(uint64_t mask, uint64_t bits)
+{
+	if (nr_bit_filters >= MAX_BIT_FILTERS)
+		fatal("too much bit filters\n");
+
+	opt_mask[nr_bit_filters] = mask;
+	opt_bits[nr_bit_filters] = bits;
+	nr_bit_filters++;
+}
+
+static uint64_t parse_flag_name(const char *str, int len)
+{
+	int i;
+
+	if (!*str || !len)
+		return 0;
+
+	if (len <= 8 && !strncmp(str, "compound", len))
+		return BITS_COMPOUND;
+
+	for (i = 0; i < ARRAY_SIZE(page_flag_names); i++) {
+		if (!page_flag_names[i])
+			continue;
+		if (!strncmp(str, page_flag_names[i] + 2, len))
+			return 1ULL << i;
+	}
+
+	return parse_number(str);
+}
+
+static uint64_t parse_flag_names(const char *str, int all)
+{
+	const char *p    = str;
+	uint64_t   flags = 0;
+
+	while (1) {
+		if (*p == ',' || *p == '=' || *p == '\0') {
+			if ((*str != '~') || (*str == '~' && all && *++str))
+				flags |= parse_flag_name(str, p - str);
+			if (*p != ',')
+				break;
+			str = p + 1;
+		}
+		p++;
+	}
+
+	return flags;
+}
+
+static void parse_bits_mask(const char *optarg)
+{
+	uint64_t mask;
+	uint64_t bits;
+	const char *p;
+
+	p = strchr(optarg, '=');
+	if (p == optarg) {
+		mask = KPF_ALL_BITS;
+		bits = parse_flag_names(p + 1, 0);
+	} else if (p) {
+		mask = parse_flag_names(optarg, 0);
+		bits = parse_flag_names(p + 1, 0);
+	} else if (strchr(optarg, '~')) {
+		mask = parse_flag_names(optarg, 1);
+		bits = parse_flag_names(optarg, 0);
+	} else {
+		mask = parse_flag_names(optarg, 0);
+		bits = KPF_ALL_BITS;
+	}
+
+	add_bits_filter(mask, bits);
+}
+
+static void describe_flags(const char *optarg)
+{
+	uint64_t flags = parse_flag_names(optarg, 0);
+
+	printf("0x%016llx\t%s\t%s\n",
+		(unsigned long long)flags,
+		page_flag_name(flags),
+		page_flag_longname(flags));
+}
+
+static const struct option opts[] = {
+	{ "raw"       , 0, NULL, 'r' },
+	{ "pid"       , 1, NULL, 'p' },
+	{ "file"      , 1, NULL, 'f' },
+	{ "addr"      , 1, NULL, 'a' },
+	{ "bits"      , 1, NULL, 'b' },
+	{ "describe"  , 1, NULL, 'd' },
+	{ "list"      , 0, NULL, 'l' },
+	{ "list-each" , 0, NULL, 'L' },
+	{ "no-summary", 0, NULL, 'N' },
+	{ "hwpoison"  , 0, NULL, 'X' },
+	{ "unpoison"  , 0, NULL, 'x' },
+	{ "help"      , 0, NULL, 'h' },
+	{ NULL        , 0, NULL, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+	int c;
+
+	page_size = getpagesize();
+
+	while ((c = getopt_long(argc, argv,
+				"rp:f:a:b:d:lLNXxh", opts, NULL)) != -1) {
+		switch (c) {
+		case 'r':
+			opt_raw = 1;
+			break;
+		case 'p':
+			parse_pid(optarg);
+			break;
+		case 'f':
+			parse_file(optarg);
+			break;
+		case 'a':
+			parse_addr_range(optarg);
+			break;
+		case 'b':
+			parse_bits_mask(optarg);
+			break;
+		case 'd':
+			describe_flags(optarg);
+			exit(0);
+		case 'l':
+			opt_list = 1;
+			break;
+		case 'L':
+			opt_list = 2;
+			break;
+		case 'N':
+			opt_no_summary = 1;
+			break;
+		case 'X':
+			opt_hwpoison = 1;
+			prepare_hwpoison_fd();
+			break;
+		case 'x':
+			opt_unpoison = 1;
+			prepare_hwpoison_fd();
+			break;
+		case 'h':
+			usage();
+			exit(0);
+		default:
+			usage();
+			exit(1);
+		}
+	}
+
+	if (opt_list && opt_pid)
+		printf("voffset\t");
+	if (opt_list == 1)
+		printf("offset\tlen\tflags\n");
+	if (opt_list == 2)
+		printf("offset\tflags\n");
+
+	walk_addr_ranges();
+
+	if (opt_list == 1)
+		show_page_range(0, 0, 0);  /* drain the buffer */
+
+	if (opt_no_summary)
+		return 0;
+
+	if (opt_list)
+		printf("\n\n");
+
+	show_summary();
+
+	return 0;
+}
diff --git a/tools/slub/slabinfo.c b/tools/vm/slabinfo.c
similarity index 100%
rename from tools/slub/slabinfo.c
rename to tools/vm/slabinfo.c
diff --git a/virt/kvm/assigned-dev.c b/virt/kvm/assigned-dev.c
index 758e3b3..01f572c 100644
--- a/virt/kvm/assigned-dev.c
+++ b/virt/kvm/assigned-dev.c
@@ -49,31 +49,73 @@
 			index = i;
 			break;
 		}
-	if (index < 0) {
+	if (index < 0)
 		printk(KERN_WARNING "Fail to find correlated MSI-X entry!\n");
-		return 0;
-	}
 
 	return index;
 }
 
-static irqreturn_t kvm_assigned_dev_thread(int irq, void *dev_id)
+static irqreturn_t kvm_assigned_dev_intx(int irq, void *dev_id)
+{
+	struct kvm_assigned_dev_kernel *assigned_dev = dev_id;
+	int ret;
+
+	spin_lock(&assigned_dev->intx_lock);
+	if (pci_check_and_mask_intx(assigned_dev->dev)) {
+		assigned_dev->host_irq_disabled = true;
+		ret = IRQ_WAKE_THREAD;
+	} else
+		ret = IRQ_NONE;
+	spin_unlock(&assigned_dev->intx_lock);
+
+	return ret;
+}
+
+static void
+kvm_assigned_dev_raise_guest_irq(struct kvm_assigned_dev_kernel *assigned_dev,
+				 int vector)
+{
+	if (unlikely(assigned_dev->irq_requested_type &
+		     KVM_DEV_IRQ_GUEST_INTX)) {
+		spin_lock(&assigned_dev->intx_mask_lock);
+		if (!(assigned_dev->flags & KVM_DEV_ASSIGN_MASK_INTX))
+			kvm_set_irq(assigned_dev->kvm,
+				    assigned_dev->irq_source_id, vector, 1);
+		spin_unlock(&assigned_dev->intx_mask_lock);
+	} else
+		kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
+			    vector, 1);
+}
+
+static irqreturn_t kvm_assigned_dev_thread_intx(int irq, void *dev_id)
 {
 	struct kvm_assigned_dev_kernel *assigned_dev = dev_id;
 
-	if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_INTX) {
-		spin_lock(&assigned_dev->intx_lock);
+	if (!(assigned_dev->flags & KVM_DEV_ASSIGN_PCI_2_3)) {
+		spin_lock_irq(&assigned_dev->intx_lock);
 		disable_irq_nosync(irq);
 		assigned_dev->host_irq_disabled = true;
-		spin_unlock(&assigned_dev->intx_lock);
+		spin_unlock_irq(&assigned_dev->intx_lock);
 	}
 
-	kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
-		    assigned_dev->guest_irq, 1);
+	kvm_assigned_dev_raise_guest_irq(assigned_dev,
+					 assigned_dev->guest_irq);
 
 	return IRQ_HANDLED;
 }
 
+#ifdef __KVM_HAVE_MSI
+static irqreturn_t kvm_assigned_dev_thread_msi(int irq, void *dev_id)
+{
+	struct kvm_assigned_dev_kernel *assigned_dev = dev_id;
+
+	kvm_assigned_dev_raise_guest_irq(assigned_dev,
+					 assigned_dev->guest_irq);
+
+	return IRQ_HANDLED;
+}
+#endif
+
 #ifdef __KVM_HAVE_MSIX
 static irqreturn_t kvm_assigned_dev_thread_msix(int irq, void *dev_id)
 {
@@ -83,8 +125,7 @@
 
 	if (index >= 0) {
 		vector = assigned_dev->guest_msix_entries[index].vector;
-		kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
-			    vector, 1);
+		kvm_assigned_dev_raise_guest_irq(assigned_dev, vector);
 	}
 
 	return IRQ_HANDLED;
@@ -100,15 +141,31 @@
 
 	kvm_set_irq(dev->kvm, dev->irq_source_id, dev->guest_irq, 0);
 
-	/* The guest irq may be shared so this ack may be
-	 * from another device.
-	 */
-	spin_lock(&dev->intx_lock);
-	if (dev->host_irq_disabled) {
-		enable_irq(dev->host_irq);
-		dev->host_irq_disabled = false;
+	spin_lock(&dev->intx_mask_lock);
+
+	if (!(dev->flags & KVM_DEV_ASSIGN_MASK_INTX)) {
+		bool reassert = false;
+
+		spin_lock_irq(&dev->intx_lock);
+		/*
+		 * The guest IRQ may be shared so this ack can come from an
+		 * IRQ for another guest device.
+		 */
+		if (dev->host_irq_disabled) {
+			if (!(dev->flags & KVM_DEV_ASSIGN_PCI_2_3))
+				enable_irq(dev->host_irq);
+			else if (!pci_check_and_unmask_intx(dev->dev))
+				reassert = true;
+			dev->host_irq_disabled = reassert;
+		}
+		spin_unlock_irq(&dev->intx_lock);
+
+		if (reassert)
+			kvm_set_irq(dev->kvm, dev->irq_source_id,
+				    dev->guest_irq, 1);
 	}
-	spin_unlock(&dev->intx_lock);
+
+	spin_unlock(&dev->intx_mask_lock);
 }
 
 static void deassign_guest_irq(struct kvm *kvm,
@@ -156,7 +213,15 @@
 		pci_disable_msix(assigned_dev->dev);
 	} else {
 		/* Deal with MSI and INTx */
-		disable_irq(assigned_dev->host_irq);
+		if ((assigned_dev->irq_requested_type &
+		     KVM_DEV_IRQ_HOST_INTX) &&
+		    (assigned_dev->flags & KVM_DEV_ASSIGN_PCI_2_3)) {
+			spin_lock_irq(&assigned_dev->intx_lock);
+			pci_intx(assigned_dev->dev, false);
+			spin_unlock_irq(&assigned_dev->intx_lock);
+			synchronize_irq(assigned_dev->host_irq);
+		} else
+			disable_irq(assigned_dev->host_irq);
 
 		free_irq(assigned_dev->host_irq, assigned_dev);
 
@@ -237,15 +302,34 @@
 static int assigned_device_enable_host_intx(struct kvm *kvm,
 					    struct kvm_assigned_dev_kernel *dev)
 {
+	irq_handler_t irq_handler;
+	unsigned long flags;
+
 	dev->host_irq = dev->dev->irq;
-	/* Even though this is PCI, we don't want to use shared
-	 * interrupts. Sharing host devices with guest-assigned devices
-	 * on the same interrupt line is not a happy situation: there
-	 * are going to be long delays in accepting, acking, etc.
+
+	/*
+	 * We can only share the IRQ line with other host devices if we are
+	 * able to disable the IRQ source at device-level - independently of
+	 * the guest driver. Otherwise host devices may suffer from unbounded
+	 * IRQ latencies when the guest keeps the line asserted.
 	 */
-	if (request_threaded_irq(dev->host_irq, NULL, kvm_assigned_dev_thread,
-				 IRQF_ONESHOT, dev->irq_name, dev))
+	if (dev->flags & KVM_DEV_ASSIGN_PCI_2_3) {
+		irq_handler = kvm_assigned_dev_intx;
+		flags = IRQF_SHARED;
+	} else {
+		irq_handler = NULL;
+		flags = IRQF_ONESHOT;
+	}
+	if (request_threaded_irq(dev->host_irq, irq_handler,
+				 kvm_assigned_dev_thread_intx, flags,
+				 dev->irq_name, dev))
 		return -EIO;
+
+	if (dev->flags & KVM_DEV_ASSIGN_PCI_2_3) {
+		spin_lock_irq(&dev->intx_lock);
+		pci_intx(dev->dev, true);
+		spin_unlock_irq(&dev->intx_lock);
+	}
 	return 0;
 }
 
@@ -262,8 +346,9 @@
 	}
 
 	dev->host_irq = dev->dev->irq;
-	if (request_threaded_irq(dev->host_irq, NULL, kvm_assigned_dev_thread,
-				 0, dev->irq_name, dev)) {
+	if (request_threaded_irq(dev->host_irq, NULL,
+				 kvm_assigned_dev_thread_msi, 0,
+				 dev->irq_name, dev)) {
 		pci_disable_msi(dev->dev);
 		return -EIO;
 	}
@@ -321,7 +406,6 @@
 {
 	dev->guest_irq = irq->guest_irq;
 	dev->ack_notifier.gsi = -1;
-	dev->host_irq_disabled = false;
 	return 0;
 }
 #endif
@@ -333,7 +417,6 @@
 {
 	dev->guest_irq = irq->guest_irq;
 	dev->ack_notifier.gsi = -1;
-	dev->host_irq_disabled = false;
 	return 0;
 }
 #endif
@@ -367,6 +450,7 @@
 	default:
 		r = -EINVAL;
 	}
+	dev->host_irq_disabled = false;
 
 	if (!r)
 		dev->irq_requested_type |= host_irq_type;
@@ -468,6 +552,7 @@
 {
 	int r = -ENODEV;
 	struct kvm_assigned_dev_kernel *match;
+	unsigned long irq_type;
 
 	mutex_lock(&kvm->lock);
 
@@ -476,7 +561,9 @@
 	if (!match)
 		goto out;
 
-	r = kvm_deassign_irq(kvm, match, assigned_irq->flags);
+	irq_type = assigned_irq->flags & (KVM_DEV_IRQ_HOST_MASK |
+					  KVM_DEV_IRQ_GUEST_MASK);
+	r = kvm_deassign_irq(kvm, match, irq_type);
 out:
 	mutex_unlock(&kvm->lock);
 	return r;
@@ -609,6 +696,10 @@
 	if (!match->pci_saved_state)
 		printk(KERN_DEBUG "%s: Couldn't store %s saved state\n",
 		       __func__, dev_name(&dev->dev));
+
+	if (!pci_intx_mask_supported(dev))
+		assigned_dev->flags &= ~KVM_DEV_ASSIGN_PCI_2_3;
+
 	match->assigned_dev_id = assigned_dev->assigned_dev_id;
 	match->host_segnr = assigned_dev->segnr;
 	match->host_busnr = assigned_dev->busnr;
@@ -616,6 +707,7 @@
 	match->flags = assigned_dev->flags;
 	match->dev = dev;
 	spin_lock_init(&match->intx_lock);
+	spin_lock_init(&match->intx_mask_lock);
 	match->irq_source_id = -1;
 	match->kvm = kvm;
 	match->ack_notifier.irq_acked = kvm_assigned_dev_ack_irq;
@@ -761,6 +853,55 @@
 }
 #endif
 
+static int kvm_vm_ioctl_set_pci_irq_mask(struct kvm *kvm,
+		struct kvm_assigned_pci_dev *assigned_dev)
+{
+	int r = 0;
+	struct kvm_assigned_dev_kernel *match;
+
+	mutex_lock(&kvm->lock);
+
+	match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+				      assigned_dev->assigned_dev_id);
+	if (!match) {
+		r = -ENODEV;
+		goto out;
+	}
+
+	spin_lock(&match->intx_mask_lock);
+
+	match->flags &= ~KVM_DEV_ASSIGN_MASK_INTX;
+	match->flags |= assigned_dev->flags & KVM_DEV_ASSIGN_MASK_INTX;
+
+	if (match->irq_requested_type & KVM_DEV_IRQ_GUEST_INTX) {
+		if (assigned_dev->flags & KVM_DEV_ASSIGN_MASK_INTX) {
+			kvm_set_irq(match->kvm, match->irq_source_id,
+				    match->guest_irq, 0);
+			/*
+			 * Masking at hardware-level is performed on demand,
+			 * i.e. when an IRQ actually arrives at the host.
+			 */
+		} else if (!(assigned_dev->flags & KVM_DEV_ASSIGN_PCI_2_3)) {
+			/*
+			 * Unmask the IRQ line if required. Unmasking at
+			 * device level will be performed by user space.
+			 */
+			spin_lock_irq(&match->intx_lock);
+			if (match->host_irq_disabled) {
+				enable_irq(match->host_irq);
+				match->host_irq_disabled = false;
+			}
+			spin_unlock_irq(&match->intx_lock);
+		}
+	}
+
+	spin_unlock(&match->intx_mask_lock);
+
+out:
+	mutex_unlock(&kvm->lock);
+	return r;
+}
+
 long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl,
 				  unsigned long arg)
 {
@@ -868,6 +1009,15 @@
 		break;
 	}
 #endif
+	case KVM_ASSIGN_SET_INTX_MASK: {
+		struct kvm_assigned_pci_dev assigned_dev;
+
+		r = -EFAULT;
+		if (copy_from_user(&assigned_dev, argp, sizeof assigned_dev))
+			goto out;
+		r = kvm_vm_ioctl_set_pci_irq_mask(kvm, &assigned_dev);
+		break;
+	}
 	default:
 		r = -ENOTTY;
 		break;
@@ -875,4 +1025,3 @@
 out:
 	return r;
 }
-
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index a91f980..42b7393 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -203,7 +203,7 @@
 
 void kvm_flush_remote_tlbs(struct kvm *kvm)
 {
-	int dirty_count = kvm->tlbs_dirty;
+	long dirty_count = kvm->tlbs_dirty;
 
 	smp_mb();
 	if (make_all_cpus_request(kvm, KVM_REQ_TLB_FLUSH))
@@ -289,15 +289,15 @@
 	 */
 	idx = srcu_read_lock(&kvm->srcu);
 	spin_lock(&kvm->mmu_lock);
+
 	kvm->mmu_notifier_seq++;
 	need_tlb_flush = kvm_unmap_hva(kvm, address) | kvm->tlbs_dirty;
-	spin_unlock(&kvm->mmu_lock);
-	srcu_read_unlock(&kvm->srcu, idx);
-
 	/* we've to flush the tlb before the pages can be freed */
 	if (need_tlb_flush)
 		kvm_flush_remote_tlbs(kvm);
 
+	spin_unlock(&kvm->mmu_lock);
+	srcu_read_unlock(&kvm->srcu, idx);
 }
 
 static void kvm_mmu_notifier_change_pte(struct mmu_notifier *mn,
@@ -335,12 +335,12 @@
 	for (; start < end; start += PAGE_SIZE)
 		need_tlb_flush |= kvm_unmap_hva(kvm, start);
 	need_tlb_flush |= kvm->tlbs_dirty;
-	spin_unlock(&kvm->mmu_lock);
-	srcu_read_unlock(&kvm->srcu, idx);
-
 	/* we've to flush the tlb before the pages can be freed */
 	if (need_tlb_flush)
 		kvm_flush_remote_tlbs(kvm);
+
+	spin_unlock(&kvm->mmu_lock);
+	srcu_read_unlock(&kvm->srcu, idx);
 }
 
 static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn,
@@ -357,11 +357,11 @@
 	 * been freed.
 	 */
 	kvm->mmu_notifier_seq++;
+	smp_wmb();
 	/*
 	 * The above sequence increase must be visible before the
-	 * below count decrease but both values are read by the kvm
-	 * page fault under mmu_lock spinlock so we don't need to add
-	 * a smb_wmb() here in between the two.
+	 * below count decrease, which is ensured by the smp_wmb above
+	 * in conjunction with the smp_rmb in mmu_notifier_retry().
 	 */
 	kvm->mmu_notifier_count--;
 	spin_unlock(&kvm->mmu_lock);
@@ -378,13 +378,14 @@
 
 	idx = srcu_read_lock(&kvm->srcu);
 	spin_lock(&kvm->mmu_lock);
-	young = kvm_age_hva(kvm, address);
-	spin_unlock(&kvm->mmu_lock);
-	srcu_read_unlock(&kvm->srcu, idx);
 
+	young = kvm_age_hva(kvm, address);
 	if (young)
 		kvm_flush_remote_tlbs(kvm);
 
+	spin_unlock(&kvm->mmu_lock);
+	srcu_read_unlock(&kvm->srcu, idx);
+
 	return young;
 }
 
@@ -449,7 +450,7 @@
 		slots->id_to_index[i] = slots->memslots[i].id = i;
 }
 
-static struct kvm *kvm_create_vm(void)
+static struct kvm *kvm_create_vm(unsigned long type)
 {
 	int r, i;
 	struct kvm *kvm = kvm_arch_alloc_vm();
@@ -457,7 +458,7 @@
 	if (!kvm)
 		return ERR_PTR(-ENOMEM);
 
-	r = kvm_arch_init_vm(kvm);
+	r = kvm_arch_init_vm(kvm, type);
 	if (r)
 		goto out_err_nodisable;
 
@@ -535,21 +536,13 @@
 static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
 				  struct kvm_memory_slot *dont)
 {
-	int i;
-
 	if (!dont || free->rmap != dont->rmap)
 		vfree(free->rmap);
 
 	if (!dont || free->dirty_bitmap != dont->dirty_bitmap)
 		kvm_destroy_dirty_bitmap(free);
 
-
-	for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
-		if (!dont || free->lpage_info[i] != dont->lpage_info[i]) {
-			vfree(free->lpage_info[i]);
-			free->lpage_info[i] = NULL;
-		}
-	}
+	kvm_arch_free_memslot(free, dont);
 
 	free->npages = 0;
 	free->rmap = NULL;
@@ -616,7 +609,6 @@
 	return 0;
 }
 
-#ifndef CONFIG_S390
 /*
  * Allocation size is twice as large as the actual dirty bitmap size.
  * This makes it possible to do double buffering: see x86's
@@ -624,6 +616,7 @@
  */
 static int kvm_create_dirty_bitmap(struct kvm_memory_slot *memslot)
 {
+#ifndef CONFIG_S390
 	unsigned long dirty_bytes = 2 * kvm_dirty_bitmap_bytes(memslot);
 
 	if (dirty_bytes > PAGE_SIZE)
@@ -636,21 +629,8 @@
 
 	memslot->dirty_bitmap_head = memslot->dirty_bitmap;
 	memslot->nr_dirty_pages = 0;
-	return 0;
-}
 #endif /* !CONFIG_S390 */
-
-static struct kvm_memory_slot *
-search_memslots(struct kvm_memslots *slots, gfn_t gfn)
-{
-	struct kvm_memory_slot *memslot;
-
-	kvm_for_each_memslot(memslot, slots)
-		if (gfn >= memslot->base_gfn &&
-		      gfn < memslot->base_gfn + memslot->npages)
-			return memslot;
-
-	return NULL;
+	return 0;
 }
 
 static int cmp_memslot(const void *slot1, const void *slot2)
@@ -778,69 +758,24 @@
 	r = -ENOMEM;
 
 	/* Allocate if a slot is being created */
-#ifndef CONFIG_S390
-	if (npages && !new.rmap) {
-		new.rmap = vzalloc(npages * sizeof(*new.rmap));
-
-		if (!new.rmap)
-			goto out_free;
-
+	if (npages && !old.npages) {
 		new.user_alloc = user_alloc;
 		new.userspace_addr = mem->userspace_addr;
-	}
-	if (!npages)
-		goto skip_lpage;
-
-	for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
-		unsigned long ugfn;
-		unsigned long j;
-		int lpages;
-		int level = i + 2;
-
-		/* Avoid unused variable warning if no large pages */
-		(void)level;
-
-		if (new.lpage_info[i])
-			continue;
-
-		lpages = 1 + ((base_gfn + npages - 1)
-			     >> KVM_HPAGE_GFN_SHIFT(level));
-		lpages -= base_gfn >> KVM_HPAGE_GFN_SHIFT(level);
-
-		new.lpage_info[i] = vzalloc(lpages * sizeof(*new.lpage_info[i]));
-
-		if (!new.lpage_info[i])
+#ifndef CONFIG_S390
+		new.rmap = vzalloc(npages * sizeof(*new.rmap));
+		if (!new.rmap)
 			goto out_free;
-
-		if (base_gfn & (KVM_PAGES_PER_HPAGE(level) - 1))
-			new.lpage_info[i][0].write_count = 1;
-		if ((base_gfn+npages) & (KVM_PAGES_PER_HPAGE(level) - 1))
-			new.lpage_info[i][lpages - 1].write_count = 1;
-		ugfn = new.userspace_addr >> PAGE_SHIFT;
-		/*
-		 * If the gfn and userspace address are not aligned wrt each
-		 * other, or if explicitly asked to, disable large page
-		 * support for this slot
-		 */
-		if ((base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE(level) - 1) ||
-		    !largepages_enabled)
-			for (j = 0; j < lpages; ++j)
-				new.lpage_info[i][j].write_count = 1;
+#endif /* not defined CONFIG_S390 */
+		if (kvm_arch_create_memslot(&new, npages))
+			goto out_free;
 	}
 
-skip_lpage:
-
 	/* Allocate page dirty bitmap if needed */
 	if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) {
 		if (kvm_create_dirty_bitmap(&new) < 0)
 			goto out_free;
 		/* destroy any largepage mappings for dirty tracking */
 	}
-#else  /* not defined CONFIG_S390 */
-	new.user_alloc = user_alloc;
-	if (user_alloc)
-		new.userspace_addr = mem->userspace_addr;
-#endif /* not defined CONFIG_S390 */
 
 	if (!npages) {
 		struct kvm_memory_slot *slot;
@@ -890,8 +825,7 @@
 	if (!npages) {
 		new.rmap = NULL;
 		new.dirty_bitmap = NULL;
-		for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i)
-			new.lpage_info[i] = NULL;
+		memset(&new.arch, 0, sizeof(new.arch));
 	}
 
 	update_memslots(slots, &new);
@@ -978,6 +912,11 @@
 	return r;
 }
 
+bool kvm_largepages_enabled(void)
+{
+	return largepages_enabled;
+}
+
 void kvm_disable_largepages(void)
 {
 	largepages_enabled = false;
@@ -1031,12 +970,6 @@
 }
 EXPORT_SYMBOL_GPL(kvm_is_error_hva);
 
-static struct kvm_memory_slot *__gfn_to_memslot(struct kvm_memslots *slots,
-						gfn_t gfn)
-{
-	return search_memslots(slots, gfn);
-}
-
 struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
 {
 	return __gfn_to_memslot(kvm_memslots(kvm), gfn);
@@ -1459,7 +1392,7 @@
 
 	ghc->gpa = gpa;
 	ghc->generation = slots->generation;
-	ghc->memslot = __gfn_to_memslot(slots, gfn);
+	ghc->memslot = gfn_to_memslot(kvm, gfn);
 	ghc->hva = gfn_to_hva_many(ghc->memslot, gfn, NULL);
 	if (!kvm_is_error_hva(ghc->hva))
 		ghc->hva += offset;
@@ -1657,7 +1590,7 @@
 		page = virt_to_page(vcpu->kvm->coalesced_mmio_ring);
 #endif
 	else
-		return VM_FAULT_SIGBUS;
+		return kvm_arch_vcpu_fault(vcpu, vmf);
 	get_page(page);
 	vmf->page = page;
 	return 0;
@@ -1718,6 +1651,10 @@
 		goto vcpu_destroy;
 
 	mutex_lock(&kvm->lock);
+	if (!kvm_vcpu_compatible(vcpu)) {
+		r = -EINVAL;
+		goto unlock_vcpu_destroy;
+	}
 	if (atomic_read(&kvm->online_vcpus) == KVM_MAX_VCPUS) {
 		r = -EINVAL;
 		goto unlock_vcpu_destroy;
@@ -2198,12 +2135,12 @@
 	.llseek		= noop_llseek,
 };
 
-static int kvm_dev_ioctl_create_vm(void)
+static int kvm_dev_ioctl_create_vm(unsigned long type)
 {
 	int r;
 	struct kvm *kvm;
 
-	kvm = kvm_create_vm();
+	kvm = kvm_create_vm(type);
 	if (IS_ERR(kvm))
 		return PTR_ERR(kvm);
 #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
@@ -2254,10 +2191,7 @@
 		r = KVM_API_VERSION;
 		break;
 	case KVM_CREATE_VM:
-		r = -EINVAL;
-		if (arg)
-			goto out;
-		r = kvm_dev_ioctl_create_vm();
+		r = kvm_dev_ioctl_create_vm(arg);
 		break;
 	case KVM_CHECK_EXTENSION:
 		r = kvm_dev_ioctl_check_extension_generic(arg);